diff --git a/.changeset/afraid-buckets-yell.md b/.changeset/afraid-buckets-yell.md
new file mode 100644
index 00000000000..88e94692082
--- /dev/null
+++ b/.changeset/afraid-buckets-yell.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+#internal Exposed Confirmed state to ChainWriter GetTransactionStatus method
diff --git a/.changeset/beige-eels-teach.md b/.changeset/beige-eels-teach.md
new file mode 100644
index 00000000000..3a3c59ec260
--- /dev/null
+++ b/.changeset/beige-eels-teach.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Fix bhe datarace #internal
diff --git a/.changeset/big-dots-report.md b/.changeset/big-dots-report.md
new file mode 100644
index 00000000000..01475010f0d
--- /dev/null
+++ b/.changeset/big-dots-report.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Updated ZK overflow detection to skip transactions with non-broadcasted attempts. Delayed detection for zkEVM using the MinAttempts config. Updated XLayer to use the same detection logic as zkEVM. #internal
diff --git a/.changeset/big-kiwis-cross.md b/.changeset/big-kiwis-cross.md
new file mode 100644
index 00000000000..3bc450c20e5
--- /dev/null
+++ b/.changeset/big-kiwis-cross.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Initialize start of v2.16.0 release
diff --git a/.changeset/big-students-rush.md b/.changeset/big-students-rush.md
new file mode 100644
index 00000000000..914205cdf7c
--- /dev/null
+++ b/.changeset/big-students-rush.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#bugfix Fixes test flake
diff --git a/.changeset/blue-roses-brush.md b/.changeset/blue-roses-brush.md
new file mode 100644
index 00000000000..57dc796c03b
--- /dev/null
+++ b/.changeset/blue-roses-brush.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#added Allow workflows to run without external registry configured
diff --git a/.changeset/calm-badgers-jump.md b/.changeset/calm-badgers-jump.md
new file mode 100644
index 00000000000..76f6e5d3121
--- /dev/null
+++ b/.changeset/calm-badgers-jump.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+add error handling when arbitrum sequencer is not accessible #added
diff --git a/.changeset/chatty-spiders-double.md b/.changeset/chatty-spiders-double.md
new file mode 100644
index 00000000000..750a11628fe
--- /dev/null
+++ b/.changeset/chatty-spiders-double.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+remove dependency on FinalityDepth in EVM TXM code. #internal
diff --git a/.changeset/chilly-cars-attend.md b/.changeset/chilly-cars-attend.md
new file mode 100644
index 00000000000..2cb8323ab3c
--- /dev/null
+++ b/.changeset/chilly-cars-attend.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+add error handle for gnosis chiado for seen tx #added
diff --git a/.changeset/cool-mirrors-beg.md b/.changeset/cool-mirrors-beg.md
new file mode 100644
index 00000000000..a030ac7e3a6
--- /dev/null
+++ b/.changeset/cool-mirrors-beg.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#added L3X Config
diff --git a/.changeset/cuddly-eels-lay.md b/.changeset/cuddly-eels-lay.md
new file mode 100644
index 00000000000..25b38d3164d
--- /dev/null
+++ b/.changeset/cuddly-eels-lay.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Improve TXM performance by optimizing Confirmer and Finalizer queries to stop pulling EVM receipt. #internal
diff --git a/.changeset/early-glasses-rhyme.md b/.changeset/early-glasses-rhyme.md
new file mode 100644
index 00000000000..aa35bf897ea
--- /dev/null
+++ b/.changeset/early-glasses-rhyme.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+use FilteredLogs in EventBinding GetLatestValue instead of manual filtering. #internal
diff --git a/.changeset/eight-bees-speak.md b/.changeset/eight-bees-speak.md
new file mode 100644
index 00000000000..9c8ebe428d5
--- /dev/null
+++ b/.changeset/eight-bees-speak.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#bugfix head reporter non-zero reporting period
diff --git a/.changeset/eight-radios-hear.md b/.changeset/eight-radios-hear.md
new file mode 100644
index 00000000000..b422f378326
--- /dev/null
+++ b/.changeset/eight-radios-hear.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+#added merging core/capabilities/ccip from https://github.com/smartcontractkit/ccip
diff --git a/.changeset/eight-rocks-notice.md b/.changeset/eight-rocks-notice.md
new file mode 100644
index 00000000000..230abaec481
--- /dev/null
+++ b/.changeset/eight-rocks-notice.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+New Mercury v4 report schema #added
diff --git a/.changeset/fast-insects-shout.md b/.changeset/fast-insects-shout.md
new file mode 100644
index 00000000000..847fc8d057f
--- /dev/null
+++ b/.changeset/fast-insects-shout.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+#internal Change CapabilityType to string; remove possiblity of a panic
diff --git a/.changeset/flat-mirrors-confess.md b/.changeset/flat-mirrors-confess.md
new file mode 100644
index 00000000000..7c0a6a92a3f
--- /dev/null
+++ b/.changeset/flat-mirrors-confess.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#updated Sync feeds-manager wsrpc proto
diff --git a/.changeset/friendly-impalas-sniff.md b/.changeset/friendly-impalas-sniff.md
new file mode 100644
index 00000000000..8a041a338bc
--- /dev/null
+++ b/.changeset/friendly-impalas-sniff.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Added nonce validation immediately after broadcast for Hedera #internal
diff --git a/.changeset/happy-adults-wash.md b/.changeset/happy-adults-wash.md
new file mode 100644
index 00000000000..738f8998b20
--- /dev/null
+++ b/.changeset/happy-adults-wash.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal fix to keystone e2e test dispatcher to correctly mock duplicate registration error
diff --git a/.changeset/hip-crabs-agree.md b/.changeset/hip-crabs-agree.md
new file mode 100644
index 00000000000..5085899e3d3
--- /dev/null
+++ b/.changeset/hip-crabs-agree.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#added Add Astar TerminallyUnderpriced error mapping
diff --git a/.changeset/hot-laws-deny.md b/.changeset/hot-laws-deny.md
new file mode 100644
index 00000000000..d71783d1b78
--- /dev/null
+++ b/.changeset/hot-laws-deny.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal log info on missed finalized head instead of returning an error
diff --git a/.changeset/itchy-bugs-clean.md b/.changeset/itchy-bugs-clean.md
new file mode 100644
index 00000000000..beeed8ace1e
--- /dev/null
+++ b/.changeset/itchy-bugs-clean.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Introduced finalized transaction state. Added a finalizer component to the TXM to mark transactions as finalized. #internal
diff --git a/.changeset/late-stingrays-promise.md b/.changeset/late-stingrays-promise.md
new file mode 100644
index 00000000000..39ca570f581
--- /dev/null
+++ b/.changeset/late-stingrays-promise.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+Separate price updates schedule for token prices in CCIP #updated
diff --git a/.changeset/loud-windows-call.md b/.changeset/loud-windows-call.md
new file mode 100644
index 00000000000..e05bed706a6
--- /dev/null
+++ b/.changeset/loud-windows-call.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Added gas limit estimation feature to EVM gas estimators #added
diff --git a/.changeset/lucky-boats-run.md b/.changeset/lucky-boats-run.md
new file mode 100644
index 00000000000..c5864a6e370
--- /dev/null
+++ b/.changeset/lucky-boats-run.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+Reporting all the token prices from the job spec for CCIP #updated
diff --git a/.changeset/many-knives-play.md b/.changeset/many-knives-play.md
new file mode 100644
index 00000000000..8c1f5da1a48
--- /dev/null
+++ b/.changeset/many-knives-play.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#updated Adds DB syncing for registry syncer
diff --git a/.changeset/mean-brooms-agree.md b/.changeset/mean-brooms-agree.md
new file mode 100644
index 00000000000..0dd2ba7bd33
--- /dev/null
+++ b/.changeset/mean-brooms-agree.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+Custom (30s) timeout for Hedera RPC requests with large payloads (SendTransaction, CallContext, etc.) #internal
diff --git a/.changeset/new-eagles-marry.md b/.changeset/new-eagles-marry.md
new file mode 100644
index 00000000000..9577c2bbe09
--- /dev/null
+++ b/.changeset/new-eagles-marry.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal prevent editing whether or not a DON accepts workflows
diff --git a/.changeset/ninety-cougars-tease.md b/.changeset/ninety-cougars-tease.md
new file mode 100644
index 00000000000..ab12a571914
--- /dev/null
+++ b/.changeset/ninety-cougars-tease.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal restore common version to head of develop
diff --git a/.changeset/ninety-ways-run.md b/.changeset/ninety-ways-run.md
new file mode 100644
index 00000000000..0b4508bdd24
--- /dev/null
+++ b/.changeset/ninety-ways-run.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal speed up keystone e2e tests
diff --git a/.changeset/odd-eagles-shave.md b/.changeset/odd-eagles-shave.md
new file mode 100644
index 00000000000..0c68bc1573c
--- /dev/null
+++ b/.changeset/odd-eagles-shave.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+#internal Add hexutil Bytes encoding to batchcall data
diff --git a/.changeset/odd-hats-repeat.md b/.changeset/odd-hats-repeat.md
new file mode 100644
index 00000000000..ce80b45caff
--- /dev/null
+++ b/.changeset/odd-hats-repeat.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal fix the mock trigger to ensure events are sent
diff --git a/.changeset/polite-crabs-pretend.md b/.changeset/polite-crabs-pretend.md
new file mode 100644
index 00000000000..f8ea63b45c1
--- /dev/null
+++ b/.changeset/polite-crabs-pretend.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal ensure remote target request hash is deterministic
diff --git a/.changeset/proud-jokes-exercise.md b/.changeset/proud-jokes-exercise.md
new file mode 100644
index 00000000000..4e36d139de5
--- /dev/null
+++ b/.changeset/proud-jokes-exercise.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+#added Report new heads as a telemetry to OTI
diff --git a/.changeset/rich-chairs-hug.md b/.changeset/rich-chairs-hug.md
new file mode 100644
index 00000000000..0408383bd03
--- /dev/null
+++ b/.changeset/rich-chairs-hug.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal
diff --git a/.changeset/seven-kiwis-run.md b/.changeset/seven-kiwis-run.md
new file mode 100644
index 00000000000..3b56117c469
--- /dev/null
+++ b/.changeset/seven-kiwis-run.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+Added custom client error messages for Mantle to capture InsufficientEth and Fatal errors. #added
diff --git a/.changeset/shy-windows-juggle.md b/.changeset/shy-windows-juggle.md
new file mode 100644
index 00000000000..0408383bd03
--- /dev/null
+++ b/.changeset/shy-windows-juggle.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal
diff --git a/.changeset/slimy-cars-sparkle.md b/.changeset/slimy-cars-sparkle.md
new file mode 100644
index 00000000000..aa7658ae908
--- /dev/null
+++ b/.changeset/slimy-cars-sparkle.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal ks-404 validate ids before using as seed of transmission schedule
diff --git a/.changeset/slimy-forks-wait.md b/.changeset/slimy-forks-wait.md
new file mode 100644
index 00000000000..0408383bd03
--- /dev/null
+++ b/.changeset/slimy-forks-wait.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal
diff --git a/.changeset/smart-pumas-collect.md b/.changeset/smart-pumas-collect.md
new file mode 100644
index 00000000000..0748f170b9f
--- /dev/null
+++ b/.changeset/smart-pumas-collect.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#bugfix Fix incorrect error handling when registering a new feed manager
diff --git a/.changeset/strong-dogs-smash.md b/.changeset/strong-dogs-smash.md
new file mode 100644
index 00000000000..a34a418e65d
--- /dev/null
+++ b/.changeset/strong-dogs-smash.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+error handling for Treasure #added
\ No newline at end of file
diff --git a/.changeset/sweet-pumas-refuse.md b/.changeset/sweet-pumas-refuse.md
new file mode 100644
index 00000000000..fd642a9c94c
--- /dev/null
+++ b/.changeset/sweet-pumas-refuse.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+#bugfix Addresses 2 minor issues with the pruning of LogPoller's db tables: logs not matching any filter will now be pruned, and rows deleted are now properly reported for observability
diff --git a/.changeset/tall-poems-swim.md b/.changeset/tall-poems-swim.md
new file mode 100644
index 00000000000..0408383bd03
--- /dev/null
+++ b/.changeset/tall-poems-swim.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal
diff --git a/.changeset/tasty-walls-collect.md b/.changeset/tasty-walls-collect.md
new file mode 100644
index 00000000000..eefe4441507
--- /dev/null
+++ b/.changeset/tasty-walls-collect.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#updated Update Polygon configs to match PIP-35
diff --git a/.changeset/tasty-windows-own.md b/.changeset/tasty-windows-own.md
new file mode 100644
index 00000000000..bd81338cb4e
--- /dev/null
+++ b/.changeset/tasty-windows-own.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#bugfix balance shutdown deadlock
diff --git a/.changeset/tender-wombats-juggle.md b/.changeset/tender-wombats-juggle.md
new file mode 100644
index 00000000000..08f256f4be8
--- /dev/null
+++ b/.changeset/tender-wombats-juggle.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal topeerid should validate []byte length
diff --git a/.changeset/thick-mails-applaud.md b/.changeset/thick-mails-applaud.md
new file mode 100644
index 00000000000..ceec9e64fd4
--- /dev/null
+++ b/.changeset/thick-mails-applaud.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+Simplify how token and gas prices are stored in the database - user upsert instead of insert/delete flow #db_update
diff --git a/.changeset/thin-rings-count.md b/.changeset/thin-rings-count.md
new file mode 100644
index 00000000000..20f4b54311e
--- /dev/null
+++ b/.changeset/thin-rings-count.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+#internal Add evm Chain Reader GetLatestValue support for filtering on indexed topic types that get hashed.
diff --git a/.changeset/thirty-olives-marry.md b/.changeset/thirty-olives-marry.md
new file mode 100644
index 00000000000..8be272b9357
--- /dev/null
+++ b/.changeset/thirty-olives-marry.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Change ChainReader Block primitive field from int to string. #internal
diff --git a/.changeset/twelve-balloons-turn.md b/.changeset/twelve-balloons-turn.md
new file mode 100644
index 00000000000..f4f0e2670e9
--- /dev/null
+++ b/.changeset/twelve-balloons-turn.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal fix data race in syncer launcher
diff --git a/.changeset/two-mugs-complain.md b/.changeset/two-mugs-complain.md
new file mode 100644
index 00000000000..77cdcbfe9ec
--- /dev/null
+++ b/.changeset/two-mugs-complain.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Edited the Optimism Stack L1 Oracle to add support for Mantle #added
diff --git a/.changeset/violet-clouds-rhyme.md b/.changeset/violet-clouds-rhyme.md
new file mode 100644
index 00000000000..b6db0e85c4f
--- /dev/null
+++ b/.changeset/violet-clouds-rhyme.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Updated AutoPurge.Threshold and AutoPurge.MinAttempts configs to only be required for heuristic and added content-type header for Scroll API #internal
diff --git a/.changeset/warm-houses-build.md b/.changeset/warm-houses-build.md
new file mode 100644
index 00000000000..6ce6215a88c
--- /dev/null
+++ b/.changeset/warm-houses-build.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Added custom finality calculation for Astar #internal
diff --git a/.changeset/weak-rabbits-sell.md b/.changeset/weak-rabbits-sell.md
new file mode 100644
index 00000000000..3f0785d3d5e
--- /dev/null
+++ b/.changeset/weak-rabbits-sell.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+#internal prevent reentrancy when configuring DON in Capabilities Registry
diff --git a/.changeset/wild-seals-look.md b/.changeset/wild-seals-look.md
new file mode 100644
index 00000000000..3cd854f0e61
--- /dev/null
+++ b/.changeset/wild-seals-look.md
@@ -0,0 +1,5 @@
+---
+"chainlink": patch
+---
+
+Added new health check that ensures RPC provides new finalized heads at least every `NoNewFinalizedHeadsThreshold` #added
diff --git a/.changeset/yellow-cougars-act.md b/.changeset/yellow-cougars-act.md
new file mode 100644
index 00000000000..61ed62607a0
--- /dev/null
+++ b/.changeset/yellow-cougars-act.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Added client error classification for terminally stuck transactions in the TXM #internal
diff --git a/.changeset/young-mice-invent.md b/.changeset/young-mice-invent.md
new file mode 100644
index 00000000000..ba9c67198aa
--- /dev/null
+++ b/.changeset/young-mice-invent.md
@@ -0,0 +1,5 @@
+---
+"chainlink": minor
+---
+
+Added CCIP plugins code from https://github.com/smartcontractkit/ccip/ #added
diff --git a/.github/actions/detect-solidity-file-changes/action.yml b/.github/actions/detect-solidity-file-changes/action.yml
index 37cb871d68d..b86c91dbb4d 100644
--- a/.github/actions/detect-solidity-file-changes/action.yml
+++ b/.github/actions/detect-solidity-file-changes/action.yml
@@ -1,5 +1,5 @@
-name: 'Detect Changes Composite Action'
-description: 'Detects changes in solidity files and fails if read-only files are modified.'
+name: 'Detect Solidity File Changes Composite Action'
+description: 'Detects changes in solidity files and outputs the result.'
outputs:
changes:
description: 'Whether or not changes were detected'
@@ -19,18 +19,3 @@ runs:
- '.github/workflows/solidity.yml'
- '.github/workflows/solidity-foundry.yml'
- '.github/workflows/solidity-wrappers.yml'
- 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.changed_files.outputs.read_only_sol == 'true' }}
- shell: bash
- run: |
- echo "One or more read-only Solidity file(s) has changed."
- for file in ${{ steps.changed_files.outputs.read_only_sol_files }}; do
- echo "$file was changed"
- done
- exit 1
diff --git a/.github/actions/detect-solidity-foundry-version/action.yml b/.github/actions/detect-solidity-foundry-version/action.yml
new file mode 100644
index 00000000000..b37f1e25094
--- /dev/null
+++ b/.github/actions/detect-solidity-foundry-version/action.yml
@@ -0,0 +1,26 @@
+name: 'Detect Foundry version in GNUmakefile'
+description: 'Detects Foundry version in GNUmakefile'
+inputs:
+ working-directory:
+ description: 'The GNUmakefile directory'
+ required: false
+ default: 'contracts'
+outputs:
+ foundry-version:
+ description: 'Foundry version found in GNUmakefile'
+ value: ${{ steps.extract-foundry-version.outputs.foundry-version }}
+runs:
+ using: 'composite'
+ steps:
+ - name: Extract Foundry version
+ id: extract-foundry-version
+ shell: bash
+ working-directory: ${{ inputs.working-directory }}
+ run: |
+ foundry_version=$(grep -Eo "foundryup --version [^ ]+" GNUmakefile | awk '{print $3}')
+ if [ -z "$foundry_version" ]; then
+ echo "::error::Foundry version not found in GNUmakefile"
+ exit 1
+ fi
+ echo "Foundry version found: $foundry_version"
+ echo "foundry-version=$foundry_version" >> $GITHUB_OUTPUT
diff --git a/.github/actions/detect-solidity-readonly-file-changes/action.yml b/.github/actions/detect-solidity-readonly-file-changes/action.yml
new file mode 100644
index 00000000000..faca16d53f0
--- /dev/null
+++ b/.github/actions/detect-solidity-readonly-file-changes/action.yml
@@ -0,0 +1,31 @@
+name: 'Detect Solidity Readonly Files Changes Composite Action'
+description: 'Detects changes in readonly solidity files and fails if they are modified.'
+outputs:
+ changes:
+ description: 'Whether or not changes were detected'
+ value: ${{ steps.changed_files.outputs.src }}
+runs:
+ using: 'composite'
+ steps:
+
+ - name: Filter paths
+ uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
+ id: changed_files
+ with:
+ list-files: 'csv'
+ filters: |
+ 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.changed_files.outputs.read_only_sol == 'true' }}
+ shell: bash
+ run: |
+ echo "One or more read-only Solidity file(s) has changed."
+ for file in ${{ steps.changed_files.outputs.read_only_sol_files }}; do
+ echo "$file was changed"
+ done
+ exit 1
diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml
index f3697ed7195..ffcfeea3d0c 100644
--- a/.github/actions/golangci-lint/action.yml
+++ b/.github/actions/golangci-lint/action.yml
@@ -58,7 +58,7 @@ runs:
skip-pkg-cache: true
skip-build-cache: true
# only-new-issues is only applicable to PRs, otherwise it is always set to false
- only-new-issues: false # disabled for PRs due to unreliability
+ only-new-issues: true
args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml
working-directory: ${{ inputs.go-directory }}
- name: Print lint report artifact
diff --git a/.github/actions/goreleaser-build-sign-publish/README.md b/.github/actions/goreleaser-build-sign-publish/README.md
index d6bf7e6fd4a..189578391f5 100644
--- a/.github/actions/goreleaser-build-sign-publish/README.md
+++ b/.github/actions/goreleaser-build-sign-publish/README.md
@@ -97,13 +97,17 @@ Following inputs can be used as `step.with` keys
| Name | Type | Default | Description |
| ---------------------------- | ------ | ------------------ | ----------------------------------------------------------------------- |
-| `goreleaser-version` | String | `1.13.1` | `goreleaser` version |
-| `zig-version` | String | `0.10.0` | `zig` version |
-| `cosign-version` | String | `v1.13.1` | `cosign` version |
+| `goreleaser-version` | String | `~> v2` | `goreleaser` version |
+| `zig-version` | String | `0.10.1` | `zig` version |
+| `cosign-version` | String | `v2.2.2` | `cosign` version |
| `macos-sdk-dir` | String | `MacOSX12.3.sdk` | MacOSX sdk directory |
| `enable-docker-publish` | Bool | `true` | Enable publishing of Docker images / manifests |
| `docker-registry` | String | `localhost:5001` | Docker registry |
+| `docker-image-name` | String | `chainlink` | Docker image name |
+| `docker-image-tag` | String | `develop` | Docker image tag |
| `enable-goreleaser-snapshot` | Bool | `false` | Enable goreleaser build / release snapshot |
+| `enable-goreleaser-split` | Bool | `false` | Enable goreleaser build using split and merge |
+| `goreleaser-split-arch` | String | `""` | The arch to build the image with - amd64, arm64 |
| `goreleaser-exec` | String | `goreleaser` | The goreleaser executable, can invoke wrapper script |
| `goreleaser-config` | String | `.goreleaser.yaml` | The goreleaser configuration yaml |
| `enable-cosign` | Bool | `false` | Enable signing of Docker images |
diff --git a/.github/actions/goreleaser-build-sign-publish/action.yml b/.github/actions/goreleaser-build-sign-publish/action.yml
index f4b2111bea5..cf9da323def 100644
--- a/.github/actions/goreleaser-build-sign-publish/action.yml
+++ b/.github/actions/goreleaser-build-sign-publish/action.yml
@@ -3,7 +3,7 @@ description: A composite action that allows building and publishing signed chain
inputs:
goreleaser-version:
description: The goreleaser version
- default: 1.23.0
+ default: "~> v2"
required: false
goreleaser-key:
description: The goreleaser key
@@ -29,10 +29,13 @@ inputs:
description: The docker registry
default: localhost:5001
required: false
- # snapshot inputs
- enable-goreleaser-snapshot:
- description: Enable goreleaser build / release snapshot
- default: "false"
+ docker-image-name:
+ description: The docker image name
+ default: chainlink
+ required: false
+ docker-image-tag:
+ description: The docker image tag
+ default: develop
required: false
# goreleaser inputs
goreleaser-exec:
@@ -43,6 +46,17 @@ inputs:
description: "The goreleaser configuration yaml"
default: ".goreleaser.yaml"
required: false
+ enable-goreleaser-snapshot:
+ description: Enable goreleaser build / release snapshot
+ default: "false"
+ required: false
+ enable-goreleaser-split:
+ description: Enable goreleaser split and merge builds
+ default: "false"
+ required: false
+ goreleaser-split-arch:
+ description: The architecture to split the goreleaser build
+ required: false
# signing inputs
enable-cosign:
description: Enable signing of docker images
@@ -57,13 +71,6 @@ inputs:
cosign-password:
description: The password to decrypt the cosign private key needed to sign the image
required: false
-outputs:
- goreleaser-metadata:
- description: "Build result metadata"
- value: ${{ steps.goreleaser.outputs.metadata }}
- goreleaser-artifacts:
- description: "Build result artifacts"
- value: ${{ steps.goreleaser.outputs.artifacts }}
runs:
using: composite
steps:
@@ -76,7 +83,7 @@ runs:
with:
go-version-file: "go.mod"
- name: Setup goreleaser
- uses: goreleaser/goreleaser-action@7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8 # v5.0.0
+ uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0
with:
distribution: goreleaser-pro
install-only: true
@@ -97,14 +104,22 @@ runs:
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
with:
registry: ${{ inputs.docker-registry }}
- - name: Goreleaser release
- id: goreleaser
+ - name: Set goreleaser split env
+ if: inputs.enable-goreleaser-split == 'true'
+ shell: bash
+ run: |
+ echo "GOOS=linux" | tee -a $GITHUB_ENV
+ echo "GOARCH=${{ inputs.goreleaser-split-arch }}" | tee -a $GITHUB_ENV
+ - name: Run goreleaser release
shell: bash
env:
ENABLE_COSIGN: ${{ inputs.enable-cosign }}
ENABLE_GORELEASER_SNAPSHOT: ${{ inputs.enable-goreleaser-snapshot }}
+ ENABLE_GORELEASER_SPLIT: ${{ inputs.enable-goreleaser-split }}
ENABLE_DOCKER_PUBLISH: ${{ inputs.enable-docker-publish }}
IMAGE_PREFIX: ${{ inputs.docker-registry }}
+ IMAGE_NAME: ${{ inputs.docker-image-name }}
+ IMAGE_TAG: ${{ inputs.docker-image-tag }}
GORELEASER_EXEC: ${{ inputs.goreleaser-exec }}
GORELEASER_CONFIG: ${{ inputs.goreleaser-config }}
COSIGN_PASSWORD: ${{ inputs.cosign-password }}
diff --git a/.github/actions/goreleaser-build-sign-publish/action_utils b/.github/actions/goreleaser-build-sign-publish/action_utils
index 4aac78d6fcc..051e0763fbd 100755
--- a/.github/actions/goreleaser-build-sign-publish/action_utils
+++ b/.github/actions/goreleaser-build-sign-publish/action_utils
@@ -4,6 +4,7 @@ set -euo pipefail
ENABLE_COSIGN=${ENABLE_COSIGN:-false}
ENABLE_GORELEASER_SNAPSHOT=${ENABLE_GORELEASER_SNAPSHOT:-false}
+ENABLE_GORELEASER_SPLIT=${ENABLE_GORELEASER_SPLIT:-false}
ENABLE_DOCKER_PUBLISH=${ENABLE_DOCKER_PUBLISH:-false}
COSIGN_PASSWORD=${COSIGN_PASSWORD:-""}
GORELEASER_EXEC=${GORELEASER_EXEC:-goreleaser}
@@ -27,8 +28,12 @@ _publish_snapshot_manifests() {
local docker_manifest_extra_args=$DOCKER_MANIFEST_EXTRA_ARGS
local full_sha=$(git rev-parse HEAD)
local images=$(docker images --filter "label=org.opencontainers.image.revision=$full_sha" --format "{{.Repository}}:{{.Tag}}" | sort)
- local arches=(amd64 arm64)
local raw_manifest_lists=""
+ if [[ $ENABLE_GORELEASER_SPLIT == "true" ]]; then
+ local arches=(${GOARCH:-""})
+ else
+ local arches=(amd64 arm64)
+ fi
for image in $images; do
for arch in "${arches[@]}"; do
image=${image%"-$arch"}
@@ -51,22 +56,35 @@ _publish_snapshot_manifests() {
# wrapper function to invoke goreleaser release
goreleaser_release() {
+ goreleaser_flags=()
+
+ # set goreleaser flags
+ if [[ $ENABLE_GORELEASER_SNAPSHOT == "true" ]]; then
+ goreleaser_flags+=("--snapshot")
+ goreleaser_flags+=("--clean")
+ fi
+ if [[ $ENABLE_GORELEASER_SPLIT == "true" ]]; then
+ goreleaser_flags+=("--split")
+ fi
+ flags=$(printf "%s " "${goreleaser_flags[@]}")
+ flags=$(echo "$flags" | sed 's/ *$//')
+
if [[ $ENABLE_COSIGN == "true" ]]; then
echo "$COSIGN_PUBLIC_KEY" > cosign.pub
echo "$COSIGN_PRIVATE_KEY" > cosign.key
fi
+
if [[ -n $MACOS_SDK_DIR ]]; then
MACOS_SDK_DIR=$(echo "$(cd "$(dirname "$MACOS_SDK_DIR")" || exit; pwd)/$(basename "$MACOS_SDK_DIR")")
fi
- if [[ $ENABLE_GORELEASER_SNAPSHOT == "true" ]]; then
- $GORELEASER_EXEC release --snapshot --clean --config "$GORELEASER_CONFIG" "$@"
- if [[ $ENABLE_DOCKER_PUBLISH == "true" ]]; then
+
+ $GORELEASER_EXEC release ${flags} --config "$GORELEASER_CONFIG" "$@"
+
+ if [[ $ENABLE_DOCKER_PUBLISH == "true" ]]; then
_publish_snapshot_images
_publish_snapshot_manifests
- fi
- else
- $GORELEASER_EXEC release --clean --config "$GORELEASER_CONFIG" "$@"
fi
+
if [[ $ENABLE_COSIGN == "true" ]]; then
rm -rf cosign.pub
rm -rf cosign.key
diff --git a/.github/actions/setup-create-base64-config-ccip/action.yml b/.github/actions/setup-create-base64-config-ccip/action.yml
new file mode 100644
index 00000000000..cb20c886e38
--- /dev/null
+++ b/.github/actions/setup-create-base64-config-ccip/action.yml
@@ -0,0 +1,151 @@
+name: Create Base64 Config for CCIP Tests
+description: A composite action that creates a base64-encoded config to be used by ccip integration tests
+
+inputs:
+ runId:
+ description: The run id
+ existingNamespace:
+ description: If test needs to run against already deployed namespace
+ testLogCollect:
+ description: Whether to always collect logs, even for passing tests
+ default: "false"
+ selectedNetworks:
+ description: The networks to run tests against
+ chainlinkVersion:
+ description: The git commit sha to use for the image tag
+ upgradeVersion:
+ description: The git commit sha to use for the image tag
+ logstreamLogTargets:
+ description: Where to send logs (e.g. file, loki)
+ customEvmNodes:
+ description: Custom EVM nodes to use in key=value format, where key is chain id and value is docker image to use. If they are provided the number of networksSelected must be equal to the number of customEvmNodes
+ evmNodeLogLevel:
+ description: Log level for the custom EVM nodes
+ default: "info"
+outputs:
+ base64_config:
+ description: The base64-encoded config
+ value: ${{ steps.base64_config_override.outputs.base64_config }}
+
+runs:
+ using: composite
+ steps:
+ - name: Prepare Base64 TOML override
+ shell: bash
+ id: base64_config_override
+ env:
+ RUN_ID: ${{ inputs.runId }}
+ SELECTED_NETWORKS: ${{ inputs.selectedNetworks }}
+ EXISTING_NAMESPACE: ${{ inputs.existingNamespace }}
+ TEST_LOG_COLLECT: ${{ inputs.testLogCollect }}
+ CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }}
+ UPGRADE_VERSION: ${{ inputs.upgradeVersion }}
+ LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }}
+ CUSTOM_EVM_NODES: ${{ inputs.customEvmNodes }}
+ EVM_NODE_LOG_LEVEL: ${{ inputs.evmNodeLogLevel }}
+ run: |
+ function convert_to_toml_array() {
+ local IFS=','
+ local input_array=($1)
+ local toml_array_format="["
+
+ for element in "${input_array[@]}"; do
+ toml_array_format+="\"$element\","
+ done
+
+ toml_array_format="${toml_array_format%,}]"
+ echo "$toml_array_format"
+ }
+
+ selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS")
+ log_targets=$(convert_to_toml_array "$LOGSTREAM_LOG_TARGETS")
+
+ if [ -n "$TEST_LOG_COLLECT" ]; then
+ test_log_collect=true
+ else
+ test_log_collect=false
+ fi
+
+ # make sure the number of networks and nodes match
+ IFS=',' read -r -a networks_array <<< "$SELECTED_NETWORKS"
+ IFS=',' read -r -a nodes_array <<< "$CUSTOM_EVM_NODES"
+
+ networks_count=${#networks_array[@]}
+ nodes_count=${#nodes_array[@]}
+
+ # Initialize or clear CONFIG_TOML environment variable
+ custom_nodes_toml=""
+
+ # Check if the number of CUSTOM_EVM_NODES is zero
+ if [ $nodes_count -eq 0 ]; then
+ echo "The number of CUSTOM_EVM_NODES is zero, won't output any custom private Ethereum network configurations."
+ else
+ if [ $networks_count -ne $nodes_count ]; then
+ echo "The number of elements in SELECTED_NETWORKS (${networks_count}) and CUSTOM_EVM_NODES does not match (${nodes_count})."
+ exit 1
+ else
+ for i in "${!networks_array[@]}"; do
+ IFS='=' read -r chain_id docker_image <<< "${nodes_array[i]}"
+ custom_nodes_toml+="
+ [CCIP.Env.PrivateEthereumNetworks.${networks_array[i]}]
+ ethereum_version=\"\"
+ execution_layer=\"\"
+
+ [CCIP.Env.PrivateEthereumNetworks.${networks_array[i]}.EthereumChainConfig]
+ seconds_per_slot=3
+ slots_per_epoch=2
+ genesis_delay=15
+ validator_count=4
+ chain_id=${chain_id}
+ addresses_to_fund=[\"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266\", \"0x70997970C51812dc3A010C7d01b50e0d17dc79C8\"]
+ node_log_level=\"${EVM_NODES_LOG_LEVEL}\"
+
+ [CCIP.Env.PrivateEthereumNetworks.${networks_array[i]}.EthereumChainConfig.HardForkEpochs]
+ Deneb=500
+
+ [CCIP.Env.PrivateEthereumNetworks.${networks_array[i]}.CustomDockerImages]
+ execution_layer=\"${docker_image}\"
+ "
+ done
+ fi
+ fi
+
+ cat << EOF > config.toml
+ [CCIP]
+ [CCIP.Env]
+ EnvToConnect="$EXISTING_NAMESPACE"
+ [CCIP.Env.Network]
+ selected_networks = $selected_networks
+ [CCIP.Env.NewCLCluster]
+ [CCIP.Env.NewCLCluster.Common]
+ [CCIP.Env.NewCLCluster.Common.ChainlinkImage]
+ version="$CHAINLINK_VERSION"
+
+ $custom_nodes_toml
+
+ [CCIP.Env.Logging]
+ test_log_collect=$test_log_collect
+ run_id="$RUN_ID"
+
+ [CCIP.Env.Logging.LogStream]
+ log_targets=$log_targets
+
+ [CCIP.Groups.load]
+ TestRunName = '$EXISTING_NAMESPACE'
+
+ [CCIP.Groups.smoke]
+ TestRunName = '$EXISTING_NAMESPACE'
+
+ EOF
+
+ # Check if UPGRADE_VERSION is not empty and append to config.toml
+ if [ -n "$UPGRADE_VERSION" ]; then
+ cat << EOF >> config.toml
+ [CCIP.Env.NewCLCluster.Common.ChainlinkUpgradeImage]
+ version="$UPGRADE_VERSION"
+ EOF
+ fi
+
+ BASE64_CONFIG=$(cat config.toml | base64 -w 0)
+ echo ::add-mask::$BASE64_CONFIG
+ echo "base64_config=$BASE64_CONFIG" >> $GITHUB_OUTPUT
\ No newline at end of file
diff --git a/.github/actions/setup-slither/action.yaml b/.github/actions/setup-slither/action.yaml
new file mode 100644
index 00000000000..b8bef38575d
--- /dev/null
+++ b/.github/actions/setup-slither/action.yaml
@@ -0,0 +1,10 @@
+name: Setup Slither
+description: Installs Slither 0.10.3 for contract analysis. Requires Python 3.6 or higher.
+runs:
+ using: composite
+ steps:
+ - name: Install Slither
+ shell: bash
+ run: |
+ python -m pip install --upgrade pip
+ pip install slither-analyzer==0.10.3
diff --git a/.github/actions/setup-solc-select/action.yaml b/.github/actions/setup-solc-select/action.yaml
new file mode 100644
index 00000000000..b74ffae018d
--- /dev/null
+++ b/.github/actions/setup-solc-select/action.yaml
@@ -0,0 +1,30 @@
+name: Setup Solc Select
+description: Installs Solc Select, required versions and selects the version to use. Requires Python 3.6 or higher.
+inputs:
+ to_install:
+ description: Comma-separated list of solc versions to install
+ required: true
+ to_use:
+ description: Solc version to use
+ required: true
+
+runs:
+ using: composite
+ steps:
+ - name: Install solc-select and solc
+ shell: bash
+ run: |
+ pip3 install solc-select
+ sudo ln -s /usr/local/bin/solc-select /usr/bin/solc-select
+
+ IFS=',' read -ra versions <<< "${{ inputs.to_install }}"
+ for version in "${versions[@]}"; do
+ solc-select install $version
+ if [ $? -ne 0 ]; then
+ echo "Failed to install Solc $version"
+ exit 1
+ fi
+ done
+
+ solc-select install ${{ inputs.to_use }}
+ solc-select use ${{ inputs.to_use }}
diff --git a/.github/actions/validate-artifact-scope/action.yaml b/.github/actions/validate-artifact-scope/action.yaml
new file mode 100644
index 00000000000..7440efc63a3
--- /dev/null
+++ b/.github/actions/validate-artifact-scope/action.yaml
@@ -0,0 +1,103 @@
+name: Validate Artifact Scope
+description: Checks there are any modified Solidity files outside of the specified scope. If so, it prints a warning message, but does not fail the workflow.
+inputs:
+ product:
+ description: The product for which the artifacts are being generated
+ required: true
+ sol_files:
+ description: Comma-separated (CSV) or space-separated (shell) list of Solidity files to check
+ required: true
+
+runs:
+ using: composite
+ steps:
+ - name: Transform input array
+ id: transform_input_array
+ shell: bash
+ run: |
+ is_csv_format() {
+ local input="$1"
+ if [[ "$input" =~ "," ]]; then
+ return 0
+ else
+ return 1
+ fi
+ }
+
+ is_space_separated_string() {
+ local input="$1"
+ if [[ "$input" =~ ^[^[:space:]]+([[:space:]][^[:space:]]+)*$ ]]; then
+ return 0
+ else
+ return 1
+ fi
+ }
+
+ array="${{ inputs.sol_files }}"
+
+ if is_csv_format "$array"; then
+ echo "::debug::CSV format detected, nothing to do"
+ echo "sol_files=$array" >> $GITHUB_OUTPUT
+ exit 0
+ fi
+
+ if is_space_separated_string "$array"; then
+ echo "::debug::Space-separated format detected, converting to CSV"
+ csv_array="${array// /,}"
+ echo "sol_files=$csv_array" >> $GITHUB_OUTPUT
+ exit 0
+ fi
+
+ echo "::error::Invalid input format for sol_files. Please provide a comma-separated (CSV) or space-separated (shell) list of Solidity files"
+ exit 1
+
+ - name: Check for changes outside of artifact scope
+ shell: bash
+ run: |
+ echo "::debug::All modified contracts:"
+ echo "${{ steps.transform_input_array.outputs.sol_files }}" | tr ',' '\n'
+ if [ "${{ inputs.product }}" = "shared" ]; then
+ excluded_paths_pattern="!/^contracts\/src\/v0\.8\/interfaces/ && !/^contracts\/src\/v0\.8\/${{ inputs.product }}/ && !/^contracts\/src\/v0\.8\/[^\/]+\.sol$/"
+ else
+ excluded_paths_pattern="!/^contracts\/src\/v0\.8\/${{ inputs.product }}/"
+ fi
+ echo "::debug::Excluded paths: $excluded_paths_pattern"
+ unexpected_files=$(echo "${{ steps.transform_input_array.outputs.sol_files }}" | tr ',' '\n' | awk "$excluded_paths_pattern")
+ missing_files=""
+ set -e
+ set -o pipefail
+ if [[ -n "$unexpected_files" ]]; then
+ products=()
+ productsStr=""
+ IFS=$'\n' read -r -d '' -a files <<< "$unexpected_files" || true
+ echo "Files: ${files[@]}"
+
+ for file in "${files[@]}"; do
+ missing_files+="$file,"
+
+ product=$(echo "$file" | awk -F'src/v0.8/' '{if ($2 ~ /\//) print substr($2, 1, index($2, "/")-1); else print "shared"}')
+ if [[ ! " ${products[@]} " =~ " ${product} " ]]; then
+ products+=("$product")
+ productsStr+="$product, "
+ fi
+ done
+ productsStr=${productsStr%, }
+
+ set +e
+ set +o pipefail
+
+ missing_files=$(echo $missing_files | tr ',' '\n')
+
+ echo "Error: Found modified contracts outside of the expected scope: ${{ inputs.product }}"
+ echo "Files:"
+ echo "$missing_files"
+ echo "Action required: If you want to generate artifacts for other products ($productsStr) run this workflow again with updated configuration"
+
+ echo "# Warning!" >> $GITHUB_STEP_SUMMARY
+ echo "## Reason: Found modified contracts outside of the expected scope: ${{ inputs.product }}" >> $GITHUB_STEP_SUMMARY
+ echo "### Files:" >> $GITHUB_STEP_SUMMARY
+ echo "$missing_files" >> $GITHUB_STEP_SUMMARY
+ echo "## Action required: If you want to generate artifacts for other products ($productsStr) run this workflow again with updated configuration" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "No unexpected files found."
+ fi
diff --git a/.github/actions/validate-solidity-artifacts/action.yaml b/.github/actions/validate-solidity-artifacts/action.yaml
new file mode 100644
index 00000000000..5357a87f96b
--- /dev/null
+++ b/.github/actions/validate-solidity-artifacts/action.yaml
@@ -0,0 +1,115 @@
+name: Validate Solidity Artifacts
+description: Checks whether Slither reports and UML diagrams were generated for all necessary files. If not, a warning is printed in job summary, but the job is not marked as failed.
+inputs:
+ slither_reports_path:
+ description: Path to the Slither reports directory (without trailing slash)
+ required: true
+ uml_diagrams_path:
+ description: Path to the UML diagrams directory (without trailing slash)
+ required: true
+ validate_slither_reports:
+ description: Whether Slither reports should be validated
+ required: true
+ validate_uml_diagrams:
+ description: Whether UML diagrams should be validated
+ required: true
+ sol_files:
+ description: Comma-separated (CSV) or space-separated (shell) list of Solidity files to check
+ required: true
+
+runs:
+ using: composite
+ steps:
+ - name: Transform input array
+ id: transform_input_array
+ shell: bash
+ run: |
+ is_csv_format() {
+ local input="$1"
+ if [[ "$input" =~ "," ]]; then
+ return 0
+ else
+ return 1
+ fi
+ }
+
+ is_space_separated_string() {
+ local input="$1"
+ if [[ "$input" =~ ^[^[:space:]]+([[:space:]][^[:space:]]+)*$ ]]; then
+ return 0
+ else
+ return 1
+ fi
+ }
+
+ array="${{ inputs.sol_files }}"
+
+ if is_csv_format "$array"; then
+ echo "::debug::CSV format detected, nothing to do"
+ echo "sol_files=$array" >> $GITHUB_OUTPUT
+ exit 0
+ fi
+
+ if is_space_separated_string "$array"; then
+ echo "::debug::Space-separated format detected, converting to CSV"
+ csv_array="${array// /,}"
+ echo "sol_files=$csv_array" >> $GITHUB_OUTPUT
+ exit 0
+ fi
+
+ echo "::error::Invalid input format for sol_files. Please provide a comma-separated (CSV) or space-separated (shell) list of Solidity files"
+ exit 1
+
+ - name: Validate UML diagrams
+ if: ${{ inputs.validate_uml_diagrams == 'true' }}
+ shell: bash
+ run: |
+ echo "Validating UML diagrams"
+ IFS=',' read -r -a modified_files <<< "${{ steps.transform_input_array.outputs.sol_files }}"
+ missing_svgs=()
+ for file in "${modified_files[@]}"; do
+ svg_file="$(basename "${file%.sol}").svg"
+ if [ ! -f "${{ inputs.uml_diagrams_path }}/$svg_file" ]; then
+ echo "Error: UML diagram for $file not found"
+ missing_svgs+=("$file")
+ fi
+ done
+
+ if [ ${#missing_svgs[@]} -gt 0 ]; then
+ echo "Error: Missing UML diagrams for files: ${missing_svgs[@]}"
+ echo "# Warning!" >> $GITHUB_STEP_SUMMARY
+ echo "## Reason: Missing UML diagrams for files:" >> $GITHUB_STEP_SUMMARY
+ for file in "${missing_svgs[@]}"; do
+ echo " $file" >> $GITHUB_STEP_SUMMARY
+ done
+ echo "## Action required: Please try to generate artifacts for them locally or using a different tool" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "All UML diagrams generated successfully"
+ fi
+
+ - name: Validate Slither reports
+ if: ${{ inputs.validate_slither_reports == 'true' }}
+ shell: bash
+ run: |
+ echo "Validating Slither reports"
+ IFS=',' read -r -a modified_files <<< "${{ steps.transform_input_array.outputs.sol_files }}"
+ missing_reports=()
+ for file in "${modified_files[@]}"; do
+ report_file="$(basename "${file%.sol}")-slither-report.md"
+ if [ ! -f "${{ inputs.slither_reports_path }}/$report_file" ]; then
+ echo "Error: Slither report for $file not found"
+ missing_reports+=("$file")
+ fi
+ done
+
+ if [ ${#missing_reports[@]} -gt 0 ]; then
+ echo "Error: Missing Slither reports for files: ${missing_reports[@]}"
+ echo "# Warning!" >> $GITHUB_STEP_SUMMARY
+ echo "## Reason: Missing Slither reports for files:" >> $GITHUB_STEP_SUMMARY
+ for file in "${missing_reports[@]}"; do
+ echo " $file" >> $GITHUB_STEP_SUMMARY
+ done
+ echo "## Action required: Please try to generate artifacts for them locally" >> $GITHUB_STEP_SUMMARY
+ else
+ echo "All Slither reports generated successfully"
+ fi
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index cdb1d4fe2f5..cea4f07b90d 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,17 +1,17 @@
version: 2
updates:
- package-ecosystem: gomod
- directory: '/'
+ directory: "/"
schedule:
interval: monthly
- open-pull-requests-limit: 10
+ open-pull-requests-limit: 0
ignore:
# Old versions are pinned for libocr.
- dependency-name: github.com/libp2p/go-libp2p-core
- dependency-name: github.com/libp2p/go-libp2p-peerstore
- dependency-name: github.com/multiformats/go-multiaddr
- package-ecosystem: npm
- directory: '/'
+ directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 0
@@ -24,7 +24,7 @@ updates:
versions:
- 4.17.21
- package-ecosystem: github-actions
- directory: '/'
+ directory: "/"
schedule:
- interval: daily
- open-pull-requests-limit: 10
+ interval: monthly
+ open-pull-requests-limit: 0
diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml
index 0d92d1900dc..3f5c531cfd2 100644
--- a/.github/e2e-tests.yml
+++ b/.github/e2e-tests.yml
@@ -3,491 +3,472 @@
# Each entry in this file includes the following:
# - The GitHub runner (runs_on field) that will execute tests.
# - The tests that will be run by the runner.
-# - The workflows (e.g., Run PR E2E Tests, Run Nightly E2E Tests) that should trigger these tests.
+# - The workflows (e.g., Run PR E2E Tests, Nightly E2E Tests) that should trigger these tests.
#
runner-test-matrix:
# START: OCR tests
# Example of 1 runner for all tests in integration-tests/smoke/ocr_test.go
- - id: integration-tests/smoke/ocr_test.go:*
+ - id: smoke/ocr_test.go:*
path: integration-tests/smoke/ocr_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/ocr_test.go -timeout 30m -count=1 -test.parallel=2 -json
pyroscope_env: ci-smoke-ocr-evm-simulated
- # Example of 2 separate runners for the same test file but different tests. Can be used if tests if are too heavy to run on the same runner
- - id: integration-tests/smoke/ocr2_test.go:^TestOCRv2Request$
- path: integration-tests/smoke/ocr2_test.go
- test_env_type: docker
- runs_on: ubuntu-latest
- workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
- test_cmd: cd integration-tests/ && go test smoke/ocr2_test.go -test.run ^TestOCRv2Request$ -test.parallel=1 -timeout 30m -count=1 -json
- pyroscope_env: ci-smoke-ocr2-evm-simulated-nightly
-
- - id: integration-tests/smoke/ocr2_test.go:^TestOCRv2Basic$
- path: integration-tests/smoke/ocr2_test.go
- test_env_type: docker
- runs_on: ubuntu-latest
- workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
- test_cmd: cd integration-tests/ && go test smoke/ocr2_test.go -test.run ^TestOCRv2Basic$ -test.parallel=1 -timeout 30m -count=1 -json
- pyroscope_env: ci-smoke-ocr2-evm-simulated-nightly
-
# Example of a configuration for running a single soak test in Kubernetes Remote Runner
- - id: integration-tests/soak/ocr_test.go:^TestOCRv1Soak$
+ - id: soak/ocr_test.go:^TestOCRv1Soak$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestOCRv1Soak$ -test.parallel=1 -timeout 30m -count=1 -json
- test_inputs:
- test_suite: soak
+ test_config_override_required: true
+ test_secrets_required: true
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestOCRv2Soak$
+ - id: soak/ocr_test.go:^TestOCRv2Soak$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestOCRv2Soak$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestForwarderOCRv1Soak$
+ - id: soak/ocr_test.go:^TestForwarderOCRv1Soak$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestForwarderOCRv1Soak$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestForwarderOCRv2Soak$
+ - id: soak/ocr_test.go:^TestForwarderOCRv2Soak$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestForwarderOCRv2Soak$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestOCRSoak_GethReorgBelowFinality_FinalityTagDisabled$
+ - id: soak/ocr_test.go:^TestOCRSoak_GethReorgBelowFinality_FinalityTagDisabled$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestOCRSoak_GethReorgBelowFinality_FinalityTagDisabled$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestOCRSoak_GethReorgBelowFinality_FinalityTagEnabled$
+ - id: soak/ocr_test.go:^TestOCRSoak_GethReorgBelowFinality_FinalityTagEnabled$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestOCRSoak_GethReorgBelowFinality_FinalityTagEnabled$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestOCRSoak_GasSpike$
+ - id: soak/ocr_test.go:^TestOCRSoak_GasSpike$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestOCRSoak_GasSpike$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestOCRSoak_ChangeBlockGasLimit$
+ - id: soak/ocr_test.go:^TestOCRSoak_ChangeBlockGasLimit$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestOCRSoak_ChangeBlockGasLimit$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestOCRSoak_RPCDownForAllCLNodes$
+ - id: soak/ocr_test.go:^TestOCRSoak_RPCDownForAllCLNodes$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestOCRSoak_RPCDownForAllCLNodes$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/soak/ocr_test.go:^TestOCRSoak_RPCDownForHalfCLNodes$
+ - id: soak/ocr_test.go:^TestOCRSoak_RPCDownForHalfCLNodes$
path: integration-tests/soak/ocr_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
test_cmd: cd integration-tests/ && go test soak/ocr_test.go -v -test.run ^TestOCRSoak_RPCDownForHalfCLNodes$ -test.parallel=1 -timeout 30m -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: soak
+ test_env_vars:
+ TEST_SUITE: soak
- - id: integration-tests/smoke/forwarder_ocr_test.go:*
+ - id: smoke/forwarder_ocr_test.go:*
path: integration-tests/smoke/forwarder_ocr_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/forwarder_ocr_test.go -timeout 30m -count=1 -test.parallel=2 -json
pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated
- - id: integration-tests/smoke/forwarders_ocr2_test.go:*
+ - id: smoke/forwarders_ocr2_test.go:*
path: integration-tests/smoke/forwarders_ocr2_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/forwarders_ocr2_test.go -timeout 30m -count=1 -test.parallel=2 -json
pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated
- - id: integration-tests/smoke/ocr2_test.go:*
+ - id: smoke/ocr2_test.go:*
path: integration-tests/smoke/ocr2_test.go
test_env_type: docker
runs_on: ubuntu22.04-16cores-64GB
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/ocr2_test.go -timeout 30m -count=1 -test.parallel=6 -json
pyroscope_env: ci-smoke-ocr2-evm-simulated
- - id: integration-tests/smoke/ocr2_test.go:*-plugins
+ - id: smoke/ocr2_test.go:*-plugins
path: integration-tests/smoke/ocr2_test.go
test_env_type: docker
runs_on: ubuntu22.04-16cores-64GB
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/ocr2_test.go -timeout 30m -count=1 -test.parallel=6 -json
pyroscope_env: ci-smoke-ocr2-plugins-evm-simulated
- test_inputs:
- # chainlink_version: '{{ env.GITHUB_SHA_PLUGINS }}' # This is the chainlink version that has the plugins
- chainlink_version: develop-plugins
+ test_env_vars:
+ E2E_TEST_CHAINLINK_VERSION: '{{ env.DEFAULT_CHAINLINK_PLUGINS_VERSION }}' # This is the chainlink version that has the plugins
+ ENABLE_OTEL_TRACES: true
# END: OCR tests
# START: Automation tests
- - id: integration-tests/smoke/automation_test.go:^TestAutomationBasic/registry_2_0|TestAutomationBasic/registry_2_1_conditional|TestAutomationBasic/registry_2_1_logtrigger$
+ - id: smoke/automation_test.go:^TestAutomationBasic/registry_2_0|TestAutomationBasic/registry_2_1_conditional|TestAutomationBasic/registry_2_1_logtrigger$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run "^TestAutomationBasic/registry_2_0|TestAutomationBasic/registry_2_1_conditional|TestAutomationBasic/registry_2_1_logtrigger$" -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationBasic/registry_2_1_with_mercury_v02|TestAutomationBasic/registry_2_1_with_mercury_v03|TestAutomationBasic/registry_2_1_with_logtrigger_and_mercury_v02$
+ - id: smoke/automation_test.go:^TestAutomationBasic/registry_2_1_with_mercury_v02|TestAutomationBasic/registry_2_1_with_mercury_v03|TestAutomationBasic/registry_2_1_with_logtrigger_and_mercury_v02$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run "^TestAutomationBasic/registry_2_1_with_mercury_v02|TestAutomationBasic/registry_2_1_with_mercury_v03|TestAutomationBasic/registry_2_1_with_logtrigger_and_mercury_v02$" -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationBasic/registry_2_2_conditional|TestAutomationBasic/registry_2_2_logtrigger|TestAutomationBasic/registry_2_2_with_mercury_v02$
+ - id: smoke/automation_test.go:^TestAutomationBasic/registry_2_2_conditional|TestAutomationBasic/registry_2_2_logtrigger|TestAutomationBasic/registry_2_2_with_mercury_v02$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run "^TestAutomationBasic/registry_2_2_conditional|TestAutomationBasic/registry_2_2_logtrigger|TestAutomationBasic/registry_2_2_with_mercury_v02$" -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationBasic/registry_2_2_with_mercury_v03|TestAutomationBasic/registry_2_2_with_logtrigger_and_mercury_v02$
+ - id: smoke/automation_test.go:^TestAutomationBasic/registry_2_2_with_mercury_v03|TestAutomationBasic/registry_2_2_with_logtrigger_and_mercury_v02$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run "^TestAutomationBasic/registry_2_2_with_mercury_v03|TestAutomationBasic/registry_2_2_with_logtrigger_and_mercury_v02$" -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationBasic/registry_2_3_conditional_native|TestAutomationBasic/registry_2_3_conditional_link$
+ - id: smoke/automation_test.go:^TestAutomationBasic/registry_2_3_conditional_native|TestAutomationBasic/registry_2_3_conditional_link$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
- test_cmd: cd integration-tests/smoke && go test -test.run "^TestAutomationBasic/registry_2_3_conditional_native|TestAutomationBasic/registry_2_3_conditional_link$" -test.parallel=3 -timeout 30m -count=1 -json
+ - PR E2E Core Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/smoke && go test -test.run "^TestAutomationBasic/registry_2_3_conditional_native|TestAutomationBasic/registry_2_3_conditional_link$" -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationBasic/registry_2_3_logtrigger_native|TestAutomationBasic/registry_2_3_logtrigger_link$
+ - id: smoke/automation_test.go:^TestAutomationBasic/registry_2_3_logtrigger_native|TestAutomationBasic/registry_2_3_logtrigger_link$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run "^TestAutomationBasic/registry_2_3_logtrigger_native|TestAutomationBasic/registry_2_3_logtrigger_link$" -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationBasic/registry_2_3_with_mercury_v03_link|TestAutomationBasic/registry_2_3_with_logtrigger_and_mercury_v02_link$
+ - id: smoke/automation_test.go:^TestAutomationBasic/registry_2_3_with_mercury_v03_link|TestAutomationBasic/registry_2_3_with_logtrigger_and_mercury_v02_link$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run "^TestAutomationBasic/registry_2_3_with_mercury_v03_link|TestAutomationBasic/registry_2_3_with_logtrigger_and_mercury_v02_link$" -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestSetUpkeepTriggerConfig$
+ - id: smoke/automation_test.go:^TestSetUpkeepTriggerConfig$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestSetUpkeepTriggerConfig$ -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationAddFunds$
+ - id: smoke/automation_test.go:^TestAutomationAddFunds$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationAddFunds$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationPauseUnPause$
+ - id: smoke/automation_test.go:^TestAutomationPauseUnPause$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationPauseUnPause$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationRegisterUpkeep$
+ - id: smoke/automation_test.go:^TestAutomationRegisterUpkeep$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationRegisterUpkeep$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationPauseRegistry$
+ - id: smoke/automation_test.go:^TestAutomationPauseRegistry$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationPauseRegistry$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationKeeperNodesDown$
+ - id: smoke/automation_test.go:^TestAutomationKeeperNodesDown$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationKeeperNodesDown$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationPerformSimulation$
+ - id: smoke/automation_test.go:^TestAutomationPerformSimulation$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationPerformSimulation$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestAutomationCheckPerformGasLimit$
+ - id: smoke/automation_test.go:^TestAutomationCheckPerformGasLimit$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationCheckPerformGasLimit$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestUpdateCheckData$
+ - id: smoke/automation_test.go:^TestUpdateCheckData$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestUpdateCheckData$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/automation_test.go:^TestSetOffchainConfigWithMaxGasPrice$
+ - id: smoke/automation_test.go:^TestSetOffchainConfigWithMaxGasPrice$
path: integration-tests/smoke/automation_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestSetOffchainConfigWithMaxGasPrice$ -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-automation-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperBasicSmoke$
+ - id: smoke/keeper_test.go:^TestKeeperBasicSmoke$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperBasicSmoke$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperBlockCountPerTurn$
+ - id: smoke/keeper_test.go:^TestKeeperBlockCountPerTurn$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperBlockCountPerTurn$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperSimulation$
+ - id: smoke/keeper_test.go:^TestKeeperSimulation$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperSimulation$ -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperCheckPerformGasLimit$
+ - id: smoke/keeper_test.go:^TestKeeperCheckPerformGasLimit$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
- test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperCheckPerformGasLimit$ -test.parallel=3 -timeout 30m -count=1 -json
+ - PR E2E Core Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperCheckPerformGasLimit$ -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperRegisterUpkeep$
+ - id: smoke/keeper_test.go:^TestKeeperRegisterUpkeep$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperRegisterUpkeep$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperAddFunds$
+ - id: smoke/keeper_test.go:^TestKeeperAddFunds$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperAddFunds$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperRemove$
+ - id: smoke/keeper_test.go:^TestKeeperRemove$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperRemove$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperPauseRegistry$
+ - id: smoke/keeper_test.go:^TestKeeperPauseRegistry$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperPauseRegistry$ -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperMigrateRegistry$
+ - id: smoke/keeper_test.go:^TestKeeperMigrateRegistry$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperMigrateRegistry$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperNodeDown$
+ - id: smoke/keeper_test.go:^TestKeeperNodeDown$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperNodeDown$ -test.parallel=3 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperPauseUnPauseUpkeep$
+ - id: smoke/keeper_test.go:^TestKeeperPauseUnPauseUpkeep$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperPauseUnPauseUpkeep$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperUpdateCheckData$
+ - id: smoke/keeper_test.go:^TestKeeperUpdateCheckData$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperUpdateCheckData$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/smoke/keeper_test.go:^TestKeeperJobReplacement$
+ - id: smoke/keeper_test.go:^TestKeeperJobReplacement$
path: integration-tests/smoke/keeper_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestKeeperJobReplacement$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-keeper-evm-simulated
- - id: integration-tests/load/automationv2_1/automationv2_1_test.go:TestLogTrigger
+ - id: load/automationv2_1/automationv2_1_test.go:TestLogTrigger
path: integration-tests/load/automationv2_1/automationv2_1_test.go
runs_on: ubuntu-latest
test_env_type: k8s-remote-runner
@@ -495,93 +476,127 @@ runner-test-matrix:
remote_runner_memory: 4Gi
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_suite: automationv2_1
+ test_env_vars:
+ TEST_SUITE: automationv2_1
workflows:
- Automation Load Test
pyroscope_env: automation-load-test
- - id: integration-tests/smoke/automation_upgrade_test.go:^TestAutomationNodeUpgrade/registry_2_0
+ - id: smoke/automation_upgrade_test.go:^TestAutomationNodeUpgrade/registry_2_0
path: integration-tests/smoke/automation_upgrade_test.go
test_env_type: docker
runs_on: ubuntu22.04-8cores-32GB
workflows:
- Run Automation Product Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationNodeUpgrade/registry_2_0 -test.parallel=1 -timeout 60m -count=1 -json
- test_inputs:
- chainlink_image: public.ecr.aws/chainlink/chainlink
- chainlink_version: latest
- chainlink_upgrade_image: '{{ env.QA_CHAINLINK_IMAGE }}'
- chainlink_upgrade_version: develop
+ test_env_vars:
+ E2E_TEST_CHAINLINK_IMAGE: public.ecr.aws/chainlink/chainlink
+ E2E_TEST_CHAINLINK_VERSION: latest
+ E2E_TEST_CHAINLINK_UPGRADE_IMAGE: '{{ env.QA_CHAINLINK_IMAGE }}'
+ E2E_TEST_CHAINLINK_UPGRADE_VERSION: develop
pyroscope_env: ci-smoke-automation-upgrade-tests
- - id: integration-tests/smoke/automation_upgrade_test.go:^TestAutomationNodeUpgrade/registry_2_1
+ - id: smoke/automation_upgrade_test.go:^TestAutomationNodeUpgrade/registry_2_1
path: integration-tests/smoke/automation_upgrade_test.go
test_env_type: docker
runs_on: ubuntu22.04-8cores-32GB
workflows:
- Run Automation Product Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationNodeUpgrade/registry_2_1 -test.parallel=5 -timeout 60m -count=1 -json
- test_inputs:
- chainlink_image: public.ecr.aws/chainlink/chainlink
- chainlink_version: latest
- chainlink_upgrade_image: '{{ env.QA_CHAINLINK_IMAGE }}'
- chainlink_upgrade_version: develop
+ test_env_vars:
+ E2E_TEST_CHAINLINK_IMAGE: public.ecr.aws/chainlink/chainlink
+ E2E_TEST_CHAINLINK_VERSION: latest
+ E2E_TEST_CHAINLINK_UPGRADE_IMAGE: '{{ env.QA_CHAINLINK_IMAGE }}'
+ E2E_TEST_CHAINLINK_UPGRADE_VERSION: develop
pyroscope_env: ci-smoke-automation-upgrade-tests
- - id: integration-tests/smoke/automation_upgrade_test.go:^TestAutomationNodeUpgrade/registry_2_2
+ - id: smoke/automation_upgrade_test.go:^TestAutomationNodeUpgrade/registry_2_2
path: integration-tests/smoke/automation_upgrade_test.go
test_env_type: docker
runs_on: ubuntu22.04-8cores-32GB
workflows:
- Run Automation Product Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestAutomationNodeUpgrade/registry_2_2 -test.parallel=5 -timeout 60m -count=1 -json
- test_inputs:
- chainlink_image: public.ecr.aws/chainlink/chainlink
- chainlink_version: latest
- chainlink_upgrade_image: '{{ env.QA_CHAINLINK_IMAGE }}'
- chainlink_upgrade_version: develop
+ test_env_vars:
+ E2E_TEST_CHAINLINK_IMAGE: public.ecr.aws/chainlink/chainlink
+ E2E_TEST_CHAINLINK_VERSION: latest
+ E2E_TEST_CHAINLINK_UPGRADE_IMAGE: '{{ env.QA_CHAINLINK_IMAGE }}'
+ E2E_TEST_CHAINLINK_UPGRADE_VERSION: develop
pyroscope_env: ci-smoke-automation-upgrade-tests
- - id: integration-tests/reorg/automation_reorg_test.go
+ - id: reorg/automation_reorg_test.go^TestAutomationReorg/registry_2_0
path: integration-tests/reorg/automation_reorg_test.go
runs_on: ubuntu-latest
- test_env_type: k8s-remote-runner
- test_inputs:
- test_suite: reorg
+ test_env_type: docker
+ test_env_vars:
+ TEST_SUITE: reorg
+ workflows:
+ - Run Automation On Demand Tests (TEST WORKFLOW)
+ test_cmd: cd integration-tests/reorg && DETACH_RUNNER=false go test -v -test.run ^TestAutomationReorg/registry_2_0 -test.parallel=1 -timeout 30m -count=1 -json
+ pyroscope_env: ci-automation-on-demand-reorg
+
+ - id: reorg/automation_reorg_test.go^TestAutomationReorg/registry_2_1
+ path: integration-tests/reorg/automation_reorg_test.go
+ runs_on: ubuntu-latest
+ test_env_type: docker
+ test_env_vars:
+ TEST_SUITE: reorg
workflows:
- Run Automation On Demand Tests (TEST WORKFLOW)
- test_cmd: cd integration-tests/reorg && DETACH_RUNNER=false go test -v -test.run ^TestAutomationReorg$ -test.parallel=7 -timeout 60m -count=1 -json
+ test_cmd: cd integration-tests/reorg && DETACH_RUNNER=false go test -v -test.run ^TestAutomationReorg/registry_2_1 -test.parallel=2 -timeout 30m -count=1 -json
pyroscope_env: ci-automation-on-demand-reorg
- - id: integration-tests/chaos/automation_chaos_test.go
+ - id: reorg/automation_reorg_test.go^TestAutomationReorg/registry_2_2
+ path: integration-tests/reorg/automation_reorg_test.go
+ runs_on: ubuntu-latest
+ test_env_type: docker
+ test_env_vars:
+ TEST_SUITE: reorg
+ workflows:
+ - Run Automation On Demand Tests (TEST WORKFLOW)
+ test_cmd: cd integration-tests/reorg && DETACH_RUNNER=false go test -v -test.run ^TestAutomationReorg/registry_2_2 -test.parallel=2 -timeout 30m -count=1 -json
+ pyroscope_env: ci-automation-on-demand-reorg
+
+ - id: reorg/automation_reorg_test.go^TestAutomationReorg/registry_2_3
+ path: integration-tests/reorg/automation_reorg_test.go
+ runs_on: ubuntu-latest
+ test_env_type: docker
+ test_env_vars:
+ TEST_SUITE: reorg
+ workflows:
+ - Run Automation On Demand Tests (TEST WORKFLOW)
+ test_cmd: cd integration-tests/reorg && DETACH_RUNNER=false go test -v -test.run ^TestAutomationReorg/registry_2_3 -test.parallel=2 -timeout 30m -count=1 -json
+ pyroscope_env: ci-automation-on-demand-reorg
+
+ - id: chaos/automation_chaos_test.go
path: integration-tests/chaos/automation_chaos_test.go
test_env_type: k8s-remote-runner
runs_on: ubuntu-latest
workflows:
- Run Automation On Demand Tests (TEST WORKFLOW)
- test_cmd: cd integration-tests/chaos && DETACH_RUNNER=false go test -v -test.run ^TestAutomationChaos$ -test.parallel=15 -timeout 60m -count=1 -json
+ test_cmd: cd integration-tests/chaos && DETACH_RUNNER=false go test -v -test.run ^TestAutomationChaos$ -test.parallel=20 -timeout 60m -count=1 -json
pyroscope_env: ci-automation-on-demand-chaos
- test_inputs:
- test_suite: chaos
+ test_env_vars:
+ TEST_SUITE: chaos
- - id: integration-tests/benchmark/keeper_test.go:^TestAutomationBenchmark$
+ - id: benchmark/keeper_test.go:^TestAutomationBenchmark$
path: integration-tests/benchmark/keeper_test.go
test_env_type: k8s-remote-runner
remote_runner_memory: 4Gi
runs_on: ubuntu-latest
# workflows:
- # - Run Nightly E2E Tests
+ # - Nightly E2E Tests
test_cmd: cd integration-tests/benchmark && go test -v -test.run ^TestAutomationBenchmark$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-benchmark-automation-nightly
- test_inputs:
- test_suite: benchmark
+ test_env_vars:
+ TEST_SUITE: benchmark
+ TEST_TYPE: benchmark
# END: Automation tests
# START: VRF tests
- - id: integration-tests/smoke/vrfv2_test.go:TestVRFv2Basic
+ - id: smoke/vrfv2_test.go:TestVRFv2Basic
path: integration-tests/smoke/vrfv2_test.go
runs_on: ubuntu22.04-8cores-32GB
test_env_type: docker
@@ -591,55 +606,55 @@ runner-test-matrix:
workflows:
- On Demand VRFV2 Smoke Test (Ethereum clients)
- - id: integration-tests/load/vrfv2plus/vrfv2plus_test.go:^TestVRFV2PlusPerformance$Smoke
+ - id: load/vrfv2plus/vrfv2plus_test.go:^TestVRFV2PlusPerformance$Smoke
path: integration-tests/load/vrfv2plus/vrfv2plus_test.go
runs_on: ubuntu22.04-8cores-32GB
test_env_type: docker
test_cmd: cd integration-tests/load/vrfv2plus && go test -v -test.run ^TestVRFV2PlusPerformance$ -test.parallel=1 -timeout 24h -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_type: Smoke
+ test_env_vars:
+ TEST_TYPE: Smoke
workflows:
- On Demand VRFV2 Plus Performance Test
- - id: integration-tests/load/vrfv2plus/vrfv2plus_test.go:^TestVRFV2PlusBHSPerformance$Smoke
+ - id: load/vrfv2plus/vrfv2plus_test.go:^TestVRFV2PlusBHSPerformance$Smoke
path: integration-tests/load/vrfv2plus/vrfv2plus_test.go
runs_on: ubuntu22.04-8cores-32GB
test_env_type: docker
test_cmd: cd integration-tests/load/vrfv2plus && go test -v -test.run ^TestVRFV2PlusBHSPerformance$ -test.parallel=1 -timeout 24h -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_type: Smoke
+ test_env_vars:
+ TEST_TYPE: Smoke
workflows:
- On Demand VRFV2 Plus Performance Test
- - id: integration-tests/load/vrfv2/vrfv2_test.go:^TestVRFV2Performance$Smoke
+ - id: load/vrfv2/vrfv2_test.go:^TestVRFV2Performance$Smoke
path: integration-tests/load/vrfv2/vrfv2_test.go
runs_on: ubuntu22.04-8cores-32GB
test_env_type: docker
test_cmd: cd integration-tests/load/vrfv2 && go test -v -test.run ^TestVRFV2Performance$ -test.parallel=1 -timeout 24h -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_type: Smoke
+ test_env_vars:
+ TEST_TYPE: Smoke
workflows:
- On Demand VRFV2 Performance Test
- - id: integration-tests/load/vrfv2/vrfv2_test.go:^TestVRFV2PlusBHSPerformance$Smoke
+ - id: load/vrfv2/vrfv2_test.go:^TestVRFV2PlusBHSPerformance$Smoke
path: integration-tests/load/vrfv2/vrfv2_test.go
runs_on: ubuntu22.04-8cores-32GB
test_env_type: docker
test_cmd: cd integration-tests/load/vrfv2 && go test -v -test.run ^TestVRFV2PlusBHSPerformance$ -test.parallel=1 -timeout 24h -count=1 -json
test_config_override_required: true
test_secrets_required: true
- test_inputs:
- test_type: Smoke
+ test_env_vars:
+ TEST_TYPE: Smoke
workflows:
- On Demand VRFV2 Performance Test
- - id: integration-tests/smoke/vrfv2plus_test.go:^TestVRFv2Plus$/^Link_Billing$
+ - id: smoke/vrfv2plus_test.go:^TestVRFv2Plus$/^Link_Billing$
path: integration-tests/smoke/vrfv2plus_test.go
runs_on: ubuntu22.04-8cores-32GB
test_env_type: docker
@@ -649,33 +664,33 @@ runner-test-matrix:
workflows:
- On Demand VRFV2Plus Smoke Test (Ethereum clients)
- - id: integration-tests/smoke/vrf_test.go:*
+ - id: smoke/vrf_test.go:*
path: integration-tests/smoke/vrf_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/vrf_test.go -timeout 30m -count=1 -test.parallel=2 -json
pyroscope_env: ci-smoke-vrf-evm-simulated
- - id: integration-tests/smoke/vrfv2_test.go:*
+ - id: smoke/vrfv2_test.go:*
path: integration-tests/smoke/vrfv2_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/vrfv2_test.go -timeout 30m -count=1 -test.parallel=6 -json
pyroscope_env: ci-smoke-vrf2-evm-simulated
- - id: integration-tests/smoke/vrfv2plus_test.go:*
+ - id: smoke/vrfv2plus_test.go:*
path: integration-tests/smoke/vrfv2plus_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/vrfv2plus_test.go -timeout 30m -count=1 -test.parallel=9 -json
pyroscope_env: ci-smoke-vrf2plus-evm-simulated
@@ -683,83 +698,83 @@ runner-test-matrix:
# START: LogPoller tests
- - id: integration-tests/smoke/log_poller_test.go:^TestLogPollerFewFiltersFixedDepth$
+ - id: smoke/log_poller_test.go:^TestLogPollerFewFiltersFixedDepth$
path: integration-tests/smoke/log_poller_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestLogPollerFewFiltersFixedDepth$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-log_poller-evm-simulated
- - id: integration-tests/smoke/log_poller_test.go:^TestLogPollerFewFiltersFinalityTag$
+ - id: smoke/log_poller_test.go:^TestLogPollerFewFiltersFinalityTag$
path: integration-tests/smoke/log_poller_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestLogPollerFewFiltersFinalityTag$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-log_poller-evm-simulated
- - id: integration-tests/smoke/log_poller_test.go:^TestLogPollerWithChaosFixedDepth$
+ - id: smoke/log_poller_test.go:^TestLogPollerWithChaosFixedDepth$
path: integration-tests/smoke/log_poller_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestLogPollerWithChaosFixedDepth$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-log_poller-evm-simulated
- - id: integration-tests/smoke/log_poller_test.go:^TestLogPollerWithChaosFinalityTag$
+ - id: smoke/log_poller_test.go:^TestLogPollerWithChaosFinalityTag$
path: integration-tests/smoke/log_poller_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestLogPollerWithChaosFinalityTag$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-log_poller-evm-simulated
- - id: integration-tests/smoke/log_poller_test.go:^TestLogPollerWithChaosPostgresFinalityTag$
+ - id: smoke/log_poller_test.go:^TestLogPollerWithChaosPostgresFinalityTag$
path: integration-tests/smoke/log_poller_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestLogPollerWithChaosPostgresFinalityTag$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-log_poller-evm-simulated
- - id: integration-tests/smoke/log_poller_test.go:^TestLogPollerWithChaosPostgresFixedDepth$
+ - id: smoke/log_poller_test.go:^TestLogPollerWithChaosPostgresFixedDepth$
path: integration-tests/smoke/log_poller_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestLogPollerWithChaosPostgresFixedDepth$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-log_poller-evm-simulated
- - id: integration-tests/smoke/log_poller_test.go:^TestLogPollerReplayFixedDepth$
+ - id: smoke/log_poller_test.go:^TestLogPollerReplayFixedDepth$
path: integration-tests/smoke/log_poller_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestLogPollerReplayFixedDepth$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-log_poller-evm-simulated
- - id: integration-tests/smoke/log_poller_test.go:^TestLogPollerReplayFinalityTag$
+ - id: smoke/log_poller_test.go:^TestLogPollerReplayFinalityTag$
path: integration-tests/smoke/log_poller_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/smoke && go test -test.run ^TestLogPollerReplayFinalityTag$ -test.parallel=1 -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-log_poller-evm-simulated
@@ -767,58 +782,186 @@ runner-test-matrix:
# START: Other tests
- - id: integration-tests/smoke/runlog_test.go:*
+ - id: smoke/runlog_test.go:*
path: integration-tests/smoke/runlog_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
- test_cmd: cd integration-tests/ && go test smoke/runlog_test.go -timeout 30m -count=1 -json
+ - PR E2E Core Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ && go test smoke/runlog_test.go -timeout 30m -test.parallel=2 -count=1 -json
pyroscope_env: ci-smoke-runlog-evm-simulated
- - id: integration-tests/smoke/cron_test.go:*
+ - id: smoke/cron_test.go:*
path: integration-tests/smoke/cron_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/cron_test.go -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-cron-evm-simulated
- - id: integration-tests/smoke/flux_test.go:*
+ - id: smoke/flux_test.go:*
path: integration-tests/smoke/flux_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/flux_test.go -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-flux-evm-simulated
- - id: integration-tests/smoke/reorg_above_finality_test.go:*
+ - id: smoke/reorg_above_finality_test.go:*
path: integration-tests/smoke/reorg_above_finality_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/ && go test smoke/reorg_above_finality_test.go -timeout 30m -count=1 -json
pyroscope_env: ci-smoke-reorg-above-finality-evm-simulated
- - id: integration-tests/migration/upgrade_version_test.go:*
+ - id: migration/upgrade_version_test.go:*
path: integration-tests/migration/upgrade_version_test.go
test_env_type: docker
runs_on: ubuntu-latest
workflows:
- - Run PR E2E Tests
- - Run Nightly E2E Tests
+ - PR E2E Core Tests
+ - Nightly E2E Tests
test_cmd: cd integration-tests/migration && go test upgrade_version_test.go -timeout 30m -count=1 -test.parallel=2 -json
- test_inputs:
- chainlink_image: public.ecr.aws/chainlink/chainlink
- chainlink_version: '{{ env.LATEST_CHAINLINK_RELEASE_VERSION }}'
- chainlink_upgrade_image: '{{ env.QA_CHAINLINK_IMAGE }}'
- chainlink_upgrade_version: develop
+ test_env_vars:
+ E2E_TEST_CHAINLINK_IMAGE: public.ecr.aws/chainlink/chainlink
+ E2E_TEST_CHAINLINK_VERSION: '{{ env.LATEST_CHAINLINK_RELEASE_VERSION }}'
+ E2E_TEST_CHAINLINK_UPGRADE_IMAGE: '{{ env.QA_CHAINLINK_IMAGE }}'
+ E2E_TEST_CHAINLINK_UPGRADE_VERSION: '{{ env.DEFAULT_CHAINLINK_VERSION }}'
# END: Other tests
+
+ # START: CCIP tests
+
+ - id: ccip-smoke
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - PR E2E CCIP Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPForBidirectionalLane$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+
+ - id: ccip-smoke-1.4-pools
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - PR E2E CCIP Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPForBidirectionalLane$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+ test_config_override_path: integration-tests/ccip-tests/testconfig/tomls/contract-version1.4.toml
+
+ - id: ccip-smoke-usdc
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - PR E2E CCIP Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPForBidirectionalLane$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+ test_config_override_path: integration-tests/ccip-tests/testconfig/tomls/usdc_mock_deployment.toml
+
+ - id: ccip-smoke-db-compatibility
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - PR E2E CCIP Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPForBidirectionalLane$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+ test_config_override_path: integration-tests/ccip-tests/testconfig/tomls/db-compatibility.toml
+
+ - id: ccip-smoke-leader-lane
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ # Leader lane test is flakey in Core repo - Need to fix CCIP-3074 to enable it.
+ workflows:
+ # - PR E2E CCIP Tests
+ # - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPForBidirectionalLane$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+ test_config_override_path: integration-tests/ccip-tests/testconfig/tomls/leader-lane.toml
+
+ - id: ccip-tests/smoke/ccip_test.go:^TestSmokeCCIPTokenPoolRateLimits$
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - PR E2E CCIP Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPTokenPoolRateLimits$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+
+ - id: ccip-tests/smoke/ccip_test.go:^TestSmokeCCIPMulticall$
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - PR E2E CCIP Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPMulticall$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+
+ - id: ccip-tests/smoke/ccip_test.go:^TestSmokeCCIPManuallyExecuteAfterExecutionFailingDueToInsufficientGas$
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - PR E2E CCIP Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPManuallyExecuteAfterExecutionFailingDueToInsufficientGas$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+
+ - id: ccip-tests/smoke/ccip_test.go:^TestSmokeCCIPOnRampLimits$
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - PR E2E CCIP Tests
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPOnRampLimits$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+
+ - id: ccip-tests/smoke/ccip_test.go:^TestSmokeCCIPOffRampCapacityLimit$
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPOffRampCapacityLimit$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+
+ - id: ccip-tests/smoke/ccip_test.go:^TestSmokeCCIPOffRampAggRateLimit$
+ path: integration-tests/ccip-tests/smoke/ccip_test.go
+ test_env_type: docker
+ runs_on: ubuntu-latest
+ workflows:
+ - Nightly E2E Tests
+ test_cmd: cd integration-tests/ccip-tests/smoke && go test ccip_test.go -test.run ^TestSmokeCCIPOffRampAggRateLimit$ -timeout 30m -count=1 -test.parallel=1 -json
+ test_env_vars:
+ E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2
+
+ # END: CCIP tests
\ No newline at end of file
diff --git a/.github/scripts/crib/lib/check-route53-records.js b/.github/scripts/crib/lib/check-route53-records.js
deleted file mode 100644
index f35762ec88a..00000000000
--- a/.github/scripts/crib/lib/check-route53-records.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import { setTimeout } from "node:timers/promises";
-import {
- Route53Client,
- ListResourceRecordSetsCommand,
-} from "@aws-sdk/client-route-53";
-
-// us-east-1 is the global region used by Route 53.
-const route53Client = new Route53Client({ region: "us-east-1" });
-
-async function paginateListResourceRecordSets(route53Client, params) {
- let isTruncated = true;
- let nextRecordName, nextRecordType;
- let allRecordSets = [];
-
- while (isTruncated) {
- const response = await route53Client.send(
- new ListResourceRecordSetsCommand({
- ...params,
- ...(nextRecordName && { StartRecordName: nextRecordName }),
- ...(nextRecordType && { StartRecordType: nextRecordType }),
- })
- );
-
- allRecordSets = allRecordSets.concat(response.ResourceRecordSets);
- isTruncated = response.IsTruncated;
- if (isTruncated) {
- nextRecordName = response.NextRecordName;
- nextRecordType = response.NextRecordType;
- }
- }
-
- return allRecordSets;
-}
-
-/**
- * Check if Route 53 records exist for a given Route 53 zone.
- *
- * @param {string} hostedZoneId The ID of the hosted zone.
- * @param {string[]} recordNames An array of record names to check.
- * @param {number} maxRetries The maximum number of retries.
- * @param {number} initialBackoffMs The initial backoff time in milliseconds.
- * @returns {Promise} True if records exist, false otherwise.
- */
-export async function route53RecordsExist(
- hostedZoneId,
- recordNames,
- maxRetries = 8,
- initialBackoffMs = 2000
-) {
- let attempts = 0;
-
- // We try to gather all records within a specified time limit.
- // We issue retries due to an indeterminate amount of time required
- // for record propagation.
- console.info("Checking DNS records in Route 53...");
- while (attempts < maxRetries) {
- try {
- const allRecordSets = await paginateListResourceRecordSets(
- route53Client,
- {
- HostedZoneId: hostedZoneId,
- MaxItems: "300",
- }
- );
-
- const recordExists = recordNames.every((name) =>
- allRecordSets.some((r) => r.Name.includes(name))
- );
-
- if (recordExists) {
- console.info("All records found in Route 53.");
- return true;
- }
-
- // If any record is not found, throw an error to trigger a retry
- throw new Error(
- "One or more DNS records not found in Route 53, retrying..."
- );
- } catch (error) {
- console.error(`Attempt ${attempts + 1}:`, error.message);
- if (attempts === maxRetries - 1) {
- return false; // Return false after the last attempt
- }
- // Exponential backoff
- await setTimeout(initialBackoffMs * 2 ** attempts);
- attempts++;
- }
- }
- // Should not reach here if retries are exhausted
- return false;
-}
diff --git a/.github/scripts/crib/package.json b/.github/scripts/crib/package.json
deleted file mode 100644
index b009d63f386..00000000000
--- a/.github/scripts/crib/package.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "crib",
- "version": "1.0.0",
- "description": "",
- "main": "pr-comment-crib-env.js",
- "type": "module",
- "keywords": [],
- "author": "",
- "license": "MIT",
- "engines": {
- "node": ">=18",
- "pnpm": ">=9"
- },
- "dependencies": {
- "@actions/core": "^1.10.1",
- "@actions/github": "^6.0.0",
- "@aws-sdk/client-route-53": "^3.525.0",
- "@octokit/rest": "^20.0.2"
- }
-}
diff --git a/.github/scripts/crib/pnpm-lock.yaml b/.github/scripts/crib/pnpm-lock.yaml
deleted file mode 100644
index a65caf8355d..00000000000
--- a/.github/scripts/crib/pnpm-lock.yaml
+++ /dev/null
@@ -1,1206 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- dependencies:
- '@actions/core':
- specifier: ^1.10.1
- version: 1.10.1
- '@actions/github':
- specifier: ^6.0.0
- version: 6.0.0
- '@aws-sdk/client-route-53':
- specifier: ^3.525.0
- version: 3.529.1
- '@octokit/rest':
- specifier: ^20.0.2
- version: 20.0.2
-
-packages:
-
- '@actions/core@1.10.1':
- resolution: {integrity: sha512-3lBR9EDAY+iYIpTnTIXmWcNbX3T2kCkAEQGIQx4NVQ0575nk2k3GRZDTPQG+vVtS2izSLmINlxXf0uLtnrTP+g==}
-
- '@actions/github@6.0.0':
- resolution: {integrity: sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==}
-
- '@actions/http-client@2.2.1':
- resolution: {integrity: sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==}
-
- '@aws-crypto/crc32@3.0.0':
- resolution: {integrity: sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==}
-
- '@aws-crypto/ie11-detection@3.0.0':
- resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==}
-
- '@aws-crypto/sha256-browser@3.0.0':
- resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==}
-
- '@aws-crypto/sha256-js@3.0.0':
- resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==}
-
- '@aws-crypto/supports-web-crypto@3.0.0':
- resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==}
-
- '@aws-crypto/util@3.0.0':
- resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==}
-
- '@aws-sdk/client-route-53@3.529.1':
- resolution: {integrity: sha512-osra30V5ILwEBeE1DUZreY7HYWQGco+WcQ1qg1UDSh/C0Nyxlu+8bVpwB/bjaldmy5Fi9MRv8SQsMdiAJFNp+w==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/client-sso-oidc@3.529.1':
- resolution: {integrity: sha512-bimxCWAvRnVcluWEQeadXvHyzWlBWsuGVligsaVZaGF0TLSn0eLpzpN9B1EhHzTf7m0Kh/wGtPSH1JxO6PpB+A==}
- engines: {node: '>=14.0.0'}
- peerDependencies:
- '@aws-sdk/credential-provider-node': ^3.529.1
-
- '@aws-sdk/client-sso@3.529.1':
- resolution: {integrity: sha512-KT1U/ZNjDhVv2ZgjzaeAn9VM7l667yeSguMrRYC8qk5h91/61MbjZypi6eOuKuVM+0fsQvzKScTQz0Lio0eYag==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/client-sts@3.529.1':
- resolution: {integrity: sha512-Rvk2Sr3MACQTOtngUU+omlf4E17k47dRVXR7OFRD6Ow5iGgC9tkN2q/ExDPW/ktPOmM0lSgzWyQ6/PC/Zq3HUg==}
- engines: {node: '>=14.0.0'}
- peerDependencies:
- '@aws-sdk/credential-provider-node': ^3.529.1
-
- '@aws-sdk/core@3.529.1':
- resolution: {integrity: sha512-Sj42sYPfaL9PHvvciMICxhyrDZjqnnvFbPKDmQL5aFKyXy122qx7RdVqUOQERDmMQfvJh6+0W1zQlLnre89q4Q==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/credential-provider-env@3.523.0':
- resolution: {integrity: sha512-Y6DWdH6/OuMDoNKVzZlNeBc6f1Yjk1lYMjANKpIhMbkRCvLJw/PYZKOZa8WpXbTYdgg9XLjKybnLIb3ww3uuzA==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/credential-provider-http@3.525.0':
- resolution: {integrity: sha512-RNWQGuSBQZhl3iqklOslUEfQ4br1V3DCPboMpeqFtddUWJV3m2u2extFur9/4Uy+1EHVF120IwZUKtd8dF+ibw==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/credential-provider-ini@3.529.1':
- resolution: {integrity: sha512-RjHsuTvHIwXG7a/3ERexemiD3c9riKMCZQzY2/b0Gg0ButEVbBcMfERtUzWmQ0V4ufe/PEZjP68MH1gupcoF9A==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/credential-provider-node@3.529.1':
- resolution: {integrity: sha512-mvY7F3dMmk/0dZOCfl5sUI1bG0osureBjxhELGCF0KkJqhWI0hIzh8UnPkYytSg3vdc97CMv7pTcozxrdA3b0g==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/credential-provider-process@3.523.0':
- resolution: {integrity: sha512-f0LP9KlFmMvPWdKeUKYlZ6FkQAECUeZMmISsv6NKtvPCI9e4O4cLTeR09telwDK8P0HrgcRuZfXM7E30m8re0Q==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/credential-provider-sso@3.529.1':
- resolution: {integrity: sha512-KFMKkaoTGDgSJG+o9Ii7AglWG5JQeF6IFw9cXLMwDdIrp3KUmRcUIqe0cjOoCqeQEDGy0VHsimHmKKJ3894i/A==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/credential-provider-web-identity@3.529.1':
- resolution: {integrity: sha512-AGuZDOKN+AttjwTjrF47WLqzeEut2YynyxjkXZhxZF/xn8i5Y51kUAUdXsXw1bgR25pAeXQIdhsrQlRa1Pm5kw==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/middleware-host-header@3.523.0':
- resolution: {integrity: sha512-4g3q7Ta9sdD9TMUuohBAkbx/e3I/juTqfKi7TPgP+8jxcYX72MOsgemAMHuP6CX27eyj4dpvjH+w4SIVDiDSmg==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/middleware-logger@3.523.0':
- resolution: {integrity: sha512-PeDNJNhfiaZx54LBaLTXzUaJ9LXFwDFFIksipjqjvxMafnoVcQwKbkoPUWLe5ytT4nnL1LogD3s55mERFUsnwg==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/middleware-recursion-detection@3.523.0':
- resolution: {integrity: sha512-nZ3Vt7ehfSDYnrcg/aAfjjvpdE+61B3Zk68i6/hSUIegT3IH9H1vSW67NDKVp+50hcEfzWwM2HMPXxlzuyFyrw==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/middleware-sdk-route53@3.523.0':
- resolution: {integrity: sha512-d+SKqDBM3XCVkF/crRWwJD1WuS4PBY/CaTGwIyND1Z3o3ZCMhyo4f2ni19U+7ZtEULW50ZGznhB2F4GJHqpDUg==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/middleware-user-agent@3.525.0':
- resolution: {integrity: sha512-4al/6uO+t/QIYXK2OgqzDKQzzLAYJza1vWFS+S0lJ3jLNGyLB5BMU5KqWjDzevYZ4eCnz2Nn7z0FveUTNz8YdQ==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/region-config-resolver@3.525.0':
- resolution: {integrity: sha512-8kFqXk6UyKgTMi7N7QlhA6qM4pGPWbiUXqEY2RgUWngtxqNFGeM9JTexZeuavQI+qLLe09VPShPNX71fEDcM6w==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/token-providers@3.529.1':
- resolution: {integrity: sha512-NpgMjsfpqiugbxrYGXtta914N43Mx/H0niidqv8wKMTgWQEtsJvYtOni+kuLXB+LmpjaMFNlpadooFU/bK4buA==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/types@3.523.0':
- resolution: {integrity: sha512-AqGIu4u+SxPiUuNBp2acCVcq80KDUFjxe6e3cMTvKWTzCbrVk1AXv0dAaJnCmdkWIha6zJDWxpIk/aL4EGhZ9A==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/util-endpoints@3.525.0':
- resolution: {integrity: sha512-DIW7WWU5tIGkeeKX6NJUyrEIdWMiqjLQG3XBzaUj+ufIENwNjdAHhlD8l2vX7Yr3JZRT6yN/84wBCj7Tw1xd1g==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/util-locate-window@3.495.0':
- resolution: {integrity: sha512-MfaPXT0kLX2tQaR90saBT9fWQq2DHqSSJRzW+MZWsmF+y5LGCOhO22ac/2o6TKSQm7h0HRc2GaADqYYYor62yg==}
- engines: {node: '>=14.0.0'}
-
- '@aws-sdk/util-user-agent-browser@3.523.0':
- resolution: {integrity: sha512-6ZRNdGHX6+HQFqTbIA5+i8RWzxFyxsZv8D3soRfpdyWIKkzhSz8IyRKXRciwKBJDaC7OX2jzGE90wxRQft27nA==}
-
- '@aws-sdk/util-user-agent-node@3.525.0':
- resolution: {integrity: sha512-88Wjt4efyUSBGcyIuh1dvoMqY1k15jpJc5A/3yi67clBQEFsu9QCodQCQPqmRjV3VRcMtBOk+jeCTiUzTY5dRQ==}
- engines: {node: '>=14.0.0'}
- peerDependencies:
- aws-crt: '>=1.0.0'
- peerDependenciesMeta:
- aws-crt:
- optional: true
-
- '@aws-sdk/util-utf8-browser@3.259.0':
- resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==}
-
- '@aws-sdk/xml-builder@3.523.0':
- resolution: {integrity: sha512-wfvyVymj2TUw7SuDor9IuFcAzJZvWRBZotvY/wQJOlYa3UP3Oezzecy64N4FWfBJEsZdrTN+HOZFl+IzTWWnUA==}
- engines: {node: '>=14.0.0'}
-
- '@fastify/busboy@2.1.1':
- resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
- engines: {node: '>=14'}
-
- '@octokit/auth-token@4.0.0':
- resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==}
- engines: {node: '>= 18'}
-
- '@octokit/core@5.1.0':
- resolution: {integrity: sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==}
- engines: {node: '>= 18'}
-
- '@octokit/endpoint@9.0.4':
- resolution: {integrity: sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==}
- engines: {node: '>= 18'}
-
- '@octokit/graphql@7.0.2':
- resolution: {integrity: sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==}
- engines: {node: '>= 18'}
-
- '@octokit/openapi-types@20.0.0':
- resolution: {integrity: sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==}
-
- '@octokit/plugin-paginate-rest@9.2.1':
- resolution: {integrity: sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==}
- engines: {node: '>= 18'}
- peerDependencies:
- '@octokit/core': '5'
-
- '@octokit/plugin-request-log@4.0.1':
- resolution: {integrity: sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==}
- engines: {node: '>= 18'}
- peerDependencies:
- '@octokit/core': '5'
-
- '@octokit/plugin-rest-endpoint-methods@10.4.1':
- resolution: {integrity: sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==}
- engines: {node: '>= 18'}
- peerDependencies:
- '@octokit/core': '5'
-
- '@octokit/request-error@5.0.1':
- resolution: {integrity: sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==}
- engines: {node: '>= 18'}
-
- '@octokit/request@8.2.0':
- resolution: {integrity: sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==}
- engines: {node: '>= 18'}
-
- '@octokit/rest@20.0.2':
- resolution: {integrity: sha512-Ux8NDgEraQ/DMAU1PlAohyfBBXDwhnX2j33Z1nJNziqAfHi70PuxkFYIcIt8aIAxtRE7KVuKp8lSR8pA0J5iOQ==}
- engines: {node: '>= 18'}
-
- '@octokit/types@12.6.0':
- resolution: {integrity: sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==}
-
- '@smithy/abort-controller@2.1.4':
- resolution: {integrity: sha512-66HO817oIZ2otLIqy06R5muapqZjkgF1jfU0wyNko8cuqZNu8nbS9ljlhcRYw/M/uWRJzB9ih81DLSHhYbBLlQ==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/config-resolver@2.1.5':
- resolution: {integrity: sha512-LcBB5JQC3Tx2ZExIJzfvWaajhFIwHrUNQeqxhred2r5nnqrdly9uoCrvM1sxOOdghYuWWm2Kr8tBCDOmxsgeTA==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/core@1.3.8':
- resolution: {integrity: sha512-6cFhQ9ChU7MxvOXJn6nuUSONacpNsGHWhfueROQuM/0vibDdZA9FWEdNbVkuVuc+BFI5BnaX3ltERUlpUirpIA==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/credential-provider-imds@2.2.6':
- resolution: {integrity: sha512-+xQe4Pite0kdk9qn0Vyw5BRVh0iSlj+T4TEKRXr4E1wZKtVgIzGlkCrfICSjiPVFkPxk4jMpVboMYdEiiA88/w==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/eventstream-codec@2.1.4':
- resolution: {integrity: sha512-UkiieTztP7adg8EuqZvB0Y4LewdleZCJU7Kgt9RDutMsRYqO32fMpWeQHeTHaIMosmzcRZUykMRrhwGJe9mP3A==}
-
- '@smithy/fetch-http-handler@2.4.5':
- resolution: {integrity: sha512-FR1IMGdo0yRFs1tk71zRGSa1MznVLQOVNaPjyNtx6dOcy/u0ovEnXN5NVz6slw5KujFlg3N1w4+UbO8F3WyYUg==}
-
- '@smithy/hash-node@2.1.4':
- resolution: {integrity: sha512-uvCcpDLXaTTL0X/9ezF8T8sS77UglTfZVQaUOBiCvR0QydeSyio3t0Hj3QooVdyFsKTubR8gCk/ubLk3vAyDng==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/invalid-dependency@2.1.4':
- resolution: {integrity: sha512-QzlNBl6jt3nb9jNnE51wTegReVvUdozyMMrFEyb/rc6AzPID1O+qMJYjAAoNw098y0CZVfCpEnoK2+mfBOd8XA==}
-
- '@smithy/is-array-buffer@2.1.1':
- resolution: {integrity: sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/middleware-content-length@2.1.4':
- resolution: {integrity: sha512-C6VRwfcr0w9qRFhDGCpWMVhlEIBFlmlPRP1aX9Cv9xDj9SUwlDrNvoV1oP1vjRYuLxCDgovBBynCwwcluS2wLw==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/middleware-endpoint@2.4.6':
- resolution: {integrity: sha512-AsXtUXHPOAS0EGZUSFOsVJvc7p0KL29PGkLxLfycPOcFVLru/oinYB6yvyL73ZZPX2OB8sMYUMrj7eH2kI7V/w==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/middleware-retry@2.1.7':
- resolution: {integrity: sha512-8fOP/cJN4oMv+5SRffZC8RkqfWxHqGgn/86JPINY/1DnTRegzf+G5GT9lmIdG1YasuSbU7LISfW9PXil3isPVw==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/middleware-serde@2.2.1':
- resolution: {integrity: sha512-VAWRWqnNjgccebndpyK94om4ZTYzXLQxUmNCXYzM/3O9MTfQjTNBgtFtQwyIIez6z7LWcCsXmnKVIOE9mLqAHQ==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/middleware-stack@2.1.4':
- resolution: {integrity: sha512-Qqs2ba8Ax1rGKOSGJS2JN23fhhox2WMdRuzx0NYHtXzhxbJOIMmz9uQY6Hf4PY8FPteBPp1+h0j5Fmr+oW12sg==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/node-config-provider@2.2.5':
- resolution: {integrity: sha512-CxPf2CXhjO79IypHJLBATB66Dw6suvr1Yc2ccY39hpR6wdse3pZ3E8RF83SODiNH0Wjmkd0ze4OF8exugEixgA==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/node-http-handler@2.4.3':
- resolution: {integrity: sha512-bD5zRdEl1u/4vAAMeQnGEUNbH1seISV2Z0Wnn7ltPRl/6B2zND1R9XzTfsOnH1R5jqghpochF/mma8u7uXz0qQ==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/property-provider@2.1.4':
- resolution: {integrity: sha512-nWaY/MImj1BiXZ9WY65h45dcxOx8pl06KYoHxwojDxDL+Q9yLU1YnZpgv8zsHhEftlj9KhePENjQTlNowWVyug==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/protocol-http@3.2.2':
- resolution: {integrity: sha512-xYBlllOQcOuLoxzhF2u8kRHhIFGQpDeTQj/dBSnw4kfI29WMKL5RnW1m9YjnJAJ49miuIvrkJR+gW5bCQ+Mchw==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/querystring-builder@2.1.4':
- resolution: {integrity: sha512-LXSL0J/nRWvGT+jIj+Fip3j0J1ZmHkUyBFRzg/4SmPNCLeDrtVu7ptKOnTboPsFZu5BxmpYok3kJuQzzRdrhbw==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/querystring-parser@2.1.4':
- resolution: {integrity: sha512-U2b8olKXgZAs0eRo7Op11jTNmmcC/sqYmsA7vN6A+jkGnDvJlEl7AetUegbBzU8q3D6WzC5rhR/joIy8tXPzIg==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/service-error-classification@2.1.4':
- resolution: {integrity: sha512-JW2Hthy21evnvDmYYk1kItOmbp3X5XI5iqorXgFEunb6hQfSDZ7O1g0Clyxg7k/Pcr9pfLk5xDIR2To/IohlsQ==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/shared-ini-file-loader@2.3.5':
- resolution: {integrity: sha512-oI99+hOvsM8oAJtxAGmoL/YCcGXtbP0fjPseYGaNmJ4X5xOFTer0KPk7AIH3AL6c5AlYErivEi1X/X78HgTVIw==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/signature-v4@2.1.4':
- resolution: {integrity: sha512-gnu9gCn0qQ8IdhNjs6o3QVCXzUs33znSDYwVMWo3nX4dM6j7z9u6FC302ShYyVWfO4MkVMuGCCJ6nl3PcH7V1Q==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/smithy-client@2.4.5':
- resolution: {integrity: sha512-igXOM4kPXPo6b5LZXTUqTnrGk20uVd8OXoybC3f89gczzGfziLK4yUNOmiHSdxY9OOMOnnhVe5MpTm01MpFqvA==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/types@2.11.0':
- resolution: {integrity: sha512-AR0SXO7FuAskfNhyGfSTThpLRntDI5bOrU0xrpVYU0rZyjl3LBXInZFMTP/NNSd7IS6Ksdtar0QvnrPRIhVrLQ==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/url-parser@2.1.4':
- resolution: {integrity: sha512-1hTy6UYRYqOZlHKH2/2NzdNQ4NNmW2Lp0sYYvztKy+dEQuLvZL9w88zCzFQqqFer3DMcscYOshImxkJTGdV+rg==}
-
- '@smithy/util-base64@2.2.1':
- resolution: {integrity: sha512-troGfokrpoqv8TGgsb8p4vvM71vqor314514jyQ0i9Zae3qs0jUVbSMCIBB1tseVynXFRcZJAZ9hPQYlifLD5A==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-body-length-browser@2.1.1':
- resolution: {integrity: sha512-ekOGBLvs1VS2d1zM2ER4JEeBWAvIOUKeaFch29UjjJsxmZ/f0L3K3x0dEETgh3Q9bkZNHgT+rkdl/J/VUqSRag==}
-
- '@smithy/util-body-length-node@2.2.2':
- resolution: {integrity: sha512-U7DooaT1SfW7XHrOcxthYJnQ+WMaefRrFPxW5Qmypw38Ivv+TKvfVuVHA9V162h8BeW9rzOJwOunjgXd0DdB4w==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-buffer-from@2.1.1':
- resolution: {integrity: sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-config-provider@2.2.1':
- resolution: {integrity: sha512-50VL/tx9oYYcjJn/qKqNy7sCtpD0+s8XEBamIFo4mFFTclKMNp+rsnymD796uybjiIquB7VCB/DeafduL0y2kw==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-defaults-mode-browser@2.1.7':
- resolution: {integrity: sha512-vvIpWsysEdY77R0Qzr6+LRW50ye7eii7AyHM0OJnTi0isHYiXo5M/7o4k8gjK/b1upQJdfjzSBoJVa2SWrI+2g==}
- engines: {node: '>= 10.0.0'}
-
- '@smithy/util-defaults-mode-node@2.2.7':
- resolution: {integrity: sha512-qzXkSDyU6Th+rNNcNkG4a7Ix7m5HlMOtSCPxTVKlkz7eVsqbSSPggegbFeQJ2MVELBB4wnzNPsVPJIrpIaJpXA==}
- engines: {node: '>= 10.0.0'}
-
- '@smithy/util-endpoints@1.1.5':
- resolution: {integrity: sha512-tgDpaUNsUtRvNiBulKU1VnpoXU1GINMfZZXunRhUXOTBEAufG1Wp79uDXLau2gg1RZ4dpAR6lXCkrmddihCGUg==}
- engines: {node: '>= 14.0.0'}
-
- '@smithy/util-hex-encoding@2.1.1':
- resolution: {integrity: sha512-3UNdP2pkYUUBGEXzQI9ODTDK+Tcu1BlCyDBaRHwyxhA+8xLP8agEKQq4MGmpjqb4VQAjq9TwlCQX0kP6XDKYLg==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-middleware@2.1.4':
- resolution: {integrity: sha512-5yYNOgCN0DL0OplME0pthoUR/sCfipnROkbTO7m872o0GHCVNJj5xOFJ143rvHNA54+pIPMLum4z2DhPC2pVGA==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-retry@2.1.4':
- resolution: {integrity: sha512-JRZwhA3fhkdenSEYIWatC8oLwt4Bdf2LhHbNQApqb7yFoIGMl4twcYI3BcJZ7YIBZrACA9jGveW6tuCd836XzQ==}
- engines: {node: '>= 14.0.0'}
-
- '@smithy/util-stream@2.1.5':
- resolution: {integrity: sha512-FqvBFeTgx+QC4+i8USHqU8Ifs9nYRpW/OBfksojtgkxPIQ2H7ypXDEbnQRAV7PwoNHWcSwPomLYi0svmQQG5ow==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-uri-escape@2.1.1':
- resolution: {integrity: sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-utf8@2.2.0':
- resolution: {integrity: sha512-hBsKr5BqrDrKS8qy+YcV7/htmMGxriA1PREOf/8AGBhHIZnfilVv1Waf1OyKhSbFW15U/8+gcMUQ9/Kk5qwpHQ==}
- engines: {node: '>=14.0.0'}
-
- '@smithy/util-waiter@2.1.4':
- resolution: {integrity: sha512-AK17WaC0hx1wR9juAOsQkJ6DjDxBGEf5TrKhpXtNFEn+cVto9Li3MVsdpAO97AF7bhFXSyC8tJA3F4ThhqwCdg==}
- engines: {node: '>=14.0.0'}
-
- before-after-hook@2.2.3:
- resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==}
-
- bowser@2.11.0:
- resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
-
- deprecation@2.3.1:
- resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==}
-
- fast-xml-parser@4.2.5:
- resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==}
- hasBin: true
-
- once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
-
- strnum@1.0.5:
- resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
-
- tslib@1.14.1:
- resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
-
- tslib@2.6.2:
- resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
-
- tunnel@0.0.6:
- resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
- engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
-
- undici@5.28.3:
- resolution: {integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==}
- engines: {node: '>=14.0'}
-
- universal-user-agent@6.0.1:
- resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==}
-
- uuid@8.3.2:
- resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
- hasBin: true
-
- wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
-
-snapshots:
-
- '@actions/core@1.10.1':
- dependencies:
- '@actions/http-client': 2.2.1
- uuid: 8.3.2
-
- '@actions/github@6.0.0':
- dependencies:
- '@actions/http-client': 2.2.1
- '@octokit/core': 5.1.0
- '@octokit/plugin-paginate-rest': 9.2.1(@octokit/core@5.1.0)
- '@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.1.0)
-
- '@actions/http-client@2.2.1':
- dependencies:
- tunnel: 0.0.6
- undici: 5.28.3
-
- '@aws-crypto/crc32@3.0.0':
- dependencies:
- '@aws-crypto/util': 3.0.0
- '@aws-sdk/types': 3.523.0
- tslib: 1.14.1
-
- '@aws-crypto/ie11-detection@3.0.0':
- dependencies:
- tslib: 1.14.1
-
- '@aws-crypto/sha256-browser@3.0.0':
- dependencies:
- '@aws-crypto/ie11-detection': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-crypto/supports-web-crypto': 3.0.0
- '@aws-crypto/util': 3.0.0
- '@aws-sdk/types': 3.523.0
- '@aws-sdk/util-locate-window': 3.495.0
- '@aws-sdk/util-utf8-browser': 3.259.0
- tslib: 1.14.1
-
- '@aws-crypto/sha256-js@3.0.0':
- dependencies:
- '@aws-crypto/util': 3.0.0
- '@aws-sdk/types': 3.523.0
- tslib: 1.14.1
-
- '@aws-crypto/supports-web-crypto@3.0.0':
- dependencies:
- tslib: 1.14.1
-
- '@aws-crypto/util@3.0.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@aws-sdk/util-utf8-browser': 3.259.0
- tslib: 1.14.1
-
- '@aws-sdk/client-route-53@3.529.1':
- dependencies:
- '@aws-crypto/sha256-browser': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-sdk/client-sts': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/core': 3.529.1
- '@aws-sdk/credential-provider-node': 3.529.1
- '@aws-sdk/middleware-host-header': 3.523.0
- '@aws-sdk/middleware-logger': 3.523.0
- '@aws-sdk/middleware-recursion-detection': 3.523.0
- '@aws-sdk/middleware-sdk-route53': 3.523.0
- '@aws-sdk/middleware-user-agent': 3.525.0
- '@aws-sdk/region-config-resolver': 3.525.0
- '@aws-sdk/types': 3.523.0
- '@aws-sdk/util-endpoints': 3.525.0
- '@aws-sdk/util-user-agent-browser': 3.523.0
- '@aws-sdk/util-user-agent-node': 3.525.0
- '@aws-sdk/xml-builder': 3.523.0
- '@smithy/config-resolver': 2.1.5
- '@smithy/core': 1.3.8
- '@smithy/fetch-http-handler': 2.4.5
- '@smithy/hash-node': 2.1.4
- '@smithy/invalid-dependency': 2.1.4
- '@smithy/middleware-content-length': 2.1.4
- '@smithy/middleware-endpoint': 2.4.6
- '@smithy/middleware-retry': 2.1.7
- '@smithy/middleware-serde': 2.2.1
- '@smithy/middleware-stack': 2.1.4
- '@smithy/node-config-provider': 2.2.5
- '@smithy/node-http-handler': 2.4.3
- '@smithy/protocol-http': 3.2.2
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- '@smithy/url-parser': 2.1.4
- '@smithy/util-base64': 2.2.1
- '@smithy/util-body-length-browser': 2.1.1
- '@smithy/util-body-length-node': 2.2.2
- '@smithy/util-defaults-mode-browser': 2.1.7
- '@smithy/util-defaults-mode-node': 2.2.7
- '@smithy/util-endpoints': 1.1.5
- '@smithy/util-middleware': 2.1.4
- '@smithy/util-retry': 2.1.4
- '@smithy/util-utf8': 2.2.0
- '@smithy/util-waiter': 2.1.4
- tslib: 2.6.2
- transitivePeerDependencies:
- - aws-crt
-
- '@aws-sdk/client-sso-oidc@3.529.1(@aws-sdk/credential-provider-node@3.529.1)':
- dependencies:
- '@aws-crypto/sha256-browser': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-sdk/client-sts': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/core': 3.529.1
- '@aws-sdk/credential-provider-node': 3.529.1
- '@aws-sdk/middleware-host-header': 3.523.0
- '@aws-sdk/middleware-logger': 3.523.0
- '@aws-sdk/middleware-recursion-detection': 3.523.0
- '@aws-sdk/middleware-user-agent': 3.525.0
- '@aws-sdk/region-config-resolver': 3.525.0
- '@aws-sdk/types': 3.523.0
- '@aws-sdk/util-endpoints': 3.525.0
- '@aws-sdk/util-user-agent-browser': 3.523.0
- '@aws-sdk/util-user-agent-node': 3.525.0
- '@smithy/config-resolver': 2.1.5
- '@smithy/core': 1.3.8
- '@smithy/fetch-http-handler': 2.4.5
- '@smithy/hash-node': 2.1.4
- '@smithy/invalid-dependency': 2.1.4
- '@smithy/middleware-content-length': 2.1.4
- '@smithy/middleware-endpoint': 2.4.6
- '@smithy/middleware-retry': 2.1.7
- '@smithy/middleware-serde': 2.2.1
- '@smithy/middleware-stack': 2.1.4
- '@smithy/node-config-provider': 2.2.5
- '@smithy/node-http-handler': 2.4.3
- '@smithy/protocol-http': 3.2.2
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- '@smithy/url-parser': 2.1.4
- '@smithy/util-base64': 2.2.1
- '@smithy/util-body-length-browser': 2.1.1
- '@smithy/util-body-length-node': 2.2.2
- '@smithy/util-defaults-mode-browser': 2.1.7
- '@smithy/util-defaults-mode-node': 2.2.7
- '@smithy/util-endpoints': 1.1.5
- '@smithy/util-middleware': 2.1.4
- '@smithy/util-retry': 2.1.4
- '@smithy/util-utf8': 2.2.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - aws-crt
-
- '@aws-sdk/client-sso@3.529.1':
- dependencies:
- '@aws-crypto/sha256-browser': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-sdk/core': 3.529.1
- '@aws-sdk/middleware-host-header': 3.523.0
- '@aws-sdk/middleware-logger': 3.523.0
- '@aws-sdk/middleware-recursion-detection': 3.523.0
- '@aws-sdk/middleware-user-agent': 3.525.0
- '@aws-sdk/region-config-resolver': 3.525.0
- '@aws-sdk/types': 3.523.0
- '@aws-sdk/util-endpoints': 3.525.0
- '@aws-sdk/util-user-agent-browser': 3.523.0
- '@aws-sdk/util-user-agent-node': 3.525.0
- '@smithy/config-resolver': 2.1.5
- '@smithy/core': 1.3.8
- '@smithy/fetch-http-handler': 2.4.5
- '@smithy/hash-node': 2.1.4
- '@smithy/invalid-dependency': 2.1.4
- '@smithy/middleware-content-length': 2.1.4
- '@smithy/middleware-endpoint': 2.4.6
- '@smithy/middleware-retry': 2.1.7
- '@smithy/middleware-serde': 2.2.1
- '@smithy/middleware-stack': 2.1.4
- '@smithy/node-config-provider': 2.2.5
- '@smithy/node-http-handler': 2.4.3
- '@smithy/protocol-http': 3.2.2
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- '@smithy/url-parser': 2.1.4
- '@smithy/util-base64': 2.2.1
- '@smithy/util-body-length-browser': 2.1.1
- '@smithy/util-body-length-node': 2.2.2
- '@smithy/util-defaults-mode-browser': 2.1.7
- '@smithy/util-defaults-mode-node': 2.2.7
- '@smithy/util-endpoints': 1.1.5
- '@smithy/util-middleware': 2.1.4
- '@smithy/util-retry': 2.1.4
- '@smithy/util-utf8': 2.2.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - aws-crt
-
- '@aws-sdk/client-sts@3.529.1(@aws-sdk/credential-provider-node@3.529.1)':
- dependencies:
- '@aws-crypto/sha256-browser': 3.0.0
- '@aws-crypto/sha256-js': 3.0.0
- '@aws-sdk/core': 3.529.1
- '@aws-sdk/credential-provider-node': 3.529.1
- '@aws-sdk/middleware-host-header': 3.523.0
- '@aws-sdk/middleware-logger': 3.523.0
- '@aws-sdk/middleware-recursion-detection': 3.523.0
- '@aws-sdk/middleware-user-agent': 3.525.0
- '@aws-sdk/region-config-resolver': 3.525.0
- '@aws-sdk/types': 3.523.0
- '@aws-sdk/util-endpoints': 3.525.0
- '@aws-sdk/util-user-agent-browser': 3.523.0
- '@aws-sdk/util-user-agent-node': 3.525.0
- '@smithy/config-resolver': 2.1.5
- '@smithy/core': 1.3.8
- '@smithy/fetch-http-handler': 2.4.5
- '@smithy/hash-node': 2.1.4
- '@smithy/invalid-dependency': 2.1.4
- '@smithy/middleware-content-length': 2.1.4
- '@smithy/middleware-endpoint': 2.4.6
- '@smithy/middleware-retry': 2.1.7
- '@smithy/middleware-serde': 2.2.1
- '@smithy/middleware-stack': 2.1.4
- '@smithy/node-config-provider': 2.2.5
- '@smithy/node-http-handler': 2.4.3
- '@smithy/protocol-http': 3.2.2
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- '@smithy/url-parser': 2.1.4
- '@smithy/util-base64': 2.2.1
- '@smithy/util-body-length-browser': 2.1.1
- '@smithy/util-body-length-node': 2.2.2
- '@smithy/util-defaults-mode-browser': 2.1.7
- '@smithy/util-defaults-mode-node': 2.2.7
- '@smithy/util-endpoints': 1.1.5
- '@smithy/util-middleware': 2.1.4
- '@smithy/util-retry': 2.1.4
- '@smithy/util-utf8': 2.2.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - aws-crt
-
- '@aws-sdk/core@3.529.1':
- dependencies:
- '@smithy/core': 1.3.8
- '@smithy/protocol-http': 3.2.2
- '@smithy/signature-v4': 2.1.4
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- fast-xml-parser: 4.2.5
- tslib: 2.6.2
-
- '@aws-sdk/credential-provider-env@3.523.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/property-provider': 2.1.4
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/credential-provider-http@3.525.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/fetch-http-handler': 2.4.5
- '@smithy/node-http-handler': 2.4.3
- '@smithy/property-provider': 2.1.4
- '@smithy/protocol-http': 3.2.2
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- '@smithy/util-stream': 2.1.5
- tslib: 2.6.2
-
- '@aws-sdk/credential-provider-ini@3.529.1(@aws-sdk/credential-provider-node@3.529.1)':
- dependencies:
- '@aws-sdk/client-sts': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/credential-provider-env': 3.523.0
- '@aws-sdk/credential-provider-process': 3.523.0
- '@aws-sdk/credential-provider-sso': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/credential-provider-web-identity': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/types': 3.523.0
- '@smithy/credential-provider-imds': 2.2.6
- '@smithy/property-provider': 2.1.4
- '@smithy/shared-ini-file-loader': 2.3.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - '@aws-sdk/credential-provider-node'
- - aws-crt
-
- '@aws-sdk/credential-provider-node@3.529.1':
- dependencies:
- '@aws-sdk/credential-provider-env': 3.523.0
- '@aws-sdk/credential-provider-http': 3.525.0
- '@aws-sdk/credential-provider-ini': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/credential-provider-process': 3.523.0
- '@aws-sdk/credential-provider-sso': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/credential-provider-web-identity': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/types': 3.523.0
- '@smithy/credential-provider-imds': 2.2.6
- '@smithy/property-provider': 2.1.4
- '@smithy/shared-ini-file-loader': 2.3.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - aws-crt
-
- '@aws-sdk/credential-provider-process@3.523.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/property-provider': 2.1.4
- '@smithy/shared-ini-file-loader': 2.3.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/credential-provider-sso@3.529.1(@aws-sdk/credential-provider-node@3.529.1)':
- dependencies:
- '@aws-sdk/client-sso': 3.529.1
- '@aws-sdk/token-providers': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/types': 3.523.0
- '@smithy/property-provider': 2.1.4
- '@smithy/shared-ini-file-loader': 2.3.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - '@aws-sdk/credential-provider-node'
- - aws-crt
-
- '@aws-sdk/credential-provider-web-identity@3.529.1(@aws-sdk/credential-provider-node@3.529.1)':
- dependencies:
- '@aws-sdk/client-sts': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/types': 3.523.0
- '@smithy/property-provider': 2.1.4
- '@smithy/types': 2.11.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - '@aws-sdk/credential-provider-node'
- - aws-crt
-
- '@aws-sdk/middleware-host-header@3.523.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/protocol-http': 3.2.2
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/middleware-logger@3.523.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/middleware-recursion-detection@3.523.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/protocol-http': 3.2.2
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/middleware-sdk-route53@3.523.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/middleware-user-agent@3.525.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@aws-sdk/util-endpoints': 3.525.0
- '@smithy/protocol-http': 3.2.2
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/region-config-resolver@3.525.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/node-config-provider': 2.2.5
- '@smithy/types': 2.11.0
- '@smithy/util-config-provider': 2.2.1
- '@smithy/util-middleware': 2.1.4
- tslib: 2.6.2
-
- '@aws-sdk/token-providers@3.529.1(@aws-sdk/credential-provider-node@3.529.1)':
- dependencies:
- '@aws-sdk/client-sso-oidc': 3.529.1(@aws-sdk/credential-provider-node@3.529.1)
- '@aws-sdk/types': 3.523.0
- '@smithy/property-provider': 2.1.4
- '@smithy/shared-ini-file-loader': 2.3.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
- transitivePeerDependencies:
- - '@aws-sdk/credential-provider-node'
- - aws-crt
-
- '@aws-sdk/types@3.523.0':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/util-endpoints@3.525.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/types': 2.11.0
- '@smithy/util-endpoints': 1.1.5
- tslib: 2.6.2
-
- '@aws-sdk/util-locate-window@3.495.0':
- dependencies:
- tslib: 2.6.2
-
- '@aws-sdk/util-user-agent-browser@3.523.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/types': 2.11.0
- bowser: 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/util-user-agent-node@3.525.0':
- dependencies:
- '@aws-sdk/types': 3.523.0
- '@smithy/node-config-provider': 2.2.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@aws-sdk/util-utf8-browser@3.259.0':
- dependencies:
- tslib: 2.6.2
-
- '@aws-sdk/xml-builder@3.523.0':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@fastify/busboy@2.1.1': {}
-
- '@octokit/auth-token@4.0.0': {}
-
- '@octokit/core@5.1.0':
- dependencies:
- '@octokit/auth-token': 4.0.0
- '@octokit/graphql': 7.0.2
- '@octokit/request': 8.2.0
- '@octokit/request-error': 5.0.1
- '@octokit/types': 12.6.0
- before-after-hook: 2.2.3
- universal-user-agent: 6.0.1
-
- '@octokit/endpoint@9.0.4':
- dependencies:
- '@octokit/types': 12.6.0
- universal-user-agent: 6.0.1
-
- '@octokit/graphql@7.0.2':
- dependencies:
- '@octokit/request': 8.2.0
- '@octokit/types': 12.6.0
- universal-user-agent: 6.0.1
-
- '@octokit/openapi-types@20.0.0': {}
-
- '@octokit/plugin-paginate-rest@9.2.1(@octokit/core@5.1.0)':
- dependencies:
- '@octokit/core': 5.1.0
- '@octokit/types': 12.6.0
-
- '@octokit/plugin-request-log@4.0.1(@octokit/core@5.1.0)':
- dependencies:
- '@octokit/core': 5.1.0
-
- '@octokit/plugin-rest-endpoint-methods@10.4.1(@octokit/core@5.1.0)':
- dependencies:
- '@octokit/core': 5.1.0
- '@octokit/types': 12.6.0
-
- '@octokit/request-error@5.0.1':
- dependencies:
- '@octokit/types': 12.6.0
- deprecation: 2.3.1
- once: 1.4.0
-
- '@octokit/request@8.2.0':
- dependencies:
- '@octokit/endpoint': 9.0.4
- '@octokit/request-error': 5.0.1
- '@octokit/types': 12.6.0
- universal-user-agent: 6.0.1
-
- '@octokit/rest@20.0.2':
- dependencies:
- '@octokit/core': 5.1.0
- '@octokit/plugin-paginate-rest': 9.2.1(@octokit/core@5.1.0)
- '@octokit/plugin-request-log': 4.0.1(@octokit/core@5.1.0)
- '@octokit/plugin-rest-endpoint-methods': 10.4.1(@octokit/core@5.1.0)
-
- '@octokit/types@12.6.0':
- dependencies:
- '@octokit/openapi-types': 20.0.0
-
- '@smithy/abort-controller@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/config-resolver@2.1.5':
- dependencies:
- '@smithy/node-config-provider': 2.2.5
- '@smithy/types': 2.11.0
- '@smithy/util-config-provider': 2.2.1
- '@smithy/util-middleware': 2.1.4
- tslib: 2.6.2
-
- '@smithy/core@1.3.8':
- dependencies:
- '@smithy/middleware-endpoint': 2.4.6
- '@smithy/middleware-retry': 2.1.7
- '@smithy/middleware-serde': 2.2.1
- '@smithy/protocol-http': 3.2.2
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- '@smithy/util-middleware': 2.1.4
- tslib: 2.6.2
-
- '@smithy/credential-provider-imds@2.2.6':
- dependencies:
- '@smithy/node-config-provider': 2.2.5
- '@smithy/property-provider': 2.1.4
- '@smithy/types': 2.11.0
- '@smithy/url-parser': 2.1.4
- tslib: 2.6.2
-
- '@smithy/eventstream-codec@2.1.4':
- dependencies:
- '@aws-crypto/crc32': 3.0.0
- '@smithy/types': 2.11.0
- '@smithy/util-hex-encoding': 2.1.1
- tslib: 2.6.2
-
- '@smithy/fetch-http-handler@2.4.5':
- dependencies:
- '@smithy/protocol-http': 3.2.2
- '@smithy/querystring-builder': 2.1.4
- '@smithy/types': 2.11.0
- '@smithy/util-base64': 2.2.1
- tslib: 2.6.2
-
- '@smithy/hash-node@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
- '@smithy/util-buffer-from': 2.1.1
- '@smithy/util-utf8': 2.2.0
- tslib: 2.6.2
-
- '@smithy/invalid-dependency@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/is-array-buffer@2.1.1':
- dependencies:
- tslib: 2.6.2
-
- '@smithy/middleware-content-length@2.1.4':
- dependencies:
- '@smithy/protocol-http': 3.2.2
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/middleware-endpoint@2.4.6':
- dependencies:
- '@smithy/middleware-serde': 2.2.1
- '@smithy/node-config-provider': 2.2.5
- '@smithy/shared-ini-file-loader': 2.3.5
- '@smithy/types': 2.11.0
- '@smithy/url-parser': 2.1.4
- '@smithy/util-middleware': 2.1.4
- tslib: 2.6.2
-
- '@smithy/middleware-retry@2.1.7':
- dependencies:
- '@smithy/node-config-provider': 2.2.5
- '@smithy/protocol-http': 3.2.2
- '@smithy/service-error-classification': 2.1.4
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- '@smithy/util-middleware': 2.1.4
- '@smithy/util-retry': 2.1.4
- tslib: 2.6.2
- uuid: 8.3.2
-
- '@smithy/middleware-serde@2.2.1':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/middleware-stack@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/node-config-provider@2.2.5':
- dependencies:
- '@smithy/property-provider': 2.1.4
- '@smithy/shared-ini-file-loader': 2.3.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/node-http-handler@2.4.3':
- dependencies:
- '@smithy/abort-controller': 2.1.4
- '@smithy/protocol-http': 3.2.2
- '@smithy/querystring-builder': 2.1.4
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/property-provider@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/protocol-http@3.2.2':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/querystring-builder@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
- '@smithy/util-uri-escape': 2.1.1
- tslib: 2.6.2
-
- '@smithy/querystring-parser@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/service-error-classification@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
-
- '@smithy/shared-ini-file-loader@2.3.5':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/signature-v4@2.1.4':
- dependencies:
- '@smithy/eventstream-codec': 2.1.4
- '@smithy/is-array-buffer': 2.1.1
- '@smithy/types': 2.11.0
- '@smithy/util-hex-encoding': 2.1.1
- '@smithy/util-middleware': 2.1.4
- '@smithy/util-uri-escape': 2.1.1
- '@smithy/util-utf8': 2.2.0
- tslib: 2.6.2
-
- '@smithy/smithy-client@2.4.5':
- dependencies:
- '@smithy/middleware-endpoint': 2.4.6
- '@smithy/middleware-stack': 2.1.4
- '@smithy/protocol-http': 3.2.2
- '@smithy/types': 2.11.0
- '@smithy/util-stream': 2.1.5
- tslib: 2.6.2
-
- '@smithy/types@2.11.0':
- dependencies:
- tslib: 2.6.2
-
- '@smithy/url-parser@2.1.4':
- dependencies:
- '@smithy/querystring-parser': 2.1.4
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/util-base64@2.2.1':
- dependencies:
- '@smithy/util-buffer-from': 2.1.1
- '@smithy/util-utf8': 2.2.0
- tslib: 2.6.2
-
- '@smithy/util-body-length-browser@2.1.1':
- dependencies:
- tslib: 2.6.2
-
- '@smithy/util-body-length-node@2.2.2':
- dependencies:
- tslib: 2.6.2
-
- '@smithy/util-buffer-from@2.1.1':
- dependencies:
- '@smithy/is-array-buffer': 2.1.1
- tslib: 2.6.2
-
- '@smithy/util-config-provider@2.2.1':
- dependencies:
- tslib: 2.6.2
-
- '@smithy/util-defaults-mode-browser@2.1.7':
- dependencies:
- '@smithy/property-provider': 2.1.4
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- bowser: 2.11.0
- tslib: 2.6.2
-
- '@smithy/util-defaults-mode-node@2.2.7':
- dependencies:
- '@smithy/config-resolver': 2.1.5
- '@smithy/credential-provider-imds': 2.2.6
- '@smithy/node-config-provider': 2.2.5
- '@smithy/property-provider': 2.1.4
- '@smithy/smithy-client': 2.4.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/util-endpoints@1.1.5':
- dependencies:
- '@smithy/node-config-provider': 2.2.5
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/util-hex-encoding@2.1.1':
- dependencies:
- tslib: 2.6.2
-
- '@smithy/util-middleware@2.1.4':
- dependencies:
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/util-retry@2.1.4':
- dependencies:
- '@smithy/service-error-classification': 2.1.4
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- '@smithy/util-stream@2.1.5':
- dependencies:
- '@smithy/fetch-http-handler': 2.4.5
- '@smithy/node-http-handler': 2.4.3
- '@smithy/types': 2.11.0
- '@smithy/util-base64': 2.2.1
- '@smithy/util-buffer-from': 2.1.1
- '@smithy/util-hex-encoding': 2.1.1
- '@smithy/util-utf8': 2.2.0
- tslib: 2.6.2
-
- '@smithy/util-uri-escape@2.1.1':
- dependencies:
- tslib: 2.6.2
-
- '@smithy/util-utf8@2.2.0':
- dependencies:
- '@smithy/util-buffer-from': 2.1.1
- tslib: 2.6.2
-
- '@smithy/util-waiter@2.1.4':
- dependencies:
- '@smithy/abort-controller': 2.1.4
- '@smithy/types': 2.11.0
- tslib: 2.6.2
-
- before-after-hook@2.2.3: {}
-
- bowser@2.11.0: {}
-
- deprecation@2.3.1: {}
-
- fast-xml-parser@4.2.5:
- dependencies:
- strnum: 1.0.5
-
- once@1.4.0:
- dependencies:
- wrappy: 1.0.2
-
- strnum@1.0.5: {}
-
- tslib@1.14.1: {}
-
- tslib@2.6.2: {}
-
- tunnel@0.0.6: {}
-
- undici@5.28.3:
- dependencies:
- '@fastify/busboy': 2.1.1
-
- universal-user-agent@6.0.1: {}
-
- uuid@8.3.2: {}
-
- wrappy@1.0.2: {}
diff --git a/.github/scripts/crib/pr-comment-crib-env.js b/.github/scripts/crib/pr-comment-crib-env.js
deleted file mode 100755
index cc36a9deb7b..00000000000
--- a/.github/scripts/crib/pr-comment-crib-env.js
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/usr/bin/env node
-
-import * as core from "@actions/core";
-import * as github from "@actions/github";
-import { route53RecordsExist } from "./lib/check-route53-records.js";
-
-function generateSubdomains(subdomainPrefix, prNumber) {
- const subDomainSuffixes = [
- "node1",
- "node2",
- "node3",
- "node4",
- "node5",
- "geth-1337-http",
- "geth-1337-ws",
- "geth-2337-http",
- "geth-2337-ws",
- "mockserver",
- ];
- return subDomainSuffixes.map(
- (suffix) => `${subdomainPrefix}-${prNumber}-${suffix}`
- );
-}
-
-async function commentExists(octokit, owner, repo, prNumber, uniqueIdentifier) {
- // This will automatically paginate through all comments
- const comments = await octokit.paginate(octokit.rest.issues.listComments, {
- owner,
- repo,
- issue_number: prNumber,
- });
-
- // Check each comment for the unique identifier
- return comments.some((comment) => comment.body.includes(uniqueIdentifier));
-}
-
-async function run() {
- try {
- const token = process.env.GITHUB_TOKEN;
- const route53ZoneId = process.env.ROUTE53_ZONE_ID;
- const subdomainPrefix = process.env.SUBDOMAIN_PREFIX || "crib-chainlink";
-
- // Check for the existence of GITHUB_TOKEN and ROUTE53_ZONE_ID
- if (!token || !route53ZoneId) {
- core.setFailed(
- "Error: Missing required environment variables: GITHUB_TOKEN or ROUTE53_ZONE_ID."
- );
- return;
- }
-
- const octokit = github.getOctokit(token);
- const context = github.context;
-
- const labelsToCheck = ["crib"];
- const { owner, repo } = context.repo;
- const prNumber = context.issue.number;
-
- if (!prNumber) {
- core.setFailed("Error: Could not get PR number from context");
- return;
- }
-
- // List labels on the PR
- const { data: labels } = await octokit.rest.issues.listLabelsOnIssue({
- owner,
- repo,
- issue_number: prNumber,
- });
-
- // Check if any label matches the labelsToCheck
- const labelMatches = labels.some((label) =>
- labelsToCheck.includes(label.name)
- );
-
- if (!labelMatches) {
- core.info("No 'crib' PR label found. Proceeding.");
- return;
- }
-
- const subdomains = generateSubdomains(subdomainPrefix, prNumber);
- core.debug("Subdomains:", subdomains);
-
- // Comment header and unique identifier
- const commentHeader = "## CRIB Environment Details";
-
- // Check if the comment already exists
- if (await commentExists(octokit, owner, repo, prNumber, commentHeader)) {
- core.info("CRIB environment comment already exists. Skipping.");
- return;
- }
-
- // Check if DNS records exist in Route 53 before printing out the subdomains.
- try {
- const maxRetries = 8;
- const recordsExist = await route53RecordsExist(
- route53ZoneId,
- subdomains,
- maxRetries
- );
- if (recordsExist) {
- core.info("Route 53 DNS records exist.");
- } else {
- core.setFailed(
- "Route 53 DNS records do not exist. Please check the Route 53 hosted zone."
- );
- return;
- }
- } catch (error) {
- core.setFailed(error.message);
- return;
- }
-
- const subdomainsFormatted = subdomains
- .map((subdomain) => `- ${subdomain}.`)
- .join("\n");
-
- // Construct the comment
- const comment = `${commentHeader} :information_source:
-
-CRIB activated via the 'crib' label. To destroy the environment, remove the 'crib' PR label or close the PR.
-
-Please review the following details:
-
-### Subdomains
-
-_Use these subdomains to access the CRIB environment. They are prefixes to the internal base domain which work over the VPN._
-
-${subdomainsFormatted}
-
-**NOTE:** If you have trouble resolving these subdomains, please try to reset your VPN DNS and/or local DNS.
-`;
-
- // Create a comment on the PR
- await octokit.rest.issues.createComment({
- owner,
- repo,
- issue_number: prNumber,
- body: comment,
- });
- } catch (error) {
- core.setFailed(error.message);
- }
-}
-
-run();
diff --git a/.github/scripts/jira/enforce-jira-issue.ts b/.github/scripts/jira/enforce-jira-issue.ts
new file mode 100644
index 00000000000..e0054b25d0e
--- /dev/null
+++ b/.github/scripts/jira/enforce-jira-issue.ts
@@ -0,0 +1,77 @@
+import * as core from "@actions/core";
+import jira from "jira.js";
+import { createJiraClient, parseIssueNumberFrom } from "./lib";
+
+async function doesIssueExist(
+ client: jira.Version3Client,
+ issueNumber: string,
+ dryRun: boolean
+) {
+ const payload = {
+ issueIdOrKey: issueNumber,
+ };
+
+ if (dryRun) {
+ core.info("Dry run enabled, skipping JIRA issue enforcement");
+ return true;
+ }
+
+ try {
+ /**
+ * The issue is identified by its ID or key, however, if the identifier doesn't match an issue, a case-insensitive search and check for moved issues is performed.
+ * If a matching issue is found its details are returned, a 302 or other redirect is not returned. The issue key returned in the response is the key of the issue found.
+ */
+ const issue = await client.issues.getIssue(payload);
+ core.debug(
+ `JIRA issue id:${issue.id} key: ${issue.key} found while querying for ${issueNumber}`
+ );
+ if (issue.key !== issueNumber) {
+ core.error(
+ `JIRA issue key ${issueNumber} not found, but found issue key ${issue.key} instead. This can happen if the identifier doesn't match an issue, in which case a case-insensitive search and check for moved issues is performed. Make sure the issue key is correct.`
+ );
+ return false;
+ }
+
+ return true;
+ } catch (e) {
+ core.debug(e as any);
+ return false;
+ }
+}
+
+async function main() {
+ const prTitle = process.env.PR_TITLE;
+ const commitMessage = process.env.COMMIT_MESSAGE;
+ const branchName = process.env.BRANCH_NAME;
+ const dryRun = !!process.env.DRY_RUN;
+ const client = createJiraClient();
+
+ // Checks for the Jira issue number and exit if it can't find it
+ const issueNumber = parseIssueNumberFrom(prTitle, commitMessage, branchName);
+ if (!issueNumber) {
+ const msg =
+ "No JIRA issue number found in PR title, commit message, or branch name. This pull request must be associated with a JIRA issue.";
+
+ core.setFailed(msg);
+ return;
+ }
+
+ const exists = await doesIssueExist(client, issueNumber, dryRun);
+ if (!exists) {
+ core.setFailed(`JIRA issue ${issueNumber} not found, this pull request must be associated with a JIRA issue.`);
+ return;
+ }
+}
+
+async function run() {
+ try {
+ await main();
+ } catch (error) {
+ if (error instanceof Error) {
+ return core.setFailed(error.message);
+ }
+ core.setFailed(error as any);
+ }
+}
+
+run();
diff --git a/.github/scripts/jira/lib.test.ts b/.github/scripts/jira/lib.test.ts
new file mode 100644
index 00000000000..9c751e84088
--- /dev/null
+++ b/.github/scripts/jira/lib.test.ts
@@ -0,0 +1,47 @@
+import { expect, describe, it } from "vitest";
+import { parseIssueNumberFrom, tagsToLabels } from "./lib";
+
+describe("parseIssueNumberFrom", () => {
+ it("should return the first JIRA issue number found", () => {
+ let r = parseIssueNumberFrom("CORE-123", "CORE-456", "CORE-789");
+ expect(r).to.equal("CORE-123");
+
+ r = parseIssueNumberFrom(
+ "2f3df5gf",
+ "chore/test-RE-78-branch",
+ "RE-78 Create new test branches"
+ );
+ expect(r).to.equal("RE-78");
+
+ // handle lower case
+ r = parseIssueNumberFrom("core-123", "CORE-456", "CORE-789");
+ expect(r).to.equal("CORE-123");
+ });
+
+ it("works with multiline commit bodies", () => {
+ const r = parseIssueNumberFrom(
+ `This is a multiline commit body
+
+CORE-1011`,
+ "CORE-456",
+ "CORE-789"
+ );
+ expect(r).to.equal("CORE-1011");
+ });
+
+ it("should return undefined if no JIRA issue number is found", () => {
+ const result = parseIssueNumberFrom("No issue number");
+ expect(result).to.be.undefined;
+ });
+});
+
+describe("tagsToLabels", () => {
+ it("should convert an array of tags to an array of labels", () => {
+ const tags = ["v1.0.0", "v1.1.0"];
+ const result = tagsToLabels(tags);
+ expect(result).to.deep.equal([
+ { add: "core-release/1.0.0" },
+ { add: "core-release/1.1.0" },
+ ]);
+ });
+});
diff --git a/.github/scripts/jira/lib.ts b/.github/scripts/jira/lib.ts
new file mode 100644
index 00000000000..72f1d57966c
--- /dev/null
+++ b/.github/scripts/jira/lib.ts
@@ -0,0 +1,63 @@
+
+import * as core from '@actions/core'
+import * as jira from 'jira.js'
+
+/**
+ * Given a list of strings, this function will return the first JIRA issue number it finds.
+ *
+ * @example parseIssueNumberFrom("CORE-123", "CORE-456", "CORE-789") => "CORE-123"
+ * @example parseIssueNumberFrom("2f3df5gf", "chore/test-RE-78-branch", "RE-78 Create new test branches") => "RE-78"
+ */
+export function parseIssueNumberFrom(
+ ...inputs: (string | undefined)[]
+): string | undefined {
+ function parse(str?: string) {
+ const jiraIssueRegex = /[A-Z]{2,}-\d+/;
+
+ return str?.toUpperCase().match(jiraIssueRegex)?.[0];
+ }
+
+ core.debug(`Parsing issue number from: ${inputs.join(", ")}`);
+ const parsed: string[] = inputs.map(parse).filter((x) => x !== undefined);
+ core.debug(`Found issue number: ${parsed[0]}`);
+
+ return parsed[0];
+}
+
+/**
+ * Converts an array of tags to an array of labels.
+ *
+ * A label is a string that is formatted as `core-release/{tag}`, with the leading `v` removed from the tag.
+ *
+ * @example tagsToLabels(["v1.0.0", "v1.1.0"]) => [{ add: "core-release/1.0.0" }, { add: "core-release/1.1.0" }]
+ */
+export function tagsToLabels(tags: string[]) {
+ const labelPrefix = "core-release";
+
+ return tags.map((t) => ({
+ add: `${labelPrefix}/${t.substring(1)}`,
+ }));
+}
+
+export function createJiraClient() {
+ const jiraHost = process.env.JIRA_HOST;
+ const jiraUserName = process.env.JIRA_USERNAME;
+ const jiraApiToken = process.env.JIRA_API_TOKEN;
+
+ if (!jiraHost || !jiraUserName || !jiraApiToken) {
+ core.setFailed(
+ "Error: Missing required environment variables: JIRA_HOST and JIRA_USERNAME and JIRA_API_TOKEN."
+ );
+ process.exit(1);
+ }
+
+ return new jira.Version3Client({
+ host: jiraHost,
+ authentication: {
+ basic: {
+ email: jiraUserName,
+ apiToken: jiraApiToken,
+ },
+ },
+ });
+}
diff --git a/.github/scripts/jira/package.json b/.github/scripts/jira/package.json
index 2c57d35a647..95bfbb1e486 100644
--- a/.github/scripts/jira/package.json
+++ b/.github/scripts/jira/package.json
@@ -12,8 +12,19 @@
"node": ">=18",
"pnpm": ">=9"
},
+ "scripts": {
+ "issue:update": "tsx update-jira-issue.ts",
+ "issue:enforce": "tsx enforce-jira-issue.ts",
+ "test": "vitest"
+ },
"dependencies": {
"@actions/core": "^1.10.1",
- "node-fetch": "^2.7.0"
+ "jira.js": "^4.0.1",
+ "tsx": "^4.16.2"
+ },
+ "devDependencies": {
+ "@types/node": "^20.14.10",
+ "typescript": "^5.5.3",
+ "vitest": "^2.0.3"
}
}
diff --git a/.github/scripts/jira/pnpm-lock.yaml b/.github/scripts/jira/pnpm-lock.yaml
index 09ba8c749cc..4deeef7f339 100644
--- a/.github/scripts/jira/pnpm-lock.yaml
+++ b/.github/scripts/jira/pnpm-lock.yaml
@@ -11,9 +11,22 @@ importers:
'@actions/core':
specifier: ^1.10.1
version: 1.10.1
- node-fetch:
- specifier: ^2.7.0
- version: 2.7.0
+ jira.js:
+ specifier: ^4.0.1
+ version: 4.0.1
+ tsx:
+ specifier: ^4.16.2
+ version: 4.16.2
+ devDependencies:
+ '@types/node':
+ specifier: ^20.14.10
+ version: 20.14.10
+ typescript:
+ specifier: ^5.5.3
+ version: 5.5.3
+ vitest:
+ specifier: ^2.0.3
+ version: 2.0.3(@types/node@20.14.10)
packages:
@@ -23,26 +36,509 @@ packages:
'@actions/http-client@2.2.1':
resolution: {integrity: sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==}
+ '@ampproject/remapping@2.3.0':
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
+
+ '@esbuild/aix-ppc64@0.21.5':
+ resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.21.5':
+ resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.21.5':
+ resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.21.5':
+ resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.21.5':
+ resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.21.5':
+ resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.21.5':
+ resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.21.5':
+ resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.21.5':
+ resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.21.5':
+ resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.21.5':
+ resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.21.5':
+ resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.21.5':
+ resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.21.5':
+ resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.21.5':
+ resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.21.5':
+ resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-x64@0.21.5':
+ resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-x64@0.21.5':
+ resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.21.5':
+ resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.21.5':
+ resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.21.5':
+ resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.21.5':
+ resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+
'@fastify/busboy@2.1.1':
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
engines: {node: '>=14'}
- node-fetch@2.7.0:
- resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
- engines: {node: 4.x || >=6.0.0}
+ '@jridgewell/gen-mapping@0.3.5':
+ resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/set-array@1.2.1':
+ resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.0':
+ resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
+ '@rollup/rollup-android-arm-eabi@4.18.1':
+ resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.18.1':
+ resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.18.1':
+ resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.18.1':
+ resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.18.1':
+ resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.18.1':
+ resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.18.1':
+ resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.18.1':
+ resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.18.1':
+ resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.18.1':
+ resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.18.1':
+ resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.18.1':
+ resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.18.1':
+ resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-win32-arm64-msvc@4.18.1':
+ resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.18.1':
+ resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.18.1':
+ resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==}
+ cpu: [x64]
+ os: [win32]
+
+ '@types/estree@1.0.5':
+ resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+
+ '@types/node@20.14.10':
+ resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==}
+
+ '@vitest/expect@2.0.3':
+ resolution: {integrity: sha512-X6AepoOYePM0lDNUPsGXTxgXZAl3EXd0GYe/MZyVE4HzkUqyUVC6S3PrY5mClDJ6/7/7vALLMV3+xD/Ko60Hqg==}
+
+ '@vitest/pretty-format@2.0.3':
+ resolution: {integrity: sha512-URM4GLsB2xD37nnTyvf6kfObFafxmycCL8un3OC9gaCs5cti2u+5rJdIflZ2fUJUen4NbvF6jCufwViAFLvz1g==}
+
+ '@vitest/runner@2.0.3':
+ resolution: {integrity: sha512-EmSP4mcjYhAcuBWwqgpjR3FYVeiA4ROzRunqKltWjBfLNs1tnMLtF+qtgd5ClTwkDP6/DGlKJTNa6WxNK0bNYQ==}
+
+ '@vitest/snapshot@2.0.3':
+ resolution: {integrity: sha512-6OyA6v65Oe3tTzoSuRPcU6kh9m+mPL1vQ2jDlPdn9IQoUxl8rXhBnfICNOC+vwxWY684Vt5UPgtcA2aPFBb6wg==}
+
+ '@vitest/spy@2.0.3':
+ resolution: {integrity: sha512-sfqyAw/ypOXlaj4S+w8689qKM1OyPOqnonqOc9T91DsoHbfN5mU7FdifWWv3MtQFf0lEUstEwR9L/q/M390C+A==}
+
+ '@vitest/utils@2.0.3':
+ resolution: {integrity: sha512-c/UdELMuHitQbbc/EVctlBaxoYAwQPQdSNwv7z/vHyBKy2edYZaFgptE27BRueZB7eW8po+cllotMNTDpL3HWg==}
+
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+ axios@1.7.2:
+ resolution: {integrity: sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==}
+
+ cac@6.7.14:
+ resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+ engines: {node: '>=8'}
+
+ chai@5.1.1:
+ resolution: {integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==}
+ engines: {node: '>=12'}
+
+ check-error@2.1.1:
+ resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+ engines: {node: '>= 16'}
+
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
+ cross-spawn@7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+
+ debug@4.3.5:
+ resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+ engines: {node: '>=6'}
+
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
+ esbuild@0.21.5:
+ resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ estree-walker@3.0.3:
+ resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
+ execa@8.0.1:
+ resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
+ engines: {node: '>=16.17'}
+
+ follow-redirects@1.15.6:
+ resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
+ engines: {node: '>=4.0'}
peerDependencies:
- encoding: ^0.1.0
+ debug: '*'
peerDependenciesMeta:
- encoding:
+ debug:
optional: true
- tr46@0.0.3:
- resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+ form-data@4.0.0:
+ resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
+ engines: {node: '>= 6'}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ get-func-name@2.0.2:
+ resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
+
+ get-stream@8.0.1:
+ resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==}
+ engines: {node: '>=16'}
+
+ get-tsconfig@4.7.5:
+ resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==}
+
+ human-signals@5.0.0:
+ resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
+ engines: {node: '>=16.17.0'}
+
+ is-stream@3.0.0:
+ resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ jira.js@4.0.1:
+ resolution: {integrity: sha512-2zf8LozW9rgx5wgTdGSJMhUXDK1g8a/ngm1xDWnREX/h8kuBhNkMro4XELA2XRVvaNTbRMIK3PBgOvWFDddhIw==}
+
+ loupe@3.1.1:
+ resolution: {integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==}
+
+ magic-string@0.30.10:
+ resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
+
+ merge-stream@2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
+ mime-db@1.52.0:
+ resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+ engines: {node: '>= 0.6'}
+
+ mime-types@2.1.35:
+ resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+ engines: {node: '>= 0.6'}
+
+ mimic-fn@4.0.0:
+ resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
+ engines: {node: '>=12'}
+
+ ms@2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+
+ nanoid@3.3.7:
+ resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ npm-run-path@5.3.0:
+ resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+
+ onetime@6.0.0:
+ resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
+ engines: {node: '>=12'}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ path-key@4.0.0:
+ resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+ engines: {node: '>=12'}
+
+ pathe@1.1.2:
+ resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
+
+ pathval@2.0.0:
+ resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
+ engines: {node: '>= 14.16'}
+
+ picocolors@1.0.1:
+ resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
+
+ postcss@8.4.39:
+ resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ proxy-from-env@1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+ resolve-pkg-maps@1.0.0:
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+ rollup@4.18.1:
+ resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
+ signal-exit@4.1.0:
+ resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+ engines: {node: '>=14'}
+
+ source-map-js@1.2.0:
+ resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
+ engines: {node: '>=0.10.0'}
+
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+ std-env@3.7.0:
+ resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==}
+
+ strip-final-newline@3.0.0:
+ resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
+ engines: {node: '>=12'}
+
+ tinybench@2.8.0:
+ resolution: {integrity: sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==}
+
+ tinypool@1.0.0:
+ resolution: {integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
+ tinyrainbow@1.2.0:
+ resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
+ engines: {node: '>=14.0.0'}
+
+ tinyspy@3.0.0:
+ resolution: {integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==}
+ engines: {node: '>=14.0.0'}
+
+ tslib@2.6.3:
+ resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
+
+ tsx@4.16.2:
+ resolution: {integrity: sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==}
+ engines: {node: '>=18.0.0'}
+ hasBin: true
tunnel@0.0.6:
resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
+ typescript@5.5.3:
+ resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ undici-types@5.26.5:
+ resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+
undici@5.28.4:
resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==}
engines: {node: '>=14.0'}
@@ -51,11 +547,73 @@ packages:
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
hasBin: true
- webidl-conversions@3.0.1:
- resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+ vite-node@2.0.3:
+ resolution: {integrity: sha512-14jzwMx7XTcMB+9BhGQyoEAmSl0eOr3nrnn+Z12WNERtOvLN+d2scbRUvyni05rT3997Bg+rZb47NyP4IQPKXg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+
+ vite@5.3.3:
+ resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+
+ vitest@2.0.3:
+ resolution: {integrity: sha512-o3HRvU93q6qZK4rI2JrhKyZMMuxg/JRt30E6qeQs6ueaiz5hr1cPj+Sk2kATgQzMMqsa2DiNI0TIK++1ULx8Jw==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/node': ^18.0.0 || >=20.0.0
+ '@vitest/browser': 2.0.3
+ '@vitest/ui': 2.0.3
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
- whatwg-url@5.0.0:
- resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
snapshots:
@@ -69,25 +627,485 @@ snapshots:
tunnel: 0.0.6
undici: 5.28.4
+ '@ampproject/remapping@2.3.0':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@esbuild/aix-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm@0.21.5':
+ optional: true
+
+ '@esbuild/android-x64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-x64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/linux-loong64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-s390x@0.21.5':
+ optional: true
+
+ '@esbuild/linux-x64@0.21.5':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/sunos-x64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/win32-x64@0.21.5':
+ optional: true
+
'@fastify/busboy@2.1.1': {}
- node-fetch@2.7.0:
+ '@jridgewell/gen-mapping@0.3.5':
+ dependencies:
+ '@jridgewell/set-array': 1.2.1
+ '@jridgewell/sourcemap-codec': 1.5.0
+ '@jridgewell/trace-mapping': 0.3.25
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/set-array@1.2.1': {}
+
+ '@jridgewell/sourcemap-codec@1.5.0': {}
+
+ '@jridgewell/trace-mapping@0.3.25':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ '@rollup/rollup-android-arm-eabi@4.18.1':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.18.1':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.18.1':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.18.1':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.18.1':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.18.1':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.18.1':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.18.1':
+ optional: true
+
+ '@types/estree@1.0.5': {}
+
+ '@types/node@20.14.10':
+ dependencies:
+ undici-types: 5.26.5
+
+ '@vitest/expect@2.0.3':
+ dependencies:
+ '@vitest/spy': 2.0.3
+ '@vitest/utils': 2.0.3
+ chai: 5.1.1
+ tinyrainbow: 1.2.0
+
+ '@vitest/pretty-format@2.0.3':
+ dependencies:
+ tinyrainbow: 1.2.0
+
+ '@vitest/runner@2.0.3':
+ dependencies:
+ '@vitest/utils': 2.0.3
+ pathe: 1.1.2
+
+ '@vitest/snapshot@2.0.3':
+ dependencies:
+ '@vitest/pretty-format': 2.0.3
+ magic-string: 0.30.10
+ pathe: 1.1.2
+
+ '@vitest/spy@2.0.3':
+ dependencies:
+ tinyspy: 3.0.0
+
+ '@vitest/utils@2.0.3':
+ dependencies:
+ '@vitest/pretty-format': 2.0.3
+ estree-walker: 3.0.3
+ loupe: 3.1.1
+ tinyrainbow: 1.2.0
+
+ assertion-error@2.0.1: {}
+
+ asynckit@0.4.0: {}
+
+ axios@1.7.2:
+ dependencies:
+ follow-redirects: 1.15.6
+ form-data: 4.0.0
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+
+ cac@6.7.14: {}
+
+ chai@5.1.1:
+ dependencies:
+ assertion-error: 2.0.1
+ check-error: 2.1.1
+ deep-eql: 5.0.2
+ loupe: 3.1.1
+ pathval: 2.0.0
+
+ check-error@2.1.1: {}
+
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+
+ cross-spawn@7.0.3:
dependencies:
- whatwg-url: 5.0.0
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
- tr46@0.0.3: {}
+ debug@4.3.5:
+ dependencies:
+ ms: 2.1.2
+
+ deep-eql@5.0.2: {}
+
+ delayed-stream@1.0.0: {}
+
+ esbuild@0.21.5:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.21.5
+ '@esbuild/android-arm': 0.21.5
+ '@esbuild/android-arm64': 0.21.5
+ '@esbuild/android-x64': 0.21.5
+ '@esbuild/darwin-arm64': 0.21.5
+ '@esbuild/darwin-x64': 0.21.5
+ '@esbuild/freebsd-arm64': 0.21.5
+ '@esbuild/freebsd-x64': 0.21.5
+ '@esbuild/linux-arm': 0.21.5
+ '@esbuild/linux-arm64': 0.21.5
+ '@esbuild/linux-ia32': 0.21.5
+ '@esbuild/linux-loong64': 0.21.5
+ '@esbuild/linux-mips64el': 0.21.5
+ '@esbuild/linux-ppc64': 0.21.5
+ '@esbuild/linux-riscv64': 0.21.5
+ '@esbuild/linux-s390x': 0.21.5
+ '@esbuild/linux-x64': 0.21.5
+ '@esbuild/netbsd-x64': 0.21.5
+ '@esbuild/openbsd-x64': 0.21.5
+ '@esbuild/sunos-x64': 0.21.5
+ '@esbuild/win32-arm64': 0.21.5
+ '@esbuild/win32-ia32': 0.21.5
+ '@esbuild/win32-x64': 0.21.5
+
+ estree-walker@3.0.3:
+ dependencies:
+ '@types/estree': 1.0.5
+
+ execa@8.0.1:
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 8.0.1
+ human-signals: 5.0.0
+ is-stream: 3.0.0
+ merge-stream: 2.0.0
+ npm-run-path: 5.3.0
+ onetime: 6.0.0
+ signal-exit: 4.1.0
+ strip-final-newline: 3.0.0
+
+ follow-redirects@1.15.6: {}
+
+ form-data@4.0.0:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.35
+
+ fsevents@2.3.3:
+ optional: true
+
+ get-func-name@2.0.2: {}
+
+ get-stream@8.0.1: {}
+
+ get-tsconfig@4.7.5:
+ dependencies:
+ resolve-pkg-maps: 1.0.0
+
+ human-signals@5.0.0: {}
+
+ is-stream@3.0.0: {}
+
+ isexe@2.0.0: {}
+
+ jira.js@4.0.1:
+ dependencies:
+ axios: 1.7.2
+ form-data: 4.0.0
+ tslib: 2.6.3
+ transitivePeerDependencies:
+ - debug
+
+ loupe@3.1.1:
+ dependencies:
+ get-func-name: 2.0.2
+
+ magic-string@0.30.10:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.0
+
+ merge-stream@2.0.0: {}
+
+ mime-db@1.52.0: {}
+
+ mime-types@2.1.35:
+ dependencies:
+ mime-db: 1.52.0
+
+ mimic-fn@4.0.0: {}
+
+ ms@2.1.2: {}
+
+ nanoid@3.3.7: {}
+
+ npm-run-path@5.3.0:
+ dependencies:
+ path-key: 4.0.0
+
+ onetime@6.0.0:
+ dependencies:
+ mimic-fn: 4.0.0
+
+ path-key@3.1.1: {}
+
+ path-key@4.0.0: {}
+
+ pathe@1.1.2: {}
+
+ pathval@2.0.0: {}
+
+ picocolors@1.0.1: {}
+
+ postcss@8.4.39:
+ dependencies:
+ nanoid: 3.3.7
+ picocolors: 1.0.1
+ source-map-js: 1.2.0
+
+ proxy-from-env@1.1.0: {}
+
+ resolve-pkg-maps@1.0.0: {}
+
+ rollup@4.18.1:
+ dependencies:
+ '@types/estree': 1.0.5
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.18.1
+ '@rollup/rollup-android-arm64': 4.18.1
+ '@rollup/rollup-darwin-arm64': 4.18.1
+ '@rollup/rollup-darwin-x64': 4.18.1
+ '@rollup/rollup-linux-arm-gnueabihf': 4.18.1
+ '@rollup/rollup-linux-arm-musleabihf': 4.18.1
+ '@rollup/rollup-linux-arm64-gnu': 4.18.1
+ '@rollup/rollup-linux-arm64-musl': 4.18.1
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.18.1
+ '@rollup/rollup-linux-riscv64-gnu': 4.18.1
+ '@rollup/rollup-linux-s390x-gnu': 4.18.1
+ '@rollup/rollup-linux-x64-gnu': 4.18.1
+ '@rollup/rollup-linux-x64-musl': 4.18.1
+ '@rollup/rollup-win32-arm64-msvc': 4.18.1
+ '@rollup/rollup-win32-ia32-msvc': 4.18.1
+ '@rollup/rollup-win32-x64-msvc': 4.18.1
+ fsevents: 2.3.3
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ siginfo@2.0.0: {}
+
+ signal-exit@4.1.0: {}
+
+ source-map-js@1.2.0: {}
+
+ stackback@0.0.2: {}
+
+ std-env@3.7.0: {}
+
+ strip-final-newline@3.0.0: {}
+
+ tinybench@2.8.0: {}
+
+ tinypool@1.0.0: {}
+
+ tinyrainbow@1.2.0: {}
+
+ tinyspy@3.0.0: {}
+
+ tslib@2.6.3: {}
+
+ tsx@4.16.2:
+ dependencies:
+ esbuild: 0.21.5
+ get-tsconfig: 4.7.5
+ optionalDependencies:
+ fsevents: 2.3.3
tunnel@0.0.6: {}
+ typescript@5.5.3: {}
+
+ undici-types@5.26.5: {}
+
undici@5.28.4:
dependencies:
'@fastify/busboy': 2.1.1
uuid@8.3.2: {}
- webidl-conversions@3.0.1: {}
+ vite-node@2.0.3(@types/node@20.14.10):
+ dependencies:
+ cac: 6.7.14
+ debug: 4.3.5
+ pathe: 1.1.2
+ tinyrainbow: 1.2.0
+ vite: 5.3.3(@types/node@20.14.10)
+ transitivePeerDependencies:
+ - '@types/node'
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
+ vite@5.3.3(@types/node@20.14.10):
+ dependencies:
+ esbuild: 0.21.5
+ postcss: 8.4.39
+ rollup: 4.18.1
+ optionalDependencies:
+ '@types/node': 20.14.10
+ fsevents: 2.3.3
+
+ vitest@2.0.3(@types/node@20.14.10):
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@vitest/expect': 2.0.3
+ '@vitest/pretty-format': 2.0.3
+ '@vitest/runner': 2.0.3
+ '@vitest/snapshot': 2.0.3
+ '@vitest/spy': 2.0.3
+ '@vitest/utils': 2.0.3
+ chai: 5.1.1
+ debug: 4.3.5
+ execa: 8.0.1
+ magic-string: 0.30.10
+ pathe: 1.1.2
+ std-env: 3.7.0
+ tinybench: 2.8.0
+ tinypool: 1.0.0
+ tinyrainbow: 1.2.0
+ vite: 5.3.3(@types/node@20.14.10)
+ vite-node: 2.0.3(@types/node@20.14.10)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 20.14.10
+ transitivePeerDependencies:
+ - less
+ - lightningcss
+ - sass
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
- whatwg-url@5.0.0:
+ why-is-node-running@2.3.0:
dependencies:
- tr46: 0.0.3
- webidl-conversions: 3.0.1
+ siginfo: 2.0.0
+ stackback: 0.0.2
diff --git a/.github/scripts/jira/tsconfig.json b/.github/scripts/jira/tsconfig.json
new file mode 100644
index 00000000000..746f76774b0
--- /dev/null
+++ b/.github/scripts/jira/tsconfig.json
@@ -0,0 +1,108 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig to read more about this file */
+
+ /* Projects */
+ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
+ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
+ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
+ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
+ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
+ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
+
+ /* Language and Environment */
+ "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+ // "jsx": "preserve", /* Specify what JSX code is generated. */
+ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
+ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
+ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
+ // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
+ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
+ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
+ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
+
+ /* Modules */
+ "module": "commonjs", /* Specify what module code is generated. */
+ // "rootDir": "./", /* Specify the root folder within your source files. */
+ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
+ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
+ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
+ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
+ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
+ // "types": [], /* Specify type package names to be included without being referenced in a source file. */
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
+ // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
+ // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
+ // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
+ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
+ // "resolveJsonModule": true, /* Enable importing .json files. */
+ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
+ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
+
+ /* JavaScript Support */
+ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
+ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
+ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
+
+ /* Emit */
+ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
+ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
+ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
+ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
+ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
+ // "outDir": "./", /* Specify an output folder for all emitted files. */
+ // "removeComments": true, /* Disable emitting comments. */
+ // "noEmit": true, /* Disable emitting files from a compilation. */
+ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
+ // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
+ // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+ // "newLine": "crlf", /* Set the newline character for emitting files. */
+ // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+ // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
+ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
+ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
+ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
+
+ /* Interop Constraints */
+ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
+ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
+ // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
+ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
+ "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
+ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
+
+ /* Type Checking */
+ "strict": true, /* Enable all strict type-checking options. */
+ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
+ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+ // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
+ // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
+ // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
+ // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
+ // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
+ // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
+ // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
+ // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
+ // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
+ // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
+ // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
+ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
+ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
+ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
+ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
+
+ /* Completeness */
+ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */
+ }
+}
diff --git a/.github/scripts/jira/update-jira-issue.js b/.github/scripts/jira/update-jira-issue.js
deleted file mode 100644
index 77d5b81bff8..00000000000
--- a/.github/scripts/jira/update-jira-issue.js
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env node
-
-import * as core from "@actions/core";
-import fetch from "node-fetch";
-
-function parseIssueNumber(prTitle, commitMessage, branchName) {
- const jiraIssueRegex = /[A-Z]{2,}-\d+/;
- if (!!branchName && jiraIssueRegex.test(branchName.toUpperCase())) {
- return branchName.toUpperCase().match(jiraIssueRegex)[0];
- } else if (
- !!commitMessage &&
- jiraIssueRegex.test(commitMessage.toUpperCase())
- ) {
- return commitMessage.toUpperCase().match(jiraIssueRegex)[0];
- } else if (!!prTitle && jiraIssueRegex.test(prTitle.toUpperCase())) {
- return prTitle.toUpperCase().match(jiraIssueRegex)[0];
- } else {
- return null;
- }
-}
-
-function getLabels(tags) {
- const labelPrefix = "core-release";
- return tags.map((tag) => {
- return {
- add: `${labelPrefix}/${tag.substring(1)}`,
- };
- });
-}
-
-async function updateJiraIssue(
- jiraHost,
- jiraUserName,
- jiraApiToken,
- issueNumber,
- tags,
- fixVersionName
-) {
- const token = Buffer.from(`${jiraUserName}:${jiraApiToken}`).toString(
- "base64"
- );
- const bodyData = {
- update: {
- labels: getLabels(tags),
- fixVersions: [{ set: [{ name: fixVersionName }] }],
- },
- };
-
- fetch(`https://${jiraHost}/rest/api/3/issue/${issueNumber}`, {
- method: "PUT",
- headers: {
- Authorization: `Basic ${token}`,
- Accept: "application/json",
- "Content-Type": "application/json",
- },
- body: JSON.stringify(bodyData),
- })
- .then((response) => {
- console.log(`Response: ${JSON.stringify(response)}`);
- return response.text();
- })
- .then((text) => console.log(text))
- .catch((err) => console.error(err));
-}
-
-async function run() {
- try {
- const jiraHost = process.env.JIRA_HOST;
- const jiraUserName = process.env.JIRA_USERNAME;
- const jiraApiToken = process.env.JIRA_API_TOKEN;
- const chainlinkVersion = process.env.CHAINLINK_VERSION;
- const prTitle = process.env.PR_TITLE;
- const commitMessage = process.env.COMMIT_MESSAGE;
- const branchName = process.env.BRANCH_NAME;
- // tags are not getting used at the current moment so will always default to []
- const tags = process.env.FOUND_TAGS
- ? process.env.FOUND_TAGS.split(",")
- : [];
-
- // Check for the existence of JIRA_HOST and JIRA_USERNAME and JIRA_API_TOKEN
- if (!jiraHost || !jiraUserName || !jiraApiToken) {
- core.setFailed(
- "Error: Missing required environment variables: JIRA_HOST and JIRA_USERNAME and JIRA_API_TOKEN."
- );
- return;
- }
-
- // Checks for the Jira issue number and exit if it can't find it
- const issueNumber = parseIssueNumber(prTitle, commitMessage, branchName);
- if (!issueNumber) {
- core.info(
- "No JIRA issue number found in: PR title, commit message, or branch name. Please include the issue ID in one of these."
- );
- core.notice(
- "No JIRA issue number found in: PR title, commit message, or branch name. Please include the issue ID in one of these."
- );
- core.setOutput(
- "jiraComment",
- "> :medal_military: No JIRA issue number found - Please include it in the PR title or in a commit message."
- );
- return;
- }
- const fixVersionName = `chainlink-v${chainlinkVersion}`;
- await updateJiraIssue(
- jiraHost,
- jiraUserName,
- jiraApiToken,
- issueNumber,
- tags,
- fixVersionName
- );
- core.setOutput("jiraComment", "");
- } catch (error) {
- core.setFailed(error.message);
- }
-}
-
-run();
diff --git a/.github/scripts/jira/update-jira-issue.ts b/.github/scripts/jira/update-jira-issue.ts
new file mode 100644
index 00000000000..6e539c7ffa8
--- /dev/null
+++ b/.github/scripts/jira/update-jira-issue.ts
@@ -0,0 +1,77 @@
+import * as core from "@actions/core";
+import jira from "jira.js";
+import { tagsToLabels, createJiraClient, parseIssueNumberFrom } from "./lib";
+
+function updateJiraIssue(
+ client: jira.Version3Client,
+ issueNumber: string,
+ tags: string[],
+ fixVersionName: string,
+ dryRun: boolean
+) {
+ const payload = {
+ issueIdOrKey: issueNumber,
+ update: {
+ labels: tagsToLabels(tags),
+ fixVersions: [{ set: [{ name: fixVersionName }] }],
+ },
+ };
+
+ core.info(
+ `Updating JIRA issue ${issueNumber} with fix version ${fixVersionName} and labels [${payload.update.labels.join(
+ ", "
+ )}]`
+ );
+ if (dryRun) {
+ core.info("Dry run enabled, skipping JIRA issue update");
+ return;
+ }
+
+ return client.issues.editIssue(payload);
+}
+
+async function main() {
+ const prTitle = process.env.PR_TITLE;
+ const commitMessage = process.env.COMMIT_MESSAGE;
+ const branchName = process.env.BRANCH_NAME;
+
+ const chainlinkVersion = process.env.CHAINLINK_VERSION;
+ const dryRun = !!process.env.DRY_RUN;
+ // tags are not getting used at the current moment so will always default to []
+ const tags = process.env.FOUND_TAGS ? process.env.FOUND_TAGS.split(",") : [];
+
+ const client = createJiraClient();
+
+ // Checks for the Jira issue number and exit if it can't find it
+ const issueNumber = parseIssueNumberFrom(prTitle, commitMessage, branchName);
+ if (!issueNumber) {
+ const msg =
+ "No JIRA issue number found in: PR title, commit message, or branch name. Please include the issue ID in one of these.";
+
+ core.info(msg);
+ core.notice(msg);
+ core.setOutput("jiraComment", `> :medal_military: ${msg}`);
+
+ return;
+ }
+
+ const fixVersionName = `chainlink-v${chainlinkVersion}`;
+ await updateJiraIssue(client, issueNumber, tags, fixVersionName, dryRun);
+
+ core.setOutput("jiraComment", "");
+}
+
+async function run() {
+ try {
+ await main();
+ } catch (error) {
+ if (error instanceof Error) {
+ core.setFailed(error.message);
+ }
+ core.setFailed(
+ "Error: Failed to update JIRA issue with fix version and labels."
+ );
+ }
+}
+
+run();
diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml
index 7514743fa88..ed69bd5ac05 100644
--- a/.github/workflows/automation-ondemand-tests.yml
+++ b/.github/workflows/automation-ondemand-tests.yml
@@ -1,16 +1,17 @@
-name: Automation On Demand Tests
+name: Run Automation On Demand Tests
+
on:
workflow_dispatch:
inputs:
chainlinkVersionUpdate:
- description: Chainlink image version to upgrade to
+ description: Chainlink image version to upgrade to (Leave empty to build from head/ref)
required: false
type: string
chainlinkImageUpdate:
- description: Chainlink image repo to upgrade to (Leave empty to build from head/ref)
+ description: Chainlink image repo to upgrade to
options:
- - public.ecr.aws/chainlink/chainlink
- QA_ECR
+ - public.ecr.aws/chainlink/chainlink
type: choice
chainlinkVersion:
description: Chainlink image version to use initially for upgrade test
@@ -34,285 +35,144 @@ on:
type: boolean
default: false
required: true
-
-env:
- ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }}
- CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink
+ with_existing_remote_runner_version:
+ description: 'Tag of the existing remote runner version to use (Leave empty to build from head/ref)'
+ required: false
+ type: string
jobs:
- build-chainlink:
- environment: integration
- permissions:
- id-token: write
- contents: read
- strategy:
- matrix:
- image:
- - name: ""
- dockerfile: core/chainlink.Dockerfile
- tag-suffix: ""
- - name: (plugins)
- dockerfile: plugins/chainlink.Dockerfile
- tag-suffix: -plugins
- name: Build Chainlink Image ${{ matrix.image.name }}
- runs-on: ubuntu22.04-16cores-64GB
+ # Set tests to run based on the workflow inputs
+ set-tests-to-run:
+ name: Set tests to run
+ runs-on: ubuntu-latest
+ outputs:
+ test_list: ${{ steps.set-tests.outputs.test_list }}
+ require_chainlink_image_versions_in_qa_ecr: ${{ steps.determine-chainlink-image-check.outputs.require_chainlink_image_versions_in_qa_ecr }}
steps:
- - name: Collect Metrics
- if: inputs.chainlinkImage == ''
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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@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@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
- with:
- repository: chainlink
- tag: ${{ github.sha }}${{ matrix.image.tag-suffix }}
- AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- 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@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
- with:
- cl_repo: smartcontractkit/chainlink
- cl_ref: ${{ github.sha }}
- cl_dockerfile: ${{ matrix.image.dockerfile }}
- push_tag: ${{ env.CHAINLINK_IMAGE }}:${{ github.sha }}${{ matrix.image.tag-suffix }}
- QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- - name: Print Chainlink Image Built
- if: inputs.chainlinkImage == ''
- run: |
- echo "### chainlink node image tag used for this test run :link:" >>$GITHUB_STEP_SUMMARY
- echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY
-
- build-test-image:
- environment: integration
- permissions:
- id-token: write
- contents: read
- name: Build Test Image
- runs-on: ubuntu22.04-16cores-64GB
- steps:
- - name: Collect Metrics
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- with:
- ref: ${{ github.head_ref || github.ref_name }}
- - name: Build Test Image
- if: inputs.enableChaos || inputs.enableReorg
- uses: ./.github/actions/build-test-image
- with:
- QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
-
- automation-on-demand-tests:
- environment: integration
- permissions:
- checks: write
- pull-requests: write
- id-token: write
- contents: read
- needs: [build-chainlink, build-test-image]
- env:
- CHAINLINK_COMMIT_SHA: ${{ github.sha }}
- CHAINLINK_ENV_USER: ${{ github.actor }}
- TEST_LOG_LEVEL: info
- strategy:
- fail-fast: false
- matrix:
- tests:
- - name: chaos
- id: chaos
- suite: chaos
- nodes: 20
- os: ubuntu-latest
- enabled: ${{ inputs.enableChaos }}
- pyroscope_env: ci-automation-on-demand-chaos
- network: SIMULATED
- command: -run ^TestAutomationChaos$ ./chaos
- - name: reorg 2.0
- id: reorg-2.0
- suite: reorg
- nodes: 1
- os: ubuntu-latest
- enabled: ${{ inputs.enableReorg }}
- pyroscope_env: ci-automation-on-demand-reorg
- network: SIMULATED
- command: -run ^TestAutomationReorg/registry_2_0 ./reorg
- - name: reorg 2.1
- id: reorg-2.1
- suite: reorg
- nodes: 2
- os: ubuntu-latest
- enabled: ${{ inputs.enableReorg }}
- pyroscope_env: ci-automation-on-demand-reorg
- network: SIMULATED
- command: -run ^TestAutomationReorg/registry_2_1 ./reorg
- - name: reorg 2.2
- id: reorg-2.2
- suite: reorg
- nodes: 2
- os: ubuntu-latest
- enabled: ${{ inputs.enableReorg }}
- pyroscope_env: ci-automation-on-demand-reorg
- network: SIMULATED
- command: -run ^TestAutomationReorg/registry_2_2 ./reorg
- - name: reorg 2.3
- id: reorg-2.3
- suite: reorg
- nodes: 2
- os: ubuntu-latest
- enabled: ${{ inputs.enableReorg }}
- pyroscope_env: ci-automation-on-demand-reorg
- network: SIMULATED
- command: -run ^TestAutomationReorg/registry_2_3 ./reorg
- - name: upgrade 2.0
- id: upgrade-2.0
- type: upgrade
- suite: smoke
- nodes: 1
- 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: 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: ubuntu22.04-8cores-32GB
- enabled: true
- pyroscope_env: ci-automation-on-demand-upgrade
- network: SIMULATED
- command: -run ^TestAutomationNodeUpgrade/registry_2_2 ./smoke
- runs-on: ${{ matrix.tests.os }}
- name: Automation On Demand ${{ matrix.tests.name }} Test
- steps:
- - name: Checkout the repo
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- with:
- ref: ${{ github.head_ref || github.ref_name }}
- name: Determine build to use
id: determine-build
shell: bash
run: |
if [[ "${{ inputs.chainlinkImage }}" == "QA_ECR" ]]; then
- echo "image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT
+ echo "image='{{ env.QA_CHAINLINK_IMAGE }}'" >> $GITHUB_ENV
else
- echo "image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT
+ echo "image=${{ inputs.chainlinkImage }}" >> $GITHUB_ENV
fi
if [[ "${{ inputs.chainlinkImageUpdate }}" == "QA_ECR" ]]; then
- echo "upgrade_image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT
+ echo "upgrade_image='{{ env.QA_CHAINLINK_IMAGE }}'" >> $GITHUB_ENV
else
- echo "upgrade_image=${{ inputs.chainlinkImageUpdate }}" >>$GITHUB_OUTPUT
+ echo "upgrade_image=${{ inputs.chainlinkImageUpdate }}" >> $GITHUB_ENV
fi
if [[ -z "${{ inputs.chainlinkVersion }}" ]] && [[ "${{ inputs.chainlinkImage }}" == "QA_ECR" ]]; then
- echo "version=${{ github.sha }}" >>$GITHUB_OUTPUT
+ echo "version=${{ github.sha }}" >> $GITHUB_ENV
else
- echo "version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT
+ echo "version=${{ inputs.chainlinkVersion }}" >> $GITHUB_ENV
fi
if [[ -z "${{ inputs.chainlinkVersionUpdate }}" ]] && [[ "${{ inputs.chainlinkImageUpdate }}" == "QA_ECR" ]]; then
- echo "upgrade_version=${{ github.sha }}" >>$GITHUB_OUTPUT
+ echo "upgrade_version=${{ github.sha }}" >> $GITHUB_ENV
else
- echo "upgrade_version=${{ inputs.chainlinkVersionUpdate }}" >>$GITHUB_OUTPUT
+ echo "upgrade_version=${{ inputs.chainlinkVersionUpdate }}" >> $GITHUB_ENV
+ fi
+ - name: Check if chainlink image check required
+ id: determine-chainlink-image-check
+ shell: bash
+ run: |
+ chainlink_image_versions=""
+ if [ "${{ github.event.inputs.chainlinkImage }}" = "QA_ECR" ]; then
+ chainlink_image_versions+="${{ env.version }},"
+ fi
+ if [ "${{ github.event.inputs.chainlinkImageUpdate }}" = "QA_ECR" ]; then
+ chainlink_image_versions+="${{ env.upgrade_version }}"
fi
- - name: Setup GAP for Grafana
- uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2
- with:
- # aws inputs
- aws-region: ${{ secrets.AWS_REGION }}
- aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }}
- api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
- # other inputs
- duplicate-authorization-header: "true"
-
- - name: Run Tests
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
- if: ${{ matrix.tests.enabled == true }}
- with:
- test_config_override_base64: ${{ env.BASE64_CONFIG_OVERRIDE }}
- test_command_to_run: cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
- test_download_vendor_packages_command: cd ./integration-tests && go mod download
- test_suite: ${{ matrix.tests.suite }}
- test_config_chainlink_version: ${{ steps.determine-build.outputs.version }}
- test_config_chainlink_upgrade_version: ${{ steps.determine-build.outputs.upgrade_version }}
- test_config_selected_networks: ${{ matrix.tests.network }}
- test_config_logging_run_id: ${{ github.run_id }}
- test_config_logstream_log_targets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
- test_config_test_log_collect: "true"
- cl_repo: ${{ steps.determine-build.outputs.image }}
- cl_image_tag: ${{ steps.determine-build.outputs.version }}
- aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
- artifacts_location: ./integration-tests/${{ matrix.tests.suite }}/logs
- publish_check_name: Automation On Demand Results ${{ matrix.tests.name }}
- token: ${{ secrets.GITHUB_TOKEN }}
- go_mod_path: ./integration-tests/go.mod
- QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
- DEFAULT_CHAINLINK_IMAGE: ${{ steps.determine-build.outputs.image }}
- DEFAULT_CHAINLINK_UPGRADE_IMAGE: ${{ steps.determine-build.outputs.upgrade_image }}
- DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- DEFAULT_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
- DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
- DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
- DEFAULT_PYROSCOPE_SERVER_URL: ${{ matrix.tests.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725
- DEFAULT_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
- DEFAULT_PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }}
- DEFAULT_PYROSCOPE_ENABLED: ${{ matrix.tests.pyroscope_env == '' || !startsWith(github.ref, 'refs/tags/') && 'false' || 'true' }}
-
- - name: Upload test log
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
- if: failure()
- with:
- name: test-log-${{ matrix.tests.name }}
- path: /tmp/gotest.log
- retention-days: 7
- continue-on-error: true
- - name: Collect Metrics
- if: always()
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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 }}
- this-job-name: Automation On Demand ${{ matrix.tests.name }} Test
- test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}'
- continue-on-error: true
+ echo "require_chainlink_image_versions_in_qa_ecr=$chainlink_image_versions" >> $GITHUB_OUTPUT
+ - name: Set tests to run
+ id: set-tests
+ run: |
+
+ # Always run upgrade tests
+ cat > test_list.yaml <> test_list.yaml <> test_list.yaml <> $GITHUB_OUTPUT
+
+ call-run-e2e-tests-workflow:
+ name: Run E2E Tests
+ needs: set-tests-to-run
+ uses: ./.github/workflows/run-e2e-tests-reusable-workflow.yml
+ with:
+ test_list: ${{ needs.set-tests-to-run.outputs.test_list }}
+ require_chainlink_image_versions_in_qa_ecr: ${{ needs.set-tests-to-run.outputs.require_chainlink_image_versions_in_qa_ecr }}
+ with_existing_remote_runner_version: ${{ github.event.inputs.with_existing_remote_runner_version }}
+ test_log_upload_on_failure: true
+ test_log_upload_retention_days: 7
+ secrets:
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }}
+ QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
+ QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
+ GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ GRAFANA_INTERNAL_URL_SHORTENER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }}
+ AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
+
diff --git a/.github/workflows/build-publish-develop-pr.yml b/.github/workflows/build-publish-develop-pr.yml
new file mode 100644
index 00000000000..0b75b6c4778
--- /dev/null
+++ b/.github/workflows/build-publish-develop-pr.yml
@@ -0,0 +1,114 @@
+name: "Build and Publish Chainlink"
+
+on:
+ pull_request:
+ push:
+ branches:
+ - develop
+ - "release/**"
+ workflow_dispatch:
+ inputs:
+ git_ref:
+ description: "The git ref to check out"
+ required: true
+ build-publish:
+ description: "Whether to build and publish - defaults to just build"
+ required: false
+ default: "false"
+
+env:
+ GIT_REF: ${{ github.event.inputs.git_ref || github.ref }}
+
+jobs:
+ goreleaser-build-publish-chainlink:
+ runs-on: ubuntu-20.04
+ permissions:
+ id-token: write
+ contents: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ with:
+ ref: ${{ env.GIT_REF }}
+
+ # This gets the image tag and whether to publish the image based on the event type
+ # PR builds: pr-- (if label 'build-publish' is present publishes the image)
+ # develop builds: develop- and develop (only amd64)
+ # release builds: release-
+ # manual builds: (if build-publish is true publishes the image)
+ - name: Get image tag
+ id: get-image-tag
+ run: |
+ short_sha=$(git rev-parse --short HEAD)
+ echo "build-publish=false" | tee -a $GITHUB_OUTPUT
+ if [[ ${{ github.event_name }} == 'push' ]]; then
+ if [[ ${{ github.ref_name }} == 'release/'* ]]; then
+ echo "image-tag=release-${short_sha}" | tee -a $GITHUB_OUTPUT
+ echo "build-publish=true" | tee -a $GITHUB_OUTPUT
+ else
+ echo "image-tag=develop" | tee -a $GITHUB_OUTPUT
+ echo "build-publish=true" | tee -a $GITHUB_OUTPUT
+ fi
+ elif [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then
+ echo "image-tag=${short_sha}" | tee -a $GITHUB_OUTPUT
+ echo "build-publish=${{ github.event.inputs.build-publish }}" | tee -a $GITHUB_OUTPUT
+ else
+ if [[ ${{ github.event_name }} == "pull_request" ]]; then
+ echo "image-tag=pr-${{ github.event.number }}-${short_sha}" | tee -a $GITHUB_OUTPUT
+ if [[ ${{ contains(github.event.pull_request.labels.*.name, 'build-publish') }} == "true" ]]; then
+ echo "build-publish=true" | tee -a $GITHUB_OUTPUT
+ fi
+ fi
+ fi
+
+ - name: Configure aws credentials
+ if: steps.get-image-tag.outputs.build-publish == 'true'
+ uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ with:
+ role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_BUILD_PUBLISH_DEVELOP_PR }}
+ aws-region: ${{ secrets.AWS_REGION }}
+ mask-aws-account-id: true
+ role-session-name: goreleaser-build-publish-chainlink
+
+ - name: Build and publish images
+ uses: ./.github/actions/goreleaser-build-sign-publish
+ with:
+ enable-docker-publish: ${{ steps.get-image-tag.outputs.build-publish }}
+ docker-registry: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }}
+ docker-image-name: chainlink
+ docker-image-tag: ${{ steps.get-image-tag.outputs.image-tag }}
+ enable-goreleaser-snapshot: "true"
+ goreleaser-exec: ./tools/bin/goreleaser_wrapper
+ goreleaser-config: .goreleaser.develop.yaml
+ goreleaser-key: ${{ secrets.GORELEASER_KEY }}
+ zig-version: 0.11.0
+
+ - name: Output image name and digest
+ if: steps.get-image-tag.outputs.build-publish == 'true'
+ shell: bash
+ run: |
+ # need to check if artifacts.json exists because goreleaser could split the build
+ if [[ -f dist/artifacts.json ]]; then
+ artifact_path="dist/artifacts.json"
+ else
+ artifact_path="dist/linux_${{ matrix.goarch }}/artifacts.json"
+ cat dist/linux_${{ matrix.goarch }}/artifacts.json
+ fi
+ echo "### Docker Images" | tee -a "$GITHUB_STEP_SUMMARY"
+ jq -r '.[] | select(.type == "Docker Image") | "`\(.goarch)-image`: \(.name)"' ${artifact_path} >> output.txt
+ jq -r '.[] | select(.type == "Archive") | "`\(.goarch)-digest`: \(.extra.Checksum)"' ${artifact_path} >> output.txt
+ while read -r line; do
+ echo "$line" | tee -a "$GITHUB_STEP_SUMMARY"
+ done < output.txt
+
+ - name: Collect Metrics
+ if: always()
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
+ with:
+ id: goreleaser-build-publish
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: goreleaser-build-publish-chainlink
+ continue-on-error: true
\ No newline at end of file
diff --git a/.github/workflows/build-publish-develop.yml b/.github/workflows/build-publish-develop.yml
deleted file mode 100644
index 8c6e5e76ac4..00000000000
--- a/.github/workflows/build-publish-develop.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-name: "Push develop to private ECR"
-
-on:
- push:
- branches:
- - develop
- workflow_dispatch:
- inputs:
- git_ref:
- description: "Git ref (commit SHA, branch name, tag name, etc.) to checkout"
- required: true
-env:
- GIT_REF: ${{ github.event.inputs.git_ref || github.ref }}
-
-jobs:
- push-chainlink-develop:
- runs-on: ubuntu-20.04
- environment: build-develop
- permissions:
- id-token: write
- contents: read
- strategy:
- matrix:
- image:
- - name: ""
- dockerfile: core/chainlink.Dockerfile
- tag-suffix: ""
- - name: (plugins)
- dockerfile: plugins/chainlink.Dockerfile
- tag-suffix: -plugins
- name: push-chainlink-develop ${{ matrix.image.name }}
- steps:
- - name: Checkout repository
- 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
- # different than the checked out commit sha. The core build uses this
- # commit sha as build metadata, so we need to make sure it's correct.
- - name: Get checked out git ref
- if: github.event.inputs.git_ref
- id: git-ref
- run: echo "checked-out=$(git rev-parse HEAD)" | tee -a "${GITHUB_OUTPUT}"
- - name: Build, sign and publish chainlink image
- uses: ./.github/actions/build-sign-publish-chainlink
- with:
- publish: true
- aws-role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_ARN }}
- aws-role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }}
- aws-region: ${{ secrets.AWS_REGION }}
- ecr-hostname: ${{ secrets.AWS_DEVELOP_ECR_HOSTNAME }}
- ecr-image-name: chainlink
- ecr-tag-suffix: ${{ matrix.image.tag-suffix }}
- dockerfile: ${{ matrix.image.dockerfile }}
- dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }}
- dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }}
- git-commit-sha: ${{ steps.git-ref.outputs.checked-out || github.sha }}
-
- - name: Collect Metrics
- if: always()
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- with:
- id: build-chainlink-develop
- org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
- this-job-name: push-chainlink-develop ${{ matrix.image.name }}
- continue-on-error: true
diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml
deleted file mode 100644
index 36eac61cab0..00000000000
--- a/.github/workflows/build-publish-pr.yml
+++ /dev/null
@@ -1,66 +0,0 @@
-name: "Build and Publish from PR"
-
-##
-# This workflow builds and publishes a Docker image for Chainlink from a PR.
-# It has its own special IAM role, does not sign the image, and publishes to
-# a special ECR repo.
-##
-
-on:
- pull_request:
-
-jobs:
- build-publish-untrusted:
- if: ${{ ! startsWith(github.ref_name, 'release/') || (! startsWith(github.head_ref, 'release/') && ! startsWith(github.ref_name, 'chore/'))}}
- runs-on: ubuntu-20.04
- environment: sdlc
- permissions:
- id-token: write
- contents: read
- env:
- ECR_IMAGE_NAME: crib-chainlink-untrusted
- steps:
- - name: Checkout repository
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
-
- - name: Git Short SHA
- shell: bash
- env:
- GIT_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
- run: |
- echo "GIT_SHORT_SHA=${GIT_PR_HEAD_SHA:0:7}" | tee -a "$GITHUB_ENV"
-
- - name: Check if image exists
- id: check-image
- uses: smartcontractkit/chainlink-github-actions/docker/image-exists@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
- with:
- repository: ${{ env.ECR_IMAGE_NAME}}
- tag: sha-${{ env.GIT_SHORT_SHA }}
- AWS_REGION: ${{ secrets.AWS_REGION }}
- AWS_ROLE_TO_ASSUME: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }}
-
- - name: Build and publish chainlink image
- if: steps.check-image.outputs.exists == 'false'
- uses: ./.github/actions/build-sign-publish-chainlink
- with:
- publish: true
- aws-role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }}
- aws-role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS_DEFAULT }}
- aws-region: ${{ secrets.AWS_REGION }}
- sign-images: false
- ecr-hostname: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }}
- ecr-image-name: ${{ env.ECR_IMAGE_NAME }}
- dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }}
- dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }}
-
- - name: Collect Metrics
- if: always()
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- with:
- id: build-chainlink-pr
- org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
- this-job-name: build-publish-untrusted
- continue-on-error: true
diff --git a/.github/workflows/build-publish.yml b/.github/workflows/build-publish.yml
index be87de580dd..033526e0339 100644
--- a/.github/workflows/build-publish.yml
+++ b/.github/workflows/build-publish.yml
@@ -1,4 +1,4 @@
-name: "Build Chainlink and Publish"
+name: "Build, Sign and Publish Chainlink"
on:
# Mimics old circleci behaviour
@@ -59,6 +59,7 @@ jobs:
dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }}
dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }}
verify-signature: true
+
- name: Collect Metrics
if: always()
id: collect-gha-metrics
@@ -71,6 +72,68 @@ jobs:
this-job-name: build-sign-publish-chainlink
continue-on-error: true
+ goreleaser-build-sign-publish-chainlink:
+ needs: [checks]
+ if: ${{ ! startsWith(github.ref_name, 'release/') }}
+ runs-on: ubuntu-20.04
+ environment: build-publish
+ permissions:
+ id-token: write
+ contents: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+
+ - name: Configure aws credentials
+ uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
+ with:
+ role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_ARN }}
+ role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }}
+ aws-region: ${{ secrets.AWS_REGION }}
+ mask-aws-account-id: true
+ role-session-name: goreleaser-build-sign-publish-chainlink
+
+ - name: Build, sign, and publish image
+ id: goreleaser-build-sign-publish
+ uses: ./.github/actions/goreleaser-build-sign-publish
+ with:
+ enable-docker-publish: "true"
+ docker-registry: ${{ env.ECR_HOSTNAME}}
+ docker-image-name: ${{ env.ECR_IMAGE_NAME }}
+ docker-image-tag: ${{ github.ref_name }}
+ goreleaser-exec: ./tools/bin/goreleaser_wrapper
+ goreleaser-config: .goreleaser.develop.yaml
+ goreleaser-key: ${{ secrets.GORELEASER_KEY }}
+ zig-version: 0.11.0
+ enable-cosign: "true"
+ cosign-version: 3.4.0
+ cosign-password: ${{ secrets.COSIGN_PASSWORD }}
+ cosign-public-key: ${{ secrets.COSIGN_PUBLIC_KEY }}
+ cosign-private-key: ${{ secrets.COSIGN_PRIVATE_KEY }}
+
+ - name: Output image name and digest
+ shell: sh
+ run: |
+ artifact_path="dist/artifacts.json"
+ echo "### Docker Images" | tee -a "$GITHUB_STEP_SUMMARY"
+ jq -r '.[] | select(.type == "Docker Image") | "`\(.goarch)-image`: \(.name)"' ${artifact_path} >> output.txt
+ jq -r '.[] | select(.type == "Archive") | "`\(.goarch)-digest`: \(.extra.Checksum)"' ${artifact_path} >> output.txt
+ while read -r line; do
+ echo "$line" | tee -a "$GITHUB_STEP_SUMMARY"
+ done < output.txt
+
+ - name: Collect Metrics
+ if: always()
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
+ with:
+ id: goreleaser-build-chainlink-publish
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: goreleaser-build-sign-publish-chainlink
+ continue-on-error: true
+
# Notify Slack channel for new git tags.
slack-notify:
if: github.ref_type == 'tag'
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
deleted file mode 100644
index 6e3272204ed..00000000000
--- a/.github/workflows/build.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-name: "Build Chainlink"
-
-on:
- pull_request:
-
-jobs:
- build-chainlink:
- runs-on: ubuntu-20.04
- if: ${{ ! startsWith(github.head_ref, 'release/') && ! startsWith(github.ref_name, 'chore/') }}
- steps:
- - name: Checkout repository
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
-
- - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
- id: change
- with:
- predicate-quantifier: every
- filters: |
- changelog-only:
- - 'CHANGELOG.md'
- - '!common/**'
- - '!contracts/**'
- - '!core/**'
- - '!crib/**'
- - '!dashboard-lib/**'
- - '!fuzz/**'
- - '!integration-tests/**'
- - '!internal/**'
- - '!operator_ui/**'
- - '!plugins/**'
- - '!tools/**'
-
- - name: Build chainlink image
- if: ${{ steps.change.outputs.changelog-only == 'false' }}
- uses: ./.github/actions/build-sign-publish-chainlink
- with:
- dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }}
- dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }}
- publish: false
- sign-images: false
-
- - name: Collect Metrics
- if: always()
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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
- continue-on-error: true
diff --git a/.github/workflows/ccip-chaos-tests.yml b/.github/workflows/ccip-chaos-tests.yml
new file mode 100644
index 00000000000..03f809b44c9
--- /dev/null
+++ b/.github/workflows/ccip-chaos-tests.yml
@@ -0,0 +1,258 @@
+name: CCIP Chaos Tests
+on:
+ workflow_run:
+ workflows: [ CCIP Load Test ]
+ types: [ completed ]
+ branches: [ develop ]
+ workflow_dispatch:
+
+# Only run 1 of this workflow at a time per PR
+concurrency:
+ group: chaos-ccip-tests-chainlink-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ # TODO: TT-1470 - Update image names as we solidify new realease strategy
+ CL_ECR: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink
+ ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }}
+ MOD_CACHE_VERSION: 1
+
+jobs:
+ build-chainlink:
+ environment: integration
+ permissions:
+ id-token: write
+ contents: read
+ name: Build Chainlink Image
+ runs-on: ubuntu20.04-16cores-64GB
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - name: Check if image exists
+ id: check-image
+ uses: smartcontractkit/chainlink-github-actions/docker/image-exists@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17
+ with:
+ repository: chainlink
+ tag: ${{ github.sha }}
+ AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ 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@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17
+ env:
+ GH_TOKEN: ${{ github.token }}
+ with:
+ cl_repo: smartcontractkit/chainlink
+ cl_ref: ${{ github.sha }}
+ push_tag: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink:${{ github.sha }}
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ - name: Collect Metrics
+ if: always()
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: ccip-chaos-tests-build-chainlink-image
+ 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
+
+ build-test-image:
+ environment: integration
+ permissions:
+ id-token: write
+ contents: read
+ name: Build Test Image
+ runs-on: ubuntu20.04-16cores-64GB
+ steps:
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: ccip-chaos-tests-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@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - name: Build Test Image
+ uses: ./.github/actions/build-test-image
+ with:
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+
+ ccip-chaos-tests:
+ environment: integration
+ permissions:
+ issues: read
+ checks: write
+ pull-requests: write
+ id-token: write
+ contents: read
+ name: CCIP Chaos Tests
+ runs-on: ubuntu-latest
+ needs: [ build-chainlink, build-test-image ]
+ env:
+ TEST_SUITE: chaos
+ TEST_ARGS: -test.timeout 30m
+ CHAINLINK_COMMIT_SHA: ${{ github.sha }}
+ CHAINLINK_ENV_USER: ${{ github.actor }}
+ TEST_TRIGGERED_BY: ccip-cron-chaos-eth
+ TEST_LOG_LEVEL: debug
+ DATABASE_URL: postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable
+ GH_TOKEN: ${{ github.token }}
+ steps:
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: ccip-chaos-tests
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: CCIP Chaos Tests
+ test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}'
+ continue-on-error: true
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - name: Prepare Base64 TOML override for CCIP secrets
+ uses: ./.github/actions/setup-create-base64-config-ccip
+ id: setup_create_base64_config_ccip
+ with:
+ runId: ${{ github.run_id }}
+ testLogCollect: ${{ vars.TEST_LOG_COLLECT }}
+ chainlinkVersion: ${{ github.sha }}
+ logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
+ - name: Run Chaos Tests
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@d38226be720c5ccc1ff4d3cee40608ebf264cd59 # v2.3.26
+ env:
+ BASE64_CCIP_CONFIG_OVERRIDE: ${{ steps.setup_create_base64_config_ccip.outputs.base64_config }}
+ TEST_BASE64_CCIP_CONFIG_OVERRIDE: ${{ steps.setup_create_base64_config_ccip.outputs.base64_config }}
+ with:
+ test_command_to_run: cd ./integration-tests && go test -timeout 1h -count=1 -json -test.parallel 11 -run 'TestChaosCCIP' ./chaos 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci
+ test_download_vendor_packages_command: make gomod
+ artifacts_location: ./integration-tests/chaos/logs
+ publish_check_name: CCIP Chaos Test Results
+ publish_report_paths: ./tests-chaos-report.xml
+ triggered_by: ${{ env.TEST_TRIGGERED_BY }}
+ token: ${{ secrets.GITHUB_TOKEN }}
+ go_mod_path: ./integration-tests/go.mod
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
+ CGO_ENABLED: "1"
+ aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ cache_key_id: ccip-load-${{ env.MOD_CACHE_VERSION }}
+ cache_restore_only: "true"
+ DEFAULT_LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }}
+ DEFAULT_LOKI_ENDPOINT: ${{ secrets.LOKI_URL }}
+ DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }}
+ DEFAULT_CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink
+ DEFAULT_GRAFANA_BASE_URL: ${{ vars.GRAFANA_URL }}
+ DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
+
+ ## Notify in slack if the job fails
+ - name: Notify Slack
+ if: failure() && github.event_name != 'workflow_dispatch'
+ uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
+ env:
+ SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
+ with:
+ channel-id: "#ccip-testing"
+ slack-message: ":x: :mild-panic-intensifies: CCIP chaos tests failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}"
+ ## Run Cleanup if the job succeeds
+ - name: cleanup
+ if: always()
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/cleanup@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17
+ with:
+ triggered_by: ${{ env.TEST_TRIGGERED_BY }}
+
+ ccip-chaos-with-load-tests:
+ environment: integration
+ permissions:
+ issues: read
+ checks: write
+ pull-requests: write
+ id-token: write
+ contents: read
+ name: CCIP Load With Chaos Tests
+ if: false # Disabled until CCIP-2555 is resolved
+ runs-on: ubuntu-latest
+ needs: [ build-chainlink, build-test-image ]
+ env:
+ TEST_SUITE: load
+ TEST_ARGS: -test.timeout 1h
+ CHAINLINK_COMMIT_SHA: ${{ github.sha }}
+ CHAINLINK_ENV_USER: ${{ github.actor }}
+ TEST_TRIGGERED_BY: ccip-cron-chaos-and-load-eth
+ TEST_LOG_LEVEL: debug
+ DATABASE_URL: postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable
+ GH_TOKEN: ${{ github.token }}
+ steps:
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: ccip-chaos-tests-with-load-test
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: CCIP load with chaos test
+ continue-on-error: true
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - name: Prepare Base64 TOML override for CCIP secrests
+ uses: ./.github/actions/setup-create-base64-config-ccip
+ id: setup_create_base64_config_ccip
+ with:
+ runId: ${{ github.run_id }}
+ testLogCollect: ${{ vars.TEST_LOG_COLLECT }}
+ chainlinkVersion: ${{ github.sha }}
+ logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
+ - name: Run Load With Chaos Tests
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@d38226be720c5ccc1ff4d3cee40608ebf264cd59 # v2.3.26
+ env:
+ BASE64_CCIP_CONFIG_OVERRIDE: ${{ steps.setup_create_base64_config_ccip.outputs.base64_config }}
+ TEST_BASE64_CCIP_CONFIG_OVERRIDE: ${{ steps.setup_create_base64_config_ccip.outputs.base64_config }}
+ with:
+ test_command_to_run: cd ./integration-tests/ccip-tests && go test -timeout 2h -count=1 -json -test.parallel 4 -run '^TestLoadCCIPStableWithPodChaosDiffCommitAndExec' ./load 2>&1 | tee /tmp/gotest.log | gotestfmt
+ test_download_vendor_packages_command: make gomod
+ artifacts_location: ./integration-tests/load/logs
+ publish_check_name: CCIP Chaos With Load Test Results
+ publish_report_paths: ./tests-chaos-with-load-report.xml
+ triggered_by: ${{ env.TEST_TRIGGERED_BY }}
+ token: ${{ secrets.GITHUB_TOKEN }}
+ go_mod_path: ./integration-tests/go.mod
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
+ CGO_ENABLED: "1"
+ aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ cache_key_id: ccip-load-${{ env.MOD_CACHE_VERSION }}
+ cache_restore_only: "true"
+ DEFAULT_LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }}
+ DEFAULT_LOKI_ENDPOINT: ${{ secrets.LOKI_URL }}
+ DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }}
+ DEFAULT_CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink
+ DEFAULT_GRAFANA_BASE_URL: ${{ vars.GRAFANA_URL }}
+ DEFAULT_GRAFANA_DASHBOARD_URL: "/d/6vjVx-1V8/ccip-long-running-tests"
+ ## Notify in slack if the job fails
+ - name: Notify Slack
+ if: failure() && github.event_name != 'workflow_dispatch'
+ uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
+ env:
+ SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
+ with:
+ channel-id: "#ccip-testing"
+ slack-message: ":x: :mild-panic-intensifies: CCIP chaos with load tests failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}"
+ ## Run Cleanup if the job succeeds
+ - name: cleanup
+ if: always()
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/cleanup@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17
+ with:
+ triggered_by: ${{ env.TEST_TRIGGERED_BY }}
\ No newline at end of file
diff --git a/.github/workflows/ccip-load-tests.yml b/.github/workflows/ccip-load-tests.yml
new file mode 100644
index 00000000000..a6d073715d1
--- /dev/null
+++ b/.github/workflows/ccip-load-tests.yml
@@ -0,0 +1,297 @@
+name: CCIP Load Test
+on:
+ push:
+ paths:
+ - '**/*ccip*'
+ - '**/*ccip*/**'
+ branches:
+ - develop
+ tags:
+ - '*'
+ workflow_dispatch:
+ inputs:
+ base64_test_input: # base64 encoded toml for test input
+ description: 'Base64 encoded toml test input'
+ required: false
+ test_secrets_override_key:
+ description: 'Key to run tests with custom test secrets'
+ required: false
+ type: string
+
+# Only run 1 of this workflow at a time per PR
+concurrency:
+ group: load-ccip-tests-chainlink-${{ github.ref }}
+ cancel-in-progress: true
+
+env:
+ # TODO: TT-1470 - Update image names as we solidify new realease strategy
+ CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink
+ CHAINLINK_VERSION: ${{ github.sha}}
+ INPUT_CHAINLINK_TEST_VERSION: ${{ github.sha}}
+ ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }}
+ INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com
+ AWS_ECR_REPO_PUBLIC_REGISTRY: public.ecr.aws
+ MOD_CACHE_VERSION: 1
+
+jobs:
+ build-chainlink:
+ environment: integration
+ permissions:
+ id-token: write
+ contents: read
+ name: Build Chainlink Image
+ runs-on: ubuntu20.04-16cores-64GB
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - name: Check if image exists
+ id: check-image
+ uses: smartcontractkit/chainlink-github-actions/docker/image-exists@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17
+ with:
+ repository: chainlink
+ tag: ${{ env.CHAINLINK_VERSION }}
+ AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ 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@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17
+ env:
+ GH_TOKEN: ${{ github.token }}
+ with:
+ cl_repo: smartcontractkit/chainlink
+ cl_ref: ${{ env.CHAINLINK_VERSION }}
+ push_tag: ${{ env.CHAINLINK_IMAGE }}:${{ env.CHAINLINK_VERSION }}
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ - name: Collect Metrics
+ if: always()
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: ccip-load-test-build-chainlink-image
+ 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
+
+ build-test-image:
+ environment: integration
+ permissions:
+ id-token: write
+ contents: read
+ name: Build Test Image
+ runs-on: ubuntu20.04-16cores-64GB
+ steps:
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: ccip-load-test-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@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - name: Build Test Image
+ uses: ./.github/actions/build-test-image
+ with:
+ tag: ${{ env.INPUT_CHAINLINK_TEST_VERSION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+
+ ccip-load-test:
+ environment: integration
+ needs: [ build-chainlink, build-test-image ]
+ if: ${{ always() && !contains(needs.*.result, 'failure') }}
+ permissions:
+ issues: read
+ checks: write
+ pull-requests: write
+ id-token: write
+ contents: read
+ env:
+ CHAINLINK_ENV_USER: ${{ github.actor }}
+ SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }}
+ SLACK_CHANNEL: ${{ secrets.QA_SLACK_CHANNEL }}
+ TEST_LOG_LEVEL: info
+ REF_NAME: ${{ github.head_ref || github.ref_name }}
+ BASE64_NETWORK_CONFIG: ${{ secrets.BASE64_NETWORK_CONFIG }}
+ strategy:
+ fail-fast: false
+ matrix:
+ type:
+ - name: stable-load
+ run: ^TestLoadCCIPStableRPS$
+ os: ubuntu-latest
+ - name: load-with-arm-curse-uncurse
+ run: ^TestLoadCCIPStableRPSAfterARMCurseAndUncurse$
+ config_path: ./integration-tests/ccip-tests/testconfig/tomls/load-with-arm-curse-uncurse.toml
+ os: ubuntu-latest
+ runs-on: ${{ matrix.type.os }}
+ name: CCIP ${{ matrix.type.name }}
+ steps:
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: ccip-load-test-${{ matrix.type.name }}
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: CCIP ${{ matrix.type.name }}
+ 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: ${{ env.REF_NAME }}
+ - name: Sets env vars
+ id: set_override_config
+ shell: bash
+ run: |
+ # if the matrix.type.config_path is set, use it as the override config
+ if [ -n "${{ matrix.type.config_path }}" ]; then
+ BASE64_CCIP_CONFIG_OVERRIDE=$(base64 -w 0 -i ${{ matrix.type.config_path }})
+ echo ::add-mask::$BASE64_CCIP_CONFIG_OVERRIDE
+ echo "base_64_override=$BASE64_CCIP_CONFIG_OVERRIDE" >> $GITHUB_OUTPUT
+ fi
+ if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
+ BASE64_CCIP_CONFIG_OVERRIDE=$(jq -r '.inputs.base64_test_input' $GITHUB_EVENT_PATH)
+ echo ::add-mask::$BASE64_CCIP_CONFIG_OVERRIDE
+ echo "base_64_override=$BASE64_CCIP_CONFIG_OVERRIDE" >> $GITHUB_OUTPUT
+ fi
+ - name: step summary
+ shell: bash
+ run: |
+ echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY
+ echo "\`${{ env.CHAINLINK_VERSION }}\`" >> $GITHUB_STEP_SUMMARY
+ echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY
+ echo "\`${{ env.INPUT_CHAINLINK_TEST_VERSION }}\`" >> $GITHUB_STEP_SUMMARY
+ - name: Prepare Base64 TOML override for CCIP secrets
+ uses: ./.github/actions/setup-create-base64-config-ccip
+ id: setup_create_base64_config_ccip
+ with:
+ runId: ${{ github.run_id }}
+ testLogCollect: ${{ vars.TEST_LOG_COLLECT }}
+ chainlinkVersion: ${{ github.sha }}
+ logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
+ - name: Run Tests
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@d38226be720c5ccc1ff4d3cee40608ebf264cd59 # v2.3.26
+ env:
+ TEST_SUITE: load
+ TEST_ARGS: -test.timeout 900h
+ DATABASE_URL: postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable
+ RR_MEM: 8Gi
+ RR_CPU: 4
+ TEST_TRIGGERED_BY: ccip-load-test-ci-${{ matrix.type.name }}
+ BASE64_CCIP_CONFIG_OVERRIDE: ${{ steps.set_override_config.outputs.base_64_override }},${{ steps.setup_create_base64_config_ccip.outputs.base64_config }}
+ TEST_BASE64_CCIP_CONFIG_OVERRIDE: ${{ steps.set_override_config.outputs.base_64_override }},${{ steps.setup_create_base64_config_ccip.outputs.base64_config }}
+ with:
+ test_command_to_run: cd ./integration-tests/ccip-tests && go test -v -timeout 70m -count=1 -json -run ${{ matrix.type.run }} ./load 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci
+ test_download_vendor_packages_command: cd ./integration-tests && go mod download
+ test_secrets_override_base64: ${{ secrets[inputs.test_secrets_override_key] }}
+ token: ${{ secrets.GITHUB_TOKEN }}
+ go_mod_path: ./integration-tests/go.mod
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
+ triggered_by: ${{ env.TEST_TRIGGERED_BY }}
+ publish_check_name: ${{ matrix.type.name }}
+ artifacts_location: ./integration-tests/load/logs/payload_ccip.json
+ aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ cache_key_id: ccip-load-${{ env.MOD_CACHE_VERSION }}
+ cache_restore_only: "true"
+ should_cleanup: "true"
+ DEFAULT_CHAINLINK_IMAGE: ${{ env.CHAINLINK_IMAGE }}
+ DEFAULT_LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }}
+ DEFAULT_LOKI_ENDPOINT: ${{ secrets.LOKI_URL }}
+ DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }}
+ DEFAULT_GRAFANA_BASE_URL: ${{ vars.GRAFANA_URL }}
+ DEFAULT_GRAFANA_DASHBOARD_URL: "/d/6vjVx-1V8/ccip-long-running-tests"
+
+ # Reporting Jobs
+ start-slack-thread:
+ name: Start Slack Thread
+ if: ${{ failure() && needs.ccip-load-test.result != 'skipped' && needs.ccip-load-test.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: [ccip-load-test]
+ 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: "#ccip-testing"
+ payload: |
+ {
+ "attachments": [
+ {
+ "color": "${{ contains(join(needs.*.result, ','), 'failure') && '#C62828' || '#2E7D32' }}",
+ "blocks": [
+ {
+ "type": "header",
+ "text": {
+ "type": "plain_text",
+ "text": "CCIP load tests results ${{ contains(join(needs.*.result, ','), 'failure') && ':x:' || ':white_check_mark:'}}",
+ "emoji": true
+ }
+ },
+ {
+ "type": "divider"
+ },
+ {
+ "type": "section",
+ "text": {
+ "type": "mrkdwn",
+ "text": "<${{ github.server_url }}/${{ github.repository }}/${{contains(github.ref_name, 'release') && 'releases/tag' || 'tree'}}/${{ 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
+ if: ${{ failure() && needs.start-slack-thread.result != 'skipped' && needs.start-slack-thread.result != 'cancelled' }}
+ environment: integration
+ permissions:
+ checks: write
+ pull-requests: write
+ id-token: write
+ contents: read
+ runs-on: ubuntu-latest
+ needs: start-slack-thread
+ 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
+ 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: ^CCIP (.*)$
+ message_title: CCIP Jobs
+ slack_channel_id: "#ccip-testing"
+ slack_bot_token: ${{ secrets.QA_SLACK_API_KEY }}
+ slack_thread_ts: ${{ needs.start-slack-thread.outputs.thread_ts }}
+
+ # End Reporting Jobs
\ No newline at end of file
diff --git a/.github/workflows/chain-selectors-check.yml b/.github/workflows/chain-selectors-check.yml
new file mode 100644
index 00000000000..c2b58e68d44
--- /dev/null
+++ b/.github/workflows/chain-selectors-check.yml
@@ -0,0 +1,39 @@
+name: Chain Selectors Version Check
+
+on:
+ push:
+ branches:
+ - develop
+ - release/*
+ tags:
+ - v*
+ pull_request:
+ branches:
+ - release/*
+
+
+jobs:
+ verify-version:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout Repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+
+ - name: Setup Go
+ uses: ./.github/actions/setup-go
+ with:
+ only-modules: true
+ go-version-file: "go.mod"
+
+ - name: Get chain-selectors version
+ id: get-chain-selectors-version
+ shell: bash
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ current_chain_selector_version=$(go list -m -f '{{.Version}}' github.com/smartcontractkit/chain-selectors)
+ latest_chain_selector_version=$(gh release view -R smartcontractkit/chain-selectors --json tagName --jq '.tagName')
+ if [[ "$current_chain_selector_version" != "$latest_chain_selector_version" ]]; then
+ echo "::error:: Chain Selectors version mismatch. Current version: $current_chain_selector_version, Latest version: $latest_chain_selector_version"
+ exit 1
+ fi
diff --git a/.github/workflows/changeset.yml b/.github/workflows/changeset.yml
index cfb4b322bf2..5e16b90c400 100644
--- a/.github/workflows/changeset.yml
+++ b/.github/workflows/changeset.yml
@@ -94,7 +94,7 @@ jobs:
working-directory: ./.github/scripts/jira
run: |
echo "COMMIT_MESSAGE=$(git log -1 --pretty=format:'%s')" >> $GITHUB_ENV
- pnpm install && node update-jira-issue.js
+ pnpm install && pnpm issue:update
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JIRA_HOST: ${{ secrets.JIRA_HOST }}
diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml
index aac8e578d13..74369493eb3 100644
--- a/.github/workflows/ci-core.yml
+++ b/.github/workflows/ci-core.yml
@@ -341,37 +341,48 @@ jobs:
- name: Download all workflow run artifacts
uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4
- - name: Set SonarQube Report Paths
- id: sonarqube_report_paths
+ - name: Check and Set SonarQube Report Paths
shell: bash
run: |
- echo "sonarqube_tests_report_paths=$(find go_core_tests_logs -name output.txt | paste -sd "," -)" >> $GITHUB_OUTPUT
- echo "sonarqube_coverage_report_paths=$(find go_core_tests_logs -name coverage.txt | paste -sd "," -)" >> $GITHUB_OUTPUT
- echo "sonarqube_lint_report_paths=$(find golangci-lint-report -name golangci-lint-report.xml | paste -sd "," -)" >> $GITHUB_OUTPUT
+ # Check and assign paths for coverage/test reports
+ if [ -d "go_core_tests_logs" ]; then
+ sonarqube_coverage_report_paths=$(find go_core_tests_logs -name coverage.txt | paste -sd "," -)
+ sonarqube_tests_report_paths=$(find go_core_tests_logs -name output.txt | paste -sd "," -)
+ else
+ sonarqube_coverage_report_paths=""
+ sonarqube_tests_report_paths=""
+ fi
- - name: Check SonarQube Report Paths
- id: check_sonarqube_paths
- run: |
- ARGS=""
+ # Check and assign paths for lint reports
+ if [ -d "golangci-lint-report" ]; then
+ sonarqube_lint_report_paths=$(find golangci-lint-report -name golangci-lint-report.xml | paste -sd "," -)
+ else
+ sonarqube_lint_report_paths=""
+ fi
- if [[ -z "${{ steps.sonarqube_report_paths.outputs.sonarqube_tests_report_paths }}" ]]; then
+ ARGS=""
+ if [[ -z "$sonarqube_tests_report_paths" ]]; then
echo "::warning::No test report paths found, will not pass to sonarqube"
else
- ARGS="$ARGS -Dsonar.go.tests.reportPaths=${{ steps.sonarqube_report_paths.outputs.sonarqube_tests_report_paths }}"
+ echo "Found test report paths: $sonarqube_tests_report_paths"
+ ARGS="$ARGS -Dsonar.go.tests.reportPaths=$sonarqube_tests_report_paths"
fi
- if [[ -z "${{ steps.sonarqube_report_paths.outputs.sonarqube_coverage_report_paths }}" ]]; then
+ if [[ -z "$sonarqube_coverage_report_paths" ]]; then
echo "::warning::No coverage report paths found, will not pass to sonarqube"
else
- ARGS="$ARGS -Dsonar.go.coverage.reportPaths=${{ steps.sonarqube_report_paths.outputs.sonarqube_coverage_report_paths }}"
+ echo "Found coverage report paths: $sonarqube_coverage_report_paths"
+ ARGS="$ARGS -Dsonar.go.coverage.reportPaths=$sonarqube_coverage_report_paths"
fi
- if [[ -z "${{ steps.sonarqube_report_paths.outputs.sonarqube_lint_report_paths }}" ]]; then
+ if [[ -z "$sonarqube_lint_report_paths" ]]; then
echo "::warning::No lint report paths found, will not pass to sonarqube"
else
- ARGS="$ARGS -Dsonar.go.golangci-lint.reportPaths=${{ steps.sonarqube_report_paths.outputs.sonarqube_lint_report_paths }}"
+ echo "Found lint report paths: $sonarqube_lint_report_paths"
+ ARGS="$ARGS -Dsonar.go.golangci-lint.reportPaths=$sonarqube_lint_report_paths"
fi
+ echo "Final SONARQUBE_ARGS: $ARGS"
echo "SONARQUBE_ARGS=$ARGS" >> $GITHUB_ENV
- name: SonarQube Scan
@@ -420,7 +431,8 @@ jobs:
run: curl https://github.com/smartcontractkit/wsrpc/raw/main/cmd/protoc-gen-go-wsrpc/protoc-gen-go-wsrpc --output $HOME/go/bin/protoc-gen-go-wsrpc && chmod +x $HOME/go/bin/protoc-gen-go-wsrpc
- name: Setup NodeJS
uses: ./.github/actions/setup-nodejs
- - run: |
+ - name: make generate
+ run: |
make rm-mocked
make generate
- name: Ensure clean after generate
diff --git a/.github/workflows/ci-scripts.yml b/.github/workflows/ci-scripts.yml
index 2c1024310f2..73e72eced54 100644
--- a/.github/workflows/ci-scripts.yml
+++ b/.github/workflows/ci-scripts.yml
@@ -6,6 +6,8 @@ on:
jobs:
lint-scripts:
+ # 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]' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
diff --git a/.github/workflows/client-compatibility-tests.yml b/.github/workflows/client-compatibility-tests.yml
index 956da46e771..ea0b9119362 100644
--- a/.github/workflows/client-compatibility-tests.yml
+++ b/.github/workflows/client-compatibility-tests.yml
@@ -14,10 +14,10 @@ on:
required: false
type: string
evmImplementations:
- description: comma separated list of EVM implementations to test (ignored if base64TestList is used)
+ description: comma separated list of EVM implementations to test (ignored if base64TestList is used); supports geth,besu,nethermind,erigon,reth
required: true
type: string
- default: "geth,besu,nethermind,erigon"
+ default: "geth,besu,nethermind,erigon,reth"
latestVersionsNumber:
description: how many of latest images of EVM implementations to test with (ignored if base64TestList is used)
required: true
@@ -162,6 +162,12 @@ jobs:
echo "New nethermind release found: $new_nethermind"
implementations_arr+=("nethermind")
fi
+ new_reth=$(ghlatestreleasechecker "paradigmxyz/reth" $RELEASED_DAYS_AGO)
+ if [ "new_reth" != "none" ]; then
+ echo "New reth release found: $new_reth"
+ implementations_arr+=("reth")
+ fi
+
IFS=','
eth_implementations="${implementations_arr[*]}"
if [ -n "$eth_implementations" ]; then
@@ -179,7 +185,7 @@ jobs:
fi
else
echo "Will test all EVM implementations"
- echo "evm_implementations=geth,besu,nethermind,erigon" >> $GITHUB_OUTPUT
+ echo "evm_implementations=geth,besu,nethermind,erigon,reth" >> $GITHUB_OUTPUT
fi
- name: Select Chainlink version
id: select-chainlink-version
@@ -192,8 +198,7 @@ jobs:
implementations_arr=()
# we use 100 days since we really want the latest one, and it's highly improbable there won't be a release in last 100 days
chainlink_version=$(ghlatestreleasechecker "smartcontractkit/chainlink" 100)
- echo "chainlink_version=$chainlink_version" >> $GITHUB_OUTPUT
- cl_ref_path="release"
+ cl_ref_path="releases"
elif [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then
echo "Fetching Chainlink version from input"
if [ -n "${{ github.event.inputs.chainlinkVersion }}" ]; then
@@ -202,35 +207,33 @@ jobs:
if [[ "$chainlink_version" =~ ^[0-9a-f]{40}$ ]]; then
cl_ref_path="commit"
else
- cl_ref_path="release"
+ cl_ref_path="releases"
fi
else
echo "Chainlink version not provided in input. Using latest commit SHA."
chainlink_version=${{ github.sha }}
cl_ref_path="commit"
fi
- echo "chainlink_version=$chainlink_version" >> $GITHUB_OUTPUT
- echo "cl_ref_path=$cl_ref_path" >> $GITHUB_OUTPUT
elif [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
echo "Fetching Chainlink version from PR's head commit"
chainlink_version="${{ github.event.pull_request.head.sha }}"
- echo "chainlink_version=$chainlink_version" >> $GITHUB_OUTPUT
- echo "cl_ref_path=commit" >> $GITHUB_OUTPUT
+ cl_ref_path="commit"
elif [ "$GITHUB_EVENT_NAME" = "merge_queue" ]; then
echo "Fetching Chainlink version from merge queue's head commit"
chainlink_version="${{ github.event.merge_group.head_sha }}"
- echo "chainlink_version=$chainlink_version" >> $GITHUB_OUTPUT
- echo "cl_ref_path=commit" >> $GITHUB_OUTPUT
+ cl_ref_path="commit"
elif [ "$GITHUB_REF_TYPE" = "tag" ]; then
echo "Fetching Chainlink version from tag"
chainlink_version="${{ github.ref_name }}"
- echo "chainlink_version=$chainlink_version" >> $GITHUB_OUTPUT
- echo "cl_ref_path=release" >> $GITHUB_OUTPUT
+ chainlink_version=${chainlink_version#v}
+ cl_ref_path="releases"
else
echo "Unsupported trigger event. It's probably an issue with the pipeline definition. Please reach out to the Test Tooling team."
exit 1
fi
echo "Will use following Chainlink version: $chainlink_version"
+ echo "chainlink_version=$chainlink_version" >> $GITHUB_OUTPUT
+ echo "cl_ref_path=$cl_ref_path" >> $GITHUB_OUTPUT
- name: Get image count
id: get-image-count
run: |
@@ -273,9 +276,11 @@ jobs:
expression: '^[0-9]+\.[0-9]+\.[0-9]+$'
- name: tofelb/ethereum-genesis-generator
expression: '^[0-9]+\.[0-9]+\.[0-9]+(\-slots\-per\-epoch)?'
+ - name: ghcr.io/paradigmxyz/reth
+ expression: '^v[0-9]+\.[0-9]+\.[0-9]+$'
steps:
- name: Update internal ECR if the latest Ethereum client image does not exist
- uses: smartcontractkit/chainlink-testing-framework/.github/actions/update-internal-mirrors@5eea86ee4f7742b4e944561a570a6b268e712d9e # v1.30.3
+ uses: smartcontractkit/chainlink-testing-framework/.github/actions/update-internal-mirrors@352cf299b529a33208146d9f7f0e0b5534fba6e7 # v1.33.0
with:
aws_region: ${{ secrets.QA_AWS_REGION }}
role_to_assume: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
@@ -283,12 +288,12 @@ jobs:
image_name: ${{matrix.mirror.name}}
expression: ${{matrix.mirror.expression}}
page_size: ${{matrix.mirror.page_size}}
+ github_token: ${{ secrets.RETH_GH_TOKEN }} # needed only for checking GHRC.io repositories
build-chainlink:
if: |
always() &&
needs.should-run.outputs.should_run == 'true' &&
- github.ref_type != 'tag' &&
(
needs.select-versions.outputs.evm_implementations != '' ||
github.event.inputs.base64TestList != ''
@@ -327,7 +332,7 @@ jobs:
get-latest-available-images:
name: Get Latest EVM Implementation's Images
- if: always() && needs.should-run.outputs.should_run == 'true' && (needs.select-versions.outputs.evm_implementations != '' || github.event.inputs.base64TestList != '')
+ if: always() && needs.should-run.outputs.should_run == 'true' && needs.select-versions.outputs.evm_implementations != '' && github.event.inputs.base64TestList == ''
environment: integration
runs-on: ubuntu-latest
needs: [check-ecr-images-exist, should-run, select-versions]
@@ -341,6 +346,7 @@ jobs:
nethermind_images: ${{ env.NETHERMIND_IMAGES }}
besu_images: ${{ env.BESU_IMAGES }}
erigon_images: ${{ env.ERIGON_IMAGES }}
+ reth_images: ${{ env.RETH_IMAGES }}
steps:
# Setup AWS creds
- name: Configure AWS Credentials
@@ -395,6 +401,12 @@ jobs:
echo "ERIGON_IMAGES=$erigon_images" >> $GITHUB_ENV
echo "Erigon latest images: $erigon_images"
fi
+
+ if [[ "$ETH_IMPLEMENTATIONS" == *"reth"* ]]; then
+ reth_images=$(ecrimagefetcher 'ghcr.io/paradigmxyz/reth' '^v[0-9]+\.[0-9]+\.[0-9]+$' ${{ env.LATEST_IMAGE_COUNT }})
+ echo "RETH_IMAGES=$reth_images" >> $GITHUB_ENV
+ echo "Reth latest images: $reth_images"
+ fi
# End Build Test Dependencies
@@ -523,7 +535,24 @@ jobs:
else
echo "Will not test compatibility with nethermind"
fi
-
+
+ if [[ "$ETH_IMPLEMENTATIONS" == *"reth"* ]]; then
+ echo "Will test compatibility with reth"
+ testlistgenerator -o compatibility_test_list.json -p cron -r TestCronBasic -f './smoke/cron_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p flux -r TestFluxBasic -f './smoke/flux_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p runlog -r TestRunLogBasic -f './smoke/runlog_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p log_poller -r TestLogPollerFewFiltersFixedDepth -f './smoke/log_poller_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p ocr -r TestOCRBasic -f './smoke/ocr_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p ocr2 -r '^TestOCRv2Basic/plugins$' -f './smoke/ocr2_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p automation -r 'TestAutomationBasic/registry_2_1_logtrigger' -f './smoke/automation_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p keeper -r 'TestKeeperBasicSmoke/registry_1_3' -f './smoke/keeper_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p vrf -r '^TestVRFBasic/Request_Randomness$' -f './smoke/vrf_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p vrfv2 -r '^TestVRFv2Basic/Request_Randomness$' -f './smoke/vrfv2_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ testlistgenerator -o compatibility_test_list.json -p vrfv2plus -r '^TestVRFv2Plus$/^Link_Billing$' -f './smoke/vrfv2plus_test.go' -e reth -d "${{ needs.get-latest-available-images.outputs.reth_images }}" -t "evm-implementation-compatibility-test" -n "ubuntu-latest"
+ else
+ echo "Will not test compatibility with reth"
+ fi
+
jq . compatibility_test_list.json
JOB_MATRIX_JSON=$(jq -c . compatibility_test_list.json)
echo "JOB_MATRIX_JSON=${JOB_MATRIX_JSON}" >> $GITHUB_ENV
@@ -596,7 +625,7 @@ jobs:
# comment_on_pr: false
# theme: 'dark'
- name: Run Tests
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@d2f9642bcc24a73400568756f24b72c188ac7a9a # v2.3.31
with:
test_command_to_run: cd ./integration-tests && touch .root_dir && go test -timeout 30m -count=1 -json ${{ matrix.evm_node.run }} 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
test_download_vendor_packages_command: cd ./integration-tests && go mod download
@@ -613,6 +642,7 @@ jobs:
artifacts_name: ${{ env.TEST_LOG_NAME }}
artifacts_location: |
./integration-tests/smoke/logs/
+ ./integration-tests/smoke/db_dumps/
/tmp/gotest.log
publish_check_name: ${{ matrix.evm_node.product }}-${{ matrix.evm_node.eth_implementation }}
token: ${{ secrets.GITHUB_TOKEN }}
@@ -680,7 +710,7 @@ jobs:
"type": "section",
"text": {
"type": "mrkdwn",
- "text": "${{ contains(join(needs.*.result, ','), 'failure') && format('Some tests failed, notifying <{0}>', secrets.COMPAT_SLACK_NOTIFICATION_HANDLE) || 'All Good!' }}"
+ "text": "${{ contains(join(needs.*.result, ','), 'failure') && format('Some tests failed, notifying ', secrets.COMPAT_SLACK_NOTIFICATION_HANDLE) || 'All Good!' }}"
}
},
{
diff --git a/.github/workflows/crib-integration-test.yml b/.github/workflows/crib-integration-test.yml
index 75b2215d2fc..6fcfe281553 100644
--- a/.github/workflows/crib-integration-test.yml
+++ b/.github/workflows/crib-integration-test.yml
@@ -1,74 +1,113 @@
-# this is disabled because of GAP limitations, should be re-enabled when github-actions-controller will be installed
+name: CRIB Integration Tests
+on:
+ schedule:
+ - cron: "0 1 * * *"
+ workflow_call:
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ environment: integration
+ permissions:
+ id-token: write
+ contents: read
+ actions: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
-#name: CRIB Integration Tests
-#on:
-# push:
-# workflow_call:
-#concurrency:
-# group: ${{ github.workflow }}-${{ github.ref }}
-# cancel-in-progress: true
-#jobs:
-# test:
-# runs-on: ubuntu-latest
-# environment: integration
-# permissions:
-# id-token: write
-# contents: read
-# actions: read
-# steps:
-# - name: Checkout repository
-# uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
-#
-# - name: Setup Nix + GATI environment
-# uses: smartcontractkit/.github/actions/setup-nix-gati@514fe346780e2eddf7ea8b9f48120c2fba120d94
-# with:
-# aws-role-arn: ${{ secrets.AWS_OIDC_CHAINLINK_AUTO_PR_TOKEN_ISSUER_ROLE_ARN }}
-# aws-lambda-url: ${{ secrets.AWS_CORE_TOKEN_ISSUER_LAMBDA_URL }} # see https://github.com/smartcontractkit/ infra/blob/a79bcfb48315c4411023c182e98eb80ff9e9cda6/accounts/production/us-west-2/lambda/ github-app-token-issuer-production/teams/releng/config.json#L9
-# aws-region: ${{ secrets.AWS_REGION }}
-# aws-role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }}
-# enable-magic-cache: true
-#
-# - name: Nix Develop Action
-# uses: nicknovitski/nix-develop@v1
-# with:
-# arguments: "--accept-flake-config"
-# - name: setup-gap
-# uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2
-# with:
-# aws-role-arn: ${{ secrets.AWS_OIDC_CRIB_ROLE_ARN_STAGE }}
-# api-gateway-host: ${{ secrets.AWS_API_GW_HOST_K8S_STAGE }}
-# aws-region: ${{ secrets.AWS_REGION }}
-# ecr-private-registry: ${{ secrets.AWS_ACCOUNT_ID_PROD }}
-# k8s-cluster-name: ${{ secrets.AWS_K8S_CLUSTER_NAME_STAGE }}
-# use-private-ecr-registry: true
-# use-k8s: true
-# metrics-job-name: "k8s"
-# gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
-# gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }}
-# gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
-# - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
-# name: Checkout CRIB repository
-# with:
-# repository: 'smartcontractkit/crib'
-# ref: 'main'
-# - name: Generate Short UUID
-# id: uuid
-# run: echo "CRIB_NAMESPACE=$(uuidgen | cut -c1-5)" >> $GITHUB_ENV
-# - name: Create a new CRIB environment
-# run: |-
-# devspace use namespace $CRIB_NAMESPACE
-# devspace deploy --profile local-dev-simulated-core-ocr1
-# - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
-# - name: Setup go
-# uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
-# with:
-# go-version-file: "go.mod"
-# - name: Run CRIB integration test
-# working-directory: integration-tests/crib
-# env:
-# K8S_STAGING_INGRESS_SUFFIX: ${{ secrets.K8S_STAGING_INGRESS_SUFFIX }}
-# CRIB_NAMESPACE: ${{ env.CRIB_NAMESPACE }}
-# CRIB_NETWORK: geth
-# CRIB_NODES: 5
-# run: |-
-# go test -v -run TestCRIB
\ No newline at end of file
+ - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
+ with:
+ nix_path: nixpkgs=channel:nixos-unstable
+
+ - name: setup-gap crib
+ uses: smartcontractkit/.github/actions/setup-gap@00b58566e0ee2761e56d9db0ea72b783fdb89b8d # setup-gap@0.4.0
+ with:
+ aws-role-duration-seconds: 3600 # 1 hour
+ aws-role-arn: ${{ secrets.AWS_OIDC_CRIB_ROLE_ARN_STAGE }}
+ api-gateway-host: ${{ secrets.AWS_API_GW_HOST_CRIB_STAGE }}
+ aws-region: ${{ secrets.AWS_REGION }}
+ ecr-private-registry: ${{ secrets.AWS_ACCOUNT_ID_PROD }}
+ k8s-cluster-name: ${{ secrets.AWS_K8S_CLUSTER_NAME_STAGE }}
+ gap-name: crib
+ use-private-ecr-registry: true
+ use-tls: true
+ proxy-port: 8080
+ metrics-job-name: "test"
+ gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+
+ - name: setup-gap k8s
+ uses: smartcontractkit/.github/actions/setup-gap@00b58566e0ee2761e56d9db0ea72b783fdb89b8d # setup-gap@0.4.0
+ with:
+ aws-role-duration-seconds: 3600 # 1 hour
+ aws-role-arn: ${{ secrets.AWS_OIDC_CRIB_ROLE_ARN_STAGE }}
+ api-gateway-host: ${{ secrets.AWS_API_GW_HOST_K8S_STAGE }}
+ aws-region: ${{ secrets.AWS_REGION }}
+ ecr-private-registry: ${{ secrets.AWS_ACCOUNT_ID_PROD }}
+ k8s-cluster-name: ${{ secrets.AWS_K8S_CLUSTER_NAME_STAGE }}
+ gap-name: k8s
+ use-private-ecr-registry: true
+ use-k8s: true
+ proxy-port: 8443
+ metrics-job-name: "test"
+ gc-basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ gc-host: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ gc-org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+
+ - name: Setup GitHub token using GATI
+ id: token
+ uses: smartcontractkit/.github/actions/setup-github-token@c0b38e6c40d72d01b8d2f24f92623a2538b3dedb # main
+ with:
+ aws-role-arn: ${{ secrets.AWS_OIDC_GLOBAL_READ_ONLY_TOKEN_ISSUER_ROLE_ARN }}
+ aws-lambda-url: ${{ secrets.AWS_INFRA_RELENG_TOKEN_ISSUER_LAMBDA_URL }}
+ aws-region: ${{ secrets.AWS_REGION }}
+ aws-role-duration-seconds: "1800"
+ - name: Debug workspace dir
+ shell: bash
+ run: |
+ echo ${{ github.workspace }}
+ echo $GITHUB_WORKSPACE
+
+ - name: Deploy and validate CRIB Environment for Core
+ uses: smartcontractkit/.github/actions/crib-deploy-environment@4dd21a9d6e3f1383ffe8b9650b55f6e6031d3d0a # crib-deploy-environment@1.0.0
+ id: deploy-crib
+ with:
+ github-token: ${{ steps.token.outputs.access-token }}
+ api-gateway-host: ${{ secrets.AWS_API_GW_HOST_K8S_STAGE }}
+ aws-region: ${{ secrets.AWS_REGION }}
+ aws-role-arn: ${{ secrets.AWS_OIDC_CRIB_ROLE_ARN_STAGE }}
+ ecr-private-registry: ${{ secrets.AWS_ACCOUNT_ID_PROD }}
+ ingress-base-domain: ${{ secrets.INGRESS_BASE_DOMAIN_STAGE }}
+ k8s-cluster-name: ${{ secrets.AWS_K8S_CLUSTER_NAME_STAGE }}
+ devspace-profiles: "local-dev-simulated-core-ocr1"
+ crib-alert-slack-webhook: ${{ secrets.CRIB_ALERT_SLACK_WEBHOOK }}
+ product-image: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }}/chainlink
+ product-image-tag: develop
+ - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - name: Setup go
+ uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
+ with:
+ go-version-file: "go.mod"
+ - name: Run CRIB integration test
+ working-directory: integration-tests/crib
+ env:
+ K8S_STAGING_INGRESS_SUFFIX: ${{ secrets.K8S_STAGING_INGRESS_SUFFIX }}
+ CRIB_NAMESPACE: ${{ steps.deploy-crib.outputs.devspace-namespace }}
+ CRIB_NETWORK: geth
+ CRIB_NODES: 5
+ GAP_URL: ${{ secrets.GAP_URL }}
+ SETH_LOG_LEVEL: info
+ # RESTY_DEBUG: true
+ TEST_PERSISTENCE: true
+ run: |-
+ go test -v -run TestCRIB
+ - name: Destroy CRIB Environment
+ id: destroy
+ if: always() && steps.deploy-crib.outputs.devspace-namespace != ''
+ uses: smartcontractkit/.github/actions/crib-purge-environment@c0b38e6c40d72d01b8d2f24f92623a2538b3dedb # crib-purge-environment@0.1.0
+ with:
+ namespace: ${{ steps.deploy-crib.outputs.devspace-namespace }}
diff --git a/.github/workflows/goreleaser-build-publish-develop.yml b/.github/workflows/goreleaser-build-publish-develop.yml
deleted file mode 100644
index 835d650f181..00000000000
--- a/.github/workflows/goreleaser-build-publish-develop.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-name: "Build publish Chainlink develop on private ECR"
-
-on:
- push:
- branches:
- - develop
-
-jobs:
- push-chainlink-develop-goreleaser:
- runs-on:
- labels: ubuntu22.04-16cores-64GB
- outputs:
- goreleaser-metadata: ${{ steps.build-sign-publish.outputs.goreleaser-metadata }}
- goreleaser-artifacts: ${{ steps.build-sign-publish.outputs.goreleaser-artifacts }}
- environment: build-develop
- permissions:
- id-token: write
- contents: read
- steps:
- - name: Checkout repository
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- - name: Configure aws credentials
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
- with:
- role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE_ARN }}
- role-duration-seconds: ${{ secrets.AWS_ROLE_DURATION_SECONDS }}
- aws-region: ${{ secrets.AWS_REGION }}
- mask-aws-account-id: true
- role-session-name: goreleaser-build-publish-chainlink.push-develop
- - name: Build, sign, and publish image
- id: build-sign-publish
- uses: ./.github/actions/goreleaser-build-sign-publish
- with:
- enable-docker-publish: "true"
- docker-registry: ${{ secrets.AWS_DEVELOP_ECR_HOSTNAME }}
- enable-goreleaser-snapshot: "true"
- goreleaser-exec: ./tools/bin/goreleaser_wrapper
- goreleaser-config: .goreleaser.develop.yaml
- goreleaser-key: ${{ secrets.GORELEASER_KEY }}
- zig-version: 0.11.0
- - name: Collect Metrics
- if: always()
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- with:
- id: goreleaser-build-publish
- org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
- this-job-name: push-chainlink-develop-goreleaser
- continue-on-error: true
-
\ No newline at end of file
diff --git a/.github/workflows/integration-staging-tests.yml b/.github/workflows/integration-staging-tests.yml
deleted file mode 100644
index d092b2bca1c..00000000000
--- a/.github/workflows/integration-staging-tests.yml
+++ /dev/null
@@ -1,132 +0,0 @@
-# NEEDS ADJUSTING TO TOML CONFIG BEFORE USING!!
-name: E2E Functions staging tests
-
-on:
-# TODO: enable when env will be stable
-# schedule:
-# - cron: "0 0 * * *"
- workflow_dispatch:
- inputs:
- network:
- description: Blockchain network (testnet)
- type: choice
- default: "MUMBAI"
- options:
- - "MUMBAI"
- test_type:
- description: Test type
- type: choice
- default: "mumbai_functions_soak_test_real"
- options:
- - "mumbai_functions_soak_test_http"
- - "mumbai_functions_stress_test_http"
- - "mumbai_functions_soak_test_only_secrets"
- - "mumbai_functions_stress_test_only_secrets"
- - "mumbai_functions_soak_test_real"
- - "mumbai_functions_stress_test_real"
-# TODO: disabled, need GATI access
-# - "gateway_secrets_set_soak_test"
-# - "gateway_secrets_list_soak_test"
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}
- cancel-in-progress: true
-
-jobs:
- e2e-soak-test:
- environment: sdlc
- runs-on: ubuntu22.04-8cores-32GB
- permissions:
- contents: read
- id-token: write
- env:
- LOKI_URL: ${{ secrets.LOKI_URL }}
- LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }}
- SELECTED_NETWORKS: ${{ inputs.network }}
- SELECTED_TEST: ${{ inputs.test_type }}
- MUMBAI_URLS: ${{ secrets.FUNCTIONS_STAGING_MUMBAI_URLS }}
- MUMBAI_KEYS: ${{ secrets.FUNCTIONS_STAGING_MUMBAI_KEYS }}
- WASP_LOG_LEVEL: info
- steps:
- - name: Checkout code
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- with:
- fetch-depth: 0
- - name: Prepare Base64 TOML override
- env:
- PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }}
- PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia
- PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
- run: |
- convert_to_toml_array() {
- local IFS=','
- local input_array=($1)
- local toml_array_format="["
-
- for element in "${input_array[@]}"; do
- toml_array_format+="\"$element\","
- done
-
- toml_array_format="${toml_array_format%,}]"
- echo "$toml_array_format"
- }
-
- if [ -n "$PYROSCOPE_SERVER" ]; then
- pyroscope_enabled=true
- else
- pyroscope_enabled=false
- fi
-
- cat << EOF > config.toml
- [Common]
- chainlink_node_funding=0.5
-
- [ChainlinkImage]
- image="$CHAINLINK_IMAGE"
- version="${{ github.sha }}"
-
- [Pyroscope]
- enabled=$pyroscope_enabled
- server_url="$PYROSCOPE_SERVER"
- environment="$PYROSCOPE_ENVIRONMENT"
- key_secret="$PYROSCOPE_KEY"
-
- [Logging]
- run_id="$RUN_ID"
-
- [Logging.LogStream]
- log_targets=$log_targets
-
- [Logging.Loki]
- tenant_id="$LOKI_TENANT_ID"
- endpoint="$LOKI_URL"
- basic_auth_secret="$LOKI_BASIC_AUTH"
-
- [Logging.Grafana]
- base_url="$GRAFANA_URL"
- dashboard_url="/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
-
- [Network]
- selected_networks=["sepolia"]
-
- [Network.RpcHttpUrls]
- sepolia = $(convert_to_toml_array "$SEPOLIA_HTTP_URLS")
-
- [Network.RpcWsUrls]
- sepolia = $(convert_to_toml_array "$SEPOLIA_URLS")
-
- [Network.WalletKeys]
- sepolia = $(convert_to_toml_array "$EVM_KEYS")
- EOF
-
- BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0)
- echo ::add-mask::$BASE64_CONFIG_OVERRIDE
- echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV
- - name: Run E2E soak tests
- run: |
- cd integration-tests/load/functions
- if [[ $SELECTED_TEST == mumbai_functions* ]]; then
- go test -v -timeout 6h -run TestFunctionsLoad/$SELECTED_TEST
- elif [[ $SELECTED_TEST == gateway* ]]; then
- go test -v -timeout 6h -run TestGatewayLoad/$SELECTED_TEST
- fi
\ No newline at end of file
diff --git a/.github/workflows/integration-tests-publish.yml b/.github/workflows/integration-tests-publish.yml
index 76a86c43238..de551fedce1 100644
--- a/.github/workflows/integration-tests-publish.yml
+++ b/.github/workflows/integration-tests-publish.yml
@@ -54,7 +54,7 @@ jobs:
SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
with:
channel-id: "#team-test-tooling-internal"
- slack-message: ":x: :mild-panic-intensifies: Publish Integration Test Image failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}"
+ slack-message: ":x: :mild-panic-intensifies: Publish Integration Test Image failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}\nRepository: Chainlink\n${{ format('Notifying ', secrets.GUARDIAN_SLACK_NOTIFICATION_HANDLE)}}"
build-chainlink-image:
environment: integration
# Only run this build for workflow_dispatch
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index ec9168133da..972228bc8ec 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -92,15 +92,21 @@ jobs:
id: changes
with:
filters: |
- changes:
+ github_ci_changes:
+ - '.github/workflows/integration-tests.yml'
+ - '.github/workflows/run-e2e-tests-reusable-workflow.yml'
+ - '.github/e2e-tests.yml'
+ core_changes:
- '**/*.go'
- '**/*go.sum'
- '**/*go.mod'
- - '.github/workflows/integration-tests.yml'
- '**/*Dockerfile'
- 'core/**/migrations/*.sql'
- 'core/**/config/**/*.toml'
- 'integration-tests/**/*.toml'
+ ccip_changes:
+ - '**/*ccip*'
+ - '**/*ccip*/**'
- name: Ignore Filter On Workflow Dispatch
if: ${{ github.event_name == 'workflow_dispatch' }}
id: ignore-filter
@@ -117,10 +123,12 @@ jobs:
this-job-name: Check Paths That Require Tests To Run
continue-on-error: true
outputs:
- src: ${{ steps.ignore-filter.outputs.changes || steps.changes.outputs.changes }}
+ github_ci_changes: ${{ steps.ignore-filter.outputs.changes || steps.changes.outputs.github_ci_changes }}
+ core_changes: ${{ steps.ignore-filter.outputs.changes || steps.changes.outputs.core_changes }}
+ ccip_changes: ${{ steps.ignore-filter.outputs.changes || steps.changes.outputs.ccip_changes }}
- build-lint-integration-tests:
- name: Build and Lint ${{ matrix.project.name }}
+ lint-integration-tests:
+ name: Lint ${{ matrix.project.name }}
runs-on: ubuntu22.04-8cores-32GB
# We don't directly merge dependabot PRs, so let's not waste the resources
if: github.actor != 'dependabot[bot]'
@@ -128,13 +136,13 @@ jobs:
matrix:
project:
- name: integration-tests
- id: e2e
+ id: e2e-tests
path: ./integration-tests
- cache-id: e2e
+ cache_id: e2e-tests
- name: load
id: load
path: ./integration-tests/load
- cache-id: load
+ cache_id: load
steps:
- name: Collect Metrics
id: collect-gha-metrics
@@ -144,7 +152,7 @@ jobs:
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 }}
+ this-job-name: Lint ${{ matrix.project.name }}
continue-on-error: true
- name: Checkout the repo
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
@@ -152,17 +160,12 @@ jobs:
repository: smartcontractkit/chainlink
ref: ${{ inputs.cl_ref }}
- name: Setup Go
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@0ce1e67b254a4f041e03cc6f0e3afc987b47c7bd # v2.3.30
with:
test_download_vendor_packages_command: cd ${{ matrix.project.path }} && go mod download
go_mod_path: ${{ matrix.project.path }}/go.mod
- cache_key_id: core-${{ matrix.project.cache-id }}-${{ env.MOD_CACHE_VERSION }}
- cache_restore_only: "true"
- - name: Build Go
- run: |
- cd ${{ matrix.project.path }}
- go build ./...
- go test -run=^# ./...
+ cache_key_id: ${{ matrix.project.cache_id }}
+ cache_restore_only: "true"
- name: Lint Go
uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0
with:
@@ -194,7 +197,7 @@ jobs:
needs: [changes, enforce-ctf-version]
steps:
- name: Collect Metrics
- if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.core_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true' || github.event_name == 'workflow_dispatch'
id: collect-gha-metrics
uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
@@ -219,7 +222,7 @@ jobs:
aws-region: ${{ secrets.AWS_REGION }}
set-git-config: "true"
- name: Build Chainlink Image
- if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.core_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true' || github.event_name == 'workflow_dispatch'
uses: ./.github/actions/build-chainlink-image
with:
tag_suffix: ${{ matrix.image.tag-suffix }}
@@ -229,587 +232,126 @@ jobs:
AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
dep_evm_sha: ${{ inputs.evm-ref }}
- compare-tests:
- needs: [changes]
- runs-on: ubuntu-latest
- name: Compare/Build Automation Test List
- outputs:
- automation-matrix: ${{ env.AUTOMATION_JOB_MATRIX_JSON }}
- lp-matrix: ${{ env.LP_JOB_MATRIX_JSON }}
- steps:
- - name: Check for Skip Tests Label
- if: contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests')
- run: |
- echo "## \`skip-smoke-tests\` label is active, skipping E2E smoke tests" >>$GITHUB_STEP_SUMMARY
- exit 0
- - name: Checkout the repo
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- with:
- repository: smartcontractkit/chainlink
- ref: ${{ inputs.cl_ref }}
- - name: Compare Test Lists
- run: |
- cd ./integration-tests
- ./scripts/compareTestList.sh ./smoke/automation_test.go
- ./scripts/compareTestList.sh ./smoke/keeper_test.go
- ./scripts/compareTestList.sh ./smoke/log_poller_test.go
- - name: Build Test Matrix Lists
- id: build-test-matrix-list
- run: |
- cd ./integration-tests
- MATRIX_JSON_AUTOMATION=$(./scripts/buildTestMatrixList.sh ./smoke/automation_test.go automation ubuntu-latest 1)
- MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu-latest 1)
- COMBINED_ARRAY=$(jq -c -n "$MATRIX_JSON_AUTOMATION + $MATRIX_JSON_KEEPER")
- echo "combined array = ${COMBINED_ARRAY}"
- echo "event name = $GITHUB_EVENT_NAME"
-
- LOG_POLLER_MATRIX_JSON=$(./scripts/buildTestMatrixList.sh ./smoke/log_poller_test.go log_poller ubuntu-latest 1)
- echo "LP_JOB_MATRIX_JSON=${LOG_POLLER_MATRIX_JSON}" >> $GITHUB_ENV
-
- # if we running a PR against the develop branch we should only run the automation tests unless we are in the merge group event
- if [[ "$GITHUB_EVENT_NAME" == "merge_group" ]]; then
- echo "We are in a merge_group event, run both automation and keepers tests"
- echo "AUTOMATION_JOB_MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV
- else
- echo "we are not in a merge_group event, if this is a PR to develop run only automation tests, otherwise run everything because we could be running against a release branch"
- target_branch=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.base.ref)
- if [[ "$target_branch" == "develop" ]]; then
- echo "only run automation tests"
- echo "AUTOMATION_JOB_MATRIX_JSON=${MATRIX_JSON_AUTOMATION}" >> $GITHUB_ENV
- else
- echo "run both automation and keepers tests"
- echo "AUTOMATION_JOB_MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV
- fi
- fi
-
- eth-smoke-tests-matrix-automation:
- if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }}
- environment: integration
- permissions:
- checks: write
- pull-requests: write
- id-token: write
- contents: read
- needs:
- [build-chainlink, changes, compare-tests, build-lint-integration-tests]
- env:
- SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2
- CHAINLINK_COMMIT_SHA: ${{ inputs.evm-ref || github.sha }}
- CHAINLINK_ENV_USER: ${{ github.actor }}
- TEST_LOG_LEVEL: debug
- strategy:
- fail-fast: false
- matrix:
- product: ${{fromJson(needs.compare-tests.outputs.automation-matrix)}}
- runs-on: ${{ matrix.product.os }}
- name: ETH Smoke Tests ${{ matrix.product.name }}
- 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@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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 }}
- this-job-name: ETH Smoke Tests ${{ matrix.product.name }}
- 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:
- repository: smartcontractkit/chainlink
- ref: ${{ inputs.cl_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.product.run is set, use it for a different command
- if [ "${{ matrix.product.run }}" != "" ]; then
- echo "run_command=${{ matrix.product.run }} ./smoke/${{ matrix.product.file }}_test.go" >> "$GITHUB_OUTPUT"
- else
- echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT"
- fi
- - name: Setup GAP for Grafana
- uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2
- id: setup-gap
- with:
- # aws inputs
- aws-region: ${{ secrets.AWS_REGION }}
- aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }}
- api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
- # other inputs
- duplicate-authorization-header: "true"
-
- ## 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@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
- 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 | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
- test_download_vendor_packages_command: cd ./integration-tests && go mod download
- test_config_chainlink_version: ${{ inputs.evm-ref || github.sha }}
- test_config_selected_networks: ${{ env.SELECTED_NETWORKS }}
- test_config_logging_run_id: ${{ github.run_id }}
- test_config_logstream_log_targets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
- test_config_test_log_collect: ${{ vars.TEST_LOG_COLLECT }}
- cl_repo: ${{ env.CHAINLINK_IMAGE }}
- cl_image_tag: ${{ inputs.evm-ref || github.sha }}
- aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
- artifacts_name: ${{ matrix.product.name }}-test-logs
- artifacts_location: |
- ./integration-tests/smoke/logs/
- /tmp/gotest.log
- publish_check_name: ${{ matrix.product.name }}
- 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"
- go_coverage_src_dir: /var/tmp/go-coverage
- go_coverage_dest_dir: ${{ github.workspace }}/.covdata
- DEFAULT_CHAINLINK_IMAGE: ${{ env.CHAINLINK_IMAGE }}
- DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- DEFAULT_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
- DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
- DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
- DEFAULT_PYROSCOPE_SERVER_URL: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725
- DEFAULT_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
- DEFAULT_PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }}
- DEFAULT_PYROSCOPE_ENABLED: ${{ matrix.product.pyroscope_env == '' || !startsWith(github.ref, 'refs/tags/') && 'false' || 'true' }}
-
- - name: Upload Coverage Data
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
- timeout-minutes: 2
- continue-on-error: true
- with:
- name: cl-node-coverage-data-${{ matrix.product.name }}
- path: .covdata
- retention-days: 1
-
- - name: Print failed test summary
- if: always()
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
-
- eth-smoke-tests-matrix-log-poller:
- if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') || inputs.distinct_run_name != '' }}
- environment: integration
+ run-core-e2e-tests-workflow:
+ name: Run Core E2E Tests
permissions:
+ actions: read
checks: write
pull-requests: write
id-token: write
contents: read
- needs:
- [build-chainlink, changes, compare-tests, build-lint-integration-tests]
- env:
- SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2
- CHAINLINK_COMMIT_SHA: ${{ inputs.evm-ref || github.sha }}
- CHAINLINK_ENV_USER: ${{ github.actor }}
- TEST_LOG_LEVEL: debug
- strategy:
- fail-fast: false
- matrix:
- product: ${{fromJson(needs.compare-tests.outputs.lp-matrix)}}
- runs-on: ${{ matrix.product.os }}
- name: ETH Smoke Tests ${{ matrix.product.name }}
- steps:
- - name: Collect Metrics
- if: needs.changes.outputs.src == 'true'
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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 }}
- this-job-name: ETH Smoke Tests ${{ matrix.product.name }}
- 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:
- repository: smartcontractkit/chainlink
- ref: ${{ inputs.cl_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.product.run is set, use it for a different command
- if [ "${{ matrix.product.run }}" != "" ]; then
- echo "run_command=${{ matrix.product.run }} ./smoke/${{ matrix.product.file }}_test.go" >> "$GITHUB_OUTPUT"
- else
- echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT"
- fi
- - name: Setup GAP for Grafana
- uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2
- id: setup-gap
- with:
- # aws inputs
- aws-region: ${{ secrets.AWS_REGION }}
- aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }}
- api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
- # other inputs
- duplicate-authorization-header: "true"
- ## 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@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
- 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 | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
- test_download_vendor_packages_command: cd ./integration-tests && go mod download
- test_config_chainlink_version: ${{ inputs.evm-ref || github.sha }}
- test_config_selected_networks: ${{ env.SELECTED_NETWORKS }}
- test_config_logging_run_id: ${{ github.run_id }}
- test_config_logstream_log_targets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
- test_config_test_log_collect: ${{ vars.TEST_LOG_COLLECT }}
- cl_repo: ${{ env.CHAINLINK_IMAGE }}
- cl_image_tag: ${{ inputs.evm-ref || github.sha }}
- aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
- artifacts_name: ${{ matrix.product.name }}-test-logs
- artifacts_location: |
- ./integration-tests/smoke/logs/
- /tmp/gotest.log
- publish_check_name: ${{ matrix.product.name }}
- 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"
- go_coverage_src_dir: /var/tmp/go-coverage
- go_coverage_dest_dir: ${{ github.workspace }}/.covdata
- DEFAULT_CHAINLINK_IMAGE: ${{ env.CHAINLINK_IMAGE }}
- DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- DEFAULT_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
- DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
- DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
- DEFAULT_PYROSCOPE_SERVER_URL: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725
- DEFAULT_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
- DEFAULT_PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }}
- DEFAULT_PYROSCOPE_ENABLED: ${{ matrix.product.pyroscope_env == '' || !startsWith(github.ref, 'refs/tags/') && 'false' || 'true' }}
-
- - name: Upload Coverage Data
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
- timeout-minutes: 2
- continue-on-error: true
- with:
- name: cl-node-coverage-data-${{ matrix.product.name }}
- path: .covdata
- retention-days: 1
-
- - name: Print failed test summary
- if: always()
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
-
-
- eth-smoke-tests-matrix:
- if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }}
- environment: integration
+ needs: [build-chainlink, changes]
+ if: needs.changes.outputs.core_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true'
+ uses: ./.github/workflows/run-e2e-tests-reusable-workflow.yml
+ with:
+ workflow_name: Run Core E2E Tests
+ chainlink_version: ${{ inputs.evm-ref || github.sha }}
+ chainlink_upgrade_version: ${{ github.sha }}
+ test_workflow: PR E2E Core Tests
+ upload_cl_node_coverage_artifact: true
+ upload_cl_node_coverage_artifact_prefix: cl_node_coverage_data_
+ enable_otel_traces_for_ocr2_plugins: ${{ contains(join(github.event.pull_request.labels.*.name, ' '), 'enable tracing') }}
+ secrets:
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }}
+ QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
+ QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
+ GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ GRAFANA_INTERNAL_URL_SHORTENER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }}
+ AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
+ SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
+
+ run-ccip-e2e-tests-workflow:
+ name: Run CCIP E2E Tests
permissions:
actions: read
checks: write
pull-requests: write
id-token: write
contents: read
- needs: [build-chainlink, changes, build-lint-integration-tests]
- env:
- SELECTED_NETWORKS: SIMULATED
- CHAINLINK_COMMIT_SHA: ${{ inputs.evm-ref || github.sha }}
- CHAINLINK_ENV_USER: ${{ github.actor }}
- TEST_LOG_LEVEL: debug
- strategy:
- fail-fast: false
- 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: reorg_above_finality
- id: reorg_above_finality
- nodes: 1
- os: ubuntu-latest
- file: reorg_above_finality
- pyroscope_env: ci-smoke-reorg-above-finality-evm-simulated
- - name: ocr2
- id: ocr2
- nodes: 6
- os: ubuntu22.04-16cores-64GB
- file: ocr2
- pyroscope_env: ci-smoke-ocr2-evm-simulated
- - name: ocr2
- id: ocr2-plugins
- nodes: 6
- 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: 6
- os: ubuntu-latest
- pyroscope_env: ci-smoke-vrf2-evm-simulated
- - name: vrfv2plus
- id: vrfv2plus
- nodes: 9
- 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
- runs-on: ${{ matrix.product.os }}
- name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }}
+ needs: [build-chainlink, changes]
+ if: needs.changes.outputs.ccip_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true'
+ uses: ./.github/workflows/run-e2e-tests-reusable-workflow.yml
+ with:
+ workflow_name: Run CCIP E2E Tests
+ chainlink_version: ${{ inputs.evm-ref || github.sha }}
+ chainlink_upgrade_version: ${{ github.sha }}
+ test_workflow: PR E2E CCIP Tests
+ upload_cl_node_coverage_artifact: true
+ upload_cl_node_coverage_artifact_prefix: cl_node_coverage_data_
+ enable_otel_traces_for_ocr2_plugins: ${{ contains(join(github.event.pull_request.labels.*.name, ' '), 'enable tracing') }}
+ secrets:
+ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
+ QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }}
+ QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
+ QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
+ GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ GRAFANA_INTERNAL_URL_SHORTENER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ AWS_REGION: ${{ secrets.QA_AWS_REGION }}
+ AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }}
+ AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
+ SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
+
+ check-e2e-test-results:
+ if: always()
+ name: ETH Smoke Tests
+ runs-on: ubuntu-latest
+ needs: [run-core-e2e-tests-workflow, run-ccip-e2e-tests-workflow]
steps:
- # Handy for debugging resource usage
- # - name: Collect Workflow Telemetry
- # uses: catchpoint/workflow-telemetry-action@v2
- - name: Collect Metrics
- if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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 }}
- this-job-name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }}
- 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:
- repository: smartcontractkit/chainlink
- ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }}
- - name: Build Go Test Command
- id: build-go-test-command
+ - name: Check Core test results
+ id: check_core_results
run: |
- # if the matrix.product.run is set, use it for a different command
- if [ "${{ matrix.product.run }}" != "" ]; then
- echo "run_command=${{ matrix.product.run }} ./smoke/${{ matrix.product.file }}_test.go" >> "$GITHUB_OUTPUT"
- else
- echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT"
- fi
- - name: Check for "enable tracing" label
- id: check-label
- run: |
- label=$(jq -r '.pull_request.labels[]?.name // empty' "$GITHUB_EVENT_PATH")
+ results='${{ needs.run-core-e2e-tests-workflow.outputs.test_results }}'
+ echo "Core test results:"
+ echo "$results" | jq .
+
+ node_migration_tests_failed=$(echo $results | jq '[.[] | select(.id == "integration-tests/migration/upgrade_version_test.go:*" ) | select(.result != "success")] | length > 0')
+ echo "node_migration_tests_failed=$node_migration_tests_failed" >> $GITHUB_OUTPUT
- if [[ -n "$label" ]]; then
- if [[ "$label" == "enable tracing" ]]; then
- echo "Enable tracing label found."
- echo "trace=true" >> $GITHUB_OUTPUT
- else
- echo "Enable tracing label not found."
- echo "trace=false" >> $GITHUB_OUTPUT
- fi
+ - name: Check CCIP test results
+ id: check_ccip_results
+ run: |
+ if [[ '${{ needs.run-ccip-e2e-tests-workflow.result }}' != 'skipped' ]]; then
+ results='${{ needs.run-ccip-e2e-tests-workflow.outputs.test_results }}'
+ echo "CCIP test results:"
+ echo "$results" | jq .
else
- echo "No labels present or labels are null."
- echo "trace=false" >> $GITHUB_OUTPUT
+ echo "CCIP tests were skipped."
fi
- - name: Setup Grafana and OpenTelemetry
- id: docker-setup
- if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins'
- run: |
- # Create network
- docker network create --driver bridge tracing
-
- # Make trace directory
- cd integration-tests/smoke/
- mkdir ./traces
- chmod -R 777 ./traces
-
- # Switch directory
- cd ../../.github/tracing
-
- # Create a Docker volume for traces
- # docker volume create otel-traces
-
- # Start OpenTelemetry Collector
- # Note the user must be set to the same user as the runner for the trace data to be accessible
- docker run -d --network=tracing --name=otel-collector \
- -v $PWD/otel-collector-ci.yaml:/etc/otel-collector.yaml \
- -v $PWD/../../integration-tests/smoke/traces:/tracing \
- --user "$(id -u):$(id -g)" \
- -p 4317:4317 otel/opentelemetry-collector:0.88.0 --config=/etc/otel-collector.yaml
-
- - name: Locate Docker Volume
- id: locate-volume
- if: false
- run: |
- echo "VOLUME_PATH=$(docker volume inspect --format '{{ .Mountpoint }}' otel-traces)" >> $GITHUB_OUTPUT
-
- - name: Show Otel-Collector Logs
- if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins'
- run: |
- docker logs otel-collector
-
- - name: Setup GAP for Grafana
- uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2
- id: setup-gap
- with:
- # aws inputs
- aws-region: ${{ secrets.AWS_REGION }}
- aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }}
- api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
- # other inputs
- duplicate-authorization-header: "true"
-
- ## 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@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
- 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 | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
- test_download_vendor_packages_command: cd ./integration-tests && go mod download
- test_config_chainlink_version: ${{ inputs.evm-ref || github.sha }}
- test_config_selected_networks: ${{ env.SELECTED_NETWORKS }}
- test_config_logging_run_id: ${{ github.run_id }}
- test_config_logstream_log_targets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
- test_config_test_log_collect: ${{ vars.TEST_LOG_COLLECT }}
- cl_repo: ${{ env.CHAINLINK_IMAGE }}
- cl_image_tag: ${{ inputs.evm-ref || github.sha }}${{ matrix.product.tag_suffix }}
- aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
- artifacts_name: ${{ matrix.product.name }}${{ matrix.product.tag_suffix }}-test-logs
- artifacts_location: |
- ./integration-tests/smoke/logs/
- /tmp/gotest.log
- publish_check_name: ${{ matrix.product.name }}
- 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"
- go_coverage_src_dir: /var/tmp/go-coverage
- go_coverage_dest_dir: ${{ github.workspace }}/.covdata
- DEFAULT_CHAINLINK_IMAGE: ${{ env.CHAINLINK_IMAGE }}
- DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- DEFAULT_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
- DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
- DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
- DEFAULT_PYROSCOPE_SERVER_URL: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725
- DEFAULT_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
- DEFAULT_PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }}
- DEFAULT_PYROSCOPE_ENABLED: ${{ matrix.product.pyroscope_env == '' || !startsWith(github.ref, 'refs/tags/') && 'false' || 'true' }}
-
- - name: Upload Coverage Data
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
- timeout-minutes: 2
- continue-on-error: true
- with:
- name: cl-node-coverage-data-${{ matrix.product.name }}-${{ matrix.product.tag_suffix }}
- path: .covdata
- retention-days: 1
-
- # 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@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
- with:
- test_download_vendor_packages_command: cd ./integration-tests && go mod download
- 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: Show Otel-Collector Logs
- if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins'
- run: |
- docker logs otel-collector
-
- - name: Permissions on traces
- if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins'
- run: |
- 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@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@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
+ - name: Send slack notification for failed migration tests
+ if: steps.check_core_results.outputs.node_migration_tests_failed == 'true' && github.event_name != 'workflow_dispatch'
+ uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
+ env:
+ SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
with:
- test_directory: ./integration-tests/smoke/
+ channel-id: "#team-test-tooling-internal"
+ slack-message: ":x: :mild-panic-intensifies: Node Migration Tests Failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}\n${{ format('Notifying ', secrets.GUARDIAN_SLACK_NOTIFICATION_HANDLE) }}"
- ### Used to check the required checks box when the matrix completes
- eth-smoke-tests:
- if: always()
- runs-on: ubuntu-latest
- name: ETH Smoke Tests
- needs: [eth-smoke-tests-matrix, eth-smoke-tests-matrix-automation, eth-smoke-tests-matrix-log-poller]
- 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'
+ - name: Fail the job if Core tests failed
+ if: always() && needs.run-core-e2e-tests-workflow.result == 'failure'
run: |
- echo "ETH Smoke Tests: ${{ needs.eth-smoke-tests-matrix.result }}"
- echo "Automation: ${{ needs.eth-smoke-tests-matrix-automation.result }}"
- echo "Log Poller: ${{ needs.eth-smoke-tests-matrix-log-poller.result }}"
+ echo "Core E2E tests failed"
+ echo "Job status:"
+ echo ${{ needs.run-core-e2e-tests-workflow.result }}
exit 1
- - name: Collect Metrics
- if: always()
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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 }}
- this-job-name: ETH Smoke Tests
- matrix-aggregator-status: ${{ needs.eth-smoke-tests-matrix.result }}
- continue-on-error: true
cleanup:
name: Clean up integration environment deployments
if: always()
- needs: [eth-smoke-tests]
+ needs: [run-core-e2e-tests-workflow, run-ccip-e2e-tests-workflow]
runs-on: ubuntu-latest
steps:
- name: Checkout repo
@@ -838,10 +380,10 @@ jobs:
this-job-name: Clean up integration environment deployments
continue-on-error: true
- show-coverage:
+ show-chainlink-node-coverage:
name: Show Chainlink Node Go Coverage
if: always()
- needs: [cleanup]
+ needs: [run-core-e2e-tests-workflow, run-ccip-e2e-tests-workflow]
runs-on: ubuntu-latest
steps:
- name: Checkout the repo
@@ -852,149 +394,11 @@ jobs:
- name: Download All Artifacts
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
with:
- path: cl-node-coverage-data
- pattern: cl-node-coverage-data-*
+ path: cl_node_coverage_data
+ pattern: cl_node_coverage_data_*
merge-multiple: true
- name: Show Coverage
- run: go run ./integration-tests/scripts/show_coverage.go "${{ github.workspace }}/cl-node-coverage-data/*/merged"
-
- # Run the setup if the matrix finishes but this time save the cache if we have a cache hit miss
- # this will also only run if both of the matrix jobs pass
- eth-smoke-go-mod-cache:
- environment: integration
- needs: [eth-smoke-tests]
- runs-on: ubuntu-latest
- name: ETH Smoke Tests Go Mod Cache
- continue-on-error: true
- steps:
- - name: Checkout the repo
- 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@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
- with:
- test_download_vendor_packages_command: |
- cd ./integration-tests
- go mod download
- # force download of test dependencies
- go test -run=NonExistentTest ./smoke/... || echo "ignore expected test failure"
- go_mod_path: ./integration-tests/go.mod
- cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }}
- cache_restore_only: "false"
-
- ### Migration tests
- node-migration-tests:
- name: Version Migration Tests
- environment: integration
- permissions:
- checks: write
- pull-requests: write
- id-token: write
- contents: read
- runs-on: ubuntu-latest
- needs: [build-chainlink, changes]
- # Only run migration tests on new tags
- if: startsWith(github.ref, 'refs/tags/')
- env:
- SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2
- CHAINLINK_COMMIT_SHA: ${{ inputs.evm-ref || github.sha }}
- CHAINLINK_ENV_USER: ${{ github.actor }}
- CHAINLINK_IMAGE: public.ecr.aws/chainlink/chainlink
- UPGRADE_VERSION: ${{ inputs.evm-ref || github.sha }}
- UPGRADE_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink
- TEST_LOG_LEVEL: debug
- TEST_SUITE: migration
- steps:
- - name: Collect Metrics
- id: collect-gha-metrics
- uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
- 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 }}
- this-job-name: Version Migration Tests
- 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:
- repository: smartcontractkit/chainlink
- ref: ${{ inputs.cl_ref || github.event.pull_request.head.sha || github.event.merge_group.head_sha }}
- - name: Get Latest Version
- id: get_latest_version
- run: |
- untrimmed_ver=$(curl --header "Authorization: token ${{ secrets.GITHUB_TOKEN }}" --request GET https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r .name)
- latest_version="${untrimmed_ver:1}"
- # Check if latest_version is empty
- if [ -z "$latest_version" ]; then
- echo "Error: The latest_version is empty. The migration tests need a verison to run."
- exit 1
- fi
- echo "latest_version=${latest_version}" >> "$GITHUB_OUTPUT"
- - name: Name Versions
- run: |
- echo "Running migration tests from version '${{ steps.get_latest_version.outputs.latest_version }}' to: '${{ inputs.evm-ref || github.sha }}'"
- - name: Prepare Base64 TOML override
- uses: ./.github/actions/setup-create-base64-upgrade-config
- with:
- selectedNetworks: ${{ env.SELECTED_NETWORKS }}
- chainlinkVersion: ${{ steps.get_latest_version.outputs.latest_version }}
- upgradeVersion: ${{ env.UPGRADE_VERSION }}
- runId: ${{ github.run_id }}
- testLogCollect: ${{ vars.TEST_LOG_COLLECT }}
- logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
- - name: Run Migration Tests
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
- with:
- test_command_to_run: cd ./integration-tests && go test -timeout 20m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
- test_download_vendor_packages_command: cd ./integration-tests && go mod download
- test_config_override_base64: ${{ env.BASE64_CONFIG_OVERRIDE }}
- cl_repo: ${{ env.CHAINLINK_IMAGE }}
- cl_image_tag: ${{ steps.get_latest_version.outputs.latest_version }}
- aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
- artifacts_name: node-migration-test-logs
- artifacts_location: |
- ./integration-tests/migration/logs
- /tmp/gotest.log
- publish_check_name: Node Migration Test Results
- 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: ""
- go_coverage_src_dir: /var/tmp/go-coverage
- go_coverage_dest_dir: ${{ github.workspace }}/.covdata
- should_tidy: "false"
- DEFAULT_CHAINLINK_IMAGE: ${{ env.CHAINLINK_IMAGE }}
- DEFAULT_CHAINLINK_UPGRADE_IMAGE: ${{ env.UPGRADE_IMAGE }}
- DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- DEFAULT_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
- DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
- DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
-
- - name: Upload Coverage Data
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
- timeout-minutes: 2
- continue-on-error: true
- with:
- name: cl-node-coverage-data-migration-tests
- path: .covdata
- retention-days: 1
- - name: Notify Slack
- if: failure() && github.event_name != 'workflow_dispatch'
- uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
- env:
- SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}
- with:
- channel-id: "#team-test-tooling-internal"
- slack-message: ":x: :mild-panic-intensifies: Node Migration Tests Failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}"
+ run: go run ./integration-tests/scripts/show_coverage.go "${{ github.workspace }}/cl_node_coverage_data/*/merged"
## Solana Section
get_solana_sha:
@@ -1037,7 +441,7 @@ jobs:
id: getsha
run: |
cd solanapath
- full_sha=$(git rev-parse ${{steps.getshortsha.outputs.short_sha}})
+ full_sha=$(git rev-parse ${{steps.getshortsha.outputs.short_sha}}^{}) # additional suffix allows handling tagged versions as well
if [ -z "${full_sha}" ]; then
echo "Error: could not get the full sha from the short sha using git, look above for error(s)"
exit 1
@@ -1077,7 +481,7 @@ jobs:
steps:
- name: Check if image exists
id: check-image
- uses: smartcontractkit/chainlink-github-actions/docker/image-exists@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
+ uses: smartcontractkit/chainlink-github-actions/docker/image-exists@0ce1e67b254a4f041e03cc6f0e3afc987b47c7bd # v2.3.30
with:
repository: chainlink-solana-tests
tag: ${{ needs.get_solana_sha.outputs.sha }}
@@ -1102,7 +506,7 @@ jobs:
]
steps:
- name: Collect Metrics
- if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch'
id: collect-gha-metrics
uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
@@ -1118,11 +522,11 @@ jobs:
repository: smartcontractkit/chainlink-solana
ref: ${{ needs.get_solana_sha.outputs.sha }}
- name: Build contracts
- if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false'
+ if: (needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false'
uses: smartcontractkit/chainlink-solana/.github/actions/build_contract_artifacts@46b1311a5a83f33d08ffa8e1e0ab04f9ad51665d # node20 update on may 10, 2024
with:
ref: ${{ needs.get_solana_sha.outputs.sha }}
- image: projectserum/build
+ image: backpackapp/build
image-version: ${{ needs.get_projectserum_version.outputs.projectserum_version }}
solana-build-test-image:
@@ -1145,7 +549,7 @@ jobs:
CONTRACT_ARTIFACTS_PATH: contracts/target/deploy
steps:
- name: Collect Metrics
- if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false'
+ if: (needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false'
id: collect-gha-metrics
uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
@@ -1156,13 +560,13 @@ jobs:
this-job-name: Solana Build Test Image
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'
+ if: (needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false'
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
repository: smartcontractkit/chainlink-solana
ref: ${{ needs.get_solana_sha.outputs.sha }}
- name: Build Test Image
- if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false'
+ if: (needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false'
uses: ./.github/actions/build-test-image
with:
tag: ${{ needs.get_solana_sha.outputs.sha }}
@@ -1171,7 +575,7 @@ jobs:
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
- run: echo "this exists so we don't have to run anything else if the build is skipped"
- if: needs.changes.outputs.src == 'false' || needs.solana-test-image-exists.outputs.exists == 'true'
+ if: needs.changes.outputs.core_changes == 'false' || needs.solana-test-image-exists.outputs.exists == 'true'
solana-smoke-tests:
if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }}
@@ -1198,7 +602,7 @@ jobs:
CONTRACT_ARTIFACTS_PATH: contracts/target/deploy
steps:
- name: Collect Metrics
- if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch'
id: collect-gha-metrics
uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
@@ -1215,8 +619,8 @@ jobs:
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@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
+ if: needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch'
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@0ce1e67b254a4f041e03cc6f0e3afc987b47c7bd # v2.3.30
with:
go_mod_path: ./integration-tests/go.mod
cache_restore_only: true
@@ -1228,7 +632,7 @@ jobs:
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
- name: Pull Artifacts
- if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch'
+ if: needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch'
run: |
IMAGE_NAME=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }}
# Pull the Docker image
@@ -1268,8 +672,8 @@ jobs:
# shellcheck disable=SC2086
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@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
+ if: needs.changes.outputs.core_changes == 'true' || github.event_name == 'workflow_dispatch'
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@d2f9642bcc24a73400568756f24b72c188ac7a9a # v2.3.31
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
test_config_override_base64: ${{ env.BASE64_CONFIG_OVERRIDE }}
@@ -1280,9 +684,11 @@ jobs:
cache_key_id: core-solana-e2e-${{ env.MOD_CACHE_VERSION }}
token: ${{ secrets.GITHUB_TOKEN }}
aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
- artifacts_name: solana-test-logs
+ artifacts_name: solana-test-artifacts
artifacts_location: |
./integration-tests/smoke/logs
+ ./integration-tests/smoke/db_dumps
+ ./integration-tests/smoke/seth_artifacts
/tmp/gotest.log
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
@@ -1296,7 +702,7 @@ jobs:
timeout-minutes: 2
continue-on-error: true
with:
- name: cl-node-coverage-data-solana-tests
+ name: cl_node_coverage_data_solana_tests
path: .covdata
retention-days: 1
diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml
index a7eaa19f7f0..bcf4dfea199 100644
--- a/.github/workflows/live-testnet-tests.yml
+++ b/.github/workflows/live-testnet-tests.yml
@@ -302,7 +302,7 @@ jobs:
if: always()
uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
with:
- test_directory: "./"
+ test_directories: "./"
bsc-testnet-smoke-tests:
environment: integration
diff --git a/.github/workflows/live-vrf-tests.yml b/.github/workflows/live-vrf-tests.yml
index faa4042e66e..28f5867954b 100644
--- a/.github/workflows/live-vrf-tests.yml
+++ b/.github/workflows/live-vrf-tests.yml
@@ -120,7 +120,7 @@ jobs:
needs: [build-chainlink, build-tests]
strategy:
fail-fast: false
- matrix:
+ matrix:
network: ${{fromJson(needs.build-tests.outputs.matrix)}}
name: Smoke Tests on ${{ matrix.network }}
runs-on: ubuntu-latest
@@ -190,4 +190,4 @@ jobs:
if: always()
uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@75a9005952a9e905649cfb5a6971fd9429436acd # v2.3.25
with:
- test_directory: "./"
\ No newline at end of file
+ test_directories: "./"
diff --git a/.github/workflows/on-demand-keeper-smoke-tests.yml b/.github/workflows/on-demand-keeper-smoke-tests.yml
index 75359c7501f..23626c2c98a 100644
--- a/.github/workflows/on-demand-keeper-smoke-tests.yml
+++ b/.github/workflows/on-demand-keeper-smoke-tests.yml
@@ -134,7 +134,7 @@ jobs:
## Run this step when changes that require tests to be run are made
- name: Run Tests
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@d2f9642bcc24a73400568756f24b72c188ac7a9a # v2.3.31
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 | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
test_download_vendor_packages_command: cd ./integration-tests && go mod download
@@ -149,6 +149,7 @@ jobs:
artifacts_name: ${{ matrix.product.name }}-test-logs
artifacts_location: |
./integration-tests/smoke/logs/
+ ./integration-tests/smoke/db_dumps/
/tmp/gotest.log
publish_check_name: ${{ matrix.product.name }}
token: ${{ secrets.GITHUB_TOKEN }}
@@ -286,4 +287,4 @@ jobs:
go test -run=NonExistentTest ./smoke/... || echo "ignore expected test failure"
go_mod_path: ./integration-tests/go.mod
cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }}
- cache_restore_only: "false"
\ No newline at end of file
+ cache_restore_only: "false"
diff --git a/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml
index 5f24fa81c3d..6d92acd9ea8 100644
--- a/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml
+++ b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml
@@ -5,12 +5,12 @@ on:
base64Config:
description: base64-ed config
required: true
- type: string
+ type: string
test_secrets_override_key:
description: 'Key to run tests with custom test secrets'
required: false
- type: string
-
+ type: string
+
jobs:
vrfv2_smoke_test:
name: VRFV2 Smoke Test with custom EL client client
@@ -24,11 +24,11 @@ jobs:
env:
TEST_LOG_LEVEL: debug
REF_NAME: ${{ github.head_ref || github.ref_name }}
- steps:
+ steps:
- name: Checkout code
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
- fetch-depth: 0
+ fetch-depth: 0
- name: Mask base64 config
run: |
BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH)
@@ -37,7 +37,7 @@ jobs:
- name: Parse base64 config
uses: ./.github/actions/setup-parse-base64-config
with:
- base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }}
+ base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }}
- name: Send details to Step Summary
shell: bash
run: |
@@ -48,7 +48,7 @@ jobs:
echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY
echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY
echo "### Execution client used" >>$GITHUB_STEP_SUMMARY
- echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY
+ echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY
- name: Run Tests
uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@2967f2287bd3f3ddbac7b476e9568993df01796e # v2.3.27
with:
@@ -59,12 +59,14 @@ jobs:
cl_image_tag: ${{ env.CHAINLINK_VERSION }}
aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
artifacts_name: vrf-test-logs
- artifacts_location: ./integration-tests/smoke/logs/
+ artifacts_location: |
+ ./integration-tests/smoke/logs/
+ ./integration-tests/smoke/db_dumps/
token: ${{ secrets.GITHUB_TOKEN }}
go_mod_path: ./integration-tests/go.mod
should_cleanup: false
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_KUBECONFIG: ""
DEFAULT_CHAINLINK_IMAGE: ${{ env.CHAINLINK_IMAGE }}
DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
@@ -72,4 +74,4 @@ jobs:
DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
\ No newline at end of file
+ DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
diff --git a/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml
index 58ecd39763d..1e58002fc1b 100644
--- a/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml
+++ b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml
@@ -5,11 +5,11 @@ on:
base64Config:
description: base64-ed config
required: true
- type: string
+ type: string
test_secrets_override_key:
description: 'Key to run tests with custom test secrets'
required: false
- type: string
+ type: string
jobs:
vrfv2plus_smoke_test:
@@ -24,7 +24,7 @@ jobs:
env:
TEST_LOG_LEVEL: debug
REF_NAME: ${{ github.head_ref || github.ref_name }}
- steps:
+ steps:
- name: Checkout code
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
@@ -48,7 +48,7 @@ jobs:
echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY
echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY
echo "### Execution client used" >>$GITHUB_STEP_SUMMARY
- echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY
+ echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY
- name: Run Tests
uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@2967f2287bd3f3ddbac7b476e9568993df01796e # v2.3.27
with:
@@ -59,12 +59,14 @@ jobs:
cl_image_tag: ${{ env.CHAINLINK_VERSION }}
aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
artifacts_name: vrfplus-test-logs
- artifacts_location: ./integration-tests/smoke/logs/
+ artifacts_location: |
+ ./integration-tests/smoke/logs/
+ ./integration-tests/smoke/db_dumps/
token: ${{ secrets.GITHUB_TOKEN }}
go_mod_path: ./integration-tests/go.mod
should_cleanup: false
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
QA_KUBECONFIG: ""
DEFAULT_CHAINLINK_IMAGE: ${{ env.CHAINLINK_IMAGE }}
DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
@@ -72,4 +74,4 @@ jobs:
DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
\ No newline at end of file
+ DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
diff --git a/.github/workflows/pr-labels.yml b/.github/workflows/pr-labels.yml
deleted file mode 100644
index fc4cae227a5..00000000000
--- a/.github/workflows/pr-labels.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-name: PR Labels
-
-on:
- pull_request:
- types: [labeled]
-
-jobs:
- crib:
- runs-on: ubuntu-latest
- permissions:
- # For AWS assume role.
- id-token: write
- contents: read
- # To comment on PR's.
- issues: write
- pull-requests: write
- steps:
- - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
-
- - uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0
- with:
- version: ^9.0.0
-
- - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
- with:
- node-version: 20
- cache: pnpm
- cache-dependency-path: ./.github/scripts/crib/pnpm-lock.yaml
-
- - run: pnpm install
- working-directory: ./.github/scripts/crib
-
- - name: Assume role capable of dispatching action
- uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2
- with:
- role-to-assume: ${{ secrets.AWS_OIDC_CRIB_ROLE_ARN_SAND }}
- aws-region: ${{ secrets.AWS_REGION }}
- role-duration-seconds: 900
- mask-aws-account-id: true
- role-session-name: pr-labels.crib
-
- - name: Comment CRIB details on PR
- run: ./.github/scripts/crib/pr-comment-crib-env.js
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- ROUTE53_ZONE_ID: ${{ secrets.ROUTE53_ZONE_ID_SAND }}
diff --git a/.github/workflows/run-automation-ondemand-e2e-tests.yml b/.github/workflows/run-automation-ondemand-e2e-tests.yml
deleted file mode 100644
index 7bf4691ecc5..00000000000
--- a/.github/workflows/run-automation-ondemand-e2e-tests.yml
+++ /dev/null
@@ -1,163 +0,0 @@
-name: Run Automation On Demand Tests (TEST WORKFLOW)
-
-on:
- workflow_dispatch:
- inputs:
- chainlinkVersionUpdate:
- description: Chainlink image version to upgrade to (Leave empty to build from head/ref)
- required: false
- type: string
- chainlinkImageUpdate:
- description: Chainlink image repo to upgrade to
- options:
- - QA_ECR
- - public.ecr.aws/chainlink/chainlink
- type: choice
- chainlinkVersion:
- description: Chainlink image version to use initially for upgrade test
- default: latest
- required: true
- type: string
- chainlinkImage:
- description: Chainlink image repo to use initially for upgrade test
- required: true
- options:
- - public.ecr.aws/chainlink/chainlink
- - QA_ECR
- type: choice
- enableChaos:
- description: Check to enable chaos tests
- type: boolean
- default: false
- required: true
- enableReorg:
- description: Check to enable reorg tests
- type: boolean
- default: false
- required: true
- with_existing_remote_runner_version:
- description: 'Tag of the existing remote runner version to use (Leave empty to build from head/ref)'
- required: false
- type: string
-
-jobs:
- # Set tests to run based on the workflow inputs
- set-tests-to-run:
- name: Set tests to run
- runs-on: ubuntu-latest
- outputs:
- test_list: ${{ steps.set-tests.outputs.test_list }}
- require_chainlink_image_versions_in_qa_ecr: ${{ steps.determine-chainlink-image-check.outputs.require_chainlink_image_versions_in_qa_ecr }}
- steps:
- - name: Determine build to use
- id: determine-build
- shell: bash
- run: |
- if [[ "${{ inputs.chainlinkImage }}" == "QA_ECR" ]]; then
- echo "image='{{ env.QA_CHAINLINK_IMAGE }}'" >>$GITHUB_OUTPUT
- else
- echo "image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT
- fi
- if [[ "${{ inputs.chainlinkImageUpdate }}" == "QA_ECR" ]]; then
- echo "upgrade_image='{{ env.QA_CHAINLINK_IMAGE }}'" >>$GITHUB_OUTPUT
- else
- echo "upgrade_image=${{ inputs.chainlinkImageUpdate }}" >>$GITHUB_OUTPUT
- fi
- if [[ -z "${{ inputs.chainlinkVersion }}" ]] && [[ "${{ inputs.chainlinkImage }}" == "QA_ECR" ]]; then
- echo "version=${{ github.sha }}" >>$GITHUB_OUTPUT
- else
- echo "version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT
- fi
- if [[ -z "${{ inputs.chainlinkVersionUpdate }}" ]] && [[ "${{ inputs.chainlinkImageUpdate }}" == "QA_ECR" ]]; then
- echo "upgrade_version=${{ github.sha }}" >>$GITHUB_OUTPUT
- else
- echo "upgrade_version=${{ inputs.chainlinkVersionUpdate }}" >>$GITHUB_OUTPUT
- fi
- - name: Check if chainlink image check required
- id: determine-chainlink-image-check
- shell: bash
- run: |
- chainlink_image_versions=""
- if [ "${{ github.event.inputs.chainlinkImage }}" = "QA_ECR" ]; then
- chainlink_image_versions+="${{ steps.determine-build.outputs.version }},"
- fi
- if [ "${{ github.event.inputs.chainlinkImageUpdate }}" = "QA_ECR" ]; then
- chainlink_image_versions+="${{ steps.determine-build.outputs.upgrade_version }}"
- fi
- echo "require_chainlink_image_versions_in_qa_ecr=$chainlink_image_versions" >> $GITHUB_OUTPUT
- - name: Set tests to run
- id: set-tests
- run: |
-
- # Always run upgrade tests
- cat > test_list.yaml <> test_list.yaml <> test_list.yaml <> $GITHUB_OUTPUT
-
- call-run-e2e-tests-workflow:
- name: Run E2E Tests
- needs: set-tests-to-run
- uses: ./.github/workflows/run-e2e-tests-reusable-workflow.yml
- with:
- test_list: ${{ needs.set-tests-to-run.outputs.test_list }}
- require_chainlink_image_versions_in_qa_ecr: ${{ needs.set-tests-to-run.outputs.require_chainlink_image_versions_in_qa_ecr }}
- with_existing_remote_runner_version: ${{ github.event.inputs.with_existing_remote_runner_version }}
- test_log_upload_on_failure: true
- test_log_upload_retention_days: 7
- secrets:
- QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
- QA_PYROSCOPE_INSTANCE: ${{ secrets.QA_PYROSCOPE_INSTANCE }}
- QA_PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }}
- QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
- GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }}
- GRAFANA_INTERNAL_URL_SHORTENER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }}
- AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
-
diff --git a/.github/workflows/run-e2e-tests-reusable-workflow.yml b/.github/workflows/run-e2e-tests-reusable-workflow.yml
index 2d3f31aa3b3..182e0f31d58 100644
--- a/.github/workflows/run-e2e-tests-reusable-workflow.yml
+++ b/.github/workflows/run-e2e-tests-reusable-workflow.yml
@@ -1,13 +1,22 @@
-# This is a reusable workflow that runs E2E tests for Chainlink.
+# This is a reusable workflow that runs E2E tests for Chainlink.
# It is not meant to be run on its own.
name: Run E2E Tests
on:
workflow_call:
inputs:
+ workflow_name:
+ description: 'Custom name for the workflow run'
+ required: false
+ type: string
+ default: 'Run E2E Tests'
chainlink_version:
- description: 'Enter Chainlink version to use for the tests. Example: "v2.10.0" or sha'
+ description: 'Enter Chainlink version to use for the tests. Example: v2.10.0, develop or commit sha'
required: false
- type: string
+ type: string
+ chainlink_upgrade_version:
+ description: 'Enter Chainlink version to use for the upgrade tests. Example: v2.10.0, develop or commit sha'
+ required: false
+ type: string
test_ids:
description: 'Run tests by test ids separated by commas. Example: "run_all_in_ocr_tests_go,run_TestOCRv2Request_in_ocr2_test_go". Check all test IDs in .github/e2e-tests.yml'
required: false
@@ -15,12 +24,12 @@ on:
test_list:
description: 'Base64 encoded list of tests (YML objects) to run. Example in run-automation-ondemand-e2e-tests.yml'
required: false
- type: string
+ type: string
test_workflow:
description: 'Run tests by workflow name. Example: "Run Nightly E2E Tests"'
required: false
type: string
- # TODO: Uncomment once Test Config does not have any secrets. Related ticket https://smartcontract-it.atlassian.net/browse/TT-1392
+ # TODO: Uncomment once Test Config does not have any secrets. Related ticket https://smartcontract-it.atlassian.net/browse/TT-1392
# test_config_override_base64:
# required: false
# description: The base64-encoded test config override
@@ -64,7 +73,30 @@ on:
description: 'Number of days to retain the test log. Default is 3 days'
required: false
type: number
- default: 3
+ default: 3
+ test_log_level:
+ description: 'Set the log level for the tests. Default is "debug"'
+ required: false
+ type: string
+ default: debug
+ upload_cl_node_coverage_artifact:
+ description: 'Set to "true" to upload Chainlink node coverage artifact to as Github artifact'
+ required: false
+ type: boolean
+ default: false
+ upload_cl_node_coverage_artifact_prefix:
+ description: 'Prefix for the Chainlink node coverage artifact'
+ required: false
+ type: string
+ enable_otel_traces_for_ocr2_plugins:
+ description: 'Set to "true" to enable OpenTelemetry traces for OCR2 plugins tests'
+ required: false
+ type: boolean
+ default: false
+ outputs:
+ test_results:
+ description: 'Test results from all executed tests'
+ value: ${{ jobs.after_tests.outputs.test_results }}
secrets:
TEST_SECRETS_OVERRIDE_BASE64:
required: false
@@ -89,25 +121,27 @@ on:
GRAFANA_INTERNAL_URL_SHORTENER_TOKEN:
required: true
GH_TOKEN:
- required: true
+ required: true
AWS_REGION:
required: true
AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN:
required: true
AWS_API_GW_HOST_GRAFANA:
- required: true
+ required: true
SLACK_BOT_TOKEN:
required: false
-
-env:
+
+env:
CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink
QA_CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink
- GITHUB_SHA_PLUGINS: ${{ github.sha }}-plugins
+ DEFAULT_CHAINLINK_VERSION: ${{ inputs.chainlink_version || github.sha }}
+ DEFAULT_CHAINLINK_PLUGINS_VERSION: ${{ inputs.chainlink_version != '' && format('{0}-plugins', inputs.chainlink_version) || format('{0}-plugins', github.sha) }}
CHAINLINK_ENV_USER: ${{ github.actor }}
CHAINLINK_COMMIT_SHA: ${{ inputs.evm-ref || github.sha }}
SELECTED_NETWORKS: SIMULATED
MOD_CACHE_VERSION: 1
- TEST_LOG_LEVEL: debug
+ TEST_LOG_LEVEL: ${{ inputs.test_log_level }}
+ METRICS_COLLECTION_ID: chainlink-e2e-tests
jobs:
validate-inputs:
@@ -127,7 +161,7 @@ jobs:
echo "Will run tests with custom test secrets"
fi
- name: Install jq
- run: sudo apt-get install jq
+ run: sudo apt-get install jq
- name: Create matrix for required Chainlink image versions
id: set-required-chainlink-image-versions-matrix
run: |
@@ -149,14 +183,17 @@ jobs:
needs: validate-inputs
runs-on: ubuntu-latest
steps:
- - name: Checkout code
+ - name: Checkout core
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- - name: Setup Go
- uses: ./.github/actions/setup-go
+ with:
+ fetch-depth: 0
+ path: core
+ - name: Install citool
+ shell: bash
+ run: go install github.com/smartcontractkit/chainlink-testing-framework/tools/citool@a49f2dff000fcf020ab9978b33e3726d7df5bf96 # v1.34.4
- name: Run Check Tests Command
run: |
- cd integration-tests/
- if ! go run citool/main.go check-tests . ../.github/e2e-tests.yml; then
+ if ! citool check-tests ${{ github.workspace }}/integration-tests ${{ github.workspace }}/.github/e2e-tests.yml; then
echo "::error::Some E2E test configurations have to be added to .github/e2e-tests.yml. This file defines Github CI configuration for each E2E test or set of E2E tests." && exit 1
fi
@@ -189,26 +226,31 @@ jobs:
run-k8s-tests: ${{ steps.check-matrices.outputs.run-k8s-tests }}
docker-matrix: ${{ steps.set-docker-matrix.outputs.matrix }}
k8s-runner-matrix: ${{ steps.set-k8s-runner-matrix.outputs.matrix }}
+ workflow_id: ${{ steps.gen_id.outputs.workflow_id }}
steps:
- name: Checkout code
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- name: Setup Go
- uses: ./.github/actions/setup-go
+ uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
+ with:
+ go-version: '1.22.6'
+ check-latest: true
+ - name: Install citool
+ shell: bash
+ run: go install github.com/smartcontractkit/chainlink-testing-framework/tools/citool@a49f2dff000fcf020ab9978b33e3726d7df5bf96 # v1.34.4
- name: Install jq
run: sudo apt-get install jq
- name: Generate Docker Tests Matrix
id: set-docker-matrix
run: |
- cd integration-tests/citool
- MATRIX_JSON=$(go run main.go filter --file ${{ github.workspace }}/.github/e2e-tests.yml --test-env-type 'docker' --test-list '${{ inputs.test_list }}' --test-ids '${{ inputs.test_ids }}' --workflow '${{ inputs.test_workflow }}')
+ MATRIX_JSON=$(citool filter --file ${{ github.workspace }}/.github/e2e-tests.yml --test-env-type 'docker' --test-list '${{ inputs.test_list }}' --test-ids '${{ inputs.test_ids }}' --workflow '${{ inputs.test_workflow }}')
echo "Docker tests:"
echo "$MATRIX_JSON" | jq
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
- name: Generate K8s Tests Matrix
id: set-k8s-runner-matrix
run: |
- cd integration-tests/citool
- MATRIX_JSON=$(go run main.go filter --file ${{ github.workspace }}/.github/e2e-tests.yml --test-env-type 'k8s-remote-runner' --test-list '${{ inputs.test_list }}' --test-ids '${{ inputs.test_ids }}' --workflow '${{ inputs.test_workflow }}')
+ MATRIX_JSON=$(citool filter --file ${{ github.workspace }}/.github/e2e-tests.yml --test-env-type 'k8s-remote-runner' --test-list '${{ inputs.test_list }}' --test-ids '${{ inputs.test_ids }}' --workflow '${{ inputs.test_workflow }}')
echo "K8s tests:"
echo "$MATRIX_JSON" | jq
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
@@ -301,6 +343,11 @@ jobs:
echo "No tests require secrets. Proceeding without additional secret setup."
fi
+ - name: Generate random workflow id
+ id: gen_id
+ run: echo "workflow_id=$(uuidgen)" >> $GITHUB_OUTPUT
+
+
# Build Chainlink images required for the tests
require-chainlink-image-versions-in-qa-ecr:
name: Build Chainlink image
@@ -328,11 +375,11 @@ jobs:
tag_suffix: ''
check_image_exists: 'true'
AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
# Build Chainlink plugins required for the tests
require-chainlink-plugin-versions-in-qa-ecr:
- name: Build Chainlink plugins
+ name: Build Chainlink plugins
needs: [validate-inputs, load-test-configurations]
if: ${{ needs.validate-inputs.outputs.require_chainlink_plugin_versions_in_qa_ecr_matrix != '' }}
runs-on: ubuntu-latest
@@ -357,14 +404,14 @@ jobs:
tag_suffix: '-plugins'
check_image_exists: 'true'
AWS_REGION: ${{ secrets.QA_AWS_REGION }}
- AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
+ AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
# Run Docker tests
run-docker-tests:
- name: Run ${{ matrix.tests.id }}
+ name: ${{ matrix.tests.id }}
needs: [load-test-configurations, require-chainlink-image-versions-in-qa-ecr, require-chainlink-plugin-versions-in-qa-ecr, get_latest_chainlink_release_version]
- # Run when none of the needed jobs fail or are cancelled (skipped or successful jobs are ok)
- if: ${{ needs.load-test-configurations.outputs.run-docker-tests == 'true' && always() && !failure() && !cancelled() }}
+ # Run when none of the needed jobs fail or are cancelled (skipped or successful jobs are ok)
+ if: ${{ needs.load-test-configurations.outputs.run-docker-tests == 'true' && always() && !failure() && !cancelled() }}
runs-on: ${{ matrix.tests.runs_on }}
strategy:
fail-fast: false
@@ -388,7 +435,7 @@ jobs:
org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
- this-job-name: Run E2E Tests / Run ${{ matrix.tests.id }}
+ this-job-name: ${{ inputs.workflow_name }} / ${{ matrix.tests.id }}
test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}'
continue-on-error: true
@@ -398,8 +445,7 @@ jobs:
run: sudo apt-get install -y jq
- name: Show test configuration
run: echo '${{ toJson(matrix.tests) }}' | jq .
- - name: Setup Go
- uses: ./.github/actions/setup-go
+
- name: Setup GAP for Grafana
uses: smartcontractkit/.github/actions/setup-gap@d316f66b2990ea4daa479daa3de6fc92b00f863e # setup-gap@0.3.2
id: setup-gap
@@ -409,32 +455,74 @@ jobs:
api-gateway-host: ${{ secrets.AWS_API_GW_HOST_GRAFANA }}
duplicate-authorization-header: "true"
+ - name: Setup Grafana and OpenTelemetry
+ id: docker-setup
+ if: inputs.enable_otel_traces_for_ocr2_plugins && matrix.tests.test_env_vars.ENABLE_OTEL_TRACES == 'true'
+ run: |
+ # Create network
+ docker network create --driver bridge tracing
+
+ # Make trace directory
+ cd integration-tests/smoke/
+ mkdir ./traces
+ chmod -R 777 ./traces
+
+ # Switch directory
+ cd ../../.github/tracing
+
+ # Create a Docker volume for traces
+ # docker volume create otel-traces
+
+ # Start OpenTelemetry Collector
+ # Note the user must be set to the same user as the runner for the trace data to be accessible
+ docker run -d --network=tracing --name=otel-collector \
+ -v $PWD/otel-collector-ci.yaml:/etc/otel-collector.yaml \
+ -v $PWD/../../integration-tests/smoke/traces:/tracing \
+ --user "$(id -u):$(id -g)" \
+ -p 4317:4317 otel/opentelemetry-collector:0.88.0 --config=/etc/otel-collector.yaml
+
- name: Run tests
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
+ id: run_tests
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c164251be2a7c5b2b23a6e5f7014982f232c14 # v2.3.32
env:
DETACH_RUNNER: true
+ E2E_TEST_CHAINLINK_VERSION: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_VERSION || inputs.chainlink_version || github.sha }}
+ E2E_TEST_CHAINLINK_UPGRADE_VERSION: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_UPGRADE_VERSION }}
+ E2E_TEST_CHAINLINK_POSTGRES_VERSION: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_POSTGRES_VERSION }}
+ E2E_TEST_SELECTED_NETWORK: ${{ matrix.tests.test_env_vars.E2E_TEST_SELECTED_NETWORK || env.SELECTED_NETWORKS }}
+ E2E_TEST_LOGGING_RUN_ID: ${{ github.run_id }}
+ E2E_TEST_LOG_STREAM_LOG_TARGETS: ${{ vars.LOGSTREAM_LOG_TARGETS }}
+ E2E_TEST_LOG_COLLECT: ${{ vars.TEST_LOG_COLLECT }}
+ E2E_TEST_CHAINLINK_IMAGE: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_IMAGE || env.CHAINLINK_IMAGE }}
+ E2E_TEST_CHAINLINK_UPGRADE_IMAGE: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_UPGRADE_IMAGE }}
+ E2E_TEST_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ E2E_TEST_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
+ E2E_TEST_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ E2E_TEST_GRAFANA_BASE_URL: "http://localhost:8080/primary"
+ E2E_TEST_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
+ E2E_TEST_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
+ E2E_TEST_PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }}
+ E2E_TEST_PYROSCOPE_SERVER_URL: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_INSTANCE || '' }}
+ E2E_TEST_PYROSCOPE_KEY: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_KEY || '' }}
+ E2E_TEST_PYROSCOPE_ENABLED: ${{ matrix.tests.pyroscope_env != '' && 'true' || '' }}
with:
test_command_to_run: ${{ matrix.tests.test_cmd }} 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
- test_download_vendor_packages_command: cd ./integration-tests && go mod download
+ test_download_vendor_packages_command: cd $(dirname ${{ matrix.tests.path }}) && go mod download
test_secrets_override_base64: ${{ secrets.TEST_SECRETS_OVERRIDE_BASE64 }}
- # TODO: Uncomment once Test Config does not have any secrets. Related ticket https://smartcontract-it.atlassian.net/browse/TT-1392
+ test_config_override_path: ${{ matrix.tests.test_config_override_path }}
+ # TODO: Uncomment once Test Config does not have any secrets. Related ticket https://smartcontract-it.atlassian.net/browse/TT-1392
# test_config_override_base64: ${{ inputs.test_config_override_base64 }}
- test_config_chainlink_version: ${{ matrix.tests.test_inputs.chainlink_version || inputs.chainlink_version || github.sha }}
- test_config_chainlink_upgrade_version: ${{ matrix.tests.test_inputs.chainlink_upgrade_version }}
- test_config_chainlink_postgres_version: ${{ matrix.tests.test_inputs.chainlink_postgres_version }}
- test_config_selected_networks: ${{ matrix.tests.test_inputs.selected_networks || env.SELECTED_NETWORKS}}
- test_config_logging_run_id: ${{ github.run_id }}
- test_config_logstream_log_targets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
- test_type: ${{ matrix.tests.test_inputs.test_type }}
- test_suite: ${{ matrix.tests.test_inputs.test_suite }}
+ test_type: ${{ matrix.tests.test_env_vars.TEST_TYPE }}
+ test_suite: ${{ matrix.tests.test_env_vars.TEST_SUITE }}
aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}
artifacts_name: ${{ matrix.tests.id_sanitized }}-test-logs
artifacts_location: |
./integration-tests/smoke/logs/
+ ./integration-tests/smoke/db_dumps/
/tmp/gotest.log
publish_check_name: ${{ matrix.tests.id_sanitized }}
token: ${{ secrets.GH_TOKEN }}
- no_cache: true # Do not restore cache since go was already configured in the previous step
+ cache_key_id: e2e-tests
go_mod_path: ./integration-tests/go.mod
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
@@ -442,19 +530,24 @@ jobs:
should_tidy: "false"
go_coverage_src_dir: /var/tmp/go-coverage
go_coverage_dest_dir: ${{ github.workspace }}/.covdata
- DEFAULT_CHAINLINK_IMAGE: ${{ matrix.tests.test_inputs.chainlink_image || env.CHAINLINK_IMAGE }}
- DEFAULT_CHAINLINK_UPGRADE_IMAGE: ${{ matrix.tests.test_inputs.chainlink_upgrade_image }}
- DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- DEFAULT_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
- DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
- DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
- DEFAULT_PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }}
- DEFAULT_PYROSCOPE_SERVER_URL: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_INSTANCE || '' }}
- DEFAULT_PYROSCOPE_KEY: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_KEY || '' }}
- DEFAULT_PYROSCOPE_ENABLED: ${{ matrix.tests.pyroscope_env != '' && 'true' || '' }}
+ - name: Show Otel-Collector logs
+ if: inputs.enable_otel_traces_for_ocr2_plugins && matrix.tests.test_env_vars.ENABLE_OTEL_TRACES == 'true'
+ run: |
+ docker logs otel-collector
+
+ - name: Permissions on traces
+ if: inputs.enable_otel_traces_for_ocr2_plugins && matrix.tests.test_env_vars.ENABLE_OTEL_TRACES == 'true'
+ run: |
+ ls -l ./integration-tests/smoke/traces
+
+ - name: Upload trace data as Github artifact
+ if: inputs.enable_otel_traces_for_ocr2_plugins && matrix.tests.test_env_vars.ENABLE_OTEL_TRACES == 'true'
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ with:
+ name: trace-data
+ path: ./integration-tests/smoke/traces/trace-data.json
+
- name: Upload test log as Github artifact
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
if: inputs.test_log_upload_on_failure && failure()
@@ -462,13 +555,42 @@ jobs:
name: test_log_${{ matrix.tests.id_sanitized }}
path: /tmp/gotest.log
retention-days: ${{ inputs.test_log_upload_retention_days }}
- continue-on-error: true
+ continue-on-error: true
+
+ - name: Upload cl node coverage data as Github artifact
+ if: inputs.upload_cl_node_coverage_artifact
+ uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
+ timeout-minutes: 2
+ continue-on-error: true
+ with:
+ name: ${{ inputs.upload_cl_node_coverage_artifact_prefix }}${{ matrix.tests.id_sanitized }}
+ path: .covdata
+ retention-days: 1
+
+ - name: Record test result
+ if: ${{ always() }}
+ run: |
+ id="${{ matrix.tests.id }}"
+ result="${{ steps.run_tests.outcome }}"
+ echo "{\"id\": \"$id\", \"result\": \"$result\"}" > test_result.json
+
+ - name: Upload test result as artifact
+ uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
+ with:
+ name: test_result_${{ needs.load-test-configurations.outputs.workflow_id }}_${{ matrix.tests.id_sanitized }}
+ path: test_result.json
+ retention-days: 1
+
+ - name: Print failed test summary
+ if: always()
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@70ccaef155381025e411cf7cd1fa5ef8f668ed75 # v2.3.25
+
# Run K8s tests using old remote runner
prepare-remote-runner-test-image:
needs: [load-test-configurations, require-chainlink-image-versions-in-qa-ecr, require-chainlink-plugin-versions-in-qa-ecr]
- if: ${{ needs.load-test-configurations.outputs.run-k8s-tests == 'true' && always() && !failure() && !cancelled() }}
+ if: ${{ needs.load-test-configurations.outputs.run-k8s-tests == 'true' && always() && !failure() && !cancelled() }}
name: Prepare remote runner test image
runs-on: ubuntu-latest
environment: integration
@@ -484,7 +606,7 @@ jobs:
ENV_JOB_IMAGE_BASE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests
steps:
- name: Checkout repository
- uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- name: Build Test Runner Image
uses: ./.github/actions/build-test-image
if: ${{ inputs.with_existing_remote_runner_version == '' }}
@@ -503,8 +625,8 @@ jobs:
run-k8s-runner-tests:
needs: [load-test-configurations, prepare-remote-runner-test-image, require-chainlink-image-versions-in-qa-ecr, require-chainlink-plugin-versions-in-qa-ecr, get_latest_chainlink_release_version]
- if: ${{ needs.load-test-configurations.outputs.run-k8s-tests == 'true' && always() && !failure() && !cancelled() }}
- name: Run ${{ matrix.tests.id }}
+ if: ${{ needs.load-test-configurations.outputs.run-k8s-tests == 'true' && always() && !failure() && !cancelled() }}
+ name: ${{ matrix.tests.id }}
runs-on: ${{ matrix.tests.runs_on }}
strategy:
fail-fast: false
@@ -517,7 +639,7 @@ jobs:
id-token: write
contents: read
env:
- LATEST_CHAINLINK_RELEASE_VERSION: ${{ needs.get_latest_chainlink_release_version.outputs.latest_chainlink_release_version }}
+ LATEST_CHAINLINK_RELEASE_VERSION: ${{ needs.get_latest_chainlink_release_version.outputs.latest_chainlink_release_version }}
steps:
- name: Collect Metrics
if: always()
@@ -528,7 +650,7 @@ jobs:
org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
- this-job-name: Run E2E Tests / Run ${{ matrix.tests.id }}
+ this-job-name: ${{ inputs.workflow_name }} / ${{ matrix.tests.id }}
continue-on-error: true
- name: Checkout repository
@@ -542,7 +664,8 @@ jobs:
echo "Remote Runner Version: ${{ needs.prepare-remote-runner-test-image.outputs.remote-runner-version }}"
- name: Run tests
- uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@aa8eea635029ab8d95abd3c206f56dae1e22e623 # v2.3.28
+ id: run_tests
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@00c164251be2a7c5b2b23a6e5f7014982f232c14 # v2.3.32
env:
DETACH_RUNNER: true
RR_MEM: ${{ matrix.tests.remote_runner_memory }}
@@ -552,86 +675,83 @@ jobs:
# We can comment these out when we have a stable soak test and aren't worried about resource consumption
TEST_UPLOAD_CPU_PROFILE: true
TEST_UPLOAD_MEM_PROFILE: true
- TEST_LOG_LEVEL: debug
REF_NAME: ${{ github.head_ref || github.ref_name }}
+ E2E_TEST_CHAINLINK_VERSION: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_VERSION || inputs.chainlink_version || github.sha }}
+ E2E_TEST_CHAINLINK_UPGRADE_VERSION: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_UPGRADE_VERSION }}
+ E2E_TEST_CHAINLINK_POSTGRES_VERSION: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_POSTGRES_VERSION }}
+ E2E_TEST_SELECTED_NETWORK: ${{ matrix.tests.test_env_vars.E2E_TEST_SELECTED_NETWORK || env.SELECTED_NETWORKS }}
+ E2E_TEST_LOGGING_RUN_ID: ${{ github.run_id }}
+ E2E_TEST_LOG_STREAM_LOG_TARGETS: ${{ vars.LOGSTREAM_LOG_TARGETS }}
+ E2E_TEST_LOG_COLLECT: ${{ vars.TEST_LOG_COLLECT }}
+ E2E_TEST_CHAINLINK_IMAGE: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_IMAGE || env.CHAINLINK_IMAGE }}
+ E2E_TEST_CHAINLINK_UPGRADE_IMAGE: ${{ matrix.tests.test_env_vars.E2E_TEST_CHAINLINK_UPGRADE_IMAGE }}
+ E2E_TEST_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ E2E_TEST_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
+ E2E_TEST_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ E2E_TEST_GRAFANA_BASE_URL: "http://localhost:8080/primary"
+ E2E_TEST_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
+ E2E_TEST_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
+ E2E_TEST_PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }}
+ E2E_TEST_PYROSCOPE_SERVER_URL: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_INSTANCE || '' }}
+ E2E_TEST_PYROSCOPE_KEY: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_KEY || '' }}
+ E2E_TEST_PYROSCOPE_ENABLED: ${{ matrix.tests.pyroscope_env != '' && 'true' || '' }}
with:
test_command_to_run: ${{ matrix.tests.test_cmd }} 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs
test_download_vendor_packages_command: make gomod
test_secrets_override_base64: ${{ secrets.TEST_SECRETS_OVERRIDE_BASE64 }}
- # TODO: Uncomment once Test Config does not have any secrets. Related ticket https://smartcontract-it.atlassian.net/browse/TT-1392
- # test_config_override_base64: ${{ inputs.test_config_override_base64 }}
- test_config_chainlink_version: ${{ matrix.tests.test_inputs.chainlink_version || inputs.chainlink_version || github.sha }}
- test_config_chainlink_upgrade_version: ${{ matrix.tests.test_inputs.chainlink_upgrade_version }}
- test_config_chainlink_postgres_version: ${{ matrix.tests.test_inputs.chainlink_postgres_version }}
- test_config_selected_networks: ${{ matrix.tests.test_inputs.selected_networks || env.SELECTED_NETWORKS}}
- test_config_logging_run_id: ${{ github.run_id }}
- test_config_logstream_log_targets: ${{ vars.LOGSTREAM_LOG_TARGETS }}
- test_type: ${{ matrix.tests.test_inputs.test_type }}
- test_suite: ${{ matrix.tests.test_inputs.test_suite }}
+ test_type: ${{ matrix.tests.test_env_vars.TEST_TYPE }}
+ test_suite: ${{ matrix.tests.test_env_vars.TEST_SUITE }}
token: ${{ secrets.GH_TOKEN }}
should_cleanup: false
- no_cache: true # Do not restore cache since go was already configured in the previous step
+ cache_key_id: e2e-tests
go_mod_path: ./integration-tests/go.mod
QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }}
QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }}
- QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
- DEFAULT_CHAINLINK_IMAGE: ${{ matrix.tests.test_inputs.chainlink_image || env.CHAINLINK_IMAGE }}
- DEFAULT_CHAINLINK_UPGRADE_IMAGE: ${{ matrix.tests.test_inputs.chainlink_upgrade_image }}
- DEFAULT_LOKI_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
- DEFAULT_LOKI_ENDPOINT: https://${{ secrets.GRAFANA_INTERNAL_HOST }}/loki/api/v1/push
- DEFAULT_LOKI_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
- DEFAULT_GRAFANA_BASE_URL: "http://localhost:8080/primary"
- DEFAULT_GRAFANA_DASHBOARD_URL: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs"
- DEFAULT_GRAFANA_BEARER_TOKEN: ${{ secrets.GRAFANA_INTERNAL_URL_SHORTENER_TOKEN }}
- DEFAULT_PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }}
- DEFAULT_PYROSCOPE_SERVER_URL: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_INSTANCE || '' }}
- DEFAULT_PYROSCOPE_KEY: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_KEY || '' }}
- DEFAULT_PYROSCOPE_ENABLED: ${{ matrix.tests.pyroscope_env != '' && 'true' || '' }}
-
+ QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }}
+
- name: Upload test log as Github artifact
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
if: inputs.test_log_upload_on_failure && failure()
with:
name: test_log_${{ matrix.tests.id_sanitized }}
path: /tmp/gotest.log
retention-days: ${{ inputs.test_log_upload_retention_days }}
- continue-on-error: true
+ continue-on-error: true
+
+ # TODO: move to run-tests GHA
+ - name: Print failed test summary
+ if: always()
+ uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@70ccaef155381025e411cf7cd1fa5ef8f668ed75 # v2.3.25
after_tests:
- needs: [run-docker-tests, run-k8s-runner-tests]
+ needs: [load-test-configurations, run-docker-tests, run-k8s-runner-tests]
if: always()
- name: After tests notifications
+ name: After tests
runs-on: ubuntu-latest
+ outputs:
+ test_results: ${{ steps.set_test_results.outputs.results }}
steps:
- - name: Determine combined test results
- id: combine_results
+ - name: Download all test result artifacts
+ uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
+ with:
+ path: test_results
+ pattern: test_result_${{ needs.load-test-configurations.outputs.workflow_id }}_*
+
+ - name: Set detailed test results
+ id: set_test_results
run: |
- docker_result="${{ needs.run-docker-tests.result }}"
- k8s_result="${{ needs.run-k8s-runner-tests.result }}"
-
- function map_outcome {
- case "$1" in
- success|skipped)
- echo "success"
- ;;
- cancelled)
- echo "cancelled"
- ;;
- *)
- echo "failure"
- ;;
- esac
- }
-
- combined_docker_result=$(map_outcome $docker_result)
- combined_k8s_result=$(map_outcome $k8s_result)
-
- if [[ $combined_docker_result == "failure" || $combined_k8s_result == "failure" ]]; then
- echo "result=failure" >> $GITHUB_OUTPUT
- elif [[ $combined_docker_result == "cancelled" || $combined_k8s_result == "cancelled" ]]; then
- echo "result=cancelled" >> $GITHUB_OUTPUT
+ if [ -d "test_results" ]; then
+ cd test_results
+ ls -R .
+ # Combine JSON files into one
+ find . -name '*.json' -exec cat {} + | jq -s '.' > test_results.json
+ # Display the combined JSON
+ jq . test_results.json
+ # Set the combined results as an output
+ echo "results=$(jq -c . test_results.json)" >> $GITHUB_OUTPUT
else
- echo "result=success" >> $GITHUB_OUTPUT
+ echo "No test results directory found."
+ echo "results=[]" >> $GITHUB_OUTPUT
fi
- name: Send Slack notification
@@ -649,7 +769,7 @@ jobs:
"type": "section",
"text": {
"type": "mrkdwn",
- "text": "${{ inputs.slack_notification_after_tests_name }} - ${{ steps.combine_results.outputs.result == 'failure' && 'Failed :x:' || steps.combine_results.outputs.result == 'cancelled' && 'Cancelled :warning:' || 'Passed :white_check_mark:' }}"
+ "text": "${{ inputs.slack_notification_after_tests_name }} - ${{ contains(join(needs.*.result, ','), 'failure') && 'Failed :x:' || contains(join(needs.*.result, ','), 'cancelled') && 'Cancelled :warning:' || 'Passed :white_check_mark:' }}"
}
},
{
@@ -670,12 +790,12 @@ jobs:
# steps:
# - name: Checkout repository
# uses: actions/checkout@v2
-
+
# - name: Set up Go
# uses: actions/setup-go@v2
# with:
# go-version: '1.18'
-
+
# - name: Load Runner Config
# run: echo "$RUNNER_CONFIG" > runner.toml
# env:
@@ -683,7 +803,7 @@ jobs:
# # Runner configuration
# detached_mode = true
# debug = false
-
+
# [[test_runs]]
# namespace = "dev-env"
# rbac_role_name = "dev-role"
@@ -708,7 +828,7 @@ jobs:
# WASP_LOG_LEVEL = "info"
# TEST_LOG_LEVEL = "info"
# MERCURY_TEST_LOG_LEVEL = "info"
-
+
# [[test_runs]]
# namespace = "prod-env"
# rbac_role_name = "prod-role"
@@ -733,7 +853,7 @@ jobs:
# WASP_LOG_LEVEL = "info"
# TEST_LOG_LEVEL = "info"
# MERCURY_TEST_LOG_LEVEL = "info"
-
+
# # Schedule the tests in K8s in remote runner
# - name: Run Kubernetes Tests
- # run: go run ./cmd/main.go run -c runner.toml
\ No newline at end of file
+ # run: go run ./cmd/main.go run -c runner.toml
diff --git a/.github/workflows/run-nightly-e2e-tests.yml b/.github/workflows/run-nightly-e2e-tests.yml
index ab12b36555f..6d7056ed04d 100644
--- a/.github/workflows/run-nightly-e2e-tests.yml
+++ b/.github/workflows/run-nightly-e2e-tests.yml
@@ -12,7 +12,7 @@ jobs:
uses: ./.github/workflows/run-e2e-tests-reusable-workflow.yml
with:
chainlink_version: develop
- test_workflow: Run Nightly E2E Tests
+ test_workflow: Nightly E2E Tests
slack_notification_after_tests: true
slack_notification_after_tests_channel_id: "#team-test-tooling-internal"
slack_notification_after_tests_name: Nightly E2E Tests
diff --git a/.github/workflows/solidity-foundry-artifacts.yml b/.github/workflows/solidity-foundry-artifacts.yml
new file mode 100644
index 00000000000..9bba72b2e4c
--- /dev/null
+++ b/.github/workflows/solidity-foundry-artifacts.yml
@@ -0,0 +1,390 @@
+name: Solidity Foundry Artifact Generation
+on:
+ workflow_dispatch:
+ inputs:
+ product:
+ type: choice
+ description: 'product for which to generate artifacts; should be the same as Foundry profile'
+ required: true
+ options:
+ - "automation"
+ - "ccip"
+ - "functions"
+ - "keystone"
+ - "l2ep"
+ - "liquiditymanager"
+ - "llo-feeds"
+ - "operatorforwarder"
+ - "shared"
+ - "transmission"
+ - "vrf"
+ commit_to_use:
+ type: string
+ description: 'commit SHA to use for artifact generation; if empty HEAD will be used'
+ required: false
+ base_ref:
+ description: 'commit or tag to use as base reference, when looking for modified Solidity files'
+ required: true
+
+env:
+ FOUNDRY_PROFILE: ci
+
+jobs:
+ changes:
+ name: Detect changes
+ runs-on: ubuntu-latest
+ outputs:
+ changes: ${{ steps.changes.outputs.sol }}
+ product_changes: ${{ steps.changes-transform.outputs.product_changes }}
+ product_files: ${{ steps.changes-transform.outputs.product_files }}
+ changeset_changes: ${{ steps.changes-dorny.outputs.changeset }}
+ changeset_files: ${{ steps.changes-dorny.outputs.changeset_files }}
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ with:
+ ref: ${{ inputs.commit_to_use || github.sha }}
+ - name: Find modified contracts
+ uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
+ id: changes
+ with:
+ list-files: 'csv'
+ base: ${{ inputs.base_ref }}
+ predicate-quantifier: every
+ filters: |
+ ignored: &ignored
+ - '!contracts/src/v0.8/**/test/**'
+ - '!contracts/src/v0.8/**/tests/**'
+ - '!contracts/src/v0.8/**/mock/**'
+ - '!contracts/src/v0.8/**/mocks/**'
+ - '!contracts/src/v0.8/**/*.t.sol'
+ - '!contracts/src/v0.8/*.t.sol'
+ - '!contracts/src/v0.8/**/testhelpers/**'
+ - '!contracts/src/v0.8/testhelpers/**'
+ - '!contracts/src/v0.8/vendor/**'
+ other_shared:
+ - modified|added: 'contracts/src/v0.8/(interfaces/**/*.sol|*.sol)'
+ - *ignored
+ sol:
+ - modified|added: 'contracts/src/v0.8/**/*.sol'
+ - *ignored
+ product: &product
+ - modified|added: 'contracts/src/v0.8/${{ inputs.product }}/**/*.sol'
+ - *ignored
+ changeset:
+ - modified|added: 'contracts/.changeset/!(README)*.md'
+
+ # Manual transformation needed, because shared contracts have a different folder structure
+ - name: Transform modified files
+ id: changes-transform
+ shell: bash
+ run: |
+ if [ "${{ inputs.product }}" = "shared" ]; then
+ echo "::debug:: Product is shared, transforming changes"
+ if [[ "${{ steps.changes.outputs.product }}" == "true" && "${{ steps.changes.outputs.other_shared }}" == "true" ]]; then
+ echo "::debug:: Changes were found in 'shared' folder and in 'interfaces' and root folders"
+ echo "product_changes=true" >> $GITHUB_OUTPUT
+ echo "product_files=${{ steps.changes.outputs.product_files }},${{ steps.changes.outputs.other_shared_files }}" >> $GITHUB_OUTPUT
+ elif [[ "${{ steps.changes.outputs.product }}" == "false" && "${{ steps.changes.outputs.other_shared }}" == "true" ]]; then
+ echo "::debug:: Only contracts in' interfaces' and root folders were modified"
+ echo "product_changes=true" >> $GITHUB_OUTPUT
+ echo "product_files=${{ steps.changes.outputs.other_shared_files }}" >> $GITHUB_OUTPUT
+ elif [[ "${{ steps.changes.outputs.product }}" == "true" && "${{ steps.changes.outputs.other_shared }}" == "false" ]]; then
+ echo "::debug:: Only contracts in 'shared' folder were modified"
+ echo "product_changes=true" >> $GITHUB_OUTPUT
+ echo "product_files=${{ steps.changes.outputs.product_files }}" >> $GITHUB_OUTPUT
+ else
+ echo "::debug:: No contracts were modified"
+ echo "product_changes=false" >> $GITHUB_OUTPUT
+ echo "product_files=" >> $GITHUB_OUTPUT
+ fi
+ else
+ echo "product_changes=${{ steps.changes.outputs.product }}" >> $GITHUB_OUTPUT
+ echo "product_files=${{ steps.changes.outputs.product_files }}" >> $GITHUB_OUTPUT
+ fi
+
+ - name: Check for changes outside of artifact scope
+ uses: ./.github/actions/validate-artifact-scope
+ if: ${{ steps.changes.outputs.sol == 'true' }}
+ with:
+ sol_files: ${{ steps.changes.outputs.sol_files }}
+ product: ${{ inputs.product }}
+
+ gather-basic-info:
+ name: Gather basic info
+ if: ${{ needs.changes.outputs.product_changes == 'true' }}
+ runs-on: ubuntu-22.04
+ needs: [ changes ]
+ outputs:
+ foundry_version: ${{ steps.extract-foundry-version.outputs.foundry-version }}
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ with:
+ fetch-depth: 0
+
+ - name: Extract Foundry version
+ id: extract-foundry-version
+ uses: ./.github/actions/detect-solidity-foundry-version
+ with:
+ working-directory: contracts
+
+ - name: Copy modified changesets
+ if: ${{ needs.changes.outputs.changeset_changes == 'true' }}
+ run: |
+ mkdir -p contracts/changesets
+ files="${{ needs.changes.outputs.changeset_files }}"
+ IFS=",'
+ for changeset in $files; do
+ echo "::debug:: Copying $changeset"
+ cp $changeset contracts/changesets
+ done
+
+ - name: Generate basic info and modified contracts list
+ shell: bash
+ run: |
+ echo "Product: ${{ inputs.product }}" > contracts/commit_sha_base_ref.txt
+ echo "Commit SHA used to generate artifacts: ${{ inputs.commit_to_use || github.sha }}" >> contracts/commit_sha_base_ref.txt
+ echo "Base reference SHA used to find modified contracts: ${{ inputs.base_ref }}" >> contracts/commit_sha_base_ref.txt
+
+ IFS=',' read -r -a modified_files <<< "${{ needs.changes.outputs.product_files }}"
+ echo "# Modified contracts:" > contracts/modified_contracts.md
+ for file in "${modified_files[@]}"; do
+ echo " - [$file](${{ github.server_url }}/${{ github.repository }}/blob/${{ inputs.commit_to_use || github.sha }}/$file)" >> contracts/modified_contracts.md
+ echo "$file" >> contracts/modified_contracts.txt
+ done
+
+ - name: Upload basic info and modified contracts list
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ timeout-minutes: 2
+ continue-on-error: true
+ with:
+ name: tmp-basic-info
+ path: |
+ contracts/modified_contracts.md
+ contracts/modified_contracts.txt
+ contracts/commit_sha_base_ref.txt
+ contracts/changesets
+ retention-days: 7
+
+ # some of the artifacts can only be generated on product level, and we cannot scope them to single contracts
+ # some product-level modifications might also require shared contracts changes, so if these happened we need to generate artifacts for shared contracts as well
+ coverage-and-book:
+ if: ${{ needs.changes.outputs.product_changes == 'true' }}
+ name: Generate Docs and Code Coverage reports
+ runs-on: ubuntu-22.04
+ needs: [changes, gather-basic-info]
+ steps:
+ - name: Prepare exclusion list
+ id: prepare-exclusion-list
+ run: |
+ cat < coverage_exclusions.json
+ ["automation", "functions", "vrf"]
+ EOF
+ coverage_exclusions=$(cat coverage_exclusions.json | jq -c .)
+ echo "coverage_exclusions=$coverage_exclusions" >> $GITHUB_OUTPUT
+
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ with:
+ ref: ${{ inputs.commit_to_use || github.sha }}
+
+ - name: Setup NodeJS
+ uses: ./.github/actions/setup-nodejs
+
+ - name: Create directories
+ shell: bash
+ run: |
+ mkdir -p contracts/code-coverage
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@8f1998e9878d786675189ef566a2e4bf24869773 # v1.2.0
+ with:
+ version: ${{ needs.gather-basic-info.outputs.foundry_version }}
+
+ # required for code coverage report generation
+ - name: Setup LCOV
+ uses: hrishikesh-kadam/setup-lcov@f5da1b26b0dcf5d893077a3c4f29cf78079c841d # v1.0.0
+
+ - name: Run Forge build for product contracts
+ if: ${{ needs.changes.outputs.product_changes == 'true' }}
+ run: |
+ forge --version
+ forge build
+ working-directory: contracts
+ env:
+ FOUNDRY_PROFILE: ${{ inputs.product }}
+
+ - name: Run coverage for product contracts
+ if: ${{ !contains(fromJson(steps.prepare-exclusion-list.outputs.coverage_exclusions), inputs.product) && needs.changes.outputs.product_changes == 'true' }}
+ working-directory: contracts
+ run: forge coverage --report lcov --report-file code-coverage/lcov.info
+ env:
+ FOUNDRY_PROFILE: ${{ inputs.product }}
+
+ - name: Prune lcov report
+ if: ${{ !contains(fromJson(steps.prepare-exclusion-list.outputs.coverage_exclusions), inputs.product) && needs.changes.outputs.product_changes == 'true' }}
+ shell: bash
+ working-directory: contracts
+ run: |
+ ./scripts/lcov_prune ${{ inputs.product }} ./code-coverage/lcov.info ./code-coverage/lcov.info.pruned
+
+ - name: Generate Code Coverage HTML report for product contracts
+ if: ${{ !contains(fromJson(steps.prepare-exclusion-list.outputs.coverage_exclusions), inputs.product) && needs.changes.outputs.product_changes == 'true' }}
+ shell: bash
+ working-directory: contracts
+ run: genhtml code-coverage/lcov.info.pruned --branch-coverage --output-directory code-coverage
+
+ - name: Run Forge doc for product contracts
+ if: ${{ needs.changes.outputs.product_changes == 'true' }}
+ run: forge doc --build -o docs
+ working-directory: contracts
+ env:
+ FOUNDRY_PROFILE: ${{ inputs.product }}
+
+ - name: Upload Artifacts for product contracts
+ if: ${{ needs.changes.outputs.product_changes == 'true' }}
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ timeout-minutes: 2
+ continue-on-error: true
+ with:
+ name: tmp-${{ inputs.product }}-artifacts
+ path: |
+ contracts/docs
+ contracts/code-coverage/lcov-.info
+ contracts/code-coverage
+ retention-days: 7
+
+ # Generates UML diagrams and Slither reports for modified contracts
+ uml-static-analysis:
+ if: ${{ needs.changes.outputs.product_changes == 'true' }}
+ name: Generate UML and Slither reports for modified contracts
+ runs-on: ubuntu-22.04
+ needs: [changes, gather-basic-info]
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ with:
+ fetch-depth: 0
+ ref: ${{ inputs.commit_to_use || github.sha }}
+
+ - name: Setup NodeJS
+ uses: ./.github/actions/setup-nodejs
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@8f1998e9878d786675189ef566a2e4bf24869773 # v1.2.0
+ with:
+ version: ${{ needs.gather-basic-info.outputs.foundry_version }}
+
+ - name: Install Sol2uml
+ run: |
+ npm link sol2uml --only=production
+
+ - name: Set up Python
+ uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f #v5.1.1
+ with:
+ python-version: '3.8'
+
+ - name: Install solc-select and solc
+ uses: ./.github/actions/setup-solc-select
+ with:
+ to_install: '0.8.19'
+ to_use: '0.8.19'
+
+ - name: Install Slither
+ uses: ./.github/actions/setup-slither
+
+ - name: Generate UML
+ shell: bash
+ run: |
+ contract_list="${{ needs.changes.outputs.product_files }}"
+
+ # modify remappings so that solc can find dependencies
+ ./contracts/scripts/ci/modify_remappings.sh contracts contracts/remappings.txt
+ mv remappings_modified.txt remappings.txt
+
+ ./contracts/scripts/ci/generate_uml.sh "./" "contracts/uml-diagrams" "$contract_list"
+
+ - name: Generate Slither Markdown reports
+ run: |
+ contract_list="${{ needs.changes.outputs.product_files }}"
+
+ echo "::debug::Processing contracts: $contract_list"
+ ./contracts/scripts/ci/generate_slither_report.sh "${{ github.server_url }}/${{ github.repository }}/blob/${{ inputs.commit_to_use || github.sha }}/" contracts/configs/slither/.slither.config-artifacts.json "." "$contract_list" "contracts/slither-reports" "--solc-remaps @=contracts/node_modules/@"
+
+ - name: Upload UMLs and Slither reports
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ timeout-minutes: 10
+ continue-on-error: true
+ with:
+ name: tmp-contracts-artifacts
+ path: |
+ contracts/uml-diagrams
+ contracts/slither-reports
+ retention-days: 7
+
+ - name: Validate if all Slither run for all contracts
+ uses: ./.github/actions/validate-solidity-artifacts
+ with:
+ validate_slither_reports: 'true'
+ validate_uml_diagrams: 'true'
+ slither_reports_path: 'contracts/slither-reports'
+ uml_diagrams_path: 'contracts/uml-diagrams'
+ sol_files: ${{ needs.changes.outputs.product_files }}
+
+ gather-all-artifacts:
+ name: Gather all artifacts
+ if: ${{ needs.changes.outputs.product_changes == 'true' }}
+ runs-on: ubuntu-latest
+ needs: [coverage-and-book, uml-static-analysis, gather-basic-info, changes]
+ steps:
+ - name: Download all artifacts
+ uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
+ with:
+ path: review_artifacts
+ merge-multiple: true
+
+ - name: Upload all artifacts as single package
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ with:
+ name: review-artifacts-${{ inputs.product }}-${{ inputs.commit_to_use || github.sha }}
+ path: review_artifacts
+ retention-days: 60
+
+ - name: Remove temporary artifacts
+ uses: geekyeggo/delete-artifact@24928e75e6e6590170563b8ddae9fac674508aa1 # v5.0
+ with:
+ name: tmp-*
+
+ - name: Print Artifact URL in job summary
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ ARTIFACTS=$(gh api -X GET repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts)
+ ARTIFACT_ID=$(echo "$ARTIFACTS" | jq '.artifacts[] | select(.name=="review-artifacts-${{ inputs.product }}-${{ inputs.commit_to_use || github.sha }}") | .id')
+ echo "Artifact ID: $ARTIFACT_ID"
+
+ echo "# Solidity Review Artifact Generated" >> $GITHUB_STEP_SUMMARY
+ echo "Product: **${{ inputs.product }}**" >> $GITHUB_STEP_SUMMARY
+ echo "Base Ref used: **${{ inputs.base_ref }}**" >> $GITHUB_STEP_SUMMARY
+ echo "Commit SHA used: **${{ inputs.commit_to_use || github.sha }}**" >> $GITHUB_STEP_SUMMARY
+ echo "[Artifact URL](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/$ARTIFACT_ID)" >> $GITHUB_STEP_SUMMARY
+
+ notify-no-changes:
+ if: ${{ needs.changes.outputs.product_changes == 'false' }}
+ needs: [changes]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Print warning in job summary
+ shell: bash
+ run: |
+ echo "# Solidity Review Artifact NOT Generated" >> $GITHUB_STEP_SUMMARY
+ echo "Base Ref used: **${{ inputs.base_ref }}**" >> $GITHUB_STEP_SUMMARY
+ echo "Commit SHA used: **${{ inputs.commit_to_use || github.sha }}**" >> $GITHUB_STEP_SUMMARY
+ echo "## Reason: No modified Solidity files found for ${{ inputs.product }}" >> $GITHUB_STEP_SUMMARY
+ echo "* no modified Solidity files found between ${{ inputs.base_ref }} and ${{ inputs.commit_to_use || github.sha }} commits" >> $GITHUB_STEP_SUMMARY
+ echo "* or they are located outside of ./contracts/src/v0.8 folder" >> $GITHUB_STEP_SUMMARY
+ echo "* or they were limited to test files" >> $GITHUB_STEP_SUMMARY
+ exit 1
diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml
index a7ced0f5653..ef643e32e87 100644
--- a/.github/workflows/solidity-foundry.yml
+++ b/.github/workflows/solidity-foundry.yml
@@ -4,39 +4,130 @@ on: [pull_request]
env:
FOUNDRY_PROFILE: ci
+# Making changes:
+# * use the top-level matrix to decide, which checks should run for each product.
+# * when enabling code coverage, remember to adjust the minimum code coverage as it's set to 98.5% by default.
+
+# This pipeline will run product tests only if product-specific contracts were modified or if broad-impact changes were made (e.g. changes to this pipeline, Foundry configuration, etc.)
+# For modified contracts we use a LLM to extract new issues introduced by the changes. For new contracts full report is delivered.
+# Slither has a default configuration, but also supports per-product configuration. If a product-specific configuration is not found, the default one is used.
+# Changes to test files do not trigger static analysis or formatting checks.
+
jobs:
+ define-matrix:
+ name: Define test matrix
+ runs-on: ubuntu-latest
+ outputs:
+ matrix: ${{ steps.define-matrix.outputs.matrix }}
+ foundry-version: ${{ steps.extract-foundry-version.outputs.foundry-version }}
+ steps:
+ - name: Define test matrix
+ id: define-matrix
+ shell: bash
+ run: |
+ cat < matrix.json
+ [
+ { "name": "automation", "setup": { "run-coverage": false, "min-coverage": 98.5, "run-gas-snapshot": false, "run-forge-fmt": false }},
+ { "name": "ccip", "setup": { "run-coverage": true, "min-coverage": 98.5, "run-gas-snapshot": true, "run-forge-fmt": true }},
+ { "name": "functions", "setup": { "run-coverage": false, "min-coverage": 98.5, "run-gas-snapshot": true, "run-forge-fmt": false }},
+ { "name": "keystone", "setup": { "run-coverage": true, "min-coverage": 74.1, "run-gas-snapshot": false, "run-forge-fmt": false }},
+ { "name": "l2ep", "setup": { "run-coverage": true, "min-coverage": 65.6, "run-gas-snapshot": true, "run-forge-fmt": false }},
+ { "name": "liquiditymanager", "setup": { "run-coverage": true, "min-coverage": 46.3, "run-gas-snapshot": true, "run-forge-fmt": false }},
+ { "name": "llo-feeds", "setup": { "run-coverage": true, "min-coverage": 49.3, "run-gas-snapshot": true, "run-forge-fmt": false }},
+ { "name": "operatorforwarder", "setup": { "run-coverage": true, "min-coverage": 55.7, "run-gas-snapshot": true, "run-forge-fmt": false }},
+ { "name": "shared", "setup": { "run-coverage": true, "min-coverage": 32.6, "run-gas-snapshot": true, "run-forge-fmt": false }},
+ { "name": "transmission", "setup": { "run-coverage": true, "min-coverage": 65.6, "run-gas-snapshot": true, "run-forge-fmt": false }},
+ { "name": "vrf", "setup": { "run-coverage": false, "min-coverage": 98.5, "run-gas-snapshot": false, "run-forge-fmt": false }}
+ ]
+ EOF
+
+ matrix=$(cat matrix.json | jq -c .)
+ echo "matrix=$matrix" >> $GITHUB_OUTPUT
+
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+
+ - name: Extract Foundry version
+ id: extract-foundry-version
+ uses: ./.github/actions/detect-solidity-foundry-version
+ with:
+ working-directory: contracts
+
changes:
name: Detect changes
runs-on: ubuntu-latest
outputs:
- changes: ${{ steps.changes.outputs.src }}
+ non_src_changes: ${{ steps.changes.outputs.non_src }}
+ sol_modified_added: ${{ steps.changes.outputs.sol }}
+ sol_modified_added_files: ${{ steps.changes.outputs.sol_files }}
+ sol_mod_only: ${{ steps.changes.outputs.sol_mod_only }}
+ sol_mod_only_files: ${{ steps.changes.outputs.sol_mod_only_files }}
+ not_test_sol_modified: ${{ steps.changes.outputs.not_test_sol }}
+ not_test_sol_modified_files: ${{ steps.changes.outputs.not_test_sol_files }}
+ all_changes: ${{ steps.changes.outputs.changes }}
steps:
- name: Checkout the repo
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: changes
with:
+ list-files: 'shell'
filters: |
- src:
- - 'contracts/src/v0.8/**/*'
- - '.github/workflows/solidity-foundry.yml'
+ non_src:
+ - '.github/workflows/solidity-foundry.yml'
- 'contracts/foundry.toml'
- 'contracts/gas-snapshots/*.gas-snapshot'
+ - 'contracts/package.json'
+ sol:
+ - modified|added: 'contracts/src/v0.8/**/*.sol'
+ sol_mod_only:
+ - modified: 'contracts/src/v0.8/**/!(tests|mocks)/!(*.t).sol'
+ not_test_sol:
+ - modified|added: 'contracts/src/v0.8/**/!(tests|mocks)/!(*.t).sol'
+ automation:
+ - 'contracts/src/v0.8/automation/**/*.sol'
+ ccip:
+ - 'contracts/src/v0.8/ccip/**/*.sol'
+ functions:
+ - 'contracts/src/v0.8/functions/**/*.sol'
+ keystone:
+ - 'contracts/src/v0.8/keystone/**/*.sol'
+ l2ep:
+ - 'contracts/src/v0.8/l2ep/**/*.sol'
+ liquiditymanager:
+ - 'contracts/src/v0.8/liquiditymanager/**/*.sol'
+ llo-feeds:
+ - 'contracts/src/v0.8/llo-feeds/**/*.sol'
+ operatorforwarder:
+ - 'contracts/src/v0.8/operatorforwarder/**/*.sol'
+ vrf:
+ - 'contracts/src/v0.8/vrf/**/*.sol'
+ shared:
+ - 'contracts/src/v0.8/shared/**/*.sol'
+ - 'contracts/src/v0.8/*.sol'
+ - 'contracts/src/v0.8/mocks/**/*.sol'
+ - 'contracts/src/v0.8/tests/**/*.sol'
+ - 'contracts/src/v0.8/vendor/**/*.sol'
+ transmission:
+ - 'contracts/src/v0.8/transmission/**/*.sol'
tests:
+ if: ${{ needs.changes.outputs.non_src_changes == 'true' || needs.changes.outputs.sol_modified_added == 'true' }}
strategy:
fail-fast: false
matrix:
- product: [automation, functions, keystone, l2ep, llo-feeds, operatorforwarder, shared, vrf]
- needs: [changes]
- name: Foundry Tests ${{ matrix.product }}
- # See https://github.com/foundry-rs/foundry/issues/3827
+ product: ${{fromJson(needs.define-matrix.outputs.matrix)}}
+ needs: [define-matrix, changes]
+ name: Foundry Tests ${{ matrix.product.name }}
runs-on: ubuntu-22.04
# The if statements for steps after checkout repo is workaround for
# passing required check for PRs that don't have filtered changes.
steps:
- name: Checkout the repo
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true' }}
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
submodules: recursive
@@ -45,52 +136,423 @@ jobs:
# and not native Foundry. This is to make sure the dependencies
# stay in sync.
- name: Setup NodeJS
- if: needs.changes.outputs.changes == 'true'
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true' }}
uses: ./.github/actions/setup-nodejs
- name: Install Foundry
- if: needs.changes.outputs.changes == 'true'
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true' }}
uses: foundry-rs/foundry-toolchain@8f1998e9878d786675189ef566a2e4bf24869773 # v1.2.0
with:
- # Has to match the `make foundry` version.
- version: nightly-de33b6af53005037b463318d2628b5cfcaf39916
+ version: ${{ needs.define-matrix.outputs.foundry-version }}
- name: Run Forge build
- if: needs.changes.outputs.changes == 'true'
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true' }}
run: |
forge --version
forge build
id: build
working-directory: contracts
env:
- FOUNDRY_PROFILE: ${{ matrix.product }}
+ FOUNDRY_PROFILE: ${{ matrix.product.name }}
- name: Run Forge tests
- if: needs.changes.outputs.changes == 'true'
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true' }}
run: |
forge test -vvv
id: test
working-directory: contracts
env:
- FOUNDRY_PROFILE: ${{ matrix.product }}
+ FOUNDRY_PROFILE: ${{ matrix.product.name }}
- name: Run Forge snapshot
- if: ${{ !contains(fromJson('["vrf"]'), matrix.product) && !contains(fromJson('["automation"]'), matrix.product) && !contains(fromJson('["keystone"]'), matrix.product) && needs.changes.outputs.changes == 'true' }}
+ if: ${{ (contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true')
+ && matrix.product.setup.run-gas-snapshot }}
run: |
- forge snapshot --nmt "testFuzz_\w{1,}?" --check gas-snapshots/${{ matrix.product }}.gas-snapshot
+ forge snapshot --nmt "test_?Fuzz_\w{1,}?" --check gas-snapshots/${{ matrix.product.name }}.gas-snapshot
id: snapshot
working-directory: contracts
env:
- FOUNDRY_PROFILE: ${{ matrix.product }}
+ FOUNDRY_PROFILE: ${{ matrix.product.name }}
+
+ # required for code coverage report generation
+ - name: Setup LCOV
+ if: ${{ (contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true')
+ && matrix.product.setup.run-coverage }}
+ uses: hrishikesh-kadam/setup-lcov@f5da1b26b0dcf5d893077a3c4f29cf78079c841d # v1.0.0
+
+ - name: Run coverage for ${{ matrix.product.name }}
+ if: ${{ (contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true')
+ && matrix.product.setup.run-coverage }}
+ working-directory: contracts
+ run: forge coverage --report lcov
+ env:
+ FOUNDRY_PROFILE: ${{ matrix.product.name }}
+
+ - name: Prune lcov report
+ if: ${{ (contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true')
+ && matrix.product.setup.run-coverage }}
+ run: |
+ ./contracts/scripts/lcov_prune ${{ matrix.product.name }} ./contracts/lcov.info ./contracts/lcov.info.pruned
+
+ - name: Report code coverage for ${{ matrix.product.name }}
+ if: ${{ (contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true')
+ && matrix.product.setup.run-coverage }}
+ uses: zgosalvez/github-actions-report-lcov@a546f89a65a0cdcd82a92ae8d65e74d450ff3fbc # v4.1.4
+ with:
+ update-comment: false
+ coverage-files: ./contracts/lcov.info.pruned
+ minimum-coverage: ${{ matrix.product.min-coverage }}
+ artifact-name: code-coverage-report-${{ matrix.product.name }}
+ working-directory: ./contracts
- name: Collect Metrics
- if: needs.changes.outputs.changes == 'true'
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name)
+ || contains(fromJson(needs.changes.outputs.all_changes), 'shared')
+ || needs.changes.outputs.non_src_changes == 'true' }}
id: collect-gha-metrics
uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
with:
- id: solidity-foundry
+ id: ${{ matrix.product.name }}-solidity-foundry
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Foundry Tests ${{ matrix.product.name }}
+ continue-on-error: true
+
+ # runs only if non-test contracts were modified; scoped only to modified or added contracts
+ analyze:
+ needs: [ changes, define-matrix ]
+ name: Run static analysis
+ if: needs.changes.outputs.not_test_sol_modified == 'true'
+ runs-on: ubuntu-22.04
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ with:
+ submodules: recursive
+
+ - name: Setup NodeJS
+ uses: ./.github/actions/setup-nodejs
+
+ - name: Install Foundry
+ uses: foundry-rs/foundry-toolchain@8f1998e9878d786675189ef566a2e4bf24869773 # v1.2.0
+ with:
+ version: ${{ needs.define-matrix.outputs.foundry-version }}
+
+ - name: Set up Python
+ uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f #v5.1.1
+ with:
+ python-version: '3.8'
+
+ - name: Install solc-select and solc
+ uses: ./.github/actions/setup-solc-select
+ with:
+ to_install: '0.8.19'
+ to_use: '0.8.19'
+
+ - name: Install Slither
+ uses: ./.github/actions/setup-slither
+
+ - name: Run Slither
+ shell: bash
+ run: |
+ # modify remappings so that solc can find dependencies
+ ./contracts/scripts/ci/modify_remappings.sh contracts contracts/remappings.txt
+ mv remappings_modified.txt remappings.txt
+
+ # without it Slither sometimes fails to use remappings correctly
+ cp contracts/foundry.toml foundry.toml
+
+ FILES="${{ needs.changes.outputs.not_test_sol_modified_files }}"
+
+ for FILE in $FILES; do
+ PRODUCT=$(echo "$FILE" | awk -F'src/[^/]*/' '{print $2}' | cut -d'/' -f1)
+ echo "::debug::Running Slither for $FILE in $PRODUCT"
+ SLITHER_CONFIG="contracts/configs/slither/.slither.config-$PRODUCT-pr.json"
+ if [[ ! -f $SLITHER_CONFIG ]]; then
+ echo "::debug::No Slither config found for $PRODUCT, using default"
+ SLITHER_CONFIG="contracts/configs/slither/.slither.config-default-pr.json"
+ fi
+ ./contracts/scripts/ci/generate_slither_report.sh "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/" "$SLITHER_CONFIG" "." "$FILE" "contracts/slither-reports-current" "--solc-remaps @=contracts/node_modules/@"
+ done
+
+ # all the actions below, up to printing results, run only if any existing contracts were modified
+ # in that case we extract new issues introduced by the changes by using an LLM model
+ - name: Upload Slither results for current branch
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ timeout-minutes: 2
+ continue-on-error: true
+ with:
+ name: slither-reports-current-${{ github.sha }}
+ path: contracts/slither-reports-current
+ retention-days: 7
+
+ # we need to upload scripts and configuration in case base_ref doesn't have the scripts, or they are in different version
+ - name: Upload Slither scripts
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ timeout-minutes: 2
+ continue-on-error: true
+ with:
+ name: tmp-slither-scripts-${{ github.sha }}
+ path: contracts/scripts/ci
+ retention-days: 7
+
+ - name: Upload configs
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ timeout-minutes: 2
+ continue-on-error: true
+ with:
+ name: tmp-configs-${{ github.sha }}
+ path: contracts/configs
+ retention-days: 7
+
+ - name: Checkout the repo
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ with:
+ ref: ${{ github.base_ref }}
+
+ - name: Download Slither scripts
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
+ with:
+ name: tmp-slither-scripts-${{ github.sha }}
+ path: contracts/scripts/ci
+
+ - name: Download configs
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
+ with:
+ name: tmp-configs-${{ github.sha }}
+ path: contracts/configs
+
+ # since we have just checked out the repository again, we lose NPM dependencies installs previously, we need to install them again to compile contracts
+ - name: Setup NodeJS
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: ./.github/actions/setup-nodejs
+
+ - name: Run Slither for base reference
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ shell: bash
+ run: |
+ # we need to set file permission again since they are lost during download
+ for file in contracts/scripts/ci/*.sh; do
+ chmod +x "$file"
+ done
+
+ # modify remappings so that solc can find dependencies
+ ./contracts/scripts/ci/modify_remappings.sh contracts contracts/remappings.txt
+ mv remappings_modified.txt remappings.txt
+
+ # without it Slither sometimes fails to use remappings correctly
+ cp contracts/foundry.toml foundry.toml
+
+ FILES="${{ needs.changes.outputs.sol_mod_only_files }}"
+
+ for FILE in $FILES; do
+ PRODUCT=$(echo "$FILE" | awk -F'src/[^/]*/' '{print $2}' | cut -d'/' -f1)
+ echo "::debug::Running Slither for $FILE in $PRODUCT"
+ SLITHER_CONFIG="contracts/configs/slither/.slither.config-$PRODUCT-pr.json"
+ if [[ ! -f $SLITHER_CONFIG ]]; then
+ echo "::debug::No Slither config found for $PRODUCT, using default"
+ SLITHER_CONFIG="contracts/configs/slither/.slither.config-default-pr.json"
+ fi
+ ./contracts/scripts/ci/generate_slither_report.sh "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/" "$SLITHER_CONFIG" "." "$FILE" "contracts/slither-reports-base-ref" "--solc-remaps @=contracts/node_modules/@"
+ done
+
+ - name: Upload Slither report
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ timeout-minutes: 10
+ continue-on-error: true
+ with:
+ name: slither-reports-base-${{ github.sha }}
+ path: |
+ contracts/slither-reports-base-ref
+ retention-days: 7
+
+ - name: Download Slither results for current branch
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
+ with:
+ name: slither-reports-current-${{ github.sha }}
+ path: contracts/slither-reports-current
+
+ - name: Generate diff of Slither reports for modified files
+ if: needs.changes.outputs.sol_mod_only == 'true'
+ env:
+ OPEN_API_KEY: ${{ secrets.OPEN_AI_SLITHER_API_KEY }}
+ shell: bash
+ run: |
+ set -euo pipefail
+ for base_report in contracts/slither-reports-base-ref/*.md; do
+ filename=$(basename "$base_report")
+ current_report="contracts/slither-reports-current/$filename"
+ new_issues_report="contracts/slither-reports-current/${filename%.md}_new_issues.md"
+ if [ -f "$current_report" ]; then
+ if ./contracts/scripts/ci/find_slither_report_diff.sh "$base_report" "$current_report" "$new_issues_report" "contracts/scripts/ci/prompt-difference.md" "contracts/scripts/ci/prompt-validation.md"; then
+ if [[ -s $new_issues_report ]]; then
+ awk 'NR==2{print "*This new issues report has been automatically generated by LLM model using two Slither reports. One based on `${{ github.base_ref}}` and another on `${{ github.sha }}` commits.*"}1' $new_issues_report > tmp.md && mv tmp.md $new_issues_report
+ echo "Replacing full Slither report with diff for $current_report"
+ rm $current_report && mv $new_issues_report $current_report
+ else
+ echo "No difference detected between $base_report and $current_report reports. Won't include any of them."
+ rm $current_report
+ fi
+ else
+ echo "::warning::Failed to generate a diff report with new issues for $base_report using an LLM model, will use full report."
+ fi
+
+ else
+ echo "::warning::Failed to find current commit's equivalent of $base_report (file $current_report doesn't exist, but should have been generated). Please check Slither logs."
+ fi
+ done
+
+ # actions that execute only if any existing contracts were modified end here
+ - name: Print Slither summary
+ shell: bash
+ run: |
+ echo "# Static analysis results " >> $GITHUB_STEP_SUMMARY
+ for file in "contracts/slither-reports-current"/*.md; do
+ if [ -e "$file" ]; then
+ cat "$file" >> $GITHUB_STEP_SUMMARY
+ fi
+ done
+
+ - name: Validate if all Slither run for all contracts
+ uses: ./.github/actions/validate-solidity-artifacts
+ with:
+ validate_slither_reports: 'true'
+ slither_reports_path: 'contracts/slither-reports-current'
+ sol_files: ${{ needs.changes.outputs.not_test_sol_modified_files }}
+
+ - name: Upload Slither reports
+ uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4
+ timeout-minutes: 10
+ continue-on-error: true
+ with:
+ name: slither-reports-${{ github.sha }}
+ path: |
+ contracts/slither-reports-current
+ retention-days: 7
+
+ - name: Find Slither comment in the PR
+ uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.0.0
+ id: find-comment
+ with:
+ issue-number: ${{ github.event.pull_request.number }}
+ comment-author: 'github-actions[bot]'
+ body-includes: 'Static analysis results'
+
+ - name: Extract job summary URL
+ id: job-summary-url
+ uses: pl-strflt/job-summary-url-action@df2d22c5351f73e0a187d20879854b8d98e6e001 # v1.0.0
+ with:
+ job: 'Run static analysis'
+
+ - name: Build Slither reports artifacts URL
+ id: build-slither-artifact-url
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ ARTIFACTS=$(gh api -X GET repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts)
+ ARTIFACT_ID=$(echo "$ARTIFACTS" | jq '.artifacts[] | select(.name=="slither-reports-${{ github.sha }}") | .id')
+ echo "Artifact ID: $ARTIFACT_ID"
+
+ slither_artifact_url="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts/$ARTIFACT_ID"
+ echo "slither_artifact_url=$slither_artifact_url" >> $GITHUB_OUTPUT
+
+ - name: Create or update Slither comment in the PR
+ uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
+ with:
+ comment-id: ${{ steps.find-comment.outputs.comment-id }}
+ issue-number: ${{ github.event.pull_request.number }}
+ body: |
+ ## Static analysis results are available
+ Hey @${{ github.event.push && github.event.push.pusher && github.event.push.pusher.username || github.actor }}, you can view Slither reports in the job summary [here](${{ steps.job-summary-url.outputs.job_summary_url }}) or download them as artifact [here](${{ steps.build-slither-artifact-url.outputs.slither_artifact_url }}).
+
+ Please check them before merging and make sure you have addressed all issues.
+ edit-mode: replace
+
+ - name: Remove temp artifacts
+ uses: geekyeggo/delete-artifact@24928e75e6e6590170563b8ddae9fac674508aa1 # v5.0
+ with:
+ name: tmp-*
+
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: solidity-foundry-slither
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Run static analysis
+ continue-on-error: true
+
+ solidity-forge-fmt:
+ name: Forge fmt ${{ matrix.product.name }}
+ if: ${{ needs.changes.outputs.non_src_changes == 'true' || needs.changes.outputs.not_test_sol_modified == 'true' }}
+ needs: [define-matrix, changes]
+ strategy:
+ fail-fast: false
+ matrix:
+ product: ${{fromJson(needs.define-matrix.outputs.matrix)}}
+ runs-on: ubuntu-22.04
+ steps:
+ - name: Checkout the repo
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name) && matrix.product.setup.run-forge-fmt }}
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ with:
+ submodules: recursive
+
+ - name: Setup NodeJS
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name) && matrix.product.setup.run-forge-fmt }}
+ uses: ./.github/actions/setup-nodejs
+
+ - name: Install Foundry
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name) && matrix.product.setup.run-forge-fmt }}
+ uses: foundry-rs/foundry-toolchain@8f1998e9878d786675189ef566a2e4bf24869773 # v1.2.0
+ with:
+ version: ${{ needs.define-matrix.outputs.foundry-version }}
+
+ - name: Run Forge fmt
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name) && matrix.product.setup.run-forge-fmt }}
+ run: forge fmt --check
+ id: fmt
+ working-directory: contracts
+ env:
+ FOUNDRY_PROFILE: ${{ matrix.product.name }}
+
+ - name: Collect Metrics
+ if: ${{ contains(fromJson(needs.changes.outputs.all_changes), matrix.product.name) && matrix.product.setup.run-forge-fmt }}
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0
+ with:
+ id: solidity-forge-fmt-${{ matrix.product.name }}
org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
- this-job-name: Foundry Tests ${{ matrix.product }}
+ this-job-name: Forge fmt ${{ matrix.product.name }}
continue-on-error: true
diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml
index fb6ba6fef43..705fad3be60 100644
--- a/.github/workflows/solidity-hardhat.yml
+++ b/.github/workflows/solidity-hardhat.yml
@@ -25,7 +25,7 @@ jobs:
with:
filters: |
src:
- - 'contracts/src/!(v0.8/(ccip|functions|keystone|l2ep|llo-feeds|transmission|vrf)/**)/**/*'
+ - 'contracts/src/!(v0.8/(ccip|functions|keystone|l2ep|liquiditymanager|llo-feeds|transmission|vrf)/**)/**/*'
- 'contracts/test/**/*'
- 'contracts/package.json'
- 'contracts/pnpm-lock.yaml'
@@ -84,4 +84,4 @@ jobs:
basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
this-job-name: Solidity
- continue-on-error: true
\ No newline at end of file
+ continue-on-error: true
diff --git a/.github/workflows/solidity-jira.yml b/.github/workflows/solidity-jira.yml
new file mode 100644
index 00000000000..1054bfa9875
--- /dev/null
+++ b/.github/workflows/solidity-jira.yml
@@ -0,0 +1,100 @@
+# This is its own independent workflow since "solidity.yml" depends on "merge_group" and "push" events.
+# But for ensuring that JIRA tickets are always updated, we only care about "pull_request" events.
+#
+# We still need to add "merge_group" event and noop so that we'll pass required workflow checks.
+#
+# I didn't add this to the "changeset.yml" workflow because the "changeset" job isnt required, and we'd need to add the "merge_group" event to the "changeset.yml" workflow.
+# If we made the change to make it required.
+name: Solidity Jira
+
+on:
+ merge_group:
+ pull_request:
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ skip-enforce-jira-issue:
+ name: Should Skip
+ # We want to skip merge_group events, and any release branches
+ # Since we only want to enforce Jira issues on pull requests related to feature branches
+ if: ${{ github.event_name != 'merge_group' && !startsWith(github.head_ref, 'release/') }}
+ outputs:
+ should-enforce: ${{ steps.changed_files.outputs.only_src_contracts }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+
+ # We don't use detect-solidity-file-changes here because we need to use the "every" predicate quantifier
+ - name: Filter paths
+ uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
+ id: changed_files
+ with:
+ list-files: "csv"
+ # This is a valid input, see https://github.com/dorny/paths-filter/pull/226
+ predicate-quantifier: "every"
+ filters: |
+ only_src_contracts:
+ - contracts/**/*.sol
+ - '!contracts/**/*.t.sol'
+
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
+ with:
+ id: solidity-jira
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Should Skip
+ continue-on-error: true
+
+ enforce-jira-issue:
+ name: Enforce Jira Issue
+ runs-on: ubuntu-latest
+ # If a needs job is skipped, this job will be skipped and counted as successful
+ # The job skips on merge_group events, and any release branches
+ # Since we only want to enforce Jira issues on pull requests related to feature branches
+ needs: [skip-enforce-jira-issue]
+ # In addition to the above conditions, we only want to running on solidity related PRs.
+ #
+ # Note: A job that is skipped will report its status as "Success".
+ # It will not prevent a pull request from merging, even if it is a required check.
+ if: ${{ needs.skip-enforce-jira-issue.outputs.should-enforce == 'true' }}
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+
+ - name: Setup NodeJS
+ uses: ./.github/actions/setup-nodejs
+
+ - name: Setup Jira
+ working-directory: ./.github/scripts/jira
+ run: pnpm i
+
+ - name: Enforce Jira Issue
+ working-directory: ./.github/scripts/jira
+ run: |
+ echo "COMMIT_MESSAGE=$(git log -1 --pretty=format:'%s')" >> $GITHUB_ENV
+ pnpm issue:enforce
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ JIRA_HOST: ${{ secrets.JIRA_HOST }}
+ JIRA_USERNAME: ${{ secrets.JIRA_USERNAME }}
+ JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
+ PR_TITLE: ${{ github.event.pull_request.title }}
+ BRANCH_NAME: ${{ github.event.pull_request.head.ref }}
+
+ - name: Collect Metrics
+ id: collect-gha-metrics
+ uses: smartcontractkit/push-gha-metrics-action@d9da21a2747016b3e13de58c7d4115a3d5c97935 # v3.0.1
+ with:
+ id: solidity-jira
+ org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }}
+ basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }}
+ hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }}
+ this-job-name: Enforce Jira Issue
+ continue-on-error: true
diff --git a/.github/workflows/solidity.yml b/.github/workflows/solidity.yml
index dff35b3cc93..10193bfc2ec 100644
--- a/.github/workflows/solidity.yml
+++ b/.github/workflows/solidity.yml
@@ -9,6 +9,18 @@ defaults:
shell: bash
jobs:
+ readonly_changes:
+ name: Detect readonly solidity file changes
+ runs-on: ubuntu-latest
+ outputs:
+ changes: ${{ steps.ch.outputs.changes }}
+ steps:
+ - name: Checkout the repo
+ uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
+ - name: Detect readonly solidity file changes
+ id: ch
+ uses: ./.github/actions/detect-solidity-readonly-file-changes
+
changes:
name: Detect changes
runs-on: ubuntu-latest
@@ -31,15 +43,15 @@ jobs:
release-version: ${{ steps.release-tag-check.outputs.release-version }}
pre-release-version: ${{ steps.release-tag-check.outputs.pre-release-version }}
steps:
- - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
- name: Check release tag
id: release-tag-check
- uses: smartcontractkit/chainlink-github-actions/release/release-tag-check@2031e56eb4edb8115ce8ba07cbbfb457149d865d # v2.3.8
+ uses: smartcontractkit/chainlink-github-actions/release/release-tag-check@5dd916d08c03cb5f9a97304f4f174820421bb946 # v2.3.11
env:
# Match semver git tags with a "contracts-" prefix.
RELEASE_REGEX: '^contracts-v[0-9]+\.[0-9]+\.[0-9]+$'
PRE_RELEASE_REGEX: '^contracts-v[0-9]+\.[0-9]+\.[0-9]+-(.+)$'
- # Get the version by stripping the "contracts-v" prefix.
+ # Get the version by stripping the "contracts-v" prefix.
VERSION_PREFIX: 'contracts-v'
prepublish-test:
@@ -171,7 +183,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
@@ -211,7 +223,7 @@ jobs:
contents: write
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
diff --git a/.gitignore b/.gitignore
index 2b31c9d3a59..bd7a6b72cde 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,11 +69,13 @@ ztarrepo.tar.gz
**/test-ledger/*
__debug_bin*
.test_summary/
+db_dumps/
.run.id
integration-tests/**/traces/
benchmark_report.csv
benchmark_summary.json
-integration-tests/citool/output.csv
+secrets.toml
+tmp_laneconfig/
# goreleaser builds
cosign.*
@@ -84,6 +86,7 @@ MacOSX*
*report.xml
*report.json
*.out
+dot_graphs/
contracts/yarn.lock
@@ -100,7 +103,7 @@ tools/flakeytests/coverage.txt
# Runtime test configuration that might contain secrets
override*.toml
-# Pythin venv
+# Python venv
.venv/
ocr_soak_report.csv
diff --git a/.golangci.yml b/.golangci.yml
index 7155cff2d51..72f52bd4528 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -71,9 +71,10 @@ linters-settings:
- name: error-return
- name: error-strings
- name: error-naming
+ - name: exported
- name: if-return
- name: increment-decrement
- # - name: var-naming
+ - name: var-naming
- name: var-declaration
- name: package-comments
- name: range
@@ -92,7 +93,7 @@ linters-settings:
- name: struct-tag
# - name: string-format
- name: string-of-int
- # - name: range-val-address
+ - name: range-val-address
- name: range-val-in-closure
- name: modifies-value-receiver
- name: modifies-parameter
diff --git a/.goreleaser.develop.yaml b/.goreleaser.develop.yaml
index 7fbd2aa667b..08d8e4de945 100644
--- a/.goreleaser.develop.yaml
+++ b/.goreleaser.develop.yaml
@@ -1,9 +1,12 @@
-## goreleaser <1.14.0
project_name: chainlink
+version: 2
+
env:
- ZIG_EXEC={{ if index .Env "ZIG_EXEC" }}{{ .Env.ZIG_EXEC }}{{ else }}zig{{ end }}
- IMAGE_PREFIX={{ if index .Env "IMAGE_PREFIX" }}{{ .Env.IMAGE_PREFIX }}{{ else }}localhost:5001{{ end }}
+ - IMAGE_NAME={{ if index .Env "IMAGE_NAME" }}{{ .Env.IMAGE_NAME }}{{ else }}chainlink{{ end }}
+ - IMAGE_TAG={{ if index .Env "IMAGE_TAG" }}{{ .Env.IMAGE_TAG }}{{ else }}develop{{ end }}
- IMAGE_LABEL_DESCRIPTION="node of the decentralized oracle network, bridging on and off-chain computation"
- IMAGE_LABEL_LICENSES="MIT"
- IMAGE_LABEL_SOURCE="https://github.com/smartcontractkit/{{ .ProjectName }}"
@@ -56,18 +59,18 @@ builds:
# See https://goreleaser.com/customization/docker/
dockers:
- - id: root-linux-amd64
+ - id: linux-amd64
dockerfile: core/chainlink.goreleaser.Dockerfile
use: buildx
goos: linux
goarch: amd64
extra_files:
- tmp/linux_amd64/libs
- - tmp/linux_amd64/plugins
- tools/bin/ldd_fix
build_flag_templates:
- "--platform=linux/amd64"
- "--pull"
+ - "--build-arg=CHAINLINK_USER=chainlink"
- "--build-arg=COMMIT_SHA={{ .FullCommit }}"
- "--label=org.opencontainers.image.created={{ .Date }}"
- "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}"
@@ -78,20 +81,21 @@ dockers:
- "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}"
- "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}"
image_templates:
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-root-amd64"
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-root-amd64"
- - id: root-linux-arm64
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-amd64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-amd64"
+ - id: linux-arm64
dockerfile: core/chainlink.goreleaser.Dockerfile
use: buildx
goos: linux
goarch: arm64
extra_files:
- tmp/linux_arm64/libs
- - tmp/linux_arm64/plugins
- tools/bin/ldd_fix
build_flag_templates:
- "--platform=linux/arm64"
- "--pull"
+ - "--build-arg=CHAINLINK_USER=chainlink"
- "--build-arg=COMMIT_SHA={{ .FullCommit }}"
- "--label=org.opencontainers.image.created={{ .Date }}"
- "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}"
@@ -102,9 +106,9 @@ dockers:
- "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}"
- "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}"
image_templates:
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-root-arm64"
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-root-arm64"
- - id: linux-amd64
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-arm64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-arm64"
+ - id: linux-amd64-plugins
dockerfile: core/chainlink.goreleaser.Dockerfile
use: buildx
goos: linux
@@ -118,6 +122,10 @@ dockers:
- "--pull"
- "--build-arg=CHAINLINK_USER=chainlink"
- "--build-arg=COMMIT_SHA={{ .FullCommit }}"
+ - "--build-arg=CL_MEDIAN_CMD=chainlink-feeds"
+ - "--build-arg=CL_MERCURY_CMD=chainlink-mercury"
+ - "--build-arg=CL_SOLANA_CMD=chainlink-solana"
+ - "--build-arg=CL_STARKNET_CMD=chainlink-starknet"
- "--label=org.opencontainers.image.created={{ .Date }}"
- "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}"
- "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}"
@@ -127,9 +135,10 @@ dockers:
- "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}"
- "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}"
image_templates:
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-amd64"
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-amd64"
- - id: linux-arm64
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-plugins"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-plugins-amd64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-plugins-amd64"
+ - id: linux-arm64-plugins
dockerfile: core/chainlink.goreleaser.Dockerfile
use: buildx
goos: linux
@@ -143,6 +152,10 @@ dockers:
- "--pull"
- "--build-arg=CHAINLINK_USER=chainlink"
- "--build-arg=COMMIT_SHA={{ .FullCommit }}"
+ - "--build-arg=CL_MEDIAN_CMD=chainlink-feeds"
+ - "--build-arg=CL_MERCURY_CMD=chainlink-mercury"
+ - "--build-arg=CL_SOLANA_CMD=chainlink-solana"
+ - "--build-arg=CL_STARKNET_CMD=chainlink-starknet"
- "--label=org.opencontainers.image.created={{ .Date }}"
- "--label=org.opencontainers.image.description={{ .Env.IMAGE_LABEL_DESCRIPTION }}"
- "--label=org.opencontainers.image.licenses={{ .Env.IMAGE_LABEL_LICENSES }}"
@@ -152,27 +165,29 @@ dockers:
- "--label=org.opencontainers.image.version={{ .Env.CHAINLINK_VERSION }}"
- "--label=org.opencontainers.image.url={{ .Env.IMAGE_LABEL_SOURCE }}"
image_templates:
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-arm64"
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-arm64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-plugins-arm64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-plugins-arm64"
# See https://goreleaser.com/customization/docker_manifest/
docker_manifests:
- - name_template: "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-root"
+ - name_template: "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}"
image_templates:
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-root-amd64"
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-root-arm64"
- - name_template: "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-root"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-amd64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-arm64"
+ - name_template: "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}"
image_templates:
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-root-amd64"
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-root-arm64"
- - name_template: "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-amd64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-arm64"
+ - name_template: "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-plugins"
image_templates:
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-amd64"
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:develop-arm64"
- - name_template: "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-plugins"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-plugins-amd64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:{{ .Env.IMAGE_TAG }}-plugins-arm64"
+ - name_template: "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-plugins"
image_templates:
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-amd64"
- - "{{ .Env.IMAGE_PREFIX }}/{{ .ProjectName }}-develop:sha-{{ .ShortCommit }}-arm64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-plugins-amd64"
+ - "{{ .Env.IMAGE_PREFIX }}/{{ .Env.IMAGE_NAME }}:sha-{{ .ShortCommit }}-plugins-arm64"
# See https://goreleaser.com/customization/docker_sign/
docker_signs:
@@ -183,7 +198,10 @@ checksum:
name_template: "checksums.txt"
snapshot:
- name_template: "{{ .Env.CHAINLINK_VERSION }}-{{ .ShortCommit }}"
+ version_template: "{{ .Env.CHAINLINK_VERSION }}-{{ .ShortCommit }}"
+
+partial:
+ by: target
changelog:
sort: asc
diff --git a/.goreleaser.devspace.yaml b/.goreleaser.devspace.yaml
index bca65e90454..d0167b34cda 100644
--- a/.goreleaser.devspace.yaml
+++ b/.goreleaser.devspace.yaml
@@ -1,6 +1,7 @@
-## goreleaser <1.14.0
project_name: chainlink-devspace
+version: 2
+
env:
- ZIG_EXEC={{ if index .Env "ZIG_EXEC" }}{{ .Env.ZIG_EXEC }}{{ else }}zig{{ end }}
- IMAGE_LABEL_DESCRIPTION="node of the decentralized oracle network, bridging on and off-chain computation"
@@ -75,7 +76,7 @@ checksum:
name_template: "checksums.txt"
snapshot:
- name_template: '{{ .Env.CHAINLINK_VERSION }}-{{ .Runtime.Goarch }}-{{ .Now.Format "2006-01-02-15-04-05Z" }}'
+ version_template: '{{ .Env.CHAINLINK_VERSION }}-{{ .Runtime.Goarch }}-{{ .Now.Format "2006-01-02-15-04-05Z" }}'
changelog:
sort: asc
diff --git a/.mockery.yaml b/.mockery.yaml
index 17800e3609a..5cba66f3dad 100644
--- a/.mockery.yaml
+++ b/.mockery.yaml
@@ -43,6 +43,10 @@ packages:
github.com/smartcontractkit/chainlink/v2/core/bridges:
interfaces:
ORM:
+ github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types:
+ interfaces:
+ CCIPOracle:
+ OracleCreator:
github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types:
interfaces:
Dispatcher:
@@ -258,11 +262,20 @@ packages:
ORM:
Runner:
PipelineParamUnmarshaler:
- github.com/smartcontractkit/chainlink/v2/core/services/promreporter:
+ github.com/smartcontractkit/chainlink/v2/core/services/headreporter:
config:
- dir: core/internal/mocks
+ dir: "{{ .InterfaceDir }}"
+ filename: "{{ .InterfaceName | snakecase }}_mock.go"
+ inpackage: true
+ mockname: "Mock{{ .InterfaceName | camelcase }}"
interfaces:
+ HeadReporter:
PrometheusBackend:
+ github.com/smartcontractkit/libocr/commontypes:
+ config:
+ dir: "common/types/mocks"
+ interfaces:
+ MonitoringEndpoint:
github.com/smartcontractkit/chainlink/v2/core/services/relay/evm:
interfaces:
BatchCaller:
@@ -297,6 +310,15 @@ packages:
interfaces:
Config:
FeeConfig:
+ github.com/smartcontractkit/chainlink/v2/core/services/telemetry:
+ config:
+ dir: "{{ .InterfaceDir }}"
+ filename: "{{ .InterfaceName | snakecase }}_mock.go"
+ inpackage: true
+ mockname: "Mock{{ .InterfaceName | camelcase }}"
+ interfaces:
+ MonitoringEndpointGenerator:
+ IngressAgent:
github.com/smartcontractkit/chainlink/v2/core/services/webhook:
interfaces:
ExternalInitiatorManager:
@@ -318,7 +340,242 @@ packages:
dir: core/services/relay/evm/mocks
ChainReader:
ChainWriter:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp:
+ config:
+ dir: core/gethwrappers/ccip/mocks/
+ filename: evm2_evm_on_ramp_interface.go
+ outpkg: mock_contracts
+ interfaces:
+ EVM2EVMOnRampInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp:
+ config:
+ dir: core/gethwrappers/ccip/mocks/
+ filename: evm2_evm_off_ramp_interface.go
+ outpkg: mock_contracts
+ interfaces:
+ EVM2EVMOffRampInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0:
+ config:
+ dir: core/gethwrappers/ccip/mocks/v1_2_0/
+ filename: evm2_evm_off_ramp_interface.go
+ outpkg: mock_contracts
+ interfaces:
+ EVM2EVMOffRampInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0:
+ config:
+ dir: core/gethwrappers/ccip/mocks/v1_0_0/
+ filename: evm2_evm_off_ramp_interface.go
+ outpkg: mock_contracts
+ interfaces:
+ EVM2EVMOffRampInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store:
+ config:
+ dir: core/gethwrappers/ccip/mocks/
+ filename: commit_store_interface.go
+ outpkg: mock_contracts
+ interfaces:
+ CommitStoreInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry:
+ config:
+ dir: core/gethwrappers/ccip/mocks/
+ filename: price_registry_interface.go
+ outpkg: mock_contracts
+ interfaces:
+ PriceRegistryInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface:
+ config:
+ dir: core/gethwrappers/ccip/mocks/
+ filename: link_token_interface.go
+ outpkg: mock_contracts
+ interfaces:
+ LinkTokenInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_l1_bridge_adapter:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_l1_bridge_adapter/
+ filename: arbitrum_l1_bridge_adapter_interface.go
+ outpkg: mock_arbitrum_l1_bridge_adapter
+ interfaces:
+ ArbitrumL1BridgeAdapterInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_l2_bridge_adapter:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_l2_bridge_adapter/
+ filename: arbitrum_l2_bridge_adapter_interface.go
+ outpkg: mock_arbitrum_l2_bridge_adapter
+ interfaces:
+ ArbitrumL2BridgeAdapterInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_gateway_router:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_gateway_router/
+ filename: arbitrum_gateway_router_interface.go
+ outpkg: mock_arbitrum_gateway_router
+ interfaces:
+ ArbitrumGatewayRouterInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_inbox:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_inbox/
+ filename: arbitrum_inbox_interface.go
+ outpkg: mock_arbitrum_inbox
+ interfaces:
+ ArbitrumInboxInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_gateway:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_l2_arbitrum_gateway/
+ filename: l2_arbitrum_gateway_interface.go
+ outpkg: mock_l2_arbitrum_gateway
+ interfaces:
+ L2ArbitrumGatewayInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbsys:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_arbsys/
+ filename: arb_sys_interface.go
+ outpkg: mock_arbsys
+ interfaces:
+ ArbSysInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arb_node_interface:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_node_interface/
+ filename: node_interface_interface.go
+ outpkg: mock_node_interface
+ interfaces:
+ NodeInterfaceInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_messenger:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_l2_arbitrum_messenger/
+ filename: l2_arbitrum_messenger_interface.go
+ outpkg: mock_l2_arbitrum_messenger
+ interfaces:
+ L2ArbitrumMessengerInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_rollup_core:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_rollup_core/
+ filename: arb_rollup_core_interface.go
+ outpkg: mock_arbitrum_rollup_core
+ interfaces:
+ ArbRollupCoreInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/optimism_portal:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_optimism_portal/
+ filename: optimism_portal_interface.go
+ outpkg: mock_optimism_portal
+ interfaces:
+ OptimismPortalInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/optimism_l2_output_oracle:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_optimism_l2_output_oracle/
+ filename: optimism_l2_output_oracle_interface.go
+ outpkg: mock_optimism_l2_output_oracle
+ interfaces:
+ OptimismL2OutputOracleInterface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/optimism_portal_2:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_optimism_portal_2/
+ filename: optimism_portal2_interface.go
+ outpkg: mock_optimism_portal_2
+ interfaces:
+ OptimismPortal2Interface:
+ github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/optimism_dispute_game_factory:
+ config:
+ dir: core/gethwrappers/liquiditymanager/mocks/mock_optimism_dispute_game_factory/
+ filename: optimism_dispute_game_factory_interface.go
+ outpkg: mock_optimism_dispute_game_factory
+ interfaces:
+ OptimismDisputeGameFactoryInterface:
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache:
+ config:
+ filename: chain_health_mock.go
+ interfaces:
+ ChainHealthcheck:
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata:
+ interfaces:
+ CommitStoreReader:
+ config:
+ filename: commit_store_reader_mock.go
+ OffRampReader:
+ config:
+ filename: offramp_reader_mock.go
+ OnRampReader:
+ config:
+ filename: onramp_reader_mock.go
+ PriceRegistryReader:
+ config:
+ filename: price_registry_reader_mock.go
+ TokenPoolReader:
+ config:
+ filename: token_pool_reader_mock.go
+ USDCReader:
+ config:
+ filename: usdc_reader_mock.go
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader:
+ config:
+ filename: token_pool_batched_reader_mock.go
+ interfaces:
+ TokenPoolBatchedReader:
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider:
+ config:
+ filename: price_registry_mock.go
+ interfaces:
+ PriceRegistry:
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdb:
+ config:
+ filename: price_service_mock.go
+ interfaces:
+ PriceService:
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter:
+ config:
+ filename: mock.go
+ dir: "{{ .InterfaceDir }}/"
+ outpkg: pricegetter
+ interfaces:
+ PriceGetter:
+ config:
+ mockname: "Mock{{ .InterfaceName }}"
+ filename: mock.go
+ AllTokensPriceGetter:
+ config:
+ mockname: "Mock{{ .InterfaceName }}"
+ filename: all_price_getter_mock.go
+ github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/statuschecker:
+ interfaces:
+ CCIPTransactionStatusChecker:
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib:
+ config:
+ outpkg: rpclibmocks
+ interfaces:
+ BatchCaller:
+ config:
+ filename: batch_caller.go
+ dir: core/services/relay/evm/rpclibmocks
+ EvmBatchCaller:
+ config:
+ filename: evm_mock.go
+ dir: "{{ .InterfaceDir }}/rpclibmocks"
-
-
-
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices:
+ config:
+ dir: "{{ .InterfaceDir }}/"
+ outpkg: prices
+ interfaces:
+ GasPriceEstimatorCommit:
+ config:
+ mockname: "Mock{{ .InterfaceName }}"
+ filename: gas_price_estimator_commit_mock.go
+ GasPriceEstimatorExec:
+ config:
+ mockname: "Mock{{ .InterfaceName }}"
+ filename: gas_price_estimator_exec_mock.go
+ GasPriceEstimator:
+ config:
+ mockname: "Mock{{ .InterfaceName }}"
+ filename: gas_price_estimator_mock.go
+ github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata:
+ config:
+ filename: reader_mock.go
+ dir: "{{ .InterfaceDir }}/"
+ outpkg: tokendata
+ interfaces:
+ Reader:
+ config:
+ mockname: "Mock{{ .InterfaceName }}"
+ github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer:
+ interfaces:
+ ORM:
\ No newline at end of file
diff --git a/.swp b/.swp
deleted file mode 100644
index e2293baeb2c..00000000000
Binary files a/.swp and /dev/null differ
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a78e070b434..780c68003f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
# Changelog Chainlink Core
-## 2.15.0 - 2024-08-19
+## 2.15.0 - 2024-08-21
### Minor Changes
diff --git a/GNUmakefile b/GNUmakefile
index 3cba1738d5d..775d204269b 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -27,12 +27,8 @@ gomod: ## Ensure chainlink's go dependencies are installed.
go mod download
.PHONY: gomodtidy
-gomodtidy: ## 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
+gomodtidy: gomods ## Run go mod tidy on all modules.
+ gomods tidy
.PHONY: docs
docs: ## Install and run pkgsite to view Go docs
@@ -89,12 +85,8 @@ abigen: ## Build & install abigen.
./tools/bin/build_abigen
.PHONY: generate
-generate: abigen codecgen mockery protoc ## Execute all go:generate commands.
- go generate -x ./...
- cd ./core/scripts && go generate -x ./...
- cd ./integration-tests && go generate -x ./...
- cd ./integration-tests/load && go generate -x ./...
- cd ./dashboard-lib && go generate -x ./...
+generate: abigen codecgen mockery protoc gomods ## Execute all go:generate commands.
+ gomods -w go generate -x ./...
mockery
.PHONY: rm-mocked
@@ -136,7 +128,7 @@ presubmit: ## Format go files and imports.
.PHONY: gomods
gomods: ## Install gomods
- go install github.com/jmank88/gomods@v0.1.1
+ go install github.com/jmank88/gomods@v0.1.3
.PHONY: mockery
mockery: $(mockery) ## Install mockery.
@@ -168,8 +160,7 @@ config-docs: ## Generate core node configuration documentation
.PHONY: golangci-lint
golangci-lint: ## Run golangci-lint for all issues.
[ -d "./golangci-lint" ] || mkdir ./golangci-lint && \
- docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.59.1 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt
-
+ docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.59.1 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 | tee ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt
GORELEASER_CONFIG ?= .goreleaser.yaml
diff --git a/LICENSE b/LICENSE
index 1fa3822f510..3af9faa6c6f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,8 @@
-The MIT License (MIT)
+Copyright (c) 2018 SmartContract ChainLink Limited SEZC
+
+Portions of this software are licensed as follows:
-Copyright (c) 2018 SmartContract ChainLink, Ltd.
+The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -19,3 +21,12 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+
+
+*All content residing under (1) “/contracts/src/v0.8/ccip”; (2)
+“/core/gethwrappers/ccip”; (3) “/core/services/ocr2/plugins/ccip”; (4) "/core/capabilities/ccip" are licensed
+under “Business Source License 1.1” with a Change Date of May 23, 2027 and
+Change License to “MIT License”
+
+* Content outside of the above mentioned directories or restrictions
+above is available under the "MIT" license as defined above.
\ No newline at end of file
diff --git a/bors.toml b/bors.toml
deleted file mode 100644
index 5970c638cee..00000000000
--- a/bors.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-# https://github.com/bors-ng/bors-ng/issues/730
-status = [
- "sigscanner-check",
- "lint",
- "Core Tests (go_core_tests)",
- "Core Tests (go_core_race_tests)",
- "Solana Smoke Tests",
- "Prettier Formatting",
- "ETH Smoke Tests",
- "Solidity"
-]
-block_labels = [ "do-not-merge", "do-not-merge-yet", "needs changes", "wip" ]
-timeout_sec = 3600 # one hour
-required_approvals = 1
-up_to_date_approvals = true
-delete_merged_branches = true
-update_base_for_deletes = true
-# todo: enable after organizing codeowners
-# use_codeowners = true
-use_squash_merge = true
diff --git a/common/client/mock_node_client_test.go b/common/client/mock_node_client_test.go
index 5b7abe82121..5643dcde90e 100644
--- a/common/client/mock_node_client_test.go
+++ b/common/client/mock_node_client_test.go
@@ -400,62 +400,6 @@ func (_c *mockNodeClient_IsSyncing_Call[CHAIN_ID, HEAD]) RunAndReturn(run func(c
return _c
}
-// 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
-}
-
-// mockNodeClient_LatestFinalizedBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestFinalizedBlock'
-type mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID types.ID, HEAD Head] struct {
- *mock.Call
-}
-
-// LatestFinalizedBlock is a helper method to define mock.On call
-// - ctx context.Context
-func (_e *mockNodeClient_Expecter[CHAIN_ID, HEAD]) LatestFinalizedBlock(ctx interface{}) *mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID, HEAD] {
- return &mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID, HEAD]{Call: _e.mock.On("LatestFinalizedBlock", ctx)}
-}
-
-func (_c *mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID, HEAD]) Run(run func(ctx context.Context)) *mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID, HEAD] {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context))
- })
- return _c
-}
-
-func (_c *mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID, HEAD]) Return(_a0 HEAD, _a1 error) *mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID, HEAD] {
- _c.Call.Return(_a0, _a1)
- return _c
-}
-
-func (_c *mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID, HEAD]) RunAndReturn(run func(context.Context) (HEAD, error)) *mockNodeClient_LatestFinalizedBlock_Call[CHAIN_ID, HEAD] {
- _c.Call.Return(run)
- return _c
-}
-
// SetAliveLoopSub provides a mock function with given fields: _a0
func (_m *mockNodeClient[CHAIN_ID, HEAD]) SetAliveLoopSub(_a0 types.Subscription) {
_m.Called(_a0)
@@ -538,8 +482,8 @@ func (_c *mockNodeClient_SubscribeNewHead_Call[CHAIN_ID, HEAD]) Run(run func(ctx
return _c
}
-func (_c *mockNodeClient_SubscribeNewHead_Call[CHAIN_ID, HEAD]) Return(_a0 types.Subscription, _a1 error) *mockNodeClient_SubscribeNewHead_Call[CHAIN_ID, HEAD] {
- _c.Call.Return(_a0, _a1)
+func (_c *mockNodeClient_SubscribeNewHead_Call[CHAIN_ID, HEAD]) Return(s types.Subscription, err error) *mockNodeClient_SubscribeNewHead_Call[CHAIN_ID, HEAD] {
+ _c.Call.Return(s, err)
return _c
}
@@ -548,6 +492,140 @@ func (_c *mockNodeClient_SubscribeNewHead_Call[CHAIN_ID, HEAD]) RunAndReturn(run
return _c
}
+// SubscribeToFinalizedHeads provides a mock function with given fields: _a0
+func (_m *mockNodeClient[CHAIN_ID, HEAD]) SubscribeToFinalizedHeads(_a0 context.Context) (<-chan HEAD, types.Subscription, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SubscribeToFinalizedHeads")
+ }
+
+ var r0 <-chan HEAD
+ var r1 types.Subscription
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context) (<-chan HEAD, types.Subscription, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) <-chan HEAD); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(<-chan HEAD)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) types.Subscription); ok {
+ r1 = rf(_a0)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(types.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context) error); ok {
+ r2 = rf(_a0)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// mockNodeClient_SubscribeToFinalizedHeads_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeToFinalizedHeads'
+type mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID types.ID, HEAD Head] struct {
+ *mock.Call
+}
+
+// SubscribeToFinalizedHeads is a helper method to define mock.On call
+// - _a0 context.Context
+func (_e *mockNodeClient_Expecter[CHAIN_ID, HEAD]) SubscribeToFinalizedHeads(_a0 interface{}) *mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID, HEAD] {
+ return &mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID, HEAD]{Call: _e.mock.On("SubscribeToFinalizedHeads", _a0)}
+}
+
+func (_c *mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID, HEAD]) Run(run func(_a0 context.Context)) *mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID, HEAD] {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID, HEAD]) Return(_a0 <-chan HEAD, _a1 types.Subscription, _a2 error) *mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID, HEAD] {
+ _c.Call.Return(_a0, _a1, _a2)
+ return _c
+}
+
+func (_c *mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID, HEAD]) RunAndReturn(run func(context.Context) (<-chan HEAD, types.Subscription, error)) *mockNodeClient_SubscribeToFinalizedHeads_Call[CHAIN_ID, HEAD] {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SubscribeToHeads provides a mock function with given fields: ctx
+func (_m *mockNodeClient[CHAIN_ID, HEAD]) SubscribeToHeads(ctx context.Context) (<-chan HEAD, types.Subscription, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SubscribeToHeads")
+ }
+
+ var r0 <-chan HEAD
+ var r1 types.Subscription
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context) (<-chan HEAD, types.Subscription, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) <-chan HEAD); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(<-chan HEAD)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) types.Subscription); ok {
+ r1 = rf(ctx)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(types.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context) error); ok {
+ r2 = rf(ctx)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// mockNodeClient_SubscribeToHeads_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeToHeads'
+type mockNodeClient_SubscribeToHeads_Call[CHAIN_ID types.ID, HEAD Head] struct {
+ *mock.Call
+}
+
+// SubscribeToHeads is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *mockNodeClient_Expecter[CHAIN_ID, HEAD]) SubscribeToHeads(ctx interface{}) *mockNodeClient_SubscribeToHeads_Call[CHAIN_ID, HEAD] {
+ return &mockNodeClient_SubscribeToHeads_Call[CHAIN_ID, HEAD]{Call: _e.mock.On("SubscribeToHeads", ctx)}
+}
+
+func (_c *mockNodeClient_SubscribeToHeads_Call[CHAIN_ID, HEAD]) Run(run func(ctx context.Context)) *mockNodeClient_SubscribeToHeads_Call[CHAIN_ID, HEAD] {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *mockNodeClient_SubscribeToHeads_Call[CHAIN_ID, HEAD]) Return(ch <-chan HEAD, sub types.Subscription, err error) *mockNodeClient_SubscribeToHeads_Call[CHAIN_ID, HEAD] {
+ _c.Call.Return(ch, sub, err)
+ return _c
+}
+
+func (_c *mockNodeClient_SubscribeToHeads_Call[CHAIN_ID, HEAD]) RunAndReturn(run func(context.Context) (<-chan HEAD, types.Subscription, error)) *mockNodeClient_SubscribeToHeads_Call[CHAIN_ID, HEAD] {
+ _c.Call.Return(run)
+ return _c
+}
+
// SubscribersCount provides a mock function with given fields:
func (_m *mockNodeClient[CHAIN_ID, HEAD]) SubscribersCount() int32 {
ret := _m.Called()
diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go
index 36beae901c6..00473c66369 100644
--- a/common/client/mock_rpc_test.go
+++ b/common/client/mock_rpc_test.go
@@ -1508,8 +1508,8 @@ func (_c *mockRPC_SubscribeNewHead_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_
return _c
}
-func (_c *mockRPC_SubscribeNewHead_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) Return(_a0 types.Subscription, _a1 error) *mockRPC_SubscribeNewHead_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
- _c.Call.Return(_a0, _a1)
+func (_c *mockRPC_SubscribeNewHead_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) Return(s types.Subscription, err error) *mockRPC_SubscribeNewHead_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ _c.Call.Return(s, err)
return _c
}
@@ -1518,6 +1518,140 @@ func (_c *mockRPC_SubscribeNewHead_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_
return _c
}
+// SubscribeToFinalizedHeads provides a mock function with given fields: _a0
+func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) SubscribeToFinalizedHeads(_a0 context.Context) (<-chan HEAD, types.Subscription, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SubscribeToFinalizedHeads")
+ }
+
+ var r0 <-chan HEAD
+ var r1 types.Subscription
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context) (<-chan HEAD, types.Subscription, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) <-chan HEAD); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(<-chan HEAD)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) types.Subscription); ok {
+ r1 = rf(_a0)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(types.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context) error); ok {
+ r2 = rf(_a0)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// mockRPC_SubscribeToFinalizedHeads_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeToFinalizedHeads'
+type mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID types.ID, SEQ types.Sequence, ADDR types.Hashable, BLOCK_HASH types.Hashable, TX interface{}, TX_HASH types.Hashable, EVENT interface{}, EVENT_OPS interface{}, TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], FEE feetypes.Fee, HEAD types.Head[BLOCK_HASH], BATCH_ELEM interface{}] struct {
+ *mock.Call
+}
+
+// SubscribeToFinalizedHeads is a helper method to define mock.On call
+// - _a0 context.Context
+func (_e *mockRPC_Expecter[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) SubscribeToFinalizedHeads(_a0 interface{}) *mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ return &mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]{Call: _e.mock.On("SubscribeToFinalizedHeads", _a0)}
+}
+
+func (_c *mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) Run(run func(_a0 context.Context)) *mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) Return(_a0 <-chan HEAD, _a1 types.Subscription, _a2 error) *mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ _c.Call.Return(_a0, _a1, _a2)
+ return _c
+}
+
+func (_c *mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) RunAndReturn(run func(context.Context) (<-chan HEAD, types.Subscription, error)) *mockRPC_SubscribeToFinalizedHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SubscribeToHeads provides a mock function with given fields: ctx
+func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) SubscribeToHeads(ctx context.Context) (<-chan HEAD, types.Subscription, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SubscribeToHeads")
+ }
+
+ var r0 <-chan HEAD
+ var r1 types.Subscription
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context) (<-chan HEAD, types.Subscription, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) <-chan HEAD); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(<-chan HEAD)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) types.Subscription); ok {
+ r1 = rf(ctx)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(types.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context) error); ok {
+ r2 = rf(ctx)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// mockRPC_SubscribeToHeads_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeToHeads'
+type mockRPC_SubscribeToHeads_Call[CHAIN_ID types.ID, SEQ types.Sequence, ADDR types.Hashable, BLOCK_HASH types.Hashable, TX interface{}, TX_HASH types.Hashable, EVENT interface{}, EVENT_OPS interface{}, TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], FEE feetypes.Fee, HEAD types.Head[BLOCK_HASH], BATCH_ELEM interface{}] struct {
+ *mock.Call
+}
+
+// SubscribeToHeads is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *mockRPC_Expecter[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) SubscribeToHeads(ctx interface{}) *mockRPC_SubscribeToHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ return &mockRPC_SubscribeToHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]{Call: _e.mock.On("SubscribeToHeads", ctx)}
+}
+
+func (_c *mockRPC_SubscribeToHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) Run(run func(ctx context.Context)) *mockRPC_SubscribeToHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *mockRPC_SubscribeToHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) Return(ch <-chan HEAD, sub types.Subscription, err error) *mockRPC_SubscribeToHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ _c.Call.Return(ch, sub, err)
+ return _c
+}
+
+func (_c *mockRPC_SubscribeToHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) RunAndReturn(run func(context.Context) (<-chan HEAD, types.Subscription, error)) *mockRPC_SubscribeToHeads_Call[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM] {
+ _c.Call.Return(run)
+ return _c
+}
+
// SubscribersCount provides a mock function with given fields:
func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, BATCH_ELEM]) SubscribersCount() int32 {
ret := _m.Called()
diff --git a/common/client/mocks/config.go b/common/client/mocks/config.go
index d1007f39f0f..95b57cce0c3 100644
--- a/common/client/mocks/config.go
+++ b/common/client/mocks/config.go
@@ -3,10 +3,11 @@ package mocks
import "time"
type ChainConfig struct {
- IsFinalityTagEnabled bool
- FinalityDepthVal uint32
- NoNewHeadsThresholdVal time.Duration
- FinalizedBlockOffsetVal uint32
+ IsFinalityTagEnabled bool
+ FinalityDepthVal uint32
+ NoNewHeadsThresholdVal time.Duration
+ FinalizedBlockOffsetVal uint32
+ NoNewFinalizedHeadsThresholdVal time.Duration
}
func (t ChainConfig) NodeNoNewHeadsThreshold() time.Duration {
@@ -24,3 +25,7 @@ func (t ChainConfig) FinalityTagEnabled() bool {
func (t ChainConfig) FinalizedBlockOffset() uint32 {
return t.FinalizedBlockOffsetVal
}
+
+func (t ChainConfig) NoNewFinalizedHeadsThreshold() time.Duration {
+ return t.NoNewFinalizedHeadsThresholdVal
+}
diff --git a/common/client/models.go b/common/client/models.go
index 8b616137669..526bb25c887 100644
--- a/common/client/models.go
+++ b/common/client/models.go
@@ -1,6 +1,7 @@
package client
import (
+ "bytes"
"fmt"
)
@@ -74,3 +75,47 @@ func (n NodeTier) String() string {
return fmt.Sprintf("NodeTier(%d)", n)
}
}
+
+// syncStatus - defines problems related to RPC's state synchronization. Can be used as a bitmask to define multiple issues
+type syncStatus int
+
+const (
+ // syncStatusSynced - RPC is fully synced
+ syncStatusSynced = 0
+ // syncStatusNotInSyncWithPool - RPC is lagging behind the highest block observed within the pool of RPCs
+ syncStatusNotInSyncWithPool syncStatus = 1 << iota
+ // syncStatusNoNewHead - RPC failed to produce a new head for too long
+ syncStatusNoNewHead
+ // syncStatusNoNewFinalizedHead - RPC failed to produce a new finalized head for too long
+ syncStatusNoNewFinalizedHead
+ syncStatusLen
+)
+
+func (s syncStatus) String() string {
+ if s == syncStatusSynced {
+ return "Synced"
+ }
+ var result bytes.Buffer
+ for i := syncStatusNotInSyncWithPool; i < syncStatusLen; i = i << 1 {
+ if i&s == 0 {
+ continue
+ }
+ result.WriteString(i.string())
+ result.WriteString(",")
+ }
+ result.Truncate(result.Len() - 1)
+ return result.String()
+}
+
+func (s syncStatus) string() string {
+ switch s {
+ case syncStatusNotInSyncWithPool:
+ return "NotInSyncWithRPCPool"
+ case syncStatusNoNewHead:
+ return "NoNewHead"
+ case syncStatusNoNewFinalizedHead:
+ return "NoNewFinalizedHead"
+ default:
+ return fmt.Sprintf("syncStatus(%d)", s)
+ }
+}
diff --git a/common/client/models_test.go b/common/client/models_test.go
index 2d5dc31b373..a10592c3b68 100644
--- a/common/client/models_test.go
+++ b/common/client/models_test.go
@@ -3,6 +3,8 @@ package client
import (
"strings"
"testing"
+
+ "github.com/stretchr/testify/assert"
)
func TestSendTxReturnCode_String(t *testing.T) {
@@ -14,3 +16,35 @@ func TestSendTxReturnCode_String(t *testing.T) {
}
}
}
+
+func TestSyncStatus_String(t *testing.T) {
+ t.Run("All of the statuses have proper string representation", func(t *testing.T) {
+ for i := syncStatusNotInSyncWithPool; i < syncStatusLen; i <<= 1 {
+ // ensure that i's string representation is not equal to `syncStatus(%d)`
+ assert.NotContains(t, i.String(), "syncStatus(")
+ }
+ })
+ t.Run("Unwraps mask", func(t *testing.T) {
+ testCases := []struct {
+ Mask syncStatus
+ ExpectedStr string
+ }{
+ {
+ ExpectedStr: "Synced",
+ },
+ {
+ Mask: syncStatusNotInSyncWithPool | syncStatusNoNewHead,
+ ExpectedStr: "NotInSyncWithRPCPool,NoNewHead",
+ },
+ {
+ Mask: syncStatusNotInSyncWithPool | syncStatusNoNewHead | syncStatusNoNewFinalizedHead,
+ ExpectedStr: "NotInSyncWithRPCPool,NoNewHead,NoNewFinalizedHead",
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.ExpectedStr, func(t *testing.T) {
+ assert.Equal(t, testCase.ExpectedStr, testCase.Mask.String())
+ })
+ }
+ })
+}
diff --git a/common/client/multi_node.go b/common/client/multi_node.go
index 4d4ea925fe8..c9250a1d620 100644
--- a/common/client/multi_node.go
+++ b/common/client/multi_node.go
@@ -15,6 +15,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/assets"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
+
feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types"
"github.com/smartcontractkit/chainlink/v2/common/types"
)
@@ -821,6 +822,14 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP
return n.RPC().SubscribeNewHead(ctx, channel)
}
+func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) SubscribeToHeads(ctx context.Context) (ch <-chan HEAD, sub types.Subscription, err error) {
+ n, err := c.selectNode()
+ if err != nil {
+ return nil, nil, err
+ }
+ return n.RPC().SubscribeToHeads(ctx)
+}
+
func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT, BATCH_ELEM]) TokenBalance(ctx context.Context, account ADDR, tokenAddr ADDR) (b *big.Int, err error) {
n, err := c.selectNode()
if err != nil {
diff --git a/common/client/node.go b/common/client/node.go
index 5ea31d65961..d6543c772a8 100644
--- a/common/client/node.go
+++ b/common/client/node.go
@@ -49,6 +49,7 @@ type NodeConfig interface {
type ChainConfig interface {
NodeNoNewHeadsThreshold() time.Duration
+ NoNewFinalizedHeadsThreshold() time.Duration
FinalityDepth() uint32
FinalityTagEnabled() bool
FinalizedBlockOffset() uint32
diff --git a/common/client/node_fsm.go b/common/client/node_fsm.go
index 5a5e2554431..e58de071fbc 100644
--- a/common/client/node_fsm.go
+++ b/common/client/node_fsm.go
@@ -2,7 +2,6 @@ package client
import (
"fmt"
- "math/big"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
@@ -240,11 +239,11 @@ func (n *node[CHAIN_ID, HEAD, RPC]) transitionToInSync(fn func()) {
// declareOutOfSync puts a node into OutOfSync state, disconnecting all current
// clients and making it unavailable for use until back in-sync.
-func (n *node[CHAIN_ID, HEAD, RPC]) declareOutOfSync(isOutOfSync func(num int64, td *big.Int) bool) {
+func (n *node[CHAIN_ID, HEAD, RPC]) declareOutOfSync(syncIssues syncStatus) {
n.transitionToOutOfSync(func() {
- n.lfcLog.Errorw("RPC Node is out of sync", "nodeState", n.state)
+ n.lfcLog.Errorw("RPC Node is out of sync", "nodeState", n.state, "syncIssues", syncIssues)
n.wg.Add(1)
- go n.outOfSyncLoop(isOutOfSync)
+ go n.outOfSyncLoop(syncIssues)
})
}
diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go
index 39e17bb4972..40d9a9ef6ef 100644
--- a/common/client/node_lifecycle.go
+++ b/common/client/node_lifecycle.go
@@ -7,6 +7,8 @@ import (
"math/big"
"time"
+ "github.com/smartcontractkit/chainlink/v2/common/types"
+
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
@@ -86,33 +88,37 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() {
}
noNewHeadsTimeoutThreshold := n.chainCfg.NodeNoNewHeadsThreshold()
+ noNewFinalizedBlocksTimeoutThreshold := n.chainCfg.NoNewFinalizedHeadsThreshold()
pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold()
pollInterval := n.nodePoolCfg.PollInterval()
lggr := logger.Sugared(n.lfcLog).Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold)
lggr.Tracew("Alive loop starting", "nodeState", n.getCachedState())
- headsC := make(chan HEAD)
- sub, err := n.rpc.SubscribeNewHead(ctx, headsC)
+ headsSub, err := n.registerNewSubscription(ctx, lggr.With("subscriptionType", "heads"),
+ n.chainCfg.NodeNoNewHeadsThreshold(), n.rpc.SubscribeToHeads)
if err != nil {
- lggr.Errorw("Initial subscribe for heads failed", "nodeState", n.getCachedState())
+ lggr.Errorw("Initial subscribe for heads failed", "nodeState", n.getCachedState(), "err", err)
n.declareUnreachable()
return
}
- // TODO: nit fix. If multinode switches primary node before we set sub as AliveSub, sub will be closed and we'll
- // falsely transition this node to unreachable state
- n.rpc.SetAliveLoopSub(sub)
- defer sub.Unsubscribe()
-
- var outOfSyncT *time.Ticker
- var outOfSyncTC <-chan time.Time
- if noNewHeadsTimeoutThreshold > 0 {
- lggr.Debugw("Head liveness checking enabled", "nodeState", n.getCachedState())
- outOfSyncT = time.NewTicker(noNewHeadsTimeoutThreshold)
- defer outOfSyncT.Stop()
- outOfSyncTC = outOfSyncT.C
- } else {
- lggr.Debug("Head liveness checking disabled")
+
+ // TODO: will be removed as part of merging effort with BCI-2875
+ n.rpc.SetAliveLoopSub(headsSub.sub)
+
+ defer headsSub.Unsubscribe()
+
+ var finalizedHeadsSub headSubscription[HEAD]
+ if n.chainCfg.FinalityTagEnabled() {
+ finalizedHeadsSub, err = n.registerNewSubscription(ctx, lggr.With("subscriptionType", "finalizedHeads"),
+ n.chainCfg.NoNewFinalizedHeadsThreshold(), n.rpc.SubscribeToFinalizedHeads)
+ if err != nil {
+ lggr.Errorw("Failed to subscribe to finalized heads", "err", err)
+ n.declareUnreachable()
+ return
+ }
+
+ defer finalizedHeadsSub.Unsubscribe()
}
var pollCh <-chan time.Time
@@ -131,14 +137,6 @@ 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
- }
-
localHighestChainInfo, _ := n.rpc.GetInterceptedChainInfo()
var pollFailures uint32
@@ -149,7 +147,8 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() {
case <-pollCh:
promPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc()
lggr.Tracew("Polling for version", "nodeState", n.getCachedState(), "pollFailures", pollFailures)
- version, err := func(ctx context.Context) (string, error) {
+ var version string
+ version, err = func(ctx context.Context) (string, error) {
ctx, cancel := context.WithTimeout(ctx, pollInterval)
defer cancel()
return n.RPC().ClientVersion(ctx)
@@ -177,47 +176,33 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() {
n.declareUnreachable()
return
}
- _, ci := n.StateAndLatest()
- if outOfSync, liveNodes := n.syncStatus(ci.BlockNumber, ci.TotalDifficulty); outOfSync {
+ _, latestChainInfo := n.StateAndLatest()
+ if outOfSync, liveNodes := n.isOutOfSyncWithPool(latestChainInfo); outOfSync {
// note: there must be another live node for us to be out of sync
- lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", ci.BlockNumber, "totalDifficulty", ci.TotalDifficulty, "nodeState", n.getCachedState())
+ lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", latestChainInfo.BlockNumber, "totalDifficulty", latestChainInfo.TotalDifficulty, "nodeState", n.getCachedState())
if liveNodes < 2 {
lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState)
continue
}
- n.declareOutOfSync(n.isOutOfSync)
+ n.declareOutOfSync(syncStatusNotInSyncWithPool)
return
}
- case bh, open := <-headsC:
+ case bh, open := <-headsSub.Heads:
if !open {
lggr.Errorw("Subscription channel unexpectedly closed", "nodeState", n.getCachedState())
n.declareUnreachable()
return
}
- promPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc()
- lggr.Tracew("Got head", "head", bh)
- if bh.BlockNumber() > localHighestChainInfo.BlockNumber {
- promPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.BlockNumber()))
- lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", localHighestChainInfo.BlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.getCachedState())
- localHighestChainInfo.BlockNumber = bh.BlockNumber()
- } else {
- lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", localHighestChainInfo.BlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.getCachedState())
- }
- if outOfSyncT != nil {
- outOfSyncT.Reset(noNewHeadsTimeoutThreshold)
- }
- if !n.chainCfg.FinalityTagEnabled() {
- latestFinalizedBN := max(bh.BlockNumber()-int64(n.chainCfg.FinalityDepth()), 0)
- if latestFinalizedBN > localHighestChainInfo.FinalizedBlockNumber {
- promPoolRPCNodeHighestFinalizedBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(latestFinalizedBN))
- localHighestChainInfo.FinalizedBlockNumber = latestFinalizedBN
- }
+
+ receivedNewHead := n.onNewHead(lggr, &localHighestChainInfo, bh)
+ if receivedNewHead && noNewHeadsTimeoutThreshold > 0 {
+ headsSub.ResetTimer(noNewHeadsTimeoutThreshold)
}
- case err := <-sub.Err():
+ case err = <-headsSub.Errors:
lggr.Errorw("Subscription was terminated", "err", err, "nodeState", n.getCachedState())
n.declareUnreachable()
return
- case <-outOfSyncTC:
+ case <-headsSub.NoNewHeads:
// We haven't received a head on the channel for at least the
// threshold amount of time, mark it broken
lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, localHighestChainInfo.BlockNumber), "nodeState", n.getCachedState(), "latestReceivedBlockNumber", localHighestChainInfo.BlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold)
@@ -226,47 +211,151 @@ 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(noNewHeadsTimeoutThreshold))
+ headsSub.ResetTimer(zombieNodeCheckInterval(noNewHeadsTimeoutThreshold))
continue
}
}
- n.declareOutOfSync(func(num int64, td *big.Int) bool { return num < localHighestChainInfo.BlockNumber })
+ n.declareOutOfSync(syncStatusNoNewHead)
return
- case <-pollFinalizedHeadCh:
- latestFinalized, err := func(ctx context.Context) (HEAD, error) {
- ctx, cancel := context.WithTimeout(ctx, n.nodePoolCfg.FinalizedBlockPollInterval())
- defer cancel()
- return n.RPC().LatestFinalizedBlock(ctx)
- }(ctx)
- if err != nil {
- lggr.Warnw("Failed to fetch latest finalized block", "err", err)
- continue
+ case latestFinalized, open := <-finalizedHeadsSub.Heads:
+ if !open {
+ lggr.Errorw("Finalized heads subscription channel unexpectedly closed", "nodeState", n.getCachedState())
+ n.declareUnreachable()
+ return
}
- if !latestFinalized.IsValid() {
- lggr.Warn("Latest finalized block is not valid")
- continue
+ receivedNewHead := n.onNewFinalizedHead(lggr, &localHighestChainInfo, latestFinalized)
+ if receivedNewHead && noNewFinalizedBlocksTimeoutThreshold > 0 {
+ finalizedHeadsSub.ResetTimer(noNewFinalizedBlocksTimeoutThreshold)
}
-
- latestFinalizedBN := latestFinalized.BlockNumber()
- if latestFinalizedBN > localHighestChainInfo.FinalizedBlockNumber {
- promPoolRPCNodeHighestFinalizedBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(latestFinalizedBN))
- localHighestChainInfo.FinalizedBlockNumber = latestFinalizedBN
+ case <-finalizedHeadsSub.NoNewHeads:
+ // We haven't received a finalized head on the channel for at least the
+ // threshold amount of time, mark it broken
+ lggr.Errorw(fmt.Sprintf("RPC's finalized state is out of sync; no new finalized heads received for %s (last finalized head received was %v)", noNewFinalizedBlocksTimeoutThreshold, localHighestChainInfo.FinalizedBlockNumber), "latestReceivedBlockNumber", localHighestChainInfo.BlockNumber)
+ if n.poolInfoProvider != nil {
+ if l, _ := n.poolInfoProvider.LatestChainInfo(); l < 2 {
+ lggr.Criticalf("RPC's finalized state is 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
+ finalizedHeadsSub.ResetTimer(zombieNodeCheckInterval(noNewFinalizedBlocksTimeoutThreshold))
+ continue
+ }
}
+ n.declareOutOfSync(syncStatusNoNewFinalizedHead)
+ return
+ case <-finalizedHeadsSub.Errors:
+ lggr.Errorw("Finalized heads subscription was terminated", "err", err)
+ n.declareUnreachable()
+ return
}
}
}
-func (n *node[CHAIN_ID, HEAD, RPC]) isOutOfSync(num int64, td *big.Int) (outOfSync bool) {
- outOfSync, _ = n.syncStatus(num, td)
- return
+type headSubscription[HEAD any] struct {
+ Heads <-chan HEAD
+ Errors <-chan error
+ NoNewHeads <-chan time.Time
+
+ noNewHeadsTicker *time.Ticker
+ sub types.Subscription
+ cleanUpTasks []func()
+}
+
+func (sub *headSubscription[HEAD]) ResetTimer(duration time.Duration) {
+ sub.noNewHeadsTicker.Reset(duration)
+}
+
+func (sub *headSubscription[HEAD]) Unsubscribe() {
+ for _, doCleanUp := range sub.cleanUpTasks {
+ doCleanUp()
+ }
+}
+
+func (n *node[CHAIN_ID, HEAD, PRC]) registerNewSubscription(ctx context.Context, lggr logger.SugaredLogger,
+ noNewDataThreshold time.Duration, newSub func(ctx context.Context) (<-chan HEAD, types.Subscription, error)) (headSubscription[HEAD], error) {
+ result := headSubscription[HEAD]{}
+ var err error
+ var sub types.Subscription
+ result.Heads, sub, err = newSub(ctx)
+ if err != nil {
+ return result, err
+ }
+
+ result.Errors = sub.Err()
+ lggr.Debug("Successfully subscribed")
+
+ // TODO: will be removed as part of merging effort with BCI-2875
+ result.sub = sub
+ //n.stateMu.Lock()
+ //n.healthCheckSubs = append(n.healthCheckSubs, sub)
+ //n.stateMu.Unlock()
+
+ result.cleanUpTasks = append(result.cleanUpTasks, sub.Unsubscribe)
+
+ if noNewDataThreshold > 0 {
+ lggr.Debugw("Subscription liveness checking enabled")
+ result.noNewHeadsTicker = time.NewTicker(noNewDataThreshold)
+ result.NoNewHeads = result.noNewHeadsTicker.C
+ result.cleanUpTasks = append(result.cleanUpTasks, result.noNewHeadsTicker.Stop)
+ } else {
+ lggr.Debug("Subscription liveness checking disabled")
+ }
+
+ return result, nil
}
-// syncStatus returns outOfSync true if num or td is more than SyncThresold behind the best node.
+func (n *node[CHAIN_ID, HEAD, RPC]) onNewFinalizedHead(lggr logger.SugaredLogger, chainInfo *ChainInfo, latestFinalized HEAD) bool {
+ if !latestFinalized.IsValid() {
+ lggr.Warn("Latest finalized block is not valid")
+ return false
+ }
+
+ latestFinalizedBN := latestFinalized.BlockNumber()
+ lggr.Tracew("Got latest finalized head", "latestFinalized", latestFinalized)
+ if latestFinalizedBN <= chainInfo.FinalizedBlockNumber {
+ lggr.Tracew("Ignoring previously seen finalized block number")
+ return false
+ }
+
+ promPoolRPCNodeHighestFinalizedBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(latestFinalizedBN))
+ chainInfo.FinalizedBlockNumber = latestFinalizedBN
+ return true
+}
+
+func (n *node[CHAIN_ID, HEAD, RPC]) onNewHead(lggr logger.SugaredLogger, chainInfo *ChainInfo, head HEAD) bool {
+ if !head.IsValid() {
+ lggr.Warn("Latest head is not valid")
+ return false
+ }
+
+ promPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc()
+ lggr.Tracew("Got head", "head", head)
+ lggr = lggr.With("latestReceivedBlockNumber", chainInfo.BlockNumber, "blockNumber", head.BlockNumber(), "nodeState", n.getCachedState())
+ if head.BlockNumber() <= chainInfo.BlockNumber {
+ lggr.Tracew("Ignoring previously seen block number")
+ return false
+ }
+
+ promPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(head.BlockNumber()))
+ chainInfo.BlockNumber = head.BlockNumber()
+
+ if !n.chainCfg.FinalityTagEnabled() {
+ latestFinalizedBN := max(head.BlockNumber()-int64(n.chainCfg.FinalityDepth()), 0)
+ if latestFinalizedBN > chainInfo.FinalizedBlockNumber {
+ promPoolRPCNodeHighestFinalizedBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(latestFinalizedBN))
+ chainInfo.FinalizedBlockNumber = latestFinalizedBN
+ }
+ }
+
+ return true
+}
+
+// isOutOfSyncWithPool returns outOfSync true if num or td is more than SyncThresold behind the best node.
// Always returns outOfSync false for SyncThreshold 0.
// liveNodes is only included when outOfSync is true.
-func (n *node[CHAIN_ID, HEAD, RPC]) syncStatus(num int64, td *big.Int) (outOfSync bool, liveNodes int) {
+func (n *node[CHAIN_ID, HEAD, RPC]) isOutOfSyncWithPool(localState ChainInfo) (outOfSync bool, liveNodes int) {
if n.poolInfoProvider == nil {
+ n.lfcLog.Warn("skipping sync state against the pool - should only occur in tests")
return // skip for tests
}
threshold := n.nodePoolCfg.SyncThreshold()
@@ -278,22 +367,23 @@ func (n *node[CHAIN_ID, HEAD, RPC]) syncStatus(num int64, td *big.Int) (outOfSyn
mode := n.nodePoolCfg.SelectionMode()
switch mode {
case NodeSelectionModeHighestHead, NodeSelectionModeRoundRobin, NodeSelectionModePriorityLevel:
- return num < ci.BlockNumber-int64(threshold), ln
+ return localState.BlockNumber < ci.BlockNumber-int64(threshold), ln
case NodeSelectionModeTotalDifficulty:
bigThreshold := big.NewInt(int64(threshold))
- return td.Cmp(bigmath.Sub(ci.TotalDifficulty, bigThreshold)) < 0, ln
+ return localState.TotalDifficulty.Cmp(bigmath.Sub(ci.TotalDifficulty, bigThreshold)) < 0, ln
default:
panic("unrecognized NodeSelectionMode: " + mode)
}
}
const (
- msgReceivedBlock = "Received block for RPC node, waiting until back in-sync to mark as live again"
- msgInSync = "RPC node back in sync"
+ msgReceivedBlock = "Received block for RPC node, waiting until back in-sync to mark as live again"
+ msgReceivedFinalizedBlock = "Received new finalized block for RPC node, waiting until back in-sync to mark as live again"
+ msgInSync = "RPC node back in sync"
)
// outOfSyncLoop takes an OutOfSync node and waits until isOutOfSync returns false to go back to live status
-func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) {
+func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(syncIssues syncStatus) {
defer n.wg.Done()
ctx, cancel := n.newCtx()
defer cancel()
@@ -312,8 +402,9 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td
outOfSyncAt := time.Now()
- lggr := logger.Sugared(logger.Named(n.lfcLog, "OutOfSync"))
- lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.getCachedState())
+ // set logger name to OutOfSync or FinalizedBlockOutOfSync
+ lggr := logger.Sugared(logger.Named(n.lfcLog, n.getCachedState().String())).With("nodeState", n.getCachedState())
+ lggr.Debugw("Trying to revive out-of-sync RPC node")
// Need to redial since out-of-sync nodes are automatically disconnected
state := n.createVerifiedConn(ctx, lggr)
@@ -322,46 +413,118 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td
return
}
- lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.getCachedState())
-
- ch := make(chan HEAD)
- sub, err := n.rpc.SubscribeNewHead(ctx, ch)
+ noNewHeadsTimeoutThreshold := n.chainCfg.NodeNoNewHeadsThreshold()
+ headsSub, err := n.registerNewSubscription(ctx, lggr.With("subscriptionType", "heads"),
+ noNewHeadsTimeoutThreshold, n.rpc.SubscribeToHeads)
if err != nil {
- lggr.Errorw("Failed to subscribe heads on out-of-sync RPC node", "nodeState", n.getCachedState(), "err", err)
+ lggr.Errorw("Failed to subscribe heads on out-of-sync RPC node", "err", err)
n.declareUnreachable()
return
}
- defer sub.Unsubscribe()
+ lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node")
+ defer headsSub.Unsubscribe()
+
+ noNewFinalizedBlocksTimeoutThreshold := n.chainCfg.NoNewFinalizedHeadsThreshold()
+ var finalizedHeadsSub headSubscription[HEAD]
+ if n.chainCfg.FinalityTagEnabled() {
+ finalizedHeadsSub, err = n.registerNewSubscription(ctx, lggr.With("subscriptionType", "finalizedHeads"),
+ noNewFinalizedBlocksTimeoutThreshold, n.rpc.SubscribeToFinalizedHeads)
+ if err != nil {
+ lggr.Errorw("Subscribe to finalized heads failed on out-of-sync RPC node", "err", err)
+ n.declareUnreachable()
+ return
+ }
+
+ lggr.Tracew("Successfully subscribed to finalized heads feed on out-of-sync RPC node")
+ defer finalizedHeadsSub.Unsubscribe()
+ }
+
+ _, localHighestChainInfo := n.rpc.GetInterceptedChainInfo()
for {
+ if syncIssues == syncStatusSynced {
+ // back in-sync! flip back into alive loop
+ lggr.Infow(fmt.Sprintf("%s: %s. Node was out-of-sync for %s", msgInSync, n.String(), time.Since(outOfSyncAt)))
+ n.declareInSync()
+ return
+ }
+
select {
case <-ctx.Done():
return
- case head, open := <-ch:
+ case head, open := <-headsSub.Heads:
if !open {
- lggr.Error("Subscription channel unexpectedly closed", "nodeState", n.getCachedState())
+ lggr.Errorw("Subscription channel unexpectedly closed", "nodeState", n.getCachedState())
n.declareUnreachable()
return
}
- if !isOutOfSync(head.BlockNumber(), head.BlockDifficulty()) {
- // back in-sync! flip back into alive loop
- lggr.Infow(fmt.Sprintf("%s: %s. Node was out-of-sync for %s", msgInSync, n.String(), time.Since(outOfSyncAt)), "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.getCachedState())
- n.declareInSync()
- return
+
+ if !n.onNewHead(lggr, &localHighestChainInfo, head) {
+ continue
+ }
+
+ // received a new head - clear NoNewHead flag
+ syncIssues &= ^syncStatusNoNewHead
+ if outOfSync, _ := n.isOutOfSyncWithPool(localHighestChainInfo); !outOfSync {
+ // we caught up with the pool - clear NotInSyncWithPool flag
+ syncIssues &= ^syncStatusNotInSyncWithPool
+ } else {
+ // we've received new head, but lagging behind the pool, add NotInSyncWithPool flag to prevent false transition to alive
+ syncIssues |= syncStatusNotInSyncWithPool
+ }
+
+ if noNewHeadsTimeoutThreshold > 0 {
+ headsSub.ResetTimer(noNewHeadsTimeoutThreshold)
}
- lggr.Debugw(msgReceivedBlock, "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.getCachedState())
- case <-time.After(zombieNodeCheckInterval(n.chainCfg.NodeNoNewHeadsThreshold())):
+
+ lggr.Debugw(msgReceivedBlock, "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "syncIssues", syncIssues)
+ case <-time.After(zombieNodeCheckInterval(noNewHeadsTimeoutThreshold)):
if n.poolInfoProvider != nil {
if l, _ := n.poolInfoProvider.LatestChainInfo(); 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")
+ lggr.Criticalw("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", "syncIssues", syncIssues)
n.declareInSync()
return
}
}
- case err := <-sub.Err():
- lggr.Errorw("Subscription was terminated", "nodeState", n.getCachedState(), "err", err)
+ case err := <-headsSub.Errors:
+ lggr.Errorw("Subscription was terminated", "err", err)
+ n.declareUnreachable()
+ return
+ case <-headsSub.NoNewHeads:
+ // we are not resetting the timer, as there is no need to add syncStatusNoNewHead until it's removed on new head.
+ syncIssues |= syncStatusNoNewHead
+ lggr.Debugw(fmt.Sprintf("No new heads received for %s. Node stays out-of-sync due to sync issues: %s", noNewHeadsTimeoutThreshold, syncIssues))
+ case latestFinalized, open := <-finalizedHeadsSub.Heads:
+ if !open {
+ lggr.Errorw("Finalized heads subscription channel unexpectedly closed")
+ n.declareUnreachable()
+ return
+ }
+ if !latestFinalized.IsValid() {
+ lggr.Warn("Latest finalized block is not valid")
+ continue
+ }
+
+ receivedNewHead := n.onNewFinalizedHead(lggr, &localHighestChainInfo, latestFinalized)
+ if !receivedNewHead {
+ continue
+ }
+
+ // on new finalized head remove NoNewFinalizedHead flag from the mask
+ syncIssues &= ^syncStatusNoNewFinalizedHead
+ if noNewFinalizedBlocksTimeoutThreshold > 0 {
+ finalizedHeadsSub.ResetTimer(noNewFinalizedBlocksTimeoutThreshold)
+ }
+
+ lggr.Debugw(msgReceivedFinalizedBlock, "blockNumber", latestFinalized.BlockNumber(), "syncIssues", syncIssues)
+ case err := <-finalizedHeadsSub.Errors:
+ lggr.Errorw("Finalized head subscription was terminated", "err", err)
n.declareUnreachable()
return
+ case <-finalizedHeadsSub.NoNewHeads:
+ // we are not resetting the timer, as there is no need to add syncStatusNoNewFinalizedHead until it's removed on new finalized head.
+ syncIssues |= syncStatusNoNewFinalizedHead
+ lggr.Debugw(fmt.Sprintf("No new finalized heads received for %s. Node stays out-of-sync due to sync issues: %s", noNewFinalizedBlocksTimeoutThreshold, syncIssues))
}
}
}
diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go
index 863a15a1fad..833bccf7f29 100644
--- a/common/client/node_lifecycle_test.go
+++ b/common/client/node_lifecycle_test.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"math/big"
+ "sync"
"sync/atomic"
"testing"
@@ -49,7 +50,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
expectedError := errors.New("failed to subscribe to rpc")
rpc.On("DisconnectAll").Once()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(nil, expectedError).Once()
+ rpc.On("SubscribeToHeads", mock.Anything).Return(nil, nil, expectedError).Once()
// might be called in unreachable loop
rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe()
node.declareAlive()
@@ -74,7 +75,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
close(errChan)
sub.On("Err").Return((<-chan error)(errChan)).Once()
sub.On("Unsubscribe").Once()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once()
+ rpc.On("SubscribeToHeads", mock.Anything).Return(nil, sub, nil).Once()
rpc.On("SetAliveLoopSub", sub).Once()
// disconnects all on transfer to unreachable
rpc.On("DisconnectAll").Once()
@@ -89,7 +90,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
sub := mocks.NewSubscription(t)
sub.On("Err").Return((<-chan error)(nil))
sub.On("Unsubscribe").Once()
- opts.rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once()
+ opts.rpc.On("SubscribeToHeads", mock.Anything).Return(make(<-chan Head), sub, nil)
opts.rpc.On("SetAliveLoopSub", sub).Once()
return newDialedNode(t, opts)
}
@@ -105,7 +106,7 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
})
defer func() { assert.NoError(t, node.close()) }()
node.declareAlive()
- tests.AssertLogEventually(t, observedLogs, "Head liveness checking disabled")
+ tests.AssertLogEventually(t, observedLogs, "Subscription liveness checking disabled")
tests.AssertLogEventually(t, observedLogs, "Polling disabled")
assert.Equal(t, nodeStateAlive, node.State())
})
@@ -340,18 +341,21 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
tests.AssertLogEventually(t, observedLogs, fmt.Sprintf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState))
assert.Equal(t, nodeStateAlive, node.State())
})
- t.Run("rpc closed head channel", func(t *testing.T) {
- t.Parallel()
- rpc := newMockNodeClient[types.ID, Head](t)
- rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
+ newSub := func(t *testing.T) *mocks.Subscription {
sub := mocks.NewSubscription(t)
sub.On("Err").Return((<-chan error)(nil))
sub.On("Unsubscribe").Once()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
- ch := args.Get(1).(chan<- Head)
+ return sub
+ }
+ t.Run("rpc closed head channel", func(t *testing.T) {
+ t.Parallel()
+ rpc := newMockNodeClient[types.ID, Head](t)
+ ch := make(chan Head)
+ rpc.On("SubscribeToHeads", mock.Anything).Run(func(args mock.Arguments) {
close(ch)
- }).Return(sub, nil).Once()
- rpc.On("SetAliveLoopSub", sub).Once()
+ }).Return((<-chan Head)(ch), newSub(t), nil).Once()
+ rpc.On("SetAliveLoopSub", mock.Anything).Once()
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel)
node := newDialedNode(t, testNodeOpts{
lggr: lggr,
@@ -380,10 +384,10 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
const finalityDepth = 10
const expectedBlock = 990
rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
- ch := args.Get(1).(chan<- Head)
+ ch := make(chan Head)
+ rpc.On("SubscribeToHeads", mock.Anything).Run(func(args mock.Arguments) {
go writeHeads(t, ch, head{BlockNumber: blockNumber - 1}, head{BlockNumber: blockNumber}, head{BlockNumber: blockNumber - 1})
- }).Return(sub, nil).Once()
+ }).Return((<-chan Head)(ch), sub, nil).Once()
rpc.On("SetAliveLoopSub", sub).Once()
name := "node-" + rand.Str(5)
node := newDialedNode(t, testNodeOpts{
@@ -403,18 +407,13 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
return float64(expectedBlock) == m.Gauge.GetValue()
})
})
- t.Run("Logs warning if failed to get finalized block", func(t *testing.T) {
+ t.Run("If fails to subscribe to latest finalized blocks, transitions to unreachable ", func(t *testing.T) {
t.Parallel()
rpc := newMockNodeClient[types.ID, Head](t)
- rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
- 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("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once()
- rpc.On("SetAliveLoopSub", sub).Once()
+ expectedError := errors.New("failed to subscribe to finalized heads")
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return(nil, mocks.NewSubscription(t), expectedError).Once()
lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel)
- node := newDialedNode(t, testNodeOpts{
+ node := newSubscribedNode(t, testNodeOpts{
config: testNodeConfig{
finalizedBlockPollInterval: tests.TestInterval,
},
@@ -425,26 +424,31 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
lggr: lggr,
})
defer func() { assert.NoError(t, node.close()) }()
+ // disconnects all on transfer to unreachable or outOfSync
+ rpc.On("DisconnectAll").Once()
+ // might be called in unreachable loop
+ rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe()
node.declareAlive()
- tests.AssertLogEventually(t, observedLogs, "Failed to fetch latest finalized block")
+ tests.AssertLogEventually(t, observedLogs, "Failed to subscribe to finalized heads")
+ tests.AssertEventually(t, func() bool {
+ return nodeStateUnreachable == node.State()
+ })
})
t.Run("Logs warning if latest finalized block is not valid", func(t *testing.T) {
t.Parallel()
rpc := newMockNodeClient[types.ID, Head](t)
+ ch := make(chan Head, 1)
head := newMockHead(t)
head.On("IsValid").Return(false)
- rpc.On("LatestFinalizedBlock", mock.Anything).Return(head, nil)
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Run(func(args mock.Arguments) {
+ ch <- head
+ }).Return((<-chan Head)(ch), newSub(t), nil).Once()
rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
- sub := mocks.NewSubscription(t)
- sub.On("Err").Return((<-chan error)(nil))
- sub.On("Unsubscribe").Once()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once()
- rpc.On("SetAliveLoopSub", sub).Once()
+ rpc.On("SubscribeToHeads", mock.Anything).Return(make(<-chan Head), newSub(t), nil).Once()
+ rpc.On("SetAliveLoopSub", mock.Anything).Once()
lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel)
node := newDialedNode(t, testNodeOpts{
- config: testNodeConfig{
- finalizedBlockPollInterval: tests.TestInterval,
- },
+ config: testNodeConfig{},
chainConfig: clientMocks.ChainConfig{
IsFinalityTagEnabled: true,
},
@@ -455,29 +459,17 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
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.Run("On new finalized block updates corresponding 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("SubscribeNewHead", mock.Anything, mock.Anything).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()
+ ch := make(chan Head)
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return((<-chan Head)(ch), newSub(t), nil).Once()
rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
- rpc.On("SetAliveLoopSub", sub).Once()
name := "node-" + rand.Str(5)
- node := newDialedNode(t, testNodeOpts{
- config: testNodeConfig{
- finalizedBlockPollInterval: tests.TestInterval,
- },
+ node := newSubscribedNode(t, testNodeOpts{
+ config: testNodeConfig{},
chainConfig: clientMocks.ChainConfig{
FinalityDepthVal: finalityDepth,
IsFinalityTagEnabled: true,
@@ -488,6 +480,12 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
})
defer func() { assert.NoError(t, node.close()) }()
node.declareAlive()
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ writeHeads(t, ch, head{BlockNumber: expectedBlock - 1}, head{BlockNumber: expectedBlock}, head{BlockNumber: expectedBlock - 1})
+ }()
tests.AssertEventually(t, func() bool {
metric, err := promPoolRPCNodeHighestFinalizedBlock.GetMetricWithLabelValues(big.NewInt(1).String(), name)
require.NoError(t, err)
@@ -496,6 +494,123 @@ func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) {
return float64(expectedBlock) == m.Gauge.GetValue()
})
})
+ t.Run("If finalized heads channel is closed, transitions to unreachable", func(t *testing.T) {
+ t.Parallel()
+ rpc := newMockNodeClient[types.ID, Head](t)
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
+ ch := make(chan Head)
+ close(ch)
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return((<-chan Head)(ch), newSub(t), nil).Once()
+ lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel)
+ node := newSubscribedNode(t, testNodeOpts{
+ chainConfig: clientMocks.ChainConfig{
+ IsFinalityTagEnabled: true,
+ },
+ rpc: rpc,
+ lggr: lggr,
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+ // disconnects all on transfer to unreachable or outOfSync
+ rpc.On("DisconnectAll").Once()
+ // might be called in unreachable loop
+ rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe()
+ node.declareAlive()
+ tests.AssertLogEventually(t, observedLogs, "Finalized heads subscription channel unexpectedly closed")
+ tests.AssertEventually(t, func() bool {
+ return nodeStateUnreachable == node.State()
+ })
+ })
+ t.Run("when no new finalized heads received for threshold, transitions to out of sync", func(t *testing.T) {
+ t.Parallel()
+ rpc := newMockNodeClient[types.ID, Head](t)
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
+ ch := make(chan Head, 1)
+ ch <- head{BlockNumber: 10}.ToMockHead(t)
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return((<-chan Head)(ch), newSub(t), nil).Once()
+ lggr, observed := logger.TestObserved(t, zap.DebugLevel)
+ noNewFinalizedHeadsThreshold := tests.TestInterval
+ node := newSubscribedNode(t, testNodeOpts{
+ config: testNodeConfig{},
+ chainConfig: clientMocks.ChainConfig{
+ NoNewFinalizedHeadsThresholdVal: noNewFinalizedHeadsThreshold,
+ IsFinalityTagEnabled: true,
+ },
+ rpc: rpc,
+ lggr: lggr,
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+ // tries to redial in outOfSync
+ rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Run(func(_ mock.Arguments) {
+ assert.Equal(t, nodeStateOutOfSync, node.State())
+ }).Once()
+ // disconnects all on transfer to unreachable or outOfSync
+ rpc.On("DisconnectAll").Maybe()
+ // might be called in unreachable loop
+ rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe()
+ node.declareAlive()
+ tests.AssertLogEventually(t, observed, fmt.Sprintf("RPC's finalized state is out of sync; no new finalized heads received for %s (last finalized head received was 10)", noNewFinalizedHeadsThreshold))
+ tests.AssertEventually(t, func() bool {
+ // right after outOfSync we'll transfer to unreachable due to returned error on Dial
+ // we check that we were in out of sync state on first Dial call
+ return node.State() == nodeStateUnreachable
+ })
+ })
+ t.Run("when no new finalized heads received for threshold but we are the last live node, forcibly stays alive", func(t *testing.T) {
+ t.Parallel()
+ rpc := newMockNodeClient[types.ID, Head](t)
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return(make(<-chan Head), newSub(t), nil).Once()
+ lggr, observed := logger.TestObserved(t, zap.DebugLevel)
+ noNewFinalizedHeadsThreshold := tests.TestInterval
+ node := newSubscribedNode(t, testNodeOpts{
+ config: testNodeConfig{},
+ chainConfig: clientMocks.ChainConfig{
+ NoNewFinalizedHeadsThresholdVal: noNewFinalizedHeadsThreshold,
+ IsFinalityTagEnabled: true,
+ },
+ rpc: rpc,
+ lggr: lggr,
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+ poolInfo := newMockPoolChainInfoProvider(t)
+ poolInfo.On("LatestChainInfo").Return(1, ChainInfo{
+ BlockNumber: 20,
+ TotalDifficulty: big.NewInt(10),
+ }).Once()
+ node.SetPoolChainInfoProvider(poolInfo)
+ node.declareAlive()
+ tests.AssertLogEventually(t, observed, fmt.Sprintf("RPC's finalized state is out of sync; %s %s", msgCannotDisable, msgDegradedState))
+ assert.Equal(t, nodeStateAlive, node.State())
+ })
+ t.Run("If finalized subscription returns an error, transitions to unreachable", func(t *testing.T) {
+ t.Parallel()
+ rpc := newMockNodeClient[types.ID, Head](t)
+ rpc.On("DisconnectAll").Once()
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
+ sub := mocks.NewSubscription(t)
+ errCh := make(chan error, 1)
+ errCh <- errors.New("subscription failed")
+ sub.On("Err").Return((<-chan error)(errCh))
+ sub.On("Unsubscribe").Once()
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return((<-chan Head)(nil), sub, nil).Once()
+ lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel)
+ node := newSubscribedNode(t, testNodeOpts{
+ chainConfig: clientMocks.ChainConfig{
+ IsFinalityTagEnabled: true,
+ },
+ rpc: rpc,
+ lggr: lggr,
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+ // disconnects all on transfer to unreachable or outOfSync
+ // might be called in unreachable loop
+ rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe()
+ node.declareAlive()
+ tests.AssertLogEventually(t, observedLogs, "Finalized heads subscription was terminated")
+ tests.AssertEventually(t, func() bool {
+ return nodeStateUnreachable == node.State()
+ })
+ })
}
type head struct {
@@ -525,9 +640,10 @@ func writeHeads(t *testing.T, ch chan<- Head, heads ...head) {
func setupRPCForAliveLoop(t *testing.T, rpc *mockNodeClient[types.ID, Head]) {
rpc.On("Dial", mock.Anything).Return(nil).Maybe()
aliveSubscription := mocks.NewSubscription(t)
- aliveSubscription.On("Err").Return((<-chan error)(nil)).Maybe()
+ aliveSubscription.On("Err").Return(nil).Maybe()
aliveSubscription.On("Unsubscribe").Maybe()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(aliveSubscription, nil).Maybe()
+ rpc.On("SubscribeToHeads", mock.Anything).Return(make(<-chan Head), aliveSubscription, nil).Maybe()
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return(make(<-chan Head), aliveSubscription, nil).Maybe()
rpc.On("SetAliveLoopSub", mock.Anything).Maybe()
rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Maybe()
}
@@ -544,22 +660,18 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
return node
}
- stubIsOutOfSync := func(num int64, td *big.Int) bool {
- return false
- }
-
t.Run("returns on closed", func(t *testing.T) {
t.Parallel()
node := newTestNode(t, testNodeOpts{})
node.setState(nodeStateClosed)
node.wg.Add(1)
- node.outOfSyncLoop(stubIsOutOfSync)
+ node.outOfSyncLoop(syncStatusNotInSyncWithPool)
})
t.Run("on old blocks stays outOfSync and returns on close", func(t *testing.T) {
t.Parallel()
rpc := newMockNodeClient[types.ID, Head](t)
nodeChainID := types.RandomID()
- lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel)
+ lggr := logger.Test(t)
node := newAliveNode(t, testNodeOpts{
rpc: rpc,
chainID: nodeChainID,
@@ -569,21 +681,27 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
rpc.On("Dial", mock.Anything).Return(nil).Once()
rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once()
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: 0}, ChainInfo{BlockNumber: 13}).Once()
outOfSyncSubscription := mocks.NewSubscription(t)
outOfSyncSubscription.On("Err").Return((<-chan error)(nil))
outOfSyncSubscription.On("Unsubscribe").Once()
heads := []head{{BlockNumber: 7}, {BlockNumber: 11}, {BlockNumber: 13}}
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
- ch := args.Get(1).(chan<- Head)
- go writeHeads(t, ch, heads...)
- }).Return(outOfSyncSubscription, nil).Once()
+ ch := make(chan Head)
+ var wg sync.WaitGroup
+ wg.Add(1)
+ rpc.On("SubscribeToHeads", mock.Anything).Run(func(args mock.Arguments) {
+ go func() {
+ defer wg.Done()
+ writeHeads(t, ch, heads...)
+ }()
+ }).Return((<-chan Head)(ch), outOfSyncSubscription, nil).Once()
+
rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe()
- node.declareOutOfSync(func(num int64, td *big.Int) bool {
- return true
- })
- tests.AssertLogCountEventually(t, observedLogs, msgReceivedBlock, len(heads))
+ node.declareOutOfSync(syncStatusNoNewHead)
+ // wait until all heads are consumed
+ wg.Wait()
assert.Equal(t, nodeStateOutOfSync, node.State())
})
t.Run("if initial dial fails, transitions to unreachable", func(t *testing.T) {
@@ -597,7 +715,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
expectedError := errors.New("failed to dial rpc")
// might be called again in unreachable loop, so no need to set once
rpc.On("Dial", mock.Anything).Return(expectedError)
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateUnreachable
})
@@ -617,7 +735,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
expectedError := errors.New("failed to get chain ID")
// might be called multiple times
rpc.On("ChainID", mock.Anything).Return(types.NewIDFromInt(0), expectedError)
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateUnreachable
})
@@ -637,7 +755,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
rpc.On("Dial", mock.Anything).Return(nil).Twice()
// might be called multiple times
rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil)
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateInvalidChainID
})
@@ -657,7 +775,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil)
// might be called multiple times
rpc.On("IsSyncing", mock.Anything).Return(true, nil)
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateSyncing
})
@@ -680,7 +798,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once()
// might be called multiple times
rpc.On("IsSyncing", mock.Anything).Return(false, errors.New("failed to check syncing"))
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateUnreachable
})
@@ -698,9 +816,9 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
rpc.On("Dial", mock.Anything).Return(nil).Once()
rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once()
expectedError := errors.New("failed to subscribe")
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(nil, expectedError)
+ rpc.On("SubscribeToHeads", mock.Anything).Return(nil, nil, expectedError).Once()
rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe()
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateUnreachable
})
@@ -719,15 +837,15 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
rpc.On("Dial", mock.Anything).Return(nil).Once()
rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once()
-
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
sub := mocks.NewSubscription(t)
errChan := make(chan error, 1)
errChan <- errors.New("subscription was terminate")
sub.On("Err").Return((<-chan error)(errChan))
sub.On("Unsubscribe").Once()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(sub, nil).Once()
+ rpc.On("SubscribeToHeads", mock.Anything).Return(make(<-chan Head), sub, nil).Once()
rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe()
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertLogEventually(t, observedLogs, "Subscription was terminated")
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateUnreachable
@@ -747,22 +865,22 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
rpc.On("Dial", mock.Anything).Return(nil).Once()
rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once()
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
sub := mocks.NewSubscription(t)
sub.On("Err").Return((<-chan error)(nil))
sub.On("Unsubscribe").Once()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
- ch := args.Get(1).(chan<- Head)
+ ch := make(chan Head)
+ rpc.On("SubscribeToHeads", mock.Anything).Run(func(args mock.Arguments) {
close(ch)
- }).Return(sub, nil).Once()
+ }).Return((<-chan Head)(ch), sub, nil).Once()
rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe()
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertLogEventually(t, observedLogs, "Subscription channel unexpectedly closed")
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateUnreachable
})
})
-
t.Run("becomes alive if it receives a newer head", func(t *testing.T) {
t.Parallel()
rpc := newMockNodeClient[types.ID, Head](t)
@@ -782,17 +900,14 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
outOfSyncSubscription.On("Err").Return((<-chan error)(nil))
outOfSyncSubscription.On("Unsubscribe").Once()
const highestBlock = 1000
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
- ch := args.Get(1).(chan<- Head)
- go writeHeads(t, ch, head{BlockNumber: highestBlock - 1}, head{BlockNumber: highestBlock})
- }).Return(outOfSyncSubscription, nil).Once()
+ ch := make(chan Head)
+ rpc.On("SubscribeToHeads", mock.Anything).Run(func(args mock.Arguments) {
+ go writeHeads(t, ch, head{BlockNumber: highestBlock - 1}, head{BlockNumber: highestBlock}, head{BlockNumber: highestBlock + 1})
+ }).Return((<-chan Head)(ch), outOfSyncSubscription, nil).Once()
rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: highestBlock}, ChainInfo{BlockNumber: highestBlock})
-
setupRPCForAliveLoop(t, rpc)
- node.declareOutOfSync(func(num int64, td *big.Int) bool {
- return num < highestBlock
- })
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertLogEventually(t, observedLogs, msgReceivedBlock)
tests.AssertLogEventually(t, observedLogs, msgInSync)
tests.AssertEventually(t, func() bool {
@@ -819,7 +934,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
TotalDifficulty: big.NewInt(200),
})
node.SetPoolChainInfoProvider(poolInfo)
- rpc.On("GetInterceptedChainInfo").Return(ChainInfo{BlockNumber: 0}, ChainInfo{BlockNumber: 0})
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{})
rpc.On("Dial", mock.Anything).Return(nil).Once()
rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once()
@@ -827,16 +942,225 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) {
outOfSyncSubscription := mocks.NewSubscription(t)
outOfSyncSubscription.On("Err").Return((<-chan error)(nil))
outOfSyncSubscription.On("Unsubscribe").Once()
- rpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(outOfSyncSubscription, nil).Once()
-
+ rpc.On("SubscribeToHeads", mock.Anything).Return(make(<-chan Head), outOfSyncSubscription, nil).Once()
setupRPCForAliveLoop(t, rpc)
- node.declareOutOfSync(stubIsOutOfSync)
+ node.declareOutOfSync(syncStatusNoNewHead)
tests.AssertLogEventually(t, observedLogs, "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")
tests.AssertEventually(t, func() bool {
return node.State() == nodeStateAlive
})
})
+ t.Run("Stays out-of-sync if received new head, but lags behind pool", func(t *testing.T) {
+ t.Parallel()
+ rpc := newMockNodeClient[types.ID, Head](t)
+ nodeChainID := types.RandomID()
+ lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel)
+ node := newAliveNode(t, testNodeOpts{
+ chainConfig: clientMocks.ChainConfig{
+ NoNewHeadsThresholdVal: tests.TestInterval,
+ },
+ config: testNodeConfig{
+ syncThreshold: 1,
+ selectionMode: NodeSelectionModeHighestHead,
+ },
+ rpc: rpc,
+ chainID: nodeChainID,
+ lggr: lggr,
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+ poolInfo := newMockPoolChainInfoProvider(t)
+ const highestBlock = 20
+ poolInfo.On("LatestChainInfo").Return(1, ChainInfo{
+ BlockNumber: highestBlock * 2,
+ TotalDifficulty: big.NewInt(200),
+ })
+ node.SetPoolChainInfoProvider(poolInfo)
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{BlockNumber: highestBlock})
+
+ rpc.On("Dial", mock.Anything).Return(nil).Once()
+ rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once()
+
+ outOfSyncSubscription := mocks.NewSubscription(t)
+ outOfSyncSubscription.On("Err").Return((<-chan error)(nil))
+ outOfSyncSubscription.On("Unsubscribe").Once()
+ ch := make(chan Head)
+ rpc.On("SubscribeToHeads", mock.Anything).Run(func(args mock.Arguments) {
+ go writeHeads(t, ch, head{BlockNumber: highestBlock - 1}, head{BlockNumber: highestBlock}, head{BlockNumber: highestBlock + 1})
+ }).Return((<-chan Head)(ch), outOfSyncSubscription, nil).Once()
+
+ node.declareOutOfSync(syncStatusNoNewHead)
+ tests.AssertLogEventually(t, observedLogs, msgReceivedBlock)
+ tests.AssertLogEventually(t, observedLogs, "No new heads received for")
+ tests.AssertEventually(t, func() bool {
+ return node.State() == nodeStateOutOfSync
+ })
+ })
+
+ // creates RPC mock with all calls necessary to create heads subscription that won't produce any events
+ newRPCWithNoOpHeads := func(t *testing.T, chainID types.ID) *mockNodeClient[types.ID, Head] {
+ rpc := newMockNodeClient[types.ID, Head](t)
+ rpc.On("Dial", mock.Anything).Return(nil).Once()
+ rpc.On("ChainID", mock.Anything).Return(chainID, nil).Once()
+ sub := mocks.NewSubscription(t)
+ sub.On("Err").Return((<-chan error)(nil))
+ sub.On("Unsubscribe").Once()
+ rpc.On("SubscribeToHeads", mock.Anything).Return(make(<-chan Head), sub, nil).Once()
+ return rpc
+ }
+
+ t.Run("if fails to subscribe to finalized, becomes unreachable", func(t *testing.T) {
+ t.Parallel()
+ nodeChainID := types.RandomID()
+ rpc := newRPCWithNoOpHeads(t, nodeChainID)
+ node := newAliveNode(t, testNodeOpts{
+ rpc: rpc,
+ chainID: nodeChainID,
+ chainConfig: clientMocks.ChainConfig{
+ IsFinalityTagEnabled: true,
+ },
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return((<-chan Head)(nil), nil, errors.New("failed to subscribe")).Once()
+ // unreachable
+ rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe()
+
+ node.declareOutOfSync(syncStatusNoNewHead)
+ tests.AssertEventually(t, func() bool {
+ return node.State() == nodeStateUnreachable
+ })
+ })
+ t.Run("on subscription termination becomes unreachable", func(t *testing.T) {
+ t.Parallel()
+ nodeChainID := types.RandomID()
+ rpc := newRPCWithNoOpHeads(t, nodeChainID)
+ lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel)
+ node := newAliveNode(t, testNodeOpts{
+ rpc: rpc,
+ chainID: nodeChainID,
+ lggr: lggr,
+ chainConfig: clientMocks.ChainConfig{
+ IsFinalityTagEnabled: true,
+ },
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+
+ sub := mocks.NewSubscription(t)
+ errChan := make(chan error, 1)
+ errChan <- errors.New("subscription was terminate")
+ sub.On("Err").Return((<-chan error)(errChan))
+ sub.On("Unsubscribe").Once()
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return(make(<-chan Head), sub, nil).Once()
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
+ // unreachable
+ rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe()
+ node.declareOutOfSync(syncStatusNoNewHead)
+ tests.AssertLogEventually(t, observedLogs, "Finalized head subscription was terminated")
+ tests.AssertEventually(t, func() bool {
+ return node.State() == nodeStateUnreachable
+ })
+ })
+ t.Run("becomes unreachable if head channel is closed", func(t *testing.T) {
+ t.Parallel()
+ nodeChainID := types.RandomID()
+ rpc := newRPCWithNoOpHeads(t, nodeChainID)
+ lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel)
+ node := newAliveNode(t, testNodeOpts{
+ rpc: rpc,
+ chainID: nodeChainID,
+ lggr: lggr,
+ chainConfig: clientMocks.ChainConfig{
+ IsFinalityTagEnabled: true,
+ },
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+
+ sub := mocks.NewSubscription(t)
+ sub.On("Err").Return((<-chan error)(nil))
+ sub.On("Unsubscribe").Once()
+ ch := make(chan Head)
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Run(func(args mock.Arguments) {
+ close(ch)
+ }).Return((<-chan Head)(ch), sub, nil).Once()
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{}).Once()
+ // unreachable
+ rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe()
+ node.declareOutOfSync(syncStatusNoNewHead)
+ tests.AssertLogEventually(t, observedLogs, "Finalized heads subscription channel unexpectedly closed")
+ tests.AssertEventually(t, func() bool {
+ return node.State() == nodeStateUnreachable
+ })
+ })
+ t.Run("becomes alive on new finalized block", func(t *testing.T) {
+ t.Parallel()
+ nodeChainID := types.RandomID()
+ rpc := newRPCWithNoOpHeads(t, nodeChainID)
+ lggr := logger.Test(t)
+ node := newAliveNode(t, testNodeOpts{
+ rpc: rpc,
+ chainID: nodeChainID,
+ lggr: lggr,
+ chainConfig: clientMocks.ChainConfig{
+ IsFinalityTagEnabled: true,
+ NoNewFinalizedHeadsThresholdVal: tests.TestInterval,
+ },
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+
+ const highestBlock = 13
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{FinalizedBlockNumber: highestBlock}).Once()
+
+ outOfSyncSubscription := mocks.NewSubscription(t)
+ outOfSyncSubscription.On("Err").Return((<-chan error)(nil))
+ outOfSyncSubscription.On("Unsubscribe").Once()
+ ch := make(chan Head)
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return((<-chan Head)(ch), outOfSyncSubscription, nil).Once()
+
+ setupRPCForAliveLoop(t, rpc)
+
+ node.declareOutOfSync(syncStatusNoNewFinalizedHead)
+ heads := []head{{BlockNumber: highestBlock - 1}, {BlockNumber: highestBlock}}
+ writeHeads(t, ch, heads...)
+ assert.Equal(t, nodeStateOutOfSync, node.State())
+ writeHeads(t, ch, head{BlockNumber: highestBlock + 1})
+ tests.AssertEventually(t, func() bool {
+ return node.State() == nodeStateAlive
+ })
+ })
+ t.Run("adds finalized block is not increasing flag, if there is no new finalized heads for too long", func(t *testing.T) {
+ t.Parallel()
+ nodeChainID := types.RandomID()
+ rpc := newRPCWithNoOpHeads(t, nodeChainID)
+ lggr, observed := logger.TestObserved(t, zap.DebugLevel)
+ const noNewFinalizedHeads = tests.TestInterval
+ node := newAliveNode(t, testNodeOpts{
+ rpc: rpc,
+ chainID: nodeChainID,
+ lggr: lggr,
+ chainConfig: clientMocks.ChainConfig{
+ IsFinalityTagEnabled: true,
+ NoNewFinalizedHeadsThresholdVal: noNewFinalizedHeads,
+ },
+ })
+ defer func() { assert.NoError(t, node.close()) }()
+
+ const highestBlock = 13
+ rpc.On("GetInterceptedChainInfo").Return(ChainInfo{}, ChainInfo{FinalizedBlockNumber: highestBlock}).Once()
+
+ outOfSyncSubscription := mocks.NewSubscription(t)
+ outOfSyncSubscription.On("Err").Return((<-chan error)(nil))
+ outOfSyncSubscription.On("Unsubscribe").Once()
+ ch := make(chan Head)
+ rpc.On("SubscribeToFinalizedHeads", mock.Anything).Return((<-chan Head)(ch), outOfSyncSubscription, nil).Once()
+
+ node.declareOutOfSync(syncStatusNotInSyncWithPool)
+ heads := []head{{BlockNumber: highestBlock - 1}, {BlockNumber: highestBlock}}
+ writeHeads(t, ch, heads...)
+ assert.Equal(t, nodeStateOutOfSync, node.State())
+ tests.AssertLogEventually(t, observed, fmt.Sprintf("No new finalized heads received for %s. Node stays "+
+ "out-of-sync due to sync issues: NotInSyncWithRPCPool,NoNewFinalizedHead", noNewFinalizedHeads))
+ })
}
func TestUnit_NodeLifecycle_unreachableLoop(t *testing.T) {
@@ -1296,11 +1620,11 @@ func TestUnit_NodeLifecycle_start(t *testing.T) {
})
}
-func TestUnit_NodeLifecycle_syncStatus(t *testing.T) {
+func TestUnit_NodeLifecycle_outOfSyncWithPool(t *testing.T) {
t.Parallel()
t.Run("skip if nLiveNodes is not configured", func(t *testing.T) {
node := newTestNode(t, testNodeOpts{})
- outOfSync, liveNodes := node.syncStatus(0, nil)
+ outOfSync, liveNodes := node.isOutOfSyncWithPool(ChainInfo{})
assert.Equal(t, false, outOfSync)
assert.Equal(t, 0, liveNodes)
})
@@ -1308,7 +1632,7 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) {
node := newTestNode(t, testNodeOpts{})
poolInfo := newMockPoolChainInfoProvider(t)
node.SetPoolChainInfoProvider(poolInfo)
- outOfSync, liveNodes := node.syncStatus(0, nil)
+ outOfSync, liveNodes := node.isOutOfSyncWithPool(ChainInfo{})
assert.Equal(t, false, outOfSync)
assert.Equal(t, 0, liveNodes)
})
@@ -1320,7 +1644,7 @@ func TestUnit_NodeLifecycle_syncStatus(t *testing.T) {
poolInfo.On("LatestChainInfo").Return(1, ChainInfo{}).Once()
node.SetPoolChainInfoProvider(poolInfo)
assert.Panics(t, func() {
- _, _ = node.syncStatus(0, nil)
+ _, _ = node.isOutOfSyncWithPool(ChainInfo{})
})
})
t.Run("block height selection mode", func(t *testing.T) {
@@ -1371,7 +1695,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: SelectionModeVal: %s: total difficulty: %d", testCase.name, selectionMode, td), func(t *testing.T) {
- outOfSync, liveNodes := node.syncStatus(testCase.blockNumber, big.NewInt(td))
+ outOfSync, liveNodes := node.isOutOfSyncWithPool(ChainInfo{BlockNumber: testCase.blockNumber, TotalDifficulty: big.NewInt(td)})
assert.Equal(t, nodesNum, liveNodes)
assert.Equal(t, testCase.outOfSync, outOfSync)
})
@@ -1427,7 +1751,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: SelectionModeVal: %s: highest block: %d", testCase.name, NodeSelectionModeTotalDifficulty, hb), func(t *testing.T) {
- outOfSync, liveNodes := node.syncStatus(hb, big.NewInt(testCase.totalDifficulty))
+ outOfSync, liveNodes := node.isOutOfSyncWithPool(ChainInfo{BlockNumber: hb, TotalDifficulty: big.NewInt(testCase.totalDifficulty)})
assert.Equal(t, nodesNum, liveNodes)
assert.Equal(t, testCase.outOfSync, outOfSync)
})
diff --git a/common/client/types.go b/common/client/types.go
index b07f57eb8fb..c9b6a3580eb 100644
--- a/common/client/types.go
+++ b/common/client/types.go
@@ -68,7 +68,7 @@ type NodeClient[
SetAliveLoopSub(types.Subscription)
UnsubscribeAllExceptAliveLoop()
IsSyncing(ctx context.Context) (bool, error)
- LatestFinalizedBlock(ctx context.Context) (HEAD, error)
+ SubscribeToFinalizedHeads(_ context.Context) (<-chan HEAD, types.Subscription, error)
// GetInterceptedChainInfo - returns latest and highest observed by application layer ChainInfo.
// latest ChainInfo is the most recent value received within a NodeClient's current lifecycle between Dial and DisconnectAll.
// highestUserObservations ChainInfo is the highest ChainInfo observed excluding health checks calls.
@@ -151,7 +151,9 @@ type connection[
] interface {
ChainID(ctx context.Context) (CHAIN_ID, error)
Dial(ctx context.Context) error
- SubscribeNewHead(ctx context.Context, channel chan<- HEAD) (types.Subscription, error)
+ SubscribeToHeads(ctx context.Context) (ch <-chan HEAD, sub types.Subscription, err error)
+ // TODO: remove as part of merge with BCI-2875
+ SubscribeNewHead(ctx context.Context, channel chan<- HEAD) (s types.Subscription, err error)
}
// PoolChainInfoProvider - provides aggregation of nodes pool ChainInfo
diff --git a/common/fee/models.go b/common/fee/models.go
index 0568a2f1433..0496d3929c2 100644
--- a/common/fee/models.go
+++ b/common/fee/models.go
@@ -14,6 +14,7 @@ var (
ErrBumpFeeExceedsLimit = errors.New("fee bump exceeds limit")
ErrBump = errors.New("fee bump failed")
ErrConnectivity = errors.New("transaction propagation issue: transactions are not being mined")
+ ErrFeeLimitTooLow = errors.New("provided fee limit too low")
)
func IsBumpErr(err error) bool {
diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go
index 7edcccfccbd..c81c61141f2 100644
--- a/common/headtracker/head_broadcaster.go
+++ b/common/headtracker/head_broadcaster.go
@@ -42,13 +42,12 @@ type HeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interf
}
type headBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct {
- services.StateMachine
- logger logger.Logger
+ services.Service
+ eng *services.Engine
+
callbacks callbackSet[H, BLOCK_HASH]
mailbox *mailbox.Mailbox[H]
mutex sync.Mutex
- chClose services.StopChan
- wgDone sync.WaitGroup
latest H
lastCallbackID int
}
@@ -60,41 +59,29 @@ func NewHeadBroadcaster[
](
lggr logger.Logger,
) HeadBroadcaster[H, BLOCK_HASH] {
- return &headBroadcaster[H, BLOCK_HASH]{
- logger: logger.Named(lggr, "HeadBroadcaster"),
+ hb := &headBroadcaster[H, BLOCK_HASH]{
callbacks: make(callbackSet[H, BLOCK_HASH]),
mailbox: mailbox.NewSingle[H](),
- chClose: make(chan struct{}),
}
+ hb.Service, hb.eng = services.Config{
+ Name: "HeadBroadcaster",
+ Start: hb.start,
+ Close: hb.close,
+ }.NewServiceEngine(lggr)
+ return hb
}
-func (hb *headBroadcaster[H, BLOCK_HASH]) Start(context.Context) error {
- return hb.StartOnce("HeadBroadcaster", func() error {
- hb.wgDone.Add(1)
- go hb.run()
- return nil
- })
-}
-
-func (hb *headBroadcaster[H, BLOCK_HASH]) Close() error {
- return hb.StopOnce("HeadBroadcaster", func() error {
- hb.mutex.Lock()
- // clear all callbacks
- hb.callbacks = make(callbackSet[H, BLOCK_HASH])
- hb.mutex.Unlock()
-
- close(hb.chClose)
- hb.wgDone.Wait()
- return nil
- })
+func (hb *headBroadcaster[H, BLOCK_HASH]) start(context.Context) error {
+ hb.eng.Go(hb.run)
+ return nil
}
-func (hb *headBroadcaster[H, BLOCK_HASH]) Name() string {
- return hb.logger.Name()
-}
-
-func (hb *headBroadcaster[H, BLOCK_HASH]) HealthReport() map[string]error {
- return map[string]error{hb.Name(): hb.Healthy()}
+func (hb *headBroadcaster[H, BLOCK_HASH]) close() error {
+ hb.mutex.Lock()
+ // clear all callbacks
+ hb.callbacks = make(callbackSet[H, BLOCK_HASH])
+ hb.mutex.Unlock()
+ return nil
}
func (hb *headBroadcaster[H, BLOCK_HASH]) BroadcastNewLongestChain(head H) {
@@ -121,15 +108,13 @@ func (hb *headBroadcaster[H, BLOCK_HASH]) Subscribe(callback HeadTrackable[H, BL
return
}
-func (hb *headBroadcaster[H, BLOCK_HASH]) run() {
- defer hb.wgDone.Done()
-
+func (hb *headBroadcaster[H, BLOCK_HASH]) run(ctx context.Context) {
for {
select {
- case <-hb.chClose:
+ case <-ctx.Done():
return
case <-hb.mailbox.Notify():
- hb.executeCallbacks()
+ hb.executeCallbacks(ctx)
}
}
}
@@ -137,10 +122,10 @@ func (hb *headBroadcaster[H, BLOCK_HASH]) run() {
// DEV: the head relayer makes no promises about head delivery! Subscribing
// Jobs should expect to the relayer to skip heads if there is a large number of listeners
// and all callbacks cannot be completed in the allotted time.
-func (hb *headBroadcaster[H, BLOCK_HASH]) executeCallbacks() {
+func (hb *headBroadcaster[H, BLOCK_HASH]) executeCallbacks(ctx context.Context) {
head, exists := hb.mailbox.Retrieve()
if !exists {
- hb.logger.Info("No head to retrieve. It might have been skipped")
+ hb.eng.Info("No head to retrieve. It might have been skipped")
return
}
@@ -149,7 +134,7 @@ func (hb *headBroadcaster[H, BLOCK_HASH]) executeCallbacks() {
hb.latest = head
hb.mutex.Unlock()
- hb.logger.Debugw("Initiating callbacks",
+ hb.eng.Debugw("Initiating callbacks",
"headNum", head.BlockNumber(),
"numCallbacks", len(callbacks),
)
@@ -157,9 +142,6 @@ func (hb *headBroadcaster[H, BLOCK_HASH]) executeCallbacks() {
wg := sync.WaitGroup{}
wg.Add(len(callbacks))
- ctx, cancel := hb.chClose.NewCtx()
- defer cancel()
-
for _, callback := range callbacks {
go func(trackable HeadTrackable[H, BLOCK_HASH]) {
defer wg.Done()
@@ -168,7 +150,7 @@ func (hb *headBroadcaster[H, BLOCK_HASH]) executeCallbacks() {
defer cancel()
trackable.OnNewLongestChain(cctx, head)
elapsed := time.Since(start)
- hb.logger.Debugw(fmt.Sprintf("Finished callback in %s", elapsed),
+ hb.eng.Debugw(fmt.Sprintf("Finished callback in %s", elapsed),
"callbackType", reflect.TypeOf(trackable), "blockNumber", head.BlockNumber(), "time", elapsed)
}(callback)
}
diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go
index 25715b35280..d240caab3c3 100644
--- a/common/headtracker/head_listener.go
+++ b/common/headtracker/head_listener.go
@@ -29,14 +29,15 @@ var (
}, []string{"ChainID"})
)
-// headHandler is a callback that handles incoming heads
-type headHandler[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] func(ctx context.Context, header H) error
+// HeadHandler is a callback that handles incoming heads
+type HeadHandler[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] func(ctx context.Context, header H) error
// HeadListener is a chain agnostic interface that manages connection of Client that receives heads from the blockchain node
type HeadListener[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface {
- // ListenForNewHeads kicks off the listen loop (not thread safe)
- // done() must be executed upon leaving ListenForNewHeads()
- ListenForNewHeads(onSubscribe func(), handleNewHead headHandler[H, BLOCK_HASH], done func())
+ services.Service
+
+ // ListenForNewHeads runs the listen loop (not thread safe)
+ ListenForNewHeads(ctx context.Context)
// ReceivingHeads returns true if the listener is receiving heads (thread safe)
ReceivingHeads() bool
@@ -54,10 +55,13 @@ type headListener[
ID types.ID,
BLOCK_HASH types.Hashable,
] struct {
+ services.Service
+ eng *services.Engine
+
config htrktypes.Config
client htrktypes.Client[HTH, S, ID, BLOCK_HASH]
- logger logger.Logger
- chStop services.StopChan
+ onSubscription func(context.Context)
+ handleNewHead HeadHandler[HTH, BLOCK_HASH]
chHeaders chan HTH
headSubscription types.Subscription
connected atomic.Bool
@@ -74,38 +78,43 @@ func NewHeadListener[
lggr logger.Logger,
client CLIENT,
config htrktypes.Config,
- chStop chan struct{},
+ onSubscription func(context.Context),
+ handleNewHead HeadHandler[HTH, BLOCK_HASH],
) HeadListener[HTH, BLOCK_HASH] {
- return &headListener[HTH, S, ID, BLOCK_HASH]{
- config: config,
- client: client,
- logger: logger.Named(lggr, "HeadListener"),
- chStop: chStop,
+ hl := &headListener[HTH, S, ID, BLOCK_HASH]{
+ config: config,
+ client: client,
+ onSubscription: onSubscription,
+ handleNewHead: handleNewHead,
}
+ hl.Service, hl.eng = services.Config{
+ Name: "HeadListener",
+ Start: hl.start,
+ }.NewServiceEngine(lggr)
+ return hl
}
-func (hl *headListener[HTH, S, ID, BLOCK_HASH]) Name() string {
- return hl.logger.Name()
+func (hl *headListener[HTH, S, ID, BLOCK_HASH]) start(context.Context) error {
+ hl.eng.Go(hl.ListenForNewHeads)
+ return nil
}
-func (hl *headListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(onSubscription func(), handleNewHead headHandler[HTH, BLOCK_HASH], done func()) {
- defer done()
+func (hl *headListener[HTH, S, ID, BLOCK_HASH]) ListenForNewHeads(ctx context.Context) {
defer hl.unsubscribe()
- ctx, cancel := hl.chStop.NewCtx()
- defer cancel()
-
for {
if !hl.subscribe(ctx) {
break
}
- onSubscription()
- err := hl.receiveHeaders(ctx, handleNewHead)
+ if hl.onSubscription != nil {
+ hl.onSubscription(ctx)
+ }
+ err := hl.receiveHeaders(ctx, hl.handleNewHead)
if ctx.Err() != nil {
break
} else if err != nil {
- hl.logger.Errorw("Error in new head subscription, unsubscribed", "err", err)
+ hl.eng.Errorw("Error in new head subscription, unsubscribed", "err", err)
continue
}
break
@@ -131,7 +140,7 @@ func (hl *headListener[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error
return map[string]error{hl.Name(): err}
}
-func (hl *headListener[HTH, S, ID, BLOCK_HASH]) receiveHeaders(ctx context.Context, handleNewHead headHandler[HTH, BLOCK_HASH]) error {
+func (hl *headListener[HTH, S, ID, BLOCK_HASH]) receiveHeaders(ctx context.Context, handleNewHead HeadHandler[HTH, BLOCK_HASH]) error {
var noHeadsAlarmC <-chan time.Time
var noHeadsAlarmT *time.Ticker
noHeadsAlarmDuration := hl.config.BlockEmissionIdleWarningThreshold()
@@ -142,7 +151,7 @@ func (hl *headListener[HTH, S, ID, BLOCK_HASH]) receiveHeaders(ctx context.Conte
for {
select {
- case <-hl.chStop:
+ case <-ctx.Done():
return nil
case blockHeader, open := <-hl.chHeaders:
@@ -158,13 +167,13 @@ func (hl *headListener[HTH, S, ID, BLOCK_HASH]) receiveHeaders(ctx context.Conte
return errors.New("head listener: chHeaders prematurely closed")
}
if !blockHeader.IsValid() {
- hl.logger.Error("got nil block header")
+ hl.eng.Error("got nil block header")
continue
}
// Compare the chain ID of the block header to the chain ID of the client
if !blockHeader.HasChainID() || blockHeader.ChainID().String() != chainId.String() {
- hl.logger.Panicf("head listener for %s received block header for %s", chainId, blockHeader.ChainID())
+ hl.eng.Panicf("head listener for %s received block header for %s", chainId, blockHeader.ChainID())
}
promNumHeadsReceived.WithLabelValues(chainId.String()).Inc()
@@ -184,7 +193,7 @@ func (hl *headListener[HTH, S, ID, BLOCK_HASH]) receiveHeaders(ctx context.Conte
case <-noHeadsAlarmC:
// We haven't received a head on the channel for a long time, log a warning
- hl.logger.Warnf("have not received a head for %v", noHeadsAlarmDuration)
+ hl.eng.Warnf("have not received a head for %v", noHeadsAlarmDuration)
hl.receivingHeads.Store(false)
}
}
@@ -198,19 +207,19 @@ func (hl *headListener[HTH, S, ID, BLOCK_HASH]) subscribe(ctx context.Context) b
for {
hl.unsubscribe()
- hl.logger.Debugf("Subscribing to new heads on chain %s", chainId.String())
+ hl.eng.Debugf("Subscribing to new heads on chain %s", chainId.String())
select {
- case <-hl.chStop:
+ case <-ctx.Done():
return false
case <-time.After(subscribeRetryBackoff.Duration()):
err := hl.subscribeToHead(ctx)
if err != nil {
promEthConnectionErrors.WithLabelValues(chainId.String()).Inc()
- hl.logger.Warnw("Failed to subscribe to heads on chain", "chainID", chainId.String(), "err", err)
+ hl.eng.Warnw("Failed to subscribe to heads on chain", "chainID", chainId.String(), "err", err)
} else {
- hl.logger.Debugf("Subscribed to heads on chain %s", chainId.String())
+ hl.eng.Debugf("Subscribed to heads on chain %s", chainId.String())
return true
}
}
diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go
index afa5d931ee6..8546d856b67 100644
--- a/common/headtracker/head_tracker.go
+++ b/common/headtracker/head_tracker.go
@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"math/big"
- "sync"
"time"
"github.com/prometheus/client_golang/prometheus"
@@ -51,7 +50,9 @@ type headTracker[
ID types.ID,
BLOCK_HASH types.Hashable,
] struct {
- services.StateMachine
+ services.Service
+ eng *services.Engine
+
log logger.SugaredLogger
headBroadcaster HeadBroadcaster[HTH, BLOCK_HASH]
headSaver HeadSaver[HTH, BLOCK_HASH]
@@ -64,8 +65,6 @@ type headTracker[
backfillMB *mailbox.Mailbox[HTH]
broadcastMB *mailbox.Mailbox[HTH]
headListener HeadListener[HTH, BLOCK_HASH]
- chStop services.StopChan
- wgDone sync.WaitGroup
getNilHead func() HTH
}
@@ -85,52 +84,52 @@ func NewHeadTracker[
mailMon *mailbox.Monitor,
getNilHead func() HTH,
) HeadTracker[HTH, BLOCK_HASH] {
- chStop := make(chan struct{})
- lggr = logger.Named(lggr, "HeadTracker")
- return &headTracker[HTH, S, ID, BLOCK_HASH]{
+ ht := &headTracker[HTH, S, ID, BLOCK_HASH]{
headBroadcaster: headBroadcaster,
client: client,
chainID: client.ConfiguredChainID(),
config: config,
htConfig: htConfig,
- log: logger.Sugared(lggr),
backfillMB: mailbox.NewSingle[HTH](),
broadcastMB: mailbox.New[HTH](HeadsBufferSize),
- chStop: chStop,
- headListener: NewHeadListener[HTH, S, ID, BLOCK_HASH](lggr, client, config, chStop),
headSaver: headSaver,
mailMon: mailMon,
getNilHead: getNilHead,
}
+ ht.Service, ht.eng = services.Config{
+ Name: "HeadTracker",
+ NewSubServices: func(lggr logger.Logger) []services.Service {
+ ht.headListener = NewHeadListener[HTH, S, ID, BLOCK_HASH](lggr, client, config,
+ // NOTE: Always try to start the head tracker off with whatever the
+ // latest head is, without waiting for the subscription to send us one.
+ //
+ // In some cases the subscription will send us the most recent head
+ // anyway when we connect (but we should not rely on this because it is
+ // not specced). If it happens this is fine, and the head will be
+ // ignored as a duplicate.
+ func(ctx context.Context) {
+ err := ht.handleInitialHead(ctx)
+ if err != nil {
+ ht.log.Errorw("Error handling initial head", "err", err.Error())
+ }
+ }, ht.handleNewHead)
+ return []services.Service{ht.headListener}
+ },
+ Start: ht.start,
+ Close: ht.close,
+ }.NewServiceEngine(lggr)
+ ht.log = logger.Sugared(ht.eng)
+ return ht
}
// Start starts HeadTracker service.
-func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Start(ctx context.Context) error {
- return ht.StartOnce("HeadTracker", func() error {
- ht.log.Debugw("Starting HeadTracker", "chainID", ht.chainID)
- // NOTE: Always try to start the head tracker off with whatever the
- // latest head is, without waiting for the subscription to send us one.
- //
- // In some cases the subscription will send us the most recent head
- // anyway when we connect (but we should not rely on this because it is
- // not specced). If it happens this is fine, and the head will be
- // ignored as a duplicate.
- onSubscribe := func() {
- err := ht.handleInitialHead(ctx)
- if err != nil {
- ht.log.Errorw("Error handling initial head", "err", err.Error())
- }
- }
+func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) start(context.Context) error {
+ ht.eng.Go(ht.backfillLoop)
+ ht.eng.Go(ht.broadcastLoop)
- ht.wgDone.Add(3)
- go ht.headListener.ListenForNewHeads(onSubscribe, ht.handleNewHead, ht.wgDone.Done)
- go ht.backfillLoop()
- go ht.broadcastLoop()
+ ht.mailMon.Monitor(ht.broadcastMB, "HeadTracker", "Broadcast", ht.chainID.String())
- ht.mailMon.Monitor(ht.broadcastMB, "HeadTracker", "Broadcast", ht.chainID.String())
-
- return nil
- })
+ return nil
}
func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) handleInitialHead(ctx context.Context) error {
@@ -176,23 +175,8 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) handleInitialHead(ctx context.Con
return nil
}
-// Close stops HeadTracker service.
-func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Close() error {
- return ht.StopOnce("HeadTracker", func() error {
- close(ht.chStop)
- ht.wgDone.Wait()
- return ht.broadcastMB.Close()
- })
-}
-
-func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Name() string {
- return ht.log.Name()
-}
-
-func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) HealthReport() map[string]error {
- report := map[string]error{ht.Name(): ht.Healthy()}
- services.CopyHealth(report, ht.headListener.HealthReport())
- return report
+func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) close() error {
+ return ht.broadcastMB.Close()
}
func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain HTH) (err error) {
@@ -236,8 +220,7 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context
"blockDifficulty", head.BlockDifficulty(),
)
- err := ht.headSaver.Save(ctx, head)
- if ctx.Err() != nil {
+ if err := ht.headSaver.Save(ctx, head); ctx.Err() != nil {
return nil
} else if err != nil {
return fmt.Errorf("failed to save head: %#v: %w", head, err)
@@ -264,16 +247,15 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context
if prevLatestFinalized != nil && head.BlockNumber() <= prevLatestFinalized.BlockNumber() {
promOldHead.WithLabelValues(ht.chainID.String()).Inc()
- ht.log.Criticalf("Got very old block with number %d (highest seen was %d). This is a problem and either means a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", head.BlockNumber(), prevHead.BlockNumber())
- ht.SvcErrBuffer.Append(errors.New("got very old block"))
+ err := fmt.Errorf("got very old block with number %d (highest seen was %d)", head.BlockNumber(), prevHead.BlockNumber())
+ ht.log.Critical("Got very old block. Either a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", "err", err)
+ ht.eng.EmitHealthErr(err)
}
}
return nil
}
-func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) broadcastLoop() {
- defer ht.wgDone.Done()
-
+func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) broadcastLoop(ctx context.Context) {
samplingInterval := ht.htConfig.SamplingInterval()
if samplingInterval > 0 {
ht.log.Debugf("Head sampling is enabled - sampling interval is set to: %v", samplingInterval)
@@ -281,7 +263,7 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) broadcastLoop() {
defer debounceHead.Stop()
for {
select {
- case <-ht.chStop:
+ case <-ctx.Done():
return
case <-debounceHead.C:
item := ht.broadcastMB.RetrieveLatestAndClear()
@@ -295,7 +277,7 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) broadcastLoop() {
ht.log.Info("Head sampling is disabled - callback will be called on every head")
for {
select {
- case <-ht.chStop:
+ case <-ctx.Done():
return
case <-ht.broadcastMB.Notify():
for {
@@ -310,15 +292,10 @@ func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) broadcastLoop() {
}
}
-func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) backfillLoop() {
- defer ht.wgDone.Done()
-
- ctx, cancel := ht.chStop.NewCtx()
- defer cancel()
-
+func (ht *headTracker[HTH, S, ID, BLOCK_HASH]) backfillLoop(ctx context.Context) {
for {
select {
- case <-ht.chStop:
+ case <-ctx.Done():
return
case <-ht.backfillMB.Notify():
for {
diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go
index 2a9c1231d7b..1606f58ce0d 100644
--- a/common/txmgr/broadcaster.go
+++ b/common/txmgr/broadcaster.go
@@ -20,6 +20,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink/v2/common/client"
+ commonfee "github.com/smartcontractkit/chainlink/v2/common/fee"
feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types"
txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types"
"github.com/smartcontractkit/chainlink/v2/common/types"
@@ -34,6 +35,13 @@ const (
// TransmitCheckTimeout controls the maximum amount of time that will be
// spent on the transmit check.
TransmitCheckTimeout = 2 * time.Second
+
+ // maxBroadcastRetries is the number of times a transaction broadcast is retried when the sequence fails to increment on Hedera
+ maxHederaBroadcastRetries = 3
+
+ // hederaChainType is the string representation of the Hedera chain type
+ // Temporary solution until the Broadcaster is moved to the EVM code base
+ hederaChainType = "hedera"
)
var (
@@ -114,6 +122,7 @@ type Broadcaster[
sequenceTracker txmgrtypes.SequenceTracker[ADDR, SEQ]
resumeCallback ResumeCallback
chainID CHAIN_ID
+ chainType string
config txmgrtypes.BroadcasterChainConfig
feeConfig txmgrtypes.BroadcasterFeeConfig
txConfig txmgrtypes.BroadcasterTransactionsConfig
@@ -163,6 +172,7 @@ func NewBroadcaster[
lggr logger.Logger,
checkerFactory TransmitCheckerFactory[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE],
autoSyncSequence bool,
+ chainType string,
) *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]{
@@ -171,6 +181,7 @@ func NewBroadcaster[
client: client,
TxAttemptBuilder: txAttemptBuilder,
chainID: client.ConfiguredChainID(),
+ chainType: chainType,
config: config,
feeConfig: feeConfig,
txConfig: txConfig,
@@ -411,7 +422,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand
return fmt.Errorf("handleAnyInProgressTx failed: %w", err), true
}
if etx != nil {
- if err, retryable := eb.handleInProgressTx(ctx, *etx, etx.TxAttempts[0], etx.CreatedAt); err != nil {
+ if err, retryable := eb.handleInProgressTx(ctx, *etx, etx.TxAttempts[0], etx.CreatedAt, 0); err != nil {
return fmt.Errorf("handleAnyInProgressTx failed: %w", err), retryable
}
}
@@ -424,7 +435,11 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand
}
attempt, _, _, retryable, err := eb.NewTxAttempt(ctx, *etx, eb.lggr)
- if err != nil {
+ // Mark transaction as fatal if provided gas limit is set too low
+ if errors.Is(err, commonfee.ErrFeeLimitTooLow) {
+ etx.Error = null.StringFrom(commonfee.ErrFeeLimitTooLow.Error())
+ return eb.saveFatallyErroredTransaction(eb.lggr, etx), false
+ } else if err != nil {
return fmt.Errorf("processUnstartedTxs failed on NewAttempt: %w", err), retryable
}
@@ -464,12 +479,12 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand
return fmt.Errorf("processUnstartedTxs failed on UpdateTxUnstartedToInProgress: %w", err), true
}
- return eb.handleInProgressTx(ctx, *etx, attempt, time.Now())
+ return eb.handleInProgressTx(ctx, *etx, attempt, time.Now(), 0)
}
// There can be at most one in_progress transaction per address.
// Here we complete the job that we didn't finish last time.
-func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleInProgressTx(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (error, bool) {
+func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleInProgressTx(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time, retryCount int) (error, bool) {
if etx.State != TxInProgress {
return fmt.Errorf("invariant violation: expected transaction %v to be in_progress, it was %s", etx.ID, etx.State), false
}
@@ -478,16 +493,21 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand
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 {
- etx.InitialBroadcastAt = &initialBroadcastAt
- etx.BroadcastAt = &initialBroadcastAt
+ // The validation below is only applicable to Hedera because it has instant finality and a unique sequence behavior
+ if eb.chainType == hederaChainType {
+ errType, err = eb.validateOnChainSequence(ctx, lgr, errType, err, etx, retryCount)
}
- switch errType {
- case client.Fatal:
+ if errType == client.Fatal || errType == client.TerminallyStuck {
eb.SvcErrBuffer.Append(err)
etx.Error = null.StringFrom(err.Error())
return eb.saveFatallyErroredTransaction(lgr, &etx), true
+ }
+
+ etx.InitialBroadcastAt = &initialBroadcastAt
+ etx.BroadcastAt = &initialBroadcastAt
+
+ switch errType {
case client.TransactionAlreadyKnown:
fallthrough
case client.Successful:
@@ -538,7 +558,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand
eb.sequenceTracker.GenerateNextSequence(etx.FromAddress, *etx.Sequence)
return err, true
case client.Underpriced:
- return eb.tryAgainBumpingGas(ctx, lgr, err, etx, attempt, initialBroadcastAt)
+ return eb.tryAgainBumpingGas(ctx, lgr, err, etx, attempt, initialBroadcastAt, retryCount+1)
case client.InsufficientFunds:
// NOTE: This bails out of the entire cycle and essentially "blocks" on
// any transaction that gets insufficient_funds. This is OK if a
@@ -600,6 +620,44 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand
}
}
+func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) validateOnChainSequence(ctx context.Context, lgr logger.SugaredLogger, errType client.SendTxReturnCode, err error, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], retryCount int) (client.SendTxReturnCode, error) {
+ // Only check if sequence was incremented if broadcast was successful, otherwise return the existing err type
+ if errType != client.Successful {
+ return errType, err
+ }
+ // Transaction sequence cannot be nil here since a sequence is required to broadcast
+ txSeq := *etx.Sequence
+ // Retrieve the latest mined sequence from on-chain
+ nextSeqOnChain, err := eb.client.SequenceAt(ctx, etx.FromAddress, nil)
+ if err != nil {
+ return errType, err
+ }
+
+ // Check that the transaction count has incremented on-chain to include the broadcasted transaction
+ // Insufficient transaction fee is a common scenario in which the sequence is not incremented by the chain even though we got a successful response
+ // If the sequence failed to increment and hasn't reached the max retries, return the Underpriced error to try again with a bumped attempt
+ if nextSeqOnChain.Int64() == txSeq.Int64() && retryCount < maxHederaBroadcastRetries {
+ return client.Underpriced, nil
+ }
+
+ // If the transaction reaches the retry limit and fails to get included, mark it as fatally errored
+ // Some unknown error other than insufficient tx fee could be the cause
+ if nextSeqOnChain.Int64() == txSeq.Int64() && retryCount >= maxHederaBroadcastRetries {
+ err := fmt.Errorf("failed to broadcast transaction on %s after %d retries", hederaChainType, retryCount)
+ lgr.Error(err.Error())
+ return client.Fatal, err
+ }
+
+ // Belts and braces approach to detect and handle sqeuence gaps if the broadcast is considered successful
+ if nextSeqOnChain.Int64() < txSeq.Int64() {
+ err := fmt.Errorf("next expected sequence on-chain (%s) is less than the broadcasted transaction's sequence (%s)", nextSeqOnChain.String(), txSeq.String())
+ lgr.Criticalw("Sequence gap has been detected and needs to be filled", "error", err)
+ return client.Fatal, err
+ }
+
+ return client.Successful, nil
+}
+
// Finds next transaction in the queue, assigns a sequence, and moves it to "in_progress" state ready for broadcast.
// Returns nil if no transactions are in queue
func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) nextUnstartedTransactionWithSequence(fromAddress ADDR) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) {
@@ -622,23 +680,26 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) next
return etx, nil
}
-func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryAgainBumpingGas(ctx context.Context, lgr logger.Logger, txError error, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (err error, retryable bool) {
- logger.With(lgr,
- "sendError", txError,
- "attemptFee", attempt.TxFee,
- "maxGasPriceConfig", eb.feeConfig.MaxFeePrice(),
- ).Errorf("attempt fee %v was rejected by the node for being too low. "+
- "Node returned: '%s'. "+
- "Will bump and retry. ACTION REQUIRED: This is a configuration error. "+
- "Consider increasing FeeEstimator.PriceDefault (current value: %s)",
- attempt.TxFee, txError.Error(), eb.feeConfig.FeePriceDefault())
+func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryAgainBumpingGas(ctx context.Context, lgr logger.Logger, txError error, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time, retry int) (err error, retryable bool) {
+ // This log error is not applicable to Hedera since the action required would not be needed for its gas estimator
+ if eb.chainType != hederaChainType {
+ logger.With(lgr,
+ "sendError", txError,
+ "attemptFee", attempt.TxFee,
+ "maxGasPriceConfig", eb.feeConfig.MaxFeePrice(),
+ ).Errorf("attempt fee %v was rejected by the node for being too low. "+
+ "Node returned: '%s'. "+
+ "Will bump and retry. ACTION REQUIRED: This is a configuration error. "+
+ "Consider increasing FeeEstimator.PriceDefault (current value: %s)",
+ attempt.TxFee, txError.Error(), eb.feeConfig.FeePriceDefault())
+ }
replacementAttempt, bumpedFee, bumpedFeeLimit, retryable, err := eb.NewBumpTxAttempt(ctx, etx, attempt, nil, lgr)
if err != nil {
return fmt.Errorf("tryAgainBumpFee failed: %w", err), retryable
}
- return eb.saveTryAgainAttempt(ctx, lgr, etx, attempt, replacementAttempt, initialBroadcastAt, bumpedFee, bumpedFeeLimit)
+ return eb.saveTryAgainAttempt(ctx, lgr, etx, attempt, replacementAttempt, initialBroadcastAt, bumpedFee, bumpedFeeLimit, retry)
}
func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryAgainWithNewEstimation(ctx context.Context, lgr logger.Logger, txError error, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (err error, retryable bool) {
@@ -655,15 +716,15 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA
lgr.Warnw("L2 rejected transaction due to incorrect fee, re-estimated and will try again",
"etxID", etx.ID, "err", err, "newGasPrice", fee, "newGasLimit", feeLimit)
- return eb.saveTryAgainAttempt(ctx, lgr, etx, attempt, replacementAttempt, initialBroadcastAt, fee, feeLimit)
+ return eb.saveTryAgainAttempt(ctx, lgr, etx, attempt, replacementAttempt, initialBroadcastAt, fee, feeLimit, 0)
}
-func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) saveTryAgainAttempt(ctx context.Context, lgr logger.Logger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time, newFee FEE, newFeeLimit uint64) (err error, retyrable bool) {
+func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) saveTryAgainAttempt(ctx context.Context, lgr logger.Logger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time, newFee FEE, newFeeLimit uint64, retry int) (err error, retyrable bool) {
if err = eb.txStore.SaveReplacementInProgressAttempt(ctx, attempt, &replacementAttempt); err != nil {
return fmt.Errorf("tryAgainWithNewFee failed: %w", err), true
}
lgr.Debugw("Bumped fee on initial send", "oldFee", attempt.TxFee.String(), "newFee", newFee.String(), "newFeeLimit", newFeeLimit)
- return eb.handleInProgressTx(ctx, etx, replacementAttempt, initialBroadcastAt)
+ return eb.handleInProgressTx(ctx, etx, replacementAttempt, initialBroadcastAt, retry)
}
func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) saveFatallyErroredTransaction(lgr logger.Logger, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error {
diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go
index a9e30ffff1e..d67bd451228 100644
--- a/common/txmgr/confirmer.go
+++ b/common/txmgr/confirmer.go
@@ -102,6 +102,10 @@ var (
}, []string{"chainID"})
)
+type confirmerHeadTracker[HEAD types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] interface {
+ LatestAndFinalizedBlock(ctx context.Context) (latest, finalized HEAD, err error)
+}
+
// Confirmer is a broad service which performs four different tasks in sequence on every new longest chain
// Step 1: Mark that all currently pending transaction attempts were broadcast before this block
// Step 2: Check pending transactions for receipts
@@ -133,14 +137,15 @@ type Confirmer[
ks txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ]
enabledAddresses []ADDR
- mb *mailbox.Mailbox[HEAD]
- stopCh services.StopChan
- wg sync.WaitGroup
- initSync sync.Mutex
- isStarted bool
-
+ mb *mailbox.Mailbox[HEAD]
+ stopCh services.StopChan
+ wg sync.WaitGroup
+ initSync sync.Mutex
+ isStarted bool
nConsecutiveBlocksChainTooShort int
isReceiptNil func(R) bool
+
+ headTracker confirmerHeadTracker[HEAD, BLOCK_HASH]
}
func NewConfirmer[
@@ -164,6 +169,7 @@ func NewConfirmer[
lggr logger.Logger,
isReceiptNil func(R) bool,
stuckTxDetector txmgrtypes.StuckTxDetector[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE],
+ headTracker confirmerHeadTracker[HEAD, BLOCK_HASH],
) *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
lggr = logger.Named(lggr, "Confirmer")
return &Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{
@@ -181,6 +187,7 @@ func NewConfirmer[
mb: mailbox.NewSingle[HEAD](),
isReceiptNil: isReceiptNil,
stuckTxDetector: stuckTxDetector,
+ headTracker: headTracker,
}
}
@@ -297,7 +304,20 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pro
return fmt.Errorf("CheckConfirmedMissingReceipt failed: %w", err)
}
- if err := ec.CheckForReceipts(ctx, head.BlockNumber()); err != nil {
+ _, latestFinalizedHead, err := ec.headTracker.LatestAndFinalizedBlock(ctx)
+ if err != nil {
+ return fmt.Errorf("failed to retrieve latest finalized head: %w", err)
+ }
+
+ if !latestFinalizedHead.IsValid() {
+ return fmt.Errorf("latest finalized head is not valid")
+ }
+
+ if latestFinalizedHead.BlockNumber() > head.BlockNumber() {
+ ec.lggr.Debugw("processHead received old block", "latestFinalizedHead", latestFinalizedHead.BlockNumber(), "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer")
+ }
+
+ if err := ec.CheckForReceipts(ctx, head.BlockNumber(), latestFinalizedHead.BlockNumber()); err != nil {
return fmt.Errorf("CheckForReceipts failed: %w", err)
}
@@ -318,7 +338,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pro
ec.lggr.Debugw("Finished RebroadcastWhereNecessary", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer")
mark = time.Now()
- if err := ec.EnsureConfirmedTransactionsInLongestChain(ctx, head); err != nil {
+ if err := ec.EnsureConfirmedTransactionsInLongestChain(ctx, head, latestFinalizedHead.BlockNumber()); err != nil {
return fmt.Errorf("EnsureConfirmedTransactionsInLongestChain failed: %w", err)
}
@@ -395,8 +415,8 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che
return
}
-// CheckForReceipts finds attempts that are still pending and checks to see if a receipt is present for the given block number
-func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckForReceipts(ctx context.Context, blockNum int64) error {
+// CheckForReceipts finds attempts that are still pending and checks to see if a receipt is present for the given block number.
+func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckForReceipts(ctx context.Context, blockNum int64, latestFinalizedBlockNum int64) error {
attempts, err := ec.txStore.FindTxAttemptsRequiringReceiptFetch(ctx, ec.chainID)
if err != nil {
return fmt.Errorf("FindTxAttemptsRequiringReceiptFetch failed: %w", err)
@@ -443,7 +463,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che
return fmt.Errorf("unable to mark txes as 'confirmed_missing_receipt': %w", err)
}
- if err := ec.txStore.MarkOldTxesMissingReceiptAsErrored(ctx, blockNum, ec.chainConfig.FinalityDepth(), ec.chainID); err != nil {
+ if err := ec.txStore.MarkOldTxesMissingReceiptAsErrored(ctx, blockNum, latestFinalizedBlockNum, ec.chainID); err != nil {
return fmt.Errorf("unable to confirm buried unconfirmed txes': %w", err)
}
return nil
@@ -471,7 +491,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Pro
go func(tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) {
defer wg.Done()
lggr := tx.GetLogger(ec.lggr)
- // Create an purge attempt for tx
+ // Create a purge attempt for tx
purgeAttempt, err := ec.TxAttemptBuilder.NewPurgeTxAttempt(ctx, tx, lggr)
if err != nil {
errMu.Lock()
@@ -664,11 +684,15 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat
}
if receipt.GetStatus() == 0 {
- rpcError, errExtract := ec.client.CallContract(ctx, attempt, receipt.GetBlockNumber())
- if errExtract == nil {
- l.Warnw("transaction reverted on-chain", "hash", receipt.GetTxHash(), "rpcError", rpcError.String())
+ if receipt.GetRevertReason() != nil {
+ l.Warnw("transaction reverted on-chain", "hash", receipt.GetTxHash(), "revertReason", *receipt.GetRevertReason())
} else {
- l.Warnw("transaction reverted on-chain unable to extract revert reason", "hash", receipt.GetTxHash(), "err", err)
+ rpcError, errExtract := ec.client.CallContract(ctx, attempt, receipt.GetBlockNumber())
+ if errExtract == nil {
+ l.Warnw("transaction reverted on-chain", "hash", receipt.GetTxHash(), "rpcError", rpcError.String())
+ } else {
+ l.Warnw("transaction reverted on-chain unable to extract revert reason", "hash", receipt.GetTxHash(), "err", err)
+ }
}
// This might increment more than once e.g. in case of re-orgs going back and forth we might re-fetch the same receipt
promRevertedTxCount.WithLabelValues(ec.chainID.String()).Add(1)
@@ -975,6 +999,21 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han
ec.SvcErrBuffer.Append(sendError)
// This will loop continuously on every new head so it must be handled manually by the node operator!
return ec.txStore.DeleteInProgressAttempt(ctx, attempt)
+ case client.TerminallyStuck:
+ // A transaction could broadcast successfully but then be considered terminally stuck on another attempt
+ // Even though the transaction can succeed under different circumstances, we want to purge this transaction as soon as we get this error
+ lggr.Warnw("terminally stuck transaction detected", "err", sendError.Error())
+ ec.SvcErrBuffer.Append(sendError)
+ // Create a purge attempt for tx
+ purgeAttempt, err := ec.TxAttemptBuilder.NewPurgeTxAttempt(ctx, etx, lggr)
+ if err != nil {
+ return fmt.Errorf("NewPurgeTxAttempt failed: %w", err)
+ }
+ // Replace the in progress attempt with the purge attempt
+ if err := ec.txStore.SaveReplacementInProgressAttempt(ctx, attempt, &purgeAttempt); err != nil {
+ return fmt.Errorf("saveReplacementInProgressAttempt failed: %w", err)
+ }
+ return ec.handleInProgressAttempt(ctx, lggr, etx, purgeAttempt, blockHeight)
case client.TransactionAlreadyKnown:
// Sequence too low indicated that a transaction at this sequence was confirmed already.
// Mark confirmed_missing_receipt and wait for the next cycle to try to get a receipt
@@ -1000,22 +1039,30 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han
}
}
-// EnsureConfirmedTransactionsInLongestChain finds all confirmed txes up to the depth
+// EnsureConfirmedTransactionsInLongestChain finds all confirmed txes up to the earliest head
// of the given chain and ensures that every one has a receipt with a block hash that is
// in the given chain.
//
// If any of the confirmed transactions does not have a receipt in the chain, it has been
// re-org'd out and will be rebroadcast.
-func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) EnsureConfirmedTransactionsInLongestChain(ctx context.Context, head types.Head[BLOCK_HASH]) error {
- if head.ChainLength() < ec.chainConfig.FinalityDepth() {
- logArgs := []interface{}{
- "chainLength", head.ChainLength(), "finalityDepth", ec.chainConfig.FinalityDepth(),
- }
+func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) EnsureConfirmedTransactionsInLongestChain(ctx context.Context, head types.Head[BLOCK_HASH], latestFinalizedHeadNumber int64) error {
+ logArgs := []interface{}{
+ "chainLength", head.ChainLength(), "latestFinalizedHead number", latestFinalizedHeadNumber,
+ }
+
+ if head.BlockNumber() < latestFinalizedHeadNumber {
+ errMsg := "current head is shorter than latest finalized head"
+ ec.lggr.Errorw(errMsg, append(logArgs, "head block number", head.BlockNumber())...)
+ return errors.New(errMsg)
+ }
+
+ calculatedFinalityDepth := uint32(head.BlockNumber() - latestFinalizedHeadNumber)
+ if head.ChainLength() < calculatedFinalityDepth {
if ec.nConsecutiveBlocksChainTooShort > logAfterNConsecutiveBlocksChainTooShort {
- warnMsg := "Chain length supplied for re-org detection was shorter than FinalityDepth. Re-org protection is not working properly. This could indicate a problem with the remote RPC endpoint, a compatibility issue with a particular blockchain, a bug with this particular blockchain, heads table being truncated too early, remote node out of sync, or something else. If this happens a lot please raise a bug with the Chainlink team including a log output sample and details of the chain and RPC endpoint you are using."
+ warnMsg := "Chain length supplied for re-org detection was shorter than the depth from the latest head to the finalized head. Re-org protection is not working properly. This could indicate a problem with the remote RPC endpoint, a compatibility issue with a particular blockchain, a bug with this particular blockchain, heads table being truncated too early, remote node out of sync, or something else. If this happens a lot please raise a bug with the Chainlink team including a log output sample and details of the chain and RPC endpoint you are using."
ec.lggr.Warnw(warnMsg, append(logArgs, "nConsecutiveBlocksChainTooShort", ec.nConsecutiveBlocksChainTooShort)...)
} else {
- logMsg := "Chain length supplied for re-org detection was shorter than FinalityDepth"
+ logMsg := "Chain length supplied for re-org detection was shorter than the depth from the latest head to the finalized head"
ec.lggr.Debugw(logMsg, append(logArgs, "nConsecutiveBlocksChainTooShort", ec.nConsecutiveBlocksChainTooShort)...)
}
ec.nConsecutiveBlocksChainTooShort++
diff --git a/common/txmgr/models.go b/common/txmgr/models.go
index dd121a2c7c4..ca5e7d4f251 100644
--- a/common/txmgr/models.go
+++ b/common/txmgr/models.go
@@ -11,4 +11,5 @@ const (
TxUnconfirmed = txmgrtypes.TxState("unconfirmed")
TxConfirmed = txmgrtypes.TxState("confirmed")
TxConfirmedMissingReceipt = txmgrtypes.TxState("confirmed_missing_receipt")
+ TxFinalized = txmgrtypes.TxState("finalized")
)
diff --git a/common/txmgr/reaper.go b/common/txmgr/reaper.go
index 932b58f6430..0c797548b16 100644
--- a/common/txmgr/reaper.go
+++ b/common/txmgr/reaper.go
@@ -14,7 +14,6 @@ import (
// Reaper handles periodic database cleanup for Txm
type Reaper[CHAIN_ID types.ID] struct {
store txmgrtypes.TxHistoryReaper[CHAIN_ID]
- config txmgrtypes.ReaperChainConfig
txConfig txmgrtypes.ReaperTransactionsConfig
chainID CHAIN_ID
log logger.Logger
@@ -25,10 +24,9 @@ type Reaper[CHAIN_ID types.ID] struct {
}
// NewReaper instantiates a new reaper object
-func NewReaper[CHAIN_ID types.ID](lggr logger.Logger, store txmgrtypes.TxHistoryReaper[CHAIN_ID], config txmgrtypes.ReaperChainConfig, txConfig txmgrtypes.ReaperTransactionsConfig, chainID CHAIN_ID) *Reaper[CHAIN_ID] {
+func NewReaper[CHAIN_ID types.ID](lggr logger.Logger, store txmgrtypes.TxHistoryReaper[CHAIN_ID], txConfig txmgrtypes.ReaperTransactionsConfig, chainID CHAIN_ID) *Reaper[CHAIN_ID] {
r := &Reaper[CHAIN_ID]{
store,
- config,
txConfig,
chainID,
logger.Named(lggr, "Reaper"),
@@ -103,13 +101,12 @@ func (r *Reaper[CHAIN_ID]) ReapTxes(headNum int64) error {
r.log.Debug("Transactions.ReaperThreshold set to 0; skipping ReapTxes")
return nil
}
- minBlockNumberToKeep := headNum - int64(r.config.FinalityDepth())
mark := time.Now()
timeThreshold := mark.Add(-threshold)
- r.log.Debugw(fmt.Sprintf("reaping old txes created before %s", timeThreshold.Format(time.RFC3339)), "ageThreshold", threshold, "timeThreshold", timeThreshold, "minBlockNumberToKeep", minBlockNumberToKeep)
+ r.log.Debugw(fmt.Sprintf("reaping old txes created before %s", timeThreshold.Format(time.RFC3339)), "ageThreshold", threshold, "timeThreshold", timeThreshold)
- if err := r.store.ReapTxHistory(ctx, minBlockNumberToKeep, timeThreshold, r.chainID); err != nil {
+ if err := r.store.ReapTxHistory(ctx, timeThreshold, r.chainID); err != nil {
return err
}
diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go
index fc27e930c37..28d505e5e05 100644
--- a/common/txmgr/txmgr.go
+++ b/common/txmgr/txmgr.go
@@ -108,6 +108,7 @@ type Txm[
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]
tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]
+ finalizer txmgrtypes.Finalizer[BLOCK_HASH, HEAD]
fwdMgr txmgrtypes.ForwarderManager[ADDR]
txAttemptBuilder txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]
newErrorClassifier NewErrorClassifier
@@ -143,6 +144,7 @@ func NewTxm[
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],
tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE],
+ finalizer txmgrtypes.Finalizer[BLOCK_HASH, HEAD],
newErrorClassifierFunc NewErrorClassifier,
) *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
b := Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{
@@ -165,13 +167,14 @@ func NewTxm[
resender: resender,
tracker: tracker,
newErrorClassifier: newErrorClassifierFunc,
+ finalizer: finalizer,
}
if txCfg.ResendAfterThreshold() <= 0 {
b.logger.Info("Resender: Disabled")
}
if txCfg.ReaperThreshold() > 0 && txCfg.ReaperInterval() > 0 {
- b.reaper = NewReaper[CHAIN_ID](lggr, b.txStore, cfg, txCfg, chainId)
+ b.reaper = NewReaper[CHAIN_ID](lggr, b.txStore, txCfg, chainId)
} else {
b.logger.Info("TxReaper: Disabled")
}
@@ -199,6 +202,10 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Start(ctx
return fmt.Errorf("Txm: Tracker failed to start: %w", err)
}
+ if err := ms.Start(ctx, b.finalizer); err != nil {
+ return fmt.Errorf("Txm: Finalizer failed to start: %w", err)
+ }
+
b.logger.Info("Txm starting runLoop")
b.wg.Add(1)
go b.runLoop()
@@ -293,6 +300,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HealthRepo
services.CopyHealth(report, b.broadcaster.HealthReport())
services.CopyHealth(report, b.confirmer.HealthReport())
services.CopyHealth(report, b.txAttemptBuilder.HealthReport())
+ services.CopyHealth(report, b.finalizer.HealthReport())
})
if b.txConfig.ForwardersEnabled() {
@@ -415,6 +423,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop()
case head := <-b.chHeads:
b.confirmer.mb.Deliver(head)
b.tracker.mb.Deliver(head.BlockNumber())
+ b.finalizer.DeliverLatestHead(head)
case reset := <-b.reset:
// This check prevents the weird edge-case where you can select
// into this block after chStop has already been closed and the
@@ -446,6 +455,10 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop()
if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) {
b.logger.Errorw(fmt.Sprintf("Failed to Close Tracker: %v", err), "err", err)
}
+ err = b.finalizer.Close()
+ if err != nil && (!errors.Is(err, services.ErrAlreadyStopped) || !errors.Is(err, services.ErrCannotStopUnstarted)) {
+ b.logger.Errorw(fmt.Sprintf("Failed to Close Finalizer: %v", err), "err", err)
+ }
return
case <-keysChanged:
// This check prevents the weird edge-case where you can select
@@ -641,12 +654,13 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTransac
}
switch tx.State {
case TxUnconfirmed, TxConfirmedMissingReceipt:
- // Return unconfirmed for ConfirmedMissingReceipt since a receipt is required to determine if it is finalized
- return commontypes.Unconfirmed, nil
+ // Return pending for ConfirmedMissingReceipt since a receipt is required to consider it as unconfirmed
+ return commontypes.Pending, nil
case TxConfirmed:
- // TODO: Check for finality and return finalized status
- // Return unconfirmed if tx receipt's block is newer than the latest finalized block
+ // Return unconfirmed for confirmed transactions because they are not yet finalized
return commontypes.Unconfirmed, nil
+ case TxFinalized:
+ return commontypes.Finalized, nil
case TxFatalError:
// Use an ErrorClassifier to determine if the transaction is considered Fatal
txErr := b.newErrorClassifier(tx.GetError())
diff --git a/common/txmgr/types/config.go b/common/txmgr/types/config.go
index 4d9af5f0673..8b11a45d11d 100644
--- a/common/txmgr/types/config.go
+++ b/common/txmgr/types/config.go
@@ -5,7 +5,6 @@ import "time"
type TransactionManagerChainConfig interface {
BroadcasterChainConfig
ConfirmerChainConfig
- ReaperChainConfig
}
type TransactionManagerFeeConfig interface {
@@ -74,11 +73,6 @@ type ResenderTransactionsConfig interface {
MaxInFlight() uint32
}
-// ReaperConfig is the config subset used by the reaper
-type ReaperChainConfig interface {
- FinalityDepth() uint32
-}
-
type ReaperTransactionsConfig interface {
ReaperInterval() time.Duration
ReaperThreshold() time.Duration
diff --git a/common/txmgr/types/finalizer.go b/common/txmgr/types/finalizer.go
new file mode 100644
index 00000000000..be3c897d0e2
--- /dev/null
+++ b/common/txmgr/types/finalizer.go
@@ -0,0 +1,12 @@
+package types
+
+import (
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
+ "github.com/smartcontractkit/chainlink/v2/common/types"
+)
+
+type Finalizer[BLOCK_HASH types.Hashable, HEAD types.Head[BLOCK_HASH]] interface {
+ // interfaces for running the underlying estimator
+ services.Service
+ DeliverLatestHead(head HEAD) bool
+}
diff --git a/common/txmgr/types/mocks/reaper_chain_config.go b/common/txmgr/types/mocks/reaper_chain_config.go
deleted file mode 100644
index 0531b071708..00000000000
--- a/common/txmgr/types/mocks/reaper_chain_config.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Code generated by mockery v2.43.2. DO NOT EDIT.
-
-package mocks
-
-import mock "github.com/stretchr/testify/mock"
-
-// ReaperConfig is an autogenerated mock type for the ReaperChainConfig type
-type ReaperConfig struct {
- mock.Mock
-}
-
-type ReaperConfig_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *ReaperConfig) EXPECT() *ReaperConfig_Expecter {
- return &ReaperConfig_Expecter{mock: &_m.Mock}
-}
-
-// FinalityDepth provides a mock function with given fields:
-func (_m *ReaperConfig) FinalityDepth() uint32 {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for FinalityDepth")
- }
-
- var r0 uint32
- if rf, ok := ret.Get(0).(func() uint32); ok {
- r0 = rf()
- } else {
- r0 = ret.Get(0).(uint32)
- }
-
- return r0
-}
-
-// ReaperConfig_FinalityDepth_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FinalityDepth'
-type ReaperConfig_FinalityDepth_Call struct {
- *mock.Call
-}
-
-// FinalityDepth is a helper method to define mock.On call
-func (_e *ReaperConfig_Expecter) FinalityDepth() *ReaperConfig_FinalityDepth_Call {
- return &ReaperConfig_FinalityDepth_Call{Call: _e.mock.On("FinalityDepth")}
-}
-
-func (_c *ReaperConfig_FinalityDepth_Call) Run(run func()) *ReaperConfig_FinalityDepth_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run()
- })
- return _c
-}
-
-func (_c *ReaperConfig_FinalityDepth_Call) Return(_a0 uint32) *ReaperConfig_FinalityDepth_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *ReaperConfig_FinalityDepth_Call) RunAndReturn(run func() uint32) *ReaperConfig_FinalityDepth_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewReaperConfig creates a new instance of ReaperConfig. 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 NewReaperConfig(t interface {
- mock.TestingT
- Cleanup(func())
-}) *ReaperConfig {
- mock := &ReaperConfig{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go
index ee166638e34..4467729e167 100644
--- a/common/txmgr/types/mocks/tx_store.go
+++ b/common/txmgr/types/mocks/tx_store.go
@@ -1760,65 +1760,6 @@ func (_c *TxStore_HasInProgressTransaction_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_H
return _c
}
-// IsTxFinalized provides a mock function with given fields: ctx, blockHeight, txID, chainID
-func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID CHAIN_ID) (bool, error) {
- ret := _m.Called(ctx, blockHeight, txID, chainID)
-
- if len(ret) == 0 {
- panic("no return value specified for IsTxFinalized")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) (bool, error)); ok {
- return rf(ctx, blockHeight, txID, chainID)
- }
- if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) bool); ok {
- r0 = rf(ctx, blockHeight, txID, chainID)
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func(context.Context, int64, int64, CHAIN_ID) error); ok {
- r1 = rf(ctx, blockHeight, txID, chainID)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// TxStore_IsTxFinalized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsTxFinalized'
-type TxStore_IsTxFinalized_Call[ADDR types.Hashable, CHAIN_ID types.ID, TX_HASH types.Hashable, BLOCK_HASH types.Hashable, R txmgrtypes.ChainReceipt[TX_HASH, BLOCK_HASH], SEQ types.Sequence, FEE feetypes.Fee] struct {
- *mock.Call
-}
-
-// IsTxFinalized is a helper method to define mock.On call
-// - ctx context.Context
-// - blockHeight int64
-// - txID int64
-// - chainID CHAIN_ID
-func (_e *TxStore_Expecter[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsTxFinalized(ctx interface{}, blockHeight interface{}, txID interface{}, chainID interface{}) *TxStore_IsTxFinalized_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
- return &TxStore_IsTxFinalized_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{Call: _e.mock.On("IsTxFinalized", ctx, blockHeight, txID, chainID)}
-}
-
-func (_c *TxStore_IsTxFinalized_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Run(run func(ctx context.Context, blockHeight int64, txID int64, chainID CHAIN_ID)) *TxStore_IsTxFinalized_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(int64), args[2].(int64), args[3].(CHAIN_ID))
- })
- return _c
-}
-
-func (_c *TxStore_IsTxFinalized_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Return(finalized bool, err error) *TxStore_IsTxFinalized_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
- _c.Call.Return(finalized, err)
- return _c
-}
-
-func (_c *TxStore_IsTxFinalized_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) RunAndReturn(run func(context.Context, int64, int64, CHAIN_ID) (bool, error)) *TxStore_IsTxFinalized_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
- _c.Call.Return(run)
- return _c
-}
-
// LoadTxAttempts provides a mock function with given fields: ctx, etx
func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttempts(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error {
ret := _m.Called(ctx, etx)
@@ -1913,17 +1854,17 @@ func (_c *TxStore_MarkAllConfirmedMissingReceipt_Call[ADDR, CHAIN_ID, TX_HASH, B
return _c
}
-// MarkOldTxesMissingReceiptAsErrored provides a mock function with given fields: ctx, blockNum, finalityDepth, chainID
-func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID CHAIN_ID) error {
- ret := _m.Called(ctx, blockNum, finalityDepth, chainID)
+// MarkOldTxesMissingReceiptAsErrored provides a mock function with given fields: ctx, blockNum, latestFinalizedBlockNum, chainID
+func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, latestFinalizedBlockNum int64, chainID CHAIN_ID) error {
+ ret := _m.Called(ctx, blockNum, latestFinalizedBlockNum, chainID)
if len(ret) == 0 {
panic("no return value specified for MarkOldTxesMissingReceiptAsErrored")
}
var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, int64, uint32, CHAIN_ID) error); ok {
- r0 = rf(ctx, blockNum, finalityDepth, chainID)
+ if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) error); ok {
+ r0 = rf(ctx, blockNum, latestFinalizedBlockNum, chainID)
} else {
r0 = ret.Error(0)
}
@@ -1939,15 +1880,15 @@ type TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR types.Hashable, CHAIN_
// MarkOldTxesMissingReceiptAsErrored is a helper method to define mock.On call
// - ctx context.Context
// - blockNum int64
-// - finalityDepth uint32
+// - latestFinalizedBlockNum int64
// - chainID CHAIN_ID
-func (_e *TxStore_Expecter[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxesMissingReceiptAsErrored(ctx interface{}, blockNum interface{}, finalityDepth interface{}, chainID interface{}) *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
- return &TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{Call: _e.mock.On("MarkOldTxesMissingReceiptAsErrored", ctx, blockNum, finalityDepth, chainID)}
+func (_e *TxStore_Expecter[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxesMissingReceiptAsErrored(ctx interface{}, blockNum interface{}, latestFinalizedBlockNum interface{}, chainID interface{}) *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
+ return &TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{Call: _e.mock.On("MarkOldTxesMissingReceiptAsErrored", ctx, blockNum, latestFinalizedBlockNum, chainID)}
}
-func (_c *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Run(run func(ctx context.Context, blockNum int64, finalityDepth uint32, chainID CHAIN_ID)) *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
+func (_c *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Run(run func(ctx context.Context, blockNum int64, latestFinalizedBlockNum int64, chainID CHAIN_ID)) *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
_c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(int64), args[2].(uint32), args[3].(CHAIN_ID))
+ run(args[0].(context.Context), args[1].(int64), args[2].(int64), args[3].(CHAIN_ID))
})
return _c
}
@@ -1957,7 +1898,7 @@ func (_c *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HAS
return _c
}
-func (_c *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) RunAndReturn(run func(context.Context, int64, uint32, CHAIN_ID) error) *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
+func (_c *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) RunAndReturn(run func(context.Context, int64, int64, CHAIN_ID) error) *TxStore_MarkOldTxesMissingReceiptAsErrored_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
_c.Call.Return(run)
return _c
}
@@ -2069,17 +2010,17 @@ func (_c *TxStore_PruneUnstartedTxQueue_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH
return _c
}
-// ReapTxHistory provides a mock function with given fields: ctx, minBlockNumberToKeep, timeThreshold, chainID
-func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID) error {
- ret := _m.Called(ctx, minBlockNumberToKeep, timeThreshold, chainID)
+// ReapTxHistory provides a mock function with given fields: ctx, timeThreshold, chainID
+func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHistory(ctx context.Context, timeThreshold time.Time, chainID CHAIN_ID) error {
+ ret := _m.Called(ctx, timeThreshold, chainID)
if len(ret) == 0 {
panic("no return value specified for ReapTxHistory")
}
var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, int64, time.Time, CHAIN_ID) error); ok {
- r0 = rf(ctx, minBlockNumberToKeep, timeThreshold, chainID)
+ if rf, ok := ret.Get(0).(func(context.Context, time.Time, CHAIN_ID) error); ok {
+ r0 = rf(ctx, timeThreshold, chainID)
} else {
r0 = ret.Error(0)
}
@@ -2094,16 +2035,15 @@ type TxStore_ReapTxHistory_Call[ADDR types.Hashable, CHAIN_ID types.ID, TX_HASH
// ReapTxHistory is a helper method to define mock.On call
// - ctx context.Context
-// - minBlockNumberToKeep int64
// - timeThreshold time.Time
// - chainID CHAIN_ID
-func (_e *TxStore_Expecter[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHistory(ctx interface{}, minBlockNumberToKeep interface{}, timeThreshold interface{}, chainID interface{}) *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
- return &TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{Call: _e.mock.On("ReapTxHistory", ctx, minBlockNumberToKeep, timeThreshold, chainID)}
+func (_e *TxStore_Expecter[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHistory(ctx interface{}, timeThreshold interface{}, chainID interface{}) *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
+ return &TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{Call: _e.mock.On("ReapTxHistory", ctx, timeThreshold, chainID)}
}
-func (_c *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Run(run func(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID)) *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
+func (_c *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Run(run func(ctx context.Context, timeThreshold time.Time, chainID CHAIN_ID)) *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
_c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(int64), args[2].(time.Time), args[3].(CHAIN_ID))
+ run(args[0].(context.Context), args[1].(time.Time), args[2].(CHAIN_ID))
})
return _c
}
@@ -2113,7 +2053,7 @@ func (_c *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ
return _c
}
-func (_c *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) RunAndReturn(run func(context.Context, int64, time.Time, CHAIN_ID) error) *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
+func (_c *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) RunAndReturn(run func(context.Context, time.Time, CHAIN_ID) error) *TxStore_ReapTxHistory_Call[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] {
_c.Call.Return(run)
return _c
}
diff --git a/common/txmgr/types/tx_store.go b/common/txmgr/types/tx_store.go
index 25040ea3bdb..3d874cc4366 100644
--- a/common/txmgr/types/tx_store.go
+++ b/common/txmgr/types/tx_store.go
@@ -79,6 +79,8 @@ type TransactionStore[
// Search for Tx using the fromAddress and sequence
FindTxWithSequence(ctx context.Context, fromAddress ADDR, seq SEQ) (etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error)
FindNextUnstartedTransactionFromAddress(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)
+
+ // FindTransactionsConfirmedInBlockRange retrieves tx with attempts and partial receipt values for optimization purpose
FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber, lowBlockNumber int64, chainID CHAIN_ID) (etxs []*Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], err error)
FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID CHAIN_ID) (null.Time, error)
FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID CHAIN_ID) (null.Int, error)
@@ -89,7 +91,7 @@ type TransactionStore[
HasInProgressTransaction(ctx context.Context, account ADDR, chainID CHAIN_ID) (exists bool, err error)
LoadTxAttempts(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error
MarkAllConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) (err error)
- MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID CHAIN_ID) error
+ MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, latestFinalizedBlockNum int64, chainID CHAIN_ID) error
PreloadTxes(ctx context.Context, attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error
SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error
SaveInProgressAttempt(ctx context.Context, attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error
@@ -105,11 +107,10 @@ type TransactionStore[
UpdateTxUnstartedToInProgress(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error
UpdateTxFatalError(ctx context.Context, etx *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error
UpdateTxForRebroadcast(ctx context.Context, etx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], etxAttempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error
- IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID CHAIN_ID) (finalized bool, err error)
}
type TxHistoryReaper[CHAIN_ID types.ID] interface {
- ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID) error
+ ReapTxHistory(ctx context.Context, timeThreshold time.Time, chainID CHAIN_ID) error
}
type UnstartedTxQueuePruner interface {
@@ -132,4 +133,5 @@ type ChainReceipt[TX_HASH, BLOCK_HASH types.Hashable] interface {
GetFeeUsed() uint64
GetTransactionIndex() uint
GetBlockHash() BLOCK_HASH
+ GetRevertReason() *string
}
diff --git a/common/types/mocks/monitoring_endpoint.go b/common/types/mocks/monitoring_endpoint.go
new file mode 100644
index 00000000000..5afc04c9090
--- /dev/null
+++ b/common/types/mocks/monitoring_endpoint.go
@@ -0,0 +1,65 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import mock "github.com/stretchr/testify/mock"
+
+// MonitoringEndpoint is an autogenerated mock type for the MonitoringEndpoint type
+type MonitoringEndpoint struct {
+ mock.Mock
+}
+
+type MonitoringEndpoint_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MonitoringEndpoint) EXPECT() *MonitoringEndpoint_Expecter {
+ return &MonitoringEndpoint_Expecter{mock: &_m.Mock}
+}
+
+// SendLog provides a mock function with given fields: log
+func (_m *MonitoringEndpoint) SendLog(log []byte) {
+ _m.Called(log)
+}
+
+// MonitoringEndpoint_SendLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendLog'
+type MonitoringEndpoint_SendLog_Call struct {
+ *mock.Call
+}
+
+// SendLog is a helper method to define mock.On call
+// - log []byte
+func (_e *MonitoringEndpoint_Expecter) SendLog(log interface{}) *MonitoringEndpoint_SendLog_Call {
+ return &MonitoringEndpoint_SendLog_Call{Call: _e.mock.On("SendLog", log)}
+}
+
+func (_c *MonitoringEndpoint_SendLog_Call) Run(run func(log []byte)) *MonitoringEndpoint_SendLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].([]byte))
+ })
+ return _c
+}
+
+func (_c *MonitoringEndpoint_SendLog_Call) Return() *MonitoringEndpoint_SendLog_Call {
+ _c.Call.Return()
+ return _c
+}
+
+func (_c *MonitoringEndpoint_SendLog_Call) RunAndReturn(run func([]byte)) *MonitoringEndpoint_SendLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMonitoringEndpoint creates a new instance of MonitoringEndpoint. 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 NewMonitoringEndpoint(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MonitoringEndpoint {
+ mock := &MonitoringEndpoint{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/contracts/.changeset/eighty-ways-vanish.md b/contracts/.changeset/eighty-ways-vanish.md
new file mode 100644
index 00000000000..3a48ca4e710
--- /dev/null
+++ b/contracts/.changeset/eighty-ways-vanish.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+Publish a comment in PR mentioning the actor and informing her about avilability of Slither reports.
diff --git a/contracts/.changeset/itchy-deers-deny.md b/contracts/.changeset/itchy-deers-deny.md
new file mode 100644
index 00000000000..888d58ce311
--- /dev/null
+++ b/contracts/.changeset/itchy-deers-deny.md
@@ -0,0 +1,5 @@
+---
+"@chainlink/contracts": patch
+---
+
+More comprehensive & product-scoped Solidity Foundry pipeline
diff --git a/contracts/.changeset/itchy-turtles-agree.md b/contracts/.changeset/itchy-turtles-agree.md
new file mode 100644
index 00000000000..930ab850d9b
--- /dev/null
+++ b/contracts/.changeset/itchy-turtles-agree.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': minor
+---
+
+#internal Add an event with indexed topics that get hashed to Chain Reader Tester contract.
diff --git a/contracts/.changeset/loud-lobsters-guess.md b/contracts/.changeset/loud-lobsters-guess.md
new file mode 100644
index 00000000000..e470267e4e4
--- /dev/null
+++ b/contracts/.changeset/loud-lobsters-guess.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+auto: create a replication from v2_3 to v2_3_zksync
diff --git a/contracts/.changeset/mean-zoos-fly.md b/contracts/.changeset/mean-zoos-fly.md
new file mode 100644
index 00000000000..72eb98198d0
--- /dev/null
+++ b/contracts/.changeset/mean-zoos-fly.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+add OZ v0.5 contracts
diff --git a/contracts/.changeset/nasty-llamas-prove.md b/contracts/.changeset/nasty-llamas-prove.md
new file mode 100644
index 00000000000..c3b26c9be36
--- /dev/null
+++ b/contracts/.changeset/nasty-llamas-prove.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+DEVSVCS-147: add a reentrancy guard for balance monitor
diff --git a/contracts/.changeset/nice-planets-share.md b/contracts/.changeset/nice-planets-share.md
new file mode 100644
index 00000000000..a8af56ac613
--- /dev/null
+++ b/contracts/.changeset/nice-planets-share.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': minor
+---
+
+EnumerableMap Library for an Address to Bytes mapping
diff --git a/contracts/.changeset/polite-masks-jog.md b/contracts/.changeset/polite-masks-jog.md
new file mode 100644
index 00000000000..93fba83b558
--- /dev/null
+++ b/contracts/.changeset/polite-masks-jog.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+#internal
diff --git a/contracts/.changeset/seven-donkeys-live.md b/contracts/.changeset/seven-donkeys-live.md
new file mode 100644
index 00000000000..141588f5b9f
--- /dev/null
+++ b/contracts/.changeset/seven-donkeys-live.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+improve cron contracts imports
diff --git a/contracts/.changeset/silver-pots-cover.md b/contracts/.changeset/silver-pots-cover.md
new file mode 100644
index 00000000000..93fba83b558
--- /dev/null
+++ b/contracts/.changeset/silver-pots-cover.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+#internal
diff --git a/contracts/.changeset/slimy-pens-listen.md b/contracts/.changeset/slimy-pens-listen.md
new file mode 100644
index 00000000000..ff81d222378
--- /dev/null
+++ b/contracts/.changeset/slimy-pens-listen.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+#internal prevent editing whether or not a DON accepts workflows
diff --git a/contracts/.changeset/tender-comics-check.md b/contracts/.changeset/tender-comics-check.md
new file mode 100644
index 00000000000..6ea48d92e4e
--- /dev/null
+++ b/contracts/.changeset/tender-comics-check.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+#internal prevent reentrancy when configuring DON in capabilities registry
diff --git a/contracts/.changeset/thirty-lamps-reply.md b/contracts/.changeset/thirty-lamps-reply.md
new file mode 100644
index 00000000000..d8bcf8d4e83
--- /dev/null
+++ b/contracts/.changeset/thirty-lamps-reply.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': patch
+---
+
+implement an auto registry for zksync with no forwarder interface change
diff --git a/contracts/.changeset/three-stingrays-compete.md b/contracts/.changeset/three-stingrays-compete.md
new file mode 100644
index 00000000000..613b2784657
--- /dev/null
+++ b/contracts/.changeset/three-stingrays-compete.md
@@ -0,0 +1,5 @@
+---
+'@chainlink/contracts': minor
+---
+
+add ccip contracts to the repo
diff --git a/contracts/.gas-snapshot b/contracts/.gas-snapshot
new file mode 100644
index 00000000000..3a0354d539c
--- /dev/null
+++ b/contracts/.gas-snapshot
@@ -0,0 +1,112 @@
+CapabilitiesRegistry_AddCapabilitiesTest:test_AddCapability_NoConfigurationContract() (gas: 154832)
+CapabilitiesRegistry_AddCapabilitiesTest:test_AddCapability_WithConfiguration() (gas: 178813)
+CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_CalledByNonAdmin() (gas: 24723)
+CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_CapabilityExists() (gas: 145703)
+CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_ConfigurationContractDoesNotMatchInterface() (gas: 94606)
+CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_ConfigurationContractNotDeployed() (gas: 92961)
+CapabilitiesRegistry_AddDONTest:test_AddDON() (gas: 372302)
+CapabilitiesRegistry_AddDONTest:test_RevertWhen_CalledByNonAdmin() (gas: 19273)
+CapabilitiesRegistry_AddDONTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 169752)
+CapabilitiesRegistry_AddDONTest:test_RevertWhen_DeprecatedCapabilityAdded() (gas: 239789)
+CapabilitiesRegistry_AddDONTest:test_RevertWhen_DuplicateCapabilityAdded() (gas: 249596)
+CapabilitiesRegistry_AddDONTest:test_RevertWhen_DuplicateNodeAdded() (gas: 116890)
+CapabilitiesRegistry_AddDONTest:test_RevertWhen_FaultToleranceIsZero() (gas: 43358)
+CapabilitiesRegistry_AddDONTest:test_RevertWhen_NodeAlreadyBelongsToWorkflowDON() (gas: 343924)
+CapabilitiesRegistry_AddDONTest:test_RevertWhen_NodeDoesNotSupportCapability() (gas: 180150)
+CapabilitiesRegistry_AddNodeOperatorsTest:test_AddNodeOperators() (gas: 184135)
+CapabilitiesRegistry_AddNodeOperatorsTest:test_RevertWhen_CalledByNonAdmin() (gas: 17602)
+CapabilitiesRegistry_AddNodeOperatorsTest:test_RevertWhen_NodeOperatorAdminAddressZero() (gas: 18498)
+CapabilitiesRegistry_AddNodesTest:test_AddsNodeParams() (gas: 358448)
+CapabilitiesRegistry_AddNodesTest:test_OwnerCanAddNodes() (gas: 358414)
+CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingDuplicateP2PId() (gas: 301229)
+CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithInvalidCapability() (gas: 55174)
+CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithInvalidNodeOperator() (gas: 24895)
+CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithoutCapabilities() (gas: 27669)
+CapabilitiesRegistry_AddNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 25108)
+CapabilitiesRegistry_AddNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 27408)
+CapabilitiesRegistry_AddNodesTest:test_RevertWhen_SignerAddressEmpty() (gas: 27047)
+CapabilitiesRegistry_AddNodesTest:test_RevertWhen_SignerAddressNotUnique() (gas: 309679)
+CapabilitiesRegistry_DeprecateCapabilitiesTest:test_DeprecatesCapability() (gas: 89807)
+CapabilitiesRegistry_DeprecateCapabilitiesTest:test_EmitsEvent() (gas: 89935)
+CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CalledByNonAdmin() (gas: 22944)
+CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 16231)
+CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CapabilityIsDeprecated() (gas: 91264)
+CapabilitiesRegistry_GetCapabilitiesTest:test_ReturnsCapabilities() (gas: 135553)
+CapabilitiesRegistry_GetDONsTest:test_CorrectlyFetchesDONs() (gas: 65468)
+CapabilitiesRegistry_GetDONsTest:test_DoesNotIncludeRemovedDONs() (gas: 64924)
+CapabilitiesRegistry_GetHashedCapabilityTest:test_CorrectlyGeneratesHashedCapabilityId() (gas: 11428)
+CapabilitiesRegistry_GetHashedCapabilityTest:test_DoesNotCauseIncorrectClashes() (gas: 13087)
+CapabilitiesRegistry_GetNodeOperatorsTest:test_CorrectlyFetchesNodeOperators() (gas: 36407)
+CapabilitiesRegistry_GetNodeOperatorsTest:test_DoesNotIncludeRemovedNodeOperators() (gas: 38692)
+CapabilitiesRegistry_GetNodesTest:test_CorrectlyFetchesNodes() (gas: 65288)
+CapabilitiesRegistry_GetNodesTest:test_DoesNotIncludeRemovedNodes() (gas: 73533)
+CapabilitiesRegistry_RemoveDONsTest:test_RemovesDON() (gas: 54761)
+CapabilitiesRegistry_RemoveDONsTest:test_RevertWhen_CalledByNonAdmin() (gas: 15647)
+CapabilitiesRegistry_RemoveDONsTest:test_RevertWhen_DONDoesNotExist() (gas: 16550)
+CapabilitiesRegistry_RemoveNodeOperatorsTest:test_RemovesNodeOperator() (gas: 36122)
+CapabilitiesRegistry_RemoveNodeOperatorsTest:test_RevertWhen_CalledByNonOwner() (gas: 15816)
+CapabilitiesRegistry_RemoveNodesTest:test_CanAddNodeWithSameSignerAddressAfterRemoving() (gas: 115151)
+CapabilitiesRegistry_RemoveNodesTest:test_CanRemoveWhenDONDeleted() (gas: 287716)
+CapabilitiesRegistry_RemoveNodesTest:test_CanRemoveWhenNodeNoLongerPartOfDON() (gas: 561023)
+CapabilitiesRegistry_RemoveNodesTest:test_OwnerCanRemoveNodes() (gas: 73376)
+CapabilitiesRegistry_RemoveNodesTest:test_RemovesNode() (gas: 75211)
+CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 25053)
+CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_NodeDoesNotExist() (gas: 18418)
+CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_NodePartOfCapabilitiesDON() (gas: 385369)
+CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 18408)
+CapabilitiesRegistry_TypeAndVersionTest:test_TypeAndVersion() (gas: 9796)
+CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_CalledByNonAdmin() (gas: 19415)
+CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 152914)
+CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DONDoesNotExist() (gas: 17835)
+CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DeprecatedCapabilityAdded() (gas: 222996)
+CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DuplicateCapabilityAdded() (gas: 232804)
+CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DuplicateNodeAdded() (gas: 107643)
+CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_NodeDoesNotSupportCapability() (gas: 163357)
+CapabilitiesRegistry_UpdateDONTest:test_UpdatesDON() (gas: 371909)
+CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_CalledByNonAdminAndNonOwner() (gas: 20728)
+CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorAdminIsZeroAddress() (gas: 20052)
+CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorDoesNotExist() (gas: 19790)
+CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorIdAndParamLengthsMismatch() (gas: 15430)
+CapabilitiesRegistry_UpdateNodeOperatorTest:test_UpdatesNodeOperator() (gas: 37034)
+CapabilitiesRegistry_UpdateNodesTest:test_CanUpdateParamsIfNodeSignerAddressNoLongerUsed() (gas: 256371)
+CapabilitiesRegistry_UpdateNodesTest:test_OwnerCanUpdateNodes() (gas: 162166)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_AddingNodeWithInvalidCapability() (gas: 35873)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByAnotherNodeOperatorAdmin() (gas: 29200)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 29377)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeDoesNotExist() (gas: 29199)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeSignerAlreadyAssignedToAnotherNode() (gas: 31326)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 29165)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByCapabilityDON() (gas: 470910)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByWorkflowDON() (gas: 341191)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_SignerAddressEmpty() (gas: 29058)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_UpdatingNodeWithoutCapabilities() (gas: 27587)
+CapabilitiesRegistry_UpdateNodesTest:test_UpdatesNodeParams() (gas: 162220)
+KeystoneForwarder_ReportTest:test_Report_ConfigVersion() (gas: 2002057)
+KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverInterfaceNotSupported() (gas: 128934)
+KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverNotContract() (gas: 130621)
+KeystoneForwarder_ReportTest:test_Report_SuccessfulDelivery() (gas: 359123)
+KeystoneForwarder_ReportTest:test_Report_SuccessfulRetryWithMoreGas() (gas: 423982)
+KeystoneForwarder_ReportTest:test_RevertWhen_AnySignatureIsInvalid() (gas: 86348)
+KeystoneForwarder_ReportTest:test_RevertWhen_AnySignerIsInvalid() (gas: 118486)
+KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasDuplicateSignatures() (gas: 94516)
+KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasIncorrectDON() (gas: 75930)
+KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasInexistentConfigVersion() (gas: 76320)
+KeystoneForwarder_ReportTest:test_RevertWhen_ReportIsMalformed() (gas: 45585)
+KeystoneForwarder_ReportTest:test_RevertWhen_RetryingInvalidContractTransmission() (gas: 143354)
+KeystoneForwarder_ReportTest:test_RevertWhen_RetryingSuccessfulTransmission() (gas: 353272)
+KeystoneForwarder_ReportTest:test_RevertWhen_TooFewSignatures() (gas: 55292)
+KeystoneForwarder_ReportTest:test_RevertWhen_TooManySignatures() (gas: 56050)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_ExcessSigners() (gas: 20184)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_FaultToleranceIsZero() (gas: 88057)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_InsufficientSigners() (gas: 14533)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_NotOwner() (gas: 88766)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingDuplicateSigners() (gas: 114570)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingZeroAddressSigner() (gas: 114225)
+KeystoneForwarder_SetConfigTest:test_SetConfig_FirstTime() (gas: 1540541)
+KeystoneForwarder_SetConfigTest:test_SetConfig_WhenSignersAreRemoved() (gas: 1535211)
+KeystoneForwarder_TypeAndVersionTest:test_TypeAndVersion() (gas: 9641)
+KeystoneRouter_SetConfigTest:test_AddForwarder_RevertWhen_NotOwner() (gas: 10978)
+KeystoneRouter_SetConfigTest:test_RemoveForwarder_RevertWhen_NotOwner() (gas: 10923)
+KeystoneRouter_SetConfigTest:test_RemoveForwarder_Success() (gas: 17599)
+KeystoneRouter_SetConfigTest:test_Route_RevertWhen_UnauthorizedForwarder() (gas: 18552)
+KeystoneRouter_SetConfigTest:test_Route_Success() (gas: 76407)
\ No newline at end of file
diff --git a/contracts/.prettierignore b/contracts/.prettierignore
index 7c3131db424..440cf95afa2 100644
--- a/contracts/.prettierignore
+++ b/contracts/.prettierignore
@@ -21,6 +21,7 @@ solc
LinkToken.json
typechain
**/vendor
+src/v0.8/ccip/**
# Ignore TS definition and map files
**/**.d.ts
@@ -35,4 +36,4 @@ venv/
.solhint.json
src/v0.8/mocks/FunctionsOracleEventsMock.sol
-src/v0.8/mocks/FunctionsBillingRegistryEventsMock.sol
\ No newline at end of file
+src/v0.8/mocks/FunctionsBillingRegistryEventsMock.sol
diff --git a/contracts/.prettierrc.js b/contracts/.prettierrc.js
index 774a5e964e8..17662841223 100644
--- a/contracts/.prettierrc.js
+++ b/contracts/.prettierrc.js
@@ -5,6 +5,7 @@ module.exports = {
endOfLine: 'auto',
tabWidth: 2,
trailingComma: 'all',
+ plugins: ['prettier-plugin-solidity'],
overrides: [
{
files: '*.sol',
diff --git a/contracts/.solhintignore b/contracts/.solhintignore
index bab41a57940..bad1935442b 100644
--- a/contracts/.solhintignore
+++ b/contracts/.solhintignore
@@ -1,6 +1,3 @@
-# 344 warnings
-#./src/v0.8/automation
-
# Ignore frozen Automation code
./src/v0.8/automation/v1_2
./src/v0.8/automation/interfaces/v1_2
@@ -39,6 +36,7 @@
./src/v0.8/llo-feeds/test
./src/v0.8/vrf/testhelpers
./src/v0.8/functions/tests
+./src/v0.8/ccip/test
# Always ignore vendor
./src/v0.8/vendor
diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile
index c3e69464698..0ebad8446e5 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 = functions keystone l2ep llo-feeds operatorforwarder shared transmission
+# profile defined and use the Foundry snapshots.
+ALL_FOUNDRY_PRODUCTS = ccip functions keystone l2ep liquiditymanager llo-feeds operatorforwarder 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`
@@ -16,11 +16,11 @@ ALL_FOUNDRY_PRODUCTS = functions keystone l2ep llo-feeds operatorforwarder share
# a static fuzz seed by default, flaky gas results per platform are still observed.
.PHONY: snapshot
snapshot: ## Make a snapshot for a specific product.
- export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "testFuzz_\w{1,}?" --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot
+ export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "test_?Fuzz_\w{1,}?" --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot
.PHONY: snapshot-diff
snapshot-diff: ## Make a snapshot for a specific product.
- export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "testFuzz_\w{1,}?" --diff gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot
+ export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "test_?Fuzz_\w{1,}?" --diff gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot
.PHONY: snapshot-all
@@ -50,6 +50,21 @@ foundry-refresh: foundry
git submodule deinit -f .
git submodule update --init --recursive
+ccip-precommit: export FOUNDRY_PROFILE=ccip
+.PHONY: ccip-precommit
+ccip-precommit:
+ forge test
+ make snapshot
+ forge fmt
+ pnpm solhint
+
+ccip-lcov: export FOUNDRY_PROFILE=ccip
+.PHONY: ccip-lcov
+ccip-lcov:
+ forge coverage --report lcov
+ ../tools/ci/ccip_lcov_prune ./lcov.info ./lcov.info.pruned
+ genhtml -o report lcov.info.pruned --branch-coverage
+
# To generate gethwrappers for a specific product, either set the `FOUNDRY_PROFILE`
# env var or call the target with `FOUNDRY_PROFILE=product`
# This uses FOUNDRY_PROFILE, even though it does support non-foundry products. This
diff --git a/contracts/README.md b/contracts/README.md
index 26b0a823298..182891ceef7 100644
--- a/contracts/README.md
+++ b/contracts/README.md
@@ -67,5 +67,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## License
+Most of the contracts are licensed under the [MIT](https://choosealicense.com/licenses/mit/) license.
+An exception to this is the ccip folder, which defaults to be licensed under the [BUSL-1.1](./src/v0.8/ccip/LICENSE.md) license, however, there are a few exceptions
-[MIT](https://choosealicense.com/licenses/mit/)
+- `src/v0.8/ccip/applications/*` is licensed under the [MIT](./src/v0.8/ccip/LICENSE-MIT.md) license
+- `src/v0.8/ccip/interfaces/*` is licensed under the [MIT](./src/v0.8/ccip/LICENSE-MIT.md) license
+- `src/v0.8/ccip/libraries/{Client.sol, Internal.sol}` is licensed under the [MIT](./src/v0.8/ccip/LICENSE-MIT.md) license
\ No newline at end of file
diff --git a/contracts/STYLE_GUIDE.md b/contracts/STYLE_GUIDE.md
index b9294de5765..c5dc20abeab 100644
--- a/contracts/STYLE_GUIDE.md
+++ b/contracts/STYLE_GUIDE.md
@@ -1,7 +1,7 @@
# Structure
-This guide is split into two sections: [Guidelines](#guidelines) and [Rules](#rules).
-Guidelines are recommendations that should be followed but are hard to enforce in an automated way.
+This guide is split into two sections: [Guidelines](#guidelines) and [Rules](#rules).
+Guidelines are recommendations that should be followed but are hard to enforce in an automated way.
Rules are all enforced through CI, this can be through Solhint rules or other tools.
## Background
@@ -76,11 +76,11 @@ uint256 networkFeeUSDCents; // good
struct FeeTokenConfigArgs {
address token; // ────────────╮ Token address
uint32 networkFeeUSD; // │ Flat network fee to charge for messages, multiples of 0.01 USD
- // │ multiline comments should work like this. More fee info
+ // │ multiline comments should work like this. More fee info
uint64 gasMultiplier; // ─────╯ Price multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost
uint64 premiumMultiplier; // ─╮ Multiplier for fee-token-specific premiums
bool enabled; // ─────────────╯ Whether this fee token is enabled
- uint256 fee; // The flat fee the user pays in juels
+ uint256 fee; // The flat fee the user pays in juels
}
```
## Functions
@@ -132,7 +132,7 @@ assembly {
// call and return whether we succeeded. ignore return data
// call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0, 0)
-
+
// limit our copy to maxReturnBytes bytes
let toCopy := returndatasize()
if gt(toCopy, maxReturnBytes) {
@@ -242,7 +242,7 @@ contract AccessControlledFoo is Foo {
contract OffchainAggregator is ITypeAndVersion {
string public constant override typeAndVersion = "OffchainAggregator 1.0.0";
-
+
function getData() public returns(uint256) {
return 4;
}
@@ -310,8 +310,8 @@ import {IPool} from "../interfaces/pools/IPool.sol";
import {AggregateRateLimiter} from "../AggregateRateLimiter.sol";
import {Client} from "../libraries/Client.sol";
-import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol";
-import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol";
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
```
## Variables
diff --git a/contracts/configs/slither/.slither.config-artifacts.json b/contracts/configs/slither/.slither.config-artifacts.json
new file mode 100644
index 00000000000..75071341f51
--- /dev/null
+++ b/contracts/configs/slither/.slither.config-artifacts.json
@@ -0,0 +1,3 @@
+{
+ "filter_paths": "(openzeppelin|mocks/|test/|tests/|testhelpers)"
+}
diff --git a/contracts/configs/slither/.slither.config-ccip-pr.json b/contracts/configs/slither/.slither.config-ccip-pr.json
new file mode 100644
index 00000000000..84d231ea07b
--- /dev/null
+++ b/contracts/configs/slither/.slither.config-ccip-pr.json
@@ -0,0 +1,4 @@
+{
+ "filter_paths": "(openzeppelin|mocks/|test/|tests/|testhelpers)",
+ "detectors_to_exclude": "pragma,solc-version,naming-convention,assembly,reentrancy-events,timestamp,calls-loop,unused-return"
+}
diff --git a/contracts/configs/slither/.slither.config-default-pr.json b/contracts/configs/slither/.slither.config-default-pr.json
new file mode 100644
index 00000000000..1ef145a7954
--- /dev/null
+++ b/contracts/configs/slither/.slither.config-default-pr.json
@@ -0,0 +1,4 @@
+{
+ "filter_paths": "(openzeppelin|mocks/|test/|tests/|testhelpers)",
+ "detectors_to_exclude": "pragma"
+}
diff --git a/contracts/foundry.toml b/contracts/foundry.toml
index 08940b4e9ff..c755ba6437b 100644
--- a/contracts/foundry.toml
+++ b/contracts/foundry.toml
@@ -16,6 +16,19 @@ gas_price = 1
block_timestamp = 1234567890
block_number = 12345
+[fmt]
+tab_width = 2
+multiline_func_header = "params_first"
+sort_imports = true
+single_line_statement_blocks = "preserve"
+
+[profile.ccip]
+solc_version = '0.8.24'
+src = 'src/v0.8/ccip'
+test = 'src/v0.8/ccip/test'
+optimizer_runs = 3_600
+evm_version = 'paris'
+
[profile.functions]
solc_version = '0.8.19'
src = 'src/v0.8/functions/dev/v1_X'
@@ -52,6 +65,13 @@ src = 'src/v0.8/llo-feeds'
test = 'src/v0.8/llo-feeds/test'
solc_version = '0.8.19'
+[profile.liquiditymanager]
+optimizer_runs = 1000000
+src = 'src/v0.8/liquiditymanager'
+test = 'src/v0.8/liquiditymanager/test'
+solc_version = '0.8.24'
+evm_version = 'paris'
+
[profile.keystone]
optimizer_runs = 1_000_000
solc_version = '0.8.24'
diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot
new file mode 100644
index 00000000000..5fc99a9a409
--- /dev/null
+++ b/contracts/gas-snapshots/ccip.gas-snapshot
@@ -0,0 +1,943 @@
+ARMProxyStandaloneTest:test_ARMCallEmptyContractRevert() (gas: 19600)
+ARMProxyStandaloneTest:test_Constructor() (gas: 374544)
+ARMProxyStandaloneTest:test_SetARM() (gas: 16494)
+ARMProxyStandaloneTest:test_SetARMzero() (gas: 11216)
+ARMProxyTest:test_ARMCallRevertReasonForwarded() (gas: 47793)
+ARMProxyTest:test_ARMIsBlessed_Success() (gas: 36269)
+ARMProxyTest:test_ARMIsCursed_Success() (gas: 49740)
+AggregateTokenLimiter_constructor:test_Constructor_Success() (gas: 26920)
+AggregateTokenLimiter_getTokenBucket:test_GetTokenBucket_Success() (gas: 19691)
+AggregateTokenLimiter_getTokenBucket:test_Refill_Success() (gas: 40911)
+AggregateTokenLimiter_getTokenBucket:test_TimeUnderflow_Revert() (gas: 15368)
+AggregateTokenLimiter_getTokenLimitAdmin:test_GetTokenLimitAdmin_Success() (gas: 10531)
+AggregateTokenLimiter_getTokenValue:test_GetTokenValue_Success() (gas: 19696)
+AggregateTokenLimiter_getTokenValue:test_NoTokenPrice_Reverts() (gas: 21281)
+AggregateTokenLimiter_rateLimitValue:test_AggregateValueMaxCapacityExceeded_Revert() (gas: 16418)
+AggregateTokenLimiter_rateLimitValue:test_RateLimitValueSuccess_gas() (gas: 18306)
+AggregateTokenLimiter_setAdmin:test_OnlyOwnerOrAdmin_Revert() (gas: 13047)
+AggregateTokenLimiter_setAdmin:test_Owner_Success() (gas: 18989)
+AggregateTokenLimiter_setRateLimiterConfig:test_OnlyOnlyCallableByAdminOrOwner_Revert() (gas: 17479)
+AggregateTokenLimiter_setRateLimiterConfig:test_Owner_Success() (gas: 30062)
+AggregateTokenLimiter_setRateLimiterConfig:test_TokenLimitAdmin_Success() (gas: 32071)
+BurnFromMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 28675)
+BurnFromMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55158)
+BurnFromMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 243525)
+BurnFromMintTokenPool_lockOrBurn:test_Setup_Success() (gas: 23907)
+BurnMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 27565)
+BurnMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55158)
+BurnMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 241416)
+BurnMintTokenPool_lockOrBurn:test_Setup_Success() (gas: 17633)
+BurnMintTokenPool_releaseOrMint:test_ChainNotAllowed_Revert() (gas: 28537)
+BurnMintTokenPool_releaseOrMint:test_PoolMintNotHealthy_Revert() (gas: 55991)
+BurnMintTokenPool_releaseOrMint:test_PoolMint_Success() (gas: 110657)
+BurnWithFromMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 28675)
+BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 55158)
+BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 243552)
+BurnWithFromMintTokenPool_lockOrBurn:test_Setup_Success() (gas: 24260)
+CCIPClientExample_sanity:test_ImmutableExamples_Success() (gas: 2131281)
+CCIPConfigSetup:test_getCapabilityConfiguration_Success() (gas: 9495)
+CCIPConfig_ConfigStateMachine:test__computeConfigDigest_Success() (gas: 70755)
+CCIPConfig_ConfigStateMachine:test__computeNewConfigWithMeta_InitToRunning_Success() (gas: 363647)
+CCIPConfig_ConfigStateMachine:test__computeNewConfigWithMeta_RunningToStaging_Success() (gas: 488774)
+CCIPConfig_ConfigStateMachine:test__computeNewConfigWithMeta_StagingToRunning_Success() (gas: 453384)
+CCIPConfig_ConfigStateMachine:test__groupByPluginType_TooManyOCR3Configs_Reverts() (gas: 37027)
+CCIPConfig_ConfigStateMachine:test__groupByPluginType_threeCommitConfigs_Reverts() (gas: 61043)
+CCIPConfig_ConfigStateMachine:test__groupByPluginType_threeExecutionConfigs_Reverts() (gas: 60963)
+CCIPConfig_ConfigStateMachine:test__stateFromConfigLength_Success() (gas: 11764)
+CCIPConfig_ConfigStateMachine:test__validateConfigStateTransition_Success() (gas: 8765)
+CCIPConfig_ConfigStateMachine:test__validateConfigTransition_InitToRunning_Success() (gas: 311991)
+CCIPConfig_ConfigStateMachine:test__validateConfigTransition_InitToRunning_WrongConfigCount_Reverts() (gas: 49663)
+CCIPConfig_ConfigStateMachine:test__validateConfigTransition_NonExistentConfigTransition_Reverts() (gas: 32275)
+CCIPConfig_ConfigStateMachine:test__validateConfigTransition_RunningToStaging_Success() (gas: 376576)
+CCIPConfig_ConfigStateMachine:test__validateConfigTransition_RunningToStaging_WrongConfigCount_Reverts() (gas: 120943)
+CCIPConfig_ConfigStateMachine:test__validateConfigTransition_RunningToStaging_WrongConfigDigestBlueGreen_Reverts() (gas: 157105)
+CCIPConfig_ConfigStateMachine:test__validateConfigTransition_StagingToRunning_Success() (gas: 376352)
+CCIPConfig_ConfigStateMachine:test__validateConfigTransition_StagingToRunning_WrongConfigDigest_Reverts() (gas: 157172)
+CCIPConfig_ConfigStateMachine:test_getCapabilityConfiguration_Success() (gas: 9583)
+CCIPConfig__updatePluginConfig:test__updatePluginConfig_InitToRunning_Success() (gas: 1057393)
+CCIPConfig__updatePluginConfig:test__updatePluginConfig_InvalidConfigLength_Reverts() (gas: 27539)
+CCIPConfig__updatePluginConfig:test__updatePluginConfig_InvalidConfigStateTransition_Reverts() (gas: 23105)
+CCIPConfig__updatePluginConfig:test__updatePluginConfig_RunningToStaging_Success() (gas: 2009309)
+CCIPConfig__updatePluginConfig:test__updatePluginConfig_StagingToRunning_Success() (gas: 2616177)
+CCIPConfig__updatePluginConfig:test_getCapabilityConfiguration_Success() (gas: 9583)
+CCIPConfig_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_CommitAndExecConfig_Success() (gas: 1851188)
+CCIPConfig_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_CommitConfigOnly_Success() (gas: 1068362)
+CCIPConfig_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_ExecConfigOnly_Success() (gas: 1068393)
+CCIPConfig_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_OnlyCapabilitiesRegistryCanCall_Reverts() (gas: 9599)
+CCIPConfig_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_ZeroLengthConfig_Success() (gas: 16070)
+CCIPConfig_beforeCapabilityConfigSet:test_getCapabilityConfiguration_Success() (gas: 9583)
+CCIPConfig_chainConfig:test__applyChainConfigUpdates_FChainNotPositive_Reverts() (gas: 184703)
+CCIPConfig_chainConfig:test_applyChainConfigUpdates_addChainConfigs_Success() (gas: 344332)
+CCIPConfig_chainConfig:test_applyChainConfigUpdates_nodeNotInRegistry_Reverts() (gas: 20258)
+CCIPConfig_chainConfig:test_applyChainConfigUpdates_removeChainConfigs_Success() (gas: 267558)
+CCIPConfig_chainConfig:test_applyChainConfigUpdates_selectorNotFound_Reverts() (gas: 14829)
+CCIPConfig_chainConfig:test_getCapabilityConfiguration_Success() (gas: 9626)
+CCIPConfig_validateConfig:test__validateConfig_BootstrapP2PIdsHasDuplicates_Reverts() (gas: 294893)
+CCIPConfig_validateConfig:test__validateConfig_BootstrapP2PIdsNotASubsetOfP2PIds_Reverts() (gas: 298325)
+CCIPConfig_validateConfig:test__validateConfig_BootstrapP2PIdsNotSorted_Reverts() (gas: 295038)
+CCIPConfig_validateConfig:test__validateConfig_ChainSelectorNotFound_Reverts() (gas: 294357)
+CCIPConfig_validateConfig:test__validateConfig_ChainSelectorNotSet_Reverts() (gas: 291431)
+CCIPConfig_validateConfig:test__validateConfig_FMustBePositive_Reverts() (gas: 292396)
+CCIPConfig_validateConfig:test__validateConfig_FTooHigh_Reverts() (gas: 292540)
+CCIPConfig_validateConfig:test__validateConfig_NodeNotInRegistry_Reverts() (gas: 299420)
+CCIPConfig_validateConfig:test__validateConfig_NotEnoughTransmitters_Reverts() (gas: 1160094)
+CCIPConfig_validateConfig:test__validateConfig_OfframpAddressCannotBeZero_Reverts() (gas: 291260)
+CCIPConfig_validateConfig:test__validateConfig_P2PIdsHasDuplicates_Reverts() (gas: 295907)
+CCIPConfig_validateConfig:test__validateConfig_P2PIdsLengthNotMatching_Reverts() (gas: 293229)
+CCIPConfig_validateConfig:test__validateConfig_P2PIdsNotSorted_Reverts() (gas: 295623)
+CCIPConfig_validateConfig:test__validateConfig_Success() (gas: 302186)
+CCIPConfig_validateConfig:test__validateConfig_TooManyBootstrapP2PIds_Reverts() (gas: 294539)
+CCIPConfig_validateConfig:test__validateConfig_TooManySigners_Reverts() (gas: 1215861)
+CCIPConfig_validateConfig:test__validateConfig_TooManyTransmitters_Reverts() (gas: 1214264)
+CCIPConfig_validateConfig:test_getCapabilityConfiguration_Success() (gas: 9562)
+CommitStore_constructor:test_Constructor_Success() (gas: 3091326)
+CommitStore_isUnpausedAndRMNHealthy:test_RMN_Success() (gas: 73420)
+CommitStore_report:test_InvalidIntervalMinLargerThanMax_Revert() (gas: 28670)
+CommitStore_report:test_InvalidInterval_Revert() (gas: 28610)
+CommitStore_report:test_InvalidRootRevert() (gas: 27843)
+CommitStore_report:test_OnlyGasPriceUpdates_Success() (gas: 53253)
+CommitStore_report:test_OnlyPriceUpdateStaleReport_Revert() (gas: 59049)
+CommitStore_report:test_OnlyTokenPriceUpdates_Success() (gas: 53251)
+CommitStore_report:test_Paused_Revert() (gas: 21259)
+CommitStore_report:test_ReportAndPriceUpdate_Success() (gas: 84242)
+CommitStore_report:test_ReportOnlyRootSuccess_gas() (gas: 56313)
+CommitStore_report:test_RootAlreadyCommitted_Revert() (gas: 63969)
+CommitStore_report:test_StaleReportWithRoot_Success() (gas: 119420)
+CommitStore_report:test_Unhealthy_Revert() (gas: 44751)
+CommitStore_report:test_ValidPriceUpdateThenStaleReportWithRoot_Success() (gas: 100758)
+CommitStore_report:test_ZeroEpochAndRound_Revert() (gas: 27626)
+CommitStore_resetUnblessedRoots:test_OnlyOwner_Revert() (gas: 11325)
+CommitStore_resetUnblessedRoots:test_ResetUnblessedRoots_Success() (gas: 143718)
+CommitStore_setDynamicConfig:test_InvalidCommitStoreConfig_Revert() (gas: 37263)
+CommitStore_setDynamicConfig:test_OnlyOwner_Revert() (gas: 37399)
+CommitStore_setDynamicConfig:test_PriceEpochCleared_Success() (gas: 129098)
+CommitStore_setLatestPriceEpochAndRound:test_OnlyOwner_Revert() (gas: 11047)
+CommitStore_setLatestPriceEpochAndRound:test_SetLatestPriceEpochAndRound_Success() (gas: 20642)
+CommitStore_setMinSeqNr:test_OnlyOwner_Revert() (gas: 11046)
+CommitStore_verify:test_Blessed_Success() (gas: 96389)
+CommitStore_verify:test_NotBlessed_Success() (gas: 61374)
+CommitStore_verify:test_Paused_Revert() (gas: 18496)
+CommitStore_verify:test_TooManyLeaves_Revert() (gas: 36785)
+DefensiveExampleTest:test_HappyPath_Success() (gas: 200018)
+DefensiveExampleTest:test_Recovery() (gas: 424253)
+E2E:test_E2E_3MessagesSuccess_gas() (gas: 1103438)
+EVM2EVMMultiOffRamp__releaseOrMintSingleToken:test__releaseOrMintSingleToken_NotACompatiblePool_Revert() (gas: 38157)
+EVM2EVMMultiOffRamp__releaseOrMintSingleToken:test__releaseOrMintSingleToken_Success() (gas: 108343)
+EVM2EVMMultiOffRamp__releaseOrMintSingleToken:test__releaseOrMintSingleToken_TokenHandlingError_revert_Revert() (gas: 116811)
+EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_AddMultipleChains_Success() (gas: 460560)
+EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_AddNewChain_Success() (gas: 95542)
+EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ApplyZeroUpdates_Success() (gas: 12463)
+EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ReplaceExistingChainOnRamp_Revert() (gas: 90385)
+EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ReplaceExistingChain_Success() (gas: 105586)
+EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ZeroOnRampAddress_Revert() (gas: 15719)
+EVM2EVMMultiOffRamp_applySourceChainConfigUpdates:test_ZeroSourceChainSelector_Revert() (gas: 13057)
+EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsDifferentChains_Success() (gas: 298564)
+EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsSameChain_Success() (gas: 239899)
+EVM2EVMMultiOffRamp_batchExecute:test_MultipleReportsSkipDuplicate_Success() (gas: 158863)
+EVM2EVMMultiOffRamp_batchExecute:test_OutOfBoundsGasLimitsAccess_Revert() (gas: 189303)
+EVM2EVMMultiOffRamp_batchExecute:test_SingleReport_Success() (gas: 147582)
+EVM2EVMMultiOffRamp_batchExecute:test_Unhealthy_Revert() (gas: 521508)
+EVM2EVMMultiOffRamp_batchExecute:test_ZeroReports_Revert() (gas: 10459)
+EVM2EVMMultiOffRamp_ccipReceive:test_Reverts() (gas: 15662)
+EVM2EVMMultiOffRamp_commit:test_InvalidIntervalMinLargerThanMax_Revert() (gas: 67195)
+EVM2EVMMultiOffRamp_commit:test_InvalidInterval_Revert() (gas: 59698)
+EVM2EVMMultiOffRamp_commit:test_InvalidRootRevert() (gas: 58778)
+EVM2EVMMultiOffRamp_commit:test_NoConfigWithOtherConfigPresent_Revert() (gas: 6394741)
+EVM2EVMMultiOffRamp_commit:test_NoConfig_Revert() (gas: 5977968)
+EVM2EVMMultiOffRamp_commit:test_OnlyGasPriceUpdates_Success() (gas: 106229)
+EVM2EVMMultiOffRamp_commit:test_OnlyPriceUpdateStaleReport_Revert() (gas: 116228)
+EVM2EVMMultiOffRamp_commit:test_OnlyTokenPriceUpdates_Success() (gas: 106272)
+EVM2EVMMultiOffRamp_commit:test_PriceSequenceNumberCleared_Success() (gas: 351414)
+EVM2EVMMultiOffRamp_commit:test_ReportAndPriceUpdate_Success() (gas: 159132)
+EVM2EVMMultiOffRamp_commit:test_ReportOnlyRootSuccess_gas() (gas: 136253)
+EVM2EVMMultiOffRamp_commit:test_RootAlreadyCommitted_Revert() (gas: 136831)
+EVM2EVMMultiOffRamp_commit:test_SourceChainNotEnabled_Revert() (gas: 59046)
+EVM2EVMMultiOffRamp_commit:test_StaleReportWithRoot_Success() (gas: 227807)
+EVM2EVMMultiOffRamp_commit:test_UnauthorizedTransmitter_Revert() (gas: 117527)
+EVM2EVMMultiOffRamp_commit:test_Unhealthy_Revert() (gas: 77605)
+EVM2EVMMultiOffRamp_commit:test_ValidPriceUpdateThenStaleReportWithRoot_Success() (gas: 207057)
+EVM2EVMMultiOffRamp_commit:test_WrongConfigWithoutSigners_Revert() (gas: 6389130)
+EVM2EVMMultiOffRamp_commit:test_ZeroEpochAndRound_Revert() (gas: 47785)
+EVM2EVMMultiOffRamp_constructor:test_Constructor_Success() (gas: 5981174)
+EVM2EVMMultiOffRamp_constructor:test_SourceChainSelector_Revert() (gas: 157326)
+EVM2EVMMultiOffRamp_constructor:test_ZeroChainSelector_Revert() (gas: 103815)
+EVM2EVMMultiOffRamp_constructor:test_ZeroNonceManager_Revert() (gas: 101686)
+EVM2EVMMultiOffRamp_constructor:test_ZeroOnRampAddress_Revert() (gas: 159832)
+EVM2EVMMultiOffRamp_constructor:test_ZeroRMNProxy_Revert() (gas: 101585)
+EVM2EVMMultiOffRamp_constructor:test_ZeroTokenAdminRegistry_Revert() (gas: 101652)
+EVM2EVMMultiOffRamp_execute:test_IncorrectArrayType_Revert() (gas: 17280)
+EVM2EVMMultiOffRamp_execute:test_LargeBatch_Success() (gas: 1559406)
+EVM2EVMMultiOffRamp_execute:test_MultipleReportsWithPartialValidationFailures_Success() (gas: 342924)
+EVM2EVMMultiOffRamp_execute:test_MultipleReports_Success() (gas: 260178)
+EVM2EVMMultiOffRamp_execute:test_NoConfigWithOtherConfigPresent_Revert() (gas: 6445247)
+EVM2EVMMultiOffRamp_execute:test_NoConfig_Revert() (gas: 6028193)
+EVM2EVMMultiOffRamp_execute:test_NonArray_Revert() (gas: 27681)
+EVM2EVMMultiOffRamp_execute:test_SingleReport_Success() (gas: 165181)
+EVM2EVMMultiOffRamp_execute:test_UnauthorizedTransmitter_Revert() (gas: 149137)
+EVM2EVMMultiOffRamp_execute:test_WrongConfigWithSigners_Revert() (gas: 6807322)
+EVM2EVMMultiOffRamp_execute:test_ZeroReports_Revert() (gas: 17154)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_MessageSender_Revert() (gas: 18413)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_NonContractWithTokens_Success() (gas: 249368)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_NonContract_Success() (gas: 20672)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_TokenHandlingError_Revert() (gas: 201673)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_ZeroGasDONExecution_Revert() (gas: 48860)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_NoTokens_Success() (gas: 48381)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithFailingValidationNoRouterCall_Revert() (gas: 232798)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithFailingValidation_Revert() (gas: 89392)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens_Success() (gas: 278146)
+EVM2EVMMultiOffRamp_executeSingleMessage:test_executeSingleMessage_WithValidation_Success() (gas: 93615)
+EVM2EVMMultiOffRamp_executeSingleReport:test_DisabledSourceChain_Revert() (gas: 35083)
+EVM2EVMMultiOffRamp_executeSingleReport:test_EmptyReport_Revert() (gas: 23907)
+EVM2EVMMultiOffRamp_executeSingleReport:test_InvalidSourcePoolAddress_Success() (gas: 451358)
+EVM2EVMMultiOffRamp_executeSingleReport:test_ManualExecutionNotYetEnabled_Revert() (gas: 54475)
+EVM2EVMMultiOffRamp_executeSingleReport:test_MismatchingDestChainSelector_Revert() (gas: 35917)
+EVM2EVMMultiOffRamp_executeSingleReport:test_MismatchingOnRampRoot_Revert() (gas: 154369)
+EVM2EVMMultiOffRamp_executeSingleReport:test_NonExistingSourceChain_Revert() (gas: 35317)
+EVM2EVMMultiOffRamp_executeSingleReport:test_ReceiverError_Success() (gas: 181353)
+EVM2EVMMultiOffRamp_executeSingleReport:test_RetryFailedMessageWithoutManualExecution_Revert() (gas: 190627)
+EVM2EVMMultiOffRamp_executeSingleReport:test_RootNotCommitted_Revert() (gas: 48053)
+EVM2EVMMultiOffRamp_executeSingleReport:test_RouterYULCall_Revert() (gas: 443030)
+EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokensOtherChain_Success() (gas: 251770)
+EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokensUnordered_Success() (gas: 173962)
+EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageNoTokens_Success() (gas: 193657)
+EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessageToNonCCIPReceiver_Success() (gas: 259648)
+EVM2EVMMultiOffRamp_executeSingleReport:test_SingleMessagesNoTokensSuccess_gas() (gas: 129585)
+EVM2EVMMultiOffRamp_executeSingleReport:test_SkippedIncorrectNonceStillExecutes_Success() (gas: 391710)
+EVM2EVMMultiOffRamp_executeSingleReport:test_SkippedIncorrectNonce_Success() (gas: 65899)
+EVM2EVMMultiOffRamp_executeSingleReport:test_TokenDataMismatch_Revert() (gas: 80955)
+EVM2EVMMultiOffRamp_executeSingleReport:test_TwoMessagesWithTokensAndGE_Success() (gas: 535429)
+EVM2EVMMultiOffRamp_executeSingleReport:test_TwoMessagesWithTokensSuccess_gas() (gas: 480345)
+EVM2EVMMultiOffRamp_executeSingleReport:test_UnexpectedTokenData_Revert() (gas: 35763)
+EVM2EVMMultiOffRamp_executeSingleReport:test_UnhealthySingleChainCurse_Revert() (gas: 520344)
+EVM2EVMMultiOffRamp_executeSingleReport:test_Unhealthy_Revert() (gas: 517712)
+EVM2EVMMultiOffRamp_executeSingleReport:test_WithCurseOnAnotherSourceChain_Success() (gas: 487848)
+EVM2EVMMultiOffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessageUnordered_Success() (gas: 127921)
+EVM2EVMMultiOffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessage_Success() (gas: 157144)
+EVM2EVMMultiOffRamp_getExecutionState:test_FillExecutionState_Success() (gas: 3655340)
+EVM2EVMMultiOffRamp_getExecutionState:test_GetDifferentChainExecutionState_Success() (gas: 118224)
+EVM2EVMMultiOffRamp_getExecutionState:test_GetExecutionState_Success() (gas: 87461)
+EVM2EVMMultiOffRamp_manuallyExecute:test_ManualExecGasLimitMismatchSingleReport_Revert() (gas: 75600)
+EVM2EVMMultiOffRamp_manuallyExecute:test_ManualExecInvalidGasLimit_Revert() (gas: 26461)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_DoesNotRevertIfUntouched_Success() (gas: 163081)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_FailedTx_Revert() (gas: 207379)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_ForkedChain_Revert() (gas: 26004)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_GasLimitMismatchMultipleReports_Revert() (gas: 152867)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_LowGasLimit_Success() (gas: 507480)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_ReentrancyFails() (gas: 2307925)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_Success() (gas: 209633)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithGasOverride_Success() (gas: 210210)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithMultiReportGasOverride_Success() (gas: 668610)
+EVM2EVMMultiOffRamp_manuallyExecute:test_manuallyExecute_WithPartialMessages_Success() (gas: 299477)
+EVM2EVMMultiOffRamp_releaseOrMintTokens:test_TokenHandlingError_Reverts() (gas: 160598)
+EVM2EVMMultiOffRamp_releaseOrMintTokens:test__releaseOrMintTokens_PoolIsNotAPool_Reverts() (gas: 24131)
+EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_InvalidDataLengthReturnData_Revert() (gas: 59105)
+EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_InvalidEVMAddress_Revert() (gas: 40405)
+EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_PoolDoesNotSupportDest_Reverts() (gas: 76130)
+EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_Success() (gas: 178951)
+EVM2EVMMultiOffRamp_releaseOrMintTokens:test_releaseOrMintTokens_destDenominatedDecimals_Success() (gas: 278805)
+EVM2EVMMultiOffRamp_resetUnblessedRoots:test_OnlyOwner_Revert() (gas: 11379)
+EVM2EVMMultiOffRamp_resetUnblessedRoots:test_ResetUnblessedRoots_Success() (gas: 215406)
+EVM2EVMMultiOffRamp_setDynamicConfig:test_NonOwner_Revert() (gas: 14374)
+EVM2EVMMultiOffRamp_setDynamicConfig:test_PriceRegistryZeroAddress_Revert() (gas: 11898)
+EVM2EVMMultiOffRamp_setDynamicConfig:test_RouterZeroAddress_Revert() (gas: 14054)
+EVM2EVMMultiOffRamp_setDynamicConfig:test_SetDynamicConfigWithValidator_Success() (gas: 55771)
+EVM2EVMMultiOffRamp_setDynamicConfig:test_SetDynamicConfig_Success() (gas: 33781)
+EVM2EVMMultiOffRamp_trialExecute:test_RateLimitError_Success() (gas: 238004)
+EVM2EVMMultiOffRamp_trialExecute:test_TokenHandlingErrorIsCaught_Success() (gas: 246667)
+EVM2EVMMultiOffRamp_trialExecute:test_TokenPoolIsNotAContract_Success() (gas: 299499)
+EVM2EVMMultiOffRamp_trialExecute:test_trialExecute_Success() (gas: 280579)
+EVM2EVMMultiOffRamp_verify:test_Blessed_Success() (gas: 176604)
+EVM2EVMMultiOffRamp_verify:test_NotBlessedWrongChainSelector_Success() (gas: 178672)
+EVM2EVMMultiOffRamp_verify:test_NotBlessed_Success() (gas: 141533)
+EVM2EVMMultiOffRamp_verify:test_TooManyLeaves_Revert() (gas: 51508)
+EVM2EVMMultiOnRamp_constructor:test_Constructor_InvalidConfigChainSelectorEqZero_Revert() (gas: 94528)
+EVM2EVMMultiOnRamp_constructor:test_Constructor_InvalidConfigNonceManagerEqAddressZero_Revert() (gas: 92480)
+EVM2EVMMultiOnRamp_constructor:test_Constructor_InvalidConfigRMNProxyEqAddressZero_Revert() (gas: 97483)
+EVM2EVMMultiOnRamp_constructor:test_Constructor_InvalidConfigTokenAdminRegistryEqAddressZero_Revert() (gas: 92538)
+EVM2EVMMultiOnRamp_constructor:test_Constructor_Success() (gas: 2260144)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_CannotSendZeroTokens_Revert() (gas: 90987)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() (gas: 130983)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2_Success() (gas: 161753)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessCustomExtraArgs() (gas: 161306)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessEmptyExtraArgs() (gas: 159506)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessLegacyExtraArgs() (gas: 161536)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ForwardFromRouter_Success() (gas: 160928)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_InvalidExtraArgsTag_Revert() (gas: 26206)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_MessageValidationError_Revert() (gas: 134082)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_MesssageFeeTooHigh_Revert() (gas: 24272)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_OriginalSender_Revert() (gas: 12819)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_Paused_Revert() (gas: 30695)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_Permissions_Revert() (gas: 15675)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: 198276)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 224545)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldStoreLinkFees() (gas: 140840)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 162262)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3803257)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 127615)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 93044)
+EVM2EVMMultiOnRamp_forwardFromRouter:test_forwardFromRouter_WithValidation_Success() (gas: 282576)
+EVM2EVMMultiOnRamp_getFee:test_EmptyMessage_Success() (gas: 104423)
+EVM2EVMMultiOnRamp_getFee:test_EnforceOutOfOrder_Revert() (gas: 74041)
+EVM2EVMMultiOnRamp_getFee:test_SingleTokenMessage_Success() (gas: 119755)
+EVM2EVMMultiOnRamp_getFee:test_Unhealthy_Revert() (gas: 43657)
+EVM2EVMMultiOnRamp_getSupportedTokens:test_GetSupportedTokens_Revert() (gas: 10438)
+EVM2EVMMultiOnRamp_getTokenPool:test_GetTokenPool_Success() (gas: 35204)
+EVM2EVMMultiOnRamp_setDynamicConfig:test_SetConfigInvalidConfigFeeAggregatorEqAddressZero_Revert() (gas: 11356)
+EVM2EVMMultiOnRamp_setDynamicConfig:test_SetConfigInvalidConfigPriceRegistryEqAddressZero_Revert() (gas: 12956)
+EVM2EVMMultiOnRamp_setDynamicConfig:test_SetConfigInvalidConfig_Revert() (gas: 11313)
+EVM2EVMMultiOnRamp_setDynamicConfig:test_SetConfigOnlyOwner_Revert() (gas: 16287)
+EVM2EVMMultiOnRamp_setDynamicConfig:test_SetDynamicConfig_Success() (gas: 58439)
+EVM2EVMMultiOnRamp_withdrawFeeTokens:test_WithdrawFeeTokens_Success() (gas: 97185)
+EVM2EVMOffRamp__releaseOrMintToken:test__releaseOrMintToken_NotACompatiblePool_Revert() (gas: 38028)
+EVM2EVMOffRamp__releaseOrMintToken:test__releaseOrMintToken_Success() (gas: 108191)
+EVM2EVMOffRamp__releaseOrMintToken:test__releaseOrMintToken_TokenHandlingError_revert_Revert() (gas: 116732)
+EVM2EVMOffRamp__releaseOrMintTokens:test_OverValueWithARLOff_Success() (gas: 391880)
+EVM2EVMOffRamp__releaseOrMintTokens:test_PriceNotFoundForToken_Reverts() (gas: 145379)
+EVM2EVMOffRamp__releaseOrMintTokens:test_RateLimitErrors_Reverts() (gas: 788000)
+EVM2EVMOffRamp__releaseOrMintTokens:test_TokenHandlingError_Reverts() (gas: 176208)
+EVM2EVMOffRamp__releaseOrMintTokens:test__releaseOrMintTokens_NotACompatiblePool_Reverts() (gas: 29700)
+EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_InvalidDataLengthReturnData_Revert() (gas: 63325)
+EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_InvalidEVMAddress_Revert() (gas: 44501)
+EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_Success() (gas: 214151)
+EVM2EVMOffRamp__releaseOrMintTokens:test_releaseOrMintTokens_destDenominatedDecimals_Success() (gas: 306912)
+EVM2EVMOffRamp__report:test_Report_Success() (gas: 127459)
+EVM2EVMOffRamp__trialExecute:test_RateLimitError_Success() (gas: 255047)
+EVM2EVMOffRamp__trialExecute:test_TokenHandlingErrorIsCaught_Success() (gas: 263638)
+EVM2EVMOffRamp__trialExecute:test_TokenPoolIsNotAContract_Success() (gas: 335707)
+EVM2EVMOffRamp__trialExecute:test_trialExecute_Success() (gas: 314443)
+EVM2EVMOffRamp_ccipReceive:test_Reverts() (gas: 17009)
+EVM2EVMOffRamp_constructor:test_CommitStoreAlreadyInUse_Revert() (gas: 153427)
+EVM2EVMOffRamp_constructor:test_Constructor_Success() (gas: 5464875)
+EVM2EVMOffRamp_constructor:test_ZeroOnRampAddress_Revert() (gas: 144183)
+EVM2EVMOffRamp_execute:test_EmptyReport_Revert() (gas: 21345)
+EVM2EVMOffRamp_execute:test_InvalidMessageId_Revert() (gas: 36442)
+EVM2EVMOffRamp_execute:test_InvalidSourceChain_Revert() (gas: 51701)
+EVM2EVMOffRamp_execute:test_InvalidSourcePoolAddress_Success() (gas: 473575)
+EVM2EVMOffRamp_execute:test_ManualExecutionNotYetEnabled_Revert() (gas: 46423)
+EVM2EVMOffRamp_execute:test_MessageTooLarge_Revert() (gas: 152453)
+EVM2EVMOffRamp_execute:test_Paused_Revert() (gas: 101458)
+EVM2EVMOffRamp_execute:test_ReceiverError_Success() (gas: 165036)
+EVM2EVMOffRamp_execute:test_RetryFailedMessageWithoutManualExecution_Revert() (gas: 177824)
+EVM2EVMOffRamp_execute:test_RootNotCommitted_Revert() (gas: 41317)
+EVM2EVMOffRamp_execute:test_RouterYULCall_Revert() (gas: 402506)
+EVM2EVMOffRamp_execute:test_SingleMessageNoTokensUnordered_Success() (gas: 159387)
+EVM2EVMOffRamp_execute:test_SingleMessageNoTokens_Success() (gas: 174622)
+EVM2EVMOffRamp_execute:test_SingleMessageToNonCCIPReceiver_Success() (gas: 248634)
+EVM2EVMOffRamp_execute:test_SingleMessagesNoTokensSuccess_gas() (gas: 115017)
+EVM2EVMOffRamp_execute:test_SkippedIncorrectNonceStillExecutes_Success() (gas: 409338)
+EVM2EVMOffRamp_execute:test_SkippedIncorrectNonce_Success() (gas: 54173)
+EVM2EVMOffRamp_execute:test_StrictUntouchedToSuccess_Success() (gas: 132056)
+EVM2EVMOffRamp_execute:test_TokenDataMismatch_Revert() (gas: 52200)
+EVM2EVMOffRamp_execute:test_TwoMessagesWithTokensAndGE_Success() (gas: 560178)
+EVM2EVMOffRamp_execute:test_TwoMessagesWithTokensSuccess_gas() (gas: 499424)
+EVM2EVMOffRamp_execute:test_UnexpectedTokenData_Revert() (gas: 35442)
+EVM2EVMOffRamp_execute:test_Unhealthy_Revert() (gas: 546987)
+EVM2EVMOffRamp_execute:test_UnsupportedNumberOfTokens_Revert() (gas: 64045)
+EVM2EVMOffRamp_execute:test__execute_SkippedAlreadyExecutedMessageUnordered_Success() (gas: 123223)
+EVM2EVMOffRamp_execute:test__execute_SkippedAlreadyExecutedMessage_Success() (gas: 143388)
+EVM2EVMOffRamp_executeSingleMessage:test_MessageSender_Revert() (gas: 20582)
+EVM2EVMOffRamp_executeSingleMessage:test_NonContractWithTokens_Success() (gas: 281891)
+EVM2EVMOffRamp_executeSingleMessage:test_NonContract_Success() (gas: 20231)
+EVM2EVMOffRamp_executeSingleMessage:test_TokenHandlingError_Revert() (gas: 219228)
+EVM2EVMOffRamp_executeSingleMessage:test_ZeroGasDONExecution_Revert() (gas: 48632)
+EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_NoTokens_Success() (gas: 48120)
+EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens_Success() (gas: 316477)
+EVM2EVMOffRamp_executeSingleMessage:test_executeSingleMessage_ZeroGasZeroData_Success() (gas: 72423)
+EVM2EVMOffRamp_execute_upgrade:test_V2NonceNewSenderStartsAtZero_Success() (gas: 231326)
+EVM2EVMOffRamp_execute_upgrade:test_V2NonceStartsAtV1Nonce_Success() (gas: 279867)
+EVM2EVMOffRamp_execute_upgrade:test_V2OffRampNonceSkipsIfMsgInFlight_Success() (gas: 261109)
+EVM2EVMOffRamp_execute_upgrade:test_V2SenderNoncesReadsPreviousRamp_Success() (gas: 229397)
+EVM2EVMOffRamp_execute_upgrade:test_V2_Success() (gas: 131682)
+EVM2EVMOffRamp_getAllRateLimitTokens:test_GetAllRateLimitTokens_Success() (gas: 38408)
+EVM2EVMOffRamp_getExecutionState:test_FillExecutionState_Success() (gas: 3213556)
+EVM2EVMOffRamp_getExecutionState:test_GetExecutionState_Success() (gas: 83091)
+EVM2EVMOffRamp_manuallyExecute:test_LowGasLimitManualExec_Success() (gas: 483328)
+EVM2EVMOffRamp_manuallyExecute:test_ManualExecFailedTx_Revert() (gas: 186413)
+EVM2EVMOffRamp_manuallyExecute:test_ManualExecForkedChain_Revert() (gas: 25824)
+EVM2EVMOffRamp_manuallyExecute:test_ManualExecGasLimitMismatch_Revert() (gas: 43449)
+EVM2EVMOffRamp_manuallyExecute:test_ManualExecInvalidGasLimit_Revert() (gas: 25927)
+EVM2EVMOffRamp_manuallyExecute:test_ManualExecWithGasOverride_Success() (gas: 188518)
+EVM2EVMOffRamp_manuallyExecute:test_ManualExec_Success() (gas: 187965)
+EVM2EVMOffRamp_manuallyExecute:test_ReentrancyManualExecuteFails() (gas: 2027441)
+EVM2EVMOffRamp_manuallyExecute:test_manuallyExecute_DoesNotRevertIfUntouched_Success() (gas: 143803)
+EVM2EVMOffRamp_metadataHash:test_MetadataHash_Success() (gas: 8871)
+EVM2EVMOffRamp_setDynamicConfig:test_NonOwner_Revert() (gas: 40429)
+EVM2EVMOffRamp_setDynamicConfig:test_RouterZeroAddress_Revert() (gas: 38804)
+EVM2EVMOffRamp_setDynamicConfig:test_SetDynamicConfig_Success() (gas: 146790)
+EVM2EVMOffRamp_updateRateLimitTokens:test_updateRateLimitTokens_AddsAndRemoves_Success() (gas: 162464)
+EVM2EVMOffRamp_updateRateLimitTokens:test_updateRateLimitTokens_NonOwner_Revert() (gas: 16667)
+EVM2EVMOffRamp_updateRateLimitTokens:test_updateRateLimitTokens_Success() (gas: 197660)
+EVM2EVMOnRamp_constructor:test_Constructor_Success() (gas: 5619710)
+EVM2EVMOnRamp_forwardFromRouter:test_CannotSendZeroTokens_Revert() (gas: 35778)
+EVM2EVMOnRamp_forwardFromRouter:test_EnforceOutOfOrder_Revert() (gas: 99470)
+EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() (gas: 114210)
+EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2_Success() (gas: 114252)
+EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessCustomExtraArgs() (gas: 130118)
+EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouterSuccessLegacyExtraArgs() (gas: 138650)
+EVM2EVMOnRamp_forwardFromRouter:test_ForwardFromRouter_Success() (gas: 129804)
+EVM2EVMOnRamp_forwardFromRouter:test_InvalidAddressEncodePacked_Revert() (gas: 38254)
+EVM2EVMOnRamp_forwardFromRouter:test_InvalidAddress_Revert() (gas: 38370)
+EVM2EVMOnRamp_forwardFromRouter:test_InvalidChainSelector_Revert() (gas: 25511)
+EVM2EVMOnRamp_forwardFromRouter:test_InvalidExtraArgsTag_Revert() (gas: 25297)
+EVM2EVMOnRamp_forwardFromRouter:test_MaxCapacityExceeded_Revert() (gas: 86041)
+EVM2EVMOnRamp_forwardFromRouter:test_MaxFeeBalanceReached_Revert() (gas: 36457)
+EVM2EVMOnRamp_forwardFromRouter:test_MessageGasLimitTooHigh_Revert() (gas: 29037)
+EVM2EVMOnRamp_forwardFromRouter:test_MessageTooLarge_Revert() (gas: 107526)
+EVM2EVMOnRamp_forwardFromRouter:test_OriginalSender_Revert() (gas: 22635)
+EVM2EVMOnRamp_forwardFromRouter:test_OverValueWithARLOff_Success() (gas: 223665)
+EVM2EVMOnRamp_forwardFromRouter:test_Paused_Revert() (gas: 53935)
+EVM2EVMOnRamp_forwardFromRouter:test_Permissions_Revert() (gas: 25481)
+EVM2EVMOnRamp_forwardFromRouter:test_PriceNotFoundForToken_Revert() (gas: 59303)
+EVM2EVMOnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: 179141)
+EVM2EVMOnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 177355)
+EVM2EVMOnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 137297)
+EVM2EVMOnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3731767)
+EVM2EVMOnRamp_forwardFromRouter:test_TooManyTokens_Revert() (gas: 30187)
+EVM2EVMOnRamp_forwardFromRouter:test_Unhealthy_Revert() (gas: 43300)
+EVM2EVMOnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 109258)
+EVM2EVMOnRamp_forwardFromRouter:test_ZeroAddressReceiver_Revert() (gas: 312351)
+EVM2EVMOnRamp_forwardFromRouter:test_forwardFromRouter_ShouldStoreLinkFees_Success() (gas: 112319)
+EVM2EVMOnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 72181)
+EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2NonceNewSenderStartsAtZero_Success() (gas: 147614)
+EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2NonceStartsAtV1Nonce_Success() (gas: 190454)
+EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2SenderNoncesReadsPreviousRamp_Success() (gas: 121245)
+EVM2EVMOnRamp_forwardFromRouter_upgrade:test_V2_Success() (gas: 95324)
+EVM2EVMOnRamp_getDataAvailabilityCost:test_EmptyMessageCalculatesDataAvailabilityCost_Success() (gas: 20760)
+EVM2EVMOnRamp_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCost_Success() (gas: 21128)
+EVM2EVMOnRamp_getFee:test_EmptyMessage_Success() (gas: 78242)
+EVM2EVMOnRamp_getFee:test_HighGasMessage_Success() (gas: 234090)
+EVM2EVMOnRamp_getFee:test_MessageGasLimitTooHigh_Revert() (gas: 16715)
+EVM2EVMOnRamp_getFee:test_MessageTooLarge_Revert() (gas: 95271)
+EVM2EVMOnRamp_getFee:test_MessageWithDataAndTokenTransfer_Success() (gas: 159220)
+EVM2EVMOnRamp_getFee:test_NotAFeeToken_Revert() (gas: 24089)
+EVM2EVMOnRamp_getFee:test_SingleTokenMessage_Success() (gas: 117858)
+EVM2EVMOnRamp_getFee:test_TooManyTokens_Revert() (gas: 19902)
+EVM2EVMOnRamp_getFee:test_ZeroDataAvailabilityMultiplier_Success() (gas: 65663)
+EVM2EVMOnRamp_getSupportedTokens:test_GetSupportedTokens_Revert() (gas: 10460)
+EVM2EVMOnRamp_getTokenPool:test_GetTokenPool_Success() (gas: 35195)
+EVM2EVMOnRamp_getTokenTransferCost:test_CustomTokenBpsFee_Success() (gas: 45037)
+EVM2EVMOnRamp_getTokenTransferCost:test_FeeTokenBpsFee_Success() (gas: 33041)
+EVM2EVMOnRamp_getTokenTransferCost:test_LargeTokenTransferChargesMaxFeeAndGas_Success() (gas: 28296)
+EVM2EVMOnRamp_getTokenTransferCost:test_MixedTokenTransferFee_Success() (gas: 130189)
+EVM2EVMOnRamp_getTokenTransferCost:test_NoTokenTransferChargesZeroFee_Success() (gas: 15260)
+EVM2EVMOnRamp_getTokenTransferCost:test_SmallTokenTransferChargesMinFeeAndGas_Success() (gas: 28104)
+EVM2EVMOnRamp_getTokenTransferCost:test_UnsupportedToken_Revert() (gas: 21248)
+EVM2EVMOnRamp_getTokenTransferCost:test_WETHTokenBpsFee_Success() (gas: 38922)
+EVM2EVMOnRamp_getTokenTransferCost:test_ZeroAmountTokenTransferChargesMinFeeAndGas_Success() (gas: 28149)
+EVM2EVMOnRamp_getTokenTransferCost:test_ZeroFeeConfigChargesMinFee_Success() (gas: 38615)
+EVM2EVMOnRamp_getTokenTransferCost:test__getTokenTransferCost_selfServeUsesDefaults_Success() (gas: 29527)
+EVM2EVMOnRamp_linkAvailableForPayment:test_InsufficientLinkBalance_Success() (gas: 32615)
+EVM2EVMOnRamp_linkAvailableForPayment:test_LinkAvailableForPayment_Success() (gas: 134833)
+EVM2EVMOnRamp_payNops:test_AdminPayNops_Success() (gas: 143054)
+EVM2EVMOnRamp_payNops:test_InsufficientBalance_Revert() (gas: 26543)
+EVM2EVMOnRamp_payNops:test_NoFeesToPay_Revert() (gas: 127367)
+EVM2EVMOnRamp_payNops:test_NoNopsToPay_Revert() (gas: 133251)
+EVM2EVMOnRamp_payNops:test_NopPayNops_Success() (gas: 146341)
+EVM2EVMOnRamp_payNops:test_OwnerPayNops_Success() (gas: 140916)
+EVM2EVMOnRamp_payNops:test_PayNopsSuccessAfterSetNops() (gas: 297485)
+EVM2EVMOnRamp_payNops:test_WrongPermissions_Revert() (gas: 15294)
+EVM2EVMOnRamp_setDynamicConfig:test_SetConfigInvalidConfig_Revert() (gas: 43376)
+EVM2EVMOnRamp_setDynamicConfig:test_SetConfigOnlyOwner_Revert() (gas: 21646)
+EVM2EVMOnRamp_setDynamicConfig:test_SetDynamicConfig_Success() (gas: 55086)
+EVM2EVMOnRamp_setFeeTokenConfig:test_OnlyCallableByOwnerOrAdmin_Revert() (gas: 13464)
+EVM2EVMOnRamp_setFeeTokenConfig:test_SetFeeTokenConfigByAdmin_Success() (gas: 16449)
+EVM2EVMOnRamp_setFeeTokenConfig:test_SetFeeTokenConfig_Success() (gas: 13994)
+EVM2EVMOnRamp_setNops:test_AdminCanSetNops_Success() (gas: 61759)
+EVM2EVMOnRamp_setNops:test_IncludesPayment_Success() (gas: 469097)
+EVM2EVMOnRamp_setNops:test_LinkTokenCannotBeNop_Revert() (gas: 57255)
+EVM2EVMOnRamp_setNops:test_NonOwnerOrAdmin_Revert() (gas: 14665)
+EVM2EVMOnRamp_setNops:test_NotEnoughFundsForPayout_Revert() (gas: 84455)
+EVM2EVMOnRamp_setNops:test_SetNopsRemovesOldNopsCompletely_Success() (gas: 60637)
+EVM2EVMOnRamp_setNops:test_SetNops_Success() (gas: 173677)
+EVM2EVMOnRamp_setNops:test_TooManyNops_Revert() (gas: 190338)
+EVM2EVMOnRamp_setNops:test_ZeroAddressCannotBeNop_Revert() (gas: 53596)
+EVM2EVMOnRamp_setTokenTransferFeeConfig:test__setTokenTransferFeeConfig_InvalidDestBytesOverhead_Revert() (gas: 14493)
+EVM2EVMOnRamp_setTokenTransferFeeConfig:test__setTokenTransferFeeConfig_OnlyCallableByOwnerOrAdmin_Revert() (gas: 14277)
+EVM2EVMOnRamp_setTokenTransferFeeConfig:test__setTokenTransferFeeConfig_Success() (gas: 84017)
+EVM2EVMOnRamp_setTokenTransferFeeConfig:test__setTokenTransferFeeConfig_byAdmin_Success() (gas: 17369)
+EVM2EVMOnRamp_withdrawNonLinkFees:test_LinkBalanceNotSettled_Revert() (gas: 82980)
+EVM2EVMOnRamp_withdrawNonLinkFees:test_NonOwnerOrAdmin_Revert() (gas: 15275)
+EVM2EVMOnRamp_withdrawNonLinkFees:test_SettlingBalance_Success() (gas: 272015)
+EVM2EVMOnRamp_withdrawNonLinkFees:test_WithdrawNonLinkFees_Success() (gas: 53446)
+EVM2EVMOnRamp_withdrawNonLinkFees:test_WithdrawToZeroAddress_Revert() (gas: 12830)
+EtherSenderReceiverTest_ccipReceive:test_ccipReceive_fallbackToWethTransfer() (gas: 96729)
+EtherSenderReceiverTest_ccipReceive:test_ccipReceive_happyPath() (gas: 47688)
+EtherSenderReceiverTest_ccipReceive:test_ccipReceive_wrongToken() (gas: 17384)
+EtherSenderReceiverTest_ccipReceive:test_ccipReceive_wrongTokenAmount() (gas: 15677)
+EtherSenderReceiverTest_ccipSend:test_ccipSend_reverts_insufficientFee_feeToken() (gas: 99741)
+EtherSenderReceiverTest_ccipSend:test_ccipSend_reverts_insufficientFee_native() (gas: 76096)
+EtherSenderReceiverTest_ccipSend:test_ccipSend_reverts_insufficientFee_weth() (gas: 99748)
+EtherSenderReceiverTest_ccipSend:test_ccipSend_success_feeToken() (gas: 144569)
+EtherSenderReceiverTest_ccipSend:test_ccipSend_success_native() (gas: 80259)
+EtherSenderReceiverTest_ccipSend:test_ccipSend_success_nativeExcess() (gas: 80446)
+EtherSenderReceiverTest_ccipSend:test_ccipSend_success_weth() (gas: 95713)
+EtherSenderReceiverTest_constructor:test_constructor() (gas: 17511)
+EtherSenderReceiverTest_getFee:test_getFee() (gas: 27289)
+EtherSenderReceiverTest_validateFeeToken:test_validateFeeToken_reverts_feeToken_tokenAmountNotEqualToMsgValue() (gas: 20333)
+EtherSenderReceiverTest_validateFeeToken:test_validateFeeToken_valid_feeToken() (gas: 16715)
+EtherSenderReceiverTest_validateFeeToken:test_validateFeeToken_valid_native() (gas: 16654)
+EtherSenderReceiverTest_validatedMessage:test_validatedMessage_dataOverwrittenToMsgSender() (gas: 25415)
+EtherSenderReceiverTest_validatedMessage:test_validatedMessage_emptyDataOverwrittenToMsgSender() (gas: 25265)
+EtherSenderReceiverTest_validatedMessage:test_validatedMessage_invalidTokenAmounts() (gas: 17895)
+EtherSenderReceiverTest_validatedMessage:test_validatedMessage_tokenOverwrittenToWeth() (gas: 25287)
+EtherSenderReceiverTest_validatedMessage:test_validatedMessage_validMessage_extraArgs() (gas: 26292)
+LockReleaseTokenPoolAndProxy_setRateLimitAdmin:test_SetRateLimitAdmin_Revert() (gas: 11058)
+LockReleaseTokenPoolAndProxy_setRateLimitAdmin:test_SetRateLimitAdmin_Success() (gas: 35097)
+LockReleaseTokenPoolAndProxy_setRebalancer:test_SetRebalancer_Revert() (gas: 10970)
+LockReleaseTokenPoolAndProxy_setRebalancer:test_SetRebalancer_Success() (gas: 18036)
+LockReleaseTokenPoolPoolAndProxy_canAcceptLiquidity:test_CanAcceptLiquidity_Success() (gas: 3313980)
+LockReleaseTokenPoolPoolAndProxy_provideLiquidity:test_LiquidityNotAccepted_Revert() (gas: 3310379)
+LockReleaseTokenPoolPoolAndProxy_provideLiquidity:test_Unauthorized_Revert() (gas: 11380)
+LockReleaseTokenPoolPoolAndProxy_setChainRateLimiterConfig:test_NonExistentChain_Revert() (gas: 17135)
+LockReleaseTokenPoolPoolAndProxy_setChainRateLimiterConfig:test_OnlyOwnerOrRateLimitAdmin_Revert() (gas: 69142)
+LockReleaseTokenPoolPoolAndProxy_setChainRateLimiterConfig:test_OnlyOwner_Revert() (gas: 17319)
+LockReleaseTokenPoolPoolAndProxy_supportsInterface:test_SupportsInterface_Success() (gas: 9977)
+LockReleaseTokenPoolPoolAndProxy_withdrawalLiquidity:test_InsufficientLiquidity_Revert() (gas: 60043)
+LockReleaseTokenPoolPoolAndProxy_withdrawalLiquidity:test_Unauthorized_Revert() (gas: 11355)
+LockReleaseTokenPool_canAcceptLiquidity:test_CanAcceptLiquidity_Success() (gas: 3067883)
+LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 29942)
+LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Success() (gas: 79844)
+LockReleaseTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 59464)
+LockReleaseTokenPool_provideLiquidity:test_LiquidityNotAccepted_Revert() (gas: 3064325)
+LockReleaseTokenPool_provideLiquidity:test_Unauthorized_Revert() (gas: 11380)
+LockReleaseTokenPool_releaseOrMint:test_ChainNotAllowed_Revert() (gas: 72662)
+LockReleaseTokenPool_releaseOrMint:test_PoolMintNotHealthy_Revert() (gas: 56131)
+LockReleaseTokenPool_releaseOrMint:test_ReleaseOrMint_Success() (gas: 238673)
+LockReleaseTokenPool_setChainRateLimiterConfig:test_NonExistentChain_Revert() (gas: 17102)
+LockReleaseTokenPool_setChainRateLimiterConfig:test_OnlyOwnerOrRateLimitAdmin_Revert() (gas: 69075)
+LockReleaseTokenPool_setChainRateLimiterConfig:test_OnlyOwner_Revert() (gas: 17297)
+LockReleaseTokenPool_setRateLimitAdmin:test_SetRateLimitAdmin_Revert() (gas: 11057)
+LockReleaseTokenPool_setRateLimitAdmin:test_SetRateLimitAdmin_Success() (gas: 35140)
+LockReleaseTokenPool_setRebalancer:test_SetRebalancer_Revert() (gas: 10992)
+LockReleaseTokenPool_setRebalancer:test_SetRebalancer_Success() (gas: 17926)
+LockReleaseTokenPool_supportsInterface:test_SupportsInterface_Success() (gas: 9977)
+LockReleaseTokenPool_withdrawalLiquidity:test_InsufficientLiquidity_Revert() (gas: 60043)
+LockReleaseTokenPool_withdrawalLiquidity:test_Unauthorized_Revert() (gas: 11355)
+MerkleMultiProofTest:test_CVE_2023_34459() (gas: 5451)
+MerkleMultiProofTest:test_EmptyLeaf_Revert() (gas: 3552)
+MerkleMultiProofTest:test_MerkleRoot256() (gas: 394876)
+MerkleMultiProofTest:test_MerkleRootSingleLeaf_Success() (gas: 3649)
+MerkleMultiProofTest:test_SpecSync_gas() (gas: 34123)
+MockRouterTest:test_ccipSendWithInsufficientNativeTokens_Revert() (gas: 33965)
+MockRouterTest:test_ccipSendWithInvalidMsgValue_Revert() (gas: 60758)
+MockRouterTest:test_ccipSendWithLinkFeeTokenAndValidMsgValue_Success() (gas: 126294)
+MockRouterTest:test_ccipSendWithLinkFeeTokenbutInsufficientAllowance_Revert() (gas: 63302)
+MockRouterTest:test_ccipSendWithSufficientNativeFeeTokens_Success() (gas: 43853)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_MultipleConfigsBothLanes_Success() (gas: 132031)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_MultipleConfigs_Success() (gas: 312057)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_OnlyCallableByOwner_Revert() (gas: 17717)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_SingleConfigOutbound_Success() (gas: 75784)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_SingleConfig_Success() (gas: 75700)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_UpdateExistingConfigWithNoDifference_Success() (gas: 38133)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_UpdateExistingConfig_Success() (gas: 53092)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_ZeroChainSelector_Revert() (gas: 17019)
+MultiAggregateRateLimiter_applyRateLimiterConfigUpdates:test_ZeroConfigs_Success() (gas: 12295)
+MultiAggregateRateLimiter_constructor:test_ConstructorNoAuthorizedCallers_Success() (gas: 1971805)
+MultiAggregateRateLimiter_constructor:test_Constructor_Success() (gas: 2085252)
+MultiAggregateRateLimiter_getTokenBucket:test_GetTokenBucket_Success() (gas: 30248)
+MultiAggregateRateLimiter_getTokenBucket:test_Refill_Success() (gas: 47358)
+MultiAggregateRateLimiter_getTokenBucket:test_TimeUnderflow_Revert() (gas: 15821)
+MultiAggregateRateLimiter_getTokenValue:test_GetTokenValue_Success() (gas: 19668)
+MultiAggregateRateLimiter_getTokenValue:test_NoTokenPrice_Reverts() (gas: 21253)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageFromUnauthorizedCaller_Revert() (gas: 14527)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageWithDifferentTokensOnDifferentChains_Success() (gas: 189450)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageWithDisabledRateLimitToken_Success() (gas: 59927)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageWithNoTokens_Success() (gas: 17593)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageWithRateLimitDisabled_Success() (gas: 44895)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageWithRateLimitExceeded_Revert() (gas: 50598)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageWithRateLimitReset_Success() (gas: 78780)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageWithTokensOnDifferentChains_Success() (gas: 263510)
+MultiAggregateRateLimiter_onInboundMessage:test_ValidateMessageWithTokens_Success() (gas: 54784)
+MultiAggregateRateLimiter_onOutboundMessage:test_RateLimitValueDifferentLanes_Success() (gas: 9223372036854754743)
+MultiAggregateRateLimiter_onOutboundMessage:test_ValidateMessageWithNoTokens_Success() (gas: 19104)
+MultiAggregateRateLimiter_onOutboundMessage:test_onOutboundMessage_ValidateMessageFromUnauthorizedCaller_Revert() (gas: 15778)
+MultiAggregateRateLimiter_onOutboundMessage:test_onOutboundMessage_ValidateMessageWithDifferentTokensOnDifferentChains_Success() (gas: 189438)
+MultiAggregateRateLimiter_onOutboundMessage:test_onOutboundMessage_ValidateMessageWithDisabledRateLimitToken_Success() (gas: 61662)
+MultiAggregateRateLimiter_onOutboundMessage:test_onOutboundMessage_ValidateMessageWithRateLimitDisabled_Success() (gas: 46683)
+MultiAggregateRateLimiter_onOutboundMessage:test_onOutboundMessage_ValidateMessageWithRateLimitExceeded_Revert() (gas: 52371)
+MultiAggregateRateLimiter_onOutboundMessage:test_onOutboundMessage_ValidateMessageWithRateLimitReset_Success() (gas: 79845)
+MultiAggregateRateLimiter_onOutboundMessage:test_onOutboundMessage_ValidateMessageWithTokensOnDifferentChains_Success() (gas: 263724)
+MultiAggregateRateLimiter_onOutboundMessage:test_onOutboundMessage_ValidateMessageWithTokens_Success() (gas: 56541)
+MultiAggregateRateLimiter_setPriceRegistry:test_OnlyOwner_Revert() (gas: 11336)
+MultiAggregateRateLimiter_setPriceRegistry:test_Owner_Success() (gas: 19124)
+MultiAggregateRateLimiter_setPriceRegistry:test_ZeroAddress_Revert() (gas: 10608)
+MultiAggregateRateLimiter_updateRateLimitTokens:test_NonOwner_Revert() (gas: 16085)
+MultiAggregateRateLimiter_updateRateLimitTokens:test_UpdateRateLimitTokensMultipleChains_Success() (gas: 225643)
+MultiAggregateRateLimiter_updateRateLimitTokens:test_UpdateRateLimitTokensSingleChain_Success() (gas: 200192)
+MultiAggregateRateLimiter_updateRateLimitTokens:test_UpdateRateLimitTokens_AddsAndRemoves_Success() (gas: 162053)
+MultiAggregateRateLimiter_updateRateLimitTokens:test_UpdateRateLimitTokens_RemoveNonExistentToken_Success() (gas: 28509)
+MultiAggregateRateLimiter_updateRateLimitTokens:test_ZeroDestToken_Revert() (gas: 17430)
+MultiAggregateRateLimiter_updateRateLimitTokens:test_ZeroSourceToken_Revert() (gas: 17485)
+MultiOCR3Base_setOCR3Configs:test_FMustBePositive_Revert() (gas: 59331)
+MultiOCR3Base_setOCR3Configs:test_FTooHigh_Revert() (gas: 44298)
+MultiOCR3Base_setOCR3Configs:test_RepeatSignerAddress_Revert() (gas: 283711)
+MultiOCR3Base_setOCR3Configs:test_RepeatTransmitterAddress_Revert() (gas: 422848)
+MultiOCR3Base_setOCR3Configs:test_SetConfigIgnoreSigners_Success() (gas: 511694)
+MultiOCR3Base_setOCR3Configs:test_SetConfigWithSigners_Success() (gas: 829593)
+MultiOCR3Base_setOCR3Configs:test_SetConfigWithoutSigners_Success() (gas: 457446)
+MultiOCR3Base_setOCR3Configs:test_SetConfigsZeroInput_Success() (gas: 12376)
+MultiOCR3Base_setOCR3Configs:test_SetMultipleConfigs_Success() (gas: 2143220)
+MultiOCR3Base_setOCR3Configs:test_SignerCannotBeZeroAddress_Revert() (gas: 141744)
+MultiOCR3Base_setOCR3Configs:test_StaticConfigChange_Revert() (gas: 808478)
+MultiOCR3Base_setOCR3Configs:test_TooManySigners_Revert() (gas: 171331)
+MultiOCR3Base_setOCR3Configs:test_TooManyTransmitters_Revert() (gas: 30298)
+MultiOCR3Base_setOCR3Configs:test_TransmitterCannotBeZeroAddress_Revert() (gas: 254454)
+MultiOCR3Base_setOCR3Configs:test_UpdateConfigSigners_Success() (gas: 861521)
+MultiOCR3Base_setOCR3Configs:test_UpdateConfigTransmittersWithoutSigners_Success() (gas: 475825)
+MultiOCR3Base_transmit:test_ConfigDigestMismatch_Revert() (gas: 42837)
+MultiOCR3Base_transmit:test_ForkedChain_Revert() (gas: 48442)
+MultiOCR3Base_transmit:test_InsufficientSignatures_Revert() (gas: 76930)
+MultiOCR3Base_transmit:test_NonUniqueSignature_Revert() (gas: 66127)
+MultiOCR3Base_transmit:test_SignatureOutOfRegistration_Revert() (gas: 33419)
+MultiOCR3Base_transmit:test_TooManySignatures_Revert() (gas: 79521)
+MultiOCR3Base_transmit:test_TransmitSigners_gas_Success() (gas: 34131)
+MultiOCR3Base_transmit:test_TransmitWithExtraCalldataArgs_Revert() (gas: 47114)
+MultiOCR3Base_transmit:test_TransmitWithLessCalldataArgs_Revert() (gas: 25682)
+MultiOCR3Base_transmit:test_TransmitWithoutSignatureVerification_gas_Success() (gas: 18726)
+MultiOCR3Base_transmit:test_UnAuthorizedTransmitter_Revert() (gas: 24191)
+MultiOCR3Base_transmit:test_UnauthorizedSigner_Revert() (gas: 61409)
+MultiOCR3Base_transmit:test_UnconfiguredPlugin_Revert() (gas: 39890)
+MultiOCR3Base_transmit:test_ZeroSignatures_Revert() (gas: 32973)
+MultiOnRampTokenPoolReentrancy:test_OnRampTokenPoolReentrancy_Success() (gas: 412349)
+MultiRampsE2E:test_E2E_3MessagesSuccess_gas() (gas: 1426976)
+NonceManager_NonceIncrementation:test_getIncrementedOutboundNonce_Success() (gas: 37907)
+NonceManager_NonceIncrementation:test_incrementInboundNonce_Skip() (gas: 23694)
+NonceManager_NonceIncrementation:test_incrementInboundNonce_Success() (gas: 38763)
+NonceManager_NonceIncrementation:test_incrementNoncesInboundAndOutbound_Success() (gas: 71847)
+NonceManager_OffRampUpgrade:test_NoPrevOffRampForChain_Success() (gas: 252566)
+NonceManager_OffRampUpgrade:test_UpgradedNonceNewSenderStartsAtZero_Success() (gas: 254866)
+NonceManager_OffRampUpgrade:test_UpgradedNonceStartsAtV1Nonce_Success() (gas: 307885)
+NonceManager_OffRampUpgrade:test_UpgradedOffRampNonceSkipsIfMsgInFlight_Success() (gas: 290962)
+NonceManager_OffRampUpgrade:test_UpgradedSenderNoncesReadsPreviousRampTransitive_Success() (gas: 247990)
+NonceManager_OffRampUpgrade:test_UpgradedSenderNoncesReadsPreviousRamp_Success() (gas: 236024)
+NonceManager_OffRampUpgrade:test_Upgraded_Success() (gas: 144774)
+NonceManager_OnRampUpgrade:test_UpgradeNonceNewSenderStartsAtZero_Success() (gas: 186669)
+NonceManager_OnRampUpgrade:test_UpgradeNonceStartsAtV1Nonce_Success() (gas: 237737)
+NonceManager_OnRampUpgrade:test_UpgradeSenderNoncesReadsPreviousRamp_Success() (gas: 124995)
+NonceManager_OnRampUpgrade:test_Upgrade_Success() (gas: 125923)
+NonceManager_applyPreviousRampsUpdates:test_MultipleRampsUpdates() (gas: 122899)
+NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySetOffRamp_Revert() (gas: 42959)
+NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySetOnRampAndOffRamp_Revert() (gas: 64282)
+NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySetOnRamp_Revert() (gas: 42823)
+NonceManager_applyPreviousRampsUpdates:test_SingleRampUpdate() (gas: 66548)
+NonceManager_applyPreviousRampsUpdates:test_ZeroInput() (gas: 12025)
+OCR2BaseNoChecks_setOCR2Config:test_FMustBePositive_Revert() (gas: 12171)
+OCR2BaseNoChecks_setOCR2Config:test_RepeatAddress_Revert() (gas: 42233)
+OCR2BaseNoChecks_setOCR2Config:test_SetConfigSuccess_gas() (gas: 84124)
+OCR2BaseNoChecks_setOCR2Config:test_TooManyTransmitter_Revert() (gas: 36938)
+OCR2BaseNoChecks_setOCR2Config:test_TransmitterCannotBeZeroAddress_Revert() (gas: 24158)
+OCR2BaseNoChecks_transmit:test_ConfigDigestMismatch_Revert() (gas: 17448)
+OCR2BaseNoChecks_transmit:test_ForkedChain_Revert() (gas: 26726)
+OCR2BaseNoChecks_transmit:test_TransmitSuccess_gas() (gas: 27478)
+OCR2BaseNoChecks_transmit:test_UnAuthorizedTransmitter_Revert() (gas: 21296)
+OCR2Base_setOCR2Config:test_FMustBePositive_Revert() (gas: 12189)
+OCR2Base_setOCR2Config:test_FTooHigh_Revert() (gas: 12345)
+OCR2Base_setOCR2Config:test_OracleOutOfRegister_Revert() (gas: 14892)
+OCR2Base_setOCR2Config:test_RepeatAddress_Revert() (gas: 45442)
+OCR2Base_setOCR2Config:test_SetConfigSuccess_gas() (gas: 155192)
+OCR2Base_setOCR2Config:test_SingerCannotBeZeroAddress_Revert() (gas: 24407)
+OCR2Base_setOCR2Config:test_TooManySigners_Revert() (gas: 20508)
+OCR2Base_setOCR2Config:test_TransmitterCannotBeZeroAddress_Revert() (gas: 47298)
+OCR2Base_transmit:test_ConfigDigestMismatch_Revert() (gas: 19623)
+OCR2Base_transmit:test_ForkedChain_Revert() (gas: 37683)
+OCR2Base_transmit:test_NonUniqueSignature_Revert() (gas: 55309)
+OCR2Base_transmit:test_SignatureOutOfRegistration_Revert() (gas: 20962)
+OCR2Base_transmit:test_Transmit2SignersSuccess_gas() (gas: 51686)
+OCR2Base_transmit:test_UnAuthorizedTransmitter_Revert() (gas: 23484)
+OCR2Base_transmit:test_UnauthorizedSigner_Revert() (gas: 39665)
+OCR2Base_transmit:test_WrongNumberOfSignatures_Revert() (gas: 20557)
+OnRampTokenPoolReentrancy:test_OnRampTokenPoolReentrancy_Success() (gas: 380360)
+PingPong_ccipReceive:test_CcipReceive_Success() (gas: 148380)
+PingPong_plumbing:test_Pausing_Success() (gas: 17803)
+PingPong_startPingPong:test_StartPingPong_Success() (gas: 178340)
+PriceRegistry_applyDestChainConfigUpdates:test_InvalidChainFamilySelector_Revert() (gas: 16719)
+PriceRegistry_applyDestChainConfigUpdates:test_InvalidDestBytesOverhead_Revert() (gas: 16784)
+PriceRegistry_applyDestChainConfigUpdates:test_InvalidDestChainConfigDestChainSelectorEqZero_Revert() (gas: 16611)
+PriceRegistry_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesDefaultTxGasLimitEqZero_Revert() (gas: 16675)
+PriceRegistry_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesDefaultTxGasLimitGtMaxPerMessageGasLimit_Revert() (gas: 40953)
+PriceRegistry_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesZeroIntput_Success() (gas: 12341)
+PriceRegistry_applyDestChainConfigUpdates:test_applyDestChainConfigUpdates_Success() (gas: 139564)
+PriceRegistry_applyFeeTokensUpdates:test_ApplyFeeTokensUpdates_Success() (gas: 80002)
+PriceRegistry_applyFeeTokensUpdates:test_OnlyCallableByOwner_Revert() (gas: 12603)
+PriceRegistry_applyPremiumMultiplierWeiPerEthUpdates:test_OnlyCallableByOwnerOrAdmin_Revert() (gas: 11465)
+PriceRegistry_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesMultipleTokens_Success() (gas: 54149)
+PriceRegistry_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesSingleToken_Success() (gas: 44835)
+PriceRegistry_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesZeroInput() (gas: 12301)
+PriceRegistry_applyTokenTransferFeeConfigUpdates:test_ApplyTokenTransferFeeConfig_Success() (gas: 86826)
+PriceRegistry_applyTokenTransferFeeConfigUpdates:test_ApplyTokenTransferFeeZeroInput() (gas: 13089)
+PriceRegistry_applyTokenTransferFeeConfigUpdates:test_InvalidDestBytesOverhead_Revert() (gas: 17045)
+PriceRegistry_applyTokenTransferFeeConfigUpdates:test_OnlyCallableByOwnerOrAdmin_Revert() (gas: 12240)
+PriceRegistry_constructor:test_InvalidLinkTokenEqZeroAddress_Revert() (gas: 105966)
+PriceRegistry_constructor:test_InvalidMaxFeeJuelsPerMsg_Revert() (gas: 110316)
+PriceRegistry_constructor:test_InvalidStalenessThreshold_Revert() (gas: 110369)
+PriceRegistry_constructor:test_Setup_Success() (gas: 4650895)
+PriceRegistry_convertTokenAmount:test_ConvertTokenAmount_Success() (gas: 72751)
+PriceRegistry_convertTokenAmount:test_LinkTokenNotSupported_Revert() (gas: 30981)
+PriceRegistry_getDataAvailabilityCost:test_EmptyMessageCalculatesDataAvailabilityCost_Success() (gas: 95575)
+PriceRegistry_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCostUnsupportedDestChainSelector_Success() (gas: 14636)
+PriceRegistry_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCost_Success() (gas: 20614)
+PriceRegistry_getTokenAndGasPrices:test_GetFeeTokenAndGasPrices_Success() (gas: 70449)
+PriceRegistry_getTokenAndGasPrices:test_StaleGasPrice_Revert() (gas: 16838)
+PriceRegistry_getTokenAndGasPrices:test_UnsupportedChain_Revert() (gas: 16140)
+PriceRegistry_getTokenAndGasPrices:test_ZeroGasPrice_Success() (gas: 45734)
+PriceRegistry_getTokenPrice:test_GetTokenPriceFromFeed_Success() (gas: 62311)
+PriceRegistry_getTokenPrices:test_GetTokenPrices_Success() (gas: 84774)
+PriceRegistry_getTokenTransferCost:test_CustomTokenBpsFee_Success() (gas: 41283)
+PriceRegistry_getTokenTransferCost:test_FeeTokenBpsFee_Success() (gas: 34733)
+PriceRegistry_getTokenTransferCost:test_LargeTokenTransferChargesMaxFeeAndGas_Success() (gas: 27807)
+PriceRegistry_getTokenTransferCost:test_MixedTokenTransferFee_Success() (gas: 108018)
+PriceRegistry_getTokenTransferCost:test_NoTokenTransferChargesZeroFee_Success() (gas: 20359)
+PriceRegistry_getTokenTransferCost:test_SmallTokenTransferChargesMinFeeAndGas_Success() (gas: 27615)
+PriceRegistry_getTokenTransferCost:test_WETHTokenBpsFee_Success() (gas: 40668)
+PriceRegistry_getTokenTransferCost:test_ZeroAmountTokenTransferChargesMinFeeAndGas_Success() (gas: 27638)
+PriceRegistry_getTokenTransferCost:test_ZeroFeeConfigChargesMinFee_Success() (gas: 40015)
+PriceRegistry_getTokenTransferCost:test_getTokenTransferCost_selfServeUsesDefaults_Success() (gas: 29343)
+PriceRegistry_getValidatedFee:test_DestinationChainNotEnabled_Revert() (gas: 18203)
+PriceRegistry_getValidatedFee:test_EmptyMessage_Success() (gas: 81464)
+PriceRegistry_getValidatedFee:test_EnforceOutOfOrder_Revert() (gas: 55184)
+PriceRegistry_getValidatedFee:test_HighGasMessage_Success() (gas: 237926)
+PriceRegistry_getValidatedFee:test_InvalidEVMAddress_Revert() (gas: 19971)
+PriceRegistry_getValidatedFee:test_MessageGasLimitTooHigh_Revert() (gas: 31775)
+PriceRegistry_getValidatedFee:test_MessageTooLarge_Revert() (gas: 97714)
+PriceRegistry_getValidatedFee:test_MessageWithDataAndTokenTransfer_Success() (gas: 143193)
+PriceRegistry_getValidatedFee:test_NotAFeeToken_Revert() (gas: 29435)
+PriceRegistry_getValidatedFee:test_SingleTokenMessage_Success() (gas: 112283)
+PriceRegistry_getValidatedFee:test_TooManyTokens_Revert() (gas: 20107)
+PriceRegistry_getValidatedFee:test_ZeroDataAvailabilityMultiplier_Success() (gas: 62956)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedErc20Above18Decimals_Success() (gas: 2094532)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedErc20Below18Decimals_Success() (gas: 2094490)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedFeedAt0Decimals_Success() (gas: 2074609)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedFeedAt18Decimals_Success() (gas: 2094264)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedFlippedDecimals_Success() (gas: 2094468)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedMaxInt224Value_Success() (gas: 2094280)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedOverStalenessPeriod_Success() (gas: 61997)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeed_Success() (gas: 61877)
+PriceRegistry_getValidatedTokenPrice:test_GetValidatedTokenPrice_Success() (gas: 60998)
+PriceRegistry_getValidatedTokenPrice:test_OverflowFeedPrice_Revert() (gas: 2093992)
+PriceRegistry_getValidatedTokenPrice:test_StaleFeeToken_Success() (gas: 61525)
+PriceRegistry_getValidatedTokenPrice:test_TokenNotSupportedFeed_Revert() (gas: 109113)
+PriceRegistry_getValidatedTokenPrice:test_TokenNotSupported_Revert() (gas: 13819)
+PriceRegistry_getValidatedTokenPrice:test_UnderflowFeedPrice_Revert() (gas: 2092670)
+PriceRegistry_parseEVMExtraArgsFromBytes:test_EVMExtraArgsDefault_Success() (gas: 17360)
+PriceRegistry_parseEVMExtraArgsFromBytes:test_EVMExtraArgsEnforceOutOfOrder_Revert() (gas: 21454)
+PriceRegistry_parseEVMExtraArgsFromBytes:test_EVMExtraArgsGasLimitTooHigh_Revert() (gas: 18551)
+PriceRegistry_parseEVMExtraArgsFromBytes:test_EVMExtraArgsInvalidExtraArgsTag_Revert() (gas: 18075)
+PriceRegistry_parseEVMExtraArgsFromBytes:test_EVMExtraArgsV1_Success() (gas: 18452)
+PriceRegistry_parseEVMExtraArgsFromBytes:test_EVMExtraArgsV2_Success() (gas: 18569)
+PriceRegistry_processMessageArgs:test_InvalidExtraArgs_Revert() (gas: 18306)
+PriceRegistry_processMessageArgs:test_MalformedEVMExtraArgs_Revert() (gas: 18852)
+PriceRegistry_processMessageArgs:test_MessageFeeTooHigh_Revert() (gas: 16360)
+PriceRegistry_processMessageArgs:test_WitEVMExtraArgsV2_Success() (gas: 26236)
+PriceRegistry_processMessageArgs:test_WithConvertedTokenAmount_Success() (gas: 32410)
+PriceRegistry_processMessageArgs:test_WithEVMExtraArgsV1_Success() (gas: 25848)
+PriceRegistry_processMessageArgs:test_WithEmptyEVMExtraArgs_Success() (gas: 23663)
+PriceRegistry_processMessageArgs:test_WithLinkTokenAmount_Success() (gas: 17320)
+PriceRegistry_updatePrices:test_OnlyCallableByUpdater_Revert() (gas: 12080)
+PriceRegistry_updatePrices:test_OnlyGasPrice_Success() (gas: 23599)
+PriceRegistry_updatePrices:test_OnlyTokenPrice_Success() (gas: 30637)
+PriceRegistry_updatePrices:test_UpdatableByAuthorizedCaller_Success() (gas: 76043)
+PriceRegistry_updatePrices:test_UpdateMultiplePrices_Success() (gas: 151521)
+PriceRegistry_updateTokenPriceFeeds:test_FeedNotUpdated() (gas: 50699)
+PriceRegistry_updateTokenPriceFeeds:test_FeedUnset_Success() (gas: 63882)
+PriceRegistry_updateTokenPriceFeeds:test_FeedUpdatedByNonOwner_Revert() (gas: 19998)
+PriceRegistry_updateTokenPriceFeeds:test_MultipleFeedUpdate_Success() (gas: 89162)
+PriceRegistry_updateTokenPriceFeeds:test_SingleFeedUpdate_Success() (gas: 50949)
+PriceRegistry_updateTokenPriceFeeds:test_ZeroFeeds_Success() (gas: 12362)
+PriceRegistry_validateDestFamilyAddress:test_InvalidEVMAddressEncodePacked_Revert() (gas: 10572)
+PriceRegistry_validateDestFamilyAddress:test_InvalidEVMAddressPrecompiles_Revert() (gas: 3916546)
+PriceRegistry_validateDestFamilyAddress:test_InvalidEVMAddress_Revert() (gas: 10756)
+PriceRegistry_validateDestFamilyAddress:test_ValidEVMAddress_Success() (gas: 6660)
+PriceRegistry_validateDestFamilyAddress:test_ValidNonEVMAddress_Success() (gas: 6440)
+PriceRegistry_validatePoolReturnData:test_InvalidEVMAddressDestToken_Revert() (gas: 35457)
+PriceRegistry_validatePoolReturnData:test_SourceTokenDataTooLarge_Revert() (gas: 90631)
+PriceRegistry_validatePoolReturnData:test_TokenAmountArraysMismatching_Revert() (gas: 32749)
+PriceRegistry_validatePoolReturnData:test_WithSingleToken_Success() (gas: 31293)
+RMN_constructor:test_Constructor_Success() (gas: 48838)
+RMN_getRecordedCurseRelatedOps:test_OpsPostDeployment() (gas: 19666)
+RMN_lazyVoteToCurseUpdate_Benchmark:test_VoteToCurseLazilyRetain3VotersUponConfigChange_gas() (gas: 152152)
+RMN_ownerUnbless:test_Unbless_Success() (gas: 74699)
+RMN_ownerUnvoteToCurse:test_CanBlessAndCurseAfterGlobalCurseIsLifted() (gas: 470965)
+RMN_ownerUnvoteToCurse:test_IsIdempotent() (gas: 397532)
+RMN_ownerUnvoteToCurse:test_NonOwner_Revert() (gas: 18591)
+RMN_ownerUnvoteToCurse:test_OwnerUnvoteToCurseSuccess_gas() (gas: 357403)
+RMN_ownerUnvoteToCurse:test_UnknownVoter_Revert() (gas: 32980)
+RMN_ownerUnvoteToCurse_Benchmark:test_OwnerUnvoteToCurse_1Voter_LiftsCurse_gas() (gas: 261985)
+RMN_permaBlessing:test_PermaBlessing() (gas: 202686)
+RMN_setConfig:test_BlessVoterIsZeroAddress_Revert() (gas: 15494)
+RMN_setConfig:test_EitherThresholdIsZero_Revert() (gas: 21095)
+RMN_setConfig:test_NonOwner_Revert() (gas: 14713)
+RMN_setConfig:test_RepeatedAddress_Revert() (gas: 18213)
+RMN_setConfig:test_SetConfigSuccess_gas() (gas: 104204)
+RMN_setConfig:test_TotalWeightsSmallerThanEachThreshold_Revert() (gas: 30173)
+RMN_setConfig:test_VoteToBlessByEjectedVoter_Revert() (gas: 130303)
+RMN_setConfig:test_VotersLengthIsZero_Revert() (gas: 12128)
+RMN_setConfig:test_WeightIsZeroAddress_Revert() (gas: 15734)
+RMN_setConfig_Benchmark_1:test_SetConfig_7Voters_gas() (gas: 659123)
+RMN_setConfig_Benchmark_2:test_ResetConfig_7Voters_gas() (gas: 212156)
+RMN_unvoteToCurse:test_InvalidCursesHash() (gas: 26364)
+RMN_unvoteToCurse:test_OwnerSkips() (gas: 33753)
+RMN_unvoteToCurse:test_OwnerSucceeds() (gas: 63909)
+RMN_unvoteToCurse:test_UnauthorizedVoter() (gas: 47478)
+RMN_unvoteToCurse:test_ValidCursesHash() (gas: 61067)
+RMN_unvoteToCurse:test_VotersCantLiftCurseButOwnerCan() (gas: 627750)
+RMN_voteToBless:test_Curse_Revert() (gas: 472823)
+RMN_voteToBless:test_IsAlreadyBlessed_Revert() (gas: 114829)
+RMN_voteToBless:test_RootSuccess() (gas: 555559)
+RMN_voteToBless:test_SenderAlreadyVoted_Revert() (gas: 96730)
+RMN_voteToBless:test_UnauthorizedVoter_Revert() (gas: 17087)
+RMN_voteToBless_Benchmark:test_1RootSuccess_gas() (gas: 44667)
+RMN_voteToBless_Benchmark:test_3RootSuccess_gas() (gas: 98565)
+RMN_voteToBless_Benchmark:test_5RootSuccess_gas() (gas: 152401)
+RMN_voteToBless_Blessed_Benchmark:test_1RootSuccessBecameBlessed_gas() (gas: 29619)
+RMN_voteToBless_Blessed_Benchmark:test_1RootSuccess_gas() (gas: 27565)
+RMN_voteToBless_Blessed_Benchmark:test_3RootSuccess_gas() (gas: 81485)
+RMN_voteToBless_Blessed_Benchmark:test_5RootSuccess_gas() (gas: 135299)
+RMN_voteToCurse:test_CurseOnlyWhenThresholdReached_Success() (gas: 1648701)
+RMN_voteToCurse:test_EmptySubjects_Revert() (gas: 14019)
+RMN_voteToCurse:test_EvenIfAlreadyCursed_Success() (gas: 534332)
+RMN_voteToCurse:test_OwnerCanCurseAndUncurse() (gas: 399001)
+RMN_voteToCurse:test_RepeatedSubject_Revert() (gas: 144225)
+RMN_voteToCurse:test_ReusedCurseId_Revert() (gas: 146738)
+RMN_voteToCurse:test_UnauthorizedVoter_Revert() (gas: 12600)
+RMN_voteToCurse:test_VoteToCurse_NoCurse_Success() (gas: 187244)
+RMN_voteToCurse:test_VoteToCurse_YesCurse_Success() (gas: 472452)
+RMN_voteToCurse_2:test_VotesAreDroppedIfSubjectIsNotCursedDuringConfigChange() (gas: 370468)
+RMN_voteToCurse_2:test_VotesAreRetainedIfSubjectIsCursedDuringConfigChange() (gas: 1151909)
+RMN_voteToCurse_Benchmark_1:test_VoteToCurse_NewSubject_NewVoter_NoCurse_gas() (gas: 140968)
+RMN_voteToCurse_Benchmark_1:test_VoteToCurse_NewSubject_NewVoter_YesCurse_gas() (gas: 165087)
+RMN_voteToCurse_Benchmark_2:test_VoteToCurse_OldSubject_NewVoter_NoCurse_gas() (gas: 121305)
+RMN_voteToCurse_Benchmark_2:test_VoteToCurse_OldSubject_OldVoter_NoCurse_gas() (gas: 98247)
+RMN_voteToCurse_Benchmark_3:test_VoteToCurse_OldSubject_NewVoter_YesCurse_gas() (gas: 145631)
+RateLimiter_constructor:test_Constructor_Success() (gas: 19650)
+RateLimiter_consume:test_AggregateValueMaxCapacityExceeded_Revert() (gas: 15916)
+RateLimiter_consume:test_AggregateValueRateLimitReached_Revert() (gas: 22222)
+RateLimiter_consume:test_ConsumeAggregateValue_Success() (gas: 31353)
+RateLimiter_consume:test_ConsumeTokens_Success() (gas: 20336)
+RateLimiter_consume:test_ConsumeUnlimited_Success() (gas: 40285)
+RateLimiter_consume:test_ConsumingMoreThanUint128_Revert() (gas: 15720)
+RateLimiter_consume:test_RateLimitReachedOverConsecutiveBlocks_Revert() (gas: 25594)
+RateLimiter_consume:test_Refill_Success() (gas: 37222)
+RateLimiter_consume:test_TokenMaxCapacityExceeded_Revert() (gas: 18250)
+RateLimiter_consume:test_TokenRateLimitReached_Revert() (gas: 24706)
+RateLimiter_currentTokenBucketState:test_CurrentTokenBucketState_Success() (gas: 38647)
+RateLimiter_currentTokenBucketState:test_Refill_Success() (gas: 46384)
+RateLimiter_setTokenBucketConfig:test_SetRateLimiterConfig_Success() (gas: 38017)
+RegistryModuleOwnerCustom_constructor:test_constructor_Revert() (gas: 36031)
+RegistryModuleOwnerCustom_registerAdminViaGetCCIPAdmin:test_registerAdminViaGetCCIPAdmin_Revert() (gas: 19637)
+RegistryModuleOwnerCustom_registerAdminViaGetCCIPAdmin:test_registerAdminViaGetCCIPAdmin_Success() (gas: 129918)
+RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Revert() (gas: 19451)
+RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Success() (gas: 129731)
+Router_applyRampUpdates:test_OffRampMismatch_Revert() (gas: 89288)
+Router_applyRampUpdates:test_OffRampUpdatesWithRouting() (gas: 10642128)
+Router_applyRampUpdates:test_OnRampDisable() (gas: 55913)
+Router_applyRampUpdates:test_OnlyOwner_Revert() (gas: 12311)
+Router_ccipSend:test_CCIPSendLinkFeeNoTokenSuccess_gas() (gas: 113861)
+Router_ccipSend:test_CCIPSendLinkFeeOneTokenSuccess_gas() (gas: 200634)
+Router_ccipSend:test_CCIPSendNativeFeeNoTokenSuccess_gas() (gas: 128508)
+Router_ccipSend:test_CCIPSendNativeFeeOneTokenSuccess_gas() (gas: 215283)
+Router_ccipSend:test_FeeTokenAmountTooLow_Revert() (gas: 66275)
+Router_ccipSend:test_InvalidMsgValue() (gas: 31963)
+Router_ccipSend:test_NativeFeeTokenInsufficientValue() (gas: 68711)
+Router_ccipSend:test_NativeFeeTokenOverpay_Success() (gas: 173605)
+Router_ccipSend:test_NativeFeeTokenZeroValue() (gas: 56037)
+Router_ccipSend:test_NativeFeeToken_Success() (gas: 172199)
+Router_ccipSend:test_NonLinkFeeToken_Success() (gas: 242707)
+Router_ccipSend:test_UnsupportedDestinationChain_Revert() (gas: 24749)
+Router_ccipSend:test_WhenNotHealthy_Revert() (gas: 44724)
+Router_ccipSend:test_WrappedNativeFeeToken_Success() (gas: 174415)
+Router_ccipSend:test_ZeroFeeAndGasPrice_Success() (gas: 245121)
+Router_constructor:test_Constructor_Success() (gas: 13074)
+Router_getArmProxy:test_getArmProxy() (gas: 10561)
+Router_getFee:test_GetFeeSupportedChain_Success() (gas: 46464)
+Router_getFee:test_UnsupportedDestinationChain_Revert() (gas: 17138)
+Router_getSupportedTokens:test_GetSupportedTokens_Revert() (gas: 10460)
+Router_recoverTokens:test_RecoverTokensInvalidRecipient_Revert() (gas: 11316)
+Router_recoverTokens:test_RecoverTokensNoFunds_Revert() (gas: 17761)
+Router_recoverTokens:test_RecoverTokensNonOwner_Revert() (gas: 11159)
+Router_recoverTokens:test_RecoverTokensValueReceiver_Revert() (gas: 422138)
+Router_recoverTokens:test_RecoverTokens_Success() (gas: 50437)
+Router_routeMessage:test_AutoExec_Success() (gas: 42684)
+Router_routeMessage:test_ExecutionEvent_Success() (gas: 158002)
+Router_routeMessage:test_ManualExec_Success() (gas: 35381)
+Router_routeMessage:test_OnlyOffRamp_Revert() (gas: 25116)
+Router_routeMessage:test_WhenNotHealthy_Revert() (gas: 44724)
+Router_setWrappedNative:test_OnlyOwner_Revert() (gas: 10985)
+SelfFundedPingPong_ccipReceive:test_FundingIfNotANop_Revert() (gas: 53540)
+SelfFundedPingPong_ccipReceive:test_Funding_Success() (gas: 416930)
+SelfFundedPingPong_setCountIncrBeforeFunding:test_setCountIncrBeforeFunding() (gas: 20157)
+TokenAdminRegistry_acceptAdminRole:test_acceptAdminRole_OnlyPendingAdministrator_Revert() (gas: 51085)
+TokenAdminRegistry_acceptAdminRole:test_acceptAdminRole_Success() (gas: 43947)
+TokenAdminRegistry_addRegistryModule:test_addRegistryModule_OnlyOwner_Revert() (gas: 12629)
+TokenAdminRegistry_addRegistryModule:test_addRegistryModule_Success() (gas: 67011)
+TokenAdminRegistry_getAllConfiguredTokens:test_getAllConfiguredTokens_outOfBounds_Success() (gas: 11350)
+TokenAdminRegistry_getPool:test_getPool_Success() (gas: 17581)
+TokenAdminRegistry_getPools:test_getPools_Success() (gas: 39902)
+TokenAdminRegistry_isAdministrator:test_isAdministrator_Success() (gas: 105922)
+TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_AlreadyRegistered_Revert() (gas: 104001)
+TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_OnlyRegistryModule_Revert() (gas: 15481)
+TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_ZeroAddress_Revert() (gas: 15026)
+TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_module_Success() (gas: 112536)
+TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_owner_Success() (gas: 107656)
+TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_reRegisterWhileUnclaimed_Success() (gas: 115686)
+TokenAdminRegistry_removeRegistryModule:test_removeRegistryModule_OnlyOwner_Revert() (gas: 12585)
+TokenAdminRegistry_removeRegistryModule:test_removeRegistryModule_Success() (gas: 54473)
+TokenAdminRegistry_setPool:test_setPool_InvalidTokenPoolToken_Revert() (gas: 19148)
+TokenAdminRegistry_setPool:test_setPool_OnlyAdministrator_Revert() (gas: 18020)
+TokenAdminRegistry_setPool:test_setPool_Success() (gas: 35943)
+TokenAdminRegistry_setPool:test_setPool_ZeroAddressRemovesPool_Success() (gas: 30617)
+TokenAdminRegistry_transferAdminRole:test_transferAdminRole_OnlyAdministrator_Revert() (gas: 18043)
+TokenAdminRegistry_transferAdminRole:test_transferAdminRole_Success() (gas: 49390)
+TokenPoolAndProxy:test_lockOrBurn_burnMint_Success() (gas: 6036775)
+TokenPoolAndProxy:test_lockOrBurn_lockRelease_Success() (gas: 6282531)
+TokenPoolAndProxyMigration:test_tokenPoolMigration_Success_1_2() (gas: 6883397)
+TokenPoolAndProxyMigration:test_tokenPoolMigration_Success_1_4() (gas: 7067512)
+TokenPoolWithAllowList_applyAllowListUpdates:test_AllowListNotEnabled_Revert() (gas: 2169749)
+TokenPoolWithAllowList_applyAllowListUpdates:test_OnlyOwner_Revert() (gas: 12089)
+TokenPoolWithAllowList_applyAllowListUpdates:test_SetAllowListSkipsZero_Success() (gas: 23280)
+TokenPoolWithAllowList_applyAllowListUpdates:test_SetAllowList_Success() (gas: 177516)
+TokenPoolWithAllowList_getAllowList:test_GetAllowList_Success() (gas: 23648)
+TokenPoolWithAllowList_getAllowListEnabled:test_GetAllowListEnabled_Success() (gas: 8363)
+TokenPoolWithAllowList_setRouter:test_SetRouter_Success() (gas: 24765)
+TokenPool_applyChainUpdates:test_applyChainUpdates_DisabledNonZeroRateLimit_Revert() (gas: 271305)
+TokenPool_applyChainUpdates:test_applyChainUpdates_InvalidRateLimitRate_Revert() (gas: 541162)
+TokenPool_applyChainUpdates:test_applyChainUpdates_NonExistentChain_Revert() (gas: 18344)
+TokenPool_applyChainUpdates:test_applyChainUpdates_OnlyCallableByOwner_Revert() (gas: 11385)
+TokenPool_applyChainUpdates:test_applyChainUpdates_Success() (gas: 476472)
+TokenPool_applyChainUpdates:test_applyChainUpdates_ZeroAddressNotAllowed_Revert() (gas: 157074)
+TokenPool_constructor:test_ZeroAddressNotAllowed_Revert() (gas: 70676)
+TokenPool_constructor:test_immutableFields_Success() (gas: 20522)
+TokenPool_getRemotePool:test_getRemotePool_Success() (gas: 273962)
+TokenPool_onlyOffRamp:test_CallerIsNotARampOnRouter_Revert() (gas: 276952)
+TokenPool_onlyOffRamp:test_ChainNotAllowed_Revert() (gas: 289509)
+TokenPool_onlyOffRamp:test_onlyOffRamp_Success() (gas: 349763)
+TokenPool_onlyOnRamp:test_CallerIsNotARampOnRouter_Revert() (gas: 276643)
+TokenPool_onlyOnRamp:test_ChainNotAllowed_Revert() (gas: 253466)
+TokenPool_onlyOnRamp:test_onlyOnRamp_Success() (gas: 304761)
+TokenPool_setChainRateLimiterConfig:test_NonExistentChain_Revert() (gas: 14906)
+TokenPool_setChainRateLimiterConfig:test_OnlyOwner_Revert() (gas: 12565)
+TokenPool_setRemotePool:test_setRemotePool_NonExistentChain_Reverts() (gas: 15598)
+TokenPool_setRemotePool:test_setRemotePool_OnlyOwner_Reverts() (gas: 13173)
+TokenPool_setRemotePool:test_setRemotePool_Success() (gas: 281890)
+TokenProxy_ccipSend:test_CcipSendGasShouldBeZero_Revert() (gas: 17109)
+TokenProxy_ccipSend:test_CcipSendInsufficientAllowance_Revert() (gas: 136351)
+TokenProxy_ccipSend:test_CcipSendInvalidToken_Revert() (gas: 15919)
+TokenProxy_ccipSend:test_CcipSendNative_Success() (gas: 244483)
+TokenProxy_ccipSend:test_CcipSendNoDataAllowed_Revert() (gas: 16303)
+TokenProxy_ccipSend:test_CcipSend_Success() (gas: 261100)
+TokenProxy_constructor:test_Constructor() (gas: 13812)
+TokenProxy_getFee:test_GetFeeGasShouldBeZero_Revert() (gas: 16827)
+TokenProxy_getFee:test_GetFeeInvalidToken_Revert() (gas: 12658)
+TokenProxy_getFee:test_GetFeeNoDataAllowed_Revert() (gas: 15849)
+TokenProxy_getFee:test_GetFee_Success() (gas: 86948)
+USDCTokenPool__validateMessage:test_ValidateInvalidMessage_Revert() (gas: 24960)
+USDCTokenPool_lockOrBurn:test_CallerIsNotARampOnRouter_Revert() (gas: 35312)
+USDCTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 30063)
+USDCTokenPool_lockOrBurn:test_LockOrBurn_Success() (gas: 132864)
+USDCTokenPool_lockOrBurn:test_UnknownDomain_Revert() (gas: 477209)
+USDCTokenPool_lockOrBurn:test_lockOrBurn_InvalidReceiver_Revert() (gas: 52606)
+USDCTokenPool_releaseOrMint:test_ReleaseOrMintRealTx_Success() (gas: 289268)
+USDCTokenPool_releaseOrMint:test_TokenMaxCapacityExceeded_Revert() (gas: 50682)
+USDCTokenPool_releaseOrMint:test_UnlockingUSDCFailed_Revert() (gas: 119185)
+USDCTokenPool_setDomains:test_InvalidDomain_Revert() (gas: 66150)
+USDCTokenPool_setDomains:test_OnlyOwner_Revert() (gas: 11339)
+USDCTokenPool_supportsInterface:test_SupportsInterface_Success() (gas: 9876)
\ No newline at end of file
diff --git a/contracts/gas-snapshots/keystone.gas-snapshot b/contracts/gas-snapshots/keystone.gas-snapshot
index 2880e4c0e31..49b1d4add4b 100644
--- a/contracts/gas-snapshots/keystone.gas-snapshot
+++ b/contracts/gas-snapshots/keystone.gas-snapshot
@@ -63,45 +63,51 @@ CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DuplicateCapabilityAdded() (g
CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DuplicateNodeAdded() (gas: 107643)
CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_NodeDoesNotSupportCapability() (gas: 163357)
CapabilitiesRegistry_UpdateDONTest:test_UpdatesDON() (gas: 371909)
-CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_CalledByNonAdminAndNonOwner() (gas: 20631)
+CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_CalledByNonAdminAndNonOwner() (gas: 20728)
CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorAdminIsZeroAddress() (gas: 20052)
CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorDoesNotExist() (gas: 19790)
CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorIdAndParamLengthsMismatch() (gas: 15430)
-CapabilitiesRegistry_UpdateNodeOperatorTest:test_UpdatesNodeOperator() (gas: 36937)
-CapabilitiesRegistry_UpdateNodesTest:test_CanUpdateParamsIfNodeSignerAddressNoLongerUsed() (gas: 256157)
-CapabilitiesRegistry_UpdateNodesTest:test_OwnerCanUpdateNodes() (gas: 162059)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_AddingNodeWithInvalidCapability() (gas: 35766)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 25069)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeDoesNotExist() (gas: 27308)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeSignerAlreadyAssignedToAnotherNode() (gas: 29219)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 27296)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByCapabilityDON() (gas: 470803)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByWorkflowDON() (gas: 341084)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_SignerAddressEmpty() (gas: 26951)
-CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_UpdatingNodeWithoutCapabilities() (gas: 25480)
-CapabilitiesRegistry_UpdateNodesTest:test_UpdatesNodeParams() (gas: 162113)
-KeystoneForwarder_ReportTest:test_Report_ConfigVersion() (gas: 1797755)
-KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverInterfaceNotSupported() (gas: 125910)
-KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverNotContract() (gas: 127403)
-KeystoneForwarder_ReportTest:test_Report_SuccessfulDelivery() (gas: 155928)
-KeystoneForwarder_ReportTest:test_RevertWhen_AlreadyAttempted() (gas: 152358)
-KeystoneForwarder_ReportTest:test_RevertWhen_AnySignatureIsInvalid() (gas: 86348)
-KeystoneForwarder_ReportTest:test_RevertWhen_AnySignerIsInvalid() (gas: 118486)
+CapabilitiesRegistry_UpdateNodeOperatorTest:test_UpdatesNodeOperator() (gas: 37034)
+CapabilitiesRegistry_UpdateNodesTest:test_CanUpdateParamsIfNodeSignerAddressNoLongerUsed() (gas: 256371)
+CapabilitiesRegistry_UpdateNodesTest:test_OwnerCanUpdateNodes() (gas: 162166)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_AddingNodeWithInvalidCapability() (gas: 35873)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByAnotherNodeOperatorAdmin() (gas: 29200)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 29377)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeDoesNotExist() (gas: 29199)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeSignerAlreadyAssignedToAnotherNode() (gas: 31326)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 29165)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByCapabilityDON() (gas: 470910)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByWorkflowDON() (gas: 341191)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_SignerAddressEmpty() (gas: 29058)
+CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_UpdatingNodeWithoutCapabilities() (gas: 27587)
+CapabilitiesRegistry_UpdateNodesTest:test_UpdatesNodeParams() (gas: 162220)
+KeystoneForwarder_ReportTest:test_Report_ConfigVersion() (gas: 2003568)
+KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverInterfaceNotSupported() (gas: 124908)
+KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverNotContract() (gas: 126927)
+KeystoneForwarder_ReportTest:test_Report_SuccessfulDelivery() (gas: 361243)
+KeystoneForwarder_ReportTest:test_Report_SuccessfulRetryWithMoreGas() (gas: 501084)
+KeystoneForwarder_ReportTest:test_RevertWhen_AnySignatureIsInvalid() (gas: 86326)
+KeystoneForwarder_ReportTest:test_RevertWhen_AnySignerIsInvalid() (gas: 118521)
+KeystoneForwarder_ReportTest:test_RevertWhen_AttemptingTransmissionWithInsufficientGas() (gas: 96279)
KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasDuplicateSignatures() (gas: 94516)
KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasIncorrectDON() (gas: 75930)
KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasInexistentConfigVersion() (gas: 76298)
-KeystoneForwarder_ReportTest:test_RevertWhen_ReportIsMalformed() (gas: 45585)
+KeystoneForwarder_ReportTest:test_RevertWhen_ReportIsMalformed() (gas: 45563)
+KeystoneForwarder_ReportTest:test_RevertWhen_RetryingInvalidContractTransmission() (gas: 143591)
+KeystoneForwarder_ReportTest:test_RevertWhen_RetryingSuccessfulTransmission() (gas: 354042)
KeystoneForwarder_ReportTest:test_RevertWhen_TooFewSignatures() (gas: 55292)
KeystoneForwarder_ReportTest:test_RevertWhen_TooManySignatures() (gas: 56050)
KeystoneForwarder_SetConfigTest:test_RevertWhen_ExcessSigners() (gas: 20184)
KeystoneForwarder_SetConfigTest:test_RevertWhen_FaultToleranceIsZero() (gas: 88057)
KeystoneForwarder_SetConfigTest:test_RevertWhen_InsufficientSigners() (gas: 14533)
-KeystoneForwarder_SetConfigTest:test_RevertWhen_NotOwner() (gas: 88788)
-KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingDuplicateSigners() (gas: 114507)
-KeystoneForwarder_SetConfigTest:test_SetConfig_FirstTime() (gas: 1539921)
-KeystoneForwarder_SetConfigTest:test_SetConfig_WhenSignersAreRemoved() (gas: 1534476)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_NotOwner() (gas: 88766)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingDuplicateSigners() (gas: 114570)
+KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingZeroAddressSigner() (gas: 114225)
+KeystoneForwarder_SetConfigTest:test_SetConfig_FirstTime() (gas: 1540541)
+KeystoneForwarder_SetConfigTest:test_SetConfig_WhenSignersAreRemoved() (gas: 1535211)
KeystoneForwarder_TypeAndVersionTest:test_TypeAndVersion() (gas: 9641)
KeystoneRouter_SetConfigTest:test_AddForwarder_RevertWhen_NotOwner() (gas: 10978)
KeystoneRouter_SetConfigTest:test_RemoveForwarder_RevertWhen_NotOwner() (gas: 10923)
-KeystoneRouter_SetConfigTest:test_Route_RevertWhen_UnauthorizedForwarder() (gas: 18553)
-KeystoneRouter_SetConfigTest:test_Route_Success() (gas: 75629)
\ No newline at end of file
+KeystoneRouter_SetConfigTest:test_RemoveForwarder_Success() (gas: 17599)
+KeystoneRouter_SetConfigTest:test_Route_RevertWhen_UnauthorizedForwarder() (gas: 18552)
+KeystoneRouter_SetConfigTest:test_Route_Success() (gas: 79379)
\ No newline at end of file
diff --git a/contracts/gas-snapshots/liquiditymanager.gas-snapshot b/contracts/gas-snapshots/liquiditymanager.gas-snapshot
new file mode 100644
index 00000000000..53483ed6c7c
--- /dev/null
+++ b/contracts/gas-snapshots/liquiditymanager.gas-snapshot
@@ -0,0 +1,48 @@
+LiquidityManager__report:test_EmptyReportReverts() (gas: 11181)
+LiquidityManager_addLiquidity:test_addLiquiditySuccess() (gas: 279154)
+LiquidityManager_rebalanceLiquidity:test_InsufficientLiquidityReverts() (gas: 206745)
+LiquidityManager_rebalanceLiquidity:test_InvalidRemoteChainReverts() (gas: 192319)
+LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPoolsSuccess() (gas: 9141768)
+LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPoolsSuccess_AlreadyFinalized() (gas: 8898695)
+LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_MultiStageFinalization() (gas: 8893901)
+LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_NativeRewrap() (gas: 8821699)
+LiquidityManager_rebalanceLiquidity:test_rebalanceLiquiditySuccess() (gas: 382897)
+LiquidityManager_receive:test_receive_success() (gas: 21182)
+LiquidityManager_removeLiquidity:test_InsufficientLiquidityReverts() (gas: 184869)
+LiquidityManager_removeLiquidity:test_OnlyFinanceRoleReverts() (gas: 10872)
+LiquidityManager_removeLiquidity:test_removeLiquiditySuccess() (gas: 236342)
+LiquidityManager_setCrossChainRebalancer:test_OnlyOwnerReverts() (gas: 17005)
+LiquidityManager_setCrossChainRebalancer:test_ZeroAddressReverts() (gas: 21624)
+LiquidityManager_setCrossChainRebalancer:test_ZeroChainSelectorReverts() (gas: 13099)
+LiquidityManager_setCrossChainRebalancer:test_setCrossChainRebalancerSuccess() (gas: 162186)
+LiquidityManager_setFinanceRole:test_OnlyOwnerReverts() (gas: 10987)
+LiquidityManager_setFinanceRole:test_setFinanceRoleSuccess() (gas: 21836)
+LiquidityManager_setLocalLiquidityContainer:test_OnlyOwnerReverts() (gas: 11052)
+LiquidityManager_setLocalLiquidityContainer:test_ReverstWhen_CalledWithTheZeroAddress() (gas: 10643)
+LiquidityManager_setLocalLiquidityContainer:test_setLocalLiquidityContainerSuccess() (gas: 3436651)
+LiquidityManager_setMinimumLiquidity:test_OnlyOwnerReverts() (gas: 10925)
+LiquidityManager_setMinimumLiquidity:test_setMinimumLiquiditySuccess() (gas: 36389)
+LiquidityManager_withdrawERC20:test_withdrawERC20Reverts() (gas: 180359)
+LiquidityManager_withdrawERC20:test_withdrawERC20Success() (gas: 205858)
+LiquidityManager_withdrawNative:test_OnlyFinanceRoleReverts() (gas: 13046)
+LiquidityManager_withdrawNative:test_withdrawNative_success() (gas: 51398)
+OCR3Base_setOCR3Config:testFMustBePositiveReverts() (gas: 12245)
+OCR3Base_setOCR3Config:testFTooHighReverts() (gas: 12429)
+OCR3Base_setOCR3Config:testOracleOutOfRegisterReverts() (gas: 14847)
+OCR3Base_setOCR3Config:testRepeatAddressReverts() (gas: 44932)
+OCR3Base_setOCR3Config:testSetConfigSuccess() (gas: 154642)
+OCR3Base_setOCR3Config:testSignerCannotBeZeroAddressReverts() (gas: 23712)
+OCR3Base_setOCR3Config:testTooManySignersReverts() (gas: 19832)
+OCR3Base_setOCR3Config:testTransmitterCannotBeZeroAddressReverts() (gas: 46539)
+OCR3Base_transmit:testConfigDigestMismatchReverts() (gas: 24827)
+OCR3Base_transmit:testForkedChainReverts() (gas: 42846)
+OCR3Base_transmit:testNonIncreasingSequenceNumberReverts() (gas: 30522)
+OCR3Base_transmit:testNonUniqueSignatureReverts() (gas: 60370)
+OCR3Base_transmit:testSignatureOutOfRegistrationReverts() (gas: 26128)
+OCR3Base_transmit:testTransmit2SignersSuccess_gas() (gas: 56783)
+OCR3Base_transmit:testUnAuthorizedTransmitterReverts() (gas: 28618)
+OCR3Base_transmit:testUnauthorizedSignerReverts() (gas: 44759)
+OCR3Base_transmit:testWrongNumberOfSignaturesReverts() (gas: 25678)
+OptimismL1BridgeAdapter_finalizeWithdrawERC20:testFinalizeWithdrawERC20Reverts() (gas: 12932)
+OptimismL1BridgeAdapter_finalizeWithdrawERC20:testfinalizeWithdrawERC20FinalizeSuccess() (gas: 16972)
+OptimismL1BridgeAdapter_finalizeWithdrawERC20:testfinalizeWithdrawERC20proveWithdrawalSuccess() (gas: 20758)
\ 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 0162809e90d..89073a78468 100644
--- a/contracts/gas-snapshots/llo-feeds.gas-snapshot
+++ b/contracts/gas-snapshots/llo-feeds.gas-snapshot
@@ -18,6 +18,220 @@ ByteUtilTest:test_readUint32MultiWord() (gas: 3393)
ByteUtilTest:test_readUint32WithEmptyArray() (gas: 3253)
ByteUtilTest:test_readUint32WithNotEnoughBytes() (gas: 3272)
ByteUtilTest:test_readZeroAddress() (gas: 3365)
+DestinationFeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52669)
+DestinationFeeManagerProcessFeeTest:test_DiscountIsReturnedForNative() (gas: 52685)
+DestinationFeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78876)
+DestinationFeeManagerProcessFeeTest:test_V1PayloadVerifies() (gas: 29324)
+DestinationFeeManagerProcessFeeTest:test_V1PayloadVerifiesAndReturnsChange() (gas: 61187)
+DestinationFeeManagerProcessFeeTest:test_V2PayloadVerifies() (gas: 121137)
+DestinationFeeManagerProcessFeeTest:test_V2PayloadWithoutQuoteFails() (gas: 29669)
+DestinationFeeManagerProcessFeeTest:test_V2PayloadWithoutZeroFee() (gas: 74797)
+DestinationFeeManagerProcessFeeTest:test_WithdrawERC20() (gas: 72796)
+DestinationFeeManagerProcessFeeTest:test_WithdrawNonAdminAddr() (gas: 56334)
+DestinationFeeManagerProcessFeeTest:test_WithdrawUnwrappedNative() (gas: 26411)
+DestinationFeeManagerProcessFeeTest:test_addVerifier() (gas: 131079)
+DestinationFeeManagerProcessFeeTest:test_addVerifierExistingAddress() (gas: 34148)
+DestinationFeeManagerProcessFeeTest:test_baseFeeIsAppliedForLink() (gas: 17214)
+DestinationFeeManagerProcessFeeTest:test_baseFeeIsAppliedForNative() (gas: 20152)
+DestinationFeeManagerProcessFeeTest:test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() (gas: 91103)
+DestinationFeeManagerProcessFeeTest:test_discountAIsNotAppliedWhenSetForOtherUsers() (gas: 56580)
+DestinationFeeManagerProcessFeeTest:test_discountFeeRoundsDownWhenUneven() (gas: 52871)
+DestinationFeeManagerProcessFeeTest:test_discountIsAppliedForLink() (gas: 49682)
+DestinationFeeManagerProcessFeeTest:test_discountIsAppliedWith100PercentSurcharge() (gas: 78949)
+DestinationFeeManagerProcessFeeTest:test_discountIsNoLongerAppliedAfterRemoving() (gas: 46567)
+DestinationFeeManagerProcessFeeTest:test_discountIsNotAppliedForInvalidTokenAddress() (gas: 17582)
+DestinationFeeManagerProcessFeeTest:test_discountIsNotAppliedToOtherFeeds() (gas: 54628)
+DestinationFeeManagerProcessFeeTest:test_discountIsReturnedForLink() (gas: 49654)
+DestinationFeeManagerProcessFeeTest:test_emptyQuoteRevertsWithError() (gas: 12231)
+DestinationFeeManagerProcessFeeTest:test_eventIsEmittedAfterSurchargeIsSet() (gas: 41424)
+DestinationFeeManagerProcessFeeTest:test_eventIsEmittedIfNotEnoughLink() (gas: 179229)
+DestinationFeeManagerProcessFeeTest:test_eventIsEmittedUponWithdraw() (gas: 69057)
+DestinationFeeManagerProcessFeeTest:test_feeIsUpdatedAfterDiscountIsRemoved() (gas: 49831)
+DestinationFeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewDiscountIsApplied() (gas: 67769)
+DestinationFeeManagerProcessFeeTest:test_feeIsUpdatedAfterNewSurchargeIsApplied() (gas: 64460)
+DestinationFeeManagerProcessFeeTest:test_feeIsZeroWith100PercentDiscount() (gas: 52091)
+DestinationFeeManagerProcessFeeTest:test_getBaseRewardWithLinkQuote() (gas: 17231)
+DestinationFeeManagerProcessFeeTest:test_getLinkFeeIsRoundedUp() (gas: 49853)
+DestinationFeeManagerProcessFeeTest:test_getLinkRewardIsSameAsFee() (gas: 55711)
+DestinationFeeManagerProcessFeeTest:test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() (gas: 82833)
+DestinationFeeManagerProcessFeeTest:test_getRewardWithLinkDiscount() (gas: 49700)
+DestinationFeeManagerProcessFeeTest:test_getRewardWithLinkQuoteAndLinkDiscount() (gas: 49681)
+DestinationFeeManagerProcessFeeTest:test_getRewardWithNativeQuote() (gas: 20150)
+DestinationFeeManagerProcessFeeTest:test_getRewardWithNativeQuoteAndSurcharge() (gas: 50885)
+DestinationFeeManagerProcessFeeTest:test_linkAvailableForPaymentReturnsLinkBalance() (gas: 53172)
+DestinationFeeManagerProcessFeeTest:test_nativeSurcharge0Percent() (gas: 30937)
+DestinationFeeManagerProcessFeeTest:test_nativeSurcharge100Percent() (gas: 50887)
+DestinationFeeManagerProcessFeeTest:test_nativeSurchargeCannotExceed100Percent() (gas: 17220)
+DestinationFeeManagerProcessFeeTest:test_nativeSurchargeEventIsEmittedOnUpdate() (gas: 41402)
+DestinationFeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFee() (gas: 51914)
+DestinationFeeManagerProcessFeeTest:test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() (gas: 78172)
+DestinationFeeManagerProcessFeeTest:test_nonAdminProxyUserCannotProcessFee() (gas: 24185)
+DestinationFeeManagerProcessFeeTest:test_nonAdminUserCanNotSetDiscount() (gas: 19871)
+DestinationFeeManagerProcessFeeTest:test_onlyCallableByOwnerReverts() (gas: 15453)
+DestinationFeeManagerProcessFeeTest:test_payLinkDeficit() (gas: 198072)
+DestinationFeeManagerProcessFeeTest:test_payLinkDeficitOnlyCallableByAdmin() (gas: 17415)
+DestinationFeeManagerProcessFeeTest:test_payLinkDeficitPaysAllFeesProcessed() (gas: 218691)
+DestinationFeeManagerProcessFeeTest:test_payLinkDeficitTwice() (gas: 202446)
+DestinationFeeManagerProcessFeeTest:test_poolIdsCannotBeZeroAddress() (gas: 115317)
+DestinationFeeManagerProcessFeeTest:test_processFeeAsProxy() (gas: 121475)
+DestinationFeeManagerProcessFeeTest:test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() (gas: 29745)
+DestinationFeeManagerProcessFeeTest:test_processFeeEmitsEventIfNotEnoughLink() (gas: 165393)
+DestinationFeeManagerProcessFeeTest:test_processFeeIfSubscriberIsSelf() (gas: 30063)
+DestinationFeeManagerProcessFeeTest:test_processFeeNative() (gas: 178204)
+DestinationFeeManagerProcessFeeTest:test_processFeeUsesCorrectDigest() (gas: 122766)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() (gas: 31822)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithDiscountEmitsEvent() (gas: 245890)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithInvalidReportVersionFailsToDecode() (gas: 30770)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithNoDiscountDoesNotEmitEvent() (gas: 171109)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithUnwrappedNative() (gas: 186069)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddress() (gas: 135874)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() (gas: 161459)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeShortFunds() (gas: 94841)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithUnwrappedNativeWithExcessiveFee() (gas: 193032)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithWithCorruptQuotePayload() (gas: 75084)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithWithEmptyQuotePayload() (gas: 30006)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithWithZeroQuotePayload() (gas: 30056)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() (gas: 35320)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() (gas: 158081)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkReturnsChange() (gas: 56059)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() (gas: 121473)
+DestinationFeeManagerProcessFeeTest:test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() (gas: 38024)
+DestinationFeeManagerProcessFeeTest:test_processMultipleLinkReports() (gas: 230434)
+DestinationFeeManagerProcessFeeTest:test_processMultipleUnwrappedNativeReports() (gas: 264223)
+DestinationFeeManagerProcessFeeTest:test_processMultipleV1Reports() (gas: 81155)
+DestinationFeeManagerProcessFeeTest:test_processMultipleWrappedNativeReports() (gas: 247072)
+DestinationFeeManagerProcessFeeTest:test_processPoolIdsPassedMismatched() (gas: 98793)
+DestinationFeeManagerProcessFeeTest:test_processV1V2V3Reports() (gas: 215445)
+DestinationFeeManagerProcessFeeTest:test_processV1V2V3ReportsWithUnwrapped() (gas: 257087)
+DestinationFeeManagerProcessFeeTest:test_removeVerifierNonExistentAddress() (gas: 12822)
+DestinationFeeManagerProcessFeeTest:test_removeVerifierZeroAaddress() (gas: 10678)
+DestinationFeeManagerProcessFeeTest:test_reportWithNoExpiryOrFeeReturnsZero() (gas: 13615)
+DestinationFeeManagerProcessFeeTest:test_revertOnSettingAnAddressZeroVerifier() (gas: 10614)
+DestinationFeeManagerProcessFeeTest:test_rewardsAreCorrectlySentToEachAssociatedPoolWhenVerifyingInBulk() (gas: 263181)
+DestinationFeeManagerProcessFeeTest:test_setDiscountOver100Percent() (gas: 19562)
+DestinationFeeManagerProcessFeeTest:test_setRewardManagerZeroAddress() (gas: 10626)
+DestinationFeeManagerProcessFeeTest:test_subscriberDiscountEventIsEmittedOnUpdate() (gas: 46329)
+DestinationFeeManagerProcessFeeTest:test_surchargeFeeRoundsUpWhenUneven() (gas: 51261)
+DestinationFeeManagerProcessFeeTest:test_surchargeIsApplied() (gas: 51165)
+DestinationFeeManagerProcessFeeTest:test_surchargeIsAppliedForNativeFeeWithDiscount() (gas: 79356)
+DestinationFeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 47132)
+DestinationFeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49962)
+DestinationFeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 78352)
+DestinationFeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14943)
+DestinationRewardManagerClaimTest:test_claimAllRecipients() (gas: 277191)
+DestinationRewardManagerClaimTest:test_claimMultipleRecipients() (gas: 154371)
+DestinationRewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 330208)
+DestinationRewardManagerClaimTest:test_claimSingleRecipient() (gas: 89039)
+DestinationRewardManagerClaimTest:test_claimUnevenAmountRoundsDown() (gas: 315411)
+DestinationRewardManagerClaimTest:test_claimUnregisteredPoolId() (gas: 35164)
+DestinationRewardManagerClaimTest:test_claimUnregisteredRecipient() (gas: 41201)
+DestinationRewardManagerClaimTest:test_eventIsEmittedUponClaim() (gas: 86084)
+DestinationRewardManagerClaimTest:test_eventIsNotEmittedUponUnsuccessfulClaim() (gas: 25050)
+DestinationRewardManagerClaimTest:test_recipientsClaimMultipleDeposits() (gas: 386857)
+DestinationRewardManagerClaimTest:test_singleRecipientClaimMultipleDeposits() (gas: 137777)
+DestinationRewardManagerNoRecipientSet:test_claimAllRecipientsAfterRecipientsSet() (gas: 492227)
+DestinationRewardManagerPayRecipientsTest:test_addFundsToPoolAsNonOwnerOrFeeManager() (gas: 11503)
+DestinationRewardManagerPayRecipientsTest:test_addFundsToPoolAsOwner() (gas: 53944)
+DestinationRewardManagerPayRecipientsTest:test_payAllRecipients() (gas: 250829)
+DestinationRewardManagerPayRecipientsTest:test_payAllRecipientsFromNonAdminUser() (gas: 20496)
+DestinationRewardManagerPayRecipientsTest:test_payAllRecipientsFromRecipientInPool() (gas: 251075)
+DestinationRewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalInvalidRecipient() (gas: 262275)
+DestinationRewardManagerPayRecipientsTest:test_payAllRecipientsWithAdditionalUnregisteredRecipient() (gas: 265760)
+DestinationRewardManagerPayRecipientsTest:test_payRecipientWithInvalidPool() (gas: 28908)
+DestinationRewardManagerPayRecipientsTest:test_payRecipientsEmptyRecipientList() (gas: 25333)
+DestinationRewardManagerPayRecipientsTest:test_payRecipientsWithInvalidPoolId() (gas: 31402)
+DestinationRewardManagerPayRecipientsTest:test_paySingleRecipient() (gas: 84709)
+DestinationRewardManagerPayRecipientsTest:test_paySubsetOfRecipientsInPool() (gas: 198474)
+DestinationRewardManagerRecipientClaimDifferentWeightsTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 280853)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsMultiplePools() (gas: 512489)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimAllRecipientsSinglePool() (gas: 283649)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimEmptyPoolWhenSecondPoolContainsFunds() (gas: 293497)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsMultiplePools() (gas: 263075)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimMultipleRecipientsSinglePool() (gas: 154537)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleRecipientMultiplePools() (gas: 132653)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimSingleUniqueRecipient() (gas: 106056)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimUnevenAmountRoundsDown() (gas: 579776)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_claimUnregisteredRecipient() (gas: 64664)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorAndTotalPoolsEqual() (gas: 13074)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() (gas: 12703)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_getAvailableRewardsCursorSingleResult() (gas: 22471)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPools() (gas: 32248)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() (gas: 148629)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInNoPools() (gas: 21728)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_getRewardsAvailableToRecipientInSinglePool() (gas: 27765)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_recipientsClaimMultipleDeposits() (gas: 391427)
+DestinationRewardManagerRecipientClaimMultiplePoolsTest:test_singleRecipientClaimMultipleDeposits() (gas: 137862)
+DestinationRewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmount() (gas: 199546)
+DestinationRewardManagerRecipientClaimUnevenWeightTest:test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() (gas: 219419)
+DestinationRewardManagerSetRecipientsTest:test_eventIsEmittedUponSetRecipients() (gas: 191707)
+DestinationRewardManagerSetRecipientsTest:test_setRecipientContainsDuplicateRecipients() (gas: 126060)
+DestinationRewardManagerSetRecipientsTest:test_setRewardRecipientFromManagerAddress() (gas: 214117)
+DestinationRewardManagerSetRecipientsTest:test_setRewardRecipientFromNonOwnerOrFeeManagerAddress() (gas: 21496)
+DestinationRewardManagerSetRecipientsTest:test_setRewardRecipientTwice() (gas: 193280)
+DestinationRewardManagerSetRecipientsTest:test_setRewardRecipientWeights() (gas: 180608)
+DestinationRewardManagerSetRecipientsTest:test_setRewardRecipientWithZeroAddress() (gas: 90202)
+DestinationRewardManagerSetRecipientsTest:test_setRewardRecipientWithZeroWeight() (gas: 191312)
+DestinationRewardManagerSetRecipientsTest:test_setRewardRecipients() (gas: 185567)
+DestinationRewardManagerSetRecipientsTest:test_setRewardRecipientsIsEmpty() (gas: 87091)
+DestinationRewardManagerSetRecipientsTest:test_setSingleRewardRecipient() (gas: 110349)
+DestinationRewardManagerSetupTest:test_addFeeManagerExistingAddress() (gas: 35281)
+DestinationRewardManagerSetupTest:test_addFeeManagerZeroAddress() (gas: 10580)
+DestinationRewardManagerSetupTest:test_addRemoveFeeManager() (gas: 48248)
+DestinationRewardManagerSetupTest:test_eventEmittedUponFeeManagerUpdate() (gas: 41581)
+DestinationRewardManagerSetupTest:test_eventEmittedUponFeePaid() (gas: 259172)
+DestinationRewardManagerSetupTest:test_rejectsZeroLinkAddressOnConstruction() (gas: 59610)
+DestinationRewardManagerSetupTest:test_removeFeeManagerNonExistentAddress() (gas: 12778)
+DestinationRewardManagerSetupTest:test_setFeeManagerZeroAddress() (gas: 17084)
+DestinationRewardManagerUpdateRewardRecipientsMultiplePoolsTest:test_updatePrimaryRecipientWeights() (gas: 376674)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_eventIsEmittedUponUpdateRecipients() (gas: 280411)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_onlyAdminCanUpdateRecipients() (gas: 19705)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_partialUpdateRecipientWeights() (gas: 221004)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateAllRecipientsWithSameAddressAndWeight() (gas: 274233)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsToSubset() (gas: 254156)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithExcessiveWeight() (gas: 259143)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithSameAddressAndWeight() (gas: 149856)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updatePartialRecipientsWithUnderWeightSet() (gas: 259217)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientWeights() (gas: 372155)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientWithNewZeroAddress() (gas: 270700)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientsContainsDuplicateRecipients() (gas: 288483)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentLargerSet() (gas: 407780)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentPartialSet() (gas: 317945)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSet() (gas: 377692)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientsToDifferentSetWithInvalidWeights() (gas: 312038)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForLargerSet() (gas: 399603)
+DestinationRewardManagerUpdateRewardRecipientsTest:test_updateRecipientsUpdateAndRemoveExistingForSmallerSet() (gas: 289433)
+DestinationVerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 639153)
+DestinationVerifierBulkVerifyBillingReport:test_verifyWithBulkNative() (gas: 640232)
+DestinationVerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrapped() (gas: 661796)
+DestinationVerifierBulkVerifyBillingReport:test_verifyWithBulkNativeUnwrappedReturnsChange() (gas: 661751)
+DestinationVerifierConstructorTest:test_falseIfIsNotCorrectInterface() (gas: 8719)
+DestinationVerifierConstructorTest:test_revertsIfInitializedWithEmptyVerifierProxy() (gas: 61121)
+DestinationVerifierConstructorTest:test_trueIfIsCorrectInterface() (gas: 8604)
+DestinationVerifierConstructorTest:test_typeAndVersion() (gas: 2818189)
+DestinationVerifierProxyInitializeVerifierTest:test_correctlySetsTheOwner() (gas: 1035181)
+DestinationVerifierProxyInitializeVerifierTest:test_correctlySetsVersion() (gas: 9841)
+DestinationVerifierProxyInitializeVerifierTest:test_setVerifierCalledByNoOwner() (gas: 17483)
+DestinationVerifierProxyInitializeVerifierTest:test_setVerifierOk() (gas: 30622)
+DestinationVerifierProxyInitializeVerifierTest:test_setVerifierWhichDoesntHonourInterface() (gas: 16851)
+DestinationVerifierSetAccessControllerTest:test_emitsTheCorrectEvent() (gas: 35391)
+DestinationVerifierSetAccessControllerTest:test_revertsIfCalledByNonOwner() (gas: 15089)
+DestinationVerifierSetAccessControllerTest:test_successfullySetsNewAccessController() (gas: 34885)
+DestinationVerifierSetAccessControllerTest:test_successfullySetsNewAccessControllerIsEmpty() (gas: 15007)
+DestinationVerifierSetConfigTest:test_NoDonConfigAlreadyExists() (gas: 2874492)
+DestinationVerifierSetConfigTest:test_addressesAndWeightsDoNotProduceSideEffectsInDonConfigIds() (gas: 1323177)
+DestinationVerifierSetConfigTest:test_donConfigIdIsSameForSignersInDifferentOrder() (gas: 1290374)
+DestinationVerifierSetConfigTest:test_removeLatestConfig() (gas: 786275)
+DestinationVerifierSetConfigTest:test_removeLatestConfigWhenNoConfigShouldFail() (gas: 12870)
+DestinationVerifierSetConfigTest:test_revertsIfCalledByNonOwner() (gas: 174936)
+DestinationVerifierSetConfigTest:test_revertsIfDuplicateSigners() (gas: 171604)
+DestinationVerifierSetConfigTest:test_revertsIfFaultToleranceIsZero() (gas: 168484)
+DestinationVerifierSetConfigTest:test_revertsIfNotEnoughSigners() (gas: 11571)
+DestinationVerifierSetConfigTest:test_revertsIfSetWithTooManySigners() (gas: 17943)
+DestinationVerifierSetConfigTest:test_revertsIfSignerContainsZeroAddress() (gas: 324333)
+DestinationVerifierSetConfigTest:test_setConfigActiveUnknownDonConfigId() (gas: 13102)
+DestinationVerifierSetConfigTest:test_setConfigWithActivationTime() (gas: 1088176)
+DestinationVerifierSetConfigTest:test_setConfigWithActivationTimeEarlierThanLatestConfigShouldFail() (gas: 1963414)
+DestinationVerifierSetConfigTest:test_setConfigWithActivationTimeNoFutureTimeShouldFail() (gas: 259797)
FeeManagerProcessFeeTest:test_DiscountIsAppliedForNative() (gas: 52645)
FeeManagerProcessFeeTest:test_DiscountIsReturnedForNative() (gas: 52595)
FeeManagerProcessFeeTest:test_DiscountIsReturnedForNativeWithSurcharge() (gas: 78808)
@@ -108,6 +322,7 @@ FeeManagerProcessFeeTest:test_surchargeIsNoLongerAppliedAfterRemoving() (gas: 47
FeeManagerProcessFeeTest:test_surchargeIsNotAppliedForLinkFee() (gas: 49938)
FeeManagerProcessFeeTest:test_surchargeIsNotAppliedWith100PercentDiscount() (gas: 78261)
FeeManagerProcessFeeTest:test_testRevertIfReportHasExpired() (gas: 14919)
+MultiVerifierBillingTests:test_multipleFeeManagersAndVerifiers() (gas: 4586990)
RewardManagerClaimTest:test_claimAllRecipients() (gas: 277131)
RewardManagerClaimTest:test_claimMultipleRecipients() (gas: 154341)
RewardManagerClaimTest:test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() (gas: 330086)
@@ -200,6 +415,13 @@ VerifierActivateFeedTest:test_revertsIfNoFeedExistsActivate() (gas: 13179)
VerifierActivateFeedTest:test_revertsIfNoFeedExistsDeactivate() (gas: 13157)
VerifierActivateFeedTest:test_revertsIfNotOwnerActivateFeed() (gas: 17109)
VerifierActivateFeedTest:test_revertsIfNotOwnerDeactivateFeed() (gas: 17164)
+VerifierBillingTests:test_rewardsAreDistributedAccordingToWeights() (gas: 1731717)
+VerifierBillingTests:test_rewardsAreDistributedAccordingToWeightsMultipleWeigths() (gas: 4460715)
+VerifierBillingTests:test_rewardsAreDistributedAccordingToWeightsUsingHistoricalConfigs() (gas: 2098833)
+VerifierBillingTests:test_verifyWithLinkV3Report() (gas: 1591346)
+VerifierBillingTests:test_verifyWithNativeERC20() (gas: 1467256)
+VerifierBillingTests:test_verifyWithNativeUnwrapped() (gas: 1376447)
+VerifierBillingTests:test_verifyWithNativeUnwrappedReturnsChange() (gas: 1383493)
VerifierBulkVerifyBillingReport:test_verifyMultiVersions() (gas: 476595)
VerifierBulkVerifyBillingReport:test_verifyMultiVersionsReturnsVerifiedReports() (gas: 474853)
VerifierBulkVerifyBillingReport:test_verifyWithBulkLink() (gas: 557541)
@@ -212,6 +434,7 @@ VerifierDeactivateFeedWithVerifyTest:test_currentReportAllowsVerification() (gas
VerifierDeactivateFeedWithVerifyTest:test_currentReportFailsVerification() (gas: 113388)
VerifierDeactivateFeedWithVerifyTest:test_previousReportAllowsVerification() (gas: 99624)
VerifierDeactivateFeedWithVerifyTest:test_previousReportFailsVerification() (gas: 69943)
+VerifierInterfacesTest:test_DestinationContractInterfaces() (gas: 623467)
VerifierProxyAccessControlledVerificationTest:test_proxiesToTheVerifierIfHasAccess() (gas: 208529)
VerifierProxyAccessControlledVerificationTest:test_revertsIfNoAccess() (gas: 112345)
VerifierProxyConstructorTest:test_correctlySetsTheCorrectAccessControllerInterface() (gas: 1485359)
@@ -236,6 +459,9 @@ VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_correctlyUnsetsVeri
VerifierProxyUnsetVerifierWithPreviouslySetVerifierTest:test_emitsAnEventAfterUnsettingVerifier() (gas: 17961)
VerifierProxyVerifyTest:test_proxiesToTheCorrectVerifier() (gas: 204342)
VerifierProxyVerifyTest:test_revertsIfNoVerifierConfigured() (gas: 117264)
+VerifierSetAccessControllerTest:test_revertsIfCalledByNonOwner() (gas: 17196)
+VerifierSetAccessControllerTest:test_setFeeManagerWhichDoesntHonourInterface() (gas: 16571)
+VerifierSetAccessControllerTest:test_successfullySetsNewFeeManager() (gas: 44855)
VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlySetsConfigWhenDigestsAreRemoved() (gas: 542302)
VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesDigestsOnMultipleVerifiersInTheProxy() (gas: 967768)
VerifierSetConfigFromSourceMultipleDigestsTest:test_correctlyUpdatesTheDigestInTheProxy() (gas: 523251)
@@ -256,6 +482,9 @@ VerifierTestBillingReport:test_verifyWithLink() (gas: 275293)
VerifierTestBillingReport:test_verifyWithNative() (gas: 316326)
VerifierTestBillingReport:test_verifyWithNativeUnwrapped() (gas: 318574)
VerifierTestBillingReport:test_verifyWithNativeUnwrappedReturnsChange() (gas: 325642)
+VerifierVerifyBulkTest:test_revertsVerifyBulkIfNoAccess() (gas: 112867)
+VerifierVerifyBulkTest:test_verifyBulkSingleCaseWithSingleConfig() (gas: 745046)
+VerifierVerifyBulkTest:test_verifyBulkWithSingleConfigOneVerifyFails() (gas: 698203)
VerifierVerifyMultipleConfigDigestTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 133961)
VerifierVerifyMultipleConfigDigestTest:test_canVerifyOlderReportsWithOlderConfigs() (gas: 189865)
VerifierVerifyMultipleConfigDigestTest:test_revertsIfAReportIsVerifiedWithAnExistingButIncorrectDigest() (gas: 88216)
@@ -270,6 +499,18 @@ VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedByNonProxy() (gas: 10
VerifierVerifySingleConfigDigestTest:test_revertsIfVerifiedWithIncorrectAddresses() (gas: 184077)
VerifierVerifySingleConfigDigestTest:test_revertsIfWrongNumberOfSigners() (gas: 110042)
VerifierVerifySingleConfigDigestTest:test_setsTheCorrectEpoch() (gas: 194592)
+VerifierVerifyTest:test_canVerifyNewerReportsWithNewerConfigs() (gas: 861741)
+VerifierVerifyTest:test_canVerifyOlderV3ReportsWithOlderConfigs() (gas: 815984)
+VerifierVerifyTest:test_failToVerifyReportIfDupSigners() (gas: 450715)
+VerifierVerifyTest:test_failToVerifyReportIfNoSigners() (gas: 426492)
+VerifierVerifyTest:test_failToVerifyReportIfNotEnoughSigners() (gas: 434814)
+VerifierVerifyTest:test_failToVerifyReportIfSignerNotInConfig() (gas: 456866)
+VerifierVerifyTest:test_revertsVerifyIfNoAccess() (gas: 109465)
+VerifierVerifyTest:test_rollingOutConfiguration() (gas: 1497254)
+VerifierVerifyTest:test_scenarioRollingNewChainWithHistoricConfigs() (gas: 976162)
+VerifierVerifyTest:test_verifyFailsWhenReportIsOlderThanConfig() (gas: 2303366)
+VerifierVerifyTest:test_verifyReport() (gas: 1434811)
+VerifierVerifyTest:test_verifyTooglingActiveFlagsDonConfigs() (gas: 1918797)
Verifier_accessControlledVerify:testVerifyWithAccessControl_gas() (gas: 212077)
Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithLinkFeeSuccess_gas() (gas: 519389)
Verifier_bulkVerifyWithFee:testBulkVerifyProxyWithNativeFeeSuccess_gas() (gas: 542808)
diff --git a/contracts/gas-snapshots/shared.gas-snapshot b/contracts/gas-snapshots/shared.gas-snapshot
index 0419c42a6aa..3cc143ecc0e 100644
--- a/contracts/gas-snapshots/shared.gas-snapshot
+++ b/contracts/gas-snapshots/shared.gas-snapshot
@@ -51,21 +51,29 @@ CallWithExactGas__callWithExactGasSafeReturnData:test_NoContractReverts() (gas:
CallWithExactGas__callWithExactGasSafeReturnData:test_NoGasForCallExactCheckReverts() (gas: 16139)
CallWithExactGas__callWithExactGasSafeReturnData:test_NotEnoughGasForCallReverts() (gas: 16547)
CallWithExactGas__callWithExactGasSafeReturnData:test_callWithExactGasSafeReturnData_ThrowOOGError_Revert() (gas: 36752)
-EnumerableMapAddresses_at:testAtSuccess() (gas: 95001)
-EnumerableMapAddresses_at:testBytes32AtSuccess() (gas: 94770)
+EnumerableMapAddresses_at:testAtSuccess() (gas: 95086)
+EnumerableMapAddresses_at:testBytes32AtSuccess() (gas: 94877)
EnumerableMapAddresses_contains:testBytes32ContainsSuccess() (gas: 93518)
EnumerableMapAddresses_contains:testContainsSuccess() (gas: 93696)
-EnumerableMapAddresses_get:testBytes32GetSuccess() (gas: 94249)
-EnumerableMapAddresses_get:testGetSuccess() (gas: 94436)
-EnumerableMapAddresses_get_errorMessage:testGetErrorMessageSuccess() (gas: 94477)
-EnumerableMapAddresses_length:testBytes32LengthSuccess() (gas: 72404)
-EnumerableMapAddresses_length:testLengthSuccess() (gas: 72582)
-EnumerableMapAddresses_remove:testBytes32RemoveSuccess() (gas: 73408)
+EnumerableMapAddresses_get:testBytes32GetSuccess() (gas: 94278)
+EnumerableMapAddresses_get:testGetSuccess() (gas: 94453)
+EnumerableMapAddresses_get_errorMessage:testGetErrorMessageSuccess() (gas: 94489)
+EnumerableMapAddresses_length:testBytes32LengthSuccess() (gas: 72445)
+EnumerableMapAddresses_length:testLengthSuccess() (gas: 72640)
+EnumerableMapAddresses_remove:testBytes32RemoveSuccess() (gas: 73462)
EnumerableMapAddresses_remove:testRemoveSuccess() (gas: 73686)
EnumerableMapAddresses_set:testBytes32SetSuccess() (gas: 94496)
EnumerableMapAddresses_set:testSetSuccess() (gas: 94685)
-EnumerableMapAddresses_tryGet:testBytes32TryGetSuccess() (gas: 94604)
-EnumerableMapAddresses_tryGet:testTryGetSuccess() (gas: 94864)
+EnumerableMapAddresses_tryGet:testBytes32TryGetSuccess() (gas: 94622)
+EnumerableMapAddresses_tryGet:testTryGetSuccess() (gas: 94893)
+EnumerableMapAddresses_at:testBytesAtSuccess() (gas: 96564)
+EnumerableMapAddresses_contains:testBytesContainsSuccess() (gas: 94012)
+EnumerableMapAddresses_get:testBytesGetSuccess() (gas: 95879)
+EnumerableMapAddresses_get_errorMessage:testBytesGetErrorMessageSuccess() (gas: 95878)
+EnumerableMapAddresses_length:testBytesLengthSuccess() (gas: 73011)
+EnumerableMapAddresses_remove:testBytesRemoveSuccess() (gas: 74249)
+EnumerableMapAddresses_set:testBytesSetSuccess() (gas: 95428)
+EnumerableMapAddresses_tryGet:testBytesTryGetSuccess() (gas: 96279)
OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1743649)
OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 298649)
OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957)
diff --git a/contracts/hardhat.config.ts b/contracts/hardhat.config.ts
index 1b2ac1bdf19..73e70081e9a 100644
--- a/contracts/hardhat.config.ts
+++ b/contracts/hardhat.config.ts
@@ -21,7 +21,8 @@ subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(
async (_, __, runSuper) => {
const paths = await runSuper()
const noTests = paths.filter((p: string) => !p.endsWith('.t.sol'))
- return noTests.filter(
+ const noCCIP = noTests.filter((p: string) => !p.includes('/v0.8/ccip'))
+ return noCCIP.filter(
(p: string) => !p.includes('src/v0.8/vendor/forge-std'),
)
},
diff --git a/contracts/package.json b/contracts/package.json
index 5a13d561f0c..85bae226c43 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": "pnpm publish --tag latest",
- "solhint": "solhint --max-warnings 2 \"./src/v0.8/**/*.sol\""
+ "solhint": "solhint --max-warnings 0 \"./src/v0.8/**/*.sol\""
},
"files": [
"src/v0.8",
@@ -78,6 +78,8 @@
"typescript": "^5.4.5"
},
"dependencies": {
+ "@arbitrum/nitro-contracts": "1.1.1",
+ "@arbitrum/token-bridge-contracts": "1.1.2",
"@changesets/changelog-github": "^0.5.0",
"@changesets/cli": "~2.27.3",
"@eth-optimism/contracts": "0.6.0",
diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml
index 4ad8deda991..825715f4160 100644
--- a/contracts/pnpm-lock.yaml
+++ b/contracts/pnpm-lock.yaml
@@ -11,6 +11,12 @@ importers:
.:
dependencies:
+ '@arbitrum/nitro-contracts':
+ specifier: 1.1.1
+ version: 1.1.1
+ '@arbitrum/token-bridge-contracts':
+ specifier: 1.1.2
+ version: 1.1.2
'@changesets/changelog-github':
specifier: ^0.5.0
version: 0.5.0
@@ -50,22 +56,22 @@ importers:
version: 5.7.2
'@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)
+ version: 1.0.6(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)))(chai@4.4.1)(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))
'@nomicfoundation/hardhat-ethers':
specifier: ^3.0.6
- version: 3.0.6(ethers@5.7.2)(hardhat@2.20.1)
+ version: 3.0.6(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))
'@nomicfoundation/hardhat-network-helpers':
specifier: ^1.0.9
- version: 1.0.10(hardhat@2.20.1)
+ version: 1.0.10(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))
'@nomicfoundation/hardhat-verify':
specifier: ^2.0.7
- version: 2.0.7(hardhat@2.20.1)
+ version: 2.0.7(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))
'@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.4.5)
+ 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.5))(typescript@5.4.5)
'@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.20.1)(typechain@8.3.2)
+ version: 7.0.0(@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.4.5))(typescript@5.4.5))(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))(typechain@8.3.2(typescript@5.4.5))
'@types/cbor':
specifier: ~5.0.1
version: 5.0.1
@@ -86,7 +92,7 @@ importers:
version: 20.12.12
'@typescript-eslint/eslint-plugin':
specifier: ^7.10.0
- version: 7.10.0(@typescript-eslint/parser@7.10.0)(eslint@8.57.0)(typescript@5.4.5)
+ version: 7.10.0(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)
'@typescript-eslint/parser':
specifier: ^7.10.0
version: 7.10.0(eslint@8.57.0)(typescript@5.4.5)
@@ -113,16 +119,16 @@ importers:
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.57.0)(prettier@3.2.5)
+ version: 5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5)
ethers:
specifier: ~5.7.2
version: 5.7.2
hardhat:
specifier: ~2.20.1
- version: 2.20.1(ts-node@10.9.2)(typescript@5.4.5)
+ version: 2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)
hardhat-abi-exporter:
specifier: ^2.10.1
- version: 2.10.1(hardhat@2.20.1)
+ version: 2.10.1(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))
hardhat-ignore-warnings:
specifier: ^0.2.6
version: 0.2.11
@@ -143,7 +149,7 @@ importers:
version: '@chainlink/solhint-plugin-chainlink-solidity@https://codeload.github.com/smartcontractkit/chainlink-solhint-rules/tar.gz/1b4c0c2663fcd983589d4f33a2e73908624ed43c'
solhint-plugin-prettier:
specifier: ^0.1.0
- version: 0.1.0(prettier-plugin-solidity@1.3.1)(prettier@3.2.5)
+ version: 0.1.0(prettier-plugin-solidity@1.3.1(prettier@3.2.5))(prettier@3.2.5)
ts-node:
specifier: ^10.9.2
version: 10.9.2(@types/node@20.12.12)(typescript@5.4.5)
@@ -160,6 +166,12 @@ packages:
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
engines: {node: '>=0.10.0'}
+ '@arbitrum/nitro-contracts@1.1.1':
+ resolution: {integrity: sha512-4Tyk3XVHz+bm8UujUC78LYSw3xAxyYvBCxfEX4z3qE4/ww7Qck/rmce5gbHMzQjArEAzAP2YSfYIFuIFuRXtfg==}
+
+ '@arbitrum/token-bridge-contracts@1.1.2':
+ resolution: {integrity: sha512-k7AZXiB2HFecJ1KfaDBqgOKe3Loo1ttGLC7hUOVB+0YrihIR6cYpJRuqKSKK4YCy+FF21AUDtaG3x57OFM667Q==}
+
'@babel/code-frame@7.18.6':
resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
engines: {node: '>=6.9.0'}
@@ -178,7 +190,6 @@ packages:
'@chainlink/solhint-plugin-chainlink-solidity@https://codeload.github.com/smartcontractkit/chainlink-solhint-rules/tar.gz/1b4c0c2663fcd983589d4f33a2e73908624ed43c':
resolution: {tarball: https://codeload.github.com/smartcontractkit/chainlink-solhint-rules/tar.gz/1b4c0c2663fcd983589d4f33a2e73908624ed43c}
- name: '@chainlink/solhint-plugin-chainlink-solidity'
version: 1.2.0
'@changesets/apply-release-plan@7.0.1':
@@ -572,12 +583,37 @@ packages:
ethers: ^5.0.0
hardhat: ^2.0.0
+ '@offchainlabs/upgrade-executor@1.1.0-beta.0':
+ resolution: {integrity: sha512-mpn6PHjH/KDDjNX0pXHEKdyv8m6DVGQiI2nGzQn0JbM1nOSHJpWx6fvfjtH7YxHJ6zBZTcsKkqGkFKDtCfoSLw==}
+
+ '@openzeppelin/contracts-upgradeable@4.5.2':
+ resolution: {integrity: sha512-xgWZYaPlrEOQo3cBj97Ufiuv79SPd8Brh4GcFYhPgb6WvAq4ppz8dWKL6h+jLAK01rUqMRp/TS9AdXgAeNvCLA==}
+
+ '@openzeppelin/contracts-upgradeable@4.7.3':
+ resolution: {integrity: sha512-+wuegAMaLcZnLCJIvrVUDzA9z/Wp93f0Dla/4jJvIhijRrPabjQbZe6fWiECLaJyfn5ci9fqf9vTw3xpQOad2A==}
+
+ '@openzeppelin/contracts-upgradeable@4.8.3':
+ resolution: {integrity: sha512-SXDRl7HKpl2WDoJpn7CK/M9U4Z8gNXDHHChAKh0Iz+Wew3wu6CmFYBeie3je8V0GSXZAIYYwUktSrnW/kwVPtg==}
+
'@openzeppelin/contracts-upgradeable@4.9.3':
resolution: {integrity: sha512-jjaHAVRMrE4UuZNfDwjlLGDxTHWIOwTJS2ldnc278a0gevfXfPr8hxKEVBGFBE96kl2G3VHDZhUimw/+G3TG2A==}
+ '@openzeppelin/contracts@4.5.0':
+ resolution: {integrity: sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA==}
+
+ '@openzeppelin/contracts@4.7.3':
+ resolution: {integrity: sha512-dGRS0agJzu8ybo44pCIf3xBaPQN/65AIXNgK8+4gzKd5kbvlqyxryUYVLJv7fK98Seyd2hDZzVEHSWAh0Bt1Yw==}
+
+ '@openzeppelin/contracts@4.8.3':
+ resolution: {integrity: sha512-bQHV8R9Me8IaJoJ2vPG4rXcL7seB7YVuskr4f+f5RyOStSZetwzkWtoqDMl5erkBJy0lDRUnIR2WIkPiC0GJlg==}
+
'@openzeppelin/contracts@4.9.3':
resolution: {integrity: sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg==}
+ '@openzeppelin/upgrades-core@1.34.4':
+ resolution: {integrity: sha512-iGN3StqYHYVqqSKs8hWY+Gz6VkiEqOkQccBhHl7lHLGBJF91QUZ8wNMZ59SA5Usg1Fstu/HurvZTCEshPJAZ8w==}
+ hasBin: true
+
'@pkgr/core@0.1.1':
resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
@@ -821,6 +857,9 @@ packages:
'@ungap/structured-clone@1.2.0':
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+ '@yarnpkg/lockfile@1.1.0':
+ resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==}
+
abi-to-sol@0.6.6:
resolution: {integrity: sha512-PRn81rSpv6NXFPYQSw7ujruqIP6UkwZ/XoFldtiqCX8+2kHVc73xVaUVvdbro06vvBVZiwnxhEIGdI4BRMwGHw==}
hasBin: true
@@ -924,10 +963,18 @@ packages:
array-buffer-byte-length@1.0.0:
resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==}
+ array-buffer-byte-length@1.0.1:
+ resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
+ engines: {node: '>= 0.4'}
+
array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'}
+ array.prototype.findlast@1.2.5:
+ resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
+ engines: {node: '>= 0.4'}
+
array.prototype.flat@1.3.2:
resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
engines: {node: '>= 0.4'}
@@ -936,6 +983,10 @@ packages:
resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==}
engines: {node: '>= 0.4'}
+ arraybuffer.prototype.slice@1.0.3:
+ resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
+ engines: {node: '>= 0.4'}
+
arrify@1.0.1:
resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
engines: {node: '>=0.10.0'}
@@ -958,6 +1009,10 @@ packages:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
+ available-typed-arrays@1.0.7:
+ resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+ engines: {node: '>= 0.4'}
+
balanced-match@1.0.0:
resolution: {integrity: sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==}
@@ -1056,6 +1111,10 @@ packages:
call-bind@1.0.5:
resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==}
+ call-bind@1.0.7:
+ resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
+ engines: {node: '>= 0.4'}
+
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -1083,6 +1142,10 @@ packages:
resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==}
engines: {node: '>=12.19'}
+ cbor@9.0.2:
+ resolution: {integrity: sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==}
+ engines: {node: '>=16'}
+
chai-as-promised@7.1.1:
resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==}
peerDependencies:
@@ -1183,6 +1246,9 @@ packages:
commander@3.0.2:
resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==}
+ compare-versions@6.1.1:
+ resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
+
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -1215,6 +1281,10 @@ packages:
cross-spawn@5.1.0:
resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==}
+ cross-spawn@6.0.5:
+ resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
+ engines: {node: '>=4.8'}
+
cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
@@ -1232,6 +1302,18 @@ packages:
resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==}
engines: {node: '>= 0.1.90'}
+ data-view-buffer@1.0.1:
+ resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-length@1.0.1:
+ resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==}
+ engines: {node: '>= 0.4'}
+
+ data-view-byte-offset@1.0.0:
+ resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
+ engines: {node: '>= 0.4'}
+
dataloader@1.4.0:
resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==}
@@ -1285,6 +1367,10 @@ packages:
resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
engines: {node: '>= 0.4'}
+ define-data-property@1.1.4:
+ resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+ engines: {node: '>= 0.4'}
+
define-properties@1.2.1:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
@@ -1349,10 +1435,30 @@ packages:
resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==}
engines: {node: '>= 0.4'}
+ es-abstract@1.23.3:
+ resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==}
+ engines: {node: '>= 0.4'}
+
+ es-define-property@1.0.0:
+ resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-object-atoms@1.0.0:
+ resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
+ engines: {node: '>= 0.4'}
+
es-set-tostringtag@2.0.2:
resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==}
engines: {node: '>= 0.4'}
+ es-set-tostringtag@2.0.3:
+ resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
+ engines: {node: '>= 0.4'}
+
es-shim-unscopables@1.0.2:
resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
@@ -1520,6 +1626,9 @@ packages:
find-yarn-workspace-root2@1.2.16:
resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==}
+ find-yarn-workspace-root@2.0.0:
+ resolution: {integrity: sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==}
+
flat-cache@3.2.0:
resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
engines: {node: ^10.12.0 || >=12.0.0}
@@ -1592,6 +1701,10 @@ packages:
get-intrinsic@1.2.2:
resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
+ get-intrinsic@1.2.4:
+ resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
+ engines: {node: '>= 0.4'}
+
get-stream@5.1.0:
resolution: {integrity: sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==}
engines: {node: '>=8'}
@@ -1604,6 +1717,10 @@ packages:
resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
engines: {node: '>= 0.4'}
+ get-symbol-description@1.0.2:
+ resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
+ engines: {node: '>= 0.4'}
+
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -1692,10 +1809,17 @@ packages:
has-property-descriptors@1.0.0:
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
+ has-property-descriptors@1.0.2:
+ resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+
has-proto@1.0.1:
resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
engines: {node: '>= 0.4'}
+ has-proto@1.0.3:
+ resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
+ engines: {node: '>= 0.4'}
+
has-symbols@1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
@@ -1704,6 +1828,10 @@ packages:
resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
engines: {node: '>= 0.4'}
+ has-tostringtag@1.0.2:
+ resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+ engines: {node: '>= 0.4'}
+
has@1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
@@ -1719,6 +1847,10 @@ packages:
resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
engines: {node: '>= 0.4'}
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
he@1.2.0:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
@@ -1790,12 +1922,20 @@ packages:
resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==}
engines: {node: '>= 0.4'}
+ internal-slot@1.0.7:
+ resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
+ engines: {node: '>= 0.4'}
+
io-ts@1.10.4:
resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==}
is-array-buffer@3.0.2:
resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
+ is-array-buffer@3.0.4:
+ resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
+ engines: {node: '>= 0.4'}
+
is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
@@ -1814,13 +1954,26 @@ packages:
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
engines: {node: '>= 0.4'}
+ is-ci@2.0.0:
+ resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==}
+ hasBin: true
+
is-core-module@2.10.0:
resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==}
+ is-data-view@1.0.1:
+ resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==}
+ engines: {node: '>= 0.4'}
+
is-date-object@1.0.2:
resolution: {integrity: sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==}
engines: {node: '>= 0.4'}
+ is-docker@2.2.1:
+ resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
+ engines: {node: '>=8'}
+ hasBin: true
+
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -1844,6 +1997,10 @@ packages:
resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
engines: {node: '>= 0.4'}
+ is-negative-zero@2.0.3:
+ resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
+ engines: {node: '>= 0.4'}
+
is-number-object@1.0.7:
resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
engines: {node: '>= 0.4'}
@@ -1871,6 +2028,10 @@ packages:
is-shared-array-buffer@1.0.2:
resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==}
+ is-shared-array-buffer@1.0.3:
+ resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
+ engines: {node: '>= 0.4'}
+
is-string@1.0.7:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
@@ -1887,6 +2048,10 @@ packages:
resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==}
engines: {node: '>= 0.4'}
+ is-typed-array@1.1.13:
+ resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
+ engines: {node: '>= 0.4'}
+
is-unicode-supported@0.1.0:
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
engines: {node: '>=10'}
@@ -1901,6 +2066,10 @@ packages:
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'}
+
isarray@2.0.5:
resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
@@ -1970,6 +2139,9 @@ packages:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
+ klaw-sync@6.0.0:
+ resolution: {integrity: sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==}
+
klaw@1.3.1:
resolution: {integrity: sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==}
@@ -2170,6 +2342,9 @@ packages:
neodoc@2.0.2:
resolution: {integrity: sha512-NAppJ0YecKWdhSXFYCHbo6RutiX8vOt/Jo3l46mUg6pQlpJNaqc5cGxdrW2jITQm5JIYySbFVPDl3RrREXNyPw==}
+ nice-try@1.0.5:
+ resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
+
no-case@2.3.2:
resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==}
@@ -2227,12 +2402,20 @@ packages:
resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==}
engines: {node: '>= 0.4'}
+ object.assign@4.1.5:
+ resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
+ engines: {node: '>= 0.4'}
+
obliterator@2.0.4:
resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==}
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ open@7.4.2:
+ resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==}
+ engines: {node: '>=8'}
+
optionator@0.9.3:
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
engines: {node: '>= 0.8.0'}
@@ -2313,6 +2496,11 @@ packages:
pascal-case@2.0.1:
resolution: {integrity: sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==}
+ patch-package@6.5.1:
+ resolution: {integrity: sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==}
+ engines: {node: '>=10', npm: '>5'}
+ hasBin: true
+
path-case@2.1.1:
resolution: {integrity: sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==}
@@ -2328,6 +2516,10 @@ packages:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
+ path-key@2.0.1:
+ resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
+ engines: {node: '>=4'}
+
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
@@ -2366,6 +2558,10 @@ packages:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
+ possible-typed-array-names@1.0.0:
+ resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
+ engines: {node: '>= 0.4'}
+
preferred-pm@3.1.3:
resolution: {integrity: sha512-MkXsENfftWSRpzCzImcp4FRsCc3y1opwB73CfCNWyzMqArju2CrlMHlqB7VexKiPEOjGMbttv1r9fSCn5S610w==}
engines: {node: '>=10'}
@@ -2394,6 +2590,9 @@ packages:
engines: {node: '>=14'}
hasBin: true
+ proper-lockfile@4.1.2:
+ resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==}
+
proto-list@1.2.4:
resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
@@ -2464,6 +2663,10 @@ packages:
resolution: {integrity: sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==}
engines: {node: '>= 0.4'}
+ regexp.prototype.flags@1.5.2:
+ resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
+ engines: {node: '>= 0.4'}
+
registry-auth-token@5.0.2:
resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==}
engines: {node: '>=14'}
@@ -2504,6 +2707,10 @@ packages:
responselike@2.0.1:
resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==}
+ retry@0.12.0:
+ resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
+ engines: {node: '>= 4'}
+
reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@@ -2536,6 +2743,10 @@ packages:
resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==}
engines: {node: '>=0.4'}
+ safe-array-concat@1.1.2:
+ resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
+ engines: {node: '>=0.4'}
+
safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
@@ -2545,6 +2756,10 @@ packages:
safe-regex-test@1.0.0:
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
+ safe-regex-test@1.0.3:
+ resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
+ engines: {node: '>= 0.4'}
+
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
@@ -2581,6 +2796,10 @@ packages:
resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==}
engines: {node: '>= 0.4'}
+ set-function-length@1.2.2:
+ resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+ engines: {node: '>= 0.4'}
+
set-function-name@2.0.1:
resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==}
engines: {node: '>= 0.4'}
@@ -2620,6 +2839,10 @@ packages:
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ slash@2.0.0:
+ resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==}
+ engines: {node: '>=6'}
+
slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@@ -2651,6 +2874,9 @@ packages:
resolution: {integrity: sha512-QeQLS9HGCnIiibt+xiOa/+MuP7BWz9N7C5+Mj9pLHshdkNhuo3AzCpWmjfWVZBUuwIUO3YyCRVIcYLR3YOKGfg==}
hasBin: true
+ solidity-ast@0.4.56:
+ resolution: {integrity: sha512-HgmsA/Gfklm/M8GFbCX/J1qkVH0spXHgALCNZ8fA8x5X+MFdn/8CP2gr5OVyXjXw6RZTPC/Sxl2RUDQOXyNMeA==}
+
solidity-comments-darwin-arm64@0.0.2:
resolution: {integrity: sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==}
engines: {node: '>= 10'}
@@ -2768,12 +2994,23 @@ packages:
resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==}
engines: {node: '>= 0.4'}
+ string.prototype.trim@1.2.9:
+ resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
+ engines: {node: '>= 0.4'}
+
string.prototype.trimend@1.0.7:
resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==}
+ string.prototype.trimend@1.0.8:
+ resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==}
+
string.prototype.trimstart@1.0.7:
resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==}
+ string.prototype.trimstart@1.0.8:
+ resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
+ engines: {node: '>= 0.4'}
+
string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
@@ -2952,17 +3189,33 @@ packages:
resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
engines: {node: '>= 0.4'}
+ typed-array-buffer@1.0.2:
+ resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
+ engines: {node: '>= 0.4'}
+
typed-array-byte-length@1.0.0:
resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==}
engines: {node: '>= 0.4'}
+ typed-array-byte-length@1.0.1:
+ resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
+ engines: {node: '>= 0.4'}
+
typed-array-byte-offset@1.0.0:
resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==}
engines: {node: '>= 0.4'}
+ typed-array-byte-offset@1.0.2:
+ resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
+ engines: {node: '>= 0.4'}
+
typed-array-length@1.0.4:
resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==}
+ typed-array-length@1.0.6:
+ resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==}
+ engines: {node: '>= 0.4'}
+
typescript@5.4.5:
resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==}
engines: {node: '>=14.17'}
@@ -3050,6 +3303,10 @@ packages:
resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==}
engines: {node: '>= 0.4'}
+ which-typed-array@1.1.15:
+ resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==}
+ engines: {node: '>= 0.4'}
+
which@1.3.1:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
hasBin: true
@@ -3115,6 +3372,10 @@ packages:
yallist@2.1.2:
resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==}
+ yaml@1.10.2:
+ resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
+ engines: {node: '>= 6'}
+
yargs-parser@18.1.3:
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
engines: {node: '>=6'}
@@ -3155,6 +3416,24 @@ snapshots:
'@aashutoshrathi/word-wrap@1.2.6': {}
+ '@arbitrum/nitro-contracts@1.1.1':
+ dependencies:
+ '@offchainlabs/upgrade-executor': 1.1.0-beta.0
+ '@openzeppelin/contracts': 4.5.0
+ '@openzeppelin/contracts-upgradeable': 4.5.2
+ patch-package: 6.5.1
+
+ '@arbitrum/token-bridge-contracts@1.1.2':
+ dependencies:
+ '@arbitrum/nitro-contracts': 1.1.1
+ '@offchainlabs/upgrade-executor': 1.1.0-beta.0
+ '@openzeppelin/contracts': 4.8.3
+ '@openzeppelin/contracts-upgradeable': 4.8.3
+ optionalDependencies:
+ '@openzeppelin/upgrades-core': 1.34.4
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/code-frame@7.18.6':
dependencies:
'@babel/highlight': 7.18.6
@@ -3787,11 +4066,12 @@ snapshots:
'@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
js-sdsl: 4.4.2
lru-cache: 10.2.2
+ optionalDependencies:
+ '@nomicfoundation/ethereumjs-verkle': 0.0.2
transitivePeerDependencies:
- c-kzg
- supports-color
@@ -3846,40 +4126,40 @@ snapshots:
- c-kzg
- supports-color
- '@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)':
+ '@nomicfoundation/hardhat-chai-matchers@1.0.6(@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)))(chai@4.4.1)(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))':
dependencies:
'@ethersproject/abi': 5.7.0
- '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.20.1)
+ '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))
'@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.5)
+ hardhat: 2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)
ordinal: 1.0.3
- '@nomicfoundation/hardhat-ethers@3.0.6(ethers@5.7.2)(hardhat@2.20.1)':
+ '@nomicfoundation/hardhat-ethers@3.0.6(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))':
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.5)
+ hardhat: 2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)
lodash.isequal: 4.5.0
transitivePeerDependencies:
- supports-color
- '@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.20.1)':
+ '@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))':
dependencies:
ethereumjs-util: 7.1.5
- hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.5)
+ hardhat: 2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)
- '@nomicfoundation/hardhat-verify@2.0.7(hardhat@2.20.1)':
+ '@nomicfoundation/hardhat-verify@2.0.7(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))':
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.5)
+ hardhat: 2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)
lodash.clonedeep: 4.5.0
semver: 6.3.0
table: 6.8.1
@@ -3930,15 +4210,46 @@ snapshots:
'@nomicfoundation/solidity-analyzer-win32-ia32-msvc': 0.1.0
'@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.0
- '@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.20.1)':
+ '@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))':
dependencies:
ethers: 5.7.2
- hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.5)
+ hardhat: 2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)
+
+ '@offchainlabs/upgrade-executor@1.1.0-beta.0':
+ dependencies:
+ '@openzeppelin/contracts': 4.7.3
+ '@openzeppelin/contracts-upgradeable': 4.7.3
+
+ '@openzeppelin/contracts-upgradeable@4.5.2': {}
+
+ '@openzeppelin/contracts-upgradeable@4.7.3': {}
+
+ '@openzeppelin/contracts-upgradeable@4.8.3': {}
'@openzeppelin/contracts-upgradeable@4.9.3': {}
+ '@openzeppelin/contracts@4.5.0': {}
+
+ '@openzeppelin/contracts@4.7.3': {}
+
+ '@openzeppelin/contracts@4.8.3': {}
+
'@openzeppelin/contracts@4.9.3': {}
+ '@openzeppelin/upgrades-core@1.34.4':
+ dependencies:
+ cbor: 9.0.2
+ chalk: 4.1.2
+ compare-versions: 6.1.1
+ 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.56
+ transitivePeerDependencies:
+ - supports-color
+ optional: true
+
'@pkgr/core@0.1.1': {}
'@pnpm/config.env-replace@1.1.0': {}
@@ -4052,7 +4363,7 @@ snapshots:
'@tsconfig/node16@1.0.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.5)':
+ '@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.5))(typescript@5.4.5)':
dependencies:
'@ethersproject/abi': 5.7.0
'@ethersproject/bytes': 5.7.0
@@ -4063,14 +4374,14 @@ snapshots:
typechain: 8.3.2(typescript@5.4.5)
typescript: 5.4.5
- '@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)':
+ '@typechain/hardhat@7.0.0(@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.4.5))(typescript@5.4.5))(ethers@5.7.2)(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5))(typechain@8.3.2(typescript@5.4.5))':
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.4.5)
+ '@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.5))(typescript@5.4.5)
ethers: 5.7.2
fs-extra: 9.1.0
- hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.5)
+ hardhat: 2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)
typechain: 8.3.2(typescript@5.4.5)
'@types/bn.js@4.11.6':
@@ -4147,7 +4458,7 @@ snapshots:
'@types/semver@7.5.0': {}
- '@typescript-eslint/eslint-plugin@7.10.0(@typescript-eslint/parser@7.10.0)(eslint@8.57.0)(typescript@5.4.5)':
+ '@typescript-eslint/eslint-plugin@7.10.0(@typescript-eslint/parser@7.10.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)':
dependencies:
'@eslint-community/regexpp': 4.10.0
'@typescript-eslint/parser': 7.10.0(eslint@8.57.0)(typescript@5.4.5)
@@ -4160,6 +4471,7 @@ snapshots:
ignore: 5.3.1
natural-compare: 1.4.0
ts-api-utils: 1.3.0(typescript@5.4.5)
+ optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
@@ -4172,6 +4484,7 @@ snapshots:
'@typescript-eslint/visitor-keys': 7.10.0
debug: 4.3.4(supports-color@8.1.1)
eslint: 8.57.0
+ optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
@@ -4188,6 +4501,7 @@ snapshots:
debug: 4.3.4(supports-color@8.1.1)
eslint: 8.57.0
ts-api-utils: 1.3.0(typescript@5.4.5)
+ optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
@@ -4204,6 +4518,7 @@ snapshots:
minimatch: 9.0.4
semver: 7.6.2
ts-api-utils: 1.3.0(typescript@5.4.5)
+ optionalDependencies:
typescript: 5.4.5
transitivePeerDependencies:
- supports-color
@@ -4226,6 +4541,8 @@ snapshots:
'@ungap/structured-clone@1.2.0': {}
+ '@yarnpkg/lockfile@1.1.0': {}
+
abi-to-sol@0.6.6:
dependencies:
'@truffle/abi-utils': 0.3.2
@@ -4328,8 +4645,24 @@ snapshots:
call-bind: 1.0.5
is-array-buffer: 3.0.2
+ array-buffer-byte-length@1.0.1:
+ dependencies:
+ call-bind: 1.0.7
+ is-array-buffer: 3.0.4
+ optional: true
+
array-union@2.1.0: {}
+ array.prototype.findlast@1.2.5:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+ es-errors: 1.3.0
+ es-object-atoms: 1.0.0
+ es-shim-unscopables: 1.0.2
+ optional: true
+
array.prototype.flat@1.3.2:
dependencies:
call-bind: 1.0.5
@@ -4347,6 +4680,18 @@ snapshots:
is-array-buffer: 3.0.2
is-shared-array-buffer: 1.0.2
+ arraybuffer.prototype.slice@1.0.3:
+ dependencies:
+ array-buffer-byte-length: 1.0.1
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ is-array-buffer: 3.0.4
+ is-shared-array-buffer: 1.0.3
+ optional: true
+
arrify@1.0.1: {}
assertion-error@1.1.0: {}
@@ -4359,6 +4704,11 @@ snapshots:
available-typed-arrays@1.0.5: {}
+ available-typed-arrays@1.0.7:
+ dependencies:
+ possible-typed-array-names: 1.0.0
+ optional: true
+
balanced-match@1.0.0: {}
base-x@3.0.9:
@@ -4473,6 +4823,15 @@ snapshots:
get-intrinsic: 1.2.2
set-function-length: 1.1.1
+ call-bind@1.0.7:
+ dependencies:
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ set-function-length: 1.2.2
+ optional: true
+
callsites@3.1.0: {}
camel-case@3.0.0:
@@ -4499,6 +4858,11 @@ snapshots:
dependencies:
nofilter: 3.1.0
+ cbor@9.0.2:
+ dependencies:
+ nofilter: 3.1.0
+ optional: true
+
chai-as-promised@7.1.1(chai@4.4.1):
dependencies:
chai: 4.4.1
@@ -4635,6 +4999,9 @@ snapshots:
commander@3.0.2: {}
+ compare-versions@6.1.1:
+ optional: true
+
concat-map@0.0.1: {}
config-chain@1.1.13:
@@ -4683,6 +5050,14 @@ snapshots:
shebang-command: 1.2.0
which: 1.3.1
+ cross-spawn@6.0.5:
+ dependencies:
+ nice-try: 1.0.5
+ path-key: 2.0.1
+ semver: 5.7.1
+ shebang-command: 1.2.0
+ which: 1.3.1
+
cross-spawn@7.0.3:
dependencies:
path-key: 3.1.1
@@ -4702,11 +5077,33 @@ snapshots:
csv-stringify: 5.6.5
stream-transform: 2.1.3
+ data-view-buffer@1.0.1:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-data-view: 1.0.1
+ optional: true
+
+ data-view-byte-length@1.0.1:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-data-view: 1.0.1
+ optional: true
+
+ data-view-byte-offset@1.0.0:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-data-view: 1.0.1
+ optional: true
+
dataloader@1.4.0: {}
debug@4.3.4(supports-color@8.1.1):
dependencies:
ms: 2.1.2
+ optionalDependencies:
supports-color: 8.1.1
decamelize-keys@1.1.1:
@@ -4747,6 +5144,13 @@ snapshots:
gopd: 1.0.1
has-property-descriptors: 1.0.0
+ define-data-property@1.1.4:
+ dependencies:
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ gopd: 1.0.1
+ optional: true
+
define-properties@1.2.1:
dependencies:
define-data-property: 1.1.1
@@ -4850,12 +5254,82 @@ snapshots:
unbox-primitive: 1.0.2
which-typed-array: 1.1.13
+ es-abstract@1.23.3:
+ dependencies:
+ array-buffer-byte-length: 1.0.1
+ arraybuffer.prototype.slice: 1.0.3
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ data-view-buffer: 1.0.1
+ data-view-byte-length: 1.0.1
+ data-view-byte-offset: 1.0.0
+ es-define-property: 1.0.0
+ es-errors: 1.3.0
+ es-object-atoms: 1.0.0
+ es-set-tostringtag: 2.0.3
+ es-to-primitive: 1.2.1
+ function.prototype.name: 1.1.6
+ get-intrinsic: 1.2.4
+ get-symbol-description: 1.0.2
+ globalthis: 1.0.3
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
+ has-proto: 1.0.3
+ has-symbols: 1.0.3
+ hasown: 2.0.2
+ internal-slot: 1.0.7
+ is-array-buffer: 3.0.4
+ is-callable: 1.2.7
+ is-data-view: 1.0.1
+ is-negative-zero: 2.0.3
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.3
+ is-string: 1.0.7
+ is-typed-array: 1.1.13
+ is-weakref: 1.0.2
+ object-inspect: 1.13.1
+ object-keys: 1.1.1
+ object.assign: 4.1.5
+ regexp.prototype.flags: 1.5.2
+ safe-array-concat: 1.1.2
+ safe-regex-test: 1.0.3
+ string.prototype.trim: 1.2.9
+ string.prototype.trimend: 1.0.8
+ string.prototype.trimstart: 1.0.8
+ typed-array-buffer: 1.0.2
+ typed-array-byte-length: 1.0.1
+ typed-array-byte-offset: 1.0.2
+ typed-array-length: 1.0.6
+ unbox-primitive: 1.0.2
+ which-typed-array: 1.1.15
+ optional: true
+
+ es-define-property@1.0.0:
+ dependencies:
+ get-intrinsic: 1.2.4
+ optional: true
+
+ es-errors@1.3.0:
+ optional: true
+
+ es-object-atoms@1.0.0:
+ dependencies:
+ es-errors: 1.3.0
+ optional: true
+
es-set-tostringtag@2.0.2:
dependencies:
get-intrinsic: 1.2.2
has-tostringtag: 1.0.0
hasown: 2.0.0
+ es-set-tostringtag@2.0.3:
+ dependencies:
+ get-intrinsic: 1.2.4
+ has-tostringtag: 1.0.2
+ hasown: 2.0.2
+ optional: true
+
es-shim-unscopables@1.0.2:
dependencies:
hasown: 2.0.0
@@ -4876,13 +5350,14 @@ snapshots:
dependencies:
eslint: 8.57.0
- eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.2.5):
+ eslint-plugin-prettier@5.1.3(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5):
dependencies:
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
+ optionalDependencies:
+ eslint-config-prettier: 9.1.0(eslint@8.57.0)
eslint-scope@7.2.2:
dependencies:
@@ -5120,6 +5595,10 @@ snapshots:
micromatch: 4.0.5
pkg-dir: 4.2.0
+ find-yarn-workspace-root@2.0.0:
+ dependencies:
+ micromatch: 4.0.5
+
flat-cache@3.2.0:
dependencies:
flatted: 3.3.1
@@ -5131,7 +5610,7 @@ snapshots:
flatted@3.3.1: {}
follow-redirects@1.15.6(debug@4.3.4):
- dependencies:
+ optionalDependencies:
debug: 4.3.4(supports-color@8.1.1)
for-each@0.3.3:
@@ -5196,6 +5675,15 @@ snapshots:
has-symbols: 1.0.3
hasown: 2.0.0
+ get-intrinsic@1.2.4:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ has-proto: 1.0.1
+ has-symbols: 1.0.3
+ hasown: 2.0.0
+ optional: true
+
get-stream@5.1.0:
dependencies:
pump: 3.0.0
@@ -5207,6 +5695,13 @@ snapshots:
call-bind: 1.0.5
get-intrinsic: 1.2.2
+ get-symbol-description@1.0.2:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ get-intrinsic: 1.2.4
+ optional: true
+
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -5295,11 +5790,11 @@ snapshots:
hard-rejection@2.1.0: {}
- hardhat-abi-exporter@2.10.1(hardhat@2.20.1):
+ hardhat-abi-exporter@2.10.1(hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)):
dependencies:
'@ethersproject/abi': 5.7.0
delete-empty: 3.0.0
- hardhat: 2.20.1(ts-node@10.9.2)(typescript@5.4.5)
+ hardhat: 2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5)
hardhat-ignore-warnings@0.2.11:
dependencies:
@@ -5307,7 +5802,7 @@ snapshots:
node-interval-tree: 2.1.2
solidity-comments: 0.0.2
- hardhat@2.20.1(ts-node@10.9.2)(typescript@5.4.5):
+ hardhat@2.20.1(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5))(typescript@5.4.5):
dependencies:
'@ethersproject/abi': 5.7.0
'@metamask/eth-sig-util': 4.0.1
@@ -5355,12 +5850,13 @@ snapshots:
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@20.12.12)(typescript@5.4.5)
tsort: 0.0.1
- typescript: 5.4.5
undici: 5.28.4
uuid: 8.3.2
ws: 7.5.9
+ optionalDependencies:
+ ts-node: 10.9.2(@types/node@20.12.12)(typescript@5.4.5)
+ typescript: 5.4.5
transitivePeerDependencies:
- bufferutil
- c-kzg
@@ -5377,14 +5873,27 @@ snapshots:
dependencies:
get-intrinsic: 1.2.2
+ has-property-descriptors@1.0.2:
+ dependencies:
+ es-define-property: 1.0.0
+ optional: true
+
has-proto@1.0.1: {}
+ has-proto@1.0.3:
+ optional: true
+
has-symbols@1.0.3: {}
has-tostringtag@1.0.0:
dependencies:
has-symbols: 1.0.3
+ has-tostringtag@1.0.2:
+ dependencies:
+ has-symbols: 1.0.3
+ optional: true
+
has@1.0.3:
dependencies:
function-bind: 1.1.2
@@ -5404,6 +5913,11 @@ snapshots:
dependencies:
function-bind: 1.1.2
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+ optional: true
+
he@1.2.0: {}
header-case@1.0.1:
@@ -5477,6 +5991,13 @@ snapshots:
hasown: 2.0.0
side-channel: 1.0.4
+ internal-slot@1.0.7:
+ dependencies:
+ es-errors: 1.3.0
+ hasown: 2.0.2
+ side-channel: 1.0.4
+ optional: true
+
io-ts@1.10.4:
dependencies:
fp-ts: 1.19.3
@@ -5487,6 +6008,12 @@ snapshots:
get-intrinsic: 1.2.2
is-typed-array: 1.1.12
+ is-array-buffer@3.0.4:
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+ optional: true
+
is-arrayish@0.2.1: {}
is-bigint@1.0.4:
@@ -5504,12 +6031,23 @@ snapshots:
is-callable@1.2.7: {}
+ is-ci@2.0.0:
+ dependencies:
+ ci-info: 2.0.0
+
is-core-module@2.10.0:
dependencies:
has: 1.0.3
+ is-data-view@1.0.1:
+ dependencies:
+ is-typed-array: 1.1.13
+ optional: true
+
is-date-object@1.0.2: {}
+ is-docker@2.2.1: {}
+
is-extglob@2.1.1: {}
is-fullwidth-code-point@3.0.0: {}
@@ -5526,6 +6064,9 @@ snapshots:
is-negative-zero@2.0.2: {}
+ is-negative-zero@2.0.3:
+ optional: true
+
is-number-object@1.0.7:
dependencies:
has-tostringtag: 1.0.0
@@ -5547,6 +6088,11 @@ snapshots:
dependencies:
call-bind: 1.0.5
+ is-shared-array-buffer@1.0.3:
+ dependencies:
+ call-bind: 1.0.7
+ optional: true
+
is-string@1.0.7:
dependencies:
has-tostringtag: 1.0.0
@@ -5563,6 +6109,11 @@ snapshots:
dependencies:
which-typed-array: 1.1.13
+ is-typed-array@1.1.13:
+ dependencies:
+ which-typed-array: 1.1.15
+ optional: true
+
is-unicode-supported@0.1.0: {}
is-upper-case@1.1.2:
@@ -5575,6 +6126,10 @@ snapshots:
is-windows@1.0.2: {}
+ is-wsl@2.2.0:
+ dependencies:
+ is-docker: 2.2.1
+
isarray@2.0.5: {}
isexe@2.0.0: {}
@@ -5641,6 +6196,10 @@ snapshots:
kind-of@6.0.3: {}
+ klaw-sync@6.0.0:
+ dependencies:
+ graceful-fs: 4.2.10
+
klaw@1.3.1:
optionalDependencies:
graceful-fs: 4.2.10
@@ -5839,6 +6398,8 @@ snapshots:
dependencies:
ansi-regex: 2.1.1
+ nice-try@1.0.5: {}
+
no-case@2.3.2:
dependencies:
lower-case: 1.1.4
@@ -5886,12 +6447,25 @@ snapshots:
has-symbols: 1.0.3
object-keys: 1.1.1
+ object.assign@4.1.5:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ has-symbols: 1.0.3
+ object-keys: 1.1.1
+ optional: true
+
obliterator@2.0.4: {}
once@1.4.0:
dependencies:
wrappy: 1.0.2
+ open@7.4.2:
+ dependencies:
+ is-docker: 2.2.1
+ is-wsl: 2.2.0
+
optionator@0.9.3:
dependencies:
'@aashutoshrathi/word-wrap': 1.2.6
@@ -5974,6 +6548,23 @@ snapshots:
camel-case: 3.0.0
upper-case-first: 1.1.2
+ patch-package@6.5.1:
+ dependencies:
+ '@yarnpkg/lockfile': 1.1.0
+ chalk: 4.1.2
+ cross-spawn: 6.0.5
+ find-yarn-workspace-root: 2.0.0
+ fs-extra: 9.1.0
+ 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
+ yaml: 1.10.2
+
path-case@2.1.1:
dependencies:
no-case: 2.3.2
@@ -5984,6 +6575,8 @@ snapshots:
path-is-absolute@1.0.1: {}
+ path-key@2.0.1: {}
+
path-key@3.1.1: {}
path-parse@1.0.7: {}
@@ -6012,6 +6605,9 @@ snapshots:
pluralize@8.0.0: {}
+ possible-typed-array-names@1.0.0:
+ optional: true
+
preferred-pm@3.1.3:
dependencies:
find-up: 5.0.0
@@ -6044,6 +6640,13 @@ snapshots:
prettier@3.2.5: {}
+ proper-lockfile@4.1.2:
+ dependencies:
+ graceful-fs: 4.2.10
+ retry: 0.12.0
+ signal-exit: 3.0.7
+ optional: true
+
proto-list@1.2.4: {}
pseudomap@1.0.2: {}
@@ -6124,6 +6727,14 @@ snapshots:
define-properties: 1.2.1
set-function-name: 2.0.1
+ regexp.prototype.flags@1.5.2:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-errors: 1.3.0
+ set-function-name: 2.0.1
+ optional: true
+
registry-auth-token@5.0.2:
dependencies:
'@pnpm/npm-conf': 2.2.2
@@ -6158,6 +6769,9 @@ snapshots:
dependencies:
lowercase-keys: 2.0.0
+ retry@0.12.0:
+ optional: true
+
reusify@1.0.4: {}
rimraf@2.7.1:
@@ -6192,6 +6806,14 @@ snapshots:
has-symbols: 1.0.3
isarray: 2.0.5
+ safe-array-concat@1.1.2:
+ dependencies:
+ call-bind: 1.0.7
+ get-intrinsic: 1.2.4
+ has-symbols: 1.0.3
+ isarray: 2.0.5
+ optional: true
+
safe-buffer@5.1.2: {}
safe-buffer@5.2.1: {}
@@ -6202,6 +6824,13 @@ snapshots:
get-intrinsic: 1.2.2
is-regex: 1.1.4
+ safe-regex-test@1.0.3:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-regex: 1.1.4
+ optional: true
+
safer-buffer@2.1.2: {}
scrypt-js@3.0.1: {}
@@ -6236,6 +6865,16 @@ snapshots:
gopd: 1.0.1
has-property-descriptors: 1.0.0
+ set-function-length@1.2.2:
+ dependencies:
+ define-data-property: 1.1.4
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+ get-intrinsic: 1.2.4
+ gopd: 1.0.1
+ has-property-descriptors: 1.0.2
+ optional: true
+
set-function-name@2.0.1:
dependencies:
define-data-property: 1.1.1
@@ -6273,6 +6912,8 @@ snapshots:
signal-exit@3.0.7: {}
+ slash@2.0.0: {}
+
slash@3.0.0: {}
slice-ansi@4.0.0:
@@ -6308,7 +6949,7 @@ snapshots:
transitivePeerDependencies:
- debug
- solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.3.1)(prettier@3.2.5):
+ solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.3.1(prettier@3.2.5))(prettier@3.2.5):
dependencies:
'@prettier/sync': 0.3.0(prettier@3.2.5)
prettier: 3.2.5
@@ -6338,6 +6979,11 @@ snapshots:
optionalDependencies:
prettier: 2.8.8
+ solidity-ast@0.4.56:
+ dependencies:
+ array.prototype.findlast: 1.2.5
+ optional: true
+
solidity-comments-darwin-arm64@0.0.2:
optional: true
@@ -6439,18 +7085,40 @@ snapshots:
define-properties: 1.2.1
es-abstract: 1.22.3
+ string.prototype.trim@1.2.9:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-abstract: 1.23.3
+ es-object-atoms: 1.0.0
+ optional: true
+
string.prototype.trimend@1.0.7:
dependencies:
call-bind: 1.0.5
define-properties: 1.2.1
es-abstract: 1.22.3
+ string.prototype.trimend@1.0.8:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-object-atoms: 1.0.0
+ optional: true
+
string.prototype.trimstart@1.0.7:
dependencies:
call-bind: 1.0.5
define-properties: 1.2.1
es-abstract: 1.22.3
+ string.prototype.trimstart@1.0.8:
+ dependencies:
+ call-bind: 1.0.7
+ define-properties: 1.2.1
+ es-object-atoms: 1.0.0
+ optional: true
+
string_decoder@1.3.0:
dependencies:
safe-buffer: 5.2.1
@@ -6628,6 +7296,13 @@ snapshots:
get-intrinsic: 1.2.2
is-typed-array: 1.1.12
+ typed-array-buffer@1.0.2:
+ dependencies:
+ call-bind: 1.0.7
+ es-errors: 1.3.0
+ is-typed-array: 1.1.13
+ optional: true
+
typed-array-byte-length@1.0.0:
dependencies:
call-bind: 1.0.5
@@ -6635,6 +7310,15 @@ snapshots:
has-proto: 1.0.1
is-typed-array: 1.1.12
+ typed-array-byte-length@1.0.1:
+ dependencies:
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+ optional: true
+
typed-array-byte-offset@1.0.0:
dependencies:
available-typed-arrays: 1.0.5
@@ -6643,12 +7327,32 @@ snapshots:
has-proto: 1.0.1
is-typed-array: 1.1.12
+ typed-array-byte-offset@1.0.2:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+ optional: true
+
typed-array-length@1.0.4:
dependencies:
call-bind: 1.0.5
for-each: 0.3.3
is-typed-array: 1.1.12
+ typed-array-length@1.0.6:
+ dependencies:
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-proto: 1.0.3
+ is-typed-array: 1.1.13
+ possible-typed-array-names: 1.0.0
+ optional: true
+
typescript@5.4.5: {}
typical@4.0.0: {}
@@ -6741,6 +7445,15 @@ snapshots:
gopd: 1.0.1
has-tostringtag: 1.0.0
+ which-typed-array@1.1.15:
+ dependencies:
+ available-typed-arrays: 1.0.7
+ call-bind: 1.0.7
+ for-each: 0.3.3
+ gopd: 1.0.1
+ has-tostringtag: 1.0.2
+ optional: true
+
which@1.3.1:
dependencies:
isexe: 2.0.0
@@ -6784,6 +7497,8 @@ snapshots:
yallist@2.1.2: {}
+ yaml@1.10.2: {}
+
yargs-parser@18.1.3:
dependencies:
camelcase: 5.3.1
diff --git a/contracts/remappings.txt b/contracts/remappings.txt
index 1428f50b316..ec64b1b2118 100644
--- a/contracts/remappings.txt
+++ b/contracts/remappings.txt
@@ -1,6 +1,7 @@
forge-std/=src/v0.8/vendor/forge-std/src/
@openzeppelin/=node_modules/@openzeppelin/
+@arbitrum/=node_modules/@arbitrum/
hardhat/=node_modules/hardhat/
@eth-optimism/=node_modules/@eth-optimism/
@scroll-tech/=node_modules/@scroll-tech/
diff --git a/contracts/scripts/ci/find_slither_report_diff.sh b/contracts/scripts/ci/find_slither_report_diff.sh
new file mode 100755
index 00000000000..d0b5238a1ac
--- /dev/null
+++ b/contracts/scripts/ci/find_slither_report_diff.sh
@@ -0,0 +1,94 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+if [[ "$#" -lt 4 ]]; then
+ >&2 echo "Generates a markdown file with diff in new issues detected by ChatGPT between two Slither reports."
+ >&2 echo "Usage: $0 [path-to-validation-prompt]"
+ exit 1
+fi
+
+if [[ -z "${OPEN_API_KEY+x}" ]]; then
+ >&2 echo "OPEN_API_KEY is not set."
+ exit 1
+fi
+
+first_report_path=$1
+second_report_path=$2
+new_issues_report_path=$3
+report_prompt_path=$4
+if [[ "$#" -eq 5 ]]; then
+ validation_prompt_path=$5
+else
+ validation_prompt_path=""
+fi
+
+first_report_content=$(cat "$first_report_path" | sed 's/"//g' | sed -E 's/\\+$//g' | sed -E 's/\\+ //g')
+second_report_content=$(cat "$second_report_path" | sed 's/"//g' | sed -E 's/\\+$//g' | sed -E 's/\\+ //g')
+openai_prompt=$(cat "$report_prompt_path" | sed 's/"/\\"/g' | sed -E 's/\\+$//g' | sed -E 's/\\+ //g')
+openai_model="gpt-4o-2024-05-13"
+openai_result=$(echo '{
+ "model": "'$openai_model'",
+ "temperature": 0.01,
+ "messages": [
+ {
+ "role": "system",
+ "content": "'$openai_prompt' \nreport1:\n```'$first_report_content'```\nreport2:\n```'$second_report_content'```"
+ }
+ ]
+}' | envsubst | curl https://api.openai.com/v1/chat/completions \
+ -w "%{http_code}" \
+ -o prompt_response.json \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer $OPEN_API_KEY" \
+ -d @-
+)
+
+# throw error openai_result when is not 200
+if [ "$openai_result" != '200' ]; then
+ echo "::error::OpenAI API call failed with status $openai_result: $(cat prompt_response.json)"
+ exit 1
+fi
+
+# replace lines starting with ' -' (1space) with ' -' (2spaces)
+response_content=$(cat prompt_response.json | jq -r '.choices[0].message.content')
+new_issues_report_content=$(echo "$response_content" | sed -e 's/^ -/ -/g')
+echo "$new_issues_report_content" > "$new_issues_report_path"
+
+if [[ -n "$validation_prompt_path" ]]; then
+ echo "::debug::Validating the diff report using the validation prompt"
+ openai_model="gpt-4-turbo-2024-04-09"
+ report_input=$(echo "$new_issues_report_content" | sed 's/"//g' | sed -E 's/\\+$//g' | sed -E 's/\\+ //g')
+ validation_prompt_content=$(cat "$validation_prompt_path" | sed 's/"/\\"/g' | sed -E 's/\\+$//g' | sed -E 's/\\+ //g')
+ validation_result=$(echo '{
+ "model": "'$openai_model'",
+ "temperature": 0.01,
+ "messages": [
+ {
+ "role": "system",
+ "content": "'$validation_prompt_content' \nreport1:\n```'$first_report_content'```\nreport2:\n```'$second_report_content'```\nnew_issues:\n```'$report_input'```"
+ }
+ ]
+ }' | envsubst | curl https://api.openai.com/v1/chat/completions \
+ -w "%{http_code}" \
+ -o prompt_validation_response.json \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer $OPEN_API_KEY" \
+ -d @-
+ )
+
+ # throw error openai_result when is not 200
+ if [ "$validation_result" != '200' ]; then
+ echo "::error::OpenAI API call failed with status $validation_result: $(cat prompt_validation_response.json)"
+ exit 1
+ fi
+
+ # replace lines starting with ' -' (1space) with ' -' (2spaces)
+ response_content=$(cat prompt_validation_response.json | jq -r '.choices[0].message.content')
+
+ echo "$response_content" | sed -e 's/^ -/ -/g' >> "$new_issues_report_path"
+ echo "" >> "$new_issues_report_path"
+ echo "*Confidence rating presented above is an automatic validation (self-check) of the differences between two reports generated by ChatGPT ${openai_model} model. It has a scale of 1 to 5, where 1 means that all new issues are missing and 5 that all new issues are present*." >> "$new_issues_report_path"
+ echo "" >> "$new_issues_report_path"
+ echo "*If confidence rating is low it's advised to look for differences manually by downloading Slither reports for base reference and current commit from job's artifacts*." >> "$new_issues_report_path"
+fi
diff --git a/contracts/scripts/ci/generate_slither_report.sh b/contracts/scripts/ci/generate_slither_report.sh
new file mode 100755
index 00000000000..bc876ae1182
--- /dev/null
+++ b/contracts/scripts/ci/generate_slither_report.sh
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+function check_chainlink_dir() {
+ local param_dir="chainlink"
+ current_dir=$(pwd)
+
+ current_base=$(basename "$current_dir")
+
+ if [[ "$current_base" != "$param_dir" ]]; then
+ >&2 echo "The script must be run from the root of $param_dir directory"
+ exit 1
+ fi
+}
+
+check_chainlink_dir
+
+if [ "$#" -lt 5 ]; then
+ >&2 echo "Generates Markdown Slither reports and saves them to a target directory."
+ >&2 echo "Usage: $0 [slither extra params]"
+ exit 1
+fi
+
+REPO_URL=$1
+CONFIG_FILE=$2
+SOURCE_DIR=$3
+FILES=${4// /} # Remove any spaces from the list of files
+TARGET_DIR=$5
+SLITHER_EXTRA_PARAMS=$6
+
+run_slither() {
+ local FILE=$1
+ local TARGET_DIR=$2
+
+ if [[ ! -f "$FILE" ]]; then
+ >&2 echo "::error:File not found: $FILE"
+ return 1
+ fi
+
+ set +e
+ source ./contracts/scripts/ci/select_solc_version.sh "$FILE"
+ if [[ $? -ne 0 ]]; then
+ >&2 echo "::error::Failed to select Solc version for $FILE"
+ return 1
+ fi
+
+ SLITHER_OUTPUT_FILE="$TARGET_DIR/$(basename "${FILE%.sol}")-slither-report.md"
+ if ! output=$(slither --config-file "$CONFIG_FILE" "$FILE" --checklist --markdown-root "$REPO_URL" --fail-none $SLITHER_EXTRA_PARAMS); then
+ >&2 echo "::warning::Slither failed for $FILE"
+ return 0
+ fi
+ set -e
+ output=$(echo "$output" | sed '/\*\*THIS CHECKLIST IS NOT COMPLETE\*\*. Use `--show-ignored-findings` to show all the results./d' | sed '/Summary/d')
+
+ echo "# Summary for $FILE" > "$SLITHER_OUTPUT_FILE"
+ echo "$output" >> "$SLITHER_OUTPUT_FILE"
+
+ if [[ -z "$output" ]]; then
+ echo "No issues found." >> "$SLITHER_OUTPUT_FILE"
+ fi
+}
+
+process_files() {
+ local SOURCE_DIR=$1
+ local TARGET_DIR=$2
+ local FILES=(${3//,/ }) # Split the comma-separated list into an array
+
+ mkdir -p "$TARGET_DIR"
+
+ for FILE in "${FILES[@]}"; do
+ FILE=${FILE//\"/}
+ run_slither "$SOURCE_DIR/$FILE" "$TARGET_DIR"
+ done
+}
+
+set +e
+process_files "$SOURCE_DIR" "$TARGET_DIR" "${FILES[@]}"
+
+if [[ $? -ne 0 ]]; then
+ >&2 echo "::warning::Failed to generate some Slither reports"
+ exit 0
+fi
+
+echo "Slither reports saved in $TARGET_DIR folder"
diff --git a/contracts/scripts/ci/generate_uml.sh b/contracts/scripts/ci/generate_uml.sh
new file mode 100755
index 00000000000..c71d0a1ac7d
--- /dev/null
+++ b/contracts/scripts/ci/generate_uml.sh
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+function check_chainlink_dir() {
+ local param_dir="chainlink"
+ current_dir=$(pwd)
+
+ current_base=$(basename "$current_dir")
+
+ if [[ "$current_base" != "$param_dir" ]]; then
+ >&2 echo "The script must be run from the root of $param_dir directory"
+ exit 1
+ fi
+}
+
+check_chainlink_dir
+
+if [ "$#" -lt 2 ]; then
+ >&2 echo "Generates UML diagrams for all contracts in a directory after flattening them to avoid call stack overflows."
+ >&2 echo "Usage: $0 [comma-separated list of files]"
+ exit 1
+fi
+
+SOURCE_DIR="$1"
+TARGET_DIR="$2"
+FILES=${3// /} # Remove any spaces from the list of files
+FAILED_FILES=()
+
+flatten_and_generate_uml() {
+ local FILE=$1
+ local TARGET_DIR=$2
+
+ set +e
+ FLATTENED_FILE="$TARGET_DIR/flattened_$(basename "$FILE")"
+ echo "::debug::Flattening $FILE to $FLATTENED_FILE"
+ forge flatten "$FILE" -o "$FLATTENED_FILE" --root contracts
+ if [[ $? -ne 0 ]]; then
+ >&2 echo "::error::Failed to flatten $FILE"
+ FAILED_FILES+=("$FILE")
+ return
+ fi
+
+ OUTPUT_FILE=${FLATTENED_FILE//"flattened_"/""}
+ OUTPUT_FILE_SVG="${OUTPUT_FILE%.sol}.svg"
+ echo "::debug::Generating SVG UML for $FLATTENED_FILE to $OUTPUT_FILE_SVG"
+ sol2uml "$FLATTENED_FILE" -o "$OUTPUT_FILE_SVG"
+ if [[ $? -ne 0 ]]; then
+ >&2 echo "::error::Failed to generate UML diagram in SVG format for $FILE"
+ FAILED_FILES+=("$FILE")
+ rm "$FLATTENED_FILE"
+ return
+ fi
+ OUTPUT_FILE_DOT="${OUTPUT_FILE%.sol}.dot"
+ echo "::debug::Generating DOT UML for $FLATTENED_FILE to $OUTPUT_FILE_DOT"
+ sol2uml "$FLATTENED_FILE" -o "$OUTPUT_FILE_DOT" -f dot
+ if [[ $? -ne 0 ]]; then
+ >&2 echo "::error::Failed to generate UML diagram in DOT format for $FILE"
+ FAILED_FILES+=("$FILE")
+ rm "$FLATTENED_FILE"
+ return
+ fi
+
+ rm "$FLATTENED_FILE"
+ set -e
+}
+
+process_all_files_in_directory() {
+ local SOURCE_DIR=$1
+ local TARGET_DIR=$2
+
+ mkdir -p "$TARGET_DIR"
+
+ find "$SOURCE_DIR" -type f -name '*.sol' | while read -r ITEM; do
+ flatten_and_generate_uml "$ITEM" "$TARGET_DIR"
+ done
+}
+
+process_selected_files() {
+ local SOURCE_DIR=$1
+ local TARGET_DIR=$2
+ local FILES=(${3//,/ }) # Split the comma-separated list into an array
+
+ mkdir -p "$TARGET_DIR"
+
+ for FILE in "${FILES[@]}"; do
+ FILE=${FILE//\"/}
+ MATCHES=($(find "$SOURCE_DIR" -type f -path "*/$FILE"))
+
+ if [[ ${#MATCHES[@]} -gt 1 ]]; then
+ >&2 echo "::error:: Multiple matches found for $FILE:"
+ for MATCH in "${MATCHES[@]}"; do
+ >&2 echo " $MATCH"
+ done
+ exit 1
+ elif [[ ${#MATCHES[@]} -eq 1 ]]; then
+ >&2 echo "::debug::File found: ${MATCHES[0]}"
+ flatten_and_generate_uml "${MATCHES[0]}" "$TARGET_DIR"
+ else
+ >&2 echo "::error::File $FILE does not exist within the source directory $SOURCE_DIR."
+ exit 1
+ fi
+ done
+}
+
+# if FILES is empty, process all files in the directory, otherwise process only the selected files
+if [[ -z "$FILES" ]]; then
+ process_all_files_in_directory "$SOURCE_DIR" "$TARGET_DIR"
+else
+ process_selected_files "$SOURCE_DIR" "$TARGET_DIR" "$FILES"
+fi
+
+if [[ "${#FAILED_FILES[@]}" -gt 0 ]]; then
+ >&2 echo ":error::Failed to generate UML diagrams for ${#FAILED_FILES[@]} files:"
+ for FILE in "${FAILED_FILES[@]}"; do
+ >&2 echo " $FILE"
+ echo "$FILE" >> "$TARGET_DIR/uml_generation_failures.txt"
+ done
+fi
+
+echo "UML diagrams saved in $TARGET_DIR folder"
diff --git a/contracts/scripts/ci/modify_remappings.sh b/contracts/scripts/ci/modify_remappings.sh
new file mode 100755
index 00000000000..e64ca369b0c
--- /dev/null
+++ b/contracts/scripts/ci/modify_remappings.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+if [ "$#" -ne 2 ]; then
+ >&2 echo "Usage: $0 "
+ exit 1
+fi
+
+DIR_PREFIX=$1
+REMAPPINGS_FILE=$2
+
+if [ ! -f "$REMAPPINGS_FILE" ]; then
+ >&2 echo "::error:: Remappings file '$REMAPPINGS_FILE' not found."
+ exit 1
+fi
+
+OUTPUT_FILE="remappings_modified.txt"
+
+while IFS= read -r line; do
+ if [[ "$line" =~ ^[^=]+= ]]; then
+ REMAPPED_PATH="${line#*=}"
+ MODIFIED_LINE="${line%=*}=${DIR_PREFIX}/${REMAPPED_PATH}"
+ echo "$MODIFIED_LINE" >> "$OUTPUT_FILE"
+ else
+ echo "$line" >> "$OUTPUT_FILE"
+ fi
+done < "$REMAPPINGS_FILE"
+
+echo "Modified remappings have been saved to: $OUTPUT_FILE"
diff --git a/contracts/scripts/ci/prompt-difference.md b/contracts/scripts/ci/prompt-difference.md
new file mode 100644
index 00000000000..b7603c97482
--- /dev/null
+++ b/contracts/scripts/ci/prompt-difference.md
@@ -0,0 +1,21 @@
+You are a helpful expert data engineer with expertise in Blockchain and Decentralized Oracle Networks.
+
+Given two reports generated by Slither - a Solidity static analysis tool - provided at the bottom of the reply, your task is to help create a report for your peers with new issues introduced in the second report in order to decrease noise resulting from irrelevant changes to the report, by focusing on a single topic: **New Issues**.
+
+First report is provided under Heading 2 (##) called `report1` and is surrounded by triple backticks (```) to indicate the beginning and end of the report.
+Second report is provided under Heading 2 (##) called `report2` and is surrounded by triple backticks (```) to indicate the beginning and end of the report.
+
+First report is report generated by Slither using default branch of the code repository. Second report is report generated by Slither using a feature branch of the code repository. You want to help your peers understand the impact of changes they introduced in the pull request on the codebase and whether they introduced any new issues.
+
+**New Issues**
+
+Provide a bullet point summary of new issues that were introduced in the second report. If a given issue is not present in first report, but is present in the second one, it is considered a new issue. If the count for given issue type is higher in the second report than in the first one, it is considered a new issue.
+For each issue include original description text from the report together with severity level, issue ID, line number and a link to problematic line in the code.
+Group the issues by their type, which is defined as Heading 2 (##).
+
+Output your response starting from**New Issues** in escaped, markdown text that can be sent as http body to API. Do not wrap output in code blocks.
+Extract the name of the file from the first line of the report and title the new report with it in a following way: "# Slither's new issues in: "
+
+Remember that it might be possible that second report does not introduce any new issues. In such case, provide an empty report.
+
+Format **New Issues** as Heading 2 using double sharp characters (##). Otherwise, do not include any another preamble and postamble to your answer.
diff --git a/contracts/scripts/ci/prompt-validation.md b/contracts/scripts/ci/prompt-validation.md
new file mode 100644
index 00000000000..5fcf08e1462
--- /dev/null
+++ b/contracts/scripts/ci/prompt-validation.md
@@ -0,0 +1,33 @@
+You are a helpful expert data engineer with expertise in Blockchain and Decentralized Oracle Networks.
+
+At the bottom of the reply you will find two reports generated by Slither - a Solidity static analysis tool - and another report that contains new issues found in the second report.
+Your task is to evaluate how well that new issues report shows all new issues mentioned in the second Slither report and assert its completeness.
+Rate your confidence in the completeness of the new issues report on a scale from 1 to 5, where 1 means it's missing all new issues and 5 means that all new issues are present.
+
+First report is provided under Heading 2 (##) called `report1` and is surrounded by triple backticks (```) to indicate the beginning and end of the report.
+Second report is provided under Heading 2 (##) called `report2` and is surrounded by triple backticks (```) to indicate the beginning and end of the report.
+New issues report is provided under Heading 2 (##) called `new_issues` and is surrounded by triple backticks (```) to indicate the beginning and end of the report.
+
+Use the following steps to evaluate the new issues report:
+* each report begins with a summary with types of issues found and number of issues found for each type, called "# Summary for "
+* group issues by type and count for each report and calculate the expected difference in number of issues for each type for each report
+* exclude all issue types, for which the count for is higher in the first report than in the second one
+* for each remaining issue type, compare the number of issues found in the new issues report with the expected difference
+* evaluate if the new issues report captures all new issues introduced in the second report
+
+Do not focus on:
+* the quality of the Slither reports themselves, but rather on whether all new issues from the second report are present in the new issues report
+* how well the new issues report is structured or written and how well it presents new issues
+
+It is crucial that you ignore all differences in the reports that are not related to new issues, such as resolved issues or issues, which count has decreased.
+
+If a given issue is not present in first report, but is present in the second one, it is considered a new issue. Similar behaviour is expected from the new issues report.
+If the count for given issue type is higher in the second report than in the first one, it is considered a new issue.
+
+Your report should include only a single section titled "Confidence level".
+Your evaluation of the completeness of the new issues report should be displayed as a Heading 3 using triple sharp characters (###). In a new line a brief explanation of the scale used, with minimum and maximum possible values.
+
+Remember that it might be possible that second report does not introduce any new issues. In such case, confidence rating should be 5.
+
+Output your response as escaped, markdown text that can be sent as http body to API. Do not wrap output in code blocks. Do not include any partial results or statistics regarding the number of new and resolved issues in any of the reports.
+Format **Confidence level** as Heading 2 using double sharp characters (##). Otherwise, do not include any another preamble and postamble to your answer.
diff --git a/contracts/scripts/ci/select_solc_version.sh b/contracts/scripts/ci/select_solc_version.sh
new file mode 100755
index 00000000000..cfa13de0f60
--- /dev/null
+++ b/contracts/scripts/ci/select_solc_version.sh
@@ -0,0 +1,118 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+function check_chainlink_dir() {
+ local param_dir="chainlink"
+ current_dir=$(pwd)
+
+ current_base=$(basename "$current_dir")
+
+ if [[ "$current_base" != "$param_dir" ]]; then
+ >&2 echo "::error::The script must be run from the root of $param_dir directory"
+ exit 1
+ fi
+}
+
+check_chainlink_dir
+
+FILE="$1"
+
+if [[ "$#" -lt 1 ]]; then
+ echo "Detects the Solidity version of a file and selects the appropriate Solc version."
+ echo "If the version is not installed, it will be installed and selected."
+ echo "Will prefer to use the version from Foundry profile if it satisfies the version in the file."
+ echo "Usage: $0 "
+ exit 1
+fi
+
+if [[ -z "$FILE" ]]; then
+ >&2 echo "::error:: File not provided."
+ exit 1
+fi
+
+extract_product() {
+ local path=$1
+
+ echo "$path" | awk -F'src/[^/]*/' '{print $2}' | cut -d'/' -f1
+}
+
+extract_pragma() {
+ local FILE=$1
+
+ if [[ -f "$FILE" ]]; then
+ SOLCVER="$(grep --no-filename '^pragma solidity' "$FILE" | cut -d' ' -f3)"
+ else
+ >&2 echo ":error::$FILE is not a file or it could not be found. Exiting."
+ return 1
+ fi
+ SOLCVER="$(echo "$SOLCVER" | sed 's/[^0-9\.^]//g')"
+ >&2 echo "::debug::Detected Solidity version in pragma: $SOLCVER"
+ echo "$SOLCVER"
+}
+
+echo "Detecting Solc version for $FILE"
+
+# Set FOUNDRY_PROFILE to the product name only if it is set; otherwise either already set value will be used or it will be empty
+PRODUCT=$(extract_product "$FILE")
+if [ -n "$PRODUCT" ]; then
+ FOUNDRY_PROFILE="$PRODUCT"
+fi
+SOLC_IN_PROFILE=$(forge config --json --root contracts | jq ".solc")
+SOLC_IN_PROFILE=$(echo "$SOLC_IN_PROFILE" | tr -d "'\"")
+echo "::debug::Detected Solidity version in profile: $SOLC_IN_PROFILE"
+
+set +e
+SOLCVER=$(extract_pragma "$FILE")
+
+if [[ $? -ne 0 ]]; then
+ >&2 echo "::error:: Failed to extract the Solidity version from $FILE."
+ return 1
+fi
+
+set -e
+
+SOLCVER=$(echo "$SOLCVER" | tr -d "'\"")
+
+if [[ "$SOLC_IN_PROFILE" != "null" && -n "$SOLCVER" ]]; then
+ set +e
+ COMPAT_SOLC_VERSION=$(npx semver "$SOLC_IN_PROFILE" -r "$SOLCVER")
+ exit_code=$?
+ set -e
+ if [[ $exit_code -eq 0 && -n "$COMPAT_SOLC_VERSION" ]]; then
+ echo "::debug::Version $SOLC_IN_PROFILE satisfies the constraint $SOLCVER"
+ SOLC_TO_USE="$SOLC_IN_PROFILE"
+ else
+ echo "::debug::Version $SOLC_IN_PROFILE does not satisfy the constraint $SOLCVER"
+ SOLC_TO_USE="$SOLCVER"
+ fi
+ elif [[ "$SOLC_IN_PROFILE" != "null" && -z "$SOLCVER" ]]; then
+ >&2 echo "::error::No version found in the Solidity file. Exiting"
+ return 1
+ elif [[ "$SOLC_IN_PROFILE" == "null" && -n "$SOLCVER" ]]; then
+ echo "::debug::Using the version from the file: $SOLCVER"
+ SOLC_TO_USE="$SOLCVER"
+ else
+ >&2 echo "::error::No version found in the profile or the Solidity file."
+ return 1
+fi
+
+echo "Will use $SOLC_TO_USE"
+SOLC_TO_USE=$(echo "$SOLC_TO_USE" | tr -d "'\"")
+SOLC_TO_USE="$(echo "$SOLC_TO_USE" | sed 's/[^0-9\.]//g')"
+
+INSTALLED_VERSIONS=$(solc-select versions)
+
+if echo "$INSTALLED_VERSIONS" | grep -q "$SOLC_TO_USE"; then
+ echo "::debug::Version $SOLCVER is already installed."
+ if echo "$INSTALLED_VERSIONS" | grep "$SOLC_TO_USE" | grep -q "current"; then
+ echo "::debug::Version $SOLCVER is already selected."
+ else
+ echo "::debug::Selecting $SOLC_TO_USE"
+ solc-select use "$SOLC_TO_USE"
+ fi
+else
+ echo "::debug::Version $SOLC_TO_USE is not installed."
+ solc-select install "$SOLC_TO_USE"
+ solc-select use "$SOLC_TO_USE"
+fi
diff --git a/contracts/scripts/generate-zksync-automation-master-interface-v2_3.ts b/contracts/scripts/generate-zksync-automation-master-interface-v2_3.ts
new file mode 100644
index 00000000000..1b91fd36361
--- /dev/null
+++ b/contracts/scripts/generate-zksync-automation-master-interface-v2_3.ts
@@ -0,0 +1,58 @@
+/**
+ * @description this script generates a master interface for interacting with the automation registry
+ * @notice run this script with pnpm ts-node ./scripts/generate-zksync-automation-master-interface-v2_3.ts
+ */
+import { ZKSyncAutomationRegistry2_3__factory as Registry } from '../typechain/factories/ZKSyncAutomationRegistry2_3__factory'
+import { ZKSyncAutomationRegistryLogicA2_3__factory as RegistryLogicA } from '../typechain/factories/ZKSyncAutomationRegistryLogicA2_3__factory'
+import { ZKSyncAutomationRegistryLogicB2_3__factory as RegistryLogicB } from '../typechain/factories/ZKSyncAutomationRegistryLogicB2_3__factory'
+import { ZKSyncAutomationRegistryLogicC2_3__factory as RegistryLogicC } from '../typechain/factories/ZKSyncAutomationRegistryLogicC2_3__factory'
+import { utils } from 'ethers'
+import fs from 'fs'
+import { exec } from 'child_process'
+
+const dest = 'src/v0.8/automation/interfaces/zksync'
+const srcDest = `${dest}/IZKSyncAutomationRegistryMaster2_3.sol`
+const tmpDest = `${dest}/tmp.txt`
+
+const combinedABI = []
+const abiSet = new Set()
+const abis = [
+ Registry.abi,
+ RegistryLogicA.abi,
+ RegistryLogicB.abi,
+ RegistryLogicC.abi,
+]
+
+for (const abi of abis) {
+ for (const entry of abi) {
+ const id = utils.id(JSON.stringify(entry))
+ if (!abiSet.has(id)) {
+ abiSet.add(id)
+ if (
+ entry.type === 'function' &&
+ (entry.name === 'checkUpkeep' ||
+ entry.name === 'checkCallback' ||
+ entry.name === 'simulatePerformUpkeep')
+ ) {
+ entry.stateMutability = 'view' // override stateMutability for check / callback / simulate functions
+ }
+ combinedABI.push(entry)
+ }
+ }
+}
+
+const checksum = utils.id(abis.join(''))
+
+fs.writeFileSync(`${tmpDest}`, JSON.stringify(combinedABI))
+
+const cmd = `
+cat ${tmpDest} | pnpm abi-to-sol --solidity-version ^0.8.4 --license MIT > ${srcDest} IZKSyncAutomationRegistryMaster2_3;
+echo "// solhint-disable \n// abi-checksum: ${checksum}" | cat - ${srcDest} > ${tmpDest} && mv ${tmpDest} ${srcDest};
+pnpm prettier --write ${srcDest};
+`
+
+exec(cmd)
+
+console.log(
+ 'generated new master interface for zksync automation registry v2_3',
+)
diff --git a/contracts/scripts/lcov_prune b/contracts/scripts/lcov_prune
new file mode 100755
index 00000000000..0f16715cb2e
--- /dev/null
+++ b/contracts/scripts/lcov_prune
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+if [ "$#" -ne 3 ]; then
+ >&2 echo "Usage: $0 "
+ exit 1
+fi
+
+set -e
+
+product_name=$1
+input_coverage_file=$2
+output_coverage_file=$3
+
+# src/v0.8/ccip/libraries/Internal.sol
+# src/v0.8/ccip/libraries/RateLimiter.sol
+# src/v0.8/ccip/libraries/USDPriceWith18Decimals.sol
+# src/v0.8/ccip/libraries/MerkleMultiProof.sol
+# src/v0.8/ccip/libraries/Pool.sol
+# excluded because Foundry doesn't support coverage on library files
+
+# BurnWithFromMintTokenPool is excluded because Forge doesn't seem to
+# register coverage, even though it is 100% covered.
+exclusion_list_ccip=(
+ "src/v0.8/ccip/ocr/OCR2Abstract.sol"
+ "src/v0.8/ccip/libraries/Internal.sol"
+ "src/v0.8/ccip/libraries/RateLimiter.sol"
+ "src/v0.8/ccip/libraries/USDPriceWith18Decimals.sol"
+ "src/v0.8/ccip/libraries/MerkleMultiProof.sol"
+ "src/v0.8/ccip/libraries/Pool.sol"
+ "src/v0.8/ConfirmedOwnerWithProposal.sol"
+ "src/v0.8/tests/MockV3Aggregator.sol"
+ "src/v0.8/ccip/applications/CCIPClientExample.sol"
+ "src/v0.8/ccip/pools/BurnWithFromMintTokenPool.sol"
+)
+
+exclusion_list_shared=(
+ "*/shared/*"
+)
+
+exclusion_list_common=(
+ "*/$product_name/test/*"
+ "*/vendor/*"
+)
+
+all_exclusions=()
+
+case "$product_name" in
+ "ccip")
+ all_exclusions+=("${exclusion_list_ccip[@]}")
+ ;;
+ "shared")
+ # No product-specific exclusions for shared
+ ;;
+ *)
+ ;;
+esac
+
+all_exclusions+=("${exclusion_list_common[@]}")
+
+if [ "$product_name" != "shared" ]; then
+ all_exclusions+=("${exclusion_list_shared[@]}")
+fi
+
+echo "Excluding the following files for product $product_name:"
+for exclusion in "${all_exclusions[@]}"; do
+ echo "$exclusion"
+done
+
+lcov_command="lcov --remove $input_coverage_file -o $output_coverage_file"
+
+for exclusion in "${all_exclusions[@]}"; do
+ lcov_command+=" \"$exclusion\""
+done
+
+lcov_command+=" --rc lcov_branch_coverage=1"
+
+eval $lcov_command
diff --git a/contracts/scripts/native_solc_compile_all b/contracts/scripts/native_solc_compile_all
index 542337a191a..6e9f17561dd 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 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 ccip liquiditymanager
do
$SCRIPTPATH/native_solc_compile_all_$product
done
diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation
index f144e4f7dc8..e189e78cb0f 100755
--- a/contracts/scripts/native_solc_compile_all_automation
+++ b/contracts/scripts/native_solc_compile_all_automation
@@ -93,7 +93,7 @@ compileContract automation/v2_2/AutomationUtils2_2.sol
compileContract automation/interfaces/v2_2/IAutomationRegistryMaster.sol
compileContract automation/chains/ArbitrumModule.sol
compileContract automation/chains/ChainModuleBase.sol
-compileContract automation/chains/OptimismModule.sol
+compileContract automation/chains/OptimismModuleV2.sol
compileContract automation/chains/ScrollModule.sol
compileContract automation/interfaces/IChainModule.sol
compileContract automation/interfaces/IAutomationV21PlusCommon.sol
@@ -108,4 +108,4 @@ compileContract automation/v2_3/AutomationUtils2_3.sol
compileContract automation/interfaces/v2_3/IAutomationRegistryMaster2_3.sol
compileContract automation/testhelpers/MockETHUSDAggregator.sol
-compileContract automation/test/v2_3/WETH9.sol
+compileContract automation/test/WETH9.sol
diff --git a/contracts/scripts/native_solc_compile_all_ccip b/contracts/scripts/native_solc_compile_all_ccip
new file mode 100755
index 00000000000..1dbb70502d6
--- /dev/null
+++ b/contracts/scripts/native_solc_compile_all_ccip
@@ -0,0 +1,97 @@
+#!/usr/bin/env bash
+
+set -e
+
+echo " ┌──────────────────────────────────────────────┐"
+echo " │ Compiling CCIP contracts... │"
+echo " └──────────────────────────────────────────────┘"
+
+SOLC_VERSION="0.8.24"
+OPTIMIZE_RUNS=26000
+OPTIMIZE_RUNS_OFFRAMP=18000
+OPTIMIZE_RUNS_ONRAMP=4100
+OPTIMIZE_RUNS_MULTI_OFFRAMP=2500
+
+
+SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; 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
+
+ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )"
+
+compileContract () {
+ local contract
+ contract=$(basename "$1" ".sol")
+
+ local optimize_runs=$OPTIMIZE_RUNS
+
+ case $1 in
+ "ccip/offRamp/EVM2EVMOffRamp.sol")
+ echo "OffRamp uses $OPTIMIZE_RUNS_OFFRAMP optimizer runs."
+ optimize_runs=$OPTIMIZE_RUNS_OFFRAMP
+ ;;
+ "ccip/offRamp/EVM2EVMMultiOffRamp.sol")
+ echo "MultiOffRamp uses $OPTIMIZE_RUNS_MULTI_OFFRAMP optimizer runs."
+ optimize_runs=$OPTIMIZE_RUNS_MULTI_OFFRAMP
+ ;;
+ "ccip/onRamp/EVM2EVMOnRamp.sol")
+ echo "OnRamp uses $OPTIMIZE_RUNS_ONRAMP optimizer runs."
+ optimize_runs=$OPTIMIZE_RUNS_ONRAMP
+ ;;
+ esac
+
+ solc --overwrite --optimize --optimize-runs $optimize_runs --metadata-hash none \
+ -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \
+ --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8 \
+ --evm-version paris \
+ "$ROOT"/contracts/src/v0.8/"$1"
+}
+
+
+# Solc produces and overwrites intermediary contracts.
+# Contracts should be ordered in reverse-import-complexity-order to minimize overwrite risks.
+compileContract ccip/offRamp/EVM2EVMOffRamp.sol
+compileContract ccip/offRamp/EVM2EVMMultiOffRamp.sol
+compileContract ccip/applications/PingPongDemo.sol
+compileContract ccip/applications/SelfFundedPingPong.sol
+compileContract ccip/applications/EtherSenderReceiver.sol
+compileContract ccip/onRamp/EVM2EVMMultiOnRamp.sol
+compileContract ccip/onRamp/EVM2EVMOnRamp.sol
+compileContract ccip/CommitStore.sol
+compileContract ccip/MultiAggregateRateLimiter.sol
+compileContract ccip/Router.sol
+compileContract ccip/PriceRegistry.sol
+compileContract ccip/pools/LockReleaseTokenPool.sol
+compileContract ccip/pools/BurnMintTokenPool.sol
+compileContract ccip/pools/BurnFromMintTokenPool.sol
+compileContract ccip/pools/BurnWithFromMintTokenPool.sol
+compileContract ccip/pools/LockReleaseTokenPoolAndProxy.sol
+compileContract ccip/pools/BurnMintTokenPoolAndProxy.sol
+compileContract ccip/pools/TokenPool.sol
+compileContract shared/token/ERC677/BurnMintERC677.sol
+compileContract ccip/RMN.sol
+compileContract ccip/ARMProxy.sol
+compileContract ccip/tokenAdminRegistry/TokenAdminRegistry.sol
+compileContract ccip/tokenAdminRegistry/RegistryModuleOwnerCustom.sol
+compileContract ccip/capability/CCIPConfig.sol
+compileContract ccip/capability/interfaces/IOCR3ConfigEncoder.sol
+compileContract ccip/NonceManager.sol
+
+# Test helpers
+compileContract ccip/test/helpers/BurnMintERC677Helper.sol
+compileContract ccip/test/helpers/CommitStoreHelper.sol
+compileContract ccip/test/helpers/MessageHasher.sol
+compileContract ccip/test/helpers/ReportCodec.sol
+compileContract ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol
+compileContract ccip/test/helpers/MultiOCR3Helper.sol
+compileContract ccip/test/mocks/MockRMN1_0.sol
+compileContract ccip/test/mocks/MockE2EUSDCTokenMessenger.sol
+compileContract ccip/test/mocks/MockE2EUSDCTransmitter.sol
+compileContract ccip/test/WETH9.sol
+
+# Customer contracts
+compileContract ccip/pools/USDC/USDCTokenPool.sol
+
+compileContract tests/MockV3Aggregator.sol
diff --git a/contracts/scripts/native_solc_compile_all_liquiditymanager b/contracts/scripts/native_solc_compile_all_liquiditymanager
new file mode 100755
index 00000000000..a29f041c77b
--- /dev/null
+++ b/contracts/scripts/native_solc_compile_all_liquiditymanager
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+
+set -e
+
+echo " ┌──────────────────────────────────────────────┐"
+echo " │ Compiling LiquidityManager contracts... │"
+echo " └──────────────────────────────────────────────┘"
+
+SOLC_VERSION="0.8.24"
+OPTIMIZE_RUNS=1000000
+
+
+SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; 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
+
+ROOT="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; cd ../../ && pwd -P )"
+
+compileContract () {
+ local contract
+ contract=$(basename "$1" ".sol")
+
+ solc @arbitrum/="$ROOT"/contracts/node_modules/@arbitrum/ \
+ @eth-optimism/="$ROOT"/contracts/node_modules/@eth-optimism/ \
+ @openzeppelin/="$ROOT"/contracts/node_modules/@openzeppelin/ \
+ --overwrite --optimize --optimize-runs $OPTIMIZE_RUNS --metadata-hash none \
+ -o "$ROOT"/contracts/solc/v$SOLC_VERSION/"$contract" \
+ --abi --bin --allow-paths "$ROOT"/contracts/src/v0.8,"$ROOT"/contracts/node_modules \
+ --evm-version paris \
+ "$ROOT"/contracts/src/v0.8/"$1"
+}
+
+
+# Liquidity Management
+compileContract liquiditymanager/LiquidityManager.sol
+compileContract liquiditymanager/bridge-adapters/ArbitrumL1BridgeAdapter.sol
+compileContract liquiditymanager/bridge-adapters/ArbitrumL2BridgeAdapter.sol
+compileContract liquiditymanager/bridge-adapters/OptimismL1BridgeAdapter.sol
+compileContract liquiditymanager/bridge-adapters/OptimismL2BridgeAdapter.sol
+compileContract liquiditymanager/test/mocks/NoOpOCR3.sol
+compileContract liquiditymanager/test/mocks/MockBridgeAdapter.sol
+compileContract liquiditymanager/test/helpers/ReportEncoder.sol
+
+# Arbitrum helpers
+compileContract liquiditymanager/interfaces/arbitrum/IArbSys.sol
+compileContract liquiditymanager/interfaces/arbitrum/INodeInterface.sol
+compileContract liquiditymanager/interfaces/arbitrum/IL2ArbitrumGateway.sol
+compileContract liquiditymanager/interfaces/arbitrum/IL2ArbitrumMessenger.sol
+compileContract liquiditymanager/interfaces/arbitrum/IArbRollupCore.sol
+compileContract liquiditymanager/interfaces/arbitrum/IArbitrumL1GatewayRouter.sol
+compileContract liquiditymanager/interfaces/arbitrum/IArbitrumInbox.sol
+compileContract liquiditymanager/interfaces/arbitrum/IArbitrumGatewayRouter.sol
+compileContract liquiditymanager/interfaces/arbitrum/IArbitrumTokenGateway.sol
+compileContract liquiditymanager/interfaces/arbitrum/IAbstractArbitrumTokenGateway.sol
+
+# Optimism helpers
+compileContract liquiditymanager/interfaces/optimism/IOptimismPortal.sol
+compileContract liquiditymanager/interfaces/optimism/IOptimismL2OutputOracle.sol
+compileContract liquiditymanager/interfaces/optimism/IOptimismL2ToL1MessagePasser.sol
+compileContract liquiditymanager/interfaces/optimism/IOptimismCrossDomainMessenger.sol
+compileContract liquiditymanager/interfaces/optimism/IOptimismPortal2.sol
+compileContract liquiditymanager/interfaces/optimism/IOptimismDisputeGameFactory.sol
+compileContract liquiditymanager/interfaces/optimism/IOptimismStandardBridge.sol
+compileContract liquiditymanager/interfaces/optimism/IOptimismL1StandardBridge.sol
+compileContract liquiditymanager/encoders/OptimismL1BridgeAdapterEncoder.sol
diff --git a/contracts/scripts/native_solc_compile_all_llo-feeds b/contracts/scripts/native_solc_compile_all_llo-feeds
index eb17f93b0de..f0224d962cc 100755
--- a/contracts/scripts/native_solc_compile_all_llo-feeds
+++ b/contracts/scripts/native_solc_compile_all_llo-feeds
@@ -28,15 +28,19 @@ compileContract () {
"$ROOT"/contracts/src/v0.8/"$1"
}
-compileContract llo-feeds/Verifier.sol
-compileContract llo-feeds/VerifierProxy.sol
-compileContract llo-feeds/FeeManager.sol
-compileContract llo-feeds/RewardManager.sol
+compileContract llo-feeds/v0.3.0/Verifier.sol
+compileContract llo-feeds/v0.3.0/VerifierProxy.sol
+compileContract llo-feeds/v0.3.0/FeeManager.sol
+compileContract llo-feeds/v0.3.0/RewardManager.sol
+compileContract llo-feeds/v0.4.0/DestinationVerifier.sol
+compileContract llo-feeds/v0.4.0/DestinationVerifierProxy.sol
+compileContract llo-feeds/v0.4.0/DestinationFeeManager.sol
+compileContract llo-feeds/v0.4.0/DestinationRewardManager.sol
# Test | Mocks
-compileContract llo-feeds/test/mocks/ErroredVerifier.sol
-compileContract llo-feeds/test/mocks/ExposedVerifier.sol
+compileContract llo-feeds/v0.3.0/test/mocks/ErroredVerifier.sol
+compileContract llo-feeds/v0.3.0/test/mocks/ExposedVerifier.sol
# LLO
compileContract llo-feeds/dev/ChannelConfigStore.sol
diff --git a/contracts/src/v0.8/automation/ZKSyncAutomationForwarder.sol b/contracts/src/v0.8/automation/ZKSyncAutomationForwarder.sol
new file mode 100644
index 00000000000..fd6eb3dee99
--- /dev/null
+++ b/contracts/src/v0.8/automation/ZKSyncAutomationForwarder.sol
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.16;
+
+import {IAutomationRegistryConsumer} from "./interfaces/IAutomationRegistryConsumer.sol";
+import {GAS_BOUND_CALLER, IGasBoundCaller} from "./interfaces/zksync/IGasBoundCaller.sol";
+
+uint256 constant PERFORM_GAS_CUSHION = 50_000;
+
+/**
+ * @title ZKSyncAutomationForwarder is a relayer that sits between the registry and the customer's target contract
+ * @dev The purpose of the forwarder is to give customers a consistent address to authorize against,
+ * which stays consistent between migrations. The Forwarder also exposes the registry address, so that users who
+ * want to programmatically interact with the registry (ie top up funds) can do so.
+ */
+contract ZKSyncAutomationForwarder {
+ error InvalidCaller(address);
+
+ /// @notice the user's target contract address
+ address private immutable i_target;
+
+ /// @notice the shared logic address
+ address private immutable i_logic;
+
+ IAutomationRegistryConsumer private s_registry;
+
+ constructor(address target, address registry, address logic) {
+ s_registry = IAutomationRegistryConsumer(registry);
+ i_target = target;
+ i_logic = logic;
+ }
+
+ /**
+ * @notice forward is called by the registry and forwards the call to the target
+ * @param gasAmount is the amount of gas to use in the call
+ * @param data is the 4 bytes function selector + arbitrary function data
+ * @return success indicating whether the target call succeeded or failed
+ * @return gasUsed the total gas used from this forwarding call
+ */
+ function forward(uint256 gasAmount, bytes memory data) external returns (bool success, uint256 gasUsed) {
+ if (msg.sender != address(s_registry)) revert InvalidCaller(msg.sender);
+
+ uint256 g1 = gasleft();
+ address target = i_target;
+
+ assembly {
+ let g := gas()
+ // Compute g -= PERFORM_GAS_CUSHION and check for underflow
+ if lt(g, PERFORM_GAS_CUSHION) {
+ revert(0, 0)
+ }
+ g := sub(g, PERFORM_GAS_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)
+ }
+ }
+
+ bytes memory returnData;
+ // solhint-disable-next-line avoid-low-level-calls
+ (success, returnData) = GAS_BOUND_CALLER.delegatecall{gas: gasAmount}(
+ abi.encodeWithSelector(IGasBoundCaller.gasBoundCall.selector, target, gasAmount, data)
+ );
+ uint256 pubdataGasSpent;
+ if (success) {
+ (, pubdataGasSpent) = abi.decode(returnData, (bytes, uint256));
+ }
+ gasUsed = g1 - gasleft() + pubdataGasSpent;
+ return (success, gasUsed);
+ }
+
+ function getTarget() external view returns (address) {
+ return i_target;
+ }
+
+ // solhint-disable-next-line no-complex-fallback
+ fallback() external payable {
+ // copy to memory for assembly access
+ address logic = i_logic;
+ // copied directly from OZ's Proxy contract
+ assembly {
+ // Copy msg.data. We take full control of memory in this inline assembly
+ // block because it will not return to Solidity code. We overwrite the
+ // Solidity scratch pad at memory position 0.
+ calldatacopy(0, 0, calldatasize())
+
+ // out and outsize are 0 because we don't know the size yet.
+ let result := delegatecall(gas(), logic, 0, calldatasize(), 0, 0)
+
+ // Copy the returned data.
+ returndatacopy(0, 0, returndatasize())
+
+ switch result
+ // delegatecall returns 0 on error.
+ case 0 {
+ revert(0, returndatasize())
+ }
+ default {
+ return(0, returndatasize())
+ }
+ }
+ }
+}
diff --git a/contracts/src/v0.8/automation/chains/ArbitrumModule.sol b/contracts/src/v0.8/automation/chains/ArbitrumModule.sol
index e27a0809b7e..2ad6fdddc8c 100644
--- a/contracts/src/v0.8/automation/chains/ArbitrumModule.sol
+++ b/contracts/src/v0.8/automation/chains/ArbitrumModule.sol
@@ -31,7 +31,7 @@ contract ArbitrumModule is ChainModuleBase {
return ARB_SYS.arbBlockNumber();
}
- function getCurrentL1Fee() external view override returns (uint256) {
+ function getCurrentL1Fee(uint256) external view override returns (uint256) {
return ARB_GAS.getCurrentTxL1GasFees();
}
diff --git a/contracts/src/v0.8/automation/chains/ChainModuleBase.sol b/contracts/src/v0.8/automation/chains/ChainModuleBase.sol
index e9b082063bb..c595dbd6408 100644
--- a/contracts/src/v0.8/automation/chains/ChainModuleBase.sol
+++ b/contracts/src/v0.8/automation/chains/ChainModuleBase.sol
@@ -18,11 +18,11 @@ contract ChainModuleBase is IChainModule {
return blockhash(n);
}
- function getCurrentL1Fee() external view virtual returns (uint256) {
+ function getCurrentL1Fee(uint256) external view virtual returns (uint256 l1Fee) {
return 0;
}
- function getMaxL1Fee(uint256) external view virtual returns (uint256) {
+ function getMaxL1Fee(uint256) external view virtual returns (uint256 maxL1Fee) {
return 0;
}
diff --git a/contracts/src/v0.8/automation/chains/OptimismModule.sol b/contracts/src/v0.8/automation/chains/OptimismModule.sol
index 91c1c0ed968..7a464294963 100644
--- a/contracts/src/v0.8/automation/chains/OptimismModule.sol
+++ b/contracts/src/v0.8/automation/chains/OptimismModule.sol
@@ -4,6 +4,10 @@ pragma solidity 0.8.19;
import {OVM_GasPriceOracle} from "../../vendor/@eth-optimism/contracts/v0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol";
import {ChainModuleBase} from "./ChainModuleBase.sol";
+/**
+ * @notice This contract is deprecated. Please use OptimismModuleV2 which utilizes the most recent offerings from OP
+ * and can estimate L1 fee with much lower cost.
+ */
contract OptimismModule is ChainModuleBase {
/// @dev OP_L1_DATA_FEE_PADDING includes 80 bytes for L1 data padding for Optimism and BASE
bytes private constant OP_L1_DATA_FEE_PADDING =
@@ -16,11 +20,22 @@ contract OptimismModule is ChainModuleBase {
uint256 private constant FIXED_GAS_OVERHEAD = 60_000;
uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 270;
- function getCurrentL1Fee() external view override returns (uint256) {
- return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(msg.data, OP_L1_DATA_FEE_PADDING));
+ // @dev This will be updated to use the new function introduced by OP team
+ function getCurrentL1Fee(uint256 dataSize) external view override returns (uint256) {
+ return _getL1Fee(dataSize);
}
function getMaxL1Fee(uint256 dataSize) external view override returns (uint256) {
+ return _getL1Fee(dataSize);
+ }
+
+ /* @notice this function provides an estimation for L1 fee incurred by calldata of a certain size
+ * @dev this function uses the getL1Fee function in OP gas price oracle. it estimates the exact L1 fee but it costs
+ * a lot of gas to call.
+ * @param dataSize the size of calldata
+ * @return l1Fee the L1 fee
+ */
+ function _getL1Fee(uint256 dataSize) internal view returns (uint256) {
// fee is 4 per 0 byte, 16 per non-zero byte. Worst case we can have all non zero-bytes.
// Instead of setting bytes to non-zero, we initialize 'new bytes' of length 4*dataSize to cover for zero bytes.
bytes memory txCallData = new bytes(4 * dataSize);
diff --git a/contracts/src/v0.8/automation/chains/OptimismModuleV2.sol b/contracts/src/v0.8/automation/chains/OptimismModuleV2.sol
new file mode 100644
index 00000000000..772b66cdf99
--- /dev/null
+++ b/contracts/src/v0.8/automation/chains/OptimismModuleV2.sol
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.19;
+
+import {GasPriceOracle as OVM_GasPriceOracle} from "../../vendor/@eth-optimism/contracts-bedrock/v0.17.3/src/L2/GasPriceOracle.sol";
+import {ChainModuleBase} from "./ChainModuleBase.sol";
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
+
+/**
+ * @notice OptimismModuleV2 provides a cost-efficient way to get L1 fee on OP stack.
+ * After EIP-4844 is implemented in OP stack, the new OP upgrade includes a new function getL1FeeUpperBound to estimate
+ * the upper bound of current transaction's L1 fee.
+ */
+contract OptimismModuleV2 is ChainModuleBase, ConfirmedOwner {
+ error InvalidL1FeeCoefficient(uint8 coefficient);
+ event L1FeeCoefficientSet(uint8 coefficient);
+
+ /// @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);
+
+ /// @dev L1 fee coefficient is used to account for the impact of data compression on the l1 fee
+ /// getL1FeeUpperBound returns the upper bound of l1 fee so this configurable coefficient will help
+ /// charge a predefined percentage of the upper bound.
+ uint8 private s_l1FeeCoefficient = 100;
+ uint256 private constant FIXED_GAS_OVERHEAD = 28_000;
+ uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 0;
+
+ constructor() ConfirmedOwner(msg.sender) {}
+
+ function getCurrentL1Fee(uint256 dataSize) external view override returns (uint256) {
+ return (s_l1FeeCoefficient * _getL1Fee(dataSize)) / 100;
+ }
+
+ function getMaxL1Fee(uint256 dataSize) external view override returns (uint256) {
+ return _getL1Fee(dataSize);
+ }
+
+ /* @notice this function provides an estimation for L1 fee incurred by calldata of a certain size
+ * @dev this function uses the newly provided getL1FeeUpperBound function in OP gas price oracle. this helps
+ * estimate L1 fee with much lower cost
+ * @param dataSize the size of calldata
+ * @return l1Fee the L1 fee
+ */
+ function _getL1Fee(uint256 dataSize) internal view returns (uint256) {
+ return OVM_GASPRICEORACLE.getL1FeeUpperBound(dataSize);
+ }
+
+ function getGasOverhead()
+ external
+ pure
+ override
+ returns (uint256 chainModuleFixedOverhead, uint256 chainModulePerByteOverhead)
+ {
+ return (FIXED_GAS_OVERHEAD, PER_CALLDATA_BYTE_GAS_OVERHEAD);
+ }
+
+ /* @notice this function sets a new coefficient for L1 fee estimation.
+ * @dev this function can only be invoked by contract owner
+ * @param coefficient the new coefficient
+ */
+ function setL1FeeCalculation(uint8 coefficient) external onlyOwner {
+ if (coefficient > 100) {
+ revert InvalidL1FeeCoefficient(coefficient);
+ }
+
+ s_l1FeeCoefficient = coefficient;
+
+ emit L1FeeCoefficientSet(coefficient);
+ }
+
+ /* @notice this function returns the s_l1FeeCoefficient
+ * @return coefficient the current s_l1FeeCoefficient in effect
+ */
+ function getL1FeeCoefficient() public view returns (uint256 coefficient) {
+ return s_l1FeeCoefficient;
+ }
+}
diff --git a/contracts/src/v0.8/automation/chains/ScrollModule.sol b/contracts/src/v0.8/automation/chains/ScrollModule.sol
index 1e41ed3805f..30fdc908d49 100644
--- a/contracts/src/v0.8/automation/chains/ScrollModule.sol
+++ b/contracts/src/v0.8/automation/chains/ScrollModule.sol
@@ -3,8 +3,12 @@ pragma solidity 0.8.19;
import {IScrollL1GasPriceOracle} from "../../vendor/@scroll-tech/contracts/src/L2/predeploys/IScrollL1GasPriceOracle.sol";
import {ChainModuleBase} from "./ChainModuleBase.sol";
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
+
+contract ScrollModule is ChainModuleBase, ConfirmedOwner {
+ error InvalidL1FeeCoefficient(uint8 coefficient);
+ event L1FeeCoefficientSet(uint8 coefficient);
-contract ScrollModule is ChainModuleBase {
/// @dev SCROLL_L1_FEE_DATA_PADDING includes 140 bytes for L1 data padding for Scroll
/// @dev according to testing, this padding allows automation registry to properly estimates L1 data fee with 3-5% buffer
/// @dev this MAY NOT work for a different product and this may get out of date if transmit function is changed
@@ -15,14 +19,26 @@ contract ScrollModule is ChainModuleBase {
address private constant SCROLL_ORACLE_ADDR = 0x5300000000000000000000000000000000000002;
IScrollL1GasPriceOracle private constant SCROLL_ORACLE = IScrollL1GasPriceOracle(SCROLL_ORACLE_ADDR);
+ /// @dev L1 fee coefficient can be applied to reduce possibly inflated gas cost
+ uint8 private s_l1FeeCoefficient = 100;
uint256 private constant FIXED_GAS_OVERHEAD = 45_000;
uint256 private constant PER_CALLDATA_BYTE_GAS_OVERHEAD = 170;
- function getCurrentL1Fee() external view override returns (uint256) {
- return SCROLL_ORACLE.getL1Fee(bytes.concat(msg.data, SCROLL_L1_FEE_DATA_PADDING));
+ constructor() ConfirmedOwner(msg.sender) {}
+
+ function getCurrentL1Fee(uint256 dataSize) external view override returns (uint256) {
+ return (s_l1FeeCoefficient * _getL1Fee(dataSize)) / 100;
}
function getMaxL1Fee(uint256 dataSize) external view override returns (uint256) {
+ return _getL1Fee(dataSize);
+ }
+
+ /* @notice this function provides an estimation for L1 fee incurred by calldata of a certain size
+ * @param dataSize the size of calldata
+ * @return l1Fee the L1 fee
+ */
+ function _getL1Fee(uint256 dataSize) internal view returns (uint256 l1Fee) {
// fee is 4 per 0 byte, 16 per non-zero byte. Worst case we can have all non zero-bytes.
// Instead of setting bytes to non-zero, we initialize 'new bytes' of length 4*dataSize to cover for zero bytes.
// this is the same as OP.
@@ -38,4 +54,25 @@ contract ScrollModule is ChainModuleBase {
{
return (FIXED_GAS_OVERHEAD, PER_CALLDATA_BYTE_GAS_OVERHEAD);
}
+
+ /* @notice this function sets a new coefficient for L1 fee estimation.
+ * @dev this function can only be invoked by contract owner
+ * @param coefficient the new coefficient
+ */
+ function setL1FeeCalculation(uint8 coefficient) external onlyOwner {
+ if (coefficient > 100) {
+ revert InvalidL1FeeCoefficient(coefficient);
+ }
+
+ s_l1FeeCoefficient = coefficient;
+
+ emit L1FeeCoefficientSet(coefficient);
+ }
+
+ /* @notice this function returns the s_l1FeeCoefficient
+ * @return coefficient the current s_l1FeeCoefficient in effect
+ */
+ function getL1FeeCoefficient() public view returns (uint256 coefficient) {
+ return s_l1FeeCoefficient;
+ }
}
diff --git a/contracts/src/v0.8/automation/interfaces/IChainModule.sol b/contracts/src/v0.8/automation/interfaces/IChainModule.sol
index e3a4b32c9b1..15e84f79848 100644
--- a/contracts/src/v0.8/automation/interfaces/IChainModule.sol
+++ b/contracts/src/v0.8/automation/interfaces/IChainModule.sol
@@ -2,26 +2,39 @@
pragma solidity ^0.8.0;
interface IChainModule {
- // retrieve the native block number of a chain. e.g. L2 block number on Arbitrum
- function blockNumber() external view returns (uint256);
+ /* @notice this function provides the block number of current chain.
+ * @dev certain chains have its own function to retrieve block number, e.g. Arbitrum
+ * @return blockNumber the block number of the current chain.
+ */
+ function blockNumber() external view returns (uint256 blockNumber);
- // retrieve the native block hash of a chain.
- function blockHash(uint256) external view returns (bytes32);
+ /* @notice this function provides the block hash of a block number.
+ * @dev this function can usually look back 256 blocks at most, unless otherwise specified
+ * @param blockNumber the block number
+ * @return blockHash the block hash of the input block number
+ */
+ function blockHash(uint256 blockNumber) external view returns (bytes32 blockHash);
- // retrieve the L1 data fee for a L2 transaction. it should return 0 for L1 chains and
- // L2 chains which don't have L1 fee component. it uses msg.data to estimate L1 data so
- // it must be used with a transaction. Return value in wei.
- function getCurrentL1Fee() external view returns (uint256);
+ /* @notice this function provides the L1 fee of current transaction.
+ * @dev retrieve the L1 data fee for a L2 transaction. it should return 0 for L1 chains. it should
+ * return 0 for L2 chains if they don't have L1 fee component.
+ * @param dataSize the calldata size of the current transaction
+ * @return l1Fee the L1 fee in wei incurred by calldata of this data size
+ */
+ function getCurrentL1Fee(uint256 dataSize) external view returns (uint256 l1Fee);
- // retrieve the L1 data fee for a L2 simulation. it should return 0 for L1 chains and
- // L2 chains which don't have L1 fee component. Return value in wei.
- function getMaxL1Fee(uint256 dataSize) external view returns (uint256);
+ /* @notice this function provides the max possible L1 fee of current transaction.
+ * @dev retrieve the max possible L1 data fee for a L2 transaction. it should return 0 for L1 chains. it should
+ * return 0 for L2 chains if they don't have L1 fee component.
+ * @param dataSize the calldata size of the current transaction
+ * @return maxL1Fee the max possible L1 fee in wei incurred by calldata of this data size
+ */
+ function getMaxL1Fee(uint256 dataSize) external view returns (uint256 maxL1Fee);
- // Returns an upper bound on execution gas cost for one invocation of blockNumber(),
- // one invocation of blockHash() and one invocation of getCurrentL1Fee().
- // Returns two values, first value indicates a fixed cost and the second value is
- // the cost per msg.data byte (As some chain module's getCurrentL1Fee execution cost
- // scales with calldata size)
+ /* @notice this function provides the overheads of calling this chain module.
+ * @return chainModuleFixedOverhead the fixed overhead incurred by calling this chain module
+ * @return chainModulePerByteOverhead the fixed overhead per byte incurred by calling this chain module with calldata
+ */
function getGasOverhead()
external
view
diff --git a/contracts/src/v0.8/automation/interfaces/zksync/IGasBoundCaller.sol b/contracts/src/v0.8/automation/interfaces/zksync/IGasBoundCaller.sol
new file mode 100644
index 00000000000..9edb541f9aa
--- /dev/null
+++ b/contracts/src/v0.8/automation/interfaces/zksync/IGasBoundCaller.sol
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.19;
+
+address constant GAS_BOUND_CALLER = address(0xc706EC7dfA5D4Dc87f29f859094165E8290530f5);
+
+interface IGasBoundCaller {
+ function gasBoundCall(address _to, uint256 _maxTotalGas, bytes calldata _data) external payable;
+}
diff --git a/contracts/src/v0.8/automation/interfaces/zksync/ISystemContext.sol b/contracts/src/v0.8/automation/interfaces/zksync/ISystemContext.sol
new file mode 100644
index 00000000000..c8f480065c4
--- /dev/null
+++ b/contracts/src/v0.8/automation/interfaces/zksync/ISystemContext.sol
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.19;
+
+ISystemContext constant SYSTEM_CONTEXT_CONTRACT = ISystemContext(address(0x800b));
+
+interface ISystemContext {
+ function gasPrice() external view returns (uint256);
+ function gasPerPubdataByte() external view returns (uint256 gasPerPubdataByte);
+ function getCurrentPubdataSpent() external view returns (uint256 currentPubdataSpent);
+}
diff --git a/contracts/src/v0.8/automation/interfaces/zksync/IZKSyncAutomationRegistryMaster2_3.sol b/contracts/src/v0.8/automation/interfaces/zksync/IZKSyncAutomationRegistryMaster2_3.sol
new file mode 100644
index 00000000000..26b8a7d5c55
--- /dev/null
+++ b/contracts/src/v0.8/automation/interfaces/zksync/IZKSyncAutomationRegistryMaster2_3.sol
@@ -0,0 +1,441 @@
+// solhint-disable
+// abi-checksum: 0x5857a77a981fcb60dbdac0700e68420cbe544249b20d9326d51c5ef8584c5dd7
+// SPDX-License-Identifier: MIT
+// !! THIS FILE WAS AUTOGENERATED BY abi-to-sol v0.6.6. SEE SOURCE BELOW. !!
+pragma solidity ^0.8.4;
+
+interface IZKSyncAutomationRegistryMaster2_3 {
+ error ArrayHasNoEntries();
+ error CannotCancel();
+ error CheckDataExceedsLimit();
+ error ConfigDigestMismatch();
+ error DuplicateEntry();
+ error DuplicateSigners();
+ error GasLimitCanOnlyIncrease();
+ error GasLimitOutsideRange();
+ error IncorrectNumberOfFaultyOracles();
+ error IncorrectNumberOfSignatures();
+ 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 MigrationNotPermitted();
+ error MustSettleOffchain();
+ error MustSettleOnchain();
+ error NotAContract();
+ error OnlyActiveSigners();
+ error OnlyActiveTransmitters();
+ error OnlyCallableByAdmin();
+ error OnlyCallableByLINKToken();
+ error OnlyCallableByOwnerOrAdmin();
+ error OnlyCallableByOwnerOrRegistrar();
+ error OnlyCallableByPayee();
+ error OnlyCallableByProposedAdmin();
+ error OnlyCallableByProposedPayee();
+ error OnlyCallableByUpkeepPrivilegeManager();
+ error OnlyFinanceAdmin();
+ error OnlyPausedUpkeep();
+ error OnlySimulatedBackend();
+ error OnlyUnpausedUpkeep();
+ error ParameterLengthError();
+ error ReentrantCall();
+ error RegistryPaused();
+ error RepeatedSigner();
+ error RepeatedTransmitter();
+ error TargetCheckReverted(bytes reason);
+ error TooManyOracles();
+ error TranscoderNotSet();
+ error TransferFailed();
+ error UpkeepAlreadyExists();
+ error UpkeepCancelled();
+ error UpkeepNotCanceled();
+ error UpkeepNotNeeded();
+ error ValueNotChanged();
+ error ZeroAddressNotAllowed();
+ event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig);
+ event BillingConfigOverridden(uint256 indexed id, ZKSyncAutomationRegistryBase2_3.BillingOverrides overrides);
+ event BillingConfigOverrideRemoved(uint256 indexed id);
+ event BillingConfigSet(address indexed token, ZKSyncAutomationRegistryBase2_3.BillingConfig config);
+ event CancelledUpkeepReport(uint256 indexed id, bytes trigger);
+ event ChainSpecificModuleUpdated(address newModule);
+ event ConfigSet(
+ uint32 previousConfigBlockNumber,
+ bytes32 configDigest,
+ uint64 configCount,
+ address[] signers,
+ address[] transmitters,
+ uint8 f,
+ bytes onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes offchainConfig
+ );
+ 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 OwnershipTransferRequested(address indexed from, address indexed to);
+ event OwnershipTransferred(address indexed from, address indexed to);
+ event Paused(address account);
+ event PayeesUpdated(address[] transmitters, address[] payees);
+ event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to);
+ event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to);
+ event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee);
+ event ReorgedUpkeepReport(uint256 indexed id, bytes trigger);
+ event StaleUpkeepReport(uint256 indexed id, bytes trigger);
+ event Transmitted(bytes32 configDigest, uint32 epoch);
+ event Unpaused(address account);
+ event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to);
+ event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to);
+ event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight);
+ event UpkeepCharged(uint256 indexed id, ZKSyncAutomationRegistryBase2_3.PaymentReceipt receipt);
+ event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData);
+ event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
+ event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination);
+ event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig);
+ event UpkeepPaused(uint256 indexed id);
+ event UpkeepPerformed(
+ uint256 indexed id,
+ bool indexed success,
+ uint96 totalPayment,
+ uint256 gasUsed,
+ uint256 gasOverhead,
+ bytes trigger
+ );
+ event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig);
+ event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom);
+ event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin);
+ event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig);
+ event UpkeepUnpaused(uint256 indexed id);
+ fallback() external payable;
+ function acceptOwnership() external;
+ 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);
+ function owner() external view returns (address);
+ function setConfig(
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfigBytes,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) external;
+ function setConfigTypeSafe(
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ ZKSyncAutomationRegistryBase2_3.OnchainConfig memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig,
+ address[] memory billingTokens,
+ ZKSyncAutomationRegistryBase2_3.BillingConfig[] memory billingConfigs
+ ) external;
+ function transferOwnership(address to) external;
+ function transmit(
+ bytes32[3] memory reportContext,
+ bytes memory rawReport,
+ bytes32[] memory rs,
+ bytes32[] memory ss,
+ bytes32 rawVs
+ ) external;
+ function typeAndVersion() external view returns (string memory);
+
+ function cancelUpkeep(uint256 id) external;
+ function migrateUpkeeps(uint256[] memory ids, address destination) external;
+ function onTokenTransfer(address sender, uint256 amount, bytes memory data) 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 addFunds(uint256 id, uint96 amount) external payable;
+ function checkCallback(
+ uint256 id,
+ bytes[] memory values,
+ bytes memory extraData
+ ) external view returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed);
+ function checkUpkeep(
+ uint256 id,
+ bytes memory triggerData
+ )
+ external
+ view
+ returns (
+ bool upkeepNeeded,
+ bytes memory performData,
+ uint8 upkeepFailureReason,
+ uint256 gasUsed,
+ uint256 gasLimit,
+ uint256 fastGasWei,
+ uint256 linkUSD
+ );
+ function checkUpkeep(
+ uint256 id
+ )
+ external
+ view
+ returns (
+ bool upkeepNeeded,
+ bytes memory performData,
+ uint8 upkeepFailureReason,
+ uint256 gasUsed,
+ uint256 gasLimit,
+ uint256 fastGasWei,
+ uint256 linkUSD
+ );
+ function executeCallback(
+ uint256 id,
+ bytes memory payload
+ ) external returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed);
+ function pauseUpkeep(uint256 id) external;
+ function removeBillingOverrides(uint256 id) external;
+ function setBillingOverrides(
+ uint256 id,
+ ZKSyncAutomationRegistryBase2_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 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 getAvailableERC20ForPayment(address billingToken) external view returns (uint256);
+ function getBalance(uint256 id) external view returns (uint96 balance);
+ function getBillingConfig(
+ address billingToken
+ ) external view returns (ZKSyncAutomationRegistryBase2_3.BillingConfig memory);
+ function getBillingOverrides(
+ uint256 upkeepID
+ ) external view returns (ZKSyncAutomationRegistryBase2_3.BillingOverrides memory);
+ function getBillingOverridesEnabled(uint256 upkeepID) external view returns (bool);
+ function getBillingToken(uint256 upkeepID) external view returns (address);
+ function getBillingTokenConfig(
+ address token
+ ) external view returns (ZKSyncAutomationRegistryBase2_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 (ZKSyncAutomationRegistryBase2_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 (ZKSyncAutomationRegistryBase2_3.HotVars memory);
+ function getLinkAddress() external view returns (address);
+ function getLinkUSDFeedAddress() external view returns (address);
+ function getLogGasOverhead() external pure returns (uint256);
+ 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 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 (
+ IAutomationV21PlusCommon.StateLegacy memory state,
+ IAutomationV21PlusCommon.OnchainConfigLegacy memory config,
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f
+ );
+ function getStorage() external view returns (ZKSyncAutomationRegistryBase2_3.Storage memory);
+ function getTransmitterInfo(
+ address query
+ ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee);
+ function getTransmittersWithPayees()
+ external
+ view
+ returns (ZKSyncAutomationRegistryBase2_3.TransmitterPayeeInfo[] memory);
+ function getTriggerType(uint256 upkeepId) external pure returns (uint8);
+ 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 (int256);
+ function pause() external;
+ function setAdminPrivilegeConfig(address admin, bytes memory newPrivilegeConfig) external;
+ function setPayees(address[] memory payees) external;
+ function setPeerRegistryMigrationPermission(address peer, uint8 permission) 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 unpause() external;
+ function upkeepVersion() external pure returns (uint8);
+ function withdrawPayment(address from, address to) external;
+}
+
+interface ZKSyncAutomationRegistryBase2_3 {
+ struct BillingOverrides {
+ uint32 gasFeePPB;
+ uint24 flatFeeMilliCents;
+ }
+
+ struct BillingConfig {
+ uint32 gasFeePPB;
+ uint24 flatFeeMilliCents;
+ address priceFeed;
+ uint8 decimals;
+ uint256 fallbackPrice;
+ uint96 minSpend;
+ }
+
+ struct PaymentReceipt {
+ uint96 gasChargeInBillingToken;
+ uint96 premiumInBillingToken;
+ uint96 gasReimbursementInJuels;
+ uint96 premiumInJuels;
+ address billingToken;
+ uint96 linkUSD;
+ uint96 nativeUSD;
+ uint96 billingUSD;
+ }
+
+ struct OnchainConfig {
+ uint32 checkGasLimit;
+ 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[] registrars;
+ 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 TransmitterPayeeInfo {
+ address transmitterAddress;
+ address payeeAddress;
+ }
+}
+
+interface IAutomationV21PlusCommon {
+ struct StateLegacy {
+ uint32 nonce;
+ uint96 ownerLinkBalance;
+ uint256 expectedLinkBalance;
+ uint96 totalPremium;
+ uint256 numUpkeeps;
+ uint32 configCount;
+ uint32 latestConfigBlockNumber;
+ bytes32 latestConfigDigest;
+ uint32 latestEpoch;
+ bool paused;
+ }
+
+ struct OnchainConfigLegacy {
+ uint32 paymentPremiumPPB;
+ uint32 flatFeeMicroLink;
+ 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;
+ }
+
+ struct UpkeepInfoLegacy {
+ address target;
+ uint32 performGas;
+ bytes checkData;
+ uint96 balance;
+ address admin;
+ uint64 maxValidBlocknumber;
+ uint32 lastPerformedBlockNumber;
+ uint96 amountSpent;
+ bool paused;
+ bytes offchainConfig;
+ }
+}
+
+// THIS FILE WAS AUTOGENERATED FROM THE FOLLOWING ABI JSON:
+/*
+[{"inputs":[{"internalType":"contract ZKSyncAutomationRegistryLogicA2_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 ZKSyncAutomationRegistryBase2_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 IERC20Metadata","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":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"indexed":false,"internalType":"struct ZKSyncAutomationRegistryBase2_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"},{"components":[{"internalType":"uint96","name":"gasChargeInBillingToken","type":"uint96"},{"internalType":"uint96","name":"premiumInBillingToken","type":"uint96"},{"internalType":"uint96","name":"gasReimbursementInJuels","type":"uint96"},{"internalType":"uint96","name":"premiumInJuels","type":"uint96"},{"internalType":"contract IERC20Metadata","name":"billingToken","type":"address"},{"internalType":"uint96","name":"linkUSD","type":"uint96"},{"internalType":"uint96","name":"nativeUSD","type":"uint96"},{"internalType":"uint96","name":"billingUSD","type":"uint96"}],"indexed":false,"internalType":"struct ZKSyncAutomationRegistryBase2_3.PaymentReceipt","name":"receipt","type":"tuple"}],"name":"UpkeepCharged","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":[],"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 ZKSyncAutomationRegistryBase2_3.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"},{"internalType":"contract IERC20Metadata[]","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":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct ZKSyncAutomationRegistryBase2_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 ZKSyncAutomationRegistryLogicB2_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":"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":"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 ZKSyncAutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"contract IERC20Metadata","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 ZKSyncAutomationRegistryLogicC2_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":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"payable","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 ZKSyncAutomationRegistryBase2_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 ZKSyncAutomationRegistryBase2_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 ZKSyncAutomationRegistryBase2_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 ZKSyncAutomationRegistryBase2_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 ZKSyncAutomationRegistryBase2_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 IERC20Metadata","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 ZKSyncAutomationRegistryBase2_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":"contract IERC20Metadata","name":"billingToken","type":"address"}],"name":"getAvailableERC20ForPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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 IERC20Metadata","name":"billingToken","type":"address"}],"name":"getBillingConfig","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"},{"internalType":"contract AggregatorV3Interface","name":"priceFeed","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct ZKSyncAutomationRegistryBase2_3.BillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingOverrides","outputs":[{"components":[{"internalType":"uint32","name":"gasFeePPB","type":"uint32"},{"internalType":"uint24","name":"flatFeeMilliCents","type":"uint24"}],"internalType":"struct ZKSyncAutomationRegistryBase2_3.BillingOverrides","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingOverridesEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepID","type":"uint256"}],"name":"getBillingToken","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Metadata","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":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"fallbackPrice","type":"uint256"},{"internalType":"uint96","name":"minSpend","type":"uint96"}],"internalType":"struct ZKSyncAutomationRegistryBase2_3.BillingConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBillingTokens","outputs":[{"internalType":"contract IERC20Metadata[]","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 ZKSyncAutomationRegistryBase2_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 ZKSyncAutomationRegistryBase2_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 ZKSyncAutomationRegistryBase2_3.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"contract IERC20Metadata","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 ZKSyncAutomationRegistryBase2_3.PayoutMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum ZKSyncAutomationRegistryBase2_3.MigrationPermission","name":"","type":"uint8"}],"stateMutability":"view","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 IERC20Metadata","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 ZKSyncAutomationRegistryBase2_3.Storage","name":"","type":"tuple"}],"stateMutability":"view","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":[],"name":"getTransmittersWithPayees","outputs":[{"components":[{"internalType":"address","name":"transmitterAddress","type":"address"},{"internalType":"address","name":"payeeAddress","type":"address"}],"internalType":"struct ZKSyncAutomationRegistryBase2_3.TransmitterPayeeInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"upkeepId","type":"uint256"}],"name":"getTriggerType","outputs":[{"internalType":"enum ZKSyncAutomationRegistryBase2_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 ZKSyncAutomationRegistryBase2_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 IERC20Metadata","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/test/v2_3/WETH9.sol b/contracts/src/v0.8/automation/test/WETH9.sol
similarity index 100%
rename from contracts/src/v0.8/automation/test/v2_3/WETH9.sol
rename to contracts/src/v0.8/automation/test/WETH9.sol
diff --git a/contracts/src/v0.8/automation/test/v2_3/AutomationRegistry2_3.t.sol b/contracts/src/v0.8/automation/test/v2_3/AutomationRegistry2_3.t.sol
index dbc0c203c07..41aabf1bbe2 100644
--- a/contracts/src/v0.8/automation/test/v2_3/AutomationRegistry2_3.t.sol
+++ b/contracts/src/v0.8/automation/test/v2_3/AutomationRegistry2_3.t.sol
@@ -22,11 +22,11 @@ contract SetUp is BaseTest {
AutomationRegistryBase2_3.OnchainConfig internal config;
bytes internal constant offchainConfigBytes = abi.encode(1234, ZERO_ADDRESS);
- uint256 linkUpkeepID;
- uint256 linkUpkeepID2; // 2 upkeeps use the same billing token (LINK) to test migration scenario
- uint256 usdUpkeepID18; // 1 upkeep uses ERC20 token with 18 decimals
- uint256 usdUpkeepID6; // 1 upkeep uses ERC20 token with 6 decimals
- uint256 nativeUpkeepID;
+ uint256 internal linkUpkeepID;
+ uint256 internal linkUpkeepID2; // 2 upkeeps use the same billing token (LINK) to test migration scenario
+ uint256 internal usdUpkeepID18; // 1 upkeep uses ERC20 token with 18 decimals
+ uint256 internal usdUpkeepID6; // 1 upkeep uses ERC20 token with 6 decimals
+ uint256 internal nativeUpkeepID;
function setUp() public virtual override {
super.setUp();
@@ -790,6 +790,7 @@ contract SetConfig is SetUp {
}
function testSetConfigOnTransmittersAndPayees() public {
+ registry.setPayees(PAYEES);
AutomationRegistryBase2_3.TransmitterPayeeInfo[] memory transmitterPayeeInfos = registry
.getTransmittersWithPayees();
assertEq(transmitterPayeeInfos.length, TRANSMITTERS.length);
@@ -975,6 +976,7 @@ contract NOPsSettlement is SetUp {
function testSettleNOPsOffchainSuccess() public {
// deploy and configure a registry with OFF_CHAIN payout
(Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+ registry.setPayees(PAYEES);
uint256[] memory payments = new uint256[](TRANSMITTERS.length);
for (uint256 i = 0; i < TRANSMITTERS.length; i++) {
@@ -991,6 +993,7 @@ contract NOPsSettlement is SetUp {
function testSettleNOPsOffchainSuccessWithERC20MultiSteps() public {
// deploy and configure a registry with OFF_CHAIN payout
(Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+ registry.setPayees(PAYEES);
// register an upkeep and add funds
uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", "");
@@ -1186,6 +1189,7 @@ contract NOPsSettlement is SetUp {
function testSinglePerformAndNodesCanWithdrawOnchain() public {
// deploy and configure a registry with OFF_CHAIN payout
(Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+ registry.setPayees(PAYEES);
// register an upkeep and add funds
uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", "");
@@ -1224,6 +1228,7 @@ contract NOPsSettlement is SetUp {
function testMultiplePerformsAndNodesCanWithdrawOnchain() public {
// deploy and configure a registry with OFF_CHAIN payout
(Registry registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+ registry.setPayees(PAYEES);
// register an upkeep and add funds
uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", "");
@@ -1977,3 +1982,772 @@ contract MigrateReceive is SetUp {
vm.stopPrank();
}
}
+
+contract Pause is SetUp {
+ function test_RevertsWhen_CalledByNonOwner() external {
+ vm.expectRevert(bytes("Only callable by owner"));
+ vm.prank(STRANGER);
+ registry.pause();
+ }
+
+ function test_CalledByOwner_success() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+
+ (IAutomationV21PlusCommon.StateLegacy memory state, , , , ) = registry.getState();
+ assertTrue(state.paused);
+ }
+
+ function test_revertsWhen_transmitInPausedRegistry() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+
+ _transmitAndExpectRevert(usdUpkeepID18, registry, Registry.RegistryPaused.selector);
+ }
+}
+
+contract Unpause is SetUp {
+ function test_RevertsWhen_CalledByNonOwner() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+
+ vm.expectRevert(bytes("Only callable by owner"));
+ vm.startPrank(STRANGER);
+ registry.unpause();
+ }
+
+ function test_CalledByOwner_success() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+ (IAutomationV21PlusCommon.StateLegacy memory state1, , , , ) = registry.getState();
+ assertTrue(state1.paused);
+
+ registry.unpause();
+ (IAutomationV21PlusCommon.StateLegacy memory state2, , , , ) = registry.getState();
+ assertFalse(state2.paused);
+ }
+}
+
+contract CancelUpkeep is SetUp {
+ event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight);
+
+ function test_RevertsWhen_IdIsInvalid_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ vm.expectRevert(Registry.CannotCancel.selector);
+ registry.cancelUpkeep(1111111);
+ }
+
+ function test_RevertsWhen_IdIsInvalid_CalledByOwner() external {
+ vm.startPrank(registry.owner());
+ vm.expectRevert(Registry.CannotCancel.selector);
+ registry.cancelUpkeep(1111111);
+ }
+
+ function test_RevertsWhen_NotCalledByOwnerOrAdmin() external {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(Registry.OnlyCallableByOwnerOrAdmin.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceledByAdmin_CalledByOwner() external {
+ uint256 bn = block.number;
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.startPrank(registry.owner());
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceledByOwner_CalledByAdmin() external {
+ uint256 bn = block.number;
+ vm.startPrank(registry.owner());
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.startPrank(UPKEEP_ADMIN);
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceledByAdmin_CalledByAdmin() external {
+ uint256 bn = block.number;
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceledByOwner_CalledByOwner() external {
+ uint256 bn = block.number;
+ vm.startPrank(registry.owner());
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_CancelUpkeep_SetMaxValidBlockNumber_CalledByAdmin() external {
+ uint256 bn = block.number;
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ uint256 maxValidBlocknumber = uint256(registry.getUpkeep(linkUpkeepID).maxValidBlocknumber);
+
+ // 50 is the cancellation delay
+ assertEq(bn + 50, maxValidBlocknumber);
+ }
+
+ function test_CancelUpkeep_SetMaxValidBlockNumber_CalledByOwner() external {
+ uint256 bn = block.number;
+ vm.startPrank(registry.owner());
+ registry.cancelUpkeep(linkUpkeepID);
+
+ uint256 maxValidBlocknumber = uint256(registry.getUpkeep(linkUpkeepID).maxValidBlocknumber);
+
+ // cancellation by registry owner is immediate and no cancellation delay is applied
+ assertEq(bn, maxValidBlocknumber);
+ }
+
+ function test_CancelUpkeep_EmitEvent_CalledByAdmin() external {
+ uint256 bn = block.number;
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepCanceled(linkUpkeepID, uint64(bn + 50));
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_CancelUpkeep_EmitEvent_CalledByOwner() external {
+ uint256 bn = block.number;
+ vm.startPrank(registry.owner());
+
+ vm.expectEmit();
+ emit UpkeepCanceled(linkUpkeepID, uint64(bn));
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+}
+
+contract SetPeerRegistryMigrationPermission is SetUp {
+ function test_SetPeerRegistryMigrationPermission_CalledByOwner() external {
+ address peer = randomAddress();
+ vm.startPrank(registry.owner());
+
+ uint8 permission = registry.getPeerRegistryMigrationPermission(peer);
+ assertEq(0, permission);
+
+ registry.setPeerRegistryMigrationPermission(peer, 1);
+ permission = registry.getPeerRegistryMigrationPermission(peer);
+ assertEq(1, permission);
+
+ registry.setPeerRegistryMigrationPermission(peer, 2);
+ permission = registry.getPeerRegistryMigrationPermission(peer);
+ assertEq(2, permission);
+
+ registry.setPeerRegistryMigrationPermission(peer, 0);
+ permission = registry.getPeerRegistryMigrationPermission(peer);
+ assertEq(0, permission);
+ }
+
+ function test_RevertsWhen_InvalidPermission_CalledByOwner() external {
+ address peer = randomAddress();
+ vm.startPrank(registry.owner());
+
+ vm.expectRevert();
+ registry.setPeerRegistryMigrationPermission(peer, 100);
+ }
+
+ function test_RevertsWhen_CalledByNonOwner() external {
+ address peer = randomAddress();
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(bytes("Only callable by owner"));
+ registry.setPeerRegistryMigrationPermission(peer, 1);
+ }
+}
+
+contract SetUpkeepPrivilegeConfig is SetUp {
+ function test_RevertsWhen_CalledByNonManager() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByUpkeepPrivilegeManager.selector);
+ registry.setUpkeepPrivilegeConfig(linkUpkeepID, hex"1233");
+ }
+
+ function test_UpkeepHasEmptyConfig() external {
+ bytes memory cfg = registry.getUpkeepPrivilegeConfig(linkUpkeepID);
+ assertEq(cfg, bytes(""));
+ }
+
+ function test_SetUpkeepPrivilegeConfig_CalledByManager() external {
+ vm.startPrank(PRIVILEGE_MANAGER);
+
+ registry.setUpkeepPrivilegeConfig(linkUpkeepID, hex"1233");
+
+ bytes memory cfg = registry.getUpkeepPrivilegeConfig(linkUpkeepID);
+ assertEq(cfg, hex"1233");
+ }
+}
+
+contract SetAdminPrivilegeConfig is SetUp {
+ function test_RevertsWhen_CalledByNonManager() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByUpkeepPrivilegeManager.selector);
+ registry.setAdminPrivilegeConfig(randomAddress(), hex"1233");
+ }
+
+ function test_UpkeepHasEmptyConfig() external {
+ bytes memory cfg = registry.getAdminPrivilegeConfig(randomAddress());
+ assertEq(cfg, bytes(""));
+ }
+
+ function test_SetAdminPrivilegeConfig_CalledByManager() external {
+ vm.startPrank(PRIVILEGE_MANAGER);
+ address admin = randomAddress();
+
+ registry.setAdminPrivilegeConfig(admin, hex"1233");
+
+ bytes memory cfg = registry.getAdminPrivilegeConfig(admin);
+ assertEq(cfg, hex"1233");
+ }
+}
+
+contract TransferUpkeepAdmin is SetUp {
+ event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to);
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.transferUpkeepAdmin(linkUpkeepID, randomAddress());
+ }
+
+ function test_RevertsWhen_TransferToSelf() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.ValueNotChanged.selector);
+ registry.transferUpkeepAdmin(linkUpkeepID, UPKEEP_ADMIN);
+ }
+
+ function test_RevertsWhen_UpkeepCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.transferUpkeepAdmin(linkUpkeepID, randomAddress());
+ }
+
+ function test_DoesNotChangeUpkeepAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.transferUpkeepAdmin(linkUpkeepID, randomAddress());
+
+ assertEq(registry.getUpkeep(linkUpkeepID).admin, UPKEEP_ADMIN);
+ }
+
+ function test_EmitEvent_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+
+ vm.expectEmit();
+ emit UpkeepAdminTransferRequested(linkUpkeepID, UPKEEP_ADMIN, newAdmin);
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ // transferring to the same propose admin won't yield another event
+ vm.recordLogs();
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+ Vm.Log[] memory entries = vm.getRecordedLogs();
+ assertEq(0, entries.length);
+ }
+
+ function test_CancelTransfer_ByTransferToEmptyAddress() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+
+ vm.expectEmit();
+ emit UpkeepAdminTransferRequested(linkUpkeepID, UPKEEP_ADMIN, newAdmin);
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ vm.expectEmit();
+ emit UpkeepAdminTransferRequested(linkUpkeepID, UPKEEP_ADMIN, address(0));
+ registry.transferUpkeepAdmin(linkUpkeepID, address(0));
+ }
+}
+
+contract AcceptUpkeepAdmin is SetUp {
+ event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to);
+
+ function test_RevertsWhen_NotCalledByProposedAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert(Registry.OnlyCallableByProposedAdmin.selector);
+ registry.acceptUpkeepAdmin(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.startPrank(newAdmin);
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.acceptUpkeepAdmin(linkUpkeepID);
+ }
+
+ function test_UpkeepAdminChanged() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ vm.startPrank(newAdmin);
+ vm.expectEmit();
+ emit UpkeepAdminTransferred(linkUpkeepID, UPKEEP_ADMIN, newAdmin);
+ registry.acceptUpkeepAdmin(linkUpkeepID);
+
+ assertEq(newAdmin, registry.getUpkeep(linkUpkeepID).admin);
+ }
+}
+
+contract PauseUpkeep is SetUp {
+ event UpkeepPaused(uint256 indexed id);
+
+ function test_RevertsWhen_NotCalledByUpkeepAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.pauseUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.pauseUpkeep(linkUpkeepID + 1);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.pauseUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyPaused() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.pauseUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.OnlyUnpausedUpkeep.selector);
+ registry.pauseUpkeep(linkUpkeepID);
+ }
+
+ function test_EmitEvent_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepPaused(linkUpkeepID);
+ registry.pauseUpkeep(linkUpkeepID);
+ }
+}
+
+contract UnpauseUpkeep is SetUp {
+ event UpkeepUnpaused(uint256 indexed id);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.unpauseUpkeep(linkUpkeepID + 1);
+ }
+
+ function test_RevertsWhen_UpkeepIsNotPaused() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyPausedUpkeep.selector);
+ registry.unpauseUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.pauseUpkeep(linkUpkeepID);
+
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.unpauseUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_NotCalledByUpkeepAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.pauseUpkeep(linkUpkeepID);
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.unpauseUpkeep(linkUpkeepID);
+ }
+
+ function test_UnpauseUpkeep_CalledByUpkeepAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.pauseUpkeep(linkUpkeepID);
+
+ uint256[] memory ids1 = registry.getActiveUpkeepIDs(0, 0);
+
+ vm.expectEmit();
+ emit UpkeepUnpaused(linkUpkeepID);
+ registry.unpauseUpkeep(linkUpkeepID);
+
+ uint256[] memory ids2 = registry.getActiveUpkeepIDs(0, 0);
+ assertEq(ids1.length + 1, ids2.length);
+ }
+}
+
+contract SetUpkeepCheckData is SetUp {
+ event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepCheckData(linkUpkeepID + 1, hex"1234");
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.setUpkeepCheckData(linkUpkeepID, hex"1234");
+ }
+
+ function test_RevertsWhen_NewCheckDataTooLarge() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.CheckDataExceedsLimit.selector);
+ registry.setUpkeepCheckData(linkUpkeepID, new bytes(10_000));
+ }
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepCheckData(linkUpkeepID, hex"1234");
+ }
+
+ function test_UpdateOffchainConfig_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepCheckDataSet(linkUpkeepID, hex"1234");
+ registry.setUpkeepCheckData(linkUpkeepID, hex"1234");
+
+ assertEq(registry.getUpkeep(linkUpkeepID).checkData, hex"1234");
+ }
+
+ function test_UpdateOffchainConfigOnPausedUpkeep_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ registry.pauseUpkeep(linkUpkeepID);
+
+ vm.expectEmit();
+ emit UpkeepCheckDataSet(linkUpkeepID, hex"1234");
+ registry.setUpkeepCheckData(linkUpkeepID, hex"1234");
+
+ assertTrue(registry.getUpkeep(linkUpkeepID).paused);
+ assertEq(registry.getUpkeep(linkUpkeepID).checkData, hex"1234");
+ }
+}
+
+contract SetUpkeepGasLimit is SetUp {
+ event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID + 1, 1230000);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID, 1230000);
+ }
+
+ function test_RevertsWhen_NewGasLimitOutOfRange() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.GasLimitOutsideRange.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID, 300);
+
+ vm.expectRevert(Registry.GasLimitOutsideRange.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID, 3000000000);
+ }
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID, 1230000);
+ }
+
+ function test_UpdateGasLimit_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepGasLimitSet(linkUpkeepID, 1230000);
+ registry.setUpkeepGasLimit(linkUpkeepID, 1230000);
+
+ assertEq(registry.getUpkeep(linkUpkeepID).performGas, 1230000);
+ }
+}
+
+contract SetUpkeepOffchainConfig is SetUp {
+ event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepOffchainConfig(linkUpkeepID + 1, hex"1233");
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.setUpkeepOffchainConfig(linkUpkeepID, hex"1234");
+ }
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepOffchainConfig(linkUpkeepID, hex"1234");
+ }
+
+ function test_UpdateOffchainConfig_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepOffchainConfigSet(linkUpkeepID, hex"1234");
+ registry.setUpkeepOffchainConfig(linkUpkeepID, hex"1234");
+
+ assertEq(registry.getUpkeep(linkUpkeepID).offchainConfig, hex"1234");
+ }
+}
+
+contract SetUpkeepTriggerConfig is SetUp {
+ event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepTriggerConfig(linkUpkeepID + 1, hex"1233");
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.setUpkeepTriggerConfig(linkUpkeepID, hex"1234");
+ }
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepTriggerConfig(linkUpkeepID, hex"1234");
+ }
+
+ function test_UpdateTriggerConfig_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepTriggerConfigSet(linkUpkeepID, hex"1234");
+ registry.setUpkeepTriggerConfig(linkUpkeepID, hex"1234");
+
+ assertEq(registry.getUpkeepTriggerConfig(linkUpkeepID), hex"1234");
+ }
+}
+
+contract TransferPayeeship is SetUp {
+ event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to);
+
+ function test_RevertsWhen_NotCalledByPayee() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByPayee.selector);
+ registry.transferPayeeship(TRANSMITTERS[0], randomAddress());
+ }
+
+ function test_RevertsWhen_TransferToSelf() external {
+ registry.setPayees(PAYEES);
+ vm.startPrank(PAYEES[0]);
+
+ vm.expectRevert(Registry.ValueNotChanged.selector);
+ registry.transferPayeeship(TRANSMITTERS[0], PAYEES[0]);
+ }
+
+ function test_Transfer_DoesNotChangePayee() external {
+ registry.setPayees(PAYEES);
+
+ vm.startPrank(PAYEES[0]);
+
+ registry.transferPayeeship(TRANSMITTERS[0], randomAddress());
+
+ (, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[0]);
+ assertEq(PAYEES[0], payee);
+ }
+
+ function test_EmitEvent_CalledByPayee() external {
+ registry.setPayees(PAYEES);
+
+ vm.startPrank(PAYEES[0]);
+ address newPayee = randomAddress();
+
+ vm.expectEmit();
+ emit PayeeshipTransferRequested(TRANSMITTERS[0], PAYEES[0], newPayee);
+ registry.transferPayeeship(TRANSMITTERS[0], newPayee);
+
+ // transferring to the same propose payee won't yield another event
+ vm.recordLogs();
+ registry.transferPayeeship(TRANSMITTERS[0], newPayee);
+ Vm.Log[] memory entries = vm.getRecordedLogs();
+ assertEq(0, entries.length);
+ }
+}
+
+contract AcceptPayeeship is SetUp {
+ event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to);
+
+ function test_RevertsWhen_NotCalledByProposedPayee() external {
+ registry.setPayees(PAYEES);
+
+ vm.startPrank(PAYEES[0]);
+ address newPayee = randomAddress();
+ registry.transferPayeeship(TRANSMITTERS[0], newPayee);
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert(Registry.OnlyCallableByProposedPayee.selector);
+ registry.acceptPayeeship(TRANSMITTERS[0]);
+ }
+
+ function test_PayeeChanged() external {
+ registry.setPayees(PAYEES);
+
+ vm.startPrank(PAYEES[0]);
+ address newPayee = randomAddress();
+ registry.transferPayeeship(TRANSMITTERS[0], newPayee);
+
+ vm.startPrank(newPayee);
+ vm.expectEmit();
+ emit PayeeshipTransferred(TRANSMITTERS[0], PAYEES[0], newPayee);
+ registry.acceptPayeeship(TRANSMITTERS[0]);
+
+ (, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[0]);
+ assertEq(newPayee, payee);
+ }
+}
+
+contract SetPayees is SetUp {
+ event PayeesUpdated(address[] transmitters, address[] payees);
+
+ function test_RevertsWhen_NotCalledByOwner() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(bytes("Only callable by owner"));
+ registry.setPayees(NEW_PAYEES);
+ }
+
+ function test_RevertsWhen_PayeesLengthError() external {
+ vm.startPrank(registry.owner());
+
+ address[] memory payees = new address[](5);
+ vm.expectRevert(Registry.ParameterLengthError.selector);
+ registry.setPayees(payees);
+ }
+
+ function test_RevertsWhen_InvalidPayee() external {
+ vm.startPrank(registry.owner());
+
+ NEW_PAYEES[0] = address(0);
+ vm.expectRevert(Registry.InvalidPayee.selector);
+ registry.setPayees(NEW_PAYEES);
+ }
+
+ function test_SetPayees_WhenExistingPayeesAreEmpty() external {
+ (registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+
+ for (uint256 i = 0; i < TRANSMITTERS.length; i++) {
+ (, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[i]);
+ assertEq(address(0), payee);
+ }
+
+ vm.startPrank(registry.owner());
+
+ vm.expectEmit();
+ emit PayeesUpdated(TRANSMITTERS, PAYEES);
+ registry.setPayees(PAYEES);
+ for (uint256 i = 0; i < TRANSMITTERS.length; i++) {
+ (bool active, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[i]);
+ assertTrue(active);
+ assertEq(PAYEES[i], payee);
+ }
+ }
+
+ function test_DotNotSetPayeesToIgnoredAddress() external {
+ address IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
+ (registry, ) = deployAndConfigureRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+ PAYEES[0] = IGNORE_ADDRESS;
+
+ registry.setPayees(PAYEES);
+ (bool active, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[0]);
+ assertTrue(active);
+ assertEq(address(0), payee);
+
+ (active, , , , payee) = registry.getTransmitterInfo(TRANSMITTERS[1]);
+ assertTrue(active);
+ assertEq(PAYEES[1], payee);
+ }
+}
+
+contract GetActiveUpkeepIDs is SetUp {
+ function test_RevertsWhen_IndexOutOfRange() external {
+ vm.expectRevert(Registry.IndexOutOfRange.selector);
+ registry.getActiveUpkeepIDs(5, 0);
+
+ vm.expectRevert(Registry.IndexOutOfRange.selector);
+ registry.getActiveUpkeepIDs(6, 0);
+ }
+
+ function test_ReturnsAllUpkeeps_WhenMaxCountIsZero() external {
+ uint256[] memory uids = registry.getActiveUpkeepIDs(0, 0);
+ assertEq(5, uids.length);
+
+ uids = registry.getActiveUpkeepIDs(2, 0);
+ assertEq(3, uids.length);
+ }
+
+ function test_ReturnsAllRemainingUpkeeps_WhenMaxCountIsTooLarge() external {
+ uint256[] memory uids = registry.getActiveUpkeepIDs(2, 20);
+ assertEq(3, uids.length);
+ }
+
+ function test_ReturnsUpkeeps_BoundByMaxCount() external {
+ uint256[] memory uids = registry.getActiveUpkeepIDs(1, 2);
+ assertEq(2, uids.length);
+ assertEq(uids[0], linkUpkeepID2);
+ assertEq(uids[1], usdUpkeepID18);
+ }
+}
diff --git a/contracts/src/v0.8/automation/test/v2_3/BaseTest.t.sol b/contracts/src/v0.8/automation/test/v2_3/BaseTest.t.sol
index 9016f52c55d..e0d15daab6c 100644
--- a/contracts/src/v0.8/automation/test/v2_3/BaseTest.t.sol
+++ b/contracts/src/v0.8/automation/test/v2_3/BaseTest.t.sol
@@ -20,14 +20,14 @@ import {ChainModuleBase} from "../../chains/ChainModuleBase.sol";
import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {MockUpkeep} from "../../mocks/MockUpkeep.sol";
import {IWrappedNative} from "../../interfaces/v2_3/IWrappedNative.sol";
-import {WETH9} from "./WETH9.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 {
- // test state (not exposed to derrived tests)
+ // test state (not exposed to derived tests)
uint256 private nonce;
// constants
@@ -283,7 +283,6 @@ contract BaseTest is Test {
billingTokenAddresses,
billingTokenConfigs
);
- registry.setPayees(PAYEES);
return (registry, registrar);
}
@@ -356,40 +355,58 @@ contract BaseTest is Test {
);
}
+ // tests single upkeep, expects success
function _transmit(uint256 id, Registry registry) internal {
uint256[] memory ids = new uint256[](1);
ids[0] = id;
- _transmit(ids, registry);
+ _handleTransmit(ids, registry, bytes4(0));
}
+ // tests multiple upkeeps, expects success
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");
+ _handleTransmit(ids, registry, bytes4(0));
+ }
+
+ // tests single upkeep, expects revert
+ function _transmitAndExpectRevert(uint256 id, Registry registry, bytes4 selector) internal {
+ uint256[] memory ids = new uint256[](1);
+ ids[0] = id;
+ _handleTransmit(ids, registry, selector);
+ }
+
+ // private function not exposed to actual testing contract
+ function _handleTransmit(uint256[] memory ids, Registry registry, bytes4 selector) private {
+ bytes memory reportBytes;
+ {
+ 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);
+ AutoBase.Report memory report = AutoBase.Report(
+ uint256(1000000000),
+ uint256(2000000000),
+ upkeepIds,
+ gasLimits,
+ triggers,
+ performDatas
+ );
+
+ reportBytes = _encodeReport(report);
+ }
(, , bytes32 configDigest) = registry.latestConfigDetails();
bytes32[3] memory reportContext = [configDigest, configDigest, configDigest];
uint256[] memory signerPKs = new uint256[](2);
@@ -398,6 +415,9 @@ contract BaseTest is Test {
(bytes32[] memory rs, bytes32[] memory ss, bytes32 vs) = _signReport(reportBytes, reportContext, signerPKs);
vm.startPrank(TRANSMITTERS[0]);
+ if (selector != bytes4(0)) {
+ vm.expectRevert(selector);
+ }
registry.transmit(reportContext, reportBytes, rs, ss, vs);
vm.stopPrank();
}
diff --git a/contracts/src/v0.8/automation/test/v2_3_zksync/BaseTest.t.sol b/contracts/src/v0.8/automation/test/v2_3_zksync/BaseTest.t.sol
new file mode 100644
index 00000000000..cde05ab3a22
--- /dev/null
+++ b/contracts/src/v0.8/automation/test/v2_3_zksync/BaseTest.t.sol
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: MIT
+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 {ERC20Mock6Decimals} from "../../mocks/ERC20Mock6Decimals.sol";
+import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol";
+import {AutomationForwarderLogic} from "../../AutomationForwarderLogic.sol";
+import {UpkeepTranscoder5_0 as Transcoder} from "../../v2_3/UpkeepTranscoder5_0.sol";
+import {ZKSyncAutomationRegistry2_3} from "../../v2_3_zksync/ZKSyncAutomationRegistry2_3.sol";
+import {ZKSyncAutomationRegistryLogicA2_3} from "../../v2_3_zksync/ZKSyncAutomationRegistryLogicA2_3.sol";
+import {ZKSyncAutomationRegistryLogicB2_3} from "../../v2_3_zksync/ZKSyncAutomationRegistryLogicB2_3.sol";
+import {ZKSyncAutomationRegistryLogicC2_3} from "../../v2_3_zksync/ZKSyncAutomationRegistryLogicC2_3.sol";
+import {ZKSyncAutomationRegistryBase2_3 as ZKSyncAutoBase} from "../../v2_3_zksync/ZKSyncAutomationRegistryBase2_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 {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol";
+import {MockUpkeep} from "../../mocks/MockUpkeep.sol";
+import {IWrappedNative} from "../../interfaces/v2_3/IWrappedNative.sol";
+import {WETH9} from "../WETH9.sol";
+import {MockGasBoundCaller} from "../../../tests/MockGasBoundCaller.sol";
+import {MockZKSyncSystemContext} from "../../../tests/MockZKSyncSystemContext.sol";
+
+/**
+ * @title BaseTest provides basic test setup procedures and dependencies for use by other
+ * unit tests
+ */
+contract BaseTest is Test {
+ // test state (not exposed to derived 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;
+ ERC20Mock6Decimals internal usdToken6;
+ ERC20Mock internal usdToken18;
+ ERC20Mock internal usdToken18_2;
+ 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;
+ MockGasBoundCaller internal GAS_BOUND_CALLER;
+ MockZKSyncSystemContext internal SYSTEM_CONTEXT;
+
+ // 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);
+ linkToken = new LinkToken();
+ linkToken.grantMintRole(OWNER);
+ usdToken18 = new ERC20Mock("MOCK_ERC20_18Decimals", "MOCK_ERC20_18Decimals", OWNER, 0);
+ usdToken18_2 = new ERC20Mock("Second_MOCK_ERC20_18Decimals", "Second_MOCK_ERC20_18Decimals", OWNER, 0);
+ usdToken6 = new ERC20Mock6Decimals("MOCK_ERC20_6Decimals", "MOCK_ERC20_6Decimals", 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();
+ GAS_BOUND_CALLER = new MockGasBoundCaller();
+ SYSTEM_CONTEXT = new MockZKSyncSystemContext();
+
+ bytes memory callerCode = address(GAS_BOUND_CALLER).code;
+ vm.etch(0xc706EC7dfA5D4Dc87f29f859094165E8290530f5, callerCode);
+
+ bytes memory contextCode = address(SYSTEM_CONTEXT).code;
+ vm.etch(0x000000000000000000000000000000000000800B, contextCode);
+
+ 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);
+
+ usdToken18.mint(OWNER, 1000e18);
+ usdToken18.mint(UPKEEP_ADMIN, 1000e18);
+ usdToken18.mint(FINANCE_ADMIN, 1000e18);
+ usdToken18.mint(STRANGER, 1000e18);
+
+ usdToken18_2.mint(UPKEEP_ADMIN, 1000e18);
+
+ usdToken6.mint(OWNER, 1000e6);
+ usdToken6.mint(UPKEEP_ADMIN, 1000e6);
+ usdToken6.mint(FINANCE_ADMIN, 1000e6);
+ usdToken6.mint(STRANGER, 1000e6);
+
+ 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 deployZKSyncRegistry(ZKSyncAutoBase.PayoutMode payoutMode) internal returns (Registry) {
+ AutomationForwarderLogic forwarderLogic = new AutomationForwarderLogic();
+ ZKSyncAutomationRegistryLogicC2_3 logicC2_3 = new ZKSyncAutomationRegistryLogicC2_3(
+ address(linkToken),
+ address(LINK_USD_FEED),
+ address(NATIVE_USD_FEED),
+ address(FAST_GAS_FEED),
+ address(forwarderLogic),
+ ZERO_ADDRESS,
+ payoutMode,
+ address(weth)
+ );
+ ZKSyncAutomationRegistryLogicB2_3 logicB2_3 = new ZKSyncAutomationRegistryLogicB2_3(logicC2_3);
+ ZKSyncAutomationRegistryLogicA2_3 logicA2_3 = new ZKSyncAutomationRegistryLogicA2_3(logicB2_3);
+ return Registry(payable(address(new ZKSyncAutomationRegistry2_3(logicA2_3))));
+ }
+
+ /// @notice deploys and configures a registry, registrar, and everything needed for most tests
+ function deployAndConfigureZKSyncRegistryAndRegistrar(
+ ZKSyncAutoBase.PayoutMode payoutMode
+ ) internal returns (Registry, AutomationRegistrar2_3) {
+ Registry registry = deployZKSyncRegistry(payoutMode);
+
+ IERC20[] memory billingTokens = new IERC20[](4);
+ billingTokens[0] = IERC20(address(usdToken18));
+ billingTokens[1] = IERC20(address(weth));
+ billingTokens[2] = IERC20(address(linkToken));
+ billingTokens[3] = IERC20(address(usdToken6));
+ uint256[] memory minRegistrationFees = new uint256[](billingTokens.length);
+ minRegistrationFees[0] = 100e18; // 100 USD
+ minRegistrationFees[1] = 5e18; // 5 Native
+ minRegistrationFees[2] = 5e18; // 5 LINK
+ minRegistrationFees[3] = 100e6; // 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: DEFAULT_GAS_FEE_PPB, // 15%
+ flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents
+ priceFeed: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 100_000_000, // $1
+ minSpend: 1e18, // 1 USD
+ decimals: 18
+ });
+ 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: 5e18, // 5 Native
+ decimals: 18
+ });
+ 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: 1e18, // 1 LINK
+ decimals: 18
+ });
+ billingTokenConfigs[3] = AutomationRegistryBase2_3.BillingConfig({
+ gasFeePPB: DEFAULT_GAS_FEE_PPB, // 15%
+ flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents
+ priceFeed: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 1e8, // $1
+ minSpend: 1e6, // 1 USD
+ decimals: 6
+ });
+
+ if (payoutMode == ZKSyncAutoBase.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
+ );
+ 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, bytes4 selector) internal {
+ uint256[] memory ids = new uint256[](1);
+ ids[0] = id;
+ _transmit(ids, registry, selector);
+ }
+
+ function _transmit(uint256[] memory ids, Registry registry, bytes4 selector) internal {
+ bytes memory reportBytes;
+ {
+ 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(
+ ZKSyncAutoBase.ConditionalTrigger(uint32(block.number - 1), blockhash(block.number - 1))
+ );
+ } else {
+ revert("not implemented");
+ }
+ }
+ ZKSyncAutoBase.Report memory report = ZKSyncAutoBase.Report(
+ uint256(1000000000),
+ uint256(2000000000),
+ upkeepIds,
+ gasLimits,
+ triggers,
+ performDatas
+ );
+
+ 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]);
+ if (selector != bytes4(0)) {
+ vm.expectRevert(selector);
+ }
+ 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(ZKSyncAutoBase.Report memory report) internal pure returns (bytes memory reportBytes) {
+ return abi.encode(report);
+ }
+
+ function _encodeConditionalTrigger(
+ ZKSyncAutoBase.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 with 18 decimals to the recipient
+ function _mintERC20_18Decimals(address recipient, uint256 amount) internal {
+ vm.prank(OWNER);
+ usdToken18.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/test/v2_3_zksync/ZKSyncAutomationRegistry2_3.t.sol b/contracts/src/v0.8/automation/test/v2_3_zksync/ZKSyncAutomationRegistry2_3.t.sol
new file mode 100644
index 00000000000..7098d9f38fa
--- /dev/null
+++ b/contracts/src/v0.8/automation/test/v2_3_zksync/ZKSyncAutomationRegistry2_3.t.sol
@@ -0,0 +1,2772 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.19;
+
+import {Vm} from "forge-std/Test.sol";
+import {BaseTest} from "./BaseTest.t.sol";
+import {ZKSyncAutomationRegistryBase2_3 as AutoBase} from "../../v2_3_zksync/ZKSyncAutomationRegistryBase2_3.sol";
+import {AutomationRegistrar2_3 as Registrar} from "../../v2_3/AutomationRegistrar2_3.sol";
+import {IAutomationRegistryMaster2_3 as Registry, AutomationRegistryBase2_3, IAutomationV21PlusCommon} from "../../interfaces/v2_3/IAutomationRegistryMaster2_3.sol";
+import {ChainModuleBase} from "../../chains/ChainModuleBase.sol";
+import {IERC20Metadata as IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol";
+import {IWrappedNative} from "../../interfaces/v2_3/IWrappedNative.sol";
+
+// forge test --match-path src/v0.8/automation/test/v2_3_zksync/ZKSyncAutomationRegistry2_3.t.sol --match-test
+
+enum Trigger {
+ CONDITION,
+ LOG
+}
+
+contract SetUp is BaseTest {
+ Registry internal registry;
+ AutomationRegistryBase2_3.OnchainConfig internal config;
+ bytes internal constant offchainConfigBytes = abi.encode(1234, ZERO_ADDRESS);
+
+ uint256 linkUpkeepID;
+ uint256 linkUpkeepID2; // 2 upkeeps use the same billing token (LINK) to test migration scenario
+ uint256 usdUpkeepID18; // 1 upkeep uses ERC20 token with 18 decimals
+ uint256 usdUpkeepID6; // 1 upkeep uses ERC20 token with 6 decimals
+ uint256 nativeUpkeepID;
+
+ function setUp() public virtual override {
+ super.setUp();
+ (registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+ config = registry.getConfig();
+
+ vm.startPrank(OWNER);
+ linkToken.approve(address(registry), type(uint256).max);
+ usdToken6.approve(address(registry), type(uint256).max);
+ usdToken18.approve(address(registry), type(uint256).max);
+ weth.approve(address(registry), type(uint256).max);
+ vm.startPrank(UPKEEP_ADMIN);
+ linkToken.approve(address(registry), type(uint256).max);
+ usdToken6.approve(address(registry), type(uint256).max);
+ usdToken18.approve(address(registry), type(uint256).max);
+ weth.approve(address(registry), type(uint256).max);
+ vm.startPrank(STRANGER);
+ linkToken.approve(address(registry), type(uint256).max);
+ usdToken6.approve(address(registry), type(uint256).max);
+ usdToken18.approve(address(registry), type(uint256).max);
+ weth.approve(address(registry), type(uint256).max);
+ vm.stopPrank();
+
+ linkUpkeepID = registry.registerUpkeep(
+ address(TARGET1),
+ config.maxPerformGas,
+ UPKEEP_ADMIN,
+ uint8(Trigger.CONDITION),
+ address(linkToken),
+ "",
+ "",
+ ""
+ );
+
+ linkUpkeepID2 = registry.registerUpkeep(
+ address(TARGET1),
+ config.maxPerformGas,
+ UPKEEP_ADMIN,
+ uint8(Trigger.CONDITION),
+ address(linkToken),
+ "",
+ "",
+ ""
+ );
+
+ usdUpkeepID18 = registry.registerUpkeep(
+ address(TARGET1),
+ config.maxPerformGas,
+ UPKEEP_ADMIN,
+ uint8(Trigger.CONDITION),
+ address(usdToken18),
+ "",
+ "",
+ ""
+ );
+
+ usdUpkeepID6 = registry.registerUpkeep(
+ address(TARGET1),
+ config.maxPerformGas,
+ UPKEEP_ADMIN,
+ uint8(Trigger.CONDITION),
+ address(usdToken6),
+ "",
+ "",
+ ""
+ );
+
+ 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(linkUpkeepID2, registry.getMinBalanceForUpkeep(linkUpkeepID2));
+ registry.addFunds(usdUpkeepID18, registry.getMinBalanceForUpkeep(usdUpkeepID18));
+ registry.addFunds(usdUpkeepID6, registry.getMinBalanceForUpkeep(usdUpkeepID6));
+ registry.addFunds(nativeUpkeepID, registry.getMinBalanceForUpkeep(nativeUpkeepID));
+ vm.stopPrank();
+ }
+}
+
+contract LatestConfigDetails is SetUp {
+ function testGet() public {
+ (uint32 configCount, uint32 blockNumber, bytes32 configDigest) = registry.latestConfigDetails();
+ assertEq(configCount, 1);
+ assertTrue(blockNumber > 0);
+ assertNotEq(configDigest, "");
+ }
+}
+
+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(Registry.OnlySimulatedBackend.selector));
+ registry.checkUpkeep(id, triggerData);
+ }
+}
+
+contract WithdrawFunds is SetUp {
+ event FundsWithdrawn(uint256 indexed id, uint256 amount, address to);
+
+ function test_RevertsWhen_CalledByNonAdmin() external {
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ vm.prank(STRANGER);
+ registry.withdrawFunds(linkUpkeepID, STRANGER);
+ }
+
+ function test_RevertsWhen_InvalidRecipient() external {
+ vm.expectRevert(Registry.InvalidRecipient.selector);
+ vm.prank(UPKEEP_ADMIN);
+ registry.withdrawFunds(linkUpkeepID, ZERO_ADDRESS);
+ }
+
+ function test_RevertsWhen_UpkeepNotCanceled() external {
+ vm.expectRevert(Registry.UpkeepNotCanceled.selector);
+ vm.prank(UPKEEP_ADMIN);
+ registry.withdrawFunds(linkUpkeepID, UPKEEP_ADMIN);
+ }
+
+ function test_Happy_Link() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+ vm.roll(100 + block.number);
+
+ uint256 startUpkeepAdminBalance = linkToken.balanceOf(UPKEEP_ADMIN);
+ uint256 startLinkReserveAmountBalance = registry.getReserveAmount(address(linkToken));
+
+ uint256 upkeepBalance = registry.getBalance(linkUpkeepID);
+ vm.expectEmit();
+ emit FundsWithdrawn(linkUpkeepID, upkeepBalance, address(UPKEEP_ADMIN));
+ registry.withdrawFunds(linkUpkeepID, UPKEEP_ADMIN);
+
+ assertEq(registry.getBalance(linkUpkeepID), 0);
+ assertEq(linkToken.balanceOf(UPKEEP_ADMIN), startUpkeepAdminBalance + upkeepBalance);
+ assertEq(registry.getReserveAmount(address(linkToken)), startLinkReserveAmountBalance - upkeepBalance);
+ }
+
+ function test_Happy_USDToken() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(usdUpkeepID6);
+ vm.roll(100 + block.number);
+
+ uint256 startUpkeepAdminBalance = usdToken6.balanceOf(UPKEEP_ADMIN);
+ uint256 startUSDToken6ReserveAmountBalance = registry.getReserveAmount(address(usdToken6));
+
+ uint256 upkeepBalance = registry.getBalance(usdUpkeepID6);
+ vm.expectEmit();
+ emit FundsWithdrawn(usdUpkeepID6, upkeepBalance, address(UPKEEP_ADMIN));
+ registry.withdrawFunds(usdUpkeepID6, UPKEEP_ADMIN);
+
+ assertEq(registry.getBalance(usdUpkeepID6), 0);
+ assertEq(usdToken6.balanceOf(UPKEEP_ADMIN), startUpkeepAdminBalance + upkeepBalance);
+ assertEq(registry.getReserveAmount(address(usdToken6)), startUSDToken6ReserveAmountBalance - upkeepBalance);
+ }
+}
+
+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 test_HappyWhen_NativeUpkeep_WithMsgValue0() 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);
+ assertEq(registry.getAvailableERC20ForPayment(address(weth)), 0);
+ }
+
+ // when msg.value is not 0, it uses the native payment path
+ function test_HappyWhen_NativeUpkeep_WithMsgValueNot0() 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);
+ assertEq(registry.getAvailableERC20ForPayment(address(weth)), 0);
+ }
+
+ // 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 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);
+ registry.addFunds(linkUpkeepID, 1);
+ assertEq(registry.getBalance(linkUpkeepID), startAmount + 1);
+ vm.prank(STRANGER);
+ registry.addFunds(linkUpkeepID, 1);
+ assertEq(registry.getBalance(linkUpkeepID), startAmount + 2);
+ }
+
+ function test_movesFundFromCorrectToken() public {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ uint256 startLINKRegistryBalance = linkToken.balanceOf(address(registry));
+ uint256 startUSDRegistryBalance = usdToken18.balanceOf(address(registry));
+ uint256 startLinkUpkeepBalance = registry.getBalance(linkUpkeepID);
+ uint256 startUSDUpkeepBalance = registry.getBalance(usdUpkeepID18);
+
+ registry.addFunds(linkUpkeepID, 1);
+ assertEq(registry.getBalance(linkUpkeepID), startLinkUpkeepBalance + 1);
+ assertEq(registry.getBalance(usdUpkeepID18), startUSDRegistryBalance);
+ assertEq(linkToken.balanceOf(address(registry)), startLINKRegistryBalance + 1);
+ assertEq(usdToken18.balanceOf(address(registry)), startUSDUpkeepBalance);
+
+ registry.addFunds(usdUpkeepID18, 2);
+ assertEq(registry.getBalance(linkUpkeepID), startLinkUpkeepBalance + 1);
+ assertEq(registry.getBalance(usdUpkeepID18), startUSDRegistryBalance + 2);
+ assertEq(linkToken.balanceOf(address(registry)), startLINKRegistryBalance + 1);
+ assertEq(usdToken18.balanceOf(address(registry)), startUSDUpkeepBalance + 2);
+ }
+
+ 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(registry), 1e10);
+
+ //check there's a balance
+ assertEq(linkToken.balanceOf(address(registry)), startBalance + 1e10);
+
+ //check the link available has increased by the same amount
+ assertEq(uint256(registry.linkAvailableForPayment()), uint256(startLinkAvailable) + 1e10);
+ }
+
+ function testWithdrawLinkRevertsBecauseOnlyFinanceAdminAllowed() public {
+ vm.expectRevert(abi.encodeWithSelector(Registry.OnlyFinanceAdmin.selector));
+ registry.withdrawLink(aMockAddress, 1);
+ }
+
+ function testWithdrawLinkRevertsBecauseOfInsufficientBalance() public {
+ vm.startPrank(FINANCE_ADMIN);
+
+ // try to withdraw 1 link while there is 0 balance
+ vm.expectRevert(abi.encodeWithSelector(Registry.InsufficientBalance.selector, 0, 1));
+ registry.withdrawLink(aMockAddress, 1);
+
+ vm.stopPrank();
+ }
+
+ function testWithdrawLinkRevertsBecauseOfInvalidRecipient() public {
+ vm.startPrank(FINANCE_ADMIN);
+
+ // try to withdraw 1 link while there is 0 balance
+ vm.expectRevert(abi.encodeWithSelector(Registry.InvalidRecipient.selector));
+ registry.withdrawLink(ZERO_ADDRESS, 1);
+
+ vm.stopPrank();
+ }
+
+ function testWithdrawLinkSuccess() public {
+ //simulate a deposit of link to the liquidity pool
+ _mintLink(address(registry), 1e10);
+ uint256 startBalance = linkToken.balanceOf(address(registry));
+
+ vm.startPrank(FINANCE_ADMIN);
+
+ // try to withdraw 1 link while there is a ton of link available
+ registry.withdrawLink(aMockAddress, 1);
+
+ vm.stopPrank();
+
+ assertEq(linkToken.balanceOf(address(aMockAddress)), 1);
+ assertEq(linkToken.balanceOf(address(registry)), startBalance - 1);
+ }
+
+ function test_WithdrawERC20Fees_RespectsReserveAmount() public {
+ assertEq(registry.getBalance(usdUpkeepID18), registry.getReserveAmount(address(usdToken18)));
+ vm.startPrank(FINANCE_ADMIN);
+ vm.expectRevert(abi.encodeWithSelector(Registry.InsufficientBalance.selector, 0, 1));
+ registry.withdrawERC20Fees(address(usdToken18), FINANCE_ADMIN, 1);
+ }
+
+ 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
+ }
+
+ // default is ON_CHAIN mode
+ function test_WithdrawERC20Fees_RevertsWhen_LinkAvailableForPaymentIsNegative() public {
+ _transmit(usdUpkeepID18, registry, bytes4(0)); // adds USD token to finance withdrawable, and gives NOPs a LINK balance
+ require(registry.linkAvailableForPayment() < 0, "linkAvailableForPayment should be negative");
+ require(
+ registry.getAvailableERC20ForPayment(address(usdToken18)) > 0,
+ "ERC20AvailableForPayment should be positive"
+ );
+ vm.expectRevert(Registry.InsufficientLinkLiquidity.selector);
+ vm.prank(FINANCE_ADMIN);
+ registry.withdrawERC20Fees(address(usdToken18), FINANCE_ADMIN, 1); // should revert
+ _mintLink(address(registry), uint256(registry.linkAvailableForPayment() * -10)); // top up LINK liquidity pool
+ vm.prank(FINANCE_ADMIN);
+ registry.withdrawERC20Fees(address(usdToken18), FINANCE_ADMIN, 1); // now finance can withdraw
+ }
+
+ function test_WithdrawERC20Fees_InOffChainMode_Happy() public {
+ // deploy and configure a registry with OFF_CHAIN payout
+ (Registry registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+
+ // register an upkeep and add funds
+ uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", "");
+ _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20);
+ vm.startPrank(UPKEEP_ADMIN);
+ usdToken18.approve(address(registry), 1e20);
+ registry.addFunds(id, 1e20);
+
+ // manually create a transmit so transmitters earn some rewards
+ _transmit(id, registry, bytes4(0));
+ require(registry.linkAvailableForPayment() < 0, "linkAvailableForPayment should be negative");
+ vm.prank(FINANCE_ADMIN);
+ registry.withdrawERC20Fees(address(usdToken18), aMockAddress, 1); // finance can withdraw
+
+ // recipient should get the funds
+ assertEq(usdToken18.balanceOf(address(aMockAddress)), 1);
+ }
+
+ function testWithdrawERC20FeeSuccess() public {
+ // deposit excess USDToken to the registry (this goes to the "finance withdrawable" pool be default)
+ uint256 startReserveAmount = registry.getReserveAmount(address(usdToken18));
+ uint256 startAmount = usdToken18.balanceOf(address(registry));
+ _mintERC20_18Decimals(address(registry), 1e10);
+
+ // depositing shouldn't change reserve amount
+ assertEq(registry.getReserveAmount(address(usdToken18)), startReserveAmount);
+
+ vm.startPrank(FINANCE_ADMIN);
+
+ // try to withdraw 1 USDToken
+ registry.withdrawERC20Fees(address(usdToken18), aMockAddress, 1);
+
+ vm.stopPrank();
+
+ assertEq(usdToken18.balanceOf(address(aMockAddress)), 1);
+ assertEq(usdToken18.balanceOf(address(registry)), startAmount + 1e10 - 1);
+ assertEq(registry.getReserveAmount(address(usdToken18)), startReserveAmount);
+ }
+}
+
+contract SetConfig is SetUp {
+ event ConfigSet(
+ uint32 previousConfigBlockNumber,
+ bytes32 configDigest,
+ uint64 configCount,
+ address[] signers,
+ address[] transmitters,
+ uint8 f,
+ bytes onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes offchainConfig
+ );
+
+ address module = address(new ChainModuleBase());
+
+ AutomationRegistryBase2_3.OnchainConfig cfg =
+ AutomationRegistryBase2_3.OnchainConfig({
+ checkGasLimit: 5_000_000,
+ stalenessSeconds: 90_000,
+ gasCeilingMultiplier: 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: _getRegistrars(),
+ upkeepPrivilegeManager: PRIVILEGE_MANAGER,
+ chainModule: module,
+ reorgProtectionEnabled: true,
+ financeAdmin: FINANCE_ADMIN
+ });
+
+ function testSetConfigSuccess() public {
+ (uint32 configCount, uint32 blockNumber, ) = registry.latestConfigDetails();
+ assertEq(configCount, 1);
+
+ address billingTokenAddress = address(usdToken18);
+ 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: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 2_000_000_000, // $20
+ minSpend: 100_000,
+ decimals: 18
+ });
+
+ bytes memory onchainConfigBytes = abi.encode(cfg);
+ bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs);
+
+ 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.setConfig(
+ SIGNERS,
+ TRANSMITTERS,
+ F,
+ onchainConfigBytesWithBilling,
+ OFFCHAIN_CONFIG_VERSION,
+ offchainConfigBytes
+ );
+
+ (, , address[] memory signers, address[] memory transmitters, uint8 f) = registry.getState();
+
+ assertEq(signers, SIGNERS);
+ assertEq(transmitters, TRANSMITTERS);
+ assertEq(f, F);
+
+ AutomationRegistryBase2_3.BillingConfig memory config = registry.getBillingTokenConfig(billingTokenAddress);
+ assertEq(config.gasFeePPB, 5_000);
+ assertEq(config.flatFeeMilliCents, 20_000);
+ assertEq(config.priceFeed, address(USDTOKEN_USD_FEED));
+ assertEq(config.minSpend, 100_000);
+
+ address[] memory tokens = registry.getBillingTokens();
+ assertEq(tokens.length, 1);
+ }
+
+ function testSetConfigMultipleBillingConfigsSuccess() public {
+ (uint32 configCount, , ) = registry.latestConfigDetails();
+ assertEq(configCount, 1);
+
+ address billingTokenAddress1 = address(linkToken);
+ address billingTokenAddress2 = address(usdToken18);
+ address[] memory billingTokens = new address[](2);
+ billingTokens[0] = billingTokenAddress1;
+ billingTokens[1] = billingTokenAddress2;
+
+ AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs = new AutomationRegistryBase2_3.BillingConfig[](2);
+ billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({
+ gasFeePPB: 5_001,
+ flatFeeMilliCents: 20_001,
+ priceFeed: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 100,
+ minSpend: 100,
+ decimals: 18
+ });
+ billingConfigs[1] = AutomationRegistryBase2_3.BillingConfig({
+ gasFeePPB: 5_002,
+ flatFeeMilliCents: 20_002,
+ priceFeed: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 200,
+ minSpend: 200,
+ decimals: 18
+ });
+
+ bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs);
+
+ registry.setConfig(
+ SIGNERS,
+ TRANSMITTERS,
+ F,
+ onchainConfigBytesWithBilling,
+ OFFCHAIN_CONFIG_VERSION,
+ offchainConfigBytes
+ );
+
+ (, , address[] memory signers, address[] memory transmitters, uint8 f) = registry.getState();
+
+ assertEq(signers, SIGNERS);
+ assertEq(transmitters, TRANSMITTERS);
+ assertEq(f, F);
+
+ AutomationRegistryBase2_3.BillingConfig memory config1 = registry.getBillingTokenConfig(billingTokenAddress1);
+ assertEq(config1.gasFeePPB, 5_001);
+ assertEq(config1.flatFeeMilliCents, 20_001);
+ assertEq(config1.priceFeed, address(USDTOKEN_USD_FEED));
+ assertEq(config1.fallbackPrice, 100);
+ assertEq(config1.minSpend, 100);
+
+ AutomationRegistryBase2_3.BillingConfig memory config2 = registry.getBillingTokenConfig(billingTokenAddress2);
+ assertEq(config2.gasFeePPB, 5_002);
+ assertEq(config2.flatFeeMilliCents, 20_002);
+ assertEq(config2.priceFeed, address(USDTOKEN_USD_FEED));
+ assertEq(config2.fallbackPrice, 200);
+ assertEq(config2.minSpend, 200);
+
+ address[] memory tokens = registry.getBillingTokens();
+ assertEq(tokens.length, 2);
+ }
+
+ function testSetConfigTwiceAndLastSetOverwrites() public {
+ (uint32 configCount, , ) = registry.latestConfigDetails();
+ assertEq(configCount, 1);
+
+ // BillingConfig1
+ address billingTokenAddress1 = address(usdToken18);
+ address[] memory billingTokens1 = new address[](1);
+ billingTokens1[0] = billingTokenAddress1;
+
+ AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs1 = new AutomationRegistryBase2_3.BillingConfig[](1);
+ billingConfigs1[0] = AutomationRegistryBase2_3.BillingConfig({
+ gasFeePPB: 5_001,
+ flatFeeMilliCents: 20_001,
+ priceFeed: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 100,
+ minSpend: 100,
+ decimals: 18
+ });
+
+ // the first time uses the default onchain config with 2 registrars
+ bytes memory onchainConfigBytesWithBilling1 = abi.encode(cfg, billingTokens1, billingConfigs1);
+
+ // set config once
+ registry.setConfig(
+ SIGNERS,
+ TRANSMITTERS,
+ F,
+ onchainConfigBytesWithBilling1,
+ OFFCHAIN_CONFIG_VERSION,
+ offchainConfigBytes
+ );
+
+ (, IAutomationV21PlusCommon.OnchainConfigLegacy memory onchainConfig1, , , ) = registry.getState();
+ assertEq(onchainConfig1.registrars.length, 2);
+
+ // BillingConfig2
+ address billingTokenAddress2 = address(usdToken18);
+ address[] memory billingTokens2 = new address[](1);
+ billingTokens2[0] = billingTokenAddress2;
+
+ AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs2 = new AutomationRegistryBase2_3.BillingConfig[](1);
+ billingConfigs2[0] = AutomationRegistryBase2_3.BillingConfig({
+ gasFeePPB: 5_002,
+ flatFeeMilliCents: 20_002,
+ priceFeed: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 200,
+ minSpend: 200,
+ decimals: 18
+ });
+
+ address[] memory newRegistrars = new address[](3);
+ newRegistrars[0] = address(uint160(uint256(keccak256("newRegistrar1"))));
+ newRegistrars[1] = address(uint160(uint256(keccak256("newRegistrar2"))));
+ newRegistrars[2] = address(uint160(uint256(keccak256("newRegistrar3"))));
+
+ // new onchain config with 3 new registrars, all other fields stay the same as the default
+ AutomationRegistryBase2_3.OnchainConfig memory cfg2 = AutomationRegistryBase2_3.OnchainConfig({
+ checkGasLimit: 5_000_000,
+ stalenessSeconds: 90_000,
+ gasCeilingMultiplier: 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: newRegistrars,
+ upkeepPrivilegeManager: PRIVILEGE_MANAGER,
+ chainModule: module,
+ reorgProtectionEnabled: true,
+ financeAdmin: FINANCE_ADMIN
+ });
+
+ // the second time uses the new onchain config with 3 new registrars and also new billing tokens/configs
+ bytes memory onchainConfigBytesWithBilling2 = abi.encode(cfg2, billingTokens2, billingConfigs2);
+
+ // set config twice
+ registry.setConfig(
+ SIGNERS,
+ TRANSMITTERS,
+ F,
+ onchainConfigBytesWithBilling2,
+ OFFCHAIN_CONFIG_VERSION,
+ offchainConfigBytes
+ );
+
+ (
+ ,
+ IAutomationV21PlusCommon.OnchainConfigLegacy memory onchainConfig2,
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f
+ ) = registry.getState();
+
+ assertEq(onchainConfig2.registrars.length, 3);
+ for (uint256 i = 0; i < newRegistrars.length; i++) {
+ assertEq(newRegistrars[i], onchainConfig2.registrars[i]);
+ }
+ assertEq(signers, SIGNERS);
+ assertEq(transmitters, TRANSMITTERS);
+ assertEq(f, F);
+
+ AutomationRegistryBase2_3.BillingConfig memory config2 = registry.getBillingTokenConfig(billingTokenAddress2);
+ assertEq(config2.gasFeePPB, 5_002);
+ assertEq(config2.flatFeeMilliCents, 20_002);
+ assertEq(config2.priceFeed, address(USDTOKEN_USD_FEED));
+ assertEq(config2.fallbackPrice, 200);
+ assertEq(config2.minSpend, 200);
+
+ address[] memory tokens = registry.getBillingTokens();
+ assertEq(tokens.length, 1);
+ }
+
+ function testSetConfigDuplicateBillingConfigFailure() public {
+ (uint32 configCount, , ) = registry.latestConfigDetails();
+ assertEq(configCount, 1);
+
+ address billingTokenAddress1 = address(linkToken);
+ address billingTokenAddress2 = address(linkToken);
+ address[] memory billingTokens = new address[](2);
+ billingTokens[0] = billingTokenAddress1;
+ billingTokens[1] = billingTokenAddress2;
+
+ AutomationRegistryBase2_3.BillingConfig[] memory billingConfigs = new AutomationRegistryBase2_3.BillingConfig[](2);
+ billingConfigs[0] = AutomationRegistryBase2_3.BillingConfig({
+ gasFeePPB: 5_001,
+ flatFeeMilliCents: 20_001,
+ priceFeed: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 100,
+ minSpend: 100,
+ decimals: 18
+ });
+ billingConfigs[1] = AutomationRegistryBase2_3.BillingConfig({
+ gasFeePPB: 5_002,
+ flatFeeMilliCents: 20_002,
+ priceFeed: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 200,
+ minSpend: 200,
+ decimals: 18
+ });
+
+ bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs);
+
+ // expect revert because of duplicate tokens
+ vm.expectRevert(abi.encodeWithSelector(Registry.DuplicateEntry.selector));
+ registry.setConfig(
+ SIGNERS,
+ TRANSMITTERS,
+ F,
+ onchainConfigBytesWithBilling,
+ OFFCHAIN_CONFIG_VERSION,
+ offchainConfigBytes
+ );
+ }
+
+ 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: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 2_000_000_000, // $20
+ minSpend: 100_000,
+ decimals: 18
+ });
+
+ // deploy registry with OFF_CHAIN payout mode
+ registry = deployZKSyncRegistry(AutoBase.PayoutMode.OFF_CHAIN);
+
+ vm.expectRevert(abi.encodeWithSelector(Registry.InvalidToken.selector));
+ registry.setConfigTypeSafe(
+ SIGNERS,
+ TRANSMITTERS,
+ F,
+ cfg,
+ OFFCHAIN_CONFIG_VERSION,
+ offchainConfigBytes,
+ billingTokens,
+ billingConfigs
+ );
+ }
+
+ function testSetConfigRevertDueToInvalidDecimals() 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: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 2_000_000_000, // $20
+ minSpend: 100_000,
+ decimals: 6 // link token should have 18 decimals
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(Registry.InvalidToken.selector));
+ registry.setConfigTypeSafe(
+ SIGNERS,
+ TRANSMITTERS,
+ F,
+ cfg,
+ OFFCHAIN_CONFIG_VERSION,
+ offchainConfigBytes,
+ billingTokens,
+ billingConfigs
+ );
+ }
+
+ function testSetConfigOnTransmittersAndPayees() public {
+ registry.setPayees(PAYEES);
+ AutomationRegistryBase2_3.TransmitterPayeeInfo[] memory transmitterPayeeInfos = registry
+ .getTransmittersWithPayees();
+ assertEq(transmitterPayeeInfos.length, TRANSMITTERS.length);
+
+ for (uint256 i = 0; i < transmitterPayeeInfos.length; i++) {
+ address transmitterAddress = transmitterPayeeInfos[i].transmitterAddress;
+ address payeeAddress = transmitterPayeeInfos[i].payeeAddress;
+
+ address expectedTransmitter = TRANSMITTERS[i];
+ address expectedPayee = PAYEES[i];
+
+ assertEq(transmitterAddress, expectedTransmitter);
+ assertEq(payeeAddress, expectedPayee);
+ }
+ }
+
+ function testSetConfigWithNewTransmittersSuccess() public {
+ registry = deployZKSyncRegistry(AutoBase.PayoutMode.OFF_CHAIN);
+
+ (uint32 configCount, uint32 blockNumber, ) = registry.latestConfigDetails();
+ assertEq(configCount, 0);
+
+ address billingTokenAddress = address(usdToken18);
+ 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: address(USDTOKEN_USD_FEED),
+ fallbackPrice: 2_000_000_000, // $20
+ minSpend: 100_000,
+ decimals: 18
+ });
+
+ 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 _getRegistrars() private pure returns (address[] memory) {
+ address[] memory registrars = new address[](2);
+ registrars[0] = address(uint160(uint256(keccak256("registrar1"))));
+ registrars[1] = address(uint160(uint256(keccak256("registrar2"))));
+ return registrars;
+ }
+
+ function _configDigestFromConfigData(
+ uint256 chainId,
+ address contractAddress,
+ uint64 configCount,
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) internal pure returns (bytes32) {
+ uint256 h = uint256(
+ keccak256(
+ abi.encode(
+ chainId,
+ contractAddress,
+ configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ )
+ )
+ );
+ uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00
+ uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00
+ 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, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+
+ vm.expectRevert(abi.encodeWithSelector(Registry.OnlyFinanceAdmin.selector));
+ registry.settleNOPsOffchain();
+ }
+
+ function testSettleNOPsOffchainRevertDueToOffchainSettlementDisabled() public {
+ (Registry registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(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, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+ registry.setPayees(PAYEES);
+
+ 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();
+ }
+
+ // 1. transmitter balance zeroed after settlement, 2. admin can withdraw ERC20, 3. switch to onchain mode, 4. link amount owed to NOPs stays the same
+ function testSettleNOPsOffchainSuccessWithERC20MultiSteps() public {
+ // deploy and configure a registry with OFF_CHAIN payout
+ (Registry registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+ registry.setPayees(PAYEES);
+
+ // register an upkeep and add funds
+ uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", "");
+ _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20);
+ vm.startPrank(UPKEEP_ADMIN);
+ usdToken18.approve(address(registry), 1e20);
+ registry.addFunds(id, 1e20);
+
+ // manually create a transmit so transmitters earn some rewards
+ _transmit(id, registry, bytes4(0));
+
+ // 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);
+ }
+
+ // after the offchain settlement, the total reserve amount of LINK should be 0
+ assertEq(registry.getReserveAmount(address(linkToken)), 0);
+ // should have some ERC20s in registry after transmit
+ uint256 erc20ForPayment1 = registry.getAvailableERC20ForPayment(address(usdToken18));
+ require(erc20ForPayment1 > 0, "ERC20AvailableForPayment should be positive");
+
+ vm.startPrank(UPKEEP_ADMIN);
+ vm.roll(100 + block.number);
+ // manually create a transmit so transmitters earn some rewards
+ _transmit(id, registry, bytes4(0));
+
+ uint256 erc20ForPayment2 = registry.getAvailableERC20ForPayment(address(usdToken18));
+ require(erc20ForPayment2 > erc20ForPayment1, "ERC20AvailableForPayment should be greater after another transmit");
+
+ // finance admin comes to withdraw all available ERC20s
+ vm.startPrank(FINANCE_ADMIN);
+ registry.withdrawERC20Fees(address(usdToken18), FINANCE_ADMIN, erc20ForPayment2);
+
+ uint256 erc20ForPayment3 = registry.getAvailableERC20ForPayment(address(usdToken18));
+ require(erc20ForPayment3 == 0, "ERC20AvailableForPayment should be 0 now after withdrawal");
+
+ uint256 reservedLink = registry.getReserveAmount(address(linkToken));
+ require(reservedLink > 0, "Reserve amount of LINK should be positive since there was another transmit");
+
+ // owner comes to disable offchain mode
+ vm.startPrank(registry.owner());
+ registry.disableOffchainPayments();
+
+ // finance admin comes to withdraw all available ERC20s, should revert bc of insufficient link liquidity
+ vm.startPrank(FINANCE_ADMIN);
+ uint256 erc20ForPayment4 = registry.getAvailableERC20ForPayment(address(usdToken18));
+ vm.expectRevert(abi.encodeWithSelector(Registry.InsufficientLinkLiquidity.selector));
+ registry.withdrawERC20Fees(address(usdToken18), FINANCE_ADMIN, erc20ForPayment4);
+
+ // reserved link amount to NOPs should stay the same after switching to onchain mode
+ assertEq(registry.getReserveAmount(address(linkToken)), reservedLink);
+ // available ERC20 for payment should be 0 since finance admin withdrew all already
+ assertEq(erc20ForPayment4, 0);
+ }
+
+ function testSettleNOPsOffchainForDeactivatedTransmittersSuccess() public {
+ // deploy and configure a registry with OFF_CHAIN payout
+ (Registry registry, Registrar registrar) = deployAndConfigureZKSyncRegistryAndRegistrar(
+ AutoBase.PayoutMode.OFF_CHAIN
+ );
+
+ // register an upkeep and add funds
+ uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", "");
+ _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20);
+ vm.startPrank(UPKEEP_ADMIN);
+ usdToken18.approve(address(registry), 1e20);
+ registry.addFunds(id, 1e20);
+
+ // manually create a transmit so TRANSMITTERS earn some rewards
+ _transmit(id, registry, bytes4(0));
+
+ // TRANSMITTERS have positive balance now
+ // configure the registry to use NEW_TRANSMITTERS
+ _configureWithNewTransmitters(registry, registrar);
+
+ _transmit(id, registry, bytes4(0));
+
+ // 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);
+ }
+
+ // after the offchain settlement, the total reserve amount of LINK should be 0
+ assertEq(registry.getReserveAmount(address(linkToken)), 0);
+ }
+
+ function testDisableOffchainPaymentsRevertDueToUnauthorizedCaller() public {
+ (Registry registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+
+ vm.startPrank(FINANCE_ADMIN);
+ vm.expectRevert(bytes("Only callable by owner"));
+ registry.disableOffchainPayments();
+ }
+
+ function testDisableOffchainPaymentsSuccess() public {
+ (Registry registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(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, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+ registry.setPayees(PAYEES);
+
+ // register an upkeep and add funds
+ uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", "");
+ _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20);
+ vm.startPrank(UPKEEP_ADMIN);
+ usdToken18.approve(address(registry), 1e20);
+ registry.addFunds(id, 1e20);
+
+ // manually create a transmit so transmitters earn some rewards
+ _transmit(id, registry, bytes4(0));
+
+ // 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, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.OFF_CHAIN);
+ registry.setPayees(PAYEES);
+
+ // register an upkeep and add funds
+ uint256 id = registry.registerUpkeep(address(TARGET1), 1000000, UPKEEP_ADMIN, 0, address(usdToken18), "", "", "");
+ _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20);
+ vm.startPrank(UPKEEP_ADMIN);
+ usdToken18.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, bytes4(0));
+ }
+
+ // 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, bytes4(0));
+ }
+
+ // 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(usdToken18));
+
+ uint256[] memory minRegistrationFees = new uint256[](billingTokens.length);
+ minRegistrationFees[0] = 100e18; // 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: 1e8, // $1
+ minSpend: 1e18, // 1 USD
+ decimals: 18
+ });
+
+ address[] memory 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 = deployZKSyncRegistry(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(usdUpkeepID18));
+ }
+
+ 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_with18Decimals() public {
+ // set fee to 0
+ AutomationRegistryBase2_3.BillingConfig memory usdTokenConfig = registry.getBillingTokenConfig(address(usdToken18));
+ usdTokenConfig.flatFeeMilliCents = 0;
+ _updateBillingTokenConfig(registry, address(usdToken18), usdTokenConfig);
+
+ uint256 minBalanceBefore = registry.getMinBalanceForUpkeep(usdUpkeepID18);
+
+ // set fee to non-zero
+ usdTokenConfig.flatFeeMilliCents = 100;
+ _updateBillingTokenConfig(registry, address(usdToken18), usdTokenConfig);
+
+ uint256 minBalanceAfter = registry.getMinBalanceForUpkeep(usdUpkeepID18);
+ assertEq(
+ minBalanceAfter,
+ minBalanceBefore + ((uint256(usdTokenConfig.flatFeeMilliCents) * 1e13) / 10 ** (18 - usdTokenConfig.decimals))
+ );
+ }
+
+ function test_accountsForFlatFee_with6Decimals() public {
+ // set fee to 0
+ AutomationRegistryBase2_3.BillingConfig memory usdTokenConfig = registry.getBillingTokenConfig(address(usdToken6));
+ usdTokenConfig.flatFeeMilliCents = 0;
+ _updateBillingTokenConfig(registry, address(usdToken6), usdTokenConfig);
+
+ uint256 minBalanceBefore = registry.getMinBalanceForUpkeep(usdUpkeepID6);
+
+ // set fee to non-zero
+ usdTokenConfig.flatFeeMilliCents = 100;
+ _updateBillingTokenConfig(registry, address(usdToken6), usdTokenConfig);
+
+ uint256 minBalanceAfter = registry.getMinBalanceForUpkeep(usdUpkeepID6);
+ assertEq(
+ minBalanceAfter,
+ minBalanceBefore + ((uint256(usdTokenConfig.flatFeeMilliCents) * 1e13) / 10 ** (18 - usdTokenConfig.decimals))
+ );
+ }
+}
+
+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_transmitRevertWithExtraBytes() external {
+ bytes32[3] memory exampleReportContext = [
+ bytes32(0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef),
+ bytes32(0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890),
+ bytes32(0x7890abcdef1234567890abcdef1234567890abcdef1234567890abcdef123456)
+ ];
+
+ bytes memory exampleRawReport = hex"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
+
+ bytes32[] memory exampleRs = new bytes32[](3);
+ exampleRs[0] = bytes32(0x1234561234561234561234561234561234561234561234561234561234561234);
+ exampleRs[1] = bytes32(0x1234561234561234561234561234561234561234561234561234561234561234);
+ exampleRs[2] = bytes32(0x7890789078907890789078907890789078907890789078907890789078907890);
+
+ bytes32[] memory exampleSs = new bytes32[](3);
+ exampleSs[0] = bytes32(0x1234561234561234561234561234561234561234561234561234561234561234);
+ exampleSs[1] = bytes32(0x1234561234561234561234561234561234561234561234561234561234561234);
+ exampleSs[2] = bytes32(0x1234561234561234561234561234561234561234561234561234561234561234);
+
+ bytes32 exampleRawVs = bytes32(0x1234561234561234561234561234561234561234561234561234561234561234);
+
+ bytes memory transmitData = abi.encodeWithSelector(
+ registry.transmit.selector,
+ exampleReportContext,
+ exampleRawReport,
+ exampleRs,
+ exampleSs,
+ exampleRawVs
+ );
+ bytes memory badTransmitData = bytes.concat(transmitData, bytes1(0x00)); // add extra data
+ vm.startPrank(TRANSMITTERS[0]);
+ (bool success, bytes memory returnData) = address(registry).call(badTransmitData); // send the bogus transmit
+ assertFalse(success, "Call did not revert as expected");
+ assertEq(returnData, abi.encodePacked(Registry.InvalidDataLength.selector));
+ vm.stopPrank();
+ }
+
+ function test_handlesMixedBatchOfBillingTokens() external {
+ uint256[] memory prevUpkeepBalances = new uint256[](3);
+ prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID);
+ prevUpkeepBalances[1] = registry.getBalance(usdUpkeepID18);
+ prevUpkeepBalances[2] = registry.getBalance(nativeUpkeepID);
+ uint256[] memory prevTokenBalances = new uint256[](3);
+ prevTokenBalances[0] = linkToken.balanceOf(address(registry));
+ prevTokenBalances[1] = usdToken18.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(usdToken18));
+ prevReserveBalances[2] = registry.getReserveAmount(address(weth));
+ uint256[] memory upkeepIDs = new uint256[](3);
+ upkeepIDs[0] = linkUpkeepID;
+ upkeepIDs[1] = usdUpkeepID18;
+ upkeepIDs[2] = nativeUpkeepID;
+
+ // withdraw-able by finance team should be 0
+ require(registry.getAvailableERC20ForPayment(address(usdToken18)) == 0, "ERC20AvailableForPayment should be 0");
+ require(registry.getAvailableERC20ForPayment(address(weth)) == 0, "ERC20AvailableForPayment should be 0");
+
+ // do the thing
+ _transmit(upkeepIDs, registry, bytes4(0));
+
+ // withdraw-able by the finance team should be positive
+ require(
+ registry.getAvailableERC20ForPayment(address(usdToken18)) > 0,
+ "ERC20AvailableForPayment should be positive"
+ );
+ require(registry.getAvailableERC20ForPayment(address(weth)) > 0, "ERC20AvailableForPayment should be positive");
+
+ // assert upkeep balances have decreased
+ require(prevUpkeepBalances[0] > registry.getBalance(linkUpkeepID), "link upkeep balance should have decreased");
+ require(prevUpkeepBalances[1] > registry.getBalance(usdUpkeepID18), "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], usdToken18.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(usdToken18)),
+ "usd reserve amount should have decreased"
+ );
+ require(
+ prevReserveBalances[2] > registry.getReserveAmount(address(weth)),
+ "native reserve amount should have decreased"
+ );
+ }
+
+ function test_handlesInsufficientBalanceWithUSDToken18() external {
+ // deploy and configure a registry with ON_CHAIN payout
+ (Registry registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+
+ // register an upkeep and add funds
+ uint256 upkeepID = registry.registerUpkeep(
+ address(TARGET1),
+ 1000000,
+ UPKEEP_ADMIN,
+ 0,
+ address(usdToken18),
+ "",
+ "",
+ ""
+ );
+ _mintERC20_18Decimals(UPKEEP_ADMIN, 1e20);
+ vm.startPrank(UPKEEP_ADMIN);
+ usdToken18.approve(address(registry), 1e20);
+ registry.addFunds(upkeepID, 1); // smaller than gasCharge
+ uint256 balance = registry.getBalance(upkeepID);
+
+ // manually create a transmit
+ vm.recordLogs();
+ _transmit(upkeepID, registry, bytes4(0));
+ Vm.Log[] memory entries = vm.getRecordedLogs();
+
+ assertEq(entries.length, 3);
+ Vm.Log memory l1 = entries[1];
+ assertEq(
+ l1.topics[0],
+ keccak256("UpkeepCharged(uint256,(uint96,uint96,uint96,uint96,address,uint96,uint96,uint96))")
+ );
+ (
+ uint96 gasChargeInBillingToken,
+ uint96 premiumInBillingToken,
+ uint96 gasReimbursementInJuels,
+ uint96 premiumInJuels,
+ address billingToken,
+ uint96 linkUSD,
+ uint96 nativeUSD,
+ uint96 billingUSD
+ ) = abi.decode(l1.data, (uint96, uint96, uint96, uint96, address, uint96, uint96, uint96));
+
+ assertEq(gasChargeInBillingToken, balance);
+ assertEq(gasReimbursementInJuels, (balance * billingUSD) / linkUSD);
+ assertEq(premiumInJuels, 0);
+ assertEq(premiumInBillingToken, 0);
+ }
+
+ function test_handlesInsufficientBalanceWithUSDToken6() external {
+ // deploy and configure a registry with ON_CHAIN payout
+ (Registry registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+
+ // register an upkeep and add funds
+ uint256 upkeepID = registry.registerUpkeep(
+ address(TARGET1),
+ 1000000,
+ UPKEEP_ADMIN,
+ 0,
+ address(usdToken6),
+ "",
+ "",
+ ""
+ );
+ vm.prank(OWNER);
+ usdToken6.mint(UPKEEP_ADMIN, 1e20);
+
+ vm.startPrank(UPKEEP_ADMIN);
+ usdToken6.approve(address(registry), 1e20);
+ registry.addFunds(upkeepID, 100); // this is greater than gasCharge but less than (gasCharge + premium)
+ uint256 balance = registry.getBalance(upkeepID);
+
+ // manually create a transmit
+ vm.recordLogs();
+ _transmit(upkeepID, registry, bytes4(0));
+ Vm.Log[] memory entries = vm.getRecordedLogs();
+
+ assertEq(entries.length, 3);
+ Vm.Log memory l1 = entries[1];
+ assertEq(
+ l1.topics[0],
+ keccak256("UpkeepCharged(uint256,(uint96,uint96,uint96,uint96,address,uint96,uint96,uint96))")
+ );
+ (
+ uint96 gasChargeInBillingToken,
+ uint96 premiumInBillingToken,
+ uint96 gasReimbursementInJuels,
+ uint96 premiumInJuels,
+ address billingToken,
+ uint96 linkUSD,
+ uint96 nativeUSD,
+ uint96 billingUSD
+ ) = abi.decode(l1.data, (uint96, uint96, uint96, uint96, address, uint96, uint96, uint96));
+
+ assertEq(premiumInJuels, (balance * billingUSD * 1e12) / linkUSD - gasReimbursementInJuels); // scale to 18 decimals
+ assertEq(premiumInBillingToken, (premiumInJuels * linkUSD + (billingUSD * 1e12 - 1)) / (billingUSD * 1e12));
+ }
+}
+
+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, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+ idsToMigrate.push(linkUpkeepID);
+ idsToMigrate.push(linkUpkeepID2);
+ idsToMigrate.push(usdUpkeepID18);
+ 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(usdUpkeepID18);
+ registry.setUpkeepTriggerConfig(linkUpkeepID, randomBytes(100));
+ registry.setUpkeepCheckData(nativeUpkeepID, randomBytes(25));
+
+ // record previous state
+ uint256[] memory prevUpkeepBalances = new uint256[](4);
+ prevUpkeepBalances[0] = registry.getBalance(linkUpkeepID);
+ prevUpkeepBalances[1] = registry.getBalance(linkUpkeepID2);
+ prevUpkeepBalances[2] = registry.getBalance(usdUpkeepID18);
+ prevUpkeepBalances[3] = registry.getBalance(nativeUpkeepID);
+ uint256[] memory prevReserveBalances = new uint256[](3);
+ prevReserveBalances[0] = registry.getReserveAmount(address(linkToken));
+ prevReserveBalances[1] = registry.getReserveAmount(address(usdToken18));
+ prevReserveBalances[2] = registry.getReserveAmount(address(weth));
+ uint256[] memory prevTokenBalances = new uint256[](3);
+ prevTokenBalances[0] = linkToken.balanceOf(address(registry));
+ prevTokenBalances[1] = usdToken18.balanceOf(address(registry));
+ prevTokenBalances[2] = weth.balanceOf(address(registry));
+ bytes[] memory prevUpkeepData = new bytes[](4);
+ prevUpkeepData[0] = abi.encode(registry.getUpkeep(linkUpkeepID));
+ prevUpkeepData[1] = abi.encode(registry.getUpkeep(linkUpkeepID2));
+ prevUpkeepData[2] = abi.encode(registry.getUpkeep(usdUpkeepID18));
+ prevUpkeepData[3] = abi.encode(registry.getUpkeep(nativeUpkeepID));
+ bytes[] memory prevUpkeepTriggerData = new bytes[](4);
+ prevUpkeepTriggerData[0] = registry.getUpkeepTriggerConfig(linkUpkeepID);
+ prevUpkeepTriggerData[1] = registry.getUpkeepTriggerConfig(linkUpkeepID2);
+ prevUpkeepTriggerData[2] = registry.getUpkeepTriggerConfig(usdUpkeepID18);
+ prevUpkeepTriggerData[3] = registry.getUpkeepTriggerConfig(nativeUpkeepID);
+
+ // event expectations
+ vm.expectEmit(address(registry));
+ emit UpkeepMigrated(linkUpkeepID, prevUpkeepBalances[0], address(newRegistry));
+ vm.expectEmit(address(registry));
+ emit UpkeepMigrated(linkUpkeepID2, prevUpkeepBalances[1], address(newRegistry));
+ vm.expectEmit(address(registry));
+ emit UpkeepMigrated(usdUpkeepID18, prevUpkeepBalances[2], address(newRegistry));
+ vm.expectEmit(address(registry));
+ emit UpkeepMigrated(nativeUpkeepID, prevUpkeepBalances[3], address(newRegistry));
+ vm.expectEmit(address(newRegistry));
+ emit UpkeepReceived(linkUpkeepID, prevUpkeepBalances[0], address(registry));
+ vm.expectEmit(address(newRegistry));
+ emit UpkeepReceived(linkUpkeepID2, prevUpkeepBalances[1], address(registry));
+ vm.expectEmit(address(newRegistry));
+ emit UpkeepReceived(usdUpkeepID18, prevUpkeepBalances[2], address(registry));
+ vm.expectEmit(address(newRegistry));
+ emit UpkeepReceived(nativeUpkeepID, prevUpkeepBalances[3], address(registry));
+
+ // do the thing
+ registry.migrateUpkeeps(idsToMigrate, address(newRegistry));
+
+ // assert upkeep balances have been migrated
+ assertEq(registry.getBalance(linkUpkeepID), 0);
+ assertEq(registry.getBalance(linkUpkeepID2), 0);
+ assertEq(registry.getBalance(usdUpkeepID18), 0);
+ assertEq(registry.getBalance(nativeUpkeepID), 0);
+ assertEq(newRegistry.getBalance(linkUpkeepID), prevUpkeepBalances[0]);
+ assertEq(newRegistry.getBalance(linkUpkeepID2), prevUpkeepBalances[1]);
+ assertEq(newRegistry.getBalance(usdUpkeepID18), prevUpkeepBalances[2]);
+ assertEq(newRegistry.getBalance(nativeUpkeepID), prevUpkeepBalances[3]);
+
+ // assert reserve balances have been adjusted
+ assertEq(
+ newRegistry.getReserveAmount(address(linkToken)),
+ newRegistry.getBalance(linkUpkeepID) + newRegistry.getBalance(linkUpkeepID2)
+ );
+ assertEq(newRegistry.getReserveAmount(address(usdToken18)), newRegistry.getBalance(usdUpkeepID18));
+ assertEq(newRegistry.getReserveAmount(address(weth)), newRegistry.getBalance(nativeUpkeepID));
+ assertEq(
+ newRegistry.getReserveAmount(address(linkToken)),
+ prevReserveBalances[0] - registry.getReserveAmount(address(linkToken))
+ );
+ assertEq(
+ newRegistry.getReserveAmount(address(usdToken18)),
+ prevReserveBalances[1] - registry.getReserveAmount(address(usdToken18))
+ );
+ assertEq(
+ newRegistry.getReserveAmount(address(weth)),
+ prevReserveBalances[2] - registry.getReserveAmount(address(weth))
+ );
+
+ // assert token have been transferred
+ assertEq(
+ linkToken.balanceOf(address(newRegistry)),
+ newRegistry.getBalance(linkUpkeepID) + newRegistry.getBalance(linkUpkeepID2)
+ );
+ assertEq(usdToken18.balanceOf(address(newRegistry)), newRegistry.getBalance(usdUpkeepID18));
+ assertEq(weth.balanceOf(address(newRegistry)), newRegistry.getBalance(nativeUpkeepID));
+ assertEq(linkToken.balanceOf(address(registry)), prevTokenBalances[0] - linkToken.balanceOf(address(newRegistry)));
+ assertEq(
+ usdToken18.balanceOf(address(registry)),
+ prevTokenBalances[1] - usdToken18.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(linkUpkeepID2)));
+ assertEq(prevUpkeepData[2], abi.encode(newRegistry.getUpkeep(usdUpkeepID18)));
+ assertEq(prevUpkeepData[3], abi.encode(newRegistry.getUpkeep(nativeUpkeepID)));
+ assertEq(prevUpkeepTriggerData[0], newRegistry.getUpkeepTriggerConfig(linkUpkeepID));
+ assertEq(prevUpkeepTriggerData[1], newRegistry.getUpkeepTriggerConfig(linkUpkeepID2));
+ assertEq(prevUpkeepTriggerData[2], newRegistry.getUpkeepTriggerConfig(usdUpkeepID18));
+ assertEq(prevUpkeepTriggerData[3], newRegistry.getUpkeepTriggerConfig(nativeUpkeepID));
+
+ vm.stopPrank();
+ }
+}
+
+contract Pause is SetUp {
+ function test_RevertsWhen_CalledByNonOwner() external {
+ vm.expectRevert(bytes("Only callable by owner"));
+ vm.prank(STRANGER);
+ registry.pause();
+ }
+
+ function test_CalledByOwner_success() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+
+ (IAutomationV21PlusCommon.StateLegacy memory state, , , , ) = registry.getState();
+ assertTrue(state.paused);
+ }
+
+ function test_revertsWhen_registerUpkeepInPausedRegistry() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+
+ vm.expectRevert(Registry.RegistryPaused.selector);
+ uint256 id = registry.registerUpkeep(
+ address(TARGET1),
+ config.maxPerformGas,
+ UPKEEP_ADMIN,
+ uint8(Trigger.CONDITION),
+ address(linkToken),
+ "",
+ "",
+ ""
+ );
+ }
+
+ function test_revertsWhen_transmitInPausedRegistry() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+
+ _transmit(usdUpkeepID18, registry, Registry.RegistryPaused.selector);
+ }
+}
+
+contract Unpause is SetUp {
+ function test_RevertsWhen_CalledByNonOwner() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+
+ vm.expectRevert(bytes("Only callable by owner"));
+ vm.startPrank(STRANGER);
+ registry.unpause();
+ }
+
+ function test_CalledByOwner_success() external {
+ vm.startPrank(registry.owner());
+ registry.pause();
+ (IAutomationV21PlusCommon.StateLegacy memory state1, , , , ) = registry.getState();
+ assertTrue(state1.paused);
+
+ registry.unpause();
+ (IAutomationV21PlusCommon.StateLegacy memory state2, , , , ) = registry.getState();
+ assertFalse(state2.paused);
+ }
+}
+
+contract CancelUpkeep is SetUp {
+ event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight);
+
+ function test_RevertsWhen_IdIsInvalid_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ vm.expectRevert(Registry.CannotCancel.selector);
+ registry.cancelUpkeep(1111111);
+ }
+
+ function test_RevertsWhen_IdIsInvalid_CalledByOwner() external {
+ vm.startPrank(registry.owner());
+ vm.expectRevert(Registry.CannotCancel.selector);
+ registry.cancelUpkeep(1111111);
+ }
+
+ function test_RevertsWhen_NotCalledByOwnerOrAdmin() external {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(Registry.OnlyCallableByOwnerOrAdmin.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceledByAdmin_CalledByOwner() external {
+ uint256 bn = block.number;
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.startPrank(registry.owner());
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceledByOwner_CalledByAdmin() external {
+ uint256 bn = block.number;
+ vm.startPrank(registry.owner());
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.startPrank(UPKEEP_ADMIN);
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceledByAdmin_CalledByAdmin() external {
+ uint256 bn = block.number;
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceledByOwner_CalledByOwner() external {
+ uint256 bn = block.number;
+ vm.startPrank(registry.owner());
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_CancelUpkeep_SetMaxValidBlockNumber_CalledByAdmin() external {
+ uint256 bn = block.number;
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ uint256 maxValidBlocknumber = uint256(registry.getUpkeep(linkUpkeepID).maxValidBlocknumber);
+
+ // 50 is the cancellation delay
+ assertEq(bn + 50, maxValidBlocknumber);
+ }
+
+ function test_CancelUpkeep_SetMaxValidBlockNumber_CalledByOwner() external {
+ uint256 bn = block.number;
+ vm.startPrank(registry.owner());
+ registry.cancelUpkeep(linkUpkeepID);
+
+ uint256 maxValidBlocknumber = uint256(registry.getUpkeep(linkUpkeepID).maxValidBlocknumber);
+
+ // cancellation by registry owner is immediate and no cancellation delay is applied
+ assertEq(bn, maxValidBlocknumber);
+ }
+
+ function test_CancelUpkeep_EmitEvent_CalledByAdmin() external {
+ uint256 bn = block.number;
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepCanceled(linkUpkeepID, uint64(bn + 50));
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+
+ function test_CancelUpkeep_EmitEvent_CalledByOwner() external {
+ uint256 bn = block.number;
+ vm.startPrank(registry.owner());
+
+ vm.expectEmit();
+ emit UpkeepCanceled(linkUpkeepID, uint64(bn));
+ registry.cancelUpkeep(linkUpkeepID);
+ }
+}
+
+contract SetPeerRegistryMigrationPermission is SetUp {
+ function test_SetPeerRegistryMigrationPermission_CalledByOwner() external {
+ address peer = randomAddress();
+ vm.startPrank(registry.owner());
+
+ uint8 permission = registry.getPeerRegistryMigrationPermission(peer);
+ assertEq(0, permission);
+
+ registry.setPeerRegistryMigrationPermission(peer, 1);
+ permission = registry.getPeerRegistryMigrationPermission(peer);
+ assertEq(1, permission);
+
+ registry.setPeerRegistryMigrationPermission(peer, 2);
+ permission = registry.getPeerRegistryMigrationPermission(peer);
+ assertEq(2, permission);
+
+ registry.setPeerRegistryMigrationPermission(peer, 0);
+ permission = registry.getPeerRegistryMigrationPermission(peer);
+ assertEq(0, permission);
+ }
+
+ function test_RevertsWhen_InvalidPermission_CalledByOwner() external {
+ address peer = randomAddress();
+ vm.startPrank(registry.owner());
+
+ vm.expectRevert();
+ registry.setPeerRegistryMigrationPermission(peer, 100);
+ }
+
+ function test_RevertsWhen_CalledByNonOwner() external {
+ address peer = randomAddress();
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(bytes("Only callable by owner"));
+ registry.setPeerRegistryMigrationPermission(peer, 1);
+ }
+}
+
+contract SetUpkeepPrivilegeConfig is SetUp {
+ function test_RevertsWhen_CalledByNonManager() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByUpkeepPrivilegeManager.selector);
+ registry.setUpkeepPrivilegeConfig(linkUpkeepID, hex"1233");
+ }
+
+ function test_UpkeepHasEmptyConfig() external {
+ bytes memory cfg = registry.getUpkeepPrivilegeConfig(linkUpkeepID);
+ assertEq(cfg, bytes(""));
+ }
+
+ function test_SetUpkeepPrivilegeConfig_CalledByManager() external {
+ vm.startPrank(PRIVILEGE_MANAGER);
+
+ registry.setUpkeepPrivilegeConfig(linkUpkeepID, hex"1233");
+
+ bytes memory cfg = registry.getUpkeepPrivilegeConfig(linkUpkeepID);
+ assertEq(cfg, hex"1233");
+ }
+}
+
+contract SetAdminPrivilegeConfig is SetUp {
+ function test_RevertsWhen_CalledByNonManager() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByUpkeepPrivilegeManager.selector);
+ registry.setAdminPrivilegeConfig(randomAddress(), hex"1233");
+ }
+
+ function test_UpkeepHasEmptyConfig() external {
+ bytes memory cfg = registry.getAdminPrivilegeConfig(randomAddress());
+ assertEq(cfg, bytes(""));
+ }
+
+ function test_SetAdminPrivilegeConfig_CalledByManager() external {
+ vm.startPrank(PRIVILEGE_MANAGER);
+ address admin = randomAddress();
+
+ registry.setAdminPrivilegeConfig(admin, hex"1233");
+
+ bytes memory cfg = registry.getAdminPrivilegeConfig(admin);
+ assertEq(cfg, hex"1233");
+ }
+}
+
+contract TransferUpkeepAdmin is SetUp {
+ event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to);
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.transferUpkeepAdmin(linkUpkeepID, randomAddress());
+ }
+
+ function test_RevertsWhen_TransferToSelf() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.ValueNotChanged.selector);
+ registry.transferUpkeepAdmin(linkUpkeepID, UPKEEP_ADMIN);
+ }
+
+ function test_RevertsWhen_UpkeepCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.transferUpkeepAdmin(linkUpkeepID, randomAddress());
+ }
+
+ function test_DoesNotChangeUpkeepAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.transferUpkeepAdmin(linkUpkeepID, randomAddress());
+
+ assertEq(registry.getUpkeep(linkUpkeepID).admin, UPKEEP_ADMIN);
+ }
+
+ function test_EmitEvent_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+
+ vm.expectEmit();
+ emit UpkeepAdminTransferRequested(linkUpkeepID, UPKEEP_ADMIN, newAdmin);
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ // transferring to the same propose admin won't yield another event
+ vm.recordLogs();
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+ Vm.Log[] memory entries = vm.getRecordedLogs();
+ assertEq(0, entries.length);
+ }
+
+ function test_CancelTransfer_ByTransferToEmptyAddress() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+
+ vm.expectEmit();
+ emit UpkeepAdminTransferRequested(linkUpkeepID, UPKEEP_ADMIN, newAdmin);
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ vm.expectEmit();
+ emit UpkeepAdminTransferRequested(linkUpkeepID, UPKEEP_ADMIN, address(0));
+ registry.transferUpkeepAdmin(linkUpkeepID, address(0));
+ }
+}
+
+contract AcceptUpkeepAdmin is SetUp {
+ event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to);
+
+ function test_RevertsWhen_NotCalledByProposedAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert(Registry.OnlyCallableByProposedAdmin.selector);
+ registry.acceptUpkeepAdmin(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.startPrank(newAdmin);
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.acceptUpkeepAdmin(linkUpkeepID);
+ }
+
+ function test_UpkeepAdminChanged() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ address newAdmin = randomAddress();
+ registry.transferUpkeepAdmin(linkUpkeepID, newAdmin);
+
+ vm.startPrank(newAdmin);
+ vm.expectEmit();
+ emit UpkeepAdminTransferred(linkUpkeepID, UPKEEP_ADMIN, newAdmin);
+ registry.acceptUpkeepAdmin(linkUpkeepID);
+
+ assertEq(newAdmin, registry.getUpkeep(linkUpkeepID).admin);
+ }
+}
+
+contract PauseUpkeep is SetUp {
+ event UpkeepPaused(uint256 indexed id);
+
+ function test_RevertsWhen_NotCalledByUpkeepAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.pauseUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.pauseUpkeep(linkUpkeepID + 1);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.pauseUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyPaused() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.pauseUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.OnlyUnpausedUpkeep.selector);
+ registry.pauseUpkeep(linkUpkeepID);
+ }
+
+ function test_EmitEvent_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepPaused(linkUpkeepID);
+ registry.pauseUpkeep(linkUpkeepID);
+ }
+}
+
+contract UnpauseUpkeep is SetUp {
+ event UpkeepUnpaused(uint256 indexed id);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.unpauseUpkeep(linkUpkeepID + 1);
+ }
+
+ function test_RevertsWhen_UpkeepIsNotPaused() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyPausedUpkeep.selector);
+ registry.unpauseUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.pauseUpkeep(linkUpkeepID);
+
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.unpauseUpkeep(linkUpkeepID);
+ }
+
+ function test_RevertsWhen_NotCalledByUpkeepAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.pauseUpkeep(linkUpkeepID);
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.unpauseUpkeep(linkUpkeepID);
+ }
+
+ function test_UnpauseUpkeep_CalledByUpkeepAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.pauseUpkeep(linkUpkeepID);
+
+ uint256[] memory ids1 = registry.getActiveUpkeepIDs(0, 0);
+
+ vm.expectEmit();
+ emit UpkeepUnpaused(linkUpkeepID);
+ registry.unpauseUpkeep(linkUpkeepID);
+
+ uint256[] memory ids2 = registry.getActiveUpkeepIDs(0, 0);
+ assertEq(ids1.length + 1, ids2.length);
+ }
+}
+
+contract SetUpkeepCheckData is SetUp {
+ event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepCheckData(linkUpkeepID + 1, hex"1234");
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.setUpkeepCheckData(linkUpkeepID, hex"1234");
+ }
+
+ function test_RevertsWhen_NewCheckDataTooLarge() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.CheckDataExceedsLimit.selector);
+ registry.setUpkeepCheckData(linkUpkeepID, new bytes(10_000));
+ }
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepCheckData(linkUpkeepID, hex"1234");
+ }
+
+ function test_UpdateOffchainConfig_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepCheckDataSet(linkUpkeepID, hex"1234");
+ registry.setUpkeepCheckData(linkUpkeepID, hex"1234");
+
+ assertEq(registry.getUpkeep(linkUpkeepID).checkData, hex"1234");
+ }
+
+ function test_UpdateOffchainConfigOnPausedUpkeep_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ registry.pauseUpkeep(linkUpkeepID);
+
+ vm.expectEmit();
+ emit UpkeepCheckDataSet(linkUpkeepID, hex"1234");
+ registry.setUpkeepCheckData(linkUpkeepID, hex"1234");
+
+ assertTrue(registry.getUpkeep(linkUpkeepID).paused);
+ assertEq(registry.getUpkeep(linkUpkeepID).checkData, hex"1234");
+ }
+}
+
+contract SetUpkeepGasLimit is SetUp {
+ event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID + 1, 1230000);
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID, 1230000);
+ }
+
+ function test_RevertsWhen_NewGasLimitOutOfRange() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.GasLimitOutsideRange.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID, 300);
+
+ vm.expectRevert(Registry.GasLimitOutsideRange.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID, 3000000000);
+ }
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepGasLimit(linkUpkeepID, 1230000);
+ }
+
+ function test_UpdateGasLimit_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepGasLimitSet(linkUpkeepID, 1230000);
+ registry.setUpkeepGasLimit(linkUpkeepID, 1230000);
+
+ assertEq(registry.getUpkeep(linkUpkeepID).performGas, 1230000);
+ }
+}
+
+contract SetUpkeepOffchainConfig is SetUp {
+ event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepOffchainConfig(linkUpkeepID + 1, hex"1233");
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.setUpkeepOffchainConfig(linkUpkeepID, hex"1234");
+ }
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepOffchainConfig(linkUpkeepID, hex"1234");
+ }
+
+ function test_UpdateOffchainConfig_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepOffchainConfigSet(linkUpkeepID, hex"1234");
+ registry.setUpkeepOffchainConfig(linkUpkeepID, hex"1234");
+
+ assertEq(registry.getUpkeep(linkUpkeepID).offchainConfig, hex"1234");
+ }
+}
+
+contract SetUpkeepTriggerConfig is SetUp {
+ event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig);
+
+ function test_RevertsWhen_InvalidUpkeepId() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepTriggerConfig(linkUpkeepID + 1, hex"1233");
+ }
+
+ function test_RevertsWhen_UpkeepAlreadyCanceled() external {
+ vm.startPrank(UPKEEP_ADMIN);
+ registry.cancelUpkeep(linkUpkeepID);
+
+ vm.expectRevert(Registry.UpkeepCancelled.selector);
+ registry.setUpkeepTriggerConfig(linkUpkeepID, hex"1234");
+ }
+
+ function test_RevertsWhen_NotCalledByAdmin() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByAdmin.selector);
+ registry.setUpkeepTriggerConfig(linkUpkeepID, hex"1234");
+ }
+
+ function test_UpdateTriggerConfig_CalledByAdmin() external {
+ vm.startPrank(UPKEEP_ADMIN);
+
+ vm.expectEmit();
+ emit UpkeepTriggerConfigSet(linkUpkeepID, hex"1234");
+ registry.setUpkeepTriggerConfig(linkUpkeepID, hex"1234");
+
+ assertEq(registry.getUpkeepTriggerConfig(linkUpkeepID), hex"1234");
+ }
+}
+
+contract TransferPayeeship is SetUp {
+ event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to);
+
+ function test_RevertsWhen_NotCalledByPayee() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(Registry.OnlyCallableByPayee.selector);
+ registry.transferPayeeship(TRANSMITTERS[0], randomAddress());
+ }
+
+ function test_RevertsWhen_TransferToSelf() external {
+ registry.setPayees(PAYEES);
+ vm.startPrank(PAYEES[0]);
+
+ vm.expectRevert(Registry.ValueNotChanged.selector);
+ registry.transferPayeeship(TRANSMITTERS[0], PAYEES[0]);
+ }
+
+ function test_Transfer_DoesNotChangePayee() external {
+ registry.setPayees(PAYEES);
+
+ vm.startPrank(PAYEES[0]);
+
+ registry.transferPayeeship(TRANSMITTERS[0], randomAddress());
+
+ (, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[0]);
+ assertEq(PAYEES[0], payee);
+ }
+
+ function test_EmitEvent_CalledByPayee() external {
+ registry.setPayees(PAYEES);
+
+ vm.startPrank(PAYEES[0]);
+ address newPayee = randomAddress();
+
+ vm.expectEmit();
+ emit PayeeshipTransferRequested(TRANSMITTERS[0], PAYEES[0], newPayee);
+ registry.transferPayeeship(TRANSMITTERS[0], newPayee);
+
+ // transferring to the same propose payee won't yield another event
+ vm.recordLogs();
+ registry.transferPayeeship(TRANSMITTERS[0], newPayee);
+ Vm.Log[] memory entries = vm.getRecordedLogs();
+ assertEq(0, entries.length);
+ }
+}
+
+contract AcceptPayeeship is SetUp {
+ event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to);
+
+ function test_RevertsWhen_NotCalledByProposedPayee() external {
+ registry.setPayees(PAYEES);
+
+ vm.startPrank(PAYEES[0]);
+ address newPayee = randomAddress();
+ registry.transferPayeeship(TRANSMITTERS[0], newPayee);
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert(Registry.OnlyCallableByProposedPayee.selector);
+ registry.acceptPayeeship(TRANSMITTERS[0]);
+ }
+
+ function test_PayeeChanged() external {
+ registry.setPayees(PAYEES);
+
+ vm.startPrank(PAYEES[0]);
+ address newPayee = randomAddress();
+ registry.transferPayeeship(TRANSMITTERS[0], newPayee);
+
+ vm.startPrank(newPayee);
+ vm.expectEmit();
+ emit PayeeshipTransferred(TRANSMITTERS[0], PAYEES[0], newPayee);
+ registry.acceptPayeeship(TRANSMITTERS[0]);
+
+ (, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[0]);
+ assertEq(newPayee, payee);
+ }
+}
+
+contract SetPayees is SetUp {
+ event PayeesUpdated(address[] transmitters, address[] payees);
+
+ function test_RevertsWhen_NotCalledByOwner() external {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(bytes("Only callable by owner"));
+ registry.setPayees(NEW_PAYEES);
+ }
+
+ function test_RevertsWhen_PayeesLengthError() external {
+ vm.startPrank(registry.owner());
+
+ address[] memory payees = new address[](5);
+ vm.expectRevert(Registry.ParameterLengthError.selector);
+ registry.setPayees(payees);
+ }
+
+ function test_RevertsWhen_InvalidPayee() external {
+ vm.startPrank(registry.owner());
+
+ NEW_PAYEES[0] = address(0);
+ vm.expectRevert(Registry.InvalidPayee.selector);
+ registry.setPayees(NEW_PAYEES);
+ }
+
+ function test_SetPayees_WhenExistingPayeesAreEmpty() external {
+ (registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+
+ for (uint256 i = 0; i < TRANSMITTERS.length; i++) {
+ (, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[i]);
+ assertEq(address(0), payee);
+ }
+
+ vm.startPrank(registry.owner());
+
+ vm.expectEmit();
+ emit PayeesUpdated(TRANSMITTERS, PAYEES);
+ registry.setPayees(PAYEES);
+ for (uint256 i = 0; i < TRANSMITTERS.length; i++) {
+ (bool active, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[i]);
+ assertTrue(active);
+ assertEq(PAYEES[i], payee);
+ }
+ }
+
+ function test_DotNotSetPayeesToIgnoredAddress() external {
+ address IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
+ (registry, ) = deployAndConfigureZKSyncRegistryAndRegistrar(AutoBase.PayoutMode.ON_CHAIN);
+ PAYEES[0] = IGNORE_ADDRESS;
+
+ registry.setPayees(PAYEES);
+ (bool active, , , , address payee) = registry.getTransmitterInfo(TRANSMITTERS[0]);
+ assertTrue(active);
+ assertEq(address(0), payee);
+
+ (active, , , , payee) = registry.getTransmitterInfo(TRANSMITTERS[1]);
+ assertTrue(active);
+ assertEq(PAYEES[1], payee);
+ }
+}
+
+contract GetActiveUpkeepIDs is SetUp {
+ function test_RevertsWhen_IndexOutOfRange() external {
+ vm.expectRevert(Registry.IndexOutOfRange.selector);
+ registry.getActiveUpkeepIDs(5, 0);
+
+ vm.expectRevert(Registry.IndexOutOfRange.selector);
+ registry.getActiveUpkeepIDs(6, 0);
+ }
+
+ function test_ReturnsAllUpkeeps_WhenMaxCountIsZero() external {
+ uint256[] memory uids = registry.getActiveUpkeepIDs(0, 0);
+ assertEq(5, uids.length);
+
+ uids = registry.getActiveUpkeepIDs(2, 0);
+ assertEq(3, uids.length);
+ }
+
+ function test_ReturnsAllRemainingUpkeeps_WhenMaxCountIsTooLarge() external {
+ uint256[] memory uids = registry.getActiveUpkeepIDs(2, 20);
+ assertEq(3, uids.length);
+ }
+
+ function test_ReturnsUpkeeps_BoundByMaxCount() external {
+ uint256[] memory uids = registry.getActiveUpkeepIDs(1, 2);
+ assertEq(2, uids.length);
+ assertEq(uids[0], linkUpkeepID2);
+ assertEq(uids[1], usdUpkeepID18);
+ }
+}
diff --git a/contracts/src/v0.8/automation/testhelpers/UpkeepCounterNew.sol b/contracts/src/v0.8/automation/testhelpers/UpkeepCounterNew.sol
new file mode 100644
index 00000000000..76b38776893
--- /dev/null
+++ b/contracts/src/v0.8/automation/testhelpers/UpkeepCounterNew.sol
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.16;
+
+contract UpkeepCounterNew {
+ event PerformingUpkeep(
+ address indexed from,
+ uint256 initialTimestamp,
+ uint256 lastTimestamp,
+ uint256 previousBlock,
+ uint256 counter
+ );
+ error InvalidCaller(address caller, address forwarder);
+
+ uint256 public testRange;
+ uint256 public interval;
+ uint256 public lastTimestamp;
+ uint256 public previousPerformBlock;
+ uint256 public initialTimestamp;
+ uint256 public counter;
+ bool public useMoreCheckGas;
+ bool public useMorePerformGas;
+ bool public useMorePerformData;
+ uint256 public checkGasToBurn;
+ uint256 public performGasToBurn;
+ bytes public data;
+ bytes public dataCopy;
+ bool public trickSimulation = false;
+ address public forwarder;
+
+ constructor() {
+ testRange = 1000000;
+ interval = 40;
+ previousPerformBlock = 0;
+ lastTimestamp = block.timestamp;
+ initialTimestamp = 0;
+ counter = 0;
+ useMoreCheckGas = false;
+ useMorePerformData = false;
+ useMorePerformGas = false;
+ checkGasToBurn = 9700000;
+ performGasToBurn = 7700000;
+ }
+
+ function setPerformGasToBurn(uint256 _performGasToBurn) external {
+ performGasToBurn = _performGasToBurn;
+ }
+
+ function setCheckGasToBurn(uint256 _checkGasToBurn) external {
+ checkGasToBurn = _checkGasToBurn;
+ }
+
+ function setUseMoreCheckGas(bool _useMoreCheckGas) external {
+ useMoreCheckGas = _useMoreCheckGas;
+ }
+
+ function setUseMorePerformGas(bool _useMorePerformGas) external {
+ useMorePerformGas = _useMorePerformGas;
+ }
+
+ function setUseMorePerformData(bool _useMorePerformData) external {
+ useMorePerformData = _useMorePerformData;
+ }
+
+ function setData(bytes calldata _data) external {
+ data = _data;
+ }
+
+ function checkUpkeep(bytes calldata) external view returns (bool, bytes memory) {
+ if (useMoreCheckGas) {
+ uint256 startGas = gasleft();
+ while (startGas - gasleft() < checkGasToBurn) {} // burn gas
+ }
+
+ if (useMorePerformData) {
+ return (eligible(), data);
+ }
+ return (eligible(), "");
+ }
+
+ function setTrickSimulation(bool _trickSimulation) external {
+ trickSimulation = _trickSimulation;
+ }
+
+ function performUpkeep(bytes calldata performData) external {
+ if (trickSimulation && tx.origin == address(0)) {
+ return;
+ }
+
+ if (msg.sender != forwarder) {
+ revert InvalidCaller(msg.sender, forwarder);
+ }
+
+ if (useMorePerformGas) {
+ uint256 startGas = gasleft();
+ while (startGas - gasleft() < performGasToBurn) {} // burn gas
+ }
+
+ if (initialTimestamp == 0) {
+ initialTimestamp = block.timestamp;
+ }
+ lastTimestamp = block.timestamp;
+ counter = counter + 1;
+ dataCopy = performData;
+ emit PerformingUpkeep(tx.origin, initialTimestamp, lastTimestamp, previousPerformBlock, counter);
+ previousPerformBlock = lastTimestamp;
+ }
+
+ function eligible() public view returns (bool) {
+ if (initialTimestamp == 0) {
+ return true;
+ }
+
+ return (block.timestamp - initialTimestamp) < testRange && (block.timestamp - lastTimestamp) >= interval;
+ }
+
+ function setSpread(uint256 _testRange, uint256 _interval) external {
+ testRange = _testRange;
+ interval = _interval;
+ initialTimestamp = 0;
+ counter = 0;
+ }
+
+ function setForwarder(address _forwarder) external {
+ forwarder = _forwarder;
+ }
+}
diff --git a/contracts/src/v0.8/automation/upkeeps/CronUpkeep.sol b/contracts/src/v0.8/automation/upkeeps/CronUpkeep.sol
index 614b84635ab..b9eda1f4001 100644
--- a/contracts/src/v0.8/automation/upkeeps/CronUpkeep.sol
+++ b/contracts/src/v0.8/automation/upkeeps/CronUpkeep.sol
@@ -18,12 +18,12 @@
pragma solidity 0.8.6;
-import "@openzeppelin/contracts/security/Pausable.sol";
-import "@openzeppelin/contracts/proxy/Proxy.sol";
-import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
-import "../../shared/access/ConfirmedOwner.sol";
-import "../KeeperBase.sol";
-import "../interfaces/KeeperCompatibleInterface.sol";
+import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol";
+import {Proxy} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/proxy/Proxy.sol";
+import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
+import {KeeperBase as KeeperBase} from "../KeeperBase.sol";
+import {KeeperCompatibleInterface as KeeperCompatibleInterface} from "../interfaces/KeeperCompatibleInterface.sol";
import {Cron as CronInternal, Spec} from "../libraries/internal/Cron.sol";
import {Cron as CronExternal} from "../libraries/external/Cron.sol";
diff --git a/contracts/src/v0.8/automation/upkeeps/CronUpkeepDelegate.sol b/contracts/src/v0.8/automation/upkeeps/CronUpkeepDelegate.sol
index ec2c2a0fd91..ed8d031c86f 100644
--- a/contracts/src/v0.8/automation/upkeeps/CronUpkeepDelegate.sol
+++ b/contracts/src/v0.8/automation/upkeeps/CronUpkeepDelegate.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.6;
-import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
+import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
import {Cron, Spec} from "../libraries/internal/Cron.sol";
/**
diff --git a/contracts/src/v0.8/automation/upkeeps/CronUpkeepFactory.sol b/contracts/src/v0.8/automation/upkeeps/CronUpkeepFactory.sol
index cd9ae5d7a92..2b6e97e4d03 100644
--- a/contracts/src/v0.8/automation/upkeeps/CronUpkeepFactory.sol
+++ b/contracts/src/v0.8/automation/upkeeps/CronUpkeepFactory.sol
@@ -2,9 +2,9 @@
pragma solidity 0.8.6;
-import "./CronUpkeep.sol";
-import "./CronUpkeepDelegate.sol";
-import "../../shared/access/ConfirmedOwner.sol";
+import {CronUpkeep} from "./CronUpkeep.sol";
+import {CronUpkeepDelegate} from "./CronUpkeepDelegate.sol";
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
import {Spec, Cron as CronExternal} from "../libraries/external/Cron.sol";
/**
diff --git a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol
index 5d8a8d58c8d..824bce711bf 100644
--- a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol
+++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol
@@ -61,6 +61,7 @@ contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInter
error InvalidWatchList();
error InvalidChainSelector();
error DuplicateAddress(address duplicate);
+ error ReentrantCall();
struct MonitoredAddress {
uint96 minBalance;
@@ -94,6 +95,8 @@ contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInter
/// whenever a new one is deployed with the same dstChainSelector.
EnumerableMap.UintToAddressMap private s_onRampAddresses;
+ bool private reentrancyGuard;
+
/// @param admin is the administrator address of this contract
/// @param linkToken the LINK token address
/// @param minWaitPeriodSeconds represents the amount of time that has to wait a contract to be funded
@@ -116,6 +119,7 @@ contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInter
setMaxPerform(maxPerform);
setMaxCheck(maxCheck);
setUpkeepInterval(upkeepInterval);
+ reentrancyGuard = false;
}
/// @notice Sets the list of subscriptions to watch and their funding parameters
@@ -259,7 +263,7 @@ contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInter
/// @notice tries to fund an array of target addresses, checking if they're underfunded in the process
/// @param targetAddresses is an array of contract addresses to be funded in case they're underfunded
- function topUp(address[] memory targetAddresses) public whenNotPaused {
+ function topUp(address[] memory targetAddresses) public whenNotPaused nonReentrant {
MonitoredAddress memory contractToFund;
uint256 minWaitPeriod = s_minWaitPeriodSeconds;
uint256 localBalance = i_linkToken.balanceOf(address(this));
@@ -457,6 +461,13 @@ contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInter
_;
}
+ modifier nonReentrant() {
+ if (reentrancyGuard) revert ReentrantCall();
+ reentrancyGuard = true;
+ _;
+ reentrancyGuard = false;
+ }
+
/// @notice Pause the contract, which prevents executing performUpkeep
function pause() external onlyRole(ADMIN_ROLE) {
_pause();
diff --git a/contracts/src/v0.8/automation/v2_2/AutomationRegistry2_2.sol b/contracts/src/v0.8/automation/v2_2/AutomationRegistry2_2.sol
index f0c703679ca..464e8746398 100644
--- a/contracts/src/v0.8/automation/v2_2/AutomationRegistry2_2.sol
+++ b/contracts/src/v0.8/automation/v2_2/AutomationRegistry2_2.sol
@@ -115,7 +115,7 @@ contract AutomationRegistry2_2 is AutomationRegistryBase2_2, OCR2Abstract, Chain
});
uint256 blocknumber = hotVars.chainModule.blockNumber();
- uint256 l1Fee = hotVars.chainModule.getCurrentL1Fee();
+ uint256 l1Fee = hotVars.chainModule.getCurrentL1Fee(msg.data.length);
for (uint256 i = 0; i < report.upkeepIds.length; i++) {
upkeepTransmitInfo[i].upkeep = s_upkeep[report.upkeepIds[i]];
diff --git a/contracts/src/v0.8/automation/v2_3/AutomationRegistry2_3.sol b/contracts/src/v0.8/automation/v2_3/AutomationRegistry2_3.sol
index 6113cbf9fd1..031d7b5dfb8 100644
--- a/contracts/src/v0.8/automation/v2_3/AutomationRegistry2_3.sol
+++ b/contracts/src/v0.8/automation/v2_3/AutomationRegistry2_3.sol
@@ -136,7 +136,7 @@ contract AutomationRegistry2_3 is AutomationRegistryBase2_3, OCR2Abstract, Chain
});
uint256 blocknumber = hotVars.chainModule.blockNumber();
- uint256 l1Fee = hotVars.chainModule.getCurrentL1Fee();
+ uint256 l1Fee = hotVars.chainModule.getCurrentL1Fee(msg.data.length);
for (uint256 i = 0; i < report.upkeepIds.length; i++) {
upkeepTransmitInfo[i].upkeep = s_upkeep[report.upkeepIds[i]];
diff --git a/contracts/src/v0.8/automation/v2_3/AutomationRegistryBase2_3.sol b/contracts/src/v0.8/automation/v2_3/AutomationRegistryBase2_3.sol
index fa8f06ffc02..354a6a9b475 100644
--- a/contracts/src/v0.8/automation/v2_3/AutomationRegistryBase2_3.sol
+++ b/contracts/src/v0.8/automation/v2_3/AutomationRegistryBase2_3.sol
@@ -45,7 +45,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {
// These values are calibrated using hardhat tests which simulate various cases and verify that
// the variables result in accurate estimation
uint256 internal constant REGISTRY_CONDITIONAL_OVERHEAD = 98_200; // Fixed gas overhead for conditional upkeeps
- uint256 internal constant REGISTRY_LOG_OVERHEAD = 122_500; // Fixed gas overhead for log upkeeps
+ uint256 internal constant REGISTRY_LOG_OVERHEAD = 123_500; // 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
diff --git a/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistry2_3.sol b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistry2_3.sol
new file mode 100644
index 00000000000..67a9a56b3d5
--- /dev/null
+++ b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistry2_3.sol
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: BUSL-1.1
+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 {ZKSyncAutomationRegistryBase2_3} from "./ZKSyncAutomationRegistryBase2_3.sol";
+import {ZKSyncAutomationRegistryLogicA2_3} from "./ZKSyncAutomationRegistryLogicA2_3.sol";
+import {ZKSyncAutomationRegistryLogicC2_3} from "./ZKSyncAutomationRegistryLogicC2_3.sol";
+import {Chainable} from "../Chainable.sol";
+import {OCR2Abstract} from "../../shared/ocr2/OCR2Abstract.sol";
+import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol";
+
+/**
+ * @notice Registry for adding work for Chainlink nodes to perform on client
+ * contracts. Clients must support the AutomationCompatibleInterface interface.
+ */
+contract ZKSyncAutomationRegistry2_3 is ZKSyncAutomationRegistryBase2_3, OCR2Abstract, Chainable {
+ using Address for address;
+ using EnumerableSet for EnumerableSet.UintSet;
+ using EnumerableSet for EnumerableSet.AddressSet;
+
+ /**
+ * @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"
+ * KeeperRegistry 2.0.2: pass revert bytes as performData when target contract reverts
+ * fixes issue with arbitrum block number
+ * does an early return in case of stale report instead of revert
+ * KeeperRegistry 2.0.1: implements workaround for buggy migrate function in 1.X
+ * KeeperRegistry 2.0.0: implement OCR interface
+ * KeeperRegistry 1.3.0: split contract into Proxy and Logic
+ * account for Arbitrum and Optimism L1 gas fee
+ * allow users to configure upkeeps
+ * KeeperRegistry 1.2.0: allow funding within performUpkeep
+ * allow configurable registry maxPerformGas
+ * add function to let admin change upkeep gas limit
+ * add minUpkeepSpend requirement
+ * upgrade to solidity v0.8
+ * KeeperRegistry 1.1.0: added flatFeeMicroLink
+ * KeeperRegistry 1.0.0: initial release
+ */
+ string public constant override typeAndVersion = "AutomationRegistry 2.3.0";
+
+ /**
+ * @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(
+ ZKSyncAutomationRegistryLogicA2_3 logicA
+ )
+ ZKSyncAutomationRegistryBase2_3(
+ ZKSyncAutomationRegistryLogicC2_3(address(logicA)).getLinkAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicA)).getLinkUSDFeedAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicA)).getNativeUSDFeedAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicA)).getFastGasFeedAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicA)).getAutomationForwarderLogic(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicA)).getAllowedReadOnlyAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicA)).getPayoutMode(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicA)).getWrappedNativeTokenAddress()
+ )
+ Chainable(address(logicA))
+ {}
+
+ /**
+ * @notice holds the variables used in the transmit function, necessary to avoid stack too deep errors
+ */
+ struct TransmitVars {
+ uint16 numUpkeepsPassedChecks;
+ uint96 totalReimbursement;
+ uint96 totalPremium;
+ }
+
+ // ================================================================
+ // | HOT PATH ACTIONS |
+ // ================================================================
+
+ /**
+ * @inheritdoc OCR2Abstract
+ */
+ function transmit(
+ bytes32[3] calldata reportContext,
+ bytes calldata rawReport,
+ bytes32[] calldata rs,
+ bytes32[] calldata ss,
+ bytes32 rawVs
+ ) external override {
+ // use this msg.data length check to ensure no extra data is included in the call
+ // 4 is first 4 bytes of the keccak-256 hash of the function signature. ss.length == rs.length so use one of them
+ // 4 + (32 * 3) + (rawReport.length + 32 + 32) + (32 * rs.length + 32 + 32) + (32 * ss.length + 32 + 32) + 32
+ uint256 requiredLength = 324 + rawReport.length + 64 * rs.length;
+ if (msg.data.length != requiredLength) revert InvalidDataLength();
+ HotVars memory hotVars = s_hotVars;
+
+ if (hotVars.paused) revert RegistryPaused();
+ if (!s_transmitters[msg.sender].active) revert OnlyActiveTransmitters();
+
+ // Verify signatures
+ if (s_latestConfigDigest != reportContext[0]) revert ConfigDigestMismatch();
+ if (rs.length != hotVars.f + 1 || rs.length != ss.length) revert IncorrectNumberOfSignatures();
+ _verifyReportSignature(reportContext, rawReport, rs, ss, rawVs);
+
+ Report memory report = _decodeReport(rawReport);
+
+ uint40 epochAndRound = uint40(uint256(reportContext[1]));
+ uint32 epoch = uint32(epochAndRound >> 8);
+
+ _handleReport(hotVars, report);
+
+ if (epoch > hotVars.latestEpoch) {
+ s_hotVars.latestEpoch = epoch;
+ }
+ }
+
+ /**
+ * @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)
+ * @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) private {
+ UpkeepTransmitInfo[] memory upkeepTransmitInfo = new UpkeepTransmitInfo[](report.upkeepIds.length);
+ TransmitVars memory transmitVars = TransmitVars({
+ numUpkeepsPassedChecks: 0,
+ totalReimbursement: 0,
+ totalPremium: 0
+ });
+
+ uint256 blocknumber = hotVars.chainModule.blockNumber();
+ uint256 gasOverhead;
+
+ for (uint256 i = 0; i < report.upkeepIds.length; i++) {
+ upkeepTransmitInfo[i].upkeep = s_upkeep[report.upkeepIds[i]];
+ upkeepTransmitInfo[i].triggerType = _getTriggerType(report.upkeepIds[i]);
+
+ (upkeepTransmitInfo[i].earlyChecksPassed, upkeepTransmitInfo[i].dedupID) = _prePerformChecks(
+ report.upkeepIds[i],
+ blocknumber,
+ report.triggers[i],
+ upkeepTransmitInfo[i],
+ hotVars
+ );
+
+ if (upkeepTransmitInfo[i].earlyChecksPassed) {
+ transmitVars.numUpkeepsPassedChecks += 1;
+ } else {
+ continue;
+ }
+
+ // Actually perform the target upkeep
+ (upkeepTransmitInfo[i].performSuccess, upkeepTransmitInfo[i].gasUsed) = _performUpkeep(
+ upkeepTransmitInfo[i].upkeep.forwarder,
+ report.gasLimits[i],
+ report.performDatas[i]
+ );
+
+ // Store last perform block number / deduping key for upkeep
+ _updateTriggerMarker(report.upkeepIds[i], blocknumber, upkeepTransmitInfo[i]);
+
+ if (upkeepTransmitInfo[i].triggerType == Trigger.CONDITION) {
+ gasOverhead += REGISTRY_CONDITIONAL_OVERHEAD;
+ } else {
+ gasOverhead += REGISTRY_LOG_OVERHEAD;
+ }
+ }
+ // No upkeeps to be performed in this report
+ if (transmitVars.numUpkeepsPassedChecks == 0) {
+ return;
+ }
+
+ gasOverhead +=
+ 16 *
+ msg.data.length +
+ ACCOUNTING_FIXED_GAS_OVERHEAD +
+ (REGISTRY_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1));
+ 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({
+ gasLimit: upkeepTransmitInfo[i].gasUsed,
+ gasOverhead: gasOverhead,
+ l1CostWei: 0,
+ fastGasWei: report.fastGasWei,
+ linkUSD: report.linkUSD,
+ nativeUSD: nativeUSD,
+ billingToken: upkeepTransmitInfo[i].upkeep.billingToken,
+ billingTokenParams: billingTokenParams,
+ isTransaction: true
+ }),
+ report.upkeepIds[i],
+ upkeepTransmitInfo[i].upkeep
+ );
+ transmitVars.totalPremium += receipt.premiumInJuels;
+ transmitVars.totalReimbursement += receipt.gasReimbursementInJuels;
+
+ emit UpkeepPerformed(
+ report.upkeepIds[i],
+ upkeepTransmitInfo[i].performSuccess,
+ receipt.gasChargeInBillingToken + receipt.premiumInBillingToken,
+ upkeepTransmitInfo[i].gasUsed,
+ gasOverhead,
+ report.triggers[i]
+ );
+ }
+ }
+ }
+ // record payments to NOPs, all in LINK
+ s_transmitters[msg.sender].balance += transmitVars.totalReimbursement;
+ s_hotVars.totalPremium += transmitVars.totalPremium;
+ s_reserveAmounts[IERC20(address(i_link))] += transmitVars.totalReimbursement + transmitVars.totalPremium;
+ }
+
+ // ================================================================
+ // | 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,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfigBytes,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) external override {
+ (OnchainConfig memory config, IERC20[] memory billingTokens, BillingConfig[] memory billingConfigs) = abi.decode(
+ onchainConfigBytes,
+ (OnchainConfig, IERC20[], BillingConfig[])
+ );
+
+ setConfigTypeSafe(
+ signers,
+ transmitters,
+ f,
+ config,
+ offchainConfigVersion,
+ offchainConfig,
+ billingTokens,
+ billingConfigs
+ );
+ }
+
+ /**
+ * @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,
+ uint8 f,
+ OnchainConfig memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig,
+ IERC20[] memory billingTokens,
+ BillingConfig[] memory billingConfigs
+ ) public onlyOwner {
+ if (signers.length > MAX_NUM_ORACLES) revert TooManyOracles();
+ if (f == 0) revert IncorrectNumberOfFaultyOracles();
+ if (signers.length != transmitters.length || signers.length <= 3 * f) revert IncorrectNumberOfSigners();
+ if (billingTokens.length != billingConfigs.length) revert ParameterLengthError();
+ // set billing config for tokens
+ _setBillingConfig(billingTokens, billingConfigs);
+
+ _updateTransmitters(signers, transmitters);
+
+ s_hotVars = HotVars({
+ f: f,
+ stalenessSeconds: onchainConfig.stalenessSeconds,
+ gasCeilingMultiplier: onchainConfig.gasCeilingMultiplier,
+ paused: s_hotVars.paused,
+ reentrancyGuard: s_hotVars.reentrancyGuard,
+ totalPremium: s_hotVars.totalPremium,
+ latestEpoch: 0, // DON restarts epoch
+ reorgProtectionEnabled: onchainConfig.reorgProtectionEnabled,
+ chainModule: onchainConfig.chainModule
+ });
+
+ uint32 previousConfigBlockNumber = s_storage.latestConfigBlockNumber;
+ uint32 newLatestConfigBlockNumber = uint32(onchainConfig.chainModule.blockNumber());
+ uint32 newConfigCount = s_storage.configCount + 1;
+
+ s_storage = Storage({
+ checkGasLimit: onchainConfig.checkGasLimit,
+ maxPerformGas: onchainConfig.maxPerformGas,
+ transcoder: onchainConfig.transcoder,
+ maxCheckDataSize: onchainConfig.maxCheckDataSize,
+ maxPerformDataSize: onchainConfig.maxPerformDataSize,
+ maxRevertDataSize: onchainConfig.maxRevertDataSize,
+ upkeepPrivilegeManager: onchainConfig.upkeepPrivilegeManager,
+ financeAdmin: onchainConfig.financeAdmin,
+ nonce: s_storage.nonce,
+ configCount: newConfigCount,
+ latestConfigBlockNumber: newLatestConfigBlockNumber
+ });
+ s_fallbackGasPrice = onchainConfig.fallbackGasPrice;
+ s_fallbackLinkPrice = onchainConfig.fallbackLinkPrice;
+ s_fallbackNativePrice = onchainConfig.fallbackNativePrice;
+
+ bytes memory onchainConfigBytes = abi.encode(onchainConfig);
+
+ s_latestConfigDigest = _configDigestFromConfigData(
+ block.chainid,
+ address(this),
+ s_storage.configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfigBytes,
+ offchainConfigVersion,
+ offchainConfig
+ );
+
+ for (uint256 idx = s_registrars.length(); idx > 0; idx--) {
+ s_registrars.remove(s_registrars.at(idx - 1));
+ }
+
+ for (uint256 idx = 0; idx < onchainConfig.registrars.length; idx++) {
+ s_registrars.add(onchainConfig.registrars[idx]);
+ }
+
+ emit ConfigSet(
+ previousConfigBlockNumber,
+ s_latestConfigDigest,
+ s_storage.configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfigBytes,
+ offchainConfigVersion,
+ offchainConfig
+ );
+ }
+
+ /**
+ * @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
+ view
+ override
+ returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest)
+ {
+ return (s_storage.configCount, s_storage.latestConfigBlockNumber, s_latestConfigDigest);
+ }
+
+ /**
+ * @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
+ view
+ override
+ returns (bool scanLogs, bytes32 configDigest, uint32 epoch)
+ {
+ return (false, s_latestConfigDigest, s_hotVars.latestEpoch);
+ }
+}
diff --git a/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryBase2_3.sol b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryBase2_3.sol
new file mode 100644
index 00000000000..41097af7f26
--- /dev/null
+++ b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryBase2_3.sol
@@ -0,0 +1,1197 @@
+// SPDX-License-Identifier: BUSL-1.1
+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 {StreamsLookupCompatibleInterface} from "../interfaces/StreamsLookupCompatibleInterface.sol";
+import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol";
+import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol";
+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 {IChainModule} from "../interfaces/IChainModule.sol";
+import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.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
+ * AutomationRegistry and AutomationRegistryLogic
+ * @dev all errors, events, and internal functions should live here
+ */
+// solhint-disable-next-line max-states-count
+abstract contract ZKSyncAutomationRegistryBase2_3 is ConfirmedOwner {
+ using Address for address;
+ using EnumerableSet for EnumerableSet.UintSet;
+ using EnumerableSet for EnumerableSet.AddressSet;
+
+ address internal constant ZERO_ADDRESS = address(0);
+ address internal constant IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
+ bytes4 internal constant CHECK_SELECTOR = KeeperCompatibleInterface.checkUpkeep.selector;
+ bytes4 internal constant PERFORM_SELECTOR = KeeperCompatibleInterface.performUpkeep.selector;
+ bytes4 internal constant CHECK_CALLBACK_SELECTOR = StreamsLookupCompatibleInterface.checkCallback.selector;
+ bytes4 internal constant CHECK_LOG_SELECTOR = ILogAutomation.checkLog.selector;
+ uint256 internal constant PERFORM_GAS_MIN = 2_300;
+ uint256 internal constant CANCELLATION_DELAY = 50;
+ uint32 internal constant UINT32_MAX = type(uint32).max;
+ // The first byte of the mask can be 0, because we only ever have 31 oracles
+ uint256 internal constant ORACLE_MASK = 0x0001010101010101010101010101010101010101010101010101010101010101;
+ 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 simulate various cases and verify that
+ // the variables result in accurate estimation
+ uint256 internal constant REGISTRY_CONDITIONAL_OVERHEAD = 98_200; // Fixed gas overhead for conditional upkeeps
+ uint256 internal constant REGISTRY_LOG_OVERHEAD = 122_500; // Fixed gas overhead for log upkeeps
+ uint256 internal constant REGISTRY_PER_SIGNER_GAS_OVERHEAD = 5_600; // Value scales with f
+
+ // Next block of constants are used in actual payment calculation. We calculate the exact gas used within the
+ // 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 = 51_000; // Fixed overhead per tx
+ uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 20_000; // Overhead per upkeep performed in batch
+
+ LinkTokenInterface internal immutable i_link;
+ AggregatorV3Interface internal immutable i_linkUSDFeed;
+ AggregatorV3Interface internal immutable i_nativeUSDFeed;
+ 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
+ * is stored compactly. Rest of the storage layout is not of much concern as transmit is the only hot path
+ */
+
+ // Upkeep storage
+ EnumerableSet.UintSet internal s_upkeepIDs;
+ mapping(uint256 => Upkeep) internal s_upkeep; // accessed during transmit
+ mapping(uint256 => address) internal s_upkeepAdmin;
+ mapping(uint256 => address) internal s_proposedAdmin;
+ mapping(uint256 => bytes) internal s_checkData;
+ mapping(bytes32 => bool) internal s_dedupKeys;
+ // Registry config and state
+ EnumerableSet.AddressSet internal s_registrars;
+ mapping(address => Transmitter) internal s_transmitters;
+ 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
+ HotVars internal s_hotVars; // Mixture of config and state, used in transmit
+ Storage internal s_storage; // Mixture of config and state, not used in transmit
+ uint256 internal s_fallbackGasPrice;
+ uint256 internal s_fallbackLinkPrice;
+ uint256 internal s_fallbackNativePrice;
+ 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();
+ error CheckDataExceedsLimit();
+ error ConfigDigestMismatch();
+ error DuplicateEntry();
+ error DuplicateSigners();
+ error GasLimitCanOnlyIncrease();
+ error GasLimitOutsideRange();
+ error IncorrectNumberOfFaultyOracles();
+ error IncorrectNumberOfSignatures();
+ error IncorrectNumberOfSigners();
+ error IndexOutOfRange();
+ error InsufficientBalance(uint256 available, uint256 requested);
+ error InsufficientLinkLiquidity();
+ error InvalidDataLength();
+ error InvalidFeed();
+ error InvalidTrigger();
+ error InvalidPayee();
+ error InvalidRecipient();
+ error InvalidReport();
+ error InvalidSigner();
+ error InvalidToken();
+ error InvalidTransmitter();
+ error InvalidTriggerType();
+ error MigrationNotPermitted();
+ error MustSettleOffchain();
+ error MustSettleOnchain();
+ error NotAContract();
+ error OnlyActiveSigners();
+ error OnlyActiveTransmitters();
+ error OnlyCallableByAdmin();
+ error OnlyCallableByLINKToken();
+ error OnlyCallableByOwnerOrAdmin();
+ error OnlyCallableByOwnerOrRegistrar();
+ error OnlyCallableByPayee();
+ error OnlyCallableByProposedAdmin();
+ error OnlyCallableByProposedPayee();
+ error OnlyCallableByUpkeepPrivilegeManager();
+ error OnlyFinanceAdmin();
+ error OnlyPausedUpkeep();
+ error OnlySimulatedBackend();
+ error OnlyUnpausedUpkeep();
+ error ParameterLengthError();
+ error ReentrantCall();
+ error RegistryPaused();
+ error RepeatedSigner();
+ error RepeatedTransmitter();
+ error TargetCheckReverted(bytes reason);
+ error TooManyOracles();
+ error TranscoderNotSet();
+ error TransferFailed();
+ error UpkeepAlreadyExists();
+ error UpkeepCancelled();
+ error UpkeepNotCanceled();
+ error UpkeepNotNeeded();
+ error ValueNotChanged();
+ error ZeroAddressNotAllowed();
+
+ enum MigrationPermission {
+ NONE,
+ OUTGOING,
+ INCOMING,
+ BIDIRECTIONAL
+ }
+
+ enum Trigger {
+ CONDITION,
+ LOG
+ }
+
+ enum UpkeepFailureReason {
+ NONE,
+ UPKEEP_CANCELLED,
+ UPKEEP_PAUSED,
+ TARGET_CHECK_REVERTED,
+ UPKEEP_NOT_NEEDED,
+ PERFORM_DATA_EXCEEDS_LIMIT,
+ INSUFFICIENT_BALANCE,
+ CALLBACK_REVERTED,
+ REVERT_DATA_EXCEEDS_LIMIT,
+ REGISTRY_PAUSED
+ }
+
+ enum PayoutMode {
+ ON_CHAIN,
+ OFF_CHAIN
+ }
+
+ /**
+ * @notice OnchainConfig of the registry
+ * @dev used only in setConfig()
+ * @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 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
+ * @member reorgProtectionEnabled if this registry enables re-org protection checks
+ * @member chainModule the chain specific module
+ */
+ struct OnchainConfig {
+ uint32 checkGasLimit;
+ 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[] registrars;
+ IChainModule chainModule;
+ }
+
+ /**
+ * @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, 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;
+ // 2 bytes left in 1st EVM word - read in transmit path
+ uint128 amountSpent;
+ uint96 balance;
+ uint32 lastPerformedBlockNumber;
+ // 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 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 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 {
+ address transcoder; // Address of transcoder contract used in migrations
+ 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
+ // 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
+ 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
+ // 4 bytes left in 3rd EVM word
+ }
+
+ /// @dev Report transmitted by OCR to transmit function
+ struct Report {
+ uint256 fastGasWei;
+ uint256 linkUSD;
+ uint256[] upkeepIds;
+ uint256[] gasLimits;
+ bytes[] triggers;
+ bytes[] performDatas;
+ }
+
+ /**
+ * @dev This struct is used to maintain run time information about an upkeep in transmit function
+ * @member upkeep the upkeep struct
+ * @member earlyChecksPassed whether the upkeep passed early checks before perform
+ * @member performSuccess whether the perform was successful
+ * @member triggerType the type of trigger
+ * @member gasUsed gasUsed by this upkeep in perform
+ * @member dedupID unique ID used to dedup an upkeep/trigger combo
+ */
+ struct UpkeepTransmitInfo {
+ Upkeep upkeep;
+ bool earlyChecksPassed;
+ bool performSuccess;
+ Trigger triggerType;
+ uint256 gasUsed;
+ 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;
+ uint96 balance;
+ uint96 lastCollected;
+ }
+
+ struct TransmitterPayeeInfo {
+ address transmitterAddress;
+ address payeeAddress;
+ }
+
+ struct Signer {
+ bool active;
+ // Index of oracle in s_signersList/s_transmittersList
+ uint8 index;
+ }
+
+ /**
+ * @notice the trigger structure conditional trigger type
+ */
+ struct ConditionalTrigger {
+ uint32 blockNum;
+ bytes32 blockHash;
+ }
+
+ /**
+ * @notice the trigger structure of log upkeeps
+ * @dev NOTE that blockNum / blockHash describe the block used for the callback,
+ * not necessarily the block number that the log was emitted in!!!!
+ */
+ struct LogTrigger {
+ bytes32 logBlockHash;
+ bytes32 txHash;
+ uint32 logIndex;
+ uint32 blockNum;
+ bytes32 blockHash;
+ }
+
+ /**
+ * @notice the billing config of a token
+ * @dev this is a storage struct
+ */
+ // solhint-disable-next-line gas-struct-packing
+ struct BillingConfig {
+ uint32 gasFeePPB;
+ uint24 flatFeeMilliCents; // min fee is $0.00001, max fee is $167
+ AggregatorV3Interface priceFeed;
+ uint8 decimals;
+ // 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 {
+ uint8 decimals;
+ uint32 gasFeePPB;
+ uint24 flatFeeMilliCents;
+ uint256 priceUSD;
+ }
+
+ /**
+ * @notice struct containing price & payment information used in calculating payment amount
+ * @member gasLimit the amount of gas used
+ * @member gasOverhead the amount of gas overhead
+ * @member l1CostWei the amount to be charged for L1 fee in wei
+ * @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 {
+ uint256 gasLimit;
+ uint256 gasOverhead;
+ uint256 l1CostWei;
+ uint256 fastGasWei;
+ uint256 linkUSD;
+ uint256 nativeUSD;
+ IERC20 billingToken;
+ BillingTokenPaymentParams billingTokenParams;
+ bool isTransaction;
+ }
+
+ /**
+ * @notice struct containing receipt information about a payment or cost estimation
+ * @member gasChargeInBillingToken the amount to charge a user for gas spent using the billing token's native decimals
+ * @member premiumInBillingToken the premium charged to the user, shared between all nodes, using the billing token's native decimals
+ * @member gasReimbursementInJuels the amount to reimburse a node for gas spent
+ * @member premiumInJuels the premium paid to NOPs, shared between all nodes
+ */
+ // solhint-disable-next-line gas-struct-packing
+ struct PaymentReceipt {
+ uint96 gasChargeInBillingToken;
+ uint96 premiumInBillingToken;
+ // one word ends
+ uint96 gasReimbursementInJuels;
+ uint96 premiumInJuels;
+ // second word ends
+ IERC20 billingToken;
+ uint96 linkUSD;
+ // third word ends
+ uint96 nativeUSD;
+ uint96 billingUSD;
+ // fourth word ends
+ }
+
+ 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);
+ event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to);
+ event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee);
+ event ReorgedUpkeepReport(uint256 indexed id, bytes trigger);
+ event StaleUpkeepReport(uint256 indexed id, bytes trigger);
+ event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to);
+ event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to);
+ event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight);
+ event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData);
+ event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit);
+ event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination);
+ event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig);
+ event UpkeepPaused(uint256 indexed id);
+ event UpkeepPerformed(
+ uint256 indexed id,
+ bool indexed success,
+ uint96 totalPayment,
+ uint256 gasUsed,
+ uint256 gasOverhead,
+ bytes trigger
+ );
+ event UpkeepCharged(uint256 indexed id, PaymentReceipt receipt);
+ event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig);
+ event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom);
+ event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin);
+ event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig);
+ event UpkeepUnpaused(uint256 indexed id);
+ event Unpaused(address account);
+
+ /**
+ * @param link address of the LINK Token
+ * @param linkUSDFeed address of the LINK/USD price feed
+ * @param nativeUSDFeed address of the Native/USD price feed
+ * @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,
+ address linkUSDFeed,
+ address nativeUSDFeed,
+ address fastGasFeed,
+ address automationForwarderLogic,
+ address allowedReadOnlyAddress,
+ PayoutMode payoutMode,
+ address wrappedNativeTokenAddress
+ ) ConfirmedOwner(msg.sender) {
+ i_link = LinkTokenInterface(link);
+ i_linkUSDFeed = AggregatorV3Interface(linkUSDFeed);
+ i_nativeUSDFeed = AggregatorV3Interface(nativeUSDFeed);
+ 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();
+ }
+ }
+
+ // ================================================================
+ // | INTERNAL FUNCTIONS ONLY |
+ // ================================================================
+
+ /**
+ * @dev creates a new upkeep with the given fields
+ * @param id the id of the upkeep
+ * @param upkeep the upkeep to create
+ * @param admin address to cancel upkeep and withdraw remaining funds
+ * @param checkData data which is passed to user's checkUpkeep
+ * @param triggerConfig the trigger config for this upkeep
+ * @param offchainConfig the off-chain config of this upkeep
+ */
+ function _createUpkeep(
+ uint256 id,
+ Upkeep memory upkeep,
+ address admin,
+ bytes memory checkData,
+ bytes memory triggerConfig,
+ bytes memory offchainConfig
+ ) internal {
+ if (s_hotVars.paused) revert RegistryPaused();
+ if (checkData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit();
+ 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[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] + upkeep.balance;
+ s_upkeepTriggerConfig[id] = triggerConfig;
+ s_upkeepOffchainConfig[id] = offchainConfig;
+ s_upkeepIDs.add(id);
+ }
+
+ /**
+ * @dev creates an ID for the upkeep based on the upkeep's type
+ * @dev the format of the ID looks like this:
+ * ****00000000000X****************
+ * 4 bytes of entropy
+ * 11 bytes of zeros
+ * 1 identifying byte for the trigger type
+ * 16 bytes of entropy
+ * @dev this maintains the same level of entropy as eth addresses, so IDs will still be unique
+ * @dev we add the "identifying" part in the middle so that it is mostly hidden from users who usually only
+ * see the first 4 and last 4 hex values ex 0x1234...ABCD
+ */
+ function _createID(Trigger triggerType) internal view returns (uint256) {
+ bytes1 empty;
+ IChainModule chainModule = s_hotVars.chainModule;
+ bytes memory idBytes = abi.encodePacked(
+ keccak256(abi.encode(chainModule.blockHash((chainModule.blockNumber() - 1)), address(this), s_storage.nonce))
+ );
+ for (uint256 idx = 4; idx < 15; idx++) {
+ idBytes[idx] = empty;
+ }
+ idBytes[15] = bytes1(uint8(triggerType));
+ return uint256(bytes32(idBytes));
+ }
+
+ /**
+ * @dev retrieves feed data for fast gas/native and link/native 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(
+ HotVars memory hotVars
+ ) internal view returns (uint256 gasWei, uint256 linkUSD, uint256 nativeUSD) {
+ uint32 stalenessSeconds = hotVars.stalenessSeconds;
+ bool staleFallback = stalenessSeconds > 0;
+ uint256 timestamp;
+ int256 feedValue;
+ (, feedValue, , timestamp, ) = i_fastGasFeed.latestRoundData();
+ if (
+ feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp)
+ ) {
+ gasWei = s_fallbackGasPrice;
+ } else {
+ gasWei = uint256(feedValue);
+ }
+ (, feedValue, , timestamp, ) = i_linkUSDFeed.latestRoundData();
+ if (
+ feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp)
+ ) {
+ linkUSD = s_fallbackLinkPrice;
+ } else {
+ linkUSD = uint256(feedValue);
+ }
+ return (gasWei, linkUSD, _getNativeUSD(hotVars));
+ }
+
+ /**
+ * @dev this price has it's own getter for use in the transmit() hot path
+ * in the future, all price data should be included in the report instead of
+ * getting read during execution
+ */
+ function _getNativeUSD(HotVars memory hotVars) internal view returns (uint256) {
+ (, int256 feedValue, , uint256 timestamp, ) = i_nativeUSDFeed.latestRoundData();
+ if (
+ feedValue <= 0 ||
+ block.timestamp < timestamp ||
+ (hotVars.stalenessSeconds > 0 && hotVars.stalenessSeconds < block.timestamp - timestamp)
+ ) {
+ return s_fallbackNativePrice;
+ } else {
+ return uint256(feedValue);
+ }
+ }
+
+ /**
+ * @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;
+ paymentParams.decimals = config.decimals;
+ (, 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;
+ }
+
+ /**
+ * @param hotVars the hot path variables
+ * @param paymentParams the pricing data and gas usage data
+ * @return receipt the receipt of payment with pricing breakdown
+ * @dev use of PaymentParams struct is necessary to avoid stack too deep errors
+ * @dev calculates LINK paid for gas spent plus a configure premium percentage
+ * @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 (PaymentReceipt memory receipt) {
+ uint256 decimals = paymentParams.billingTokenParams.decimals;
+ 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;
+ }
+
+ // scaling factor is based on decimals of billing token, and applies to premium and gasCharge
+ uint256 numeratorScalingFactor = decimals > 18 ? 10 ** (decimals - 18) : 1;
+ uint256 denominatorScalingFactor = decimals < 18 ? 10 ** (18 - decimals) : 1;
+
+ // gas calculation
+ uint256 gasPaymentHexaicosaUSD = (gasWei *
+ (paymentParams.gasLimit + paymentParams.gasOverhead) +
+ paymentParams.l1CostWei) * paymentParams.nativeUSD; // gasPaymentHexaicosaUSD has an extra 8 zeros because of decimals on nativeUSD feed
+ // gasChargeInBillingToken is scaled by the billing token's decimals. Round up to ensure a minimum billing token is charged for gas
+ receipt.gasChargeInBillingToken = SafeCast.toUint96(
+ ((gasPaymentHexaicosaUSD * numeratorScalingFactor) +
+ (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor - 1)) /
+ (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor)
+ );
+ // 18 decimals: 26 decimals / 8 decimals
+ receipt.gasReimbursementInJuels = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.linkUSD);
+
+ // premium calculation
+ 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;
+ // premium is scaled by the billing token's decimals. Round up to ensure at least minimum charge
+ receipt.premiumInBillingToken = SafeCast.toUint96(
+ ((premiumHexaicosaUSD * numeratorScalingFactor) +
+ (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor - 1)) /
+ (paymentParams.billingTokenParams.priceUSD * denominatorScalingFactor)
+ );
+ receipt.premiumInJuels = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.linkUSD);
+
+ receipt.billingToken = paymentParams.billingToken;
+ receipt.linkUSD = SafeCast.toUint96(paymentParams.linkUSD);
+ receipt.nativeUSD = SafeCast.toUint96(paymentParams.nativeUSD);
+ receipt.billingUSD = SafeCast.toUint96(paymentParams.billingTokenParams.priceUSD);
+
+ return receipt;
+ }
+
+ /**
+ * @dev calculates the max payment for an upkeep. Called during checkUpkeep simulation and assumes
+ * maximum gas overhead, L1 fee
+ */
+ function _getMaxPayment(
+ uint256 upkeepId,
+ HotVars memory hotVars,
+ Trigger triggerType,
+ uint32 performGas,
+ uint256 fastGasWei,
+ uint256 linkUSD,
+ uint256 nativeUSD,
+ IERC20 billingToken
+ ) internal view returns (uint96) {
+ uint256 maxGasOverhead;
+
+ {
+ if (triggerType == Trigger.CONDITION) {
+ maxGasOverhead = REGISTRY_CONDITIONAL_OVERHEAD;
+ } else if (triggerType == Trigger.LOG) {
+ maxGasOverhead = REGISTRY_LOG_OVERHEAD;
+ } else {
+ revert InvalidTriggerType();
+ }
+ (uint256 chainModuleFixedOverhead, ) = s_hotVars.chainModule.getGasOverhead();
+ maxGasOverhead += (REGISTRY_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1)) + chainModuleFixedOverhead;
+ }
+
+ 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,
+ gasOverhead: maxGasOverhead,
+ l1CostWei: 0,
+ fastGasWei: fastGasWei,
+ linkUSD: linkUSD,
+ nativeUSD: nativeUSD,
+ billingToken: billingToken,
+ billingTokenParams: paymentParams,
+ isTransaction: false
+ })
+ );
+
+ return receipt.gasChargeInBillingToken + receipt.premiumInBillingToken;
+ }
+
+ /**
+ * @dev move a transmitter's balance from total pool to withdrawable balance
+ */
+ function _updateTransmitterBalanceFromPool(
+ address transmitterAddress,
+ uint96 totalPremium,
+ uint96 payeeCount
+ ) internal returns (uint96) {
+ Transmitter memory transmitter = s_transmitters[transmitterAddress];
+
+ if (transmitter.active) {
+ uint96 uncollected = totalPremium - transmitter.lastCollected;
+ uint96 due = uncollected / payeeCount;
+ transmitter.balance += due;
+ transmitter.lastCollected += due * payeeCount;
+ s_transmitters[transmitterAddress] = transmitter;
+ }
+
+ return transmitter.balance;
+ }
+
+ /**
+ * @dev gets the trigger type from an upkeepID (trigger type is encoded in the middle of the ID)
+ */
+ function _getTriggerType(uint256 upkeepId) internal pure returns (Trigger) {
+ bytes32 rawID = bytes32(upkeepId);
+ bytes1 empty = bytes1(0);
+ for (uint256 idx = 4; idx < 15; idx++) {
+ if (rawID[idx] != empty) {
+ // old IDs that were created before this standard and migrated to this registry
+ return Trigger.CONDITION;
+ }
+ }
+ return Trigger(uint8(rawID[15]));
+ }
+
+ function _checkPayload(
+ uint256 upkeepId,
+ Trigger triggerType,
+ bytes memory triggerData
+ ) internal view returns (bytes memory) {
+ if (triggerType == Trigger.CONDITION) {
+ return abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[upkeepId]);
+ } else if (triggerType == Trigger.LOG) {
+ Log memory log = abi.decode(triggerData, (Log));
+ return abi.encodeWithSelector(CHECK_LOG_SELECTOR, log, s_checkData[upkeepId]);
+ }
+ revert InvalidTriggerType();
+ }
+
+ /**
+ * @dev _decodeReport decodes a serialized report into a Report struct
+ */
+ function _decodeReport(bytes calldata rawReport) internal pure returns (Report memory) {
+ Report memory report = abi.decode(rawReport, (Report));
+ uint256 expectedLength = report.upkeepIds.length;
+ if (
+ report.gasLimits.length != expectedLength ||
+ report.triggers.length != expectedLength ||
+ report.performDatas.length != expectedLength
+ ) {
+ revert InvalidReport();
+ }
+ return report;
+ }
+
+ /**
+ * @dev Does some early sanity checks before actually performing an upkeep
+ * @return bool whether the upkeep should be performed
+ * @return bytes32 dedupID for preventing duplicate performances of this trigger
+ */
+ function _prePerformChecks(
+ uint256 upkeepId,
+ uint256 blocknumber,
+ bytes memory rawTrigger,
+ UpkeepTransmitInfo memory transmitInfo,
+ HotVars memory hotVars
+ ) internal returns (bool, bytes32) {
+ bytes32 dedupID;
+ if (transmitInfo.triggerType == Trigger.CONDITION) {
+ if (!_validateConditionalTrigger(upkeepId, blocknumber, rawTrigger, transmitInfo, hotVars))
+ return (false, dedupID);
+ } else if (transmitInfo.triggerType == Trigger.LOG) {
+ bool valid;
+ (valid, dedupID) = _validateLogTrigger(upkeepId, blocknumber, rawTrigger, hotVars);
+ if (!valid) return (false, dedupID);
+ } else {
+ revert InvalidTriggerType();
+ }
+ if (transmitInfo.upkeep.maxValidBlocknumber <= blocknumber) {
+ // Can happen when an upkeep got cancelled after report was generated.
+ // However we have a CANCELLATION_DELAY of 50 blocks so shouldn't happen in practice
+ emit CancelledUpkeepReport(upkeepId, rawTrigger);
+ return (false, dedupID);
+ }
+ return (true, dedupID);
+ }
+
+ /**
+ * @dev Does some early sanity checks before actually performing an upkeep
+ */
+ function _validateConditionalTrigger(
+ uint256 upkeepId,
+ uint256 blocknumber,
+ bytes memory rawTrigger,
+ UpkeepTransmitInfo memory transmitInfo,
+ HotVars memory hotVars
+ ) internal returns (bool) {
+ ConditionalTrigger memory trigger = abi.decode(rawTrigger, (ConditionalTrigger));
+ if (trigger.blockNum < transmitInfo.upkeep.lastPerformedBlockNumber) {
+ // Can happen when another report performed this upkeep after this report was generated
+ emit StaleUpkeepReport(upkeepId, rawTrigger);
+ return false;
+ }
+ if (
+ (hotVars.reorgProtectionEnabled &&
+ (trigger.blockHash != bytes32("") && hotVars.chainModule.blockHash(trigger.blockNum) != trigger.blockHash)) ||
+ trigger.blockNum >= blocknumber
+ ) {
+ // There are two cases of reorged report
+ // 1. trigger block number is in future: this is an edge case during extreme deep reorgs of chain
+ // which is always protected against
+ // 2. blockHash at trigger block number was same as trigger time. This is an optional check which is
+ // applied if DON sends non empty trigger.blockHash. Note: It only works for last 256 blocks on chain
+ // when it is sent
+ emit ReorgedUpkeepReport(upkeepId, rawTrigger);
+ return false;
+ }
+ return true;
+ }
+
+ function _validateLogTrigger(
+ uint256 upkeepId,
+ uint256 blocknumber,
+ bytes memory rawTrigger,
+ HotVars memory hotVars
+ ) internal returns (bool, bytes32) {
+ LogTrigger memory trigger = abi.decode(rawTrigger, (LogTrigger));
+ bytes32 dedupID = keccak256(abi.encodePacked(upkeepId, trigger.logBlockHash, trigger.txHash, trigger.logIndex));
+ if (
+ (hotVars.reorgProtectionEnabled &&
+ (trigger.blockHash != bytes32("") && hotVars.chainModule.blockHash(trigger.blockNum) != trigger.blockHash)) ||
+ trigger.blockNum >= blocknumber
+ ) {
+ // Reorg protection is same as conditional trigger upkeeps
+ emit ReorgedUpkeepReport(upkeepId, rawTrigger);
+ return (false, dedupID);
+ }
+ if (s_dedupKeys[dedupID]) {
+ emit StaleUpkeepReport(upkeepId, rawTrigger);
+ return (false, dedupID);
+ }
+ return (true, dedupID);
+ }
+
+ /**
+ * @dev Verify signatures attached to report
+ */
+ function _verifyReportSignature(
+ bytes32[3] calldata reportContext,
+ bytes calldata report,
+ bytes32[] calldata rs,
+ bytes32[] calldata ss,
+ bytes32 rawVs
+ ) internal view {
+ bytes32 h = keccak256(abi.encode(keccak256(report), reportContext));
+ // i-th byte counts number of sigs made by i-th signer
+ uint256 signedCount = 0;
+
+ Signer memory signer;
+ address signerAddress;
+ for (uint256 i = 0; i < rs.length; i++) {
+ signerAddress = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]);
+ signer = s_signers[signerAddress];
+ if (!signer.active) revert OnlyActiveSigners();
+ unchecked {
+ signedCount += 1 << (8 * signer.index);
+ }
+ }
+
+ if (signedCount & ORACLE_MASK != signedCount) revert DuplicateSigners();
+ }
+
+ /**
+ * @dev updates a storage marker for this upkeep to prevent duplicate and out of order performances
+ * @dev for conditional triggers we set the latest block number, for log triggers we store a dedupID
+ */
+ function _updateTriggerMarker(
+ uint256 upkeepID,
+ uint256 blocknumber,
+ UpkeepTransmitInfo memory upkeepTransmitInfo
+ ) internal {
+ if (upkeepTransmitInfo.triggerType == Trigger.CONDITION) {
+ s_upkeep[upkeepID].lastPerformedBlockNumber = uint32(blocknumber);
+ } else if (upkeepTransmitInfo.triggerType == Trigger.LOG) {
+ s_dedupKeys[upkeepTransmitInfo.dedupID] = true;
+ emit DedupKeyAdded(upkeepTransmitInfo.dedupID);
+ }
+ }
+
+ /**
+ * @dev calls the Upkeep target with the performData param passed in by the
+ * transmitter and the exact gas required by the Upkeep
+ */
+ function _performUpkeep(
+ IAutomationForwarder forwarder,
+ uint256 performGas,
+ bytes memory performData
+ ) internal nonReentrant returns (bool success, uint256 gasUsed) {
+ performData = abi.encodeWithSelector(PERFORM_SELECTOR, performData);
+ return forwarder.forward(performGas, performData);
+ }
+
+ /**
+ * @dev handles the payment processing after an upkeep has been performed.
+ * Deducts an upkeep's balance and increases the amount spent.
+ */
+ function _handlePayment(
+ HotVars memory hotVars,
+ PaymentParams memory paymentParams,
+ uint256 upkeepId,
+ Upkeep memory upkeep
+ ) internal returns (PaymentReceipt memory) {
+ 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);
+
+ // balance is in the token's native decimals
+ uint96 balance = upkeep.balance;
+ // payment is in the token's native decimals
+ uint96 payment = receipt.gasChargeInBillingToken + receipt.premiumInBillingToken;
+
+ // scaling factors to adjust decimals between billing token and LINK
+ uint256 decimals = paymentParams.billingTokenParams.decimals;
+ uint256 scalingFactor1 = decimals < 18 ? 10 ** (18 - decimals) : 1;
+ uint256 scalingFactor2 = decimals > 18 ? 10 ** (decimals - 18) : 1;
+
+ // 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 < receipt.gasChargeInBillingToken) {
+ // 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;
+ receipt.gasReimbursementInJuels = SafeCast.toUint96(
+ (balance * paymentParams.billingTokenParams.priceUSD * scalingFactor1) /
+ (paymentParams.linkUSD * scalingFactor2)
+ );
+ receipt.premiumInJuels = 0;
+ receipt.premiumInBillingToken = 0;
+ receipt.gasChargeInBillingToken = balance;
+ } else if (balance < payment) {
+ // if the user can cover the gas fee, but not the premium, then reduce the premium
+ payment = balance;
+ receipt.premiumInJuels = SafeCast.toUint96(
+ ((balance * paymentParams.billingTokenParams.priceUSD * scalingFactor1) /
+ (paymentParams.linkUSD * scalingFactor2)) - receipt.gasReimbursementInJuels
+ );
+ // round up
+ receipt.premiumInBillingToken = SafeCast.toUint96(
+ ((receipt.premiumInJuels * paymentParams.linkUSD * scalingFactor2) +
+ (paymentParams.billingTokenParams.priceUSD * scalingFactor1 - 1)) /
+ (paymentParams.billingTokenParams.priceUSD * scalingFactor1)
+ );
+ }
+
+ s_upkeep[upkeepId].balance -= payment;
+ s_upkeep[upkeepId].amountSpent += payment;
+ s_reserveAmounts[paymentParams.billingToken] -= payment;
+
+ emit UpkeepCharged(upkeepId, receipt);
+ return receipt;
+ }
+
+ /**
+ * @dev ensures the upkeep is not cancelled and the caller is the upkeep admin
+ */
+ function _requireAdminAndNotCancelled(uint256 upkeepId) internal view {
+ if (msg.sender != s_upkeepAdmin[upkeepId]) revert OnlyCallableByAdmin();
+ if (s_upkeep[upkeepId].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled();
+ }
+
+ /**
+ * @dev replicates Open Zeppelin's ReentrancyGuard but optimized to fit our storage
+ */
+ modifier nonReentrant() {
+ if (s_hotVars.reentrancyGuard) revert ReentrantCall();
+ s_hotVars.reentrancyGuard = true;
+ _;
+ s_hotVars.reentrancyGuard = false;
+ }
+
+ /**
+ * @notice only allows a pre-configured address to initiate offchain read
+ */
+ function _preventExecution() internal view {
+ // solhint-disable-next-line avoid-tx-origin
+ if (tx.origin != i_allowedReadOnlyAddress) {
+ revert OnlySimulatedBackend();
+ }
+ }
+
+ /**
+ * @notice only allows finance admin to call the function
+ */
+ function _onlyFinanceAdminAllowed() internal view {
+ if (msg.sender != s_storage.financeAdmin) {
+ revert OnlyFinanceAdmin();
+ }
+ }
+
+ /**
+ * @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
+ * @param billingConfigs the configs for tokens
+ */
+ function _setBillingConfig(IERC20[] memory billingTokens, BillingConfig[] memory billingConfigs) internal {
+ // Clear existing data
+ for (uint256 i = 0; i < s_billingTokens.length; i++) {
+ delete s_billingConfigs[s_billingTokens[i]];
+ }
+ delete s_billingTokens;
+
+ PayoutMode mode = s_payoutMode;
+ for (uint256 i = 0; i < billingTokens.length; i++) {
+ IERC20 token = billingTokens[i];
+ BillingConfig memory config = billingConfigs[i];
+
+ // most ERC20 tokens are 18 decimals, priceFeed must be 8 decimals
+ if (config.decimals != token.decimals() || config.priceFeed.decimals() != 8) {
+ revert InvalidToken();
+ }
+
+ // 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 (address(s_billingConfigs[token].priceFeed) != ZERO_ADDRESS) {
+ revert DuplicateEntry();
+ }
+ s_billingTokens.push(token);
+
+ // update the billing config for an existing token or add a new one
+ s_billingConfigs[token] = config;
+
+ emit BillingConfigSet(token, config);
+ }
+ }
+
+ /**
+ * @notice updates the signers and transmitters lists
+ */
+ function _updateTransmitters(address[] memory signers, address[] memory transmitters) internal {
+ uint96 transmittersListLength = uint96(s_transmittersList.length);
+ uint96 totalPremium = s_hotVars.totalPremium;
+
+ // 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], totalPremium, transmittersListLength);
+ }
+
+ // 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/v2_3_zksync/ZKSyncAutomationRegistryLogicA2_3.sol b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryLogicA2_3.sol
new file mode 100644
index 00000000000..64d697c70f9
--- /dev/null
+++ b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryLogicA2_3.sol
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: BUSL-1.1
+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 {ZKSyncAutomationRegistryBase2_3} from "./ZKSyncAutomationRegistryBase2_3.sol";
+import {ZKSyncAutomationRegistryLogicC2_3} from "./ZKSyncAutomationRegistryLogicC2_3.sol";
+import {ZKSyncAutomationRegistryLogicB2_3} from "./ZKSyncAutomationRegistryLogicB2_3.sol";
+import {Chainable} from "../Chainable.sol";
+import {ZKSyncAutomationForwarder} from "../ZKSyncAutomationForwarder.sol";
+import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol";
+import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol";
+import {MigratableKeeperRegistryInterfaceV2} from "../interfaces/MigratableKeeperRegistryInterfaceV2.sol";
+import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol";
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol";
+
+/**
+ * @notice Logic contract, works in tandem with AutomationRegistry as a proxy
+ */
+contract ZKSyncAutomationRegistryLogicA2_3 is ZKSyncAutomationRegistryBase2_3, Chainable, IERC677Receiver {
+ 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(
+ ZKSyncAutomationRegistryLogicB2_3 logicB
+ )
+ ZKSyncAutomationRegistryBase2_3(
+ ZKSyncAutomationRegistryLogicC2_3(address(logicB)).getLinkAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicB)).getLinkUSDFeedAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicB)).getNativeUSDFeedAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicB)).getFastGasFeedAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicB)).getAutomationForwarderLogic(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicB)).getAllowedReadOnlyAddress(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicB)).getPayoutMode(),
+ ZKSyncAutomationRegistryLogicC2_3(address(logicB)).getWrappedNativeTokenAddress()
+ )
+ Chainable(address(logicB))
+ {}
+
+ /**
+ * @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 override {
+ if (msg.sender != address(i_link)) revert OnlyCallableByLINKToken();
+ 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[IERC20(address(i_link))] = s_reserveAmounts[IERC20(address(i_link))] + amount;
+ emit FundsAdded(id, sender, uint96(amount));
+ }
+
+ // ================================================================
+ // | UPKEEP MANAGEMENT |
+ // ================================================================
+
+ /**
+ * @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 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
+ */
+ function registerUpkeep(
+ address target,
+ uint32 gasLimit,
+ address admin,
+ Trigger triggerType,
+ IERC20 billingToken,
+ bytes calldata checkData,
+ bytes memory triggerConfig,
+ bytes memory offchainConfig
+ ) public returns (uint256 id) {
+ if (msg.sender != owner() && !s_registrars.contains(msg.sender)) revert OnlyCallableByOwnerOrRegistrar();
+ if (!target.isContract()) revert NotAContract();
+ id = _createID(triggerType);
+ IAutomationForwarder forwarder = IAutomationForwarder(
+ address(new ZKSyncAutomationForwarder(target, address(this), i_automationForwarderLogic))
+ );
+ _createUpkeep(
+ id,
+ Upkeep({
+ overridesEnabled: false,
+ performGas: gasLimit,
+ balance: 0,
+ maxValidBlocknumber: UINT32_MAX,
+ lastPerformedBlockNumber: 0,
+ amountSpent: 0,
+ paused: false,
+ forwarder: forwarder,
+ billingToken: billingToken
+ }),
+ admin,
+ checkData,
+ triggerConfig,
+ offchainConfig
+ );
+ s_storage.nonce++;
+ emit UpkeepRegistered(id, gasLimit, admin);
+ emit UpkeepCheckDataSet(id, checkData);
+ emit UpkeepTriggerConfigSet(id, triggerConfig);
+ emit UpkeepOffchainConfigSet(id, offchainConfig);
+ return (id);
+ }
+
+ /**
+ * @notice cancels an upkeep
+ * @param id the upkeepID to cancel
+ * @dev if a user cancels an upkeep, their funds are locked for CANCELLATION_DELAY blocks to
+ * allow any pending performUpkeep txs time to get confirmed
+ */
+ 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();
+ if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled();
+ if (!isOwner && msg.sender != s_upkeepAdmin[id]) revert OnlyCallableByOwnerOrAdmin();
+
+ if (!isOwner) {
+ height = height + CANCELLATION_DELAY;
+ }
+ s_upkeep[id].maxValidBlocknumber = uint32(height);
+ s_upkeepIDs.remove(id);
+
+ // charge the cancellation fee if the minSpend is not met
+ uint96 cancellationFee = 0;
+ // 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[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] - cancellationFee;
+
+ emit UpkeepCanceled(id, uint64(height));
+ }
+
+ /**
+ * @notice migrates upkeeps from one registry to another.
+ * @param ids the upkeepIDs to migrate
+ * @param destination the destination registry address
+ * @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
+ * @dev s_billingOverrides and s_upkeepPrivilegeConfig are not migrated in this function
+ */
+ function migrateUpkeeps(uint256[] calldata ids, address destination) external {
+ if (
+ s_peerRegistryMigrationPermission[destination] != MigrationPermission.OUTGOING &&
+ s_peerRegistryMigrationPermission[destination] != MigrationPermission.BIDIRECTIONAL
+ ) 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;
+ address[] memory admins = new address[](ids.length);
+ Upkeep[] memory upkeeps = new Upkeep[](ids.length);
+ bytes[] memory checkDatas = new bytes[](ids.length);
+ bytes[] memory triggerConfigs = new bytes[](ids.length);
+ bytes[] memory offchainConfigs = new bytes[](ids.length);
+
+ for (uint256 idx = 0; idx < ids.length; idx++) {
+ id = ids[idx];
+ upkeep = s_upkeep[id];
+
+ if (idx == 0) {
+ billingToken = upkeep.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;
+ } else if (idx != 0) {
+ balanceToTransfer += upkeep.balance;
+ }
+
+ _requireAdminAndNotCancelled(id);
+ upkeep.forwarder.updateRegistry(destination);
+
+ upkeeps[idx] = upkeep;
+ admins[idx] = s_upkeepAdmin[id];
+ checkDatas[idx] = s_checkData[id];
+ triggerConfigs[idx] = s_upkeepTriggerConfig[id];
+ offchainConfigs[idx] = s_upkeepOffchainConfig[id];
+ delete s_upkeep[id];
+ delete s_checkData[id];
+ delete s_upkeepTriggerConfig[id];
+ delete s_upkeepOffchainConfig[id];
+ // nullify existing proposed admin change if an upkeep is being migrated
+ delete s_proposedAdmin[id];
+ delete s_upkeepAdmin[id];
+ s_upkeepIDs.remove(id);
+ emit UpkeepMigrated(id, upkeep.balance, destination);
+ }
+ // always transfer the rolling sum in the end
+ s_reserveAmounts[billingToken] = s_reserveAmounts[billingToken] - balanceToTransfer;
+ billingToken.safeTransfer(destination, balanceToTransfer);
+
+ bytes memory encodedUpkeeps = abi.encode(
+ ids,
+ upkeeps,
+ new address[](ids.length),
+ admins,
+ checkDatas,
+ triggerConfigs,
+ offchainConfigs
+ );
+ MigratableKeeperRegistryInterfaceV2(destination).receiveUpkeeps(
+ UpkeepTranscoderInterfaceV2(s_storage.transcoder).transcodeUpkeeps(
+ UPKEEP_VERSION_BASE,
+ MigratableKeeperRegistryInterfaceV2(destination).upkeepVersion(),
+ encodedUpkeeps
+ )
+ );
+ }
+
+ /**
+ * @notice received upkeeps migrated from another registry
+ * @param encodedUpkeeps the raw upkeep data to import
+ * @dev this function is never called directly, it is only called by another registry's migrate function
+ * @dev s_billingOverrides and s_upkeepPrivilegeConfig are not handled in this function
+ */
+ function receiveUpkeeps(bytes calldata encodedUpkeeps) external {
+ if (
+ s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.INCOMING &&
+ s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.BIDIRECTIONAL
+ ) revert MigrationNotPermitted();
+ (
+ uint256[] memory ids,
+ Upkeep[] memory upkeeps,
+ address[] memory targets,
+ address[] memory upkeepAdmins,
+ bytes[] memory checkDatas,
+ bytes[] memory triggerConfigs,
+ bytes[] memory offchainConfigs
+ ) = abi.decode(encodedUpkeeps, (uint256[], Upkeep[], address[], address[], bytes[], bytes[], bytes[]));
+ for (uint256 idx = 0; idx < ids.length; idx++) {
+ if (address(upkeeps[idx].forwarder) == ZERO_ADDRESS) {
+ upkeeps[idx].forwarder = IAutomationForwarder(
+ address(new ZKSyncAutomationForwarder(targets[idx], address(this), i_automationForwarderLogic))
+ );
+ }
+ _createUpkeep(
+ ids[idx],
+ upkeeps[idx],
+ upkeepAdmins[idx],
+ checkDatas[idx],
+ triggerConfigs[idx],
+ offchainConfigs[idx]
+ );
+ emit UpkeepReceived(ids[idx], upkeeps[idx].balance, msg.sender);
+ }
+ }
+}
diff --git a/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryLogicB2_3.sol b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryLogicB2_3.sol
new file mode 100644
index 00000000000..55af99fde87
--- /dev/null
+++ b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryLogicB2_3.sol
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.19;
+
+import {ZKSyncAutomationRegistryBase2_3} from "./ZKSyncAutomationRegistryBase2_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 {ZKSyncAutomationRegistryLogicC2_3} from "./ZKSyncAutomationRegistryLogicC2_3.sol";
+import {Chainable} from "../Chainable.sol";
+import {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol";
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+import {SafeCast} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol";
+
+contract ZKSyncAutomationRegistryLogicB2_3 is ZKSyncAutomationRegistryBase2_3, Chainable {
+ using Address for address;
+ using EnumerableSet for EnumerableSet.UintSet;
+ using EnumerableSet for EnumerableSet.AddressSet;
+ using SafeERC20 for IERC20;
+
+ /**
+ * @param logicC the address of the third logic contract
+ */
+ constructor(
+ ZKSyncAutomationRegistryLogicC2_3 logicC
+ )
+ ZKSyncAutomationRegistryBase2_3(
+ 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();
+ // solhint-disable-next-line avoid-low-level-calls
+ (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();
+ // solhint-disable-next-line avoid-low-level-calls
+ (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 adds fund to an upkeep
+ * @param id the upkeepID
+ * @param amount the amount of funds to add, in the upkeep's billing token
+ */
+ function addFunds(uint256 id, uint96 amount) external payable {
+ Upkeep memory upkeep = s_upkeep[id];
+ 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
+ upkeep.billingToken.safeTransferFrom(msg.sender, address(this), amount);
+ } else {
+ // native payment
+ i_wrappedNativeToken.deposit{value: amount}();
+ }
+
+ emit FundsAdded(id, msg.sender, amount);
+ }
+
+ /**
+ * @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
+ */
+ function transferUpkeepAdmin(uint256 id, address proposed) external {
+ _requireAdminAndNotCancelled(id);
+ if (proposed == msg.sender) revert ValueNotChanged();
+
+ if (s_proposedAdmin[id] != proposed) {
+ s_proposedAdmin[id] = proposed;
+ emit UpkeepAdminTransferRequested(id, msg.sender, proposed);
+ }
+ }
+
+ /**
+ * @notice accepts the transfer of an upkeep admin
+ */
+ function acceptUpkeepAdmin(uint256 id) external {
+ Upkeep memory upkeep = s_upkeep[id];
+ if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled();
+ if (s_proposedAdmin[id] != msg.sender) revert OnlyCallableByProposedAdmin();
+ address past = s_upkeepAdmin[id];
+ s_upkeepAdmin[id] = msg.sender;
+ s_proposedAdmin[id] = ZERO_ADDRESS;
+
+ emit UpkeepAdminTransferred(id, past, msg.sender);
+ }
+
+ /**
+ * @notice pauses an upkeep - an upkeep will be neither checked nor performed while paused
+ */
+ function pauseUpkeep(uint256 id) external {
+ _requireAdminAndNotCancelled(id);
+ Upkeep memory upkeep = s_upkeep[id];
+ if (upkeep.paused) revert OnlyUnpausedUpkeep();
+ s_upkeep[id].paused = true;
+ s_upkeepIDs.remove(id);
+ emit UpkeepPaused(id);
+ }
+
+ /**
+ * @notice unpauses an upkeep
+ */
+ function unpauseUpkeep(uint256 id) external {
+ _requireAdminAndNotCancelled(id);
+ Upkeep memory upkeep = s_upkeep[id];
+ if (!upkeep.paused) revert OnlyPausedUpkeep();
+ s_upkeep[id].paused = false;
+ s_upkeepIDs.add(id);
+ emit UpkeepUnpaused(id);
+ }
+
+ /**
+ * @notice updates the checkData for an upkeep
+ */
+ function setUpkeepCheckData(uint256 id, bytes calldata newCheckData) external {
+ _requireAdminAndNotCancelled(id);
+ if (newCheckData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit();
+ s_checkData[id] = newCheckData;
+ emit UpkeepCheckDataSet(id, newCheckData);
+ }
+
+ /**
+ * @notice updates the gas limit for an upkeep
+ */
+ function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external {
+ if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange();
+ _requireAdminAndNotCancelled(id);
+ s_upkeep[id].performGas = gasLimit;
+
+ emit UpkeepGasLimitSet(id, gasLimit);
+ }
+
+ /**
+ * @notice updates the offchain config for an upkeep
+ */
+ function setUpkeepOffchainConfig(uint256 id, bytes calldata config) external {
+ _requireAdminAndNotCancelled(id);
+ s_upkeepOffchainConfig[id] = config;
+ emit UpkeepOffchainConfigSet(id, config);
+ }
+
+ /**
+ * @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 {
+ if (to == ZERO_ADDRESS) revert InvalidRecipient();
+ Upkeep memory upkeep = s_upkeep[id];
+ 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[upkeep.billingToken] = s_reserveAmounts[upkeep.billingToken] - amountToWithdraw;
+ s_upkeep[id].balance = 0;
+ upkeep.billingToken.safeTransfer(to, amountToWithdraw);
+ emit FundsWithdrawn(id, amountToWithdraw, to);
+ }
+
+ // ================================================================
+ // | FINANCE ACTIONS |
+ // ================================================================
+
+ /**
+ * @notice withdraws excess LINK from the liquidity pool
+ * @param to the address to send the fees to
+ * @param amount the amount to withdraw
+ */
+ function withdrawLink(address to, uint256 amount) external {
+ _onlyFinanceAdminAllowed();
+ if (to == ZERO_ADDRESS) revert InvalidRecipient();
+
+ int256 available = _linkAvailableForPayment();
+ if (available < 0) {
+ revert InsufficientBalance(0, amount);
+ } else if (amount > uint256(available)) {
+ revert InsufficientBalance(uint256(available), amount);
+ }
+
+ bool transferStatus = i_link.transfer(to, amount);
+ if (!transferStatus) {
+ revert TransferFailed();
+ }
+ emit FeesWithdrawn(address(i_link), to, amount);
+ }
+
+ /**
+ * @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 in ON_CHAIN mode, we prevent withdrawing non-LINK fees unless there is sufficient LINK liquidity
+ * to cover all outstanding debts on the registry
+ */
+ function withdrawERC20Fees(IERC20 asset, address to, uint256 amount) external {
+ _onlyFinanceAdminAllowed();
+ if (to == ZERO_ADDRESS) revert InvalidRecipient();
+ if (address(asset) == address(i_link)) revert InvalidToken();
+ if (_linkAvailableForPayment() < 0 && s_payoutMode == PayoutMode.ON_CHAIN) revert InsufficientLinkLiquidity();
+ uint256 available = asset.balanceOf(address(this)) - s_reserveAmounts[asset];
+ if (amount > available) revert InsufficientBalance(available, amount);
+
+ asset.safeTransfer(to, amount);
+ emit FeesWithdrawn(address(asset), to, amount);
+ }
+}
diff --git a/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryLogicC2_3.sol b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryLogicC2_3.sol
new file mode 100644
index 00000000000..3b4b023c7a2
--- /dev/null
+++ b/contracts/src/v0.8/automation/v2_3_zksync/ZKSyncAutomationRegistryLogicC2_3.sol
@@ -0,0 +1,626 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.19;
+
+import {ZKSyncAutomationRegistryBase2_3} from "./ZKSyncAutomationRegistryBase2_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 {IERC20Metadata as IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol";
+import {IAutomationV21PlusCommon} from "../interfaces/IAutomationV21PlusCommon.sol";
+
+contract ZKSyncAutomationRegistryLogicC2_3 is ZKSyncAutomationRegistryBase2_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
+ )
+ ZKSyncAutomationRegistryBase2_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 this is for NOPs to withdraw 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;
+ bool transferStatus = i_link.transfer(to, balance);
+ if (!transferStatus) {
+ revert TransferFailed();
+ }
+ 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 this is used by the owner to set the initial payees for newly added transmitters. The owner is not allowed to change payees for existing transmitters.
+ * @dev the IGNORE_ADDRESS is a "helper" that makes it easier to construct a list of payees when you only care about setting the payee for a small number of 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();
+
+ uint96 totalPremium = s_hotVars.totalPremium;
+ 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,
+ 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;
+ }
+
+ // reserve amount of LINK is reset to 0 since no user deposits of LINK are expected in offchain mode
+ s_reserveAmounts[IERC20(address(i_link))] = 0;
+
+ for (uint256 idx = s_deactivatedTransmitters.length(); idx > 0; idx--) {
+ s_deactivatedTransmitters.remove(s_deactivatedTransmitters.at(idx - 1));
+ }
+
+ 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 getPerSignerGasOverhead() external pure returns (uint256) {
+ return REGISTRY_PER_SIGNER_GAS_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 getBillingOverridesEnabled(uint256 upkeepID) external view returns (bool) {
+ return s_upkeep[upkeepID].overridesEnabled;
+ }
+
+ 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 admin's 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 if the dedupKey exists or not
+ */
+ 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 amount of a particular token that is withdraw-able by finance admin
+ */
+ function getAvailableERC20ForPayment(IERC20 billingToken) external view returns (uint256) {
+ return billingToken.balanceOf(address(this)) - s_reserveAmounts[IERC20(address(billingToken))];
+ }
+
+ /**
+ * @notice returns the size of the LINK liquidity pool
+ */
+ function linkAvailableForPayment() public view returns (int256) {
+ return _linkAvailableForPayment();
+ }
+
+ /**
+ * @notice returns the BillingOverrides config for a given upkeep
+ */
+ function getBillingOverrides(uint256 upkeepID) external view returns (BillingOverrides memory) {
+ return s_billingOverrides[upkeepID];
+ }
+
+ /**
+ * @notice returns the BillingConfig for a given billing token, this includes decimals and price feed etc
+ */
+ function getBillingConfig(IERC20 billingToken) external view returns (BillingConfig memory) {
+ return s_billingConfigs[billingToken];
+ }
+
+ /**
+ * @notice returns all active transmitters with their associated payees
+ */
+ function getTransmittersWithPayees() external view returns (TransmitterPayeeInfo[] memory) {
+ uint256 transmitterCount = s_transmittersList.length;
+ TransmitterPayeeInfo[] memory transmitters = new TransmitterPayeeInfo[](transmitterCount);
+
+ for (uint256 i = 0; i < transmitterCount; i++) {
+ address transmitterAddress = s_transmittersList[i];
+ address payeeAddress = s_transmitterPayees[transmitterAddress];
+
+ transmitters[i] = TransmitterPayeeInfo(transmitterAddress, payeeAddress);
+ }
+
+ return transmitters;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/ARMProxy.sol b/contracts/src/v0.8/ccip/ARMProxy.sol
new file mode 100644
index 00000000000..e9ccde8680b
--- /dev/null
+++ b/contracts/src/v0.8/ccip/ARMProxy.sol
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
+
+import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol";
+
+/// @notice The ARMProxy serves to allow CCIP contracts
+/// to point to a static address for ARM queries, which saves gas
+/// since each contract need not store an ARM address in storage. That way
+/// we can add ARM queries along many code paths for increased defense in depth
+/// with minimal additional cost.
+contract ARMProxy is OwnerIsCreator, ITypeAndVersion {
+ error ZeroAddressNotAllowed();
+
+ event ARMSet(address arm);
+
+ // STATIC CONFIG
+ // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables
+ string public constant override typeAndVersion = "ARMProxy 1.0.0";
+
+ // DYNAMIC CONFIG
+ address private s_arm;
+
+ constructor(address arm) {
+ setARM(arm);
+ }
+
+ /// @notice SetARM sets the ARM implementation contract address.
+ /// @param arm The address of the arm implementation contract.
+ function setARM(address arm) public onlyOwner {
+ if (arm == address(0)) revert ZeroAddressNotAllowed();
+ s_arm = arm;
+ emit ARMSet(arm);
+ }
+
+ /// @notice getARM gets the ARM implementation contract address.
+ /// @return arm The address of the arm implementation contract.
+ function getARM() external view returns (address) {
+ return s_arm;
+ }
+
+ // We use a fallback function instead of explicit implementations of the functions
+ // defined in IRMN.sol to preserve compatibility with future additions to the IRMN
+ // interface. Calling IRMN interface methods in ARMProxy should be transparent, i.e.
+ // their input/output behaviour should be identical to calling the proxied s_arm
+ // contract directly. (If s_arm doesn't point to a contract, we always revert.)
+ // solhint-disable-next-line payable-fallback, no-complex-fallback
+ fallback() external {
+ address arm = s_arm;
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ // Revert if no contract present at destination address, otherwise call
+ // might succeed unintentionally.
+ if iszero(extcodesize(arm)) { revert(0, 0) }
+ // We use memory starting at zero, overwriting anything that might already
+ // be stored there. This messes with Solidity's expectations around memory
+ // layout, but it's fine because we always exit execution of this contract
+ // inside this assembly block, i.e. we don't cede control to code generated
+ // by the Solidity compiler that might have expectations around memory
+ // layout.
+ // Copy calldatasize() bytes from calldata offset 0 to memory offset 0.
+ calldatacopy(0, 0, calldatasize())
+ // Call the underlying ARM implementation. out and outsize are 0 because
+ // we don't know the size yet. We hardcode value to zero.
+ let success := call(gas(), arm, 0, 0, calldatasize(), 0, 0)
+ // Copy the returned data.
+ returndatacopy(0, 0, returndatasize())
+ // Pass through successful return or revert and associated data.
+ if success { return(0, returndatasize()) }
+ revert(0, returndatasize())
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/AggregateRateLimiter.sol b/contracts/src/v0.8/ccip/AggregateRateLimiter.sol
new file mode 100644
index 00000000000..7401df2ed49
--- /dev/null
+++ b/contracts/src/v0.8/ccip/AggregateRateLimiter.sol
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol";
+
+import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol";
+import {Client} from "./libraries/Client.sol";
+import {RateLimiter} from "./libraries/RateLimiter.sol";
+import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol";
+
+/// @notice The aggregate rate limiter is a wrapper of the token bucket rate limiter
+/// which permits rate limiting based on the aggregate value of a group of
+/// token transfers, using a price registry to convert to a numeraire asset (e.g. USD).
+contract AggregateRateLimiter is OwnerIsCreator {
+ using RateLimiter for RateLimiter.TokenBucket;
+ using USDPriceWith18Decimals for uint224;
+
+ error PriceNotFoundForToken(address token);
+
+ event AdminSet(address newAdmin);
+
+ // The address of the token limit admin that has the same permissions as the owner.
+ address internal s_admin;
+
+ // The token bucket object that contains the bucket state.
+ RateLimiter.TokenBucket private s_rateLimiter;
+
+ /// @param config The RateLimiter.Config
+ constructor(RateLimiter.Config memory config) {
+ s_rateLimiter = RateLimiter.TokenBucket({
+ rate: config.rate,
+ capacity: config.capacity,
+ tokens: config.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: config.isEnabled
+ });
+ }
+
+ /// @notice Consumes value from the rate limiter bucket based on the token value given.
+ function _rateLimitValue(uint256 value) internal {
+ s_rateLimiter._consume(value, address(0));
+ }
+
+ function _getTokenValue(
+ Client.EVMTokenAmount memory tokenAmount,
+ IPriceRegistry priceRegistry
+ ) internal view returns (uint256) {
+ // not fetching validated price, as price staleness is not important for value-based rate limiting
+ // we only need to verify the price is not 0
+ uint224 pricePerToken = priceRegistry.getTokenPrice(tokenAmount.token).value;
+ if (pricePerToken == 0) revert PriceNotFoundForToken(tokenAmount.token);
+ return pricePerToken._calcUSDValueFromTokenAmount(tokenAmount.amount);
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function currentRateLimiterState() external view returns (RateLimiter.TokenBucket memory) {
+ return s_rateLimiter._currentTokenBucketState();
+ }
+
+ /// @notice Sets the rate limited config.
+ /// @param config The new rate limiter config.
+ /// @dev should only be callable by the owner or token limit admin.
+ function setRateLimiterConfig(RateLimiter.Config memory config) external onlyAdminOrOwner {
+ s_rateLimiter._setTokenBucketConfig(config);
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @notice Gets the token limit admin address.
+ /// @return the token limit admin address.
+ function getTokenLimitAdmin() external view returns (address) {
+ return s_admin;
+ }
+
+ /// @notice Sets the token limit admin address.
+ /// @param newAdmin the address of the new admin.
+ /// @dev setting this to address(0) indicates there is no active admin.
+ function setAdmin(address newAdmin) external onlyAdminOrOwner {
+ s_admin = newAdmin;
+ emit AdminSet(newAdmin);
+ }
+
+ /// @notice a modifier that allows the owner or the s_tokenLimitAdmin call the functions
+ /// it is applied to.
+ modifier onlyAdminOrOwner() {
+ if (msg.sender != owner() && msg.sender != s_admin) revert RateLimiter.OnlyCallableByAdminOrOwner();
+ _;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/CommitStore.sol b/contracts/src/v0.8/ccip/CommitStore.sol
new file mode 100644
index 00000000000..27388b6dcc2
--- /dev/null
+++ b/contracts/src/v0.8/ccip/CommitStore.sol
@@ -0,0 +1,314 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
+import {ICommitStore} from "./interfaces/ICommitStore.sol";
+import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol";
+import {IRMN} from "./interfaces/IRMN.sol";
+
+import {Internal} from "./libraries/Internal.sol";
+import {MerkleMultiProof} from "./libraries/MerkleMultiProof.sol";
+import {OCR2Base} from "./ocr/OCR2Base.sol";
+
+contract CommitStore is ICommitStore, ITypeAndVersion, OCR2Base {
+ error StaleReport();
+ error PausedError();
+ error InvalidInterval(Interval interval);
+ error InvalidRoot();
+ error InvalidCommitStoreConfig();
+ error CursedByRMN();
+ error RootAlreadyCommitted();
+
+ event Paused(address account);
+ event Unpaused(address account);
+ /// @dev RMN depends on this event, if changing, please notify the RMN maintainers.
+ event ReportAccepted(CommitReport report);
+ event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig);
+ event RootRemoved(bytes32 root);
+ event SequenceNumberSet(uint64 oldSeqNum, uint64 newSeqNum);
+ event LatestPriceEpochAndRoundSet(uint40 oldEpochAndRound, uint40 newEpochAndRound);
+
+ /// @notice Static commit store config
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ //solhint-disable gas-struct-packing
+ struct StaticConfig {
+ uint64 chainSelector; // ───────╮ Destination chainSelector
+ uint64 sourceChainSelector; // ─╯ Source chainSelector
+ address onRamp; // OnRamp address on the source chain
+ address rmnProxy; // RMN proxy address
+ }
+
+ /// @notice Dynamic commit store config
+ struct DynamicConfig {
+ address priceRegistry; // Price registry address on the destination chain
+ }
+
+ /// @notice a sequenceNumber interval
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct Interval {
+ uint64 min; // ───╮ Minimum sequence number, inclusive
+ uint64 max; // ───╯ Maximum sequence number, inclusive
+ }
+
+ /// @notice Report that is committed by the observing DON at the committing phase
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct CommitReport {
+ Internal.PriceUpdates priceUpdates;
+ Interval interval;
+ bytes32 merkleRoot;
+ }
+
+ // STATIC CONFIG
+ string public constant override typeAndVersion = "CommitStore 1.5.0-dev";
+ // Chain ID of this chain
+ uint64 internal immutable i_chainSelector;
+ // Chain ID of the source chain
+ uint64 internal immutable i_sourceChainSelector;
+ // The onRamp address on the source chain
+ address internal immutable i_onRamp;
+ // The address of the rmn proxy
+ address internal immutable i_rmnProxy;
+
+ // DYNAMIC CONFIG
+ // The dynamic commitStore config
+ DynamicConfig internal s_dynamicConfig;
+
+ // STATE
+ // The min sequence number expected for future messages
+ uint64 private s_minSeqNr = 1;
+ /// @dev The epoch and round of the last report
+ uint40 private s_latestPriceEpochAndRound;
+ /// @dev Whether this CommitStore is paused or not
+ bool private s_paused = false;
+ // merkleRoot => timestamp when received
+ mapping(bytes32 merkleRoot => uint256 timestamp) private s_roots;
+
+ /// @param staticConfig Containing the static part of the commitStore config
+ /// @dev When instantiating OCR2Base we set UNIQUE_REPORTS to false, which means
+ /// that we do not require 2f+1 signatures on a report, only f+1 to save gas. 2f+1 is required
+ /// only if one must strictly ensure that for a given round there is only one valid report ever generated by
+ /// the DON. In our case additional valid reports (i.e. approved by >= f+1 oracles) are not a problem, as they will
+ /// will either be ignored (reverted as an invalid interval) or will be accepted as an additional valid price update.
+ constructor(StaticConfig memory staticConfig) OCR2Base(false) {
+ if (
+ staticConfig.onRamp == address(0) || staticConfig.chainSelector == 0 || staticConfig.sourceChainSelector == 0
+ || staticConfig.rmnProxy == address(0)
+ ) revert InvalidCommitStoreConfig();
+
+ i_chainSelector = staticConfig.chainSelector;
+ i_sourceChainSelector = staticConfig.sourceChainSelector;
+ i_onRamp = staticConfig.onRamp;
+ i_rmnProxy = staticConfig.rmnProxy;
+ }
+
+ // ================================================================
+ // │ Verification │
+ // ================================================================
+
+ /// @notice Returns the next expected sequence number.
+ /// @return the next expected sequenceNumber.
+ function getExpectedNextSequenceNumber() external view returns (uint64) {
+ return s_minSeqNr;
+ }
+
+ /// @notice Sets the minimum sequence number.
+ /// @param minSeqNr The new minimum sequence number.
+ function setMinSeqNr(uint64 minSeqNr) external onlyOwner {
+ uint64 oldSeqNum = s_minSeqNr;
+
+ s_minSeqNr = minSeqNr;
+
+ emit SequenceNumberSet(oldSeqNum, minSeqNr);
+ }
+
+ /// @notice Returns the epoch and round of the last price update.
+ /// @return the latest price epoch and round.
+ function getLatestPriceEpochAndRound() external view returns (uint64) {
+ return s_latestPriceEpochAndRound;
+ }
+
+ /// @notice Sets the latest epoch and round for price update.
+ /// @param latestPriceEpochAndRound The new epoch and round for prices.
+ function setLatestPriceEpochAndRound(uint40 latestPriceEpochAndRound) external onlyOwner {
+ uint40 oldEpochAndRound = s_latestPriceEpochAndRound;
+
+ s_latestPriceEpochAndRound = latestPriceEpochAndRound;
+
+ emit LatestPriceEpochAndRoundSet(oldEpochAndRound, latestPriceEpochAndRound);
+ }
+
+ /// @notice Returns the timestamp of a potentially previously committed merkle root.
+ /// If the root was never committed 0 will be returned.
+ /// @param root The merkle root to check the commit status for.
+ /// @return the timestamp of the committed root or zero in the case that it was never
+ /// committed.
+ function getMerkleRoot(bytes32 root) external view returns (uint256) {
+ return s_roots[root];
+ }
+
+ /// @notice Returns if a root is blessed or not.
+ /// @param root The merkle root to check the blessing status for.
+ /// @return whether the root is blessed or not.
+ function isBlessed(bytes32 root) public view returns (bool) {
+ return IRMN(i_rmnProxy).isBlessed(IRMN.TaggedRoot({commitStore: address(this), root: root}));
+ }
+
+ /// @notice Used by the owner in case an invalid sequence of roots has been
+ /// posted and needs to be removed. The interval in the report is trusted.
+ /// @param rootToReset The roots that will be reset. This function will only
+ /// reset roots that are not blessed.
+ function resetUnblessedRoots(bytes32[] calldata rootToReset) external onlyOwner {
+ for (uint256 i = 0; i < rootToReset.length; ++i) {
+ bytes32 root = rootToReset[i];
+ if (!isBlessed(root)) {
+ delete s_roots[root];
+ emit RootRemoved(root);
+ }
+ }
+ }
+
+ /// @inheritdoc ICommitStore
+ function verify(
+ bytes32[] calldata hashedLeaves,
+ bytes32[] calldata proofs,
+ uint256 proofFlagBits
+ ) external view override whenNotPaused returns (uint256 timestamp) {
+ bytes32 root = MerkleMultiProof.merkleRoot(hashedLeaves, proofs, proofFlagBits);
+ // Only return non-zero if present and blessed.
+ if (!isBlessed(root)) {
+ return 0;
+ }
+ return s_roots[root];
+ }
+
+ /// @inheritdoc OCR2Base
+ /// @dev A commitReport can have two distinct parts (batched together to amortize the cost of checking sigs):
+ /// 1. Price updates
+ /// 2. A merkle root and sequence number interval
+ /// Both have their own, separate, staleness checks, with price updates using the epoch and round
+ /// number of the latest price update. The merkle root checks for staleness based on the seqNums.
+ /// They need to be separate because a price report for round t+2 might be included before a report
+ /// containing a merkle root for round t+1. This merkle root report for round t+1 is still valid
+ /// and should not be rejected. When a report with a stale root but valid price updates is submitted,
+ /// we are OK to revert to preserve the invariant that we always revert on invalid sequence number ranges.
+ /// If that happens, prices will be updates in later rounds.
+ function _report(bytes calldata encodedReport, uint40 epochAndRound) internal override whenNotPaused {
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(i_sourceChainSelector)))) revert CursedByRMN();
+
+ CommitReport memory report = abi.decode(encodedReport, (CommitReport));
+
+ // Check if the report contains price updates
+ if (report.priceUpdates.tokenPriceUpdates.length > 0 || report.priceUpdates.gasPriceUpdates.length > 0) {
+ // Check for price staleness based on the epoch and round
+ if (s_latestPriceEpochAndRound < epochAndRound) {
+ // If prices are not stale, update the latest epoch and round
+ s_latestPriceEpochAndRound = epochAndRound;
+ // And update the prices in the price registry
+ IPriceRegistry(s_dynamicConfig.priceRegistry).updatePrices(report.priceUpdates);
+
+ // If there is no root, the report only contained fee updated and
+ // we return to not revert on the empty root check below.
+ if (report.merkleRoot == bytes32(0)) return;
+ } else {
+ // If prices are stale and the report doesn't contain a root, this report
+ // does not have any valid information and we revert.
+ // If it does contain a merkle root, continue to the root checking section.
+ if (report.merkleRoot == bytes32(0)) revert StaleReport();
+ }
+ }
+
+ // If we reached this section, the report should contain a valid root
+ if (s_minSeqNr != report.interval.min || report.interval.min > report.interval.max) {
+ revert InvalidInterval(report.interval);
+ }
+
+ if (report.merkleRoot == bytes32(0)) revert InvalidRoot();
+ // Disallow duplicate roots as that would reset the timestamp and
+ // delay potential manual execution.
+ if (s_roots[report.merkleRoot] != 0) revert RootAlreadyCommitted();
+
+ s_minSeqNr = report.interval.max + 1;
+ s_roots[report.merkleRoot] = block.timestamp;
+ emit ReportAccepted(report);
+ }
+
+ // ================================================================
+ // │ Config │
+ // ================================================================
+
+ /// @notice Returns the static commit store config.
+ /// @dev RMN depends on this function, if changing, please notify the RMN maintainers.
+ /// @return the configuration.
+ function getStaticConfig() external view returns (StaticConfig memory) {
+ return StaticConfig({
+ chainSelector: i_chainSelector,
+ sourceChainSelector: i_sourceChainSelector,
+ onRamp: i_onRamp,
+ rmnProxy: i_rmnProxy
+ });
+ }
+
+ /// @notice Returns the dynamic commit store config.
+ /// @return the configuration.
+ function getDynamicConfig() external view returns (DynamicConfig memory) {
+ return s_dynamicConfig;
+ }
+
+ /// @notice Sets the dynamic config. This function is called during `setOCR2Config` flow
+ function _beforeSetConfig(bytes memory onchainConfig) internal override {
+ DynamicConfig memory dynamicConfig = abi.decode(onchainConfig, (DynamicConfig));
+
+ if (dynamicConfig.priceRegistry == address(0)) revert InvalidCommitStoreConfig();
+
+ s_dynamicConfig = dynamicConfig;
+ // When the OCR config changes, we reset the price epoch and round
+ // since epoch and rounds are scoped per config digest.
+ // Note that s_minSeqNr/roots do not need to be reset as the roots persist
+ // across reconfigurations and are de-duplicated separately.
+ s_latestPriceEpochAndRound = 0;
+
+ emit ConfigSet(
+ StaticConfig({
+ chainSelector: i_chainSelector,
+ sourceChainSelector: i_sourceChainSelector,
+ onRamp: i_onRamp,
+ rmnProxy: i_rmnProxy
+ }),
+ dynamicConfig
+ );
+ }
+
+ // ================================================================
+ // │ Access and RMN │
+ // ================================================================
+
+ /// @notice Single function to check the status of the commitStore.
+ function isUnpausedAndNotCursed() external view returns (bool) {
+ return !IRMN(i_rmnProxy).isCursed(bytes16(uint128(i_sourceChainSelector))) && !s_paused;
+ }
+
+ /// @notice Modifier to make a function callable only when the contract is not paused.
+ modifier whenNotPaused() {
+ if (paused()) revert PausedError();
+ _;
+ }
+
+ /// @notice Returns true if the contract is paused, and false otherwise.
+ function paused() public view returns (bool) {
+ return s_paused;
+ }
+
+ /// @notice Pause the contract
+ /// @dev only callable by the owner
+ function pause() external onlyOwner {
+ s_paused = true;
+ emit Paused(msg.sender);
+ }
+
+ /// @notice Unpause the contract
+ /// @dev only callable by the owner
+ function unpause() external onlyOwner {
+ s_paused = false;
+ emit Unpaused(msg.sender);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/LICENSE-MIT.md b/contracts/src/v0.8/ccip/LICENSE-MIT.md
new file mode 100644
index 00000000000..812debd8e9b
--- /dev/null
+++ b/contracts/src/v0.8/ccip/LICENSE-MIT.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 SmartContract ChainLink, Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/contracts/src/v0.8/ccip/LICENSE.md b/contracts/src/v0.8/ccip/LICENSE.md
new file mode 100644
index 00000000000..5f2783f7a34
--- /dev/null
+++ b/contracts/src/v0.8/ccip/LICENSE.md
@@ -0,0 +1,56 @@
+Business Source License 1.1
+
+License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
+"Business Source License" is a trademark of MariaDB Corporation Ab.
+
+-----------------------------------------------------------------------------
+
+Parameters
+
+Licensor: SmartContract Chainlink Limited SEZC
+
+Licensed Work: Cross-Chain Interoperability Protocol v1.4
+The Licensed Work is (c) 2023 SmartContract Chainlink Limited SEZC
+
+Additional Use Grant: Any uses listed and defined at [v1.4-CCIP-License-grants](
+./v1.4-CCIP-License-grants)
+
+Change Date: May 23, 2027
+
+Change License: MIT
+
+-----------------------------------------------------------------------------
+
+Terms
+
+The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use.
+
+Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate.
+
+If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work.
+
+All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor.
+
+You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work.
+
+Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work.
+
+This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License).
+
+TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
+
+MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below.
+
+-----------------------------------------------------------------------------
+
+Covenants of Licensor
+
+In consideration of the right to use this License’s text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor:
+
+1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation.
+
+2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None".
+
+3. To specify a Change Date.
+
+4. Not to modify this License in any other way.
\ No newline at end of file
diff --git a/contracts/src/v0.8/ccip/MultiAggregateRateLimiter.sol b/contracts/src/v0.8/ccip/MultiAggregateRateLimiter.sol
new file mode 100644
index 00000000000..2a9d087a26c
--- /dev/null
+++ b/contracts/src/v0.8/ccip/MultiAggregateRateLimiter.sol
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IMessageInterceptor} from "./interfaces/IMessageInterceptor.sol";
+import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol";
+
+import {AuthorizedCallers} from "../shared/access/AuthorizedCallers.sol";
+import {EnumerableMapAddresses} from "./../shared/enumerable/EnumerableMapAddresses.sol";
+import {Client} from "./libraries/Client.sol";
+import {RateLimiter} from "./libraries/RateLimiter.sol";
+import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol";
+
+import {EnumerableSet} from "./../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @notice The aggregate rate limiter is a wrapper of the token bucket rate limiter
+/// which permits rate limiting based on the aggregate value of a group of
+/// token transfers, using a price registry to convert to a numeraire asset (e.g. USD).
+/// The contract is a standalone multi-lane message validator contract, which can be called by authorized
+/// ramp contracts to apply rate limit changes to lanes, and revert when the rate limits get breached.
+contract MultiAggregateRateLimiter is IMessageInterceptor, AuthorizedCallers {
+ using RateLimiter for RateLimiter.TokenBucket;
+ using USDPriceWith18Decimals for uint224;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
+ using EnumerableSet for EnumerableSet.AddressSet;
+
+ error PriceNotFoundForToken(address token);
+ error ZeroChainSelectorNotAllowed();
+
+ event RateLimiterConfigUpdated(uint64 indexed remoteChainSelector, bool isOutboundLane, RateLimiter.Config config);
+ event PriceRegistrySet(address newPriceRegistry);
+ event TokenAggregateRateLimitAdded(uint64 remoteChainSelector, bytes32 remoteToken, address localToken);
+ event TokenAggregateRateLimitRemoved(uint64 remoteChainSelector, address localToken);
+
+ /// @notice RemoteRateLimitToken struct containing the local token address with the chain selector
+ /// The struct is used for removals and updates, since the local -> remote token mappings are scoped per-chain
+ struct LocalRateLimitToken {
+ uint64 remoteChainSelector; // ────╮ Remote chain selector for which to update the rate limit token mapping
+ address localToken; // ────────────╯ Token on the chain on which the multi-ARL is deployed
+ }
+
+ /// @notice RateLimitToken struct containing both the local and remote token addresses
+ struct RateLimitTokenArgs {
+ LocalRateLimitToken localTokenArgs; // Local token update args scoped to one remote chain
+ bytes32 remoteToken; // Token on the remote chain (for OnRamp - dest, of OffRamp - source)
+ }
+
+ /// @notice Update args for a single rate limiter config update
+ struct RateLimiterConfigArgs {
+ uint64 remoteChainSelector; // ────╮ Chain selector to set config for
+ bool isOutboundLane; // ───────────╯ If set to true, represents the outbound message lane (OnRamp), and the inbound message lane otherwise (OffRamp)
+ RateLimiter.Config rateLimiterConfig; // Rate limiter config to set
+ }
+
+ /// @notice Struct to store rate limit token buckets for both lane directions
+ struct RateLimiterBuckets {
+ RateLimiter.TokenBucket inboundLaneBucket; // Bucket for the inbound lane (remote -> local)
+ RateLimiter.TokenBucket outboundLaneBucket; // Bucket for the outbound lane (local -> remote)
+ }
+
+ /// @dev Tokens that should be included in Aggregate Rate Limiting (from local chain (this chain) -> remote),
+ /// grouped per-remote chain.
+ mapping(uint64 remoteChainSelector => EnumerableMapAddresses.AddressToBytes32Map tokensLocalToRemote) internal
+ s_rateLimitedTokensLocalToRemote;
+
+ /// @notice The address of the PriceRegistry used to query token values for ratelimiting
+ address internal s_priceRegistry;
+
+ /// @notice Rate limiter token bucket states per chain, with separate buckets for inbound and outbound lanes.
+ mapping(uint64 remoteChainSelector => RateLimiterBuckets buckets) internal s_rateLimitersByChainSelector;
+
+ /// @param priceRegistry the price registry to set
+ /// @param authorizedCallers the authorized callers to set
+ constructor(address priceRegistry, address[] memory authorizedCallers) AuthorizedCallers(authorizedCallers) {
+ _setPriceRegistry(priceRegistry);
+ }
+
+ /// @inheritdoc IMessageInterceptor
+ function onInboundMessage(Client.Any2EVMMessage memory message) external onlyAuthorizedCallers {
+ _applyRateLimit(message.sourceChainSelector, message.destTokenAmounts, false);
+ }
+
+ /// @inheritdoc IMessageInterceptor
+ function onOutboundMessage(
+ uint64 destChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external onlyAuthorizedCallers {
+ _applyRateLimit(destChainSelector, message.tokenAmounts, true);
+ }
+
+ /// @notice Applies the rate limit to the token bucket if enabled
+ /// @param remoteChainSelector The remote chain selector
+ /// @param tokenAmounts The tokens and amounts to rate limit
+ /// @param isOutgoingLane if set to true, fetches the bucket for the outgoing message lane (OnRamp).
+ function _applyRateLimit(
+ uint64 remoteChainSelector,
+ Client.EVMTokenAmount[] memory tokenAmounts,
+ bool isOutgoingLane
+ ) private {
+ RateLimiter.TokenBucket storage tokenBucket = _getTokenBucket(remoteChainSelector, isOutgoingLane);
+
+ // Skip rate limiting if it is disabled
+ if (tokenBucket.isEnabled) {
+ uint256 value;
+ for (uint256 i = 0; i < tokenAmounts.length; ++i) {
+ if (s_rateLimitedTokensLocalToRemote[remoteChainSelector].contains(tokenAmounts[i].token)) {
+ value += _getTokenValue(tokenAmounts[i]);
+ }
+ }
+ // Rate limit on aggregated token value
+ if (value > 0) tokenBucket._consume(value, address(0));
+ }
+ }
+
+ /// @param remoteChainSelector chain selector to retrieve token bucket for
+ /// @param isOutboundLane if set to true, fetches the bucket for the outbound message lane (OnRamp).
+ /// Otherwise fetches for the inbound message lane (OffRamp).
+ /// @return bucket Storage pointer to the token bucket representing a specific lane
+ function _getTokenBucket(
+ uint64 remoteChainSelector,
+ bool isOutboundLane
+ ) internal view returns (RateLimiter.TokenBucket storage) {
+ RateLimiterBuckets storage rateLimiterBuckets = s_rateLimitersByChainSelector[remoteChainSelector];
+ if (isOutboundLane) {
+ return rateLimiterBuckets.outboundLaneBucket;
+ } else {
+ return rateLimiterBuckets.inboundLaneBucket;
+ }
+ }
+
+ /// @notice Retrieves the token value for a token using the PriceRegistry
+ /// @return tokenValue USD value in 18 decimals
+ function _getTokenValue(Client.EVMTokenAmount memory tokenAmount) internal view returns (uint256) {
+ // not fetching validated price, as price staleness is not important for value-based rate limiting
+ // we only need to verify the price is not 0
+ uint224 pricePerToken = IPriceRegistry(s_priceRegistry).getTokenPrice(tokenAmount.token).value;
+ if (pricePerToken == 0) revert PriceNotFoundForToken(tokenAmount.token);
+ return pricePerToken._calcUSDValueFromTokenAmount(tokenAmount.amount);
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @param remoteChainSelector chain selector to retrieve state for
+ /// @param isOutboundLane if set to true, fetches the rate limit state for the outbound message lane (OnRamp).
+ /// Otherwise fetches for the inbound message lane (OffRamp).
+ /// The outbound and inbound message rate limit state is completely separated.
+ /// @return The token bucket.
+ function currentRateLimiterState(
+ uint64 remoteChainSelector,
+ bool isOutboundLane
+ ) external view returns (RateLimiter.TokenBucket memory) {
+ return _getTokenBucket(remoteChainSelector, isOutboundLane)._currentTokenBucketState();
+ }
+
+ /// @notice Applies the provided rate limiter config updates.
+ /// @param rateLimiterUpdates Rate limiter updates
+ /// @dev should only be callable by the owner
+ function applyRateLimiterConfigUpdates(RateLimiterConfigArgs[] memory rateLimiterUpdates) external onlyOwner {
+ for (uint256 i = 0; i < rateLimiterUpdates.length; ++i) {
+ RateLimiterConfigArgs memory updateArgs = rateLimiterUpdates[i];
+ RateLimiter.Config memory configUpdate = updateArgs.rateLimiterConfig;
+ uint64 remoteChainSelector = updateArgs.remoteChainSelector;
+
+ if (remoteChainSelector == 0) {
+ revert ZeroChainSelectorNotAllowed();
+ }
+
+ bool isOutboundLane = updateArgs.isOutboundLane;
+
+ RateLimiter.TokenBucket storage tokenBucket = _getTokenBucket(remoteChainSelector, isOutboundLane);
+
+ if (tokenBucket.lastUpdated == 0) {
+ // Token bucket needs to be newly added
+ RateLimiter.TokenBucket memory newTokenBucket = RateLimiter.TokenBucket({
+ rate: configUpdate.rate,
+ capacity: configUpdate.capacity,
+ tokens: configUpdate.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: configUpdate.isEnabled
+ });
+
+ if (isOutboundLane) {
+ s_rateLimitersByChainSelector[remoteChainSelector].outboundLaneBucket = newTokenBucket;
+ } else {
+ s_rateLimitersByChainSelector[remoteChainSelector].inboundLaneBucket = newTokenBucket;
+ }
+ } else {
+ tokenBucket._setTokenBucketConfig(configUpdate);
+ }
+ emit RateLimiterConfigUpdated(remoteChainSelector, isOutboundLane, configUpdate);
+ }
+ }
+
+ /// @notice Get all tokens which are included in Aggregate Rate Limiting.
+ /// @param remoteChainSelector chain selector to get rate limit tokens for
+ /// @return localTokens The local chain representation of the tokens that are rate limited.
+ /// @return remoteTokens The remote representation of the tokens that are rate limited.
+ /// @dev the order of IDs in the list is **not guaranteed**, therefore, if ordering matters when
+ /// making successive calls, one should keep the block height constant to ensure a consistent result.
+ function getAllRateLimitTokens(uint64 remoteChainSelector)
+ external
+ view
+ returns (address[] memory localTokens, bytes32[] memory remoteTokens)
+ {
+ uint256 tokenCount = s_rateLimitedTokensLocalToRemote[remoteChainSelector].length();
+
+ localTokens = new address[](tokenCount);
+ remoteTokens = new bytes32[](tokenCount);
+
+ for (uint256 i = 0; i < tokenCount; ++i) {
+ (address localToken, bytes32 remoteToken) = s_rateLimitedTokensLocalToRemote[remoteChainSelector].at(i);
+ localTokens[i] = localToken;
+ remoteTokens[i] = remoteToken;
+ }
+ return (localTokens, remoteTokens);
+ }
+
+ /// @notice Adds or removes tokens from being used in Aggregate Rate Limiting.
+ /// @param removes - A list of one or more tokens to be removed.
+ /// @param adds - A list of one or more tokens to be added.
+ function updateRateLimitTokens(
+ LocalRateLimitToken[] memory removes,
+ RateLimitTokenArgs[] memory adds
+ ) external onlyOwner {
+ for (uint256 i = 0; i < removes.length; ++i) {
+ address localToken = removes[i].localToken;
+ uint64 remoteChainSelector = removes[i].remoteChainSelector;
+
+ if (s_rateLimitedTokensLocalToRemote[remoteChainSelector].remove(localToken)) {
+ emit TokenAggregateRateLimitRemoved(remoteChainSelector, localToken);
+ }
+ }
+
+ for (uint256 i = 0; i < adds.length; ++i) {
+ LocalRateLimitToken memory localTokenArgs = adds[i].localTokenArgs;
+ bytes32 remoteToken = adds[i].remoteToken;
+ address localToken = localTokenArgs.localToken;
+
+ if (localToken == address(0) || remoteToken == bytes32("")) {
+ revert ZeroAddressNotAllowed();
+ }
+
+ uint64 remoteChainSelector = localTokenArgs.remoteChainSelector;
+
+ if (s_rateLimitedTokensLocalToRemote[remoteChainSelector].set(localToken, remoteToken)) {
+ emit TokenAggregateRateLimitAdded(remoteChainSelector, remoteToken, localToken);
+ }
+ }
+ }
+
+ /// @return priceRegistry The configured PriceRegistry address
+ function getPriceRegistry() external view returns (address) {
+ return s_priceRegistry;
+ }
+
+ /// @notice Sets the Price Registry address
+ /// @param newPriceRegistry the address of the new PriceRegistry
+ /// @dev precondition The address must be a non-zero address
+ function setPriceRegistry(address newPriceRegistry) external onlyOwner {
+ _setPriceRegistry(newPriceRegistry);
+ }
+
+ /// @notice Sets the Price Registry address
+ /// @param newPriceRegistry the address of the new PriceRegistry
+ /// @dev precondition The address must be a non-zero address
+ function _setPriceRegistry(address newPriceRegistry) internal {
+ if (newPriceRegistry == address(0)) {
+ revert ZeroAddressNotAllowed();
+ }
+
+ s_priceRegistry = newPriceRegistry;
+ emit PriceRegistrySet(newPriceRegistry);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/NonceManager.sol b/contracts/src/v0.8/ccip/NonceManager.sol
new file mode 100644
index 00000000000..2cfcbbe9e2b
--- /dev/null
+++ b/contracts/src/v0.8/ccip/NonceManager.sol
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IEVM2AnyOnRamp} from "./interfaces/IEVM2AnyOnRamp.sol";
+import {INonceManager} from "./interfaces/INonceManager.sol";
+
+import {AuthorizedCallers} from "../shared/access/AuthorizedCallers.sol";
+
+/// @title NonceManager
+/// @notice NonceManager contract that manages sender nonces for the on/off ramps
+contract NonceManager is INonceManager, AuthorizedCallers {
+ error PreviousRampAlreadySet();
+
+ event PreviousRampsUpdated(uint64 indexed remoteChainSelector, PreviousRamps prevRamp);
+ event SkippedIncorrectNonce(uint64 sourceChainSelector, uint64 nonce, bytes sender);
+
+ /// @dev Struct that contains the previous on/off ramp addresses
+ struct PreviousRamps {
+ address prevOnRamp; // Previous onRamp
+ address prevOffRamp; // Previous offRamp
+ }
+
+ /// @dev Struct that contains the chain selector and the previous on/off ramps, same as PreviousRamps but with the chain selector
+ /// so that an array of these can be passed to the applyPreviousRampsUpdates function
+ struct PreviousRampsArgs {
+ uint64 remoteChainSelector; // Chain selector
+ PreviousRamps prevRamps; // Previous on/off ramps
+ }
+
+ /// @dev previous ramps
+ mapping(uint64 chainSelector => PreviousRamps previousRamps) private s_previousRamps;
+ /// @dev The current outbound nonce per sender used on the onramp
+ mapping(uint64 destChainSelector => mapping(address sender => uint64 outboundNonce)) private s_outboundNonces;
+ /// @dev The current inbound nonce per sender used on the offramp
+ /// Eventually in sync with the outbound nonce in the remote source chain NonceManager, used to enforce that messages are
+ /// executed in the same order they are sent (assuming they are DON)
+ mapping(uint64 sourceChainSelector => mapping(bytes sender => uint64 inboundNonce)) private s_inboundNonces;
+
+ constructor(address[] memory authorizedCallers) AuthorizedCallers(authorizedCallers) {}
+
+ /// @inheritdoc INonceManager
+ function getIncrementedOutboundNonce(
+ uint64 destChainSelector,
+ address sender
+ ) external onlyAuthorizedCallers returns (uint64) {
+ uint64 outboundNonce = _getOutboundNonce(destChainSelector, sender) + 1;
+ s_outboundNonces[destChainSelector][sender] = outboundNonce;
+
+ return outboundNonce;
+ }
+
+ /// @notice Returns the outbound nonce for a given sender on a given destination chain
+ /// @param destChainSelector The destination chain selector
+ /// @param sender The sender address
+ /// @return The outbound nonce
+ function getOutboundNonce(uint64 destChainSelector, address sender) external view returns (uint64) {
+ return _getOutboundNonce(destChainSelector, sender);
+ }
+
+ function _getOutboundNonce(uint64 destChainSelector, address sender) private view returns (uint64) {
+ uint64 outboundNonce = s_outboundNonces[destChainSelector][sender];
+
+ // When introducing the NonceManager with existing lanes, we still want to have sequential nonces.
+ // Referencing the old onRamp preserves sequencing between updates.
+ if (outboundNonce == 0) {
+ address prevOnRamp = s_previousRamps[destChainSelector].prevOnRamp;
+ if (prevOnRamp != address(0)) {
+ return IEVM2AnyOnRamp(prevOnRamp).getSenderNonce(sender);
+ }
+ }
+
+ return outboundNonce;
+ }
+
+ /// @inheritdoc INonceManager
+ function incrementInboundNonce(
+ uint64 sourceChainSelector,
+ uint64 expectedNonce,
+ bytes calldata sender
+ ) external onlyAuthorizedCallers returns (bool) {
+ uint64 inboundNonce = _getInboundNonce(sourceChainSelector, sender) + 1;
+
+ if (inboundNonce != expectedNonce) {
+ // If the nonce is not the expected one, this means that there are still messages in flight so we skip
+ // the nonce increment
+ emit SkippedIncorrectNonce(sourceChainSelector, expectedNonce, sender);
+ return false;
+ }
+
+ s_inboundNonces[sourceChainSelector][sender] = inboundNonce;
+
+ return true;
+ }
+
+ /// @notice Returns the inbound nonce for a given sender on a given source chain
+ /// @param sourceChainSelector The source chain selector
+ /// @param sender The encoded sender address
+ /// @return The inbound nonce
+ function getInboundNonce(uint64 sourceChainSelector, bytes calldata sender) external view returns (uint64) {
+ return _getInboundNonce(sourceChainSelector, sender);
+ }
+
+ function _getInboundNonce(uint64 sourceChainSelector, bytes calldata sender) private view returns (uint64) {
+ uint64 inboundNonce = s_inboundNonces[sourceChainSelector][sender];
+
+ // When introducing the NonceManager with existing lanes, we still want to have sequential nonces.
+ // Referencing the old offRamp to check the expected nonce if none is set for a
+ // given sender allows us to skip the current message in the current offRamp if it would not be the next according
+ // to the old offRamp. This preserves sequencing between updates.
+ if (inboundNonce == 0) {
+ address prevOffRamp = s_previousRamps[sourceChainSelector].prevOffRamp;
+ if (prevOffRamp != address(0)) {
+ // We only expect EVM previous offRamps here so we can safely decode the sender
+ return IEVM2AnyOnRamp(prevOffRamp).getSenderNonce(abi.decode(sender, (address)));
+ }
+ }
+
+ return inboundNonce;
+ }
+
+ /// @notice Updates the previous ramps addresses
+ /// @param previousRampsArgs The previous on/off ramps addresses
+ function applyPreviousRampsUpdates(PreviousRampsArgs[] calldata previousRampsArgs) external onlyOwner {
+ for (uint256 i = 0; i < previousRampsArgs.length; ++i) {
+ PreviousRampsArgs calldata previousRampsArg = previousRampsArgs[i];
+
+ PreviousRamps storage prevRamps = s_previousRamps[previousRampsArg.remoteChainSelector];
+
+ // If the previous ramps are already set then they should not be updated
+ if (prevRamps.prevOnRamp != address(0) || prevRamps.prevOffRamp != address(0)) {
+ revert PreviousRampAlreadySet();
+ }
+
+ prevRamps.prevOnRamp = previousRampsArg.prevRamps.prevOnRamp;
+ prevRamps.prevOffRamp = previousRampsArg.prevRamps.prevOffRamp;
+
+ emit PreviousRampsUpdated(previousRampsArg.remoteChainSelector, previousRampsArg.prevRamps);
+ }
+ }
+
+ /// @notice Gets the previous onRamp address for the given chain selector
+ /// @param chainSelector The chain selector
+ /// @return The previous onRamp address
+ function getPreviousRamps(uint64 chainSelector) external view returns (PreviousRamps memory) {
+ return s_previousRamps[chainSelector];
+ }
+}
diff --git a/contracts/src/v0.8/ccip/PriceRegistry.sol b/contracts/src/v0.8/ccip/PriceRegistry.sol
new file mode 100644
index 00000000000..f15232271e9
--- /dev/null
+++ b/contracts/src/v0.8/ccip/PriceRegistry.sol
@@ -0,0 +1,888 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
+import {IPriceRegistry} from "./interfaces/IPriceRegistry.sol";
+
+import {AuthorizedCallers} from "../shared/access/AuthorizedCallers.sol";
+import {AggregatorV3Interface} from "./../shared/interfaces/AggregatorV3Interface.sol";
+import {Client} from "./libraries/Client.sol";
+import {Internal} from "./libraries/Internal.sol";
+import {Pool} from "./libraries/Pool.sol";
+import {USDPriceWith18Decimals} from "./libraries/USDPriceWith18Decimals.sol";
+
+import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @notice The PriceRegistry contract responsibility is to store the current gas price in USD for a given destination chain,
+/// and the price of a token in USD allowing the owner or priceUpdater to update this value.
+/// The authorized callers in the contract represent the fee price updaters.
+contract PriceRegistry is AuthorizedCallers, IPriceRegistry, ITypeAndVersion {
+ using EnumerableSet for EnumerableSet.AddressSet;
+ using USDPriceWith18Decimals for uint224;
+
+ /// @notice Token price data feed update
+ struct TokenPriceFeedUpdate {
+ address sourceToken; // Source token to update feed for
+ IPriceRegistry.TokenPriceFeedConfig feedConfig; // Feed config update data
+ }
+
+ /// @dev Struct that contains the static configuration
+ /// RMN depends on this struct, if changing, please notify the RMN maintainers.
+ // solhint-disable-next-line gas-struct-packing
+ struct StaticConfig {
+ uint96 maxFeeJuelsPerMsg; // ─╮ Maximum fee that can be charged for a message
+ address linkToken; // ────────╯ LINK token address
+ uint32 stalenessThreshold; // The amount of time a gas price can be stale before it is considered invalid.
+ }
+
+ error TokenNotSupported(address token);
+ error ChainNotSupported(uint64 chain);
+ error StaleGasPrice(uint64 destChainSelector, uint256 threshold, uint256 timePassed);
+ error DataFeedValueOutOfUint224Range();
+ error InvalidDestBytesOverhead(address token, uint32 destBytesOverhead);
+ error MessageGasLimitTooHigh();
+ error DestinationChainNotEnabled(uint64 destChainSelector);
+ error ExtraArgOutOfOrderExecutionMustBeTrue();
+ error InvalidExtraArgsTag();
+ error SourceTokenDataTooLarge(address token);
+ error InvalidDestChainConfig(uint64 destChainSelector);
+ error MessageFeeTooHigh(uint256 msgFeeJuels, uint256 maxFeeJuelsPerMsg);
+ error InvalidStaticConfig();
+ error MessageTooLarge(uint256 maxSize, uint256 actualSize);
+ error UnsupportedNumberOfTokens();
+
+ event PriceUpdaterSet(address indexed priceUpdater);
+ event PriceUpdaterRemoved(address indexed priceUpdater);
+ event FeeTokenAdded(address indexed feeToken);
+ event FeeTokenRemoved(address indexed feeToken);
+ event UsdPerUnitGasUpdated(uint64 indexed destChain, uint256 value, uint256 timestamp);
+ event UsdPerTokenUpdated(address indexed token, uint256 value, uint256 timestamp);
+ event PriceFeedPerTokenUpdated(address indexed token, IPriceRegistry.TokenPriceFeedConfig priceFeedConfig);
+
+ event TokenTransferFeeConfigUpdated(
+ uint64 indexed destChainSelector, address indexed token, TokenTransferFeeConfig tokenTransferFeeConfig
+ );
+ event TokenTransferFeeConfigDeleted(uint64 indexed destChainSelector, address indexed token);
+ event PremiumMultiplierWeiPerEthUpdated(address indexed token, uint64 premiumMultiplierWeiPerEth);
+ event DestChainConfigUpdated(uint64 indexed destChainSelector, DestChainConfig destChainConfig);
+ event DestChainAdded(uint64 indexed destChainSelector, DestChainConfig destChainConfig);
+
+ /// @dev Struct to hold the fee & validation configs for a destination chain
+ struct DestChainConfig {
+ bool isEnabled; // ──────────────────────────╮ Whether this destination chain is enabled
+ uint16 maxNumberOfTokensPerMsg; // │ Maximum number of distinct ERC20 token transferred per message
+ uint32 maxDataBytes; // │ Maximum payload data size in bytes
+ uint32 maxPerMsgGasLimit; // │ Maximum gas limit for messages targeting EVMs
+ uint32 destGasOverhead; // │ Gas charged on top of the gasLimit to cover destination chain costs
+ uint16 destGasPerPayloadByte; // │ Destination chain gas charged for passing each byte of `data` payload to receiver
+ uint32 destDataAvailabilityOverheadGas; // | Extra data availability gas charged on top of the message, e.g. for OCR
+ uint16 destGasPerDataAvailabilityByte; // | Amount of gas to charge per byte of message data that needs availability
+ uint16 destDataAvailabilityMultiplierBps; // │ Multiplier for data availability gas, multiples of bps, or 0.0001
+ // The following three properties are defaults, they can be overridden by setting the TokenTransferFeeConfig for a token
+ uint16 defaultTokenFeeUSDCents; // │ Default token fee charged per token transfer
+ uint32 defaultTokenDestGasOverhead; // ──────╯ Default gas charged to execute the token transfer on the destination chain
+ uint32 defaultTokenDestBytesOverhead; // ────╮ Default extra data availability bytes charged per token transfer
+ uint32 defaultTxGasLimit; // │ Default gas limit for a tx
+ uint64 gasMultiplierWeiPerEth; // │ Multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost.
+ uint32 networkFeeUSDCents; // │ Flat network fee to charge for messages, multiples of 0.01 USD
+ bool enforceOutOfOrder; // │ Whether to enforce the allowOutOfOrderExecution extraArg value to be true.
+ bytes4 chainFamilySelector; // ──────────────╯ Selector that identifies the destination chain's family. Used to determine the correct validations to perform for the dest chain.
+ }
+
+ /// @dev Struct to hold the configs and its destination chain selector
+ /// Same as DestChainConfig but with the destChainSelector so that an array of these
+ /// can be passed in the constructor and the applyDestChainConfigUpdates function
+ //solhint-disable gas-struct-packing
+ struct DestChainConfigArgs {
+ uint64 destChainSelector; // Destination chain selector
+ DestChainConfig destChainConfig; // Config to update for the chain selector
+ }
+
+ /// @dev Struct to hold the transfer fee configuration for token transfers
+ struct TokenTransferFeeConfig {
+ uint32 minFeeUSDCents; // ──────────╮ Minimum fee to charge per token transfer, multiples of 0.01 USD
+ uint32 maxFeeUSDCents; // │ Maximum fee to charge per token transfer, multiples of 0.01 USD
+ uint16 deciBps; // │ Basis points charged on token transfers, multiples of 0.1bps, or 1e-5
+ uint32 destGasOverhead; // │ Gas charged to execute the token transfer on the destination chain
+ // │ Extra data availability bytes that are returned from the source pool and sent
+ uint32 destBytesOverhead; // │ to the destination pool. Must be >= Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES
+ bool isEnabled; // ─────────────────╯ Whether this token has custom transfer fees
+ }
+
+ /// @dev Struct to hold the token transfer fee configurations for a token, same as TokenTransferFeeConfig but with the token address included so
+ /// that an array of these can be passed in the TokenTransferFeeConfigArgs struct to set the mapping
+ struct TokenTransferFeeConfigSingleTokenArgs {
+ address token; // Token address
+ TokenTransferFeeConfig tokenTransferFeeConfig; // struct to hold the transfer fee configuration for token transfers
+ }
+
+ /// @dev Struct to hold the token transfer fee configurations for a destination chain and a set of tokens. Same as TokenTransferFeeConfigSingleTokenArgs
+ /// but with the destChainSelector and an array of TokenTransferFeeConfigSingleTokenArgs included so that an array of these can be passed in the constructor
+ /// and the applyTokenTransferFeeConfigUpdates function
+ struct TokenTransferFeeConfigArgs {
+ uint64 destChainSelector; // Destination chain selector
+ TokenTransferFeeConfigSingleTokenArgs[] tokenTransferFeeConfigs; // Array of token transfer fee configurations
+ }
+
+ /// @dev Struct to hold a pair of destination chain selector and token address so that an array of these can be passed in the
+ /// applyTokenTransferFeeConfigUpdates function to remove the token transfer fee configuration for a token
+ struct TokenTransferFeeConfigRemoveArgs {
+ uint64 destChainSelector; // ─╮ Destination chain selector
+ address token; // ────────────╯ Token address
+ }
+
+ /// @dev Struct to hold the fee token configuration for a token, same as the s_premiumMultiplierWeiPerEth but with
+ /// the token address included so that an array of these can be passed in the constructor and
+ /// applyPremiumMultiplierWeiPerEthUpdates to set the mapping
+ struct PremiumMultiplierWeiPerEthArgs {
+ address token; // // ───────────────────╮ Token address
+ uint64 premiumMultiplierWeiPerEth; // ──╯ Multiplier for destination chain specific premiums. Should never be 0 so can be used as an isEnabled flag
+ }
+
+ string public constant override typeAndVersion = "PriceRegistry 1.6.0-dev";
+
+ /// @dev The gas price per unit of gas for a given destination chain, in USD with 18 decimals.
+ /// Multiple gas prices can be encoded into the same value. Each price takes {Internal.GAS_PRICE_BITS} bits.
+ /// For example, if Optimism is the destination chain, gas price can include L1 base fee and L2 gas price.
+ /// Logic to parse the price components is chain-specific, and should live in OnRamp.
+ /// @dev Price of 1e18 is 1 USD. Examples:
+ /// Very Expensive: 1 unit of gas costs 1 USD -> 1e18
+ /// Expensive: 1 unit of gas costs 0.1 USD -> 1e17
+ /// Cheap: 1 unit of gas costs 0.000001 USD -> 1e12
+ mapping(uint64 destChainSelector => Internal.TimestampedPackedUint224 price) private
+ s_usdPerUnitGasByDestChainSelector;
+
+ /// @dev The price, in USD with 18 decimals, per 1e18 of the smallest token denomination.
+ /// @dev Price of 1e18 represents 1 USD per 1e18 token amount.
+ /// 1 USDC = 1.00 USD per full token, each full token is 1e6 units -> 1 * 1e18 * 1e18 / 1e6 = 1e30
+ /// 1 ETH = 2,000 USD per full token, each full token is 1e18 units -> 2000 * 1e18 * 1e18 / 1e18 = 2_000e18
+ /// 1 LINK = 5.00 USD per full token, each full token is 1e18 units -> 5 * 1e18 * 1e18 / 1e18 = 5e18
+ mapping(address token => Internal.TimestampedPackedUint224 price) private s_usdPerToken;
+
+ /// @dev Stores the price data feed configurations per token.
+ mapping(address token => IPriceRegistry.TokenPriceFeedConfig dataFeedAddress) private s_usdPriceFeedsPerToken;
+
+ /// @dev The multiplier for destination chain specific premiums that can be set by the owner or fee admin
+ /// This should never be 0 once set, so it can be used as an isEnabled flag
+ mapping(address token => uint64 premiumMultiplierWeiPerEth) internal s_premiumMultiplierWeiPerEth;
+
+ /// @dev The destination chain specific fee configs
+ mapping(uint64 destChainSelector => DestChainConfig destChainConfig) internal s_destChainConfigs;
+
+ /// @dev The token transfer fee config that can be set by the owner or fee admin
+ mapping(uint64 destChainSelector => mapping(address token => TokenTransferFeeConfig tranferFeeConfig)) internal
+ s_tokenTransferFeeConfig;
+
+ /// @dev Maximum fee that can be charged for a message. This is a guard to prevent massively overcharging due to misconfiguation.
+ uint96 internal immutable i_maxFeeJuelsPerMsg;
+ /// @dev The link token address
+ address internal immutable i_linkToken;
+
+ // Price updaters are allowed to update the prices.
+ EnumerableSet.AddressSet private s_priceUpdaters;
+ // Subset of tokens which prices tracked by this registry which are fee tokens.
+ EnumerableSet.AddressSet private s_feeTokens;
+ // The amount of time a gas price can be stale before it is considered invalid.
+ uint32 private immutable i_stalenessThreshold;
+
+ constructor(
+ StaticConfig memory staticConfig,
+ address[] memory priceUpdaters,
+ address[] memory feeTokens,
+ TokenPriceFeedUpdate[] memory tokenPriceFeeds,
+ TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
+ PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs,
+ DestChainConfigArgs[] memory destChainConfigArgs
+ ) AuthorizedCallers(priceUpdaters) {
+ if (
+ staticConfig.linkToken == address(0) || staticConfig.maxFeeJuelsPerMsg == 0
+ || staticConfig.stalenessThreshold == 0
+ ) {
+ revert InvalidStaticConfig();
+ }
+
+ i_linkToken = staticConfig.linkToken;
+ i_maxFeeJuelsPerMsg = staticConfig.maxFeeJuelsPerMsg;
+ i_stalenessThreshold = staticConfig.stalenessThreshold;
+
+ _applyFeeTokensUpdates(feeTokens, new address[](0));
+ _updateTokenPriceFeeds(tokenPriceFeeds);
+ _applyDestChainConfigUpdates(destChainConfigArgs);
+ _applyPremiumMultiplierWeiPerEthUpdates(premiumMultiplierWeiPerEthArgs);
+ _applyTokenTransferFeeConfigUpdates(tokenTransferFeeConfigArgs, new TokenTransferFeeConfigRemoveArgs[](0));
+ }
+
+ // ================================================================
+ // │ Price calculations │
+ // ================================================================
+
+ /// @inheritdoc IPriceRegistry
+ function getTokenPrice(address token) public view override returns (Internal.TimestampedPackedUint224 memory) {
+ IPriceRegistry.TokenPriceFeedConfig memory priceFeedConfig = s_usdPriceFeedsPerToken[token];
+ if (priceFeedConfig.dataFeedAddress == address(0)) {
+ return s_usdPerToken[token];
+ }
+
+ return _getTokenPriceFromDataFeed(priceFeedConfig);
+ }
+
+ /// @inheritdoc IPriceRegistry
+ function getValidatedTokenPrice(address token) external view override returns (uint224) {
+ return _getValidatedTokenPrice(token);
+ }
+
+ /// @inheritdoc IPriceRegistry
+ function getTokenPrices(address[] calldata tokens)
+ external
+ view
+ override
+ returns (Internal.TimestampedPackedUint224[] memory)
+ {
+ uint256 length = tokens.length;
+ Internal.TimestampedPackedUint224[] memory tokenPrices = new Internal.TimestampedPackedUint224[](length);
+ for (uint256 i = 0; i < length; ++i) {
+ tokenPrices[i] = getTokenPrice(tokens[i]);
+ }
+ return tokenPrices;
+ }
+
+ /// @inheritdoc IPriceRegistry
+ function getTokenPriceFeedConfig(address token)
+ external
+ view
+ override
+ returns (IPriceRegistry.TokenPriceFeedConfig memory)
+ {
+ return s_usdPriceFeedsPerToken[token];
+ }
+
+ /// @inheritdoc IPriceRegistry
+ function getDestinationChainGasPrice(uint64 destChainSelector)
+ external
+ view
+ override
+ returns (Internal.TimestampedPackedUint224 memory)
+ {
+ return s_usdPerUnitGasByDestChainSelector[destChainSelector];
+ }
+
+ /// @inheritdoc IPriceRegistry
+ function getTokenAndGasPrices(
+ address token,
+ uint64 destChainSelector
+ ) public view override returns (uint224 tokenPrice, uint224 gasPriceValue) {
+ Internal.TimestampedPackedUint224 memory gasPrice = s_usdPerUnitGasByDestChainSelector[destChainSelector];
+ // We do allow a gas price of 0, but no stale or unset gas prices
+ if (gasPrice.timestamp == 0) revert ChainNotSupported(destChainSelector);
+ uint256 timePassed = block.timestamp - gasPrice.timestamp;
+ if (timePassed > i_stalenessThreshold) revert StaleGasPrice(destChainSelector, i_stalenessThreshold, timePassed);
+
+ return (_getValidatedTokenPrice(token), gasPrice.value);
+ }
+
+ /// @inheritdoc IPriceRegistry
+ /// @dev this function assumes that no more than 1e59 dollars are sent as payment.
+ /// If more is sent, the multiplication of feeTokenAmount and feeTokenValue will overflow.
+ /// Since there isn't even close to 1e59 dollars in the world economy this is safe.
+ function convertTokenAmount(
+ address fromToken,
+ uint256 fromTokenAmount,
+ address toToken
+ ) public view override returns (uint256) {
+ /// Example:
+ /// fromTokenAmount: 1e18 // 1 ETH
+ /// ETH: 2_000e18
+ /// LINK: 5e18
+ /// return: 1e18 * 2_000e18 / 5e18 = 400e18 (400 LINK)
+ return (fromTokenAmount * _getValidatedTokenPrice(fromToken)) / _getValidatedTokenPrice(toToken);
+ }
+
+ /// @notice Gets the token price for a given token and revert if the token is not supported
+ /// @param token The address of the token to get the price for
+ /// @return the token price
+ function _getValidatedTokenPrice(address token) internal view returns (uint224) {
+ Internal.TimestampedPackedUint224 memory tokenPrice = getTokenPrice(token);
+ // Token price must be set at least once
+ if (tokenPrice.timestamp == 0 || tokenPrice.value == 0) revert TokenNotSupported(token);
+ return tokenPrice.value;
+ }
+
+ /// @notice Gets the token price from a data feed address, rebased to the same units as s_usdPerToken
+ /// @param priceFeedConfig token data feed configuration with valid data feed address (used to retrieve price & timestamp)
+ /// @return tokenPrice data feed price answer rebased to s_usdPerToken units, with latest block timestamp
+ function _getTokenPriceFromDataFeed(IPriceRegistry.TokenPriceFeedConfig memory priceFeedConfig)
+ internal
+ view
+ returns (Internal.TimestampedPackedUint224 memory tokenPrice)
+ {
+ AggregatorV3Interface dataFeedContract = AggregatorV3Interface(priceFeedConfig.dataFeedAddress);
+ (
+ /* uint80 roundID */
+ ,
+ int256 dataFeedAnswer,
+ /* uint startedAt */
+ ,
+ /* uint256 updatedAt */
+ ,
+ /* uint80 answeredInRound */
+ ) = dataFeedContract.latestRoundData();
+
+ if (dataFeedAnswer < 0) {
+ revert DataFeedValueOutOfUint224Range();
+ }
+ uint256 rebasedValue = uint256(dataFeedAnswer);
+
+ // Rebase formula for units in smallest token denomination: usdValue * (1e18 * 1e18) / 1eTokenDecimals
+ // feedValue * (10 ** (18 - feedDecimals)) * (10 ** (18 - erc20Decimals))
+ // feedValue * (10 ** ((18 - feedDecimals) + (18 - erc20Decimals)))
+ // feedValue * (10 ** (36 - feedDecimals - erc20Decimals))
+ // feedValue * (10 ** (36 - (feedDecimals + erc20Decimals)))
+ // feedValue * (10 ** (36 - excessDecimals))
+ // If excessDecimals > 36 => flip it to feedValue / (10 ** (excessDecimals - 36))
+
+ uint8 excessDecimals = dataFeedContract.decimals() + priceFeedConfig.tokenDecimals;
+
+ if (excessDecimals > 36) {
+ rebasedValue /= 10 ** (excessDecimals - 36);
+ } else {
+ rebasedValue *= 10 ** (36 - excessDecimals);
+ }
+
+ if (rebasedValue > type(uint224).max) {
+ revert DataFeedValueOutOfUint224Range();
+ }
+
+ // Data feed staleness is unchecked to decouple the PriceRegistry from data feed delay issues
+ return Internal.TimestampedPackedUint224({value: uint224(rebasedValue), timestamp: uint32(block.timestamp)});
+ }
+
+ // ================================================================
+ // │ Fee tokens │
+ // ================================================================
+
+ /// @inheritdoc IPriceRegistry
+ function getFeeTokens() external view returns (address[] memory) {
+ return s_feeTokens.values();
+ }
+
+ /// @notice Add and remove tokens from feeTokens set.
+ /// @param feeTokensToAdd The addresses of the tokens which are now considered fee tokens
+ /// and can be used to calculate fees.
+ /// @param feeTokensToRemove The addresses of the tokens which are no longer considered feeTokens.
+ function applyFeeTokensUpdates(
+ address[] memory feeTokensToAdd,
+ address[] memory feeTokensToRemove
+ ) external onlyOwner {
+ _applyFeeTokensUpdates(feeTokensToAdd, feeTokensToRemove);
+ }
+
+ /// @notice Add and remove tokens from feeTokens set.
+ /// @param feeTokensToAdd The addresses of the tokens which are now considered fee tokens
+ /// and can be used to calculate fees.
+ /// @param feeTokensToRemove The addresses of the tokens which are no longer considered feeTokens.
+ function _applyFeeTokensUpdates(address[] memory feeTokensToAdd, address[] memory feeTokensToRemove) private {
+ for (uint256 i = 0; i < feeTokensToAdd.length; ++i) {
+ if (s_feeTokens.add(feeTokensToAdd[i])) {
+ emit FeeTokenAdded(feeTokensToAdd[i]);
+ }
+ }
+ for (uint256 i = 0; i < feeTokensToRemove.length; ++i) {
+ if (s_feeTokens.remove(feeTokensToRemove[i])) {
+ emit FeeTokenRemoved(feeTokensToRemove[i]);
+ }
+ }
+ }
+
+ // ================================================================
+ // │ Price updates │
+ // ================================================================
+
+ /// @inheritdoc IPriceRegistry
+ function updatePrices(Internal.PriceUpdates calldata priceUpdates) external override {
+ // The caller must be the fee updater
+ _validateCaller();
+
+ uint256 tokenUpdatesLength = priceUpdates.tokenPriceUpdates.length;
+
+ for (uint256 i = 0; i < tokenUpdatesLength; ++i) {
+ Internal.TokenPriceUpdate memory update = priceUpdates.tokenPriceUpdates[i];
+ s_usdPerToken[update.sourceToken] =
+ Internal.TimestampedPackedUint224({value: update.usdPerToken, timestamp: uint32(block.timestamp)});
+ emit UsdPerTokenUpdated(update.sourceToken, update.usdPerToken, block.timestamp);
+ }
+
+ uint256 gasUpdatesLength = priceUpdates.gasPriceUpdates.length;
+
+ for (uint256 i = 0; i < gasUpdatesLength; ++i) {
+ Internal.GasPriceUpdate memory update = priceUpdates.gasPriceUpdates[i];
+ s_usdPerUnitGasByDestChainSelector[update.destChainSelector] =
+ Internal.TimestampedPackedUint224({value: update.usdPerUnitGas, timestamp: uint32(block.timestamp)});
+ emit UsdPerUnitGasUpdated(update.destChainSelector, update.usdPerUnitGas, block.timestamp);
+ }
+ }
+
+ /// @notice Updates the USD token price feeds for given tokens
+ /// @param tokenPriceFeedUpdates Token price feed updates to apply
+ function updateTokenPriceFeeds(TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates) external onlyOwner {
+ _updateTokenPriceFeeds(tokenPriceFeedUpdates);
+ }
+
+ /// @notice Updates the USD token price feeds for given tokens
+ /// @param tokenPriceFeedUpdates Token price feed updates to apply
+ function _updateTokenPriceFeeds(TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates) private {
+ for (uint256 i; i < tokenPriceFeedUpdates.length; ++i) {
+ TokenPriceFeedUpdate memory update = tokenPriceFeedUpdates[i];
+ address sourceToken = update.sourceToken;
+ IPriceRegistry.TokenPriceFeedConfig memory tokenPriceFeedConfig = update.feedConfig;
+
+ s_usdPriceFeedsPerToken[sourceToken] = tokenPriceFeedConfig;
+ emit PriceFeedPerTokenUpdated(sourceToken, tokenPriceFeedConfig);
+ }
+ }
+
+ // ================================================================
+ // │ Fee quoting │
+ // ================================================================
+
+ /// @inheritdoc IPriceRegistry
+ /// @dev The function should always validate message.extraArgs, message.receiver and family-specific configs
+ function getValidatedFee(
+ uint64 destChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external view returns (uint256 feeTokenAmount) {
+ DestChainConfig memory destChainConfig = s_destChainConfigs[destChainSelector];
+ if (!destChainConfig.isEnabled) revert DestinationChainNotEnabled(destChainSelector);
+
+ uint256 numberOfTokens = message.tokenAmounts.length;
+ _validateMessage(destChainConfig, message.data.length, numberOfTokens, message.receiver);
+
+ uint64 premiumMultiplierWeiPerEth = s_premiumMultiplierWeiPerEth[message.feeToken];
+
+ // The below call asserts that feeToken is a supported token
+ (uint224 feeTokenPrice, uint224 packedGasPrice) = getTokenAndGasPrices(message.feeToken, destChainSelector);
+
+ // Calculate premiumFee in USD with 18 decimals precision first.
+ // If message-only and no token transfers, a flat network fee is charged.
+ // If there are token transfers, premiumFee is calculated from token transfer fee.
+ // If there are both token transfers and message, premiumFee is only calculated from token transfer fee.
+ uint256 premiumFee = 0;
+ uint32 tokenTransferGas = 0;
+ uint32 tokenTransferBytesOverhead = 0;
+ if (numberOfTokens > 0) {
+ (premiumFee, tokenTransferGas, tokenTransferBytesOverhead) =
+ _getTokenTransferCost(destChainConfig, destChainSelector, message.feeToken, feeTokenPrice, message.tokenAmounts);
+ } else {
+ // Convert USD cents with 2 decimals to 18 decimals.
+ premiumFee = uint256(destChainConfig.networkFeeUSDCents) * 1e16;
+ }
+
+ // Calculate data availability cost in USD with 36 decimals. Data availability cost exists on rollups that need to post
+ // transaction calldata onto another storage layer, e.g. Eth mainnet, incurring additional storage gas costs.
+ uint256 dataAvailabilityCost = 0;
+
+ // Only calculate data availability cost if data availability multiplier is non-zero.
+ // The multiplier should be set to 0 if destination chain does not charge data availability cost.
+ if (destChainConfig.destDataAvailabilityMultiplierBps > 0) {
+ dataAvailabilityCost = _getDataAvailabilityCost(
+ destChainConfig,
+ // Parse the data availability gas price stored in the higher-order 112 bits of the encoded gas price.
+ uint112(packedGasPrice >> Internal.GAS_PRICE_BITS),
+ message.data.length,
+ numberOfTokens,
+ tokenTransferBytesOverhead
+ );
+ }
+
+ // Calculate execution gas fee on destination chain in USD with 36 decimals.
+ // We add the message gas limit, the overhead gas, the gas of passing message data to receiver, and token transfer gas together.
+ // We then multiply this gas total with the gas multiplier and gas price, converting it into USD with 36 decimals.
+ // uint112(packedGasPrice) = executionGasPrice
+
+ // NOTE: when supporting non-EVM chains, revisit how generic this fee logic can be
+ // NOTE: revisit parsing non-EVM args
+
+ uint256 executionCost = uint112(packedGasPrice)
+ * (
+ destChainConfig.destGasOverhead + (message.data.length * destChainConfig.destGasPerPayloadByte) + tokenTransferGas
+ + _parseEVMExtraArgsFromBytes(message.extraArgs, destChainConfig).gasLimit
+ ) * destChainConfig.gasMultiplierWeiPerEth;
+
+ // Calculate number of fee tokens to charge.
+ // Total USD fee is in 36 decimals, feeTokenPrice is in 18 decimals USD for 1e18 smallest token denominations.
+ // Result of the division is the number of smallest token denominations.
+ return ((premiumFee * premiumMultiplierWeiPerEth) + executionCost + dataAvailabilityCost) / feeTokenPrice;
+ }
+
+ /// @notice Sets the fee configuration for a token
+ /// @param premiumMultiplierWeiPerEthArgs Array of PremiumMultiplierWeiPerEthArgs structs.
+ function applyPremiumMultiplierWeiPerEthUpdates(
+ PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs
+ ) external onlyOwner {
+ _applyPremiumMultiplierWeiPerEthUpdates(premiumMultiplierWeiPerEthArgs);
+ }
+
+ /// @dev Set the fee config.
+ /// @param premiumMultiplierWeiPerEthArgs The multiplier for destination chain specific premiums.
+ function _applyPremiumMultiplierWeiPerEthUpdates(
+ PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs
+ ) internal {
+ for (uint256 i = 0; i < premiumMultiplierWeiPerEthArgs.length; ++i) {
+ address token = premiumMultiplierWeiPerEthArgs[i].token;
+ uint64 premiumMultiplierWeiPerEth = premiumMultiplierWeiPerEthArgs[i].premiumMultiplierWeiPerEth;
+ s_premiumMultiplierWeiPerEth[token] = premiumMultiplierWeiPerEth;
+
+ emit PremiumMultiplierWeiPerEthUpdated(token, premiumMultiplierWeiPerEth);
+ }
+ }
+
+ /// @notice Gets the fee configuration for a token.
+ /// @param token The token to get the fee configuration for.
+ /// @return premiumMultiplierWeiPerEth The multiplier for destination chain specific premiums.
+ function getPremiumMultiplierWeiPerEth(address token) external view returns (uint64 premiumMultiplierWeiPerEth) {
+ return s_premiumMultiplierWeiPerEth[token];
+ }
+
+ /// @notice Returns the token transfer cost parameters.
+ /// A basis point fee is calculated from the USD value of each token transfer.
+ /// For each individual transfer, this fee is between [minFeeUSD, maxFeeUSD].
+ /// Total transfer fee is the sum of each individual token transfer fee.
+ /// @dev Assumes that tokenAmounts are validated to be listed tokens elsewhere.
+ /// @dev Splitting one token transfer into multiple transfers is discouraged,
+ /// as it will result in a transferFee equal or greater than the same amount aggregated/de-duped.
+ /// @param destChainConfig the config configured for the destination chain selector.
+ /// @param destChainSelector the destination chain selector.
+ /// @param feeToken address of the feeToken.
+ /// @param feeTokenPrice price of feeToken in USD with 18 decimals.
+ /// @param tokenAmounts token transfers in the message.
+ /// @return tokenTransferFeeUSDWei total token transfer bps fee in USD with 18 decimals.
+ /// @return tokenTransferGas total execution gas of the token transfers.
+ /// @return tokenTransferBytesOverhead additional token transfer data passed to destination, e.g. USDC attestation.
+ function _getTokenTransferCost(
+ DestChainConfig memory destChainConfig,
+ uint64 destChainSelector,
+ address feeToken,
+ uint224 feeTokenPrice,
+ Client.EVMTokenAmount[] calldata tokenAmounts
+ ) internal view returns (uint256 tokenTransferFeeUSDWei, uint32 tokenTransferGas, uint32 tokenTransferBytesOverhead) {
+ uint256 numberOfTokens = tokenAmounts.length;
+
+ for (uint256 i = 0; i < numberOfTokens; ++i) {
+ Client.EVMTokenAmount memory tokenAmount = tokenAmounts[i];
+ TokenTransferFeeConfig memory transferFeeConfig = s_tokenTransferFeeConfig[destChainSelector][tokenAmount.token];
+
+ // If the token has no specific overrides configured, we use the global defaults.
+ if (!transferFeeConfig.isEnabled) {
+ tokenTransferFeeUSDWei += uint256(destChainConfig.defaultTokenFeeUSDCents) * 1e16;
+ tokenTransferGas += destChainConfig.defaultTokenDestGasOverhead;
+ tokenTransferBytesOverhead += destChainConfig.defaultTokenDestBytesOverhead;
+ continue;
+ }
+
+ uint256 bpsFeeUSDWei = 0;
+ // Only calculate bps fee if ratio is greater than 0. Ratio of 0 means no bps fee for a token.
+ // Useful for when the PriceRegistry cannot return a valid price for the token.
+ if (transferFeeConfig.deciBps > 0) {
+ uint224 tokenPrice = 0;
+ if (tokenAmount.token != feeToken) {
+ tokenPrice = _getValidatedTokenPrice(tokenAmount.token);
+ } else {
+ tokenPrice = feeTokenPrice;
+ }
+
+ // Calculate token transfer value, then apply fee ratio
+ // ratio represents multiples of 0.1bps, or 1e-5
+ bpsFeeUSDWei = (tokenPrice._calcUSDValueFromTokenAmount(tokenAmount.amount) * transferFeeConfig.deciBps) / 1e5;
+ }
+
+ tokenTransferGas += transferFeeConfig.destGasOverhead;
+ tokenTransferBytesOverhead += transferFeeConfig.destBytesOverhead;
+
+ // Bps fees should be kept within range of [minFeeUSD, maxFeeUSD].
+ // Convert USD values with 2 decimals to 18 decimals.
+ uint256 minFeeUSDWei = uint256(transferFeeConfig.minFeeUSDCents) * 1e16;
+ if (bpsFeeUSDWei < minFeeUSDWei) {
+ tokenTransferFeeUSDWei += minFeeUSDWei;
+ continue;
+ }
+
+ uint256 maxFeeUSDWei = uint256(transferFeeConfig.maxFeeUSDCents) * 1e16;
+ if (bpsFeeUSDWei > maxFeeUSDWei) {
+ tokenTransferFeeUSDWei += maxFeeUSDWei;
+ continue;
+ }
+
+ tokenTransferFeeUSDWei += bpsFeeUSDWei;
+ }
+
+ return (tokenTransferFeeUSDWei, tokenTransferGas, tokenTransferBytesOverhead);
+ }
+
+ /// @notice Returns the estimated data availability cost of the message.
+ /// @dev To save on gas, we use a single destGasPerDataAvailabilityByte value for both zero and non-zero bytes.
+ /// @param destChainConfig the config configured for the destination chain selector.
+ /// @param dataAvailabilityGasPrice USD per data availability gas in 18 decimals.
+ /// @param messageDataLength length of the data field in the message.
+ /// @param numberOfTokens number of distinct token transfers in the message.
+ /// @param tokenTransferBytesOverhead additional token transfer data passed to destination, e.g. USDC attestation.
+ /// @return dataAvailabilityCostUSD36Decimal total data availability cost in USD with 36 decimals.
+ function _getDataAvailabilityCost(
+ DestChainConfig memory destChainConfig,
+ uint112 dataAvailabilityGasPrice,
+ uint256 messageDataLength,
+ uint256 numberOfTokens,
+ uint32 tokenTransferBytesOverhead
+ ) internal pure returns (uint256 dataAvailabilityCostUSD36Decimal) {
+ // dataAvailabilityLengthBytes sums up byte lengths of fixed message fields and dynamic message fields.
+ // Fixed message fields do account for the offset and length slot of the dynamic fields.
+ uint256 dataAvailabilityLengthBytes = Internal.ANY_2_EVM_MESSAGE_FIXED_BYTES + messageDataLength
+ + (numberOfTokens * Internal.ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN) + tokenTransferBytesOverhead;
+
+ // destDataAvailabilityOverheadGas is a separate config value for flexibility to be updated independently of message cost.
+ // Its value is determined by CCIP lane implementation, e.g. the overhead data posted for OCR.
+ uint256 dataAvailabilityGas = (dataAvailabilityLengthBytes * destChainConfig.destGasPerDataAvailabilityByte)
+ + destChainConfig.destDataAvailabilityOverheadGas;
+
+ // dataAvailabilityGasPrice is in 18 decimals, destDataAvailabilityMultiplierBps is in 4 decimals
+ // We pad 14 decimals to bring the result to 36 decimals, in line with token bps and execution fee.
+ return ((dataAvailabilityGas * dataAvailabilityGasPrice) * destChainConfig.destDataAvailabilityMultiplierBps) * 1e14;
+ }
+
+ /// @notice Gets the transfer fee config for a given token.
+ /// @param destChainSelector The destination chain selector.
+ /// @param token The token address.
+ function getTokenTransferFeeConfig(
+ uint64 destChainSelector,
+ address token
+ ) external view returns (TokenTransferFeeConfig memory tokenTransferFeeConfig) {
+ return s_tokenTransferFeeConfig[destChainSelector][token];
+ }
+
+ /// @notice Sets the transfer fee config.
+ /// @dev only callable by the owner or admin.
+ function applyTokenTransferFeeConfigUpdates(
+ TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
+ TokenTransferFeeConfigRemoveArgs[] memory tokensToUseDefaultFeeConfigs
+ ) external onlyOwner {
+ _applyTokenTransferFeeConfigUpdates(tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs);
+ }
+
+ /// @notice internal helper to set the token transfer fee config.
+ function _applyTokenTransferFeeConfigUpdates(
+ TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
+ TokenTransferFeeConfigRemoveArgs[] memory tokensToUseDefaultFeeConfigs
+ ) internal {
+ for (uint256 i = 0; i < tokenTransferFeeConfigArgs.length; ++i) {
+ TokenTransferFeeConfigArgs memory tokenTransferFeeConfigArg = tokenTransferFeeConfigArgs[i];
+ uint64 destChainSelector = tokenTransferFeeConfigArg.destChainSelector;
+
+ for (uint256 j = 0; j < tokenTransferFeeConfigArg.tokenTransferFeeConfigs.length; ++j) {
+ TokenTransferFeeConfig memory tokenTransferFeeConfig =
+ tokenTransferFeeConfigArg.tokenTransferFeeConfigs[j].tokenTransferFeeConfig;
+ address token = tokenTransferFeeConfigArg.tokenTransferFeeConfigs[j].token;
+
+ if (tokenTransferFeeConfig.destBytesOverhead < Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) {
+ revert InvalidDestBytesOverhead(token, tokenTransferFeeConfig.destBytesOverhead);
+ }
+
+ s_tokenTransferFeeConfig[destChainSelector][token] = tokenTransferFeeConfig;
+
+ emit TokenTransferFeeConfigUpdated(destChainSelector, token, tokenTransferFeeConfig);
+ }
+ }
+
+ // Remove the custom fee configs for the tokens that are in the tokensToUseDefaultFeeConfigs array
+ for (uint256 i = 0; i < tokensToUseDefaultFeeConfigs.length; ++i) {
+ uint64 destChainSelector = tokensToUseDefaultFeeConfigs[i].destChainSelector;
+ address token = tokensToUseDefaultFeeConfigs[i].token;
+ delete s_tokenTransferFeeConfig[destChainSelector][token];
+ emit TokenTransferFeeConfigDeleted(destChainSelector, token);
+ }
+ }
+
+ // ================================================================
+ // │ Validations & message processing │
+ // ================================================================
+
+ /// @notice Validates that the destAddress matches the expected format of the family.
+ /// @param chainFamilySelector Tag to identify the target family
+ /// @param destAddress Dest address to validate
+ /// @dev precondition - assumes the family tag is correct and validated
+ function _validateDestFamilyAddress(bytes4 chainFamilySelector, bytes memory destAddress) internal pure {
+ if (chainFamilySelector == Internal.CHAIN_FAMILY_SELECTOR_EVM) {
+ Internal._validateEVMAddress(destAddress);
+ }
+ }
+
+ /// @dev Convert the extra args bytes into a struct with validations against the dest chain config
+ /// @param extraArgs The extra args bytes
+ /// @param destChainConfig Dest chain config to validate against
+ /// @return EVMExtraArgs the extra args struct (latest version)
+ function _parseEVMExtraArgsFromBytes(
+ bytes calldata extraArgs,
+ DestChainConfig memory destChainConfig
+ ) internal pure returns (Client.EVMExtraArgsV2 memory) {
+ Client.EVMExtraArgsV2 memory evmExtraArgs =
+ _parseUnvalidatedEVMExtraArgsFromBytes(extraArgs, destChainConfig.defaultTxGasLimit);
+
+ if (evmExtraArgs.gasLimit > uint256(destChainConfig.maxPerMsgGasLimit)) revert MessageGasLimitTooHigh();
+ if (destChainConfig.enforceOutOfOrder && !evmExtraArgs.allowOutOfOrderExecution) {
+ revert ExtraArgOutOfOrderExecutionMustBeTrue();
+ }
+
+ return evmExtraArgs;
+ }
+
+ /// @dev Convert the extra args bytes into a struct
+ /// @param extraArgs The extra args bytes
+ /// @param defaultTxGasLimit default tx gas limit to use in the absence of extra args
+ /// @return EVMExtraArgs the extra args struct (latest version)
+ function _parseUnvalidatedEVMExtraArgsFromBytes(
+ bytes calldata extraArgs,
+ uint64 defaultTxGasLimit
+ ) private pure returns (Client.EVMExtraArgsV2 memory) {
+ if (extraArgs.length == 0) {
+ // If extra args are empty, generate default values
+ return Client.EVMExtraArgsV2({gasLimit: defaultTxGasLimit, allowOutOfOrderExecution: false});
+ }
+
+ bytes4 extraArgsTag = bytes4(extraArgs);
+ bytes memory argsData = extraArgs[4:];
+
+ if (extraArgsTag == Client.EVM_EXTRA_ARGS_V2_TAG) {
+ return abi.decode(argsData, (Client.EVMExtraArgsV2));
+ } else if (extraArgsTag == Client.EVM_EXTRA_ARGS_V1_TAG) {
+ // EVMExtraArgsV1 originally included a second boolean (strict) field which has been deprecated.
+ // Clients may still include it but it will be ignored.
+ return Client.EVMExtraArgsV2({gasLimit: abi.decode(argsData, (uint256)), allowOutOfOrderExecution: false});
+ }
+
+ revert InvalidExtraArgsTag();
+ }
+
+ /// @notice Validate the forwarded message to ensure it matches the configuration limits (message length, number of tokens)
+ /// and family-specific expectations (address format)
+ /// @param destChainConfig Dest chain config
+ /// @param dataLength The length of the data field of the message.
+ /// @param numberOfTokens The number of tokens to be sent.
+ /// @param receiver Message receiver on the dest chain
+ function _validateMessage(
+ DestChainConfig memory destChainConfig,
+ uint256 dataLength,
+ uint256 numberOfTokens,
+ bytes memory receiver
+ ) internal pure {
+ // Check that payload is formed correctly
+ if (dataLength > uint256(destChainConfig.maxDataBytes)) {
+ revert MessageTooLarge(uint256(destChainConfig.maxDataBytes), dataLength);
+ }
+ if (numberOfTokens > uint256(destChainConfig.maxNumberOfTokensPerMsg)) revert UnsupportedNumberOfTokens();
+ _validateDestFamilyAddress(destChainConfig.chainFamilySelector, receiver);
+ }
+
+ /// @inheritdoc IPriceRegistry
+ function processMessageArgs(
+ uint64 destChainSelector,
+ address feeToken,
+ uint256 feeTokenAmount,
+ bytes calldata extraArgs
+ ) external view returns (uint256 msgFeeJuels, bool isOutOfOrderExecution, bytes memory convertedExtraArgs) {
+ // Convert feeToken to link if not already in link
+ if (feeToken == i_linkToken) {
+ msgFeeJuels = feeTokenAmount;
+ } else {
+ msgFeeJuels = convertTokenAmount(feeToken, feeTokenAmount, i_linkToken);
+ }
+
+ if (msgFeeJuels > i_maxFeeJuelsPerMsg) revert MessageFeeTooHigh(msgFeeJuels, i_maxFeeJuelsPerMsg);
+
+ uint64 defaultTxGasLimit = s_destChainConfigs[destChainSelector].defaultTxGasLimit;
+ // NOTE: when supporting non-EVM chains, revisit this and parse non-EVM args.
+ // We can parse unvalidated args since this message is called after getFee (which will already validate the params)
+ Client.EVMExtraArgsV2 memory parsedExtraArgs = _parseUnvalidatedEVMExtraArgsFromBytes(extraArgs, defaultTxGasLimit);
+ isOutOfOrderExecution = parsedExtraArgs.allowOutOfOrderExecution;
+
+ return (msgFeeJuels, isOutOfOrderExecution, Client._argsToBytes(parsedExtraArgs));
+ }
+
+ /// @inheritdoc IPriceRegistry
+ /// @dev precondition - rampTokenAmounts and sourceTokenAmounts lengths must be equal
+ function validatePoolReturnData(
+ uint64 destChainSelector,
+ Internal.RampTokenAmount[] calldata rampTokenAmounts,
+ Client.EVMTokenAmount[] calldata sourceTokenAmounts
+ ) external view {
+ bytes4 chainFamilySelector = s_destChainConfigs[destChainSelector].chainFamilySelector;
+
+ for (uint256 i = 0; i < rampTokenAmounts.length; ++i) {
+ address sourceToken = sourceTokenAmounts[i].token;
+
+ // Since the DON has to pay for the extraData to be included on the destination chain, we cap the length of the
+ // extraData. This prevents gas bomb attacks on the NOPs. As destBytesOverhead accounts for both
+ // extraData and offchainData, this caps the worst case abuse to the number of bytes reserved for offchainData.
+ uint256 destPoolDataLength = rampTokenAmounts[i].extraData.length;
+ if (destPoolDataLength > Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) {
+ if (destPoolDataLength > s_tokenTransferFeeConfig[destChainSelector][sourceToken].destBytesOverhead) {
+ revert SourceTokenDataTooLarge(sourceToken);
+ }
+ }
+
+ _validateDestFamilyAddress(chainFamilySelector, rampTokenAmounts[i].destTokenAddress);
+ }
+ }
+
+ // ================================================================
+ // │ Configs │
+ // ================================================================
+
+ /// @notice Returns the configured config for the dest chain selector
+ /// @param destChainSelector destination chain selector to fetch config for
+ /// @return destChainConfig config for the dest chain
+ function getDestChainConfig(uint64 destChainSelector) external view returns (DestChainConfig memory) {
+ return s_destChainConfigs[destChainSelector];
+ }
+
+ /// @notice Updates the destination chain specific config.
+ /// @param destChainConfigArgs Array of source chain specific configs.
+ function applyDestChainConfigUpdates(DestChainConfigArgs[] memory destChainConfigArgs) external onlyOwner {
+ _applyDestChainConfigUpdates(destChainConfigArgs);
+ }
+
+ /// @notice Internal version of applyDestChainConfigUpdates.
+ function _applyDestChainConfigUpdates(DestChainConfigArgs[] memory destChainConfigArgs) internal {
+ for (uint256 i = 0; i < destChainConfigArgs.length; ++i) {
+ DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[i];
+ uint64 destChainSelector = destChainConfigArgs[i].destChainSelector;
+ DestChainConfig memory destChainConfig = destChainConfigArg.destChainConfig;
+
+ // NOTE: when supporting non-EVM chains, update chainFamilySelector validations
+ if (
+ destChainSelector == 0 || destChainConfig.defaultTxGasLimit == 0
+ || destChainConfig.chainFamilySelector != Internal.CHAIN_FAMILY_SELECTOR_EVM
+ || destChainConfig.defaultTokenDestBytesOverhead < Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES
+ || destChainConfig.defaultTxGasLimit > destChainConfig.maxPerMsgGasLimit
+ ) {
+ revert InvalidDestChainConfig(destChainSelector);
+ }
+
+ // The chain family selector cannot be zero - indicates that it is a new chain
+ if (s_destChainConfigs[destChainSelector].chainFamilySelector == 0) {
+ emit DestChainAdded(destChainSelector, destChainConfig);
+ } else {
+ emit DestChainConfigUpdated(destChainSelector, destChainConfig);
+ }
+
+ s_destChainConfigs[destChainSelector] = destChainConfig;
+ }
+ }
+
+ /// @notice Returns the static PriceRegistry config.
+ /// @dev RMN depends on this function, if changing, please notify the RMN maintainers.
+ /// @return the configuration.
+ function getStaticConfig() external view returns (StaticConfig memory) {
+ return StaticConfig({
+ maxFeeJuelsPerMsg: i_maxFeeJuelsPerMsg,
+ linkToken: i_linkToken,
+ stalenessThreshold: i_stalenessThreshold
+ });
+ }
+}
diff --git a/contracts/src/v0.8/ccip/RMN.sol b/contracts/src/v0.8/ccip/RMN.sol
new file mode 100644
index 00000000000..424aad8fa57
--- /dev/null
+++ b/contracts/src/v0.8/ccip/RMN.sol
@@ -0,0 +1,964 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
+import {IRMN} from "./interfaces/IRMN.sol";
+
+import {OwnerIsCreator} from "./../shared/access/OwnerIsCreator.sol";
+
+import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+// An active curse on this subject will cause isCursed() to return true. Use this subject if there is an issue with a
+// remote chain, for which there exists a legacy lane contract deployed on the same chain as this RMN contract is
+// deployed, relying on isCursed().
+bytes16 constant LEGACY_CURSE_SUBJECT = 0x01000000000000000000000000000000;
+
+// An active curse on this subject will cause isCursed() and isCursed(bytes32) to return true. Use this subject for
+// issues affecting all of CCIP chains, or pertaining to the chain that this contract is deployed on, instead of using
+// the local chain selector as a subject.
+bytes16 constant GLOBAL_CURSE_SUBJECT = 0x01000000000000000000000000000001;
+
+// The curse vote address representing the owner in data structures, events and recorded votes. Remains constant, even
+// if the owner changes.
+address constant OWNER_CURSE_VOTE_ADDR = address(~uint160(0)); // 0xff...ff
+
+// The curse vote address used in an OwnerUnvoteToCurseRequest to lift a curse, if there is no active curse votes for
+// the subject that we are able to unvote, but the conditions for an active curse no longer hold.
+address constant LIFT_CURSE_VOTE_ADDR = address(0);
+
+/// @dev This contract is owned by RMN, if changing, please notify the RMN maintainers.
+// solhint-disable chainlink-solidity/explicit-returns
+contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion {
+ using EnumerableSet for EnumerableSet.AddressSet;
+
+ // STATIC CONFIG
+ string public constant override typeAndVersion = "RMN 1.5.0-dev";
+
+ uint256 private constant MAX_NUM_VOTERS = 16;
+
+ // MAGIC VALUES
+ bytes28 private constant NO_VOTES_CURSES_HASH = bytes28(0);
+
+ // DYNAMIC CONFIG
+ /// @notice blessVoteAddr and curseVoteAddr can't be 0. Additionally curseVoteAddr can't be LIFT_CURSE_VOTE_ADDR or
+ /// OWNER_CURSE_VOTE_ADDR. At least one of blessWeight & curseWeight must be non-zero, i.e., a voter could only vote
+ /// to bless, or only vote to curse, or both vote to bless and vote to curse.
+ struct Voter {
+ // This is the address the voter should use to call voteToBless.
+ address blessVoteAddr;
+ // This is the address the voter should use to call voteToCurse.
+ address curseVoteAddr;
+ // The weight of this voter's vote for blessing.
+ uint8 blessWeight;
+ // The weight of this voter's vote for cursing.
+ uint8 curseWeight;
+ }
+
+ struct Config {
+ Voter[] voters;
+ // When the total weight of voters that have voted to bless a tagged root reaches
+ // or exceeds blessWeightThreshold, the tagged root becomes blessed.
+ uint16 blessWeightThreshold;
+ // When the total weight of voters that have voted to curse a subject reaches or
+ // exceeds curseWeightThreshold, the subject becomes cursed.
+ uint16 curseWeightThreshold;
+ }
+
+ struct VersionedConfig {
+ Config config;
+ // The version is incremented every time the config changes.
+ // The initial configuration on the contract will have configVersion == 1.
+ uint32 configVersion;
+ // The block number at which the config was last set. Helps the offchain
+ // code check that the config was set in a stable block or double-check
+ // that it has the correct config by querying logs at that block number.
+ uint32 blockNumber;
+ }
+
+ VersionedConfig private s_versionedConfig;
+
+ // STATE
+ struct BlesserRecord {
+ // The config version at which this BlesserRecord was last set. A blesser
+ // is considered active iff this configVersion equals
+ // s_versionedConfig.configVersion.
+ uint32 configVersion;
+ uint8 weight;
+ uint8 index;
+ }
+
+ mapping(address blessVoteAddr => BlesserRecord blesserRecord) private s_blesserRecords;
+
+ struct BlessVoteProgress {
+ // This particular ordering saves us ~400 gas per voteToBless call, compared to the bool being at the bottom, even
+ // though the size of the struct is the same.
+ bool weightThresholdMet;
+ // A BlessVoteProgress is considered invalid if weightThresholdMet is false when
+ // s_versionedConfig.configVersion changes. we don't want old in-progress
+ // votes to continue when we set a new config!
+ // The config version at which the bless vote for a tagged root was initiated.
+ uint32 configVersion;
+ uint16 accumulatedWeight;
+ // Care must be taken that the bitmap has at least as many bits as MAX_NUM_VOTERS.
+ // uint200 is much larger than we need, but it saves us ~100 gas per voteToBless call to fill the word instead of
+ // using a smaller type.
+ // _bitmapGet(voterBitmap, i) = true indicates that the i-th voter has voted to bless
+ uint200 voterBitmap;
+ }
+
+ mapping(bytes32 taggedRootHash => BlessVoteProgress blessVoteProgress) private s_blessVoteProgressByTaggedRootHash;
+
+ // Any tagged root with a commit store included in s_permaBlessedCommitStores will be considered automatically
+ // blessed.
+ EnumerableSet.AddressSet private s_permaBlessedCommitStores;
+
+ struct CurserRecord {
+ bool active;
+ uint8 weight;
+ mapping(bytes16 curseId => bool used) usedCurseIds; // retained across config changes
+ }
+
+ mapping(address curseVoteAddr => CurserRecord curserRecord) private s_curserRecords;
+
+ struct ConfigVersionAndCursesHash {
+ uint32 configVersion; // configVersion != s_versionedConfig.configVersion means no active vote
+ bytes28 cursesHash; // bytes28(0) means no active vote; truncated so that ConfigVersionAndCursesHash fits in a word
+ }
+
+ struct CurseVoteProgress {
+ uint32 configVersion; // upon config change, lazy set to new config version
+ uint16 curseWeightThreshold; // upon config change, lazy set to new config value
+ uint16 accumulatedWeight; // upon config change, lazy set to 0
+ // A curse becomes active after either:
+ // - sum([voter.weight for voter who voted in current config]) >= curseWeightThreshold
+ // - ownerCurse is invoked
+ // Once a curse is active, only the owner can lift it.
+ bool curseActive; // retained across config changes
+ mapping(address => ConfigVersionAndCursesHash) latestVoteToCurseByCurseVoteAddr; // retained across config changes
+ }
+
+ mapping(bytes16 subject => CurseVoteProgress curseVoteProgress) private
+ s_potentiallyOutdatedCurseVoteProgressBySubject;
+
+ // We intentionally use a struct here, even though it contains a single field, to make it obvious to future editors
+ // that there is space for more fields.
+ struct CurseHotVars {
+ uint64 numSubjectsCursed; // incremented by voteToCurse, ownerCurse; decremented by ownerUnvoteToCurse
+ }
+
+ CurseHotVars private s_curseHotVars;
+
+ enum RecordedCurseRelatedOpTag {
+ // A vote to curse, through either voteToCurse or ownerCurse.
+ VoteToCurse,
+ // An unvote to curse, through unvoteToCurse.
+ UnvoteToCurse,
+ // An unvote to curse, through ownerUnvoteToCurse, which was not forced (forceUnvote=false).
+ OwnerUnvoteToCurseUnforced,
+ // An unvote to curse, through ownerUnvoteToCurse, which was forced (forceUnvote=true).
+ OwnerUnvoteToCurseForced,
+ // A configuration change.
+ //
+ // For subjects that are not cursed when this happens, past votes do not get accounted for in the new configuration.
+ // If a voter votes during the new configuration, their curses hash will restart from NO_VOTES_CURSES_HASH.
+ //
+ // For subjects that are cursed when this happens, past votes get accounted for.
+ // If a voter votes during the new configuration, their curses hash will continue from its old value.
+ SetConfig
+ }
+
+ /// @notice Provides the ability to quickly reconstruct the curse-related state of the contract offchain, without
+ /// having to replay all past events. Replaying past events often takes long, and in some cases might even be
+ /// infeasible due to log pruning.
+ ///
+ /// @dev We could save some gas by omitting some fields and instead using them as mapping keys, but we would lose the
+ /// cross-voter ordering, or cross-subject ordering, or cross-vote/unvote ordering.
+ struct RecordedCurseRelatedOp {
+ RecordedCurseRelatedOpTag tag;
+ uint64 blockTimestamp;
+ bool cursed; // whether the subject is cursed after this op; if tag in {SetConfig}, will be false
+ address curseVoteAddr; // if tag in {SetConfig}, will be address(0)
+ bytes16 subject; // if tag in {SetConfig}, will be bytes16(0)
+ bytes16 curseId; // if tag in {SetConfig, UnvoteToCurse, OwnerUnvoteToCurseUnforced, OwnerUnvoteToCurseForced}, will be bytes16(0)
+ }
+
+ RecordedCurseRelatedOp[] private s_recordedCurseRelatedOps;
+
+ /// @dev This function is to _ONLY_ be called in order to determine if a curse should become active upon a
+ /// vote-to-curse, or a curse should be deactivated upon an owner-unvote-to-curse.
+ /// Other reasons for a curse to be active, which are not covered here:
+ /// 1. Cursedness is retained from a prior config.
+ /// 2. The curse weight threshold was met at some point, which activated a curse, and enough voters unvoted to curse
+ /// such that the curse weight threshold is no longer met.
+ function _shouldCurseBeActive(CurseVoteProgress storage sptr_upToDateCurseVoteProgress) internal view returns (bool) {
+ return sptr_upToDateCurseVoteProgress.latestVoteToCurseByCurseVoteAddr[OWNER_CURSE_VOTE_ADDR].cursesHash
+ != NO_VOTES_CURSES_HASH
+ || sptr_upToDateCurseVoteProgress.accumulatedWeight >= sptr_upToDateCurseVoteProgress.curseWeightThreshold;
+ }
+
+ /// @dev It might be the case that due to the lazy update of curseVoteProgress, a curse is active even though
+ /// _shouldCurseBeActive(curseVoteProgress) is false, i.e., the owner has no active vote to curse and the curse
+ /// weight threshold has not been met.
+ function _getUpToDateCurseVoteProgress(
+ uint32 configVersion,
+ bytes16 subject
+ ) internal returns (CurseVoteProgress storage) {
+ CurseVoteProgress storage sptr_curseVoteProgress = s_potentiallyOutdatedCurseVoteProgressBySubject[subject];
+ if (configVersion != sptr_curseVoteProgress.configVersion) {
+ sptr_curseVoteProgress.configVersion = configVersion;
+ sptr_curseVoteProgress.curseWeightThreshold = s_versionedConfig.config.curseWeightThreshold;
+ sptr_curseVoteProgress.accumulatedWeight = 0;
+
+ if (sptr_curseVoteProgress.curseActive) {
+ // If a curse was active, count past votes to curse and retain the curses hash for cursers who are part of the
+ // new config.
+ Config storage sptr_config = s_versionedConfig.config;
+ for (uint256 i = 0; i < sptr_config.voters.length; ++i) {
+ Voter storage sptr_voter = sptr_config.voters[i];
+ ConfigVersionAndCursesHash storage sptr_cvch =
+ sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[sptr_voter.curseVoteAddr];
+ if (sptr_cvch.configVersion < configVersion && sptr_cvch.cursesHash != NO_VOTES_CURSES_HASH) {
+ // `< configVersion` instead of `== configVersion-1`, because there might have been multiple config changes
+ // without a lazy update of our subject. This has the side effect of retaining votes from very old configs
+ // that we might not really intend to retain, but these can be removed by the owner later.
+ sptr_cvch.configVersion = configVersion;
+ sptr_curseVoteProgress.accumulatedWeight += sptr_voter.curseWeight;
+ }
+ }
+ // We don't need to think about OWNER_CURSE_VOTE_ADDR here, because its ConfigVersionAndCursesHash counts even
+ // if the configVersion is not the current config version, in contrast to regular voters.
+ // It's an irregularity, but it saves us > 5k gas (if the owner had previously voted) for the unlucky voter who
+ // enters this branch.
+ } else {
+ // If a curse was not active, we don't count past votes to curse for voters who are part of the new config.
+ // Their curses hash will be restart from NO_VOTES_CURSES_HASH when they vote to curse again.
+ // We expect that the offchain code will revote to curse in case it voted to curse, and the vote to curse was
+ // lost due to any reason, including a config change when the curse was not yet active.
+ }
+ }
+ return sptr_curseVoteProgress;
+ }
+
+ // EVENTS, ERRORS
+
+ event ConfigSet(uint32 indexed configVersion, Config config);
+
+ error InvalidConfig();
+
+ event TaggedRootBlessed(uint32 indexed configVersion, IRMN.TaggedRoot taggedRoot, uint16 accumulatedWeight);
+ event TaggedRootBlessVotesReset(uint32 indexed configVersion, IRMN.TaggedRoot taggedRoot, bool wasBlessed);
+ event VotedToBless(uint32 indexed configVersion, address indexed voter, IRMN.TaggedRoot taggedRoot, uint8 weight);
+
+ event VotedToCurse(
+ uint32 indexed configVersion,
+ address indexed voter,
+ bytes16 subject,
+ bytes16 curseId,
+ uint8 weight,
+ uint64 blockTimestamp,
+ bytes28 cursesHash,
+ uint16 accumulatedWeight
+ );
+ event UnvotedToCurse(
+ uint32 indexed configVersion,
+ address indexed voter,
+ bytes16 subject,
+ uint8 weight,
+ bytes28 cursesHash,
+ uint16 remainingAccumulatedWeight
+ );
+ event SkippedUnvoteToCurse(address indexed voter, bytes16 subject, bytes28 onchainCursesHash, bytes28 cursesHash);
+ event Cursed(uint32 indexed configVersion, bytes16 subject, uint64 blockTimestamp);
+ event CurseLifted(bytes16 subject);
+
+ // These events make it easier for offchain logic to discover that it performs
+ // the same actions multiple times.
+ event AlreadyVotedToBless(uint32 indexed configVersion, address indexed voter, IRMN.TaggedRoot taggedRoot);
+ event AlreadyBlessed(uint32 indexed configVersion, address indexed voter, IRMN.TaggedRoot taggedRoot);
+
+ // Emitted by ownerRemoveThenAddPermaBlessedCommitStores.
+ event PermaBlessedCommitStoreAdded(address commitStore);
+ event PermaBlessedCommitStoreRemoved(address commitStore);
+
+ error ReusedCurseId(address voter, bytes16 curseId);
+ error UnauthorizedVoter(address voter);
+ error VoteToBlessNoop();
+ error VoteToCurseNoop();
+ error UnvoteToCurseNoop();
+ error VoteToBlessForbiddenDuringActiveGlobalCurse();
+
+ /// @notice Thrown when subjects are not a strictly increasing monotone sequence.
+ // Prevents a subject from receiving multiple votes to curse with the same curse id.
+ error SubjectsMustBeStrictlyIncreasing();
+
+ constructor(Config memory config) {
+ {
+ // Ensure that the bitmap is large enough to hold MAX_NUM_VOTERS.
+ // We do this in the constructor because MAX_NUM_VOTERS is constant.
+ BlessVoteProgress memory vp = BlessVoteProgress({
+ configVersion: 0,
+ voterBitmap: type(uint200).max, // will not compile if it doesn't fit
+ accumulatedWeight: 0,
+ weightThresholdMet: false
+ });
+ assert(vp.voterBitmap >> (MAX_NUM_VOTERS - 1) >= 1);
+ }
+ _setConfig(config);
+ }
+
+ function _bitmapGet(uint200 bitmap, uint8 index) internal pure returns (bool) {
+ assert(index < MAX_NUM_VOTERS);
+ return bitmap & (uint200(1) << index) != 0;
+ }
+
+ function _bitmapSet(uint200 bitmap, uint8 index) internal pure returns (uint200) {
+ assert(index < MAX_NUM_VOTERS);
+ return bitmap | (uint200(1) << index);
+ }
+
+ function _bitmapCount(uint200 bitmap) internal pure returns (uint8 oneBits) {
+ assert(bitmap < 1 << MAX_NUM_VOTERS);
+ // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
+ for (; bitmap != 0; ++oneBits) {
+ bitmap &= bitmap - 1;
+ }
+ }
+
+ function _taggedRootHash(IRMN.TaggedRoot memory taggedRoot) internal pure returns (bytes32) {
+ return keccak256(abi.encode(taggedRoot.commitStore, taggedRoot.root));
+ }
+
+ function _cursesHash(bytes28 prevCursesHash, bytes16 curseId) internal pure returns (bytes28) {
+ return bytes28(keccak256(abi.encode(prevCursesHash, curseId)));
+ }
+
+ function _blockTimestamp() internal view returns (uint64) {
+ return uint64(block.timestamp);
+ }
+
+ /// @param taggedRoots A tagged root is hashed as `keccak256(abi.encode(taggedRoot.commitStore
+ /// /* address */, taggedRoot.root /* bytes32 */))`.
+ /// @notice Tagged roots which are already (voted to be) blessed are skipped and emit corresponding events. In case
+ /// the call has no effect, i.e., all passed tagged roots are skipped, the function reverts with a `VoteToBlessNoop`.
+ function voteToBless(IRMN.TaggedRoot[] calldata taggedRoots) external {
+ // If we have an active global curse, something is really wrong. Let's err on the
+ // side of caution and not accept further blessings during this time of
+ // uncertainty.
+ if (isCursed(GLOBAL_CURSE_SUBJECT)) revert VoteToBlessForbiddenDuringActiveGlobalCurse();
+
+ uint32 configVersion = s_versionedConfig.configVersion;
+ BlesserRecord memory blesserRecord = s_blesserRecords[msg.sender];
+ if (blesserRecord.configVersion != configVersion) revert UnauthorizedVoter(msg.sender);
+
+ bool noop = true;
+ for (uint256 i = 0; i < taggedRoots.length; ++i) {
+ IRMN.TaggedRoot memory taggedRoot = taggedRoots[i];
+ bytes32 taggedRootHash = _taggedRootHash(taggedRoot);
+ BlessVoteProgress memory voteProgress = s_blessVoteProgressByTaggedRootHash[taggedRootHash];
+ if (voteProgress.weightThresholdMet) {
+ // We don't revert here because it's unreasonable to expect from the
+ // voter to know exactly when to stop voting. Most likely when they
+ // voted they didn't realize the threshold would be reached by the time
+ // their vote was counted.
+ // Additionally, there might be other tagged roots for which votes might
+ // count, and we want to allow that to happen.
+ emit AlreadyBlessed(configVersion, msg.sender, taggedRoot);
+ continue;
+ } else if (voteProgress.configVersion != configVersion) {
+ // Note that voteProgress.weightThresholdMet must be false at this point
+
+ // If votes were received while an older config was in effect,
+ // invalidate them and start from scratch.
+ // If votes were never received, set the current config version.
+ voteProgress = BlessVoteProgress({
+ configVersion: configVersion,
+ voterBitmap: 0,
+ accumulatedWeight: 0,
+ weightThresholdMet: false
+ });
+ } else if (_bitmapGet(voteProgress.voterBitmap, blesserRecord.index)) {
+ // We don't revert here because there might be other tagged roots for
+ // which votes might count, and we want to allow that to happen.
+ emit AlreadyVotedToBless(configVersion, msg.sender, taggedRoot);
+ continue;
+ }
+ noop = false;
+ voteProgress.voterBitmap = _bitmapSet(voteProgress.voterBitmap, blesserRecord.index);
+ voteProgress.accumulatedWeight += blesserRecord.weight;
+ emit VotedToBless(configVersion, msg.sender, taggedRoot, blesserRecord.weight);
+ if (voteProgress.accumulatedWeight >= s_versionedConfig.config.blessWeightThreshold) {
+ voteProgress.weightThresholdMet = true;
+ emit TaggedRootBlessed(configVersion, taggedRoot, voteProgress.accumulatedWeight);
+ }
+ s_blessVoteProgressByTaggedRootHash[taggedRootHash] = voteProgress;
+ }
+
+ if (noop) {
+ revert VoteToBlessNoop();
+ }
+ }
+
+ /// @notice Can be called by the owner to remove unintentionally voted or even blessed tagged roots in a recovery
+ /// scenario. The owner must ensure that there are no in-flight transactions by RMN nodes voting for any of the
+ /// taggedRoots before calling this function, as such in-flight transactions could lead to the roots becoming
+ /// re-blessed shortly after the call to this function, contrary to the original intention.
+ function ownerResetBlessVotes(IRMN.TaggedRoot[] calldata taggedRoots) external onlyOwner {
+ uint32 configVersion = s_versionedConfig.configVersion;
+ for (uint256 i = 0; i < taggedRoots.length; ++i) {
+ IRMN.TaggedRoot memory taggedRoot = taggedRoots[i];
+ bytes32 taggedRootHash = _taggedRootHash(taggedRoot);
+ BlessVoteProgress memory voteProgress = s_blessVoteProgressByTaggedRootHash[taggedRootHash];
+ delete s_blessVoteProgressByTaggedRootHash[taggedRootHash];
+ bool wasBlessed = voteProgress.weightThresholdMet;
+ if (voteProgress.configVersion == configVersion || wasBlessed) {
+ emit TaggedRootBlessVotesReset(configVersion, taggedRoot, wasBlessed);
+ }
+ }
+ }
+
+ struct UnvoteToCurseRequest {
+ bytes16 subject;
+ bytes28 cursesHash;
+ }
+
+ // For use in internal calls.
+ enum Privilege {
+ Owner,
+ Voter
+ }
+
+ function _authorizedUnvoteToCurse(
+ Privilege priv, // Privilege.Owner during an ownerUnvoteToCurse call, Privilege.Voter during a unvoteToCurse call
+ uint32 configVersion,
+ address curseVoteAddr,
+ UnvoteToCurseRequest memory req,
+ bool forceUnvote, // true only during an ownerUnvoteToCurse call, when OwnerUnvoteToCurseRequest.forceUnvote is true
+ CurserRecord storage sptr_curserRecord,
+ CurseVoteProgress storage sptr_curseVoteProgress
+ ) internal returns (bool unvoted, bool curseLifted) {
+ {
+ assert(priv == Privilege.Voter || priv == Privilege.Owner); // sanity check
+ // Check that the supplied arguments are feasible for our privilege.
+ if (forceUnvote || curseVoteAddr == OWNER_CURSE_VOTE_ADDR || curseVoteAddr == LIFT_CURSE_VOTE_ADDR) {
+ assert(priv == Privilege.Owner);
+ }
+ }
+
+ ConfigVersionAndCursesHash memory cvch = sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr];
+
+ // First, try to unvote.
+ if (
+ sptr_curserRecord.active && (curseVoteAddr == OWNER_CURSE_VOTE_ADDR || cvch.configVersion == configVersion)
+ && cvch.cursesHash != NO_VOTES_CURSES_HASH && (cvch.cursesHash == req.cursesHash || forceUnvote)
+ ) {
+ unvoted = true;
+ delete sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr];
+ // Assumes: s_curserRecords[OWNER_CURSE_VOTE_ADDR].weight == 0, enforced by _setConfig
+ sptr_curseVoteProgress.accumulatedWeight -= sptr_curserRecord.weight;
+
+ emit UnvotedToCurse(
+ configVersion,
+ curseVoteAddr,
+ req.subject,
+ sptr_curserRecord.weight,
+ req.cursesHash,
+ sptr_curseVoteProgress.accumulatedWeight
+ );
+ }
+
+ // If we have owner privilege, and the conditions for the curse to be active no longer hold, we are able to lift the
+ // curse.
+ bool shouldTryToLiftCurse = priv == Privilege.Owner && (unvoted || curseVoteAddr == LIFT_CURSE_VOTE_ADDR);
+
+ if (shouldTryToLiftCurse && sptr_curseVoteProgress.curseActive && !_shouldCurseBeActive(sptr_curseVoteProgress)) {
+ curseLifted = true;
+ sptr_curseVoteProgress.curseActive = false;
+ --s_curseHotVars.numSubjectsCursed;
+ emit CurseLifted(req.subject);
+ }
+
+ if (unvoted || curseLifted) {
+ RecordedCurseRelatedOpTag tag;
+ if (priv == Privilege.Owner) {
+ if (forceUnvote) {
+ tag = RecordedCurseRelatedOpTag.OwnerUnvoteToCurseForced;
+ } else {
+ tag = RecordedCurseRelatedOpTag.OwnerUnvoteToCurseUnforced;
+ }
+ } else if (priv == Privilege.Voter) {
+ tag = RecordedCurseRelatedOpTag.UnvoteToCurse;
+ } else {
+ // solhint-disable-next-line gas-custom-errors, reason-string
+ revert(); // assumption violation
+ }
+ s_recordedCurseRelatedOps.push(
+ RecordedCurseRelatedOp({
+ tag: tag,
+ cursed: sptr_curseVoteProgress.curseActive,
+ curseVoteAddr: curseVoteAddr,
+ curseId: bytes16(0),
+ subject: req.subject,
+ blockTimestamp: _blockTimestamp()
+ })
+ );
+ } else {
+ emit SkippedUnvoteToCurse(curseVoteAddr, req.subject, cvch.cursesHash, req.cursesHash);
+ }
+ }
+
+ /// @notice Can be called by a curser to remove unintentional votes to curse.
+ /// We expect this to be called very rarely, e.g. in case of a bug in the
+ /// offchain code causing false voteToCurse calls.
+ /// @notice Should be called from curser's corresponding curseVoteAddr.
+ function unvoteToCurse(UnvoteToCurseRequest[] memory unvoteToCurseRequests) external {
+ address curseVoteAddr = msg.sender;
+ CurserRecord storage sptr_curserRecord = s_curserRecords[curseVoteAddr];
+
+ if (!sptr_curserRecord.active) revert UnauthorizedVoter(curseVoteAddr);
+
+ uint32 configVersion = s_versionedConfig.configVersion;
+ bool anyVoteWasUnvoted = false;
+ for (uint256 i = 0; i < unvoteToCurseRequests.length; ++i) {
+ UnvoteToCurseRequest memory req = unvoteToCurseRequests[i];
+ CurseVoteProgress storage sptr_curseVoteProgress = _getUpToDateCurseVoteProgress(configVersion, req.subject);
+ (bool unvoted, bool curseLifted) = _authorizedUnvoteToCurse(
+ Privilege.Voter, configVersion, curseVoteAddr, req, false, sptr_curserRecord, sptr_curseVoteProgress
+ );
+ assert(!curseLifted); // assumption violation: voters can't lift curses
+ anyVoteWasUnvoted = anyVoteWasUnvoted || unvoted;
+ }
+
+ if (!anyVoteWasUnvoted) {
+ revert UnvoteToCurseNoop();
+ }
+ }
+
+ /// @notice A vote to curse is appropriate during unhealthy blockchain conditions
+ /// (eg. finality violations).
+ function voteToCurse(bytes16 curseId, bytes16[] memory subjects) external {
+ address curseVoteAddr = msg.sender;
+ assert(curseVoteAddr != OWNER_CURSE_VOTE_ADDR);
+ CurserRecord storage sptr_curserRecord = s_curserRecords[curseVoteAddr];
+ if (!sptr_curserRecord.active) revert UnauthorizedVoter(curseVoteAddr);
+ _authorizedVoteToCurse(curseVoteAddr, curseId, subjects, sptr_curserRecord);
+ }
+
+ function _authorizedVoteToCurse(
+ address curseVoteAddr,
+ bytes16 curseId,
+ bytes16[] memory subjects,
+ CurserRecord storage sptr_curserRecord
+ ) internal {
+ if (subjects.length == 0) revert VoteToCurseNoop();
+
+ if (sptr_curserRecord.usedCurseIds[curseId]) revert ReusedCurseId(curseVoteAddr, curseId);
+ sptr_curserRecord.usedCurseIds[curseId] = true;
+
+ // NOTE: We could pack configVersion into CurserRecord that we already load in the beginning of this function to
+ // avoid the following extra storage read for it, but since voteToCurse is not on the hot path we'd rather keep
+ // things simple.
+ uint32 configVersion = s_versionedConfig.configVersion;
+ for (uint256 i = 0; i < subjects.length; ++i) {
+ if (i >= 1 && !(subjects[i - 1] < subjects[i])) {
+ // Prevents a subject from receiving multiple votes to curse with the same curse id.
+ revert SubjectsMustBeStrictlyIncreasing();
+ }
+
+ bytes16 subject = subjects[i];
+ CurseVoteProgress storage sptr_curseVoteProgress = _getUpToDateCurseVoteProgress(configVersion, subject);
+ ConfigVersionAndCursesHash memory cvch = sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr];
+ bytes28 prevCursesHash;
+ if (
+ (curseVoteAddr != OWNER_CURSE_VOTE_ADDR && cvch.configVersion < configVersion)
+ || cvch.cursesHash == NO_VOTES_CURSES_HASH
+ ) {
+ // if owner's first vote, or if voter's first vote in this config version
+ prevCursesHash = NO_VOTES_CURSES_HASH; // start hashchain from scratch, explicit
+ sptr_curseVoteProgress.accumulatedWeight += sptr_curserRecord.weight;
+ } else {
+ // we've already accounted for the weight
+ prevCursesHash = cvch.cursesHash;
+ }
+ sptr_curseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr] = cvch =
+ ConfigVersionAndCursesHash({configVersion: configVersion, cursesHash: _cursesHash(prevCursesHash, curseId)});
+ emit VotedToCurse(
+ configVersion,
+ curseVoteAddr,
+ subject,
+ curseId,
+ sptr_curserRecord.weight,
+ _blockTimestamp(),
+ cvch.cursesHash,
+ sptr_curseVoteProgress.accumulatedWeight
+ );
+
+ if (
+ prevCursesHash == NO_VOTES_CURSES_HASH && !sptr_curseVoteProgress.curseActive
+ && _shouldCurseBeActive(sptr_curseVoteProgress)
+ ) {
+ sptr_curseVoteProgress.curseActive = true;
+ ++s_curseHotVars.numSubjectsCursed;
+ emit Cursed(configVersion, subject, _blockTimestamp());
+ }
+
+ s_recordedCurseRelatedOps.push(
+ RecordedCurseRelatedOp({
+ tag: RecordedCurseRelatedOpTag.VoteToCurse,
+ cursed: sptr_curseVoteProgress.curseActive,
+ curseVoteAddr: curseVoteAddr,
+ curseId: curseId,
+ subject: subject,
+ blockTimestamp: _blockTimestamp()
+ })
+ );
+ }
+ }
+
+ /// @notice Enables the owner to immediately have the system enter the cursed state.
+ function ownerCurse(bytes16 curseId, bytes16[] memory subjects) external onlyOwner {
+ address curseVoteAddr = OWNER_CURSE_VOTE_ADDR;
+ CurserRecord storage sptr_curserRecord = s_curserRecords[curseVoteAddr];
+ // no need to check if sptr_curserRecord.active, we must have the onlyOwner modifier
+ _authorizedVoteToCurse(curseVoteAddr, curseId, subjects, sptr_curserRecord);
+ }
+
+ // Set curseVoteAddr=LIFT_CURSE_VOTE_ADDR, cursesHash=bytes28(0), to reset curseActive if it can be reset. Useful if
+ // all voters have unvoted to curse on their own and the curse can now be lifted without any individual votes that can
+ // be unvoted.
+ // solhint-disable-next-line gas-struct-packing
+ struct OwnerUnvoteToCurseRequest {
+ address curseVoteAddr;
+ UnvoteToCurseRequest unit;
+ bool forceUnvote;
+ }
+
+ /// @notice Enables the owner to remove curse votes. After the curse votes are removed,
+ /// this function will check whether the curse is still valid and restore the uncursed state if possible.
+ /// This function also enables the owner to lift a curse created through ownerCurse.
+ function ownerUnvoteToCurse(OwnerUnvoteToCurseRequest[] memory ownerUnvoteToCurseRequests) external onlyOwner {
+ bool anyCurseWasLifted = false;
+ bool anyVoteWasUnvoted = false;
+ uint32 configVersion = s_versionedConfig.configVersion;
+ for (uint256 i = 0; i < ownerUnvoteToCurseRequests.length; ++i) {
+ OwnerUnvoteToCurseRequest memory req = ownerUnvoteToCurseRequests[i];
+ CurseVoteProgress storage sptr_curseVoteProgress = _getUpToDateCurseVoteProgress(configVersion, req.unit.subject);
+ (bool unvoted, bool curseLifted) = _authorizedUnvoteToCurse(
+ Privilege.Owner,
+ configVersion,
+ req.curseVoteAddr,
+ req.unit,
+ req.forceUnvote,
+ s_curserRecords[req.curseVoteAddr],
+ sptr_curseVoteProgress
+ );
+ anyVoteWasUnvoted = anyVoteWasUnvoted || unvoted;
+ anyCurseWasLifted = anyCurseWasLifted || curseLifted;
+ }
+
+ if (anyCurseWasLifted) {
+ // Invalidate all in-progress votes to bless or curse by bumping the config version.
+ // They might have been based on false information about the source chain
+ // (e.g. in case of a finality violation).
+ _setConfig(s_versionedConfig.config);
+ }
+
+ if (!(anyVoteWasUnvoted || anyCurseWasLifted)) {
+ revert UnvoteToCurseNoop();
+ }
+ }
+
+ function setConfig(Config memory config) external onlyOwner {
+ _setConfig(config);
+ }
+
+ /// @notice Any tagged root with a commit store included in this array will be considered automatically blessed.
+ function getPermaBlessedCommitStores() external view returns (address[] memory) {
+ return s_permaBlessedCommitStores.values();
+ }
+
+ /// @notice The ordering of parameters is important. First come the commit stores to remove, then the commit stores to
+ /// add.
+ function ownerRemoveThenAddPermaBlessedCommitStores(
+ address[] memory removes,
+ address[] memory adds
+ ) external onlyOwner {
+ for (uint256 i = 0; i < removes.length; ++i) {
+ if (s_permaBlessedCommitStores.remove(removes[i])) {
+ emit PermaBlessedCommitStoreRemoved(removes[i]);
+ }
+ }
+ for (uint256 i = 0; i < adds.length; ++i) {
+ if (s_permaBlessedCommitStores.add(adds[i])) {
+ emit PermaBlessedCommitStoreAdded(adds[i]);
+ }
+ }
+ }
+
+ /// @inheritdoc IRMN
+ function isBlessed(IRMN.TaggedRoot calldata taggedRoot) external view returns (bool) {
+ return s_blessVoteProgressByTaggedRootHash[_taggedRootHash(taggedRoot)].weightThresholdMet
+ || s_permaBlessedCommitStores.contains(taggedRoot.commitStore);
+ }
+
+ /// @inheritdoc IRMN
+ function isCursed() external view returns (bool) {
+ if (s_curseHotVars.numSubjectsCursed == 0) {
+ return false; // happy path costs a single SLOAD
+ } else {
+ return s_potentiallyOutdatedCurseVoteProgressBySubject[GLOBAL_CURSE_SUBJECT].curseActive
+ || s_potentiallyOutdatedCurseVoteProgressBySubject[LEGACY_CURSE_SUBJECT].curseActive;
+ }
+ }
+
+ /// @inheritdoc IRMN
+ function isCursed(bytes16 subject) public view returns (bool) {
+ if (s_curseHotVars.numSubjectsCursed == 0) {
+ return false; // happy path costs a single SLOAD
+ } else {
+ return s_potentiallyOutdatedCurseVoteProgressBySubject[GLOBAL_CURSE_SUBJECT].curseActive
+ || s_potentiallyOutdatedCurseVoteProgressBySubject[subject].curseActive;
+ }
+ }
+
+ /// @notice Config version might be incremented for many reasons, including
+ /// the lifting of a curse, or a regular config change.
+ function getConfigDetails() external view returns (uint32 version, uint32 blockNumber, Config memory config) {
+ version = s_versionedConfig.configVersion;
+ blockNumber = s_versionedConfig.blockNumber;
+ config = s_versionedConfig.config;
+ }
+
+ /// @return blessVoteAddrs addresses of voters, will be empty if voting took place with an older config version
+ /// @return accumulatedWeight sum of weights of voters, will be zero if voting took place with an older config version
+ /// @return blessed will be accurate regardless of when voting took place
+ /// @dev This is a helper method for offchain code so efficiency is not really a concern.
+ function getBlessProgress(IRMN.TaggedRoot calldata taggedRoot)
+ external
+ view
+ returns (address[] memory blessVoteAddrs, uint16 accumulatedWeight, bool blessed)
+ {
+ bytes32 taggedRootHash = _taggedRootHash(taggedRoot);
+ BlessVoteProgress memory progress = s_blessVoteProgressByTaggedRootHash[taggedRootHash];
+ blessed = progress.weightThresholdMet;
+ if (progress.configVersion == s_versionedConfig.configVersion) {
+ accumulatedWeight = progress.accumulatedWeight;
+ uint200 bitmap = progress.voterBitmap;
+ blessVoteAddrs = new address[](_bitmapCount(bitmap));
+ Voter[] memory voters = s_versionedConfig.config.voters;
+ uint256 j = 0;
+ for (uint8 i = 0; i < voters.length; ++i) {
+ if (_bitmapGet(bitmap, i)) {
+ blessVoteAddrs[j] = voters[i].blessVoteAddr;
+ ++j;
+ }
+ }
+ }
+ }
+
+ /// @return curseVoteAddrs the curseVoteAddr of each voter with an active vote to curse
+ /// @return cursesHashes the i-th value is the curses hash of curseVoteAddrs[i]
+ /// @return accumulatedWeight the accumulated weight of all voters with an active vote to curse who are part of the
+ /// current config
+ /// @return cursed might be true even if the owner has no active vote and accumulatedWeight < curseWeightThreshold,
+ /// due to a retained curse from a prior config
+ /// @dev This is a helper method for offchain code so efficiency is not really a concern.
+ function getCurseProgress(bytes16 subject)
+ external
+ view
+ returns (address[] memory curseVoteAddrs, bytes28[] memory cursesHashes, uint16 accumulatedWeight, bool cursed)
+ {
+ uint32 configVersion = s_versionedConfig.configVersion;
+ Config memory config = s_versionedConfig.config;
+ // Can't use _getUpToDateCurseVoteProgress here because we can't call a non-view function from within a view.
+ // So we get to repeat some accounting.
+ CurseVoteProgress storage outdatedCurseVoteProgress = s_potentiallyOutdatedCurseVoteProgressBySubject[subject];
+
+ cursed = outdatedCurseVoteProgress.curseActive;
+
+ // See _getUpToDateCurseVoteProgress for more context.
+ bool shouldCountVotesFromOlderConfigs = outdatedCurseVoteProgress.configVersion < configVersion && cursed;
+
+ // A play in two acts, because we can't push to arrays in memory, so we need to precompute the array's length.
+ // First act: we count the number of cursers, i.e., voters with active vote.
+ // Second act: push the cursers to the arrays, sum their weights.
+
+ uint256 numCursers = 0; // we reuse this variable for writing to perserve stack space
+ accumulatedWeight = 0;
+ for (uint256 act = 1; act <= 2; ++act) {
+ uint256 i = config.voters.length; // not config.voters.length-1 to account for the owner
+ while (true) {
+ address curseVoteAddr;
+ uint8 weight;
+ if (i < config.voters.length) {
+ curseVoteAddr = config.voters[i].curseVoteAddr;
+ weight = config.voters[i].curseWeight;
+ } else {
+ // Allows us to include the owner's vote and curses hash in the result.
+ curseVoteAddr = OWNER_CURSE_VOTE_ADDR;
+ weight = 0;
+ }
+
+ ConfigVersionAndCursesHash memory cvch =
+ outdatedCurseVoteProgress.latestVoteToCurseByCurseVoteAddr[curseVoteAddr];
+ bool hasActiveVote = (
+ shouldCountVotesFromOlderConfigs || cvch.configVersion == configVersion
+ || curseVoteAddr == OWNER_CURSE_VOTE_ADDR
+ ) && cvch.cursesHash != NO_VOTES_CURSES_HASH;
+ if (hasActiveVote) {
+ if (act == 1) {
+ ++numCursers;
+ } else if (act == 2) {
+ accumulatedWeight += weight;
+ --numCursers;
+ curseVoteAddrs[numCursers] = curseVoteAddr;
+ cursesHashes[numCursers] = cvch.cursesHash;
+ } else {
+ // solhint-disable-next-line gas-custom-errors, reason-string
+ revert(); // assumption violation
+ }
+ }
+
+ if (i > 0) {
+ --i;
+ } else {
+ break;
+ }
+ }
+
+ if (act == 1) {
+ // We are done counting at this point, initialize the arrays for the second act that follows immediately after.
+ curseVoteAddrs = new address[](numCursers);
+ cursesHashes = new bytes28[](numCursers);
+ }
+ }
+ }
+
+ /// @notice Returns the number of subjects that are currently cursed.
+ function getCursedSubjectsCount() external view returns (uint256) {
+ return s_curseHotVars.numSubjectsCursed;
+ }
+
+ /// @dev This is a helper method for offchain code to know what arguments to use for getRecordedCurseRelatedOps.
+ function getRecordedCurseRelatedOpsCount() external view returns (uint256) {
+ return s_recordedCurseRelatedOps.length;
+ }
+
+ /// @dev This is a helper method for offchain code so efficiency is not really a concern.
+ /// @dev Returns s_recordedCurseRelatedOps[offset:offset+limit].
+ function getRecordedCurseRelatedOps(
+ uint256 offset,
+ uint256 limit
+ ) external view returns (RecordedCurseRelatedOp[] memory) {
+ uint256 pageLen;
+ if (offset + limit <= s_recordedCurseRelatedOps.length) {
+ pageLen = limit;
+ } else if (offset < s_recordedCurseRelatedOps.length) {
+ pageLen = s_recordedCurseRelatedOps.length - offset;
+ } else {
+ pageLen = 0;
+ }
+ RecordedCurseRelatedOp[] memory page = new RecordedCurseRelatedOp[](pageLen);
+ for (uint256 i = 0; i < pageLen; ++i) {
+ page[i] = s_recordedCurseRelatedOps[offset + i];
+ }
+ return page;
+ }
+
+ function _validateConfig(Config memory config) internal pure returns (bool) {
+ if (
+ config.voters.length == 0 || config.voters.length > MAX_NUM_VOTERS || config.blessWeightThreshold == 0
+ || config.curseWeightThreshold == 0
+ ) {
+ return false;
+ }
+
+ uint256 totalBlessWeight = 0;
+ uint256 totalCurseWeight = 0;
+ address[] memory allAddrs = new address[](2 * config.voters.length);
+ for (uint256 i = 0; i < config.voters.length; ++i) {
+ Voter memory voter = config.voters[i];
+ // The owner can always curse using the ownerCurse method, and is not supposed to be included in the voters list.
+ // Even though the intent is for the actual owner address to NOT be included in the voters list, we don't
+ // explicitly disallow curseVoteAddr == owner() here. Even if we did, the owner could transfer ownership of the
+ // contract, and so we couldn't guarantee that the owner is not eventually included in the voters list.
+ if (
+ voter.blessVoteAddr == address(0) || voter.curseVoteAddr == address(0)
+ || voter.curseVoteAddr == LIFT_CURSE_VOTE_ADDR || voter.curseVoteAddr == OWNER_CURSE_VOTE_ADDR
+ || (voter.blessWeight == 0 && voter.curseWeight == 0)
+ ) {
+ return false;
+ }
+ allAddrs[2 * i + 0] = voter.blessVoteAddr;
+ allAddrs[2 * i + 1] = voter.curseVoteAddr;
+ totalBlessWeight += voter.blessWeight;
+ totalCurseWeight += voter.curseWeight;
+ }
+ for (uint256 i = 0; i < allAddrs.length; ++i) {
+ address allAddrs_i = allAddrs[i];
+ for (uint256 j = i + 1; j < allAddrs.length; ++j) {
+ if (allAddrs_i == allAddrs[j]) {
+ return false;
+ }
+ }
+ }
+
+ return totalBlessWeight >= config.blessWeightThreshold && totalCurseWeight >= config.curseWeightThreshold;
+ }
+
+ function _setConfig(Config memory config) private {
+ if (!_validateConfig(config)) revert InvalidConfig();
+
+ // We can't directly assign s_versionedConfig.config to config
+ // because copying a memory array into storage is not supported.
+ {
+ s_versionedConfig.config.blessWeightThreshold = config.blessWeightThreshold;
+ s_versionedConfig.config.curseWeightThreshold = config.curseWeightThreshold;
+ while (s_versionedConfig.config.voters.length != 0) {
+ Voter memory voter = s_versionedConfig.config.voters[s_versionedConfig.config.voters.length - 1];
+ delete s_blesserRecords[voter.blessVoteAddr];
+ delete s_curserRecords[voter.curseVoteAddr]; // usedCurseIds mapping is retained, as intended
+ s_versionedConfig.config.voters.pop();
+ }
+ for (uint256 i = 0; i < config.voters.length; ++i) {
+ s_versionedConfig.config.voters.push(config.voters[i]);
+ }
+ }
+
+ ++s_versionedConfig.configVersion;
+ uint32 configVersion = s_versionedConfig.configVersion;
+
+ for (uint8 i = 0; i < config.voters.length; ++i) {
+ Voter memory voter = config.voters[i];
+ s_blesserRecords[voter.blessVoteAddr] =
+ BlesserRecord({configVersion: configVersion, index: i, weight: voter.blessWeight});
+ {
+ CurserRecord storage sptr_curserRecord = s_curserRecords[voter.curseVoteAddr];
+ // Solidity will not let us initialize as CurserRecord({...}) due to the nested mapping
+ sptr_curserRecord.active = true;
+ sptr_curserRecord.weight = voter.curseWeight;
+ }
+ }
+ {
+ // Initialize the owner's CurserRecord
+ // We could in principle perform this initialization once in the constructor instead, and save a small bit of gas.
+ // But configuration changes are relatively infrequent, and keeping the initialization here makes the contract's
+ // correctness easier to reason about.
+ CurserRecord storage sptr_ownerCurserRecord = s_curserRecords[OWNER_CURSE_VOTE_ADDR];
+ sptr_ownerCurserRecord.active = true; // Assumed by vote/unvote-to-curse logic
+ sptr_ownerCurserRecord.weight = 0; // Assumed by vote/unvote-to-curse logic
+ }
+ s_versionedConfig.blockNumber = uint32(block.number);
+ emit ConfigSet(configVersion, config);
+
+ s_recordedCurseRelatedOps.push(
+ RecordedCurseRelatedOp({
+ tag: RecordedCurseRelatedOpTag.SetConfig,
+ blockTimestamp: _blockTimestamp(),
+ cursed: false,
+ curseVoteAddr: address(0),
+ curseId: bytes16(0),
+ subject: bytes16(0)
+ })
+ );
+ }
+}
diff --git a/contracts/src/v0.8/ccip/Router.sol b/contracts/src/v0.8/ccip/Router.sol
new file mode 100644
index 00000000000..e50651bc5ba
--- /dev/null
+++ b/contracts/src/v0.8/ccip/Router.sol
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
+import {IAny2EVMMessageReceiver} from "./interfaces/IAny2EVMMessageReceiver.sol";
+import {IEVM2AnyOnRamp} from "./interfaces/IEVM2AnyOnRamp.sol";
+import {IRMN} from "./interfaces/IRMN.sol";
+import {IRouter} from "./interfaces/IRouter.sol";
+import {IRouterClient} from "./interfaces/IRouterClient.sol";
+import {IWrappedNative} from "./interfaces/IWrappedNative.sol";
+
+import {OwnerIsCreator} from "../shared/access/OwnerIsCreator.sol";
+import {CallWithExactGas} from "../shared/call/CallWithExactGas.sol";
+import {Client} from "./libraries/Client.sol";
+import {Internal} from "./libraries/Internal.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";
+import {EnumerableSet} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @title Router
+/// @notice This is the entry point for the end user wishing to send data across chains.
+/// @dev This contract is used as a router for both on-ramps and off-ramps
+contract Router is IRouter, IRouterClient, ITypeAndVersion, OwnerIsCreator {
+ using SafeERC20 for IERC20;
+ using EnumerableSet for EnumerableSet.UintSet;
+
+ error FailedToSendValue();
+ error InvalidRecipientAddress(address to);
+ error OffRampMismatch(uint64 chainSelector, address offRamp);
+ error BadARMSignal();
+
+ event OnRampSet(uint64 indexed destChainSelector, address onRamp);
+ event OffRampAdded(uint64 indexed sourceChainSelector, address offRamp);
+ event OffRampRemoved(uint64 indexed sourceChainSelector, address offRamp);
+ event MessageExecuted(bytes32 messageId, uint64 sourceChainSelector, address offRamp, bytes32 calldataHash);
+
+ struct OnRamp {
+ uint64 destChainSelector;
+ address onRamp;
+ }
+
+ struct OffRamp {
+ uint64 sourceChainSelector;
+ address offRamp;
+ }
+
+ string public constant override typeAndVersion = "Router 1.2.0";
+ // We limit return data to a selector plus 4 words. This is to avoid
+ // malicious contracts from returning large amounts of data and causing
+ // repeated out-of-gas scenarios.
+ uint16 public constant MAX_RET_BYTES = 4 + 4 * 32;
+ // STATIC CONFIG
+ // Address of RMN proxy contract (formerly known as ARM)
+ address private immutable i_armProxy;
+
+ // DYNAMIC CONFIG
+ address private s_wrappedNative;
+ // destChainSelector => onRamp address
+ // Only ever one onRamp enabled at a time for a given destChainSelector.
+ mapping(uint256 destChainSelector => address onRamp) private s_onRamps;
+ // Stores [sourceChainSelector << 160 + offramp] as a pair to allow for
+ // lookups for specific chain/offramp pairs.
+ EnumerableSet.UintSet private s_chainSelectorAndOffRamps;
+
+ constructor(address wrappedNative, address armProxy) {
+ // Zero address indicates unsupported auto-wrapping, therefore, unsupported
+ // native fee token payments.
+ s_wrappedNative = wrappedNative;
+ i_armProxy = armProxy;
+ }
+
+ // ================================================================
+ // │ Message sending │
+ // ================================================================
+
+ /// @inheritdoc IRouterClient
+ function getFee(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage memory message
+ ) external view returns (uint256 fee) {
+ if (message.feeToken == address(0)) {
+ // For empty feeToken return native quote.
+ message.feeToken = address(s_wrappedNative);
+ }
+ address onRamp = s_onRamps[destinationChainSelector];
+ if (onRamp == address(0)) revert UnsupportedDestinationChain(destinationChainSelector);
+ return IEVM2AnyOnRamp(onRamp).getFee(destinationChainSelector, message);
+ }
+
+ /// @notice This functionality has been removed and will revert when called.
+ function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory) {
+ if (!isChainSupported(chainSelector)) {
+ return new address[](0);
+ }
+ return IEVM2AnyOnRamp(s_onRamps[uint256(chainSelector)]).getSupportedTokens(chainSelector);
+ }
+
+ /// @inheritdoc IRouterClient
+ function isChainSupported(uint64 chainSelector) public view returns (bool) {
+ return s_onRamps[chainSelector] != address(0);
+ }
+
+ /// @inheritdoc IRouterClient
+ function ccipSend(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage memory message
+ ) external payable whenNotCursed returns (bytes32) {
+ address onRamp = s_onRamps[destinationChainSelector];
+ if (onRamp == address(0)) revert UnsupportedDestinationChain(destinationChainSelector);
+ uint256 feeTokenAmount;
+ // address(0) signals payment in true native
+ if (message.feeToken == address(0)) {
+ // for fee calculation we check the wrapped native price as we wrap
+ // as part of the native fee coin payment.
+ message.feeToken = s_wrappedNative;
+ // We rely on getFee to validate that the feeToken is whitelisted.
+ feeTokenAmount = IEVM2AnyOnRamp(onRamp).getFee(destinationChainSelector, message);
+ // Ensure sufficient native.
+ if (msg.value < feeTokenAmount) revert InsufficientFeeTokenAmount();
+ // Wrap and send native payment.
+ // Note we take the whole msg.value regardless if its larger.
+ feeTokenAmount = msg.value;
+ IWrappedNative(message.feeToken).deposit{value: feeTokenAmount}();
+ IERC20(message.feeToken).safeTransfer(onRamp, feeTokenAmount);
+ } else {
+ if (msg.value > 0) revert InvalidMsgValue();
+ // We rely on getFee to validate that the feeToken is whitelisted.
+ feeTokenAmount = IEVM2AnyOnRamp(onRamp).getFee(destinationChainSelector, message);
+ IERC20(message.feeToken).safeTransferFrom(msg.sender, onRamp, feeTokenAmount);
+ }
+
+ // Transfer the tokens to the token pools.
+ for (uint256 i = 0; i < message.tokenAmounts.length; ++i) {
+ IERC20 token = IERC20(message.tokenAmounts[i].token);
+ // We rely on getPoolBySourceToken to validate that the token is whitelisted.
+ token.safeTransferFrom(
+ msg.sender,
+ address(IEVM2AnyOnRamp(onRamp).getPoolBySourceToken(destinationChainSelector, token)),
+ message.tokenAmounts[i].amount
+ );
+ }
+
+ return IEVM2AnyOnRamp(onRamp).forwardFromRouter(destinationChainSelector, message, feeTokenAmount, msg.sender);
+ }
+
+ // ================================================================
+ // │ Message execution │
+ // ================================================================
+
+ /// @inheritdoc IRouter
+ /// @dev _callWithExactGas protects against return data bombs by capping the return data size at MAX_RET_BYTES.
+ function routeMessage(
+ Client.Any2EVMMessage calldata message,
+ uint16 gasForCallExactCheck,
+ uint256 gasLimit,
+ address receiver
+ ) external override whenNotCursed returns (bool success, bytes memory retData, uint256 gasUsed) {
+ // We only permit offRamps to call this function.
+ if (!isOffRamp(message.sourceChainSelector, msg.sender)) revert OnlyOffRamp();
+
+ // We encode here instead of the offRamps to constrain specifically what functions
+ // can be called from the router.
+ bytes memory data = abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message);
+
+ (success, retData, gasUsed) = CallWithExactGas._callWithExactGasSafeReturnData(
+ data, receiver, gasLimit, gasForCallExactCheck, Internal.MAX_RET_BYTES
+ );
+
+ emit MessageExecuted(message.messageId, message.sourceChainSelector, msg.sender, keccak256(data));
+ return (success, retData, gasUsed);
+ }
+
+ // @notice Merges a chain selector and offRamp address into a single uint256 by shifting the
+ // chain selector 160 bits to the left.
+ function _mergeChainSelectorAndOffRamp(
+ uint64 sourceChainSelector,
+ address offRampAddress
+ ) internal pure returns (uint256) {
+ return (uint256(sourceChainSelector) << 160) + uint160(offRampAddress);
+ }
+
+ // ================================================================
+ // │ Config │
+ // ================================================================
+
+ /// @notice Gets the wrapped representation of the native fee coin.
+ /// @return The address of the ERC20 wrapped native.
+ function getWrappedNative() external view returns (address) {
+ return s_wrappedNative;
+ }
+
+ /// @notice Sets a new wrapped native token.
+ /// @param wrappedNative The address of the new wrapped native ERC20 token.
+ function setWrappedNative(address wrappedNative) external onlyOwner {
+ s_wrappedNative = wrappedNative;
+ }
+
+ /// @notice Gets the RMN address, formerly known as ARM
+ /// @return The address of the RMN proxy contract, formerly known as ARM
+ function getArmProxy() external view returns (address) {
+ return i_armProxy;
+ }
+
+ /// @inheritdoc IRouter
+ function getOnRamp(uint64 destChainSelector) external view returns (address) {
+ return s_onRamps[destChainSelector];
+ }
+
+ function getOffRamps() external view returns (OffRamp[] memory) {
+ uint256[] memory encodedOffRamps = s_chainSelectorAndOffRamps.values();
+ OffRamp[] memory offRamps = new OffRamp[](encodedOffRamps.length);
+ for (uint256 i = 0; i < encodedOffRamps.length; ++i) {
+ uint256 encodedOffRamp = encodedOffRamps[i];
+ offRamps[i] =
+ OffRamp({sourceChainSelector: uint64(encodedOffRamp >> 160), offRamp: address(uint160(encodedOffRamp))});
+ }
+ return offRamps;
+ }
+
+ /// @inheritdoc IRouter
+ function isOffRamp(uint64 sourceChainSelector, address offRamp) public view returns (bool) {
+ // We have to encode the sourceChainSelector and offRamp into a uint256 to use as a key in the set.
+ return s_chainSelectorAndOffRamps.contains(_mergeChainSelectorAndOffRamp(sourceChainSelector, offRamp));
+ }
+
+ /// @notice applyRampUpdates applies a set of ramp changes which provides
+ /// the ability to add new chains and upgrade ramps.
+ function applyRampUpdates(
+ OnRamp[] calldata onRampUpdates,
+ OffRamp[] calldata offRampRemoves,
+ OffRamp[] calldata offRampAdds
+ ) external onlyOwner {
+ // Apply egress updates.
+ // We permit zero address as way to disable egress.
+ for (uint256 i = 0; i < onRampUpdates.length; ++i) {
+ OnRamp memory onRampUpdate = onRampUpdates[i];
+ s_onRamps[onRampUpdate.destChainSelector] = onRampUpdate.onRamp;
+ emit OnRampSet(onRampUpdate.destChainSelector, onRampUpdate.onRamp);
+ }
+
+ // Apply ingress updates.
+ for (uint256 i = 0; i < offRampRemoves.length; ++i) {
+ uint64 sourceChainSelector = offRampRemoves[i].sourceChainSelector;
+ address offRampAddress = offRampRemoves[i].offRamp;
+
+ // If the selector-offRamp pair does not exist, revert.
+ if (!s_chainSelectorAndOffRamps.remove(_mergeChainSelectorAndOffRamp(sourceChainSelector, offRampAddress))) {
+ revert OffRampMismatch(sourceChainSelector, offRampAddress);
+ }
+
+ emit OffRampRemoved(sourceChainSelector, offRampAddress);
+ }
+
+ for (uint256 i = 0; i < offRampAdds.length; ++i) {
+ uint64 sourceChainSelector = offRampAdds[i].sourceChainSelector;
+ address offRampAddress = offRampAdds[i].offRamp;
+
+ if (s_chainSelectorAndOffRamps.add(_mergeChainSelectorAndOffRamp(sourceChainSelector, offRampAddress))) {
+ emit OffRampAdded(sourceChainSelector, offRampAddress);
+ }
+ }
+ }
+
+ /// @notice Provides the ability for the owner to recover any tokens accidentally
+ /// sent to this contract.
+ /// @dev Must be onlyOwner to avoid malicious token contract calls.
+ /// @param tokenAddress ERC20-token to recover
+ /// @param to Destination address to send the tokens to.
+ function recoverTokens(address tokenAddress, address to, uint256 amount) external onlyOwner {
+ if (to == address(0)) revert InvalidRecipientAddress(to);
+
+ if (tokenAddress == address(0)) {
+ (bool success,) = to.call{value: amount}("");
+ if (!success) revert FailedToSendValue();
+ return;
+ }
+ IERC20(tokenAddress).safeTransfer(to, amount);
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @notice Ensure that the RMN has not cursed the network.
+ modifier whenNotCursed() {
+ if (IRMN(i_armProxy).isCursed()) revert BadARMSignal();
+ _;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/applications/CCIPClientExample.sol b/contracts/src/v0.8/ccip/applications/CCIPClientExample.sol
new file mode 100644
index 00000000000..b105cf8b00f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/applications/CCIPClientExample.sol
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {IRouterClient} from "../interfaces/IRouterClient.sol";
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+import {Client} from "../libraries/Client.sol";
+import {CCIPReceiver} from "./CCIPReceiver.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+// @notice Example of a client which supports EVM/non-EVM chains
+// @dev If chain specific logic is required for different chain families (e.g. particular
+// decoding the bytes sender for authorization checks), it may be required to point to a helper
+// authorization contract unless all chain families are known up front.
+// @dev If contract does not implement IAny2EVMMessageReceiver and IERC165,
+// and tokens are sent to it, ccipReceive will not be called but tokens will be transferred.
+// @dev If the client is upgradeable you have significantly more flexibility and
+// can avoid storage based options like the below contract uses. However it's
+// worth carefully considering how the trust assumptions of your client dapp will
+// change if you introduce upgradeability. An immutable dapp building on top of CCIP
+// like the example below will inherit the trust properties of CCIP (i.e. the oracle network).
+// @dev The receiver's are encoded offchain and passed as direct arguments to permit supporting
+// new chain family receivers (e.g. a Solana encoded receiver address) without upgrading.
+contract CCIPClientExample is CCIPReceiver, OwnerIsCreator {
+ error InvalidChain(uint64 chainSelector);
+
+ event MessageSent(bytes32 messageId);
+ event MessageReceived(bytes32 messageId);
+
+ // Current feeToken
+ IERC20 public s_feeToken;
+ // Below is a simplistic example (same params for all messages) of using storage to allow for new options without
+ // upgrading the dapp. Note that extra args are chain family specific (e.g. gasLimit is EVM specific etc.).
+ // and will always be backwards compatible i.e. upgrades are opt-in.
+ // Offchain we can compute the V1 extraArgs:
+ // Client.EVMExtraArgsV1 memory extraArgs = Client.EVMExtraArgsV1({gasLimit: 300_000});
+ // bytes memory encodedV1ExtraArgs = Client._argsToBytes(extraArgs);
+ // Then later compute V2 extraArgs, for example if a refund feature was added:
+ // Client.EVMExtraArgsV2 memory extraArgs = Client.EVMExtraArgsV2({gasLimit: 300_000, destRefundAddress: 0x1234});
+ // bytes memory encodedV2ExtraArgs = Client._argsToBytes(extraArgs);
+ // and update storage with the new args.
+ // If different options are required for different messages, for example different gas limits,
+ // one can simply key based on (chainSelector, messageType) instead of only chainSelector.
+ mapping(uint64 destChainSelector => bytes extraArgsBytes) public s_chains;
+
+ constructor(IRouterClient router, IERC20 feeToken) CCIPReceiver(address(router)) {
+ s_feeToken = feeToken;
+ s_feeToken.approve(address(router), type(uint256).max);
+ }
+
+ function enableChain(uint64 chainSelector, bytes memory extraArgs) external onlyOwner {
+ s_chains[chainSelector] = extraArgs;
+ }
+
+ function disableChain(uint64 chainSelector) external onlyOwner {
+ delete s_chains[chainSelector];
+ }
+
+ function ccipReceive(Client.Any2EVMMessage calldata message)
+ external
+ virtual
+ override
+ onlyRouter
+ validChain(message.sourceChainSelector)
+ {
+ // Extremely important to ensure only router calls this.
+ // Tokens in message if any will be transferred to this contract
+ // TODO: Validate sender/origin chain and process message and/or tokens.
+ _ccipReceive(message);
+ }
+
+ function _ccipReceive(Client.Any2EVMMessage memory message) internal override {
+ emit MessageReceived(message.messageId);
+ }
+
+ /// @notice sends data to receiver on dest chain. Assumes address(this) has sufficient native asset.
+ function sendDataPayNative(
+ uint64 destChainSelector,
+ bytes memory receiver,
+ bytes memory data
+ ) external validChain(destChainSelector) {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](0);
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: receiver,
+ data: data,
+ tokenAmounts: tokenAmounts,
+ extraArgs: s_chains[destChainSelector],
+ feeToken: address(0) // We leave the feeToken empty indicating we'll pay raw native.
+ });
+ bytes32 messageId = IRouterClient(i_ccipRouter).ccipSend{
+ value: IRouterClient(i_ccipRouter).getFee(destChainSelector, message)
+ }(destChainSelector, message);
+ emit MessageSent(messageId);
+ }
+
+ /// @notice sends data to receiver on dest chain. Assumes address(this) has sufficient feeToken.
+ function sendDataPayFeeToken(
+ uint64 destChainSelector,
+ bytes memory receiver,
+ bytes memory data
+ ) external validChain(destChainSelector) {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](0);
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: receiver,
+ data: data,
+ tokenAmounts: tokenAmounts,
+ extraArgs: s_chains[destChainSelector],
+ feeToken: address(s_feeToken)
+ });
+ // Optional uint256 fee = i_ccipRouter.getFee(destChainSelector, message);
+ // Can decide if fee is acceptable.
+ // address(this) must have sufficient feeToken or the send will revert.
+ bytes32 messageId = IRouterClient(i_ccipRouter).ccipSend(destChainSelector, message);
+ emit MessageSent(messageId);
+ }
+
+ /// @notice sends data to receiver on dest chain. Assumes address(this) has sufficient native token.
+ function sendDataAndTokens(
+ uint64 destChainSelector,
+ bytes memory receiver,
+ bytes memory data,
+ Client.EVMTokenAmount[] memory tokenAmounts
+ ) external validChain(destChainSelector) {
+ for (uint256 i = 0; i < tokenAmounts.length; ++i) {
+ IERC20(tokenAmounts[i].token).transferFrom(msg.sender, address(this), tokenAmounts[i].amount);
+ IERC20(tokenAmounts[i].token).approve(i_ccipRouter, tokenAmounts[i].amount);
+ }
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: receiver,
+ data: data,
+ tokenAmounts: tokenAmounts,
+ extraArgs: s_chains[destChainSelector],
+ feeToken: address(s_feeToken)
+ });
+ // Optional uint256 fee = i_ccipRouter.getFee(destChainSelector, message);
+ // Can decide if fee is acceptable.
+ // address(this) must have sufficient feeToken or the send will revert.
+ bytes32 messageId = IRouterClient(i_ccipRouter).ccipSend(destChainSelector, message);
+ emit MessageSent(messageId);
+ }
+
+ // @notice user sends tokens to a receiver
+ // Approvals can be optimized with a whitelist of tokens and inf approvals if desired.
+ function sendTokens(
+ uint64 destChainSelector,
+ bytes memory receiver,
+ Client.EVMTokenAmount[] memory tokenAmounts
+ ) external validChain(destChainSelector) {
+ for (uint256 i = 0; i < tokenAmounts.length; ++i) {
+ IERC20(tokenAmounts[i].token).transferFrom(msg.sender, address(this), tokenAmounts[i].amount);
+ IERC20(tokenAmounts[i].token).approve(i_ccipRouter, tokenAmounts[i].amount);
+ }
+ bytes memory data;
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: receiver,
+ data: data,
+ tokenAmounts: tokenAmounts,
+ extraArgs: s_chains[destChainSelector],
+ feeToken: address(s_feeToken)
+ });
+ // Optional uint256 fee = i_ccipRouter.getFee(destChainSelector, message);
+ // Can decide if fee is acceptable.
+ // address(this) must have sufficient feeToken or the send will revert.
+ bytes32 messageId = IRouterClient(i_ccipRouter).ccipSend(destChainSelector, message);
+ emit MessageSent(messageId);
+ }
+
+ modifier validChain(uint64 chainSelector) {
+ if (s_chains[chainSelector].length == 0) revert InvalidChain(chainSelector);
+ _;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/applications/CCIPReceiver.sol b/contracts/src/v0.8/ccip/applications/CCIPReceiver.sol
new file mode 100644
index 00000000000..7011f814de7
--- /dev/null
+++ b/contracts/src/v0.8/ccip/applications/CCIPReceiver.sol
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol";
+
+import {Client} from "../libraries/Client.sol";
+
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+
+/// @title CCIPReceiver - Base contract for CCIP applications that can receive messages.
+abstract contract CCIPReceiver is IAny2EVMMessageReceiver, IERC165 {
+ address internal immutable i_ccipRouter;
+
+ constructor(address router) {
+ if (router == address(0)) revert InvalidRouter(address(0));
+ i_ccipRouter = router;
+ }
+
+ /// @notice IERC165 supports an interfaceId
+ /// @param interfaceId The interfaceId to check
+ /// @return true if the interfaceId is supported
+ /// @dev Should indicate whether the contract implements IAny2EVMMessageReceiver
+ /// e.g. return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId
+ /// This allows CCIP to check if ccipReceive is available before calling it.
+ /// If this returns false or reverts, only tokens are transferred to the receiver.
+ /// If this returns true, tokens are transferred and ccipReceive is called atomically.
+ /// Additionally, if the receiver address does not have code associated with
+ /// it at the time of execution (EXTCODESIZE returns 0), only tokens will be transferred.
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;
+ }
+
+ /// @inheritdoc IAny2EVMMessageReceiver
+ function ccipReceive(Client.Any2EVMMessage calldata message) external virtual override onlyRouter {
+ _ccipReceive(message);
+ }
+
+ /// @notice Override this function in your implementation.
+ /// @param message Any2EVMMessage
+ function _ccipReceive(Client.Any2EVMMessage memory message) internal virtual;
+
+ /////////////////////////////////////////////////////////////////////
+ // Plumbing
+ /////////////////////////////////////////////////////////////////////
+
+ /// @notice Return the current router
+ /// @return CCIP router address
+ function getRouter() public view virtual returns (address) {
+ return address(i_ccipRouter);
+ }
+
+ error InvalidRouter(address router);
+
+ /// @dev only calls from the set router are accepted.
+ modifier onlyRouter() {
+ if (msg.sender != getRouter()) revert InvalidRouter(msg.sender);
+ _;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/applications/DefensiveExample.sol b/contracts/src/v0.8/ccip/applications/DefensiveExample.sol
new file mode 100644
index 00000000000..54e1e809465
--- /dev/null
+++ b/contracts/src/v0.8/ccip/applications/DefensiveExample.sol
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {IRouterClient} from "../interfaces/IRouterClient.sol";
+
+import {Client} from "../libraries/Client.sol";
+import {CCIPClientExample} from "./CCIPClientExample.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";
+import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol";
+
+contract DefensiveExample is CCIPClientExample {
+ using EnumerableMap for EnumerableMap.Bytes32ToUintMap;
+ using SafeERC20 for IERC20;
+
+ error OnlySelf();
+ error ErrorCase();
+ error MessageNotFailed(bytes32 messageId);
+
+ event MessageFailed(bytes32 indexed messageId, bytes reason);
+ event MessageSucceeded(bytes32 indexed messageId);
+ event MessageRecovered(bytes32 indexed messageId);
+
+ // Example error code, could have many different error codes.
+ enum ErrorCode {
+ // RESOLVED is first so that the default value is resolved.
+ RESOLVED,
+ // Could have any number of error codes here.
+ BASIC
+ }
+
+ // The message contents of failed messages are stored here.
+ mapping(bytes32 messageId => Client.Any2EVMMessage contents) public s_messageContents;
+
+ // Contains failed messages and their state.
+ EnumerableMap.Bytes32ToUintMap internal s_failedMessages;
+
+ // This is used to simulate a revert in the processMessage function.
+ bool internal s_simRevert = false;
+
+ constructor(IRouterClient router, IERC20 feeToken) CCIPClientExample(router, feeToken) {}
+
+ /// @notice The entrypoint for the CCIP router to call. This function should
+ /// never revert, all errors should be handled internally in this contract.
+ /// @param message The message to process.
+ /// @dev Extremely important to ensure only router calls this.
+ function ccipReceive(Client.Any2EVMMessage calldata message)
+ external
+ override
+ onlyRouter
+ validChain(message.sourceChainSelector)
+ {
+ try this.processMessage(message) {}
+ catch (bytes memory err) {
+ // Could set different error codes based on the caught error. Each could be
+ // handled differently.
+ s_failedMessages.set(message.messageId, uint256(ErrorCode.BASIC));
+ s_messageContents[message.messageId] = message;
+ // Don't revert so CCIP doesn't revert. Emit event instead.
+ // The message can be retried later without having to do manual execution of CCIP.
+ emit MessageFailed(message.messageId, err);
+ return;
+ }
+ emit MessageSucceeded(message.messageId);
+ }
+
+ /// @notice This function the entrypoint for this contract to process messages.
+ /// @param message The message to process.
+ /// @dev This example just sends the tokens to the owner of this contracts. More
+ /// interesting functions could be implemented.
+ /// @dev It has to be external because of the try/catch.
+ function processMessage(Client.Any2EVMMessage calldata message)
+ external
+ onlySelf
+ validChain(message.sourceChainSelector)
+ {
+ // Simulate a revert
+ if (s_simRevert) revert ErrorCase();
+
+ // Send tokens to the owner
+ for (uint256 i = 0; i < message.destTokenAmounts.length; ++i) {
+ IERC20(message.destTokenAmounts[i].token).safeTransfer(owner(), message.destTokenAmounts[i].amount);
+ }
+ // Do other things that might revert
+ }
+
+ /// @notice This function is callable by the owner when a message has failed
+ /// to unblock the tokens that are associated with that message.
+ /// @dev This function is only callable by the owner.
+ function retryFailedMessage(bytes32 messageId, address tokenReceiver) external onlyOwner {
+ if (s_failedMessages.get(messageId) != uint256(ErrorCode.BASIC)) revert MessageNotFailed(messageId);
+ // Set the error code to 0 to disallow reentry and retry the same failed message
+ // multiple times.
+ s_failedMessages.set(messageId, uint256(ErrorCode.RESOLVED));
+
+ // Do stuff to retry message, potentially just releasing the associated tokens
+ Client.Any2EVMMessage memory message = s_messageContents[messageId];
+
+ // send the tokens to the receiver as escape hatch
+ for (uint256 i = 0; i < message.destTokenAmounts.length; ++i) {
+ IERC20(message.destTokenAmounts[i].token).safeTransfer(tokenReceiver, message.destTokenAmounts[i].amount);
+ }
+
+ emit MessageRecovered(messageId);
+ }
+
+ // An example function to demonstrate recovery
+ function setSimRevert(bool simRevert) external onlyOwner {
+ s_simRevert = simRevert;
+ }
+
+ modifier onlySelf() {
+ if (msg.sender != address(this)) revert OnlySelf();
+ _;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/applications/EtherSenderReceiver.sol b/contracts/src/v0.8/ccip/applications/EtherSenderReceiver.sol
new file mode 100644
index 00000000000..ce8ed1ff7a0
--- /dev/null
+++ b/contracts/src/v0.8/ccip/applications/EtherSenderReceiver.sol
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+
+import {IRouterClient} from "../interfaces/IRouterClient.sol";
+import {IWrappedNative} from "../interfaces/IWrappedNative.sol";
+
+import {Client} from "./../libraries/Client.sol";
+import {CCIPReceiver} from "./CCIPReceiver.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";
+
+//solhint-disable interface-starts-with-i
+interface CCIPRouter {
+ function getWrappedNative() external view returns (address);
+}
+
+/// @notice A contract that can send raw ether cross-chain using CCIP.
+/// Since CCIP only supports ERC-20 token transfers, this contract accepts
+/// normal ether, wraps it, and uses CCIP to send it cross-chain.
+/// On the receiving side, the wrapped ether is unwrapped and sent to the final receiver.
+/// @notice This contract only supports chains where the wrapped native contract
+/// is the WETH contract (i.e not WMATIC, or WAVAX, etc.). This is because the
+/// receiving contract will always unwrap the ether using it's local wrapped native contract.
+/// @dev This contract is both a sender and a receiver. This same contract can be
+/// deployed on source and destination chains to facilitate cross-chain ether transfers
+/// and act as a sender and a receiver.
+/// @dev This contract is intentionally ownerless and permissionless. This contract
+/// will never hold any excess funds, native or otherwise, when used correctly.
+contract EtherSenderReceiver is CCIPReceiver, ITypeAndVersion {
+ using SafeERC20 for IERC20;
+
+ error InvalidTokenAmounts(uint256 gotAmounts);
+ error InvalidToken(address gotToken, address expectedToken);
+ error TokenAmountNotEqualToMsgValue(uint256 gotAmount, uint256 msgValue);
+
+ string public constant override typeAndVersion = "EtherSenderReceiver 1.5.0";
+
+ /// @notice The wrapped native token address.
+ /// @dev If the wrapped native token address changes on the router, this contract will need to be redeployed.
+ IWrappedNative public immutable i_weth;
+
+ /// @param router The CCIP router address.
+ constructor(address router) CCIPReceiver(router) {
+ i_weth = IWrappedNative(CCIPRouter(router).getWrappedNative());
+ i_weth.approve(router, type(uint256).max);
+ }
+
+ /// @notice Need this in order to unwrap correctly.
+ receive() external payable {}
+
+ /// @notice Get the fee for sending a message to a destination chain.
+ /// This is mirrored from the router for convenience, construct the appropriate
+ /// message and get it's fee.
+ /// @param destinationChainSelector The destination chainSelector
+ /// @param message The cross-chain CCIP message including data and/or tokens
+ /// @return fee returns execution fee for the message
+ /// delivery to destination chain, denominated in the feeToken specified in the message.
+ /// @dev Reverts with appropriate reason upon invalid message.
+ function getFee(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external view returns (uint256 fee) {
+ Client.EVM2AnyMessage memory validatedMessage = _validatedMessage(message);
+
+ return IRouterClient(getRouter()).getFee(destinationChainSelector, validatedMessage);
+ }
+
+ /// @notice Send raw native tokens cross-chain.
+ /// @param destinationChainSelector The destination chain selector.
+ /// @param message The CCIP message with the following fields correctly set:
+ /// - bytes receiver: The _contract_ address on the destination chain that will receive the wrapped ether.
+ /// The caller must ensure that this contract address is correct, otherwise funds may be lost forever.
+ /// - address feeToken: The fee token address. Must be address(0) for native tokens, or a supported CCIP fee token otherwise (i.e, LINK token).
+ /// In the event a feeToken is set, we will transferFrom the caller the fee amount before sending the message, in order to forward them to the router.
+ /// - EVMTokenAmount[] tokenAmounts: The tokenAmounts array must contain a single element with the following fields:
+ /// - uint256 amount: The amount of ether to send.
+ /// There are a couple of cases here that depend on the fee token specified:
+ /// 1. If feeToken == address(0), the fee must be included in msg.value. Therefore tokenAmounts[0].amount must be less than msg.value,
+ /// and the difference will be used as the fee.
+ /// 2. If feeToken != address(0), the fee is not included in msg.value, and tokenAmounts[0].amount must be equal to msg.value.
+ /// these fees to the CCIP router.
+ /// @return messageId The CCIP message ID.
+ function ccipSend(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external payable returns (bytes32) {
+ _validateFeeToken(message);
+ Client.EVM2AnyMessage memory validatedMessage = _validatedMessage(message);
+
+ i_weth.deposit{value: validatedMessage.tokenAmounts[0].amount}();
+
+ uint256 fee = IRouterClient(getRouter()).getFee(destinationChainSelector, validatedMessage);
+ if (validatedMessage.feeToken != address(0)) {
+ // If the fee token is not native, we need to transfer the fee to this contract and re-approve it to the router.
+ // Its not possible to have any leftover tokens in this path because we transferFrom the exact fee that CCIP
+ // requires from the caller.
+ IERC20(validatedMessage.feeToken).safeTransferFrom(msg.sender, address(this), fee);
+
+ // We gave an infinite approval of weth to the router in the constructor.
+ if (validatedMessage.feeToken != address(i_weth)) {
+ IERC20(validatedMessage.feeToken).approve(getRouter(), fee);
+ }
+
+ return IRouterClient(getRouter()).ccipSend(destinationChainSelector, validatedMessage);
+ }
+
+ // We don't want to keep any excess ether in this contract, so we send over the entire address(this).balance as the fee.
+ // CCIP will revert if the fee is insufficient, so we don't need to check here.
+ return IRouterClient(getRouter()).ccipSend{value: address(this).balance}(destinationChainSelector, validatedMessage);
+ }
+
+ /// @notice Validate the message content.
+ /// @dev Only allows a single token to be sent. Always overwritten to be address(i_weth)
+ /// and receiver is always msg.sender.
+ function _validatedMessage(Client.EVM2AnyMessage calldata message)
+ internal
+ view
+ returns (Client.EVM2AnyMessage memory)
+ {
+ Client.EVM2AnyMessage memory validatedMessage = message;
+
+ if (validatedMessage.tokenAmounts.length != 1) {
+ revert InvalidTokenAmounts(validatedMessage.tokenAmounts.length);
+ }
+
+ validatedMessage.data = abi.encode(msg.sender);
+ validatedMessage.tokenAmounts[0].token = address(i_weth);
+
+ return validatedMessage;
+ }
+
+ function _validateFeeToken(Client.EVM2AnyMessage calldata message) internal view {
+ uint256 tokenAmount = message.tokenAmounts[0].amount;
+
+ if (message.feeToken != address(0)) {
+ // If the fee token is NOT native, then the token amount must be equal to msg.value.
+ // This is done to ensure that there is no leftover ether in this contract.
+ if (msg.value != tokenAmount) {
+ revert TokenAmountNotEqualToMsgValue(tokenAmount, msg.value);
+ }
+ }
+ }
+
+ /// @notice Receive the wrapped ether, unwrap it, and send it to the specified EOA in the data field.
+ /// @param message The CCIP message containing the wrapped ether amount and the final receiver.
+ /// @dev The code below should never revert if the message being is valid according
+ /// to the above _validatedMessage and _validateFeeToken functions.
+ function _ccipReceive(Client.Any2EVMMessage memory message) internal override {
+ address receiver = abi.decode(message.data, (address));
+
+ if (message.destTokenAmounts.length != 1) {
+ revert InvalidTokenAmounts(message.destTokenAmounts.length);
+ }
+
+ if (message.destTokenAmounts[0].token != address(i_weth)) {
+ revert InvalidToken(message.destTokenAmounts[0].token, address(i_weth));
+ }
+
+ uint256 tokenAmount = message.destTokenAmounts[0].amount;
+ i_weth.withdraw(tokenAmount);
+
+ // it is possible that the below call may fail if receiver.code.length > 0 and the contract
+ // doesn't e.g have a receive() or a fallback() function.
+ (bool success,) = payable(receiver).call{value: tokenAmount}("");
+ if (!success) {
+ // We have a few options here:
+ // 1. Revert: this is bad generally because it may mean that these tokens are stuck.
+ // 2. Store the tokens in a mapping and allow the user to withdraw them with another tx.
+ // 3. Send WETH to the receiver address.
+ // We opt for (3) here because at least the receiver will have the funds and can unwrap them if needed.
+ // However it is worth noting that if receiver is actually a contract AND the contract _cannot_ withdraw
+ // the WETH, then the WETH will be stuck in this contract.
+ i_weth.deposit{value: tokenAmount}();
+ i_weth.transfer(receiver, tokenAmount);
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/applications/PingPongDemo.sol b/contracts/src/v0.8/ccip/applications/PingPongDemo.sol
new file mode 100644
index 00000000000..423fdc45467
--- /dev/null
+++ b/contracts/src/v0.8/ccip/applications/PingPongDemo.sol
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IRouterClient} from "../interfaces/IRouterClient.sol";
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+import {Client} from "../libraries/Client.sol";
+import {CCIPReceiver} from "./CCIPReceiver.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+/// @title PingPongDemo - A simple ping-pong contract for demonstrating cross-chain communication
+contract PingPongDemo is CCIPReceiver, OwnerIsCreator, ITypeAndVersion {
+ event Ping(uint256 pingPongCount);
+ event Pong(uint256 pingPongCount);
+
+ // The chain ID of the counterpart ping pong contract
+ uint64 internal s_counterpartChainSelector;
+ // The contract address of the counterpart ping pong contract
+ address internal s_counterpartAddress;
+ // Pause ping-ponging
+ bool private s_isPaused;
+ // The fee token used to pay for CCIP transactions
+ IERC20 internal s_feeToken;
+
+ constructor(address router, IERC20 feeToken) CCIPReceiver(router) {
+ s_isPaused = false;
+ s_feeToken = feeToken;
+ s_feeToken.approve(address(router), type(uint256).max);
+ }
+
+ function typeAndVersion() external pure virtual returns (string memory) {
+ return "PingPongDemo 1.2.0";
+ }
+
+ function setCounterpart(uint64 counterpartChainSelector, address counterpartAddress) external onlyOwner {
+ s_counterpartChainSelector = counterpartChainSelector;
+ s_counterpartAddress = counterpartAddress;
+ }
+
+ function startPingPong() external onlyOwner {
+ s_isPaused = false;
+ _respond(1);
+ }
+
+ function _respond(uint256 pingPongCount) internal virtual {
+ if (pingPongCount & 1 == 1) {
+ emit Ping(pingPongCount);
+ } else {
+ emit Pong(pingPongCount);
+ }
+ bytes memory data = abi.encode(pingPongCount);
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(s_counterpartAddress),
+ data: data,
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ extraArgs: "",
+ feeToken: address(s_feeToken)
+ });
+ IRouterClient(getRouter()).ccipSend(s_counterpartChainSelector, message);
+ }
+
+ function _ccipReceive(Client.Any2EVMMessage memory message) internal override {
+ uint256 pingPongCount = abi.decode(message.data, (uint256));
+ if (!s_isPaused) {
+ _respond(pingPongCount + 1);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////
+ // Plumbing
+ /////////////////////////////////////////////////////////////////////
+
+ function getCounterpartChainSelector() external view returns (uint64) {
+ return s_counterpartChainSelector;
+ }
+
+ function setCounterpartChainSelector(uint64 chainSelector) external onlyOwner {
+ s_counterpartChainSelector = chainSelector;
+ }
+
+ function getCounterpartAddress() external view returns (address) {
+ return s_counterpartAddress;
+ }
+
+ function getFeeToken() external view returns (IERC20) {
+ return s_feeToken;
+ }
+
+ function setCounterpartAddress(address addr) external onlyOwner {
+ s_counterpartAddress = addr;
+ }
+
+ function isPaused() external view returns (bool) {
+ return s_isPaused;
+ }
+
+ function setPaused(bool pause) external onlyOwner {
+ s_isPaused = pause;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/applications/SelfFundedPingPong.sol b/contracts/src/v0.8/ccip/applications/SelfFundedPingPong.sol
new file mode 100644
index 00000000000..80bc7bb24ab
--- /dev/null
+++ b/contracts/src/v0.8/ccip/applications/SelfFundedPingPong.sol
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Router} from "../Router.sol";
+import {Client} from "../libraries/Client.sol";
+import {EVM2EVMOnRamp} from "../onRamp/EVM2EVMOnRamp.sol";
+import {PingPongDemo} from "./PingPongDemo.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract SelfFundedPingPong is PingPongDemo {
+ string public constant override typeAndVersion = "SelfFundedPingPong 1.2.0";
+
+ event Funded();
+ event CountIncrBeforeFundingSet(uint8 countIncrBeforeFunding);
+
+ // Defines the increase in ping pong count before self-funding is attempted.
+ // Set to 0 to disable auto-funding, auto-funding only works for ping-pongs that are set as NOPs in the onRamp.
+ uint8 private s_countIncrBeforeFunding;
+
+ constructor(address router, IERC20 feeToken, uint8 roundTripsBeforeFunding) PingPongDemo(router, feeToken) {
+ // PingPong count increases by 2 for each round trip.
+ s_countIncrBeforeFunding = roundTripsBeforeFunding * 2;
+ }
+
+ function _respond(uint256 pingPongCount) internal override {
+ if (pingPongCount & 1 == 1) {
+ emit Ping(pingPongCount);
+ } else {
+ emit Pong(pingPongCount);
+ }
+
+ fundPingPong(pingPongCount);
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(s_counterpartAddress),
+ data: abi.encode(pingPongCount),
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ extraArgs: "",
+ feeToken: address(s_feeToken)
+ });
+ Router(getRouter()).ccipSend(s_counterpartChainSelector, message);
+ }
+
+ /// @notice A function that is responsible for funding this contract.
+ /// The contract can only be funded if it is set as a nop in the target onRamp.
+ /// In case your contract is not a nop you can prevent this function from being called by setting s_countIncrBeforeFunding=0.
+ function fundPingPong(uint256 pingPongCount) public {
+ // If selfFunding is disabled, or ping pong count has not reached s_countIncrPerFunding, do not attempt funding.
+ if (s_countIncrBeforeFunding == 0 || pingPongCount < s_countIncrBeforeFunding) return;
+
+ // Ping pong on one side will always be even, one side will always to odd.
+ if (pingPongCount % s_countIncrBeforeFunding <= 1) {
+ EVM2EVMOnRamp(Router(getRouter()).getOnRamp(s_counterpartChainSelector)).payNops();
+ emit Funded();
+ }
+ }
+
+ function getCountIncrBeforeFunding() external view returns (uint8) {
+ return s_countIncrBeforeFunding;
+ }
+
+ function setCountIncrBeforeFunding(uint8 countIncrBeforeFunding) external onlyOwner {
+ s_countIncrBeforeFunding = countIncrBeforeFunding;
+ emit CountIncrBeforeFundingSet(countIncrBeforeFunding);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/applications/TokenProxy.sol b/contracts/src/v0.8/ccip/applications/TokenProxy.sol
new file mode 100644
index 00000000000..6fd26c076bc
--- /dev/null
+++ b/contracts/src/v0.8/ccip/applications/TokenProxy.sol
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.24;
+
+import {IRouterClient} from "../interfaces/IRouterClient.sol";
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+import {Client} from "../libraries/Client.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 TokenProxy is OwnerIsCreator {
+ using SafeERC20 for IERC20;
+
+ error InvalidToken();
+ error NoDataAllowed();
+ error GasShouldBeZero();
+
+ /// @notice The CCIP router contract
+ IRouterClient internal immutable i_ccipRouter;
+ /// @notice Only this token is allowed to be sent using this proxy
+ address internal immutable i_token;
+
+ constructor(address router, address token) OwnerIsCreator() {
+ i_ccipRouter = IRouterClient(router);
+ i_token = token;
+ // Approve the router to spend an unlimited amount of tokens to reduce
+ // gas cost per tx.
+ IERC20(token).approve(router, type(uint256).max);
+ }
+
+ /// @notice Simply forwards the request to the CCIP router and returns the result.
+ /// @param destinationChainSelector The destination chainSelector
+ /// @param message The cross-chain CCIP message including data and/or tokens
+ /// @return fee returns execution fee for the message delivery to destination chain,
+ /// denominated in the feeToken specified in the message.
+ /// @dev Reverts with appropriate reason upon invalid message.
+ function getFee(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external view returns (uint256 fee) {
+ _validateMessage(message);
+ return i_ccipRouter.getFee(destinationChainSelector, message);
+ }
+
+ /// @notice Validates the message content, forwards it to the CCIP router and returns the result.
+ function ccipSend(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external payable returns (bytes32 messageId) {
+ _validateMessage(message);
+ if (message.feeToken != address(0)) {
+ // This path is probably warmed up already so the extra cost isn't too bad.
+ uint256 feeAmount = i_ccipRouter.getFee(destinationChainSelector, message);
+ IERC20(message.feeToken).safeTransferFrom(msg.sender, address(this), feeAmount);
+ IERC20(message.feeToken).approve(address(i_ccipRouter), feeAmount);
+ }
+
+ // Transfer the tokens from the sender to this contract.
+ IERC20(message.tokenAmounts[0].token).transferFrom(msg.sender, address(this), message.tokenAmounts[0].amount);
+
+ return i_ccipRouter.ccipSend{value: msg.value}(destinationChainSelector, message);
+ }
+
+ /// @notice Validates the message content.
+ /// @dev Only allows a single token to be sent, and no data.
+ function _validateMessage(Client.EVM2AnyMessage calldata message) internal view {
+ if (message.tokenAmounts.length != 1 || message.tokenAmounts[0].token != i_token) revert InvalidToken();
+ if (message.data.length > 0) revert NoDataAllowed();
+
+ if (message.extraArgs.length == 0 || bytes4(message.extraArgs) != Client.EVM_EXTRA_ARGS_V1_TAG) {
+ revert GasShouldBeZero();
+ }
+
+ if (abi.decode(message.extraArgs[4:], (Client.EVMExtraArgsV1)).gasLimit != 0) revert GasShouldBeZero();
+ }
+
+ /// @notice Returns the CCIP router contract.
+ function getRouter() external view returns (IRouterClient) {
+ return i_ccipRouter;
+ }
+
+ /// @notice Returns the token that this proxy is allowed to send.
+ function getToken() external view returns (address) {
+ return i_token;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/capability/CCIPConfig.sol b/contracts/src/v0.8/ccip/capability/CCIPConfig.sol
new file mode 100644
index 00000000000..40b7a4a2f93
--- /dev/null
+++ b/contracts/src/v0.8/ccip/capability/CCIPConfig.sol
@@ -0,0 +1,476 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ICapabilityConfiguration} from "../../keystone/interfaces/ICapabilityConfiguration.sol";
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {ICapabilitiesRegistry} from "./interfaces/ICapabilitiesRegistry.sol";
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+
+import {SortedSetValidationUtil} from "../../shared/util/SortedSetValidationUtil.sol";
+import {Internal} from "../libraries/Internal.sol";
+import {CCIPConfigTypes} from "./libraries/CCIPConfigTypes.sol";
+
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @notice CCIPConfig stores the configuration for the CCIP capability.
+/// We have two classes of configuration: chain configuration and DON (in the CapabilitiesRegistry sense) configuration.
+/// Each chain will have a single configuration which includes information like the router address.
+/// Each CR DON will have up to four configurations: for each of (commit, exec), one blue and one green configuration.
+/// This is done in order to achieve "blue-green" deployments.
+contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator, IERC165 {
+ using EnumerableSet for EnumerableSet.UintSet;
+
+ /// @notice Emitted when a chain's configuration is set.
+ /// @param chainSelector The chain selector.
+ /// @param chainConfig The chain configuration.
+ event ChainConfigSet(uint64 chainSelector, CCIPConfigTypes.ChainConfig chainConfig);
+
+ /// @notice Emitted when a chain's configuration is removed.
+ /// @param chainSelector The chain selector.
+ event ChainConfigRemoved(uint64 chainSelector);
+
+ error ChainConfigNotSetForChain(uint64 chainSelector);
+ error NodeNotInRegistry(bytes32 p2pId);
+ error OnlyCapabilitiesRegistryCanCall();
+ error ChainSelectorNotFound(uint64 chainSelector);
+ error ChainSelectorNotSet();
+ error TooManyOCR3Configs();
+ error TooManySigners();
+ error TooManyTransmitters();
+ error TooManyBootstrapP2PIds();
+ error P2PIdsLengthNotMatching(uint256 p2pIdsLength, uint256 signersLength, uint256 transmittersLength);
+ error NotEnoughTransmitters(uint256 got, uint256 minimum);
+ error FMustBePositive();
+ error FChainMustBePositive();
+ error FTooHigh();
+ error InvalidPluginType();
+ error OfframpAddressCannotBeZero();
+ error InvalidConfigLength(uint256 length);
+ error InvalidConfigStateTransition(
+ CCIPConfigTypes.ConfigState currentState, CCIPConfigTypes.ConfigState proposedState
+ );
+ error NonExistentConfigTransition();
+ error WrongConfigCount(uint64 got, uint64 expected);
+ error WrongConfigDigest(bytes32 got, bytes32 expected);
+ error WrongConfigDigestBlueGreen(bytes32 got, bytes32 expected);
+
+ /// @notice Type and version override.
+ string public constant override typeAndVersion = "CCIPConfig 1.6.0-dev";
+
+ /// @notice The canonical capabilities registry address.
+ address internal immutable i_capabilitiesRegistry;
+
+ /// @notice chain configuration for each chain that CCIP is deployed on.
+ mapping(uint64 chainSelector => CCIPConfigTypes.ChainConfig chainConfig) internal s_chainConfigurations;
+
+ /// @notice All chains that are configured.
+ EnumerableSet.UintSet internal s_remoteChainSelectors;
+
+ /// @notice OCR3 configurations for each DON.
+ /// Each CR DON will have a commit and execution configuration.
+ /// This means that a DON can have up to 4 configurations, since we are implementing blue/green deployments.
+ mapping(
+ uint32 donId => mapping(Internal.OCRPluginType pluginType => CCIPConfigTypes.OCR3ConfigWithMeta[] ocr3Configs)
+ ) internal s_ocr3Configs;
+
+ /// @notice The DONs that have been configured.
+ EnumerableSet.UintSet internal s_donIds;
+
+ uint8 internal constant MAX_OCR3_CONFIGS_PER_PLUGIN = 2;
+ uint8 internal constant MAX_OCR3_CONFIGS_PER_DON = 4;
+ uint8 internal constant MAX_NUM_ORACLES = 31;
+
+ /// @param capabilitiesRegistry the canonical capabilities registry address.
+ constructor(address capabilitiesRegistry) {
+ i_capabilitiesRegistry = capabilitiesRegistry;
+ }
+
+ /// @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
+ return interfaceId == type(ICapabilityConfiguration).interfaceId || interfaceId == type(IERC165).interfaceId;
+ }
+
+ // ================================================================
+ // │ Config Getters │
+ // ================================================================
+
+ /// @notice Returns all the chain configurations.
+ /// @return The chain configurations.
+ // TODO: will this eventually hit the RPC max response size limit?
+ function getAllChainConfigs() external view returns (CCIPConfigTypes.ChainConfigInfo[] memory) {
+ uint256[] memory chainSelectors = s_remoteChainSelectors.values();
+ CCIPConfigTypes.ChainConfigInfo[] memory chainConfigs =
+ new CCIPConfigTypes.ChainConfigInfo[](s_remoteChainSelectors.length());
+ for (uint256 i = 0; i < chainSelectors.length; ++i) {
+ uint64 chainSelector = uint64(chainSelectors[i]);
+ chainConfigs[i] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: chainSelector,
+ chainConfig: s_chainConfigurations[chainSelector]
+ });
+ }
+ return chainConfigs;
+ }
+
+ /// @notice Returns the OCR configuration for the given don ID and plugin type.
+ /// @param donId The DON ID.
+ /// @param pluginType The plugin type.
+ /// @return The OCR3 configurations, up to 2 (blue and green).
+ function getOCRConfig(
+ uint32 donId,
+ Internal.OCRPluginType pluginType
+ ) external view returns (CCIPConfigTypes.OCR3ConfigWithMeta[] memory) {
+ return s_ocr3Configs[donId][pluginType];
+ }
+
+ // ================================================================
+ // │ Capability Configuration │
+ // ================================================================
+
+ /// @inheritdoc ICapabilityConfiguration
+ /// @dev The CCIP capability will fetch the configuration needed directly from this contract.
+ /// The offchain syncer will call this function, however, so its important that it doesn't revert.
+ function getCapabilityConfiguration(uint32 /* donId */ ) external pure override returns (bytes memory configuration) {
+ return bytes("");
+ }
+
+ /// @notice Called by the registry prior to the config being set for a particular DON.
+ function beforeCapabilityConfigSet(
+ bytes32[] calldata, /* nodes */
+ bytes calldata config,
+ uint64, /* configCount */
+ uint32 donId
+ ) external override {
+ if (msg.sender != i_capabilitiesRegistry) {
+ revert OnlyCapabilitiesRegistryCanCall();
+ }
+
+ CCIPConfigTypes.OCR3Config[] memory ocr3Configs = abi.decode(config, (CCIPConfigTypes.OCR3Config[]));
+ (CCIPConfigTypes.OCR3Config[] memory commitConfigs, CCIPConfigTypes.OCR3Config[] memory execConfigs) =
+ _groupByPluginType(ocr3Configs);
+ if (commitConfigs.length > 0) {
+ _updatePluginConfig(donId, Internal.OCRPluginType.Commit, commitConfigs);
+ }
+ if (execConfigs.length > 0) {
+ _updatePluginConfig(donId, Internal.OCRPluginType.Execution, execConfigs);
+ }
+ }
+
+ function _updatePluginConfig(
+ uint32 donId,
+ Internal.OCRPluginType pluginType,
+ CCIPConfigTypes.OCR3Config[] memory newConfig
+ ) internal {
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = s_ocr3Configs[donId][pluginType];
+
+ // Validate the state transition being proposed, which is implicitly defined by the combination
+ // of lengths of the current and new configurations.
+ CCIPConfigTypes.ConfigState currentState = _stateFromConfigLength(currentConfig.length);
+ CCIPConfigTypes.ConfigState proposedState = _stateFromConfigLength(newConfig.length);
+ _validateConfigStateTransition(currentState, proposedState);
+
+ // Build the new configuration with metadata and validate that the transition is valid.
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfigWithMeta =
+ _computeNewConfigWithMeta(donId, currentConfig, newConfig, currentState, proposedState);
+ _validateConfigTransition(currentConfig, newConfigWithMeta);
+
+ // Update contract state with new configuration if its valid.
+ // We won't run out of gas from this delete since the array is at most 2 elements long.
+ delete s_ocr3Configs[donId][pluginType];
+ for (uint256 i = 0; i < newConfigWithMeta.length; ++i) {
+ s_ocr3Configs[donId][pluginType].push(newConfigWithMeta[i]);
+ }
+ }
+
+ // ================================================================
+ // │ Config State Machine │
+ // ================================================================
+
+ /// @notice Determine the config state of the configuration from the length of the config.
+ /// @param configLen The length of the configuration.
+ /// @return The config state.
+ function _stateFromConfigLength(uint256 configLen) internal pure returns (CCIPConfigTypes.ConfigState) {
+ if (configLen > 2) {
+ revert InvalidConfigLength(configLen);
+ }
+ return CCIPConfigTypes.ConfigState(configLen);
+ }
+
+ // the only valid state transitions are the following:
+ // init -> running (first ever config)
+ // running -> staging (blue/green proposal)
+ // staging -> running (promotion)
+ // everything else is invalid and should revert.
+ function _validateConfigStateTransition(
+ CCIPConfigTypes.ConfigState currentState,
+ CCIPConfigTypes.ConfigState newState
+ ) internal pure {
+ // Calculate the difference between the new state and the current state
+ int256 stateDiff = int256(uint256(newState)) - int256(uint256(currentState));
+
+ // Check if the state transition is valid:
+ // Valid transitions:
+ // 1. currentState -> newState (where stateDiff == 1)
+ // e.g., init -> running or running -> staging
+ // 2. staging -> running (where stateDiff == -1)
+ if (stateDiff == 1 || (stateDiff == -1 && currentState == CCIPConfigTypes.ConfigState.Staging)) {
+ return;
+ }
+ revert InvalidConfigStateTransition(currentState, newState);
+ }
+
+ function _validateConfigTransition(
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig,
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfigWithMeta
+ ) internal pure {
+ uint256 currentConfigLen = currentConfig.length;
+ uint256 newConfigLen = newConfigWithMeta.length;
+ if (currentConfigLen == 0 && newConfigLen == 1) {
+ // Config counts always must start at 1 for the first ever config.
+ if (newConfigWithMeta[0].configCount != 1) {
+ revert WrongConfigCount(newConfigWithMeta[0].configCount, 1);
+ }
+ return;
+ }
+
+ if (currentConfigLen == 1 && newConfigLen == 2) {
+ // On a blue/green proposal:
+ // * the config digest of the blue config must remain unchanged.
+ // * the green config count must be the blue config count + 1.
+ if (newConfigWithMeta[0].configDigest != currentConfig[0].configDigest) {
+ revert WrongConfigDigestBlueGreen(newConfigWithMeta[0].configDigest, currentConfig[0].configDigest);
+ }
+ if (newConfigWithMeta[1].configCount != currentConfig[0].configCount + 1) {
+ revert WrongConfigCount(newConfigWithMeta[1].configCount, currentConfig[0].configCount + 1);
+ }
+ return;
+ }
+
+ if (currentConfigLen == 2 && newConfigLen == 1) {
+ // On a promotion, the green config digest must become the blue config digest.
+ if (newConfigWithMeta[0].configDigest != currentConfig[1].configDigest) {
+ revert WrongConfigDigest(newConfigWithMeta[0].configDigest, currentConfig[1].configDigest);
+ }
+ return;
+ }
+
+ revert NonExistentConfigTransition();
+ }
+
+ /// @notice Computes a new configuration with metadata based on the current configuration and the new configuration.
+ /// @param donId The DON ID.
+ /// @param currentConfig The current configuration, including metadata.
+ /// @param newConfig The new configuration, without metadata.
+ /// @param currentState The current state of the configuration.
+ /// @param newState The new state of the configuration.
+ /// @return The new configuration with metadata.
+ function _computeNewConfigWithMeta(
+ uint32 donId,
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig,
+ CCIPConfigTypes.OCR3Config[] memory newConfig,
+ CCIPConfigTypes.ConfigState currentState,
+ CCIPConfigTypes.ConfigState newState
+ ) internal view returns (CCIPConfigTypes.OCR3ConfigWithMeta[] memory) {
+ uint64[] memory configCounts = new uint64[](newConfig.length);
+
+ // Set config counts based on the only valid state transitions.
+ // Init -> Running (first ever config)
+ // Running -> Staging (blue/green proposal)
+ // Staging -> Running (promotion)
+ if (currentState == CCIPConfigTypes.ConfigState.Init && newState == CCIPConfigTypes.ConfigState.Running) {
+ // First ever config starts with config count == 1.
+ configCounts[0] = 1;
+ } else if (currentState == CCIPConfigTypes.ConfigState.Running && newState == CCIPConfigTypes.ConfigState.Staging) {
+ // On a blue/green proposal, the config count of the green config is the blue config count + 1.
+ configCounts[0] = currentConfig[0].configCount;
+ configCounts[1] = currentConfig[0].configCount + 1;
+ } else if (currentState == CCIPConfigTypes.ConfigState.Staging && newState == CCIPConfigTypes.ConfigState.Running) {
+ // On a promotion, the config count of the green config becomes the blue config count.
+ configCounts[0] = currentConfig[1].configCount;
+ } else {
+ revert InvalidConfigStateTransition(currentState, newState);
+ }
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfigWithMeta =
+ new CCIPConfigTypes.OCR3ConfigWithMeta[](newConfig.length);
+ for (uint256 i = 0; i < configCounts.length; ++i) {
+ _validateConfig(newConfig[i]);
+ newConfigWithMeta[i] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ config: newConfig[i],
+ configCount: configCounts[i],
+ configDigest: _computeConfigDigest(donId, configCounts[i], newConfig[i])
+ });
+ }
+
+ return newConfigWithMeta;
+ }
+
+ /// @notice Group the OCR3 configurations by plugin type for further processing.
+ /// @param ocr3Configs The OCR3 configurations to group.
+ function _groupByPluginType(CCIPConfigTypes.OCR3Config[] memory ocr3Configs)
+ internal
+ pure
+ returns (CCIPConfigTypes.OCR3Config[] memory commitConfigs, CCIPConfigTypes.OCR3Config[] memory execConfigs)
+ {
+ if (ocr3Configs.length > MAX_OCR3_CONFIGS_PER_DON) {
+ revert TooManyOCR3Configs();
+ }
+
+ // Declare with size 2 since we have a maximum of two configs per plugin type (blue, green).
+ // If we have less we will adjust the length later using mstore.
+ // If the caller provides more than 2 configs per plugin type, we will revert due to out of bounds
+ // access in the for loop below.
+ commitConfigs = new CCIPConfigTypes.OCR3Config[](MAX_OCR3_CONFIGS_PER_PLUGIN);
+ execConfigs = new CCIPConfigTypes.OCR3Config[](MAX_OCR3_CONFIGS_PER_PLUGIN);
+ uint256 commitCount;
+ uint256 execCount;
+ for (uint256 i = 0; i < ocr3Configs.length; ++i) {
+ if (ocr3Configs[i].pluginType == Internal.OCRPluginType.Commit) {
+ commitConfigs[commitCount] = ocr3Configs[i];
+ ++commitCount;
+ } else {
+ execConfigs[execCount] = ocr3Configs[i];
+ ++execCount;
+ }
+ }
+
+ // Adjust the length of the arrays to the actual number of configs.
+ assembly {
+ mstore(commitConfigs, commitCount)
+ mstore(execConfigs, execCount)
+ }
+
+ return (commitConfigs, execConfigs);
+ }
+
+ function _validateConfig(CCIPConfigTypes.OCR3Config memory cfg) internal view {
+ if (cfg.chainSelector == 0) revert ChainSelectorNotSet();
+ if (cfg.pluginType != Internal.OCRPluginType.Commit && cfg.pluginType != Internal.OCRPluginType.Execution) {
+ revert InvalidPluginType();
+ }
+ // TODO: can we do more sophisticated validation than this?
+ if (cfg.offrampAddress.length == 0) revert OfframpAddressCannotBeZero();
+ if (!s_remoteChainSelectors.contains(cfg.chainSelector)) revert ChainSelectorNotFound(cfg.chainSelector);
+
+ // Some of these checks below are done in OCR2/3Base config validation, so we do them again here.
+ // Role DON OCR configs will have all the Role DON signers but only a subset of transmitters.
+ if (cfg.signers.length > MAX_NUM_ORACLES) revert TooManySigners();
+ if (cfg.transmitters.length > MAX_NUM_ORACLES) revert TooManyTransmitters();
+
+ // We check for chain config presence above, so fChain here must be non-zero.
+ uint256 minTransmittersLength = 3 * s_chainConfigurations[cfg.chainSelector].fChain + 1;
+ if (cfg.transmitters.length < minTransmittersLength) {
+ revert NotEnoughTransmitters(cfg.transmitters.length, minTransmittersLength);
+ }
+ if (cfg.F == 0) revert FMustBePositive();
+ if (cfg.signers.length <= 3 * cfg.F) revert FTooHigh();
+
+ if (cfg.p2pIds.length != cfg.signers.length || cfg.p2pIds.length != cfg.transmitters.length) {
+ revert P2PIdsLengthNotMatching(cfg.p2pIds.length, cfg.signers.length, cfg.transmitters.length);
+ }
+ if (cfg.bootstrapP2PIds.length > cfg.p2pIds.length) revert TooManyBootstrapP2PIds();
+
+ // check for duplicate p2p ids and bootstrapP2PIds.
+ // check that p2p ids in cfg.bootstrapP2PIds are included in cfg.p2pIds.
+ SortedSetValidationUtil._checkIsValidUniqueSubset(cfg.bootstrapP2PIds, cfg.p2pIds);
+
+ // Check that the readers are in the capabilities registry.
+ for (uint256 i = 0; i < cfg.signers.length; ++i) {
+ _ensureInRegistry(cfg.p2pIds[i]);
+ }
+ }
+
+ /// @notice Computes the digest of the provided configuration.
+ /// @dev In traditional OCR config digest computation, block.chainid and address(this) are used
+ /// in order to further domain separate the digest. We can't do that here since the digest will
+ /// be used on remote chains; so we use the chain selector instead of block.chainid. The don ID
+ /// replaces the address(this) in the traditional computation.
+ /// @param donId The DON ID.
+ /// @param configCount The configuration count.
+ /// @param ocr3Config The OCR3 configuration.
+ /// @return The computed digest.
+ function _computeConfigDigest(
+ uint32 donId,
+ uint64 configCount,
+ CCIPConfigTypes.OCR3Config memory ocr3Config
+ ) internal pure returns (bytes32) {
+ uint256 h = uint256(
+ keccak256(
+ abi.encode(
+ ocr3Config.chainSelector,
+ donId,
+ ocr3Config.pluginType,
+ ocr3Config.offrampAddress,
+ configCount,
+ ocr3Config.bootstrapP2PIds,
+ ocr3Config.p2pIds,
+ ocr3Config.signers,
+ ocr3Config.transmitters,
+ ocr3Config.F,
+ ocr3Config.offchainConfigVersion,
+ ocr3Config.offchainConfig
+ )
+ )
+ );
+ uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00
+ uint256 prefix = 0x000a << (256 - 16); // 0x000a00..00
+ return bytes32((prefix & prefixMask) | (h & ~prefixMask));
+ }
+
+ // ================================================================
+ // │ Chain Configuration │
+ // ================================================================
+
+ /// @notice Sets and/or removes chain configurations.
+ /// @param chainSelectorRemoves The chain configurations to remove.
+ /// @param chainConfigAdds The chain configurations to add.
+ function applyChainConfigUpdates(
+ uint64[] calldata chainSelectorRemoves,
+ CCIPConfigTypes.ChainConfigInfo[] calldata chainConfigAdds
+ ) external onlyOwner {
+ // Process removals first.
+ for (uint256 i = 0; i < chainSelectorRemoves.length; ++i) {
+ // check if the chain selector is in s_remoteChainSelectors first.
+ if (!s_remoteChainSelectors.contains(chainSelectorRemoves[i])) {
+ revert ChainSelectorNotFound(chainSelectorRemoves[i]);
+ }
+
+ delete s_chainConfigurations[chainSelectorRemoves[i]];
+ s_remoteChainSelectors.remove(chainSelectorRemoves[i]);
+
+ emit ChainConfigRemoved(chainSelectorRemoves[i]);
+ }
+
+ // Process additions next.
+ for (uint256 i = 0; i < chainConfigAdds.length; ++i) {
+ CCIPConfigTypes.ChainConfig memory chainConfig = chainConfigAdds[i].chainConfig;
+ bytes32[] memory readers = chainConfig.readers;
+ uint64 chainSelector = chainConfigAdds[i].chainSelector;
+
+ // Verify that the provided readers are present in the capabilities registry.
+ for (uint256 j = 0; j < readers.length; j++) {
+ _ensureInRegistry(readers[j]);
+ }
+
+ // Verify that fChain is positive.
+ if (chainConfig.fChain == 0) {
+ revert FChainMustBePositive();
+ }
+
+ s_chainConfigurations[chainSelector] = chainConfig;
+ s_remoteChainSelectors.add(chainSelector);
+
+ emit ChainConfigSet(chainSelector, chainConfig);
+ }
+ }
+
+ /// @notice Helper function to ensure that a node is in the capabilities registry.
+ /// @param p2pId The P2P ID of the node to check.
+ function _ensureInRegistry(bytes32 p2pId) internal view {
+ ICapabilitiesRegistry.NodeInfo memory node = ICapabilitiesRegistry(i_capabilitiesRegistry).getNode(p2pId);
+ if (node.p2pId == bytes32("")) {
+ revert NodeNotInRegistry(p2pId);
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/capability/interfaces/ICapabilitiesRegistry.sol b/contracts/src/v0.8/ccip/capability/interfaces/ICapabilitiesRegistry.sol
new file mode 100644
index 00000000000..621c3686cfa
--- /dev/null
+++ b/contracts/src/v0.8/ccip/capability/interfaces/ICapabilitiesRegistry.sol
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.24;
+
+interface ICapabilitiesRegistry {
+ struct NodeInfo {
+ /// @notice The id of the node operator that manages this node
+ uint32 nodeOperatorId;
+ /// @notice The number of times the node's configuration has been updated
+ uint32 configCount;
+ /// @notice The ID of the Workflow DON that the node belongs to. A node can
+ /// only belong to one DON that accepts Workflows.
+ uint32 workflowDONId;
+ /// @notice The signer address for application-layer message verification.
+ bytes32 signer;
+ /// @notice This is an Ed25519 public key that is used to identify a node.
+ /// This key is guaranteed to be unique in the CapabilitiesRegistry. It is
+ /// used to identify a node in the the P2P network.
+ bytes32 p2pId;
+ /// @notice The list of hashed capability IDs supported by the node
+ bytes32[] hashedCapabilityIds;
+ /// @notice The list of capabilities DON Ids supported by the node. A node
+ /// can belong to multiple capabilities DONs. This list does not include a
+ /// Workflow DON id if the node belongs to one.
+ uint256[] capabilitiesDONIds;
+ }
+
+ /// @notice Gets a node's data
+ /// @param p2pId The P2P ID of the node to query for
+ /// @return NodeInfo The node data
+ function getNode(bytes32 p2pId) external view returns (NodeInfo memory);
+}
diff --git a/contracts/src/v0.8/ccip/capability/interfaces/IOCR3ConfigEncoder.sol b/contracts/src/v0.8/ccip/capability/interfaces/IOCR3ConfigEncoder.sol
new file mode 100644
index 00000000000..6d0b0f72a5a
--- /dev/null
+++ b/contracts/src/v0.8/ccip/capability/interfaces/IOCR3ConfigEncoder.sol
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {CCIPConfigTypes} from "../libraries/CCIPConfigTypes.sol";
+
+/// @dev This is so that we can generate gethwrappers and easily encode/decode OCR3Config
+/// in the offchain integration tests.
+interface IOCR3ConfigEncoder {
+ /// @dev Encodes an array of OCR3Config into a bytes array. For test usage only.
+ function exposeOCR3Config(CCIPConfigTypes.OCR3Config[] calldata config) external view returns (bytes memory);
+}
diff --git a/contracts/src/v0.8/ccip/capability/libraries/CCIPConfigTypes.sol b/contracts/src/v0.8/ccip/capability/libraries/CCIPConfigTypes.sol
new file mode 100644
index 00000000000..99adef84b10
--- /dev/null
+++ b/contracts/src/v0.8/ccip/capability/libraries/CCIPConfigTypes.sol
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {Internal} from "../../libraries/Internal.sol";
+
+library CCIPConfigTypes {
+ /// @notice ConfigState indicates the state of the configuration.
+ /// A DON's configuration always starts out in the "Init" state - this is the starting state.
+ /// The only valid transition from "Init" is to the "Running" state - this is the first ever configuration.
+ /// The only valid transition from "Running" is to the "Staging" state - this is a blue/green proposal.
+ /// The only valid transition from "Staging" is back to the "Running" state - this is a promotion.
+ /// TODO: explain rollbacks?
+ enum ConfigState {
+ Init,
+ Running,
+ Staging
+ }
+
+ /// @notice Chain configuration.
+ /// Changes to chain configuration are detected out-of-band in plugins and decoded offchain.
+ struct ChainConfig {
+ bytes32[] readers; // The P2P IDs of the readers for the chain. These IDs must be registered in the capabilities registry.
+ uint8 fChain; // The fault tolerance parameter of the chain.
+ bytes config; // The chain configuration. This is kept intentionally opaque so as to add fields in the future if needed.
+ }
+
+ /// @notice Chain configuration information struct used in applyChainConfigUpdates and getAllChainConfigs.
+ struct ChainConfigInfo {
+ uint64 chainSelector;
+ ChainConfig chainConfig;
+ }
+
+ /// @notice OCR3 configuration.
+ struct OCR3Config {
+ Internal.OCRPluginType pluginType; // ────────╮ The plugin that the configuration is for.
+ uint64 chainSelector; // | The (remote) chain that the configuration is for.
+ uint8 F; // | The "big F" parameter for the role DON.
+ uint64 offchainConfigVersion; // ─────────────╯ The version of the offchain configuration.
+ bytes offrampAddress; // The remote chain offramp address.
+ // NOTE: bootstrapP2PIds and p2pIds should be sent as sorted sets
+ bytes32[] bootstrapP2PIds; // The bootstrap P2P IDs of the oracles that are part of the role DON.
+ // len(p2pIds) == len(signers) == len(transmitters) == 3 * F + 1
+ // NOTE: indexes matter here! The p2p ID at index i corresponds to the signer at index i and the transmitter at index i.
+ // This is crucial in order to build the oracle ID <-> peer ID mapping offchain.
+ bytes32[] p2pIds; // The P2P IDs of the oracles that are part of the role DON.
+ bytes[] signers; // The onchain signing keys of nodes in the don.
+ bytes[] transmitters; // The onchain transmitter keys of nodes in the don.
+ bytes offchainConfig; // The offchain configuration for the OCR3 protocol. Protobuf encoded.
+ }
+
+ /// @notice OCR3 configuration with metadata, specifically the config count and the config digest.
+ struct OCR3ConfigWithMeta {
+ OCR3Config config; // The OCR3 configuration.
+ uint64 configCount; // The config count used to compute the config digest.
+ bytes32 configDigest; // The config digest of the OCR3 configuration.
+ }
+}
diff --git a/contracts/src/v0.8/ccip/docs/multi-chain-overview-ocr3.png b/contracts/src/v0.8/ccip/docs/multi-chain-overview-ocr3.png
new file mode 100644
index 00000000000..39302619cb4
Binary files /dev/null and b/contracts/src/v0.8/ccip/docs/multi-chain-overview-ocr3.png differ
diff --git a/contracts/src/v0.8/ccip/docs/multi-chain-overview.drawio b/contracts/src/v0.8/ccip/docs/multi-chain-overview.drawio
new file mode 100644
index 00000000000..5743bf5182e
--- /dev/null
+++ b/contracts/src/v0.8/ccip/docs/multi-chain-overview.drawio
@@ -0,0 +1,2060 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contracts/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol b/contracts/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol
new file mode 100644
index 00000000000..6305311050d
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IAny2EVMMessageReceiver.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Client} from "../libraries/Client.sol";
+
+/// @notice Application contracts that intend to receive messages from
+/// the router should implement this interface.
+interface IAny2EVMMessageReceiver {
+ /// @notice Called by the Router to deliver a message.
+ /// If this reverts, any token transfers also revert. The message
+ /// will move to a FAILED state and become available for manual execution.
+ /// @param message CCIP Message
+ /// @dev Note ensure you check the msg.sender is the OffRampRouter
+ function ccipReceive(Client.Any2EVMMessage calldata message) external;
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IAny2EVMOffRamp.sol b/contracts/src/v0.8/ccip/interfaces/IAny2EVMOffRamp.sol
new file mode 100644
index 00000000000..1881dede2ee
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IAny2EVMOffRamp.sol
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+interface IAny2EVMOffRamp {
+ /// @notice Returns the the current nonce for a receiver.
+ /// @param sender The sender address
+ /// @return nonce The nonce value belonging to the sender address.
+ function getSenderNonce(address sender) external view returns (uint64 nonce);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/ICommitStore.sol b/contracts/src/v0.8/ccip/interfaces/ICommitStore.sol
new file mode 100644
index 00000000000..1183eb277b8
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/ICommitStore.sol
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+interface ICommitStore {
+ /// @notice Returns timestamp of when root was accepted or 0 if verification fails.
+ /// @dev This method uses a merkle tree within a merkle tree, with the hashedLeaves,
+ /// proofs and proofFlagBits being used to get the root of the inner tree.
+ /// This root is then used as the singular leaf of the outer tree.
+ function verify(
+ bytes32[] calldata hashedLeaves,
+ bytes32[] calldata proofs,
+ uint256 proofFlagBits
+ ) external view returns (uint256 timestamp);
+
+ /// @notice Returns the expected next sequence number
+ function getExpectedNextSequenceNumber() external view returns (uint64 sequenceNumber);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRamp.sol b/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRamp.sol
new file mode 100644
index 00000000000..d657e148cb2
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRamp.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {IEVM2AnyOnRampClient} from "./IEVM2AnyOnRampClient.sol";
+
+interface IEVM2AnyOnRamp is IEVM2AnyOnRampClient {
+ /// @notice Gets the next sequence number to be used in the onRamp
+ /// @return the next sequence number to be used
+ function getExpectedNextSequenceNumber() external view returns (uint64);
+
+ /// @notice Get the next nonce for a given sender
+ /// @param sender The sender to get the nonce for
+ /// @return nonce The next nonce for the sender
+ function getSenderNonce(address sender) external view returns (uint64 nonce);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRampClient.sol b/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRampClient.sol
new file mode 100644
index 00000000000..1744d6c2295
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRampClient.sol
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {IPoolV1} from "./IPool.sol";
+
+import {Client} from "../libraries/Client.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+interface IEVM2AnyOnRampClient {
+ /// @notice Get the fee for a given ccip message
+ /// @param destChainSelector The destination chain selector
+ /// @param message The message to calculate the cost for
+ /// @return fee The calculated fee
+ function getFee(uint64 destChainSelector, Client.EVM2AnyMessage calldata message) external view returns (uint256 fee);
+
+ /// @notice Get the pool for a specific token
+ /// @param destChainSelector The destination chain selector
+ /// @param sourceToken The source chain token to get the pool for
+ /// @return pool Token pool
+ function getPoolBySourceToken(uint64 destChainSelector, IERC20 sourceToken) external view returns (IPoolV1);
+
+ /// @notice Gets a list of all supported source chain tokens.
+ /// @param destChainSelector The destination chain selector
+ /// @return tokens The addresses of all tokens that this onRamp supports the given destination chain
+ function getSupportedTokens(uint64 destChainSelector) external view returns (address[] memory tokens);
+
+ /// @notice Send a message to the remote chain
+ /// @dev only callable by the Router
+ /// @dev approve() must have already been called on the token using the this ramp address as the spender.
+ /// @dev if the contract is paused, this function will revert.
+ /// @param destChainSelector The destination chain selector
+ /// @param message Message struct to send
+ /// @param feeTokenAmount Amount of fee tokens for payment
+ /// @param originalSender The original initiator of the CCIP request
+ function forwardFromRouter(
+ uint64 destChainSelector,
+ Client.EVM2AnyMessage memory message,
+ uint256 feeTokenAmount,
+ address originalSender
+ ) external returns (bytes32);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IGetCCIPAdmin.sol b/contracts/src/v0.8/ccip/interfaces/IGetCCIPAdmin.sol
new file mode 100644
index 00000000000..d83a1f34e89
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IGetCCIPAdmin.sol
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+interface IGetCCIPAdmin {
+ /// @notice Returns the admin of the token.
+ /// @dev This method is named to never conflict with existing methods.
+ function getCCIPAdmin() external view returns (address);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IMessageInterceptor.sol b/contracts/src/v0.8/ccip/interfaces/IMessageInterceptor.sol
new file mode 100644
index 00000000000..c2b432426b6
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IMessageInterceptor.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Client} from "../libraries/Client.sol";
+
+/// @notice Interface for plug-in message hook contracts that intercept OffRamp & OnRamp messages
+/// and perform validations / state changes on top of the messages. The interceptor functions are expected to
+/// revert on validation failures.
+interface IMessageInterceptor {
+ /// @notice Common error that can be thrown on validation failures and used by consumers
+ /// @param errorReason abi encoded revert reason
+ error MessageValidationError(bytes errorReason);
+
+ /// @notice Intercepts & validates the given OffRamp message. Reverts on validation failure
+ /// @param message to validate
+ function onInboundMessage(Client.Any2EVMMessage memory message) external;
+
+ /// @notice Intercepts & validates the given OnRamp message. Reverts on validation failure
+ /// @param destChainSelector remote destination chain selector where the message is being sent to
+ /// @param message to validate
+ function onOutboundMessage(uint64 destChainSelector, Client.EVM2AnyMessage memory message) external;
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/INonceManager.sol b/contracts/src/v0.8/ccip/interfaces/INonceManager.sol
new file mode 100644
index 00000000000..52408ae4f57
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/INonceManager.sol
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+/// @notice Contract interface that allows managing sender nonces
+interface INonceManager {
+ /// @notice Increments the outbound nonce for a given sender on a given destination chain
+ /// @param destChainSelector The destination chain selector
+ /// @param sender The sender address
+ /// @return The new outbound nonce
+ function getIncrementedOutboundNonce(uint64 destChainSelector, address sender) external returns (uint64);
+
+ /// @notice Increments the inbound nonce for a given sender on a given source chain
+ /// @notice The increment is only applied if the resulting nonce matches the expectedNonce
+ /// @param sourceChainSelector The destination chain selector
+ /// @param expectedNonce The expected inbound nonce
+ /// @param sender The encoded sender address
+ /// @return True if the nonce was incremented, false otherwise
+ function incrementInboundNonce(
+ uint64 sourceChainSelector,
+ uint64 expectedNonce,
+ bytes calldata sender
+ ) external returns (bool);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IOwner.sol b/contracts/src/v0.8/ccip/interfaces/IOwner.sol
new file mode 100644
index 00000000000..ccb1039e555
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IOwner.sol
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+interface IOwner {
+ /// @notice Returns the owner of the contract.
+ /// @dev This method is named to match with the OpenZeppelin Ownable contract.
+ function owner() external view returns (address);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IPool.sol b/contracts/src/v0.8/ccip/interfaces/IPool.sol
new file mode 100644
index 00000000000..5d5c95e03c7
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IPool.sol
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Pool} from "../libraries/Pool.sol";
+
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+
+/// @notice Shared public interface for multiple V1 pool types.
+/// Each pool type handles a different child token model (lock/unlock, mint/burn.)
+interface IPoolV1 is IERC165 {
+ /// @notice Lock tokens into the pool or burn the tokens.
+ /// @param lockOrBurnIn Encoded data fields for the processing of tokens on the source chain.
+ /// @return lockOrBurnOut Encoded data fields for the processing of tokens on the destination chain.
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ returns (Pool.LockOrBurnOutV1 memory lockOrBurnOut);
+
+ /// @notice Releases or mints tokens to the receiver address.
+ /// @param releaseOrMintIn All data required to release or mint tokens.
+ /// @return releaseOrMintOut The amount of tokens released or minted on the local chain, denominated
+ /// in the local token's decimals.
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ returns (Pool.ReleaseOrMintOutV1 memory);
+
+ /// @notice Checks whether a remote chain is supported in the token pool.
+ /// @param remoteChainSelector The selector of the remote chain.
+ /// @return true if the given chain is a permissioned remote chain.
+ function isSupportedChain(uint64 remoteChainSelector) external view returns (bool);
+
+ /// @notice Returns if the token pool supports the given token.
+ /// @param token The address of the token.
+ /// @return true if the token is supported by the pool.
+ function isSupportedToken(address token) external view returns (bool);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IPoolPriorTo1_5.sol b/contracts/src/v0.8/ccip/interfaces/IPoolPriorTo1_5.sol
new file mode 100644
index 00000000000..d8a2f15fd29
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IPoolPriorTo1_5.sol
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+// Shared public interface for multiple pool types.
+// Each pool type handles a different child token model (lock/unlock, mint/burn.)
+interface IPoolPriorTo1_5 {
+ /// @notice Lock tokens into the pool or burn the tokens.
+ /// @param originalSender Original sender of the tokens.
+ /// @param receiver Receiver of the tokens on destination chain.
+ /// @param amount Amount to lock or burn.
+ /// @param remoteChainSelector Destination chain Id.
+ /// @param extraArgs Additional data passed in by sender for lockOrBurn processing
+ /// in custom pools on source chain.
+ /// @return retData Optional field that contains bytes. Unused for now but already
+ /// implemented to allow future upgrades while preserving the interface.
+ function lockOrBurn(
+ address originalSender,
+ bytes calldata receiver,
+ uint256 amount,
+ uint64 remoteChainSelector,
+ bytes calldata extraArgs
+ ) external returns (bytes memory);
+
+ /// @notice Releases or mints tokens to the receiver address.
+ /// @param originalSender Original sender of the tokens.
+ /// @param receiver Receiver of the tokens.
+ /// @param amount Amount to release or mint.
+ /// @param remoteChainSelector Source chain Id.
+ /// @param extraData Additional data supplied offchain for releaseOrMint processing in
+ /// custom pools on dest chain. This could be an attestation that was retrieved through a
+ /// third party API.
+ /// @dev offchainData can come from any untrusted source.
+ function releaseOrMint(
+ bytes memory originalSender,
+ address receiver,
+ uint256 amount,
+ uint64 remoteChainSelector,
+ bytes memory extraData
+ ) external;
+
+ /// @notice Gets the IERC20 token that this pool can lock or burn.
+ /// @return token The IERC20 token representation.
+ function getToken() external view returns (IERC20 token);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IPriceRegistry.sol b/contracts/src/v0.8/ccip/interfaces/IPriceRegistry.sol
new file mode 100644
index 00000000000..8a20299371f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IPriceRegistry.sol
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Client} from "../libraries/Client.sol";
+import {Internal} from "../libraries/Internal.sol";
+
+interface IPriceRegistry {
+ /// @notice Token price data feed configuration
+ struct TokenPriceFeedConfig {
+ address dataFeedAddress; // ──╮ AggregatorV3Interface contract (0 - feed is unset)
+ uint8 tokenDecimals; // ──────╯ Decimals of the token that the feed represents
+ }
+
+ /// @notice Update the price for given tokens and gas prices for given chains.
+ /// @param priceUpdates The price updates to apply.
+ function updatePrices(Internal.PriceUpdates memory priceUpdates) external;
+
+ /// @notice Get the `tokenPrice` for a given token.
+ /// @param token The token to get the price for.
+ /// @return tokenPrice The tokenPrice for the given token.
+ function getTokenPrice(address token) external view returns (Internal.TimestampedPackedUint224 memory);
+
+ /// @notice Get the `tokenPrice` for a given token, checks if the price is valid.
+ /// @param token The token to get the price for.
+ /// @return tokenPrice The tokenPrice for the given token if it exists and is valid.
+ function getValidatedTokenPrice(address token) external view returns (uint224);
+
+ /// @notice Get the `tokenPrice` for an array of tokens.
+ /// @param tokens The tokens to get prices for.
+ /// @return tokenPrices The tokenPrices for the given tokens.
+ function getTokenPrices(address[] calldata tokens) external view returns (Internal.TimestampedPackedUint224[] memory);
+
+ /// @notice Returns the token price data feed configuration
+ /// @param token The token to retrieve the feed config for
+ /// @return dataFeedAddress The token price data feed config (if feed address is 0, the feed config is disabled)
+ function getTokenPriceFeedConfig(address token) external view returns (TokenPriceFeedConfig memory);
+
+ /// @notice Get an encoded `gasPrice` for a given destination chain ID.
+ /// The 224-bit result encodes necessary gas price components.
+ /// On L1 chains like Ethereum or Avax, the only component is the gas price.
+ /// On Optimistic Rollups, there are two components - the L2 gas price, and L1 base fee for data availability.
+ /// On future chains, there could be more or differing price components.
+ /// PriceRegistry does not contain chain-specific logic to parse destination chain price components.
+ /// @param destChainSelector The destination chain to get the price for.
+ /// @return gasPrice The encoded gasPrice for the given destination chain ID.
+ function getDestinationChainGasPrice(uint64 destChainSelector)
+ external
+ view
+ returns (Internal.TimestampedPackedUint224 memory);
+
+ /// @notice Gets the fee token price and the gas price, both denominated in dollars.
+ /// @param token The source token to get the price for.
+ /// @param destChainSelector The destination chain to get the gas price for.
+ /// @return tokenPrice The price of the feeToken in 1e18 dollars per base unit.
+ /// @return gasPrice The price of gas in 1e18 dollars per base unit.
+ function getTokenAndGasPrices(
+ address token,
+ uint64 destChainSelector
+ ) external view returns (uint224 tokenPrice, uint224 gasPrice);
+
+ /// @notice Convert a given token amount to target token amount.
+ /// @param fromToken The given token address.
+ /// @param fromTokenAmount The given token amount.
+ /// @param toToken The target token address.
+ /// @return toTokenAmount The target token amount.
+ function convertTokenAmount(
+ address fromToken,
+ uint256 fromTokenAmount,
+ address toToken
+ ) external view returns (uint256 toTokenAmount);
+
+ /// @notice Get the list of fee tokens.
+ /// @return The tokens set as fee tokens.
+ function getFeeTokens() external view returns (address[] memory);
+
+ /// @notice Validates the ccip message & returns the fee
+ /// @param destChainSelector The destination chain selector.
+ /// @param message The message to get quote for.
+ /// @return feeTokenAmount The amount of fee token needed for the fee, in smallest denomination of the fee token.
+ function getValidatedFee(
+ uint64 destChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external view returns (uint256 feeTokenAmount);
+
+ /// @notice Converts the extraArgs to the latest version and returns the converted message fee in juels
+ /// @param destChainSelector destination chain selector to process
+ /// @param feeToken Fee token address used to pay for message fees
+ /// @param feeTokenAmount Fee token amount
+ /// @param extraArgs Message extra args that were passed in by the client
+ /// @return msgFeeJuels message fee in juels
+ /// @return isOutOfOrderExecution true if the message should be executed out of order
+ /// @return convertedExtraArgs extra args converted to the latest family-specific args version
+ function processMessageArgs(
+ uint64 destChainSelector,
+ address feeToken,
+ uint256 feeTokenAmount,
+ bytes memory extraArgs
+ ) external view returns (uint256 msgFeeJuels, bool isOutOfOrderExecution, bytes memory convertedExtraArgs);
+
+ /// @notice Validates pool return data
+ /// @param destChainSelector Destination chain selector to which the token amounts are sent to
+ /// @param rampTokenAmounts Token amounts with populated pool return data
+ /// @param sourceTokenAmounts Token amounts originally sent in a Client.EVM2AnyMessage message
+ function validatePoolReturnData(
+ uint64 destChainSelector,
+ Internal.RampTokenAmount[] calldata rampTokenAmounts,
+ Client.EVMTokenAmount[] calldata sourceTokenAmounts
+ ) external view;
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IRMN.sol b/contracts/src/v0.8/ccip/interfaces/IRMN.sol
new file mode 100644
index 00000000000..a409731549f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IRMN.sol
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+/// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts.
+interface IRMN {
+ /// @notice A Merkle root tagged with the address of the commit store contract it is destined for.
+ struct TaggedRoot {
+ address commitStore;
+ bytes32 root;
+ }
+
+ /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed.
+ function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool);
+
+ /// @notice Iff there is an active global or legacy curse, this function returns true.
+ function isCursed() external view returns (bool);
+
+ /// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true.
+ /// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)).
+ function isCursed(bytes16 subject) external view returns (bool);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IRouter.sol b/contracts/src/v0.8/ccip/interfaces/IRouter.sol
new file mode 100644
index 00000000000..7f4544fd0fa
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IRouter.sol
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Client} from "../libraries/Client.sol";
+
+interface IRouter {
+ error OnlyOffRamp();
+
+ /// @notice Route the message to its intended receiver contract.
+ /// @param message Client.Any2EVMMessage struct.
+ /// @param gasForCallExactCheck of params for exec
+ /// @param gasLimit set of params for exec
+ /// @param receiver set of params for exec
+ /// @dev if the receiver is a contracts that signals support for CCIP execution through EIP-165.
+ /// the contract is called. If not, only tokens are transferred.
+ /// @return success A boolean value indicating whether the ccip message was received without errors.
+ /// @return retBytes A bytes array containing return data form CCIP receiver.
+ /// @return gasUsed the gas used by the external customer call. Does not include any overhead.
+ function routeMessage(
+ Client.Any2EVMMessage calldata message,
+ uint16 gasForCallExactCheck,
+ uint256 gasLimit,
+ address receiver
+ ) external returns (bool success, bytes memory retBytes, uint256 gasUsed);
+
+ /// @notice Returns the configured onramp for a specific destination chain.
+ /// @param destChainSelector The destination chain Id to get the onRamp for.
+ /// @return onRampAddress The address of the onRamp.
+ function getOnRamp(uint64 destChainSelector) external view returns (address onRampAddress);
+
+ /// @notice Return true if the given offRamp is a configured offRamp for the given source chain.
+ /// @param sourceChainSelector The source chain selector to check.
+ /// @param offRamp The address of the offRamp to check.
+ function isOffRamp(uint64 sourceChainSelector, address offRamp) external view returns (bool isOffRamp);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IRouterClient.sol b/contracts/src/v0.8/ccip/interfaces/IRouterClient.sol
new file mode 100644
index 00000000000..9805a41bbdc
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/IRouterClient.sol
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Client} from "../libraries/Client.sol";
+
+interface IRouterClient {
+ error UnsupportedDestinationChain(uint64 destChainSelector);
+ error InsufficientFeeTokenAmount();
+ error InvalidMsgValue();
+
+ /// @notice Checks if the given chain ID is supported for sending/receiving.
+ /// @param destChainSelector The chain to check.
+ /// @return supported is true if it is supported, false if not.
+ function isChainSupported(uint64 destChainSelector) external view returns (bool supported);
+
+ /// @param destinationChainSelector The destination chainSelector
+ /// @param message The cross-chain CCIP message including data and/or tokens
+ /// @return fee returns execution fee for the message
+ /// delivery to destination chain, denominated in the feeToken specified in the message.
+ /// @dev Reverts with appropriate reason upon invalid message.
+ function getFee(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage memory message
+ ) external view returns (uint256 fee);
+
+ /// @notice Request a message to be sent to the destination chain
+ /// @param destinationChainSelector The destination chain ID
+ /// @param message The cross-chain CCIP message including data and/or tokens
+ /// @return messageId The message ID
+ /// @dev Note if msg.value is larger than the required fee (from getFee) we accept
+ /// the overpayment with no refund.
+ /// @dev Reverts with appropriate reason upon invalid message.
+ function ccipSend(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external payable returns (bytes32);
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/ITokenAdminRegistry.sol b/contracts/src/v0.8/ccip/interfaces/ITokenAdminRegistry.sol
new file mode 100644
index 00000000000..0e441229011
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/ITokenAdminRegistry.sol
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+interface ITokenAdminRegistry {
+ /// @notice Returns the pool for the given token.
+ function getPool(address token) external view returns (address);
+
+ /// @notice Proposes an administrator for the given token as pending administrator.
+ /// @param localToken The token to register the administrator for.
+ /// @param administrator The administrator to register.
+ function proposeAdministrator(address localToken, address administrator) external;
+}
diff --git a/contracts/src/v0.8/ccip/interfaces/IWrappedNative.sol b/contracts/src/v0.8/ccip/interfaces/IWrappedNative.sol
new file mode 100644
index 00000000000..4225827a612
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/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/ccip/interfaces/automation/ILinkAvailable.sol b/contracts/src/v0.8/ccip/interfaces/automation/ILinkAvailable.sol
new file mode 100644
index 00000000000..b0dad9a5e70
--- /dev/null
+++ b/contracts/src/v0.8/ccip/interfaces/automation/ILinkAvailable.sol
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+/// @notice Implement this contract so that a keeper-compatible contract can monitor
+/// and fund the implementation contract with LINK if it falls below a defined threshold.
+interface ILinkAvailable {
+ function linkAvailableForPayment() external view returns (int256 availableBalance);
+}
diff --git a/contracts/src/v0.8/ccip/libraries/Client.sol b/contracts/src/v0.8/ccip/libraries/Client.sol
new file mode 100644
index 00000000000..a985371bef1
--- /dev/null
+++ b/contracts/src/v0.8/ccip/libraries/Client.sol
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+// End consumer library.
+library Client {
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct EVMTokenAmount {
+ address token; // token address on the local chain.
+ uint256 amount; // Amount of tokens.
+ }
+
+ struct Any2EVMMessage {
+ bytes32 messageId; // MessageId corresponding to ccipSend on source.
+ uint64 sourceChainSelector; // Source chain selector.
+ bytes sender; // abi.decode(sender) if coming from an EVM chain.
+ bytes data; // payload sent in original message.
+ EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.
+ }
+
+ // If extraArgs is empty bytes, the default is 200k gas limit.
+ struct EVM2AnyMessage {
+ bytes receiver; // abi.encode(receiver address) for dest EVM chains
+ bytes data; // Data payload
+ EVMTokenAmount[] tokenAmounts; // Token transfers
+ address feeToken; // Address of feeToken. address(0) means you will send msg.value.
+ bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2)
+ }
+
+ // bytes4(keccak256("CCIP EVMExtraArgsV1"));
+ bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;
+
+ struct EVMExtraArgsV1 {
+ uint256 gasLimit;
+ }
+
+ function _argsToBytes(EVMExtraArgsV1 memory extraArgs) internal pure returns (bytes memory bts) {
+ return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);
+ }
+
+ // bytes4(keccak256("CCIP EVMExtraArgsV2"));
+ bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10;
+
+ /// @param gasLimit: gas limit for the callback on the destination chain.
+ /// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to other messages from the same sender.
+ /// This value's default varies by chain. On some chains, a particular value is enforced, meaning if the expected value
+ /// is not set, the message request will revert.
+ struct EVMExtraArgsV2 {
+ uint256 gasLimit;
+ bool allowOutOfOrderExecution;
+ }
+
+ function _argsToBytes(EVMExtraArgsV2 memory extraArgs) internal pure returns (bytes memory bts) {
+ return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/libraries/Internal.sol b/contracts/src/v0.8/ccip/libraries/Internal.sol
new file mode 100644
index 00000000000..db2bc05ee53
--- /dev/null
+++ b/contracts/src/v0.8/ccip/libraries/Internal.sol
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
+import {Client} from "./Client.sol";
+
+// Library for CCIP internal definitions common to multiple contracts.
+library Internal {
+ error InvalidEVMAddress(bytes encodedAddress);
+
+ /// @dev The minimum amount of gas to perform the call with exact gas.
+ /// We include this in the offramp so that we can redeploy to adjust it
+ /// should a hardfork change the gas costs of relevant opcodes in callWithExactGas.
+ uint16 internal constant GAS_FOR_CALL_EXACT_CHECK = 5_000;
+ // @dev We limit return data to a selector plus 4 words. This is to avoid
+ // malicious contracts from returning large amounts of data and causing
+ // repeated out-of-gas scenarios.
+ uint16 internal constant MAX_RET_BYTES = 4 + 4 * 32;
+
+ /// @notice A collection of token price and gas price updates.
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct PriceUpdates {
+ TokenPriceUpdate[] tokenPriceUpdates;
+ GasPriceUpdate[] gasPriceUpdates;
+ }
+
+ /// @notice Token price in USD.
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct TokenPriceUpdate {
+ address sourceToken; // Source token
+ uint224 usdPerToken; // 1e18 USD per 1e18 of the smallest token denomination.
+ }
+
+ /// @notice Gas price for a given chain in USD, its value may contain tightly packed fields.
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct GasPriceUpdate {
+ uint64 destChainSelector; // Destination chain selector
+ uint224 usdPerUnitGas; // 1e18 USD per smallest unit (e.g. wei) of destination chain gas
+ }
+
+ /// @notice A timestamped uint224 value that can contain several tightly packed fields.
+ struct TimestampedPackedUint224 {
+ uint224 value; // ───────╮ Value in uint224, packed.
+ uint32 timestamp; // ────╯ Timestamp of the most recent price update.
+ }
+
+ /// @dev Gas price is stored in 112-bit unsigned int. uint224 can pack 2 prices.
+ /// When packing L1 and L2 gas prices, L1 gas price is left-shifted to the higher-order bits.
+ /// Using uint8 type, which cannot be higher than other bit shift operands, to avoid shift operand type warning.
+ uint8 public constant GAS_PRICE_BITS = 112;
+
+ struct PoolUpdate {
+ address token; // The IERC20 token address
+ address pool; // The token pool address
+ }
+
+ struct SourceTokenData {
+ // The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be
+ // relied upon by the destination pool to validate the source pool.
+ bytes sourcePoolAddress;
+ // The address of the destination token, abi encoded in the case of EVM chains
+ // This value is UNTRUSTED as any pool owner can return whatever value they want.
+ bytes destTokenAddress;
+ // Optional pool data to be transferred to the destination chain. Be default this is capped at
+ // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
+ // has to be set for the specific token.
+ bytes extraData;
+ }
+
+ /// @notice Report that is submitted by the execution DON at the execution phase. (including chain selector data)
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct ExecutionReportSingleChain {
+ uint64 sourceChainSelector; // Source chain selector for which the report is submitted
+ Any2EVMRampMessage[] messages;
+ // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token
+ bytes[][] offchainTokenData;
+ bytes32[] proofs;
+ uint256 proofFlagBits;
+ }
+
+ /// @notice Report that is submitted by the execution DON at the execution phase.
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct ExecutionReport {
+ EVM2EVMMessage[] messages;
+ // Contains a bytes array for each message, each inner bytes array contains bytes per transferred token
+ bytes[][] offchainTokenData;
+ bytes32[] proofs;
+ uint256 proofFlagBits;
+ }
+
+ /// @notice The cross chain message that gets committed to EVM chains.
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct EVM2EVMMessage {
+ uint64 sourceChainSelector; // ───────────╮ the chain selector of the source chain, note: not chainId
+ address sender; // ───────────────────────╯ sender address on the source chain
+ address receiver; // ─────────────────────╮ receiver address on the destination chain
+ uint64 sequenceNumber; // ────────────────╯ sequence number, not unique across lanes
+ uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution
+ bool strict; // ──────────────────────────╮ DEPRECATED
+ uint64 nonce; // │ nonce for this lane for this sender, not unique across senders/lanes
+ address feeToken; // ─────────────────────╯ fee token
+ uint256 feeTokenAmount; // fee token amount
+ bytes data; // arbitrary data payload supplied by the message sender
+ Client.EVMTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer
+ bytes[] sourceTokenData; // array of token data, one per token
+ bytes32 messageId; // a hash of the message data
+ }
+
+ /// @dev EVM2EVMMessage struct has 13 fields, including 3 variable arrays.
+ /// Each variable array takes 1 more slot to store its length.
+ /// When abi encoded, excluding array contents,
+ /// EVM2EVMMessage takes up a fixed number of 16 lots, 32 bytes each.
+ /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 17.
+ uint256 public constant MESSAGE_FIXED_BYTES = 32 * 17;
+
+ /// @dev Each token transfer adds 1 EVMTokenAmount and 1 bytes.
+ /// When abiEncoded, each EVMTokenAmount takes 2 slots, each bytes takes 2 slots, excl bytes contents
+ uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * 4;
+
+ /// @dev Any2EVMRampMessage struct has 10 fields, including 3 variable unnested arrays (data, receiver and tokenAmounts).
+ /// Each variable array takes 1 more slot to store its length.
+ /// When abi encoded, excluding array contents,
+ /// Any2EVMMessage takes up a fixed number of 13 slots, 32 bytes each.
+ /// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 14.
+ /// The fixed bytes does not cover struct data (this is represented by ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN)
+ uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES = 32 * 14;
+
+ /// @dev Each token transfer adds 1 RampTokenAmount
+ /// RampTokenAmount has 4 fields, including 3 bytes.
+ /// Each bytes takes 1 more slot to store its length.
+ /// When abi encoded, each token transfer takes up 7 slots, excl bytes contents.
+ uint256 public constant ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * 7;
+
+ bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageHashV2");
+
+ /// @dev Used to hash messages for single-lane ramps.
+ /// OnRamp hash(EVM2EVMMessage) = OffRamp hash(EVM2EVMMessage)
+ /// The EVM2EVMMessage's messageId is expected to be the output of this hash function
+ /// @param original Message to hash
+ /// @param metadataHash Immutable metadata hash representing a lane with a fixed OnRamp
+ /// @return hashedMessage hashed message as a keccak256
+ function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
+ // Fixed-size message fields are included in nested hash to reduce stack pressure.
+ // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
+ return keccak256(
+ abi.encode(
+ MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
+ metadataHash,
+ keccak256(
+ abi.encode(
+ original.sender,
+ original.receiver,
+ original.sequenceNumber,
+ original.gasLimit,
+ original.strict,
+ original.nonce,
+ original.feeToken,
+ original.feeTokenAmount
+ )
+ ),
+ keccak256(original.data),
+ keccak256(abi.encode(original.tokenAmounts)),
+ keccak256(abi.encode(original.sourceTokenData))
+ )
+ );
+ }
+
+ bytes32 internal constant ANY_2_EVM_MESSAGE_HASH = keccak256("Any2EVMMessageHashV1");
+ bytes32 internal constant EVM_2_ANY_MESSAGE_HASH = keccak256("EVM2AnyMessageHashV1");
+
+ /// @dev Used to hash messages for multi-lane family-agnostic OffRamps.
+ /// OnRamp hash(EVM2AnyMessage) != Any2EVMRampMessage.messageId
+ /// OnRamp hash(EVM2AnyMessage) != OffRamp hash(Any2EVMRampMessage)
+ /// @param original OffRamp message to hash
+ /// @param onRamp OnRamp to hash the message with - used to compute the metadataHash
+ /// @return hashedMessage hashed message as a keccak256
+ function _hash(Any2EVMRampMessage memory original, bytes memory onRamp) internal pure returns (bytes32) {
+ // Fixed-size message fields are included in nested hash to reduce stack pressure.
+ // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
+ return keccak256(
+ abi.encode(
+ MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
+ // Implicit metadata hash
+ keccak256(
+ abi.encode(
+ ANY_2_EVM_MESSAGE_HASH, original.header.sourceChainSelector, original.header.destChainSelector, onRamp
+ )
+ ),
+ keccak256(
+ abi.encode(
+ original.header.messageId,
+ original.sender,
+ original.receiver,
+ original.header.sequenceNumber,
+ original.gasLimit,
+ original.header.nonce
+ )
+ ),
+ keccak256(original.data),
+ keccak256(abi.encode(original.tokenAmounts))
+ )
+ );
+ }
+
+ function _hash(EVM2AnyRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
+ // Fixed-size message fields are included in nested hash to reduce stack pressure.
+ // This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
+ return keccak256(
+ abi.encode(
+ MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
+ metadataHash,
+ keccak256(
+ abi.encode(
+ original.sender,
+ original.receiver,
+ original.header.sequenceNumber,
+ original.header.nonce,
+ original.feeToken,
+ original.feeTokenAmount
+ )
+ ),
+ keccak256(original.data),
+ keccak256(abi.encode(original.tokenAmounts)),
+ keccak256(original.extraArgs)
+ )
+ );
+ }
+
+ /// @dev We disallow the first 1024 addresses to never allow calling precompiles. It is extremely unlikely that
+ /// anyone would ever be able to generate an address in this range.
+ uint256 public constant PRECOMPILE_SPACE = 1024;
+
+ /// @notice This methods provides validation for parsing abi encoded addresses by ensuring the
+ /// address is within the EVM address space. If it isn't it will revert with an InvalidEVMAddress error, which
+ /// we can catch and handle more gracefully than a revert from abi.decode.
+ /// @return The address if it is valid, the function will revert otherwise.
+ function _validateEVMAddress(bytes memory encodedAddress) internal pure returns (address) {
+ if (encodedAddress.length != 32) revert InvalidEVMAddress(encodedAddress);
+ uint256 encodedAddressUint = abi.decode(encodedAddress, (uint256));
+ if (encodedAddressUint > type(uint160).max || encodedAddressUint < PRECOMPILE_SPACE) {
+ revert InvalidEVMAddress(encodedAddress);
+ }
+ return address(uint160(encodedAddressUint));
+ }
+
+ /// @notice Enum listing the possible message execution states within
+ /// the offRamp contract.
+ /// UNTOUCHED never executed
+ /// IN_PROGRESS currently being executed, used a replay protection
+ /// SUCCESS successfully executed. End state
+ /// FAILURE unsuccessfully executed, manual execution is now enabled.
+ /// @dev RMN depends on this enum, if changing, please notify the RMN maintainers.
+ enum MessageExecutionState {
+ UNTOUCHED,
+ IN_PROGRESS,
+ SUCCESS,
+ FAILURE
+ }
+
+ /// @notice CCIP OCR plugin type, used to separate execution & commit transmissions and configs
+ enum OCRPluginType {
+ Commit,
+ Execution
+ }
+
+ /// @notice Family-agnostic token amounts used for both OnRamp & OffRamp messages
+ struct RampTokenAmount {
+ // The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be
+ // relied upon by the destination pool to validate the source pool.
+ bytes sourcePoolAddress;
+ // The address of the destination token, abi encoded in the case of EVM chains
+ // This value is UNTRUSTED as any pool owner can return whatever value they want.
+ bytes destTokenAddress;
+ // Optional pool data to be transferred to the destination chain. Be default this is capped at
+ // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
+ // has to be set for the specific token.
+ bytes extraData;
+ uint256 amount; // Amount of tokens.
+ }
+
+ /// @notice Family-agnostic header for OnRamp & OffRamp messages.
+ /// The messageId is not expected to match hash(message), since it may originate from another ramp family
+ struct RampMessageHeader {
+ bytes32 messageId; // Unique identifier for the message, generated with the source chain's encoding scheme (i.e. not necessarily abi.encoded)
+ uint64 sourceChainSelector; // ───────╮ the chain selector of the source chain, note: not chainId
+ uint64 destChainSelector; // | the chain selector of the destination chain, note: not chainId
+ uint64 sequenceNumber; // │ sequence number, not unique across lanes
+ uint64 nonce; // ─────────────────────╯ nonce for this lane for this sender, not unique across senders/lanes
+ }
+
+ /// @notice Family-agnostic message routed to an OffRamp
+ /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage), hash(Any2EVMRampMessage) != messageId
+ /// due to encoding & parameter differences
+ struct Any2EVMRampMessage {
+ RampMessageHeader header; // Message header
+ bytes sender; // sender address on the source chain
+ bytes data; // arbitrary data payload supplied by the message sender
+ address receiver; // receiver address on the destination chain
+ uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution
+ RampTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer
+ }
+
+ /// @notice Family-agnostic message emitted from the OnRamp
+ /// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage) due to encoding & parameter differences
+ /// messageId = hash(EVM2AnyRampMessage) using the source EVM chain's encoding format
+ struct EVM2AnyRampMessage {
+ RampMessageHeader header; // Message header
+ address sender; // sender address on the source chain
+ bytes data; // arbitrary data payload supplied by the message sender
+ bytes receiver; // receiver address on the destination chain
+ bytes extraArgs; // destination-chain specific extra args, such as the gasLimit for EVM chains
+ address feeToken; // fee token
+ uint256 feeTokenAmount; // fee token amount
+ RampTokenAmount[] tokenAmounts; // array of tokens and amounts to transfer
+ }
+
+ // bytes4(keccak256("CCIP ChainFamilySelector EVM"))
+ bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;
+}
diff --git a/contracts/src/v0.8/ccip/libraries/MerkleMultiProof.sol b/contracts/src/v0.8/ccip/libraries/MerkleMultiProof.sol
new file mode 100644
index 00000000000..fed8a1165bb
--- /dev/null
+++ b/contracts/src/v0.8/ccip/libraries/MerkleMultiProof.sol
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+library MerkleMultiProof {
+ /// @notice Leaf domain separator, should be used as the first 32 bytes of a leaf's preimage.
+ bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000;
+ /// @notice Internal domain separator, should be used as the first 32 bytes of an internal node's preiimage.
+ bytes32 internal constant INTERNAL_DOMAIN_SEPARATOR =
+ 0x0000000000000000000000000000000000000000000000000000000000000001;
+
+ uint256 internal constant MAX_NUM_HASHES = 256;
+
+ error InvalidProof();
+ error LeavesCannotBeEmpty();
+
+ /// @notice Computes the root based on provided pre-hashed leaf nodes in
+ /// leaves, internal nodes in proofs, and using proofFlagBits' i-th bit to
+ /// determine if an element of proofs or one of the previously computed leafs
+ /// or internal nodes will be used for the i-th hash.
+ /// @param leaves Should be pre-hashed and the first 32 bytes of a leaf's
+ /// preimage should match LEAF_DOMAIN_SEPARATOR.
+ /// @param proofs The hashes to be used instead of a leaf hash when the proofFlagBits
+ /// indicates a proof should be used.
+ /// @param proofFlagBits A single uint256 of which each bit indicates whether a leaf or
+ /// a proof needs to be used in a hash operation.
+ /// @dev the maximum number of hash operations it set to 256. Any input that would require
+ /// more than 256 hashes to get to a root will revert.
+ /// @dev For given input `leaves` = [a,b,c] `proofs` = [D] and `proofFlagBits` = 5
+ /// totalHashes = 3 + 1 - 1 = 3
+ /// ** round 1 **
+ /// proofFlagBits = (5 >> 0) & 1 = true
+ /// hashes[0] = hashPair(a, b)
+ /// (leafPos, hashPos, proofPos) = (2, 0, 0);
+ ///
+ /// ** round 2 **
+ /// proofFlagBits = (5 >> 1) & 1 = false
+ /// hashes[1] = hashPair(D, c)
+ /// (leafPos, hashPos, proofPos) = (3, 0, 1);
+ ///
+ /// ** round 3 **
+ /// proofFlagBits = (5 >> 2) & 1 = true
+ /// hashes[2] = hashPair(hashes[0], hashes[1])
+ /// (leafPos, hashPos, proofPos) = (3, 2, 1);
+ ///
+ /// i = 3 and no longer < totalHashes. The algorithm is done
+ /// return hashes[totalHashes - 1] = hashes[2]; the last hash we computed.
+ // We mark this function as internal to force it to be inlined in contracts
+ // that use it, but semantically it is public.
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function merkleRoot(
+ bytes32[] memory leaves,
+ bytes32[] memory proofs,
+ uint256 proofFlagBits
+ ) internal pure returns (bytes32) {
+ unchecked {
+ uint256 leavesLen = leaves.length;
+ uint256 proofsLen = proofs.length;
+ if (leavesLen == 0) revert LeavesCannotBeEmpty();
+ if (!(leavesLen <= MAX_NUM_HASHES + 1 && proofsLen <= MAX_NUM_HASHES + 1)) revert InvalidProof();
+ uint256 totalHashes = leavesLen + proofsLen - 1;
+ if (!(totalHashes <= MAX_NUM_HASHES)) revert InvalidProof();
+ if (totalHashes == 0) {
+ return leaves[0];
+ }
+ bytes32[] memory hashes = new bytes32[](totalHashes);
+ (uint256 leafPos, uint256 hashPos, uint256 proofPos) = (0, 0, 0);
+
+ for (uint256 i = 0; i < totalHashes; ++i) {
+ // Checks if the bit flag signals the use of a supplied proof or a leaf/previous hash.
+ bytes32 a;
+ if (proofFlagBits & (1 << i) == (1 << i)) {
+ // Use a leaf or a previously computed hash.
+ if (leafPos < leavesLen) {
+ a = leaves[leafPos++];
+ } else {
+ a = hashes[hashPos++];
+ }
+ } else {
+ // Use a supplied proof.
+ a = proofs[proofPos++];
+ }
+
+ // The second part of the hashed pair is never a proof as hashing two proofs would result in a
+ // hash that can already be computed offchain.
+ bytes32 b;
+ if (leafPos < leavesLen) {
+ b = leaves[leafPos++];
+ } else {
+ b = hashes[hashPos++];
+ }
+
+ if (!(hashPos <= i)) revert InvalidProof();
+
+ hashes[i] = _hashPair(a, b);
+ }
+ if (!(hashPos == totalHashes - 1 && leafPos == leavesLen && proofPos == proofsLen)) revert InvalidProof();
+ // Return the last hash.
+ return hashes[totalHashes - 1];
+ }
+ }
+
+ /// @notice Hashes two bytes32 objects in their given order, prepended by the
+ /// INTERNAL_DOMAIN_SEPARATOR.
+ function _hashInternalNode(bytes32 left, bytes32 right) private pure returns (bytes32 hash) {
+ return keccak256(abi.encode(INTERNAL_DOMAIN_SEPARATOR, left, right));
+ }
+
+ /// @notice Hashes two bytes32 objects. The order is taken into account,
+ /// using the lower value first.
+ function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
+ return a < b ? _hashInternalNode(a, b) : _hashInternalNode(b, a);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/libraries/Pool.sol b/contracts/src/v0.8/ccip/libraries/Pool.sol
new file mode 100644
index 00000000000..3f1895dcf5a
--- /dev/null
+++ b/contracts/src/v0.8/ccip/libraries/Pool.sol
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+/// @notice This library contains various token pool functions to aid constructing the return data.
+library Pool {
+ // The tag used to signal support for the pool v1 standard
+ // bytes4(keccak256("CCIP_POOL_V1"))
+ bytes4 public constant CCIP_POOL_V1 = 0xaff2afbf;
+
+ // The number of bytes in the return data for a pool v1 releaseOrMint call.
+ // This should match the size of the ReleaseOrMintOutV1 struct.
+ uint16 public constant CCIP_POOL_V1_RET_BYTES = 32;
+
+ // The default max number of bytes in the return data for a pool v1 lockOrBurn call.
+ // This data can be used to send information to the destination chain token pool. Can be overwritten
+ // in the TokenTransferFeeConfig.destBytesOverhead if more data is required.
+ uint256 public constant CCIP_LOCK_OR_BURN_V1_RET_BYTES = 32;
+
+ struct LockOrBurnInV1 {
+ bytes receiver; // The recipient of the tokens on the destination chain, abi encoded
+ uint64 remoteChainSelector; // ─╮ The chain ID of the destination chain
+ address originalSender; // ─────╯ The original sender of the tx on the source chain
+ uint256 amount; // The amount of tokens to lock or burn, denominated in the source token's decimals
+ address localToken; // The address on this chain of the token to lock or burn
+ }
+
+ struct LockOrBurnOutV1 {
+ // The address of the destination token pool, abi encoded in the case of EVM chains
+ // This value is UNTRUSTED as any pool owner can return whatever value they want.
+ bytes destTokenAddress;
+ // Optional pool data to be transferred to the destination chain. Be default this is capped at
+ // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
+ // has to be set for the specific token.
+ bytes destPoolData;
+ }
+
+ struct ReleaseOrMintInV1 {
+ bytes originalSender; // The original sender of the tx on the source chain
+ uint64 remoteChainSelector; // ─╮ The chain ID of the source chain
+ address receiver; // ───────────╯ The recipient of the tokens on the destination chain. This is *NOT* the address to
+ // send the tokens to, but the address that will receive the tokens via the offRamp.
+ uint256 amount; // The amount of tokens to release or mint, denominated in the source token's decimals
+ address localToken; // The address on this chain of the token to release or mint
+ /// @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the
+ /// expected pool address for the given remoteChainSelector.
+ bytes sourcePoolAddress; // The address of the source pool, abi encoded in the case of EVM chains
+ bytes sourcePoolData; // The data received from the source pool to process the release or mint
+ /// @dev WARNING: offchainTokenData is untrusted data.
+ bytes offchainTokenData; // The offchain data to process the release or mint
+ }
+
+ struct ReleaseOrMintOutV1 {
+ // The number of tokens released or minted on the destination chain, denominated in the local token's decimals.
+ // This value is expected to be equal to the ReleaseOrMintInV1.amount in the case where the source and destination
+ // chain have the same number of decimals.
+ uint256 destinationAmount;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/libraries/RateLimiter.sol b/contracts/src/v0.8/ccip/libraries/RateLimiter.sol
new file mode 100644
index 00000000000..40ac3ca213e
--- /dev/null
+++ b/contracts/src/v0.8/ccip/libraries/RateLimiter.sol
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+/// @notice Implements Token Bucket rate limiting.
+/// @dev uint128 is safe for rate limiter state.
+/// For USD value rate limiting, it can adequately store USD value in 18 decimals.
+/// For ERC20 token amount rate limiting, all tokens that will be listed will have at most
+/// a supply of uint128.max tokens, and it will therefore not overflow the bucket.
+/// In exceptional scenarios where tokens consumed may be larger than uint128,
+/// e.g. compromised issuer, an enabled RateLimiter will check and revert.
+library RateLimiter {
+ error BucketOverfilled();
+ error OnlyCallableByAdminOrOwner();
+ error TokenMaxCapacityExceeded(uint256 capacity, uint256 requested, address tokenAddress);
+ error TokenRateLimitReached(uint256 minWaitInSeconds, uint256 available, address tokenAddress);
+ error AggregateValueMaxCapacityExceeded(uint256 capacity, uint256 requested);
+ error AggregateValueRateLimitReached(uint256 minWaitInSeconds, uint256 available);
+ error InvalidRateLimitRate(Config rateLimiterConfig);
+ error DisabledNonZeroRateLimit(Config config);
+ error RateLimitMustBeDisabled();
+
+ event TokensConsumed(uint256 tokens);
+ event ConfigChanged(Config config);
+
+ struct TokenBucket {
+ uint128 tokens; // ──────╮ Current number of tokens that are in the bucket.
+ uint32 lastUpdated; // │ Timestamp in seconds of the last token refill, good for 100+ years.
+ bool isEnabled; // ──────╯ Indication whether the rate limiting is enabled or not
+ uint128 capacity; // ────╮ Maximum number of tokens that can be in the bucket.
+ uint128 rate; // ────────╯ Number of tokens per second that the bucket is refilled.
+ }
+
+ struct Config {
+ bool isEnabled; // Indication whether the rate limiting should be enabled
+ uint128 capacity; // ────╮ Specifies the capacity of the rate limiter
+ uint128 rate; // ───────╯ Specifies the rate of the rate limiter
+ }
+
+ /// @notice _consume removes the given tokens from the pool, lowering the
+ /// rate tokens allowed to be consumed for subsequent calls.
+ /// @param requestTokens The total tokens to be consumed from the bucket.
+ /// @param tokenAddress The token to consume capacity for, use 0x0 to indicate aggregate value capacity.
+ /// @dev Reverts when requestTokens exceeds bucket capacity or available tokens in the bucket
+ /// @dev emits removal of requestTokens if requestTokens is > 0
+ function _consume(TokenBucket storage s_bucket, uint256 requestTokens, address tokenAddress) internal {
+ // If there is no value to remove or rate limiting is turned off, skip this step to reduce gas usage
+ if (!s_bucket.isEnabled || requestTokens == 0) {
+ return;
+ }
+
+ uint256 tokens = s_bucket.tokens;
+ uint256 capacity = s_bucket.capacity;
+ uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
+
+ if (timeDiff != 0) {
+ if (tokens > capacity) revert BucketOverfilled();
+
+ // Refill tokens when arriving at a new block time
+ tokens = _calculateRefill(capacity, tokens, timeDiff, s_bucket.rate);
+
+ s_bucket.lastUpdated = uint32(block.timestamp);
+ }
+
+ if (capacity < requestTokens) {
+ // Token address 0 indicates consuming aggregate value rate limit capacity.
+ if (tokenAddress == address(0)) revert AggregateValueMaxCapacityExceeded(capacity, requestTokens);
+ revert TokenMaxCapacityExceeded(capacity, requestTokens, tokenAddress);
+ }
+ if (tokens < requestTokens) {
+ uint256 rate = s_bucket.rate;
+ // Wait required until the bucket is refilled enough to accept this value, round up to next higher second
+ // Consume is not guaranteed to succeed after wait time passes if there is competing traffic.
+ // This acts as a lower bound of wait time.
+ uint256 minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate;
+
+ if (tokenAddress == address(0)) revert AggregateValueRateLimitReached(minWaitInSeconds, tokens);
+ revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress);
+ }
+ tokens -= requestTokens;
+
+ // Downcast is safe here, as tokens is not larger than capacity
+ s_bucket.tokens = uint128(tokens);
+ emit TokensConsumed(requestTokens);
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function _currentTokenBucketState(TokenBucket memory bucket) internal view returns (TokenBucket memory) {
+ // We update the bucket to reflect the status at the exact time of the
+ // call. This means we might need to refill a part of the bucket based
+ // on the time that has passed since the last update.
+ bucket.tokens =
+ uint128(_calculateRefill(bucket.capacity, bucket.tokens, block.timestamp - bucket.lastUpdated, bucket.rate));
+ bucket.lastUpdated = uint32(block.timestamp);
+ return bucket;
+ }
+
+ /// @notice Sets the rate limited config.
+ /// @param s_bucket The token bucket
+ /// @param config The new config
+ function _setTokenBucketConfig(TokenBucket storage s_bucket, Config memory config) internal {
+ // First update the bucket to make sure the proper rate is used for all the time
+ // up until the config change.
+ uint256 timeDiff = block.timestamp - s_bucket.lastUpdated;
+ if (timeDiff != 0) {
+ s_bucket.tokens = uint128(_calculateRefill(s_bucket.capacity, s_bucket.tokens, timeDiff, s_bucket.rate));
+
+ s_bucket.lastUpdated = uint32(block.timestamp);
+ }
+
+ s_bucket.tokens = uint128(_min(config.capacity, s_bucket.tokens));
+ s_bucket.isEnabled = config.isEnabled;
+ s_bucket.capacity = config.capacity;
+ s_bucket.rate = config.rate;
+
+ emit ConfigChanged(config);
+ }
+
+ /// @notice Validates the token bucket config
+ function _validateTokenBucketConfig(Config memory config, bool mustBeDisabled) internal pure {
+ if (config.isEnabled) {
+ if (config.rate >= config.capacity || config.rate == 0) {
+ revert InvalidRateLimitRate(config);
+ }
+ if (mustBeDisabled) {
+ revert RateLimitMustBeDisabled();
+ }
+ } else {
+ if (config.rate != 0 || config.capacity != 0) {
+ revert DisabledNonZeroRateLimit(config);
+ }
+ }
+ }
+
+ /// @notice Calculate refilled tokens
+ /// @param capacity bucket capacity
+ /// @param tokens current bucket tokens
+ /// @param timeDiff block time difference since last refill
+ /// @param rate bucket refill rate
+ /// @return the value of tokens after refill
+ function _calculateRefill(
+ uint256 capacity,
+ uint256 tokens,
+ uint256 timeDiff,
+ uint256 rate
+ ) private pure returns (uint256) {
+ return _min(capacity, tokens + timeDiff * rate);
+ }
+
+ /// @notice Return the smallest of two integers
+ /// @param a first int
+ /// @param b second int
+ /// @return smallest
+ function _min(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a < b ? a : b;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/libraries/USDPriceWith18Decimals.sol b/contracts/src/v0.8/ccip/libraries/USDPriceWith18Decimals.sol
new file mode 100644
index 00000000000..3508276d769
--- /dev/null
+++ b/contracts/src/v0.8/ccip/libraries/USDPriceWith18Decimals.sol
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+library USDPriceWith18Decimals {
+ /// @notice Takes a price in USD, with 18 decimals per 1e18 token amount,
+ /// and amount of the smallest token denomination,
+ /// calculates the value in USD with 18 decimals.
+ /// @param tokenPrice The USD price of the token.
+ /// @param tokenAmount Amount of the smallest token denomination.
+ /// @return USD value with 18 decimals.
+ /// @dev this function assumes that no more than 1e59 US dollar worth of token is passed in.
+ /// If more is sent, this function will overflow and revert.
+ /// Since there isn't even close to 1e59 dollars, this is ok for all legit tokens.
+ function _calcUSDValueFromTokenAmount(uint224 tokenPrice, uint256 tokenAmount) internal pure returns (uint256) {
+ /// LINK Example:
+ /// tokenPrice: 8e18 -> $8/LINK, as 1e18 token amount is 1 LINK, worth 8 USD, or 8e18 with 18 decimals
+ /// tokenAmount: 2e18 -> 2 LINK
+ /// result: 8e18 * 2e18 / 1e18 -> 16e18 with 18 decimals = $16
+
+ /// USDC Example:
+ /// tokenPrice: 1e30 -> $1/USDC, as 1e18 token amount is 1e12 USDC, worth 1e12 USD, or 1e30 with 18 decimals
+ /// tokenAmount: 5e6 -> 5 USDC
+ /// result: 1e30 * 5e6 / 1e18 -> 5e18 with 18 decimals = $5
+ return (tokenPrice * tokenAmount) / 1e18;
+ }
+
+ /// @notice Takes a price in USD, with 18 decimals per 1e18 token amount,
+ /// and USD value with 18 decimals,
+ /// calculates amount of the smallest token denomination.
+ /// @param tokenPrice The USD price of the token.
+ /// @param usdValue USD value with 18 decimals.
+ /// @return Amount of the smallest token denomination.
+ function _calcTokenAmountFromUSDValue(uint224 tokenPrice, uint256 usdValue) internal pure returns (uint256) {
+ /// LINK Example:
+ /// tokenPrice: 8e18 -> $8/LINK, as 1e18 token amount is 1 LINK, worth 8 USD, or 8e18 with 18 decimals
+ /// usdValue: 16e18 -> $16
+ /// result: 16e18 * 1e18 / 8e18 -> 2e18 = 2 LINK
+
+ /// USDC Example:
+ /// tokenPrice: 1e30 -> $1/USDC, as 1e18 token amount is 1e12 USDC, worth 1e12 USD, or 1e30 with 18 decimals
+ /// usdValue: 5e18 -> $5
+ /// result: 5e18 * 1e18 / 1e30 -> 5e6 = 5 USDC
+ return (usdValue * 1e18) / tokenPrice;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/ocr/MultiOCR3Base.sol b/contracts/src/v0.8/ccip/ocr/MultiOCR3Base.sol
new file mode 100644
index 00000000000..1872ae276ce
--- /dev/null
+++ b/contracts/src/v0.8/ccip/ocr/MultiOCR3Base.sol
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+
+/// @notice Onchain verification of reports from the offchain reporting protocol
+/// with multiple OCR plugin support.
+abstract contract MultiOCR3Base is ITypeAndVersion, OwnerIsCreator {
+ // 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 ocrPluginType OCR plugin type for which the config was set
+ /// @param configDigest configDigest of this configuration
+ /// @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
+ event ConfigSet(uint8 ocrPluginType, bytes32 configDigest, address[] signers, address[] transmitters, uint8 F);
+
+ /// @notice optionally emitted to indicate the latest configDigest and sequence number
+ /// for which a report was successfully transmitted. Alternatively, the contract may
+ /// use latestConfigDigestAndEpoch with scanLogs set to false.
+ event Transmitted(uint8 indexed ocrPluginType, bytes32 configDigest, uint64 sequenceNumber);
+
+ enum InvalidConfigErrorType {
+ F_MUST_BE_POSITIVE,
+ TOO_MANY_TRANSMITTERS,
+ TOO_MANY_SIGNERS,
+ F_TOO_HIGH,
+ REPEATED_ORACLE_ADDRESS
+ }
+
+ error InvalidConfig(InvalidConfigErrorType errorType);
+ error WrongMessageLength(uint256 expected, uint256 actual);
+ error ConfigDigestMismatch(bytes32 expected, bytes32 actual);
+ error ForkedChain(uint256 expected, uint256 actual);
+ error WrongNumberOfSignatures();
+ error SignaturesOutOfRegistration();
+ error UnauthorizedTransmitter();
+ error UnauthorizedSigner();
+ error NonUniqueSignatures();
+ error OracleCannotBeZeroAddress();
+ error StaticConfigCannotBeChanged(uint8 ocrPluginType);
+
+ /// @dev Packing these fields used on the hot path in a ConfigInfo variable reduces the
+ /// retrieval of all of them to a minimum number of SLOADs.
+ struct ConfigInfo {
+ bytes32 configDigest;
+ uint8 F; // ──────────────────────────────╮ maximum number of faulty/dishonest oracles the system can tolerate
+ uint8 n; // │ number of signers / transmitters
+ bool isSignatureVerificationEnabled; // ──╯ if true, requires signers and verifies signatures on transmission verification
+ }
+
+ /// @notice 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
+ }
+
+ /// @notice OCR configuration for a single OCR plugin within a DON
+ struct OCRConfig {
+ ConfigInfo configInfo; // latest OCR config
+ address[] signers; // addresses oracles use to sign the reports
+ address[] transmitters; // addresses oracles use to transmit the reports
+ }
+
+ /// @notice Args to update an OCR Config
+ struct OCRConfigArgs {
+ bytes32 configDigest; // Config digest to update to
+ uint8 ocrPluginType; // ──────────────────╮ OCR plugin type to update config for
+ uint8 F; // │ maximum number of faulty/dishonest oracles
+ bool isSignatureVerificationEnabled; // ──╯ if true, requires signers and verifies signatures on transmission verification
+ address[] signers; // signing address of each oracle
+ address[] transmitters; // transmission address of each oracle (i.e. the address the oracle actually sends transactions to the contract from)
+ }
+
+ /// @notice mapping of OCR plugin type -> DON config
+ mapping(uint8 ocrPluginType => OCRConfig config) internal s_ocrConfigs;
+
+ /// @notice OCR plugin type => signer OR transmitter address mapping
+ mapping(uint8 ocrPluginType => mapping(address signerOrTransmiter => Oracle oracle)) internal s_oracles;
+
+ // 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
+
+ /// @notice constant length component for transmit functions with no signatures.
+ /// The signatures are expected to match transmitPlugin(reportContext, report)
+ uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT_NO_SIGNATURES = 4 // function selector
+ + 3 * 32 // 3 words containing reportContext
+ + 32 // word containing start location of abiencoded report value
+ + 32; // word containing length of report
+
+ /// @notice extra constant length component for transmit functions with signatures (relative to no signatures)
+ /// The signatures are expected to match transmitPlugin(reportContext, report, rs, ss, rawVs)
+ uint16 private constant TRANSMIT_MSGDATA_EXTRA_CONSTANT_LENGTH_COMPONENT_FOR_SIGNATURES = 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 rs
+ + 32; // word containing length of ss
+
+ uint256 internal immutable i_chainID;
+
+ constructor() {
+ i_chainID = block.chainid;
+ }
+
+ /// @notice sets offchain reporting protocol configuration incl. participating oracles
+ /// NOTE: The OCR3 config must be sanity-checked against the home-chain registry configuration, to ensure
+ /// home-chain and remote-chain parity!
+ /// @param ocrConfigArgs OCR config update args
+ function setOCR3Configs(OCRConfigArgs[] memory ocrConfigArgs) external onlyOwner {
+ for (uint256 i; i < ocrConfigArgs.length; ++i) {
+ _setOCR3Config(ocrConfigArgs[i]);
+ }
+ }
+
+ /// @notice sets offchain reporting protocol configuration incl. participating oracles for a single OCR plugin type
+ /// @param ocrConfigArgs OCR config update args
+ function _setOCR3Config(OCRConfigArgs memory ocrConfigArgs) internal {
+ if (ocrConfigArgs.F == 0) revert InvalidConfig(InvalidConfigErrorType.F_MUST_BE_POSITIVE);
+
+ uint8 ocrPluginType = ocrConfigArgs.ocrPluginType;
+ OCRConfig storage ocrConfig = s_ocrConfigs[ocrPluginType];
+ ConfigInfo storage configInfo = ocrConfig.configInfo;
+
+ // If F is 0, then the config is not yet set
+ if (configInfo.F == 0) {
+ configInfo.isSignatureVerificationEnabled = ocrConfigArgs.isSignatureVerificationEnabled;
+ } else if (configInfo.isSignatureVerificationEnabled != ocrConfigArgs.isSignatureVerificationEnabled) {
+ revert StaticConfigCannotBeChanged(ocrPluginType);
+ }
+
+ address[] memory transmitters = ocrConfigArgs.transmitters;
+ // Transmitters are expected to never exceed 255 (since this is bounded by MAX_NUM_ORACLES)
+ uint8 newTransmittersLength = uint8(transmitters.length);
+
+ if (newTransmittersLength > MAX_NUM_ORACLES) revert InvalidConfig(InvalidConfigErrorType.TOO_MANY_TRANSMITTERS);
+
+ _clearOracleRoles(ocrPluginType, ocrConfig.transmitters);
+
+ if (ocrConfigArgs.isSignatureVerificationEnabled) {
+ _clearOracleRoles(ocrPluginType, ocrConfig.signers);
+
+ address[] memory signers = ocrConfigArgs.signers;
+ ocrConfig.signers = signers;
+
+ uint8 signersLength = uint8(signers.length);
+ configInfo.n = signersLength;
+
+ if (signersLength > MAX_NUM_ORACLES) revert InvalidConfig(InvalidConfigErrorType.TOO_MANY_SIGNERS);
+ if (signersLength <= 3 * ocrConfigArgs.F) revert InvalidConfig(InvalidConfigErrorType.F_TOO_HIGH);
+
+ _assignOracleRoles(ocrPluginType, signers, Role.Signer);
+ }
+
+ _assignOracleRoles(ocrPluginType, transmitters, Role.Transmitter);
+
+ ocrConfig.transmitters = transmitters;
+ configInfo.F = ocrConfigArgs.F;
+ configInfo.configDigest = ocrConfigArgs.configDigest;
+
+ emit ConfigSet(
+ ocrPluginType, ocrConfigArgs.configDigest, ocrConfig.signers, ocrConfigArgs.transmitters, ocrConfigArgs.F
+ );
+ _afterOCR3ConfigSet(ocrPluginType);
+ }
+
+ /// @notice Hook that is called after a plugin's OCR3 config changes
+ /// @param ocrPluginType Plugin type for which the config changed
+ function _afterOCR3ConfigSet(uint8 ocrPluginType) internal virtual;
+
+ /// @notice Clears oracle roles for the provided oracle addresses
+ /// @param ocrPluginType OCR plugin type to clear roles for
+ /// @param oracleAddresses Oracle addresses to clear roles for
+ function _clearOracleRoles(uint8 ocrPluginType, address[] memory oracleAddresses) internal {
+ for (uint256 i = 0; i < oracleAddresses.length; ++i) {
+ delete s_oracles[ocrPluginType][oracleAddresses[i]];
+ }
+ }
+
+ /// @notice Assigns oracles roles for the provided oracle addresses with uniqueness verification
+ /// @param ocrPluginType OCR plugin type to assign roles for
+ /// @param oracleAddresses Oracle addresses to assign roles to
+ /// @param role Role to assign
+ function _assignOracleRoles(uint8 ocrPluginType, address[] memory oracleAddresses, Role role) internal {
+ for (uint8 i = 0; i < oracleAddresses.length; ++i) {
+ address oracle = oracleAddresses[i];
+ if (s_oracles[ocrPluginType][oracle].role != Role.Unset) {
+ revert InvalidConfig(InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS);
+ }
+ if (oracle == address(0)) revert OracleCannotBeZeroAddress();
+ s_oracles[ocrPluginType][oracle] = Oracle(i, role);
+ }
+ }
+
+ /// @notice _transmit is called to post a new report to the contract.
+ /// The function should be called after the per-DON reporting logic is completed.
+ /// @param ocrPluginType OCR plugin type to transmit report for
+ /// @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 MAX_NUM_ORACLES entries
+ /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries
+ /// @param rawVs ith element is the the V component of the ith signature
+ function _transmit(
+ uint8 ocrPluginType,
+ // 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[] memory rs,
+ bytes32[] memory ss,
+ bytes32 rawVs // signatures
+ ) internal {
+ // reportContext consists of:
+ // reportContext[0]: ConfigDigest
+ // reportContext[1]: 24 byte padding, 8 byte sequence number
+ // reportContext[2]: ExtraHash
+ ConfigInfo memory configInfo = s_ocrConfigs[ocrPluginType].configInfo;
+ bytes32 configDigest = reportContext[0];
+
+ // Scoping this reduces stack pressure and gas usage
+ {
+ uint256 expectedDataLength = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT_NO_SIGNATURES) + report.length; // one byte pure entry in _report
+
+ if (configInfo.isSignatureVerificationEnabled) {
+ expectedDataLength += TRANSMIT_MSGDATA_EXTRA_CONSTANT_LENGTH_COMPONENT_FOR_SIGNATURES + rs.length * 32 // 32 bytes per entry in _rs
+ + ss.length * 32; // 32 bytes per entry in _ss)
+ }
+
+ if (msg.data.length != expectedDataLength) revert WrongMessageLength(expectedDataLength, msg.data.length);
+ }
+
+ if (configInfo.configDigest != configDigest) {
+ revert ConfigDigestMismatch(configInfo.configDigest, configDigest);
+ }
+ // If the cached chainID at time of deployment doesn't match the current chainID, we reject all signed reports.
+ // This avoids a (rare) scenario where chain A forks into chain A and A', A' still has configDigest
+ // calculated from chain A and so OCR reports will be valid on both forks.
+ _whenChainNotForked();
+
+ // Scoping this reduces stack pressure and gas usage
+ {
+ Oracle memory transmitter = s_oracles[ocrPluginType][msg.sender];
+ // Check that sender is authorized to report
+ if (
+ !(
+ transmitter.role == Role.Transmitter
+ && msg.sender == s_ocrConfigs[ocrPluginType].transmitters[transmitter.index]
+ )
+ ) {
+ revert UnauthorizedTransmitter();
+ }
+ }
+
+ if (configInfo.isSignatureVerificationEnabled) {
+ // Scoping to reduce stack pressure
+ {
+ if (rs.length != configInfo.F + 1) revert WrongNumberOfSignatures();
+ if (rs.length != ss.length) revert SignaturesOutOfRegistration();
+ }
+
+ bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext));
+ _verifySignatures(ocrPluginType, h, rs, ss, rawVs);
+ }
+
+ emit Transmitted(ocrPluginType, configDigest, uint64(uint256(reportContext[1])));
+ }
+
+ /// @notice verifies the signatures of a hashed report value for one OCR plugin type
+ /// @param ocrPluginType OCR plugin type to transmit report for
+ /// @param hashedReport hashed encoded packing of report + reportContext
+ /// @param rs ith element is the R components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries
+ /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries
+ /// @param rawVs ith element is the the V component of the ith signature
+ function _verifySignatures(
+ uint8 ocrPluginType,
+ bytes32 hashedReport,
+ bytes32[] memory rs,
+ bytes32[] memory ss,
+ bytes32 rawVs // signatures
+ ) internal view {
+ // Verify signatures attached to report
+ bool[MAX_NUM_ORACLES] memory signed;
+
+ uint256 numberOfSignatures = rs.length;
+ for (uint256 i; i < numberOfSignatures; ++i) {
+ // Safe from ECDSA malleability here since we check for duplicate signers.
+ address signer = ecrecover(hashedReport, uint8(rawVs[i]) + 27, rs[i], ss[i]);
+ // Since we disallow address(0) as a valid signer address, it can
+ // never have a signer role.
+ Oracle memory oracle = s_oracles[ocrPluginType][signer];
+ if (oracle.role != Role.Signer) revert UnauthorizedSigner();
+ if (signed[oracle.index]) revert NonUniqueSignatures();
+ signed[oracle.index] = true;
+ }
+ }
+
+ /// @notice Validates that the chain ID has not diverged after deployment. Reverts if the chain IDs do not match
+ function _whenChainNotForked() internal view {
+ if (i_chainID != block.chainid) revert ForkedChain(i_chainID, block.chainid);
+ }
+
+ /// @notice information about current offchain reporting protocol configuration
+ /// @param ocrPluginType OCR plugin type to return config details for
+ /// @return ocrConfig OCR config for the plugin type
+ function latestConfigDetails(uint8 ocrPluginType) external view returns (OCRConfig memory ocrConfig) {
+ return s_ocrConfigs[ocrPluginType];
+ }
+}
diff --git a/contracts/src/v0.8/ccip/ocr/OCR2Abstract.sol b/contracts/src/v0.8/ccip/ocr/OCR2Abstract.sol
new file mode 100644
index 00000000000..741433bd5ad
--- /dev/null
+++ b/contracts/src/v0.8/ccip/ocr/OCR2Abstract.sol
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+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 setOCR2Config(
+ 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);
+
+ function _configDigestFromConfigData(
+ uint256 chainId,
+ address contractAddress,
+ uint64 configCount,
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) internal pure returns (bytes32) {
+ uint256 h = uint256(
+ keccak256(
+ abi.encode(
+ chainId,
+ contractAddress,
+ configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ )
+ )
+ );
+ uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00
+ uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00
+ return bytes32((prefix & prefixMask) | (h & ~prefixMask));
+ }
+
+ /// @notice optionally emitted to indicate the latest configDigest and epoch for
+ /// which a report was successfully transmitted. 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 MAX_NUM_ORACLES entries
+ /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES 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/ccip/ocr/OCR2Base.sol b/contracts/src/v0.8/ccip/ocr/OCR2Base.sol
new file mode 100644
index 00000000000..52a6df2f3a2
--- /dev/null
+++ b/contracts/src/v0.8/ccip/ocr/OCR2Base.sol
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.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 OwnerIsCreator, OCR2Abstract {
+ error InvalidConfig(InvalidConfigErrorType errorType);
+ error WrongMessageLength(uint256 expected, uint256 actual);
+ error ConfigDigestMismatch(bytes32 expected, bytes32 actual);
+ error ForkedChain(uint256 expected, uint256 actual);
+ error WrongNumberOfSignatures();
+ error SignaturesOutOfRegistration();
+ error UnauthorizedTransmitter();
+ error UnauthorizedSigner();
+ error NonUniqueSignatures();
+ error OracleCannotBeZeroAddress();
+
+ enum InvalidConfigErrorType {
+ F_MUST_BE_POSITIVE,
+ TOO_MANY_SIGNERS,
+ F_TOO_HIGH,
+ REPEATED_ORACLE_ADDRESS,
+ NUM_SIGNERS_NOT_NUM_TRANSMITTERS
+ }
+
+ // Packing these fields used on the hot path in a ConfigInfo variable reduces the
+ // retrieval of all of them to a minimum number of SLOADs.
+ struct ConfigInfo {
+ bytes32 latestConfigDigest;
+ uint8 f;
+ uint8 n;
+ }
+
+ // 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
+ }
+
+ // The current config
+ ConfigInfo internal s_configInfo;
+
+ // incremented each time a new config is posted. This count is incorporated
+ // into the config digest, to prevent replay attacks.
+ uint32 internal s_configCount;
+ // makes it easier for offchain systems to extract config from logs.
+ uint32 internal s_latestConfigBlockNumber;
+
+ // signer OR transmitter address
+ mapping(address signerOrTransmitter => Oracle 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;
+
+ // 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
+
+ bool internal immutable i_uniqueReports;
+ uint256 internal immutable i_chainID;
+
+ constructor(bool uniqueReports) {
+ i_uniqueReports = uniqueReports;
+ i_chainID = block.chainid;
+ }
+
+ // Reverts transaction if config args are invalid
+ modifier checkConfigValid(uint256 numSigners, uint256 numTransmitters, uint256 f) {
+ if (numSigners > MAX_NUM_ORACLES) revert InvalidConfig(InvalidConfigErrorType.TOO_MANY_SIGNERS);
+ if (f == 0) revert InvalidConfig(InvalidConfigErrorType.F_MUST_BE_POSITIVE);
+ if (numSigners != numTransmitters) revert InvalidConfig(InvalidConfigErrorType.NUM_SIGNERS_NOT_NUM_TRANSMITTERS);
+ if (numSigners <= 3 * f) revert InvalidConfig(InvalidConfigErrorType.F_TOO_HIGH);
+ _;
+ }
+
+ /// @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 setOCR2Config(
+ 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 {
+ _beforeSetConfig(onchainConfig);
+ uint256 oldSignerLength = s_signers.length;
+ for (uint256 i = 0; i < oldSignerLength; ++i) {
+ delete s_oracles[s_signers[i]];
+ delete s_oracles[s_transmitters[i]];
+ }
+
+ uint256 newSignersLength = signers.length;
+ for (uint256 i = 0; i < newSignersLength; ++i) {
+ // add new signer/transmitter addresses
+ address signer = signers[i];
+ if (s_oracles[signer].role != Role.Unset) revert InvalidConfig(InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS);
+ if (signer == address(0)) revert OracleCannotBeZeroAddress();
+ s_oracles[signer] = Oracle(uint8(i), Role.Signer);
+
+ address transmitter = transmitters[i];
+ if (s_oracles[transmitter].role != Role.Unset) {
+ revert InvalidConfig(InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS);
+ }
+ if (transmitter == address(0)) revert OracleCannotBeZeroAddress();
+ s_oracles[transmitter] = Oracle(uint8(i), Role.Transmitter);
+ }
+
+ s_signers = signers;
+ s_transmitters = transmitters;
+
+ s_configInfo.f = f;
+ s_configInfo.n = uint8(newSignersLength);
+ s_configInfo.latestConfigDigest = _configDigestFromConfigData(
+ block.chainid,
+ address(this),
+ ++s_configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+
+ uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
+ s_latestConfigBlockNumber = uint32(block.number);
+
+ emit ConfigSet(
+ previousConfigBlockNumber,
+ s_configInfo.latestConfigDigest,
+ s_configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+ }
+
+ /// @dev Hook that is run from setOCR2Config() right after validating configuration.
+ /// Empty by default, please provide an implementation in a child contract if you need additional configuration processing
+ function _beforeSetConfig(bytes memory _onchainConfig) internal virtual;
+
+ /// @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 getTransmitters() external view returns (address[] memory) {
+ return s_transmitters;
+ }
+
+ /// @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 MAX_NUM_ORACLES entries
+ /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES 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 {
+ // Scoping this reduces stack pressure and gas usage
+ {
+ // report and epochAndRound
+ _report(report, uint40(uint256(reportContext[1])));
+ }
+
+ // 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];
+ ConfigInfo memory configInfo = s_configInfo;
+
+ if (configInfo.latestConfigDigest != configDigest) {
+ revert ConfigDigestMismatch(configInfo.latestConfigDigest, configDigest);
+ }
+ // If the cached chainID at time of deployment doesn't match the current chainID, we reject all signed reports.
+ // This avoids a (rare) scenario where chain A forks into chain A and A', A' still has configDigest
+ // calculated from chain A and so OCR reports will be valid on both forks.
+ if (i_chainID != block.chainid) revert ForkedChain(i_chainID, block.chainid);
+
+ emit Transmitted(configDigest, uint32(uint256(reportContext[1]) >> 8));
+
+ uint256 expectedNumSignatures;
+ if (i_uniqueReports) {
+ expectedNumSignatures = (configInfo.n + configInfo.f) / 2 + 1;
+ } else {
+ expectedNumSignatures = configInfo.f + 1;
+ }
+ if (rs.length != expectedNumSignatures) revert WrongNumberOfSignatures();
+ if (rs.length != ss.length) revert SignaturesOutOfRegistration();
+
+ // Scoping this reduces stack pressure and gas usage
+ {
+ Oracle memory transmitter = s_oracles[msg.sender];
+ // Check that sender is authorized to report
+ if (!(transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index])) {
+ revert UnauthorizedTransmitter();
+ }
+ }
+ // Scoping this reduces stack pressure and gas usage
+ {
+ uint256 expectedDataLength = 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)
+ if (msg.data.length != expectedDataLength) revert WrongMessageLength(expectedDataLength, msg.data.length);
+ }
+
+ // Verify signatures attached to report
+ bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext));
+ bool[MAX_NUM_ORACLES] memory signed;
+
+ uint256 numberOfSignatures = rs.length;
+ for (uint256 i = 0; i < numberOfSignatures; ++i) {
+ // Safe from ECDSA malleability here since we check for duplicate signers.
+ address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]);
+ // Since we disallow address(0) as a valid signer address, it can
+ // never have a signer role.
+ Oracle memory oracle = s_oracles[signer];
+ if (oracle.role != Role.Signer) revert UnauthorizedSigner();
+ if (signed[oracle.index]) revert NonUniqueSignatures();
+ signed[oracle.index] = true;
+ }
+ }
+
+ /// @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);
+ }
+
+ /// @inheritdoc OCR2Abstract
+ function latestConfigDigestAndEpoch()
+ external
+ view
+ virtual
+ override
+ returns (bool scanLogs, bytes32 configDigest, uint32 epoch)
+ {
+ return (true, bytes32(0), uint32(0));
+ }
+
+ function _report(bytes calldata report, uint40 epochAndRound) internal virtual;
+}
diff --git a/contracts/src/v0.8/ccip/ocr/OCR2BaseNoChecks.sol b/contracts/src/v0.8/ccip/ocr/OCR2BaseNoChecks.sol
new file mode 100644
index 00000000000..a79df8d589a
--- /dev/null
+++ b/contracts/src/v0.8/ccip/ocr/OCR2BaseNoChecks.sol
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.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".
+/// @dev This contract does ***NOT*** check the supplied signatures on `transmit`
+/// This is intentional.
+abstract contract OCR2BaseNoChecks is OwnerIsCreator, OCR2Abstract {
+ error InvalidConfig(InvalidConfigErrorType errorType);
+ error WrongMessageLength(uint256 expected, uint256 actual);
+ error ConfigDigestMismatch(bytes32 expected, bytes32 actual);
+ error ForkedChain(uint256 expected, uint256 actual);
+ error UnauthorizedTransmitter();
+ error OracleCannotBeZeroAddress();
+
+ enum InvalidConfigErrorType {
+ F_MUST_BE_POSITIVE,
+ TOO_MANY_TRANSMITTERS,
+ REPEATED_ORACLE_ADDRESS
+ }
+
+ // Packing these fields used on the hot path in a ConfigInfo variable reduces the
+ // retrieval of all of them to a minimum number of SLOADs.
+ struct ConfigInfo {
+ bytes32 latestConfigDigest;
+ uint8 f;
+ uint8 n;
+ }
+
+ // 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,
+ // Unused
+ 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_transmitters
+ Role role; // Role of the address which mapped to this struct
+ }
+
+ // The current config
+ ConfigInfo internal s_configInfo;
+
+ // incremented each time a new config is posted. This count is incorporated
+ // into the config digest, to prevent replay attacks.
+ uint32 internal s_configCount;
+ // makes it easier for offchain systems to extract config from logs.
+ uint32 internal s_latestConfigBlockNumber;
+
+ // Transmitter address
+ mapping(address transmitter => Oracle oracle) internal s_oracles;
+
+ // 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;
+
+ // 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
+
+ uint256 internal immutable i_chainID;
+
+ // Reverts transaction if config args are invalid
+ modifier checkConfigValid(uint256 numTransmitters, uint256 f) {
+ if (numTransmitters > MAX_NUM_ORACLES) revert InvalidConfig(InvalidConfigErrorType.TOO_MANY_TRANSMITTERS);
+ if (f == 0) revert InvalidConfig(InvalidConfigErrorType.F_MUST_BE_POSITIVE);
+ _;
+ }
+
+ constructor() {
+ i_chainID = block.chainid;
+ }
+
+ /// @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 setOCR2Config(
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) external override checkConfigValid(transmitters.length, f) onlyOwner {
+ _beforeSetConfig(onchainConfig);
+ // Scoped to reduce contract size
+ {
+ uint256 oldTransmitterLength = s_transmitters.length;
+ for (uint256 i = 0; i < oldTransmitterLength; ++i) {
+ delete s_oracles[s_transmitters[i]];
+ }
+ }
+ uint256 newTransmitterLength = transmitters.length;
+ for (uint256 i = 0; i < newTransmitterLength; ++i) {
+ address transmitter = transmitters[i];
+ if (s_oracles[transmitter].role != Role.Unset) {
+ revert InvalidConfig(InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS);
+ }
+ if (transmitter == address(0)) revert OracleCannotBeZeroAddress();
+ s_oracles[transmitter] = Oracle(uint8(i), Role.Transmitter);
+ }
+
+ s_transmitters = transmitters;
+
+ s_configInfo.f = f;
+ s_configInfo.n = uint8(newTransmitterLength);
+ s_configInfo.latestConfigDigest = _configDigestFromConfigData(
+ block.chainid,
+ address(this),
+ ++s_configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+
+ uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
+ s_latestConfigBlockNumber = uint32(block.number);
+
+ emit ConfigSet(
+ previousConfigBlockNumber,
+ s_configInfo.latestConfigDigest,
+ s_configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+ }
+
+ /// @dev Hook that is run from setOCR2Config() right after validating configuration.
+ /// Empty by default, please provide an implementation in a child contract if you need additional configuration processing
+ function _beforeSetConfig(bytes memory _onchainConfig) internal virtual;
+
+ /// @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 getTransmitters() external view returns (address[] memory) {
+ return s_transmitters;
+ }
+
+ /// @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 MAX_NUM_ORACLES entries
+ /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries
+ 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 // signatures
+ ) external override {
+ _report(report);
+
+ // 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];
+ bytes32 latestConfigDigest = s_configInfo.latestConfigDigest;
+ if (latestConfigDigest != configDigest) revert ConfigDigestMismatch(latestConfigDigest, configDigest);
+ _checkChainForked();
+
+ emit Transmitted(configDigest, uint32(uint256(reportContext[1]) >> 8));
+
+ // Scoping this reduces stack pressure and gas usage
+ {
+ Oracle memory transmitter = s_oracles[msg.sender];
+ // Check that sender is authorized to report
+ if (!(transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index])) {
+ revert UnauthorizedTransmitter();
+ }
+ }
+
+ uint256 expectedDataLength = 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)
+ if (msg.data.length != expectedDataLength) revert WrongMessageLength(expectedDataLength, msg.data.length);
+ }
+
+ function _checkChainForked() internal view {
+ // If the cached chainID at time of deployment doesn't match the current chainID, we reject all signed reports.
+ // This avoids a (rare) scenario where chain A forks into chain A and A', A' still has configDigest
+ // calculated from chain A and so OCR reports will be valid on both forks.
+ if (i_chainID != block.chainid) revert ForkedChain(i_chainID, block.chainid);
+ }
+
+ /// @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);
+ }
+
+ /// @inheritdoc OCR2Abstract
+ function latestConfigDigestAndEpoch()
+ external
+ view
+ virtual
+ override
+ returns (bool scanLogs, bytes32 configDigest, uint32 epoch)
+ {
+ return (true, bytes32(0), uint32(0));
+ }
+
+ function _report(bytes calldata report) internal virtual;
+}
diff --git a/contracts/src/v0.8/ccip/offRamp/EVM2EVMMultiOffRamp.sol b/contracts/src/v0.8/ccip/offRamp/EVM2EVMMultiOffRamp.sol
new file mode 100644
index 00000000000..809e4e22a4e
--- /dev/null
+++ b/contracts/src/v0.8/ccip/offRamp/EVM2EVMMultiOffRamp.sol
@@ -0,0 +1,914 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol";
+import {IMessageInterceptor} from "../interfaces/IMessageInterceptor.sol";
+import {INonceManager} from "../interfaces/INonceManager.sol";
+import {IPoolV1} from "../interfaces/IPool.sol";
+import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol";
+import {IRMN} from "../interfaces/IRMN.sol";
+import {IRouter} from "../interfaces/IRouter.sol";
+import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol";
+
+import {CallWithExactGas} from "../../shared/call/CallWithExactGas.sol";
+import {EnumerableMapAddresses} from "../../shared/enumerable/EnumerableMapAddresses.sol";
+import {Client} from "../libraries/Client.sol";
+import {Internal} from "../libraries/Internal.sol";
+import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
+import {Pool} from "../libraries/Pool.sol";
+import {MultiOCR3Base} from "../ocr/MultiOCR3Base.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {ERC165Checker} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol";
+
+/// @notice EVM2EVMOffRamp enables OCR networks to execute multiple messages
+/// in an OffRamp in a single transaction.
+/// @dev The EVM2EVMMultiOnRamp and EVM2EVMMultiOffRamp form an xchain upgradeable unit. Any change to one of them
+/// results an onchain upgrade of both contracts.
+/// @dev MultiOCR3Base is used to store multiple OCR configs for both the OffRamp and the CommitStore.
+/// The execution plugin type has to be configured without signature verification, and the commit
+/// plugin type with verification.
+contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
+ using ERC165Checker for address;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+
+ error AlreadyAttempted(uint64 sourceChainSelector, uint64 sequenceNumber);
+ error AlreadyExecuted(uint64 sourceChainSelector, uint64 sequenceNumber);
+ error ZeroChainSelectorNotAllowed();
+ error ExecutionError(bytes32 messageId, bytes err);
+ error SourceChainNotEnabled(uint64 sourceChainSelector);
+ error TokenDataMismatch(uint64 sourceChainSelector, uint64 sequenceNumber);
+ error UnexpectedTokenData();
+ error ManualExecutionNotYetEnabled(uint64 sourceChainSelector);
+ error ManualExecutionGasLimitMismatch();
+ error InvalidManualExecutionGasLimit(uint64 sourceChainSelector, uint256 index, uint256 newLimit);
+ error RootNotCommitted(uint64 sourceChainSelector);
+ error RootAlreadyCommitted(uint64 sourceChainSelector, bytes32 merkleRoot);
+ error InvalidRoot();
+ error CanOnlySelfCall();
+ error ReceiverError(bytes err);
+ error TokenHandlingError(bytes err);
+ error EmptyReport();
+ error CursedByRMN(uint64 sourceChainSelector);
+ error NotACompatiblePool(address notPool);
+ error InvalidDataLength(uint256 expected, uint256 got);
+ error InvalidNewState(uint64 sourceChainSelector, uint64 sequenceNumber, Internal.MessageExecutionState newState);
+ error InvalidStaticConfig(uint64 sourceChainSelector);
+ error StaleCommitReport();
+ error InvalidInterval(uint64 sourceChainSelector, Interval interval);
+ error ZeroAddressNotAllowed();
+ error InvalidMessageDestChainSelector(uint64 messageDestChainSelector);
+
+ /// @dev Atlas depends on this event, if changing, please notify Atlas.
+ event StaticConfigSet(StaticConfig staticConfig);
+ event DynamicConfigSet(DynamicConfig dynamicConfig);
+ /// @dev RMN depends on this event, if changing, please notify the RMN maintainers.
+ event ExecutionStateChanged(
+ uint64 indexed sourceChainSelector,
+ uint64 indexed sequenceNumber,
+ bytes32 indexed messageId,
+ Internal.MessageExecutionState state,
+ bytes returnData
+ );
+ event SourceChainSelectorAdded(uint64 sourceChainSelector);
+ event SourceChainConfigSet(uint64 indexed sourceChainSelector, SourceChainConfig sourceConfig);
+ event SkippedAlreadyExecutedMessage(uint64 sourceChainSelector, uint64 sequenceNumber);
+ /// @dev RMN depends on this event, if changing, please notify the RMN maintainers.
+ event CommitReportAccepted(CommitReport report);
+ event RootRemoved(bytes32 root);
+
+ /// @notice Static offRamp config
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct StaticConfig {
+ uint64 chainSelector; // ───╮ Destination chainSelector
+ address rmnProxy; // ───────╯ RMN proxy address
+ address tokenAdminRegistry; // Token admin registry address
+ address nonceManager; // Address of the nonce manager
+ }
+
+ /// @notice Per-chain source config (defining a lane from a Source Chain -> Dest OffRamp)
+ struct SourceChainConfig {
+ bool isEnabled; // ──────────╮ Flag whether the source chain is enabled or not
+ uint64 minSeqNr; // ─────────╯ The min sequence number expected for future messages
+ bytes onRamp; // OnRamp address on the source chain
+ }
+
+ /// @notice SourceChainConfig update args scoped to one source chain
+ struct SourceChainConfigArgs {
+ uint64 sourceChainSelector; // ───╮ Source chain selector of the config to update
+ bool isEnabled; // ────────────────╯ Flag whether the source chain is enabled or not
+ bytes onRamp; // OnRamp address on the source chain
+ }
+
+ /// @notice Dynamic offRamp config
+ /// @dev since OffRampConfig is part of OffRampConfigChanged event, if changing it, we should update the ABI on Atlas
+ struct DynamicConfig {
+ address router; // ─────────────────────────────────╮ Router address
+ uint32 permissionLessExecutionThresholdSeconds; // │ Waiting time before manual execution is enabled
+ uint32 maxTokenTransferGas; // │ Maximum amount of gas passed on to token `transfer` call
+ uint32 maxPoolReleaseOrMintGas; // ─────────────────╯ Maximum amount of gas passed on to token pool when calling releaseOrMint
+ address messageValidator; // Optional message validator to validate incoming messages (zero address = no validator)
+ address priceRegistry; // Price registry address on the local chain
+ }
+
+ /// @notice a sequenceNumber interval
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct Interval {
+ uint64 min; // ───╮ Minimum sequence number, inclusive
+ uint64 max; // ───╯ Maximum sequence number, inclusive
+ }
+
+ /// @dev Struct to hold a merkle root and an interval for a source chain so that an array of these can be passed in the CommitReport.
+ struct MerkleRoot {
+ uint64 sourceChainSelector; // Remote source chain selector that the Merkle Root is scoped to
+ Interval interval; // Report interval of the merkle root
+ bytes32 merkleRoot; // Merkle root covering the interval & source chain messages
+ }
+
+ /// @notice Report that is committed by the observing DON at the committing phase
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ struct CommitReport {
+ Internal.PriceUpdates priceUpdates; // Collection of gas and price updates to commit
+ MerkleRoot[] merkleRoots; // Collection of merkle roots per source chain to commit
+ }
+
+ /// @dev Struct to hold a merkle root for a source chain so that an array of these can be passed in the resetUblessedRoots function.
+ struct UnblessedRoot {
+ uint64 sourceChainSelector; // Remote source chain selector that the Merkle Root is scoped to
+ bytes32 merkleRoot; // Merkle root of a single remote source chain
+ }
+
+ // STATIC CONFIG
+ string public constant override typeAndVersion = "EVM2EVMMultiOffRamp 1.6.0-dev";
+ /// @dev ChainSelector of this chain
+ uint64 internal immutable i_chainSelector;
+ /// @dev The address of the RMN proxy
+ address internal immutable i_rmnProxy;
+ /// @dev The address of the token admin registry
+ address internal immutable i_tokenAdminRegistry;
+ /// @dev The address of the nonce manager
+ address internal immutable i_nonceManager;
+
+ // DYNAMIC CONFIG
+ DynamicConfig internal s_dynamicConfig;
+
+ /// @notice SourceConfig per chain
+ /// (forms lane configurations from sourceChainSelector => StaticConfig.chainSelector)
+ mapping(uint64 sourceChainSelector => SourceChainConfig sourceChainConfig) internal s_sourceChainConfigs;
+
+ // STATE
+ /// @dev A mapping of sequence numbers (per source chain) to execution state using a bitmap with each execution
+ /// state only taking up 2 bits of the uint256, packing 128 states into a single slot.
+ /// Message state is tracked to ensure message can only be executed successfully once.
+ mapping(uint64 sourceChainSelector => mapping(uint64 seqNum => uint256 executionStateBitmap)) internal
+ s_executionStates;
+
+ // sourceChainSelector => merkleRoot => timestamp when received
+ mapping(uint64 sourceChainSelector => mapping(bytes32 merkleRoot => uint256 timestamp)) internal s_roots;
+ /// @dev The sequence number of the last price update
+ uint64 private s_latestPriceSequenceNumber;
+
+ constructor(
+ StaticConfig memory staticConfig,
+ DynamicConfig memory dynamicConfig,
+ SourceChainConfigArgs[] memory sourceChainConfigs
+ ) MultiOCR3Base() {
+ if (
+ staticConfig.rmnProxy == address(0) || staticConfig.tokenAdminRegistry == address(0)
+ || staticConfig.nonceManager == address(0)
+ ) {
+ revert ZeroAddressNotAllowed();
+ }
+
+ if (staticConfig.chainSelector == 0) {
+ revert ZeroChainSelectorNotAllowed();
+ }
+
+ i_chainSelector = staticConfig.chainSelector;
+ i_rmnProxy = staticConfig.rmnProxy;
+ i_tokenAdminRegistry = staticConfig.tokenAdminRegistry;
+ i_nonceManager = staticConfig.nonceManager;
+ emit StaticConfigSet(staticConfig);
+
+ _setDynamicConfig(dynamicConfig);
+ _applySourceChainConfigUpdates(sourceChainConfigs);
+ }
+
+ // ================================================================
+ // │ Messaging │
+ // ================================================================
+
+ // The size of the execution state in bits
+ uint256 private constant MESSAGE_EXECUTION_STATE_BIT_WIDTH = 2;
+ // The mask for the execution state bits
+ uint256 private constant MESSAGE_EXECUTION_STATE_MASK = (1 << MESSAGE_EXECUTION_STATE_BIT_WIDTH) - 1;
+
+ // ================================================================
+ // │ Execution │
+ // ================================================================
+
+ /// @notice Returns the current execution state of a message based on its sequenceNumber.
+ /// @param sourceChainSelector The source chain to get the execution state for
+ /// @param sequenceNumber The sequence number of the message to get the execution state for.
+ /// @return The current execution state of the message.
+ /// @dev we use the literal number 128 because using a constant increased gas usage.
+ function getExecutionState(
+ uint64 sourceChainSelector,
+ uint64 sequenceNumber
+ ) public view returns (Internal.MessageExecutionState) {
+ return Internal.MessageExecutionState(
+ (
+ _getSequenceNumberBitmap(sourceChainSelector, sequenceNumber)
+ >> ((sequenceNumber % 128) * MESSAGE_EXECUTION_STATE_BIT_WIDTH)
+ ) & MESSAGE_EXECUTION_STATE_MASK
+ );
+ }
+
+ /// @notice Sets a new execution state for a given sequence number. It will overwrite any existing state.
+ /// @param sourceChainSelector The source chain to set the execution state for
+ /// @param sequenceNumber The sequence number for which the state will be saved.
+ /// @param newState The new value the state will be in after this function is called.
+ /// @dev we use the literal number 128 because using a constant increased gas usage.
+ function _setExecutionState(
+ uint64 sourceChainSelector,
+ uint64 sequenceNumber,
+ Internal.MessageExecutionState newState
+ ) internal {
+ uint256 offset = (sequenceNumber % 128) * MESSAGE_EXECUTION_STATE_BIT_WIDTH;
+ uint256 bitmap = _getSequenceNumberBitmap(sourceChainSelector, sequenceNumber);
+ // to unset any potential existing state we zero the bits of the section the state occupies,
+ // then we do an AND operation to blank out any existing state for the section.
+ bitmap &= ~(MESSAGE_EXECUTION_STATE_MASK << offset);
+ // Set the new state
+ bitmap |= uint256(newState) << offset;
+
+ s_executionStates[sourceChainSelector][sequenceNumber / 128] = bitmap;
+ }
+
+ /// @param sourceChainSelector remote source chain selector to get sequence number bitmap for
+ /// @param sequenceNumber sequence number to get bitmap for
+ /// @return bitmap Bitmap of the given sequence number for the provided source chain selector. One bitmap represents 128 sequence numbers
+ function _getSequenceNumberBitmap(
+ uint64 sourceChainSelector,
+ uint64 sequenceNumber
+ ) internal view returns (uint256 bitmap) {
+ return s_executionStates[sourceChainSelector][sequenceNumber / 128];
+ }
+
+ /// @notice Manually executes a set of reports.
+ /// @param reports Internal.ExecutionReportSingleChain[] - list of reports to execute
+ /// @param gasLimitOverrides New gasLimit for each message per report
+ // The outer array represents each report, inner array represents each message in the report.
+ // i.e. gasLimitOverrides[report1][report1Message1] -> access message1 from report1
+ /// @dev We permit gas limit overrides so that users may manually execute messages which failed due to
+ /// insufficient gas provided.
+ /// The reports do not have to contain all the messages (they can be omitted). Multiple reports can be passed in simultaneously.
+ function manuallyExecute(
+ Internal.ExecutionReportSingleChain[] memory reports,
+ uint256[][] memory gasLimitOverrides
+ ) external {
+ // We do this here because the other _execute path is already covered by MultiOCR3Base.
+ _whenChainNotForked();
+
+ uint256 numReports = reports.length;
+ if (numReports != gasLimitOverrides.length) revert ManualExecutionGasLimitMismatch();
+
+ for (uint256 reportIndex = 0; reportIndex < numReports; ++reportIndex) {
+ Internal.ExecutionReportSingleChain memory report = reports[reportIndex];
+
+ uint256 numMsgs = report.messages.length;
+ uint256[] memory msgGasLimitOverrides = gasLimitOverrides[reportIndex];
+ if (numMsgs != msgGasLimitOverrides.length) revert ManualExecutionGasLimitMismatch();
+
+ for (uint256 msgIndex = 0; msgIndex < numMsgs; ++msgIndex) {
+ uint256 newLimit = msgGasLimitOverrides[msgIndex];
+ // Checks to ensure message cannot be executed with less gas than specified.
+ if (newLimit != 0) {
+ if (newLimit < report.messages[msgIndex].gasLimit) {
+ revert InvalidManualExecutionGasLimit(report.sourceChainSelector, msgIndex, newLimit);
+ }
+ }
+ }
+ }
+
+ _batchExecute(reports, gasLimitOverrides);
+ }
+
+ /// @notice Transmit function for execution reports. The function takes no signatures,
+ /// and expects the exec plugin type to be configured with no signatures.
+ /// @param report serialized execution report
+ function execute(bytes32[3] calldata reportContext, bytes calldata report) external {
+ _batchExecute(abi.decode(report, (Internal.ExecutionReportSingleChain[])), new uint256[][](0));
+
+ bytes32[] memory emptySigs = new bytes32[](0);
+ _transmit(uint8(Internal.OCRPluginType.Execution), reportContext, report, emptySigs, emptySigs, bytes32(""));
+ }
+
+ /// @notice Batch executes a set of reports, each report matching one single source chain
+ /// @param reports Set of execution reports (one per chain) containing the messages and proofs
+ /// @param manualExecGasLimits An array of gas limits to use for manual execution
+ // The outer array represents each report, inner array represents each message in the report.
+ // i.e. gasLimitOverrides[report1][report1Message1] -> access message1 from report1
+ /// @dev The manualExecGasLimits array should either be empty, or match the length of the reports array
+ /// @dev If called from manual execution, each inner array's length has to match the number of messages.
+ function _batchExecute(
+ Internal.ExecutionReportSingleChain[] memory reports,
+ uint256[][] memory manualExecGasLimits
+ ) internal {
+ if (reports.length == 0) revert EmptyReport();
+
+ bool areManualGasLimitsEmpty = manualExecGasLimits.length == 0;
+ // Cache array for gas savings in the loop's condition
+ uint256[] memory emptyGasLimits = new uint256[](0);
+
+ for (uint256 i = 0; i < reports.length; ++i) {
+ _executeSingleReport(reports[i], areManualGasLimitsEmpty ? emptyGasLimits : manualExecGasLimits[i]);
+ }
+ }
+
+ /// @notice Executes a report, executing each message in order.
+ /// @param report The execution report containing the messages and proofs.
+ /// @param manualExecGasLimits An array of gas limits to use for manual execution.
+ /// @dev If called from the DON, this array is always empty.
+ /// @dev If called from manual execution, this array is always same length as messages.
+ function _executeSingleReport(
+ Internal.ExecutionReportSingleChain memory report,
+ uint256[] memory manualExecGasLimits
+ ) internal {
+ uint64 sourceChainSelector = report.sourceChainSelector;
+ _whenNotCursed(sourceChainSelector);
+
+ SourceChainConfig storage sourceChainConfig = _getEnabledSourceChainConfig(sourceChainSelector);
+
+ uint256 numMsgs = report.messages.length;
+ if (numMsgs == 0) revert EmptyReport();
+ if (numMsgs != report.offchainTokenData.length) revert UnexpectedTokenData();
+
+ bytes32[] memory hashedLeaves = new bytes32[](numMsgs);
+
+ for (uint256 i = 0; i < numMsgs; ++i) {
+ Internal.Any2EVMRampMessage memory message = report.messages[i];
+
+ // Commits do not verify the destChainSelector in the message, since only the root is committed,
+ // so we have to check it explicitly
+ if (message.header.destChainSelector != i_chainSelector) {
+ revert InvalidMessageDestChainSelector(message.header.destChainSelector);
+ }
+
+ // We do this hash here instead of in _verifyMessages to avoid two separate loops
+ // over the same data, which increases gas cost.
+ // Hashing all of the message fields ensures that the message being executed is correct and not tampered with.
+ // Including the known OnRamp ensures that the message originates from the correct on ramp version
+ hashedLeaves[i] = Internal._hash(message, sourceChainConfig.onRamp);
+ }
+
+ // SECURITY CRITICAL CHECK
+ // NOTE: This check also verifies that all messages match the report's sourceChainSelector
+ uint256 timestampCommitted = _verify(sourceChainSelector, hashedLeaves, report.proofs, report.proofFlagBits);
+ if (timestampCommitted == 0) revert RootNotCommitted(sourceChainSelector);
+
+ // Execute messages
+ bool manualExecution = manualExecGasLimits.length != 0;
+ for (uint256 i = 0; i < numMsgs; ++i) {
+ Internal.Any2EVMRampMessage memory message = report.messages[i];
+
+ Internal.MessageExecutionState originalState =
+ getExecutionState(sourceChainSelector, message.header.sequenceNumber);
+ if (originalState == Internal.MessageExecutionState.SUCCESS) {
+ // If the message has already been executed, we skip it. We want to not revert on race conditions between
+ // executing parties. This will allow us to open up manual exec while also attempting with the DON, without
+ // reverting an entire DON batch when a user manually executes while the tx is inflight.
+ emit SkippedAlreadyExecutedMessage(sourceChainSelector, message.header.sequenceNumber);
+ continue;
+ }
+ // Two valid cases here, we either have never touched this message before, or we tried to execute
+ // and failed. This check protects against reentry and re-execution because the other state is
+ // IN_PROGRESS which should not be allowed to execute.
+ if (
+ !(
+ originalState == Internal.MessageExecutionState.UNTOUCHED
+ || originalState == Internal.MessageExecutionState.FAILURE
+ )
+ ) revert AlreadyExecuted(sourceChainSelector, message.header.sequenceNumber);
+
+ if (manualExecution) {
+ bool isOldCommitReport =
+ (block.timestamp - timestampCommitted) > s_dynamicConfig.permissionLessExecutionThresholdSeconds;
+ // Manually execution is fine if we previously failed or if the commit report is just too old
+ // Acceptable state transitions: FAILURE->SUCCESS, UNTOUCHED->SUCCESS, FAILURE->FAILURE
+ if (!(isOldCommitReport || originalState == Internal.MessageExecutionState.FAILURE)) {
+ revert ManualExecutionNotYetEnabled(sourceChainSelector);
+ }
+
+ // Manual execution gas limit can override gas limit specified in the message. Value of 0 indicates no override.
+ if (manualExecGasLimits[i] != 0) {
+ message.gasLimit = manualExecGasLimits[i];
+ }
+ } else {
+ // DON can only execute a message once
+ // Acceptable state transitions: UNTOUCHED->SUCCESS, UNTOUCHED->FAILURE
+ if (originalState != Internal.MessageExecutionState.UNTOUCHED) {
+ revert AlreadyAttempted(sourceChainSelector, message.header.sequenceNumber);
+ }
+ }
+
+ // Nonce changes per state transition (these only apply for ordered messages):
+ // UNTOUCHED -> FAILURE nonce bump
+ // UNTOUCHED -> SUCCESS nonce bump
+ // FAILURE -> FAILURE no nonce bump
+ // FAILURE -> SUCCESS no nonce bump
+ // UNTOUCHED messages MUST be executed in order always
+ if (message.header.nonce != 0) {
+ if (originalState == Internal.MessageExecutionState.UNTOUCHED) {
+ // If a nonce is not incremented, that means it was skipped, and we can ignore the message
+ if (
+ !INonceManager(i_nonceManager).incrementInboundNonce(
+ sourceChainSelector, message.header.nonce, message.sender
+ )
+ ) continue;
+ }
+ }
+
+ // Although we expect only valid messages will be committed, we check again
+ // when executing as a defense in depth measure.
+ bytes[] memory offchainTokenData = report.offchainTokenData[i];
+ if (message.tokenAmounts.length != offchainTokenData.length) {
+ revert TokenDataMismatch(sourceChainSelector, message.header.sequenceNumber);
+ }
+
+ _setExecutionState(sourceChainSelector, message.header.sequenceNumber, Internal.MessageExecutionState.IN_PROGRESS);
+
+ (Internal.MessageExecutionState newState, bytes memory returnData) = _trialExecute(message, offchainTokenData);
+ _setExecutionState(sourceChainSelector, message.header.sequenceNumber, newState);
+
+ // Since it's hard to estimate whether manual execution will succeed, we
+ // revert the entire transaction if it fails. This will show the user if
+ // their manual exec will fail before they submit it.
+ if (manualExecution) {
+ if (newState == Internal.MessageExecutionState.FAILURE) {
+ if (originalState != Internal.MessageExecutionState.UNTOUCHED) {
+ // If manual execution fails, we revert the entire transaction, unless the originalState is UNTOUCHED as we
+ // would still be making progress by changing the state from UNTOUCHED to FAILURE.
+ revert ExecutionError(message.header.messageId, returnData);
+ }
+ }
+ }
+
+ // The only valid prior states are UNTOUCHED and FAILURE (checked above)
+ // The only valid post states are FAILURE and SUCCESS (checked below)
+ if (newState != Internal.MessageExecutionState.SUCCESS) {
+ if (newState != Internal.MessageExecutionState.FAILURE) {
+ revert InvalidNewState(sourceChainSelector, message.header.sequenceNumber, newState);
+ }
+ }
+
+ emit ExecutionStateChanged(
+ sourceChainSelector, message.header.sequenceNumber, message.header.messageId, newState, returnData
+ );
+ }
+ }
+
+ /// @notice Try executing a message.
+ /// @param message Internal.Any2EVMRampMessage memory message.
+ /// @param offchainTokenData Data provided by the DON for token transfers.
+ /// @return the new state of the message, being either SUCCESS or FAILURE.
+ /// @return revert data in bytes if CCIP receiver reverted during execution.
+ function _trialExecute(
+ Internal.Any2EVMRampMessage memory message,
+ bytes[] memory offchainTokenData
+ ) internal returns (Internal.MessageExecutionState, bytes memory) {
+ try this.executeSingleMessage(message, offchainTokenData) {}
+ catch (bytes memory err) {
+ // return the message execution state as FAILURE and the revert data
+ // Max length of revert data is Router.MAX_RET_BYTES, max length of err is 4 + Router.MAX_RET_BYTES
+ return (Internal.MessageExecutionState.FAILURE, err);
+ }
+ // If message execution succeeded, no CCIP receiver return data is expected, return with empty bytes.
+ return (Internal.MessageExecutionState.SUCCESS, "");
+ }
+
+ /// @notice Execute a single message.
+ /// @param message The message that will be executed.
+ /// @param offchainTokenData Token transfer data to be passed to TokenPool.
+ /// @dev We make this external and callable by the contract itself, in order to try/catch
+ /// its execution and enforce atomicity among successful message processing and token transfer.
+ /// @dev We use ERC-165 to check for the ccipReceive interface to permit sending tokens to contracts
+ /// (for example smart contract wallets) without an associated message.
+ function executeSingleMessage(Internal.Any2EVMRampMessage memory message, bytes[] memory offchainTokenData) external {
+ if (msg.sender != address(this)) revert CanOnlySelfCall();
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](0);
+ if (message.tokenAmounts.length > 0) {
+ destTokenAmounts = _releaseOrMintTokens(
+ message.tokenAmounts, message.sender, message.receiver, message.header.sourceChainSelector, offchainTokenData
+ );
+ }
+
+ Client.Any2EVMMessage memory any2EvmMessage = Client.Any2EVMMessage({
+ messageId: message.header.messageId,
+ sourceChainSelector: message.header.sourceChainSelector,
+ sender: abi.encode(message.sender),
+ data: message.data,
+ destTokenAmounts: destTokenAmounts
+ });
+
+ address messageValidator = s_dynamicConfig.messageValidator;
+ if (messageValidator != address(0)) {
+ try IMessageInterceptor(messageValidator).onInboundMessage(any2EvmMessage) {}
+ catch (bytes memory err) {
+ revert IMessageInterceptor.MessageValidationError(err);
+ }
+ }
+
+ // There are three cases in which we skip calling the receiver:
+ // 1. If the message data is empty AND the gas limit is 0.
+ // This indicates a message that only transfers tokens. It is valid to only send tokens to a contract
+ // that supports the IAny2EVMMessageReceiver interface, but without this first check we would call the
+ // receiver without any gas, which would revert the transaction.
+ // 2. If the receiver is not a contract.
+ // 3. If the receiver is a contract but it does not support the IAny2EVMMessageReceiver interface.
+ //
+ // The ordering of these checks is important, as the first check is the cheapest to execute.
+ if (
+ (message.data.length == 0 && message.gasLimit == 0) || message.receiver.code.length == 0
+ || !message.receiver.supportsInterface(type(IAny2EVMMessageReceiver).interfaceId)
+ ) return;
+
+ (bool success, bytes memory returnData,) = IRouter(s_dynamicConfig.router).routeMessage(
+ any2EvmMessage, Internal.GAS_FOR_CALL_EXACT_CHECK, message.gasLimit, message.receiver
+ );
+ // If CCIP receiver execution is not successful, revert the call including token transfers
+ if (!success) revert ReceiverError(returnData);
+ }
+
+ // ================================================================
+ // │ Commit │
+ // ================================================================
+
+ /// @notice Transmit function for commit reports. The function requires signatures,
+ /// and expects the commit plugin type to be configured with signatures.
+ /// @param report serialized commit report
+ /// @dev A commitReport can have two distinct parts (batched together to amortize the cost of checking sigs):
+ /// 1. Price updates
+ /// 2. A batch of merkle root and sequence number intervals (per-source)
+ /// Both have their own, separate, staleness checks, with price updates using the epoch and round
+ /// number of the latest price update. The merkle root checks for staleness based on the seqNums.
+ /// They need to be separate because a price report for round t+2 might be included before a report
+ /// containing a merkle root for round t+1. This merkle root report for round t+1 is still valid
+ /// and should not be rejected. When a report with a stale root but valid price updates is submitted,
+ /// we are OK to revert to preserve the invariant that we always revert on invalid sequence number ranges.
+ /// If that happens, prices will be updates in later rounds.
+ function commit(
+ bytes32[3] calldata reportContext,
+ bytes calldata report,
+ bytes32[] calldata rs,
+ bytes32[] calldata ss,
+ bytes32 rawVs // signatures
+ ) external {
+ CommitReport memory commitReport = abi.decode(report, (CommitReport));
+
+ // Check if the report contains price updates
+ if (commitReport.priceUpdates.tokenPriceUpdates.length > 0 || commitReport.priceUpdates.gasPriceUpdates.length > 0)
+ {
+ uint64 sequenceNumber = uint64(uint256(reportContext[1]));
+
+ // Check for price staleness based on the epoch and round
+ if (s_latestPriceSequenceNumber < sequenceNumber) {
+ // If prices are not stale, update the latest epoch and round
+ s_latestPriceSequenceNumber = sequenceNumber;
+ // And update the prices in the price registry
+ IPriceRegistry(s_dynamicConfig.priceRegistry).updatePrices(commitReport.priceUpdates);
+ } else {
+ // If prices are stale and the report doesn't contain a root, this report
+ // does not have any valid information and we revert.
+ // If it does contain a merkle root, continue to the root checking section.
+ if (commitReport.merkleRoots.length == 0) revert StaleCommitReport();
+ }
+ }
+
+ for (uint256 i = 0; i < commitReport.merkleRoots.length; ++i) {
+ MerkleRoot memory root = commitReport.merkleRoots[i];
+ uint64 sourceChainSelector = root.sourceChainSelector;
+
+ _whenNotCursed(sourceChainSelector);
+ SourceChainConfig storage sourceChainConfig = _getEnabledSourceChainConfig(sourceChainSelector);
+
+ // If we reached this section, the report should contain a valid root
+ if (sourceChainConfig.minSeqNr != root.interval.min || root.interval.min > root.interval.max) {
+ revert InvalidInterval(root.sourceChainSelector, root.interval);
+ }
+
+ // TODO: confirm how RMN offchain blessing impacts commit report
+ bytes32 merkleRoot = root.merkleRoot;
+ if (merkleRoot == bytes32(0)) revert InvalidRoot();
+ // Disallow duplicate roots as that would reset the timestamp and
+ // delay potential manual execution.
+ if (s_roots[root.sourceChainSelector][merkleRoot] != 0) {
+ revert RootAlreadyCommitted(root.sourceChainSelector, merkleRoot);
+ }
+
+ sourceChainConfig.minSeqNr = root.interval.max + 1;
+ s_roots[root.sourceChainSelector][merkleRoot] = block.timestamp;
+ }
+
+ emit CommitReportAccepted(commitReport);
+
+ _transmit(uint8(Internal.OCRPluginType.Commit), reportContext, report, rs, ss, rawVs);
+ }
+
+ /// @notice Returns the sequence number of the last price update.
+ /// @return the latest price update sequence number.
+ function getLatestPriceSequenceNumber() public view returns (uint64) {
+ return s_latestPriceSequenceNumber;
+ }
+
+ /// @notice Returns the timestamp of a potentially previously committed merkle root.
+ /// If the root was never committed 0 will be returned.
+ /// @param sourceChainSelector The source chain selector.
+ /// @param root The merkle root to check the commit status for.
+ /// @return the timestamp of the committed root or zero in the case that it was never
+ /// committed.
+ function getMerkleRoot(uint64 sourceChainSelector, bytes32 root) external view returns (uint256) {
+ return s_roots[sourceChainSelector][root];
+ }
+
+ /// @notice Returns if a root is blessed or not.
+ /// @param root The merkle root to check the blessing status for.
+ /// @return whether the root is blessed or not.
+ function isBlessed(bytes32 root) public view returns (bool) {
+ // TODO: update RMN to also consider the source chain selector for blessing
+ return IRMN(i_rmnProxy).isBlessed(IRMN.TaggedRoot({commitStore: address(this), root: root}));
+ }
+
+ /// @notice Used by the owner in case an invalid sequence of roots has been
+ /// posted and needs to be removed. The interval in the report is trusted.
+ /// @param rootToReset The roots that will be reset. This function will only
+ /// reset roots that are not blessed.
+ function resetUnblessedRoots(UnblessedRoot[] calldata rootToReset) external onlyOwner {
+ for (uint256 i = 0; i < rootToReset.length; ++i) {
+ UnblessedRoot memory root = rootToReset[i];
+ if (!isBlessed(root.merkleRoot)) {
+ delete s_roots[root.sourceChainSelector][root.merkleRoot];
+ emit RootRemoved(root.merkleRoot);
+ }
+ }
+ }
+
+ /// @notice Returns timestamp of when root was accepted or 0 if verification fails.
+ /// @dev This method uses a merkle tree within a merkle tree, with the hashedLeaves,
+ /// proofs and proofFlagBits being used to get the root of the inner tree.
+ /// This root is then used as the singular leaf of the outer tree.
+ function _verify(
+ uint64 sourceChainSelector,
+ bytes32[] memory hashedLeaves,
+ bytes32[] memory proofs,
+ uint256 proofFlagBits
+ ) internal view virtual returns (uint256 timestamp) {
+ bytes32 root = MerkleMultiProof.merkleRoot(hashedLeaves, proofs, proofFlagBits);
+ // Only return non-zero if present and blessed.
+ if (!isBlessed(root)) {
+ return 0;
+ }
+ return s_roots[sourceChainSelector][root];
+ }
+
+ /// @inheritdoc MultiOCR3Base
+ function _afterOCR3ConfigSet(uint8 ocrPluginType) internal override {
+ if (ocrPluginType == uint8(Internal.OCRPluginType.Commit)) {
+ // When the OCR config changes, we reset the sequence number
+ // since it is scoped per config digest.
+ // Note that s_minSeqNr/roots do not need to be reset as the roots persist
+ // across reconfigurations and are de-duplicated separately.
+ s_latestPriceSequenceNumber = 0;
+ }
+ }
+
+ // ================================================================
+ // │ Config │
+ // ================================================================
+
+ /// @notice Returns the static config.
+ /// @dev This function will always return the same struct as the contents is static and can never change.
+ /// RMN depends on this function, if changing, please notify the RMN maintainers.
+ function getStaticConfig() external view returns (StaticConfig memory) {
+ return StaticConfig({
+ chainSelector: i_chainSelector,
+ rmnProxy: i_rmnProxy,
+ tokenAdminRegistry: i_tokenAdminRegistry,
+ nonceManager: i_nonceManager
+ });
+ }
+
+ /// @notice Returns the current dynamic config.
+ /// @return The current config.
+ function getDynamicConfig() external view returns (DynamicConfig memory) {
+ return s_dynamicConfig;
+ }
+
+ /// @notice Returns the source chain config for the provided source chain selector
+ /// @param sourceChainSelector chain to retrieve configuration for
+ /// @return SourceChainConfig config for the source chain
+ function getSourceChainConfig(uint64 sourceChainSelector) external view returns (SourceChainConfig memory) {
+ return s_sourceChainConfigs[sourceChainSelector];
+ }
+
+ /// @notice Updates source configs
+ /// @param sourceChainConfigUpdates Source chain configs
+ function applySourceChainConfigUpdates(SourceChainConfigArgs[] memory sourceChainConfigUpdates) external onlyOwner {
+ _applySourceChainConfigUpdates(sourceChainConfigUpdates);
+ }
+
+ /// @notice Updates source configs
+ /// @param sourceChainConfigUpdates Source chain configs
+ function _applySourceChainConfigUpdates(SourceChainConfigArgs[] memory sourceChainConfigUpdates) internal {
+ for (uint256 i = 0; i < sourceChainConfigUpdates.length; ++i) {
+ SourceChainConfigArgs memory sourceConfigUpdate = sourceChainConfigUpdates[i];
+ uint64 sourceChainSelector = sourceConfigUpdate.sourceChainSelector;
+
+ if (sourceChainSelector == 0) {
+ revert ZeroChainSelectorNotAllowed();
+ }
+
+ SourceChainConfig storage currentConfig = s_sourceChainConfigs[sourceChainSelector];
+ bytes memory currentOnRamp = currentConfig.onRamp;
+ bytes memory newOnRamp = sourceConfigUpdate.onRamp;
+
+ // OnRamp can never be zero - if it is, then the source chain has been added for the first time
+ if (currentOnRamp.length == 0) {
+ if (newOnRamp.length == 0) {
+ revert ZeroAddressNotAllowed();
+ }
+
+ currentConfig.onRamp = newOnRamp;
+ currentConfig.minSeqNr = 1;
+ emit SourceChainSelectorAdded(sourceChainSelector);
+ } else if (keccak256(currentOnRamp) != keccak256(newOnRamp)) {
+ revert InvalidStaticConfig(sourceChainSelector);
+ }
+
+ // The only dynamic config is the isEnabled flag
+ currentConfig.isEnabled = sourceConfigUpdate.isEnabled;
+ emit SourceChainConfigSet(sourceChainSelector, currentConfig);
+ }
+ }
+
+ /// @notice Sets the dynamic config.
+ /// @param dynamicConfig The new dynamic config.
+ function setDynamicConfig(DynamicConfig memory dynamicConfig) external onlyOwner {
+ _setDynamicConfig(dynamicConfig);
+ }
+
+ /// @notice Sets the dynamic config.
+ /// @param dynamicConfig The dynamic config.
+ function _setDynamicConfig(DynamicConfig memory dynamicConfig) internal {
+ if (dynamicConfig.priceRegistry == address(0) || dynamicConfig.router == address(0)) {
+ revert ZeroAddressNotAllowed();
+ }
+
+ s_dynamicConfig = dynamicConfig;
+
+ emit DynamicConfigSet(dynamicConfig);
+ }
+
+ /// @notice Returns a source chain config with a check that the config is enabled
+ /// @param sourceChainSelector Source chain selector to check for cursing
+ /// @return sourceChainConfig Source chain config
+ function _getEnabledSourceChainConfig(uint64 sourceChainSelector) internal view returns (SourceChainConfig storage) {
+ SourceChainConfig storage sourceChainConfig = s_sourceChainConfigs[sourceChainSelector];
+ if (!sourceChainConfig.isEnabled) {
+ revert SourceChainNotEnabled(sourceChainSelector);
+ }
+
+ return sourceChainConfig;
+ }
+
+ // ================================================================
+ // │ Tokens and pools │
+ // ================================================================
+
+ /// @notice Uses a pool to release or mint a token to a receiver address in two steps. First, the pool is called
+ /// to release the tokens to the offRamp, then the offRamp calls the token contract to transfer the tokens to the
+ /// receiver. This is done to ensure the exact number of tokens, the pool claims to release are actually transferred.
+ /// @dev The local token address is validated through the TokenAdminRegistry. If, due to some misconfiguration, the
+ /// token is unknown to the registry, the offRamp will revert. The tx, and the tokens, can be retrieved by
+ /// registering the token on this chain, and re-trying the msg.
+ /// @param sourceTokenAmount Amount and source data of the token to be released/minted.
+ /// @param originalSender The message sender on the source chain.
+ /// @param receiver The address that will receive the tokens.
+ /// @param sourceChainSelector The remote source chain selector
+ /// @param offchainTokenData Data fetched offchain by the DON.
+ /// @return destTokenAmount local token address with amount
+ function _releaseOrMintSingleToken(
+ Internal.RampTokenAmount memory sourceTokenAmount,
+ bytes memory originalSender,
+ address receiver,
+ uint64 sourceChainSelector,
+ bytes memory offchainTokenData
+ ) internal returns (Client.EVMTokenAmount memory destTokenAmount) {
+ // We need to safely decode the token address from the sourceTokenData, as it could be wrong,
+ // in which case it doesn't have to be a valid EVM address.
+ address localToken = Internal._validateEVMAddress(sourceTokenAmount.destTokenAddress);
+ // We check with the token admin registry if the token has a pool on this chain.
+ address localPoolAddress = ITokenAdminRegistry(i_tokenAdminRegistry).getPool(localToken);
+ // This will call the supportsInterface through the ERC165Checker, and not directly on the pool address.
+ // This is done to prevent a pool from reverting the entire transaction if it doesn't support the interface.
+ // The call gets a max or 30k gas per instance, of which there are three. This means gas estimations should
+ // account for 90k gas overhead due to the interface check.
+ if (localPoolAddress == address(0) || !localPoolAddress.supportsInterface(Pool.CCIP_POOL_V1)) {
+ revert NotACompatiblePool(localPoolAddress);
+ }
+
+ // We determined that the pool address is a valid EVM address, but that does not mean the code at this
+ // address is a (compatible) pool contract. _callWithExactGasSafeReturnData will check if the location
+ // contains a contract. If it doesn't it reverts with a known error, which we catch gracefully.
+ // We call the pool with exact gas to increase resistance against malicious tokens or token pools.
+ // We protects against return data bombs by capping the return data size at MAX_RET_BYTES.
+ (bool success, bytes memory returnData,) = CallWithExactGas._callWithExactGasSafeReturnData(
+ abi.encodeCall(
+ IPoolV1.releaseOrMint,
+ Pool.ReleaseOrMintInV1({
+ originalSender: originalSender,
+ receiver: receiver,
+ amount: sourceTokenAmount.amount,
+ localToken: localToken,
+ remoteChainSelector: sourceChainSelector,
+ sourcePoolAddress: sourceTokenAmount.sourcePoolAddress,
+ sourcePoolData: sourceTokenAmount.extraData,
+ offchainTokenData: offchainTokenData
+ })
+ ),
+ localPoolAddress,
+ s_dynamicConfig.maxPoolReleaseOrMintGas,
+ Internal.GAS_FOR_CALL_EXACT_CHECK,
+ Internal.MAX_RET_BYTES
+ );
+
+ // wrap and rethrow the error so we can catch it lower in the stack
+ if (!success) revert TokenHandlingError(returnData);
+
+ // If the call was successful, the returnData should be the local token address.
+ if (returnData.length != Pool.CCIP_POOL_V1_RET_BYTES) {
+ revert InvalidDataLength(Pool.CCIP_POOL_V1_RET_BYTES, returnData.length);
+ }
+ uint256 localAmount = abi.decode(returnData, (uint256));
+ // Since token pools send the tokens to the msg.sender, which is this offRamp, we need to
+ // transfer them to the final receiver. We use the _callWithExactGasSafeReturnData function because
+ // the token contracts are not considered trusted.
+ (success, returnData,) = CallWithExactGas._callWithExactGasSafeReturnData(
+ abi.encodeCall(IERC20.transfer, (receiver, localAmount)),
+ localToken,
+ s_dynamicConfig.maxTokenTransferGas,
+ Internal.GAS_FOR_CALL_EXACT_CHECK,
+ Internal.MAX_RET_BYTES
+ );
+
+ if (!success) revert TokenHandlingError(returnData);
+
+ return Client.EVMTokenAmount({token: localToken, amount: localAmount});
+ }
+
+ /// @notice Uses pools to release or mint a number of different tokens to a receiver address.
+ /// @param sourceTokenAmounts List of token amounts with source data of the tokens to be released/minted.
+ /// @param originalSender The message sender on the source chain.
+ /// @param receiver The address that will receive the tokens.
+ /// @param sourceChainSelector The remote source chain selector
+ /// @param offchainTokenData Array of token data fetched offchain by the DON.
+ /// @return destTokenAmounts local token addresses with amounts
+ /// @dev This function wrappes the token pool call in a try catch block to gracefully handle
+ /// any non-rate limiting errors that may occur. If we encounter a rate limiting related error
+ /// we bubble it up. If we encounter a non-rate limiting error we wrap it in a TokenHandlingError.
+ function _releaseOrMintTokens(
+ Internal.RampTokenAmount[] memory sourceTokenAmounts,
+ bytes memory originalSender,
+ address receiver,
+ uint64 sourceChainSelector,
+ bytes[] memory offchainTokenData
+ ) internal returns (Client.EVMTokenAmount[] memory destTokenAmounts) {
+ destTokenAmounts = new Client.EVMTokenAmount[](sourceTokenAmounts.length);
+ for (uint256 i = 0; i < sourceTokenAmounts.length; ++i) {
+ destTokenAmounts[i] = _releaseOrMintSingleToken(
+ sourceTokenAmounts[i], originalSender, receiver, sourceChainSelector, offchainTokenData[i]
+ );
+ }
+
+ return destTokenAmounts;
+ }
+
+ // ================================================================
+ // │ Access and RMN │
+ // ================================================================
+
+ /// @notice Reverts as this contract should not access CCIP messages
+ function ccipReceive(Client.Any2EVMMessage calldata) external pure {
+ // solhint-disable-next-line
+ revert();
+ }
+
+ /// @notice Validates that the source chain -> this chain lane, and reverts if it is cursed
+ /// @param sourceChainSelector Source chain selector to check for cursing
+ function _whenNotCursed(uint64 sourceChainSelector) internal view {
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(sourceChainSelector)))) {
+ revert CursedByRMN(sourceChainSelector);
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol b/contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol
new file mode 100644
index 00000000000..1aec436ef8c
--- /dev/null
+++ b/contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol
@@ -0,0 +1,721 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol";
+import {IAny2EVMOffRamp} from "../interfaces/IAny2EVMOffRamp.sol";
+import {ICommitStore} from "../interfaces/ICommitStore.sol";
+import {IPoolV1} from "../interfaces/IPool.sol";
+import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol";
+import {IRMN} from "../interfaces/IRMN.sol";
+import {IRouter} from "../interfaces/IRouter.sol";
+import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol";
+
+import {CallWithExactGas} from "../../shared/call/CallWithExactGas.sol";
+import {EnumerableMapAddresses} from "../../shared/enumerable/EnumerableMapAddresses.sol";
+import {AggregateRateLimiter} from "../AggregateRateLimiter.sol";
+import {Client} from "../libraries/Client.sol";
+import {Internal} from "../libraries/Internal.sol";
+import {Pool} from "../libraries/Pool.sol";
+import {RateLimiter} from "../libraries/RateLimiter.sol";
+import {OCR2BaseNoChecks} from "../ocr/OCR2BaseNoChecks.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {ERC165Checker} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol";
+
+/// @notice EVM2EVMOffRamp enables OCR networks to execute multiple messages
+/// in an OffRamp in a single transaction.
+/// @dev The EVM2EVMOnRamp, CommitStore and EVM2EVMOffRamp form an xchain upgradeable unit. Any change to one of them
+/// results an onchain upgrade of all 3.
+/// @dev OCR2BaseNoChecks is used to save gas, signatures are not required as the offramp can only execute
+/// messages which are committed in the commitStore. We still make use of OCR2 as an executor whitelist
+/// and turn-taking mechanism.
+contract EVM2EVMOffRamp is IAny2EVMOffRamp, AggregateRateLimiter, ITypeAndVersion, OCR2BaseNoChecks {
+ using ERC165Checker for address;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+
+ error AlreadyAttempted(uint64 sequenceNumber);
+ error AlreadyExecuted(uint64 sequenceNumber);
+ error ZeroAddressNotAllowed();
+ error CommitStoreAlreadyInUse();
+ error ExecutionError(bytes err);
+ error InvalidSourceChain(uint64 sourceChainSelector);
+ error MessageTooLarge(uint256 maxSize, uint256 actualSize);
+ error TokenDataMismatch(uint64 sequenceNumber);
+ error UnexpectedTokenData();
+ error UnsupportedNumberOfTokens(uint64 sequenceNumber);
+ error ManualExecutionNotYetEnabled();
+ error ManualExecutionGasLimitMismatch();
+ error InvalidManualExecutionGasLimit(uint256 index, uint256 newLimit);
+ error RootNotCommitted();
+ error CanOnlySelfCall();
+ error ReceiverError(bytes err);
+ error TokenHandlingError(bytes err);
+ error EmptyReport();
+ error CursedByRMN();
+ error InvalidMessageId();
+ error NotACompatiblePool(address notPool);
+ error InvalidDataLength(uint256 expected, uint256 got);
+ error InvalidNewState(uint64 sequenceNumber, Internal.MessageExecutionState newState);
+
+ /// @dev Atlas depends on this event, if changing, please notify Atlas.
+ event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig);
+ event SkippedIncorrectNonce(uint64 indexed nonce, address indexed sender);
+ event SkippedSenderWithPreviousRampMessageInflight(uint64 indexed nonce, address indexed sender);
+ /// @dev RMN depends on this event, if changing, please notify the RMN maintainers.
+ event ExecutionStateChanged(
+ uint64 indexed sequenceNumber, bytes32 indexed messageId, Internal.MessageExecutionState state, bytes returnData
+ );
+ event TokenAggregateRateLimitAdded(address sourceToken, address destToken);
+ event TokenAggregateRateLimitRemoved(address sourceToken, address destToken);
+ event SkippedAlreadyExecutedMessage(uint64 indexed sequenceNumber);
+
+ /// @notice Static offRamp config
+ /// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
+ //solhint-disable gas-struct-packing
+ struct StaticConfig {
+ address commitStore; // ────────╮ CommitStore address on the destination chain
+ uint64 chainSelector; // ───────╯ Destination chainSelector
+ uint64 sourceChainSelector; // ─╮ Source chainSelector
+ address onRamp; // ─────────────╯ OnRamp address on the source chain
+ address prevOffRamp; // Address of previous-version OffRamp
+ address rmnProxy; // RMN proxy address
+ address tokenAdminRegistry; // Token admin registry address
+ }
+
+ /// @notice Dynamic offRamp config
+ /// @dev since OffRampConfig is part of OffRampConfigChanged event, if changing it, we should update the ABI on Atlas
+ struct DynamicConfig {
+ uint32 permissionLessExecutionThresholdSeconds; // ─╮ Waiting time before manual execution is enabled
+ uint32 maxDataBytes; // │ Maximum payload data size in bytes
+ uint16 maxNumberOfTokensPerMsg; // │ Maximum number of ERC20 token transfers that can be included per message
+ address router; // ─────────────────────────────────╯ Router address
+ address priceRegistry; // ──────────╮ Price registry address
+ uint32 maxPoolReleaseOrMintGas; // │ Maximum amount of gas passed on to token pool `releaseOrMint` call
+ uint32 maxTokenTransferGas; // ─────╯ Maximum amount of gas passed on to token `transfer` call
+ }
+
+ /// @notice RateLimitToken struct containing both the source and destination token addresses
+ struct RateLimitToken {
+ address sourceToken;
+ address destToken;
+ }
+
+ // STATIC CONFIG
+ string public constant override typeAndVersion = "EVM2EVMOffRamp 1.5.0-dev";
+
+ /// @dev Commit store address on the destination chain
+ address internal immutable i_commitStore;
+ /// @dev ChainSelector of the source chain
+ uint64 internal immutable i_sourceChainSelector;
+ /// @dev ChainSelector of this chain
+ uint64 internal immutable i_chainSelector;
+ /// @dev OnRamp address on the source chain
+ address internal immutable i_onRamp;
+ /// @dev metadataHash is a lane-specific prefix for a message hash preimage which ensures global uniqueness.
+ /// Ensures that 2 identical messages sent to 2 different lanes will have a distinct hash.
+ /// Must match the metadataHash used in computing leaf hashes offchain for the root committed in
+ /// the commitStore and i_metadataHash in the onRamp.
+ bytes32 internal immutable i_metadataHash;
+ /// @dev The address of previous-version OffRamp for this lane.
+ /// Used to be able to provide sequencing continuity during a zero downtime upgrade.
+ address internal immutable i_prevOffRamp;
+ /// @dev The address of the RMN proxy
+ address internal immutable i_rmnProxy;
+ /// @dev The address of the token admin registry
+ address internal immutable i_tokenAdminRegistry;
+
+ // DYNAMIC CONFIG
+ DynamicConfig internal s_dynamicConfig;
+ /// @dev Tokens that should be included in Aggregate Rate Limiting
+ /// An (address => address) map is used for backwards compatability of offchain code
+ EnumerableMapAddresses.AddressToAddressMap internal s_rateLimitedTokensDestToSource;
+
+ // STATE
+ /// @dev The expected nonce for a given sender.
+ /// Corresponds to s_senderNonce in the OnRamp, used to enforce that messages are
+ /// executed in the same order they are sent (assuming they are DON). Note that re-execution
+ /// of FAILED messages however, can be out of order.
+ mapping(address sender => uint64 nonce) internal s_senderNonce;
+ /// @dev A mapping of sequence numbers to execution state using a bitmap with each execution
+ /// state only taking up 2 bits of the uint256, packing 128 states into a single slot.
+ /// Message state is tracked to ensure message can only be executed successfully once.
+ mapping(uint64 seqNum => uint256 executionStateBitmap) internal s_executionStates;
+
+ constructor(
+ StaticConfig memory staticConfig,
+ RateLimiter.Config memory rateLimiterConfig
+ ) OCR2BaseNoChecks() AggregateRateLimiter(rateLimiterConfig) {
+ if (
+ staticConfig.onRamp == address(0) || staticConfig.commitStore == address(0)
+ || staticConfig.tokenAdminRegistry == address(0)
+ ) revert ZeroAddressNotAllowed();
+ // Ensures we can never deploy a new offRamp that points to a commitStore that
+ // already has roots committed.
+ if (ICommitStore(staticConfig.commitStore).getExpectedNextSequenceNumber() != 1) revert CommitStoreAlreadyInUse();
+
+ i_commitStore = staticConfig.commitStore;
+ i_sourceChainSelector = staticConfig.sourceChainSelector;
+ i_chainSelector = staticConfig.chainSelector;
+ i_onRamp = staticConfig.onRamp;
+ i_prevOffRamp = staticConfig.prevOffRamp;
+ i_rmnProxy = staticConfig.rmnProxy;
+ i_tokenAdminRegistry = staticConfig.tokenAdminRegistry;
+
+ i_metadataHash = _metadataHash(Internal.EVM_2_EVM_MESSAGE_HASH);
+ }
+
+ // ================================================================
+ // │ Messaging │
+ // ================================================================
+
+ // The size of the execution state in bits
+ uint256 private constant MESSAGE_EXECUTION_STATE_BIT_WIDTH = 2;
+ // The mask for the execution state bits
+ uint256 private constant MESSAGE_EXECUTION_STATE_MASK = (1 << MESSAGE_EXECUTION_STATE_BIT_WIDTH) - 1;
+
+ /// @notice Returns the current execution state of a message based on its sequenceNumber.
+ /// @param sequenceNumber The sequence number of the message to get the execution state for.
+ /// @return The current execution state of the message.
+ /// @dev we use the literal number 128 because using a constant increased gas usage.
+ function getExecutionState(uint64 sequenceNumber) public view returns (Internal.MessageExecutionState) {
+ return Internal.MessageExecutionState(
+ (s_executionStates[sequenceNumber / 128] >> ((sequenceNumber % 128) * MESSAGE_EXECUTION_STATE_BIT_WIDTH))
+ & MESSAGE_EXECUTION_STATE_MASK
+ );
+ }
+
+ /// @notice Sets a new execution state for a given sequence number. It will overwrite any existing state.
+ /// @param sequenceNumber The sequence number for which the state will be saved.
+ /// @param newState The new value the state will be in after this function is called.
+ /// @dev we use the literal number 128 because using a constant increased gas usage.
+ function _setExecutionState(uint64 sequenceNumber, Internal.MessageExecutionState newState) internal {
+ uint256 offset = (sequenceNumber % 128) * MESSAGE_EXECUTION_STATE_BIT_WIDTH;
+ uint256 bitmap = s_executionStates[sequenceNumber / 128];
+ // to unset any potential existing state we zero the bits of the section the state occupies,
+ // then we do an AND operation to blank out any existing state for the section.
+ bitmap &= ~(MESSAGE_EXECUTION_STATE_MASK << offset);
+ // Set the new state
+ bitmap |= uint256(newState) << offset;
+
+ s_executionStates[sequenceNumber / 128] = bitmap;
+ }
+
+ /// @inheritdoc IAny2EVMOffRamp
+ function getSenderNonce(address sender) external view returns (uint64 nonce) {
+ uint256 senderNonce = s_senderNonce[sender];
+
+ if (senderNonce == 0) {
+ if (i_prevOffRamp != address(0)) {
+ // If OffRamp was upgraded, check if sender has a nonce from the previous OffRamp.
+ return IAny2EVMOffRamp(i_prevOffRamp).getSenderNonce(sender);
+ }
+ }
+ return uint64(senderNonce);
+ }
+
+ /// @notice Manually execute a message.
+ /// @param report Internal.ExecutionReport.
+ /// @param gasLimitOverrides New gasLimit for each message in the report.
+ /// @dev We permit gas limit overrides so that users may manually execute messages which failed due to
+ /// insufficient gas provided.
+ function manuallyExecute(Internal.ExecutionReport memory report, uint256[] memory gasLimitOverrides) external {
+ // We do this here because the other _execute path is already covered OCR2BaseXXX.
+ _checkChainForked();
+
+ uint256 numMsgs = report.messages.length;
+ if (numMsgs != gasLimitOverrides.length) revert ManualExecutionGasLimitMismatch();
+ for (uint256 i = 0; i < numMsgs; ++i) {
+ uint256 newLimit = gasLimitOverrides[i];
+ // Checks to ensure message cannot be executed with less gas than specified.
+ if (newLimit != 0) {
+ if (newLimit < report.messages[i].gasLimit) {
+ revert InvalidManualExecutionGasLimit(i, newLimit);
+ }
+ }
+ }
+
+ _execute(report, gasLimitOverrides);
+ }
+
+ /// @notice Entrypoint for execution, called by the OCR network
+ /// @dev Expects an encoded ExecutionReport
+ function _report(bytes calldata report) internal override {
+ _execute(abi.decode(report, (Internal.ExecutionReport)), new uint256[](0));
+ }
+
+ /// @notice Executes a report, executing each message in order.
+ /// @param report The execution report containing the messages and proofs.
+ /// @param manualExecGasLimits An array of gas limits to use for manual execution.
+ /// @dev If called from the DON, this array is always empty.
+ /// @dev If called from manual execution, this array is always same length as messages.
+ function _execute(Internal.ExecutionReport memory report, uint256[] memory manualExecGasLimits) internal {
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(i_sourceChainSelector)))) revert CursedByRMN();
+
+ uint256 numMsgs = report.messages.length;
+ if (numMsgs == 0) revert EmptyReport();
+ if (numMsgs != report.offchainTokenData.length) revert UnexpectedTokenData();
+
+ bytes32[] memory hashedLeaves = new bytes32[](numMsgs);
+
+ for (uint256 i = 0; i < numMsgs; ++i) {
+ Internal.EVM2EVMMessage memory message = report.messages[i];
+ // We do this hash here instead of in _verifyMessages to avoid two separate loops
+ // over the same data, which increases gas cost
+ hashedLeaves[i] = Internal._hash(message, i_metadataHash);
+ // For EVM2EVM offramps, the messageID is the leaf hash.
+ // Asserting that this is true ensures we don't accidentally commit and then execute
+ // a message with an unexpected hash.
+ if (hashedLeaves[i] != message.messageId) revert InvalidMessageId();
+ }
+
+ // SECURITY CRITICAL CHECK
+ uint256 timestampCommitted = ICommitStore(i_commitStore).verify(hashedLeaves, report.proofs, report.proofFlagBits);
+ if (timestampCommitted == 0) revert RootNotCommitted();
+
+ // Execute messages
+ bool manualExecution = manualExecGasLimits.length != 0;
+ for (uint256 i = 0; i < numMsgs; ++i) {
+ Internal.EVM2EVMMessage memory message = report.messages[i];
+ Internal.MessageExecutionState originalState = getExecutionState(message.sequenceNumber);
+ if (originalState == Internal.MessageExecutionState.SUCCESS) {
+ // If the message has already been executed, we skip it. We want to not revert on race conditions between
+ // executing parties. This will allow us to open up manual exec while also attempting with the DON, without
+ // reverting an entire DON batch when a user manually executes while the tx is inflight.
+ emit SkippedAlreadyExecutedMessage(message.sequenceNumber);
+ continue;
+ }
+ // Two valid cases here, we either have never touched this message before, or we tried to execute
+ // and failed. This check protects against reentry and re-execution because the other state is
+ // IN_PROGRESS which should not be allowed to execute.
+ if (
+ !(
+ originalState == Internal.MessageExecutionState.UNTOUCHED
+ || originalState == Internal.MessageExecutionState.FAILURE
+ )
+ ) revert AlreadyExecuted(message.sequenceNumber);
+
+ if (manualExecution) {
+ bool isOldCommitReport =
+ (block.timestamp - timestampCommitted) > s_dynamicConfig.permissionLessExecutionThresholdSeconds;
+ // Manually execution is fine if we previously failed or if the commit report is just too old
+ // Acceptable state transitions: FAILURE->SUCCESS, UNTOUCHED->SUCCESS, FAILURE->FAILURE
+ if (!(isOldCommitReport || originalState == Internal.MessageExecutionState.FAILURE)) {
+ revert ManualExecutionNotYetEnabled();
+ }
+
+ // Manual execution gas limit can override gas limit specified in the message. Value of 0 indicates no override.
+ if (manualExecGasLimits[i] != 0) {
+ message.gasLimit = manualExecGasLimits[i];
+ }
+ } else {
+ // DON can only execute a message once
+ // Acceptable state transitions: UNTOUCHED->SUCCESS, UNTOUCHED->FAILURE
+ if (originalState != Internal.MessageExecutionState.UNTOUCHED) revert AlreadyAttempted(message.sequenceNumber);
+ }
+
+ if (message.nonce != 0) {
+ // In the scenario where we upgrade offRamps, we still want to have sequential nonces.
+ // Referencing the old offRamp to check the expected nonce if none is set for a
+ // given sender allows us to skip the current message if it would not be the next according
+ // to the old offRamp. This preserves sequencing between updates.
+ uint64 prevNonce = s_senderNonce[message.sender];
+ if (prevNonce == 0) {
+ if (i_prevOffRamp != address(0)) {
+ prevNonce = IAny2EVMOffRamp(i_prevOffRamp).getSenderNonce(message.sender);
+ if (prevNonce + 1 != message.nonce) {
+ // the starting v2 onramp nonce, i.e. the 1st message nonce v2 offramp is expected to receive,
+ // is guaranteed to equal (largest v1 onramp nonce + 1).
+ // if this message's nonce isn't (v1 offramp nonce + 1), then v1 offramp nonce != largest v1 onramp nonce,
+ // it tells us there are still messages inflight for v1 offramp
+ emit SkippedSenderWithPreviousRampMessageInflight(message.nonce, message.sender);
+ continue;
+ }
+ // Otherwise this nonce is indeed the "transitional nonce", that is
+ // all messages sent to v1 ramp have been executed by the DON and the sequence can resume in V2.
+ // Note if first time user in V2, then prevNonce will be 0, and message.nonce = 1, so this will be a no-op.
+ s_senderNonce[message.sender] = prevNonce;
+ }
+ }
+
+ // UNTOUCHED messages MUST be executed in order always IF message.nonce > 0.
+ if (originalState == Internal.MessageExecutionState.UNTOUCHED) {
+ if (prevNonce + 1 != message.nonce) {
+ // We skip the message if the nonce is incorrect, since message.nonce > 0.
+ emit SkippedIncorrectNonce(message.nonce, message.sender);
+ continue;
+ }
+ }
+ }
+
+ // Although we expect only valid messages will be committed, we check again
+ // when executing as a defense in depth measure.
+ bytes[] memory offchainTokenData = report.offchainTokenData[i];
+ _isWellFormed(
+ message.sequenceNumber,
+ message.sourceChainSelector,
+ message.tokenAmounts.length,
+ message.data.length,
+ offchainTokenData.length
+ );
+
+ _setExecutionState(message.sequenceNumber, Internal.MessageExecutionState.IN_PROGRESS);
+ (Internal.MessageExecutionState newState, bytes memory returnData) = _trialExecute(message, offchainTokenData);
+ _setExecutionState(message.sequenceNumber, newState);
+
+ // Since it's hard to estimate whether manual execution will succeed, we
+ // revert the entire transaction if it fails. This will show the user if
+ // their manual exec will fail before they submit it.
+ if (manualExecution) {
+ if (newState == Internal.MessageExecutionState.FAILURE) {
+ if (originalState != Internal.MessageExecutionState.UNTOUCHED) {
+ // If manual execution fails, we revert the entire transaction, unless the originalState is UNTOUCHED as we
+ // would still be making progress by changing the state from UNTOUCHED to FAILURE.
+ revert ExecutionError(returnData);
+ }
+ }
+ }
+
+ // The only valid prior states are UNTOUCHED and FAILURE (checked above)
+ // The only valid post states are SUCCESS and FAILURE (checked below)
+ if (newState != Internal.MessageExecutionState.SUCCESS) {
+ if (newState != Internal.MessageExecutionState.FAILURE) {
+ revert InvalidNewState(message.sequenceNumber, newState);
+ }
+ }
+
+ // Nonce changes per state transition.
+ // These only apply for ordered messages.
+ // UNTOUCHED -> FAILURE nonce bump
+ // UNTOUCHED -> SUCCESS nonce bump
+ // FAILURE -> FAILURE no nonce bump
+ // FAILURE -> SUCCESS no nonce bump
+ if (message.nonce != 0) {
+ if (originalState == Internal.MessageExecutionState.UNTOUCHED) {
+ s_senderNonce[message.sender]++;
+ }
+ }
+
+ emit ExecutionStateChanged(message.sequenceNumber, message.messageId, newState, returnData);
+ }
+ }
+
+ /// @notice Does basic message validation. Should never fail.
+ /// @param sequenceNumber Sequence number of the message.
+ /// @param sourceChainSelector SourceChainSelector of the message.
+ /// @param numberOfTokens Length of tokenAmounts array in the message.
+ /// @param dataLength Length of data field in the message.
+ /// @param offchainTokenDataLength Length of offchainTokenData array.
+ /// @dev reverts on validation failures.
+ function _isWellFormed(
+ uint64 sequenceNumber,
+ uint64 sourceChainSelector,
+ uint256 numberOfTokens,
+ uint256 dataLength,
+ uint256 offchainTokenDataLength
+ ) private view {
+ if (sourceChainSelector != i_sourceChainSelector) revert InvalidSourceChain(sourceChainSelector);
+ if (numberOfTokens > uint256(s_dynamicConfig.maxNumberOfTokensPerMsg)) {
+ revert UnsupportedNumberOfTokens(sequenceNumber);
+ }
+ if (numberOfTokens != offchainTokenDataLength) revert TokenDataMismatch(sequenceNumber);
+ if (dataLength > uint256(s_dynamicConfig.maxDataBytes)) {
+ revert MessageTooLarge(uint256(s_dynamicConfig.maxDataBytes), dataLength);
+ }
+ }
+
+ /// @notice Try executing a message.
+ /// @param message Internal.EVM2EVMMessage memory message.
+ /// @param offchainTokenData Data provided by the DON for token transfers.
+ /// @return the new state of the message, being either SUCCESS or FAILURE.
+ /// @return revert data in bytes if CCIP receiver reverted during execution.
+ function _trialExecute(
+ Internal.EVM2EVMMessage memory message,
+ bytes[] memory offchainTokenData
+ ) internal returns (Internal.MessageExecutionState, bytes memory) {
+ try this.executeSingleMessage(message, offchainTokenData) {}
+ catch (bytes memory err) {
+ if (
+ ReceiverError.selector == bytes4(err) || TokenHandlingError.selector == bytes4(err)
+ || Internal.InvalidEVMAddress.selector == bytes4(err) || InvalidDataLength.selector == bytes4(err)
+ || CallWithExactGas.NoContract.selector == bytes4(err) || NotACompatiblePool.selector == bytes4(err)
+ ) {
+ // If CCIP receiver execution is not successful, bubble up receiver revert data,
+ // prepended by the 4 bytes of ReceiverError.selector, TokenHandlingError.selector or InvalidPoolAddress.selector.
+ // Max length of revert data is Router.MAX_RET_BYTES, max length of err is 4 + Router.MAX_RET_BYTES
+ return (Internal.MessageExecutionState.FAILURE, err);
+ }
+ // If revert is not caused by CCIP receiver, it is unexpected, bubble up the revert.
+ revert ExecutionError(err);
+ }
+ // If message execution succeeded, no CCIP receiver return data is expected, return with empty bytes.
+ return (Internal.MessageExecutionState.SUCCESS, "");
+ }
+
+ /// @notice Execute a single message.
+ /// @param message The message that will be executed.
+ /// @param offchainTokenData Token transfer data to be passed to TokenPool.
+ /// @dev We make this external and callable by the contract itself, in order to try/catch
+ /// its execution and enforce atomicity among successful message processing and token transfer.
+ /// @dev We use ERC-165 to check for the ccipReceive interface to permit sending tokens to contracts
+ /// (for example smart contract wallets) without an associated message.
+ function executeSingleMessage(Internal.EVM2EVMMessage memory message, bytes[] memory offchainTokenData) external {
+ if (msg.sender != address(this)) revert CanOnlySelfCall();
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](0);
+ if (message.tokenAmounts.length > 0) {
+ destTokenAmounts = _releaseOrMintTokens(
+ message.tokenAmounts, abi.encode(message.sender), message.receiver, message.sourceTokenData, offchainTokenData
+ );
+ }
+ // There are three cases in which we skip calling the receiver:
+ // 1. If the message data is empty AND the gas limit is 0.
+ // This indicates a message that only transfers tokens. It is valid to only send tokens to a contract
+ // that supports the IAny2EVMMessageReceiver interface, but without this first check we would call the
+ // receiver without any gas, which would revert the transaction.
+ // 2. If the receiver is not a contract.
+ // 3. If the receiver is a contract but it does not support the IAny2EVMMessageReceiver interface.
+ //
+ // The ordering of these checks is important, as the first check is the cheapest to execute.
+ if (
+ (message.data.length == 0 && message.gasLimit == 0) || message.receiver.code.length == 0
+ || !message.receiver.supportsInterface(type(IAny2EVMMessageReceiver).interfaceId)
+ ) return;
+
+ (bool success, bytes memory returnData,) = IRouter(s_dynamicConfig.router).routeMessage(
+ Client.Any2EVMMessage({
+ messageId: message.messageId,
+ sourceChainSelector: message.sourceChainSelector,
+ sender: abi.encode(message.sender),
+ data: message.data,
+ destTokenAmounts: destTokenAmounts
+ }),
+ Internal.GAS_FOR_CALL_EXACT_CHECK,
+ message.gasLimit,
+ message.receiver
+ );
+ // If CCIP receiver execution is not successful, revert the call including token transfers
+ if (!success) revert ReceiverError(returnData);
+ }
+
+ /// @notice creates a unique hash to be used in message hashing.
+ function _metadataHash(bytes32 prefix) internal view returns (bytes32) {
+ return keccak256(abi.encode(prefix, i_sourceChainSelector, i_chainSelector, i_onRamp));
+ }
+
+ // ================================================================
+ // │ Config │
+ // ================================================================
+
+ /// @notice Returns the static config.
+ /// @dev This function will always return the same struct as the contents is static and can never change.
+ /// RMN depends on this function, if changing, please notify the RMN maintainers.
+ function getStaticConfig() external view returns (StaticConfig memory) {
+ return StaticConfig({
+ commitStore: i_commitStore,
+ chainSelector: i_chainSelector,
+ sourceChainSelector: i_sourceChainSelector,
+ onRamp: i_onRamp,
+ prevOffRamp: i_prevOffRamp,
+ rmnProxy: i_rmnProxy,
+ tokenAdminRegistry: i_tokenAdminRegistry
+ });
+ }
+
+ /// @notice Returns the current dynamic config.
+ /// @return The current config.
+ function getDynamicConfig() external view returns (DynamicConfig memory) {
+ return s_dynamicConfig;
+ }
+
+ /// @notice Sets the dynamic config. This function is called during `setOCR2Config` flow
+ function _beforeSetConfig(bytes memory onchainConfig) internal override {
+ DynamicConfig memory dynamicConfig = abi.decode(onchainConfig, (DynamicConfig));
+
+ if (dynamicConfig.router == address(0)) revert ZeroAddressNotAllowed();
+
+ s_dynamicConfig = dynamicConfig;
+
+ emit ConfigSet(
+ StaticConfig({
+ commitStore: i_commitStore,
+ chainSelector: i_chainSelector,
+ sourceChainSelector: i_sourceChainSelector,
+ onRamp: i_onRamp,
+ prevOffRamp: i_prevOffRamp,
+ rmnProxy: i_rmnProxy,
+ tokenAdminRegistry: i_tokenAdminRegistry
+ }),
+ dynamicConfig
+ );
+ }
+
+ /// @notice Get all tokens which are included in Aggregate Rate Limiting.
+ /// @return sourceTokens The source representation of the tokens that are rate limited.
+ /// @return destTokens The destination representation of the tokens that are rate limited.
+ /// @dev the order of IDs in the list is **not guaranteed**, therefore, if ordering matters when
+ /// making successive calls, one should keep the block height constant to ensure a consistent result.
+ function getAllRateLimitTokens() external view returns (address[] memory sourceTokens, address[] memory destTokens) {
+ uint256 numRateLimitedTokens = s_rateLimitedTokensDestToSource.length();
+ sourceTokens = new address[](numRateLimitedTokens);
+ destTokens = new address[](numRateLimitedTokens);
+
+ for (uint256 i = 0; i < numRateLimitedTokens; ++i) {
+ (address destToken, address sourceToken) = s_rateLimitedTokensDestToSource.at(i);
+ sourceTokens[i] = sourceToken;
+ destTokens[i] = destToken;
+ }
+ return (sourceTokens, destTokens);
+ }
+
+ /// @notice Adds or removes tokens from being used in Aggregate Rate Limiting.
+ /// @param removes - A list of one or more tokens to be removed.
+ /// @param adds - A list of one or more tokens to be added.
+ function updateRateLimitTokens(RateLimitToken[] memory removes, RateLimitToken[] memory adds) external onlyOwner {
+ for (uint256 i = 0; i < removes.length; ++i) {
+ if (s_rateLimitedTokensDestToSource.remove(removes[i].destToken)) {
+ emit TokenAggregateRateLimitRemoved(removes[i].sourceToken, removes[i].destToken);
+ }
+ }
+
+ for (uint256 i = 0; i < adds.length; ++i) {
+ if (s_rateLimitedTokensDestToSource.set(adds[i].destToken, adds[i].sourceToken)) {
+ emit TokenAggregateRateLimitAdded(adds[i].sourceToken, adds[i].destToken);
+ }
+ }
+ }
+
+ // ================================================================
+ // │ Tokens and pools │
+ // ================================================================
+
+ /// @notice Uses a pool to release or mint a token to a receiver address in two steps. First, the pool is called
+ /// to release the tokens to the offRamp, then the offRamp calls the token contract to transfer the tokens to the
+ /// receiver. This is done to ensure the exact number of tokens, the pool claims to release are actually transferred.
+ /// @dev The local token address is validated through the TokenAdminRegistry. If, due to some misconfiguration, the
+ /// token is unknown to the registry, the offRamp will revert. The tx, and the tokens, can be retrieved by
+ /// registering the token on this chain, and re-trying the msg.
+ /// @param sourceAmount The amount of tokens to be released/minted.
+ /// @param originalSender The message sender on the source chain.
+ /// @param receiver The address that will receive the tokens.
+ /// @param sourceTokenData A struct containing the local token address, the source pool address and optional data
+ /// returned from the source pool.
+ /// @param offchainTokenData Data fetched offchain by the DON.
+ function _releaseOrMintToken(
+ uint256 sourceAmount,
+ bytes memory originalSender,
+ address receiver,
+ Internal.SourceTokenData memory sourceTokenData,
+ bytes memory offchainTokenData
+ ) internal returns (Client.EVMTokenAmount memory destTokenAmount) {
+ // We need to safely decode the token address from the sourceTokenData, as it could be wrong,
+ // in which case it doesn't have to be a valid EVM address.
+ address localToken = Internal._validateEVMAddress(sourceTokenData.destTokenAddress);
+ // We check with the token admin registry if the token has a pool on this chain.
+ address localPoolAddress = ITokenAdminRegistry(i_tokenAdminRegistry).getPool(localToken);
+ // This will call the supportsInterface through the ERC165Checker, and not directly on the pool address.
+ // This is done to prevent a pool from reverting the entire transaction if it doesn't support the interface.
+ // The call gets a max or 30k gas per instance, of which there are three. This means gas estimations should
+ // account for 90k gas overhead due to the interface check.
+ if (localPoolAddress == address(0) || !localPoolAddress.supportsInterface(Pool.CCIP_POOL_V1)) {
+ revert NotACompatiblePool(localPoolAddress);
+ }
+
+ // We determined that the pool address is a valid EVM address, but that does not mean the code at this
+ // address is a (compatible) pool contract. _callWithExactGasSafeReturnData will check if the location
+ // contains a contract. If it doesn't it reverts with a known error, which we catch gracefully.
+ // We call the pool with exact gas to increase resistance against malicious tokens or token pools.
+ // We protects against return data bombs by capping the return data size at MAX_RET_BYTES.
+ (bool success, bytes memory returnData,) = CallWithExactGas._callWithExactGasSafeReturnData(
+ abi.encodeCall(
+ IPoolV1.releaseOrMint,
+ Pool.ReleaseOrMintInV1({
+ originalSender: originalSender,
+ receiver: receiver,
+ amount: sourceAmount,
+ localToken: localToken,
+ remoteChainSelector: i_sourceChainSelector,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData
+ })
+ ),
+ localPoolAddress,
+ s_dynamicConfig.maxPoolReleaseOrMintGas,
+ Internal.GAS_FOR_CALL_EXACT_CHECK,
+ Internal.MAX_RET_BYTES
+ );
+
+ // wrap and rethrow the error so we can catch it lower in the stack
+ if (!success) revert TokenHandlingError(returnData);
+
+ // If the call was successful, the returnData should contain only the local token amount.
+ if (returnData.length != Pool.CCIP_POOL_V1_RET_BYTES) {
+ revert InvalidDataLength(Pool.CCIP_POOL_V1_RET_BYTES, returnData.length);
+ }
+ uint256 localAmount = abi.decode(returnData, (uint256));
+ // Since token pools send the tokens to the msg.sender, which is this offRamp, we need to
+ // transfer them to the final receiver. We use the _callWithExactGasSafeReturnData function because
+ // the token contracts are not considered trusted.
+ (success, returnData,) = CallWithExactGas._callWithExactGasSafeReturnData(
+ abi.encodeCall(IERC20.transfer, (receiver, localAmount)),
+ localToken,
+ s_dynamicConfig.maxTokenTransferGas,
+ Internal.GAS_FOR_CALL_EXACT_CHECK,
+ Internal.MAX_RET_BYTES
+ );
+
+ if (!success) revert TokenHandlingError(returnData);
+
+ return Client.EVMTokenAmount({token: localToken, amount: localAmount});
+ }
+
+ /// @notice Uses pools to release or mint a number of different tokens to a receiver address.
+ /// @param sourceTokenAmounts List of tokens and amount values to be released/minted.
+ /// @param originalSender The message sender.
+ /// @param receiver The address that will receive the tokens.
+ /// @param encodedSourceTokenData Array of token data returned by token pools on the source chain.
+ /// @param offchainTokenData Array of token data fetched offchain by the DON.
+ /// @dev This function wrappes the token pool call in a try catch block to gracefully handle
+ /// any non-rate limiting errors that may occur. If we encounter a rate limiting related error
+ /// we bubble it up. If we encounter a non-rate limiting error we wrap it in a TokenHandlingError.
+ function _releaseOrMintTokens(
+ Client.EVMTokenAmount[] memory sourceTokenAmounts,
+ bytes memory originalSender,
+ address receiver,
+ bytes[] memory encodedSourceTokenData,
+ bytes[] memory offchainTokenData
+ ) internal returns (Client.EVMTokenAmount[] memory destTokenAmounts) {
+ // Creating a copy is more gas efficient than initializing a new array.
+ destTokenAmounts = sourceTokenAmounts;
+ uint256 value = 0;
+ for (uint256 i = 0; i < sourceTokenAmounts.length; ++i) {
+ destTokenAmounts[i] = _releaseOrMintToken(
+ sourceTokenAmounts[i].amount,
+ originalSender,
+ receiver,
+ // This should never revert as the onRamp encodes the sourceTokenData struct. Only the inner components from
+ // this struct come from untrusted sources.
+ abi.decode(encodedSourceTokenData[i], (Internal.SourceTokenData)),
+ offchainTokenData[i]
+ );
+
+ if (s_rateLimitedTokensDestToSource.contains(destTokenAmounts[i].token)) {
+ value += _getTokenValue(destTokenAmounts[i], IPriceRegistry(s_dynamicConfig.priceRegistry));
+ }
+ }
+
+ if (value > 0) _rateLimitValue(value);
+
+ return destTokenAmounts;
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @notice Reverts as this contract should not access CCIP messages
+ function ccipReceive(Client.Any2EVMMessage calldata) external pure {
+ // solhint-disable-next-line
+ revert();
+ }
+}
diff --git a/contracts/src/v0.8/ccip/onRamp/EVM2EVMMultiOnRamp.sol b/contracts/src/v0.8/ccip/onRamp/EVM2EVMMultiOnRamp.sol
new file mode 100644
index 00000000000..fc455cc869e
--- /dev/null
+++ b/contracts/src/v0.8/ccip/onRamp/EVM2EVMMultiOnRamp.sol
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IEVM2AnyOnRampClient} from "../interfaces/IEVM2AnyOnRampClient.sol";
+import {IMessageInterceptor} from "../interfaces/IMessageInterceptor.sol";
+import {INonceManager} from "../interfaces/INonceManager.sol";
+import {IPoolV1} from "../interfaces/IPool.sol";
+import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol";
+import {IRMN} from "../interfaces/IRMN.sol";
+import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol";
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+import {Client} from "../libraries/Client.sol";
+import {Internal} from "../libraries/Internal.sol";
+import {Pool} from "../libraries/Pool.sol";
+import {USDPriceWith18Decimals} from "../libraries/USDPriceWith18Decimals.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 The EVM2EVMMultiOnRamp is a contract that handles lane-specific fee logic
+/// @dev The EVM2EVMMultiOnRamp, MultiCommitStore and EVM2EVMMultiOffRamp form an xchain upgradeable unit. Any change to one of them
+/// results an onchain upgrade of all 3.
+contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCreator {
+ using SafeERC20 for IERC20;
+ using USDPriceWith18Decimals for uint224;
+
+ error CannotSendZeroTokens();
+ error InvalidExtraArgsTag();
+ error ExtraArgOutOfOrderExecutionMustBeTrue();
+ error OnlyCallableByOwnerOrAdmin();
+ error MessageGasLimitTooHigh();
+ error UnsupportedToken(address token);
+ error MustBeCalledByRouter();
+ error RouterMustSetOriginalSender();
+ error InvalidConfig();
+ error CursedByRMN(uint64 sourceChainSelector);
+ error GetSupportedTokensFunctionalityRemovedCheckAdminRegistry();
+
+ event AdminSet(address newAdmin);
+ event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig);
+ event FeePaid(address indexed feeToken, uint256 feeValueJuels);
+ event FeeTokenWithdrawn(address indexed feeAggregator, address indexed feeToken, uint256 amount);
+ /// RMN depends on this event, if changing, please notify the RMN maintainers.
+ event CCIPSendRequested(uint64 indexed destChainSelector, Internal.EVM2AnyRampMessage message);
+
+ /// @dev Struct that contains the static configuration
+ /// RMN depends on this struct, if changing, please notify the RMN maintainers.
+ // solhint-disable-next-line gas-struct-packing
+ struct StaticConfig {
+ uint64 chainSelector; // ─────╮ Source chainSelector
+ address rmnProxy; // ─────────╯ Address of RMN proxy
+ address nonceManager; // Address of the nonce manager
+ address tokenAdminRegistry; // Token admin registry address
+ }
+
+ /// @dev Struct to contains the dynamic configuration
+ // solhint-disable-next-line gas-struct-packing
+ struct DynamicConfig {
+ address router; // Router address
+ address priceRegistry; // Price registry address
+ address messageValidator; // Optional message validator to validate outbound messages (zero address = no validator)
+ address feeAggregator; // Fee aggregator address
+ }
+
+ // STATIC CONFIG
+ string public constant override typeAndVersion = "EVM2EVMMultiOnRamp 1.6.0-dev";
+ /// @dev The chain ID of the source chain that this contract is deployed to
+ uint64 internal immutable i_chainSelector;
+ /// @dev The address of the rmn proxy
+ address internal immutable i_rmnProxy;
+ /// @dev The address of the nonce manager
+ address internal immutable i_nonceManager;
+ /// @dev The address of the token admin registry
+ address internal immutable i_tokenAdminRegistry;
+ /// @dev the maximum number of nops that can be configured at the same time.
+ /// Used to bound gas for loops over nops.
+ uint256 private constant MAX_NUMBER_OF_NOPS = 64;
+
+ // DYNAMIC CONFIG
+ /// @dev The config for the onRamp
+ DynamicConfig internal s_dynamicConfig;
+
+ /// @dev Last used sequence number per destination chain.
+ /// This is zero in the case where no messages have been sent yet.
+ /// 0 is not a valid sequence number for any real transaction.
+ mapping(uint64 destChainSelector => uint64 sequenceNumber) internal s_destChainSequenceNumbers;
+
+ // STATE
+ /// @dev The amount of LINK available to pay NOPS
+ uint96 internal s_nopFeesJuels;
+ /// @dev The combined weight of all NOPs weights
+ uint32 internal s_nopWeightsTotal;
+
+ constructor(StaticConfig memory staticConfig, DynamicConfig memory dynamicConfig) {
+ if (
+ staticConfig.chainSelector == 0 || staticConfig.rmnProxy == address(0) || staticConfig.nonceManager == address(0)
+ || staticConfig.tokenAdminRegistry == address(0)
+ ) {
+ revert InvalidConfig();
+ }
+
+ i_chainSelector = staticConfig.chainSelector;
+ i_rmnProxy = staticConfig.rmnProxy;
+ i_nonceManager = staticConfig.nonceManager;
+ i_tokenAdminRegistry = staticConfig.tokenAdminRegistry;
+
+ _setDynamicConfig(dynamicConfig);
+ }
+
+ // ================================================================
+ // │ Messaging │
+ // ================================================================
+
+ /// @notice Gets the next sequence number to be used in the onRamp
+ /// @param destChainSelector The destination chain selector
+ /// @return the next sequence number to be used
+ function getExpectedNextSequenceNumber(uint64 destChainSelector) external view returns (uint64) {
+ return s_destChainSequenceNumbers[destChainSelector] + 1;
+ }
+
+ /// @inheritdoc IEVM2AnyOnRampClient
+ function forwardFromRouter(
+ uint64 destChainSelector,
+ Client.EVM2AnyMessage calldata message,
+ uint256 feeTokenAmount,
+ address originalSender
+ ) external returns (bytes32) {
+ // NOTE: assumes the message has already been validated through the getFee call
+ // Validate message sender is set and allowed. Not validated in `getFee` since it is not user-driven.
+ if (originalSender == address(0)) revert RouterMustSetOriginalSender();
+ // Router address may be zero intentionally to pause.
+ if (msg.sender != s_dynamicConfig.router) revert MustBeCalledByRouter();
+
+ address messageValidator = s_dynamicConfig.messageValidator;
+ if (messageValidator != address(0)) {
+ IMessageInterceptor(messageValidator).onOutboundMessage(destChainSelector, message);
+ }
+
+ // Convert message fee to juels and retrieve converted args
+ (uint256 msgFeeJuels, bool isOutOfOrderExecution, bytes memory convertedExtraArgs) = IPriceRegistry(
+ s_dynamicConfig.priceRegistry
+ ).processMessageArgs(destChainSelector, message.feeToken, feeTokenAmount, message.extraArgs);
+
+ emit FeePaid(message.feeToken, msgFeeJuels);
+
+ Internal.EVM2AnyRampMessage memory newMessage = Internal.EVM2AnyRampMessage({
+ header: Internal.RampMessageHeader({
+ // Should be generated after the message is complete
+ messageId: "",
+ sourceChainSelector: i_chainSelector,
+ destChainSelector: destChainSelector,
+ // We need the next available sequence number so we increment before we use the value
+ sequenceNumber: ++s_destChainSequenceNumbers[destChainSelector],
+ // Only bump nonce for messages that specify allowOutOfOrderExecution == false. Otherwise, we
+ // may block ordered message nonces, which is not what we want.
+ nonce: isOutOfOrderExecution
+ ? 0
+ : INonceManager(i_nonceManager).getIncrementedOutboundNonce(destChainSelector, originalSender)
+ }),
+ sender: originalSender,
+ data: message.data,
+ extraArgs: message.extraArgs,
+ receiver: message.receiver,
+ feeToken: message.feeToken,
+ feeTokenAmount: feeTokenAmount,
+ // Should be populated via lock / burn pool calls
+ tokenAmounts: new Internal.RampTokenAmount[](message.tokenAmounts.length)
+ });
+
+ // Lock the tokens as last step. TokenPools may not always be trusted.
+ // There should be no state changes after external call to TokenPools.
+ for (uint256 i = 0; i < message.tokenAmounts.length; ++i) {
+ newMessage.tokenAmounts[i] =
+ _lockOrBurnSingleToken(message.tokenAmounts[i], destChainSelector, message.receiver, originalSender);
+ }
+
+ // Validate pool return data after it is populated (view function - no state changes)
+ IPriceRegistry(s_dynamicConfig.priceRegistry).validatePoolReturnData(
+ destChainSelector, newMessage.tokenAmounts, message.tokenAmounts
+ );
+
+ // Override extraArgs with latest version
+ newMessage.extraArgs = convertedExtraArgs;
+
+ // Hash only after all fields have been set
+ newMessage.header.messageId = Internal._hash(
+ newMessage,
+ // Metadata hash preimage to ensure global uniqueness, ensuring 2 identical messages sent to 2 different
+ // lanes will have a distinct hash.
+ keccak256(abi.encode(Internal.EVM_2_ANY_MESSAGE_HASH, i_chainSelector, destChainSelector, address(this)))
+ );
+
+ // Emit message request
+ // This must happen after any pool events as some tokens (e.g. USDC) emit events that we expect to precede this
+ // event in the offchain code.
+ emit CCIPSendRequested(destChainSelector, newMessage);
+ return newMessage.header.messageId;
+ }
+
+ /// @notice Uses a pool to lock or burn a token
+ /// @param tokenAndAmount Token address and amount to lock or burn
+ /// @param destChainSelector Target dest chain selector of the message
+ /// @param receiver Message receiver
+ /// @param originalSender Message sender
+ /// @return rampTokenAndAmount Ramp token and amount data
+ function _lockOrBurnSingleToken(
+ Client.EVMTokenAmount memory tokenAndAmount,
+ uint64 destChainSelector,
+ bytes memory receiver,
+ address originalSender
+ ) internal returns (Internal.RampTokenAmount memory) {
+ if (tokenAndAmount.amount == 0) revert CannotSendZeroTokens();
+
+ IPoolV1 sourcePool = getPoolBySourceToken(destChainSelector, IERC20(tokenAndAmount.token));
+ // We don't have to check if it supports the pool version in a non-reverting way here because
+ // if we revert here, there is no effect on CCIP. Therefore we directly call the supportsInterface
+ // function and not through the ERC165Checker.
+ if (address(sourcePool) == address(0) || !sourcePool.supportsInterface(Pool.CCIP_POOL_V1)) {
+ revert UnsupportedToken(tokenAndAmount.token);
+ }
+
+ Pool.LockOrBurnOutV1 memory poolReturnData = sourcePool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ receiver: receiver,
+ remoteChainSelector: destChainSelector,
+ originalSender: originalSender,
+ amount: tokenAndAmount.amount,
+ localToken: tokenAndAmount.token
+ })
+ );
+
+ // NOTE: pool data validations are outsourced to the PriceRegistry to handle family-specific logic handling
+
+ return Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(sourcePool),
+ destTokenAddress: poolReturnData.destTokenAddress,
+ extraData: poolReturnData.destPoolData,
+ amount: tokenAndAmount.amount
+ });
+ }
+
+ // ================================================================
+ // │ Config │
+ // ================================================================
+
+ /// @notice Returns the static onRamp config.
+ /// @dev RMN depends on this function, if changing, please notify the RMN maintainers.
+ /// @return the configuration.
+ function getStaticConfig() external view returns (StaticConfig memory) {
+ return StaticConfig({
+ chainSelector: i_chainSelector,
+ rmnProxy: i_rmnProxy,
+ nonceManager: i_nonceManager,
+ tokenAdminRegistry: i_tokenAdminRegistry
+ });
+ }
+
+ /// @notice Returns the dynamic onRamp config.
+ /// @return dynamicConfig the configuration.
+ function getDynamicConfig() external view returns (DynamicConfig memory dynamicConfig) {
+ return s_dynamicConfig;
+ }
+
+ /// @notice Sets the dynamic configuration.
+ /// @param dynamicConfig The configuration.
+ function setDynamicConfig(DynamicConfig memory dynamicConfig) external onlyOwner {
+ _setDynamicConfig(dynamicConfig);
+ }
+
+ /// @notice Internal version of setDynamicConfig to allow for reuse in the constructor.
+ function _setDynamicConfig(DynamicConfig memory dynamicConfig) internal {
+ // We permit router to be set to zero as a way to pause the contract.
+ if (dynamicConfig.priceRegistry == address(0) || dynamicConfig.feeAggregator == address(0)) revert InvalidConfig();
+
+ s_dynamicConfig = dynamicConfig;
+
+ emit ConfigSet(
+ StaticConfig({
+ chainSelector: i_chainSelector,
+ rmnProxy: i_rmnProxy,
+ nonceManager: i_nonceManager,
+ tokenAdminRegistry: i_tokenAdminRegistry
+ }),
+ dynamicConfig
+ );
+ }
+
+ // ================================================================
+ // │ Tokens and pools │
+ // ================================================================
+
+ /// @inheritdoc IEVM2AnyOnRampClient
+ function getPoolBySourceToken(uint64, /*destChainSelector*/ IERC20 sourceToken) public view returns (IPoolV1) {
+ return IPoolV1(ITokenAdminRegistry(i_tokenAdminRegistry).getPool(address(sourceToken)));
+ }
+
+ /// @inheritdoc IEVM2AnyOnRampClient
+ function getSupportedTokens(uint64 /*destChainSelector*/ ) external pure returns (address[] memory) {
+ revert GetSupportedTokensFunctionalityRemovedCheckAdminRegistry();
+ }
+
+ // ================================================================
+ // │ Fees │
+ // ================================================================
+
+ /// @inheritdoc IEVM2AnyOnRampClient
+ /// @dev getFee MUST revert if the feeToken is not listed in the fee token config, as the router assumes it does.
+ /// @param destChainSelector The destination chain selector.
+ /// @param message The message to get quote for.
+ /// @return feeTokenAmount The amount of fee token needed for the fee, in smallest denomination of the fee token.
+ function getFee(
+ uint64 destChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external view returns (uint256 feeTokenAmount) {
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(destChainSelector)))) revert CursedByRMN(destChainSelector);
+
+ return IPriceRegistry(s_dynamicConfig.priceRegistry).getValidatedFee(destChainSelector, message);
+ }
+
+ /// @notice Withdraws the outstanding fee token balances to the fee aggregator.
+ /// @dev This function can be permissionless as it only transfers accepted fee tokens to the fee aggregator which is a trusted address.
+ function withdrawFeeTokens() external {
+ address[] memory feeTokens = IPriceRegistry(s_dynamicConfig.priceRegistry).getFeeTokens();
+ address feeAggregator = s_dynamicConfig.feeAggregator;
+
+ for (uint256 i = 0; i < feeTokens.length; ++i) {
+ IERC20 feeToken = IERC20(feeTokens[i]);
+ uint256 feeTokenBalance = feeToken.balanceOf(address(this));
+
+ if (feeTokenBalance > 0) {
+ feeToken.safeTransfer(feeAggregator, feeTokenBalance);
+
+ emit FeeTokenWithdrawn(feeAggregator, address(feeToken), feeTokenBalance);
+ }
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol b/contracts/src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol
new file mode 100644
index 00000000000..0e978596e4c
--- /dev/null
+++ b/contracts/src/v0.8/ccip/onRamp/EVM2EVMOnRamp.sol
@@ -0,0 +1,916 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IEVM2AnyOnRamp} from "../interfaces/IEVM2AnyOnRamp.sol";
+import {IEVM2AnyOnRampClient} from "../interfaces/IEVM2AnyOnRampClient.sol";
+import {IPoolV1} from "../interfaces/IPool.sol";
+import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol";
+import {IRMN} from "../interfaces/IRMN.sol";
+import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol";
+import {ILinkAvailable} from "../interfaces/automation/ILinkAvailable.sol";
+
+import {AggregateRateLimiter} from "../AggregateRateLimiter.sol";
+import {Client} from "../libraries/Client.sol";
+import {Internal} from "../libraries/Internal.sol";
+import {Pool} from "../libraries/Pool.sol";
+import {RateLimiter} from "../libraries/RateLimiter.sol";
+import {USDPriceWith18Decimals} from "../libraries/USDPriceWith18Decimals.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";
+import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol";
+
+/// @notice The onRamp is a contract that handles lane-specific fee logic, NOP payments and
+/// bridgeable token support.
+/// @dev The EVM2EVMOnRamp, CommitStore and EVM2EVMOffRamp form an xchain upgradeable unit. Any change to one of them
+/// results an onchain upgrade of all 3.
+contract EVM2EVMOnRamp is IEVM2AnyOnRamp, ILinkAvailable, AggregateRateLimiter, ITypeAndVersion {
+ using SafeERC20 for IERC20;
+ using EnumerableMap for EnumerableMap.AddressToUintMap;
+ using USDPriceWith18Decimals for uint224;
+
+ error InvalidExtraArgsTag();
+ error ExtraArgOutOfOrderExecutionMustBeTrue();
+ error OnlyCallableByOwnerOrAdmin();
+ error OnlyCallableByOwnerOrAdminOrNop();
+ error InvalidWithdrawParams();
+ error NoFeesToPay();
+ error NoNopsToPay();
+ error InsufficientBalance();
+ error TooManyNops();
+ error MaxFeeBalanceReached();
+ error MessageTooLarge(uint256 maxSize, uint256 actualSize);
+ error MessageGasLimitTooHigh();
+ error UnsupportedNumberOfTokens();
+ error UnsupportedToken(address token);
+ error MustBeCalledByRouter();
+ error RouterMustSetOriginalSender();
+ error InvalidConfig();
+ error CursedByRMN();
+ error LinkBalanceNotSettled();
+ error InvalidNopAddress(address nop);
+ error NotAFeeToken(address token);
+ error CannotSendZeroTokens();
+ error SourceTokenDataTooLarge(address token);
+ error InvalidChainSelector(uint64 chainSelector);
+ error GetSupportedTokensFunctionalityRemovedCheckAdminRegistry();
+ error InvalidDestBytesOverhead(address token, uint32 destBytesOverhead);
+
+ event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig);
+ event NopPaid(address indexed nop, uint256 amount);
+ event FeeConfigSet(FeeTokenConfigArgs[] feeConfig);
+ event TokenTransferFeeConfigSet(TokenTransferFeeConfigArgs[] transferFeeConfig);
+ event TokenTransferFeeConfigDeleted(address[] tokens);
+ /// RMN depends on this event, if changing, please notify the RMN maintainers.
+ event CCIPSendRequested(Internal.EVM2EVMMessage message);
+ event NopsSet(uint256 nopWeightsTotal, NopAndWeight[] nopsAndWeights);
+
+ /// @dev Struct that contains the static configuration
+ /// RMN depends on this struct, if changing, please notify the RMN maintainers.
+ //solhint-disable gas-struct-packing
+ struct StaticConfig {
+ address linkToken; // ────────╮ Link token address
+ uint64 chainSelector; // ─────╯ Source chainSelector
+ uint64 destChainSelector; // ─╮ Destination chainSelector
+ uint64 defaultTxGasLimit; // │ Default gas limit for a tx
+ uint96 maxNopFeesJuels; // ───╯ Max nop fee balance onramp can have
+ address prevOnRamp; // Address of previous-version OnRamp
+ address rmnProxy; // Address of RMN proxy
+ address tokenAdminRegistry; // Address of the token admin registry
+ }
+
+ /// @dev Struct to contains the dynamic configuration
+ struct DynamicConfig {
+ address router; // ──────────────────────────╮ Router address
+ uint16 maxNumberOfTokensPerMsg; // │ Maximum number of distinct ERC20 token transferred per message
+ uint32 destGasOverhead; // │ Gas charged on top of the gasLimit to cover destination chain costs
+ uint16 destGasPerPayloadByte; // │ Destination chain gas charged for passing each byte of `data` payload to receiver
+ uint32 destDataAvailabilityOverheadGas; // ──╯ Extra data availability gas charged on top of the message, e.g. for OCR
+ uint16 destGasPerDataAvailabilityByte; // ───╮ Amount of gas to charge per byte of message data that needs availability
+ uint16 destDataAvailabilityMultiplierBps; // │ Multiplier for data availability gas, multiples of bps, or 0.0001
+ address priceRegistry; // │ Price registry address
+ uint32 maxDataBytes; // │ Maximum payload data size in bytes
+ uint32 maxPerMsgGasLimit; // ────────────────╯ Maximum gas limit for messages targeting EVMs
+ // │
+ // The following three properties are defaults, they can be overridden by setting the TokenTransferFeeConfig for a token
+ uint16 defaultTokenFeeUSDCents; // ──────────╮ Default token fee charged per token transfer
+ uint32 defaultTokenDestGasOverhead; // │ Default gas charged to execute the token transfer on the destination chain
+ // │ Default data availability bytes that are returned from the source pool and sent
+ uint32 defaultTokenDestBytesOverhead; // | to the destination pool. Must be >= Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES
+ bool enforceOutOfOrder; // ──────────────────╯ Whether to enforce the allowOutOfOrderExecution extraArg value to be true.
+ }
+
+ /// @dev Struct to hold the execution fee configuration for a fee token
+ struct FeeTokenConfig {
+ uint32 networkFeeUSDCents; // ─────────╮ Flat network fee to charge for messages, multiples of 0.01 USD
+ uint64 gasMultiplierWeiPerEth; // │ Multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost.
+ uint64 premiumMultiplierWeiPerEth; // │ Multiplier for fee-token-specific premiums
+ bool enabled; // ──────────────────────╯ Whether this fee token is enabled
+ }
+
+ /// @dev Struct to hold the fee configuration for a fee token, same as the FeeTokenConfig but with
+ /// token included so that an array of these can be passed in to setFeeTokenConfig to set the mapping
+ struct FeeTokenConfigArgs {
+ address token; // ─────────────────────╮ Token address
+ uint32 networkFeeUSDCents; // │ Flat network fee to charge for messages, multiples of 0.01 USD
+ uint64 gasMultiplierWeiPerEth; // ─────╯ Multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost
+ uint64 premiumMultiplierWeiPerEth; // ─╮ Multiplier for fee-token-specific premiums, 1e18 based
+ bool enabled; // ──────────────────────╯ Whether this fee token is enabled
+ }
+
+ /// @dev Struct to hold the transfer fee configuration for token transfers
+ struct TokenTransferFeeConfig {
+ uint32 minFeeUSDCents; // ──────────╮ Minimum fee to charge per token transfer, multiples of 0.01 USD
+ uint32 maxFeeUSDCents; // │ Maximum fee to charge per token transfer, multiples of 0.01 USD
+ uint16 deciBps; // │ Basis points charged on token transfers, multiples of 0.1bps, or 1e-5
+ uint32 destGasOverhead; // │ Gas charged to execute the token transfer on the destination chain
+ // │ Extra data availability bytes that are returned from the source pool and sent
+ uint32 destBytesOverhead; // │ to the destination pool. Must be >= Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES
+ bool aggregateRateLimitEnabled; // │ Whether this transfer token is to be included in Aggregate Rate Limiting
+ bool isEnabled; // ─────────────────╯ Whether this token has custom transfer fees
+ }
+
+ /// @dev Same as TokenTransferFeeConfig
+ /// token included so that an array of these can be passed in to setTokenTransferFeeConfig
+ struct TokenTransferFeeConfigArgs {
+ address token; // ──────────────────╮ Token address
+ uint32 minFeeUSDCents; // │ Minimum fee to charge per token transfer, multiples of 0.01 USD
+ uint32 maxFeeUSDCents; // │ Maximum fee to charge per token transfer, multiples of 0.01 USD
+ uint16 deciBps; // ─────────────────╯ Basis points charged on token transfers, multiples of 0.1bps, or 1e-5
+ uint32 destGasOverhead; // ─────────╮ Gas charged to execute the token transfer on the destination chain
+ // │ Extra data availability bytes that are returned from the source pool and sent
+ uint32 destBytesOverhead; // │ to the destination pool. Must be >= Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES
+ bool aggregateRateLimitEnabled; // ─╯ Whether this transfer token is to be included in Aggregate Rate Limiting
+ }
+
+ /// @dev Nop address and weight, used to set the nops and their weights
+ struct NopAndWeight {
+ address nop; // ────╮ Address of the node operator
+ uint16 weight; // ──╯ Weight for nop rewards
+ }
+
+ // STATIC CONFIG
+ string public constant override typeAndVersion = "EVM2EVMOnRamp 1.5.0-dev";
+ /// @dev metadataHash is a lane-specific prefix for a message hash preimage which ensures global uniqueness
+ /// Ensures that 2 identical messages sent to 2 different lanes will have a distinct hash.
+ /// Must match the metadataHash used in computing leaf hashes offchain for the root committed in
+ /// the commitStore and i_metadataHash in the offRamp.
+ bytes32 internal immutable i_metadataHash;
+ /// @dev Default gas limit for a transactions that did not specify
+ /// a gas limit in the extraArgs.
+ uint64 internal immutable i_defaultTxGasLimit;
+ /// @dev Maximum nop fee that can accumulate in this onramp
+ uint96 internal immutable i_maxNopFeesJuels;
+ /// @dev The link token address - known to pay nops for their work
+ address internal immutable i_linkToken;
+ /// @dev The chain ID of the source chain that this contract is deployed to
+ uint64 internal immutable i_chainSelector;
+ /// @dev The chain ID of the destination chain
+ uint64 internal immutable i_destChainSelector;
+ /// @dev The address of previous-version OnRamp for this lane
+ /// Used to be able to provide sequencing continuity during a zero downtime upgrade.
+ address internal immutable i_prevOnRamp;
+ /// @dev The address of the RMN proxy
+ address internal immutable i_rmnProxy;
+ /// @dev The address of the token admin registry
+ address internal immutable i_tokenAdminRegistry;
+ /// @dev the maximum number of nops that can be configured at the same time.
+ /// Used to bound gas for loops over nops.
+ uint256 private constant MAX_NUMBER_OF_NOPS = 64;
+
+ // DYNAMIC CONFIG
+ /// @dev The config for the onRamp
+ DynamicConfig internal s_dynamicConfig;
+ /// @dev (address nop => uint256 weight)
+ EnumerableMap.AddressToUintMap internal s_nops;
+
+ /// @dev The execution fee token config that can be set by the owner or fee admin
+ mapping(address token => FeeTokenConfig feeTokenConfig) internal s_feeTokenConfig;
+ /// @dev The token transfer fee config that can be set by the owner or fee admin
+ mapping(address token => TokenTransferFeeConfig tranferFeeConfig) internal s_tokenTransferFeeConfig;
+
+ // STATE
+ /// @dev The current nonce per sender.
+ /// The offramp has a corresponding s_senderNonce mapping to ensure messages
+ /// are executed in the same order they are sent.
+ mapping(address sender => uint64 nonce) internal s_senderNonce;
+ /// @dev The amount of LINK available to pay NOPS
+ uint96 internal s_nopFeesJuels;
+ /// @dev The combined weight of all NOPs weights
+ uint32 internal s_nopWeightsTotal;
+ /// @dev The last used sequence number. This is zero in the case where no
+ /// messages has been sent yet. 0 is not a valid sequence number for any
+ /// real transaction.
+ uint64 internal s_sequenceNumber;
+
+ constructor(
+ StaticConfig memory staticConfig,
+ DynamicConfig memory dynamicConfig,
+ RateLimiter.Config memory rateLimiterConfig,
+ FeeTokenConfigArgs[] memory feeTokenConfigs,
+ TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
+ NopAndWeight[] memory nopsAndWeights
+ ) AggregateRateLimiter(rateLimiterConfig) {
+ if (
+ staticConfig.linkToken == address(0) || staticConfig.chainSelector == 0 || staticConfig.destChainSelector == 0
+ || staticConfig.defaultTxGasLimit == 0 || staticConfig.rmnProxy == address(0)
+ || staticConfig.tokenAdminRegistry == address(0)
+ ) revert InvalidConfig();
+
+ i_metadataHash = keccak256(
+ abi.encode(
+ Internal.EVM_2_EVM_MESSAGE_HASH, staticConfig.chainSelector, staticConfig.destChainSelector, address(this)
+ )
+ );
+ i_linkToken = staticConfig.linkToken;
+ i_chainSelector = staticConfig.chainSelector;
+ i_destChainSelector = staticConfig.destChainSelector;
+ i_defaultTxGasLimit = staticConfig.defaultTxGasLimit;
+ i_maxNopFeesJuels = staticConfig.maxNopFeesJuels;
+ i_prevOnRamp = staticConfig.prevOnRamp;
+ i_rmnProxy = staticConfig.rmnProxy;
+ i_tokenAdminRegistry = staticConfig.tokenAdminRegistry;
+
+ _setDynamicConfig(dynamicConfig);
+ _setFeeTokenConfig(feeTokenConfigs);
+ _setTokenTransferFeeConfig(tokenTransferFeeConfigArgs, new address[](0));
+ _setNops(nopsAndWeights);
+ }
+
+ // ================================================================
+ // │ Messaging │
+ // ================================================================
+
+ /// @inheritdoc IEVM2AnyOnRamp
+ function getExpectedNextSequenceNumber() external view returns (uint64) {
+ return s_sequenceNumber + 1;
+ }
+
+ /// @inheritdoc IEVM2AnyOnRamp
+ function getSenderNonce(address sender) external view returns (uint64) {
+ uint256 senderNonce = s_senderNonce[sender];
+
+ if (i_prevOnRamp != address(0)) {
+ if (senderNonce == 0) {
+ // If OnRamp was upgraded, check if sender has a nonce from the previous OnRamp.
+ return IEVM2AnyOnRamp(i_prevOnRamp).getSenderNonce(sender);
+ }
+ }
+ return uint64(senderNonce);
+ }
+
+ /// @inheritdoc IEVM2AnyOnRampClient
+ function forwardFromRouter(
+ uint64 destChainSelector,
+ Client.EVM2AnyMessage calldata message,
+ uint256 feeTokenAmount,
+ address originalSender
+ ) external returns (bytes32) {
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(destChainSelector)))) revert CursedByRMN();
+ // Validate message sender is set and allowed. Not validated in `getFee` since it is not user-driven.
+ if (originalSender == address(0)) revert RouterMustSetOriginalSender();
+ // Router address may be zero intentionally to pause.
+ if (msg.sender != s_dynamicConfig.router) revert MustBeCalledByRouter();
+ if (destChainSelector != i_destChainSelector) revert InvalidChainSelector(destChainSelector);
+
+ Client.EVMExtraArgsV2 memory extraArgs = _fromBytes(message.extraArgs);
+ // Validate the message with various checks
+ uint256 numberOfTokens = message.tokenAmounts.length;
+ _validateMessage(message.data.length, extraArgs.gasLimit, numberOfTokens, extraArgs.allowOutOfOrderExecution);
+
+ // Only check token value if there are tokens
+ if (numberOfTokens > 0) {
+ uint256 value;
+ for (uint256 i = 0; i < numberOfTokens; ++i) {
+ if (message.tokenAmounts[i].amount == 0) revert CannotSendZeroTokens();
+ if (s_tokenTransferFeeConfig[message.tokenAmounts[i].token].aggregateRateLimitEnabled) {
+ value += _getTokenValue(message.tokenAmounts[i], IPriceRegistry(s_dynamicConfig.priceRegistry));
+ }
+ }
+ // Rate limit on aggregated token value
+ if (value > 0) _rateLimitValue(value);
+ }
+
+ // Convert feeToken to link if not already in link
+ if (message.feeToken == i_linkToken) {
+ // Since there is only 1b link this is safe
+ s_nopFeesJuels += uint96(feeTokenAmount);
+ } else {
+ // the cast from uint256 to uint96 is considered safe, uint96 can store more than max supply of link token
+ s_nopFeesJuels += uint96(
+ IPriceRegistry(s_dynamicConfig.priceRegistry).convertTokenAmount(message.feeToken, feeTokenAmount, i_linkToken)
+ );
+ }
+ if (s_nopFeesJuels > i_maxNopFeesJuels) revert MaxFeeBalanceReached();
+
+ if (i_prevOnRamp != address(0)) {
+ if (s_senderNonce[originalSender] == 0) {
+ // If this is first time send for a sender in new OnRamp, check if they have a nonce
+ // from the previous OnRamp and start from there instead of zero.
+ s_senderNonce[originalSender] = IEVM2AnyOnRamp(i_prevOnRamp).getSenderNonce(originalSender);
+ }
+ }
+
+ // We need the next available sequence number so we increment before we use the value
+ Internal.EVM2EVMMessage memory newMessage = Internal.EVM2EVMMessage({
+ sourceChainSelector: i_chainSelector,
+ sender: originalSender,
+ // EVM destination addresses should be abi encoded and therefore always 32 bytes long
+ // Not duplicately validated in `getFee`. Invalid address is uncommon, gas cost outweighs UX gain.
+ receiver: Internal._validateEVMAddress(message.receiver),
+ sequenceNumber: ++s_sequenceNumber,
+ gasLimit: extraArgs.gasLimit,
+ strict: false,
+ // Only bump nonce for messages that specify allowOutOfOrderExecution == false. Otherwise, we
+ // may block ordered message nonces, which is not what we want.
+ nonce: extraArgs.allowOutOfOrderExecution ? 0 : ++s_senderNonce[originalSender],
+ feeToken: message.feeToken,
+ feeTokenAmount: feeTokenAmount,
+ data: message.data,
+ tokenAmounts: message.tokenAmounts,
+ sourceTokenData: new bytes[](numberOfTokens), // will be populated below
+ messageId: ""
+ });
+
+ // Lock the tokens as last step. TokenPools may not always be trusted.
+ // There should be no state changes after external call to TokenPools.
+ for (uint256 i = 0; i < numberOfTokens; ++i) {
+ Client.EVMTokenAmount memory tokenAndAmount = message.tokenAmounts[i];
+ IPoolV1 sourcePool = getPoolBySourceToken(destChainSelector, IERC20(tokenAndAmount.token));
+ // We don't have to check if it supports the pool version in a non-reverting way here because
+ // if we revert here, there is no effect on CCIP. Therefore we directly call the supportsInterface
+ // function and not through the ERC165Checker.
+ if (address(sourcePool) == address(0) || !sourcePool.supportsInterface(Pool.CCIP_POOL_V1)) {
+ revert UnsupportedToken(tokenAndAmount.token);
+ }
+
+ Pool.LockOrBurnOutV1 memory poolReturnData = sourcePool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ receiver: message.receiver,
+ remoteChainSelector: i_destChainSelector,
+ originalSender: originalSender,
+ amount: tokenAndAmount.amount,
+ localToken: tokenAndAmount.token
+ })
+ );
+
+ // Since the DON has to pay for the extraData to be included on the destination chain, we cap the length of the
+ // extraData. This prevents gas bomb attacks on the NOPs. As destBytesOverhead accounts for both
+ // extraData and offchainData, this caps the worst case abuse to the number of bytes reserved for offchainData.
+ if (poolReturnData.destPoolData.length > Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) {
+ if (poolReturnData.destPoolData.length > s_tokenTransferFeeConfig[tokenAndAmount.token].destBytesOverhead) {
+ revert SourceTokenDataTooLarge(tokenAndAmount.token);
+ }
+ }
+ // We validate the token address to ensure it is a valid EVM address
+ Internal._validateEVMAddress(poolReturnData.destTokenAddress);
+
+ newMessage.sourceTokenData[i] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(sourcePool),
+ destTokenAddress: poolReturnData.destTokenAddress,
+ extraData: poolReturnData.destPoolData
+ })
+ );
+ }
+
+ // Hash only after the sourceTokenData has been set
+ newMessage.messageId = Internal._hash(newMessage, i_metadataHash);
+
+ // Emit message request
+ // This must happen after any pool events as some tokens (e.g. USDC) emit events that we expect to precede this
+ // event in the offchain code.
+ emit CCIPSendRequested(newMessage);
+ return newMessage.messageId;
+ }
+
+ /// @dev Convert the extra args bytes into a struct
+ /// @param extraArgs The extra args bytes
+ /// @return The extra args struct
+ function _fromBytes(bytes calldata extraArgs) internal view returns (Client.EVMExtraArgsV2 memory) {
+ if (extraArgs.length == 0) {
+ return Client.EVMExtraArgsV2({gasLimit: i_defaultTxGasLimit, allowOutOfOrderExecution: false});
+ }
+
+ bytes4 extraArgsTag = bytes4(extraArgs);
+ if (extraArgsTag == Client.EVM_EXTRA_ARGS_V2_TAG) {
+ return abi.decode(extraArgs[4:], (Client.EVMExtraArgsV2));
+ } else if (extraArgsTag == Client.EVM_EXTRA_ARGS_V1_TAG) {
+ // EVMExtraArgsV1 originally included a second boolean (strict) field which has been deprecated.
+ // Clients may still include it but it will be ignored.
+ return Client.EVMExtraArgsV2({gasLimit: abi.decode(extraArgs[4:], (uint256)), allowOutOfOrderExecution: false});
+ }
+
+ revert InvalidExtraArgsTag();
+ }
+
+ /// @notice Validate the forwarded message with various checks.
+ /// @dev This function can be called multiple times during a CCIPSend,
+ /// only common user-driven mistakes are validated here to minimize duplicate validation cost.
+ /// @param dataLength The length of the data field of the message.
+ /// @param gasLimit The gasLimit set in message for destination execution.
+ /// @param numberOfTokens The number of tokens to be sent.
+ function _validateMessage(
+ uint256 dataLength,
+ uint256 gasLimit,
+ uint256 numberOfTokens,
+ bool allowOutOfOrderExecution
+ ) internal view {
+ uint256 maxDataBytes = uint256(s_dynamicConfig.maxDataBytes);
+ if (dataLength > maxDataBytes) revert MessageTooLarge(maxDataBytes, dataLength);
+ if (gasLimit > uint256(s_dynamicConfig.maxPerMsgGasLimit)) revert MessageGasLimitTooHigh();
+ if (numberOfTokens > uint256(s_dynamicConfig.maxNumberOfTokensPerMsg)) revert UnsupportedNumberOfTokens();
+ if (!allowOutOfOrderExecution) {
+ if (s_dynamicConfig.enforceOutOfOrder) {
+ revert ExtraArgOutOfOrderExecutionMustBeTrue();
+ }
+ }
+ }
+
+ // ================================================================
+ // │ Config │
+ // ================================================================
+
+ /// @notice Returns the static onRamp config.
+ /// @dev RMN depends on this function, if changing, please notify the RMN maintainers.
+ /// @return the configuration.
+ function getStaticConfig() external view returns (StaticConfig memory) {
+ return StaticConfig({
+ linkToken: i_linkToken,
+ chainSelector: i_chainSelector,
+ destChainSelector: i_destChainSelector,
+ defaultTxGasLimit: i_defaultTxGasLimit,
+ maxNopFeesJuels: i_maxNopFeesJuels,
+ prevOnRamp: i_prevOnRamp,
+ rmnProxy: i_rmnProxy,
+ tokenAdminRegistry: i_tokenAdminRegistry
+ });
+ }
+
+ /// @notice Returns the dynamic onRamp config.
+ /// @return dynamicConfig the configuration.
+ function getDynamicConfig() external view returns (DynamicConfig memory dynamicConfig) {
+ return s_dynamicConfig;
+ }
+
+ /// @notice Sets the dynamic configuration.
+ /// @param dynamicConfig The configuration.
+ function setDynamicConfig(DynamicConfig memory dynamicConfig) external onlyOwner {
+ _setDynamicConfig(dynamicConfig);
+ }
+
+ /// @notice Internal version of setDynamicConfig to allow for reuse in the constructor.
+ function _setDynamicConfig(DynamicConfig memory dynamicConfig) internal {
+ // We permit router to be set to zero as a way to pause the contract.
+ if (dynamicConfig.priceRegistry == address(0)) revert InvalidConfig();
+ if (dynamicConfig.defaultTokenDestBytesOverhead < Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) {
+ revert InvalidDestBytesOverhead(address(0), dynamicConfig.defaultTokenDestBytesOverhead);
+ }
+
+ s_dynamicConfig = dynamicConfig;
+
+ emit ConfigSet(
+ StaticConfig({
+ linkToken: i_linkToken,
+ chainSelector: i_chainSelector,
+ destChainSelector: i_destChainSelector,
+ defaultTxGasLimit: i_defaultTxGasLimit,
+ maxNopFeesJuels: i_maxNopFeesJuels,
+ prevOnRamp: i_prevOnRamp,
+ rmnProxy: i_rmnProxy,
+ tokenAdminRegistry: i_tokenAdminRegistry
+ }),
+ dynamicConfig
+ );
+ }
+
+ // ================================================================
+ // │ Tokens and pools │
+ // ================================================================
+
+ /// @inheritdoc IEVM2AnyOnRampClient
+ function getPoolBySourceToken(uint64, /*destChainSelector*/ IERC20 sourceToken) public view returns (IPoolV1) {
+ return IPoolV1(ITokenAdminRegistry(i_tokenAdminRegistry).getPool(address(sourceToken)));
+ }
+
+ /// @inheritdoc IEVM2AnyOnRampClient
+ function getSupportedTokens(uint64) external pure returns (address[] memory) {
+ revert GetSupportedTokensFunctionalityRemovedCheckAdminRegistry();
+ }
+
+ // ================================================================
+ // │ Fees │
+ // ================================================================
+
+ /// @inheritdoc IEVM2AnyOnRampClient
+ /// @dev getFee MUST revert if the feeToken is not listed in the fee token config, as the router assumes it does.
+ /// @param destChainSelector The destination chain selector.
+ /// @param message The message to get quote for.
+ /// @return feeTokenAmount The amount of fee token needed for the fee, in smallest denomination of the fee token.
+ function getFee(
+ uint64 destChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external view returns (uint256 feeTokenAmount) {
+ if (destChainSelector != i_destChainSelector) revert InvalidChainSelector(destChainSelector);
+
+ Client.EVMExtraArgsV2 memory extraArgs = _fromBytes(message.extraArgs);
+ // Validate the message with various checks
+ _validateMessage(
+ message.data.length, extraArgs.gasLimit, message.tokenAmounts.length, extraArgs.allowOutOfOrderExecution
+ );
+
+ FeeTokenConfig memory feeTokenConfig = s_feeTokenConfig[message.feeToken];
+ if (!feeTokenConfig.enabled) revert NotAFeeToken(message.feeToken);
+
+ (uint224 feeTokenPrice, uint224 packedGasPrice) =
+ IPriceRegistry(s_dynamicConfig.priceRegistry).getTokenAndGasPrices(message.feeToken, destChainSelector);
+
+ // Calculate premiumFee in USD with 18 decimals precision first.
+ // If message-only and no token transfers, a flat network fee is charged.
+ // If there are token transfers, premiumFee is calculated from token transfer fee.
+ // If there are both token transfers and message, premiumFee is only calculated from token transfer fee.
+ uint256 premiumFee = 0;
+ uint32 tokenTransferGas = 0;
+ uint32 tokenTransferBytesOverhead = 0;
+ if (message.tokenAmounts.length > 0) {
+ (premiumFee, tokenTransferGas, tokenTransferBytesOverhead) =
+ _getTokenTransferCost(message.feeToken, feeTokenPrice, message.tokenAmounts);
+ } else {
+ // Convert USD cents with 2 decimals to 18 decimals.
+ premiumFee = uint256(feeTokenConfig.networkFeeUSDCents) * 1e16;
+ }
+
+ // Calculate data availability cost in USD with 36 decimals. Data availability cost exists on rollups that need to post
+ // transaction calldata onto another storage layer, e.g. Eth mainnet, incurring additional storage gas costs.
+ uint256 dataAvailabilityCost = 0;
+ // Only calculate data availability cost if data availability multiplier is non-zero.
+ // The multiplier should be set to 0 if destination chain does not charge data availability cost.
+ if (s_dynamicConfig.destDataAvailabilityMultiplierBps > 0) {
+ dataAvailabilityCost = _getDataAvailabilityCost(
+ // Parse the data availability gas price stored in the higher-order 112 bits of the encoded gas price.
+ uint112(packedGasPrice >> Internal.GAS_PRICE_BITS),
+ message.data.length,
+ message.tokenAmounts.length,
+ tokenTransferBytesOverhead
+ );
+ }
+
+ // Calculate execution gas fee on destination chain in USD with 36 decimals.
+ // We add the message gas limit, the overhead gas, the gas of passing message data to receiver, and token transfer gas together.
+ // We then multiply this gas total with the gas multiplier and gas price, converting it into USD with 36 decimals.
+ // uint112(packedGasPrice) = executionGasPrice
+ uint256 executionCost = uint112(packedGasPrice)
+ * (
+ extraArgs.gasLimit + s_dynamicConfig.destGasOverhead
+ + (message.data.length * s_dynamicConfig.destGasPerPayloadByte) + tokenTransferGas
+ ) * feeTokenConfig.gasMultiplierWeiPerEth;
+
+ // Calculate number of fee tokens to charge.
+ // Total USD fee is in 36 decimals, feeTokenPrice is in 18 decimals USD for 1e18 smallest token denominations.
+ // Result of the division is the number of smallest token denominations.
+ return
+ ((premiumFee * feeTokenConfig.premiumMultiplierWeiPerEth) + executionCost + dataAvailabilityCost) / feeTokenPrice;
+ }
+
+ /// @notice Returns the estimated data availability cost of the message.
+ /// @dev To save on gas, we use a single destGasPerDataAvailabilityByte value for both zero and non-zero bytes.
+ /// @param dataAvailabilityGasPrice USD per data availability gas in 18 decimals.
+ /// @param messageDataLength length of the data field in the message.
+ /// @param numberOfTokens number of distinct token transfers in the message.
+ /// @param tokenTransferBytesOverhead additional token transfer data passed to destination, e.g. USDC attestation.
+ /// @return dataAvailabilityCostUSD36Decimal total data availability cost in USD with 36 decimals.
+ function _getDataAvailabilityCost(
+ uint112 dataAvailabilityGasPrice,
+ uint256 messageDataLength,
+ uint256 numberOfTokens,
+ uint32 tokenTransferBytesOverhead
+ ) internal view returns (uint256 dataAvailabilityCostUSD36Decimal) {
+ // dataAvailabilityLengthBytes sums up byte lengths of fixed message fields and dynamic message fields.
+ // Fixed message fields do account for the offset and length slot of the dynamic fields.
+ uint256 dataAvailabilityLengthBytes = Internal.MESSAGE_FIXED_BYTES + messageDataLength
+ + (numberOfTokens * Internal.MESSAGE_FIXED_BYTES_PER_TOKEN) + tokenTransferBytesOverhead;
+
+ // destDataAvailabilityOverheadGas is a separate config value for flexibility to be updated independently of message cost.
+ // Its value is determined by CCIP lane implementation, e.g. the overhead data posted for OCR.
+ uint256 dataAvailabilityGas = (dataAvailabilityLengthBytes * s_dynamicConfig.destGasPerDataAvailabilityByte)
+ + s_dynamicConfig.destDataAvailabilityOverheadGas;
+
+ // dataAvailabilityGasPrice is in 18 decimals, destDataAvailabilityMultiplierBps is in 4 decimals
+ // We pad 14 decimals to bring the result to 36 decimals, in line with token bps and execution fee.
+ return ((dataAvailabilityGas * dataAvailabilityGasPrice) * s_dynamicConfig.destDataAvailabilityMultiplierBps) * 1e14;
+ }
+
+ /// @notice Returns the token transfer cost parameters.
+ /// A basis point fee is calculated from the USD value of each token transfer.
+ /// For each individual transfer, this fee is between [minFeeUSD, maxFeeUSD].
+ /// Total transfer fee is the sum of each individual token transfer fee.
+ /// @dev Assumes that tokenAmounts are validated to be listed tokens elsewhere.
+ /// @dev Splitting one token transfer into multiple transfers is discouraged,
+ /// as it will result in a transferFee equal or greater than the same amount aggregated/de-duped.
+ /// @param feeToken address of the feeToken.
+ /// @param feeTokenPrice price of feeToken in USD with 18 decimals.
+ /// @param tokenAmounts token transfers in the message.
+ /// @return tokenTransferFeeUSDWei total token transfer bps fee in USD with 18 decimals.
+ /// @return tokenTransferGas total execution gas of the token transfers.
+ /// @return tokenTransferBytesOverhead additional token transfer data passed to destination, e.g. USDC attestation.
+ function _getTokenTransferCost(
+ address feeToken,
+ uint224 feeTokenPrice,
+ Client.EVMTokenAmount[] calldata tokenAmounts
+ ) internal view returns (uint256 tokenTransferFeeUSDWei, uint32 tokenTransferGas, uint32 tokenTransferBytesOverhead) {
+ uint256 numberOfTokens = tokenAmounts.length;
+
+ for (uint256 i = 0; i < numberOfTokens; ++i) {
+ Client.EVMTokenAmount memory tokenAmount = tokenAmounts[i];
+
+ // Validate if the token is supported, do not calculate fee for unsupported tokens.
+ if (address(getPoolBySourceToken(i_destChainSelector, IERC20(tokenAmount.token))) == address(0)) {
+ revert UnsupportedToken(tokenAmount.token);
+ }
+
+ TokenTransferFeeConfig memory transferFeeConfig = s_tokenTransferFeeConfig[tokenAmount.token];
+
+ // If the token has no specific overrides configured, we use the global defaults.
+ if (!transferFeeConfig.isEnabled) {
+ tokenTransferFeeUSDWei += uint256(s_dynamicConfig.defaultTokenFeeUSDCents) * 1e16;
+ tokenTransferGas += s_dynamicConfig.defaultTokenDestGasOverhead;
+ tokenTransferBytesOverhead += s_dynamicConfig.defaultTokenDestBytesOverhead;
+ continue;
+ }
+
+ uint256 bpsFeeUSDWei = 0;
+ // Only calculate bps fee if ratio is greater than 0. Ratio of 0 means no bps fee for a token.
+ // Useful for when the PriceRegistry cannot return a valid price for the token.
+ if (transferFeeConfig.deciBps > 0) {
+ uint224 tokenPrice = 0;
+ if (tokenAmount.token != feeToken) {
+ tokenPrice = IPriceRegistry(s_dynamicConfig.priceRegistry).getValidatedTokenPrice(tokenAmount.token);
+ } else {
+ tokenPrice = feeTokenPrice;
+ }
+
+ // Calculate token transfer value, then apply fee ratio
+ // ratio represents multiples of 0.1bps, or 1e-5
+ bpsFeeUSDWei = (tokenPrice._calcUSDValueFromTokenAmount(tokenAmount.amount) * transferFeeConfig.deciBps) / 1e5;
+ }
+
+ tokenTransferGas += transferFeeConfig.destGasOverhead;
+ tokenTransferBytesOverhead += transferFeeConfig.destBytesOverhead;
+
+ // Bps fees should be kept within range of [minFeeUSD, maxFeeUSD].
+ // Convert USD values with 2 decimals to 18 decimals.
+ uint256 minFeeUSDWei = uint256(transferFeeConfig.minFeeUSDCents) * 1e16;
+ if (bpsFeeUSDWei < minFeeUSDWei) {
+ tokenTransferFeeUSDWei += minFeeUSDWei;
+ continue;
+ }
+
+ uint256 maxFeeUSDWei = uint256(transferFeeConfig.maxFeeUSDCents) * 1e16;
+ if (bpsFeeUSDWei > maxFeeUSDWei) {
+ tokenTransferFeeUSDWei += maxFeeUSDWei;
+ continue;
+ }
+
+ tokenTransferFeeUSDWei += bpsFeeUSDWei;
+ }
+
+ return (tokenTransferFeeUSDWei, tokenTransferGas, tokenTransferBytesOverhead);
+ }
+
+ /// @notice Gets the fee configuration for a token
+ /// @param token The token to get the fee configuration for
+ /// @return feeTokenConfig FeeTokenConfig struct
+ function getFeeTokenConfig(address token) external view returns (FeeTokenConfig memory feeTokenConfig) {
+ return s_feeTokenConfig[token];
+ }
+
+ /// @notice Sets the fee configuration for a token
+ /// @param feeTokenConfigArgs Array of FeeTokenConfigArgs structs.
+ function setFeeTokenConfig(FeeTokenConfigArgs[] memory feeTokenConfigArgs) external {
+ _onlyOwnerOrAdmin();
+ _setFeeTokenConfig(feeTokenConfigArgs);
+ }
+
+ /// @dev Set the fee config
+ /// @param feeTokenConfigArgs The fee token configs.
+ function _setFeeTokenConfig(FeeTokenConfigArgs[] memory feeTokenConfigArgs) internal {
+ for (uint256 i = 0; i < feeTokenConfigArgs.length; ++i) {
+ FeeTokenConfigArgs memory configArg = feeTokenConfigArgs[i];
+
+ s_feeTokenConfig[configArg.token] = FeeTokenConfig({
+ networkFeeUSDCents: configArg.networkFeeUSDCents,
+ gasMultiplierWeiPerEth: configArg.gasMultiplierWeiPerEth,
+ premiumMultiplierWeiPerEth: configArg.premiumMultiplierWeiPerEth,
+ enabled: configArg.enabled
+ });
+ }
+ emit FeeConfigSet(feeTokenConfigArgs);
+ }
+
+ /// @notice Gets the transfer fee config for a given token.
+ function getTokenTransferFeeConfig(address token)
+ external
+ view
+ returns (TokenTransferFeeConfig memory tokenTransferFeeConfig)
+ {
+ return s_tokenTransferFeeConfig[token];
+ }
+
+ /// @notice Sets the transfer fee config.
+ /// @dev only callable by the owner or admin.
+ function setTokenTransferFeeConfig(
+ TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
+ address[] memory tokensToUseDefaultFeeConfigs
+ ) external {
+ _onlyOwnerOrAdmin();
+ _setTokenTransferFeeConfig(tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs);
+ }
+
+ /// @notice internal helper to set the token transfer fee config.
+ function _setTokenTransferFeeConfig(
+ TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
+ address[] memory tokensToUseDefaultFeeConfigs
+ ) internal {
+ for (uint256 i = 0; i < tokenTransferFeeConfigArgs.length; ++i) {
+ TokenTransferFeeConfigArgs memory configArg = tokenTransferFeeConfigArgs[i];
+
+ if (configArg.destBytesOverhead < Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) {
+ revert InvalidDestBytesOverhead(configArg.token, configArg.destBytesOverhead);
+ }
+
+ s_tokenTransferFeeConfig[configArg.token] = TokenTransferFeeConfig({
+ minFeeUSDCents: configArg.minFeeUSDCents,
+ maxFeeUSDCents: configArg.maxFeeUSDCents,
+ deciBps: configArg.deciBps,
+ destGasOverhead: configArg.destGasOverhead,
+ destBytesOverhead: configArg.destBytesOverhead,
+ aggregateRateLimitEnabled: configArg.aggregateRateLimitEnabled,
+ isEnabled: true
+ });
+ }
+ emit TokenTransferFeeConfigSet(tokenTransferFeeConfigArgs);
+
+ // Remove the custom fee configs for the tokens that are in the tokensToUseDefaultFeeConfigs array
+ for (uint256 i = 0; i < tokensToUseDefaultFeeConfigs.length; ++i) {
+ delete s_tokenTransferFeeConfig[tokensToUseDefaultFeeConfigs[i]];
+ }
+ if (tokensToUseDefaultFeeConfigs.length > 0) {
+ emit TokenTransferFeeConfigDeleted(tokensToUseDefaultFeeConfigs);
+ }
+ }
+
+ // ================================================================
+ // │ NOP payments │
+ // ================================================================
+
+ /// @notice Get the total amount of fees to be paid to the Nops (in LINK)
+ /// @return totalNopFees
+ function getNopFeesJuels() external view returns (uint96) {
+ return s_nopFeesJuels;
+ }
+
+ /// @notice Gets the Nops and their weights
+ /// @return nopsAndWeights Array of NopAndWeight structs
+ /// @return weightsTotal The sum weight of all Nops
+ function getNops() external view returns (NopAndWeight[] memory nopsAndWeights, uint256 weightsTotal) {
+ uint256 length = s_nops.length();
+ nopsAndWeights = new NopAndWeight[](length);
+ for (uint256 i = 0; i < length; ++i) {
+ (address nopAddress, uint256 nopWeight) = s_nops.at(i);
+ nopsAndWeights[i] = NopAndWeight({nop: nopAddress, weight: uint16(nopWeight)});
+ }
+ weightsTotal = s_nopWeightsTotal;
+ return (nopsAndWeights, weightsTotal);
+ }
+
+ /// @notice Sets the Nops and their weights
+ /// @param nopsAndWeights Array of NopAndWeight structs
+ function setNops(NopAndWeight[] calldata nopsAndWeights) external {
+ _onlyOwnerOrAdmin();
+ _setNops(nopsAndWeights);
+ }
+
+ /// @param nopsAndWeights New set of nops and weights
+ /// @dev Clears existing nops, sets new nops and weights
+ /// @dev We permit fees to accrue before nops are configured, in which case
+ /// they will go to the first set of configured nops.
+ function _setNops(NopAndWeight[] memory nopsAndWeights) internal {
+ uint256 numberOfNops = nopsAndWeights.length;
+ if (numberOfNops > MAX_NUMBER_OF_NOPS) revert TooManyNops();
+
+ // Make sure all nops have been paid before removing nops
+ // We only have to pay when there are nops and there is enough
+ // outstanding NOP balance to trigger a payment.
+ if (s_nopWeightsTotal > 0) {
+ if (s_nopFeesJuels >= s_nopWeightsTotal) {
+ payNops();
+ }
+ }
+
+ // Remove all previous nops, move from end to start to avoid shifting
+ for (uint256 i = s_nops.length(); i > 0; --i) {
+ (address nop,) = s_nops.at(i - 1);
+ s_nops.remove(nop);
+ }
+
+ // Add new
+ uint32 nopWeightsTotal = 0;
+ // nopWeightsTotal is bounded by the MAX_NUMBER_OF_NOPS and the weight of
+ // a single nop being of type uint16. This ensures nopWeightsTotal will
+ // always fit into the uint32 type.
+ for (uint256 i = 0; i < numberOfNops; ++i) {
+ // Make sure the LINK token is not a nop because the link token doesn't allow
+ // self transfers. If set as nop, payNops would always revert. Since setNops
+ // calls payNops, we can never remove the LINK token as a nop.
+ address nop = nopsAndWeights[i].nop;
+ uint16 weight = nopsAndWeights[i].weight;
+ if (nop == i_linkToken || nop == address(0)) revert InvalidNopAddress(nop);
+ s_nops.set(nop, weight);
+ nopWeightsTotal += weight;
+ }
+ s_nopWeightsTotal = nopWeightsTotal;
+ emit NopsSet(nopWeightsTotal, nopsAndWeights);
+ }
+
+ /// @notice Pays the Node Ops their outstanding balances.
+ /// @dev some balance can remain after payments are done. This is at most the sum
+ /// of the weight of all nops. Since nop weights are uint16s and we can have at
+ /// most MAX_NUMBER_OF_NOPS NOPs, the highest possible value is 2**22 or 0.04 gjuels.
+ function payNops() public {
+ if (msg.sender != owner()) {
+ if (msg.sender != s_admin) {
+ if (!s_nops.contains(msg.sender)) {
+ revert OnlyCallableByOwnerOrAdminOrNop();
+ }
+ }
+ }
+ uint256 weightsTotal = s_nopWeightsTotal;
+ if (weightsTotal == 0) revert NoNopsToPay();
+
+ uint96 totalFeesToPay = s_nopFeesJuels;
+ if (totalFeesToPay < weightsTotal) revert NoFeesToPay();
+ if (linkAvailableForPayment() < 0) revert InsufficientBalance();
+
+ uint96 fundsLeft = totalFeesToPay;
+ uint256 numberOfNops = s_nops.length();
+ for (uint256 i = 0; i < numberOfNops; ++i) {
+ (address nop, uint256 weight) = s_nops.at(i);
+ // amount can never be higher than totalFeesToPay so the cast to uint96 is safe
+ uint96 amount = uint96((totalFeesToPay * weight) / weightsTotal);
+ fundsLeft -= amount;
+ IERC20(i_linkToken).safeTransfer(nop, amount);
+ emit NopPaid(nop, amount);
+ }
+ // Some funds can remain, since this is an incredibly small
+ // amount we consider this OK.
+ s_nopFeesJuels = fundsLeft;
+ }
+
+ /// @notice Allows the owner to withdraw any ERC20 token from the contract.
+ /// The NOP link balance is not withdrawable.
+ /// @param feeToken The token to withdraw
+ /// @param to The address to send the tokens to
+ function withdrawNonLinkFees(address feeToken, address to) external {
+ _onlyOwnerOrAdmin();
+ if (to == address(0)) revert InvalidWithdrawParams();
+
+ // We require the link balance to be settled before allowing withdrawal of non-link fees.
+ int256 linkAfterNopFees = linkAvailableForPayment();
+ if (linkAfterNopFees < 0) revert LinkBalanceNotSettled();
+
+ if (feeToken == i_linkToken) {
+ // Withdraw only the left over link balance
+ IERC20(feeToken).safeTransfer(to, uint256(linkAfterNopFees));
+ } else {
+ // Withdrawal all non-link tokens in the contract
+ IERC20(feeToken).safeTransfer(to, IERC20(feeToken).balanceOf(address(this)));
+ }
+ }
+
+ // ================================================================
+ // │ Link monitoring │
+ // ================================================================
+
+ /// @notice Calculate remaining LINK balance after paying nops
+ /// @dev Allow keeper to monitor funds available for paying nops
+ /// @return balance if nops were to be paid
+ function linkAvailableForPayment() public view returns (int256) {
+ // Since LINK caps at uint96, casting to int256 is safe
+ return int256(IERC20(i_linkToken).balanceOf(address(this))) - int256(uint256(s_nopFeesJuels));
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @dev Require that the sender is the owner or the fee admin
+ /// Not a modifier to save on contract size
+ function _onlyOwnerOrAdmin() internal view {
+ if (msg.sender != owner()) {
+ if (msg.sender != s_admin) {
+ revert OnlyCallableByOwnerOrAdmin();
+ }
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/BurnFromMintTokenPool.sol b/contracts/src/v0.8/ccip/pools/BurnFromMintTokenPool.sol
new file mode 100644
index 00000000000..de68b18a302
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/BurnFromMintTokenPool.sol
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol";
+
+import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol";
+import {TokenPool} from "./TokenPool.sol";
+
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+
+/// @notice This pool mints and burns a 3rd-party token.
+/// @dev Pool whitelisting mode is set in the constructor and cannot be modified later.
+/// It either accepts any address as originalSender, or only accepts whitelisted originalSender.
+/// The only way to change whitelisting mode is to deploy a new pool.
+/// If that is expected, please make sure the token's burner/minter roles are adjustable.
+/// @dev This contract is a variant of BurnMintTokenPool that uses `burnFrom(from, amount)`.
+contract BurnFromMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersion {
+ using SafeERC20 for IBurnMintERC20;
+
+ string public constant override typeAndVersion = "BurnFromMintTokenPool 1.5.0-dev";
+
+ constructor(
+ IBurnMintERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) TokenPool(token, allowlist, rmnProxy, router) {
+ // Some tokens allow burning from the sender without approval, but not all do.
+ // To be safe, we approve the pool to burn from the pool.
+ token.safeIncreaseAllowance(address(this), type(uint256).max);
+ }
+
+ /// @inheritdoc BurnMintTokenPoolAbstract
+ function _burn(uint256 amount) internal virtual override {
+ IBurnMintERC20(address(i_token)).burnFrom(address(this), amount);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/BurnMintTokenPool.sol b/contracts/src/v0.8/ccip/pools/BurnMintTokenPool.sol
new file mode 100644
index 00000000000..a8562ae4d36
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/BurnMintTokenPool.sol
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol";
+
+import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol";
+import {TokenPool} from "./TokenPool.sol";
+
+/// @notice This pool mints and burns a 3rd-party token.
+/// @dev Pool whitelisting mode is set in the constructor and cannot be modified later.
+/// It either accepts any address as originalSender, or only accepts whitelisted originalSender.
+/// The only way to change whitelisting mode is to deploy a new pool.
+/// If that is expected, please make sure the token's burner/minter roles are adjustable.
+/// @dev This contract is a variant of BurnMintTokenPool that uses `burn(amount)`.
+contract BurnMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersion {
+ string public constant override typeAndVersion = "BurnMintTokenPool 1.5.0-dev";
+
+ constructor(
+ IBurnMintERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) TokenPool(token, allowlist, rmnProxy, router) {}
+
+ /// @inheritdoc BurnMintTokenPoolAbstract
+ function _burn(uint256 amount) internal virtual override {
+ IBurnMintERC20(address(i_token)).burn(amount);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol b/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol
new file mode 100644
index 00000000000..2085c9427b0
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol";
+
+import {Pool} from "../libraries/Pool.sol";
+import {TokenPool} from "./TokenPool.sol";
+
+abstract contract BurnMintTokenPoolAbstract is TokenPool {
+ /// @notice Contains the specific burn call for a pool.
+ /// @dev overriding this method allows us to create pools with different burn signatures
+ /// without duplicating the underlying logic.
+ function _burn(uint256 amount) internal virtual;
+
+ /// @notice Burn the token in the pool
+ /// @dev The _validateLockOrBurn check is an essential security check
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ virtual
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ _validateLockOrBurn(lockOrBurnIn);
+
+ _burn(lockOrBurnIn.amount);
+
+ emit Burned(msg.sender, lockOrBurnIn.amount);
+
+ return Pool.LockOrBurnOutV1({destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: ""});
+ }
+
+ /// @notice Mint tokens from the pool to the recipient
+ /// @dev The _validateReleaseOrMint check is an essential security check
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ virtual
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ _validateReleaseOrMint(releaseOrMintIn);
+
+ // Mint to the offRamp, which forwards it to the recipient
+ IBurnMintERC20(address(i_token)).mint(msg.sender, releaseOrMintIn.amount);
+
+ emit Minted(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount);
+
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAndProxy.sol b/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAndProxy.sol
new file mode 100644
index 00000000000..a3a7e082cc7
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAndProxy.sol
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol";
+
+import {Pool} from "../libraries/Pool.sol";
+import {LegacyPoolWrapper} from "./LegacyPoolWrapper.sol";
+
+contract BurnMintTokenPoolAndProxy is ITypeAndVersion, LegacyPoolWrapper {
+ string public constant override typeAndVersion = "BurnMintTokenPoolAndProxy 1.5.0-dev";
+
+ constructor(
+ IBurnMintERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) LegacyPoolWrapper(token, allowlist, rmnProxy, router) {}
+
+ /// @notice Burn the token in the pool
+ /// @dev The _validateLockOrBurn check is an essential security check
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ virtual
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ _validateLockOrBurn(lockOrBurnIn);
+
+ if (!_hasLegacyPool()) {
+ IBurnMintERC20(address(i_token)).burn(lockOrBurnIn.amount);
+ } else {
+ _lockOrBurnLegacy(lockOrBurnIn);
+ }
+
+ emit Burned(msg.sender, lockOrBurnIn.amount);
+
+ return Pool.LockOrBurnOutV1({destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: ""});
+ }
+
+ /// @notice Mint tokens from the pool to the recipient
+ /// @dev The _validateReleaseOrMint check is an essential security check
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ virtual
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ _validateReleaseOrMint(releaseOrMintIn);
+
+ if (!_hasLegacyPool()) {
+ // Mint to the offRamp, which forwards it to the recipient
+ IBurnMintERC20(address(i_token)).mint(msg.sender, releaseOrMintIn.amount);
+ } else {
+ _releaseOrMintLegacy(releaseOrMintIn);
+ }
+
+ emit Minted(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount);
+
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/BurnWithFromMintTokenPool.sol b/contracts/src/v0.8/ccip/pools/BurnWithFromMintTokenPool.sol
new file mode 100644
index 00000000000..33f6c43c5b0
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/BurnWithFromMintTokenPool.sol
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IBurnMintERC20} from "../../shared/token/ERC20/IBurnMintERC20.sol";
+
+import {BurnMintTokenPoolAbstract} from "./BurnMintTokenPoolAbstract.sol";
+import {TokenPool} from "./TokenPool.sol";
+
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+
+/// @notice This pool mints and burns a 3rd-party token.
+/// @dev Pool whitelisting mode is set in the constructor and cannot be modified later.
+/// It either accepts any address as originalSender, or only accepts whitelisted originalSender.
+/// The only way to change whitelisting mode is to deploy a new pool.
+/// If that is expected, please make sure the token's burner/minter roles are adjustable.
+/// @dev This contract is a variant of BurnMintTokenPool that uses `burn(from, amount)`.
+contract BurnWithFromMintTokenPool is BurnMintTokenPoolAbstract, ITypeAndVersion {
+ using SafeERC20 for IBurnMintERC20;
+
+ string public constant override typeAndVersion = "BurnWithFromMintTokenPool 1.5.0-dev";
+
+ constructor(
+ IBurnMintERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) TokenPool(token, allowlist, rmnProxy, router) {
+ // Some tokens allow burning from the sender without approval, but not all do.
+ // To be safe, we approve the pool to burn from the pool.
+ token.safeIncreaseAllowance(address(this), type(uint256).max);
+ }
+
+ /// @inheritdoc BurnMintTokenPoolAbstract
+ function _burn(uint256 amount) internal virtual override {
+ IBurnMintERC20(address(i_token)).burn(address(this), amount);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/LegacyPoolWrapper.sol b/contracts/src/v0.8/ccip/pools/LegacyPoolWrapper.sol
new file mode 100644
index 00000000000..125a3a28ee4
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/LegacyPoolWrapper.sol
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IPoolPriorTo1_5} from "../interfaces/IPoolPriorTo1_5.sol";
+
+import {Pool} from "../libraries/Pool.sol";
+import {TokenPool} from "./TokenPool.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";
+
+abstract contract LegacyPoolWrapper is TokenPool {
+ using SafeERC20 for IERC20;
+
+ event LegacyPoolChanged(IPoolPriorTo1_5 oldPool, IPoolPriorTo1_5 newPool);
+
+ /// @dev The previous pool, if there is any. This is a property to make the older 1.0-1.4 pools
+ /// compatible with the current 1.5 pool. To achieve this, we set the previous pool address to the
+ /// currently deployed legacy pool. Then we configure this new pool as onRamp and offRamp on the legacy pools.
+ /// In the case of a 1.4 pool, this new pool contract has to be set to the Router as well, as it validates
+ /// who can call it through the router calls. This contract will always return itself as the only allowed ramp.
+ /// @dev Can be address(0), this would indicate that this pool is operating as a normal pool as opposed to
+ /// a proxy pool.
+ IPoolPriorTo1_5 internal s_previousPool;
+
+ constructor(
+ IERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) TokenPool(token, allowlist, rmnProxy, router) {}
+
+ // ================================================================
+ // │ Legacy Fallbacks │
+ // ================================================================
+ // Legacy fallbacks for older token pools that do not implement the new interface.
+
+ /// @notice Legacy fallback for the 1.4 token pools.
+ function getOnRamp(uint64) external view returns (address onRampAddress) {
+ return address(this);
+ }
+
+ /// @notice Return true if the given offRamp is a configured offRamp for the given source chain.
+ function isOffRamp(uint64 sourceChainSelector, address offRamp) external view returns (bool) {
+ return offRamp == address(this) || s_router.isOffRamp(sourceChainSelector, offRamp);
+ }
+
+ /// @notice Configures the legacy fallback option. If the previous pool is set, this pool will act as a proxy for
+ /// the legacy pool.
+ /// @param prevPool The address of the previous pool.
+ function setPreviousPool(IPoolPriorTo1_5 prevPool) external onlyOwner {
+ IPoolPriorTo1_5 oldPrevPool = s_previousPool;
+ s_previousPool = prevPool;
+
+ emit LegacyPoolChanged(oldPrevPool, prevPool);
+ }
+
+ function _hasLegacyPool() internal view returns (bool) {
+ return address(s_previousPool) != address(0);
+ }
+
+ function _lockOrBurnLegacy(Pool.LockOrBurnInV1 memory lockOrBurnIn) internal {
+ i_token.safeTransfer(address(s_previousPool), lockOrBurnIn.amount);
+ s_previousPool.lockOrBurn(
+ lockOrBurnIn.originalSender, lockOrBurnIn.receiver, lockOrBurnIn.amount, lockOrBurnIn.remoteChainSelector, ""
+ );
+ }
+
+ /// @notice This call converts the arguments from a >=1.5 pool call to those of a <1.5 pool call, and uses these
+ /// to call the previous pool.
+ /// @param releaseOrMintIn The 1.5 style release or mint arguments.
+ /// @dev Overwrites the receiver so the previous pool sends the tokens to the sender of this call, which is the
+ /// offRamp. This is due to the older pools sending funds directly to the receiver, while the new pools do a hop
+ /// through the offRamp to ensure the correct tokens are sent.
+ /// @dev Since extraData has never been used in LockRelease or MintBurn token pools, we can safely ignore it.
+ function _releaseOrMintLegacy(Pool.ReleaseOrMintInV1 memory releaseOrMintIn) internal {
+ s_previousPool.releaseOrMint(
+ releaseOrMintIn.originalSender, msg.sender, releaseOrMintIn.amount, releaseOrMintIn.remoteChainSelector, ""
+ );
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/LockReleaseTokenPool.sol b/contracts/src/v0.8/ccip/pools/LockReleaseTokenPool.sol
new file mode 100644
index 00000000000..5716777fb5e
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/LockReleaseTokenPool.sol
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ILiquidityContainer} from "../../liquiditymanager/interfaces/ILiquidityContainer.sol";
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+
+import {Pool} from "../libraries/Pool.sol";
+import {RateLimiter} from "../libraries/RateLimiter.sol";
+import {TokenPool} from "./TokenPool.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 Token pool used for tokens on their native chain. This uses a lock and release mechanism.
+/// Because of lock/unlock requiring liquidity, this pool contract also has function to add and remove
+/// liquidity. This allows for proper bookkeeping for both user and liquidity provider balances.
+/// @dev One token per LockReleaseTokenPool.
+contract LockReleaseTokenPool is TokenPool, ILiquidityContainer, ITypeAndVersion {
+ using SafeERC20 for IERC20;
+
+ error InsufficientLiquidity();
+ error LiquidityNotAccepted();
+ error Unauthorized(address caller);
+
+ string public constant override typeAndVersion = "LockReleaseTokenPool 1.5.0-dev";
+
+ /// @dev Whether or not the pool accepts liquidity.
+ /// External liquidity is not required when there is one canonical token deployed to a chain,
+ /// and CCIP is facilitating mint/burn on all the other chains, in which case the invariant
+ /// balanceOf(pool) on home chain == sum(totalSupply(mint/burn "wrapped" token) on all remote chains) should always hold
+ bool internal immutable i_acceptLiquidity;
+ /// @notice The address of the rebalancer.
+ address internal s_rebalancer;
+ /// @notice The address of the rate limiter admin.
+ /// @dev Can be address(0) if none is configured.
+ address internal s_rateLimitAdmin;
+
+ constructor(
+ IERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ bool acceptLiquidity,
+ address router
+ ) TokenPool(token, allowlist, rmnProxy, router) {
+ i_acceptLiquidity = acceptLiquidity;
+ }
+
+ /// @notice Locks the token in the pool
+ /// @dev The _validateLockOrBurn check is an essential security check
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ virtual
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ _validateLockOrBurn(lockOrBurnIn);
+
+ emit Locked(msg.sender, lockOrBurnIn.amount);
+
+ return Pool.LockOrBurnOutV1({destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: ""});
+ }
+
+ /// @notice Release tokens from the pool to the recipient
+ /// @dev The _validateReleaseOrMint check is an essential security check
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ virtual
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ _validateReleaseOrMint(releaseOrMintIn);
+
+ // Release to the offRamp, which forwards it to the recipient
+ getToken().safeTransfer(msg.sender, releaseOrMintIn.amount);
+
+ emit Released(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount);
+
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+
+ // @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
+ return interfaceId == type(ILiquidityContainer).interfaceId || super.supportsInterface(interfaceId);
+ }
+
+ /// @notice Gets LiquidityManager, can be address(0) if none is configured.
+ /// @return The current liquidity manager.
+ function getRebalancer() external view returns (address) {
+ return s_rebalancer;
+ }
+
+ /// @notice Sets the LiquidityManager address.
+ /// @dev Only callable by the owner.
+ function setRebalancer(address rebalancer) external onlyOwner {
+ s_rebalancer = rebalancer;
+ }
+
+ /// @notice Sets the rate limiter admin address.
+ /// @dev Only callable by the owner.
+ /// @param rateLimitAdmin The new rate limiter admin address.
+ function setRateLimitAdmin(address rateLimitAdmin) external onlyOwner {
+ s_rateLimitAdmin = rateLimitAdmin;
+ }
+
+ /// @notice Gets the rate limiter admin address.
+ function getRateLimitAdmin() external view returns (address) {
+ return s_rateLimitAdmin;
+ }
+
+ /// @notice Checks if the pool can accept liquidity.
+ /// @return true if the pool can accept liquidity, false otherwise.
+ function canAcceptLiquidity() external view returns (bool) {
+ return i_acceptLiquidity;
+ }
+
+ /// @notice Adds liquidity to the pool. The tokens should be approved first.
+ /// @param amount The amount of liquidity to provide.
+ function provideLiquidity(uint256 amount) external {
+ if (!i_acceptLiquidity) revert LiquidityNotAccepted();
+ if (s_rebalancer != msg.sender) revert Unauthorized(msg.sender);
+
+ i_token.safeTransferFrom(msg.sender, address(this), amount);
+ emit LiquidityAdded(msg.sender, amount);
+ }
+
+ /// @notice Removed liquidity to the pool. The tokens will be sent to msg.sender.
+ /// @param amount The amount of liquidity to remove.
+ function withdrawLiquidity(uint256 amount) external {
+ if (s_rebalancer != msg.sender) revert Unauthorized(msg.sender);
+
+ if (i_token.balanceOf(address(this)) < amount) revert InsufficientLiquidity();
+ i_token.safeTransfer(msg.sender, amount);
+ emit LiquidityRemoved(msg.sender, amount);
+ }
+
+ /// @notice Sets the rate limiter admin address.
+ /// @dev Only callable by the owner or the rate limiter admin. NOTE: overwrites the normal
+ /// onlyAdmin check in the base implementation to also allow the rate limiter admin.
+ /// @param remoteChainSelector The remote chain selector for which the rate limits apply.
+ /// @param outboundConfig The new outbound rate limiter config.
+ /// @param inboundConfig The new inbound rate limiter config.
+ function setChainRateLimiterConfig(
+ uint64 remoteChainSelector,
+ RateLimiter.Config memory outboundConfig,
+ RateLimiter.Config memory inboundConfig
+ ) external override {
+ if (msg.sender != s_rateLimitAdmin && msg.sender != owner()) revert Unauthorized(msg.sender);
+
+ _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/LockReleaseTokenPoolAndProxy.sol b/contracts/src/v0.8/ccip/pools/LockReleaseTokenPoolAndProxy.sol
new file mode 100644
index 00000000000..91766d5f26a
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/LockReleaseTokenPoolAndProxy.sol
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ILiquidityContainer} from "../../liquiditymanager/interfaces/ILiquidityContainer.sol";
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+
+import {Pool} from "../libraries/Pool.sol";
+import {RateLimiter} from "../libraries/RateLimiter.sol";
+import {LegacyPoolWrapper} from "./LegacyPoolWrapper.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 Token pool used for tokens on their native chain. This uses a lock and release mechanism.
+/// Because of lock/unlock requiring liquidity, this pool contract also has function to add and remove
+/// liquidity. This allows for proper bookkeeping for both user and liquidity provider balances.
+/// @dev One token per LockReleaseTokenPool.
+contract LockReleaseTokenPoolAndProxy is LegacyPoolWrapper, ILiquidityContainer, ITypeAndVersion {
+ using SafeERC20 for IERC20;
+
+ error InsufficientLiquidity();
+ error LiquidityNotAccepted();
+ error Unauthorized(address caller);
+
+ string public constant override typeAndVersion = "LockReleaseTokenPoolAndProxy 1.5.0-dev";
+
+ /// @dev Whether or not the pool accepts liquidity.
+ /// External liquidity is not required when there is one canonical token deployed to a chain,
+ /// and CCIP is facilitating mint/burn on all the other chains, in which case the invariant
+ /// balanceOf(pool) on home chain == sum(totalSupply(mint/burn "wrapped" token) on all remote chains) should always hold
+ bool internal immutable i_acceptLiquidity;
+ /// @notice The address of the rebalancer.
+ address internal s_rebalancer;
+ /// @notice The address of the rate limiter admin.
+ /// @dev Can be address(0) if none is configured.
+ address internal s_rateLimitAdmin;
+
+ constructor(
+ IERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ bool acceptLiquidity,
+ address router
+ ) LegacyPoolWrapper(token, allowlist, rmnProxy, router) {
+ i_acceptLiquidity = acceptLiquidity;
+ }
+
+ /// @notice Locks the token in the pool
+ /// @dev The _validateLockOrBurn check is an essential security check
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ virtual
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ _validateLockOrBurn(lockOrBurnIn);
+
+ if (_hasLegacyPool()) {
+ _lockOrBurnLegacy(lockOrBurnIn);
+ }
+
+ emit Locked(msg.sender, lockOrBurnIn.amount);
+
+ return Pool.LockOrBurnOutV1({destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: ""});
+ }
+
+ /// @notice Release tokens from the pool to the recipient
+ /// @dev The _validateReleaseOrMint check is an essential security check
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ virtual
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ _validateReleaseOrMint(releaseOrMintIn);
+
+ if (!_hasLegacyPool()) {
+ // Release to the offRamp, which forwards it to the recipient
+ getToken().safeTransfer(msg.sender, releaseOrMintIn.amount);
+ } else {
+ _releaseOrMintLegacy(releaseOrMintIn);
+ }
+
+ emit Released(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount);
+
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+
+ // @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
+ return interfaceId == type(ILiquidityContainer).interfaceId || super.supportsInterface(interfaceId);
+ }
+
+ /// @notice Gets LiquidityManager, can be address(0) if none is configured.
+ /// @return The current liquidity manager.
+ function getRebalancer() external view returns (address) {
+ return s_rebalancer;
+ }
+
+ /// @notice Sets the LiquidityManager address.
+ /// @dev Only callable by the owner.
+ function setRebalancer(address rebalancer) external onlyOwner {
+ s_rebalancer = rebalancer;
+ }
+
+ /// @notice Sets the rate limiter admin address.
+ /// @dev Only callable by the owner.
+ /// @param rateLimitAdmin The new rate limiter admin address.
+ function setRateLimitAdmin(address rateLimitAdmin) external onlyOwner {
+ s_rateLimitAdmin = rateLimitAdmin;
+ }
+
+ /// @notice Gets the rate limiter admin address.
+ function getRateLimitAdmin() external view returns (address) {
+ return s_rateLimitAdmin;
+ }
+
+ /// @notice Checks if the pool can accept liquidity.
+ /// @return true if the pool can accept liquidity, false otherwise.
+ function canAcceptLiquidity() external view returns (bool) {
+ return i_acceptLiquidity;
+ }
+
+ /// @notice Adds liquidity to the pool. The tokens should be approved first.
+ /// @param amount The amount of liquidity to provide.
+ function provideLiquidity(uint256 amount) external {
+ if (!i_acceptLiquidity) revert LiquidityNotAccepted();
+ if (s_rebalancer != msg.sender) revert Unauthorized(msg.sender);
+
+ i_token.safeTransferFrom(msg.sender, address(this), amount);
+ emit LiquidityAdded(msg.sender, amount);
+ }
+
+ /// @notice Removed liquidity to the pool. The tokens will be sent to msg.sender.
+ /// @param amount The amount of liquidity to remove.
+ function withdrawLiquidity(uint256 amount) external {
+ if (s_rebalancer != msg.sender) revert Unauthorized(msg.sender);
+
+ if (i_token.balanceOf(address(this)) < amount) revert InsufficientLiquidity();
+ i_token.safeTransfer(msg.sender, amount);
+ emit LiquidityRemoved(msg.sender, amount);
+ }
+
+ /// @notice Sets the rate limiter admin address.
+ /// @dev Only callable by the owner or the rate limiter admin. NOTE: overwrites the normal
+ /// onlyAdmin check in the base implementation to also allow the rate limiter admin.
+ /// @param remoteChainSelector The remote chain selector for which the rate limits apply.
+ /// @param outboundConfig The new outbound rate limiter config.
+ /// @param inboundConfig The new inbound rate limiter config.
+ function setChainRateLimiterConfig(
+ uint64 remoteChainSelector,
+ RateLimiter.Config memory outboundConfig,
+ RateLimiter.Config memory inboundConfig
+ ) external override {
+ if (msg.sender != s_rateLimitAdmin && msg.sender != owner()) revert Unauthorized(msg.sender);
+
+ _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/TokenPool.sol b/contracts/src/v0.8/ccip/pools/TokenPool.sol
new file mode 100644
index 00000000000..fb1f8c49e6f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/TokenPool.sol
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPoolV1} from "../interfaces/IPool.sol";
+import {IRMN} from "../interfaces/IRMN.sol";
+import {IRouter} from "../interfaces/IRouter.sol";
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+import {Pool} from "../libraries/Pool.sol";
+import {RateLimiter} from "../libraries/RateLimiter.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @notice Base abstract class with common functions for all token pools.
+/// A token pool serves as isolated place for holding tokens and token specific logic
+/// that may execute as tokens move across the bridge.
+abstract contract TokenPool is IPoolV1, OwnerIsCreator {
+ using EnumerableSet for EnumerableSet.AddressSet;
+ using EnumerableSet for EnumerableSet.UintSet;
+ using RateLimiter for RateLimiter.TokenBucket;
+
+ error CallerIsNotARampOnRouter(address caller);
+ error ZeroAddressNotAllowed();
+ error SenderNotAllowed(address sender);
+ error AllowListNotEnabled();
+ error NonExistentChain(uint64 remoteChainSelector);
+ error ChainNotAllowed(uint64 remoteChainSelector);
+ error CursedByRMN();
+ error ChainAlreadyExists(uint64 chainSelector);
+ error InvalidSourcePoolAddress(bytes sourcePoolAddress);
+ error InvalidToken(address token);
+
+ event Locked(address indexed sender, uint256 amount);
+ event Burned(address indexed sender, uint256 amount);
+ event Released(address indexed sender, address indexed recipient, uint256 amount);
+ event Minted(address indexed sender, address indexed recipient, uint256 amount);
+ event ChainAdded(
+ uint64 remoteChainSelector,
+ bytes remoteToken,
+ RateLimiter.Config outboundRateLimiterConfig,
+ RateLimiter.Config inboundRateLimiterConfig
+ );
+ event ChainConfigured(
+ uint64 remoteChainSelector,
+ RateLimiter.Config outboundRateLimiterConfig,
+ RateLimiter.Config inboundRateLimiterConfig
+ );
+ event ChainRemoved(uint64 remoteChainSelector);
+ event RemotePoolSet(uint64 indexed remoteChainSelector, bytes previousPoolAddress, bytes remotePoolAddress);
+ event AllowListAdd(address sender);
+ event AllowListRemove(address sender);
+ event RouterUpdated(address oldRouter, address newRouter);
+
+ struct ChainUpdate {
+ uint64 remoteChainSelector; // ──╮ Remote chain selector
+ bool allowed; // ────────────────╯ Whether the chain should be enabled
+ bytes remotePoolAddress; // Address of the remote pool, ABI encoded in the case of a remove EVM chain.
+ bytes remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain.
+ RateLimiter.Config outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain
+ RateLimiter.Config inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain
+ }
+
+ struct RemoteChainConfig {
+ RateLimiter.TokenBucket outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain
+ RateLimiter.TokenBucket inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain
+ bytes remotePoolAddress; // Address of the remote pool, ABI encoded in the case of a remote EVM chain.
+ bytes remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain.
+ }
+
+ /// @dev The bridgeable token that is managed by this pool.
+ IERC20 internal immutable i_token;
+ /// @dev The address of the RMN proxy
+ address internal immutable i_rmnProxy;
+ /// @dev The immutable flag that indicates if the pool is access-controlled.
+ bool internal immutable i_allowlistEnabled;
+ /// @dev A set of addresses allowed to trigger lockOrBurn as original senders.
+ /// Only takes effect if i_allowlistEnabled is true.
+ /// This can be used to ensure only token-issuer specified addresses can
+ /// move tokens.
+ EnumerableSet.AddressSet internal s_allowList;
+ /// @dev The address of the router
+ IRouter internal s_router;
+ /// @dev A set of allowed chain selectors. We want the allowlist to be enumerable to
+ /// be able to quickly determine (without parsing logs) who can access the pool.
+ /// @dev The chain selectors are in uint256 format because of the EnumerableSet implementation.
+ EnumerableSet.UintSet internal s_remoteChainSelectors;
+ mapping(uint64 remoteChainSelector => RemoteChainConfig) internal s_remoteChainConfigs;
+
+ constructor(IERC20 token, address[] memory allowlist, address rmnProxy, address router) {
+ if (address(token) == address(0) || router == address(0) || rmnProxy == address(0)) revert ZeroAddressNotAllowed();
+ i_token = token;
+ i_rmnProxy = rmnProxy;
+ s_router = IRouter(router);
+
+ // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas.
+ i_allowlistEnabled = allowlist.length > 0;
+ if (i_allowlistEnabled) {
+ _applyAllowListUpdates(new address[](0), allowlist);
+ }
+ }
+
+ /// @notice Get RMN proxy address
+ /// @return rmnProxy Address of RMN proxy
+ function getRmnProxy() public view returns (address rmnProxy) {
+ return i_rmnProxy;
+ }
+
+ /// @inheritdoc IPoolV1
+ function isSupportedToken(address token) public view virtual returns (bool) {
+ return token == address(i_token);
+ }
+
+ /// @notice Gets the IERC20 token that this pool can lock or burn.
+ /// @return token The IERC20 token representation.
+ function getToken() public view returns (IERC20 token) {
+ return i_token;
+ }
+
+ /// @notice Gets the pool's Router
+ /// @return router The pool's Router
+ function getRouter() public view returns (address router) {
+ return address(s_router);
+ }
+
+ /// @notice Sets the pool's Router
+ /// @param newRouter The new Router
+ function setRouter(address newRouter) public onlyOwner {
+ if (newRouter == address(0)) revert ZeroAddressNotAllowed();
+ address oldRouter = address(s_router);
+ s_router = IRouter(newRouter);
+
+ emit RouterUpdated(oldRouter, newRouter);
+ }
+
+ /// @notice Signals which version of the pool interface is supported
+ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
+ return interfaceId == Pool.CCIP_POOL_V1 || interfaceId == type(IPoolV1).interfaceId
+ || interfaceId == type(IERC165).interfaceId;
+ }
+
+ // ================================================================
+ // │ Validation │
+ // ================================================================
+
+ /// @notice Validates the lock or burn input for correctness on
+ /// - token to be locked or burned
+ /// - RMN curse status
+ /// - allowlist status
+ /// - if the sender is a valid onRamp
+ /// - rate limit status
+ /// @param lockOrBurnIn The input to validate.
+ /// @dev This function should always be called before executing a lock or burn. Not doing so would allow
+ /// for various exploits.
+ function _validateLockOrBurn(Pool.LockOrBurnInV1 memory lockOrBurnIn) internal {
+ if (!isSupportedToken(lockOrBurnIn.localToken)) revert InvalidToken(lockOrBurnIn.localToken);
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(lockOrBurnIn.remoteChainSelector)))) revert CursedByRMN();
+ _checkAllowList(lockOrBurnIn.originalSender);
+
+ _onlyOnRamp(lockOrBurnIn.remoteChainSelector);
+ _consumeOutboundRateLimit(lockOrBurnIn.remoteChainSelector, lockOrBurnIn.amount);
+ }
+
+ /// @notice Validates the release or mint input for correctness on
+ /// - token to be released or minted
+ /// - RMN curse status
+ /// - if the sender is a valid offRamp
+ /// - if the source pool is valid
+ /// - rate limit status
+ /// @param releaseOrMintIn The input to validate.
+ /// @dev This function should always be called before executing a lock or burn. Not doing so would allow
+ /// for various exploits.
+ function _validateReleaseOrMint(Pool.ReleaseOrMintInV1 memory releaseOrMintIn) internal {
+ if (!isSupportedToken(releaseOrMintIn.localToken)) revert InvalidToken(releaseOrMintIn.localToken);
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(releaseOrMintIn.remoteChainSelector)))) revert CursedByRMN();
+ _onlyOffRamp(releaseOrMintIn.remoteChainSelector);
+
+ // Validates that the source pool address is configured on this pool.
+ bytes memory configuredRemotePool = getRemotePool(releaseOrMintIn.remoteChainSelector);
+ if (
+ configuredRemotePool.length == 0
+ || keccak256(releaseOrMintIn.sourcePoolAddress) != keccak256(configuredRemotePool)
+ ) {
+ revert InvalidSourcePoolAddress(releaseOrMintIn.sourcePoolAddress);
+ }
+ _consumeInboundRateLimit(releaseOrMintIn.remoteChainSelector, releaseOrMintIn.amount);
+ }
+
+ // ================================================================
+ // │ Chain permissions │
+ // ================================================================
+
+ /// @notice Gets the pool address on the remote chain.
+ /// @param remoteChainSelector Remote chain selector.
+ /// @dev To support non-evm chains, this value is encoded into bytes
+ function getRemotePool(uint64 remoteChainSelector) public view returns (bytes memory) {
+ return s_remoteChainConfigs[remoteChainSelector].remotePoolAddress;
+ }
+
+ /// @notice Gets the token address on the remote chain.
+ /// @param remoteChainSelector Remote chain selector.
+ /// @dev To support non-evm chains, this value is encoded into bytes
+ function getRemoteToken(uint64 remoteChainSelector) public view returns (bytes memory) {
+ return s_remoteChainConfigs[remoteChainSelector].remoteTokenAddress;
+ }
+
+ /// @notice Sets the remote pool address for a given chain selector.
+ /// @param remoteChainSelector The remote chain selector for which the remote pool address is being set.
+ /// @param remotePoolAddress The address of the remote pool.
+ function setRemotePool(uint64 remoteChainSelector, bytes calldata remotePoolAddress) external onlyOwner {
+ if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
+
+ bytes memory prevAddress = s_remoteChainConfigs[remoteChainSelector].remotePoolAddress;
+ s_remoteChainConfigs[remoteChainSelector].remotePoolAddress = remotePoolAddress;
+
+ emit RemotePoolSet(remoteChainSelector, prevAddress, remotePoolAddress);
+ }
+
+ /// @inheritdoc IPoolV1
+ function isSupportedChain(uint64 remoteChainSelector) public view returns (bool) {
+ return s_remoteChainSelectors.contains(remoteChainSelector);
+ }
+
+ /// @notice Get list of allowed chains
+ /// @return list of chains.
+ function getSupportedChains() public view returns (uint64[] memory) {
+ uint256[] memory uint256ChainSelectors = s_remoteChainSelectors.values();
+ uint64[] memory chainSelectors = new uint64[](uint256ChainSelectors.length);
+ for (uint256 i = 0; i < uint256ChainSelectors.length; ++i) {
+ chainSelectors[i] = uint64(uint256ChainSelectors[i]);
+ }
+
+ return chainSelectors;
+ }
+
+ /// @notice Sets the permissions for a list of chains selectors. Actual senders for these chains
+ /// need to be allowed on the Router to interact with this pool.
+ /// @dev Only callable by the owner
+ /// @param chains A list of chains and their new permission status & rate limits. Rate limits
+ /// are only used when the chain is being added through `allowed` being true.
+ function applyChainUpdates(ChainUpdate[] calldata chains) external virtual onlyOwner {
+ for (uint256 i = 0; i < chains.length; ++i) {
+ ChainUpdate memory update = chains[i];
+ RateLimiter._validateTokenBucketConfig(update.outboundRateLimiterConfig, !update.allowed);
+ RateLimiter._validateTokenBucketConfig(update.inboundRateLimiterConfig, !update.allowed);
+
+ if (update.allowed) {
+ // If the chain already exists, revert
+ if (!s_remoteChainSelectors.add(update.remoteChainSelector)) {
+ revert ChainAlreadyExists(update.remoteChainSelector);
+ }
+
+ if (update.remotePoolAddress.length == 0 || update.remoteTokenAddress.length == 0) {
+ revert ZeroAddressNotAllowed();
+ }
+
+ s_remoteChainConfigs[update.remoteChainSelector] = RemoteChainConfig({
+ outboundRateLimiterConfig: RateLimiter.TokenBucket({
+ rate: update.outboundRateLimiterConfig.rate,
+ capacity: update.outboundRateLimiterConfig.capacity,
+ tokens: update.outboundRateLimiterConfig.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: update.outboundRateLimiterConfig.isEnabled
+ }),
+ inboundRateLimiterConfig: RateLimiter.TokenBucket({
+ rate: update.inboundRateLimiterConfig.rate,
+ capacity: update.inboundRateLimiterConfig.capacity,
+ tokens: update.inboundRateLimiterConfig.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: update.inboundRateLimiterConfig.isEnabled
+ }),
+ remotePoolAddress: update.remotePoolAddress,
+ remoteTokenAddress: update.remoteTokenAddress
+ });
+
+ emit ChainAdded(
+ update.remoteChainSelector,
+ update.remoteTokenAddress,
+ update.outboundRateLimiterConfig,
+ update.inboundRateLimiterConfig
+ );
+ } else {
+ // If the chain doesn't exist, revert
+ if (!s_remoteChainSelectors.remove(update.remoteChainSelector)) {
+ revert NonExistentChain(update.remoteChainSelector);
+ }
+
+ delete s_remoteChainConfigs[update.remoteChainSelector];
+
+ emit ChainRemoved(update.remoteChainSelector);
+ }
+ }
+ }
+
+ // ================================================================
+ // │ Rate limiting │
+ // ================================================================
+
+ /// @notice Consumes outbound rate limiting capacity in this pool
+ function _consumeOutboundRateLimit(uint64 remoteChainSelector, uint256 amount) internal {
+ s_remoteChainConfigs[remoteChainSelector].outboundRateLimiterConfig._consume(amount, address(i_token));
+ }
+
+ /// @notice Consumes inbound rate limiting capacity in this pool
+ function _consumeInboundRateLimit(uint64 remoteChainSelector, uint256 amount) internal {
+ s_remoteChainConfigs[remoteChainSelector].inboundRateLimiterConfig._consume(amount, address(i_token));
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function getCurrentOutboundRateLimiterState(uint64 remoteChainSelector)
+ external
+ view
+ returns (RateLimiter.TokenBucket memory)
+ {
+ return s_remoteChainConfigs[remoteChainSelector].outboundRateLimiterConfig._currentTokenBucketState();
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function getCurrentInboundRateLimiterState(uint64 remoteChainSelector)
+ external
+ view
+ returns (RateLimiter.TokenBucket memory)
+ {
+ return s_remoteChainConfigs[remoteChainSelector].inboundRateLimiterConfig._currentTokenBucketState();
+ }
+
+ /// @notice Sets the chain rate limiter config.
+ /// @param remoteChainSelector The remote chain selector for which the rate limits apply.
+ /// @param outboundConfig The new outbound rate limiter config, meaning the onRamp rate limits for the given chain.
+ /// @param inboundConfig The new inbound rate limiter config, meaning the offRamp rate limits for the given chain.
+ function setChainRateLimiterConfig(
+ uint64 remoteChainSelector,
+ RateLimiter.Config memory outboundConfig,
+ RateLimiter.Config memory inboundConfig
+ ) external virtual onlyOwner {
+ _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig);
+ }
+
+ function _setRateLimitConfig(
+ uint64 remoteChainSelector,
+ RateLimiter.Config memory outboundConfig,
+ RateLimiter.Config memory inboundConfig
+ ) internal {
+ if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
+ RateLimiter._validateTokenBucketConfig(outboundConfig, false);
+ s_remoteChainConfigs[remoteChainSelector].outboundRateLimiterConfig._setTokenBucketConfig(outboundConfig);
+ RateLimiter._validateTokenBucketConfig(inboundConfig, false);
+ s_remoteChainConfigs[remoteChainSelector].inboundRateLimiterConfig._setTokenBucketConfig(inboundConfig);
+ emit ChainConfigured(remoteChainSelector, outboundConfig, inboundConfig);
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender
+ /// is a permissioned onRamp for the given chain on the Router.
+ function _onlyOnRamp(uint64 remoteChainSelector) internal view {
+ if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector);
+ if (!(msg.sender == s_router.getOnRamp(remoteChainSelector))) revert CallerIsNotARampOnRouter(msg.sender);
+ }
+
+ /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender
+ /// is a permissioned offRamp for the given chain on the Router.
+ function _onlyOffRamp(uint64 remoteChainSelector) internal view {
+ if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector);
+ if (!s_router.isOffRamp(remoteChainSelector, msg.sender)) revert CallerIsNotARampOnRouter(msg.sender);
+ }
+
+ // ================================================================
+ // │ Allowlist │
+ // ================================================================
+
+ function _checkAllowList(address sender) internal view {
+ if (i_allowlistEnabled) {
+ if (!s_allowList.contains(sender)) {
+ revert SenderNotAllowed(sender);
+ }
+ }
+ }
+
+ /// @notice Gets whether the allowList functionality is enabled.
+ /// @return true is enabled, false if not.
+ function getAllowListEnabled() external view returns (bool) {
+ return i_allowlistEnabled;
+ }
+
+ /// @notice Gets the allowed addresses.
+ /// @return The allowed addresses.
+ function getAllowList() external view returns (address[] memory) {
+ return s_allowList.values();
+ }
+
+ /// @notice Apply updates to the allow list.
+ /// @param removes The addresses to be removed.
+ /// @param adds The addresses to be added.
+ function applyAllowListUpdates(address[] calldata removes, address[] calldata adds) external onlyOwner {
+ _applyAllowListUpdates(removes, adds);
+ }
+
+ /// @notice Internal version of applyAllowListUpdates to allow for reuse in the constructor.
+ function _applyAllowListUpdates(address[] memory removes, address[] memory adds) internal {
+ if (!i_allowlistEnabled) revert AllowListNotEnabled();
+
+ for (uint256 i = 0; i < removes.length; ++i) {
+ address toRemove = removes[i];
+ if (s_allowList.remove(toRemove)) {
+ emit AllowListRemove(toRemove);
+ }
+ }
+ for (uint256 i = 0; i < adds.length; ++i) {
+ address toAdd = adds[i];
+ if (toAdd == address(0)) {
+ continue;
+ }
+ if (s_allowList.add(toAdd)) {
+ emit AllowListAdd(toAdd);
+ }
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/pools/USDC/IMessageTransmitter.sol b/contracts/src/v0.8/ccip/pools/USDC/IMessageTransmitter.sol
new file mode 100644
index 00000000000..1b2a0f90210
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/USDC/IMessageTransmitter.sol
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2022, Circle Internet Financial Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+pragma solidity ^0.8.0;
+
+interface IMessageTransmitter {
+ /// @notice Unlocks USDC tokens on the destination chain
+ /// @param message The original message on the source chain
+ /// * Message format:
+ /// * Field Bytes Type Index
+ /// * version 4 uint32 0
+ /// * sourceDomain 4 uint32 4
+ /// * destinationDomain 4 uint32 8
+ /// * nonce 8 uint64 12
+ /// * sender 32 bytes32 20
+ /// * recipient 32 bytes32 52
+ /// * destinationCaller 32 bytes32 84
+ /// * messageBody dynamic bytes 116
+ /// param attestation A valid attestation is the concatenated 65-byte signature(s) of
+ /// exactly `thresholdSignature` signatures, in increasing order of attester address.
+ /// ***If the attester addresses recovered from signatures are not in increasing order,
+ /// signature verification will fail.***
+ /// If incorrect number of signatures or duplicate signatures are supplied,
+ /// signature verification will fail.
+ function receiveMessage(bytes calldata message, bytes calldata attestation) external returns (bool success);
+
+ /// Returns domain of chain on which the contract is deployed.
+ /// @dev immutable
+ function localDomain() external view returns (uint32);
+
+ /// Returns message format version.
+ /// @dev immutable
+ function version() external view returns (uint32);
+}
diff --git a/contracts/src/v0.8/ccip/pools/USDC/ITokenMessenger.sol b/contracts/src/v0.8/ccip/pools/USDC/ITokenMessenger.sol
new file mode 100644
index 00000000000..ce5923cfdcd
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/USDC/ITokenMessenger.sol
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2022, Circle Internet Financial Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+pragma solidity ^0.8.0;
+
+interface ITokenMessenger {
+ /// @notice Emitted when a DepositForBurn message is sent
+ /// @param nonce Unique nonce reserved by message
+ /// @param burnToken Address of token burnt on source domain
+ /// @param amount Deposit amount
+ /// @param depositor Address where deposit is transferred from
+ /// @param mintRecipient Address receiving minted tokens on destination domain as bytes32
+ /// @param destinationDomain Destination domain
+ /// @param destinationTokenMessenger Address of TokenMessenger on destination domain as bytes32
+ /// @param destinationCaller Authorized caller as bytes32 of receiveMessage() on destination domain,
+ /// if not equal to bytes32(0). If equal to bytes32(0), any address can call receiveMessage().
+ event DepositForBurn(
+ uint64 indexed nonce,
+ address indexed burnToken,
+ uint256 amount,
+ address indexed depositor,
+ bytes32 mintRecipient,
+ uint32 destinationDomain,
+ bytes32 destinationTokenMessenger,
+ bytes32 destinationCaller
+ );
+
+ /// @notice Burns the tokens on the source side to produce a nonce through
+ /// Circles Cross Chain Transfer Protocol.
+ /// @param amount Amount of tokens to deposit and burn.
+ /// @param destinationDomain Destination domain identifier.
+ /// @param mintRecipient Address of mint recipient on destination domain.
+ /// @param burnToken Address of contract to burn deposited tokens, on local domain.
+ /// @param destinationCaller Caller on the destination domain, as bytes32.
+ /// @return nonce The unique nonce used in unlocking the funds on the destination chain.
+ /// @dev emits DepositForBurn
+ function depositForBurnWithCaller(
+ uint256 amount,
+ uint32 destinationDomain,
+ bytes32 mintRecipient,
+ address burnToken,
+ bytes32 destinationCaller
+ ) external returns (uint64 nonce);
+
+ /// Returns the version of the message body format.
+ /// @dev immutable
+ function messageBodyVersion() external view returns (uint32);
+
+ /// Returns local Message Transmitter responsible for sending and receiving messages
+ /// to/from remote domainsmessage transmitter for this token messenger.
+ /// @dev immutable
+ function localMessageTransmitter() external view returns (address);
+}
diff --git a/contracts/src/v0.8/ccip/pools/USDC/USDCTokenPool.sol b/contracts/src/v0.8/ccip/pools/USDC/USDCTokenPool.sol
new file mode 100644
index 00000000000..339ed09992f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/pools/USDC/USDCTokenPool.sol
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol";
+import {IMessageTransmitter} from "./IMessageTransmitter.sol";
+import {ITokenMessenger} from "./ITokenMessenger.sol";
+
+import {Pool} from "../../libraries/Pool.sol";
+import {TokenPool} from "../TokenPool.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 This pool mints and burns USDC tokens through the Cross Chain Transfer
+/// Protocol (CCTP).
+contract USDCTokenPool is TokenPool, ITypeAndVersion {
+ using SafeERC20 for IERC20;
+
+ event DomainsSet(DomainUpdate[]);
+ event ConfigSet(address tokenMessenger);
+
+ error UnknownDomain(uint64 domain);
+ error UnlockingUSDCFailed();
+ error InvalidConfig();
+ error InvalidDomain(DomainUpdate domain);
+ error InvalidMessageVersion(uint32 version);
+ error InvalidTokenMessengerVersion(uint32 version);
+ error InvalidNonce(uint64 expected, uint64 got);
+ error InvalidSourceDomain(uint32 expected, uint32 got);
+ error InvalidDestinationDomain(uint32 expected, uint32 got);
+ error InvalidReceiver(bytes receiver);
+
+ // This data is supplied from offchain and contains everything needed
+ // to receive the USDC tokens.
+ struct MessageAndAttestation {
+ bytes message;
+ bytes attestation;
+ }
+
+ // A domain is a USDC representation of a chain.
+ struct DomainUpdate {
+ bytes32 allowedCaller; // Address allowed to mint on the domain
+ uint32 domainIdentifier; // ──╮ Unique domain ID
+ uint64 destChainSelector; // │ The destination chain for this domain
+ bool enabled; // ─────────────╯ Whether the domain is enabled
+ }
+
+ struct SourceTokenDataPayload {
+ uint64 nonce;
+ uint32 sourceDomain;
+ }
+
+ string public constant override typeAndVersion = "USDCTokenPool 1.4.0";
+
+ // We restrict to the first version. New pool may be required for subsequent versions.
+ uint32 public constant SUPPORTED_USDC_VERSION = 0;
+
+ // The local USDC config
+ ITokenMessenger public immutable i_tokenMessenger;
+ IMessageTransmitter public immutable i_messageTransmitter;
+ uint32 public immutable i_localDomainIdentifier;
+
+ /// A domain is a USDC representation of a destination chain.
+ /// @dev Zero is a valid domain identifier.
+ /// @dev The address to mint on the destination chain is the corresponding USDC pool.
+ struct Domain {
+ bytes32 allowedCaller; // Address allowed to mint on the domain
+ uint32 domainIdentifier; // ─╮ Unique domain ID
+ bool enabled; // ────────────╯ Whether the domain is enabled
+ }
+
+ // A mapping of CCIP chain identifiers to destination domains
+ mapping(uint64 chainSelector => Domain CCTPDomain) private s_chainToDomain;
+
+ constructor(
+ ITokenMessenger tokenMessenger,
+ IERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) TokenPool(token, allowlist, rmnProxy, router) {
+ if (address(tokenMessenger) == address(0)) revert InvalidConfig();
+ IMessageTransmitter transmitter = IMessageTransmitter(tokenMessenger.localMessageTransmitter());
+ uint32 transmitterVersion = transmitter.version();
+ if (transmitterVersion != SUPPORTED_USDC_VERSION) revert InvalidMessageVersion(transmitterVersion);
+ uint32 tokenMessengerVersion = tokenMessenger.messageBodyVersion();
+ if (tokenMessengerVersion != SUPPORTED_USDC_VERSION) revert InvalidTokenMessengerVersion(tokenMessengerVersion);
+
+ i_tokenMessenger = tokenMessenger;
+ i_messageTransmitter = transmitter;
+ i_localDomainIdentifier = transmitter.localDomain();
+ i_token.safeIncreaseAllowance(address(i_tokenMessenger), type(uint256).max);
+ emit ConfigSet(address(tokenMessenger));
+ }
+
+ /// @notice Burn the token in the pool
+ /// @dev Burn is not rate limited at per-pool level. Burn does not contribute to honey pot risk.
+ /// Benefits of rate limiting here does not justify the extra gas cost.
+ /// @dev emits ITokenMessenger.DepositForBurn
+ /// @dev Assumes caller has validated destinationReceiver
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ virtual
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ _validateLockOrBurn(lockOrBurnIn);
+
+ Domain memory domain = s_chainToDomain[lockOrBurnIn.remoteChainSelector];
+ if (!domain.enabled) revert UnknownDomain(lockOrBurnIn.remoteChainSelector);
+ if (lockOrBurnIn.receiver.length != 32) {
+ revert InvalidReceiver(lockOrBurnIn.receiver);
+ }
+
+ // Since this pool is the msg sender of the CCTP transaction, only this contract
+ // is able to call replaceDepositForBurn. Since this contract does not implement
+ // replaceDepositForBurn, the tokens cannot be maliciously re-routed to another address.
+ uint64 nonce = i_tokenMessenger.depositForBurnWithCaller(
+ // We set the domain.allowedCaller as the receiver of the funds, as this is the token pool. Since 1.5 the
+ // token pools receiver the funds to hop them through the offRamps.
+ lockOrBurnIn.amount,
+ domain.domainIdentifier,
+ domain.allowedCaller,
+ address(i_token),
+ domain.allowedCaller
+ );
+
+ emit Burned(msg.sender, lockOrBurnIn.amount);
+
+ return Pool.LockOrBurnOutV1({
+ destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector),
+ destPoolData: abi.encode(SourceTokenDataPayload({nonce: nonce, sourceDomain: i_localDomainIdentifier}))
+ });
+ }
+
+ /// @notice Mint tokens from the pool to the recipient
+ /// * sourceTokenData is part of the verified message and passed directly from
+ /// the offramp so it is guaranteed to be what the lockOrBurn pool released on the
+ /// source chain. It contains (nonce, sourceDomain) which is guaranteed by CCTP
+ /// to be unique.
+ /// * offchainTokenData is untrusted (can be supplied by manual execution), but we assert
+ /// that (nonce, sourceDomain) is equal to the message's (nonce, sourceDomain) and
+ /// receiveMessage will assert that Attestation contains a valid attestation signature
+ /// for that message, including its (nonce, sourceDomain). This way, the only
+ /// non-reverting offchainTokenData that can be supplied is a valid attestation for the
+ /// specific message that was sent on source.
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ _validateReleaseOrMint(releaseOrMintIn);
+ SourceTokenDataPayload memory sourceTokenDataPayload =
+ abi.decode(releaseOrMintIn.sourcePoolData, (SourceTokenDataPayload));
+ MessageAndAttestation memory msgAndAttestation =
+ abi.decode(releaseOrMintIn.offchainTokenData, (MessageAndAttestation));
+
+ _validateMessage(msgAndAttestation.message, sourceTokenDataPayload);
+
+ if (!i_messageTransmitter.receiveMessage(msgAndAttestation.message, msgAndAttestation.attestation)) {
+ revert UnlockingUSDCFailed();
+ }
+ // Since the tokens are minted to the pool, the pool has to send it to the offRamp
+ getToken().safeTransfer(msg.sender, releaseOrMintIn.amount);
+
+ emit Minted(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount);
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+
+ /// @notice Validates the USDC encoded message against the given parameters.
+ /// @param usdcMessage The USDC encoded message
+ /// @param sourceTokenData The expected source chain token data to check against
+ /// @dev Only supports version SUPPORTED_USDC_VERSION of the CCTP message format
+ /// @dev Message format for USDC:
+ /// * Field Bytes Type Index
+ /// * version 4 uint32 0
+ /// * sourceDomain 4 uint32 4
+ /// * destinationDomain 4 uint32 8
+ /// * nonce 8 uint64 12
+ /// * sender 32 bytes32 20
+ /// * recipient 32 bytes32 52
+ /// * destinationCaller 32 bytes32 84
+ /// * messageBody dynamic bytes 116
+ function _validateMessage(bytes memory usdcMessage, SourceTokenDataPayload memory sourceTokenData) internal view {
+ uint32 version;
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ // We truncate using the datatype of the version variable, meaning
+ // we will only be left with the first 4 bytes of the message.
+ version := mload(add(usdcMessage, 4)) // 0 + 4 = 4
+ }
+ // This token pool only supports version 0 of the CCTP message format
+ // We check the version prior to loading the rest of the message
+ // to avoid unexpected reverts due to out-of-bounds reads.
+ if (version != SUPPORTED_USDC_VERSION) revert InvalidMessageVersion(version);
+
+ uint32 sourceDomain;
+ uint32 destinationDomain;
+ uint64 nonce;
+
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ sourceDomain := mload(add(usdcMessage, 8)) // 4 + 4 = 8
+ destinationDomain := mload(add(usdcMessage, 12)) // 8 + 4 = 12
+ nonce := mload(add(usdcMessage, 20)) // 12 + 8 = 20
+ }
+
+ if (sourceDomain != sourceTokenData.sourceDomain) {
+ revert InvalidSourceDomain(sourceTokenData.sourceDomain, sourceDomain);
+ }
+ if (destinationDomain != i_localDomainIdentifier) {
+ revert InvalidDestinationDomain(i_localDomainIdentifier, destinationDomain);
+ }
+ if (nonce != sourceTokenData.nonce) revert InvalidNonce(sourceTokenData.nonce, nonce);
+ }
+
+ // ================================================================
+ // │ Config │
+ // ================================================================
+
+ /// @notice Gets the CCTP domain for a given CCIP chain selector.
+ function getDomain(uint64 chainSelector) external view returns (Domain memory) {
+ return s_chainToDomain[chainSelector];
+ }
+
+ /// @notice Sets the CCTP domain for a CCIP chain selector.
+ /// @dev Must verify mapping of selectors -> (domain, caller) offchain.
+ function setDomains(DomainUpdate[] calldata domains) external onlyOwner {
+ for (uint256 i = 0; i < domains.length; ++i) {
+ DomainUpdate memory domain = domains[i];
+ if (domain.allowedCaller == bytes32(0) || domain.destChainSelector == 0) revert InvalidDomain(domain);
+
+ s_chainToDomain[domain.destChainSelector] = Domain({
+ domainIdentifier: domain.domainIdentifier,
+ allowedCaller: domain.allowedCaller,
+ enabled: domain.enabled
+ });
+ }
+ emit DomainsSet(domains);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/BaseTest.t.sol b/contracts/src/v0.8/ccip/test/BaseTest.t.sol
new file mode 100644
index 00000000000..ee3f3e6fd4c
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/BaseTest.t.sol
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+// Imports to any non-library are not allowed due to the significant cascading
+// compile time increase they cause when imported into this base test.
+import {Internal} from "../libraries/Internal.sol";
+import {RateLimiter} from "../libraries/RateLimiter.sol";
+import {MockRMN} from "./mocks/MockRMN.sol";
+import {Test} from "forge-std/Test.sol";
+
+contract BaseTest is Test {
+ // Addresses
+ address internal constant OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e;
+ address internal constant STRANGER = address(999999);
+ address internal constant DUMMY_CONTRACT_ADDRESS = 0x1111111111111111111111111111111111111112;
+ address internal constant ON_RAMP_ADDRESS = 0x11118e64e1FB0c487f25dD6D3601FF6aF8d32E4e;
+ address internal constant ZERO_ADDRESS = address(0);
+ address internal constant FEE_AGGREGATOR = 0xa33CDB32eAEce34F6affEfF4899cef45744EDea3;
+
+ address internal constant USER_1 = address(1);
+ address internal constant USER_2 = address(2);
+ address internal constant USER_3 = address(3);
+ address internal constant USER_4 = address(4);
+
+ // Message info
+ uint64 internal constant SOURCE_CHAIN_SELECTOR = 1;
+ uint64 internal constant DEST_CHAIN_SELECTOR = 2;
+ uint32 internal constant GAS_LIMIT = 200_000;
+
+ // Timing
+ uint256 internal constant BLOCK_TIME = 1234567890;
+ uint32 internal constant TWELVE_HOURS = 60 * 60 * 12;
+
+ // Onramp
+ uint96 internal constant MAX_NOP_FEES_JUELS = 1e27;
+ uint96 internal constant MAX_MSG_FEES_JUELS = 1e18;
+ uint32 internal constant DEST_GAS_OVERHEAD = 350_000;
+ uint16 internal constant DEST_GAS_PER_PAYLOAD_BYTE = 16;
+
+ uint16 internal constant DEFAULT_TOKEN_FEE_USD_CENTS = 50;
+ uint32 internal constant DEFAULT_TOKEN_DEST_GAS_OVERHEAD = 34_000;
+ uint32 internal constant DEFAULT_TOKEN_BYTES_OVERHEAD = 50;
+
+ bool private s_baseTestInitialized;
+
+ // Use 16 gas per data availability byte in our tests.
+ // This is an overestimation in OP stack, it ignores 4 gas per 0 byte rule.
+ // Arbitrum on the other hand, does always use 16 gas per data availability byte.
+ // This value may be substantially decreased after EIP 4844.
+ uint16 internal constant DEST_GAS_PER_DATA_AVAILABILITY_BYTE = 16;
+
+ // Total L1 data availability overhead estimate is 33_596 gas.
+ // This value includes complete CommitStore and OffRamp call data.
+ uint32 internal constant DEST_DATA_AVAILABILITY_OVERHEAD_GAS = 188 // Fixed data availability overhead in OP stack.
+ + (32 * 31 + 4) * DEST_GAS_PER_DATA_AVAILABILITY_BYTE // CommitStore single-root transmission takes up about 31 slots, plus selector.
+ + (32 * 34 + 4) * DEST_GAS_PER_DATA_AVAILABILITY_BYTE; // OffRamp transmission excluding EVM2EVMMessage takes up about 34 slots, plus selector.
+
+ // Multiples of bps, or 0.0001, use 6840 to be same as OP mainnet compression factor of 0.684.
+ uint16 internal constant DEST_GAS_DATA_AVAILABILITY_MULTIPLIER_BPS = 6840;
+
+ // OffRamp
+ uint32 internal constant MAX_DATA_SIZE = 30_000;
+ uint16 internal constant MAX_TOKENS_LENGTH = 5;
+ uint32 internal constant MAX_TOKEN_POOL_RELEASE_OR_MINT_GAS = 200_000;
+ uint32 internal constant MAX_TOKEN_POOL_TRANSFER_GAS = 50_000;
+ uint16 internal constant GAS_FOR_CALL_EXACT_CHECK = 5000;
+ uint32 internal constant PERMISSION_LESS_EXECUTION_THRESHOLD_SECONDS = 500;
+ uint32 internal constant MAX_GAS_LIMIT = 4_000_000;
+
+ // Rate limiter
+ address internal constant ADMIN = 0x11118e64e1FB0c487f25dD6D3601FF6aF8d32E4e;
+
+ MockRMN internal s_mockRMN;
+
+ 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 the sender to OWNER permanently
+ vm.startPrank(OWNER);
+ deal(OWNER, 1e20);
+ vm.label(OWNER, "Owner");
+ vm.label(STRANGER, "Stranger");
+
+ // Set the block time to a constant known value
+ vm.warp(BLOCK_TIME);
+
+ s_mockRMN = new MockRMN();
+ }
+
+ function getOutboundRateLimiterConfig() internal pure returns (RateLimiter.Config memory) {
+ return RateLimiter.Config({isEnabled: true, capacity: 100e28, rate: 1e15});
+ }
+
+ function getInboundRateLimiterConfig() internal pure returns (RateLimiter.Config memory) {
+ return RateLimiter.Config({isEnabled: true, capacity: 222e30, rate: 1e18});
+ }
+
+ function getSingleTokenPriceUpdateStruct(
+ address token,
+ uint224 price
+ ) internal pure returns (Internal.PriceUpdates memory) {
+ Internal.TokenPriceUpdate[] memory tokenPriceUpdates = new Internal.TokenPriceUpdate[](1);
+ tokenPriceUpdates[0] = Internal.TokenPriceUpdate({sourceToken: token, usdPerToken: price});
+
+ Internal.PriceUpdates memory priceUpdates =
+ Internal.PriceUpdates({tokenPriceUpdates: tokenPriceUpdates, gasPriceUpdates: new Internal.GasPriceUpdate[](0)});
+
+ return priceUpdates;
+ }
+
+ function getSingleGasPriceUpdateStruct(
+ uint64 chainSelector,
+ uint224 usdPerUnitGas
+ ) internal pure returns (Internal.PriceUpdates memory) {
+ Internal.GasPriceUpdate[] memory gasPriceUpdates = new Internal.GasPriceUpdate[](1);
+ gasPriceUpdates[0] = Internal.GasPriceUpdate({destChainSelector: chainSelector, usdPerUnitGas: usdPerUnitGas});
+
+ Internal.PriceUpdates memory priceUpdates =
+ Internal.PriceUpdates({tokenPriceUpdates: new Internal.TokenPriceUpdate[](0), gasPriceUpdates: gasPriceUpdates});
+
+ return priceUpdates;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/NonceManager.t.sol b/contracts/src/v0.8/ccip/test/NonceManager.t.sol
new file mode 100644
index 00000000000..75de4db8c5c
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/NonceManager.t.sol
@@ -0,0 +1,649 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {NonceManager} from "../NonceManager.sol";
+import {ICommitStore} from "../interfaces/ICommitStore.sol";
+import {Client} from "../libraries/Client.sol";
+import {Internal} from "../libraries/Internal.sol";
+import {Pool} from "../libraries/Pool.sol";
+import {RateLimiter} from "../libraries/RateLimiter.sol";
+import {EVM2EVMMultiOffRamp} from "../offRamp/EVM2EVMMultiOffRamp.sol";
+import {EVM2EVMMultiOnRamp} from "../onRamp/EVM2EVMMultiOnRamp.sol";
+import {EVM2EVMOnRamp} from "../onRamp/EVM2EVMOnRamp.sol";
+
+import {BaseTest} from "./BaseTest.t.sol";
+import {EVM2EVMMultiOnRampHelper} from "./helpers/EVM2EVMMultiOnRampHelper.sol";
+import {EVM2EVMOffRampHelper} from "./helpers/EVM2EVMOffRampHelper.sol";
+import {EVM2EVMOnRampHelper} from "./helpers/EVM2EVMOnRampHelper.sol";
+import {MockCommitStore} from "./mocks/MockCommitStore.sol";
+import {EVM2EVMMultiOffRampSetup} from "./offRamp/EVM2EVMMultiOffRampSetup.t.sol";
+import {EVM2EVMMultiOnRampSetup} from "./onRamp/EVM2EVMMultiOnRampSetup.t.sol";
+
+contract NonceManager_NonceIncrementation is BaseTest {
+ NonceManager private s_nonceManager;
+
+ function setUp() public override {
+ address[] memory authorizedCallers = new address[](1);
+ authorizedCallers[0] = address(this);
+ s_nonceManager = new NonceManager(authorizedCallers);
+ }
+
+ function test_getIncrementedOutboundNonce_Success() public {
+ address sender = address(this);
+
+ assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 0);
+
+ uint64 outboundNonce = s_nonceManager.getIncrementedOutboundNonce(DEST_CHAIN_SELECTOR, sender);
+ assertEq(outboundNonce, 1);
+ }
+
+ function test_incrementInboundNonce_Success() public {
+ address sender = address(this);
+
+ s_nonceManager.incrementInboundNonce(SOURCE_CHAIN_SELECTOR, 1, abi.encode(sender));
+
+ assertEq(s_nonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR, abi.encode(sender)), 1);
+ }
+
+ function test_incrementInboundNonce_Skip() public {
+ address sender = address(this);
+ uint64 expectedNonce = 2;
+
+ vm.expectEmit();
+ emit NonceManager.SkippedIncorrectNonce(SOURCE_CHAIN_SELECTOR, expectedNonce, abi.encode(sender));
+
+ s_nonceManager.incrementInboundNonce(SOURCE_CHAIN_SELECTOR, expectedNonce, abi.encode(sender));
+
+ assertEq(s_nonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR, abi.encode(sender)), 0);
+ }
+
+ function test_incrementNoncesInboundAndOutbound_Success() public {
+ address sender = address(this);
+
+ assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 0);
+ uint64 outboundNonce = s_nonceManager.getIncrementedOutboundNonce(DEST_CHAIN_SELECTOR, sender);
+ assertEq(outboundNonce, 1);
+
+ // Inbound nonce unchanged
+ assertEq(s_nonceManager.getInboundNonce(DEST_CHAIN_SELECTOR, abi.encode(sender)), 0);
+
+ s_nonceManager.incrementInboundNonce(DEST_CHAIN_SELECTOR, 1, abi.encode(sender));
+ assertEq(s_nonceManager.getInboundNonce(DEST_CHAIN_SELECTOR, abi.encode(sender)), 1);
+
+ // Outbound nonce unchanged
+ assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 1);
+ }
+}
+
+contract NonceManager_applyPreviousRampsUpdates is EVM2EVMMultiOnRampSetup {
+ function test_SingleRampUpdate() public {
+ address prevOnRamp = makeAddr("prevOnRamp");
+ address prevOffRamp = makeAddr("prevOffRamp");
+ NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1);
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(prevOnRamp, prevOffRamp));
+
+ vm.expectEmit();
+ emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR, previousRamps[0].prevRamps);
+
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+
+ _assertPreviousRampsEqual(s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR), previousRamps[0].prevRamps);
+ }
+
+ function test_MultipleRampsUpdates() public {
+ address prevOnRamp1 = makeAddr("prevOnRamp1");
+ address prevOnRamp2 = makeAddr("prevOnRamp2");
+ address prevOffRamp1 = makeAddr("prevOffRamp1");
+ address prevOffRamp2 = makeAddr("prevOffRamp2");
+ NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](2);
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(prevOnRamp1, prevOffRamp1));
+ previousRamps[1] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR + 1, NonceManager.PreviousRamps(prevOnRamp2, prevOffRamp2));
+
+ vm.expectEmit();
+ emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR, previousRamps[0].prevRamps);
+ vm.expectEmit();
+ emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR + 1, previousRamps[1].prevRamps);
+
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+
+ _assertPreviousRampsEqual(s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR), previousRamps[0].prevRamps);
+ _assertPreviousRampsEqual(
+ s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR + 1), previousRamps[1].prevRamps
+ );
+ }
+
+ function test_ZeroInput() public {
+ vm.recordLogs();
+ s_outboundNonceManager.applyPreviousRampsUpdates(new NonceManager.PreviousRampsArgs[](0));
+
+ assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ function test_PreviousRampAlreadySetOnRamp_Revert() public {
+ NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1);
+ address prevOnRamp = makeAddr("prevOnRamp");
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(prevOnRamp, address(0)));
+
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(prevOnRamp, address(0)));
+
+ vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector);
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+ }
+
+ function test_PreviousRampAlreadySetOffRamp_Revert() public {
+ NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1);
+ address prevOffRamp = makeAddr("prevOffRamp");
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(address(0), prevOffRamp));
+
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(address(0), prevOffRamp));
+
+ vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector);
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+ }
+
+ function test_PreviousRampAlreadySetOnRampAndOffRamp_Revert() public {
+ NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1);
+ address prevOnRamp = makeAddr("prevOnRamp");
+ address prevOffRamp = makeAddr("prevOffRamp");
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(prevOnRamp, prevOffRamp));
+
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(prevOnRamp, prevOffRamp));
+
+ vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector);
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+ }
+
+ function _assertPreviousRampsEqual(
+ NonceManager.PreviousRamps memory a,
+ NonceManager.PreviousRamps memory b
+ ) internal pure {
+ assertEq(a.prevOnRamp, b.prevOnRamp);
+ assertEq(a.prevOffRamp, b.prevOffRamp);
+ }
+}
+
+contract NonceManager_OnRampUpgrade is EVM2EVMMultiOnRampSetup {
+ uint256 internal constant FEE_AMOUNT = 1234567890;
+ EVM2EVMOnRampHelper internal s_prevOnRamp;
+
+ function setUp() public virtual override {
+ super.setUp();
+
+ EVM2EVMOnRamp.FeeTokenConfigArgs[] memory feeTokenConfigArgs = new EVM2EVMOnRamp.FeeTokenConfigArgs[](1);
+ feeTokenConfigArgs[0] = EVM2EVMOnRamp.FeeTokenConfigArgs({
+ token: s_sourceFeeToken,
+ networkFeeUSDCents: 1_00, // 1 USD
+ gasMultiplierWeiPerEth: 1e18, // 1x
+ premiumMultiplierWeiPerEth: 5e17, // 0.5x
+ enabled: true
+ });
+
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfig =
+ new EVM2EVMOnRamp.TokenTransferFeeConfigArgs[](1);
+
+ tokenTransferFeeConfig[0] = EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: s_sourceFeeToken,
+ minFeeUSDCents: 1_00, // 1 USD
+ maxFeeUSDCents: 1000_00, // 1,000 USD
+ deciBps: 2_5, // 2.5 bps, or 0.025%
+ destGasOverhead: 40_000,
+ destBytesOverhead: uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES),
+ aggregateRateLimitEnabled: true
+ });
+
+ s_prevOnRamp = new EVM2EVMOnRampHelper(
+ EVM2EVMOnRamp.StaticConfig({
+ linkToken: s_sourceTokens[0],
+ chainSelector: SOURCE_CHAIN_SELECTOR,
+ destChainSelector: DEST_CHAIN_SELECTOR,
+ defaultTxGasLimit: GAS_LIMIT,
+ maxNopFeesJuels: MAX_NOP_FEES_JUELS,
+ prevOnRamp: address(0),
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ EVM2EVMOnRamp.DynamicConfig({
+ router: address(s_sourceRouter),
+ maxNumberOfTokensPerMsg: MAX_TOKENS_LENGTH,
+ destGasOverhead: DEST_GAS_OVERHEAD,
+ destGasPerPayloadByte: DEST_GAS_PER_PAYLOAD_BYTE,
+ destDataAvailabilityOverheadGas: DEST_DATA_AVAILABILITY_OVERHEAD_GAS,
+ destGasPerDataAvailabilityByte: DEST_GAS_PER_DATA_AVAILABILITY_BYTE,
+ destDataAvailabilityMultiplierBps: DEST_GAS_DATA_AVAILABILITY_MULTIPLIER_BPS,
+ priceRegistry: address(s_priceRegistry),
+ maxDataBytes: MAX_DATA_SIZE,
+ maxPerMsgGasLimit: MAX_GAS_LIMIT,
+ defaultTokenFeeUSDCents: DEFAULT_TOKEN_FEE_USD_CENTS,
+ defaultTokenDestGasOverhead: DEFAULT_TOKEN_DEST_GAS_OVERHEAD,
+ defaultTokenDestBytesOverhead: DEFAULT_TOKEN_BYTES_OVERHEAD,
+ enforceOutOfOrder: false
+ }),
+ RateLimiter.Config({isEnabled: true, capacity: 100e28, rate: 1e15}),
+ feeTokenConfigArgs,
+ tokenTransferFeeConfig,
+ new EVM2EVMOnRamp.NopAndWeight[](0)
+ );
+
+ NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1);
+ previousRamps[0] =
+ NonceManager.PreviousRampsArgs(DEST_CHAIN_SELECTOR, NonceManager.PreviousRamps(address(s_prevOnRamp), address(0)));
+ s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+
+ (s_onRamp, s_metadataHash) = _deployOnRamp(
+ SOURCE_CHAIN_SELECTOR, address(s_sourceRouter), address(s_outboundNonceManager), address(s_tokenAdminRegistry)
+ );
+
+ vm.startPrank(address(s_sourceRouter));
+ }
+
+ function test_Upgrade_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, FEE_AMOUNT, OWNER));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+ }
+
+ function test_UpgradeSenderNoncesReadsPreviousRamp_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ uint64 startNonce = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER);
+
+ for (uint64 i = 1; i < 4; ++i) {
+ s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ assertEq(startNonce + i, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER));
+ }
+ }
+
+ function test_UpgradeNonceStartsAtV1Nonce_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint64 startNonce = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER);
+
+ // send 1 message from previous onramp
+ s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+
+ assertEq(startNonce + 1, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER));
+
+ // new onramp nonce should start from 2, while sequence number start from 1
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(
+ DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, startNonce + 2, FEE_AMOUNT, OWNER)
+ );
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+
+ assertEq(startNonce + 2, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER));
+
+ // after another send, nonce should be 3, and sequence number be 2
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(
+ DEST_CHAIN_SELECTOR, _messageToEvent(message, 2, startNonce + 3, FEE_AMOUNT, OWNER)
+ );
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+
+ assertEq(startNonce + 3, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER));
+ }
+
+ function test_UpgradeNonceNewSenderStartsAtZero_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ // send 1 message from previous onramp from OWNER
+ s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+
+ address newSender = address(1234567);
+ // new onramp nonce should start from 1 for new sender
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(
+ DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, FEE_AMOUNT, newSender)
+ );
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, newSender);
+ }
+}
+
+contract NonceManager_OffRampUpgrade is EVM2EVMMultiOffRampSetup {
+ EVM2EVMOffRampHelper internal s_prevOffRamp;
+ EVM2EVMOffRampHelper[] internal s_nestedPrevOffRamps;
+
+ address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_1 = abi.decode(ON_RAMP_ADDRESS_1, (address));
+ address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_2 = abi.decode(ON_RAMP_ADDRESS_2, (address));
+ address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_3 = abi.decode(ON_RAMP_ADDRESS_3, (address));
+
+ function setUp() public virtual override {
+ super.setUp();
+
+ ICommitStore mockPrevCommitStore = new MockCommitStore();
+ s_prevOffRamp = _deploySingleLaneOffRamp(
+ mockPrevCommitStore, s_destRouter, address(0), SOURCE_CHAIN_SELECTOR_1, SINGLE_LANE_ON_RAMP_ADDRESS_1
+ );
+
+ s_nestedPrevOffRamps = new EVM2EVMOffRampHelper[](2);
+ s_nestedPrevOffRamps[0] = _deploySingleLaneOffRamp(
+ mockPrevCommitStore, s_destRouter, address(0), SOURCE_CHAIN_SELECTOR_2, SINGLE_LANE_ON_RAMP_ADDRESS_2
+ );
+ s_nestedPrevOffRamps[1] = _deploySingleLaneOffRamp(
+ mockPrevCommitStore,
+ s_destRouter,
+ address(s_nestedPrevOffRamps[0]),
+ SOURCE_CHAIN_SELECTOR_2,
+ SINGLE_LANE_ON_RAMP_ADDRESS_2
+ );
+
+ NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](3);
+ previousRamps[0] = NonceManager.PreviousRampsArgs(
+ SOURCE_CHAIN_SELECTOR_1, NonceManager.PreviousRamps(address(0), address(s_prevOffRamp))
+ );
+ previousRamps[1] = NonceManager.PreviousRampsArgs(
+ SOURCE_CHAIN_SELECTOR_2, NonceManager.PreviousRamps(address(0), address(s_nestedPrevOffRamps[1]))
+ );
+ previousRamps[2] = NonceManager.PreviousRampsArgs(
+ SOURCE_CHAIN_SELECTOR_3, NonceManager.PreviousRamps(SINGLE_LANE_ON_RAMP_ADDRESS_3, address(0))
+ );
+ s_inboundNonceManager.applyPreviousRampsUpdates(previousRamps);
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](3);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ isEnabled: true,
+ onRamp: ON_RAMP_ADDRESS_1
+ });
+ sourceChainConfigs[1] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_2,
+ isEnabled: true,
+ onRamp: ON_RAMP_ADDRESS_2
+ });
+ sourceChainConfigs[2] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_3,
+ isEnabled: true,
+ onRamp: ON_RAMP_ADDRESS_3
+ });
+
+ _setupMultipleOffRampsFromConfigs(sourceChainConfigs);
+
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1);
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_3, 1);
+ }
+
+ function test_Upgraded_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ }
+
+ function test_NoPrevOffRampForChain_Success() public {
+ Internal.EVM2EVMMessage[] memory messages =
+ _generateSingleLaneSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, SINGLE_LANE_ON_RAMP_ADDRESS_1);
+ uint64 startNonceChain3 =
+ s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, abi.encode(messages[0].sender));
+ s_prevOffRamp.execute(_generateSingleLaneRampReportFromMessages(messages), new uint256[](0));
+
+ // Nonce unchanged for chain 3
+ assertEq(
+ startNonceChain3, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, abi.encode(messages[0].sender))
+ );
+
+ Internal.Any2EVMRampMessage[] memory messagesChain3 =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_3, ON_RAMP_ADDRESS_3);
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_3,
+ messagesChain3[0].header.sequenceNumber,
+ messagesChain3[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_3, messagesChain3), new uint256[](0)
+ );
+ assertEq(
+ startNonceChain3 + 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, messagesChain3[0].sender)
+ );
+ }
+
+ function test_UpgradedSenderNoncesReadsPreviousRamp_Success() public {
+ Internal.EVM2EVMMessage[] memory messages =
+ _generateSingleLaneSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, SINGLE_LANE_ON_RAMP_ADDRESS_1);
+ uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(messages[0].sender));
+
+ for (uint64 i = 1; i < 4; ++i) {
+ s_prevOffRamp.execute(_generateSingleLaneRampReportFromMessages(messages), new uint256[](0));
+
+ // messages contains a single message - update for the next execution
+ messages[0].nonce++;
+ messages[0].sequenceNumber++;
+ messages[0].messageId = Internal._hash(messages[0], s_prevOffRamp.metadataHash());
+
+ assertEq(
+ startNonce + i, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(messages[0].sender))
+ );
+ }
+ }
+
+ function test_UpgradedSenderNoncesReadsPreviousRampTransitive_Success() public {
+ Internal.EVM2EVMMessage[] memory messages =
+ _generateSingleLaneSingleBasicMessage(SOURCE_CHAIN_SELECTOR_2, SINGLE_LANE_ON_RAMP_ADDRESS_2);
+ uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_2, abi.encode(messages[0].sender));
+
+ for (uint64 i = 1; i < 4; ++i) {
+ s_nestedPrevOffRamps[0].execute(_generateSingleLaneRampReportFromMessages(messages), new uint256[](0));
+
+ // messages contains a single message - update for the next execution
+ messages[0].nonce++;
+ messages[0].sequenceNumber++;
+ messages[0].messageId = Internal._hash(messages[0], s_nestedPrevOffRamps[0].metadataHash());
+
+ // Read through prev sender nonce through prevOffRamp -> prevPrevOffRamp
+ assertEq(
+ startNonce + i, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_2, abi.encode(messages[0].sender))
+ );
+ }
+ }
+
+ function test_UpgradedNonceStartsAtV1Nonce_Success() public {
+ Internal.EVM2EVMMessage[] memory messages =
+ _generateSingleLaneSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, SINGLE_LANE_ON_RAMP_ADDRESS_1);
+
+ uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(messages[0].sender));
+ s_prevOffRamp.execute(_generateSingleLaneRampReportFromMessages(messages), new uint256[](0));
+
+ assertEq(
+ startNonce + 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(messages[0].sender))
+ );
+
+ Internal.Any2EVMRampMessage[] memory messagesMultiRamp =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ messagesMultiRamp[0].header.nonce++;
+ messagesMultiRamp[0].header.messageId = Internal._hash(messagesMultiRamp[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messagesMultiRamp[0].header.sequenceNumber,
+ messagesMultiRamp[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new uint256[](0)
+ );
+ assertEq(
+ startNonce + 2, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp[0].sender)
+ );
+
+ messagesMultiRamp[0].header.nonce++;
+ messagesMultiRamp[0].header.sequenceNumber++;
+ messagesMultiRamp[0].header.messageId = Internal._hash(messagesMultiRamp[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messagesMultiRamp[0].header.sequenceNumber,
+ messagesMultiRamp[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new uint256[](0)
+ );
+ assertEq(
+ startNonce + 3, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp[0].sender)
+ );
+ }
+
+ function test_UpgradedNonceNewSenderStartsAtZero_Success() public {
+ Internal.EVM2EVMMessage[] memory messages =
+ _generateSingleLaneSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, SINGLE_LANE_ON_RAMP_ADDRESS_1);
+
+ s_prevOffRamp.execute(_generateSingleLaneRampReportFromMessages(messages), new uint256[](0));
+
+ Internal.Any2EVMRampMessage[] memory messagesMultiRamp =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ bytes memory newSender = abi.encode(address(1234567));
+ messagesMultiRamp[0].sender = newSender;
+ messagesMultiRamp[0].header.messageId = Internal._hash(messagesMultiRamp[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messagesMultiRamp[0].header.sequenceNumber,
+ messagesMultiRamp[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ // new sender nonce in new offramp should go from 0 -> 1
+ assertEq(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, newSender), 0);
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new uint256[](0)
+ );
+ assertEq(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, newSender), 1);
+ }
+
+ function test_UpgradedOffRampNonceSkipsIfMsgInFlight_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ address newSender = address(1234567);
+ messages[0].sender = abi.encode(newSender);
+ messages[0].header.nonce = 2;
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender);
+
+ // new offramp sees msg nonce higher than senderNonce
+ // it waits for previous offramp to execute
+ vm.expectEmit();
+ emit NonceManager.SkippedIncorrectNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].header.nonce, messages[0].sender);
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ assertEq(startNonce, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender));
+
+ Internal.EVM2EVMMessage[] memory messagesSingleLane =
+ _generateSingleLaneSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, SINGLE_LANE_ON_RAMP_ADDRESS_1);
+
+ messagesSingleLane[0].nonce = 1;
+ messagesSingleLane[0].sender = newSender;
+ messagesSingleLane[0].messageId = Internal._hash(messagesSingleLane[0], s_prevOffRamp.metadataHash());
+
+ // previous offramp executes msg and increases nonce
+ s_prevOffRamp.execute(_generateSingleLaneRampReportFromMessages(messagesSingleLane), new uint256[](0));
+ assertEq(
+ startNonce + 1,
+ s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(messagesSingleLane[0].sender))
+ );
+
+ messages[0].header.nonce = 2;
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ // new offramp is able to execute
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ assertEq(startNonce + 2, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender));
+ }
+
+ function _generateSingleLaneRampReportFromMessages(Internal.EVM2EVMMessage[] memory messages)
+ internal
+ pure
+ returns (Internal.ExecutionReport memory)
+ {
+ bytes[][] memory offchainTokenData = new bytes[][](messages.length);
+
+ for (uint256 i = 0; i < messages.length; ++i) {
+ offchainTokenData[i] = new bytes[](messages[i].tokenAmounts.length);
+ }
+
+ return Internal.ExecutionReport({
+ proofs: new bytes32[](0),
+ proofFlagBits: 2 ** 256 - 1,
+ messages: messages,
+ offchainTokenData: offchainTokenData
+ });
+ }
+
+ function _generateSingleLaneSingleBasicMessage(
+ uint64 sourceChainSelector,
+ address onRamp
+ ) internal view returns (Internal.EVM2EVMMessage[] memory) {
+ Internal.EVM2EVMMessage[] memory messages = new Internal.EVM2EVMMessage[](1);
+
+ bytes memory data = abi.encode(0);
+ messages[0] = Internal.EVM2EVMMessage({
+ sequenceNumber: 1,
+ sender: OWNER,
+ nonce: 1,
+ gasLimit: GAS_LIMIT,
+ strict: false,
+ sourceChainSelector: sourceChainSelector,
+ receiver: address(s_receiver),
+ data: data,
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ sourceTokenData: new bytes[](0),
+ feeToken: s_destFeeToken,
+ feeTokenAmount: uint256(0),
+ messageId: ""
+ });
+
+ messages[0].messageId = Internal._hash(
+ messages[0],
+ keccak256(abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, sourceChainSelector, DEST_CHAIN_SELECTOR, onRamp))
+ );
+
+ return messages;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/README.md b/contracts/src/v0.8/ccip/test/README.md
new file mode 100644
index 00000000000..99223e1a63d
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/README.md
@@ -0,0 +1,89 @@
+# Foundry Test Guidelines
+
+We're using Foundry to test our CCIP smart contracts here. This enables us to test in Solidity. If you need to add tests for anything outside the CCIP contracts, please write them in hardhat (for the time being).
+
+## Directory Structure
+
+The test directory structure mimics the source contract file structure as closely as possible. Example:
+
+`./offRamp/SomeOffRamp.sol` should have a test contract `./test/offRamp/SomeOffRamp.t.sol`.
+
+## Test File Structure
+
+Break the test file down into multiple contracts, each contract testing a specific function inside the source contract.
+
+For Example, here's a source contract `SomeOffRamp`:
+
+```
+contract SomeOffRamp {
+
+ constructor() {
+ ... set some state
+ }
+
+ function firstFunction() public {
+ ...
+ }
+
+ function theNextFunction() public {
+ ...
+ }
+
+ function _anInternalFunction() internal {
+ ...
+ }
+}
+```
+
+Our test file `SomeOffRamp.t.sol` should be structured like this:
+
+```
+contract SomeOffRamp_constructor {
+ // constructor state setup tests here
+}
+
+contract SomeOffRamp_firstFunction {
+ // first function tests here
+}
+
+contract SomeOffRamp_theNextFunction {
+ // tests here too...
+}
+
+contract SomeOffRamp_anInternalFunction {
+ // This function will require a helper contract to expose it.
+}
+```
+
+## Test Structure
+
+Inside each test contract, group tests into `Success` and `Reverts` by starting with all the success cases and then adding a `// Reverts` comments to indicate the failure cases below.
+
+```
+contract SomeOffRamp_firstFunction {
+ function testZeroValueSuccess() public {
+ ...
+ }
+
+ ...
+
+
+ // Reverts
+
+ function testOwnerReverts() public {
+ // test that an ownable function reverts when not called by the owner
+ ...
+ }
+
+ ...
+
+}
+```
+
+Function naming should follow this structure, where the `_fuzz_` section denotes whether it's a fuzz test. Do not write tests that are named `testSuccess`, always include the description of the test, even if it's just the name of the function that is being called.
+
+`test{_fuzz_}{description of test}[Success|Reverts]`
+
+Try to cover all the code paths present in each function being tested. In most cases, this will result in many more failure tests than success tests.
+
+If a test file requires a complicated setUp, or if it requires many helper functions (like `_generateAMessageWithNoTokensStruct()`), create a separate file to perform this setup in. Using the example above, `SomeOffRampSetup.t.sol`. Inherit this and call the setUp function in the test file.
diff --git a/contracts/src/v0.8/ccip/test/TokenSetup.t.sol b/contracts/src/v0.8/ccip/test/TokenSetup.t.sol
new file mode 100644
index 00000000000..182d92c5c94
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/TokenSetup.t.sol
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPoolV1} from "../interfaces/IPool.sol";
+
+import {BurnMintERC677} from "../../shared/token/ERC677/BurnMintERC677.sol";
+import {Client} from "../libraries/Client.sol";
+import {BurnMintTokenPool} from "../pools/BurnMintTokenPool.sol";
+import {LockReleaseTokenPool} from "../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../pools/TokenPool.sol";
+import {TokenAdminRegistry} from "../tokenAdminRegistry/TokenAdminRegistry.sol";
+import {MaybeRevertingBurnMintTokenPool} from "./helpers/MaybeRevertingBurnMintTokenPool.sol";
+import {RouterSetup} from "./router/RouterSetup.t.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract TokenSetup is RouterSetup {
+ address[] internal s_sourceTokens;
+ address[] internal s_destTokens;
+
+ address internal s_sourceFeeToken;
+ address internal s_destFeeToken;
+
+ TokenAdminRegistry internal s_tokenAdminRegistry;
+
+ mapping(address sourceToken => address sourcePool) internal s_sourcePoolByToken;
+ mapping(address sourceToken => address destPool) internal s_destPoolBySourceToken;
+ mapping(address destToken => address destPool) internal s_destPoolByToken;
+ mapping(address sourceToken => address destToken) internal s_destTokenBySourceToken;
+
+ function _deploySourceToken(string memory tokenName, uint256 dealAmount, uint8 decimals) internal returns (address) {
+ BurnMintERC677 token = new BurnMintERC677(tokenName, tokenName, decimals, 0);
+ s_sourceTokens.push(address(token));
+ deal(address(token), OWNER, dealAmount);
+ return address(token);
+ }
+
+ function _deployDestToken(string memory tokenName, uint256 dealAmount) internal returns (address) {
+ BurnMintERC677 token = new BurnMintERC677(tokenName, tokenName, 18, 0);
+ s_destTokens.push(address(token));
+ deal(address(token), OWNER, dealAmount);
+ return address(token);
+ }
+
+ function _deployLockReleasePool(address token, bool isSourcePool) internal {
+ address router = address(s_sourceRouter);
+ if (!isSourcePool) {
+ router = address(s_destRouter);
+ }
+
+ LockReleaseTokenPool pool =
+ new LockReleaseTokenPool(IERC20(token), new address[](0), address(s_mockRMN), true, router);
+
+ if (isSourcePool) {
+ s_sourcePoolByToken[address(token)] = address(pool);
+ } else {
+ s_destPoolByToken[address(token)] = address(pool);
+ s_destPoolBySourceToken[s_sourceTokens[s_destTokens.length - 1]] = address(pool);
+ }
+ }
+
+ function _deployTokenAndBurnMintPool(address token, bool isSourcePool) internal {
+ address router = address(s_sourceRouter);
+ if (!isSourcePool) {
+ router = address(s_destRouter);
+ }
+
+ BurnMintTokenPool pool =
+ new MaybeRevertingBurnMintTokenPool(BurnMintERC677(token), new address[](0), address(s_mockRMN), router);
+ BurnMintERC677(token).grantMintAndBurnRoles(address(pool));
+
+ if (isSourcePool) {
+ s_sourcePoolByToken[address(token)] = address(pool);
+ } else {
+ s_destPoolByToken[address(token)] = address(pool);
+ s_destPoolBySourceToken[s_sourceTokens[s_destTokens.length - 1]] = address(pool);
+ }
+ }
+
+ function setUp() public virtual override {
+ RouterSetup.setUp();
+
+ bool isSetup = s_sourceTokens.length != 0;
+ if (isSetup) {
+ return;
+ }
+
+ // Source tokens & pools
+ address sourceLink = _deploySourceToken("sLINK", type(uint256).max, 18);
+ _deployLockReleasePool(sourceLink, true);
+ s_sourceFeeToken = sourceLink;
+
+ address sourceEth = _deploySourceToken("sETH", 2 ** 128, 18);
+ _deployTokenAndBurnMintPool(sourceEth, true);
+
+ // Destination tokens & pools
+ address destLink = _deployDestToken("dLINK", type(uint256).max);
+ _deployLockReleasePool(destLink, false);
+ s_destFeeToken = destLink;
+
+ s_destTokenBySourceToken[sourceLink] = destLink;
+
+ address destEth = _deployDestToken("dETH", 2 ** 128);
+ _deployTokenAndBurnMintPool(destEth, false);
+
+ s_destTokenBySourceToken[sourceEth] = destEth;
+
+ // Float the dest link lock release pool with funds
+ IERC20(destLink).transfer(s_destPoolByToken[destLink], 1000 ether);
+
+ s_tokenAdminRegistry = new TokenAdminRegistry();
+
+ // Set pools in the registry
+ for (uint256 i = 0; i < s_sourceTokens.length; ++i) {
+ address token = s_sourceTokens[i];
+ address pool = s_sourcePoolByToken[token];
+
+ _setPool(
+ s_tokenAdminRegistry, token, pool, DEST_CHAIN_SELECTOR, s_destPoolByToken[s_destTokens[i]], s_destTokens[i]
+ );
+ }
+
+ for (uint256 i = 0; i < s_destTokens.length; ++i) {
+ address token = s_destTokens[i];
+ address pool = s_destPoolByToken[token];
+ s_tokenAdminRegistry.proposeAdministrator(token, OWNER);
+ s_tokenAdminRegistry.acceptAdminRole(token);
+ s_tokenAdminRegistry.setPool(token, pool);
+
+ _setPool(
+ s_tokenAdminRegistry,
+ token,
+ pool,
+ SOURCE_CHAIN_SELECTOR,
+ s_sourcePoolByToken[s_sourceTokens[i]],
+ s_sourceTokens[i]
+ );
+ }
+ }
+
+ function getCastedSourceEVMTokenAmountsWithZeroAmounts()
+ internal
+ view
+ returns (Client.EVMTokenAmount[] memory tokenAmounts)
+ {
+ tokenAmounts = new Client.EVMTokenAmount[](s_sourceTokens.length);
+ for (uint256 i = 0; i < tokenAmounts.length; ++i) {
+ tokenAmounts[i].token = s_sourceTokens[i];
+ }
+ }
+
+ function _setPool(
+ TokenAdminRegistry tokenAdminRegistry,
+ address token,
+ address pool,
+ uint64 remoteChainSelector,
+ address remotePoolAddress,
+ address remoteToken
+ ) internal {
+ if (!tokenAdminRegistry.isAdministrator(token, OWNER)) {
+ tokenAdminRegistry.proposeAdministrator(token, OWNER);
+ tokenAdminRegistry.acceptAdminRole(token);
+ }
+
+ tokenAdminRegistry.setPool(token, pool);
+
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: remoteChainSelector,
+ remotePoolAddress: abi.encode(remotePoolAddress),
+ remoteTokenAddress: abi.encode(remoteToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+
+ TokenPool(pool).applyChainUpdates(chainUpdates);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/WETH9.sol b/contracts/src/v0.8/ccip/test/WETH9.sol
new file mode 100644
index 00000000000..fbc19ee2c4d
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/WETH9.sol
@@ -0,0 +1,82 @@
+// 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.24;
+
+// solhint-disable
+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);
+
+ 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 withdraw(uint256 wad) external {
+ require(balanceOf[msg.sender] >= wad);
+ 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) {
+ require(balanceOf[src] >= wad);
+
+ if (src != msg.sender && allowance[src][msg.sender] != type(uint128).max) {
+ require(allowance[src][msg.sender] >= wad);
+ 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/ccip/test/applications/DefensiveExample.t.sol b/contracts/src/v0.8/ccip/test/applications/DefensiveExample.t.sol
new file mode 100644
index 00000000000..18453f9f525
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/applications/DefensiveExample.t.sol
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {DefensiveExample} from "../../applications/DefensiveExample.sol";
+import {Client} from "../../libraries/Client.sol";
+import {EVM2EVMOnRampSetup} from "../onRamp/EVM2EVMOnRampSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract DefensiveExampleTest is EVM2EVMOnRampSetup {
+ event MessageFailed(bytes32 indexed messageId, bytes reason);
+ event MessageSucceeded(bytes32 indexed messageId);
+ event MessageRecovered(bytes32 indexed messageId);
+
+ DefensiveExample internal s_receiver;
+ uint64 internal sourceChainSelector = 7331;
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ s_receiver = new DefensiveExample(s_destRouter, IERC20(s_destFeeToken));
+ s_receiver.enableChain(sourceChainSelector, abi.encode(""));
+ }
+
+ function test_Recovery() public {
+ bytes32 messageId = keccak256("messageId");
+ address token = address(s_destFeeToken);
+ uint256 amount = 111333333777;
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](1);
+ destTokenAmounts[0] = Client.EVMTokenAmount({token: token, amount: amount});
+
+ // Make sure we give the receiver contract enough tokens like CCIP would.
+ deal(token, address(s_receiver), amount);
+
+ // Make sure the contract call reverts so we can test recovery.
+ s_receiver.setSimRevert(true);
+
+ // The receiver contract will revert if the router is not the sender.
+ vm.startPrank(address(s_destRouter));
+
+ vm.expectEmit();
+ emit MessageFailed(messageId, abi.encodeWithSelector(DefensiveExample.ErrorCase.selector));
+
+ s_receiver.ccipReceive(
+ Client.Any2EVMMessage({
+ messageId: messageId,
+ sourceChainSelector: sourceChainSelector,
+ sender: abi.encode(address(0)), // wrong sender, will revert internally
+ data: "",
+ destTokenAmounts: destTokenAmounts
+ })
+ );
+
+ address tokenReceiver = address(0x000001337);
+ uint256 tokenReceiverBalancePre = IERC20(token).balanceOf(tokenReceiver);
+ uint256 receiverBalancePre = IERC20(token).balanceOf(address(s_receiver));
+
+ // Recovery can only be done by the owner.
+ vm.startPrank(OWNER);
+
+ vm.expectEmit();
+ emit MessageRecovered(messageId);
+
+ s_receiver.retryFailedMessage(messageId, tokenReceiver);
+
+ // Assert the tokens have successfully been rescued from the contract.
+ assertEq(IERC20(token).balanceOf(tokenReceiver), tokenReceiverBalancePre + amount);
+ assertEq(IERC20(token).balanceOf(address(s_receiver)), receiverBalancePre - amount);
+ }
+
+ function test_HappyPath_Success() public {
+ bytes32 messageId = keccak256("messageId");
+ address token = address(s_destFeeToken);
+ uint256 amount = 111333333777;
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](1);
+ destTokenAmounts[0] = Client.EVMTokenAmount({token: token, amount: amount});
+
+ // Make sure we give the receiver contract enough tokens like CCIP would.
+ deal(token, address(s_receiver), amount);
+
+ // The receiver contract will revert if the router is not the sender.
+ vm.startPrank(address(s_destRouter));
+
+ vm.expectEmit();
+ emit MessageSucceeded(messageId);
+
+ s_receiver.ccipReceive(
+ Client.Any2EVMMessage({
+ messageId: messageId,
+ sourceChainSelector: sourceChainSelector,
+ sender: abi.encode(address(s_receiver)), // correct sender
+ data: "",
+ destTokenAmounts: destTokenAmounts
+ })
+ );
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver.t.sol b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver.t.sol
new file mode 100644
index 00000000000..cfd402d9106
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver.t.sol
@@ -0,0 +1,718 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Test} from "forge-std/Test.sol";
+
+import {CCIPRouter} from "../../applications/EtherSenderReceiver.sol";
+
+import {IRouterClient} from "../../interfaces/IRouterClient.sol";
+import {Client} from "../../libraries/Client.sol";
+import {WETH9} from "../WETH9.sol";
+import {EtherSenderReceiverHelper} from "./../helpers/EtherSenderReceiverHelper.sol";
+
+import {ERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol";
+
+contract EtherSenderReceiverTest is Test {
+ EtherSenderReceiverHelper internal s_etherSenderReceiver;
+ WETH9 internal s_weth;
+ WETH9 internal s_someOtherWeth;
+ ERC20 internal s_linkToken;
+
+ address internal constant OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e;
+ address internal constant ROUTER = 0x0F3779ee3a832D10158073ae2F5e61ac7FBBF880;
+ address internal constant XCHAIN_RECEIVER = 0xBd91b2073218AF872BF73b65e2e5950ea356d147;
+
+ function setUp() public {
+ vm.startPrank(OWNER);
+
+ s_linkToken = new ERC20("Chainlink Token", "LINK");
+ s_someOtherWeth = new WETH9();
+ s_weth = new WETH9();
+ vm.mockCall(ROUTER, abi.encodeWithSelector(CCIPRouter.getWrappedNative.selector), abi.encode(address(s_weth)));
+ s_etherSenderReceiver = new EtherSenderReceiverHelper(ROUTER);
+
+ deal(OWNER, 1_000_000 ether);
+ deal(address(s_linkToken), OWNER, 1_000_000 ether);
+
+ // deposit some eth into the weth contract.
+ s_weth.deposit{value: 10 ether}();
+ uint256 wethSupply = s_weth.totalSupply();
+ assertEq(wethSupply, 10 ether, "total weth supply must be 10 ether");
+ }
+}
+
+contract EtherSenderReceiverTest_constructor is EtherSenderReceiverTest {
+ function test_constructor() public view {
+ assertEq(s_etherSenderReceiver.getRouter(), ROUTER, "router must be set correctly");
+ uint256 allowance = s_weth.allowance(address(s_etherSenderReceiver), ROUTER);
+ assertEq(allowance, type(uint256).max, "allowance must be set infinite");
+ }
+}
+
+contract EtherSenderReceiverTest_validateFeeToken is EtherSenderReceiverTest {
+ uint256 internal constant amount = 100;
+
+ error InsufficientMsgValue(uint256 gotAmount, uint256 msgValue);
+ error TokenAmountNotEqualToMsgValue(uint256 gotAmount, uint256 msgValue);
+
+ function test_validateFeeToken_valid_native() public {
+ Client.EVMTokenAmount[] memory tokenAmount = new Client.EVMTokenAmount[](1);
+ tokenAmount[0] = Client.EVMTokenAmount({token: address(s_weth), amount: amount});
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmount,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ s_etherSenderReceiver.validateFeeToken{value: amount + 1}(message);
+ }
+
+ function test_validateFeeToken_valid_feeToken() public {
+ Client.EVMTokenAmount[] memory tokenAmount = new Client.EVMTokenAmount[](1);
+ tokenAmount[0] = Client.EVMTokenAmount({token: address(s_weth), amount: amount});
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmount,
+ feeToken: address(s_weth),
+ extraArgs: ""
+ });
+
+ s_etherSenderReceiver.validateFeeToken{value: amount}(message);
+ }
+
+ function test_validateFeeToken_reverts_feeToken_tokenAmountNotEqualToMsgValue() public {
+ Client.EVMTokenAmount[] memory tokenAmount = new Client.EVMTokenAmount[](1);
+ tokenAmount[0] = Client.EVMTokenAmount({token: address(s_weth), amount: amount});
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmount,
+ feeToken: address(s_weth),
+ extraArgs: ""
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(TokenAmountNotEqualToMsgValue.selector, amount, amount + 1));
+ s_etherSenderReceiver.validateFeeToken{value: amount + 1}(message);
+ }
+}
+
+contract EtherSenderReceiverTest_validatedMessage is EtherSenderReceiverTest {
+ error InvalidDestinationReceiver(bytes destReceiver);
+ error InvalidTokenAmounts(uint256 gotAmounts);
+ error InvalidWethAddress(address want, address got);
+ error GasLimitTooLow(uint256 minLimit, uint256 gotLimit);
+
+ uint256 internal constant amount = 100;
+
+ function test_Fuzz_validatedMessage_msgSenderOverwrite(bytes memory data) public view {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: data,
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+ assertEq(validatedMessage.receiver, abi.encode(XCHAIN_RECEIVER), "receiver must be XCHAIN_RECEIVER");
+ assertEq(validatedMessage.data, abi.encode(OWNER), "data must be msg.sender");
+ assertEq(validatedMessage.tokenAmounts[0].token, address(s_weth), "token must be weth");
+ assertEq(validatedMessage.tokenAmounts[0].amount, amount, "amount must be correct");
+ assertEq(validatedMessage.feeToken, address(0), "feeToken must be 0");
+ assertEq(validatedMessage.extraArgs, bytes(""), "extraArgs must be empty");
+ }
+
+ function test_Fuzz_validatedMessage_tokenAddressOverwrite(address token) public view {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: token, amount: amount});
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+ assertEq(validatedMessage.receiver, abi.encode(XCHAIN_RECEIVER), "receiver must be XCHAIN_RECEIVER");
+ assertEq(validatedMessage.data, abi.encode(OWNER), "data must be msg.sender");
+ assertEq(validatedMessage.tokenAmounts[0].token, address(s_weth), "token must be weth");
+ assertEq(validatedMessage.tokenAmounts[0].amount, amount, "amount must be correct");
+ assertEq(validatedMessage.feeToken, address(0), "feeToken must be 0");
+ assertEq(validatedMessage.extraArgs, bytes(""), "extraArgs must be empty");
+ }
+
+ function test_validatedMessage_emptyDataOverwrittenToMsgSender() public view {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+ assertEq(validatedMessage.receiver, abi.encode(XCHAIN_RECEIVER), "receiver must be XCHAIN_RECEIVER");
+ assertEq(validatedMessage.data, abi.encode(OWNER), "data must be msg.sender");
+ assertEq(validatedMessage.tokenAmounts[0].token, address(s_weth), "token must be weth");
+ assertEq(validatedMessage.tokenAmounts[0].amount, amount, "amount must be correct");
+ assertEq(validatedMessage.feeToken, address(0), "feeToken must be 0");
+ assertEq(validatedMessage.extraArgs, bytes(""), "extraArgs must be empty");
+ }
+
+ function test_validatedMessage_dataOverwrittenToMsgSender() public view {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: abi.encode(address(42)),
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+ assertEq(validatedMessage.receiver, abi.encode(XCHAIN_RECEIVER), "receiver must be XCHAIN_RECEIVER");
+ assertEq(validatedMessage.data, abi.encode(OWNER), "data must be msg.sender");
+ assertEq(validatedMessage.tokenAmounts[0].token, address(s_weth), "token must be weth");
+ assertEq(validatedMessage.tokenAmounts[0].amount, amount, "amount must be correct");
+ assertEq(validatedMessage.feeToken, address(0), "feeToken must be 0");
+ assertEq(validatedMessage.extraArgs, bytes(""), "extraArgs must be empty");
+ }
+
+ function test_validatedMessage_tokenOverwrittenToWeth() public view {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(42), // incorrect token.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+ assertEq(validatedMessage.receiver, abi.encode(XCHAIN_RECEIVER), "receiver must be XCHAIN_RECEIVER");
+ assertEq(validatedMessage.data, abi.encode(OWNER), "data must be msg.sender");
+ assertEq(validatedMessage.tokenAmounts[0].token, address(s_weth), "token must be weth");
+ assertEq(validatedMessage.tokenAmounts[0].amount, amount, "amount must be correct");
+ assertEq(validatedMessage.feeToken, address(0), "feeToken must be 0");
+ assertEq(validatedMessage.extraArgs, bytes(""), "extraArgs must be empty");
+ }
+
+ function test_validatedMessage_validMessage_extraArgs() public view {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 200_000}))
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+ assertEq(validatedMessage.receiver, abi.encode(XCHAIN_RECEIVER), "receiver must be XCHAIN_RECEIVER");
+ assertEq(validatedMessage.data, abi.encode(OWNER), "data must be msg.sender");
+ assertEq(validatedMessage.tokenAmounts[0].token, address(s_weth), "token must be weth");
+ assertEq(validatedMessage.tokenAmounts[0].amount, amount, "amount must be correct");
+ assertEq(validatedMessage.feeToken, address(0), "feeToken must be 0");
+ assertEq(
+ validatedMessage.extraArgs,
+ Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 200_000})),
+ "extraArgs must be correct"
+ );
+ }
+
+ function test_validatedMessage_invalidTokenAmounts() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: address(0), amount: amount});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: address(0), amount: amount});
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(InvalidTokenAmounts.selector, uint256(2)));
+ s_etherSenderReceiver.validatedMessage(message);
+ }
+}
+
+contract EtherSenderReceiverTest_getFee is EtherSenderReceiverTest {
+ uint64 internal constant destinationChainSelector = 424242;
+ uint256 internal constant feeWei = 121212;
+ uint256 internal constant amount = 100;
+
+ function test_getFee() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: address(0), amount: amount});
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeWei)
+ );
+
+ uint256 fee = s_etherSenderReceiver.getFee(destinationChainSelector, message);
+ assertEq(fee, feeWei, "fee must be feeWei");
+ }
+}
+
+contract EtherSenderReceiverTest_ccipReceive is EtherSenderReceiverTest {
+ uint256 internal constant amount = 100;
+ uint64 internal constant sourceChainSelector = 424242;
+ address internal constant XCHAIN_SENDER = 0x9951529C13B01E542f7eE3b6D6665D292e9BA2E0;
+
+ error InvalidTokenAmounts(uint256 gotAmounts);
+ error InvalidToken(address gotToken, address expectedToken);
+
+ function test_Fuzz_ccipReceive(uint256 tokenAmount) public {
+ // cap to 10 ether because OWNER only has 10 ether.
+ if (tokenAmount > 10 ether) {
+ return;
+ }
+
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](1);
+ destTokenAmounts[0] = Client.EVMTokenAmount({token: address(s_weth), amount: tokenAmount});
+ Client.Any2EVMMessage memory message = Client.Any2EVMMessage({
+ messageId: keccak256(abi.encode("ccip send")),
+ sourceChainSelector: sourceChainSelector,
+ sender: abi.encode(XCHAIN_SENDER),
+ data: abi.encode(OWNER),
+ destTokenAmounts: destTokenAmounts
+ });
+
+ // simulate a cross-chain token transfer, just transfer the weth to s_etherSenderReceiver.
+ s_weth.transfer(address(s_etherSenderReceiver), tokenAmount);
+
+ uint256 balanceBefore = OWNER.balance;
+ s_etherSenderReceiver.publicCcipReceive(message);
+ uint256 balanceAfter = OWNER.balance;
+ assertEq(balanceAfter, balanceBefore + tokenAmount, "balance must be correct");
+ }
+
+ function test_ccipReceive_happyPath() public {
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](1);
+ destTokenAmounts[0] = Client.EVMTokenAmount({token: address(s_weth), amount: amount});
+ Client.Any2EVMMessage memory message = Client.Any2EVMMessage({
+ messageId: keccak256(abi.encode("ccip send")),
+ sourceChainSelector: 424242,
+ sender: abi.encode(XCHAIN_SENDER),
+ data: abi.encode(OWNER),
+ destTokenAmounts: destTokenAmounts
+ });
+
+ // simulate a cross-chain token transfer, just transfer the weth to s_etherSenderReceiver.
+ s_weth.transfer(address(s_etherSenderReceiver), amount);
+
+ uint256 balanceBefore = OWNER.balance;
+ s_etherSenderReceiver.publicCcipReceive(message);
+ uint256 balanceAfter = OWNER.balance;
+ assertEq(balanceAfter, balanceBefore + amount, "balance must be correct");
+ }
+
+ function test_ccipReceive_fallbackToWethTransfer() public {
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](1);
+ destTokenAmounts[0] = Client.EVMTokenAmount({token: address(s_weth), amount: amount});
+ Client.Any2EVMMessage memory message = Client.Any2EVMMessage({
+ messageId: keccak256(abi.encode("ccip send")),
+ sourceChainSelector: 424242,
+ sender: abi.encode(XCHAIN_SENDER),
+ data: abi.encode(address(s_linkToken)), // ERC20 cannot receive() ether.
+ destTokenAmounts: destTokenAmounts
+ });
+
+ // simulate a cross-chain token transfer, just transfer the weth to s_etherSenderReceiver.
+ s_weth.transfer(address(s_etherSenderReceiver), amount);
+
+ uint256 balanceBefore = address(s_linkToken).balance;
+ s_etherSenderReceiver.publicCcipReceive(message);
+ uint256 balanceAfter = address(s_linkToken).balance;
+ assertEq(balanceAfter, balanceBefore, "balance must be unchanged");
+ uint256 wethBalance = s_weth.balanceOf(address(s_linkToken));
+ assertEq(wethBalance, amount, "weth balance must be correct");
+ }
+
+ function test_ccipReceive_wrongTokenAmount() public {
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](2);
+ destTokenAmounts[0] = Client.EVMTokenAmount({token: address(s_weth), amount: amount});
+ destTokenAmounts[1] = Client.EVMTokenAmount({token: address(s_weth), amount: amount});
+ Client.Any2EVMMessage memory message = Client.Any2EVMMessage({
+ messageId: keccak256(abi.encode("ccip send")),
+ sourceChainSelector: 424242,
+ sender: abi.encode(XCHAIN_SENDER),
+ data: abi.encode(OWNER),
+ destTokenAmounts: destTokenAmounts
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(InvalidTokenAmounts.selector, uint256(2)));
+ s_etherSenderReceiver.publicCcipReceive(message);
+ }
+
+ function test_ccipReceive_wrongToken() public {
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](1);
+ destTokenAmounts[0] = Client.EVMTokenAmount({token: address(s_someOtherWeth), amount: amount});
+ Client.Any2EVMMessage memory message = Client.Any2EVMMessage({
+ messageId: keccak256(abi.encode("ccip send")),
+ sourceChainSelector: 424242,
+ sender: abi.encode(XCHAIN_SENDER),
+ data: abi.encode(OWNER),
+ destTokenAmounts: destTokenAmounts
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(InvalidToken.selector, address(s_someOtherWeth), address(s_weth)));
+ s_etherSenderReceiver.publicCcipReceive(message);
+ }
+}
+
+contract EtherSenderReceiverTest_ccipSend is EtherSenderReceiverTest {
+ error InsufficientFee(uint256 gotFee, uint256 fee);
+
+ uint256 internal constant amount = 100;
+ uint64 internal constant destinationChainSelector = 424242;
+ uint256 internal constant feeWei = 121212;
+ uint256 internal constant feeJuels = 232323;
+
+ function test_Fuzz_ccipSend(uint256 feeFromRouter, uint256 feeSupplied) public {
+ // cap the fuzzer because OWNER only has a million ether.
+ vm.assume(feeSupplied < 1_000_000 ether - amount);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeFromRouter)
+ );
+
+ if (feeSupplied < feeFromRouter) {
+ vm.expectRevert();
+ s_etherSenderReceiver.ccipSend{value: amount + feeSupplied}(destinationChainSelector, message);
+ } else {
+ bytes32 expectedMsgId = keccak256(abi.encode("ccip send"));
+ vm.mockCall(
+ ROUTER,
+ feeSupplied,
+ abi.encodeWithSelector(IRouterClient.ccipSend.selector, destinationChainSelector, validatedMessage),
+ abi.encode(expectedMsgId)
+ );
+
+ bytes32 actualMsgId =
+ s_etherSenderReceiver.ccipSend{value: amount + feeSupplied}(destinationChainSelector, message);
+ assertEq(actualMsgId, expectedMsgId, "message id must be correct");
+ }
+ }
+
+ function test_Fuzz_ccipSend_feeToken(uint256 feeFromRouter, uint256 feeSupplied) public {
+ // cap the fuzzer because OWNER only has a million LINK.
+ vm.assume(feeSupplied < 1_000_000 ether - amount);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(s_linkToken),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeFromRouter)
+ );
+
+ s_linkToken.approve(address(s_etherSenderReceiver), feeSupplied);
+
+ if (feeSupplied < feeFromRouter) {
+ vm.expectRevert();
+ s_etherSenderReceiver.ccipSend{value: amount}(destinationChainSelector, message);
+ } else {
+ bytes32 expectedMsgId = keccak256(abi.encode("ccip send"));
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.ccipSend.selector, destinationChainSelector, validatedMessage),
+ abi.encode(expectedMsgId)
+ );
+
+ bytes32 actualMsgId = s_etherSenderReceiver.ccipSend{value: amount}(destinationChainSelector, message);
+ assertEq(actualMsgId, expectedMsgId, "message id must be correct");
+ }
+ }
+
+ function test_ccipSend_reverts_insufficientFee_weth() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(s_weth),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeWei)
+ );
+
+ s_weth.approve(address(s_etherSenderReceiver), feeWei - 1);
+
+ vm.expectRevert("SafeERC20: low-level call failed");
+ s_etherSenderReceiver.ccipSend{value: amount}(destinationChainSelector, message);
+ }
+
+ function test_ccipSend_reverts_insufficientFee_feeToken() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(s_linkToken),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeJuels)
+ );
+
+ s_linkToken.approve(address(s_etherSenderReceiver), feeJuels - 1);
+
+ vm.expectRevert("ERC20: insufficient allowance");
+ s_etherSenderReceiver.ccipSend{value: amount}(destinationChainSelector, message);
+ }
+
+ function test_ccipSend_reverts_insufficientFee_native() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeWei)
+ );
+
+ vm.expectRevert();
+ s_etherSenderReceiver.ccipSend{value: amount + feeWei - 1}(destinationChainSelector, message);
+ }
+
+ function test_ccipSend_success_nativeExcess() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ bytes32 expectedMsgId = keccak256(abi.encode("ccip send"));
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeWei)
+ );
+
+ // we assert that the correct value is sent to the router call, which should be
+ // the msg.value - feeWei.
+ vm.mockCall(
+ ROUTER,
+ feeWei + 1,
+ abi.encodeWithSelector(IRouterClient.ccipSend.selector, destinationChainSelector, validatedMessage),
+ abi.encode(expectedMsgId)
+ );
+
+ bytes32 actualMsgId = s_etherSenderReceiver.ccipSend{value: amount + feeWei + 1}(destinationChainSelector, message);
+ assertEq(actualMsgId, expectedMsgId, "message id must be correct");
+ }
+
+ function test_ccipSend_success_native() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(0),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ bytes32 expectedMsgId = keccak256(abi.encode("ccip send"));
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeWei)
+ );
+ vm.mockCall(
+ ROUTER,
+ feeWei,
+ abi.encodeWithSelector(IRouterClient.ccipSend.selector, destinationChainSelector, validatedMessage),
+ abi.encode(expectedMsgId)
+ );
+
+ bytes32 actualMsgId = s_etherSenderReceiver.ccipSend{value: amount + feeWei}(destinationChainSelector, message);
+ assertEq(actualMsgId, expectedMsgId, "message id must be correct");
+ }
+
+ function test_ccipSend_success_feeToken() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(s_linkToken),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ bytes32 expectedMsgId = keccak256(abi.encode("ccip send"));
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeJuels)
+ );
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.ccipSend.selector, destinationChainSelector, validatedMessage),
+ abi.encode(expectedMsgId)
+ );
+
+ s_linkToken.approve(address(s_etherSenderReceiver), feeJuels);
+
+ bytes32 actualMsgId = s_etherSenderReceiver.ccipSend{value: amount}(destinationChainSelector, message);
+ assertEq(actualMsgId, expectedMsgId, "message id must be correct");
+ uint256 routerAllowance = s_linkToken.allowance(address(s_etherSenderReceiver), ROUTER);
+ assertEq(routerAllowance, feeJuels, "router allowance must be feeJuels");
+ }
+
+ function test_ccipSend_success_weth() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({
+ token: address(0), // callers may not specify this.
+ amount: amount
+ });
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(XCHAIN_RECEIVER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: address(s_weth),
+ extraArgs: ""
+ });
+
+ Client.EVM2AnyMessage memory validatedMessage = s_etherSenderReceiver.validatedMessage(message);
+
+ bytes32 expectedMsgId = keccak256(abi.encode("ccip send"));
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.getFee.selector, destinationChainSelector, validatedMessage),
+ abi.encode(feeWei)
+ );
+ vm.mockCall(
+ ROUTER,
+ abi.encodeWithSelector(IRouterClient.ccipSend.selector, destinationChainSelector, validatedMessage),
+ abi.encode(expectedMsgId)
+ );
+
+ s_weth.approve(address(s_etherSenderReceiver), feeWei);
+
+ bytes32 actualMsgId = s_etherSenderReceiver.ccipSend{value: amount}(destinationChainSelector, message);
+ assertEq(actualMsgId, expectedMsgId, "message id must be correct");
+ uint256 routerAllowance = s_weth.allowance(address(s_etherSenderReceiver), ROUTER);
+ assertEq(routerAllowance, type(uint256).max, "router allowance must be max for weth");
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/applications/ImmutableExample.t.sol b/contracts/src/v0.8/ccip/test/applications/ImmutableExample.t.sol
new file mode 100644
index 00000000000..eb12e6205a4
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/applications/ImmutableExample.t.sol
@@ -0,0 +1,61 @@
+pragma solidity ^0.8.0;
+
+import {IAny2EVMMessageReceiver} from "../../interfaces/IAny2EVMMessageReceiver.sol";
+
+import {CCIPClientExample} from "../../applications/CCIPClientExample.sol";
+import {Client} from "../../libraries/Client.sol";
+import {EVM2EVMOnRampSetup} from "../onRamp/EVM2EVMOnRampSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {ERC165Checker} from
+ "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol";
+
+contract CCIPClientExample_sanity is EVM2EVMOnRampSetup {
+ function test_ImmutableExamples_Success() public {
+ CCIPClientExample exampleContract = new CCIPClientExample(s_sourceRouter, IERC20(s_sourceFeeToken));
+ deal(address(exampleContract), 100 ether);
+ deal(s_sourceFeeToken, address(exampleContract), 100 ether);
+
+ // feeToken approval works
+ assertEq(IERC20(s_sourceFeeToken).allowance(address(exampleContract), address(s_sourceRouter)), 2 ** 256 - 1);
+
+ // Can set chain
+ Client.EVMExtraArgsV1 memory extraArgs = Client.EVMExtraArgsV1({gasLimit: 300_000});
+ bytes memory encodedExtraArgs = Client._argsToBytes(extraArgs);
+ exampleContract.enableChain(DEST_CHAIN_SELECTOR, encodedExtraArgs);
+ assertEq(exampleContract.s_chains(DEST_CHAIN_SELECTOR), encodedExtraArgs);
+
+ address toAddress = makeAddr("toAddress");
+
+ // Can send data pay native
+ exampleContract.sendDataPayNative(DEST_CHAIN_SELECTOR, abi.encode(toAddress), bytes("hello"));
+
+ // Can send data pay feeToken
+ exampleContract.sendDataPayFeeToken(DEST_CHAIN_SELECTOR, abi.encode(toAddress), bytes("hello"));
+
+ // Can send data tokens
+ address sourceToken = s_sourceTokens[1];
+ assertEq(
+ address(s_onRamp.getPoolBySourceToken(DEST_CHAIN_SELECTOR, IERC20(sourceToken))),
+ address(s_sourcePoolByToken[sourceToken])
+ );
+ deal(sourceToken, OWNER, 100 ether);
+ IERC20(sourceToken).approve(address(exampleContract), 1 ether);
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: sourceToken, amount: 1 ether});
+ exampleContract.sendDataAndTokens(DEST_CHAIN_SELECTOR, abi.encode(toAddress), bytes("hello"), tokenAmounts);
+ // Tokens transferred from owner to router then burned in pool.
+ assertEq(IERC20(sourceToken).balanceOf(OWNER), 99 ether);
+ assertEq(IERC20(sourceToken).balanceOf(address(s_sourceRouter)), 0);
+
+ // Can send just tokens
+ IERC20(sourceToken).approve(address(exampleContract), 1 ether);
+ exampleContract.sendTokens(DEST_CHAIN_SELECTOR, abi.encode(toAddress), tokenAmounts);
+
+ // Can receive
+ assertTrue(ERC165Checker.supportsInterface(address(exampleContract), type(IAny2EVMMessageReceiver).interfaceId));
+
+ // Can disable chain
+ exampleContract.disableChain(DEST_CHAIN_SELECTOR);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/applications/PingPongDemo.t.sol b/contracts/src/v0.8/ccip/test/applications/PingPongDemo.t.sol
new file mode 100644
index 00000000000..3297e1f4fbc
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/applications/PingPongDemo.t.sol
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {PingPongDemo} from "../../applications/PingPongDemo.sol";
+import {Client} from "../../libraries/Client.sol";
+import "../onRamp/EVM2EVMOnRampSetup.t.sol";
+
+// setup
+contract PingPongDappSetup is EVM2EVMOnRampSetup {
+ PingPongDemo internal s_pingPong;
+ IERC20 internal s_feeToken;
+
+ address internal immutable i_pongContract = makeAddr("ping_pong_counterpart");
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ s_feeToken = IERC20(s_sourceTokens[0]);
+ s_pingPong = new PingPongDemo(address(s_sourceRouter), s_feeToken);
+ s_pingPong.setCounterpart(DEST_CHAIN_SELECTOR, i_pongContract);
+
+ uint256 fundingAmount = 1e18;
+
+ // Fund the contract with LINK tokens
+ s_feeToken.transfer(address(s_pingPong), fundingAmount);
+ }
+}
+
+contract PingPong_startPingPong is PingPongDappSetup {
+ function test_StartPingPong_Success() public {
+ uint256 pingPongNumber = 1;
+ bytes memory data = abi.encode(pingPongNumber);
+
+ Client.EVM2AnyMessage memory sentMessage = Client.EVM2AnyMessage({
+ receiver: abi.encode(i_pongContract),
+ data: data,
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 2e5}))
+ });
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, sentMessage);
+
+ Internal.EVM2EVMMessage memory message = Internal.EVM2EVMMessage({
+ sequenceNumber: 1,
+ feeTokenAmount: expectedFee,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ sender: address(s_pingPong),
+ receiver: i_pongContract,
+ nonce: 1,
+ data: data,
+ tokenAmounts: sentMessage.tokenAmounts,
+ sourceTokenData: new bytes[](sentMessage.tokenAmounts.length),
+ gasLimit: 2e5,
+ feeToken: sentMessage.feeToken,
+ strict: false,
+ messageId: ""
+ });
+ message.messageId = Internal._hash(message, s_metadataHash);
+
+ vm.expectEmit();
+ emit PingPongDemo.Ping(pingPongNumber);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(message);
+
+ s_pingPong.startPingPong();
+ }
+}
+
+contract PingPong_ccipReceive is PingPongDappSetup {
+ function test_CcipReceive_Success() public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](0);
+
+ uint256 pingPongNumber = 5;
+
+ Client.Any2EVMMessage memory message = Client.Any2EVMMessage({
+ messageId: bytes32("a"),
+ sourceChainSelector: DEST_CHAIN_SELECTOR,
+ sender: abi.encode(i_pongContract),
+ data: abi.encode(pingPongNumber),
+ destTokenAmounts: tokenAmounts
+ });
+
+ vm.startPrank(address(s_sourceRouter));
+
+ vm.expectEmit();
+ emit PingPongDemo.Pong(pingPongNumber + 1);
+
+ s_pingPong.ccipReceive(message);
+ }
+}
+
+contract PingPong_plumbing is PingPongDappSetup {
+ function test_Fuzz_CounterPartChainSelector_Success(uint64 chainSelector) public {
+ s_pingPong.setCounterpartChainSelector(chainSelector);
+
+ assertEq(s_pingPong.getCounterpartChainSelector(), chainSelector);
+ }
+
+ function test_Fuzz_CounterPartAddress_Success(address counterpartAddress) public {
+ s_pingPong.setCounterpartAddress(counterpartAddress);
+
+ assertEq(s_pingPong.getCounterpartAddress(), counterpartAddress);
+ }
+
+ function test_Fuzz_CounterPartAddress_Success(uint64 chainSelector, address counterpartAddress) public {
+ s_pingPong.setCounterpart(chainSelector, counterpartAddress);
+
+ assertEq(s_pingPong.getCounterpartAddress(), counterpartAddress);
+ assertEq(s_pingPong.getCounterpartChainSelector(), chainSelector);
+ }
+
+ function test_Pausing_Success() public {
+ assertFalse(s_pingPong.isPaused());
+
+ s_pingPong.setPaused(true);
+
+ assertTrue(s_pingPong.isPaused());
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/applications/SelfFundedPingPong.t.sol b/contracts/src/v0.8/ccip/test/applications/SelfFundedPingPong.t.sol
new file mode 100644
index 00000000000..d5db9d1f9d0
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/applications/SelfFundedPingPong.t.sol
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {SelfFundedPingPong} from "../../applications/SelfFundedPingPong.sol";
+import {Client} from "../../libraries/Client.sol";
+import {EVM2EVMOnRamp} from "../../onRamp/EVM2EVMOnRamp.sol";
+import {EVM2EVMOnRampSetup} from "../onRamp/EVM2EVMOnRampSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract SelfFundedPingPongDappSetup is EVM2EVMOnRampSetup {
+ SelfFundedPingPong internal s_pingPong;
+ IERC20 internal s_feeToken;
+ uint8 internal constant s_roundTripsBeforeFunding = 0;
+
+ address internal immutable i_pongContract = makeAddr("ping_pong_counterpart");
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ s_feeToken = IERC20(s_sourceTokens[0]);
+ s_pingPong = new SelfFundedPingPong(address(s_sourceRouter), s_feeToken, s_roundTripsBeforeFunding);
+ s_pingPong.setCounterpart(DEST_CHAIN_SELECTOR, i_pongContract);
+
+ uint256 fundingAmount = 5e18;
+
+ // set ping pong as an onRamp nop to make sure that funding runs
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = new EVM2EVMOnRamp.NopAndWeight[](1);
+ nopsAndWeights[0] = EVM2EVMOnRamp.NopAndWeight({nop: address(s_pingPong), weight: 1});
+ s_onRamp.setNops(nopsAndWeights);
+
+ // Fund the contract with LINK tokens
+ s_feeToken.transfer(address(s_pingPong), fundingAmount);
+ }
+}
+
+contract SelfFundedPingPong_ccipReceive is SelfFundedPingPongDappSetup {
+ function test_Funding_Success() public {
+ Client.Any2EVMMessage memory message = Client.Any2EVMMessage({
+ messageId: keccak256("msg id"),
+ sourceChainSelector: DEST_CHAIN_SELECTOR,
+ sender: abi.encode(i_pongContract),
+ data: "",
+ destTokenAmounts: new Client.EVMTokenAmount[](0)
+ });
+
+ uint8 countIncrBeforeFunding = 5;
+
+ vm.expectEmit();
+ emit SelfFundedPingPong.CountIncrBeforeFundingSet(countIncrBeforeFunding);
+
+ s_pingPong.setCountIncrBeforeFunding(countIncrBeforeFunding);
+
+ vm.startPrank(address(s_sourceRouter));
+ for (uint256 pingPongNumber = 0; pingPongNumber <= countIncrBeforeFunding; ++pingPongNumber) {
+ message.data = abi.encode(pingPongNumber);
+ if (pingPongNumber == countIncrBeforeFunding - 1) {
+ vm.expectEmit();
+ emit SelfFundedPingPong.Funded();
+ vm.expectCall(address(s_onRamp), "");
+ }
+ s_pingPong.ccipReceive(message);
+ }
+ }
+
+ function test_FundingIfNotANop_Revert() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = new EVM2EVMOnRamp.NopAndWeight[](0);
+ s_onRamp.setNops(nopsAndWeights);
+
+ uint8 countIncrBeforeFunding = 3;
+ s_pingPong.setCountIncrBeforeFunding(countIncrBeforeFunding);
+
+ vm.startPrank(address(s_sourceRouter));
+ Client.Any2EVMMessage memory message = Client.Any2EVMMessage({
+ messageId: bytes32("a"),
+ sourceChainSelector: DEST_CHAIN_SELECTOR,
+ sender: abi.encode(i_pongContract),
+ data: abi.encode(countIncrBeforeFunding),
+ destTokenAmounts: new Client.EVMTokenAmount[](0)
+ });
+
+ // because pingPong is not set as a nop
+ vm.expectRevert(EVM2EVMOnRamp.OnlyCallableByOwnerOrAdminOrNop.selector);
+ s_pingPong.ccipReceive(message);
+ }
+}
+
+contract SelfFundedPingPong_setCountIncrBeforeFunding is SelfFundedPingPongDappSetup {
+ function test_setCountIncrBeforeFunding() public {
+ uint8 c = s_pingPong.getCountIncrBeforeFunding();
+
+ vm.expectEmit();
+ emit SelfFundedPingPong.CountIncrBeforeFundingSet(c + 1);
+
+ s_pingPong.setCountIncrBeforeFunding(c + 1);
+ uint8 c2 = s_pingPong.getCountIncrBeforeFunding();
+ assertEq(c2, c + 1);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/applications/TokenProxy.t.sol b/contracts/src/v0.8/ccip/test/applications/TokenProxy.t.sol
new file mode 100644
index 00000000000..9e78f6e369f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/applications/TokenProxy.t.sol
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.24;
+
+import {TokenProxy} from "../../applications/TokenProxy.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {EVM2EVMOnRamp} from "../../onRamp/EVM2EVMOnRamp.sol";
+import {EVM2EVMOnRampSetup} from "../onRamp/EVM2EVMOnRampSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract TokenProxySetup is EVM2EVMOnRampSetup {
+ TokenProxy internal s_tokenProxy;
+ IERC20 internal s_feeToken;
+ IERC20 internal s_transferToken;
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ s_feeToken = IERC20(s_sourceTokens[0]);
+ s_transferToken = IERC20(s_sourceTokens[1]);
+ s_tokenProxy = new TokenProxy(address(s_sourceRouter), address(s_transferToken));
+
+ s_transferToken.approve(address(s_tokenProxy), type(uint256).max);
+ s_feeToken.approve(address(s_tokenProxy), type(uint256).max);
+ }
+}
+
+contract TokenProxy_constructor is TokenProxySetup {
+ function test_Constructor() public view {
+ assertEq(address(s_tokenProxy.getRouter()), address(s_sourceRouter));
+ assertEq(address(s_tokenProxy.getToken()), address(s_transferToken));
+ }
+}
+
+contract TokenProxy_getFee is TokenProxySetup {
+ function test_GetFee_Success() public view {
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_transferToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(s_tokenProxy),
+ data: "",
+ tokenAmounts: tokens,
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}))
+ });
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ uint256 actualFee = s_tokenProxy.getFee(DEST_CHAIN_SELECTOR, message);
+ assertEq(expectedFee, actualFee);
+ }
+
+ // Reverts
+
+ function test_GetFeeInvalidToken_Revert() public {
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(s_tokenProxy),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}))
+ });
+
+ vm.expectRevert(TokenProxy.InvalidToken.selector);
+
+ s_tokenProxy.getFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_GetFeeNoDataAllowed_Revert() public {
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_transferToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(s_tokenProxy),
+ data: "not empty",
+ tokenAmounts: tokens,
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}))
+ });
+
+ vm.expectRevert(TokenProxy.NoDataAllowed.selector);
+
+ s_tokenProxy.getFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_GetFeeGasShouldBeZero_Revert() public {
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_transferToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(s_tokenProxy),
+ data: "",
+ tokenAmounts: tokens,
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 10}))
+ });
+
+ vm.expectRevert(TokenProxy.GasShouldBeZero.selector);
+
+ s_tokenProxy.getFee(DEST_CHAIN_SELECTOR, message);
+ }
+}
+
+contract TokenProxy_ccipSend is TokenProxySetup {
+ function test_CcipSend_Success() public {
+ vm.pauseGasMetering();
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_transferToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = tokens;
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}));
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+
+ s_feeToken.approve(address(s_tokenProxy), expectedFee);
+
+ Internal.EVM2EVMMessage memory msgEvent = _messageToEvent(message, 1, 1, expectedFee, OWNER);
+ msgEvent.sender = address(s_tokenProxy);
+ msgEvent.messageId = Internal._hash(msgEvent, s_metadataHash);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent);
+
+ vm.resumeGasMetering();
+ s_tokenProxy.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_CcipSendNative_Success() public {
+ vm.pauseGasMetering();
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_transferToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = tokens;
+ message.feeToken = address(0);
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}));
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+
+ Internal.EVM2EVMMessage memory msgEvent = _messageToEvent(message, 1, 1, expectedFee, OWNER);
+ msgEvent.sender = address(s_tokenProxy);
+ msgEvent.feeToken = s_sourceRouter.getWrappedNative();
+ msgEvent.messageId = Internal._hash(msgEvent, s_metadataHash);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent);
+
+ vm.resumeGasMetering();
+ s_tokenProxy.ccipSend{value: expectedFee}(DEST_CHAIN_SELECTOR, message);
+ }
+
+ // Reverts
+
+ function test_CcipSendInsufficientAllowance_Revert() public {
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_transferToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = tokens;
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}));
+
+ // Revoke allowance
+ s_transferToken.approve(address(s_tokenProxy), 0);
+
+ vm.expectRevert("ERC20: insufficient allowance");
+
+ s_tokenProxy.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_CcipSendInvalidToken_Revert() public {
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_feeToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = tokens;
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}));
+
+ vm.expectRevert(TokenProxy.InvalidToken.selector);
+
+ s_tokenProxy.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_CcipSendNoDataAllowed_Revert() public {
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_transferToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = tokens;
+ message.data = "not empty";
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 0}));
+
+ vm.expectRevert(TokenProxy.NoDataAllowed.selector);
+
+ s_tokenProxy.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_CcipSendGasShouldBeZero_Revert() public {
+ Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1);
+ tokens[0] = Client.EVMTokenAmount({token: address(s_transferToken), amount: 1e18});
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = tokens;
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 1}));
+
+ vm.expectRevert(TokenProxy.GasShouldBeZero.selector);
+
+ s_tokenProxy.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/arm/ARMProxy.t.sol b/contracts/src/v0.8/ccip/test/arm/ARMProxy.t.sol
new file mode 100644
index 00000000000..24b617c82a0
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/arm/ARMProxy.t.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IRMN} from "../../interfaces/IRMN.sol";
+
+import {ARMProxy} from "../../ARMProxy.sol";
+import {RMN} from "../../RMN.sol";
+import {MockRMN} from "../mocks/MockRMN.sol";
+import {RMNSetup, makeSubjects} from "./RMNSetup.t.sol";
+
+contract ARMProxyTest is RMNSetup {
+ MockRMN internal s_mockRMN;
+ ARMProxy internal s_armProxy;
+
+ function setUp() public virtual override {
+ RMNSetup.setUp();
+ s_mockRMN = new MockRMN();
+ s_armProxy = new ARMProxy(address(s_rmn));
+ }
+
+ function test_ARMIsCursed_Success() public {
+ s_armProxy.setARM(address(s_mockRMN));
+ assertFalse(IRMN(address(s_armProxy)).isCursed());
+ s_mockRMN.setGlobalCursed(true);
+ assertTrue(IRMN(address(s_armProxy)).isCursed());
+ }
+
+ function test_ARMIsBlessed_Success() public {
+ s_armProxy.setARM(address(s_mockRMN));
+ s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)}), true);
+ assertTrue(IRMN(address(s_armProxy)).isBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)})));
+ s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)}), false);
+ assertFalse(IRMN(address(s_armProxy)).isBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)})));
+ }
+
+ function test_ARMCallRevertReasonForwarded() public {
+ bytes memory err = bytes("revert");
+ s_mockRMN.setIsCursedRevert(err);
+ s_armProxy.setARM(address(s_mockRMN));
+ vm.expectRevert(abi.encodeWithSelector(MockRMN.CustomError.selector, err));
+ IRMN(address(s_armProxy)).isCursed();
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/arm/ARMProxy_standalone.t.sol b/contracts/src/v0.8/ccip/test/arm/ARMProxy_standalone.t.sol
new file mode 100644
index 00000000000..4f3e96fafa2
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/arm/ARMProxy_standalone.t.sol
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ARMProxy} from "../../ARMProxy.sol";
+import {Test} from "forge-std/Test.sol";
+
+contract ARMProxyStandaloneTest is Test {
+ address internal constant EMPTY_ADDRESS = address(0x1);
+ address internal constant OWNER_ADDRESS = 0xC0ffeeEeC0fFeeeEc0ffeEeEc0ffEEEEC0FfEEee;
+ address internal constant MOCK_RMN_ADDRESS = 0x1337133713371337133713371337133713371337;
+
+ ARMProxy internal s_armProxy;
+
+ function setUp() public virtual {
+ // needed so that the extcodesize check in ARMProxy.fallback doesn't revert
+ vm.etch(MOCK_RMN_ADDRESS, bytes("fake bytecode"));
+
+ vm.prank(OWNER_ADDRESS);
+ s_armProxy = new ARMProxy(MOCK_RMN_ADDRESS);
+ }
+
+ function test_Constructor() public {
+ vm.expectEmit();
+ emit ARMProxy.ARMSet(MOCK_RMN_ADDRESS);
+ ARMProxy proxy = new ARMProxy(MOCK_RMN_ADDRESS);
+ assertEq(proxy.getARM(), MOCK_RMN_ADDRESS);
+ }
+
+ function test_SetARM() public {
+ vm.expectEmit();
+ emit ARMProxy.ARMSet(MOCK_RMN_ADDRESS);
+ vm.prank(OWNER_ADDRESS);
+ s_armProxy.setARM(MOCK_RMN_ADDRESS);
+ assertEq(s_armProxy.getARM(), MOCK_RMN_ADDRESS);
+ }
+
+ function test_SetARMzero() public {
+ vm.expectRevert(abi.encodeWithSelector(ARMProxy.ZeroAddressNotAllowed.selector));
+ vm.prank(OWNER_ADDRESS);
+ s_armProxy.setARM(address(0x0));
+ }
+
+ /*
+ function test_Fuzz_ARMCall(bool expectedSuccess, bytes memory call, bytes memory ret) public {
+ // filter out calls to functions that will be handled on the ARMProxy instead
+ // of the underlying ARM contract
+ vm.assume(
+ call.length < 4 ||
+ (bytes4(call) != s_armProxy.getARM.selector &&
+ bytes4(call) != s_armProxy.setARM.selector &&
+ bytes4(call) != s_armProxy.owner.selector &&
+ bytes4(call) != s_armProxy.acceptOwnership.selector &&
+ bytes4(call) != s_armProxy.transferOwnership.selector &&
+ bytes4(call) != s_armProxy.typeAndVersion.selector)
+ );
+
+ if (expectedSuccess) {
+ vm.mockCall(MOCK_RMN_ADDRESS, 0, call, ret);
+ } else {
+ vm.mockCallRevert(MOCK_RMN_ADDRESS, 0, call, ret);
+ }
+ (bool actualSuccess, bytes memory result) = address(s_armProxy).call(call);
+ vm.clearMockedCalls();
+
+ assertEq(result, ret);
+ assertEq(expectedSuccess, actualSuccess);
+ }
+ */
+
+ function test_ARMCallEmptyContractRevert() public {
+ vm.prank(OWNER_ADDRESS);
+ s_armProxy.setARM(EMPTY_ADDRESS); // No code at address 1, should revert.
+ vm.expectRevert();
+ bytes memory b = new bytes(0);
+ (bool success,) = address(s_armProxy).call(b);
+ success;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/arm/RMN.t.sol b/contracts/src/v0.8/ccip/test/arm/RMN.t.sol
new file mode 100644
index 00000000000..d3237592f29
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/arm/RMN.t.sol
@@ -0,0 +1,1068 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IRMN} from "../../interfaces/IRMN.sol";
+
+import {GLOBAL_CURSE_SUBJECT, LIFT_CURSE_VOTE_ADDR, OWNER_CURSE_VOTE_ADDR, RMN} from "../../RMN.sol";
+import {RMNSetup, makeCursesHash, makeSubjects} from "./RMNSetup.t.sol";
+
+import {Test} from "forge-std/Test.sol";
+
+bytes28 constant GARBAGE_CURSES_HASH = bytes28(keccak256("GARBAGE_CURSES_HASH"));
+
+contract ConfigCompare is Test {
+ function assertConfigEq(RMN.Config memory actualConfig, RMN.Config memory expectedConfig) public pure {
+ assertEq(actualConfig.voters.length, expectedConfig.voters.length);
+ for (uint256 i = 0; i < expectedConfig.voters.length; ++i) {
+ RMN.Voter memory expectedVoter = expectedConfig.voters[i];
+ RMN.Voter memory actualVoter = actualConfig.voters[i];
+ assertEq(actualVoter.blessVoteAddr, expectedVoter.blessVoteAddr);
+ assertEq(actualVoter.curseVoteAddr, expectedVoter.curseVoteAddr);
+ assertEq(actualVoter.blessWeight, expectedVoter.blessWeight);
+ assertEq(actualVoter.curseWeight, expectedVoter.curseWeight);
+ }
+ assertEq(actualConfig.blessWeightThreshold, expectedConfig.blessWeightThreshold);
+ assertEq(actualConfig.curseWeightThreshold, expectedConfig.curseWeightThreshold);
+ }
+}
+
+contract RMN_constructor is ConfigCompare, RMNSetup {
+ function test_Constructor_Success() public view {
+ RMN.Config memory expectedConfig = rmnConstructorArgs();
+ (uint32 actualVersion,, RMN.Config memory actualConfig) = s_rmn.getConfigDetails();
+ assertEq(actualVersion, 1);
+ assertConfigEq(actualConfig, expectedConfig);
+ }
+}
+
+contract RMN_voteToBless is RMNSetup {
+ function _getFirstBlessVoterAndWeight() internal pure returns (address, uint8) {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ return (cfg.voters[0].blessVoteAddr, cfg.voters[0].blessWeight);
+ }
+
+ // Success
+
+ function test_RootSuccess() public {
+ uint256 numRoots = 10;
+
+ (address voter, uint8 voterWeight) = _getFirstBlessVoterAndWeight();
+
+ for (uint256 i = 1; i <= numRoots; ++i) {
+ vm.expectEmit();
+ emit RMN.VotedToBless(1, voter, makeTaggedRoot(i), voterWeight);
+ }
+
+ vm.prank(voter);
+ s_rmn.voteToBless(makeTaggedRootsInclusive(1, numRoots));
+
+ for (uint256 i = 1; i <= numRoots; ++i) {
+ assertFalse(s_rmn.isBlessed(makeTaggedRoot(i)));
+ assertEq(voterWeight, getWeightOfVotesToBlessRoot(makeTaggedRoot(i)));
+ assertTrue(hasVotedToBlessRoot(voter, makeTaggedRoot(1)));
+ }
+ }
+
+ // Reverts
+
+ function test_SenderAlreadyVoted_Revert() public {
+ (address voter,) = _getFirstBlessVoterAndWeight();
+
+ vm.startPrank(voter);
+ s_rmn.voteToBless(makeTaggedRootSingleton(1));
+ assertTrue(hasVotedToBlessRoot(voter, makeTaggedRoot(1)));
+
+ uint256 votesToBlessBefore = getWeightOfVotesToBlessRoot(makeTaggedRoot(1));
+ vm.expectRevert(RMN.VoteToBlessNoop.selector);
+ s_rmn.voteToBless(makeTaggedRootSingleton(1));
+ assertEq(votesToBlessBefore, getWeightOfVotesToBlessRoot(makeTaggedRoot(1)));
+ }
+
+ function test_IsAlreadyBlessed_Revert() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+
+ // Bless voters 2,3,4 vote to bless
+ for (uint256 i = 1; i < cfg.voters.length; i++) {
+ vm.startPrank(cfg.voters[i].blessVoteAddr);
+ s_rmn.voteToBless(makeTaggedRootSingleton(1));
+ }
+
+ uint256 votesToBlessBefore = getWeightOfVotesToBlessRoot(makeTaggedRoot(1));
+ vm.startPrank(cfg.voters[0].blessVoteAddr);
+ vm.expectRevert(RMN.VoteToBlessNoop.selector);
+ s_rmn.voteToBless(makeTaggedRootSingleton(1));
+ assertEq(votesToBlessBefore, getWeightOfVotesToBlessRoot(makeTaggedRoot(1)));
+ }
+
+ function test_Curse_Revert() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+
+ for (uint256 i = 0; i < cfg.voters.length; i++) {
+ vm.startPrank(cfg.voters[i].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(i), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+
+ vm.startPrank(cfg.voters[0].blessVoteAddr);
+ vm.expectRevert(RMN.VoteToBlessForbiddenDuringActiveGlobalCurse.selector);
+ s_rmn.voteToBless(makeTaggedRootSingleton(12903));
+ }
+
+ function test_UnauthorizedVoter_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(abi.encodeWithSelector(RMN.UnauthorizedVoter.selector, STRANGER));
+ s_rmn.voteToBless(makeTaggedRootSingleton(12321));
+ }
+}
+
+contract RMN_ownerUnbless is RMNSetup {
+ function test_Unbless_Success() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ for (uint256 i = 0; i < cfg.voters.length; ++i) {
+ vm.startPrank(cfg.voters[i].blessVoteAddr);
+ s_rmn.voteToBless(makeTaggedRootSingleton(1));
+ }
+ assertTrue(s_rmn.isBlessed(makeTaggedRoot(1)));
+
+ vm.startPrank(OWNER);
+ s_rmn.ownerResetBlessVotes(makeTaggedRootSingleton(1));
+ assertFalse(s_rmn.isBlessed(makeTaggedRoot(1)));
+ }
+}
+
+contract RMN_unvoteToCurse is RMNSetup {
+ uint256 internal s_curser;
+ bytes28 internal s_cursesHash;
+
+ function setUp() public override {
+ RMNSetup.setUp();
+ RMN.Config memory cfg = rmnConstructorArgs();
+
+ s_curser = 0;
+ vm.startPrank(cfg.voters[s_curser].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+ bytes28 expectedCursesHash = makeCursesHash(makeCurseId(1));
+ assertFalse(s_rmn.isCursed());
+ (address[] memory cursers, bytes28[] memory cursesHashes, uint16 weight, bool cursed) = s_rmn.getCurseProgress(0);
+ assertEq(1, cursers.length);
+ assertEq(cfg.voters[s_curser].curseVoteAddr, cursers[0]);
+ assertEq(cfg.voters[s_curser].curseWeight, weight);
+ assertEq(1, cursesHashes.length);
+ assertEq(expectedCursesHash, cursesHashes[0]);
+ assertFalse(cursed);
+
+ s_cursesHash = expectedCursesHash;
+ }
+
+ function test_UnauthorizedVoter() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ // Someone else cannot unvote to curse on the curser's behalf.
+ address[] memory unauthorized = new address[](3);
+ unauthorized[0] = cfg.voters[s_curser].blessVoteAddr;
+ unauthorized[1] = cfg.voters[s_curser ^ 1].blessVoteAddr;
+ unauthorized[2] = OWNER;
+
+ for (uint256 i = 0; i < unauthorized.length; ++i) {
+ bytes memory expectedRevert = abi.encodeWithSelector(RMN.UnauthorizedVoter.selector, unauthorized[i]);
+ vm.startPrank(unauthorized[i]);
+ {
+ // should fail when using the correct curses hash
+ RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1);
+ reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: s_cursesHash});
+ vm.expectRevert(expectedRevert);
+ s_rmn.unvoteToCurse(reqs);
+ }
+ {
+ // should fail when using garbage curses hash
+ RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1);
+ reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: GARBAGE_CURSES_HASH});
+ vm.expectRevert(expectedRevert);
+ s_rmn.unvoteToCurse(reqs);
+ }
+ }
+ }
+
+ function test_InvalidCursesHash() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ vm.startPrank(cfg.voters[s_curser].curseVoteAddr);
+ RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1);
+ reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: GARBAGE_CURSES_HASH});
+ vm.expectRevert(RMN.UnvoteToCurseNoop.selector);
+ s_rmn.unvoteToCurse(reqs);
+ }
+
+ function test_ValidCursesHash() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ vm.startPrank(cfg.voters[s_curser].curseVoteAddr);
+ RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1);
+ reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: s_cursesHash});
+ s_rmn.unvoteToCurse(reqs); // succeeds
+ }
+
+ function test_OwnerSucceeds() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ vm.startPrank(OWNER);
+ RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](1);
+ reqs[0] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: cfg.voters[s_curser].curseVoteAddr,
+ unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: s_cursesHash}),
+ forceUnvote: false
+ });
+ s_rmn.ownerUnvoteToCurse(reqs);
+ }
+
+ function test_OwnerSkips() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ vm.startPrank(OWNER);
+ RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](1);
+ reqs[0] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: cfg.voters[s_curser].curseVoteAddr,
+ unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: GARBAGE_CURSES_HASH}),
+ forceUnvote: false
+ });
+
+ vm.expectEmit();
+ emit RMN.SkippedUnvoteToCurse(cfg.voters[s_curser].curseVoteAddr, 0, s_cursesHash, GARBAGE_CURSES_HASH);
+ vm.expectRevert(RMN.UnvoteToCurseNoop.selector);
+ s_rmn.ownerUnvoteToCurse(reqs);
+ }
+
+ function test_VotersCantLiftCurseButOwnerCan() public {
+ vm.stopPrank();
+ RMN.Config memory cfg = rmnConstructorArgs();
+ // s_curser has voted to curse during setUp
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(accWeight, cfg.voters[s_curser].curseWeight);
+ assertFalse(cursed);
+ assertEq(voters.length, 1);
+ assertEq(cursesHashes.length, 1);
+ assertEq(voters[0], cfg.voters[s_curser].curseVoteAddr);
+ assertEq(cursesHashes[0], makeCursesHash(makeCurseId(1)));
+ }
+ // everyone else votes now, same curse id, same subject
+ {
+ for (uint256 i = 0; i < cfg.voters.length; ++i) {
+ if (i == s_curser) continue; // already voted to curse
+ vm.prank(cfg.voters[i].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+ }
+ }
+ // subject must be cursed now
+ {
+ assertTrue(s_rmn.isCursed(0));
+ }
+ // curse progress should be as full as it can get
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ uint256 allWeights;
+ for (uint256 i = 0; i < cfg.voters.length; i++) {
+ allWeights += cfg.voters[i].curseWeight;
+ }
+ assertEq(accWeight, allWeights);
+ assertTrue(cursed);
+ assertEq(voters.length, cfg.voters.length);
+ assertEq(cursesHashes.length, cfg.voters.length);
+ for (uint256 i = 0; i < cfg.voters.length; ++i) {
+ assertEq(voters[i], cfg.voters[i].curseVoteAddr);
+ assertEq(cursesHashes[i], makeCursesHash(makeCurseId(1)));
+ }
+ }
+ // everyone unvotes to curse, successfully
+ {
+ for (uint256 i = 0; i < cfg.voters.length; ++i) {
+ vm.prank(cfg.voters[i].curseVoteAddr);
+ RMN.UnvoteToCurseRequest[] memory reqs = new RMN.UnvoteToCurseRequest[](1);
+ reqs[0] = RMN.UnvoteToCurseRequest({subject: 0, cursesHash: makeCursesHash(makeCurseId(1))});
+ s_rmn.unvoteToCurse(reqs);
+ }
+ }
+ // curse should still be in place as only the owner can lift it
+ {
+ assertTrue(s_rmn.isCursed(0));
+ }
+ // curse progress should be empty, expect for the cursed flag
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(accWeight, 0);
+ assertTrue(cursed);
+ assertEq(voters.length, 0);
+ assertEq(cursesHashes.length, 0);
+ }
+ // owner lifts curse
+ {
+ RMN.OwnerUnvoteToCurseRequest[] memory ownerReq = new RMN.OwnerUnvoteToCurseRequest[](1);
+ ownerReq[0] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: LIFT_CURSE_VOTE_ADDR,
+ unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: 0}),
+ forceUnvote: false
+ });
+ vm.prank(OWNER);
+ s_rmn.ownerUnvoteToCurse(ownerReq);
+ }
+ // curse should now be lifted
+ {
+ assertFalse(s_rmn.isCursed(0));
+ }
+ }
+}
+
+contract RMN_voteToCurse_2 is RMNSetup {
+ function initialConfig() internal pure returns (RMN.Config memory) {
+ RMN.Config memory cfg = RMN.Config({voters: new RMN.Voter[](3), blessWeightThreshold: 1, curseWeightThreshold: 3});
+ cfg.voters[0] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTER_1, curseVoteAddr: CURSE_VOTER_1, blessWeight: 1, curseWeight: 1});
+ cfg.voters[1] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTER_2, curseVoteAddr: CURSE_VOTER_2, blessWeight: 1, curseWeight: 1});
+ cfg.voters[2] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTER_3, curseVoteAddr: CURSE_VOTER_3, blessWeight: 1, curseWeight: 1});
+ return cfg;
+ }
+
+ function setUp() public override {
+ vm.prank(OWNER);
+ s_rmn = new RMN(initialConfig());
+ }
+
+ function test_VotesAreDroppedIfSubjectIsNotCursedDuringConfigChange() public {
+ // vote to curse the subject from an insufficient number of voters, one voter
+ {
+ RMN.Config memory cfg = initialConfig();
+ vm.prank(cfg.voters[0].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+ }
+ // vote must be in place
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(voters.length, 1);
+ assertEq(cursesHashes.length, 1);
+ assertEq(accWeight, 1);
+ assertFalse(cursed);
+ }
+ // change config to include only the first voter, i.e., initialConfig().voters[0]
+ {
+ RMN.Config memory cfg = initialConfig();
+ RMN.Voter[] memory voters = cfg.voters;
+ assembly {
+ mstore(voters, 1)
+ }
+ cfg.curseWeightThreshold = 1;
+ vm.prank(OWNER);
+ s_rmn.setConfig(cfg);
+ }
+ // vote must be dropped
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(voters.length, 0);
+ assertEq(cursesHashes.length, 0);
+ assertEq(accWeight, 0);
+ assertFalse(cursed);
+ }
+ // cause an owner curse now
+ {
+ vm.prank(OWNER);
+ s_rmn.ownerCurse(makeCurseId(1), makeSubjects(0));
+ }
+ // only the owner curse must be visible
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(voters.length, 1);
+ assertEq(voters[0], OWNER_CURSE_VOTE_ADDR);
+ assertEq(cursesHashes.length, 1);
+ assertEq(cursesHashes[0], makeCursesHash(makeCurseId(1)));
+ assertEq(accWeight, 0);
+ assertTrue(cursed);
+ }
+ }
+
+ function test_VotesAreRetainedIfSubjectIsCursedDuringConfigChange() public {
+ uint256 numVotersInitially = initialConfig().voters.length;
+ // curse the subject with votes from all voters
+ {
+ RMN.Config memory cfg = initialConfig();
+ for (uint256 i = 0; i < cfg.voters.length; ++i) {
+ vm.prank(cfg.voters[i].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+ }
+ }
+ // subject is now cursed
+ {
+ assertTrue(s_rmn.isCursed(0));
+ }
+ // throw in an owner curse
+ {
+ vm.prank(OWNER);
+ s_rmn.ownerCurse(makeCurseId(1), makeSubjects(0));
+ }
+
+ uint256 snapshot = vm.snapshot();
+
+ for (uint256 keepVoters = 1; keepVoters <= numVotersInitially; ++keepVoters) {
+ vm.revertTo(snapshot);
+
+ // change config to include only the first #keepVoters voters, i.e., initialConfig().voters[0..keepVoters]
+ {
+ RMN.Config memory cfg = initialConfig();
+ RMN.Voter[] memory voters = cfg.voters;
+ assembly {
+ mstore(voters, keepVoters)
+ }
+ cfg.curseWeightThreshold = uint16(keepVoters);
+ vm.prank(OWNER);
+ s_rmn.setConfig(cfg);
+ }
+ // subject is still cursed
+ {
+ assertTrue(s_rmn.isCursed(0));
+ }
+ // all votes from the first keepVoters & owner must be present
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint16 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(voters.length, keepVoters + 1 /* owner */ );
+ assertEq(cursesHashes.length, keepVoters + 1 /* owner */ );
+ assertEq(accWeight, keepVoters /* 1 per voter */ );
+ assertTrue(cursed);
+ for (uint256 i = 0; i < keepVoters; ++i) {
+ assertEq(voters[i], initialConfig().voters[i].curseVoteAddr);
+ assertEq(cursesHashes[i], makeCursesHash(makeCurseId(1)));
+ }
+ assertEq(voters[voters.length - 1], OWNER_CURSE_VOTE_ADDR);
+ assertEq(cursesHashes[cursesHashes.length - 1], makeCursesHash(makeCurseId(1)));
+ }
+ // the owner unvoting for all is not enough to lift the curse, because remember that the owner has an active vote
+ // also
+ {
+ for (uint256 i = 0; i < keepVoters; ++i) {
+ RMN.OwnerUnvoteToCurseRequest[] memory ownerReq = new RMN.OwnerUnvoteToCurseRequest[](1);
+ ownerReq[0] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: initialConfig().voters[i].curseVoteAddr,
+ unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: makeCursesHash(makeCurseId(1))}),
+ forceUnvote: false
+ });
+ vm.prank(OWNER);
+ s_rmn.ownerUnvoteToCurse(ownerReq);
+
+ assertTrue(s_rmn.isCursed(0));
+ }
+ }
+ // after owner unvotes for themselves, finally, the curse will be lifted
+ {
+ RMN.OwnerUnvoteToCurseRequest[] memory ownerReq = new RMN.OwnerUnvoteToCurseRequest[](1);
+ ownerReq[0] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: OWNER_CURSE_VOTE_ADDR,
+ unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: makeCursesHash(makeCurseId(1))}),
+ forceUnvote: false
+ });
+ vm.prank(OWNER);
+ s_rmn.ownerUnvoteToCurse(ownerReq);
+
+ assertFalse(s_rmn.isCursed(0));
+ }
+ }
+ }
+}
+
+contract RMN_voteToCurse is RMNSetup {
+ function _getFirstCurseVoterAndWeight() internal pure returns (address, uint8) {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ return (cfg.voters[0].curseVoteAddr, cfg.voters[0].curseWeight);
+ }
+
+ // Success
+
+ function test_CurseOnlyWhenThresholdReached_Success() public {
+ uint256 numSubjects = 3;
+ uint256 maxNumRevotes = 2;
+
+ RMN.Config memory cfg = rmnConstructorArgs();
+ bytes16[] memory subjects = new bytes16[](numSubjects);
+ for (uint256 i = 0; i < numSubjects; ++i) {
+ subjects[i] = bytes16(uint128(i));
+ }
+ for (uint256 numRevotes = 1; numRevotes <= maxNumRevotes; ++numRevotes) {
+ // all voters but the last vote, but can't surpass the curse weight threshold
+ for (uint256 i = 0; i < cfg.voters.length - 1; ++i) {
+ vm.prank(cfg.voters[i].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(numRevotes), subjects);
+ }
+ // no curse is yet active, last voter also needs to vote for any curse to be active
+ {
+ // ensure every subject is not cursed
+ for (uint256 i = 0; i < numSubjects; ++i) {
+ assertFalse(s_rmn.isCursed(subjects[i]));
+ }
+ // ensure every vote has been recorded
+ assertEq(
+ s_rmn.getRecordedCurseRelatedOpsCount(),
+ 1 /* setConfig */ + (cfg.voters.length - 1) * numRevotes * numSubjects
+ );
+ }
+ }
+
+ // last voter now votes
+ vm.prank(cfg.voters[cfg.voters.length - 1].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(0), subjects);
+ // curses should be now active
+ {
+ // ensure every subject is now cursed
+ for (uint256 i = 0; i < numSubjects; ++i) {
+ assertTrue(s_rmn.isCursed(subjects[i]));
+ }
+ // ensure every vote has been recorded
+ assertEq(
+ s_rmn.getRecordedCurseRelatedOpsCount(),
+ 1 /* setConfig */ + ((cfg.voters.length - 1) * maxNumRevotes + 1) * numSubjects
+ );
+ }
+ }
+
+ function test_VoteToCurse_NoCurse_Success() public {
+ (address voter, uint8 weight) = _getFirstCurseVoterAndWeight();
+ vm.startPrank(voter);
+ vm.expectEmit();
+ emit RMN.VotedToCurse(
+ 1, // configVersion
+ voter,
+ GLOBAL_CURSE_SUBJECT,
+ makeCurseId(123),
+ weight,
+ 1234567890, // blockTimestamp
+ makeCursesHash(makeCurseId(123)), // cursesHash
+ weight
+ );
+
+ s_rmn.voteToCurse(makeCurseId(123), makeSubjects(GLOBAL_CURSE_SUBJECT));
+
+ (address[] memory voters,, uint16 votes, bool cursed) = s_rmn.getCurseProgress(GLOBAL_CURSE_SUBJECT);
+ assertEq(1, voters.length);
+ assertEq(voter, voters[0]);
+ assertEq(weight, votes);
+ assertFalse(cursed);
+ }
+
+ function test_VoteToCurse_YesCurse_Success() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ for (uint256 i = 0; i < cfg.voters.length - 1; ++i) {
+ vm.startPrank(cfg.voters[i].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+ }
+
+ vm.expectEmit();
+ emit RMN.Cursed(1, 0, uint64(block.timestamp));
+
+ vm.startPrank(cfg.voters[cfg.voters.length - 1].curseVoteAddr);
+ vm.resumeGasMetering();
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+ }
+
+ function test_EvenIfAlreadyCursed_Success() public {
+ RMN.Config memory cfg = rmnConstructorArgs();
+ uint16 weightSum = 0;
+ for (uint256 i = 0; i < cfg.voters.length; ++i) {
+ vm.startPrank(cfg.voters[i].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(i), makeSubjects(0));
+ weightSum += cfg.voters[i].curseWeight;
+ }
+
+ // Not part of the assertion of this test but good to have as a sanity
+ // check. We want a curse to be active in order for the ultimate assertion
+ // to make sense.
+ assert(s_rmn.isCursed(0));
+
+ vm.expectEmit();
+ emit RMN.VotedToCurse(
+ 1, // configVersion
+ cfg.voters[cfg.voters.length - 1].curseVoteAddr,
+ 0, // subject
+ makeCurseId(cfg.voters.length + 1), // this curse id
+ cfg.voters[cfg.voters.length - 1].curseWeight,
+ uint64(block.timestamp), // blockTimestamp
+ makeCursesHash(makeCurseId(cfg.voters.length - 1), makeCurseId(cfg.voters.length + 1)), // cursesHash
+ weightSum // accumulatedWeight
+ );
+ // Asserts that this call to vote with a new curse id goes through with no
+ // reverts even when the RMN contract is cursed.
+ s_rmn.voteToCurse(makeCurseId(cfg.voters.length + 1), makeSubjects(0));
+ }
+
+ function test_OwnerCanCurseAndUncurse() public {
+ vm.startPrank(OWNER);
+ bytes28 expectedCursesHash = makeCursesHash(makeCurseId(0));
+ vm.expectEmit();
+ emit RMN.VotedToCurse(
+ 1, // configVersion
+ OWNER_CURSE_VOTE_ADDR, // owner
+ 0, // subject
+ makeCurseId(0), // curse id
+ 0, // weight
+ uint64(block.timestamp), // blockTimestamp
+ expectedCursesHash, // cursesHash
+ 0 // accumulatedWeight
+ );
+ vm.expectEmit();
+ emit RMN.Cursed(
+ 1, // configVersion
+ 0, // subject
+ uint64(block.timestamp) // blockTimestamp
+ );
+ s_rmn.ownerCurse(makeCurseId(0), makeSubjects(0));
+
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint24 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(voters.length, 1);
+ assertEq(voters[0], OWNER_CURSE_VOTE_ADDR /* owner */ );
+ assertEq(cursesHashes.length, 1);
+ assertEq(cursesHashes[0], expectedCursesHash);
+ assertEq(accWeight, 0);
+ assertTrue(cursed);
+ }
+
+ // ownerCurse again, should cause a vote to appear and a change in curses hash
+ expectedCursesHash = makeCursesHash(makeCurseId(0), makeCurseId(1));
+ vm.expectEmit();
+ emit RMN.VotedToCurse(
+ 1, // configVersion
+ OWNER_CURSE_VOTE_ADDR, // owner
+ 0, // subject
+ makeCurseId(1), // curse id
+ 0, // weight
+ uint64(block.timestamp), // blockTimestamp
+ expectedCursesHash, // cursesHash
+ 0 // accumulatedWeight
+ );
+ s_rmn.ownerCurse(makeCurseId(1), makeSubjects(0));
+
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint24 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(voters.length, 1);
+ assertEq(voters[0], OWNER_CURSE_VOTE_ADDR /* owner */ );
+ assertEq(cursesHashes.length, 1);
+ assertEq(cursesHashes[0], expectedCursesHash);
+ assertEq(accWeight, 0);
+ assertTrue(cursed);
+ }
+
+ RMN.OwnerUnvoteToCurseRequest[] memory unvoteReqs = new RMN.OwnerUnvoteToCurseRequest[](1);
+ unvoteReqs[0] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: OWNER_CURSE_VOTE_ADDR,
+ unit: RMN.UnvoteToCurseRequest({subject: 0, cursesHash: 0}),
+ forceUnvote: true // TODO: test with forceUnvote false also
+ });
+ vm.expectEmit();
+ emit RMN.CurseLifted(0);
+ s_rmn.ownerUnvoteToCurse(unvoteReqs);
+ {
+ (address[] memory voters, bytes28[] memory cursesHashes, uint24 accWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(voters.length, 0);
+ assertEq(cursesHashes.length, 0);
+ assertEq(accWeight, 0);
+ assertFalse(cursed);
+ }
+ }
+
+ // Reverts
+
+ function test_UnauthorizedVoter_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(abi.encodeWithSelector(RMN.UnauthorizedVoter.selector, STRANGER));
+ s_rmn.voteToCurse(makeCurseId(12312), makeSubjects(0));
+ }
+
+ function test_ReusedCurseId_Revert() public {
+ (address voter,) = _getFirstCurseVoterAndWeight();
+ vm.startPrank(voter);
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+
+ vm.expectRevert(abi.encodeWithSelector(RMN.ReusedCurseId.selector, voter, makeCurseId(1)));
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+ }
+
+ function test_RepeatedSubject_Revert() public {
+ (address voter,) = _getFirstCurseVoterAndWeight();
+ vm.prank(voter);
+
+ bytes16 subject = bytes16(uint128(1));
+
+ vm.expectRevert(RMN.SubjectsMustBeStrictlyIncreasing.selector);
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(subject, subject));
+ }
+
+ function test_EmptySubjects_Revert() public {
+ (address voter,) = _getFirstCurseVoterAndWeight();
+ vm.prank(voter);
+
+ vm.expectRevert(RMN.VoteToCurseNoop.selector);
+ s_rmn.voteToCurse(makeCurseId(1), new bytes16[](0));
+ }
+}
+
+contract RMN_ownerUnvoteToCurse is RMNSetup {
+ // These cursers are going to curse in setUp curseCount times.
+ function getCursersAndCurseCounts() internal pure returns (address[] memory cursers, uint32[] memory curseCounts) {
+ // NOTE: Change this when changing setUp or rmnConstructorArgs.
+ // This is a bit ugly and error prone but if we read from storage we would
+ // not get an accurate gas reading for ownerUnvoteToCurse when we need it.
+ cursers = new address[](4);
+ cursers[0] = CURSE_VOTER_1;
+ cursers[1] = CURSE_VOTER_2;
+ cursers[2] = CURSE_VOTER_3;
+ cursers[3] = CURSE_VOTER_4;
+ curseCounts = new uint32[](cursers.length);
+ for (uint256 i = 0; i < cursers.length; ++i) {
+ curseCounts[i] = 1;
+ }
+ }
+
+ function setUp() public virtual override {
+ RMNSetup.setUp();
+ (address[] memory cursers, uint32[] memory curseCounts) = getCursersAndCurseCounts();
+ for (uint256 i = 0; i < cursers.length; ++i) {
+ vm.startPrank(cursers[i]);
+ for (uint256 j = 0; j < curseCounts[i]; ++j) {
+ s_rmn.voteToCurse(makeCurseId(j), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+ }
+ }
+
+ function ownerUnvoteToCurse() internal {
+ s_rmn.ownerUnvoteToCurse(makeOwnerUnvoteToCurseRequests());
+ }
+
+ function makeOwnerUnvoteToCurseRequests() internal pure returns (RMN.OwnerUnvoteToCurseRequest[] memory) {
+ (address[] memory cursers,) = getCursersAndCurseCounts();
+ RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](cursers.length);
+ for (uint256 i = 0; i < cursers.length; ++i) {
+ reqs[i] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: cursers[i],
+ unit: RMN.UnvoteToCurseRequest({subject: GLOBAL_CURSE_SUBJECT, cursesHash: bytes28(0)}),
+ forceUnvote: true
+ });
+ }
+ return reqs;
+ }
+
+ // Success
+
+ function test_OwnerUnvoteToCurseSuccess_gas() public {
+ vm.pauseGasMetering();
+ vm.startPrank(OWNER);
+
+ vm.expectEmit();
+ emit RMN.CurseLifted(GLOBAL_CURSE_SUBJECT);
+
+ vm.resumeGasMetering();
+ ownerUnvoteToCurse();
+ vm.pauseGasMetering();
+
+ assertFalse(s_rmn.isCursed());
+ (address[] memory voters, bytes28[] memory cursesHashes, uint256 weight, bool cursed) =
+ s_rmn.getCurseProgress(GLOBAL_CURSE_SUBJECT);
+ assertEq(voters.length, 0);
+ assertEq(cursesHashes.length, 0);
+ assertEq(weight, 0);
+ assertFalse(cursed);
+ vm.resumeGasMetering();
+ }
+
+ function test_IsIdempotent() public {
+ vm.startPrank(OWNER);
+ ownerUnvoteToCurse();
+ vm.expectRevert(RMN.UnvoteToCurseNoop.selector);
+ ownerUnvoteToCurse();
+
+ assertFalse(s_rmn.isCursed());
+ (address[] memory voters, bytes28[] memory cursesHashes, uint256 weight, bool cursed) =
+ s_rmn.getCurseProgress(GLOBAL_CURSE_SUBJECT);
+ assertEq(voters.length, 0);
+ assertEq(cursesHashes.length, 0);
+ assertEq(weight, 0);
+ assertFalse(cursed);
+ }
+
+ function test_CanBlessAndCurseAfterGlobalCurseIsLifted() public {
+ // Contract is already cursed due to setUp.
+
+ // Owner unvotes to curse.
+ vm.startPrank(OWNER);
+ vm.expectEmit();
+ emit RMN.CurseLifted(GLOBAL_CURSE_SUBJECT);
+ ownerUnvoteToCurse();
+
+ // Contract is now uncursed.
+ assertFalse(s_rmn.isCursed());
+
+ // Vote to bless should go through.
+ vm.startPrank(BLESS_VOTER_1);
+ s_rmn.voteToBless(makeTaggedRootSingleton(2387489729));
+
+ // Vote to curse should go through.
+ vm.startPrank(CURSE_VOTER_1);
+ s_rmn.voteToCurse(makeCurseId(73894728973), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+
+ // Reverts
+
+ function test_NonOwner_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+ ownerUnvoteToCurse();
+ }
+
+ function test_UnknownVoter_Revert() public {
+ vm.stopPrank();
+ RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](1);
+ reqs[0] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: STRANGER,
+ unit: RMN.UnvoteToCurseRequest({subject: GLOBAL_CURSE_SUBJECT, cursesHash: bytes28(0)}),
+ forceUnvote: true
+ });
+
+ vm.prank(OWNER);
+ vm.expectEmit();
+ emit RMN.SkippedUnvoteToCurse(STRANGER, GLOBAL_CURSE_SUBJECT, bytes28(0), bytes28(0));
+ vm.expectRevert(RMN.UnvoteToCurseNoop.selector);
+ s_rmn.ownerUnvoteToCurse(reqs);
+
+ // no effect on cursedness
+ assertTrue(s_rmn.isCursed(GLOBAL_CURSE_SUBJECT));
+ }
+}
+
+contract RMN_setConfig is ConfigCompare, RMNSetup {
+ /// @notice Test-specific function to use only in setConfig tests
+ function getDifferentConfigArgs() private pure returns (RMN.Config memory) {
+ RMN.Voter[] memory voters = new RMN.Voter[](2);
+ voters[0] = RMN.Voter({
+ blessVoteAddr: BLESS_VOTER_1,
+ curseVoteAddr: CURSE_VOTER_1,
+ blessWeight: WEIGHT_1,
+ curseWeight: WEIGHT_1
+ });
+ voters[1] = RMN.Voter({
+ blessVoteAddr: BLESS_VOTER_2,
+ curseVoteAddr: CURSE_VOTER_2,
+ blessWeight: WEIGHT_10,
+ curseWeight: WEIGHT_10
+ });
+ return RMN.Config({
+ voters: voters,
+ blessWeightThreshold: WEIGHT_1 + WEIGHT_10,
+ curseWeightThreshold: WEIGHT_1 + WEIGHT_10
+ });
+ }
+
+ function setUp() public virtual override {
+ RMNSetup.setUp();
+ RMN.Config memory cfg = rmnConstructorArgs();
+
+ // Setup some partial state
+ vm.startPrank(cfg.voters[0].blessVoteAddr);
+ s_rmn.voteToBless(makeTaggedRootSingleton(1));
+ vm.startPrank(cfg.voters[1].blessVoteAddr);
+ s_rmn.voteToBless(makeTaggedRootSingleton(1));
+ vm.startPrank(cfg.voters[1].curseVoteAddr);
+ s_rmn.voteToCurse(makeCurseId(1), makeSubjects(0));
+ }
+
+ // Success
+
+ event ConfigSet(uint32 indexed configVersion, RMN.Config config);
+
+ function test_VoteToBlessByEjectedVoter_Revert() public {
+ // Previous config included BLESS_VOTER_4. Change to new config that doesn't.
+ RMN.Config memory cfg = getDifferentConfigArgs();
+ vm.startPrank(OWNER);
+ s_rmn.setConfig(cfg);
+
+ // BLESS_VOTER_4 is not part of cfg anymore, vote to bless should revert.
+ vm.startPrank(BLESS_VOTER_4);
+ vm.expectRevert(abi.encodeWithSelector(RMN.UnauthorizedVoter.selector, BLESS_VOTER_4));
+ s_rmn.voteToBless(makeTaggedRootSingleton(2));
+ }
+
+ function test_SetConfigSuccess_gas() public {
+ vm.pauseGasMetering();
+ RMN.Config memory cfg = getDifferentConfigArgs();
+
+ vm.startPrank(OWNER);
+ vm.expectEmit();
+ emit ConfigSet(2, cfg);
+
+ (uint32 configVersionBefore,,) = s_rmn.getConfigDetails();
+ vm.resumeGasMetering();
+ s_rmn.setConfig(cfg);
+ vm.pauseGasMetering();
+ // Assert VersionedConfig has changed correctly
+ (uint32 configVersionAfter,, RMN.Config memory configAfter) = s_rmn.getConfigDetails();
+ assertEq(configVersionBefore + 1, configVersionAfter);
+ assertConfigEq(configAfter, cfg);
+
+ // Assert that curse votes have been cleared
+
+ (address[] memory curseVoters, bytes28[] memory cursesHashes, uint256 curseWeight, bool cursed) =
+ s_rmn.getCurseProgress(0);
+ assertEq(0, curseVoters.length);
+ assertEq(0, cursesHashes.length);
+ assertEq(0, curseWeight);
+ assertFalse(cursed);
+
+ // Assert that good votes have been cleared
+ uint256 votesToBlessRoot = getWeightOfVotesToBlessRoot(makeTaggedRoot(1));
+ assertEq(ZERO, votesToBlessRoot);
+ assertFalse(hasVotedToBlessRoot(cfg.voters[0].blessVoteAddr, makeTaggedRoot(1)));
+ assertFalse(hasVotedToBlessRoot(cfg.voters[1].blessVoteAddr, makeTaggedRoot(1)));
+ vm.resumeGasMetering();
+ }
+
+ // Reverts
+
+ function test_NonOwner_Revert() public {
+ RMN.Config memory cfg = getDifferentConfigArgs();
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+ s_rmn.setConfig(cfg);
+ }
+
+ function test_VotersLengthIsZero_Revert() public {
+ vm.startPrank(OWNER);
+ vm.expectRevert(RMN.InvalidConfig.selector);
+ s_rmn.setConfig(RMN.Config({voters: new RMN.Voter[](0), blessWeightThreshold: 1, curseWeightThreshold: 1}));
+ }
+
+ function test_EitherThresholdIsZero_Revert() public {
+ RMN.Config memory cfg = getDifferentConfigArgs();
+
+ vm.startPrank(OWNER);
+ vm.expectRevert(RMN.InvalidConfig.selector);
+ s_rmn.setConfig(
+ RMN.Config({voters: cfg.voters, blessWeightThreshold: ZERO, curseWeightThreshold: cfg.curseWeightThreshold})
+ );
+ vm.expectRevert(RMN.InvalidConfig.selector);
+ s_rmn.setConfig(
+ RMN.Config({voters: cfg.voters, blessWeightThreshold: cfg.blessWeightThreshold, curseWeightThreshold: ZERO})
+ );
+ }
+
+ function test_BlessVoterIsZeroAddress_Revert() public {
+ RMN.Config memory cfg = getDifferentConfigArgs();
+
+ vm.startPrank(OWNER);
+ cfg.voters[0].blessVoteAddr = ZERO_ADDRESS;
+ vm.expectRevert(RMN.InvalidConfig.selector);
+ s_rmn.setConfig(cfg);
+ }
+
+ function test_WeightIsZeroAddress_Revert() public {
+ RMN.Config memory cfg = getDifferentConfigArgs();
+
+ vm.startPrank(OWNER);
+ cfg.voters[0].blessWeight = ZERO;
+ cfg.voters[0].curseWeight = ZERO;
+ vm.expectRevert(RMN.InvalidConfig.selector);
+ s_rmn.setConfig(cfg);
+ }
+
+ function test_TotalWeightsSmallerThanEachThreshold_Revert() public {
+ RMN.Config memory cfg = getDifferentConfigArgs();
+
+ vm.startPrank(OWNER);
+ vm.expectRevert(RMN.InvalidConfig.selector);
+ s_rmn.setConfig(
+ RMN.Config({voters: cfg.voters, blessWeightThreshold: WEIGHT_40, curseWeightThreshold: cfg.curseWeightThreshold})
+ );
+ vm.expectRevert(RMN.InvalidConfig.selector);
+ s_rmn.setConfig(
+ RMN.Config({voters: cfg.voters, blessWeightThreshold: cfg.blessWeightThreshold, curseWeightThreshold: WEIGHT_40})
+ );
+ }
+
+ function test_RepeatedAddress_Revert() public {
+ RMN.Config memory cfg = getDifferentConfigArgs();
+
+ vm.startPrank(OWNER);
+ cfg.voters[0].blessVoteAddr = cfg.voters[1].curseVoteAddr;
+ vm.expectRevert(RMN.InvalidConfig.selector);
+ s_rmn.setConfig(cfg);
+ }
+}
+
+contract RMN_permaBlessing is RMNSetup {
+ function addresses() private pure returns (address[] memory) {
+ return new address[](0);
+ }
+
+ function addresses(address a) private pure returns (address[] memory) {
+ address[] memory arr = new address[](1);
+ arr[0] = a;
+ return arr;
+ }
+
+ function addresses(address a, address b) private pure returns (address[] memory) {
+ address[] memory arr = new address[](2);
+ arr[0] = a;
+ arr[1] = b;
+ return arr;
+ }
+
+ function test_PermaBlessing() public {
+ bytes32 SOME_ROOT = bytes32(~uint256(0));
+ address COMMIT_STORE_1 = makeAddr("COMMIT_STORE_1");
+ address COMMIT_STORE_2 = makeAddr("COMMIT_STORE_2");
+ IRMN.TaggedRoot memory taggedRootCommitStore1 = IRMN.TaggedRoot({root: SOME_ROOT, commitStore: COMMIT_STORE_1});
+ IRMN.TaggedRoot memory taggedRootCommitStore2 = IRMN.TaggedRoot({root: SOME_ROOT, commitStore: COMMIT_STORE_2});
+
+ assertFalse(s_rmn.isBlessed(taggedRootCommitStore1));
+ assertFalse(s_rmn.isBlessed(taggedRootCommitStore2));
+ assertEq(s_rmn.getPermaBlessedCommitStores(), addresses());
+
+ // only owner can mutate permaBlessedCommitStores
+ vm.prank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+ s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(), addresses(COMMIT_STORE_1));
+
+ vm.prank(OWNER);
+ s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(), addresses(COMMIT_STORE_1));
+ assertTrue(s_rmn.isBlessed(taggedRootCommitStore1));
+ assertFalse(s_rmn.isBlessed(taggedRootCommitStore2));
+ assertEq(s_rmn.getPermaBlessedCommitStores(), addresses(COMMIT_STORE_1));
+
+ vm.prank(OWNER);
+ s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(COMMIT_STORE_1), addresses(COMMIT_STORE_2));
+ assertFalse(s_rmn.isBlessed(taggedRootCommitStore1));
+ assertTrue(s_rmn.isBlessed(taggedRootCommitStore2));
+ assertEq(s_rmn.getPermaBlessedCommitStores(), addresses(COMMIT_STORE_2));
+
+ vm.prank(OWNER);
+ s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(), addresses(COMMIT_STORE_1));
+ assertTrue(s_rmn.isBlessed(taggedRootCommitStore1));
+ assertTrue(s_rmn.isBlessed(taggedRootCommitStore2));
+ assertEq(s_rmn.getPermaBlessedCommitStores(), addresses(COMMIT_STORE_2, COMMIT_STORE_1));
+
+ vm.prank(OWNER);
+ s_rmn.ownerRemoveThenAddPermaBlessedCommitStores(addresses(COMMIT_STORE_1, COMMIT_STORE_2), addresses());
+ assertFalse(s_rmn.isBlessed(taggedRootCommitStore1));
+ assertFalse(s_rmn.isBlessed(taggedRootCommitStore2));
+ assertEq(s_rmn.getPermaBlessedCommitStores(), addresses());
+ }
+}
+
+contract RMN_getRecordedCurseRelatedOps is RMNSetup {
+ function test_OpsPostDeployment() public {
+ // The constructor call includes a setConfig, so that's the only thing we should expect to find.
+ assertEq(s_rmn.getRecordedCurseRelatedOpsCount(), 1);
+ RMN.RecordedCurseRelatedOp[] memory recordedCurseRelatedOps = s_rmn.getRecordedCurseRelatedOps(0, type(uint256).max);
+ assertEq(recordedCurseRelatedOps.length, 1);
+ assertEq(uint8(recordedCurseRelatedOps[0].tag), uint8(RMN.RecordedCurseRelatedOpTag.SetConfig));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/arm/RMNSetup.t.sol b/contracts/src/v0.8/ccip/test/arm/RMNSetup.t.sol
new file mode 100644
index 00000000000..8feacb95f45
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/arm/RMNSetup.t.sol
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {RMN} from "../../RMN.sol";
+import {IRMN} from "../../interfaces/IRMN.sol";
+
+import {Test} from "forge-std/Test.sol";
+
+function makeSubjects(bytes16 a) pure returns (bytes16[] memory) {
+ bytes16[] memory subjects = new bytes16[](1);
+ subjects[0] = a;
+ return subjects;
+}
+
+function makeSubjects(bytes16 a, bytes16 b) pure returns (bytes16[] memory) {
+ bytes16[] memory subjects = new bytes16[](2);
+ subjects[0] = a;
+ subjects[1] = b;
+ return subjects;
+}
+
+// in order from earliest to latest curse ids
+function makeCursesHashFromList(bytes32[] memory curseIds) pure returns (bytes28 cursesHash) {
+ for (uint256 i = 0; i < curseIds.length; ++i) {
+ cursesHash = bytes28(keccak256(abi.encode(cursesHash, curseIds[i])));
+ }
+}
+
+// hides the ugliness from tests
+function makeCursesHash(bytes32 a) pure returns (bytes28) {
+ bytes32[] memory curseIds = new bytes32[](1);
+ curseIds[0] = a;
+ return makeCursesHashFromList(curseIds);
+}
+
+function makeCursesHash(bytes32 a, bytes32 b) pure returns (bytes28) {
+ bytes32[] memory curseIds = new bytes32[](2);
+ curseIds[0] = a;
+ curseIds[1] = b;
+ return makeCursesHashFromList(curseIds);
+}
+
+contract RMNSetup is Test {
+ // Addresses
+ address internal constant OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e;
+ address internal constant STRANGER = address(999999);
+ address internal constant ZERO_ADDRESS = address(0);
+ address internal constant BLESS_VOTER_1 = address(1);
+ address internal constant CURSE_VOTER_1 = address(10);
+ address internal constant BLESS_VOTER_2 = address(2);
+ address internal constant CURSE_VOTER_2 = address(12);
+ address internal constant BLESS_VOTER_3 = address(3);
+ address internal constant CURSE_VOTER_3 = address(13);
+ address internal constant BLESS_VOTER_4 = address(4);
+ address internal constant CURSE_VOTER_4 = address(14);
+
+ // Arm
+ function rmnConstructorArgs() internal pure returns (RMN.Config memory) {
+ RMN.Voter[] memory voters = new RMN.Voter[](4);
+ voters[0] = RMN.Voter({
+ blessVoteAddr: BLESS_VOTER_1,
+ curseVoteAddr: CURSE_VOTER_1,
+ blessWeight: WEIGHT_1,
+ curseWeight: WEIGHT_1
+ });
+ voters[1] = RMN.Voter({
+ blessVoteAddr: BLESS_VOTER_2,
+ curseVoteAddr: CURSE_VOTER_2,
+ blessWeight: WEIGHT_10,
+ curseWeight: WEIGHT_10
+ });
+ voters[2] = RMN.Voter({
+ blessVoteAddr: BLESS_VOTER_3,
+ curseVoteAddr: CURSE_VOTER_3,
+ blessWeight: WEIGHT_20,
+ curseWeight: WEIGHT_20
+ });
+ voters[3] = RMN.Voter({
+ blessVoteAddr: BLESS_VOTER_4,
+ curseVoteAddr: CURSE_VOTER_4,
+ blessWeight: WEIGHT_40,
+ curseWeight: WEIGHT_40
+ });
+ return RMN.Config({
+ voters: voters,
+ blessWeightThreshold: WEIGHT_10 + WEIGHT_20 + WEIGHT_40,
+ curseWeightThreshold: WEIGHT_1 + WEIGHT_10 + WEIGHT_20 + WEIGHT_40
+ });
+ }
+
+ uint8 internal constant ZERO = 0;
+ uint8 internal constant WEIGHT_1 = 1;
+ uint8 internal constant WEIGHT_10 = 10;
+ uint8 internal constant WEIGHT_20 = 20;
+ uint8 internal constant WEIGHT_40 = 40;
+
+ function makeTaggedRootsInclusive(uint256 from, uint256 to) internal pure returns (IRMN.TaggedRoot[] memory) {
+ IRMN.TaggedRoot[] memory votes = new IRMN.TaggedRoot[](to - from + 1);
+ for (uint256 i = from; i <= to; ++i) {
+ votes[i - from] = IRMN.TaggedRoot({commitStore: address(1), root: bytes32(uint256(i))});
+ }
+ return votes;
+ }
+
+ function makeTaggedRootSingleton(uint256 index) internal pure returns (IRMN.TaggedRoot[] memory) {
+ return makeTaggedRootsInclusive(index, index);
+ }
+
+ function makeTaggedRoot(uint256 index) internal pure returns (IRMN.TaggedRoot memory) {
+ return makeTaggedRootSingleton(index)[0];
+ }
+
+ function makeTaggedRootHash(uint256 index) internal pure returns (bytes32) {
+ IRMN.TaggedRoot memory taggedRoot = makeTaggedRootSingleton(index)[0];
+ return keccak256(abi.encode(taggedRoot.commitStore, taggedRoot.root));
+ }
+
+ function makeCurseId(uint256 index) internal pure returns (bytes16) {
+ return bytes16(uint128(index));
+ }
+
+ RMN internal s_rmn;
+
+ function setUp() public virtual {
+ vm.startPrank(OWNER);
+ s_rmn = new RMN(rmnConstructorArgs());
+ vm.stopPrank();
+ }
+
+ function hasVotedToBlessRoot(address voter, IRMN.TaggedRoot memory taggedRoot_) internal view returns (bool) {
+ (address[] memory voters,,) = s_rmn.getBlessProgress(taggedRoot_);
+ for (uint256 i = 0; i < voters.length; ++i) {
+ if (voters[i] == voter) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function getWeightOfVotesToBlessRoot(IRMN.TaggedRoot memory taggedRoot_) internal view returns (uint16) {
+ (, uint16 weight,) = s_rmn.getBlessProgress(taggedRoot_);
+ return weight;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/arm/RMN_benchmark.t.sol b/contracts/src/v0.8/ccip/test/arm/RMN_benchmark.t.sol
new file mode 100644
index 00000000000..8564614a748
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/arm/RMN_benchmark.t.sol
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {GLOBAL_CURSE_SUBJECT, OWNER_CURSE_VOTE_ADDR, RMN} from "../../RMN.sol";
+import {RMNSetup, makeCursesHash, makeSubjects} from "./RMNSetup.t.sol";
+
+contract RMN_voteToBless_Benchmark is RMNSetup {
+ function test_RootSuccess_gas(uint256 n) internal {
+ vm.prank(BLESS_VOTER_1);
+ s_rmn.voteToBless(makeTaggedRootsInclusive(1, n));
+ }
+
+ function test_1RootSuccess_gas() public {
+ test_RootSuccess_gas(1);
+ }
+
+ function test_3RootSuccess_gas() public {
+ test_RootSuccess_gas(3);
+ }
+
+ function test_5RootSuccess_gas() public {
+ test_RootSuccess_gas(5);
+ }
+}
+
+contract RMN_voteToBless_Blessed_Benchmark is RMN_voteToBless_Benchmark {
+ function setUp() public virtual override {
+ RMNSetup.setUp();
+ vm.prank(BLESS_VOTER_2);
+ s_rmn.voteToBless(makeTaggedRootsInclusive(1, 1));
+ vm.prank(BLESS_VOTER_3);
+ s_rmn.voteToBless(makeTaggedRootsInclusive(1, 1));
+ }
+
+ function test_1RootSuccessBecameBlessed_gas() public {
+ vm.prank(BLESS_VOTER_4);
+ s_rmn.voteToBless(makeTaggedRootsInclusive(1, 1));
+ }
+}
+
+abstract contract RMN_voteToCurse_Benchmark is RMNSetup {
+ struct PreVote {
+ address voter;
+ bytes16 subject;
+ }
+
+ PreVote[] internal s_preVotes;
+
+ function setUp() public virtual override {
+ // Intentionally does not inherit RMNSetup setUp(), because we set up a simpler config here.
+ // The only way to ensure that storage slots are cold for the actual functions to be benchmarked is to perform the
+ // setup in setUp().
+
+ RMN.Config memory cfg = RMN.Config({voters: new RMN.Voter[](3), blessWeightThreshold: 3, curseWeightThreshold: 3});
+ cfg.voters[0] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTER_1, curseVoteAddr: CURSE_VOTER_1, blessWeight: 1, curseWeight: 1});
+ cfg.voters[1] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTER_2, curseVoteAddr: CURSE_VOTER_2, blessWeight: 1, curseWeight: 1});
+ cfg.voters[2] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTER_3, curseVoteAddr: CURSE_VOTER_3, blessWeight: 1, curseWeight: 1});
+ vm.prank(OWNER);
+ s_rmn = new RMN(cfg);
+
+ for (uint256 i = 0; i < s_preVotes.length; ++i) {
+ vm.prank(s_preVotes[i].voter);
+ s_rmn.voteToCurse(makeCurseId(i), makeSubjects(s_preVotes[i].subject));
+ }
+ }
+}
+
+contract RMN_voteToCurse_Benchmark_1 is RMN_voteToCurse_Benchmark {
+ constructor() {
+ // some irrelevant subject & voter so that we don't pay for the nonzero->zero SSTORE of
+ // s_recordedVotesToCurse.length in the benchmark below
+ s_preVotes.push(PreVote({voter: CURSE_VOTER_3, subject: bytes16(~uint128(0))}));
+ }
+
+ function test_VoteToCurse_NewSubject_NewVoter_NoCurse_gas() public {
+ vm.prank(CURSE_VOTER_1);
+ s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+
+ function test_VoteToCurse_NewSubject_NewVoter_YesCurse_gas() public {
+ vm.prank(OWNER);
+ s_rmn.ownerCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+}
+
+contract RMN_voteToCurse_Benchmark_2 is RMN_voteToCurse_Benchmark {
+ constructor() {
+ s_preVotes.push(PreVote({voter: CURSE_VOTER_1, subject: GLOBAL_CURSE_SUBJECT}));
+ }
+
+ function test_VoteToCurse_OldSubject_OldVoter_NoCurse_gas() public {
+ vm.prank(CURSE_VOTER_1);
+ s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+
+ function test_VoteToCurse_OldSubject_NewVoter_NoCurse_gas() public {
+ vm.prank(CURSE_VOTER_2);
+ s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+}
+
+contract RMN_voteToCurse_Benchmark_3 is RMN_voteToCurse_Benchmark {
+ constructor() {
+ s_preVotes.push(PreVote({voter: CURSE_VOTER_1, subject: GLOBAL_CURSE_SUBJECT}));
+ s_preVotes.push(PreVote({voter: CURSE_VOTER_2, subject: GLOBAL_CURSE_SUBJECT}));
+ }
+
+ function test_VoteToCurse_OldSubject_NewVoter_YesCurse_gas() public {
+ vm.prank(CURSE_VOTER_3);
+ s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+}
+
+contract RMN_lazyVoteToCurseUpdate_Benchmark is RMN_voteToCurse_Benchmark {
+ constructor() {
+ s_preVotes.push(PreVote({voter: CURSE_VOTER_1, subject: GLOBAL_CURSE_SUBJECT}));
+ s_preVotes.push(PreVote({voter: CURSE_VOTER_2, subject: GLOBAL_CURSE_SUBJECT}));
+ s_preVotes.push(PreVote({voter: CURSE_VOTER_3, subject: GLOBAL_CURSE_SUBJECT}));
+ }
+
+ function setUp() public override {
+ RMN_voteToCurse_Benchmark.setUp(); // sends the prevotes
+ // initial config includes voters CURSE_VOTER_1, CURSE_VOTER_2, CURSE_VOTER_3
+ // include a new voter in the config
+ {
+ (,, RMN.Config memory cfg) = s_rmn.getConfigDetails();
+ RMN.Voter[] memory newVoters = new RMN.Voter[](cfg.voters.length + 1);
+ for (uint256 i = 0; i < cfg.voters.length; ++i) {
+ newVoters[i] = cfg.voters[i];
+ }
+ newVoters[newVoters.length - 1] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTER_4, curseVoteAddr: CURSE_VOTER_4, blessWeight: 1, curseWeight: 1});
+ cfg.voters = newVoters;
+
+ vm.prank(OWNER);
+ s_rmn.setConfig(cfg);
+ }
+ }
+
+ function test_VoteToCurseLazilyRetain3VotersUponConfigChange_gas() public {
+ // send a vote as the new voter, should cause a lazy update and votes from CURSE_VOTER_1, CURSE_VOTER_2,
+ // CURSE_VOTER_3 to be retained, which is the worst case for the prior config
+ vm.prank(CURSE_VOTER_4);
+ s_rmn.voteToCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+}
+
+contract RMN_setConfig_Benchmark is RMNSetup {
+ uint256 s_numVoters;
+
+ function configWithVoters(uint256 numVoters) internal pure returns (RMN.Config memory) {
+ RMN.Config memory cfg =
+ RMN.Config({voters: new RMN.Voter[](numVoters), blessWeightThreshold: 1, curseWeightThreshold: 1});
+ for (uint256 i = 1; i <= numVoters; ++i) {
+ cfg.voters[i - 1] = RMN.Voter({
+ blessVoteAddr: address(uint160(2 * i)),
+ curseVoteAddr: address(uint160(2 * i + 1)),
+ blessWeight: 1,
+ curseWeight: 1
+ });
+ }
+ return cfg;
+ }
+
+ function setUp() public virtual override {
+ vm.prank(OWNER);
+ s_rmn = new RMN(configWithVoters(s_numVoters));
+ }
+}
+
+contract RMN_setConfig_Benchmark_1 is RMN_setConfig_Benchmark {
+ constructor() {
+ s_numVoters = 1;
+ }
+
+ function test_SetConfig_7Voters_gas() public {
+ vm.prank(OWNER);
+ s_rmn.setConfig(configWithVoters(7));
+ }
+}
+
+contract RMN_setConfig_Benchmark_2 is RMN_setConfig_Benchmark {
+ constructor() {
+ s_numVoters = 7;
+ }
+
+ function test_ResetConfig_7Voters_gas() public {
+ vm.prank(OWNER);
+ s_rmn.setConfig(configWithVoters(7));
+ }
+}
+
+contract RMN_ownerUnvoteToCurse_Benchmark is RMN_setConfig_Benchmark {
+ constructor() {
+ s_numVoters = 7;
+ }
+
+ function setUp() public override {
+ RMN_setConfig_Benchmark.setUp();
+ vm.prank(OWNER);
+ s_rmn.ownerCurse(makeCurseId(0xffff), makeSubjects(GLOBAL_CURSE_SUBJECT));
+ }
+
+ function test_OwnerUnvoteToCurse_1Voter_LiftsCurse_gas() public {
+ RMN.OwnerUnvoteToCurseRequest[] memory reqs = new RMN.OwnerUnvoteToCurseRequest[](1);
+ reqs[0] = RMN.OwnerUnvoteToCurseRequest({
+ curseVoteAddr: OWNER_CURSE_VOTE_ADDR,
+ unit: RMN.UnvoteToCurseRequest({cursesHash: makeCursesHash(makeCurseId(0xffff)), subject: GLOBAL_CURSE_SUBJECT}),
+ forceUnvote: false
+ });
+ vm.prank(OWNER);
+ s_rmn.ownerUnvoteToCurse(reqs);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/attacks/onRamp/FacadeClient.sol b/contracts/src/v0.8/ccip/test/attacks/onRamp/FacadeClient.sol
new file mode 100644
index 00000000000..ad549e6ccc2
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/attacks/onRamp/FacadeClient.sol
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IRouterClient} from "../../../interfaces/IRouterClient.sol";
+
+import {Client} from "../../../libraries/Client.sol";
+
+import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+/// @title FacadeClient - A simple proxy for calling Router
+contract FacadeClient {
+ address private immutable i_router;
+ uint64 private immutable i_destChainSelector;
+ IERC20 private immutable i_sourceToken;
+ IERC20 private immutable i_feeToken;
+ address private immutable i_receiver;
+
+ uint256 private s_msg_sequence = 1;
+
+ constructor(address router, uint64 destChainSelector, IERC20 sourceToken, IERC20 feeToken, address receiver) {
+ i_router = router;
+ i_destChainSelector = destChainSelector;
+ i_sourceToken = sourceToken;
+ i_feeToken = feeToken;
+ i_receiver = receiver;
+
+ sourceToken.approve(address(router), 2 ** 256 - 1);
+ feeToken.approve(address(router), 2 ** 256 - 1);
+ }
+
+ /// @dev Calls Router to initiate CCIP send.
+ /// The expectation is that s_msg_sequence will always match the sequence in emitted CCIP messages.
+ function send(uint256 amount) public {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0].token = address(i_sourceToken);
+ tokenAmounts[0].amount = amount;
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(i_receiver),
+ data: abi.encodePacked(s_msg_sequence),
+ tokenAmounts: tokenAmounts,
+ extraArgs: "",
+ feeToken: address(i_feeToken)
+ });
+
+ s_msg_sequence++;
+
+ IRouterClient(i_router).ccipSend(i_destChainSelector, message);
+ }
+
+ function getSequence() public view returns (uint256) {
+ return s_msg_sequence;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/attacks/onRamp/MultiOnRampTokenPoolReentrancy.t.sol b/contracts/src/v0.8/ccip/test/attacks/onRamp/MultiOnRampTokenPoolReentrancy.t.sol
new file mode 100644
index 00000000000..5deeda64063
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/attacks/onRamp/MultiOnRampTokenPoolReentrancy.t.sol
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Client} from "../../../libraries/Client.sol";
+import {Internal} from "../../../libraries/Internal.sol";
+import {EVM2EVMMultiOnRamp} from "../../../onRamp/EVM2EVMMultiOnRamp.sol";
+import {TokenPool} from "../../../pools/TokenPool.sol";
+import {EVM2EVMMultiOnRampSetup} from "../../onRamp/EVM2EVMMultiOnRampSetup.t.sol";
+import {FacadeClient} from "./FacadeClient.sol";
+import {ReentrantMaliciousTokenPool} from "./ReentrantMaliciousTokenPool.sol";
+
+import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+import {console} from "forge-std/console.sol";
+
+/// @title MultiOnRampTokenPoolReentrancy
+/// Attempts to perform a reentrancy exploit on Onramp with a malicious TokenPool
+contract MultiOnRampTokenPoolReentrancy is EVM2EVMMultiOnRampSetup {
+ FacadeClient internal s_facadeClient;
+ ReentrantMaliciousTokenPool internal s_maliciousTokenPool;
+ IERC20 internal s_sourceToken;
+ IERC20 internal s_feeToken;
+ address internal immutable i_receiver = makeAddr("receiver");
+
+ function setUp() public virtual override {
+ EVM2EVMMultiOnRampSetup.setUp();
+
+ s_sourceToken = IERC20(s_sourceTokens[0]);
+ s_feeToken = IERC20(s_sourceTokens[0]);
+
+ s_facadeClient =
+ new FacadeClient(address(s_sourceRouter), DEST_CHAIN_SELECTOR, s_sourceToken, s_feeToken, i_receiver);
+
+ s_maliciousTokenPool = new ReentrantMaliciousTokenPool(
+ address(s_facadeClient), s_sourceToken, address(s_mockRMN), address(s_sourceRouter)
+ );
+
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_destPoolBySourceToken[s_sourceTokens[0]]),
+ remoteTokenAddress: abi.encode(s_destTokens[0]),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_maliciousTokenPool.applyChainUpdates(chainUpdates);
+ s_sourcePoolByToken[address(s_sourceToken)] = address(s_maliciousTokenPool);
+
+ Internal.PoolUpdate[] memory removes = new Internal.PoolUpdate[](1);
+ removes[0].token = address(s_sourceToken);
+ removes[0].pool = address(s_sourcePoolByToken[address(s_sourceToken)]);
+ Internal.PoolUpdate[] memory adds = new Internal.PoolUpdate[](1);
+ adds[0].token = address(s_sourceToken);
+ adds[0].pool = address(s_maliciousTokenPool);
+
+ s_tokenAdminRegistry.setPool(address(s_sourceToken), address(s_maliciousTokenPool));
+
+ s_sourceToken.transfer(address(s_facadeClient), 1e18);
+ s_feeToken.transfer(address(s_facadeClient), 1e18);
+ }
+
+ /// @dev This test was used to showcase a reentrancy exploit on OnRamp with malicious TokenPool.
+ /// How it worked: OnRamp used to construct EVM2Any messages after calling TokenPool's lockOrBurn.
+ /// This allowed the malicious TokenPool to break message sequencing expectations as follows:
+ /// Any user -> Facade -> 1st call to ccipSend -> pool’s lockOrBurn —>
+ /// (reenter)-> Facade -> 2nd call to ccipSend
+ /// In this case, Facade's second call would produce an EVM2Any msg with a lower sequence number.
+ /// The issue was fixed by moving state updates and event construction to before TokenPool calls.
+ /// This test is kept to verify message sequence expectations are not broken.
+ function test_OnRampTokenPoolReentrancy_Success() public {
+ uint256 amount = 1;
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0].token = address(s_sourceToken);
+ tokenAmounts[0].amount = amount;
+
+ Client.EVM2AnyMessage memory message1 = Client.EVM2AnyMessage({
+ receiver: abi.encode(i_receiver),
+ data: abi.encodePacked(uint256(1)), // message 1 contains data 1
+ tokenAmounts: tokenAmounts,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 200_000})),
+ feeToken: address(s_feeToken)
+ });
+
+ Client.EVM2AnyMessage memory message2 = Client.EVM2AnyMessage({
+ receiver: abi.encode(i_receiver),
+ data: abi.encodePacked(uint256(2)), // message 2 contains data 2
+ tokenAmounts: tokenAmounts,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 200_000})),
+ feeToken: address(s_feeToken)
+ });
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message1);
+ assertGt(expectedFee, 0);
+
+ // Outcome of a successful exploit:
+ // Message 1 event from OnRamp contains sequence/nonce 2, message 2 contains sequence/nonce 1
+ // Internal.EVM2EVMMessage memory msgEvent1 = _messageToEvent(message1, 2, 2, expectedFee, address(s_facadeClient));
+ // Internal.EVM2EVMMessage memory msgEvent2 = _messageToEvent(message2, 1, 1, expectedFee, address(s_facadeClient));
+
+ // vm.expectEmit();
+ // emit CCIPSendRequested(msgEvent2);
+ // vm.expectEmit();
+ // emit CCIPSendRequested(msgEvent1);
+
+ // After issue is fixed, sequence now increments as expected
+ Internal.EVM2AnyRampMessage memory msgEvent1 = _messageToEvent(message1, 1, 1, expectedFee, address(s_facadeClient));
+ Internal.EVM2AnyRampMessage memory msgEvent2 = _messageToEvent(message2, 2, 2, expectedFee, address(s_facadeClient));
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, msgEvent2);
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, msgEvent1);
+
+ s_facadeClient.send(amount);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/attacks/onRamp/OnRampTokenPoolReentrancy.t.sol b/contracts/src/v0.8/ccip/test/attacks/onRamp/OnRampTokenPoolReentrancy.t.sol
new file mode 100644
index 00000000000..8fc71be8573
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/attacks/onRamp/OnRampTokenPoolReentrancy.t.sol
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Client} from "../../../libraries/Client.sol";
+import {Internal} from "../../../libraries/Internal.sol";
+import {EVM2EVMOnRamp} from "../../../onRamp/EVM2EVMOnRamp.sol";
+import {TokenPool} from "../../../pools/TokenPool.sol";
+import {EVM2EVMOnRampSetup} from "../../onRamp/EVM2EVMOnRampSetup.t.sol";
+import {FacadeClient} from "./FacadeClient.sol";
+import {ReentrantMaliciousTokenPool} from "./ReentrantMaliciousTokenPool.sol";
+
+import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+/// @title OnRampTokenPoolReentrancy
+/// Attempts to perform a reentrancy exploit on Onramp with a malicious TokenPool
+contract OnRampTokenPoolReentrancy is EVM2EVMOnRampSetup {
+ FacadeClient internal s_facadeClient;
+ ReentrantMaliciousTokenPool internal s_maliciousTokenPool;
+ IERC20 internal s_sourceToken;
+ IERC20 internal s_feeToken;
+ address internal immutable i_receiver = makeAddr("receiver");
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ s_sourceToken = IERC20(s_sourceTokens[0]);
+ s_feeToken = IERC20(s_sourceTokens[0]);
+
+ s_facadeClient =
+ new FacadeClient(address(s_sourceRouter), DEST_CHAIN_SELECTOR, s_sourceToken, s_feeToken, i_receiver);
+
+ s_maliciousTokenPool = new ReentrantMaliciousTokenPool(
+ address(s_facadeClient), s_sourceToken, address(s_mockRMN), address(s_sourceRouter)
+ );
+
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_destPoolBySourceToken[s_sourceTokens[0]]),
+ remoteTokenAddress: abi.encode(s_destTokens[0]),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_maliciousTokenPool.applyChainUpdates(chainUpdates);
+ s_sourcePoolByToken[address(s_sourceToken)] = address(s_maliciousTokenPool);
+
+ Internal.PoolUpdate[] memory removes = new Internal.PoolUpdate[](1);
+ removes[0].token = address(s_sourceToken);
+ removes[0].pool = address(s_sourcePoolByToken[address(s_sourceToken)]);
+ Internal.PoolUpdate[] memory adds = new Internal.PoolUpdate[](1);
+ adds[0].token = address(s_sourceToken);
+ adds[0].pool = address(s_maliciousTokenPool);
+
+ s_tokenAdminRegistry.setPool(address(s_sourceToken), address(s_maliciousTokenPool));
+
+ s_sourceToken.transfer(address(s_facadeClient), 1e18);
+ s_feeToken.transfer(address(s_facadeClient), 1e18);
+ }
+
+ /// @dev This test was used to showcase a reentrancy exploit on OnRamp with malicious TokenPool.
+ /// How it worked: OnRamp used to construct EVM2EVM messages after calling TokenPool's lockOrBurn.
+ /// This allowed the malicious TokenPool to break message sequencing expectations as follows:
+ /// Any user -> Facade -> 1st call to ccipSend -> pool’s lockOrBurn —>
+ /// (reenter)-> Facade -> 2nd call to ccipSend
+ /// In this case, Facade's second call would produce an EVM2EVM msg with a lower sequence number.
+ /// The issue was fixed by moving state updates and event construction to before TokenPool calls.
+ /// This test is kept to verify message sequence expectations are not broken.
+ function test_OnRampTokenPoolReentrancy_Success() public {
+ uint256 amount = 1;
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0].token = address(s_sourceToken);
+ tokenAmounts[0].amount = amount;
+
+ Client.EVM2AnyMessage memory message1 = Client.EVM2AnyMessage({
+ receiver: abi.encode(i_receiver),
+ data: abi.encodePacked(uint256(1)), // message 1 contains data 1
+ tokenAmounts: tokenAmounts,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 200_000})),
+ feeToken: address(s_feeToken)
+ });
+
+ Client.EVM2AnyMessage memory message2 = Client.EVM2AnyMessage({
+ receiver: abi.encode(i_receiver),
+ data: abi.encodePacked(uint256(2)), // message 2 contains data 2
+ tokenAmounts: tokenAmounts,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 200_000})),
+ feeToken: address(s_feeToken)
+ });
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message1);
+ assertGt(expectedFee, 0);
+
+ // Outcome of a successful exploit:
+ // Message 1 event from OnRamp contains sequence/nonce 2, message 2 contains sequence/nonce 1
+ // Internal.EVM2EVMMessage memory msgEvent1 = _messageToEvent(message1, 2, 2, expectedFee, address(s_facadeClient));
+ // Internal.EVM2EVMMessage memory msgEvent2 = _messageToEvent(message2, 1, 1, expectedFee, address(s_facadeClient));
+
+ // vm.expectEmit();
+ // emit CCIPSendRequested(msgEvent2);
+ // vm.expectEmit();
+ // emit CCIPSendRequested(msgEvent1);
+
+ // After issue is fixed, sequence now increments as expected
+ Internal.EVM2EVMMessage memory msgEvent1 = _messageToEvent(message1, 1, 1, expectedFee, address(s_facadeClient));
+ Internal.EVM2EVMMessage memory msgEvent2 = _messageToEvent(message2, 2, 2, expectedFee, address(s_facadeClient));
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent2);
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent1);
+
+ s_facadeClient.send(amount);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/attacks/onRamp/ReentrantMaliciousTokenPool.sol b/contracts/src/v0.8/ccip/test/attacks/onRamp/ReentrantMaliciousTokenPool.sol
new file mode 100644
index 00000000000..17c13a8148e
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/attacks/onRamp/ReentrantMaliciousTokenPool.sol
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Pool} from "../../../libraries/Pool.sol";
+import {TokenPool} from "../../../pools/TokenPool.sol";
+import {FacadeClient} from "./FacadeClient.sol";
+
+import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract ReentrantMaliciousTokenPool is TokenPool {
+ address private i_facade;
+
+ bool private s_attacked;
+
+ constructor(
+ address facade,
+ IERC20 token,
+ address rmnProxy,
+ address router
+ ) TokenPool(token, new address[](0), rmnProxy, router) {
+ i_facade = facade;
+ }
+
+ /// @dev Calls into Facade to reenter Router exactly 1 time
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ if (s_attacked) {
+ return
+ Pool.LockOrBurnOutV1({destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: ""});
+ }
+
+ s_attacked = true;
+
+ FacadeClient(i_facade).send(lockOrBurnIn.amount);
+ emit Burned(msg.sender, lockOrBurnIn.amount);
+ return Pool.LockOrBurnOutV1({destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: ""});
+ }
+
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ pure
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/capability/CCIPConfig.t.sol b/contracts/src/v0.8/ccip/test/capability/CCIPConfig.t.sol
new file mode 100644
index 00000000000..0c3108d279f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/capability/CCIPConfig.t.sol
@@ -0,0 +1,1681 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.24;
+
+import {Test} from "forge-std/Test.sol";
+
+import {SortedSetValidationUtil} from "../../../shared/util/SortedSetValidationUtil.sol";
+import {CCIPConfig} from "../../capability/CCIPConfig.sol";
+import {ICapabilitiesRegistry} from "../../capability/interfaces/ICapabilitiesRegistry.sol";
+import {CCIPConfigTypes} from "../../capability/libraries/CCIPConfigTypes.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {CCIPConfigHelper} from "../helpers/CCIPConfigHelper.sol";
+
+contract CCIPConfigSetup is Test {
+ address public constant OWNER = 0x82ae2B4F57CA5C1CBF8f744ADbD3697aD1a35AFe;
+ address public constant CAPABILITIES_REGISTRY = 0x272aF4BF7FBFc4944Ed59F914Cd864DfD912D55e;
+
+ CCIPConfigHelper public s_ccipCC;
+
+ function setUp() public {
+ changePrank(OWNER);
+ s_ccipCC = new CCIPConfigHelper(CAPABILITIES_REGISTRY);
+ }
+
+ function _makeBytes32Array(uint256 length, uint256 seed) internal pure returns (bytes32[] memory arr) {
+ arr = new bytes32[](length);
+ for (uint256 i = 0; i < length; i++) {
+ arr[i] = keccak256(abi.encode(i, 1, seed));
+ }
+ return arr;
+ }
+
+ function _makeBytesArray(uint256 length, uint256 seed) internal pure returns (bytes[] memory arr) {
+ arr = new bytes[](length);
+ for (uint256 i = 0; i < length; i++) {
+ arr[i] = abi.encodePacked(keccak256(abi.encode(i, 1, seed)));
+ }
+ return arr;
+ }
+
+ function _subset(bytes32[] memory arr, uint256 start, uint256 end) internal pure returns (bytes32[] memory) {
+ bytes32[] memory subset = new bytes32[](end - start);
+ for (uint256 i = start; i < end; i++) {
+ subset[i - start] = arr[i];
+ }
+ return subset;
+ }
+
+ //TODO: Use OZ's Arrays.sort when we upgrade to OZ v5
+ function _sort(bytes32[] memory arr, int256 left, int256 right) private pure {
+ int256 i = left;
+ int256 j = right;
+ if (i == j) return;
+ bytes32 pivot = arr[uint256(left + (right - left) / 2)];
+ while (i <= j) {
+ while (arr[uint256(i)] < pivot) i++;
+ while (pivot < arr[uint256(j)]) j--;
+ if (i <= j) {
+ (arr[uint256(i)], arr[uint256(j)]) = (arr[uint256(j)], arr[uint256(i)]);
+ i++;
+ j--;
+ }
+ }
+ if (left < j) _sort(arr, left, j);
+ if (i < right) _sort(arr, i, right);
+ }
+
+ function _addChainConfig(uint256 numNodes)
+ internal
+ returns (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters)
+ {
+ p2pIds = _makeBytes32Array(numNodes, 0);
+ _sort(p2pIds, 0, int256(numNodes - 1));
+ signers = _makeBytesArray(numNodes, 10);
+ transmitters = _makeBytesArray(numNodes, 20);
+ for (uint256 i = 0; i < numNodes; i++) {
+ vm.mockCall(
+ CAPABILITIES_REGISTRY,
+ abi.encodeWithSelector(ICapabilitiesRegistry.getNode.selector, p2pIds[i]),
+ abi.encode(
+ ICapabilitiesRegistry.NodeInfo({
+ nodeOperatorId: 1,
+ signer: bytes32(signers[i]),
+ p2pId: p2pIds[i],
+ hashedCapabilityIds: new bytes32[](0),
+ configCount: uint32(1),
+ workflowDONId: uint32(1),
+ capabilitiesDONIds: new uint256[](0)
+ })
+ )
+ );
+ }
+ // Add chain selector for chain 1.
+ CCIPConfigTypes.ChainConfigInfo[] memory adds = new CCIPConfigTypes.ChainConfigInfo[](1);
+ adds[0] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: 1,
+ chainConfig: CCIPConfigTypes.ChainConfig({readers: p2pIds, fChain: 1, config: bytes("config1")})
+ });
+
+ vm.expectEmit();
+ emit CCIPConfig.ChainConfigSet(1, adds[0].chainConfig);
+ s_ccipCC.applyChainConfigUpdates(new uint64[](0), adds);
+
+ return (p2pIds, signers, transmitters);
+ }
+
+ function test_getCapabilityConfiguration_Success() public {
+ bytes memory capConfig = s_ccipCC.getCapabilityConfiguration(42 /* doesn't matter, not used */ );
+ assertEq(capConfig.length, 0, "capability config length must be 0");
+ }
+}
+
+contract CCIPConfig_chainConfig is CCIPConfigSetup {
+ // Successes.
+
+ function test_applyChainConfigUpdates_addChainConfigs_Success() public {
+ bytes32[] memory chainReaders = new bytes32[](1);
+ chainReaders[0] = keccak256(abi.encode(1));
+ CCIPConfigTypes.ChainConfigInfo[] memory adds = new CCIPConfigTypes.ChainConfigInfo[](2);
+ adds[0] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: 1,
+ chainConfig: CCIPConfigTypes.ChainConfig({readers: chainReaders, fChain: 1, config: bytes("config1")})
+ });
+ adds[1] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: 2,
+ chainConfig: CCIPConfigTypes.ChainConfig({readers: chainReaders, fChain: 1, config: bytes("config2")})
+ });
+
+ vm.mockCall(
+ CAPABILITIES_REGISTRY,
+ abi.encodeWithSelector(ICapabilitiesRegistry.getNode.selector, chainReaders[0]),
+ abi.encode(
+ ICapabilitiesRegistry.NodeInfo({
+ nodeOperatorId: 1,
+ signer: bytes32(uint256(1)),
+ p2pId: chainReaders[0],
+ hashedCapabilityIds: new bytes32[](0),
+ configCount: uint32(1),
+ workflowDONId: uint32(1),
+ capabilitiesDONIds: new uint256[](0)
+ })
+ )
+ );
+
+ vm.expectEmit();
+ emit CCIPConfig.ChainConfigSet(1, adds[0].chainConfig);
+ vm.expectEmit();
+ emit CCIPConfig.ChainConfigSet(2, adds[1].chainConfig);
+ s_ccipCC.applyChainConfigUpdates(new uint64[](0), adds);
+
+ CCIPConfigTypes.ChainConfigInfo[] memory configs = s_ccipCC.getAllChainConfigs();
+ assertEq(configs.length, 2, "chain configs length must be 2");
+ assertEq(configs[0].chainSelector, 1, "chain selector must match");
+ assertEq(configs[1].chainSelector, 2, "chain selector must match");
+ }
+
+ function test_applyChainConfigUpdates_removeChainConfigs_Success() public {
+ bytes32[] memory chainReaders = new bytes32[](1);
+ chainReaders[0] = keccak256(abi.encode(1));
+ CCIPConfigTypes.ChainConfigInfo[] memory adds = new CCIPConfigTypes.ChainConfigInfo[](2);
+ adds[0] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: 1,
+ chainConfig: CCIPConfigTypes.ChainConfig({readers: chainReaders, fChain: 1, config: bytes("config1")})
+ });
+ adds[1] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: 2,
+ chainConfig: CCIPConfigTypes.ChainConfig({readers: chainReaders, fChain: 1, config: bytes("config2")})
+ });
+
+ vm.mockCall(
+ CAPABILITIES_REGISTRY,
+ abi.encodeWithSelector(ICapabilitiesRegistry.getNode.selector, chainReaders[0]),
+ abi.encode(
+ ICapabilitiesRegistry.NodeInfo({
+ nodeOperatorId: 1,
+ signer: bytes32(uint256(1)),
+ p2pId: chainReaders[0],
+ hashedCapabilityIds: new bytes32[](0),
+ configCount: uint32(1),
+ workflowDONId: uint32(1),
+ capabilitiesDONIds: new uint256[](0)
+ })
+ )
+ );
+
+ vm.expectEmit();
+ emit CCIPConfig.ChainConfigSet(1, adds[0].chainConfig);
+ vm.expectEmit();
+ emit CCIPConfig.ChainConfigSet(2, adds[1].chainConfig);
+ s_ccipCC.applyChainConfigUpdates(new uint64[](0), adds);
+
+ uint64[] memory removes = new uint64[](1);
+ removes[0] = uint64(1);
+
+ vm.expectEmit();
+ emit CCIPConfig.ChainConfigRemoved(1);
+ s_ccipCC.applyChainConfigUpdates(removes, new CCIPConfigTypes.ChainConfigInfo[](0));
+ }
+
+ // Reverts.
+
+ function test_applyChainConfigUpdates_selectorNotFound_Reverts() public {
+ uint64[] memory removes = new uint64[](1);
+ removes[0] = uint64(1);
+
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.ChainSelectorNotFound.selector, 1));
+ s_ccipCC.applyChainConfigUpdates(removes, new CCIPConfigTypes.ChainConfigInfo[](0));
+ }
+
+ function test_applyChainConfigUpdates_nodeNotInRegistry_Reverts() public {
+ bytes32[] memory chainReaders = new bytes32[](1);
+ chainReaders[0] = keccak256(abi.encode(1));
+ CCIPConfigTypes.ChainConfigInfo[] memory adds = new CCIPConfigTypes.ChainConfigInfo[](1);
+ adds[0] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: 1,
+ chainConfig: CCIPConfigTypes.ChainConfig({readers: chainReaders, fChain: 1, config: abi.encode(1, 2, 3)})
+ });
+
+ vm.mockCall(
+ CAPABILITIES_REGISTRY,
+ abi.encodeWithSelector(ICapabilitiesRegistry.getNode.selector, chainReaders[0]),
+ abi.encode(
+ ICapabilitiesRegistry.NodeInfo({
+ nodeOperatorId: 0,
+ signer: bytes32(0),
+ p2pId: bytes32(uint256(0)),
+ hashedCapabilityIds: new bytes32[](0),
+ configCount: uint32(1),
+ workflowDONId: uint32(1),
+ capabilitiesDONIds: new uint256[](0)
+ })
+ )
+ );
+
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.NodeNotInRegistry.selector, chainReaders[0]));
+ s_ccipCC.applyChainConfigUpdates(new uint64[](0), adds);
+ }
+
+ function test__applyChainConfigUpdates_FChainNotPositive_Reverts() public {
+ bytes32[] memory chainReaders = new bytes32[](1);
+ chainReaders[0] = keccak256(abi.encode(1));
+ CCIPConfigTypes.ChainConfigInfo[] memory adds = new CCIPConfigTypes.ChainConfigInfo[](2);
+ adds[0] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: 1,
+ chainConfig: CCIPConfigTypes.ChainConfig({readers: chainReaders, fChain: 1, config: bytes("config1")})
+ });
+ adds[1] = CCIPConfigTypes.ChainConfigInfo({
+ chainSelector: 2,
+ chainConfig: CCIPConfigTypes.ChainConfig({readers: chainReaders, fChain: 0, config: bytes("config2")}) // bad fChain
+ });
+
+ vm.mockCall(
+ CAPABILITIES_REGISTRY,
+ abi.encodeWithSelector(ICapabilitiesRegistry.getNode.selector, chainReaders[0]),
+ abi.encode(
+ ICapabilitiesRegistry.NodeInfo({
+ nodeOperatorId: 1,
+ signer: bytes32(uint256(1)),
+ p2pId: chainReaders[0],
+ hashedCapabilityIds: new bytes32[](0),
+ configCount: uint32(1),
+ workflowDONId: uint32(1),
+ capabilitiesDONIds: new uint256[](0)
+ })
+ )
+ );
+
+ vm.expectRevert(CCIPConfig.FChainMustBePositive.selector);
+ s_ccipCC.applyChainConfigUpdates(new uint64[](0), adds);
+ }
+}
+
+contract CCIPConfig_validateConfig is CCIPConfigSetup {
+ // Successes.
+
+ function test__validateConfig_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+
+ // Config is for 4 nodes, so f == 1.
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+ s_ccipCC.validateConfig(config);
+ }
+
+ // Reverts.
+
+ function test__validateConfig_ChainSelectorNotSet_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+
+ // Config is for 4 nodes, so f == 1.
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 0, // invalid
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(CCIPConfig.ChainSelectorNotSet.selector);
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_OfframpAddressCannotBeZero_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+
+ // Config is for 4 nodes, so f == 1.
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: bytes(""), // invalid
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(CCIPConfig.OfframpAddressCannotBeZero.selector);
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_ChainSelectorNotFound_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+
+ // Config is for 4 nodes, so f == 1.
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 2, // not set
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.ChainSelectorNotFound.selector, 2));
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_TooManySigners_Reverts() public {
+ // 32 > 31 (max num oracles)
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(32);
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(CCIPConfig.TooManySigners.selector);
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_TooManyTransmitters_Reverts() public {
+ // 32 > 31 (max num oracles)
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(32);
+
+ // truncate signers but keep transmitters > 31
+ assembly {
+ mstore(signers, 30)
+ }
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(CCIPConfig.TooManyTransmitters.selector);
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_NotEnoughTransmitters_Reverts() public {
+ // 32 > 31 (max num oracles)
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(31);
+
+ // truncate transmitters to < 3 * fChain + 1
+ // since fChain is 1 in this case, we need to truncate to 3 transmitters.
+ assembly {
+ mstore(transmitters, 3)
+ }
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.NotEnoughTransmitters.selector, 3, 4));
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_FMustBePositive_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+
+ // Config is for 4 nodes, so f == 1.
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 0,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(CCIPConfig.FMustBePositive.selector);
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_FTooHigh_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 2,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(CCIPConfig.FTooHigh.selector);
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_P2PIdsLengthNotMatching_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ // truncate the p2pIds length
+ assembly {
+ mstore(p2pIds, 3)
+ }
+
+ // Config is for 4 nodes, so f == 1.
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(CCIPConfig.P2PIdsLengthNotMatching.selector, uint256(3), uint256(4), uint256(4))
+ );
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_TooManyBootstrapP2PIds_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+
+ // Config is for 4 nodes, so f == 1.
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _makeBytes32Array(5, 0), // too many bootstrap p2pIds, 5 > 4
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(CCIPConfig.TooManyBootstrapP2PIds.selector);
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_NodeNotInRegistry_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ bytes32 nonExistentP2PId = keccak256("notInRegistry");
+ p2pIds[0] = nonExistentP2PId;
+
+ vm.mockCall(
+ CAPABILITIES_REGISTRY,
+ abi.encodeWithSelector(ICapabilitiesRegistry.getNode.selector, nonExistentP2PId),
+ abi.encode(
+ ICapabilitiesRegistry.NodeInfo({
+ nodeOperatorId: 0,
+ signer: bytes32(0),
+ p2pId: bytes32(uint256(0)),
+ hashedCapabilityIds: new bytes32[](0),
+ configCount: uint32(1),
+ workflowDONId: uint32(1),
+ capabilitiesDONIds: new uint256[](0)
+ })
+ )
+ );
+
+ // Config is for 4 nodes, so f == 1.
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.NodeNotInRegistry.selector, nonExistentP2PId));
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_P2PIdsNotSorted_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ // Config is for 4 nodes, so f == 1.
+
+ //swapping two adjacent p2pIds to make it unsorted
+ (p2pIds[2], p2pIds[3]) = (p2pIds[3], p2pIds[2]);
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, p2pIds));
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_BootstrapP2PIdsNotSorted_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ // Config is for 4 nodes, so f == 1.
+
+ bytes32[] memory bootstrapP2PIds = _subset(p2pIds, 0, 2);
+
+ //swapping bootstrapP2PIds to make it unsorted
+ (bootstrapP2PIds[0], bootstrapP2PIds[1]) = (bootstrapP2PIds[1], bootstrapP2PIds[0]);
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: bootstrapP2PIds,
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, bootstrapP2PIds));
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_P2PIdsHasDuplicates_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ // Config is for 4 nodes, so f == 1.
+
+ //forcing duplicate p2pIds
+ p2pIds[1] = p2pIds[2];
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 2),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, p2pIds));
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_BootstrapP2PIdsHasDuplicates_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ // Config is for 4 nodes, so f == 1.
+
+ bytes32[] memory bootstrapP2PIds = _subset(p2pIds, 0, 2);
+ //forcing duplicate bootstrapP2PIds
+ bootstrapP2PIds[1] = bootstrapP2PIds[0];
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: bootstrapP2PIds,
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, bootstrapP2PIds));
+ s_ccipCC.validateConfig(config);
+ }
+
+ function test__validateConfig_BootstrapP2PIdsNotASubsetOfP2PIds_Reverts() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ // Config is for 4 nodes, so f == 1.
+
+ //forcing invalid bootstrapP2PIds where the bootstrapP2PIds is sorted, but one of the element is not in the p2pIdsSet
+ bytes32[] memory bootstrapP2PIds = _subset(p2pIds, 0, 2);
+ p2pIds[1] = bytes32(uint256(p2pIds[0]) + 100);
+
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: bootstrapP2PIds,
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASubset.selector, bootstrapP2PIds, p2pIds));
+ s_ccipCC.validateConfig(config);
+ }
+}
+
+contract CCIPConfig_ConfigStateMachine is CCIPConfigSetup {
+ // Successful cases.
+
+ function test__stateFromConfigLength_Success() public {
+ uint256 configLen = 0;
+ CCIPConfigTypes.ConfigState state = s_ccipCC.stateFromConfigLength(configLen);
+ assertEq(uint256(state), uint256(CCIPConfigTypes.ConfigState.Init));
+
+ configLen = 1;
+ state = s_ccipCC.stateFromConfigLength(configLen);
+ assertEq(uint256(state), uint256(CCIPConfigTypes.ConfigState.Running));
+
+ configLen = 2;
+ state = s_ccipCC.stateFromConfigLength(configLen);
+ assertEq(uint256(state), uint256(CCIPConfigTypes.ConfigState.Staging));
+ }
+
+ function test__validateConfigStateTransition_Success() public {
+ s_ccipCC.validateConfigStateTransition(CCIPConfigTypes.ConfigState.Init, CCIPConfigTypes.ConfigState.Running);
+
+ s_ccipCC.validateConfigStateTransition(CCIPConfigTypes.ConfigState.Running, CCIPConfigTypes.ConfigState.Staging);
+
+ s_ccipCC.validateConfigStateTransition(CCIPConfigTypes.ConfigState.Staging, CCIPConfigTypes.ConfigState.Running);
+ }
+
+ function test__computeConfigDigest_Success() public {
+ // config digest must change upon:
+ // - ocr config change (e.g plugin type, chain selector, etc.)
+ // - don id change
+ // - config count change
+ bytes32[] memory p2pIds = _makeBytes32Array(4, 0);
+ bytes[] memory signers = _makeBytesArray(2, 10);
+ bytes[] memory transmitters = _makeBytesArray(2, 20);
+ CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("offchainConfig")
+ });
+ uint32 donId = 1;
+ uint32 configCount = 1;
+
+ bytes32 configDigest1 = s_ccipCC.computeConfigDigest(donId, configCount, config);
+
+ donId = 2;
+ bytes32 configDigest2 = s_ccipCC.computeConfigDigest(donId, configCount, config);
+
+ donId = 1;
+ configCount = 2;
+ bytes32 configDigest3 = s_ccipCC.computeConfigDigest(donId, configCount, config);
+
+ configCount = 1;
+ config.pluginType = Internal.OCRPluginType.Execution;
+ bytes32 configDigest4 = s_ccipCC.computeConfigDigest(donId, configCount, config);
+
+ assertNotEq(configDigest1, configDigest2, "config digests 1 and 2 must not match");
+ assertNotEq(configDigest1, configDigest3, "config digests 1 and 3 must not match");
+ assertNotEq(configDigest1, configDigest4, "config digests 1 and 4 must not match");
+
+ assertNotEq(configDigest2, configDigest3, "config digests 2 and 3 must not match");
+ assertNotEq(configDigest2, configDigest4, "config digests 2 and 4 must not match");
+ }
+
+ function test_Fuzz__groupByPluginType_Success(uint256 numCommitCfgs, uint256 numExecCfgs) public {
+ numCommitCfgs = bound(numCommitCfgs, 0, 2);
+ numExecCfgs = bound(numExecCfgs, 0, 2);
+
+ bytes32[] memory p2pIds = _makeBytes32Array(4, 0);
+ bytes[] memory signers = _makeBytesArray(4, 10);
+ bytes[] memory transmitters = _makeBytesArray(4, 20);
+ CCIPConfigTypes.OCR3Config[] memory cfgs = new CCIPConfigTypes.OCR3Config[](numCommitCfgs + numExecCfgs);
+ for (uint256 i = 0; i < numCommitCfgs; i++) {
+ cfgs[i] = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: abi.encode("commit", i)
+ });
+ }
+ for (uint256 i = 0; i < numExecCfgs; i++) {
+ cfgs[numCommitCfgs + i] = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Execution,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: abi.encode("exec", numCommitCfgs + i)
+ });
+ }
+ (CCIPConfigTypes.OCR3Config[] memory commitCfgs, CCIPConfigTypes.OCR3Config[] memory execCfgs) =
+ s_ccipCC.groupByPluginType(cfgs);
+
+ assertEq(commitCfgs.length, numCommitCfgs, "commitCfgs length must match");
+ assertEq(execCfgs.length, numExecCfgs, "execCfgs length must match");
+ for (uint256 i = 0; i < commitCfgs.length; i++) {
+ assertEq(uint8(commitCfgs[i].pluginType), uint8(Internal.OCRPluginType.Commit), "plugin type must be commit");
+ assertEq(commitCfgs[i].offchainConfig, abi.encode("commit", i), "offchain config must match");
+ }
+ for (uint256 i = 0; i < execCfgs.length; i++) {
+ assertEq(uint8(execCfgs[i].pluginType), uint8(Internal.OCRPluginType.Execution), "plugin type must be execution");
+ assertEq(execCfgs[i].offchainConfig, abi.encode("exec", numCommitCfgs + i), "offchain config must match");
+ }
+ }
+
+ function test__computeNewConfigWithMeta_InitToRunning_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](0);
+ CCIPConfigTypes.OCR3Config[] memory newConfig = new CCIPConfigTypes.OCR3Config[](1);
+ newConfig[0] = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.ConfigState currentState = CCIPConfigTypes.ConfigState.Init;
+ CCIPConfigTypes.ConfigState newState = CCIPConfigTypes.ConfigState.Running;
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfigWithMeta =
+ s_ccipCC.computeNewConfigWithMeta(donId, currentConfig, newConfig, currentState, newState);
+ assertEq(newConfigWithMeta.length, 1, "new config with meta length must be 1");
+ assertEq(newConfigWithMeta[0].configCount, uint64(1), "config count must be 1");
+ assertEq(uint8(newConfigWithMeta[0].config.pluginType), uint8(newConfig[0].pluginType), "plugin type must match");
+ assertEq(newConfigWithMeta[0].config.offchainConfig, newConfig[0].offchainConfig, "offchain config must match");
+ assertEq(
+ newConfigWithMeta[0].configDigest,
+ s_ccipCC.computeConfigDigest(donId, 1, newConfig[0]),
+ "config digest must match"
+ );
+
+ // This ensures that the test case is using correct inputs.
+ s_ccipCC.validateConfigTransition(currentConfig, newConfigWithMeta);
+ }
+
+ function test__computeNewConfigWithMeta_RunningToStaging_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ currentConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+
+ CCIPConfigTypes.OCR3Config[] memory newConfig = new CCIPConfigTypes.OCR3Config[](2);
+ // existing blue config first.
+ newConfig[0] = blueConfig;
+ // green config next.
+ newConfig[1] = greenConfig;
+
+ CCIPConfigTypes.ConfigState currentState = CCIPConfigTypes.ConfigState.Running;
+ CCIPConfigTypes.ConfigState newState = CCIPConfigTypes.ConfigState.Staging;
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfigWithMeta =
+ s_ccipCC.computeNewConfigWithMeta(donId, currentConfig, newConfig, currentState, newState);
+ assertEq(newConfigWithMeta.length, 2, "new config with meta length must be 2");
+
+ assertEq(newConfigWithMeta[0].configCount, uint64(1), "config count of blue must be 1");
+ assertEq(
+ uint8(newConfigWithMeta[0].config.pluginType), uint8(blueConfig.pluginType), "plugin type of blue must match"
+ );
+ assertEq(
+ newConfigWithMeta[0].config.offchainConfig, blueConfig.offchainConfig, "offchain config of blue must match"
+ );
+ assertEq(
+ newConfigWithMeta[0].configDigest,
+ s_ccipCC.computeConfigDigest(donId, 1, blueConfig),
+ "config digest of blue must match"
+ );
+
+ assertEq(newConfigWithMeta[1].configCount, uint64(2), "config count of green must be 2");
+ assertEq(
+ uint8(newConfigWithMeta[1].config.pluginType), uint8(greenConfig.pluginType), "plugin type of green must match"
+ );
+ assertEq(
+ newConfigWithMeta[1].config.offchainConfig, greenConfig.offchainConfig, "offchain config of green must match"
+ );
+ assertEq(
+ newConfigWithMeta[1].configDigest,
+ s_ccipCC.computeConfigDigest(donId, 2, greenConfig),
+ "config digest of green must match"
+ );
+
+ // This ensures that the test case is using correct inputs.
+ s_ccipCC.validateConfigTransition(currentConfig, newConfigWithMeta);
+ }
+
+ function test__computeNewConfigWithMeta_StagingToRunning_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](2);
+ currentConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+ currentConfig[1] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 2,
+ config: greenConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 2, greenConfig)
+ });
+ CCIPConfigTypes.OCR3Config[] memory newConfig = new CCIPConfigTypes.OCR3Config[](1);
+ newConfig[0] = greenConfig;
+
+ CCIPConfigTypes.ConfigState currentState = CCIPConfigTypes.ConfigState.Staging;
+ CCIPConfigTypes.ConfigState newState = CCIPConfigTypes.ConfigState.Running;
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfigWithMeta =
+ s_ccipCC.computeNewConfigWithMeta(donId, currentConfig, newConfig, currentState, newState);
+
+ assertEq(newConfigWithMeta.length, 1, "new config with meta length must be 1");
+ assertEq(newConfigWithMeta[0].configCount, uint64(2), "config count must be 2");
+ assertEq(uint8(newConfigWithMeta[0].config.pluginType), uint8(greenConfig.pluginType), "plugin type must match");
+ assertEq(newConfigWithMeta[0].config.offchainConfig, greenConfig.offchainConfig, "offchain config must match");
+ assertEq(
+ newConfigWithMeta[0].configDigest, s_ccipCC.computeConfigDigest(donId, 2, greenConfig), "config digest must match"
+ );
+
+ // This ensures that the test case is using correct inputs.
+ s_ccipCC.validateConfigTransition(currentConfig, newConfigWithMeta);
+ }
+
+ function test__validateConfigTransition_InitToRunning_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ newConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](0);
+
+ s_ccipCC.validateConfigTransition(currentConfig, newConfig);
+ }
+
+ function test__validateConfigTransition_RunningToStaging_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](2);
+ newConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+ newConfig[1] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 2,
+ config: greenConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 2, greenConfig)
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ currentConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+
+ s_ccipCC.validateConfigTransition(currentConfig, newConfig);
+ }
+
+ function test__validateConfigTransition_StagingToRunning_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](2);
+ currentConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+ currentConfig[1] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 2,
+ config: greenConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 2, greenConfig)
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ newConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 2,
+ config: greenConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 2, greenConfig)
+ });
+
+ s_ccipCC.validateConfigTransition(currentConfig, newConfig);
+ }
+
+ // Reverts.
+
+ function test_Fuzz__stateFromConfigLength_Reverts(uint256 configLen) public {
+ vm.assume(configLen > 2);
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.InvalidConfigLength.selector, configLen));
+ s_ccipCC.stateFromConfigLength(configLen);
+ }
+
+ function test__groupByPluginType_threeCommitConfigs_Reverts() public {
+ bytes32[] memory p2pIds = _makeBytes32Array(4, 0);
+ bytes[] memory signers = _makeBytesArray(4, 10);
+ bytes[] memory transmitters = _makeBytesArray(4, 20);
+ CCIPConfigTypes.OCR3Config[] memory cfgs = new CCIPConfigTypes.OCR3Config[](3);
+ for (uint256 i = 0; i < 3; i++) {
+ cfgs[i] = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: abi.encode("commit", i)
+ });
+ }
+ vm.expectRevert();
+ s_ccipCC.groupByPluginType(cfgs);
+ }
+
+ function test__groupByPluginType_threeExecutionConfigs_Reverts() public {
+ bytes32[] memory p2pIds = _makeBytes32Array(4, 0);
+ bytes[] memory signers = _makeBytesArray(4, 10);
+ bytes[] memory transmitters = _makeBytesArray(4, 20);
+ CCIPConfigTypes.OCR3Config[] memory cfgs = new CCIPConfigTypes.OCR3Config[](3);
+ for (uint256 i = 0; i < 3; i++) {
+ cfgs[i] = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Execution,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: abi.encode("exec", i)
+ });
+ }
+ vm.expectRevert();
+ s_ccipCC.groupByPluginType(cfgs);
+ }
+
+ function test__groupByPluginType_TooManyOCR3Configs_Reverts() public {
+ CCIPConfigTypes.OCR3Config[] memory cfgs = new CCIPConfigTypes.OCR3Config[](5);
+ vm.expectRevert(CCIPConfig.TooManyOCR3Configs.selector);
+ s_ccipCC.groupByPluginType(cfgs);
+ }
+
+ function test__validateConfigTransition_InitToRunning_WrongConfigCount_Reverts() public {
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(_makeBytes32Array(4, 0), 0, 1),
+ p2pIds: _makeBytes32Array(4, 0),
+ signers: _makeBytesArray(4, 10),
+ transmitters: _makeBytesArray(4, 20),
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ newConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 0,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](0);
+
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.WrongConfigCount.selector, 0, 1));
+ s_ccipCC.validateConfigTransition(currentConfig, newConfig);
+ }
+
+ function test__validateConfigTransition_RunningToStaging_WrongConfigDigestBlueGreen_Reverts() public {
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(_makeBytes32Array(4, 0), 0, 1),
+ p2pIds: _makeBytes32Array(4, 0),
+ signers: _makeBytesArray(4, 10),
+ transmitters: _makeBytesArray(4, 20),
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(_makeBytes32Array(4, 0), 0, 1),
+ p2pIds: _makeBytes32Array(4, 0),
+ signers: _makeBytesArray(4, 10),
+ transmitters: _makeBytesArray(4, 20),
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ currentConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](2);
+ newConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 3, blueConfig) // wrong config digest (due to diff config count)
+ });
+ newConfig[1] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 2,
+ config: greenConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 2, greenConfig)
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ CCIPConfig.WrongConfigDigestBlueGreen.selector,
+ s_ccipCC.computeConfigDigest(donId, 3, blueConfig),
+ s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ )
+ );
+ s_ccipCC.validateConfigTransition(currentConfig, newConfig);
+ }
+
+ function test__validateConfigTransition_RunningToStaging_WrongConfigCount_Reverts() public {
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(_makeBytes32Array(4, 0), 0, 1),
+ p2pIds: _makeBytes32Array(4, 0),
+ signers: _makeBytesArray(4, 10),
+ transmitters: _makeBytesArray(4, 20),
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(_makeBytes32Array(4, 0), 0, 1),
+ p2pIds: _makeBytes32Array(4, 0),
+ signers: _makeBytesArray(4, 10),
+ transmitters: _makeBytesArray(4, 20),
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ currentConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](2);
+ newConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+ newConfig[1] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 3, // wrong config count
+ config: greenConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 3, greenConfig)
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.WrongConfigCount.selector, 3, 2));
+ s_ccipCC.validateConfigTransition(currentConfig, newConfig);
+ }
+
+ function test__validateConfigTransition_StagingToRunning_WrongConfigDigest_Reverts() public {
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(_makeBytes32Array(4, 0), 0, 1),
+ p2pIds: _makeBytes32Array(4, 0),
+ signers: _makeBytesArray(4, 10),
+ transmitters: _makeBytesArray(4, 20),
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(_makeBytes32Array(4, 0), 0, 1),
+ p2pIds: _makeBytes32Array(4, 0),
+ signers: _makeBytesArray(4, 10),
+ transmitters: _makeBytesArray(4, 20),
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](2);
+ currentConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 1,
+ config: blueConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 1, blueConfig)
+ });
+ currentConfig[1] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 2,
+ config: greenConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 2, greenConfig)
+ });
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ newConfig[0] = CCIPConfigTypes.OCR3ConfigWithMeta({
+ configCount: 2,
+ config: greenConfig,
+ configDigest: s_ccipCC.computeConfigDigest(donId, 3, greenConfig) // wrong config digest
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ CCIPConfig.WrongConfigDigest.selector,
+ s_ccipCC.computeConfigDigest(donId, 3, greenConfig),
+ s_ccipCC.computeConfigDigest(donId, 2, greenConfig)
+ )
+ );
+ s_ccipCC.validateConfigTransition(currentConfig, newConfig);
+ }
+
+ function test__validateConfigTransition_NonExistentConfigTransition_Reverts() public {
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](3);
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfig = new CCIPConfigTypes.OCR3ConfigWithMeta[](1);
+ vm.expectRevert(CCIPConfig.NonExistentConfigTransition.selector);
+ s_ccipCC.validateConfigTransition(currentConfig, newConfig);
+ }
+}
+
+contract CCIPConfig__updatePluginConfig is CCIPConfigSetup {
+ // Successes.
+
+ function test__updatePluginConfig_InitToRunning_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config[] memory configs = new CCIPConfigTypes.OCR3Config[](1);
+ configs[0] = blueConfig;
+
+ s_ccipCC.updatePluginConfig(donId, Internal.OCRPluginType.Commit, configs);
+
+ // should see the updated config in the contract state.
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory storedConfig =
+ s_ccipCC.getOCRConfig(donId, Internal.OCRPluginType.Commit);
+ assertEq(storedConfig.length, 1, "don config length must be 1");
+ assertEq(storedConfig[0].configCount, uint64(1), "config count must be 1");
+ assertEq(uint256(storedConfig[0].config.pluginType), uint256(blueConfig.pluginType), "plugin type must match");
+ }
+
+ function test__updatePluginConfig_RunningToStaging_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ // add blue config.
+ uint32 donId = 1;
+ Internal.OCRPluginType pluginType = Internal.OCRPluginType.Commit;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config[] memory startConfigs = new CCIPConfigTypes.OCR3Config[](1);
+ startConfigs[0] = blueConfig;
+
+ // add blue AND green config to indicate an update.
+ s_ccipCC.updatePluginConfig(donId, Internal.OCRPluginType.Commit, startConfigs);
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+ CCIPConfigTypes.OCR3Config[] memory blueAndGreen = new CCIPConfigTypes.OCR3Config[](2);
+ blueAndGreen[0] = blueConfig;
+ blueAndGreen[1] = greenConfig;
+
+ s_ccipCC.updatePluginConfig(donId, Internal.OCRPluginType.Commit, blueAndGreen);
+
+ // should see the updated config in the contract state.
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory storedConfig =
+ s_ccipCC.getOCRConfig(donId, Internal.OCRPluginType.Commit);
+ assertEq(storedConfig.length, 2, "don config length must be 2");
+ // 0 index is blue config, 1 index is green config.
+ assertEq(storedConfig[1].configCount, uint64(2), "config count must be 2");
+ assertEq(
+ uint256(storedConfig[0].config.pluginType), uint256(Internal.OCRPluginType.Commit), "plugin type must match"
+ );
+ assertEq(
+ uint256(storedConfig[1].config.pluginType), uint256(Internal.OCRPluginType.Commit), "plugin type must match"
+ );
+ assertEq(storedConfig[0].config.offchainConfig, bytes("commit"), "blue offchain config must match");
+ assertEq(storedConfig[1].config.offchainConfig, bytes("commit-new"), "green offchain config must match");
+ }
+
+ function test__updatePluginConfig_StagingToRunning_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ // add blue config.
+ uint32 donId = 1;
+ Internal.OCRPluginType pluginType = Internal.OCRPluginType.Commit;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config[] memory startConfigs = new CCIPConfigTypes.OCR3Config[](1);
+ startConfigs[0] = blueConfig;
+
+ // add blue AND green config to indicate an update.
+ s_ccipCC.updatePluginConfig(donId, Internal.OCRPluginType.Commit, startConfigs);
+ CCIPConfigTypes.OCR3Config memory greenConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit-new")
+ });
+ CCIPConfigTypes.OCR3Config[] memory blueAndGreen = new CCIPConfigTypes.OCR3Config[](2);
+ blueAndGreen[0] = blueConfig;
+ blueAndGreen[1] = greenConfig;
+
+ s_ccipCC.updatePluginConfig(donId, Internal.OCRPluginType.Commit, blueAndGreen);
+
+ // should see the updated config in the contract state.
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory storedConfig =
+ s_ccipCC.getOCRConfig(donId, Internal.OCRPluginType.Commit);
+ assertEq(storedConfig.length, 2, "don config length must be 2");
+ // 0 index is blue config, 1 index is green config.
+ assertEq(storedConfig[1].configCount, uint64(2), "config count must be 2");
+ assertEq(
+ uint256(storedConfig[0].config.pluginType), uint256(Internal.OCRPluginType.Commit), "plugin type must match"
+ );
+ assertEq(
+ uint256(storedConfig[1].config.pluginType), uint256(Internal.OCRPluginType.Commit), "plugin type must match"
+ );
+ assertEq(storedConfig[0].config.offchainConfig, bytes("commit"), "blue offchain config must match");
+ assertEq(storedConfig[1].config.offchainConfig, bytes("commit-new"), "green offchain config must match");
+
+ // promote green to blue.
+ CCIPConfigTypes.OCR3Config[] memory promote = new CCIPConfigTypes.OCR3Config[](1);
+ promote[0] = greenConfig;
+
+ s_ccipCC.updatePluginConfig(donId, Internal.OCRPluginType.Commit, promote);
+
+ // should see the updated config in the contract state.
+ storedConfig = s_ccipCC.getOCRConfig(donId, Internal.OCRPluginType.Commit);
+ assertEq(storedConfig.length, 1, "don config length must be 1");
+ assertEq(storedConfig[0].configCount, uint64(2), "config count must be 2");
+ assertEq(
+ uint256(storedConfig[0].config.pluginType), uint256(Internal.OCRPluginType.Commit), "plugin type must match"
+ );
+ assertEq(storedConfig[0].config.offchainConfig, bytes("commit-new"), "green offchain config must match");
+ }
+
+ // Reverts.
+ function test__updatePluginConfig_InvalidConfigLength_Reverts() public {
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config[] memory newConfig = new CCIPConfigTypes.OCR3Config[](3);
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.InvalidConfigLength.selector, uint256(3)));
+ s_ccipCC.updatePluginConfig(donId, Internal.OCRPluginType.Commit, newConfig);
+ }
+
+ function test__updatePluginConfig_InvalidConfigStateTransition_Reverts() public {
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config[] memory newConfig = new CCIPConfigTypes.OCR3Config[](2);
+ // 0 -> 2 is an invalid state transition.
+ vm.expectRevert(abi.encodeWithSelector(CCIPConfig.InvalidConfigStateTransition.selector, 0, 2));
+ s_ccipCC.updatePluginConfig(donId, Internal.OCRPluginType.Commit, newConfig);
+ }
+}
+
+contract CCIPConfig_beforeCapabilityConfigSet is CCIPConfigSetup {
+ // Successes.
+ function test_beforeCapabilityConfigSet_ZeroLengthConfig_Success() public {
+ changePrank(CAPABILITIES_REGISTRY);
+
+ CCIPConfigTypes.OCR3Config[] memory configs = new CCIPConfigTypes.OCR3Config[](0);
+ bytes memory encodedConfigs = abi.encode(configs);
+ s_ccipCC.beforeCapabilityConfigSet(new bytes32[](0), encodedConfigs, 1, 1);
+ }
+
+ function test_beforeCapabilityConfigSet_CommitConfigOnly_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ changePrank(CAPABILITIES_REGISTRY);
+
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config[] memory configs = new CCIPConfigTypes.OCR3Config[](1);
+ configs[0] = blueConfig;
+
+ bytes memory encoded = abi.encode(configs);
+ s_ccipCC.beforeCapabilityConfigSet(new bytes32[](0), encoded, 1, donId);
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory storedConfigs =
+ s_ccipCC.getOCRConfig(donId, Internal.OCRPluginType.Commit);
+ assertEq(storedConfigs.length, 1, "config length must be 1");
+ assertEq(storedConfigs[0].configCount, uint64(1), "config count must be 1");
+ assertEq(
+ uint256(storedConfigs[0].config.pluginType), uint256(Internal.OCRPluginType.Commit), "plugin type must be commit"
+ );
+ }
+
+ function test_beforeCapabilityConfigSet_ExecConfigOnly_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ changePrank(CAPABILITIES_REGISTRY);
+
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Execution,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("exec")
+ });
+ CCIPConfigTypes.OCR3Config[] memory configs = new CCIPConfigTypes.OCR3Config[](1);
+ configs[0] = blueConfig;
+
+ bytes memory encoded = abi.encode(configs);
+ s_ccipCC.beforeCapabilityConfigSet(new bytes32[](0), encoded, 1, donId);
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory storedConfigs =
+ s_ccipCC.getOCRConfig(donId, Internal.OCRPluginType.Execution);
+ assertEq(storedConfigs.length, 1, "config length must be 1");
+ assertEq(storedConfigs[0].configCount, uint64(1), "config count must be 1");
+ assertEq(
+ uint256(storedConfigs[0].config.pluginType),
+ uint256(Internal.OCRPluginType.Execution),
+ "plugin type must be execution"
+ );
+ }
+
+ function test_beforeCapabilityConfigSet_CommitAndExecConfig_Success() public {
+ (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
+ changePrank(CAPABILITIES_REGISTRY);
+
+ uint32 donId = 1;
+ CCIPConfigTypes.OCR3Config memory blueCommitConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Commit,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("commit")
+ });
+ CCIPConfigTypes.OCR3Config memory blueExecConfig = CCIPConfigTypes.OCR3Config({
+ pluginType: Internal.OCRPluginType.Execution,
+ offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
+ chainSelector: 1,
+ bootstrapP2PIds: _subset(p2pIds, 0, 1),
+ p2pIds: p2pIds,
+ signers: signers,
+ transmitters: transmitters,
+ F: 1,
+ offchainConfigVersion: 30,
+ offchainConfig: bytes("exec")
+ });
+ CCIPConfigTypes.OCR3Config[] memory configs = new CCIPConfigTypes.OCR3Config[](2);
+ configs[0] = blueExecConfig;
+ configs[1] = blueCommitConfig;
+
+ bytes memory encoded = abi.encode(configs);
+ s_ccipCC.beforeCapabilityConfigSet(new bytes32[](0), encoded, 1, donId);
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory storedExecConfigs =
+ s_ccipCC.getOCRConfig(donId, Internal.OCRPluginType.Execution);
+ assertEq(storedExecConfigs.length, 1, "config length must be 1");
+ assertEq(storedExecConfigs[0].configCount, uint64(1), "config count must be 1");
+ assertEq(
+ uint256(storedExecConfigs[0].config.pluginType),
+ uint256(Internal.OCRPluginType.Execution),
+ "plugin type must be execution"
+ );
+
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory storedCommitConfigs =
+ s_ccipCC.getOCRConfig(donId, Internal.OCRPluginType.Commit);
+ assertEq(storedCommitConfigs.length, 1, "config length must be 1");
+ assertEq(storedCommitConfigs[0].configCount, uint64(1), "config count must be 1");
+ assertEq(
+ uint256(storedCommitConfigs[0].config.pluginType),
+ uint256(Internal.OCRPluginType.Commit),
+ "plugin type must be commit"
+ );
+ }
+
+ // Reverts.
+
+ function test_beforeCapabilityConfigSet_OnlyCapabilitiesRegistryCanCall_Reverts() public {
+ bytes32[] memory nodes = new bytes32[](0);
+ bytes memory config = bytes("");
+ uint64 configCount = 1;
+ uint32 donId = 1;
+ vm.expectRevert(CCIPConfig.OnlyCapabilitiesRegistryCanCall.selector);
+ s_ccipCC.beforeCapabilityConfigSet(nodes, config, configCount, donId);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/commitStore/CommitStore.t.sol b/contracts/src/v0.8/ccip/test/commitStore/CommitStore.t.sol
new file mode 100644
index 00000000000..7598f9ccb69
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/commitStore/CommitStore.t.sol
@@ -0,0 +1,618 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPriceRegistry} from "../../interfaces/IPriceRegistry.sol";
+import {IRMN} from "../../interfaces/IRMN.sol";
+
+import {AuthorizedCallers} from "../../../shared/access/AuthorizedCallers.sol";
+import {CommitStore} from "../../CommitStore.sol";
+import {PriceRegistry} from "../../PriceRegistry.sol";
+import {RMN} from "../../RMN.sol";
+import {MerkleMultiProof} from "../../libraries/MerkleMultiProof.sol";
+import {OCR2Abstract} from "../../ocr/OCR2Abstract.sol";
+import {CommitStoreHelper} from "../helpers/CommitStoreHelper.sol";
+import {OCR2BaseSetup} from "../ocr/OCR2Base.t.sol";
+import {PriceRegistrySetup} from "../priceRegistry/PriceRegistry.t.sol";
+
+contract CommitStoreSetup is PriceRegistrySetup, OCR2BaseSetup {
+ CommitStoreHelper internal s_commitStore;
+
+ function setUp() public virtual override(PriceRegistrySetup, OCR2BaseSetup) {
+ PriceRegistrySetup.setUp();
+ OCR2BaseSetup.setUp();
+
+ s_commitStore = new CommitStoreHelper(
+ CommitStore.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ onRamp: ON_RAMP_ADDRESS,
+ rmnProxy: address(s_mockRMN)
+ })
+ );
+ CommitStore.DynamicConfig memory dynamicConfig =
+ CommitStore.DynamicConfig({priceRegistry: address(s_priceRegistry)});
+ s_commitStore.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+
+ address[] memory priceUpdaters = new address[](1);
+ priceUpdaters[0] = address(s_commitStore);
+ s_priceRegistry.applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: priceUpdaters, removedCallers: new address[](0)})
+ );
+ }
+}
+
+contract CommitStoreRealRMNSetup is PriceRegistrySetup, OCR2BaseSetup {
+ CommitStoreHelper internal s_commitStore;
+
+ RMN internal s_rmn;
+
+ address internal constant BLESS_VOTE_ADDR = address(8888);
+
+ function setUp() public virtual override(PriceRegistrySetup, OCR2BaseSetup) {
+ PriceRegistrySetup.setUp();
+ OCR2BaseSetup.setUp();
+
+ RMN.Voter[] memory voters = new RMN.Voter[](1);
+ voters[0] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTE_ADDR, curseVoteAddr: address(9999), blessWeight: 1, curseWeight: 1});
+ // Overwrite base mock rmn with real.
+ s_rmn = new RMN(RMN.Config({voters: voters, blessWeightThreshold: 1, curseWeightThreshold: 1}));
+ s_commitStore = new CommitStoreHelper(
+ CommitStore.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ onRamp: ON_RAMP_ADDRESS,
+ rmnProxy: address(s_rmn)
+ })
+ );
+ CommitStore.DynamicConfig memory dynamicConfig =
+ CommitStore.DynamicConfig({priceRegistry: address(s_priceRegistry)});
+ s_commitStore.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+ }
+}
+
+contract CommitStore_constructor is PriceRegistrySetup, OCR2BaseSetup {
+ function setUp() public virtual override(PriceRegistrySetup, OCR2BaseSetup) {
+ PriceRegistrySetup.setUp();
+ OCR2BaseSetup.setUp();
+ }
+
+ function test_Constructor_Success() public {
+ CommitStore.StaticConfig memory staticConfig = CommitStore.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ onRamp: 0x2C44CDDdB6a900Fa2B585dd299E03D12Fa4293Bc,
+ rmnProxy: address(s_mockRMN)
+ });
+ CommitStore.DynamicConfig memory dynamicConfig =
+ CommitStore.DynamicConfig({priceRegistry: address(s_priceRegistry)});
+
+ vm.expectEmit();
+ emit CommitStore.ConfigSet(staticConfig, dynamicConfig);
+
+ CommitStore commitStore = new CommitStore(staticConfig);
+ commitStore.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+
+ CommitStore.StaticConfig memory gotStaticConfig = commitStore.getStaticConfig();
+
+ assertEq(staticConfig.chainSelector, gotStaticConfig.chainSelector);
+ assertEq(staticConfig.sourceChainSelector, gotStaticConfig.sourceChainSelector);
+ assertEq(staticConfig.onRamp, gotStaticConfig.onRamp);
+ assertEq(staticConfig.rmnProxy, gotStaticConfig.rmnProxy);
+
+ CommitStore.DynamicConfig memory gotDynamicConfig = commitStore.getDynamicConfig();
+
+ assertEq(dynamicConfig.priceRegistry, gotDynamicConfig.priceRegistry);
+
+ // CommitStore initial values
+ assertEq(0, commitStore.getLatestPriceEpochAndRound());
+ assertEq(1, commitStore.getExpectedNextSequenceNumber());
+ assertEq(commitStore.typeAndVersion(), "CommitStore 1.5.0-dev");
+ assertEq(OWNER, commitStore.owner());
+ assertTrue(commitStore.isUnpausedAndNotCursed());
+ }
+}
+
+contract CommitStore_setMinSeqNr is CommitStoreSetup {
+ function test_Fuzz_SetMinSeqNr_Success(uint64 minSeqNr) public {
+ vm.expectEmit();
+ emit CommitStore.SequenceNumberSet(s_commitStore.getExpectedNextSequenceNumber(), minSeqNr);
+
+ s_commitStore.setMinSeqNr(minSeqNr);
+
+ assertEq(s_commitStore.getExpectedNextSequenceNumber(), minSeqNr);
+ }
+
+ // Reverts
+ function test_OnlyOwner_Revert() public {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ s_commitStore.setMinSeqNr(6723);
+ }
+}
+
+contract CommitStore_setDynamicConfig is CommitStoreSetup {
+ function test_Fuzz_SetDynamicConfig_Success(address priceRegistry) public {
+ vm.assume(priceRegistry != address(0));
+ CommitStore.StaticConfig memory staticConfig = s_commitStore.getStaticConfig();
+ CommitStore.DynamicConfig memory dynamicConfig = CommitStore.DynamicConfig({priceRegistry: priceRegistry});
+ bytes memory onchainConfig = abi.encode(dynamicConfig);
+
+ vm.expectEmit();
+ emit CommitStore.ConfigSet(staticConfig, dynamicConfig);
+
+ uint32 configCount = 1;
+
+ vm.expectEmit();
+ emit OCR2Abstract.ConfigSet(
+ uint32(block.number),
+ getBasicConfigDigest(address(s_commitStore), s_f, configCount, onchainConfig),
+ configCount + 1,
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ onchainConfig,
+ s_offchainConfigVersion,
+ abi.encode("")
+ );
+
+ s_commitStore.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, onchainConfig, s_offchainConfigVersion, abi.encode("")
+ );
+
+ CommitStore.DynamicConfig memory gotDynamicConfig = s_commitStore.getDynamicConfig();
+ assertEq(gotDynamicConfig.priceRegistry, dynamicConfig.priceRegistry);
+ }
+
+ function test_PriceEpochCleared_Success() public {
+ // Set latest price epoch and round to non-zero.
+ uint40 latestEpochAndRound = 1782155;
+ s_commitStore.setLatestPriceEpochAndRound(latestEpochAndRound);
+ assertEq(latestEpochAndRound, s_commitStore.getLatestPriceEpochAndRound());
+
+ CommitStore.DynamicConfig memory dynamicConfig = CommitStore.DynamicConfig({priceRegistry: address(1)});
+ // New config should clear it.
+ s_commitStore.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+ // Assert cleared.
+ assertEq(0, s_commitStore.getLatestPriceEpochAndRound());
+ }
+
+ // Reverts
+ function test_OnlyOwner_Revert() public {
+ CommitStore.DynamicConfig memory dynamicConfig = CommitStore.DynamicConfig({priceRegistry: address(23784264)});
+
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ s_commitStore.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+ }
+
+ function test_InvalidCommitStoreConfig_Revert() public {
+ CommitStore.DynamicConfig memory dynamicConfig = CommitStore.DynamicConfig({priceRegistry: address(0)});
+
+ vm.expectRevert(CommitStore.InvalidCommitStoreConfig.selector);
+ s_commitStore.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+ }
+}
+
+contract CommitStore_resetUnblessedRoots is CommitStoreRealRMNSetup {
+ function test_ResetUnblessedRoots_Success() public {
+ bytes32[] memory rootsToReset = new bytes32[](3);
+ rootsToReset[0] = "1";
+ rootsToReset[1] = "2";
+ rootsToReset[2] = "3";
+
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(1, 2),
+ merkleRoot: rootsToReset[0]
+ });
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+
+ report = CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(3, 4),
+ merkleRoot: rootsToReset[1]
+ });
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+
+ report = CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(5, 5),
+ merkleRoot: rootsToReset[2]
+ });
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+
+ IRMN.TaggedRoot[] memory blessedTaggedRoots = new IRMN.TaggedRoot[](1);
+ blessedTaggedRoots[0] = IRMN.TaggedRoot({commitStore: address(s_commitStore), root: rootsToReset[1]});
+
+ vm.startPrank(BLESS_VOTE_ADDR);
+ s_rmn.voteToBless(blessedTaggedRoots);
+
+ vm.expectEmit(false, false, false, true);
+ emit CommitStore.RootRemoved(rootsToReset[0]);
+
+ vm.expectEmit(false, false, false, true);
+ emit CommitStore.RootRemoved(rootsToReset[2]);
+
+ vm.startPrank(OWNER);
+ s_commitStore.resetUnblessedRoots(rootsToReset);
+
+ assertEq(0, s_commitStore.getMerkleRoot(rootsToReset[0]));
+ assertEq(BLOCK_TIME, s_commitStore.getMerkleRoot(rootsToReset[1]));
+ assertEq(0, s_commitStore.getMerkleRoot(rootsToReset[2]));
+ }
+
+ // Reverts
+
+ function test_OnlyOwner_Revert() public {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ bytes32[] memory rootToReset;
+ s_commitStore.resetUnblessedRoots(rootToReset);
+ }
+}
+
+contract CommitStore_report is CommitStoreSetup {
+ function test_ReportOnlyRootSuccess_gas() public {
+ vm.pauseGasMetering();
+ uint64 max1 = 931;
+ bytes32 root = "Only a single root";
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(1, max1),
+ merkleRoot: root
+ });
+
+ vm.expectEmit();
+ emit CommitStore.ReportAccepted(report);
+
+ bytes memory encodedReport = abi.encode(report);
+
+ vm.resumeGasMetering();
+ s_commitStore.report(encodedReport, ++s_latestEpochAndRound);
+ vm.pauseGasMetering();
+
+ assertEq(max1 + 1, s_commitStore.getExpectedNextSequenceNumber());
+ assertEq(block.timestamp, s_commitStore.getMerkleRoot(root));
+ vm.resumeGasMetering();
+ }
+
+ function test_ReportAndPriceUpdate_Success() public {
+ uint64 max1 = 12;
+
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ interval: CommitStore.Interval(1, max1),
+ merkleRoot: "test #2"
+ });
+
+ vm.expectEmit();
+ emit CommitStore.ReportAccepted(report);
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+
+ assertEq(max1 + 1, s_commitStore.getExpectedNextSequenceNumber());
+ assertEq(s_latestEpochAndRound, s_commitStore.getLatestPriceEpochAndRound());
+ }
+
+ function test_StaleReportWithRoot_Success() public {
+ uint64 maxSeq = 12;
+ uint224 tokenStartPrice =
+ IPriceRegistry(s_commitStore.getDynamicConfig().priceRegistry).getTokenPrice(s_sourceFeeToken).value;
+
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ interval: CommitStore.Interval(1, maxSeq),
+ merkleRoot: "stale report 1"
+ });
+
+ vm.expectEmit();
+ emit CommitStore.ReportAccepted(report);
+
+ s_commitStore.report(abi.encode(report), s_latestEpochAndRound);
+ assertEq(maxSeq + 1, s_commitStore.getExpectedNextSequenceNumber());
+ assertEq(s_latestEpochAndRound, s_commitStore.getLatestPriceEpochAndRound());
+
+ report = CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(maxSeq + 1, maxSeq * 2),
+ merkleRoot: "stale report 2"
+ });
+
+ vm.expectEmit();
+ emit CommitStore.ReportAccepted(report);
+
+ s_commitStore.report(abi.encode(report), s_latestEpochAndRound);
+ assertEq(maxSeq * 2 + 1, s_commitStore.getExpectedNextSequenceNumber());
+ assertEq(s_latestEpochAndRound, s_commitStore.getLatestPriceEpochAndRound());
+ assertEq(
+ tokenStartPrice,
+ IPriceRegistry(s_commitStore.getDynamicConfig().priceRegistry).getTokenPrice(s_sourceFeeToken).value
+ );
+ }
+
+ function test_OnlyTokenPriceUpdates_Success() public {
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ interval: CommitStore.Interval(0, 0),
+ merkleRoot: ""
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, 4e18, block.timestamp);
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+ assertEq(s_latestEpochAndRound, s_commitStore.getLatestPriceEpochAndRound());
+ }
+
+ function test_OnlyGasPriceUpdates_Success() public {
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ interval: CommitStore.Interval(0, 0),
+ merkleRoot: ""
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, 4e18, block.timestamp);
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+ assertEq(s_latestEpochAndRound, s_commitStore.getLatestPriceEpochAndRound());
+ }
+
+ function test_ValidPriceUpdateThenStaleReportWithRoot_Success() public {
+ uint64 maxSeq = 12;
+ uint224 tokenPrice1 = 4e18;
+ uint224 tokenPrice2 = 5e18;
+
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, tokenPrice1),
+ interval: CommitStore.Interval(0, 0),
+ merkleRoot: ""
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, tokenPrice1, block.timestamp);
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+ assertEq(s_latestEpochAndRound, s_commitStore.getLatestPriceEpochAndRound());
+
+ report = CommitStore.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, tokenPrice2),
+ interval: CommitStore.Interval(1, maxSeq),
+ merkleRoot: "stale report"
+ });
+
+ vm.expectEmit();
+ emit CommitStore.ReportAccepted(report);
+
+ s_commitStore.report(abi.encode(report), s_latestEpochAndRound);
+
+ assertEq(maxSeq + 1, s_commitStore.getExpectedNextSequenceNumber());
+ assertEq(
+ tokenPrice1, IPriceRegistry(s_commitStore.getDynamicConfig().priceRegistry).getTokenPrice(s_sourceFeeToken).value
+ );
+ assertEq(s_latestEpochAndRound, s_commitStore.getLatestPriceEpochAndRound());
+ }
+
+ // Reverts
+
+ function test_Paused_Revert() public {
+ s_commitStore.pause();
+ bytes memory report;
+ vm.expectRevert(CommitStore.PausedError.selector);
+ s_commitStore.report(report, ++s_latestEpochAndRound);
+ }
+
+ function test_Unhealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ vm.expectRevert(CommitStore.CursedByRMN.selector);
+ bytes memory report;
+ s_commitStore.report(report, ++s_latestEpochAndRound);
+ }
+
+ function test_InvalidRootRevert() public {
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(1, 4),
+ merkleRoot: bytes32(0)
+ });
+
+ vm.expectRevert(CommitStore.InvalidRoot.selector);
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+ }
+
+ function test_InvalidInterval_Revert() public {
+ CommitStore.Interval memory interval = CommitStore.Interval(2, 2);
+ CommitStore.CommitReport memory report =
+ CommitStore.CommitReport({priceUpdates: getEmptyPriceUpdates(), interval: interval, merkleRoot: bytes32(0)});
+
+ vm.expectRevert(abi.encodeWithSelector(CommitStore.InvalidInterval.selector, interval));
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+ }
+
+ function test_InvalidIntervalMinLargerThanMax_Revert() public {
+ CommitStore.Interval memory interval = CommitStore.Interval(1, 0);
+ CommitStore.CommitReport memory report =
+ CommitStore.CommitReport({priceUpdates: getEmptyPriceUpdates(), interval: interval, merkleRoot: bytes32(0)});
+
+ vm.expectRevert(abi.encodeWithSelector(CommitStore.InvalidInterval.selector, interval));
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+ }
+
+ function test_ZeroEpochAndRound_Revert() public {
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ interval: CommitStore.Interval(0, 0),
+ merkleRoot: bytes32(0)
+ });
+
+ vm.expectRevert(CommitStore.StaleReport.selector);
+
+ s_commitStore.report(abi.encode(report), 0);
+ }
+
+ function test_OnlyPriceUpdateStaleReport_Revert() public {
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ interval: CommitStore.Interval(0, 0),
+ merkleRoot: bytes32(0)
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, 4e18, block.timestamp);
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+
+ vm.expectRevert(CommitStore.StaleReport.selector);
+ s_commitStore.report(abi.encode(report), s_latestEpochAndRound);
+ }
+
+ function test_RootAlreadyCommitted_Revert() public {
+ CommitStore.CommitReport memory report = CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(1, 2),
+ merkleRoot: "Only a single root"
+ });
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+
+ report = CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(3, 3),
+ merkleRoot: "Only a single root"
+ });
+
+ vm.expectRevert(CommitStore.RootAlreadyCommitted.selector);
+
+ s_commitStore.report(abi.encode(report), ++s_latestEpochAndRound);
+ }
+}
+
+contract CommitStore_verify is CommitStoreRealRMNSetup {
+ function test_NotBlessed_Success() public {
+ bytes32[] memory leaves = new bytes32[](1);
+ leaves[0] = "root";
+ s_commitStore.report(
+ abi.encode(
+ CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(1, 2),
+ merkleRoot: leaves[0]
+ })
+ ),
+ ++s_latestEpochAndRound
+ );
+ bytes32[] memory proofs = new bytes32[](0);
+ // We have not blessed this root, should return 0.
+ uint256 timestamp = s_commitStore.verify(leaves, proofs, 0);
+ assertEq(uint256(0), timestamp);
+ }
+
+ function test_Blessed_Success() public {
+ bytes32[] memory leaves = new bytes32[](1);
+ leaves[0] = "root";
+ s_commitStore.report(
+ abi.encode(
+ CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(1, 2),
+ merkleRoot: leaves[0]
+ })
+ ),
+ ++s_latestEpochAndRound
+ );
+ // Bless that root.
+ IRMN.TaggedRoot[] memory taggedRoots = new IRMN.TaggedRoot[](1);
+ taggedRoots[0] = IRMN.TaggedRoot({commitStore: address(s_commitStore), root: leaves[0]});
+ vm.startPrank(BLESS_VOTE_ADDR);
+ s_rmn.voteToBless(taggedRoots);
+ bytes32[] memory proofs = new bytes32[](0);
+ uint256 timestamp = s_commitStore.verify(leaves, proofs, 0);
+ assertEq(BLOCK_TIME, timestamp);
+ }
+
+ // Reverts
+
+ function test_Paused_Revert() public {
+ s_commitStore.pause();
+
+ bytes32[] memory hashedLeaves = new bytes32[](0);
+ bytes32[] memory proofs = new bytes32[](0);
+ uint256 proofFlagBits = 0;
+
+ vm.expectRevert(CommitStore.PausedError.selector);
+ s_commitStore.verify(hashedLeaves, proofs, proofFlagBits);
+ }
+
+ function test_TooManyLeaves_Revert() public {
+ bytes32[] memory leaves = new bytes32[](258);
+ bytes32[] memory proofs = new bytes32[](0);
+
+ vm.expectRevert(MerkleMultiProof.InvalidProof.selector);
+
+ s_commitStore.verify(leaves, proofs, 0);
+ }
+}
+
+contract CommitStore_isUnpausedAndRMNHealthy is CommitStoreSetup {
+ function test_RMN_Success() public {
+ // Test pausing
+ assertFalse(s_commitStore.paused());
+ assertTrue(s_commitStore.isUnpausedAndNotCursed());
+ s_commitStore.pause();
+ assertTrue(s_commitStore.paused());
+ assertFalse(s_commitStore.isUnpausedAndNotCursed());
+ s_commitStore.unpause();
+ assertFalse(s_commitStore.paused());
+ assertTrue(s_commitStore.isUnpausedAndNotCursed());
+
+ // Test rmn
+ s_mockRMN.setGlobalCursed(true);
+ assertFalse(s_commitStore.isUnpausedAndNotCursed());
+ s_mockRMN.setGlobalCursed(false);
+ // TODO: also test with s_mockRMN.setChainCursed(sourceChainSelector),
+ // also for other similar tests (e.g., OffRamp, OnRamp)
+ assertTrue(s_commitStore.isUnpausedAndNotCursed());
+
+ s_mockRMN.setGlobalCursed(true);
+ s_commitStore.pause();
+ assertFalse(s_commitStore.isUnpausedAndNotCursed());
+ }
+}
+
+contract CommitStore_setLatestPriceEpochAndRound is CommitStoreSetup {
+ function test_SetLatestPriceEpochAndRound_Success() public {
+ uint40 latestRoundAndEpoch = 1782155;
+
+ vm.expectEmit();
+ emit CommitStore.LatestPriceEpochAndRoundSet(
+ uint40(s_commitStore.getLatestPriceEpochAndRound()), latestRoundAndEpoch
+ );
+
+ s_commitStore.setLatestPriceEpochAndRound(latestRoundAndEpoch);
+
+ assertEq(uint40(s_commitStore.getLatestPriceEpochAndRound()), latestRoundAndEpoch);
+ }
+
+ // Reverts
+ function test_OnlyOwner_Revert() public {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ s_commitStore.setLatestPriceEpochAndRound(6723);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/e2e/End2End.t.sol b/contracts/src/v0.8/ccip/test/e2e/End2End.t.sol
new file mode 100644
index 00000000000..816862cbdfc
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/e2e/End2End.t.sol
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import "../commitStore/CommitStore.t.sol";
+import "../helpers/MerkleHelper.sol";
+import "../offRamp/EVM2EVMOffRampSetup.t.sol";
+import "../onRamp/EVM2EVMOnRampSetup.t.sol";
+
+contract E2E is EVM2EVMOnRampSetup, CommitStoreSetup, EVM2EVMOffRampSetup {
+ using Internal for Internal.EVM2EVMMessage;
+
+ function setUp() public virtual override(EVM2EVMOnRampSetup, CommitStoreSetup, EVM2EVMOffRampSetup) {
+ EVM2EVMOnRampSetup.setUp();
+ CommitStoreSetup.setUp();
+ EVM2EVMOffRampSetup.setUp();
+
+ deployOffRamp(s_commitStore, s_destRouter, address(0));
+ }
+
+ function test_E2E_3MessagesSuccess_gas() public {
+ vm.pauseGasMetering();
+ IERC20 token0 = IERC20(s_sourceTokens[0]);
+ IERC20 token1 = IERC20(s_sourceTokens[1]);
+ uint256 balance0Pre = token0.balanceOf(OWNER);
+ uint256 balance1Pre = token1.balanceOf(OWNER);
+
+ Internal.EVM2EVMMessage[] memory messages = new Internal.EVM2EVMMessage[](3);
+ messages[0] = sendRequest(1);
+ messages[1] = sendRequest(2);
+ messages[2] = sendRequest(3);
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, _generateTokenMessage());
+ // Asserts that the tokens have been sent and the fee has been paid.
+ assertEq(balance0Pre - messages.length * (i_tokenAmount0 + expectedFee), token0.balanceOf(OWNER));
+ assertEq(balance1Pre - messages.length * i_tokenAmount1, token1.balanceOf(OWNER));
+
+ bytes32 metaDataHash = s_offRamp.metadataHash();
+
+ bytes32[] memory hashedMessages = new bytes32[](3);
+ hashedMessages[0] = messages[0]._hash(metaDataHash);
+ messages[0].messageId = hashedMessages[0];
+ hashedMessages[1] = messages[1]._hash(metaDataHash);
+ messages[1].messageId = hashedMessages[1];
+ hashedMessages[2] = messages[2]._hash(metaDataHash);
+ messages[2].messageId = hashedMessages[2];
+
+ bytes32[] memory merkleRoots = new bytes32[](1);
+ merkleRoots[0] = MerkleHelper.getMerkleRoot(hashedMessages);
+
+ address[] memory onRamps = new address[](1);
+ onRamps[0] = ON_RAMP_ADDRESS;
+
+ bytes memory commitReport = abi.encode(
+ CommitStore.CommitReport({
+ priceUpdates: getEmptyPriceUpdates(),
+ interval: CommitStore.Interval(messages[0].sequenceNumber, messages[2].sequenceNumber),
+ merkleRoot: merkleRoots[0]
+ })
+ );
+
+ vm.resumeGasMetering();
+ s_commitStore.report(commitReport, ++s_latestEpochAndRound);
+ vm.pauseGasMetering();
+
+ s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(s_commitStore), root: merkleRoots[0]}), true);
+
+ bytes32[] memory proofs = new bytes32[](0);
+ uint256 timestamp = s_commitStore.verify(merkleRoots, proofs, 2 ** 2 - 1);
+ assertEq(BLOCK_TIME, timestamp);
+
+ // We change the block time so when execute would e.g. use the current
+ // block time instead of the committed block time the value would be
+ // incorrect in the checks below.
+ vm.warp(BLOCK_TIME + 2000);
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[1].sequenceNumber, messages[1].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[2].sequenceNumber, messages[2].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ Internal.ExecutionReport memory execReport = _generateReportFromMessages(messages);
+ vm.resumeGasMetering();
+ s_offRamp.execute(execReport, new uint256[](0));
+ }
+
+ function sendRequest(uint64 expectedSeqNum) public returns (Internal.EVM2EVMMessage memory) {
+ Client.EVM2AnyMessage memory message = _generateTokenMessage();
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+
+ IERC20(s_sourceTokens[0]).approve(address(s_sourceRouter), i_tokenAmount0 + expectedFee);
+ IERC20(s_sourceTokens[1]).approve(address(s_sourceRouter), i_tokenAmount1);
+
+ message.receiver = abi.encode(address(s_receiver));
+ Internal.EVM2EVMMessage memory msgEvent =
+ _messageToEvent(message, expectedSeqNum, expectedSeqNum, expectedFee, OWNER);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent);
+
+ vm.resumeGasMetering();
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ vm.pauseGasMetering();
+
+ return msgEvent;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.sol b/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.sol
new file mode 100644
index 00000000000..cbe8a35dce5
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.sol
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {AuthorizedCallers} from "../../../shared/access/AuthorizedCallers.sol";
+import {NonceManager} from "../../NonceManager.sol";
+import {TokenAdminRegistry} from "../../tokenAdminRegistry/TokenAdminRegistry.sol";
+import "../helpers/MerkleHelper.sol";
+import "../offRamp/EVM2EVMMultiOffRampSetup.t.sol";
+import "../onRamp/EVM2EVMMultiOnRampSetup.t.sol";
+
+/// @notice This E2E test implements the following scenario:
+/// 1. Send multiple messages from multiple source chains to a single destination chain (2 messages from source chain 1 and 1 from
+/// source chain 2).
+/// 2. Commit multiple merkle roots (1 for each source chain).
+/// 3. Batch execute all the committed messages.
+contract MultiRampsE2E is EVM2EVMMultiOnRampSetup, EVM2EVMMultiOffRampSetup {
+ using Internal for Internal.Any2EVMRampMessage;
+
+ Router internal s_sourceRouter2;
+ EVM2EVMMultiOnRampHelper internal s_onRamp2;
+ TokenAdminRegistry internal s_tokenAdminRegistry2;
+ NonceManager internal s_nonceManager2;
+
+ bytes32 internal s_metadataHash2;
+
+ mapping(address destPool => address sourcePool) internal s_sourcePoolByDestPool;
+
+ function setUp() public virtual override(EVM2EVMMultiOnRampSetup, EVM2EVMMultiOffRampSetup) {
+ EVM2EVMMultiOnRampSetup.setUp();
+ EVM2EVMMultiOffRampSetup.setUp();
+
+ // Deploy new source router for the new source chain
+ s_sourceRouter2 = new Router(s_sourceRouter.getWrappedNative(), address(s_mockRMN));
+
+ // Deploy new TokenAdminRegistry for the new source chain
+ s_tokenAdminRegistry2 = new TokenAdminRegistry();
+
+ // Deploy new token pools and set them on the new TokenAdminRegistry
+ for (uint256 i = 0; i < s_sourceTokens.length; ++i) {
+ address token = s_sourceTokens[i];
+ address pool = address(
+ new LockReleaseTokenPool(IERC20(token), new address[](0), address(s_mockRMN), true, address(s_sourceRouter2))
+ );
+
+ s_sourcePoolByDestPool[s_destPoolBySourceToken[token]] = pool;
+
+ _setPool(
+ s_tokenAdminRegistry2, token, pool, DEST_CHAIN_SELECTOR, s_destPoolByToken[s_destTokens[i]], s_destTokens[i]
+ );
+ }
+
+ for (uint256 i = 0; i < s_destTokens.length; ++i) {
+ address token = s_destTokens[i];
+ address pool = s_destPoolByToken[token];
+
+ _setPool(
+ s_tokenAdminRegistry2, token, pool, SOURCE_CHAIN_SELECTOR + 1, s_sourcePoolByDestPool[pool], s_sourceTokens[i]
+ );
+ }
+
+ s_nonceManager2 = new NonceManager(new address[](0));
+
+ (
+ // Deploy the new source chain onramp
+ // Outsource to shared helper function with EVM2EVMMultiOnRampSetup
+ s_onRamp2,
+ s_metadataHash2
+ ) = _deployOnRamp(
+ SOURCE_CHAIN_SELECTOR + 1, address(s_sourceRouter2), address(s_nonceManager2), address(s_tokenAdminRegistry2)
+ );
+
+ address[] memory authorizedCallers = new address[](1);
+ authorizedCallers[0] = address(s_onRamp2);
+ s_nonceManager2.applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: authorizedCallers, removedCallers: new address[](0)})
+ );
+
+ // Enable destination chain on new source chain router
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: address(s_onRamp2)});
+ s_sourceRouter2.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), new Router.OffRamp[](0));
+
+ // Deploy offramp
+ _deployOffRamp(s_destRouter, s_mockRMN, s_inboundNonceManager);
+
+ // Enable source chains on offramp
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](2);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ isEnabled: true,
+ // Must match OnRamp address
+ onRamp: abi.encode(address(s_onRamp))
+ });
+ sourceChainConfigs[1] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR + 1,
+ isEnabled: true,
+ onRamp: abi.encode(address(s_onRamp2))
+ });
+
+ _setupMultipleOffRampsFromConfigs(sourceChainConfigs);
+ }
+
+ function test_E2E_3MessagesSuccess_gas() public {
+ vm.pauseGasMetering();
+ IERC20 token0 = IERC20(s_sourceTokens[0]);
+ IERC20 token1 = IERC20(s_sourceTokens[1]);
+ uint256 balance0Pre = token0.balanceOf(OWNER);
+ uint256 balance1Pre = token1.balanceOf(OWNER);
+
+ // Send messages
+ Internal.Any2EVMRampMessage[] memory messages1 = new Internal.Any2EVMRampMessage[](2);
+ messages1[0] = _sendRequest(1, SOURCE_CHAIN_SELECTOR, 1, s_metadataHash, s_sourceRouter, s_tokenAdminRegistry);
+ messages1[1] = _sendRequest(2, SOURCE_CHAIN_SELECTOR, 2, s_metadataHash, s_sourceRouter, s_tokenAdminRegistry);
+ Internal.Any2EVMRampMessage[] memory messages2 = new Internal.Any2EVMRampMessage[](1);
+ messages2[0] =
+ _sendRequest(1, SOURCE_CHAIN_SELECTOR + 1, 1, s_metadataHash2, s_sourceRouter2, s_tokenAdminRegistry2);
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, _generateTokenMessage());
+ // Asserts that the tokens have been sent and the fee has been paid.
+ assertEq(
+ balance0Pre - (messages1.length + messages2.length) * (i_tokenAmount0 + expectedFee), token0.balanceOf(OWNER)
+ );
+ assertEq(balance1Pre - (messages1.length + messages2.length) * i_tokenAmount1, token1.balanceOf(OWNER));
+
+ // Commit
+ bytes32[] memory hashedMessages1 = new bytes32[](2);
+ hashedMessages1[0] = messages1[0]._hash(abi.encode(address(s_onRamp)));
+ hashedMessages1[1] = messages1[1]._hash(abi.encode(address(s_onRamp)));
+ bytes32[] memory hashedMessages2 = new bytes32[](1);
+ hashedMessages2[0] = messages2[0]._hash(abi.encode(address(s_onRamp2)));
+
+ bytes32[] memory merkleRoots = new bytes32[](2);
+ merkleRoots[0] = MerkleHelper.getMerkleRoot(hashedMessages1);
+ merkleRoots[1] = MerkleHelper.getMerkleRoot(hashedMessages2);
+
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](2);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ interval: EVM2EVMMultiOffRamp.Interval(messages1[0].header.sequenceNumber, messages1[1].header.sequenceNumber),
+ merkleRoot: merkleRoots[0]
+ });
+ roots[1] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR + 1,
+ interval: EVM2EVMMultiOffRamp.Interval(messages2[0].header.sequenceNumber, messages2[0].header.sequenceNumber),
+ merkleRoot: merkleRoots[1]
+ });
+
+ EVM2EVMMultiOffRamp.CommitReport memory report =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ vm.resumeGasMetering();
+ _commit(report, ++s_latestSequenceNumber);
+ vm.pauseGasMetering();
+
+ s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(s_offRamp), root: merkleRoots[0]}), true);
+ s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(s_offRamp), root: merkleRoots[1]}), true);
+
+ bytes32[] memory proofs = new bytes32[](0);
+ bytes32[] memory hashedLeaves = new bytes32[](1);
+ hashedLeaves[0] = merkleRoots[0];
+ uint256 timestamp = s_offRamp.verify(SOURCE_CHAIN_SELECTOR, hashedLeaves, proofs, 2 ** 2 - 1);
+ assertEq(BLOCK_TIME, timestamp);
+ hashedLeaves[0] = merkleRoots[1];
+ timestamp = s_offRamp.verify(SOURCE_CHAIN_SELECTOR + 1, hashedLeaves, proofs, 2 ** 2 - 1);
+ assertEq(BLOCK_TIME, timestamp);
+
+ // We change the block time so when execute would e.g. use the current
+ // block time instead of the committed block time the value would be
+ // incorrect in the checks below.
+ vm.warp(BLOCK_TIME + 2000);
+
+ // Execute
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR,
+ messages1[0].header.sequenceNumber,
+ messages1[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR,
+ messages1[1].header.sequenceNumber,
+ messages1[1].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR + 1,
+ messages2[0].header.sequenceNumber,
+ messages2[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR, messages1);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR + 1, messages2);
+
+ vm.resumeGasMetering();
+ _execute(reports);
+ }
+
+ function _sendRequest(
+ uint64 expectedSeqNum,
+ uint64 sourceChainSelector,
+ uint64 nonce,
+ bytes32 metadataHash,
+ Router router,
+ TokenAdminRegistry tokenAdminRegistry
+ ) public returns (Internal.Any2EVMRampMessage memory) {
+ Client.EVM2AnyMessage memory message = _generateTokenMessage();
+ uint256 expectedFee = router.getFee(DEST_CHAIN_SELECTOR, message);
+
+ IERC20(s_sourceTokens[0]).approve(address(router), i_tokenAmount0 + expectedFee);
+ IERC20(s_sourceTokens[1]).approve(address(router), i_tokenAmount1);
+
+ message.receiver = abi.encode(address(s_receiver));
+ Internal.EVM2AnyRampMessage memory msgEvent = _messageToEvent(
+ message,
+ sourceChainSelector,
+ DEST_CHAIN_SELECTOR,
+ expectedSeqNum,
+ nonce,
+ expectedFee,
+ OWNER,
+ metadataHash,
+ tokenAdminRegistry
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, msgEvent);
+
+ vm.resumeGasMetering();
+ router.ccipSend(DEST_CHAIN_SELECTOR, message);
+ vm.pauseGasMetering();
+
+ uint256 gasLimit = s_priceRegistry.parseEVMExtraArgsFromBytes(msgEvent.extraArgs, DEST_CHAIN_SELECTOR).gasLimit;
+
+ return Internal.Any2EVMRampMessage({
+ header: Internal.RampMessageHeader({
+ messageId: msgEvent.header.messageId,
+ sourceChainSelector: sourceChainSelector,
+ destChainSelector: DEST_CHAIN_SELECTOR,
+ sequenceNumber: msgEvent.header.sequenceNumber,
+ nonce: msgEvent.header.nonce
+ }),
+ sender: abi.encode(msgEvent.sender),
+ data: msgEvent.data,
+ receiver: abi.decode(msgEvent.receiver, (address)),
+ gasLimit: gasLimit,
+ tokenAmounts: msgEvent.tokenAmounts
+ });
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/AggregateRateLimiterHelper.sol b/contracts/src/v0.8/ccip/test/helpers/AggregateRateLimiterHelper.sol
new file mode 100644
index 00000000000..ced605a7524
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/AggregateRateLimiterHelper.sol
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import "../../AggregateRateLimiter.sol";
+
+contract AggregateRateLimiterHelper is AggregateRateLimiter {
+ constructor(RateLimiter.Config memory config) AggregateRateLimiter(config) {}
+
+ function rateLimitValue(uint256 value) public {
+ _rateLimitValue(value);
+ }
+
+ function getTokenValue(
+ Client.EVMTokenAmount memory tokenAmount,
+ IPriceRegistry priceRegistry
+ ) public view returns (uint256) {
+ return _getTokenValue(tokenAmount, priceRegistry);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/BurnMintERC677Helper.sol b/contracts/src/v0.8/ccip/test/helpers/BurnMintERC677Helper.sol
new file mode 100644
index 00000000000..9d2346996ae
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/BurnMintERC677Helper.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {IGetCCIPAdmin} from "../../interfaces/IGetCCIPAdmin.sol";
+
+contract BurnMintERC677Helper is BurnMintERC677, IGetCCIPAdmin {
+ constructor(string memory name, string memory symbol) BurnMintERC677(name, symbol, 18, 0) {}
+
+ // Gives one full token to any given address.
+ function drip(address to) external {
+ _mint(to, 1e18);
+ }
+
+ function getCCIPAdmin() external view override returns (address) {
+ return owner();
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/BurnMintMultiTokenPool.sol b/contracts/src/v0.8/ccip/test/helpers/BurnMintMultiTokenPool.sol
new file mode 100644
index 00000000000..a21fcde8357
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/BurnMintMultiTokenPool.sol
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
+
+import {Pool} from "../../libraries/Pool.sol";
+import {MultiTokenPool} from "./MultiTokenPool.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract BurnMintMultiTokenPool is MultiTokenPool {
+ constructor(
+ IERC20[] memory tokens,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) MultiTokenPool(tokens, allowlist, rmnProxy, router) {}
+
+ /// @notice Burn the token in the pool
+ /// @dev The _validateLockOrBurn check is an essential security check
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ virtual
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ _validateLockOrBurn(lockOrBurnIn);
+
+ IBurnMintERC20(lockOrBurnIn.localToken).burn(lockOrBurnIn.amount);
+
+ emit Burned(msg.sender, lockOrBurnIn.amount);
+
+ return Pool.LockOrBurnOutV1({
+ destTokenAddress: getRemoteToken(lockOrBurnIn.localToken, lockOrBurnIn.remoteChainSelector),
+ destPoolData: ""
+ });
+ }
+
+ /// @notice Mint tokens from the pool to the recipient
+ /// @dev The _validateReleaseOrMint check is an essential security check
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ virtual
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ _validateReleaseOrMint(releaseOrMintIn);
+
+ // Mint to the offRamp, which forwards it to the recipient
+ IBurnMintERC20(releaseOrMintIn.localToken).mint(msg.sender, releaseOrMintIn.amount);
+
+ emit Minted(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount);
+
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/CCIPConfigHelper.sol b/contracts/src/v0.8/ccip/test/helpers/CCIPConfigHelper.sol
new file mode 100644
index 00000000000..74f03890d3b
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/CCIPConfigHelper.sol
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.24;
+
+import {CCIPConfig} from "../../capability/CCIPConfig.sol";
+import {CCIPConfigTypes} from "../../capability/libraries/CCIPConfigTypes.sol";
+import {Internal} from "../../libraries/Internal.sol";
+
+contract CCIPConfigHelper is CCIPConfig {
+ constructor(address capabilitiesRegistry) CCIPConfig(capabilitiesRegistry) {}
+
+ function stateFromConfigLength(uint256 configLength) public pure returns (CCIPConfigTypes.ConfigState) {
+ return _stateFromConfigLength(configLength);
+ }
+
+ function validateConfigStateTransition(
+ CCIPConfigTypes.ConfigState currentState,
+ CCIPConfigTypes.ConfigState newState
+ ) public pure {
+ _validateConfigStateTransition(currentState, newState);
+ }
+
+ function validateConfigTransition(
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig,
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory newConfigWithMeta
+ ) public pure {
+ _validateConfigTransition(currentConfig, newConfigWithMeta);
+ }
+
+ function computeNewConfigWithMeta(
+ uint32 donId,
+ CCIPConfigTypes.OCR3ConfigWithMeta[] memory currentConfig,
+ CCIPConfigTypes.OCR3Config[] memory newConfig,
+ CCIPConfigTypes.ConfigState currentState,
+ CCIPConfigTypes.ConfigState newState
+ ) public view returns (CCIPConfigTypes.OCR3ConfigWithMeta[] memory) {
+ return _computeNewConfigWithMeta(donId, currentConfig, newConfig, currentState, newState);
+ }
+
+ function groupByPluginType(CCIPConfigTypes.OCR3Config[] memory ocr3Configs)
+ public
+ pure
+ returns (CCIPConfigTypes.OCR3Config[] memory commitConfigs, CCIPConfigTypes.OCR3Config[] memory execConfigs)
+ {
+ return _groupByPluginType(ocr3Configs);
+ }
+
+ function computeConfigDigest(
+ uint32 donId,
+ uint64 configCount,
+ CCIPConfigTypes.OCR3Config memory ocr3Config
+ ) public pure returns (bytes32) {
+ return _computeConfigDigest(donId, configCount, ocr3Config);
+ }
+
+ function validateConfig(CCIPConfigTypes.OCR3Config memory cfg) public view {
+ _validateConfig(cfg);
+ }
+
+ function updatePluginConfig(
+ uint32 donId,
+ Internal.OCRPluginType pluginType,
+ CCIPConfigTypes.OCR3Config[] memory newConfig
+ ) public {
+ _updatePluginConfig(donId, pluginType, newConfig);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/CommitStoreHelper.sol b/contracts/src/v0.8/ccip/test/helpers/CommitStoreHelper.sol
new file mode 100644
index 00000000000..c8d66b8d72f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/CommitStoreHelper.sol
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import "../../CommitStore.sol";
+
+contract CommitStoreHelper is CommitStore {
+ constructor(StaticConfig memory staticConfig) CommitStore(staticConfig) {}
+
+ /// @dev Expose _report for tests
+ function report(bytes calldata commitReport, uint40 epochAndRound) external {
+ _report(commitReport, epochAndRound);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/EVM2EVMMultiOffRampHelper.sol b/contracts/src/v0.8/ccip/test/helpers/EVM2EVMMultiOffRampHelper.sol
new file mode 100644
index 00000000000..581d9bd7051
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/EVM2EVMMultiOffRampHelper.sol
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {EVM2EVMMultiOffRamp} from "../../offRamp/EVM2EVMMultiOffRamp.sol";
+import {IgnoreContractSize} from "./IgnoreContractSize.sol";
+
+contract EVM2EVMMultiOffRampHelper is EVM2EVMMultiOffRamp, IgnoreContractSize {
+ mapping(uint64 sourceChainSelector => uint256 overrideTimestamp) private s_sourceChainVerificationOverride;
+
+ constructor(
+ StaticConfig memory staticConfig,
+ DynamicConfig memory dynamicConfig,
+ SourceChainConfigArgs[] memory sourceChainConfigs
+ ) EVM2EVMMultiOffRamp(staticConfig, dynamicConfig, sourceChainConfigs) {}
+
+ function setExecutionStateHelper(
+ uint64 sourceChainSelector,
+ uint64 sequenceNumber,
+ Internal.MessageExecutionState state
+ ) public {
+ _setExecutionState(sourceChainSelector, sequenceNumber, state);
+ }
+
+ function getExecutionStateBitMap(uint64 sourceChainSelector, uint64 bitmapIndex) public view returns (uint256) {
+ return s_executionStates[sourceChainSelector][bitmapIndex];
+ }
+
+ function releaseOrMintSingleToken(
+ Internal.RampTokenAmount memory sourceTokenAmount,
+ bytes calldata originalSender,
+ address receiver,
+ uint64 sourceChainSelector,
+ bytes calldata offchainTokenData
+ ) external returns (Client.EVMTokenAmount memory) {
+ return
+ _releaseOrMintSingleToken(sourceTokenAmount, originalSender, receiver, sourceChainSelector, offchainTokenData);
+ }
+
+ function releaseOrMintTokens(
+ Internal.RampTokenAmount[] memory sourceTokenAmounts,
+ bytes memory originalSender,
+ address receiver,
+ uint64 sourceChainSelector,
+ bytes[] calldata offchainTokenData
+ ) external returns (Client.EVMTokenAmount[] memory) {
+ return _releaseOrMintTokens(sourceTokenAmounts, originalSender, receiver, sourceChainSelector, offchainTokenData);
+ }
+
+ function trialExecute(
+ Internal.Any2EVMRampMessage memory message,
+ bytes[] memory offchainTokenData
+ ) external returns (Internal.MessageExecutionState, bytes memory) {
+ return _trialExecute(message, offchainTokenData);
+ }
+
+ function executeSingleReport(
+ Internal.ExecutionReportSingleChain memory rep,
+ uint256[] memory manualExecGasLimits
+ ) external {
+ _executeSingleReport(rep, manualExecGasLimits);
+ }
+
+ function batchExecute(
+ Internal.ExecutionReportSingleChain[] memory reports,
+ uint256[][] memory manualExecGasLimits
+ ) external {
+ _batchExecute(reports, manualExecGasLimits);
+ }
+
+ function verify(
+ uint64 sourceChainSelector,
+ bytes32[] memory hashedLeaves,
+ bytes32[] memory proofs,
+ uint256 proofFlagBits
+ ) external view returns (uint256 timestamp) {
+ return super._verify(sourceChainSelector, hashedLeaves, proofs, proofFlagBits);
+ }
+
+ function _verify(
+ uint64 sourceChainSelector,
+ bytes32[] memory hashedLeaves,
+ bytes32[] memory proofs,
+ uint256 proofFlagBits
+ ) internal view override returns (uint256 timestamp) {
+ uint256 overrideTimestamp = s_sourceChainVerificationOverride[sourceChainSelector];
+
+ return overrideTimestamp == 0
+ ? super._verify(sourceChainSelector, hashedLeaves, proofs, proofFlagBits)
+ : overrideTimestamp;
+ }
+
+ /// @dev Test helper to override _verify result for easier exec testing
+ function setVerifyOverrideResult(uint64 sourceChainSelector, uint256 overrideTimestamp) external {
+ s_sourceChainVerificationOverride[sourceChainSelector] = overrideTimestamp;
+ }
+
+ /// @dev Test helper to directly set a root's timestamp
+ function setRootTimestamp(uint64 sourceChainSelector, bytes32 root, uint256 timestamp) external {
+ s_roots[sourceChainSelector][root] = timestamp;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/EVM2EVMMultiOnRampHelper.sol b/contracts/src/v0.8/ccip/test/helpers/EVM2EVMMultiOnRampHelper.sol
new file mode 100644
index 00000000000..0532697d649
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/EVM2EVMMultiOnRampHelper.sol
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import "../../onRamp/EVM2EVMMultiOnRamp.sol";
+import {IgnoreContractSize} from "./IgnoreContractSize.sol";
+
+contract EVM2EVMMultiOnRampHelper is EVM2EVMMultiOnRamp, IgnoreContractSize {
+ constructor(
+ StaticConfig memory staticConfig,
+ DynamicConfig memory dynamicConfig
+ ) EVM2EVMMultiOnRamp(staticConfig, dynamicConfig) {}
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/EVM2EVMOffRampHelper.sol b/contracts/src/v0.8/ccip/test/helpers/EVM2EVMOffRampHelper.sol
new file mode 100644
index 00000000000..e328f0ade29
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/EVM2EVMOffRampHelper.sol
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import "../../offRamp/EVM2EVMOffRamp.sol";
+import {IgnoreContractSize} from "./IgnoreContractSize.sol";
+
+contract EVM2EVMOffRampHelper is EVM2EVMOffRamp, IgnoreContractSize {
+ constructor(
+ StaticConfig memory staticConfig,
+ RateLimiter.Config memory rateLimiterConfig
+ ) EVM2EVMOffRamp(staticConfig, rateLimiterConfig) {}
+
+ function setExecutionStateHelper(uint64 sequenceNumber, Internal.MessageExecutionState state) public {
+ _setExecutionState(sequenceNumber, state);
+ }
+
+ function getExecutionStateBitMap(uint64 bitmapIndex) public view returns (uint256) {
+ return s_executionStates[bitmapIndex];
+ }
+
+ function releaseOrMintToken(
+ uint256 sourceTokenAmount,
+ bytes calldata originalSender,
+ address receiver,
+ Internal.SourceTokenData calldata sourceTokenData,
+ bytes calldata offchainTokenData
+ ) external returns (Client.EVMTokenAmount memory) {
+ return _releaseOrMintToken(sourceTokenAmount, originalSender, receiver, sourceTokenData, offchainTokenData);
+ }
+
+ function releaseOrMintTokens(
+ Client.EVMTokenAmount[] memory sourceTokenAmounts,
+ bytes calldata originalSender,
+ address receiver,
+ bytes[] calldata sourceTokenData,
+ bytes[] calldata offchainTokenData
+ ) external returns (Client.EVMTokenAmount[] memory) {
+ return _releaseOrMintTokens(sourceTokenAmounts, originalSender, receiver, sourceTokenData, offchainTokenData);
+ }
+
+ function trialExecute(
+ Internal.EVM2EVMMessage memory message,
+ bytes[] memory offchainTokenData
+ ) external returns (Internal.MessageExecutionState, bytes memory) {
+ return _trialExecute(message, offchainTokenData);
+ }
+
+ function report(bytes calldata executableMessages) external {
+ _report(executableMessages);
+ }
+
+ function execute(Internal.ExecutionReport memory rep, uint256[] memory manualExecGasLimits) external {
+ _execute(rep, manualExecGasLimits);
+ }
+
+ function metadataHash() external view returns (bytes32) {
+ return _metadataHash(Internal.EVM_2_EVM_MESSAGE_HASH);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/EVM2EVMOnRampHelper.sol b/contracts/src/v0.8/ccip/test/helpers/EVM2EVMOnRampHelper.sol
new file mode 100644
index 00000000000..5cce6aaa445
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/EVM2EVMOnRampHelper.sol
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import "../../onRamp/EVM2EVMOnRamp.sol";
+import {IgnoreContractSize} from "./IgnoreContractSize.sol";
+
+contract EVM2EVMOnRampHelper is EVM2EVMOnRamp, IgnoreContractSize {
+ constructor(
+ StaticConfig memory staticConfig,
+ DynamicConfig memory dynamicConfig,
+ RateLimiter.Config memory rateLimiterConfig,
+ FeeTokenConfigArgs[] memory feeTokenConfigs,
+ TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
+ NopAndWeight[] memory nopsAndWeights
+ )
+ EVM2EVMOnRamp(
+ staticConfig,
+ dynamicConfig,
+ rateLimiterConfig,
+ feeTokenConfigs,
+ tokenTransferFeeConfigArgs,
+ nopsAndWeights
+ )
+ {}
+
+ function getDataAvailabilityCost(
+ uint112 dataAvailabilityGasPrice,
+ uint256 messageDataLength,
+ uint256 numberOfTokens,
+ uint32 tokenTransferBytesOverhead
+ ) external view returns (uint256) {
+ return
+ _getDataAvailabilityCost(dataAvailabilityGasPrice, messageDataLength, numberOfTokens, tokenTransferBytesOverhead);
+ }
+
+ function getTokenTransferCost(
+ address feeToken,
+ uint224 feeTokenPrice,
+ Client.EVMTokenAmount[] calldata tokenAmounts
+ ) external view returns (uint256, uint32, uint32) {
+ return _getTokenTransferCost(feeToken, feeTokenPrice, tokenAmounts);
+ }
+
+ function getSequenceNumber() external view returns (uint64) {
+ return s_sequenceNumber;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/EtherSenderReceiverHelper.sol b/contracts/src/v0.8/ccip/test/helpers/EtherSenderReceiverHelper.sol
new file mode 100644
index 00000000000..71a5cdc7ab6
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/EtherSenderReceiverHelper.sol
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {EtherSenderReceiver} from "../../applications/EtherSenderReceiver.sol";
+import {Client} from "../../libraries/Client.sol";
+
+contract EtherSenderReceiverHelper is EtherSenderReceiver {
+ constructor(address router) EtherSenderReceiver(router) {}
+
+ function validatedMessage(Client.EVM2AnyMessage calldata message) public view returns (Client.EVM2AnyMessage memory) {
+ return _validatedMessage(message);
+ }
+
+ function validateFeeToken(Client.EVM2AnyMessage calldata message) public payable {
+ _validateFeeToken(message);
+ }
+
+ function publicCcipReceive(Client.Any2EVMMessage memory message) public {
+ _ccipReceive(message);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/IgnoreContractSize.sol b/contracts/src/v0.8/ccip/test/helpers/IgnoreContractSize.sol
new file mode 100644
index 00000000000..b30124069f2
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/IgnoreContractSize.sol
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+contract IgnoreContractSize {
+ // test contracts are excluded from forge build --sizes by default
+ // --sizes exits with code 1 if any contract is over limit, which fails CI
+ // for helper contracts that are not explicit test contracts
+ // use this flag to exclude from --sizes
+ bool public IS_SCRIPT = true;
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/MaybeRevertingBurnMintTokenPool.sol b/contracts/src/v0.8/ccip/test/helpers/MaybeRevertingBurnMintTokenPool.sol
new file mode 100644
index 00000000000..e572f798ad9
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/MaybeRevertingBurnMintTokenPool.sol
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
+
+import {Pool} from "../../libraries/Pool.sol";
+import {BurnMintTokenPool} from "../../pools/BurnMintTokenPool.sol";
+
+contract MaybeRevertingBurnMintTokenPool is BurnMintTokenPool {
+ bytes public s_revertReason = "";
+ bytes public s_sourceTokenData = "";
+
+ constructor(
+ IBurnMintERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) BurnMintTokenPool(token, allowlist, rmnProxy, router) {}
+
+ function setShouldRevert(bytes calldata revertReason) external {
+ s_revertReason = revertReason;
+ }
+
+ function setSourceTokenData(bytes calldata sourceTokenData) external {
+ s_sourceTokenData = sourceTokenData;
+ }
+
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ virtual
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ _validateLockOrBurn(lockOrBurnIn);
+
+ bytes memory revertReason = s_revertReason;
+ if (revertReason.length != 0) {
+ assembly {
+ revert(add(32, revertReason), mload(revertReason))
+ }
+ }
+
+ IBurnMintERC20(address(i_token)).burn(lockOrBurnIn.amount);
+ emit Burned(msg.sender, lockOrBurnIn.amount);
+ return Pool.LockOrBurnOutV1({
+ destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector),
+ destPoolData: s_sourceTokenData
+ });
+ }
+
+ /// @notice Reverts depending on the value of `s_revertReason`
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ virtual
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ _validateReleaseOrMint(releaseOrMintIn);
+
+ bytes memory revertReason = s_revertReason;
+ if (revertReason.length != 0) {
+ assembly {
+ revert(add(32, revertReason), mload(revertReason))
+ }
+ }
+ IBurnMintERC20(address(i_token)).mint(msg.sender, releaseOrMintIn.amount);
+ emit Minted(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount);
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/MerkleHelper.sol b/contracts/src/v0.8/ccip/test/helpers/MerkleHelper.sol
new file mode 100644
index 00000000000..ccb05681f1c
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/MerkleHelper.sol
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {MerkleMultiProof} from "../../libraries/MerkleMultiProof.sol";
+
+library MerkleHelper {
+ /// @notice Generate a Merkle Root from a full set of leaves. When a tree is unbalanced
+ /// the value is brought up in the tree. For example consider (a,b,c) as leaves. This would
+ /// result in the following tree with d being computed from hash(a,c) and the root r from
+ /// hash(d,c). Notice c is not being rehashed when it is brought up in the tree, so the
+ /// root is NOT hash(d,hash(c)) but instead hash(d,c) == hash(hash(a,b),c).
+ /// r
+ /// / \
+ /// d c
+ /// / \
+ /// a b
+ function getMerkleRoot(bytes32[] memory hashedLeaves) public pure returns (bytes32) {
+ require(hashedLeaves.length <= 256);
+ while (hashedLeaves.length > 1) {
+ hashedLeaves = computeNextLayer(hashedLeaves);
+ }
+ return hashedLeaves[0];
+ }
+
+ /// @notice Computes a single layer of a merkle proof by hashing each pair (i, i+1) for
+ /// each i, i+2, i+4.. n. When an uneven number of leaves is supplied the last item
+ /// is simply included as the last element in the result set and not hashed.
+ function computeNextLayer(bytes32[] memory layer) public pure returns (bytes32[] memory) {
+ uint256 leavesLen = layer.length;
+ if (leavesLen == 1) return layer;
+
+ unchecked {
+ bytes32[] memory nextLayer = new bytes32[]((leavesLen + 1) / 2);
+ for (uint256 i = 0; i < leavesLen; i += 2) {
+ if (i == leavesLen - 1) {
+ nextLayer[i / 2] = layer[i];
+ } else {
+ nextLayer[i / 2] = hashPair(layer[i], layer[i + 1]);
+ }
+ }
+ return nextLayer;
+ }
+ }
+
+ function hashPair(bytes32 a, bytes32 b) public pure returns (bytes32) {
+ return a < b ? hashInternalNode(a, b) : hashInternalNode(b, a);
+ }
+
+ function hashInternalNode(bytes32 left, bytes32 right) public pure returns (bytes32 hash) {
+ return keccak256(abi.encode(MerkleMultiProof.INTERNAL_DOMAIN_SEPARATOR, left, right));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/MessageHasher.sol b/contracts/src/v0.8/ccip/test/helpers/MessageHasher.sol
new file mode 100644
index 00000000000..19f35df7969
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/MessageHasher.sol
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+
+/// @notice MessageHasher is a contract that utility functions to hash an Any2EVMRampMessage
+/// and encode various preimages for the final hash of the message.
+/// @dev This is only deployed in tests and is not part of the production contracts.
+contract MessageHasher {
+ function hash(Internal.Any2EVMRampMessage memory message, bytes memory onRamp) public pure returns (bytes32) {
+ return Internal._hash(message, onRamp);
+ }
+
+ function encodeTokenAmountsHashPreimage(Internal.RampTokenAmount[] memory rampTokenAmounts)
+ public
+ pure
+ returns (bytes memory)
+ {
+ return abi.encode(rampTokenAmounts);
+ }
+
+ function encodeMetadataHashPreimage(
+ bytes32 any2EVMMessageHash,
+ uint64 sourceChainSelector,
+ uint64 destChainSelector,
+ bytes memory onRamp
+ ) public pure returns (bytes memory) {
+ return abi.encode(any2EVMMessageHash, sourceChainSelector, destChainSelector, onRamp);
+ }
+
+ function encodeFixedSizeFieldsHashPreimage(
+ bytes32 messageId,
+ bytes memory sender,
+ address receiver,
+ uint64 sequenceNumber,
+ uint256 gasLimit,
+ uint64 nonce
+ ) public pure returns (bytes memory) {
+ return abi.encode(messageId, sender, receiver, sequenceNumber, gasLimit, nonce);
+ }
+
+ function encodeFinalHashPreimage(
+ bytes32 leafDomainSeparator,
+ bytes32 implicitMetadataHash,
+ bytes32 fixedSizeFieldsHash,
+ bytes32 dataHash,
+ bytes32 tokenAmountsHash
+ ) public pure returns (bytes memory) {
+ return abi.encode(leafDomainSeparator, implicitMetadataHash, fixedSizeFieldsHash, dataHash, tokenAmountsHash);
+ }
+
+ function encodeEVMExtraArgsV1(Client.EVMExtraArgsV1 memory extraArgs) public pure returns (bytes memory) {
+ return Client._argsToBytes(extraArgs);
+ }
+
+ function encodeEVMExtraArgsV2(Client.EVMExtraArgsV2 memory extraArgs) public pure returns (bytes memory) {
+ return Client._argsToBytes(extraArgs);
+ }
+
+ function decodeEVMExtraArgsV1(uint256 gasLimit) public pure returns (Client.EVMExtraArgsV1 memory) {
+ return Client.EVMExtraArgsV1(gasLimit);
+ }
+
+ function decodeEVMExtraArgsV2(
+ uint256 gasLimit,
+ bool allowOutOfOrderExecution
+ ) public pure returns (Client.EVMExtraArgsV2 memory) {
+ return Client.EVMExtraArgsV2(gasLimit, allowOutOfOrderExecution);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/MessageInterceptorHelper.sol b/contracts/src/v0.8/ccip/test/helpers/MessageInterceptorHelper.sol
new file mode 100644
index 00000000000..a54145da84e
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/MessageInterceptorHelper.sol
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IMessageInterceptor} from "../../interfaces/IMessageInterceptor.sol";
+import {Client} from "../../libraries/Client.sol";
+
+contract MessageInterceptorHelper is IMessageInterceptor {
+ mapping(bytes32 messageId => bool isInvalid) internal s_invalidMessageIds;
+
+ constructor() {}
+
+ function setMessageIdValidationState(bytes32 messageId, bool isInvalid) external {
+ s_invalidMessageIds[messageId] = isInvalid;
+ }
+
+ /// @inheritdoc IMessageInterceptor
+ function onInboundMessage(Client.Any2EVMMessage memory message) external view {
+ if (s_invalidMessageIds[message.messageId]) {
+ revert MessageValidationError(bytes("Invalid message"));
+ }
+ }
+
+ /// @inheritdoc IMessageInterceptor
+ function onOutboundMessage(uint64, Client.EVM2AnyMessage calldata message) external view {
+ if (s_invalidMessageIds[keccak256(abi.encode(message))]) {
+ revert MessageValidationError(bytes("Invalid message"));
+ }
+ return;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/MultiAggregateRateLimiterHelper.sol b/contracts/src/v0.8/ccip/test/helpers/MultiAggregateRateLimiterHelper.sol
new file mode 100644
index 00000000000..d9386ca7db0
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/MultiAggregateRateLimiterHelper.sol
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {MultiAggregateRateLimiter} from "../../MultiAggregateRateLimiter.sol";
+import {IPriceRegistry} from "../../interfaces/IPriceRegistry.sol";
+import {Client} from "../../libraries/Client.sol";
+
+contract MultiAggregateRateLimiterHelper is MultiAggregateRateLimiter {
+ constructor(
+ address priceRegistry,
+ address[] memory authorizedCallers
+ ) MultiAggregateRateLimiter(priceRegistry, authorizedCallers) {}
+
+ function getTokenValue(Client.EVMTokenAmount memory tokenAmount) public view returns (uint256) {
+ return _getTokenValue(tokenAmount);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/MultiOCR3Helper.sol b/contracts/src/v0.8/ccip/test/helpers/MultiOCR3Helper.sol
new file mode 100644
index 00000000000..003a5326b89
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/MultiOCR3Helper.sol
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {MultiOCR3Base} from "../../ocr/MultiOCR3Base.sol";
+
+contract MultiOCR3Helper is MultiOCR3Base {
+ event AfterConfigSet(uint8 ocrPluginType);
+
+ /// @dev OCR plugin type used for transmit.
+ /// Defined in storage since it cannot be passed as calldata due to strict transmit checks
+ uint8 internal s_transmitOcrPluginType;
+
+ function setTransmitOcrPluginType(uint8 ocrPluginType) external {
+ s_transmitOcrPluginType = ocrPluginType;
+ }
+
+ /// @dev transmit function with signatures
+ function transmitWithSignatures(
+ bytes32[3] calldata reportContext,
+ bytes calldata report,
+ bytes32[] calldata rs,
+ bytes32[] calldata ss,
+ bytes32 rawVs
+ ) external {
+ _transmit(s_transmitOcrPluginType, reportContext, report, rs, ss, rawVs);
+ }
+
+ /// @dev transmit function with no signatures
+ function transmitWithoutSignatures(bytes32[3] calldata reportContext, bytes calldata report) external {
+ bytes32[] memory emptySigs = new bytes32[](0);
+ _transmit(s_transmitOcrPluginType, reportContext, report, emptySigs, emptySigs, bytes32(""));
+ }
+
+ function getOracle(uint8 ocrPluginType, address oracleAddress) external view returns (Oracle memory) {
+ return s_oracles[ocrPluginType][oracleAddress];
+ }
+
+ function typeAndVersion() public pure override returns (string memory) {
+ return "MultiOCR3BaseHelper 1.0.0";
+ }
+
+ function _afterOCR3ConfigSet(uint8 ocrPluginType) internal virtual override {
+ emit AfterConfigSet(ocrPluginType);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/MultiTokenPool.sol b/contracts/src/v0.8/ccip/test/helpers/MultiTokenPool.sol
new file mode 100644
index 00000000000..0f7c312f713
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/MultiTokenPool.sol
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPoolV1} from "../../interfaces/IPool.sol";
+import {IRMN} from "../../interfaces/IRMN.sol";
+import {IRouter} from "../../interfaces/IRouter.sol";
+
+import {OwnerIsCreator} from "../../../shared/access/OwnerIsCreator.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @notice This contract is a proof of concept and should NOT be used in production.
+abstract contract MultiTokenPool is IPoolV1, OwnerIsCreator {
+ using EnumerableSet for EnumerableSet.AddressSet;
+ using EnumerableSet for EnumerableSet.UintSet;
+ using RateLimiter for RateLimiter.TokenBucket;
+
+ error CallerIsNotARampOnRouter(address caller);
+ error ZeroAddressNotAllowed();
+ error SenderNotAllowed(address sender);
+ error AllowListNotEnabled();
+ error NonExistentChain(uint64 remoteChainSelector);
+ error ChainNotAllowed(uint64 remoteChainSelector);
+ error CursedByRMN();
+ error ChainAlreadyExists(uint64 chainSelector);
+ error InvalidSourcePoolAddress(bytes sourcePoolAddress);
+ error InvalidToken(address token);
+
+ event Locked(address indexed sender, uint256 amount);
+ event Burned(address indexed sender, uint256 amount);
+ event Released(address indexed sender, address indexed recipient, uint256 amount);
+ event Minted(address indexed sender, address indexed recipient, uint256 amount);
+ event ChainAdded(
+ uint64 remoteChainSelector,
+ bytes remoteToken,
+ RateLimiter.Config outboundRateLimiterConfig,
+ RateLimiter.Config inboundRateLimiterConfig
+ );
+ event ChainConfigured(
+ uint64 remoteChainSelector,
+ RateLimiter.Config outboundRateLimiterConfig,
+ RateLimiter.Config inboundRateLimiterConfig
+ );
+ event ChainRemoved(uint64 remoteChainSelector);
+ event RemotePoolSet(uint64 indexed remoteChainSelector, bytes previousPoolAddress, bytes remotePoolAddress);
+ event AllowListAdd(address sender);
+ event AllowListRemove(address sender);
+ event RouterUpdated(address oldRouter, address newRouter);
+
+ struct ChainUpdate {
+ uint64 remoteChainSelector; // ──╮ Remote chain selector
+ bool allowed; // ────────────────╯ Whether the chain is allowed
+ bytes remotePoolAddress; // Address of the remote pool, ABI encoded in the case of a remove EVM chain.
+ bytes remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain.
+ RateLimiter.Config outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain
+ RateLimiter.Config inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain
+ }
+
+ struct RemoteChainConfig {
+ RateLimiter.TokenBucket outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain
+ RateLimiter.TokenBucket inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain
+ bytes remotePoolAddress; // Address of the remote pool, ABI encoded in the case of a remote EVM chain.
+ bytes remoteTokenAddress; // Address of the remote token, ABI encoded in the case of a remote EVM chain.
+ }
+
+ /// @dev The IERC20 token that this pool supports
+ EnumerableSet.AddressSet internal s_tokens;
+ /// @dev The address of the RMN proxy
+ address internal immutable i_rmnProxy;
+ /// @dev The immutable flag that indicates if the pool is access-controlled.
+ bool internal immutable i_allowlistEnabled;
+ /// @dev A set of addresses allowed to trigger lockOrBurn as original senders.
+ /// Only takes effect if i_allowlistEnabled is true.
+ /// This can be used to ensure only token-issuer specified addresses can
+ /// move tokens.
+ EnumerableSet.AddressSet internal s_allowList;
+ /// @dev The address of the router
+ IRouter internal s_router;
+ /// @dev A set of allowed chain selectors. We want the allowlist to be enumerable to
+ /// be able to quickly determine (without parsing logs) who can access the pool.
+ /// @dev The chain selectors are in uin256 format because of the EnumerableSet implementation.
+ EnumerableSet.UintSet internal s_remoteChainSelectors;
+ mapping(address token => mapping(uint64 remoteChainSelector => RemoteChainConfig)) internal s_remoteChainConfigs;
+
+ constructor(IERC20[] memory token, address[] memory allowlist, address rmnProxy, address router) {
+ if (router == address(0) || rmnProxy == address(0)) revert ZeroAddressNotAllowed();
+ for (uint256 i = 0; i < token.length; ++i) {
+ s_tokens.add(address(token[i]));
+ }
+ i_rmnProxy = rmnProxy;
+ s_router = IRouter(router);
+
+ // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas.
+ i_allowlistEnabled = allowlist.length > 0;
+ if (i_allowlistEnabled) {
+ _applyAllowListUpdates(new address[](0), allowlist);
+ }
+ }
+
+ /// @notice Get RMN proxy address
+ /// @return rmnProxy Address of RMN proxy
+ function getRmnProxy() public view returns (address rmnProxy) {
+ return i_rmnProxy;
+ }
+
+ /// @inheritdoc IPoolV1
+ function isSupportedToken(address token) public view virtual returns (bool) {
+ return s_tokens.contains(token);
+ }
+
+ /// @notice Gets the IERC20 token that this pool can lock or burn.
+ /// @return tokens The IERC20 token representation.
+ function getTokens() public view returns (IERC20[] memory tokens) {
+ tokens = new IERC20[](s_tokens.length());
+ for (uint256 i = 0; i < s_tokens.length(); ++i) {
+ tokens[i] = IERC20(s_tokens.at(i));
+ }
+ return tokens;
+ }
+
+ /// @notice Gets the pool's Router
+ /// @return router The pool's Router
+ function getRouter() public view returns (address router) {
+ return address(s_router);
+ }
+
+ /// @notice Sets the pool's Router
+ /// @param newRouter The new Router
+ function setRouter(address newRouter) public onlyOwner {
+ if (newRouter == address(0)) revert ZeroAddressNotAllowed();
+ address oldRouter = address(s_router);
+ s_router = IRouter(newRouter);
+
+ emit RouterUpdated(oldRouter, newRouter);
+ }
+
+ /// @notice Signals which version of the pool interface is supported
+ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
+ return interfaceId == Pool.CCIP_POOL_V1 || interfaceId == type(IPoolV1).interfaceId
+ || interfaceId == type(IERC165).interfaceId;
+ }
+
+ // ================================================================
+ // │ Validation │
+ // ================================================================
+
+ /// @notice Validates the lock or burn input for correctness on
+ /// - token to be locked or burned
+ /// - RMN curse status
+ /// - allowlist status
+ /// - if the sender is a valid onRamp
+ /// - rate limit status
+ /// @param lockOrBurnIn The input to validate.
+ /// @dev This function should always be called before executing a lock or burn. Not doing so would allow
+ /// for various exploits.
+ function _validateLockOrBurn(Pool.LockOrBurnInV1 memory lockOrBurnIn) internal {
+ if (!isSupportedToken(lockOrBurnIn.localToken)) revert InvalidToken(lockOrBurnIn.localToken);
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(lockOrBurnIn.remoteChainSelector)))) revert CursedByRMN();
+ _checkAllowList(lockOrBurnIn.originalSender);
+
+ _onlyOnRamp(lockOrBurnIn.remoteChainSelector);
+ _consumeOutboundRateLimit(lockOrBurnIn.localToken, lockOrBurnIn.remoteChainSelector, lockOrBurnIn.amount);
+ }
+
+ /// @notice Validates the release or mint input for correctness on
+ /// - token to be released or minted
+ /// - RMN curse status
+ /// - if the sender is a valid offRamp
+ /// - if the source pool is valid
+ /// - rate limit status
+ /// @param releaseOrMintIn The input to validate.
+ /// @dev This function should always be called before executing a lock or burn. Not doing so would allow
+ /// for various exploits.
+ function _validateReleaseOrMint(Pool.ReleaseOrMintInV1 memory releaseOrMintIn) internal {
+ if (!isSupportedToken(releaseOrMintIn.localToken)) revert InvalidToken(releaseOrMintIn.localToken);
+ if (IRMN(i_rmnProxy).isCursed(bytes16(uint128(releaseOrMintIn.remoteChainSelector)))) revert CursedByRMN();
+ _onlyOffRamp(releaseOrMintIn.remoteChainSelector);
+
+ // Validates that the source pool address is configured on this pool.
+ bytes memory configuredRemotePool = getRemotePool(releaseOrMintIn.localToken, releaseOrMintIn.remoteChainSelector);
+ if (
+ configuredRemotePool.length == 0
+ || keccak256(releaseOrMintIn.sourcePoolAddress) != keccak256(configuredRemotePool)
+ ) {
+ revert InvalidSourcePoolAddress(releaseOrMintIn.sourcePoolAddress);
+ }
+ _consumeInboundRateLimit(releaseOrMintIn.localToken, releaseOrMintIn.remoteChainSelector, releaseOrMintIn.amount);
+ }
+
+ // ================================================================
+ // │ Chain permissions │
+ // ================================================================
+
+ /// @notice Gets the pool address on the remote chain.
+ /// @param remoteChainSelector Remote chain selector.
+ /// @dev To support non-evm chains, this value is encoded into bytes
+ function getRemotePool(address token, uint64 remoteChainSelector) public view returns (bytes memory) {
+ return s_remoteChainConfigs[token][remoteChainSelector].remotePoolAddress;
+ }
+
+ /// @notice Gets the token address on the remote chain.
+ /// @param remoteChainSelector Remote chain selector.
+ /// @dev To support non-evm chains, this value is encoded into bytes
+ function getRemoteToken(address token, uint64 remoteChainSelector) public view returns (bytes memory) {
+ return s_remoteChainConfigs[token][remoteChainSelector].remoteTokenAddress;
+ }
+
+ /// @notice Sets the remote pool address for a given chain selector.
+ /// @param remoteChainSelector The remote chain selector for which the remote pool address is being set.
+ /// @param remotePoolAddress The address of the remote pool.
+ function setRemotePool(
+ address token,
+ uint64 remoteChainSelector,
+ bytes calldata remotePoolAddress
+ ) external onlyOwner {
+ if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
+
+ bytes memory prevAddress = s_remoteChainConfigs[token][remoteChainSelector].remotePoolAddress;
+ s_remoteChainConfigs[token][remoteChainSelector].remotePoolAddress = remotePoolAddress;
+
+ emit RemotePoolSet(remoteChainSelector, prevAddress, remotePoolAddress);
+ }
+
+ /// @inheritdoc IPoolV1
+ function isSupportedChain(uint64 remoteChainSelector) public view returns (bool) {
+ return s_remoteChainSelectors.contains(remoteChainSelector);
+ }
+
+ /// @notice Get list of allowed chains
+ /// @return list of chains.
+ function getSupportedChains() public view returns (uint64[] memory) {
+ uint256[] memory uint256ChainSelectors = s_remoteChainSelectors.values();
+ uint64[] memory chainSelectors = new uint64[](uint256ChainSelectors.length);
+ for (uint256 i = 0; i < uint256ChainSelectors.length; ++i) {
+ chainSelectors[i] = uint64(uint256ChainSelectors[i]);
+ }
+
+ return chainSelectors;
+ }
+
+ /// @notice Sets the permissions for a list of chains selectors. Actual senders for these chains
+ /// need to be allowed on the Router to interact with this pool.
+ /// @dev Only callable by the owner
+ /// @param chains A list of chains and their new permission status & rate limits. Rate limits
+ /// are only used when the chain is being added through `allowed` being true.
+ function applyChainUpdates(address token, ChainUpdate[] calldata chains) external virtual onlyOwner {
+ for (uint256 i = 0; i < chains.length; ++i) {
+ ChainUpdate memory update = chains[i];
+ RateLimiter._validateTokenBucketConfig(update.outboundRateLimiterConfig, !update.allowed);
+ RateLimiter._validateTokenBucketConfig(update.inboundRateLimiterConfig, !update.allowed);
+
+ if (update.allowed) {
+ // If the chain already exists, revert
+ if (!s_remoteChainSelectors.add(update.remoteChainSelector)) {
+ revert ChainAlreadyExists(update.remoteChainSelector);
+ }
+
+ if (update.remotePoolAddress.length == 0 || update.remoteTokenAddress.length == 0) {
+ revert ZeroAddressNotAllowed();
+ }
+
+ s_remoteChainConfigs[token][update.remoteChainSelector] = RemoteChainConfig({
+ outboundRateLimiterConfig: RateLimiter.TokenBucket({
+ rate: update.outboundRateLimiterConfig.rate,
+ capacity: update.outboundRateLimiterConfig.capacity,
+ tokens: update.outboundRateLimiterConfig.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: update.outboundRateLimiterConfig.isEnabled
+ }),
+ inboundRateLimiterConfig: RateLimiter.TokenBucket({
+ rate: update.inboundRateLimiterConfig.rate,
+ capacity: update.inboundRateLimiterConfig.capacity,
+ tokens: update.inboundRateLimiterConfig.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: update.inboundRateLimiterConfig.isEnabled
+ }),
+ remotePoolAddress: update.remotePoolAddress,
+ remoteTokenAddress: update.remoteTokenAddress
+ });
+
+ emit ChainAdded(
+ update.remoteChainSelector,
+ update.remoteTokenAddress,
+ update.outboundRateLimiterConfig,
+ update.inboundRateLimiterConfig
+ );
+ } else {
+ // If the chain doesn't exist, revert
+ if (!s_remoteChainSelectors.remove(update.remoteChainSelector)) {
+ revert NonExistentChain(update.remoteChainSelector);
+ }
+
+ delete s_remoteChainConfigs[token][update.remoteChainSelector];
+
+ emit ChainRemoved(update.remoteChainSelector);
+ }
+ }
+ }
+
+ // ================================================================
+ // │ Rate limiting │
+ // ================================================================
+
+ /// @notice Consumes outbound rate limiting capacity in this pool
+ function _consumeOutboundRateLimit(address token, uint64 remoteChainSelector, uint256 amount) internal {
+ s_remoteChainConfigs[token][remoteChainSelector].outboundRateLimiterConfig._consume(amount, token);
+ }
+
+ /// @notice Consumes inbound rate limiting capacity in this pool
+ function _consumeInboundRateLimit(address token, uint64 remoteChainSelector, uint256 amount) internal {
+ s_remoteChainConfigs[token][remoteChainSelector].inboundRateLimiterConfig._consume(amount, token);
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function getCurrentOutboundRateLimiterState(
+ address token,
+ uint64 remoteChainSelector
+ ) external view returns (RateLimiter.TokenBucket memory) {
+ return s_remoteChainConfigs[token][remoteChainSelector].outboundRateLimiterConfig._currentTokenBucketState();
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function getCurrentInboundRateLimiterState(
+ address token,
+ uint64 remoteChainSelector
+ ) external view returns (RateLimiter.TokenBucket memory) {
+ return s_remoteChainConfigs[token][remoteChainSelector].inboundRateLimiterConfig._currentTokenBucketState();
+ }
+
+ /// @notice Sets the chain rate limiter config.
+ /// @param remoteChainSelector The remote chain selector for which the rate limits apply.
+ /// @param outboundConfig The new outbound rate limiter config, meaning the onRamp rate limits for the given chain.
+ /// @param inboundConfig The new inbound rate limiter config, meaning the offRamp rate limits for the given chain.
+ function setChainRateLimiterConfig(
+ address token,
+ uint64 remoteChainSelector,
+ RateLimiter.Config memory outboundConfig,
+ RateLimiter.Config memory inboundConfig
+ ) internal {
+ if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
+ RateLimiter._validateTokenBucketConfig(outboundConfig, false);
+ s_remoteChainConfigs[token][remoteChainSelector].outboundRateLimiterConfig._setTokenBucketConfig(outboundConfig);
+ RateLimiter._validateTokenBucketConfig(inboundConfig, false);
+ s_remoteChainConfigs[token][remoteChainSelector].inboundRateLimiterConfig._setTokenBucketConfig(inboundConfig);
+ emit ChainConfigured(remoteChainSelector, outboundConfig, inboundConfig);
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender
+ /// is a permissioned onRamp for the given chain on the Router.
+ function _onlyOnRamp(uint64 remoteChainSelector) internal view {
+ if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector);
+ if (!(msg.sender == s_router.getOnRamp(remoteChainSelector))) revert CallerIsNotARampOnRouter(msg.sender);
+ }
+
+ /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender
+ /// is a permissioned offRamp for the given chain on the Router.
+ function _onlyOffRamp(uint64 remoteChainSelector) internal view {
+ if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector);
+ if (!s_router.isOffRamp(remoteChainSelector, msg.sender)) revert CallerIsNotARampOnRouter(msg.sender);
+ }
+
+ // ================================================================
+ // │ Allowlist │
+ // ================================================================
+
+ function _checkAllowList(address sender) internal view {
+ if (i_allowlistEnabled && !s_allowList.contains(sender)) revert SenderNotAllowed(sender);
+ }
+
+ /// @notice Gets whether the allowList functionality is enabled.
+ /// @return true is enabled, false if not.
+ function getAllowListEnabled() external view returns (bool) {
+ return i_allowlistEnabled;
+ }
+
+ /// @notice Gets the allowed addresses.
+ /// @return The allowed addresses.
+ function getAllowList() external view returns (address[] memory) {
+ return s_allowList.values();
+ }
+
+ /// @notice Apply updates to the allow list.
+ /// @param removes The addresses to be removed.
+ /// @param adds The addresses to be added.
+ /// @dev allowListing will be removed before public launch
+ function applyAllowListUpdates(address[] calldata removes, address[] calldata adds) external onlyOwner {
+ _applyAllowListUpdates(removes, adds);
+ }
+
+ /// @notice Internal version of applyAllowListUpdates to allow for reuse in the constructor.
+ function _applyAllowListUpdates(address[] memory removes, address[] memory adds) internal {
+ if (!i_allowlistEnabled) revert AllowListNotEnabled();
+
+ for (uint256 i = 0; i < removes.length; ++i) {
+ address toRemove = removes[i];
+ if (s_allowList.remove(toRemove)) {
+ emit AllowListRemove(toRemove);
+ }
+ }
+ for (uint256 i = 0; i < adds.length; ++i) {
+ address toAdd = adds[i];
+ if (toAdd == address(0)) {
+ continue;
+ }
+ if (s_allowList.add(toAdd)) {
+ emit AllowListAdd(toAdd);
+ }
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/OCR2Helper.sol b/contracts/src/v0.8/ccip/test/helpers/OCR2Helper.sol
new file mode 100644
index 00000000000..cb66352ff65
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/OCR2Helper.sol
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {OCR2Base} from "../../ocr/OCR2Base.sol";
+
+contract OCR2Helper is OCR2Base(false) {
+ function configDigestFromConfigData(
+ uint256 chainSelector,
+ address contractAddress,
+ uint64 configCount,
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) public pure returns (bytes32) {
+ return _configDigestFromConfigData(
+ chainSelector,
+ contractAddress,
+ configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+ }
+
+ function _report(bytes calldata report, uint40 epochAndRound) internal override {}
+
+ function typeAndVersion() public pure override returns (string memory) {
+ return "OCR2BaseHelper 1.0.0";
+ }
+
+ function _beforeSetConfig(bytes memory _onchainConfig) internal override {}
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/OCR2NoChecksHelper.sol b/contracts/src/v0.8/ccip/test/helpers/OCR2NoChecksHelper.sol
new file mode 100644
index 00000000000..a1ececa326f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/OCR2NoChecksHelper.sol
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {OCR2BaseNoChecks} from "../../ocr/OCR2BaseNoChecks.sol";
+
+contract OCR2NoChecksHelper is OCR2BaseNoChecks {
+ function configDigestFromConfigData(
+ uint256 chainSelector,
+ address contractAddress,
+ uint64 configCount,
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) public pure returns (bytes32) {
+ return _configDigestFromConfigData(
+ chainSelector,
+ contractAddress,
+ configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+ }
+
+ function _report(bytes calldata report) internal override {}
+
+ function typeAndVersion() public pure override returns (string memory) {
+ return "OCR2BaseHelper 1.0.0";
+ }
+
+ function _beforeSetConfig(bytes memory _onchainConfig) internal override {}
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/PriceRegistryHelper.sol b/contracts/src/v0.8/ccip/test/helpers/PriceRegistryHelper.sol
new file mode 100644
index 00000000000..8524df12ccf
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/PriceRegistryHelper.sol
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {PriceRegistry} from "../../PriceRegistry.sol";
+import {Client} from "../../libraries/Client.sol";
+
+contract PriceRegistryHelper is PriceRegistry {
+ constructor(
+ StaticConfig memory staticConfig,
+ address[] memory priceUpdaters,
+ address[] memory feeTokens,
+ TokenPriceFeedUpdate[] memory tokenPriceFeeds,
+ TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs,
+ PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs,
+ DestChainConfigArgs[] memory destChainConfigArgs
+ )
+ PriceRegistry(
+ staticConfig,
+ priceUpdaters,
+ feeTokens,
+ tokenPriceFeeds,
+ tokenTransferFeeConfigArgs,
+ premiumMultiplierWeiPerEthArgs,
+ destChainConfigArgs
+ )
+ {}
+
+ function getDataAvailabilityCost(
+ uint64 destChainSelector,
+ uint112 dataAvailabilityGasPrice,
+ uint256 messageDataLength,
+ uint256 numberOfTokens,
+ uint32 tokenTransferBytesOverhead
+ ) external view returns (uint256) {
+ return _getDataAvailabilityCost(
+ s_destChainConfigs[destChainSelector],
+ dataAvailabilityGasPrice,
+ messageDataLength,
+ numberOfTokens,
+ tokenTransferBytesOverhead
+ );
+ }
+
+ function getTokenTransferCost(
+ uint64 destChainSelector,
+ address feeToken,
+ uint224 feeTokenPrice,
+ Client.EVMTokenAmount[] calldata tokenAmounts
+ ) external view returns (uint256, uint32, uint32) {
+ return _getTokenTransferCost(
+ s_destChainConfigs[destChainSelector], destChainSelector, feeToken, feeTokenPrice, tokenAmounts
+ );
+ }
+
+ function parseEVMExtraArgsFromBytes(
+ bytes calldata extraArgs,
+ uint64 destChainSelector
+ ) external view returns (Client.EVMExtraArgsV2 memory) {
+ return _parseEVMExtraArgsFromBytes(extraArgs, s_destChainConfigs[destChainSelector]);
+ }
+
+ function parseEVMExtraArgsFromBytes(
+ bytes calldata extraArgs,
+ DestChainConfig memory destChainConfig
+ ) external pure returns (Client.EVMExtraArgsV2 memory) {
+ return _parseEVMExtraArgsFromBytes(extraArgs, destChainConfig);
+ }
+
+ function validateDestFamilyAddress(bytes4 chainFamilySelector, bytes memory destAddress) external pure {
+ _validateDestFamilyAddress(chainFamilySelector, destAddress);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/RateLimiterHelper.sol b/contracts/src/v0.8/ccip/test/helpers/RateLimiterHelper.sol
new file mode 100644
index 00000000000..8fb96a0c1c3
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/RateLimiterHelper.sol
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+
+contract RateLimiterHelper {
+ using RateLimiter for RateLimiter.TokenBucket;
+
+ RateLimiter.TokenBucket internal s_rateLimiter;
+
+ constructor(RateLimiter.Config memory config) {
+ s_rateLimiter = RateLimiter.TokenBucket({
+ rate: config.rate,
+ capacity: config.capacity,
+ tokens: config.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: config.isEnabled
+ });
+ }
+
+ function consume(uint256 requestTokens, address tokenAddress) external {
+ s_rateLimiter._consume(requestTokens, tokenAddress);
+ }
+
+ function currentTokenBucketState() external view returns (RateLimiter.TokenBucket memory) {
+ return s_rateLimiter._currentTokenBucketState();
+ }
+
+ function setTokenBucketConfig(RateLimiter.Config memory config) external {
+ s_rateLimiter._setTokenBucketConfig(config);
+ }
+
+ function getRateLimiter() external view returns (RateLimiter.TokenBucket memory) {
+ return s_rateLimiter;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/ReportCodec.sol b/contracts/src/v0.8/ccip/test/helpers/ReportCodec.sol
new file mode 100644
index 00000000000..ca53d512c0d
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/ReportCodec.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {Internal} from "../../libraries/Internal.sol";
+import {EVM2EVMMultiOffRamp} from "../../offRamp/EVM2EVMMultiOffRamp.sol";
+
+contract ReportCodec {
+ event ExecuteReportDecoded(Internal.ExecutionReportSingleChain[] report);
+ event CommitReportDecoded(EVM2EVMMultiOffRamp.CommitReport report);
+
+ function decodeExecuteReport(bytes memory report) public pure returns (Internal.ExecutionReportSingleChain[] memory) {
+ return abi.decode(report, (Internal.ExecutionReportSingleChain[]));
+ }
+
+ function decodeCommitReport(bytes memory report) public pure returns (EVM2EVMMultiOffRamp.CommitReport memory) {
+ return abi.decode(report, (EVM2EVMMultiOffRamp.CommitReport));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/TokenPoolHelper.sol b/contracts/src/v0.8/ccip/test/helpers/TokenPoolHelper.sol
new file mode 100644
index 00000000000..c57bfa33119
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/TokenPoolHelper.sol
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Pool} from "../../libraries/Pool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract TokenPoolHelper is TokenPool {
+ constructor(
+ IERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) TokenPool(token, allowlist, rmnProxy, router) {}
+
+ function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
+ external
+ view
+ override
+ returns (Pool.LockOrBurnOutV1 memory)
+ {
+ return Pool.LockOrBurnOutV1({destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: ""});
+ }
+
+ function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
+ external
+ pure
+ override
+ returns (Pool.ReleaseOrMintOutV1 memory)
+ {
+ return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
+ }
+
+ function onlyOnRampModifier(uint64 remoteChainSelector) external view {
+ _onlyOnRamp(remoteChainSelector);
+ }
+
+ function onlyOffRampModifier(uint64 remoteChainSelector) external view {
+ _onlyOffRamp(remoteChainSelector);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/USDCTokenPoolHelper.sol b/contracts/src/v0.8/ccip/test/helpers/USDCTokenPoolHelper.sol
new file mode 100644
index 00000000000..7a3400588a8
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/USDCTokenPoolHelper.sol
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
+
+import {ITokenMessenger} from "../../pools/USDC/ITokenMessenger.sol";
+import {USDCTokenPool} from "../../pools/USDC/USDCTokenPool.sol";
+
+contract USDCTokenPoolHelper is USDCTokenPool {
+ constructor(
+ ITokenMessenger tokenMessenger,
+ IBurnMintERC20 token,
+ address[] memory allowlist,
+ address rmnProxy,
+ address router
+ ) USDCTokenPool(tokenMessenger, token, allowlist, rmnProxy, router) {}
+
+ function validateMessage(bytes memory usdcMessage, SourceTokenDataPayload memory sourceTokenData) external view {
+ return _validateMessage(usdcMessage, sourceTokenData);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/receivers/ConformingReceiver.sol b/contracts/src/v0.8/ccip/test/helpers/receivers/ConformingReceiver.sol
new file mode 100644
index 00000000000..159cd7a8514
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/receivers/ConformingReceiver.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {CCIPReceiver} from "../../../applications/CCIPReceiver.sol";
+import {Client} from "../../../libraries/Client.sol";
+
+contract ConformingReceiver is CCIPReceiver {
+ event MessageReceived();
+
+ constructor(address router, address feeToken) CCIPReceiver(router) {}
+
+ function _ccipReceive(Client.Any2EVMMessage memory) internal virtual override {
+ emit MessageReceived();
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol b/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol
new file mode 100644
index 00000000000..dd65f202dfe
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IAny2EVMMessageReceiver} from "../../../interfaces/IAny2EVMMessageReceiver.sol";
+import {Client} from "../../../libraries/Client.sol";
+
+import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+
+contract MaybeRevertMessageReceiver is IAny2EVMMessageReceiver, IERC165 {
+ error ReceiveRevert();
+ error CustomError(bytes err);
+
+ event ValueReceived(uint256 amount);
+ event MessageReceived();
+
+ address private s_manager;
+ bool public s_toRevert;
+ bytes private s_err;
+
+ constructor(bool toRevert) {
+ s_manager = msg.sender;
+ s_toRevert = toRevert;
+ }
+
+ function setRevert(bool toRevert) external {
+ s_toRevert = toRevert;
+ }
+
+ function setErr(bytes memory err) external {
+ s_err = err;
+ }
+
+ /// @notice IERC165 supports an interfaceId
+ /// @param interfaceId The interfaceId to check
+ /// @return true if the interfaceId is supported
+ function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
+ return interfaceId == type(IAny2EVMMessageReceiver).interfaceId || interfaceId == type(IERC165).interfaceId;
+ }
+
+ function ccipReceive(Client.Any2EVMMessage calldata) external override {
+ if (s_toRevert) {
+ revert CustomError(s_err);
+ }
+ emit MessageReceived();
+ }
+
+ receive() external payable {
+ if (s_toRevert) {
+ revert ReceiveRevert();
+ }
+
+ emit ValueReceived(msg.value);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiverNo165.sol b/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiverNo165.sol
new file mode 100644
index 00000000000..4f56394c4e5
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/receivers/MaybeRevertMessageReceiverNo165.sol
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import "../../../interfaces/IAny2EVMMessageReceiver.sol";
+
+contract MaybeRevertMessageReceiverNo165 is IAny2EVMMessageReceiver {
+ address private s_manager;
+ bool public s_toRevert;
+
+ event MessageReceived();
+
+ constructor(bool toRevert) {
+ s_manager = msg.sender;
+ s_toRevert = toRevert;
+ }
+
+ function setRevert(bool toRevert) external {
+ s_toRevert = toRevert;
+ }
+
+ function ccipReceive(Client.Any2EVMMessage calldata) external override {
+ if (s_toRevert) {
+ revert();
+ }
+ emit MessageReceived();
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/receivers/ReentrancyAbuser.sol b/contracts/src/v0.8/ccip/test/helpers/receivers/ReentrancyAbuser.sol
new file mode 100644
index 00000000000..ae8759099cd
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/receivers/ReentrancyAbuser.sol
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {CCIPReceiver} from "../../../applications/CCIPReceiver.sol";
+import {Client} from "../../../libraries/Client.sol";
+import {Internal} from "../../../libraries/Internal.sol";
+import {EVM2EVMOffRamp} from "../../../offRamp/EVM2EVMOffRamp.sol";
+
+contract ReentrancyAbuser is CCIPReceiver {
+ event ReentrancySucceeded();
+
+ bool internal s_ReentrancyDone = false;
+ Internal.ExecutionReport internal s_payload;
+ EVM2EVMOffRamp internal s_offRamp;
+
+ constructor(address router, EVM2EVMOffRamp offRamp) CCIPReceiver(router) {
+ s_offRamp = offRamp;
+ }
+
+ function setPayload(Internal.ExecutionReport calldata payload) public {
+ s_payload = payload;
+ }
+
+ function _ccipReceive(Client.Any2EVMMessage memory) internal override {
+ // Use original message gas limits in manual execution
+ uint256 numMsgs = s_payload.messages.length;
+ uint256[] memory gasOverrides = new uint256[](numMsgs);
+ for (uint256 i = 0; i < numMsgs; ++i) {
+ gasOverrides[i] = 0;
+ }
+
+ if (!s_ReentrancyDone) {
+ // Could do more rounds but a PoC one is enough
+ s_ReentrancyDone = true;
+ s_offRamp.manuallyExecute(s_payload, gasOverrides);
+ } else {
+ emit ReentrancySucceeded();
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/helpers/receivers/ReentrancyAbuserMultiRamp.sol b/contracts/src/v0.8/ccip/test/helpers/receivers/ReentrancyAbuserMultiRamp.sol
new file mode 100644
index 00000000000..c9e7d7e8ad6
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/helpers/receivers/ReentrancyAbuserMultiRamp.sol
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.19;
+
+import {CCIPReceiver} from "../../../applications/CCIPReceiver.sol";
+import {Client} from "../../../libraries/Client.sol";
+import {Internal} from "../../../libraries/Internal.sol";
+import {EVM2EVMMultiOffRamp} from "../../../offRamp/EVM2EVMMultiOffRamp.sol";
+
+contract ReentrancyAbuserMultiRamp is CCIPReceiver {
+ event ReentrancySucceeded();
+
+ bool internal s_ReentrancyDone = false;
+ Internal.ExecutionReportSingleChain internal s_payload;
+ EVM2EVMMultiOffRamp internal s_offRamp;
+
+ constructor(address router, EVM2EVMMultiOffRamp offRamp) CCIPReceiver(router) {
+ s_offRamp = offRamp;
+ }
+
+ function setPayload(Internal.ExecutionReportSingleChain calldata payload) public {
+ s_payload = payload;
+ }
+
+ function _ccipReceive(Client.Any2EVMMessage memory) internal override {
+ // Use original message gas limits in manual execution
+ uint256 numMsgs = s_payload.messages.length;
+ uint256[][] memory gasOverrides = new uint256[][](1);
+ gasOverrides[0] = new uint256[](numMsgs);
+ for (uint256 i = 0; i < numMsgs; ++i) {
+ gasOverrides[0][i] = 0;
+ }
+
+ Internal.ExecutionReportSingleChain[] memory batchPayload = new Internal.ExecutionReportSingleChain[](1);
+ batchPayload[0] = s_payload;
+
+ if (!s_ReentrancyDone) {
+ // Could do more rounds but a PoC one is enough
+ s_ReentrancyDone = true;
+ s_offRamp.manuallyExecute(batchPayload, gasOverrides);
+ } else {
+ emit ReentrancySucceeded();
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/legacy/BurnMintTokenPool1_2.sol b/contracts/src/v0.8/ccip/test/legacy/BurnMintTokenPool1_2.sol
new file mode 100644
index 00000000000..2e7878730ea
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/legacy/BurnMintTokenPool1_2.sol
@@ -0,0 +1,353 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity ^0.8.0;
+
+import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol";
+import {IPoolPriorTo1_5} from "../../interfaces/IPoolPriorTo1_5.sol";
+import {IRMN} from "../../interfaces/IRMN.sol";
+
+import {OwnerIsCreator} from "../../../shared/access/OwnerIsCreator.sol";
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @notice Base abstract class with common functions for all token pools.
+/// A token pool serves as isolated place for holding tokens and token specific logic
+/// that may execute as tokens move across the bridge.
+abstract contract TokenPool1_2 is IPoolPriorTo1_5, OwnerIsCreator, IERC165 {
+ using EnumerableSet for EnumerableSet.AddressSet;
+ using RateLimiter for RateLimiter.TokenBucket;
+
+ error PermissionsError();
+ error ZeroAddressNotAllowed();
+ error SenderNotAllowed(address sender);
+ error AllowListNotEnabled();
+ error NonExistentRamp(address ramp);
+ error BadARMSignal();
+ error RampAlreadyExists(address ramp);
+
+ event Locked(address indexed sender, uint256 amount);
+ event Burned(address indexed sender, uint256 amount);
+ event Released(address indexed sender, address indexed recipient, uint256 amount);
+ event Minted(address indexed sender, address indexed recipient, uint256 amount);
+ event OnRampAdded(address onRamp, RateLimiter.Config rateLimiterConfig);
+ event OnRampConfigured(address onRamp, RateLimiter.Config rateLimiterConfig);
+ event OnRampRemoved(address onRamp);
+ event OffRampAdded(address offRamp, RateLimiter.Config rateLimiterConfig);
+ event OffRampConfigured(address offRamp, RateLimiter.Config rateLimiterConfig);
+ event OffRampRemoved(address offRamp);
+ event AllowListAdd(address sender);
+ event AllowListRemove(address sender);
+
+ struct RampUpdate {
+ address ramp;
+ bool allowed;
+ RateLimiter.Config rateLimiterConfig;
+ }
+
+ /// @dev The bridgeable token that is managed by this pool.
+ IERC20 internal immutable i_token;
+ /// @dev The address of the arm proxy
+ address internal immutable i_armProxy;
+ /// @dev The immutable flag that indicates if the pool is access-controlled.
+ bool internal immutable i_allowlistEnabled;
+ /// @dev A set of addresses allowed to trigger lockOrBurn as original senders.
+ /// Only takes effect if i_allowlistEnabled is true.
+ /// This can be used to ensure only token-issuer specified addresses can
+ /// move tokens.
+ EnumerableSet.AddressSet internal s_allowList;
+
+ /// @dev A set of allowed onRamps. We want the whitelist to be enumerable to
+ /// be able to quickly determine (without parsing logs) who can access the pool.
+ EnumerableSet.AddressSet internal s_onRamps;
+ /// @dev Inbound rate limits. This allows per destination chain
+ /// token issuer specified rate limiting (e.g. issuers may trust chains to varying
+ /// degrees and prefer different limits)
+ mapping(address => RateLimiter.TokenBucket) internal s_onRampRateLimits;
+ /// @dev A set of allowed offRamps.
+ EnumerableSet.AddressSet internal s_offRamps;
+ /// @dev Outbound rate limits. Corresponds to the inbound rate limit for the pool
+ /// on the remote chain.
+ mapping(address => RateLimiter.TokenBucket) internal s_offRampRateLimits;
+
+ constructor(IERC20 token, address[] memory allowlist, address armProxy) {
+ if (address(token) == address(0)) revert ZeroAddressNotAllowed();
+ i_token = token;
+ i_armProxy = armProxy;
+
+ // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas.
+ i_allowlistEnabled = allowlist.length > 0;
+ if (i_allowlistEnabled) {
+ _applyAllowListUpdates(new address[](0), allowlist);
+ }
+ }
+
+ /// @notice Get ARM proxy address
+ /// @return armProxy Address of arm proxy
+ function getArmProxy() public view returns (address armProxy) {
+ return i_armProxy;
+ }
+
+ /// @inheritdoc IPoolPriorTo1_5
+ function getToken() public view override returns (IERC20 token) {
+ return i_token;
+ }
+
+ /// @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
+ return interfaceId == type(IPoolPriorTo1_5).interfaceId || interfaceId == type(IERC165).interfaceId;
+ }
+
+ // ================================================================
+ // │ Ramp permissions │
+ // ================================================================
+
+ /// @notice Checks whether something is a permissioned onRamp on this contract.
+ /// @return true if the given address is a permissioned onRamp.
+ function isOnRamp(address onRamp) public view returns (bool) {
+ return s_onRamps.contains(onRamp);
+ }
+
+ /// @notice Checks whether something is a permissioned offRamp on this contract.
+ /// @return true if the given address is a permissioned offRamp.
+ function isOffRamp(address offRamp) public view returns (bool) {
+ return s_offRamps.contains(offRamp);
+ }
+
+ /// @notice Get onRamp whitelist
+ /// @return list of onRamps.
+ function getOnRamps() public view returns (address[] memory) {
+ return s_onRamps.values();
+ }
+
+ /// @notice Get offRamp whitelist
+ /// @return list of offramps
+ function getOffRamps() public view returns (address[] memory) {
+ return s_offRamps.values();
+ }
+
+ /// @notice Sets permissions for all on and offRamps.
+ /// @dev Only callable by the owner
+ /// @param onRamps A list of onRamps and their new permission status/rate limits
+ /// @param offRamps A list of offRamps and their new permission status/rate limits
+ function applyRampUpdates(RampUpdate[] calldata onRamps, RampUpdate[] calldata offRamps) external virtual onlyOwner {
+ _applyRampUpdates(onRamps, offRamps);
+ }
+
+ function _applyRampUpdates(RampUpdate[] calldata onRamps, RampUpdate[] calldata offRamps) internal onlyOwner {
+ for (uint256 i = 0; i < onRamps.length; ++i) {
+ RampUpdate memory update = onRamps[i];
+ if (update.allowed) {
+ if (s_onRamps.add(update.ramp)) {
+ s_onRampRateLimits[update.ramp] = RateLimiter.TokenBucket({
+ rate: update.rateLimiterConfig.rate,
+ capacity: update.rateLimiterConfig.capacity,
+ tokens: update.rateLimiterConfig.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: update.rateLimiterConfig.isEnabled
+ });
+ emit OnRampAdded(update.ramp, update.rateLimiterConfig);
+ } else {
+ revert RampAlreadyExists(update.ramp);
+ }
+ } else {
+ if (s_onRamps.remove(update.ramp)) {
+ delete s_onRampRateLimits[update.ramp];
+ emit OnRampRemoved(update.ramp);
+ } else {
+ // Cannot remove a non-existent onRamp.
+ revert NonExistentRamp(update.ramp);
+ }
+ }
+ }
+
+ for (uint256 i = 0; i < offRamps.length; ++i) {
+ RampUpdate memory update = offRamps[i];
+ if (update.allowed) {
+ if (s_offRamps.add(update.ramp)) {
+ s_offRampRateLimits[update.ramp] = RateLimiter.TokenBucket({
+ rate: update.rateLimiterConfig.rate,
+ capacity: update.rateLimiterConfig.capacity,
+ tokens: update.rateLimiterConfig.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: update.rateLimiterConfig.isEnabled
+ });
+ emit OffRampAdded(update.ramp, update.rateLimiterConfig);
+ } else {
+ revert RampAlreadyExists(update.ramp);
+ }
+ } else {
+ if (s_offRamps.remove(update.ramp)) {
+ delete s_offRampRateLimits[update.ramp];
+ emit OffRampRemoved(update.ramp);
+ } else {
+ // Cannot remove a non-existent offRamp.
+ revert NonExistentRamp(update.ramp);
+ }
+ }
+ }
+ }
+
+ // ================================================================
+ // │ Rate limiting │
+ // ================================================================
+
+ /// @notice Consumes outbound rate limiting capacity in this pool
+ function _consumeOnRampRateLimit(uint256 amount) internal {
+ s_onRampRateLimits[msg.sender]._consume(amount, address(i_token));
+ }
+
+ /// @notice Consumes inbound rate limiting capacity in this pool
+ function _consumeOffRampRateLimit(uint256 amount) internal {
+ s_offRampRateLimits[msg.sender]._consume(amount, address(i_token));
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function currentOnRampRateLimiterState(address onRamp) external view returns (RateLimiter.TokenBucket memory) {
+ return s_onRampRateLimits[onRamp]._currentTokenBucketState();
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function currentOffRampRateLimiterState(address offRamp) external view returns (RateLimiter.TokenBucket memory) {
+ return s_offRampRateLimits[offRamp]._currentTokenBucketState();
+ }
+
+ /// @notice Sets the onramp rate limited config.
+ /// @param config The new rate limiter config.
+ function setOnRampRateLimiterConfig(address onRamp, RateLimiter.Config memory config) external onlyOwner {
+ if (!isOnRamp(onRamp)) revert NonExistentRamp(onRamp);
+ s_onRampRateLimits[onRamp]._setTokenBucketConfig(config);
+ emit OnRampConfigured(onRamp, config);
+ }
+
+ /// @notice Sets the offramp rate limited config.
+ /// @param config The new rate limiter config.
+ function setOffRampRateLimiterConfig(address offRamp, RateLimiter.Config memory config) external onlyOwner {
+ if (!isOffRamp(offRamp)) revert NonExistentRamp(offRamp);
+ s_offRampRateLimits[offRamp]._setTokenBucketConfig(config);
+ emit OffRampConfigured(offRamp, config);
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @notice Checks whether the msg.sender is a permissioned onRamp on this contract
+ /// @dev Reverts with a PermissionsError if check fails
+ modifier onlyOnRamp() {
+ if (!isOnRamp(msg.sender)) revert PermissionsError();
+ _;
+ }
+
+ /// @notice Checks whether the msg.sender is a permissioned offRamp on this contract
+ /// @dev Reverts with a PermissionsError if check fails
+ modifier onlyOffRamp() {
+ if (!isOffRamp(msg.sender)) revert PermissionsError();
+ _;
+ }
+
+ // ================================================================
+ // │ Allowlist │
+ // ================================================================
+
+ modifier checkAllowList(address sender) {
+ if (i_allowlistEnabled && !s_allowList.contains(sender)) revert SenderNotAllowed(sender);
+ _;
+ }
+
+ /// @notice Gets whether the allowList functionality is enabled.
+ /// @return true is enabled, false if not.
+ function getAllowListEnabled() external view returns (bool) {
+ return i_allowlistEnabled;
+ }
+
+ /// @notice Gets the allowed addresses.
+ /// @return The allowed addresses.
+ function getAllowList() external view returns (address[] memory) {
+ return s_allowList.values();
+ }
+
+ /// @notice Apply updates to the allow list.
+ /// @param removes The addresses to be removed.
+ /// @param adds The addresses to be added.
+ /// @dev allowListing will be removed before public launch
+ function applyAllowListUpdates(address[] calldata removes, address[] calldata adds) external onlyOwner {
+ _applyAllowListUpdates(removes, adds);
+ }
+
+ /// @notice Internal version of applyAllowListUpdates to allow for reuse in the constructor.
+ function _applyAllowListUpdates(address[] memory removes, address[] memory adds) internal {
+ if (!i_allowlistEnabled) revert AllowListNotEnabled();
+
+ for (uint256 i = 0; i < removes.length; ++i) {
+ address toRemove = removes[i];
+ if (s_allowList.remove(toRemove)) {
+ emit AllowListRemove(toRemove);
+ }
+ }
+ for (uint256 i = 0; i < adds.length; ++i) {
+ address toAdd = adds[i];
+ if (toAdd == address(0)) {
+ continue;
+ }
+ if (s_allowList.add(toAdd)) {
+ emit AllowListAdd(toAdd);
+ }
+ }
+ }
+
+ /// @notice Ensure that there is no active curse.
+ modifier whenHealthy() {
+ if (IRMN(i_armProxy).isCursed()) revert BadARMSignal();
+ _;
+ }
+}
+
+contract BurnMintTokenPool1_2 is ITypeAndVersion, TokenPool1_2 {
+ // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables
+ string public constant override typeAndVersion = "BurnMintTokenPool 1.2.0";
+
+ constructor(
+ IBurnMintERC20 token,
+ address[] memory allowlist,
+ address armProxy
+ ) TokenPool1_2(token, allowlist, armProxy) {}
+
+ /// @notice Burn the token in the pool
+ /// @param amount Amount to burn
+ /// @dev The whenHealthy check is important to ensure that even if a ramp is compromised
+ /// we're able to stop token movement via ARM.
+ function lockOrBurn(
+ address originalSender,
+ bytes calldata,
+ uint256 amount,
+ uint64,
+ bytes calldata
+ ) external virtual override onlyOnRamp checkAllowList(originalSender) whenHealthy returns (bytes memory) {
+ _consumeOnRampRateLimit(amount);
+ IBurnMintERC20(address(i_token)).burn(amount);
+ emit Burned(msg.sender, amount);
+ return "";
+ }
+
+ /// @notice Mint tokens from the pool to the recipient
+ /// @param receiver Recipient address
+ /// @param amount Amount to mint
+ /// @dev The whenHealthy check is important to ensure that even if a ramp is compromised
+ /// we're able to stop token movement via ARM.
+ function releaseOrMint(
+ bytes memory,
+ address receiver,
+ uint256 amount,
+ uint64,
+ bytes memory
+ ) external virtual override whenHealthy onlyOffRamp {
+ _consumeOffRampRateLimit(amount);
+ IBurnMintERC20(address(i_token)).mint(receiver, amount);
+ emit Minted(msg.sender, receiver, amount);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/legacy/BurnMintTokenPool1_4.sol b/contracts/src/v0.8/ccip/test/legacy/BurnMintTokenPool1_4.sol
new file mode 100644
index 00000000000..9ac5d66b1cf
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/legacy/BurnMintTokenPool1_4.sol
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol";
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
+import {IPoolPriorTo1_5} from "../../interfaces/IPoolPriorTo1_5.sol";
+import {IRMN} from "../../interfaces/IRMN.sol";
+import {IRouter} from "../../interfaces/IRouter.sol";
+
+import {OwnerIsCreator} from "../../../shared/access/OwnerIsCreator.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @notice Base abstract class with common functions for all token pools.
+/// A token pool serves as isolated place for holding tokens and token specific logic
+/// that may execute as tokens move across the bridge.
+abstract contract TokenPool1_4 is IPoolPriorTo1_5, OwnerIsCreator, IERC165 {
+ using EnumerableSet for EnumerableSet.AddressSet;
+ using EnumerableSet for EnumerableSet.UintSet;
+ using RateLimiter for RateLimiter.TokenBucket;
+
+ error CallerIsNotARampOnRouter(address caller);
+ error ZeroAddressNotAllowed();
+ error SenderNotAllowed(address sender);
+ error AllowListNotEnabled();
+ error NonExistentChain(uint64 remoteChainSelector);
+ error ChainNotAllowed(uint64 remoteChainSelector);
+ error BadARMSignal();
+ error ChainAlreadyExists(uint64 chainSelector);
+
+ event Locked(address indexed sender, uint256 amount);
+ event Burned(address indexed sender, uint256 amount);
+ event Released(address indexed sender, address indexed recipient, uint256 amount);
+ event Minted(address indexed sender, address indexed recipient, uint256 amount);
+ event ChainAdded(
+ uint64 remoteChainSelector,
+ RateLimiter.Config outboundRateLimiterConfig,
+ RateLimiter.Config inboundRateLimiterConfig
+ );
+ event ChainConfigured(
+ uint64 remoteChainSelector,
+ RateLimiter.Config outboundRateLimiterConfig,
+ RateLimiter.Config inboundRateLimiterConfig
+ );
+ event ChainRemoved(uint64 remoteChainSelector);
+ event AllowListAdd(address sender);
+ event AllowListRemove(address sender);
+ event RouterUpdated(address oldRouter, address newRouter);
+
+ struct ChainUpdate {
+ uint64 remoteChainSelector; // ──╮ Remote chain selector
+ bool allowed; // ────────────────╯ Whether the chain is allowed
+ RateLimiter.Config outboundRateLimiterConfig; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain
+ RateLimiter.Config inboundRateLimiterConfig; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain
+ }
+
+ /// @dev The bridgeable token that is managed by this pool.
+ IERC20 internal immutable i_token;
+ /// @dev The address of the arm proxy
+ address internal immutable i_armProxy;
+ /// @dev The immutable flag that indicates if the pool is access-controlled.
+ bool internal immutable i_allowlistEnabled;
+ /// @dev A set of addresses allowed to trigger lockOrBurn as original senders.
+ /// Only takes effect if i_allowlistEnabled is true.
+ /// This can be used to ensure only token-issuer specified addresses can
+ /// move tokens.
+ EnumerableSet.AddressSet internal s_allowList;
+ /// @dev The address of the router
+ IRouter internal s_router;
+ /// @dev A set of allowed chain selectors. We want the allowlist to be enumerable to
+ /// be able to quickly determine (without parsing logs) who can access the pool.
+ /// @dev The chain selectors are in uin256 format because of the EnumerableSet implementation.
+ EnumerableSet.UintSet internal s_remoteChainSelectors;
+ /// @dev Outbound rate limits. Corresponds to the inbound rate limit for the pool
+ /// on the remote chain.
+ mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) internal s_outboundRateLimits;
+ /// @dev Inbound rate limits. This allows per destination chain
+ /// token issuer specified rate limiting (e.g. issuers may trust chains to varying
+ /// degrees and prefer different limits)
+ mapping(uint64 remoteChainSelector => RateLimiter.TokenBucket) internal s_inboundRateLimits;
+
+ constructor(IERC20 token, address[] memory allowlist, address armProxy, address router) {
+ if (address(token) == address(0) || router == address(0)) revert ZeroAddressNotAllowed();
+ i_token = token;
+ i_armProxy = armProxy;
+ s_router = IRouter(router);
+
+ // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas.
+ i_allowlistEnabled = allowlist.length > 0;
+ if (i_allowlistEnabled) {
+ _applyAllowListUpdates(new address[](0), allowlist);
+ }
+ }
+
+ /// @notice Get ARM proxy address
+ /// @return armProxy Address of arm proxy
+ function getArmProxy() public view returns (address armProxy) {
+ return i_armProxy;
+ }
+
+ /// @inheritdoc IPoolPriorTo1_5
+ function getToken() public view override returns (IERC20 token) {
+ return i_token;
+ }
+
+ /// @notice Gets the pool's Router
+ /// @return router The pool's Router
+ function getRouter() public view returns (address router) {
+ return address(s_router);
+ }
+
+ /// @notice Sets the pool's Router
+ /// @param newRouter The new Router
+ function setRouter(address newRouter) public onlyOwner {
+ if (newRouter == address(0)) revert ZeroAddressNotAllowed();
+ address oldRouter = address(s_router);
+ s_router = IRouter(newRouter);
+
+ emit RouterUpdated(oldRouter, newRouter);
+ }
+
+ /// @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
+ return interfaceId == type(IPoolPriorTo1_5).interfaceId || interfaceId == type(IERC165).interfaceId;
+ }
+
+ // ================================================================
+ // │ Chain permissions │
+ // ================================================================
+
+ /// @notice Checks whether a chain selector is permissioned on this contract.
+ /// @return true if the given chain selector is a permissioned remote chain.
+ function isSupportedChain(uint64 remoteChainSelector) public view returns (bool) {
+ return s_remoteChainSelectors.contains(remoteChainSelector);
+ }
+
+ /// @notice Get list of allowed chains
+ /// @return list of chains.
+ function getSupportedChains() public view returns (uint64[] memory) {
+ uint256[] memory uint256ChainSelectors = s_remoteChainSelectors.values();
+ uint64[] memory chainSelectors = new uint64[](uint256ChainSelectors.length);
+ for (uint256 i = 0; i < uint256ChainSelectors.length; ++i) {
+ chainSelectors[i] = uint64(uint256ChainSelectors[i]);
+ }
+
+ return chainSelectors;
+ }
+
+ /// @notice Sets the permissions for a list of chains selectors. Actual senders for these chains
+ /// need to be allowed on the Router to interact with this pool.
+ /// @dev Only callable by the owner
+ /// @param chains A list of chains and their new permission status & rate limits. Rate limits
+ /// are only used when the chain is being added through `allowed` being true.
+ function applyChainUpdates(ChainUpdate[] calldata chains) external virtual onlyOwner {
+ for (uint256 i = 0; i < chains.length; ++i) {
+ ChainUpdate memory update = chains[i];
+ RateLimiter._validateTokenBucketConfig(update.outboundRateLimiterConfig, !update.allowed);
+ RateLimiter._validateTokenBucketConfig(update.inboundRateLimiterConfig, !update.allowed);
+
+ if (update.allowed) {
+ // If the chain already exists, revert
+ if (!s_remoteChainSelectors.add(update.remoteChainSelector)) {
+ revert ChainAlreadyExists(update.remoteChainSelector);
+ }
+
+ s_outboundRateLimits[update.remoteChainSelector] = RateLimiter.TokenBucket({
+ rate: update.outboundRateLimiterConfig.rate,
+ capacity: update.outboundRateLimiterConfig.capacity,
+ tokens: update.outboundRateLimiterConfig.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: update.outboundRateLimiterConfig.isEnabled
+ });
+
+ s_inboundRateLimits[update.remoteChainSelector] = RateLimiter.TokenBucket({
+ rate: update.inboundRateLimiterConfig.rate,
+ capacity: update.inboundRateLimiterConfig.capacity,
+ tokens: update.inboundRateLimiterConfig.capacity,
+ lastUpdated: uint32(block.timestamp),
+ isEnabled: update.inboundRateLimiterConfig.isEnabled
+ });
+ emit ChainAdded(update.remoteChainSelector, update.outboundRateLimiterConfig, update.inboundRateLimiterConfig);
+ } else {
+ // If the chain doesn't exist, revert
+ if (!s_remoteChainSelectors.remove(update.remoteChainSelector)) {
+ revert NonExistentChain(update.remoteChainSelector);
+ }
+
+ delete s_inboundRateLimits[update.remoteChainSelector];
+ delete s_outboundRateLimits[update.remoteChainSelector];
+ emit ChainRemoved(update.remoteChainSelector);
+ }
+ }
+ }
+
+ // ================================================================
+ // │ Rate limiting │
+ // ================================================================
+
+ /// @notice Consumes outbound rate limiting capacity in this pool
+ function _consumeOutboundRateLimit(uint64 remoteChainSelector, uint256 amount) internal {
+ s_outboundRateLimits[remoteChainSelector]._consume(amount, address(i_token));
+ }
+
+ /// @notice Consumes inbound rate limiting capacity in this pool
+ function _consumeInboundRateLimit(uint64 remoteChainSelector, uint256 amount) internal {
+ s_inboundRateLimits[remoteChainSelector]._consume(amount, address(i_token));
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function getCurrentOutboundRateLimiterState(uint64 remoteChainSelector)
+ external
+ view
+ returns (RateLimiter.TokenBucket memory)
+ {
+ return s_outboundRateLimits[remoteChainSelector]._currentTokenBucketState();
+ }
+
+ /// @notice Gets the token bucket with its values for the block it was requested at.
+ /// @return The token bucket.
+ function getCurrentInboundRateLimiterState(uint64 remoteChainSelector)
+ external
+ view
+ returns (RateLimiter.TokenBucket memory)
+ {
+ return s_inboundRateLimits[remoteChainSelector]._currentTokenBucketState();
+ }
+
+ /// @notice Sets the chain rate limiter config.
+ /// @param remoteChainSelector The remote chain selector for which the rate limits apply.
+ /// @param outboundConfig The new outbound rate limiter config, meaning the onRamp rate limits for the given chain.
+ /// @param inboundConfig The new inbound rate limiter config, meaning the offRamp rate limits for the given chain.
+ function setChainRateLimiterConfig(
+ uint64 remoteChainSelector,
+ RateLimiter.Config memory outboundConfig,
+ RateLimiter.Config memory inboundConfig
+ ) external virtual onlyOwner {
+ _setRateLimitConfig(remoteChainSelector, outboundConfig, inboundConfig);
+ }
+
+ function _setRateLimitConfig(
+ uint64 remoteChainSelector,
+ RateLimiter.Config memory outboundConfig,
+ RateLimiter.Config memory inboundConfig
+ ) internal {
+ if (!isSupportedChain(remoteChainSelector)) revert NonExistentChain(remoteChainSelector);
+ RateLimiter._validateTokenBucketConfig(outboundConfig, false);
+ s_outboundRateLimits[remoteChainSelector]._setTokenBucketConfig(outboundConfig);
+ RateLimiter._validateTokenBucketConfig(inboundConfig, false);
+ s_inboundRateLimits[remoteChainSelector]._setTokenBucketConfig(inboundConfig);
+ emit ChainConfigured(remoteChainSelector, outboundConfig, inboundConfig);
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender
+ /// is a permissioned onRamp for the given chain on the Router.
+ modifier onlyOnRamp(uint64 remoteChainSelector) {
+ if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector);
+ if (!(msg.sender == s_router.getOnRamp(remoteChainSelector))) revert CallerIsNotARampOnRouter(msg.sender);
+ _;
+ }
+
+ /// @notice Checks whether remote chain selector is configured on this contract, and if the msg.sender
+ /// is a permissioned offRamp for the given chain on the Router.
+ modifier onlyOffRamp(uint64 remoteChainSelector) {
+ if (!isSupportedChain(remoteChainSelector)) revert ChainNotAllowed(remoteChainSelector);
+ if (!s_router.isOffRamp(remoteChainSelector, msg.sender)) revert CallerIsNotARampOnRouter(msg.sender);
+ _;
+ }
+
+ // ================================================================
+ // │ Allowlist │
+ // ================================================================
+
+ modifier checkAllowList(address sender) {
+ if (i_allowlistEnabled && !s_allowList.contains(sender)) revert SenderNotAllowed(sender);
+ _;
+ }
+
+ /// @notice Gets whether the allowList functionality is enabled.
+ /// @return true is enabled, false if not.
+ function getAllowListEnabled() external view returns (bool) {
+ return i_allowlistEnabled;
+ }
+
+ /// @notice Gets the allowed addresses.
+ /// @return The allowed addresses.
+ function getAllowList() external view returns (address[] memory) {
+ return s_allowList.values();
+ }
+
+ /// @notice Apply updates to the allow list.
+ /// @param removes The addresses to be removed.
+ /// @param adds The addresses to be added.
+ /// @dev allowListing will be removed before public launch
+ function applyAllowListUpdates(address[] calldata removes, address[] calldata adds) external onlyOwner {
+ _applyAllowListUpdates(removes, adds);
+ }
+
+ /// @notice Internal version of applyAllowListUpdates to allow for reuse in the constructor.
+ function _applyAllowListUpdates(address[] memory removes, address[] memory adds) internal {
+ if (!i_allowlistEnabled) revert AllowListNotEnabled();
+
+ for (uint256 i = 0; i < removes.length; ++i) {
+ address toRemove = removes[i];
+ if (s_allowList.remove(toRemove)) {
+ emit AllowListRemove(toRemove);
+ }
+ }
+ for (uint256 i = 0; i < adds.length; ++i) {
+ address toAdd = adds[i];
+ if (toAdd == address(0)) {
+ continue;
+ }
+ if (s_allowList.add(toAdd)) {
+ emit AllowListAdd(toAdd);
+ }
+ }
+ }
+
+ /// @notice Ensure that there is no active curse.
+ modifier whenHealthy() {
+ if (IRMN(i_armProxy).isCursed()) revert BadARMSignal();
+ _;
+ }
+}
+
+abstract contract BurnMintTokenPoolAbstract is TokenPool1_4 {
+ /// @notice Contains the specific burn call for a pool.
+ /// @dev overriding this method allows us to create pools with different burn signatures
+ /// without duplicating the underlying logic.
+ function _burn(uint256 amount) internal virtual;
+
+ /// @notice Burn the token in the pool
+ /// @param amount Amount to burn
+ /// @dev The whenHealthy check is important to ensure that even if a ramp is compromised
+ /// we're able to stop token movement via ARM.
+ function lockOrBurn(
+ address originalSender,
+ bytes calldata,
+ uint256 amount,
+ uint64 remoteChainSelector,
+ bytes calldata
+ )
+ external
+ virtual
+ override
+ onlyOnRamp(remoteChainSelector)
+ checkAllowList(originalSender)
+ whenHealthy
+ returns (bytes memory)
+ {
+ _consumeOutboundRateLimit(remoteChainSelector, amount);
+ _burn(amount);
+ emit Burned(msg.sender, amount);
+ return "";
+ }
+
+ /// @notice Mint tokens from the pool to the recipient
+ /// @param receiver Recipient address
+ /// @param amount Amount to mint
+ /// @dev The whenHealthy check is important to ensure that even if a ramp is compromised
+ /// we're able to stop token movement via ARM.
+ function releaseOrMint(
+ bytes memory,
+ address receiver,
+ uint256 amount,
+ uint64 remoteChainSelector,
+ bytes memory
+ ) external virtual override whenHealthy onlyOffRamp(remoteChainSelector) {
+ _consumeInboundRateLimit(remoteChainSelector, amount);
+ IBurnMintERC20(address(i_token)).mint(receiver, amount);
+ emit Minted(msg.sender, receiver, amount);
+ }
+}
+
+/// @notice This pool mints and burns a 3rd-party token.
+/// @dev Pool whitelisting mode is set in the constructor and cannot be modified later.
+/// It either accepts any address as originalSender, or only accepts whitelisted originalSender.
+/// The only way to change whitelisting mode is to deploy a new pool.
+/// If that is expected, please make sure the token's burner/minter roles are adjustable.
+contract BurnMintTokenPool1_4 is BurnMintTokenPoolAbstract, ITypeAndVersion {
+ string public constant override typeAndVersion = "BurnMintTokenPool 1.4.0";
+
+ constructor(
+ IBurnMintERC20 token,
+ address[] memory allowlist,
+ address armProxy,
+ address router
+ ) TokenPool1_4(token, allowlist, armProxy, router) {}
+
+ /// @inheritdoc BurnMintTokenPoolAbstract
+ function _burn(uint256 amount) internal virtual override {
+ IBurnMintERC20(address(i_token)).burn(amount);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/legacy/TokenPoolAndProxy.t.sol b/contracts/src/v0.8/ccip/test/legacy/TokenPoolAndProxy.t.sol
new file mode 100644
index 00000000000..292ac9a3bfd
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/legacy/TokenPoolAndProxy.t.sol
@@ -0,0 +1,771 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IPoolV1} from "../../interfaces/IPool.sol";
+import {IPoolPriorTo1_5} from "../../interfaces/IPoolPriorTo1_5.sol";
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {PriceRegistry} from "../../PriceRegistry.sol";
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {BurnMintTokenPoolAndProxy} from "../../pools/BurnMintTokenPoolAndProxy.sol";
+import {LockReleaseTokenPoolAndProxy} from "../../pools/LockReleaseTokenPoolAndProxy.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {TokenSetup} from "../TokenSetup.t.sol";
+import {EVM2EVMOnRampHelper} from "../helpers/EVM2EVMOnRampHelper.sol";
+import {EVM2EVMOnRampSetup} from "../onRamp/EVM2EVMOnRampSetup.t.sol";
+import {RouterSetup} from "../router/RouterSetup.t.sol";
+import {BurnMintTokenPool1_2, TokenPool1_2} from "./BurnMintTokenPool1_2.sol";
+import {BurnMintTokenPool1_4, TokenPool1_4} from "./BurnMintTokenPool1_4.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+
+contract TokenPoolAndProxyMigration is EVM2EVMOnRampSetup {
+ BurnMintTokenPoolAndProxy internal s_newPool;
+ IPoolPriorTo1_5 internal s_legacyPool;
+ BurnMintERC677 internal s_token;
+
+ address internal s_offRamp;
+ address internal s_sourcePool = makeAddr("source_pool");
+ address internal s_sourceToken = makeAddr("source_token");
+ uint256 internal constant AMOUNT = 1;
+
+ function setUp() public virtual override {
+ super.setUp();
+ // Create a system with a token and a legacy pool
+ s_token = new BurnMintERC677("Test", "TEST", 18, type(uint256).max);
+ // dealing doesn't update the total supply, meaning the first time we burn a token we underflow, which isn't
+ // guarded against. Then, when we mint a token, we overflow, which is guarded against and will revert.
+ s_token.grantMintAndBurnRoles(OWNER);
+ s_token.mint(OWNER, 1e18);
+
+ s_offRamp = s_offRamps[0];
+ // Approve enough for a few calls
+ s_token.approve(address(s_sourceRouter), AMOUNT * 100);
+
+ // Approve infinite fee tokens
+ IERC20(s_sourceFeeToken).approve(address(s_sourceRouter), type(uint256).max);
+ }
+
+ /// @notice This test covers the entire migration plan for 1.0-1.2 pools to 1.5 pools. For simplicity
+ /// we will refer to the 1.0/1.2 pools as 1.2 pools, as they are functionally the same.
+ function test_tokenPoolMigration_Success_1_2() public {
+ // ================================================================
+ // | 1 1.2 prior to upgrade |
+ // ================================================================
+ _deployPool1_2();
+
+ // Ensure everything works on the 1.2 pool
+ _ccipSend_OLD();
+ _fakeReleaseOrMintFromOffRamp_OLD();
+
+ // ================================================================
+ // | 2 Deploy self serve |
+ // ================================================================
+ _deploySelfServe();
+
+ // This doesn't impact the 1.2 pool, so it should still be functional
+ _ccipSend_OLD();
+ _fakeReleaseOrMintFromOffRamp_OLD();
+
+ // ================================================================
+ // | 3 Configure new pool on old pool |
+ // ================================================================
+ // In the 1.2 case, everything keeps working on both the 1.2 and 1.5 pools. This config can be
+ // done in advance of the actual swap to 1.5 lanes.
+ vm.startPrank(OWNER);
+ TokenPool1_2.RampUpdate[] memory rampUpdates = new TokenPool1_2.RampUpdate[](1);
+ rampUpdates[0] = TokenPool1_2.RampUpdate({
+ ramp: address(s_newPool),
+ allowed: true,
+ // The rate limits should be turned off for this fake ramp, as the 1.5 pool will handle all the
+ // rate limiting for us.
+ rateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0})
+ });
+ // Since this call doesn't impact the usability of the old pool, we can do it whenever we want
+ BurnMintTokenPool1_2(address(s_legacyPool)).applyRampUpdates(rampUpdates, rampUpdates);
+
+ // Assert the 1.2 lanes still work
+ _ccipSend_OLD();
+ _fakeReleaseOrMintFromOffRamp_OLD();
+
+ // ================================================================
+ // | 4 Update the router with to 1.5 |
+ // ================================================================
+
+ // This will stop any new messages entering the old lanes, and will direct all traffic to the
+ // new 1.5 lanes, and therefore to the 1.5 pools. Note that the old pools will still receive
+ // inflight messages, and will need to continue functioning until all of those are processed.
+ _fakeReleaseOrMintFromOffRamp_OLD();
+
+ // Everything is configured, we can now send a ccip tx to the new pool
+ _ccipSend1_5();
+ _fakeReleaseOrMintFromOffRamp1_5();
+
+ // ================================================================
+ // | 5 Migrate to using 1.5 the pool |
+ // ================================================================
+ // Turn off the legacy pool, this enabled the 1.5 pool logic. This should be done AFTER the new pool
+ // has gotten permissions to mint/burn. We see the case where that isn't done below.
+ vm.startPrank(OWNER);
+ s_newPool.setPreviousPool(IPoolPriorTo1_5(address(0)));
+
+ // The new pool is now active, but is has not been given permissions to burn/mint yet
+ vm.expectRevert(abi.encodeWithSelector(BurnMintERC677.SenderNotBurner.selector, address(s_newPool)));
+ _ccipSend1_5();
+ vm.expectRevert(abi.encodeWithSelector(BurnMintERC677.SenderNotMinter.selector, address(s_newPool)));
+ _fakeReleaseOrMintFromOffRamp1_5();
+
+ // When we do give burn/mint, the new pool is fully active
+ vm.startPrank(OWNER);
+ s_token.grantMintAndBurnRoles(address(s_newPool));
+ _ccipSend1_5();
+ _fakeReleaseOrMintFromOffRamp1_5();
+
+ // Even after the pool has taken over as primary, the old pool can still process messages from the old lane
+ _fakeReleaseOrMintFromOffRamp_OLD();
+ }
+
+ function test_tokenPoolMigration_Success_1_4() public {
+ // ================================================================
+ // | 1 1.4 prior to upgrade |
+ // ================================================================
+ _deployPool1_4();
+
+ // Ensure everything works on the 1.4 pool
+ _ccipSend_OLD();
+ _fakeReleaseOrMintFromOffRamp_OLD();
+
+ // ================================================================
+ // | 2 Deploy self serve |
+ // ================================================================
+ _deploySelfServe();
+
+ // This doesn't impact the 1.4 pool, so it should still be functional
+ _ccipSend_OLD();
+ _fakeReleaseOrMintFromOffRamp_OLD();
+
+ // ================================================================
+ // | 3 Configure new pool on old pool |
+ // | AND |
+ // | Update the router with to 1.5 |
+ // ================================================================
+ // NOTE: when this call is made, the SENDING SIDE of old lanes stop working.
+ vm.startPrank(OWNER);
+ BurnMintTokenPool1_4(address(s_legacyPool)).setRouter(address(s_newPool));
+
+ // This will stop any new messages entering the old lanes, and will direct all traffic to the
+ // new 1.5 lanes, and therefore to the 1.5 pools. Note that the old pools will still receive
+ // inflight messages, and will need to continue functioning until all of those are processed.
+ _fakeReleaseOrMintFromOffRamp_OLD();
+
+ // Sending to the old 1.4 pool no longer works
+ _ccipSend_OLD_Reverts();
+
+ // Everything is configured, we can now send a ccip tx
+ _ccipSend1_5();
+ _fakeReleaseOrMintFromOffRamp1_5();
+
+ // ================================================================
+ // | 4 Migrate to using 1.5 the pool |
+ // ================================================================
+ // Turn off the legacy pool, this enabled the 1.5 pool logic. This should be done AFTER the new pool
+ // has gotten permissions to mint/burn. We see the case where that isn't done below.
+ vm.startPrank(OWNER);
+ s_newPool.setPreviousPool(IPoolPriorTo1_5(address(0)));
+
+ // The new pool is now active, but is has not been given permissions to burn/mint yet
+ vm.expectRevert(abi.encodeWithSelector(BurnMintERC677.SenderNotBurner.selector, address(s_newPool)));
+ _ccipSend1_5();
+ vm.expectRevert(abi.encodeWithSelector(BurnMintERC677.SenderNotMinter.selector, address(s_newPool)));
+ _fakeReleaseOrMintFromOffRamp1_5();
+
+ // When we do give burn/mint, the new pool is fully active
+ vm.startPrank(OWNER);
+ s_token.grantMintAndBurnRoles(address(s_newPool));
+ _ccipSend1_5();
+ _fakeReleaseOrMintFromOffRamp1_5();
+
+ // Even after the pool has taken over as primary, the old pool can still process messages from the old lane
+ _fakeReleaseOrMintFromOffRamp_OLD();
+ }
+
+ function _ccipSend_OLD() internal {
+ // We send the funds to the pool manually, as the ramp normally does that
+ deal(address(s_token), address(s_legacyPool), AMOUNT);
+ vm.startPrank(address(s_onRamp));
+ s_legacyPool.lockOrBurn(OWNER, abi.encode(OWNER), AMOUNT, DEST_CHAIN_SELECTOR, "");
+ }
+
+ function _ccipSend_OLD_Reverts() internal {
+ // We send the funds to the pool manually, as the ramp normally does that
+ deal(address(s_token), address(s_legacyPool), AMOUNT);
+ vm.startPrank(address(s_onRamp));
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool1_4.CallerIsNotARampOnRouter.selector, address(s_onRamp)));
+
+ s_legacyPool.lockOrBurn(OWNER, abi.encode(OWNER), AMOUNT, DEST_CHAIN_SELECTOR, "");
+ }
+
+ function _ccipSend1_5() internal {
+ vm.startPrank(address(OWNER));
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: address(s_token), amount: AMOUNT});
+
+ s_sourceRouter.ccipSend(
+ DEST_CHAIN_SELECTOR,
+ Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: s_sourceFeeToken,
+ extraArgs: ""
+ })
+ );
+ }
+
+ function _fakeReleaseOrMintFromOffRamp1_5() internal {
+ // This is a fake call to simulate the release or mint from the "offRamp"
+ vm.startPrank(s_offRamp);
+ s_newPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ receiver: OWNER,
+ amount: AMOUNT,
+ localToken: address(s_token),
+ sourcePoolAddress: abi.encode(s_sourcePool),
+ sourcePoolData: "",
+ offchainTokenData: ""
+ })
+ );
+ }
+
+ function _fakeReleaseOrMintFromOffRamp_OLD() internal {
+ // This is a fake call to simulate the release or mint from the "offRamp"
+ vm.startPrank(s_offRamp);
+ s_legacyPool.releaseOrMint(abi.encode(OWNER), OWNER, AMOUNT, SOURCE_CHAIN_SELECTOR, "");
+ }
+
+ function _deployPool1_2() internal {
+ vm.startPrank(OWNER);
+ s_legacyPool = new BurnMintTokenPool1_2(s_token, new address[](0), address(s_mockRMN));
+ s_token.grantMintAndBurnRoles(address(s_legacyPool));
+
+ TokenPool1_2.RampUpdate[] memory onRampUpdates = new TokenPool1_2.RampUpdate[](1);
+ onRampUpdates[0] = TokenPool1_2.RampUpdate({
+ ramp: address(s_onRamp),
+ allowed: true,
+ rateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ TokenPool1_2.RampUpdate[] memory offRampUpdates = new TokenPool1_2.RampUpdate[](1);
+ offRampUpdates[0] = TokenPool1_2.RampUpdate({
+ ramp: address(s_offRamp),
+ allowed: true,
+ rateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ BurnMintTokenPool1_2(address(s_legacyPool)).applyRampUpdates(onRampUpdates, offRampUpdates);
+ }
+
+ function _deployPool1_4() internal {
+ vm.startPrank(OWNER);
+ s_legacyPool = new BurnMintTokenPool1_4(s_token, new address[](0), address(s_mockRMN), address(s_sourceRouter));
+ s_token.grantMintAndBurnRoles(address(s_legacyPool));
+
+ TokenPool1_4.ChainUpdate[] memory legacyChainUpdates = new TokenPool1_4.ChainUpdate[](2);
+ legacyChainUpdates[0] = TokenPool1_4.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ legacyChainUpdates[1] = TokenPool1_4.ChainUpdate({
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ BurnMintTokenPool1_4(address(s_legacyPool)).applyChainUpdates(legacyChainUpdates);
+ }
+
+ function _deploySelfServe() internal {
+ vm.startPrank(OWNER);
+ // Deploy the new pool
+ s_newPool = new BurnMintTokenPoolAndProxy(s_token, new address[](0), address(s_mockRMN), address(s_sourceRouter));
+ // Set the previous pool on the new pool
+ s_newPool.setPreviousPool(s_legacyPool);
+
+ // Configure the lanes just like the legacy pool
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](2);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_destTokenPool),
+ remoteTokenAddress: abi.encode(s_destToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ chainUpdates[1] = TokenPool.ChainUpdate({
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_sourcePool),
+ remoteTokenAddress: abi.encode(s_sourceToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_newPool.applyChainUpdates(chainUpdates);
+
+ // Register the token on the token admin registry
+ s_tokenAdminRegistry.proposeAdministrator(address(s_token), OWNER);
+ // Accept ownership of the token
+ s_tokenAdminRegistry.acceptAdminRole(address(s_token));
+ // Set the pool on the admin registry
+ s_tokenAdminRegistry.setPool(address(s_token), address(s_newPool));
+ }
+}
+
+contract TokenPoolAndProxy is EVM2EVMOnRampSetup {
+ event Burned(address indexed sender, uint256 amount);
+ event Minted(address indexed sender, address indexed recipient, uint256 amount);
+
+ IPoolV1 internal s_pool;
+ BurnMintERC677 internal s_token;
+ IPoolPriorTo1_5 internal s_legacyPool;
+ address internal s_fakeOffRamp = makeAddr("off_ramp");
+
+ address internal s_destPool = makeAddr("dest_pool");
+
+ function setUp() public virtual override {
+ super.setUp();
+ s_token = BurnMintERC677(s_sourceFeeToken);
+
+ Router.OffRamp[] memory fakeOffRamps = new Router.OffRamp[](1);
+ fakeOffRamps[0] = Router.OffRamp({sourceChainSelector: DEST_CHAIN_SELECTOR, offRamp: s_fakeOffRamp});
+ s_sourceRouter.applyRampUpdates(new Router.OnRamp[](0), new Router.OffRamp[](0), fakeOffRamps);
+
+ s_token.grantMintAndBurnRoles(OWNER);
+ s_token.mint(OWNER, 1e18);
+ }
+
+ function test_lockOrBurn_burnMint_Success() public {
+ s_pool = new BurnMintTokenPoolAndProxy(s_token, new address[](0), address(s_mockRMN), address(s_sourceRouter));
+ _configurePool();
+ _deployOldPool();
+ _assertLockOrBurnCorrect();
+
+ vm.startPrank(OWNER);
+ BurnMintTokenPoolAndProxy(address(s_pool)).setPreviousPool(IPoolPriorTo1_5(address(0)));
+
+ _assertReleaseOrMintCorrect();
+ }
+
+ function test_lockOrBurn_lockRelease_Success() public {
+ s_pool =
+ new LockReleaseTokenPoolAndProxy(s_token, new address[](0), address(s_mockRMN), false, address(s_sourceRouter));
+ _configurePool();
+ _deployOldPool();
+ _assertLockOrBurnCorrect();
+
+ vm.startPrank(OWNER);
+ BurnMintTokenPoolAndProxy(address(s_pool)).setPreviousPool(IPoolPriorTo1_5(address(0)));
+
+ _assertReleaseOrMintCorrect();
+ }
+
+ function _deployOldPool() internal {
+ s_legacyPool = new BurnMintTokenPool1_2(s_token, new address[](0), address(s_mockRMN));
+ s_token.grantMintAndBurnRoles(address(s_legacyPool));
+
+ TokenPool1_2.RampUpdate[] memory onRampUpdates = new TokenPool1_2.RampUpdate[](1);
+ onRampUpdates[0] =
+ TokenPool1_2.RampUpdate({ramp: address(s_pool), allowed: true, rateLimiterConfig: getInboundRateLimiterConfig()});
+ TokenPool1_2.RampUpdate[] memory offRampUpdates = new TokenPool1_2.RampUpdate[](1);
+ offRampUpdates[0] =
+ TokenPool1_2.RampUpdate({ramp: address(s_pool), allowed: true, rateLimiterConfig: getInboundRateLimiterConfig()});
+ BurnMintTokenPool1_2(address(s_legacyPool)).applyRampUpdates(onRampUpdates, offRampUpdates);
+ }
+
+ function _configurePool() internal {
+ TokenPool.ChainUpdate[] memory chains = new TokenPool.ChainUpdate[](1);
+ chains[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_destPool),
+ remoteTokenAddress: abi.encode(s_destToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+
+ BurnMintTokenPoolAndProxy(address(s_pool)).applyChainUpdates(chains);
+
+ // CCIP Token Admin has already been registered from TokenSetup
+ s_tokenAdminRegistry.setPool(address(s_token), address(s_pool));
+
+ s_token.grantMintAndBurnRoles(address(s_pool));
+ }
+
+ function _assertLockOrBurnCorrect() internal {
+ uint256 amount = 1234;
+ vm.startPrank(address(s_onRamp));
+
+ // lockOrBurn, assert normal path is taken
+ deal(address(s_token), address(s_pool), amount);
+
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ receiver: abi.encode(OWNER),
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ originalSender: OWNER,
+ amount: amount,
+ localToken: address(s_token)
+ })
+ );
+
+ // set legacy pool
+
+ vm.startPrank(OWNER);
+ BurnMintTokenPoolAndProxy(address(s_pool)).setPreviousPool(s_legacyPool);
+
+ // lockOrBurn, assert legacy pool is called
+
+ vm.startPrank(address(s_onRamp));
+ deal(address(s_token), address(s_pool), amount);
+
+ vm.expectEmit(address(s_legacyPool));
+ emit Burned(address(s_pool), amount);
+
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ receiver: abi.encode(OWNER),
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ originalSender: OWNER,
+ amount: amount,
+ localToken: address(s_token)
+ })
+ );
+ }
+
+ function _assertReleaseOrMintCorrect() internal {
+ uint256 amount = 1234;
+ vm.startPrank(s_fakeOffRamp);
+
+ // releaseOrMint, assert normal path is taken
+ deal(address(s_token), address(s_pool), amount);
+
+ s_pool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ receiver: OWNER,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ originalSender: abi.encode(OWNER),
+ amount: amount,
+ localToken: address(s_token),
+ sourcePoolAddress: abi.encode(s_destPool),
+ sourcePoolData: "",
+ offchainTokenData: ""
+ })
+ );
+
+ // set legacy pool
+
+ vm.startPrank(OWNER);
+ BurnMintTokenPoolAndProxy(address(s_pool)).setPreviousPool(s_legacyPool);
+
+ // releaseOrMint, assert legacy pool is called
+
+ vm.startPrank(address(s_fakeOffRamp));
+
+ vm.expectEmit(address(s_legacyPool));
+ emit Minted(address(s_pool), s_fakeOffRamp, amount);
+
+ s_pool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ receiver: OWNER,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ originalSender: abi.encode(OWNER),
+ amount: amount,
+ localToken: address(s_token),
+ sourcePoolAddress: abi.encode(s_destPool),
+ sourcePoolData: "",
+ offchainTokenData: ""
+ })
+ );
+ }
+}
+
+////
+/// Duplicated tests from LockReleaseTokenPool.t.sol
+///
+
+contract LockReleaseTokenPoolAndProxySetup is RouterSetup {
+ IERC20 internal s_token;
+ LockReleaseTokenPoolAndProxy internal s_lockReleaseTokenPoolAndProxy;
+ LockReleaseTokenPoolAndProxy internal s_lockReleaseTokenPoolAndProxyWithAllowList;
+ address[] internal s_allowedList;
+
+ address internal s_allowedOnRamp = address(123);
+ address internal s_allowedOffRamp = address(234);
+
+ address internal s_destPoolAddress = address(2736782345);
+ address internal s_sourcePoolAddress = address(53852352095);
+
+ function setUp() public virtual override {
+ RouterSetup.setUp();
+ s_token = new BurnMintERC677("LINK", "LNK", 18, 0);
+ deal(address(s_token), OWNER, type(uint256).max);
+ s_lockReleaseTokenPoolAndProxy =
+ new LockReleaseTokenPoolAndProxy(s_token, new address[](0), address(s_mockRMN), true, address(s_sourceRouter));
+
+ s_allowedList.push(USER_1);
+ s_allowedList.push(DUMMY_CONTRACT_ADDRESS);
+ s_lockReleaseTokenPoolAndProxyWithAllowList =
+ new LockReleaseTokenPoolAndProxy(s_token, s_allowedList, address(s_mockRMN), true, address(s_sourceRouter));
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_destPoolAddress),
+ remoteTokenAddress: abi.encode(address(s_token)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+
+ s_lockReleaseTokenPoolAndProxy.applyChainUpdates(chainUpdate);
+ s_lockReleaseTokenPoolAndProxyWithAllowList.applyChainUpdates(chainUpdate);
+ s_lockReleaseTokenPoolAndProxy.setRebalancer(OWNER);
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_allowedOnRamp});
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: s_allowedOffRamp});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+ }
+}
+
+contract LockReleaseTokenPoolAndProxy_setRebalancer is LockReleaseTokenPoolAndProxySetup {
+ function test_SetRebalancer_Success() public {
+ assertEq(address(s_lockReleaseTokenPoolAndProxy.getRebalancer()), OWNER);
+ s_lockReleaseTokenPoolAndProxy.setRebalancer(STRANGER);
+ assertEq(address(s_lockReleaseTokenPoolAndProxy.getRebalancer()), STRANGER);
+ }
+
+ function test_SetRebalancer_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert("Only callable by owner");
+ s_lockReleaseTokenPoolAndProxy.setRebalancer(STRANGER);
+ }
+}
+
+contract LockReleaseTokenPoolPoolAndProxy_canAcceptLiquidity is LockReleaseTokenPoolAndProxySetup {
+ function test_CanAcceptLiquidity_Success() public {
+ assertEq(true, s_lockReleaseTokenPoolAndProxy.canAcceptLiquidity());
+
+ s_lockReleaseTokenPoolAndProxy =
+ new LockReleaseTokenPoolAndProxy(s_token, new address[](0), address(s_mockRMN), false, address(s_sourceRouter));
+ assertEq(false, s_lockReleaseTokenPoolAndProxy.canAcceptLiquidity());
+ }
+}
+
+contract LockReleaseTokenPoolPoolAndProxy_provideLiquidity is LockReleaseTokenPoolAndProxySetup {
+ function test_Fuzz_ProvideLiquidity_Success(uint256 amount) public {
+ uint256 balancePre = s_token.balanceOf(OWNER);
+ s_token.approve(address(s_lockReleaseTokenPoolAndProxy), amount);
+
+ s_lockReleaseTokenPoolAndProxy.provideLiquidity(amount);
+
+ assertEq(s_token.balanceOf(OWNER), balancePre - amount);
+ assertEq(s_token.balanceOf(address(s_lockReleaseTokenPoolAndProxy)), amount);
+ }
+
+ // Reverts
+
+ function test_Unauthorized_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(abi.encodeWithSelector(LockReleaseTokenPoolAndProxy.Unauthorized.selector, STRANGER));
+
+ s_lockReleaseTokenPoolAndProxy.provideLiquidity(1);
+ }
+
+ function test_Fuzz_ExceedsAllowance(uint256 amount) public {
+ vm.assume(amount > 0);
+ vm.expectRevert("ERC20: insufficient allowance");
+ s_lockReleaseTokenPoolAndProxy.provideLiquidity(amount);
+ }
+
+ function test_LiquidityNotAccepted_Revert() public {
+ s_lockReleaseTokenPoolAndProxy =
+ new LockReleaseTokenPoolAndProxy(s_token, new address[](0), address(s_mockRMN), false, address(s_sourceRouter));
+
+ vm.expectRevert(LockReleaseTokenPoolAndProxy.LiquidityNotAccepted.selector);
+ s_lockReleaseTokenPoolAndProxy.provideLiquidity(1);
+ }
+}
+
+contract LockReleaseTokenPoolPoolAndProxy_withdrawalLiquidity is LockReleaseTokenPoolAndProxySetup {
+ function test_Fuzz_WithdrawalLiquidity_Success(uint256 amount) public {
+ uint256 balancePre = s_token.balanceOf(OWNER);
+ s_token.approve(address(s_lockReleaseTokenPoolAndProxy), amount);
+ s_lockReleaseTokenPoolAndProxy.provideLiquidity(amount);
+
+ s_lockReleaseTokenPoolAndProxy.withdrawLiquidity(amount);
+
+ assertEq(s_token.balanceOf(OWNER), balancePre);
+ }
+
+ // Reverts
+
+ function test_Unauthorized_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(abi.encodeWithSelector(LockReleaseTokenPoolAndProxy.Unauthorized.selector, STRANGER));
+
+ s_lockReleaseTokenPoolAndProxy.withdrawLiquidity(1);
+ }
+
+ function test_InsufficientLiquidity_Revert() public {
+ uint256 maxUint256 = 2 ** 256 - 1;
+ s_token.approve(address(s_lockReleaseTokenPoolAndProxy), maxUint256);
+ s_lockReleaseTokenPoolAndProxy.provideLiquidity(maxUint256);
+
+ vm.startPrank(address(s_lockReleaseTokenPoolAndProxy));
+ s_token.transfer(OWNER, maxUint256);
+ vm.startPrank(OWNER);
+
+ vm.expectRevert(LockReleaseTokenPoolAndProxy.InsufficientLiquidity.selector);
+ s_lockReleaseTokenPoolAndProxy.withdrawLiquidity(1);
+ }
+}
+
+contract LockReleaseTokenPoolPoolAndProxy_supportsInterface is LockReleaseTokenPoolAndProxySetup {
+ function test_SupportsInterface_Success() public view {
+ assertTrue(s_lockReleaseTokenPoolAndProxy.supportsInterface(type(IPoolV1).interfaceId));
+ assertTrue(s_lockReleaseTokenPoolAndProxy.supportsInterface(type(IERC165).interfaceId));
+ }
+}
+
+contract LockReleaseTokenPoolPoolAndProxy_setChainRateLimiterConfig is LockReleaseTokenPoolAndProxySetup {
+ event ConfigChanged(RateLimiter.Config);
+ event ChainConfigured(
+ uint64 chainSelector, RateLimiter.Config outboundRateLimiterConfig, RateLimiter.Config inboundRateLimiterConfig
+ );
+
+ uint64 internal s_remoteChainSelector;
+
+ function setUp() public virtual override {
+ LockReleaseTokenPoolAndProxySetup.setUp();
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ s_remoteChainSelector = 123124;
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: s_remoteChainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_lockReleaseTokenPoolAndProxy.applyChainUpdates(chainUpdates);
+ }
+
+ function test_Fuzz_SetChainRateLimiterConfig_Success(uint128 capacity, uint128 rate, uint32 newTime) public {
+ // Cap the lower bound to 4 so 4/2 is still >= 2
+ vm.assume(capacity >= 4);
+ // Cap the lower bound to 2 so 2/2 is still >= 1
+ rate = uint128(bound(rate, 2, capacity - 2));
+ // Bucket updates only work on increasing time
+ newTime = uint32(bound(newTime, block.timestamp + 1, type(uint32).max));
+ vm.warp(newTime);
+
+ uint256 oldOutboundTokens =
+ s_lockReleaseTokenPoolAndProxy.getCurrentOutboundRateLimiterState(s_remoteChainSelector).tokens;
+ uint256 oldInboundTokens =
+ s_lockReleaseTokenPoolAndProxy.getCurrentInboundRateLimiterState(s_remoteChainSelector).tokens;
+
+ RateLimiter.Config memory newOutboundConfig = RateLimiter.Config({isEnabled: true, capacity: capacity, rate: rate});
+ RateLimiter.Config memory newInboundConfig =
+ RateLimiter.Config({isEnabled: true, capacity: capacity / 2, rate: rate / 2});
+
+ vm.expectEmit();
+ emit ConfigChanged(newOutboundConfig);
+ vm.expectEmit();
+ emit ConfigChanged(newInboundConfig);
+ vm.expectEmit();
+ emit ChainConfigured(s_remoteChainSelector, newOutboundConfig, newInboundConfig);
+
+ s_lockReleaseTokenPoolAndProxy.setChainRateLimiterConfig(s_remoteChainSelector, newOutboundConfig, newInboundConfig);
+
+ uint256 expectedTokens = RateLimiter._min(newOutboundConfig.capacity, oldOutboundTokens);
+
+ RateLimiter.TokenBucket memory bucket =
+ s_lockReleaseTokenPoolAndProxy.getCurrentOutboundRateLimiterState(s_remoteChainSelector);
+ assertEq(bucket.capacity, newOutboundConfig.capacity);
+ assertEq(bucket.rate, newOutboundConfig.rate);
+ assertEq(bucket.tokens, expectedTokens);
+ assertEq(bucket.lastUpdated, newTime);
+
+ expectedTokens = RateLimiter._min(newInboundConfig.capacity, oldInboundTokens);
+
+ bucket = s_lockReleaseTokenPoolAndProxy.getCurrentInboundRateLimiterState(s_remoteChainSelector);
+ assertEq(bucket.capacity, newInboundConfig.capacity);
+ assertEq(bucket.rate, newInboundConfig.rate);
+ assertEq(bucket.tokens, expectedTokens);
+ assertEq(bucket.lastUpdated, newTime);
+ }
+
+ function test_OnlyOwnerOrRateLimitAdmin_Revert() public {
+ address rateLimiterAdmin = address(28973509103597907);
+
+ s_lockReleaseTokenPoolAndProxy.setRateLimitAdmin(rateLimiterAdmin);
+
+ vm.startPrank(rateLimiterAdmin);
+
+ s_lockReleaseTokenPoolAndProxy.setChainRateLimiterConfig(
+ s_remoteChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+
+ vm.startPrank(OWNER);
+
+ s_lockReleaseTokenPoolAndProxy.setChainRateLimiterConfig(
+ s_remoteChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+ }
+
+ // Reverts
+
+ function test_OnlyOwner_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(abi.encodeWithSelector(LockReleaseTokenPoolAndProxy.Unauthorized.selector, STRANGER));
+ s_lockReleaseTokenPoolAndProxy.setChainRateLimiterConfig(
+ s_remoteChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+ }
+
+ function test_NonExistentChain_Revert() public {
+ uint64 wrongChainSelector = 9084102894;
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.NonExistentChain.selector, wrongChainSelector));
+ s_lockReleaseTokenPoolAndProxy.setChainRateLimiterConfig(
+ wrongChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+ }
+}
+
+contract LockReleaseTokenPoolAndProxy_setRateLimitAdmin is LockReleaseTokenPoolAndProxySetup {
+ function test_SetRateLimitAdmin_Success() public {
+ assertEq(address(0), s_lockReleaseTokenPoolAndProxy.getRateLimitAdmin());
+ s_lockReleaseTokenPoolAndProxy.setRateLimitAdmin(OWNER);
+ assertEq(OWNER, s_lockReleaseTokenPoolAndProxy.getRateLimitAdmin());
+ }
+
+ // Reverts
+
+ function test_SetRateLimitAdmin_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert("Only callable by owner");
+ s_lockReleaseTokenPoolAndProxy.setRateLimitAdmin(STRANGER);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/libraries/MerkleMultiProof.t.sol b/contracts/src/v0.8/ccip/test/libraries/MerkleMultiProof.t.sol
new file mode 100644
index 00000000000..e2fc9814d07
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/libraries/MerkleMultiProof.t.sol
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {MerkleMultiProof} from "../../libraries/MerkleMultiProof.sol";
+import {MerkleHelper} from "../helpers/MerkleHelper.sol";
+import {Test} from "forge-std/Test.sol";
+
+contract MerkleMultiProofTest is Test {
+ // This must match the spec
+ function test_SpecSync_gas() public pure {
+ bytes32 expectedRoot = 0xd4f0f3c40a4d583d98c17d89e550b1143fe4d3d759f25ccc63131c90b183928e;
+
+ bytes32[] memory leaves = new bytes32[](10);
+ leaves[0] = 0xa20c0244af79697a4ef4e2378c9d5d14cbd49ddab3427b12594c7cfa67a7f240;
+ leaves[1] = 0x3de96afb24ce2ac45a5595aa13d1a5163ae0b3c94cef6b2dc306b5966f32dfa5;
+ leaves[2] = 0xacadf7b4d13cd57c5d25f1d27be39b656347fe8f8e0de8db9c76d979dff57736;
+ leaves[3] = 0xc21c26a709802fe1ae52a9cd8ad94d15bf142ded26314339cd87a13e5b468165;
+ leaves[4] = 0x55f6df03562738c9a6437cd9ad221c52b76906a175ae96188cff60e0a2a59933;
+ leaves[5] = 0x2dbbe66452e43fec839dc65d5945aad6433d410c65863eaf1d876e1e0b06343c;
+ leaves[6] = 0x8beab00297b94bf079fcd5893b0a33ebf6b0ce862cd06be07c87d3c63e1c4acf;
+ leaves[7] = 0xcabdd3ad25daeb1e0541042f2ea4cd177f54e67aa4a2c697acd4bb682e94de59;
+ leaves[8] = 0x7e01d497203685e99e34df33d55465c66b2253fa1630ee2fe5c4997968e4a6fa;
+ leaves[9] = 0x1a03d013f1e2fa9cc04f89c7528ac3216e3e096a1185d7247304e97c59f9661f;
+
+ bytes32[] memory proofs = new bytes32[](33);
+ proofs[0] = 0xde96f24fcf9ddd20c803dc9c5fba7c478a5598a08a0faa5f032c65823b8e26a3;
+ proofs[1] = 0xe1303cffc3958a6b93e2dc04caf21f200ff5aa5be090c5013f37804b91488bc2;
+ proofs[2] = 0x90d80c76bccb44a91f4e16604976163aaa39e9a1588b0b24b33a61f1d4ba7bb5;
+ proofs[3] = 0x012a299b25539d513c8677ecf37968774e9e4b045e79737f48defd350224cdfd;
+ proofs[4] = 0x420a36c5a73f87d8fb98e70c48d0d6f9dd83f50b7b91416a6f5f91fac4db800f;
+ proofs[5] = 0x5857d8d1b56abcd7f863cedd3c3f8677256f54d675be61f05efa45d6495fc30a;
+ proofs[6] = 0xbf176d20166fdeb72593ff97efec1ce6244af41ca46cf0bc902d19d50c446f7b;
+ proofs[7] = 0xa9221608e4380250a1815fb308632bce99f611a673d2e17fc617123fdc6afcd2;
+ proofs[8] = 0xbd14f3366c73186314f182027217d0f70eba55817561de9e9a1f2c78bf5cbead;
+ proofs[9] = 0x2f9aa48c0c9f82aaac65d7a9374a52d9dc138ed100a5809ede57e70697f48b56;
+ proofs[10] = 0x2ae60afa54271cb421c12e4441c2dac0a25f25c9433a6d07cb32419e993fe344;
+ proofs[11] = 0xc765c091680f0434b74c44507b932e5c80f6e995a975a275e5b130af1de1064c;
+ proofs[12] = 0x59d2d6e0c4a5d07b169dbcdfa39dad7aea7b7783a814399f4f44c4a36b6336d3;
+ proofs[13] = 0xdd14d1387d10740187d71ad9500475399559c0922dbe2576882e61f1edd84692;
+ proofs[14] = 0x5412b8395509935406811ab3da43ab80be7acd8ffb5f398ab70f056ff3740f46;
+ proofs[15] = 0xeadab258ae7d779ce5f10fbb1bb0273116b8eccbf738ed878db570de78bed1e4;
+ proofs[16] = 0x6133aa40e6db75373b7cfc79e6f8b8ce80e441e6c1f98b85a593464dda3cf9c0;
+ proofs[17] = 0x5418948467112660639b932af9b1b212e40d71b24326b4606679d168a765af4f;
+ proofs[18] = 0x44f618505355c7e4e7c0f81d6bb15d2ec9cf9b366f9e1dc37db52745486e6b0f;
+ proofs[19] = 0xa410ee174a66a4d64f3c000b93efe15b5b1f3e39e962af2580fcd30bce07d039;
+ proofs[20] = 0x09c3eb05ac9552022a45c00d01a47cd56f95f94afdd4402299dba1291a17f976;
+ proofs[21] = 0x0e780f6acd081b07320a55208fa3e1d884e2e95cb13d1c98c74b7e853372c813;
+ proofs[22] = 0x2b60e8c21f78ef22fa4297f28f1d8c747181edfc465121b39c16be97d4fb8a04;
+ proofs[23] = 0xf24da95060a8598c06e9dfb3926e1a8c8bd8ec2c65be10e69323442840724888;
+ proofs[24] = 0x7e220fc095bcd2b0f5ef134d9620d89f6d7a1e8719ce8893bb9aff15e847578f;
+ proofs[25] = 0xcfe9e475c4bd32f1e36b2cc65a959c403c59979ff914fb629a64385b0c680a71;
+ proofs[26] = 0x25237fb8d1bfdc01ca5363ec3166a2b40789e38d5adcc8627801da683d2e1d76;
+ proofs[27] = 0x42647949fed0250139c01212d739d8c83d2852589ebc892d3490ae52e411432c;
+ proofs[28] = 0x34397a30930e6dd4fb5af48084afc5cfbe02c18dd9544b3faff4e2e90bf00cb9;
+ proofs[29] = 0xa028f33226adc3d1cb72b19eb6808dab9190b25066a45cacb5dfe5d640e57cf2;
+ proofs[30] = 0x7cff66ba47a05f932d06d168c294266dcb0d3943a4f2a4a75c860b9fd6e53092;
+ proofs[31] = 0x5ca1b32f1dbfadd83205882be5eb76f34c49e834726f5239905a0e70d0a5e0eb;
+ proofs[32] = 0x1b4b087a89e4eca6cdd237210932559dc8fd167d5f4f2d9acb13264e1e305479;
+
+ uint256 flagsUint256 = 0x2f3c0000000;
+
+ bytes32 root = MerkleMultiProof.merkleRoot(leaves, proofs, flagsUint256);
+
+ assertEq(expectedRoot, root);
+ }
+
+ function test_Fuzz_MerkleRoot2(bytes32 left, bytes32 right) public pure {
+ bytes32[] memory leaves = new bytes32[](2);
+ leaves[0] = left;
+ leaves[1] = right;
+ bytes32[] memory proofs = new bytes32[](0);
+
+ bytes32 expectedRoot = MerkleHelper.hashPair(left, right);
+
+ bytes32 root = MerkleMultiProof.merkleRoot(leaves, proofs, 2 ** 2 - 1);
+
+ assertEq(root, expectedRoot);
+ }
+
+ function test_MerkleRoot256() public pure {
+ bytes32[] memory leaves = new bytes32[](256);
+ for (uint256 i = 0; i < leaves.length; ++i) {
+ leaves[i] = keccak256("a");
+ }
+ bytes32[] memory proofs = new bytes32[](0);
+
+ bytes32 expectedRoot = MerkleHelper.getMerkleRoot(leaves);
+
+ bytes32 root = MerkleMultiProof.merkleRoot(leaves, proofs, 2 ** 256 - 1);
+
+ assertEq(root, expectedRoot);
+ }
+
+ function test_Fuzz_MerkleMulti1of4(bytes32 leaf1, bytes32 proof1, bytes32 proof2) public pure {
+ bytes32[] memory leaves = new bytes32[](1);
+ leaves[0] = leaf1;
+ bytes32[] memory proofs = new bytes32[](2);
+ proofs[0] = proof1;
+ proofs[1] = proof2;
+
+ // Proof flag = false
+ bytes32 result = MerkleHelper.hashPair(leaves[0], proofs[0]);
+ // Proof flag = false
+ result = MerkleHelper.hashPair(result, proofs[1]);
+
+ assertEq(MerkleMultiProof.merkleRoot(leaves, proofs, 0), result);
+ }
+
+ function test_Fuzz_MerkleMulti2of4(bytes32 leaf1, bytes32 leaf2, bytes32 proof1, bytes32 proof2) public pure {
+ bytes32[] memory leaves = new bytes32[](2);
+ leaves[0] = leaf1;
+ leaves[1] = leaf2;
+ bytes32[] memory proofs = new bytes32[](2);
+ proofs[0] = proof1;
+ proofs[1] = proof2;
+
+ // Proof flag = false
+ bytes32 result1 = MerkleHelper.hashPair(leaves[0], proofs[0]);
+ // Proof flag = false
+ bytes32 result2 = MerkleHelper.hashPair(leaves[1], proofs[1]);
+ // Proof flag = true
+ bytes32 finalResult = MerkleHelper.hashPair(result1, result2);
+
+ assertEq(MerkleMultiProof.merkleRoot(leaves, proofs, 4), finalResult);
+ }
+
+ function test_Fuzz_MerkleMulti3of4(bytes32 leaf1, bytes32 leaf2, bytes32 leaf3, bytes32 proof) public pure {
+ bytes32[] memory leaves = new bytes32[](3);
+ leaves[0] = leaf1;
+ leaves[1] = leaf2;
+ leaves[2] = leaf3;
+ bytes32[] memory proofs = new bytes32[](1);
+ proofs[0] = proof;
+
+ // Proof flag = true
+ bytes32 result1 = MerkleHelper.hashPair(leaves[0], leaves[1]);
+ // Proof flag = false
+ bytes32 result2 = MerkleHelper.hashPair(leaves[2], proofs[0]);
+ // Proof flag = true
+ bytes32 finalResult = MerkleHelper.hashPair(result1, result2);
+
+ assertEq(MerkleMultiProof.merkleRoot(leaves, proofs, 5), finalResult);
+ }
+
+ function test_Fuzz_MerkleMulti4of4(bytes32 leaf1, bytes32 leaf2, bytes32 leaf3, bytes32 leaf4) public pure {
+ bytes32[] memory leaves = new bytes32[](4);
+ leaves[0] = leaf1;
+ leaves[1] = leaf2;
+ leaves[2] = leaf3;
+ leaves[3] = leaf4;
+ bytes32[] memory proofs = new bytes32[](0);
+
+ // Proof flag = true
+ bytes32 result1 = MerkleHelper.hashPair(leaves[0], leaves[1]);
+ // Proof flag = true
+ bytes32 result2 = MerkleHelper.hashPair(leaves[2], leaves[3]);
+ // Proof flag = true
+ bytes32 finalResult = MerkleHelper.hashPair(result1, result2);
+
+ assertEq(MerkleMultiProof.merkleRoot(leaves, proofs, 7), finalResult);
+ }
+
+ function test_MerkleRootSingleLeaf_Success() public pure {
+ bytes32[] memory leaves = new bytes32[](1);
+ leaves[0] = "root";
+ bytes32[] memory proofs = new bytes32[](0);
+ assertEq(MerkleMultiProof.merkleRoot(leaves, proofs, 0), leaves[0]);
+ }
+
+ function test_EmptyLeaf_Revert() public {
+ bytes32[] memory leaves = new bytes32[](0);
+ bytes32[] memory proofs = new bytes32[](0);
+
+ vm.expectRevert(abi.encodeWithSelector(MerkleMultiProof.LeavesCannotBeEmpty.selector));
+ MerkleMultiProof.merkleRoot(leaves, proofs, 0);
+ }
+
+ function test_CVE_2023_34459() public {
+ bytes32[] memory leaves = new bytes32[](2);
+ // leaves[0] stays uninitialized, i.e., 0x000...0
+ leaves[1] = "leaf";
+
+ bytes32[] memory proof = new bytes32[](2);
+ proof[0] = leaves[1];
+ proof[1] = "will never be used";
+
+ bytes32[] memory malicious = new bytes32[](2);
+ malicious[0] = "malicious leaf";
+ malicious[1] = "another malicious leaf";
+
+ vm.expectRevert(abi.encodeWithSelector(MerkleMultiProof.InvalidProof.selector));
+ MerkleMultiProof.merkleRoot(malicious, proof, 3);
+ // Note, that without the revert the above computed root
+ // would equal MerkleHelper.hashPair(leaves[0], leaves[1]).
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/libraries/RateLimiter.t.sol b/contracts/src/v0.8/ccip/test/libraries/RateLimiter.t.sol
new file mode 100644
index 00000000000..da6a6f9ada7
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/libraries/RateLimiter.t.sol
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {RateLimiterHelper} from "../helpers/RateLimiterHelper.sol";
+import {Test} from "forge-std/Test.sol";
+
+contract RateLimiterSetup is Test {
+ RateLimiterHelper internal s_helper;
+ RateLimiter.Config internal s_config;
+
+ uint256 internal constant BLOCK_TIME = 1234567890;
+
+ function setUp() public virtual {
+ s_config = RateLimiter.Config({isEnabled: true, rate: 5, capacity: 100});
+ s_helper = new RateLimiterHelper(s_config);
+ }
+}
+
+contract RateLimiter_constructor is RateLimiterSetup {
+ function test_Constructor_Success() public view {
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.rate, rateLimiter.rate);
+ assertEq(s_config.capacity, rateLimiter.capacity);
+ assertEq(s_config.capacity, rateLimiter.tokens);
+ assertEq(s_config.isEnabled, rateLimiter.isEnabled);
+ assertEq(BLOCK_TIME, rateLimiter.lastUpdated);
+ }
+}
+
+contract RateLimiter_setTokenBucketConfig is RateLimiterSetup {
+ function test_SetRateLimiterConfig_Success() public {
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.rate, rateLimiter.rate);
+ assertEq(s_config.capacity, rateLimiter.capacity);
+
+ s_config =
+ RateLimiter.Config({isEnabled: true, rate: uint128(rateLimiter.rate * 2), capacity: rateLimiter.capacity * 8});
+
+ vm.expectEmit();
+ emit RateLimiter.ConfigChanged(s_config);
+
+ s_helper.setTokenBucketConfig(s_config);
+
+ rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.rate, rateLimiter.rate);
+ assertEq(s_config.capacity, rateLimiter.capacity);
+ assertEq(s_config.capacity / 8, rateLimiter.tokens);
+ assertEq(s_config.isEnabled, rateLimiter.isEnabled);
+ assertEq(BLOCK_TIME, rateLimiter.lastUpdated);
+ }
+}
+
+contract RateLimiter_currentTokenBucketState is RateLimiterSetup {
+ function test_CurrentTokenBucketState_Success() public {
+ RateLimiter.TokenBucket memory bucket = s_helper.currentTokenBucketState();
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.capacity, bucket.tokens);
+ assertEq(s_config.isEnabled, bucket.isEnabled);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+
+ s_config = RateLimiter.Config({isEnabled: true, rate: uint128(bucket.rate * 2), capacity: bucket.capacity * 8});
+
+ s_helper.setTokenBucketConfig(s_config);
+
+ bucket = s_helper.currentTokenBucketState();
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.capacity / 8, bucket.tokens);
+ assertEq(s_config.isEnabled, bucket.isEnabled);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+ }
+
+ function test_Refill_Success() public {
+ RateLimiter.TokenBucket memory bucket = s_helper.currentTokenBucketState();
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.capacity, bucket.tokens);
+ assertEq(s_config.isEnabled, bucket.isEnabled);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+
+ s_config = RateLimiter.Config({isEnabled: true, rate: uint128(bucket.rate * 2), capacity: bucket.capacity * 8});
+
+ s_helper.setTokenBucketConfig(s_config);
+
+ bucket = s_helper.currentTokenBucketState();
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.capacity / 8, bucket.tokens);
+ assertEq(s_config.isEnabled, bucket.isEnabled);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+
+ uint256 warpTime = 4;
+ vm.warp(BLOCK_TIME + warpTime);
+
+ bucket = s_helper.currentTokenBucketState();
+
+ assertEq(s_config.capacity / 8 + warpTime * s_config.rate, bucket.tokens);
+
+ vm.warp(BLOCK_TIME + warpTime * 100);
+
+ // Bucket overflow
+ bucket = s_helper.currentTokenBucketState();
+ assertEq(s_config.capacity, bucket.tokens);
+ }
+}
+
+contract RateLimiter_consume is RateLimiterSetup {
+ address internal s_token = address(100);
+
+ function test_ConsumeAggregateValue_Success() public {
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.rate, rateLimiter.rate);
+ assertEq(s_config.capacity, rateLimiter.capacity);
+ assertEq(s_config.capacity, rateLimiter.tokens);
+ assertEq(s_config.isEnabled, rateLimiter.isEnabled);
+ assertEq(BLOCK_TIME, rateLimiter.lastUpdated);
+
+ uint256 requestTokens = 50;
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(requestTokens);
+
+ s_helper.consume(requestTokens, address(0));
+
+ rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.rate, rateLimiter.rate);
+ assertEq(s_config.capacity, rateLimiter.capacity);
+ assertEq(s_config.capacity - requestTokens, rateLimiter.tokens);
+ assertEq(s_config.isEnabled, rateLimiter.isEnabled);
+ assertEq(BLOCK_TIME, rateLimiter.lastUpdated);
+ }
+
+ function test_ConsumeTokens_Success() public {
+ uint256 requestTokens = 50;
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(requestTokens);
+
+ s_helper.consume(requestTokens, s_token);
+ }
+
+ function test_Refill_Success() public {
+ uint256 requestTokens = 50;
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(requestTokens);
+
+ s_helper.consume(requestTokens, address(0));
+
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.rate, rateLimiter.rate);
+ assertEq(s_config.capacity, rateLimiter.capacity);
+ assertEq(s_config.capacity - requestTokens, rateLimiter.tokens);
+ assertEq(s_config.isEnabled, rateLimiter.isEnabled);
+ assertEq(BLOCK_TIME, rateLimiter.lastUpdated);
+
+ uint256 warpTime = 4;
+ vm.warp(BLOCK_TIME + warpTime);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(requestTokens);
+
+ s_helper.consume(requestTokens, address(0));
+
+ rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.rate, rateLimiter.rate);
+ assertEq(s_config.capacity, rateLimiter.capacity);
+ assertEq(s_config.capacity - requestTokens * 2 + warpTime * s_config.rate, rateLimiter.tokens);
+ assertEq(s_config.isEnabled, rateLimiter.isEnabled);
+ assertEq(BLOCK_TIME + warpTime, rateLimiter.lastUpdated);
+ }
+
+ function test_ConsumeUnlimited_Success() public {
+ s_helper.consume(0, address(0));
+
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.capacity, rateLimiter.tokens);
+ assertEq(s_config.isEnabled, rateLimiter.isEnabled);
+
+ RateLimiter.Config memory disableConfig = RateLimiter.Config({isEnabled: false, rate: 0, capacity: 0});
+
+ s_helper.setTokenBucketConfig(disableConfig);
+
+ uint256 requestTokens = 50;
+ s_helper.consume(requestTokens, address(0));
+
+ rateLimiter = s_helper.getRateLimiter();
+ assertEq(disableConfig.capacity, rateLimiter.tokens);
+ assertEq(disableConfig.isEnabled, rateLimiter.isEnabled);
+
+ s_helper.setTokenBucketConfig(s_config);
+
+ vm.expectRevert(abi.encodeWithSelector(RateLimiter.AggregateValueRateLimitReached.selector, 10, 0));
+ s_helper.consume(requestTokens, address(0));
+
+ rateLimiter = s_helper.getRateLimiter();
+ assertEq(s_config.rate, rateLimiter.rate);
+ assertEq(s_config.capacity, rateLimiter.capacity);
+ assertEq(0, rateLimiter.tokens);
+ assertEq(s_config.isEnabled, rateLimiter.isEnabled);
+ }
+
+ // Reverts
+
+ function test_AggregateValueMaxCapacityExceeded_Revert() public {
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ RateLimiter.AggregateValueMaxCapacityExceeded.selector, rateLimiter.capacity, rateLimiter.capacity + 1
+ )
+ );
+ s_helper.consume(rateLimiter.capacity + 1, address(0));
+ }
+
+ function test_TokenMaxCapacityExceeded_Revert() public {
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ RateLimiter.TokenMaxCapacityExceeded.selector, rateLimiter.capacity, rateLimiter.capacity + 1, s_token
+ )
+ );
+ s_helper.consume(rateLimiter.capacity + 1, s_token);
+ }
+
+ function test_ConsumingMoreThanUint128_Revert() public {
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+
+ uint256 request = uint256(type(uint128).max) + 1;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.AggregateValueMaxCapacityExceeded.selector, rateLimiter.capacity, request)
+ );
+ s_helper.consume(request, address(0));
+ }
+
+ function test_AggregateValueRateLimitReached_Revert() public {
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+
+ uint256 overLimit = 20;
+ uint256 requestTokens1 = rateLimiter.capacity / 2;
+ uint256 requestTokens2 = rateLimiter.capacity / 2 + overLimit;
+
+ uint256 waitInSeconds = overLimit / rateLimiter.rate;
+
+ s_helper.consume(requestTokens1, address(0));
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ RateLimiter.AggregateValueRateLimitReached.selector, waitInSeconds, rateLimiter.capacity - requestTokens1
+ )
+ );
+ s_helper.consume(requestTokens2, address(0));
+ }
+
+ function test_TokenRateLimitReached_Revert() public {
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+
+ uint256 overLimit = 20;
+ uint256 requestTokens1 = rateLimiter.capacity / 2;
+ uint256 requestTokens2 = rateLimiter.capacity / 2 + overLimit;
+
+ uint256 waitInSeconds = overLimit / rateLimiter.rate;
+
+ s_helper.consume(requestTokens1, s_token);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ RateLimiter.TokenRateLimitReached.selector, waitInSeconds, rateLimiter.capacity - requestTokens1, s_token
+ )
+ );
+ s_helper.consume(requestTokens2, s_token);
+ }
+
+ function test_RateLimitReachedOverConsecutiveBlocks_Revert() public {
+ uint256 initBlockTime = BLOCK_TIME + 10000;
+ vm.warp(initBlockTime);
+
+ RateLimiter.TokenBucket memory rateLimiter = s_helper.getRateLimiter();
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(rateLimiter.capacity);
+
+ s_helper.consume(rateLimiter.capacity, address(0));
+
+ vm.warp(initBlockTime + 1);
+
+ // Over rate limit by 1, force 1 second wait
+ uint256 overLimit = 1;
+
+ vm.expectRevert(abi.encodeWithSelector(RateLimiter.AggregateValueRateLimitReached.selector, 1, rateLimiter.rate));
+ s_helper.consume(rateLimiter.rate + overLimit, address(0));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/MockCommitStore.sol b/contracts/src/v0.8/ccip/test/mocks/MockCommitStore.sol
new file mode 100644
index 00000000000..aff06016fa5
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/MockCommitStore.sol
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ICommitStore} from "../../interfaces/ICommitStore.sol";
+
+contract MockCommitStore is ICommitStore {
+ error PausedError();
+
+ uint64 private s_expectedNextSequenceNumber = 1;
+
+ bool private s_paused = false;
+
+ /// @inheritdoc ICommitStore
+ function verify(
+ bytes32[] calldata,
+ bytes32[] calldata,
+ uint256
+ ) external view whenNotPaused returns (uint256 timestamp) {
+ return 1;
+ }
+
+ function getExpectedNextSequenceNumber() external view returns (uint64) {
+ return s_expectedNextSequenceNumber;
+ }
+
+ function setExpectedNextSequenceNumber(uint64 nextSeqNum) external {
+ s_expectedNextSequenceNumber = nextSeqNum;
+ }
+
+ modifier whenNotPaused() {
+ if (paused()) revert PausedError();
+ _;
+ }
+
+ function paused() public view returns (bool) {
+ return s_paused;
+ }
+
+ function pause() external {
+ s_paused = true;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/MockE2EUSDCTokenMessenger.sol b/contracts/src/v0.8/ccip/test/mocks/MockE2EUSDCTokenMessenger.sol
new file mode 100644
index 00000000000..9fa5cd1a66d
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/MockE2EUSDCTokenMessenger.sol
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2022, Circle Internet Financial Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+pragma solidity 0.8.24;
+
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
+import {ITokenMessenger} from "../../pools/USDC/ITokenMessenger.sol";
+import {IMessageTransmitterWithRelay} from "./interfaces/IMessageTransmitterWithRelay.sol";
+
+// This contract mocks both the ITokenMessenger and IMessageTransmitter
+// contracts involved with the Cross Chain Token Protocol.
+contract MockE2EUSDCTokenMessenger is ITokenMessenger {
+ uint32 private immutable i_messageBodyVersion;
+ address private immutable i_transmitter;
+
+ bytes32 public constant DESTINATION_TOKEN_MESSENGER = keccak256("i_destinationTokenMessenger");
+
+ uint64 public s_nonce;
+
+ // Local Message Transmitter responsible for sending and receiving messages to/from remote domains
+ IMessageTransmitterWithRelay public immutable localMessageTransmitterWithRelay;
+
+ constructor(uint32 version, address transmitter) {
+ i_messageBodyVersion = version;
+ s_nonce = 1;
+ i_transmitter = transmitter;
+ localMessageTransmitterWithRelay = IMessageTransmitterWithRelay(transmitter);
+ }
+
+ // The mock function is based on the same function in https://github.com/circlefin/evm-cctp-contracts/blob/master/src/TokenMessenger.sol
+ function depositForBurnWithCaller(
+ uint256 amount,
+ uint32 destinationDomain,
+ bytes32 mintRecipient,
+ address burnToken,
+ bytes32 destinationCaller
+ ) external returns (uint64) {
+ IBurnMintERC20(burnToken).transferFrom(msg.sender, address(this), amount);
+ IBurnMintERC20(burnToken).burn(amount);
+ // Format message body
+ bytes memory _burnMessage =
+ abi.encodePacked(i_messageBodyVersion, burnToken, mintRecipient, amount, bytes32(uint256(uint160((msg.sender)))));
+ s_nonce =
+ _sendDepositForBurnMessage(destinationDomain, DESTINATION_TOKEN_MESSENGER, destinationCaller, _burnMessage);
+ emit DepositForBurn(
+ s_nonce,
+ burnToken,
+ amount,
+ msg.sender,
+ mintRecipient,
+ destinationDomain,
+ DESTINATION_TOKEN_MESSENGER,
+ destinationCaller
+ );
+ return s_nonce;
+ }
+
+ function messageBodyVersion() external view returns (uint32) {
+ return i_messageBodyVersion;
+ }
+
+ function localMessageTransmitter() external view returns (address) {
+ return i_transmitter;
+ }
+
+ /**
+ * @notice Sends a BurnMessage through the local message transmitter
+ * @dev calls local message transmitter's sendMessage() function if `_destinationCaller` == bytes32(0),
+ * or else calls sendMessageWithCaller().
+ * @param _destinationDomain destination domain
+ * @param _destinationTokenMessenger address of registered TokenMessenger contract on destination domain, as bytes32
+ * @param _destinationCaller caller on the destination domain, as bytes32. If `_destinationCaller` == bytes32(0),
+ * any address can call receiveMessage() on destination domain.
+ * @param _burnMessage formatted BurnMessage bytes (message body)
+ * @return nonce unique nonce reserved by message
+ */
+ function _sendDepositForBurnMessage(
+ uint32 _destinationDomain,
+ bytes32 _destinationTokenMessenger,
+ bytes32 _destinationCaller,
+ bytes memory _burnMessage
+ ) internal returns (uint64 nonce) {
+ if (_destinationCaller == bytes32(0)) {
+ return localMessageTransmitterWithRelay.sendMessage(_destinationDomain, _destinationTokenMessenger, _burnMessage);
+ } else {
+ return localMessageTransmitterWithRelay.sendMessageWithCaller(
+ _destinationDomain, _destinationTokenMessenger, _destinationCaller, _burnMessage
+ );
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/MockE2EUSDCTransmitter.sol b/contracts/src/v0.8/ccip/test/mocks/MockE2EUSDCTransmitter.sol
new file mode 100644
index 00000000000..8e50bedea99
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/MockE2EUSDCTransmitter.sol
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2022, Circle Internet Financial Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+pragma solidity ^0.8.0;
+
+import {IMessageTransmitterWithRelay} from "./interfaces/IMessageTransmitterWithRelay.sol";
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+
+contract MockE2EUSDCTransmitter is IMessageTransmitterWithRelay {
+ // Indicated whether the receiveMessage() call should succeed.
+ bool public s_shouldSucceed;
+ uint32 private immutable i_version;
+ uint32 private immutable i_localDomain;
+ // Next available nonce from this source domain
+ uint64 public nextAvailableNonce;
+
+ BurnMintERC677 internal immutable i_token;
+
+ /**
+ * @notice Emitted when a new message is dispatched
+ * @param message Raw bytes of message
+ */
+ event MessageSent(bytes message);
+
+ constructor(uint32 _version, uint32 _localDomain, address token) {
+ i_version = _version;
+ i_localDomain = _localDomain;
+ s_shouldSucceed = true;
+
+ i_token = BurnMintERC677(token);
+ }
+
+ /// @param message The original message on the source chain
+ /// * Message format:
+ /// * Field Bytes Type Index
+ /// * version 4 uint32 0
+ /// * sourceDomain 4 uint32 4
+ /// * destinationDomain 4 uint32 8
+ /// * nonce 8 uint64 12
+ /// * sender 32 bytes32 20
+ /// * recipient 32 bytes32 52
+ /// * destinationCaller 32 bytes32 84
+ /// * messageBody dynamic bytes 116
+ function receiveMessage(bytes calldata message, bytes calldata) external returns (bool success) {
+ address recipient = address(bytes20(message[64:84]));
+
+ // We always mint 1000e18 tokens to not complicate the test.
+ i_token.mint(recipient, 1000e18);
+
+ return s_shouldSucceed;
+ }
+
+ function setShouldSucceed(bool shouldSucceed) external {
+ s_shouldSucceed = shouldSucceed;
+ }
+
+ function version() external view returns (uint32) {
+ return i_version;
+ }
+
+ function localDomain() external view returns (uint32) {
+ return i_localDomain;
+ }
+
+ /**
+ * This is based on similar function in https://github.com/circlefin/evm-cctp-contracts/blob/master/src/MessageTransmitter.sol
+ * @notice Send the message to the destination domain and recipient
+ * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.
+ * @param destinationDomain Domain of destination chain
+ * @param recipient Address of message recipient on destination chain as bytes32
+ * @param messageBody Raw bytes content of message
+ * @return nonce reserved by message
+ */
+ function sendMessage(
+ uint32 destinationDomain,
+ bytes32 recipient,
+ bytes calldata messageBody
+ ) external returns (uint64) {
+ bytes32 _emptyDestinationCaller = bytes32(0);
+ uint64 _nonce = _reserveAndIncrementNonce();
+ bytes32 _messageSender = bytes32(uint256(uint160((msg.sender))));
+
+ _sendMessage(destinationDomain, recipient, _emptyDestinationCaller, _messageSender, _nonce, messageBody);
+
+ return _nonce;
+ }
+
+ /**
+ * @notice Send the message to the destination domain and recipient, for a specified `destinationCaller` on the
+ * destination domain.
+ * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.
+ * WARNING: if the `destinationCaller` does not represent a valid address, then it will not be possible
+ * to broadcast the message on the destination domain. This is an advanced feature, and the standard
+ * sendMessage() should be preferred for use cases where a specific destination caller is not required.
+ * @param destinationDomain Domain of destination chain
+ * @param recipient Address of message recipient on destination domain as bytes32
+ * @param destinationCaller caller on the destination domain, as bytes32
+ * @param messageBody Raw bytes content of message
+ * @return nonce reserved by message
+ */
+ function sendMessageWithCaller(
+ uint32 destinationDomain,
+ bytes32 recipient,
+ bytes32 destinationCaller,
+ bytes calldata messageBody
+ ) external returns (uint64) {
+ require(destinationCaller != bytes32(0), "Destination caller must be nonzero");
+
+ uint64 _nonce = _reserveAndIncrementNonce();
+ bytes32 _messageSender = bytes32(uint256(uint160((msg.sender))));
+
+ _sendMessage(destinationDomain, recipient, destinationCaller, _messageSender, _nonce, messageBody);
+
+ return _nonce;
+ }
+
+ /**
+ * Reserve and increment next available nonce
+ * @return nonce reserved
+ */
+ function _reserveAndIncrementNonce() internal returns (uint64) {
+ uint64 _nonceReserved = nextAvailableNonce;
+ nextAvailableNonce = nextAvailableNonce + 1;
+ return _nonceReserved;
+ }
+
+ /**
+ * @notice Send the message to the destination domain and recipient. If `_destinationCaller` is not equal to bytes32(0),
+ * the message can only be received on the destination chain when called by `_destinationCaller`.
+ * @dev Format the message and emit `MessageSent` event with message information.
+ * @param _destinationDomain Domain of destination chain
+ * @param _recipient Address of message recipient on destination domain as bytes32
+ * @param _destinationCaller caller on the destination domain, as bytes32
+ * @param _sender message sender, as bytes32
+ * @param _nonce nonce reserved for message
+ * @param _messageBody Raw bytes content of message
+ */
+ function _sendMessage(
+ uint32 _destinationDomain,
+ bytes32 _recipient,
+ bytes32 _destinationCaller,
+ bytes32 _sender,
+ uint64 _nonce,
+ bytes calldata _messageBody
+ ) internal {
+ require(_recipient != bytes32(0), "Recipient must be nonzero");
+ // serialize message
+ bytes memory _message = abi.encodePacked(
+ i_version, i_localDomain, _destinationDomain, _nonce, _sender, _recipient, _destinationCaller, _messageBody
+ );
+
+ // Emit MessageSent event
+ emit MessageSent(_message);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/MockRMN.sol b/contracts/src/v0.8/ccip/test/mocks/MockRMN.sol
new file mode 100644
index 00000000000..3f7b0200e6f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/MockRMN.sol
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {RMN} from "../../RMN.sol";
+import {IRMN} from "../../interfaces/IRMN.sol";
+import {OwnerIsCreator} from "./../../../shared/access/OwnerIsCreator.sol";
+
+/// @notice WARNING: This contract is to be only used for testing, all methods are unprotected.
+contract MockRMN is IRMN {
+ error CustomError(bytes err);
+
+ bytes private s_isCursedRevert;
+
+ bool private s_globalCursed;
+ mapping(bytes16 subject => bool cursed) private s_cursedBySubject;
+ mapping(address commitStore => mapping(bytes32 root => bool blessed)) private s_blessedByRoot;
+
+ function setTaggedRootBlessed(IRMN.TaggedRoot calldata taggedRoot, bool blessed) external {
+ s_blessedByRoot[taggedRoot.commitStore][taggedRoot.root] = blessed;
+ }
+
+ function setGlobalCursed(bool cursed) external {
+ s_globalCursed = cursed;
+ }
+
+ function setChainCursed(uint64 chainSelector, bool cursed) external {
+ s_cursedBySubject[bytes16(uint128(chainSelector))] = cursed;
+ }
+
+ /// @notice Setting a revert error with length of 0 will disable reverts
+ /// @dev Useful to test revert handling of ARMProxy
+ function setIsCursedRevert(bytes calldata revertErr) external {
+ s_isCursedRevert = revertErr;
+ }
+
+ // IRMN implementation follows
+
+ function isCursed() external view returns (bool) {
+ if (s_isCursedRevert.length > 0) {
+ revert CustomError(s_isCursedRevert);
+ }
+ return s_globalCursed;
+ }
+
+ function isCursed(bytes16 subject) external view returns (bool) {
+ if (s_isCursedRevert.length > 0) {
+ revert CustomError(s_isCursedRevert);
+ }
+ return s_globalCursed || s_cursedBySubject[subject];
+ }
+
+ function isBlessed(IRMN.TaggedRoot calldata taggedRoot) external view returns (bool) {
+ return s_blessedByRoot[taggedRoot.commitStore][taggedRoot.root];
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/MockRMN1_0.sol b/contracts/src/v0.8/ccip/test/mocks/MockRMN1_0.sol
new file mode 100644
index 00000000000..44ffc23b78f
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/MockRMN1_0.sol
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IRMN} from "../../interfaces/IRMN.sol";
+import {OwnerIsCreator} from "./../../../shared/access/OwnerIsCreator.sol";
+
+// Inlined from RMN 1.0 contract.
+// solhint-disable gas-struct-packing
+contract RMN {
+ struct Voter {
+ address blessVoteAddr;
+ address curseVoteAddr;
+ address curseUnvoteAddr;
+ uint8 blessWeight;
+ uint8 curseWeight;
+ }
+
+ struct Config {
+ Voter[] voters;
+ uint16 blessWeightThreshold;
+ uint16 curseWeightThreshold;
+ }
+
+ struct VersionedConfig {
+ Config config;
+ uint32 configVersion;
+ uint32 blockNumber;
+ }
+
+ struct UnvoteToCurseRecord {
+ address curseVoteAddr;
+ bytes32 cursesHash;
+ bool forceUnvote;
+ }
+}
+
+/// @dev Retained almost as-is from commit 88f285b94c23d0c684d337064758a5edde380fe2 for compatibility with offchain
+/// tests and scripts. Internal structs of the RMN 1.0 contract that were depended on have been inlined.
+/// @dev This contract should no longer be used for any new tests or scripts.
+/// @notice WARNING: This contract is to be only used for testing, all methods are unprotected.
+// TODO: remove this contract when tests and scripts are updated
+contract MockRMN is IRMN, OwnerIsCreator {
+ error CustomError(bytes err);
+
+ bool private s_curse;
+ bytes private s_err;
+ RMN.VersionedConfig private s_versionedConfig;
+ mapping(bytes16 subject => bool cursed) private s_curseBySubject;
+
+ function isCursed() external view override returns (bool) {
+ if (s_err.length != 0) {
+ revert CustomError(s_err);
+ }
+ return s_curse;
+ }
+
+ function isCursed(bytes16 subject) external view override returns (bool) {
+ if (s_err.length != 0) {
+ revert CustomError(s_err);
+ }
+ return s_curse || s_curseBySubject[subject];
+ }
+
+ function voteToCurse(bytes32) external {
+ s_curse = true;
+ }
+
+ function voteToCurse(bytes32, bytes16 subject) external {
+ s_curseBySubject[subject] = true;
+ }
+
+ function ownerUnvoteToCurse(RMN.UnvoteToCurseRecord[] memory) external {
+ s_curse = false;
+ }
+
+ function ownerUnvoteToCurse(RMN.UnvoteToCurseRecord[] memory, bytes16 subject) external {
+ s_curseBySubject[subject] = false;
+ }
+
+ function setRevert(bytes memory err) external {
+ s_err = err;
+ }
+
+ function isBlessed(IRMN.TaggedRoot calldata) external view override returns (bool) {
+ return !s_curse;
+ }
+
+ function getConfigDetails() external view returns (uint32 version, uint32 blockNumber, RMN.Config memory config) {
+ return (s_versionedConfig.configVersion, s_versionedConfig.blockNumber, s_versionedConfig.config);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/MockRouter.sol b/contracts/src/v0.8/ccip/test/mocks/MockRouter.sol
new file mode 100644
index 00000000000..87db0319514
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/MockRouter.sol
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import {IAny2EVMMessageReceiver} from "../../interfaces/IAny2EVMMessageReceiver.sol";
+import {IRouter} from "../../interfaces/IRouter.sol";
+import {IRouterClient} from "../../interfaces/IRouterClient.sol";
+
+import {CallWithExactGas} from "../../../shared/call/CallWithExactGas.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.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";
+import {ERC165Checker} from
+ "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol";
+
+contract MockCCIPRouter is IRouter, IRouterClient {
+ using SafeERC20 for IERC20;
+ using ERC165Checker for address;
+
+ error InvalidAddress(bytes encodedAddress);
+ error InvalidExtraArgsTag();
+ error ReceiverError(bytes err);
+
+ event MessageExecuted(bytes32 messageId, uint64 sourceChainSelector, address offRamp, bytes32 calldataHash);
+ event MsgExecuted(bool success, bytes retData, uint256 gasUsed);
+
+ uint16 public constant GAS_FOR_CALL_EXACT_CHECK = 5_000;
+ uint32 public constant DEFAULT_GAS_LIMIT = 200_000;
+
+ uint256 internal s_mockFeeTokenAmount; //use setFee() to change to non-zero to test fees
+
+ function routeMessage(
+ Client.Any2EVMMessage calldata message,
+ uint16 gasForCallExactCheck,
+ uint256 gasLimit,
+ address receiver
+ ) external returns (bool success, bytes memory retData, uint256 gasUsed) {
+ return _routeMessage(message, gasForCallExactCheck, gasLimit, receiver);
+ }
+
+ function _routeMessage(
+ Client.Any2EVMMessage memory message,
+ uint16 gasForCallExactCheck,
+ uint256 gasLimit,
+ address receiver
+ ) internal returns (bool success, bytes memory retData, uint256 gasUsed) {
+ // Only send through the router if the receiver is a contract and implements the IAny2EVMMessageReceiver interface.
+ if (receiver.code.length == 0 || !receiver.supportsInterface(type(IAny2EVMMessageReceiver).interfaceId)) {
+ return (true, "", 0);
+ }
+
+ bytes memory data = abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message);
+
+ (success, retData, gasUsed) = CallWithExactGas._callWithExactGasSafeReturnData(
+ data, receiver, gasLimit, gasForCallExactCheck, Internal.MAX_RET_BYTES
+ );
+
+ // Event to assist testing, does not exist on real deployments
+ emit MsgExecuted(success, retData, gasUsed);
+
+ // Real router event
+ emit MessageExecuted(message.messageId, message.sourceChainSelector, msg.sender, keccak256(data));
+ return (success, retData, gasUsed);
+ }
+
+ /// @notice Sends the tx locally to the receiver instead of on the destination chain.
+ /// @dev Ignores destinationChainSelector
+ /// @dev Returns a mock message ID, which is not calculated from the message contents in the
+ /// same way as the real message ID.
+ function ccipSend(
+ uint64 destinationChainSelector,
+ Client.EVM2AnyMessage calldata message
+ ) external payable returns (bytes32) {
+ if (message.receiver.length != 32) revert InvalidAddress(message.receiver);
+ uint256 decodedReceiver = abi.decode(message.receiver, (uint256));
+ // We want to disallow sending to address(0) and to precompiles, which exist on address(1) through address(9).
+ if (decodedReceiver > type(uint160).max || decodedReceiver < 10) revert InvalidAddress(message.receiver);
+
+ uint256 feeTokenAmount = getFee(destinationChainSelector, message);
+ if (message.feeToken == address(0)) {
+ if (msg.value < feeTokenAmount) revert InsufficientFeeTokenAmount();
+ } else {
+ if (msg.value > 0) revert InvalidMsgValue();
+ IERC20(message.feeToken).safeTransferFrom(msg.sender, address(this), feeTokenAmount);
+ }
+
+ address receiver = address(uint160(decodedReceiver));
+ uint256 gasLimit = _fromBytes(message.extraArgs).gasLimit;
+ bytes32 mockMsgId = keccak256(abi.encode(message));
+
+ Client.Any2EVMMessage memory executableMsg = Client.Any2EVMMessage({
+ messageId: mockMsgId,
+ sourceChainSelector: 16015286601757825753, // Sepolia
+ sender: abi.encode(msg.sender),
+ data: message.data,
+ destTokenAmounts: message.tokenAmounts
+ });
+
+ for (uint256 i = 0; i < message.tokenAmounts.length; ++i) {
+ IERC20(message.tokenAmounts[i].token).safeTransferFrom(msg.sender, receiver, message.tokenAmounts[i].amount);
+ }
+
+ (bool success, bytes memory retData,) = _routeMessage(executableMsg, GAS_FOR_CALL_EXACT_CHECK, gasLimit, receiver);
+
+ if (!success) revert ReceiverError(retData);
+
+ return mockMsgId;
+ }
+
+ function _fromBytes(bytes calldata extraArgs) internal pure returns (Client.EVMExtraArgsV1 memory) {
+ if (extraArgs.length == 0) {
+ return Client.EVMExtraArgsV1({gasLimit: DEFAULT_GAS_LIMIT});
+ }
+ if (bytes4(extraArgs) != Client.EVM_EXTRA_ARGS_V1_TAG) revert InvalidExtraArgsTag();
+ return abi.decode(extraArgs[4:], (Client.EVMExtraArgsV1));
+ }
+
+ /// @notice Always returns true to make sure this check can be performed on any chain.
+ function isChainSupported(uint64) external pure returns (bool supported) {
+ return true;
+ }
+
+ /// @notice Returns an empty array.
+ function getSupportedTokens(uint64) external pure returns (address[] memory tokens) {
+ return new address[](0);
+ }
+
+ /// @notice Returns 0 as the fee is not supported in this mock contract.
+ function getFee(uint64, Client.EVM2AnyMessage memory) public view returns (uint256) {
+ return s_mockFeeTokenAmount;
+ }
+
+ /// @notice Sets the fees returned by getFee but is only checked when using native fee tokens
+ function setFee(uint256 feeAmount) external {
+ s_mockFeeTokenAmount = feeAmount;
+ }
+
+ /// @notice Always returns address(1234567890)
+ function getOnRamp(uint64 /* destChainSelector */ ) external pure returns (address onRampAddress) {
+ return address(1234567890);
+ }
+
+ /// @notice Always returns true
+ function isOffRamp(uint64, /* sourceChainSelector */ address /* offRamp */ ) external pure returns (bool) {
+ return true;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/MockUSDCTokenMessenger.sol b/contracts/src/v0.8/ccip/test/mocks/MockUSDCTokenMessenger.sol
new file mode 100644
index 00000000000..562a9f467ff
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/MockUSDCTokenMessenger.sol
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
+import {ITokenMessenger} from "../../pools/USDC/ITokenMessenger.sol";
+
+// This contract mocks both the ITokenMessenger and IMessageTransmitter
+// contracts involved with the Cross Chain Token Protocol.
+contract MockUSDCTokenMessenger is ITokenMessenger {
+ uint32 private immutable i_messageBodyVersion;
+ address private immutable i_transmitter;
+
+ bytes32 public constant DESTINATION_TOKEN_MESSENGER = keccak256("i_destinationTokenMessenger");
+
+ uint64 public s_nonce;
+
+ constructor(uint32 version, address transmitter) {
+ i_messageBodyVersion = version;
+ s_nonce = 1;
+ i_transmitter = transmitter;
+ }
+
+ function depositForBurnWithCaller(
+ uint256 amount,
+ uint32 destinationDomain,
+ bytes32 mintRecipient,
+ address burnToken,
+ bytes32 destinationCaller
+ ) external returns (uint64) {
+ IBurnMintERC20(burnToken).transferFrom(msg.sender, address(this), amount);
+ IBurnMintERC20(burnToken).burn(amount);
+ emit DepositForBurn(
+ s_nonce,
+ burnToken,
+ amount,
+ msg.sender,
+ mintRecipient,
+ destinationDomain,
+ DESTINATION_TOKEN_MESSENGER,
+ destinationCaller
+ );
+ return s_nonce++;
+ }
+
+ function messageBodyVersion() external view returns (uint32) {
+ return i_messageBodyVersion;
+ }
+
+ function localMessageTransmitter() external view returns (address) {
+ return i_transmitter;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/interfaces/IMessageTransmitterWithRelay.sol b/contracts/src/v0.8/ccip/test/mocks/interfaces/IMessageTransmitterWithRelay.sol
new file mode 100644
index 00000000000..dc9c644e07a
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/interfaces/IMessageTransmitterWithRelay.sol
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022, Circle Internet Financial Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+pragma solidity ^0.8.0;
+
+import {IMessageTransmitter} from "../../../pools/USDC/IMessageTransmitter.sol";
+
+// This follows https://github.com/circlefin/evm-cctp-contracts/blob/master/src/interfaces/IMessageTransmitter.sol
+interface IMessageTransmitterWithRelay is IMessageTransmitter {
+ /**
+ * @notice Sends an outgoing message from the source domain.
+ * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.
+ * @param destinationDomain Domain of destination chain
+ * @param recipient Address of message recipient on destination domain as bytes32
+ * @param messageBody Raw bytes content of message
+ * @return nonce reserved by message
+ */
+ function sendMessage(
+ uint32 destinationDomain,
+ bytes32 recipient,
+ bytes calldata messageBody
+ ) external returns (uint64);
+
+ /**
+ * @notice Sends an outgoing message from the source domain, with a specified caller on the
+ * destination domain.
+ * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.
+ * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible
+ * to broadcast the message on the destination domain. This is an advanced feature, and the standard
+ * sendMessage() should be preferred for use cases where a specific destination caller is not required.
+ * @param destinationDomain Domain of destination chain
+ * @param recipient Address of message recipient on destination domain as bytes32
+ * @param destinationCaller caller on the destination domain, as bytes32
+ * @param messageBody Raw bytes content of message
+ * @return nonce reserved by message
+ */
+ function sendMessageWithCaller(
+ uint32 destinationDomain,
+ bytes32 recipient,
+ bytes32 destinationCaller,
+ bytes calldata messageBody
+ ) external returns (uint64);
+}
diff --git a/contracts/src/v0.8/ccip/test/mocks/test/MockRouterTest.t.sol b/contracts/src/v0.8/ccip/test/mocks/test/MockRouterTest.t.sol
new file mode 100644
index 00000000000..91798b494df
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/mocks/test/MockRouterTest.t.sol
@@ -0,0 +1,68 @@
+pragma solidity ^0.8.0;
+
+import {Client} from "../../../libraries/Client.sol";
+
+import {TokenSetup} from "../../TokenSetup.t.sol";
+import {IRouter, IRouterClient, MockCCIPRouter} from "../MockRouter.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 MockRouterTest is TokenSetup {
+ using SafeERC20 for IERC20;
+
+ MockCCIPRouter public mockRouter;
+
+ uint64 public constant mockChainSelector = 123456;
+
+ Client.EVM2AnyMessage public message;
+
+ function setUp() public override {
+ mockRouter = new MockCCIPRouter();
+
+ //Configure the Fee to 0.1 ether for native token fees
+ mockRouter.setFee(0.1 ether);
+
+ deal(address(this), 100 ether);
+
+ message.receiver = abi.encode(address(0x12345));
+ message.data = abi.encode("Hello World");
+
+ s_sourceFeeToken = _deploySourceToken("sLINK", type(uint256).max, 18);
+ }
+
+ function test_ccipSendWithInsufficientNativeTokens_Revert() public {
+ //Should revert because did not include sufficient eth to pay for fees
+ vm.expectRevert(IRouterClient.InsufficientFeeTokenAmount.selector);
+ mockRouter.ccipSend(mockChainSelector, message);
+ }
+
+ function test_ccipSendWithSufficientNativeFeeTokens_Success() public {
+ //ccipSend with sufficient native tokens for fees
+ mockRouter.ccipSend{value: 0.1 ether}(mockChainSelector, message);
+ }
+
+ function test_ccipSendWithInvalidMsgValue_Revert() public {
+ message.feeToken = address(1); //Set to non native-token fees
+
+ vm.expectRevert(IRouterClient.InvalidMsgValue.selector);
+ mockRouter.ccipSend{value: 0.1 ether}(mockChainSelector, message);
+ }
+
+ function test_ccipSendWithLinkFeeTokenbutInsufficientAllowance_Revert() public {
+ message.feeToken = s_sourceFeeToken;
+
+ vm.expectRevert(bytes("ERC20: insufficient allowance"));
+ mockRouter.ccipSend(mockChainSelector, message);
+ }
+
+ function test_ccipSendWithLinkFeeTokenAndValidMsgValue_Success() public {
+ message.feeToken = s_sourceFeeToken;
+
+ vm.startPrank(OWNER, OWNER);
+
+ IERC20(s_sourceFeeToken).safeApprove(address(mockRouter), type(uint256).max);
+
+ mockRouter.ccipSend(mockChainSelector, message);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base.t.sol b/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base.t.sol
new file mode 100644
index 00000000000..5b784bf7219
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base.t.sol
@@ -0,0 +1,921 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {MultiOCR3Base} from "../../ocr/MultiOCR3Base.sol";
+import {MultiOCR3Helper} from "../helpers/MultiOCR3Helper.sol";
+import {MultiOCR3BaseSetup} from "./MultiOCR3BaseSetup.t.sol";
+
+import {Vm} from "forge-std/Vm.sol";
+
+contract MultiOCR3Base_transmit is MultiOCR3BaseSetup {
+ bytes32 internal s_configDigest1;
+ bytes32 internal s_configDigest2;
+ bytes32 internal s_configDigest3;
+
+ function setUp() public virtual override {
+ super.setUp();
+
+ s_configDigest1 = _getBasicConfigDigest(1, s_validSigners, s_validTransmitters);
+ s_configDigest2 = _getBasicConfigDigest(1, s_validSigners, s_validTransmitters);
+ s_configDigest3 = _getBasicConfigDigest(2, s_emptySigners, s_validTransmitters);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](3);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: s_configDigest1,
+ F: 1,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+ ocrConfigs[1] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 1,
+ configDigest: s_configDigest2,
+ F: 2,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+ ocrConfigs[2] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 2,
+ configDigest: s_configDigest3,
+ F: 1,
+ isSignatureVerificationEnabled: false,
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_TransmitSigners_gas_Success() public {
+ vm.pauseGasMetering();
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ // F = 2, need 2 signatures
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, REPORT, reportContext, 2);
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(0, s_configDigest1, uint64(uint256(s_configDigest1)));
+
+ vm.startPrank(s_validTransmitters[1]);
+ vm.resumeGasMetering();
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ function test_TransmitWithoutSignatureVerification_gas_Success() public {
+ vm.pauseGasMetering();
+ bytes32[3] memory reportContext = [s_configDigest3, s_configDigest3, s_configDigest3];
+
+ s_multiOCR3.setTransmitOcrPluginType(2);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(2, s_configDigest3, uint64(uint256(s_configDigest3)));
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.resumeGasMetering();
+ s_multiOCR3.transmitWithoutSignatures(reportContext, REPORT);
+ }
+
+ function test_Fuzz_TransmitSignersWithSignatures_Success(uint8 F, uint64 randomAddressOffset) public {
+ vm.pauseGasMetering();
+
+ F = uint8(bound(F, 1, 3));
+
+ // condition: signers.length > 3F
+ uint8 signersLength = 3 * F + 1;
+ address[] memory signers = new address[](signersLength);
+ address[] memory transmitters = new address[](signersLength);
+ uint256[] memory signerKeys = new uint256[](signersLength);
+
+ // Force addresses to be unique (with a random offset for broader testing)
+ for (uint160 i = 0; i < signersLength; ++i) {
+ transmitters[i] = vm.addr(PRIVATE0 + randomAddressOffset + i);
+ // condition: non-zero oracle address
+ vm.assume(transmitters[i] != address(0));
+
+ // condition: non-repeating addresses (no clashes with transmitters)
+ signerKeys[i] = PRIVATE0 + randomAddressOffset + i + signersLength;
+ signers[i] = vm.addr(signerKeys[i]);
+ vm.assume(signers[i] != address(0));
+ }
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 3,
+ configDigest: s_configDigest1,
+ F: F,
+ isSignatureVerificationEnabled: true,
+ signers: signers,
+ transmitters: transmitters
+ });
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ s_multiOCR3.setTransmitOcrPluginType(3);
+
+ // Randomise picked transmitter with random offset
+ vm.startPrank(transmitters[randomAddressOffset % signersLength]);
+
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ // condition: matches signature expectation for transmit
+ uint8 numSignatures = F + 1;
+ uint256[] memory pickedSignerKeys = new uint256[](numSignatures);
+
+ // Randomise picked signers with random offset
+ for (uint256 i; i < numSignatures; ++i) {
+ pickedSignerKeys[i] = signerKeys[(i + randomAddressOffset) % numSignatures];
+ }
+
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(pickedSignerKeys, REPORT, reportContext, numSignatures);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(3, s_configDigest1, uint64(uint256(s_configDigest1)));
+
+ vm.resumeGasMetering();
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ // Reverts
+ function test_ForkedChain_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, REPORT, reportContext, 2);
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ uint256 chain1 = block.chainid;
+ uint256 chain2 = chain1 + 1;
+ vm.chainId(chain2);
+ vm.expectRevert(abi.encodeWithSelector(MultiOCR3Base.ForkedChain.selector, chain1, chain2));
+
+ vm.startPrank(s_validTransmitters[0]);
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ function test_ZeroSignatures_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert(MultiOCR3Base.WrongNumberOfSignatures.selector);
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, new bytes32[](0), new bytes32[](0), bytes32(""));
+ }
+
+ function test_TooManySignatures_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ // 1 signature too many
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, REPORT, reportContext, 6);
+
+ s_multiOCR3.setTransmitOcrPluginType(1);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert(MultiOCR3Base.WrongNumberOfSignatures.selector);
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ function test_InsufficientSignatures_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ // Missing 1 signature for unique report
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, REPORT, reportContext, 4);
+
+ s_multiOCR3.setTransmitOcrPluginType(1);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert(MultiOCR3Base.WrongNumberOfSignatures.selector);
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ function test_ConfigDigestMismatch_Revert() public {
+ bytes32 configDigest;
+ bytes32[3] memory reportContext = [configDigest, configDigest, configDigest];
+
+ (,,, bytes32 rawVs) = _getSignaturesForDigest(s_validSignerKeys, REPORT, reportContext, 2);
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ vm.expectRevert(abi.encodeWithSelector(MultiOCR3Base.ConfigDigestMismatch.selector, s_configDigest1, configDigest));
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, new bytes32[](0), new bytes32[](0), rawVs);
+ }
+
+ function test_SignatureOutOfRegistration_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](1);
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert(MultiOCR3Base.SignaturesOutOfRegistration.selector);
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, bytes32(""));
+ }
+
+ function test_UnAuthorizedTransmitter_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](2);
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ vm.expectRevert(MultiOCR3Base.UnauthorizedTransmitter.selector);
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, bytes32(""));
+ }
+
+ function test_NonUniqueSignature_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ (bytes32[] memory rs, bytes32[] memory ss, uint8[] memory vs, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, REPORT, reportContext, 2);
+
+ rs[1] = rs[0];
+ ss[1] = ss[0];
+ // Need to reset the rawVs to be valid
+ rawVs = bytes32(bytes1(vs[0] - 27)) | (bytes32(bytes1(vs[0] - 27)) >> 8);
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert(MultiOCR3Base.NonUniqueSignatures.selector);
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ function test_UnauthorizedSigner_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, REPORT, reportContext, 2);
+
+ rs[0] = s_configDigest1;
+ ss = rs;
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert(MultiOCR3Base.UnauthorizedSigner.selector);
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ function test_UnconfiguredPlugin_Revert() public {
+ bytes32 configDigest;
+ bytes32[3] memory reportContext = [configDigest, configDigest, configDigest];
+
+ s_multiOCR3.setTransmitOcrPluginType(42);
+
+ vm.expectRevert(MultiOCR3Base.UnauthorizedTransmitter.selector);
+ s_multiOCR3.transmitWithoutSignatures(reportContext, REPORT);
+ }
+
+ function test_TransmitWithLessCalldataArgs_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+
+ s_multiOCR3.setTransmitOcrPluginType(0);
+
+ // The transmit should fail, since we are trying to transmit without signatures when signatures are enabled
+ vm.startPrank(s_validTransmitters[1]);
+
+ // report length + function selector + report length + abiencoded location of report value + report context words
+ uint256 receivedLength = REPORT.length + 4 + 5 * 32;
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ MultiOCR3Base.WrongMessageLength.selector,
+ // Expecting inclusion of signature constant length components
+ receivedLength + 5 * 32,
+ receivedLength
+ )
+ );
+ s_multiOCR3.transmitWithoutSignatures(reportContext, REPORT);
+ }
+
+ function test_TransmitWithExtraCalldataArgs_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest1, s_configDigest1, s_configDigest1];
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](2);
+
+ s_multiOCR3.setTransmitOcrPluginType(2);
+
+ // The transmit should fail, since we are trying to transmit with signatures when signatures are disabled
+ vm.startPrank(s_validTransmitters[1]);
+
+ // dynamic length + function selector + report length + abiencoded location of report value + report context words
+ // rawVs value, lengths of rs, ss, and start locations of rs & ss -> 5 words
+ uint256 receivedLength = REPORT.length + 4 + (5 * 32) + (5 * 32) + (2 * 32) + (2 * 32);
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ MultiOCR3Base.WrongMessageLength.selector,
+ // Expecting exclusion of signature constant length components and rs, ss words
+ receivedLength - (5 * 32) - (4 * 32),
+ receivedLength
+ )
+ );
+ s_multiOCR3.transmitWithSignatures(reportContext, REPORT, rs, ss, bytes32(""));
+ }
+}
+
+contract MultiOCR3Base_setOCR3Configs is MultiOCR3BaseSetup {
+ function test_SetConfigsZeroInput_Success() public {
+ vm.recordLogs();
+ s_multiOCR3.setOCR3Configs(new MultiOCR3Base.OCRConfigArgs[](0));
+
+ // No logs emitted
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 0);
+ }
+
+ function test_SetConfigWithSigners_Success() public {
+ uint8 F = 2;
+
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(0));
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(F, s_validSigners, s_validTransmitters),
+ F: F,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+
+ vm.expectEmit();
+ emit MultiOCR3Base.ConfigSet(
+ ocrConfigs[0].ocrPluginType,
+ ocrConfigs[0].configDigest,
+ ocrConfigs[0].signers,
+ ocrConfigs[0].transmitters,
+ ocrConfigs[0].F
+ );
+
+ vm.expectEmit();
+ emit MultiOCR3Helper.AfterConfigSet(ocrConfigs[0].ocrPluginType);
+
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ MultiOCR3Base.OCRConfig memory expectedConfig = MultiOCR3Base.OCRConfig({
+ configInfo: MultiOCR3Base.ConfigInfo({
+ configDigest: ocrConfigs[0].configDigest,
+ F: ocrConfigs[0].F,
+ n: uint8(ocrConfigs[0].signers.length),
+ isSignatureVerificationEnabled: ocrConfigs[0].isSignatureVerificationEnabled
+ }),
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+ _assertOCRConfigEquality(s_multiOCR3.latestConfigDetails(0), expectedConfig);
+ }
+
+ function test_SetConfigWithoutSigners_Success() public {
+ uint8 F = 1;
+ address[] memory signers = new address[](0);
+
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(0));
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(F, signers, s_validTransmitters),
+ F: F,
+ isSignatureVerificationEnabled: false,
+ signers: signers,
+ transmitters: s_validTransmitters
+ });
+
+ vm.expectEmit();
+ emit MultiOCR3Base.ConfigSet(
+ ocrConfigs[0].ocrPluginType,
+ ocrConfigs[0].configDigest,
+ ocrConfigs[0].signers,
+ ocrConfigs[0].transmitters,
+ ocrConfigs[0].F
+ );
+
+ vm.expectEmit();
+ emit MultiOCR3Helper.AfterConfigSet(ocrConfigs[0].ocrPluginType);
+
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ MultiOCR3Base.OCRConfig memory expectedConfig = MultiOCR3Base.OCRConfig({
+ configInfo: MultiOCR3Base.ConfigInfo({
+ configDigest: ocrConfigs[0].configDigest,
+ F: ocrConfigs[0].F,
+ n: uint8(ocrConfigs[0].signers.length),
+ isSignatureVerificationEnabled: ocrConfigs[0].isSignatureVerificationEnabled
+ }),
+ signers: signers,
+ transmitters: s_validTransmitters
+ });
+ _assertOCRConfigEquality(s_multiOCR3.latestConfigDetails(0), expectedConfig);
+ }
+
+ function test_SetConfigIgnoreSigners_Success() public {
+ uint8 F = 1;
+
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(0));
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(F, new address[](0), s_validTransmitters),
+ F: F,
+ isSignatureVerificationEnabled: false,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+
+ vm.expectEmit();
+ emit MultiOCR3Base.ConfigSet(
+ ocrConfigs[0].ocrPluginType,
+ ocrConfigs[0].configDigest,
+ s_emptySigners,
+ ocrConfigs[0].transmitters,
+ ocrConfigs[0].F
+ );
+
+ vm.expectEmit();
+ emit MultiOCR3Helper.AfterConfigSet(ocrConfigs[0].ocrPluginType);
+
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ MultiOCR3Base.OCRConfig memory expectedConfig = MultiOCR3Base.OCRConfig({
+ configInfo: MultiOCR3Base.ConfigInfo({
+ configDigest: ocrConfigs[0].configDigest,
+ F: ocrConfigs[0].F,
+ n: 0,
+ isSignatureVerificationEnabled: ocrConfigs[0].isSignatureVerificationEnabled
+ }),
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+ _assertOCRConfigEquality(s_multiOCR3.latestConfigDetails(0), expectedConfig);
+
+ // Verify no signer role is set
+ for (uint256 i = 0; i < s_validSigners.length; ++i) {
+ MultiOCR3Base.Oracle memory signerOracle = s_multiOCR3.getOracle(0, s_validSigners[i]);
+ assertEq(uint8(signerOracle.role), uint8(MultiOCR3Base.Role.Unset));
+ }
+ }
+
+ function test_SetMultipleConfigs_Success() public {
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(0));
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(1));
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(2));
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](3);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(2, s_validSigners, s_validTransmitters),
+ F: 2,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+ ocrConfigs[1] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 1,
+ configDigest: _getBasicConfigDigest(1, s_validSigners, s_validTransmitters),
+ F: 1,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+ ocrConfigs[2] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 2,
+ configDigest: _getBasicConfigDigest(1, s_partialSigners, s_partialTransmitters),
+ F: 1,
+ isSignatureVerificationEnabled: true,
+ signers: s_partialSigners,
+ transmitters: s_partialTransmitters
+ });
+
+ for (uint256 i; i < ocrConfigs.length; ++i) {
+ vm.expectEmit();
+ emit MultiOCR3Base.ConfigSet(
+ ocrConfigs[i].ocrPluginType,
+ ocrConfigs[i].configDigest,
+ ocrConfigs[i].signers,
+ ocrConfigs[i].transmitters,
+ ocrConfigs[i].F
+ );
+
+ vm.expectEmit();
+ emit MultiOCR3Helper.AfterConfigSet(ocrConfigs[i].ocrPluginType);
+ }
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ for (uint256 i; i < ocrConfigs.length; ++i) {
+ MultiOCR3Base.OCRConfig memory expectedConfig = MultiOCR3Base.OCRConfig({
+ configInfo: MultiOCR3Base.ConfigInfo({
+ configDigest: ocrConfigs[i].configDigest,
+ F: ocrConfigs[i].F,
+ n: uint8(ocrConfigs[i].signers.length),
+ isSignatureVerificationEnabled: ocrConfigs[i].isSignatureVerificationEnabled
+ }),
+ signers: ocrConfigs[i].signers,
+ transmitters: ocrConfigs[i].transmitters
+ });
+ _assertOCRConfigEquality(s_multiOCR3.latestConfigDetails(ocrConfigs[i].ocrPluginType), expectedConfig);
+ }
+
+ // pluginType 3 remains unconfigured
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(3));
+ }
+
+ function test_Fuzz_SetConfig_Success(MultiOCR3Base.OCRConfigArgs memory ocrConfig, uint64 randomAddressOffset) public {
+ // condition: cannot assume max oracle count
+ vm.assume(ocrConfig.transmitters.length <= 31);
+ vm.assume(ocrConfig.signers.length <= 31);
+
+ // condition: F > 0
+ ocrConfig.F = uint8(bound(ocrConfig.F, 1, 3));
+
+ uint256 transmittersLength = ocrConfig.transmitters.length;
+
+ // Force addresses to be unique (with a random offset for broader testing)
+ for (uint160 i = 0; i < transmittersLength; ++i) {
+ ocrConfig.transmitters[i] = vm.addr(PRIVATE0 + randomAddressOffset + i);
+ // condition: non-zero oracle address
+ vm.assume(ocrConfig.transmitters[i] != address(0));
+ }
+
+ if (ocrConfig.signers.length == 0) {
+ ocrConfig.isSignatureVerificationEnabled = false;
+ } else {
+ ocrConfig.isSignatureVerificationEnabled = true;
+
+ // condition: number of signers > 3F
+ vm.assume(ocrConfig.signers.length > 3 * ocrConfig.F);
+
+ uint256 signersLength = ocrConfig.signers.length;
+
+ // Force addresses to be unique - continuing generation with an offset after the transmitter addresses
+ for (uint160 i = 0; i < signersLength; ++i) {
+ ocrConfig.signers[i] = vm.addr(PRIVATE0 + randomAddressOffset + i + transmittersLength);
+ // condition: non-zero oracle address
+ vm.assume(ocrConfig.signers[i] != address(0));
+ }
+ }
+
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(ocrConfig.ocrPluginType));
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = ocrConfig;
+
+ vm.expectEmit();
+ emit MultiOCR3Base.ConfigSet(
+ ocrConfig.ocrPluginType, ocrConfig.configDigest, ocrConfig.signers, ocrConfig.transmitters, ocrConfig.F
+ );
+ vm.expectEmit();
+ emit MultiOCR3Helper.AfterConfigSet(ocrConfig.ocrPluginType);
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ MultiOCR3Base.OCRConfig memory expectedConfig = MultiOCR3Base.OCRConfig({
+ configInfo: MultiOCR3Base.ConfigInfo({
+ configDigest: ocrConfig.configDigest,
+ F: ocrConfig.F,
+ n: ocrConfig.isSignatureVerificationEnabled ? uint8(ocrConfig.signers.length) : 0,
+ isSignatureVerificationEnabled: ocrConfig.isSignatureVerificationEnabled
+ }),
+ signers: ocrConfig.signers,
+ transmitters: ocrConfig.transmitters
+ });
+ _assertOCRConfigEquality(s_multiOCR3.latestConfigDetails(ocrConfig.ocrPluginType), expectedConfig);
+ }
+
+ function test_UpdateConfigTransmittersWithoutSigners_Success() public {
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(0));
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(1, s_emptySigners, s_validTransmitters),
+ F: 1,
+ isSignatureVerificationEnabled: false,
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ address[] memory newTransmitters = s_partialSigners;
+
+ ocrConfigs[0].F = 2;
+ ocrConfigs[0].configDigest = _getBasicConfigDigest(2, s_emptySigners, newTransmitters);
+ ocrConfigs[0].transmitters = newTransmitters;
+
+ vm.expectEmit();
+ emit MultiOCR3Base.ConfigSet(
+ ocrConfigs[0].ocrPluginType,
+ ocrConfigs[0].configDigest,
+ ocrConfigs[0].signers,
+ ocrConfigs[0].transmitters,
+ ocrConfigs[0].F
+ );
+ vm.expectEmit();
+ emit MultiOCR3Helper.AfterConfigSet(ocrConfigs[0].ocrPluginType);
+
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ MultiOCR3Base.OCRConfig memory expectedConfig = MultiOCR3Base.OCRConfig({
+ configInfo: MultiOCR3Base.ConfigInfo({
+ configDigest: ocrConfigs[0].configDigest,
+ F: ocrConfigs[0].F,
+ n: uint8(ocrConfigs[0].signers.length),
+ isSignatureVerificationEnabled: ocrConfigs[0].isSignatureVerificationEnabled
+ }),
+ signers: s_emptySigners,
+ transmitters: newTransmitters
+ });
+ _assertOCRConfigEquality(s_multiOCR3.latestConfigDetails(0), expectedConfig);
+
+ // Verify oracle roles get correctly re-assigned
+ for (uint256 i; i < newTransmitters.length; ++i) {
+ MultiOCR3Base.Oracle memory transmitterOracle = s_multiOCR3.getOracle(0, newTransmitters[i]);
+ assertEq(transmitterOracle.index, i);
+ assertEq(uint8(transmitterOracle.role), uint8(MultiOCR3Base.Role.Transmitter));
+ }
+
+ // Verify old transmitters get correctly unset
+ for (uint256 i = newTransmitters.length; i < s_validTransmitters.length; ++i) {
+ MultiOCR3Base.Oracle memory transmitterOracle = s_multiOCR3.getOracle(0, s_validTransmitters[i]);
+ assertEq(uint8(transmitterOracle.role), uint8(MultiOCR3Base.Role.Unset));
+ }
+ }
+
+ function test_UpdateConfigSigners_Success() public {
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(0));
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(2, s_validSigners, s_validTransmitters),
+ F: 2,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ address[] memory newSigners = s_partialTransmitters;
+ address[] memory newTransmitters = s_partialSigners;
+
+ ocrConfigs[0].F = 1;
+ ocrConfigs[0].configDigest = _getBasicConfigDigest(1, newSigners, newTransmitters);
+ ocrConfigs[0].signers = newSigners;
+ ocrConfigs[0].transmitters = newTransmitters;
+
+ vm.expectEmit();
+ emit MultiOCR3Base.ConfigSet(
+ ocrConfigs[0].ocrPluginType,
+ ocrConfigs[0].configDigest,
+ ocrConfigs[0].signers,
+ ocrConfigs[0].transmitters,
+ ocrConfigs[0].F
+ );
+ vm.expectEmit();
+ emit MultiOCR3Helper.AfterConfigSet(ocrConfigs[0].ocrPluginType);
+
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ MultiOCR3Base.OCRConfig memory expectedConfig = MultiOCR3Base.OCRConfig({
+ configInfo: MultiOCR3Base.ConfigInfo({
+ configDigest: ocrConfigs[0].configDigest,
+ F: ocrConfigs[0].F,
+ n: uint8(ocrConfigs[0].signers.length),
+ isSignatureVerificationEnabled: ocrConfigs[0].isSignatureVerificationEnabled
+ }),
+ signers: newSigners,
+ transmitters: newTransmitters
+ });
+ _assertOCRConfigEquality(s_multiOCR3.latestConfigDetails(0), expectedConfig);
+
+ // Verify oracle roles get correctly re-assigned
+ for (uint256 i; i < newSigners.length; ++i) {
+ MultiOCR3Base.Oracle memory signerOracle = s_multiOCR3.getOracle(0, newSigners[i]);
+ assertEq(signerOracle.index, i);
+ assertEq(uint8(signerOracle.role), uint8(MultiOCR3Base.Role.Signer));
+
+ MultiOCR3Base.Oracle memory transmitterOracle = s_multiOCR3.getOracle(0, newTransmitters[i]);
+ assertEq(transmitterOracle.index, i);
+ assertEq(uint8(transmitterOracle.role), uint8(MultiOCR3Base.Role.Transmitter));
+ }
+
+ // Verify old signers / transmitters get correctly unset
+ for (uint256 i = newSigners.length; i < s_validSigners.length; ++i) {
+ MultiOCR3Base.Oracle memory signerOracle = s_multiOCR3.getOracle(0, s_validSigners[i]);
+ assertEq(uint8(signerOracle.role), uint8(MultiOCR3Base.Role.Unset));
+
+ MultiOCR3Base.Oracle memory transmitterOracle = s_multiOCR3.getOracle(0, s_validTransmitters[i]);
+ assertEq(uint8(transmitterOracle.role), uint8(MultiOCR3Base.Role.Unset));
+ }
+ }
+
+ // Reverts
+
+ function test_RepeatTransmitterAddress_Revert() public {
+ address[] memory signers = s_validSigners;
+ address[] memory transmitters = s_validTransmitters;
+ transmitters[0] = signers[0];
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(1, signers, transmitters),
+ F: 1,
+ isSignatureVerificationEnabled: true,
+ signers: signers,
+ transmitters: transmitters
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ MultiOCR3Base.InvalidConfig.selector, MultiOCR3Base.InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS
+ )
+ );
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_RepeatSignerAddress_Revert() public {
+ address[] memory signers = s_validSigners;
+ address[] memory transmitters = s_validTransmitters;
+ signers[1] = signers[0];
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(1, signers, transmitters),
+ F: 1,
+ isSignatureVerificationEnabled: true,
+ signers: signers,
+ transmitters: transmitters
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ MultiOCR3Base.InvalidConfig.selector, MultiOCR3Base.InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS
+ )
+ );
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_SignerCannotBeZeroAddress_Revert() public {
+ uint8 F = 1;
+ address[] memory signers = new address[](3 * F + 1);
+ address[] memory transmitters = new address[](3 * F + 1);
+ for (uint160 i = 0; i < 3 * F + 1; ++i) {
+ signers[i] = address(i + 1);
+ transmitters[i] = address(i + 1000);
+ }
+
+ signers[0] = address(0);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(F, signers, transmitters),
+ F: F,
+ isSignatureVerificationEnabled: true,
+ signers: signers,
+ transmitters: transmitters
+ });
+
+ vm.expectRevert(MultiOCR3Base.OracleCannotBeZeroAddress.selector);
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_TransmitterCannotBeZeroAddress_Revert() public {
+ uint8 F = 1;
+ address[] memory signers = new address[](3 * F + 1);
+ address[] memory transmitters = new address[](3 * F + 1);
+ for (uint160 i = 0; i < 3 * F + 1; ++i) {
+ signers[i] = address(i + 1);
+ transmitters[i] = address(i + 1000);
+ }
+
+ transmitters[0] = address(0);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(F, signers, transmitters),
+ F: F,
+ isSignatureVerificationEnabled: true,
+ signers: signers,
+ transmitters: transmitters
+ });
+
+ vm.expectRevert(MultiOCR3Base.OracleCannotBeZeroAddress.selector);
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_StaticConfigChange_Revert() public {
+ uint8 F = 1;
+
+ _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(0));
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(F, s_validSigners, s_validTransmitters),
+ F: F,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+
+ // signature verification cannot change
+ ocrConfigs[0].isSignatureVerificationEnabled = false;
+ vm.expectRevert(abi.encodeWithSelector(MultiOCR3Base.StaticConfigCannotBeChanged.selector, 0));
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_FTooHigh_Revert() public {
+ address[] memory signers = new address[](0);
+ address[] memory transmitters = new address[](0);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(1, signers, transmitters),
+ F: 1,
+ isSignatureVerificationEnabled: true,
+ signers: signers,
+ transmitters: transmitters
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(MultiOCR3Base.InvalidConfig.selector, MultiOCR3Base.InvalidConfigErrorType.F_TOO_HIGH)
+ );
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_FMustBePositive_Revert() public {
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(0, s_validSigners, s_validTransmitters),
+ F: 0,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ MultiOCR3Base.InvalidConfig.selector, MultiOCR3Base.InvalidConfigErrorType.F_MUST_BE_POSITIVE
+ )
+ );
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_TooManyTransmitters_Revert() public {
+ address[] memory signers = new address[](0);
+ address[] memory transmitters = new address[](32);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(10, signers, transmitters),
+ F: 10,
+ isSignatureVerificationEnabled: false,
+ signers: signers,
+ transmitters: transmitters
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ MultiOCR3Base.InvalidConfig.selector, MultiOCR3Base.InvalidConfigErrorType.TOO_MANY_TRANSMITTERS
+ )
+ );
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+
+ function test_TooManySigners_Revert() public {
+ address[] memory signers = new address[](32);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: 0,
+ configDigest: _getBasicConfigDigest(1, signers, s_validTransmitters),
+ F: 1,
+ isSignatureVerificationEnabled: true,
+ signers: signers,
+ transmitters: s_validTransmitters
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ MultiOCR3Base.InvalidConfig.selector, MultiOCR3Base.InvalidConfigErrorType.TOO_MANY_SIGNERS
+ )
+ );
+ s_multiOCR3.setOCR3Configs(ocrConfigs);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/ocr/MultiOCR3BaseSetup.t.sol b/contracts/src/v0.8/ccip/test/ocr/MultiOCR3BaseSetup.t.sol
new file mode 100644
index 00000000000..6f6219bc9b0
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/ocr/MultiOCR3BaseSetup.t.sol
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {MultiOCR3Base} from "../../ocr/MultiOCR3Base.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+import {MultiOCR3Helper} from "../helpers/MultiOCR3Helper.sol";
+
+contract MultiOCR3BaseSetup is BaseTest {
+ // Signer private keys used for these test
+ uint256 internal constant PRIVATE0 = 0x7b2e97fe057e6de99d6872a2ef2abf52c9b4469bc848c2465ac3fcd8d336e81d;
+
+ address[] internal s_validSigners;
+ address[] internal s_validTransmitters;
+ uint256[] internal s_validSignerKeys;
+
+ address[] internal s_partialSigners;
+ address[] internal s_partialTransmitters;
+ uint256[] internal s_partialSignerKeys;
+
+ address[] internal s_emptySigners;
+
+ bytes internal constant REPORT = abi.encode("testReport");
+ MultiOCR3Helper internal s_multiOCR3;
+
+ function setUp() public virtual override {
+ BaseTest.setUp();
+
+ uint160 numSigners = 7;
+ s_validSignerKeys = new uint256[](numSigners);
+ s_validSigners = new address[](numSigners);
+ s_validTransmitters = new address[](numSigners);
+
+ for (uint160 i; i < numSigners; ++i) {
+ s_validTransmitters[i] = address(4 + i);
+ s_validSignerKeys[i] = PRIVATE0 + i;
+ s_validSigners[i] = vm.addr(s_validSignerKeys[i]);
+ }
+
+ s_partialSigners = new address[](4);
+ s_partialSignerKeys = new uint256[](4);
+ s_partialTransmitters = new address[](4);
+ for (uint256 i; i < s_partialSigners.length; ++i) {
+ s_partialSigners[i] = s_validSigners[i];
+ s_partialSignerKeys[i] = s_validSignerKeys[i];
+ s_partialTransmitters[i] = s_validTransmitters[i];
+ }
+
+ s_emptySigners = new address[](0);
+
+ s_multiOCR3 = new MultiOCR3Helper();
+ }
+
+ /// @dev returns a mock config digest with config digest computation logic similar to OCR2Base
+ function _getBasicConfigDigest(
+ uint8 F,
+ address[] memory signers,
+ address[] memory transmitters
+ ) internal view returns (bytes32) {
+ bytes memory configBytes = abi.encode("");
+ uint256 configVersion = 1;
+
+ uint256 h = uint256(
+ keccak256(
+ abi.encode(
+ block.chainid, address(s_multiOCR3), signers, transmitters, F, configBytes, configVersion, configBytes
+ )
+ )
+ );
+ uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00
+ uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00
+ return bytes32((prefix & prefixMask) | (h & ~prefixMask));
+ }
+
+ function _assertOCRConfigEquality(
+ MultiOCR3Base.OCRConfig memory configA,
+ MultiOCR3Base.OCRConfig memory configB
+ ) internal pure {
+ vm.assertEq(configA.configInfo.configDigest, configB.configInfo.configDigest);
+ vm.assertEq(configA.configInfo.F, configB.configInfo.F);
+ vm.assertEq(configA.configInfo.n, configB.configInfo.n);
+ vm.assertEq(configA.configInfo.isSignatureVerificationEnabled, configB.configInfo.isSignatureVerificationEnabled);
+
+ vm.assertEq(configA.signers, configB.signers);
+ vm.assertEq(configA.transmitters, configB.transmitters);
+ }
+
+ function _assertOCRConfigUnconfigured(MultiOCR3Base.OCRConfig memory config) internal pure {
+ assertEq(config.configInfo.configDigest, bytes32(""));
+ assertEq(config.signers.length, 0);
+ assertEq(config.transmitters.length, 0);
+ }
+
+ function _getSignaturesForDigest(
+ uint256[] memory signerPrivateKeys,
+ bytes memory report,
+ bytes32[3] memory reportContext,
+ uint8 signatureCount
+ ) internal pure returns (bytes32[] memory rs, bytes32[] memory ss, uint8[] memory vs, bytes32 rawVs) {
+ rs = new bytes32[](signatureCount);
+ ss = new bytes32[](signatureCount);
+ vs = new uint8[](signatureCount);
+
+ bytes32 reportDigest = keccak256(abi.encodePacked(keccak256(report), reportContext));
+
+ // Calculate signatures
+ for (uint256 i; i < signatureCount; ++i) {
+ (vs[i], rs[i], ss[i]) = vm.sign(signerPrivateKeys[i], reportDigest);
+ rawVs = rawVs | (bytes32(bytes1(vs[i] - 27)) >> (8 * i));
+ }
+
+ return (rs, ss, vs, rawVs);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/ocr/OCR2Base.t.sol b/contracts/src/v0.8/ccip/test/ocr/OCR2Base.t.sol
new file mode 100644
index 00000000000..7511ebdffae
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/ocr/OCR2Base.t.sol
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {OCR2Abstract} from "../../ocr/OCR2Abstract.sol";
+import {OCR2Base} from "../../ocr/OCR2Base.sol";
+import {OCR2Helper} from "../helpers/OCR2Helper.sol";
+import {OCR2Setup} from "./OCR2Setup.t.sol";
+
+contract OCR2BaseSetup is OCR2Setup {
+ OCR2Helper internal s_OCR2Base;
+
+ bytes32[] internal s_rs;
+ bytes32[] internal s_ss;
+ bytes32 internal s_rawVs;
+
+ uint40 internal s_latestEpochAndRound;
+
+ function setUp() public virtual override {
+ OCR2Setup.setUp();
+ s_OCR2Base = new OCR2Helper();
+
+ bytes32 testReportDigest = getTestReportDigest();
+
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](2);
+ uint8[] memory vs = new uint8[](2);
+
+ // Calculate signatures
+ (vs[0], rs[0], ss[0]) = vm.sign(PRIVATE0, testReportDigest);
+ (vs[1], rs[1], ss[1]) = vm.sign(PRIVATE1, testReportDigest);
+
+ s_rs = rs;
+ s_ss = ss;
+ s_rawVs = bytes32(bytes1(vs[0] - 27)) | (bytes32(bytes1(vs[1] - 27)) >> 8);
+ }
+
+ function getBasicConfigDigest(uint8 f, uint64 currentConfigCount) internal view returns (bytes32) {
+ bytes memory configBytes = abi.encode("");
+ return s_OCR2Base.configDigestFromConfigData(
+ block.chainid,
+ address(s_OCR2Base),
+ currentConfigCount + 1,
+ s_valid_signers,
+ s_valid_transmitters,
+ f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+ }
+
+ function getTestReportDigest() internal view returns (bytes32) {
+ bytes32 configDigest = getBasicConfigDigest(s_f, 0);
+ bytes32[3] memory reportContext = [configDigest, configDigest, configDigest];
+ return keccak256(abi.encodePacked(keccak256(REPORT), reportContext));
+ }
+
+ function getBasicConfigDigest(
+ address contractAddress,
+ uint8 f,
+ uint64 currentConfigCount,
+ bytes memory onchainConfig
+ ) internal view returns (bytes32) {
+ return s_OCR2Base.configDigestFromConfigData(
+ block.chainid,
+ contractAddress,
+ currentConfigCount + 1,
+ s_valid_signers,
+ s_valid_transmitters,
+ f,
+ onchainConfig,
+ s_offchainConfigVersion,
+ abi.encode("")
+ );
+ }
+}
+
+contract OCR2Base_transmit is OCR2BaseSetup {
+ bytes32 internal s_configDigest;
+
+ function setUp() public virtual override {
+ OCR2BaseSetup.setUp();
+ bytes memory configBytes = abi.encode("");
+
+ s_configDigest = getBasicConfigDigest(s_f, 0);
+ s_OCR2Base.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, configBytes, s_offchainConfigVersion, configBytes
+ );
+ }
+
+ function test_Transmit2SignersSuccess_gas() public {
+ vm.pauseGasMetering();
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ vm.startPrank(s_valid_transmitters[0]);
+ vm.resumeGasMetering();
+ s_OCR2Base.transmit(reportContext, REPORT, s_rs, s_ss, s_rawVs);
+ }
+
+ // Reverts
+
+ function test_ForkedChain_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ uint256 chain1 = block.chainid;
+ uint256 chain2 = chain1 + 1;
+ vm.chainId(chain2);
+ vm.expectRevert(abi.encodeWithSelector(OCR2Base.ForkedChain.selector, chain1, chain2));
+ vm.startPrank(s_valid_transmitters[0]);
+ s_OCR2Base.transmit(reportContext, REPORT, s_rs, s_ss, s_rawVs);
+ }
+
+ function test_WrongNumberOfSignatures_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ vm.expectRevert(OCR2Base.WrongNumberOfSignatures.selector);
+ s_OCR2Base.transmit(reportContext, REPORT, new bytes32[](0), new bytes32[](0), s_rawVs);
+ }
+
+ function test_ConfigDigestMismatch_Revert() public {
+ bytes32 configDigest;
+ bytes32[3] memory reportContext = [configDigest, configDigest, configDigest];
+
+ vm.expectRevert(abi.encodeWithSelector(OCR2Base.ConfigDigestMismatch.selector, s_configDigest, configDigest));
+ s_OCR2Base.transmit(reportContext, REPORT, new bytes32[](0), new bytes32[](0), s_rawVs);
+ }
+
+ function test_SignatureOutOfRegistration_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](1);
+
+ vm.expectRevert(OCR2Base.SignaturesOutOfRegistration.selector);
+ s_OCR2Base.transmit(reportContext, REPORT, rs, ss, s_rawVs);
+ }
+
+ function test_UnAuthorizedTransmitter_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](2);
+
+ vm.expectRevert(OCR2Base.UnauthorizedTransmitter.selector);
+ s_OCR2Base.transmit(reportContext, REPORT, rs, ss, s_rawVs);
+ }
+
+ function test_NonUniqueSignature_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+ bytes32[] memory rs = s_rs;
+ bytes32[] memory ss = s_ss;
+
+ rs[1] = rs[0];
+ ss[1] = ss[0];
+ // Need to reset the rawVs to be valid
+ bytes32 rawVs = bytes32(bytes1(uint8(28) - 27)) | (bytes32(bytes1(uint8(28) - 27)) >> 8);
+
+ vm.startPrank(s_valid_transmitters[0]);
+ vm.expectRevert(OCR2Base.NonUniqueSignatures.selector);
+ s_OCR2Base.transmit(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ function test_UnauthorizedSigner_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+ bytes32[] memory rs = new bytes32[](2);
+ rs[0] = s_configDigest;
+ bytes32[] memory ss = rs;
+
+ vm.startPrank(s_valid_transmitters[0]);
+ vm.expectRevert(OCR2Base.UnauthorizedSigner.selector);
+ s_OCR2Base.transmit(reportContext, REPORT, rs, ss, s_rawVs);
+ }
+}
+
+contract OCR2Base_setOCR2Config is OCR2BaseSetup {
+ function test_SetConfigSuccess_gas() public {
+ vm.pauseGasMetering();
+ bytes memory configBytes = abi.encode("");
+ uint32 configCount = 0;
+
+ bytes32 configDigest = getBasicConfigDigest(s_f, configCount++);
+
+ address[] memory transmitters = s_OCR2Base.getTransmitters();
+ assertEq(0, transmitters.length);
+
+ vm.expectEmit();
+ emit OCR2Abstract.ConfigSet(
+ 0,
+ configDigest,
+ configCount,
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+
+ s_OCR2Base.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, configBytes, s_offchainConfigVersion, configBytes
+ );
+
+ transmitters = s_OCR2Base.getTransmitters();
+ assertEq(s_valid_transmitters, transmitters);
+
+ configDigest = getBasicConfigDigest(s_f, configCount++);
+
+ vm.expectEmit();
+ emit OCR2Abstract.ConfigSet(
+ uint32(block.number),
+ configDigest,
+ configCount,
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+ vm.resumeGasMetering();
+ s_OCR2Base.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, configBytes, s_offchainConfigVersion, configBytes
+ );
+ }
+
+ // Reverts
+ function test_RepeatAddress_Revert() public {
+ address[] memory signers = new address[](10);
+ signers[0] = address(1245678);
+ address[] memory transmitters = new address[](10);
+ transmitters[0] = signers[0];
+
+ vm.expectRevert(
+ abi.encodeWithSelector(OCR2Base.InvalidConfig.selector, OCR2Base.InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS)
+ );
+ s_OCR2Base.setOCR2Config(signers, transmitters, 2, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_SingerCannotBeZeroAddress_Revert() public {
+ uint256 f = 1;
+ address[] memory signers = new address[](3 * f + 1);
+ address[] memory transmitters = new address[](3 * f + 1);
+ for (uint160 i = 0; i < 3 * f + 1; ++i) {
+ signers[i] = address(i + 1);
+ transmitters[i] = address(i + 1000);
+ }
+
+ signers[0] = address(0);
+
+ vm.expectRevert(OCR2Base.OracleCannotBeZeroAddress.selector);
+ s_OCR2Base.setOCR2Config(signers, transmitters, uint8(f), abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_TransmitterCannotBeZeroAddress_Revert() public {
+ uint256 f = 1;
+ address[] memory signers = new address[](3 * f + 1);
+ address[] memory transmitters = new address[](3 * f + 1);
+ for (uint160 i = 0; i < 3 * f + 1; ++i) {
+ signers[i] = address(i + 1);
+ transmitters[i] = address(i + 1000);
+ }
+
+ transmitters[0] = address(0);
+
+ vm.expectRevert(OCR2Base.OracleCannotBeZeroAddress.selector);
+ s_OCR2Base.setOCR2Config(signers, transmitters, uint8(f), abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_OracleOutOfRegister_Revert() public {
+ address[] memory signers = new address[](10);
+ address[] memory transmitters = new address[](0);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ OCR2Base.InvalidConfig.selector, OCR2Base.InvalidConfigErrorType.NUM_SIGNERS_NOT_NUM_TRANSMITTERS
+ )
+ );
+ s_OCR2Base.setOCR2Config(signers, transmitters, 2, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_FTooHigh_Revert() public {
+ address[] memory signers = new address[](0);
+ uint8 f = 1;
+
+ vm.expectRevert(abi.encodeWithSelector(OCR2Base.InvalidConfig.selector, OCR2Base.InvalidConfigErrorType.F_TOO_HIGH));
+ s_OCR2Base.setOCR2Config(signers, new address[](0), f, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_FMustBePositive_Revert() public {
+ uint8 f = 0;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(OCR2Base.InvalidConfig.selector, OCR2Base.InvalidConfigErrorType.F_MUST_BE_POSITIVE)
+ );
+ s_OCR2Base.setOCR2Config(new address[](0), new address[](0), f, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_TooManySigners_Revert() public {
+ address[] memory signers = new address[](32);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(OCR2Base.InvalidConfig.selector, OCR2Base.InvalidConfigErrorType.TOO_MANY_SIGNERS)
+ );
+ s_OCR2Base.setOCR2Config(signers, new address[](0), 0, abi.encode(""), 100, abi.encode(""));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/ocr/OCR2BaseNoChecks.t.sol b/contracts/src/v0.8/ccip/test/ocr/OCR2BaseNoChecks.t.sol
new file mode 100644
index 00000000000..fd4cf3fc9e7
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/ocr/OCR2BaseNoChecks.t.sol
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {OCR2BaseNoChecks} from "../../ocr/OCR2BaseNoChecks.sol";
+import {OCR2NoChecksHelper} from "../helpers/OCR2NoChecksHelper.sol";
+import {OCR2Setup} from "./OCR2Setup.t.sol";
+
+contract OCR2BaseNoChecksSetup is OCR2Setup {
+ OCR2NoChecksHelper internal s_OCR2Base;
+
+ bytes32[] internal s_rs;
+ bytes32[] internal s_ss;
+ bytes32 internal s_rawVs;
+
+ function setUp() public virtual override {
+ OCR2Setup.setUp();
+ s_OCR2Base = new OCR2NoChecksHelper();
+ }
+
+ function getBasicConfigDigest(uint8 f, uint64 currentConfigCount) internal view returns (bytes32) {
+ bytes memory configBytes = abi.encode("");
+ return s_OCR2Base.configDigestFromConfigData(
+ block.chainid,
+ address(s_OCR2Base),
+ currentConfigCount + 1,
+ s_valid_signers,
+ s_valid_transmitters,
+ f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+ }
+}
+
+contract OCR2BaseNoChecks_transmit is OCR2BaseNoChecksSetup {
+ bytes32 internal s_configDigest;
+
+ function setUp() public virtual override {
+ OCR2BaseNoChecksSetup.setUp();
+ bytes memory configBytes = abi.encode("");
+
+ s_configDigest = getBasicConfigDigest(s_f, 0);
+ s_OCR2Base.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, configBytes, s_offchainConfigVersion, configBytes
+ );
+ }
+
+ function test_TransmitSuccess_gas() public {
+ vm.pauseGasMetering();
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ vm.startPrank(s_valid_transmitters[0]);
+ vm.resumeGasMetering();
+ s_OCR2Base.transmit(reportContext, REPORT, s_rs, s_ss, s_rawVs);
+ }
+
+ // Reverts
+
+ function test_ForkedChain_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ uint256 chain1 = block.chainid;
+ uint256 chain2 = chain1 + 1;
+ vm.chainId(chain2);
+ vm.expectRevert(abi.encodeWithSelector(OCR2BaseNoChecks.ForkedChain.selector, chain1, chain2));
+ vm.startPrank(s_valid_transmitters[0]);
+ s_OCR2Base.transmit(reportContext, REPORT, s_rs, s_ss, s_rawVs);
+ }
+
+ function test_ConfigDigestMismatch_Revert() public {
+ bytes32 configDigest;
+
+ bytes32[3] memory reportContext = [configDigest, configDigest, configDigest];
+
+ vm.expectRevert(
+ abi.encodeWithSelector(OCR2BaseNoChecks.ConfigDigestMismatch.selector, s_configDigest, configDigest)
+ );
+ s_OCR2Base.transmit(reportContext, REPORT, new bytes32[](0), new bytes32[](0), s_rawVs);
+ }
+
+ function test_UnAuthorizedTransmitter_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+ bytes32[] memory rs = new bytes32[](3);
+ bytes32[] memory ss = new bytes32[](3);
+
+ vm.expectRevert(OCR2BaseNoChecks.UnauthorizedTransmitter.selector);
+ s_OCR2Base.transmit(reportContext, REPORT, rs, ss, s_rawVs);
+ }
+}
+
+contract OCR2BaseNoChecks_setOCR2Config is OCR2BaseNoChecksSetup {
+ event ConfigSet(
+ uint32 previousConfigBlockNumber,
+ bytes32 configDigest,
+ uint64 configCount,
+ address[] signers,
+ address[] transmitters,
+ uint8 f,
+ bytes onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes offchainConfig
+ );
+
+ function test_SetConfigSuccess_gas() public {
+ vm.pauseGasMetering();
+ bytes memory configBytes = abi.encode("");
+ uint32 configCount = 0;
+
+ bytes32 configDigest = getBasicConfigDigest(s_f, configCount++);
+
+ address[] memory transmitters = s_OCR2Base.getTransmitters();
+ assertEq(0, transmitters.length);
+
+ vm.expectEmit();
+ emit ConfigSet(
+ 0,
+ configDigest,
+ configCount,
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+
+ s_OCR2Base.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, configBytes, s_offchainConfigVersion, configBytes
+ );
+
+ transmitters = s_OCR2Base.getTransmitters();
+ assertEq(s_valid_transmitters, transmitters);
+
+ configDigest = getBasicConfigDigest(s_f, configCount++);
+
+ vm.expectEmit();
+ emit ConfigSet(
+ uint32(block.number),
+ configDigest,
+ configCount,
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+ vm.resumeGasMetering();
+ s_OCR2Base.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, configBytes, s_offchainConfigVersion, configBytes
+ );
+ }
+
+ // Reverts
+ function test_RepeatAddress_Revert() public {
+ address[] memory signers = new address[](4);
+ address[] memory transmitters = new address[](4);
+ transmitters[0] = address(1245678);
+ transmitters[1] = address(1245678);
+ transmitters[2] = address(1245678);
+ transmitters[3] = address(1245678);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ OCR2BaseNoChecks.InvalidConfig.selector, OCR2BaseNoChecks.InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS
+ )
+ );
+ s_OCR2Base.setOCR2Config(signers, transmitters, 1, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_FMustBePositive_Revert() public {
+ uint8 f = 0;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ OCR2BaseNoChecks.InvalidConfig.selector, OCR2BaseNoChecks.InvalidConfigErrorType.F_MUST_BE_POSITIVE
+ )
+ );
+ s_OCR2Base.setOCR2Config(new address[](0), new address[](0), f, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_TransmitterCannotBeZeroAddress_Revert() public {
+ uint256 f = 1;
+ address[] memory signers = new address[](3 * f + 1);
+ address[] memory transmitters = new address[](3 * f + 1);
+ for (uint160 i = 0; i < 3 * f + 1; ++i) {
+ signers[i] = address(i + 1);
+ transmitters[i] = address(i + 1000);
+ }
+
+ transmitters[0] = address(0);
+
+ vm.expectRevert(OCR2BaseNoChecks.OracleCannotBeZeroAddress.selector);
+ s_OCR2Base.setOCR2Config(signers, transmitters, uint8(f), abi.encode(""), 100, abi.encode(""));
+ }
+
+ function test_TooManyTransmitter_Revert() public {
+ address[] memory transmitters = new address[](100);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ OCR2BaseNoChecks.InvalidConfig.selector, OCR2BaseNoChecks.InvalidConfigErrorType.TOO_MANY_TRANSMITTERS
+ )
+ );
+ s_OCR2Base.setOCR2Config(new address[](0), transmitters, 0, abi.encode(""), 100, abi.encode(""));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/ocr/OCR2Setup.t.sol b/contracts/src/v0.8/ccip/test/ocr/OCR2Setup.t.sol
new file mode 100644
index 00000000000..e4be8ffa29b
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/ocr/OCR2Setup.t.sol
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Test} from "forge-std/Test.sol";
+
+contract OCR2Setup is Test {
+ uint256 internal constant PRIVATE0 = 0x7b2e97fe057e6de99d6872a2ef2abf52c9b4469bc848c2465ac3fcd8d336e81d;
+ uint256 internal constant PRIVATE1 = 0xab56160806b05ef1796789248e1d7f34a6465c5280899159d645218cd216cee6;
+ uint256 internal constant PRIVATE2 = 0x6ec7caa8406a49b76736602810e0a2871959fbbb675e23a8590839e4717f1f7f;
+ uint256 internal constant PRIVATE3 = 0x80f14b11da94ae7f29d9a7713ea13dc838e31960a5c0f2baf45ed458947b730a;
+
+ address[] internal s_valid_signers;
+ address[] internal s_valid_transmitters;
+
+ uint64 internal constant s_offchainConfigVersion = 3;
+ uint8 internal constant s_f = 1;
+ bytes internal constant REPORT = abi.encode("testReport");
+
+ function setUp() public virtual {
+ s_valid_transmitters = new address[](4);
+ for (uint160 i = 0; i < 4; ++i) {
+ s_valid_transmitters[i] = address(4 + i);
+ }
+
+ 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
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRamp.t.sol b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRamp.t.sol
new file mode 100644
index 00000000000..43899cbfd69
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRamp.t.sol
@@ -0,0 +1,3429 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ICommitStore} from "../../interfaces/ICommitStore.sol";
+import {IMessageInterceptor} from "../../interfaces/IMessageInterceptor.sol";
+import {IPriceRegistry} from "../../interfaces/IPriceRegistry.sol";
+import {IRMN} from "../../interfaces/IRMN.sol";
+import {ITokenAdminRegistry} from "../../interfaces/ITokenAdminRegistry.sol";
+
+import {CallWithExactGas} from "../../../shared/call/CallWithExactGas.sol";
+import {NonceManager} from "../../NonceManager.sol";
+import {PriceRegistry} from "../../PriceRegistry.sol";
+import {RMN} from "../../RMN.sol";
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {MerkleMultiProof} from "../../libraries/MerkleMultiProof.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {MultiOCR3Base} from "../../ocr/MultiOCR3Base.sol";
+import {EVM2EVMMultiOffRamp} from "../../offRamp/EVM2EVMMultiOffRamp.sol";
+import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {EVM2EVMMultiOffRampHelper} from "../helpers/EVM2EVMMultiOffRampHelper.sol";
+import {EVM2EVMOffRampHelper} from "../helpers/EVM2EVMOffRampHelper.sol";
+import {MaybeRevertingBurnMintTokenPool} from "../helpers/MaybeRevertingBurnMintTokenPool.sol";
+import {MessageInterceptorHelper} from "../helpers/MessageInterceptorHelper.sol";
+import {ConformingReceiver} from "../helpers/receivers/ConformingReceiver.sol";
+import {MaybeRevertMessageReceiver} from "../helpers/receivers/MaybeRevertMessageReceiver.sol";
+import {MaybeRevertMessageReceiverNo165} from "../helpers/receivers/MaybeRevertMessageReceiverNo165.sol";
+import {ReentrancyAbuserMultiRamp} from "../helpers/receivers/ReentrancyAbuserMultiRamp.sol";
+import {EVM2EVMMultiOffRampSetup} from "./EVM2EVMMultiOffRampSetup.t.sol";
+import {Vm} from "forge-std/Vm.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract EVM2EVMMultiOffRamp_constructor is EVM2EVMMultiOffRampSetup {
+ function test_Constructor_Success() public {
+ EVM2EVMMultiOffRamp.StaticConfig memory staticConfig = EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry),
+ nonceManager: address(s_inboundNonceManager)
+ });
+ EVM2EVMMultiOffRamp.DynamicConfig memory dynamicConfig =
+ _generateDynamicMultiOffRampConfig(address(s_destRouter), address(s_priceRegistry));
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](2);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: ON_RAMP_ADDRESS_1,
+ isEnabled: true
+ });
+ sourceChainConfigs[1] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1 + 1,
+ onRamp: ON_RAMP_ADDRESS_2,
+ isEnabled: true
+ });
+
+ EVM2EVMMultiOffRamp.SourceChainConfig memory expectedSourceChainConfig1 =
+ EVM2EVMMultiOffRamp.SourceChainConfig({isEnabled: true, minSeqNr: 1, onRamp: sourceChainConfigs[0].onRamp});
+
+ EVM2EVMMultiOffRamp.SourceChainConfig memory expectedSourceChainConfig2 =
+ EVM2EVMMultiOffRamp.SourceChainConfig({isEnabled: true, minSeqNr: 1, onRamp: sourceChainConfigs[1].onRamp});
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.StaticConfigSet(staticConfig);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.DynamicConfigSet(dynamicConfig);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainSelectorAdded(SOURCE_CHAIN_SELECTOR_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainConfigSet(SOURCE_CHAIN_SELECTOR_1, expectedSourceChainConfig1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainSelectorAdded(SOURCE_CHAIN_SELECTOR_1 + 1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainConfigSet(SOURCE_CHAIN_SELECTOR_1 + 1, expectedSourceChainConfig2);
+
+ s_offRamp = new EVM2EVMMultiOffRampHelper(staticConfig, dynamicConfig, sourceChainConfigs);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Execution),
+ configDigest: s_configDigestExec,
+ F: s_F,
+ isSignatureVerificationEnabled: false,
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+
+ s_offRamp.setOCR3Configs(ocrConfigs);
+
+ // Static config
+ EVM2EVMMultiOffRamp.StaticConfig memory gotStaticConfig = s_offRamp.getStaticConfig();
+ assertEq(staticConfig.chainSelector, gotStaticConfig.chainSelector);
+ assertEq(staticConfig.rmnProxy, gotStaticConfig.rmnProxy);
+ assertEq(staticConfig.tokenAdminRegistry, gotStaticConfig.tokenAdminRegistry);
+
+ // Dynamic config
+ EVM2EVMMultiOffRamp.DynamicConfig memory gotDynamicConfig = s_offRamp.getDynamicConfig();
+ _assertSameConfig(dynamicConfig, gotDynamicConfig);
+
+ // OCR Config
+ MultiOCR3Base.OCRConfig memory expectedOCRConfig = MultiOCR3Base.OCRConfig({
+ configInfo: MultiOCR3Base.ConfigInfo({
+ configDigest: ocrConfigs[0].configDigest,
+ F: ocrConfigs[0].F,
+ n: 0,
+ isSignatureVerificationEnabled: ocrConfigs[0].isSignatureVerificationEnabled
+ }),
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+ MultiOCR3Base.OCRConfig memory gotOCRConfig = s_offRamp.latestConfigDetails(uint8(Internal.OCRPluginType.Execution));
+ _assertOCRConfigEquality(expectedOCRConfig, gotOCRConfig);
+
+ _assertSourceChainConfigEquality(
+ s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR_1), expectedSourceChainConfig1
+ );
+ _assertSourceChainConfigEquality(
+ s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR_1 + 1), expectedSourceChainConfig2
+ );
+
+ // OffRamp initial values
+ assertEq("EVM2EVMMultiOffRamp 1.6.0-dev", s_offRamp.typeAndVersion());
+ assertEq(OWNER, s_offRamp.owner());
+ assertEq(0, s_offRamp.getLatestPriceSequenceNumber());
+ }
+
+ // Revert
+ function test_ZeroOnRampAddress_Revert() public {
+ uint64[] memory sourceChainSelectors = new uint64[](1);
+ sourceChainSelectors[0] = SOURCE_CHAIN_SELECTOR_1;
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](1);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: new bytes(0),
+ isEnabled: true
+ });
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroAddressNotAllowed.selector);
+
+ s_offRamp = new EVM2EVMMultiOffRampHelper(
+ EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry),
+ nonceManager: address(s_inboundNonceManager)
+ }),
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry)),
+ sourceChainConfigs
+ );
+ }
+
+ function test_SourceChainSelector_Revert() public {
+ uint64[] memory sourceChainSelectors = new uint64[](1);
+ sourceChainSelectors[0] = SOURCE_CHAIN_SELECTOR_1;
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](1);
+ sourceChainConfigs[0] =
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs({sourceChainSelector: 0, onRamp: ON_RAMP_ADDRESS_1, isEnabled: true});
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroChainSelectorNotAllowed.selector);
+
+ s_offRamp = new EVM2EVMMultiOffRampHelper(
+ EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry),
+ nonceManager: address(s_inboundNonceManager)
+ }),
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry)),
+ sourceChainConfigs
+ );
+ }
+
+ function test_ZeroRMNProxy_Revert() public {
+ uint64[] memory sourceChainSelectors = new uint64[](1);
+ sourceChainSelectors[0] = SOURCE_CHAIN_SELECTOR_1;
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](0);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroAddressNotAllowed.selector);
+
+ s_offRamp = new EVM2EVMMultiOffRampHelper(
+ EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ rmnProxy: ZERO_ADDRESS,
+ tokenAdminRegistry: address(s_tokenAdminRegistry),
+ nonceManager: address(s_inboundNonceManager)
+ }),
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry)),
+ sourceChainConfigs
+ );
+ }
+
+ function test_ZeroChainSelector_Revert() public {
+ uint64[] memory sourceChainSelectors = new uint64[](1);
+ sourceChainSelectors[0] = SOURCE_CHAIN_SELECTOR_1;
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](0);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroChainSelectorNotAllowed.selector);
+
+ s_offRamp = new EVM2EVMMultiOffRampHelper(
+ EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: 0,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry),
+ nonceManager: address(s_inboundNonceManager)
+ }),
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry)),
+ sourceChainConfigs
+ );
+ }
+
+ function test_ZeroTokenAdminRegistry_Revert() public {
+ uint64[] memory sourceChainSelectors = new uint64[](1);
+ sourceChainSelectors[0] = SOURCE_CHAIN_SELECTOR_1;
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](0);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroAddressNotAllowed.selector);
+
+ s_offRamp = new EVM2EVMMultiOffRampHelper(
+ EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: ZERO_ADDRESS,
+ nonceManager: address(s_inboundNonceManager)
+ }),
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry)),
+ sourceChainConfigs
+ );
+ }
+
+ function test_ZeroNonceManager_Revert() public {
+ uint64[] memory sourceChainSelectors = new uint64[](1);
+ sourceChainSelectors[0] = SOURCE_CHAIN_SELECTOR_1;
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](0);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroAddressNotAllowed.selector);
+
+ s_offRamp = new EVM2EVMMultiOffRampHelper(
+ EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry),
+ nonceManager: ZERO_ADDRESS
+ }),
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry)),
+ sourceChainConfigs
+ );
+ }
+}
+
+contract EVM2EVMMultiOffRamp_setDynamicConfig is EVM2EVMMultiOffRampSetup {
+ function test_SetDynamicConfig_Success() public {
+ EVM2EVMMultiOffRamp.DynamicConfig memory dynamicConfig =
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry));
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.DynamicConfigSet(dynamicConfig);
+
+ s_offRamp.setDynamicConfig(dynamicConfig);
+
+ EVM2EVMMultiOffRamp.DynamicConfig memory newConfig = s_offRamp.getDynamicConfig();
+ _assertSameConfig(dynamicConfig, newConfig);
+ }
+
+ function test_SetDynamicConfigWithValidator_Success() public {
+ EVM2EVMMultiOffRamp.DynamicConfig memory dynamicConfig =
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry));
+ dynamicConfig.messageValidator = address(s_inboundMessageValidator);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.DynamicConfigSet(dynamicConfig);
+
+ s_offRamp.setDynamicConfig(dynamicConfig);
+
+ EVM2EVMMultiOffRamp.DynamicConfig memory newConfig = s_offRamp.getDynamicConfig();
+ _assertSameConfig(dynamicConfig, newConfig);
+ }
+
+ // Reverts
+
+ function test_NonOwner_Revert() public {
+ vm.startPrank(STRANGER);
+ EVM2EVMMultiOffRamp.DynamicConfig memory dynamicConfig =
+ _generateDynamicMultiOffRampConfig(USER_3, address(s_priceRegistry));
+
+ vm.expectRevert("Only callable by owner");
+
+ s_offRamp.setDynamicConfig(dynamicConfig);
+ }
+
+ function test_RouterZeroAddress_Revert() public {
+ EVM2EVMMultiOffRamp.DynamicConfig memory dynamicConfig =
+ _generateDynamicMultiOffRampConfig(ZERO_ADDRESS, address(s_priceRegistry));
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroAddressNotAllowed.selector);
+
+ s_offRamp.setDynamicConfig(dynamicConfig);
+ }
+
+ function test_PriceRegistryZeroAddress_Revert() public {
+ EVM2EVMMultiOffRamp.DynamicConfig memory dynamicConfig = _generateDynamicMultiOffRampConfig(USER_3, ZERO_ADDRESS);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroAddressNotAllowed.selector);
+
+ s_offRamp.setDynamicConfig(dynamicConfig);
+ }
+}
+
+contract EVM2EVMMultiOffRamp_ccipReceive is EVM2EVMMultiOffRampSetup {
+ // Reverts
+
+ function test_Reverts() public {
+ Client.Any2EVMMessage memory message =
+ _convertToGeneralMessage(_generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1));
+ vm.expectRevert();
+ s_offRamp.ccipReceive(message);
+ }
+}
+
+contract EVM2EVMMultiOffRamp_executeSingleReport is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1);
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_3, 1);
+ }
+
+ function test_SingleMessageNoTokens_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+
+ messages[0].header.nonce++;
+ messages[0].header.sequenceNumber++;
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ uint64 nonceBefore = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender);
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ assertGt(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender), nonceBefore);
+ }
+
+ function test_SingleMessageNoTokensUnordered_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ messages[0].header.nonce = 0;
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ // Nonce never increments on unordered messages.
+ uint64 nonceBefore = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender);
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ assertEq(
+ s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender),
+ nonceBefore,
+ "nonce must remain unchanged on unordered messages"
+ );
+
+ messages[0].header.sequenceNumber++;
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ // Nonce never increments on unordered messages.
+ nonceBefore = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender);
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ assertEq(
+ s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender),
+ nonceBefore,
+ "nonce must remain unchanged on unordered messages"
+ );
+ }
+
+ function test_SingleMessageNoTokensOtherChain_Success() public {
+ Internal.Any2EVMRampMessage[] memory messagesChain1 =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesChain1), new uint256[](0)
+ );
+
+ uint64 nonceChain1 = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messagesChain1[0].sender);
+ assertGt(nonceChain1, 0);
+
+ Internal.Any2EVMRampMessage[] memory messagesChain2 =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_3, ON_RAMP_ADDRESS_3);
+ assertEq(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, messagesChain2[0].sender), 0);
+
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_3, messagesChain2), new uint256[](0)
+ );
+ assertGt(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, messagesChain2[0].sender), 0);
+
+ // Other chain's nonce is unaffected
+ assertEq(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messagesChain1[0].sender), nonceChain1);
+ }
+
+ function test_ReceiverError_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ bytes memory realError1 = new bytes(2);
+ realError1[0] = 0xbe;
+ realError1[1] = 0xef;
+ s_reverting_receiver.setErr(realError1);
+
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, realError1)
+ )
+ );
+ // Nonce should increment on non-strict
+ assertEq(uint64(0), s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(OWNER)));
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ assertEq(uint64(1), s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(OWNER)));
+ }
+
+ function test_SkippedIncorrectNonce_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ messages[0].header.nonce++;
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit NonceManager.SkippedIncorrectNonce(
+ messages[0].header.sourceChainSelector, messages[0].header.nonce, messages[0].sender
+ );
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ }
+
+ function test_SkippedIncorrectNonceStillExecutes_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ messages[1].header.nonce++;
+ messages[1].header.messageId = Internal._hash(messages[1], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit NonceManager.SkippedIncorrectNonce(SOURCE_CHAIN_SELECTOR_1, messages[1].header.nonce, messages[1].sender);
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ }
+
+ function test__execute_SkippedAlreadyExecutedMessage_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SkippedAlreadyExecutedMessage(SOURCE_CHAIN_SELECTOR_1, messages[0].header.sequenceNumber);
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ }
+
+ function test__execute_SkippedAlreadyExecutedMessageUnordered_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ messages[0].header.nonce = 0;
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SkippedAlreadyExecutedMessage(SOURCE_CHAIN_SELECTOR_1, messages[0].header.sequenceNumber);
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ }
+
+ // Send a message to a contract that does not implement the CCIPReceiver interface
+ // This should execute successfully.
+ function test_SingleMessageToNonCCIPReceiver_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ MaybeRevertMessageReceiverNo165 newReceiver = new MaybeRevertMessageReceiverNo165(true);
+ messages[0].receiver = address(newReceiver);
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ }
+
+ function test_SingleMessagesNoTokensSuccess_gas() public {
+ vm.pauseGasMetering();
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ Internal.ExecutionReportSingleChain memory report = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.resumeGasMetering();
+ s_offRamp.executeSingleReport(report, new uint256[](0));
+ }
+
+ function test_TwoMessagesWithTokensSuccess_gas() public {
+ vm.pauseGasMetering();
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ // Set message 1 to use another receiver to simulate more fair gas costs
+ messages[1].receiver = address(s_secondary_receiver);
+ messages[1].header.messageId = Internal._hash(messages[1], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[1].header.sequenceNumber,
+ messages[1].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ Internal.ExecutionReportSingleChain memory report = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.resumeGasMetering();
+ s_offRamp.executeSingleReport(report, new uint256[](0));
+ }
+
+ function test_TwoMessagesWithTokensAndGE_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ // Set message 1 to use another receiver to simulate more fair gas costs
+ messages[1].receiver = address(s_secondary_receiver);
+ messages[1].header.messageId = Internal._hash(messages[1], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[1].header.sequenceNumber,
+ messages[1].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ assertEq(uint64(0), s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(OWNER)));
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), _getGasLimitsFromMessages(messages)
+ );
+ assertEq(uint64(2), s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(OWNER)));
+ }
+
+ function test_Fuzz_InterleavingOrderedAndUnorderedMessages_Success(bool[7] memory orderings) public {
+ Internal.Any2EVMRampMessage[] memory messages = new Internal.Any2EVMRampMessage[](orderings.length);
+ // number of tokens needs to be capped otherwise we hit UnsupportedNumberOfTokens.
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](3);
+ for (uint256 i = 0; i < 3; ++i) {
+ tokenAmounts[i].token = s_sourceTokens[i % s_sourceTokens.length];
+ tokenAmounts[i].amount = 1e18;
+ }
+ uint64 expectedNonce = 0;
+ for (uint256 i = 0; i < orderings.length; ++i) {
+ messages[i] =
+ _generateAny2EVMMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, uint64(i + 1), tokenAmounts, !orderings[i]);
+ if (orderings[i]) {
+ messages[i].header.nonce = ++expectedNonce;
+ }
+ messages[i].header.messageId = Internal._hash(messages[i], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[i].header.sequenceNumber,
+ messages[i].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+ }
+
+ uint64 nonceBefore = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(OWNER));
+ assertEq(uint64(0), nonceBefore, "nonce before exec should be 0");
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), _getGasLimitsFromMessages(messages)
+ );
+ // all executions should succeed.
+ for (uint256 i = 0; i < orderings.length; ++i) {
+ assertEq(
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, messages[i].header.sequenceNumber)),
+ uint256(Internal.MessageExecutionState.SUCCESS)
+ );
+ }
+ assertEq(
+ nonceBefore + expectedNonce, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(OWNER))
+ );
+ }
+
+ function test_InvalidSourcePoolAddress_Success() public {
+ address fakePoolAddress = address(0x0000000000333333);
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ messages[0].tokenAmounts[0].sourcePoolAddress = abi.encode(fakePoolAddress);
+
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+ messages[1].header.messageId = Internal._hash(messages[1], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.TokenHandlingError.selector,
+ abi.encodeWithSelector(TokenPool.InvalidSourcePoolAddress.selector, abi.encode(fakePoolAddress))
+ )
+ );
+
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ }
+
+ function test_WithCurseOnAnotherSourceChain_Success() public {
+ s_mockRMN.setChainCursed(SOURCE_CHAIN_SELECTOR_2, true);
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(
+ SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)
+ ),
+ new uint256[](0)
+ );
+ }
+
+ // Reverts
+
+ function test_MismatchingDestChainSelector_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_3, ON_RAMP_ADDRESS_3);
+ messages[0].header.destChainSelector = DEST_CHAIN_SELECTOR + 1;
+
+ Internal.ExecutionReportSingleChain memory executionReport =
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.InvalidMessageDestChainSelector.selector, messages[0].header.destChainSelector
+ )
+ );
+ s_offRamp.executeSingleReport(executionReport, new uint256[](0));
+ }
+
+ function test_MismatchingOnRampRoot_Revert() public {
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 0);
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = _constructCommitReport(
+ // Root against mismatching on ramp
+ Internal._hash(messages[0], ON_RAMP_ADDRESS_3)
+ );
+ _commit(commitReport, s_latestSequenceNumber);
+
+ Internal.ExecutionReportSingleChain memory executionReport =
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.RootNotCommitted.selector, SOURCE_CHAIN_SELECTOR_1));
+ s_offRamp.executeSingleReport(executionReport, new uint256[](0));
+ }
+
+ function test_Unhealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.CursedByRMN.selector, SOURCE_CHAIN_SELECTOR_1));
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(
+ SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)
+ ),
+ new uint256[](0)
+ );
+ // Uncurse should succeed
+ s_mockRMN.setGlobalCursed(false);
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(
+ SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)
+ ),
+ new uint256[](0)
+ );
+ }
+
+ function test_UnhealthySingleChainCurse_Revert() public {
+ s_mockRMN.setChainCursed(SOURCE_CHAIN_SELECTOR_1, true);
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.CursedByRMN.selector, SOURCE_CHAIN_SELECTOR_1));
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(
+ SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)
+ ),
+ new uint256[](0)
+ );
+ // Uncurse should succeed
+ s_mockRMN.setChainCursed(SOURCE_CHAIN_SELECTOR_1, false);
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(
+ SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)
+ ),
+ new uint256[](0)
+ );
+ }
+
+ function test_UnexpectedTokenData_Revert() public {
+ Internal.ExecutionReportSingleChain memory report = _generateReportFromMessages(
+ SOURCE_CHAIN_SELECTOR_1, _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)
+ );
+ report.offchainTokenData = new bytes[][](report.messages.length + 1);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.UnexpectedTokenData.selector);
+
+ s_offRamp.executeSingleReport(report, new uint256[](0));
+ }
+
+ function test_EmptyReport_Revert() public {
+ vm.expectRevert(EVM2EVMMultiOffRamp.EmptyReport.selector);
+ s_offRamp.executeSingleReport(
+ Internal.ExecutionReportSingleChain({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ proofs: new bytes32[](0),
+ proofFlagBits: 0,
+ messages: new Internal.Any2EVMRampMessage[](0),
+ offchainTokenData: new bytes[][](0)
+ }),
+ new uint256[](0)
+ );
+ }
+
+ function test_RootNotCommitted_Revert() public {
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 0);
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.RootNotCommitted.selector, SOURCE_CHAIN_SELECTOR_1));
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), _getGasLimitsFromMessages(messages)
+ );
+ }
+
+ function test_ManualExecutionNotYetEnabled_Revert() public {
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, BLOCK_TIME);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(EVM2EVMMultiOffRamp.ManualExecutionNotYetEnabled.selector, SOURCE_CHAIN_SELECTOR_1)
+ );
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ s_offRamp.executeSingleReport(
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), _getGasLimitsFromMessages(messages)
+ );
+ }
+
+ function test_NonExistingSourceChain_Revert() public {
+ uint64 newSourceChainSelector = SOURCE_CHAIN_SELECTOR_1 + 1;
+ bytes memory newOnRamp = abi.encode(ON_RAMP_ADDRESS, 1);
+
+ Internal.Any2EVMRampMessage[] memory messages = _generateSingleBasicMessage(newSourceChainSelector, newOnRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.SourceChainNotEnabled.selector, newSourceChainSelector));
+ s_offRamp.executeSingleReport(_generateReportFromMessages(newSourceChainSelector, messages), new uint256[](0));
+ }
+
+ function test_DisabledSourceChain_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_2, ON_RAMP_ADDRESS_2);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.SourceChainNotEnabled.selector, SOURCE_CHAIN_SELECTOR_2));
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_2, messages), new uint256[](0));
+ }
+
+ function test_TokenDataMismatch_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ Internal.ExecutionReportSingleChain memory report = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ report.offchainTokenData[0] = new bytes[](messages[0].tokenAmounts.length + 1);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.TokenDataMismatch.selector, SOURCE_CHAIN_SELECTOR_1, messages[0].header.sequenceNumber
+ )
+ );
+ s_offRamp.executeSingleReport(report, new uint256[](0));
+ }
+
+ function test_RouterYULCall_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ // gas limit too high, Router's external call should revert
+ messages[0].gasLimit = 1e36;
+ messages[0].receiver = address(new ConformingReceiver(address(s_destRouter), s_destFeeToken));
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ Internal.ExecutionReportSingleChain memory executionReport =
+ _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(CallWithExactGas.NotEnoughGasForCall.selector)
+ );
+ s_offRamp.executeSingleReport(executionReport, new uint256[](0));
+ }
+
+ function test_RetryFailedMessageWithoutManualExecution_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ bytes memory realError1 = new bytes(2);
+ realError1[0] = 0xbe;
+ realError1[1] = 0xef;
+ s_reverting_receiver.setErr(realError1);
+
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, realError1)
+ )
+ );
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.AlreadyAttempted.selector, SOURCE_CHAIN_SELECTOR_1, messages[0].header.sequenceNumber
+ )
+ );
+ s_offRamp.executeSingleReport(_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[](0));
+ }
+
+ function _constructCommitReport(bytes32 merkleRoot) internal view returns (EVM2EVMMultiOffRamp.CommitReport memory) {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 2),
+ merkleRoot: merkleRoot
+ });
+
+ return EVM2EVMMultiOffRamp.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ merkleRoots: roots
+ });
+ }
+}
+
+contract EVM2EVMMultiOffRamp_executeSingleMessage is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+ vm.startPrank(address(s_offRamp));
+ }
+
+ function test_executeSingleMessage_NoTokens_Success() public {
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_executeSingleMessage_WithTokens_Success() public {
+ Internal.Any2EVMRampMessage memory message =
+ _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)[0];
+ bytes[] memory offchainTokenData = new bytes[](message.tokenAmounts.length);
+
+ vm.expectCall(
+ s_destPoolByToken[s_destTokens[0]],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: message.sender,
+ receiver: message.receiver,
+ amount: message.tokenAmounts[0].amount,
+ localToken: abi.decode(message.tokenAmounts[0].destTokenAddress, (address)),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ sourcePoolAddress: message.tokenAmounts[0].sourcePoolAddress,
+ sourcePoolData: message.tokenAmounts[0].extraData,
+ offchainTokenData: offchainTokenData[0]
+ })
+ )
+ );
+
+ s_offRamp.executeSingleMessage(message, offchainTokenData);
+ }
+
+ function test_executeSingleMessage_WithValidation_Success() public {
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ _enableInboundMessageValidator();
+ vm.startPrank(address(s_offRamp));
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_NonContract_Success() public {
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ message.receiver = STRANGER;
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_NonContractWithTokens_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+ vm.expectEmit();
+ emit TokenPool.Released(address(s_offRamp), STRANGER, amounts[0]);
+ vm.expectEmit();
+ emit TokenPool.Minted(address(s_offRamp), STRANGER, amounts[1]);
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1, amounts);
+ message.receiver = STRANGER;
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ // Reverts
+
+ function test_TokenHandlingError_Revert() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+
+ bytes memory errorMessage = "Random token pool issue";
+
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1, amounts);
+ s_maybeRevertingPool.setShouldRevert(errorMessage);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.TokenHandlingError.selector, errorMessage));
+
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_ZeroGasDONExecution_Revert() public {
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ message.gasLimit = 0;
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.ReceiverError.selector, ""));
+
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_MessageSender_Revert() public {
+ vm.stopPrank();
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ vm.expectRevert(EVM2EVMMultiOffRamp.CanOnlySelfCall.selector);
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_executeSingleMessage_WithFailingValidation_Revert() public {
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ _enableInboundMessageValidator();
+ vm.startPrank(address(s_offRamp));
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ s_inboundMessageValidator.setMessageIdValidationState(message.header.messageId, true);
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ IMessageInterceptor.MessageValidationError.selector,
+ abi.encodeWithSelector(IMessageInterceptor.MessageValidationError.selector, bytes("Invalid message"))
+ )
+ );
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_executeSingleMessage_WithFailingValidationNoRouterCall_Revert() public {
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ _enableInboundMessageValidator();
+ vm.startPrank(address(s_offRamp));
+
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+
+ // Setup the receiver to a non-CCIP Receiver, which will skip the Router call (but should still perform the validation)
+ MaybeRevertMessageReceiverNo165 newReceiver = new MaybeRevertMessageReceiverNo165(true);
+ message.receiver = address(newReceiver);
+ message.header.messageId = Internal._hash(message, ON_RAMP_ADDRESS_1);
+
+ s_inboundMessageValidator.setMessageIdValidationState(message.header.messageId, true);
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ IMessageInterceptor.MessageValidationError.selector,
+ abi.encodeWithSelector(IMessageInterceptor.MessageValidationError.selector, bytes("Invalid message"))
+ )
+ );
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+}
+
+contract EVM2EVMMultiOffRamp_batchExecute is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1);
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_3, 1);
+ }
+
+ function test_SingleReport_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ uint64 nonceBefore = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender);
+ s_offRamp.batchExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[][](1));
+
+ assertGt(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender), nonceBefore);
+ }
+
+ function test_MultipleReportsSameChain_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages1 = new Internal.Any2EVMRampMessage[](2);
+ Internal.Any2EVMRampMessage[] memory messages2 = new Internal.Any2EVMRampMessage[](1);
+
+ messages1[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ messages1[1] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 2);
+ messages2[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 3);
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages1);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages2);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages1[0].header.sourceChainSelector,
+ messages1[0].header.sequenceNumber,
+ messages1[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages1[1].header.sourceChainSelector,
+ messages1[1].header.sequenceNumber,
+ messages1[1].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages2[0].header.sourceChainSelector,
+ messages2[0].header.sequenceNumber,
+ messages2[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ uint64 nonceBefore = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages1[0].sender);
+ s_offRamp.batchExecute(reports, new uint256[][](2));
+ assertGt(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages1[0].sender), nonceBefore);
+ }
+
+ function test_MultipleReportsDifferentChains_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages1 = new Internal.Any2EVMRampMessage[](2);
+ Internal.Any2EVMRampMessage[] memory messages2 = new Internal.Any2EVMRampMessage[](1);
+
+ messages1[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ messages1[1] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 2);
+ messages2[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_3, ON_RAMP_ADDRESS_3, 1);
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages1);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_3, messages2);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages1[0].header.sourceChainSelector,
+ messages1[0].header.sequenceNumber,
+ messages1[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages1[1].header.sourceChainSelector,
+ messages1[1].header.sequenceNumber,
+ messages1[1].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages2[0].header.sourceChainSelector,
+ messages2[0].header.sequenceNumber,
+ messages2[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.batchExecute(reports, new uint256[][](2));
+
+ uint64 nonceChain1 = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages1[0].sender);
+ uint64 nonceChain3 = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, messages2[0].sender);
+
+ assertTrue(nonceChain1 != nonceChain3);
+ assertGt(nonceChain1, 0);
+ assertGt(nonceChain3, 0);
+ }
+
+ function test_MultipleReportsSkipDuplicate_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SkippedAlreadyExecutedMessage(SOURCE_CHAIN_SELECTOR_1, messages[0].header.sequenceNumber);
+
+ s_offRamp.batchExecute(reports, new uint256[][](2));
+ }
+
+ // Reverts
+ function test_ZeroReports_Revert() public {
+ vm.expectRevert(EVM2EVMMultiOffRamp.EmptyReport.selector);
+ s_offRamp.batchExecute(new Internal.ExecutionReportSingleChain[](0), new uint256[][](1));
+ }
+
+ function test_Unhealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.CursedByRMN.selector, SOURCE_CHAIN_SELECTOR_1));
+ s_offRamp.batchExecute(
+ _generateBatchReportFromMessages(
+ SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)
+ ),
+ new uint256[][](1)
+ );
+ // Uncurse should succeed
+ s_mockRMN.setGlobalCursed(false);
+ s_offRamp.batchExecute(
+ _generateBatchReportFromMessages(
+ SOURCE_CHAIN_SELECTOR_1, _generateMessagesWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1)
+ ),
+ new uint256[][](1)
+ );
+ }
+
+ function test_OutOfBoundsGasLimitsAccess_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages1 = new Internal.Any2EVMRampMessage[](2);
+ Internal.Any2EVMRampMessage[] memory messages2 = new Internal.Any2EVMRampMessage[](1);
+
+ messages1[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ messages1[1] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 2);
+ messages2[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 3);
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages1);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages2);
+
+ vm.expectRevert();
+ s_offRamp.batchExecute(reports, new uint256[][](1));
+ }
+}
+
+contract EVM2EVMMultiOffRamp_manuallyExecute is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1);
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_3, 1);
+ }
+
+ function test_manuallyExecute_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+ s_offRamp.batchExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[][](1));
+
+ s_reverting_receiver.setRevert(false);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = new uint256[](messages.length);
+ s_offRamp.manuallyExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), gasLimitOverrides);
+ }
+
+ function test_manuallyExecute_WithGasOverride_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+ s_offRamp.batchExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[][](1));
+
+ s_reverting_receiver.setRevert(false);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = _getGasLimitsFromMessages(messages);
+ gasLimitOverrides[0][0] += 1;
+
+ s_offRamp.manuallyExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), gasLimitOverrides);
+ }
+
+ function test_manuallyExecute_DoesNotRevertIfUntouched_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ assertEq(
+ messages[0].header.nonce - 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender)
+ );
+
+ s_reverting_receiver.setRevert(true);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, "")
+ )
+ );
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = _getGasLimitsFromMessages(messages);
+
+ s_offRamp.manuallyExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), gasLimitOverrides);
+
+ assertEq(
+ messages[0].header.nonce, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender)
+ );
+ }
+
+ function test_manuallyExecute_WithMultiReportGasOverride_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages1 = new Internal.Any2EVMRampMessage[](3);
+ Internal.Any2EVMRampMessage[] memory messages2 = new Internal.Any2EVMRampMessage[](2);
+
+ for (uint64 i = 0; i < 3; ++i) {
+ messages1[i] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, i + 1);
+ messages1[i].receiver = address(s_reverting_receiver);
+ messages1[i].header.messageId = Internal._hash(messages1[i], ON_RAMP_ADDRESS_1);
+ }
+
+ for (uint64 i = 0; i < 2; ++i) {
+ messages2[i] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_3, ON_RAMP_ADDRESS_3, i + 1);
+ messages2[i].receiver = address(s_reverting_receiver);
+ messages2[i].header.messageId = Internal._hash(messages2[i], ON_RAMP_ADDRESS_3);
+ }
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages1);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_3, messages2);
+
+ s_offRamp.batchExecute(reports, new uint256[][](2));
+
+ s_reverting_receiver.setRevert(false);
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](2);
+ gasLimitOverrides[0] = _getGasLimitsFromMessages(messages1);
+ gasLimitOverrides[1] = _getGasLimitsFromMessages(messages2);
+
+ for (uint256 i = 0; i < 3; ++i) {
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages1[i].header.sequenceNumber,
+ messages1[i].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ gasLimitOverrides[0][i] += 1;
+ }
+
+ for (uint256 i = 0; i < 2; ++i) {
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_3,
+ messages2[i].header.sequenceNumber,
+ messages2[i].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ gasLimitOverrides[1][i] += 1;
+ }
+
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+ }
+
+ function test_manuallyExecute_WithPartialMessages_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages = new Internal.Any2EVMRampMessage[](3);
+
+ for (uint64 i = 0; i < 3; ++i) {
+ messages[i] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, i + 1);
+ }
+ messages[1].receiver = address(s_reverting_receiver);
+ messages[1].header.messageId = Internal._hash(messages[1], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[1].header.sequenceNumber,
+ messages[1].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, bytes(""))
+ )
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[2].header.sequenceNumber,
+ messages[2].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.batchExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[][](1));
+
+ s_reverting_receiver.setRevert(false);
+
+ // Only the 2nd message reverted
+ Internal.Any2EVMRampMessage[] memory newMessages = new Internal.Any2EVMRampMessage[](1);
+ newMessages[0] = messages[1];
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = _getGasLimitsFromMessages(newMessages);
+ gasLimitOverrides[0][0] += 1;
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ newMessages[0].header.sequenceNumber,
+ newMessages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ s_offRamp.manuallyExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, newMessages), gasLimitOverrides);
+ }
+
+ function test_manuallyExecute_LowGasLimit_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ messages[0].gasLimit = 1;
+ messages[0].receiver = address(new ConformingReceiver(address(s_destRouter), s_destFeeToken));
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(EVM2EVMMultiOffRamp.ReceiverError.selector, "")
+ );
+ s_offRamp.batchExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[][](1));
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = new uint256[](1);
+ gasLimitOverrides[0][0] = 100_000;
+
+ vm.expectEmit();
+ emit ConformingReceiver.MessageReceived();
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+ s_offRamp.manuallyExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), gasLimitOverrides);
+ }
+
+ // Reverts
+
+ function test_manuallyExecute_ForkedChain_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ Internal.ExecutionReportSingleChain[] memory reports =
+ _generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+ uint256 chain1 = block.chainid;
+ uint256 chain2 = chain1 + 1;
+ vm.chainId(chain2);
+ vm.expectRevert(abi.encodeWithSelector(MultiOCR3Base.ForkedChain.selector, chain1, chain2));
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = _getGasLimitsFromMessages(messages);
+
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+ }
+
+ function test_ManualExecGasLimitMismatchSingleReport_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages = new Internal.Any2EVMRampMessage[](2);
+ messages[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ messages[1] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 2);
+
+ Internal.ExecutionReportSingleChain[] memory reports =
+ _generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ // No overrides for report
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, new uint256[][](0));
+
+ // No messages
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+
+ // 1 message missing
+ gasLimitOverrides[0] = new uint256[](1);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+
+ // 1 message in excess
+ gasLimitOverrides[0] = new uint256[](3);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+ }
+
+ function test_manuallyExecute_GasLimitMismatchMultipleReports_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages1 = new Internal.Any2EVMRampMessage[](2);
+ Internal.Any2EVMRampMessage[] memory messages2 = new Internal.Any2EVMRampMessage[](1);
+
+ messages1[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ messages1[1] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 2);
+ messages2[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_3, ON_RAMP_ADDRESS_3, 1);
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages1);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_3, messages2);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, new uint256[][](0));
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, new uint256[][](1));
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](2);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+
+ // 2nd report empty
+ gasLimitOverrides[0] = new uint256[](2);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+
+ // 1st report empty
+ gasLimitOverrides[0] = new uint256[](0);
+ gasLimitOverrides[1] = new uint256[](1);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+
+ // 1st report oversized
+ gasLimitOverrides[0] = new uint256[](3);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(reports, gasLimitOverrides);
+ }
+
+ function test_ManualExecInvalidGasLimit_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = _getGasLimitsFromMessages(messages);
+ gasLimitOverrides[0][0]--;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.InvalidManualExecutionGasLimit.selector, SOURCE_CHAIN_SELECTOR_1, 0, gasLimitOverrides[0][0]
+ )
+ );
+ s_offRamp.manuallyExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), gasLimitOverrides);
+ }
+
+ function test_manuallyExecute_FailedTx_Revert() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ s_offRamp.batchExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new uint256[][](1));
+
+ s_reverting_receiver.setRevert(true);
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = _getGasLimitsFromMessages(messages);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.ExecutionError.selector,
+ messages[0].header.messageId,
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, bytes(""))
+ )
+ )
+ );
+ s_offRamp.manuallyExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), gasLimitOverrides);
+ }
+
+ function test_manuallyExecute_ReentrancyFails() public {
+ uint256 tokenAmount = 1e9;
+ IERC20 tokenToAbuse = IERC20(s_destFeeToken);
+
+ // This needs to be deployed before the source chain message is sent
+ // because we need the address for the receiver.
+ ReentrancyAbuserMultiRamp receiver = new ReentrancyAbuserMultiRamp(address(s_destRouter), s_offRamp);
+ uint256 balancePre = tokenToAbuse.balanceOf(address(receiver));
+
+ // For this test any message will be flagged as correct by the
+ // commitStore. In a real scenario the abuser would have to actually
+ // send the message that they want to replay.
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ messages[0].tokenAmounts = new Internal.RampTokenAmount[](1);
+ messages[0].tokenAmounts[0] = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[s_sourceFeeToken]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[s_sourceFeeToken]),
+ extraData: "",
+ amount: tokenAmount
+ });
+
+ messages[0].receiver = address(receiver);
+
+ messages[0].header.messageId = Internal._hash(messages[0], ON_RAMP_ADDRESS_1);
+
+ Internal.ExecutionReportSingleChain memory report = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ // sets the report to be repeated on the ReentrancyAbuser to be able to replay
+ receiver.setPayload(report);
+
+ uint256[][] memory gasLimitOverrides = new uint256[][](1);
+ gasLimitOverrides[0] = _getGasLimitsFromMessages(messages);
+
+ // The first entry should be fine and triggers the second entry. This one fails
+ // but since it's an inner tx of the first one it is caught in the try-catch.
+ // This means the first tx is marked `FAILURE` with the error message of the second tx.
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.AlreadyExecuted.selector,
+ messages[0].header.sourceChainSelector,
+ messages[0].header.sequenceNumber
+ )
+ )
+ );
+
+ s_offRamp.manuallyExecute(_generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), gasLimitOverrides);
+
+ // Since the tx failed we don't release the tokens
+ assertEq(tokenToAbuse.balanceOf(address(receiver)), balancePre);
+ }
+}
+
+contract EVM2EVMMultiOffRamp_execute is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1);
+ }
+
+ // Asserts that execute completes
+ function test_SingleReport_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ Internal.ExecutionReportSingleChain[] memory reports =
+ _generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ SOURCE_CHAIN_SELECTOR_1,
+ messages[0].header.sequenceNumber,
+ messages[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(
+ uint8(Internal.OCRPluginType.Execution), s_configDigestExec, uint64(uint256(s_configDigestExec))
+ );
+
+ _execute(reports);
+ }
+
+ function test_MultipleReports_Success() public {
+ Internal.Any2EVMRampMessage[] memory messages1 = new Internal.Any2EVMRampMessage[](2);
+ Internal.Any2EVMRampMessage[] memory messages2 = new Internal.Any2EVMRampMessage[](1);
+
+ messages1[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ messages1[1] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 2);
+ messages2[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 3);
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages1);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages2);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages1[0].header.sourceChainSelector,
+ messages1[0].header.sequenceNumber,
+ messages1[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages1[1].header.sourceChainSelector,
+ messages1[1].header.sequenceNumber,
+ messages1[1].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages2[0].header.sourceChainSelector,
+ messages2[0].header.sequenceNumber,
+ messages2[0].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(
+ uint8(Internal.OCRPluginType.Execution), s_configDigestExec, uint64(uint256(s_configDigestExec))
+ );
+
+ _execute(reports);
+ }
+
+ function test_LargeBatch_Success() public {
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](10);
+ for (uint64 i = 0; i < reports.length; ++i) {
+ Internal.Any2EVMRampMessage[] memory messages = new Internal.Any2EVMRampMessage[](3);
+ messages[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1 + i * 3);
+ messages[1] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 2 + i * 3);
+ messages[2] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 3 + i * 3);
+
+ reports[i] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+ }
+
+ for (uint64 i = 0; i < reports.length; ++i) {
+ for (uint64 j = 0; j < reports[i].messages.length; ++j) {
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ reports[i].messages[j].header.sourceChainSelector,
+ reports[i].messages[j].header.sequenceNumber,
+ reports[i].messages[j].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+ }
+ }
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(
+ uint8(Internal.OCRPluginType.Execution), s_configDigestExec, uint64(uint256(s_configDigestExec))
+ );
+
+ _execute(reports);
+ }
+
+ function test_MultipleReportsWithPartialValidationFailures_Success() public {
+ _enableInboundMessageValidator();
+
+ Internal.Any2EVMRampMessage[] memory messages1 = new Internal.Any2EVMRampMessage[](2);
+ Internal.Any2EVMRampMessage[] memory messages2 = new Internal.Any2EVMRampMessage[](1);
+
+ messages1[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1);
+ messages1[1] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 2);
+ messages2[0] = _generateAny2EVMMessageNoTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 3);
+
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](2);
+ reports[0] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages1);
+ reports[1] = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages2);
+
+ s_inboundMessageValidator.setMessageIdValidationState(messages1[0].header.messageId, true);
+ s_inboundMessageValidator.setMessageIdValidationState(messages2[0].header.messageId, true);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages1[0].header.sourceChainSelector,
+ messages1[0].header.sequenceNumber,
+ messages1[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ IMessageInterceptor.MessageValidationError.selector,
+ abi.encodeWithSelector(IMessageInterceptor.MessageValidationError.selector, bytes("Invalid message"))
+ )
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages1[1].header.sourceChainSelector,
+ messages1[1].header.sequenceNumber,
+ messages1[1].header.messageId,
+ Internal.MessageExecutionState.SUCCESS,
+ ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.ExecutionStateChanged(
+ messages2[0].header.sourceChainSelector,
+ messages2[0].header.sequenceNumber,
+ messages2[0].header.messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ IMessageInterceptor.MessageValidationError.selector,
+ abi.encodeWithSelector(IMessageInterceptor.MessageValidationError.selector, bytes("Invalid message"))
+ )
+ );
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(
+ uint8(Internal.OCRPluginType.Execution), s_configDigestExec, uint64(uint256(s_configDigestExec))
+ );
+
+ _execute(reports);
+ }
+
+ // Reverts
+
+ function test_UnauthorizedTransmitter_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigestExec, s_configDigestExec, s_configDigestExec];
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ Internal.ExecutionReportSingleChain[] memory reports =
+ _generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.expectRevert(MultiOCR3Base.UnauthorizedTransmitter.selector);
+ s_offRamp.execute(reportContext, abi.encode(reports));
+ }
+
+ function test_NoConfig_Revert() public {
+ _redeployOffRampWithNoOCRConfigs();
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1);
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ Internal.ExecutionReportSingleChain[] memory reports =
+ _generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ bytes32[3] memory reportContext = [bytes32(""), s_configDigestExec, s_configDigestExec];
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert(MultiOCR3Base.UnauthorizedTransmitter.selector);
+ s_offRamp.execute(reportContext, abi.encode(reports));
+ }
+
+ function test_NoConfigWithOtherConfigPresent_Revert() public {
+ _redeployOffRampWithNoOCRConfigs();
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Commit),
+ configDigest: s_configDigestCommit,
+ F: s_F,
+ isSignatureVerificationEnabled: false,
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+ s_offRamp.setOCR3Configs(ocrConfigs);
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ Internal.ExecutionReportSingleChain[] memory reports =
+ _generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ bytes32[3] memory reportContext = [bytes32(""), s_configDigestExec, s_configDigestExec];
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert(MultiOCR3Base.UnauthorizedTransmitter.selector);
+ s_offRamp.execute(reportContext, abi.encode(reports));
+ }
+
+ function test_WrongConfigWithSigners_Revert() public {
+ _redeployOffRampWithNoOCRConfigs();
+ s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1);
+
+ s_configDigestExec = _getBasicConfigDigest(1, s_validSigners, s_validTransmitters);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Execution),
+ configDigest: s_configDigestExec,
+ F: s_F,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+ s_offRamp.setOCR3Configs(ocrConfigs);
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ Internal.ExecutionReportSingleChain[] memory reports =
+ _generateBatchReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.expectRevert();
+ _execute(reports);
+ }
+
+ function test_ZeroReports_Revert() public {
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](0);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.EmptyReport.selector);
+ _execute(reports);
+ }
+
+ function test_IncorrectArrayType_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigestExec, s_configDigestExec, s_configDigestExec];
+
+ uint256[] memory wrongData = new uint256[](1);
+ wrongData[0] = 1;
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert();
+ s_offRamp.execute(reportContext, abi.encode(wrongData));
+ }
+
+ function test_NonArray_Revert() public {
+ bytes32[3] memory reportContext = [s_configDigestExec, s_configDigestExec, s_configDigestExec];
+
+ Internal.Any2EVMRampMessage[] memory messages =
+ _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1);
+ Internal.ExecutionReportSingleChain memory report = _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert();
+ s_offRamp.execute(reportContext, abi.encode(report));
+ }
+}
+
+contract EVM2EVMMultiOffRamp_getExecutionState is EVM2EVMMultiOffRampSetup {
+ mapping(uint64 sourceChainSelector => mapping(uint64 seqNum => Internal.MessageExecutionState state)) internal
+ s_differentialExecutionState;
+
+ /// forge-config: default.fuzz.runs = 32
+ /// forge-config: ccip.fuzz.runs = 32
+ function test_Fuzz_Differential_Success(
+ uint64 sourceChainSelector,
+ uint16[500] memory seqNums,
+ uint8[500] memory values
+ ) public {
+ for (uint256 i = 0; i < seqNums.length; ++i) {
+ // Only use the first three slots. This makes sure existing slots get overwritten
+ // as the tests uses 500 sequence numbers.
+ uint16 seqNum = seqNums[i] % 386;
+ Internal.MessageExecutionState state = Internal.MessageExecutionState(values[i] % 4);
+ s_differentialExecutionState[sourceChainSelector][seqNum] = state;
+ s_offRamp.setExecutionStateHelper(sourceChainSelector, seqNum, state);
+ assertEq(uint256(state), uint256(s_offRamp.getExecutionState(sourceChainSelector, seqNum)));
+ }
+
+ for (uint256 i = 0; i < seqNums.length; ++i) {
+ uint16 seqNum = seqNums[i] % 386;
+ Internal.MessageExecutionState expectedState = s_differentialExecutionState[sourceChainSelector][seqNum];
+ assertEq(uint256(expectedState), uint256(s_offRamp.getExecutionState(sourceChainSelector, seqNum)));
+ }
+ }
+
+ function test_GetExecutionState_Success() public {
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 0, Internal.MessageExecutionState.FAILURE);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3);
+
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 1, Internal.MessageExecutionState.FAILURE);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3 + (3 << 2));
+
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 1, Internal.MessageExecutionState.IN_PROGRESS);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3 + (1 << 2));
+
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 2, Internal.MessageExecutionState.FAILURE);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3 + (1 << 2) + (3 << 4));
+
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 127, Internal.MessageExecutionState.IN_PROGRESS);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3 + (1 << 2) + (3 << 4) + (1 << 254));
+
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 128, Internal.MessageExecutionState.SUCCESS);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3 + (1 << 2) + (3 << 4) + (1 << 254));
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 1), 2);
+
+ assertEq(
+ uint256(Internal.MessageExecutionState.FAILURE), uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, 0))
+ );
+ assertEq(
+ uint256(Internal.MessageExecutionState.IN_PROGRESS),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, 1))
+ );
+ assertEq(
+ uint256(Internal.MessageExecutionState.FAILURE), uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, 2))
+ );
+ assertEq(
+ uint256(Internal.MessageExecutionState.IN_PROGRESS),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, 127))
+ );
+ assertEq(
+ uint256(Internal.MessageExecutionState.SUCCESS),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, 128))
+ );
+ }
+
+ function test_GetDifferentChainExecutionState_Success() public {
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 0, Internal.MessageExecutionState.FAILURE);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1 + 1, 0), 0);
+
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 127, Internal.MessageExecutionState.IN_PROGRESS);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3 + (1 << 254));
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1 + 1, 0), 0);
+
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, 128, Internal.MessageExecutionState.SUCCESS);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3 + (1 << 254));
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 1), 2);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1 + 1, 0), 0);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1 + 1, 1), 0);
+
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1 + 1, 127, Internal.MessageExecutionState.FAILURE);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 0), 3 + (1 << 254));
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, 1), 2);
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1 + 1, 0), (3 << 254));
+ assertEq(s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1 + 1, 1), 0);
+
+ assertEq(
+ uint256(Internal.MessageExecutionState.FAILURE), uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, 0))
+ );
+ assertEq(
+ uint256(Internal.MessageExecutionState.IN_PROGRESS),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, 127))
+ );
+ assertEq(
+ uint256(Internal.MessageExecutionState.SUCCESS),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, 128))
+ );
+
+ assertEq(
+ uint256(Internal.MessageExecutionState.UNTOUCHED),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1 + 1, 0))
+ );
+ assertEq(
+ uint256(Internal.MessageExecutionState.FAILURE),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1 + 1, 127))
+ );
+ assertEq(
+ uint256(Internal.MessageExecutionState.UNTOUCHED),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1 + 1, 128))
+ );
+ }
+
+ function test_FillExecutionState_Success() public {
+ for (uint64 i = 0; i < 384; ++i) {
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, i, Internal.MessageExecutionState.FAILURE);
+ }
+
+ for (uint64 i = 0; i < 384; ++i) {
+ assertEq(
+ uint256(Internal.MessageExecutionState.FAILURE),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, i))
+ );
+ }
+
+ for (uint64 i = 0; i < 3; ++i) {
+ assertEq(type(uint256).max, s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, i));
+ }
+
+ for (uint64 i = 0; i < 384; ++i) {
+ s_offRamp.setExecutionStateHelper(SOURCE_CHAIN_SELECTOR_1, i, Internal.MessageExecutionState.IN_PROGRESS);
+ }
+
+ for (uint64 i = 0; i < 384; ++i) {
+ assertEq(
+ uint256(Internal.MessageExecutionState.IN_PROGRESS),
+ uint256(s_offRamp.getExecutionState(SOURCE_CHAIN_SELECTOR_1, i))
+ );
+ }
+
+ for (uint64 i = 0; i < 3; ++i) {
+ // 0x555... == 0b101010101010.....
+ assertEq(
+ 0x5555555555555555555555555555555555555555555555555555555555555555,
+ s_offRamp.getExecutionStateBitMap(SOURCE_CHAIN_SELECTOR_1, i)
+ );
+ }
+ }
+}
+
+contract EVM2EVMMultiOffRamp_trialExecute is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+ }
+
+ function test_trialExecute_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1, amounts);
+ IERC20 dstToken0 = IERC20(s_destTokens[0]);
+ uint256 startingBalance = dstToken0.balanceOf(message.receiver);
+
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+ assertEq(uint256(Internal.MessageExecutionState.SUCCESS), uint256(newState));
+ assertEq("", err);
+
+ // Check that the tokens were transferred
+ assertEq(startingBalance + amounts[0], dstToken0.balanceOf(message.receiver));
+ }
+
+ function test_TokenHandlingErrorIsCaught_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+
+ IERC20 dstToken0 = IERC20(s_destTokens[0]);
+ uint256 startingBalance = dstToken0.balanceOf(OWNER);
+
+ bytes memory errorMessage = "Random token pool issue";
+
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1, amounts);
+ s_maybeRevertingPool.setShouldRevert(errorMessage);
+
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(newState));
+ assertEq(abi.encodeWithSelector(EVM2EVMMultiOffRamp.TokenHandlingError.selector, errorMessage), err);
+
+ // Expect the balance to remain the same
+ assertEq(startingBalance, dstToken0.balanceOf(OWNER));
+ }
+
+ function test_RateLimitError_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+
+ bytes memory errorMessage = abi.encodeWithSelector(RateLimiter.BucketOverfilled.selector);
+
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1, amounts);
+ s_maybeRevertingPool.setShouldRevert(errorMessage);
+
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(newState));
+ assertEq(abi.encodeWithSelector(EVM2EVMMultiOffRamp.TokenHandlingError.selector, errorMessage), err);
+ }
+
+ // TODO test actual pool exists but isn't compatible instead of just no pool
+ function test_TokenPoolIsNotAContract_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 10000;
+ Internal.Any2EVMRampMessage memory message =
+ _generateAny2EVMMessageWithTokens(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1, 1, amounts);
+
+ // Happy path, pool is correct
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+
+ assertEq(uint256(Internal.MessageExecutionState.SUCCESS), uint256(newState));
+ assertEq("", err);
+
+ // address 0 has no contract
+ assertEq(address(0).code.length, 0);
+
+ message.tokenAmounts[0] = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(address(0)),
+ destTokenAddress: abi.encode(address(0)),
+ extraData: "",
+ amount: message.tokenAmounts[0].amount
+ });
+
+ message.header.messageId = Internal._hash(message, ON_RAMP_ADDRESS_1);
+
+ // Unhappy path, no revert but marked as failed.
+ (newState, err) = s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(newState));
+ assertEq(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, abi.encode(address(0))), err);
+
+ address notAContract = makeAddr("not_a_contract");
+
+ message.tokenAmounts[0] = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(address(0)),
+ destTokenAddress: abi.encode(notAContract),
+ extraData: "",
+ amount: message.tokenAmounts[0].amount
+ });
+
+ message.header.messageId = Internal._hash(message, ON_RAMP_ADDRESS_1);
+
+ (newState, err) = s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(newState));
+ assertEq(abi.encodeWithSelector(EVM2EVMMultiOffRamp.NotACompatiblePool.selector, address(0)), err);
+ }
+}
+
+contract EVM2EVMMultiOffRamp__releaseOrMintSingleToken is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+ }
+
+ function test__releaseOrMintSingleToken_Success() public {
+ uint256 amount = 123123;
+ address token = s_sourceTokens[0];
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes memory offchainTokenData = abi.encode(keccak256("offchainTokenData"));
+
+ IERC20 dstToken1 = IERC20(s_destTokenBySourceToken[token]);
+ uint256 startingBalance = dstToken1.balanceOf(OWNER);
+
+ Internal.RampTokenAmount memory tokenAmount = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[token]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[token]),
+ extraData: "",
+ amount: amount
+ });
+
+ vm.expectCall(
+ s_destPoolBySourceToken[token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: originalSender,
+ receiver: OWNER,
+ amount: amount,
+ localToken: s_destTokenBySourceToken[token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ sourcePoolAddress: tokenAmount.sourcePoolAddress,
+ sourcePoolData: tokenAmount.extraData,
+ offchainTokenData: offchainTokenData
+ })
+ )
+ );
+
+ s_offRamp.releaseOrMintSingleToken(tokenAmount, originalSender, OWNER, SOURCE_CHAIN_SELECTOR_1, offchainTokenData);
+
+ assertEq(startingBalance + amount, dstToken1.balanceOf(OWNER));
+ }
+
+ function test__releaseOrMintSingleToken_NotACompatiblePool_Revert() public {
+ uint256 amount = 123123;
+ address token = s_sourceTokens[0];
+ address destToken = s_destTokenBySourceToken[token];
+ vm.label(destToken, "destToken");
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes memory offchainTokenData = abi.encode(keccak256("offchainTokenData"));
+
+ Internal.RampTokenAmount memory tokenAmount = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[token]),
+ destTokenAddress: abi.encode(destToken),
+ extraData: "",
+ amount: amount
+ });
+
+ // Address(0) should always revert
+ address returnedPool = address(0);
+
+ vm.mockCall(
+ address(s_tokenAdminRegistry),
+ abi.encodeWithSelector(ITokenAdminRegistry.getPool.selector, destToken),
+ abi.encode(returnedPool)
+ );
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.NotACompatiblePool.selector, returnedPool));
+
+ s_offRamp.releaseOrMintSingleToken(tokenAmount, originalSender, OWNER, SOURCE_CHAIN_SELECTOR_1, offchainTokenData);
+
+ // A contract that doesn't support the interface should also revert
+ returnedPool = address(s_offRamp);
+
+ vm.mockCall(
+ address(s_tokenAdminRegistry),
+ abi.encodeWithSelector(ITokenAdminRegistry.getPool.selector, destToken),
+ abi.encode(returnedPool)
+ );
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.NotACompatiblePool.selector, returnedPool));
+
+ s_offRamp.releaseOrMintSingleToken(tokenAmount, originalSender, OWNER, SOURCE_CHAIN_SELECTOR_1, offchainTokenData);
+ }
+
+ function test__releaseOrMintSingleToken_TokenHandlingError_revert_Revert() public {
+ address receiver = makeAddr("receiver");
+ uint256 amount = 123123;
+ address token = s_sourceTokens[0];
+ address destToken = s_destTokenBySourceToken[token];
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes memory offchainTokenData = abi.encode(keccak256("offchainTokenData"));
+
+ Internal.RampTokenAmount memory tokenAmount = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[token]),
+ destTokenAddress: abi.encode(destToken),
+ extraData: "",
+ amount: amount
+ });
+
+ bytes memory revertData = "call reverted :o";
+
+ vm.mockCallRevert(destToken, abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount), revertData);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.TokenHandlingError.selector, revertData));
+ s_offRamp.releaseOrMintSingleToken(
+ tokenAmount, originalSender, receiver, SOURCE_CHAIN_SELECTOR_1, offchainTokenData
+ );
+ }
+}
+
+contract EVM2EVMMultiOffRamp_releaseOrMintTokens is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+ }
+
+ function test_releaseOrMintTokens_Success() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ IERC20 dstToken1 = IERC20(s_destFeeToken);
+ uint256 startingBalance = dstToken1.balanceOf(OWNER);
+ uint256 amount1 = 100;
+ srcTokenAmounts[0].amount = amount1;
+
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ offchainTokenData[0] = abi.encode(0x12345678);
+
+ Internal.RampTokenAmount[] memory sourceTokenAmounts = _getDefaultSourceTokenData(srcTokenAmounts);
+
+ vm.expectCall(
+ s_destPoolBySourceToken[srcTokenAmounts[0].token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ receiver: OWNER,
+ amount: srcTokenAmounts[0].amount,
+ localToken: s_destTokenBySourceToken[srcTokenAmounts[0].token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ sourcePoolAddress: sourceTokenAmounts[0].sourcePoolAddress,
+ sourcePoolData: sourceTokenAmounts[0].extraData,
+ offchainTokenData: offchainTokenData[0]
+ })
+ )
+ );
+
+ s_offRamp.releaseOrMintTokens(
+ sourceTokenAmounts, abi.encode(OWNER), OWNER, SOURCE_CHAIN_SELECTOR_1, offchainTokenData
+ );
+
+ assertEq(startingBalance + amount1, dstToken1.balanceOf(OWNER));
+ }
+
+ function test_releaseOrMintTokens_destDenominatedDecimals_Success() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ address destToken = s_destFeeToken;
+ uint256 amount = 100;
+ uint256 destinationDenominationMultiplier = 1000;
+ srcTokenAmounts[0].amount = amount;
+
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+
+ Internal.RampTokenAmount[] memory sourceTokenAmounts = _getDefaultSourceTokenData(srcTokenAmounts);
+
+ // Since the pool call is mocked, we manually release funds to the offRamp
+ deal(destToken, address(s_offRamp), amount * destinationDenominationMultiplier);
+
+ vm.mockCall(
+ s_destPoolBySourceToken[srcTokenAmounts[0].token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ receiver: OWNER,
+ amount: amount,
+ localToken: s_destTokenBySourceToken[srcTokenAmounts[0].token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ sourcePoolAddress: sourceTokenAmounts[0].sourcePoolAddress,
+ sourcePoolData: sourceTokenAmounts[0].extraData,
+ offchainTokenData: offchainTokenData[0]
+ })
+ ),
+ abi.encode(amount * destinationDenominationMultiplier)
+ );
+
+ Client.EVMTokenAmount[] memory destTokenAmounts = s_offRamp.releaseOrMintTokens(
+ sourceTokenAmounts, abi.encode(OWNER), OWNER, SOURCE_CHAIN_SELECTOR_1, offchainTokenData
+ );
+
+ assertEq(destTokenAmounts[0].amount, amount * destinationDenominationMultiplier);
+ assertEq(destTokenAmounts[0].token, destToken);
+ }
+
+ // Revert
+
+ function test_TokenHandlingError_Reverts() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+
+ bytes memory unknownError = bytes("unknown error");
+ s_maybeRevertingPool.setShouldRevert(unknownError);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.TokenHandlingError.selector, unknownError));
+
+ s_offRamp.releaseOrMintTokens(
+ _getDefaultSourceTokenData(srcTokenAmounts),
+ abi.encode(OWNER),
+ OWNER,
+ SOURCE_CHAIN_SELECTOR_1,
+ new bytes[](srcTokenAmounts.length)
+ );
+ }
+
+ function test_releaseOrMintTokens_InvalidDataLengthReturnData_Revert() public {
+ uint256 amount = 100;
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ srcTokenAmounts[0].amount = amount;
+
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ Internal.RampTokenAmount[] memory sourceTokenAmounts = _getDefaultSourceTokenData(srcTokenAmounts);
+
+ vm.mockCall(
+ s_destPoolBySourceToken[srcTokenAmounts[0].token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ receiver: OWNER,
+ amount: amount,
+ localToken: s_destTokenBySourceToken[srcTokenAmounts[0].token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ sourcePoolAddress: sourceTokenAmounts[0].sourcePoolAddress,
+ sourcePoolData: sourceTokenAmounts[0].extraData,
+ offchainTokenData: offchainTokenData[0]
+ })
+ ),
+ // Includes the amount twice, this will revert due to the return data being to long
+ abi.encode(amount, amount)
+ );
+
+ vm.expectRevert(
+ abi.encodeWithSelector(EVM2EVMMultiOffRamp.InvalidDataLength.selector, Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, 64)
+ );
+
+ s_offRamp.releaseOrMintTokens(
+ sourceTokenAmounts, abi.encode(OWNER), OWNER, SOURCE_CHAIN_SELECTOR_1, offchainTokenData
+ );
+ }
+
+ function test_releaseOrMintTokens_InvalidEVMAddress_Revert() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ Internal.RampTokenAmount[] memory sourceTokenAmounts = _getDefaultSourceTokenData(srcTokenAmounts);
+ bytes memory wrongAddress = abi.encode(address(1000), address(10000), address(10000));
+
+ sourceTokenAmounts[0].destTokenAddress = wrongAddress;
+
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, wrongAddress));
+
+ s_offRamp.releaseOrMintTokens(
+ sourceTokenAmounts, abi.encode(OWNER), OWNER, SOURCE_CHAIN_SELECTOR_1, offchainTokenData
+ );
+ }
+
+ function test__releaseOrMintTokens_PoolIsNotAPool_Reverts() public {
+ // The offRamp is a contract, but not a pool
+ address fakePoolAddress = address(s_offRamp);
+
+ Internal.RampTokenAmount[] memory sourceTokenAmounts = new Internal.RampTokenAmount[](1);
+ sourceTokenAmounts[0] = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(fakePoolAddress),
+ destTokenAddress: abi.encode(s_offRamp),
+ extraData: "",
+ amount: 1
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.NotACompatiblePool.selector, address(0)));
+ s_offRamp.releaseOrMintTokens(sourceTokenAmounts, abi.encode(OWNER), OWNER, SOURCE_CHAIN_SELECTOR_1, new bytes[](1));
+ }
+
+ function test_releaseOrMintTokens_PoolDoesNotSupportDest_Reverts() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ uint256 amount1 = 100;
+ srcTokenAmounts[0].amount = amount1;
+
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ offchainTokenData[0] = abi.encode(0x12345678);
+
+ Internal.RampTokenAmount[] memory sourceTokenAmounts = _getDefaultSourceTokenData(srcTokenAmounts);
+
+ vm.expectCall(
+ s_destPoolBySourceToken[srcTokenAmounts[0].token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ receiver: OWNER,
+ amount: srcTokenAmounts[0].amount,
+ localToken: s_destTokenBySourceToken[srcTokenAmounts[0].token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR_3,
+ sourcePoolAddress: sourceTokenAmounts[0].sourcePoolAddress,
+ sourcePoolData: sourceTokenAmounts[0].extraData,
+ offchainTokenData: offchainTokenData[0]
+ })
+ )
+ );
+ vm.expectRevert();
+ s_offRamp.releaseOrMintTokens(
+ sourceTokenAmounts, abi.encode(OWNER), OWNER, SOURCE_CHAIN_SELECTOR_3, offchainTokenData
+ );
+ }
+
+ /// forge-config: default.fuzz.runs = 32
+ /// forge-config: ccip.fuzz.runs = 1024
+ // Uint256 gives a good range of values to test, both inside and outside of the eth address space.
+ function test_Fuzz__releaseOrMintTokens_AnyRevertIsCaught_Success(uint256 destPool) public {
+ // Input 447301751254033913445893214690834296930546521452, which is 0x4E59B44847B379578588920CA78FBF26C0B4956C
+ // triggers some Create2Deployer and causes it to fail
+ vm.assume(destPool != 447301751254033913445893214690834296930546521452);
+ bytes memory unusedVar = abi.encode(makeAddr("unused"));
+ Internal.RampTokenAmount[] memory sourceTokenAmounts = new Internal.RampTokenAmount[](1);
+ sourceTokenAmounts[0] = Internal.RampTokenAmount({
+ sourcePoolAddress: unusedVar,
+ destTokenAddress: abi.encode(destPool),
+ extraData: unusedVar,
+ amount: 1
+ });
+
+ try s_offRamp.releaseOrMintTokens(
+ sourceTokenAmounts, abi.encode(OWNER), OWNER, SOURCE_CHAIN_SELECTOR_1, new bytes[](1)
+ ) {} catch (bytes memory reason) {
+ // Any revert should be a TokenHandlingError, InvalidEVMAddress, InvalidDataLength or NoContract as those are caught by the offramp
+ assertTrue(
+ bytes4(reason) == EVM2EVMMultiOffRamp.TokenHandlingError.selector
+ || bytes4(reason) == Internal.InvalidEVMAddress.selector
+ || bytes4(reason) == EVM2EVMMultiOffRamp.InvalidDataLength.selector
+ || bytes4(reason) == CallWithExactGas.NoContract.selector
+ || bytes4(reason) == EVM2EVMMultiOffRamp.NotACompatiblePool.selector,
+ "Expected TokenHandlingError or InvalidEVMAddress"
+ );
+
+ if (destPool > type(uint160).max) {
+ assertEq(reason, abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, abi.encode(destPool)));
+ }
+ }
+ }
+}
+
+contract EVM2EVMMultiOffRamp_applySourceChainConfigUpdates is EVM2EVMMultiOffRampSetup {
+ function test_ApplyZeroUpdates_Success() public {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](0);
+
+ vm.recordLogs();
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+
+ // No logs emitted
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 0);
+
+ // assertEq(s_offRamp.getSourceChainSelectors().length, 0);
+ }
+
+ function test_AddNewChain_Success() public {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](1);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: ON_RAMP_ADDRESS_1,
+ isEnabled: true
+ });
+
+ EVM2EVMMultiOffRamp.SourceChainConfig memory expectedSourceChainConfig =
+ EVM2EVMMultiOffRamp.SourceChainConfig({isEnabled: true, minSeqNr: 1, onRamp: ON_RAMP_ADDRESS_1});
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainSelectorAdded(SOURCE_CHAIN_SELECTOR_1);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainConfigSet(SOURCE_CHAIN_SELECTOR_1, expectedSourceChainConfig);
+
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+
+ _assertSourceChainConfigEquality(s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR_1), expectedSourceChainConfig);
+ }
+
+ function test_ReplaceExistingChain_Success() public {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](1);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: ON_RAMP_ADDRESS_1,
+ isEnabled: true
+ });
+
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+
+ sourceChainConfigs[0].isEnabled = false;
+ EVM2EVMMultiOffRamp.SourceChainConfig memory expectedSourceChainConfig =
+ EVM2EVMMultiOffRamp.SourceChainConfig({isEnabled: false, minSeqNr: 1, onRamp: ON_RAMP_ADDRESS_1});
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainConfigSet(SOURCE_CHAIN_SELECTOR_1, expectedSourceChainConfig);
+
+ vm.recordLogs();
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+
+ // No log emitted for chain selector added (only for setting the config)
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 1);
+
+ _assertSourceChainConfigEquality(s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR_1), expectedSourceChainConfig);
+
+ // uint64[] memory resultSourceChainSelectors = s_offRamp.getSourceChainSelectors();
+ // assertEq(resultSourceChainSelectors.length, 1);
+ // assertEq(resultSourceChainSelectors[0], SOURCE_CHAIN_SELECTOR_1);
+ }
+
+ function test_AddMultipleChains_Success() public {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](3);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: abi.encode(ON_RAMP_ADDRESS_1, 0),
+ isEnabled: true
+ });
+ sourceChainConfigs[1] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1 + 1,
+ onRamp: abi.encode(ON_RAMP_ADDRESS_1, 1),
+ isEnabled: false
+ });
+ sourceChainConfigs[2] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1 + 2,
+ onRamp: abi.encode(ON_RAMP_ADDRESS_1, 2),
+ isEnabled: true
+ });
+
+ EVM2EVMMultiOffRamp.SourceChainConfig[] memory expectedSourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfig[](3);
+ for (uint256 i = 0; i < 3; ++i) {
+ expectedSourceChainConfigs[i] = EVM2EVMMultiOffRamp.SourceChainConfig({
+ isEnabled: sourceChainConfigs[i].isEnabled,
+ minSeqNr: 1,
+ onRamp: abi.encode(ON_RAMP_ADDRESS_1, i)
+ });
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainSelectorAdded(sourceChainConfigs[i].sourceChainSelector);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainConfigSet(
+ sourceChainConfigs[i].sourceChainSelector, expectedSourceChainConfigs[i]
+ );
+ }
+
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+
+ for (uint256 i = 0; i < 3; ++i) {
+ _assertSourceChainConfigEquality(
+ s_offRamp.getSourceChainConfig(sourceChainConfigs[i].sourceChainSelector), expectedSourceChainConfigs[i]
+ );
+ }
+ }
+
+ function test_Fuzz_applySourceChainConfigUpdate_Success(
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs memory sourceChainConfigArgs
+ ) public {
+ // Skip invalid inputs
+ vm.assume(sourceChainConfigArgs.sourceChainSelector != 0);
+ vm.assume(sourceChainConfigArgs.onRamp.length != 0);
+
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](2);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: ON_RAMP_ADDRESS_1,
+ isEnabled: true
+ });
+ sourceChainConfigs[1] = sourceChainConfigArgs;
+
+ // Handle cases when an update occurs
+ bool isNewChain = sourceChainConfigs[1].sourceChainSelector != SOURCE_CHAIN_SELECTOR_1;
+ if (!isNewChain) {
+ sourceChainConfigs[1].onRamp = sourceChainConfigs[0].onRamp;
+ }
+
+ EVM2EVMMultiOffRamp.SourceChainConfig memory expectedSourceChainConfig = EVM2EVMMultiOffRamp.SourceChainConfig({
+ isEnabled: sourceChainConfigArgs.isEnabled,
+ minSeqNr: 1,
+ onRamp: sourceChainConfigArgs.onRamp
+ });
+
+ if (isNewChain) {
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainSelectorAdded(sourceChainConfigArgs.sourceChainSelector);
+ }
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.SourceChainConfigSet(sourceChainConfigArgs.sourceChainSelector, expectedSourceChainConfig);
+
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+
+ _assertSourceChainConfigEquality(
+ s_offRamp.getSourceChainConfig(sourceChainConfigArgs.sourceChainSelector), expectedSourceChainConfig
+ );
+ }
+
+ // Reverts
+
+ function test_ZeroOnRampAddress_Revert() public {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](1);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: new bytes(0),
+ isEnabled: true
+ });
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroAddressNotAllowed.selector);
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+ }
+
+ function test_ZeroSourceChainSelector_Revert() public {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](1);
+ sourceChainConfigs[0] =
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs({sourceChainSelector: 0, onRamp: ON_RAMP_ADDRESS_1, isEnabled: true});
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.ZeroChainSelectorNotAllowed.selector);
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+ }
+
+ function test_ReplaceExistingChainOnRamp_Revert() public {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](1);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: ON_RAMP_ADDRESS_1,
+ isEnabled: true
+ });
+
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+
+ sourceChainConfigs[0].onRamp = ON_RAMP_ADDRESS_2;
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.InvalidStaticConfig.selector, SOURCE_CHAIN_SELECTOR_1));
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+ }
+}
+
+contract EVM2EVMMultiOffRamp_commit is EVM2EVMMultiOffRampSetup {
+ uint64 internal s_maxInterval = 12;
+
+ function setUp() public virtual override {
+ super.setUp();
+ _setupMultipleOffRamps();
+
+ s_latestSequenceNumber = uint64(uint256(s_configDigestCommit));
+ }
+
+ function test_ReportAndPriceUpdate_Success() public {
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = _constructCommitReport();
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.CommitReportAccepted(commitReport);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(uint8(Internal.OCRPluginType.Commit), s_configDigestCommit, s_latestSequenceNumber);
+
+ _commit(commitReport, s_latestSequenceNumber);
+
+ assertEq(s_maxInterval + 1, s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR).minSeqNr);
+ assertEq(s_latestSequenceNumber, s_offRamp.getLatestPriceSequenceNumber());
+ }
+
+ function test_ReportOnlyRootSuccess_gas() public {
+ uint64 max1 = 931;
+ bytes32 root = "Only a single root";
+
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: EVM2EVMMultiOffRamp.Interval(1, max1),
+ merkleRoot: root
+ });
+
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.CommitReportAccepted(commitReport);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(uint8(Internal.OCRPluginType.Commit), s_configDigestCommit, s_latestSequenceNumber);
+
+ _commit(commitReport, s_latestSequenceNumber);
+
+ assertEq(max1 + 1, s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR).minSeqNr);
+ assertEq(0, s_offRamp.getLatestPriceSequenceNumber());
+ assertEq(block.timestamp, s_offRamp.getMerkleRoot(SOURCE_CHAIN_SELECTOR_1, root));
+ }
+
+ function test_StaleReportWithRoot_Success() public {
+ uint64 maxSeq = 12;
+ uint224 tokenStartPrice =
+ IPriceRegistry(s_offRamp.getDynamicConfig().priceRegistry).getTokenPrice(s_sourceFeeToken).value;
+
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: EVM2EVMMultiOffRamp.Interval(1, maxSeq),
+ merkleRoot: "stale report 1"
+ });
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.CommitReportAccepted(commitReport);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(uint8(Internal.OCRPluginType.Commit), s_configDigestCommit, s_latestSequenceNumber);
+
+ _commit(commitReport, s_latestSequenceNumber);
+
+ assertEq(maxSeq + 1, s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR).minSeqNr);
+ assertEq(0, s_offRamp.getLatestPriceSequenceNumber());
+
+ commitReport.merkleRoots[0].interval = EVM2EVMMultiOffRamp.Interval(maxSeq + 1, maxSeq * 2);
+ commitReport.merkleRoots[0].merkleRoot = "stale report 2";
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.CommitReportAccepted(commitReport);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(uint8(Internal.OCRPluginType.Commit), s_configDigestCommit, s_latestSequenceNumber);
+
+ _commit(commitReport, s_latestSequenceNumber);
+
+ assertEq(maxSeq * 2 + 1, s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR).minSeqNr);
+ assertEq(0, s_offRamp.getLatestPriceSequenceNumber());
+ assertEq(
+ tokenStartPrice, IPriceRegistry(s_offRamp.getDynamicConfig().priceRegistry).getTokenPrice(s_sourceFeeToken).value
+ );
+ }
+
+ function test_OnlyTokenPriceUpdates_Success() public {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](0);
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = EVM2EVMMultiOffRamp.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ merkleRoots: roots
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, 4e18, block.timestamp);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(uint8(Internal.OCRPluginType.Commit), s_configDigestCommit, s_latestSequenceNumber);
+
+ _commit(commitReport, s_latestSequenceNumber);
+
+ assertEq(s_latestSequenceNumber, s_offRamp.getLatestPriceSequenceNumber());
+ }
+
+ function test_OnlyGasPriceUpdates_Success() public {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](0);
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = EVM2EVMMultiOffRamp.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ merkleRoots: roots
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, 4e18, block.timestamp);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(uint8(Internal.OCRPluginType.Commit), s_configDigestCommit, s_latestSequenceNumber);
+
+ _commit(commitReport, s_latestSequenceNumber);
+ assertEq(s_latestSequenceNumber, s_offRamp.getLatestPriceSequenceNumber());
+ }
+
+ function test_PriceSequenceNumberCleared_Success() public {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](0);
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = EVM2EVMMultiOffRamp.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ merkleRoots: roots
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, 4e18, block.timestamp);
+ _commit(commitReport, s_latestSequenceNumber);
+
+ assertEq(s_latestSequenceNumber, s_offRamp.getLatestPriceSequenceNumber());
+
+ vm.startPrank(OWNER);
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Execution),
+ configDigest: s_configDigestExec,
+ F: s_F,
+ isSignatureVerificationEnabled: false,
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+ s_offRamp.setOCR3Configs(ocrConfigs);
+
+ // Execution plugin OCR config should not clear latest epoch and round
+ assertEq(s_latestSequenceNumber, s_offRamp.getLatestPriceSequenceNumber());
+
+ // Commit plugin config should clear latest epoch & round
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Commit),
+ configDigest: s_configDigestCommit,
+ F: s_F,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+ s_offRamp.setOCR3Configs(ocrConfigs);
+
+ assertEq(0, s_offRamp.getLatestPriceSequenceNumber());
+
+ // The same sequence number can be reported again
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, 4e18, block.timestamp);
+
+ _commit(commitReport, s_latestSequenceNumber);
+ }
+
+ function test_ValidPriceUpdateThenStaleReportWithRoot_Success() public {
+ uint64 maxSeq = 12;
+ uint224 tokenPrice1 = 4e18;
+ uint224 tokenPrice2 = 5e18;
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](0);
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = EVM2EVMMultiOffRamp.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, tokenPrice1),
+ merkleRoots: roots
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, tokenPrice1, block.timestamp);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(uint8(Internal.OCRPluginType.Commit), s_configDigestCommit, s_latestSequenceNumber);
+
+ _commit(commitReport, s_latestSequenceNumber);
+ assertEq(s_latestSequenceNumber, s_offRamp.getLatestPriceSequenceNumber());
+
+ roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: EVM2EVMMultiOffRamp.Interval(1, maxSeq),
+ merkleRoot: "stale report"
+ });
+ commitReport.priceUpdates = getSingleTokenPriceUpdateStruct(s_sourceFeeToken, tokenPrice2);
+ commitReport.merkleRoots = roots;
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOffRamp.CommitReportAccepted(commitReport);
+
+ vm.expectEmit();
+ emit MultiOCR3Base.Transmitted(uint8(Internal.OCRPluginType.Commit), s_configDigestCommit, s_latestSequenceNumber);
+
+ _commit(commitReport, s_latestSequenceNumber);
+
+ assertEq(maxSeq + 1, s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR).minSeqNr);
+ assertEq(
+ tokenPrice1, IPriceRegistry(s_offRamp.getDynamicConfig().priceRegistry).getTokenPrice(s_sourceFeeToken).value
+ );
+ assertEq(s_latestSequenceNumber, s_offRamp.getLatestPriceSequenceNumber());
+ }
+
+ // Reverts
+
+ function test_UnauthorizedTransmitter_Revert() public {
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = _constructCommitReport();
+
+ bytes32[3] memory reportContext =
+ [s_configDigestCommit, bytes32(uint256(s_latestSequenceNumber)), s_configDigestCommit];
+
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, abi.encode(commitReport), reportContext, s_F + 1);
+
+ vm.expectRevert(MultiOCR3Base.UnauthorizedTransmitter.selector);
+ s_offRamp.commit(reportContext, abi.encode(commitReport), rs, ss, rawVs);
+ }
+
+ function test_NoConfig_Revert() public {
+ _redeployOffRampWithNoOCRConfigs();
+
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = _constructCommitReport();
+
+ bytes32[3] memory reportContext = [bytes32(""), s_configDigestCommit, s_configDigestCommit];
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, abi.encode(commitReport), reportContext, s_F + 1);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert();
+ s_offRamp.commit(reportContext, abi.encode(commitReport), rs, ss, rawVs);
+ }
+
+ function test_NoConfigWithOtherConfigPresent_Revert() public {
+ _redeployOffRampWithNoOCRConfigs();
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Execution),
+ configDigest: s_configDigestExec,
+ F: s_F,
+ isSignatureVerificationEnabled: false,
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+ s_offRamp.setOCR3Configs(ocrConfigs);
+
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = _constructCommitReport();
+
+ bytes32[3] memory reportContext = [bytes32(""), s_configDigestCommit, s_configDigestCommit];
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, abi.encode(commitReport), reportContext, s_F + 1);
+
+ vm.startPrank(s_validTransmitters[0]);
+ vm.expectRevert();
+ s_offRamp.commit(reportContext, abi.encode(commitReport), rs, ss, rawVs);
+ }
+
+ function test_WrongConfigWithoutSigners_Revert() public {
+ _redeployOffRampWithNoOCRConfigs();
+
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = _constructCommitReport();
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](1);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Commit),
+ configDigest: s_configDigestCommit,
+ F: s_F,
+ isSignatureVerificationEnabled: false,
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+ s_offRamp.setOCR3Configs(ocrConfigs);
+
+ vm.expectRevert();
+ _commit(commitReport, s_latestSequenceNumber);
+ }
+
+ function test_Unhealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 2),
+ merkleRoot: "Only a single root"
+ });
+
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.CursedByRMN.selector, roots[0].sourceChainSelector));
+ _commit(commitReport, s_latestSequenceNumber);
+ }
+
+ function test_InvalidRootRevert() public {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 4),
+ merkleRoot: bytes32(0)
+ });
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.InvalidRoot.selector);
+ _commit(commitReport, s_latestSequenceNumber);
+ }
+
+ function test_InvalidInterval_Revert() public {
+ EVM2EVMMultiOffRamp.Interval memory interval = EVM2EVMMultiOffRamp.Interval(2, 2);
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: interval,
+ merkleRoot: bytes32(0)
+ });
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ vm.expectRevert(
+ abi.encodeWithSelector(EVM2EVMMultiOffRamp.InvalidInterval.selector, roots[0].sourceChainSelector, interval)
+ );
+ _commit(commitReport, s_latestSequenceNumber);
+ }
+
+ function test_InvalidIntervalMinLargerThanMax_Revert() public {
+ s_offRamp.getSourceChainConfig(SOURCE_CHAIN_SELECTOR);
+ EVM2EVMMultiOffRamp.Interval memory interval = EVM2EVMMultiOffRamp.Interval(1, 0);
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: interval,
+ merkleRoot: bytes32(0)
+ });
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ vm.expectRevert(
+ abi.encodeWithSelector(EVM2EVMMultiOffRamp.InvalidInterval.selector, roots[0].sourceChainSelector, interval)
+ );
+ _commit(commitReport, s_latestSequenceNumber);
+ }
+
+ function test_ZeroEpochAndRound_Revert() public {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](0);
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = EVM2EVMMultiOffRamp.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ merkleRoots: roots
+ });
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.StaleCommitReport.selector);
+ _commit(commitReport, 0);
+ }
+
+ function test_OnlyPriceUpdateStaleReport_Revert() public {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](0);
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport = EVM2EVMMultiOffRamp.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ merkleRoots: roots
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(s_sourceFeeToken, 4e18, block.timestamp);
+ _commit(commitReport, s_latestSequenceNumber);
+
+ vm.expectRevert(EVM2EVMMultiOffRamp.StaleCommitReport.selector);
+ _commit(commitReport, s_latestSequenceNumber);
+ }
+
+ function test_SourceChainNotEnabled_Revert() public {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: 0,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 2),
+ merkleRoot: "Only a single root"
+ });
+
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOffRamp.SourceChainNotEnabled.selector, 0));
+ _commit(commitReport, s_latestSequenceNumber);
+ }
+
+ function test_RootAlreadyCommitted_Revert() public {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 2),
+ merkleRoot: "Only a single root"
+ });
+ EVM2EVMMultiOffRamp.CommitReport memory commitReport =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ _commit(commitReport, s_latestSequenceNumber);
+ commitReport.merkleRoots[0].interval = EVM2EVMMultiOffRamp.Interval(3, 3);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMMultiOffRamp.RootAlreadyCommitted.selector, roots[0].sourceChainSelector, roots[0].merkleRoot
+ )
+ );
+ _commit(commitReport, ++s_latestSequenceNumber);
+ }
+
+ function _constructCommitReport() internal view returns (EVM2EVMMultiOffRamp.CommitReport memory) {
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ interval: EVM2EVMMultiOffRamp.Interval(1, s_maxInterval),
+ merkleRoot: "test #2"
+ });
+
+ return EVM2EVMMultiOffRamp.CommitReport({
+ priceUpdates: getSingleTokenPriceUpdateStruct(s_sourceFeeToken, 4e18),
+ merkleRoots: roots
+ });
+ }
+}
+
+contract EVM2EVMMultiOffRamp_resetUnblessedRoots is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupRealRMN();
+ _deployOffRamp(s_destRouter, s_realRMN, s_inboundNonceManager);
+ _setupMultipleOffRamps();
+ }
+
+ function test_ResetUnblessedRoots_Success() public {
+ EVM2EVMMultiOffRamp.UnblessedRoot[] memory rootsToReset = new EVM2EVMMultiOffRamp.UnblessedRoot[](3);
+ rootsToReset[0] = EVM2EVMMultiOffRamp.UnblessedRoot({sourceChainSelector: SOURCE_CHAIN_SELECTOR, merkleRoot: "1"});
+ rootsToReset[1] = EVM2EVMMultiOffRamp.UnblessedRoot({sourceChainSelector: SOURCE_CHAIN_SELECTOR, merkleRoot: "2"});
+ rootsToReset[2] = EVM2EVMMultiOffRamp.UnblessedRoot({sourceChainSelector: SOURCE_CHAIN_SELECTOR, merkleRoot: "3"});
+
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](3);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 2),
+ merkleRoot: rootsToReset[0].merkleRoot
+ });
+ roots[1] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ interval: EVM2EVMMultiOffRamp.Interval(3, 4),
+ merkleRoot: rootsToReset[1].merkleRoot
+ });
+ roots[2] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ interval: EVM2EVMMultiOffRamp.Interval(5, 5),
+ merkleRoot: rootsToReset[2].merkleRoot
+ });
+
+ EVM2EVMMultiOffRamp.CommitReport memory report =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+
+ _commit(report, ++s_latestSequenceNumber);
+
+ IRMN.TaggedRoot[] memory blessedTaggedRoots = new IRMN.TaggedRoot[](1);
+ blessedTaggedRoots[0] = IRMN.TaggedRoot({commitStore: address(s_offRamp), root: rootsToReset[1].merkleRoot});
+
+ vm.startPrank(BLESS_VOTE_ADDR);
+ s_realRMN.voteToBless(blessedTaggedRoots);
+
+ vm.expectEmit(false, false, false, true);
+ emit EVM2EVMMultiOffRamp.RootRemoved(rootsToReset[0].merkleRoot);
+
+ vm.expectEmit(false, false, false, true);
+ emit EVM2EVMMultiOffRamp.RootRemoved(rootsToReset[2].merkleRoot);
+
+ vm.startPrank(OWNER);
+ s_offRamp.resetUnblessedRoots(rootsToReset);
+
+ assertEq(0, s_offRamp.getMerkleRoot(SOURCE_CHAIN_SELECTOR, rootsToReset[0].merkleRoot));
+ assertEq(BLOCK_TIME, s_offRamp.getMerkleRoot(SOURCE_CHAIN_SELECTOR, rootsToReset[1].merkleRoot));
+ assertEq(0, s_offRamp.getMerkleRoot(SOURCE_CHAIN_SELECTOR, rootsToReset[2].merkleRoot));
+ }
+
+ // Reverts
+
+ function test_OnlyOwner_Revert() public {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ EVM2EVMMultiOffRamp.UnblessedRoot[] memory rootsToReset = new EVM2EVMMultiOffRamp.UnblessedRoot[](0);
+ s_offRamp.resetUnblessedRoots(rootsToReset);
+ }
+}
+
+contract EVM2EVMMultiOffRamp_verify is EVM2EVMMultiOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ _setupRealRMN();
+ _deployOffRamp(s_destRouter, s_realRMN, s_inboundNonceManager);
+ _setupMultipleOffRamps();
+ }
+
+ function test_NotBlessed_Success() public {
+ bytes32[] memory leaves = new bytes32[](1);
+ leaves[0] = "root";
+
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 2),
+ merkleRoot: leaves[0]
+ });
+ EVM2EVMMultiOffRamp.CommitReport memory report =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+ _commit(report, ++s_latestSequenceNumber);
+ bytes32[] memory proofs = new bytes32[](0);
+ // We have not blessed this root, should return 0.
+ uint256 timestamp = s_offRamp.verify(SOURCE_CHAIN_SELECTOR, leaves, proofs, 0);
+ assertEq(uint256(0), timestamp);
+ }
+
+ function test_Blessed_Success() public {
+ bytes32[] memory leaves = new bytes32[](1);
+ leaves[0] = "root";
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 2),
+ merkleRoot: leaves[0]
+ });
+ EVM2EVMMultiOffRamp.CommitReport memory report =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+ _commit(report, ++s_latestSequenceNumber);
+ // Bless that root.
+ IRMN.TaggedRoot[] memory taggedRoots = new IRMN.TaggedRoot[](1);
+ taggedRoots[0] = IRMN.TaggedRoot({commitStore: address(s_offRamp), root: leaves[0]});
+ vm.startPrank(BLESS_VOTE_ADDR);
+ s_realRMN.voteToBless(taggedRoots);
+ bytes32[] memory proofs = new bytes32[](0);
+ uint256 timestamp = s_offRamp.verify(SOURCE_CHAIN_SELECTOR, leaves, proofs, 0);
+ assertEq(BLOCK_TIME, timestamp);
+ }
+
+ function test_NotBlessedWrongChainSelector_Success() public {
+ bytes32[] memory leaves = new bytes32[](1);
+ leaves[0] = "root";
+ EVM2EVMMultiOffRamp.MerkleRoot[] memory roots = new EVM2EVMMultiOffRamp.MerkleRoot[](1);
+ roots[0] = EVM2EVMMultiOffRamp.MerkleRoot({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ interval: EVM2EVMMultiOffRamp.Interval(1, 2),
+ merkleRoot: leaves[0]
+ });
+
+ EVM2EVMMultiOffRamp.CommitReport memory report =
+ EVM2EVMMultiOffRamp.CommitReport({priceUpdates: getEmptyPriceUpdates(), merkleRoots: roots});
+ _commit(report, ++s_latestSequenceNumber);
+
+ // Bless that root.
+ IRMN.TaggedRoot[] memory taggedRoots = new IRMN.TaggedRoot[](1);
+ taggedRoots[0] = IRMN.TaggedRoot({commitStore: address(s_offRamp), root: leaves[0]});
+ vm.startPrank(BLESS_VOTE_ADDR);
+ s_realRMN.voteToBless(taggedRoots);
+
+ bytes32[] memory proofs = new bytes32[](0);
+ uint256 timestamp = s_offRamp.verify(SOURCE_CHAIN_SELECTOR + 1, leaves, proofs, 0);
+ assertEq(uint256(0), timestamp);
+ }
+
+ // Reverts
+
+ function test_TooManyLeaves_Revert() public {
+ bytes32[] memory leaves = new bytes32[](258);
+ bytes32[] memory proofs = new bytes32[](0);
+ vm.expectRevert(MerkleMultiProof.InvalidProof.selector);
+ s_offRamp.verify(SOURCE_CHAIN_SELECTOR, leaves, proofs, 0);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRampSetup.t.sol b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRampSetup.t.sol
new file mode 100644
index 00000000000..507e966a70a
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMMultiOffRampSetup.t.sol
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IAny2EVMMessageReceiver} from "../../interfaces/IAny2EVMMessageReceiver.sol";
+
+import {IAny2EVMOffRamp} from "../../interfaces/IAny2EVMOffRamp.sol";
+import {ICommitStore} from "../../interfaces/ICommitStore.sol";
+import {IRMN} from "../../interfaces/IRMN.sol";
+
+import {AuthorizedCallers} from "../../../shared/access/AuthorizedCallers.sol";
+import {NonceManager} from "../../NonceManager.sol";
+import {RMN} from "../../RMN.sol";
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {MultiOCR3Base} from "../../ocr/MultiOCR3Base.sol";
+import {EVM2EVMMultiOffRamp} from "../../offRamp/EVM2EVMMultiOffRamp.sol";
+import {EVM2EVMOffRamp} from "../../offRamp/EVM2EVMOffRamp.sol";
+import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {TokenSetup} from "../TokenSetup.t.sol";
+import {EVM2EVMMultiOffRampHelper} from "../helpers/EVM2EVMMultiOffRampHelper.sol";
+import {EVM2EVMOffRampHelper} from "../helpers/EVM2EVMOffRampHelper.sol";
+import {MaybeRevertingBurnMintTokenPool} from "../helpers/MaybeRevertingBurnMintTokenPool.sol";
+import {MessageInterceptorHelper} from "../helpers/MessageInterceptorHelper.sol";
+import {MaybeRevertMessageReceiver} from "../helpers/receivers/MaybeRevertMessageReceiver.sol";
+import {MockCommitStore} from "../mocks/MockCommitStore.sol";
+import {MultiOCR3BaseSetup} from "../ocr/MultiOCR3BaseSetup.t.sol";
+import {PriceRegistrySetup} from "../priceRegistry/PriceRegistry.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract EVM2EVMMultiOffRampSetup is TokenSetup, PriceRegistrySetup, MultiOCR3BaseSetup {
+ uint64 internal constant SOURCE_CHAIN_SELECTOR_1 = SOURCE_CHAIN_SELECTOR;
+ uint64 internal constant SOURCE_CHAIN_SELECTOR_2 = 6433500567565415381;
+ uint64 internal constant SOURCE_CHAIN_SELECTOR_3 = 4051577828743386545;
+
+ bytes internal constant ON_RAMP_ADDRESS_1 = abi.encode(ON_RAMP_ADDRESS);
+ bytes internal constant ON_RAMP_ADDRESS_2 = abi.encode(0xaA3f843Cf8E33B1F02dd28303b6bD87B1aBF8AE4);
+ bytes internal constant ON_RAMP_ADDRESS_3 = abi.encode(0x71830C37Cb193e820de488Da111cfbFcC680a1b9);
+
+ address internal constant BLESS_VOTE_ADDR = address(8888);
+
+ IAny2EVMMessageReceiver internal s_receiver;
+ IAny2EVMMessageReceiver internal s_secondary_receiver;
+ MaybeRevertMessageReceiver internal s_reverting_receiver;
+
+ MaybeRevertingBurnMintTokenPool internal s_maybeRevertingPool;
+
+ EVM2EVMMultiOffRampHelper internal s_offRamp;
+ MessageInterceptorHelper internal s_inboundMessageValidator;
+ NonceManager internal s_inboundNonceManager;
+ RMN internal s_realRMN;
+ address internal s_sourceTokenPool = makeAddr("sourceTokenPool");
+
+ bytes32 internal s_configDigestExec;
+ bytes32 internal s_configDigestCommit;
+ uint64 internal constant s_offchainConfigVersion = 3;
+ uint8 internal constant s_F = 1;
+
+ uint64 internal s_latestSequenceNumber;
+
+ function setUp() public virtual override(TokenSetup, PriceRegistrySetup, MultiOCR3BaseSetup) {
+ TokenSetup.setUp();
+ PriceRegistrySetup.setUp();
+ MultiOCR3BaseSetup.setUp();
+
+ s_inboundMessageValidator = new MessageInterceptorHelper();
+ s_receiver = new MaybeRevertMessageReceiver(false);
+ s_secondary_receiver = new MaybeRevertMessageReceiver(false);
+ s_reverting_receiver = new MaybeRevertMessageReceiver(true);
+
+ s_maybeRevertingPool = MaybeRevertingBurnMintTokenPool(s_destPoolByToken[s_destTokens[1]]);
+ s_inboundNonceManager = new NonceManager(new address[](0));
+
+ _deployOffRamp(s_destRouter, s_mockRMN, s_inboundNonceManager);
+ }
+
+ function _deployOffRamp(Router router, IRMN rmnProxy, NonceManager nonceManager) internal {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](0);
+
+ s_offRamp = new EVM2EVMMultiOffRampHelper(
+ EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ rmnProxy: address(rmnProxy),
+ tokenAdminRegistry: address(s_tokenAdminRegistry),
+ nonceManager: address(nonceManager)
+ }),
+ _generateDynamicMultiOffRampConfig(address(router), address(s_priceRegistry)),
+ sourceChainConfigs
+ );
+
+ s_configDigestExec = _getBasicConfigDigest(s_F, s_emptySigners, s_validTransmitters);
+ s_configDigestCommit = _getBasicConfigDigest(s_F, s_validSigners, s_validTransmitters);
+
+ MultiOCR3Base.OCRConfigArgs[] memory ocrConfigs = new MultiOCR3Base.OCRConfigArgs[](2);
+ ocrConfigs[0] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Execution),
+ configDigest: s_configDigestExec,
+ F: s_F,
+ isSignatureVerificationEnabled: false,
+ signers: s_emptySigners,
+ transmitters: s_validTransmitters
+ });
+ ocrConfigs[1] = MultiOCR3Base.OCRConfigArgs({
+ ocrPluginType: uint8(Internal.OCRPluginType.Commit),
+ configDigest: s_configDigestCommit,
+ F: s_F,
+ isSignatureVerificationEnabled: true,
+ signers: s_validSigners,
+ transmitters: s_validTransmitters
+ });
+
+ s_offRamp.setDynamicConfig(_generateDynamicMultiOffRampConfig(address(router), address(s_priceRegistry)));
+ s_offRamp.setOCR3Configs(ocrConfigs);
+
+ address[] memory authorizedCallers = new address[](1);
+ authorizedCallers[0] = address(s_offRamp);
+ NonceManager(nonceManager).applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: authorizedCallers, removedCallers: new address[](0)})
+ );
+
+ address[] memory priceUpdaters = new address[](1);
+ priceUpdaters[0] = address(s_offRamp);
+ s_priceRegistry.applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: priceUpdaters, removedCallers: new address[](0)})
+ );
+ }
+
+ // TODO: function can be made common across OffRampSetup and MultiOffRampSetup
+ function _deploySingleLaneOffRamp(
+ ICommitStore commitStore,
+ Router router,
+ address prevOffRamp,
+ uint64 sourceChainSelector,
+ address onRampAddress
+ ) internal returns (EVM2EVMOffRampHelper) {
+ EVM2EVMOffRampHelper offRamp = new EVM2EVMOffRampHelper(
+ EVM2EVMOffRamp.StaticConfig({
+ commitStore: address(commitStore),
+ chainSelector: DEST_CHAIN_SELECTOR,
+ sourceChainSelector: sourceChainSelector,
+ onRamp: onRampAddress,
+ prevOffRamp: prevOffRamp,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ getInboundRateLimiterConfig()
+ );
+ offRamp.setOCR2Config(
+ s_validSigners,
+ s_validTransmitters,
+ s_F,
+ abi.encode(_generateDynamicOffRampConfig(address(router), address(s_priceRegistry))),
+ s_offchainConfigVersion,
+ abi.encode("")
+ );
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](0);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](2);
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: sourceChainSelector, offRamp: address(s_offRamp)});
+ offRampUpdates[1] = Router.OffRamp({sourceChainSelector: sourceChainSelector, offRamp: address(prevOffRamp)});
+ s_destRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+ EVM2EVMOffRamp.RateLimitToken[] memory tokensToAdd = new EVM2EVMOffRamp.RateLimitToken[](s_sourceTokens.length);
+ for (uint256 i = 0; i < s_sourceTokens.length; ++i) {
+ tokensToAdd[i] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceTokens[i], destToken: s_destTokens[i]});
+ }
+ offRamp.updateRateLimitTokens(new EVM2EVMOffRamp.RateLimitToken[](0), tokensToAdd);
+
+ return offRamp;
+ }
+
+ function _setupMultipleOffRamps() internal {
+ EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs =
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](3);
+ sourceChainConfigs[0] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_1,
+ onRamp: ON_RAMP_ADDRESS_1,
+ isEnabled: true
+ });
+ sourceChainConfigs[1] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_2,
+ onRamp: ON_RAMP_ADDRESS_2,
+ isEnabled: false
+ });
+ sourceChainConfigs[2] = EVM2EVMMultiOffRamp.SourceChainConfigArgs({
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR_3,
+ onRamp: ON_RAMP_ADDRESS_3,
+ isEnabled: true
+ });
+ _setupMultipleOffRampsFromConfigs(sourceChainConfigs);
+ }
+
+ function _setupMultipleOffRampsFromConfigs(EVM2EVMMultiOffRamp.SourceChainConfigArgs[] memory sourceChainConfigs)
+ internal
+ {
+ s_offRamp.applySourceChainConfigUpdates(sourceChainConfigs);
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](0);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](2 * sourceChainConfigs.length);
+
+ for (uint256 i = 0; i < sourceChainConfigs.length; ++i) {
+ uint64 sourceChainSelector = sourceChainConfigs[i].sourceChainSelector;
+
+ offRampUpdates[2 * i] = Router.OffRamp({sourceChainSelector: sourceChainSelector, offRamp: address(s_offRamp)});
+ offRampUpdates[2 * i + 1] = Router.OffRamp({
+ sourceChainSelector: sourceChainSelector,
+ offRamp: s_inboundNonceManager.getPreviousRamps(sourceChainSelector).prevOffRamp
+ });
+ }
+
+ s_destRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+ }
+
+ function _generateDynamicOffRampConfig(
+ address router,
+ address priceRegistry
+ ) internal pure returns (EVM2EVMOffRamp.DynamicConfig memory) {
+ return EVM2EVMOffRamp.DynamicConfig({
+ permissionLessExecutionThresholdSeconds: PERMISSION_LESS_EXECUTION_THRESHOLD_SECONDS,
+ router: router,
+ priceRegistry: priceRegistry,
+ maxNumberOfTokensPerMsg: MAX_TOKENS_LENGTH,
+ maxDataBytes: MAX_DATA_SIZE,
+ maxPoolReleaseOrMintGas: MAX_TOKEN_POOL_RELEASE_OR_MINT_GAS,
+ maxTokenTransferGas: MAX_TOKEN_POOL_TRANSFER_GAS
+ });
+ }
+
+ function _generateDynamicMultiOffRampConfig(
+ address router,
+ address priceRegistry
+ ) internal pure returns (EVM2EVMMultiOffRamp.DynamicConfig memory) {
+ return EVM2EVMMultiOffRamp.DynamicConfig({
+ permissionLessExecutionThresholdSeconds: PERMISSION_LESS_EXECUTION_THRESHOLD_SECONDS,
+ router: router,
+ priceRegistry: priceRegistry,
+ messageValidator: address(0),
+ maxPoolReleaseOrMintGas: MAX_TOKEN_POOL_RELEASE_OR_MINT_GAS,
+ maxTokenTransferGas: MAX_TOKEN_POOL_TRANSFER_GAS
+ });
+ }
+
+ function _convertToGeneralMessage(Internal.Any2EVMRampMessage memory original)
+ internal
+ view
+ returns (Client.Any2EVMMessage memory message)
+ {
+ uint256 numberOfTokens = original.tokenAmounts.length;
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](numberOfTokens);
+
+ for (uint256 i = 0; i < numberOfTokens; ++i) {
+ Internal.RampTokenAmount memory tokenAmount = original.tokenAmounts[i];
+
+ address destPoolAddress = abi.decode(tokenAmount.destTokenAddress, (address));
+ TokenPool pool = TokenPool(destPoolAddress);
+ destTokenAmounts[i].token = address(pool.getToken());
+ destTokenAmounts[i].amount = tokenAmount.amount;
+ }
+
+ return Client.Any2EVMMessage({
+ messageId: original.header.messageId,
+ sourceChainSelector: original.header.sourceChainSelector,
+ sender: abi.encode(original.sender),
+ data: original.data,
+ destTokenAmounts: destTokenAmounts
+ });
+ }
+
+ function _generateAny2EVMMessageNoTokens(
+ uint64 sourceChainSelector,
+ bytes memory onRamp,
+ uint64 sequenceNumber
+ ) internal view returns (Internal.Any2EVMRampMessage memory) {
+ return _generateAny2EVMMessage(sourceChainSelector, onRamp, sequenceNumber, new Client.EVMTokenAmount[](0), false);
+ }
+
+ function _generateAny2EVMMessageWithTokens(
+ uint64 sourceChainSelector,
+ bytes memory onRamp,
+ uint64 sequenceNumber,
+ uint256[] memory amounts
+ ) internal view returns (Internal.Any2EVMRampMessage memory) {
+ Client.EVMTokenAmount[] memory tokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ for (uint256 i = 0; i < tokenAmounts.length; ++i) {
+ tokenAmounts[i].amount = amounts[i];
+ }
+ return _generateAny2EVMMessage(sourceChainSelector, onRamp, sequenceNumber, tokenAmounts, false);
+ }
+
+ function _generateAny2EVMMessage(
+ uint64 sourceChainSelector,
+ bytes memory onRamp,
+ uint64 sequenceNumber,
+ Client.EVMTokenAmount[] memory tokenAmounts,
+ bool allowOutOfOrderExecution
+ ) internal view returns (Internal.Any2EVMRampMessage memory) {
+ bytes memory data = abi.encode(0);
+
+ Internal.RampTokenAmount[] memory rampTokenAmounts = new Internal.RampTokenAmount[](tokenAmounts.length);
+
+ // Correctly set the TokenDataPayload for each token. Tokens have to be set up in the TokenSetup.
+ for (uint256 i = 0; i < tokenAmounts.length; ++i) {
+ rampTokenAmounts[i] = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[tokenAmounts[i].token]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[tokenAmounts[i].token]),
+ extraData: "",
+ amount: tokenAmounts[i].amount
+ });
+ }
+
+ Internal.Any2EVMRampMessage memory message = Internal.Any2EVMRampMessage({
+ header: Internal.RampMessageHeader({
+ messageId: "",
+ sourceChainSelector: sourceChainSelector,
+ destChainSelector: DEST_CHAIN_SELECTOR,
+ sequenceNumber: sequenceNumber,
+ nonce: allowOutOfOrderExecution ? 0 : sequenceNumber
+ }),
+ sender: abi.encode(OWNER),
+ data: data,
+ receiver: address(s_receiver),
+ tokenAmounts: rampTokenAmounts,
+ gasLimit: GAS_LIMIT
+ });
+
+ message.header.messageId = Internal._hash(message, onRamp);
+
+ return message;
+ }
+
+ function _generateSingleBasicMessage(
+ uint64 sourceChainSelector,
+ bytes memory onRamp
+ ) internal view returns (Internal.Any2EVMRampMessage[] memory) {
+ Internal.Any2EVMRampMessage[] memory messages = new Internal.Any2EVMRampMessage[](1);
+ messages[0] = _generateAny2EVMMessageNoTokens(sourceChainSelector, onRamp, 1);
+ return messages;
+ }
+
+ function _generateMessagesWithTokens(
+ uint64 sourceChainSelector,
+ bytes memory onRamp
+ ) internal view returns (Internal.Any2EVMRampMessage[] memory) {
+ Internal.Any2EVMRampMessage[] memory messages = new Internal.Any2EVMRampMessage[](2);
+ Client.EVMTokenAmount[] memory tokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ tokenAmounts[0].amount = 1e18;
+ tokenAmounts[1].amount = 5e18;
+ messages[0] = _generateAny2EVMMessage(sourceChainSelector, onRamp, 1, tokenAmounts, false);
+ messages[1] = _generateAny2EVMMessage(sourceChainSelector, onRamp, 2, tokenAmounts, false);
+
+ return messages;
+ }
+
+ function _generateReportFromMessages(
+ uint64 sourceChainSelector,
+ Internal.Any2EVMRampMessage[] memory messages
+ ) internal pure returns (Internal.ExecutionReportSingleChain memory) {
+ bytes[][] memory offchainTokenData = new bytes[][](messages.length);
+
+ for (uint256 i = 0; i < messages.length; ++i) {
+ offchainTokenData[i] = new bytes[](messages[i].tokenAmounts.length);
+ }
+
+ return Internal.ExecutionReportSingleChain({
+ sourceChainSelector: sourceChainSelector,
+ proofs: new bytes32[](0),
+ proofFlagBits: 2 ** 256 - 1,
+ messages: messages,
+ offchainTokenData: offchainTokenData
+ });
+ }
+
+ function _generateBatchReportFromMessages(
+ uint64 sourceChainSelector,
+ Internal.Any2EVMRampMessage[] memory messages
+ ) internal pure returns (Internal.ExecutionReportSingleChain[] memory) {
+ Internal.ExecutionReportSingleChain[] memory reports = new Internal.ExecutionReportSingleChain[](1);
+ reports[0] = _generateReportFromMessages(sourceChainSelector, messages);
+ return reports;
+ }
+
+ function _getGasLimitsFromMessages(Internal.Any2EVMRampMessage[] memory messages)
+ internal
+ pure
+ returns (uint256[] memory)
+ {
+ uint256[] memory gasLimits = new uint256[](messages.length);
+ for (uint256 i = 0; i < messages.length; ++i) {
+ gasLimits[i] = messages[i].gasLimit;
+ }
+
+ return gasLimits;
+ }
+
+ function _assertSameConfig(
+ EVM2EVMMultiOffRamp.DynamicConfig memory a,
+ EVM2EVMMultiOffRamp.DynamicConfig memory b
+ ) public pure {
+ assertEq(a.permissionLessExecutionThresholdSeconds, b.permissionLessExecutionThresholdSeconds);
+ assertEq(a.router, b.router);
+ assertEq(a.maxPoolReleaseOrMintGas, b.maxPoolReleaseOrMintGas);
+ assertEq(a.maxTokenTransferGas, b.maxTokenTransferGas);
+ assertEq(a.messageValidator, b.messageValidator);
+ assertEq(a.priceRegistry, b.priceRegistry);
+ }
+
+ function _assertSourceChainConfigEquality(
+ EVM2EVMMultiOffRamp.SourceChainConfig memory config1,
+ EVM2EVMMultiOffRamp.SourceChainConfig memory config2
+ ) internal pure {
+ assertEq(config1.isEnabled, config2.isEnabled);
+ assertEq(config1.minSeqNr, config2.minSeqNr);
+ assertEq(config1.onRamp, config2.onRamp);
+ }
+
+ function _getDefaultSourceTokenData(Client.EVMTokenAmount[] memory srcTokenAmounts)
+ internal
+ view
+ returns (Internal.RampTokenAmount[] memory)
+ {
+ Internal.RampTokenAmount[] memory sourceTokenData = new Internal.RampTokenAmount[](srcTokenAmounts.length);
+ for (uint256 i = 0; i < srcTokenAmounts.length; ++i) {
+ sourceTokenData[i] = Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[srcTokenAmounts[i].token]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[srcTokenAmounts[i].token]),
+ extraData: "",
+ amount: srcTokenAmounts[i].amount
+ });
+ }
+ return sourceTokenData;
+ }
+
+ function _enableInboundMessageValidator() internal {
+ EVM2EVMMultiOffRamp.DynamicConfig memory dynamicConfig = s_offRamp.getDynamicConfig();
+ dynamicConfig.messageValidator = address(s_inboundMessageValidator);
+ s_offRamp.setDynamicConfig(dynamicConfig);
+ }
+
+ function _redeployOffRampWithNoOCRConfigs() internal {
+ s_offRamp = new EVM2EVMMultiOffRampHelper(
+ EVM2EVMMultiOffRamp.StaticConfig({
+ chainSelector: DEST_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry),
+ nonceManager: address(s_inboundNonceManager)
+ }),
+ _generateDynamicMultiOffRampConfig(address(s_destRouter), address(s_priceRegistry)),
+ new EVM2EVMMultiOffRamp.SourceChainConfigArgs[](0)
+ );
+
+ address[] memory authorizedCallers = new address[](1);
+ authorizedCallers[0] = address(s_offRamp);
+ s_inboundNonceManager.applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: authorizedCallers, removedCallers: new address[](0)})
+ );
+ _setupMultipleOffRamps();
+
+ address[] memory priceUpdaters = new address[](1);
+ priceUpdaters[0] = address(s_offRamp);
+ s_priceRegistry.applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: priceUpdaters, removedCallers: new address[](0)})
+ );
+ }
+
+ function _setupRealRMN() internal {
+ RMN.Voter[] memory voters = new RMN.Voter[](1);
+ voters[0] =
+ RMN.Voter({blessVoteAddr: BLESS_VOTE_ADDR, curseVoteAddr: address(9999), blessWeight: 1, curseWeight: 1});
+ // Overwrite base mock rmn with real.
+ s_realRMN = new RMN(RMN.Config({voters: voters, blessWeightThreshold: 1, curseWeightThreshold: 1}));
+ }
+
+ function _commit(EVM2EVMMultiOffRamp.CommitReport memory commitReport, uint64 sequenceNumber) internal {
+ bytes32[3] memory reportContext = [s_configDigestCommit, bytes32(uint256(sequenceNumber)), s_configDigestCommit];
+
+ (bytes32[] memory rs, bytes32[] memory ss,, bytes32 rawVs) =
+ _getSignaturesForDigest(s_validSignerKeys, abi.encode(commitReport), reportContext, s_F + 1);
+
+ vm.startPrank(s_validTransmitters[0]);
+ s_offRamp.commit(reportContext, abi.encode(commitReport), rs, ss, rawVs);
+ }
+
+ function _execute(Internal.ExecutionReportSingleChain[] memory reports) internal {
+ bytes32[3] memory reportContext = [s_configDigestExec, s_configDigestExec, s_configDigestExec];
+
+ vm.startPrank(s_validTransmitters[0]);
+ s_offRamp.execute(reportContext, abi.encode(reports));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRamp.t.sol b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRamp.t.sol
new file mode 100644
index 00000000000..e94184e3c5e
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRamp.t.sol
@@ -0,0 +1,1986 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ICommitStore} from "../../interfaces/ICommitStore.sol";
+import {IPoolV1} from "../../interfaces/IPool.sol";
+import {ITokenAdminRegistry} from "../../interfaces/ITokenAdminRegistry.sol";
+
+import {CallWithExactGas} from "../../../shared/call/CallWithExactGas.sol";
+
+import {GenericReceiver} from "../../../shared/test/testhelpers/GenericReceiver.sol";
+import {AggregateRateLimiter} from "../../AggregateRateLimiter.sol";
+import {RMN} from "../../RMN.sol";
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {OCR2Abstract} from "../../ocr/OCR2Abstract.sol";
+import {EVM2EVMOffRamp} from "../../offRamp/EVM2EVMOffRamp.sol";
+import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {EVM2EVMOffRampHelper} from "../helpers/EVM2EVMOffRampHelper.sol";
+import {MaybeRevertingBurnMintTokenPool} from "../helpers/MaybeRevertingBurnMintTokenPool.sol";
+import {ConformingReceiver} from "../helpers/receivers/ConformingReceiver.sol";
+import {MaybeRevertMessageReceiver} from "../helpers/receivers/MaybeRevertMessageReceiver.sol";
+import {MaybeRevertMessageReceiverNo165} from "../helpers/receivers/MaybeRevertMessageReceiverNo165.sol";
+import {ReentrancyAbuser} from "../helpers/receivers/ReentrancyAbuser.sol";
+import {MockCommitStore} from "../mocks/MockCommitStore.sol";
+import {OCR2Base} from "../ocr/OCR2Base.t.sol";
+import {OCR2BaseNoChecks} from "../ocr/OCR2BaseNoChecks.t.sol";
+import {EVM2EVMOffRampSetup} from "./EVM2EVMOffRampSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract EVM2EVMOffRamp_constructor is EVM2EVMOffRampSetup {
+ function test_Constructor_Success() public {
+ EVM2EVMOffRamp.StaticConfig memory staticConfig = EVM2EVMOffRamp.StaticConfig({
+ commitStore: address(s_mockCommitStore),
+ chainSelector: DEST_CHAIN_SELECTOR,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ onRamp: ON_RAMP_ADDRESS,
+ prevOffRamp: address(0),
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ });
+ EVM2EVMOffRamp.DynamicConfig memory dynamicConfig =
+ generateDynamicOffRampConfig(address(s_destRouter), address(s_priceRegistry));
+
+ s_offRamp = new EVM2EVMOffRampHelper(staticConfig, getInboundRateLimiterConfig());
+
+ s_offRamp.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+
+ // Static config
+ EVM2EVMOffRamp.StaticConfig memory gotStaticConfig = s_offRamp.getStaticConfig();
+ assertEq(staticConfig.commitStore, gotStaticConfig.commitStore);
+ assertEq(staticConfig.sourceChainSelector, gotStaticConfig.sourceChainSelector);
+ assertEq(staticConfig.chainSelector, gotStaticConfig.chainSelector);
+ assertEq(staticConfig.onRamp, gotStaticConfig.onRamp);
+ assertEq(staticConfig.prevOffRamp, gotStaticConfig.prevOffRamp);
+ assertEq(staticConfig.tokenAdminRegistry, gotStaticConfig.tokenAdminRegistry);
+
+ // Dynamic config
+ EVM2EVMOffRamp.DynamicConfig memory gotDynamicConfig = s_offRamp.getDynamicConfig();
+ _assertSameConfig(dynamicConfig, gotDynamicConfig);
+
+ (uint32 configCount, uint32 blockNumber,) = s_offRamp.latestConfigDetails();
+ assertEq(1, configCount);
+ assertEq(block.number, blockNumber);
+
+ // OffRamp initial values
+ assertEq("EVM2EVMOffRamp 1.5.0-dev", s_offRamp.typeAndVersion());
+ assertEq(OWNER, s_offRamp.owner());
+ }
+
+ // Revert
+ function test_ZeroOnRampAddress_Revert() public {
+ vm.expectRevert(EVM2EVMOffRamp.ZeroAddressNotAllowed.selector);
+
+ s_offRamp = new EVM2EVMOffRampHelper(
+ EVM2EVMOffRamp.StaticConfig({
+ commitStore: address(s_mockCommitStore),
+ chainSelector: DEST_CHAIN_SELECTOR,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ onRamp: ZERO_ADDRESS,
+ prevOffRamp: address(0),
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ RateLimiter.Config({isEnabled: true, rate: 1e20, capacity: 1e20})
+ );
+ }
+
+ function test_CommitStoreAlreadyInUse_Revert() public {
+ s_mockCommitStore.setExpectedNextSequenceNumber(2);
+
+ vm.expectRevert(EVM2EVMOffRamp.CommitStoreAlreadyInUse.selector);
+
+ s_offRamp = new EVM2EVMOffRampHelper(
+ EVM2EVMOffRamp.StaticConfig({
+ commitStore: address(s_mockCommitStore),
+ chainSelector: DEST_CHAIN_SELECTOR,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ onRamp: ON_RAMP_ADDRESS,
+ prevOffRamp: address(0),
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ getInboundRateLimiterConfig()
+ );
+ }
+}
+
+contract EVM2EVMOffRamp_setDynamicConfig is EVM2EVMOffRampSetup {
+ function test_SetDynamicConfig_Success() public {
+ EVM2EVMOffRamp.StaticConfig memory staticConfig = s_offRamp.getStaticConfig();
+ EVM2EVMOffRamp.DynamicConfig memory dynamicConfig = generateDynamicOffRampConfig(USER_3, address(s_priceRegistry));
+ bytes memory onchainConfig = abi.encode(dynamicConfig);
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ConfigSet(staticConfig, dynamicConfig);
+
+ vm.expectEmit();
+ uint32 configCount = 1;
+ emit OCR2Abstract.ConfigSet(
+ uint32(block.number),
+ getBasicConfigDigest(address(s_offRamp), s_f, configCount, onchainConfig),
+ configCount + 1,
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ onchainConfig,
+ s_offchainConfigVersion,
+ abi.encode("")
+ );
+
+ s_offRamp.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, onchainConfig, s_offchainConfigVersion, abi.encode("")
+ );
+
+ EVM2EVMOffRamp.DynamicConfig memory newConfig = s_offRamp.getDynamicConfig();
+ _assertSameConfig(dynamicConfig, newConfig);
+ }
+
+ function test_NonOwner_Revert() public {
+ vm.startPrank(STRANGER);
+ EVM2EVMOffRamp.DynamicConfig memory dynamicConfig = generateDynamicOffRampConfig(USER_3, address(s_priceRegistry));
+
+ vm.expectRevert("Only callable by owner");
+
+ s_offRamp.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+ }
+
+ function test_RouterZeroAddress_Revert() public {
+ EVM2EVMOffRamp.DynamicConfig memory dynamicConfig = generateDynamicOffRampConfig(ZERO_ADDRESS, ZERO_ADDRESS);
+
+ vm.expectRevert(EVM2EVMOffRamp.ZeroAddressNotAllowed.selector);
+
+ s_offRamp.setOCR2Config(
+ s_valid_signers, s_valid_transmitters, s_f, abi.encode(dynamicConfig), s_offchainConfigVersion, abi.encode("")
+ );
+ }
+}
+
+contract EVM2EVMOffRamp_metadataHash is EVM2EVMOffRampSetup {
+ function test_MetadataHash_Success() public view {
+ bytes32 h = s_offRamp.metadataHash();
+ assertEq(
+ h,
+ keccak256(
+ abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, ON_RAMP_ADDRESS)
+ )
+ );
+ }
+}
+
+contract EVM2EVMOffRamp_ccipReceive is EVM2EVMOffRampSetup {
+ // Reverts
+
+ function test_Reverts() public {
+ Client.Any2EVMMessage memory message = _convertToGeneralMessage(_generateAny2EVMMessageNoTokens(1));
+ vm.expectRevert();
+ s_offRamp.ccipReceive(message);
+ }
+}
+
+contract EVM2EVMOffRamp_execute is EVM2EVMOffRampSetup {
+ error PausedError();
+
+ function _generateMsgWithoutTokens(
+ uint256 gasLimit,
+ bytes memory messageData
+ ) internal view returns (Internal.EVM2EVMMessage memory) {
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageNoTokens(1);
+ message.gasLimit = gasLimit;
+ message.data = messageData;
+ message.messageId = Internal._hash(
+ message,
+ keccak256(
+ abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, ON_RAMP_ADDRESS)
+ )
+ );
+ return message;
+ }
+
+ function test_Fuzz_trialExecuteWithoutTokens_Success(bytes4 funcSelector, bytes memory messageData) public {
+ vm.assume(
+ funcSelector != GenericReceiver.setRevert.selector && funcSelector != GenericReceiver.setErr.selector
+ && funcSelector != 0x5100fc21 && funcSelector != 0x00000000 // s_toRevert(), which is public and therefore has a function selector
+ );
+
+ // Convert bytes4 into bytes memory to use in the message
+ Internal.EVM2EVMMessage memory message = _generateMsgWithoutTokens(GAS_LIMIT, messageData);
+
+ // Convert an Internal.EVM2EVMMessage into a Client.Any2EVMMessage digestable by the client
+ Client.Any2EVMMessage memory receivedMessage = _convertToGeneralMessage(message);
+ bytes memory expectedCallData =
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.ccipReceive.selector, receivedMessage);
+
+ vm.expectCall(address(s_receiver), expectedCallData);
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+ assertEq(uint256(Internal.MessageExecutionState.SUCCESS), uint256(newState));
+ assertEq("", err);
+ }
+
+ function test_Fuzz_trialExecuteWithTokens_Success(uint16 tokenAmount, bytes calldata messageData) public {
+ vm.assume(tokenAmount != 0);
+
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = uint256(tokenAmount);
+ amounts[1] = uint256(tokenAmount);
+
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageWithTokens(1, amounts);
+ // console.log(message.length);
+ message.data = messageData;
+
+ IERC20 dstToken0 = IERC20(s_destTokens[0]);
+ uint256 startingBalance = dstToken0.balanceOf(message.receiver);
+
+ vm.expectCall(s_destTokens[0], abi.encodeWithSelector(IERC20.transfer.selector, address(s_receiver), amounts[0]));
+
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+ assertEq(uint256(Internal.MessageExecutionState.SUCCESS), uint256(newState));
+ assertEq("", err);
+
+ // Check that the tokens were transferred
+ assertEq(startingBalance + amounts[0], dstToken0.balanceOf(message.receiver));
+ }
+
+ function test_Fuzz_getSenderNonce(uint8 trialExecutions) public {
+ vm.assume(trialExecutions > 1);
+
+ Internal.EVM2EVMMessage[] memory messages;
+
+ if (trialExecutions == 1) {
+ messages = new Internal.EVM2EVMMessage[](1);
+ messages[0] = _generateAny2EVMMessageNoTokens(0);
+ } else {
+ messages = _generateSingleBasicMessage();
+ }
+
+ // Fuzz the number of calls from the sender to ensure that getSenderNonce works
+ for (uint256 i = 1; i < trialExecutions; ++i) {
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ messages[0].nonce++;
+ messages[0].sequenceNumber++;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+ }
+
+ messages[0].nonce = 0;
+ messages[0].sequenceNumber = 0;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ uint64 nonceBefore = s_offRamp.getSenderNonce(messages[0].sender);
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(s_offRamp.getSenderNonce(messages[0].sender), nonceBefore, "sender nonce is not as expected");
+ }
+
+ function test_Fuzz_getSenderNonceWithPrevOffRamp_Success(uint8 trialExecutions) public {
+ vm.assume(trialExecutions > 1);
+ // Fuzz a random nonce for getSenderNonce
+ test_Fuzz_getSenderNonce(trialExecutions);
+
+ address prevOffRamp = address(s_offRamp);
+ deployOffRamp(s_mockCommitStore, s_destRouter, prevOffRamp);
+
+ // Make sure the off-ramp address has changed by querying the static config
+ assertNotEq(address(s_offRamp), prevOffRamp);
+ EVM2EVMOffRamp.StaticConfig memory staticConfig = s_offRamp.getStaticConfig();
+ assertEq(staticConfig.prevOffRamp, prevOffRamp, "Previous offRamp does not match expected address");
+
+ // Since i_prevOffRamp != address(0) and senderNonce == 0, there should be a call to the previous offRamp
+ vm.expectCall(prevOffRamp, abi.encodeWithSelector(s_offRamp.getSenderNonce.selector, OWNER));
+ uint256 currentSenderNonce = s_offRamp.getSenderNonce(OWNER);
+ assertNotEq(currentSenderNonce, 0, "Sender nonce should not be zero");
+ assertEq(currentSenderNonce, trialExecutions - 1, "Sender Nonce does not match expected trial executions");
+
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ currentSenderNonce = s_offRamp.getSenderNonce(OWNER);
+ assertEq(currentSenderNonce, trialExecutions - 1, "Sender Nonce on new offramp does not match expected executions");
+ }
+
+ function test_SingleMessageNoTokens_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ messages[0].nonce++;
+ messages[0].sequenceNumber++;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ uint64 nonceBefore = s_offRamp.getSenderNonce(messages[0].sender);
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertGt(s_offRamp.getSenderNonce(messages[0].sender), nonceBefore);
+ }
+
+ function test_SingleMessageNoTokensUnordered_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].nonce = 0;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ // Nonce never increments on unordered messages.
+ uint64 nonceBefore = s_offRamp.getSenderNonce(messages[0].sender);
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(
+ s_offRamp.getSenderNonce(messages[0].sender), nonceBefore, "nonce must remain unchanged on unordered messages"
+ );
+
+ messages[0].sequenceNumber++;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ // Nonce never increments on unordered messages.
+ nonceBefore = s_offRamp.getSenderNonce(messages[0].sender);
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(
+ s_offRamp.getSenderNonce(messages[0].sender), nonceBefore, "nonce must remain unchanged on unordered messages"
+ );
+ }
+
+ function test_ReceiverError_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ bytes memory realError1 = new bytes(2);
+ realError1[0] = 0xbe;
+ realError1[1] = 0xef;
+ s_reverting_receiver.setErr(realError1);
+
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber,
+ messages[0].messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, realError1)
+ )
+ );
+ // Nonce should increment on non-strict
+ assertEq(uint64(0), s_offRamp.getSenderNonce(address(OWNER)));
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(uint64(1), s_offRamp.getSenderNonce(address(OWNER)));
+ }
+
+ function test_StrictUntouchedToSuccess_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ messages[0].strict = true;
+ messages[0].receiver = address(s_receiver);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+ // Nonce should increment on a strict untouched -> success.
+ assertEq(uint64(0), s_offRamp.getSenderNonce(address(OWNER)));
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(uint64(1), s_offRamp.getSenderNonce(address(OWNER)));
+ }
+
+ function test_SkippedIncorrectNonce_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ messages[0].nonce++;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.SkippedIncorrectNonce(messages[0].nonce, messages[0].sender);
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+
+ function test_SkippedIncorrectNonceStillExecutes_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateMessagesWithTokens();
+
+ messages[1].nonce++;
+ messages[1].messageId = Internal._hash(messages[1], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.SkippedIncorrectNonce(messages[1].nonce, messages[1].sender);
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+
+ function test__execute_SkippedAlreadyExecutedMessage_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.SkippedAlreadyExecutedMessage(messages[0].sequenceNumber);
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+
+ function test__execute_SkippedAlreadyExecutedMessageUnordered_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].nonce = 0;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.SkippedAlreadyExecutedMessage(messages[0].sequenceNumber);
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+
+ // Send a message to a contract that does not implement the CCIPReceiver interface
+ // This should execute successfully.
+ function test_SingleMessageToNonCCIPReceiver_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ MaybeRevertMessageReceiverNo165 newReceiver = new MaybeRevertMessageReceiverNo165(true);
+ messages[0].receiver = address(newReceiver);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+
+ function test_SingleMessagesNoTokensSuccess_gas() public {
+ vm.pauseGasMetering();
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ Internal.ExecutionReport memory report = _generateReportFromMessages(messages);
+
+ vm.resumeGasMetering();
+ s_offRamp.execute(report, new uint256[](0));
+ }
+
+ function test_TwoMessagesWithTokensSuccess_gas() public {
+ vm.pauseGasMetering();
+ Internal.EVM2EVMMessage[] memory messages = _generateMessagesWithTokens();
+ // Set message 1 to use another receiver to simulate more fair gas costs
+ messages[1].receiver = address(s_secondary_receiver);
+ messages[1].messageId = Internal._hash(messages[1], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[1].sequenceNumber, messages[1].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ Internal.ExecutionReport memory report = _generateReportFromMessages(messages);
+
+ vm.resumeGasMetering();
+ s_offRamp.execute(report, new uint256[](0));
+ }
+
+ function test_TwoMessagesWithTokensAndGE_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateMessagesWithTokens();
+ // Set message 1 to use another receiver to simulate more fair gas costs
+ messages[1].receiver = address(s_secondary_receiver);
+ messages[1].messageId = Internal._hash(messages[1], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[1].sequenceNumber, messages[1].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ assertEq(uint64(0), s_offRamp.getSenderNonce(OWNER));
+ s_offRamp.execute(_generateReportFromMessages(messages), _getGasLimitsFromMessages(messages));
+ assertEq(uint64(2), s_offRamp.getSenderNonce(OWNER));
+ }
+
+ function test_Fuzz_InterleavingOrderedAndUnorderedMessages_Success(bool[7] memory orderings) public {
+ Internal.EVM2EVMMessage[] memory messages = new Internal.EVM2EVMMessage[](orderings.length);
+ // number of tokens needs to be capped otherwise we hit UnsupportedNumberOfTokens.
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](3);
+ for (uint256 i = 0; i < 3; ++i) {
+ tokenAmounts[i].token = s_sourceTokens[i % s_sourceTokens.length];
+ tokenAmounts[i].amount = 1e18;
+ }
+ uint64 expectedNonce = 0;
+ for (uint256 i = 0; i < orderings.length; ++i) {
+ messages[i] = _generateAny2EVMMessage(uint64(i + 1), tokenAmounts, !orderings[i]);
+ if (orderings[i]) {
+ messages[i].nonce = ++expectedNonce;
+ }
+ messages[i].messageId = Internal._hash(messages[i], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[i].sequenceNumber, messages[i].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+ }
+
+ uint64 nonceBefore = s_offRamp.getSenderNonce(OWNER);
+ assertEq(uint64(0), nonceBefore, "nonce before exec should be 0");
+ s_offRamp.execute(_generateReportFromMessages(messages), _getGasLimitsFromMessages(messages));
+ // all executions should succeed.
+ for (uint256 i = 0; i < orderings.length; ++i) {
+ assertEq(
+ uint256(s_offRamp.getExecutionState(messages[i].sequenceNumber)),
+ uint256(Internal.MessageExecutionState.SUCCESS)
+ );
+ }
+ assertEq(nonceBefore + expectedNonce, s_offRamp.getSenderNonce(OWNER));
+ }
+
+ function test_InvalidSourcePoolAddress_Success() public {
+ address fakePoolAddress = address(0x0000000000333333);
+
+ Internal.EVM2EVMMessage[] memory messages = _generateMessagesWithTokens();
+ messages[0].sourceTokenData[0] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(fakePoolAddress),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[messages[0].tokenAmounts[0].token]),
+ extraData: ""
+ })
+ );
+
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+ messages[1].messageId = Internal._hash(messages[1], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber,
+ messages[0].messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMOffRamp.TokenHandlingError.selector,
+ abi.encodeWithSelector(TokenPool.InvalidSourcePoolAddress.selector, abi.encode(fakePoolAddress))
+ )
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+
+ // Reverts
+
+ function test_InvalidMessageId_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].nonce++;
+ // MessageID no longer matches hash.
+ Internal.ExecutionReport memory executionReport = _generateReportFromMessages(messages);
+ vm.expectRevert(EVM2EVMOffRamp.InvalidMessageId.selector);
+ s_offRamp.execute(executionReport, new uint256[](0));
+ }
+
+ function test_Paused_Revert() public {
+ s_mockCommitStore.pause();
+ vm.expectRevert(PausedError.selector);
+ s_offRamp.execute(_generateReportFromMessages(_generateMessagesWithTokens()), new uint256[](0));
+ }
+
+ function test_Unhealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ vm.expectRevert(EVM2EVMOffRamp.CursedByRMN.selector);
+ s_offRamp.execute(_generateReportFromMessages(_generateMessagesWithTokens()), new uint256[](0));
+ // Uncurse should succeed
+ s_mockRMN.setGlobalCursed(false);
+ s_offRamp.execute(_generateReportFromMessages(_generateMessagesWithTokens()), new uint256[](0));
+ }
+
+ function test_UnexpectedTokenData_Revert() public {
+ Internal.ExecutionReport memory report = _generateReportFromMessages(_generateSingleBasicMessage());
+ report.offchainTokenData = new bytes[][](report.messages.length + 1);
+
+ vm.expectRevert(EVM2EVMOffRamp.UnexpectedTokenData.selector);
+
+ s_offRamp.execute(report, new uint256[](0));
+ }
+
+ function test_EmptyReport_Revert() public {
+ vm.expectRevert(EVM2EVMOffRamp.EmptyReport.selector);
+ s_offRamp.execute(
+ Internal.ExecutionReport({
+ proofs: new bytes32[](0),
+ proofFlagBits: 0,
+ messages: new Internal.EVM2EVMMessage[](0),
+ offchainTokenData: new bytes[][](0)
+ }),
+ new uint256[](0)
+ );
+ }
+
+ function test_RootNotCommitted_Revert() public {
+ vm.mockCall(address(s_mockCommitStore), abi.encodeWithSelector(ICommitStore.verify.selector), abi.encode(0));
+ vm.expectRevert(EVM2EVMOffRamp.RootNotCommitted.selector);
+
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ s_offRamp.execute(_generateReportFromMessages(messages), _getGasLimitsFromMessages(messages));
+ vm.clearMockedCalls();
+ }
+
+ function test_ManualExecutionNotYetEnabled_Revert() public {
+ vm.mockCall(
+ address(s_mockCommitStore), abi.encodeWithSelector(ICommitStore.verify.selector), abi.encode(BLOCK_TIME)
+ );
+ vm.expectRevert(EVM2EVMOffRamp.ManualExecutionNotYetEnabled.selector);
+
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ s_offRamp.execute(_generateReportFromMessages(messages), _getGasLimitsFromMessages(messages));
+ vm.clearMockedCalls();
+ }
+
+ function test_InvalidSourceChain_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].sourceChainSelector = SOURCE_CHAIN_SELECTOR + 1;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.InvalidSourceChain.selector, SOURCE_CHAIN_SELECTOR + 1));
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+
+ function test_UnsupportedNumberOfTokens_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ Client.EVMTokenAmount[] memory newTokens = new Client.EVMTokenAmount[](MAX_TOKENS_LENGTH + 1);
+ messages[0].tokenAmounts = newTokens;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+ Internal.ExecutionReport memory report = _generateReportFromMessages(messages);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(EVM2EVMOffRamp.UnsupportedNumberOfTokens.selector, messages[0].sequenceNumber)
+ );
+ s_offRamp.execute(report, new uint256[](0));
+ }
+
+ function test_TokenDataMismatch_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ Internal.ExecutionReport memory report = _generateReportFromMessages(messages);
+
+ report.offchainTokenData[0] = new bytes[](messages[0].tokenAmounts.length + 1);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.TokenDataMismatch.selector, messages[0].sequenceNumber));
+ s_offRamp.execute(report, new uint256[](0));
+ }
+
+ function test_MessageTooLarge_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].data = new bytes(MAX_DATA_SIZE + 1);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ Internal.ExecutionReport memory executionReport = _generateReportFromMessages(messages);
+ vm.expectRevert(
+ abi.encodeWithSelector(EVM2EVMOffRamp.MessageTooLarge.selector, MAX_DATA_SIZE, messages[0].data.length)
+ );
+ s_offRamp.execute(executionReport, new uint256[](0));
+ }
+
+ function test_RouterYULCall_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ // gas limit too high, Router's external call should revert
+ messages[0].gasLimit = 1e36;
+ messages[0].receiver = address(new ConformingReceiver(address(s_destRouter), s_destFeeToken));
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ Internal.ExecutionReport memory executionReport = _generateReportFromMessages(messages);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMOffRamp.ExecutionError.selector, abi.encodeWithSelector(CallWithExactGas.NotEnoughGasForCall.selector)
+ )
+ );
+ s_offRamp.execute(executionReport, new uint256[](0));
+ }
+
+ function test_RetryFailedMessageWithoutManualExecution_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ bytes memory realError1 = new bytes(2);
+ realError1[0] = 0xbe;
+ realError1[1] = 0xef;
+ s_reverting_receiver.setErr(realError1);
+
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber,
+ messages[0].messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, realError1)
+ )
+ );
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.AlreadyAttempted.selector, messages[0].sequenceNumber));
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+}
+
+contract EVM2EVMOffRamp_execute_upgrade is EVM2EVMOffRampSetup {
+ EVM2EVMOffRampHelper internal s_prevOffRamp;
+
+ function setUp() public virtual override {
+ super.setUp();
+
+ s_prevOffRamp = s_offRamp;
+
+ deployOffRamp(s_mockCommitStore, s_destRouter, address(s_prevOffRamp));
+ }
+
+ function test_V2_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ }
+
+ function test_V2SenderNoncesReadsPreviousRamp_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ uint64 startNonce = s_offRamp.getSenderNonce(messages[0].sender);
+
+ for (uint64 i = 1; i < 4; ++i) {
+ s_prevOffRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ messages[0].nonce++;
+ messages[0].sequenceNumber++;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ assertEq(startNonce + i, s_offRamp.getSenderNonce(messages[0].sender));
+ }
+ }
+
+ function test_V2NonceStartsAtV1Nonce_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ uint64 startNonce = s_offRamp.getSenderNonce(messages[0].sender);
+
+ s_prevOffRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ assertEq(startNonce + 1, s_offRamp.getSenderNonce(messages[0].sender));
+
+ messages[0].nonce++;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(startNonce + 2, s_offRamp.getSenderNonce(messages[0].sender));
+
+ messages[0].nonce++;
+ messages[0].sequenceNumber++;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(startNonce + 3, s_offRamp.getSenderNonce(messages[0].sender));
+ }
+
+ function test_V2NonceNewSenderStartsAtZero_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_prevOffRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ address newSender = address(1234567);
+ messages[0].sender = newSender;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ // new sender nonce in new offramp should go from 0 -> 1
+ assertEq(s_offRamp.getSenderNonce(newSender), 0);
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(s_offRamp.getSenderNonce(newSender), 1);
+ }
+
+ function test_V2OffRampNonceSkipsIfMsgInFlight_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ address newSender = address(1234567);
+ messages[0].sender = newSender;
+ messages[0].nonce = 2;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ uint64 startNonce = s_offRamp.getSenderNonce(messages[0].sender);
+
+ // new offramp sees msg nonce higher than senderNonce
+ // it waits for previous offramp to execute
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.SkippedSenderWithPreviousRampMessageInflight(messages[0].nonce, newSender);
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(startNonce, s_offRamp.getSenderNonce(messages[0].sender));
+
+ messages[0].nonce = 1;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ // previous offramp executes msg and increases nonce
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+ s_prevOffRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(startNonce + 1, s_offRamp.getSenderNonce(messages[0].sender));
+
+ messages[0].nonce = 2;
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ // new offramp is able to execute
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+ assertEq(startNonce + 2, s_offRamp.getSenderNonce(messages[0].sender));
+ }
+}
+
+contract EVM2EVMOffRamp_executeSingleMessage is EVM2EVMOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ vm.startPrank(address(s_offRamp));
+ }
+
+ function test_executeSingleMessage_NoTokens_Success() public {
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageNoTokens(1);
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_executeSingleMessage_WithTokens_Success() public {
+ Internal.EVM2EVMMessage memory message = _generateMessagesWithTokens()[0];
+ bytes[] memory offchainTokenData = new bytes[](message.tokenAmounts.length);
+ Internal.SourceTokenData memory sourceTokenData = abi.decode(message.sourceTokenData[0], (Internal.SourceTokenData));
+
+ vm.expectCall(
+ s_destPoolByToken[s_destTokens[0]],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(message.sender),
+ receiver: message.receiver,
+ amount: message.tokenAmounts[0].amount,
+ localToken: s_destTokenBySourceToken[message.tokenAmounts[0].token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: ""
+ })
+ )
+ );
+
+ s_offRamp.executeSingleMessage(message, offchainTokenData);
+ }
+
+ function test_executeSingleMessage_ZeroGasZeroData_Success() public {
+ uint256 gasLimit = 0;
+ Internal.EVM2EVMMessage memory message = _generateMsgWithoutTokens(gasLimit);
+ Client.Any2EVMMessage memory receiverMsg = _convertToGeneralMessage(message);
+
+ // expect 0 calls to be made as no gas is provided
+ vm.expectCall(
+ address(s_destRouter),
+ abi.encodeCall(Router.routeMessage, (receiverMsg, Internal.GAS_FOR_CALL_EXACT_CHECK, gasLimit, message.receiver)),
+ 0
+ );
+
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+
+ // Ensure we encoded it properly, and didn't simply expect the wrong call
+ gasLimit = 200_000;
+ message = _generateMsgWithoutTokens(gasLimit);
+ receiverMsg = _convertToGeneralMessage(message);
+
+ vm.expectCall(
+ address(s_destRouter),
+ abi.encodeCall(Router.routeMessage, (receiverMsg, Internal.GAS_FOR_CALL_EXACT_CHECK, gasLimit, message.receiver)),
+ 1
+ );
+
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function _generateMsgWithoutTokens(uint256 gasLimit) internal view returns (Internal.EVM2EVMMessage memory) {
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageNoTokens(1);
+ message.gasLimit = gasLimit;
+ message.data = "";
+ message.messageId = Internal._hash(
+ message,
+ keccak256(
+ abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, ON_RAMP_ADDRESS)
+ )
+ );
+ return message;
+ }
+
+ function test_NonContract_Success() public {
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageNoTokens(1);
+ message.receiver = STRANGER;
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_NonContractWithTokens_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+ vm.expectEmit();
+ emit TokenPool.Released(address(s_offRamp), STRANGER, amounts[0]);
+ vm.expectEmit();
+ emit TokenPool.Minted(address(s_offRamp), STRANGER, amounts[1]);
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageWithTokens(1, amounts);
+ message.receiver = STRANGER;
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ // Reverts
+
+ function test_TokenHandlingError_Revert() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+
+ bytes memory errorMessage = "Random token pool issue";
+
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageWithTokens(1, amounts);
+ s_maybeRevertingPool.setShouldRevert(errorMessage);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.TokenHandlingError.selector, errorMessage));
+
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_ZeroGasDONExecution_Revert() public {
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageNoTokens(1);
+ message.gasLimit = 0;
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.ReceiverError.selector, ""));
+
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+
+ function test_MessageSender_Revert() public {
+ vm.stopPrank();
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageNoTokens(1);
+ vm.expectRevert(EVM2EVMOffRamp.CanOnlySelfCall.selector);
+ s_offRamp.executeSingleMessage(message, new bytes[](message.tokenAmounts.length));
+ }
+}
+
+contract EVM2EVMOffRamp__report is EVM2EVMOffRampSetup {
+ // Asserts that execute completes
+ function test_Report_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ Internal.ExecutionReport memory report = _generateReportFromMessages(messages);
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+ s_offRamp.report(abi.encode(report));
+ }
+}
+
+contract EVM2EVMOffRamp_manuallyExecute is EVM2EVMOffRampSetup {
+ function test_ManualExec_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ s_reverting_receiver.setRevert(false);
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), new uint256[](messages.length));
+ }
+
+ function test_manuallyExecute_DoesNotRevertIfUntouched_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ assertEq(messages[0].nonce - 1, s_offRamp.getSenderNonce(messages[0].sender));
+
+ s_reverting_receiver.setRevert(true);
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber,
+ messages[0].messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, "")
+ )
+ );
+
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), new uint256[](1));
+
+ assertEq(messages[0].nonce, s_offRamp.getSenderNonce(messages[0].sender));
+ }
+
+ function test_ManualExecWithGasOverride_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ s_reverting_receiver.setRevert(false);
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+
+ uint256[] memory gasLimitOverrides = _getGasLimitsFromMessages(messages);
+ gasLimitOverrides[0] += 1;
+
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), gasLimitOverrides);
+ }
+
+ function test_LowGasLimitManualExec_Success() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].gasLimit = 1;
+ messages[0].receiver = address(new ConformingReceiver(address(s_destRouter), s_destFeeToken));
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber,
+ messages[0].messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(EVM2EVMOffRamp.ReceiverError.selector, "")
+ );
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ uint256[] memory gasLimitOverrides = new uint256[](1);
+ gasLimitOverrides[0] = 100_000;
+
+ vm.expectEmit();
+ emit MaybeRevertMessageReceiver.MessageReceived();
+
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
+ );
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), gasLimitOverrides);
+ }
+
+ function test_ManualExecForkedChain_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ Internal.ExecutionReport memory report = _generateReportFromMessages(messages);
+ uint256 chain1 = block.chainid;
+ uint256 chain2 = chain1 + 1;
+ vm.chainId(chain2);
+ vm.expectRevert(abi.encodeWithSelector(OCR2BaseNoChecks.ForkedChain.selector, chain1, chain2));
+
+ s_offRamp.manuallyExecute(report, _getGasLimitsFromMessages(messages));
+ }
+
+ function test_ManualExecGasLimitMismatch_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ vm.expectRevert(EVM2EVMOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), new uint256[](0));
+
+ vm.expectRevert(EVM2EVMOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), new uint256[](messages.length - 1));
+
+ vm.expectRevert(EVM2EVMOffRamp.ManualExecutionGasLimitMismatch.selector);
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), new uint256[](messages.length + 1));
+ }
+
+ function test_ManualExecInvalidGasLimit_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ uint256[] memory gasLimits = _getGasLimitsFromMessages(messages);
+ gasLimits[0]--;
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.InvalidManualExecutionGasLimit.selector, 0, gasLimits[0]));
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), gasLimits);
+ }
+
+ function test_ManualExecFailedTx_Revert() public {
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+
+ messages[0].receiver = address(s_reverting_receiver);
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ s_offRamp.execute(_generateReportFromMessages(messages), new uint256[](0));
+
+ s_reverting_receiver.setRevert(true);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMOffRamp.ExecutionError.selector,
+ abi.encodeWithSelector(
+ EVM2EVMOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, bytes(""))
+ )
+ )
+ );
+ s_offRamp.manuallyExecute(_generateReportFromMessages(messages), _getGasLimitsFromMessages(messages));
+ }
+
+ function test_ReentrancyManualExecuteFails() public {
+ uint256 tokenAmount = 1e9;
+ IERC20 tokenToAbuse = IERC20(s_destFeeToken);
+
+ // This needs to be deployed before the source chain message is sent
+ // because we need the address for the receiver.
+ ReentrancyAbuser receiver = new ReentrancyAbuser(address(s_destRouter), s_offRamp);
+ uint256 balancePre = tokenToAbuse.balanceOf(address(receiver));
+
+ // For this test any message will be flagged as correct by the
+ // commitStore. In a real scenario the abuser would have to actually
+ // send the message that they want to replay.
+ Internal.EVM2EVMMessage[] memory messages = _generateSingleBasicMessage();
+ messages[0].tokenAmounts = new Client.EVMTokenAmount[](1);
+ messages[0].tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceFeeToken, amount: tokenAmount});
+ messages[0].receiver = address(receiver);
+ messages[0].sourceTokenData = new bytes[](1);
+ messages[0].sourceTokenData[0] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[s_sourceFeeToken]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[s_sourceFeeToken]),
+ extraData: ""
+ })
+ );
+
+ messages[0].messageId = Internal._hash(messages[0], s_offRamp.metadataHash());
+
+ Internal.ExecutionReport memory report = _generateReportFromMessages(messages);
+
+ // sets the report to be repeated on the ReentrancyAbuser to be able to replay
+ receiver.setPayload(report);
+
+ // The first entry should be fine and triggers the second entry. This one fails
+ // but since it's an inner tx of the first one it is caught in the try-catch.
+ // This means the first tx is marked `FAILURE` with the error message of the second tx.
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.ExecutionStateChanged(
+ messages[0].sequenceNumber,
+ messages[0].messageId,
+ Internal.MessageExecutionState.FAILURE,
+ abi.encodeWithSelector(
+ EVM2EVMOffRamp.ReceiverError.selector,
+ abi.encodeWithSelector(EVM2EVMOffRamp.AlreadyExecuted.selector, messages[0].sequenceNumber)
+ )
+ );
+
+ s_offRamp.manuallyExecute(report, _getGasLimitsFromMessages(messages));
+
+ // Since the tx failed we don't release the tokens
+ assertEq(tokenToAbuse.balanceOf(address(receiver)), balancePre);
+ }
+}
+
+contract EVM2EVMOffRamp_getExecutionState is EVM2EVMOffRampSetup {
+ mapping(uint64 seqNum => Internal.MessageExecutionState state) internal s_differentialExecutionState;
+
+ /// forge-config: default.fuzz.runs = 32
+ /// forge-config: ccip.fuzz.runs = 32
+ function test_Fuzz_Differential_Success(uint16[500] memory seqNums, uint8[500] memory values) public {
+ for (uint256 i = 0; i < seqNums.length; ++i) {
+ // Only use the first three slots. This makes sure existing slots get overwritten
+ // as the tests uses 500 sequence numbers.
+ uint16 seqNum = seqNums[i] % 386;
+ Internal.MessageExecutionState state = Internal.MessageExecutionState(values[i] % 4);
+ s_differentialExecutionState[seqNum] = state;
+ s_offRamp.setExecutionStateHelper(seqNum, state);
+ assertEq(uint256(state), uint256(s_offRamp.getExecutionState(seqNum)));
+ }
+
+ for (uint256 i = 0; i < seqNums.length; ++i) {
+ uint16 seqNum = seqNums[i] % 386;
+ Internal.MessageExecutionState expectedState = s_differentialExecutionState[seqNum];
+ assertEq(uint256(expectedState), uint256(s_offRamp.getExecutionState(seqNum)));
+ }
+ }
+
+ function test_GetExecutionState_Success() public {
+ s_offRamp.setExecutionStateHelper(0, Internal.MessageExecutionState.FAILURE);
+ assertEq(s_offRamp.getExecutionStateBitMap(0), 3);
+
+ s_offRamp.setExecutionStateHelper(1, Internal.MessageExecutionState.FAILURE);
+ assertEq(s_offRamp.getExecutionStateBitMap(0), 3 + (3 << 2));
+
+ s_offRamp.setExecutionStateHelper(1, Internal.MessageExecutionState.IN_PROGRESS);
+ assertEq(s_offRamp.getExecutionStateBitMap(0), 3 + (1 << 2));
+
+ s_offRamp.setExecutionStateHelper(2, Internal.MessageExecutionState.FAILURE);
+ assertEq(s_offRamp.getExecutionStateBitMap(0), 3 + (1 << 2) + (3 << 4));
+
+ s_offRamp.setExecutionStateHelper(127, Internal.MessageExecutionState.IN_PROGRESS);
+ assertEq(s_offRamp.getExecutionStateBitMap(0), 3 + (1 << 2) + (3 << 4) + (1 << 254));
+
+ s_offRamp.setExecutionStateHelper(128, Internal.MessageExecutionState.SUCCESS);
+ assertEq(s_offRamp.getExecutionStateBitMap(0), 3 + (1 << 2) + (3 << 4) + (1 << 254));
+ assertEq(s_offRamp.getExecutionStateBitMap(1), 2);
+
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(s_offRamp.getExecutionState(0)));
+ assertEq(uint256(Internal.MessageExecutionState.IN_PROGRESS), uint256(s_offRamp.getExecutionState(1)));
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(s_offRamp.getExecutionState(2)));
+ assertEq(uint256(Internal.MessageExecutionState.IN_PROGRESS), uint256(s_offRamp.getExecutionState(127)));
+ assertEq(uint256(Internal.MessageExecutionState.SUCCESS), uint256(s_offRamp.getExecutionState(128)));
+ }
+
+ function test_FillExecutionState_Success() public {
+ for (uint64 i = 0; i < 384; ++i) {
+ s_offRamp.setExecutionStateHelper(i, Internal.MessageExecutionState.FAILURE);
+ }
+
+ for (uint64 i = 0; i < 384; ++i) {
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(s_offRamp.getExecutionState(i)));
+ }
+
+ for (uint64 i = 0; i < 3; ++i) {
+ assertEq(type(uint256).max, s_offRamp.getExecutionStateBitMap(i));
+ }
+
+ for (uint64 i = 0; i < 384; ++i) {
+ s_offRamp.setExecutionStateHelper(i, Internal.MessageExecutionState.IN_PROGRESS);
+ }
+
+ for (uint64 i = 0; i < 384; ++i) {
+ assertEq(uint256(Internal.MessageExecutionState.IN_PROGRESS), uint256(s_offRamp.getExecutionState(i)));
+ }
+
+ for (uint64 i = 0; i < 3; ++i) {
+ // 0x555... == 0b101010101010.....
+ assertEq(0x5555555555555555555555555555555555555555555555555555555555555555, s_offRamp.getExecutionStateBitMap(i));
+ }
+ }
+}
+
+contract EVM2EVMOffRamp__trialExecute is EVM2EVMOffRampSetup {
+ function test_trialExecute_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageWithTokens(1, amounts);
+ IERC20 dstToken0 = IERC20(s_destTokens[0]);
+ uint256 startingBalance = dstToken0.balanceOf(message.receiver);
+
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+ assertEq(uint256(Internal.MessageExecutionState.SUCCESS), uint256(newState));
+ assertEq("", err);
+
+ // Check that the tokens were transferred
+ assertEq(startingBalance + amounts[0], dstToken0.balanceOf(message.receiver));
+ }
+
+ function test_TokenHandlingErrorIsCaught_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+
+ IERC20 dstToken0 = IERC20(s_destTokens[0]);
+ uint256 startingBalance = dstToken0.balanceOf(OWNER);
+
+ bytes memory errorMessage = "Random token pool issue";
+
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageWithTokens(1, amounts);
+ s_maybeRevertingPool.setShouldRevert(errorMessage);
+
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(newState));
+ assertEq(abi.encodeWithSelector(EVM2EVMOffRamp.TokenHandlingError.selector, errorMessage), err);
+
+ // Expect the balance to remain the same
+ assertEq(startingBalance, dstToken0.balanceOf(OWNER));
+ }
+
+ function test_RateLimitError_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 1000;
+ amounts[1] = 50;
+
+ bytes memory errorMessage = abi.encodeWithSelector(RateLimiter.BucketOverfilled.selector);
+
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageWithTokens(1, amounts);
+ s_maybeRevertingPool.setShouldRevert(errorMessage);
+
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(newState));
+ assertEq(abi.encodeWithSelector(EVM2EVMOffRamp.TokenHandlingError.selector, errorMessage), err);
+ }
+
+ function test_TokenPoolIsNotAContract_Success() public {
+ uint256[] memory amounts = new uint256[](2);
+ amounts[0] = 10000;
+ Internal.EVM2EVMMessage memory message = _generateAny2EVMMessageWithTokens(1, amounts);
+
+ // Happy path, pool is correct
+ (Internal.MessageExecutionState newState, bytes memory err) =
+ s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+
+ assertEq(uint256(Internal.MessageExecutionState.SUCCESS), uint256(newState));
+ assertEq("", err);
+
+ // address 0 has no contract
+ assertEq(address(0).code.length, 0);
+ message.sourceTokenData[0] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(address(0)),
+ destTokenAddress: abi.encode(address(0)),
+ extraData: ""
+ })
+ );
+
+ message.messageId = Internal._hash(
+ message,
+ keccak256(
+ abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, ON_RAMP_ADDRESS)
+ )
+ );
+
+ // Unhappy path, no revert but marked as failed.
+ (newState, err) = s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(newState));
+ assertEq(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, abi.encode(address(0))), err);
+
+ address notAContract = makeAddr("not_a_contract");
+
+ message.sourceTokenData[0] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(address(0)),
+ destTokenAddress: abi.encode(notAContract),
+ extraData: ""
+ })
+ );
+
+ message.messageId = Internal._hash(
+ message,
+ keccak256(
+ abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, ON_RAMP_ADDRESS)
+ )
+ );
+
+ (newState, err) = s_offRamp.trialExecute(message, new bytes[](message.tokenAmounts.length));
+
+ assertEq(uint256(Internal.MessageExecutionState.FAILURE), uint256(newState));
+ assertEq(abi.encodeWithSelector(EVM2EVMOffRamp.NotACompatiblePool.selector, address(0)), err);
+ }
+}
+
+contract EVM2EVMOffRamp__releaseOrMintToken is EVM2EVMOffRampSetup {
+ function test__releaseOrMintToken_Success() public {
+ uint256 amount = 123123;
+ address token = s_sourceTokens[0];
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes memory offchainTokenData = abi.encode(keccak256("offchainTokenData"));
+
+ IERC20 dstToken1 = IERC20(s_destTokenBySourceToken[token]);
+ uint256 startingBalance = dstToken1.balanceOf(OWNER);
+
+ Internal.SourceTokenData memory sourceTokenData = Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[token]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[token]),
+ extraData: ""
+ });
+
+ vm.expectCall(
+ s_destPoolBySourceToken[token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: originalSender,
+ receiver: OWNER,
+ amount: amount,
+ localToken: s_destTokenBySourceToken[token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData
+ })
+ )
+ );
+
+ s_offRamp.releaseOrMintToken(amount, originalSender, OWNER, sourceTokenData, offchainTokenData);
+
+ assertEq(startingBalance + amount, dstToken1.balanceOf(OWNER));
+ }
+
+ function test__releaseOrMintToken_NotACompatiblePool_Revert() public {
+ uint256 amount = 123123;
+ address token = s_sourceTokens[0];
+ address destToken = s_destTokenBySourceToken[token];
+ vm.label(destToken, "destToken");
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes memory offchainTokenData = abi.encode(keccak256("offchainTokenData"));
+
+ Internal.SourceTokenData memory sourceTokenData = Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[token]),
+ destTokenAddress: abi.encode(destToken),
+ extraData: ""
+ });
+
+ // Address(0) should always revert
+ address returnedPool = address(0);
+
+ vm.mockCall(
+ address(s_tokenAdminRegistry),
+ abi.encodeWithSelector(ITokenAdminRegistry.getPool.selector, destToken),
+ abi.encode(returnedPool)
+ );
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.NotACompatiblePool.selector, returnedPool));
+
+ s_offRamp.releaseOrMintToken(amount, originalSender, OWNER, sourceTokenData, offchainTokenData);
+
+ // A contract that doesn't support the interface should also revert
+ returnedPool = address(s_offRamp);
+
+ vm.mockCall(
+ address(s_tokenAdminRegistry),
+ abi.encodeWithSelector(ITokenAdminRegistry.getPool.selector, destToken),
+ abi.encode(returnedPool)
+ );
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.NotACompatiblePool.selector, returnedPool));
+
+ s_offRamp.releaseOrMintToken(amount, originalSender, OWNER, sourceTokenData, offchainTokenData);
+ }
+
+ function test__releaseOrMintToken_TokenHandlingError_revert_Revert() public {
+ address receiver = makeAddr("receiver");
+ uint256 amount = 123123;
+ address token = s_sourceTokens[0];
+ address destToken = s_destTokenBySourceToken[token];
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes memory offchainTokenData = abi.encode(keccak256("offchainTokenData"));
+
+ Internal.SourceTokenData memory sourceTokenData = Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[token]),
+ destTokenAddress: abi.encode(destToken),
+ extraData: ""
+ });
+
+ bytes memory revertData = "call reverted :o";
+
+ vm.mockCallRevert(destToken, abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount), revertData);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.TokenHandlingError.selector, revertData));
+ s_offRamp.releaseOrMintToken(amount, originalSender, receiver, sourceTokenData, offchainTokenData);
+ }
+}
+
+contract EVM2EVMOffRamp__releaseOrMintTokens is EVM2EVMOffRampSetup {
+ function test_releaseOrMintTokens_Success() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ IERC20 dstToken1 = IERC20(s_destFeeToken);
+ uint256 startingBalance = dstToken1.balanceOf(OWNER);
+ uint256 amount1 = 100;
+ srcTokenAmounts[0].amount = amount1;
+
+ bytes memory originalSender = abi.encode(OWNER);
+
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ offchainTokenData[0] = abi.encode(0x12345678);
+
+ bytes[] memory encodedSourceTokenData = _getDefaultSourceTokenData(srcTokenAmounts);
+ Internal.SourceTokenData memory sourceTokenData = abi.decode(encodedSourceTokenData[0], (Internal.SourceTokenData));
+
+ vm.expectCall(
+ s_destPoolBySourceToken[srcTokenAmounts[0].token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: originalSender,
+ receiver: OWNER,
+ amount: srcTokenAmounts[0].amount,
+ localToken: s_destTokenBySourceToken[srcTokenAmounts[0].token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData[0]
+ })
+ )
+ );
+
+ s_offRamp.releaseOrMintTokens(srcTokenAmounts, originalSender, OWNER, encodedSourceTokenData, offchainTokenData);
+
+ assertEq(startingBalance + amount1, dstToken1.balanceOf(OWNER));
+ }
+
+ function test_releaseOrMintTokens_destDenominatedDecimals_Success() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ address destToken = s_destFeeToken;
+ uint256 amount = 100;
+ uint256 destinationDenominationMultiplier = 1000;
+ srcTokenAmounts[0].amount = amount;
+
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ bytes[] memory encodedSourceTokenData = _getDefaultSourceTokenData(srcTokenAmounts);
+ Internal.SourceTokenData memory sourceTokenData = abi.decode(encodedSourceTokenData[0], (Internal.SourceTokenData));
+
+ // Since the pool call is mocked, we manually release funds to the offRamp
+ deal(destToken, address(s_offRamp), amount * destinationDenominationMultiplier);
+
+ vm.mockCall(
+ s_destPoolBySourceToken[srcTokenAmounts[0].token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: originalSender,
+ receiver: OWNER,
+ amount: amount,
+ localToken: s_destTokenBySourceToken[srcTokenAmounts[0].token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData[0]
+ })
+ ),
+ abi.encode(amount * destinationDenominationMultiplier)
+ );
+
+ Client.EVMTokenAmount[] memory destTokenAmounts =
+ s_offRamp.releaseOrMintTokens(srcTokenAmounts, originalSender, OWNER, encodedSourceTokenData, offchainTokenData);
+
+ assertEq(destTokenAmounts[0].amount, amount * destinationDenominationMultiplier);
+ assertEq(destTokenAmounts[0].token, destToken);
+ }
+
+ function test_OverValueWithARLOff_Success() public {
+ // Set a high price to trip the ARL
+ uint224 tokenPrice = 3 ** 128;
+ Internal.PriceUpdates memory priceUpdates = getSingleTokenPriceUpdateStruct(s_destFeeToken, tokenPrice);
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ uint256 amount1 = 100;
+ srcTokenAmounts[0].amount = amount1;
+
+ bytes memory originalSender = abi.encode(OWNER);
+
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ offchainTokenData[0] = abi.encode(0x12345678);
+
+ bytes[] memory sourceTokenData = _getDefaultSourceTokenData(srcTokenAmounts);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ RateLimiter.AggregateValueMaxCapacityExceeded.selector,
+ getInboundRateLimiterConfig().capacity,
+ (amount1 * tokenPrice) / 1e18
+ )
+ );
+
+ // // Expect to fail from ARL
+ s_offRamp.releaseOrMintTokens(srcTokenAmounts, originalSender, OWNER, sourceTokenData, offchainTokenData);
+
+ // Configure ARL off for token
+ EVM2EVMOffRamp.RateLimitToken[] memory removes = new EVM2EVMOffRamp.RateLimitToken[](1);
+ removes[0] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceFeeToken, destToken: s_destFeeToken});
+ s_offRamp.updateRateLimitTokens(removes, new EVM2EVMOffRamp.RateLimitToken[](0));
+
+ // Expect the call now succeeds
+ s_offRamp.releaseOrMintTokens(srcTokenAmounts, originalSender, OWNER, sourceTokenData, offchainTokenData);
+ }
+
+ // Revert
+
+ function test_TokenHandlingError_Reverts() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+
+ bytes memory unknownError = bytes("unknown error");
+ s_maybeRevertingPool.setShouldRevert(unknownError);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.TokenHandlingError.selector, unknownError));
+
+ s_offRamp.releaseOrMintTokens(
+ srcTokenAmounts,
+ abi.encode(OWNER),
+ OWNER,
+ _getDefaultSourceTokenData(srcTokenAmounts),
+ new bytes[](srcTokenAmounts.length)
+ );
+ }
+
+ function test_releaseOrMintTokens_InvalidDataLengthReturnData_Revert() public {
+ uint256 amount = 100;
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ srcTokenAmounts[0].amount = amount;
+
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ bytes[] memory encodedSourceTokenData = _getDefaultSourceTokenData(srcTokenAmounts);
+ Internal.SourceTokenData memory sourceTokenData = abi.decode(encodedSourceTokenData[0], (Internal.SourceTokenData));
+
+ vm.mockCall(
+ s_destPoolBySourceToken[srcTokenAmounts[0].token],
+ abi.encodeWithSelector(
+ LockReleaseTokenPool.releaseOrMint.selector,
+ Pool.ReleaseOrMintInV1({
+ originalSender: originalSender,
+ receiver: OWNER,
+ amount: amount,
+ localToken: s_destTokenBySourceToken[srcTokenAmounts[0].token],
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData[0]
+ })
+ ),
+ // Includes the amount twice, this will revert due to the return data being to long
+ abi.encode(amount, amount)
+ );
+
+ vm.expectRevert(
+ abi.encodeWithSelector(EVM2EVMOffRamp.InvalidDataLength.selector, Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, 64)
+ );
+
+ s_offRamp.releaseOrMintTokens(srcTokenAmounts, originalSender, OWNER, encodedSourceTokenData, offchainTokenData);
+ }
+
+ function test_releaseOrMintTokens_InvalidEVMAddress_Revert() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+
+ bytes memory originalSender = abi.encode(OWNER);
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ bytes[] memory sourceTokenData = _getDefaultSourceTokenData(srcTokenAmounts);
+ bytes memory wrongAddress = abi.encode(address(1000), address(10000), address(10000));
+
+ sourceTokenData[0] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[srcTokenAmounts[0].token]),
+ destTokenAddress: wrongAddress,
+ extraData: ""
+ })
+ );
+
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, wrongAddress));
+
+ s_offRamp.releaseOrMintTokens(srcTokenAmounts, originalSender, OWNER, sourceTokenData, offchainTokenData);
+ }
+
+ function test_RateLimitErrors_Reverts() public {
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+
+ bytes[] memory rateLimitErrors = new bytes[](5);
+ rateLimitErrors[0] = abi.encodeWithSelector(RateLimiter.BucketOverfilled.selector);
+ rateLimitErrors[1] =
+ abi.encodeWithSelector(RateLimiter.AggregateValueMaxCapacityExceeded.selector, uint256(100), uint256(1000));
+ rateLimitErrors[2] =
+ abi.encodeWithSelector(RateLimiter.AggregateValueRateLimitReached.selector, uint256(42), 1, s_sourceTokens[0]);
+ rateLimitErrors[3] = abi.encodeWithSelector(
+ RateLimiter.TokenMaxCapacityExceeded.selector, uint256(100), uint256(1000), s_sourceTokens[0]
+ );
+ rateLimitErrors[4] =
+ abi.encodeWithSelector(RateLimiter.TokenRateLimitReached.selector, uint256(42), 1, s_sourceTokens[0]);
+
+ for (uint256 i = 0; i < rateLimitErrors.length; ++i) {
+ s_maybeRevertingPool.setShouldRevert(rateLimitErrors[i]);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.TokenHandlingError.selector, rateLimitErrors[i]));
+
+ s_offRamp.releaseOrMintTokens(
+ srcTokenAmounts,
+ abi.encode(OWNER),
+ OWNER,
+ _getDefaultSourceTokenData(srcTokenAmounts),
+ new bytes[](srcTokenAmounts.length)
+ );
+ }
+ }
+
+ function test__releaseOrMintTokens_NotACompatiblePool_Reverts() public {
+ address fakePoolAddress = makeAddr("Doesn't exist");
+
+ bytes[] memory sourceTokenData = new bytes[](1);
+ sourceTokenData[0] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(fakePoolAddress),
+ destTokenAddress: abi.encode(fakePoolAddress),
+ extraData: ""
+ })
+ );
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOffRamp.NotACompatiblePool.selector, address(0)));
+ s_offRamp.releaseOrMintTokens(
+ new Client.EVMTokenAmount[](1), abi.encode(makeAddr("original_sender")), OWNER, sourceTokenData, new bytes[](1)
+ );
+ }
+
+ function test_PriceNotFoundForToken_Reverts() public {
+ // Set token price to 0
+ s_priceRegistry.updatePrices(getSingleTokenPriceUpdateStruct(s_destFeeToken, 0));
+
+ Client.EVMTokenAmount[] memory srcTokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ uint256 amount1 = 100;
+ srcTokenAmounts[0].amount = amount1;
+
+ bytes memory originalSender = abi.encode(OWNER);
+
+ bytes[] memory offchainTokenData = new bytes[](srcTokenAmounts.length);
+ offchainTokenData[0] = abi.encode(0x12345678);
+
+ bytes[] memory sourceTokenData = _getDefaultSourceTokenData(srcTokenAmounts);
+
+ vm.expectRevert(abi.encodeWithSelector(AggregateRateLimiter.PriceNotFoundForToken.selector, s_destFeeToken));
+
+ s_offRamp.releaseOrMintTokens(srcTokenAmounts, originalSender, OWNER, sourceTokenData, offchainTokenData);
+ }
+
+ /// forge-config: default.fuzz.runs = 32
+ /// forge-config: ccip.fuzz.runs = 1024
+ // Uint256 gives a good range of values to test, both inside and outside of the eth address space.
+ function test_Fuzz__releaseOrMintTokens_AnyRevertIsCaught_Success(uint256 destPool) public {
+ // Input 447301751254033913445893214690834296930546521452, which is 0x4E59B44847B379578588920CA78FBF26C0B4956C
+ // triggers some Create2Deployer and causes it to fail
+ vm.assume(destPool != 447301751254033913445893214690834296930546521452);
+ bytes memory unusedVar = abi.encode(makeAddr("unused"));
+ bytes[] memory sourceTokenData = new bytes[](1);
+ sourceTokenData[0] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: unusedVar,
+ destTokenAddress: abi.encode(destPool),
+ extraData: unusedVar
+ })
+ );
+
+ try s_offRamp.releaseOrMintTokens(new Client.EVMTokenAmount[](1), unusedVar, OWNER, sourceTokenData, new bytes[](1))
+ {} catch (bytes memory reason) {
+ // Any revert should be a TokenHandlingError, InvalidEVMAddress, InvalidDataLength or NoContract as those are caught by the offramp
+ assertTrue(
+ bytes4(reason) == EVM2EVMOffRamp.TokenHandlingError.selector
+ || bytes4(reason) == Internal.InvalidEVMAddress.selector
+ || bytes4(reason) == EVM2EVMOffRamp.InvalidDataLength.selector
+ || bytes4(reason) == CallWithExactGas.NoContract.selector
+ || bytes4(reason) == EVM2EVMOffRamp.NotACompatiblePool.selector,
+ "Expected TokenHandlingError or InvalidEVMAddress"
+ );
+
+ if (destPool > type(uint160).max) {
+ assertEq(reason, abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, abi.encode(destPool)));
+ }
+ }
+ }
+}
+
+contract EVM2EVMOffRamp_getAllRateLimitTokens is EVM2EVMOffRampSetup {
+ function test_GetAllRateLimitTokens_Success() public view {
+ (address[] memory sourceTokens, address[] memory destTokens) = s_offRamp.getAllRateLimitTokens();
+
+ for (uint256 i = 0; i < s_sourceTokens.length; ++i) {
+ assertEq(s_sourceTokens[i], sourceTokens[i]);
+ assertEq(s_destTokens[i], destTokens[i]);
+ }
+ }
+}
+
+contract EVM2EVMOffRamp_updateRateLimitTokens is EVM2EVMOffRampSetup {
+ function setUp() public virtual override {
+ super.setUp();
+ // Clear rate limit tokens state
+ EVM2EVMOffRamp.RateLimitToken[] memory remove = new EVM2EVMOffRamp.RateLimitToken[](s_sourceTokens.length);
+ for (uint256 i = 0; i < s_sourceTokens.length; ++i) {
+ remove[i] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceTokens[i], destToken: s_destTokens[i]});
+ }
+ s_offRamp.updateRateLimitTokens(remove, new EVM2EVMOffRamp.RateLimitToken[](0));
+ }
+
+ function test_updateRateLimitTokens_Success() public {
+ EVM2EVMOffRamp.RateLimitToken[] memory adds = new EVM2EVMOffRamp.RateLimitToken[](2);
+ adds[0] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceTokens[0], destToken: s_destTokens[0]});
+ adds[1] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceTokens[1], destToken: s_destTokens[1]});
+
+ for (uint256 i = 0; i < adds.length; ++i) {
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.TokenAggregateRateLimitAdded(adds[i].sourceToken, adds[i].destToken);
+ }
+
+ s_offRamp.updateRateLimitTokens(new EVM2EVMOffRamp.RateLimitToken[](0), adds);
+
+ (address[] memory sourceTokens, address[] memory destTokens) = s_offRamp.getAllRateLimitTokens();
+
+ for (uint256 i = 0; i < adds.length; ++i) {
+ assertEq(adds[i].sourceToken, sourceTokens[i]);
+ assertEq(adds[i].destToken, destTokens[i]);
+ }
+ }
+
+ function test_updateRateLimitTokens_AddsAndRemoves_Success() public {
+ EVM2EVMOffRamp.RateLimitToken[] memory adds = new EVM2EVMOffRamp.RateLimitToken[](3);
+ adds[0] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceTokens[0], destToken: s_destTokens[0]});
+ adds[1] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceTokens[1], destToken: s_destTokens[1]});
+ // Add a duplicate, this should not revert the tx
+ adds[2] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceTokens[1], destToken: s_destTokens[1]});
+
+ EVM2EVMOffRamp.RateLimitToken[] memory removes = new EVM2EVMOffRamp.RateLimitToken[](1);
+ removes[0] = adds[0];
+
+ for (uint256 i = 0; i < adds.length - 1; ++i) {
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.TokenAggregateRateLimitAdded(adds[i].sourceToken, adds[i].destToken);
+ }
+
+ s_offRamp.updateRateLimitTokens(removes, adds);
+
+ for (uint256 i = 0; i < removes.length; ++i) {
+ vm.expectEmit();
+ emit EVM2EVMOffRamp.TokenAggregateRateLimitRemoved(removes[i].sourceToken, removes[i].destToken);
+ }
+
+ s_offRamp.updateRateLimitTokens(removes, new EVM2EVMOffRamp.RateLimitToken[](0));
+
+ (address[] memory sourceTokens, address[] memory destTokens) = s_offRamp.getAllRateLimitTokens();
+
+ assertEq(1, sourceTokens.length);
+ assertEq(adds[1].sourceToken, sourceTokens[0]);
+
+ assertEq(1, destTokens.length);
+ assertEq(adds[1].destToken, destTokens[0]);
+ }
+
+ function test_Fuzz_UpdateRateLimitTokens(uint8 numTokens) public {
+ // Needs to be more than 1 so that the division doesn't round down and the even makes the comparisons simpler
+ vm.assume(numTokens > 1 && numTokens % 2 == 0);
+
+ // Clear the Rate limit tokens array so the test can start from a baseline
+ (address[] memory sourceTokens, address[] memory destTokens) = s_offRamp.getAllRateLimitTokens();
+ EVM2EVMOffRamp.RateLimitToken[] memory removes = new EVM2EVMOffRamp.RateLimitToken[](sourceTokens.length);
+ for (uint256 x = 0; x < removes.length; x++) {
+ removes[x] = EVM2EVMOffRamp.RateLimitToken({sourceToken: sourceTokens[x], destToken: destTokens[x]});
+ }
+ s_offRamp.updateRateLimitTokens(removes, new EVM2EVMOffRamp.RateLimitToken[](0));
+
+ // Sanity check that the rateLimitTokens were successfully cleared
+ (sourceTokens, destTokens) = s_offRamp.getAllRateLimitTokens();
+ assertEq(sourceTokens.length, 0, "sourceTokenLength should be zero");
+
+ EVM2EVMOffRamp.RateLimitToken[] memory adds = new EVM2EVMOffRamp.RateLimitToken[](numTokens);
+
+ for (uint256 x = 0; x < numTokens; x++) {
+ address tokenAddr = vm.addr(x + 1);
+
+ // Create an array of several fake tokens to add which are deployed on the same address on both chains for simplicity
+ adds[x] = EVM2EVMOffRamp.RateLimitToken({sourceToken: tokenAddr, destToken: tokenAddr});
+ }
+
+ // Attempt to add the tokens to the RateLimitToken Array
+ s_offRamp.updateRateLimitTokens(new EVM2EVMOffRamp.RateLimitToken[](0), adds);
+
+ // Retrieve them from storage and make sure that they all match the expected adds
+ (sourceTokens, destTokens) = s_offRamp.getAllRateLimitTokens();
+
+ for (uint256 x = 0; x < sourceTokens.length; x++) {
+ // Check that the tokens match the ones we generated earlier
+ assertEq(sourceTokens[x], adds[x].sourceToken, "Source token doesn't match add");
+ assertEq(destTokens[x], adds[x].sourceToken, "dest Token doesn't match add");
+ }
+
+ // Attempt to remove half of the numTokens by removing the second half of the list and copying it to a removes array
+ removes = new EVM2EVMOffRamp.RateLimitToken[](adds.length / 2);
+
+ for (uint256 x = 0; x < adds.length / 2; x++) {
+ removes[x] = adds[x + (adds.length / 2)];
+ }
+
+ // Attempt to update again, this time adding nothing and removing the second half of the tokens
+ s_offRamp.updateRateLimitTokens(removes, new EVM2EVMOffRamp.RateLimitToken[](0));
+
+ (sourceTokens, destTokens) = s_offRamp.getAllRateLimitTokens();
+ assertEq(sourceTokens.length, adds.length / 2, "Current Rate limit token length is not half of the original adds");
+ for (uint256 x = 0; x < sourceTokens.length; x++) {
+ // Check that the tokens match the ones we generated earlier and didn't remove in the previous step
+ assertEq(sourceTokens[x], adds[x].sourceToken, "Source token doesn't match add after removes");
+ assertEq(destTokens[x], adds[x].destToken, "dest Token doesn't match add after removes");
+ }
+ }
+
+ // Reverts
+
+ function test_updateRateLimitTokens_NonOwner_Revert() public {
+ EVM2EVMOffRamp.RateLimitToken[] memory addsAndRemoves = new EVM2EVMOffRamp.RateLimitToken[](4);
+
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert("Only callable by owner");
+
+ s_offRamp.updateRateLimitTokens(addsAndRemoves, addsAndRemoves);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRampSetup.t.sol b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRampSetup.t.sol
new file mode 100644
index 00000000000..053869b88a6
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRampSetup.t.sol
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IAny2EVMMessageReceiver} from "../../interfaces/IAny2EVMMessageReceiver.sol";
+import {ICommitStore} from "../../interfaces/ICommitStore.sol";
+import {IPoolV1} from "../../interfaces/IPool.sol";
+
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {EVM2EVMOffRamp} from "../../offRamp/EVM2EVMOffRamp.sol";
+import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {TokenSetup} from "../TokenSetup.t.sol";
+import {EVM2EVMOffRampHelper} from "../helpers/EVM2EVMOffRampHelper.sol";
+import {MaybeRevertingBurnMintTokenPool} from "../helpers/MaybeRevertingBurnMintTokenPool.sol";
+import {MaybeRevertMessageReceiver} from "../helpers/receivers/MaybeRevertMessageReceiver.sol";
+import {MockCommitStore} from "../mocks/MockCommitStore.sol";
+import {OCR2BaseSetup} from "../ocr/OCR2Base.t.sol";
+import {PriceRegistrySetup} from "../priceRegistry/PriceRegistry.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract EVM2EVMOffRampSetup is TokenSetup, PriceRegistrySetup, OCR2BaseSetup {
+ MockCommitStore internal s_mockCommitStore;
+ IAny2EVMMessageReceiver internal s_receiver;
+ IAny2EVMMessageReceiver internal s_secondary_receiver;
+ MaybeRevertMessageReceiver internal s_reverting_receiver;
+
+ MaybeRevertingBurnMintTokenPool internal s_maybeRevertingPool;
+
+ EVM2EVMOffRampHelper internal s_offRamp;
+ address internal s_sourceTokenPool = makeAddr("sourceTokenPool");
+
+ function setUp() public virtual override(TokenSetup, PriceRegistrySetup, OCR2BaseSetup) {
+ TokenSetup.setUp();
+ PriceRegistrySetup.setUp();
+ OCR2BaseSetup.setUp();
+
+ s_mockCommitStore = new MockCommitStore();
+ s_receiver = new MaybeRevertMessageReceiver(false);
+ s_secondary_receiver = new MaybeRevertMessageReceiver(false);
+ s_reverting_receiver = new MaybeRevertMessageReceiver(true);
+
+ s_maybeRevertingPool = MaybeRevertingBurnMintTokenPool(s_destPoolByToken[s_destTokens[1]]);
+
+ deployOffRamp(s_mockCommitStore, s_destRouter, address(0));
+ }
+
+ function deployOffRamp(ICommitStore commitStore, Router router, address prevOffRamp) internal {
+ s_offRamp = new EVM2EVMOffRampHelper(
+ EVM2EVMOffRamp.StaticConfig({
+ commitStore: address(commitStore),
+ chainSelector: DEST_CHAIN_SELECTOR,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ onRamp: ON_RAMP_ADDRESS,
+ prevOffRamp: prevOffRamp,
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ getInboundRateLimiterConfig()
+ );
+ s_offRamp.setOCR2Config(
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ abi.encode(generateDynamicOffRampConfig(address(router), address(s_priceRegistry))),
+ s_offchainConfigVersion,
+ abi.encode("")
+ );
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](0);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](2);
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: address(s_offRamp)});
+ offRampUpdates[1] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: address(prevOffRamp)});
+ s_destRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+ EVM2EVMOffRamp.RateLimitToken[] memory tokensToAdd = new EVM2EVMOffRamp.RateLimitToken[](s_sourceTokens.length);
+ for (uint256 i = 0; i < s_sourceTokens.length; ++i) {
+ tokensToAdd[i] = EVM2EVMOffRamp.RateLimitToken({sourceToken: s_sourceTokens[i], destToken: s_destTokens[i]});
+ }
+ s_offRamp.updateRateLimitTokens(new EVM2EVMOffRamp.RateLimitToken[](0), tokensToAdd);
+ }
+
+ function generateDynamicOffRampConfig(
+ address router,
+ address priceRegistry
+ ) internal pure returns (EVM2EVMOffRamp.DynamicConfig memory) {
+ return EVM2EVMOffRamp.DynamicConfig({
+ permissionLessExecutionThresholdSeconds: PERMISSION_LESS_EXECUTION_THRESHOLD_SECONDS,
+ router: router,
+ priceRegistry: priceRegistry,
+ maxNumberOfTokensPerMsg: MAX_TOKENS_LENGTH,
+ maxDataBytes: MAX_DATA_SIZE,
+ maxPoolReleaseOrMintGas: MAX_TOKEN_POOL_RELEASE_OR_MINT_GAS,
+ maxTokenTransferGas: MAX_TOKEN_POOL_TRANSFER_GAS
+ });
+ }
+
+ function _convertToGeneralMessage(Internal.EVM2EVMMessage memory original)
+ internal
+ view
+ returns (Client.Any2EVMMessage memory message)
+ {
+ uint256 numberOfTokens = original.tokenAmounts.length;
+ Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](numberOfTokens);
+
+ for (uint256 i = 0; i < numberOfTokens; ++i) {
+ Internal.SourceTokenData memory sourceTokenData =
+ abi.decode(original.sourceTokenData[i], (Internal.SourceTokenData));
+
+ address destPoolAddress = abi.decode(sourceTokenData.destTokenAddress, (address));
+ TokenPool pool = TokenPool(destPoolAddress);
+ destTokenAmounts[i].token = address(pool.getToken());
+ destTokenAmounts[i].amount = original.tokenAmounts[i].amount;
+ }
+
+ return Client.Any2EVMMessage({
+ messageId: original.messageId,
+ sourceChainSelector: original.sourceChainSelector,
+ sender: abi.encode(original.sender),
+ data: original.data,
+ destTokenAmounts: destTokenAmounts
+ });
+ }
+
+ function _generateAny2EVMMessageNoTokens(uint64 sequenceNumber)
+ internal
+ view
+ returns (Internal.EVM2EVMMessage memory)
+ {
+ return _generateAny2EVMMessage(sequenceNumber, new Client.EVMTokenAmount[](0), false);
+ }
+
+ function _generateAny2EVMMessageWithTokens(
+ uint64 sequenceNumber,
+ uint256[] memory amounts
+ ) internal view returns (Internal.EVM2EVMMessage memory) {
+ Client.EVMTokenAmount[] memory tokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ for (uint256 i = 0; i < tokenAmounts.length; ++i) {
+ tokenAmounts[i].amount = amounts[i];
+ }
+ return _generateAny2EVMMessage(sequenceNumber, tokenAmounts, false);
+ }
+
+ function _generateAny2EVMMessage(
+ uint64 sequenceNumber,
+ Client.EVMTokenAmount[] memory tokenAmounts,
+ bool allowOutOfOrderExecution
+ ) internal view returns (Internal.EVM2EVMMessage memory) {
+ bytes memory data = abi.encode(0);
+ Internal.EVM2EVMMessage memory message = Internal.EVM2EVMMessage({
+ sequenceNumber: sequenceNumber,
+ sender: OWNER,
+ nonce: allowOutOfOrderExecution ? 0 : sequenceNumber,
+ gasLimit: GAS_LIMIT,
+ strict: false,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ receiver: address(s_receiver),
+ data: data,
+ tokenAmounts: tokenAmounts,
+ sourceTokenData: new bytes[](tokenAmounts.length),
+ feeToken: s_destFeeToken,
+ feeTokenAmount: uint256(0),
+ messageId: ""
+ });
+
+ // Correctly set the TokenDataPayload for each token. Tokens have to be set up in the TokenSetup.
+ for (uint256 i = 0; i < tokenAmounts.length; ++i) {
+ message.sourceTokenData[i] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[tokenAmounts[i].token]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[tokenAmounts[i].token]),
+ extraData: ""
+ })
+ );
+ }
+
+ message.messageId = Internal._hash(
+ message,
+ keccak256(
+ abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, ON_RAMP_ADDRESS)
+ )
+ );
+
+ return message;
+ }
+
+ function _generateSingleBasicMessage() internal view returns (Internal.EVM2EVMMessage[] memory) {
+ Internal.EVM2EVMMessage[] memory messages = new Internal.EVM2EVMMessage[](1);
+ messages[0] = _generateAny2EVMMessageNoTokens(1);
+ return messages;
+ }
+
+ function _generateMessagesWithTokens() internal view returns (Internal.EVM2EVMMessage[] memory) {
+ Internal.EVM2EVMMessage[] memory messages = new Internal.EVM2EVMMessage[](2);
+ Client.EVMTokenAmount[] memory tokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ tokenAmounts[0].amount = 1e18;
+ tokenAmounts[1].amount = 5e18;
+ messages[0] = _generateAny2EVMMessage(1, tokenAmounts, false);
+ messages[1] = _generateAny2EVMMessage(2, tokenAmounts, false);
+
+ return messages;
+ }
+
+ function _generateReportFromMessages(Internal.EVM2EVMMessage[] memory messages)
+ internal
+ pure
+ returns (Internal.ExecutionReport memory)
+ {
+ bytes[][] memory offchainTokenData = new bytes[][](messages.length);
+
+ for (uint256 i = 0; i < messages.length; ++i) {
+ offchainTokenData[i] = new bytes[](messages[i].tokenAmounts.length);
+ }
+
+ return Internal.ExecutionReport({
+ proofs: new bytes32[](0),
+ proofFlagBits: 2 ** 256 - 1,
+ messages: messages,
+ offchainTokenData: offchainTokenData
+ });
+ }
+
+ function _getGasLimitsFromMessages(Internal.EVM2EVMMessage[] memory messages)
+ internal
+ pure
+ returns (uint256[] memory)
+ {
+ uint256[] memory gasLimits = new uint256[](messages.length);
+ for (uint256 i = 0; i < messages.length; ++i) {
+ gasLimits[i] = messages[i].gasLimit;
+ }
+
+ return gasLimits;
+ }
+
+ function _assertSameConfig(EVM2EVMOffRamp.DynamicConfig memory a, EVM2EVMOffRamp.DynamicConfig memory b) public pure {
+ assertEq(a.permissionLessExecutionThresholdSeconds, b.permissionLessExecutionThresholdSeconds);
+ assertEq(a.router, b.router);
+ assertEq(a.priceRegistry, b.priceRegistry);
+ assertEq(a.maxNumberOfTokensPerMsg, b.maxNumberOfTokensPerMsg);
+ assertEq(a.maxDataBytes, b.maxDataBytes);
+ assertEq(a.maxPoolReleaseOrMintGas, b.maxPoolReleaseOrMintGas);
+ assertEq(a.maxTokenTransferGas, b.maxTokenTransferGas);
+ }
+
+ function _getDefaultSourceTokenData(Client.EVMTokenAmount[] memory srcTokenAmounts)
+ internal
+ view
+ returns (bytes[] memory)
+ {
+ bytes[] memory sourceTokenData = new bytes[](srcTokenAmounts.length);
+ for (uint256 i = 0; i < srcTokenAmounts.length; ++i) {
+ sourceTokenData[i] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[srcTokenAmounts[i].token]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[srcTokenAmounts[i].token]),
+ extraData: ""
+ })
+ );
+ }
+ return sourceTokenData;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRamp.t.sol b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRamp.t.sol
new file mode 100644
index 00000000000..bc7fac95be6
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRamp.t.sol
@@ -0,0 +1,720 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IMessageInterceptor} from "../../interfaces/IMessageInterceptor.sol";
+import {ITokenAdminRegistry} from "../../interfaces/ITokenAdminRegistry.sol";
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {MultiAggregateRateLimiter} from "../../MultiAggregateRateLimiter.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {USDPriceWith18Decimals} from "../../libraries/USDPriceWith18Decimals.sol";
+import {EVM2EVMMultiOnRamp} from "../../onRamp/EVM2EVMMultiOnRamp.sol";
+import {EVM2EVMOnRamp} from "../../onRamp/EVM2EVMOnRamp.sol";
+import {TokenAdminRegistry} from "../../tokenAdminRegistry/TokenAdminRegistry.sol";
+import {EVM2EVMOnRampHelper} from "../helpers/EVM2EVMOnRampHelper.sol";
+import {MaybeRevertingBurnMintTokenPool} from "../helpers/MaybeRevertingBurnMintTokenPool.sol";
+import {MessageInterceptorHelper} from "../helpers/MessageInterceptorHelper.sol";
+import "./EVM2EVMMultiOnRampSetup.t.sol";
+
+contract EVM2EVMMultiOnRamp_constructor is EVM2EVMMultiOnRampSetup {
+ function test_Constructor_Success() public {
+ EVM2EVMMultiOnRamp.StaticConfig memory staticConfig = EVM2EVMMultiOnRamp.StaticConfig({
+ chainSelector: SOURCE_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ nonceManager: address(s_outboundNonceManager),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ });
+ EVM2EVMMultiOnRamp.DynamicConfig memory dynamicConfig =
+ _generateDynamicMultiOnRampConfig(address(s_sourceRouter), address(s_priceRegistry));
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.ConfigSet(staticConfig, dynamicConfig);
+
+ _deployOnRamp(
+ SOURCE_CHAIN_SELECTOR, address(s_sourceRouter), address(s_outboundNonceManager), address(s_tokenAdminRegistry)
+ );
+
+ EVM2EVMMultiOnRamp.StaticConfig memory gotStaticConfig = s_onRamp.getStaticConfig();
+ _assertStaticConfigsEqual(staticConfig, gotStaticConfig);
+
+ EVM2EVMMultiOnRamp.DynamicConfig memory gotDynamicConfig = s_onRamp.getDynamicConfig();
+ _assertDynamicConfigsEqual(dynamicConfig, gotDynamicConfig);
+
+ // Initial values
+ assertEq("EVM2EVMMultiOnRamp 1.6.0-dev", s_onRamp.typeAndVersion());
+ assertEq(OWNER, s_onRamp.owner());
+ assertEq(1, s_onRamp.getExpectedNextSequenceNumber(DEST_CHAIN_SELECTOR));
+ }
+
+ function test_Constructor_InvalidConfigChainSelectorEqZero_Revert() public {
+ vm.expectRevert(EVM2EVMMultiOnRamp.InvalidConfig.selector);
+ new EVM2EVMMultiOnRampHelper(
+ EVM2EVMMultiOnRamp.StaticConfig({
+ chainSelector: 0,
+ rmnProxy: address(s_mockRMN),
+ nonceManager: address(s_outboundNonceManager),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ _generateDynamicMultiOnRampConfig(address(s_sourceRouter), address(s_priceRegistry))
+ );
+ }
+
+ function test_Constructor_InvalidConfigRMNProxyEqAddressZero_Revert() public {
+ vm.expectRevert(EVM2EVMMultiOnRamp.InvalidConfig.selector);
+ s_onRamp = new EVM2EVMMultiOnRampHelper(
+ EVM2EVMMultiOnRamp.StaticConfig({
+ chainSelector: SOURCE_CHAIN_SELECTOR,
+ rmnProxy: address(0),
+ nonceManager: address(s_outboundNonceManager),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ _generateDynamicMultiOnRampConfig(address(s_sourceRouter), address(s_priceRegistry))
+ );
+ }
+
+ function test_Constructor_InvalidConfigNonceManagerEqAddressZero_Revert() public {
+ vm.expectRevert(EVM2EVMMultiOnRamp.InvalidConfig.selector);
+ new EVM2EVMMultiOnRampHelper(
+ EVM2EVMMultiOnRamp.StaticConfig({
+ chainSelector: SOURCE_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ nonceManager: address(0),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ _generateDynamicMultiOnRampConfig(address(s_sourceRouter), address(s_priceRegistry))
+ );
+ }
+
+ function test_Constructor_InvalidConfigTokenAdminRegistryEqAddressZero_Revert() public {
+ vm.expectRevert(EVM2EVMMultiOnRamp.InvalidConfig.selector);
+ new EVM2EVMMultiOnRampHelper(
+ EVM2EVMMultiOnRamp.StaticConfig({
+ chainSelector: SOURCE_CHAIN_SELECTOR,
+ rmnProxy: address(s_mockRMN),
+ nonceManager: address(s_outboundNonceManager),
+ tokenAdminRegistry: address(0)
+ }),
+ _generateDynamicMultiOnRampConfig(address(s_sourceRouter), address(s_priceRegistry))
+ );
+ }
+}
+
+contract EVM2EVMMultiOnRamp_forwardFromRouter is EVM2EVMMultiOnRampSetup {
+ struct LegacyExtraArgs {
+ uint256 gasLimit;
+ bool strict;
+ }
+
+ function setUp() public virtual override {
+ super.setUp();
+
+ address[] memory feeTokens = new address[](1);
+ feeTokens[0] = s_sourceTokens[1];
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+
+ // Since we'll mostly be testing for valid calls from the router we'll
+ // mock all calls to be originating from the router and re-mock in
+ // tests that require failure.
+ vm.startPrank(address(s_sourceRouter));
+ }
+
+ function test_ForwardFromRouterSuccessCustomExtraArgs() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT * 2}));
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouterSuccessLegacyExtraArgs() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs =
+ abi.encodeWithSelector(Client.EVM_EXTRA_ARGS_V1_TAG, LegacyExtraArgs({gasLimit: GAS_LIMIT * 2, strict: true}));
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ // We expect the message to be emitted with strict = false.
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouterSuccessEmptyExtraArgs() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = "";
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ // We expect the message to be emitted with strict = false.
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouter_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouterExtraArgsV2_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = abi.encodeWithSelector(
+ Client.EVM_EXTRA_ARGS_V2_TAG, Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT * 2, allowOutOfOrderExecution: false})
+ );
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = abi.encodeWithSelector(
+ Client.EVM_EXTRA_ARGS_V2_TAG, Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT * 2, allowOutOfOrderExecution: true})
+ );
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ShouldIncrementSeqNumAndNonce_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ for (uint64 i = 1; i < 4; ++i) {
+ uint64 nonceBefore = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER);
+ uint64 sequenceNumberBefore = s_onRamp.getExpectedNextSequenceNumber(DEST_CHAIN_SELECTOR) - 1;
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, i, i, 0, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ uint64 nonceAfter = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER);
+ uint64 sequenceNumberAfter = s_onRamp.getExpectedNextSequenceNumber(DEST_CHAIN_SELECTOR) - 1;
+ assertEq(nonceAfter, nonceBefore + 1);
+ assertEq(sequenceNumberAfter, sequenceNumberBefore + 1);
+ }
+ }
+
+ function test_ShouldIncrementNonceOnlyOnOrdered_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = abi.encodeWithSelector(
+ Client.EVM_EXTRA_ARGS_V2_TAG, Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT * 2, allowOutOfOrderExecution: true})
+ );
+
+ for (uint64 i = 1; i < 4; ++i) {
+ uint64 nonceBefore = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER);
+ uint64 sequenceNumberBefore = s_onRamp.getExpectedNextSequenceNumber(DEST_CHAIN_SELECTOR) - 1;
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, i, i, 0, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ uint64 nonceAfter = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER);
+ uint64 sequenceNumberAfter = s_onRamp.getExpectedNextSequenceNumber(DEST_CHAIN_SELECTOR) - 1;
+ assertEq(nonceAfter, nonceBefore);
+ assertEq(sequenceNumberAfter, sequenceNumberBefore + 1);
+ }
+ }
+
+ function test_ShouldStoreLinkFees() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.FeePaid(s_sourceFeeToken, feeAmount);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(address(s_onRamp)), feeAmount);
+ }
+
+ function test_ShouldStoreNonLinkFees() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = s_sourceTokens[1];
+
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceTokens[1]).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ // Calculate conversion done by prices contract
+ uint256 feeTokenPrice = s_priceRegistry.getTokenPrice(s_sourceTokens[1]).value;
+ uint256 linkTokenPrice = s_priceRegistry.getTokenPrice(s_sourceFeeToken).value;
+ uint256 conversionRate = (feeTokenPrice * 1e18) / linkTokenPrice;
+ uint256 expectedJuels = (feeAmount * conversionRate) / 1e18;
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.FeePaid(s_sourceTokens[1], expectedJuels);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+
+ assertEq(IERC20(s_sourceTokens[1]).balanceOf(address(s_onRamp)), feeAmount);
+ }
+
+ // Make sure any valid sender, receiver and feeAmount can be handled.
+ // @TODO Temporarily setting lower fuzz run as 256 triggers snapshot gas off by 1 error.
+ // https://github.com/foundry-rs/foundry/issues/5689
+ /// forge-dynamicConfig: default.fuzz.runs = 32
+ /// forge-dynamicConfig: ccip.fuzz.runs = 32
+ function test_Fuzz_ForwardFromRouter_Success(address originalSender, address receiver, uint96 feeTokenAmount) public {
+ // To avoid RouterMustSetOriginalSender
+ vm.assume(originalSender != address(0));
+ vm.assume(uint160(receiver) >= Internal.PRECOMPILE_SPACE);
+ feeTokenAmount = uint96(bound(feeTokenAmount, 0, MAX_MSG_FEES_JUELS));
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.receiver = abi.encode(receiver);
+
+ // Make sure the tokens are in the contract
+ deal(s_sourceFeeToken, address(s_onRamp), feeTokenAmount);
+
+ Internal.EVM2AnyRampMessage memory expectedEvent = _messageToEvent(message, 1, 1, feeTokenAmount, originalSender);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.FeePaid(s_sourceFeeToken, feeTokenAmount);
+ vm.expectEmit(false, false, false, true);
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, expectedEvent);
+
+ // Assert the message Id is correct
+ assertEq(
+ expectedEvent.header.messageId,
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeTokenAmount, originalSender)
+ );
+ }
+
+ function test_forwardFromRouter_WithValidation_Success() public {
+ _enableOutboundMessageValidator();
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT * 2}));
+ uint256 feeAmount = 1234567890;
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 1e18;
+ message.tokenAmounts[0].token = s_sourceTokens[0];
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+ s_outboundMessageValidator.setMessageIdValidationState(keccak256(abi.encode(message)), false);
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.CCIPSendRequested(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ // Reverts
+
+ function test_Paused_Revert() public {
+ // We pause by disabling the whitelist
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ address router = address(0);
+ s_onRamp.setDynamicConfig(_generateDynamicMultiOnRampConfig(router, address(2)));
+ vm.expectRevert(EVM2EVMMultiOnRamp.MustBeCalledByRouter.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, OWNER);
+ }
+
+ function test_InvalidExtraArgsTag_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = bytes("bad args");
+
+ vm.expectRevert(EVM2EVMMultiOnRamp.InvalidExtraArgsTag.selector);
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_Permissions_Revert() public {
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ vm.expectRevert(EVM2EVMMultiOnRamp.MustBeCalledByRouter.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, OWNER);
+ }
+
+ function test_OriginalSender_Revert() public {
+ vm.expectRevert(EVM2EVMMultiOnRamp.RouterMustSetOriginalSender.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, address(0));
+ }
+
+ function test_MessageValidationError_Revert() public {
+ _enableOutboundMessageValidator();
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT * 2}));
+ uint256 feeAmount = 1234567890;
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 1e18;
+ message.tokenAmounts[0].token = s_sourceTokens[0];
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+ s_outboundMessageValidator.setMessageIdValidationState(keccak256(abi.encode(message)), true);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(IMessageInterceptor.MessageValidationError.selector, bytes("Invalid message"))
+ );
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_CannotSendZeroTokens_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 0;
+ message.tokenAmounts[0].token = s_sourceTokens[0];
+ vm.expectRevert(EVM2EVMMultiOnRamp.CannotSendZeroTokens.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, STRANGER);
+ }
+
+ function test_UnsupportedToken_Revert() public {
+ address wrongToken = address(1);
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].token = wrongToken;
+ message.tokenAmounts[0].amount = 1;
+
+ // We need to set the price of this new token to be able to reach
+ // the proper revert point. This must be called by the owner.
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+
+ Internal.PriceUpdates memory priceUpdates = getSingleTokenPriceUpdateStruct(wrongToken, 1);
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ // Change back to the router
+ vm.startPrank(address(s_sourceRouter));
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOnRamp.UnsupportedToken.selector, wrongToken));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_forwardFromRouter_UnsupportedToken_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 1;
+ message.tokenAmounts[0].token = address(1);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOnRamp.UnsupportedToken.selector, message.tokenAmounts[0].token));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_MesssageFeeTooHigh_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ vm.expectRevert(
+ abi.encodeWithSelector(PriceRegistry.MessageFeeTooHigh.selector, MAX_MSG_FEES_JUELS + 1, MAX_MSG_FEES_JUELS)
+ );
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, MAX_MSG_FEES_JUELS + 1, OWNER);
+ }
+
+ function test_SourceTokenDataTooLarge_Revert() public {
+ address sourceETH = s_sourceTokens[1];
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+
+ MaybeRevertingBurnMintTokenPool newPool = new MaybeRevertingBurnMintTokenPool(
+ BurnMintERC677(sourceETH), new address[](0), address(s_mockRMN), address(s_sourceRouter)
+ );
+ BurnMintERC677(sourceETH).grantMintAndBurnRoles(address(newPool));
+ deal(address(sourceETH), address(newPool), type(uint256).max);
+
+ // Add TokenPool to OnRamp
+ s_tokenAdminRegistry.setPool(sourceETH, address(newPool));
+
+ // Allow chain in TokenPool
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_destTokenPool),
+ remoteTokenAddress: abi.encode(s_destToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ newPool.applyChainUpdates(chainUpdates);
+
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(address(sourceETH), 1000);
+
+ // No data set, should succeed
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Set max data length, should succeed
+ vm.startPrank(OWNER);
+ newPool.setSourceTokenData(new bytes(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES));
+
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Set data to max length +1, should revert
+ vm.startPrank(OWNER);
+ newPool.setSourceTokenData(new bytes(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES + 1));
+
+ vm.startPrank(address(s_sourceRouter));
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.SourceTokenDataTooLarge.selector, sourceETH));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Set token config to allow larger data
+ vm.startPrank(OWNER);
+ PriceRegistry.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ _generateTokenTransferFeeConfigArgs(1, 1);
+ tokenTransferFeeConfigArgs[0].destChainSelector = DEST_CHAIN_SELECTOR;
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token = sourceETH;
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig = PriceRegistry
+ .TokenTransferFeeConfig({
+ minFeeUSDCents: 1,
+ maxFeeUSDCents: 0,
+ deciBps: 0,
+ destGasOverhead: 0,
+ destBytesOverhead: uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) + 32,
+ isEnabled: true
+ });
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(
+ tokenTransferFeeConfigArgs, new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](0)
+ );
+
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Set the token data larger than the configured token data, should revert
+ vm.startPrank(OWNER);
+ newPool.setSourceTokenData(new bytes(uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) + 32 + 1));
+
+ vm.startPrank(address(s_sourceRouter));
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.SourceTokenDataTooLarge.selector, sourceETH));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+}
+
+contract EVM2EVMMultiOnRamp_getSupportedTokens is EVM2EVMMultiOnRampSetup {
+ function test_GetSupportedTokens_Revert() public {
+ vm.expectRevert(EVM2EVMMultiOnRamp.GetSupportedTokensFunctionalityRemovedCheckAdminRegistry.selector);
+ s_onRamp.getSupportedTokens(DEST_CHAIN_SELECTOR);
+ }
+}
+
+contract EVM2EVMMultiOnRamp_getFee is EVM2EVMMultiOnRampSetup {
+ using USDPriceWith18Decimals for uint224;
+
+ function test_EmptyMessage_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = testTokens[i];
+
+ uint256 feeAmount = s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+ uint256 expectedFeeAmount = s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+
+ assertEq(expectedFeeAmount, feeAmount);
+ }
+ }
+
+ function test_SingleTokenMessage_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ uint256 tokenAmount = 10000e18;
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, tokenAmount);
+ message.feeToken = testTokens[i];
+
+ uint256 feeAmount = s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+ uint256 expectedFeeAmount = s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+
+ assertEq(expectedFeeAmount, feeAmount);
+ }
+ }
+
+ // Reverts
+
+ function test_Unhealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMMultiOnRamp.CursedByRMN.selector, DEST_CHAIN_SELECTOR));
+ s_onRamp.getFee(DEST_CHAIN_SELECTOR, _generateEmptyMessage());
+ }
+
+ function test_EnforceOutOfOrder_Revert() public {
+ // Update dynamic config to enforce allowOutOfOrderExecution = true.
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ destChainConfigArgs[0].destChainConfig.enforceOutOfOrder = true;
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+ vm.stopPrank();
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ // Empty extraArgs to should revert since it enforceOutOfOrder is true.
+ message.extraArgs = "";
+
+ vm.expectRevert(PriceRegistry.ExtraArgOutOfOrderExecutionMustBeTrue.selector);
+ s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+ }
+}
+
+contract EVM2EVMMultiOnRamp_setDynamicConfig is EVM2EVMMultiOnRampSetup {
+ function test_SetDynamicConfig_Success() public {
+ EVM2EVMMultiOnRamp.StaticConfig memory staticConfig = s_onRamp.getStaticConfig();
+ EVM2EVMMultiOnRamp.DynamicConfig memory newConfig = EVM2EVMMultiOnRamp.DynamicConfig({
+ router: address(2134),
+ priceRegistry: address(23423),
+ messageValidator: makeAddr("messageValidator"),
+ feeAggregator: FEE_AGGREGATOR
+ });
+
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.ConfigSet(staticConfig, newConfig);
+
+ s_onRamp.setDynamicConfig(newConfig);
+
+ EVM2EVMMultiOnRamp.DynamicConfig memory gotDynamicConfig = s_onRamp.getDynamicConfig();
+ assertEq(newConfig.router, gotDynamicConfig.router);
+ assertEq(newConfig.priceRegistry, gotDynamicConfig.priceRegistry);
+ }
+
+ // Reverts
+
+ function test_SetConfigInvalidConfigPriceRegistryEqAddressZero_Revert() public {
+ EVM2EVMMultiOnRamp.DynamicConfig memory newConfig = EVM2EVMMultiOnRamp.DynamicConfig({
+ router: address(2134),
+ priceRegistry: address(0),
+ feeAggregator: FEE_AGGREGATOR,
+ messageValidator: makeAddr("messageValidator")
+ });
+
+ vm.expectRevert(EVM2EVMMultiOnRamp.InvalidConfig.selector);
+ s_onRamp.setDynamicConfig(newConfig);
+ }
+
+ function test_SetConfigInvalidConfig_Revert() public {
+ EVM2EVMMultiOnRamp.DynamicConfig memory newConfig = EVM2EVMMultiOnRamp.DynamicConfig({
+ router: address(1),
+ priceRegistry: address(23423),
+ messageValidator: address(0),
+ feeAggregator: FEE_AGGREGATOR
+ });
+
+ // Invalid price reg reverts.
+ newConfig.priceRegistry = address(0);
+ vm.expectRevert(EVM2EVMMultiOnRamp.InvalidConfig.selector);
+ s_onRamp.setDynamicConfig(newConfig);
+ }
+
+ function test_SetConfigInvalidConfigFeeAggregatorEqAddressZero_Revert() public {
+ EVM2EVMMultiOnRamp.DynamicConfig memory newConfig = EVM2EVMMultiOnRamp.DynamicConfig({
+ router: address(2134),
+ priceRegistry: address(23423),
+ messageValidator: address(0),
+ feeAggregator: address(0)
+ });
+ vm.expectRevert(EVM2EVMMultiOnRamp.InvalidConfig.selector);
+ s_onRamp.setDynamicConfig(newConfig);
+ }
+
+ function test_SetConfigOnlyOwner_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+ s_onRamp.setDynamicConfig(_generateDynamicMultiOnRampConfig(address(1), address(2)));
+ vm.startPrank(ADMIN);
+ vm.expectRevert("Only callable by owner");
+ s_onRamp.setDynamicConfig(_generateDynamicMultiOnRampConfig(address(1), address(2)));
+ }
+}
+
+contract EVM2EVMMultiOnRamp_withdrawFeeTokens is EVM2EVMMultiOnRampSetup {
+ mapping(address => uint256) internal s_nopFees;
+
+ function setUp() public virtual override {
+ super.setUp();
+
+ // Since we'll mostly be testing for valid calls from the router we'll
+ // mock all calls to be originating from the router and re-mock in
+ // tests that require failure.
+ vm.startPrank(address(s_sourceRouter));
+
+ uint256 feeAmount = 1234567890;
+
+ // Send a bunch of messages, increasing the juels in the contract
+ for (uint256 i = 0; i < s_sourceFeeTokens.length; ++i) {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = s_sourceFeeTokens[i % s_sourceFeeTokens.length];
+ uint256 newFeeTokenBalance = IERC20(message.feeToken).balanceOf(address(s_onRamp)) + feeAmount;
+ deal(message.feeToken, address(s_onRamp), newFeeTokenBalance);
+ s_nopFees[message.feeToken] = newFeeTokenBalance;
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+ }
+
+ function test_Fuzz_WithdrawFeeTokens_Success(uint256[5] memory amounts) public {
+ vm.startPrank(OWNER);
+ address[] memory feeTokens = new address[](amounts.length);
+ for (uint256 i = 0; i < amounts.length; ++i) {
+ vm.assume(amounts[i] > 0);
+ feeTokens[i] = _deploySourceToken("", amounts[i], 18);
+ IERC20(feeTokens[i]).transfer(address(s_onRamp), amounts[i]);
+ }
+
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+
+ for (uint256 i = 0; i < feeTokens.length; ++i) {
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.FeeTokenWithdrawn(FEE_AGGREGATOR, feeTokens[i], amounts[i]);
+ }
+
+ s_onRamp.withdrawFeeTokens();
+
+ for (uint256 i = 0; i < feeTokens.length; ++i) {
+ assertEq(IERC20(feeTokens[i]).balanceOf(FEE_AGGREGATOR), amounts[i]);
+ assertEq(IERC20(feeTokens[i]).balanceOf(address(s_onRamp)), 0);
+ }
+ }
+
+ function test_WithdrawFeeTokens_Success() public {
+ vm.expectEmit();
+ emit EVM2EVMMultiOnRamp.FeeTokenWithdrawn(FEE_AGGREGATOR, s_sourceFeeToken, s_nopFees[s_sourceFeeToken]);
+
+ s_onRamp.withdrawFeeTokens();
+
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(FEE_AGGREGATOR), s_nopFees[s_sourceFeeToken]);
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(address(s_onRamp)), 0);
+ }
+}
+
+contract EVM2EVMMultiOnRamp_getTokenPool is EVM2EVMMultiOnRampSetup {
+ function test_GetTokenPool_Success() public view {
+ assertEq(
+ s_sourcePoolByToken[s_sourceTokens[0]],
+ address(s_onRamp.getPoolBySourceToken(DEST_CHAIN_SELECTOR, IERC20(s_sourceTokens[0])))
+ );
+ assertEq(
+ s_sourcePoolByToken[s_sourceTokens[1]],
+ address(s_onRamp.getPoolBySourceToken(DEST_CHAIN_SELECTOR, IERC20(s_sourceTokens[1])))
+ );
+
+ address wrongToken = address(123);
+ address nonExistentPool = address(s_onRamp.getPoolBySourceToken(DEST_CHAIN_SELECTOR, IERC20(wrongToken)));
+
+ assertEq(address(0), nonExistentPool);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRampSetup.t.sol b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRampSetup.t.sol
new file mode 100644
index 00000000000..f085185753d
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMMultiOnRampSetup.t.sol
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPoolV1} from "../../interfaces/IPool.sol";
+
+import {AuthorizedCallers} from "../../../shared/access/AuthorizedCallers.sol";
+import {NonceManager} from "../../NonceManager.sol";
+import {PriceRegistry} from "../../PriceRegistry.sol";
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {EVM2EVMMultiOnRamp} from "../../onRamp/EVM2EVMMultiOnRamp.sol";
+import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {TokenAdminRegistry} from "../../tokenAdminRegistry/TokenAdminRegistry.sol";
+import {TokenSetup} from "../TokenSetup.t.sol";
+import {EVM2EVMMultiOnRampHelper} from "../helpers/EVM2EVMMultiOnRampHelper.sol";
+import {MessageInterceptorHelper} from "../helpers/MessageInterceptorHelper.sol";
+import {PriceRegistryFeeSetup} from "../priceRegistry/PriceRegistry.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract EVM2EVMMultiOnRampSetup is TokenSetup, PriceRegistryFeeSetup {
+ uint256 internal immutable i_tokenAmount0 = 9;
+ uint256 internal immutable i_tokenAmount1 = 7;
+
+ bytes32 internal s_metadataHash;
+
+ EVM2EVMMultiOnRampHelper internal s_onRamp;
+ MessageInterceptorHelper internal s_outboundMessageValidator;
+ address[] internal s_offRamps;
+ NonceManager internal s_outboundNonceManager;
+
+ function setUp() public virtual override(TokenSetup, PriceRegistryFeeSetup) {
+ TokenSetup.setUp();
+ PriceRegistryFeeSetup.setUp();
+
+ s_outboundMessageValidator = new MessageInterceptorHelper();
+ s_outboundNonceManager = new NonceManager(new address[](0));
+ (s_onRamp, s_metadataHash) = _deployOnRamp(
+ SOURCE_CHAIN_SELECTOR, address(s_sourceRouter), address(s_outboundNonceManager), address(s_tokenAdminRegistry)
+ );
+
+ s_offRamps = new address[](2);
+ s_offRamps[0] = address(10);
+ s_offRamps[1] = address(11);
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](2);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: address(s_onRamp)});
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: s_offRamps[0]});
+ offRampUpdates[1] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: s_offRamps[1]});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+
+ // Pre approve the first token so the gas estimates of the tests
+ // only cover actual gas usage from the ramps
+ IERC20(s_sourceTokens[0]).approve(address(s_sourceRouter), 2 ** 128);
+ IERC20(s_sourceTokens[1]).approve(address(s_sourceRouter), 2 ** 128);
+ }
+
+ function _generateTokenMessage() public view returns (Client.EVM2AnyMessage memory) {
+ Client.EVMTokenAmount[] memory tokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ tokenAmounts[0].amount = i_tokenAmount0;
+ tokenAmounts[1].amount = i_tokenAmount1;
+ return Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ }
+
+ function _messageToEvent(
+ Client.EVM2AnyMessage memory message,
+ uint64 seqNum,
+ uint64 nonce,
+ uint256 feeTokenAmount,
+ address originalSender
+ ) public view returns (Internal.EVM2AnyRampMessage memory) {
+ return _messageToEvent(
+ message,
+ SOURCE_CHAIN_SELECTOR,
+ DEST_CHAIN_SELECTOR,
+ seqNum,
+ nonce,
+ feeTokenAmount,
+ originalSender,
+ s_metadataHash,
+ s_tokenAdminRegistry
+ );
+ }
+
+ function _generateDynamicMultiOnRampConfig(
+ address router,
+ address priceRegistry
+ ) internal pure returns (EVM2EVMMultiOnRamp.DynamicConfig memory) {
+ return EVM2EVMMultiOnRamp.DynamicConfig({
+ router: router,
+ priceRegistry: priceRegistry,
+ messageValidator: address(0),
+ feeAggregator: FEE_AGGREGATOR
+ });
+ }
+
+ // Slicing is only available for calldata. So we have to build a new bytes array.
+ function _removeFirst4Bytes(bytes memory data) internal pure returns (bytes memory) {
+ bytes memory result = new bytes(data.length - 4);
+ for (uint256 i = 4; i < data.length; ++i) {
+ result[i - 4] = data[i];
+ }
+ return result;
+ }
+
+ function _deployOnRamp(
+ uint64 sourceChainSelector,
+ address sourceRouter,
+ address nonceManager,
+ address tokenAdminRegistry
+ ) internal returns (EVM2EVMMultiOnRampHelper, bytes32 metadataHash) {
+ EVM2EVMMultiOnRampHelper onRamp = new EVM2EVMMultiOnRampHelper(
+ EVM2EVMMultiOnRamp.StaticConfig({
+ chainSelector: sourceChainSelector,
+ rmnProxy: address(s_mockRMN),
+ nonceManager: nonceManager,
+ tokenAdminRegistry: tokenAdminRegistry
+ }),
+ _generateDynamicMultiOnRampConfig(sourceRouter, address(s_priceRegistry))
+ );
+
+ address[] memory authorizedCallers = new address[](1);
+ authorizedCallers[0] = address(onRamp);
+
+ NonceManager(nonceManager).applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: authorizedCallers, removedCallers: new address[](0)})
+ );
+
+ return (
+ onRamp,
+ keccak256(abi.encode(Internal.EVM_2_ANY_MESSAGE_HASH, sourceChainSelector, DEST_CHAIN_SELECTOR, address(onRamp)))
+ );
+ }
+
+ function _enableOutboundMessageValidator() internal {
+ (, address msgSender,) = vm.readCallers();
+
+ bool resetPrank = false;
+
+ if (msgSender != OWNER) {
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ resetPrank = true;
+ }
+
+ EVM2EVMMultiOnRamp.DynamicConfig memory dynamicConfig = s_onRamp.getDynamicConfig();
+ dynamicConfig.messageValidator = address(s_outboundMessageValidator);
+ s_onRamp.setDynamicConfig(dynamicConfig);
+
+ if (resetPrank) {
+ vm.stopPrank();
+ vm.startPrank(msgSender);
+ }
+ }
+
+ function _assertStaticConfigsEqual(
+ EVM2EVMMultiOnRamp.StaticConfig memory a,
+ EVM2EVMMultiOnRamp.StaticConfig memory b
+ ) internal pure {
+ assertEq(a.chainSelector, b.chainSelector);
+ assertEq(a.rmnProxy, b.rmnProxy);
+ assertEq(a.tokenAdminRegistry, b.tokenAdminRegistry);
+ }
+
+ function _assertDynamicConfigsEqual(
+ EVM2EVMMultiOnRamp.DynamicConfig memory a,
+ EVM2EVMMultiOnRamp.DynamicConfig memory b
+ ) internal pure {
+ assertEq(a.router, b.router);
+ assertEq(a.priceRegistry, b.priceRegistry);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRamp.t.sol b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRamp.t.sol
new file mode 100644
index 00000000000..197a87b7081
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRamp.t.sol
@@ -0,0 +1,1986 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITokenAdminRegistry} from "../../interfaces/ITokenAdminRegistry.sol";
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {AggregateRateLimiter} from "../../AggregateRateLimiter.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {USDPriceWith18Decimals} from "../../libraries/USDPriceWith18Decimals.sol";
+import {EVM2EVMOnRamp} from "../../onRamp/EVM2EVMOnRamp.sol";
+import {TokenAdminRegistry} from "../../tokenAdminRegistry/TokenAdminRegistry.sol";
+import {MaybeRevertingBurnMintTokenPool} from "../helpers/MaybeRevertingBurnMintTokenPool.sol";
+import "./EVM2EVMOnRampSetup.t.sol";
+
+contract EVM2EVMOnRamp_constructor is EVM2EVMOnRampSetup {
+ function test_Constructor_Success() public {
+ EVM2EVMOnRamp.StaticConfig memory staticConfig = EVM2EVMOnRamp.StaticConfig({
+ linkToken: s_sourceTokens[0],
+ chainSelector: SOURCE_CHAIN_SELECTOR,
+ destChainSelector: DEST_CHAIN_SELECTOR,
+ defaultTxGasLimit: GAS_LIMIT,
+ maxNopFeesJuels: MAX_NOP_FEES_JUELS,
+ prevOnRamp: address(0),
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ });
+ EVM2EVMOnRamp.DynamicConfig memory dynamicConfig =
+ generateDynamicOnRampConfig(address(s_sourceRouter), address(s_priceRegistry));
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.ConfigSet(staticConfig, dynamicConfig);
+
+ s_onRamp = new EVM2EVMOnRampHelper(
+ staticConfig,
+ dynamicConfig,
+ getOutboundRateLimiterConfig(),
+ s_feeTokenConfigArgs,
+ s_tokenTransferFeeConfigArgs,
+ getNopsAndWeights()
+ );
+
+ EVM2EVMOnRamp.StaticConfig memory gotStaticConfig = s_onRamp.getStaticConfig();
+ assertEq(staticConfig.linkToken, gotStaticConfig.linkToken);
+ assertEq(staticConfig.chainSelector, gotStaticConfig.chainSelector);
+ assertEq(staticConfig.destChainSelector, gotStaticConfig.destChainSelector);
+ assertEq(staticConfig.defaultTxGasLimit, gotStaticConfig.defaultTxGasLimit);
+ assertEq(staticConfig.maxNopFeesJuels, gotStaticConfig.maxNopFeesJuels);
+ assertEq(staticConfig.prevOnRamp, gotStaticConfig.prevOnRamp);
+ assertEq(staticConfig.rmnProxy, gotStaticConfig.rmnProxy);
+
+ EVM2EVMOnRamp.DynamicConfig memory gotDynamicConfig = s_onRamp.getDynamicConfig();
+ assertEq(dynamicConfig.router, gotDynamicConfig.router);
+ assertEq(dynamicConfig.maxNumberOfTokensPerMsg, gotDynamicConfig.maxNumberOfTokensPerMsg);
+ assertEq(dynamicConfig.destGasOverhead, gotDynamicConfig.destGasOverhead);
+ assertEq(dynamicConfig.destGasPerPayloadByte, gotDynamicConfig.destGasPerPayloadByte);
+ assertEq(dynamicConfig.priceRegistry, gotDynamicConfig.priceRegistry);
+ assertEq(dynamicConfig.maxDataBytes, gotDynamicConfig.maxDataBytes);
+ assertEq(dynamicConfig.maxPerMsgGasLimit, gotDynamicConfig.maxPerMsgGasLimit);
+
+ // Initial values
+ assertEq("EVM2EVMOnRamp 1.5.0-dev", s_onRamp.typeAndVersion());
+ assertEq(OWNER, s_onRamp.owner());
+ assertEq(1, s_onRamp.getExpectedNextSequenceNumber());
+ }
+}
+
+contract EVM2EVMOnRamp_payNops_fuzz is EVM2EVMOnRampSetup {
+ function test_Fuzz_NopPayNops_Success(uint96 nopFeesJuels) public {
+ (EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights, uint256 weightsTotal) = s_onRamp.getNops();
+ // To avoid NoFeesToPay
+ vm.assume(nopFeesJuels > weightsTotal);
+ vm.assume(nopFeesJuels < MAX_NOP_FEES_JUELS);
+
+ // Set Nop fee juels
+ deal(s_sourceFeeToken, address(s_onRamp), nopFeesJuels);
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), nopFeesJuels, OWNER);
+
+ vm.startPrank(OWNER);
+
+ uint256 totalJuels = s_onRamp.getNopFeesJuels();
+ s_onRamp.payNops();
+ for (uint256 i = 0; i < nopsAndWeights.length; ++i) {
+ uint256 expectedPayout = (totalJuels * nopsAndWeights[i].weight) / weightsTotal;
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(nopsAndWeights[i].nop), expectedPayout);
+ }
+ }
+}
+
+contract EVM2EVMNopsFeeSetup is EVM2EVMOnRampSetup {
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ // Since we'll mostly be testing for valid calls from the router we'll
+ // mock all calls to be originating from the router and re-mock in
+ // tests that require failure.
+ vm.startPrank(address(s_sourceRouter));
+
+ uint256 feeAmount = 1234567890;
+ uint256 numberOfMessages = 5;
+
+ // Send a bunch of messages, increasing the juels in the contract
+ for (uint256 i = 0; i < numberOfMessages; ++i) {
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), feeAmount, OWNER);
+ }
+
+ assertEq(s_onRamp.getNopFeesJuels(), feeAmount * numberOfMessages);
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(address(s_onRamp)), feeAmount * numberOfMessages);
+ }
+}
+
+contract EVM2EVMOnRamp_payNops is EVM2EVMNopsFeeSetup {
+ function test_OwnerPayNops_Success() public {
+ vm.startPrank(OWNER);
+
+ uint256 totalJuels = s_onRamp.getNopFeesJuels();
+ s_onRamp.payNops();
+ (EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights, uint256 weightsTotal) = s_onRamp.getNops();
+ for (uint256 i = 0; i < nopsAndWeights.length; ++i) {
+ uint256 expectedPayout = (nopsAndWeights[i].weight * totalJuels) / weightsTotal;
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(nopsAndWeights[i].nop), expectedPayout);
+ }
+ }
+
+ function test_AdminPayNops_Success() public {
+ vm.startPrank(ADMIN);
+
+ uint256 totalJuels = s_onRamp.getNopFeesJuels();
+ s_onRamp.payNops();
+ (EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights, uint256 weightsTotal) = s_onRamp.getNops();
+ for (uint256 i = 0; i < nopsAndWeights.length; ++i) {
+ uint256 expectedPayout = (nopsAndWeights[i].weight * totalJuels) / weightsTotal;
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(nopsAndWeights[i].nop), expectedPayout);
+ }
+ }
+
+ function test_NopPayNops_Success() public {
+ vm.startPrank(getNopsAndWeights()[0].nop);
+
+ uint256 totalJuels = s_onRamp.getNopFeesJuels();
+ s_onRamp.payNops();
+ (EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights, uint256 weightsTotal) = s_onRamp.getNops();
+ for (uint256 i = 0; i < nopsAndWeights.length; ++i) {
+ uint256 expectedPayout = (nopsAndWeights[i].weight * totalJuels) / weightsTotal;
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(nopsAndWeights[i].nop), expectedPayout);
+ }
+ }
+
+ function test_PayNopsSuccessAfterSetNops() public {
+ vm.startPrank(OWNER);
+
+ // set 2 nops, 1 from previous, 1 new
+ address prevNop = getNopsAndWeights()[0].nop;
+ address newNop = STRANGER;
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = new EVM2EVMOnRamp.NopAndWeight[](2);
+ nopsAndWeights[0] = EVM2EVMOnRamp.NopAndWeight({nop: prevNop, weight: 1});
+ nopsAndWeights[1] = EVM2EVMOnRamp.NopAndWeight({nop: newNop, weight: 1});
+ s_onRamp.setNops(nopsAndWeights);
+
+ // refill OnRamp nops fees
+ vm.startPrank(address(s_sourceRouter));
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), feeAmount, OWNER);
+
+ vm.startPrank(newNop);
+ uint256 prevNopBalance = IERC20(s_sourceFeeToken).balanceOf(prevNop);
+ uint256 totalJuels = s_onRamp.getNopFeesJuels();
+
+ s_onRamp.payNops();
+
+ assertEq(totalJuels / 2 + prevNopBalance, IERC20(s_sourceFeeToken).balanceOf(prevNop));
+ assertEq(totalJuels / 2, IERC20(s_sourceFeeToken).balanceOf(newNop));
+ }
+
+ // Reverts
+
+ function test_InsufficientBalance_Revert() public {
+ vm.startPrank(address(s_onRamp));
+ IERC20(s_sourceFeeToken).transfer(OWNER, IERC20(s_sourceFeeToken).balanceOf(address(s_onRamp)));
+ vm.startPrank(OWNER);
+ vm.expectRevert(EVM2EVMOnRamp.InsufficientBalance.selector);
+ s_onRamp.payNops();
+ }
+
+ function test_WrongPermissions_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(EVM2EVMOnRamp.OnlyCallableByOwnerOrAdminOrNop.selector);
+ s_onRamp.payNops();
+ }
+
+ function test_NoFeesToPay_Revert() public {
+ vm.startPrank(OWNER);
+ s_onRamp.payNops();
+ vm.expectRevert(EVM2EVMOnRamp.NoFeesToPay.selector);
+ s_onRamp.payNops();
+ }
+
+ function test_NoNopsToPay_Revert() public {
+ vm.startPrank(OWNER);
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = new EVM2EVMOnRamp.NopAndWeight[](0);
+ s_onRamp.setNops(nopsAndWeights);
+ vm.expectRevert(EVM2EVMOnRamp.NoNopsToPay.selector);
+ s_onRamp.payNops();
+ }
+}
+
+contract EVM2EVMOnRamp_linkAvailableForPayment is EVM2EVMNopsFeeSetup {
+ function test_LinkAvailableForPayment_Success() public {
+ uint256 totalJuels = s_onRamp.getNopFeesJuels();
+ uint256 linkBalance = IERC20(s_sourceFeeToken).balanceOf(address(s_onRamp));
+
+ assertEq(int256(linkBalance - totalJuels), s_onRamp.linkAvailableForPayment());
+
+ vm.startPrank(OWNER);
+ s_onRamp.payNops();
+
+ assertEq(int256(linkBalance - totalJuels), s_onRamp.linkAvailableForPayment());
+ }
+
+ function test_InsufficientLinkBalance_Success() public {
+ uint256 totalJuels = s_onRamp.getNopFeesJuels();
+ uint256 linkBalance = IERC20(s_sourceFeeToken).balanceOf(address(s_onRamp));
+
+ vm.startPrank(address(s_onRamp));
+
+ uint256 linkRemaining = 1;
+ IERC20(s_sourceFeeToken).transfer(OWNER, linkBalance - linkRemaining);
+
+ vm.startPrank(STRANGER);
+ assertEq(int256(linkRemaining) - int256(totalJuels), s_onRamp.linkAvailableForPayment());
+ }
+}
+
+contract EVM2EVMOnRamp_forwardFromRouter is EVM2EVMOnRampSetup {
+ struct LegacyExtraArgs {
+ uint256 gasLimit;
+ bool strict;
+ }
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ address[] memory feeTokens = new address[](1);
+ feeTokens[0] = s_sourceTokens[1];
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+
+ // Since we'll mostly be testing for valid calls from the router we'll
+ // mock all calls to be originating from the router and re-mock in
+ // tests that require failure.
+ vm.startPrank(address(s_sourceRouter));
+ }
+
+ function test_ForwardFromRouterSuccessCustomExtraArgs() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT * 2}));
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouterSuccessLegacyExtraArgs() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs =
+ abi.encodeWithSelector(Client.EVM_EXTRA_ARGS_V1_TAG, LegacyExtraArgs({gasLimit: GAS_LIMIT * 2, strict: true}));
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ // We expect the message to be emitted with strict = false.
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouter_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouterExtraArgsV2_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = abi.encodeWithSelector(
+ Client.EVM_EXTRA_ARGS_V2_TAG, Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT * 2, allowOutOfOrderExecution: true})
+ );
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = abi.encodeWithSelector(
+ Client.EVM_EXTRA_ARGS_V2_TAG, Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT * 2, allowOutOfOrderExecution: true})
+ );
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, feeAmount, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+
+ function test_Fuzz_EnforceOutOfOrder(bool enforce, bool allowOutOfOrderExecution) public {
+ // Update dynamic config to enforce allowOutOfOrderExecution = defaultVal.
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ EVM2EVMOnRamp.DynamicConfig memory dynamicConfig = s_onRamp.getDynamicConfig();
+ s_onRamp.setDynamicConfig(
+ EVM2EVMOnRamp.DynamicConfig({
+ router: dynamicConfig.router,
+ maxNumberOfTokensPerMsg: dynamicConfig.maxNumberOfTokensPerMsg,
+ destGasOverhead: dynamicConfig.destGasOverhead,
+ destGasPerPayloadByte: dynamicConfig.destGasPerPayloadByte,
+ destDataAvailabilityOverheadGas: dynamicConfig.destDataAvailabilityOverheadGas,
+ destGasPerDataAvailabilityByte: dynamicConfig.destGasPerDataAvailabilityByte,
+ destDataAvailabilityMultiplierBps: dynamicConfig.destDataAvailabilityMultiplierBps,
+ priceRegistry: dynamicConfig.priceRegistry,
+ maxDataBytes: dynamicConfig.maxDataBytes,
+ maxPerMsgGasLimit: dynamicConfig.maxPerMsgGasLimit,
+ defaultTokenFeeUSDCents: dynamicConfig.defaultTokenFeeUSDCents,
+ defaultTokenDestGasOverhead: dynamicConfig.defaultTokenDestGasOverhead,
+ defaultTokenDestBytesOverhead: dynamicConfig.defaultTokenDestBytesOverhead,
+ enforceOutOfOrder: enforce
+ })
+ );
+ vm.stopPrank();
+
+ vm.startPrank(address(s_sourceRouter));
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = abi.encodeWithSelector(
+ Client.EVM_EXTRA_ARGS_V2_TAG,
+ Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT * 2, allowOutOfOrderExecution: allowOutOfOrderExecution})
+ );
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ if (enforce) {
+ // If enforcement is on, only true should be allowed.
+ if (allowOutOfOrderExecution) {
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, feeAmount, OWNER));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ } else {
+ vm.expectRevert(EVM2EVMOnRamp.ExtraArgOutOfOrderExecutionMustBeTrue.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+ } else {
+ // no enforcement should allow any value.
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, feeAmount, OWNER));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+ }
+
+ function test_ShouldIncrementSeqNumAndNonce_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ for (uint64 i = 1; i < 4; ++i) {
+ uint64 nonceBefore = s_onRamp.getSenderNonce(OWNER);
+ uint64 sequenceNumberBefore = s_onRamp.getSequenceNumber();
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, i, i, 0, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ uint64 nonceAfter = s_onRamp.getSenderNonce(OWNER);
+ uint64 sequenceNumberAfter = s_onRamp.getSequenceNumber();
+ assertEq(nonceAfter, nonceBefore + 1);
+ assertEq(sequenceNumberAfter, sequenceNumberBefore + 1);
+ }
+ }
+
+ function test_ShouldIncrementNonceOnlyOnOrdered_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = abi.encodeWithSelector(
+ Client.EVM_EXTRA_ARGS_V2_TAG, Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT * 2, allowOutOfOrderExecution: true})
+ );
+
+ for (uint64 i = 1; i < 4; ++i) {
+ uint64 nonceBefore = s_onRamp.getSenderNonce(OWNER);
+ uint64 sequenceNumberBefore = s_onRamp.getSequenceNumber();
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, i, i, 0, OWNER));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ uint64 nonceAfter = s_onRamp.getSenderNonce(OWNER);
+ uint64 sequenceNumberAfter = s_onRamp.getSequenceNumber();
+ assertEq(nonceAfter, nonceBefore);
+ assertEq(sequenceNumberAfter, sequenceNumberBefore + 1);
+ }
+ }
+
+ function test_forwardFromRouter_ShouldStoreLinkFees_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+
+ assertEq(IERC20(s_sourceFeeToken).balanceOf(address(s_onRamp)), feeAmount);
+ assertEq(s_onRamp.getNopFeesJuels(), feeAmount);
+ }
+
+ function test_ShouldStoreNonLinkFees() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = s_sourceTokens[1];
+
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceTokens[1]).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+
+ assertEq(IERC20(s_sourceTokens[1]).balanceOf(address(s_onRamp)), feeAmount);
+
+ // Calculate conversion done by prices contract
+ uint256 feeTokenPrice = s_priceRegistry.getTokenPrice(s_sourceTokens[1]).value;
+ uint256 linkTokenPrice = s_priceRegistry.getTokenPrice(s_sourceFeeToken).value;
+ uint256 conversionRate = (feeTokenPrice * 1e18) / linkTokenPrice;
+ uint256 expectedJuels = (feeAmount * conversionRate) / 1e18;
+
+ assertEq(s_onRamp.getNopFeesJuels(), expectedJuels);
+ }
+
+ // Make sure any valid sender, receiver and feeAmount can be handled.
+ // @TODO Temporarily setting lower fuzz run as 256 triggers snapshot gas off by 1 error.
+ // https://github.com/foundry-rs/foundry/issues/5689
+ /// forge-config: default.fuzz.runs = 32
+ /// forge-config: ccip.fuzz.runs = 32
+ function test_Fuzz_ForwardFromRouter_Success(address originalSender, address receiver, uint96 feeTokenAmount) public {
+ // To avoid RouterMustSetOriginalSender
+ vm.assume(originalSender != address(0));
+ vm.assume(uint160(receiver) >= Internal.PRECOMPILE_SPACE);
+ vm.assume(feeTokenAmount <= MAX_NOP_FEES_JUELS);
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.receiver = abi.encode(receiver);
+
+ // Make sure the tokens are in the contract
+ deal(s_sourceFeeToken, address(s_onRamp), feeTokenAmount);
+
+ Internal.EVM2EVMMessage memory expectedEvent = _messageToEvent(message, 1, 1, feeTokenAmount, originalSender);
+
+ vm.expectEmit(false, false, false, true);
+ emit EVM2EVMOnRamp.CCIPSendRequested(expectedEvent);
+
+ // Assert the message Id is correct
+ assertEq(
+ expectedEvent.messageId, s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeTokenAmount, originalSender)
+ );
+ // Assert the fee token amount is correctly assigned to the nop fee pool
+ assertEq(feeTokenAmount, s_onRamp.getNopFeesJuels());
+ }
+
+ function test_OverValueWithARLOff_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 10;
+ message.tokenAmounts[0].token = s_sourceTokens[0];
+
+ IERC20(s_sourceTokens[0]).approve(address(s_onRamp), 10);
+
+ vm.startPrank(OWNER);
+ // Set a high price to trip the ARL
+ uint224 tokenPrice = 3 ** 128;
+ Internal.PriceUpdates memory priceUpdates = getSingleTokenPriceUpdateStruct(s_sourceTokens[0], tokenPrice);
+ s_priceRegistry.updatePrices(priceUpdates);
+ vm.startPrank(address(s_sourceRouter));
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ RateLimiter.AggregateValueMaxCapacityExceeded.selector,
+ getOutboundRateLimiterConfig().capacity,
+ (message.tokenAmounts[0].amount * tokenPrice) / 1e18
+ )
+ );
+ // Expect to fail from ARL
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Configure ARL off for token
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory tokenTransferFeeConfig =
+ s_onRamp.getTokenTransferFeeConfig(s_sourceTokens[0]);
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ new EVM2EVMOnRamp.TokenTransferFeeConfigArgs[](1);
+ tokenTransferFeeConfigArgs[0] = EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: s_sourceTokens[0],
+ minFeeUSDCents: tokenTransferFeeConfig.minFeeUSDCents,
+ maxFeeUSDCents: tokenTransferFeeConfig.maxFeeUSDCents,
+ deciBps: tokenTransferFeeConfig.deciBps,
+ destGasOverhead: tokenTransferFeeConfig.destGasOverhead,
+ destBytesOverhead: tokenTransferFeeConfig.destBytesOverhead,
+ aggregateRateLimitEnabled: false
+ });
+ vm.startPrank(OWNER);
+ s_onRamp.setTokenTransferFeeConfig(tokenTransferFeeConfigArgs, new address[](0));
+
+ vm.startPrank(address(s_sourceRouter));
+ // Expect the call now succeeds
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ // Reverts
+
+ function test_Paused_Revert() public {
+ // We pause by disabling the whitelist
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ address router = address(0);
+ s_onRamp.setDynamicConfig(generateDynamicOnRampConfig(router, address(2)));
+ vm.expectRevert(EVM2EVMOnRamp.MustBeCalledByRouter.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, OWNER);
+ }
+
+ function test_InvalidExtraArgsTag_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = bytes("bad args");
+
+ vm.expectRevert(EVM2EVMOnRamp.InvalidExtraArgsTag.selector);
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_Unhealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ vm.expectRevert(EVM2EVMOnRamp.CursedByRMN.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, OWNER);
+ }
+
+ function test_Permissions_Revert() public {
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ vm.expectRevert(EVM2EVMOnRamp.MustBeCalledByRouter.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, OWNER);
+ }
+
+ function test_OriginalSender_Revert() public {
+ vm.expectRevert(EVM2EVMOnRamp.RouterMustSetOriginalSender.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), 0, address(0));
+ }
+
+ function test_MessageTooLarge_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.data = new bytes(MAX_DATA_SIZE + 1);
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.MessageTooLarge.selector, MAX_DATA_SIZE, message.data.length));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, STRANGER);
+ }
+
+ function test_TooManyTokens_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ uint256 tooMany = MAX_TOKENS_LENGTH + 1;
+ message.tokenAmounts = new Client.EVMTokenAmount[](tooMany);
+ vm.expectRevert(EVM2EVMOnRamp.UnsupportedNumberOfTokens.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, STRANGER);
+ }
+
+ function test_CannotSendZeroTokens_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 0;
+ message.tokenAmounts[0].token = s_sourceTokens[0];
+ vm.expectRevert(EVM2EVMOnRamp.CannotSendZeroTokens.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, STRANGER);
+ }
+
+ function test_UnsupportedToken_Revert() public {
+ address wrongToken = address(1);
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].token = wrongToken;
+ message.tokenAmounts[0].amount = 1;
+
+ // We need to set the price of this new token to be able to reach
+ // the proper revert point. This must be called by the owner.
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+
+ Internal.PriceUpdates memory priceUpdates = getSingleTokenPriceUpdateStruct(wrongToken, 1);
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ // Change back to the router
+ vm.startPrank(address(s_sourceRouter));
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.UnsupportedToken.selector, wrongToken));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_MaxCapacityExceeded_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 2 ** 128;
+ message.tokenAmounts[0].token = s_sourceTokens[0];
+
+ IERC20(s_sourceTokens[0]).approve(address(s_onRamp), 2 ** 128);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ RateLimiter.AggregateValueMaxCapacityExceeded.selector,
+ getOutboundRateLimiterConfig().capacity,
+ (message.tokenAmounts[0].amount * s_sourceTokenPrices[0]) / 1e18
+ )
+ );
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_PriceNotFoundForToken_Revert() public {
+ // Set token price to 0
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ s_priceRegistry.updatePrices(getSingleTokenPriceUpdateStruct(CUSTOM_TOKEN, 0));
+
+ vm.startPrank(address(s_sourceRouter));
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].token = CUSTOM_TOKEN;
+ message.tokenAmounts[0].amount = 1;
+
+ vm.expectRevert(abi.encodeWithSelector(AggregateRateLimiter.PriceNotFoundForToken.selector, CUSTOM_TOKEN));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ // Asserts gasLimit must be <=maxGasLimit
+ function test_MessageGasLimitTooHigh_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: MAX_GAS_LIMIT + 1}));
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.MessageGasLimitTooHigh.selector));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_InvalidAddressEncodePacked_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.receiver = abi.encodePacked(address(234));
+
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, message.receiver));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 1, OWNER);
+ }
+
+ function test_InvalidAddress_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.receiver = abi.encode(type(uint208).max);
+
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, message.receiver));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 1, OWNER);
+ }
+
+ // We disallow sending to addresses 0-9.
+ function test_ZeroAddressReceiver_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ for (uint160 i = 0; i < 10; ++i) {
+ message.receiver = abi.encode(address(i));
+
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, message.receiver));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 1, OWNER);
+ }
+ }
+
+ function test_MaxFeeBalanceReached_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ vm.expectRevert(EVM2EVMOnRamp.MaxFeeBalanceReached.selector);
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, MAX_NOP_FEES_JUELS + 1, OWNER);
+ }
+
+ function test_InvalidChainSelector_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint64 wrongChainSelector = DEST_CHAIN_SELECTOR + 1;
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.InvalidChainSelector.selector, wrongChainSelector));
+
+ s_onRamp.forwardFromRouter(wrongChainSelector, message, 1, OWNER);
+ }
+
+ function test_SourceTokenDataTooLarge_Revert() public {
+ address sourceETH = s_sourceTokens[1];
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+
+ MaybeRevertingBurnMintTokenPool newPool = new MaybeRevertingBurnMintTokenPool(
+ BurnMintERC677(sourceETH), new address[](0), address(s_mockRMN), address(s_sourceRouter)
+ );
+ BurnMintERC677(sourceETH).grantMintAndBurnRoles(address(newPool));
+ deal(address(sourceETH), address(newPool), type(uint256).max);
+
+ // Add TokenPool to OnRamp
+ s_tokenAdminRegistry.setPool(sourceETH, address(newPool));
+
+ // Allow chain in TokenPool
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_destTokenPool),
+ remoteTokenAddress: abi.encode(s_destToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ newPool.applyChainUpdates(chainUpdates);
+
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(address(sourceETH), 1000);
+
+ // No data set, should succeed
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Set max data length, should succeed
+ vm.startPrank(OWNER);
+ newPool.setSourceTokenData(new bytes(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES));
+
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Set data to max length +1, should revert
+ vm.startPrank(OWNER);
+ newPool.setSourceTokenData(new bytes(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES + 1));
+
+ vm.startPrank(address(s_sourceRouter));
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.SourceTokenDataTooLarge.selector, sourceETH));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Set token config to allow larger data
+ vm.startPrank(OWNER);
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ new EVM2EVMOnRamp.TokenTransferFeeConfigArgs[](1);
+ tokenTransferFeeConfigArgs[0] = EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: sourceETH,
+ minFeeUSDCents: 1,
+ maxFeeUSDCents: 0,
+ deciBps: 0,
+ destGasOverhead: 0,
+ destBytesOverhead: uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) + 32,
+ aggregateRateLimitEnabled: false
+ });
+ s_onRamp.setTokenTransferFeeConfig(tokenTransferFeeConfigArgs, new address[](0));
+
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ // Set the token data larger than the configured token data, should revert
+ vm.startPrank(OWNER);
+ newPool.setSourceTokenData(new bytes(uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) + 32 + 1));
+
+ vm.startPrank(address(s_sourceRouter));
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.SourceTokenDataTooLarge.selector, sourceETH));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_forwardFromRouter_UnsupportedToken_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 1;
+ message.tokenAmounts[0].token = address(1);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.UnsupportedToken.selector, message.tokenAmounts[0].token));
+
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+ }
+
+ function test_EnforceOutOfOrder_Revert() public {
+ // Update dynamic config to enforce allowOutOfOrderExecution = true.
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+ EVM2EVMOnRamp.DynamicConfig memory dynamicConfig = s_onRamp.getDynamicConfig();
+ s_onRamp.setDynamicConfig(
+ EVM2EVMOnRamp.DynamicConfig({
+ router: dynamicConfig.router,
+ maxNumberOfTokensPerMsg: dynamicConfig.maxNumberOfTokensPerMsg,
+ destGasOverhead: dynamicConfig.destGasOverhead,
+ destGasPerPayloadByte: dynamicConfig.destGasPerPayloadByte,
+ destDataAvailabilityOverheadGas: dynamicConfig.destDataAvailabilityOverheadGas,
+ destGasPerDataAvailabilityByte: dynamicConfig.destGasPerDataAvailabilityByte,
+ destDataAvailabilityMultiplierBps: dynamicConfig.destDataAvailabilityMultiplierBps,
+ priceRegistry: dynamicConfig.priceRegistry,
+ maxDataBytes: dynamicConfig.maxDataBytes,
+ maxPerMsgGasLimit: dynamicConfig.maxPerMsgGasLimit,
+ defaultTokenFeeUSDCents: dynamicConfig.defaultTokenFeeUSDCents,
+ defaultTokenDestGasOverhead: dynamicConfig.defaultTokenDestGasOverhead,
+ defaultTokenDestBytesOverhead: dynamicConfig.defaultTokenDestBytesOverhead,
+ enforceOutOfOrder: true
+ })
+ );
+ vm.stopPrank();
+
+ vm.startPrank(address(s_sourceRouter));
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ // Empty extraArgs to should revert since it enforceOutOfOrder is true.
+ message.extraArgs = "";
+ uint256 feeAmount = 1234567890;
+ IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount);
+
+ vm.expectRevert(EVM2EVMOnRamp.ExtraArgOutOfOrderExecutionMustBeTrue.selector);
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER);
+ }
+}
+
+contract EVM2EVMOnRamp_forwardFromRouter_upgrade is EVM2EVMOnRampSetup {
+ uint256 internal constant FEE_AMOUNT = 1234567890;
+ EVM2EVMOnRampHelper internal s_prevOnRamp;
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ s_prevOnRamp = s_onRamp;
+
+ s_onRamp = new EVM2EVMOnRampHelper(
+ EVM2EVMOnRamp.StaticConfig({
+ linkToken: s_sourceTokens[0],
+ chainSelector: SOURCE_CHAIN_SELECTOR,
+ destChainSelector: DEST_CHAIN_SELECTOR,
+ defaultTxGasLimit: GAS_LIMIT,
+ maxNopFeesJuels: MAX_NOP_FEES_JUELS,
+ prevOnRamp: address(s_prevOnRamp),
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ generateDynamicOnRampConfig(address(s_sourceRouter), address(s_priceRegistry)),
+ getOutboundRateLimiterConfig(),
+ s_feeTokenConfigArgs,
+ s_tokenTransferFeeConfigArgs,
+ getNopsAndWeights()
+ );
+ s_onRamp.setAdmin(ADMIN);
+
+ s_metadataHash = keccak256(
+ abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, address(s_onRamp))
+ );
+
+ vm.startPrank(address(s_sourceRouter));
+ }
+
+ function test_V2_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, FEE_AMOUNT, OWNER));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+ }
+
+ function test_V2SenderNoncesReadsPreviousRamp_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ uint64 startNonce = s_onRamp.getSenderNonce(OWNER);
+
+ for (uint64 i = 1; i < 4; ++i) {
+ s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER);
+
+ assertEq(startNonce + i, s_onRamp.getSenderNonce(OWNER));
+ }
+ }
+
+ function test_V2NonceStartsAtV1Nonce_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint64 startNonce = s_onRamp.getSenderNonce(OWNER);
+
+ // send 1 message from previous onramp
+ s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+
+ assertEq(startNonce + 1, s_onRamp.getSenderNonce(OWNER));
+
+ // new onramp nonce should start from 2, while sequence number start from 1
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, startNonce + 2, FEE_AMOUNT, OWNER));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+
+ assertEq(startNonce + 2, s_onRamp.getSenderNonce(OWNER));
+
+ // after another send, nonce should be 3, and sequence number be 2
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 2, startNonce + 3, FEE_AMOUNT, OWNER));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+
+ assertEq(startNonce + 3, s_onRamp.getSenderNonce(OWNER));
+ }
+
+ function test_V2NonceNewSenderStartsAtZero_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ // send 1 message from previous onramp from OWNER
+ s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER);
+
+ address newSender = address(1234567);
+ // new onramp nonce should start from 1 for new sender
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(_messageToEvent(message, 1, 1, FEE_AMOUNT, newSender));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, newSender);
+ }
+}
+
+contract EVM2EVMOnRamp_getFeeSetup is EVM2EVMOnRampSetup {
+ uint224 internal s_feeTokenPrice;
+ uint224 internal s_wrappedTokenPrice;
+ uint224 internal s_customTokenPrice;
+
+ address internal s_selfServeTokenDefaultPricing = makeAddr("self-serve-token-default-pricing");
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+
+ // Add additional pool addresses for test tokens to mark them as supported
+ s_tokenAdminRegistry.proposeAdministrator(s_sourceRouter.getWrappedNative(), OWNER);
+ s_tokenAdminRegistry.acceptAdminRole(s_sourceRouter.getWrappedNative());
+ s_tokenAdminRegistry.proposeAdministrator(CUSTOM_TOKEN, OWNER);
+ s_tokenAdminRegistry.acceptAdminRole(CUSTOM_TOKEN);
+
+ LockReleaseTokenPool wrappedNativePool = new LockReleaseTokenPool(
+ IERC20(s_sourceRouter.getWrappedNative()), new address[](0), address(s_mockRMN), true, address(s_sourceRouter)
+ );
+
+ TokenPool.ChainUpdate[] memory wrappedNativeChainUpdate = new TokenPool.ChainUpdate[](1);
+ wrappedNativeChainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(address(111111)),
+ remoteTokenAddress: abi.encode(s_destToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ wrappedNativePool.applyChainUpdates(wrappedNativeChainUpdate);
+ s_tokenAdminRegistry.setPool(s_sourceRouter.getWrappedNative(), address(wrappedNativePool));
+
+ LockReleaseTokenPool customPool = new LockReleaseTokenPool(
+ IERC20(CUSTOM_TOKEN), new address[](0), address(s_mockRMN), true, address(s_sourceRouter)
+ );
+ TokenPool.ChainUpdate[] memory customChainUpdate = new TokenPool.ChainUpdate[](1);
+ customChainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(makeAddr("random")),
+ remoteTokenAddress: abi.encode(s_destToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ customPool.applyChainUpdates(customChainUpdate);
+ s_tokenAdminRegistry.setPool(CUSTOM_TOKEN, address(customPool));
+
+ s_feeTokenPrice = s_sourceTokenPrices[0];
+ s_wrappedTokenPrice = s_sourceTokenPrices[2];
+ s_customTokenPrice = CUSTOM_TOKEN_PRICE;
+
+ // Ensure the self-serve token is set up on the admin registry
+ vm.mockCall(
+ address(s_tokenAdminRegistry),
+ abi.encodeWithSelector(ITokenAdminRegistry.getPool.selector, s_selfServeTokenDefaultPricing),
+ abi.encode(makeAddr("self-serve-pool"))
+ );
+ }
+
+ function calcUSDValueFromTokenAmount(uint224 tokenPrice, uint256 tokenAmount) internal pure returns (uint256) {
+ return (tokenPrice * tokenAmount) / 1e18;
+ }
+
+ function applyBpsRatio(uint256 tokenAmount, uint16 ratio) internal pure returns (uint256) {
+ return (tokenAmount * ratio) / 1e5;
+ }
+
+ function configUSDCentToWei(uint256 usdCent) internal pure returns (uint256) {
+ return usdCent * 1e16;
+ }
+}
+
+contract EVM2EVMOnRamp_getDataAvailabilityCost is EVM2EVMOnRamp_getFeeSetup {
+ function test_EmptyMessageCalculatesDataAvailabilityCost_Success() public view {
+ uint256 dataAvailabilityCostUSD = s_onRamp.getDataAvailabilityCost(USD_PER_DATA_AVAILABILITY_GAS, 0, 0, 0);
+
+ EVM2EVMOnRamp.DynamicConfig memory dynamicConfig = s_onRamp.getDynamicConfig();
+
+ uint256 dataAvailabilityGas = dynamicConfig.destDataAvailabilityOverheadGas
+ + dynamicConfig.destGasPerDataAvailabilityByte * Internal.MESSAGE_FIXED_BYTES;
+ uint256 expectedDataAvailabilityCostUSD =
+ USD_PER_DATA_AVAILABILITY_GAS * dataAvailabilityGas * dynamicConfig.destDataAvailabilityMultiplierBps * 1e14;
+
+ assertEq(expectedDataAvailabilityCostUSD, dataAvailabilityCostUSD);
+ }
+
+ function test_SimpleMessageCalculatesDataAvailabilityCost_Success() public view {
+ uint256 dataAvailabilityCostUSD = s_onRamp.getDataAvailabilityCost(USD_PER_DATA_AVAILABILITY_GAS, 100, 5, 50);
+
+ EVM2EVMOnRamp.DynamicConfig memory dynamicConfig = s_onRamp.getDynamicConfig();
+
+ uint256 dataAvailabilityLengthBytes =
+ Internal.MESSAGE_FIXED_BYTES + 100 + (5 * Internal.MESSAGE_FIXED_BYTES_PER_TOKEN) + 50;
+ uint256 dataAvailabilityGas = dynamicConfig.destDataAvailabilityOverheadGas
+ + dynamicConfig.destGasPerDataAvailabilityByte * dataAvailabilityLengthBytes;
+ uint256 expectedDataAvailabilityCostUSD =
+ USD_PER_DATA_AVAILABILITY_GAS * dataAvailabilityGas * dynamicConfig.destDataAvailabilityMultiplierBps * 1e14;
+
+ assertEq(expectedDataAvailabilityCostUSD, dataAvailabilityCostUSD);
+ }
+
+ function test_Fuzz_ZeroDataAvailabilityGasPriceAlwaysCalculatesZeroDataAvailabilityCost_Success(
+ uint64 messageDataLength,
+ uint32 numberOfTokens,
+ uint32 tokenTransferBytesOverhead
+ ) public view {
+ uint256 dataAvailabilityCostUSD =
+ s_onRamp.getDataAvailabilityCost(0, messageDataLength, numberOfTokens, tokenTransferBytesOverhead);
+
+ assertEq(0, dataAvailabilityCostUSD);
+ }
+
+ function test_Fuzz_CalculateDataAvailabilityCost_Success(
+ uint32 destDataAvailabilityOverheadGas,
+ uint16 destGasPerDataAvailabilityByte,
+ uint16 destDataAvailabilityMultiplierBps,
+ uint112 dataAvailabilityGasPrice,
+ uint64 messageDataLength,
+ uint32 numberOfTokens,
+ uint32 tokenTransferBytesOverhead
+ ) public {
+ EVM2EVMOnRamp.DynamicConfig memory dynamicConfig = s_onRamp.getDynamicConfig();
+ dynamicConfig.destDataAvailabilityOverheadGas = destDataAvailabilityOverheadGas;
+ dynamicConfig.destGasPerDataAvailabilityByte = destGasPerDataAvailabilityByte;
+ dynamicConfig.destDataAvailabilityMultiplierBps = destDataAvailabilityMultiplierBps;
+ s_onRamp.setDynamicConfig(dynamicConfig);
+
+ uint256 dataAvailabilityCostUSD = s_onRamp.getDataAvailabilityCost(
+ dataAvailabilityGasPrice, messageDataLength, numberOfTokens, tokenTransferBytesOverhead
+ );
+
+ uint256 dataAvailabilityLengthBytes = Internal.MESSAGE_FIXED_BYTES + messageDataLength
+ + (numberOfTokens * Internal.MESSAGE_FIXED_BYTES_PER_TOKEN) + tokenTransferBytesOverhead;
+
+ uint256 dataAvailabilityGas =
+ destDataAvailabilityOverheadGas + destGasPerDataAvailabilityByte * dataAvailabilityLengthBytes;
+ uint256 expectedDataAvailabilityCostUSD =
+ dataAvailabilityGasPrice * dataAvailabilityGas * destDataAvailabilityMultiplierBps * 1e14;
+
+ assertEq(expectedDataAvailabilityCostUSD, dataAvailabilityCostUSD);
+ }
+}
+
+contract EVM2EVMOnRamp_getSupportedTokens is EVM2EVMOnRampSetup {
+ function test_GetSupportedTokens_Revert() public {
+ vm.expectRevert(EVM2EVMOnRamp.GetSupportedTokensFunctionalityRemovedCheckAdminRegistry.selector);
+ s_onRamp.getSupportedTokens(DEST_CHAIN_SELECTOR);
+ }
+}
+
+contract EVM2EVMOnRamp_getTokenTransferCost is EVM2EVMOnRamp_getFeeSetup {
+ using USDPriceWith18Decimals for uint224;
+
+ function test_NoTokenTransferChargesZeroFee_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ assertEq(0, feeUSDWei);
+ assertEq(0, destGasOverhead);
+ assertEq(0, destBytesOverhead);
+ }
+
+ function test__getTokenTransferCost_selfServeUsesDefaults_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_selfServeTokenDefaultPricing, 1000);
+
+ // Get config to assert it isn't set
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory transferFeeConfig =
+ s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token);
+
+ assertFalse(transferFeeConfig.isEnabled);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ // Assert that the default values are used
+ assertEq(uint256(DEFAULT_TOKEN_FEE_USD_CENTS) * 1e16, feeUSDWei);
+ assertEq(DEFAULT_TOKEN_DEST_GAS_OVERHEAD, destGasOverhead);
+ assertEq(DEFAULT_TOKEN_BYTES_OVERHEAD, destBytesOverhead);
+ }
+
+ function test_SmallTokenTransferChargesMinFeeAndGas_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, 1000);
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory transferFeeConfig =
+ s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ assertEq(configUSDCentToWei(transferFeeConfig.minFeeUSDCents), feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, destBytesOverhead);
+ }
+
+ function test_ZeroAmountTokenTransferChargesMinFeeAndGas_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, 0);
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory transferFeeConfig =
+ s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ assertEq(configUSDCentToWei(transferFeeConfig.minFeeUSDCents), feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, destBytesOverhead);
+ }
+
+ function test_LargeTokenTransferChargesMaxFeeAndGas_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, 1e36);
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory transferFeeConfig =
+ s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ assertEq(configUSDCentToWei(transferFeeConfig.maxFeeUSDCents), feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, destBytesOverhead);
+ }
+
+ function test_FeeTokenBpsFee_Success() public view {
+ uint256 tokenAmount = 10000e18;
+
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, tokenAmount);
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory transferFeeConfig =
+ s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ uint256 usdWei = calcUSDValueFromTokenAmount(s_feeTokenPrice, tokenAmount);
+ uint256 bpsUSDWei = applyBpsRatio(usdWei, s_tokenTransferFeeConfigArgs[0].deciBps);
+
+ assertEq(bpsUSDWei, feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, destBytesOverhead);
+ }
+
+ function test_WETHTokenBpsFee_Success() public view {
+ uint256 tokenAmount = 100e18;
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](1),
+ feeToken: s_sourceRouter.getWrappedNative(),
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ message.tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceRouter.getWrappedNative(), amount: tokenAmount});
+
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory transferFeeConfig =
+ s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_wrappedTokenPrice, message.tokenAmounts);
+
+ uint256 usdWei = calcUSDValueFromTokenAmount(s_wrappedTokenPrice, tokenAmount);
+ uint256 bpsUSDWei = applyBpsRatio(usdWei, s_tokenTransferFeeConfigArgs[1].deciBps);
+
+ assertEq(bpsUSDWei, feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(transferFeeConfig.destBytesOverhead, destBytesOverhead);
+ }
+
+ function test_CustomTokenBpsFee_Success() public view {
+ uint256 tokenAmount = 200000e18;
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](1),
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ message.tokenAmounts[0] = Client.EVMTokenAmount({token: CUSTOM_TOKEN, amount: tokenAmount});
+
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory transferFeeConfig =
+ s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ uint256 usdWei = calcUSDValueFromTokenAmount(s_customTokenPrice, tokenAmount);
+ uint256 bpsUSDWei = applyBpsRatio(usdWei, s_tokenTransferFeeConfigArgs[2].deciBps);
+
+ assertEq(bpsUSDWei, feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(transferFeeConfig.destBytesOverhead, destBytesOverhead);
+ }
+
+ function test_ZeroFeeConfigChargesMinFee_Success() public {
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ new EVM2EVMOnRamp.TokenTransferFeeConfigArgs[](1);
+ tokenTransferFeeConfigArgs[0] = EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: s_sourceFeeToken,
+ minFeeUSDCents: 1,
+ maxFeeUSDCents: 0,
+ deciBps: 0,
+ destGasOverhead: 0,
+ destBytesOverhead: uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES),
+ aggregateRateLimitEnabled: true
+ });
+ s_onRamp.setTokenTransferFeeConfig(tokenTransferFeeConfigArgs, new address[](0));
+
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, 1e36);
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ // if token charges 0 bps, it should cost minFee to transfer
+ assertEq(configUSDCentToWei(tokenTransferFeeConfigArgs[0].minFeeUSDCents), feeUSDWei);
+ assertEq(0, destGasOverhead);
+ assertEq(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, destBytesOverhead);
+ }
+
+ function test_Fuzz_TokenTransferFeeDuplicateTokens_Success(uint256 transfers, uint256 amount) public view {
+ // It shouldn't be possible to pay materially lower fees by splitting up the transfers.
+ // Note it is possible to pay higher fees since the minimum fees are added.
+ EVM2EVMOnRamp.DynamicConfig memory dynamicConfig = s_onRamp.getDynamicConfig();
+ transfers = bound(transfers, 1, dynamicConfig.maxNumberOfTokensPerMsg);
+ // Cap amount to avoid overflow
+ amount = bound(amount, 0, 1e36);
+ Client.EVMTokenAmount[] memory multiple = new Client.EVMTokenAmount[](transfers);
+ for (uint256 i = 0; i < transfers; ++i) {
+ multiple[i] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: amount});
+ }
+ Client.EVMTokenAmount[] memory single = new Client.EVMTokenAmount[](1);
+ single[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: amount * transfers});
+
+ address feeToken = s_sourceRouter.getWrappedNative();
+
+ (uint256 feeSingleUSDWei, uint32 gasOverheadSingle, uint32 bytesOverheadSingle) =
+ s_onRamp.getTokenTransferCost(feeToken, s_wrappedTokenPrice, single);
+ (uint256 feeMultipleUSDWei, uint32 gasOverheadMultiple, uint32 bytesOverheadMultiple) =
+ s_onRamp.getTokenTransferCost(feeToken, s_wrappedTokenPrice, multiple);
+
+ // Note that there can be a rounding error once per split.
+ assertTrue(feeMultipleUSDWei >= (feeSingleUSDWei - dynamicConfig.maxNumberOfTokensPerMsg));
+ assertEq(gasOverheadMultiple, gasOverheadSingle * transfers);
+ assertEq(bytesOverheadMultiple, bytesOverheadSingle * transfers);
+ }
+
+ function test_MixedTokenTransferFee_Success() public view {
+ address[3] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative(), CUSTOM_TOKEN];
+ uint224[3] memory tokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice, s_customTokenPrice];
+ EVM2EVMOnRamp.TokenTransferFeeConfig[3] memory tokenTransferFeeConfigs = [
+ s_onRamp.getTokenTransferFeeConfig(testTokens[0]),
+ s_onRamp.getTokenTransferFeeConfig(testTokens[1]),
+ s_onRamp.getTokenTransferFeeConfig(testTokens[2])
+ ];
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](3),
+ feeToken: s_sourceRouter.getWrappedNative(),
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ uint256 expectedTotalGas = 0;
+ uint256 expectedTotalBytes = 0;
+
+ // Start with small token transfers, total bps fee is lower than min token transfer fee
+ for (uint256 i = 0; i < testTokens.length; ++i) {
+ message.tokenAmounts[i] = Client.EVMTokenAmount({token: testTokens[i], amount: 1e14});
+ expectedTotalGas += s_onRamp.getTokenTransferFeeConfig(testTokens[i]).destGasOverhead;
+ uint32 dstBytesOverhead = s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[i].token).destBytesOverhead;
+ expectedTotalBytes += dstBytesOverhead == 0 ? uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) : dstBytesOverhead;
+ }
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_wrappedTokenPrice, message.tokenAmounts);
+
+ uint256 expectedFeeUSDWei = 0;
+ for (uint256 i = 0; i < testTokens.length; ++i) {
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[i].minFeeUSDCents);
+ }
+
+ assertEq(expectedFeeUSDWei, feeUSDWei);
+ assertEq(expectedTotalGas, destGasOverhead);
+ assertEq(expectedTotalBytes, destBytesOverhead);
+
+ // Set 1st token transfer to a meaningful amount so its bps fee is now between min and max fee
+ message.tokenAmounts[0] = Client.EVMTokenAmount({token: testTokens[0], amount: 10000e18});
+
+ (feeUSDWei, destGasOverhead, destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_wrappedTokenPrice, message.tokenAmounts);
+ expectedFeeUSDWei = applyBpsRatio(
+ calcUSDValueFromTokenAmount(tokenPrices[0], message.tokenAmounts[0].amount), tokenTransferFeeConfigs[0].deciBps
+ );
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[1].minFeeUSDCents);
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[2].minFeeUSDCents);
+
+ assertEq(expectedFeeUSDWei, feeUSDWei);
+ assertEq(expectedTotalGas, destGasOverhead);
+ assertEq(expectedTotalBytes, destBytesOverhead);
+
+ // Set 2nd token transfer to a large amount that is higher than maxFeeUSD
+ message.tokenAmounts[1] = Client.EVMTokenAmount({token: testTokens[1], amount: 1e36});
+
+ (feeUSDWei, destGasOverhead, destBytesOverhead) =
+ s_onRamp.getTokenTransferCost(message.feeToken, s_wrappedTokenPrice, message.tokenAmounts);
+ expectedFeeUSDWei = applyBpsRatio(
+ calcUSDValueFromTokenAmount(tokenPrices[0], message.tokenAmounts[0].amount), tokenTransferFeeConfigs[0].deciBps
+ );
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[1].maxFeeUSDCents);
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[2].minFeeUSDCents);
+
+ assertEq(expectedFeeUSDWei, feeUSDWei);
+ assertEq(expectedTotalGas, destGasOverhead);
+ assertEq(expectedTotalBytes, destBytesOverhead);
+ }
+
+ // reverts
+
+ function test_UnsupportedToken_Revert() public {
+ address NOT_SUPPORTED_TOKEN = address(123);
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(NOT_SUPPORTED_TOKEN, 200);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.UnsupportedToken.selector, NOT_SUPPORTED_TOKEN));
+
+ s_onRamp.getTokenTransferCost(message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+ }
+}
+
+contract EVM2EVMOnRamp_getFee is EVM2EVMOnRamp_getFeeSetup {
+ using USDPriceWith18Decimals for uint224;
+
+ function test_EmptyMessage_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = testTokens[i];
+ EVM2EVMOnRamp.FeeTokenConfig memory feeTokenConfig = s_onRamp.getFeeTokenConfig(message.feeToken);
+
+ uint256 feeAmount = s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+
+ uint256 gasUsed = GAS_LIMIT + DEST_GAS_OVERHEAD;
+ uint256 gasFeeUSD = (gasUsed * feeTokenConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ uint256 messageFeeUSD =
+ (configUSDCentToWei(feeTokenConfig.networkFeeUSDCents) * feeTokenConfig.premiumMultiplierWeiPerEth);
+ uint256 dataAvailabilityFeeUSD = s_onRamp.getDataAvailabilityCost(
+ USD_PER_DATA_AVAILABILITY_GAS, message.data.length, message.tokenAmounts.length, 0
+ );
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD + dataAvailabilityFeeUSD) / feeTokenPrices[i];
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+ }
+
+ function test_ZeroDataAvailabilityMultiplier_Success() public {
+ EVM2EVMOnRamp.DynamicConfig memory dynamicConfig = s_onRamp.getDynamicConfig();
+ dynamicConfig.destDataAvailabilityMultiplierBps = 0;
+ s_onRamp.setDynamicConfig(dynamicConfig);
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ EVM2EVMOnRamp.FeeTokenConfig memory feeTokenConfig = s_onRamp.getFeeTokenConfig(message.feeToken);
+
+ uint256 feeAmount = s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+
+ uint256 gasUsed = GAS_LIMIT + DEST_GAS_OVERHEAD;
+ uint256 gasFeeUSD = (gasUsed * feeTokenConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ uint256 messageFeeUSD =
+ (configUSDCentToWei(feeTokenConfig.networkFeeUSDCents) * feeTokenConfig.premiumMultiplierWeiPerEth);
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD) / s_feeTokenPrice;
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+
+ function test_HighGasMessage_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ uint256 customGasLimit = MAX_GAS_LIMIT;
+ uint256 customDataSize = MAX_DATA_SIZE;
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: new bytes(customDataSize),
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ feeToken: testTokens[i],
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: customGasLimit}))
+ });
+
+ EVM2EVMOnRamp.FeeTokenConfig memory feeTokenConfig = s_onRamp.getFeeTokenConfig(message.feeToken);
+ uint256 feeAmount = s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+
+ uint256 gasUsed = customGasLimit + DEST_GAS_OVERHEAD + customDataSize * DEST_GAS_PER_PAYLOAD_BYTE;
+ uint256 gasFeeUSD = (gasUsed * feeTokenConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ uint256 messageFeeUSD =
+ (configUSDCentToWei(feeTokenConfig.networkFeeUSDCents) * feeTokenConfig.premiumMultiplierWeiPerEth);
+ uint256 dataAvailabilityFeeUSD = s_onRamp.getDataAvailabilityCost(
+ USD_PER_DATA_AVAILABILITY_GAS, message.data.length, message.tokenAmounts.length, 0
+ );
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD + dataAvailabilityFeeUSD) / feeTokenPrices[i];
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+ }
+
+ function test_SingleTokenMessage_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ uint256 tokenAmount = 10000e18;
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, tokenAmount);
+ message.feeToken = testTokens[i];
+ EVM2EVMOnRamp.FeeTokenConfig memory feeTokenConfig = s_onRamp.getFeeTokenConfig(message.feeToken);
+ uint32 tokenGasOverhead = s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token).destGasOverhead;
+ uint32 destBytesOverhead = s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[0].token).destBytesOverhead;
+ uint32 tokenBytesOverhead =
+ destBytesOverhead == 0 ? uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) : destBytesOverhead;
+
+ uint256 feeAmount = s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+
+ uint256 gasUsed = GAS_LIMIT + DEST_GAS_OVERHEAD + tokenGasOverhead;
+ uint256 gasFeeUSD = (gasUsed * feeTokenConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ (uint256 transferFeeUSD,,) =
+ s_onRamp.getTokenTransferCost(message.feeToken, feeTokenPrices[i], message.tokenAmounts);
+ uint256 messageFeeUSD = (transferFeeUSD * feeTokenConfig.premiumMultiplierWeiPerEth);
+ uint256 dataAvailabilityFeeUSD = s_onRamp.getDataAvailabilityCost(
+ USD_PER_DATA_AVAILABILITY_GAS, message.data.length, message.tokenAmounts.length, tokenBytesOverhead
+ );
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD + dataAvailabilityFeeUSD) / feeTokenPrices[i];
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+ }
+
+ function test_MessageWithDataAndTokenTransfer_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ uint256 customGasLimit = 1_000_000;
+ uint256 feeTokenAmount = 10000e18;
+ uint256 customTokenAmount = 200000e18;
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](2),
+ feeToken: testTokens[i],
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: customGasLimit}))
+ });
+ EVM2EVMOnRamp.FeeTokenConfig memory feeTokenConfig = s_onRamp.getFeeTokenConfig(message.feeToken);
+
+ message.tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceFeeToken, amount: feeTokenAmount});
+ message.tokenAmounts[1] = Client.EVMTokenAmount({token: CUSTOM_TOKEN, amount: customTokenAmount});
+ message.data = "random bits and bytes that should be factored into the cost of the message";
+
+ uint32 tokenGasOverhead = 0;
+ uint32 tokenBytesOverhead = 0;
+ for (uint256 j = 0; j < message.tokenAmounts.length; ++j) {
+ tokenGasOverhead += s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[j].token).destGasOverhead;
+ uint32 destBytesOverhead = s_onRamp.getTokenTransferFeeConfig(message.tokenAmounts[j].token).destBytesOverhead;
+ tokenBytesOverhead += destBytesOverhead == 0 ? uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) : destBytesOverhead;
+ }
+
+ uint256 feeAmount = s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+
+ uint256 gasUsed =
+ customGasLimit + DEST_GAS_OVERHEAD + message.data.length * DEST_GAS_PER_PAYLOAD_BYTE + tokenGasOverhead;
+ uint256 gasFeeUSD = (gasUsed * feeTokenConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ (uint256 transferFeeUSD,,) =
+ s_onRamp.getTokenTransferCost(message.feeToken, feeTokenPrices[i], message.tokenAmounts);
+ uint256 messageFeeUSD = (transferFeeUSD * feeTokenConfig.premiumMultiplierWeiPerEth);
+ uint256 dataAvailabilityFeeUSD = s_onRamp.getDataAvailabilityCost(
+ USD_PER_DATA_AVAILABILITY_GAS, message.data.length, message.tokenAmounts.length, tokenBytesOverhead
+ );
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD + dataAvailabilityFeeUSD) / feeTokenPrices[i];
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+ }
+
+ // Reverts
+
+ function test_NotAFeeToken_Revert() public {
+ address notAFeeToken = address(0x111111);
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(notAFeeToken, 1);
+ message.feeToken = notAFeeToken;
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.NotAFeeToken.selector, notAFeeToken));
+
+ s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_MessageTooLarge_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.data = new bytes(MAX_DATA_SIZE + 1);
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.MessageTooLarge.selector, MAX_DATA_SIZE, message.data.length));
+
+ s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_TooManyTokens_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ uint256 tooMany = MAX_TOKENS_LENGTH + 1;
+ message.tokenAmounts = new Client.EVMTokenAmount[](tooMany);
+ vm.expectRevert(EVM2EVMOnRamp.UnsupportedNumberOfTokens.selector);
+ s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ // Asserts gasLimit must be <=maxGasLimit
+ function test_MessageGasLimitTooHigh_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: MAX_GAS_LIMIT + 1}));
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.MessageGasLimitTooHigh.selector));
+ s_onRamp.getFee(DEST_CHAIN_SELECTOR, message);
+ }
+}
+
+contract EVM2EVMOnRamp_setNops is EVM2EVMOnRampSetup {
+ // Used because EnumerableMap doesn't guarantee order
+ mapping(address nop => uint256 weight) internal s_nopsToWeights;
+
+ function test_SetNops_Success() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = getNopsAndWeights();
+ nopsAndWeights[1].nop = USER_4;
+ nopsAndWeights[1].weight = 20;
+ for (uint256 i = 0; i < nopsAndWeights.length; ++i) {
+ s_nopsToWeights[nopsAndWeights[i].nop] = nopsAndWeights[i].weight;
+ }
+
+ s_onRamp.setNops(nopsAndWeights);
+
+ (EVM2EVMOnRamp.NopAndWeight[] memory actual,) = s_onRamp.getNops();
+ for (uint256 i = 0; i < actual.length; ++i) {
+ assertEq(actual[i].weight, s_nopsToWeights[actual[i].nop]);
+ }
+ }
+
+ function test_AdminCanSetNops_Success() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = getNopsAndWeights();
+ // Should not revert
+ vm.startPrank(ADMIN);
+ s_onRamp.setNops(nopsAndWeights);
+ }
+
+ function test_IncludesPayment_Success() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = getNopsAndWeights();
+ nopsAndWeights[1].nop = USER_4;
+ nopsAndWeights[1].weight = 20;
+ uint32 totalWeight;
+ for (uint256 i = 0; i < nopsAndWeights.length; ++i) {
+ totalWeight += nopsAndWeights[i].weight;
+ s_nopsToWeights[nopsAndWeights[i].nop] = nopsAndWeights[i].weight;
+ }
+
+ // Make sure a payout happens regardless of what the weights are set to
+ uint96 nopFeesJuels = totalWeight * 5;
+ // Set Nop fee juels
+ deal(s_sourceFeeToken, address(s_onRamp), nopFeesJuels);
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), nopFeesJuels, OWNER);
+ vm.startPrank(OWNER);
+
+ // We don't care about the fee calculation logic in this test
+ // so we don't verify the amounts. We do verify the addresses to
+ // make sure the existing nops get paid and not the new ones.
+ EVM2EVMOnRamp.NopAndWeight[] memory existingNopsAndWeights = getNopsAndWeights();
+ for (uint256 i = 0; i < existingNopsAndWeights.length; ++i) {
+ vm.expectEmit(true, false, false, false);
+ emit EVM2EVMOnRamp.NopPaid(existingNopsAndWeights[i].nop, 0);
+ }
+
+ s_onRamp.setNops(nopsAndWeights);
+
+ (EVM2EVMOnRamp.NopAndWeight[] memory actual,) = s_onRamp.getNops();
+ for (uint256 i = 0; i < actual.length; ++i) {
+ assertEq(actual[i].weight, s_nopsToWeights[actual[i].nop]);
+ }
+ }
+
+ function test_SetNopsRemovesOldNopsCompletely_Success() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = new EVM2EVMOnRamp.NopAndWeight[](0);
+ s_onRamp.setNops(nopsAndWeights);
+ (EVM2EVMOnRamp.NopAndWeight[] memory actual, uint256 totalWeight) = s_onRamp.getNops();
+ assertEq(actual.length, 0);
+ assertEq(totalWeight, 0);
+
+ address prevNop = getNopsAndWeights()[0].nop;
+ vm.startPrank(prevNop);
+
+ // prev nop should not have permission to call payNops
+ vm.expectRevert(EVM2EVMOnRamp.OnlyCallableByOwnerOrAdminOrNop.selector);
+ s_onRamp.payNops();
+ }
+
+ // Reverts
+
+ function test_NotEnoughFundsForPayout_Revert() public {
+ uint96 nopFeesJuels = MAX_NOP_FEES_JUELS;
+ // Set Nop fee juels but don't transfer LINK. This can happen when users
+ // pay in non-link tokens.
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), nopFeesJuels, OWNER);
+ vm.startPrank(OWNER);
+
+ vm.expectRevert(EVM2EVMOnRamp.InsufficientBalance.selector);
+
+ s_onRamp.setNops(getNopsAndWeights());
+ }
+
+ function test_NonOwnerOrAdmin_Revert() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = getNopsAndWeights();
+ vm.startPrank(STRANGER);
+ vm.expectRevert(EVM2EVMOnRamp.OnlyCallableByOwnerOrAdmin.selector);
+ s_onRamp.setNops(nopsAndWeights);
+ }
+
+ function test_LinkTokenCannotBeNop_Revert() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = getNopsAndWeights();
+ nopsAndWeights[0].nop = address(s_sourceTokens[0]);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.InvalidNopAddress.selector, address(s_sourceTokens[0])));
+
+ s_onRamp.setNops(nopsAndWeights);
+ }
+
+ function test_ZeroAddressCannotBeNop_Revert() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = getNopsAndWeights();
+ nopsAndWeights[0].nop = address(0);
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.InvalidNopAddress.selector, address(0)));
+
+ s_onRamp.setNops(nopsAndWeights);
+ }
+
+ function test_TooManyNops_Revert() public {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = new EVM2EVMOnRamp.NopAndWeight[](257);
+
+ vm.expectRevert(EVM2EVMOnRamp.TooManyNops.selector);
+
+ s_onRamp.setNops(nopsAndWeights);
+ }
+}
+
+contract EVM2EVMOnRamp_withdrawNonLinkFees is EVM2EVMOnRampSetup {
+ IERC20 internal s_token;
+
+ function setUp() public virtual override {
+ EVM2EVMOnRampSetup.setUp();
+ // Send some non-link tokens to the onRamp
+ s_token = IERC20(s_sourceTokens[1]);
+ deal(s_sourceTokens[1], address(s_onRamp), 100);
+ }
+
+ function test_WithdrawNonLinkFees_Success() public {
+ s_onRamp.withdrawNonLinkFees(address(s_token), address(this));
+
+ assertEq(0, s_token.balanceOf(address(s_onRamp)));
+ assertEq(100, s_token.balanceOf(address(this)));
+ }
+
+ function test_SettlingBalance_Success() public {
+ // Set Nop fee juels
+ uint96 nopFeesJuels = 10000000;
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), nopFeesJuels, OWNER);
+ vm.startPrank(OWNER);
+
+ vm.expectRevert(EVM2EVMOnRamp.LinkBalanceNotSettled.selector);
+ s_onRamp.withdrawNonLinkFees(address(s_token), address(this));
+
+ // It doesnt matter how the link tokens get to the onRamp
+ // In this case we simply deal them to the ramp to show
+ // anyone can settle the balance
+ deal(s_sourceTokens[0], address(s_onRamp), nopFeesJuels);
+
+ s_onRamp.withdrawNonLinkFees(address(s_token), address(this));
+ }
+
+ function test_Fuzz_FuzzWithdrawalOnlyLeftoverLink_Success(uint96 nopFeeJuels, uint64 extraJuels) public {
+ nopFeeJuels = uint96(bound(nopFeeJuels, 1, MAX_NOP_FEES_JUELS));
+
+ // Set Nop fee juels
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), nopFeeJuels, OWNER);
+ vm.startPrank(OWNER);
+
+ vm.expectRevert(EVM2EVMOnRamp.LinkBalanceNotSettled.selector);
+ s_onRamp.withdrawNonLinkFees(address(s_token), address(this));
+
+ address linkToken = s_sourceTokens[0];
+ // It doesnt matter how the link tokens get to the onRamp
+ // In this case we simply deal them to the ramp to show
+ // anyone can settle the balance
+ deal(linkToken, address(s_onRamp), nopFeeJuels + uint96(extraJuels));
+
+ // Now that we've sent nopFeesJuels + extraJuels, we should be able to withdraw extraJuels
+ address linkRecipient = address(0x123456789);
+ assertEq(0, IERC20(linkToken).balanceOf(linkRecipient));
+
+ s_onRamp.withdrawNonLinkFees(linkToken, linkRecipient);
+
+ assertEq(extraJuels, IERC20(linkToken).balanceOf(linkRecipient));
+ }
+
+ // Reverts
+
+ function test_LinkBalanceNotSettled_Revert() public {
+ // Set Nop fee juels
+ uint96 nopFeesJuels = 10000000;
+ vm.startPrank(address(s_sourceRouter));
+ s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, _generateEmptyMessage(), nopFeesJuels, OWNER);
+ vm.startPrank(OWNER);
+
+ vm.expectRevert(EVM2EVMOnRamp.LinkBalanceNotSettled.selector);
+
+ s_onRamp.withdrawNonLinkFees(address(s_token), address(this));
+ }
+
+ function test_NonOwnerOrAdmin_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(EVM2EVMOnRamp.OnlyCallableByOwnerOrAdmin.selector);
+ s_onRamp.withdrawNonLinkFees(address(s_token), address(this));
+ }
+
+ function test_WithdrawToZeroAddress_Revert() public {
+ vm.expectRevert(EVM2EVMOnRamp.InvalidWithdrawParams.selector);
+ s_onRamp.withdrawNonLinkFees(address(s_token), address(0));
+ }
+}
+
+contract EVM2EVMOnRamp_setFeeTokenConfig is EVM2EVMOnRampSetup {
+ function test_SetFeeTokenConfig_Success() public {
+ EVM2EVMOnRamp.FeeTokenConfigArgs[] memory feeConfig;
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.FeeConfigSet(feeConfig);
+
+ s_onRamp.setFeeTokenConfig(feeConfig);
+ }
+
+ function test_SetFeeTokenConfigByAdmin_Success() public {
+ EVM2EVMOnRamp.FeeTokenConfigArgs[] memory feeConfig;
+
+ vm.startPrank(ADMIN);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.FeeConfigSet(feeConfig);
+
+ s_onRamp.setFeeTokenConfig(feeConfig);
+ }
+
+ // Reverts
+
+ function test_OnlyCallableByOwnerOrAdmin_Revert() public {
+ EVM2EVMOnRamp.FeeTokenConfigArgs[] memory feeConfig;
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(EVM2EVMOnRamp.OnlyCallableByOwnerOrAdmin.selector);
+
+ s_onRamp.setFeeTokenConfig(feeConfig);
+ }
+}
+
+contract EVM2EVMOnRamp_setTokenTransferFeeConfig is EVM2EVMOnRampSetup {
+ function test__setTokenTransferFeeConfig_Success() public {
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] memory tokenTransferFeeArgs =
+ new EVM2EVMOnRamp.TokenTransferFeeConfigArgs[](2);
+ tokenTransferFeeArgs[0] = EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: address(5),
+ minFeeUSDCents: 6,
+ maxFeeUSDCents: 7,
+ deciBps: 8,
+ destGasOverhead: 9,
+ destBytesOverhead: 312,
+ aggregateRateLimitEnabled: true
+ });
+ tokenTransferFeeArgs[1] = EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: address(11),
+ minFeeUSDCents: 12,
+ maxFeeUSDCents: 13,
+ deciBps: 14,
+ destGasOverhead: 15,
+ destBytesOverhead: 394,
+ aggregateRateLimitEnabled: false
+ });
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.TokenTransferFeeConfigSet(tokenTransferFeeArgs);
+
+ s_onRamp.setTokenTransferFeeConfig(tokenTransferFeeArgs, new address[](0));
+
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory config0 =
+ s_onRamp.getTokenTransferFeeConfig(tokenTransferFeeArgs[0].token);
+
+ assertEq(tokenTransferFeeArgs[0].minFeeUSDCents, config0.minFeeUSDCents);
+ assertEq(tokenTransferFeeArgs[0].maxFeeUSDCents, config0.maxFeeUSDCents);
+ assertEq(tokenTransferFeeArgs[0].deciBps, config0.deciBps);
+ assertEq(tokenTransferFeeArgs[0].destGasOverhead, config0.destGasOverhead);
+ assertEq(tokenTransferFeeArgs[0].destBytesOverhead, config0.destBytesOverhead);
+ assertEq(tokenTransferFeeArgs[0].aggregateRateLimitEnabled, config0.aggregateRateLimitEnabled);
+ assertTrue(config0.isEnabled);
+
+ EVM2EVMOnRamp.TokenTransferFeeConfig memory config1 =
+ s_onRamp.getTokenTransferFeeConfig(tokenTransferFeeArgs[1].token);
+
+ assertEq(tokenTransferFeeArgs[1].minFeeUSDCents, config1.minFeeUSDCents);
+ assertEq(tokenTransferFeeArgs[1].maxFeeUSDCents, config1.maxFeeUSDCents);
+ assertEq(tokenTransferFeeArgs[1].deciBps, config1.deciBps);
+ assertEq(tokenTransferFeeArgs[1].destGasOverhead, config1.destGasOverhead);
+ assertEq(tokenTransferFeeArgs[1].destBytesOverhead, config1.destBytesOverhead);
+ assertEq(tokenTransferFeeArgs[1].aggregateRateLimitEnabled, config1.aggregateRateLimitEnabled);
+ assertTrue(config0.isEnabled);
+
+ // Remove only the first token and validate only the first token is removed
+ address[] memory tokensToRemove = new address[](1);
+ tokensToRemove[0] = tokenTransferFeeArgs[0].token;
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.TokenTransferFeeConfigDeleted(tokensToRemove);
+
+ s_onRamp.setTokenTransferFeeConfig(new EVM2EVMOnRamp.TokenTransferFeeConfigArgs[](0), tokensToRemove);
+
+ config0 = s_onRamp.getTokenTransferFeeConfig(tokenTransferFeeArgs[0].token);
+
+ assertEq(0, config0.minFeeUSDCents);
+ assertEq(0, config0.maxFeeUSDCents);
+ assertEq(0, config0.deciBps);
+ assertEq(0, config0.destGasOverhead);
+ assertEq(0, config0.destBytesOverhead);
+ assertFalse(config0.aggregateRateLimitEnabled);
+ assertFalse(config0.isEnabled);
+
+ config1 = s_onRamp.getTokenTransferFeeConfig(tokenTransferFeeArgs[1].token);
+
+ assertEq(tokenTransferFeeArgs[1].minFeeUSDCents, config1.minFeeUSDCents);
+ assertEq(tokenTransferFeeArgs[1].maxFeeUSDCents, config1.maxFeeUSDCents);
+ assertEq(tokenTransferFeeArgs[1].deciBps, config1.deciBps);
+ assertEq(tokenTransferFeeArgs[1].destGasOverhead, config1.destGasOverhead);
+ assertEq(tokenTransferFeeArgs[1].destBytesOverhead, config1.destBytesOverhead);
+ assertEq(tokenTransferFeeArgs[1].aggregateRateLimitEnabled, config1.aggregateRateLimitEnabled);
+ assertTrue(config1.isEnabled);
+ }
+
+ function test__setTokenTransferFeeConfig_byAdmin_Success() public {
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] memory transferFeeConfig;
+ vm.startPrank(ADMIN);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.TokenTransferFeeConfigSet(transferFeeConfig);
+
+ s_onRamp.setTokenTransferFeeConfig(transferFeeConfig, new address[](0));
+ }
+
+ // Reverts
+
+ function test__setTokenTransferFeeConfig_InvalidDestBytesOverhead_Revert() public {
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] memory transferFeeConfig =
+ new EVM2EVMOnRamp.TokenTransferFeeConfigArgs[](1);
+ transferFeeConfig[0].destBytesOverhead = uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) - 1;
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ EVM2EVMOnRamp.InvalidDestBytesOverhead.selector,
+ transferFeeConfig[0].token,
+ transferFeeConfig[0].destBytesOverhead
+ )
+ );
+ s_onRamp.setTokenTransferFeeConfig(transferFeeConfig, new address[](0));
+ }
+
+ function test__setTokenTransferFeeConfig_OnlyCallableByOwnerOrAdmin_Revert() public {
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] memory transferFeeConfig;
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(EVM2EVMOnRamp.OnlyCallableByOwnerOrAdmin.selector);
+
+ s_onRamp.setTokenTransferFeeConfig(transferFeeConfig, new address[](0));
+ }
+}
+
+contract EVM2EVMOnRamp_getTokenPool is EVM2EVMOnRampSetup {
+ function test_GetTokenPool_Success() public view {
+ assertEq(
+ s_sourcePoolByToken[s_sourceTokens[0]],
+ address(s_onRamp.getPoolBySourceToken(DEST_CHAIN_SELECTOR, IERC20(s_sourceTokens[0])))
+ );
+ assertEq(
+ s_sourcePoolByToken[s_sourceTokens[1]],
+ address(s_onRamp.getPoolBySourceToken(DEST_CHAIN_SELECTOR, IERC20(s_sourceTokens[1])))
+ );
+
+ address wrongToken = address(123);
+ address nonExistentPool = address(s_onRamp.getPoolBySourceToken(DEST_CHAIN_SELECTOR, IERC20(wrongToken)));
+
+ assertEq(address(0), nonExistentPool);
+ }
+}
+
+contract EVM2EVMOnRamp_setDynamicConfig is EVM2EVMOnRampSetup {
+ function test_SetDynamicConfig_Success() public {
+ EVM2EVMOnRamp.StaticConfig memory staticConfig = s_onRamp.getStaticConfig();
+ EVM2EVMOnRamp.DynamicConfig memory newConfig = EVM2EVMOnRamp.DynamicConfig({
+ router: address(2134),
+ maxNumberOfTokensPerMsg: 14,
+ destGasOverhead: DEST_GAS_OVERHEAD / 2,
+ destGasPerPayloadByte: DEST_GAS_PER_PAYLOAD_BYTE / 2,
+ destDataAvailabilityOverheadGas: DEST_DATA_AVAILABILITY_OVERHEAD_GAS,
+ destGasPerDataAvailabilityByte: DEST_GAS_PER_DATA_AVAILABILITY_BYTE,
+ destDataAvailabilityMultiplierBps: DEST_GAS_DATA_AVAILABILITY_MULTIPLIER_BPS,
+ priceRegistry: address(23423),
+ maxDataBytes: 400,
+ maxPerMsgGasLimit: MAX_GAS_LIMIT / 2,
+ defaultTokenFeeUSDCents: DEFAULT_TOKEN_FEE_USD_CENTS,
+ defaultTokenDestGasOverhead: DEFAULT_TOKEN_DEST_GAS_OVERHEAD,
+ defaultTokenDestBytesOverhead: DEFAULT_TOKEN_BYTES_OVERHEAD,
+ enforceOutOfOrder: false
+ });
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.ConfigSet(staticConfig, newConfig);
+
+ s_onRamp.setDynamicConfig(newConfig);
+
+ EVM2EVMOnRamp.DynamicConfig memory gotDynamicConfig = s_onRamp.getDynamicConfig();
+ assertEq(newConfig.router, gotDynamicConfig.router);
+ assertEq(newConfig.maxNumberOfTokensPerMsg, gotDynamicConfig.maxNumberOfTokensPerMsg);
+ assertEq(newConfig.destGasOverhead, gotDynamicConfig.destGasOverhead);
+ assertEq(newConfig.destGasPerPayloadByte, gotDynamicConfig.destGasPerPayloadByte);
+ assertEq(newConfig.priceRegistry, gotDynamicConfig.priceRegistry);
+ assertEq(newConfig.maxDataBytes, gotDynamicConfig.maxDataBytes);
+ assertEq(newConfig.maxPerMsgGasLimit, gotDynamicConfig.maxPerMsgGasLimit);
+ }
+
+ // Reverts
+
+ function test_SetConfigInvalidConfig_Revert() public {
+ EVM2EVMOnRamp.DynamicConfig memory newConfig = EVM2EVMOnRamp.DynamicConfig({
+ router: address(1),
+ maxNumberOfTokensPerMsg: 14,
+ destGasOverhead: DEST_GAS_OVERHEAD / 2,
+ destGasPerPayloadByte: DEST_GAS_PER_PAYLOAD_BYTE / 2,
+ destDataAvailabilityOverheadGas: DEST_DATA_AVAILABILITY_OVERHEAD_GAS,
+ destGasPerDataAvailabilityByte: DEST_GAS_PER_DATA_AVAILABILITY_BYTE,
+ destDataAvailabilityMultiplierBps: DEST_GAS_DATA_AVAILABILITY_MULTIPLIER_BPS,
+ priceRegistry: address(23423),
+ maxDataBytes: 400,
+ maxPerMsgGasLimit: MAX_GAS_LIMIT / 2,
+ defaultTokenFeeUSDCents: DEFAULT_TOKEN_FEE_USD_CENTS,
+ defaultTokenDestGasOverhead: DEFAULT_TOKEN_DEST_GAS_OVERHEAD,
+ defaultTokenDestBytesOverhead: DEFAULT_TOKEN_BYTES_OVERHEAD,
+ enforceOutOfOrder: false
+ });
+
+ // Invalid price reg reverts.
+ newConfig.priceRegistry = address(0);
+ vm.expectRevert(EVM2EVMOnRamp.InvalidConfig.selector);
+ s_onRamp.setDynamicConfig(newConfig);
+
+ // Succeeds if valid
+ newConfig.priceRegistry = address(23423);
+ s_onRamp.setDynamicConfig(newConfig);
+ }
+
+ function test_SetConfigOnlyOwner_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+ s_onRamp.setDynamicConfig(generateDynamicOnRampConfig(address(1), address(2)));
+ vm.startPrank(ADMIN);
+ vm.expectRevert("Only callable by owner");
+ s_onRamp.setDynamicConfig(generateDynamicOnRampConfig(address(1), address(2)));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRampSetup.t.sol b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRampSetup.t.sol
new file mode 100644
index 00000000000..6659b1217fd
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/onRamp/EVM2EVMOnRampSetup.t.sol
@@ -0,0 +1,261 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPoolV1} from "../../interfaces/IPool.sol";
+
+import {PriceRegistry} from "../../PriceRegistry.sol";
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {EVM2EVMOnRamp} from "../../onRamp/EVM2EVMOnRamp.sol";
+import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {TokenSetup} from "../TokenSetup.t.sol";
+import {EVM2EVMOnRampHelper} from "../helpers/EVM2EVMOnRampHelper.sol";
+import {PriceRegistrySetup} from "../priceRegistry/PriceRegistry.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract EVM2EVMOnRampSetup is TokenSetup, PriceRegistrySetup {
+ uint256 internal immutable i_tokenAmount0 = 9;
+ uint256 internal immutable i_tokenAmount1 = 7;
+
+ bytes32 internal s_metadataHash;
+
+ EVM2EVMOnRampHelper internal s_onRamp;
+ address[] internal s_offRamps;
+
+ address internal s_destTokenPool = makeAddr("destTokenPool");
+ address internal s_destToken = makeAddr("destToken");
+
+ EVM2EVMOnRamp.FeeTokenConfigArgs[] internal s_feeTokenConfigArgs;
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs[] internal s_tokenTransferFeeConfigArgs;
+
+ function setUp() public virtual override(TokenSetup, PriceRegistrySetup) {
+ TokenSetup.setUp();
+ PriceRegistrySetup.setUp();
+
+ s_priceRegistry.updatePrices(getSingleTokenPriceUpdateStruct(CUSTOM_TOKEN, CUSTOM_TOKEN_PRICE));
+
+ address WETH = s_sourceRouter.getWrappedNative();
+
+ s_feeTokenConfigArgs.push(
+ EVM2EVMOnRamp.FeeTokenConfigArgs({
+ token: s_sourceFeeToken,
+ networkFeeUSDCents: 1_00, // 1 USD
+ gasMultiplierWeiPerEth: 1e18, // 1x
+ premiumMultiplierWeiPerEth: 5e17, // 0.5x
+ enabled: true
+ })
+ );
+ s_feeTokenConfigArgs.push(
+ EVM2EVMOnRamp.FeeTokenConfigArgs({
+ token: WETH,
+ networkFeeUSDCents: 5_00, // 5 USD
+ gasMultiplierWeiPerEth: 2e18, // 2x
+ premiumMultiplierWeiPerEth: 2e18, // 2x
+ enabled: true
+ })
+ );
+
+ s_tokenTransferFeeConfigArgs.push(
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: s_sourceFeeToken,
+ minFeeUSDCents: 1_00, // 1 USD
+ maxFeeUSDCents: 1000_00, // 1,000 USD
+ deciBps: 2_5, // 2.5 bps, or 0.025%
+ destGasOverhead: 40_000,
+ destBytesOverhead: uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES),
+ aggregateRateLimitEnabled: true
+ })
+ );
+ s_tokenTransferFeeConfigArgs.push(
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: s_sourceRouter.getWrappedNative(),
+ minFeeUSDCents: 50, // 0.5 USD
+ maxFeeUSDCents: 500_00, // 500 USD
+ deciBps: 5_0, // 5 bps, or 0.05%
+ destGasOverhead: 10_000,
+ destBytesOverhead: 100,
+ aggregateRateLimitEnabled: true
+ })
+ );
+ s_tokenTransferFeeConfigArgs.push(
+ EVM2EVMOnRamp.TokenTransferFeeConfigArgs({
+ token: CUSTOM_TOKEN,
+ minFeeUSDCents: 2_00, // 1 USD
+ maxFeeUSDCents: 2000_00, // 1,000 USD
+ deciBps: 10_0, // 10 bps, or 0.1%
+ destGasOverhead: 1,
+ destBytesOverhead: 200,
+ aggregateRateLimitEnabled: true
+ })
+ );
+
+ s_onRamp = new EVM2EVMOnRampHelper(
+ EVM2EVMOnRamp.StaticConfig({
+ linkToken: s_sourceTokens[0],
+ chainSelector: SOURCE_CHAIN_SELECTOR,
+ destChainSelector: DEST_CHAIN_SELECTOR,
+ defaultTxGasLimit: GAS_LIMIT,
+ maxNopFeesJuels: MAX_NOP_FEES_JUELS,
+ prevOnRamp: address(0),
+ rmnProxy: address(s_mockRMN),
+ tokenAdminRegistry: address(s_tokenAdminRegistry)
+ }),
+ generateDynamicOnRampConfig(address(s_sourceRouter), address(s_priceRegistry)),
+ getOutboundRateLimiterConfig(),
+ s_feeTokenConfigArgs,
+ s_tokenTransferFeeConfigArgs,
+ getNopsAndWeights()
+ );
+ s_onRamp.setAdmin(ADMIN);
+
+ s_metadataHash = keccak256(
+ abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, SOURCE_CHAIN_SELECTOR, DEST_CHAIN_SELECTOR, address(s_onRamp))
+ );
+
+ s_offRamps = new address[](2);
+ s_offRamps[0] = address(10);
+ s_offRamps[1] = address(11);
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](2);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: address(s_onRamp)});
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: s_offRamps[0]});
+ offRampUpdates[1] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: s_offRamps[1]});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+
+ // Pre approve the first token so the gas estimates of the tests
+ // only cover actual gas usage from the ramps
+ IERC20(s_sourceTokens[0]).approve(address(s_sourceRouter), 2 ** 128);
+ IERC20(s_sourceTokens[1]).approve(address(s_sourceRouter), 2 ** 128);
+ }
+
+ function getNopsAndWeights() internal pure returns (EVM2EVMOnRamp.NopAndWeight[] memory) {
+ EVM2EVMOnRamp.NopAndWeight[] memory nopsAndWeights = new EVM2EVMOnRamp.NopAndWeight[](3);
+ nopsAndWeights[0] = EVM2EVMOnRamp.NopAndWeight({nop: USER_1, weight: 19284});
+ nopsAndWeights[1] = EVM2EVMOnRamp.NopAndWeight({nop: USER_2, weight: 52935});
+ nopsAndWeights[2] = EVM2EVMOnRamp.NopAndWeight({nop: USER_3, weight: 8});
+ return nopsAndWeights;
+ }
+
+ function generateDynamicOnRampConfig(
+ address router,
+ address priceRegistry
+ ) internal pure returns (EVM2EVMOnRamp.DynamicConfig memory) {
+ return EVM2EVMOnRamp.DynamicConfig({
+ router: router,
+ maxNumberOfTokensPerMsg: MAX_TOKENS_LENGTH,
+ destGasOverhead: DEST_GAS_OVERHEAD,
+ destGasPerPayloadByte: DEST_GAS_PER_PAYLOAD_BYTE,
+ destDataAvailabilityOverheadGas: DEST_DATA_AVAILABILITY_OVERHEAD_GAS,
+ destGasPerDataAvailabilityByte: DEST_GAS_PER_DATA_AVAILABILITY_BYTE,
+ destDataAvailabilityMultiplierBps: DEST_GAS_DATA_AVAILABILITY_MULTIPLIER_BPS,
+ priceRegistry: priceRegistry,
+ maxDataBytes: MAX_DATA_SIZE,
+ maxPerMsgGasLimit: MAX_GAS_LIMIT,
+ defaultTokenFeeUSDCents: DEFAULT_TOKEN_FEE_USD_CENTS,
+ defaultTokenDestGasOverhead: DEFAULT_TOKEN_DEST_GAS_OVERHEAD,
+ defaultTokenDestBytesOverhead: DEFAULT_TOKEN_BYTES_OVERHEAD,
+ enforceOutOfOrder: false
+ });
+ }
+
+ function _generateTokenMessage() public view returns (Client.EVM2AnyMessage memory) {
+ Client.EVMTokenAmount[] memory tokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
+ tokenAmounts[0].amount = i_tokenAmount0;
+ tokenAmounts[1].amount = i_tokenAmount1;
+ return Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ }
+
+ function _generateSingleTokenMessage(
+ address token,
+ uint256 amount
+ ) public view returns (Client.EVM2AnyMessage memory) {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: token, amount: amount});
+
+ return Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ }
+
+ function _generateEmptyMessage() public view returns (Client.EVM2AnyMessage memory) {
+ return Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ }
+
+ function _messageToEvent(
+ Client.EVM2AnyMessage memory message,
+ uint64 seqNum,
+ uint64 nonce,
+ uint256 feeTokenAmount,
+ address originalSender
+ ) public view returns (Internal.EVM2EVMMessage memory) {
+ // Slicing is only available for calldata. So we have to build a new bytes array.
+ bytes memory args = new bytes(message.extraArgs.length - 4);
+ for (uint256 i = 4; i < message.extraArgs.length; ++i) {
+ args[i - 4] = message.extraArgs[i];
+ }
+ uint256 numberOfTokens = message.tokenAmounts.length;
+ Client.EVMExtraArgsV2 memory extraArgs = _extraArgsFromBytes(bytes4(message.extraArgs), args);
+ Internal.EVM2EVMMessage memory messageEvent = Internal.EVM2EVMMessage({
+ sequenceNumber: seqNum,
+ feeTokenAmount: feeTokenAmount,
+ sender: originalSender,
+ nonce: extraArgs.allowOutOfOrderExecution ? 0 : nonce,
+ gasLimit: extraArgs.gasLimit,
+ strict: false,
+ sourceChainSelector: SOURCE_CHAIN_SELECTOR,
+ receiver: abi.decode(message.receiver, (address)),
+ data: message.data,
+ tokenAmounts: message.tokenAmounts,
+ sourceTokenData: new bytes[](numberOfTokens),
+ feeToken: message.feeToken,
+ messageId: ""
+ });
+
+ for (uint256 i = 0; i < numberOfTokens; ++i) {
+ messageEvent.sourceTokenData[i] = abi.encode(
+ Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(s_sourcePoolByToken[message.tokenAmounts[i].token]),
+ destTokenAddress: abi.encode(s_destTokenBySourceToken[message.tokenAmounts[i].token]),
+ extraData: ""
+ })
+ );
+ }
+
+ messageEvent.messageId = Internal._hash(messageEvent, s_metadataHash);
+ return messageEvent;
+ }
+
+ function _extraArgsFromBytes(
+ bytes4 sig,
+ bytes memory extraArgData
+ ) public pure returns (Client.EVMExtraArgsV2 memory) {
+ if (sig == Client.EVM_EXTRA_ARGS_V1_TAG) {
+ Client.EVMExtraArgsV1 memory extraArgsV1 = abi.decode(extraArgData, (Client.EVMExtraArgsV1));
+ return Client.EVMExtraArgsV2({gasLimit: extraArgsV1.gasLimit, allowOutOfOrderExecution: false});
+ } else if (sig == Client.EVM_EXTRA_ARGS_V2_TAG) {
+ return abi.decode(extraArgData, (Client.EVMExtraArgsV2));
+ } else {
+ revert("Invalid extraArgs tag");
+ }
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/pools/BurnFromMintTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnFromMintTokenPool.t.sol
new file mode 100644
index 00000000000..290c4ae1537
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/pools/BurnFromMintTokenPool.t.sol
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {BurnFromMintTokenPool} from "../../pools/BurnFromMintTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+import {BurnMintSetup} from "./BurnMintSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract BurnFromMintTokenPoolSetup is BurnMintSetup {
+ BurnFromMintTokenPool internal s_pool;
+
+ function setUp() public virtual override {
+ BurnMintSetup.setUp();
+
+ s_pool = new BurnFromMintTokenPool(s_burnMintERC677, new address[](0), address(s_mockRMN), address(s_sourceRouter));
+ s_burnMintERC677.grantMintAndBurnRoles(address(s_pool));
+
+ _applyChainUpdates(address(s_pool));
+ }
+}
+
+contract BurnFromMintTokenPool_lockOrBurn is BurnFromMintTokenPoolSetup {
+ function test_Setup_Success() public view {
+ assertEq(address(s_burnMintERC677), address(s_pool.getToken()));
+ assertEq(address(s_mockRMN), s_pool.getRmnProxy());
+ assertEq(false, s_pool.getAllowListEnabled());
+ assertEq(type(uint256).max, s_burnMintERC677.allowance(address(s_pool), address(s_pool)));
+ assertEq("BurnFromMintTokenPool 1.5.0-dev", s_pool.typeAndVersion());
+ }
+
+ function test_PoolBurn_Success() public {
+ uint256 burnAmount = 20_000e18;
+
+ deal(address(s_burnMintERC677), address(s_pool), burnAmount);
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), burnAmount);
+
+ vm.startPrank(s_burnMintOnRamp);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(burnAmount);
+
+ vm.expectEmit();
+ emit IERC20.Transfer(address(s_pool), address(0), burnAmount);
+
+ vm.expectEmit();
+ emit TokenPool.Burned(address(s_burnMintOnRamp), burnAmount);
+
+ bytes4 expectedSignature = bytes4(keccak256("burnFrom(address,uint256)"));
+ vm.expectCall(address(s_burnMintERC677), abi.encodeWithSelector(expectedSignature, address(s_pool), burnAmount));
+
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: bytes(""),
+ amount: burnAmount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_burnMintERC677)
+ })
+ );
+
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), 0);
+ }
+
+ // Should not burn tokens if cursed.
+ function test_PoolBurnRevertNotHealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ uint256 before = s_burnMintERC677.balanceOf(address(s_pool));
+ vm.startPrank(s_burnMintOnRamp);
+
+ vm.expectRevert(TokenPool.CursedByRMN.selector);
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: bytes(""),
+ amount: 1e5,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_burnMintERC677)
+ })
+ );
+
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), before);
+ }
+
+ function test_ChainNotAllowed_Revert() public {
+ uint64 wrongChainSelector = 8838833;
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, wrongChainSelector));
+ s_pool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: OWNER,
+ amount: 1,
+ localToken: address(s_burnMintERC677),
+ remoteChainSelector: wrongChainSelector,
+ sourcePoolAddress: generateSourceTokenData().sourcePoolAddress,
+ sourcePoolData: generateSourceTokenData().extraData,
+ offchainTokenData: ""
+ })
+ );
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/pools/BurnMintSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnMintSetup.t.sol
new file mode 100644
index 00000000000..a39fd1bb9fa
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/pools/BurnMintSetup.t.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {Router} from "../../Router.sol";
+import {BurnMintTokenPool} from "../../pools/BurnMintTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {RouterSetup} from "../router/RouterSetup.t.sol";
+
+contract BurnMintSetup is RouterSetup {
+ BurnMintERC677 internal s_burnMintERC677;
+ address internal s_burnMintOffRamp = makeAddr("burn_mint_offRamp");
+ address internal s_burnMintOnRamp = makeAddr("burn_mint_onRamp");
+
+ address internal s_remoteBurnMintPool = makeAddr("remote_burn_mint_pool");
+ address internal s_remoteToken = makeAddr("remote_token");
+
+ function setUp() public virtual override {
+ RouterSetup.setUp();
+
+ s_burnMintERC677 = new BurnMintERC677("Chainlink Token", "LINK", 18, 0);
+ }
+
+ function _applyChainUpdates(address pool) internal {
+ TokenPool.ChainUpdate[] memory chains = new TokenPool.ChainUpdate[](1);
+ chains[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_remoteBurnMintPool),
+ remoteTokenAddress: abi.encode(s_remoteToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+
+ BurnMintTokenPool(pool).applyChainUpdates(chains);
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_burnMintOnRamp});
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1);
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: DEST_CHAIN_SELECTOR, offRamp: s_burnMintOffRamp});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/pools/BurnMintTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnMintTokenPool.t.sol
new file mode 100644
index 00000000000..c628c510d43
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/pools/BurnMintTokenPool.t.sol
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPoolV1} from "../../interfaces/IPool.sol";
+
+import {Internal} from "../../libraries/Internal.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {EVM2EVMOffRamp} from "../../offRamp/EVM2EVMOffRamp.sol";
+import {BurnMintTokenPool} from "../../pools/BurnMintTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+import {BurnMintSetup} from "./BurnMintSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract BurnMintTokenPoolSetup is BurnMintSetup {
+ BurnMintTokenPool internal s_pool;
+
+ function setUp() public virtual override {
+ BurnMintSetup.setUp();
+
+ s_pool = new BurnMintTokenPool(s_burnMintERC677, new address[](0), address(s_mockRMN), address(s_sourceRouter));
+ s_burnMintERC677.grantMintAndBurnRoles(address(s_pool));
+
+ _applyChainUpdates(address(s_pool));
+ }
+}
+
+contract BurnMintTokenPool_lockOrBurn is BurnMintTokenPoolSetup {
+ function test_Setup_Success() public view {
+ assertEq(address(s_burnMintERC677), address(s_pool.getToken()));
+ assertEq(address(s_mockRMN), s_pool.getRmnProxy());
+ assertEq(false, s_pool.getAllowListEnabled());
+ assertEq("BurnMintTokenPool 1.5.0-dev", s_pool.typeAndVersion());
+ }
+
+ function test_PoolBurn_Success() public {
+ uint256 burnAmount = 20_000e18;
+
+ deal(address(s_burnMintERC677), address(s_pool), burnAmount);
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), burnAmount);
+
+ vm.startPrank(s_burnMintOnRamp);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(burnAmount);
+
+ vm.expectEmit();
+ emit IERC20.Transfer(address(s_pool), address(0), burnAmount);
+
+ vm.expectEmit();
+ emit TokenPool.Burned(address(s_burnMintOnRamp), burnAmount);
+
+ bytes4 expectedSignature = bytes4(keccak256("burn(uint256)"));
+ vm.expectCall(address(s_burnMintERC677), abi.encodeWithSelector(expectedSignature, burnAmount));
+
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: bytes(""),
+ amount: burnAmount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_burnMintERC677)
+ })
+ );
+
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), 0);
+ }
+
+ // Should not burn tokens if cursed.
+ function test_PoolBurnRevertNotHealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ uint256 before = s_burnMintERC677.balanceOf(address(s_pool));
+ vm.startPrank(s_burnMintOnRamp);
+
+ vm.expectRevert(TokenPool.CursedByRMN.selector);
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: bytes(""),
+ amount: 1e5,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_burnMintERC677)
+ })
+ );
+
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), before);
+ }
+
+ function test_ChainNotAllowed_Revert() public {
+ uint64 wrongChainSelector = 8838833;
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, wrongChainSelector));
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: bytes(""),
+ amount: 1,
+ remoteChainSelector: wrongChainSelector,
+ localToken: address(s_burnMintERC677)
+ })
+ );
+ }
+}
+
+contract BurnMintTokenPool_releaseOrMint is BurnMintTokenPoolSetup {
+ function test_PoolMint_Success() public {
+ uint256 amount = 1e19;
+
+ vm.startPrank(s_burnMintOffRamp);
+
+ vm.expectEmit();
+ emit IERC20.Transfer(address(0), address(s_burnMintOffRamp), amount);
+ s_pool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: OWNER,
+ amount: amount,
+ localToken: address(s_burnMintERC677),
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ sourcePoolAddress: abi.encode(s_remoteBurnMintPool),
+ sourcePoolData: "",
+ offchainTokenData: ""
+ })
+ );
+
+ assertEq(s_burnMintERC677.balanceOf(s_burnMintOffRamp), amount);
+ }
+
+ function test_PoolMintNotHealthy_Revert() public {
+ // Should not mint tokens if cursed.
+ s_mockRMN.setGlobalCursed(true);
+ uint256 before = s_burnMintERC677.balanceOf(OWNER);
+ vm.startPrank(s_burnMintOffRamp);
+
+ vm.expectRevert(TokenPool.CursedByRMN.selector);
+ s_pool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: OWNER,
+ amount: 1e5,
+ localToken: address(s_burnMintERC677),
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ sourcePoolAddress: generateSourceTokenData().sourcePoolAddress,
+ sourcePoolData: generateSourceTokenData().extraData,
+ offchainTokenData: ""
+ })
+ );
+
+ assertEq(s_burnMintERC677.balanceOf(OWNER), before);
+ }
+
+ function test_ChainNotAllowed_Revert() public {
+ uint64 wrongChainSelector = 8838833;
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, wrongChainSelector));
+ s_pool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: OWNER,
+ amount: 1,
+ localToken: address(s_burnMintERC677),
+ remoteChainSelector: wrongChainSelector,
+ sourcePoolAddress: generateSourceTokenData().sourcePoolAddress,
+ sourcePoolData: generateSourceTokenData().extraData,
+ offchainTokenData: ""
+ })
+ );
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/pools/BurnWithFromMintTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/BurnWithFromMintTokenPool.t.sol
new file mode 100644
index 00000000000..22362ee4a55
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/pools/BurnWithFromMintTokenPool.t.sol
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {BurnWithFromMintTokenPool} from "../../pools/BurnWithFromMintTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+import {BurnMintSetup} from "./BurnMintSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract BurnWithFromMintTokenPoolSetup is BurnMintSetup {
+ BurnWithFromMintTokenPool internal s_pool;
+
+ function setUp() public virtual override {
+ BurnMintSetup.setUp();
+
+ s_pool =
+ new BurnWithFromMintTokenPool(s_burnMintERC677, new address[](0), address(s_mockRMN), address(s_sourceRouter));
+ s_burnMintERC677.grantMintAndBurnRoles(address(s_pool));
+
+ _applyChainUpdates(address(s_pool));
+ }
+}
+
+contract BurnWithFromMintTokenPool_lockOrBurn is BurnWithFromMintTokenPoolSetup {
+ function test_Setup_Success() public view {
+ assertEq(address(s_burnMintERC677), address(s_pool.getToken()));
+ assertEq(address(s_mockRMN), s_pool.getRmnProxy());
+ assertEq(false, s_pool.getAllowListEnabled());
+ assertEq(type(uint256).max, s_burnMintERC677.allowance(address(s_pool), address(s_pool)));
+ assertEq("BurnWithFromMintTokenPool 1.5.0-dev", s_pool.typeAndVersion());
+ }
+
+ function test_PoolBurn_Success() public {
+ uint256 burnAmount = 20_000e18;
+
+ deal(address(s_burnMintERC677), address(s_pool), burnAmount);
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), burnAmount);
+
+ vm.startPrank(s_burnMintOnRamp);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(burnAmount);
+
+ vm.expectEmit();
+ emit IERC20.Transfer(address(s_pool), address(0), burnAmount);
+
+ vm.expectEmit();
+ emit TokenPool.Burned(address(s_burnMintOnRamp), burnAmount);
+
+ bytes4 expectedSignature = bytes4(keccak256("burn(address,uint256)"));
+ vm.expectCall(address(s_burnMintERC677), abi.encodeWithSelector(expectedSignature, address(s_pool), burnAmount));
+
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: bytes(""),
+ amount: burnAmount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_burnMintERC677)
+ })
+ );
+
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), 0);
+ }
+
+ // Should not burn tokens if cursed.
+ function test_PoolBurnRevertNotHealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ uint256 before = s_burnMintERC677.balanceOf(address(s_pool));
+ vm.startPrank(s_burnMintOnRamp);
+
+ vm.expectRevert(TokenPool.CursedByRMN.selector);
+ s_pool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: bytes(""),
+ amount: 1e5,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_burnMintERC677)
+ })
+ );
+
+ assertEq(s_burnMintERC677.balanceOf(address(s_pool)), before);
+ }
+
+ function test_ChainNotAllowed_Revert() public {
+ uint64 wrongChainSelector = 8838833;
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, wrongChainSelector));
+ s_pool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: OWNER,
+ amount: 1,
+ localToken: address(s_burnMintERC677),
+ remoteChainSelector: wrongChainSelector,
+ sourcePoolAddress: generateSourceTokenData().sourcePoolAddress,
+ sourcePoolData: generateSourceTokenData().extraData,
+ offchainTokenData: ""
+ })
+ );
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol
new file mode 100644
index 00000000000..97d0d4e8947
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool.t.sol
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPoolV1} from "../../interfaces/IPool.sol";
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {Router} from "../../Router.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {EVM2EVMOffRamp} from "../../offRamp/EVM2EVMOffRamp.sol";
+import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+import {RouterSetup} from "../router/RouterSetup.t.sol";
+
+contract LockReleaseTokenPoolSetup is RouterSetup {
+ IERC20 internal s_token;
+ LockReleaseTokenPool internal s_lockReleaseTokenPool;
+ LockReleaseTokenPool internal s_lockReleaseTokenPoolWithAllowList;
+ address[] internal s_allowedList;
+
+ address internal s_allowedOnRamp = address(123);
+ address internal s_allowedOffRamp = address(234);
+
+ address internal s_destPoolAddress = address(2736782345);
+ address internal s_sourcePoolAddress = address(53852352095);
+
+ function setUp() public virtual override {
+ RouterSetup.setUp();
+ s_token = new BurnMintERC677("LINK", "LNK", 18, 0);
+ deal(address(s_token), OWNER, type(uint256).max);
+ s_lockReleaseTokenPool =
+ new LockReleaseTokenPool(s_token, new address[](0), address(s_mockRMN), true, address(s_sourceRouter));
+
+ s_allowedList.push(USER_1);
+ s_allowedList.push(DUMMY_CONTRACT_ADDRESS);
+ s_lockReleaseTokenPoolWithAllowList =
+ new LockReleaseTokenPool(s_token, s_allowedList, address(s_mockRMN), true, address(s_sourceRouter));
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_destPoolAddress),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+
+ s_lockReleaseTokenPool.applyChainUpdates(chainUpdate);
+ s_lockReleaseTokenPoolWithAllowList.applyChainUpdates(chainUpdate);
+ s_lockReleaseTokenPool.setRebalancer(OWNER);
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_allowedOnRamp});
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: s_allowedOffRamp});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+ }
+}
+
+contract LockReleaseTokenPool_setRebalancer is LockReleaseTokenPoolSetup {
+ function test_SetRebalancer_Success() public {
+ assertEq(address(s_lockReleaseTokenPool.getRebalancer()), OWNER);
+ s_lockReleaseTokenPool.setRebalancer(STRANGER);
+ assertEq(address(s_lockReleaseTokenPool.getRebalancer()), STRANGER);
+ }
+
+ function test_SetRebalancer_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert("Only callable by owner");
+ s_lockReleaseTokenPool.setRebalancer(STRANGER);
+ }
+}
+
+contract LockReleaseTokenPool_lockOrBurn is LockReleaseTokenPoolSetup {
+ function test_Fuzz_LockOrBurnNoAllowList_Success(uint256 amount) public {
+ amount = bound(amount, 1, getOutboundRateLimiterConfig().capacity);
+ vm.startPrank(s_allowedOnRamp);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(amount);
+ vm.expectEmit();
+ emit TokenPool.Locked(s_allowedOnRamp, amount);
+
+ s_lockReleaseTokenPool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: STRANGER,
+ receiver: bytes(""),
+ amount: amount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+ }
+
+ function test_LockOrBurnWithAllowList_Success() public {
+ uint256 amount = 100;
+ vm.startPrank(s_allowedOnRamp);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(amount);
+ vm.expectEmit();
+ emit TokenPool.Locked(s_allowedOnRamp, amount);
+
+ s_lockReleaseTokenPoolWithAllowList.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: s_allowedList[0],
+ receiver: bytes(""),
+ amount: amount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+
+ vm.expectEmit();
+ emit TokenPool.Locked(s_allowedOnRamp, amount);
+
+ s_lockReleaseTokenPoolWithAllowList.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: s_allowedList[1],
+ receiver: bytes(""),
+ amount: amount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+ }
+
+ function test_LockOrBurnWithAllowList_Revert() public {
+ vm.startPrank(s_allowedOnRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.SenderNotAllowed.selector, STRANGER));
+
+ s_lockReleaseTokenPoolWithAllowList.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: STRANGER,
+ receiver: bytes(""),
+ amount: 100,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+ }
+
+ function test_PoolBurnRevertNotHealthy_Revert() public {
+ // Should not burn tokens if cursed.
+ s_mockRMN.setGlobalCursed(true);
+ uint256 before = s_token.balanceOf(address(s_lockReleaseTokenPoolWithAllowList));
+
+ vm.startPrank(s_allowedOnRamp);
+ vm.expectRevert(TokenPool.CursedByRMN.selector);
+
+ s_lockReleaseTokenPoolWithAllowList.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: s_allowedList[0],
+ receiver: bytes(""),
+ amount: 1e5,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+
+ assertEq(s_token.balanceOf(address(s_lockReleaseTokenPoolWithAllowList)), before);
+ }
+}
+
+contract LockReleaseTokenPool_releaseOrMint is LockReleaseTokenPoolSetup {
+ function setUp() public virtual override {
+ LockReleaseTokenPoolSetup.setUp();
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(s_sourcePoolAddress),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+
+ s_lockReleaseTokenPool.applyChainUpdates(chainUpdate);
+ s_lockReleaseTokenPoolWithAllowList.applyChainUpdates(chainUpdate);
+ }
+
+ function test_ReleaseOrMint_Success() public {
+ vm.startPrank(s_allowedOffRamp);
+
+ uint256 amount = 100;
+ deal(address(s_token), address(s_lockReleaseTokenPool), amount);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(amount);
+ vm.expectEmit();
+ emit TokenPool.Released(s_allowedOffRamp, OWNER, amount);
+
+ s_lockReleaseTokenPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: OWNER,
+ amount: amount,
+ localToken: address(s_token),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: abi.encode(s_sourcePoolAddress),
+ sourcePoolData: "",
+ offchainTokenData: ""
+ })
+ );
+ }
+
+ function test_Fuzz_ReleaseOrMint_Success(address recipient, uint256 amount) public {
+ // Since the owner already has tokens this would break the checks
+ vm.assume(recipient != OWNER);
+ vm.assume(recipient != address(0));
+ vm.assume(recipient != address(s_token));
+
+ // Makes sure the pool always has enough funds
+ deal(address(s_token), address(s_lockReleaseTokenPool), amount);
+ vm.startPrank(s_allowedOffRamp);
+
+ uint256 capacity = getInboundRateLimiterConfig().capacity;
+ // Determine if we hit the rate limit or the txs should succeed.
+ if (amount > capacity) {
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.TokenMaxCapacityExceeded.selector, capacity, amount, address(s_token))
+ );
+ } else {
+ // Only rate limit if the amount is >0
+ if (amount > 0) {
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(amount);
+ }
+
+ vm.expectEmit();
+ emit TokenPool.Released(s_allowedOffRamp, recipient, amount);
+ }
+
+ s_lockReleaseTokenPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: recipient,
+ amount: amount,
+ localToken: address(s_token),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: abi.encode(s_sourcePoolAddress),
+ sourcePoolData: "",
+ offchainTokenData: ""
+ })
+ );
+ }
+
+ function test_ChainNotAllowed_Revert() public {
+ address notAllowedRemotePoolAddress = address(1);
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(notAllowedRemotePoolAddress),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: false,
+ outboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0}),
+ inboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0})
+ });
+
+ s_lockReleaseTokenPool.applyChainUpdates(chainUpdate);
+
+ vm.startPrank(s_allowedOffRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, SOURCE_CHAIN_SELECTOR));
+ s_lockReleaseTokenPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: OWNER,
+ amount: 1e5,
+ localToken: address(s_token),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: abi.encode(s_sourcePoolAddress),
+ sourcePoolData: "",
+ offchainTokenData: ""
+ })
+ );
+ }
+
+ function test_PoolMintNotHealthy_Revert() public {
+ // Should not mint tokens if cursed.
+ s_mockRMN.setGlobalCursed(true);
+ uint256 before = s_token.balanceOf(OWNER);
+ vm.startPrank(s_allowedOffRamp);
+ vm.expectRevert(TokenPool.CursedByRMN.selector);
+ s_lockReleaseTokenPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: bytes(""),
+ receiver: OWNER,
+ amount: 1e5,
+ localToken: address(s_token),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: generateSourceTokenData().sourcePoolAddress,
+ sourcePoolData: generateSourceTokenData().extraData,
+ offchainTokenData: ""
+ })
+ );
+
+ assertEq(s_token.balanceOf(OWNER), before);
+ }
+}
+
+contract LockReleaseTokenPool_canAcceptLiquidity is LockReleaseTokenPoolSetup {
+ function test_CanAcceptLiquidity_Success() public {
+ assertEq(true, s_lockReleaseTokenPool.canAcceptLiquidity());
+
+ s_lockReleaseTokenPool =
+ new LockReleaseTokenPool(s_token, new address[](0), address(s_mockRMN), false, address(s_sourceRouter));
+ assertEq(false, s_lockReleaseTokenPool.canAcceptLiquidity());
+ }
+}
+
+contract LockReleaseTokenPool_provideLiquidity is LockReleaseTokenPoolSetup {
+ function test_Fuzz_ProvideLiquidity_Success(uint256 amount) public {
+ uint256 balancePre = s_token.balanceOf(OWNER);
+ s_token.approve(address(s_lockReleaseTokenPool), amount);
+
+ s_lockReleaseTokenPool.provideLiquidity(amount);
+
+ assertEq(s_token.balanceOf(OWNER), balancePre - amount);
+ assertEq(s_token.balanceOf(address(s_lockReleaseTokenPool)), amount);
+ }
+
+ // Reverts
+
+ function test_Unauthorized_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(abi.encodeWithSelector(LockReleaseTokenPool.Unauthorized.selector, STRANGER));
+
+ s_lockReleaseTokenPool.provideLiquidity(1);
+ }
+
+ function test_Fuzz_ExceedsAllowance(uint256 amount) public {
+ vm.assume(amount > 0);
+ vm.expectRevert("ERC20: insufficient allowance");
+ s_lockReleaseTokenPool.provideLiquidity(amount);
+ }
+
+ function test_LiquidityNotAccepted_Revert() public {
+ s_lockReleaseTokenPool =
+ new LockReleaseTokenPool(s_token, new address[](0), address(s_mockRMN), false, address(s_sourceRouter));
+
+ vm.expectRevert(LockReleaseTokenPool.LiquidityNotAccepted.selector);
+ s_lockReleaseTokenPool.provideLiquidity(1);
+ }
+}
+
+contract LockReleaseTokenPool_withdrawalLiquidity is LockReleaseTokenPoolSetup {
+ function test_Fuzz_WithdrawalLiquidity_Success(uint256 amount) public {
+ uint256 balancePre = s_token.balanceOf(OWNER);
+ s_token.approve(address(s_lockReleaseTokenPool), amount);
+ s_lockReleaseTokenPool.provideLiquidity(amount);
+
+ s_lockReleaseTokenPool.withdrawLiquidity(amount);
+
+ assertEq(s_token.balanceOf(OWNER), balancePre);
+ }
+
+ // Reverts
+
+ function test_Unauthorized_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(abi.encodeWithSelector(LockReleaseTokenPool.Unauthorized.selector, STRANGER));
+
+ s_lockReleaseTokenPool.withdrawLiquidity(1);
+ }
+
+ function test_InsufficientLiquidity_Revert() public {
+ uint256 maxUint256 = 2 ** 256 - 1;
+ s_token.approve(address(s_lockReleaseTokenPool), maxUint256);
+ s_lockReleaseTokenPool.provideLiquidity(maxUint256);
+
+ vm.startPrank(address(s_lockReleaseTokenPool));
+ s_token.transfer(OWNER, maxUint256);
+ vm.startPrank(OWNER);
+
+ vm.expectRevert(LockReleaseTokenPool.InsufficientLiquidity.selector);
+ s_lockReleaseTokenPool.withdrawLiquidity(1);
+ }
+}
+
+contract LockReleaseTokenPool_supportsInterface is LockReleaseTokenPoolSetup {
+ function test_SupportsInterface_Success() public view {
+ assertTrue(s_lockReleaseTokenPool.supportsInterface(type(IPoolV1).interfaceId));
+ assertTrue(s_lockReleaseTokenPool.supportsInterface(type(IERC165).interfaceId));
+ }
+}
+
+contract LockReleaseTokenPool_setChainRateLimiterConfig is LockReleaseTokenPoolSetup {
+ uint64 internal s_remoteChainSelector;
+
+ function setUp() public virtual override {
+ LockReleaseTokenPoolSetup.setUp();
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ s_remoteChainSelector = 123124;
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: s_remoteChainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_lockReleaseTokenPool.applyChainUpdates(chainUpdates);
+ }
+
+ function test_Fuzz_SetChainRateLimiterConfig_Success(uint128 capacity, uint128 rate, uint32 newTime) public {
+ // Cap the lower bound to 4 so 4/2 is still >= 2
+ vm.assume(capacity >= 4);
+ // Cap the lower bound to 2 so 2/2 is still >= 1
+ rate = uint128(bound(rate, 2, capacity - 2));
+ // Bucket updates only work on increasing time
+ newTime = uint32(bound(newTime, block.timestamp + 1, type(uint32).max));
+ vm.warp(newTime);
+
+ uint256 oldOutboundTokens = s_lockReleaseTokenPool.getCurrentOutboundRateLimiterState(s_remoteChainSelector).tokens;
+ uint256 oldInboundTokens = s_lockReleaseTokenPool.getCurrentInboundRateLimiterState(s_remoteChainSelector).tokens;
+
+ RateLimiter.Config memory newOutboundConfig = RateLimiter.Config({isEnabled: true, capacity: capacity, rate: rate});
+ RateLimiter.Config memory newInboundConfig =
+ RateLimiter.Config({isEnabled: true, capacity: capacity / 2, rate: rate / 2});
+
+ vm.expectEmit();
+ emit RateLimiter.ConfigChanged(newOutboundConfig);
+ vm.expectEmit();
+ emit RateLimiter.ConfigChanged(newInboundConfig);
+ vm.expectEmit();
+ emit TokenPool.ChainConfigured(s_remoteChainSelector, newOutboundConfig, newInboundConfig);
+
+ s_lockReleaseTokenPool.setChainRateLimiterConfig(s_remoteChainSelector, newOutboundConfig, newInboundConfig);
+
+ uint256 expectedTokens = RateLimiter._min(newOutboundConfig.capacity, oldOutboundTokens);
+
+ RateLimiter.TokenBucket memory bucket =
+ s_lockReleaseTokenPool.getCurrentOutboundRateLimiterState(s_remoteChainSelector);
+ assertEq(bucket.capacity, newOutboundConfig.capacity);
+ assertEq(bucket.rate, newOutboundConfig.rate);
+ assertEq(bucket.tokens, expectedTokens);
+ assertEq(bucket.lastUpdated, newTime);
+
+ expectedTokens = RateLimiter._min(newInboundConfig.capacity, oldInboundTokens);
+
+ bucket = s_lockReleaseTokenPool.getCurrentInboundRateLimiterState(s_remoteChainSelector);
+ assertEq(bucket.capacity, newInboundConfig.capacity);
+ assertEq(bucket.rate, newInboundConfig.rate);
+ assertEq(bucket.tokens, expectedTokens);
+ assertEq(bucket.lastUpdated, newTime);
+ }
+
+ function test_OnlyOwnerOrRateLimitAdmin_Revert() public {
+ address rateLimiterAdmin = address(28973509103597907);
+
+ s_lockReleaseTokenPool.setRateLimitAdmin(rateLimiterAdmin);
+
+ vm.startPrank(rateLimiterAdmin);
+
+ s_lockReleaseTokenPool.setChainRateLimiterConfig(
+ s_remoteChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+
+ vm.startPrank(OWNER);
+
+ s_lockReleaseTokenPool.setChainRateLimiterConfig(
+ s_remoteChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+ }
+
+ // Reverts
+
+ function test_OnlyOwner_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(abi.encodeWithSelector(LockReleaseTokenPool.Unauthorized.selector, STRANGER));
+ s_lockReleaseTokenPool.setChainRateLimiterConfig(
+ s_remoteChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+ }
+
+ function test_NonExistentChain_Revert() public {
+ uint64 wrongChainSelector = 9084102894;
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.NonExistentChain.selector, wrongChainSelector));
+ s_lockReleaseTokenPool.setChainRateLimiterConfig(
+ wrongChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+ }
+}
+
+contract LockReleaseTokenPool_setRateLimitAdmin is LockReleaseTokenPoolSetup {
+ function test_SetRateLimitAdmin_Success() public {
+ assertEq(address(0), s_lockReleaseTokenPool.getRateLimitAdmin());
+ s_lockReleaseTokenPool.setRateLimitAdmin(OWNER);
+ assertEq(OWNER, s_lockReleaseTokenPool.getRateLimitAdmin());
+ }
+
+ // Reverts
+
+ function test_SetRateLimitAdmin_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert("Only callable by owner");
+ s_lockReleaseTokenPool.setRateLimitAdmin(STRANGER);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/pools/TokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/TokenPool.t.sol
new file mode 100644
index 00000000000..e5eb04b7413
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/pools/TokenPool.t.sol
@@ -0,0 +1,767 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {Router} from "../../Router.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+import {TokenPoolHelper} from "../helpers/TokenPoolHelper.sol";
+import {RouterSetup} from "../router/RouterSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract TokenPoolSetup is RouterSetup {
+ IERC20 internal s_token;
+ TokenPoolHelper internal s_tokenPool;
+
+ function setUp() public virtual override {
+ RouterSetup.setUp();
+ s_token = new BurnMintERC677("LINK", "LNK", 18, 0);
+ deal(address(s_token), OWNER, type(uint256).max);
+
+ s_tokenPool = new TokenPoolHelper(s_token, new address[](0), address(s_mockRMN), address(s_sourceRouter));
+ }
+}
+
+contract TokenPool_constructor is TokenPoolSetup {
+ function test_immutableFields_Success() public view {
+ assertEq(address(s_token), address(s_tokenPool.getToken()));
+ assertEq(address(s_mockRMN), s_tokenPool.getRmnProxy());
+ assertEq(false, s_tokenPool.getAllowListEnabled());
+ assertEq(address(s_sourceRouter), s_tokenPool.getRouter());
+ }
+
+ // Reverts
+ function test_ZeroAddressNotAllowed_Revert() public {
+ vm.expectRevert(TokenPool.ZeroAddressNotAllowed.selector);
+
+ s_tokenPool = new TokenPoolHelper(IERC20(address(0)), new address[](0), address(s_mockRMN), address(s_sourceRouter));
+ }
+}
+
+contract TokenPool_getRemotePool is TokenPoolSetup {
+ function test_getRemotePool_Success() public {
+ uint64 chainSelector = 123124;
+ address remotePool = makeAddr("remotePool");
+ address remoteToken = makeAddr("remoteToken");
+
+ // Zero indicates nothing is set
+ assertEq(0, s_tokenPool.getRemotePool(chainSelector).length);
+
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(remotePool),
+ remoteTokenAddress: abi.encode(remoteToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ assertEq(remotePool, abi.decode(s_tokenPool.getRemotePool(chainSelector), (address)));
+ }
+}
+
+contract TokenPool_setRemotePool is TokenPoolSetup {
+ function test_setRemotePool_Success() public {
+ uint64 chainSelector = DEST_CHAIN_SELECTOR;
+ address initialPool = makeAddr("remotePool");
+ address remoteToken = makeAddr("remoteToken");
+ // The new pool is a non-evm pool, as it doesn't fit in the normal 160 bits
+ bytes memory newPool = abi.encode(type(uint256).max);
+
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(initialPool),
+ remoteTokenAddress: abi.encode(remoteToken),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ vm.expectEmit();
+ emit TokenPool.RemotePoolSet(chainSelector, abi.encode(initialPool), newPool);
+
+ s_tokenPool.setRemotePool(chainSelector, newPool);
+
+ assertEq(keccak256(newPool), keccak256(s_tokenPool.getRemotePool(chainSelector)));
+ }
+
+ // Reverts
+
+ function test_setRemotePool_NonExistentChain_Reverts() public {
+ uint64 chainSelector = 123124;
+ bytes memory remotePool = abi.encode(makeAddr("remotePool"));
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.NonExistentChain.selector, chainSelector));
+ s_tokenPool.setRemotePool(chainSelector, remotePool);
+ }
+
+ function test_setRemotePool_OnlyOwner_Reverts() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert("Only callable by owner");
+ s_tokenPool.setRemotePool(123124, abi.encode(makeAddr("remotePool")));
+ }
+}
+
+contract TokenPool_applyChainUpdates is TokenPoolSetup {
+ function assertState(TokenPool.ChainUpdate[] memory chainUpdates) public view {
+ uint64[] memory chainSelectors = s_tokenPool.getSupportedChains();
+ for (uint256 i = 0; i < chainUpdates.length; i++) {
+ assertEq(chainUpdates[i].remoteChainSelector, chainSelectors[i]);
+ }
+
+ for (uint256 i = 0; i < chainUpdates.length; ++i) {
+ assertTrue(s_tokenPool.isSupportedChain(chainUpdates[i].remoteChainSelector));
+ RateLimiter.TokenBucket memory bkt =
+ s_tokenPool.getCurrentOutboundRateLimiterState(chainUpdates[i].remoteChainSelector);
+ assertEq(bkt.capacity, chainUpdates[i].outboundRateLimiterConfig.capacity);
+ assertEq(bkt.rate, chainUpdates[i].outboundRateLimiterConfig.rate);
+ assertEq(bkt.isEnabled, chainUpdates[i].outboundRateLimiterConfig.isEnabled);
+
+ bkt = s_tokenPool.getCurrentInboundRateLimiterState(chainUpdates[i].remoteChainSelector);
+ assertEq(bkt.capacity, chainUpdates[i].inboundRateLimiterConfig.capacity);
+ assertEq(bkt.rate, chainUpdates[i].inboundRateLimiterConfig.rate);
+ assertEq(bkt.isEnabled, chainUpdates[i].inboundRateLimiterConfig.isEnabled);
+ }
+ }
+
+ function test_applyChainUpdates_Success() public {
+ RateLimiter.Config memory outboundRateLimit1 = RateLimiter.Config({isEnabled: true, capacity: 100e28, rate: 1e18});
+ RateLimiter.Config memory inboundRateLimit1 = RateLimiter.Config({isEnabled: true, capacity: 100e29, rate: 1e19});
+ RateLimiter.Config memory outboundRateLimit2 = RateLimiter.Config({isEnabled: true, capacity: 100e26, rate: 1e16});
+ RateLimiter.Config memory inboundRateLimit2 = RateLimiter.Config({isEnabled: true, capacity: 100e27, rate: 1e17});
+
+ // EVM chain, which uses the 160 bit evm address space
+ uint64 evmChainSelector = 1;
+ bytes memory evmRemotePool = abi.encode(makeAddr("evm_remote_pool"));
+ bytes memory evmRemoteToken = abi.encode(makeAddr("evm_remote_token"));
+
+ // Non EVM chain, which uses the full 256 bits
+ uint64 nonEvmChainSelector = type(uint64).max;
+ bytes memory nonEvmRemotePool = abi.encode(keccak256("non_evm_remote_pool"));
+ bytes memory nonEvmRemoteToken = abi.encode(keccak256("non_evm_remote_token"));
+
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](2);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: evmChainSelector,
+ remotePoolAddress: evmRemotePool,
+ remoteTokenAddress: evmRemoteToken,
+ allowed: true,
+ outboundRateLimiterConfig: outboundRateLimit1,
+ inboundRateLimiterConfig: inboundRateLimit1
+ });
+ chainUpdates[1] = TokenPool.ChainUpdate({
+ remoteChainSelector: nonEvmChainSelector,
+ remotePoolAddress: nonEvmRemotePool,
+ remoteTokenAddress: nonEvmRemoteToken,
+ allowed: true,
+ outboundRateLimiterConfig: outboundRateLimit2,
+ inboundRateLimiterConfig: inboundRateLimit2
+ });
+
+ // Assert configuration is applied
+ vm.expectEmit();
+ emit TokenPool.ChainAdded(
+ chainUpdates[0].remoteChainSelector,
+ chainUpdates[0].remoteTokenAddress,
+ chainUpdates[0].outboundRateLimiterConfig,
+ chainUpdates[0].inboundRateLimiterConfig
+ );
+ vm.expectEmit();
+ emit TokenPool.ChainAdded(
+ chainUpdates[1].remoteChainSelector,
+ chainUpdates[1].remoteTokenAddress,
+ chainUpdates[1].outboundRateLimiterConfig,
+ chainUpdates[1].inboundRateLimiterConfig
+ );
+ s_tokenPool.applyChainUpdates(chainUpdates);
+ // on1: rateLimit1, on2: rateLimit2, off1: rateLimit1, off2: rateLimit3
+ assertState(chainUpdates);
+
+ // Removing an non-existent chain should revert
+ TokenPool.ChainUpdate[] memory chainRemoves = new TokenPool.ChainUpdate[](1);
+ uint64 strangerChainSelector = 120938;
+ chainRemoves[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: strangerChainSelector,
+ remotePoolAddress: evmRemotePool,
+ remoteTokenAddress: evmRemoteToken,
+ allowed: false,
+ outboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0}),
+ inboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0})
+ });
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.NonExistentChain.selector, strangerChainSelector));
+ s_tokenPool.applyChainUpdates(chainRemoves);
+ // State remains
+ assertState(chainUpdates);
+
+ // Can remove a chain
+ chainRemoves[0].remoteChainSelector = evmChainSelector;
+
+ vm.expectEmit();
+ emit TokenPool.ChainRemoved(chainRemoves[0].remoteChainSelector);
+
+ s_tokenPool.applyChainUpdates(chainRemoves);
+
+ // State updated, only chain 2 remains
+ TokenPool.ChainUpdate[] memory singleChainConfigured = new TokenPool.ChainUpdate[](1);
+ singleChainConfigured[0] = chainUpdates[1];
+ assertState(singleChainConfigured);
+
+ // Cannot reset already configured ramp
+ vm.expectRevert(
+ abi.encodeWithSelector(TokenPool.ChainAlreadyExists.selector, singleChainConfigured[0].remoteChainSelector)
+ );
+ s_tokenPool.applyChainUpdates(singleChainConfigured);
+ }
+
+ // Reverts
+
+ function test_applyChainUpdates_OnlyCallableByOwner_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+ s_tokenPool.applyChainUpdates(new TokenPool.ChainUpdate[](0));
+ }
+
+ function test_applyChainUpdates_ZeroAddressNotAllowed_Revert() public {
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: 1,
+ remotePoolAddress: "",
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: RateLimiter.Config({isEnabled: true, capacity: 100e28, rate: 1e18}),
+ inboundRateLimiterConfig: RateLimiter.Config({isEnabled: true, capacity: 100e28, rate: 1e18})
+ });
+
+ vm.expectRevert(TokenPool.ZeroAddressNotAllowed.selector);
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: 1,
+ remotePoolAddress: abi.encode(address(2)),
+ remoteTokenAddress: "",
+ allowed: true,
+ outboundRateLimiterConfig: RateLimiter.Config({isEnabled: true, capacity: 100e28, rate: 1e18}),
+ inboundRateLimiterConfig: RateLimiter.Config({isEnabled: true, capacity: 100e28, rate: 1e18})
+ });
+
+ vm.expectRevert(TokenPool.ZeroAddressNotAllowed.selector);
+ s_tokenPool.applyChainUpdates(chainUpdates);
+ }
+
+ function test_applyChainUpdates_DisabledNonZeroRateLimit_Revert() public {
+ RateLimiter.Config memory outboundRateLimit = RateLimiter.Config({isEnabled: true, capacity: 100e28, rate: 1e18});
+ RateLimiter.Config memory inboundRateLimit = RateLimiter.Config({isEnabled: true, capacity: 100e22, rate: 1e12});
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: 1,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: outboundRateLimit,
+ inboundRateLimiterConfig: inboundRateLimit
+ });
+
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ chainUpdates[0].allowed = false;
+ chainUpdates[0].outboundRateLimiterConfig = RateLimiter.Config({isEnabled: false, capacity: 10, rate: 1});
+ chainUpdates[0].inboundRateLimiterConfig = RateLimiter.Config({isEnabled: false, capacity: 10, rate: 1});
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.DisabledNonZeroRateLimit.selector, chainUpdates[0].outboundRateLimiterConfig)
+ );
+ s_tokenPool.applyChainUpdates(chainUpdates);
+ }
+
+ function test_applyChainUpdates_NonExistentChain_Revert() public {
+ RateLimiter.Config memory outboundRateLimit = RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0});
+ RateLimiter.Config memory inboundRateLimit = RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0});
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: 1,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: false,
+ outboundRateLimiterConfig: outboundRateLimit,
+ inboundRateLimiterConfig: inboundRateLimit
+ });
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.NonExistentChain.selector, chainUpdates[0].remoteChainSelector));
+ s_tokenPool.applyChainUpdates(chainUpdates);
+ }
+
+ function test_applyChainUpdates_InvalidRateLimitRate_Revert() public {
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: 1,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: RateLimiter.Config({isEnabled: true, capacity: 0, rate: 0}),
+ inboundRateLimiterConfig: RateLimiter.Config({isEnabled: true, capacity: 100e22, rate: 1e12})
+ });
+
+ // Outbound
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.InvalidRateLimitRate.selector, chainUpdates[0].outboundRateLimiterConfig)
+ );
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ chainUpdates[0].outboundRateLimiterConfig.rate = 100;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.InvalidRateLimitRate.selector, chainUpdates[0].outboundRateLimiterConfig)
+ );
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ chainUpdates[0].outboundRateLimiterConfig.capacity = 100;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.InvalidRateLimitRate.selector, chainUpdates[0].outboundRateLimiterConfig)
+ );
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ chainUpdates[0].outboundRateLimiterConfig.capacity = 101;
+
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ // Change the chain selector as adding the same one would revert
+ chainUpdates[0].remoteChainSelector = 2;
+
+ // Inbound
+
+ chainUpdates[0].inboundRateLimiterConfig.capacity = 0;
+ chainUpdates[0].inboundRateLimiterConfig.rate = 0;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.InvalidRateLimitRate.selector, chainUpdates[0].inboundRateLimiterConfig)
+ );
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ chainUpdates[0].inboundRateLimiterConfig.rate = 100;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.InvalidRateLimitRate.selector, chainUpdates[0].inboundRateLimiterConfig)
+ );
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ chainUpdates[0].inboundRateLimiterConfig.capacity = 100;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.InvalidRateLimitRate.selector, chainUpdates[0].inboundRateLimiterConfig)
+ );
+ s_tokenPool.applyChainUpdates(chainUpdates);
+
+ chainUpdates[0].inboundRateLimiterConfig.capacity = 101;
+
+ s_tokenPool.applyChainUpdates(chainUpdates);
+ }
+}
+
+contract TokenPool_setChainRateLimiterConfig is TokenPoolSetup {
+ uint64 internal s_remoteChainSelector;
+
+ function setUp() public virtual override {
+ TokenPoolSetup.setUp();
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ s_remoteChainSelector = 123124;
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: s_remoteChainSelector,
+ remotePoolAddress: abi.encode(address(2)),
+ remoteTokenAddress: abi.encode(address(3)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdates);
+ }
+
+ function test_Fuzz_SetChainRateLimiterConfig_Success(uint128 capacity, uint128 rate, uint32 newTime) public {
+ // Cap the lower bound to 4 so 4/2 is still >= 2
+ vm.assume(capacity >= 4);
+ // Cap the lower bound to 2 so 2/2 is still >= 1
+ rate = uint128(bound(rate, 2, capacity - 2));
+ // Bucket updates only work on increasing time
+ newTime = uint32(bound(newTime, block.timestamp + 1, type(uint32).max));
+ vm.warp(newTime);
+
+ uint256 oldOutboundTokens = s_tokenPool.getCurrentOutboundRateLimiterState(s_remoteChainSelector).tokens;
+ uint256 oldInboundTokens = s_tokenPool.getCurrentInboundRateLimiterState(s_remoteChainSelector).tokens;
+
+ RateLimiter.Config memory newOutboundConfig = RateLimiter.Config({isEnabled: true, capacity: capacity, rate: rate});
+ RateLimiter.Config memory newInboundConfig =
+ RateLimiter.Config({isEnabled: true, capacity: capacity / 2, rate: rate / 2});
+
+ vm.expectEmit();
+ emit RateLimiter.ConfigChanged(newOutboundConfig);
+ vm.expectEmit();
+ emit RateLimiter.ConfigChanged(newInboundConfig);
+ vm.expectEmit();
+ emit TokenPool.ChainConfigured(s_remoteChainSelector, newOutboundConfig, newInboundConfig);
+
+ s_tokenPool.setChainRateLimiterConfig(s_remoteChainSelector, newOutboundConfig, newInboundConfig);
+
+ uint256 expectedTokens = RateLimiter._min(newOutboundConfig.capacity, oldOutboundTokens);
+
+ RateLimiter.TokenBucket memory bucket = s_tokenPool.getCurrentOutboundRateLimiterState(s_remoteChainSelector);
+ assertEq(bucket.capacity, newOutboundConfig.capacity);
+ assertEq(bucket.rate, newOutboundConfig.rate);
+ assertEq(bucket.tokens, expectedTokens);
+ assertEq(bucket.lastUpdated, newTime);
+
+ expectedTokens = RateLimiter._min(newInboundConfig.capacity, oldInboundTokens);
+
+ bucket = s_tokenPool.getCurrentInboundRateLimiterState(s_remoteChainSelector);
+ assertEq(bucket.capacity, newInboundConfig.capacity);
+ assertEq(bucket.rate, newInboundConfig.rate);
+ assertEq(bucket.tokens, expectedTokens);
+ assertEq(bucket.lastUpdated, newTime);
+ }
+
+ // Reverts
+
+ function test_OnlyOwner_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert("Only callable by owner");
+ s_tokenPool.setChainRateLimiterConfig(
+ s_remoteChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+ }
+
+ function test_NonExistentChain_Revert() public {
+ uint64 wrongChainSelector = 9084102894;
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.NonExistentChain.selector, wrongChainSelector));
+ s_tokenPool.setChainRateLimiterConfig(
+ wrongChainSelector, getOutboundRateLimiterConfig(), getInboundRateLimiterConfig()
+ );
+ }
+}
+
+contract TokenPool_onlyOnRamp is TokenPoolSetup {
+ function test_onlyOnRamp_Success() public {
+ uint64 chainSelector = 13377;
+ address onRamp = makeAddr("onRamp");
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdate);
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: chainSelector, onRamp: onRamp});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), new Router.OffRamp[](0));
+
+ vm.startPrank(onRamp);
+
+ s_tokenPool.onlyOnRampModifier(chainSelector);
+ }
+
+ function test_ChainNotAllowed_Revert() public {
+ uint64 chainSelector = 13377;
+ address onRamp = makeAddr("onRamp");
+
+ vm.startPrank(onRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, chainSelector));
+ s_tokenPool.onlyOnRampModifier(chainSelector);
+
+ vm.startPrank(OWNER);
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdate);
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: chainSelector, onRamp: onRamp});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), new Router.OffRamp[](0));
+
+ vm.startPrank(onRamp);
+ // Should succeed now that we've added the chain
+ s_tokenPool.onlyOnRampModifier(chainSelector);
+
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: false,
+ outboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0}),
+ inboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0})
+ });
+
+ vm.startPrank(OWNER);
+ s_tokenPool.applyChainUpdates(chainUpdate);
+
+ vm.startPrank(onRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, chainSelector));
+ s_tokenPool.onlyOffRampModifier(chainSelector);
+ }
+
+ function test_CallerIsNotARampOnRouter_Revert() public {
+ uint64 chainSelector = 13377;
+ address onRamp = makeAddr("onRamp");
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdate);
+
+ vm.startPrank(onRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.CallerIsNotARampOnRouter.selector, onRamp));
+
+ s_tokenPool.onlyOnRampModifier(chainSelector);
+ }
+}
+
+contract TokenPool_onlyOffRamp is TokenPoolSetup {
+ function test_onlyOffRamp_Success() public {
+ uint64 chainSelector = 13377;
+ address offRamp = makeAddr("onRamp");
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdate);
+
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1);
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: chainSelector, offRamp: offRamp});
+ s_sourceRouter.applyRampUpdates(new Router.OnRamp[](0), new Router.OffRamp[](0), offRampUpdates);
+
+ vm.startPrank(offRamp);
+
+ s_tokenPool.onlyOffRampModifier(chainSelector);
+ }
+
+ function test_ChainNotAllowed_Revert() public {
+ uint64 chainSelector = 13377;
+ address offRamp = makeAddr("onRamp");
+
+ vm.startPrank(offRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, chainSelector));
+ s_tokenPool.onlyOffRampModifier(chainSelector);
+
+ vm.startPrank(OWNER);
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdate);
+
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1);
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: chainSelector, offRamp: offRamp});
+ s_sourceRouter.applyRampUpdates(new Router.OnRamp[](0), new Router.OffRamp[](0), offRampUpdates);
+
+ vm.startPrank(offRamp);
+ // Should succeed now that we've added the chain
+ s_tokenPool.onlyOffRampModifier(chainSelector);
+
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: false,
+ outboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0}),
+ inboundRateLimiterConfig: RateLimiter.Config({isEnabled: false, capacity: 0, rate: 0})
+ });
+
+ vm.startPrank(OWNER);
+ s_tokenPool.applyChainUpdates(chainUpdate);
+
+ vm.startPrank(offRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.ChainNotAllowed.selector, chainSelector));
+ s_tokenPool.onlyOffRampModifier(chainSelector);
+ }
+
+ function test_CallerIsNotARampOnRouter_Revert() public {
+ uint64 chainSelector = 13377;
+ address offRamp = makeAddr("offRamp");
+
+ TokenPool.ChainUpdate[] memory chainUpdate = new TokenPool.ChainUpdate[](1);
+ chainUpdate[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: chainSelector,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ s_tokenPool.applyChainUpdates(chainUpdate);
+
+ vm.startPrank(offRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.CallerIsNotARampOnRouter.selector, offRamp));
+
+ s_tokenPool.onlyOffRampModifier(chainSelector);
+ }
+}
+
+contract TokenPoolWithAllowListSetup is TokenPoolSetup {
+ address[] internal s_allowedSenders;
+
+ function setUp() public virtual override {
+ TokenPoolSetup.setUp();
+
+ s_allowedSenders.push(STRANGER);
+ s_allowedSenders.push(DUMMY_CONTRACT_ADDRESS);
+
+ s_tokenPool = new TokenPoolHelper(s_token, s_allowedSenders, address(s_mockRMN), address(s_sourceRouter));
+ }
+}
+
+contract TokenPoolWithAllowList_getAllowListEnabled is TokenPoolWithAllowListSetup {
+ function test_GetAllowListEnabled_Success() public view {
+ assertTrue(s_tokenPool.getAllowListEnabled());
+ }
+}
+
+contract TokenPoolWithAllowList_setRouter is TokenPoolWithAllowListSetup {
+ function test_SetRouter_Success() public {
+ assertEq(address(s_sourceRouter), s_tokenPool.getRouter());
+
+ address newRouter = makeAddr("newRouter");
+
+ vm.expectEmit();
+ emit TokenPool.RouterUpdated(address(s_sourceRouter), newRouter);
+
+ s_tokenPool.setRouter(newRouter);
+
+ assertEq(newRouter, s_tokenPool.getRouter());
+ }
+}
+
+contract TokenPoolWithAllowList_getAllowList is TokenPoolWithAllowListSetup {
+ function test_GetAllowList_Success() public view {
+ address[] memory setAddresses = s_tokenPool.getAllowList();
+ assertEq(2, setAddresses.length);
+ assertEq(s_allowedSenders[0], setAddresses[0]);
+ assertEq(s_allowedSenders[1], setAddresses[1]);
+ }
+}
+
+contract TokenPoolWithAllowList_applyAllowListUpdates is TokenPoolWithAllowListSetup {
+ function test_SetAllowList_Success() public {
+ address[] memory newAddresses = new address[](2);
+ newAddresses[0] = address(1);
+ newAddresses[1] = address(2);
+
+ for (uint256 i = 0; i < 2; ++i) {
+ vm.expectEmit();
+ emit TokenPool.AllowListAdd(newAddresses[i]);
+ }
+
+ s_tokenPool.applyAllowListUpdates(new address[](0), newAddresses);
+ address[] memory setAddresses = s_tokenPool.getAllowList();
+
+ assertEq(s_allowedSenders[0], setAddresses[0]);
+ assertEq(s_allowedSenders[1], setAddresses[1]);
+ assertEq(address(1), setAddresses[2]);
+ assertEq(address(2), setAddresses[3]);
+
+ // address(2) exists noop, add address(3), remove address(1)
+ newAddresses = new address[](2);
+ newAddresses[0] = address(2);
+ newAddresses[1] = address(3);
+
+ address[] memory removeAddresses = new address[](1);
+ removeAddresses[0] = address(1);
+
+ vm.expectEmit();
+ emit TokenPool.AllowListRemove(address(1));
+
+ vm.expectEmit();
+ emit TokenPool.AllowListAdd(address(3));
+
+ s_tokenPool.applyAllowListUpdates(removeAddresses, newAddresses);
+ setAddresses = s_tokenPool.getAllowList();
+
+ assertEq(s_allowedSenders[0], setAddresses[0]);
+ assertEq(s_allowedSenders[1], setAddresses[1]);
+ assertEq(address(2), setAddresses[2]);
+ assertEq(address(3), setAddresses[3]);
+
+ // remove all from allowList
+ for (uint256 i = 0; i < setAddresses.length; ++i) {
+ vm.expectEmit();
+ emit TokenPool.AllowListRemove(setAddresses[i]);
+ }
+
+ s_tokenPool.applyAllowListUpdates(setAddresses, new address[](0));
+ setAddresses = s_tokenPool.getAllowList();
+
+ assertEq(0, setAddresses.length);
+ }
+
+ function test_SetAllowListSkipsZero_Success() public {
+ uint256 setAddressesLength = s_tokenPool.getAllowList().length;
+
+ address[] memory newAddresses = new address[](1);
+ newAddresses[0] = address(0);
+
+ s_tokenPool.applyAllowListUpdates(new address[](0), newAddresses);
+ address[] memory setAddresses = s_tokenPool.getAllowList();
+
+ assertEq(setAddresses.length, setAddressesLength);
+ }
+
+ // Reverts
+
+ function test_OnlyOwner_Revert() public {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ address[] memory newAddresses = new address[](2);
+ s_tokenPool.applyAllowListUpdates(new address[](0), newAddresses);
+ }
+
+ function test_AllowListNotEnabled_Revert() public {
+ s_tokenPool = new TokenPoolHelper(s_token, new address[](0), address(s_mockRMN), address(s_sourceRouter));
+
+ vm.expectRevert(TokenPool.AllowListNotEnabled.selector);
+
+ s_tokenPool.applyAllowListUpdates(new address[](0), new address[](2));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/pools/USDCTokenPool.t.sol b/contracts/src/v0.8/ccip/test/pools/USDCTokenPool.t.sol
new file mode 100644
index 00000000000..200ffb4f6d6
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/pools/USDCTokenPool.t.sol
@@ -0,0 +1,690 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBurnMintERC20} from "../../../shared/token/ERC20/IBurnMintERC20.sol";
+import {IPoolV1} from "../../interfaces/IPool.sol";
+import {ITokenMessenger} from "../../pools/USDC/ITokenMessenger.sol";
+
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {Router} from "../../Router.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {USDCTokenPool} from "../../pools/USDC/USDCTokenPool.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+import {USDCTokenPoolHelper} from "../helpers/USDCTokenPoolHelper.sol";
+import {MockE2EUSDCTransmitter} from "../mocks/MockE2EUSDCTransmitter.sol";
+import {MockUSDCTokenMessenger} from "../mocks/MockUSDCTokenMessenger.sol";
+
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
+
+contract USDCTokenPoolSetup is BaseTest {
+ IBurnMintERC20 internal s_token;
+ MockUSDCTokenMessenger internal s_mockUSDC;
+ MockE2EUSDCTransmitter internal s_mockUSDCTransmitter;
+
+ struct USDCMessage {
+ uint32 version;
+ uint32 sourceDomain;
+ uint32 destinationDomain;
+ uint64 nonce;
+ bytes32 sender;
+ bytes32 recipient;
+ bytes32 destinationCaller;
+ bytes messageBody;
+ }
+
+ uint32 internal constant SOURCE_DOMAIN_IDENTIFIER = 0x02020202;
+ uint32 internal constant DEST_DOMAIN_IDENTIFIER = 0;
+
+ bytes32 internal constant SOURCE_CHAIN_TOKEN_SENDER = bytes32(uint256(uint160(0x01111111221)));
+ address internal constant SOURCE_CHAIN_USDC_POOL = address(0x23789765456789);
+ address internal constant DEST_CHAIN_USDC_POOL = address(0x987384873458734);
+ address internal constant DEST_CHAIN_USDC_TOKEN = address(0x23598918358198766);
+
+ address internal s_routerAllowedOnRamp = address(3456);
+ address internal s_routerAllowedOffRamp = address(234);
+ Router internal s_router;
+
+ USDCTokenPoolHelper internal s_usdcTokenPool;
+ USDCTokenPoolHelper internal s_usdcTokenPoolWithAllowList;
+ address[] internal s_allowedList;
+
+ function setUp() public virtual override {
+ BaseTest.setUp();
+ BurnMintERC677 usdcToken = new BurnMintERC677("LINK", "LNK", 18, 0);
+ s_token = usdcToken;
+ deal(address(s_token), OWNER, type(uint256).max);
+ setUpRamps();
+
+ s_mockUSDCTransmitter = new MockE2EUSDCTransmitter(0, DEST_DOMAIN_IDENTIFIER, address(s_token));
+ s_mockUSDC = new MockUSDCTokenMessenger(0, address(s_mockUSDCTransmitter));
+
+ usdcToken.grantMintAndBurnRoles(address(s_mockUSDCTransmitter));
+
+ s_usdcTokenPool =
+ new USDCTokenPoolHelper(s_mockUSDC, s_token, new address[](0), address(s_mockRMN), address(s_router));
+ usdcToken.grantMintAndBurnRoles(address(s_mockUSDC));
+
+ s_allowedList.push(USER_1);
+ s_usdcTokenPoolWithAllowList =
+ new USDCTokenPoolHelper(s_mockUSDC, s_token, s_allowedList, address(s_mockRMN), address(s_router));
+
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](2);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(SOURCE_CHAIN_USDC_POOL),
+ remoteTokenAddress: abi.encode(address(s_token)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+ chainUpdates[1] = TokenPool.ChainUpdate({
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ remotePoolAddress: abi.encode(DEST_CHAIN_USDC_POOL),
+ remoteTokenAddress: abi.encode(DEST_CHAIN_USDC_TOKEN),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+
+ s_usdcTokenPool.applyChainUpdates(chainUpdates);
+ s_usdcTokenPoolWithAllowList.applyChainUpdates(chainUpdates);
+
+ USDCTokenPool.DomainUpdate[] memory domains = new USDCTokenPool.DomainUpdate[](1);
+ domains[0] = USDCTokenPool.DomainUpdate({
+ destChainSelector: DEST_CHAIN_SELECTOR,
+ domainIdentifier: 9999,
+ allowedCaller: keccak256("allowedCaller"),
+ enabled: true
+ });
+
+ s_usdcTokenPool.setDomains(domains);
+ s_usdcTokenPoolWithAllowList.setDomains(domains);
+ }
+
+ function setUpRamps() internal {
+ s_router = new Router(address(s_token), address(s_mockRMN));
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_routerAllowedOnRamp});
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1);
+ address[] memory offRamps = new address[](1);
+ offRamps[0] = s_routerAllowedOffRamp;
+ offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: offRamps[0]});
+
+ s_router.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+ }
+
+ function _generateUSDCMessage(USDCMessage memory usdcMessage) internal pure returns (bytes memory) {
+ return abi.encodePacked(
+ usdcMessage.version,
+ usdcMessage.sourceDomain,
+ usdcMessage.destinationDomain,
+ usdcMessage.nonce,
+ usdcMessage.sender,
+ usdcMessage.recipient,
+ usdcMessage.destinationCaller,
+ usdcMessage.messageBody
+ );
+ }
+}
+
+contract USDCTokenPool_lockOrBurn is USDCTokenPoolSetup {
+ // Base test case, included for PR gas comparisons as fuzz tests are excluded from forge snapshot due to being flaky.
+ function test_LockOrBurn_Success() public {
+ bytes32 receiver = bytes32(uint256(uint160(STRANGER)));
+ uint256 amount = 1;
+ s_token.transfer(address(s_usdcTokenPool), amount);
+ vm.startPrank(s_routerAllowedOnRamp);
+
+ USDCTokenPool.Domain memory expectedDomain = s_usdcTokenPool.getDomain(DEST_CHAIN_SELECTOR);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(amount);
+
+ vm.expectEmit();
+ emit ITokenMessenger.DepositForBurn(
+ s_mockUSDC.s_nonce(),
+ address(s_token),
+ amount,
+ address(s_usdcTokenPool),
+ expectedDomain.allowedCaller,
+ expectedDomain.domainIdentifier,
+ s_mockUSDC.DESTINATION_TOKEN_MESSENGER(),
+ expectedDomain.allowedCaller
+ );
+
+ vm.expectEmit();
+ emit TokenPool.Burned(s_routerAllowedOnRamp, amount);
+
+ Pool.LockOrBurnOutV1 memory poolReturnDataV1 = s_usdcTokenPool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: abi.encodePacked(receiver),
+ amount: amount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+
+ uint64 nonce = abi.decode(poolReturnDataV1.destPoolData, (uint64));
+ assertEq(s_mockUSDC.s_nonce() - 1, nonce);
+ }
+
+ function test_Fuzz_LockOrBurn_Success(bytes32 destinationReceiver, uint256 amount) public {
+ vm.assume(destinationReceiver != bytes32(0));
+ amount = bound(amount, 1, getOutboundRateLimiterConfig().capacity);
+ s_token.transfer(address(s_usdcTokenPool), amount);
+ vm.startPrank(s_routerAllowedOnRamp);
+
+ USDCTokenPool.Domain memory expectedDomain = s_usdcTokenPool.getDomain(DEST_CHAIN_SELECTOR);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(amount);
+
+ vm.expectEmit();
+ emit ITokenMessenger.DepositForBurn(
+ s_mockUSDC.s_nonce(),
+ address(s_token),
+ amount,
+ address(s_usdcTokenPool),
+ expectedDomain.allowedCaller,
+ expectedDomain.domainIdentifier,
+ s_mockUSDC.DESTINATION_TOKEN_MESSENGER(),
+ expectedDomain.allowedCaller
+ );
+
+ vm.expectEmit();
+ emit TokenPool.Burned(s_routerAllowedOnRamp, amount);
+
+ Pool.LockOrBurnOutV1 memory poolReturnDataV1 = s_usdcTokenPool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: abi.encodePacked(destinationReceiver),
+ amount: amount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+
+ uint64 nonce = abi.decode(poolReturnDataV1.destPoolData, (uint64));
+ assertEq(s_mockUSDC.s_nonce() - 1, nonce);
+ assertEq(poolReturnDataV1.destTokenAddress, abi.encode(DEST_CHAIN_USDC_TOKEN));
+ }
+
+ function test_Fuzz_LockOrBurnWithAllowList_Success(bytes32 destinationReceiver, uint256 amount) public {
+ vm.assume(destinationReceiver != bytes32(0));
+ amount = bound(amount, 1, getOutboundRateLimiterConfig().capacity);
+ s_token.transfer(address(s_usdcTokenPoolWithAllowList), amount);
+ vm.startPrank(s_routerAllowedOnRamp);
+
+ USDCTokenPool.Domain memory expectedDomain = s_usdcTokenPoolWithAllowList.getDomain(DEST_CHAIN_SELECTOR);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(amount);
+ vm.expectEmit();
+ emit ITokenMessenger.DepositForBurn(
+ s_mockUSDC.s_nonce(),
+ address(s_token),
+ amount,
+ address(s_usdcTokenPoolWithAllowList),
+ expectedDomain.allowedCaller,
+ expectedDomain.domainIdentifier,
+ s_mockUSDC.DESTINATION_TOKEN_MESSENGER(),
+ expectedDomain.allowedCaller
+ );
+ vm.expectEmit();
+ emit TokenPool.Burned(s_routerAllowedOnRamp, amount);
+
+ Pool.LockOrBurnOutV1 memory poolReturnDataV1 = s_usdcTokenPoolWithAllowList.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: s_allowedList[0],
+ receiver: abi.encodePacked(destinationReceiver),
+ amount: amount,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+ uint64 nonce = abi.decode(poolReturnDataV1.destPoolData, (uint64));
+ assertEq(s_mockUSDC.s_nonce() - 1, nonce);
+ assertEq(poolReturnDataV1.destTokenAddress, abi.encode(DEST_CHAIN_USDC_TOKEN));
+ }
+
+ // Reverts
+ function test_UnknownDomain_Revert() public {
+ uint64 wrongDomain = DEST_CHAIN_SELECTOR + 1;
+ // We need to setup the wrong chainSelector so it reaches the domain check
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: wrongDomain, onRamp: s_routerAllowedOnRamp});
+ s_router.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), new Router.OffRamp[](0));
+
+ TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](1);
+ chainUpdates[0] = TokenPool.ChainUpdate({
+ remoteChainSelector: wrongDomain,
+ remotePoolAddress: abi.encode(address(1)),
+ remoteTokenAddress: abi.encode(address(2)),
+ allowed: true,
+ outboundRateLimiterConfig: getOutboundRateLimiterConfig(),
+ inboundRateLimiterConfig: getInboundRateLimiterConfig()
+ });
+
+ s_usdcTokenPool.applyChainUpdates(chainUpdates);
+
+ uint256 amount = 1000;
+ vm.startPrank(s_routerAllowedOnRamp);
+ deal(address(s_token), s_routerAllowedOnRamp, amount);
+ s_token.approve(address(s_usdcTokenPool), amount);
+
+ vm.expectRevert(abi.encodeWithSelector(USDCTokenPool.UnknownDomain.selector, wrongDomain));
+
+ s_usdcTokenPool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: abi.encodePacked(address(0)),
+ amount: amount,
+ remoteChainSelector: wrongDomain,
+ localToken: address(s_token)
+ })
+ );
+ }
+
+ function test_CallerIsNotARampOnRouter_Revert() public {
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.CallerIsNotARampOnRouter.selector, OWNER));
+
+ s_usdcTokenPool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: abi.encodePacked(address(0)),
+ amount: 0,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+ }
+
+ function test_LockOrBurnWithAllowList_Revert() public {
+ vm.startPrank(s_routerAllowedOnRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenPool.SenderNotAllowed.selector, STRANGER));
+
+ s_usdcTokenPoolWithAllowList.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: STRANGER,
+ receiver: abi.encodePacked(address(0)),
+ amount: 1000,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+ }
+
+ function test_lockOrBurn_InvalidReceiver_Revert() public {
+ vm.startPrank(s_routerAllowedOnRamp);
+
+ bytes memory receiver = abi.encodePacked(address(0), address(1));
+
+ vm.expectRevert(abi.encodeWithSelector(USDCTokenPool.InvalidReceiver.selector, receiver));
+
+ s_usdcTokenPool.lockOrBurn(
+ Pool.LockOrBurnInV1({
+ originalSender: OWNER,
+ receiver: receiver,
+ amount: 1,
+ remoteChainSelector: DEST_CHAIN_SELECTOR,
+ localToken: address(s_token)
+ })
+ );
+ }
+}
+
+contract USDCTokenPool_releaseOrMint is USDCTokenPoolSetup {
+ function test_Fuzz_ReleaseOrMint_Success(address recipient, uint256 amount) public {
+ vm.assume(recipient != address(0) && recipient != address(s_token));
+ amount = bound(amount, 0, getInboundRateLimiterConfig().capacity);
+
+ USDCMessage memory usdcMessage = USDCMessage({
+ version: 0,
+ sourceDomain: SOURCE_DOMAIN_IDENTIFIER,
+ destinationDomain: DEST_DOMAIN_IDENTIFIER,
+ nonce: 0x060606060606,
+ sender: SOURCE_CHAIN_TOKEN_SENDER,
+ recipient: bytes32(uint256(uint160(recipient))),
+ destinationCaller: bytes32(uint256(uint160(address(s_usdcTokenPool)))),
+ messageBody: bytes("")
+ });
+
+ bytes memory message = _generateUSDCMessage(usdcMessage);
+ bytes memory attestation = bytes("attestation bytes");
+
+ Internal.SourceTokenData memory sourceTokenData = Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(SOURCE_CHAIN_USDC_POOL),
+ destTokenAddress: abi.encode(address(s_usdcTokenPool)),
+ extraData: abi.encode(
+ USDCTokenPool.SourceTokenDataPayload({nonce: usdcMessage.nonce, sourceDomain: SOURCE_DOMAIN_IDENTIFIER})
+ )
+ });
+
+ bytes memory offchainTokenData =
+ abi.encode(USDCTokenPool.MessageAndAttestation({message: message, attestation: attestation}));
+
+ // The mocked receiver does not release the token to the pool, so we manually do it here
+ deal(address(s_token), address(s_usdcTokenPool), amount);
+
+ vm.expectEmit();
+ emit TokenPool.Minted(s_routerAllowedOffRamp, recipient, amount);
+
+ vm.expectCall(
+ address(s_mockUSDCTransmitter),
+ abi.encodeWithSelector(MockE2EUSDCTransmitter.receiveMessage.selector, message, attestation)
+ );
+
+ vm.startPrank(s_routerAllowedOffRamp);
+ s_usdcTokenPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ receiver: recipient,
+ amount: amount,
+ localToken: address(s_token),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData
+ })
+ );
+ }
+
+ // https://etherscan.io/tx/0xac9f501fe0b76df1f07a22e1db30929fd12524bc7068d74012dff948632f0883
+ function test_ReleaseOrMintRealTx_Success() public {
+ bytes memory encodedUsdcMessage =
+ hex"000000000000000300000000000000000000127a00000000000000000000000019330d10d9cc8751218eaf51e8885d058642e08a000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af3155000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e58310000000000000000000000004af08f56978be7dce2d1be3c65c005b41e79401c000000000000000000000000000000000000000000000000000000002057ff7a0000000000000000000000003a23f943181408eac424116af7b7790c94cb97a50000000000000000000000000000000000000000000000000000000000000000000000000000008274119237535fd659626b090f87e365ff89ebc7096bb32e8b0e85f155626b73ae7c4bb2485c184b7cc3cf7909045487890b104efb62ae74a73e32901bdcec91df1bb9ee08ccb014fcbcfe77b74d1263fd4e0b0e8de05d6c9a5913554364abfd5ea768b222f50c715908183905d74044bb2b97527c7e70ae7983c443a603557cac3b1c000000000000000000000000000000000000000000000000000000000000";
+ bytes memory attestation = bytes("attestation bytes");
+
+ uint32 nonce = 4730;
+ uint32 sourceDomain = 3;
+ uint256 amount = 100;
+
+ Internal.SourceTokenData memory sourceTokenData = Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(SOURCE_CHAIN_USDC_POOL),
+ destTokenAddress: abi.encode(address(s_usdcTokenPool)),
+ extraData: abi.encode(USDCTokenPool.SourceTokenDataPayload({nonce: nonce, sourceDomain: sourceDomain}))
+ });
+
+ // The mocked receiver does not release the token to the pool, so we manually do it here
+ deal(address(s_token), address(s_usdcTokenPool), amount);
+
+ bytes memory offchainTokenData =
+ abi.encode(USDCTokenPool.MessageAndAttestation({message: encodedUsdcMessage, attestation: attestation}));
+
+ vm.expectCall(
+ address(s_mockUSDCTransmitter),
+ abi.encodeWithSelector(MockE2EUSDCTransmitter.receiveMessage.selector, encodedUsdcMessage, attestation)
+ );
+
+ vm.startPrank(s_routerAllowedOffRamp);
+ s_usdcTokenPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ receiver: OWNER,
+ amount: amount,
+ localToken: address(s_token),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData
+ })
+ );
+ }
+
+ // Reverts
+ function test_UnlockingUSDCFailed_Revert() public {
+ vm.startPrank(s_routerAllowedOffRamp);
+ s_mockUSDCTransmitter.setShouldSucceed(false);
+
+ uint256 amount = 13255235235;
+
+ USDCMessage memory usdcMessage = USDCMessage({
+ version: 0,
+ sourceDomain: SOURCE_DOMAIN_IDENTIFIER,
+ destinationDomain: DEST_DOMAIN_IDENTIFIER,
+ nonce: 0x060606060606,
+ sender: SOURCE_CHAIN_TOKEN_SENDER,
+ recipient: bytes32(uint256(uint160(address(s_mockUSDC)))),
+ destinationCaller: bytes32(uint256(uint160(address(s_usdcTokenPool)))),
+ messageBody: bytes("")
+ });
+
+ Internal.SourceTokenData memory sourceTokenData = Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(SOURCE_CHAIN_USDC_POOL),
+ destTokenAddress: abi.encode(address(s_usdcTokenPool)),
+ extraData: abi.encode(
+ USDCTokenPool.SourceTokenDataPayload({nonce: usdcMessage.nonce, sourceDomain: SOURCE_DOMAIN_IDENTIFIER})
+ )
+ });
+
+ bytes memory offchainTokenData = abi.encode(
+ USDCTokenPool.MessageAndAttestation({message: _generateUSDCMessage(usdcMessage), attestation: bytes("")})
+ );
+
+ vm.expectRevert(USDCTokenPool.UnlockingUSDCFailed.selector);
+
+ s_usdcTokenPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ receiver: OWNER,
+ amount: amount,
+ localToken: address(s_token),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData
+ })
+ );
+ }
+
+ function test_TokenMaxCapacityExceeded_Revert() public {
+ uint256 capacity = getInboundRateLimiterConfig().capacity;
+ uint256 amount = 10 * capacity;
+ address recipient = address(1);
+ vm.startPrank(s_routerAllowedOffRamp);
+
+ Internal.SourceTokenData memory sourceTokenData = Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(SOURCE_CHAIN_USDC_POOL),
+ destTokenAddress: abi.encode(address(s_usdcTokenPool)),
+ extraData: abi.encode(USDCTokenPool.SourceTokenDataPayload({nonce: 1, sourceDomain: SOURCE_DOMAIN_IDENTIFIER}))
+ });
+
+ bytes memory offchainTokenData =
+ abi.encode(USDCTokenPool.MessageAndAttestation({message: bytes(""), attestation: bytes("")}));
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.TokenMaxCapacityExceeded.selector, capacity, amount, address(s_token))
+ );
+
+ s_usdcTokenPool.releaseOrMint(
+ Pool.ReleaseOrMintInV1({
+ originalSender: abi.encode(OWNER),
+ receiver: recipient,
+ amount: amount,
+ localToken: address(s_token),
+ remoteChainSelector: SOURCE_CHAIN_SELECTOR,
+ sourcePoolAddress: sourceTokenData.sourcePoolAddress,
+ sourcePoolData: sourceTokenData.extraData,
+ offchainTokenData: offchainTokenData
+ })
+ );
+ }
+}
+
+contract USDCTokenPool_supportsInterface is USDCTokenPoolSetup {
+ function test_SupportsInterface_Success() public view {
+ assertTrue(s_usdcTokenPool.supportsInterface(type(IPoolV1).interfaceId));
+ assertTrue(s_usdcTokenPool.supportsInterface(type(IERC165).interfaceId));
+ }
+}
+
+contract USDCTokenPool_setDomains is USDCTokenPoolSetup {
+ mapping(uint64 destChainSelector => USDCTokenPool.Domain domain) private s_chainToDomain;
+
+ // Setting lower fuzz run as 256 runs was causing differing gas results in snapshot.
+ /// forge-config: default.fuzz.runs = 32
+ /// forge-config: ccip.fuzz.runs = 32
+ function test_Fuzz_SetDomains_Success(
+ bytes32[5] calldata allowedCallers,
+ uint32[5] calldata domainIdentifiers,
+ uint64[5] calldata destChainSelectors
+ ) public {
+ uint256 numberOfDomains = allowedCallers.length;
+ USDCTokenPool.DomainUpdate[] memory domainUpdates = new USDCTokenPool.DomainUpdate[](numberOfDomains);
+ for (uint256 i = 0; i < numberOfDomains; ++i) {
+ vm.assume(allowedCallers[i] != bytes32(0) && domainIdentifiers[i] != 0 && destChainSelectors[i] != 0);
+
+ domainUpdates[i] = USDCTokenPool.DomainUpdate({
+ allowedCaller: allowedCallers[i],
+ domainIdentifier: domainIdentifiers[i],
+ destChainSelector: destChainSelectors[i],
+ enabled: true
+ });
+
+ s_chainToDomain[destChainSelectors[i]] =
+ USDCTokenPool.Domain({domainIdentifier: domainIdentifiers[i], allowedCaller: allowedCallers[i], enabled: true});
+ }
+
+ vm.expectEmit();
+ emit USDCTokenPool.DomainsSet(domainUpdates);
+
+ s_usdcTokenPool.setDomains(domainUpdates);
+
+ for (uint256 i = 0; i < numberOfDomains; ++i) {
+ USDCTokenPool.Domain memory expected = s_chainToDomain[destChainSelectors[i]];
+ USDCTokenPool.Domain memory got = s_usdcTokenPool.getDomain(destChainSelectors[i]);
+ assertEq(got.allowedCaller, expected.allowedCaller);
+ assertEq(got.domainIdentifier, expected.domainIdentifier);
+ }
+ }
+
+ // Reverts
+
+ function test_OnlyOwner_Revert() public {
+ USDCTokenPool.DomainUpdate[] memory domainUpdates = new USDCTokenPool.DomainUpdate[](0);
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+
+ s_usdcTokenPool.setDomains(domainUpdates);
+ }
+
+ function test_InvalidDomain_Revert() public {
+ bytes32 validCaller = bytes32(uint256(25));
+ // Ensure valid domain works
+ USDCTokenPool.DomainUpdate[] memory domainUpdates = new USDCTokenPool.DomainUpdate[](1);
+ domainUpdates[0] = USDCTokenPool.DomainUpdate({
+ allowedCaller: validCaller,
+ domainIdentifier: 0, // ensures 0 is valid, as this is eth mainnet
+ destChainSelector: 45690,
+ enabled: true
+ });
+
+ s_usdcTokenPool.setDomains(domainUpdates);
+
+ // Make update invalid on allowedCaller
+ domainUpdates[0].allowedCaller = bytes32(0);
+ vm.expectRevert(abi.encodeWithSelector(USDCTokenPool.InvalidDomain.selector, domainUpdates[0]));
+
+ s_usdcTokenPool.setDomains(domainUpdates);
+
+ // Make valid again
+ domainUpdates[0].allowedCaller = validCaller;
+
+ // Make invalid on destChainSelector
+ domainUpdates[0].destChainSelector = 0;
+ vm.expectRevert(abi.encodeWithSelector(USDCTokenPool.InvalidDomain.selector, domainUpdates[0]));
+
+ s_usdcTokenPool.setDomains(domainUpdates);
+ }
+}
+
+contract USDCTokenPool__validateMessage is USDCTokenPoolSetup {
+ function test_Fuzz_ValidateMessage_Success(uint32 sourceDomain, uint64 nonce) public {
+ vm.pauseGasMetering();
+ USDCMessage memory usdcMessage = USDCMessage({
+ version: 0,
+ sourceDomain: sourceDomain,
+ destinationDomain: DEST_DOMAIN_IDENTIFIER,
+ nonce: nonce,
+ sender: SOURCE_CHAIN_TOKEN_SENDER,
+ recipient: bytes32(uint256(299999)),
+ destinationCaller: bytes32(uint256(uint160(address(s_usdcTokenPool)))),
+ messageBody: bytes("")
+ });
+
+ bytes memory encodedUsdcMessage = _generateUSDCMessage(usdcMessage);
+
+ vm.resumeGasMetering();
+ s_usdcTokenPool.validateMessage(
+ encodedUsdcMessage, USDCTokenPool.SourceTokenDataPayload({nonce: nonce, sourceDomain: sourceDomain})
+ );
+ }
+
+ // Reverts
+
+ function test_ValidateInvalidMessage_Revert() public {
+ USDCMessage memory usdcMessage = USDCMessage({
+ version: 0,
+ sourceDomain: 1553252,
+ destinationDomain: DEST_DOMAIN_IDENTIFIER,
+ nonce: 387289284924,
+ sender: SOURCE_CHAIN_TOKEN_SENDER,
+ recipient: bytes32(uint256(92398429395823)),
+ destinationCaller: bytes32(uint256(uint160(address(s_usdcTokenPool)))),
+ messageBody: bytes("")
+ });
+
+ USDCTokenPool.SourceTokenDataPayload memory sourceTokenData =
+ USDCTokenPool.SourceTokenDataPayload({nonce: usdcMessage.nonce, sourceDomain: usdcMessage.sourceDomain});
+
+ bytes memory encodedUsdcMessage = _generateUSDCMessage(usdcMessage);
+
+ s_usdcTokenPool.validateMessage(encodedUsdcMessage, sourceTokenData);
+
+ uint32 expectedSourceDomain = usdcMessage.sourceDomain + 1;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(USDCTokenPool.InvalidSourceDomain.selector, expectedSourceDomain, usdcMessage.sourceDomain)
+ );
+ s_usdcTokenPool.validateMessage(
+ encodedUsdcMessage,
+ USDCTokenPool.SourceTokenDataPayload({nonce: usdcMessage.nonce, sourceDomain: expectedSourceDomain})
+ );
+
+ uint64 expectedNonce = usdcMessage.nonce + 1;
+
+ vm.expectRevert(abi.encodeWithSelector(USDCTokenPool.InvalidNonce.selector, expectedNonce, usdcMessage.nonce));
+ s_usdcTokenPool.validateMessage(
+ encodedUsdcMessage,
+ USDCTokenPool.SourceTokenDataPayload({nonce: expectedNonce, sourceDomain: usdcMessage.sourceDomain})
+ );
+
+ usdcMessage.destinationDomain = DEST_DOMAIN_IDENTIFIER + 1;
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ USDCTokenPool.InvalidDestinationDomain.selector, DEST_DOMAIN_IDENTIFIER, usdcMessage.destinationDomain
+ )
+ );
+
+ s_usdcTokenPool.validateMessage(
+ _generateUSDCMessage(usdcMessage),
+ USDCTokenPool.SourceTokenDataPayload({nonce: usdcMessage.nonce, sourceDomain: usdcMessage.sourceDomain})
+ );
+ usdcMessage.destinationDomain = DEST_DOMAIN_IDENTIFIER;
+
+ uint32 wrongVersion = usdcMessage.version + 1;
+
+ usdcMessage.version = wrongVersion;
+ encodedUsdcMessage = _generateUSDCMessage(usdcMessage);
+
+ vm.expectRevert(abi.encodeWithSelector(USDCTokenPool.InvalidMessageVersion.selector, wrongVersion));
+ s_usdcTokenPool.validateMessage(encodedUsdcMessage, sourceTokenData);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/priceRegistry/PriceRegistry.t.sol b/contracts/src/v0.8/ccip/test/priceRegistry/PriceRegistry.t.sol
new file mode 100644
index 00000000000..c3c22ef2909
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/priceRegistry/PriceRegistry.t.sol
@@ -0,0 +1,2542 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IPriceRegistry} from "../../interfaces/IPriceRegistry.sol";
+import {ITokenAdminRegistry} from "../../interfaces/ITokenAdminRegistry.sol";
+
+import {AuthorizedCallers} from "../../../shared/access/AuthorizedCallers.sol";
+import {BurnMintERC677} from "../../../shared/token/ERC677/BurnMintERC677.sol";
+import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol";
+import {PriceRegistry} from "../../PriceRegistry.sol";
+
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {Pool} from "../../libraries/Pool.sol";
+import {USDPriceWith18Decimals} from "../../libraries/USDPriceWith18Decimals.sol";
+import {LockReleaseTokenPool} from "../../pools/LockReleaseTokenPool.sol";
+import {TokenPool} from "../../pools/TokenPool.sol";
+import {TokenAdminRegistry} from "../../tokenAdminRegistry/TokenAdminRegistry.sol";
+
+import {TokenSetup} from "../TokenSetup.t.sol";
+import {MaybeRevertingBurnMintTokenPool} from "../helpers/MaybeRevertingBurnMintTokenPool.sol";
+import {PriceRegistryHelper} from "../helpers/PriceRegistryHelper.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+import {Vm} from "forge-std/Vm.sol";
+import {console} from "forge-std/console.sol";
+
+contract PriceRegistrySetup is TokenSetup {
+ uint112 internal constant USD_PER_GAS = 1e6; // 0.001 gwei
+ uint112 internal constant USD_PER_DATA_AVAILABILITY_GAS = 1e9; // 1 gwei
+
+ address internal constant CUSTOM_TOKEN = address(12345);
+ uint224 internal constant CUSTOM_TOKEN_PRICE = 1e17; // $0.1 CUSTOM
+
+ // Encode L1 gas price and L2 gas price into a packed price.
+ // L1 gas price is left-shifted to the higher-order bits.
+ uint224 internal constant PACKED_USD_PER_GAS =
+ (uint224(USD_PER_DATA_AVAILABILITY_GAS) << Internal.GAS_PRICE_BITS) + USD_PER_GAS;
+
+ PriceRegistryHelper internal s_priceRegistry;
+ // Cheat to store the price updates in storage since struct arrays aren't supported.
+ bytes internal s_encodedInitialPriceUpdates;
+ address internal s_weth;
+
+ address[] internal s_sourceFeeTokens;
+ uint224[] internal s_sourceTokenPrices;
+ address[] internal s_destFeeTokens;
+ uint224[] internal s_destTokenPrices;
+
+ PriceRegistry.PremiumMultiplierWeiPerEthArgs[] internal s_priceRegistryPremiumMultiplierWeiPerEthArgs;
+ PriceRegistry.TokenTransferFeeConfigArgs[] internal s_priceRegistryTokenTransferFeeConfigArgs;
+
+ mapping(address token => address dataFeedAddress) internal s_dataFeedByToken;
+
+ function setUp() public virtual override {
+ TokenSetup.setUp();
+
+ _deployTokenPriceDataFeed(s_sourceFeeToken, 8, 1e8);
+
+ s_weth = s_sourceRouter.getWrappedNative();
+ _deployTokenPriceDataFeed(s_weth, 8, 1e11);
+
+ address[] memory sourceFeeTokens = new address[](3);
+ sourceFeeTokens[0] = s_sourceTokens[0];
+ sourceFeeTokens[1] = s_sourceTokens[1];
+ sourceFeeTokens[2] = s_sourceRouter.getWrappedNative();
+ s_sourceFeeTokens = sourceFeeTokens;
+
+ uint224[] memory sourceTokenPrices = new uint224[](3);
+ sourceTokenPrices[0] = 5e18;
+ sourceTokenPrices[1] = 2000e18;
+ sourceTokenPrices[2] = 2000e18;
+ s_sourceTokenPrices = sourceTokenPrices;
+
+ address[] memory destFeeTokens = new address[](3);
+ destFeeTokens[0] = s_destTokens[0];
+ destFeeTokens[1] = s_destTokens[1];
+ destFeeTokens[2] = s_destRouter.getWrappedNative();
+ s_destFeeTokens = destFeeTokens;
+
+ uint224[] memory destTokenPrices = new uint224[](3);
+ destTokenPrices[0] = 5e18;
+ destTokenPrices[1] = 2000e18;
+ destTokenPrices[2] = 2000e18;
+ s_destTokenPrices = destTokenPrices;
+
+ uint256 sourceTokenCount = sourceFeeTokens.length;
+ uint256 destTokenCount = destFeeTokens.length;
+ address[] memory pricedTokens = new address[](sourceTokenCount + destTokenCount);
+ uint224[] memory tokenPrices = new uint224[](sourceTokenCount + destTokenCount);
+ for (uint256 i = 0; i < sourceTokenCount; ++i) {
+ pricedTokens[i] = sourceFeeTokens[i];
+ tokenPrices[i] = sourceTokenPrices[i];
+ }
+ for (uint256 i = 0; i < destTokenCount; ++i) {
+ pricedTokens[i + sourceTokenCount] = destFeeTokens[i];
+ tokenPrices[i + sourceTokenCount] = destTokenPrices[i];
+ }
+
+ Internal.PriceUpdates memory priceUpdates = getPriceUpdatesStruct(pricedTokens, tokenPrices);
+ priceUpdates.gasPriceUpdates =
+ getSingleGasPriceUpdateStruct(DEST_CHAIN_SELECTOR, PACKED_USD_PER_GAS).gasPriceUpdates;
+
+ s_encodedInitialPriceUpdates = abi.encode(priceUpdates);
+
+ address[] memory priceUpdaters = new address[](1);
+ priceUpdaters[0] = OWNER;
+ address[] memory feeTokens = new address[](2);
+ feeTokens[0] = s_sourceTokens[0];
+ feeTokens[1] = s_weth;
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](0);
+
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs.push(
+ PriceRegistry.PremiumMultiplierWeiPerEthArgs({
+ token: s_sourceFeeToken,
+ premiumMultiplierWeiPerEth: 5e17 // 0.5x
+ })
+ );
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs.push(
+ PriceRegistry.PremiumMultiplierWeiPerEthArgs({
+ token: s_sourceRouter.getWrappedNative(),
+ premiumMultiplierWeiPerEth: 2e18 // 2x
+ })
+ );
+
+ s_priceRegistryTokenTransferFeeConfigArgs.push();
+ s_priceRegistryTokenTransferFeeConfigArgs[0].destChainSelector = DEST_CHAIN_SELECTOR;
+ s_priceRegistryTokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs.push(
+ PriceRegistry.TokenTransferFeeConfigSingleTokenArgs({
+ token: s_sourceFeeToken,
+ tokenTransferFeeConfig: PriceRegistry.TokenTransferFeeConfig({
+ minFeeUSDCents: 1_00, // 1 USD
+ maxFeeUSDCents: 1000_00, // 1,000 USD
+ deciBps: 2_5, // 2.5 bps, or 0.025%
+ destGasOverhead: 40_000,
+ destBytesOverhead: 32,
+ isEnabled: true
+ })
+ })
+ );
+ s_priceRegistryTokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs.push(
+ PriceRegistry.TokenTransferFeeConfigSingleTokenArgs({
+ token: s_sourceRouter.getWrappedNative(),
+ tokenTransferFeeConfig: PriceRegistry.TokenTransferFeeConfig({
+ minFeeUSDCents: 50, // 0.5 USD
+ maxFeeUSDCents: 500_00, // 500 USD
+ deciBps: 5_0, // 5 bps, or 0.05%
+ destGasOverhead: 10_000,
+ destBytesOverhead: 100,
+ isEnabled: true
+ })
+ })
+ );
+ s_priceRegistryTokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs.push(
+ PriceRegistry.TokenTransferFeeConfigSingleTokenArgs({
+ token: CUSTOM_TOKEN,
+ tokenTransferFeeConfig: PriceRegistry.TokenTransferFeeConfig({
+ minFeeUSDCents: 2_00, // 1 USD
+ maxFeeUSDCents: 2000_00, // 1,000 USD
+ deciBps: 10_0, // 10 bps, or 0.1%
+ destGasOverhead: 1,
+ destBytesOverhead: 200,
+ isEnabled: true
+ })
+ })
+ );
+
+ s_priceRegistry = new PriceRegistryHelper(
+ PriceRegistry.StaticConfig({
+ linkToken: s_sourceTokens[0],
+ maxFeeJuelsPerMsg: MAX_MSG_FEES_JUELS,
+ stalenessThreshold: uint32(TWELVE_HOURS)
+ }),
+ priceUpdaters,
+ feeTokens,
+ tokenPriceFeedUpdates,
+ s_priceRegistryTokenTransferFeeConfigArgs,
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs,
+ _generatePriceRegistryDestChainConfigArgs()
+ );
+ s_priceRegistry.updatePrices(priceUpdates);
+ }
+
+ function _deployTokenPriceDataFeed(address token, uint8 decimals, int256 initialAnswer) internal returns (address) {
+ MockV3Aggregator dataFeed = new MockV3Aggregator(decimals, initialAnswer);
+ s_dataFeedByToken[token] = address(dataFeed);
+ return address(dataFeed);
+ }
+
+ function getPriceUpdatesStruct(
+ address[] memory tokens,
+ uint224[] memory prices
+ ) internal pure returns (Internal.PriceUpdates memory) {
+ uint256 length = tokens.length;
+
+ Internal.TokenPriceUpdate[] memory tokenPriceUpdates = new Internal.TokenPriceUpdate[](length);
+ for (uint256 i = 0; i < length; ++i) {
+ tokenPriceUpdates[i] = Internal.TokenPriceUpdate({sourceToken: tokens[i], usdPerToken: prices[i]});
+ }
+ Internal.PriceUpdates memory priceUpdates =
+ Internal.PriceUpdates({tokenPriceUpdates: tokenPriceUpdates, gasPriceUpdates: new Internal.GasPriceUpdate[](0)});
+
+ return priceUpdates;
+ }
+
+ function getEmptyPriceUpdates() internal pure returns (Internal.PriceUpdates memory priceUpdates) {
+ return Internal.PriceUpdates({
+ tokenPriceUpdates: new Internal.TokenPriceUpdate[](0),
+ gasPriceUpdates: new Internal.GasPriceUpdate[](0)
+ });
+ }
+
+ function getSingleTokenPriceFeedUpdateStruct(
+ address sourceToken,
+ address dataFeedAddress,
+ uint8 tokenDecimals
+ ) internal pure returns (PriceRegistry.TokenPriceFeedUpdate memory) {
+ return PriceRegistry.TokenPriceFeedUpdate({
+ sourceToken: sourceToken,
+ feedConfig: IPriceRegistry.TokenPriceFeedConfig({dataFeedAddress: dataFeedAddress, tokenDecimals: tokenDecimals})
+ });
+ }
+
+ function _initialiseSingleTokenPriceFeed() internal returns (address) {
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] =
+ getSingleTokenPriceFeedUpdateStruct(s_sourceTokens[0], s_dataFeedByToken[s_sourceTokens[0]], 18);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+ return s_sourceTokens[0];
+ }
+
+ function _generateTokenTransferFeeConfigArgs(
+ uint256 destChainSelectorLength,
+ uint256 tokenLength
+ ) internal pure returns (PriceRegistry.TokenTransferFeeConfigArgs[] memory) {
+ PriceRegistry.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ new PriceRegistry.TokenTransferFeeConfigArgs[](destChainSelectorLength);
+ for (uint256 i = 0; i < destChainSelectorLength; ++i) {
+ tokenTransferFeeConfigArgs[i].tokenTransferFeeConfigs =
+ new PriceRegistry.TokenTransferFeeConfigSingleTokenArgs[](tokenLength);
+ }
+ return tokenTransferFeeConfigArgs;
+ }
+
+ function _generatePriceRegistryDestChainConfigArgs()
+ internal
+ pure
+ returns (PriceRegistry.DestChainConfigArgs[] memory)
+ {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigs = new PriceRegistry.DestChainConfigArgs[](1);
+ destChainConfigs[0] = PriceRegistry.DestChainConfigArgs({
+ destChainSelector: DEST_CHAIN_SELECTOR,
+ destChainConfig: PriceRegistry.DestChainConfig({
+ isEnabled: true,
+ maxNumberOfTokensPerMsg: MAX_TOKENS_LENGTH,
+ destGasOverhead: DEST_GAS_OVERHEAD,
+ destGasPerPayloadByte: DEST_GAS_PER_PAYLOAD_BYTE,
+ destDataAvailabilityOverheadGas: DEST_DATA_AVAILABILITY_OVERHEAD_GAS,
+ destGasPerDataAvailabilityByte: DEST_GAS_PER_DATA_AVAILABILITY_BYTE,
+ destDataAvailabilityMultiplierBps: DEST_GAS_DATA_AVAILABILITY_MULTIPLIER_BPS,
+ maxDataBytes: MAX_DATA_SIZE,
+ maxPerMsgGasLimit: MAX_GAS_LIMIT,
+ defaultTokenFeeUSDCents: DEFAULT_TOKEN_FEE_USD_CENTS,
+ defaultTokenDestGasOverhead: DEFAULT_TOKEN_DEST_GAS_OVERHEAD,
+ defaultTokenDestBytesOverhead: DEFAULT_TOKEN_BYTES_OVERHEAD,
+ defaultTxGasLimit: GAS_LIMIT,
+ gasMultiplierWeiPerEth: 5e17,
+ networkFeeUSDCents: 1_00,
+ enforceOutOfOrder: false,
+ chainFamilySelector: Internal.CHAIN_FAMILY_SELECTOR_EVM
+ })
+ });
+ return destChainConfigs;
+ }
+
+ function _assertTokenPriceFeedConfigEquality(
+ IPriceRegistry.TokenPriceFeedConfig memory config1,
+ IPriceRegistry.TokenPriceFeedConfig memory config2
+ ) internal pure virtual {
+ assertEq(config1.dataFeedAddress, config2.dataFeedAddress);
+ assertEq(config1.tokenDecimals, config2.tokenDecimals);
+ }
+
+ function _assertTokenPriceFeedConfigUnconfigured(IPriceRegistry.TokenPriceFeedConfig memory config)
+ internal
+ pure
+ virtual
+ {
+ _assertTokenPriceFeedConfigEquality(
+ config, IPriceRegistry.TokenPriceFeedConfig({dataFeedAddress: address(0), tokenDecimals: 0})
+ );
+ }
+
+ function _assertTokenTransferFeeConfigEqual(
+ PriceRegistry.TokenTransferFeeConfig memory a,
+ PriceRegistry.TokenTransferFeeConfig memory b
+ ) internal pure {
+ assertEq(a.minFeeUSDCents, b.minFeeUSDCents);
+ assertEq(a.maxFeeUSDCents, b.maxFeeUSDCents);
+ assertEq(a.deciBps, b.deciBps);
+ assertEq(a.destGasOverhead, b.destGasOverhead);
+ assertEq(a.destBytesOverhead, b.destBytesOverhead);
+ assertEq(a.isEnabled, b.isEnabled);
+ }
+
+ function _assertPriceRegistryStaticConfigsEqual(
+ PriceRegistry.StaticConfig memory a,
+ PriceRegistry.StaticConfig memory b
+ ) internal pure {
+ assertEq(a.linkToken, b.linkToken);
+ assertEq(a.maxFeeJuelsPerMsg, b.maxFeeJuelsPerMsg);
+ }
+
+ function _assertPriceRegistryDestChainConfigsEqual(
+ PriceRegistry.DestChainConfig memory a,
+ PriceRegistry.DestChainConfig memory b
+ ) internal pure {
+ assertEq(a.isEnabled, b.isEnabled);
+ assertEq(a.maxNumberOfTokensPerMsg, b.maxNumberOfTokensPerMsg);
+ assertEq(a.maxDataBytes, b.maxDataBytes);
+ assertEq(a.maxPerMsgGasLimit, b.maxPerMsgGasLimit);
+ assertEq(a.destGasOverhead, b.destGasOverhead);
+ assertEq(a.destGasPerPayloadByte, b.destGasPerPayloadByte);
+ assertEq(a.destDataAvailabilityOverheadGas, b.destDataAvailabilityOverheadGas);
+ assertEq(a.destGasPerDataAvailabilityByte, b.destGasPerDataAvailabilityByte);
+ assertEq(a.destDataAvailabilityMultiplierBps, b.destDataAvailabilityMultiplierBps);
+ assertEq(a.defaultTokenFeeUSDCents, b.defaultTokenFeeUSDCents);
+ assertEq(a.defaultTokenDestGasOverhead, b.defaultTokenDestGasOverhead);
+ assertEq(a.defaultTokenDestBytesOverhead, b.defaultTokenDestBytesOverhead);
+ assertEq(a.defaultTxGasLimit, b.defaultTxGasLimit);
+ }
+}
+
+contract PriceRegistryFeeSetup is PriceRegistrySetup {
+ uint224 internal s_feeTokenPrice;
+ uint224 internal s_wrappedTokenPrice;
+ uint224 internal s_customTokenPrice;
+
+ address internal s_selfServeTokenDefaultPricing = makeAddr("self-serve-token-default-pricing");
+
+ address internal s_destTokenPool = makeAddr("destTokenPool");
+ address internal s_destToken = makeAddr("destToken");
+
+ function setUp() public virtual override {
+ super.setUp();
+
+ s_feeTokenPrice = s_sourceTokenPrices[0];
+ s_wrappedTokenPrice = s_sourceTokenPrices[2];
+ s_customTokenPrice = CUSTOM_TOKEN_PRICE;
+
+ s_priceRegistry.updatePrices(getSingleTokenPriceUpdateStruct(CUSTOM_TOKEN, CUSTOM_TOKEN_PRICE));
+ }
+
+ function _generateEmptyMessage() public view returns (Client.EVM2AnyMessage memory) {
+ return Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ }
+
+ function _generateSingleTokenMessage(
+ address token,
+ uint256 amount
+ ) public view returns (Client.EVM2AnyMessage memory) {
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: token, amount: amount});
+
+ return Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ }
+
+ function _messageToEvent(
+ Client.EVM2AnyMessage memory message,
+ uint64 sourceChainSelector,
+ uint64 destChainSelector,
+ uint64 seqNum,
+ uint64 nonce,
+ uint256 feeTokenAmount,
+ address originalSender,
+ bytes32 metadataHash,
+ TokenAdminRegistry tokenAdminRegistry
+ ) internal view returns (Internal.EVM2AnyRampMessage memory) {
+ Client.EVMExtraArgsV2 memory extraArgs =
+ s_priceRegistry.parseEVMExtraArgsFromBytes(message.extraArgs, destChainSelector);
+
+ Internal.EVM2AnyRampMessage memory messageEvent = Internal.EVM2AnyRampMessage({
+ header: Internal.RampMessageHeader({
+ messageId: "",
+ sourceChainSelector: sourceChainSelector,
+ destChainSelector: destChainSelector,
+ sequenceNumber: seqNum,
+ nonce: extraArgs.allowOutOfOrderExecution ? 0 : nonce
+ }),
+ sender: originalSender,
+ data: message.data,
+ receiver: message.receiver,
+ extraArgs: Client._argsToBytes(extraArgs),
+ feeToken: message.feeToken,
+ feeTokenAmount: feeTokenAmount,
+ tokenAmounts: new Internal.RampTokenAmount[](message.tokenAmounts.length)
+ });
+
+ for (uint256 i = 0; i < message.tokenAmounts.length; ++i) {
+ messageEvent.tokenAmounts[i] = _getSourceTokenData(message.tokenAmounts[i], tokenAdminRegistry);
+ }
+
+ messageEvent.header.messageId = Internal._hash(messageEvent, metadataHash);
+ return messageEvent;
+ }
+
+ function _getSourceTokenData(
+ Client.EVMTokenAmount memory tokenAmount,
+ TokenAdminRegistry tokenAdminRegistry
+ ) internal view returns (Internal.RampTokenAmount memory) {
+ address destToken = s_destTokenBySourceToken[tokenAmount.token];
+
+ return Internal.RampTokenAmount({
+ sourcePoolAddress: abi.encode(tokenAdminRegistry.getTokenConfig(tokenAmount.token).tokenPool),
+ destTokenAddress: abi.encode(destToken),
+ extraData: "",
+ amount: tokenAmount.amount
+ });
+ }
+
+ function calcUSDValueFromTokenAmount(uint224 tokenPrice, uint256 tokenAmount) internal pure returns (uint256) {
+ return (tokenPrice * tokenAmount) / 1e18;
+ }
+
+ function applyBpsRatio(uint256 tokenAmount, uint16 ratio) internal pure returns (uint256) {
+ return (tokenAmount * ratio) / 1e5;
+ }
+
+ function configUSDCentToWei(uint256 usdCent) internal pure returns (uint256) {
+ return usdCent * 1e16;
+ }
+}
+
+contract PriceRegistry_constructor is PriceRegistrySetup {
+ function test_Setup_Success() public virtual {
+ address[] memory priceUpdaters = new address[](2);
+ priceUpdaters[0] = STRANGER;
+ priceUpdaters[1] = OWNER;
+ address[] memory feeTokens = new address[](2);
+ feeTokens[0] = s_sourceTokens[0];
+ feeTokens[1] = s_sourceTokens[1];
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](2);
+ tokenPriceFeedUpdates[0] =
+ getSingleTokenPriceFeedUpdateStruct(s_sourceTokens[0], s_dataFeedByToken[s_sourceTokens[0]], 18);
+ tokenPriceFeedUpdates[1] =
+ getSingleTokenPriceFeedUpdateStruct(s_sourceTokens[1], s_dataFeedByToken[s_sourceTokens[1]], 6);
+
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+
+ PriceRegistry.StaticConfig memory staticConfig = PriceRegistry.StaticConfig({
+ linkToken: s_sourceTokens[0],
+ maxFeeJuelsPerMsg: MAX_MSG_FEES_JUELS,
+ stalenessThreshold: uint32(TWELVE_HOURS)
+ });
+ s_priceRegistry = new PriceRegistryHelper(
+ staticConfig,
+ priceUpdaters,
+ feeTokens,
+ tokenPriceFeedUpdates,
+ s_priceRegistryTokenTransferFeeConfigArgs,
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs,
+ destChainConfigArgs
+ );
+
+ _assertPriceRegistryStaticConfigsEqual(s_priceRegistry.getStaticConfig(), staticConfig);
+ assertEq(feeTokens, s_priceRegistry.getFeeTokens());
+ assertEq(priceUpdaters, s_priceRegistry.getAllAuthorizedCallers());
+ assertEq(s_priceRegistry.typeAndVersion(), "PriceRegistry 1.6.0-dev");
+
+ _assertTokenPriceFeedConfigEquality(
+ tokenPriceFeedUpdates[0].feedConfig, s_priceRegistry.getTokenPriceFeedConfig(s_sourceTokens[0])
+ );
+
+ _assertTokenPriceFeedConfigEquality(
+ tokenPriceFeedUpdates[1].feedConfig, s_priceRegistry.getTokenPriceFeedConfig(s_sourceTokens[1])
+ );
+
+ assertEq(
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs[0].premiumMultiplierWeiPerEth,
+ s_priceRegistry.getPremiumMultiplierWeiPerEth(s_priceRegistryPremiumMultiplierWeiPerEthArgs[0].token)
+ );
+
+ assertEq(
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs[1].premiumMultiplierWeiPerEth,
+ s_priceRegistry.getPremiumMultiplierWeiPerEth(s_priceRegistryPremiumMultiplierWeiPerEthArgs[1].token)
+ );
+
+ PriceRegistry.TokenTransferFeeConfigArgs memory tokenTransferFeeConfigArg =
+ s_priceRegistryTokenTransferFeeConfigArgs[0];
+ for (uint256 i = 0; i < tokenTransferFeeConfigArg.tokenTransferFeeConfigs.length; ++i) {
+ PriceRegistry.TokenTransferFeeConfigSingleTokenArgs memory tokenFeeArgs =
+ s_priceRegistryTokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[i];
+
+ _assertTokenTransferFeeConfigEqual(
+ tokenFeeArgs.tokenTransferFeeConfig,
+ s_priceRegistry.getTokenTransferFeeConfig(tokenTransferFeeConfigArg.destChainSelector, tokenFeeArgs.token)
+ );
+ }
+
+ for (uint256 i = 0; i < destChainConfigArgs.length; ++i) {
+ PriceRegistry.DestChainConfig memory expectedConfig = destChainConfigArgs[i].destChainConfig;
+ uint64 destChainSelector = destChainConfigArgs[i].destChainSelector;
+
+ _assertPriceRegistryDestChainConfigsEqual(expectedConfig, s_priceRegistry.getDestChainConfig(destChainSelector));
+ }
+ }
+
+ function test_InvalidStalenessThreshold_Revert() public {
+ PriceRegistry.StaticConfig memory staticConfig = PriceRegistry.StaticConfig({
+ linkToken: s_sourceTokens[0],
+ maxFeeJuelsPerMsg: MAX_MSG_FEES_JUELS,
+ stalenessThreshold: 0
+ });
+
+ vm.expectRevert(PriceRegistry.InvalidStaticConfig.selector);
+
+ s_priceRegistry = new PriceRegistryHelper(
+ staticConfig,
+ new address[](0),
+ new address[](0),
+ new PriceRegistry.TokenPriceFeedUpdate[](0),
+ s_priceRegistryTokenTransferFeeConfigArgs,
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs,
+ new PriceRegistry.DestChainConfigArgs[](0)
+ );
+ }
+
+ function test_InvalidLinkTokenEqZeroAddress_Revert() public {
+ PriceRegistry.StaticConfig memory staticConfig = PriceRegistry.StaticConfig({
+ linkToken: address(0),
+ maxFeeJuelsPerMsg: MAX_MSG_FEES_JUELS,
+ stalenessThreshold: uint32(TWELVE_HOURS)
+ });
+
+ vm.expectRevert(PriceRegistry.InvalidStaticConfig.selector);
+
+ s_priceRegistry = new PriceRegistryHelper(
+ staticConfig,
+ new address[](0),
+ new address[](0),
+ new PriceRegistry.TokenPriceFeedUpdate[](0),
+ s_priceRegistryTokenTransferFeeConfigArgs,
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs,
+ new PriceRegistry.DestChainConfigArgs[](0)
+ );
+ }
+
+ function test_InvalidMaxFeeJuelsPerMsg_Revert() public {
+ PriceRegistry.StaticConfig memory staticConfig = PriceRegistry.StaticConfig({
+ linkToken: s_sourceTokens[0],
+ maxFeeJuelsPerMsg: 0,
+ stalenessThreshold: uint32(TWELVE_HOURS)
+ });
+
+ vm.expectRevert(PriceRegistry.InvalidStaticConfig.selector);
+
+ s_priceRegistry = new PriceRegistryHelper(
+ staticConfig,
+ new address[](0),
+ new address[](0),
+ new PriceRegistry.TokenPriceFeedUpdate[](0),
+ s_priceRegistryTokenTransferFeeConfigArgs,
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs,
+ new PriceRegistry.DestChainConfigArgs[](0)
+ );
+ }
+}
+
+contract PriceRegistry_getTokenPrices is PriceRegistrySetup {
+ function test_GetTokenPrices_Success() public view {
+ Internal.PriceUpdates memory priceUpdates = abi.decode(s_encodedInitialPriceUpdates, (Internal.PriceUpdates));
+
+ address[] memory tokens = new address[](3);
+ tokens[0] = s_sourceTokens[0];
+ tokens[1] = s_sourceTokens[1];
+ tokens[2] = s_weth;
+
+ Internal.TimestampedPackedUint224[] memory tokenPrices = s_priceRegistry.getTokenPrices(tokens);
+
+ assertEq(tokenPrices.length, 3);
+ assertEq(tokenPrices[0].value, priceUpdates.tokenPriceUpdates[0].usdPerToken);
+ assertEq(tokenPrices[1].value, priceUpdates.tokenPriceUpdates[1].usdPerToken);
+ assertEq(tokenPrices[2].value, priceUpdates.tokenPriceUpdates[2].usdPerToken);
+ }
+}
+
+contract PriceRegistry_getTokenPrice is PriceRegistrySetup {
+ function test_GetTokenPriceFromFeed_Success() public {
+ uint256 originalTimestampValue = block.timestamp;
+
+ // Below staleness threshold
+ vm.warp(originalTimestampValue + 1 hours);
+
+ address sourceToken = _initialiseSingleTokenPriceFeed();
+ Internal.TimestampedPackedUint224 memory tokenPriceAnswer = s_priceRegistry.getTokenPrice(sourceToken);
+
+ // Price answer is 1e8 (18 decimal token) - unit is (1e18 * 1e18 / 1e18) -> expected 1e18
+ assertEq(tokenPriceAnswer.value, uint224(1e18));
+ assertEq(tokenPriceAnswer.timestamp, uint32(block.timestamp));
+ }
+}
+
+contract PriceRegistry_getValidatedTokenPrice is PriceRegistrySetup {
+ function test_GetValidatedTokenPrice_Success() public view {
+ Internal.PriceUpdates memory priceUpdates = abi.decode(s_encodedInitialPriceUpdates, (Internal.PriceUpdates));
+ address token = priceUpdates.tokenPriceUpdates[0].sourceToken;
+
+ uint224 tokenPrice = s_priceRegistry.getValidatedTokenPrice(token);
+
+ assertEq(priceUpdates.tokenPriceUpdates[0].usdPerToken, tokenPrice);
+ }
+
+ function test_GetValidatedTokenPriceFromFeed_Success() public {
+ uint256 originalTimestampValue = block.timestamp;
+
+ // Right below staleness threshold
+ vm.warp(originalTimestampValue + TWELVE_HOURS);
+
+ address sourceToken = _initialiseSingleTokenPriceFeed();
+ uint224 tokenPriceAnswer = s_priceRegistry.getValidatedTokenPrice(sourceToken);
+
+ // Price answer is 1e8 (18 decimal token) - unit is (1e18 * 1e18 / 1e18) -> expected 1e18
+ assertEq(tokenPriceAnswer, uint224(1e18));
+ }
+
+ function test_GetValidatedTokenPriceFromFeedOverStalenessPeriod_Success() public {
+ uint256 originalTimestampValue = block.timestamp;
+
+ // Right above staleness threshold
+ vm.warp(originalTimestampValue + TWELVE_HOURS + 1);
+
+ address sourceToken = _initialiseSingleTokenPriceFeed();
+ uint224 tokenPriceAnswer = s_priceRegistry.getValidatedTokenPrice(sourceToken);
+
+ // Price answer is 1e8 (18 decimal token) - unit is (1e18 * 1e18 / 1e18) -> expected 1e18
+ assertEq(tokenPriceAnswer, uint224(1e18));
+ }
+
+ function test_GetValidatedTokenPriceFromFeedMaxInt224Value_Success() public {
+ address tokenAddress = _deploySourceToken("testToken", 0, 18);
+ address feedAddress = _deployTokenPriceDataFeed(tokenAddress, 18, int256(uint256(type(uint224).max)));
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] = getSingleTokenPriceFeedUpdateStruct(tokenAddress, feedAddress, 18);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ uint224 tokenPriceAnswer = s_priceRegistry.getValidatedTokenPrice(tokenAddress);
+
+ // Price answer is: uint224.MAX_VALUE * (10 ** (36 - 18 - 18))
+ assertEq(tokenPriceAnswer, uint224(type(uint224).max));
+ }
+
+ function test_GetValidatedTokenPriceFromFeedErc20Below18Decimals_Success() public {
+ address tokenAddress = _deploySourceToken("testToken", 0, 6);
+ address feedAddress = _deployTokenPriceDataFeed(tokenAddress, 8, 1e8);
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] = getSingleTokenPriceFeedUpdateStruct(tokenAddress, feedAddress, 6);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ uint224 tokenPriceAnswer = s_priceRegistry.getValidatedTokenPrice(tokenAddress);
+
+ // Price answer is 1e8 (6 decimal token) - unit is (1e18 * 1e18 / 1e6) -> expected 1e30
+ assertEq(tokenPriceAnswer, uint224(1e30));
+ }
+
+ function test_GetValidatedTokenPriceFromFeedErc20Above18Decimals_Success() public {
+ address tokenAddress = _deploySourceToken("testToken", 0, 24);
+ address feedAddress = _deployTokenPriceDataFeed(tokenAddress, 8, 1e8);
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] = getSingleTokenPriceFeedUpdateStruct(tokenAddress, feedAddress, 24);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ uint224 tokenPriceAnswer = s_priceRegistry.getValidatedTokenPrice(tokenAddress);
+
+ // Price answer is 1e8 (6 decimal token) - unit is (1e18 * 1e18 / 1e24) -> expected 1e12
+ assertEq(tokenPriceAnswer, uint224(1e12));
+ }
+
+ function test_GetValidatedTokenPriceFromFeedFeedAt18Decimals_Success() public {
+ address tokenAddress = _deploySourceToken("testToken", 0, 18);
+ address feedAddress = _deployTokenPriceDataFeed(tokenAddress, 18, 1e18);
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] = getSingleTokenPriceFeedUpdateStruct(tokenAddress, feedAddress, 18);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ uint224 tokenPriceAnswer = s_priceRegistry.getValidatedTokenPrice(tokenAddress);
+
+ // Price answer is 1e8 (6 decimal token) - unit is (1e18 * 1e18 / 1e18) -> expected 1e18
+ assertEq(tokenPriceAnswer, uint224(1e18));
+ }
+
+ function test_GetValidatedTokenPriceFromFeedFeedAt0Decimals_Success() public {
+ address tokenAddress = _deploySourceToken("testToken", 0, 0);
+ address feedAddress = _deployTokenPriceDataFeed(tokenAddress, 0, 1e31);
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] = getSingleTokenPriceFeedUpdateStruct(tokenAddress, feedAddress, 0);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ uint224 tokenPriceAnswer = s_priceRegistry.getValidatedTokenPrice(tokenAddress);
+
+ // Price answer is 1e31 (0 decimal token) - unit is (1e18 * 1e18 / 1e0) -> expected 1e36
+ assertEq(tokenPriceAnswer, uint224(1e67));
+ }
+
+ function test_GetValidatedTokenPriceFromFeedFlippedDecimals_Success() public {
+ address tokenAddress = _deploySourceToken("testToken", 0, 20);
+ address feedAddress = _deployTokenPriceDataFeed(tokenAddress, 20, 1e18);
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] = getSingleTokenPriceFeedUpdateStruct(tokenAddress, feedAddress, 20);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ uint224 tokenPriceAnswer = s_priceRegistry.getValidatedTokenPrice(tokenAddress);
+
+ // Price answer is 1e8 (6 decimal token) - unit is (1e18 * 1e18 / 1e20) -> expected 1e14
+ assertEq(tokenPriceAnswer, uint224(1e14));
+ }
+
+ function test_StaleFeeToken_Success() public {
+ vm.warp(block.timestamp + TWELVE_HOURS + 1);
+
+ Internal.PriceUpdates memory priceUpdates = abi.decode(s_encodedInitialPriceUpdates, (Internal.PriceUpdates));
+ address token = priceUpdates.tokenPriceUpdates[0].sourceToken;
+
+ uint224 tokenPrice = s_priceRegistry.getValidatedTokenPrice(token);
+
+ assertEq(priceUpdates.tokenPriceUpdates[0].usdPerToken, tokenPrice);
+ }
+
+ // Reverts
+
+ function test_OverflowFeedPrice_Revert() public {
+ address tokenAddress = _deploySourceToken("testToken", 0, 18);
+ address feedAddress = _deployTokenPriceDataFeed(tokenAddress, 18, int256(uint256(type(uint224).max) + 1));
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] = getSingleTokenPriceFeedUpdateStruct(tokenAddress, feedAddress, 18);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ vm.expectRevert(PriceRegistry.DataFeedValueOutOfUint224Range.selector);
+ s_priceRegistry.getValidatedTokenPrice(tokenAddress);
+ }
+
+ function test_UnderflowFeedPrice_Revert() public {
+ address tokenAddress = _deploySourceToken("testToken", 0, 18);
+ address feedAddress = _deployTokenPriceDataFeed(tokenAddress, 18, -1);
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] = getSingleTokenPriceFeedUpdateStruct(tokenAddress, feedAddress, 18);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ vm.expectRevert(PriceRegistry.DataFeedValueOutOfUint224Range.selector);
+ s_priceRegistry.getValidatedTokenPrice(tokenAddress);
+ }
+
+ function test_TokenNotSupported_Revert() public {
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.TokenNotSupported.selector, DUMMY_CONTRACT_ADDRESS));
+ s_priceRegistry.getValidatedTokenPrice(DUMMY_CONTRACT_ADDRESS);
+ }
+
+ function test_TokenNotSupportedFeed_Revert() public {
+ address sourceToken = _initialiseSingleTokenPriceFeed();
+ MockV3Aggregator(s_dataFeedByToken[sourceToken]).updateAnswer(0);
+
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.TokenNotSupported.selector, sourceToken));
+ s_priceRegistry.getValidatedTokenPrice(sourceToken);
+ }
+}
+
+contract PriceRegistry_applyFeeTokensUpdates is PriceRegistrySetup {
+ function test_ApplyFeeTokensUpdates_Success() public {
+ address[] memory feeTokens = new address[](1);
+ feeTokens[0] = s_sourceTokens[1];
+
+ vm.expectEmit();
+ emit PriceRegistry.FeeTokenAdded(feeTokens[0]);
+
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+ assertEq(s_priceRegistry.getFeeTokens().length, 3);
+ assertEq(s_priceRegistry.getFeeTokens()[2], feeTokens[0]);
+
+ // add same feeToken is no-op
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+ assertEq(s_priceRegistry.getFeeTokens().length, 3);
+ assertEq(s_priceRegistry.getFeeTokens()[2], feeTokens[0]);
+
+ vm.expectEmit();
+ emit PriceRegistry.FeeTokenRemoved(feeTokens[0]);
+
+ s_priceRegistry.applyFeeTokensUpdates(new address[](0), feeTokens);
+ assertEq(s_priceRegistry.getFeeTokens().length, 2);
+
+ // removing already removed feeToken is no-op
+ s_priceRegistry.applyFeeTokensUpdates(new address[](0), feeTokens);
+ assertEq(s_priceRegistry.getFeeTokens().length, 2);
+ }
+
+ function test_OnlyCallableByOwner_Revert() public {
+ address[] memory feeTokens = new address[](1);
+ feeTokens[0] = STRANGER;
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+ }
+}
+
+contract PriceRegistry_updatePrices is PriceRegistrySetup {
+ function test_OnlyTokenPrice_Success() public {
+ Internal.PriceUpdates memory update = Internal.PriceUpdates({
+ tokenPriceUpdates: new Internal.TokenPriceUpdate[](1),
+ gasPriceUpdates: new Internal.GasPriceUpdate[](0)
+ });
+ update.tokenPriceUpdates[0] = Internal.TokenPriceUpdate({sourceToken: s_sourceTokens[0], usdPerToken: 4e18});
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(
+ update.tokenPriceUpdates[0].sourceToken, update.tokenPriceUpdates[0].usdPerToken, block.timestamp
+ );
+
+ s_priceRegistry.updatePrices(update);
+
+ assertEq(s_priceRegistry.getTokenPrice(s_sourceTokens[0]).value, update.tokenPriceUpdates[0].usdPerToken);
+ }
+
+ function test_OnlyGasPrice_Success() public {
+ Internal.PriceUpdates memory update = Internal.PriceUpdates({
+ tokenPriceUpdates: new Internal.TokenPriceUpdate[](0),
+ gasPriceUpdates: new Internal.GasPriceUpdate[](1)
+ });
+ update.gasPriceUpdates[0] =
+ Internal.GasPriceUpdate({destChainSelector: DEST_CHAIN_SELECTOR, usdPerUnitGas: 2000e18});
+
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerUnitGasUpdated(
+ update.gasPriceUpdates[0].destChainSelector, update.gasPriceUpdates[0].usdPerUnitGas, block.timestamp
+ );
+
+ s_priceRegistry.updatePrices(update);
+
+ assertEq(
+ s_priceRegistry.getDestinationChainGasPrice(DEST_CHAIN_SELECTOR).value, update.gasPriceUpdates[0].usdPerUnitGas
+ );
+ }
+
+ function test_UpdateMultiplePrices_Success() public {
+ Internal.TokenPriceUpdate[] memory tokenPriceUpdates = new Internal.TokenPriceUpdate[](3);
+ tokenPriceUpdates[0] = Internal.TokenPriceUpdate({sourceToken: s_sourceTokens[0], usdPerToken: 4e18});
+ tokenPriceUpdates[1] = Internal.TokenPriceUpdate({sourceToken: s_sourceTokens[1], usdPerToken: 1800e18});
+ tokenPriceUpdates[2] = Internal.TokenPriceUpdate({sourceToken: address(12345), usdPerToken: 1e18});
+
+ Internal.GasPriceUpdate[] memory gasPriceUpdates = new Internal.GasPriceUpdate[](3);
+ gasPriceUpdates[0] = Internal.GasPriceUpdate({destChainSelector: DEST_CHAIN_SELECTOR, usdPerUnitGas: 2e6});
+ gasPriceUpdates[1] = Internal.GasPriceUpdate({destChainSelector: SOURCE_CHAIN_SELECTOR, usdPerUnitGas: 2000e18});
+ gasPriceUpdates[2] = Internal.GasPriceUpdate({destChainSelector: 12345, usdPerUnitGas: 1e18});
+
+ Internal.PriceUpdates memory update =
+ Internal.PriceUpdates({tokenPriceUpdates: tokenPriceUpdates, gasPriceUpdates: gasPriceUpdates});
+
+ for (uint256 i = 0; i < tokenPriceUpdates.length; ++i) {
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(
+ update.tokenPriceUpdates[i].sourceToken, update.tokenPriceUpdates[i].usdPerToken, block.timestamp
+ );
+ }
+ for (uint256 i = 0; i < gasPriceUpdates.length; ++i) {
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerUnitGasUpdated(
+ update.gasPriceUpdates[i].destChainSelector, update.gasPriceUpdates[i].usdPerUnitGas, block.timestamp
+ );
+ }
+
+ s_priceRegistry.updatePrices(update);
+
+ for (uint256 i = 0; i < tokenPriceUpdates.length; ++i) {
+ assertEq(
+ s_priceRegistry.getTokenPrice(update.tokenPriceUpdates[i].sourceToken).value, tokenPriceUpdates[i].usdPerToken
+ );
+ }
+ for (uint256 i = 0; i < gasPriceUpdates.length; ++i) {
+ assertEq(
+ s_priceRegistry.getDestinationChainGasPrice(update.gasPriceUpdates[i].destChainSelector).value,
+ gasPriceUpdates[i].usdPerUnitGas
+ );
+ }
+ }
+
+ function test_UpdatableByAuthorizedCaller_Success() public {
+ Internal.PriceUpdates memory priceUpdates = Internal.PriceUpdates({
+ tokenPriceUpdates: new Internal.TokenPriceUpdate[](1),
+ gasPriceUpdates: new Internal.GasPriceUpdate[](0)
+ });
+ priceUpdates.tokenPriceUpdates[0] = Internal.TokenPriceUpdate({sourceToken: s_sourceTokens[0], usdPerToken: 4e18});
+
+ // Revert when caller is not authorized
+ vm.startPrank(STRANGER);
+ vm.expectRevert(abi.encodeWithSelector(AuthorizedCallers.UnauthorizedCaller.selector, STRANGER));
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ address[] memory priceUpdaters = new address[](1);
+ priceUpdaters[0] = STRANGER;
+ vm.startPrank(OWNER);
+ s_priceRegistry.applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: priceUpdaters, removedCallers: new address[](0)})
+ );
+
+ // Stranger is now an authorized caller to update prices
+ vm.expectEmit();
+ emit PriceRegistry.UsdPerTokenUpdated(
+ priceUpdates.tokenPriceUpdates[0].sourceToken, priceUpdates.tokenPriceUpdates[0].usdPerToken, block.timestamp
+ );
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ assertEq(s_priceRegistry.getTokenPrice(s_sourceTokens[0]).value, priceUpdates.tokenPriceUpdates[0].usdPerToken);
+
+ vm.startPrank(OWNER);
+ s_priceRegistry.applyAuthorizedCallerUpdates(
+ AuthorizedCallers.AuthorizedCallerArgs({addedCallers: new address[](0), removedCallers: priceUpdaters})
+ );
+
+ // Revert when authorized caller is removed
+ vm.startPrank(STRANGER);
+ vm.expectRevert(abi.encodeWithSelector(AuthorizedCallers.UnauthorizedCaller.selector, STRANGER));
+ s_priceRegistry.updatePrices(priceUpdates);
+ }
+
+ // Reverts
+
+ function test_OnlyCallableByUpdater_Revert() public {
+ Internal.PriceUpdates memory priceUpdates = Internal.PriceUpdates({
+ tokenPriceUpdates: new Internal.TokenPriceUpdate[](0),
+ gasPriceUpdates: new Internal.GasPriceUpdate[](0)
+ });
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert(abi.encodeWithSelector(AuthorizedCallers.UnauthorizedCaller.selector, STRANGER));
+ s_priceRegistry.updatePrices(priceUpdates);
+ }
+}
+
+contract PriceRegistry_convertTokenAmount is PriceRegistrySetup {
+ function test_ConvertTokenAmount_Success() public view {
+ Internal.PriceUpdates memory initialPriceUpdates = abi.decode(s_encodedInitialPriceUpdates, (Internal.PriceUpdates));
+ uint256 amount = 3e16;
+ uint256 conversionRate = (uint256(initialPriceUpdates.tokenPriceUpdates[2].usdPerToken) * 1e18)
+ / uint256(initialPriceUpdates.tokenPriceUpdates[0].usdPerToken);
+ uint256 expected = (amount * conversionRate) / 1e18;
+ assertEq(s_priceRegistry.convertTokenAmount(s_weth, amount, s_sourceTokens[0]), expected);
+ }
+
+ function test_Fuzz_ConvertTokenAmount_Success(
+ uint256 feeTokenAmount,
+ uint224 usdPerFeeToken,
+ uint160 usdPerLinkToken,
+ uint224 usdPerUnitGas
+ ) public {
+ vm.assume(usdPerFeeToken > 0);
+ vm.assume(usdPerLinkToken > 0);
+ // We bound the max fees to be at most uint96.max link.
+ feeTokenAmount = bound(feeTokenAmount, 0, (uint256(type(uint96).max) * usdPerLinkToken) / usdPerFeeToken);
+
+ address feeToken = address(1);
+ address linkToken = address(2);
+ address[] memory feeTokens = new address[](1);
+ feeTokens[0] = feeToken;
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+
+ Internal.TokenPriceUpdate[] memory tokenPriceUpdates = new Internal.TokenPriceUpdate[](2);
+ tokenPriceUpdates[0] = Internal.TokenPriceUpdate({sourceToken: feeToken, usdPerToken: usdPerFeeToken});
+ tokenPriceUpdates[1] = Internal.TokenPriceUpdate({sourceToken: linkToken, usdPerToken: usdPerLinkToken});
+
+ Internal.GasPriceUpdate[] memory gasPriceUpdates = new Internal.GasPriceUpdate[](1);
+ gasPriceUpdates[0] = Internal.GasPriceUpdate({destChainSelector: DEST_CHAIN_SELECTOR, usdPerUnitGas: usdPerUnitGas});
+
+ Internal.PriceUpdates memory priceUpdates =
+ Internal.PriceUpdates({tokenPriceUpdates: tokenPriceUpdates, gasPriceUpdates: gasPriceUpdates});
+
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ uint256 linkFee = s_priceRegistry.convertTokenAmount(feeToken, feeTokenAmount, linkToken);
+ assertEq(linkFee, (feeTokenAmount * usdPerFeeToken) / usdPerLinkToken);
+ }
+
+ // Reverts
+
+ function test_LinkTokenNotSupported_Revert() public {
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.TokenNotSupported.selector, DUMMY_CONTRACT_ADDRESS));
+ s_priceRegistry.convertTokenAmount(DUMMY_CONTRACT_ADDRESS, 3e16, s_sourceTokens[0]);
+
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.TokenNotSupported.selector, DUMMY_CONTRACT_ADDRESS));
+ s_priceRegistry.convertTokenAmount(s_sourceTokens[0], 3e16, DUMMY_CONTRACT_ADDRESS);
+ }
+}
+
+contract PriceRegistry_getTokenAndGasPrices is PriceRegistrySetup {
+ function test_GetFeeTokenAndGasPrices_Success() public view {
+ (uint224 feeTokenPrice, uint224 gasPrice) =
+ s_priceRegistry.getTokenAndGasPrices(s_sourceFeeToken, DEST_CHAIN_SELECTOR);
+
+ Internal.PriceUpdates memory priceUpdates = abi.decode(s_encodedInitialPriceUpdates, (Internal.PriceUpdates));
+
+ assertEq(feeTokenPrice, s_sourceTokenPrices[0]);
+ assertEq(gasPrice, priceUpdates.gasPriceUpdates[0].usdPerUnitGas);
+ }
+
+ function test_ZeroGasPrice_Success() public {
+ uint64 zeroGasDestChainSelector = 345678;
+ Internal.GasPriceUpdate[] memory gasPriceUpdates = new Internal.GasPriceUpdate[](1);
+ gasPriceUpdates[0] = Internal.GasPriceUpdate({destChainSelector: zeroGasDestChainSelector, usdPerUnitGas: 0});
+
+ Internal.PriceUpdates memory priceUpdates =
+ Internal.PriceUpdates({tokenPriceUpdates: new Internal.TokenPriceUpdate[](0), gasPriceUpdates: gasPriceUpdates});
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ (, uint224 gasPrice) = s_priceRegistry.getTokenAndGasPrices(s_sourceFeeToken, zeroGasDestChainSelector);
+
+ assertEq(gasPrice, priceUpdates.gasPriceUpdates[0].usdPerUnitGas);
+ }
+
+ function test_UnsupportedChain_Revert() public {
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.ChainNotSupported.selector, DEST_CHAIN_SELECTOR + 1));
+ s_priceRegistry.getTokenAndGasPrices(s_sourceTokens[0], DEST_CHAIN_SELECTOR + 1);
+ }
+
+ function test_StaleGasPrice_Revert() public {
+ uint256 diff = TWELVE_HOURS + 1;
+ vm.warp(block.timestamp + diff);
+ vm.expectRevert(
+ abi.encodeWithSelector(PriceRegistry.StaleGasPrice.selector, DEST_CHAIN_SELECTOR, TWELVE_HOURS, diff)
+ );
+ s_priceRegistry.getTokenAndGasPrices(s_sourceTokens[0], DEST_CHAIN_SELECTOR);
+ }
+}
+
+contract PriceRegistry_updateTokenPriceFeeds is PriceRegistrySetup {
+ function test_ZeroFeeds_Success() public {
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](0);
+ vm.recordLogs();
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ // Verify no log emissions
+ assertEq(logEntries.length, 0);
+ }
+
+ function test_SingleFeedUpdate_Success() public {
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] =
+ getSingleTokenPriceFeedUpdateStruct(s_sourceTokens[0], s_dataFeedByToken[s_sourceTokens[0]], 18);
+
+ _assertTokenPriceFeedConfigUnconfigured(
+ s_priceRegistry.getTokenPriceFeedConfig(tokenPriceFeedUpdates[0].sourceToken)
+ );
+
+ vm.expectEmit();
+ emit PriceRegistry.PriceFeedPerTokenUpdated(
+ tokenPriceFeedUpdates[0].sourceToken, tokenPriceFeedUpdates[0].feedConfig
+ );
+
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ _assertTokenPriceFeedConfigEquality(
+ s_priceRegistry.getTokenPriceFeedConfig(tokenPriceFeedUpdates[0].sourceToken), tokenPriceFeedUpdates[0].feedConfig
+ );
+ }
+
+ function test_MultipleFeedUpdate_Success() public {
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](2);
+
+ for (uint256 i = 0; i < 2; ++i) {
+ tokenPriceFeedUpdates[i] =
+ getSingleTokenPriceFeedUpdateStruct(s_sourceTokens[i], s_dataFeedByToken[s_sourceTokens[i]], 18);
+
+ _assertTokenPriceFeedConfigUnconfigured(
+ s_priceRegistry.getTokenPriceFeedConfig(tokenPriceFeedUpdates[i].sourceToken)
+ );
+
+ vm.expectEmit();
+ emit PriceRegistry.PriceFeedPerTokenUpdated(
+ tokenPriceFeedUpdates[i].sourceToken, tokenPriceFeedUpdates[i].feedConfig
+ );
+ }
+
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ _assertTokenPriceFeedConfigEquality(
+ s_priceRegistry.getTokenPriceFeedConfig(tokenPriceFeedUpdates[0].sourceToken), tokenPriceFeedUpdates[0].feedConfig
+ );
+ _assertTokenPriceFeedConfigEquality(
+ s_priceRegistry.getTokenPriceFeedConfig(tokenPriceFeedUpdates[1].sourceToken), tokenPriceFeedUpdates[1].feedConfig
+ );
+ }
+
+ function test_FeedUnset_Success() public {
+ Internal.TimestampedPackedUint224 memory priceQueryInitial = s_priceRegistry.getTokenPrice(s_sourceTokens[0]);
+ assertFalse(priceQueryInitial.value == 0);
+ assertFalse(priceQueryInitial.timestamp == 0);
+
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] =
+ getSingleTokenPriceFeedUpdateStruct(s_sourceTokens[0], s_dataFeedByToken[s_sourceTokens[0]], 18);
+
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+ _assertTokenPriceFeedConfigEquality(
+ s_priceRegistry.getTokenPriceFeedConfig(tokenPriceFeedUpdates[0].sourceToken), tokenPriceFeedUpdates[0].feedConfig
+ );
+
+ tokenPriceFeedUpdates[0].feedConfig.dataFeedAddress = address(0);
+ vm.expectEmit();
+ emit PriceRegistry.PriceFeedPerTokenUpdated(
+ tokenPriceFeedUpdates[0].sourceToken, tokenPriceFeedUpdates[0].feedConfig
+ );
+
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+ _assertTokenPriceFeedConfigEquality(
+ s_priceRegistry.getTokenPriceFeedConfig(tokenPriceFeedUpdates[0].sourceToken), tokenPriceFeedUpdates[0].feedConfig
+ );
+
+ // Price data should remain after a feed has been set->unset
+ Internal.TimestampedPackedUint224 memory priceQueryPostUnsetFeed = s_priceRegistry.getTokenPrice(s_sourceTokens[0]);
+ assertEq(priceQueryPostUnsetFeed.value, priceQueryInitial.value);
+ assertEq(priceQueryPostUnsetFeed.timestamp, priceQueryInitial.timestamp);
+ }
+
+ function test_FeedNotUpdated() public {
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] =
+ getSingleTokenPriceFeedUpdateStruct(s_sourceTokens[0], s_dataFeedByToken[s_sourceTokens[0]], 18);
+
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+
+ _assertTokenPriceFeedConfigEquality(
+ s_priceRegistry.getTokenPriceFeedConfig(tokenPriceFeedUpdates[0].sourceToken), tokenPriceFeedUpdates[0].feedConfig
+ );
+ }
+
+ // Reverts
+
+ function test_FeedUpdatedByNonOwner_Revert() public {
+ PriceRegistry.TokenPriceFeedUpdate[] memory tokenPriceFeedUpdates = new PriceRegistry.TokenPriceFeedUpdate[](1);
+ tokenPriceFeedUpdates[0] =
+ getSingleTokenPriceFeedUpdateStruct(s_sourceTokens[0], s_dataFeedByToken[s_sourceTokens[0]], 18);
+
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+
+ s_priceRegistry.updateTokenPriceFeeds(tokenPriceFeedUpdates);
+ }
+}
+
+contract PriceRegistry_applyDestChainConfigUpdates is PriceRegistrySetup {
+ function test_Fuzz_applyDestChainConfigUpdates_Success(PriceRegistry.DestChainConfigArgs memory destChainConfigArgs)
+ public
+ {
+ vm.assume(destChainConfigArgs.destChainSelector != 0);
+ vm.assume(destChainConfigArgs.destChainConfig.maxPerMsgGasLimit != 0);
+ destChainConfigArgs.destChainConfig.defaultTxGasLimit = uint32(
+ bound(
+ destChainConfigArgs.destChainConfig.defaultTxGasLimit, 1, destChainConfigArgs.destChainConfig.maxPerMsgGasLimit
+ )
+ );
+ destChainConfigArgs.destChainConfig.defaultTokenDestBytesOverhead = uint32(
+ bound(
+ destChainConfigArgs.destChainConfig.defaultTokenDestBytesOverhead,
+ Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES,
+ type(uint32).max
+ )
+ );
+ destChainConfigArgs.destChainConfig.chainFamilySelector = Internal.CHAIN_FAMILY_SELECTOR_EVM;
+
+ bool isNewChain = destChainConfigArgs.destChainSelector != DEST_CHAIN_SELECTOR;
+
+ PriceRegistry.DestChainConfigArgs[] memory newDestChainConfigArgs = new PriceRegistry.DestChainConfigArgs[](1);
+ newDestChainConfigArgs[0] = destChainConfigArgs;
+
+ if (isNewChain) {
+ vm.expectEmit();
+ emit PriceRegistry.DestChainAdded(destChainConfigArgs.destChainSelector, destChainConfigArgs.destChainConfig);
+ } else {
+ vm.expectEmit();
+ emit PriceRegistry.DestChainConfigUpdated(
+ destChainConfigArgs.destChainSelector, destChainConfigArgs.destChainConfig
+ );
+ }
+
+ s_priceRegistry.applyDestChainConfigUpdates(newDestChainConfigArgs);
+
+ _assertPriceRegistryDestChainConfigsEqual(
+ destChainConfigArgs.destChainConfig, s_priceRegistry.getDestChainConfig(destChainConfigArgs.destChainSelector)
+ );
+ }
+
+ function test_applyDestChainConfigUpdates_Success() public {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = new PriceRegistry.DestChainConfigArgs[](2);
+ destChainConfigArgs[0] = _generatePriceRegistryDestChainConfigArgs()[0];
+ destChainConfigArgs[0].destChainConfig.isEnabled = false;
+ destChainConfigArgs[1] = _generatePriceRegistryDestChainConfigArgs()[0];
+ destChainConfigArgs[1].destChainSelector = DEST_CHAIN_SELECTOR + 1;
+
+ vm.expectEmit();
+ emit PriceRegistry.DestChainConfigUpdated(DEST_CHAIN_SELECTOR, destChainConfigArgs[0].destChainConfig);
+ vm.expectEmit();
+ emit PriceRegistry.DestChainAdded(DEST_CHAIN_SELECTOR + 1, destChainConfigArgs[1].destChainConfig);
+
+ vm.recordLogs();
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+
+ PriceRegistry.DestChainConfig memory gotDestChainConfig0 = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+ PriceRegistry.DestChainConfig memory gotDestChainConfig1 =
+ s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR + 1);
+
+ assertEq(vm.getRecordedLogs().length, 2);
+ _assertPriceRegistryDestChainConfigsEqual(destChainConfigArgs[0].destChainConfig, gotDestChainConfig0);
+ _assertPriceRegistryDestChainConfigsEqual(destChainConfigArgs[1].destChainConfig, gotDestChainConfig1);
+ }
+
+ function test_applyDestChainConfigUpdatesZeroIntput_Success() public {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = new PriceRegistry.DestChainConfigArgs[](0);
+
+ vm.recordLogs();
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+
+ assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ // Reverts
+
+ function test_applyDestChainConfigUpdatesDefaultTxGasLimitEqZero_Revert() public {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ PriceRegistry.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];
+
+ destChainConfigArg.destChainConfig.defaultTxGasLimit = 0;
+ vm.expectRevert(
+ abi.encodeWithSelector(PriceRegistry.InvalidDestChainConfig.selector, destChainConfigArg.destChainSelector)
+ );
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+ }
+
+ function test_applyDestChainConfigUpdatesDefaultTxGasLimitGtMaxPerMessageGasLimit_Revert() public {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ PriceRegistry.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];
+
+ // Allow setting to the max value
+ destChainConfigArg.destChainConfig.defaultTxGasLimit = destChainConfigArg.destChainConfig.maxPerMsgGasLimit;
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+
+ // Revert when exceeding max value
+ destChainConfigArg.destChainConfig.defaultTxGasLimit = destChainConfigArg.destChainConfig.maxPerMsgGasLimit + 1;
+ vm.expectRevert(
+ abi.encodeWithSelector(PriceRegistry.InvalidDestChainConfig.selector, destChainConfigArg.destChainSelector)
+ );
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+ }
+
+ function test_InvalidDestChainConfigDestChainSelectorEqZero_Revert() public {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ PriceRegistry.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];
+
+ destChainConfigArg.destChainSelector = 0;
+ vm.expectRevert(
+ abi.encodeWithSelector(PriceRegistry.InvalidDestChainConfig.selector, destChainConfigArg.destChainSelector)
+ );
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+ }
+
+ function test_InvalidDestBytesOverhead_Revert() public {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ PriceRegistry.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];
+
+ destChainConfigArg.destChainConfig.defaultTokenDestBytesOverhead = uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES - 1);
+
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.InvalidDestChainConfig.selector, DEST_CHAIN_SELECTOR));
+
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+ }
+
+ function test_InvalidChainFamilySelector_Revert() public {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ PriceRegistry.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];
+
+ destChainConfigArg.destChainConfig.chainFamilySelector = bytes4(uint32(1));
+
+ vm.expectRevert(
+ abi.encodeWithSelector(PriceRegistry.InvalidDestChainConfig.selector, destChainConfigArg.destChainSelector)
+ );
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+ }
+}
+
+contract PriceRegistry_getDataAvailabilityCost is PriceRegistrySetup {
+ function test_EmptyMessageCalculatesDataAvailabilityCost_Success() public {
+ uint256 dataAvailabilityCostUSD =
+ s_priceRegistry.getDataAvailabilityCost(DEST_CHAIN_SELECTOR, USD_PER_DATA_AVAILABILITY_GAS, 0, 0, 0);
+
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+
+ uint256 dataAvailabilityGas = destChainConfig.destDataAvailabilityOverheadGas
+ + destChainConfig.destGasPerDataAvailabilityByte * Internal.ANY_2_EVM_MESSAGE_FIXED_BYTES;
+ uint256 expectedDataAvailabilityCostUSD =
+ USD_PER_DATA_AVAILABILITY_GAS * dataAvailabilityGas * destChainConfig.destDataAvailabilityMultiplierBps * 1e14;
+
+ assertEq(expectedDataAvailabilityCostUSD, dataAvailabilityCostUSD);
+
+ // Test that the cost is destnation chain specific
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ destChainConfigArgs[0].destChainSelector = DEST_CHAIN_SELECTOR + 1;
+ destChainConfigArgs[0].destChainConfig.destDataAvailabilityOverheadGas =
+ destChainConfig.destDataAvailabilityOverheadGas * 2;
+ destChainConfigArgs[0].destChainConfig.destGasPerDataAvailabilityByte =
+ destChainConfig.destGasPerDataAvailabilityByte * 2;
+ destChainConfigArgs[0].destChainConfig.destDataAvailabilityMultiplierBps =
+ destChainConfig.destDataAvailabilityMultiplierBps * 2;
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+
+ destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR + 1);
+ uint256 dataAvailabilityCostUSD2 =
+ s_priceRegistry.getDataAvailabilityCost(DEST_CHAIN_SELECTOR + 1, USD_PER_DATA_AVAILABILITY_GAS, 0, 0, 0);
+ dataAvailabilityGas = destChainConfig.destDataAvailabilityOverheadGas
+ + destChainConfig.destGasPerDataAvailabilityByte * Internal.ANY_2_EVM_MESSAGE_FIXED_BYTES;
+ expectedDataAvailabilityCostUSD =
+ USD_PER_DATA_AVAILABILITY_GAS * dataAvailabilityGas * destChainConfig.destDataAvailabilityMultiplierBps * 1e14;
+
+ assertEq(expectedDataAvailabilityCostUSD, dataAvailabilityCostUSD2);
+ assertFalse(dataAvailabilityCostUSD == dataAvailabilityCostUSD2);
+ }
+
+ function test_SimpleMessageCalculatesDataAvailabilityCost_Success() public view {
+ uint256 dataAvailabilityCostUSD =
+ s_priceRegistry.getDataAvailabilityCost(DEST_CHAIN_SELECTOR, USD_PER_DATA_AVAILABILITY_GAS, 100, 5, 50);
+
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+
+ uint256 dataAvailabilityLengthBytes =
+ Internal.ANY_2_EVM_MESSAGE_FIXED_BYTES + 100 + (5 * Internal.ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN) + 50;
+ uint256 dataAvailabilityGas = destChainConfig.destDataAvailabilityOverheadGas
+ + destChainConfig.destGasPerDataAvailabilityByte * dataAvailabilityLengthBytes;
+ uint256 expectedDataAvailabilityCostUSD =
+ USD_PER_DATA_AVAILABILITY_GAS * dataAvailabilityGas * destChainConfig.destDataAvailabilityMultiplierBps * 1e14;
+
+ assertEq(expectedDataAvailabilityCostUSD, dataAvailabilityCostUSD);
+ }
+
+ function test_SimpleMessageCalculatesDataAvailabilityCostUnsupportedDestChainSelector_Success() public view {
+ uint256 dataAvailabilityCostUSD =
+ s_priceRegistry.getDataAvailabilityCost(0, USD_PER_DATA_AVAILABILITY_GAS, 100, 5, 50);
+
+ assertEq(dataAvailabilityCostUSD, 0);
+ }
+
+ function test_Fuzz_ZeroDataAvailabilityGasPriceAlwaysCalculatesZeroDataAvailabilityCost_Success(
+ uint64 messageDataLength,
+ uint32 numberOfTokens,
+ uint32 tokenTransferBytesOverhead
+ ) public view {
+ uint256 dataAvailabilityCostUSD = s_priceRegistry.getDataAvailabilityCost(
+ DEST_CHAIN_SELECTOR, 0, messageDataLength, numberOfTokens, tokenTransferBytesOverhead
+ );
+
+ assertEq(0, dataAvailabilityCostUSD);
+ }
+
+ function test_Fuzz_CalculateDataAvailabilityCost_Success(
+ uint64 destChainSelector,
+ uint32 destDataAvailabilityOverheadGas,
+ uint16 destGasPerDataAvailabilityByte,
+ uint16 destDataAvailabilityMultiplierBps,
+ uint112 dataAvailabilityGasPrice,
+ uint64 messageDataLength,
+ uint32 numberOfTokens,
+ uint32 tokenTransferBytesOverhead
+ ) public {
+ vm.assume(destChainSelector != 0);
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = new PriceRegistry.DestChainConfigArgs[](1);
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(destChainSelector);
+ destChainConfigArgs[0] =
+ PriceRegistry.DestChainConfigArgs({destChainSelector: destChainSelector, destChainConfig: destChainConfig});
+ destChainConfigArgs[0].destChainConfig.destDataAvailabilityOverheadGas = destDataAvailabilityOverheadGas;
+ destChainConfigArgs[0].destChainConfig.destGasPerDataAvailabilityByte = destGasPerDataAvailabilityByte;
+ destChainConfigArgs[0].destChainConfig.destDataAvailabilityMultiplierBps = destDataAvailabilityMultiplierBps;
+ destChainConfigArgs[0].destChainConfig.defaultTxGasLimit = GAS_LIMIT;
+ destChainConfigArgs[0].destChainConfig.maxPerMsgGasLimit = GAS_LIMIT;
+ destChainConfigArgs[0].destChainConfig.chainFamilySelector = Internal.CHAIN_FAMILY_SELECTOR_EVM;
+ destChainConfigArgs[0].destChainConfig.defaultTokenDestBytesOverhead = DEFAULT_TOKEN_BYTES_OVERHEAD;
+
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+
+ uint256 dataAvailabilityCostUSD = s_priceRegistry.getDataAvailabilityCost(
+ destChainConfigArgs[0].destChainSelector,
+ dataAvailabilityGasPrice,
+ messageDataLength,
+ numberOfTokens,
+ tokenTransferBytesOverhead
+ );
+
+ uint256 dataAvailabilityLengthBytes = Internal.ANY_2_EVM_MESSAGE_FIXED_BYTES + messageDataLength
+ + (numberOfTokens * Internal.ANY_2_EVM_MESSAGE_FIXED_BYTES_PER_TOKEN) + tokenTransferBytesOverhead;
+
+ uint256 dataAvailabilityGas =
+ destDataAvailabilityOverheadGas + destGasPerDataAvailabilityByte * dataAvailabilityLengthBytes;
+ uint256 expectedDataAvailabilityCostUSD =
+ dataAvailabilityGasPrice * dataAvailabilityGas * destDataAvailabilityMultiplierBps * 1e14;
+
+ assertEq(expectedDataAvailabilityCostUSD, dataAvailabilityCostUSD);
+ }
+}
+
+contract PriceRegistry_applyPremiumMultiplierWeiPerEthUpdates is PriceRegistrySetup {
+ function test_Fuzz_applyPremiumMultiplierWeiPerEthUpdates_Success(
+ PriceRegistry.PremiumMultiplierWeiPerEthArgs memory premiumMultiplierWeiPerEthArg
+ ) public {
+ PriceRegistry.PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs =
+ new PriceRegistry.PremiumMultiplierWeiPerEthArgs[](1);
+ premiumMultiplierWeiPerEthArgs[0] = premiumMultiplierWeiPerEthArg;
+
+ vm.expectEmit();
+ emit PriceRegistry.PremiumMultiplierWeiPerEthUpdated(
+ premiumMultiplierWeiPerEthArg.token, premiumMultiplierWeiPerEthArg.premiumMultiplierWeiPerEth
+ );
+
+ s_priceRegistry.applyPremiumMultiplierWeiPerEthUpdates(premiumMultiplierWeiPerEthArgs);
+
+ assertEq(
+ premiumMultiplierWeiPerEthArg.premiumMultiplierWeiPerEth,
+ s_priceRegistry.getPremiumMultiplierWeiPerEth(premiumMultiplierWeiPerEthArg.token)
+ );
+ }
+
+ function test_applyPremiumMultiplierWeiPerEthUpdatesSingleToken_Success() public {
+ PriceRegistry.PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs =
+ new PriceRegistry.PremiumMultiplierWeiPerEthArgs[](1);
+ premiumMultiplierWeiPerEthArgs[0] = s_priceRegistryPremiumMultiplierWeiPerEthArgs[0];
+ premiumMultiplierWeiPerEthArgs[0].token = vm.addr(1);
+
+ vm.expectEmit();
+ emit PriceRegistry.PremiumMultiplierWeiPerEthUpdated(
+ vm.addr(1), premiumMultiplierWeiPerEthArgs[0].premiumMultiplierWeiPerEth
+ );
+
+ s_priceRegistry.applyPremiumMultiplierWeiPerEthUpdates(premiumMultiplierWeiPerEthArgs);
+
+ assertEq(
+ s_priceRegistryPremiumMultiplierWeiPerEthArgs[0].premiumMultiplierWeiPerEth,
+ s_priceRegistry.getPremiumMultiplierWeiPerEth(vm.addr(1))
+ );
+ }
+
+ function test_applyPremiumMultiplierWeiPerEthUpdatesMultipleTokens_Success() public {
+ PriceRegistry.PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs =
+ new PriceRegistry.PremiumMultiplierWeiPerEthArgs[](2);
+ premiumMultiplierWeiPerEthArgs[0] = s_priceRegistryPremiumMultiplierWeiPerEthArgs[0];
+ premiumMultiplierWeiPerEthArgs[0].token = vm.addr(1);
+ premiumMultiplierWeiPerEthArgs[1].token = vm.addr(2);
+
+ vm.expectEmit();
+ emit PriceRegistry.PremiumMultiplierWeiPerEthUpdated(
+ vm.addr(1), premiumMultiplierWeiPerEthArgs[0].premiumMultiplierWeiPerEth
+ );
+ vm.expectEmit();
+ emit PriceRegistry.PremiumMultiplierWeiPerEthUpdated(
+ vm.addr(2), premiumMultiplierWeiPerEthArgs[1].premiumMultiplierWeiPerEth
+ );
+
+ s_priceRegistry.applyPremiumMultiplierWeiPerEthUpdates(premiumMultiplierWeiPerEthArgs);
+
+ assertEq(
+ premiumMultiplierWeiPerEthArgs[0].premiumMultiplierWeiPerEth,
+ s_priceRegistry.getPremiumMultiplierWeiPerEth(vm.addr(1))
+ );
+ assertEq(
+ premiumMultiplierWeiPerEthArgs[1].premiumMultiplierWeiPerEth,
+ s_priceRegistry.getPremiumMultiplierWeiPerEth(vm.addr(2))
+ );
+ }
+
+ function test_applyPremiumMultiplierWeiPerEthUpdatesZeroInput() public {
+ vm.recordLogs();
+ s_priceRegistry.applyPremiumMultiplierWeiPerEthUpdates(new PriceRegistry.PremiumMultiplierWeiPerEthArgs[](0));
+
+ assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ // Reverts
+
+ function test_OnlyCallableByOwnerOrAdmin_Revert() public {
+ PriceRegistry.PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs;
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert("Only callable by owner");
+
+ s_priceRegistry.applyPremiumMultiplierWeiPerEthUpdates(premiumMultiplierWeiPerEthArgs);
+ }
+}
+
+contract PriceRegistry_applyTokenTransferFeeConfigUpdates is PriceRegistrySetup {
+ function test_Fuzz_ApplyTokenTransferFeeConfig_Success(
+ PriceRegistry.TokenTransferFeeConfig[2] memory tokenTransferFeeConfigs
+ ) public {
+ PriceRegistry.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ _generateTokenTransferFeeConfigArgs(2, 2);
+ tokenTransferFeeConfigArgs[0].destChainSelector = DEST_CHAIN_SELECTOR;
+ tokenTransferFeeConfigArgs[1].destChainSelector = DEST_CHAIN_SELECTOR + 1;
+
+ for (uint256 i = 0; i < tokenTransferFeeConfigArgs.length; ++i) {
+ for (uint256 j = 0; j < tokenTransferFeeConfigs.length; ++j) {
+ tokenTransferFeeConfigs[j].destBytesOverhead = uint32(
+ bound(tokenTransferFeeConfigs[j].destBytesOverhead, Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, type(uint32).max)
+ );
+ address feeToken = s_sourceTokens[j];
+ tokenTransferFeeConfigArgs[i].tokenTransferFeeConfigs[j].token = feeToken;
+ tokenTransferFeeConfigArgs[i].tokenTransferFeeConfigs[j].tokenTransferFeeConfig = tokenTransferFeeConfigs[j];
+
+ vm.expectEmit();
+ emit PriceRegistry.TokenTransferFeeConfigUpdated(
+ tokenTransferFeeConfigArgs[i].destChainSelector, feeToken, tokenTransferFeeConfigs[j]
+ );
+ }
+ }
+
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(
+ tokenTransferFeeConfigArgs, new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](0)
+ );
+
+ for (uint256 i = 0; i < tokenTransferFeeConfigs.length; ++i) {
+ _assertTokenTransferFeeConfigEqual(
+ tokenTransferFeeConfigs[i],
+ s_priceRegistry.getTokenTransferFeeConfig(
+ tokenTransferFeeConfigArgs[0].destChainSelector,
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[i].token
+ )
+ );
+ }
+ }
+
+ function test_ApplyTokenTransferFeeConfig_Success() public {
+ PriceRegistry.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ _generateTokenTransferFeeConfigArgs(1, 2);
+ tokenTransferFeeConfigArgs[0].destChainSelector = DEST_CHAIN_SELECTOR;
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token = address(5);
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig = PriceRegistry
+ .TokenTransferFeeConfig({
+ minFeeUSDCents: 6,
+ maxFeeUSDCents: 7,
+ deciBps: 8,
+ destGasOverhead: 9,
+ destBytesOverhead: 312,
+ isEnabled: true
+ });
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].token = address(11);
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].tokenTransferFeeConfig = PriceRegistry
+ .TokenTransferFeeConfig({
+ minFeeUSDCents: 12,
+ maxFeeUSDCents: 13,
+ deciBps: 14,
+ destGasOverhead: 15,
+ destBytesOverhead: 394,
+ isEnabled: true
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.TokenTransferFeeConfigUpdated(
+ tokenTransferFeeConfigArgs[0].destChainSelector,
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token,
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig
+ );
+ vm.expectEmit();
+ emit PriceRegistry.TokenTransferFeeConfigUpdated(
+ tokenTransferFeeConfigArgs[0].destChainSelector,
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].token,
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].tokenTransferFeeConfig
+ );
+
+ PriceRegistry.TokenTransferFeeConfigRemoveArgs[] memory tokensToRemove =
+ new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](0);
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(tokenTransferFeeConfigArgs, tokensToRemove);
+
+ PriceRegistry.TokenTransferFeeConfig memory config0 = s_priceRegistry.getTokenTransferFeeConfig(
+ tokenTransferFeeConfigArgs[0].destChainSelector, tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token
+ );
+ PriceRegistry.TokenTransferFeeConfig memory config1 = s_priceRegistry.getTokenTransferFeeConfig(
+ tokenTransferFeeConfigArgs[0].destChainSelector, tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].token
+ );
+
+ _assertTokenTransferFeeConfigEqual(
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig, config0
+ );
+ _assertTokenTransferFeeConfigEqual(
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].tokenTransferFeeConfig, config1
+ );
+
+ // Remove only the first token and validate only the first token is removed
+ tokensToRemove = new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](1);
+ tokensToRemove[0] = PriceRegistry.TokenTransferFeeConfigRemoveArgs({
+ destChainSelector: tokenTransferFeeConfigArgs[0].destChainSelector,
+ token: tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token
+ });
+
+ vm.expectEmit();
+ emit PriceRegistry.TokenTransferFeeConfigDeleted(
+ tokenTransferFeeConfigArgs[0].destChainSelector, tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token
+ );
+
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(
+ new PriceRegistry.TokenTransferFeeConfigArgs[](0), tokensToRemove
+ );
+
+ config0 = s_priceRegistry.getTokenTransferFeeConfig(
+ tokenTransferFeeConfigArgs[0].destChainSelector, tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token
+ );
+ config1 = s_priceRegistry.getTokenTransferFeeConfig(
+ tokenTransferFeeConfigArgs[0].destChainSelector, tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].token
+ );
+
+ PriceRegistry.TokenTransferFeeConfig memory emptyConfig;
+
+ _assertTokenTransferFeeConfigEqual(emptyConfig, config0);
+ _assertTokenTransferFeeConfigEqual(
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].tokenTransferFeeConfig, config1
+ );
+ }
+
+ function test_ApplyTokenTransferFeeZeroInput() public {
+ vm.recordLogs();
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(
+ new PriceRegistry.TokenTransferFeeConfigArgs[](0), new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](0)
+ );
+
+ assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ // Reverts
+
+ function test_OnlyCallableByOwnerOrAdmin_Revert() public {
+ vm.startPrank(STRANGER);
+ PriceRegistry.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs;
+
+ vm.expectRevert("Only callable by owner");
+
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(
+ tokenTransferFeeConfigArgs, new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](0)
+ );
+ }
+
+ function test_InvalidDestBytesOverhead_Revert() public {
+ PriceRegistry.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ _generateTokenTransferFeeConfigArgs(1, 1);
+ tokenTransferFeeConfigArgs[0].destChainSelector = DEST_CHAIN_SELECTOR;
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token = address(5);
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig = PriceRegistry
+ .TokenTransferFeeConfig({
+ minFeeUSDCents: 6,
+ maxFeeUSDCents: 7,
+ deciBps: 8,
+ destGasOverhead: 9,
+ destBytesOverhead: uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES - 1),
+ isEnabled: true
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ PriceRegistry.InvalidDestBytesOverhead.selector,
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token,
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig.destBytesOverhead
+ )
+ );
+
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(
+ tokenTransferFeeConfigArgs, new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](0)
+ );
+ }
+}
+
+contract PriceRegistry_getTokenTransferCost is PriceRegistryFeeSetup {
+ using USDPriceWith18Decimals for uint224;
+
+ function test_NoTokenTransferChargesZeroFee_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ assertEq(0, feeUSDWei);
+ assertEq(0, destGasOverhead);
+ assertEq(0, destBytesOverhead);
+ }
+
+ function test_getTokenTransferCost_selfServeUsesDefaults_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_selfServeTokenDefaultPricing, 1000);
+
+ // Get config to assert it isn't set
+ PriceRegistry.TokenTransferFeeConfig memory transferFeeConfig =
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token);
+
+ assertFalse(transferFeeConfig.isEnabled);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ // Assert that the default values are used
+ assertEq(uint256(DEFAULT_TOKEN_FEE_USD_CENTS) * 1e16, feeUSDWei);
+ assertEq(DEFAULT_TOKEN_DEST_GAS_OVERHEAD, destGasOverhead);
+ assertEq(DEFAULT_TOKEN_BYTES_OVERHEAD, destBytesOverhead);
+ }
+
+ function test_SmallTokenTransferChargesMinFeeAndGas_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, 1000);
+ PriceRegistry.TokenTransferFeeConfig memory transferFeeConfig =
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ assertEq(configUSDCentToWei(transferFeeConfig.minFeeUSDCents), feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(transferFeeConfig.destBytesOverhead, destBytesOverhead);
+ }
+
+ function test_ZeroAmountTokenTransferChargesMinFeeAndGas_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, 0);
+ PriceRegistry.TokenTransferFeeConfig memory transferFeeConfig =
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ assertEq(configUSDCentToWei(transferFeeConfig.minFeeUSDCents), feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(transferFeeConfig.destBytesOverhead, destBytesOverhead);
+ }
+
+ function test_LargeTokenTransferChargesMaxFeeAndGas_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, 1e36);
+ PriceRegistry.TokenTransferFeeConfig memory transferFeeConfig =
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ assertEq(configUSDCentToWei(transferFeeConfig.maxFeeUSDCents), feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(transferFeeConfig.destBytesOverhead, destBytesOverhead);
+ }
+
+ function test_FeeTokenBpsFee_Success() public view {
+ uint256 tokenAmount = 10000e18;
+
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, tokenAmount);
+ PriceRegistry.TokenTransferFeeConfig memory transferFeeConfig =
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ uint256 usdWei = calcUSDValueFromTokenAmount(s_feeTokenPrice, tokenAmount);
+ uint256 bpsUSDWei = applyBpsRatio(
+ usdWei, s_priceRegistryTokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig.deciBps
+ );
+
+ assertEq(bpsUSDWei, feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(transferFeeConfig.destBytesOverhead, destBytesOverhead);
+ }
+
+ function test_WETHTokenBpsFee_Success() public view {
+ uint256 tokenAmount = 100e18;
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](1),
+ feeToken: s_sourceRouter.getWrappedNative(),
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ message.tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceRouter.getWrappedNative(), amount: tokenAmount});
+
+ PriceRegistry.TokenTransferFeeConfig memory transferFeeConfig =
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) = s_priceRegistry.getTokenTransferCost(
+ DEST_CHAIN_SELECTOR, message.feeToken, s_wrappedTokenPrice, message.tokenAmounts
+ );
+
+ uint256 usdWei = calcUSDValueFromTokenAmount(s_wrappedTokenPrice, tokenAmount);
+ uint256 bpsUSDWei = applyBpsRatio(
+ usdWei, s_priceRegistryTokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[1].tokenTransferFeeConfig.deciBps
+ );
+
+ assertEq(bpsUSDWei, feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(transferFeeConfig.destBytesOverhead, destBytesOverhead);
+ }
+
+ function test_CustomTokenBpsFee_Success() public view {
+ uint256 tokenAmount = 200000e18;
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](1),
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ message.tokenAmounts[0] = Client.EVMTokenAmount({token: CUSTOM_TOKEN, amount: tokenAmount});
+
+ PriceRegistry.TokenTransferFeeConfig memory transferFeeConfig =
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token);
+
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ uint256 usdWei = calcUSDValueFromTokenAmount(s_customTokenPrice, tokenAmount);
+ uint256 bpsUSDWei = applyBpsRatio(
+ usdWei, s_priceRegistryTokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[2].tokenTransferFeeConfig.deciBps
+ );
+
+ assertEq(bpsUSDWei, feeUSDWei);
+ assertEq(transferFeeConfig.destGasOverhead, destGasOverhead);
+ assertEq(transferFeeConfig.destBytesOverhead, destBytesOverhead);
+ }
+
+ function test_ZeroFeeConfigChargesMinFee_Success() public {
+ PriceRegistry.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ _generateTokenTransferFeeConfigArgs(1, 1);
+ tokenTransferFeeConfigArgs[0].destChainSelector = DEST_CHAIN_SELECTOR;
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token = s_sourceFeeToken;
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig = PriceRegistry
+ .TokenTransferFeeConfig({
+ minFeeUSDCents: 1,
+ maxFeeUSDCents: 0,
+ deciBps: 0,
+ destGasOverhead: 0,
+ destBytesOverhead: uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES),
+ isEnabled: true
+ });
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(
+ tokenTransferFeeConfigArgs, new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](0)
+ );
+
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, 1e36);
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, s_feeTokenPrice, message.tokenAmounts);
+
+ // if token charges 0 bps, it should cost minFee to transfer
+ assertEq(
+ configUSDCentToWei(tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig.minFeeUSDCents),
+ feeUSDWei
+ );
+ assertEq(0, destGasOverhead);
+ assertEq(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, destBytesOverhead);
+ }
+
+ function test_Fuzz_TokenTransferFeeDuplicateTokens_Success(uint256 transfers, uint256 amount) public view {
+ // It shouldn't be possible to pay materially lower fees by splitting up the transfers.
+ // Note it is possible to pay higher fees since the minimum fees are added.
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+ transfers = bound(transfers, 1, destChainConfig.maxNumberOfTokensPerMsg);
+ // Cap amount to avoid overflow
+ amount = bound(amount, 0, 1e36);
+ Client.EVMTokenAmount[] memory multiple = new Client.EVMTokenAmount[](transfers);
+ for (uint256 i = 0; i < transfers; ++i) {
+ multiple[i] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: amount});
+ }
+ Client.EVMTokenAmount[] memory single = new Client.EVMTokenAmount[](1);
+ single[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: amount * transfers});
+
+ address feeToken = s_sourceRouter.getWrappedNative();
+
+ (uint256 feeSingleUSDWei, uint32 gasOverheadSingle, uint32 bytesOverheadSingle) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, feeToken, s_wrappedTokenPrice, single);
+ (uint256 feeMultipleUSDWei, uint32 gasOverheadMultiple, uint32 bytesOverheadMultiple) =
+ s_priceRegistry.getTokenTransferCost(DEST_CHAIN_SELECTOR, feeToken, s_wrappedTokenPrice, multiple);
+
+ // Note that there can be a rounding error once per split.
+ assertGe(feeMultipleUSDWei, (feeSingleUSDWei - destChainConfig.maxNumberOfTokensPerMsg));
+ assertEq(gasOverheadMultiple, gasOverheadSingle * transfers);
+ assertEq(bytesOverheadMultiple, bytesOverheadSingle * transfers);
+ }
+
+ function test_MixedTokenTransferFee_Success() public view {
+ address[3] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative(), CUSTOM_TOKEN];
+ uint224[3] memory tokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice, s_customTokenPrice];
+ PriceRegistry.TokenTransferFeeConfig[3] memory tokenTransferFeeConfigs = [
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, testTokens[0]),
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, testTokens[1]),
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, testTokens[2])
+ ];
+
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](3),
+ feeToken: s_sourceRouter.getWrappedNative(),
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ uint256 expectedTotalGas = 0;
+ uint256 expectedTotalBytes = 0;
+
+ // Start with small token transfers, total bps fee is lower than min token transfer fee
+ for (uint256 i = 0; i < testTokens.length; ++i) {
+ message.tokenAmounts[i] = Client.EVMTokenAmount({token: testTokens[i], amount: 1e14});
+ expectedTotalGas += s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, testTokens[i]).destGasOverhead;
+ expectedTotalBytes +=
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, testTokens[i]).destBytesOverhead;
+ }
+ (uint256 feeUSDWei, uint32 destGasOverhead, uint32 destBytesOverhead) = s_priceRegistry.getTokenTransferCost(
+ DEST_CHAIN_SELECTOR, message.feeToken, s_wrappedTokenPrice, message.tokenAmounts
+ );
+
+ uint256 expectedFeeUSDWei = 0;
+ for (uint256 i = 0; i < testTokens.length; ++i) {
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[i].minFeeUSDCents);
+ }
+
+ assertEq(expectedFeeUSDWei, feeUSDWei);
+ assertEq(expectedTotalGas, destGasOverhead);
+ assertEq(expectedTotalBytes, destBytesOverhead);
+
+ // Set 1st token transfer to a meaningful amount so its bps fee is now between min and max fee
+ message.tokenAmounts[0] = Client.EVMTokenAmount({token: testTokens[0], amount: 10000e18});
+
+ (feeUSDWei, destGasOverhead, destBytesOverhead) = s_priceRegistry.getTokenTransferCost(
+ DEST_CHAIN_SELECTOR, message.feeToken, s_wrappedTokenPrice, message.tokenAmounts
+ );
+ expectedFeeUSDWei = applyBpsRatio(
+ calcUSDValueFromTokenAmount(tokenPrices[0], message.tokenAmounts[0].amount), tokenTransferFeeConfigs[0].deciBps
+ );
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[1].minFeeUSDCents);
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[2].minFeeUSDCents);
+
+ assertEq(expectedFeeUSDWei, feeUSDWei);
+ assertEq(expectedTotalGas, destGasOverhead);
+ assertEq(expectedTotalBytes, destBytesOverhead);
+
+ // Set 2nd token transfer to a large amount that is higher than maxFeeUSD
+ message.tokenAmounts[1] = Client.EVMTokenAmount({token: testTokens[1], amount: 1e36});
+
+ (feeUSDWei, destGasOverhead, destBytesOverhead) = s_priceRegistry.getTokenTransferCost(
+ DEST_CHAIN_SELECTOR, message.feeToken, s_wrappedTokenPrice, message.tokenAmounts
+ );
+ expectedFeeUSDWei = applyBpsRatio(
+ calcUSDValueFromTokenAmount(tokenPrices[0], message.tokenAmounts[0].amount), tokenTransferFeeConfigs[0].deciBps
+ );
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[1].maxFeeUSDCents);
+ expectedFeeUSDWei += configUSDCentToWei(tokenTransferFeeConfigs[2].minFeeUSDCents);
+
+ assertEq(expectedFeeUSDWei, feeUSDWei);
+ assertEq(expectedTotalGas, destGasOverhead);
+ assertEq(expectedTotalBytes, destBytesOverhead);
+ }
+}
+
+contract PriceRegistry_getValidatedFee is PriceRegistryFeeSetup {
+ using USDPriceWith18Decimals for uint224;
+
+ function test_EmptyMessage_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = testTokens[i];
+ uint64 premiumMultiplierWeiPerEth = s_priceRegistry.getPremiumMultiplierWeiPerEth(message.feeToken);
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+
+ uint256 feeAmount = s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+
+ uint256 gasUsed = GAS_LIMIT + DEST_GAS_OVERHEAD;
+ uint256 gasFeeUSD = (gasUsed * destChainConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ uint256 messageFeeUSD = (configUSDCentToWei(destChainConfig.networkFeeUSDCents) * premiumMultiplierWeiPerEth);
+ uint256 dataAvailabilityFeeUSD = s_priceRegistry.getDataAvailabilityCost(
+ DEST_CHAIN_SELECTOR, USD_PER_DATA_AVAILABILITY_GAS, message.data.length, message.tokenAmounts.length, 0
+ );
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD + dataAvailabilityFeeUSD) / feeTokenPrices[i];
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+ }
+
+ function test_ZeroDataAvailabilityMultiplier_Success() public {
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = new PriceRegistry.DestChainConfigArgs[](1);
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+ destChainConfigArgs[0] =
+ PriceRegistry.DestChainConfigArgs({destChainSelector: DEST_CHAIN_SELECTOR, destChainConfig: destChainConfig});
+ destChainConfigArgs[0].destChainConfig.destDataAvailabilityMultiplierBps = 0;
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ uint64 premiumMultiplierWeiPerEth = s_priceRegistry.getPremiumMultiplierWeiPerEth(message.feeToken);
+
+ uint256 feeAmount = s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+
+ uint256 gasUsed = GAS_LIMIT + DEST_GAS_OVERHEAD;
+ uint256 gasFeeUSD = (gasUsed * destChainConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ uint256 messageFeeUSD = (configUSDCentToWei(destChainConfig.networkFeeUSDCents) * premiumMultiplierWeiPerEth);
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD) / s_feeTokenPrice;
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+
+ function test_HighGasMessage_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ uint256 customGasLimit = MAX_GAS_LIMIT;
+ uint256 customDataSize = MAX_DATA_SIZE;
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: new bytes(customDataSize),
+ tokenAmounts: new Client.EVMTokenAmount[](0),
+ feeToken: testTokens[i],
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: customGasLimit}))
+ });
+
+ uint64 premiumMultiplierWeiPerEth = s_priceRegistry.getPremiumMultiplierWeiPerEth(message.feeToken);
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+
+ uint256 feeAmount = s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+ uint256 gasUsed = customGasLimit + DEST_GAS_OVERHEAD + customDataSize * DEST_GAS_PER_PAYLOAD_BYTE;
+ uint256 gasFeeUSD = (gasUsed * destChainConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ uint256 messageFeeUSD = (configUSDCentToWei(destChainConfig.networkFeeUSDCents) * premiumMultiplierWeiPerEth);
+ uint256 dataAvailabilityFeeUSD = s_priceRegistry.getDataAvailabilityCost(
+ DEST_CHAIN_SELECTOR, USD_PER_DATA_AVAILABILITY_GAS, message.data.length, message.tokenAmounts.length, 0
+ );
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD + dataAvailabilityFeeUSD) / feeTokenPrices[i];
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+ }
+
+ function test_SingleTokenMessage_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ uint256 tokenAmount = 10000e18;
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(s_sourceFeeToken, tokenAmount);
+ message.feeToken = testTokens[i];
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+ uint32 destBytesOverhead =
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token).destBytesOverhead;
+ uint32 tokenBytesOverhead =
+ destBytesOverhead == 0 ? uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) : destBytesOverhead;
+
+ uint256 feeAmount = s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+
+ uint256 gasUsed = GAS_LIMIT + DEST_GAS_OVERHEAD
+ + s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token).destGasOverhead;
+ uint256 gasFeeUSD = (gasUsed * destChainConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ (uint256 transferFeeUSD,,) = s_priceRegistry.getTokenTransferCost(
+ DEST_CHAIN_SELECTOR, message.feeToken, feeTokenPrices[i], message.tokenAmounts
+ );
+ uint256 messageFeeUSD = (transferFeeUSD * s_priceRegistry.getPremiumMultiplierWeiPerEth(message.feeToken));
+ uint256 dataAvailabilityFeeUSD = s_priceRegistry.getDataAvailabilityCost(
+ DEST_CHAIN_SELECTOR,
+ USD_PER_DATA_AVAILABILITY_GAS,
+ message.data.length,
+ message.tokenAmounts.length,
+ tokenBytesOverhead
+ );
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD + dataAvailabilityFeeUSD) / feeTokenPrices[i];
+ assertEq(totalPriceInFeeToken, feeAmount);
+ }
+ }
+
+ function test_MessageWithDataAndTokenTransfer_Success() public view {
+ address[2] memory testTokens = [s_sourceFeeToken, s_sourceRouter.getWrappedNative()];
+ uint224[2] memory feeTokenPrices = [s_feeTokenPrice, s_wrappedTokenPrice];
+
+ uint256 customGasLimit = 1_000_000;
+ for (uint256 i = 0; i < feeTokenPrices.length; ++i) {
+ Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: new Client.EVMTokenAmount[](2),
+ feeToken: testTokens[i],
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: customGasLimit}))
+ });
+ uint64 premiumMultiplierWeiPerEth = s_priceRegistry.getPremiumMultiplierWeiPerEth(message.feeToken);
+ PriceRegistry.DestChainConfig memory destChainConfig = s_priceRegistry.getDestChainConfig(DEST_CHAIN_SELECTOR);
+
+ message.tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceFeeToken, amount: 10000e18}); // feeTokenAmount
+ message.tokenAmounts[1] = Client.EVMTokenAmount({token: CUSTOM_TOKEN, amount: 200000e18}); // customTokenAmount
+ message.data = "random bits and bytes that should be factored into the cost of the message";
+
+ uint32 tokenGasOverhead = 0;
+ uint32 tokenBytesOverhead = 0;
+ for (uint256 j = 0; j < message.tokenAmounts.length; ++j) {
+ tokenGasOverhead +=
+ s_priceRegistry.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[j].token).destGasOverhead;
+ uint32 destBytesOverhead = s_priceRegistry.getTokenTransferFeeConfig(
+ DEST_CHAIN_SELECTOR, message.tokenAmounts[j].token
+ ).destBytesOverhead;
+ tokenBytesOverhead += destBytesOverhead == 0 ? uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) : destBytesOverhead;
+ }
+
+ uint256 gasUsed =
+ customGasLimit + DEST_GAS_OVERHEAD + message.data.length * DEST_GAS_PER_PAYLOAD_BYTE + tokenGasOverhead;
+ uint256 gasFeeUSD = (gasUsed * destChainConfig.gasMultiplierWeiPerEth * USD_PER_GAS);
+ (uint256 transferFeeUSD,,) = s_priceRegistry.getTokenTransferCost(
+ DEST_CHAIN_SELECTOR, message.feeToken, feeTokenPrices[i], message.tokenAmounts
+ );
+ uint256 messageFeeUSD = (transferFeeUSD * premiumMultiplierWeiPerEth);
+ uint256 dataAvailabilityFeeUSD = s_priceRegistry.getDataAvailabilityCost(
+ DEST_CHAIN_SELECTOR,
+ USD_PER_DATA_AVAILABILITY_GAS,
+ message.data.length,
+ message.tokenAmounts.length,
+ tokenBytesOverhead
+ );
+
+ uint256 totalPriceInFeeToken = (gasFeeUSD + messageFeeUSD + dataAvailabilityFeeUSD) / feeTokenPrices[i];
+ assertEq(totalPriceInFeeToken, s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message));
+ }
+ }
+
+ function test_Fuzz_EnforceOutOfOrder(bool enforce, bool allowOutOfOrderExecution) public {
+ // Update config to enforce allowOutOfOrderExecution = defaultVal.
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ destChainConfigArgs[0].destChainConfig.enforceOutOfOrder = enforce;
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = abi.encodeWithSelector(
+ Client.EVM_EXTRA_ARGS_V2_TAG,
+ Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT * 2, allowOutOfOrderExecution: allowOutOfOrderExecution})
+ );
+
+ // If enforcement is on, only true should be allowed.
+ if (enforce && !allowOutOfOrderExecution) {
+ vm.expectRevert(PriceRegistry.ExtraArgOutOfOrderExecutionMustBeTrue.selector);
+ }
+ s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ // Reverts
+
+ function test_DestinationChainNotEnabled_Revert() public {
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.DestinationChainNotEnabled.selector, DEST_CHAIN_SELECTOR + 1));
+ s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR + 1, _generateEmptyMessage());
+ }
+
+ function test_EnforceOutOfOrder_Revert() public {
+ // Update config to enforce allowOutOfOrderExecution = true.
+ vm.stopPrank();
+ vm.startPrank(OWNER);
+
+ PriceRegistry.DestChainConfigArgs[] memory destChainConfigArgs = _generatePriceRegistryDestChainConfigArgs();
+ destChainConfigArgs[0].destChainConfig.enforceOutOfOrder = true;
+ s_priceRegistry.applyDestChainConfigUpdates(destChainConfigArgs);
+ vm.stopPrank();
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ // Empty extraArgs to should revert since it enforceOutOfOrder is true.
+ message.extraArgs = "";
+
+ vm.expectRevert(PriceRegistry.ExtraArgOutOfOrderExecutionMustBeTrue.selector);
+ s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_MessageTooLarge_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.data = new bytes(MAX_DATA_SIZE + 1);
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.MessageTooLarge.selector, MAX_DATA_SIZE, message.data.length));
+
+ s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_TooManyTokens_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ uint256 tooMany = MAX_TOKENS_LENGTH + 1;
+ message.tokenAmounts = new Client.EVMTokenAmount[](tooMany);
+ vm.expectRevert(PriceRegistry.UnsupportedNumberOfTokens.selector);
+ s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ // Asserts gasLimit must be <=maxGasLimit
+ function test_MessageGasLimitTooHigh_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: MAX_GAS_LIMIT + 1}));
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.MessageGasLimitTooHigh.selector));
+ s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_NotAFeeToken_Revert() public {
+ address notAFeeToken = address(0x111111);
+ Client.EVM2AnyMessage memory message = _generateSingleTokenMessage(notAFeeToken, 1);
+ message.feeToken = notAFeeToken;
+
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.TokenNotSupported.selector, notAFeeToken));
+
+ s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_InvalidEVMAddress_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.receiver = abi.encode(type(uint208).max);
+
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, message.receiver));
+
+ s_priceRegistry.getValidatedFee(DEST_CHAIN_SELECTOR, message);
+ }
+}
+
+contract PriceRegistry_processMessageArgs is PriceRegistryFeeSetup {
+ using USDPriceWith18Decimals for uint224;
+
+ function setUp() public virtual override {
+ super.setUp();
+ }
+
+ function test_WithLinkTokenAmount_Success() public view {
+ (
+ uint256 msgFeeJuels,
+ /* bool isOutOfOrderExecution */
+ ,
+ /* bytes memory convertedExtraArgs */
+ ) = s_priceRegistry.processMessageArgs(
+ DEST_CHAIN_SELECTOR,
+ // LINK
+ s_sourceTokens[0],
+ MAX_MSG_FEES_JUELS,
+ ""
+ );
+
+ assertEq(msgFeeJuels, MAX_MSG_FEES_JUELS);
+ }
+
+ function test_WithConvertedTokenAmount_Success() public view {
+ address feeToken = s_sourceTokens[1];
+ uint256 feeTokenAmount = 10_000 gwei;
+ uint256 expectedConvertedAmount = s_priceRegistry.convertTokenAmount(feeToken, feeTokenAmount, s_sourceTokens[0]);
+
+ (
+ uint256 msgFeeJuels,
+ /* bool isOutOfOrderExecution */
+ ,
+ /* bytes memory convertedExtraArgs */
+ ) = s_priceRegistry.processMessageArgs(DEST_CHAIN_SELECTOR, feeToken, feeTokenAmount, "");
+
+ assertEq(msgFeeJuels, expectedConvertedAmount);
+ }
+
+ function test_WithEmptyEVMExtraArgs_Success() public view {
+ (
+ /* uint256 msgFeeJuels */
+ ,
+ bool isOutOfOrderExecution,
+ bytes memory convertedExtraArgs
+ ) = s_priceRegistry.processMessageArgs(DEST_CHAIN_SELECTOR, s_sourceTokens[0], 0, "");
+
+ assertEq(isOutOfOrderExecution, false);
+ assertEq(
+ convertedExtraArgs, Client._argsToBytes(s_priceRegistry.parseEVMExtraArgsFromBytes("", DEST_CHAIN_SELECTOR))
+ );
+ }
+
+ function test_WithEVMExtraArgsV1_Success() public view {
+ bytes memory extraArgs = Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 1000}));
+
+ (
+ /* uint256 msgFeeJuels */
+ ,
+ bool isOutOfOrderExecution,
+ bytes memory convertedExtraArgs
+ ) = s_priceRegistry.processMessageArgs(DEST_CHAIN_SELECTOR, s_sourceTokens[0], 0, extraArgs);
+
+ assertEq(isOutOfOrderExecution, false);
+ assertEq(
+ convertedExtraArgs,
+ Client._argsToBytes(s_priceRegistry.parseEVMExtraArgsFromBytes(extraArgs, DEST_CHAIN_SELECTOR))
+ );
+ }
+
+ function test_WitEVMExtraArgsV2_Success() public view {
+ bytes memory extraArgs = Client._argsToBytes(Client.EVMExtraArgsV2({gasLimit: 0, allowOutOfOrderExecution: true}));
+
+ (
+ /* uint256 msgFeeJuels */
+ ,
+ bool isOutOfOrderExecution,
+ bytes memory convertedExtraArgs
+ ) = s_priceRegistry.processMessageArgs(DEST_CHAIN_SELECTOR, s_sourceTokens[0], 0, extraArgs);
+
+ assertEq(isOutOfOrderExecution, true);
+ assertEq(
+ convertedExtraArgs,
+ Client._argsToBytes(s_priceRegistry.parseEVMExtraArgsFromBytes(extraArgs, DEST_CHAIN_SELECTOR))
+ );
+ }
+
+ // Reverts
+
+ function test_MessageFeeTooHigh_Revert() public {
+ vm.expectRevert(
+ abi.encodeWithSelector(PriceRegistry.MessageFeeTooHigh.selector, MAX_MSG_FEES_JUELS + 1, MAX_MSG_FEES_JUELS)
+ );
+
+ s_priceRegistry.processMessageArgs(DEST_CHAIN_SELECTOR, s_sourceTokens[0], MAX_MSG_FEES_JUELS + 1, "");
+ }
+
+ function test_InvalidExtraArgs_Revert() public {
+ vm.expectRevert(PriceRegistry.InvalidExtraArgsTag.selector);
+
+ s_priceRegistry.processMessageArgs(DEST_CHAIN_SELECTOR, s_sourceTokens[0], 0, "abcde");
+ }
+
+ function test_MalformedEVMExtraArgs_Revert() public {
+ // abi.decode error
+ vm.expectRevert();
+
+ s_priceRegistry.processMessageArgs(
+ DEST_CHAIN_SELECTOR,
+ s_sourceTokens[0],
+ 0,
+ abi.encodeWithSelector(Client.EVM_EXTRA_ARGS_V2_TAG, Client.EVMExtraArgsV1({gasLimit: 100}))
+ );
+ }
+}
+
+contract PriceRegistry_validatePoolReturnData is PriceRegistryFeeSetup {
+ function test_WithSingleToken_Success() public view {
+ Client.EVMTokenAmount[] memory sourceTokenAmounts = new Client.EVMTokenAmount[](1);
+ sourceTokenAmounts[0].amount = 1e18;
+ sourceTokenAmounts[0].token = s_sourceTokens[0];
+
+ Internal.RampTokenAmount[] memory rampTokenAmounts = new Internal.RampTokenAmount[](1);
+ rampTokenAmounts[0] = _getSourceTokenData(sourceTokenAmounts[0], s_tokenAdminRegistry);
+
+ // No revert - successful
+ s_priceRegistry.validatePoolReturnData(DEST_CHAIN_SELECTOR, rampTokenAmounts, sourceTokenAmounts);
+ }
+
+ function test_TokenAmountArraysMismatching_Revert() public {
+ Client.EVMTokenAmount[] memory sourceTokenAmounts = new Client.EVMTokenAmount[](1);
+ sourceTokenAmounts[0].amount = 1e18;
+ sourceTokenAmounts[0].token = s_sourceTokens[0];
+
+ Internal.RampTokenAmount[] memory rampTokenAmounts = new Internal.RampTokenAmount[](1);
+ rampTokenAmounts[0] = _getSourceTokenData(sourceTokenAmounts[0], s_tokenAdminRegistry);
+
+ // Revert due to index out of bounds access
+ vm.expectRevert();
+
+ s_priceRegistry.validatePoolReturnData(
+ DEST_CHAIN_SELECTOR, new Internal.RampTokenAmount[](1), new Client.EVMTokenAmount[](0)
+ );
+ }
+
+ function test_SourceTokenDataTooLarge_Revert() public {
+ address sourceETH = s_sourceTokens[1];
+
+ Client.EVMTokenAmount[] memory sourceTokenAmounts = new Client.EVMTokenAmount[](1);
+ sourceTokenAmounts[0].amount = 1000;
+ sourceTokenAmounts[0].token = sourceETH;
+
+ Internal.RampTokenAmount[] memory rampTokenAmounts = new Internal.RampTokenAmount[](1);
+ rampTokenAmounts[0] = _getSourceTokenData(sourceTokenAmounts[0], s_tokenAdminRegistry);
+
+ // No data set, should succeed
+ s_priceRegistry.validatePoolReturnData(DEST_CHAIN_SELECTOR, rampTokenAmounts, sourceTokenAmounts);
+
+ // Set max data length, should succeed
+ rampTokenAmounts[0].extraData = new bytes(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES);
+ s_priceRegistry.validatePoolReturnData(DEST_CHAIN_SELECTOR, rampTokenAmounts, sourceTokenAmounts);
+
+ // Set data to max length +1, should revert
+ rampTokenAmounts[0].extraData = new bytes(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES + 1);
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.SourceTokenDataTooLarge.selector, sourceETH));
+ s_priceRegistry.validatePoolReturnData(DEST_CHAIN_SELECTOR, rampTokenAmounts, sourceTokenAmounts);
+
+ // Set token config to allow larger data
+ PriceRegistry.TokenTransferFeeConfigArgs[] memory tokenTransferFeeConfigArgs =
+ _generateTokenTransferFeeConfigArgs(1, 1);
+ tokenTransferFeeConfigArgs[0].destChainSelector = DEST_CHAIN_SELECTOR;
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].token = sourceETH;
+ tokenTransferFeeConfigArgs[0].tokenTransferFeeConfigs[0].tokenTransferFeeConfig = PriceRegistry
+ .TokenTransferFeeConfig({
+ minFeeUSDCents: 1,
+ maxFeeUSDCents: 0,
+ deciBps: 0,
+ destGasOverhead: 0,
+ destBytesOverhead: uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) + 32,
+ isEnabled: true
+ });
+ s_priceRegistry.applyTokenTransferFeeConfigUpdates(
+ tokenTransferFeeConfigArgs, new PriceRegistry.TokenTransferFeeConfigRemoveArgs[](0)
+ );
+
+ s_priceRegistry.validatePoolReturnData(DEST_CHAIN_SELECTOR, rampTokenAmounts, sourceTokenAmounts);
+
+ // Set the token data larger than the configured token data, should revert
+ rampTokenAmounts[0].extraData = new bytes(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES + 32 + 1);
+
+ vm.expectRevert(abi.encodeWithSelector(PriceRegistry.SourceTokenDataTooLarge.selector, sourceETH));
+ s_priceRegistry.validatePoolReturnData(DEST_CHAIN_SELECTOR, rampTokenAmounts, sourceTokenAmounts);
+ }
+
+ function test_InvalidEVMAddressDestToken_Revert() public {
+ bytes memory nonEvmAddress = abi.encode(type(uint208).max);
+
+ Client.EVMTokenAmount[] memory sourceTokenAmounts = new Client.EVMTokenAmount[](1);
+ sourceTokenAmounts[0].amount = 1e18;
+ sourceTokenAmounts[0].token = s_sourceTokens[0];
+
+ Internal.RampTokenAmount[] memory rampTokenAmounts = new Internal.RampTokenAmount[](1);
+ rampTokenAmounts[0] = _getSourceTokenData(sourceTokenAmounts[0], s_tokenAdminRegistry);
+ rampTokenAmounts[0].destTokenAddress = nonEvmAddress;
+
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, nonEvmAddress));
+ s_priceRegistry.validatePoolReturnData(DEST_CHAIN_SELECTOR, rampTokenAmounts, sourceTokenAmounts);
+ }
+}
+
+contract PriceRegistry_validateDestFamilyAddress is PriceRegistrySetup {
+ function test_ValidEVMAddress_Success() public view {
+ bytes memory encodedAddress = abi.encode(address(10000));
+ s_priceRegistry.validateDestFamilyAddress(Internal.CHAIN_FAMILY_SELECTOR_EVM, encodedAddress);
+ }
+
+ function test_ValidNonEVMAddress_Success() public view {
+ s_priceRegistry.validateDestFamilyAddress(bytes4(uint32(1)), abi.encode(type(uint208).max));
+ }
+
+ // Reverts
+
+ function test_InvalidEVMAddress_Revert() public {
+ bytes memory invalidAddress = abi.encode(type(uint208).max);
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, invalidAddress));
+ s_priceRegistry.validateDestFamilyAddress(Internal.CHAIN_FAMILY_SELECTOR_EVM, invalidAddress);
+ }
+
+ function test_InvalidEVMAddressEncodePacked_Revert() public {
+ bytes memory invalidAddress = abi.encodePacked(address(234));
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, invalidAddress));
+ s_priceRegistry.validateDestFamilyAddress(Internal.CHAIN_FAMILY_SELECTOR_EVM, invalidAddress);
+ }
+
+ function test_InvalidEVMAddressPrecompiles_Revert() public {
+ for (uint160 i = 0; i < Internal.PRECOMPILE_SPACE; ++i) {
+ bytes memory invalidAddress = abi.encode(address(i));
+ vm.expectRevert(abi.encodeWithSelector(Internal.InvalidEVMAddress.selector, invalidAddress));
+ s_priceRegistry.validateDestFamilyAddress(Internal.CHAIN_FAMILY_SELECTOR_EVM, invalidAddress);
+ }
+
+ s_priceRegistry.validateDestFamilyAddress(
+ Internal.CHAIN_FAMILY_SELECTOR_EVM, abi.encode(address(uint160(Internal.PRECOMPILE_SPACE)))
+ );
+ }
+}
+
+contract PriceRegistry_parseEVMExtraArgsFromBytes is PriceRegistrySetup {
+ PriceRegistry.DestChainConfig private s_destChainConfig;
+
+ function setUp() public virtual override {
+ super.setUp();
+ s_destChainConfig = _generatePriceRegistryDestChainConfigArgs()[0].destChainConfig;
+ }
+
+ function test_EVMExtraArgsV1_Success() public view {
+ Client.EVMExtraArgsV1 memory inputArgs = Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT});
+ bytes memory inputExtraArgs = Client._argsToBytes(inputArgs);
+ Client.EVMExtraArgsV2 memory expectedOutputArgs =
+ Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT, allowOutOfOrderExecution: false});
+
+ vm.assertEq(
+ abi.encode(s_priceRegistry.parseEVMExtraArgsFromBytes(inputExtraArgs, s_destChainConfig)),
+ abi.encode(expectedOutputArgs)
+ );
+ }
+
+ function test_EVMExtraArgsV2_Success() public view {
+ Client.EVMExtraArgsV2 memory inputArgs =
+ Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT, allowOutOfOrderExecution: true});
+ bytes memory inputExtraArgs = Client._argsToBytes(inputArgs);
+
+ vm.assertEq(
+ abi.encode(s_priceRegistry.parseEVMExtraArgsFromBytes(inputExtraArgs, s_destChainConfig)), abi.encode(inputArgs)
+ );
+ }
+
+ function test_EVMExtraArgsDefault_Success() public view {
+ Client.EVMExtraArgsV2 memory expectedOutputArgs =
+ Client.EVMExtraArgsV2({gasLimit: s_destChainConfig.defaultTxGasLimit, allowOutOfOrderExecution: false});
+
+ vm.assertEq(
+ abi.encode(s_priceRegistry.parseEVMExtraArgsFromBytes("", s_destChainConfig)), abi.encode(expectedOutputArgs)
+ );
+ }
+
+ // Reverts
+
+ function test_EVMExtraArgsInvalidExtraArgsTag_Revert() public {
+ Client.EVMExtraArgsV2 memory inputArgs =
+ Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT, allowOutOfOrderExecution: true});
+ bytes memory inputExtraArgs = Client._argsToBytes(inputArgs);
+ // Invalidate selector
+ inputExtraArgs[0] = bytes1(uint8(0));
+
+ vm.expectRevert(PriceRegistry.InvalidExtraArgsTag.selector);
+ s_priceRegistry.parseEVMExtraArgsFromBytes(inputExtraArgs, s_destChainConfig);
+ }
+
+ function test_EVMExtraArgsEnforceOutOfOrder_Revert() public {
+ Client.EVMExtraArgsV2 memory inputArgs =
+ Client.EVMExtraArgsV2({gasLimit: GAS_LIMIT, allowOutOfOrderExecution: false});
+ bytes memory inputExtraArgs = Client._argsToBytes(inputArgs);
+ s_destChainConfig.enforceOutOfOrder = true;
+
+ vm.expectRevert(PriceRegistry.ExtraArgOutOfOrderExecutionMustBeTrue.selector);
+ s_priceRegistry.parseEVMExtraArgsFromBytes(inputExtraArgs, s_destChainConfig);
+ }
+
+ function test_EVMExtraArgsGasLimitTooHigh_Revert() public {
+ Client.EVMExtraArgsV2 memory inputArgs =
+ Client.EVMExtraArgsV2({gasLimit: s_destChainConfig.maxPerMsgGasLimit + 1, allowOutOfOrderExecution: true});
+ bytes memory inputExtraArgs = Client._argsToBytes(inputArgs);
+
+ vm.expectRevert(PriceRegistry.MessageGasLimitTooHigh.selector);
+ s_priceRegistry.parseEVMExtraArgsFromBytes(inputExtraArgs, s_destChainConfig);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/rateLimiter/AggregateRateLimiter.t.sol b/contracts/src/v0.8/ccip/test/rateLimiter/AggregateRateLimiter.t.sol
new file mode 100644
index 00000000000..d3a07ef11e9
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/rateLimiter/AggregateRateLimiter.t.sol
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {AggregateRateLimiter} from "../../AggregateRateLimiter.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {AggregateRateLimiterHelper} from "../helpers/AggregateRateLimiterHelper.sol";
+import {PriceRegistrySetup} from "../priceRegistry/PriceRegistry.t.sol";
+
+import {stdError} from "forge-std/Test.sol";
+
+contract AggregateTokenLimiterSetup is PriceRegistrySetup {
+ AggregateRateLimiterHelper internal s_rateLimiter;
+ RateLimiter.Config internal s_config;
+
+ address internal immutable TOKEN = 0x21118E64E1fB0c487F25Dd6d3601FF6af8D32E4e;
+ uint224 internal constant TOKEN_PRICE = 4e18;
+
+ function setUp() public virtual override {
+ PriceRegistrySetup.setUp();
+
+ Internal.PriceUpdates memory priceUpdates = getSingleTokenPriceUpdateStruct(TOKEN, TOKEN_PRICE);
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ s_config = RateLimiter.Config({isEnabled: true, rate: 5, capacity: 100});
+ s_rateLimiter = new AggregateRateLimiterHelper(s_config);
+ s_rateLimiter.setAdmin(ADMIN);
+ }
+}
+
+contract AggregateTokenLimiter_constructor is AggregateTokenLimiterSetup {
+ function test_Constructor_Success() public view {
+ assertEq(ADMIN, s_rateLimiter.getTokenLimitAdmin());
+ assertEq(OWNER, s_rateLimiter.owner());
+
+ RateLimiter.TokenBucket memory bucket = s_rateLimiter.currentRateLimiterState();
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.capacity, bucket.tokens);
+ assertEq(s_config.isEnabled, bucket.isEnabled);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+ }
+}
+
+contract AggregateTokenLimiter_getTokenLimitAdmin is AggregateTokenLimiterSetup {
+ function test_GetTokenLimitAdmin_Success() public view {
+ assertEq(ADMIN, s_rateLimiter.getTokenLimitAdmin());
+ }
+}
+
+contract AggregateTokenLimiter_setAdmin is AggregateTokenLimiterSetup {
+ function test_Owner_Success() public {
+ vm.expectEmit();
+ emit AggregateRateLimiter.AdminSet(STRANGER);
+
+ s_rateLimiter.setAdmin(STRANGER);
+ assertEq(STRANGER, s_rateLimiter.getTokenLimitAdmin());
+ }
+
+ // Reverts
+
+ function test_OnlyOwnerOrAdmin_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(RateLimiter.OnlyCallableByAdminOrOwner.selector);
+
+ s_rateLimiter.setAdmin(STRANGER);
+ }
+}
+
+contract AggregateTokenLimiter_getTokenBucket is AggregateTokenLimiterSetup {
+ function test_GetTokenBucket_Success() public view {
+ RateLimiter.TokenBucket memory bucket = s_rateLimiter.currentRateLimiterState();
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.capacity, bucket.tokens);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+ }
+
+ function test_Refill_Success() public {
+ s_config.capacity = s_config.capacity * 2;
+ s_rateLimiter.setRateLimiterConfig(s_config);
+
+ RateLimiter.TokenBucket memory bucket = s_rateLimiter.currentRateLimiterState();
+
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.capacity / 2, bucket.tokens);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+
+ uint256 warpTime = 4;
+ vm.warp(BLOCK_TIME + warpTime);
+
+ bucket = s_rateLimiter.currentRateLimiterState();
+
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.capacity / 2 + warpTime * s_config.rate, bucket.tokens);
+ assertEq(BLOCK_TIME + warpTime, bucket.lastUpdated);
+
+ vm.warp(BLOCK_TIME + warpTime * 100);
+
+ // Bucket overflow
+ bucket = s_rateLimiter.currentRateLimiterState();
+ assertEq(s_config.capacity, bucket.tokens);
+ }
+
+ // Reverts
+
+ function test_TimeUnderflow_Revert() public {
+ vm.warp(BLOCK_TIME - 1);
+
+ vm.expectRevert(stdError.arithmeticError);
+ s_rateLimiter.currentRateLimiterState();
+ }
+}
+
+contract AggregateTokenLimiter_setRateLimiterConfig is AggregateTokenLimiterSetup {
+ function test_Owner_Success() public {
+ setConfig();
+ }
+
+ function test_TokenLimitAdmin_Success() public {
+ vm.startPrank(ADMIN);
+ setConfig();
+ }
+
+ function setConfig() private {
+ RateLimiter.TokenBucket memory bucket = s_rateLimiter.currentRateLimiterState();
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+
+ if (bucket.isEnabled) {
+ s_config = RateLimiter.Config({isEnabled: false, rate: 0, capacity: 0});
+ } else {
+ s_config = RateLimiter.Config({isEnabled: true, rate: 100, capacity: 200});
+ }
+
+ vm.expectEmit();
+ emit RateLimiter.ConfigChanged(s_config);
+
+ s_rateLimiter.setRateLimiterConfig(s_config);
+
+ bucket = s_rateLimiter.currentRateLimiterState();
+ assertEq(s_config.rate, bucket.rate);
+ assertEq(s_config.capacity, bucket.capacity);
+ assertEq(s_config.isEnabled, bucket.isEnabled);
+ }
+
+ // Reverts
+
+ function test_OnlyOnlyCallableByAdminOrOwner_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(RateLimiter.OnlyCallableByAdminOrOwner.selector);
+
+ s_rateLimiter.setRateLimiterConfig(s_config);
+ }
+}
+
+contract AggregateTokenLimiter_rateLimitValue is AggregateTokenLimiterSetup {
+ function test_RateLimitValueSuccess_gas() public {
+ vm.pauseGasMetering();
+ // start from blocktime that does not equal rate limiter init timestamp
+ vm.warp(BLOCK_TIME + 1);
+
+ // 15 (tokens) * 4 (price) * 2 (number of times) > 100 (capacity)
+ uint256 numberOfTokens = 15;
+ uint256 value = (numberOfTokens * TOKEN_PRICE) / 1e18;
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(value);
+
+ vm.resumeGasMetering();
+ s_rateLimiter.rateLimitValue(value);
+ vm.pauseGasMetering();
+
+ // Get the updated bucket status
+ RateLimiter.TokenBucket memory bucket = s_rateLimiter.currentRateLimiterState();
+ // Assert the proper value has been taken out of the bucket
+ assertEq(bucket.capacity - value, bucket.tokens);
+
+ // Since value * 2 > bucket.capacity we cannot take it out twice.
+ // Expect a revert when we try, with a wait time.
+ uint256 waitTime = 4;
+ vm.expectRevert(
+ abi.encodeWithSelector(RateLimiter.AggregateValueRateLimitReached.selector, waitTime, bucket.tokens)
+ );
+ s_rateLimiter.rateLimitValue(value);
+
+ // Move the block time forward by 10 so the bucket refills by 10 * rate
+ vm.warp(BLOCK_TIME + 1 + waitTime);
+
+ // The bucket has filled up enough so we can take out more tokens
+ s_rateLimiter.rateLimitValue(value);
+ bucket = s_rateLimiter.currentRateLimiterState();
+ assertEq(bucket.capacity - value + waitTime * s_config.rate - value, bucket.tokens);
+ vm.resumeGasMetering();
+ }
+
+ // Reverts
+
+ function test_AggregateValueMaxCapacityExceeded_Revert() public {
+ RateLimiter.TokenBucket memory bucket = s_rateLimiter.currentRateLimiterState();
+
+ uint256 numberOfTokens = 100;
+ uint256 value = (numberOfTokens * TOKEN_PRICE) / 1e18;
+
+ vm.expectRevert(
+ abi.encodeWithSelector(
+ RateLimiter.AggregateValueMaxCapacityExceeded.selector, bucket.capacity, (numberOfTokens * TOKEN_PRICE) / 1e18
+ )
+ );
+ s_rateLimiter.rateLimitValue(value);
+ }
+}
+
+contract AggregateTokenLimiter_getTokenValue is AggregateTokenLimiterSetup {
+ function test_GetTokenValue_Success() public view {
+ uint256 numberOfTokens = 10;
+ Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({token: TOKEN, amount: 10});
+ uint256 value = s_rateLimiter.getTokenValue(tokenAmount, s_priceRegistry);
+ assertEq(value, (numberOfTokens * TOKEN_PRICE) / 1e18);
+ }
+
+ // Reverts
+ function test_NoTokenPrice_Reverts() public {
+ address tokenWithNoPrice = makeAddr("Token with no price");
+ Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({token: tokenWithNoPrice, amount: 10});
+
+ vm.expectRevert(abi.encodeWithSelector(AggregateRateLimiter.PriceNotFoundForToken.selector, tokenWithNoPrice));
+ s_rateLimiter.getTokenValue(tokenAmount, s_priceRegistry);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/rateLimiter/MultiAggregateRateLimiter.t.sol b/contracts/src/v0.8/ccip/test/rateLimiter/MultiAggregateRateLimiter.t.sol
new file mode 100644
index 00000000000..2bd31452f00
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/rateLimiter/MultiAggregateRateLimiter.t.sol
@@ -0,0 +1,1201 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {AuthorizedCallers} from "../../../shared/access/AuthorizedCallers.sol";
+import {MultiAggregateRateLimiter} from "../../MultiAggregateRateLimiter.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {RateLimiter} from "../../libraries/RateLimiter.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+import {MultiAggregateRateLimiterHelper} from "../helpers/MultiAggregateRateLimiterHelper.sol";
+import {PriceRegistrySetup} from "../priceRegistry/PriceRegistry.t.sol";
+import {stdError} from "forge-std/Test.sol";
+import {Vm} from "forge-std/Vm.sol";
+
+contract MultiAggregateRateLimiterSetup is BaseTest, PriceRegistrySetup {
+ MultiAggregateRateLimiterHelper internal s_rateLimiter;
+
+ address internal immutable TOKEN = 0x21118E64E1fB0c487F25Dd6d3601FF6af8D32E4e;
+ uint224 internal constant TOKEN_PRICE = 4e18;
+
+ uint64 internal constant CHAIN_SELECTOR_1 = 5009297550715157269;
+ uint64 internal constant CHAIN_SELECTOR_2 = 4949039107694359620;
+
+ RateLimiter.Config internal RATE_LIMITER_CONFIG_1 = RateLimiter.Config({isEnabled: true, rate: 5, capacity: 100});
+ RateLimiter.Config internal RATE_LIMITER_CONFIG_2 = RateLimiter.Config({isEnabled: true, rate: 10, capacity: 200});
+
+ address internal immutable MOCK_OFFRAMP = address(1111);
+ address internal immutable MOCK_ONRAMP = address(1112);
+
+ address[] internal s_authorizedCallers;
+
+ function setUp() public virtual override(BaseTest, PriceRegistrySetup) {
+ BaseTest.setUp();
+ PriceRegistrySetup.setUp();
+
+ Internal.PriceUpdates memory priceUpdates = getSingleTokenPriceUpdateStruct(TOKEN, TOKEN_PRICE);
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](4);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+ configUpdates[1] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_2,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_2
+ });
+ configUpdates[2] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ isOutboundLane: true,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+ configUpdates[3] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_2,
+ isOutboundLane: true,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_2
+ });
+
+ s_authorizedCallers = new address[](2);
+ s_authorizedCallers[0] = MOCK_OFFRAMP;
+ s_authorizedCallers[1] = MOCK_ONRAMP;
+
+ s_rateLimiter = new MultiAggregateRateLimiterHelper(address(s_priceRegistry), s_authorizedCallers);
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+ }
+
+ function _assertConfigWithTokenBucketEquality(
+ RateLimiter.Config memory config,
+ RateLimiter.TokenBucket memory tokenBucket
+ ) internal pure {
+ assertEq(config.rate, tokenBucket.rate);
+ assertEq(config.capacity, tokenBucket.capacity);
+ assertEq(config.capacity, tokenBucket.tokens);
+ assertEq(config.isEnabled, tokenBucket.isEnabled);
+ }
+
+ function _assertTokenBucketEquality(
+ RateLimiter.TokenBucket memory tokenBucketA,
+ RateLimiter.TokenBucket memory tokenBucketB
+ ) internal pure {
+ assertEq(tokenBucketA.rate, tokenBucketB.rate);
+ assertEq(tokenBucketA.capacity, tokenBucketB.capacity);
+ assertEq(tokenBucketA.tokens, tokenBucketB.tokens);
+ assertEq(tokenBucketA.isEnabled, tokenBucketB.isEnabled);
+ }
+
+ function _generateAny2EVMMessage(
+ uint64 sourceChainSelector,
+ Client.EVMTokenAmount[] memory tokenAmounts
+ ) internal pure returns (Client.Any2EVMMessage memory) {
+ return Client.Any2EVMMessage({
+ messageId: keccak256(bytes("messageId")),
+ sourceChainSelector: sourceChainSelector,
+ sender: abi.encode(OWNER),
+ data: abi.encode(0),
+ destTokenAmounts: tokenAmounts
+ });
+ }
+
+ function _generateAny2EVMMessageNoTokens(uint64 sourceChainSelector)
+ internal
+ pure
+ returns (Client.Any2EVMMessage memory)
+ {
+ return _generateAny2EVMMessage(sourceChainSelector, new Client.EVMTokenAmount[](0));
+ }
+}
+
+contract MultiAggregateRateLimiter_constructor is MultiAggregateRateLimiterSetup {
+ function test_ConstructorNoAuthorizedCallers_Success() public {
+ address[] memory authorizedCallers = new address[](0);
+
+ vm.recordLogs();
+ s_rateLimiter = new MultiAggregateRateLimiterHelper(address(s_priceRegistry), authorizedCallers);
+
+ // PriceRegistrySet
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 1);
+
+ assertEq(OWNER, s_rateLimiter.owner());
+ assertEq(address(s_priceRegistry), s_rateLimiter.getPriceRegistry());
+ }
+
+ function test_Constructor_Success() public {
+ address[] memory authorizedCallers = new address[](2);
+ authorizedCallers[0] = MOCK_OFFRAMP;
+ authorizedCallers[1] = MOCK_ONRAMP;
+
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.PriceRegistrySet(address(s_priceRegistry));
+
+ s_rateLimiter = new MultiAggregateRateLimiterHelper(address(s_priceRegistry), authorizedCallers);
+
+ assertEq(OWNER, s_rateLimiter.owner());
+ assertEq(address(s_priceRegistry), s_rateLimiter.getPriceRegistry());
+ }
+}
+
+contract MultiAggregateRateLimiter_setPriceRegistry is MultiAggregateRateLimiterSetup {
+ function test_Owner_Success() public {
+ address newAddress = address(42);
+
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.PriceRegistrySet(newAddress);
+
+ s_rateLimiter.setPriceRegistry(newAddress);
+ assertEq(newAddress, s_rateLimiter.getPriceRegistry());
+ }
+
+ // Reverts
+
+ function test_OnlyOwner_Revert() public {
+ vm.startPrank(STRANGER);
+ vm.expectRevert(bytes("Only callable by owner"));
+
+ s_rateLimiter.setPriceRegistry(STRANGER);
+ }
+
+ function test_ZeroAddress_Revert() public {
+ vm.expectRevert(AuthorizedCallers.ZeroAddressNotAllowed.selector);
+ s_rateLimiter.setPriceRegistry(address(0));
+ }
+}
+
+contract MultiAggregateRateLimiter_getTokenBucket is MultiAggregateRateLimiterSetup {
+ function test_GetTokenBucket_Success() public view {
+ RateLimiter.TokenBucket memory bucketInbound = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+ _assertConfigWithTokenBucketEquality(RATE_LIMITER_CONFIG_1, bucketInbound);
+ assertEq(BLOCK_TIME, bucketInbound.lastUpdated);
+
+ RateLimiter.TokenBucket memory bucketOutbound = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, true);
+ _assertConfigWithTokenBucketEquality(RATE_LIMITER_CONFIG_1, bucketOutbound);
+ assertEq(BLOCK_TIME, bucketOutbound.lastUpdated);
+ }
+
+ function test_Refill_Success() public {
+ RATE_LIMITER_CONFIG_1.capacity = RATE_LIMITER_CONFIG_1.capacity * 2;
+
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ RateLimiter.TokenBucket memory bucket = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+
+ assertEq(RATE_LIMITER_CONFIG_1.rate, bucket.rate);
+ assertEq(RATE_LIMITER_CONFIG_1.capacity, bucket.capacity);
+ assertEq(RATE_LIMITER_CONFIG_1.capacity / 2, bucket.tokens);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+
+ uint256 warpTime = 4;
+ vm.warp(BLOCK_TIME + warpTime);
+
+ bucket = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+
+ assertEq(RATE_LIMITER_CONFIG_1.rate, bucket.rate);
+ assertEq(RATE_LIMITER_CONFIG_1.capacity, bucket.capacity);
+ assertEq(RATE_LIMITER_CONFIG_1.capacity / 2 + warpTime * RATE_LIMITER_CONFIG_1.rate, bucket.tokens);
+ assertEq(BLOCK_TIME + warpTime, bucket.lastUpdated);
+
+ vm.warp(BLOCK_TIME + warpTime * 100);
+
+ // Bucket overflow
+ bucket = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+ assertEq(RATE_LIMITER_CONFIG_1.capacity, bucket.tokens);
+ }
+
+ // Reverts
+
+ function test_TimeUnderflow_Revert() public {
+ vm.warp(BLOCK_TIME - 1);
+
+ vm.expectRevert(stdError.arithmeticError);
+ s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+ }
+}
+
+contract MultiAggregateRateLimiter_applyRateLimiterConfigUpdates is MultiAggregateRateLimiterSetup {
+ function test_ZeroConfigs_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](0);
+
+ vm.recordLogs();
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 0);
+ }
+
+ function test_SingleConfig_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1 + 1,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.RateLimiterConfigUpdated(
+ configUpdates[0].remoteChainSelector, false, configUpdates[0].rateLimiterConfig
+ );
+
+ vm.recordLogs();
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 1);
+
+ RateLimiter.TokenBucket memory bucket1 =
+ s_rateLimiter.currentRateLimiterState(configUpdates[0].remoteChainSelector, false);
+ _assertConfigWithTokenBucketEquality(configUpdates[0].rateLimiterConfig, bucket1);
+ assertEq(BLOCK_TIME, bucket1.lastUpdated);
+ }
+
+ function test_SingleConfigOutbound_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1 + 1,
+ isOutboundLane: true,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_2
+ });
+
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.RateLimiterConfigUpdated(
+ configUpdates[0].remoteChainSelector, true, configUpdates[0].rateLimiterConfig
+ );
+
+ vm.recordLogs();
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 1);
+
+ RateLimiter.TokenBucket memory bucket1 =
+ s_rateLimiter.currentRateLimiterState(configUpdates[0].remoteChainSelector, true);
+ _assertConfigWithTokenBucketEquality(configUpdates[0].rateLimiterConfig, bucket1);
+ assertEq(BLOCK_TIME, bucket1.lastUpdated);
+ }
+
+ function test_MultipleConfigs_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](5);
+
+ for (uint64 i; i < configUpdates.length; ++i) {
+ configUpdates[i] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1 + i + 1,
+ isOutboundLane: i % 2 == 0 ? false : true,
+ rateLimiterConfig: RateLimiter.Config({isEnabled: true, rate: 5 + i, capacity: 100 + i})
+ });
+
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.RateLimiterConfigUpdated(
+ configUpdates[i].remoteChainSelector, configUpdates[i].isOutboundLane, configUpdates[i].rateLimiterConfig
+ );
+ }
+
+ vm.recordLogs();
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, configUpdates.length);
+
+ for (uint256 i; i < configUpdates.length; ++i) {
+ RateLimiter.TokenBucket memory bucket =
+ s_rateLimiter.currentRateLimiterState(configUpdates[i].remoteChainSelector, configUpdates[i].isOutboundLane);
+ _assertConfigWithTokenBucketEquality(configUpdates[i].rateLimiterConfig, bucket);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+ }
+ }
+
+ function test_MultipleConfigsBothLanes_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](2);
+
+ for (uint64 i; i < configUpdates.length; ++i) {
+ configUpdates[i] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1 + 1,
+ isOutboundLane: i % 2 == 0 ? false : true,
+ rateLimiterConfig: RateLimiter.Config({isEnabled: true, rate: 5 + i, capacity: 100 + i})
+ });
+
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.RateLimiterConfigUpdated(
+ configUpdates[i].remoteChainSelector, configUpdates[i].isOutboundLane, configUpdates[i].rateLimiterConfig
+ );
+ }
+
+ vm.recordLogs();
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, configUpdates.length);
+
+ for (uint256 i; i < configUpdates.length; ++i) {
+ RateLimiter.TokenBucket memory bucket =
+ s_rateLimiter.currentRateLimiterState(configUpdates[i].remoteChainSelector, configUpdates[i].isOutboundLane);
+ _assertConfigWithTokenBucketEquality(configUpdates[i].rateLimiterConfig, bucket);
+ assertEq(BLOCK_TIME, bucket.lastUpdated);
+ }
+ }
+
+ function test_UpdateExistingConfig_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_2
+ });
+
+ RateLimiter.TokenBucket memory bucket1 =
+ s_rateLimiter.currentRateLimiterState(configUpdates[0].remoteChainSelector, false);
+
+ // Capacity equals tokens
+ assertEq(bucket1.capacity, bucket1.tokens);
+
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.RateLimiterConfigUpdated(
+ configUpdates[0].remoteChainSelector, false, configUpdates[0].rateLimiterConfig
+ );
+
+ vm.recordLogs();
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ vm.warp(BLOCK_TIME + 1);
+ bucket1 = s_rateLimiter.currentRateLimiterState(configUpdates[0].remoteChainSelector, false);
+ assertEq(BLOCK_TIME + 1, bucket1.lastUpdated);
+
+ // Tokens < capacity since capacity doubled
+ assertTrue(bucket1.capacity != bucket1.tokens);
+
+ // Outbound lane config remains unchanged
+ _assertConfigWithTokenBucketEquality(
+ RATE_LIMITER_CONFIG_1, s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, true)
+ );
+ }
+
+ function test_UpdateExistingConfigWithNoDifference_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+
+ RateLimiter.TokenBucket memory bucketPreUpdate =
+ s_rateLimiter.currentRateLimiterState(configUpdates[0].remoteChainSelector, false);
+
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.RateLimiterConfigUpdated(
+ configUpdates[0].remoteChainSelector, false, configUpdates[0].rateLimiterConfig
+ );
+
+ vm.recordLogs();
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ vm.warp(BLOCK_TIME + 1);
+ RateLimiter.TokenBucket memory bucketPostUpdate =
+ s_rateLimiter.currentRateLimiterState(configUpdates[0].remoteChainSelector, false);
+ _assertTokenBucketEquality(bucketPreUpdate, bucketPostUpdate);
+ assertEq(BLOCK_TIME + 1, bucketPostUpdate.lastUpdated);
+ }
+
+ // Reverts
+ function test_ZeroChainSelector_Revert() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: 0,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+
+ vm.expectRevert(MultiAggregateRateLimiter.ZeroChainSelectorNotAllowed.selector);
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+ }
+
+ function test_OnlyCallableByOwner_Revert() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1 + 1,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(bytes("Only callable by owner"));
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+ }
+}
+
+contract MultiAggregateRateLimiter_getTokenValue is MultiAggregateRateLimiterSetup {
+ function test_GetTokenValue_Success() public view {
+ uint256 numberOfTokens = 10;
+ Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({token: TOKEN, amount: 10});
+ uint256 value = s_rateLimiter.getTokenValue(tokenAmount);
+ assertEq(value, (numberOfTokens * TOKEN_PRICE) / 1e18);
+ }
+
+ // Reverts
+ function test_NoTokenPrice_Reverts() public {
+ address tokenWithNoPrice = makeAddr("Token with no price");
+ Client.EVMTokenAmount memory tokenAmount = Client.EVMTokenAmount({token: tokenWithNoPrice, amount: 10});
+
+ vm.expectRevert(abi.encodeWithSelector(MultiAggregateRateLimiter.PriceNotFoundForToken.selector, tokenWithNoPrice));
+ s_rateLimiter.getTokenValue(tokenAmount);
+ }
+}
+
+contract MultiAggregateRateLimiter_updateRateLimitTokens is MultiAggregateRateLimiterSetup {
+ function setUp() public virtual override {
+ super.setUp();
+
+ // Clear rate limit tokens state
+ MultiAggregateRateLimiter.LocalRateLimitToken[] memory removes =
+ new MultiAggregateRateLimiter.LocalRateLimitToken[](s_sourceTokens.length);
+ for (uint256 i = 0; i < s_sourceTokens.length; ++i) {
+ removes[i] = MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[i]
+ });
+ }
+ s_rateLimiter.updateRateLimitTokens(removes, new MultiAggregateRateLimiter.RateLimitTokenArgs[](0));
+ }
+
+ function test_UpdateRateLimitTokensSingleChain_Success() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory adds = new MultiAggregateRateLimiter.RateLimitTokenArgs[](2);
+ adds[0] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[0]
+ }),
+ remoteToken: bytes32(bytes20(s_sourceTokens[0]))
+ });
+ adds[1] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[1]
+ }),
+ remoteToken: bytes32(bytes20(s_sourceTokens[1]))
+ });
+
+ for (uint256 i = 0; i < adds.length; ++i) {
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.TokenAggregateRateLimitAdded(
+ CHAIN_SELECTOR_1, adds[i].remoteToken, adds[i].localTokenArgs.localToken
+ );
+ }
+
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), adds);
+
+ (address[] memory localTokens, bytes32[] memory remoteTokens) =
+ s_rateLimiter.getAllRateLimitTokens(CHAIN_SELECTOR_1);
+
+ assertEq(localTokens.length, adds.length);
+ assertEq(localTokens.length, remoteTokens.length);
+
+ for (uint256 i = 0; i < adds.length; ++i) {
+ assertEq(adds[i].remoteToken, remoteTokens[i]);
+ assertEq(adds[i].localTokenArgs.localToken, localTokens[i]);
+ }
+ }
+
+ function test_UpdateRateLimitTokensMultipleChains_Success() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory adds = new MultiAggregateRateLimiter.RateLimitTokenArgs[](2);
+ adds[0] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[0]
+ }),
+ remoteToken: bytes32(bytes20(s_sourceTokens[0]))
+ });
+ adds[1] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_2,
+ localToken: s_destTokens[1]
+ }),
+ remoteToken: bytes32(bytes20(s_sourceTokens[1]))
+ });
+
+ for (uint256 i = 0; i < adds.length; ++i) {
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.TokenAggregateRateLimitAdded(
+ adds[i].localTokenArgs.remoteChainSelector, adds[i].remoteToken, adds[i].localTokenArgs.localToken
+ );
+ }
+
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), adds);
+
+ (address[] memory localTokensChain1, bytes32[] memory remoteTokensChain1) =
+ s_rateLimiter.getAllRateLimitTokens(CHAIN_SELECTOR_1);
+
+ assertEq(localTokensChain1.length, 1);
+ assertEq(localTokensChain1.length, remoteTokensChain1.length);
+ assertEq(localTokensChain1[0], adds[0].localTokenArgs.localToken);
+ assertEq(remoteTokensChain1[0], adds[0].remoteToken);
+
+ (address[] memory localTokensChain2, bytes32[] memory remoteTokensChain2) =
+ s_rateLimiter.getAllRateLimitTokens(CHAIN_SELECTOR_2);
+
+ assertEq(localTokensChain2.length, 1);
+ assertEq(localTokensChain2.length, remoteTokensChain2.length);
+ assertEq(localTokensChain2[0], adds[1].localTokenArgs.localToken);
+ assertEq(remoteTokensChain2[0], adds[1].remoteToken);
+ }
+
+ function test_UpdateRateLimitTokens_AddsAndRemoves_Success() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory adds = new MultiAggregateRateLimiter.RateLimitTokenArgs[](2);
+ adds[0] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[0]
+ }),
+ remoteToken: bytes32(bytes20(s_sourceTokens[0]))
+ });
+ adds[1] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[1]
+ }),
+ remoteToken: bytes32(bytes20(s_sourceTokens[1]))
+ });
+
+ MultiAggregateRateLimiter.LocalRateLimitToken[] memory removes =
+ new MultiAggregateRateLimiter.LocalRateLimitToken[](1);
+ removes[0] = adds[0].localTokenArgs;
+
+ for (uint256 i = 0; i < adds.length; ++i) {
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.TokenAggregateRateLimitAdded(
+ CHAIN_SELECTOR_1, adds[i].remoteToken, adds[i].localTokenArgs.localToken
+ );
+ }
+
+ s_rateLimiter.updateRateLimitTokens(removes, adds);
+
+ for (uint256 i = 0; i < removes.length; ++i) {
+ vm.expectEmit();
+ emit MultiAggregateRateLimiter.TokenAggregateRateLimitRemoved(CHAIN_SELECTOR_1, removes[i].localToken);
+ }
+
+ s_rateLimiter.updateRateLimitTokens(removes, new MultiAggregateRateLimiter.RateLimitTokenArgs[](0));
+
+ (address[] memory localTokens, bytes32[] memory remoteTokens) =
+ s_rateLimiter.getAllRateLimitTokens(CHAIN_SELECTOR_1);
+
+ assertEq(1, remoteTokens.length);
+ assertEq(adds[1].remoteToken, remoteTokens[0]);
+
+ assertEq(1, localTokens.length);
+ assertEq(adds[1].localTokenArgs.localToken, localTokens[0]);
+ }
+
+ function test_UpdateRateLimitTokens_RemoveNonExistentToken_Success() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory adds = new MultiAggregateRateLimiter.RateLimitTokenArgs[](0);
+
+ MultiAggregateRateLimiter.LocalRateLimitToken[] memory removes =
+ new MultiAggregateRateLimiter.LocalRateLimitToken[](1);
+ removes[0] = MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[0]
+ });
+
+ vm.recordLogs();
+ s_rateLimiter.updateRateLimitTokens(removes, adds);
+
+ // No event since no remove occurred
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 0);
+
+ (address[] memory localTokens, bytes32[] memory remoteTokens) =
+ s_rateLimiter.getAllRateLimitTokens(CHAIN_SELECTOR_1);
+
+ assertEq(localTokens.length, 0);
+ assertEq(localTokens.length, remoteTokens.length);
+ }
+
+ // Reverts
+
+ function test_ZeroSourceToken_Revert() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory adds = new MultiAggregateRateLimiter.RateLimitTokenArgs[](1);
+ adds[0] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[0]
+ }),
+ remoteToken: bytes32(bytes20(address(0)))
+ });
+
+ vm.expectRevert(AuthorizedCallers.ZeroAddressNotAllowed.selector);
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), adds);
+ }
+
+ function test_ZeroDestToken_Revert() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory adds = new MultiAggregateRateLimiter.RateLimitTokenArgs[](1);
+ adds[0] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: address(0)
+ }),
+ remoteToken: bytes32(bytes20(s_destTokens[0]))
+ });
+
+ vm.expectRevert(AuthorizedCallers.ZeroAddressNotAllowed.selector);
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), adds);
+ }
+
+ function test_NonOwner_Revert() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory adds = new MultiAggregateRateLimiter.RateLimitTokenArgs[](4);
+
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(bytes("Only callable by owner"));
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), adds);
+ }
+}
+
+contract MultiAggregateRateLimiter_onInboundMessage is MultiAggregateRateLimiterSetup {
+ address internal immutable MOCK_RECEIVER = address(1113);
+
+ function setUp() public virtual override {
+ super.setUp();
+
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory tokensToAdd =
+ new MultiAggregateRateLimiter.RateLimitTokenArgs[](s_sourceTokens.length);
+ for (uint224 i = 0; i < s_sourceTokens.length; ++i) {
+ tokensToAdd[i] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[i]
+ }),
+ remoteToken: bytes32(bytes20(s_sourceTokens[i]))
+ });
+
+ Internal.PriceUpdates memory priceUpdates =
+ getSingleTokenPriceUpdateStruct(s_destTokens[i], TOKEN_PRICE * (i + 1));
+ s_priceRegistry.updatePrices(priceUpdates);
+ }
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), tokensToAdd);
+ }
+
+ function test_ValidateMessageWithNoTokens_Success() public {
+ vm.startPrank(MOCK_OFFRAMP);
+
+ vm.recordLogs();
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessageNoTokens(CHAIN_SELECTOR_1));
+
+ // No consumed rate limit events
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 0);
+ }
+
+ function test_ValidateMessageWithTokens_Success() public {
+ vm.startPrank(MOCK_OFFRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_destTokens[0], amount: 3});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_destTokens[1], amount: 1});
+
+ // 3 tokens * TOKEN_PRICE + 1 token * (2 * TOKEN_PRICE)
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed((5 * TOKEN_PRICE) / 1e18);
+
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+ }
+
+ function test_ValidateMessageWithDisabledRateLimitToken_Success() public {
+ MultiAggregateRateLimiter.LocalRateLimitToken[] memory removes =
+ new MultiAggregateRateLimiter.LocalRateLimitToken[](1);
+ removes[0] = MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_destTokens[1]
+ });
+ s_rateLimiter.updateRateLimitTokens(removes, new MultiAggregateRateLimiter.RateLimitTokenArgs[](0));
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_destTokens[0], amount: 5});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_destTokens[1], amount: 1});
+
+ vm.startPrank(MOCK_OFFRAMP);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed((5 * TOKEN_PRICE) / 1e18);
+
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+ }
+
+ function test_ValidateMessageWithRateLimitDisabled_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ isOutboundLane: false,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+ configUpdates[0].rateLimiterConfig.isEnabled = false;
+
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_destTokens[0], amount: 1000});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_destTokens[1], amount: 50});
+
+ vm.startPrank(MOCK_OFFRAMP);
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+
+ // No consumed rate limit events
+ Vm.Log[] memory logEntries = vm.getRecordedLogs();
+ assertEq(logEntries.length, 0);
+ }
+
+ function test_ValidateMessageWithTokensOnDifferentChains_Success() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory tokensToAdd =
+ new MultiAggregateRateLimiter.RateLimitTokenArgs[](s_sourceTokens.length);
+ for (uint224 i = 0; i < s_sourceTokens.length; ++i) {
+ tokensToAdd[i] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_2,
+ localToken: s_destTokens[i]
+ }),
+ // Create a remote token address that is different from CHAIN_SELECTOR_1
+ remoteToken: bytes32(uint256(uint160(s_sourceTokens[i])) + type(uint160).max + 1)
+ });
+ }
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), tokensToAdd);
+
+ vm.startPrank(MOCK_OFFRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_destTokens[0], amount: 2});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_destTokens[1], amount: 1});
+
+ // 2 tokens * (TOKEN_PRICE) + 1 token * (2 * TOKEN_PRICE)
+ uint256 totalValue = (4 * TOKEN_PRICE) / 1e18;
+
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+
+ // Chain 1 changed
+ RateLimiter.TokenBucket memory bucketChain1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+ assertEq(bucketChain1.capacity - totalValue, bucketChain1.tokens);
+
+ // Chain 2 unchanged
+ RateLimiter.TokenBucket memory bucketChain2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_2, false);
+ assertEq(bucketChain2.capacity, bucketChain2.tokens);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(totalValue);
+
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_2, tokenAmounts));
+
+ // Chain 1 unchanged
+ bucketChain1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+ assertEq(bucketChain1.capacity - totalValue, bucketChain1.tokens);
+
+ // Chain 2 changed
+ bucketChain2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_2, false);
+ assertEq(bucketChain2.capacity - totalValue, bucketChain2.tokens);
+ }
+
+ function test_ValidateMessageWithDifferentTokensOnDifferentChains_Success() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory tokensToAdd =
+ new MultiAggregateRateLimiter.RateLimitTokenArgs[](1);
+
+ // Only 1 rate limited token on different chain
+ tokensToAdd[0] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_2,
+ localToken: s_destTokens[0]
+ }),
+ // Create a remote token address that is different from CHAIN_SELECTOR_1
+ remoteToken: bytes32(uint256(uint160(s_sourceTokens[0])) + type(uint160).max + 1)
+ });
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), tokensToAdd);
+
+ vm.startPrank(MOCK_OFFRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_destTokens[0], amount: 3});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_destTokens[1], amount: 1});
+
+ // 3 tokens * (TOKEN_PRICE) + 1 token * (2 * TOKEN_PRICE)
+ uint256 totalValue = (5 * TOKEN_PRICE) / 1e18;
+
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+
+ // Chain 1 changed
+ RateLimiter.TokenBucket memory bucketChain1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+ assertEq(bucketChain1.capacity - totalValue, bucketChain1.tokens);
+
+ // Chain 2 unchanged
+ RateLimiter.TokenBucket memory bucketChain2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_2, false);
+ assertEq(bucketChain2.capacity, bucketChain2.tokens);
+
+ // 3 tokens * (TOKEN_PRICE)
+ uint256 totalValue2 = (3 * TOKEN_PRICE) / 1e18;
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(totalValue2);
+
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_2, tokenAmounts));
+
+ // Chain 1 unchanged
+ bucketChain1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+ assertEq(bucketChain1.capacity - totalValue, bucketChain1.tokens);
+
+ // Chain 2 changed
+ bucketChain2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_2, false);
+ assertEq(bucketChain2.capacity - totalValue2, bucketChain2.tokens);
+ }
+
+ function test_ValidateMessageWithRateLimitReset_Success() public {
+ vm.startPrank(MOCK_OFFRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_destTokens[0], amount: 20});
+
+ // Remaining capacity: 100 -> 20
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+
+ // Cannot fit 80 rate limit value (need to wait at least 12 blocks, current capacity is 20)
+ vm.expectRevert(abi.encodeWithSelector(RateLimiter.AggregateValueRateLimitReached.selector, 12, 20));
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+
+ // Remaining capacity: 20 -> 35 (need to wait 9 more blocks)
+ vm.warp(BLOCK_TIME + 3);
+ vm.expectRevert(abi.encodeWithSelector(RateLimiter.AggregateValueRateLimitReached.selector, 9, 35));
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+
+ // Remaining capacity: 35 -> 80 (can fit exactly 80)
+ vm.warp(BLOCK_TIME + 12);
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+ }
+
+ // Reverts
+
+ function test_ValidateMessageWithRateLimitExceeded_Revert() public {
+ vm.startPrank(MOCK_OFFRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_destTokens[0], amount: 80});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_destTokens[1], amount: 30});
+
+ uint256 totalValue = (80 * TOKEN_PRICE + 2 * (30 * TOKEN_PRICE)) / 1e18;
+ vm.expectRevert(abi.encodeWithSelector(RateLimiter.AggregateValueMaxCapacityExceeded.selector, 100, totalValue));
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+ }
+
+ function test_ValidateMessageFromUnauthorizedCaller_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(abi.encodeWithSelector(AuthorizedCallers.UnauthorizedCaller.selector, STRANGER));
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessageNoTokens(CHAIN_SELECTOR_1));
+ }
+}
+
+contract MultiAggregateRateLimiter_onOutboundMessage is MultiAggregateRateLimiterSetup {
+ function setUp() public virtual override {
+ super.setUp();
+
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory tokensToAdd =
+ new MultiAggregateRateLimiter.RateLimitTokenArgs[](s_sourceTokens.length);
+ for (uint224 i = 0; i < s_sourceTokens.length; ++i) {
+ tokensToAdd[i] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_sourceTokens[i]
+ }),
+ remoteToken: bytes32(bytes20(s_destTokenBySourceToken[s_sourceTokens[i]]))
+ });
+
+ Internal.PriceUpdates memory priceUpdates =
+ getSingleTokenPriceUpdateStruct(s_sourceTokens[i], TOKEN_PRICE * (i + 1));
+ s_priceRegistry.updatePrices(priceUpdates);
+ }
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), tokensToAdd);
+ }
+
+ function test_ValidateMessageWithNoTokens_Success() public {
+ vm.startPrank(MOCK_ONRAMP);
+
+ vm.recordLogs();
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessageNoTokens());
+
+ // No consumed rate limit events
+ assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ function test_onOutboundMessage_ValidateMessageWithTokens_Success() public {
+ vm.startPrank(MOCK_ONRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: 3});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_sourceTokens[1], amount: 1});
+
+ // 3 tokens * TOKEN_PRICE + 1 token * (2 * TOKEN_PRICE)
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed((5 * TOKEN_PRICE) / 1e18);
+
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+ }
+
+ function test_onOutboundMessage_ValidateMessageWithDisabledRateLimitToken_Success() public {
+ MultiAggregateRateLimiter.LocalRateLimitToken[] memory removes =
+ new MultiAggregateRateLimiter.LocalRateLimitToken[](1);
+ removes[0] = MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ localToken: s_sourceTokens[1]
+ });
+ s_rateLimiter.updateRateLimitTokens(removes, new MultiAggregateRateLimiter.RateLimitTokenArgs[](0));
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: 5});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_sourceTokens[1], amount: 1});
+
+ vm.startPrank(MOCK_ONRAMP);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed((5 * TOKEN_PRICE) / 1e18);
+
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+ }
+
+ function test_onOutboundMessage_ValidateMessageWithRateLimitDisabled_Success() public {
+ MultiAggregateRateLimiter.RateLimiterConfigArgs[] memory configUpdates =
+ new MultiAggregateRateLimiter.RateLimiterConfigArgs[](1);
+ configUpdates[0] = MultiAggregateRateLimiter.RateLimiterConfigArgs({
+ remoteChainSelector: CHAIN_SELECTOR_1,
+ isOutboundLane: true,
+ rateLimiterConfig: RATE_LIMITER_CONFIG_1
+ });
+ configUpdates[0].rateLimiterConfig.isEnabled = false;
+
+ s_rateLimiter.applyRateLimiterConfigUpdates(configUpdates);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: 1000});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_sourceTokens[1], amount: 50});
+
+ vm.startPrank(MOCK_ONRAMP);
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+
+ // No consumed rate limit events
+ assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ function test_onOutboundMessage_ValidateMessageWithTokensOnDifferentChains_Success() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory tokensToAdd =
+ new MultiAggregateRateLimiter.RateLimitTokenArgs[](s_sourceTokens.length);
+ for (uint224 i = 0; i < s_sourceTokens.length; ++i) {
+ tokensToAdd[i] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_2,
+ localToken: s_sourceTokens[i]
+ }),
+ // Create a remote token address that is different from CHAIN_SELECTOR_1
+ remoteToken: bytes32(uint256(uint160(s_destTokenBySourceToken[s_sourceTokens[i]])) + type(uint160).max + 1)
+ });
+ }
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), tokensToAdd);
+
+ vm.startPrank(MOCK_ONRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: 2});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_sourceTokens[1], amount: 1});
+
+ // 2 tokens * (TOKEN_PRICE) + 1 token * (2 * TOKEN_PRICE)
+ uint256 totalValue = (4 * TOKEN_PRICE) / 1e18;
+
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+
+ // Chain 1 changed
+ RateLimiter.TokenBucket memory bucketChain1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, true);
+ assertEq(bucketChain1.capacity - totalValue, bucketChain1.tokens);
+
+ // Chain 2 unchanged
+ RateLimiter.TokenBucket memory bucketChain2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_2, true);
+ assertEq(bucketChain2.capacity, bucketChain2.tokens);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(totalValue);
+
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_2, _generateEVM2AnyMessage(tokenAmounts));
+
+ // Chain 1 unchanged
+ bucketChain1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, true);
+ assertEq(bucketChain1.capacity - totalValue, bucketChain1.tokens);
+
+ // Chain 2 changed
+ bucketChain2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_2, true);
+ assertEq(bucketChain2.capacity - totalValue, bucketChain2.tokens);
+ }
+
+ function test_onOutboundMessage_ValidateMessageWithDifferentTokensOnDifferentChains_Success() public {
+ MultiAggregateRateLimiter.RateLimitTokenArgs[] memory tokensToAdd =
+ new MultiAggregateRateLimiter.RateLimitTokenArgs[](1);
+
+ // Only 1 rate limited token on different chain
+ tokensToAdd[0] = MultiAggregateRateLimiter.RateLimitTokenArgs({
+ localTokenArgs: MultiAggregateRateLimiter.LocalRateLimitToken({
+ remoteChainSelector: CHAIN_SELECTOR_2,
+ localToken: s_sourceTokens[0]
+ }),
+ // Create a remote token address that is different from CHAIN_SELECTOR_1
+ remoteToken: bytes32(uint256(uint160(s_destTokenBySourceToken[s_sourceTokens[0]])) + type(uint160).max + 1)
+ });
+ s_rateLimiter.updateRateLimitTokens(new MultiAggregateRateLimiter.LocalRateLimitToken[](0), tokensToAdd);
+
+ vm.startPrank(MOCK_ONRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: 3});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_sourceTokens[1], amount: 1});
+
+ // 3 tokens * (TOKEN_PRICE) + 1 token * (2 * TOKEN_PRICE)
+ uint256 totalValue = (5 * TOKEN_PRICE) / 1e18;
+
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+
+ // Chain 1 changed
+ RateLimiter.TokenBucket memory bucketChain1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, true);
+ assertEq(bucketChain1.capacity - totalValue, bucketChain1.tokens);
+
+ // Chain 2 unchanged
+ RateLimiter.TokenBucket memory bucketChain2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_2, true);
+ assertEq(bucketChain2.capacity, bucketChain2.tokens);
+
+ // 3 tokens * (TOKEN_PRICE)
+ uint256 totalValue2 = (3 * TOKEN_PRICE) / 1e18;
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(totalValue2);
+
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_2, _generateEVM2AnyMessage(tokenAmounts));
+
+ // Chain 1 unchanged
+ bucketChain1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, true);
+ assertEq(bucketChain1.capacity - totalValue, bucketChain1.tokens);
+
+ // Chain 2 changed
+ bucketChain2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_2, true);
+ assertEq(bucketChain2.capacity - totalValue2, bucketChain2.tokens);
+ }
+
+ function test_onOutboundMessage_ValidateMessageWithRateLimitReset_Success() public {
+ vm.startPrank(MOCK_ONRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: 20});
+
+ // Remaining capacity: 100 -> 20
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+
+ // Cannot fit 80 rate limit value (need to wait at least 12 blocks, current capacity is 20)
+ vm.expectRevert(abi.encodeWithSelector(RateLimiter.AggregateValueRateLimitReached.selector, 12, 20));
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+
+ // Remaining capacity: 20 -> 35 (need to wait 9 more blocks)
+ vm.warp(BLOCK_TIME + 3);
+ vm.expectRevert(abi.encodeWithSelector(RateLimiter.AggregateValueRateLimitReached.selector, 9, 35));
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+
+ // Remaining capacity: 35 -> 80 (can fit exactly 80)
+ vm.warp(BLOCK_TIME + 12);
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+ }
+
+ function test_RateLimitValueDifferentLanes_Success() public {
+ vm.pauseGasMetering();
+ // start from blocktime that does not equal rate limiter init timestamp
+ vm.warp(BLOCK_TIME + 1);
+
+ // 10 (tokens) * 4 (price) * 2 (number of times) = 80 < 100 (capacity)
+ uint256 numberOfTokens = 10;
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: numberOfTokens});
+ uint256 value = (numberOfTokens * TOKEN_PRICE) / 1e18;
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(value);
+
+ vm.resumeGasMetering();
+ vm.startPrank(MOCK_ONRAMP);
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+ vm.pauseGasMetering();
+
+ // Get the updated bucket status
+ RateLimiter.TokenBucket memory bucket1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, true);
+ RateLimiter.TokenBucket memory bucket2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+
+ // Assert the proper value has been taken out of the bucket
+ assertEq(bucket1.capacity - value, bucket1.tokens);
+ // Inbound lane should remain unchanged
+ assertEq(bucket2.capacity, bucket2.tokens);
+
+ vm.expectEmit();
+ emit RateLimiter.TokensConsumed(value);
+
+ vm.resumeGasMetering();
+ s_rateLimiter.onInboundMessage(_generateAny2EVMMessage(CHAIN_SELECTOR_1, tokenAmounts));
+ vm.pauseGasMetering();
+
+ bucket1 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, true);
+ bucket2 = s_rateLimiter.currentRateLimiterState(CHAIN_SELECTOR_1, false);
+
+ // Inbound lane should remain unchanged
+ assertEq(bucket1.capacity - value, bucket1.tokens);
+ assertEq(bucket2.capacity - value, bucket2.tokens);
+ }
+
+ // Reverts
+
+ function test_onOutboundMessage_ValidateMessageWithRateLimitExceeded_Revert() public {
+ vm.startPrank(MOCK_OFFRAMP);
+
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](2);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: s_sourceTokens[0], amount: 80});
+ tokenAmounts[1] = Client.EVMTokenAmount({token: s_sourceTokens[1], amount: 30});
+
+ uint256 totalValue = (80 * TOKEN_PRICE + 2 * (30 * TOKEN_PRICE)) / 1e18;
+ vm.expectRevert(abi.encodeWithSelector(RateLimiter.AggregateValueMaxCapacityExceeded.selector, 100, totalValue));
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessage(tokenAmounts));
+ }
+
+ function test_onOutboundMessage_ValidateMessageFromUnauthorizedCaller_Revert() public {
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(abi.encodeWithSelector(AuthorizedCallers.UnauthorizedCaller.selector, STRANGER));
+ s_rateLimiter.onOutboundMessage(CHAIN_SELECTOR_1, _generateEVM2AnyMessageNoTokens());
+ }
+
+ function _generateEVM2AnyMessage(Client.EVMTokenAmount[] memory tokenAmounts)
+ public
+ view
+ returns (Client.EVM2AnyMessage memory)
+ {
+ return Client.EVM2AnyMessage({
+ receiver: abi.encode(OWNER),
+ data: "",
+ tokenAmounts: tokenAmounts,
+ feeToken: s_sourceFeeToken,
+ extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
+ });
+ }
+
+ function _generateEVM2AnyMessageNoTokens() internal view returns (Client.EVM2AnyMessage memory) {
+ return _generateEVM2AnyMessage(new Client.EVMTokenAmount[](0));
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/router/Router.t.sol b/contracts/src/v0.8/ccip/test/router/Router.t.sol
new file mode 100644
index 00000000000..cfe01e3c417
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/router/Router.t.sol
@@ -0,0 +1,889 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IAny2EVMMessageReceiver} from "../../interfaces/IAny2EVMMessageReceiver.sol";
+import {IRouter} from "../../interfaces/IRouter.sol";
+import {IRouterClient} from "../../interfaces/IRouterClient.sol";
+import {IWrappedNative} from "../../interfaces/IWrappedNative.sol";
+
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {EVM2EVMOnRamp} from "../../onRamp/EVM2EVMOnRamp.sol";
+import {MaybeRevertMessageReceiver} from "../helpers/receivers/MaybeRevertMessageReceiver.sol";
+import {EVM2EVMOffRampSetup} from "../offRamp/EVM2EVMOffRampSetup.t.sol";
+import {EVM2EVMOnRampSetup} from "../onRamp/EVM2EVMOnRampSetup.t.sol";
+import {RouterSetup} from "../router/RouterSetup.t.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract Router_constructor is EVM2EVMOnRampSetup {
+ function test_Constructor_Success() public view {
+ assertEq("Router 1.2.0", s_sourceRouter.typeAndVersion());
+ assertEq(OWNER, s_sourceRouter.owner());
+ }
+}
+
+contract Router_recoverTokens is EVM2EVMOnRampSetup {
+ function test_RecoverTokens_Success() public {
+ // Assert we can recover sourceToken
+ IERC20 token = IERC20(s_sourceTokens[0]);
+ uint256 balanceBefore = token.balanceOf(OWNER);
+ token.transfer(address(s_sourceRouter), 1);
+ assertEq(token.balanceOf(address(s_sourceRouter)), 1);
+ s_sourceRouter.recoverTokens(address(token), OWNER, 1);
+ assertEq(token.balanceOf(address(s_sourceRouter)), 0);
+ assertEq(token.balanceOf(OWNER), balanceBefore);
+
+ // Assert we can recover native
+ balanceBefore = OWNER.balance;
+ deal(address(s_sourceRouter), 10);
+ assertEq(address(s_sourceRouter).balance, 10);
+ s_sourceRouter.recoverTokens(address(0), OWNER, 10);
+ assertEq(OWNER.balance, balanceBefore + 10);
+ assertEq(address(s_sourceRouter).balance, 0);
+ }
+
+ function test_RecoverTokensNonOwner_Revert() public {
+ // Reverts if not owner
+ vm.startPrank(STRANGER);
+ vm.expectRevert("Only callable by owner");
+ s_sourceRouter.recoverTokens(address(0), STRANGER, 1);
+ }
+
+ function test_RecoverTokensInvalidRecipient_Revert() public {
+ vm.expectRevert(abi.encodeWithSelector(Router.InvalidRecipientAddress.selector, address(0)));
+ s_sourceRouter.recoverTokens(address(0), address(0), 1);
+ }
+
+ function test_RecoverTokensNoFunds_Revert() public {
+ // Reverts if no funds present
+ vm.expectRevert();
+ s_sourceRouter.recoverTokens(address(0), OWNER, 10);
+ }
+
+ function test_RecoverTokensValueReceiver_Revert() public {
+ MaybeRevertMessageReceiver revertingValueReceiver = new MaybeRevertMessageReceiver(true);
+ deal(address(s_sourceRouter), 10);
+
+ // Value receiver reverts
+ vm.expectRevert(Router.FailedToSendValue.selector);
+ s_sourceRouter.recoverTokens(address(0), address(revertingValueReceiver), 10);
+ }
+}
+
+contract Router_ccipSend is EVM2EVMOnRampSetup {
+ event Burned(address indexed sender, uint256 amount);
+
+ function test_CCIPSendLinkFeeOneTokenSuccess_gas() public {
+ vm.pauseGasMetering();
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ IERC20 sourceToken1 = IERC20(s_sourceTokens[1]);
+ sourceToken1.approve(address(s_sourceRouter), 2 ** 64);
+
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 2 ** 64;
+ message.tokenAmounts[0].token = s_sourceTokens[1];
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ assertGt(expectedFee, 0);
+
+ uint256 balanceBefore = sourceToken1.balanceOf(OWNER);
+
+ // Assert that the tokens are burned
+ vm.expectEmit();
+ emit Burned(address(s_onRamp), message.tokenAmounts[0].amount);
+
+ Internal.EVM2EVMMessage memory msgEvent = _messageToEvent(message, 1, 1, expectedFee, OWNER);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent);
+
+ vm.resumeGasMetering();
+ bytes32 messageId = s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ vm.pauseGasMetering();
+
+ assertEq(msgEvent.messageId, messageId);
+ // Assert the user balance is lowered by the tokenAmounts sent and the fee amount
+ uint256 expectedBalance = balanceBefore - (message.tokenAmounts[0].amount);
+ assertEq(expectedBalance, sourceToken1.balanceOf(OWNER));
+ vm.resumeGasMetering();
+ }
+
+ function test_CCIPSendLinkFeeNoTokenSuccess_gas() public {
+ vm.pauseGasMetering();
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ assertGt(expectedFee, 0);
+
+ Internal.EVM2EVMMessage memory msgEvent = _messageToEvent(message, 1, 1, expectedFee, OWNER);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent);
+
+ vm.resumeGasMetering();
+ bytes32 messageId = s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ vm.pauseGasMetering();
+
+ assertEq(msgEvent.messageId, messageId);
+ vm.resumeGasMetering();
+ }
+
+ function test_CCIPSendNativeFeeOneTokenSuccess_gas() public {
+ vm.pauseGasMetering();
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ IERC20 sourceToken1 = IERC20(s_sourceTokens[1]);
+ sourceToken1.approve(address(s_sourceRouter), 2 ** 64);
+
+ message.tokenAmounts = new Client.EVMTokenAmount[](1);
+ message.tokenAmounts[0].amount = 2 ** 64;
+ message.tokenAmounts[0].token = s_sourceTokens[1];
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ assertGt(expectedFee, 0);
+
+ uint256 balanceBefore = sourceToken1.balanceOf(OWNER);
+
+ // Assert that the tokens are burned
+ vm.expectEmit();
+ emit Burned(address(s_onRamp), message.tokenAmounts[0].amount);
+
+ // Native fees will be wrapped so we need to calculate the event with
+ // the wrapped native feeCoin address.
+ message.feeToken = s_sourceRouter.getWrappedNative();
+ Internal.EVM2EVMMessage memory msgEvent = _messageToEvent(message, 1, 1, expectedFee, OWNER);
+ // Set it to address(0) to indicate native
+ message.feeToken = address(0);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent);
+
+ vm.resumeGasMetering();
+ bytes32 messageId = s_sourceRouter.ccipSend{value: expectedFee}(DEST_CHAIN_SELECTOR, message);
+ vm.pauseGasMetering();
+
+ assertEq(msgEvent.messageId, messageId);
+ // Assert the user balance is lowered by the tokenAmounts sent and the fee amount
+ uint256 expectedBalance = balanceBefore - (message.tokenAmounts[0].amount);
+ assertEq(expectedBalance, sourceToken1.balanceOf(OWNER));
+ vm.resumeGasMetering();
+ }
+
+ function test_CCIPSendNativeFeeNoTokenSuccess_gas() public {
+ vm.pauseGasMetering();
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ assertGt(expectedFee, 0);
+
+ // Native fees will be wrapped so we need to calculate the event with
+ // the wrapped native feeCoin address.
+ message.feeToken = s_sourceRouter.getWrappedNative();
+ Internal.EVM2EVMMessage memory msgEvent = _messageToEvent(message, 1, 1, expectedFee, OWNER);
+ // Set it to address(0) to indicate native
+ message.feeToken = address(0);
+
+ vm.expectEmit();
+ emit EVM2EVMOnRamp.CCIPSendRequested(msgEvent);
+
+ vm.resumeGasMetering();
+ bytes32 messageId = s_sourceRouter.ccipSend{value: expectedFee}(DEST_CHAIN_SELECTOR, message);
+ vm.pauseGasMetering();
+
+ assertEq(msgEvent.messageId, messageId);
+ // Assert the user balance is lowered by the tokenAmounts sent and the fee amount
+ vm.resumeGasMetering();
+ }
+
+ function test_NonLinkFeeToken_Success() public {
+ EVM2EVMOnRamp.FeeTokenConfigArgs[] memory feeTokenConfigArgs = new EVM2EVMOnRamp.FeeTokenConfigArgs[](1);
+ feeTokenConfigArgs[0] = EVM2EVMOnRamp.FeeTokenConfigArgs({
+ token: s_sourceTokens[1],
+ networkFeeUSDCents: 1,
+ gasMultiplierWeiPerEth: 108e16,
+ premiumMultiplierWeiPerEth: 1e18,
+ enabled: true
+ });
+ s_onRamp.setFeeTokenConfig(feeTokenConfigArgs);
+
+ address[] memory feeTokens = new address[](1);
+ feeTokens[0] = s_sourceTokens[1];
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = s_sourceTokens[1];
+ IERC20(s_sourceTokens[1]).approve(address(s_sourceRouter), 2 ** 64);
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_NativeFeeToken_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = address(0); // Raw native
+ uint256 nativeQuote = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ vm.stopPrank();
+ hoax(address(1), 100 ether);
+ s_sourceRouter.ccipSend{value: nativeQuote}(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_NativeFeeTokenOverpay_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = address(0); // Raw native
+ uint256 nativeQuote = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ vm.stopPrank();
+ hoax(address(1), 100 ether);
+ s_sourceRouter.ccipSend{value: nativeQuote + 1}(DEST_CHAIN_SELECTOR, message);
+ // We expect the overpayment to be taken in full.
+ assertEq(address(1).balance, 100 ether - (nativeQuote + 1));
+ assertEq(address(s_sourceRouter).balance, 0);
+ }
+
+ function test_WrappedNativeFeeToken_Success() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = s_sourceRouter.getWrappedNative();
+ uint256 nativeQuote = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ vm.stopPrank();
+ hoax(address(1), 100 ether);
+ // Now address(1) has nativeQuote wrapped.
+ IWrappedNative(s_sourceRouter.getWrappedNative()).deposit{value: nativeQuote}();
+ IWrappedNative(s_sourceRouter.getWrappedNative()).approve(address(s_sourceRouter), nativeQuote);
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ // Since sending with zero fees is a legitimate use case for some destination
+ // chains, e.g. private chains, we want to make sure that we can still send even
+ // when the configured fee is 0.
+ function test_ZeroFeeAndGasPrice_Success() public {
+ // Configure a new fee token that has zero gas and zero fees but is still
+ // enabled and valid to pay with.
+ address feeTokenWithZeroFeeAndGas = s_sourceTokens[1];
+
+ // Set the new token as feeToken
+ address[] memory feeTokens = new address[](1);
+ feeTokens[0] = feeTokenWithZeroFeeAndGas;
+ s_priceRegistry.applyFeeTokensUpdates(feeTokens, new address[](0));
+
+ // Update the price of the newly set feeToken
+ Internal.PriceUpdates memory priceUpdates = getSingleTokenPriceUpdateStruct(feeTokenWithZeroFeeAndGas, 2_000 ether);
+ priceUpdates.gasPriceUpdates = getSingleGasPriceUpdateStruct(DEST_CHAIN_SELECTOR, 0).gasPriceUpdates;
+ s_priceRegistry.updatePrices(priceUpdates);
+
+ // Set the feeToken args on the onRamp
+ EVM2EVMOnRamp.FeeTokenConfigArgs[] memory feeTokenConfigArgs = new EVM2EVMOnRamp.FeeTokenConfigArgs[](1);
+ feeTokenConfigArgs[0] = EVM2EVMOnRamp.FeeTokenConfigArgs({
+ token: s_sourceTokens[1],
+ networkFeeUSDCents: 0,
+ gasMultiplierWeiPerEth: 108e16,
+ premiumMultiplierWeiPerEth: 1e18,
+ enabled: true
+ });
+
+ s_onRamp.setFeeTokenConfig(feeTokenConfigArgs);
+
+ // Send a message with the new feeToken
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = feeTokenWithZeroFeeAndGas;
+
+ // Fee should be 0 and sending should not revert
+ uint256 fee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ assertEq(fee, 0);
+
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ // Reverts
+
+ function test_WhenNotHealthy_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ s_mockRMN.setGlobalCursed(true);
+ vm.expectRevert(Router.BadARMSignal.selector);
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_UnsupportedDestinationChain_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ uint64 wrongChain = DEST_CHAIN_SELECTOR + 1;
+
+ vm.expectRevert(abi.encodeWithSelector(IRouterClient.UnsupportedDestinationChain.selector, wrongChain));
+
+ s_sourceRouter.ccipSend(wrongChain, message);
+ }
+
+ function test_Fuzz_UnsupportedFeeToken_Reverts(address wrongFeeToken) public {
+ // We have three fee tokens set, all others should revert.
+ vm.assume(address(s_sourceFeeToken) != wrongFeeToken);
+ vm.assume(address(s_sourceRouter.getWrappedNative()) != wrongFeeToken);
+ vm.assume(address(0) != wrongFeeToken);
+
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = wrongFeeToken;
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.NotAFeeToken.selector, wrongFeeToken));
+
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_Fuzz_UnsupportedToken_Reverts(address wrongToken) public {
+ for (uint256 i = 0; i < s_sourceTokens.length; ++i) {
+ vm.assume(address(s_sourceTokens[i]) != wrongToken);
+ }
+
+ for (uint256 i = 0; i < s_destTokens.length; ++i) {
+ vm.assume(address(s_destTokens[i]) != wrongToken);
+ }
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
+ tokenAmounts[0] = Client.EVMTokenAmount({token: wrongToken, amount: 1});
+ message.tokenAmounts = tokenAmounts;
+
+ vm.expectRevert(abi.encodeWithSelector(EVM2EVMOnRamp.UnsupportedToken.selector, wrongToken));
+
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_FeeTokenAmountTooLow_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ IERC20(s_sourceTokens[0]).approve(address(s_sourceRouter), 0);
+
+ vm.expectRevert("ERC20: insufficient allowance");
+
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_InvalidMsgValue() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ // Non-empty feeToken but with msg.value should revert
+ vm.stopPrank();
+ hoax(address(1), 1);
+ vm.expectRevert(IRouterClient.InvalidMsgValue.selector);
+ s_sourceRouter.ccipSend{value: 1}(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_NativeFeeTokenZeroValue() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = address(0); // Raw native
+ // Include no value, should revert
+ vm.expectRevert();
+ s_sourceRouter.ccipSend(DEST_CHAIN_SELECTOR, message);
+ }
+
+ function test_NativeFeeTokenInsufficientValue() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ message.feeToken = address(0); // Raw native
+ // Include insufficient, should also revert
+ vm.stopPrank();
+
+ s_onRamp.getFeeTokenConfig(s_sourceRouter.getWrappedNative());
+
+ hoax(address(1), 1);
+ vm.expectRevert(IRouterClient.InsufficientFeeTokenAmount.selector);
+ s_sourceRouter.ccipSend{value: 1}(DEST_CHAIN_SELECTOR, message);
+ }
+}
+
+contract Router_getArmProxy is RouterSetup {
+ function test_getArmProxy() public view {
+ assertEq(s_sourceRouter.getArmProxy(), address(s_mockRMN));
+ }
+}
+
+contract Router_applyRampUpdates is RouterSetup {
+ MaybeRevertMessageReceiver internal s_receiver;
+
+ function setUp() public virtual override(RouterSetup) {
+ RouterSetup.setUp();
+ s_receiver = new MaybeRevertMessageReceiver(false);
+ }
+
+ function assertOffRampRouteSucceeds(Router.OffRamp memory offRamp) internal {
+ vm.startPrank(offRamp.offRamp);
+
+ Client.Any2EVMMessage memory message = generateReceiverMessage(offRamp.sourceChainSelector);
+ vm.expectCall(address(s_receiver), abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message));
+ s_sourceRouter.routeMessage(message, GAS_FOR_CALL_EXACT_CHECK, 100_000, address(s_receiver));
+ }
+
+ function assertOffRampRouteReverts(Router.OffRamp memory offRamp) internal {
+ vm.startPrank(offRamp.offRamp);
+
+ vm.expectRevert(IRouter.OnlyOffRamp.selector);
+ s_sourceRouter.routeMessage(
+ generateReceiverMessage(offRamp.sourceChainSelector), GAS_FOR_CALL_EXACT_CHECK, 100_000, address(s_receiver)
+ );
+ }
+
+ function test_Fuzz_OffRampUpdates(address[20] memory offRampsInput) public {
+ Router.OffRamp[] memory offRamps = new Router.OffRamp[](20);
+
+ for (uint256 i = 0; i < offRampsInput.length; ++i) {
+ offRamps[i] = Router.OffRamp({sourceChainSelector: uint64(i), offRamp: offRampsInput[i]});
+ }
+
+ // Test adding offRamps
+ s_sourceRouter.applyRampUpdates(new Router.OnRamp[](0), new Router.OffRamp[](0), offRamps);
+
+ // There is no uniqueness guarantee on fuzz input, offRamps will not emit in case of a duplicate,
+ // hence cannot assert on number of offRamps event emissions, we need to use isOffRa
+ for (uint256 i = 0; i < offRamps.length; ++i) {
+ assertTrue(s_sourceRouter.isOffRamp(offRamps[i].sourceChainSelector, offRamps[i].offRamp));
+ }
+
+ // Test removing offRamps
+ s_sourceRouter.applyRampUpdates(new Router.OnRamp[](0), s_sourceRouter.getOffRamps(), new Router.OffRamp[](0));
+
+ assertEq(0, s_sourceRouter.getOffRamps().length);
+ for (uint256 i = 0; i < offRamps.length; ++i) {
+ assertFalse(s_sourceRouter.isOffRamp(offRamps[i].sourceChainSelector, offRamps[i].offRamp));
+ }
+
+ // Testing removing and adding in same call
+ s_sourceRouter.applyRampUpdates(new Router.OnRamp[](0), new Router.OffRamp[](0), offRamps);
+ s_sourceRouter.applyRampUpdates(new Router.OnRamp[](0), offRamps, offRamps);
+ for (uint256 i = 0; i < offRamps.length; ++i) {
+ assertTrue(s_sourceRouter.isOffRamp(offRamps[i].sourceChainSelector, offRamps[i].offRamp));
+ }
+ }
+
+ function test_OffRampUpdatesWithRouting() public {
+ // Explicitly construct chain selectors and ramp addresses so we have ramp uniqueness for the various test scenarios.
+ uint256 numberOfSelectors = 10;
+ uint64[] memory sourceChainSelectors = new uint64[](numberOfSelectors);
+ for (uint256 i = 0; i < numberOfSelectors; ++i) {
+ sourceChainSelectors[i] = uint64(i);
+ }
+
+ uint256 numberOfOffRamps = 5;
+ address[] memory offRamps = new address[](numberOfOffRamps);
+ for (uint256 i = 0; i < numberOfOffRamps; ++i) {
+ offRamps[i] = address(uint160(i * 10));
+ }
+
+ // 1st test scenario: add offramps.
+ // Check all the offramps are added correctly, and can route messages.
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](0);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](numberOfSelectors * numberOfOffRamps);
+
+ // Ensure there are multi-offramp source and multi-source offramps
+ for (uint256 i = 0; i < numberOfSelectors; ++i) {
+ for (uint256 j = 0; j < numberOfOffRamps; ++j) {
+ offRampUpdates[(i * numberOfOffRamps) + j] = Router.OffRamp(sourceChainSelectors[i], offRamps[j]);
+ }
+ }
+
+ for (uint256 i = 0; i < offRampUpdates.length; ++i) {
+ vm.expectEmit();
+ emit Router.OffRampAdded(offRampUpdates[i].sourceChainSelector, offRampUpdates[i].offRamp);
+ }
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+
+ Router.OffRamp[] memory gotOffRamps = s_sourceRouter.getOffRamps();
+ assertEq(offRampUpdates.length, gotOffRamps.length);
+
+ for (uint256 i = 0; i < offRampUpdates.length; ++i) {
+ assertEq(offRampUpdates[i].offRamp, gotOffRamps[i].offRamp);
+ assertTrue(s_sourceRouter.isOffRamp(offRampUpdates[i].sourceChainSelector, offRampUpdates[i].offRamp));
+ assertOffRampRouteSucceeds(offRampUpdates[i]);
+ }
+
+ vm.startPrank(OWNER);
+
+ // 2nd test scenario: partially remove existing offramps, add new offramps.
+ // Check offramps are removed correctly. Removed offramps cannot route messages.
+ // Check new offramps are added correctly. New offramps can route messages.
+ // Check unmodified offramps remain correct, and can still route messages.
+ uint256 numberOfPartialUpdates = offRampUpdates.length / 2;
+ Router.OffRamp[] memory partialOffRampRemoves = new Router.OffRamp[](numberOfPartialUpdates);
+ Router.OffRamp[] memory partialOffRampAdds = new Router.OffRamp[](numberOfPartialUpdates);
+ for (uint256 i = 0; i < numberOfPartialUpdates; ++i) {
+ partialOffRampRemoves[i] = offRampUpdates[i];
+ partialOffRampAdds[i] = Router.OffRamp({
+ sourceChainSelector: offRampUpdates[i].sourceChainSelector,
+ offRamp: address(uint160(offRampUpdates[i].offRamp) + 1e18) // Ensure unique new offRamps addresses
+ });
+ }
+
+ for (uint256 i = 0; i < numberOfPartialUpdates; ++i) {
+ vm.expectEmit();
+ emit Router.OffRampRemoved(partialOffRampRemoves[i].sourceChainSelector, partialOffRampRemoves[i].offRamp);
+ }
+ for (uint256 i = 0; i < numberOfPartialUpdates; ++i) {
+ vm.expectEmit();
+ emit Router.OffRampAdded(partialOffRampAdds[i].sourceChainSelector, partialOffRampAdds[i].offRamp);
+ }
+ s_sourceRouter.applyRampUpdates(onRampUpdates, partialOffRampRemoves, partialOffRampAdds);
+
+ gotOffRamps = s_sourceRouter.getOffRamps();
+ assertEq(offRampUpdates.length, gotOffRamps.length);
+
+ for (uint256 i = 0; i < numberOfPartialUpdates; ++i) {
+ assertFalse(
+ s_sourceRouter.isOffRamp(partialOffRampRemoves[i].sourceChainSelector, partialOffRampRemoves[i].offRamp)
+ );
+ assertOffRampRouteReverts(partialOffRampRemoves[i]);
+
+ assertTrue(s_sourceRouter.isOffRamp(partialOffRampAdds[i].sourceChainSelector, partialOffRampAdds[i].offRamp));
+ assertOffRampRouteSucceeds(partialOffRampAdds[i]);
+ }
+ for (uint256 i = numberOfPartialUpdates; i < offRampUpdates.length; ++i) {
+ assertTrue(s_sourceRouter.isOffRamp(offRampUpdates[i].sourceChainSelector, offRampUpdates[i].offRamp));
+ assertOffRampRouteSucceeds(offRampUpdates[i]);
+ }
+
+ vm.startPrank(OWNER);
+
+ // 3rd test scenario: remove all offRamps.
+ // Check all offramps have been removed, no offramp is able to route messages.
+ for (uint256 i = 0; i < numberOfPartialUpdates; ++i) {
+ vm.expectEmit();
+ emit Router.OffRampRemoved(partialOffRampAdds[i].sourceChainSelector, partialOffRampAdds[i].offRamp);
+ }
+ s_sourceRouter.applyRampUpdates(onRampUpdates, partialOffRampAdds, new Router.OffRamp[](0));
+
+ uint256 numberOfRemainingOfframps = offRampUpdates.length - numberOfPartialUpdates;
+ Router.OffRamp[] memory remainingOffRampRemoves = new Router.OffRamp[](numberOfRemainingOfframps);
+ for (uint256 i = 0; i < numberOfRemainingOfframps; ++i) {
+ remainingOffRampRemoves[i] = offRampUpdates[i + numberOfPartialUpdates];
+ }
+
+ for (uint256 i = 0; i < numberOfRemainingOfframps; ++i) {
+ vm.expectEmit();
+ emit Router.OffRampRemoved(remainingOffRampRemoves[i].sourceChainSelector, remainingOffRampRemoves[i].offRamp);
+ }
+ s_sourceRouter.applyRampUpdates(onRampUpdates, remainingOffRampRemoves, new Router.OffRamp[](0));
+
+ // Check there are no offRamps.
+ assertEq(0, s_sourceRouter.getOffRamps().length);
+
+ for (uint256 i = 0; i < numberOfPartialUpdates; ++i) {
+ assertFalse(s_sourceRouter.isOffRamp(partialOffRampAdds[i].sourceChainSelector, partialOffRampAdds[i].offRamp));
+ assertOffRampRouteReverts(partialOffRampAdds[i]);
+ }
+ for (uint256 i = 0; i < offRampUpdates.length; ++i) {
+ assertFalse(s_sourceRouter.isOffRamp(offRampUpdates[i].sourceChainSelector, offRampUpdates[i].offRamp));
+ assertOffRampRouteReverts(offRampUpdates[i]);
+ }
+
+ vm.startPrank(OWNER);
+
+ // 4th test scenario: add initial onRamps back.
+ // Check the offramps are added correctly, and can route messages.
+ // Check offramps that were not added back remain unset, and cannot route messages.
+ for (uint256 i = 0; i < offRampUpdates.length; ++i) {
+ vm.expectEmit();
+ emit Router.OffRampAdded(offRampUpdates[i].sourceChainSelector, offRampUpdates[i].offRamp);
+ }
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+
+ // Check initial offRamps are added back and can route to receiver.
+ gotOffRamps = s_sourceRouter.getOffRamps();
+ assertEq(offRampUpdates.length, gotOffRamps.length);
+
+ for (uint256 i = 0; i < offRampUpdates.length; ++i) {
+ assertEq(offRampUpdates[i].offRamp, gotOffRamps[i].offRamp);
+ assertTrue(s_sourceRouter.isOffRamp(offRampUpdates[i].sourceChainSelector, offRampUpdates[i].offRamp));
+ assertOffRampRouteSucceeds(offRampUpdates[i]);
+ }
+
+ // Check offramps that were not added back remain unset.
+ for (uint256 i = 0; i < numberOfPartialUpdates; ++i) {
+ assertFalse(s_sourceRouter.isOffRamp(partialOffRampAdds[i].sourceChainSelector, partialOffRampAdds[i].offRamp));
+ assertOffRampRouteReverts(partialOffRampAdds[i]);
+ }
+ }
+
+ function test_Fuzz_OnRampUpdates(Router.OnRamp[] memory onRamps) public {
+ // Test adding onRamps
+ for (uint256 i = 0; i < onRamps.length; ++i) {
+ vm.expectEmit();
+ emit Router.OnRampSet(onRamps[i].destChainSelector, onRamps[i].onRamp);
+ }
+
+ s_sourceRouter.applyRampUpdates(onRamps, new Router.OffRamp[](0), new Router.OffRamp[](0));
+
+ // Test setting onRamps to unsupported
+ for (uint256 i = 0; i < onRamps.length; ++i) {
+ onRamps[i].onRamp = address(0);
+
+ vm.expectEmit();
+ emit Router.OnRampSet(onRamps[i].destChainSelector, onRamps[i].onRamp);
+ }
+ s_sourceRouter.applyRampUpdates(onRamps, new Router.OffRamp[](0), new Router.OffRamp[](0));
+ for (uint256 i = 0; i < onRamps.length; ++i) {
+ assertEq(address(0), s_sourceRouter.getOnRamp(onRamps[i].destChainSelector));
+ assertFalse(s_sourceRouter.isChainSupported(onRamps[i].destChainSelector));
+ }
+ }
+
+ function test_OnRampDisable() public {
+ // Add onRamp
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](0);
+ address onRamp = address(uint160(2));
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: onRamp});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+ assertEq(onRamp, s_sourceRouter.getOnRamp(DEST_CHAIN_SELECTOR));
+ assertTrue(s_sourceRouter.isChainSupported(DEST_CHAIN_SELECTOR));
+
+ // Disable onRamp
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: address(0)});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), new Router.OffRamp[](0));
+ assertEq(address(0), s_sourceRouter.getOnRamp(DEST_CHAIN_SELECTOR));
+ assertFalse(s_sourceRouter.isChainSupported(DEST_CHAIN_SELECTOR));
+
+ // Re-enable onRamp
+ onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: onRamp});
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), new Router.OffRamp[](0));
+ assertEq(onRamp, s_sourceRouter.getOnRamp(DEST_CHAIN_SELECTOR));
+ assertTrue(s_sourceRouter.isChainSupported(DEST_CHAIN_SELECTOR));
+ }
+
+ function test_OnlyOwner_Revert() public {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](0);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](0);
+ s_sourceRouter.applyRampUpdates(onRampUpdates, offRampUpdates, offRampUpdates);
+ }
+
+ function test_OffRampMismatch_Revert() public {
+ address offRamp = address(uint160(2));
+
+ Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](0);
+ Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1);
+ offRampUpdates[0] = Router.OffRamp(DEST_CHAIN_SELECTOR, offRamp);
+
+ vm.expectEmit();
+ emit Router.OffRampAdded(DEST_CHAIN_SELECTOR, offRamp);
+ s_sourceRouter.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates);
+
+ offRampUpdates[0] = Router.OffRamp(SOURCE_CHAIN_SELECTOR, offRamp);
+
+ vm.expectRevert(abi.encodeWithSelector(Router.OffRampMismatch.selector, SOURCE_CHAIN_SELECTOR, offRamp));
+ s_sourceRouter.applyRampUpdates(onRampUpdates, offRampUpdates, offRampUpdates);
+ }
+}
+
+contract Router_setWrappedNative is EVM2EVMOnRampSetup {
+ function test_Fuzz_SetWrappedNative_Success(address wrappedNative) public {
+ s_sourceRouter.setWrappedNative(wrappedNative);
+ assertEq(wrappedNative, s_sourceRouter.getWrappedNative());
+ }
+
+ // Reverts
+ function test_OnlyOwner_Revert() public {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ s_sourceRouter.setWrappedNative(address(1));
+ }
+}
+
+contract Router_getSupportedTokens is EVM2EVMOnRampSetup {
+ function test_GetSupportedTokens_Revert() public {
+ vm.expectRevert(EVM2EVMOnRamp.GetSupportedTokensFunctionalityRemovedCheckAdminRegistry.selector);
+ s_onRamp.getSupportedTokens(DEST_CHAIN_SELECTOR);
+ }
+}
+
+contract Router_routeMessage is EVM2EVMOffRampSetup {
+ function setUp() public virtual override {
+ EVM2EVMOffRampSetup.setUp();
+ vm.startPrank(address(s_offRamp));
+ }
+
+ function generateManualGasLimit(uint256 callDataLength) internal view returns (uint256) {
+ return ((gasleft() - 2 * (16 * callDataLength + GAS_FOR_CALL_EXACT_CHECK)) * 62) / 64;
+ }
+
+ function test_ManualExec_Success() public {
+ Client.Any2EVMMessage memory message = generateReceiverMessage(SOURCE_CHAIN_SELECTOR);
+ // Manuel execution cannot run out of gas
+
+ (bool success, bytes memory retData, uint256 gasUsed) = s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR),
+ GAS_FOR_CALL_EXACT_CHECK,
+ generateManualGasLimit(message.data.length),
+ address(s_receiver)
+ );
+ assertTrue(success);
+ assertEq("", retData);
+ assertGt(gasUsed, 3_000);
+ }
+
+ function test_ExecutionEvent_Success() public {
+ Client.Any2EVMMessage memory message = generateReceiverMessage(SOURCE_CHAIN_SELECTOR);
+ // Should revert with reason
+ bytes memory realError1 = new bytes(2);
+ realError1[0] = 0xbe;
+ realError1[1] = 0xef;
+ s_reverting_receiver.setErr(realError1);
+
+ vm.expectEmit();
+ emit Router.MessageExecuted(
+ message.messageId,
+ message.sourceChainSelector,
+ address(s_offRamp),
+ keccak256(abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message))
+ );
+
+ (bool success, bytes memory retData, uint256 gasUsed) = s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR),
+ GAS_FOR_CALL_EXACT_CHECK,
+ generateManualGasLimit(message.data.length),
+ address(s_reverting_receiver)
+ );
+
+ assertFalse(success);
+ assertEq(abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, realError1), retData);
+ assertGt(gasUsed, 3_000);
+
+ // Reason is truncated
+ // Over the MAX_RET_BYTES limit (including offset and length word since we have a dynamic values), should be ignored
+ bytes memory realError2 = new bytes(32 * 2 + 1);
+ realError2[32 * 2 - 1] = 0xAA;
+ realError2[32 * 2] = 0xFF;
+ s_reverting_receiver.setErr(realError2);
+
+ vm.expectEmit();
+ emit Router.MessageExecuted(
+ message.messageId,
+ message.sourceChainSelector,
+ address(s_offRamp),
+ keccak256(abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message))
+ );
+
+ (success, retData, gasUsed) = s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR),
+ GAS_FOR_CALL_EXACT_CHECK,
+ generateManualGasLimit(message.data.length),
+ address(s_reverting_receiver)
+ );
+
+ assertFalse(success);
+ assertEq(
+ abi.encodeWithSelector(
+ MaybeRevertMessageReceiver.CustomError.selector,
+ uint256(32),
+ uint256(realError2.length),
+ uint256(0),
+ uint256(0xAA)
+ ),
+ retData
+ );
+ assertGt(gasUsed, 3_000);
+
+ // Should emit success
+ vm.expectEmit();
+ emit Router.MessageExecuted(
+ message.messageId,
+ message.sourceChainSelector,
+ address(s_offRamp),
+ keccak256(abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message))
+ );
+
+ (success, retData, gasUsed) = s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR),
+ GAS_FOR_CALL_EXACT_CHECK,
+ generateManualGasLimit(message.data.length),
+ address(s_receiver)
+ );
+
+ assertTrue(success);
+ assertEq("", retData);
+ assertGt(gasUsed, 3_000);
+ }
+
+ function test_Fuzz_ExecutionEvent_Success(bytes calldata error) public {
+ Client.Any2EVMMessage memory message = generateReceiverMessage(SOURCE_CHAIN_SELECTOR);
+ s_reverting_receiver.setErr(error);
+
+ bytes memory expectedRetData;
+
+ if (error.length >= 33) {
+ uint256 cutOff = error.length > 64 ? 64 : error.length;
+ vm.expectEmit();
+ emit Router.MessageExecuted(
+ message.messageId,
+ message.sourceChainSelector,
+ address(s_offRamp),
+ keccak256(abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message))
+ );
+ expectedRetData = abi.encodeWithSelector(
+ MaybeRevertMessageReceiver.CustomError.selector,
+ uint256(32),
+ uint256(error.length),
+ bytes32(error[:32]),
+ bytes32(error[32:cutOff])
+ );
+ } else {
+ vm.expectEmit();
+ emit Router.MessageExecuted(
+ message.messageId,
+ message.sourceChainSelector,
+ address(s_offRamp),
+ keccak256(abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message))
+ );
+ expectedRetData = abi.encodeWithSelector(MaybeRevertMessageReceiver.CustomError.selector, error);
+ }
+
+ (bool success, bytes memory retData,) = s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR),
+ GAS_FOR_CALL_EXACT_CHECK,
+ generateManualGasLimit(message.data.length),
+ address(s_reverting_receiver)
+ );
+
+ assertFalse(success);
+ assertEq(expectedRetData, retData);
+ }
+
+ function test_AutoExec_Success() public {
+ (bool success,,) = s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR), GAS_FOR_CALL_EXACT_CHECK, 100_000, address(s_receiver)
+ );
+
+ assertTrue(success);
+
+ (success,,) = s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR), GAS_FOR_CALL_EXACT_CHECK, 1, address(s_receiver)
+ );
+
+ // Can run out of gas, should return false
+ assertFalse(success);
+ }
+
+ // Reverts
+ function test_OnlyOffRamp_Revert() public {
+ vm.stopPrank();
+ vm.startPrank(STRANGER);
+
+ vm.expectRevert(IRouter.OnlyOffRamp.selector);
+ s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR), GAS_FOR_CALL_EXACT_CHECK, 100_000, address(s_receiver)
+ );
+ }
+
+ function test_WhenNotHealthy_Revert() public {
+ s_mockRMN.setGlobalCursed(true);
+ vm.expectRevert(Router.BadARMSignal.selector);
+ s_destRouter.routeMessage(
+ generateReceiverMessage(SOURCE_CHAIN_SELECTOR), GAS_FOR_CALL_EXACT_CHECK, 100_000, address(s_receiver)
+ );
+ }
+}
+
+contract Router_getFee is EVM2EVMOnRampSetup {
+ function test_GetFeeSupportedChain_Success() public view {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+ uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, message);
+ assertGt(expectedFee, 10e9);
+ }
+
+ // Reverts
+ function test_UnsupportedDestinationChain_Revert() public {
+ Client.EVM2AnyMessage memory message = _generateEmptyMessage();
+
+ vm.expectRevert(abi.encodeWithSelector(IRouterClient.UnsupportedDestinationChain.selector, 999));
+ s_sourceRouter.getFee(999, message);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/router/RouterSetup.t.sol b/contracts/src/v0.8/ccip/test/router/RouterSetup.t.sol
new file mode 100644
index 00000000000..de751617612
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/router/RouterSetup.t.sol
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Router} from "../../Router.sol";
+import {Client} from "../../libraries/Client.sol";
+import {Internal} from "../../libraries/Internal.sol";
+import {BaseTest} from "../BaseTest.t.sol";
+import {WETH9} from "../WETH9.sol";
+
+contract RouterSetup is BaseTest {
+ Router internal s_sourceRouter;
+ Router internal s_destRouter;
+
+ function setUp() public virtual override {
+ BaseTest.setUp();
+
+ if (address(s_sourceRouter) == address(0)) {
+ WETH9 weth = new WETH9();
+ s_sourceRouter = new Router(address(weth), address(s_mockRMN));
+ vm.label(address(s_sourceRouter), "sourceRouter");
+ }
+ if (address(s_destRouter) == address(0)) {
+ WETH9 weth = new WETH9();
+ s_destRouter = new Router(address(weth), address(s_mockRMN));
+ vm.label(address(s_destRouter), "destRouter");
+ }
+ }
+
+ function generateReceiverMessage(uint64 chainSelector) internal pure returns (Client.Any2EVMMessage memory) {
+ Client.EVMTokenAmount[] memory ta = new Client.EVMTokenAmount[](0);
+ return Client.Any2EVMMessage({
+ messageId: bytes32("a"),
+ sourceChainSelector: chainSelector,
+ sender: bytes("a"),
+ data: bytes("a"),
+ destTokenAmounts: ta
+ });
+ }
+
+ function generateSourceTokenData() internal pure returns (Internal.SourceTokenData memory) {
+ return Internal.SourceTokenData({
+ sourcePoolAddress: abi.encode(address(12312412312)),
+ destTokenAddress: abi.encode(address(9809808909)),
+ extraData: ""
+ });
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/tokenAdminRegistry/RegistryModuleOwnerCustom.t.sol b/contracts/src/v0.8/ccip/test/tokenAdminRegistry/RegistryModuleOwnerCustom.t.sol
new file mode 100644
index 00000000000..dfb599bd307
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/tokenAdminRegistry/RegistryModuleOwnerCustom.t.sol
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IGetCCIPAdmin} from "../../interfaces/IGetCCIPAdmin.sol";
+import {IOwner} from "../../interfaces/IOwner.sol";
+
+import {RegistryModuleOwnerCustom} from "../../tokenAdminRegistry/RegistryModuleOwnerCustom.sol";
+import {TokenAdminRegistry} from "../../tokenAdminRegistry/TokenAdminRegistry.sol";
+import {BurnMintERC677Helper} from "../helpers/BurnMintERC677Helper.sol";
+
+import {Test} from "forge-std/Test.sol";
+
+contract RegistryModuleOwnerCustomSetup is Test {
+ address internal constant OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e;
+
+ RegistryModuleOwnerCustom internal s_registryModuleOwnerCustom;
+ TokenAdminRegistry internal s_tokenAdminRegistry;
+ address internal s_token;
+
+ function setUp() public virtual {
+ vm.startPrank(OWNER);
+
+ s_tokenAdminRegistry = new TokenAdminRegistry();
+ s_token = address(new BurnMintERC677Helper("Test", "TST"));
+ s_registryModuleOwnerCustom = new RegistryModuleOwnerCustom(address(s_tokenAdminRegistry));
+ s_tokenAdminRegistry.addRegistryModule(address(s_registryModuleOwnerCustom));
+ }
+}
+
+contract RegistryModuleOwnerCustom_constructor is RegistryModuleOwnerCustomSetup {
+ function test_constructor_Revert() public {
+ vm.expectRevert(abi.encodeWithSelector(RegistryModuleOwnerCustom.AddressZero.selector));
+
+ new RegistryModuleOwnerCustom(address(0));
+ }
+}
+
+contract RegistryModuleOwnerCustom_registerAdminViaGetCCIPAdmin is RegistryModuleOwnerCustomSetup {
+ function test_registerAdminViaGetCCIPAdmin_Success() public {
+ assertEq(s_tokenAdminRegistry.getTokenConfig(s_token).administrator, address(0));
+
+ address expectedOwner = IGetCCIPAdmin(s_token).getCCIPAdmin();
+
+ vm.expectCall(s_token, abi.encodeWithSelector(IGetCCIPAdmin.getCCIPAdmin.selector), 1);
+ vm.expectCall(
+ address(s_tokenAdminRegistry),
+ abi.encodeWithSelector(TokenAdminRegistry.proposeAdministrator.selector, s_token, expectedOwner),
+ 1
+ );
+
+ vm.expectEmit();
+ emit RegistryModuleOwnerCustom.AdministratorRegistered(s_token, expectedOwner);
+
+ s_registryModuleOwnerCustom.registerAdminViaGetCCIPAdmin(s_token);
+
+ assertEq(s_tokenAdminRegistry.getTokenConfig(s_token).pendingAdministrator, OWNER);
+ }
+
+ function test_registerAdminViaGetCCIPAdmin_Revert() public {
+ address expectedOwner = IGetCCIPAdmin(s_token).getCCIPAdmin();
+
+ vm.startPrank(makeAddr("Not_expected_owner"));
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RegistryModuleOwnerCustom.CanOnlySelfRegister.selector, expectedOwner, s_token)
+ );
+
+ s_registryModuleOwnerCustom.registerAdminViaGetCCIPAdmin(s_token);
+ }
+}
+
+contract RegistryModuleOwnerCustom_registerAdminViaOwner is RegistryModuleOwnerCustomSetup {
+ function test_registerAdminViaOwner_Success() public {
+ assertEq(s_tokenAdminRegistry.getTokenConfig(s_token).administrator, address(0));
+
+ address expectedOwner = IOwner(s_token).owner();
+
+ vm.expectCall(s_token, abi.encodeWithSelector(IOwner.owner.selector), 1);
+ vm.expectCall(
+ address(s_tokenAdminRegistry),
+ abi.encodeWithSelector(TokenAdminRegistry.proposeAdministrator.selector, s_token, expectedOwner),
+ 1
+ );
+
+ vm.expectEmit();
+ emit RegistryModuleOwnerCustom.AdministratorRegistered(s_token, expectedOwner);
+
+ s_registryModuleOwnerCustom.registerAdminViaOwner(s_token);
+
+ assertEq(s_tokenAdminRegistry.getTokenConfig(s_token).pendingAdministrator, OWNER);
+ }
+
+ function test_registerAdminViaOwner_Revert() public {
+ address expectedOwner = IOwner(s_token).owner();
+
+ vm.startPrank(makeAddr("Not_expected_owner"));
+
+ vm.expectRevert(
+ abi.encodeWithSelector(RegistryModuleOwnerCustom.CanOnlySelfRegister.selector, expectedOwner, s_token)
+ );
+
+ s_registryModuleOwnerCustom.registerAdminViaOwner(s_token);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry.t.sol b/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry.t.sol
new file mode 100644
index 00000000000..ada0369045c
--- /dev/null
+++ b/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry.t.sol
@@ -0,0 +1,393 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IPoolV1} from "../../interfaces/IPool.sol";
+
+import {TokenAdminRegistry} from "../../tokenAdminRegistry/TokenAdminRegistry.sol";
+import {TokenSetup} from "../TokenSetup.t.sol";
+
+contract TokenAdminRegistrySetup is TokenSetup {
+ address internal s_registryModule = makeAddr("registryModule");
+
+ function setUp() public virtual override {
+ TokenSetup.setUp();
+
+ s_tokenAdminRegistry.addRegistryModule(s_registryModule);
+ }
+}
+
+contract TokenAdminRegistry_getPools is TokenAdminRegistrySetup {
+ function test_getPools_Success() public {
+ address[] memory tokens = new address[](1);
+ tokens[0] = s_sourceTokens[0];
+
+ address[] memory got = s_tokenAdminRegistry.getPools(tokens);
+ assertEq(got.length, 1);
+ assertEq(got[0], s_sourcePoolByToken[tokens[0]]);
+
+ got = s_tokenAdminRegistry.getPools(s_sourceTokens);
+ assertEq(got.length, s_sourceTokens.length);
+ for (uint256 i = 0; i < s_sourceTokens.length; i++) {
+ assertEq(got[i], s_sourcePoolByToken[s_sourceTokens[i]]);
+ }
+
+ address doesNotExist = makeAddr("doesNotExist");
+ tokens[0] = doesNotExist;
+ got = s_tokenAdminRegistry.getPools(tokens);
+ assertEq(got.length, 1);
+ assertEq(got[0], address(0));
+ }
+}
+
+contract TokenAdminRegistry_getPool is TokenAdminRegistrySetup {
+ function test_getPool_Success() public view {
+ address got = s_tokenAdminRegistry.getPool(s_sourceTokens[0]);
+ assertEq(got, s_sourcePoolByToken[s_sourceTokens[0]]);
+ }
+}
+
+contract TokenAdminRegistry_setPool is TokenAdminRegistrySetup {
+ function test_setPool_Success() public {
+ address pool = makeAddr("pool");
+ vm.mockCall(pool, abi.encodeWithSelector(IPoolV1.isSupportedToken.selector), abi.encode(true));
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.PoolSet(s_sourceTokens[0], s_sourcePoolByToken[s_sourceTokens[0]], pool);
+
+ s_tokenAdminRegistry.setPool(s_sourceTokens[0], pool);
+
+ assertEq(s_tokenAdminRegistry.getPool(s_sourceTokens[0]), pool);
+
+ // Assert the event is not emitted if the pool is the same as the current pool.
+ vm.recordLogs();
+ s_tokenAdminRegistry.setPool(s_sourceTokens[0], pool);
+
+ vm.assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ function test_setPool_ZeroAddressRemovesPool_Success() public {
+ address pool = makeAddr("pool");
+ vm.mockCall(pool, abi.encodeWithSelector(IPoolV1.isSupportedToken.selector), abi.encode(true));
+ s_tokenAdminRegistry.setPool(s_sourceTokens[0], pool);
+
+ assertEq(s_tokenAdminRegistry.getPool(s_sourceTokens[0]), pool);
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.PoolSet(s_sourceTokens[0], pool, address(0));
+
+ s_tokenAdminRegistry.setPool(s_sourceTokens[0], address(0));
+
+ assertEq(s_tokenAdminRegistry.getPool(s_sourceTokens[0]), address(0));
+ }
+
+ function test_setPool_InvalidTokenPoolToken_Revert() public {
+ address pool = makeAddr("pool");
+ vm.mockCall(pool, abi.encodeWithSelector(IPoolV1.isSupportedToken.selector), abi.encode(false));
+
+ vm.expectRevert(abi.encodeWithSelector(TokenAdminRegistry.InvalidTokenPoolToken.selector, s_sourceTokens[0]));
+ s_tokenAdminRegistry.setPool(s_sourceTokens[0], pool);
+ }
+
+ function test_setPool_OnlyAdministrator_Revert() public {
+ vm.stopPrank();
+
+ vm.expectRevert(
+ abi.encodeWithSelector(TokenAdminRegistry.OnlyAdministrator.selector, address(this), s_sourceTokens[0])
+ );
+ s_tokenAdminRegistry.setPool(s_sourceTokens[0], makeAddr("pool"));
+ }
+}
+
+contract TokenAdminRegistry_getAllConfiguredTokens is TokenAdminRegistrySetup {
+ function test_Fuzz_getAllConfiguredTokens_Success(uint8 numberOfTokens) public {
+ TokenAdminRegistry cleanTokenAdminRegistry = new TokenAdminRegistry();
+ for (uint160 i = 0; i < numberOfTokens; ++i) {
+ cleanTokenAdminRegistry.proposeAdministrator(address(i), address(i + 1000));
+ }
+
+ uint160 count = 0;
+ for (uint160 start = 0; start < numberOfTokens; start += count++) {
+ address[] memory got = cleanTokenAdminRegistry.getAllConfiguredTokens(uint64(start), uint64(count));
+ if (start + count > numberOfTokens) {
+ assertEq(got.length, numberOfTokens - start);
+ } else {
+ assertEq(got.length, count);
+ }
+
+ for (uint160 j = 0; j < got.length; ++j) {
+ assertEq(got[j], address(j + start));
+ }
+ }
+ }
+
+ function test_getAllConfiguredTokens_outOfBounds_Success() public view {
+ address[] memory tokens = s_tokenAdminRegistry.getAllConfiguredTokens(type(uint64).max, 10);
+ assertEq(tokens.length, 0);
+ }
+}
+
+contract TokenAdminRegistry_transferAdminRole is TokenAdminRegistrySetup {
+ function test_transferAdminRole_Success() public {
+ address token = s_sourceTokens[0];
+
+ address currentAdmin = s_tokenAdminRegistry.getTokenConfig(token).administrator;
+ address newAdmin = makeAddr("newAdmin");
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.AdministratorTransferRequested(token, currentAdmin, newAdmin);
+
+ s_tokenAdminRegistry.transferAdminRole(token, newAdmin);
+
+ TokenAdminRegistry.TokenConfig memory config = s_tokenAdminRegistry.getTokenConfig(token);
+
+ // Assert only the pending admin updates, without affecting the pending admin.
+ assertEq(config.pendingAdministrator, newAdmin);
+ assertEq(config.administrator, currentAdmin);
+ }
+
+ function test_transferAdminRole_OnlyAdministrator_Revert() public {
+ vm.stopPrank();
+
+ vm.expectRevert(
+ abi.encodeWithSelector(TokenAdminRegistry.OnlyAdministrator.selector, address(this), s_sourceTokens[0])
+ );
+ s_tokenAdminRegistry.transferAdminRole(s_sourceTokens[0], makeAddr("newAdmin"));
+ }
+}
+
+contract TokenAdminRegistry_acceptAdminRole is TokenAdminRegistrySetup {
+ function test_acceptAdminRole_Success() public {
+ address token = s_sourceTokens[0];
+
+ address currentAdmin = s_tokenAdminRegistry.getTokenConfig(token).administrator;
+ address newAdmin = makeAddr("newAdmin");
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.AdministratorTransferRequested(token, currentAdmin, newAdmin);
+
+ s_tokenAdminRegistry.transferAdminRole(token, newAdmin);
+
+ TokenAdminRegistry.TokenConfig memory config = s_tokenAdminRegistry.getTokenConfig(token);
+
+ // Assert only the pending admin updates, without affecting the pending admin.
+ assertEq(config.pendingAdministrator, newAdmin);
+ assertEq(config.administrator, currentAdmin);
+
+ vm.startPrank(newAdmin);
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.AdministratorTransferred(token, newAdmin);
+
+ s_tokenAdminRegistry.acceptAdminRole(token);
+
+ config = s_tokenAdminRegistry.getTokenConfig(token);
+
+ // Assert only the pending admin updates, without affecting the pending admin.
+ assertEq(config.pendingAdministrator, address(0));
+ assertEq(config.administrator, newAdmin);
+ }
+
+ function test_acceptAdminRole_OnlyPendingAdministrator_Revert() public {
+ address token = s_sourceTokens[0];
+ address currentAdmin = s_tokenAdminRegistry.getTokenConfig(token).administrator;
+ address newAdmin = makeAddr("newAdmin");
+
+ s_tokenAdminRegistry.transferAdminRole(token, newAdmin);
+
+ TokenAdminRegistry.TokenConfig memory config = s_tokenAdminRegistry.getTokenConfig(token);
+
+ // Assert only the pending admin updates, without affecting the pending admin.
+ assertEq(config.pendingAdministrator, newAdmin);
+ assertEq(config.administrator, currentAdmin);
+
+ address notNewAdmin = makeAddr("notNewAdmin");
+ vm.startPrank(notNewAdmin);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenAdminRegistry.OnlyPendingAdministrator.selector, notNewAdmin, token));
+ s_tokenAdminRegistry.acceptAdminRole(token);
+ }
+}
+
+contract TokenAdminRegistry_isAdministrator is TokenAdminRegistrySetup {
+ function test_isAdministrator_Success() public {
+ address newAdmin = makeAddr("newAdmin");
+ address newToken = makeAddr("newToken");
+ assertFalse(s_tokenAdminRegistry.isAdministrator(newToken, newAdmin));
+ assertFalse(s_tokenAdminRegistry.isAdministrator(newToken, OWNER));
+
+ s_tokenAdminRegistry.proposeAdministrator(newToken, newAdmin);
+ changePrank(newAdmin);
+ s_tokenAdminRegistry.acceptAdminRole(newToken);
+
+ assertTrue(s_tokenAdminRegistry.isAdministrator(newToken, newAdmin));
+ assertFalse(s_tokenAdminRegistry.isAdministrator(newToken, OWNER));
+ }
+}
+
+contract TokenAdminRegistry_proposeAdministrator is TokenAdminRegistrySetup {
+ function test_proposeAdministrator_module_Success() public {
+ vm.startPrank(s_registryModule);
+ address newAdmin = makeAddr("newAdmin");
+ address newToken = makeAddr("newToken");
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.AdministratorTransferRequested(newToken, address(0), newAdmin);
+
+ s_tokenAdminRegistry.proposeAdministrator(newToken, newAdmin);
+
+ assertEq(s_tokenAdminRegistry.getTokenConfig(newToken).pendingAdministrator, newAdmin);
+ assertEq(s_tokenAdminRegistry.getTokenConfig(newToken).administrator, address(0));
+ assertEq(s_tokenAdminRegistry.getTokenConfig(newToken).tokenPool, address(0));
+
+ changePrank(newAdmin);
+ s_tokenAdminRegistry.acceptAdminRole(newToken);
+
+ assertTrue(s_tokenAdminRegistry.isAdministrator(newToken, newAdmin));
+ }
+
+ function test_proposeAdministrator_owner_Success() public {
+ address newAdmin = makeAddr("newAdmin");
+ address newToken = makeAddr("newToken");
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.AdministratorTransferRequested(newToken, address(0), newAdmin);
+
+ s_tokenAdminRegistry.proposeAdministrator(newToken, newAdmin);
+
+ assertEq(s_tokenAdminRegistry.getTokenConfig(newToken).pendingAdministrator, newAdmin);
+
+ changePrank(newAdmin);
+ s_tokenAdminRegistry.acceptAdminRole(newToken);
+
+ assertTrue(s_tokenAdminRegistry.isAdministrator(newToken, newAdmin));
+ }
+
+ function test_proposeAdministrator_reRegisterWhileUnclaimed_Success() public {
+ address newAdmin = makeAddr("wrongAddress");
+ address newToken = makeAddr("newToken");
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.AdministratorTransferRequested(newToken, address(0), newAdmin);
+
+ s_tokenAdminRegistry.proposeAdministrator(newToken, newAdmin);
+
+ assertEq(s_tokenAdminRegistry.getTokenConfig(newToken).pendingAdministrator, newAdmin);
+
+ newAdmin = makeAddr("correctAddress");
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.AdministratorTransferRequested(newToken, address(0), newAdmin);
+
+ // Ensure we can still register the correct admin while the previous admin is unclaimed.
+ s_tokenAdminRegistry.proposeAdministrator(newToken, newAdmin);
+
+ changePrank(newAdmin);
+ s_tokenAdminRegistry.acceptAdminRole(newToken);
+
+ assertTrue(s_tokenAdminRegistry.isAdministrator(newToken, newAdmin));
+ }
+
+ mapping(address token => address admin) internal s_AdminByToken;
+
+ function test_Fuzz_proposeAdministrator_Success(address[50] memory tokens, address[50] memory admins) public {
+ TokenAdminRegistry cleanTokenAdminRegistry = new TokenAdminRegistry();
+ for (uint256 i = 0; i < tokens.length; i++) {
+ if (admins[i] == address(0)) {
+ continue;
+ }
+ if (cleanTokenAdminRegistry.getTokenConfig(tokens[i]).administrator != address(0)) {
+ continue;
+ }
+ cleanTokenAdminRegistry.proposeAdministrator(tokens[i], admins[i]);
+ s_AdminByToken[tokens[i]] = admins[i];
+ }
+
+ for (uint256 i = 0; i < tokens.length; i++) {
+ assertEq(cleanTokenAdminRegistry.getTokenConfig(tokens[i]).pendingAdministrator, s_AdminByToken[tokens[i]]);
+ }
+ }
+
+ function test_proposeAdministrator_OnlyRegistryModule_Revert() public {
+ address newToken = makeAddr("newToken");
+ vm.stopPrank();
+
+ vm.expectRevert(abi.encodeWithSelector(TokenAdminRegistry.OnlyRegistryModuleOrOwner.selector, address(this)));
+ s_tokenAdminRegistry.proposeAdministrator(newToken, OWNER);
+ }
+
+ function test_proposeAdministrator_ZeroAddress_Revert() public {
+ address newToken = makeAddr("newToken");
+
+ vm.expectRevert(abi.encodeWithSelector(TokenAdminRegistry.ZeroAddress.selector));
+ s_tokenAdminRegistry.proposeAdministrator(newToken, address(0));
+ }
+
+ function test_proposeAdministrator_AlreadyRegistered_Revert() public {
+ address newAdmin = makeAddr("newAdmin");
+ address newToken = makeAddr("newToken");
+
+ s_tokenAdminRegistry.proposeAdministrator(newToken, newAdmin);
+ changePrank(newAdmin);
+ s_tokenAdminRegistry.acceptAdminRole(newToken);
+
+ changePrank(OWNER);
+
+ vm.expectRevert(abi.encodeWithSelector(TokenAdminRegistry.AlreadyRegistered.selector, newToken));
+ s_tokenAdminRegistry.proposeAdministrator(newToken, newAdmin);
+ }
+}
+
+contract TokenAdminRegistry_addRegistryModule is TokenAdminRegistrySetup {
+ function test_addRegistryModule_Success() public {
+ address newModule = makeAddr("newModule");
+
+ s_tokenAdminRegistry.addRegistryModule(newModule);
+
+ assertTrue(s_tokenAdminRegistry.isRegistryModule(newModule));
+
+ // Assert the event is not emitted if the module is already added.
+ vm.recordLogs();
+ s_tokenAdminRegistry.addRegistryModule(newModule);
+
+ vm.assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ function test_addRegistryModule_OnlyOwner_Revert() public {
+ address newModule = makeAddr("newModule");
+ vm.stopPrank();
+
+ vm.expectRevert("Only callable by owner");
+ s_tokenAdminRegistry.addRegistryModule(newModule);
+ }
+}
+
+contract TokenAdminRegistry_removeRegistryModule is TokenAdminRegistrySetup {
+ function test_removeRegistryModule_Success() public {
+ address newModule = makeAddr("newModule");
+
+ s_tokenAdminRegistry.addRegistryModule(newModule);
+
+ assertTrue(s_tokenAdminRegistry.isRegistryModule(newModule));
+
+ vm.expectEmit();
+ emit TokenAdminRegistry.RegistryModuleRemoved(newModule);
+
+ s_tokenAdminRegistry.removeRegistryModule(newModule);
+
+ assertFalse(s_tokenAdminRegistry.isRegistryModule(newModule));
+
+ // Assert the event is not emitted if the module is already removed.
+ vm.recordLogs();
+ s_tokenAdminRegistry.removeRegistryModule(newModule);
+
+ vm.assertEq(vm.getRecordedLogs().length, 0);
+ }
+
+ function test_removeRegistryModule_OnlyOwner_Revert() public {
+ address newModule = makeAddr("newModule");
+ vm.stopPrank();
+
+ vm.expectRevert("Only callable by owner");
+ s_tokenAdminRegistry.removeRegistryModule(newModule);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/tokenAdminRegistry/RegistryModuleOwnerCustom.sol b/contracts/src/v0.8/ccip/tokenAdminRegistry/RegistryModuleOwnerCustom.sol
new file mode 100644
index 00000000000..3cd17df05f2
--- /dev/null
+++ b/contracts/src/v0.8/ccip/tokenAdminRegistry/RegistryModuleOwnerCustom.sol
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IGetCCIPAdmin} from "../interfaces/IGetCCIPAdmin.sol";
+import {IOwner} from "../interfaces/IOwner.sol";
+import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol";
+
+contract RegistryModuleOwnerCustom is ITypeAndVersion {
+ error CanOnlySelfRegister(address admin, address token);
+ error AddressZero();
+
+ event AdministratorRegistered(address indexed token, address indexed administrator);
+
+ string public constant override typeAndVersion = "RegistryModuleOwnerCustom 1.5.0-dev";
+
+ // The TokenAdminRegistry contract
+ ITokenAdminRegistry internal immutable i_tokenAdminRegistry;
+
+ constructor(address tokenAdminRegistry) {
+ if (tokenAdminRegistry == address(0)) {
+ revert AddressZero();
+ }
+ i_tokenAdminRegistry = ITokenAdminRegistry(tokenAdminRegistry);
+ }
+
+ /// @notice Registers the admin of the token using the `getCCIPAdmin` method.
+ /// @param token The token to register the admin for.
+ /// @dev The caller must be the admin returned by the `getCCIPAdmin` method.
+ function registerAdminViaGetCCIPAdmin(address token) external {
+ _registerAdmin(token, IGetCCIPAdmin(token).getCCIPAdmin());
+ }
+
+ /// @notice Registers the admin of the token using the `owner` method.
+ /// @param token The token to register the admin for.
+ /// @dev The caller must be the admin returned by the `owner` method.
+ function registerAdminViaOwner(address token) external {
+ _registerAdmin(token, IOwner(token).owner());
+ }
+
+ /// @notice Registers the admin of the token to msg.sender given that the
+ /// admin is equal to msg.sender.
+ /// @param token The token to register the admin for.
+ /// @param admin The caller must be the admin.
+ function _registerAdmin(address token, address admin) internal {
+ if (admin != msg.sender) {
+ revert CanOnlySelfRegister(admin, token);
+ }
+
+ i_tokenAdminRegistry.proposeAdministrator(token, admin);
+
+ emit AdministratorRegistered(token, admin);
+ }
+}
diff --git a/contracts/src/v0.8/ccip/tokenAdminRegistry/TokenAdminRegistry.sol b/contracts/src/v0.8/ccip/tokenAdminRegistry/TokenAdminRegistry.sol
new file mode 100644
index 00000000000..32394a396ec
--- /dev/null
+++ b/contracts/src/v0.8/ccip/tokenAdminRegistry/TokenAdminRegistry.sol
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+import {IPoolV1} from "../interfaces/IPool.sol";
+import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol";
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+
+import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/// @notice This contract stores the token pool configuration for all CCIP enabled tokens. It works
+/// on a self-serve basis, where tokens can be registered without intervention from the CCIP owner.
+/// @dev This contract is not considered upgradable, as it is a customer facing contract that will store
+/// significant amounts of data.
+contract TokenAdminRegistry is ITokenAdminRegistry, ITypeAndVersion, OwnerIsCreator {
+ using EnumerableSet for EnumerableSet.AddressSet;
+
+ error OnlyRegistryModuleOrOwner(address sender);
+ error OnlyAdministrator(address sender, address token);
+ error OnlyPendingAdministrator(address sender, address token);
+ error AlreadyRegistered(address token);
+ error ZeroAddress();
+ error InvalidTokenPoolToken(address token);
+
+ event PoolSet(address indexed token, address indexed previousPool, address indexed newPool);
+ event AdministratorTransferRequested(address indexed token, address indexed currentAdmin, address indexed newAdmin);
+ event AdministratorTransferred(address indexed token, address indexed newAdmin);
+ event DisableReRegistrationSet(address indexed token, bool disabled);
+ event RemovedAdministrator(address token);
+ event RegistryModuleAdded(address module);
+ event RegistryModuleRemoved(address indexed module);
+
+ // The struct is packed in a way that optimizes the attributes that are accessed together.
+ // solhint-disable-next-line gas-struct-packing
+ struct TokenConfig {
+ address administrator; // the current administrator of the token
+ address pendingAdministrator; // the address that is pending to become the new administrator
+ address tokenPool; // the token pool for this token. Can be address(0) if not deployed or not configured.
+ }
+
+ string public constant override typeAndVersion = "TokenAdminRegistry 1.5.0-dev";
+
+ // Mapping of token address to token configuration
+ mapping(address token => TokenConfig) internal s_tokenConfig;
+
+ // All tokens that have been configured
+ EnumerableSet.AddressSet internal s_tokens;
+
+ // Registry modules are allowed to register administrators for tokens
+ EnumerableSet.AddressSet internal s_registryModules;
+
+ /// @notice Returns all pools for the given tokens.
+ /// @dev Will return address(0) for tokens that do not have a pool.
+ function getPools(address[] calldata tokens) external view returns (address[] memory) {
+ address[] memory pools = new address[](tokens.length);
+ for (uint256 i = 0; i < tokens.length; ++i) {
+ pools[i] = s_tokenConfig[tokens[i]].tokenPool;
+ }
+ return pools;
+ }
+
+ /// @inheritdoc ITokenAdminRegistry
+ function getPool(address token) external view returns (address) {
+ return s_tokenConfig[token].tokenPool;
+ }
+
+ /// @notice Returns the configuration for a token.
+ /// @param token The token to get the configuration for.
+ /// @return config The configuration for the token.
+ function getTokenConfig(address token) external view returns (TokenConfig memory) {
+ return s_tokenConfig[token];
+ }
+
+ /// @notice Returns a list of tokens that are configured in the token admin registry.
+ /// @param startIndex Starting index in list, can be 0 if you want to start from the beginning.
+ /// @param maxCount Maximum number of tokens to retrieve. Since the list can be large,
+ /// it is recommended to use a paging mechanism to retrieve all tokens. If querying for very
+ /// large lists, RPCs can time out. If you want all tokens, use type(uint64).max.
+ /// @return tokens List of configured tokens.
+ /// @dev The function is paginated to avoid RPC timeouts.
+ /// @dev The ordering is guaranteed to remain the same as it is not possible to remove tokens
+ /// from s_tokens.
+ function getAllConfiguredTokens(uint64 startIndex, uint64 maxCount) external view returns (address[] memory tokens) {
+ uint256 numberOfTokens = s_tokens.length();
+ if (startIndex >= numberOfTokens) {
+ return tokens;
+ }
+ uint256 count = maxCount;
+ if (count + startIndex > numberOfTokens) {
+ count = numberOfTokens - startIndex;
+ }
+ tokens = new address[](count);
+ for (uint256 i = 0; i < count; ++i) {
+ tokens[i] = s_tokens.at(startIndex + i);
+ }
+
+ return tokens;
+ }
+
+ // ================================================================
+ // │ Administrator functions │
+ // ================================================================
+
+ /// @notice Sets the pool for a token. Setting the pool to address(0) effectively delists the token
+ /// from CCIP. Setting the pool to any other address enables the token on CCIP.
+ /// @param localToken The token to set the pool for.
+ /// @param pool The pool to set for the token.
+ function setPool(address localToken, address pool) external onlyTokenAdmin(localToken) {
+ // The pool has to support the token, but we want to allow removing the pool, so we only check
+ // if the pool supports the token if it is not address(0).
+ if (pool != address(0) && !IPoolV1(pool).isSupportedToken(localToken)) {
+ revert InvalidTokenPoolToken(localToken);
+ }
+
+ TokenConfig storage config = s_tokenConfig[localToken];
+
+ address previousPool = config.tokenPool;
+ config.tokenPool = pool;
+
+ if (previousPool != pool) {
+ emit PoolSet(localToken, previousPool, pool);
+ }
+ }
+
+ /// @notice Transfers the administrator role for a token to a new address with a 2-step process.
+ /// @param localToken The token to transfer the administrator role for.
+ /// @param newAdmin The address to transfer the administrator role to. Can be address(0) to cancel
+ /// a pending transfer.
+ /// @dev The new admin must call `acceptAdminRole` to accept the role.
+ function transferAdminRole(address localToken, address newAdmin) external onlyTokenAdmin(localToken) {
+ TokenConfig storage config = s_tokenConfig[localToken];
+ config.pendingAdministrator = newAdmin;
+
+ emit AdministratorTransferRequested(localToken, msg.sender, newAdmin);
+ }
+
+ /// @notice Accepts the administrator role for a token.
+ /// @param localToken The token to accept the administrator role for.
+ /// @dev This function can only be called by the pending administrator.
+ function acceptAdminRole(address localToken) external {
+ TokenConfig storage config = s_tokenConfig[localToken];
+ if (config.pendingAdministrator != msg.sender) {
+ revert OnlyPendingAdministrator(msg.sender, localToken);
+ }
+
+ config.administrator = msg.sender;
+ config.pendingAdministrator = address(0);
+
+ emit AdministratorTransferred(localToken, msg.sender);
+ }
+
+ // ================================================================
+ // │ Administrator config │
+ // ================================================================
+
+ /// @notice Public getter to check for permissions of an administrator
+ function isAdministrator(address localToken, address administrator) external view returns (bool) {
+ return s_tokenConfig[localToken].administrator == administrator;
+ }
+
+ /// @inheritdoc ITokenAdminRegistry
+ /// @dev Can only be called by a registry module.
+ function proposeAdministrator(address localToken, address administrator) external {
+ if (!isRegistryModule(msg.sender) && msg.sender != owner()) {
+ revert OnlyRegistryModuleOrOwner(msg.sender);
+ }
+ if (administrator == address(0)) {
+ revert ZeroAddress();
+ }
+ TokenConfig storage config = s_tokenConfig[localToken];
+
+ if (config.administrator != address(0)) {
+ revert AlreadyRegistered(localToken);
+ }
+
+ config.pendingAdministrator = administrator;
+
+ // We don't care if it's already in the set, as it's a no-op.
+ s_tokens.add(localToken);
+
+ emit AdministratorTransferRequested(localToken, address(0), administrator);
+ }
+
+ // ================================================================
+ // │ Registry Modules │
+ // ================================================================
+
+ /// @notice Checks if an address is a registry module.
+ /// @param module The address to check.
+ /// @return True if the address is a registry module, false otherwise.
+ function isRegistryModule(address module) public view returns (bool) {
+ return s_registryModules.contains(module);
+ }
+
+ /// @notice Adds a new registry module to the list of allowed modules.
+ /// @param module The module to add.
+ function addRegistryModule(address module) external onlyOwner {
+ if (s_registryModules.add(module)) {
+ emit RegistryModuleAdded(module);
+ }
+ }
+
+ /// @notice Removes a registry module from the list of allowed modules.
+ /// @param module The module to remove.
+ function removeRegistryModule(address module) external onlyOwner {
+ if (s_registryModules.remove(module)) {
+ emit RegistryModuleRemoved(module);
+ }
+ }
+
+ // ================================================================
+ // │ Access │
+ // ================================================================
+
+ /// @notice Checks if an address is the administrator of the given token.
+ modifier onlyTokenAdmin(address token) {
+ if (s_tokenConfig[token].administrator != msg.sender) {
+ revert OnlyAdministrator(msg.sender, token);
+ }
+ _;
+ }
+}
diff --git a/contracts/src/v0.8/ccip/v1.4-CCIP-License-grants.md b/contracts/src/v0.8/ccip/v1.4-CCIP-License-grants.md
new file mode 100644
index 00000000000..f206b8adcc1
--- /dev/null
+++ b/contracts/src/v0.8/ccip/v1.4-CCIP-License-grants.md
@@ -0,0 +1,5 @@
+v1.4-CCIP-License-grants
+
+Additional Use Grant(s):
+
+You may make use of the Cross-Chain Interoperability Protocol v1.4 (which is available subject to the license here the “Licensed Work ”) solely for purposes of importing client-side libraries or example clients to facilitate the integration of the Licensed Work into your application.
\ No newline at end of file
diff --git a/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol b/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol
index ba61584d0ab..2b8a82a2858 100644
--- a/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol
+++ b/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol
@@ -775,7 +775,9 @@ contract CapabilitiesRegistry is OwnerIsCreator, TypeAndVersionInterface {
/// @param nodes The nodes making up the DON
/// @param capabilityConfigurations The list of configurations for the
/// capabilities supported by the DON
- /// @param isPublic True if the DON is public
+ /// @param isPublic True if the DON is can accept external capability requests
+ /// @param acceptsWorkflows True if the DON can accept workflows
+ /// @param f The maximum number of faulty nodes the DON can tolerate
function addDON(
bytes32[] calldata nodes,
CapabilityConfiguration[] calldata capabilityConfigurations,
@@ -797,24 +799,32 @@ contract CapabilitiesRegistry is OwnerIsCreator, TypeAndVersionInterface {
/// the admin to reconfigure the list of capabilities supported
/// by the DON, the list of nodes that make up the DON as well
/// as whether or not the DON can accept external workflows
+ /// @param donId The ID of the DON to update
/// @param nodes The nodes making up the DON
/// @param capabilityConfigurations The list of configurations for the
/// capabilities supported by the DON
- /// @param isPublic True if the DON is can accept external workflows
+ /// @param isPublic True if the DON is can accept external capability requests
+ /// @param f The maximum number of nodes that can fail
function updateDON(
uint32 donId,
bytes32[] calldata nodes,
CapabilityConfiguration[] calldata capabilityConfigurations,
bool isPublic,
- bool acceptsWorkflows,
uint8 f
) external onlyOwner {
- uint32 configCount = s_dons[donId].configCount;
+ DON storage don = s_dons[donId];
+ uint32 configCount = don.configCount;
if (configCount == 0) revert DONDoesNotExist(donId);
_setDONConfig(
nodes,
capabilityConfigurations,
- DONParams({id: donId, configCount: ++configCount, isPublic: isPublic, acceptsWorkflows: acceptsWorkflows, f: f})
+ DONParams({
+ id: donId,
+ configCount: ++configCount,
+ isPublic: isPublic,
+ acceptsWorkflows: don.acceptsWorkflows,
+ f: f
+ })
);
}
@@ -961,6 +971,11 @@ contract CapabilitiesRegistry is OwnerIsCreator, TypeAndVersionInterface {
donCapabilityConfig.capabilityIds.push(configuration.capabilityId);
donCapabilityConfig.capabilityConfigs[configuration.capabilityId] = configuration.config;
+ s_dons[donParams.id].isPublic = donParams.isPublic;
+ s_dons[donParams.id].acceptsWorkflows = donParams.acceptsWorkflows;
+ s_dons[donParams.id].f = donParams.f;
+ s_dons[donParams.id].configCount = donParams.configCount;
+
_setDONCapabilityConfig(
donParams.id,
donParams.configCount,
@@ -969,10 +984,6 @@ contract CapabilitiesRegistry is OwnerIsCreator, TypeAndVersionInterface {
configuration.config
);
}
- s_dons[donParams.id].isPublic = donParams.isPublic;
- s_dons[donParams.id].acceptsWorkflows = donParams.acceptsWorkflows;
- s_dons[donParams.id].f = donParams.f;
- s_dons[donParams.id].configCount = donParams.configCount;
emit ConfigSet(donParams.id, donParams.configCount);
}
diff --git a/contracts/src/v0.8/keystone/KeystoneFeedsConsumer.sol b/contracts/src/v0.8/keystone/KeystoneFeedsConsumer.sol
index 9dc6f67560e..ba1a7c6a8c3 100644
--- a/contracts/src/v0.8/keystone/KeystoneFeedsConsumer.sol
+++ b/contracts/src/v0.8/keystone/KeystoneFeedsConsumer.sol
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
-import {IReceiver} from "./interfaces/IReceiver.sol";
+import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {OwnerIsCreator} from "../shared/access/OwnerIsCreator.sol";
+import {IReceiver} from "./interfaces/IReceiver.sol";
-contract KeystoneFeedsConsumer is IReceiver, OwnerIsCreator {
+contract KeystoneFeedsConsumer is IReceiver, OwnerIsCreator, IERC165 {
event FeedReceived(bytes32 indexed feedId, uint224 price, uint32 timestamp);
error UnauthorizedSender(address sender);
@@ -97,4 +98,8 @@ contract KeystoneFeedsConsumer is IReceiver, OwnerIsCreator {
StoredFeedReport memory report = s_feedReports[feedId];
return (report.Price, report.Timestamp);
}
+
+ function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
+ return interfaceId == this.onReport.selector;
+ }
}
diff --git a/contracts/src/v0.8/keystone/KeystoneForwarder.sol b/contracts/src/v0.8/keystone/KeystoneForwarder.sol
index 4b44feccbfe..f92295cab97 100644
--- a/contracts/src/v0.8/keystone/KeystoneForwarder.sol
+++ b/contracts/src/v0.8/keystone/KeystoneForwarder.sol
@@ -1,12 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
-import {IReceiver} from "./interfaces/IReceiver.sol";
-import {IRouter} from "./interfaces/IRouter.sol";
-import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
+import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol";
import {OwnerIsCreator} from "../shared/access/OwnerIsCreator.sol";
+import {IReceiver} from "./interfaces/IReceiver.sol";
+import {IRouter} from "./interfaces/IRouter.sol";
+
/// @notice This is an entry point for `write_${chain}` Target capability. It
/// allows nodes to determine if reports have been processed (successfully or
/// not) in a decentralized and product-agnostic way by recording processed
@@ -49,7 +51,7 @@ contract KeystoneForwarder is OwnerIsCreator, ITypeAndVersion, IRouter {
error InvalidConfig(uint64 configId);
/// @notice This error is thrown whenever a signer address is not in the
- /// configuration.
+ /// configuration or when trying to set a zero address as a signer.
/// @param signer The signer address that was not in the configuration
error InvalidSigner(address signer);
@@ -66,7 +68,7 @@ contract KeystoneForwarder is OwnerIsCreator, ITypeAndVersion, IRouter {
/// @notice Contains the configuration for each DON ID
// @param configId (uint64(donId) << 32) | configVersion
- mapping(uint64 configId => OracleSet) internal s_configs;
+ mapping(uint64 configId => OracleSet oracleSet) internal s_configs;
event ConfigSet(uint32 indexed donId, uint32 indexed configVersion, uint8 f, address[] signers);
@@ -90,12 +92,16 @@ contract KeystoneForwarder is OwnerIsCreator, ITypeAndVersion, IRouter {
uint256 internal constant FORWARDER_METADATA_LENGTH = 45;
uint256 internal constant SIGNATURE_LENGTH = 65;
+ /// @dev The gas we require to revert in case of a revert in the call to the
+ /// receiver. This is more than enough and does not attempt to be exact.
+ uint256 internal constant REQUIRED_GAS_FOR_ROUTING = 40_000;
+
// ================================================================
// │ Router │
// ================================================================
- mapping(address forwarder => bool) internal s_forwarders;
- mapping(bytes32 transmissionId => TransmissionInfo) internal s_transmissions;
+ mapping(address forwarder => bool isForwarder) internal s_forwarders;
+ mapping(bytes32 transmissionId => Transmission transmission) internal s_transmissions;
function addForwarder(address forwarder) external onlyOwner {
s_forwarders[forwarder] = true;
@@ -114,19 +120,38 @@ contract KeystoneForwarder is OwnerIsCreator, ITypeAndVersion, IRouter {
bytes calldata metadata,
bytes calldata validatedReport
) public returns (bool) {
- if (!s_forwarders[msg.sender]) {
- revert UnauthorizedForwarder();
- }
+ if (!s_forwarders[msg.sender]) revert UnauthorizedForwarder();
+ uint256 gasLeft = gasleft();
+ if (gasLeft < REQUIRED_GAS_FOR_ROUTING) revert InsufficientGasForRouting(transmissionId);
- if (s_transmissions[transmissionId].transmitter != address(0)) revert AlreadyAttempted(transmissionId);
+ Transmission memory transmission = s_transmissions[transmissionId];
+ if (transmission.success || transmission.invalidReceiver) revert AlreadyAttempted(transmissionId);
+
+ uint256 gasLimit = gasLeft - REQUIRED_GAS_FOR_ROUTING;
s_transmissions[transmissionId].transmitter = transmitter;
+ s_transmissions[transmissionId].gasLimit = uint80(gasLimit);
+
+ if (receiver.code.length == 0) {
+ s_transmissions[transmissionId].invalidReceiver = true;
+ return false;
+ }
- if (receiver.code.length == 0) return false;
+ try IERC165(receiver).supportsInterface(type(IReceiver).interfaceId) {
+ bool success;
+ bytes memory payload = abi.encodeCall(IReceiver.onReport, (metadata, validatedReport));
- try IReceiver(receiver).onReport(metadata, validatedReport) {
- s_transmissions[transmissionId].success = true;
- return true;
+ assembly {
+ // call and return whether we succeeded. ignore return data
+ // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
+ success := call(gasLimit, receiver, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
+ }
+
+ if (success) {
+ s_transmissions[transmissionId].success = true;
+ }
+ return success;
} catch {
+ s_transmissions[transmissionId].invalidReceiver = true;
return false;
}
}
@@ -141,26 +166,43 @@ contract KeystoneForwarder is OwnerIsCreator, ITypeAndVersion, IRouter {
return keccak256(bytes.concat(bytes20(uint160(receiver)), workflowExecutionId, reportId));
}
- /// @notice Get transmitter of a given report or 0x0 if it wasn't transmitted yet
- function getTransmitter(
+ function getTransmissionInfo(
address receiver,
bytes32 workflowExecutionId,
bytes2 reportId
- ) external view returns (address) {
- return s_transmissions[getTransmissionId(receiver, workflowExecutionId, reportId)].transmitter;
+ ) external view returns (TransmissionInfo memory) {
+ bytes32 transmissionId = getTransmissionId(receiver, workflowExecutionId, reportId);
+
+ Transmission memory transmission = s_transmissions[transmissionId];
+
+ TransmissionState state;
+
+ if (transmission.transmitter == address(0)) {
+ state = IRouter.TransmissionState.NOT_ATTEMPTED;
+ } else if (transmission.invalidReceiver) {
+ state = IRouter.TransmissionState.INVALID_RECEIVER;
+ } else {
+ state = transmission.success ? IRouter.TransmissionState.SUCCEEDED : IRouter.TransmissionState.FAILED;
+ }
+
+ return
+ TransmissionInfo({
+ gasLimit: transmission.gasLimit,
+ invalidReceiver: transmission.invalidReceiver,
+ state: state,
+ success: transmission.success,
+ transmissionId: transmissionId,
+ transmitter: transmission.transmitter
+ });
}
- /// @notice Get delivery status of a given report
- function getTransmissionState(
+ /// @notice Get transmitter of a given report or 0x0 if it wasn't transmitted yet
+ function getTransmitter(
address receiver,
bytes32 workflowExecutionId,
bytes2 reportId
- ) external view returns (IRouter.TransmissionState) {
- bytes32 transmissionId = getTransmissionId(receiver, workflowExecutionId, reportId);
-
- if (s_transmissions[transmissionId].transmitter == address(0)) return IRouter.TransmissionState.NOT_ATTEMPTED;
- return
- s_transmissions[transmissionId].success ? IRouter.TransmissionState.SUCCEEDED : IRouter.TransmissionState.FAILED;
+ ) external view returns (address) {
+ return s_transmissions[getTransmissionId(receiver, workflowExecutionId, reportId)].transmitter;
}
function isForwarder(address forwarder) external view returns (bool) {
@@ -187,6 +229,7 @@ contract KeystoneForwarder is OwnerIsCreator, ITypeAndVersion, IRouter {
for (uint256 i = 0; i < signers.length; ++i) {
// assign indices, detect duplicates
address signer = signers[i];
+ if (signer == address(0)) revert InvalidSigner(signer);
if (s_configs[configId]._positions[signer] != 0) revert DuplicateSigner(signer);
s_configs[configId]._positions[signer] = i + 1;
}
diff --git a/contracts/src/v0.8/keystone/OCR3Capability.sol b/contracts/src/v0.8/keystone/OCR3Capability.sol
index 8613a803b20..1ba934b1c40 100644
--- a/contracts/src/v0.8/keystone/OCR3Capability.sol
+++ b/contracts/src/v0.8/keystone/OCR3Capability.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {OCR2Base} from "./ocr/OCR2Base.sol";
diff --git a/contracts/src/v0.8/keystone/interfaces/ICapabilityConfiguration.sol b/contracts/src/v0.8/keystone/interfaces/ICapabilityConfiguration.sol
index 429c2a1d3aa..702d55dba9d 100644
--- a/contracts/src/v0.8/keystone/interfaces/ICapabilityConfiguration.sol
+++ b/contracts/src/v0.8/keystone/interfaces/ICapabilityConfiguration.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
/// @notice Interface for capability configuration contract. It MUST be
/// implemented for a contract to be used as a capability configuration.
diff --git a/contracts/src/v0.8/keystone/interfaces/IReceiver.sol b/contracts/src/v0.8/keystone/interfaces/IReceiver.sol
index f58c2da7ae1..debe58feea4 100644
--- a/contracts/src/v0.8/keystone/interfaces/IReceiver.sol
+++ b/contracts/src/v0.8/keystone/interfaces/IReceiver.sol
@@ -1,7 +1,12 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
/// @title IReceiver - receives keystone reports
interface IReceiver {
+ /// @notice Handles incoming keystone reports.
+ /// @dev If this function call reverts, it can be retried with a higher gas
+ /// limit. The receiver is responsible for discarding stale reports.
+ /// @param metadata Report's metadata.
+ /// @param report Workflow report.
function onReport(bytes calldata metadata, bytes calldata report) external;
}
diff --git a/contracts/src/v0.8/keystone/interfaces/IRouter.sol b/contracts/src/v0.8/keystone/interfaces/IRouter.sol
index a36c17c14d6..e40f3318679 100644
--- a/contracts/src/v0.8/keystone/interfaces/IRouter.sol
+++ b/contracts/src/v0.8/keystone/interfaces/IRouter.sol
@@ -1,9 +1,12 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
/// @title IRouter - delivers keystone reports to receiver
interface IRouter {
error UnauthorizedForwarder();
+ /// @dev Thrown when the gas limit is insufficient for handling state after
+ /// calling the receiver function.
+ error InsufficientGasForRouting(bytes32 transmissionId);
error AlreadyAttempted(bytes32 transmissionId);
event ForwarderAdded(address indexed forwarder);
@@ -12,12 +15,42 @@ interface IRouter {
enum TransmissionState {
NOT_ATTEMPTED,
SUCCEEDED,
+ INVALID_RECEIVER,
FAILED
}
+ struct Transmission {
+ address transmitter;
+ // This is true if the receiver is not a contract or does not implement the
+ // `IReceiver` interface.
+ bool invalidReceiver;
+ // Whether the transmission attempt was successful. If `false`, the
+ // transmission can be retried with an increased gas limit.
+ bool success;
+ // The amount of gas allocated for the `IReceiver.onReport` call. uint80
+ // allows storing gas for known EVM block gas limits.
+ // Ensures that the minimum gas requested by the user is available during
+ // the transmission attempt. If the transmission fails (indicated by a
+ // `false` success state), it can be retried with an increased gas limit.
+ uint80 gasLimit;
+ }
+
struct TransmissionInfo {
+ bytes32 transmissionId;
+ TransmissionState state;
address transmitter;
+ // This is true if the receiver is not a contract or does not implement the
+ // `IReceiver` interface.
+ bool invalidReceiver;
+ // Whether the transmission attempt was successful. If `false`, the
+ // transmission can be retried with an increased gas limit.
bool success;
+ // The amount of gas allocated for the `IReceiver.onReport` call. uint80
+ // allows storing gas for known EVM block gas limits.
+ // Ensures that the minimum gas requested by the user is available during
+ // the transmission attempt. If the transmission fails (indicated by a
+ // `false` success state), it can be retried with an increased gas limit.
+ uint80 gasLimit;
}
function addForwarder(address forwarder) external;
@@ -36,15 +69,14 @@ interface IRouter {
bytes32 workflowExecutionId,
bytes2 reportId
) external pure returns (bytes32);
- function getTransmitter(
+ function getTransmissionInfo(
address receiver,
bytes32 workflowExecutionId,
bytes2 reportId
- ) external view returns (address);
- function getTransmissionState(
+ ) external view returns (TransmissionInfo memory);
+ function getTransmitter(
address receiver,
bytes32 workflowExecutionId,
bytes2 reportId
- ) external view returns (TransmissionState);
- function isForwarder(address forwarder) external view returns (bool);
+ ) external view returns (address);
}
diff --git a/contracts/src/v0.8/keystone/ocr/OCR2Abstract.sol b/contracts/src/v0.8/keystone/ocr/OCR2Abstract.sol
index 083a4045344..3c1e304748f 100644
--- a/contracts/src/v0.8/keystone/ocr/OCR2Abstract.sol
+++ b/contracts/src/v0.8/keystone/ocr/OCR2Abstract.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
diff --git a/contracts/src/v0.8/keystone/test/BaseTest.t.sol b/contracts/src/v0.8/keystone/test/BaseTest.t.sol
index e637406c145..64dc018c3ac 100644
--- a/contracts/src/v0.8/keystone/test/BaseTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/BaseTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {Test} from "forge-std/Test.sol";
import {Constants} from "./Constants.t.sol";
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_AddDONTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_AddDONTest.t.sol
index fff6623a59b..dc0b85bfa3f 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_AddDONTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_AddDONTest.t.sol
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./BaseTest.t.sol";
import {ICapabilityConfiguration} from "../interfaces/ICapabilityConfiguration.sol";
import {CapabilitiesRegistry} from "../CapabilitiesRegistry.sol";
+import {MaliciousConfigurationContract} from "./mocks/MaliciousConfigurationContract.sol";
contract CapabilitiesRegistry_AddDONTest is BaseTest {
function setUp() public override {
@@ -245,3 +246,75 @@ contract CapabilitiesRegistry_AddDONTest is BaseTest {
assertEq(donInfo.nodeP2PIds[1], P2P_ID_THREE);
}
}
+
+contract CapabilitiesRegistry_AddDONTest_WhenMaliciousCapabilityConfigurationConfigured is BaseTest {
+ function setUp() public override {
+ BaseTest.setUp();
+ CapabilitiesRegistry.Capability[] memory capabilities = new CapabilitiesRegistry.Capability[](2);
+
+ address maliciousConfigContractAddr = address(
+ new MaliciousConfigurationContract(s_capabilityWithConfigurationContractId)
+ );
+ s_basicCapability.configurationContract = maliciousConfigContractAddr;
+ capabilities[0] = s_basicCapability;
+ capabilities[1] = s_capabilityWithConfigurationContract;
+
+ CapabilitiesRegistry.NodeOperator[] memory nodeOperators = _getNodeOperators();
+ nodeOperators[0].admin = maliciousConfigContractAddr;
+ nodeOperators[1].admin = maliciousConfigContractAddr;
+ nodeOperators[2].admin = maliciousConfigContractAddr;
+
+ s_CapabilitiesRegistry.addNodeOperators(nodeOperators);
+ s_CapabilitiesRegistry.addCapabilities(capabilities);
+
+ CapabilitiesRegistry.NodeParams[] memory nodes = new CapabilitiesRegistry.NodeParams[](3);
+ bytes32[] memory capabilityIds = new bytes32[](1);
+ capabilityIds[0] = s_basicHashedCapabilityId;
+
+ nodes[0] = CapabilitiesRegistry.NodeParams({
+ nodeOperatorId: TEST_NODE_OPERATOR_ONE_ID,
+ p2pId: P2P_ID,
+ signer: NODE_OPERATOR_ONE_SIGNER_ADDRESS,
+ hashedCapabilityIds: capabilityIds
+ });
+
+ bytes32[] memory nodeTwoCapabilityIds = new bytes32[](1);
+ nodeTwoCapabilityIds[0] = s_basicHashedCapabilityId;
+
+ nodes[1] = CapabilitiesRegistry.NodeParams({
+ nodeOperatorId: TEST_NODE_OPERATOR_TWO_ID,
+ p2pId: P2P_ID_TWO,
+ signer: NODE_OPERATOR_TWO_SIGNER_ADDRESS,
+ hashedCapabilityIds: nodeTwoCapabilityIds
+ });
+
+ nodes[2] = CapabilitiesRegistry.NodeParams({
+ nodeOperatorId: TEST_NODE_OPERATOR_THREE_ID,
+ p2pId: P2P_ID_THREE,
+ signer: NODE_OPERATOR_THREE_SIGNER_ADDRESS,
+ hashedCapabilityIds: capabilityIds
+ });
+
+ s_CapabilitiesRegistry.addNodes(nodes);
+
+ changePrank(ADMIN);
+ }
+
+ function test_RevertWhen_MaliciousCapabilitiesConfigContractTriesToRemoveCapabilitiesFromDONNodes() public {
+ bytes32[] memory nodes = new bytes32[](2);
+ nodes[0] = P2P_ID;
+ nodes[1] = P2P_ID_THREE;
+
+ CapabilitiesRegistry.CapabilityConfiguration[]
+ memory capabilityConfigs = new CapabilitiesRegistry.CapabilityConfiguration[](1);
+ capabilityConfigs[0] = CapabilitiesRegistry.CapabilityConfiguration({
+ capabilityId: s_basicHashedCapabilityId,
+ config: BASIC_CAPABILITY_CONFIG
+ });
+
+ vm.expectRevert(
+ abi.encodeWithSelector(CapabilitiesRegistry.CapabilityRequiredByDON.selector, s_basicHashedCapabilityId, DON_ID)
+ );
+ s_CapabilitiesRegistry.addDON(nodes, capabilityConfigs, true, true, F_VALUE);
+ }
+}
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_DeprecateCapabilitiesTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_DeprecateCapabilitiesTest.t.sol
index 4d289e7c745..e06fa4a703a 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_DeprecateCapabilitiesTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_DeprecateCapabilitiesTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./BaseTest.t.sol";
import {CapabilitiesRegistry} from "../CapabilitiesRegistry.sol";
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetCapabilitiesTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetCapabilitiesTest.t.sol
index 9702c62b9c7..8f39183ee79 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetCapabilitiesTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetCapabilitiesTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./BaseTest.t.sol";
import {CapabilitiesRegistry} from "../CapabilitiesRegistry.sol";
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetDONsTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetDONsTest.t.sol
index a83b1421d3c..a79485abad1 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetDONsTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetDONsTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./BaseTest.t.sol";
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetHashedCapabilityIdTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetHashedCapabilityIdTest.t.sol
index b9a6e6dc97a..cdfb0eb6439 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetHashedCapabilityIdTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetHashedCapabilityIdTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./BaseTest.t.sol";
import {CapabilityConfigurationContract} from "./mocks/CapabilityConfigurationContract.sol";
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetNodeOperatorsTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetNodeOperatorsTest.t.sol
index 36ef201a998..471f4a86ade 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetNodeOperatorsTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetNodeOperatorsTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./BaseTest.t.sol";
import {CapabilitiesRegistry} from "../CapabilitiesRegistry.sol";
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetNodesTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetNodesTest.t.sol
index 901e7b92728..a5fe5fa1d1a 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetNodesTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_GetNodesTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./BaseTest.t.sol";
import {CapabilitiesRegistry} from "../CapabilitiesRegistry.sol";
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_RemoveNodesTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_RemoveNodesTest.t.sol
index 9622c238766..08646600a67 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_RemoveNodesTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_RemoveNodesTest.t.sol
@@ -158,7 +158,7 @@ contract CapabilitiesRegistry_RemoveNodesTest is BaseTest {
bytes32[] memory updatedNodes = new bytes32[](2);
updatedNodes[0] = P2P_ID;
updatedNodes[1] = P2P_ID_THREE;
- s_CapabilitiesRegistry.updateDON(DON_ID, updatedNodes, capabilityConfigs, true, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(DON_ID, updatedNodes, capabilityConfigs, true, F_VALUE);
// Remove node
s_CapabilitiesRegistry.removeNodes(removedNodes);
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_UpdateDONTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_UpdateDONTest.t.sol
index 8b21b295067..825524ebe86 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_UpdateDONTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_UpdateDONTest.t.sol
@@ -71,7 +71,7 @@ contract CapabilitiesRegistry_UpdateDONTest is BaseTest {
capabilityId: s_basicHashedCapabilityId,
config: BASIC_CAPABILITY_CONFIG
});
- s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, F_VALUE);
}
function test_RevertWhen_NodeDoesNotSupportCapability() public {
@@ -91,7 +91,7 @@ contract CapabilitiesRegistry_UpdateDONTest is BaseTest {
s_capabilityWithConfigurationContractId
)
);
- s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, F_VALUE);
}
function test_RevertWhen_DONDoesNotExist() public {
@@ -106,7 +106,7 @@ contract CapabilitiesRegistry_UpdateDONTest is BaseTest {
config: BASIC_CAPABILITY_CONFIG
});
vm.expectRevert(abi.encodeWithSelector(CapabilitiesRegistry.DONDoesNotExist.selector, nonExistentDONId));
- s_CapabilitiesRegistry.updateDON(nonExistentDONId, nodes, capabilityConfigs, true, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(nonExistentDONId, nodes, capabilityConfigs, true, F_VALUE);
}
function test_RevertWhen_CapabilityDoesNotExist() public {
@@ -122,7 +122,7 @@ contract CapabilitiesRegistry_UpdateDONTest is BaseTest {
vm.expectRevert(
abi.encodeWithSelector(CapabilitiesRegistry.CapabilityDoesNotExist.selector, s_nonExistentHashedCapabilityId)
);
- s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, F_VALUE);
}
function test_RevertWhen_DuplicateCapabilityAdded() public {
@@ -144,7 +144,7 @@ contract CapabilitiesRegistry_UpdateDONTest is BaseTest {
vm.expectRevert(
abi.encodeWithSelector(CapabilitiesRegistry.DuplicateDONCapability.selector, 1, s_basicHashedCapabilityId)
);
- s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, F_VALUE);
}
function test_RevertWhen_DeprecatedCapabilityAdded() public {
@@ -165,7 +165,7 @@ contract CapabilitiesRegistry_UpdateDONTest is BaseTest {
});
vm.expectRevert(abi.encodeWithSelector(CapabilitiesRegistry.CapabilityIsDeprecated.selector, capabilityId));
- s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, F_VALUE);
}
function test_RevertWhen_DuplicateNodeAdded() public {
@@ -180,7 +180,7 @@ contract CapabilitiesRegistry_UpdateDONTest is BaseTest {
config: BASIC_CAPABILITY_CONFIG
});
vm.expectRevert(abi.encodeWithSelector(CapabilitiesRegistry.DuplicateDONNode.selector, 1, P2P_ID));
- s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, true, F_VALUE);
}
function test_UpdatesDON() public {
@@ -217,7 +217,7 @@ contract CapabilitiesRegistry_UpdateDONTest is BaseTest {
),
1
);
- s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, expectedDONIsPublic, true, F_VALUE);
+ s_CapabilitiesRegistry.updateDON(DON_ID, nodes, capabilityConfigs, expectedDONIsPublic, F_VALUE);
CapabilitiesRegistry.DONInfo memory donInfo = s_CapabilitiesRegistry.getDON(DON_ID);
assertEq(donInfo.id, DON_ID);
diff --git a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_UpdateNodeOperatorsTest.t.sol b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_UpdateNodeOperatorsTest.t.sol
index 721fd35eae7..8f6be580f49 100644
--- a/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_UpdateNodeOperatorsTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/CapabilitiesRegistry_UpdateNodeOperatorsTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./BaseTest.t.sol";
import {CapabilitiesRegistry} from "../CapabilitiesRegistry.sol";
diff --git a/contracts/src/v0.8/keystone/test/Constants.t.sol b/contracts/src/v0.8/keystone/test/Constants.t.sol
index 23c80eea9f1..a540a255725 100644
--- a/contracts/src/v0.8/keystone/test/Constants.t.sol
+++ b/contracts/src/v0.8/keystone/test/Constants.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
contract Constants {
address internal constant ADMIN = address(1);
diff --git a/contracts/src/v0.8/keystone/test/KeystoneForwarderBaseTest.t.sol b/contracts/src/v0.8/keystone/test/KeystoneForwarderBaseTest.t.sol
index 3b3c4060780..c106c2b2b21 100644
--- a/contracts/src/v0.8/keystone/test/KeystoneForwarderBaseTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/KeystoneForwarderBaseTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {Test} from "forge-std/Test.sol";
import {Receiver} from "./mocks/Receiver.sol";
diff --git a/contracts/src/v0.8/keystone/test/KeystoneForwarder_ReportTest.t.sol b/contracts/src/v0.8/keystone/test/KeystoneForwarder_ReportTest.t.sol
index ccb398fac5a..5363d87e92b 100644
--- a/contracts/src/v0.8/keystone/test/KeystoneForwarder_ReportTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/KeystoneForwarder_ReportTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./KeystoneForwarderBaseTest.t.sol";
import {IRouter} from "../interfaces/IRouter.sol";
@@ -141,15 +141,40 @@ contract KeystoneForwarder_ReportTest is BaseTest {
s_forwarder.report(address(s_receiver), report, reportContext, signatures);
}
- function test_RevertWhen_AlreadyAttempted() public {
- s_forwarder.report(address(s_receiver), report, reportContext, signatures);
+ function test_RevertWhen_RetryingSuccessfulTransmission() public {
+ s_forwarder.report{gas: 400_000}(address(s_receiver), report, reportContext, signatures);
bytes32 transmissionId = s_forwarder.getTransmissionId(address(s_receiver), executionId, reportId);
vm.expectRevert(abi.encodeWithSelector(IRouter.AlreadyAttempted.selector, transmissionId));
- s_forwarder.report(address(s_receiver), report, reportContext, signatures);
+ // Retyring with more gas
+ s_forwarder.report{gas: 450_000}(address(s_receiver), report, reportContext, signatures);
+ }
+
+ function test_RevertWhen_RetryingInvalidContractTransmission() public {
+ // Receiver is not a contract
+ address receiver = address(404);
+ s_forwarder.report{gas: 400_000}(receiver, report, reportContext, signatures);
+
+ bytes32 transmissionId = s_forwarder.getTransmissionId(receiver, executionId, reportId);
+ vm.expectRevert(abi.encodeWithSelector(IRouter.AlreadyAttempted.selector, transmissionId));
+ // Retyring with more gas
+ s_forwarder.report{gas: 450_000}(receiver, report, reportContext, signatures);
+ }
+
+ function test_RevertWhen_AttemptingTransmissionWithInsufficientGas() public {
+ bytes32 transmissionId = s_forwarder.getTransmissionId(address(s_receiver), executionId, reportId);
+ vm.expectRevert(abi.encodeWithSelector(IRouter.InsufficientGasForRouting.selector, transmissionId));
+ s_forwarder.report{gas: 50_000}(address(s_receiver), report, reportContext, signatures);
}
function test_Report_SuccessfulDelivery() public {
+ IRouter.TransmissionInfo memory transmissionInfo = s_forwarder.getTransmissionInfo(
+ address(s_receiver),
+ executionId,
+ reportId
+ );
+ assertEq(uint8(transmissionInfo.state), uint8(IRouter.TransmissionState.NOT_ATTEMPTED), "state mismatch");
+
vm.expectEmit(address(s_receiver));
emit MessageReceived(metadata, mercuryReports);
@@ -158,16 +183,31 @@ contract KeystoneForwarder_ReportTest is BaseTest {
s_forwarder.report(address(s_receiver), report, reportContext, signatures);
- assertEq(
- s_forwarder.getTransmitter(address(s_receiver), executionId, reportId),
- TRANSMITTER,
- "transmitter mismatch"
- );
- assertEq(
- uint8(s_forwarder.getTransmissionState(address(s_receiver), executionId, reportId)),
- uint8(IRouter.TransmissionState.SUCCEEDED),
- "TransmissionState mismatch"
+ transmissionInfo = s_forwarder.getTransmissionInfo(address(s_receiver), executionId, reportId);
+
+ assertEq(transmissionInfo.transmitter, TRANSMITTER, "transmitter mismatch");
+ assertEq(uint8(transmissionInfo.state), uint8(IRouter.TransmissionState.SUCCEEDED), "state mismatch");
+ assertGt(transmissionInfo.gasLimit, 100_000, "gas limit mismatch");
+ }
+
+ function test_Report_SuccessfulRetryWithMoreGas() public {
+ s_forwarder.report{gas: 200_000}(address(s_receiver), report, reportContext, signatures);
+
+ IRouter.TransmissionInfo memory transmissionInfo = s_forwarder.getTransmissionInfo(
+ address(s_receiver),
+ executionId,
+ reportId
);
+ // Expect to fail with the receiver running out of gas
+ assertEq(uint8(transmissionInfo.state), uint8(IRouter.TransmissionState.FAILED), "state mismatch");
+ assertGt(transmissionInfo.gasLimit, 100_000, "gas limit mismatch");
+
+ // Should succeed with more gas
+ s_forwarder.report{gas: 300_000}(address(s_receiver), report, reportContext, signatures);
+
+ transmissionInfo = s_forwarder.getTransmissionInfo(address(s_receiver), executionId, reportId);
+ assertEq(uint8(transmissionInfo.state), uint8(IRouter.TransmissionState.SUCCEEDED), "state mismatch");
+ assertGt(transmissionInfo.gasLimit, 200_000, "gas limit mismatch");
}
function test_Report_FailedDeliveryWhenReceiverNotContract() public {
@@ -179,29 +219,21 @@ contract KeystoneForwarder_ReportTest is BaseTest {
s_forwarder.report(receiver, report, reportContext, signatures);
- assertEq(s_forwarder.getTransmitter(receiver, executionId, reportId), TRANSMITTER, "transmitter mismatch");
- assertEq(
- uint8(s_forwarder.getTransmissionState(receiver, executionId, reportId)),
- uint8(IRouter.TransmissionState.FAILED),
- "TransmissionState mismatch"
- );
+ IRouter.TransmissionInfo memory transmissionInfo = s_forwarder.getTransmissionInfo(receiver, executionId, reportId);
+ assertEq(uint8(transmissionInfo.state), uint8(IRouter.TransmissionState.INVALID_RECEIVER), "state mismatch");
}
function test_Report_FailedDeliveryWhenReceiverInterfaceNotSupported() public {
// Receiver is a contract but doesn't implement the required interface
address receiver = address(s_forwarder);
- vm.expectEmit(address(s_forwarder));
+ vm.expectEmit(true, true, true, false);
emit ReportProcessed(receiver, executionId, reportId, false);
s_forwarder.report(receiver, report, reportContext, signatures);
- assertEq(s_forwarder.getTransmitter(receiver, executionId, reportId), TRANSMITTER, "transmitter mismatch");
- assertEq(
- uint8(s_forwarder.getTransmissionState(receiver, executionId, reportId)),
- uint8(IRouter.TransmissionState.FAILED),
- "TransmissionState mismatch"
- );
+ IRouter.TransmissionInfo memory transmissionInfo = s_forwarder.getTransmissionInfo(receiver, executionId, reportId);
+ assertEq(uint8(transmissionInfo.state), uint8(IRouter.TransmissionState.INVALID_RECEIVER), "state mismatch");
}
function test_Report_ConfigVersion() public {
diff --git a/contracts/src/v0.8/keystone/test/KeystoneForwarder_SetConfigTest.t.sol b/contracts/src/v0.8/keystone/test/KeystoneForwarder_SetConfigTest.t.sol
index 4b908bb702f..5dcf79b38ec 100644
--- a/contracts/src/v0.8/keystone/test/KeystoneForwarder_SetConfigTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/KeystoneForwarder_SetConfigTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./KeystoneForwarderBaseTest.t.sol";
import {KeystoneForwarder} from "../KeystoneForwarder.sol";
@@ -41,6 +41,14 @@ contract KeystoneForwarder_SetConfigTest is BaseTest {
s_forwarder.setConfig(DON_ID, CONFIG_VERSION, F, signers);
}
+ function test_RevertWhen_ProvidingZeroAddressSigner() public {
+ address[] memory signers = _getSignerAddresses();
+ signers[1] = address(0);
+
+ vm.expectRevert(abi.encodeWithSelector(KeystoneForwarder.InvalidSigner.selector, signers[1]));
+ s_forwarder.setConfig(DON_ID, CONFIG_VERSION, F, signers);
+ }
+
function test_SetConfig_FirstTime() public {
s_forwarder.setConfig(DON_ID, CONFIG_VERSION, F, _getSignerAddresses());
}
diff --git a/contracts/src/v0.8/keystone/test/KeystoneForwarder_TypeAndVersionTest.t.sol b/contracts/src/v0.8/keystone/test/KeystoneForwarder_TypeAndVersionTest.t.sol
index 8aad3766497..5a5cc70d2bb 100644
--- a/contracts/src/v0.8/keystone/test/KeystoneForwarder_TypeAndVersionTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/KeystoneForwarder_TypeAndVersionTest.t.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
import {BaseTest} from "./KeystoneForwarderBaseTest.t.sol";
diff --git a/contracts/src/v0.8/keystone/test/KeystoneRouter_AccessTest.t.sol b/contracts/src/v0.8/keystone/test/KeystoneRouter_AccessTest.t.sol
index c126f7ce31d..0e43b72bdc1 100644
--- a/contracts/src/v0.8/keystone/test/KeystoneRouter_AccessTest.t.sol
+++ b/contracts/src/v0.8/keystone/test/KeystoneRouter_AccessTest.t.sol
@@ -5,6 +5,7 @@ import {Test} from "forge-std/Test.sol";
import {IReceiver} from "../interfaces/IReceiver.sol";
import {IRouter} from "../interfaces/IRouter.sol";
import {KeystoneForwarder} from "../KeystoneForwarder.sol";
+import {Receiver} from "./mocks/Receiver.sol";
contract KeystoneRouter_SetConfigTest is Test {
address internal ADMIN = address(1);
@@ -18,10 +19,12 @@ contract KeystoneRouter_SetConfigTest is Test {
bytes32 internal id = hex"6d795f657865637574696f6e5f69640000000000000000000000000000000000";
KeystoneForwarder internal s_router;
+ Receiver internal s_receiver;
function setUp() public virtual {
vm.prank(ADMIN);
s_router = new KeystoneForwarder();
+ s_receiver = new Receiver();
}
function test_AddForwarder_RevertWhen_NotOwner() public {
@@ -36,6 +39,13 @@ contract KeystoneRouter_SetConfigTest is Test {
s_router.removeForwarder(FORWARDER);
}
+ function test_RemoveForwarder_Success() public {
+ vm.prank(ADMIN);
+ vm.expectEmit(true, false, false, false);
+ emit IRouter.ForwarderRemoved(FORWARDER);
+ s_router.removeForwarder(FORWARDER);
+ }
+
function test_Route_RevertWhen_UnauthorizedForwarder() public {
vm.prank(STRANGER);
vm.expectRevert(IRouter.UnauthorizedForwarder.selector);
@@ -50,8 +60,8 @@ contract KeystoneRouter_SetConfigTest is Test {
assertEq(s_router.isForwarder(FORWARDER), true);
vm.prank(FORWARDER);
- vm.mockCall(RECEIVER, abi.encodeCall(IReceiver.onReport, (metadata, report)), abi.encode());
- vm.expectCall(RECEIVER, abi.encodeCall(IReceiver.onReport, (metadata, report)));
- s_router.route(id, TRANSMITTER, RECEIVER, metadata, report);
+ vm.mockCall(address(s_receiver), abi.encodeCall(IReceiver.onReport, (metadata, report)), abi.encode());
+ vm.expectCall(address(s_receiver), abi.encodeCall(IReceiver.onReport, (metadata, report)));
+ s_router.route(id, TRANSMITTER, address(s_receiver), metadata, report);
}
}
diff --git a/contracts/src/v0.8/keystone/test/mocks/MaliciousConfigurationContract.sol b/contracts/src/v0.8/keystone/test/mocks/MaliciousConfigurationContract.sol
new file mode 100644
index 00000000000..72c2e23efeb
--- /dev/null
+++ b/contracts/src/v0.8/keystone/test/mocks/MaliciousConfigurationContract.sol
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.24;
+
+import {ICapabilityConfiguration} from "../../interfaces/ICapabilityConfiguration.sol";
+import {CapabilitiesRegistry} from "../../CapabilitiesRegistry.sol";
+import {ERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol";
+import {Constants} from "../Constants.t.sol";
+
+contract MaliciousConfigurationContract is ICapabilityConfiguration, ERC165, Constants {
+ bytes32 internal s_capabilityWithConfigurationContractId;
+
+ constructor(bytes32 capabilityWithConfigContractId) {
+ s_capabilityWithConfigurationContractId = capabilityWithConfigContractId;
+ }
+
+ function getCapabilityConfiguration(uint32) external view returns (bytes memory configuration) {
+ return bytes("");
+ }
+
+ function beforeCapabilityConfigSet(bytes32[] calldata, bytes calldata, uint64, uint32) external {
+ CapabilitiesRegistry.NodeParams[] memory nodes = new CapabilitiesRegistry.NodeParams[](2);
+ bytes32[] memory hashedCapabilityIds = new bytes32[](1);
+
+ hashedCapabilityIds[0] = s_capabilityWithConfigurationContractId;
+
+ // Set node one's signer to another address
+ nodes[0] = CapabilitiesRegistry.NodeParams({
+ nodeOperatorId: TEST_NODE_OPERATOR_ONE_ID,
+ p2pId: P2P_ID,
+ signer: NODE_OPERATOR_ONE_SIGNER_ADDRESS,
+ hashedCapabilityIds: hashedCapabilityIds
+ });
+
+ nodes[1] = CapabilitiesRegistry.NodeParams({
+ nodeOperatorId: TEST_NODE_OPERATOR_ONE_ID,
+ p2pId: P2P_ID_THREE,
+ signer: NODE_OPERATOR_THREE_SIGNER_ADDRESS,
+ hashedCapabilityIds: hashedCapabilityIds
+ });
+
+ CapabilitiesRegistry(msg.sender).updateNodes(nodes);
+ }
+
+ function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
+ return interfaceId == this.getCapabilityConfiguration.selector ^ this.beforeCapabilityConfigSet.selector;
+ }
+}
diff --git a/contracts/src/v0.8/keystone/test/mocks/Receiver.sol b/contracts/src/v0.8/keystone/test/mocks/Receiver.sol
index 25e8755641b..3c1f157bc4d 100644
--- a/contracts/src/v0.8/keystone/test/mocks/Receiver.sol
+++ b/contracts/src/v0.8/keystone/test/mocks/Receiver.sol
@@ -1,16 +1,24 @@
// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.19;
+pragma solidity 0.8.24;
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {IReceiver} from "../../interfaces/IReceiver.sol";
-contract Receiver is IReceiver {
+contract Receiver is IReceiver, IERC165 {
event MessageReceived(bytes metadata, bytes[] mercuryReports);
+ bytes public latestReport;
constructor() {}
function onReport(bytes calldata metadata, bytes calldata rawReport) external {
+ latestReport = rawReport;
+
// parse actual report
bytes[] memory mercuryReports = abi.decode(rawReport, (bytes[]));
emit MessageReceived(metadata, mercuryReports);
}
+
+ function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
+ return interfaceId == this.onReport.selector;
+ }
}
diff --git a/contracts/src/v0.8/liquiditymanager/LiquidityManager.sol b/contracts/src/v0.8/liquiditymanager/LiquidityManager.sol
new file mode 100644
index 00000000000..070930b904a
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/LiquidityManager.sol
@@ -0,0 +1,575 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBridgeAdapter} from "./interfaces/IBridge.sol";
+import {ILiquidityManager} from "./interfaces/ILiquidityManager.sol";
+import {ILiquidityContainer} from "./interfaces/ILiquidityContainer.sol";
+import {IWrappedNative} from "../ccip/interfaces/IWrappedNative.sol";
+
+import {OCR3Base} from "./ocr/OCR3Base.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 LiquidityManager for a single token over multiple chains.
+/// @dev This contract is designed to be used with the LockReleaseTokenPool contract but
+/// isn't constrained to it. It can be used with any contract that implements the ILiquidityContainer
+/// interface.
+/// @dev The OCR3 DON should only be able to transfer funds to other pre-approved contracts
+/// on other chains. Under no circumstances should it be able to transfer funds to arbitrary
+/// addresses. The owner is therefore in full control of the funds in this contract, not the DON.
+/// This is a security feature. The worst that can happen is that the DON can lock up funds in
+/// bridges, but it can't steal them.
+/// @dev References to local mean logic on the same chain as this contract is deployed on.
+/// References to remote mean logic on other chains.
+contract LiquidityManager is ILiquidityManager, OCR3Base {
+ using SafeERC20 for IERC20;
+
+ error ZeroAddress();
+ error InvalidRemoteChain(uint64 chainSelector);
+ error ZeroChainSelector();
+ error InsufficientLiquidity(uint256 requested, uint256 available, uint256 reserve);
+ error EmptyReport();
+ error TransferFailed();
+ error OnlyFinanceRole();
+
+ /// @notice Emitted when a finalization step is completed without funds being available.
+ /// @param ocrSeqNum The OCR sequence number of the report.
+ /// @param remoteChainSelector The chain selector of the remote chain funds are coming from.
+ /// @param bridgeSpecificData The bridge specific data that was used to finalize the transfer.
+ event FinalizationStepCompleted(
+ uint64 indexed ocrSeqNum,
+ uint64 indexed remoteChainSelector,
+ bytes bridgeSpecificData
+ );
+
+ /// @notice Emitted when the CLL finance role is set.
+ /// @param financeRole The address of the new finance role.
+ event FinanceRoleSet(address financeRole);
+
+ /// @notice Emitted when liquidity is transferred to another chain, or received from another chain.
+ /// @param ocrSeqNum The OCR sequence number of the report.
+ /// @param fromChainSelector The chain selector of the chain the funds are coming from.
+ /// In the event fromChainSelector == i_localChainSelector, this is an outgoing transfer.
+ /// Otherwise, it is an incoming transfer.
+ /// @param toChainSelector The chain selector of the chain the funds are going to.
+ /// In the event toChainSelector == i_localChainSelector, this is an incoming transfer.
+ /// Otherwise, it is an outgoing transfer.
+ /// @param to The address the funds are going to.
+ /// If this is address(this), the funds are arriving in this contract.
+ /// @param amount The amount of tokens being transferred.
+ /// @param bridgeSpecificData The bridge specific data that was passed to the local bridge adapter
+ /// when transferring the funds.
+ /// @param bridgeReturnData The return data from the local bridge adapter when transferring the funds.
+ event LiquidityTransferred(
+ uint64 indexed ocrSeqNum,
+ uint64 indexed fromChainSelector,
+ uint64 indexed toChainSelector,
+ address to,
+ uint256 amount,
+ bytes bridgeSpecificData,
+ bytes bridgeReturnData
+ );
+
+ /// @notice Emitted when liquidity is added to the local liquidity container.
+ /// @param provider The address of the provider that added the liquidity.
+ /// @param amount The amount of liquidity that was added.
+ event LiquidityAddedToContainer(address indexed provider, uint256 indexed amount);
+
+ /// @notice Emitted when liquidity is removed from the local liquidity container.
+ /// @param remover The address of the remover that removed the liquidity.
+ /// @param amount The amount of liquidity that was removed.
+ event LiquidityRemovedFromContainer(address indexed remover, uint256 indexed amount);
+
+ /// @notice Emitted when the local liquidity container is set.
+ /// @param newLiquidityContainer The address of the new liquidity container.
+ event LiquidityContainerSet(address indexed newLiquidityContainer);
+
+ /// @notice Emitted when the minimum liquidity is set.
+ /// @param oldBalance The old minimum liquidity.
+ /// @param newBalance The new minimum liquidity.
+ event MinimumLiquiditySet(uint256 oldBalance, uint256 newBalance);
+
+ /// @notice Emitted when someone sends native to this contract
+ /// @param amount The amount of native deposited
+ /// @param depositor The address that deposited the native
+ event NativeDeposited(uint256 amount, address depositor);
+
+ /// @notice Emitted when native balance is withdrawn by contract owner
+ /// @param amount The amount of native withdrawn
+ /// @param destination The address the native is sent to
+ event NativeWithdrawn(uint256 amount, address destination);
+
+ /// @notice Emitted when a cross chain rebalancer is set.
+ /// @param remoteChainSelector The chain selector of the remote chain.
+ /// @param localBridge The local bridge adapter that will be used to transfer funds.
+ /// @param remoteToken The address of the token on the remote chain.
+ /// @param remoteRebalancer The address of the remote rebalancer contract.
+ /// @param enabled Whether the rebalancer is enabled.
+ event CrossChainRebalancerSet(
+ uint64 indexed remoteChainSelector,
+ IBridgeAdapter localBridge,
+ address remoteToken,
+ address remoteRebalancer,
+ bool enabled
+ );
+
+ /// @notice Emitted when a finalization step fails.
+ /// @param ocrSeqNum The OCR sequence number of the report.
+ /// @param remoteChainSelector The chain selector of the remote chain funds are coming from.
+ /// @param bridgeSpecificData The bridge specific data that was used to finalize the transfer.
+ /// @param reason The reason the finalization failed.
+ event FinalizationFailed(
+ uint64 indexed ocrSeqNum,
+ uint64 indexed remoteChainSelector,
+ bytes bridgeSpecificData,
+ bytes reason
+ );
+
+ struct CrossChainRebalancer {
+ address remoteRebalancer;
+ IBridgeAdapter localBridge;
+ address remoteToken;
+ bool enabled;
+ }
+
+ string public constant override typeAndVersion = "LiquidityManager 1.0.0-dev";
+
+ /// @notice The token that this pool manages liquidity for.
+ IERC20 public immutable i_localToken;
+
+ /// @notice The chain selector belonging to the chain this pool is deployed on.
+ uint64 internal immutable i_localChainSelector;
+
+ /// @notice The target balance defines the expected amount of tokens for this network.
+ /// Setting the balance to 0 will disable any automated rebalancing operations.
+ uint256 internal s_minimumLiquidity;
+
+ /// @notice Mapping of chain selector to liquidity container on other chains
+ mapping(uint64 chainSelector => CrossChainRebalancer) private s_crossChainRebalancer;
+
+ uint64[] private s_supportedDestChains;
+
+ /// @notice The liquidity container on the local chain
+ /// @dev In the case of CCIP, this would be the token pool.
+ ILiquidityContainer private s_localLiquidityContainer;
+
+ /// @notice The CLL finance team multisig
+ address private s_finance;
+
+ constructor(
+ IERC20 token,
+ uint64 localChainSelector,
+ ILiquidityContainer localLiquidityContainer,
+ uint256 minimumLiquidity,
+ address finance
+ ) OCR3Base() {
+ if (localChainSelector == 0) {
+ revert ZeroChainSelector();
+ }
+
+ if (address(token) == address(0) || address(localLiquidityContainer) == address(0)) {
+ revert ZeroAddress();
+ }
+ i_localToken = token;
+ i_localChainSelector = localChainSelector;
+ s_localLiquidityContainer = localLiquidityContainer;
+ s_minimumLiquidity = minimumLiquidity;
+ s_finance = finance;
+ }
+
+ // ================================================================
+ // │ Native Management │
+ // ================================================================
+
+ receive() external payable {
+ emit NativeDeposited(msg.value, msg.sender);
+ }
+
+ /// @notice withdraw native balance
+ function withdrawNative(uint256 amount, address payable destination) external onlyFinance {
+ (bool success, ) = destination.call{value: amount}("");
+ if (!success) revert TransferFailed();
+
+ emit NativeWithdrawn(amount, destination);
+ }
+
+ // ================================================================
+ // │ Liquidity Management │
+ // ================================================================
+
+ /// @inheritdoc ILiquidityManager
+ function getLiquidity() public view returns (uint256 currentLiquidity) {
+ return i_localToken.balanceOf(address(s_localLiquidityContainer));
+ }
+
+ /// @notice Adds liquidity to the multi-chain system.
+ /// @dev Anyone can call this function, but anyone other than the owner should regard
+ /// adding liquidity as a donation to the system, as there is no way to get it out.
+ /// This function is open to anyone to be able to quickly add funds to the system
+ /// without having to go through potentially complicated multisig schemes to do it from
+ /// the owner address.
+ function addLiquidity(uint256 amount) external {
+ i_localToken.safeTransferFrom(msg.sender, address(this), amount);
+
+ // Make sure this is tether compatible, as they have strange approval requirements
+ // Should be good since all approvals are always immediately used.
+ i_localToken.safeApprove(address(s_localLiquidityContainer), amount);
+ s_localLiquidityContainer.provideLiquidity(amount);
+
+ emit LiquidityAddedToContainer(msg.sender, amount);
+ }
+
+ /// @notice Removes liquidity from the system and sends it to the caller, so the owner.
+ /// @dev Only the owner can call this function.
+ function removeLiquidity(uint256 amount) external onlyFinance {
+ uint256 currentBalance = getLiquidity();
+ if (currentBalance < amount) {
+ revert InsufficientLiquidity(amount, currentBalance, 0);
+ }
+
+ s_localLiquidityContainer.withdrawLiquidity(amount);
+ i_localToken.safeTransfer(msg.sender, amount);
+
+ emit LiquidityRemovedFromContainer(msg.sender, amount);
+ }
+
+ /// @notice escape hatch to manually withdraw any ERC20 token from the LM contract
+ /// @param token The address of the token to withdraw
+ /// @param amount The amount of tokens to withdraw
+ /// @param destination The address to send the tokens to
+ function withdrawERC20(address token, uint256 amount, address destination) external onlyFinance {
+ IERC20(token).safeTransfer(destination, amount);
+ }
+
+ /// @notice Transfers liquidity to another chain.
+ /// @dev This function is a public version of the internal _rebalanceLiquidity function.
+ /// to allow the owner to also initiate a rebalancing when needed.
+ function rebalanceLiquidity(
+ uint64 chainSelector,
+ uint256 amount,
+ uint256 nativeBridgeFee,
+ bytes calldata bridgeSpecificPayload
+ ) external onlyFinance {
+ _rebalanceLiquidity(chainSelector, amount, nativeBridgeFee, type(uint64).max, bridgeSpecificPayload);
+ }
+
+ /// @notice Finalizes liquidity from another chain.
+ /// @dev This function is a public version of the internal _receiveLiquidity function.
+ /// to allow the owner to also initiate a finalization when needed.
+ function receiveLiquidity(
+ uint64 remoteChainSelector,
+ uint256 amount,
+ bool shouldWrapNative,
+ bytes calldata bridgeSpecificPayload
+ ) external onlyFinance {
+ _receiveLiquidity(remoteChainSelector, amount, bridgeSpecificPayload, shouldWrapNative, type(uint64).max);
+ }
+
+ /// @notice Transfers liquidity to another chain.
+ /// @dev Called by both the owner and the DON.
+ /// @param chainSelector The chain selector of the chain to transfer liquidity to.
+ /// @param tokenAmount The amount of tokens to transfer.
+ /// @param nativeBridgeFee The fee to pay to the bridge.
+ /// @param ocrSeqNum The OCR sequence number of the report.
+ /// @param bridgeSpecificPayload The bridge specific data to pass to the bridge adapter.
+ function _rebalanceLiquidity(
+ uint64 chainSelector,
+ uint256 tokenAmount,
+ uint256 nativeBridgeFee,
+ uint64 ocrSeqNum,
+ bytes memory bridgeSpecificPayload
+ ) internal {
+ uint256 currentBalance = getLiquidity();
+ uint256 minBalance = s_minimumLiquidity;
+ if (currentBalance < minBalance || currentBalance - minBalance < tokenAmount) {
+ revert InsufficientLiquidity(tokenAmount, currentBalance, minBalance);
+ }
+
+ CrossChainRebalancer memory remoteLiqManager = s_crossChainRebalancer[chainSelector];
+
+ if (!remoteLiqManager.enabled) {
+ revert InvalidRemoteChain(chainSelector);
+ }
+
+ // XXX: Could be optimized by withdrawing once and then sending to all destinations
+ s_localLiquidityContainer.withdrawLiquidity(tokenAmount);
+ i_localToken.safeApprove(address(remoteLiqManager.localBridge), tokenAmount);
+
+ bytes memory bridgeReturnData = remoteLiqManager.localBridge.sendERC20{value: nativeBridgeFee}(
+ address(i_localToken),
+ remoteLiqManager.remoteToken,
+ remoteLiqManager.remoteRebalancer,
+ tokenAmount,
+ bridgeSpecificPayload
+ );
+
+ emit LiquidityTransferred(
+ ocrSeqNum,
+ i_localChainSelector,
+ chainSelector,
+ remoteLiqManager.remoteRebalancer,
+ tokenAmount,
+ bridgeSpecificPayload,
+ bridgeReturnData
+ );
+ }
+
+ /// @notice Receives liquidity from another chain.
+ /// @dev Called by both the owner and the DON.
+ /// @param remoteChainSelector The chain selector of the chain to receive liquidity from.
+ /// @param amount The amount of tokens to receive.
+ /// @param bridgeSpecificPayload The bridge specific data to pass to the bridge adapter finalizeWithdrawERC20 call.
+ /// @param shouldWrapNative Whether the token should be wrapped before injecting it into the liquidity container.
+ /// This only applies to native tokens wrapper contracts, e.g WETH.
+ /// @param ocrSeqNum The OCR sequence number of the report.
+ function _receiveLiquidity(
+ uint64 remoteChainSelector,
+ uint256 amount,
+ bytes memory bridgeSpecificPayload,
+ bool shouldWrapNative,
+ uint64 ocrSeqNum
+ ) internal {
+ // check if the remote chain is supported
+ CrossChainRebalancer memory remoteRebalancer = s_crossChainRebalancer[remoteChainSelector];
+ if (!remoteRebalancer.enabled) {
+ revert InvalidRemoteChain(remoteChainSelector);
+ }
+
+ // finalize the withdrawal through the bridge adapter
+ try
+ remoteRebalancer.localBridge.finalizeWithdrawERC20(
+ remoteRebalancer.remoteRebalancer, // remoteSender: the remote rebalancer
+ address(this), // localReceiver: this contract
+ bridgeSpecificPayload
+ )
+ returns (bool fundsAvailable) {
+ if (fundsAvailable) {
+ // finalization was successful and we can inject the liquidity into the container.
+ // approve and liquidity container should transferFrom.
+ _injectLiquidity(amount, ocrSeqNum, remoteChainSelector, bridgeSpecificPayload, shouldWrapNative);
+ } else {
+ // a finalization step was completed, but funds are not available.
+ // hence, we cannot inject any liquidity yet.
+ emit FinalizationStepCompleted(ocrSeqNum, remoteChainSelector, bridgeSpecificPayload);
+ }
+
+ // return here on the happy path.
+ // sad path is when finalizeWithdrawERC20 reverts, which is handled after the catch block.
+ return;
+ } catch (bytes memory lowLevelData) {
+ // failed to finalize the withdrawal.
+ // this could mean that the withdrawal was already finalized
+ // or that the withdrawal failed.
+ // we assume the former and continue
+ emit FinalizationFailed(ocrSeqNum, remoteChainSelector, bridgeSpecificPayload, lowLevelData);
+ }
+
+ // if we reach this point, the finalization failed.
+ // since we don't have enough information to know why it failed,
+ // we assume that it failed because the withdrawal was already finalized,
+ // and that the funds are available.
+ _injectLiquidity(amount, ocrSeqNum, remoteChainSelector, bridgeSpecificPayload, shouldWrapNative);
+ }
+
+ /// @notice Injects liquidity into the local liquidity container.
+ /// @param amount The amount of tokens to inject.
+ /// @param ocrSeqNum The OCR sequence number of the report.
+ /// @param remoteChainSelector The chain selector of the remote chain.
+ /// @param bridgeSpecificPayload The bridge specific data passed to the bridge adapter finalizeWithdrawERC20 call.
+ /// @param shouldWrapNative Whether the token should be wrapped before injecting it into the liquidity container.
+ function _injectLiquidity(
+ uint256 amount,
+ uint64 ocrSeqNum,
+ uint64 remoteChainSelector,
+ bytes memory bridgeSpecificPayload,
+ bool shouldWrapNative
+ ) private {
+ // We trust the DON or the owner (the only two actors who can end up calling this function)
+ // to correctly set the shouldWrapNative flag.
+ // Some bridges only bridge native and not wrapped native.
+ // In such a case we need to re-wrap the native in order to inject it into the liquidity container.
+ // TODO: escape hatch in case of bug?
+ if (shouldWrapNative) {
+ IWrappedNative(address(i_localToken)).deposit{value: amount}();
+ }
+
+ i_localToken.safeIncreaseAllowance(address(s_localLiquidityContainer), amount);
+ s_localLiquidityContainer.provideLiquidity(amount);
+
+ emit LiquidityTransferred(
+ ocrSeqNum,
+ remoteChainSelector,
+ i_localChainSelector,
+ address(this),
+ amount,
+ bridgeSpecificPayload,
+ bytes("") // no bridge return data when receiving
+ );
+ }
+
+ /// @notice Process the OCR report.
+ /// @dev Called by OCR3Base's transmit() function.
+ function _report(bytes calldata report, uint64 ocrSeqNum) internal override {
+ ILiquidityManager.LiquidityInstructions memory instructions = abi.decode(
+ report,
+ (ILiquidityManager.LiquidityInstructions)
+ );
+
+ uint256 sendInstructions = instructions.sendLiquidityParams.length;
+ uint256 receiveInstructions = instructions.receiveLiquidityParams.length;
+
+ // There should always be instructions to send or receive, if not, the report is invalid
+ // and we revert to save the gas of the signature validation of OCR.
+ if (sendInstructions == 0 && receiveInstructions == 0) {
+ revert EmptyReport();
+ }
+
+ for (uint256 i = 0; i < sendInstructions; ++i) {
+ _rebalanceLiquidity(
+ instructions.sendLiquidityParams[i].remoteChainSelector,
+ instructions.sendLiquidityParams[i].amount,
+ instructions.sendLiquidityParams[i].nativeBridgeFee,
+ ocrSeqNum,
+ instructions.sendLiquidityParams[i].bridgeData
+ );
+ }
+
+ for (uint256 i = 0; i < receiveInstructions; ++i) {
+ _receiveLiquidity(
+ instructions.receiveLiquidityParams[i].remoteChainSelector,
+ instructions.receiveLiquidityParams[i].amount,
+ instructions.receiveLiquidityParams[i].bridgeData,
+ instructions.receiveLiquidityParams[i].shouldWrapNative,
+ ocrSeqNum
+ );
+ }
+ }
+
+ // ================================================================
+ // │ Config │
+ // ================================================================
+
+ function getSupportedDestChains() external view returns (uint64[] memory) {
+ return s_supportedDestChains;
+ }
+
+ /// @notice Gets the cross chain liquidity manager
+ function getCrossChainRebalancer(uint64 chainSelector) external view returns (CrossChainRebalancer memory) {
+ return s_crossChainRebalancer[chainSelector];
+ }
+
+ /// @notice Gets all cross chain liquidity managers
+ /// @dev We don't care too much about gas since this function is intended for offchain usage.
+ function getAllCrossChainRebalancers() external view returns (CrossChainRebalancerArgs[] memory) {
+ uint256 numChains = s_supportedDestChains.length;
+ CrossChainRebalancerArgs[] memory managers = new CrossChainRebalancerArgs[](numChains);
+ for (uint256 i = 0; i < numChains; ++i) {
+ uint64 chainSelector = s_supportedDestChains[i];
+ CrossChainRebalancer memory currentManager = s_crossChainRebalancer[chainSelector];
+ managers[i] = CrossChainRebalancerArgs({
+ remoteRebalancer: currentManager.remoteRebalancer,
+ localBridge: currentManager.localBridge,
+ remoteToken: currentManager.remoteToken,
+ remoteChainSelector: chainSelector,
+ enabled: currentManager.enabled
+ });
+ }
+
+ return managers;
+ }
+
+ /// @notice Sets a list of cross chain liquidity managers.
+ /// @dev Will update the list of supported dest chains if the chain is new.
+ function setCrossChainRebalancers(CrossChainRebalancerArgs[] calldata crossChainRebalancers) external onlyOwner {
+ for (uint256 i = 0; i < crossChainRebalancers.length; ++i) {
+ _setCrossChainRebalancer(crossChainRebalancers[i]);
+ }
+ }
+
+ function setCrossChainRebalancer(CrossChainRebalancerArgs calldata crossChainLiqManager) external onlyOwner {
+ _setCrossChainRebalancer(crossChainLiqManager);
+ }
+
+ /// @notice Sets a single cross chain liquidity manager.
+ /// @dev Will update the list of supported dest chains if the chain is new.
+ function _setCrossChainRebalancer(CrossChainRebalancerArgs calldata crossChainLiqManager) internal {
+ if (crossChainLiqManager.remoteChainSelector == 0) {
+ revert ZeroChainSelector();
+ }
+
+ if (
+ crossChainLiqManager.remoteRebalancer == address(0) ||
+ address(crossChainLiqManager.localBridge) == address(0) ||
+ crossChainLiqManager.remoteToken == address(0)
+ ) {
+ revert ZeroAddress();
+ }
+
+ // If the destination chain is new, add it to the list of supported chains
+ if (s_crossChainRebalancer[crossChainLiqManager.remoteChainSelector].remoteToken == address(0)) {
+ s_supportedDestChains.push(crossChainLiqManager.remoteChainSelector);
+ }
+
+ s_crossChainRebalancer[crossChainLiqManager.remoteChainSelector] = CrossChainRebalancer({
+ remoteRebalancer: crossChainLiqManager.remoteRebalancer,
+ localBridge: crossChainLiqManager.localBridge,
+ remoteToken: crossChainLiqManager.remoteToken,
+ enabled: crossChainLiqManager.enabled
+ });
+
+ emit CrossChainRebalancerSet(
+ crossChainLiqManager.remoteChainSelector,
+ crossChainLiqManager.localBridge,
+ crossChainLiqManager.remoteToken,
+ crossChainLiqManager.remoteRebalancer,
+ crossChainLiqManager.enabled
+ );
+ }
+
+ /// @notice Gets the local liquidity container.
+ function getLocalLiquidityContainer() external view returns (address) {
+ return address(s_localLiquidityContainer);
+ }
+
+ /// @notice Sets the local liquidity container.
+ /// @dev Only the owner can call this function.
+ function setLocalLiquidityContainer(ILiquidityContainer localLiquidityContainer) external onlyOwner {
+ if (address(localLiquidityContainer) == address(0)) {
+ revert ZeroAddress();
+ }
+ s_localLiquidityContainer = localLiquidityContainer;
+
+ emit LiquidityContainerSet(address(localLiquidityContainer));
+ }
+
+ /// @notice Gets the target tokens balance.
+ function getMinimumLiquidity() external view returns (uint256) {
+ return s_minimumLiquidity;
+ }
+
+ /// @notice Sets the target tokens balance.
+ /// @dev Only the owner can call this function.
+ function setMinimumLiquidity(uint256 minimumLiquidity) external onlyOwner {
+ uint256 oldLiquidity = s_minimumLiquidity;
+ s_minimumLiquidity = minimumLiquidity;
+ emit MinimumLiquiditySet(oldLiquidity, s_minimumLiquidity);
+ }
+
+ /// @notice Gets the CLL finance team multisig address
+ function getFinanceRole() external view returns (address) {
+ return s_finance;
+ }
+
+ /// @notice Sets the finance team multisig address
+ /// @dev Only the owner can call this function.
+ function setFinanceRole(address finance) external onlyOwner {
+ s_finance = finance;
+ emit FinanceRoleSet(finance);
+ }
+
+ modifier onlyFinance() {
+ if (msg.sender != s_finance) revert OnlyFinanceRole();
+ _;
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/bridge-adapters/ArbitrumL1BridgeAdapter.sol b/contracts/src/v0.8/liquiditymanager/bridge-adapters/ArbitrumL1BridgeAdapter.sol
new file mode 100644
index 00000000000..9ab7376c273
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/bridge-adapters/ArbitrumL1BridgeAdapter.sol
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBridgeAdapter} from "../interfaces/IBridge.sol";
+
+import {IL1GatewayRouter} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/ethereum/gateway/IL1GatewayRouter.sol";
+import {IGatewayRouter} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/libraries/gateway/IGatewayRouter.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";
+
+interface IOutbox {
+ /**
+ * @notice Executes a messages in an Outbox entry.
+ * @dev Reverts if dispute period hasn't expired, since the outbox entry
+ * is only created once the rollup confirms the respective assertion.
+ * @dev it is not possible to execute any L2-to-L1 transaction which contains data
+ * to a contract address without any code (as enforced by the Bridge contract).
+ * @param proof Merkle proof of message inclusion in send root
+ * @param index Merkle path to message
+ * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
+ * @param to destination address for L1 contract call
+ * @param l2Block l2 block number at which sendTxToL1 call was made
+ * @param l1Block l1 block number at which sendTxToL1 call was made
+ * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
+ * @param value wei in L1 message
+ * @param data abi-encoded L1 message data
+ */
+ function executeTransaction(
+ bytes32[] calldata proof,
+ uint256 index,
+ address l2Sender,
+ address to,
+ uint256 l2Block,
+ uint256 l1Block,
+ uint256 l2Timestamp,
+ uint256 value,
+ bytes calldata data
+ ) external;
+}
+
+/// @notice Arbitrum L1 Bridge adapter
+/// @dev Auto unwraps and re-wraps wrapped eth in the bridge.
+contract ArbitrumL1BridgeAdapter is IBridgeAdapter {
+ using SafeERC20 for IERC20;
+
+ IL1GatewayRouter internal immutable i_l1GatewayRouter;
+ IOutbox internal immutable i_l1Outbox;
+
+ error NoGatewayForToken(address token);
+ error Unimplemented();
+
+ constructor(IL1GatewayRouter l1GatewayRouter, IOutbox l1Outbox) {
+ if (address(l1GatewayRouter) == address(0) || address(l1Outbox) == address(0)) {
+ revert BridgeAddressCannotBeZero();
+ }
+ i_l1GatewayRouter = l1GatewayRouter;
+ i_l1Outbox = l1Outbox;
+ }
+
+ /// @dev these are parameters provided by the caller of the sendERC20 function
+ /// and must be determined offchain.
+ struct SendERC20Params {
+ uint256 gasLimit;
+ uint256 maxSubmissionCost;
+ uint256 maxFeePerGas;
+ }
+
+ /// @inheritdoc IBridgeAdapter
+ function sendERC20(
+ address localToken,
+ address /* remoteToken */,
+ address recipient,
+ uint256 amount,
+ bytes calldata bridgeSpecificPayload
+ ) external payable override returns (bytes memory) {
+ // receive the token transfer from the msg.sender
+ IERC20(localToken).safeTransferFrom(msg.sender, address(this), amount);
+
+ // Note: the gateway router could return 0x0 for the gateway address
+ // if that token is not yet registered
+ address gateway = IGatewayRouter(address(i_l1GatewayRouter)).getGateway(localToken);
+ if (gateway == address(0)) {
+ revert NoGatewayForToken(localToken);
+ }
+
+ // approve the gateway to transfer the token amount sent to the adapter
+ IERC20(localToken).safeApprove(gateway, amount);
+
+ SendERC20Params memory params = abi.decode(bridgeSpecificPayload, (SendERC20Params));
+
+ uint256 expectedMsgValue = (params.gasLimit * params.maxFeePerGas) + params.maxSubmissionCost;
+ if (msg.value < expectedMsgValue) {
+ revert MsgValueDoesNotMatchAmount(msg.value, expectedMsgValue);
+ }
+
+ // The router will route the call to the gateway that we approved
+ // above. The gateway will then transfer the tokens to the L2.
+ // outboundTransferCustomRefund will return the abi encoded inbox sequence number
+ // which is 256 bits, so we can cap the return data to 256 bits.
+ bytes memory inboxSequenceNumber = i_l1GatewayRouter.outboundTransferCustomRefund{value: msg.value}(
+ localToken,
+ recipient,
+ recipient,
+ amount,
+ params.gasLimit,
+ params.maxFeePerGas,
+ abi.encode(params.maxSubmissionCost, bytes(""))
+ );
+
+ return inboxSequenceNumber;
+ }
+
+ /// @dev This function is so that we can easily abi-encode the arbitrum-specific payload for the sendERC20 function.
+ function exposeSendERC20Params(SendERC20Params memory params) public pure {}
+
+ /// @dev fees have to be determined offchain for arbitrum, therefore revert here to discourage usage.
+ function getBridgeFeeInNative() public pure override returns (uint256) {
+ revert Unimplemented();
+ }
+
+ /// @param proof Merkle proof of message inclusion in send root
+ /// @param index Merkle path to message
+ /// @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
+ /// @param to destination address for L1 contract call
+ /// @param l2Block l2 block number at which sendTxToL1 call was made
+ /// @param l1Block l1 block number at which sendTxToL1 call was made
+ /// @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
+ /// @param value wei in L1 message
+ /// @param data abi-encoded L1 message data
+ struct ArbitrumFinalizationPayload {
+ bytes32[] proof;
+ uint256 index;
+ address l2Sender;
+ address to;
+ uint256 l2Block;
+ uint256 l1Block;
+ uint256 l2Timestamp;
+ uint256 value;
+ bytes data;
+ }
+
+ /// @dev This function is so that we can easily abi-encode the arbitrum-specific payload for the finalizeWithdrawERC20 function.
+ function exposeArbitrumFinalizationPayload(ArbitrumFinalizationPayload memory payload) public pure {}
+
+ /// @notice Finalize an L2 -> L1 transfer.
+ /// Arbitrum finalizations are single-step, so we always return true.
+ /// Calls to this function will revert in two cases, 1) if the finalization payload is wrong,
+ /// i.e incorrect merkle proof, or index and 2) if the withdrawal was already finalized.
+ /// @return true iff the finalization does not revert.
+ function finalizeWithdrawERC20(
+ address /* remoteSender */,
+ address /* localReceiver */,
+ bytes calldata arbitrumFinalizationPayload
+ ) external override returns (bool) {
+ ArbitrumFinalizationPayload memory payload = abi.decode(arbitrumFinalizationPayload, (ArbitrumFinalizationPayload));
+ i_l1Outbox.executeTransaction(
+ payload.proof,
+ payload.index,
+ payload.l2Sender,
+ payload.to,
+ payload.l2Block,
+ payload.l1Block,
+ payload.l2Timestamp,
+ payload.value,
+ payload.data
+ );
+ return true;
+ }
+
+ /// @notice Convenience function to get the L2 token address from the L1 token address.
+ /// @return The L2 token address for the given L1 token address.
+ function getL2Token(address l1Token) external view returns (address) {
+ return i_l1GatewayRouter.calculateL2TokenAddress(l1Token);
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/bridge-adapters/ArbitrumL2BridgeAdapter.sol b/contracts/src/v0.8/liquiditymanager/bridge-adapters/ArbitrumL2BridgeAdapter.sol
new file mode 100644
index 00000000000..6ee97163f65
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/bridge-adapters/ArbitrumL2BridgeAdapter.sol
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBridgeAdapter} from "../interfaces/IBridge.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";
+
+interface IArbSys {
+ function withdrawEth(address destination) external payable returns (uint256);
+}
+
+interface IL2GatewayRouter {
+ function outboundTransfer(
+ address l1Token,
+ address to,
+ uint256 amount,
+ bytes calldata data
+ ) external payable returns (bytes memory);
+}
+
+/// @notice Arbitrum L2 Bridge adapter
+/// @dev Auto unwraps and re-wraps wrapped eth in the bridge.
+contract ArbitrumL2BridgeAdapter is IBridgeAdapter {
+ using SafeERC20 for IERC20;
+
+ IL2GatewayRouter internal immutable i_l2GatewayRouter;
+ // address internal immutable i_l1ERC20Gateway;
+ IArbSys internal constant ARB_SYS = IArbSys(address(0x64));
+
+ constructor(IL2GatewayRouter l2GatewayRouter) {
+ if (address(l2GatewayRouter) == address(0)) {
+ revert BridgeAddressCannotBeZero();
+ }
+ i_l2GatewayRouter = l2GatewayRouter;
+ }
+
+ /// @inheritdoc IBridgeAdapter
+ function sendERC20(
+ address localToken,
+ address remoteToken,
+ address recipient,
+ uint256 amount,
+ bytes calldata /* bridgeSpecificPayload */
+ ) external payable override returns (bytes memory) {
+ if (msg.value != 0) {
+ revert MsgShouldNotContainValue(msg.value);
+ }
+
+ IERC20(localToken).safeTransferFrom(msg.sender, address(this), amount);
+
+ // the data returned is the unique id of the L2 to L1 transfer
+ // see https://github.com/OffchainLabs/token-bridge-contracts/blob/bf9ad3d7f25c0eaf0a5f89eec7a0a370833cea16/contracts/tokenbridge/arbitrum/gateway/L2ArbitrumGateway.sol#L169-L191
+ // No approval needed, the bridge will burn the tokens from this contract.
+ bytes memory l2ToL1TxId = i_l2GatewayRouter.outboundTransfer(remoteToken, recipient, amount, bytes(""));
+
+ return l2ToL1TxId;
+ }
+
+ /// @notice No-op since L1 -> L2 transfers do not need finalization.
+ /// @return true always.
+ function finalizeWithdrawERC20(
+ address /* remoteSender */,
+ address /* localReceiver */,
+ bytes calldata /* bridgeSpecificPayload */
+ ) external pure override returns (bool) {
+ return true;
+ }
+
+ /// @notice There are no fees to bridge back to L1
+ function getBridgeFeeInNative() external pure returns (uint256) {
+ return 0;
+ }
+
+ function depositNativeToL1(address recipient) external payable {
+ ARB_SYS.withdrawEth{value: msg.value}(recipient);
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/bridge-adapters/OptimismL1BridgeAdapter.sol b/contracts/src/v0.8/liquiditymanager/bridge-adapters/OptimismL1BridgeAdapter.sol
new file mode 100644
index 00000000000..6734c74bd8d
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/bridge-adapters/OptimismL1BridgeAdapter.sol
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBridgeAdapter} from "../interfaces/IBridge.sol";
+import {IWrappedNative} from "../../ccip/interfaces/IWrappedNative.sol";
+import {Types} from "../interfaces/optimism/Types.sol";
+import {IOptimismPortal} from "../interfaces/optimism/IOptimismPortal.sol";
+
+import {IL1StandardBridge} from "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.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 OptimismL1BridgeAdapter implements IBridgeAdapter for the Optimism L1<=>L2 bridge.
+/// @dev L1 -> L2 deposits are done via the depositERC20To and depositETHTo functions on the L1StandardBridge.
+/// The amount of gas provided for the transaction must be buffered - the Optimism SDK recommends a 20% buffer.
+/// The Optimism Bridge implements 2-step withdrawals from L2 to L1. Once a withdrawal transaction is included
+/// in the L2 chain, it must be proven on L1 before it can be finalized. There is a buffer between the transaction
+/// being posted on L2 before it can be proven, and similarly, there is a buffer in the time it takes to prove
+/// the transaction before it can be finalized.
+/// See https://blog.oplabs.co/two-step-withdrawals/ for more details on this mechanism.
+/// @dev We have to unwrap WETH into ether before depositing it to L2. Therefore this bridge adapter bridges
+/// WETH to ether. The receiver on L2 must wrap the ether back into WETH.
+contract OptimismL1BridgeAdapter is IBridgeAdapter {
+ using SafeERC20 for IERC20;
+
+ /// @notice used when the action in the payload is invalid.
+ error InvalidFinalizationAction();
+
+ /// @notice Payload for proving a withdrawal from L2 on L1 via finalizeWithdrawERC20.
+ /// @param withdrawalTransaction The withdrawal transaction, see its docstring for more details.
+ /// @param l2OutputIndex The index of the output in the L2 block, or the dispute game index post fault proof upgrade.
+ /// @param outputRootProof The inclusion proof of the L2ToL1MessagePasser contract's storage root.
+ /// @param withdrawalProof The Merkle proof of the withdrawal key presence in the L2ToL1MessagePasser contract's state trie.
+ struct OptimismProveWithdrawalPayload {
+ Types.WithdrawalTransaction withdrawalTransaction;
+ uint256 l2OutputIndex;
+ Types.OutputRootProof outputRootProof;
+ bytes[] withdrawalProof;
+ }
+
+ /// @notice Payload for finalizing a withdrawal from L2 on L1.
+ /// Note that the withdrawal must be proven first before it can be finalized.
+ /// @param withdrawalTransaction The withdrawal transaction, see its docstring for more details.
+ struct OptimismFinalizationPayload {
+ Types.WithdrawalTransaction withdrawalTransaction;
+ }
+
+ /// @notice The action to take when finalizing a withdrawal.
+ /// Optimism implements two-step withdrawals, so we need to specify the action to take
+ /// each time the finalizeWithdrawERC20 function is called.
+ enum FinalizationAction {
+ ProveWithdrawal,
+ FinalizeWithdrawal
+ }
+
+ /// @notice Payload for interacting with the finalizeWithdrawERC20 function.
+ /// Since Optimism has 2-step withdrawals, we cannot finalize and get the funds on L1 in the same transaction.
+ /// @param action The action to take; either ProveWithdrawal or FinalizeWithdrawal.
+ /// @param data The payload for the action. If ProveWithdrawal, it must be an abi-encoded OptimismProveWithdrawalPayload.
+ /// If FinalizeWithdrawal, it must be an abi-encoded OptimismFinalizationPayload.
+ struct FinalizeWithdrawERC20Payload {
+ FinalizationAction action;
+ bytes data;
+ }
+
+ /// @dev Reference to the L1StandardBridge contract. Deposits to L2 go through this contract.
+ IL1StandardBridge internal immutable i_L1Bridge;
+
+ /// @dev Reference to the WrappedNative contract. Optimism bridges ether directly rather than WETH,
+ /// so we need to unwrap WETH into ether before depositing it to L2.
+ IWrappedNative internal immutable i_wrappedNative;
+
+ /// @dev Reference to the OptimismPortal contract, which is used to prove and finalize withdrawals.
+ IOptimismPortal internal immutable i_optimismPortal;
+
+ /// @dev Nonce to use for L2 deposits to allow for better tracking offchain.
+ uint64 private s_nonce = 0;
+
+ constructor(IL1StandardBridge l1Bridge, IWrappedNative wrappedNative, IOptimismPortal optimismPortal) {
+ if (
+ address(l1Bridge) == address(0) || address(wrappedNative) == address(0) || address(optimismPortal) == address(0)
+ ) {
+ revert BridgeAddressCannotBeZero();
+ }
+ i_L1Bridge = l1Bridge;
+ i_wrappedNative = wrappedNative;
+ i_optimismPortal = optimismPortal;
+ }
+
+ /// @notice The WETH withdraw requires this be present otherwise withdraws will fail.
+ receive() external payable {}
+
+ /// @inheritdoc IBridgeAdapter
+ function sendERC20(
+ address localToken,
+ address remoteToken,
+ address recipient,
+ uint256 amount,
+ bytes calldata /* bridgeSpecificPayload */
+ ) external payable override returns (bytes memory) {
+ IERC20(localToken).safeTransferFrom(msg.sender, address(this), amount);
+
+ if (msg.value != 0) {
+ revert MsgShouldNotContainValue(msg.value);
+ }
+
+ // Extra data for the L2 deposit.
+ // We encode the nonce in the extra data so that we can track the L2 deposit offchain.
+ bytes memory extraData = abi.encode(s_nonce++);
+
+ // If the token is the wrapped native, we unwrap it and deposit native
+ if (localToken == address(i_wrappedNative)) {
+ i_wrappedNative.withdraw(amount);
+ i_L1Bridge.depositETHTo{value: amount}(recipient, 0, extraData);
+ return extraData;
+ }
+
+ // Token is a normal ERC20.
+ IERC20(localToken).safeApprove(address(i_L1Bridge), amount);
+ i_L1Bridge.depositERC20To(localToken, remoteToken, recipient, amount, 0, extraData);
+
+ return extraData;
+ }
+
+ /// @notice Bridging to Optimism is paid for with gas
+ /// @dev Since the gas amount charged is dynamic, the gas burn can change from block to block.
+ /// You should always add a buffer of at least 20% to the gas limit for your L1 to L2 transaction
+ /// to avoid running out of gas.
+ function getBridgeFeeInNative() public pure returns (uint256) {
+ return 0;
+ }
+
+ /// @notice Prove or finalize an ERC20 withdrawal from L2.
+ /// The action to take is specified in the payload. See the docstring of FinalizeWithdrawERC20Payload for more details.
+ /// @param data The payload for the action. This is an abi.encode'd FinalizeWithdrawERC20Payload with the appropriate data.
+ /// @return true iff finalization is successful, and false for proving a withdrawal. If either of these fail,
+ /// the call to this function will revert.
+ function finalizeWithdrawERC20(
+ address /* remoteSender */,
+ address /* localReceiver */,
+ bytes calldata data
+ ) external override returns (bool) {
+ // decode the data into FinalizeWithdrawERC20Payload first and extract the action.
+ FinalizeWithdrawERC20Payload memory payload = abi.decode(data, (FinalizeWithdrawERC20Payload));
+ if (payload.action == FinalizationAction.ProveWithdrawal) {
+ // The action being ProveWithdrawal indicates that this is a withdrawal proof payload.
+ // Decode the data into OptimismProveWithdrawalPayload and call the proveWithdrawal function.
+ OptimismProveWithdrawalPayload memory provePayload = abi.decode(payload.data, (OptimismProveWithdrawalPayload));
+ _proveWithdrawal(provePayload);
+ return false;
+ } else if (payload.action == FinalizationAction.FinalizeWithdrawal) {
+ // decode the data into OptimismFinalizationPayload and call the finalizeWithdrawal function.
+ OptimismFinalizationPayload memory finalizePayload = abi.decode(payload.data, (OptimismFinalizationPayload));
+ // NOTE: finalizing ether withdrawals will currently send ether to the receiver address as indicated by the
+ // withdrawal tx. However, this is problematic because we need to re-wrap it into WETH.
+ // However, we can't do that from within this adapter because it doesn't actually have the ether.
+ // So its up to the caller to rectify this by re-wrapping the ether.
+ _finalizeWithdrawal(finalizePayload);
+ return true;
+ } else {
+ revert InvalidFinalizationAction();
+ }
+ }
+
+ function _proveWithdrawal(OptimismProveWithdrawalPayload memory payload) internal {
+ // will revert if the proof is invalid or the output index is not yet included on L1.
+ i_optimismPortal.proveWithdrawalTransaction(
+ payload.withdrawalTransaction,
+ payload.l2OutputIndex,
+ payload.outputRootProof,
+ payload.withdrawalProof
+ );
+ }
+
+ function _finalizeWithdrawal(OptimismFinalizationPayload memory payload) internal {
+ i_optimismPortal.finalizeWithdrawalTransaction(payload.withdrawalTransaction);
+ }
+
+ /// @notice returns the address of the WETH token used by this adapter.
+ /// @return the address of the WETH token used by this adapter.
+ function getWrappedNative() external view returns (address) {
+ return address(i_wrappedNative);
+ }
+
+ /// @notice returns the address of the Optimism portal contract.
+ /// @return the address of the Optimism portal contract.
+ function getOptimismPortal() external view returns (address) {
+ return address(i_optimismPortal);
+ }
+
+ /// @notice returns the address of the Optimism L1StandardBridge bridge contract.
+ /// @return the address of the Optimism L1StandardBridge bridge contract.
+ function getL1Bridge() external view returns (address) {
+ return address(i_L1Bridge);
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/bridge-adapters/OptimismL2BridgeAdapter.sol b/contracts/src/v0.8/liquiditymanager/bridge-adapters/OptimismL2BridgeAdapter.sol
new file mode 100644
index 00000000000..fd1218f6704
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/bridge-adapters/OptimismL2BridgeAdapter.sol
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IBridgeAdapter} from "../interfaces/IBridge.sol";
+import {IWrappedNative} from "../../ccip/interfaces/IWrappedNative.sol";
+
+import {Lib_PredeployAddresses} from "@eth-optimism/contracts/libraries/constants/Lib_PredeployAddresses.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";
+
+/// @dev copy/pasted from https://github.com/ethereum-optimism/optimism/blob/f707883038d527cbf1e9f8ea513fe33255deadbc/packages/contracts-bedrock/src/L2/L2StandardBridge.sol#L114-L122.
+/// We can't import it because of hard pin solidity version in the pragma (0.8.15).
+interface IL2StandardBridge {
+ /// @custom:legacy
+ /// @notice Initiates a withdrawal from L2 to L1 to a target account on L1.
+ /// Note that if ETH is sent to a contract on L1 and the call fails, then that ETH will
+ /// be locked in the L1StandardBridge. ETH may be recoverable if the call can be
+ /// successfully replayed by increasing the amount of gas supplied to the call. If the
+ /// call will fail for any amount of gas, then the ETH will be locked permanently.
+ /// This function only works with OptimismMintableERC20 tokens or ether. Use the
+ /// `bridgeERC20To` function to bridge native L2 tokens to L1.
+ /// @param _l2Token Address of the L2 token to withdraw.
+ /// @param _to Recipient account on L1.
+ /// @param _amount Amount of the L2 token to withdraw.
+ /// @param _minGasLimit Minimum gas limit to use for the transaction.
+ /// @param _extraData Extra data attached to the withdrawal.
+ function withdrawTo(
+ address _l2Token,
+ address _to,
+ uint256 _amount,
+ uint32 _minGasLimit,
+ bytes calldata _extraData
+ ) external payable;
+}
+
+/// @notice OptimismL2BridgeAdapter implements IBridgeAdapter for the Optimism L2<=>L1 bridge.
+/// @dev We have to unwrap WETH into ether before withdrawing it to L1. Therefore this bridge adapter bridges
+/// WETH to ether. The receiver on L1 must wrap the ether back into WETH.
+contract OptimismL2BridgeAdapter is IBridgeAdapter {
+ using SafeERC20 for IERC20;
+
+ IL2StandardBridge internal immutable i_L2Bridge = IL2StandardBridge(Lib_PredeployAddresses.L2_STANDARD_BRIDGE);
+ IWrappedNative internal immutable i_wrappedNative;
+
+ // Nonce to use for L1 withdrawals to allow for better tracking offchain.
+ uint64 private s_nonce = 0;
+
+ constructor(IWrappedNative wrappedNative) {
+ // Wrapped native can be address zero, this means that auto-wrapping is disabled.
+ i_wrappedNative = wrappedNative;
+ }
+
+ /// @notice The WETH withdraw requires this be present otherwise withdraws will fail.
+ receive() external payable {}
+
+ /// @inheritdoc IBridgeAdapter
+ function sendERC20(
+ address localToken,
+ address /* remoteToken */,
+ address recipient,
+ uint256 amount,
+ bytes calldata /* bridgeSpecificPayload */
+ ) external payable override returns (bytes memory) {
+ if (msg.value != 0) {
+ revert MsgShouldNotContainValue(msg.value);
+ }
+
+ IERC20(localToken).safeTransferFrom(msg.sender, address(this), amount);
+
+ // Extra data for the L2 withdraw.
+ // We encode the nonce in the extra data so that we can track the L2 withdraw offchain.
+ bytes memory extraData = abi.encode(s_nonce++);
+
+ // If the token is the wrapped native, we unwrap it and withdraw native
+ if (localToken == address(i_wrappedNative)) {
+ i_wrappedNative.withdraw(amount);
+ // XXX: Lib_PredeployAddresses.OVM_ETH is actually 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000.
+ // This code path still works because the L2 bridge is hardcoded to handle this specific address.
+ // The better approach might be to use the bridgeEthTo function, which is on the StandardBridge
+ // abstract contract, inherited by both L1StandardBridge and L2StandardBridge.
+ // This is also marked as legacy, so it might mean that this will be deprecated soon.
+ i_L2Bridge.withdrawTo{value: amount}(Lib_PredeployAddresses.OVM_ETH, recipient, amount, 0, extraData);
+ return extraData;
+ }
+
+ // Token is normal ERC20
+ IERC20(localToken).approve(address(i_L2Bridge), amount);
+ i_L2Bridge.withdrawTo(localToken, recipient, amount, 0, extraData);
+ return extraData;
+ }
+
+ /// @notice No-op since L1 -> L2 transfers do not need finalization.
+ /// @return true always.
+ function finalizeWithdrawERC20(
+ address /* remoteSender */,
+ address /* localReceiver */,
+ bytes calldata /* bridgeSpecificPayload */
+ ) external pure override returns (bool) {
+ return true;
+ }
+
+ /// @notice There are no fees to bridge back to L1
+ function getBridgeFeeInNative() external pure returns (uint256) {
+ return 0;
+ }
+
+ /// @notice returns the address of the WETH token used by this adapter.
+ /// @return the address of the WETH token used by this adapter.
+ function getWrappedNative() external view returns (address) {
+ return address(i_wrappedNative);
+ }
+
+ /// @notice returns the address of the L2 bridge used by this adapter.
+ /// @return the address of the L2 bridge used by this adapter.
+ function getL2Bridge() external view returns (address) {
+ return address(i_L2Bridge);
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/encoders/OptimismL1BridgeAdapterEncoder.sol b/contracts/src/v0.8/liquiditymanager/encoders/OptimismL1BridgeAdapterEncoder.sol
new file mode 100644
index 00000000000..888b48732d7
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/encoders/OptimismL1BridgeAdapterEncoder.sol
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {OptimismL1BridgeAdapter} from "../bridge-adapters/OptimismL1BridgeAdapter.sol";
+
+/// @dev to generate abi's for the OptimismL1BridgeAdapter's various payload types.
+/// @dev for usage examples see core/scripts/ccip/liquiditymanager/opstack/prove_withdrawal.go
+/// @dev or core/scripts/ccip/liquiditymanager/opstack/finalize.go.
+abstract contract OptimismL1BridgeAdapterEncoder {
+ function encodeFinalizeWithdrawalERC20Payload(
+ OptimismL1BridgeAdapter.FinalizeWithdrawERC20Payload memory payload
+ ) public pure {}
+
+ function encodeOptimismProveWithdrawalPayload(
+ OptimismL1BridgeAdapter.OptimismProveWithdrawalPayload memory payload
+ ) public pure {}
+
+ function encodeOptimismFinalizationPayload(
+ OptimismL1BridgeAdapter.OptimismFinalizationPayload memory payload
+ ) public pure {}
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/IBridge.sol b/contracts/src/v0.8/liquiditymanager/interfaces/IBridge.sol
new file mode 100644
index 00000000000..83e64edce48
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/IBridge.sol
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+/// @dev IBridgeAdapter provides a common interface to interact with the native bridge.
+interface IBridgeAdapter {
+ error BridgeAddressCannotBeZero();
+ error MsgValueDoesNotMatchAmount(uint256 msgValue, uint256 amount);
+ error InsufficientEthValue(uint256 wanted, uint256 got);
+ error MsgShouldNotContainValue(uint256 value);
+
+ /// @notice Send the specified amount of the local token cross-chain to the remote chain.
+ /// The tokens on the remote chain will then be sourced from the remoteToken address.
+ /// The amount to be sent must be approved by the caller beforehand on the localToken contract.
+ /// The caller must provide the bridging fee in native currency, i.e msg.value.
+ /// @param localToken The address of the local ERC-20 token.
+ /// @param remoteToken The address of the remote ERC-20 token.
+ /// @param recipient The address of the recipient on the remote chain.
+ /// @param amount The amount of the local token to send.
+ /// @param bridgeSpecificPayload The payload of the cross-chain transfer. Bridge-specific.
+ function sendERC20(
+ address localToken,
+ address remoteToken,
+ address recipient,
+ uint256 amount,
+ bytes calldata bridgeSpecificPayload
+ ) external payable returns (bytes memory);
+
+ /// @notice Get the bridging fee in native currency. This fee must be provided upon sending tokens via
+ /// the sendERC20 function.
+ /// @return The bridging fee in native currency.
+ function getBridgeFeeInNative() external view returns (uint256);
+
+ /// @notice Finalize the withdrawal of a cross-chain transfer.
+ /// Not all implementations will finalize a transfer in a single call to this function.
+ /// Optimism, for example, requires a two-step process to finalize a transfer. The first
+ /// step requires proving the withdrawal that occurred on L2 on L1. The second step is then
+ /// the finalization, whereby funds become available to the recipient. So, in that particular
+ /// scenario, `false` is returned from `finalizeWithdrawERC20` when the first step is completed,
+ /// and `true` is returned when the second step is completed.
+ /// @param remoteSender The address of the sender on the remote chain.
+ /// @param localReceiver The address of the receiver on the local chain.
+ /// @param bridgeSpecificPayload The payload of the cross-chain transfer, bridge-specific, i.e a proof of some kind.
+ /// @return true iff the funds are available, false otherwise.
+ function finalizeWithdrawERC20(
+ address remoteSender,
+ address localReceiver,
+ bytes calldata bridgeSpecificPayload
+ ) external returns (bool);
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/ILiquidityContainer.sol b/contracts/src/v0.8/liquiditymanager/interfaces/ILiquidityContainer.sol
new file mode 100644
index 00000000000..062325d9531
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/ILiquidityContainer.sol
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+/// @notice Interface for a liquidity container, this can be a CCIP token pool.
+interface ILiquidityContainer {
+ event LiquidityAdded(address indexed provider, uint256 indexed amount);
+ event LiquidityRemoved(address indexed provider, uint256 indexed amount);
+
+ /// @notice Provide additional liquidity to the container.
+ /// @dev Should emit LiquidityAdded
+ function provideLiquidity(uint256 amount) external;
+
+ /// @notice Withdraws liquidity from the container to the msg sender
+ /// @dev Should emit LiquidityRemoved
+ function withdrawLiquidity(uint256 amount) external;
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/ILiquidityManager.sol b/contracts/src/v0.8/liquiditymanager/interfaces/ILiquidityManager.sol
new file mode 100644
index 00000000000..19fd1014a4d
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/ILiquidityManager.sol
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IBridgeAdapter} from "./IBridge.sol";
+
+interface ILiquidityManager {
+ /// @notice Parameters for sending liquidity to a remote chain.
+ /// @param amount The amount of tokens to be sent to the remote chain.
+ /// @param nativeBridgeFee The amount of native that should be sent by the liquiditymanager in the sendERC20 call.
+ /// Used to pay for the bridge fees.
+ /// @param remoteChainSelector The selector of the remote chain.
+ /// @param bridgeData The bridge data that should be passed to the sendERC20 call.
+ struct SendLiquidityParams {
+ uint256 amount;
+ uint256 nativeBridgeFee;
+ uint64 remoteChainSelector;
+ bytes bridgeData;
+ }
+
+ /// @notice Parameters for receiving liquidity from a remote chain.
+ /// @param amount The amount of tokens to be received from the remote chain.
+ /// @param remoteChainSelector The selector of the remote chain.
+ /// @param bridgeData The bridge data that should be passed to the finalizeWithdrawERC20 call.
+ /// @param shouldWrapNative Whether the received native token should be wrapped into wrapped native.
+ /// This is needed for when the bridge being used doesn't bridge wrapped native but native directly.
+ struct ReceiveLiquidityParams {
+ uint256 amount;
+ uint64 remoteChainSelector;
+ bool shouldWrapNative;
+ bytes bridgeData;
+ }
+
+ /// @notice Instructions for the rebalancer on what to do with the available liquidity.
+ /// @param sendLiquidityParams The parameters for sending liquidity to a remote chain.
+ /// @param receiveLiquidityParams The parameters for receiving liquidity from a remote chain.
+ struct LiquidityInstructions {
+ SendLiquidityParams[] sendLiquidityParams;
+ ReceiveLiquidityParams[] receiveLiquidityParams;
+ }
+
+ /// @notice Parameters for adding a cross-chain rebalancer.
+ /// @param remoteRebalancer The address of the remote rebalancer.
+ /// @param localBridge The local bridge adapter address.
+ /// @param remoteToken The address of the remote token.
+ /// @param remoteChainSelector The selector of the remote chain.
+ /// @param enabled Whether the rebalancer is enabled.
+ struct CrossChainRebalancerArgs {
+ address remoteRebalancer;
+ IBridgeAdapter localBridge;
+ address remoteToken;
+ uint64 remoteChainSelector;
+ bool enabled;
+ }
+
+ /// @notice Returns the current liquidity in the liquidity container.
+ /// @return currentLiquidity The current liquidity in the liquidity container.
+ function getLiquidity() external view returns (uint256 currentLiquidity);
+
+ /// @notice Returns all the cross-chain rebalancers.
+ /// @return All the cross-chain rebalancers.
+ function getAllCrossChainRebalancers() external view returns (CrossChainRebalancerArgs[] memory);
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IAbstractArbitrumTokenGateway.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IAbstractArbitrumTokenGateway.sol
new file mode 100644
index 00000000000..c695729fa93
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IAbstractArbitrumTokenGateway.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {TokenGateway} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/libraries/gateway/TokenGateway.sol";
+
+/// @dev to generate gethwrappers
+abstract contract IAbstractArbitrumTokenGateway is TokenGateway {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbRollupCore.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbRollupCore.sol
new file mode 100644
index 00000000000..a5d0e5e8e6a
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbRollupCore.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IRollupCore} from "@arbitrum/nitro-contracts/src/rollup/IRollupCore.sol";
+
+/// @dev to generate gethwrappers
+interface IArbRollupCore is IRollupCore {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbSys.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbSys.sol
new file mode 100644
index 00000000000..7d6afbc18e4
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbSys.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {ArbSys} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol";
+
+/// @dev to generate gethwrappers
+interface IArbSys is ArbSys {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumGatewayRouter.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumGatewayRouter.sol
new file mode 100644
index 00000000000..81fc2cb1b5e
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumGatewayRouter.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IGatewayRouter} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/libraries/gateway/IGatewayRouter.sol";
+
+/// @dev to generate gethwrappers
+interface IArbitrumGatewayRouter is IGatewayRouter {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumInbox.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumInbox.sol
new file mode 100644
index 00000000000..a306ef21b1a
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumInbox.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IInboxBase} from "@arbitrum/nitro-contracts/src/bridge/IInboxBase.sol";
+
+/// @dev to generate gethwrappers
+interface IArbitrumInbox is IInboxBase {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumL1GatewayRouter.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumL1GatewayRouter.sol
new file mode 100644
index 00000000000..49e7e45dd7d
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumL1GatewayRouter.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {IL1GatewayRouter} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/ethereum/gateway/IL1GatewayRouter.sol";
+
+/// @dev to generate gethwrappers
+interface IArbitrumL1GatewayRouter is IL1GatewayRouter {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumTokenGateway.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumTokenGateway.sol
new file mode 100644
index 00000000000..0c1f2281890
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IArbitrumTokenGateway.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {ITokenGateway} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/libraries/gateway/ITokenGateway.sol";
+
+/// @dev to generate gethwrappers
+interface IArbitrumTokenGateway is ITokenGateway {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IL2ArbitrumGateway.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IL2ArbitrumGateway.sol
new file mode 100644
index 00000000000..96a63a0dcd0
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IL2ArbitrumGateway.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {L2ArbitrumGateway} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/arbitrum/gateway/L2ArbitrumGateway.sol";
+
+/// @dev to generate gethwrappers
+abstract contract IL2ArbitrumGateway is L2ArbitrumGateway {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IL2ArbitrumMessenger.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IL2ArbitrumMessenger.sol
new file mode 100644
index 00000000000..115882a2115
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/IL2ArbitrumMessenger.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {L2ArbitrumMessenger} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/arbitrum/L2ArbitrumMessenger.sol";
+
+/// @dev to generate gethwrappers
+abstract contract IL2ArbitrumMessenger is L2ArbitrumMessenger {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/INodeInterface.sol b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/INodeInterface.sol
new file mode 100644
index 00000000000..79475cdf5d1
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/arbitrum/INodeInterface.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {NodeInterface} from "@arbitrum/nitro-contracts/src/node-interface/NodeInterface.sol";
+
+/// @dev to generate gethwrappers
+interface INodeInterface is NodeInterface {}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/DisputeTypes.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/DisputeTypes.sol
new file mode 100644
index 00000000000..f0bd99fbcde
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/DisputeTypes.sol
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/v1.7.0/packages/contracts-bedrock/src/libraries/DisputeTypes.sol
+pragma solidity ^0.8.0;
+
+/// @notice A `GameType` represents the type of game being played.
+type GameType is uint32;
+
+/// @notice A `GameId` represents a packed 1 byte game ID, an 11 byte timestamp, and a 20 byte address.
+/// @dev The packed layout of this type is as follows:
+/// ┌───────────┬───────────┐
+/// │ Bits │ Value │
+/// ├───────────┼───────────┤
+/// │ [0, 8) │ Game Type │
+/// │ [8, 96) │ Timestamp │
+/// │ [96, 256) │ Address │
+/// └───────────┴───────────┘
+type GameId is bytes32;
+
+/// @notice A dedicated timestamp type.
+type Timestamp is uint64;
+
+/// @notice A claim represents an MPT root representing the state of the fault proof program.
+type Claim is bytes32;
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismCrossDomainMessenger.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismCrossDomainMessenger.sol
new file mode 100644
index 00000000000..2b5cc650724
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismCrossDomainMessenger.sol
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/f707883038d527cbf1e9f8ea513fe33255deadbc/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol#L153
+pragma solidity ^0.8.0;
+
+interface IOptimismCrossDomainMessenger {
+ /// @notice Emitted whenever a message is sent to the other chain.
+ /// @param target Address of the recipient of the message.
+ /// @param sender Address of the sender of the message.
+ /// @param message Message to trigger the recipient address with.
+ /// @param messageNonce Unique nonce attached to the message.
+ /// @param gasLimit Minimum gas limit that the message can be executed with.
+ event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit);
+
+ /// @notice Relays a message that was sent by the other CrossDomainMessenger contract. Can only
+ /// be executed via cross-chain call from the other messenger OR if the message was
+ /// already received once and is currently being replayed.
+ /// @param _nonce Nonce of the message being relayed.
+ /// @param _sender Address of the user who sent the message.
+ /// @param _target Address that the message is targeted at.
+ /// @param _value ETH value to send with the message.
+ /// @param _minGasLimit Minimum amount of gas that the message can be executed with.
+ /// @param _message Message to send to the target.
+ function relayMessage(
+ uint256 _nonce,
+ address _sender,
+ address _target,
+ uint256 _value,
+ uint256 _minGasLimit,
+ bytes calldata _message
+ ) external payable;
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismDisputeGameFactory.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismDisputeGameFactory.sol
new file mode 100644
index 00000000000..f72e6456d3f
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismDisputeGameFactory.sol
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/v1.7.0/packages/contracts-bedrock/src/dispute/DisputeGameFactory.sol
+pragma solidity ^0.8.0;
+
+import {GameType, GameId, Timestamp, Claim} from "./DisputeTypes.sol";
+
+interface IOptimismDisputeGameFactory {
+ /// @notice Information about a dispute game found in a `findLatestGames` search.
+ struct GameSearchResult {
+ uint256 index;
+ GameId metadata;
+ Timestamp timestamp;
+ Claim rootClaim;
+ bytes extraData;
+ }
+
+ /// @notice Finds the `_n` most recent `GameId`'s of type `_gameType` starting at `_start`. If there are less than
+ /// `_n` games of type `_gameType` starting at `_start`, then the returned array will be shorter than `_n`.
+ /// @param _gameType The type of game to find.
+ /// @param _start The index to start the reverse search from.
+ /// @param _n The number of games to find.
+ function findLatestGames(
+ GameType _gameType,
+ uint256 _start,
+ uint256 _n
+ ) external view returns (GameSearchResult[] memory games_);
+
+ /// @notice The total number of dispute games created by this factory.
+ /// @return gameCount_ The total number of dispute games created by this factory.
+ function gameCount() external view returns (uint256 gameCount_);
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL1StandardBridge.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL1StandardBridge.sol
new file mode 100644
index 00000000000..3a518fcf798
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL1StandardBridge.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/f707883038d527cbf1e9f8ea513fe33255deadbc/packages/contracts-bedrock/src/L1/L1StandardBridge.sol
+pragma solidity ^0.8.0;
+
+interface IOptimismL1StandardBridge {
+ /// @custom:legacy
+ /// @notice Deposits some amount of ETH into a target account on L2.
+ /// Note that if ETH is sent to a contract on L2 and the call fails, then that ETH will
+ /// be locked in the L2StandardBridge. ETH may be recoverable if the call can be
+ /// successfully replayed by increasing the amount of gas supplied to the call. If the
+ /// call will fail for any amount of gas, then the ETH will be locked permanently.
+ /// @param _to Address of the recipient on L2.
+ /// @param _minGasLimit Minimum gas limit for the deposit message on L2.
+ /// @param _extraData Optional data to forward to L2.
+ /// Data supplied here will not be used to execute any code on L2 and is
+ /// only emitted as extra data for the convenience of off-chain tooling.
+ function depositETHTo(address _to, uint32 _minGasLimit, bytes calldata _extraData) external payable;
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL2OutputOracle.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL2OutputOracle.sol
new file mode 100644
index 00000000000..fa36863c5b7
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL2OutputOracle.sol
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/v1.7.0/packages/contracts-bedrock/src/L1/L2OutputOracle.sol
+pragma solidity ^0.8.0;
+
+import {Types} from "./Types.sol";
+
+interface IOptimismL2OutputOracle {
+ /// @notice Returns the index of the L2 output that checkpoints a given L2 block number.
+ /// Uses a binary search to find the first output greater than or equal to the given
+ /// block.
+ /// @param _l2BlockNumber L2 block number to find a checkpoint for.
+ /// @return Index of the first checkpoint that commits to the given L2 block number.
+ function getL2OutputIndexAfter(uint256 _l2BlockNumber) external view returns (uint256);
+
+ /// @notice Returns an output by index. Needed to return a struct instead of a tuple.
+ /// @param _l2OutputIndex Index of the output to return.
+ /// @return The output at the given index.
+ function getL2Output(uint256 _l2OutputIndex) external view returns (Types.OutputProposal memory);
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL2ToL1MessagePasser.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL2ToL1MessagePasser.sol
new file mode 100644
index 00000000000..9ac6aebfb28
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismL2ToL1MessagePasser.sol
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/v1.7.0/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol
+pragma solidity ^0.8.0;
+
+interface IOptimismL2ToL1MessagePasser {
+ /// @notice Emitted any time a withdrawal is initiated.
+ /// @param nonce Unique value corresponding to each withdrawal.
+ /// @param sender The L2 account address which initiated the withdrawal.
+ /// @param target The L1 account address the call will be send to.
+ /// @param value The ETH value submitted for withdrawal, to be forwarded to the target.
+ /// @param gasLimit The minimum amount of gas that must be provided when withdrawing.
+ /// @param data The data to be forwarded to the target on L1.
+ /// @param withdrawalHash The hash of the withdrawal.
+ event MessagePassed(
+ uint256 indexed nonce,
+ address indexed sender,
+ address indexed target,
+ uint256 value,
+ uint256 gasLimit,
+ bytes data,
+ bytes32 withdrawalHash
+ );
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismPortal.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismPortal.sol
new file mode 100644
index 00000000000..887025bac75
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismPortal.sol
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/v1.7.0/packages/contracts-bedrock/src/L1/OptimismPortal.sol
+pragma solidity ^0.8.0;
+
+import {Types} from "./Types.sol";
+
+interface IOptimismPortal {
+ /// @notice Semantic version.
+ function version() external view returns (string memory);
+
+ /// @notice Proves a withdrawal transaction.
+ /// @param _tx Withdrawal transaction to finalize.
+ /// @param _l2OutputIndex L2 output index to prove against.
+ /// @param _outputRootProof Inclusion proof of the L2ToL1MessagePasser contract's storage root.
+ /// @param _withdrawalProof Inclusion proof of the withdrawal in L2ToL1MessagePasser contract.
+ function proveWithdrawalTransaction(
+ Types.WithdrawalTransaction memory _tx,
+ uint256 _l2OutputIndex,
+ Types.OutputRootProof calldata _outputRootProof,
+ bytes[] calldata _withdrawalProof
+ ) external;
+
+ /// @notice Finalizes a withdrawal transaction.
+ /// @param _tx Withdrawal transaction to finalize.
+ function finalizeWithdrawalTransaction(Types.WithdrawalTransaction memory _tx) external;
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismPortal2.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismPortal2.sol
new file mode 100644
index 00000000000..165922b5aae
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismPortal2.sol
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/v1.7.0/packages/contracts-bedrock/src/L1/OptimismPortal2.sol
+pragma solidity ^0.8.0;
+import {GameType} from "./DisputeTypes.sol";
+
+interface IOptimismPortal2 {
+ /// @notice The dispute game factory address.
+ /// @dev See https://github.com/ethereum-optimism/optimism/blob/f707883038d527cbf1e9f8ea513fe33255deadbc/packages/contracts-bedrock/src/L1/OptimismPortal2.sol#L79.
+ function disputeGameFactory() external view returns (address);
+ /// @notice The game type that the OptimismPortal consults for output proposals.
+ function respectedGameType() external view returns (GameType);
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismStandardBridge.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismStandardBridge.sol
new file mode 100644
index 00000000000..2f9ef91d7c4
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/IOptimismStandardBridge.sol
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/f707883038d527cbf1e9f8ea513fe33255deadbc/packages/contracts-bedrock/src/universal/StandardBridge.sol#L88
+pragma solidity ^0.8.0;
+
+interface IOptimismStandardBridge {
+ /// @notice Emitted when an ERC20 bridge is finalized on this chain.
+ /// @param localToken Address of the ERC20 on this chain.
+ /// @param remoteToken Address of the ERC20 on the remote chain.
+ /// @param from Address of the sender.
+ /// @param to Address of the receiver.
+ /// @param amount Amount of the ERC20 sent.
+ /// @param extraData Extra data sent with the transaction.
+ event ERC20BridgeFinalized(
+ address indexed localToken,
+ address indexed remoteToken,
+ address indexed from,
+ address to,
+ uint256 amount,
+ bytes extraData
+ );
+
+ /// @notice Finalizes an ERC20 bridge on this chain. Can only be triggered by the other
+ /// StandardBridge contract on the remote chain.
+ /// @param _localToken Address of the ERC20 on this chain.
+ /// @param _remoteToken Address of the corresponding token on the remote chain.
+ /// @param _from Address of the sender.
+ /// @param _to Address of the receiver.
+ /// @param _amount Amount of the ERC20 being bridged.
+ /// @param _extraData Extra data to be sent with the transaction. Note that the recipient will
+ /// not be triggered with this data, but it will be emitted and can be used
+ /// to identify the transaction.
+ function finalizeBridgeERC20(
+ address _localToken,
+ address _remoteToken,
+ address _from,
+ address _to,
+ uint256 _amount,
+ bytes calldata _extraData
+ ) external;
+}
diff --git a/contracts/src/v0.8/liquiditymanager/interfaces/optimism/Types.sol b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/Types.sol
new file mode 100644
index 00000000000..bd8d5d3b630
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/interfaces/optimism/Types.sol
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MIT
+// Copied from https://github.com/ethereum-optimism/optimism/blob/v1.7.0/packages/contracts-bedrock/src/libraries/Types.sol
+pragma solidity ^0.8.0;
+
+/// @title Types
+/// @notice Contains various types used throughout the Optimism contract system.
+library Types {
+ /// @notice OutputProposal represents a commitment to the L2 state. The timestamp is the L1
+ /// timestamp that the output root is posted. This timestamp is used to verify that the
+ /// finalization period has passed since the output root was submitted.
+ /// @custom:field outputRoot Hash of the L2 output.
+ /// @custom:field timestamp Timestamp of the L1 block that the output root was submitted in.
+ /// @custom:field l2BlockNumber L2 block number that the output corresponds to.
+ struct OutputProposal {
+ bytes32 outputRoot;
+ uint128 timestamp;
+ uint128 l2BlockNumber;
+ }
+
+ /// @notice Struct representing the elements that are hashed together to generate an output root
+ /// which itself represents a snapshot of the L2 state.
+ /// @custom:field version Version of the output root.
+ /// @custom:field stateRoot Root of the state trie at the block of this output.
+ /// @custom:field messagePasserStorageRoot Root of the message passer storage trie.
+ /// @custom:field latestBlockhash Hash of the block this output was generated from.
+ struct OutputRootProof {
+ bytes32 version;
+ bytes32 stateRoot;
+ bytes32 messagePasserStorageRoot;
+ bytes32 latestBlockhash;
+ }
+
+ /// @notice Struct representing a deposit transaction (L1 => L2 transaction) created by an end
+ /// user (as opposed to a system deposit transaction generated by the system).
+ /// @custom:field from Address of the sender of the transaction.
+ /// @custom:field to Address of the recipient of the transaction.
+ /// @custom:field isCreation True if the transaction is a contract creation.
+ /// @custom:field value Value to send to the recipient.
+ /// @custom:field mint Amount of ETH to mint.
+ /// @custom:field gasLimit Gas limit of the transaction.
+ /// @custom:field data Data of the transaction.
+ /// @custom:field l1BlockHash Hash of the block the transaction was submitted in.
+ /// @custom:field logIndex Index of the log in the block the transaction was submitted in.
+ //solhint-disable gas-struct-packing
+ struct UserDepositTransaction {
+ address from;
+ address to;
+ bool isCreation;
+ uint256 value;
+ uint256 mint;
+ uint64 gasLimit;
+ bytes data;
+ bytes32 l1BlockHash;
+ uint256 logIndex;
+ }
+
+ /// @notice Struct representing a withdrawal transaction.
+ /// @custom:field nonce Nonce of the withdrawal transaction
+ /// @custom:field sender Address of the sender of the transaction.
+ /// @custom:field target Address of the recipient of the transaction.
+ /// @custom:field value Value to send to the recipient.
+ /// @custom:field gasLimit Gas limit of the transaction.
+ /// @custom:field data Data of the transaction.
+ struct WithdrawalTransaction {
+ uint256 nonce;
+ address sender;
+ address target;
+ uint256 value;
+ uint256 gasLimit;
+ bytes data;
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/ocr/OCR3Abstract.sol b/contracts/src/v0.8/liquiditymanager/ocr/OCR3Abstract.sol
new file mode 100644
index 00000000000..44e5d89f7fb
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/ocr/OCR3Abstract.sol
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
+
+abstract contract OCR3Abstract 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 setOCR3Config(
+ 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);
+
+ function _configDigestFromConfigData(
+ uint256 chainId,
+ address contractAddress,
+ uint64 configCount,
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) internal pure returns (bytes32) {
+ uint256 h = uint256(
+ keccak256(
+ abi.encode(
+ chainId,
+ contractAddress,
+ configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ )
+ )
+ );
+ uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00
+ uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00
+ return bytes32((prefix & prefixMask) | (h & ~prefixMask));
+ }
+
+ /// @notice optionally emitted to indicate the latest configDigest and sequence number
+ /// for which a report was successfully transmitted. Alternatively, the contract may
+ /// use latestConfigDigestAndEpoch with scanLogs set to false.
+ event Transmitted(bytes32 configDigest, uint64 sequenceNumber);
+
+ /// @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 MAX_NUM_ORACLES entries
+ /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES 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/liquiditymanager/ocr/OCR3Base.sol b/contracts/src/v0.8/liquiditymanager/ocr/OCR3Base.sol
new file mode 100644
index 00000000000..b856f734e7b
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/ocr/OCR3Base.sol
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
+import {OCR3Abstract} from "./OCR3Abstract.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 OCR3Base is OwnerIsCreator, OCR3Abstract {
+ error InvalidConfig(string message);
+ error WrongMessageLength(uint256 expected, uint256 actual);
+ error ConfigDigestMismatch(bytes32 expected, bytes32 actual);
+ error ForkedChain(uint256 expected, uint256 actual);
+ error WrongNumberOfSignatures();
+ error SignaturesOutOfRegistration();
+ error UnauthorizedTransmitter();
+ error UnauthorizedSigner();
+ error NonUniqueSignatures();
+ error OracleCannotBeZeroAddress();
+ error NonIncreasingSequenceNumber(uint64 sequenceNumber, uint64 latestSequenceNumber);
+
+ // Packing these fields used on the hot path in a ConfigInfo variable reduces the
+ // retrieval of all of them to a minimum number of SLOADs.
+ struct ConfigInfo {
+ bytes32 latestConfigDigest;
+ uint8 f;
+ uint8 n;
+ }
+
+ // 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 OCR3Aggregator.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
+ }
+
+ // The current config
+ ConfigInfo internal s_configInfo;
+
+ // incremented each time a new config is posted. This count is incorporated
+ // into the config digest, to prevent replay attacks.
+ uint32 internal s_configCount;
+ // makes it easier for offchain systems to extract config from logs.
+ uint32 internal s_latestConfigBlockNumber;
+
+ uint64 internal s_latestSequenceNumber;
+
+ // signer OR transmitter address
+ mapping(address signerOrTransmitter => Oracle 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;
+
+ // 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
+
+ uint256 internal immutable i_chainID;
+
+ constructor() {
+ i_chainID = block.chainid;
+ }
+
+ // 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");
+ _;
+ }
+
+ /// @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 setOCR3Config(
+ 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 {
+ _beforeSetConfig(onchainConfig);
+ uint256 oldSignerLength = s_signers.length;
+ for (uint256 i = 0; i < oldSignerLength; ++i) {
+ delete s_oracles[s_signers[i]];
+ delete s_oracles[s_transmitters[i]];
+ }
+
+ uint256 newSignersLength = signers.length;
+ for (uint256 i = 0; i < newSignersLength; ++i) {
+ // add new signer/transmitter addresses
+ address signer = signers[i];
+ if (s_oracles[signer].role != Role.Unset) revert InvalidConfig("repeated signer address");
+ if (signer == address(0)) revert OracleCannotBeZeroAddress();
+ s_oracles[signer] = Oracle(uint8(i), Role.Signer);
+
+ address transmitter = transmitters[i];
+ if (s_oracles[transmitter].role != Role.Unset) revert InvalidConfig("repeated transmitter address");
+ if (transmitter == address(0)) revert OracleCannotBeZeroAddress();
+ s_oracles[transmitter] = Oracle(uint8(i), Role.Transmitter);
+ }
+
+ s_signers = signers;
+ s_transmitters = transmitters;
+
+ s_configInfo.f = f;
+ s_configInfo.n = uint8(newSignersLength);
+ s_configInfo.latestConfigDigest = _configDigestFromConfigData(
+ block.chainid,
+ address(this),
+ ++s_configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+
+ uint32 previousConfigBlockNumber = s_latestConfigBlockNumber;
+ s_latestConfigBlockNumber = uint32(block.number);
+ s_latestSequenceNumber = 0;
+
+ emit ConfigSet(
+ previousConfigBlockNumber,
+ s_configInfo.latestConfigDigest,
+ s_configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+ }
+
+ /// @dev Hook that is run from setOCR3Config() right after validating configuration.
+ /// Empty by default, please provide an implementation in a child contract if you need additional configuration processing
+ function _beforeSetConfig(bytes memory _onchainConfig) internal virtual {}
+
+ /// @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 getTransmitters() external view returns (address[] memory) {
+ return s_transmitters;
+ }
+
+ /// @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 MAX_NUM_ORACLES entries
+ /// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES 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 {
+ uint64 sequenceNumber = uint64(uint256(reportContext[1]));
+ if (sequenceNumber <= s_latestSequenceNumber) {
+ revert NonIncreasingSequenceNumber(sequenceNumber, s_latestSequenceNumber);
+ }
+
+ // Scoping this reduces stack pressure and gas usage
+ {
+ _report(report, sequenceNumber);
+ }
+
+ s_latestSequenceNumber = sequenceNumber;
+ // reportContext consists of:
+ // reportContext[0]: ConfigDigest
+ // reportContext[1]: 24 byte padding, 8 byte sequence number
+ bytes32 configDigest = reportContext[0];
+ ConfigInfo memory configInfo = s_configInfo;
+
+ if (configInfo.latestConfigDigest != configDigest) {
+ revert ConfigDigestMismatch(configInfo.latestConfigDigest, configDigest);
+ }
+ // If the cached chainID at time of deployment doesn't match the current chainID, we reject all signed reports.
+ // This avoids a (rare) scenario where chain A forks into chain A and A', A' still has configDigest
+ // calculated from chain A and so OCR reports will be valid on both forks.
+ if (i_chainID != block.chainid) revert ForkedChain(i_chainID, block.chainid);
+
+ emit Transmitted(configDigest, sequenceNumber);
+
+ if (rs.length != configInfo.f + 1) revert WrongNumberOfSignatures();
+ if (rs.length != ss.length) revert SignaturesOutOfRegistration();
+
+ // Scoping this reduces stack pressure and gas usage
+ {
+ Oracle memory transmitter = s_oracles[msg.sender];
+ // Check that sender is authorized to report
+ if (!(transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index]))
+ revert UnauthorizedTransmitter();
+ }
+ // Scoping this reduces stack pressure and gas usage
+ {
+ uint256 expectedDataLength = 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)
+ if (msg.data.length != expectedDataLength) revert WrongMessageLength(expectedDataLength, msg.data.length);
+ }
+
+ // Verify signatures attached to report
+ bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext));
+ bool[MAX_NUM_ORACLES] memory signed;
+
+ uint256 numberOfSignatures = rs.length;
+ for (uint256 i = 0; i < numberOfSignatures; ++i) {
+ // Safe from ECDSA malleability here since we check for duplicate signers.
+ address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]);
+ // Since we disallow address(0) as a valid signer address, it can
+ // never have a signer role.
+ Oracle memory oracle = s_oracles[signer];
+ if (oracle.role != Role.Signer) revert UnauthorizedSigner();
+ if (signed[oracle.index]) revert NonUniqueSignatures();
+ signed[oracle.index] = true;
+ }
+ }
+
+ /// @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);
+ }
+
+ /// @notice gets the latest sequence number accepted by the contract
+ /// @return sequenceNumber the monotomically incremenenting number associated with OCR reports
+ function latestSequenceNumber() external view virtual returns (uint64 sequenceNumber) {
+ return s_latestSequenceNumber;
+ }
+
+ function _report(bytes calldata report, uint64 sequenceNumber) internal virtual;
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/LiquidityManager.t.sol b/contracts/src/v0.8/liquiditymanager/test/LiquidityManager.t.sol
new file mode 100644
index 00000000000..73c9ba74455
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/LiquidityManager.t.sol
@@ -0,0 +1,945 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {ILiquidityManager} from "../interfaces/ILiquidityManager.sol";
+import {IBridgeAdapter} from "../interfaces/IBridge.sol";
+
+import {LockReleaseTokenPool} from "../../ccip/pools/LockReleaseTokenPool.sol";
+import {LiquidityManager} from "../LiquidityManager.sol";
+import {MockL1BridgeAdapter} from "./mocks/MockBridgeAdapter.sol";
+import {LiquidityManagerBaseTest} from "./LiquidityManagerBaseTest.t.sol";
+import {LiquidityManagerHelper} from "./helpers/LiquidityManagerHelper.sol";
+
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+// FOUNDRY_PROFILE=liquiditymanager forge test --match-path src/v0.8/liquiditymanager/test/LiquidityManager.t.sol
+
+contract LiquidityManagerSetup is LiquidityManagerBaseTest {
+ event FinalizationStepCompleted(
+ uint64 indexed ocrSeqNum,
+ uint64 indexed remoteChainSelector,
+ bytes bridgeSpecificData
+ );
+ event LiquidityTransferred(
+ uint64 indexed ocrSeqNum,
+ uint64 indexed fromChainSelector,
+ uint64 indexed toChainSelector,
+ address to,
+ uint256 amount,
+ bytes bridgeSpecificPayload,
+ bytes bridgeReturnData
+ );
+ event FinalizationFailed(
+ uint64 indexed ocrSeqNum,
+ uint64 indexed remoteChainSelector,
+ bytes bridgeSpecificData,
+ bytes reason
+ );
+ event FinanceRoleSet(address financeRole);
+ event LiquidityAddedToContainer(address indexed provider, uint256 indexed amount);
+ event LiquidityRemovedFromContainer(address indexed remover, uint256 indexed amount);
+ // Liquidity container event
+ event LiquidityAdded(address indexed provider, uint256 indexed amount);
+ event LiquidityRemoved(address indexed remover, uint256 indexed amount);
+
+ error NonceAlreadyUsed(uint256 nonce);
+
+ LiquidityManagerHelper internal s_liquidityManager;
+ LockReleaseTokenPool internal s_lockReleaseTokenPool;
+ MockL1BridgeAdapter internal s_bridgeAdapter;
+
+ // LiquidityManager that rebalances weth.
+ LiquidityManagerHelper internal s_wethRebalancer;
+ LockReleaseTokenPool internal s_wethLockReleaseTokenPool;
+ MockL1BridgeAdapter internal s_wethBridgeAdapter;
+
+ function setUp() public virtual override {
+ LiquidityManagerBaseTest.setUp();
+
+ s_bridgeAdapter = new MockL1BridgeAdapter(s_l1Token, false);
+ s_lockReleaseTokenPool = new LockReleaseTokenPool(s_l1Token, new address[](0), address(1), true, address(123));
+ s_liquidityManager = new LiquidityManagerHelper(
+ s_l1Token,
+ i_localChainSelector,
+ s_lockReleaseTokenPool,
+ 0,
+ FINANCE
+ );
+
+ s_lockReleaseTokenPool.setRebalancer(address(s_liquidityManager));
+
+ s_wethBridgeAdapter = new MockL1BridgeAdapter(IERC20(address(s_l1Weth)), true);
+ s_wethLockReleaseTokenPool = new LockReleaseTokenPool(
+ IERC20(address(s_l1Weth)),
+ new address[](0),
+ address(1),
+ true,
+ address(123)
+ );
+ s_wethRebalancer = new LiquidityManagerHelper(
+ IERC20(address(s_l1Weth)),
+ i_localChainSelector,
+ s_wethLockReleaseTokenPool,
+ 0,
+ FINANCE
+ );
+
+ s_wethLockReleaseTokenPool.setRebalancer(address(s_wethRebalancer));
+ }
+}
+
+contract LiquidityManager_addLiquidity is LiquidityManagerSetup {
+ function test_addLiquiditySuccess() external {
+ address caller = STRANGER;
+ vm.startPrank(caller);
+
+ uint256 amount = 12345679;
+ deal(address(s_l1Token), caller, amount);
+
+ s_l1Token.approve(address(s_liquidityManager), amount);
+
+ vm.expectEmit();
+ emit LiquidityAddedToContainer(caller, amount);
+
+ s_liquidityManager.addLiquidity(amount);
+
+ assertEq(s_l1Token.balanceOf(address(s_lockReleaseTokenPool)), amount);
+ }
+}
+
+contract LiquidityManager_removeLiquidity is LiquidityManagerSetup {
+ function test_removeLiquiditySuccess() external {
+ uint256 amount = 12345679;
+ deal(address(s_l1Token), address(s_lockReleaseTokenPool), amount);
+
+ vm.expectEmit();
+ emit LiquidityRemovedFromContainer(FINANCE, amount);
+
+ vm.startPrank(FINANCE);
+ s_liquidityManager.removeLiquidity(amount);
+
+ assertEq(s_l1Token.balanceOf(address(s_liquidityManager)), 0);
+ }
+
+ function test_InsufficientLiquidityReverts() external {
+ uint256 balance = 923;
+ uint256 requested = balance + 1;
+
+ deal(address(s_l1Token), address(s_lockReleaseTokenPool), balance);
+
+ vm.expectRevert(abi.encodeWithSelector(LiquidityManager.InsufficientLiquidity.selector, requested, balance, 0));
+
+ vm.startPrank(FINANCE);
+ s_liquidityManager.removeLiquidity(requested);
+ }
+
+ function test_OnlyFinanceRoleReverts() external {
+ vm.stopPrank();
+
+ vm.expectRevert(LiquidityManager.OnlyFinanceRole.selector);
+
+ s_liquidityManager.removeLiquidity(123);
+ }
+}
+
+contract LiquidityManager__report is LiquidityManagerSetup {
+ function test_EmptyReportReverts() external {
+ ILiquidityManager.LiquidityInstructions memory instructions = ILiquidityManager.LiquidityInstructions({
+ sendLiquidityParams: new ILiquidityManager.SendLiquidityParams[](0),
+ receiveLiquidityParams: new ILiquidityManager.ReceiveLiquidityParams[](0)
+ });
+
+ vm.expectRevert(LiquidityManager.EmptyReport.selector);
+
+ s_liquidityManager.report(abi.encode(instructions), 123);
+ }
+}
+
+contract LiquidityManager_rebalanceLiquidity is LiquidityManagerSetup {
+ uint256 internal constant AMOUNT = 12345679;
+
+ function test_rebalanceLiquiditySuccess() external {
+ deal(address(s_l1Token), address(s_lockReleaseTokenPool), AMOUNT);
+
+ LiquidityManager.CrossChainRebalancerArgs[] memory args = new LiquidityManager.CrossChainRebalancerArgs[](1);
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(s_liquidityManager),
+ localBridge: s_bridgeAdapter,
+ remoteToken: address(s_l2Token),
+ remoteChainSelector: i_remoteChainSelector,
+ enabled: true
+ });
+ s_liquidityManager.setCrossChainRebalancers(args);
+
+ vm.expectEmit();
+ emit Transfer(address(s_lockReleaseTokenPool), address(s_liquidityManager), AMOUNT);
+
+ vm.expectEmit();
+ emit Approval(address(s_liquidityManager), address(s_bridgeAdapter), AMOUNT);
+
+ vm.expectEmit();
+ emit Transfer(address(s_liquidityManager), address(s_bridgeAdapter), AMOUNT);
+
+ vm.expectEmit();
+ bytes memory encodedNonce = abi.encode(uint256(1));
+ emit LiquidityTransferred(
+ type(uint64).max,
+ i_localChainSelector,
+ i_remoteChainSelector,
+ address(s_liquidityManager),
+ AMOUNT,
+ bytes(""),
+ encodedNonce
+ );
+
+ vm.startPrank(FINANCE);
+ s_liquidityManager.rebalanceLiquidity(i_remoteChainSelector, AMOUNT, 0, bytes(""));
+
+ assertEq(s_l1Token.balanceOf(address(s_liquidityManager)), 0);
+ assertEq(s_l1Token.balanceOf(address(s_bridgeAdapter)), AMOUNT);
+ assertEq(s_l1Token.allowance(address(s_liquidityManager), address(s_bridgeAdapter)), 0);
+ }
+
+ /// @notice this test sets up a circular system where the liquidity container of
+ /// the local Liquidity manager is the bridge adapter of the remote liquidity manager
+ /// and the other way around for the remote liquidity manager. This allows us to
+ /// rebalance funds between the two liquidity managers on the same chain.
+ function test_rebalanceBetweenPoolsSuccess() external {
+ uint256 amount = 12345670;
+
+ s_liquidityManager = new LiquidityManagerHelper(s_l1Token, i_localChainSelector, s_bridgeAdapter, 0, FINANCE);
+
+ MockL1BridgeAdapter mockRemoteBridgeAdapter = new MockL1BridgeAdapter(s_l1Token, false);
+ LiquidityManager mockRemoteRebalancer = new LiquidityManager(
+ s_l1Token,
+ i_remoteChainSelector,
+ mockRemoteBridgeAdapter,
+ 0,
+ FINANCE
+ );
+
+ LiquidityManager.CrossChainRebalancerArgs[] memory args = new LiquidityManager.CrossChainRebalancerArgs[](1);
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(mockRemoteRebalancer),
+ localBridge: mockRemoteBridgeAdapter,
+ remoteToken: address(s_l1Token),
+ remoteChainSelector: i_remoteChainSelector,
+ enabled: true
+ });
+
+ s_liquidityManager.setCrossChainRebalancers(args);
+
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(s_liquidityManager),
+ localBridge: s_bridgeAdapter,
+ remoteToken: address(s_l1Token),
+ remoteChainSelector: i_localChainSelector,
+ enabled: true
+ });
+
+ mockRemoteRebalancer.setCrossChainRebalancers(args);
+
+ deal(address(s_l1Token), address(s_bridgeAdapter), amount);
+
+ vm.startPrank(FINANCE);
+ s_liquidityManager.rebalanceLiquidity(i_remoteChainSelector, amount, 0, bytes(""));
+
+ assertEq(s_l1Token.balanceOf(address(s_bridgeAdapter)), 0);
+ assertEq(s_l1Token.balanceOf(address(mockRemoteBridgeAdapter)), amount);
+ assertEq(s_l1Token.allowance(address(s_liquidityManager), address(s_bridgeAdapter)), 0);
+
+ // attach a bridge fee and see the relevant adapter's ether balance change.
+ // the bridge fee is sent along with the sendERC20 call.
+ uint256 bridgeFee = 123;
+ vm.deal(address(mockRemoteRebalancer), bridgeFee);
+ mockRemoteRebalancer.rebalanceLiquidity(i_localChainSelector, amount, bridgeFee, bytes(""));
+
+ assertEq(s_l1Token.balanceOf(address(s_bridgeAdapter)), amount);
+ assertEq(s_l1Token.balanceOf(address(mockRemoteBridgeAdapter)), 0);
+ assertEq(address(s_bridgeAdapter).balance, bridgeFee);
+
+ // Assert partial rebalancing works correctly
+ s_liquidityManager.rebalanceLiquidity(i_remoteChainSelector, amount / 2, 0, bytes(""));
+
+ assertEq(s_l1Token.balanceOf(address(s_bridgeAdapter)), amount / 2);
+ assertEq(s_l1Token.balanceOf(address(mockRemoteBridgeAdapter)), amount / 2);
+ }
+
+ function test_rebalanceBetweenPoolsSuccess_AlreadyFinalized() external {
+ // set up a rebalancer on another chain, an "L2".
+ // note we use the L1 bridge adapter because it has the reverting logic
+ // when finalization is already done.
+ MockL1BridgeAdapter remoteBridgeAdapter = new MockL1BridgeAdapter(s_l2Token, false);
+ LockReleaseTokenPool remotePool = new LockReleaseTokenPool(
+ s_l2Token,
+ new address[](0),
+ address(1),
+ true,
+ address(123)
+ );
+ LiquidityManager remoteRebalancer = new LiquidityManager(s_l2Token, i_remoteChainSelector, remotePool, 0, FINANCE);
+
+ // set rebalancer role on the pool.
+ remotePool.setRebalancer(address(remoteRebalancer));
+
+ // set up the cross chain rebalancer on "L1".
+ LiquidityManager.CrossChainRebalancerArgs[] memory args = new LiquidityManager.CrossChainRebalancerArgs[](1);
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(remoteRebalancer),
+ localBridge: s_bridgeAdapter,
+ remoteToken: address(s_l2Token),
+ remoteChainSelector: i_remoteChainSelector,
+ enabled: true
+ });
+
+ s_liquidityManager.setCrossChainRebalancers(args);
+
+ // set up the cross chain rebalancer on "L2".
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(s_liquidityManager),
+ localBridge: remoteBridgeAdapter,
+ remoteToken: address(s_l1Token),
+ remoteChainSelector: i_localChainSelector,
+ enabled: true
+ });
+
+ remoteRebalancer.setCrossChainRebalancers(args);
+
+ // deal some L1 tokens to the L1 bridge adapter so that it can send them to the rebalancer
+ // when the withdrawal gets finalized.
+ deal(address(s_l1Token), address(s_bridgeAdapter), AMOUNT);
+ // deal some L2 tokens to the remote token pool so that we can withdraw it when we rebalance.
+ deal(address(s_l2Token), address(remotePool), AMOUNT);
+
+ uint256 nonce = 1;
+ uint64 maxSeqNum = type(uint64).max;
+ bytes memory bridgeSendReturnData = abi.encode(nonce);
+ bytes memory bridgeSpecificPayload = bytes("");
+ vm.expectEmit();
+ emit LiquidityRemoved(address(remoteRebalancer), AMOUNT);
+ vm.expectEmit();
+ emit LiquidityTransferred(
+ maxSeqNum,
+ i_remoteChainSelector,
+ i_localChainSelector,
+ address(s_liquidityManager),
+ AMOUNT,
+ bridgeSpecificPayload,
+ bridgeSendReturnData
+ );
+ vm.startPrank(FINANCE);
+ remoteRebalancer.rebalanceLiquidity(i_localChainSelector, AMOUNT, 0, bridgeSpecificPayload);
+
+ // available liquidity has been moved to the remote bridge adapter from the token pool.
+ assertEq(s_l2Token.balanceOf(address(remoteBridgeAdapter)), AMOUNT, "remoteBridgeAdapter balance");
+ assertEq(s_l2Token.balanceOf(address(remotePool)), 0, "remotePool balance");
+
+ // prove and finalize manually on the L1 bridge adapter.
+ // this should transfer the funds to the rebalancer.
+ MockL1BridgeAdapter.ProvePayload memory provePayload = MockL1BridgeAdapter.ProvePayload({nonce: nonce});
+ MockL1BridgeAdapter.Payload memory payload = MockL1BridgeAdapter.Payload({
+ action: MockL1BridgeAdapter.FinalizationAction.ProveWithdrawal,
+ data: abi.encode(provePayload)
+ });
+ bool fundsAvailable = s_bridgeAdapter.finalizeWithdrawERC20(
+ address(0),
+ address(s_liquidityManager),
+ abi.encode(payload)
+ );
+ assertFalse(fundsAvailable, "fundsAvailable must be false");
+ MockL1BridgeAdapter.FinalizePayload memory finalizePayload = MockL1BridgeAdapter.FinalizePayload({
+ nonce: nonce,
+ amount: AMOUNT
+ });
+ payload = MockL1BridgeAdapter.Payload({
+ action: MockL1BridgeAdapter.FinalizationAction.FinalizeWithdrawal,
+ data: abi.encode(finalizePayload)
+ });
+ fundsAvailable = s_bridgeAdapter.finalizeWithdrawERC20(
+ address(0),
+ address(s_liquidityManager),
+ abi.encode(payload)
+ );
+ assertTrue(fundsAvailable, "fundsAvailable must be true");
+
+ // available balance on the L1 bridge adapter has been moved to the rebalancer.
+ assertEq(s_l1Token.balanceOf(address(s_liquidityManager)), AMOUNT, "rebalancer balance 1");
+ assertEq(s_l1Token.balanceOf(address(s_bridgeAdapter)), 0, "bridgeAdapter balance");
+
+ // try to finalize on L1 again
+ // bytes memory revertData = abi.encodeWithSelector(NonceAlreadyUsed.selector, nonce);
+ vm.expectEmit();
+ emit FinalizationFailed(
+ maxSeqNum,
+ i_remoteChainSelector,
+ abi.encode(payload),
+ abi.encodeWithSelector(NonceAlreadyUsed.selector, nonce)
+ );
+ vm.expectEmit();
+ emit LiquidityAdded(address(s_liquidityManager), AMOUNT);
+ vm.expectEmit();
+ emit LiquidityTransferred(
+ maxSeqNum,
+ i_remoteChainSelector,
+ i_localChainSelector,
+ address(s_liquidityManager),
+ AMOUNT,
+ abi.encode(payload),
+ bytes("")
+ );
+ s_liquidityManager.receiveLiquidity(i_remoteChainSelector, AMOUNT, false, abi.encode(payload));
+
+ // available balance on the rebalancer has been injected into the token pool.
+ assertEq(s_l1Token.balanceOf(address(s_liquidityManager)), 0, "rebalancer balance 2");
+ assertEq(s_l1Token.balanceOf(address(s_lockReleaseTokenPool)), AMOUNT, "lockReleaseTokenPool balance");
+ }
+
+ function test_rebalanceBetweenPools_MultiStageFinalization() external {
+ // set up a rebalancer on another chain, an "L2".
+ // note we use the L1 bridge adapter because it has the reverting logic
+ // when finalization is already done.
+ MockL1BridgeAdapter remoteBridgeAdapter = new MockL1BridgeAdapter(s_l2Token, false);
+ LockReleaseTokenPool remotePool = new LockReleaseTokenPool(
+ s_l2Token,
+ new address[](0),
+ address(1),
+ true,
+ address(123)
+ );
+ LiquidityManager remoteRebalancer = new LiquidityManager(s_l2Token, i_remoteChainSelector, remotePool, 0, FINANCE);
+
+ // set rebalancer role on the pool.
+ remotePool.setRebalancer(address(remoteRebalancer));
+
+ // set up the cross chain rebalancer on "L1".
+ LiquidityManager.CrossChainRebalancerArgs[] memory args = new LiquidityManager.CrossChainRebalancerArgs[](1);
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(remoteRebalancer),
+ localBridge: s_bridgeAdapter,
+ remoteToken: address(s_l2Token),
+ remoteChainSelector: i_remoteChainSelector,
+ enabled: true
+ });
+
+ s_liquidityManager.setCrossChainRebalancers(args);
+
+ // set up the cross chain rebalancer on "L2".
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(s_liquidityManager),
+ localBridge: remoteBridgeAdapter,
+ remoteToken: address(s_l1Token),
+ remoteChainSelector: i_localChainSelector,
+ enabled: true
+ });
+
+ remoteRebalancer.setCrossChainRebalancers(args);
+
+ // deal some L1 tokens to the L1 bridge adapter so that it can send them to the rebalancer
+ // when the withdrawal gets finalized.
+ deal(address(s_l1Token), address(s_bridgeAdapter), AMOUNT);
+ // deal some L2 tokens to the remote token pool so that we can withdraw it when we rebalance.
+ deal(address(s_l2Token), address(remotePool), AMOUNT);
+
+ // initiate a send from remote rebalancer to s_liquidityManager.
+ uint256 nonce = 1;
+ uint64 maxSeqNum = type(uint64).max;
+ bytes memory bridgeSendReturnData = abi.encode(nonce);
+ bytes memory bridgeSpecificPayload = bytes("");
+ vm.expectEmit();
+ emit LiquidityRemoved(address(remoteRebalancer), AMOUNT);
+ vm.expectEmit();
+ emit LiquidityTransferred(
+ maxSeqNum,
+ i_remoteChainSelector,
+ i_localChainSelector,
+ address(s_liquidityManager),
+ AMOUNT,
+ bridgeSpecificPayload,
+ bridgeSendReturnData
+ );
+ vm.startPrank(FINANCE);
+ remoteRebalancer.rebalanceLiquidity(i_localChainSelector, AMOUNT, 0, bridgeSpecificPayload);
+
+ // available liquidity has been moved to the remote bridge adapter from the token pool.
+ assertEq(s_l2Token.balanceOf(address(remoteBridgeAdapter)), AMOUNT, "remoteBridgeAdapter balance");
+ assertEq(s_l2Token.balanceOf(address(remotePool)), 0, "remotePool balance");
+
+ // prove withdrawal on the L1 bridge adapter, through the rebalancer.
+ uint256 balanceBeforeProve = s_l1Token.balanceOf(address(s_lockReleaseTokenPool));
+ MockL1BridgeAdapter.ProvePayload memory provePayload = MockL1BridgeAdapter.ProvePayload({nonce: nonce});
+ MockL1BridgeAdapter.Payload memory payload = MockL1BridgeAdapter.Payload({
+ action: MockL1BridgeAdapter.FinalizationAction.ProveWithdrawal,
+ data: abi.encode(provePayload)
+ });
+ vm.expectEmit();
+ emit FinalizationStepCompleted(maxSeqNum, i_remoteChainSelector, abi.encode(payload));
+ s_liquidityManager.receiveLiquidity(i_remoteChainSelector, AMOUNT, false, abi.encode(payload));
+
+ // s_liquidityManager should have no tokens.
+ assertEq(s_l1Token.balanceOf(address(s_liquidityManager)), 0, "rebalancer balance 1");
+ // balance of s_lockReleaseTokenPool should be unchanged since no liquidity got added yet.
+ assertEq(
+ s_l1Token.balanceOf(address(s_lockReleaseTokenPool)),
+ balanceBeforeProve,
+ "s_lockReleaseTokenPool balance should be unchanged"
+ );
+
+ // finalize withdrawal on the L1 bridge adapter, through the rebalancer.
+ MockL1BridgeAdapter.FinalizePayload memory finalizePayload = MockL1BridgeAdapter.FinalizePayload({
+ nonce: nonce,
+ amount: AMOUNT
+ });
+ payload = MockL1BridgeAdapter.Payload({
+ action: MockL1BridgeAdapter.FinalizationAction.FinalizeWithdrawal,
+ data: abi.encode(finalizePayload)
+ });
+ vm.expectEmit();
+ emit LiquidityAdded(address(s_liquidityManager), AMOUNT);
+ vm.expectEmit();
+ emit LiquidityTransferred(
+ maxSeqNum,
+ i_remoteChainSelector,
+ i_localChainSelector,
+ address(s_liquidityManager),
+ AMOUNT,
+ abi.encode(payload),
+ bytes("")
+ );
+ s_liquidityManager.receiveLiquidity(i_remoteChainSelector, AMOUNT, false, abi.encode(payload));
+
+ // s_liquidityManager should have no tokens.
+ assertEq(s_l1Token.balanceOf(address(s_liquidityManager)), 0, "rebalancer balance 2");
+ // balance of s_lockReleaseTokenPool should be updated
+ assertEq(
+ s_l1Token.balanceOf(address(s_lockReleaseTokenPool)),
+ balanceBeforeProve + AMOUNT,
+ "s_lockReleaseTokenPool balance should be updated"
+ );
+ }
+
+ function test_rebalanceBetweenPools_NativeRewrap() external {
+ // set up a rebalancer similar to the above on another chain, an "L2".
+ MockL1BridgeAdapter remoteBridgeAdapter = new MockL1BridgeAdapter(IERC20(address(s_l2Weth)), true);
+ LockReleaseTokenPool remotePool = new LockReleaseTokenPool(
+ IERC20(address(s_l2Weth)),
+ new address[](0),
+ address(1),
+ true,
+ address(123)
+ );
+ LiquidityManager remoteRebalancer = new LiquidityManager(
+ IERC20(address(s_l2Weth)),
+ i_remoteChainSelector,
+ remotePool,
+ 0,
+ FINANCE
+ );
+
+ // set rebalancer role on the pool.
+ remotePool.setRebalancer(address(remoteRebalancer));
+
+ // set up the cross chain rebalancer on "L1".
+ LiquidityManager.CrossChainRebalancerArgs[] memory args = new LiquidityManager.CrossChainRebalancerArgs[](1);
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(remoteRebalancer),
+ localBridge: s_wethBridgeAdapter,
+ remoteToken: address(s_l2Weth),
+ remoteChainSelector: i_remoteChainSelector,
+ enabled: true
+ });
+
+ s_wethRebalancer.setCrossChainRebalancers(args);
+
+ // set up the cross chain rebalancer on "L2".
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(s_wethRebalancer),
+ localBridge: remoteBridgeAdapter,
+ remoteToken: address(s_l1Weth),
+ remoteChainSelector: i_localChainSelector,
+ enabled: true
+ });
+
+ remoteRebalancer.setCrossChainRebalancers(args);
+
+ // deal some ether to the L1 bridge adapter so that it can send them to the rebalancer
+ // when the withdrawal gets finalized.
+ vm.deal(address(s_wethBridgeAdapter), AMOUNT);
+ // deal some L2 tokens to the remote token pool so that we can withdraw it when we rebalance.
+ deal(address(s_l2Weth), address(remotePool), AMOUNT);
+ // deposit some eth to the weth contract on L2 from the remote bridge adapter
+ // so that the withdraw() call succeeds.
+ vm.deal(address(remoteBridgeAdapter), AMOUNT);
+ vm.startPrank(address(remoteBridgeAdapter));
+ s_l2Weth.deposit{value: AMOUNT}();
+ vm.stopPrank();
+
+ // switch to finance for the rest of the test to avoid reverts.
+ vm.startPrank(FINANCE);
+
+ // initiate a send from remote rebalancer to s_wethRebalancer.
+ uint256 nonce = 1;
+ uint64 maxSeqNum = type(uint64).max;
+ bytes memory bridgeSendReturnData = abi.encode(nonce);
+ bytes memory bridgeSpecificPayload = bytes("");
+ vm.expectEmit();
+ emit LiquidityRemoved(address(remoteRebalancer), AMOUNT);
+ vm.expectEmit();
+ emit LiquidityTransferred(
+ maxSeqNum,
+ i_remoteChainSelector,
+ i_localChainSelector,
+ address(s_wethRebalancer),
+ AMOUNT,
+ bridgeSpecificPayload,
+ bridgeSendReturnData
+ );
+ remoteRebalancer.rebalanceLiquidity(i_localChainSelector, AMOUNT, 0, bridgeSpecificPayload);
+
+ // available liquidity has been moved to the remote bridge adapter from the token pool.
+ assertEq(s_l2Weth.balanceOf(address(remoteBridgeAdapter)), AMOUNT, "remoteBridgeAdapter balance");
+ assertEq(s_l2Weth.balanceOf(address(remotePool)), 0, "remotePool balance");
+
+ // prove withdrawal on the L1 bridge adapter, through the rebalancer.
+ uint256 balanceBeforeProve = s_l1Weth.balanceOf(address(s_wethLockReleaseTokenPool));
+ MockL1BridgeAdapter.ProvePayload memory provePayload = MockL1BridgeAdapter.ProvePayload({nonce: nonce});
+ MockL1BridgeAdapter.Payload memory payload = MockL1BridgeAdapter.Payload({
+ action: MockL1BridgeAdapter.FinalizationAction.ProveWithdrawal,
+ data: abi.encode(provePayload)
+ });
+ vm.expectEmit();
+ emit FinalizationStepCompleted(maxSeqNum, i_remoteChainSelector, abi.encode(payload));
+ s_wethRebalancer.receiveLiquidity(i_remoteChainSelector, AMOUNT, false, abi.encode(payload));
+
+ // s_wethRebalancer should have no tokens.
+ assertEq(s_l1Weth.balanceOf(address(s_wethRebalancer)), 0, "rebalancer balance 1");
+ // balance of s_wethLockReleaseTokenPool should be unchanged since no liquidity got added yet.
+ assertEq(
+ s_l1Weth.balanceOf(address(s_wethLockReleaseTokenPool)),
+ balanceBeforeProve,
+ "s_wethLockReleaseTokenPool balance should be unchanged"
+ );
+
+ // finalize withdrawal on the L1 bridge adapter, through the rebalancer.
+ MockL1BridgeAdapter.FinalizePayload memory finalizePayload = MockL1BridgeAdapter.FinalizePayload({
+ nonce: nonce,
+ amount: AMOUNT
+ });
+ payload = MockL1BridgeAdapter.Payload({
+ action: MockL1BridgeAdapter.FinalizationAction.FinalizeWithdrawal,
+ data: abi.encode(finalizePayload)
+ });
+ vm.expectEmit();
+ emit LiquidityAdded(address(s_wethRebalancer), AMOUNT);
+ vm.expectEmit();
+ emit LiquidityTransferred(
+ maxSeqNum,
+ i_remoteChainSelector,
+ i_localChainSelector,
+ address(s_wethRebalancer),
+ AMOUNT,
+ abi.encode(payload),
+ bytes("")
+ );
+ s_wethRebalancer.receiveLiquidity(i_remoteChainSelector, AMOUNT, true, abi.encode(payload));
+
+ // s_wethRebalancer should have no tokens.
+ assertEq(s_l1Weth.balanceOf(address(s_wethRebalancer)), 0, "rebalancer balance 2");
+ // s_wethRebalancer should have no native tokens.
+ assertEq(address(s_wethRebalancer).balance, 0, "rebalancer native balance should be zero");
+ // balance of s_wethLockReleaseTokenPool should be updated
+ assertEq(
+ s_l1Weth.balanceOf(address(s_wethLockReleaseTokenPool)),
+ balanceBeforeProve + AMOUNT,
+ "s_wethLockReleaseTokenPool balance should be updated"
+ );
+ }
+
+ // Reverts
+
+ function test_InsufficientLiquidityReverts() external {
+ s_liquidityManager.setMinimumLiquidity(3);
+ deal(address(s_l1Token), address(s_lockReleaseTokenPool), AMOUNT);
+ vm.expectRevert(abi.encodeWithSelector(LiquidityManager.InsufficientLiquidity.selector, AMOUNT, AMOUNT, 3));
+
+ vm.startPrank(FINANCE);
+ s_liquidityManager.rebalanceLiquidity(0, AMOUNT, 0, bytes(""));
+ }
+
+ function test_InvalidRemoteChainReverts() external {
+ deal(address(s_l1Token), address(s_lockReleaseTokenPool), AMOUNT);
+
+ vm.expectRevert(abi.encodeWithSelector(LiquidityManager.InvalidRemoteChain.selector, i_remoteChainSelector));
+
+ vm.startPrank(FINANCE);
+ s_liquidityManager.rebalanceLiquidity(i_remoteChainSelector, AMOUNT, 0, bytes(""));
+ }
+}
+
+contract LiquidityManager_setCrossChainRebalancer is LiquidityManagerSetup {
+ event CrossChainRebalancerSet(
+ uint64 indexed remoteChainSelector,
+ IBridgeAdapter localBridge,
+ address remoteToken,
+ address remoteRebalancer,
+ bool enabled
+ );
+
+ function test_setCrossChainRebalancerSuccess() external {
+ address newRebalancer = address(23892423);
+ uint64 remoteChainSelector = 12301293;
+
+ uint64[] memory supportedChains = s_liquidityManager.getSupportedDestChains();
+ assertEq(supportedChains.length, 0);
+
+ LiquidityManager.CrossChainRebalancerArgs[] memory args = new LiquidityManager.CrossChainRebalancerArgs[](1);
+ args[0] = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: newRebalancer,
+ localBridge: s_bridgeAdapter,
+ remoteToken: address(190490124908),
+ remoteChainSelector: remoteChainSelector,
+ enabled: true
+ });
+
+ vm.expectEmit();
+ emit CrossChainRebalancerSet(
+ remoteChainSelector,
+ args[0].localBridge,
+ args[0].remoteToken,
+ newRebalancer,
+ args[0].enabled
+ );
+
+ s_liquidityManager.setCrossChainRebalancers(args);
+
+ assertEq(s_liquidityManager.getCrossChainRebalancer(remoteChainSelector).remoteRebalancer, newRebalancer);
+
+ LiquidityManager.CrossChainRebalancerArgs[] memory got = s_liquidityManager.getAllCrossChainRebalancers();
+ assertEq(got.length, 1);
+ assertEq(got[0].remoteRebalancer, args[0].remoteRebalancer);
+ assertEq(address(got[0].localBridge), address(args[0].localBridge));
+ assertEq(got[0].remoteToken, args[0].remoteToken);
+ assertEq(got[0].remoteChainSelector, args[0].remoteChainSelector);
+ assertEq(got[0].enabled, args[0].enabled);
+
+ supportedChains = s_liquidityManager.getSupportedDestChains();
+ assertEq(supportedChains.length, 1);
+ assertEq(supportedChains[0], remoteChainSelector);
+
+ address anotherRebalancer = address(123);
+ args[0].remoteRebalancer = anotherRebalancer;
+
+ vm.expectEmit();
+ emit CrossChainRebalancerSet(
+ remoteChainSelector,
+ args[0].localBridge,
+ args[0].remoteToken,
+ anotherRebalancer,
+ args[0].enabled
+ );
+
+ s_liquidityManager.setCrossChainRebalancer(args[0]);
+
+ assertEq(s_liquidityManager.getCrossChainRebalancer(remoteChainSelector).remoteRebalancer, anotherRebalancer);
+
+ supportedChains = s_liquidityManager.getSupportedDestChains();
+ assertEq(supportedChains.length, 1);
+ assertEq(supportedChains[0], remoteChainSelector);
+ }
+
+ function test_ZeroChainSelectorReverts() external {
+ LiquidityManager.CrossChainRebalancerArgs memory arg = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(9),
+ localBridge: s_bridgeAdapter,
+ remoteToken: address(190490124908),
+ remoteChainSelector: 0,
+ enabled: true
+ });
+
+ vm.expectRevert(LiquidityManager.ZeroChainSelector.selector);
+
+ s_liquidityManager.setCrossChainRebalancer(arg);
+ }
+
+ function test_ZeroAddressReverts() external {
+ LiquidityManager.CrossChainRebalancerArgs memory arg = ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(0),
+ localBridge: s_bridgeAdapter,
+ remoteToken: address(190490124908),
+ remoteChainSelector: 123,
+ enabled: true
+ });
+
+ vm.expectRevert(LiquidityManager.ZeroAddress.selector);
+
+ s_liquidityManager.setCrossChainRebalancer(arg);
+
+ arg.remoteRebalancer = address(9);
+ arg.localBridge = IBridgeAdapter(address(0));
+
+ vm.expectRevert(LiquidityManager.ZeroAddress.selector);
+
+ s_liquidityManager.setCrossChainRebalancer(arg);
+
+ arg.localBridge = s_bridgeAdapter;
+ arg.remoteToken = address(0);
+
+ vm.expectRevert(LiquidityManager.ZeroAddress.selector);
+
+ s_liquidityManager.setCrossChainRebalancer(arg);
+ }
+
+ function test_OnlyOwnerReverts() external {
+ vm.stopPrank();
+
+ vm.expectRevert("Only callable by owner");
+
+ // Test the entrypoint that takes a list
+ s_liquidityManager.setCrossChainRebalancers(new LiquidityManager.CrossChainRebalancerArgs[](0));
+
+ vm.expectRevert("Only callable by owner");
+
+ // Test the entrypoint that takes a single item
+ s_liquidityManager.setCrossChainRebalancer(
+ ILiquidityManager.CrossChainRebalancerArgs({
+ remoteRebalancer: address(9),
+ localBridge: s_bridgeAdapter,
+ remoteToken: address(190490124908),
+ remoteChainSelector: 124,
+ enabled: true
+ })
+ );
+ }
+}
+
+contract LiquidityManager_setLocalLiquidityContainer is LiquidityManagerSetup {
+ event LiquidityContainerSet(address indexed newLiquidityContainer);
+
+ function test_setLocalLiquidityContainerSuccess() external {
+ LockReleaseTokenPool newPool = new LockReleaseTokenPool(
+ s_l1Token,
+ new address[](0),
+ address(1),
+ true,
+ address(123)
+ );
+
+ vm.expectEmit();
+ emit LiquidityContainerSet(address(newPool));
+
+ s_liquidityManager.setLocalLiquidityContainer(newPool);
+
+ assertEq(s_liquidityManager.getLocalLiquidityContainer(), address(newPool));
+ }
+
+ function test_OnlyOwnerReverts() external {
+ vm.stopPrank();
+
+ vm.expectRevert("Only callable by owner");
+
+ s_liquidityManager.setLocalLiquidityContainer(LockReleaseTokenPool(address(1)));
+ }
+
+ function test_ReverstWhen_CalledWithTheZeroAddress() external {
+ vm.expectRevert(LiquidityManager.ZeroAddress.selector);
+ s_liquidityManager.setLocalLiquidityContainer(LockReleaseTokenPool(address(0)));
+ }
+}
+
+contract LiquidityManager_setMinimumLiquidity is LiquidityManagerSetup {
+ event MinimumLiquiditySet(uint256 oldBalance, uint256 newBalance);
+
+ function test_setMinimumLiquiditySuccess() external {
+ vm.expectEmit();
+ emit MinimumLiquiditySet(uint256(0), uint256(1000));
+ s_liquidityManager.setMinimumLiquidity(1000);
+ assertEq(s_liquidityManager.getMinimumLiquidity(), uint256(1000));
+ }
+
+ function test_OnlyOwnerReverts() external {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ s_liquidityManager.setMinimumLiquidity(uint256(1000));
+ }
+}
+
+contract LiquidityManager_setFinanceRole is LiquidityManagerSetup {
+ event MinimumLiquiditySet(uint256 oldBalance, uint256 newBalance);
+
+ function test_setFinanceRoleSuccess() external {
+ vm.expectEmit();
+ address newFinanceRole = makeAddr("newFinanceRole");
+ assertEq(s_liquidityManager.getFinanceRole(), FINANCE);
+ emit FinanceRoleSet(newFinanceRole);
+ s_liquidityManager.setFinanceRole(newFinanceRole);
+ assertEq(s_liquidityManager.getFinanceRole(), newFinanceRole);
+ }
+
+ function test_OnlyOwnerReverts() external {
+ vm.stopPrank();
+ vm.expectRevert("Only callable by owner");
+ s_liquidityManager.setFinanceRole(address(1));
+ }
+}
+
+contract LiquidityManager_withdrawNative is LiquidityManagerSetup {
+ event NativeWithdrawn(uint256 amount, address destination);
+
+ address private receiver = makeAddr("receiver");
+
+ function setUp() public override {
+ super.setUp();
+ vm.deal(address(s_liquidityManager), 1);
+ }
+
+ function test_withdrawNative_success() external {
+ assertEq(receiver.balance, 0);
+ vm.expectEmit();
+ emit NativeWithdrawn(1, receiver);
+ vm.startPrank(FINANCE);
+ s_liquidityManager.withdrawNative(1, payable(receiver));
+ assertEq(receiver.balance, 1);
+ }
+
+ function test_OnlyFinanceRoleReverts() external {
+ vm.stopPrank();
+ vm.expectRevert(LiquidityManager.OnlyFinanceRole.selector);
+ s_liquidityManager.withdrawNative(1, payable(receiver));
+ }
+}
+
+contract LiquidityManager_receive is LiquidityManagerSetup {
+ event NativeDeposited(uint256 amount, address depositor);
+
+ address private depositor = makeAddr("depositor");
+
+ function test_receive_success() external {
+ vm.deal(depositor, 100);
+ uint256 before = address(s_liquidityManager).balance;
+ vm.expectEmit();
+ emit NativeDeposited(100, depositor);
+ vm.startPrank(depositor);
+ payable(address(s_liquidityManager)).transfer(100);
+ assertEq(address(s_liquidityManager).balance, before + 100);
+ }
+}
+
+contract LiquidityManager_withdrawERC20 is LiquidityManagerSetup {
+ function test_withdrawERC20Success() external {
+ uint256 amount = 100;
+ deal(address(s_otherToken), address(s_liquidityManager), amount);
+ assertEq(s_otherToken.balanceOf(address(1)), 0);
+ assertEq(s_otherToken.balanceOf(address(s_liquidityManager)), amount);
+ vm.startPrank(FINANCE);
+ s_liquidityManager.withdrawERC20(address(s_otherToken), amount, address(1));
+ assertEq(s_otherToken.balanceOf(address(1)), amount);
+ assertEq(s_otherToken.balanceOf(address(s_liquidityManager)), 0);
+ }
+
+ function test_withdrawERC20Reverts() external {
+ uint256 amount = 100;
+ deal(address(s_otherToken), address(s_liquidityManager), amount);
+ vm.startPrank(STRANGER);
+ vm.expectRevert(LiquidityManager.OnlyFinanceRole.selector);
+ s_liquidityManager.withdrawERC20(address(s_otherToken), amount, address(1));
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/LiquidityManagerBaseTest.t.sol b/contracts/src/v0.8/liquiditymanager/test/LiquidityManagerBaseTest.t.sol
new file mode 100644
index 00000000000..128a03f255a
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/LiquidityManagerBaseTest.t.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {Test} from "forge-std/Test.sol";
+
+import {WETH9} from "../../ccip/test/WETH9.sol";
+
+import {ERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol";
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract LiquidityManagerBaseTest is Test {
+ // ERC20 events
+ event Transfer(address indexed from, address indexed to, uint256 value);
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+
+ IERC20 internal s_l1Token;
+ IERC20 internal s_l2Token;
+ IERC20 internal s_otherToken;
+ WETH9 internal s_l1Weth;
+ WETH9 internal s_l2Weth;
+
+ uint64 internal immutable i_localChainSelector = 1234;
+ uint64 internal immutable i_remoteChainSelector = 9876;
+
+ address internal constant FINANCE = address(0x00000fffffffffffffffffffff);
+ address internal constant OWNER = address(0x00000078772732723782873283);
+ address internal constant STRANGER = address(0x00000999999911111111222222);
+
+ function setUp() public virtual {
+ s_l1Token = new ERC20("l1", "L1");
+ s_l2Token = new ERC20("l2", "L2");
+ s_otherToken = new ERC20("other", "OTHER");
+
+ s_l1Weth = new WETH9();
+ s_l2Weth = new WETH9();
+
+ vm.startPrank(OWNER);
+
+ vm.label(FINANCE, "FINANCE");
+ vm.label(OWNER, "OWNER");
+ vm.label(STRANGER, "STRANGER");
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/ArbitrumL1BridgeAdapter.t.sol b/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/ArbitrumL1BridgeAdapter.t.sol
new file mode 100644
index 00000000000..8afea2d680d
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/ArbitrumL1BridgeAdapter.t.sol
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IWrappedNative} from "../../../ccip/interfaces/IWrappedNative.sol";
+
+import {ArbitrumL1BridgeAdapter, IOutbox} from "../../bridge-adapters/ArbitrumL1BridgeAdapter.sol";
+import "forge-std/Test.sol";
+
+import {IL1GatewayRouter} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/ethereum/gateway/IL1GatewayRouter.sol";
+import {IGatewayRouter} from "@arbitrum/token-bridge-contracts/contracts/tokenbridge/libraries/gateway/IGatewayRouter.sol";
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+//contract ArbitrumL1BridgeAdapterSetup is Test {
+// uint256 internal mainnetFork;
+// uint256 internal arbitrumFork;
+//
+// string internal constant MAINNET_RPC_URL = "";
+//
+// address internal constant L1_GATEWAY_ROUTER = 0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef;
+// address internal constant L1_ERC20_GATEWAY = 0xa3A7B6F88361F48403514059F1F16C8E78d60EeC;
+// address internal constant L1_INBOX = 0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f;
+// // inbox 0x5aED5f8A1e3607476F1f81c3d8fe126deB0aFE94?
+// address internal constant L1_OUTBOX = 0x0B9857ae2D4A3DBe74ffE1d7DF045bb7F96E4840;
+//
+// IERC20 internal constant L1_LINK = IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA);
+// IWrappedNative internal constant L1_WRAPPED_NATIVE = IWrappedNative(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
+//
+// address internal constant L2_GATEWAY_ROUTER = 0x5288c571Fd7aD117beA99bF60FE0846C4E84F933;
+// address internal constant L2_ETH_WITHDRAWAL_PRECOMPILE = 0x0000000000000000000000000000000000000064;
+//
+// IERC20 internal constant L2_LINK = IERC20(0xf97f4df75117a78c1A5a0DBb814Af92458539FB4);
+// IWrappedNative internal constant L2_WRAPPED_NATIVE = IWrappedNative(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
+//
+// ArbitrumL1BridgeAdapter internal s_l1BridgeAdapter;
+//
+// uint256 internal constant TOKEN_BALANCE = 10e18;
+// address internal constant OWNER = address(0xdead);
+//
+// function setUp() public {
+// vm.startPrank(OWNER);
+//
+// mainnetFork = vm.createFork(MAINNET_RPC_URL);
+// vm.selectFork(mainnetFork);
+//
+// s_l1BridgeAdapter = new ArbitrumL1BridgeAdapter(
+// IL1GatewayRouter(L1_GATEWAY_ROUTER),
+// IOutbox(L1_OUTBOX),
+// L1_ERC20_GATEWAY
+// );
+//
+// deal(address(L1_LINK), OWNER, TOKEN_BALANCE);
+// deal(address(L1_WRAPPED_NATIVE), OWNER, TOKEN_BALANCE);
+//
+// vm.label(OWNER, "Owner");
+// vm.label(L1_GATEWAY_ROUTER, "L1GatewayRouter");
+// vm.label(L1_ERC20_GATEWAY, "L1 ERC20 Gateway");
+// }
+//}
+//
+//contract ArbitrumL1BridgeAdapter_sendERC20 is ArbitrumL1BridgeAdapterSetup {
+// event TransferRouted(address indexed token, address indexed _userFrom, address indexed _userTo, address gateway);
+//
+// function test_sendERC20Success() public {
+// L1_LINK.approve(address(s_l1BridgeAdapter), TOKEN_BALANCE);
+//
+// vm.expectEmit();
+// emit TransferRouted(address(L1_LINK), address(s_l1BridgeAdapter), OWNER, L1_ERC20_GATEWAY);
+//
+// uint256 expectedCost = s_l1BridgeAdapter.MAX_GAS() *
+// s_l1BridgeAdapter.GAS_PRICE_BID() +
+// s_l1BridgeAdapter.MAX_SUBMISSION_COST();
+//
+// s_l1BridgeAdapter.sendERC20{value: expectedCost}(address(L1_LINK), OWNER, OWNER, TOKEN_BALANCE);
+// }
+//
+// function test_BridgeFeeTooLowReverts() public {
+// L1_LINK.approve(address(s_l1BridgeAdapter), TOKEN_BALANCE);
+// uint256 expectedCost = s_l1BridgeAdapter.MAX_GAS() *
+// s_l1BridgeAdapter.GAS_PRICE_BID() +
+// s_l1BridgeAdapter.MAX_SUBMISSION_COST();
+//
+// vm.expectRevert(
+// abi.encodeWithSelector(ArbitrumL1BridgeAdapter.InsufficientEthValue.selector, expectedCost, expectedCost - 1)
+// );
+//
+// s_l1BridgeAdapter.sendERC20{value: expectedCost - 1}(address(L1_LINK), OWNER, OWNER, TOKEN_BALANCE);
+// }
+//
+// function test_noApprovalReverts() public {
+// uint256 expectedCost = s_l1BridgeAdapter.MAX_GAS() *
+// s_l1BridgeAdapter.GAS_PRICE_BID() +
+// s_l1BridgeAdapter.MAX_SUBMISSION_COST();
+//
+// vm.expectRevert("SafeERC20: low-level call failed");
+//
+// s_l1BridgeAdapter.sendERC20{value: expectedCost}(address(L1_LINK), OWNER, OWNER, TOKEN_BALANCE);
+// }
+//}
diff --git a/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/ArbitrumL2BridgeAdapter.t.sol b/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/ArbitrumL2BridgeAdapter.t.sol
new file mode 100644
index 00000000000..e34ff0480c0
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/ArbitrumL2BridgeAdapter.t.sol
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {IWrappedNative} from "../../../ccip/interfaces/IWrappedNative.sol";
+
+import {ArbitrumL2BridgeAdapter, IL2GatewayRouter} from "../../bridge-adapters/ArbitrumL2BridgeAdapter.sol";
+import "forge-std/Test.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+//contract ArbitrumL2BridgeAdapterSetup is Test {
+// uint256 internal arbitrumFork;
+//
+// string internal constant ARBITRUM_RPC_URL = "";
+//
+// address internal constant L2_GATEWAY_ROUTER = 0x5288c571Fd7aD117beA99bF60FE0846C4E84F933;
+// address internal constant L2_ETH_WITHDRAWAL_PRECOMPILE = 0x0000000000000000000000000000000000000064;
+//
+// IERC20 internal constant L1_LINK = IERC20(0x514910771AF9Ca656af840dff83E8264EcF986CA);
+// IERC20 internal constant L2_LINK = IERC20(0xf97f4df75117a78c1A5a0DBb814Af92458539FB4);
+// IWrappedNative internal constant L2_WRAPPED_NATIVE = IWrappedNative(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
+//
+// uint256 internal constant TOKEN_BALANCE = 10e18;
+// address internal constant OWNER = address(0xdead);
+//
+// ArbitrumL2BridgeAdapter internal s_l2BridgeAdapter;
+//
+// function setUp() public {
+// vm.startPrank(OWNER);
+//
+// arbitrumFork = vm.createFork(ARBITRUM_RPC_URL);
+//
+// vm.selectFork(arbitrumFork);
+// s_l2BridgeAdapter = new ArbitrumL2BridgeAdapter(IL2GatewayRouter(L2_GATEWAY_ROUTER));
+// deal(address(L2_LINK), OWNER, TOKEN_BALANCE);
+// deal(address(L2_WRAPPED_NATIVE), OWNER, TOKEN_BALANCE);
+//
+// vm.label(OWNER, "Owner");
+// vm.label(L2_GATEWAY_ROUTER, "L2GatewayRouterProxy");
+// vm.label(0xe80eb0238029333e368e0bDDB7acDf1b9cb28278, "L2GatewayRouter");
+// vm.label(L2_ETH_WITHDRAWAL_PRECOMPILE, "Precompile: ArbSys");
+// }
+//}
+//
+//contract ArbitrumL2BridgeAdapter_sendERC20 is ArbitrumL2BridgeAdapterSetup {
+// function test_sendERC20Success() public {
+// L2_LINK.approve(address(s_l2BridgeAdapter), TOKEN_BALANCE);
+//
+// s_l2BridgeAdapter.sendERC20(address(L1_LINK), address(L2_LINK), OWNER, TOKEN_BALANCE);
+// }
+//}
diff --git a/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/OptimismL1BridgeAdapter.t.sol b/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/OptimismL1BridgeAdapter.t.sol
new file mode 100644
index 00000000000..cface1d5067
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/bridge-adapters/OptimismL1BridgeAdapter.t.sol
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import "forge-std/Test.sol";
+
+import {IWrappedNative} from "../../../ccip/interfaces/IWrappedNative.sol";
+import {WETH9} from "../../../ccip/test/WETH9.sol";
+import {OptimismL1BridgeAdapter} from "../../bridge-adapters/OptimismL1BridgeAdapter.sol";
+import {Types} from "../../interfaces/optimism/Types.sol";
+import {IOptimismPortal} from "../../interfaces/optimism/IOptimismPortal.sol";
+
+import {IL1StandardBridge} from "@eth-optimism/contracts/L1/messaging/IL1StandardBridge.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract OptimismL1BridgeAdapterSetup is Test {
+ // addresses below are fake
+ address internal constant L1_STANDARD_BRIDGE = address(1234);
+ address internal constant OP_PORTAL = address(4567);
+ address internal constant OWNER = address(0xdead);
+
+ OptimismL1BridgeAdapter internal s_adapter;
+
+ function setUp() public {
+ vm.startPrank(OWNER);
+
+ // deploy wrapped native
+ WETH9 weth = new WETH9();
+
+ // deploy bridge adapter
+ s_adapter = new OptimismL1BridgeAdapter(
+ IL1StandardBridge(L1_STANDARD_BRIDGE),
+ IWrappedNative(address(weth)),
+ IOptimismPortal(OP_PORTAL)
+ );
+ }
+}
+
+contract OptimismL1BridgeAdapter_finalizeWithdrawERC20 is OptimismL1BridgeAdapterSetup {
+ function testfinalizeWithdrawERC20proveWithdrawalSuccess() public {
+ // prepare payload
+ OptimismL1BridgeAdapter.OptimismProveWithdrawalPayload memory provePayload = OptimismL1BridgeAdapter
+ .OptimismProveWithdrawalPayload({
+ withdrawalTransaction: Types.WithdrawalTransaction({
+ nonce: 1,
+ sender: address(0xdead),
+ target: address(0xbeef),
+ value: 1234,
+ gasLimit: 4567,
+ data: hex"deadbeef"
+ }),
+ l2OutputIndex: 1234,
+ outputRootProof: Types.OutputRootProof({
+ version: bytes32(0),
+ stateRoot: bytes32(uint256(500)),
+ messagePasserStorageRoot: bytes32(uint256(600)),
+ latestBlockhash: bytes32(uint256(700))
+ }),
+ withdrawalProof: new bytes[](0)
+ });
+ OptimismL1BridgeAdapter.FinalizeWithdrawERC20Payload memory payload;
+ payload.action = OptimismL1BridgeAdapter.FinalizationAction.ProveWithdrawal;
+ payload.data = abi.encode(provePayload);
+
+ bytes memory encodedPayload = abi.encode(payload);
+
+ // mock out call to optimism portal
+ vm.mockCall(
+ OP_PORTAL,
+ abi.encodeWithSelector(
+ IOptimismPortal.proveWithdrawalTransaction.selector,
+ provePayload.withdrawalTransaction,
+ provePayload.l2OutputIndex,
+ provePayload.outputRootProof,
+ provePayload.withdrawalProof
+ ),
+ ""
+ );
+
+ // call finalizeWithdrawERC20
+ s_adapter.finalizeWithdrawERC20(address(0), address(0), encodedPayload);
+ }
+
+ function testfinalizeWithdrawERC20FinalizeSuccess() public {
+ // prepare payload
+ OptimismL1BridgeAdapter.OptimismFinalizationPayload memory finalizePayload = OptimismL1BridgeAdapter
+ .OptimismFinalizationPayload({
+ withdrawalTransaction: Types.WithdrawalTransaction({
+ nonce: 1,
+ sender: address(0xdead),
+ target: address(0xbeef),
+ value: 1234,
+ gasLimit: 4567,
+ data: hex"deadbeef"
+ })
+ });
+ OptimismL1BridgeAdapter.FinalizeWithdrawERC20Payload memory payload;
+ payload.action = OptimismL1BridgeAdapter.FinalizationAction.FinalizeWithdrawal;
+ payload.data = abi.encode(finalizePayload);
+
+ bytes memory encodedPayload = abi.encode(payload);
+
+ // mock out call to optimism portal
+ vm.mockCall(
+ OP_PORTAL,
+ abi.encodeWithSelector(
+ IOptimismPortal.finalizeWithdrawalTransaction.selector,
+ finalizePayload.withdrawalTransaction
+ ),
+ ""
+ );
+
+ // call finalizeWithdrawERC20
+ s_adapter.finalizeWithdrawERC20(address(0), address(0), encodedPayload);
+ }
+
+ function testFinalizeWithdrawERC20Reverts() public {
+ // case 1: badly encoded payload
+ bytes memory payload = abi.encode(1, 2, 3);
+ vm.expectRevert();
+ s_adapter.finalizeWithdrawERC20(address(0), address(0), payload);
+
+ // case 2: invalid action
+ // can't prepare the payload in solidity
+ payload = hex"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000004deadbeef00000000000000000000000000000000000000000000000000000000";
+ vm.expectRevert();
+ s_adapter.finalizeWithdrawERC20(address(0), address(0), payload);
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/helpers/LiquidityManagerHelper.sol b/contracts/src/v0.8/liquiditymanager/test/helpers/LiquidityManagerHelper.sol
new file mode 100644
index 00000000000..9b4654a07ff
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/helpers/LiquidityManagerHelper.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {ILiquidityContainer} from "../../interfaces/ILiquidityContainer.sol";
+
+import {LiquidityManager} from "../../LiquidityManager.sol";
+
+import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
+
+contract LiquidityManagerHelper is LiquidityManager {
+ constructor(
+ IERC20 token,
+ uint64 localChainSelector,
+ ILiquidityContainer localLiquidityContainer,
+ uint256 targetTokens,
+ address finance
+ ) LiquidityManager(token, localChainSelector, localLiquidityContainer, targetTokens, finance) {}
+
+ function report(bytes calldata rep, uint64 ocrSeqNum) external {
+ _report(rep, ocrSeqNum);
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/helpers/OCR3Helper.sol b/contracts/src/v0.8/liquiditymanager/test/helpers/OCR3Helper.sol
new file mode 100644
index 00000000000..b2cd2ef3712
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/helpers/OCR3Helper.sol
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {OCR3Base} from "../../ocr/OCR3Base.sol";
+
+contract OCR3Helper is OCR3Base {
+ function configDigestFromConfigData(
+ uint256 chainSelector,
+ address contractAddress,
+ uint64 configCount,
+ address[] memory signers,
+ address[] memory transmitters,
+ uint8 f,
+ bytes memory onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes memory offchainConfig
+ ) public pure returns (bytes32) {
+ return
+ _configDigestFromConfigData(
+ chainSelector,
+ contractAddress,
+ configCount,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig
+ );
+ }
+
+ function _report(bytes calldata report, uint64 sequenceNumber) internal override {}
+
+ function typeAndVersion() public pure override returns (string memory) {
+ return "OCR3BaseHelper 1.0.0";
+ }
+
+ function setLatestSeqNum(uint64 newSeqNum) external {
+ s_latestSequenceNumber = newSeqNum;
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/helpers/ReportEncoder.sol b/contracts/src/v0.8/liquiditymanager/test/helpers/ReportEncoder.sol
new file mode 100644
index 00000000000..ff5e21f2e14
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/helpers/ReportEncoder.sol
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {ILiquidityManager} from "../../interfaces/ILiquidityManager.sol";
+
+/// @dev this is needed to generate the types to help encode the report offchain
+abstract contract ReportEncoder is ILiquidityManager {
+ /// @dev exposed so that we can encode the report for OCR offchain
+ function exposeForEncoding(ILiquidityManager.LiquidityInstructions memory instructions) public pure {}
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/mocks/MockBridgeAdapter.sol b/contracts/src/v0.8/liquiditymanager/test/mocks/MockBridgeAdapter.sol
new file mode 100644
index 00000000000..f51c60fcf3d
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/mocks/MockBridgeAdapter.sol
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: BUSL-1.1
+// solhint-disable one-contract-per-file
+pragma solidity ^0.8.0;
+
+import {IBridgeAdapter} from "../../interfaces/IBridge.sol";
+import {ILiquidityContainer} from "../../interfaces/ILiquidityContainer.sol";
+import {IWrappedNative} from "../../../ccip/interfaces/IWrappedNative.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 Mock multiple-stage finalization bridge adapter implementation.
+/// @dev Funds are only made available after both the prove and finalization steps are completed.
+/// Sends the L1 tokens from the msg sender to address(this).
+contract MockL1BridgeAdapter is IBridgeAdapter, ILiquidityContainer {
+ using SafeERC20 for IERC20;
+
+ error InsufficientLiquidity();
+ error NonceAlreadyUsed(uint256 nonce);
+ error InvalidFinalizationAction();
+ error NonceNotProven(uint256 nonce);
+ error NativeSendFailed();
+
+ /// @notice Payload to "prove" the withdrawal.
+ /// @dev This is just a mock setup, there's no real proving. This is so that
+ /// we can test the multi-step finalization code path.
+ /// @param nonce the nonce emitted on the remote chain.
+ struct ProvePayload {
+ uint256 nonce;
+ }
+
+ /// @notice Payload to "finalize" the withdrawal.
+ /// @dev This is just a mock setup, there's no real finalization. This is so that
+ /// we can test the multi-step finalization code path.
+ /// @param nonce the nonce emitted on the remote chain.
+ struct FinalizePayload {
+ uint256 nonce;
+ uint256 amount;
+ }
+
+ /// @notice The finalization action to take.
+ /// @dev This emulates Optimism's two-step withdrawal process.
+ enum FinalizationAction {
+ ProveWithdrawal,
+ FinalizeWithdrawal
+ }
+
+ /// @notice The payload to use for the bridgeSpecificPayload in the finalizeWithdrawERC20 function.
+ struct Payload {
+ FinalizationAction action;
+ bytes data;
+ }
+
+ IERC20 internal immutable i_token;
+ uint256 internal s_nonce = 1;
+ mapping(uint256 => bool) internal s_nonceProven;
+ mapping(uint256 => bool) internal s_nonceFinalized;
+
+ /// @dev For test cases where we want to send pure native upon finalizeWithdrawERC20 being called.
+ /// This is to emulate the behavior of bridges that do not bridge wrapped native.
+ bool internal immutable i_holdNative;
+
+ constructor(IERC20 token, bool holdNative) {
+ i_token = token;
+ i_holdNative = holdNative;
+ }
+
+ /// @dev The receive function is needed for IWrappedNative.withdraw() to work.
+ receive() external payable {}
+
+ /// @notice Simply transferFrom msg.sender the tokens that are to be bridged to address(this).
+ function sendERC20(
+ address localToken,
+ address /* remoteToken */,
+ address /* remoteReceiver */,
+ uint256 amount,
+ bytes calldata /* bridgeSpecificPayload */
+ ) external payable override returns (bytes memory) {
+ IERC20(localToken).transferFrom(msg.sender, address(this), amount);
+
+ // If the flag to hold native is set we assume that i_token points to a WETH contract
+ // and withdraw native.
+ // This way we can transfer the raw native back to the sender upon finalization.
+ if (i_holdNative) {
+ IWrappedNative(address(i_token)).withdraw(amount);
+ }
+
+ bytes memory encodedNonce = abi.encode(s_nonce++);
+ return encodedNonce;
+ }
+
+ function getBridgeFeeInNative() external pure returns (uint256) {
+ return 0;
+ }
+
+ function provideLiquidity(uint256 amount) external {
+ i_token.safeTransferFrom(msg.sender, address(this), amount);
+ emit LiquidityAdded(msg.sender, amount);
+ }
+
+ function withdrawLiquidity(uint256 amount) external {
+ if (i_token.balanceOf(address(this)) < amount) revert InsufficientLiquidity();
+ i_token.safeTransfer(msg.sender, amount);
+ emit LiquidityRemoved(msg.sender, amount);
+ }
+
+ /// @dev for easy encoding offchain
+ function encodeProvePayload(ProvePayload memory payload) external pure {}
+
+ function encodeFinalizePayload(FinalizePayload memory payload) external pure {}
+
+ function encodePayload(Payload memory payload) external pure {}
+
+ /// @dev Test setup is trusted, so just transfer the tokens to the localReceiver,
+ /// which should be the local rebalancer. Infer the amount from the bridgeSpecificPayload.
+ /// Note that this means that this bridge adapter will need to have some tokens,
+ /// however this is ok in a test environment since we will have infinite tokens.
+ /// @param localReceiver the address to transfer the tokens to.
+ /// @param bridgeSpecificPayload the payload to use for the finalization or proving.
+ /// @return true if the transfer was successful, revert otherwise.
+ function finalizeWithdrawERC20(
+ address /* remoteSender */,
+ address localReceiver,
+ bytes calldata bridgeSpecificPayload
+ ) external override returns (bool) {
+ Payload memory payload = abi.decode(bridgeSpecificPayload, (Payload));
+ if (payload.action == FinalizationAction.ProveWithdrawal) {
+ return _proveWithdrawal(payload);
+ } else if (payload.action == FinalizationAction.FinalizeWithdrawal) {
+ return _finalizeWithdrawal(payload, localReceiver);
+ }
+ revert InvalidFinalizationAction();
+ }
+
+ function _proveWithdrawal(Payload memory payload) internal returns (bool) {
+ ProvePayload memory provePayload = abi.decode(payload.data, (ProvePayload));
+ if (s_nonceProven[provePayload.nonce]) revert NonceAlreadyUsed(provePayload.nonce);
+ s_nonceProven[provePayload.nonce] = true;
+ return false;
+ }
+
+ function _finalizeWithdrawal(Payload memory payload, address localReceiver) internal returns (bool) {
+ FinalizePayload memory finalizePayload = abi.decode(payload.data, (FinalizePayload));
+ if (!s_nonceProven[finalizePayload.nonce]) revert NonceNotProven(finalizePayload.nonce);
+ if (s_nonceFinalized[finalizePayload.nonce]) revert NonceAlreadyUsed(finalizePayload.nonce);
+ s_nonceFinalized[finalizePayload.nonce] = true;
+ // re-entrancy prevented by nonce checks above.
+ _transferTokens(finalizePayload.amount, localReceiver);
+ return true;
+ }
+
+ function _transferTokens(uint256 amount, address localReceiver) internal {
+ if (i_holdNative) {
+ (bool success, ) = payable(localReceiver).call{value: amount}("");
+ if (!success) {
+ revert NativeSendFailed();
+ }
+ } else {
+ i_token.safeTransfer(localReceiver, amount);
+ }
+ }
+}
+
+/// @notice Mock L2 Bridge adapter
+/// @dev Sends the L2 tokens from the msg sender to address(this)
+contract MockL2BridgeAdapter is IBridgeAdapter {
+ /// @notice Simply transferFrom msg.sender the tokens that are to be bridged.
+ function sendERC20(
+ address localToken,
+ address /* remoteToken */,
+ address /* recipient */,
+ uint256 amount,
+ bytes calldata /* bridgeSpecificPayload */
+ ) external payable override returns (bytes memory) {
+ IERC20(localToken).transferFrom(msg.sender, address(this), amount);
+ return "";
+ }
+
+ function getBridgeFeeInNative() external pure returns (uint256) {
+ return 0;
+ }
+
+ // No-op
+ function finalizeWithdrawERC20(
+ address /* remoteSender */,
+ address /* localReceiver */,
+ bytes calldata /* bridgeSpecificData */
+ ) external pure override returns (bool) {
+ return true;
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/mocks/NoOpOCR3.sol b/contracts/src/v0.8/liquiditymanager/test/mocks/NoOpOCR3.sol
new file mode 100644
index 00000000000..5e771f0ccd6
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/mocks/NoOpOCR3.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {OCR3Base} from "../../ocr/OCR3Base.sol";
+
+// NoOpOCR3 is a mock implementation of the OCR3Base contract that does nothing
+// This is so that we can generate gethwrappers for the contract and use the OCR3 ABI in
+// Go code.
+contract NoOpOCR3 is OCR3Base {
+ // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables
+ string public constant override typeAndVersion = "NoOpOCR3 1.0.0";
+
+ constructor() OCR3Base() {}
+
+ function _report(bytes calldata, uint64) internal override {
+ // do nothing
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/ocr/OCR3Base.t.sol b/contracts/src/v0.8/liquiditymanager/test/ocr/OCR3Base.t.sol
new file mode 100644
index 00000000000..840e90fb876
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/ocr/OCR3Base.t.sol
@@ -0,0 +1,337 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.24;
+
+import {OCR3Setup} from "./OCR3Setup.t.sol";
+import {OCR3Base} from "../../ocr/OCR3Base.sol";
+import {OCR3Helper} from "../helpers/OCR3Helper.sol";
+
+contract OCR3BaseSetup is OCR3Setup {
+ event ConfigSet(
+ uint32 previousConfigBlockNumber,
+ bytes32 configDigest,
+ uint64 configCount,
+ address[] signers,
+ address[] transmitters,
+ uint8 f,
+ bytes onchainConfig,
+ uint64 offchainConfigVersion,
+ bytes offchainConfig
+ );
+
+ OCR3Helper internal s_OCR3Base;
+
+ bytes32[] internal s_rs;
+ bytes32[] internal s_ss;
+ bytes32 internal s_rawVs;
+
+ uint40 internal s_latestEpochAndRound;
+
+ function setUp() public virtual override {
+ OCR3Setup.setUp();
+ s_OCR3Base = new OCR3Helper();
+
+ bytes32 testReportDigest = getTestReportDigest();
+
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](2);
+ uint8[] memory vs = new uint8[](2);
+
+ // Calculate signatures
+ (vs[0], rs[0], ss[0]) = vm.sign(PRIVATE0, testReportDigest);
+ (vs[1], rs[1], ss[1]) = vm.sign(PRIVATE1, testReportDigest);
+
+ s_rs = rs;
+ s_ss = ss;
+ s_rawVs = bytes32(bytes1(vs[0] - 27)) | (bytes32(bytes1(vs[1] - 27)) >> 8);
+ }
+
+ function getBasicConfigDigest(uint8 f, uint64 currentConfigCount) internal view returns (bytes32) {
+ bytes memory configBytes = abi.encode("");
+ return
+ s_OCR3Base.configDigestFromConfigData(
+ block.chainid,
+ address(s_OCR3Base),
+ currentConfigCount + 1,
+ s_valid_signers,
+ s_valid_transmitters,
+ f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+ }
+
+ function getTestReportDigest() internal view returns (bytes32) {
+ bytes32 configDigest = getBasicConfigDigest(s_f, 0);
+ bytes32[3] memory reportContext = [configDigest, configDigest, configDigest];
+ return keccak256(abi.encodePacked(keccak256(REPORT), reportContext));
+ }
+
+ function getBasicConfigDigest(
+ address contractAddress,
+ uint8 f,
+ uint64 currentConfigCount,
+ bytes memory onchainConfig
+ ) internal view returns (bytes32) {
+ return
+ s_OCR3Base.configDigestFromConfigData(
+ block.chainid,
+ contractAddress,
+ currentConfigCount + 1,
+ s_valid_signers,
+ s_valid_transmitters,
+ f,
+ onchainConfig,
+ s_offchainConfigVersion,
+ abi.encode("")
+ );
+ }
+}
+
+contract OCR3Base_transmit is OCR3BaseSetup {
+ bytes32 internal s_configDigest;
+
+ function setUp() public virtual override {
+ OCR3BaseSetup.setUp();
+ bytes memory configBytes = abi.encode("");
+
+ s_configDigest = getBasicConfigDigest(s_f, 0);
+ s_OCR3Base.setOCR3Config(
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+ }
+
+ function testTransmit2SignersSuccess_gas() public {
+ vm.pauseGasMetering();
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ vm.startPrank(s_valid_transmitters[0]);
+ vm.resumeGasMetering();
+ s_OCR3Base.transmit(reportContext, REPORT, s_rs, s_ss, s_rawVs);
+ }
+
+ // Reverts
+
+ function testNonIncreasingSequenceNumberReverts() public {
+ bytes32[3] memory reportContext = [s_configDigest, bytes32(uint256(0)) /* sequence number */, s_configDigest];
+
+ vm.expectRevert(abi.encodeWithSelector(OCR3Base.NonIncreasingSequenceNumber.selector, 0, 0));
+ s_OCR3Base.transmit(reportContext, REPORT, s_rs, s_ss, s_rawVs);
+ }
+
+ function testForkedChainReverts() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ uint256 chain1 = block.chainid;
+ uint256 chain2 = chain1 + 1;
+ vm.chainId(chain2);
+ vm.expectRevert(abi.encodeWithSelector(OCR3Base.ForkedChain.selector, chain1, chain2));
+ vm.startPrank(s_valid_transmitters[0]);
+ s_OCR3Base.transmit(reportContext, REPORT, s_rs, s_ss, s_rawVs);
+ }
+
+ function testWrongNumberOfSignaturesReverts() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ vm.expectRevert(OCR3Base.WrongNumberOfSignatures.selector);
+ s_OCR3Base.transmit(reportContext, REPORT, new bytes32[](0), new bytes32[](0), s_rawVs);
+ }
+
+ function testConfigDigestMismatchReverts() public {
+ bytes32 configDigest;
+ bytes32[3] memory reportContext = [configDigest, bytes32(uint256(1)) /* sequence number */, configDigest];
+
+ vm.expectRevert(abi.encodeWithSelector(OCR3Base.ConfigDigestMismatch.selector, s_configDigest, configDigest));
+ s_OCR3Base.transmit(reportContext, REPORT, new bytes32[](0), new bytes32[](0), s_rawVs);
+ }
+
+ function testSignatureOutOfRegistrationReverts() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](1);
+
+ vm.expectRevert(OCR3Base.SignaturesOutOfRegistration.selector);
+ s_OCR3Base.transmit(reportContext, REPORT, rs, ss, s_rawVs);
+ }
+
+ function testUnAuthorizedTransmitterReverts() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+ bytes32[] memory rs = new bytes32[](2);
+ bytes32[] memory ss = new bytes32[](2);
+
+ vm.expectRevert(OCR3Base.UnauthorizedTransmitter.selector);
+ s_OCR3Base.transmit(reportContext, REPORT, rs, ss, s_rawVs);
+ }
+
+ function testNonUniqueSignatureReverts() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+ bytes32[] memory rs = s_rs;
+ bytes32[] memory ss = s_ss;
+
+ rs[1] = rs[0];
+ ss[1] = ss[0];
+ // Need to reset the rawVs to be valid
+ bytes32 rawVs = bytes32(bytes1(uint8(28) - 27)) | (bytes32(bytes1(uint8(28) - 27)) >> 8);
+
+ vm.startPrank(s_valid_transmitters[0]);
+ vm.expectRevert(OCR3Base.NonUniqueSignatures.selector);
+ s_OCR3Base.transmit(reportContext, REPORT, rs, ss, rawVs);
+ }
+
+ function testUnauthorizedSignerReverts() public {
+ bytes32[3] memory reportContext = [s_configDigest, s_configDigest, s_configDigest];
+ bytes32[] memory rs = new bytes32[](2);
+ rs[0] = s_configDigest;
+ bytes32[] memory ss = rs;
+
+ vm.startPrank(s_valid_transmitters[0]);
+ vm.expectRevert(OCR3Base.UnauthorizedSigner.selector);
+ s_OCR3Base.transmit(reportContext, REPORT, rs, ss, s_rawVs);
+ }
+}
+
+contract OCR3Base_setOCR3Config is OCR3BaseSetup {
+ function testSetConfigSuccess() public {
+ vm.pauseGasMetering();
+ bytes memory configBytes = abi.encode("");
+ uint32 configCount = 0;
+
+ bytes32 configDigest = getBasicConfigDigest(s_f, configCount++);
+
+ address[] memory transmitters = s_OCR3Base.getTransmitters();
+ assertEq(0, transmitters.length);
+
+ s_OCR3Base.setLatestSeqNum(3);
+ uint64 seqNum = s_OCR3Base.latestSequenceNumber();
+ assertEq(seqNum, 3);
+
+ vm.expectEmit();
+ emit ConfigSet(
+ 0,
+ configDigest,
+ configCount,
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+
+ s_OCR3Base.setOCR3Config(
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+
+ transmitters = s_OCR3Base.getTransmitters();
+ assertEq(s_valid_transmitters, transmitters);
+
+ configDigest = getBasicConfigDigest(s_f, configCount++);
+
+ seqNum = s_OCR3Base.latestSequenceNumber();
+ assertEq(seqNum, 0);
+
+ vm.expectEmit();
+ emit ConfigSet(
+ uint32(block.number),
+ configDigest,
+ configCount,
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+ vm.resumeGasMetering();
+ s_OCR3Base.setOCR3Config(
+ s_valid_signers,
+ s_valid_transmitters,
+ s_f,
+ configBytes,
+ s_offchainConfigVersion,
+ configBytes
+ );
+ }
+
+ // Reverts
+ function testRepeatAddressReverts() public {
+ address[] memory signers = new address[](10);
+ signers[0] = address(1245678);
+ address[] memory transmitters = new address[](10);
+ transmitters[0] = signers[0];
+
+ vm.expectRevert(abi.encodeWithSelector(OCR3Base.InvalidConfig.selector, "repeated transmitter address"));
+ s_OCR3Base.setOCR3Config(signers, transmitters, 2, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function testSignerCannotBeZeroAddressReverts() public {
+ uint256 f = 1;
+ address[] memory signers = new address[](3 * f + 1);
+ address[] memory transmitters = new address[](3 * f + 1);
+ for (uint160 i = 0; i < 3 * f + 1; ++i) {
+ signers[i] = address(i + 1);
+ transmitters[i] = address(i + 1000);
+ }
+
+ signers[0] = address(0);
+
+ vm.expectRevert(OCR3Base.OracleCannotBeZeroAddress.selector);
+ s_OCR3Base.setOCR3Config(signers, transmitters, uint8(f), abi.encode(""), 100, abi.encode(""));
+ }
+
+ function testTransmitterCannotBeZeroAddressReverts() public {
+ uint256 f = 1;
+ address[] memory signers = new address[](3 * f + 1);
+ address[] memory transmitters = new address[](3 * f + 1);
+ for (uint160 i = 0; i < 3 * f + 1; ++i) {
+ signers[i] = address(i + 1);
+ transmitters[i] = address(i + 1000);
+ }
+
+ transmitters[0] = address(0);
+
+ vm.expectRevert(OCR3Base.OracleCannotBeZeroAddress.selector);
+ s_OCR3Base.setOCR3Config(signers, transmitters, uint8(f), abi.encode(""), 100, abi.encode(""));
+ }
+
+ function testOracleOutOfRegisterReverts() public {
+ address[] memory signers = new address[](10);
+ address[] memory transmitters = new address[](0);
+
+ vm.expectRevert(abi.encodeWithSelector(OCR3Base.InvalidConfig.selector, "oracle addresses out of registration"));
+ s_OCR3Base.setOCR3Config(signers, transmitters, 2, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function testFTooHighReverts() public {
+ address[] memory signers = new address[](0);
+ uint8 f = 1;
+
+ vm.expectRevert(abi.encodeWithSelector(OCR3Base.InvalidConfig.selector, "faulty-oracle f too high"));
+ s_OCR3Base.setOCR3Config(signers, new address[](0), f, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function testFMustBePositiveReverts() public {
+ uint8 f = 0;
+
+ vm.expectRevert(abi.encodeWithSelector(OCR3Base.InvalidConfig.selector, "f must be positive"));
+ s_OCR3Base.setOCR3Config(new address[](0), new address[](0), f, abi.encode(""), 100, abi.encode(""));
+ }
+
+ function testTooManySignersReverts() public {
+ address[] memory signers = new address[](32);
+
+ vm.expectRevert(abi.encodeWithSelector(OCR3Base.InvalidConfig.selector, "too many signers"));
+ s_OCR3Base.setOCR3Config(signers, new address[](0), 0, abi.encode(""), 100, abi.encode(""));
+ }
+}
diff --git a/contracts/src/v0.8/liquiditymanager/test/ocr/OCR3Setup.t.sol b/contracts/src/v0.8/liquiditymanager/test/ocr/OCR3Setup.t.sol
new file mode 100644
index 00000000000..ee60c58dcc6
--- /dev/null
+++ b/contracts/src/v0.8/liquiditymanager/test/ocr/OCR3Setup.t.sol
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity ^0.8.0;
+
+import {LiquidityManagerBaseTest} from "../LiquidityManagerBaseTest.t.sol";
+
+contract OCR3Setup is LiquidityManagerBaseTest {
+ // 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;
+
+ address[] internal s_valid_signers;
+ address[] internal s_valid_transmitters;
+
+ uint64 internal constant s_offchainConfigVersion = 3;
+ uint8 internal constant s_f = 1;
+ bytes internal constant REPORT = abi.encode("testReport");
+
+ function setUp() public virtual override {
+ LiquidityManagerBaseTest.setUp();
+
+ s_valid_transmitters = new address[](4);
+ for (uint160 i = 0; i < 4; ++i) {
+ s_valid_transmitters[i] = address(4 + i);
+ }
+
+ 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
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/libraries/Common.sol b/contracts/src/v0.8/llo-feeds/libraries/Common.sol
index f732ced004b..23418bf41a9 100644
--- a/contracts/src/v0.8/llo-feeds/libraries/Common.sol
+++ b/contracts/src/v0.8/llo-feeds/libraries/Common.sol
@@ -19,6 +19,28 @@ library Common {
uint64 weight;
}
+ /**
+ * @notice Checks if an array of AddressAndWeight has duplicate addresses
+ * @param recipients The array of AddressAndWeight to check
+ * @return bool True if there are duplicates, false otherwise
+ */
+ function _hasDuplicateAddresses(address[] memory recipients) internal pure returns (bool) {
+ for (uint256 i = 0; i < recipients.length; ) {
+ for (uint256 j = i + 1; j < recipients.length; ) {
+ if (recipients[i] == recipients[j]) {
+ return true;
+ }
+ unchecked {
+ ++j;
+ }
+ }
+ unchecked {
+ ++i;
+ }
+ }
+ return false;
+ }
+
/**
* @notice Checks if an array of AddressAndWeight has duplicate addresses
* @param recipients The array of AddressAndWeight to check
@@ -40,4 +62,28 @@ library Common {
}
return false;
}
+
+ /**
+ * @notice sorts a list of addresses numerically
+ * @param arr The array of addresses to sort
+ * @param left the start index
+ * @param right the end index
+ */
+ function _quickSort(address[] memory arr, int256 left, int256 right) internal pure {
+ int256 i = left;
+ int256 j = right;
+ if (i == j) return;
+ address pivot = arr[uint256(left + (right - left) / 2)];
+ while (i <= j) {
+ while (uint160(arr[uint256(i)]) < uint160(pivot)) i++;
+ while (uint160(pivot) < uint160(arr[uint256(j)])) j--;
+ if (i <= j) {
+ (arr[uint256(i)], arr[uint256(j)]) = (arr[uint256(j)], arr[uint256(i)]);
+ i++;
+ j--;
+ }
+ }
+ if (left < j) _quickSort(arr, left, j);
+ if (i < right) _quickSort(arr, i, right);
+ }
}
diff --git a/contracts/src/v0.8/llo-feeds/test/ByteUtilTest.t.sol b/contracts/src/v0.8/llo-feeds/libraries/test/ByteUtilTest.t.sol
similarity index 99%
rename from contracts/src/v0.8/llo-feeds/test/ByteUtilTest.t.sol
rename to contracts/src/v0.8/llo-feeds/libraries/test/ByteUtilTest.t.sol
index 21bd957e4e1..8b5343866f6 100644
--- a/contracts/src/v0.8/llo-feeds/test/ByteUtilTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/libraries/test/ByteUtilTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {Test} from "forge-std/Test.sol";
-import {ByteUtil} from "../libraries/ByteUtil.sol";
+import {ByteUtil} from "../ByteUtil.sol";
contract ByteUtilTest is Test {
using ByteUtil for bytes;
diff --git a/contracts/src/v0.8/llo-feeds/FeeManager.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/FeeManager.sol
similarity index 96%
rename from contracts/src/v0.8/llo-feeds/FeeManager.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/FeeManager.sol
index 665940d4670..44f550e3253 100644
--- a/contracts/src/v0.8/llo-feeds/FeeManager.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/FeeManager.sol
@@ -1,16 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol";
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
import {IFeeManager} from "./interfaces/IFeeManager.sol";
-import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
-import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
-import {Common} from "./libraries/Common.sol";
+import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../libraries/Common.sol";
import {IRewardManager} from "./interfaces/IRewardManager.sol";
-import {IWERC20} from "../shared/interfaces/IWERC20.sol";
-import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
-import {Math} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/Math.sol";
-import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+import {IWERC20} from "../../shared/interfaces/IWERC20.sol";
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
+import {Math} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/Math.sol";
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol";
/**
diff --git a/contracts/src/v0.8/llo-feeds/RewardManager.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/RewardManager.sol
similarity index 96%
rename from contracts/src/v0.8/llo-feeds/RewardManager.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/RewardManager.sol
index 1929289a360..49fef51c569 100644
--- a/contracts/src/v0.8/llo-feeds/RewardManager.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/RewardManager.sol
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol";
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
import {IRewardManager} from "./interfaces/IRewardManager.sol";
-import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
-import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
-import {Common} from "./libraries/Common.sol";
-import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
+import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
+import {Common} from "../libraries/Common.sol";
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
/**
* @title RewardManager
diff --git a/contracts/src/v0.8/llo-feeds/Verifier.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/Verifier.sol
similarity index 98%
rename from contracts/src/v0.8/llo-feeds/Verifier.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/Verifier.sol
index c8858999dab..fe5742108a5 100644
--- a/contracts/src/v0.8/llo-feeds/Verifier.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/Verifier.sol
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol";
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
import {IVerifier} from "./interfaces/IVerifier.sol";
import {IVerifierProxy} from "./interfaces/IVerifierProxy.sol";
-import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
-import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
-import {Common} from "./libraries/Common.sol";
+import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../libraries/Common.sol";
// OCR2 standard
uint256 constant MAX_NUM_ORACLES = 31;
diff --git a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/VerifierProxy.sol
similarity index 95%
rename from contracts/src/v0.8/llo-feeds/VerifierProxy.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/VerifierProxy.sol
index c32a27178cc..c06312dd7be 100644
--- a/contracts/src/v0.8/llo-feeds/VerifierProxy.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/VerifierProxy.sol
@@ -1,14 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {ConfirmedOwner} from "../shared/access/ConfirmedOwner.sol";
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
import {IVerifierProxy} from "./interfaces/IVerifierProxy.sol";
import {IVerifier} from "./interfaces/IVerifier.sol";
-import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
-import {AccessControllerInterface} from "../shared/interfaces/AccessControllerInterface.sol";
-import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
+import {AccessControllerInterface} from "../../shared/interfaces/AccessControllerInterface.sol";
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol";
-import {Common} from "./libraries/Common.sol";
+import {Common} from "../libraries/Common.sol";
/**
* The verifier proxy contract is the gateway for all report verification requests
diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IFeeManager.sol
similarity index 94%
rename from contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IFeeManager.sol
index 4095607b911..818a3a09a4c 100644
--- a/contracts/src/v0.8/llo-feeds/interfaces/IFeeManager.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IFeeManager.sol
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
-import {Common} from "../libraries/Common.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../../libraries/Common.sol";
import {IVerifierFeeManager} from "./IVerifierFeeManager.sol";
interface IFeeManager is IERC165, IVerifierFeeManager {
diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IRewardManager.sol
similarity index 94%
rename from contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IRewardManager.sol
index 5a6e03f1c9a..f08ce34db29 100644
--- a/contracts/src/v0.8/llo-feeds/interfaces/IRewardManager.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IRewardManager.sol
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
-import {Common} from "../libraries/Common.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../../libraries/Common.sol";
interface IRewardManager is IERC165 {
/**
diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifier.sol
similarity index 97%
rename from contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifier.sol
index 617d702d3f8..94b260399ea 100644
--- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifier.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifier.sol
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
-import {Common} from "../libraries/Common.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../../libraries/Common.sol";
interface IVerifier is IERC165 {
/**
diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol
similarity index 88%
rename from contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol
index 522db952e5d..da3fdfac153 100644
--- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierFeeManager.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierFeeManager.sol
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
-import {Common} from "../libraries/Common.sol";
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../../libraries/Common.sol";
interface IVerifierFeeManager is IERC165 {
/**
diff --git a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierProxy.sol
similarity index 95%
rename from contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierProxy.sol
index 2eb1b4aff4b..6609e4869ae 100644
--- a/contracts/src/v0.8/llo-feeds/interfaces/IVerifierProxy.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/interfaces/IVerifierProxy.sol
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import {Common} from "../libraries/Common.sol";
-import {AccessControllerInterface} from "../../shared/interfaces/AccessControllerInterface.sol";
+import {Common} from "../../libraries/Common.sol";
+import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol";
import {IVerifierFeeManager} from "./IVerifierFeeManager.sol";
interface IVerifierProxy {
diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/BaseFeeManager.t.sol
similarity index 98%
rename from contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/BaseFeeManager.t.sol
index edde26b2ee1..0d598cdac52 100644
--- a/contracts/src/v0.8/llo-feeds/test/fee-manager/BaseFeeManager.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/BaseFeeManager.t.sol
@@ -4,9 +4,9 @@ pragma solidity 0.8.19;
import {Test} from "forge-std/Test.sol";
import {FeeManager} from "../../FeeManager.sol";
import {RewardManager} from "../../RewardManager.sol";
-import {Common} from "../../libraries/Common.sol";
-import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
-import {WERC20Mock} from "../../../shared/mocks/WERC20Mock.sol";
+import {Common} from "../../../libraries/Common.sol";
+import {ERC20Mock} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
+import {WERC20Mock} from "../../../../shared/mocks/WERC20Mock.sol";
import {IRewardManager} from "../../interfaces/IRewardManager.sol";
import {FeeManagerProxy} from "../mocks/FeeManagerProxy.sol";
diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.general.t.sol
similarity index 100%
rename from contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.general.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.general.t.sol
diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.getFeeAndReward.t.sol
similarity index 98%
rename from contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.getFeeAndReward.t.sol
index 299a7f09d51..1b0f95d51bd 100644
--- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.getFeeAndReward.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.getFeeAndReward.t.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
-import {Common} from "../../libraries/Common.sol";
+import {Common} from "../../../libraries/Common.sol";
import "./BaseFeeManager.t.sol";
/**
@@ -10,7 +10,7 @@ import "./BaseFeeManager.t.sol";
* @notice This contract will test the functionality of the feeManager's getFeeAndReward
*/
contract FeeManagerProcessFeeTest is BaseFeeManagerTest {
- function test_baseFeeIsAppliedForNative() public {
+ function test_baseFeeIsAppliedForNative() public view {
//get the fee required by the feeManager
Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
@@ -18,7 +18,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest {
assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE);
}
- function test_baseFeeIsAppliedForLink() public {
+ function test_baseFeeIsAppliedForLink() public view {
//get the fee required by the feeManager
Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
@@ -378,7 +378,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest {
assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE - expectedDiscount);
}
- function test_reportWithNoExpiryOrFeeReturnsZero() public {
+ function test_reportWithNoExpiryOrFeeReturnsZero() public view {
//get the fee required by the feeManager
Common.Asset memory fee = getFee(getV1Report(DEFAULT_FEED_1_V1), getNativeQuote(), USER);
@@ -462,7 +462,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest {
setNativeSurcharge(nativeSurcharge, ADMIN);
}
- function test_getBaseRewardWithLinkQuote() public {
+ function test_getBaseRewardWithLinkQuote() public view {
//get the fee required by the feeManager
Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
@@ -481,7 +481,7 @@ contract FeeManagerProcessFeeTest is BaseFeeManagerTest {
assertEq(reward.amount, DEFAULT_REPORT_LINK_FEE / 2);
}
- function test_getRewardWithNativeQuote() public {
+ function test_getRewardWithNativeQuote() public view {
//get the fee required by the feeManager
Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.processFee.t.sol
similarity index 99%
rename from contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.processFee.t.sol
index f8c1d47d4d0..0e0ed8977bc 100644
--- a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFee.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.processFee.t.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
-import {Common} from "../../libraries/Common.sol";
+import {Common} from "../../../libraries/Common.sol";
import "./BaseFeeManager.t.sol";
import {IRewardManager} from "../../interfaces/IRewardManager.sol";
diff --git a/contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFeeBulk.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.processFeeBulk.t.sol
similarity index 100%
rename from contracts/src/v0.8/llo-feeds/test/fee-manager/FeeManager.processFeeBulk.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/fee-manager/FeeManager.processFeeBulk.t.sol
diff --git a/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/gas/Gas_VerifierTest.t.sol
similarity index 98%
rename from contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/gas/Gas_VerifierTest.t.sol
index 29b488fb328..ee8ba4c3e34 100644
--- a/contracts/src/v0.8/llo-feeds/test/gas/Gas_VerifierTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/gas/Gas_VerifierTest.t.sol
@@ -2,8 +2,8 @@
pragma solidity 0.8.19;
import {BaseTest, BaseTestWithConfiguredVerifierAndFeeManager} from "../verifier/BaseVerifierTest.t.sol";
-import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol";
-import {Common} from "../../libraries/Common.sol";
+import {SimpleWriteAccessController} from "../../../../shared/access/SimpleWriteAccessController.sol";
+import {Common} from "../../../libraries/Common.sol";
import {IRewardManager} from "../../interfaces/IRewardManager.sol";
contract Verifier_setConfig is BaseTest {
diff --git a/contracts/src/v0.8/llo-feeds/test/mocks/ErroredVerifier.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/mocks/ErroredVerifier.sol
similarity index 66%
rename from contracts/src/v0.8/llo-feeds/test/mocks/ErroredVerifier.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/mocks/ErroredVerifier.sol
index 01cb1a50611..e9dcd589e23 100644
--- a/contracts/src/v0.8/llo-feeds/test/mocks/ErroredVerifier.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/mocks/ErroredVerifier.sol
@@ -2,13 +2,24 @@
pragma solidity 0.8.19;
import {IVerifier} from "../../interfaces/IVerifier.sol";
-import {Common} from "../../libraries/Common.sol";
+import {Common} from "../../../libraries/Common.sol";
contract ErroredVerifier is IVerifier {
function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return interfaceId == this.verify.selector;
}
+ //define each of the errors thrown in the revert below
+
+ error FailedToVerify();
+ error FailedToSetConfig();
+ error FailedToActivateConfig();
+ error FailedToDeactivateConfig();
+ error FailedToActivateFeed();
+ error FailedToDeactivateFeed();
+ error FailedToGetLatestConfigDigestAndEpoch();
+ error FailedToGetLatestConfigDetails();
+
function verify(
bytes memory,
/**
@@ -26,7 +37,7 @@ contract ErroredVerifier is IVerifier {
bytes memory
)
{
- revert("Failed to verify");
+ revert FailedToVerify();
}
function setConfig(
@@ -39,7 +50,7 @@ contract ErroredVerifier is IVerifier {
bytes memory,
Common.AddressAndWeight[] memory
) external pure override {
- revert("Failed to set config");
+ revert FailedToSetConfig();
}
function setConfigFromSource(
@@ -55,30 +66,30 @@ contract ErroredVerifier is IVerifier {
bytes memory,
Common.AddressAndWeight[] memory
) external pure override {
- revert("Failed to set config");
+ revert FailedToSetConfig();
}
function activateConfig(bytes32, bytes32) external pure {
- revert("Failed to activate config");
+ revert FailedToActivateConfig();
}
function deactivateConfig(bytes32, bytes32) external pure {
- revert("Failed to deactivate config");
+ revert FailedToDeactivateConfig();
}
function activateFeed(bytes32) external pure {
- revert("Failed to activate feed");
+ revert FailedToActivateFeed();
}
function deactivateFeed(bytes32) external pure {
- revert("Failed to deactivate feed");
+ revert FailedToDeactivateFeed();
}
function latestConfigDigestAndEpoch(bytes32) external pure override returns (bool, bytes32, uint32) {
- revert("Failed to get latest config digest and epoch");
+ revert FailedToGetLatestConfigDigestAndEpoch();
}
function latestConfigDetails(bytes32) external pure override returns (uint32, uint32, bytes32) {
- revert("Failed to get latest config details");
+ revert FailedToGetLatestConfigDetails();
}
}
diff --git a/contracts/src/v0.8/llo-feeds/test/mocks/ExposedVerifier.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/mocks/ExposedVerifier.sol
similarity index 100%
rename from contracts/src/v0.8/llo-feeds/test/mocks/ExposedVerifier.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/mocks/ExposedVerifier.sol
diff --git a/contracts/src/v0.8/llo-feeds/test/mocks/FeeManagerProxy.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/mocks/FeeManagerProxy.sol
similarity index 61%
rename from contracts/src/v0.8/llo-feeds/test/mocks/FeeManagerProxy.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/mocks/FeeManagerProxy.sol
index 16935f69d6b..9abb4c50c29 100644
--- a/contracts/src/v0.8/llo-feeds/test/mocks/FeeManagerProxy.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/mocks/FeeManagerProxy.sol
@@ -1,20 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
-import "../../interfaces/IFeeManager.sol";
+import {IFeeManager} from "../../interfaces/IFeeManager.sol";
contract FeeManagerProxy {
- IFeeManager internal i_feeManager;
+ IFeeManager internal s_feeManager;
function processFee(bytes calldata payload, bytes calldata parameterPayload) public payable {
- i_feeManager.processFee{value: msg.value}(payload, parameterPayload, msg.sender);
+ s_feeManager.processFee{value: msg.value}(payload, parameterPayload, msg.sender);
}
function processFeeBulk(bytes[] calldata payloads, bytes calldata parameterPayload) public payable {
- i_feeManager.processFeeBulk{value: msg.value}(payloads, parameterPayload, msg.sender);
+ s_feeManager.processFeeBulk{value: msg.value}(payloads, parameterPayload, msg.sender);
}
function setFeeManager(IFeeManager feeManager) public {
- i_feeManager = feeManager;
+ s_feeManager = feeManager;
}
}
diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/BaseRewardManager.t.sol
similarity index 97%
rename from contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/BaseRewardManager.t.sol
index 65481513f0d..c7bd7528c31 100644
--- a/contracts/src/v0.8/llo-feeds/test/reward-manager/BaseRewardManager.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/BaseRewardManager.t.sol
@@ -2,9 +2,9 @@
pragma solidity 0.8.19;
import {Test} from "forge-std/Test.sol";
-import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
-import {RewardManager} from "../../RewardManager.sol";
-import {Common} from "../../libraries/Common.sol";
+import {ERC20Mock} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
+import {RewardManager} from "../../../v0.3.0/RewardManager.sol";
+import {Common} from "../../../libraries/Common.sol";
import {IRewardManager} from "../../interfaces/IRewardManager.sol";
/**
diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.claim.t.sol
similarity index 99%
rename from contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.claim.t.sol
index 5f07d36c72c..efbe9fd6b36 100644
--- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.claim.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.claim.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol";
-import {Common} from "../../libraries/Common.sol";
+import {Common} from "../../../libraries/Common.sol";
/**
* @title BaseRewardManagerTest
@@ -574,7 +574,7 @@ contract RewardManagerRecipientClaimMultiplePoolsTest is BaseRewardManagerTest {
assertEq(poolIds[1], ZERO_POOL_ID);
}
- function test_getRewardsAvailableToRecipientInNoPools() public {
+ function test_getRewardsAvailableToRecipientInNoPools() public view {
//get index 0 as this recipient is in both default pools
bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(FEE_MANAGER, 0, type(uint256).max);
diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.general.t.sol
similarity index 92%
rename from contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.general.t.sol
index 7fde76d5281..baff3887699 100644
--- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.general.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.general.t.sol
@@ -2,8 +2,8 @@
pragma solidity 0.8.19;
import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol";
-import {RewardManager} from "../../RewardManager.sol";
-import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
+import {RewardManager} from "../../../v0.3.0/RewardManager.sol";
+import {ERC20Mock} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
import {IRewardManager} from "../../interfaces/IRewardManager.sol";
/**
diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.payRecipients.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.payRecipients.t.sol
similarity index 100%
rename from contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.payRecipients.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.payRecipients.t.sol
diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.setRecipients.t.sol
similarity index 98%
rename from contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.setRecipients.t.sol
index 1cf5b51f621..d3e6990bd9f 100644
--- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.setRecipients.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.setRecipients.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol";
-import {Common} from "../../libraries/Common.sol";
+import {Common} from "../../../libraries/Common.sol";
/**
* @title BaseRewardManagerTest
diff --git a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.updateRewardRecipients.t.sol
similarity index 99%
rename from contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.updateRewardRecipients.t.sol
index 6c51a0fbfdd..0d3a2b69b39 100644
--- a/contracts/src/v0.8/llo-feeds/test/reward-manager/RewardManager.updateRewardRecipients.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/reward-manager/RewardManager.updateRewardRecipients.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseRewardManagerTest} from "./BaseRewardManager.t.sol";
-import {Common} from "../../libraries/Common.sol";
+import {Common} from "../../../libraries/Common.sol";
/**
* @title BaseRewardManagerTest
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/BaseVerifierTest.t.sol
similarity index 97%
rename from contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/BaseVerifierTest.t.sol
index daf31875036..4d65414676e 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/BaseVerifierTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/BaseVerifierTest.t.sol
@@ -3,17 +3,16 @@ pragma solidity 0.8.19;
import {Test} from "forge-std/Test.sol";
import {VerifierProxy} from "../../VerifierProxy.sol";
-import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {IVerifier} from "../../interfaces/IVerifier.sol";
import {ErroredVerifier} from "../mocks/ErroredVerifier.sol";
import {Verifier} from "../../Verifier.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
-import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol";
-import {FeeManager} from "../../FeeManager.sol";
-import {Common} from "../../libraries/Common.sol";
-import {ERC20Mock} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
-import {WERC20Mock} from "../../../shared/mocks/WERC20Mock.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
import {FeeManager} from "../../FeeManager.sol";
+import {Common} from "../../../libraries/Common.sol";
+import {ERC20Mock} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
+import {WERC20Mock} from "../../../../shared/mocks/WERC20Mock.sol";
import {RewardManager} from "../../RewardManager.sol";
contract BaseTest is Test {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierActivateConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierActivateConfigTest.t.sol
similarity index 97%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierActivateConfigTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierActivateConfigTest.t.sol
index f53c26ba192..99daabe206b 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierActivateConfigTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierActivateConfigTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseTestWithConfiguredVerifierAndFeeManager, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol";
-import {Verifier} from "../../Verifier.sol";
+import {Verifier} from "../../../v0.3.0/Verifier.sol";
contract VerifierActivateConfigTest is BaseTestWithConfiguredVerifierAndFeeManager {
function test_revertsIfNotOwner() public {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierDeactivateFeedTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierDeactivateFeedTest.t.sol
similarity index 98%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierDeactivateFeedTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierDeactivateFeedTest.t.sol
index 97647c88635..fb52c1c93e7 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierDeactivateFeedTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierDeactivateFeedTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseTestWithConfiguredVerifierAndFeeManager, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol";
-import {Verifier} from "../../Verifier.sol";
+import {Verifier} from "../../../v0.3.0/Verifier.sol";
contract VerifierActivateFeedTest is BaseTestWithConfiguredVerifierAndFeeManager {
function test_revertsIfNotOwnerActivateFeed() public {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyConstructorTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyConstructorTest.t.sol
similarity index 77%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyConstructorTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyConstructorTest.t.sol
index b085dc8a651..82efd8907be 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyConstructorTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyConstructorTest.t.sol
@@ -2,8 +2,8 @@
pragma solidity 0.8.19;
import {BaseTest} from "./BaseVerifierTest.t.sol";
-import {VerifierProxy} from "../../VerifierProxy.sol";
-import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol";
+import {VerifierProxy} from "../../../v0.3.0/VerifierProxy.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
contract VerifierProxyConstructorTest is BaseTest {
function test_correctlySetsTheOwner() public {
@@ -17,7 +17,7 @@ contract VerifierProxyConstructorTest is BaseTest {
assertEq(address(proxy.s_accessController()), accessControllerAddr);
}
- function test_correctlySetsVersion() public {
+ function test_correctlySetsVersion() public view {
string memory version = s_verifierProxy.typeAndVersion();
assertEq(version, "VerifierProxy 2.0.0");
}
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyInitializeVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyInitializeVerifierTest.t.sol
similarity index 93%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyInitializeVerifierTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyInitializeVerifierTest.t.sol
index e02b14fe56e..5537d273be9 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyInitializeVerifierTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyInitializeVerifierTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseTest} from "./BaseVerifierTest.t.sol";
-import {VerifierProxy} from "../../VerifierProxy.sol";
+import {VerifierProxy} from "../../../v0.3.0/VerifierProxy.sol";
contract VerifierProxyInitializeVerifierTest is BaseTest {
bytes32 latestDigest;
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetAccessControllerTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxySetAccessControllerTest.t.sol
similarity index 92%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetAccessControllerTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxySetAccessControllerTest.t.sol
index 04889e0d5f4..03bd6d97ee5 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetAccessControllerTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxySetAccessControllerTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseTest} from "./BaseVerifierTest.t.sol";
-import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
contract VerifierProxySetAccessControllerTest is BaseTest {
event AccessControllerSet(address oldAccessController, address newAccessController);
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxySetVerifierTest.t.sol
similarity index 88%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxySetVerifierTest.t.sol
index ea23f880ba7..78e5ff0766f 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxySetVerifierTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxySetVerifierTest.t.sol
@@ -3,9 +3,9 @@ pragma solidity 0.8.19;
import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol";
import {IVerifier} from "../../interfaces/IVerifier.sol";
-import {VerifierProxy} from "../../VerifierProxy.sol";
-import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
-import {Common} from "../../libraries/Common.sol";
+import {VerifierProxy} from "../../../v0.3.0/VerifierProxy.sol";
+import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../../../libraries/Common.sol";
contract VerifierProxyInitializeVerifierTest is BaseTestWithConfiguredVerifierAndFeeManager {
function test_revertsIfNotCorrectVerifier() public {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyTest.t.sol
similarity index 87%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyTest.t.sol
index ea7e02d7409..441626e575b 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyTest.t.sol
@@ -2,8 +2,8 @@
pragma solidity 0.8.19;
import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol";
-import {VerifierProxy} from "../../VerifierProxy.sol";
-import {FeeManager} from "../../FeeManager.sol";
+import {VerifierProxy} from "../../../v0.3.0/VerifierProxy.sol";
+import {FeeManager} from "../../../v0.3.0/FeeManager.sol";
contract VerifierProxyInitializeVerifierTest is BaseTestWithConfiguredVerifierAndFeeManager {
function test_setFeeManagerZeroAddress() public {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyUnsetVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyUnsetVerifierTest.t.sol
similarity index 95%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyUnsetVerifierTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyUnsetVerifierTest.t.sol
index 746aa955748..a51c67e336c 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierProxyUnsetVerifierTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierProxyUnsetVerifierTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseTest, BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol";
-import {VerifierProxy} from "../../VerifierProxy.sol";
+import {VerifierProxy} from "../../../v0.3.0/VerifierProxy.sol";
contract VerifierProxyUnsetVerifierTest is BaseTest {
function test_revertsIfNotAdmin() public {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierSetConfigFromSourceTest.t.sol
similarity index 98%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierSetConfigFromSourceTest.t.sol
index 0cd5902161d..9ee9b5272a7 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigFromSourceTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierSetConfigFromSourceTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseTest, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol";
-import {Common} from "../../libraries/Common.sol";
+import {Common} from "../../../libraries/Common.sol";
contract VerifierSetConfigFromSourceTest is BaseTest {
function setUp() public virtual override {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierSetConfigTest.t.sol
similarity index 98%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierSetConfigTest.t.sol
index a4e15dcdd4c..972ead81230 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierSetConfigTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierSetConfigTest.t.sol
@@ -2,8 +2,8 @@
pragma solidity 0.8.19;
import {BaseTest, BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol";
-import {Verifier} from "../../Verifier.sol";
-import {Common} from "../../libraries/Common.sol";
+import {Verifier} from "../../../v0.3.0/Verifier.sol";
+import {Common} from "../../../libraries/Common.sol";
contract VerifierSetConfigTest is BaseTest {
function setUp() public virtual override {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierTest.t.sol
similarity index 88%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierTest.t.sol
index 2857b8f4d3d..81f65f0c6eb 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseTest} from "./BaseVerifierTest.t.sol";
-import {Verifier} from "../../Verifier.sol";
+import {Verifier} from "../../../v0.3.0/Verifier.sol";
contract VerifierConstructorTest is BaseTest {
function test_revertsIfInitializedWithEmptyVerifierProxy() public {
@@ -30,12 +30,12 @@ contract VerifierConstructorTest is BaseTest {
}
contract VerifierSupportsInterfaceTest is BaseTest {
- function test_falseIfIsNotCorrectInterface() public {
+ function test_falseIfIsNotCorrectInterface() public view {
bool isInterface = s_verifier.supportsInterface(bytes4("abcd"));
assertEq(isInterface, false);
}
- function test_trueIfIsCorrectInterface() public {
+ function test_trueIfIsCorrectInterface() public view {
bool isInterface = s_verifier.supportsInterface(Verifier.verify.selector);
assertEq(isInterface, true);
}
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierTestBillingReport.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierTestBillingReport.t.sol
similarity index 100%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierTestBillingReport.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierTestBillingReport.t.sol
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierUnsetConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierUnsetConfigTest.t.sol
similarity index 97%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierUnsetConfigTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierUnsetConfigTest.t.sol
index cc3c33331df..e192a2e9e08 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierUnsetConfigTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierUnsetConfigTest.t.sol
@@ -2,7 +2,7 @@
pragma solidity 0.8.19;
import {BaseTestWithMultipleConfiguredDigests} from "./BaseVerifierTest.t.sol";
-import {Verifier} from "../../Verifier.sol";
+import {Verifier} from "../../../v0.3.0/Verifier.sol";
contract VerificationdeactivateConfigWhenThereAreMultipleDigestsTest is BaseTestWithMultipleConfiguredDigests {
function test_revertsIfCalledByNonOwner() public {
diff --git a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierVerifyTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierVerifyTest.t.sol
similarity index 97%
rename from contracts/src/v0.8/llo-feeds/test/verifier/VerifierVerifyTest.t.sol
rename to contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierVerifyTest.t.sol
index db7be5ca543..1c14ba974c0 100644
--- a/contracts/src/v0.8/llo-feeds/test/verifier/VerifierVerifyTest.t.sol
+++ b/contracts/src/v0.8/llo-feeds/v0.3.0/test/verifier/VerifierVerifyTest.t.sol
@@ -2,10 +2,10 @@
pragma solidity 0.8.19;
import {BaseTestWithConfiguredVerifierAndFeeManager} from "./BaseVerifierTest.t.sol";
-import {Verifier} from "../../Verifier.sol";
-import {VerifierProxy} from "../../VerifierProxy.sol";
-import {AccessControllerInterface} from "../../../shared/interfaces/AccessControllerInterface.sol";
-import {Common} from "../../libraries/Common.sol";
+import {Verifier} from "../../../v0.3.0/Verifier.sol";
+import {VerifierProxy} from "../../../v0.3.0/VerifierProxy.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
+import {Common} from "../../../libraries/Common.sol";
contract VerifierVerifyTest is BaseTestWithConfiguredVerifierAndFeeManager {
bytes32[3] internal s_reportContext;
@@ -32,7 +32,7 @@ contract VerifierVerifyTest is BaseTestWithConfiguredVerifierAndFeeManager {
);
}
- function assertReportsEqual(bytes memory response, V1Report memory testReport) public {
+ function assertReportsEqual(bytes memory response, V1Report memory testReport) public pure {
(
bytes32 feedId,
uint32 timestamp,
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationFeeManager.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationFeeManager.sol
new file mode 100644
index 00000000000..38d93de5cb7
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationFeeManager.sol
@@ -0,0 +1,557 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
+import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../libraries/Common.sol";
+import {IWERC20} from "../../shared/interfaces/IWERC20.sol";
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
+import {Math} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/Math.sol";
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+import {IDestinationRewardManager} from "./interfaces/IDestinationRewardManager.sol";
+import {IDestinationFeeManager} from "./interfaces/IDestinationFeeManager.sol";
+
+/**
+ * @title FeeManager
+ * @author Michael Fletcher
+ * @author Austin Born
+ * @notice This contract is used for the handling of fees required for users verifying reports.
+ */
+contract DestinationFeeManager is IDestinationFeeManager, ConfirmedOwner, TypeAndVersionInterface {
+ using SafeERC20 for IERC20;
+
+ /// @notice list of subscribers and their discounts subscriberDiscounts[subscriber][feedId][token]
+ mapping(address => mapping(bytes32 => mapping(address => uint256))) public s_subscriberDiscounts;
+
+ /// @notice keep track of any subsidised link that is owed to the reward manager.
+ mapping(bytes32 => uint256) public s_linkDeficit;
+
+ /// @notice the total discount that can be applied to a fee, 1e18 = 100% discount
+ uint64 private constant PERCENTAGE_SCALAR = 1e18;
+
+ /// @notice the LINK token address
+ address public immutable i_linkAddress;
+
+ /// @notice the native token address
+ address public immutable i_nativeAddress;
+
+ /// @notice the verifier address
+ mapping(address => address) public s_verifierAddressList;
+
+ /// @notice the reward manager address
+ IDestinationRewardManager public i_rewardManager;
+
+ // @notice the mask to apply to get the report version
+ bytes32 private constant REPORT_VERSION_MASK = 0xffff000000000000000000000000000000000000000000000000000000000000;
+
+ // @notice the different report versions
+ bytes32 private constant REPORT_V1 = 0x0001000000000000000000000000000000000000000000000000000000000000;
+
+ /// @notice the surcharge fee to be paid if paying in native
+ uint256 public s_nativeSurcharge;
+
+ /// @notice the error thrown if the discount or surcharge is invalid
+ error InvalidSurcharge();
+
+ /// @notice the error thrown if the discount is invalid
+ error InvalidDiscount();
+
+ /// @notice the error thrown if the address is invalid
+ error InvalidAddress();
+
+ /// @notice thrown if msg.value is supplied with a bad quote
+ error InvalidDeposit();
+
+ /// @notice thrown if a report has expired
+ error ExpiredReport();
+
+ /// @notice thrown if a report has no quote
+ error InvalidQuote();
+
+ // @notice thrown when the caller is not authorized
+ error Unauthorized();
+
+ // @notice thrown when trying to clear a zero deficit
+ error ZeroDeficit();
+
+ /// @notice thrown when trying to pay an address that cannot except funds
+ error InvalidReceivingAddress();
+
+ /// @notice thrown when trying to bulk verify reports where theres not a matching number of poolIds
+ error PoolIdMismatch();
+
+ /// @notice Emitted whenever a subscriber's discount is updated
+ /// @param subscriber address of the subscriber to update discounts for
+ /// @param feedId Feed ID for the discount
+ /// @param token Token address for the discount
+ /// @param discount Discount to apply, in relation to the PERCENTAGE_SCALAR
+ event SubscriberDiscountUpdated(address indexed subscriber, bytes32 indexed feedId, address token, uint64 discount);
+
+ /// @notice Emitted when updating the native surcharge
+ /// @param newSurcharge Surcharge amount to apply relative to PERCENTAGE_SCALAR
+ event NativeSurchargeUpdated(uint64 newSurcharge);
+
+ /// @notice Emits when this contract does not have enough LINK to send to the reward manager when paying in native
+ /// @param rewards Config digest and link fees which could not be subsidised
+ event InsufficientLink(IDestinationRewardManager.FeePayment[] rewards);
+
+ /// @notice Emitted when funds are withdrawn
+ /// @param adminAddress Address of the admin
+ /// @param recipient Address of the recipient
+ /// @param assetAddress Address of the asset withdrawn
+ /// @param quantity Amount of the asset withdrawn
+ event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity);
+
+ /// @notice Emits when a deficit has been cleared for a particular config digest
+ /// @param configDigest Config digest of the deficit cleared
+ /// @param linkQuantity Amount of LINK required to pay the deficit
+ event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity);
+
+ /// @notice Emits when a fee has been processed
+ /// @param configDigest Config digest of the fee processed
+ /// @param subscriber Address of the subscriber who paid the fee
+ /// @param fee Fee paid
+ /// @param reward Reward paid
+ /// @param appliedDiscount Discount applied to the fee
+ event DiscountApplied(
+ bytes32 indexed configDigest,
+ address indexed subscriber,
+ Common.Asset fee,
+ Common.Asset reward,
+ uint256 appliedDiscount
+ );
+
+ /**
+ * @notice Construct the FeeManager contract
+ * @param _linkAddress The address of the LINK token
+ * @param _nativeAddress The address of the wrapped ERC-20 version of the native token (represents fee in native or wrapped)
+ * @param _verifierAddress The address of the verifier contract
+ * @param _rewardManagerAddress The address of the reward manager contract
+ */
+ constructor(
+ address _linkAddress,
+ address _nativeAddress,
+ address _verifierAddress,
+ address _rewardManagerAddress
+ ) ConfirmedOwner(msg.sender) {
+ if (
+ _linkAddress == address(0) ||
+ _nativeAddress == address(0) ||
+ _verifierAddress == address(0) ||
+ _rewardManagerAddress == address(0)
+ ) revert InvalidAddress();
+
+ i_linkAddress = _linkAddress;
+ i_nativeAddress = _nativeAddress;
+ s_verifierAddressList[_verifierAddress] = _verifierAddress;
+ i_rewardManager = IDestinationRewardManager(_rewardManagerAddress);
+
+ IERC20(i_linkAddress).approve(address(i_rewardManager), type(uint256).max);
+ }
+
+ modifier onlyOwnerOrVerifier() {
+ if (msg.sender != s_verifierAddressList[msg.sender] && msg.sender != owner()) revert Unauthorized();
+ _;
+ }
+
+ modifier onlyVerifier() {
+ if (msg.sender != s_verifierAddressList[msg.sender]) revert Unauthorized();
+ _;
+ }
+
+ /// @inheritdoc TypeAndVersionInterface
+ function typeAndVersion() external pure override returns (string memory) {
+ return "DestinationFeeManager 1.0.0";
+ }
+
+ /// @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
+ //for each function in IDestinationFeeManager we need to check if it matches the selector
+ return
+ interfaceId == this.getFeeAndReward.selector ||
+ interfaceId == this.setNativeSurcharge.selector ||
+ interfaceId == this.updateSubscriberDiscount.selector ||
+ interfaceId == this.withdraw.selector ||
+ interfaceId == this.linkAvailableForPayment.selector ||
+ interfaceId == this.payLinkDeficit.selector ||
+ interfaceId == this.addVerifier.selector ||
+ interfaceId == this.removeVerifier.selector ||
+ interfaceId == this.processFee.selector ||
+ interfaceId == this.processFeeBulk.selector ||
+ interfaceId == this.setFeeRecipients.selector;
+ }
+
+ function processFee(
+ bytes32 recipient,
+ bytes calldata payload,
+ bytes calldata parameterPayload,
+ address subscriber
+ ) external payable override onlyVerifier {
+ (Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _calculateFee(
+ payload,
+ parameterPayload,
+ subscriber
+ );
+
+ if (fee.amount == 0) {
+ _tryReturnChange(subscriber, msg.value);
+ return;
+ }
+
+ IDestinationFeeManager.FeeAndReward[] memory feeAndReward = new IDestinationFeeManager.FeeAndReward[](1);
+ feeAndReward[0] = IDestinationFeeManager.FeeAndReward(recipient, fee, reward, appliedDiscount);
+
+ if (fee.assetAddress == i_linkAddress) {
+ _handleFeesAndRewards(subscriber, feeAndReward, 1, 0);
+ } else {
+ _handleFeesAndRewards(subscriber, feeAndReward, 0, 1);
+ }
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function processFeeBulk(
+ bytes32[] memory poolIds,
+ bytes[] calldata payloads,
+ bytes calldata parameterPayload,
+ address subscriber
+ ) external payable override onlyVerifier {
+ //poolIDs are mapped to payloads, so they should be the same length
+ if (poolIds.length != payloads.length) revert PoolIdMismatch();
+
+ IDestinationFeeManager.FeeAndReward[] memory feesAndRewards = new IDestinationFeeManager.FeeAndReward[](
+ payloads.length
+ );
+
+ //keep track of the number of fees to prevent over initialising the FeePayment array within _convertToLinkAndNativeFees
+ uint256 numberOfLinkFees;
+ uint256 numberOfNativeFees;
+
+ uint256 feesAndRewardsIndex;
+ for (uint256 i; i < payloads.length; ++i) {
+ if (poolIds[i] == bytes32(0)) revert InvalidAddress();
+
+ (Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _calculateFee(
+ payloads[i],
+ parameterPayload,
+ subscriber
+ );
+
+ if (fee.amount != 0) {
+ feesAndRewards[feesAndRewardsIndex++] = IDestinationFeeManager.FeeAndReward(
+ poolIds[i],
+ fee,
+ reward,
+ appliedDiscount
+ );
+
+ unchecked {
+ //keep track of some tallys to make downstream calculations more efficient
+ if (fee.assetAddress == i_linkAddress) {
+ ++numberOfLinkFees;
+ } else {
+ ++numberOfNativeFees;
+ }
+ }
+ }
+ }
+
+ if (numberOfLinkFees != 0 || numberOfNativeFees != 0) {
+ _handleFeesAndRewards(subscriber, feesAndRewards, numberOfLinkFees, numberOfNativeFees);
+ } else {
+ _tryReturnChange(subscriber, msg.value);
+ }
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function getFeeAndReward(
+ address subscriber,
+ bytes memory report,
+ address quoteAddress
+ ) public view returns (Common.Asset memory, Common.Asset memory, uint256) {
+ Common.Asset memory fee;
+ Common.Asset memory reward;
+
+ //get the feedId from the report
+ bytes32 feedId = bytes32(report);
+
+ //the report needs to be a support version
+ bytes32 reportVersion = _getReportVersion(feedId);
+
+ //version 1 of the reports don't require quotes, so the fee will be 0
+ if (reportVersion == REPORT_V1) {
+ fee.assetAddress = i_nativeAddress;
+ reward.assetAddress = i_linkAddress;
+ return (fee, reward, 0);
+ }
+
+ //verify the quote payload is a supported token
+ if (quoteAddress != i_nativeAddress && quoteAddress != i_linkAddress) {
+ revert InvalidQuote();
+ }
+
+ //decode the report depending on the version
+ uint256 linkQuantity;
+ uint256 nativeQuantity;
+ uint256 expiresAt;
+ (, , , nativeQuantity, linkQuantity, expiresAt) = abi.decode(
+ report,
+ (bytes32, uint32, uint32, uint192, uint192, uint32)
+ );
+
+ //read the timestamp bytes from the report data and verify it has not expired
+ if (expiresAt < block.timestamp) {
+ revert ExpiredReport();
+ }
+
+ //get the discount being applied
+ uint256 discount = s_subscriberDiscounts[subscriber][feedId][quoteAddress];
+
+ //the reward is always set in LINK
+ reward.assetAddress = i_linkAddress;
+ reward.amount = Math.ceilDiv(linkQuantity * (PERCENTAGE_SCALAR - discount), PERCENTAGE_SCALAR);
+
+ //calculate either the LINK fee or native fee if it's within the report
+ if (quoteAddress == i_linkAddress) {
+ fee.assetAddress = i_linkAddress;
+ fee.amount = reward.amount;
+ } else {
+ uint256 surchargedFee = Math.ceilDiv(nativeQuantity * (PERCENTAGE_SCALAR + s_nativeSurcharge), PERCENTAGE_SCALAR);
+
+ fee.assetAddress = i_nativeAddress;
+ fee.amount = Math.ceilDiv(surchargedFee * (PERCENTAGE_SCALAR - discount), PERCENTAGE_SCALAR);
+ }
+
+ //return the fee
+ return (fee, reward, discount);
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function setFeeRecipients(
+ bytes32 configDigest,
+ Common.AddressAndWeight[] calldata rewardRecipientAndWeights
+ ) external onlyOwnerOrVerifier {
+ i_rewardManager.setRewardRecipients(configDigest, rewardRecipientAndWeights);
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function setNativeSurcharge(uint64 surcharge) external onlyOwner {
+ if (surcharge > PERCENTAGE_SCALAR) revert InvalidSurcharge();
+
+ s_nativeSurcharge = surcharge;
+
+ emit NativeSurchargeUpdated(surcharge);
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function updateSubscriberDiscount(
+ address subscriber,
+ bytes32 feedId,
+ address token,
+ uint64 discount
+ ) external onlyOwner {
+ //make sure the discount is not greater than the total discount that can be applied
+ if (discount > PERCENTAGE_SCALAR) revert InvalidDiscount();
+ //make sure the token is either LINK or native
+ if (token != i_linkAddress && token != i_nativeAddress) revert InvalidAddress();
+
+ s_subscriberDiscounts[subscriber][feedId][token] = discount;
+
+ emit SubscriberDiscountUpdated(subscriber, feedId, token, discount);
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function withdraw(address assetAddress, address recipient, uint192 quantity) external onlyOwner {
+ //address 0 is used to withdraw native in the context of withdrawing
+ if (assetAddress == address(0)) {
+ (bool success, ) = payable(recipient).call{value: quantity}("");
+
+ if (!success) revert InvalidReceivingAddress();
+ return;
+ }
+
+ //withdraw the requested asset
+ IERC20(assetAddress).safeTransfer(recipient, quantity);
+
+ //emit event when funds are withdrawn
+ emit Withdraw(msg.sender, recipient, assetAddress, uint192(quantity));
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function linkAvailableForPayment() external view returns (uint256) {
+ //return the amount of LINK this contact has available to pay rewards
+ return IERC20(i_linkAddress).balanceOf(address(this));
+ }
+
+ /**
+ * @notice Gets the current version of the report that is encoded as the last two bytes of the feed
+ * @param feedId feed id to get the report version for
+ */
+ function _getReportVersion(bytes32 feedId) internal pure returns (bytes32) {
+ return REPORT_VERSION_MASK & feedId;
+ }
+
+ function _calculateFee(
+ bytes calldata payload,
+ bytes calldata parameterPayload,
+ address subscriber
+ ) internal view returns (Common.Asset memory, Common.Asset memory, uint256) {
+ if (subscriber == address(this)) revert InvalidAddress();
+
+ //decode the report from the payload
+ (, bytes memory report) = abi.decode(payload, (bytes32[3], bytes));
+
+ //get the feedId from the report
+ bytes32 feedId = bytes32(report);
+
+ //v1 doesn't need a quote payload, so skip the decoding
+ address quote;
+ if (_getReportVersion(feedId) != REPORT_V1) {
+ //decode the quote from the bytes
+ (quote) = abi.decode(parameterPayload, (address));
+ }
+
+ //decode the fee, it will always be native or LINK
+ return getFeeAndReward(subscriber, report, quote);
+ }
+
+ function _handleFeesAndRewards(
+ address subscriber,
+ IDestinationFeeManager.FeeAndReward[] memory feesAndRewards,
+ uint256 numberOfLinkFees,
+ uint256 numberOfNativeFees
+ ) internal {
+ IDestinationRewardManager.FeePayment[] memory linkRewards = new IDestinationRewardManager.FeePayment[](
+ numberOfLinkFees
+ );
+ IDestinationRewardManager.FeePayment[] memory nativeFeeLinkRewards = new IDestinationRewardManager.FeePayment[](
+ numberOfNativeFees
+ );
+
+ uint256 totalNativeFee;
+ uint256 totalNativeFeeLinkValue;
+
+ uint256 linkRewardsIndex;
+ uint256 nativeFeeLinkRewardsIndex;
+
+ uint256 totalNumberOfFees = numberOfLinkFees + numberOfNativeFees;
+ for (uint256 i; i < totalNumberOfFees; ++i) {
+ if (feesAndRewards[i].fee.assetAddress == i_linkAddress) {
+ linkRewards[linkRewardsIndex++] = IDestinationRewardManager.FeePayment(
+ feesAndRewards[i].configDigest,
+ uint192(feesAndRewards[i].reward.amount)
+ );
+ } else {
+ nativeFeeLinkRewards[nativeFeeLinkRewardsIndex++] = IDestinationRewardManager.FeePayment(
+ feesAndRewards[i].configDigest,
+ uint192(feesAndRewards[i].reward.amount)
+ );
+ totalNativeFee += feesAndRewards[i].fee.amount;
+ totalNativeFeeLinkValue += feesAndRewards[i].reward.amount;
+ }
+
+ if (feesAndRewards[i].appliedDiscount != 0) {
+ emit DiscountApplied(
+ feesAndRewards[i].configDigest,
+ subscriber,
+ feesAndRewards[i].fee,
+ feesAndRewards[i].reward,
+ feesAndRewards[i].appliedDiscount
+ );
+ }
+ }
+
+ //keep track of change in case of any over payment
+ uint256 change;
+
+ if (msg.value != 0) {
+ //there must be enough to cover the fee
+ if (totalNativeFee > msg.value) revert InvalidDeposit();
+
+ //wrap the amount required to pay the fee & approve as the subscriber paid in wrapped native
+ IWERC20(i_nativeAddress).deposit{value: totalNativeFee}();
+
+ unchecked {
+ //msg.value is always >= to fee.amount
+ change = msg.value - totalNativeFee;
+ }
+ } else {
+ if (totalNativeFee != 0) {
+ //subscriber has paid in wrapped native, so transfer the native to this contract
+ IERC20(i_nativeAddress).safeTransferFrom(subscriber, address(this), totalNativeFee);
+ }
+ }
+
+ if (linkRewards.length != 0) {
+ i_rewardManager.onFeePaid(linkRewards, subscriber);
+ }
+
+ if (nativeFeeLinkRewards.length != 0) {
+ //distribute subsidised fees paid in Native
+ if (totalNativeFeeLinkValue > IERC20(i_linkAddress).balanceOf(address(this))) {
+ // If not enough LINK on this contract to forward for rewards, tally the deficit to be paid by out-of-band LINK
+ for (uint256 i; i < nativeFeeLinkRewards.length; ++i) {
+ unchecked {
+ //we have previously tallied the fees, any overflows would have already reverted
+ s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount;
+ }
+ }
+
+ emit InsufficientLink(nativeFeeLinkRewards);
+ } else {
+ //distribute the fees
+ i_rewardManager.onFeePaid(nativeFeeLinkRewards, address(this));
+ }
+ }
+
+ // a refund may be needed if the payee has paid in excess of the fee
+ _tryReturnChange(subscriber, change);
+ }
+
+ function _tryReturnChange(address subscriber, uint256 quantity) internal {
+ if (quantity != 0) {
+ payable(subscriber).transfer(quantity);
+ }
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function payLinkDeficit(bytes32 configDigest) external onlyOwner {
+ uint256 deficit = s_linkDeficit[configDigest];
+
+ if (deficit == 0) revert ZeroDeficit();
+
+ delete s_linkDeficit[configDigest];
+
+ IDestinationRewardManager.FeePayment[] memory deficitFeePayment = new IDestinationRewardManager.FeePayment[](1);
+
+ deficitFeePayment[0] = IDestinationRewardManager.FeePayment(configDigest, uint192(deficit));
+
+ i_rewardManager.onFeePaid(deficitFeePayment, address(this));
+
+ emit LinkDeficitCleared(configDigest, deficit);
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function addVerifier(address verifierAddress) external onlyOwner {
+ if (verifierAddress == address(0)) revert InvalidAddress();
+ //check doesn't already exist
+ if (s_verifierAddressList[verifierAddress] != address(0)) revert InvalidAddress();
+ s_verifierAddressList[verifierAddress] = verifierAddress;
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function removeVerifier(address verifierAddress) external onlyOwner {
+ if (verifierAddress == address(0)) revert InvalidAddress();
+ //check doesn't already exist
+ if (s_verifierAddressList[verifierAddress] == address(0)) revert InvalidAddress();
+ delete s_verifierAddressList[verifierAddress];
+ }
+
+ /// @inheritdoc IDestinationFeeManager
+ function setRewardManager(address rewardManagerAddress) external onlyOwner {
+ if (rewardManagerAddress == address(0)) revert InvalidAddress();
+ IERC20(i_linkAddress).approve(address(i_rewardManager), 0);
+ i_rewardManager = IDestinationRewardManager(rewardManagerAddress);
+ IERC20(i_linkAddress).approve(address(i_rewardManager), type(uint256).max);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationRewardManager.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationRewardManager.sol
new file mode 100644
index 00000000000..ae40a2385c7
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationRewardManager.sol
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
+import {IDestinationRewardManager} from "./interfaces/IDestinationRewardManager.sol";
+import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
+import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
+import {Common} from "../libraries/Common.sol";
+import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/utils/SafeERC20.sol";
+
+/**
+ * @title DestinationRewardManager
+ * @author Michael Fletcher
+ * @author Austin Born
+ * @notice This contract will be used to reward any configured recipients within a pool. Recipients will receive a share of their pool relative to their configured weight.
+ */
+contract DestinationRewardManager is IDestinationRewardManager, ConfirmedOwner, TypeAndVersionInterface {
+ using SafeERC20 for IERC20;
+
+ // @dev The mapping of total fees collected for a particular pot: s_totalRewardRecipientFees[poolId]
+ mapping(bytes32 => uint256) public s_totalRewardRecipientFees;
+
+ // @dev The mapping of fee balances for each pot last time the recipient claimed: s_totalRewardRecipientFeesLastClaimedAmounts[poolId][recipient]
+ mapping(bytes32 => mapping(address => uint256)) public s_totalRewardRecipientFeesLastClaimedAmounts;
+
+ // @dev The mapping of RewardRecipient weights for a particular poolId: s_rewardRecipientWeights[poolId][rewardRecipient].
+ mapping(bytes32 => mapping(address => uint256)) public s_rewardRecipientWeights;
+
+ // @dev Keep track of the reward recipient weights that have been set to prevent duplicates
+ mapping(bytes32 => bool) public s_rewardRecipientWeightsSet;
+
+ // @dev Store a list of pool ids that have been registered, to make off chain lookups easier
+ bytes32[] public s_registeredPoolIds;
+
+ // @dev The address for the LINK contract
+ address public immutable i_linkAddress;
+
+ // The total weight of all RewardRecipients. 1e18 = 100% of the pool fees
+ uint64 private constant PERCENTAGE_SCALAR = 1e18;
+
+ // The fee manager address
+ mapping(address => address) public s_feeManagerAddressList;
+
+ // @notice Thrown whenever the RewardRecipient weights are invalid
+ error InvalidWeights();
+
+ // @notice Thrown when any given address is invalid
+ error InvalidAddress();
+
+ // @notice Thrown when the pool id is invalid
+ error InvalidPoolId();
+
+ // @notice Thrown when the calling contract is not within the authorized contracts
+ error Unauthorized();
+
+ // @notice Thrown when getAvailableRewardPoolIds parameters are incorrectly set
+ error InvalidPoolLength();
+
+ // Events emitted upon state change
+ event RewardRecipientsUpdated(bytes32 indexed poolId, Common.AddressAndWeight[] newRewardRecipients);
+ event RewardsClaimed(bytes32 indexed poolId, address indexed recipient, uint192 quantity);
+ event FeeManagerUpdated(address newFeeManagerAddress);
+ event FeePaid(FeePayment[] payments, address payer);
+
+ /**
+ * @notice Constructor
+ * @param linkAddress address of the wrapped LINK token
+ */
+ constructor(address linkAddress) ConfirmedOwner(msg.sender) {
+ //ensure that the address ia not zero
+ if (linkAddress == address(0)) revert InvalidAddress();
+
+ i_linkAddress = linkAddress;
+ }
+
+ // @inheritdoc TypeAndVersionInterface
+ function typeAndVersion() external pure override returns (string memory) {
+ return "RewardManager 1.0.0";
+ }
+
+ // @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
+ return
+ interfaceId == this.claimRewards.selector ||
+ interfaceId == this.setRewardRecipients.selector ||
+ interfaceId == this.updateRewardRecipients.selector ||
+ interfaceId == this.payRecipients.selector ||
+ interfaceId == this.addFeeManager.selector ||
+ interfaceId == this.removeFeeManager.selector ||
+ interfaceId == this.getAvailableRewardPoolIds.selector ||
+ interfaceId == this.onFeePaid.selector;
+ }
+
+ modifier onlyOwnerOrFeeManager() {
+ if (msg.sender != owner() && msg.sender != s_feeManagerAddressList[msg.sender]) revert Unauthorized();
+ _;
+ }
+
+ modifier onlyOwnerOrRecipientInPool(bytes32 poolId) {
+ if (msg.sender != owner() && s_rewardRecipientWeights[poolId][msg.sender] == 0) revert Unauthorized();
+ _;
+ }
+
+ modifier onlyFeeManager() {
+ if (msg.sender != s_feeManagerAddressList[msg.sender]) revert Unauthorized();
+ _;
+ }
+
+ /// @inheritdoc IDestinationRewardManager
+ function onFeePaid(FeePayment[] calldata payments, address payer) external override onlyFeeManager {
+ uint256 totalFeeAmount;
+ for (uint256 i; i < payments.length; ++i) {
+ unchecked {
+ //the total amount for any ERC-20 asset cannot exceed 2^256 - 1
+ //see https://github.com/OpenZeppelin/openzeppelin-contracts/blob/36bf1e46fa811f0f07d38eb9cfbc69a955f300ce/contracts/token/ERC20/ERC20.sol#L266
+ //for example implementation.
+ s_totalRewardRecipientFees[payments[i].poolId] += payments[i].amount;
+
+ //tally the total payable fees
+ totalFeeAmount += payments[i].amount;
+ }
+ }
+
+ //transfer the fees to this contract
+ IERC20(i_linkAddress).safeTransferFrom(payer, address(this), totalFeeAmount);
+
+ emit FeePaid(payments, payer);
+ }
+
+ /// @inheritdoc IDestinationRewardManager
+ function claimRewards(bytes32[] memory poolIds) external override {
+ _claimRewards(msg.sender, poolIds);
+ }
+
+ // wrapper impl for claimRewards
+ function _claimRewards(address recipient, bytes32[] memory poolIds) internal returns (uint256) {
+ //get the total amount claimable for this recipient
+ uint256 claimAmount;
+
+ //loop and claim all the rewards in the poolId pot
+ for (uint256 i; i < poolIds.length; ++i) {
+ //get the poolId to be claimed
+ bytes32 poolId = poolIds[i];
+
+ //get the total fees for the pot
+ uint256 totalFeesInPot = s_totalRewardRecipientFees[poolId];
+
+ unchecked {
+ //avoid unnecessary storage reads if there's no fees in the pot
+ if (totalFeesInPot == 0) continue;
+
+ //get the claimable amount for this recipient, this calculation will never exceed the amount in the pot
+ uint256 claimableAmount = totalFeesInPot - s_totalRewardRecipientFeesLastClaimedAmounts[poolId][recipient];
+
+ //calculate the recipients share of the fees, which is their weighted share of the difference between the last amount they claimed and the current amount in the pot. This can never be more than the total amount in existence
+ uint256 recipientShare = (claimableAmount * s_rewardRecipientWeights[poolId][recipient]) / PERCENTAGE_SCALAR;
+
+ //if there's no fees to claim, continue as there's nothing to update
+ if (recipientShare == 0) continue;
+
+ //keep track of the total amount claimable, this can never be more than the total amount in existence
+ claimAmount += recipientShare;
+
+ //set the current total amount of fees in the pot as it's used to calculate future claims
+ s_totalRewardRecipientFeesLastClaimedAmounts[poolId][recipient] = totalFeesInPot;
+
+ //emit event if the recipient has rewards to claim
+ emit RewardsClaimed(poolIds[i], recipient, uint192(recipientShare));
+ }
+ }
+
+ //check if there's any rewards to claim in the given poolId
+ if (claimAmount != 0) {
+ //transfer the reward to the recipient
+ IERC20(i_linkAddress).safeTransfer(recipient, claimAmount);
+ }
+
+ return claimAmount;
+ }
+
+ /// @inheritdoc IDestinationRewardManager
+ function setRewardRecipients(
+ bytes32 poolId,
+ Common.AddressAndWeight[] calldata rewardRecipientAndWeights
+ ) external override onlyOwnerOrFeeManager {
+ //revert if there are no recipients to set
+ if (rewardRecipientAndWeights.length == 0) revert InvalidAddress();
+
+ //check that the weights have not been previously set
+ if (s_rewardRecipientWeightsSet[poolId]) revert InvalidPoolId();
+
+ //keep track of the registered poolIds to make off chain lookups easier
+ s_registeredPoolIds.push(poolId);
+
+ //keep track of which pools have had their reward recipients set
+ s_rewardRecipientWeightsSet[poolId] = true;
+
+ //set the reward recipients, this will only be called once and contain the full set of RewardRecipients with a total weight of 100%
+ _setRewardRecipientWeights(poolId, rewardRecipientAndWeights, PERCENTAGE_SCALAR);
+
+ emit RewardRecipientsUpdated(poolId, rewardRecipientAndWeights);
+ }
+
+ function _setRewardRecipientWeights(
+ bytes32 poolId,
+ Common.AddressAndWeight[] calldata rewardRecipientAndWeights,
+ uint256 expectedWeight
+ ) internal {
+ //we can't update the weights if it contains duplicates
+ if (Common._hasDuplicateAddresses(rewardRecipientAndWeights)) revert InvalidAddress();
+
+ //loop all the reward recipients and validate the weight and address
+ uint256 totalWeight;
+ for (uint256 i; i < rewardRecipientAndWeights.length; ++i) {
+ //get the weight
+ uint256 recipientWeight = rewardRecipientAndWeights[i].weight;
+ //get the address
+ address recipientAddress = rewardRecipientAndWeights[i].addr;
+
+ //ensure the reward recipient address is not zero
+ if (recipientAddress == address(0)) revert InvalidAddress();
+
+ //save/overwrite the weight for the reward recipient
+ s_rewardRecipientWeights[poolId][recipientAddress] = recipientWeight;
+
+ unchecked {
+ //keep track of the cumulative weight, this cannot overflow as the total weight is restricted at 1e18
+ totalWeight += recipientWeight;
+ }
+ }
+
+ //if total weight is not met, the fees will either be under or over distributed
+ if (totalWeight != expectedWeight) revert InvalidWeights();
+ }
+
+ /// @inheritdoc IDestinationRewardManager
+ function updateRewardRecipients(
+ bytes32 poolId,
+ Common.AddressAndWeight[] calldata newRewardRecipients
+ ) external override onlyOwner {
+ //create an array of poolIds to pass to _claimRewards if required
+ bytes32[] memory poolIds = new bytes32[](1);
+ poolIds[0] = poolId;
+
+ //loop all the reward recipients and claim their rewards before updating their weights
+ uint256 existingTotalWeight;
+ for (uint256 i; i < newRewardRecipients.length; ++i) {
+ //get the address
+ address recipientAddress = newRewardRecipients[i].addr;
+ //get the existing weight
+ uint256 existingWeight = s_rewardRecipientWeights[poolId][recipientAddress];
+
+ //if a recipient is updated, the rewards must be claimed first as they can't claim previous fees at the new weight
+ _claimRewards(newRewardRecipients[i].addr, poolIds);
+
+ unchecked {
+ //keep tally of the weights so that the expected collective weight is known
+ existingTotalWeight += existingWeight;
+ }
+ }
+
+ //update the reward recipients, if the new collective weight isn't equal to the previous collective weight, the fees will either be under or over distributed
+ _setRewardRecipientWeights(poolId, newRewardRecipients, existingTotalWeight);
+
+ //emit event
+ emit RewardRecipientsUpdated(poolId, newRewardRecipients);
+ }
+
+ /// @inheritdoc IDestinationRewardManager
+ function payRecipients(bytes32 poolId, address[] calldata recipients) external onlyOwnerOrRecipientInPool(poolId) {
+ //convert poolIds to an array to match the interface of _claimRewards
+ bytes32[] memory poolIdsArray = new bytes32[](1);
+ poolIdsArray[0] = poolId;
+
+ //loop each recipient and claim the rewards for each of the pools and assets
+ for (uint256 i; i < recipients.length; ++i) {
+ _claimRewards(recipients[i], poolIdsArray);
+ }
+ }
+
+ /// @inheritdoc IDestinationRewardManager
+ function addFeeManager(address newFeeManagerAddress) external onlyOwner {
+ if (newFeeManagerAddress == address(0)) revert InvalidAddress();
+ if (s_feeManagerAddressList[newFeeManagerAddress] != address(0)) revert InvalidAddress();
+
+ s_feeManagerAddressList[newFeeManagerAddress] = newFeeManagerAddress;
+
+ emit FeeManagerUpdated(newFeeManagerAddress);
+ }
+
+ /// @inheritdoc IDestinationRewardManager
+ function removeFeeManager(address feeManagerAddress) external onlyOwner {
+ if (s_feeManagerAddressList[feeManagerAddress] == address(0)) revert InvalidAddress();
+ delete s_feeManagerAddressList[feeManagerAddress];
+ }
+
+ /// @inheritdoc IDestinationRewardManager
+ function getAvailableRewardPoolIds(
+ address recipient,
+ uint256 startIndex,
+ uint256 endIndex
+ ) external view returns (bytes32[] memory) {
+ //get the length of the pool ids which we will loop through and potentially return
+ uint256 registeredPoolIdsLength = s_registeredPoolIds.length;
+
+ uint256 lastIndex = endIndex > registeredPoolIdsLength ? registeredPoolIdsLength : endIndex;
+
+ if (startIndex > lastIndex) revert InvalidPoolLength();
+
+ //create a new array with the maximum amount of potential pool ids
+ bytes32[] memory claimablePoolIds = new bytes32[](lastIndex - startIndex);
+ //we want the pools which a recipient has funds for to be sequential, so we need to keep track of the index
+ uint256 poolIdArrayIndex;
+
+ //loop all the pool ids, and check if the recipient has a registered weight and a claimable amount
+ for (uint256 i = startIndex; i < lastIndex; ++i) {
+ //get the poolId
+ bytes32 poolId = s_registeredPoolIds[i];
+
+ //if the recipient has a weight, they are a recipient of this poolId
+ if (s_rewardRecipientWeights[poolId][recipient] != 0) {
+ //get the total in this pool
+ uint256 totalPoolAmount = s_totalRewardRecipientFees[poolId];
+ //if the recipient has any LINK, then add the poolId to the array
+ unchecked {
+ //s_totalRewardRecipientFeesLastClaimedAmounts can never exceed total pool amount, and the number of pools can't exceed the max array length
+ if (totalPoolAmount - s_totalRewardRecipientFeesLastClaimedAmounts[poolId][recipient] != 0) {
+ claimablePoolIds[poolIdArrayIndex++] = poolId;
+ }
+ }
+ }
+ }
+
+ return claimablePoolIds;
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifier.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifier.sol
new file mode 100644
index 00000000000..52b2bd7c9a7
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifier.sol
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
+import {IDestinationVerifier} from "./interfaces/IDestinationVerifier.sol";
+import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../libraries/Common.sol";
+import {IAccessController} from "../../shared/interfaces/IAccessController.sol";
+import {IDestinationVerifierProxy} from "./interfaces/IDestinationVerifierProxy.sol";
+import {IDestinationFeeManager} from "./interfaces/IDestinationFeeManager.sol";
+
+// OCR2 standard
+uint256 constant MAX_NUM_ORACLES = 31;
+
+/**
+ * @title DestinationVerifier
+ * @author Michael Fletcher
+ * @notice This contract will be used to verify reports based on the oracle signatures. This is not the source verifier which required individual fee configurations, instead, this checks that a report has been signed by one of the configured oracles.
+ */
+contract DestinationVerifier is IDestinationVerifier, ConfirmedOwner, TypeAndVersionInterface, IERC165 {
+ /// @notice The list of DON configurations by hash(address|donConfigId) - set to true if the signer is part of the config
+ mapping(bytes32 => bool) private s_signerByAddressAndDonConfigId;
+
+ /// array of DON configs
+ DonConfig[] private s_donConfigs;
+
+ /// @notice The address of the verifierProxy
+ address public s_feeManager;
+
+ /// @notice The address of the access controller
+ address public s_accessController;
+
+ /// @notice The address of the verifierProxy
+ IDestinationVerifierProxy public immutable i_verifierProxy;
+
+ /// @notice This error is thrown whenever trying to set a config
+ /// with a fault tolerance of 0
+ error FaultToleranceMustBePositive();
+
+ /// @notice This error is thrown whenever a report is signed
+ /// with more than the max number of signers
+ /// @param numSigners The number of signers who have signed the report
+ /// @param maxSigners The maximum number of signers that can sign a report
+ error ExcessSigners(uint256 numSigners, uint256 maxSigners);
+
+ /// @notice This error is thrown whenever a report is signed or expected to be signed with less than the minimum number of signers
+ /// @param numSigners The number of signers who have signed the report
+ /// @param minSigners The minimum number of signers that need to sign a report
+ error InsufficientSigners(uint256 numSigners, uint256 minSigners);
+
+ /// @notice This error is thrown whenever a report is submitted with no signatures
+ error NoSigners();
+
+ /// @notice This error is thrown whenever a DonConfig already exists
+ /// @param donConfigId The ID of the DonConfig that already exists
+ error DonConfigAlreadyExists(bytes24 donConfigId);
+
+ /// @notice This error is thrown whenever the R and S signer components
+ /// have different lengths
+ /// @param rsLength The number of r signature components
+ /// @param ssLength The number of s signature components
+ error MismatchedSignatures(uint256 rsLength, uint256 ssLength);
+
+ /// @notice This error is thrown whenever setting a config with duplicate signatures
+ error NonUniqueSignatures();
+
+ /* @notice This error is thrown whenever a report fails to verify. This error be thrown for multiple reasons and it's purposely like
+ * this to prevent information being leaked about the verification process which could be used to enable free verifications maliciously
+ */
+ error BadVerification();
+
+ /// @notice This error is thrown whenever a zero address is passed
+ error ZeroAddress();
+
+ /// @notice This error is thrown when the fee manager at an address does
+ /// not conform to the fee manager interface
+ error FeeManagerInvalid();
+
+ /// @notice This error is thrown whenever an address tries
+ /// to execute a verification that it is not authorized to do so
+ error AccessForbidden();
+
+ /// @notice This error is thrown whenever a config does not exist
+ error DonConfigDoesNotExist();
+
+ /// @notice this error is thrown when the verifierProxy is incorrect when initialising
+ error VerifierProxyInvalid();
+
+ /// @notice This error is thrown when the activation time is either in the future or less than the current configs
+ error BadActivationTime();
+
+ /// @notice This event is emitted when a new report is verified.
+ /// It is used to keep a historical record of verified reports.
+ event ReportVerified(bytes32 indexed feedId, address requester);
+
+ /// @notice This event is emitted whenever a configuration is activated or deactivated
+ event ConfigActivated(bytes24 donConfigId, bool isActive);
+
+ /// @notice This event is emitted whenever a configuration is removed
+ event ConfigRemoved(bytes24 donConfigId);
+
+ /// @notice event is emitted whenever a new DON Config is set
+ event ConfigSet(
+ bytes24 indexed donConfigId,
+ address[] signers,
+ uint8 f,
+ Common.AddressAndWeight[] recipientAddressesAndWeights
+ );
+
+ /// @notice This event is emitted when a new fee manager is set
+ /// @param oldFeeManager The old fee manager address
+ /// @param newFeeManager The new fee manager address
+ event FeeManagerSet(address oldFeeManager, address newFeeManager);
+
+ /// @notice This event is emitted when a new access controller is set
+ /// @param oldAccessController The old access controller address
+ /// @param newAccessController The new access controller address
+ event AccessControllerSet(address oldAccessController, address newAccessController);
+
+ struct DonConfig {
+ // The ID of the DonConfig
+ bytes24 donConfigId;
+ // Fault tolerance of the DON
+ uint8 f;
+ // Whether the config is active
+ bool isActive;
+ // The time the config was set
+ uint32 activationTime;
+ }
+
+ constructor(address verifierProxy) ConfirmedOwner(msg.sender) {
+ if (verifierProxy == address(0)) {
+ revert ZeroAddress();
+ }
+
+ i_verifierProxy = IDestinationVerifierProxy(verifierProxy);
+ }
+
+ /// @inheritdoc IDestinationVerifier
+ function verify(
+ bytes calldata signedReport,
+ bytes calldata parameterPayload,
+ address sender
+ ) external payable override checkValidProxy checkAccess(sender) returns (bytes memory) {
+ (bytes memory verifierResponse, bytes32 donConfigId) = _verify(signedReport, sender);
+
+ address fm = s_feeManager;
+ if (fm != address(0)) {
+ //process the fee and catch the error
+ try IDestinationFeeManager(fm).processFee{value: msg.value}(donConfigId, signedReport, parameterPayload, sender) {
+ //do nothing
+ } catch {
+ // we purposefully obfuscate the error here to prevent information leaking leading to free verifications
+ revert BadVerification();
+ }
+ }
+
+ return verifierResponse;
+ }
+
+ /// @inheritdoc IDestinationVerifier
+ function verifyBulk(
+ bytes[] calldata signedReports,
+ bytes calldata parameterPayload,
+ address sender
+ ) external payable override checkValidProxy checkAccess(sender) returns (bytes[] memory) {
+ bytes[] memory verifierResponses = new bytes[](signedReports.length);
+ bytes32[] memory donConfigs = new bytes32[](signedReports.length);
+
+ for (uint256 i; i < signedReports.length; ++i) {
+ (bytes memory report, bytes32 config) = _verify(signedReports[i], sender);
+ verifierResponses[i] = report;
+ donConfigs[i] = config;
+ }
+
+ address fm = s_feeManager;
+ if (fm != address(0)) {
+ //process the fee and catch the error
+ try
+ IDestinationFeeManager(fm).processFeeBulk{value: msg.value}(donConfigs, signedReports, parameterPayload, sender)
+ {
+ //do nothing
+ } catch {
+ // we purposefully obfuscate the error here to prevent information leaking leading to free verifications
+ revert BadVerification();
+ }
+ }
+
+ return verifierResponses;
+ }
+
+ function _verify(bytes calldata signedReport, address sender) internal returns (bytes memory, bytes32) {
+ (
+ bytes32[3] memory reportContext,
+ bytes memory reportData,
+ bytes32[] memory rs,
+ bytes32[] memory ss,
+ bytes32 rawVs
+ ) = abi.decode(signedReport, (bytes32[3], bytes, bytes32[], bytes32[], bytes32));
+
+ // Signature lengths must match
+ if (rs.length != ss.length) revert MismatchedSignatures(rs.length, ss.length);
+
+ //Must always be at least 1 signer
+ if (rs.length == 0) revert NoSigners();
+
+ // The payload is hashed and signed by the oracles - we need to recover the addresses
+ bytes32 signedPayload = keccak256(abi.encodePacked(keccak256(reportData), reportContext));
+ address[] memory signers = new address[](rs.length);
+ for (uint256 i; i < rs.length; ++i) {
+ signers[i] = ecrecover(signedPayload, uint8(rawVs[i]) + 27, rs[i], ss[i]);
+ }
+
+ // Duplicate signatures are not allowed
+ if (Common._hasDuplicateAddresses(signers)) {
+ revert BadVerification();
+ }
+
+ //We need to know the timestamp the report was generated to lookup the active activeDonConfig
+ uint256 reportTimestamp = _decodeReportTimestamp(reportData);
+
+ // Find the latest config for this report
+ DonConfig memory activeDonConfig = _findActiveConfig(reportTimestamp);
+
+ // Check a config has been set
+ if (activeDonConfig.donConfigId == bytes24(0)) {
+ revert BadVerification();
+ }
+
+ //check the config is active
+ if (!activeDonConfig.isActive) {
+ revert BadVerification();
+ }
+
+ //check we have enough signatures
+ if (signers.length <= activeDonConfig.f) {
+ revert BadVerification();
+ }
+
+ //check each signer is registered against the active DON
+ bytes32 signerDonConfigKey;
+ for (uint256 i; i < signers.length; ++i) {
+ signerDonConfigKey = keccak256(abi.encodePacked(signers[i], activeDonConfig.donConfigId));
+ if (!s_signerByAddressAndDonConfigId[signerDonConfigKey]) {
+ revert BadVerification();
+ }
+ }
+
+ emit ReportVerified(bytes32(reportData), sender);
+
+ return (reportData, activeDonConfig.donConfigId);
+ }
+
+ /// @inheritdoc IDestinationVerifier
+ function setConfigWithActivationTime(
+ address[] memory signers,
+ uint8 f,
+ Common.AddressAndWeight[] memory recipientAddressesAndWeights,
+ uint32 activationTime
+ ) external override checkConfigValid(signers.length, f) onlyOwner {
+ _setConfig(signers, f, recipientAddressesAndWeights, activationTime);
+ }
+
+ /// @inheritdoc IDestinationVerifier
+ function setConfig(
+ address[] memory signers,
+ uint8 f,
+ Common.AddressAndWeight[] memory recipientAddressesAndWeights
+ ) external override checkConfigValid(signers.length, f) onlyOwner {
+ _setConfig(signers, f, recipientAddressesAndWeights, uint32(block.timestamp));
+ }
+
+ function _setConfig(
+ address[] memory signers,
+ uint8 f,
+ Common.AddressAndWeight[] memory recipientAddressesAndWeights,
+ uint32 activationTime
+ ) internal checkConfigValid(signers.length, f) onlyOwner {
+ // Duplicate addresses would break protocol rules
+ if (Common._hasDuplicateAddresses(signers)) {
+ revert NonUniqueSignatures();
+ }
+
+ //activation time cannot be in the future
+ if (activationTime > block.timestamp) {
+ revert BadActivationTime();
+ }
+
+ // Sort signers to ensure donConfigId is deterministic
+ Common._quickSort(signers, 0, int256(signers.length - 1));
+
+ //DonConfig is made up of hash(signers|f)
+ bytes24 donConfigId = bytes24(keccak256(abi.encodePacked(signers, f)));
+
+ // Register the signers for this DON
+ for (uint256 i; i < signers.length; ++i) {
+ if (signers[i] == address(0)) revert ZeroAddress();
+ /** This index is registered so we can efficiently lookup whether a NOP is part of a config without having to
+ loop through the entire config each verification. It's effectively a DonConfig <-> Signer
+ composite key which keys track of all historic configs for a signer */
+ s_signerByAddressAndDonConfigId[keccak256(abi.encodePacked(signers[i], donConfigId))] = true;
+ }
+
+ // Check the activation time is greater than the latest config
+ uint256 donConfigLength = s_donConfigs.length;
+ if (donConfigLength > 0 && s_donConfigs[donConfigLength - 1].activationTime > activationTime) {
+ revert BadActivationTime();
+ }
+
+ // Check the config we're setting isn't already set as the current active config as this will increase search costs unnecessarily when verifying historic reports
+ if (donConfigLength > 0 && s_donConfigs[donConfigLength - 1].donConfigId == donConfigId) {
+ revert DonConfigAlreadyExists(donConfigId);
+ }
+
+ // We may want to register these later or skip this step in the unlikely scenario they've previously been registered in the RewardsManager
+ if (recipientAddressesAndWeights.length != 0) {
+ IDestinationFeeManager(s_feeManager).setFeeRecipients(donConfigId, recipientAddressesAndWeights);
+ }
+
+ // push the DonConfig
+ s_donConfigs.push(DonConfig(donConfigId, f, true, activationTime));
+
+ emit ConfigSet(donConfigId, signers, f, recipientAddressesAndWeights);
+ }
+
+ /// @inheritdoc IDestinationVerifier
+ function setFeeManager(address feeManager) external override onlyOwner {
+ if (
+ !IERC165(feeManager).supportsInterface(IDestinationFeeManager.processFee.selector) ||
+ !IERC165(feeManager).supportsInterface(IDestinationFeeManager.processFeeBulk.selector) ||
+ !IERC165(feeManager).supportsInterface(IDestinationFeeManager.setFeeRecipients.selector)
+ ) revert FeeManagerInvalid();
+
+ address oldFeeManager = s_feeManager;
+ s_feeManager = feeManager;
+
+ emit FeeManagerSet(oldFeeManager, feeManager);
+ }
+
+ /// @inheritdoc IDestinationVerifier
+ function setAccessController(address accessController) external override onlyOwner {
+ address oldAccessController = s_accessController;
+ s_accessController = accessController;
+ emit AccessControllerSet(oldAccessController, accessController);
+ }
+
+ /// @inheritdoc IDestinationVerifier
+ function setConfigActive(uint256 donConfigIndex, bool isActive) external onlyOwner {
+ // Config must exist
+ if (donConfigIndex >= s_donConfigs.length) {
+ revert DonConfigDoesNotExist();
+ }
+
+ // Update the config
+ DonConfig storage config = s_donConfigs[donConfigIndex];
+ config.isActive = isActive;
+
+ emit ConfigActivated(config.donConfigId, isActive);
+ }
+
+ /// @inheritdoc IDestinationVerifier
+ function removeLatestConfig() external onlyOwner {
+ if (s_donConfigs.length == 0) {
+ revert DonConfigDoesNotExist();
+ }
+
+ DonConfig memory config = s_donConfigs[s_donConfigs.length - 1];
+
+ s_donConfigs.pop();
+
+ emit ConfigRemoved(config.donConfigId);
+ }
+
+ function _decodeReportTimestamp(bytes memory reportPayload) internal pure returns (uint256) {
+ (, , uint256 timestamp) = abi.decode(reportPayload, (bytes32, uint32, uint32));
+
+ return timestamp;
+ }
+
+ function _findActiveConfig(uint256 timestamp) internal view returns (DonConfig memory) {
+ DonConfig memory activeDonConfig;
+
+ // 99% of the time the signer config will be the last index, however for historic reports generated by a previous configuration we'll need to cycle back
+ uint256 i = s_donConfigs.length;
+ while (i > 0) {
+ --i;
+ if (s_donConfigs[i].activationTime <= timestamp) {
+ activeDonConfig = s_donConfigs[i];
+ break;
+ }
+ }
+ return activeDonConfig;
+ }
+
+ modifier checkConfigValid(uint256 numSigners, uint256 f) {
+ if (f == 0) revert FaultToleranceMustBePositive();
+ if (numSigners > MAX_NUM_ORACLES) revert ExcessSigners(numSigners, MAX_NUM_ORACLES);
+ if (numSigners <= 3 * f) revert InsufficientSigners(numSigners, 3 * f + 1);
+ _;
+ }
+
+ modifier checkValidProxy() {
+ if (address(i_verifierProxy) != msg.sender) {
+ revert AccessForbidden();
+ }
+ _;
+ }
+
+ modifier checkAccess(address sender) {
+ address ac = s_accessController;
+ if (address(ac) != address(0) && !IAccessController(ac).hasAccess(sender, msg.data)) revert AccessForbidden();
+ _;
+ }
+
+ /// @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
+ return
+ interfaceId == this.verify.selector ||
+ interfaceId == this.verifyBulk.selector ||
+ interfaceId == this.s_accessController.selector ||
+ interfaceId == this.s_feeManager.selector ||
+ interfaceId == this.setConfig.selector ||
+ interfaceId == this.setConfigWithActivationTime.selector ||
+ interfaceId == this.setFeeManager.selector ||
+ interfaceId == this.setAccessController.selector ||
+ interfaceId == this.setConfigActive.selector;
+ }
+
+ /// @inheritdoc TypeAndVersionInterface
+ function typeAndVersion() external pure override returns (string memory) {
+ return "DestinationVerifier 1.0.0";
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifierProxy.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifierProxy.sol
new file mode 100644
index 00000000000..1a5c62b4292
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/DestinationVerifierProxy.sol
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol";
+import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol";
+import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {IDestinationVerifierProxy} from "./interfaces/IDestinationVerifierProxy.sol";
+import {IDestinationVerifier} from "./interfaces/IDestinationVerifier.sol";
+
+/**
+ * @title DestinationVerifierProxy
+ * @author Michael Fletcher
+ * @notice This contract will be used to route all requests through to the assigned verifier contract. This contract does not support individual feed configurations and is aimed at being a simple proxy for the verifier contract on any destination chain.
+ */
+contract DestinationVerifierProxy is IDestinationVerifierProxy, ConfirmedOwner, TypeAndVersionInterface, IERC165 {
+ /// @notice The active verifier for this proxy
+ IDestinationVerifier private s_verifier;
+
+ /// @notice This error is thrown whenever a zero address is passed
+ error ZeroAddress();
+
+ /// @notice This error is thrown when trying to set a verifier address that does not implement the expected interface
+ error VerifierInvalid(address verifierAddress);
+
+ constructor() ConfirmedOwner(msg.sender) {}
+
+ /// @inheritdoc TypeAndVersionInterface
+ function typeAndVersion() external pure override returns (string memory) {
+ return "DestinationVerifierProxy 1.0.0";
+ }
+
+ /// @inheritdoc IDestinationVerifierProxy
+ function verify(bytes calldata payload, bytes calldata parameterPayload) external payable returns (bytes memory) {
+ return s_verifier.verify{value: msg.value}(payload, parameterPayload, msg.sender);
+ }
+
+ /// @inheritdoc IDestinationVerifierProxy
+ function verifyBulk(
+ bytes[] calldata payloads,
+ bytes calldata parameterPayload
+ ) external payable returns (bytes[] memory verifiedReports) {
+ return s_verifier.verifyBulk{value: msg.value}(payloads, parameterPayload, msg.sender);
+ }
+
+ /// @inheritdoc IDestinationVerifierProxy
+ function setVerifier(address verifierAddress) external onlyOwner {
+ //check it supports the functions we need
+ if (
+ !IERC165(verifierAddress).supportsInterface(IDestinationVerifier.s_accessController.selector) ||
+ !IERC165(verifierAddress).supportsInterface(IDestinationVerifier.s_feeManager.selector) ||
+ !IERC165(verifierAddress).supportsInterface(IDestinationVerifier.verify.selector) ||
+ !IERC165(verifierAddress).supportsInterface(IDestinationVerifier.verifyBulk.selector)
+ ) revert VerifierInvalid(verifierAddress);
+
+ s_verifier = IDestinationVerifier(verifierAddress);
+ }
+
+ /// @inheritdoc IDestinationVerifierProxy
+ // solhint-disable-next-line func-name-mixedcase
+ function s_feeManager() external view override returns (address) {
+ return s_verifier.s_feeManager();
+ }
+
+ /// @inheritdoc IDestinationVerifierProxy
+ // solhint-disable-next-line func-name-mixedcase
+ function s_accessController() external view override returns (address) {
+ return s_verifier.s_accessController();
+ }
+
+ /// @inheritdoc IERC165
+ function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
+ return
+ interfaceId == this.setVerifier.selector ||
+ interfaceId == this.verify.selector ||
+ interfaceId == this.verifyBulk.selector ||
+ interfaceId == this.s_feeManager.selector ||
+ interfaceId == this.s_accessController.selector;
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationFeeManager.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationFeeManager.sol
new file mode 100644
index 00000000000..f92e7cd146b
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationFeeManager.sol
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../../libraries/Common.sol";
+
+interface IDestinationFeeManager is IERC165 {
+ /**
+ * @notice Calculate the applied fee and the reward from a report. If the sender is a subscriber, they will receive a discount.
+ * @param subscriber address trying to verify
+ * @param report report to calculate the fee for
+ * @param quoteAddress address of the quote payment token
+ * @return (fee, reward, totalDiscount) fee and the reward data with the discount applied
+ */
+ function getFeeAndReward(
+ address subscriber,
+ bytes memory report,
+ address quoteAddress
+ ) external returns (Common.Asset memory, Common.Asset memory, uint256);
+
+ /**
+ * @notice Sets the native surcharge
+ * @param surcharge surcharge to be paid if paying in native
+ */
+ function setNativeSurcharge(uint64 surcharge) external;
+
+ /**
+ * @notice Adds a subscriber to the fee manager
+ * @param subscriber address of the subscriber
+ * @param feedId feed id to apply the discount to
+ * @param token token to apply the discount to
+ * @param discount discount to be applied to the fee
+ */
+ function updateSubscriberDiscount(address subscriber, bytes32 feedId, address token, uint64 discount) external;
+
+ /**
+ * @notice Withdraws any native or LINK rewards to the owner address
+ * @param assetAddress address of the asset to withdraw
+ * @param recipientAddress address to withdraw to
+ * @param quantity quantity to withdraw
+ */
+ function withdraw(address assetAddress, address recipientAddress, uint192 quantity) external;
+
+ /**
+ * @notice Returns the link balance of the fee manager
+ * @return link balance of the fee manager
+ */
+ function linkAvailableForPayment() external returns (uint256);
+
+ /**
+ * @notice Admin function to pay the LINK deficit for a given config digest
+ * @param configDigest the config digest to pay the deficit for
+ */
+ function payLinkDeficit(bytes32 configDigest) external;
+
+ /**
+ * @notice Adds the verifier to the list of verifiers able to use the feeManager
+ * @param verifier address of the verifier
+ */
+ function addVerifier(address verifier) external;
+
+ /**
+ * @notice Removes the verifier from the list of verifiers able to use the feeManager
+ * @param verifier address of the verifier
+ */
+ function removeVerifier(address verifier) external;
+
+ /**
+ * @notice Sets the reward manager to the address
+ * @param rewardManager address of the reward manager
+ */
+ function setRewardManager(address rewardManager) external;
+
+ /**
+ * @notice Handles fees for a report from the subscriber and manages rewards
+ * @param poolId pool id of the pool to pay into
+ * @param payload report to process the fee for
+ * @param parameterPayload fee payload
+ * @param subscriber address of the fee will be applied
+ */
+ function processFee(
+ bytes32 poolId,
+ bytes calldata payload,
+ bytes calldata parameterPayload,
+ address subscriber
+ ) external payable;
+
+ /**
+ * @notice Processes the fees for each report in the payload, billing the subscriber and paying the reward manager
+ * @param poolIds pool ids of the pool to pay into
+ * @param payloads reports to process
+ * @param parameterPayload fee payload
+ * @param subscriber address of the user to process fee for
+ */
+ function processFeeBulk(
+ bytes32[] memory poolIds,
+ bytes[] calldata payloads,
+ bytes calldata parameterPayload,
+ address subscriber
+ ) external payable;
+
+ /**
+ * @notice Sets the fee recipients according to the fee manager
+ * @param configDigest digest of the configuration
+ * @param rewardRecipientAndWeights the address and weights of all the recipients to receive rewards
+ */
+ function setFeeRecipients(
+ bytes32 configDigest,
+ Common.AddressAndWeight[] calldata rewardRecipientAndWeights
+ ) external;
+
+ /**
+ * @notice The structure to hold a fee and reward to verify a report
+ * @param digest the digest linked to the fee and reward
+ * @param fee the fee paid to verify the report
+ * @param reward the reward paid upon verification
+ & @param appliedDiscount the discount applied to the reward
+ */
+ struct FeeAndReward {
+ bytes32 configDigest;
+ Common.Asset fee;
+ Common.Asset reward;
+ uint256 appliedDiscount;
+ }
+
+ /**
+ * @notice The structure to hold quote metadata
+ * @param quoteAddress the address of the quote
+ */
+ struct Quote {
+ address quoteAddress;
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationRewardManager.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationRewardManager.sol
new file mode 100644
index 00000000000..95f07937aec
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationRewardManager.sol
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+import {IERC165} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {Common} from "../../libraries/Common.sol";
+
+interface IDestinationRewardManager is IERC165 {
+ /**
+ * @notice Record the fee received for a particular pool
+ * @param payments array of structs containing pool id and amount
+ * @param payee the user the funds should be retrieved from
+ */
+ function onFeePaid(FeePayment[] calldata payments, address payee) external;
+
+ /**
+ * @notice Claims the rewards in a specific pool
+ * @param poolIds array of poolIds to claim rewards for
+ */
+ function claimRewards(bytes32[] calldata poolIds) external;
+
+ /**
+ * @notice Set the RewardRecipients and weights for a specific pool. This should only be called once per pool Id. Else updateRewardRecipients should be used.
+ * @param poolId poolId to set RewardRecipients and weights for
+ * @param rewardRecipientAndWeights array of each RewardRecipient and associated weight
+ */
+ function setRewardRecipients(bytes32 poolId, Common.AddressAndWeight[] calldata rewardRecipientAndWeights) external;
+
+ /**
+ * @notice Updates a subset the reward recipients for a specific poolId. The collective weight of the recipients should add up to the recipients existing weights. Any recipients with a weight of 0 will be removed.
+ * @param poolId the poolId to update
+ * @param newRewardRecipients array of new reward recipients
+ */
+ function updateRewardRecipients(bytes32 poolId, Common.AddressAndWeight[] calldata newRewardRecipients) external;
+
+ /**
+ * @notice Pays all the recipients for each of the pool ids
+ * @param poolId the pool id to pay recipients for
+ * @param recipients array of recipients to pay within the pool
+ */
+ function payRecipients(bytes32 poolId, address[] calldata recipients) external;
+
+ /**
+ * @notice Add the fee manager to the list of feeManagers able to call the reward manager
+ * @param newFeeManager address of the new verifier proxy
+ */
+ function addFeeManager(address newFeeManager) external;
+
+ /**
+ * @notice Removes the fee manager. This needs to be done post construction to prevent a circular dependency.
+ * @param feeManager address of the verifier proxy to remove
+ */
+ function removeFeeManager(address feeManager) external;
+
+ /**
+ * @notice Gets a list of pool ids which have reward for a specific recipient.
+ * @param recipient address of the recipient to get pool ids for
+ * @param startIndex the index to start from
+ * @param endIndex the index to stop at
+ */
+ function getAvailableRewardPoolIds(
+ address recipient,
+ uint256 startIndex,
+ uint256 endIndex
+ ) external view returns (bytes32[] memory);
+
+ /**
+ * @notice The structure to hold a fee payment notice
+ * @param poolId the poolId receiving the payment
+ * @param amount the amount being paid
+ */
+ struct FeePayment {
+ bytes32 poolId;
+ uint192 amount;
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationVerifier.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationVerifier.sol
new file mode 100644
index 00000000000..69516f6e924
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationVerifier.sol
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+import {Common} from "../../libraries/Common.sol";
+
+interface IDestinationVerifier {
+ /**
+ * @notice Verifies that the data encoded has been signed correctly using the signatures included within the payload.
+ * @param signedReport The encoded data to be verified.
+ * @param parameterPayload The encoded parameters to be used in the verification and billing process.
+ * @param sender The address that requested to verify the contract.Used for logging and applying the fee.
+ * @dev Verification is typically only done through the proxy contract so we can't just use msg.sender.
+ * @return verifierResponse The encoded verified response.
+ */
+ function verify(
+ bytes calldata signedReport,
+ bytes calldata parameterPayload,
+ address sender
+ ) external payable returns (bytes memory verifierResponse);
+
+ /**
+ * @notice Bulk verifies that the data encoded has been signed correctly using the signatures included within the payload.
+ * @param signedReports The encoded data to be verified.
+ * @param parameterPayload The encoded parameters to be used in the verification and billing process.
+ * @param sender The address that requested to verify the contract. Used for logging and applying the fee.
+ * @dev Verification is typically only done through the proxy contract so we can't just use msg.sender.
+ * @return verifiedReports The encoded verified responses.
+ */
+ function verifyBulk(
+ bytes[] calldata signedReports,
+ bytes calldata parameterPayload,
+ address sender
+ ) external payable returns (bytes[] memory verifiedReports);
+
+ /**
+ * @notice sets off-chain reporting protocol configuration incl. participating oracles
+ * @param signers addresses with which oracles sign the reports
+ * @param f number of faulty oracles the system can tolerate
+ * @param recipientAddressesAndWeights the addresses and weights of all the recipients to receive rewards
+ */
+ function setConfig(
+ address[] memory signers,
+ uint8 f,
+ Common.AddressAndWeight[] memory recipientAddressesAndWeights
+ ) external;
+
+ /**
+ * @notice sets off-chain reporting protocol configuration incl. participating oracles
+ * @param signers addresses with which oracles sign the reports
+ * @param f number of faulty oracles the system can tolerate
+ * @param recipientAddressesAndWeights the addresses and weights of all the recipients to receive rewards
+ * @param activationTime the time at which the config was activated
+ */
+ function setConfigWithActivationTime(
+ address[] memory signers,
+ uint8 f,
+ Common.AddressAndWeight[] memory recipientAddressesAndWeights,
+ uint32 activationTime
+ ) external;
+
+ /**
+ * @notice Sets the fee manager address
+ * @param feeManager The address of the fee manager
+ */
+ function setFeeManager(address feeManager) external;
+
+ /**
+ * @notice Sets the access controller address
+ * @param accessController The address of the access controller
+ */
+ function setAccessController(address accessController) external;
+
+ /**
+ * @notice Updates the config active status
+ * @param donConfigId The ID of the config to update
+ * @param isActive The new config active status
+ */
+ function setConfigActive(uint256 donConfigId, bool isActive) external;
+
+ /**
+ * @notice Removes the latest config
+ */
+ function removeLatestConfig() external;
+
+ /*
+ * @notice Returns the reward manager
+ * @return IDestinationRewardManager
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function s_feeManager() external view returns (address);
+
+ /**
+ * @notice Returns the access controller
+ * @return IDestinationFeeManager
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function s_accessController() external view returns (address);
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationVerifierProxy.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationVerifierProxy.sol
new file mode 100644
index 00000000000..a88349b3014
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/interfaces/IDestinationVerifierProxy.sol
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+interface IDestinationVerifierProxy {
+ /**
+ * @notice Verifies that the data encoded has been signed
+ * correctly by routing to the verifier, and bills the user if applicable.
+ * @param payload The encoded data to be verified, including the signed
+ * report.
+ * @param parameterPayload fee metadata for billing
+ * @return verifierResponse The encoded report from the verifier.
+ */
+ function verify(
+ bytes calldata payload,
+ bytes calldata parameterPayload
+ ) external payable returns (bytes memory verifierResponse);
+
+ /**
+ * @notice Bulk verifies that the data encoded has been signed
+ * correctly by routing to the correct verifier, and bills the user if applicable.
+ * @param payloads The encoded payloads to be verified, including the signed
+ * report.
+ * @param parameterPayload fee metadata for billing
+ * @return verifiedReports The encoded reports from the verifier.
+ */
+ function verifyBulk(
+ bytes[] calldata payloads,
+ bytes calldata parameterPayload
+ ) external payable returns (bytes[] memory verifiedReports);
+
+ /**
+ * @notice Sets the active verifier for this proxy
+ * @param verifierAddress The address of the verifier contract
+ */
+ function setVerifier(address verifierAddress) external;
+
+ /**
+ * @notice Used to honor the source verifierProxy feeManager interface
+ * @return IVerifierFeeManager
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function s_feeManager() external view returns (address);
+
+ /**
+ * @notice Used to honor the source verifierProxy feeManager interface
+ * @return AccessControllerInterface
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function s_accessController() external view returns (address);
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/BaseDestinationFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/BaseDestinationFeeManager.t.sol
new file mode 100644
index 00000000000..8b70e5b2b33
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/BaseDestinationFeeManager.t.sol
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {Test} from "forge-std/Test.sol";
+import {DestinationFeeManager} from "../../DestinationFeeManager.sol";
+import {DestinationRewardManager} from "../../DestinationRewardManager.sol";
+import {Common} from "../../../libraries/Common.sol";
+import {ERC20Mock} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
+import {WERC20Mock} from "../../../../shared/mocks/WERC20Mock.sol";
+import {IDestinationRewardManager} from "../../interfaces/IDestinationRewardManager.sol";
+import {DestinationFeeManagerProxy} from "../mocks/DestinationFeeManagerProxy.sol";
+
+/**
+ * @title BaseDestinationFeeManagerTest
+ * @author Michael Fletcher
+ * @notice Base class for all feeManager tests
+ * @dev This contract is intended to be inherited from and not used directly. It contains functionality to setup the feeManager
+ */
+contract BaseDestinationFeeManagerTest is Test {
+ //contracts
+ DestinationFeeManager internal feeManager;
+ DestinationRewardManager internal rewardManager;
+ DestinationFeeManagerProxy internal feeManagerProxy;
+
+ ERC20Mock internal link;
+ WERC20Mock internal native;
+
+ //erc20 config
+ uint256 internal constant DEFAULT_LINK_MINT_QUANTITY = 100 ether;
+ uint256 internal constant DEFAULT_NATIVE_MINT_QUANTITY = 100 ether;
+
+ //contract owner
+ address internal constant INVALID_ADDRESS = address(0);
+ address internal constant ADMIN = address(uint160(uint256(keccak256("ADMIN"))));
+ address internal constant USER = address(uint160(uint256(keccak256("USER"))));
+ address internal constant PROXY = address(uint160(uint256(keccak256("PROXY"))));
+
+ //version masks
+ bytes32 internal constant V_MASK = 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
+ bytes32 internal constant V1_BITMASK = 0x0001000000000000000000000000000000000000000000000000000000000000;
+ bytes32 internal constant V2_BITMASK = 0x0002000000000000000000000000000000000000000000000000000000000000;
+ bytes32 internal constant V3_BITMASK = 0x0003000000000000000000000000000000000000000000000000000000000000;
+
+ //feed ids & config digests
+ bytes32 internal constant DEFAULT_FEED_1_V1 = (keccak256("ETH-USD") & V_MASK) | V1_BITMASK;
+ bytes32 internal constant DEFAULT_FEED_1_V2 = (keccak256("ETH-USD") & V_MASK) | V2_BITMASK;
+ bytes32 internal constant DEFAULT_FEED_1_V3 = (keccak256("ETH-USD") & V_MASK) | V3_BITMASK;
+
+ bytes32 internal constant DEFAULT_FEED_2_V3 = (keccak256("LINK-USD") & V_MASK) | V3_BITMASK;
+ bytes32 internal constant DEFAULT_CONFIG_DIGEST = keccak256("DEFAULT_CONFIG_DIGEST");
+ bytes32 internal constant DEFAULT_CONFIG_DIGEST2 = keccak256("DEFAULT_CONFIG_DIGEST2");
+
+ //report
+ uint256 internal constant DEFAULT_REPORT_LINK_FEE = 1e10;
+ uint256 internal constant DEFAULT_REPORT_NATIVE_FEE = 1e12;
+
+ //rewards
+ uint64 internal constant FEE_SCALAR = 1e18;
+
+ address internal constant NATIVE_WITHDRAW_ADDRESS = address(0);
+
+ //the selector for each error
+ bytes4 internal immutable INVALID_DISCOUNT_ERROR = DestinationFeeManager.InvalidDiscount.selector;
+ bytes4 internal immutable INVALID_ADDRESS_ERROR = DestinationFeeManager.InvalidAddress.selector;
+ bytes4 internal immutable INVALID_SURCHARGE_ERROR = DestinationFeeManager.InvalidSurcharge.selector;
+ bytes4 internal immutable EXPIRED_REPORT_ERROR = DestinationFeeManager.ExpiredReport.selector;
+ bytes4 internal immutable INVALID_DEPOSIT_ERROR = DestinationFeeManager.InvalidDeposit.selector;
+ bytes4 internal immutable INVALID_QUOTE_ERROR = DestinationFeeManager.InvalidQuote.selector;
+ bytes4 internal immutable UNAUTHORIZED_ERROR = DestinationFeeManager.Unauthorized.selector;
+ bytes4 internal immutable POOLID_MISMATCH_ERROR = DestinationFeeManager.PoolIdMismatch.selector;
+ bytes internal constant ONLY_CALLABLE_BY_OWNER_ERROR = "Only callable by owner";
+ bytes internal constant INSUFFICIENT_ALLOWANCE_ERROR = "ERC20: insufficient allowance";
+ bytes4 internal immutable ZERO_DEFICIT = DestinationFeeManager.ZeroDeficit.selector;
+
+ //events emitted
+ event SubscriberDiscountUpdated(address indexed subscriber, bytes32 indexed feedId, address token, uint64 discount);
+ event NativeSurchargeUpdated(uint64 newSurcharge);
+ event InsufficientLink(IDestinationRewardManager.FeePayment[] feesAndRewards);
+ event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity);
+ event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity);
+ event DiscountApplied(
+ bytes32 indexed configDigest,
+ address indexed subscriber,
+ Common.Asset fee,
+ Common.Asset reward,
+ uint256 appliedDiscountQuantity
+ );
+
+ function setUp() public virtual {
+ //change to admin user
+ vm.startPrank(ADMIN);
+
+ //init required contracts
+ _initializeContracts();
+ }
+
+ function _initializeContracts() internal {
+ link = new ERC20Mock("LINK", "LINK", ADMIN, 0);
+ native = new WERC20Mock();
+
+ feeManagerProxy = new DestinationFeeManagerProxy();
+ rewardManager = new DestinationRewardManager(address(link));
+ feeManager = new DestinationFeeManager(
+ address(link),
+ address(native),
+ address(feeManagerProxy),
+ address(rewardManager)
+ );
+
+ //link the feeManager to the proxy
+ feeManagerProxy.setDestinationFeeManager(feeManager);
+
+ //link the feeManager to the reward manager
+ rewardManager.addFeeManager(address(feeManager));
+
+ //mint some tokens to the admin
+ link.mint(ADMIN, DEFAULT_LINK_MINT_QUANTITY);
+ native.mint(ADMIN, DEFAULT_NATIVE_MINT_QUANTITY);
+ vm.deal(ADMIN, DEFAULT_NATIVE_MINT_QUANTITY);
+
+ //mint some tokens to the user
+ link.mint(USER, DEFAULT_LINK_MINT_QUANTITY);
+ native.mint(USER, DEFAULT_NATIVE_MINT_QUANTITY);
+ vm.deal(USER, DEFAULT_NATIVE_MINT_QUANTITY);
+
+ //mint some tokens to the proxy
+ link.mint(PROXY, DEFAULT_LINK_MINT_QUANTITY);
+ native.mint(PROXY, DEFAULT_NATIVE_MINT_QUANTITY);
+ vm.deal(PROXY, DEFAULT_NATIVE_MINT_QUANTITY);
+ }
+
+ function setSubscriberDiscount(
+ address subscriber,
+ bytes32 feedId,
+ address token,
+ uint256 discount,
+ address sender
+ ) internal {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //set the discount
+ feeManager.updateSubscriberDiscount(subscriber, feedId, token, uint64(discount));
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function setNativeSurcharge(uint256 surcharge, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //set the surcharge
+ feeManager.setNativeSurcharge(uint64(surcharge));
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ // solium-disable-next-line no-unused-vars
+ function getFee(bytes memory report, address quote, address subscriber) public view returns (Common.Asset memory) {
+ //get the fee
+ (Common.Asset memory fee, , ) = feeManager.getFeeAndReward(subscriber, report, quote);
+
+ return fee;
+ }
+
+ function getReward(bytes memory report, address quote, address subscriber) public view returns (Common.Asset memory) {
+ //get the reward
+ (, Common.Asset memory reward, ) = feeManager.getFeeAndReward(subscriber, report, quote);
+
+ return reward;
+ }
+
+ function getAppliedDiscount(bytes memory report, address quote, address subscriber) public view returns (uint256) {
+ //get the reward
+ (, , uint256 appliedDiscount) = feeManager.getFeeAndReward(subscriber, report, quote);
+
+ return appliedDiscount;
+ }
+
+ function getV1Report(bytes32 feedId) public pure returns (bytes memory) {
+ return abi.encode(feedId, uint32(0), int192(0), int192(0), int192(0), uint64(0), bytes32(0), uint64(0), uint64(0));
+ }
+
+ function getV2Report(bytes32 feedId) public view returns (bytes memory) {
+ return
+ abi.encode(
+ feedId,
+ uint32(0),
+ uint32(0),
+ uint192(DEFAULT_REPORT_NATIVE_FEE),
+ uint192(DEFAULT_REPORT_LINK_FEE),
+ uint32(block.timestamp),
+ int192(0)
+ );
+ }
+
+ function getV3Report(bytes32 feedId) public view returns (bytes memory) {
+ return
+ abi.encode(
+ feedId,
+ uint32(0),
+ uint32(0),
+ uint192(DEFAULT_REPORT_NATIVE_FEE),
+ uint192(DEFAULT_REPORT_LINK_FEE),
+ uint32(block.timestamp),
+ int192(0),
+ int192(0),
+ int192(0)
+ );
+ }
+
+ function getV3ReportWithCustomExpiryAndFee(
+ bytes32 feedId,
+ uint256 expiry,
+ uint256 linkFee,
+ uint256 nativeFee
+ ) public pure returns (bytes memory) {
+ return
+ abi.encode(
+ feedId,
+ uint32(0),
+ uint32(0),
+ uint192(nativeFee),
+ uint192(linkFee),
+ uint32(expiry),
+ int192(0),
+ int192(0),
+ int192(0)
+ );
+ }
+
+ function getLinkQuote() public view returns (address) {
+ return address(link);
+ }
+
+ function getNativeQuote() public view returns (address) {
+ return address(native);
+ }
+
+ function withdraw(address assetAddress, address recipient, uint256 amount, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //set the surcharge
+ feeManager.withdraw(assetAddress, recipient, uint192(amount));
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function getLinkBalance(address balanceAddress) public view returns (uint256) {
+ return link.balanceOf(balanceAddress);
+ }
+
+ function getNativeBalance(address balanceAddress) public view returns (uint256) {
+ return native.balanceOf(balanceAddress);
+ }
+
+ function getNativeUnwrappedBalance(address balanceAddress) public view returns (uint256) {
+ return balanceAddress.balance;
+ }
+
+ function mintLink(address recipient, uint256 amount) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(ADMIN);
+
+ //mint the link to the recipient
+ link.mint(recipient, amount);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function mintNative(address recipient, uint256 amount, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //mint the native to the recipient
+ native.mint(recipient, amount);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function issueUnwrappedNative(address recipient, uint256 quantity) public {
+ vm.deal(recipient, quantity);
+ }
+
+ function ProcessFeeAsUser(
+ bytes32 poolId,
+ bytes memory payload,
+ address subscriber,
+ address tokenAddress,
+ uint256 wrappedNativeValue,
+ address sender
+ ) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //process the fee
+ feeManager.processFee{value: wrappedNativeValue}(poolId, payload, abi.encode(tokenAddress), subscriber);
+
+ //change ProcessFeeAsUserback to the original address
+ changePrank(originalAddr);
+ }
+
+ function processFee(
+ bytes32 poolId,
+ bytes memory payload,
+ address subscriber,
+ address feeAddress,
+ uint256 wrappedNativeValue
+ ) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(subscriber);
+
+ //process the fee
+ feeManagerProxy.processFee{value: wrappedNativeValue}(poolId, payload, abi.encode(feeAddress));
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function processFee(
+ bytes32[] memory poolIds,
+ bytes[] memory payloads,
+ address subscriber,
+ address feeAddress,
+ uint256 wrappedNativeValue
+ ) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(subscriber);
+
+ //process the fee
+ feeManagerProxy.processFeeBulk{value: wrappedNativeValue}(poolIds, payloads, abi.encode(feeAddress));
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function getPayload(bytes memory reportPayload) public pure returns (bytes memory) {
+ return abi.encode([DEFAULT_CONFIG_DIGEST, 0, 0], reportPayload, new bytes32[](1), new bytes32[](1), bytes32(""));
+ }
+
+ function approveLink(address spender, uint256 quantity, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //approve the link to be transferred
+ link.approve(spender, quantity);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function approveNative(address spender, uint256 quantity, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //approve the link to be transferred
+ native.approve(spender, quantity);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function payLinkDeficit(bytes32 configDigest, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //approve the link to be transferred
+ feeManager.payLinkDeficit(configDigest);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function getLinkDeficit(bytes32 configDigest) public view returns (uint256) {
+ return feeManager.s_linkDeficit(configDigest);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.general.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.general.t.sol
new file mode 100644
index 00000000000..305125c3329
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.general.t.sol
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import "./BaseDestinationFeeManager.t.sol";
+
+/**
+ * @title BaseDestinationFeeManagerTest
+ * @author Michael Fletcher
+ * @notice This contract will test the setup functionality of the feemanager
+ */
+contract DestinationFeeManagerProcessFeeTest is BaseDestinationFeeManagerTest {
+ function setUp() public override {
+ super.setUp();
+ }
+
+ function test_WithdrawERC20() public {
+ //simulate a fee
+ mintLink(address(feeManager), DEFAULT_LINK_MINT_QUANTITY);
+
+ //get the balances to ne used for comparison
+ uint256 contractBalance = getLinkBalance(address(feeManager));
+ uint256 adminBalance = getLinkBalance(ADMIN);
+
+ //the amount to withdraw
+ uint256 withdrawAmount = contractBalance / 2;
+
+ //withdraw some balance
+ withdraw(address(link), ADMIN, withdrawAmount, ADMIN);
+
+ //check the balance has been reduced
+ uint256 newContractBalance = getLinkBalance(address(feeManager));
+ uint256 newAdminBalance = getLinkBalance(ADMIN);
+
+ //check the balance is greater than zero
+ assertGt(newContractBalance, 0);
+ //check the balance has been reduced by the correct amount
+ assertEq(newContractBalance, contractBalance - withdrawAmount);
+ //check the admin balance has increased by the correct amount
+ assertEq(newAdminBalance, adminBalance + withdrawAmount);
+ }
+
+ function test_WithdrawUnwrappedNative() public {
+ //issue funds straight to the contract to bypass the lack of fallback function
+ issueUnwrappedNative(address(feeManager), DEFAULT_NATIVE_MINT_QUANTITY);
+
+ //get the balances to be used for comparison
+ uint256 contractBalance = getNativeUnwrappedBalance(address(feeManager));
+ uint256 adminBalance = getNativeUnwrappedBalance(ADMIN);
+
+ //the amount to withdraw
+ uint256 withdrawAmount = contractBalance / 2;
+
+ //withdraw some balance
+ withdraw(NATIVE_WITHDRAW_ADDRESS, ADMIN, withdrawAmount, ADMIN);
+
+ //check the balance has been reduced
+ uint256 newContractBalance = getNativeUnwrappedBalance(address(feeManager));
+ uint256 newAdminBalance = getNativeUnwrappedBalance(ADMIN);
+
+ //check the balance is greater than zero
+ assertGt(newContractBalance, 0);
+ //check the balance has been reduced by the correct amount
+ assertEq(newContractBalance, contractBalance - withdrawAmount);
+ //check the admin balance has increased by the correct amount
+ assertEq(newAdminBalance, adminBalance + withdrawAmount);
+ }
+
+ function test_WithdrawNonAdminAddr() public {
+ //simulate a fee
+ mintLink(address(feeManager), DEFAULT_LINK_MINT_QUANTITY);
+
+ //should revert if not admin
+ vm.expectRevert(ONLY_CALLABLE_BY_OWNER_ERROR);
+
+ //withdraw some balance
+ withdraw(address(link), ADMIN, DEFAULT_LINK_MINT_QUANTITY, USER);
+ }
+
+ function test_eventIsEmittedAfterSurchargeIsSet() public {
+ //native surcharge
+ uint64 nativeSurcharge = FEE_SCALAR / 5;
+
+ //expect an emit
+ vm.expectEmit();
+
+ //emit the event that is expected to be emitted
+ emit NativeSurchargeUpdated(nativeSurcharge);
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+ }
+
+ function test_subscriberDiscountEventIsEmittedOnUpdate() public {
+ //native surcharge
+ uint64 discount = FEE_SCALAR / 3;
+
+ //an event should be emitted
+ vm.expectEmit();
+
+ //emit the event that is expected to be emitted
+ emit SubscriberDiscountUpdated(USER, DEFAULT_FEED_1_V3, address(native), discount);
+
+ //set the surcharge
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), discount, ADMIN);
+ }
+
+ function test_eventIsEmittedUponWithdraw() public {
+ //simulate a fee
+ mintLink(address(feeManager), DEFAULT_LINK_MINT_QUANTITY);
+
+ //the amount to withdraw
+ uint192 withdrawAmount = 1;
+
+ //expect an emit
+ vm.expectEmit();
+
+ //the event to be emitted
+ emit Withdraw(ADMIN, ADMIN, address(link), withdrawAmount);
+
+ //withdraw some balance
+ withdraw(address(link), ADMIN, withdrawAmount, ADMIN);
+ }
+
+ function test_linkAvailableForPaymentReturnsLinkBalance() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //check there's a balance
+ assertGt(getLinkBalance(address(feeManager)), 0);
+
+ //check the link available for payment is the link balance
+ assertEq(feeManager.linkAvailableForPayment(), getLinkBalance(address(feeManager)));
+ }
+
+ function test_payLinkDeficit() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV2Report(DEFAULT_FEED_1_V3));
+
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER);
+
+ //not enough funds in the reward pool should trigger an insufficient link event
+ vm.expectEmit();
+
+ IDestinationRewardManager.FeePayment[] memory contractFees = new IDestinationRewardManager.FeePayment[](1);
+ contractFees[0] = IDestinationRewardManager.FeePayment(DEFAULT_CONFIG_DIGEST, uint192(DEFAULT_REPORT_LINK_FEE));
+
+ emit InsufficientLink(contractFees);
+
+ //process the fee
+ processFee(contractFees[0].poolId, payload, USER, address(native), 0);
+
+ //double check the rewardManager balance is 0
+ assertEq(getLinkBalance(address(rewardManager)), 0);
+
+ //simulate a deposit of link to cover the deficit
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ vm.expectEmit();
+ emit LinkDeficitCleared(DEFAULT_CONFIG_DIGEST, DEFAULT_REPORT_LINK_FEE);
+
+ //pay the deficit which will transfer link from the rewardManager to the rewardManager
+ payLinkDeficit(DEFAULT_CONFIG_DIGEST, ADMIN);
+
+ //check the rewardManager received the link
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_payLinkDeficitTwice() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV2Report(DEFAULT_FEED_1_V3));
+
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER);
+
+ //not enough funds in the reward pool should trigger an insufficient link event
+ vm.expectEmit();
+
+ IDestinationRewardManager.FeePayment[] memory contractFees = new IDestinationRewardManager.FeePayment[](1);
+ contractFees[0] = IDestinationRewardManager.FeePayment(DEFAULT_CONFIG_DIGEST, uint192(DEFAULT_REPORT_LINK_FEE));
+
+ //emit the event that is expected to be emitted
+ emit InsufficientLink(contractFees);
+
+ //process the fee
+ processFee(contractFees[0].poolId, payload, USER, address(native), 0);
+
+ //double check the rewardManager balance is 0
+ assertEq(getLinkBalance(address(rewardManager)), 0);
+
+ //simulate a deposit of link to cover the deficit
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ vm.expectEmit();
+ emit LinkDeficitCleared(DEFAULT_CONFIG_DIGEST, DEFAULT_REPORT_LINK_FEE);
+
+ //pay the deficit which will transfer link from the rewardManager to the rewardManager
+ payLinkDeficit(DEFAULT_CONFIG_DIGEST, ADMIN);
+
+ //check the rewardManager received the link
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //paying again should revert with 0
+ vm.expectRevert(ZERO_DEFICIT);
+
+ payLinkDeficit(DEFAULT_CONFIG_DIGEST, ADMIN);
+ }
+
+ function test_payLinkDeficitPaysAllFeesProcessed() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV2Report(DEFAULT_FEED_1_V3));
+
+ //approve the native to be transferred from the user
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE * 2, USER);
+
+ //processing the fee will transfer the native from the user to the feeManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), 0);
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), 0);
+
+ //check the deficit has been increased twice
+ assertEq(getLinkDeficit(DEFAULT_CONFIG_DIGEST), DEFAULT_REPORT_LINK_FEE * 2);
+
+ //double check the rewardManager balance is 0
+ assertEq(getLinkBalance(address(rewardManager)), 0);
+
+ //simulate a deposit of link to cover the deficit
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE * 2);
+
+ vm.expectEmit();
+ emit LinkDeficitCleared(DEFAULT_CONFIG_DIGEST, DEFAULT_REPORT_LINK_FEE * 2);
+
+ //pay the deficit which will transfer link from the rewardManager to the rewardManager
+ payLinkDeficit(DEFAULT_CONFIG_DIGEST, ADMIN);
+
+ //check the rewardManager received the link
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE * 2);
+ }
+
+ function test_payLinkDeficitOnlyCallableByAdmin() public {
+ vm.expectRevert(ONLY_CALLABLE_BY_OWNER_ERROR);
+
+ payLinkDeficit(DEFAULT_CONFIG_DIGEST, USER);
+ }
+
+ function test_revertOnSettingAnAddressZeroVerifier() public {
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+ feeManager.addVerifier(address(0));
+ }
+
+ function test_onlyCallableByOwnerReverts() public {
+ address STRANGER = address(999);
+ changePrank(STRANGER);
+ vm.expectRevert(bytes("Only callable by owner"));
+ feeManager.addVerifier(address(0));
+ }
+
+ function test_addVerifierExistingAddress() public {
+ address dummyAddress = address(998);
+ feeManager.addVerifier(dummyAddress);
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+ feeManager.addVerifier(dummyAddress);
+ }
+
+ function test_addVerifier() public {
+ address dummyAddress = address(998);
+ feeManager.addVerifier(dummyAddress);
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+ feeManager.addVerifier(dummyAddress);
+
+ // check calls to setFeeRecipients it should not error unauthorized
+ changePrank(dummyAddress);
+ bytes32 dummyConfigDigest = 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef;
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](1);
+ recipients[0] = Common.AddressAndWeight(address(991), 1e18);
+ feeManager.setFeeRecipients(dummyConfigDigest, recipients);
+
+ // removing this verifier should result in unauthorized when calling setFeeRecipients
+ changePrank(ADMIN);
+ feeManager.removeVerifier(dummyAddress);
+ changePrank(dummyAddress);
+ vm.expectRevert(UNAUTHORIZED_ERROR);
+ feeManager.setFeeRecipients(dummyConfigDigest, recipients);
+ }
+
+ function test_removeVerifierZeroAaddress() public {
+ address dummyAddress = address(0);
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+ feeManager.removeVerifier(dummyAddress);
+ }
+
+ function test_removeVerifierNonExistentAddress() public {
+ address dummyAddress = address(991);
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+ feeManager.removeVerifier(dummyAddress);
+ }
+
+ function test_setRewardManagerZeroAddress() public {
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+ feeManager.setRewardManager(address(0));
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.getFeeAndReward.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.getFeeAndReward.t.sol
new file mode 100644
index 00000000000..30be694df2c
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.getFeeAndReward.t.sol
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {Common} from "../../../libraries/Common.sol";
+import "./BaseDestinationFeeManager.t.sol";
+
+/**
+ * @title BaseFeeManagerTest
+ * @author Michael Fletcher
+ * @notice This contract will test the functionality of the feeManager's getFeeAndReward
+ */
+contract DestinationFeeManagerProcessFeeTest is BaseDestinationFeeManagerTest {
+ function test_baseFeeIsAppliedForNative() public view {
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be the default
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_baseFeeIsAppliedForLink() public view {
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //fee should be the default
+ assertEq(fee.amount, DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_discountAIsNotAppliedWhenSetForOtherUsers() public {
+ //set the subscriber discount for another user
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), INVALID_ADDRESS);
+
+ //fee should be the default
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_discountIsNotAppliedForInvalidTokenAddress() public {
+ //should revert with invalid address as it's not a configured token
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+
+ //set the subscriber discount for another user
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, INVALID_ADDRESS, FEE_SCALAR / 2, ADMIN);
+ }
+
+ function test_discountIsAppliedForLink() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //fee should be half the default
+ assertEq(fee.amount, DEFAULT_REPORT_LINK_FEE / 2);
+ }
+
+ function test_DiscountIsAppliedForNative() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be half the default
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE / 2);
+ }
+
+ function test_discountIsNoLongerAppliedAfterRemoving() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //fee should be half the default
+ assertEq(fee.amount, DEFAULT_REPORT_LINK_FEE / 2);
+
+ //remove the discount
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), 0, ADMIN);
+
+ //get the fee required by the feeManager
+ fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //fee should be the default
+ assertEq(fee.amount, DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_surchargeIsApplied() public {
+ //native surcharge
+ uint256 nativeSurcharge = FEE_SCALAR / 5;
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected surcharge
+ uint256 expectedSurcharge = ((DEFAULT_REPORT_NATIVE_FEE * nativeSurcharge) / FEE_SCALAR);
+
+ //expected fee should the base fee offset by the surcharge and discount
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE + expectedSurcharge);
+ }
+
+ function test_surchargeIsNotAppliedForLinkFee() public {
+ //native surcharge
+ uint256 nativeSurcharge = FEE_SCALAR / 5;
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //fee should be the default
+ assertEq(fee.amount, DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_surchargeIsNoLongerAppliedAfterRemoving() public {
+ //native surcharge
+ uint256 nativeSurcharge = FEE_SCALAR / 5;
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected surcharge
+ uint256 expectedSurcharge = ((DEFAULT_REPORT_NATIVE_FEE * nativeSurcharge) / FEE_SCALAR);
+
+ //expected fee should be the base fee offset by the surcharge and discount
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE + expectedSurcharge);
+
+ //remove the surcharge
+ setNativeSurcharge(0, ADMIN);
+
+ //get the fee required by the feeManager
+ fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be the default
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_feeIsUpdatedAfterNewSurchargeIsApplied() public {
+ //native surcharge
+ uint256 nativeSurcharge = FEE_SCALAR / 5;
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected surcharge
+ uint256 expectedSurcharge = ((DEFAULT_REPORT_NATIVE_FEE * nativeSurcharge) / FEE_SCALAR);
+
+ //expected fee should the base fee offset by the surcharge and discount
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE + expectedSurcharge);
+
+ //change the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+
+ //get the fee required by the feeManager
+ fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected surcharge
+ expectedSurcharge = ((DEFAULT_REPORT_NATIVE_FEE * nativeSurcharge) / FEE_SCALAR);
+
+ //expected fee should the base fee offset by the surcharge and discount
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE + expectedSurcharge);
+ }
+
+ function test_surchargeIsAppliedForNativeFeeWithDiscount() public {
+ //native surcharge
+ uint256 nativeSurcharge = FEE_SCALAR / 5;
+
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected surcharge quantity
+ uint256 expectedSurcharge = ((DEFAULT_REPORT_NATIVE_FEE * nativeSurcharge) / FEE_SCALAR);
+
+ //calculate the expected discount quantity
+ uint256 expectedDiscount = ((DEFAULT_REPORT_NATIVE_FEE + expectedSurcharge) / 2);
+
+ //expected fee should the base fee offset by the surcharge and discount
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE + expectedSurcharge - expectedDiscount);
+ }
+
+ function test_emptyQuoteRevertsWithError() public {
+ //expect a revert
+ vm.expectRevert(INVALID_QUOTE_ERROR);
+
+ //get the fee required by the feeManager
+ getFee(getV3Report(DEFAULT_FEED_1_V3), address(0), USER);
+ }
+
+ function test_nativeSurcharge100Percent() public {
+ //set the surcharge
+ setNativeSurcharge(FEE_SCALAR, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be twice the base fee
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE * 2);
+ }
+
+ function test_nativeSurcharge0Percent() public {
+ //set the surcharge
+ setNativeSurcharge(0, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should base fee
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_nativeSurchargeCannotExceed100Percent() public {
+ //should revert if surcharge is greater than 100%
+ vm.expectRevert(INVALID_SURCHARGE_ERROR);
+
+ //set the surcharge above the max
+ setNativeSurcharge(FEE_SCALAR + 1, ADMIN);
+ }
+
+ function test_discountIsAppliedWith100PercentSurcharge() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //set the surcharge
+ setNativeSurcharge(FEE_SCALAR, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected discount quantity
+ uint256 expectedDiscount = DEFAULT_REPORT_NATIVE_FEE;
+
+ //fee should be twice the surcharge minus the discount
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE * 2 - expectedDiscount);
+ }
+
+ function test_feeIsZeroWith100PercentDiscount() public {
+ //set the subscriber discount to 100%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be zero
+ assertEq(fee.amount, 0);
+ }
+
+ function test_feeIsUpdatedAfterDiscountIsRemoved() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected discount quantity
+ uint256 expectedDiscount = DEFAULT_REPORT_NATIVE_FEE / 2;
+
+ //fee should be 50% of the base fee
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE - expectedDiscount);
+
+ //remove the discount
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), 0, ADMIN);
+
+ //get the fee required by the feeManager
+ fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be the base fee
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_feeIsUpdatedAfterNewDiscountIsApplied() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected discount quantity
+ uint256 expectedDiscount = DEFAULT_REPORT_NATIVE_FEE / 2;
+
+ //fee should be 50% of the base fee
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE - expectedDiscount);
+
+ //change the discount to 25%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 4, ADMIN);
+
+ //get the fee required by the feeManager
+ fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //expected discount is now 25%
+ expectedDiscount = DEFAULT_REPORT_NATIVE_FEE / 4;
+
+ //fee should be the base fee minus the expected discount
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE - expectedDiscount);
+ }
+
+ function test_setDiscountOver100Percent() public {
+ //should revert with invalid discount
+ vm.expectRevert(INVALID_DISCOUNT_ERROR);
+
+ //set the subscriber discount to over 100%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR + 1, ADMIN);
+ }
+
+ function test_surchargeIsNotAppliedWith100PercentDiscount() public {
+ //native surcharge
+ uint256 nativeSurcharge = FEE_SCALAR / 5;
+
+ //set the subscriber discount to 100%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR, ADMIN);
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be zero
+ assertEq(fee.amount, 0);
+ }
+
+ function test_nonAdminUserCanNotSetDiscount() public {
+ //should revert with unauthorized
+ vm.expectRevert(ONLY_CALLABLE_BY_OWNER_ERROR);
+
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR, USER);
+ }
+
+ function test_surchargeFeeRoundsUpWhenUneven() public {
+ //native surcharge
+ uint256 nativeSurcharge = FEE_SCALAR / 3;
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected surcharge quantity
+ uint256 expectedSurcharge = (DEFAULT_REPORT_NATIVE_FEE * nativeSurcharge) / FEE_SCALAR;
+
+ //expected fee should the base fee offset by the expected surcharge
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE + expectedSurcharge + 1);
+ }
+
+ function test_discountFeeRoundsDownWhenUneven() public {
+ //native surcharge
+ uint256 discount = FEE_SCALAR / 3;
+
+ //set the subscriber discount to 33.333%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), discount, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected quantity
+ uint256 expectedDiscount = ((DEFAULT_REPORT_NATIVE_FEE * discount) / FEE_SCALAR);
+
+ //expected fee should the base fee offset by the expected surcharge
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE - expectedDiscount);
+ }
+
+ function test_reportWithNoExpiryOrFeeReturnsZero() public view {
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV1Report(DEFAULT_FEED_1_V1), getNativeQuote(), USER);
+
+ //fee should be zero
+ assertEq(fee.amount, 0);
+ }
+
+ function test_correctDiscountIsAppliedWhenBothTokensAreDiscounted() public {
+ //set the subscriber and native discounts
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 4, ADMIN);
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager for both tokens
+ Common.Asset memory linkFee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+ Common.Asset memory nativeFee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //calculate the expected discount quantity for each token
+ uint256 expectedDiscountLink = (DEFAULT_REPORT_LINK_FEE * FEE_SCALAR) / 4 / FEE_SCALAR;
+ uint256 expectedDiscountNative = (DEFAULT_REPORT_NATIVE_FEE * FEE_SCALAR) / 2 / FEE_SCALAR;
+
+ //check the fee calculation for each token
+ assertEq(linkFee.amount, DEFAULT_REPORT_LINK_FEE - expectedDiscountLink);
+ assertEq(nativeFee.amount, DEFAULT_REPORT_NATIVE_FEE - expectedDiscountNative);
+ }
+
+ function test_discountIsNotAppliedToOtherFeeds() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_2_V3), getNativeQuote(), USER);
+
+ //fee should be the base fee
+ assertEq(fee.amount, DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_noFeeIsAppliedWhenReportHasZeroFee() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(
+ getV3ReportWithCustomExpiryAndFee(DEFAULT_FEED_1_V3, uint32(block.timestamp), 0, 0),
+ getNativeQuote(),
+ USER
+ );
+
+ //fee should be zero
+ assertEq(fee.amount, 0);
+ }
+
+ function test_noFeeIsAppliedWhenReportHasZeroFeeAndDiscountAndSurchargeIsSet() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //set the surcharge
+ setNativeSurcharge(FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(
+ getV3ReportWithCustomExpiryAndFee(DEFAULT_FEED_1_V3, uint32(block.timestamp), 0, 0),
+ getNativeQuote(),
+ USER
+ );
+
+ //fee should be zero
+ assertEq(fee.amount, 0);
+ }
+
+ function test_nativeSurchargeEventIsEmittedOnUpdate() public {
+ //native surcharge
+ uint64 nativeSurcharge = FEE_SCALAR / 3;
+
+ //an event should be emitted
+ vm.expectEmit();
+
+ //emit the event that is expected to be emitted
+ emit NativeSurchargeUpdated(nativeSurcharge);
+
+ //set the surcharge
+ setNativeSurcharge(nativeSurcharge, ADMIN);
+ }
+
+ function test_getBaseRewardWithLinkQuote() public view {
+ //get the fee required by the feeManager
+ Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //the reward should equal the base fee
+ assertEq(reward.amount, DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_getRewardWithLinkQuoteAndLinkDiscount() public {
+ //set the link discount
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //the reward should equal the discounted base fee
+ assertEq(reward.amount, DEFAULT_REPORT_LINK_FEE / 2);
+ }
+
+ function test_getRewardWithNativeQuote() public view {
+ //get the fee required by the feeManager
+ Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //the reward should equal the base fee in link
+ assertEq(reward.amount, DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_getRewardWithNativeQuoteAndSurcharge() public {
+ //set the native surcharge
+ setNativeSurcharge(FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //the reward should equal the base fee in link regardless of the surcharge
+ assertEq(reward.amount, DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_getRewardWithLinkDiscount() public {
+ //set the link discount
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //the reward should equal the discounted base fee
+ assertEq(reward.amount, DEFAULT_REPORT_LINK_FEE / 2);
+ }
+
+ function test_getLinkFeeIsRoundedUp() public {
+ //set the link discount
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 3, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //the reward should equal .66% + 1 of the base fee due to a 33% discount rounded up
+ assertEq(fee.amount, (DEFAULT_REPORT_LINK_FEE * 2) / 3 + 1);
+ }
+
+ function test_getLinkRewardIsSameAsFee() public {
+ //set the link discount
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 3, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+ Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //check the reward is in link
+ assertEq(fee.assetAddress, address(link));
+
+ //the reward should equal .66% of the base fee due to a 33% discount rounded down
+ assertEq(reward.amount, fee.amount);
+ }
+
+ function test_getLinkRewardWithNativeQuoteAndSurchargeWithLinkDiscount() public {
+ //set the native surcharge
+ setNativeSurcharge(FEE_SCALAR / 2, ADMIN);
+
+ //set the link discount
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 3, ADMIN);
+
+ //get the fee required by the feeManager
+ Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //the reward should equal the base fee in link regardless of the surcharge
+ assertEq(reward.amount, DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_testRevertIfReportHasExpired() public {
+ //expect a revert
+ vm.expectRevert(EXPIRED_REPORT_ERROR);
+
+ //get the fee required by the feeManager
+ getFee(
+ getV3ReportWithCustomExpiryAndFee(
+ DEFAULT_FEED_1_V3,
+ block.timestamp - 1,
+ DEFAULT_REPORT_LINK_FEE,
+ DEFAULT_REPORT_NATIVE_FEE
+ ),
+ getNativeQuote(),
+ USER
+ );
+ }
+
+ function test_discountIsReturnedForLink() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(link), FEE_SCALAR / 2, ADMIN);
+
+ //get the fee applied
+ uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getLinkQuote(), USER);
+
+ //fee should be half the default
+ assertEq(discount, FEE_SCALAR / 2);
+ }
+
+ function test_DiscountIsReturnedForNative() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //get the discount applied
+ uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be half the default
+ assertEq(discount, FEE_SCALAR / 2);
+ }
+
+ function test_DiscountIsReturnedForNativeWithSurcharge() public {
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //set the surcharge
+ setNativeSurcharge(FEE_SCALAR / 5, ADMIN);
+
+ //get the discount applied
+ uint256 discount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ //fee should be half the default
+ assertEq(discount, FEE_SCALAR / 2);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.processFee.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.processFee.t.sol
new file mode 100644
index 00000000000..0880352dca4
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.processFee.t.sol
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {Common} from "../../../libraries/Common.sol";
+import "./BaseDestinationFeeManager.t.sol";
+import {IDestinationRewardManager} from "../../interfaces/IDestinationRewardManager.sol";
+
+/**
+ * @title BaseFeeManagerTest
+ * @author Michael Fletcher
+ * @notice This contract will test the functionality of the feeManager processFee
+ */
+contract DestinationFeeManagerProcessFeeTest is BaseDestinationFeeManagerTest {
+ function setUp() public override {
+ super.setUp();
+ }
+
+ function test_nonAdminProxyUserCannotProcessFee() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //should revert as the user is not the owner
+ vm.expectRevert(UNAUTHORIZED_ERROR);
+
+ //process the fee
+ ProcessFeeAsUser(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0, USER);
+ }
+
+ function test_processFeeAsProxy() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //approve the link to be transferred from the from the subscriber to the rewardManager
+ approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+
+ //processing the fee will transfer the link from the user to the rewardManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+
+ //check the link has been transferred
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the user has had the link fee deducted
+ assertEq(getLinkBalance(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_processFeeIfSubscriberIsSelf() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //expect a revert due to the feeManager being the subscriber
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+
+ //process the fee will fail due to assertion
+ processFee(DEFAULT_CONFIG_DIGEST, payload, address(feeManager), address(native), 0);
+ }
+
+ function test_processFeeWithWithEmptyQuotePayload() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //expect a revert as the quote is invalid
+ vm.expectRevert();
+
+ //processing the fee will transfer the link by default
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(0), 0);
+ }
+
+ function test_processFeeWithWithZeroQuotePayload() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //expect a revert as the quote is invalid
+ vm.expectRevert(INVALID_QUOTE_ERROR);
+
+ //processing the fee will transfer the link by default
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, INVALID_ADDRESS, 0);
+ }
+
+ function test_processFeeWithWithCorruptQuotePayload() public {
+ //get the default payload
+ bytes memory payload = abi.encode(
+ [DEFAULT_CONFIG_DIGEST, 0, 0],
+ getV3Report(DEFAULT_FEED_1_V3),
+ new bytes32[](1),
+ new bytes32[](1),
+ bytes32("")
+ );
+
+ //expect an evm revert as the quote is corrupt
+ vm.expectRevert();
+
+ //processing the fee will not withdraw anything as there is no fee to collect
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+ }
+
+ function test_processFeeDefaultReportsStillVerifiesWithEmptyQuote() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV1Report(DEFAULT_FEED_1_V1));
+
+ //processing the fee will transfer the link from the user to the rewardManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(0), 0);
+ }
+
+ function test_processFeeWithDefaultReportPayloadAndQuoteStillVerifies() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV1Report(DEFAULT_FEED_1_V1));
+
+ //processing the fee will not withdraw anything as there is no fee to collect
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+ }
+
+ function test_processFeeNative() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //approve the native to be transferred from the user
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER);
+
+ //processing the fee will transfer the native from the user to the feeManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), 0);
+
+ //check the native has been transferred
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE);
+
+ //check the link has been transferred to the rewardManager
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the feeManager has had the link deducted, the remaining balance should be 0
+ assertEq(getLinkBalance(address(feeManager)), 0);
+
+ //check the subscriber has had the native deducted
+ assertEq(getNativeBalance(USER), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_processFeeEmitsEventIfNotEnoughLink() public {
+ //simulate a deposit of half the link required for the fee
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE / 2);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //approve the native to be transferred from the user
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER);
+
+ //expect an emit as there's not enough link
+ vm.expectEmit();
+
+ IDestinationRewardManager.FeePayment[] memory contractFees = new IDestinationRewardManager.FeePayment[](1);
+ contractFees[0] = IDestinationRewardManager.FeePayment(DEFAULT_CONFIG_DIGEST, uint192(DEFAULT_REPORT_LINK_FEE));
+
+ //emit the event that is expected to be emitted
+ emit InsufficientLink(contractFees);
+
+ //processing the fee will transfer the native from the user to the feeManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), 0);
+
+ //check the native has been transferred
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE);
+
+ //check no link has been transferred to the rewardManager
+ assertEq(getLinkBalance(address(rewardManager)), 0);
+ assertEq(getLinkBalance(address(feeManager)), DEFAULT_REPORT_LINK_FEE / 2);
+
+ //check the subscriber has had the native deducted
+ assertEq(getNativeBalance(USER), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_processFeeWithUnwrappedNative() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //only the proxy or admin can call processFee, they will pass in the native value on the users behalf
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), DEFAULT_REPORT_NATIVE_FEE);
+
+ //check the native has been transferred and converted to wrapped native
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE);
+ assertEq(getNativeUnwrappedBalance(address(feeManager)), 0);
+
+ //check the link has been transferred to the rewardManager
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the feeManager has had the link deducted, the remaining balance should be 0
+ assertEq(getLinkBalance(address(feeManager)), 0);
+
+ //check the subscriber has had the native deducted
+ assertEq(getNativeUnwrappedBalance(USER), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_processFeeWithUnwrappedNativeShortFunds() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //expect a revert as not enough funds
+ vm.expectRevert(INVALID_DEPOSIT_ERROR);
+
+ //only the proxy or admin can call processFee, they will pass in the native value on the users behalf
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), DEFAULT_REPORT_NATIVE_FEE - 1);
+ }
+
+ function test_processFeeWithUnwrappedNativeLinkAddress() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //expect a revert as not enough funds
+ vm.expectRevert(INSUFFICIENT_ALLOWANCE_ERROR);
+
+ //the change will be returned and the user will attempted to be billed in LINK
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), DEFAULT_REPORT_NATIVE_FEE - 1);
+ }
+
+ function test_processFeeWithUnwrappedNativeLinkAddressExcessiveFee() public {
+ //approve the link to be transferred from the from the subscriber to the rewardManager
+ approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, PROXY);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //call processFee from the proxy to test whether the funds are returned to the subscriber. In reality, the funds would be returned to the caller of the proxy.
+ processFee(DEFAULT_CONFIG_DIGEST, payload, PROXY, address(link), DEFAULT_REPORT_NATIVE_FEE);
+
+ //check the native unwrapped is no longer in the account
+ assertEq(getNativeBalance(address(feeManager)), 0);
+ assertEq(getNativeUnwrappedBalance(address(feeManager)), 0);
+
+ //check the link has been transferred to the rewardManager
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the feeManager has had the link deducted, the remaining balance should be 0
+ assertEq(getLinkBalance(address(feeManager)), 0);
+
+ //native should not be deducted
+ assertEq(getNativeUnwrappedBalance(PROXY), DEFAULT_NATIVE_MINT_QUANTITY);
+ }
+
+ function test_processFeeWithUnwrappedNativeWithExcessiveFee() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //call processFee from the proxy to test whether the funds are returned to the subscriber. In reality, the funds would be returned to the caller of the proxy.
+ processFee(DEFAULT_CONFIG_DIGEST, payload, PROXY, address(native), DEFAULT_REPORT_NATIVE_FEE * 2);
+
+ //check the native has been transferred and converted to wrapped native
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE);
+ assertEq(getNativeUnwrappedBalance(address(feeManager)), 0);
+
+ //check the link has been transferred to the rewardManager
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the feeManager has had the link deducted, the remaining balance should be 0
+ assertEq(getLinkBalance(address(feeManager)), 0);
+
+ //check the subscriber has had the native deducted
+ assertEq(getNativeUnwrappedBalance(PROXY), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_processFeeUsesCorrectDigest() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //approve the link to be transferred from the from the subscriber to the rewardManager
+ approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+
+ //processing the fee will transfer the link from the user to the rewardManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+
+ //check the link has been transferred
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the user has had the link fee deducted
+ assertEq(getLinkBalance(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE);
+
+ //check funds have been paid to the reward manager
+ assertEq(rewardManager.s_totalRewardRecipientFees(DEFAULT_CONFIG_DIGEST), DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_V1PayloadVerifies() public {
+ //replicate a default payload
+ bytes memory payload = abi.encode(
+ [DEFAULT_CONFIG_DIGEST, 0, 0],
+ getV2Report(DEFAULT_FEED_1_V1),
+ new bytes32[](1),
+ new bytes32[](1),
+ bytes32("")
+ );
+
+ //processing the fee will transfer the link from the user to the rewardManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(0), 0);
+ }
+
+ function test_V2PayloadVerifies() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV2Report(DEFAULT_FEED_1_V2));
+
+ //approve the link to be transferred from the from the subscriber to the rewardManager
+ approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+
+ //processing the fee will transfer the link from the user to the rewardManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+
+ //check the link has been transferred
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the user has had the link fee deducted
+ assertEq(getLinkBalance(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_V2PayloadWithoutQuoteFails() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV2Report(DEFAULT_FEED_1_V2));
+
+ //expect a revert as the quote is invalid
+ vm.expectRevert();
+
+ //processing the fee will transfer the link from the user to the rewardManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(0), 0);
+ }
+
+ function test_V2PayloadWithoutZeroFee() public {
+ //get the default payload
+ bytes memory payload = getPayload(getV2Report(DEFAULT_FEED_1_V2));
+
+ //expect a revert as the quote is invalid
+ vm.expectRevert();
+
+ //processing the fee will transfer the link from the user to the rewardManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+ }
+
+ function test_processFeeWithInvalidReportVersionFailsToDecode() public {
+ bytes memory data = abi.encode(0x0000100000000000000000000000000000000000000000000000000000000000);
+
+ //get the default payload
+ bytes memory payload = getPayload(data);
+
+ //serialization will fail as there is no report to decode
+ vm.expectRevert();
+
+ //processing the fee will not withdraw anything as there is no fee to collect
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+ }
+
+ function test_processFeeWithZeroNativeNonZeroLinkWithNativeQuote() public {
+ //get the default payload
+ bytes memory payload = getPayload(
+ getV3ReportWithCustomExpiryAndFee(DEFAULT_FEED_1_V3, block.timestamp, DEFAULT_REPORT_LINK_FEE, 0)
+ );
+
+ //call processFee should not revert as the fee is 0
+ processFee(DEFAULT_CONFIG_DIGEST, payload, PROXY, address(native), 0);
+ }
+
+ function test_processFeeWithZeroNativeNonZeroLinkWithLinkQuote() public {
+ //get the default payload
+ bytes memory payload = getPayload(
+ getV3ReportWithCustomExpiryAndFee(DEFAULT_FEED_1_V3, block.timestamp, DEFAULT_REPORT_LINK_FEE, 0)
+ );
+
+ //approve the link to be transferred from the from the subscriber to the rewardManager
+ approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+
+ //processing the fee will transfer the link to the rewardManager from the user
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+
+ //check the link has been transferred
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the user has had the link fee deducted
+ assertEq(getLinkBalance(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_processFeeWithZeroLinkNonZeroNativeWithNativeQuote() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //get the default payload
+ bytes memory payload = getPayload(
+ getV3ReportWithCustomExpiryAndFee(DEFAULT_FEED_1_V3, block.timestamp, 0, DEFAULT_REPORT_NATIVE_FEE)
+ );
+
+ //approve the native to be transferred from the user
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER);
+
+ //processing the fee will transfer the native from the user to the feeManager
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), 0);
+
+ //check the native has been transferred
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE);
+
+ //check no link has been transferred to the rewardManager
+ assertEq(getLinkBalance(address(rewardManager)), 0);
+
+ //check the feeManager has had no link deducted
+ assertEq(getLinkBalance(address(feeManager)), DEFAULT_REPORT_LINK_FEE);
+
+ //check the subscriber has had the native deducted
+ assertEq(getNativeBalance(USER), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE);
+ }
+
+ function test_processFeeWithZeroLinkNonZeroNativeWithLinkQuote() public {
+ //get the default payload
+ bytes memory payload = getPayload(
+ getV3ReportWithCustomExpiryAndFee(DEFAULT_FEED_1_V3, block.timestamp, 0, DEFAULT_REPORT_NATIVE_FEE)
+ );
+
+ //call processFee should not revert as the fee is 0
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), 0);
+ }
+
+ function test_processFeeWithZeroNativeNonZeroLinkReturnsChange() public {
+ //get the default payload
+ bytes memory payload = getPayload(
+ getV3ReportWithCustomExpiryAndFee(DEFAULT_FEED_1_V3, block.timestamp, 0, DEFAULT_REPORT_NATIVE_FEE)
+ );
+
+ //call processFee should not revert as the fee is 0
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(link), DEFAULT_REPORT_NATIVE_FEE);
+
+ //check the change has been returned
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ }
+
+ function test_V1PayloadVerifiesAndReturnsChange() public {
+ //emulate a V1 payload with no quote
+ bytes memory payload = getPayload(getV1Report(DEFAULT_FEED_1_V1));
+
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(0), DEFAULT_REPORT_NATIVE_FEE);
+
+ //Fee manager should not contain any native
+ assertEq(address(feeManager).balance, 0);
+ assertEq(getNativeBalance(address(feeManager)), 0);
+
+ //check the unused native passed in is returned
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ }
+
+ function test_processFeeWithDiscountEmitsEvent() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //set the subscriber discount to 50%
+ setSubscriberDiscount(USER, DEFAULT_FEED_1_V3, address(native), FEE_SCALAR / 2, ADMIN);
+
+ //approve the native to be transferred from the user
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE / 2, USER);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ Common.Asset memory fee = getFee(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+ Common.Asset memory reward = getReward(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+ uint256 appliedDiscount = getAppliedDiscount(getV3Report(DEFAULT_FEED_1_V3), getNativeQuote(), USER);
+
+ vm.expectEmit();
+
+ emit DiscountApplied(DEFAULT_CONFIG_DIGEST, USER, fee, reward, appliedDiscount);
+
+ //call processFee should not revert as the fee is 0
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), 0);
+ }
+
+ function test_processFeeWithNoDiscountDoesNotEmitEvent() public {
+ //simulate a deposit of link for the conversion pool
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+
+ //approve the native to be transferred from the user
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER);
+
+ //get the default payload
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ //call processFee should not revert as the fee is 0
+ processFee(DEFAULT_CONFIG_DIGEST, payload, USER, address(native), 0);
+
+ //no logs should have been emitted
+ assertEq(vm.getRecordedLogs().length, 0);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.processFeeBulk.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.processFeeBulk.t.sol
new file mode 100644
index 00000000000..a50441bed67
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/fee-manager/DestinationFeeManager.processFeeBulk.t.sol
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import "./BaseDestinationFeeManager.t.sol";
+import {IDestinationRewardManager} from "../../interfaces/IDestinationRewardManager.sol";
+
+/**
+ * @title BaseFeeManagerTest
+ * @author Michael Fletcher
+ * @notice This contract will test the functionality of the feeManager processFee
+ */
+contract DestinationFeeManagerProcessFeeTest is BaseDestinationFeeManagerTest {
+ uint256 internal constant NUMBER_OF_REPORTS = 5;
+
+ function setUp() public override {
+ super.setUp();
+ }
+
+ function test_processMultipleLinkReports() public {
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ payloads[i] = payload;
+ }
+
+ bytes32[] memory poolIds = new bytes32[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+
+ approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS, USER);
+
+ processFee(poolIds, payloads, USER, address(link), DEFAULT_NATIVE_MINT_QUANTITY);
+
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS);
+ assertEq(getLinkBalance(address(feeManager)), 0);
+ assertEq(getLinkBalance(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS);
+
+ //the subscriber (user) should receive funds back and not the proxy, although when live the proxy will forward the funds sent and not cover it seen here
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ assertEq(PROXY.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ }
+
+ function test_processMultipleWrappedNativeReports() public {
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS + 1);
+
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](NUMBER_OF_REPORTS);
+ for (uint256 i; i < NUMBER_OF_REPORTS; ++i) {
+ payloads[i] = payload;
+ }
+
+ bytes32[] memory poolIds = new bytes32[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE * NUMBER_OF_REPORTS, USER);
+
+ processFee(poolIds, payloads, USER, address(native), 0);
+
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE * NUMBER_OF_REPORTS);
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS);
+ assertEq(getLinkBalance(address(feeManager)), 1);
+ assertEq(getNativeBalance(USER), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE * NUMBER_OF_REPORTS);
+ }
+
+ function test_processMultipleUnwrappedNativeReports() public {
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS + 1);
+
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](NUMBER_OF_REPORTS);
+ for (uint256 i; i < NUMBER_OF_REPORTS; ++i) {
+ payloads[i] = payload;
+ }
+
+ bytes32[] memory poolIds = new bytes32[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+
+ processFee(poolIds, payloads, USER, address(native), DEFAULT_REPORT_NATIVE_FEE * NUMBER_OF_REPORTS * 2);
+
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE * NUMBER_OF_REPORTS);
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS);
+ assertEq(getLinkBalance(address(feeManager)), 1);
+
+ assertEq(PROXY.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE * NUMBER_OF_REPORTS);
+ }
+
+ function test_processV1V2V3Reports() public {
+ mintLink(address(feeManager), 1);
+
+ bytes memory payloadV1 = abi.encode(
+ [DEFAULT_CONFIG_DIGEST, 0, 0],
+ getV1Report(DEFAULT_FEED_1_V1),
+ new bytes32[](1),
+ new bytes32[](1),
+ bytes32("")
+ );
+
+ bytes memory linkPayloadV2 = getPayload(getV2Report(DEFAULT_FEED_1_V2));
+ bytes memory linkPayloadV3 = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](5);
+ payloads[0] = payloadV1;
+ payloads[1] = linkPayloadV2;
+ payloads[2] = linkPayloadV2;
+ payloads[3] = linkPayloadV3;
+ payloads[4] = linkPayloadV3;
+
+ approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE * 4, USER);
+
+ bytes32[] memory poolIds = new bytes32[](5);
+ for (uint256 i = 0; i < 5; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+
+ processFee(poolIds, payloads, USER, address(link), 0);
+
+ assertEq(getNativeBalance(address(feeManager)), 0);
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE * 4);
+ assertEq(getLinkBalance(address(feeManager)), 1);
+
+ assertEq(getLinkBalance(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE * 4);
+ assertEq(getNativeBalance(USER), DEFAULT_NATIVE_MINT_QUANTITY - 0);
+ }
+
+ function test_processV1V2V3ReportsWithUnwrapped() public {
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE * 4 + 1);
+
+ bytes memory payloadV1 = abi.encode(
+ [DEFAULT_CONFIG_DIGEST, 0, 0],
+ getV1Report(DEFAULT_FEED_1_V1),
+ new bytes32[](1),
+ new bytes32[](1),
+ bytes32("")
+ );
+
+ bytes memory nativePayloadV2 = getPayload(getV2Report(DEFAULT_FEED_1_V2));
+ bytes memory nativePayloadV3 = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](5);
+ payloads[0] = payloadV1;
+ payloads[1] = nativePayloadV2;
+ payloads[2] = nativePayloadV2;
+ payloads[3] = nativePayloadV3;
+ payloads[4] = nativePayloadV3;
+
+ bytes32[] memory poolIds = new bytes32[](5);
+ for (uint256 i = 0; i < 5; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+
+ processFee(poolIds, payloads, USER, address(native), DEFAULT_REPORT_NATIVE_FEE * 4);
+
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE * 4);
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE * 4);
+ assertEq(getLinkBalance(address(feeManager)), 1);
+
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE * 4);
+ assertEq(PROXY.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ }
+
+ function test_processMultipleV1Reports() public {
+ bytes memory payload = abi.encode(
+ [DEFAULT_CONFIG_DIGEST, 0, 0],
+ getV1Report(DEFAULT_FEED_1_V1),
+ new bytes32[](1),
+ new bytes32[](1),
+ bytes32("")
+ );
+
+ bytes[] memory payloads = new bytes[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ payloads[i] = payload;
+ }
+
+ bytes32[] memory poolIds = new bytes32[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+
+ processFee(poolIds, payloads, USER, address(native), DEFAULT_REPORT_NATIVE_FEE * 5);
+
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ assertEq(PROXY.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ }
+
+ function test_eventIsEmittedIfNotEnoughLink() public {
+ bytes memory nativePayload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](5);
+ payloads[0] = nativePayload;
+ payloads[1] = nativePayload;
+ payloads[2] = nativePayload;
+ payloads[3] = nativePayload;
+ payloads[4] = nativePayload;
+
+ approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE * 5, USER);
+
+ IDestinationRewardManager.FeePayment[] memory payments = new IDestinationRewardManager.FeePayment[](5);
+ payments[0] = IDestinationRewardManager.FeePayment(DEFAULT_CONFIG_DIGEST, uint192(DEFAULT_REPORT_LINK_FEE));
+ payments[1] = IDestinationRewardManager.FeePayment(DEFAULT_CONFIG_DIGEST, uint192(DEFAULT_REPORT_LINK_FEE));
+ payments[2] = IDestinationRewardManager.FeePayment(DEFAULT_CONFIG_DIGEST, uint192(DEFAULT_REPORT_LINK_FEE));
+ payments[3] = IDestinationRewardManager.FeePayment(DEFAULT_CONFIG_DIGEST, uint192(DEFAULT_REPORT_LINK_FEE));
+ payments[4] = IDestinationRewardManager.FeePayment(DEFAULT_CONFIG_DIGEST, uint192(DEFAULT_REPORT_LINK_FEE));
+
+ vm.expectEmit();
+
+ bytes32[] memory poolIds = new bytes32[](5);
+ for (uint256 i = 0; i < 5; ++i) {
+ poolIds[i] = payments[i].poolId;
+ }
+
+ emit InsufficientLink(payments);
+
+ processFee(poolIds, payloads, USER, address(native), 0);
+
+ assertEq(getNativeBalance(address(feeManager)), DEFAULT_REPORT_NATIVE_FEE * 5);
+ assertEq(getNativeBalance(USER), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE * 5);
+ assertEq(getLinkBalance(USER), DEFAULT_LINK_MINT_QUANTITY);
+ }
+
+ function test_processPoolIdsPassedMismatched() public {
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS + 1);
+
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](NUMBER_OF_REPORTS);
+ for (uint256 i; i < NUMBER_OF_REPORTS; ++i) {
+ payloads[i] = payload;
+ }
+
+ // poolIds passed are different that number of reports in payload
+ bytes32[] memory poolIds = new bytes32[](NUMBER_OF_REPORTS - 1);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS - 1; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+
+ vm.expectRevert(POOLID_MISMATCH_ERROR);
+ processFee(poolIds, payloads, USER, address(native), DEFAULT_REPORT_NATIVE_FEE * NUMBER_OF_REPORTS * 2);
+ }
+
+ function test_poolIdsCannotBeZeroAddress() public {
+ mintLink(address(feeManager), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS + 1);
+
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](NUMBER_OF_REPORTS);
+ for (uint256 i; i < NUMBER_OF_REPORTS; ++i) {
+ payloads[i] = payload;
+ }
+
+ bytes32[] memory poolIds = new bytes32[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+
+ poolIds[2] = 0x000;
+ vm.expectRevert(INVALID_ADDRESS_ERROR);
+ processFee(poolIds, payloads, USER, address(native), DEFAULT_REPORT_NATIVE_FEE * NUMBER_OF_REPORTS * 2);
+ }
+
+ function test_rewardsAreCorrectlySentToEachAssociatedPoolWhenVerifyingInBulk() public {
+ bytes memory payload = getPayload(getV3Report(DEFAULT_FEED_1_V3));
+
+ bytes[] memory payloads = new bytes[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ payloads[i] = payload;
+ }
+
+ bytes32[] memory poolIds = new bytes32[](NUMBER_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS - 1; ++i) {
+ poolIds[i] = DEFAULT_CONFIG_DIGEST;
+ }
+ poolIds[NUMBER_OF_REPORTS - 1] = DEFAULT_CONFIG_DIGEST2;
+
+ approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS, USER);
+
+ // Checking no rewards yet for each pool
+ for (uint256 i = 0; i < NUMBER_OF_REPORTS; ++i) {
+ bytes32 p_id = poolIds[i];
+ uint256 poolDeficit = rewardManager.s_totalRewardRecipientFees(p_id);
+ assertEq(poolDeficit, 0);
+ }
+
+ processFee(poolIds, payloads, USER, address(link), DEFAULT_NATIVE_MINT_QUANTITY);
+
+ assertEq(getLinkBalance(address(rewardManager)), DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS);
+ assertEq(getLinkBalance(address(feeManager)), 0);
+ assertEq(getLinkBalance(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE * NUMBER_OF_REPORTS);
+
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+ assertEq(PROXY.balance, DEFAULT_NATIVE_MINT_QUANTITY);
+
+ // Checking each pool got the correct rewards
+ uint256 expectedRewards = DEFAULT_REPORT_LINK_FEE * (NUMBER_OF_REPORTS - 1);
+ uint256 poolRewards = rewardManager.s_totalRewardRecipientFees(DEFAULT_CONFIG_DIGEST);
+ assertEq(poolRewards, expectedRewards);
+
+ expectedRewards = DEFAULT_REPORT_LINK_FEE;
+ poolRewards = rewardManager.s_totalRewardRecipientFees(DEFAULT_CONFIG_DIGEST2);
+ assertEq(poolRewards, expectedRewards);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/mocks/DestinationFeeManagerProxy.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/mocks/DestinationFeeManagerProxy.sol
new file mode 100644
index 00000000000..46ec7fff3b5
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/mocks/DestinationFeeManagerProxy.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+pragma solidity 0.8.19;
+
+import {IDestinationFeeManager} from "../../interfaces/IDestinationFeeManager.sol";
+
+contract DestinationFeeManagerProxy {
+ IDestinationFeeManager internal s_feeManager;
+
+ function processFee(bytes32 poolId, bytes calldata payload, bytes calldata parameterPayload) public payable {
+ s_feeManager.processFee{value: msg.value}(poolId, payload, parameterPayload, msg.sender);
+ }
+
+ function processFeeBulk(
+ bytes32[] memory poolIds,
+ bytes[] calldata payloads,
+ bytes calldata parameterPayload
+ ) public payable {
+ s_feeManager.processFeeBulk{value: msg.value}(poolIds, payloads, parameterPayload, msg.sender);
+ }
+
+ function setDestinationFeeManager(IDestinationFeeManager feeManager) public {
+ s_feeManager = feeManager;
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/BaseDestinationRewardManager.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/BaseDestinationRewardManager.t.sol
new file mode 100644
index 00000000000..7cafb1629db
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/BaseDestinationRewardManager.t.sol
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {Test} from "forge-std/Test.sol";
+import {ERC20Mock} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
+import {DestinationRewardManager} from "../../../v0.4.0/DestinationRewardManager.sol";
+import {Common} from "../../../libraries/Common.sol";
+import {IDestinationRewardManager} from "../../interfaces/IDestinationRewardManager.sol";
+
+/**
+ * @title DestinationRewardManagerTest
+ * @author Michael Fletcher
+ * @notice Base class for all reward manager tests
+ * @dev This contract is intended to be inherited from and not used directly. It contains functionality to setup a primary and secondary pool
+ */
+contract BaseDestinationRewardManagerTest is Test {
+ //contracts
+ ERC20Mock internal asset;
+ ERC20Mock internal unsupported;
+ DestinationRewardManager internal rewardManager;
+
+ //default address for unregistered recipient
+ address internal constant INVALID_ADDRESS = address(0);
+ //contract owner
+ address internal constant ADMIN = address(uint160(uint256(keccak256("ADMIN"))));
+ //address to represent feeManager contract
+ address internal constant FEE_MANAGER = address(uint160(uint256(keccak256("FEE_MANAGER"))));
+ //address to represent another feeManager
+ address internal constant FEE_MANAGER_2 = address(uint160(uint256(keccak256("FEE_MANAGER_2"))));
+ //a general user
+ address internal constant USER = address(uint160(uint256(keccak256("USER"))));
+
+ //default recipients configured in reward manager
+ address internal constant DEFAULT_RECIPIENT_1 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_1"))));
+ address internal constant DEFAULT_RECIPIENT_2 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_2"))));
+ address internal constant DEFAULT_RECIPIENT_3 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_3"))));
+ address internal constant DEFAULT_RECIPIENT_4 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_4"))));
+ address internal constant DEFAULT_RECIPIENT_5 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_5"))));
+ address internal constant DEFAULT_RECIPIENT_6 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_6"))));
+ address internal constant DEFAULT_RECIPIENT_7 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_7"))));
+
+ //additional recipients not in the reward manager
+ address internal constant DEFAULT_RECIPIENT_8 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_8"))));
+ address internal constant DEFAULT_RECIPIENT_9 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_9"))));
+
+ //two pools should be enough to test all edge cases
+ bytes32 internal constant PRIMARY_POOL_ID = keccak256("primary_pool");
+ bytes32 internal constant SECONDARY_POOL_ID = keccak256("secondary_pool");
+ bytes32 internal constant INVALID_POOL_ID = keccak256("invalid_pool");
+ bytes32 internal constant ZERO_POOL_ID = bytes32(0);
+
+ //convenience arrays of all pool combinations used for testing
+ bytes32[] internal PRIMARY_POOL_ARRAY = [PRIMARY_POOL_ID];
+ bytes32[] internal SECONDARY_POOL_ARRAY = [SECONDARY_POOL_ID];
+ bytes32[] internal ALL_POOLS = [PRIMARY_POOL_ID, SECONDARY_POOL_ID];
+
+ //erc20 config
+ uint256 internal constant DEFAULT_MINT_QUANTITY = 100 ether;
+
+ //reward scalar (this should match the const in the contract)
+ uint64 internal constant POOL_SCALAR = 1e18;
+ uint64 internal constant ONE_PERCENT = POOL_SCALAR / 100;
+ uint64 internal constant FIFTY_PERCENT = POOL_SCALAR / 2;
+ uint64 internal constant TEN_PERCENT = POOL_SCALAR / 10;
+
+ //the selector for each error
+ bytes4 internal immutable UNAUTHORIZED_ERROR_SELECTOR = DestinationRewardManager.Unauthorized.selector;
+ bytes4 internal immutable INVALID_ADDRESS_ERROR_SELECTOR = DestinationRewardManager.InvalidAddress.selector;
+ bytes4 internal immutable INVALID_WEIGHT_ERROR_SELECTOR = DestinationRewardManager.InvalidWeights.selector;
+ bytes4 internal immutable INVALID_POOL_ID_ERROR_SELECTOR = DestinationRewardManager.InvalidPoolId.selector;
+ bytes internal constant ONLY_CALLABLE_BY_OWNER_ERROR = "Only callable by owner";
+ bytes4 internal immutable INVALID_POOL_LENGTH_SELECTOR = DestinationRewardManager.InvalidPoolLength.selector;
+
+ // Events emitted within the reward manager
+ event RewardRecipientsUpdated(bytes32 indexed poolId, Common.AddressAndWeight[] newRewardRecipients);
+ event RewardsClaimed(bytes32 indexed poolId, address indexed recipient, uint192 quantity);
+ event FeeManagerUpdated(address newProxyAddress);
+ event FeePaid(IDestinationRewardManager.FeePayment[] payments, address payee);
+
+ function setUp() public virtual {
+ //change to admin user
+ vm.startPrank(ADMIN);
+
+ //init required contracts
+ _initializeERC20Contracts();
+ _initializeRewardManager();
+ }
+
+ function _initializeERC20Contracts() internal {
+ //create the contracts
+ asset = new ERC20Mock("ASSET", "AST", ADMIN, 0);
+ unsupported = new ERC20Mock("UNSUPPORTED", "UNS", ADMIN, 0);
+
+ //mint some tokens to the admin
+ asset.mint(ADMIN, DEFAULT_MINT_QUANTITY);
+ unsupported.mint(ADMIN, DEFAULT_MINT_QUANTITY);
+
+ //mint some tokens to the user
+ asset.mint(FEE_MANAGER, DEFAULT_MINT_QUANTITY);
+ unsupported.mint(FEE_MANAGER, DEFAULT_MINT_QUANTITY);
+ }
+
+ function _initializeRewardManager() internal {
+ //create the contract
+ rewardManager = new DestinationRewardManager(address(asset));
+
+ rewardManager.addFeeManager(FEE_MANAGER);
+ }
+
+ function createPrimaryPool() public {
+ rewardManager.setRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients());
+ }
+
+ function createSecondaryPool() public {
+ rewardManager.setRewardRecipients(SECONDARY_POOL_ID, getSecondaryRecipients());
+ }
+
+ //override this to test variations of different recipients. changing this function will require existing tests to be updated as constants are hardcoded to be explicit
+ function getPrimaryRecipients() public virtual returns (Common.AddressAndWeight[] memory) {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+
+ //init each recipient with even weights. 2500 = 25% of pool
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, POOL_SCALAR / 4);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, POOL_SCALAR / 4);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, POOL_SCALAR / 4);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, POOL_SCALAR / 4);
+
+ return recipients;
+ }
+
+ function getPrimaryRecipientAddresses() public pure returns (address[] memory) {
+ //array of recipients
+ address[] memory recipients = new address[](4);
+
+ recipients[0] = DEFAULT_RECIPIENT_1;
+ recipients[1] = DEFAULT_RECIPIENT_2;
+ recipients[2] = DEFAULT_RECIPIENT_3;
+ recipients[3] = DEFAULT_RECIPIENT_4;
+
+ return recipients;
+ }
+
+ //override this to test variations of different recipients.
+ function getSecondaryRecipients() public virtual returns (Common.AddressAndWeight[] memory) {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+
+ //init each recipient with even weights. 2500 = 25% of pool
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, POOL_SCALAR / 4);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, POOL_SCALAR / 4);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_6, POOL_SCALAR / 4);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_7, POOL_SCALAR / 4);
+
+ return recipients;
+ }
+
+ function getSecondaryRecipientAddresses() public pure returns (address[] memory) {
+ //array of recipients
+ address[] memory recipients = new address[](4);
+
+ recipients[0] = DEFAULT_RECIPIENT_1;
+ recipients[1] = DEFAULT_RECIPIENT_5;
+ recipients[2] = DEFAULT_RECIPIENT_6;
+ recipients[3] = DEFAULT_RECIPIENT_7;
+
+ return recipients;
+ }
+
+ function addFundsToPool(bytes32 poolId, Common.Asset memory amount, address sender) public {
+ IDestinationRewardManager.FeePayment[] memory payments = new IDestinationRewardManager.FeePayment[](1);
+ payments[0] = IDestinationRewardManager.FeePayment(poolId, uint192(amount.amount));
+
+ addFundsToPool(payments, sender);
+ }
+
+ function addFundsToPool(IDestinationRewardManager.FeePayment[] memory payments, address sender) public {
+ //record the current address and switch to the sender
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ uint256 totalPayment;
+ for (uint256 i; i < payments.length; ++i) {
+ totalPayment += payments[i].amount;
+ }
+
+ //approve the amount being paid into the pool
+ ERC20Mock(address(asset)).approve(address(rewardManager), totalPayment);
+
+ //this represents the verifier adding some funds to the pool
+ rewardManager.onFeePaid(payments, sender);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function getAsset(uint256 quantity) public view returns (Common.Asset memory) {
+ return Common.Asset(address(asset), quantity);
+ }
+
+ function getAssetBalance(address addr) public view returns (uint256) {
+ return asset.balanceOf(addr);
+ }
+
+ function claimRewards(bytes32[] memory poolIds, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //claim the rewards
+ rewardManager.claimRewards(poolIds);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function payRecipients(bytes32 poolId, address[] memory recipients, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //pay the recipients
+ rewardManager.payRecipients(poolId, recipients);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function setRewardRecipients(bytes32 poolId, Common.AddressAndWeight[] memory recipients, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //pay the recipients
+ rewardManager.setRewardRecipients(poolId, recipients);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function setFeeManager(address feeManager, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //update the proxy
+ rewardManager.addFeeManager(feeManager);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function updateRewardRecipients(bytes32 poolId, Common.AddressAndWeight[] memory recipients, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //pay the recipients
+ rewardManager.updateRewardRecipients(poolId, recipients);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.claim.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.claim.t.sol
new file mode 100644
index 00000000000..c0a67d08758
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.claim.t.sol
@@ -0,0 +1,790 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseDestinationRewardManagerTest} from "./BaseDestinationRewardManager.t.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+/**
+ * @title DestinationRewardManagerClaimTest
+ * @author Michael Fletcher
+ * @notice This contract will test the claim functionality of the RewardManager contract.
+ */
+contract DestinationRewardManagerClaimTest is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+
+ //create a single pool for these tests
+ createPrimaryPool();
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ }
+
+ function test_claimAllRecipients() public {
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+ }
+
+ function test_claimRewardsWithDuplicatePoolIdsDoesNotPayoutTwice() public {
+ //add funds to a different pool to ensure they're not claimed
+ addFundsToPool(SECONDARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //create an array containing duplicate poolIds
+ bytes32[] memory poolIds = new bytes32[](2);
+ poolIds[0] = PRIMARY_POOL_ID;
+ poolIds[1] = PRIMARY_POOL_ID;
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(poolIds, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //the pool should still have the remaining
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_claimSingleRecipient() public {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[0];
+
+ //claim the individual rewards for this recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check the recipients balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+
+ //check the rewardManager has the remaining quantity
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT - expectedRecipientAmount);
+ }
+
+ function test_claimMultipleRecipients() public {
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, getPrimaryRecipients()[0].addr);
+ claimRewards(PRIMARY_POOL_ARRAY, getPrimaryRecipients()[1].addr);
+
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check the recipients balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(getPrimaryRecipients()[0].addr), expectedRecipientAmount);
+ assertEq(getAssetBalance(getPrimaryRecipients()[1].addr), expectedRecipientAmount);
+
+ //check the rewardManager has the remaining quantity
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT - (expectedRecipientAmount * 2));
+ }
+
+ function test_claimUnregisteredRecipient() public {
+ //claim the rewards for a recipient who isn't in this pool
+ claimRewards(PRIMARY_POOL_ARRAY, getSecondaryRecipients()[1].addr);
+
+ //check the recipients didn't receive any fees from this pool
+ assertEq(getAssetBalance(getSecondaryRecipients()[1].addr), 0);
+
+ //check the rewardManager has the remaining quantity
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_claimUnevenAmountRoundsDown() public {
+ //adding 1 to the pool should leave 1 wei worth of dust, which the contract doesn't handle due to it being economically infeasible
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(1), FEE_MANAGER);
+
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //check the rewardManager has the remaining quantity equals 1 wei
+ assertEq(getAssetBalance(address(rewardManager)), 1);
+ }
+
+ function test_claimUnregisteredPoolId() public {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[0];
+
+ //claim the individual rewards for this recipient
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //check the recipients balance is still 0 as there's no pool to receive fees from
+ assertEq(getAssetBalance(recipient.addr), 0);
+
+ //check the rewardManager has the full amount
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_singleRecipientClaimMultipleDeposits() public {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[0];
+
+ //claim the individual rewards for this recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check the recipients balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+
+ //check the rewardManager has the remaining quantity, which is 3/4 of the initial deposit
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT - expectedRecipientAmount);
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //claim the individual rewards for this recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the recipients balance matches the ratio the recipient should have received, which is 1/4 of each deposit
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount * 2);
+
+ //check the rewardManager has the remaining quantity, which is now 3/4 of both deposits
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT * 2 - (expectedRecipientAmount * 2));
+ }
+
+ function test_recipientsClaimMultipleDeposits() public {
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //the reward manager balance should be 0 as all of the funds have been claimed
+ assertEq(getAssetBalance(address(rewardManager)), 0);
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //expected recipient amount is 1/4 of the pool deposit
+ expectedRecipientAmount = (POOL_DEPOSIT_AMOUNT / 4) * 2;
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //the reward manager balance should again be 0 as all of the funds have been claimed
+ assertEq(getAssetBalance(address(rewardManager)), 0);
+ }
+
+ function test_eventIsEmittedUponClaim() public {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[0];
+
+ //expect an emit
+ vm.expectEmit();
+
+ //emit the event that is expected to be emitted
+ emit RewardsClaimed(PRIMARY_POOL_ID, recipient.addr, uint192(POOL_DEPOSIT_AMOUNT / 4));
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+ }
+
+ function test_eventIsNotEmittedUponUnsuccessfulClaim() public {
+ //record logs to check no events were emitted
+ vm.recordLogs();
+
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[0];
+
+ //claim the individual rewards for each recipient
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //no logs should have been emitted
+ assertEq(vm.getRecordedLogs().length, 0);
+ }
+}
+
+contract DestinationRewardManagerRecipientClaimMultiplePoolsTest is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+
+ //create a two pools
+ createPrimaryPool();
+ createSecondaryPool();
+
+ //add funds to each of the pools to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ addFundsToPool(SECONDARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ }
+
+ function test_claimAllRecipientsSinglePool() public {
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //check the pool balance is still equal to DEPOSIT_AMOUNT as the test only claims for one of the pools
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_claimMultipleRecipientsSinglePool() public {
+ //claim the individual rewards for each recipient
+ claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[0].addr);
+ claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[1].addr);
+
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check the recipients balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(getSecondaryRecipients()[0].addr), expectedRecipientAmount);
+ assertEq(getAssetBalance(getSecondaryRecipients()[1].addr), expectedRecipientAmount);
+
+ //check the rewardManager has the remaining quantity
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT * 2 - (expectedRecipientAmount * 2));
+ }
+
+ function test_claimMultipleRecipientsMultiplePools() public {
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, getPrimaryRecipients()[0].addr);
+ claimRewards(PRIMARY_POOL_ARRAY, getPrimaryRecipients()[1].addr);
+ claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[0].addr);
+ claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[1].addr);
+
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check the recipients balance matches the ratio the recipient should have received. The first recipient is shared across both pools so should receive 1/4 of each pool
+ assertEq(getAssetBalance(getPrimaryRecipients()[0].addr), expectedRecipientAmount * 2);
+ assertEq(getAssetBalance(getPrimaryRecipients()[1].addr), expectedRecipientAmount);
+ assertEq(getAssetBalance(getSecondaryRecipients()[1].addr), expectedRecipientAmount);
+
+ //check the rewardManager has the remaining quantity
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_claimAllRecipientsMultiplePools() public {
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //claim funds for each recipient within the pool
+ for (uint256 i = 1; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //claim funds for each recipient within the pool
+ for (uint256 i = 1; i < getSecondaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory secondaryRecipient = getSecondaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(SECONDARY_POOL_ARRAY, secondaryRecipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(secondaryRecipient.addr), expectedRecipientAmount);
+ }
+
+ //special case to handle the first recipient of each pool as they're the same address
+ Common.AddressAndWeight memory commonRecipient = getPrimaryRecipients()[0];
+
+ //claim the individual rewards for each pool
+ claimRewards(PRIMARY_POOL_ARRAY, commonRecipient.addr);
+ claimRewards(SECONDARY_POOL_ARRAY, commonRecipient.addr);
+
+ //check the balance matches the ratio the recipient should have received, which is 1/4 of each deposit for each pool
+ assertEq(getAssetBalance(commonRecipient.addr), expectedRecipientAmount * 2);
+ }
+
+ function test_claimSingleUniqueRecipient() public {
+ //the first recipient of the secondary pool is in both pools, so take the second recipient which is unique
+ Common.AddressAndWeight memory recipient = getSecondaryRecipients()[1];
+
+ //claim the individual rewards for this recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //the recipient should have received 1/4 of the deposit amount
+ uint256 recipientExpectedAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //the recipient should have received 1/4 of the deposit amount
+ assertEq(getAssetBalance(recipient.addr), recipientExpectedAmount);
+
+ //check the rewardManager has the remaining quantity
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT * 2 - recipientExpectedAmount);
+ }
+
+ function test_claimSingleRecipientMultiplePools() public {
+ //the first recipient of the secondary pool is in both pools
+ Common.AddressAndWeight memory recipient = getSecondaryRecipients()[0];
+
+ //claim the individual rewards for this recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //the recipient should have received 1/4 of the deposit amount for each pool
+ uint256 recipientExpectedAmount = (POOL_DEPOSIT_AMOUNT / 4) * 2;
+
+ //this recipient belongs in both pools so should have received 1/4 of each
+ assertEq(getAssetBalance(recipient.addr), recipientExpectedAmount);
+
+ //check the rewardManager has the remaining quantity
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT * 2 - recipientExpectedAmount);
+ }
+
+ function test_claimUnregisteredRecipient() public {
+ //claim the individual rewards for this recipient
+ claimRewards(PRIMARY_POOL_ARRAY, getSecondaryRecipients()[1].addr);
+ claimRewards(SECONDARY_POOL_ARRAY, getPrimaryRecipients()[1].addr);
+
+ //check the recipients didn't receive any fees from this pool
+ assertEq(getAssetBalance(getSecondaryRecipients()[1].addr), 0);
+ assertEq(getAssetBalance(getPrimaryRecipients()[1].addr), 0);
+
+ //check the rewardManager has the remaining quantity
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT * 2);
+ }
+
+ function test_claimUnevenAmountRoundsDown() public {
+ //adding an uneven amount of dust to each pool, this should round down to the nearest whole number with 4 remaining in the contract
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(3), FEE_MANAGER);
+ addFundsToPool(SECONDARY_POOL_ID, getAsset(1), FEE_MANAGER);
+
+ //the recipient should have received 1/4 of the deposit amount for each pool
+ uint256 recipientExpectedAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), recipientExpectedAmount);
+ }
+
+ //special case to handle the first recipient of each pool as they're the same address
+ claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[0].addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(getSecondaryRecipients()[0].addr), recipientExpectedAmount * 2);
+
+ //claim funds for each recipient of the secondary pool except the first
+ for (uint256 i = 1; i < getSecondaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getSecondaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), recipientExpectedAmount);
+ }
+
+ //contract should have 4 remaining
+ assertEq(getAssetBalance(address(rewardManager)), 4);
+ }
+
+ function test_singleRecipientClaimMultipleDeposits() public {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getSecondaryRecipients()[0];
+
+ //claim the individual rewards for this recipient
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //the recipient should have received 1/4 of the deposit amount
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check the recipients balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+
+ //check the rewardManager has the remaining quantity, which is 3/4 of the initial deposit plus the deposit from the second pool
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT * 2 - expectedRecipientAmount);
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(SECONDARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //claim the individual rewards for this recipient
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //the recipient should have received 1/4 of the next deposit amount
+ expectedRecipientAmount += POOL_DEPOSIT_AMOUNT / 4;
+
+ //check the recipients balance matches the ratio the recipient should have received, which is 1/4 of each deposit
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+
+ //check the rewardManager has the remaining quantity, which is now 3/4 of both deposits
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT * 3 - expectedRecipientAmount);
+ }
+
+ function test_recipientsClaimMultipleDeposits() public {
+ //the recipient should have received 1/4 of the deposit amount
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getSecondaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getSecondaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //the reward manager balance should contain only the funds of the secondary pool
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(SECONDARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //special case to handle the first recipient of each pool as they're the same address
+ claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[0].addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(getSecondaryRecipients()[0].addr), expectedRecipientAmount * 2);
+
+ //claim funds for each recipient within the pool except the first
+ for (uint256 i = 1; i < getSecondaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getSecondaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(SECONDARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount * 2);
+ }
+
+ //the reward manager balance should again be the balance of the secondary pool as the primary pool has been emptied twice
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_claimEmptyPoolWhenSecondPoolContainsFunds() public {
+ //the recipient should have received 1/4 of the deposit amount
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //claim all rewards for each recipient in the primary pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //claim all the rewards again for the first recipient as that address is a member of both pools
+ claimRewards(PRIMARY_POOL_ARRAY, getSecondaryRecipients()[0].addr);
+
+ //check the balance
+ assertEq(getAssetBalance(getSecondaryRecipients()[0].addr), expectedRecipientAmount);
+ }
+
+ function test_getRewardsAvailableToRecipientInBothPools() public {
+ //get index 0 as this recipient is in both default pools
+ bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(
+ getPrimaryRecipients()[0].addr,
+ 0,
+ type(uint256).max
+ );
+
+ //check the recipient is in both pools
+ assertEq(poolIds[0], PRIMARY_POOL_ID);
+ assertEq(poolIds[1], SECONDARY_POOL_ID);
+ }
+
+ function test_getRewardsAvailableToRecipientInSinglePool() public {
+ //get index 0 as this recipient is in both default pools
+ bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(
+ getPrimaryRecipients()[1].addr,
+ 0,
+ type(uint256).max
+ );
+
+ //check the recipient is in both pools
+ assertEq(poolIds[0], PRIMARY_POOL_ID);
+ assertEq(poolIds[1], ZERO_POOL_ID);
+ }
+
+ function test_getRewardsAvailableToRecipientInNoPools() public view {
+ //get index 0 as this recipient is in both default pools
+ bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(FEE_MANAGER, 0, type(uint256).max);
+
+ //check the recipient is in neither pool
+ assertEq(poolIds[0], ZERO_POOL_ID);
+ assertEq(poolIds[1], ZERO_POOL_ID);
+ }
+
+ function test_getRewardsAvailableToRecipientInBothPoolsWhereAlreadyClaimed() public {
+ //get index 0 as this recipient is in both default pools
+ bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(
+ getPrimaryRecipients()[0].addr,
+ 0,
+ type(uint256).max
+ );
+
+ //check the recipient is in both pools
+ assertEq(poolIds[0], PRIMARY_POOL_ID);
+ assertEq(poolIds[1], SECONDARY_POOL_ID);
+
+ //claim the rewards for each pool
+ claimRewards(PRIMARY_POOL_ARRAY, getPrimaryRecipients()[0].addr);
+ claimRewards(SECONDARY_POOL_ARRAY, getSecondaryRecipients()[0].addr);
+
+ //get the available pools again
+ poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 0, type(uint256).max);
+
+ //user should not be in any pool
+ assertEq(poolIds[0], ZERO_POOL_ID);
+ assertEq(poolIds[1], ZERO_POOL_ID);
+ }
+
+ function test_getAvailableRewardsCursorCannotBeGreaterThanTotalPools() public {
+ vm.expectRevert(INVALID_POOL_LENGTH_SELECTOR);
+
+ rewardManager.getAvailableRewardPoolIds(FEE_MANAGER, type(uint256).max, 0);
+ }
+
+ function test_getAvailableRewardsCursorAndTotalPoolsEqual() public {
+ bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 2, 2);
+
+ assertEq(poolIds.length, 0);
+ }
+
+ function test_getAvailableRewardsCursorSingleResult() public {
+ bytes32[] memory poolIds = rewardManager.getAvailableRewardPoolIds(getPrimaryRecipients()[0].addr, 0, 1);
+
+ assertEq(poolIds[0], PRIMARY_POOL_ID);
+ }
+}
+
+contract DestinationRewardManagerRecipientClaimDifferentWeightsTest is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+
+ //create a single pool for these tests
+ createPrimaryPool();
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ }
+
+ function getPrimaryRecipients() public virtual override returns (Common.AddressAndWeight[] memory) {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+
+ //init each recipient with uneven weights
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, TEN_PERCENT);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, TEN_PERCENT * 8);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, ONE_PERCENT * 6);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, ONE_PERCENT * 4);
+
+ return recipients;
+ }
+
+ function test_allRecipientsClaimingReceiveExpectedAmount() public {
+ //loop all the recipients and claim their expected amount
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //the recipient should have received a share proportional to their weight
+ uint256 expectedRecipientAmount = (POOL_DEPOSIT_AMOUNT * recipient.weight) / POOL_SCALAR;
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+ }
+}
+
+contract DestinationRewardManagerRecipientClaimUnevenWeightTest is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+
+ //create a single pool for these tests
+ createPrimaryPool();
+ }
+
+ function getPrimaryRecipients() public virtual override returns (Common.AddressAndWeight[] memory) {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](2);
+
+ uint64 oneThird = POOL_SCALAR / 3;
+
+ //init each recipient with even weights.
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, oneThird);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, 2 * oneThird + 1);
+
+ return recipients;
+ }
+
+ function test_allRecipientsClaimingReceiveExpectedAmountWithSmallDeposit() public {
+ //add a smaller amount of funds to the pool
+ uint256 smallDeposit = 1e8;
+
+ //add a smaller amount of funds to the pool
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(smallDeposit), FEE_MANAGER);
+
+ //loop all the recipients and claim their expected amount
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //the recipient should have received a share proportional to their weight
+ uint256 expectedRecipientAmount = (smallDeposit * recipient.weight) / POOL_SCALAR;
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //smaller deposits will consequently have less precision and will not be able to be split as evenly, the remaining 1 will be lost due to 333...|... being paid out instead of 333...4|
+ assertEq(getAssetBalance(address(rewardManager)), 1);
+ }
+
+ function test_allRecipientsClaimingReceiveExpectedAmount() public {
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //loop all the recipients and claim their expected amount
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //claim the individual rewards for each recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //the recipient should have received a share proportional to their weight
+ uint256 expectedRecipientAmount = (POOL_DEPOSIT_AMOUNT * recipient.weight) / POOL_SCALAR;
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+
+ //their should be 0 wei left over indicating a successful split
+ assertEq(getAssetBalance(address(rewardManager)), 0);
+ }
+}
+
+contract DestinationRewardManagerNoRecipientSet is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+
+ //add funds to the pool to be split among the recipients once registered
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ }
+
+ function test_claimAllRecipientsAfterRecipientsSet() public {
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //try and claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //there should be no rewards claimed as the recipient is not registered
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the recipient received nothing
+ assertEq(getAssetBalance(recipient.addr), 0);
+ }
+
+ //Set the recipients after the rewards have been paid into the pool
+ setRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), ADMIN);
+
+ //claim funds for each recipient within the pool
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //get the recipient that is claiming
+ Common.AddressAndWeight memory recipient = getPrimaryRecipients()[i];
+
+ //there should be no rewards claimed as the recipient is registered
+ claimRewards(PRIMARY_POOL_ARRAY, recipient.addr);
+
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipient.addr), expectedRecipientAmount);
+ }
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.general.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.general.t.sol
new file mode 100644
index 00000000000..4c79d2cba5e
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.general.t.sol
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseDestinationRewardManagerTest} from "./BaseDestinationRewardManager.t.sol";
+import {DestinationRewardManager} from "../../../v0.4.0/DestinationRewardManager.sol";
+import {ERC20Mock} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
+import {IDestinationRewardManager} from "../../interfaces/IDestinationRewardManager.sol";
+
+/**
+ * @title DestinationRewardManagerSetupTest
+ * @author Michael Fletcher
+ * @notice This contract will test the core functionality of the DestinationRewardManager contract
+ */
+contract DestinationRewardManagerSetupTest is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+ }
+
+ function test_rejectsZeroLinkAddressOnConstruction() public {
+ //should revert if the contract is a zero address
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+
+ //create a rewardManager with a zero link address
+ new DestinationRewardManager(address(0));
+ }
+
+ function test_eventEmittedUponFeeManagerUpdate() public {
+ //expect the event to be emitted
+ vm.expectEmit();
+
+ //emit the event that is expected to be emitted
+ emit FeeManagerUpdated(FEE_MANAGER_2);
+
+ //set the verifier proxy
+ setFeeManager(FEE_MANAGER_2, ADMIN);
+ }
+
+ function test_eventEmittedUponFeePaid() public {
+ //create pool and add funds
+ createPrimaryPool();
+
+ //change to the feeManager who is the one who will be paying the fees
+ changePrank(FEE_MANAGER);
+
+ //approve the amount being paid into the pool
+ ERC20Mock(getAsset(POOL_DEPOSIT_AMOUNT).assetAddress).approve(address(rewardManager), POOL_DEPOSIT_AMOUNT);
+
+ IDestinationRewardManager.FeePayment[] memory payments = new IDestinationRewardManager.FeePayment[](1);
+ payments[0] = IDestinationRewardManager.FeePayment(PRIMARY_POOL_ID, uint192(POOL_DEPOSIT_AMOUNT));
+
+ //event is emitted when funds are added
+ vm.expectEmit();
+ emit FeePaid(payments, FEE_MANAGER);
+
+ //this represents the verifier adding some funds to the pool
+ rewardManager.onFeePaid(payments, FEE_MANAGER);
+ }
+
+ function test_setFeeManagerZeroAddress() public {
+ //should revert if the contract is a zero address
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+
+ //set the verifier proxy
+ setFeeManager(address(0), ADMIN);
+ }
+
+ function test_addFeeManagerZeroAddress() public {
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+ rewardManager.addFeeManager(address(0));
+ }
+
+ function test_addFeeManagerExistingAddress() public {
+ address dummyAddress = address(998);
+ rewardManager.addFeeManager(dummyAddress);
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+ rewardManager.addFeeManager(dummyAddress);
+ }
+
+ function test_removeFeeManagerNonExistentAddress() public {
+ address dummyAddress = address(991);
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+ rewardManager.removeFeeManager(dummyAddress);
+ }
+
+ function test_addRemoveFeeManager() public {
+ address dummyAddress1 = address(1);
+ address dummyAddress2 = address(2);
+ rewardManager.addFeeManager(dummyAddress1);
+ rewardManager.addFeeManager(dummyAddress2);
+ assertEq(rewardManager.s_feeManagerAddressList(dummyAddress1), dummyAddress1);
+ assertEq(rewardManager.s_feeManagerAddressList(dummyAddress2), dummyAddress2);
+ rewardManager.removeFeeManager(dummyAddress1);
+ assertEq(rewardManager.s_feeManagerAddressList(dummyAddress1), address(0));
+ assertEq(rewardManager.s_feeManagerAddressList(dummyAddress2), dummyAddress2);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.payRecipients.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.payRecipients.t.sol
new file mode 100644
index 00000000000..4aa3c868b35
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.payRecipients.t.sol
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseDestinationRewardManagerTest} from "./BaseDestinationRewardManager.t.sol";
+import {IDestinationRewardManager} from "../../interfaces/IDestinationRewardManager.sol";
+
+/**
+ * @title DestinationRewardManagerPayRecipientsTest
+ * @author Michael Fletcher
+ * @notice This contract will test the payRecipients functionality of the RewardManager contract
+ */
+contract DestinationRewardManagerPayRecipientsTest is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+
+ //create a single pool for these tests
+ createPrimaryPool();
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ }
+
+ function test_payAllRecipients() public {
+ //pay all the recipients in the pool
+ payRecipients(PRIMARY_POOL_ID, getPrimaryRecipientAddresses(), ADMIN);
+
+ //each recipient should receive 1/4 of the pool
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check each recipient received the correct amount
+ for (uint256 i = 0; i < getPrimaryRecipientAddresses().length; i++) {
+ assertEq(getAssetBalance(getPrimaryRecipientAddresses()[i]), expectedRecipientAmount);
+ }
+ }
+
+ function test_paySingleRecipient() public {
+ //get the first individual recipient
+ address recipient = getPrimaryRecipientAddresses()[0];
+
+ //get a single recipient as an array
+ address[] memory recipients = new address[](1);
+ recipients[0] = recipient;
+
+ //pay a single recipient
+ payRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //the recipient should have received 1/4 of the deposit amount
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ assertEq(getAssetBalance(recipient), expectedRecipientAmount);
+ }
+
+ function test_payRecipientWithInvalidPool() public {
+ //get the first individual recipient
+ address recipient = getPrimaryRecipientAddresses()[0];
+
+ //get a single recipient as an array
+ address[] memory recipients = new address[](1);
+ recipients[0] = recipient;
+
+ //pay a single recipient
+ payRecipients(SECONDARY_POOL_ID, recipients, ADMIN);
+
+ //the recipient should have received nothing
+ assertEq(getAssetBalance(recipient), 0);
+ }
+
+ function test_payRecipientsEmptyRecipientList() public {
+ //get a single recipient
+ address[] memory recipients = new address[](0);
+
+ //pay a single recipient
+ payRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //rewardManager should have the full balance
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_payAllRecipientsWithAdditionalUnregisteredRecipient() public {
+ //load all the recipients and add an additional one who is not in the pool
+ address[] memory recipients = new address[](getPrimaryRecipientAddresses().length + 1);
+ for (uint256 i = 0; i < getPrimaryRecipientAddresses().length; i++) {
+ recipients[i] = getPrimaryRecipientAddresses()[i];
+ }
+ recipients[recipients.length - 1] = DEFAULT_RECIPIENT_5;
+
+ //pay the recipients
+ payRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //each recipient should receive 1/4 of the pool except the last
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check each recipient received the correct amount
+ for (uint256 i = 0; i < getPrimaryRecipientAddresses().length; i++) {
+ assertEq(getAssetBalance(getPrimaryRecipientAddresses()[i]), expectedRecipientAmount);
+ }
+
+ //the unregistered recipient should receive nothing
+ assertEq(getAssetBalance(DEFAULT_RECIPIENT_5), 0);
+ }
+
+ function test_payAllRecipientsWithAdditionalInvalidRecipient() public {
+ //load all the recipients and add an additional one which is invalid, that should receive nothing
+ address[] memory recipients = new address[](getPrimaryRecipientAddresses().length + 1);
+ for (uint256 i = 0; i < getPrimaryRecipientAddresses().length; i++) {
+ recipients[i] = getPrimaryRecipientAddresses()[i];
+ }
+ recipients[recipients.length - 1] = INVALID_ADDRESS;
+
+ //pay the recipients
+ payRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //each recipient should receive 1/4 of the pool except the last
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check each recipient received the correct amount
+ for (uint256 i = 0; i < getPrimaryRecipientAddresses().length; i++) {
+ assertEq(getAssetBalance(getPrimaryRecipientAddresses()[i]), expectedRecipientAmount);
+ }
+ }
+
+ function test_paySubsetOfRecipientsInPool() public {
+ //load a subset of the recipients into an array
+ address[] memory recipients = new address[](getPrimaryRecipientAddresses().length - 1);
+ for (uint256 i = 0; i < recipients.length; i++) {
+ recipients[i] = getPrimaryRecipientAddresses()[i];
+ }
+
+ //pay the subset of recipients
+ payRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //each recipient should receive 1/4 of the pool except the last
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check each subset of recipients received the correct amount
+ for (uint256 i = 0; i < recipients.length - 1; i++) {
+ assertEq(getAssetBalance(recipients[i]), expectedRecipientAmount);
+ }
+
+ //check the pool has the remaining balance
+ assertEq(
+ getAssetBalance(address(rewardManager)),
+ POOL_DEPOSIT_AMOUNT - expectedRecipientAmount * recipients.length
+ );
+ }
+
+ function test_payAllRecipientsFromNonAdminUser() public {
+ //should revert if the caller isn't an admin or recipient within the pool
+ vm.expectRevert(UNAUTHORIZED_ERROR_SELECTOR);
+
+ //pay all the recipients in the pool
+ payRecipients(PRIMARY_POOL_ID, getPrimaryRecipientAddresses(), FEE_MANAGER);
+ }
+
+ function test_payAllRecipientsFromRecipientInPool() public {
+ //pay all the recipients in the pool
+ payRecipients(PRIMARY_POOL_ID, getPrimaryRecipientAddresses(), DEFAULT_RECIPIENT_1);
+
+ //each recipient should receive 1/4 of the pool
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //check each recipient received the correct amount
+ for (uint256 i = 0; i < getPrimaryRecipientAddresses().length; i++) {
+ assertEq(getAssetBalance(getPrimaryRecipientAddresses()[i]), expectedRecipientAmount);
+ }
+ }
+
+ function test_payRecipientsWithInvalidPoolId() public {
+ //pay all the recipients in the pool
+ payRecipients(INVALID_POOL_ID, getPrimaryRecipientAddresses(), ADMIN);
+
+ //pool should still contain the full balance
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_addFundsToPoolAsOwner() public {
+ //add funds to the pool
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ }
+
+ function test_addFundsToPoolAsNonOwnerOrFeeManager() public {
+ //should revert if the caller isn't an admin or recipient within the pool
+ vm.expectRevert(UNAUTHORIZED_ERROR_SELECTOR);
+
+ IDestinationRewardManager.FeePayment[] memory payments = new IDestinationRewardManager.FeePayment[](1);
+ payments[0] = IDestinationRewardManager.FeePayment(PRIMARY_POOL_ID, uint192(POOL_DEPOSIT_AMOUNT));
+
+ //add funds to the pool
+ rewardManager.onFeePaid(payments, USER);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.setRecipients.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.setRecipients.t.sol
new file mode 100644
index 00000000000..facbaa1ab77
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.setRecipients.t.sol
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseDestinationRewardManagerTest} from "./BaseDestinationRewardManager.t.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+/**
+ * @title DestinationRewardManagerSetRecipientsTest
+ * @author Michael Fletcher
+ * @notice This contract will test the setRecipient functionality of the RewardManager contract
+ */
+contract DestinationRewardManagerSetRecipientsTest is BaseDestinationRewardManagerTest {
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+ }
+
+ function test_setRewardRecipients() public {
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), ADMIN);
+ }
+
+ function test_setRewardRecipientsIsEmpty() public {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+
+ //should revert if the recipients array is empty
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_setRewardRecipientWithZeroWeight() public {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](5);
+
+ //init each recipient with even weights
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, ONE_PERCENT * 25);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, ONE_PERCENT * 25);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, ONE_PERCENT * 25);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, ONE_PERCENT * 25);
+ recipients[4] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, 0);
+
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_setRewardRecipientWithZeroAddress() public {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = getPrimaryRecipients();
+
+ //override the first recipient with a zero address
+ recipients[0].addr = address(0);
+
+ //should revert if the recipients array is empty
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_setRewardRecipientWeights() public {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+
+ //init each recipient with even weights
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, 25);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, 25);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, 25);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, 25);
+
+ //should revert if the recipients array is empty
+ vm.expectRevert(INVALID_WEIGHT_ERROR_SELECTOR);
+
+ //set the recipients with a recipient with a weight of 100%
+ setRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_setSingleRewardRecipient() public {
+ //array of recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](1);
+
+ //init each recipient with even weights
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, POOL_SCALAR);
+
+ //set the recipients with a recipient with a weight of 100%
+ setRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_setRewardRecipientTwice() public {
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), ADMIN);
+
+ //should revert if recipients for this pool have already been set
+ vm.expectRevert(INVALID_POOL_ID_ERROR_SELECTOR);
+
+ //set the recipients again
+ setRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), ADMIN);
+ }
+
+ function test_setRewardRecipientFromNonOwnerOrFeeManagerAddress() public {
+ //should revert if the sender is not the owner or proxy
+ vm.expectRevert(UNAUTHORIZED_ERROR_SELECTOR);
+
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), USER);
+ }
+
+ function test_setRewardRecipientFromManagerAddress() public {
+ //update the proxy address
+ setFeeManager(FEE_MANAGER_2, ADMIN);
+
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), FEE_MANAGER_2);
+ }
+
+ function test_eventIsEmittedUponSetRecipients() public {
+ //expect an emit
+ vm.expectEmit();
+
+ //emit the event that is expected to be emitted
+ emit RewardRecipientsUpdated(PRIMARY_POOL_ID, getPrimaryRecipients());
+
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), ADMIN);
+ }
+
+ function test_setRecipientContainsDuplicateRecipients() public {
+ //create a new array to hold the existing recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](getPrimaryRecipients().length * 2);
+
+ //add all the existing recipients
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ recipients[i] = getPrimaryRecipients()[i];
+ }
+ //add all the existing recipients again
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ recipients[i + getPrimaryRecipients().length] = getPrimaryRecipients()[i];
+ }
+
+ //should revert as the list contains a duplicate
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+
+ //set the recipients
+ setRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.updateRewardRecipients.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.updateRewardRecipients.t.sol
new file mode 100644
index 00000000000..226be8ed325
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/reward-manager/DestinationRewardManager.updateRewardRecipients.t.sol
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseDestinationRewardManagerTest} from "./BaseDestinationRewardManager.t.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+/**
+ * @title DestinationRewardManagerUpdateRewardRecipientsTest
+ * @author Michael Fletcher
+ * @notice This contract will test the updateRecipient functionality of the RewardManager contract
+ */
+contract DestinationRewardManagerUpdateRewardRecipientsTest is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+
+ //create a single pool for these tests
+ createPrimaryPool();
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ }
+
+ function test_onlyAdminCanUpdateRecipients() public {
+ //should revert if the caller is not the admin
+ vm.expectRevert(ONLY_CALLABLE_BY_OWNER_ERROR);
+
+ //updating a recipient should force the funds to be paid out
+ updateRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), FEE_MANAGER);
+ }
+
+ function test_updateAllRecipientsWithSameAddressAndWeight() public {
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //updating a recipient should force the funds to be paid out
+ updateRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), ADMIN);
+
+ //check each recipient received the correct amount
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(getPrimaryRecipients()[i].addr), expectedRecipientAmount);
+ }
+ }
+
+ function test_updatePartialRecipientsWithSameAddressAndWeight() public {
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //get a subset of the recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](2);
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, ONE_PERCENT * 25);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, ONE_PERCENT * 25);
+
+ //updating a recipient should force the funds to be paid out
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //check each recipient received the correct amount
+ for (uint256 i; i < recipients.length; i++) {
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipients[i].addr), expectedRecipientAmount);
+ }
+
+ //the reward manager should still have half remaining funds
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT / 2);
+ }
+
+ function test_updateRecipientWithNewZeroAddress() public {
+ //create a new array to hold the existing recipients plus a new zero address
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](getPrimaryRecipients().length + 1);
+
+ //add all the existing recipients
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ recipients[i] = getPrimaryRecipients()[i];
+ }
+ //add a new address to the primary recipients
+ recipients[recipients.length - 1] = Common.AddressAndWeight(address(0), 0);
+
+ //should revert if the recipient is a zero address
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+
+ //update the recipients with invalid address
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updateRecipientsContainsDuplicateRecipients() public {
+ //create a new array to hold the existing recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](getPrimaryRecipients().length * 2);
+
+ //add all the existing recipients
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ recipients[i] = getPrimaryRecipients()[i];
+ }
+ //add all the existing recipients again
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ recipients[i + getPrimaryRecipients().length] = getPrimaryRecipients()[i];
+ }
+
+ //should revert as the list contains a duplicate
+ vm.expectRevert(INVALID_ADDRESS_ERROR_SELECTOR);
+
+ //update the recipients with the duplicate addresses
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updateRecipientsToDifferentSet() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](getPrimaryRecipients().length + 4);
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //copy the recipient and set the weight to 0 which implies the recipient is being replaced
+ recipients[i] = Common.AddressAndWeight(getPrimaryRecipients()[i].addr, 0);
+ }
+
+ //add the new recipients individually
+ recipients[4] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, ONE_PERCENT * 25);
+ recipients[5] = Common.AddressAndWeight(DEFAULT_RECIPIENT_6, ONE_PERCENT * 25);
+ recipients[6] = Common.AddressAndWeight(DEFAULT_RECIPIENT_7, ONE_PERCENT * 25);
+ recipients[7] = Common.AddressAndWeight(DEFAULT_RECIPIENT_8, ONE_PERCENT * 25);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updateRecipientsToDifferentPartialSet() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](getPrimaryRecipients().length + 2);
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //copy the recipient and set the weight to 0 which implies the recipient is being replaced
+ recipients[i] = Common.AddressAndWeight(getPrimaryRecipients()[i].addr, 0);
+ }
+
+ //add the new recipients individually
+ recipients[4] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, FIFTY_PERCENT);
+ recipients[5] = Common.AddressAndWeight(DEFAULT_RECIPIENT_6, FIFTY_PERCENT);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updateRecipientsToDifferentLargerSet() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](getPrimaryRecipients().length + 5);
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //copy the recipient and set the weight to 0 which implies the recipient is being replaced
+ recipients[i] = Common.AddressAndWeight(getPrimaryRecipients()[i].addr, 0);
+ }
+
+ //add the new recipients individually
+ recipients[4] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, TEN_PERCENT * 2);
+ recipients[5] = Common.AddressAndWeight(DEFAULT_RECIPIENT_6, TEN_PERCENT * 2);
+ recipients[6] = Common.AddressAndWeight(DEFAULT_RECIPIENT_7, TEN_PERCENT * 2);
+ recipients[7] = Common.AddressAndWeight(DEFAULT_RECIPIENT_8, TEN_PERCENT * 2);
+ recipients[8] = Common.AddressAndWeight(DEFAULT_RECIPIENT_9, TEN_PERCENT * 2);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updateRecipientsUpdateAndRemoveExistingForLargerSet() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](9);
+
+ //update the existing recipients
+ recipients[0] = Common.AddressAndWeight(getPrimaryRecipients()[0].addr, 0);
+ recipients[1] = Common.AddressAndWeight(getPrimaryRecipients()[1].addr, 0);
+ recipients[2] = Common.AddressAndWeight(getPrimaryRecipients()[2].addr, TEN_PERCENT * 3);
+ recipients[3] = Common.AddressAndWeight(getPrimaryRecipients()[3].addr, TEN_PERCENT * 3);
+
+ //add the new recipients individually
+ recipients[4] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, TEN_PERCENT);
+ recipients[5] = Common.AddressAndWeight(DEFAULT_RECIPIENT_6, TEN_PERCENT);
+ recipients[6] = Common.AddressAndWeight(DEFAULT_RECIPIENT_7, TEN_PERCENT);
+ recipients[7] = Common.AddressAndWeight(DEFAULT_RECIPIENT_8, TEN_PERCENT);
+ recipients[8] = Common.AddressAndWeight(DEFAULT_RECIPIENT_9, TEN_PERCENT);
+
+ //should revert as the weight does not equal 100%
+ vm.expectRevert(INVALID_WEIGHT_ERROR_SELECTOR);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updateRecipientsUpdateAndRemoveExistingForSmallerSet() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](5);
+
+ //update the existing recipients
+ recipients[0] = Common.AddressAndWeight(getPrimaryRecipients()[0].addr, 0);
+ recipients[1] = Common.AddressAndWeight(getPrimaryRecipients()[1].addr, 0);
+ recipients[2] = Common.AddressAndWeight(getPrimaryRecipients()[2].addr, TEN_PERCENT * 3);
+ recipients[3] = Common.AddressAndWeight(getPrimaryRecipients()[3].addr, TEN_PERCENT * 2);
+
+ //add the new recipients individually
+ recipients[4] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, TEN_PERCENT * 5);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updateRecipientsToDifferentSetWithInvalidWeights() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](getPrimaryRecipients().length + 2);
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //copy the recipient and set the weight to 0 which implies the recipient is being replaced
+ recipients[i] = Common.AddressAndWeight(getPrimaryRecipients()[i].addr, 0);
+ }
+
+ //add the new recipients individually
+ recipients[4] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, TEN_PERCENT * 5);
+ recipients[5] = Common.AddressAndWeight(DEFAULT_RECIPIENT_6, TEN_PERCENT);
+
+ //should revert as the weight will not equal 100%
+ vm.expectRevert(INVALID_WEIGHT_ERROR_SELECTOR);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updatePartialRecipientsToSubset() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, 0);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, 0);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, TEN_PERCENT * 5);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, TEN_PERCENT * 5);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updatePartialRecipientsWithUnderWeightSet() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, TEN_PERCENT);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, TEN_PERCENT);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, TEN_PERCENT);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, TEN_PERCENT);
+
+ //should revert as the new weights exceed the previous weights being replaced
+ vm.expectRevert(INVALID_WEIGHT_ERROR_SELECTOR);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updatePartialRecipientsWithExcessiveWeight() public {
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, TEN_PERCENT);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, TEN_PERCENT);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, TEN_PERCENT);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, POOL_SCALAR);
+
+ //should revert as the new weights exceed the previous weights being replaced
+ vm.expectRevert(INVALID_WEIGHT_ERROR_SELECTOR);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+ }
+
+ function test_updateRecipientWeights() public {
+ //expected recipient amount is 1/4 of the pool deposit for original recipients
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //create a list of containing recipients from the primary configured set with their new weights
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, TEN_PERCENT);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, TEN_PERCENT);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, TEN_PERCENT * 3);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, TEN_PERCENT * 5);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //check each recipient received the correct amount
+ for (uint256 i; i < recipients.length; i++) {
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipients[i].addr), expectedRecipientAmount);
+ }
+
+ //the reward manager should have no funds remaining
+ assertEq(getAssetBalance(address(rewardManager)), 0);
+
+ //add more funds to the pool to check new distribution
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //loop each user and claim the rewards
+ for (uint256 i; i < recipients.length; i++) {
+ //claim the rewards for this recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipients[i].addr);
+ }
+
+ //manually check the balance of each recipient
+ assertEq(
+ getAssetBalance(DEFAULT_RECIPIENT_1),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT) / POOL_SCALAR + expectedRecipientAmount
+ );
+ assertEq(
+ getAssetBalance(DEFAULT_RECIPIENT_2),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT) / POOL_SCALAR + expectedRecipientAmount
+ );
+ assertEq(
+ getAssetBalance(DEFAULT_RECIPIENT_3),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT * 3) / POOL_SCALAR + expectedRecipientAmount
+ );
+ assertEq(
+ getAssetBalance(DEFAULT_RECIPIENT_4),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT * 5) / POOL_SCALAR + expectedRecipientAmount
+ );
+ }
+
+ function test_partialUpdateRecipientWeights() public {
+ //expected recipient amount is 1/4 of the pool deposit for original recipients
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //create a list of containing recipients from the primary configured set with their new weights
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](2);
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, TEN_PERCENT);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, TEN_PERCENT * 4);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //check each recipient received the correct amount
+ for (uint256 i; i < recipients.length; i++) {
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipients[i].addr), expectedRecipientAmount);
+ }
+
+ //the reward manager should have half the funds remaining
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT / 2);
+
+ //add more funds to the pool to check new distribution
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //loop each user and claim the rewards
+ for (uint256 i; i < recipients.length; i++) {
+ //claim the rewards for this recipient
+ claimRewards(PRIMARY_POOL_ARRAY, recipients[i].addr);
+ }
+
+ //manually check the balance of each recipient
+ assertEq(
+ getAssetBalance(DEFAULT_RECIPIENT_1),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT) / POOL_SCALAR + expectedRecipientAmount
+ );
+ assertEq(
+ getAssetBalance(DEFAULT_RECIPIENT_2),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT * 4) / POOL_SCALAR + expectedRecipientAmount
+ );
+
+ //the reward manager should have half the funds remaining
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+ }
+
+ function test_eventIsEmittedUponUpdateRecipients() public {
+ //expect an emit
+ vm.expectEmit();
+
+ //emit the event that is expected to be emitted
+ emit RewardRecipientsUpdated(PRIMARY_POOL_ID, getPrimaryRecipients());
+
+ //expected recipient amount is 1/4 of the pool deposit
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //updating a recipient should force the funds to be paid out
+ updateRewardRecipients(PRIMARY_POOL_ID, getPrimaryRecipients(), ADMIN);
+
+ //check each recipient received the correct amount
+ for (uint256 i; i < getPrimaryRecipients().length; i++) {
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(getPrimaryRecipients()[i].addr), expectedRecipientAmount);
+ }
+ }
+}
+
+contract DestinationRewardManagerUpdateRewardRecipientsMultiplePoolsTest is BaseDestinationRewardManagerTest {
+ uint256 internal constant POOL_DEPOSIT_AMOUNT = 10e18;
+
+ function setUp() public override {
+ //setup contracts
+ super.setUp();
+
+ //create a single pool for these tests
+ createPrimaryPool();
+ createSecondaryPool();
+
+ //add funds to the pool to be split among the recipients
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ addFundsToPool(SECONDARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+ }
+
+ function getSecondaryRecipients() public override returns (Common.AddressAndWeight[] memory) {
+ //for testing purposes, the primary and secondary pool to contain the same recipients
+ return getPrimaryRecipients();
+ }
+
+ function test_updatePrimaryRecipientWeights() public {
+ //expected recipient amount is 1/4 of the pool deposit for original recipients
+ uint256 expectedRecipientAmount = POOL_DEPOSIT_AMOUNT / 4;
+
+ //create a list of containing recipients from the primary configured set, and new recipients
+ Common.AddressAndWeight[] memory recipients = new Common.AddressAndWeight[](4);
+ recipients[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, TEN_PERCENT * 4);
+ recipients[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, TEN_PERCENT * 4);
+ recipients[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, TEN_PERCENT);
+ recipients[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, TEN_PERCENT);
+
+ //updating a recipient should force the funds to be paid out for the primary recipients
+ updateRewardRecipients(PRIMARY_POOL_ID, recipients, ADMIN);
+
+ //check each recipient received the correct amount
+ for (uint256 i; i < recipients.length; i++) {
+ //check the balance matches the ratio the recipient should have received
+ assertEq(getAssetBalance(recipients[i].addr), expectedRecipientAmount);
+ }
+
+ //the reward manager should still have the funds for the secondary pool
+ assertEq(getAssetBalance(address(rewardManager)), POOL_DEPOSIT_AMOUNT);
+
+ //add more funds to the pool to check new distribution
+ addFundsToPool(PRIMARY_POOL_ID, getAsset(POOL_DEPOSIT_AMOUNT), FEE_MANAGER);
+
+ //claim the rewards for the updated recipients manually
+ claimRewards(PRIMARY_POOL_ARRAY, recipients[0].addr);
+ claimRewards(PRIMARY_POOL_ARRAY, recipients[1].addr);
+ claimRewards(PRIMARY_POOL_ARRAY, recipients[2].addr);
+ claimRewards(PRIMARY_POOL_ARRAY, recipients[3].addr);
+
+ //check the balance matches the ratio the recipient who were updated should have received
+ assertEq(
+ getAssetBalance(recipients[0].addr),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT * 4) / POOL_SCALAR + expectedRecipientAmount
+ );
+ assertEq(
+ getAssetBalance(recipients[1].addr),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT * 4) / POOL_SCALAR + expectedRecipientAmount
+ );
+ assertEq(
+ getAssetBalance(recipients[2].addr),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT) / POOL_SCALAR + expectedRecipientAmount
+ );
+ assertEq(
+ getAssetBalance(recipients[3].addr),
+ (POOL_DEPOSIT_AMOUNT * TEN_PERCENT) / POOL_SCALAR + expectedRecipientAmount
+ );
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/BaseDestinationVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/BaseDestinationVerifierTest.t.sol
new file mode 100644
index 00000000000..ec3b3a0eed7
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/BaseDestinationVerifierTest.t.sol
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {Test} from "forge-std/Test.sol";
+import {DestinationVerifierProxy} from "../../DestinationVerifierProxy.sol";
+import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+import {IDestinationVerifier} from "../../interfaces/IDestinationVerifier.sol";
+import {IDestinationVerifierProxy} from "../../interfaces/IDestinationVerifierProxy.sol";
+import {DestinationVerifier} from "../../DestinationVerifier.sol";
+import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
+import {DestinationFeeManager} from "../../DestinationFeeManager.sol";
+import {Common} from "../../../libraries/Common.sol";
+import {ERC20Mock} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/mocks/ERC20Mock.sol";
+import {WERC20Mock} from "../../../../shared/mocks/WERC20Mock.sol";
+import {DestinationRewardManager} from "../../DestinationRewardManager.sol";
+import {IDestinationRewardManager} from "../../interfaces/IDestinationRewardManager.sol";
+
+contract BaseTest is Test {
+ uint64 internal constant POOL_SCALAR = 1e18;
+ uint64 internal constant ONE_PERCENT = POOL_SCALAR / 100;
+ uint256 internal constant MAX_ORACLES = 31;
+ address internal constant ADMIN = address(1);
+ address internal constant USER = address(2);
+
+ address internal constant MOCK_VERIFIER_ADDRESS = address(100);
+ address internal constant ACCESS_CONTROLLER_ADDRESS = address(300);
+
+ uint256 internal constant DEFAULT_REPORT_LINK_FEE = 1e10;
+ uint256 internal constant DEFAULT_REPORT_NATIVE_FEE = 1e12;
+
+ uint64 internal constant VERIFIER_VERSION = 1;
+
+ uint8 internal constant FAULT_TOLERANCE = 10;
+
+ DestinationVerifierProxy internal s_verifierProxy;
+ DestinationVerifier internal s_verifier;
+ DestinationFeeManager internal feeManager;
+ DestinationRewardManager internal rewardManager;
+ ERC20Mock internal link;
+ WERC20Mock internal native;
+
+ struct Signer {
+ uint256 mockPrivateKey;
+ address signerAddress;
+ }
+
+ Signer[MAX_ORACLES] internal s_signers;
+ bytes32[] internal s_offchaintransmitters;
+ bool private s_baseTestInitialized;
+
+ struct V3Report {
+ // The feed ID the report has data for
+ bytes32 feedId;
+ // The time the median value was observed on
+ uint32 observationsTimestamp;
+ // The timestamp the report is valid from
+ uint32 validFromTimestamp;
+ // The link fee
+ uint192 linkFee;
+ // The native fee
+ uint192 nativeFee;
+ // The expiry of the report
+ uint32 expiresAt;
+ // The median value agreed in an OCR round
+ int192 benchmarkPrice;
+ // The best bid value agreed in an OCR round
+ int192 bid;
+ // The best ask value agreed in an OCR round
+ int192 ask;
+ }
+
+ bytes32 internal constant V_MASK = 0x0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
+ bytes32 internal constant V1_BITMASK = 0x0001000000000000000000000000000000000000000000000000000000000000;
+ bytes32 internal constant V2_BITMASK = 0x0002000000000000000000000000000000000000000000000000000000000000;
+ bytes32 internal constant V3_BITMASK = 0x0003000000000000000000000000000000000000000000000000000000000000;
+
+ bytes32 internal constant INVALID_FEED = keccak256("INVALID");
+ uint32 internal constant OBSERVATIONS_TIMESTAMP = 1000;
+ uint64 internal constant BLOCKNUMBER_LOWER_BOUND = 1000;
+ uint64 internal constant BLOCKNUMBER_UPPER_BOUND = BLOCKNUMBER_LOWER_BOUND + 5;
+ int192 internal constant MEDIAN = 1 ether;
+ int192 internal constant BID = 500000000 gwei;
+ int192 internal constant ASK = 2 ether;
+
+ //version 0 feeds
+ bytes32 internal constant FEED_ID = (keccak256("ETH-USD") & V_MASK) | V1_BITMASK;
+ bytes32 internal constant FEED_ID_2 = (keccak256("LINK-USD") & V_MASK) | V1_BITMASK;
+ bytes32 internal constant FEED_ID_3 = (keccak256("BTC-USD") & V_MASK) | V1_BITMASK;
+
+ //version 3 feeds
+ bytes32 internal constant FEED_ID_V3 = (keccak256("ETH-USD") & V_MASK) | V3_BITMASK;
+
+ function _encodeReport(V3Report memory report) internal pure returns (bytes memory) {
+ return
+ abi.encode(
+ report.feedId,
+ report.observationsTimestamp,
+ report.validFromTimestamp,
+ report.nativeFee,
+ report.linkFee,
+ report.expiresAt,
+ report.benchmarkPrice,
+ report.bid,
+ report.ask
+ );
+ }
+
+ function _generateSignerSignatures(
+ bytes memory report,
+ bytes32[3] memory reportContext,
+ Signer[] memory signers
+ ) internal pure returns (bytes32[] memory rawRs, bytes32[] memory rawSs, bytes32 rawVs) {
+ bytes32[] memory rs = new bytes32[](signers.length);
+ bytes32[] memory ss = new bytes32[](signers.length);
+ bytes memory vs = new bytes(signers.length);
+
+ bytes32 hash = keccak256(abi.encodePacked(keccak256(report), reportContext));
+
+ for (uint256 i = 0; i < signers.length; i++) {
+ (uint8 v, bytes32 r, bytes32 s) = vm.sign(signers[i].mockPrivateKey, hash);
+ rs[i] = r;
+ ss[i] = s;
+ vs[i] = bytes1(v - 27);
+ }
+ return (rs, ss, bytes32(vs));
+ }
+
+ function _generateV3EncodedBlob(
+ V3Report memory report,
+ bytes32[3] memory reportContext,
+ Signer[] memory signers
+ ) internal pure returns (bytes memory) {
+ bytes memory reportBytes = _encodeReport(report);
+ (bytes32[] memory rs, bytes32[] memory ss, bytes32 rawVs) = _generateSignerSignatures(
+ reportBytes,
+ reportContext,
+ signers
+ );
+ return abi.encode(reportContext, reportBytes, rs, ss, rawVs);
+ }
+
+ function _verify(bytes memory payload, address feeAddress, uint256 wrappedNativeValue, address sender) internal {
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ s_verifierProxy.verify{value: wrappedNativeValue}(payload, abi.encode(feeAddress));
+
+ changePrank(originalAddr);
+ }
+
+ function _generateV3Report() internal view returns (V3Report memory) {
+ return
+ V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+ }
+
+ function _verifyBulk(
+ bytes[] memory payload,
+ address feeAddress,
+ uint256 wrappedNativeValue,
+ address sender
+ ) internal {
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ s_verifierProxy.verifyBulk{value: wrappedNativeValue}(payload, abi.encode(feeAddress));
+
+ changePrank(originalAddr);
+ }
+
+ function _approveLink(address spender, uint256 quantity, address sender) internal {
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ link.approve(spender, quantity);
+ changePrank(originalAddr);
+ }
+
+ function setUp() public virtual {
+ // BaseTest.setUp is often called multiple times from tests' setUp due to inheritance.
+ if (s_baseTestInitialized) return;
+ s_baseTestInitialized = true;
+ vm.startPrank(ADMIN);
+
+ s_verifierProxy = new DestinationVerifierProxy();
+ s_verifier = new DestinationVerifier(address(s_verifierProxy));
+ s_verifierProxy.setVerifier(address(s_verifier));
+
+ // setting up FeeManager and RewardManager
+ native = new WERC20Mock();
+ link = new ERC20Mock("LINK", "LINK", ADMIN, 0);
+ rewardManager = new DestinationRewardManager(address(link));
+ feeManager = new DestinationFeeManager(address(link), address(native), address(s_verifier), address(rewardManager));
+
+ for (uint256 i; i < MAX_ORACLES; i++) {
+ uint256 mockPK = i + 1;
+ s_signers[i].mockPrivateKey = mockPK;
+ s_signers[i].signerAddress = vm.addr(mockPK);
+ }
+ }
+
+ function _getSigners(uint256 numSigners) internal view returns (Signer[] memory) {
+ Signer[] memory signers = new Signer[](numSigners);
+ for (uint256 i; i < numSigners; i++) {
+ signers[i] = s_signers[i];
+ }
+ return signers;
+ }
+
+ function _getSignerAddresses(Signer[] memory signers) internal pure returns (address[] memory) {
+ address[] memory signerAddrs = new address[](signers.length);
+ for (uint256 i = 0; i < signerAddrs.length; i++) {
+ signerAddrs[i] = signers[i].signerAddress;
+ }
+ return signerAddrs;
+ }
+
+ function _signerAddressAndDonConfigKey(address signer, bytes24 donConfigId) internal pure returns (bytes32) {
+ return keccak256(abi.encodePacked(signer, donConfigId));
+ }
+
+ function _donConfigIdFromConfigData(address[] memory signers, uint8 f) internal pure returns (bytes24) {
+ Common._quickSort(signers, 0, int256(signers.length - 1));
+ bytes24 donConfigId = bytes24(keccak256(abi.encodePacked(signers, f)));
+ return donConfigId;
+ }
+
+ function assertReportsEqual(bytes memory response, V3Report memory testReport) public pure {
+ (
+ bytes32 feedId,
+ uint32 observationsTimestamp,
+ uint32 validFromTimestamp,
+ uint192 nativeFee,
+ uint192 linkFee,
+ uint32 expiresAt,
+ int192 benchmarkPrice,
+ int192 bid,
+ int192 ask
+ ) = abi.decode(response, (bytes32, uint32, uint32, uint192, uint192, uint32, int192, int192, int192));
+ assertEq(feedId, testReport.feedId);
+ assertEq(observationsTimestamp, testReport.observationsTimestamp);
+ assertEq(validFromTimestamp, testReport.validFromTimestamp);
+ assertEq(expiresAt, testReport.expiresAt);
+ assertEq(benchmarkPrice, testReport.benchmarkPrice);
+ assertEq(bid, testReport.bid);
+ assertEq(ask, testReport.ask);
+ assertEq(linkFee, testReport.linkFee);
+ assertEq(nativeFee, testReport.nativeFee);
+ }
+
+ function _approveNative(address spender, uint256 quantity, address sender) internal {
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ native.approve(spender, quantity);
+ changePrank(originalAddr);
+ }
+}
+
+contract VerifierWithFeeManager is BaseTest {
+ uint256 internal constant DEFAULT_LINK_MINT_QUANTITY = 100 ether;
+ uint256 internal constant DEFAULT_NATIVE_MINT_QUANTITY = 100 ether;
+
+ function setUp() public virtual override {
+ BaseTest.setUp();
+
+ s_verifierProxy.setVerifier(address(s_verifier));
+ s_verifier.setFeeManager(address(feeManager));
+ rewardManager.addFeeManager(address(feeManager));
+
+ //mint some tokens to the user
+ link.mint(USER, DEFAULT_LINK_MINT_QUANTITY);
+ native.mint(USER, DEFAULT_NATIVE_MINT_QUANTITY);
+ vm.deal(USER, DEFAULT_NATIVE_MINT_QUANTITY);
+
+ //mint some link tokens to the feeManager pool
+ link.mint(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+ }
+}
+
+contract MultipleVerifierWithMultipleFeeManagers is BaseTest {
+ uint256 internal constant DEFAULT_LINK_MINT_QUANTITY = 100 ether;
+ uint256 internal constant DEFAULT_NATIVE_MINT_QUANTITY = 100 ether;
+
+ DestinationVerifier internal s_verifier2;
+ DestinationVerifier internal s_verifier3;
+
+ DestinationVerifierProxy internal s_verifierProxy2;
+ DestinationVerifierProxy internal s_verifierProxy3;
+
+ DestinationFeeManager internal feeManager2;
+
+ function setUp() public virtual override {
+ /*
+ - Sets up 3 verifiers
+ - Sets up 2 Fee managers, wire the fee managers and verifiers
+ - Sets up a Reward Manager which can be used by both fee managers
+ */
+ BaseTest.setUp();
+
+ s_verifierProxy2 = new DestinationVerifierProxy();
+ s_verifierProxy3 = new DestinationVerifierProxy();
+
+ s_verifier2 = new DestinationVerifier(address(s_verifierProxy2));
+ s_verifier3 = new DestinationVerifier(address(s_verifierProxy3));
+
+ s_verifierProxy2.setVerifier(address(s_verifier2));
+ s_verifierProxy3.setVerifier(address(s_verifier3));
+
+ feeManager2 = new DestinationFeeManager(
+ address(link),
+ address(native),
+ address(s_verifier),
+ address(rewardManager)
+ );
+
+ s_verifier.setFeeManager(address(feeManager));
+ s_verifier2.setFeeManager(address(feeManager));
+ s_verifier3.setFeeManager(address(feeManager2));
+
+ // this is already set in the base contract
+ // feeManager.addVerifier(address(s_verifier));
+ feeManager.addVerifier(address(s_verifier2));
+ feeManager2.addVerifier(address(s_verifier3));
+
+ rewardManager.addFeeManager(address(feeManager));
+ rewardManager.addFeeManager(address(feeManager2));
+
+ //mint some tokens to the user
+ link.mint(USER, DEFAULT_LINK_MINT_QUANTITY);
+ native.mint(USER, DEFAULT_NATIVE_MINT_QUANTITY);
+ vm.deal(USER, DEFAULT_NATIVE_MINT_QUANTITY);
+
+ //mint some link tokens to the feeManager pool
+ link.mint(address(feeManager), DEFAULT_REPORT_LINK_FEE);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierInterfacesTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierInterfacesTest.t.sol
new file mode 100644
index 00000000000..d4772ba1855
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierInterfacesTest.t.sol
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {Test} from "forge-std/Test.sol";
+import {VerifierWithFeeManager} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationVerifierProxy} from "../../../v0.4.0/DestinationVerifierProxy.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
+import {IDestinationFeeManager} from "../../../v0.4.0/interfaces/IDestinationFeeManager.sol";
+import {IDestinationRewardManager} from "../../../v0.4.0/interfaces/IDestinationRewardManager.sol";
+import {IDestinationVerifierProxy} from "../../../v0.4.0/interfaces/IDestinationVerifierProxy.sol";
+import {Common} from "../../../libraries/Common.sol";
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC20.sol";
+
+/*
+This test checks the interfaces of destination verifier matches the expectations.
+The code here comes from this example:
+
+https://docs.chain.link/chainlink-automation/guides/streams-lookup
+
+*/
+
+// Custom interfaces for IVerifierProxy and IFeeManager
+interface IVerifierProxy {
+ /**
+ * @notice Verifies that the data encoded has been signed.
+ * correctly by routing to the correct verifier, and bills the user if applicable.
+ * @param payload The encoded data to be verified, including the signed
+ * report.
+ * @param parameterPayload Fee metadata for billing. For the current implementation this is just the abi-encoded fee token ERC-20 address.
+ * @return verifierResponse The encoded report from the verifier.
+ */
+ function verify(
+ bytes calldata payload,
+ bytes calldata parameterPayload
+ ) external payable returns (bytes memory verifierResponse);
+
+ function s_feeManager() external view returns (IDestinationFeeManager);
+}
+
+interface IFeeManager {
+ /**
+ * @notice Calculates the fee and reward associated with verifying a report, including discounts for subscribers.
+ * This function assesses the fee and reward for report verification, applying a discount for recognized subscriber addresses.
+ * @param subscriber The address attempting to verify the report. A discount is applied if this address
+ * is recognized as a subscriber.
+ * @param unverifiedReport The report data awaiting verification. The content of this report is used to
+ * determine the base fee and reward, before considering subscriber discounts.
+ * @param quoteAddress The payment token address used for quoting fees and rewards.
+ * @return fee The fee assessed for verifying the report, with subscriber discounts applied where applicable.
+ * @return reward The reward allocated to the caller for successfully verifying the report.
+ * @return totalDiscount The total discount amount deducted from the fee for subscribers.
+ */
+ function getFeeAndReward(
+ address subscriber,
+ bytes memory unverifiedReport,
+ address quoteAddress
+ ) external returns (Common.Asset memory, Common.Asset memory, uint256);
+
+ function i_linkAddress() external view returns (address);
+
+ function i_nativeAddress() external view returns (address);
+
+ function i_rewardManager() external view returns (address);
+}
+
+//Tests
+// https://docs.chain.link/chainlink-automation/guides/streams-lookup
+contract VerifierInterfacesTest is VerifierWithFeeManager {
+ address internal constant DEFAULT_RECIPIENT_1 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_1"))));
+
+ IVerifierProxy public verifier;
+ V3Report internal s_testReport;
+
+ address public FEE_ADDRESS;
+ string public constant DATASTREAMS_FEEDLABEL = "feedIDs";
+ string public constant DATASTREAMS_QUERYLABEL = "timestamp";
+ int192 public last_retrieved_price;
+ bytes internal signedReport;
+ bytes32[3] internal s_reportContext;
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+
+ function setUp() public virtual override {
+ VerifierWithFeeManager.setUp();
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ s_testReport = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](1);
+ weights[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, ONE_PERCENT * 100);
+ s_verifier.setConfig(signerAddrs, MINIMAL_FAULT_TOLERANCE, weights);
+ signedReport = _generateV3EncodedBlob(s_testReport, s_reportContext, signers);
+
+ verifier = IVerifierProxy(address(s_verifierProxy));
+ }
+
+ function test_DestinationContractInterfaces() public {
+ bytes memory unverifiedReport = signedReport;
+
+ (, bytes memory reportData) = abi.decode(unverifiedReport, (bytes32[3], bytes));
+
+ // Report verification fees
+ IFeeManager feeManager = IFeeManager(address(verifier.s_feeManager()));
+ IDestinationRewardManager rewardManager = IDestinationRewardManager(address(feeManager.i_rewardManager()));
+
+ address feeTokenAddress = feeManager.i_linkAddress();
+ (Common.Asset memory fee, , ) = feeManager.getFeeAndReward(address(this), reportData, feeTokenAddress);
+
+ // Approve rewardManager to spend this contract's balance in fees
+ _approveLink(address(rewardManager), fee.amount, USER);
+ _verify(unverifiedReport, address(feeTokenAddress), 0, USER);
+
+ assertEq(link.balanceOf(USER), DEFAULT_LINK_MINT_QUANTITY - fee.amount);
+ assertEq(link.balanceOf(address(rewardManager)), fee.amount);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierProxyTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierProxyTest.t.sol
new file mode 100644
index 00000000000..c93c9dc6d9a
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierProxyTest.t.sol
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifierProxy} from "../../../v0.4.0/DestinationVerifierProxy.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationFeeManager} from "../../../v0.4.0/DestinationFeeManager.sol";
+import {IERC165} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
+
+contract DestinationVerifierProxyInitializeVerifierTest is BaseTest {
+ function test_setVerifierCalledByNoOwner() public {
+ address STRANGER = address(999);
+ changePrank(STRANGER);
+ vm.expectRevert(bytes("Only callable by owner"));
+ s_verifierProxy.setVerifier(address(s_verifier));
+ }
+
+ function test_setVerifierWhichDoesntHonourInterface() public {
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifierProxy.VerifierInvalid.selector, address(rewardManager)));
+ s_verifierProxy.setVerifier(address(rewardManager));
+ }
+
+ function test_setVerifierOk() public {
+ s_verifierProxy.setVerifier(address(s_verifier));
+ assertEq(s_verifierProxy.s_feeManager(), s_verifier.s_feeManager());
+ assertEq(s_verifierProxy.s_accessController(), s_verifier.s_accessController());
+ }
+
+ function test_correctlySetsTheOwner() public {
+ DestinationVerifierProxy proxy = new DestinationVerifierProxy();
+ assertEq(proxy.owner(), ADMIN);
+ }
+
+ function test_correctlySetsVersion() public view {
+ string memory version = s_verifierProxy.typeAndVersion();
+ assertEq(version, "DestinationVerifierProxy 1.0.0");
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierRemoveLatestConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierRemoveLatestConfigTest.t.sol
new file mode 100644
index 00000000000..6309efc9959
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierRemoveLatestConfigTest.t.sol
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationRewardManager} from "../../../v0.4.0/DestinationRewardManager.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+contract DestinationVerifierSetConfigTest is BaseTest {
+ bytes32[3] internal s_reportContext;
+ V3Report internal s_testReport;
+
+ function setUp() public virtual override {
+ BaseTest.setUp();
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+ }
+
+ function test_removeLatestConfigWhenNoConfigShouldFail() public {
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.DonConfigDoesNotExist.selector));
+ s_verifier.removeLatestConfig();
+ }
+
+ function test_removeLatestConfig() public {
+ /*
+ This test sets two Configs: Config A and Config B.
+ - it removes and readds config B multiple times while trying Config A verifications
+ */
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersA = new BaseTest.Signer[](7);
+ signersA[0] = signers[0];
+ signersA[1] = signers[1];
+ signersA[2] = signers[2];
+ signersA[3] = signers[3];
+ signersA[4] = signers[4];
+ signersA[5] = signers[5];
+ signersA[6] = signers[6];
+
+ // ConfigA
+ address[] memory signersAddrA = _getSignerAddresses(signersA);
+ s_verifier.setConfig(signersAddrA, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ vm.warp(block.timestamp + 10);
+ V3Report memory s_testReportA = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ vm.warp(block.timestamp + 100);
+ // Config B
+ BaseTest.Signer[] memory signersB = new BaseTest.Signer[](7);
+ // signers in ConfigA
+ signersB[0] = signers[8];
+ signersB[1] = signers[9];
+ signersB[2] = signers[10];
+ signersB[3] = signers[11];
+ signersB[4] = signers[12];
+ signersB[5] = signers[13];
+ signersB[6] = signers[14];
+ address[] memory signersAddrsB = _getSignerAddresses(signersB);
+ s_verifier.setConfig(signersAddrsB, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ V3Report memory s_testReportB = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ BaseTest.Signer[] memory reportSignersA = new BaseTest.Signer[](3);
+ reportSignersA[0] = signers[0];
+ reportSignersA[1] = signers[1];
+ reportSignersA[2] = signers[2];
+
+ BaseTest.Signer[] memory reportSignersB = new BaseTest.Signer[](3);
+ reportSignersB[0] = signers[8];
+ reportSignersB[1] = signers[9];
+ reportSignersB[2] = signers[10];
+
+ bytes memory signedReportA = _generateV3EncodedBlob(s_testReportA, s_reportContext, reportSignersA);
+ bytes memory signedReportB = _generateV3EncodedBlob(s_testReportB, s_reportContext, reportSignersB);
+
+ // verifying should work
+ s_verifierProxy.verify(signedReportA, abi.encode(native));
+ s_verifierProxy.verify(signedReportB, abi.encode(native));
+
+ s_verifier.removeLatestConfig();
+
+ // this should remove the latest config, so ConfigA should be able to verify reports still
+ s_verifierProxy.verify(signedReportA, abi.encode(native));
+ // this report cannot be verified any longer because ConfigB is not there
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReportB, abi.encode(native));
+
+ // since ConfigB is removed we should be able to set it again with no errors
+ s_verifier.setConfig(signersAddrsB, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ // we should be able to remove ConfigB
+ s_verifier.removeLatestConfig();
+ // removing configA
+ s_verifier.removeLatestConfig();
+
+ // verifigny should fail
+ // verifying should work
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReportA, abi.encode(native));
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReportB, abi.encode(native));
+
+ // removing again should fail. no other configs exist
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.DonConfigDoesNotExist.selector));
+ s_verifier.removeLatestConfig();
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetAccessControllerTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetAccessControllerTest.t.sol
new file mode 100644
index 00000000000..d40b674f237
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetAccessControllerTest.t.sol
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+
+contract DestinationVerifierSetAccessControllerTest is BaseTest {
+ event AccessControllerSet(address oldAccessController, address newAccessController);
+
+ function test_revertsIfCalledByNonOwner() public {
+ vm.expectRevert("Only callable by owner");
+
+ changePrank(USER);
+ s_verifier.setAccessController(ACCESS_CONTROLLER_ADDRESS);
+ }
+
+ function test_successfullySetsNewAccessController() public {
+ s_verifier.setAccessController(ACCESS_CONTROLLER_ADDRESS);
+ address ac = s_verifier.s_accessController();
+ assertEq(ac, ACCESS_CONTROLLER_ADDRESS);
+ }
+
+ function test_successfullySetsNewAccessControllerIsEmpty() public {
+ s_verifier.setAccessController(address(0));
+ address ac = s_verifier.s_accessController();
+ assertEq(ac, address(0));
+ }
+
+ function test_emitsTheCorrectEvent() public {
+ vm.expectEmit(true, false, false, false);
+ emit AccessControllerSet(address(0), ACCESS_CONTROLLER_ADDRESS);
+ s_verifier.setAccessController(ACCESS_CONTROLLER_ADDRESS);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetConfigTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetConfigTest.t.sol
new file mode 100644
index 00000000000..f6e5fd1f213
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetConfigTest.t.sol
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationRewardManager} from "../../../v0.4.0/DestinationRewardManager.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+contract DestinationVerifierSetConfigTest is BaseTest {
+ function setUp() public virtual override {
+ BaseTest.setUp();
+ }
+
+ function test_revertsIfCalledByNonOwner() public {
+ vm.expectRevert("Only callable by owner");
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ changePrank(USER);
+ s_verifier.setConfig(_getSignerAddresses(signers), FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ }
+
+ function test_revertsIfSetWithTooManySigners() public {
+ address[] memory signers = new address[](MAX_ORACLES + 1);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.ExcessSigners.selector, signers.length, MAX_ORACLES));
+ s_verifier.setConfig(signers, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ }
+
+ function test_revertsIfFaultToleranceIsZero() public {
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.FaultToleranceMustBePositive.selector));
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ s_verifier.setConfig(_getSignerAddresses(signers), 0, new Common.AddressAndWeight[](0));
+ }
+
+ function test_revertsIfNotEnoughSigners() public {
+ address[] memory signers = new address[](2);
+ signers[0] = address(1000);
+ signers[1] = address(1001);
+
+ vm.expectRevert(
+ abi.encodeWithSelector(DestinationVerifier.InsufficientSigners.selector, signers.length, FAULT_TOLERANCE * 3 + 1)
+ );
+ s_verifier.setConfig(signers, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ }
+
+ function test_revertsIfDuplicateSigners() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ signerAddrs[0] = signerAddrs[1];
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.NonUniqueSignatures.selector));
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ }
+
+ function test_revertsIfSignerContainsZeroAddress() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ signerAddrs[0] = address(0);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.ZeroAddress.selector));
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ }
+
+ function test_donConfigIdIsSameForSignersInDifferentOrder() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+
+ bytes24 expectedDonConfigId = _donConfigIdFromConfigData(signerAddrs, FAULT_TOLERANCE);
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ address temp = signerAddrs[0];
+ signerAddrs[0] = signerAddrs[1];
+ signerAddrs[1] = temp;
+
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.DonConfigAlreadyExists.selector, expectedDonConfigId));
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ }
+
+ function test_NoDonConfigAlreadyExists() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ // testing adding same set of Signers but different FAULT_TOLERENCE does not result in DonConfigAlreadyExists revert
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE - 1, new Common.AddressAndWeight[](0));
+
+ // testing adding a different set of Signers with same FAULT_TOLERENCE does not result in DonConfigAlreadyExists revert
+ address[] memory signerAddrsMinusOne = new address[](signerAddrs.length - 1);
+ for (uint256 i = 0; i < signerAddrs.length - 1; i++) {
+ signerAddrsMinusOne[i] = signerAddrs[i];
+ }
+ s_verifier.setConfig(signerAddrsMinusOne, FAULT_TOLERANCE - 1, new Common.AddressAndWeight[](0));
+ }
+
+ function test_addressesAndWeightsDoNotProduceSideEffectsInDonConfigIds() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ bytes24 expectedDonConfigId = _donConfigIdFromConfigData(signerAddrs, FAULT_TOLERANCE);
+
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.DonConfigAlreadyExists.selector, expectedDonConfigId));
+
+ // Same call to setConfig with different addressAndWeights do not entail a new DonConfigID
+ // Resulting in a DonConfigAlreadyExists error
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](1);
+ weights[0] = Common.AddressAndWeight(signers[0].signerAddress, 1);
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+ }
+
+ function test_setConfigActiveUnknownDonConfigId() public {
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.DonConfigDoesNotExist.selector));
+ s_verifier.setConfigActive(3, true);
+ }
+
+ function test_setConfigWithActivationTime() public {
+ // simple case setting a config with specific activation time
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ uint32 activationTime = 10;
+ s_verifier.setConfigWithActivationTime(
+ signerAddrs,
+ FAULT_TOLERANCE,
+ new Common.AddressAndWeight[](0),
+ activationTime
+ );
+ }
+
+ function test_setConfigWithActivationTimeNoFutureTimeShouldFail() public {
+ // calling setConfigWithActivationTime with a future timestamp should fail
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ uint32 activationTime = uint32(block.timestamp) + 100;
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadActivationTime.selector));
+ s_verifier.setConfigWithActivationTime(
+ signerAddrs,
+ FAULT_TOLERANCE,
+ new Common.AddressAndWeight[](0),
+ activationTime
+ );
+ }
+
+ function test_setConfigWithActivationTimeEarlierThanLatestConfigShouldFail() public {
+ // setting a config older than the latest current config should fail
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ uint32 oldActivationTime = uint32(block.timestamp) - 1;
+ // sets a config with timestamp = block.timestamp
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ // setting a config with ealier timestamp retuls in failure
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadActivationTime.selector));
+ s_verifier.setConfigWithActivationTime(
+ signerAddrs,
+ FAULT_TOLERANCE - 1,
+ new Common.AddressAndWeight[](0),
+ oldActivationTime
+ );
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetFeeManagerTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetFeeManagerTest.t.sol
new file mode 100644
index 00000000000..fdf75d6845b
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierSetFeeManagerTest.t.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+
+contract VerifierSetAccessControllerTest is BaseTest {
+ event FeeManagerSet(address oldFeeManager, address newFeeManager);
+
+ function test_revertsIfCalledByNonOwner() public {
+ vm.expectRevert("Only callable by owner");
+ changePrank(USER);
+ s_verifier.setFeeManager(address(feeManager));
+ }
+
+ function test_successfullySetsNewFeeManager() public {
+ vm.expectEmit(true, false, false, false);
+ emit FeeManagerSet(address(0), ACCESS_CONTROLLER_ADDRESS);
+ s_verifier.setFeeManager(address(feeManager));
+ address ac = s_verifier.s_feeManager();
+ assertEq(ac, address(feeManager));
+ }
+
+ function test_setFeeManagerWhichDoesntHonourInterface() public {
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.FeeManagerInvalid.selector));
+ s_verifier.setFeeManager(address(rewardManager));
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTest.t.sol
new file mode 100644
index 00000000000..dd157d2a475
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTest.t.sol
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+
+contract DestinationVerifierConstructorTest is BaseTest {
+ bytes32[3] internal s_reportContext;
+
+ function test_revertsIfInitializedWithEmptyVerifierProxy() public {
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.ZeroAddress.selector));
+ new DestinationVerifier(address(0));
+ }
+
+ function test_typeAndVersion() public {
+ DestinationVerifier v = new DestinationVerifier(address(s_verifierProxy));
+ assertEq(v.owner(), ADMIN);
+ string memory typeAndVersion = s_verifier.typeAndVersion();
+ assertEq(typeAndVersion, "DestinationVerifier 1.0.0");
+ }
+
+ function test_falseIfIsNotCorrectInterface() public view {
+ bool isInterface = s_verifier.supportsInterface(bytes4("abcd"));
+ assertEq(isInterface, false);
+ }
+
+ function test_trueIfIsCorrectInterface() public view {
+ bool isInterface = s_verifier.supportsInterface(DestinationVerifier.verify.selector);
+ assertEq(isInterface, true);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestBillingReport.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestBillingReport.t.sol
new file mode 100644
index 00000000000..574e169cf26
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestBillingReport.t.sol
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {VerifierWithFeeManager} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationVerifierProxy} from "../../../v0.4.0/DestinationVerifierProxy.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+contract VerifierBillingTests is VerifierWithFeeManager {
+ bytes32[3] internal s_reportContext;
+ V3Report internal s_testReportThree;
+
+ function setUp() public virtual override {
+ VerifierWithFeeManager.setUp();
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+ s_testReportThree = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+ }
+
+ function test_verifyWithLinkV3Report() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](0);
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReportThree, s_reportContext, signers);
+ bytes32 expectedDonConfigId = _donConfigIdFromConfigData(signerAddrs, FAULT_TOLERANCE);
+
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+ _verify(signedReport, address(link), 0, USER);
+ assertEq(link.balanceOf(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE);
+
+ // internal state checks
+ assertEq(feeManager.s_linkDeficit(expectedDonConfigId), 0);
+ assertEq(rewardManager.s_totalRewardRecipientFees(expectedDonConfigId), DEFAULT_REPORT_LINK_FEE);
+ assertEq(link.balanceOf(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_verifyWithNativeERC20() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](1);
+ weights[0] = Common.AddressAndWeight(signerAddrs[0], ONE_PERCENT * 100);
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+ bytes memory signedReport = _generateV3EncodedBlob(
+ s_testReportThree,
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+ _approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE, USER);
+ _verify(signedReport, address(native), 0, USER);
+ assertEq(native.balanceOf(USER), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE);
+
+ assertEq(link.balanceOf(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+ }
+
+ function test_verifyWithNativeUnwrapped() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](0);
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+ bytes memory signedReport = _generateV3EncodedBlob(
+ s_testReportThree,
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+ _verify(signedReport, address(native), DEFAULT_REPORT_NATIVE_FEE, USER);
+
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE);
+ assertEq(address(feeManager).balance, 0);
+ }
+
+ function test_verifyWithNativeUnwrappedReturnsChange() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](0);
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+ bytes memory signedReport = _generateV3EncodedBlob(
+ s_testReportThree,
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+
+ _verify(signedReport, address(native), DEFAULT_REPORT_NATIVE_FEE * 2, USER);
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE);
+ assertEq(address(feeManager).balance, 0);
+ }
+}
+
+contract DestinationVerifierBulkVerifyBillingReport is VerifierWithFeeManager {
+ uint256 internal constant NUMBERS_OF_REPORTS = 5;
+
+ bytes32[3] internal s_reportContext;
+
+ function setUp() public virtual override {
+ VerifierWithFeeManager.setUp();
+ // setting a DonConfig we can reuse in the rest of tests
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](0);
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+ }
+
+ function test_verifyWithBulkLink() public {
+ bytes memory signedReport = _generateV3EncodedBlob(
+ _generateV3Report(),
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+
+ bytes[] memory signedReports = new bytes[](NUMBERS_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBERS_OF_REPORTS; i++) {
+ signedReports[i] = signedReport;
+ }
+
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE * NUMBERS_OF_REPORTS, USER);
+
+ _verifyBulk(signedReports, address(link), 0, USER);
+
+ assertEq(link.balanceOf(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE * NUMBERS_OF_REPORTS);
+ assertEq(link.balanceOf(address(rewardManager)), DEFAULT_REPORT_LINK_FEE * NUMBERS_OF_REPORTS);
+ }
+
+ function test_verifyWithBulkNative() public {
+ bytes memory signedReport = _generateV3EncodedBlob(
+ _generateV3Report(),
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+
+ bytes[] memory signedReports = new bytes[](NUMBERS_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBERS_OF_REPORTS; i++) {
+ signedReports[i] = signedReport;
+ }
+
+ _approveNative(address(feeManager), DEFAULT_REPORT_NATIVE_FEE * NUMBERS_OF_REPORTS, USER);
+ _verifyBulk(signedReports, address(native), 0, USER);
+ assertEq(native.balanceOf(USER), DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE * NUMBERS_OF_REPORTS);
+ }
+
+ function test_verifyWithBulkNativeUnwrapped() public {
+ bytes memory signedReport = _generateV3EncodedBlob(
+ _generateV3Report(),
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+
+ bytes[] memory signedReports = new bytes[](NUMBERS_OF_REPORTS);
+ for (uint256 i; i < NUMBERS_OF_REPORTS; i++) {
+ signedReports[i] = signedReport;
+ }
+
+ _verifyBulk(signedReports, address(native), 200 * DEFAULT_REPORT_NATIVE_FEE * NUMBERS_OF_REPORTS, USER);
+
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE * 5);
+ assertEq(address(feeManager).balance, 0);
+ }
+
+ function test_verifyWithBulkNativeUnwrappedReturnsChange() public {
+ bytes memory signedReport = _generateV3EncodedBlob(
+ _generateV3Report(),
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+
+ bytes[] memory signedReports = new bytes[](NUMBERS_OF_REPORTS);
+ for (uint256 i = 0; i < NUMBERS_OF_REPORTS; i++) {
+ signedReports[i] = signedReport;
+ }
+
+ _verifyBulk(signedReports, address(native), DEFAULT_REPORT_NATIVE_FEE * (NUMBERS_OF_REPORTS * 2), USER);
+
+ assertEq(USER.balance, DEFAULT_NATIVE_MINT_QUANTITY - DEFAULT_REPORT_NATIVE_FEE * NUMBERS_OF_REPORTS);
+ assertEq(address(feeManager).balance, 0);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestRewards.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestRewards.t.sol
new file mode 100644
index 00000000000..8ca954b8cac
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestRewards.t.sol
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {VerifierWithFeeManager} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationVerifierProxy} from "../../../v0.4.0/DestinationVerifierProxy.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+contract VerifierBillingTests is VerifierWithFeeManager {
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ address internal constant DEFAULT_RECIPIENT_1 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_1"))));
+ address internal constant DEFAULT_RECIPIENT_2 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_2"))));
+ address internal constant DEFAULT_RECIPIENT_3 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_3"))));
+ address internal constant DEFAULT_RECIPIENT_4 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_4"))));
+ address internal constant DEFAULT_RECIPIENT_5 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_5"))));
+ address internal constant DEFAULT_RECIPIENT_6 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_6"))));
+ address internal constant DEFAULT_RECIPIENT_7 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_7"))));
+
+ function payRecipients(bytes32 poolId, address[] memory recipients, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //pay the recipients
+ rewardManager.payRecipients(poolId, recipients);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ bytes32[3] internal s_reportContext;
+ V3Report internal s_testReport;
+
+ function setUp() public virtual override {
+ VerifierWithFeeManager.setUp();
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+ s_testReport = generateReportAtTimestamp(block.timestamp);
+ }
+
+ function generateReportAtTimestamp(uint256 timestamp) public pure returns (V3Report memory) {
+ return
+ V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ // ask michael about this expires at, is it usually set at what blocks
+ expiresAt: uint32(timestamp) + 500,
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+ }
+
+ function getRecipientAndWeightsGroup2() public pure returns (Common.AddressAndWeight[] memory, address[] memory) {
+ address[] memory recipients = new address[](4);
+ recipients[0] = DEFAULT_RECIPIENT_4;
+ recipients[1] = DEFAULT_RECIPIENT_5;
+ recipients[2] = DEFAULT_RECIPIENT_6;
+ recipients[3] = DEFAULT_RECIPIENT_7;
+
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](4);
+ //init each recipient with even weights. 2500 = 25% of pool
+ weights[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, POOL_SCALAR / 4);
+ weights[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_5, POOL_SCALAR / 4);
+ weights[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_6, POOL_SCALAR / 4);
+ weights[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_7, POOL_SCALAR / 4);
+ return (weights, recipients);
+ }
+
+ function getRecipientAndWeightsGroup1() public pure returns (Common.AddressAndWeight[] memory, address[] memory) {
+ address[] memory recipients = new address[](4);
+ recipients[0] = DEFAULT_RECIPIENT_1;
+ recipients[1] = DEFAULT_RECIPIENT_2;
+ recipients[2] = DEFAULT_RECIPIENT_3;
+ recipients[3] = DEFAULT_RECIPIENT_4;
+
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](4);
+ //init each recipient with even weights. 2500 = 25% of pool
+ weights[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, POOL_SCALAR / 4);
+ weights[1] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, POOL_SCALAR / 4);
+ weights[2] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, POOL_SCALAR / 4);
+ weights[3] = Common.AddressAndWeight(DEFAULT_RECIPIENT_4, POOL_SCALAR / 4);
+ return (weights, recipients);
+ }
+
+ function test_rewardsAreDistributedAccordingToWeights() public {
+ /*
+ Simple test verifying that rewards are distributed according to address and weights
+ associated to the DonConfig used to verify the report
+ */
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](1);
+ weights[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, ONE_PERCENT * 100);
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReport, s_reportContext, signers);
+ bytes32 expectedDonConfigId = _donConfigIdFromConfigData(signerAddrs, FAULT_TOLERANCE);
+
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+ _verify(signedReport, address(link), 0, USER);
+ assertEq(link.balanceOf(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE);
+
+ // internal state checks
+ assertEq(feeManager.s_linkDeficit(expectedDonConfigId), 0);
+ assertEq(rewardManager.s_totalRewardRecipientFees(expectedDonConfigId), DEFAULT_REPORT_LINK_FEE);
+ assertEq(link.balanceOf(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ // check the recipients are paid according to weights
+ address[] memory recipients = new address[](1);
+ recipients[0] = DEFAULT_RECIPIENT_1;
+ payRecipients(expectedDonConfigId, recipients, ADMIN);
+ assertEq(link.balanceOf(recipients[0]), DEFAULT_REPORT_LINK_FEE);
+ assertEq(link.balanceOf(address(rewardManager)), 0);
+ }
+
+ function test_rewardsAreDistributedAccordingToWeightsMultipleWeigths() public {
+ /*
+ Rewards are distributed according to AddressAndWeight's
+ associated to the DonConfig used to verify the report:
+ - multiple recipients
+ - multiple verifications
+ */
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ (Common.AddressAndWeight[] memory weights, address[] memory recipients) = getRecipientAndWeightsGroup1();
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReport, s_reportContext, signers);
+ bytes32 expectedDonConfigId = _donConfigIdFromConfigData(signerAddrs, FAULT_TOLERANCE);
+
+ uint256 number_of_reports_verified = 10;
+
+ for (uint256 i = 0; i < number_of_reports_verified; i++) {
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+ _verify(signedReport, address(link), 0, USER);
+ }
+
+ uint256 expected_pool_amount = DEFAULT_REPORT_LINK_FEE * number_of_reports_verified;
+
+ //each recipient should receive 1/4 of the pool
+ uint256 expectedRecipientAmount = expected_pool_amount / 4;
+
+ payRecipients(expectedDonConfigId, recipients, ADMIN);
+ for (uint256 i = 0; i < recipients.length; i++) {
+ // checking each recipient got rewards as set by the weights
+ assertEq(link.balanceOf(recipients[i]), expectedRecipientAmount);
+ }
+ // checking nothing left in reward manager
+ assertEq(link.balanceOf(address(rewardManager)), 0);
+ }
+
+ function test_rewardsAreDistributedAccordingToWeightsUsingHistoricalConfigs() public {
+ /*
+ Verifies that reports verified with historical give rewards according to the verifying config AddressAndWeight.
+ - Sets two Configs: ConfigA and ConfigB, These two Configs have different Recipient and Weights
+ - Verifies a couple reports with each config
+ - Pays recipients
+ - Asserts expected rewards for each recipient
+ */
+
+ Signer[] memory signers = _getSigners(10);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+
+ (Common.AddressAndWeight[] memory weights, address[] memory recipients) = getRecipientAndWeightsGroup1();
+
+ // Create ConfigA
+ s_verifier.setConfig(signerAddrs, MINIMAL_FAULT_TOLERANCE, weights);
+ vm.warp(block.timestamp + 100);
+
+ V3Report memory testReportAtT1 = generateReportAtTimestamp(block.timestamp);
+ bytes memory signedReportT1 = _generateV3EncodedBlob(testReportAtT1, s_reportContext, signers);
+ bytes32 expectedDonConfigIdA = _donConfigIdFromConfigData(signerAddrs, MINIMAL_FAULT_TOLERANCE);
+
+ uint256 number_of_reports_verified = 2;
+
+ // advancing the blocktimestamp so we can test verifying with configs
+ vm.warp(block.timestamp + 100);
+
+ Signer[] memory signers2 = _getSigners(12);
+ address[] memory signerAddrs2 = _getSignerAddresses(signers2);
+ (Common.AddressAndWeight[] memory weights2, address[] memory recipients2) = getRecipientAndWeightsGroup2();
+
+ // Create ConfigB
+ s_verifier.setConfig(signerAddrs2, MINIMAL_FAULT_TOLERANCE, weights2);
+ bytes32 expectedDonConfigIdB = _donConfigIdFromConfigData(signerAddrs2, MINIMAL_FAULT_TOLERANCE);
+
+ V3Report memory testReportAtT2 = generateReportAtTimestamp(block.timestamp);
+
+ // verifiying using ConfigA (report with Old timestamp)
+ for (uint256 i = 0; i < number_of_reports_verified; i++) {
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+ _verify(signedReportT1, address(link), 0, USER);
+ }
+
+ // verifying using ConfigB (report with new timestamp)
+ for (uint256 i = 0; i < number_of_reports_verified; i++) {
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+ _verify(_generateV3EncodedBlob(testReportAtT2, s_reportContext, signers2), address(link), 0, USER);
+ }
+
+ uint256 expected_pool_amount = DEFAULT_REPORT_LINK_FEE * number_of_reports_verified;
+ assertEq(rewardManager.s_totalRewardRecipientFees(expectedDonConfigIdA), expected_pool_amount);
+ assertEq(rewardManager.s_totalRewardRecipientFees(expectedDonConfigIdB), expected_pool_amount);
+
+ // check the recipients are paid according to weights
+ payRecipients(expectedDonConfigIdA, recipients, ADMIN);
+
+ for (uint256 i = 0; i < recipients.length; i++) {
+ // //each recipient should receive 1/4 of the pool
+ assertEq(link.balanceOf(recipients[i]), expected_pool_amount / 4);
+ }
+
+ payRecipients(expectedDonConfigIdB, recipients2, ADMIN);
+
+ for (uint256 i = 1; i < recipients2.length; i++) {
+ // //each recipient should receive 1/4 of the pool
+ assertEq(link.balanceOf(recipients2[i]), expected_pool_amount / 4);
+ }
+
+ // this recipient was part of the two config weights
+ assertEq(link.balanceOf(recipients2[0]), (expected_pool_amount / 4) * 2);
+ assertEq(link.balanceOf(address(rewardManager)), 0);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestRewardsMultiVefifierFeeManager.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestRewardsMultiVefifierFeeManager.t.sol
new file mode 100644
index 00000000000..6a90cbf3738
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierTestRewardsMultiVefifierFeeManager.t.sol
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {MultipleVerifierWithMultipleFeeManagers} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationVerifierProxy} from "../../../v0.4.0/DestinationVerifierProxy.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+contract MultiVerifierBillingTests is MultipleVerifierWithMultipleFeeManagers {
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ address internal constant DEFAULT_RECIPIENT_1 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_1"))));
+ address internal constant DEFAULT_RECIPIENT_2 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_2"))));
+ address internal constant DEFAULT_RECIPIENT_3 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_3"))));
+ address internal constant DEFAULT_RECIPIENT_4 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_4"))));
+ address internal constant DEFAULT_RECIPIENT_5 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_5"))));
+ address internal constant DEFAULT_RECIPIENT_6 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_6"))));
+ address internal constant DEFAULT_RECIPIENT_7 = address(uint160(uint256(keccak256("DEFAULT_RECIPIENT_7"))));
+
+ bytes32[3] internal s_reportContext;
+ V3Report internal s_testReport;
+
+ function setUp() public virtual override {
+ MultipleVerifierWithMultipleFeeManagers.setUp();
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+ s_testReport = generateReportAtTimestamp(block.timestamp);
+ }
+
+ function _verify(
+ DestinationVerifierProxy proxy,
+ bytes memory payload,
+ address feeAddress,
+ uint256 wrappedNativeValue,
+ address sender
+ ) internal {
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ proxy.verify{value: wrappedNativeValue}(payload, abi.encode(feeAddress));
+
+ changePrank(originalAddr);
+ }
+
+ function generateReportAtTimestamp(uint256 timestamp) public pure returns (V3Report memory) {
+ return
+ V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ // ask michael about this expires at, is it usually set at what blocks
+ expiresAt: uint32(timestamp) + 500,
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+ }
+
+ function payRecipients(bytes32 poolId, address[] memory recipients, address sender) public {
+ //record the current address and switch to the recipient
+ address originalAddr = msg.sender;
+ changePrank(sender);
+
+ //pay the recipients
+ rewardManager.payRecipients(poolId, recipients);
+
+ //change back to the original address
+ changePrank(originalAddr);
+ }
+
+ function test_multipleFeeManagersAndVerifiers() public {
+ /*
+ In this test we got:
+ - three verifiers (verifier, verifier2, verifier3).
+ - two fee managers (feeManager, feeManager2)
+ - one reward manager
+
+ we glue:
+ - feeManager is used by verifier1 and verifier2
+ - feeManager is used by verifier3
+ - Rewardmanager is used by feeManager and feeManager2
+
+ In this test we do verificatons via verifier1, verifier2 and verifier3 and check that rewards are set accordingly
+
+ */
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ Common.AddressAndWeight[] memory weights = new Common.AddressAndWeight[](1);
+ weights[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_1, ONE_PERCENT * 100);
+
+ Common.AddressAndWeight[] memory weights2 = new Common.AddressAndWeight[](1);
+ weights2[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_2, ONE_PERCENT * 100);
+
+ Common.AddressAndWeight[] memory weights3 = new Common.AddressAndWeight[](1);
+ weights3[0] = Common.AddressAndWeight(DEFAULT_RECIPIENT_3, ONE_PERCENT * 100);
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, weights);
+ s_verifier2.setConfig(signerAddrs, MINIMAL_FAULT_TOLERANCE, weights2);
+ s_verifier3.setConfig(signerAddrs, MINIMAL_FAULT_TOLERANCE + 1, weights3);
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReport, s_reportContext, signers);
+ bytes32 expectedDonConfigID = _donConfigIdFromConfigData(signerAddrs, FAULT_TOLERANCE);
+ bytes32 expectedDonConfigID2 = _donConfigIdFromConfigData(signerAddrs, MINIMAL_FAULT_TOLERANCE);
+ bytes32 expectedDonConfigID3 = _donConfigIdFromConfigData(signerAddrs, MINIMAL_FAULT_TOLERANCE + 1);
+
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+ _verify(s_verifierProxy, signedReport, address(link), 0, USER);
+ assertEq(link.balanceOf(USER), DEFAULT_LINK_MINT_QUANTITY - DEFAULT_REPORT_LINK_FEE);
+
+ // internal state checks
+ assertEq(feeManager.s_linkDeficit(expectedDonConfigID), 0);
+ assertEq(rewardManager.s_totalRewardRecipientFees(expectedDonConfigID), DEFAULT_REPORT_LINK_FEE);
+ assertEq(link.balanceOf(address(rewardManager)), DEFAULT_REPORT_LINK_FEE);
+
+ // check the recipients are paid according to weights
+ // These rewards happened through verifier1 and feeManager1
+ address[] memory recipients = new address[](1);
+ recipients[0] = DEFAULT_RECIPIENT_1;
+ payRecipients(expectedDonConfigID, recipients, ADMIN);
+ assertEq(link.balanceOf(recipients[0]), DEFAULT_REPORT_LINK_FEE);
+ assertEq(link.balanceOf(address(rewardManager)), 0);
+
+ // these rewards happaned through verifier2 and feeManager1
+ address[] memory recipients2 = new address[](1);
+ recipients2[0] = DEFAULT_RECIPIENT_2;
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+ _verify(s_verifierProxy2, signedReport, address(link), 0, USER);
+ payRecipients(expectedDonConfigID2, recipients2, ADMIN);
+ assertEq(link.balanceOf(recipients2[0]), DEFAULT_REPORT_LINK_FEE);
+ assertEq(link.balanceOf(address(rewardManager)), 0);
+
+ // these rewards happened through verifier3 and feeManager2
+ address[] memory recipients3 = new address[](1);
+ recipients3[0] = DEFAULT_RECIPIENT_3;
+ _approveLink(address(rewardManager), DEFAULT_REPORT_LINK_FEE, USER);
+ _verify(s_verifierProxy3, signedReport, address(link), 0, USER);
+ payRecipients(expectedDonConfigID3, recipients3, ADMIN);
+ assertEq(link.balanceOf(recipients3[0]), DEFAULT_REPORT_LINK_FEE);
+ assertEq(link.balanceOf(address(rewardManager)), 0);
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierVerifyBulkTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierVerifyBulkTest.t.sol
new file mode 100644
index 00000000000..1c57295baed
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierVerifyBulkTest.t.sol
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationVerifierProxy} from "../../../v0.4.0/DestinationVerifierProxy.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+contract VerifierVerifyBulkTest is BaseTest {
+ bytes32[3] internal s_reportContext;
+ V3Report internal s_testReportThree;
+
+ function setUp() public virtual override {
+ BaseTest.setUp();
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+
+ s_testReportThree = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+ }
+
+ function test_revertsVerifyBulkIfNoAccess() public {
+ vm.mockCall(
+ ACCESS_CONTROLLER_ADDRESS,
+ abi.encodeWithSelector(AccessControllerInterface.hasAccess.selector, USER),
+ abi.encode(false)
+ );
+ bytes memory signedReport = _generateV3EncodedBlob(
+ s_testReportThree,
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+
+ bytes[] memory signedReports = new bytes[](2);
+ signedReports[0] = signedReport;
+ signedReports[1] = signedReport;
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.AccessForbidden.selector));
+ changePrank(USER);
+ s_verifier.verifyBulk(signedReports, abi.encode(native), msg.sender);
+ }
+
+ function test_verifyBulkSingleCaseWithSingleConfig() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ // Config1
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ V3Report memory report = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ BaseTest.Signer[] memory reportSigners = new BaseTest.Signer[](3);
+ reportSigners[0] = signers[0];
+ reportSigners[1] = signers[1];
+ reportSigners[2] = signers[2];
+
+ bytes[] memory signedReports = new bytes[](10);
+
+ bytes memory signedReport = _generateV3EncodedBlob(report, s_reportContext, reportSigners);
+
+ for (uint256 i = 0; i < signedReports.length; i++) {
+ signedReports[i] = signedReport;
+ }
+
+ bytes[] memory verifierResponses = s_verifierProxy.verifyBulk(signedReports, abi.encode(native));
+
+ for (uint256 i = 0; i < verifierResponses.length; i++) {
+ bytes memory verifierResponse = verifierResponses[i];
+ assertReportsEqual(verifierResponse, report);
+ }
+ }
+
+ function test_verifyBulkWithSingleConfigOneVerifyFails() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ // Config1
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ BaseTest.Signer[] memory reportSigners = new BaseTest.Signer[](3);
+ reportSigners[0] = signers[0];
+ reportSigners[1] = signers[1];
+ reportSigners[2] = signers[2];
+
+ bytes[] memory signedReports = new bytes[](11);
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReportThree, s_reportContext, reportSigners);
+
+ for (uint256 i = 0; i < 10; i++) {
+ signedReports[i] = signedReport;
+ }
+
+ // Making the last report in this batch not verifiable
+ BaseTest.Signer[] memory reportSigners2 = new BaseTest.Signer[](3);
+ reportSigners2[0] = signers[30];
+ reportSigners2[1] = signers[29];
+ reportSigners2[2] = signers[28];
+ signedReports[10] = _generateV3EncodedBlob(s_testReportThree, s_reportContext, reportSigners2);
+
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verifyBulk(signedReports, abi.encode(native));
+ }
+}
diff --git a/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierVerifyTest.t.sol b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierVerifyTest.t.sol
new file mode 100644
index 00000000000..658bf4f127c
--- /dev/null
+++ b/contracts/src/v0.8/llo-feeds/v0.4.0/test/verifier/DestinationVerifierVerifyTest.t.sol
@@ -0,0 +1,711 @@
+// SPDX-License-Identifier: UNLICENSED
+pragma solidity 0.8.19;
+
+import {BaseTest} from "./BaseDestinationVerifierTest.t.sol";
+import {DestinationVerifier} from "../../../v0.4.0/DestinationVerifier.sol";
+import {DestinationVerifierProxy} from "../../../v0.4.0/DestinationVerifierProxy.sol";
+import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol";
+import {Common} from "../../../libraries/Common.sol";
+
+contract VerifierVerifyTest is BaseTest {
+ bytes32[3] internal s_reportContext;
+ V3Report internal s_testReportThree;
+
+ function setUp() public virtual override {
+ BaseTest.setUp();
+
+ s_testReportThree = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+ }
+
+ function test_verifyReport() public {
+ // Simple use case just setting a config and verifying a report
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReportThree, s_reportContext, signers);
+
+ bytes memory verifierResponse = s_verifierProxy.verify(signedReport, abi.encode(native));
+ assertReportsEqual(verifierResponse, s_testReportThree);
+ }
+
+ function test_verifyTooglingActiveFlagsDonConfigs() public {
+ // sets config
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReportThree, s_reportContext, signers);
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ // verifies report
+ bytes memory verifierResponse = s_verifierProxy.verify(signedReport, abi.encode(native));
+ assertReportsEqual(verifierResponse, s_testReportThree);
+
+ // test verifying via a config that is deactivated
+ s_verifier.setConfigActive(0, false);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ verifierResponse = s_verifierProxy.verify(signedReport, abi.encode(native));
+
+ // test verifying via a reactivated config
+ s_verifier.setConfigActive(0, true);
+ verifierResponse = s_verifierProxy.verify(signedReport, abi.encode(native));
+ assertReportsEqual(verifierResponse, s_testReportThree);
+ }
+
+ function test_failToVerifyReportIfNotEnoughSigners() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ // only one signer, signers < MINIMAL_FAULT_TOLERANCE
+ BaseTest.Signer[] memory signersSubset2 = new BaseTest.Signer[](1);
+ signersSubset2[0] = signers[4];
+
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReportThree, s_reportContext, signersSubset2);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ }
+
+ function test_failToVerifyReportIfNoSigners() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ // No signers for this report
+ BaseTest.Signer[] memory signersSubset2 = new BaseTest.Signer[](0);
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReportThree, s_reportContext, signersSubset2);
+
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.NoSigners.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ }
+
+ function test_failToVerifyReportIfDupSigners() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ // One signer is repeated
+ BaseTest.Signer[] memory signersSubset2 = new BaseTest.Signer[](4);
+ signersSubset2[0] = signers[0];
+ signersSubset2[1] = signers[1];
+ // repeated signers
+ signersSubset2[2] = signers[2];
+ signersSubset2[3] = signers[2];
+
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReportThree, s_reportContext, signersSubset2);
+
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ }
+
+ function test_failToVerifyReportIfSignerNotInConfig() public {
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ // one report whose signer is not in the config
+ BaseTest.Signer[] memory reportSigners = new BaseTest.Signer[](4);
+ // these signers are part ofm the config
+ reportSigners[0] = signers[4];
+ reportSigners[1] = signers[5];
+ reportSigners[2] = signers[6];
+ // this single signer is not in the config
+ reportSigners[3] = signers[7];
+
+ bytes memory signedReport = _generateV3EncodedBlob(s_testReportThree, s_reportContext, reportSigners);
+
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ }
+
+ function test_canVerifyOlderV3ReportsWithOlderConfigs() public {
+ /*
+ This test is checking we can use historical Configs to verify reports:
+ - DonConfigA has signers {A, B, C, E} is set at time T1
+ - DonConfigB has signers {A, B, C, D} is set at time T2
+ - checks we can verify a report with {B, C, D} signers (via DonConfigB)
+ - checks we can verify a report with {B, C, E} signers and timestamp below T2 (via DonConfigA historical config)
+ - checks we can't verify a report with {B, C, E} signers and timestamp above T2 (it gets verivied via DonConfigB)
+ - sets DonConfigA as deactivated
+ - checks we can't verify a report with {B, C, E} signers and timestamp below T2 (via DonConfigA)
+ */
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ // Config1
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ BaseTest.Signer[] memory signersSubset2 = new BaseTest.Signer[](7);
+ signersSubset2[0] = signers[0];
+ signersSubset2[1] = signers[1];
+ signersSubset2[2] = signers[2];
+ signersSubset2[3] = signers[3];
+ signersSubset2[4] = signers[4];
+ signersSubset2[5] = signers[5];
+ signersSubset2[6] = signers[29];
+ address[] memory signersAddrSubset2 = _getSignerAddresses(signersSubset2);
+
+ V3Report memory reportAtSetConfig1Timestmap = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ vm.warp(block.timestamp + 100);
+
+ // Config2
+ s_verifier.setConfig(signersAddrSubset2, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ V3Report memory reportAtSetConfig2Timestmap = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ BaseTest.Signer[] memory reportSigners = new BaseTest.Signer[](5);
+ reportSigners[0] = signers[0];
+ reportSigners[1] = signers[1];
+ reportSigners[2] = signers[2];
+ reportSigners[3] = signers[3];
+ reportSigners[4] = signers[29];
+
+ bytes memory signedReport = _generateV3EncodedBlob(reportAtSetConfig2Timestmap, s_reportContext, reportSigners);
+
+ // this report is verified via Config2
+ bytes memory verifierResponse = s_verifierProxy.verify(signedReport, abi.encode(native));
+ assertReportsEqual(verifierResponse, reportAtSetConfig2Timestmap);
+
+ BaseTest.Signer[] memory reportSigners2 = new BaseTest.Signer[](5);
+ reportSigners2[0] = signers[0];
+ reportSigners2[1] = signers[1];
+ reportSigners2[2] = signers[2];
+ reportSigners2[3] = signers[3];
+ reportSigners2[4] = signers[6];
+
+ bytes memory signedReport2 = _generateV3EncodedBlob(reportAtSetConfig1Timestmap, s_reportContext, reportSigners2);
+
+ // this report is verified via Config1 (using a historical config)
+ bytes memory verifierResponse2 = s_verifierProxy.verify(signedReport2, abi.encode(native));
+ assertReportsEqual(verifierResponse2, reportAtSetConfig1Timestmap);
+
+ // same report with same signers but with a higher timestamp gets verified via Config2
+ // which means verification fails
+ bytes memory signedReport3 = _generateV3EncodedBlob(reportAtSetConfig2Timestmap, s_reportContext, reportSigners2);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport3, abi.encode(native));
+
+ // deactivating Config1 and trying a reverifications ends in failure
+ s_verifier.setConfigActive(0, false);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport2, abi.encode(native));
+ }
+
+ function test_revertsVerifyIfNoAccess() public {
+ vm.mockCall(
+ ACCESS_CONTROLLER_ADDRESS,
+ abi.encodeWithSelector(AccessControllerInterface.hasAccess.selector, USER),
+ abi.encode(false)
+ );
+ bytes memory signedReport = _generateV3EncodedBlob(
+ s_testReportThree,
+ s_reportContext,
+ _getSigners(FAULT_TOLERANCE + 1)
+ );
+
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.AccessForbidden.selector));
+
+ changePrank(USER);
+ s_verifier.verify(signedReport, abi.encode(native), msg.sender);
+ }
+
+ function test_canVerifyNewerReportsWithNewerConfigs() public {
+ /*
+ This test is checking that we use prefer verifiying via newer configs instead of old ones.
+ - DonConfigA has signers {A, B, C, E} is set at time T1
+ - DonConfigB has signers {F, G, H, I} is set at time T2
+ - DonConfigC has signers {J, K, L, M } is set at time T3
+ - checks we can verify a report with {K, L, M} signers (via DonConfigC)
+ */
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ // Config1
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ BaseTest.Signer[] memory signersSubset2 = new BaseTest.Signer[](7);
+ signersSubset2[0] = signers[7];
+ signersSubset2[1] = signers[8];
+ signersSubset2[2] = signers[9];
+ signersSubset2[3] = signers[10];
+ signersSubset2[4] = signers[11];
+ signersSubset2[5] = signers[12];
+ signersSubset2[6] = signers[13];
+
+ address[] memory signersAddrSubset2 = _getSignerAddresses(signersSubset2);
+ // Config2
+ s_verifier.setConfig(signersAddrSubset2, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ BaseTest.Signer[] memory signersSubset3 = new BaseTest.Signer[](7);
+ signersSubset3[0] = signers[30];
+ signersSubset3[1] = signers[29];
+ signersSubset3[2] = signers[28];
+ signersSubset3[3] = signers[27];
+ signersSubset3[4] = signers[26];
+ signersSubset3[5] = signers[25];
+ signersSubset3[6] = signers[24];
+
+ address[] memory signersAddrSubset3 = _getSignerAddresses(signersSubset3);
+ // Config3
+ s_verifier.setConfig(signersAddrSubset3, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ V3Report memory report = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ BaseTest.Signer[] memory reportSigners = new BaseTest.Signer[](3);
+ reportSigners[0] = signers[30];
+ reportSigners[1] = signers[29];
+ reportSigners[2] = signers[28];
+
+ bytes memory signedReport = _generateV3EncodedBlob(report, s_reportContext, reportSigners);
+
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ }
+
+ function test_rollingOutConfiguration() public {
+ /*
+ This test is checking that we can roll out to a new DON without downtime using a transition configuration
+ - DonConfigA has signers {A, B, C} is set at time T1
+ - DonConfigB (transition config) has signers {A, B, C, D, E, F} is set at time T2
+ - DonConfigC has signers {D, E, F} is set at time T3
+
+ - checks we can verify a report with {A, B, C} signers (via DonConfigA) at time between T1 and T2
+ - checks we can verify a report with {A, B, C} signers (via DonConfigB) at time between T2 and T3
+ - checks we can verify a report with {D, E, F} signers (via DonConfigB) at time between T2 and T3
+ - checks we can verify a report with {D, E, F} signers (via DonConfigC) at time > T3
+ - checks we can't verify a report with {A, B, C} signers (via DonConfigC) and timestamp >T3 at time > T3
+ - checks we can verify a report with {A, B, C} signers (via DonConfigC) and timestamp between T2 and T3 at time > T3 (historical check)
+
+ */
+
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersSubset1 = new BaseTest.Signer[](7);
+ signersSubset1[0] = signers[0];
+ signersSubset1[1] = signers[1];
+ signersSubset1[2] = signers[2];
+ signersSubset1[3] = signers[3];
+ signersSubset1[4] = signers[4];
+ signersSubset1[5] = signers[5];
+ signersSubset1[6] = signers[6];
+
+ // ConfigA
+ address[] memory signersAddrSubset1 = _getSignerAddresses(signersSubset1);
+ s_verifier.setConfig(signersAddrSubset1, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ V3Report memory reportT1 = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ BaseTest.Signer[] memory reportSignersConfigA = new BaseTest.Signer[](3);
+ reportSignersConfigA[0] = signers[0];
+ reportSignersConfigA[1] = signers[1];
+ reportSignersConfigA[2] = signers[2];
+
+ // just testing ConfigA
+ bytes memory signedReport = _generateV3EncodedBlob(reportT1, s_reportContext, reportSignersConfigA);
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+
+ vm.warp(block.timestamp + 100);
+
+ BaseTest.Signer[] memory signersSuperset = new BaseTest.Signer[](14);
+ // signers in ConfigA
+ signersSuperset[0] = signers[0];
+ signersSuperset[1] = signers[1];
+ signersSuperset[2] = signers[2];
+ signersSuperset[3] = signers[3];
+ signersSuperset[4] = signers[4];
+ signersSuperset[5] = signers[5];
+ signersSuperset[6] = signers[6];
+ // new signers
+ signersSuperset[7] = signers[7];
+ signersSuperset[8] = signers[8];
+ signersSuperset[9] = signers[9];
+ signersSuperset[10] = signers[10];
+ signersSuperset[11] = signers[11];
+ signersSuperset[12] = signers[12];
+ signersSuperset[13] = signers[13];
+
+ BaseTest.Signer[] memory reportSignersConfigC = new BaseTest.Signer[](3);
+ reportSignersConfigC[0] = signers[7];
+ reportSignersConfigC[1] = signers[8];
+ reportSignersConfigC[2] = signers[9];
+
+ // ConfigB (transition Config)
+ address[] memory signersAddrsSuperset = _getSignerAddresses(signersSuperset);
+ s_verifier.setConfig(signersAddrsSuperset, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ V3Report memory reportT2 = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ // testing we can verify a fresh (block timestamp) report with ConfigA signers. This should use ConfigB
+ signedReport = _generateV3EncodedBlob(reportT2, s_reportContext, reportSignersConfigA);
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+
+ // testing we can verify an old ( non fresh block timestamp) report with ConfigA signers. This should use ConfigA
+ signedReport = _generateV3EncodedBlob(reportT1, s_reportContext, reportSignersConfigA);
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ // deactivating to make sure we are really verifiying via ConfigA
+ s_verifier.setConfigActive(0, false);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ s_verifier.setConfigActive(0, true);
+
+ // testing we can verify a fresh (block timestamp) report with the new signers. This should use ConfigB
+ signedReport = _generateV3EncodedBlob(reportT2, s_reportContext, reportSignersConfigC);
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+
+ vm.warp(block.timestamp + 100);
+
+ // Adding ConfigC
+ BaseTest.Signer[] memory signersSubset2 = new BaseTest.Signer[](7);
+ signersSubset2[0] = signers[7];
+ signersSubset2[1] = signers[8];
+ signersSubset2[2] = signers[9];
+ signersSubset2[3] = signers[10];
+ signersSubset2[4] = signers[11];
+ signersSubset2[5] = signers[12];
+ signersSubset2[6] = signers[13];
+ address[] memory signersAddrsSubset2 = _getSignerAddresses(signersSubset2);
+ s_verifier.setConfig(signersAddrsSubset2, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ V3Report memory reportT3 = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ // testing we can verify reports with ConfigC signers
+ signedReport = _generateV3EncodedBlob(reportT3, s_reportContext, reportSignersConfigC);
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+
+ // testing an old report (block timestamp) with ConfigC signers should verify via ConfigB
+ signedReport = _generateV3EncodedBlob(reportT2, s_reportContext, reportSignersConfigC);
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ // deactivating to make sure we are really verifiying via ConfigB
+ s_verifier.setConfigActive(1, false);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ s_verifier.setConfigActive(1, true);
+
+ // testing a recent report with ConfigA signers should not verify
+ signedReport = _generateV3EncodedBlob(reportT3, s_reportContext, reportSignersConfigA);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+
+ // testing an old report (block timestamp) with ConfigA signers should verify via ConfigB
+ signedReport = _generateV3EncodedBlob(reportT2, s_reportContext, reportSignersConfigA);
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ // deactivating to make sure we are really verifiying via ConfigB
+ s_verifier.setConfigActive(1, false);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ s_verifier.setConfigActive(1, true);
+
+ // testing an old report (block timestamp) with ConfigA signers should verify via ConfigA
+ signedReport = _generateV3EncodedBlob(reportT1, s_reportContext, reportSignersConfigA);
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ // deactivating to make sure we are really verifiying via ConfigB
+ s_verifier.setConfigActive(0, false);
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ s_verifier.setConfigActive(0, true);
+ }
+
+ function test_verifyFailsWhenReportIsOlderThanConfig() public {
+ /*
+ - SetConfig A at time T0
+ - SetConfig B at time T1
+ - tries verifing report issued at blocktimestmap < T0
+
+ this test is failing: ToDo Ask Michael
+ */
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+ address[] memory signerAddrs = _getSignerAddresses(signers);
+ s_reportContext[0] = bytes32(abi.encode(uint32(5), uint8(1)));
+
+ vm.warp(block.timestamp + 100);
+
+ V3Report memory reportAtTMinus100 = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp - 100),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+ vm.warp(block.timestamp + 100);
+ s_verifier.setConfig(signerAddrs, FAULT_TOLERANCE - 1, new Common.AddressAndWeight[](0));
+
+ bytes memory signedReport = _generateV3EncodedBlob(reportAtTMinus100, s_reportContext, signers);
+
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedReport, abi.encode(native));
+ }
+
+ function test_scenarioRollingNewChainWithHistoricConfigs() public {
+ /*
+ This test is checking that we can roll out in a new network and set historic configurations :
+ - Stars with a chain at blocktimestamp 1000
+ - SetConfigA with teimstamp 100
+ - SetConfigB with timesmtap 200
+ - SetConfigC with timestamp current
+ - tries verifying reports for all the configs
+ */
+
+ vm.warp(block.timestamp + 1000);
+
+ Signer[] memory signers = _getSigners(MAX_ORACLES);
+
+ uint8 MINIMAL_FAULT_TOLERANCE = 2;
+ BaseTest.Signer[] memory signersA = new BaseTest.Signer[](7);
+ signersA[0] = signers[0];
+ signersA[1] = signers[1];
+ signersA[2] = signers[2];
+ signersA[3] = signers[3];
+ signersA[4] = signers[4];
+ signersA[5] = signers[5];
+ signersA[6] = signers[6];
+
+ // ConfigA (historical config)
+ uint32 configATimestmap = 100;
+ address[] memory signersAddrA = _getSignerAddresses(signersA);
+ s_verifier.setConfigWithActivationTime(
+ signersAddrA,
+ MINIMAL_FAULT_TOLERANCE,
+ new Common.AddressAndWeight[](0),
+ configATimestmap
+ );
+
+ // ConfigB (historical config)
+ uint32 configBTimestmap = 200;
+ // Config B
+ BaseTest.Signer[] memory signersB = new BaseTest.Signer[](7);
+ // signers in ConfigA
+ signersB[0] = signers[8];
+ signersB[1] = signers[9];
+ signersB[2] = signers[10];
+ signersB[3] = signers[11];
+ signersB[4] = signers[12];
+ signersB[5] = signers[13];
+ signersB[6] = signers[14];
+ address[] memory signersAddrsB = _getSignerAddresses(signersB);
+ s_verifier.setConfigWithActivationTime(
+ signersAddrsB,
+ MINIMAL_FAULT_TOLERANCE,
+ new Common.AddressAndWeight[](0),
+ configBTimestmap
+ );
+
+ // ConfigC (config at current timestamp)
+ // BaseTest.Signer[] memory signersC = new BaseTest.Signer[](7);
+ // signers in ConfigA
+ signersB[6] = signers[15];
+ address[] memory signersAddrsC = _getSignerAddresses(signersB);
+ s_verifier.setConfig(signersAddrsC, MINIMAL_FAULT_TOLERANCE, new Common.AddressAndWeight[](0));
+
+ vm.warp(block.timestamp + 10);
+
+ // historical report
+ V3Report memory s_testReportA = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(101),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp + 1000),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ // historical report
+ V3Report memory s_testReportB = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(201),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp + 1000),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ // report at recent timestamp
+ V3Report memory s_testReportC = V3Report({
+ feedId: FEED_ID_V3,
+ observationsTimestamp: OBSERVATIONS_TIMESTAMP,
+ validFromTimestamp: uint32(block.timestamp),
+ nativeFee: uint192(DEFAULT_REPORT_NATIVE_FEE),
+ linkFee: uint192(DEFAULT_REPORT_LINK_FEE),
+ expiresAt: uint32(block.timestamp + 1000),
+ benchmarkPrice: MEDIAN,
+ bid: BID,
+ ask: ASK
+ });
+
+ BaseTest.Signer[] memory reportSignersA = new BaseTest.Signer[](3);
+ reportSignersA[0] = signers[0];
+ reportSignersA[1] = signers[1];
+ reportSignersA[2] = signers[2];
+
+ BaseTest.Signer[] memory reportSignersB = new BaseTest.Signer[](3);
+ reportSignersB[0] = signers[8];
+ reportSignersB[1] = signers[9];
+ reportSignersB[2] = signers[14];
+
+ BaseTest.Signer[] memory reportSignersC = new BaseTest.Signer[](3);
+ reportSignersC[0] = signers[15];
+ reportSignersC[1] = signers[13];
+ reportSignersC[2] = signers[12];
+
+ bytes memory signedReportA = _generateV3EncodedBlob(s_testReportA, s_reportContext, reportSignersA);
+ bytes memory signedReportB = _generateV3EncodedBlob(s_testReportB, s_reportContext, reportSignersB);
+ bytes memory signedReportC = _generateV3EncodedBlob(s_testReportC, s_reportContext, reportSignersC);
+
+ // verifying historical reports
+ s_verifierProxy.verify(signedReportA, abi.encode(native));
+ s_verifierProxy.verify(signedReportB, abi.encode(native));
+ // verifiying a current report
+ s_verifierProxy.verify(signedReportC, abi.encode(native));
+
+ // current report verified by historical report fails
+ bytes memory signedNewReportWithOldSignatures = _generateV3EncodedBlob(
+ s_testReportC,
+ s_reportContext,
+ reportSignersA
+ );
+ vm.expectRevert(abi.encodeWithSelector(DestinationVerifier.BadVerification.selector));
+ s_verifierProxy.verify(signedNewReportWithOldSignatures, abi.encode(native));
+ }
+}
diff --git a/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol b/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol
index 6fbd37c60d7..c14a03b4443 100644
--- a/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol
+++ b/contracts/src/v0.8/shared/enumerable/EnumerableMapAddresses.sol
@@ -1,12 +1,15 @@
// SPDX-License-Identifier: MIT
+/* solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore */
pragma solidity ^0.8.0;
import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol";
+import {EnumerableMapBytes32} from "./EnumerableMapBytes32.sol";
// TODO: the lib can be replaced with OZ v5.1 post-upgrade, which has AddressToAddressMap and AddressToBytes32Map
library EnumerableMapAddresses {
using EnumerableMap for EnumerableMap.UintToAddressMap;
using EnumerableMap for EnumerableMap.Bytes32ToBytes32Map;
+ using EnumerableMapBytes32 for EnumerableMapBytes32.Bytes32ToBytesMap;
struct AddressToAddressMap {
EnumerableMap.UintToAddressMap _inner;
@@ -57,8 +60,6 @@ library EnumerableMapAddresses {
return map._inner.get(uint256(uint160(key)), errorMessage);
}
- // AddressToBytes32Map
-
struct AddressToBytes32Map {
EnumerableMap.Bytes32ToBytes32Map _inner;
}
@@ -137,4 +138,88 @@ library EnumerableMapAddresses {
function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) {
return map._inner.get(bytes32(uint256(uint160(key))));
}
+
+ struct AddressToBytesMap {
+ EnumerableMapBytes32.Bytes32ToBytesMap _inner;
+ }
+
+ /**
+ * @dev Sets the value for `key` in the map. Returns true if the key was added to the map, that is if it was not already present.
+ * @param map The map where the value will be set
+ * @param key The key to set the value for
+ * @param value The value to set for the key
+ * @return bool indicating whether the key was added to the map
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function set(AddressToBytesMap storage map, address key, bytes memory value) internal returns (bool) {
+ return map._inner.set(bytes32(uint256(uint160(key))), value);
+ }
+
+ /**
+ * @dev Removes the value for `key` in the map. Returns true if the key was removed from the map, that is if it was present.
+ * @param map The map where the value will be removed
+ * @param key The key to remove the value for
+ * @return bool indicating whether the key was removed from the map
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function remove(AddressToBytesMap storage map, address key) internal returns (bool) {
+ return map._inner.remove(bytes32(uint256(uint160(key))));
+ }
+
+ /**
+ * @dev Checks if the map contains the `key`. Returns true if the key is in the map.
+ * @param map The map to check for the presence of the key
+ * @param key The key to check for presence in the map
+ * @return bool indicating whether the key is in the map
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function contains(AddressToBytesMap storage map, address key) internal view returns (bool) {
+ return map._inner.contains(bytes32(uint256(uint160(key))));
+ }
+
+ /**
+ * @dev Returns the number of elements in the map.
+ * @param map The map to check the length of
+ * @return uint256 indicating the number of elements in the map
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function length(AddressToBytesMap storage map) internal view returns (uint256) {
+ return map._inner.length();
+ }
+
+ /**
+ * @dev Returns the element stored at position `index` in the map. Note that there are no guarantees on the ordering of values inside the array, and it may change when more values are added or removed.
+ * @param map The map to retrieve the element from
+ * @param index The index to retrieve the element at
+ * @return address The key of the element at the specified index
+ * @return bytes The value of the element at the specified index
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function at(AddressToBytesMap storage map, uint256 index) internal view returns (address, bytes memory) {
+ (bytes32 key, bytes memory value) = map._inner.at(index);
+ return (address(uint160(uint256(key))), value);
+ }
+
+ /**
+ * @dev Tries to return the value associated with `key`. Does not revert if `key` is not in the map.
+ * @param map The map to retrieve the value from
+ * @param key The key to retrieve the value for
+ * @return bool indicating whether the key was in the map
+ * @return bytes The value associated with the key
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function tryGet(AddressToBytesMap storage map, address key) internal view returns (bool, bytes memory) {
+ return map._inner.tryGet(bytes32(uint256(uint160(key))));
+ }
+
+ /**
+ * @dev Returns the value associated with `key`.
+ * @param map The map to retrieve the value from
+ * @param key The key to retrieve the value for
+ * @return bytes The value associated with the key
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function get(AddressToBytesMap storage map, address key) internal view returns (bytes memory) {
+ return map._inner.get(bytes32(uint256(uint160(key))));
+ }
}
diff --git a/contracts/src/v0.8/shared/enumerable/EnumerableMapBytes32.sol b/contracts/src/v0.8/shared/enumerable/EnumerableMapBytes32.sol
new file mode 100644
index 00000000000..2ec9098f855
--- /dev/null
+++ b/contracts/src/v0.8/shared/enumerable/EnumerableMapBytes32.sol
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: MIT
+/* solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore */
+pragma solidity ^0.8.0;
+
+import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";
+
+/**
+ * @dev Library for managing an enumerable variant of Solidity's
+ * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
+ * type.
+ *
+ * Maps have the following properties:
+ *
+ * - Entries are added, removed, and checked for existence in constant time
+ * (O(1)).
+ * - Entries are enumerated in O(n). No guarantees are made on the ordering.
+ *
+ * ```
+ * contract Example {
+ * // Add the library methods
+ * using EnumerableMapBytes32 for EnumerableMapBytes32.Bytes32ToBytesMap;
+ *
+ * // Declare a set state variable
+ * EnumerableMapBytes32.Bytes32ToBytesMap private myMap;
+ * }
+ * ```
+ *
+ * The following map types are supported:
+ *
+ * - `bytes32 -> bytes` (`Bytes32ToBytes`)
+ *
+ * [WARNING]
+ * ====
+ * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
+ * unusable.
+ * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
+ *
+ * In order to clean up an EnumerableMapBytes32, you should remove all elements one by one.
+ * ====
+ */
+library EnumerableMapBytes32 {
+ using EnumerableSet for EnumerableSet.Bytes32Set;
+
+ error NonexistentKeyError();
+
+ struct Bytes32ToBytesMap {
+ EnumerableSet.Bytes32Set _keys;
+ mapping(bytes32 => bytes) _values;
+ }
+
+ /**
+ * @dev Adds a key-value pair to a map, or updates the value for an existing
+ * key. O(1).
+ *
+ * Returns true if the key was added to the map, that is if it was not
+ * already present.
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function set(Bytes32ToBytesMap storage map, bytes32 key, bytes memory value) internal returns (bool) {
+ map._values[key] = value;
+ return map._keys.add(key);
+ }
+
+ /**
+ * @dev Removes a key-value pair from a map. O(1).
+ *
+ * Returns true if the key was removed from the map, that is if it was present.
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function remove(Bytes32ToBytesMap storage map, bytes32 key) internal returns (bool) {
+ delete map._values[key];
+ return map._keys.remove(key);
+ }
+
+ /**
+ * @dev Returns true if the key is in the map. O(1).
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function contains(Bytes32ToBytesMap storage map, bytes32 key) internal view returns (bool) {
+ return map._keys.contains(key);
+ }
+
+ /**
+ * @dev Returns the number of key-value pairs in the map. O(1).
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function length(Bytes32ToBytesMap storage map) internal view returns (uint256) {
+ return map._keys.length();
+ }
+
+ /**
+ * @dev Returns the key-value pair stored at position `index` in the map. O(1).
+ *
+ * Note that there are no guarantees on the ordering of entries inside the
+ * array, and it may change when more entries are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function at(Bytes32ToBytesMap storage map, uint256 index) internal view returns (bytes32, bytes memory) {
+ bytes32 key = map._keys.at(index);
+ return (key, map._values[key]);
+ }
+
+ /**
+ * @dev Tries to returns the value associated with `key`. O(1).
+ * Does not revert if `key` is not in the map.
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function tryGet(Bytes32ToBytesMap storage map, bytes32 key) internal view returns (bool, bytes memory) {
+ bytes memory value = map._values[key];
+ if (value.length == 0) {
+ return (contains(map, key), bytes(""));
+ } else {
+ return (true, value);
+ }
+ }
+
+ /**
+ * @dev Returns the value associated with `key`. O(1).
+ *
+ * Requirements:
+ *
+ * - `key` must be in the map.
+ */
+ // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
+ function get(Bytes32ToBytesMap storage map, bytes32 key) internal view returns (bytes memory) {
+ bytes memory value = map._values[key];
+ if (value.length == 0 && !contains(map, key)) {
+ revert NonexistentKeyError();
+ }
+ return value;
+ }
+}
diff --git a/contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol b/contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol
index 900c546f66d..097e79e372e 100644
--- a/contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol
+++ b/contracts/src/v0.8/shared/test/enumerable/EnumerableMapAddresses.t.sol
@@ -7,11 +7,14 @@ import {EnumerableMapAddresses} from "../../enumerable/EnumerableMapAddresses.so
contract EnumerableMapAddressesTest is BaseTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
EnumerableMapAddresses.AddressToAddressMap internal s_addressToAddressMap;
EnumerableMapAddresses.AddressToBytes32Map internal s_addressToBytes32Map;
+ EnumerableMapAddresses.AddressToBytesMap internal s_addressToBytesMap;
bytes32 internal constant MOCK_BYTES32_VALUE = bytes32(uint256(42));
+ bytes internal constant MOCK_BYTES_VALUE = "0x123456789abcdef";
function setUp() public virtual override {
BaseTest.setUp();
@@ -21,6 +24,7 @@ contract EnumerableMapAddressesTest is BaseTest {
contract EnumerableMapAddresses_set is EnumerableMapAddressesTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
function testSetSuccess() public {
assertTrue(!s_addressToAddressMap.contains(address(this)));
@@ -35,11 +39,19 @@ contract EnumerableMapAddresses_set is EnumerableMapAddressesTest {
assertTrue(s_addressToBytes32Map.contains(address(this)));
assertTrue(!s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE));
}
+
+ function testBytesSetSuccess() public {
+ assertTrue(!s_addressToBytesMap.contains(address(this)));
+ assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ assertTrue(s_addressToBytesMap.contains(address(this)));
+ assertTrue(!s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ }
}
contract EnumerableMapAddresses_remove is EnumerableMapAddressesTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
function testRemoveSuccess() public {
assertTrue(!s_addressToAddressMap.contains(address(this)));
@@ -58,11 +70,21 @@ contract EnumerableMapAddresses_remove is EnumerableMapAddressesTest {
assertTrue(!s_addressToBytes32Map.contains(address(this)));
assertTrue(!s_addressToBytes32Map.remove(address(this)));
}
+
+ function testBytesRemoveSuccess() public {
+ assertTrue(!s_addressToBytesMap.contains(address(this)));
+ assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ assertTrue(s_addressToBytesMap.contains(address(this)));
+ assertTrue(s_addressToBytesMap.remove(address(this)));
+ assertTrue(!s_addressToBytesMap.contains(address(this)));
+ assertTrue(!s_addressToBytesMap.remove(address(this)));
+ }
}
contract EnumerableMapAddresses_contains is EnumerableMapAddressesTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
function testContainsSuccess() public {
assertTrue(!s_addressToAddressMap.contains(address(this)));
@@ -75,55 +97,81 @@ contract EnumerableMapAddresses_contains is EnumerableMapAddressesTest {
assertTrue(s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE));
assertTrue(s_addressToBytes32Map.contains(address(this)));
}
+
+ function testBytesContainsSuccess() public {
+ assertTrue(!s_addressToBytesMap.contains(address(this)));
+ assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ assertTrue(s_addressToBytesMap.contains(address(this)));
+ }
}
contract EnumerableMapAddresses_length is EnumerableMapAddressesTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
function testLengthSuccess() public {
- assertTrue(s_addressToAddressMap.length() == 0);
+ assertEq(s_addressToAddressMap.length(), 0);
assertTrue(s_addressToAddressMap.set(address(this), address(this)));
- assertTrue(s_addressToAddressMap.length() == 1);
+ assertEq(s_addressToAddressMap.length(), 1);
assertTrue(s_addressToAddressMap.remove(address(this)));
- assertTrue(s_addressToAddressMap.length() == 0);
+ assertEq(s_addressToAddressMap.length(), 0);
}
function testBytes32LengthSuccess() public {
- assertTrue(s_addressToBytes32Map.length() == 0);
+ assertEq(s_addressToBytes32Map.length(), 0);
assertTrue(s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE));
- assertTrue(s_addressToBytes32Map.length() == 1);
+ assertEq(s_addressToBytes32Map.length(), 1);
assertTrue(s_addressToBytes32Map.remove(address(this)));
- assertTrue(s_addressToBytes32Map.length() == 0);
+ assertEq(s_addressToBytes32Map.length(), 0);
+ }
+
+ function testBytesLengthSuccess() public {
+ assertEq(s_addressToBytesMap.length(), 0);
+ assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ assertEq(s_addressToBytesMap.length(), 1);
+ assertTrue(s_addressToBytesMap.remove(address(this)));
+ assertEq(s_addressToBytesMap.length(), 0);
}
}
contract EnumerableMapAddresses_at is EnumerableMapAddressesTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
function testAtSuccess() public {
- assertTrue(s_addressToAddressMap.length() == 0);
+ assertEq(s_addressToAddressMap.length(), 0);
assertTrue(s_addressToAddressMap.set(address(this), address(this)));
- assertTrue(s_addressToAddressMap.length() == 1);
+ assertEq(s_addressToAddressMap.length(), 1);
(address key, address value) = s_addressToAddressMap.at(0);
- assertTrue(key == address(this));
- assertTrue(value == address(this));
+ assertEq(key, address(this));
+ assertEq(value, address(this));
}
function testBytes32AtSuccess() public {
- assertTrue(s_addressToBytes32Map.length() == 0);
+ assertEq(s_addressToBytes32Map.length(), 0);
assertTrue(s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE));
- assertTrue(s_addressToBytes32Map.length() == 1);
+ assertEq(s_addressToBytes32Map.length(), 1);
(address key, bytes32 value) = s_addressToBytes32Map.at(0);
- assertTrue(key == address(this));
- assertTrue(value == MOCK_BYTES32_VALUE);
+ assertEq(key, address(this));
+ assertEq(value, MOCK_BYTES32_VALUE);
+ }
+
+ function testBytesAtSuccess() public {
+ assertEq(s_addressToBytesMap.length(), 0);
+ assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ assertEq(s_addressToBytesMap.length(), 1);
+ (address key, bytes memory value) = s_addressToBytesMap.at(0);
+ assertEq(key, address(this));
+ assertEq(value, MOCK_BYTES_VALUE);
}
}
contract EnumerableMapAddresses_tryGet is EnumerableMapAddressesTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
function testTryGetSuccess() public {
assertTrue(!s_addressToAddressMap.contains(address(this)));
@@ -131,7 +179,7 @@ contract EnumerableMapAddresses_tryGet is EnumerableMapAddressesTest {
assertTrue(s_addressToAddressMap.contains(address(this)));
(bool success, address value) = s_addressToAddressMap.tryGet(address(this));
assertTrue(success);
- assertTrue(value == address(this));
+ assertEq(value, address(this));
}
function testBytes32TryGetSuccess() public {
@@ -140,37 +188,62 @@ contract EnumerableMapAddresses_tryGet is EnumerableMapAddressesTest {
assertTrue(s_addressToBytes32Map.contains(address(this)));
(bool success, bytes32 value) = s_addressToBytes32Map.tryGet(address(this));
assertTrue(success);
- assertTrue(value == MOCK_BYTES32_VALUE);
+ assertEq(value, MOCK_BYTES32_VALUE);
+ }
+
+ function testBytesTryGetSuccess() public {
+ assertTrue(!s_addressToBytesMap.contains(address(this)));
+ assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ assertTrue(s_addressToBytesMap.contains(address(this)));
+ (bool success, bytes memory value) = s_addressToBytesMap.tryGet(address(this));
+ assertTrue(success);
+ assertEq(value, MOCK_BYTES_VALUE);
}
}
contract EnumerableMapAddresses_get is EnumerableMapAddressesTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
function testGetSuccess() public {
assertTrue(!s_addressToAddressMap.contains(address(this)));
assertTrue(s_addressToAddressMap.set(address(this), address(this)));
assertTrue(s_addressToAddressMap.contains(address(this)));
- assertTrue(s_addressToAddressMap.get(address(this)) == address(this));
+ assertEq(s_addressToAddressMap.get(address(this)), address(this));
}
function testBytes32GetSuccess() public {
assertTrue(!s_addressToBytes32Map.contains(address(this)));
assertTrue(s_addressToBytes32Map.set(address(this), MOCK_BYTES32_VALUE));
assertTrue(s_addressToBytes32Map.contains(address(this)));
- assertTrue(s_addressToBytes32Map.get(address(this)) == MOCK_BYTES32_VALUE);
+ assertEq(s_addressToBytes32Map.get(address(this)), MOCK_BYTES32_VALUE);
+ }
+
+ function testBytesGetSuccess() public {
+ assertTrue(!s_addressToBytesMap.contains(address(this)));
+ assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ assertTrue(s_addressToBytesMap.contains(address(this)));
+ assertEq(s_addressToBytesMap.get(address(this)), MOCK_BYTES_VALUE);
}
}
contract EnumerableMapAddresses_get_errorMessage is EnumerableMapAddressesTest {
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytes32Map;
using EnumerableMapAddresses for EnumerableMapAddresses.AddressToAddressMap;
+ using EnumerableMapAddresses for EnumerableMapAddresses.AddressToBytesMap;
function testGetErrorMessageSuccess() public {
assertTrue(!s_addressToAddressMap.contains(address(this)));
assertTrue(s_addressToAddressMap.set(address(this), address(this)));
assertTrue(s_addressToAddressMap.contains(address(this)));
- assertTrue(s_addressToAddressMap.get(address(this), "EnumerableMapAddresses: nonexistent key") == address(this));
+ assertEq(s_addressToAddressMap.get(address(this), "EnumerableMapAddresses: nonexistent key"), address(this));
+ }
+
+ function testBytesGetErrorMessageSuccess() public {
+ assertTrue(!s_addressToBytesMap.contains(address(this)));
+ assertTrue(s_addressToBytesMap.set(address(this), MOCK_BYTES_VALUE));
+ assertTrue(s_addressToBytesMap.contains(address(this)));
+ assertEq(s_addressToBytesMap.get(address(this)), MOCK_BYTES_VALUE);
}
}
diff --git a/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol b/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol
index 58a4b9a25c5..709d00cc382 100644
--- a/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol
+++ b/contracts/src/v0.8/shared/test/helpers/ChainReaderTester.sol
@@ -40,6 +40,9 @@ contract ChainReaderTester {
// First topic is event hash
event TriggeredWithFourTopics(int32 indexed field1, int32 indexed field2, int32 indexed field3);
+ // first topic is event hash, second and third topics get hashed before getting stored
+ event TriggeredWithFourTopicsWithHashed(string indexed field1, uint8[32] indexed field2, bytes32 indexed field3);
+
TestStruct[] private s_seen;
uint64[] private s_arr;
uint64 private s_value;
@@ -125,4 +128,9 @@ contract ChainReaderTester {
function triggerWithFourTopics(int32 field1, int32 field2, int32 field3) public {
emit TriggeredWithFourTopics(field1, field2, field3);
}
+
+ // first topic is event hash, second and third topics get hashed before getting stored
+ function triggerWithFourTopicsWithHashed(string memory field1, uint8[32] memory field2, bytes32 field3) public {
+ emit TriggeredWithFourTopicsWithHashed(field1, field2, field3);
+ }
}
diff --git a/contracts/src/v0.8/tests/MockGasBoundCaller.sol b/contracts/src/v0.8/tests/MockGasBoundCaller.sol
new file mode 100644
index 00000000000..3184f9dba38
--- /dev/null
+++ b/contracts/src/v0.8/tests/MockGasBoundCaller.sol
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.19;
+
+contract MockGasBoundCaller {
+ error TransactionFailed(address target);
+
+ function gasBoundCall(address target, uint256 gasAmount, bytes memory data) external payable {
+ bool success;
+ assembly {
+ success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0)
+ }
+
+ // gas bound caller will propagate the revert
+ if (!success) {
+ revert TransactionFailed(target);
+ }
+
+ uint256 pubdataGas = 500000;
+ bytes memory returnData = abi.encode(address(0), pubdataGas);
+
+ uint256 paddedReturndataLen = returnData.length + 96;
+ if (paddedReturndataLen % 32 != 0) {
+ paddedReturndataLen += 32 - (paddedReturndataLen % 32);
+ }
+
+ assembly {
+ mstore(sub(returnData, 0x40), 0x40)
+ mstore(sub(returnData, 0x20), pubdataGas)
+ return(sub(returnData, 0x40), paddedReturndataLen)
+ }
+ }
+}
diff --git a/contracts/src/v0.8/tests/MockOVMGasPriceOracle.sol b/contracts/src/v0.8/tests/MockOVMGasPriceOracle.sol
index 29790b0e150..6bb0dae6455 100644
--- a/contracts/src/v0.8/tests/MockOVMGasPriceOracle.sol
+++ b/contracts/src/v0.8/tests/MockOVMGasPriceOracle.sol
@@ -1,7 +1,12 @@
+// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;
contract MockOVMGasPriceOracle {
- function getL1Fee(bytes memory _data) public view returns (uint256) {
+ function getL1Fee(bytes memory) public pure returns (uint256) {
+ return 2000000;
+ }
+
+ function getL1FeeUpperBound(uint256) public pure returns (uint256) {
return 2000000;
}
}
diff --git a/contracts/src/v0.8/tests/MockZKSyncSystemContext.sol b/contracts/src/v0.8/tests/MockZKSyncSystemContext.sol
new file mode 100644
index 00000000000..265d4b678a5
--- /dev/null
+++ b/contracts/src/v0.8/tests/MockZKSyncSystemContext.sol
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.19;
+
+contract MockZKSyncSystemContext {
+ function gasPrice() external pure returns (uint256) {
+ return 250000000; // 0.25 gwei
+ }
+
+ function gasPerPubdataByte() external pure returns (uint256) {
+ return 500;
+ }
+
+ function getCurrentPubdataSpent() external pure returns (uint256 currentPubdataSpent) {
+ return 1000;
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol
new file mode 100644
index 00000000000..4daefc5d4f2
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165Checker.sol
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v4.8.2) (utils/introspection/ERC165Checker.sol)
+
+pragma solidity ^0.8.0;
+
+import "./IERC165.sol";
+
+/**
+ * @dev Library used to query support of an interface declared via {IERC165}.
+ *
+ * Note that these functions return the actual result of the query: they do not
+ * `revert` if an interface is not supported. It is up to the caller to decide
+ * what to do in these cases.
+ */
+library ERC165Checker {
+ // As per the EIP-165 spec, no interface should ever match 0xffffffff
+ bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;
+
+ /**
+ * @dev Returns true if `account` supports the {IERC165} interface.
+ */
+ function supportsERC165(address account) internal view returns (bool) {
+ // Any contract that implements ERC165 must explicitly indicate support of
+ // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
+ return
+ supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
+ !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
+ }
+
+ /**
+ * @dev Returns true if `account` supports the interface defined by
+ * `interfaceId`. Support for {IERC165} itself is queried automatically.
+ *
+ * See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
+ // query support of both ERC165 as per the spec and support of _interfaceId
+ return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
+ }
+
+ /**
+ * @dev Returns a boolean array where each value corresponds to the
+ * interfaces passed in and whether they're supported or not. This allows
+ * you to batch check interfaces for a contract where your expectation
+ * is that some interfaces may not be supported.
+ *
+ * See {IERC165-supportsInterface}.
+ *
+ * _Available since v3.4._
+ */
+ function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
+ internal
+ view
+ returns (bool[] memory)
+ {
+ // an array of booleans corresponding to interfaceIds and whether they're supported or not
+ bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
+
+ // query support of ERC165 itself
+ if (supportsERC165(account)) {
+ // query support of each interface in interfaceIds
+ for (uint256 i = 0; i < interfaceIds.length; i++) {
+ interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
+ }
+ }
+
+ return interfaceIdsSupported;
+ }
+
+ /**
+ * @dev Returns true if `account` supports all the interfaces defined in
+ * `interfaceIds`. Support for {IERC165} itself is queried automatically.
+ *
+ * Batch-querying can lead to gas savings by skipping repeated checks for
+ * {IERC165} support.
+ *
+ * See {IERC165-supportsInterface}.
+ */
+ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
+ // query support of ERC165 itself
+ if (!supportsERC165(account)) {
+ return false;
+ }
+
+ // query support of each interface in interfaceIds
+ for (uint256 i = 0; i < interfaceIds.length; i++) {
+ if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
+ return false;
+ }
+ }
+
+ // all interfaces supported
+ return true;
+ }
+
+ /**
+ * @notice Query if a contract implements an interface, does not check ERC165 support
+ * @param account The address of the contract to query for support of an interface
+ * @param interfaceId The interface identifier, as specified in ERC-165
+ * @return true if the contract at account indicates support of the interface with
+ * identifier interfaceId, false otherwise
+ * @dev Assumes that account contains a contract that supports ERC165, otherwise
+ * the behavior of this method is undefined. This precondition can be checked
+ * with {supportsERC165}.
+ *
+ * Some precompiled contracts will falsely indicate support for a given interface, so caution
+ * should be exercised when using this function.
+ *
+ * Interface identification is specified in ERC-165.
+ */
+ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
+ // prepare call
+ bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
+
+ // perform static call
+ bool success;
+ uint256 returnSize;
+ uint256 returnValue;
+ assembly {
+ success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
+ returnSize := returndatasize()
+ returnValue := mload(0x00)
+ }
+
+ return success && returnSize >= 0x20 && returnValue > 0;
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/access/AccessControl.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/access/AccessControl.sol
new file mode 100644
index 00000000000..3e3341e9cfd
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/access/AccessControl.sol
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
+
+pragma solidity ^0.8.20;
+
+import {IAccessControl} from "./IAccessControl.sol";
+import {Context} from "../utils/Context.sol";
+import {ERC165} from "../utils/introspection/ERC165.sol";
+
+/**
+ * @dev Contract module that allows children to implement role-based access
+ * control mechanisms. This is a lightweight version that doesn't allow enumerating role
+ * members except through off-chain means by accessing the contract event logs. Some
+ * applications may benefit from on-chain enumerability, for those cases see
+ * {AccessControlEnumerable}.
+ *
+ * Roles are referred to by their `bytes32` identifier. These should be exposed
+ * in the external API and be unique. The best way to achieve this is by
+ * using `public constant` hash digests:
+ *
+ * ```solidity
+ * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
+ * ```
+ *
+ * Roles can be used to represent a set of permissions. To restrict access to a
+ * function call, use {hasRole}:
+ *
+ * ```solidity
+ * function foo() public {
+ * require(hasRole(MY_ROLE, msg.sender));
+ * ...
+ * }
+ * ```
+ *
+ * Roles can be granted and revoked dynamically via the {grantRole} and
+ * {revokeRole} functions. Each role has an associated admin role, and only
+ * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
+ *
+ * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
+ * that only accounts with this role will be able to grant or revoke other
+ * roles. More complex role relationships can be created by using
+ * {_setRoleAdmin}.
+ *
+ * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
+ * grant and revoke this role. Extra precautions should be taken to secure
+ * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
+ * to enforce additional security measures for this role.
+ */
+abstract contract AccessControl is Context, IAccessControl, ERC165 {
+ struct RoleData {
+ mapping(address account => bool) hasRole;
+ bytes32 adminRole;
+ }
+
+ mapping(bytes32 role => RoleData) private _roles;
+
+ bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
+
+ /**
+ * @dev Modifier that checks that an account has a specific role. Reverts
+ * with an {AccessControlUnauthorizedAccount} error including the required role.
+ */
+ modifier onlyRole(bytes32 role) {
+ _checkRole(role);
+ _;
+ }
+
+ /**
+ * @dev See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
+ }
+
+ /**
+ * @dev Returns `true` if `account` has been granted `role`.
+ */
+ function hasRole(bytes32 role, address account) public view virtual returns (bool) {
+ return _roles[role].hasRole[account];
+ }
+
+ /**
+ * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
+ * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
+ */
+ function _checkRole(bytes32 role) internal view virtual {
+ _checkRole(role, _msgSender());
+ }
+
+ /**
+ * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
+ * is missing `role`.
+ */
+ function _checkRole(bytes32 role, address account) internal view virtual {
+ if (!hasRole(role, account)) {
+ revert AccessControlUnauthorizedAccount(account, role);
+ }
+ }
+
+ /**
+ * @dev Returns the admin role that controls `role`. See {grantRole} and
+ * {revokeRole}.
+ *
+ * To change a role's admin, use {_setRoleAdmin}.
+ */
+ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
+ return _roles[role].adminRole;
+ }
+
+ /**
+ * @dev Grants `role` to `account`.
+ *
+ * If `account` had not been already granted `role`, emits a {RoleGranted}
+ * event.
+ *
+ * Requirements:
+ *
+ * - the caller must have ``role``'s admin role.
+ *
+ * May emit a {RoleGranted} event.
+ */
+ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
+ _grantRole(role, account);
+ }
+
+ /**
+ * @dev Revokes `role` from `account`.
+ *
+ * If `account` had been granted `role`, emits a {RoleRevoked} event.
+ *
+ * Requirements:
+ *
+ * - the caller must have ``role``'s admin role.
+ *
+ * May emit a {RoleRevoked} event.
+ */
+ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
+ _revokeRole(role, account);
+ }
+
+ /**
+ * @dev Revokes `role` from the calling account.
+ *
+ * Roles are often managed via {grantRole} and {revokeRole}: this function's
+ * purpose is to provide a mechanism for accounts to lose their privileges
+ * if they are compromised (such as when a trusted device is misplaced).
+ *
+ * If the calling account had been revoked `role`, emits a {RoleRevoked}
+ * event.
+ *
+ * Requirements:
+ *
+ * - the caller must be `callerConfirmation`.
+ *
+ * May emit a {RoleRevoked} event.
+ */
+ function renounceRole(bytes32 role, address callerConfirmation) public virtual {
+ if (callerConfirmation != _msgSender()) {
+ revert AccessControlBadConfirmation();
+ }
+
+ _revokeRole(role, callerConfirmation);
+ }
+
+ /**
+ * @dev Sets `adminRole` as ``role``'s admin role.
+ *
+ * Emits a {RoleAdminChanged} event.
+ */
+ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
+ bytes32 previousAdminRole = getRoleAdmin(role);
+ _roles[role].adminRole = adminRole;
+ emit RoleAdminChanged(role, previousAdminRole, adminRole);
+ }
+
+ /**
+ * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
+ *
+ * Internal function without access restriction.
+ *
+ * May emit a {RoleGranted} event.
+ */
+ function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
+ if (!hasRole(role, account)) {
+ _roles[role].hasRole[account] = true;
+ emit RoleGranted(role, account, _msgSender());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
+ *
+ * Internal function without access restriction.
+ *
+ * May emit a {RoleRevoked} event.
+ */
+ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
+ if (hasRole(role, account)) {
+ _roles[role].hasRole[account] = false;
+ emit RoleRevoked(role, account, _msgSender());
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/access/IAccessControl.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/access/IAccessControl.sol
new file mode 100644
index 00000000000..2ac89ca7356
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/access/IAccessControl.sol
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev External interface of AccessControl declared to support ERC165 detection.
+ */
+interface IAccessControl {
+ /**
+ * @dev The `account` is missing a role.
+ */
+ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
+
+ /**
+ * @dev The caller of a function is not the expected one.
+ *
+ * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
+ */
+ error AccessControlBadConfirmation();
+
+ /**
+ * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
+ *
+ * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
+ * {RoleAdminChanged} not being emitted signaling this.
+ */
+ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
+
+ /**
+ * @dev Emitted when `account` is granted `role`.
+ *
+ * `sender` is the account that originated the contract call, an admin role
+ * bearer except when using {AccessControl-_setupRole}.
+ */
+ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
+
+ /**
+ * @dev Emitted when `account` is revoked `role`.
+ *
+ * `sender` is the account that originated the contract call:
+ * - if using `revokeRole`, it is the admin role bearer
+ * - if using `renounceRole`, it is the role bearer (i.e. `account`)
+ */
+ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
+
+ /**
+ * @dev Returns `true` if `account` has been granted `role`.
+ */
+ function hasRole(bytes32 role, address account) external view returns (bool);
+
+ /**
+ * @dev Returns the admin role that controls `role`. See {grantRole} and
+ * {revokeRole}.
+ *
+ * To change a role's admin, use {AccessControl-_setRoleAdmin}.
+ */
+ function getRoleAdmin(bytes32 role) external view returns (bytes32);
+
+ /**
+ * @dev Grants `role` to `account`.
+ *
+ * If `account` had not been already granted `role`, emits a {RoleGranted}
+ * event.
+ *
+ * Requirements:
+ *
+ * - the caller must have ``role``'s admin role.
+ */
+ function grantRole(bytes32 role, address account) external;
+
+ /**
+ * @dev Revokes `role` from `account`.
+ *
+ * If `account` had been granted `role`, emits a {RoleRevoked} event.
+ *
+ * Requirements:
+ *
+ * - the caller must have ``role``'s admin role.
+ */
+ function revokeRole(bytes32 role, address account) external;
+
+ /**
+ * @dev Revokes `role` from the calling account.
+ *
+ * Roles are often managed via {grantRole} and {revokeRole}: this function's
+ * purpose is to provide a mechanism for accounts to lose their privileges
+ * if they are compromised (such as when a trusted device is misplaced).
+ *
+ * If the calling account had been granted `role`, emits a {RoleRevoked}
+ * event.
+ *
+ * Requirements:
+ *
+ * - the caller must be `callerConfirmation`.
+ */
+ function renounceRole(bytes32 role, address callerConfirmation) external;
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC165.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC165.sol
new file mode 100644
index 00000000000..944dd0d5912
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC165.sol
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
+
+pragma solidity ^0.8.20;
+
+import {IERC165} from "../utils/introspection/IERC165.sol";
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC20.sol
new file mode 100644
index 00000000000..21d5a413275
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC20.sol
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
+
+pragma solidity ^0.8.20;
+
+import {IERC20} from "../token/ERC20/IERC20.sol";
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC5267.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC5267.sol
new file mode 100644
index 00000000000..47a9fd58855
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/IERC5267.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
+
+pragma solidity ^0.8.20;
+
+interface IERC5267 {
+ /**
+ * @dev MAY be emitted to signal that the domain could have changed.
+ */
+ event EIP712DomainChanged();
+
+ /**
+ * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
+ * signature.
+ */
+ function eip712Domain()
+ external
+ view
+ returns (
+ bytes1 fields,
+ string memory name,
+ string memory version,
+ uint256 chainId,
+ address verifyingContract,
+ bytes32 salt,
+ uint256[] memory extensions
+ );
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/draft-IERC6093.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/draft-IERC6093.sol
new file mode 100644
index 00000000000..f6990e607c9
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/interfaces/draft-IERC6093.sol
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Standard ERC20 Errors
+ * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
+ */
+interface IERC20Errors {
+ /**
+ * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
+ * @param sender Address whose tokens are being transferred.
+ * @param balance Current balance for the interacting account.
+ * @param needed Minimum amount required to perform a transfer.
+ */
+ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
+
+ /**
+ * @dev Indicates a failure with the token `sender`. Used in transfers.
+ * @param sender Address whose tokens are being transferred.
+ */
+ error ERC20InvalidSender(address sender);
+
+ /**
+ * @dev Indicates a failure with the token `receiver`. Used in transfers.
+ * @param receiver Address to which tokens are being transferred.
+ */
+ error ERC20InvalidReceiver(address receiver);
+
+ /**
+ * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
+ * @param spender Address that may be allowed to operate on tokens without being their owner.
+ * @param allowance Amount of tokens a `spender` is allowed to operate with.
+ * @param needed Minimum amount required to perform a transfer.
+ */
+ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
+
+ /**
+ * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
+ * @param approver Address initiating an approval operation.
+ */
+ error ERC20InvalidApprover(address approver);
+
+ /**
+ * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
+ * @param spender Address that may be allowed to operate on tokens without being their owner.
+ */
+ error ERC20InvalidSpender(address spender);
+}
+
+/**
+ * @dev Standard ERC721 Errors
+ * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
+ */
+interface IERC721Errors {
+ /**
+ * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
+ * Used in balance queries.
+ * @param owner Address of the current owner of a token.
+ */
+ error ERC721InvalidOwner(address owner);
+
+ /**
+ * @dev Indicates a `tokenId` whose `owner` is the zero address.
+ * @param tokenId Identifier number of a token.
+ */
+ error ERC721NonexistentToken(uint256 tokenId);
+
+ /**
+ * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
+ * @param sender Address whose tokens are being transferred.
+ * @param tokenId Identifier number of a token.
+ * @param owner Address of the current owner of a token.
+ */
+ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
+
+ /**
+ * @dev Indicates a failure with the token `sender`. Used in transfers.
+ * @param sender Address whose tokens are being transferred.
+ */
+ error ERC721InvalidSender(address sender);
+
+ /**
+ * @dev Indicates a failure with the token `receiver`. Used in transfers.
+ * @param receiver Address to which tokens are being transferred.
+ */
+ error ERC721InvalidReceiver(address receiver);
+
+ /**
+ * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
+ * @param operator Address that may be allowed to operate on tokens without being their owner.
+ * @param tokenId Identifier number of a token.
+ */
+ error ERC721InsufficientApproval(address operator, uint256 tokenId);
+
+ /**
+ * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
+ * @param approver Address initiating an approval operation.
+ */
+ error ERC721InvalidApprover(address approver);
+
+ /**
+ * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
+ * @param operator Address that may be allowed to operate on tokens without being their owner.
+ */
+ error ERC721InvalidOperator(address operator);
+}
+
+/**
+ * @dev Standard ERC1155 Errors
+ * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
+ */
+interface IERC1155Errors {
+ /**
+ * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
+ * @param sender Address whose tokens are being transferred.
+ * @param balance Current balance for the interacting account.
+ * @param needed Minimum amount required to perform a transfer.
+ * @param tokenId Identifier number of a token.
+ */
+ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
+
+ /**
+ * @dev Indicates a failure with the token `sender`. Used in transfers.
+ * @param sender Address whose tokens are being transferred.
+ */
+ error ERC1155InvalidSender(address sender);
+
+ /**
+ * @dev Indicates a failure with the token `receiver`. Used in transfers.
+ * @param receiver Address to which tokens are being transferred.
+ */
+ error ERC1155InvalidReceiver(address receiver);
+
+ /**
+ * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
+ * @param operator Address that may be allowed to operate on tokens without being their owner.
+ * @param owner Address of the current owner of a token.
+ */
+ error ERC1155MissingApprovalForAll(address operator, address owner);
+
+ /**
+ * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
+ * @param approver Address initiating an approval operation.
+ */
+ error ERC1155InvalidApprover(address approver);
+
+ /**
+ * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
+ * @param operator Address that may be allowed to operate on tokens without being their owner.
+ */
+ error ERC1155InvalidOperator(address operator);
+
+ /**
+ * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
+ * Used in batch transfers.
+ * @param idsLength Length of the array of token identifiers
+ * @param valuesLength Length of the array of token amounts
+ */
+ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/ERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/ERC20.sol
new file mode 100644
index 00000000000..1fde5279d00
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/ERC20.sol
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
+
+pragma solidity ^0.8.20;
+
+import {IERC20} from "./IERC20.sol";
+import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
+import {Context} from "../../utils/Context.sol";
+import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
+
+/**
+ * @dev Implementation of the {IERC20} interface.
+ *
+ * This implementation is agnostic to the way tokens are created. This means
+ * that a supply mechanism has to be added in a derived contract using {_mint}.
+ *
+ * TIP: For a detailed writeup see our guide
+ * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
+ * to implement supply mechanisms].
+ *
+ * The default value of {decimals} is 18. To change this, you should override
+ * this function so it returns a different value.
+ *
+ * We have followed general OpenZeppelin Contracts guidelines: functions revert
+ * instead returning `false` on failure. This behavior is nonetheless
+ * conventional and does not conflict with the expectations of ERC20
+ * applications.
+ *
+ * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
+ * This allows applications to reconstruct the allowance for all accounts just
+ * by listening to said events. Other implementations of the EIP may not emit
+ * these events, as it isn't required by the specification.
+ */
+abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
+ mapping(address account => uint256) private _balances;
+
+ mapping(address account => mapping(address spender => uint256)) private _allowances;
+
+ uint256 private _totalSupply;
+
+ string private _name;
+ string private _symbol;
+
+ /**
+ * @dev Sets the values for {name} and {symbol}.
+ *
+ * All two of these values are immutable: they can only be set once during
+ * construction.
+ */
+ constructor(string memory name_, string memory symbol_) {
+ _name = name_;
+ _symbol = symbol_;
+ }
+
+ /**
+ * @dev Returns the name of the token.
+ */
+ function name() public view virtual returns (string memory) {
+ return _name;
+ }
+
+ /**
+ * @dev Returns the symbol of the token, usually a shorter version of the
+ * name.
+ */
+ function symbol() public view virtual returns (string memory) {
+ return _symbol;
+ }
+
+ /**
+ * @dev Returns the number of decimals used to get its user representation.
+ * For example, if `decimals` equals `2`, a balance of `505` tokens should
+ * be displayed to a user as `5.05` (`505 / 10 ** 2`).
+ *
+ * Tokens usually opt for a value of 18, imitating the relationship between
+ * Ether and Wei. This is the default value returned by this function, unless
+ * it's overridden.
+ *
+ * NOTE: This information is only used for _display_ purposes: it in
+ * no way affects any of the arithmetic of the contract, including
+ * {IERC20-balanceOf} and {IERC20-transfer}.
+ */
+ function decimals() public view virtual returns (uint8) {
+ return 18;
+ }
+
+ /**
+ * @dev See {IERC20-totalSupply}.
+ */
+ function totalSupply() public view virtual returns (uint256) {
+ return _totalSupply;
+ }
+
+ /**
+ * @dev See {IERC20-balanceOf}.
+ */
+ function balanceOf(address account) public view virtual returns (uint256) {
+ return _balances[account];
+ }
+
+ /**
+ * @dev See {IERC20-transfer}.
+ *
+ * Requirements:
+ *
+ * - `to` cannot be the zero address.
+ * - the caller must have a balance of at least `value`.
+ */
+ function transfer(address to, uint256 value) public virtual returns (bool) {
+ address owner = _msgSender();
+ _transfer(owner, to, value);
+ return true;
+ }
+
+ /**
+ * @dev See {IERC20-allowance}.
+ */
+ function allowance(address owner, address spender) public view virtual returns (uint256) {
+ return _allowances[owner][spender];
+ }
+
+ /**
+ * @dev See {IERC20-approve}.
+ *
+ * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
+ * `transferFrom`. This is semantically equivalent to an infinite approval.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ */
+ function approve(address spender, uint256 value) public virtual returns (bool) {
+ address owner = _msgSender();
+ _approve(owner, spender, value);
+ return true;
+ }
+
+ /**
+ * @dev See {IERC20-transferFrom}.
+ *
+ * Emits an {Approval} event indicating the updated allowance. This is not
+ * required by the EIP. See the note at the beginning of {ERC20}.
+ *
+ * NOTE: Does not update the allowance if the current allowance
+ * is the maximum `uint256`.
+ *
+ * Requirements:
+ *
+ * - `from` and `to` cannot be the zero address.
+ * - `from` must have a balance of at least `value`.
+ * - the caller must have allowance for ``from``'s tokens of at least
+ * `value`.
+ */
+ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
+ address spender = _msgSender();
+ _spendAllowance(from, spender, value);
+ _transfer(from, to, value);
+ return true;
+ }
+
+ /**
+ * @dev Moves a `value` amount of tokens from `from` to `to`.
+ *
+ * This internal function is equivalent to {transfer}, and can be used to
+ * e.g. implement automatic token fees, slashing mechanisms, etc.
+ *
+ * Emits a {Transfer} event.
+ *
+ * NOTE: This function is not virtual, {_update} should be overridden instead.
+ */
+ function _transfer(address from, address to, uint256 value) internal {
+ if (from == address(0)) {
+ revert ERC20InvalidSender(address(0));
+ }
+ if (to == address(0)) {
+ revert ERC20InvalidReceiver(address(0));
+ }
+ _update(from, to, value);
+ }
+
+ /**
+ * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
+ * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
+ * this function.
+ *
+ * Emits a {Transfer} event.
+ */
+ function _update(address from, address to, uint256 value) internal virtual {
+ if (from == address(0)) {
+ // Overflow check required: The rest of the code assumes that totalSupply never overflows
+ _totalSupply += value;
+ } else {
+ uint256 fromBalance = _balances[from];
+ if (fromBalance < value) {
+ revert ERC20InsufficientBalance(from, fromBalance, value);
+ }
+ unchecked {
+ // Overflow not possible: value <= fromBalance <= totalSupply.
+ _balances[from] = fromBalance - value;
+ }
+ }
+
+ if (to == address(0)) {
+ unchecked {
+ // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
+ _totalSupply -= value;
+ }
+ } else {
+ unchecked {
+ // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
+ _balances[to] += value;
+ }
+ }
+
+ emit Transfer(from, to, value);
+ }
+
+ /**
+ * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
+ * Relies on the `_update` mechanism
+ *
+ * Emits a {Transfer} event with `from` set to the zero address.
+ *
+ * NOTE: This function is not virtual, {_update} should be overridden instead.
+ */
+ function _mint(address account, uint256 value) internal {
+ if (account == address(0)) {
+ revert ERC20InvalidReceiver(address(0));
+ }
+ _update(address(0), account, value);
+ }
+
+ /**
+ * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
+ * Relies on the `_update` mechanism.
+ *
+ * Emits a {Transfer} event with `to` set to the zero address.
+ *
+ * NOTE: This function is not virtual, {_update} should be overridden instead
+ */
+ function _burn(address account, uint256 value) internal {
+ if (account == address(0)) {
+ revert ERC20InvalidSender(address(0));
+ }
+ _update(account, address(0), value);
+ }
+
+ /**
+ * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
+ *
+ * This internal function is equivalent to `approve`, and can be used to
+ * e.g. set automatic allowances for certain subsystems, etc.
+ *
+ * Emits an {Approval} event.
+ *
+ * Requirements:
+ *
+ * - `owner` cannot be the zero address.
+ * - `spender` cannot be the zero address.
+ *
+ * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
+ */
+ function _approve(address owner, address spender, uint256 value) internal {
+ _approve(owner, spender, value, true);
+ }
+
+ /**
+ * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
+ *
+ * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
+ * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
+ * `Approval` event during `transferFrom` operations.
+ *
+ * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
+ * true using the following override:
+ * ```
+ * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
+ * super._approve(owner, spender, value, true);
+ * }
+ * ```
+ *
+ * Requirements are the same as {_approve}.
+ */
+ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
+ if (owner == address(0)) {
+ revert ERC20InvalidApprover(address(0));
+ }
+ if (spender == address(0)) {
+ revert ERC20InvalidSpender(address(0));
+ }
+ _allowances[owner][spender] = value;
+ if (emitEvent) {
+ emit Approval(owner, spender, value);
+ }
+ }
+
+ /**
+ * @dev Updates `owner` s allowance for `spender` based on spent `value`.
+ *
+ * Does not update the allowance value in case of infinite allowance.
+ * Revert if not enough allowance is available.
+ *
+ * Does not emit an {Approval} event.
+ */
+ function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
+ uint256 currentAllowance = allowance(owner, spender);
+ if (currentAllowance != type(uint256).max) {
+ if (currentAllowance < value) {
+ revert ERC20InsufficientAllowance(spender, currentAllowance, value);
+ }
+ unchecked {
+ _approve(owner, spender, currentAllowance - value, false);
+ }
+ }
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/IERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/IERC20.sol
new file mode 100644
index 00000000000..db01cf4c751
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/IERC20.sol
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Interface of the ERC20 standard as defined in the EIP.
+ */
+interface IERC20 {
+ /**
+ * @dev Emitted when `value` tokens are moved from one account (`from`) to
+ * another (`to`).
+ *
+ * Note that `value` may be zero.
+ */
+ event Transfer(address indexed from, address indexed to, uint256 value);
+
+ /**
+ * @dev Emitted when the allowance of a `spender` for an `owner` is set by
+ * a call to {approve}. `value` is the new allowance.
+ */
+ event Approval(address indexed owner, address indexed spender, uint256 value);
+
+ /**
+ * @dev Returns the value of tokens in existence.
+ */
+ function totalSupply() external view returns (uint256);
+
+ /**
+ * @dev Returns the value of tokens owned by `account`.
+ */
+ function balanceOf(address account) external view returns (uint256);
+
+ /**
+ * @dev Moves a `value` amount of tokens from the caller's account to `to`.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transfer(address to, uint256 value) external returns (bool);
+
+ /**
+ * @dev Returns the remaining number of tokens that `spender` will be
+ * allowed to spend on behalf of `owner` through {transferFrom}. This is
+ * zero by default.
+ *
+ * This value changes when {approve} or {transferFrom} are called.
+ */
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ /**
+ * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
+ * caller's tokens.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * IMPORTANT: Beware that changing an allowance with this method brings the risk
+ * that someone may use both the old and the new allowance by unfortunate
+ * transaction ordering. One possible solution to mitigate this race
+ * condition is to first reduce the spender's allowance to 0 and set the
+ * desired value afterwards:
+ * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
+ *
+ * Emits an {Approval} event.
+ */
+ function approve(address spender, uint256 value) external returns (bool);
+
+ /**
+ * @dev Moves a `value` amount of tokens from `from` to `to` using the
+ * allowance mechanism. `value` is then deducted from the caller's
+ * allowance.
+ *
+ * Returns a boolean value indicating whether the operation succeeded.
+ *
+ * Emits a {Transfer} event.
+ */
+ function transferFrom(address from, address to, uint256 value) external returns (bool);
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/ERC20Burnable.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/ERC20Burnable.sol
new file mode 100644
index 00000000000..4d482d8ec83
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/ERC20Burnable.sol
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)
+
+pragma solidity ^0.8.20;
+
+import {ERC20} from "../ERC20.sol";
+import {Context} from "../../../utils/Context.sol";
+
+/**
+ * @dev Extension of {ERC20} that allows token holders to destroy both their own
+ * tokens and those that they have an allowance for, in a way that can be
+ * recognized off-chain (via event analysis).
+ */
+abstract contract ERC20Burnable is Context, ERC20 {
+ /**
+ * @dev Destroys a `value` amount of tokens from the caller.
+ *
+ * See {ERC20-_burn}.
+ */
+ function burn(uint256 value) public virtual {
+ _burn(_msgSender(), value);
+ }
+
+ /**
+ * @dev Destroys a `value` amount of tokens from `account`, deducting from
+ * the caller's allowance.
+ *
+ * See {ERC20-_burn} and {ERC20-allowance}.
+ *
+ * Requirements:
+ *
+ * - the caller must have allowance for ``accounts``'s tokens of at least
+ * `value`.
+ */
+ function burnFrom(address account, uint256 value) public virtual {
+ _spendAllowance(account, _msgSender(), value);
+ _burn(account, value);
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/IERC20Metadata.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/IERC20Metadata.sol
new file mode 100644
index 00000000000..1a38cba3e06
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/IERC20Metadata.sol
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
+
+pragma solidity ^0.8.20;
+
+import {IERC20} from "../IERC20.sol";
+
+/**
+ * @dev Interface for the optional metadata functions from the ERC20 standard.
+ */
+interface IERC20Metadata is IERC20 {
+ /**
+ * @dev Returns the name of the token.
+ */
+ function name() external view returns (string memory);
+
+ /**
+ * @dev Returns the symbol of the token.
+ */
+ function symbol() external view returns (string memory);
+
+ /**
+ * @dev Returns the decimals places of the token.
+ */
+ function decimals() external view returns (uint8);
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/IERC20Permit.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/IERC20Permit.sol
new file mode 100644
index 00000000000..5af48101ab8
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/extensions/IERC20Permit.sol
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+ * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+ *
+ * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+ * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
+ * need to send a transaction, and thus is not required to hold Ether at all.
+ *
+ * ==== Security Considerations
+ *
+ * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
+ * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
+ * considered as an intention to spend the allowance in any specific way. The second is that because permits have
+ * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
+ * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
+ * generally recommended is:
+ *
+ * ```solidity
+ * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
+ * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
+ * doThing(..., value);
+ * }
+ *
+ * function doThing(..., uint256 value) public {
+ * token.safeTransferFrom(msg.sender, address(this), value);
+ * ...
+ * }
+ * ```
+ *
+ * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
+ * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
+ * {SafeERC20-safeTransferFrom}).
+ *
+ * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
+ * contracts should have entry points that don't rely on permit.
+ */
+interface IERC20Permit {
+ /**
+ * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
+ * given ``owner``'s signed approval.
+ *
+ * IMPORTANT: The same issues {IERC20-approve} has related to transaction
+ * ordering also apply here.
+ *
+ * Emits an {Approval} event.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ * - `deadline` must be a timestamp in the future.
+ * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
+ * over the EIP712-formatted function arguments.
+ * - the signature must use ``owner``'s current nonce (see {nonces}).
+ *
+ * For more information on the signature format, see the
+ * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
+ * section].
+ *
+ * CAUTION: See Security Considerations above.
+ */
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) external;
+
+ /**
+ * @dev Returns the current nonce for `owner`. This value must be
+ * included whenever a signature is generated for {permit}.
+ *
+ * Every successful call to {permit} increases ``owner``'s nonce by one. This
+ * prevents a signature from being used multiple times.
+ */
+ function nonces(address owner) external view returns (uint256);
+
+ /**
+ * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function DOMAIN_SEPARATOR() external view returns (bytes32);
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/utils/SafeERC20.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/utils/SafeERC20.sol
new file mode 100644
index 00000000000..bb65709b46b
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/utils/SafeERC20.sol
@@ -0,0 +1,118 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
+
+pragma solidity ^0.8.20;
+
+import {IERC20} from "../IERC20.sol";
+import {IERC20Permit} from "../extensions/IERC20Permit.sol";
+import {Address} from "../../../utils/Address.sol";
+
+/**
+ * @title SafeERC20
+ * @dev Wrappers around ERC20 operations that throw on failure (when the token
+ * contract returns false). Tokens that return no value (and instead revert or
+ * throw on failure) are also supported, non-reverting calls are assumed to be
+ * successful.
+ * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
+ * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
+ */
+library SafeERC20 {
+ using Address for address;
+
+ /**
+ * @dev An operation with an ERC20 token failed.
+ */
+ error SafeERC20FailedOperation(address token);
+
+ /**
+ * @dev Indicates a failed `decreaseAllowance` request.
+ */
+ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
+
+ /**
+ * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
+ * non-reverting calls are assumed to be successful.
+ */
+ function safeTransfer(IERC20 token, address to, uint256 value) internal {
+ _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
+ }
+
+ /**
+ * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
+ * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
+ */
+ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
+ _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
+ }
+
+ /**
+ * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
+ * non-reverting calls are assumed to be successful.
+ */
+ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
+ uint256 oldAllowance = token.allowance(address(this), spender);
+ forceApprove(token, spender, oldAllowance + value);
+ }
+
+ /**
+ * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
+ * value, non-reverting calls are assumed to be successful.
+ */
+ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
+ unchecked {
+ uint256 currentAllowance = token.allowance(address(this), spender);
+ if (currentAllowance < requestedDecrease) {
+ revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
+ }
+ forceApprove(token, spender, currentAllowance - requestedDecrease);
+ }
+ }
+
+ /**
+ * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
+ * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
+ * to be set to zero before setting it to a non-zero value, such as USDT.
+ */
+ function forceApprove(IERC20 token, address spender, uint256 value) internal {
+ bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
+
+ if (!_callOptionalReturnBool(token, approvalCall)) {
+ _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
+ _callOptionalReturn(token, approvalCall);
+ }
+ }
+
+ /**
+ * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
+ * on the return value: the return value is optional (but if data is returned, it must not be false).
+ * @param token The token targeted by the call.
+ * @param data The call data (encoded using abi.encode or one of its variants).
+ */
+ function _callOptionalReturn(IERC20 token, bytes memory data) private {
+ // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
+ // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
+ // the target address contains contract code and also asserts for success in the low-level call.
+
+ bytes memory returndata = address(token).functionCall(data);
+ if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
+ revert SafeERC20FailedOperation(address(token));
+ }
+ }
+
+ /**
+ * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
+ * on the return value: the return value is optional (but if data is returned, it must not be false).
+ * @param token The token targeted by the call.
+ * @param data The call data (encoded using abi.encode or one of its variants).
+ *
+ * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
+ */
+ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
+ // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
+ // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
+ // and not revert is the subcall reverts.
+
+ (bool success, bytes memory returndata) = address(token).call(data);
+ return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Address.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Address.sol
new file mode 100644
index 00000000000..b7e3059529a
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Address.sol
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Collection of functions related to the address type
+ */
+library Address {
+ /**
+ * @dev The ETH balance of the account is not enough to perform the operation.
+ */
+ error AddressInsufficientBalance(address account);
+
+ /**
+ * @dev There's no code at `target` (it is not a contract).
+ */
+ error AddressEmptyCode(address target);
+
+ /**
+ * @dev A call to an address target failed. The target may have reverted.
+ */
+ error FailedInnerCall();
+
+ /**
+ * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
+ */
+ function sendValue(address payable recipient, uint256 amount) internal {
+ if (address(this).balance < amount) {
+ revert AddressInsufficientBalance(address(this));
+ }
+
+ (bool success, ) = recipient.call{value: amount}("");
+ if (!success) {
+ revert FailedInnerCall();
+ }
+ }
+
+ /**
+ * @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 or custom error, it is bubbled
+ * up by this function (like regular Solidity function calls). However, if
+ * the call reverted with no returned reason, this function reverts with a
+ * {FailedInnerCall} error.
+ *
+ * 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.
+ */
+ function functionCall(address target, bytes memory data) internal returns (bytes memory) {
+ return functionCallWithValue(target, data, 0);
+ }
+
+ /**
+ * @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`.
+ */
+ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
+ if (address(this).balance < value) {
+ revert AddressInsufficientBalance(address(this));
+ }
+ (bool success, bytes memory returndata) = target.call{value: value}(data);
+ return verifyCallResultFromTarget(target, success, returndata);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a static call.
+ */
+ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.staticcall(data);
+ return verifyCallResultFromTarget(target, success, returndata);
+ }
+
+ /**
+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
+ * but performing a delegate call.
+ */
+ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
+ (bool success, bytes memory returndata) = target.delegatecall(data);
+ return verifyCallResultFromTarget(target, success, returndata);
+ }
+
+ /**
+ * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
+ * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
+ * unsuccessful call.
+ */
+ function verifyCallResultFromTarget(
+ address target,
+ bool success,
+ bytes memory returndata
+ ) internal view returns (bytes memory) {
+ if (!success) {
+ _revert(returndata);
+ } else {
+ // only check if target is a contract if the call was successful and the return data is empty
+ // otherwise we already know that it was a contract
+ if (returndata.length == 0 && target.code.length == 0) {
+ revert AddressEmptyCode(target);
+ }
+ return returndata;
+ }
+ }
+
+ /**
+ * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
+ * revert reason or with a default {FailedInnerCall} error.
+ */
+ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
+ if (!success) {
+ _revert(returndata);
+ } else {
+ return returndata;
+ }
+ }
+
+ /**
+ * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
+ */
+ function _revert(bytes memory returndata) private pure {
+ // 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
+ /// @solidity memory-safe-assembly
+ assembly {
+ let returndata_size := mload(returndata)
+ revert(add(32, returndata), returndata_size)
+ }
+ } else {
+ revert FailedInnerCall();
+ }
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Context.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Context.sol
new file mode 100644
index 00000000000..4e535fe03c2
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Context.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @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 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) {
+ return msg.sender;
+ }
+
+ function _msgData() internal view virtual returns (bytes calldata) {
+ return msg.data;
+ }
+
+ function _contextSuffixLength() internal view virtual returns (uint256) {
+ return 0;
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Pausable.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Pausable.sol
new file mode 100644
index 00000000000..312f1cb90fe
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Pausable.sol
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
+
+pragma solidity ^0.8.20;
+
+import {Context} from "../utils/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 {
+ bool private _paused;
+
+ /**
+ * @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);
+
+ /**
+ * @dev The operation failed because the contract is paused.
+ */
+ error EnforcedPause();
+
+ /**
+ * @dev The operation failed because the contract is not paused.
+ */
+ error ExpectedPause();
+
+ /**
+ * @dev Initializes the contract in unpaused state.
+ */
+ constructor() {
+ _paused = false;
+ }
+
+ /**
+ * @dev Modifier to make a function callable only when the contract is not paused.
+ *
+ * Requirements:
+ *
+ * - The contract must not be paused.
+ */
+ modifier whenNotPaused() {
+ _requireNotPaused();
+ _;
+ }
+
+ /**
+ * @dev Modifier to make a function callable only when the contract is paused.
+ *
+ * Requirements:
+ *
+ * - The contract must be paused.
+ */
+ modifier whenPaused() {
+ _requirePaused();
+ _;
+ }
+
+ /**
+ * @dev Returns true if the contract is paused, and false otherwise.
+ */
+ function paused() public view virtual returns (bool) {
+ return _paused;
+ }
+
+ /**
+ * @dev Throws if the contract is paused.
+ */
+ function _requireNotPaused() internal view virtual {
+ if (paused()) {
+ revert EnforcedPause();
+ }
+ }
+
+ /**
+ * @dev Throws if the contract is not paused.
+ */
+ function _requirePaused() internal view virtual {
+ if (!paused()) {
+ revert ExpectedPause();
+ }
+ }
+
+ /**
+ * @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.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/ShortStrings.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/ShortStrings.sol
new file mode 100644
index 00000000000..fdfe774d635
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/ShortStrings.sol
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
+
+pragma solidity ^0.8.20;
+
+import {StorageSlot} from "./StorageSlot.sol";
+
+// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
+// | length | 0x BB |
+type ShortString is bytes32;
+
+/**
+ * @dev This library provides functions to convert short memory strings
+ * into a `ShortString` type that can be used as an immutable variable.
+ *
+ * Strings of arbitrary length can be optimized using this library if
+ * they are short enough (up to 31 bytes) by packing them with their
+ * length (1 byte) in a single EVM word (32 bytes). Additionally, a
+ * fallback mechanism can be used for every other case.
+ *
+ * Usage example:
+ *
+ * ```solidity
+ * contract Named {
+ * using ShortStrings for *;
+ *
+ * ShortString private immutable _name;
+ * string private _nameFallback;
+ *
+ * constructor(string memory contractName) {
+ * _name = contractName.toShortStringWithFallback(_nameFallback);
+ * }
+ *
+ * function name() external view returns (string memory) {
+ * return _name.toStringWithFallback(_nameFallback);
+ * }
+ * }
+ * ```
+ */
+library ShortStrings {
+ // Used as an identifier for strings longer than 31 bytes.
+ bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
+
+ error StringTooLong(string str);
+ error InvalidShortString();
+
+ /**
+ * @dev Encode a string of at most 31 chars into a `ShortString`.
+ *
+ * This will trigger a `StringTooLong` error is the input string is too long.
+ */
+ function toShortString(string memory str) internal pure returns (ShortString) {
+ bytes memory bstr = bytes(str);
+ if (bstr.length > 31) {
+ revert StringTooLong(str);
+ }
+ return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
+ }
+
+ /**
+ * @dev Decode a `ShortString` back to a "normal" string.
+ */
+ function toString(ShortString sstr) internal pure returns (string memory) {
+ uint256 len = byteLength(sstr);
+ // using `new string(len)` would work locally but is not memory safe.
+ string memory str = new string(32);
+ /// @solidity memory-safe-assembly
+ assembly {
+ mstore(str, len)
+ mstore(add(str, 0x20), sstr)
+ }
+ return str;
+ }
+
+ /**
+ * @dev Return the length of a `ShortString`.
+ */
+ function byteLength(ShortString sstr) internal pure returns (uint256) {
+ uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
+ if (result > 31) {
+ revert InvalidShortString();
+ }
+ return result;
+ }
+
+ /**
+ * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
+ */
+ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
+ if (bytes(value).length < 32) {
+ return toShortString(value);
+ } else {
+ StorageSlot.getStringSlot(store).value = value;
+ return ShortString.wrap(FALLBACK_SENTINEL);
+ }
+ }
+
+ /**
+ * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
+ */
+ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
+ if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
+ return toString(value);
+ } else {
+ return store;
+ }
+ }
+
+ /**
+ * @dev Return the length of a string that was encoded to `ShortString` or written to storage using
+ * {setWithFallback}.
+ *
+ * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
+ * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
+ */
+ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
+ if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
+ return byteLength(value);
+ } else {
+ return bytes(store).length;
+ }
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/StorageSlot.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/StorageSlot.sol
new file mode 100644
index 00000000000..08418327a59
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/StorageSlot.sol
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
+// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Library for reading and writing primitive types to specific storage slots.
+ *
+ * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
+ * This library helps with reading and writing to such slots without the need for inline assembly.
+ *
+ * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
+ *
+ * Example usage to set ERC1967 implementation slot:
+ * ```solidity
+ * contract ERC1967 {
+ * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
+ *
+ * function _getImplementation() internal view returns (address) {
+ * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
+ * }
+ *
+ * function _setImplementation(address newImplementation) internal {
+ * require(newImplementation.code.length > 0);
+ * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
+ * }
+ * }
+ * ```
+ */
+library StorageSlot {
+ struct AddressSlot {
+ address value;
+ }
+
+ struct BooleanSlot {
+ bool value;
+ }
+
+ struct Bytes32Slot {
+ bytes32 value;
+ }
+
+ struct Uint256Slot {
+ uint256 value;
+ }
+
+ struct StringSlot {
+ string value;
+ }
+
+ struct BytesSlot {
+ bytes value;
+ }
+
+ /**
+ * @dev Returns an `AddressSlot` with member `value` located at `slot`.
+ */
+ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
+ */
+ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
+ */
+ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
+ */
+ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `StringSlot` with member `value` located at `slot`.
+ */
+ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
+ */
+ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := store.slot
+ }
+ }
+
+ /**
+ * @dev Returns an `BytesSlot` with member `value` located at `slot`.
+ */
+ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := slot
+ }
+ }
+
+ /**
+ * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
+ */
+ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ r.slot := store.slot
+ }
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Strings.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Strings.sol
new file mode 100644
index 00000000000..b2c0a40fb2a
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/Strings.sol
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
+
+pragma solidity ^0.8.20;
+
+import {Math} from "./math/Math.sol";
+import {SignedMath} from "./math/SignedMath.sol";
+
+/**
+ * @dev String operations.
+ */
+library Strings {
+ bytes16 private constant HEX_DIGITS = "0123456789abcdef";
+ uint8 private constant ADDRESS_LENGTH = 20;
+
+ /**
+ * @dev The `value` string doesn't fit in the specified `length`.
+ */
+ error StringsInsufficientHexLength(uint256 value, uint256 length);
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` decimal representation.
+ */
+ function toString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ uint256 length = Math.log10(value) + 1;
+ string memory buffer = new string(length);
+ uint256 ptr;
+ /// @solidity memory-safe-assembly
+ assembly {
+ ptr := add(buffer, add(32, length))
+ }
+ while (true) {
+ ptr--;
+ /// @solidity memory-safe-assembly
+ assembly {
+ mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
+ }
+ value /= 10;
+ if (value == 0) break;
+ }
+ return buffer;
+ }
+ }
+
+ /**
+ * @dev Converts a `int256` to its ASCII `string` decimal representation.
+ */
+ function toStringSigned(int256 value) internal pure returns (string memory) {
+ return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
+ */
+ function toHexString(uint256 value) internal pure returns (string memory) {
+ unchecked {
+ return toHexString(value, Math.log256(value) + 1);
+ }
+ }
+
+ /**
+ * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
+ */
+ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
+ uint256 localValue = value;
+ bytes memory buffer = new bytes(2 * length + 2);
+ buffer[0] = "0";
+ buffer[1] = "x";
+ for (uint256 i = 2 * length + 1; i > 1; --i) {
+ buffer[i] = HEX_DIGITS[localValue & 0xf];
+ localValue >>= 4;
+ }
+ if (localValue != 0) {
+ revert StringsInsufficientHexLength(value, length);
+ }
+ return string(buffer);
+ }
+
+ /**
+ * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
+ * representation.
+ */
+ function toHexString(address addr) internal pure returns (string memory) {
+ return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
+ }
+
+ /**
+ * @dev Returns true if the two strings are equal.
+ */
+ function equal(string memory a, string memory b) internal pure returns (bool) {
+ return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/ECDSA.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/ECDSA.sol
new file mode 100644
index 00000000000..04b3e5e0646
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/ECDSA.sol
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
+ *
+ * These functions can be used to verify that a message was signed by the holder
+ * of the private keys of a given address.
+ */
+library ECDSA {
+ enum RecoverError {
+ NoError,
+ InvalidSignature,
+ InvalidSignatureLength,
+ InvalidSignatureS
+ }
+
+ /**
+ * @dev The signature derives the `address(0)`.
+ */
+ error ECDSAInvalidSignature();
+
+ /**
+ * @dev The signature has an invalid length.
+ */
+ error ECDSAInvalidSignatureLength(uint256 length);
+
+ /**
+ * @dev The signature has an S value that is in the upper half order.
+ */
+ error ECDSAInvalidSignatureS(bytes32 s);
+
+ /**
+ * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
+ * return address(0) without also returning an error description. Errors are documented using an enum (error type)
+ * and a bytes32 providing additional information about the error.
+ *
+ * If no error is returned, then the address can be used for verification purposes.
+ *
+ * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
+ * this function rejects them by requiring the `s` value to be in the lower
+ * half order, and the `v` value to be either 27 or 28.
+ *
+ * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+ * verification to be secure: it is possible to craft signatures that
+ * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+ * this is by receiving a hash of the original message (which may otherwise
+ * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
+ *
+ * Documentation for signature generation:
+ * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
+ * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
+ */
+ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
+ if (signature.length == 65) {
+ bytes32 r;
+ bytes32 s;
+ uint8 v;
+ // ecrecover takes the signature parameters, and the only way to get them
+ // currently is to use assembly.
+ /// @solidity memory-safe-assembly
+ assembly {
+ r := mload(add(signature, 0x20))
+ s := mload(add(signature, 0x40))
+ v := byte(0, mload(add(signature, 0x60)))
+ }
+ return tryRecover(hash, v, r, s);
+ } else {
+ return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
+ }
+ }
+
+ /**
+ * @dev Returns the address that signed a hashed message (`hash`) with
+ * `signature`. This address can then be used for verification purposes.
+ *
+ * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
+ * this function rejects them by requiring the `s` value to be in the lower
+ * half order, and the `v` value to be either 27 or 28.
+ *
+ * IMPORTANT: `hash` _must_ be the result of a hash operation for the
+ * verification to be secure: it is possible to craft signatures that
+ * recover to arbitrary addresses for non-hashed data. A safe way to ensure
+ * this is by receiving a hash of the original message (which may otherwise
+ * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
+ */
+ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
+ (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
+ _throwError(error, errorArg);
+ return recovered;
+ }
+
+ /**
+ * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
+ *
+ * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
+ */
+ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
+ unchecked {
+ bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
+ // We do not check for an overflow here since the shift operation results in 0 or 1.
+ uint8 v = uint8((uint256(vs) >> 255) + 27);
+ return tryRecover(hash, v, r, s);
+ }
+ }
+
+ /**
+ * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
+ */
+ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
+ (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
+ _throwError(error, errorArg);
+ return recovered;
+ }
+
+ /**
+ * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
+ * `r` and `s` signature fields separately.
+ */
+ function tryRecover(
+ bytes32 hash,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ ) internal pure returns (address, RecoverError, bytes32) {
+ // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
+ // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
+ // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
+ // signatures from current libraries generate a unique signature with an s-value in the lower half order.
+ //
+ // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
+ // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
+ // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
+ // these malleable signatures as well.
+ if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
+ return (address(0), RecoverError.InvalidSignatureS, s);
+ }
+
+ // If the signature is valid (and not malleable), return the signer address
+ address signer = ecrecover(hash, v, r, s);
+ if (signer == address(0)) {
+ return (address(0), RecoverError.InvalidSignature, bytes32(0));
+ }
+
+ return (signer, RecoverError.NoError, bytes32(0));
+ }
+
+ /**
+ * @dev Overload of {ECDSA-recover} that receives the `v`,
+ * `r` and `s` signature fields separately.
+ */
+ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
+ (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
+ _throwError(error, errorArg);
+ return recovered;
+ }
+
+ /**
+ * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
+ */
+ function _throwError(RecoverError error, bytes32 errorArg) private pure {
+ if (error == RecoverError.NoError) {
+ return; // no error: do nothing
+ } else if (error == RecoverError.InvalidSignature) {
+ revert ECDSAInvalidSignature();
+ } else if (error == RecoverError.InvalidSignatureLength) {
+ revert ECDSAInvalidSignatureLength(uint256(errorArg));
+ } else if (error == RecoverError.InvalidSignatureS) {
+ revert ECDSAInvalidSignatureS(errorArg);
+ }
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/EIP712.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/EIP712.sol
new file mode 100644
index 00000000000..8e548cdd8f0
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/EIP712.sol
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
+
+pragma solidity ^0.8.20;
+
+import {MessageHashUtils} from "./MessageHashUtils.sol";
+import {ShortStrings, ShortString} from "../ShortStrings.sol";
+import {IERC5267} from "../../interfaces/IERC5267.sol";
+
+/**
+ * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
+ *
+ * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
+ * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
+ * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
+ * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
+ *
+ * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
+ * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
+ * ({_hashTypedDataV4}).
+ *
+ * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
+ * the chain id to protect against replay attacks on an eventual fork of the chain.
+ *
+ * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
+ * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
+ *
+ * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
+ * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
+ * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
+ *
+ * @custom:oz-upgrades-unsafe-allow state-variable-immutable
+ */
+abstract contract EIP712 is IERC5267 {
+ using ShortStrings for *;
+
+ bytes32 private constant TYPE_HASH =
+ keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
+
+ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
+ // invalidate the cached domain separator if the chain id changes.
+ bytes32 private immutable _cachedDomainSeparator;
+ uint256 private immutable _cachedChainId;
+ address private immutable _cachedThis;
+
+ bytes32 private immutable _hashedName;
+ bytes32 private immutable _hashedVersion;
+
+ ShortString private immutable _name;
+ ShortString private immutable _version;
+ string private _nameFallback;
+ string private _versionFallback;
+
+ /**
+ * @dev Initializes the domain separator and parameter caches.
+ *
+ * The meaning of `name` and `version` is specified in
+ * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
+ *
+ * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
+ * - `version`: the current major version of the signing domain.
+ *
+ * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
+ * contract upgrade].
+ */
+ constructor(string memory name, string memory version) {
+ _name = name.toShortStringWithFallback(_nameFallback);
+ _version = version.toShortStringWithFallback(_versionFallback);
+ _hashedName = keccak256(bytes(name));
+ _hashedVersion = keccak256(bytes(version));
+
+ _cachedChainId = block.chainid;
+ _cachedDomainSeparator = _buildDomainSeparator();
+ _cachedThis = address(this);
+ }
+
+ /**
+ * @dev Returns the domain separator for the current chain.
+ */
+ function _domainSeparatorV4() internal view returns (bytes32) {
+ if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
+ return _cachedDomainSeparator;
+ } else {
+ return _buildDomainSeparator();
+ }
+ }
+
+ function _buildDomainSeparator() private view returns (bytes32) {
+ return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
+ }
+
+ /**
+ * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
+ * function returns the hash of the fully encoded EIP712 message for this domain.
+ *
+ * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
+ *
+ * ```solidity
+ * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
+ * keccak256("Mail(address to,string contents)"),
+ * mailTo,
+ * keccak256(bytes(mailContents))
+ * )));
+ * address signer = ECDSA.recover(digest, signature);
+ * ```
+ */
+ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
+ return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
+ }
+
+ /**
+ * @dev See {IERC-5267}.
+ */
+ function eip712Domain()
+ public
+ view
+ virtual
+ returns (
+ bytes1 fields,
+ string memory name,
+ string memory version,
+ uint256 chainId,
+ address verifyingContract,
+ bytes32 salt,
+ uint256[] memory extensions
+ )
+ {
+ return (
+ hex"0f", // 01111
+ _EIP712Name(),
+ _EIP712Version(),
+ block.chainid,
+ address(this),
+ bytes32(0),
+ new uint256[](0)
+ );
+ }
+
+ /**
+ * @dev The name parameter for the EIP712 domain.
+ *
+ * NOTE: By default this function reads _name which is an immutable value.
+ * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function _EIP712Name() internal view returns (string memory) {
+ return _name.toStringWithFallback(_nameFallback);
+ }
+
+ /**
+ * @dev The version parameter for the EIP712 domain.
+ *
+ * NOTE: By default this function reads _version which is an immutable value.
+ * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
+ */
+ // solhint-disable-next-line func-name-mixedcase
+ function _EIP712Version() internal view returns (string memory) {
+ return _version.toStringWithFallback(_versionFallback);
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/MessageHashUtils.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/MessageHashUtils.sol
new file mode 100644
index 00000000000..8836693e79b
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/cryptography/MessageHashUtils.sol
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
+
+pragma solidity ^0.8.20;
+
+import {Strings} from "../Strings.sol";
+
+/**
+ * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
+ *
+ * The library provides methods for generating a hash of a message that conforms to the
+ * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
+ * specifications.
+ */
+library MessageHashUtils {
+ /**
+ * @dev Returns the keccak256 digest of an EIP-191 signed data with version
+ * `0x45` (`personal_sign` messages).
+ *
+ * The digest is calculated by prefixing a bytes32 `messageHash` with
+ * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
+ * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
+ *
+ * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
+ * keccak256, although any bytes32 value can be safely used because the final digest will
+ * be re-hashed.
+ *
+ * See {ECDSA-recover}.
+ */
+ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
+ mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
+ digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
+ }
+ }
+
+ /**
+ * @dev Returns the keccak256 digest of an EIP-191 signed data with version
+ * `0x45` (`personal_sign` messages).
+ *
+ * The digest is calculated by prefixing an arbitrary `message` with
+ * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
+ * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
+ *
+ * See {ECDSA-recover}.
+ */
+ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
+ return
+ keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
+ }
+
+ /**
+ * @dev Returns the keccak256 digest of an EIP-191 signed data with version
+ * `0x00` (data with intended validator).
+ *
+ * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
+ * `validator` address. Then hashing the result.
+ *
+ * See {ECDSA-recover}.
+ */
+ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
+ return keccak256(abi.encodePacked(hex"19_00", validator, data));
+ }
+
+ /**
+ * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
+ *
+ * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
+ * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
+ * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
+ *
+ * See {ECDSA-recover}.
+ */
+ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
+ /// @solidity memory-safe-assembly
+ assembly {
+ let ptr := mload(0x40)
+ mstore(ptr, hex"19_01")
+ mstore(add(ptr, 0x02), domainSeparator)
+ mstore(add(ptr, 0x22), structHash)
+ digest := keccak256(ptr, 0x42)
+ }
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/ERC165.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/ERC165.sol
new file mode 100644
index 00000000000..1e77b60d739
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/ERC165.sol
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
+
+pragma solidity ^0.8.20;
+
+import {IERC165} from "./IERC165.sol";
+
+/**
+ * @dev Implementation of the {IERC165} interface.
+ *
+ * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
+ * for the additional interface id that will be supported. For example:
+ *
+ * ```solidity
+ * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+ * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
+ * }
+ * ```
+ */
+abstract contract ERC165 is IERC165 {
+ /**
+ * @dev See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
+ return interfaceId == type(IERC165).interfaceId;
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/ERC165Checker.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/ERC165Checker.sol
new file mode 100644
index 00000000000..7b52241446d
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/ERC165Checker.sol
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)
+
+pragma solidity ^0.8.20;
+
+import {IERC165} from "./IERC165.sol";
+
+/**
+ * @dev Library used to query support of an interface declared via {IERC165}.
+ *
+ * Note that these functions return the actual result of the query: they do not
+ * `revert` if an interface is not supported. It is up to the caller to decide
+ * what to do in these cases.
+ */
+library ERC165Checker {
+ // As per the EIP-165 spec, no interface should ever match 0xffffffff
+ bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
+
+ /**
+ * @dev Returns true if `account` supports the {IERC165} interface.
+ */
+ function supportsERC165(address account) internal view returns (bool) {
+ // Any contract that implements ERC165 must explicitly indicate support of
+ // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
+ return
+ supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
+ !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
+ }
+
+ /**
+ * @dev Returns true if `account` supports the interface defined by
+ * `interfaceId`. Support for {IERC165} itself is queried automatically.
+ *
+ * See {IERC165-supportsInterface}.
+ */
+ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
+ // query support of both ERC165 as per the spec and support of _interfaceId
+ return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
+ }
+
+ /**
+ * @dev Returns a boolean array where each value corresponds to the
+ * interfaces passed in and whether they're supported or not. This allows
+ * you to batch check interfaces for a contract where your expectation
+ * is that some interfaces may not be supported.
+ *
+ * See {IERC165-supportsInterface}.
+ */
+ function getSupportedInterfaces(
+ address account,
+ bytes4[] memory interfaceIds
+ ) internal view returns (bool[] memory) {
+ // an array of booleans corresponding to interfaceIds and whether they're supported or not
+ bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
+
+ // query support of ERC165 itself
+ if (supportsERC165(account)) {
+ // query support of each interface in interfaceIds
+ for (uint256 i = 0; i < interfaceIds.length; i++) {
+ interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
+ }
+ }
+
+ return interfaceIdsSupported;
+ }
+
+ /**
+ * @dev Returns true if `account` supports all the interfaces defined in
+ * `interfaceIds`. Support for {IERC165} itself is queried automatically.
+ *
+ * Batch-querying can lead to gas savings by skipping repeated checks for
+ * {IERC165} support.
+ *
+ * See {IERC165-supportsInterface}.
+ */
+ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
+ // query support of ERC165 itself
+ if (!supportsERC165(account)) {
+ return false;
+ }
+
+ // query support of each interface in interfaceIds
+ for (uint256 i = 0; i < interfaceIds.length; i++) {
+ if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
+ return false;
+ }
+ }
+
+ // all interfaces supported
+ return true;
+ }
+
+ /**
+ * @notice Query if a contract implements an interface, does not check ERC165 support
+ * @param account The address of the contract to query for support of an interface
+ * @param interfaceId The interface identifier, as specified in ERC-165
+ * @return true if the contract at account indicates support of the interface with
+ * identifier interfaceId, false otherwise
+ * @dev Assumes that account contains a contract that supports ERC165, otherwise
+ * the behavior of this method is undefined. This precondition can be checked
+ * with {supportsERC165}.
+ *
+ * Some precompiled contracts will falsely indicate support for a given interface, so caution
+ * should be exercised when using this function.
+ *
+ * Interface identification is specified in ERC-165.
+ */
+ function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
+ // prepare call
+ bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
+
+ // perform static call
+ bool success;
+ uint256 returnSize;
+ uint256 returnValue;
+ assembly {
+ success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
+ returnSize := returndatasize()
+ returnValue := mload(0x00)
+ }
+
+ return success && returnSize >= 0x20 && returnValue > 0;
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol
new file mode 100644
index 00000000000..c09f31fe128
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Interface of the ERC165 standard, as defined in the
+ * https://eips.ethereum.org/EIPS/eip-165[EIP].
+ *
+ * Implementers can declare support of contract interfaces, which can then be
+ * queried by others ({ERC165Checker}).
+ *
+ * For an implementation, see {ERC165}.
+ */
+interface IERC165 {
+ /**
+ * @dev Returns true if this contract implements the interface defined by
+ * `interfaceId`. See the corresponding
+ * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
+ * to learn more about how these ids are created.
+ *
+ * This function call must use less than 30 000 gas.
+ */
+ function supportsInterface(bytes4 interfaceId) external view returns (bool);
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/Math.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/Math.sol
new file mode 100644
index 00000000000..9681524529b
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/Math.sol
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Standard math utilities missing in the Solidity language.
+ */
+library Math {
+ /**
+ * @dev Muldiv operation overflow.
+ */
+ error MathOverflowedMulDiv();
+
+ enum Rounding {
+ Floor, // Toward negative infinity
+ Ceil, // Toward positive infinity
+ Trunc, // Toward zero
+ Expand // Away from zero
+ }
+
+ /**
+ * @dev Returns the addition of two unsigned integers, with an overflow flag.
+ */
+ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+ unchecked {
+ uint256 c = a + b;
+ if (c < a) return (false, 0);
+ return (true, c);
+ }
+ }
+
+ /**
+ * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
+ */
+ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+ unchecked {
+ if (b > a) return (false, 0);
+ return (true, a - b);
+ }
+ }
+
+ /**
+ * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
+ */
+ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+ unchecked {
+ // 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 (true, 0);
+ uint256 c = a * b;
+ if (c / a != b) return (false, 0);
+ return (true, c);
+ }
+ }
+
+ /**
+ * @dev Returns the division of two unsigned integers, with a division by zero flag.
+ */
+ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+ unchecked {
+ if (b == 0) return (false, 0);
+ return (true, a / b);
+ }
+ }
+
+ /**
+ * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
+ */
+ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+ unchecked {
+ if (b == 0) return (false, 0);
+ return (true, a % b);
+ }
+ }
+
+ /**
+ * @dev Returns the largest of two numbers.
+ */
+ function max(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a > b ? a : b;
+ }
+
+ /**
+ * @dev Returns the smallest of two numbers.
+ */
+ function min(uint256 a, uint256 b) internal pure returns (uint256) {
+ return a < b ? a : b;
+ }
+
+ /**
+ * @dev Returns the average of two numbers. The result is rounded towards
+ * zero.
+ */
+ function average(uint256 a, uint256 b) internal pure returns (uint256) {
+ // (a + b) / 2 can overflow.
+ return (a & b) + (a ^ b) / 2;
+ }
+
+ /**
+ * @dev Returns the ceiling of the division of two numbers.
+ *
+ * This differs from standard division with `/` in that it rounds towards infinity instead
+ * of rounding towards zero.
+ */
+ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
+ if (b == 0) {
+ // Guarantee the same behavior as in a regular Solidity division.
+ return a / b;
+ }
+
+ // (a + b - 1) / b can overflow on addition, so we distribute.
+ return a == 0 ? 0 : (a - 1) / b + 1;
+ }
+
+ /**
+ * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
+ * denominator == 0.
+ * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
+ * Uniswap Labs also under MIT license.
+ */
+ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
+ unchecked {
+ // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
+ // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
+ // variables such that product = prod1 * 2^256 + prod0.
+ uint256 prod0 = x * y; // Least significant 256 bits of the product
+ uint256 prod1; // Most significant 256 bits of the product
+ assembly {
+ let mm := mulmod(x, y, not(0))
+ prod1 := sub(sub(mm, prod0), lt(mm, prod0))
+ }
+
+ // Handle non-overflow cases, 256 by 256 division.
+ if (prod1 == 0) {
+ // Solidity will revert if denominator == 0, unlike the div opcode on its own.
+ // The surrounding unchecked block does not change this fact.
+ // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
+ return prod0 / denominator;
+ }
+
+ // Make sure the result is less than 2^256. Also prevents denominator == 0.
+ if (denominator <= prod1) {
+ revert MathOverflowedMulDiv();
+ }
+
+ ///////////////////////////////////////////////
+ // 512 by 256 division.
+ ///////////////////////////////////////////////
+
+ // Make division exact by subtracting the remainder from [prod1 prod0].
+ uint256 remainder;
+ assembly {
+ // Compute remainder using mulmod.
+ remainder := mulmod(x, y, denominator)
+
+ // Subtract 256 bit number from 512 bit number.
+ prod1 := sub(prod1, gt(remainder, prod0))
+ prod0 := sub(prod0, remainder)
+ }
+
+ // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
+ // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
+
+ uint256 twos = denominator & (0 - denominator);
+ assembly {
+ // Divide denominator by twos.
+ denominator := div(denominator, twos)
+
+ // Divide [prod1 prod0] by twos.
+ prod0 := div(prod0, twos)
+
+ // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
+ twos := add(div(sub(0, twos), twos), 1)
+ }
+
+ // Shift in bits from prod1 into prod0.
+ prod0 |= prod1 * twos;
+
+ // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
+ // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
+ // four bits. That is, denominator * inv = 1 mod 2^4.
+ uint256 inverse = (3 * denominator) ^ 2;
+
+ // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
+ // works in modular arithmetic, doubling the correct bits in each step.
+ inverse *= 2 - denominator * inverse; // inverse mod 2^8
+ inverse *= 2 - denominator * inverse; // inverse mod 2^16
+ inverse *= 2 - denominator * inverse; // inverse mod 2^32
+ inverse *= 2 - denominator * inverse; // inverse mod 2^64
+ inverse *= 2 - denominator * inverse; // inverse mod 2^128
+ inverse *= 2 - denominator * inverse; // inverse mod 2^256
+
+ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
+ // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
+ // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
+ // is no longer required.
+ result = prod0 * inverse;
+ return result;
+ }
+ }
+
+ /**
+ * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
+ */
+ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
+ uint256 result = mulDiv(x, y, denominator);
+ if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
+ result += 1;
+ }
+ return result;
+ }
+
+ /**
+ * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
+ * towards zero.
+ *
+ * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
+ */
+ function sqrt(uint256 a) internal pure returns (uint256) {
+ if (a == 0) {
+ return 0;
+ }
+
+ // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
+ //
+ // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
+ // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
+ //
+ // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
+ // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
+ // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
+ //
+ // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
+ uint256 result = 1 << (log2(a) >> 1);
+
+ // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
+ // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
+ // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
+ // into the expected uint128 result.
+ unchecked {
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ result = (result + a / result) >> 1;
+ return min(result, a / result);
+ }
+ }
+
+ /**
+ * @notice Calculates sqrt(a), following the selected rounding direction.
+ */
+ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = sqrt(a);
+ return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 2 of a positive value rounded towards zero.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 128;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 64;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 32;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 16;
+ }
+ if (value >> 8 > 0) {
+ value >>= 8;
+ result += 8;
+ }
+ if (value >> 4 > 0) {
+ value >>= 4;
+ result += 4;
+ }
+ if (value >> 2 > 0) {
+ value >>= 2;
+ result += 2;
+ }
+ if (value >> 1 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log2(value);
+ return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 10 of a positive value rounded towards zero.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >= 10 ** 64) {
+ value /= 10 ** 64;
+ result += 64;
+ }
+ if (value >= 10 ** 32) {
+ value /= 10 ** 32;
+ result += 32;
+ }
+ if (value >= 10 ** 16) {
+ value /= 10 ** 16;
+ result += 16;
+ }
+ if (value >= 10 ** 8) {
+ value /= 10 ** 8;
+ result += 8;
+ }
+ if (value >= 10 ** 4) {
+ value /= 10 ** 4;
+ result += 4;
+ }
+ if (value >= 10 ** 2) {
+ value /= 10 ** 2;
+ result += 2;
+ }
+ if (value >= 10 ** 1) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log10(value);
+ return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Return the log in base 256 of a positive value rounded towards zero.
+ * Returns 0 if given 0.
+ *
+ * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
+ */
+ function log256(uint256 value) internal pure returns (uint256) {
+ uint256 result = 0;
+ unchecked {
+ if (value >> 128 > 0) {
+ value >>= 128;
+ result += 16;
+ }
+ if (value >> 64 > 0) {
+ value >>= 64;
+ result += 8;
+ }
+ if (value >> 32 > 0) {
+ value >>= 32;
+ result += 4;
+ }
+ if (value >> 16 > 0) {
+ value >>= 16;
+ result += 2;
+ }
+ if (value >> 8 > 0) {
+ result += 1;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
+ * Returns 0 if given 0.
+ */
+ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
+ unchecked {
+ uint256 result = log256(value);
+ return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
+ }
+ }
+
+ /**
+ * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
+ */
+ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
+ return uint8(rounding) % 2 == 1;
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/SafeCast.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/SafeCast.sol
new file mode 100644
index 00000000000..0ed458b43c2
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/SafeCast.sol
@@ -0,0 +1,1153 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
+// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
+ * checks.
+ *
+ * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
+ * easily result in undesired exploitation or bugs, since developers usually
+ * assume that overflows raise errors. `SafeCast` restores this intuition by
+ * reverting the transaction when such 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 SafeCast {
+ /**
+ * @dev Value doesn't fit in an uint of `bits` size.
+ */
+ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
+
+ /**
+ * @dev An int value doesn't fit in an uint of `bits` size.
+ */
+ error SafeCastOverflowedIntToUint(int256 value);
+
+ /**
+ * @dev Value doesn't fit in an int of `bits` size.
+ */
+ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
+
+ /**
+ * @dev An uint value doesn't fit in an int of `bits` size.
+ */
+ error SafeCastOverflowedUintToInt(uint256 value);
+
+ /**
+ * @dev Returns the downcasted uint248 from uint256, reverting on
+ * overflow (when the input is greater than largest uint248).
+ *
+ * Counterpart to Solidity's `uint248` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 248 bits
+ */
+ function toUint248(uint256 value) internal pure returns (uint248) {
+ if (value > type(uint248).max) {
+ revert SafeCastOverflowedUintDowncast(248, value);
+ }
+ return uint248(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint240 from uint256, reverting on
+ * overflow (when the input is greater than largest uint240).
+ *
+ * Counterpart to Solidity's `uint240` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 240 bits
+ */
+ function toUint240(uint256 value) internal pure returns (uint240) {
+ if (value > type(uint240).max) {
+ revert SafeCastOverflowedUintDowncast(240, value);
+ }
+ return uint240(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint232 from uint256, reverting on
+ * overflow (when the input is greater than largest uint232).
+ *
+ * Counterpart to Solidity's `uint232` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 232 bits
+ */
+ function toUint232(uint256 value) internal pure returns (uint232) {
+ if (value > type(uint232).max) {
+ revert SafeCastOverflowedUintDowncast(232, value);
+ }
+ return uint232(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint224 from uint256, reverting on
+ * overflow (when the input is greater than largest uint224).
+ *
+ * Counterpart to Solidity's `uint224` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 224 bits
+ */
+ function toUint224(uint256 value) internal pure returns (uint224) {
+ if (value > type(uint224).max) {
+ revert SafeCastOverflowedUintDowncast(224, value);
+ }
+ return uint224(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint216 from uint256, reverting on
+ * overflow (when the input is greater than largest uint216).
+ *
+ * Counterpart to Solidity's `uint216` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 216 bits
+ */
+ function toUint216(uint256 value) internal pure returns (uint216) {
+ if (value > type(uint216).max) {
+ revert SafeCastOverflowedUintDowncast(216, value);
+ }
+ return uint216(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint208 from uint256, reverting on
+ * overflow (when the input is greater than largest uint208).
+ *
+ * Counterpart to Solidity's `uint208` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 208 bits
+ */
+ function toUint208(uint256 value) internal pure returns (uint208) {
+ if (value > type(uint208).max) {
+ revert SafeCastOverflowedUintDowncast(208, value);
+ }
+ return uint208(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint200 from uint256, reverting on
+ * overflow (when the input is greater than largest uint200).
+ *
+ * Counterpart to Solidity's `uint200` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 200 bits
+ */
+ function toUint200(uint256 value) internal pure returns (uint200) {
+ if (value > type(uint200).max) {
+ revert SafeCastOverflowedUintDowncast(200, value);
+ }
+ return uint200(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint192 from uint256, reverting on
+ * overflow (when the input is greater than largest uint192).
+ *
+ * Counterpart to Solidity's `uint192` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 192 bits
+ */
+ function toUint192(uint256 value) internal pure returns (uint192) {
+ if (value > type(uint192).max) {
+ revert SafeCastOverflowedUintDowncast(192, value);
+ }
+ return uint192(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint184 from uint256, reverting on
+ * overflow (when the input is greater than largest uint184).
+ *
+ * Counterpart to Solidity's `uint184` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 184 bits
+ */
+ function toUint184(uint256 value) internal pure returns (uint184) {
+ if (value > type(uint184).max) {
+ revert SafeCastOverflowedUintDowncast(184, value);
+ }
+ return uint184(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint176 from uint256, reverting on
+ * overflow (when the input is greater than largest uint176).
+ *
+ * Counterpart to Solidity's `uint176` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 176 bits
+ */
+ function toUint176(uint256 value) internal pure returns (uint176) {
+ if (value > type(uint176).max) {
+ revert SafeCastOverflowedUintDowncast(176, value);
+ }
+ return uint176(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint168 from uint256, reverting on
+ * overflow (when the input is greater than largest uint168).
+ *
+ * Counterpart to Solidity's `uint168` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 168 bits
+ */
+ function toUint168(uint256 value) internal pure returns (uint168) {
+ if (value > type(uint168).max) {
+ revert SafeCastOverflowedUintDowncast(168, value);
+ }
+ return uint168(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint160 from uint256, reverting on
+ * overflow (when the input is greater than largest uint160).
+ *
+ * Counterpart to Solidity's `uint160` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 160 bits
+ */
+ function toUint160(uint256 value) internal pure returns (uint160) {
+ if (value > type(uint160).max) {
+ revert SafeCastOverflowedUintDowncast(160, value);
+ }
+ return uint160(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint152 from uint256, reverting on
+ * overflow (when the input is greater than largest uint152).
+ *
+ * Counterpart to Solidity's `uint152` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 152 bits
+ */
+ function toUint152(uint256 value) internal pure returns (uint152) {
+ if (value > type(uint152).max) {
+ revert SafeCastOverflowedUintDowncast(152, value);
+ }
+ return uint152(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint144 from uint256, reverting on
+ * overflow (when the input is greater than largest uint144).
+ *
+ * Counterpart to Solidity's `uint144` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 144 bits
+ */
+ function toUint144(uint256 value) internal pure returns (uint144) {
+ if (value > type(uint144).max) {
+ revert SafeCastOverflowedUintDowncast(144, value);
+ }
+ return uint144(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint136 from uint256, reverting on
+ * overflow (when the input is greater than largest uint136).
+ *
+ * Counterpart to Solidity's `uint136` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 136 bits
+ */
+ function toUint136(uint256 value) internal pure returns (uint136) {
+ if (value > type(uint136).max) {
+ revert SafeCastOverflowedUintDowncast(136, value);
+ }
+ return uint136(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint128 from uint256, reverting on
+ * overflow (when the input is greater than largest uint128).
+ *
+ * Counterpart to Solidity's `uint128` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 128 bits
+ */
+ function toUint128(uint256 value) internal pure returns (uint128) {
+ if (value > type(uint128).max) {
+ revert SafeCastOverflowedUintDowncast(128, value);
+ }
+ return uint128(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint120 from uint256, reverting on
+ * overflow (when the input is greater than largest uint120).
+ *
+ * Counterpart to Solidity's `uint120` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 120 bits
+ */
+ function toUint120(uint256 value) internal pure returns (uint120) {
+ if (value > type(uint120).max) {
+ revert SafeCastOverflowedUintDowncast(120, value);
+ }
+ return uint120(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint112 from uint256, reverting on
+ * overflow (when the input is greater than largest uint112).
+ *
+ * Counterpart to Solidity's `uint112` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 112 bits
+ */
+ function toUint112(uint256 value) internal pure returns (uint112) {
+ if (value > type(uint112).max) {
+ revert SafeCastOverflowedUintDowncast(112, value);
+ }
+ return uint112(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint104 from uint256, reverting on
+ * overflow (when the input is greater than largest uint104).
+ *
+ * Counterpart to Solidity's `uint104` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 104 bits
+ */
+ function toUint104(uint256 value) internal pure returns (uint104) {
+ if (value > type(uint104).max) {
+ revert SafeCastOverflowedUintDowncast(104, value);
+ }
+ return uint104(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint96 from uint256, reverting on
+ * overflow (when the input is greater than largest uint96).
+ *
+ * Counterpart to Solidity's `uint96` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 96 bits
+ */
+ function toUint96(uint256 value) internal pure returns (uint96) {
+ if (value > type(uint96).max) {
+ revert SafeCastOverflowedUintDowncast(96, value);
+ }
+ return uint96(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint88 from uint256, reverting on
+ * overflow (when the input is greater than largest uint88).
+ *
+ * Counterpart to Solidity's `uint88` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 88 bits
+ */
+ function toUint88(uint256 value) internal pure returns (uint88) {
+ if (value > type(uint88).max) {
+ revert SafeCastOverflowedUintDowncast(88, value);
+ }
+ return uint88(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint80 from uint256, reverting on
+ * overflow (when the input is greater than largest uint80).
+ *
+ * Counterpart to Solidity's `uint80` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 80 bits
+ */
+ function toUint80(uint256 value) internal pure returns (uint80) {
+ if (value > type(uint80).max) {
+ revert SafeCastOverflowedUintDowncast(80, value);
+ }
+ return uint80(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint72 from uint256, reverting on
+ * overflow (when the input is greater than largest uint72).
+ *
+ * Counterpart to Solidity's `uint72` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 72 bits
+ */
+ function toUint72(uint256 value) internal pure returns (uint72) {
+ if (value > type(uint72).max) {
+ revert SafeCastOverflowedUintDowncast(72, value);
+ }
+ return uint72(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint64 from uint256, reverting on
+ * overflow (when the input is greater than largest uint64).
+ *
+ * Counterpart to Solidity's `uint64` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 64 bits
+ */
+ function toUint64(uint256 value) internal pure returns (uint64) {
+ if (value > type(uint64).max) {
+ revert SafeCastOverflowedUintDowncast(64, value);
+ }
+ return uint64(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint56 from uint256, reverting on
+ * overflow (when the input is greater than largest uint56).
+ *
+ * Counterpart to Solidity's `uint56` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 56 bits
+ */
+ function toUint56(uint256 value) internal pure returns (uint56) {
+ if (value > type(uint56).max) {
+ revert SafeCastOverflowedUintDowncast(56, value);
+ }
+ return uint56(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint48 from uint256, reverting on
+ * overflow (when the input is greater than largest uint48).
+ *
+ * Counterpart to Solidity's `uint48` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 48 bits
+ */
+ function toUint48(uint256 value) internal pure returns (uint48) {
+ if (value > type(uint48).max) {
+ revert SafeCastOverflowedUintDowncast(48, value);
+ }
+ return uint48(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint40 from uint256, reverting on
+ * overflow (when the input is greater than largest uint40).
+ *
+ * Counterpart to Solidity's `uint40` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 40 bits
+ */
+ function toUint40(uint256 value) internal pure returns (uint40) {
+ if (value > type(uint40).max) {
+ revert SafeCastOverflowedUintDowncast(40, value);
+ }
+ return uint40(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint32 from uint256, reverting on
+ * overflow (when the input is greater than largest uint32).
+ *
+ * Counterpart to Solidity's `uint32` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 32 bits
+ */
+ function toUint32(uint256 value) internal pure returns (uint32) {
+ if (value > type(uint32).max) {
+ revert SafeCastOverflowedUintDowncast(32, value);
+ }
+ return uint32(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint24 from uint256, reverting on
+ * overflow (when the input is greater than largest uint24).
+ *
+ * Counterpart to Solidity's `uint24` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 24 bits
+ */
+ function toUint24(uint256 value) internal pure returns (uint24) {
+ if (value > type(uint24).max) {
+ revert SafeCastOverflowedUintDowncast(24, value);
+ }
+ return uint24(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint16 from uint256, reverting on
+ * overflow (when the input is greater than largest uint16).
+ *
+ * Counterpart to Solidity's `uint16` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 16 bits
+ */
+ function toUint16(uint256 value) internal pure returns (uint16) {
+ if (value > type(uint16).max) {
+ revert SafeCastOverflowedUintDowncast(16, value);
+ }
+ return uint16(value);
+ }
+
+ /**
+ * @dev Returns the downcasted uint8 from uint256, reverting on
+ * overflow (when the input is greater than largest uint8).
+ *
+ * Counterpart to Solidity's `uint8` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 8 bits
+ */
+ function toUint8(uint256 value) internal pure returns (uint8) {
+ if (value > type(uint8).max) {
+ revert SafeCastOverflowedUintDowncast(8, value);
+ }
+ return uint8(value);
+ }
+
+ /**
+ * @dev Converts a signed int256 into an unsigned uint256.
+ *
+ * Requirements:
+ *
+ * - input must be greater than or equal to 0.
+ */
+ function toUint256(int256 value) internal pure returns (uint256) {
+ if (value < 0) {
+ revert SafeCastOverflowedIntToUint(value);
+ }
+ return uint256(value);
+ }
+
+ /**
+ * @dev Returns the downcasted int248 from int256, reverting on
+ * overflow (when the input is less than smallest int248 or
+ * greater than largest int248).
+ *
+ * Counterpart to Solidity's `int248` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 248 bits
+ */
+ function toInt248(int256 value) internal pure returns (int248 downcasted) {
+ downcasted = int248(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(248, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int240 from int256, reverting on
+ * overflow (when the input is less than smallest int240 or
+ * greater than largest int240).
+ *
+ * Counterpart to Solidity's `int240` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 240 bits
+ */
+ function toInt240(int256 value) internal pure returns (int240 downcasted) {
+ downcasted = int240(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(240, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int232 from int256, reverting on
+ * overflow (when the input is less than smallest int232 or
+ * greater than largest int232).
+ *
+ * Counterpart to Solidity's `int232` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 232 bits
+ */
+ function toInt232(int256 value) internal pure returns (int232 downcasted) {
+ downcasted = int232(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(232, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int224 from int256, reverting on
+ * overflow (when the input is less than smallest int224 or
+ * greater than largest int224).
+ *
+ * Counterpart to Solidity's `int224` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 224 bits
+ */
+ function toInt224(int256 value) internal pure returns (int224 downcasted) {
+ downcasted = int224(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(224, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int216 from int256, reverting on
+ * overflow (when the input is less than smallest int216 or
+ * greater than largest int216).
+ *
+ * Counterpart to Solidity's `int216` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 216 bits
+ */
+ function toInt216(int256 value) internal pure returns (int216 downcasted) {
+ downcasted = int216(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(216, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int208 from int256, reverting on
+ * overflow (when the input is less than smallest int208 or
+ * greater than largest int208).
+ *
+ * Counterpart to Solidity's `int208` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 208 bits
+ */
+ function toInt208(int256 value) internal pure returns (int208 downcasted) {
+ downcasted = int208(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(208, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int200 from int256, reverting on
+ * overflow (when the input is less than smallest int200 or
+ * greater than largest int200).
+ *
+ * Counterpart to Solidity's `int200` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 200 bits
+ */
+ function toInt200(int256 value) internal pure returns (int200 downcasted) {
+ downcasted = int200(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(200, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int192 from int256, reverting on
+ * overflow (when the input is less than smallest int192 or
+ * greater than largest int192).
+ *
+ * Counterpart to Solidity's `int192` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 192 bits
+ */
+ function toInt192(int256 value) internal pure returns (int192 downcasted) {
+ downcasted = int192(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(192, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int184 from int256, reverting on
+ * overflow (when the input is less than smallest int184 or
+ * greater than largest int184).
+ *
+ * Counterpart to Solidity's `int184` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 184 bits
+ */
+ function toInt184(int256 value) internal pure returns (int184 downcasted) {
+ downcasted = int184(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(184, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int176 from int256, reverting on
+ * overflow (when the input is less than smallest int176 or
+ * greater than largest int176).
+ *
+ * Counterpart to Solidity's `int176` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 176 bits
+ */
+ function toInt176(int256 value) internal pure returns (int176 downcasted) {
+ downcasted = int176(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(176, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int168 from int256, reverting on
+ * overflow (when the input is less than smallest int168 or
+ * greater than largest int168).
+ *
+ * Counterpart to Solidity's `int168` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 168 bits
+ */
+ function toInt168(int256 value) internal pure returns (int168 downcasted) {
+ downcasted = int168(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(168, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int160 from int256, reverting on
+ * overflow (when the input is less than smallest int160 or
+ * greater than largest int160).
+ *
+ * Counterpart to Solidity's `int160` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 160 bits
+ */
+ function toInt160(int256 value) internal pure returns (int160 downcasted) {
+ downcasted = int160(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(160, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int152 from int256, reverting on
+ * overflow (when the input is less than smallest int152 or
+ * greater than largest int152).
+ *
+ * Counterpart to Solidity's `int152` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 152 bits
+ */
+ function toInt152(int256 value) internal pure returns (int152 downcasted) {
+ downcasted = int152(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(152, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int144 from int256, reverting on
+ * overflow (when the input is less than smallest int144 or
+ * greater than largest int144).
+ *
+ * Counterpart to Solidity's `int144` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 144 bits
+ */
+ function toInt144(int256 value) internal pure returns (int144 downcasted) {
+ downcasted = int144(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(144, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int136 from int256, reverting on
+ * overflow (when the input is less than smallest int136 or
+ * greater than largest int136).
+ *
+ * Counterpart to Solidity's `int136` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 136 bits
+ */
+ function toInt136(int256 value) internal pure returns (int136 downcasted) {
+ downcasted = int136(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(136, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int128 from int256, reverting on
+ * overflow (when the input is less than smallest int128 or
+ * greater than largest int128).
+ *
+ * Counterpart to Solidity's `int128` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 128 bits
+ */
+ function toInt128(int256 value) internal pure returns (int128 downcasted) {
+ downcasted = int128(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(128, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int120 from int256, reverting on
+ * overflow (when the input is less than smallest int120 or
+ * greater than largest int120).
+ *
+ * Counterpart to Solidity's `int120` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 120 bits
+ */
+ function toInt120(int256 value) internal pure returns (int120 downcasted) {
+ downcasted = int120(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(120, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int112 from int256, reverting on
+ * overflow (when the input is less than smallest int112 or
+ * greater than largest int112).
+ *
+ * Counterpart to Solidity's `int112` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 112 bits
+ */
+ function toInt112(int256 value) internal pure returns (int112 downcasted) {
+ downcasted = int112(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(112, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int104 from int256, reverting on
+ * overflow (when the input is less than smallest int104 or
+ * greater than largest int104).
+ *
+ * Counterpart to Solidity's `int104` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 104 bits
+ */
+ function toInt104(int256 value) internal pure returns (int104 downcasted) {
+ downcasted = int104(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(104, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int96 from int256, reverting on
+ * overflow (when the input is less than smallest int96 or
+ * greater than largest int96).
+ *
+ * Counterpart to Solidity's `int96` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 96 bits
+ */
+ function toInt96(int256 value) internal pure returns (int96 downcasted) {
+ downcasted = int96(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(96, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int88 from int256, reverting on
+ * overflow (when the input is less than smallest int88 or
+ * greater than largest int88).
+ *
+ * Counterpart to Solidity's `int88` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 88 bits
+ */
+ function toInt88(int256 value) internal pure returns (int88 downcasted) {
+ downcasted = int88(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(88, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int80 from int256, reverting on
+ * overflow (when the input is less than smallest int80 or
+ * greater than largest int80).
+ *
+ * Counterpart to Solidity's `int80` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 80 bits
+ */
+ function toInt80(int256 value) internal pure returns (int80 downcasted) {
+ downcasted = int80(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(80, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int72 from int256, reverting on
+ * overflow (when the input is less than smallest int72 or
+ * greater than largest int72).
+ *
+ * Counterpart to Solidity's `int72` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 72 bits
+ */
+ function toInt72(int256 value) internal pure returns (int72 downcasted) {
+ downcasted = int72(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(72, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int64 from int256, reverting on
+ * overflow (when the input is less than smallest int64 or
+ * greater than largest int64).
+ *
+ * Counterpart to Solidity's `int64` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 64 bits
+ */
+ function toInt64(int256 value) internal pure returns (int64 downcasted) {
+ downcasted = int64(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(64, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int56 from int256, reverting on
+ * overflow (when the input is less than smallest int56 or
+ * greater than largest int56).
+ *
+ * Counterpart to Solidity's `int56` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 56 bits
+ */
+ function toInt56(int256 value) internal pure returns (int56 downcasted) {
+ downcasted = int56(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(56, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int48 from int256, reverting on
+ * overflow (when the input is less than smallest int48 or
+ * greater than largest int48).
+ *
+ * Counterpart to Solidity's `int48` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 48 bits
+ */
+ function toInt48(int256 value) internal pure returns (int48 downcasted) {
+ downcasted = int48(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(48, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int40 from int256, reverting on
+ * overflow (when the input is less than smallest int40 or
+ * greater than largest int40).
+ *
+ * Counterpart to Solidity's `int40` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 40 bits
+ */
+ function toInt40(int256 value) internal pure returns (int40 downcasted) {
+ downcasted = int40(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(40, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int32 from int256, reverting on
+ * overflow (when the input is less than smallest int32 or
+ * greater than largest int32).
+ *
+ * Counterpart to Solidity's `int32` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 32 bits
+ */
+ function toInt32(int256 value) internal pure returns (int32 downcasted) {
+ downcasted = int32(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(32, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int24 from int256, reverting on
+ * overflow (when the input is less than smallest int24 or
+ * greater than largest int24).
+ *
+ * Counterpart to Solidity's `int24` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 24 bits
+ */
+ function toInt24(int256 value) internal pure returns (int24 downcasted) {
+ downcasted = int24(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(24, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int16 from int256, reverting on
+ * overflow (when the input is less than smallest int16 or
+ * greater than largest int16).
+ *
+ * Counterpart to Solidity's `int16` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 16 bits
+ */
+ function toInt16(int256 value) internal pure returns (int16 downcasted) {
+ downcasted = int16(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(16, value);
+ }
+ }
+
+ /**
+ * @dev Returns the downcasted int8 from int256, reverting on
+ * overflow (when the input is less than smallest int8 or
+ * greater than largest int8).
+ *
+ * Counterpart to Solidity's `int8` operator.
+ *
+ * Requirements:
+ *
+ * - input must fit into 8 bits
+ */
+ function toInt8(int256 value) internal pure returns (int8 downcasted) {
+ downcasted = int8(value);
+ if (downcasted != value) {
+ revert SafeCastOverflowedIntDowncast(8, value);
+ }
+ }
+
+ /**
+ * @dev Converts an unsigned uint256 into a signed int256.
+ *
+ * Requirements:
+ *
+ * - input must be less than or equal to maxInt256.
+ */
+ function toInt256(uint256 value) internal pure returns (int256) {
+ // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
+ if (value > uint256(type(int256).max)) {
+ revert SafeCastOverflowedUintToInt(value);
+ }
+ return int256(value);
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/SignedMath.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/SignedMath.sol
new file mode 100644
index 00000000000..66a61516292
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/math/SignedMath.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Standard signed math utilities missing in the Solidity language.
+ */
+library SignedMath {
+ /**
+ * @dev Returns the largest of two signed numbers.
+ */
+ function max(int256 a, int256 b) internal pure returns (int256) {
+ return a > b ? a : b;
+ }
+
+ /**
+ * @dev Returns the smallest of two signed numbers.
+ */
+ function min(int256 a, int256 b) internal pure returns (int256) {
+ return a < b ? a : b;
+ }
+
+ /**
+ * @dev Returns the average of two signed numbers without overflow.
+ * The result is rounded towards zero.
+ */
+ function average(int256 a, int256 b) internal pure returns (int256) {
+ // Formula from the book "Hacker's Delight"
+ int256 x = (a & b) + ((a ^ b) >> 1);
+ return x + (int256(uint256(x) >> 255) & (a ^ b));
+ }
+
+ /**
+ * @dev Returns the absolute unsigned value of a signed value.
+ */
+ function abs(int256 n) internal pure returns (uint256) {
+ unchecked {
+ // must be unchecked in order to support `n = type(int256).min`
+ return uint256(n >= 0 ? n : -n);
+ }
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableMap.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableMap.sol
new file mode 100644
index 00000000000..929ae7c536e
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableMap.sol
@@ -0,0 +1,533 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol)
+// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
+
+pragma solidity ^0.8.20;
+
+import {EnumerableSet} from "./EnumerableSet.sol";
+
+/**
+ * @dev Library for managing an enumerable variant of Solidity's
+ * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
+ * type.
+ *
+ * Maps have the following properties:
+ *
+ * - Entries are added, removed, and checked for existence in constant time
+ * (O(1)).
+ * - Entries are enumerated in O(n). No guarantees are made on the ordering.
+ *
+ * ```solidity
+ * contract Example {
+ * // Add the library methods
+ * using EnumerableMap for EnumerableMap.UintToAddressMap;
+ *
+ * // Declare a set state variable
+ * EnumerableMap.UintToAddressMap private myMap;
+ * }
+ * ```
+ *
+ * The following map types are supported:
+ *
+ * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
+ * - `address -> uint256` (`AddressToUintMap`) since v4.6.0
+ * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
+ * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
+ * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
+ *
+ * [WARNING]
+ * ====
+ * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
+ * unusable.
+ * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
+ *
+ * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
+ * array of EnumerableMap.
+ * ====
+ */
+library EnumerableMap {
+ using EnumerableSet for EnumerableSet.Bytes32Set;
+
+ // To implement this library for multiple types with as little code repetition as possible, we write it in
+ // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,
+ // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.
+ // This means that we can only create new EnumerableMaps for types that fit in bytes32.
+
+ /**
+ * @dev Query for a nonexistent map key.
+ */
+ error EnumerableMapNonexistentKey(bytes32 key);
+
+ struct Bytes32ToBytes32Map {
+ // Storage of keys
+ EnumerableSet.Bytes32Set _keys;
+ mapping(bytes32 key => bytes32) _values;
+ }
+
+ /**
+ * @dev Adds a key-value pair to a map, or updates the value for an existing
+ * key. O(1).
+ *
+ * Returns true if the key was added to the map, that is if it was not
+ * already present.
+ */
+ function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
+ map._values[key] = value;
+ return map._keys.add(key);
+ }
+
+ /**
+ * @dev Removes a key-value pair from a map. O(1).
+ *
+ * Returns true if the key was removed from the map, that is if it was present.
+ */
+ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
+ delete map._values[key];
+ return map._keys.remove(key);
+ }
+
+ /**
+ * @dev Returns true if the key is in the map. O(1).
+ */
+ function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
+ return map._keys.contains(key);
+ }
+
+ /**
+ * @dev Returns the number of key-value pairs in the map. O(1).
+ */
+ function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
+ return map._keys.length();
+ }
+
+ /**
+ * @dev Returns the key-value pair stored at position `index` in the map. O(1).
+ *
+ * Note that there are no guarantees on the ordering of entries inside the
+ * array, and it may change when more entries are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
+ bytes32 key = map._keys.at(index);
+ return (key, map._values[key]);
+ }
+
+ /**
+ * @dev Tries to returns the value associated with `key`. O(1).
+ * Does not revert if `key` is not in the map.
+ */
+ function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
+ bytes32 value = map._values[key];
+ if (value == bytes32(0)) {
+ return (contains(map, key), bytes32(0));
+ } else {
+ return (true, value);
+ }
+ }
+
+ /**
+ * @dev Returns the value associated with `key`. O(1).
+ *
+ * Requirements:
+ *
+ * - `key` must be in the map.
+ */
+ function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
+ bytes32 value = map._values[key];
+ if (value == 0 && !contains(map, key)) {
+ revert EnumerableMapNonexistentKey(key);
+ }
+ return value;
+ }
+
+ /**
+ * @dev Return the an array containing all the keys
+ *
+ * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
+ */
+ function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
+ return map._keys.values();
+ }
+
+ // UintToUintMap
+
+ struct UintToUintMap {
+ Bytes32ToBytes32Map _inner;
+ }
+
+ /**
+ * @dev Adds a key-value pair to a map, or updates the value for an existing
+ * key. O(1).
+ *
+ * Returns true if the key was added to the map, that is if it was not
+ * already present.
+ */
+ function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
+ return set(map._inner, bytes32(key), bytes32(value));
+ }
+
+ /**
+ * @dev Removes a value from a map. O(1).
+ *
+ * Returns true if the key was removed from the map, that is if it was present.
+ */
+ function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
+ return remove(map._inner, bytes32(key));
+ }
+
+ /**
+ * @dev Returns true if the key is in the map. O(1).
+ */
+ function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
+ return contains(map._inner, bytes32(key));
+ }
+
+ /**
+ * @dev Returns the number of elements in the map. O(1).
+ */
+ function length(UintToUintMap storage map) internal view returns (uint256) {
+ return length(map._inner);
+ }
+
+ /**
+ * @dev Returns the element stored at position `index` in the map. O(1).
+ * Note that there are no guarantees on the ordering of values inside the
+ * array, and it may change when more values are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
+ (bytes32 key, bytes32 value) = at(map._inner, index);
+ return (uint256(key), uint256(value));
+ }
+
+ /**
+ * @dev Tries to returns the value associated with `key`. O(1).
+ * Does not revert if `key` is not in the map.
+ */
+ function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
+ (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
+ return (success, uint256(value));
+ }
+
+ /**
+ * @dev Returns the value associated with `key`. O(1).
+ *
+ * Requirements:
+ *
+ * - `key` must be in the map.
+ */
+ function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
+ return uint256(get(map._inner, bytes32(key)));
+ }
+
+ /**
+ * @dev Return the an array containing all the keys
+ *
+ * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
+ */
+ function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
+ bytes32[] memory store = keys(map._inner);
+ uint256[] memory result;
+
+ /// @solidity memory-safe-assembly
+ assembly {
+ result := store
+ }
+
+ return result;
+ }
+
+ // UintToAddressMap
+
+ struct UintToAddressMap {
+ Bytes32ToBytes32Map _inner;
+ }
+
+ /**
+ * @dev Adds a key-value pair to a map, or updates the value for an existing
+ * key. O(1).
+ *
+ * Returns true if the key was added to the map, that is if it was not
+ * already present.
+ */
+ function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
+ return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
+ }
+
+ /**
+ * @dev Removes a value from a map. O(1).
+ *
+ * Returns true if the key was removed from the map, that is if it was present.
+ */
+ function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
+ return remove(map._inner, bytes32(key));
+ }
+
+ /**
+ * @dev Returns true if the key is in the map. O(1).
+ */
+ function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
+ return contains(map._inner, bytes32(key));
+ }
+
+ /**
+ * @dev Returns the number of elements in the map. O(1).
+ */
+ function length(UintToAddressMap storage map) internal view returns (uint256) {
+ return length(map._inner);
+ }
+
+ /**
+ * @dev Returns the element stored at position `index` in the map. O(1).
+ * Note that there are no guarantees on the ordering of values inside the
+ * array, and it may change when more values are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
+ (bytes32 key, bytes32 value) = at(map._inner, index);
+ return (uint256(key), address(uint160(uint256(value))));
+ }
+
+ /**
+ * @dev Tries to returns the value associated with `key`. O(1).
+ * Does not revert if `key` is not in the map.
+ */
+ function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
+ (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
+ return (success, address(uint160(uint256(value))));
+ }
+
+ /**
+ * @dev Returns the value associated with `key`. O(1).
+ *
+ * Requirements:
+ *
+ * - `key` must be in the map.
+ */
+ function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
+ return address(uint160(uint256(get(map._inner, bytes32(key)))));
+ }
+
+ /**
+ * @dev Return the an array containing all the keys
+ *
+ * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
+ */
+ function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
+ bytes32[] memory store = keys(map._inner);
+ uint256[] memory result;
+
+ /// @solidity memory-safe-assembly
+ assembly {
+ result := store
+ }
+
+ return result;
+ }
+
+ // AddressToUintMap
+
+ struct AddressToUintMap {
+ Bytes32ToBytes32Map _inner;
+ }
+
+ /**
+ * @dev Adds a key-value pair to a map, or updates the value for an existing
+ * key. O(1).
+ *
+ * Returns true if the key was added to the map, that is if it was not
+ * already present.
+ */
+ function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
+ return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
+ }
+
+ /**
+ * @dev Removes a value from a map. O(1).
+ *
+ * Returns true if the key was removed from the map, that is if it was present.
+ */
+ function remove(AddressToUintMap storage map, address key) internal returns (bool) {
+ return remove(map._inner, bytes32(uint256(uint160(key))));
+ }
+
+ /**
+ * @dev Returns true if the key is in the map. O(1).
+ */
+ function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
+ return contains(map._inner, bytes32(uint256(uint160(key))));
+ }
+
+ /**
+ * @dev Returns the number of elements in the map. O(1).
+ */
+ function length(AddressToUintMap storage map) internal view returns (uint256) {
+ return length(map._inner);
+ }
+
+ /**
+ * @dev Returns the element stored at position `index` in the map. O(1).
+ * Note that there are no guarantees on the ordering of values inside the
+ * array, and it may change when more values are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
+ (bytes32 key, bytes32 value) = at(map._inner, index);
+ return (address(uint160(uint256(key))), uint256(value));
+ }
+
+ /**
+ * @dev Tries to returns the value associated with `key`. O(1).
+ * Does not revert if `key` is not in the map.
+ */
+ function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
+ (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
+ return (success, uint256(value));
+ }
+
+ /**
+ * @dev Returns the value associated with `key`. O(1).
+ *
+ * Requirements:
+ *
+ * - `key` must be in the map.
+ */
+ function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
+ return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
+ }
+
+ /**
+ * @dev Return the an array containing all the keys
+ *
+ * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
+ */
+ function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
+ bytes32[] memory store = keys(map._inner);
+ address[] memory result;
+
+ /// @solidity memory-safe-assembly
+ assembly {
+ result := store
+ }
+
+ return result;
+ }
+
+ // Bytes32ToUintMap
+
+ struct Bytes32ToUintMap {
+ Bytes32ToBytes32Map _inner;
+ }
+
+ /**
+ * @dev Adds a key-value pair to a map, or updates the value for an existing
+ * key. O(1).
+ *
+ * Returns true if the key was added to the map, that is if it was not
+ * already present.
+ */
+ function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
+ return set(map._inner, key, bytes32(value));
+ }
+
+ /**
+ * @dev Removes a value from a map. O(1).
+ *
+ * Returns true if the key was removed from the map, that is if it was present.
+ */
+ function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
+ return remove(map._inner, key);
+ }
+
+ /**
+ * @dev Returns true if the key is in the map. O(1).
+ */
+ function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
+ return contains(map._inner, key);
+ }
+
+ /**
+ * @dev Returns the number of elements in the map. O(1).
+ */
+ function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
+ return length(map._inner);
+ }
+
+ /**
+ * @dev Returns the element stored at position `index` in the map. O(1).
+ * Note that there are no guarantees on the ordering of values inside the
+ * array, and it may change when more values are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
+ (bytes32 key, bytes32 value) = at(map._inner, index);
+ return (key, uint256(value));
+ }
+
+ /**
+ * @dev Tries to returns the value associated with `key`. O(1).
+ * Does not revert if `key` is not in the map.
+ */
+ function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
+ (bool success, bytes32 value) = tryGet(map._inner, key);
+ return (success, uint256(value));
+ }
+
+ /**
+ * @dev Returns the value associated with `key`. O(1).
+ *
+ * Requirements:
+ *
+ * - `key` must be in the map.
+ */
+ function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
+ return uint256(get(map._inner, key));
+ }
+
+ /**
+ * @dev Return the an array containing all the keys
+ *
+ * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
+ */
+ function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
+ bytes32[] memory store = keys(map._inner);
+ bytes32[] memory result;
+
+ /// @solidity memory-safe-assembly
+ assembly {
+ result := store
+ }
+
+ return result;
+ }
+}
diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableSet.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableSet.sol
new file mode 100644
index 00000000000..4c7fc5e1d76
--- /dev/null
+++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableSet.sol
@@ -0,0 +1,378 @@
+// SPDX-License-Identifier: MIT
+// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
+// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
+
+pragma solidity ^0.8.20;
+
+/**
+ * @dev Library for managing
+ * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
+ * types.
+ *
+ * Sets have the following properties:
+ *
+ * - Elements are added, removed, and checked for existence in constant time
+ * (O(1)).
+ * - Elements are enumerated in O(n). No guarantees are made on the ordering.
+ *
+ * ```solidity
+ * contract Example {
+ * // Add the library methods
+ * using EnumerableSet for EnumerableSet.AddressSet;
+ *
+ * // Declare a set state variable
+ * EnumerableSet.AddressSet private mySet;
+ * }
+ * ```
+ *
+ * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
+ * and `uint256` (`UintSet`) are supported.
+ *
+ * [WARNING]
+ * ====
+ * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
+ * unusable.
+ * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
+ *
+ * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
+ * array of EnumerableSet.
+ * ====
+ */
+library EnumerableSet {
+ // To implement this library for multiple types with as little code
+ // repetition as possible, we write it in terms of a generic Set type with
+ // bytes32 values.
+ // The Set implementation uses private functions, and user-facing
+ // implementations (such as AddressSet) are just wrappers around the
+ // underlying Set.
+ // This means that we can only create new EnumerableSets for types that fit
+ // in bytes32.
+
+ struct Set {
+ // Storage of set values
+ bytes32[] _values;
+ // Position is the index of the value in the `values` array plus 1.
+ // Position 0 is used to mean a value is not in the set.
+ mapping(bytes32 value => uint256) _positions;
+ }
+
+ /**
+ * @dev Add a value to a set. O(1).
+ *
+ * Returns true if the value was added to the set, that is if it was not
+ * already present.
+ */
+ function _add(Set storage set, bytes32 value) private returns (bool) {
+ if (!_contains(set, value)) {
+ set._values.push(value);
+ // The value is stored at length-1, but we add 1 to all indexes
+ // and use 0 as a sentinel value
+ set._positions[value] = set._values.length;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @dev Removes a value from a set. O(1).
+ *
+ * Returns true if the value was removed from the set, that is if it was
+ * present.
+ */
+ function _remove(Set storage set, bytes32 value) private returns (bool) {
+ // We cache the value's position to prevent multiple reads from the same storage slot
+ uint256 position = set._positions[value];
+
+ if (position != 0) {
+ // Equivalent to contains(set, value)
+ // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
+ // the array, and then remove the last element (sometimes called as 'swap and pop').
+ // This modifies the order of the array, as noted in {at}.
+
+ uint256 valueIndex = position - 1;
+ uint256 lastIndex = set._values.length - 1;
+
+ if (valueIndex != lastIndex) {
+ bytes32 lastValue = set._values[lastIndex];
+
+ // Move the lastValue to the index where the value to delete is
+ set._values[valueIndex] = lastValue;
+ // Update the tracked position of the lastValue (that was just moved)
+ set._positions[lastValue] = position;
+ }
+
+ // Delete the slot where the moved value was stored
+ set._values.pop();
+
+ // Delete the tracked position for the deleted slot
+ delete set._positions[value];
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @dev Returns true if the value is in the set. O(1).
+ */
+ function _contains(Set storage set, bytes32 value) private view returns (bool) {
+ return set._positions[value] != 0;
+ }
+
+ /**
+ * @dev Returns the number of values on the set. O(1).
+ */
+ function _length(Set storage set) private view returns (uint256) {
+ return set._values.length;
+ }
+
+ /**
+ * @dev Returns the value stored at position `index` in the set. O(1).
+ *
+ * Note that there are no guarantees on the ordering of values inside the
+ * array, and it may change when more values are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function _at(Set storage set, uint256 index) private view returns (bytes32) {
+ return set._values[index];
+ }
+
+ /**
+ * @dev Return the entire set in an array
+ *
+ * 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.
+ */
+ function _values(Set storage set) private view returns (bytes32[] memory) {
+ return set._values;
+ }
+
+ // Bytes32Set
+
+ struct Bytes32Set {
+ Set _inner;
+ }
+
+ /**
+ * @dev Add a value to a set. O(1).
+ *
+ * Returns true if the value was added to the set, that is if it was not
+ * already present.
+ */
+ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
+ return _add(set._inner, value);
+ }
+
+ /**
+ * @dev Removes a value from a set. O(1).
+ *
+ * Returns true if the value was removed from the set, that is if it was
+ * present.
+ */
+ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
+ return _remove(set._inner, value);
+ }
+
+ /**
+ * @dev Returns true if the value is in the set. O(1).
+ */
+ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
+ return _contains(set._inner, value);
+ }
+
+ /**
+ * @dev Returns the number of values in the set. O(1).
+ */
+ function length(Bytes32Set storage set) internal view returns (uint256) {
+ return _length(set._inner);
+ }
+
+ /**
+ * @dev Returns the value stored at position `index` in the set. O(1).
+ *
+ * Note that there are no guarantees on the ordering of values inside the
+ * array, and it may change when more values are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
+ return _at(set._inner, index);
+ }
+
+ /**
+ * @dev Return the entire set in an array
+ *
+ * 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.
+ */
+ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
+ bytes32[] memory store = _values(set._inner);
+ bytes32[] memory result;
+
+ /// @solidity memory-safe-assembly
+ assembly {
+ result := store
+ }
+
+ return result;
+ }
+
+ // AddressSet
+
+ struct AddressSet {
+ Set _inner;
+ }
+
+ /**
+ * @dev Add a value to a set. O(1).
+ *
+ * Returns true if the value was added to the set, that is if it was not
+ * already present.
+ */
+ function add(AddressSet storage set, address value) internal returns (bool) {
+ return _add(set._inner, bytes32(uint256(uint160(value))));
+ }
+
+ /**
+ * @dev Removes a value from a set. O(1).
+ *
+ * Returns true if the value was removed from the set, that is if it was
+ * present.
+ */
+ function remove(AddressSet storage set, address value) internal returns (bool) {
+ return _remove(set._inner, bytes32(uint256(uint160(value))));
+ }
+
+ /**
+ * @dev Returns true if the value is in the set. O(1).
+ */
+ function contains(AddressSet storage set, address value) internal view returns (bool) {
+ return _contains(set._inner, bytes32(uint256(uint160(value))));
+ }
+
+ /**
+ * @dev Returns the number of values in the set. O(1).
+ */
+ function length(AddressSet storage set) internal view returns (uint256) {
+ return _length(set._inner);
+ }
+
+ /**
+ * @dev Returns the value stored at position `index` in the set. O(1).
+ *
+ * Note that there are no guarantees on the ordering of values inside the
+ * array, and it may change when more values are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function at(AddressSet storage set, uint256 index) internal view returns (address) {
+ return address(uint160(uint256(_at(set._inner, index))));
+ }
+
+ /**
+ * @dev Return the entire set in an array
+ *
+ * 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.
+ */
+ function values(AddressSet storage set) internal view returns (address[] memory) {
+ bytes32[] memory store = _values(set._inner);
+ address[] memory result;
+
+ /// @solidity memory-safe-assembly
+ assembly {
+ result := store
+ }
+
+ return result;
+ }
+
+ // UintSet
+
+ struct UintSet {
+ Set _inner;
+ }
+
+ /**
+ * @dev Add a value to a set. O(1).
+ *
+ * Returns true if the value was added to the set, that is if it was not
+ * already present.
+ */
+ function add(UintSet storage set, uint256 value) internal returns (bool) {
+ return _add(set._inner, bytes32(value));
+ }
+
+ /**
+ * @dev Removes a value from a set. O(1).
+ *
+ * Returns true if the value was removed from the set, that is if it was
+ * present.
+ */
+ function remove(UintSet storage set, uint256 value) internal returns (bool) {
+ return _remove(set._inner, bytes32(value));
+ }
+
+ /**
+ * @dev Returns true if the value is in the set. O(1).
+ */
+ function contains(UintSet storage set, uint256 value) internal view returns (bool) {
+ return _contains(set._inner, bytes32(value));
+ }
+
+ /**
+ * @dev Returns the number of values in the set. O(1).
+ */
+ function length(UintSet storage set) internal view returns (uint256) {
+ return _length(set._inner);
+ }
+
+ /**
+ * @dev Returns the value stored at position `index` in the set. O(1).
+ *
+ * Note that there are no guarantees on the ordering of values inside the
+ * array, and it may change when more values are added or removed.
+ *
+ * Requirements:
+ *
+ * - `index` must be strictly less than {length}.
+ */
+ function at(UintSet storage set, uint256 index) internal view returns (uint256) {
+ return uint256(_at(set._inner, index));
+ }
+
+ /**
+ * @dev Return the entire set in an array
+ *
+ * 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.
+ */
+ function values(UintSet storage set) internal view returns (uint256[] memory) {
+ bytes32[] memory store = _values(set._inner);
+ uint256[] memory result;
+
+ /// @solidity memory-safe-assembly
+ assembly {
+ result := store
+ }
+
+ return result;
+ }
+}
diff --git a/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts b/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts
index 62733bcad43..6b220f2f7cb 100644
--- a/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts
+++ b/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts
@@ -23,7 +23,7 @@ import { MockArbGasInfo__factory as MockArbGasInfoFactory } from '../../../typec
import { MockOVMGasPriceOracle__factory as MockOVMGasPriceOracleFactory } from '../../../typechain/factories/MockOVMGasPriceOracle__factory'
import { ChainModuleBase__factory as ChainModuleBaseFactory } from '../../../typechain/factories/ChainModuleBase__factory'
import { ArbitrumModule__factory as ArbitrumModuleFactory } from '../../../typechain/factories/ArbitrumModule__factory'
-import { OptimismModule__factory as OptimismModuleFactory } from '../../../typechain/factories/OptimismModule__factory'
+import { OptimismModuleV2__factory as OptimismModuleV2Factory } from '../../../typechain/factories/OptimismModuleV2__factory'
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'
@@ -35,7 +35,7 @@ import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator'
import { UpkeepMock } from '../../../typechain/UpkeepMock'
import { ChainModuleBase } from '../../../typechain/ChainModuleBase'
import { ArbitrumModule } from '../../../typechain/ArbitrumModule'
-import { OptimismModule } from '../../../typechain/OptimismModule'
+import { OptimismModuleV2 } from '../../../typechain/OptimismModuleV2'
import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder'
import { IChainModule, UpkeepAutoFunder } from '../../../typechain'
import {
@@ -148,7 +148,7 @@ let upkeepMockFactory: UpkeepMockFactory
let upkeepAutoFunderFactory: UpkeepAutoFunderFactory
let chainModuleBaseFactory: ChainModuleBaseFactory
let arbitrumModuleFactory: ArbitrumModuleFactory
-let optimismModuleFactory: OptimismModuleFactory
+let optimismModuleV2Factory: OptimismModuleV2Factory
let streamsLookupUpkeepFactory: StreamsLookupUpkeepFactory
let personas: Personas
@@ -169,7 +169,7 @@ let ltUpkeep: MockContract
let transcoder: UpkeepTranscoder
let chainModuleBase: ChainModuleBase
let arbitrumModule: ArbitrumModule
-let optimismModule: OptimismModule
+let optimismModule: OptimismModuleV2
let streamsLookupUpkeep: StreamsLookupUpkeep
let automationUtils: AutomationCompatibleUtils
@@ -430,7 +430,8 @@ describe('AutomationRegistry2_2', () => {
await ethers.getContractFactory('UpkeepAutoFunder')
chainModuleBaseFactory = await ethers.getContractFactory('ChainModuleBase')
arbitrumModuleFactory = await ethers.getContractFactory('ArbitrumModule')
- optimismModuleFactory = await ethers.getContractFactory('OptimismModule')
+ optimismModuleV2Factory =
+ await ethers.getContractFactory('OptimismModuleV2')
streamsLookupUpkeepFactory = await ethers.getContractFactory(
'StreamsLookupUpkeep',
)
@@ -844,7 +845,7 @@ describe('AutomationRegistry2_2', () => {
.deploy()
chainModuleBase = await chainModuleBaseFactory.connect(owner).deploy()
arbitrumModule = await arbitrumModuleFactory.connect(owner).deploy()
- optimismModule = await optimismModuleFactory.connect(owner).deploy()
+ optimismModule = await optimismModuleV2Factory.connect(owner).deploy()
streamsLookupUpkeep = await streamsLookupUpkeepFactory
.connect(owner)
.deploy(
diff --git a/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts b/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts
index 9a572269695..f3c2d9bb984 100644
--- a/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts
+++ b/contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts
@@ -23,9 +23,8 @@ import { MockArbGasInfo__factory as MockArbGasInfoFactory } from '../../../typec
import { MockOVMGasPriceOracle__factory as MockOVMGasPriceOracleFactory } from '../../../typechain/factories/MockOVMGasPriceOracle__factory'
import { ChainModuleBase__factory as ChainModuleBaseFactory } from '../../../typechain/factories/ChainModuleBase__factory'
import { ArbitrumModule__factory as ArbitrumModuleFactory } from '../../../typechain/factories/ArbitrumModule__factory'
-import { OptimismModule__factory as OptimismModuleFactory } from '../../../typechain/factories/OptimismModule__factory'
+import { OptimismModuleV2__factory as OptimismModuleV2Factory } from '../../../typechain/factories/OptimismModuleV2__factory'
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 { AutomationCompatibleUtils } from '../../../typechain/AutomationCompatibleUtils'
import { MockArbGasInfo } from '../../../typechain/MockArbGasInfo'
@@ -35,7 +34,7 @@ import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator'
import { UpkeepMock } from '../../../typechain/UpkeepMock'
import { ChainModuleBase } from '../../../typechain/ChainModuleBase'
import { ArbitrumModule } from '../../../typechain/ArbitrumModule'
-import { OptimismModule } from '../../../typechain/OptimismModule'
+import { OptimismModuleV2 } from '../../../typechain/OptimismModuleV2'
import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder'
import { IChainModule, UpkeepAutoFunder } from '../../../typechain'
import {
@@ -153,7 +152,7 @@ let upkeepMockFactory: UpkeepMockFactory
let upkeepAutoFunderFactory: UpkeepAutoFunderFactory
let chainModuleBaseFactory: ChainModuleBaseFactory
let arbitrumModuleFactory: ArbitrumModuleFactory
-let optimismModuleFactory: OptimismModuleFactory
+let optimismModuleFactory: OptimismModuleV2Factory
let streamsLookupUpkeepFactory: StreamsLookupUpkeepFactory
let personas: Personas
@@ -175,7 +174,7 @@ let ltUpkeep: MockContract
let transcoder: UpkeepTranscoder
let chainModuleBase: ChainModuleBase
let arbitrumModule: ArbitrumModule
-let optimismModule: OptimismModule
+let optimismModule: OptimismModuleV2
let streamsLookupUpkeep: StreamsLookupUpkeep
let automationUtils: AutomationCompatibleUtils
let automationUtils2_3: AutomationUtils2_3
@@ -443,7 +442,7 @@ describe('AutomationRegistry2_3', () => {
await ethers.getContractFactory('UpkeepAutoFunder')
chainModuleBaseFactory = await ethers.getContractFactory('ChainModuleBase')
arbitrumModuleFactory = await ethers.getContractFactory('ArbitrumModule')
- optimismModuleFactory = await ethers.getContractFactory('OptimismModule')
+ optimismModuleFactory = await ethers.getContractFactory('OptimismModuleV2')
streamsLookupUpkeepFactory = await ethers.getContractFactory(
'StreamsLookupUpkeep',
)
@@ -3107,44 +3106,6 @@ describe('AutomationRegistry2_3', () => {
await getTransmitTx(registry, keeper1, [upkeepId2])
})
- it('reverts if called on a non existing ID', async () => {
- await evmRevertCustomError(
- registry
- .connect(admin)
- .withdrawFunds(upkeepId.add(1), await payee1.getAddress()),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if called by anyone but the admin', async () => {
- await evmRevertCustomError(
- registry
- .connect(owner)
- .withdrawFunds(upkeepId, await payee1.getAddress()),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if called on an uncanceled upkeep', async () => {
- await evmRevertCustomError(
- registry
- .connect(admin)
- .withdrawFunds(upkeepId, await payee1.getAddress()),
- registry,
- 'UpkeepNotCanceled',
- )
- })
-
- it('reverts if called with the 0 address', async () => {
- await evmRevertCustomError(
- registry.connect(admin).withdrawFunds(upkeepId, zeroAddress),
- registry,
- 'InvalidRecipient',
- )
- })
-
describe('after the registration is paused, then cancelled', () => {
it('allows the admin to withdraw', async () => {
const balance = await registry.getBalance(upkeepId)
@@ -3514,46 +3475,6 @@ describe('AutomationRegistry2_3', () => {
})
})
- describe('#getActiveUpkeepIDs', () => {
- it('reverts if startIndex is out of bounds ', async () => {
- await evmRevertCustomError(
- registry.getActiveUpkeepIDs(numUpkeeps, 0),
- registry,
- 'IndexOutOfRange',
- )
- await evmRevertCustomError(
- registry.getActiveUpkeepIDs(numUpkeeps + 1, 0),
- registry,
- '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', () => {
let maxl1CostWeiArbWithoutMultiplier: BigNumber
let maxl1CostWeiOptWithoutMultiplier: BigNumber
@@ -4225,1140 +4146,180 @@ describe('AutomationRegistry2_3', () => {
})
})
- 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('#pauseUpkeep', () => {
- it('reverts if the registration does not exist', async () => {
- await evmRevertCustomError(
- registry.connect(keeper1).pauseUpkeep(upkeepId.add(1)),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if the upkeep is already canceled', async () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
-
- await evmRevertCustomError(
- registry.connect(admin).pauseUpkeep(upkeepId),
- registry,
- 'UpkeepCancelled',
- )
- })
-
- it('reverts if the upkeep is already paused', async () => {
- await registry.connect(admin).pauseUpkeep(upkeepId)
-
- await evmRevertCustomError(
- registry.connect(admin).pauseUpkeep(upkeepId),
- registry,
- 'OnlyUnpausedUpkeep',
- )
- })
-
- it('reverts if the caller is not the upkeep admin', async () => {
- await evmRevertCustomError(
- registry.connect(keeper1).pauseUpkeep(upkeepId),
- registry,
- '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)
+ describe('#cancelUpkeep', () => {
+ describe('when called by the owner', async () => {
+ it('immediately prevents upkeep', async () => {
+ await registry.connect(owner).cancelUpkeep(upkeepId)
- const registration = await registry.getUpkeep(upkeepId)
- assert.equal(registration.paused, true)
+ 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)
+ })
})
- })
- describe('#unpauseUpkeep', () => {
- it('reverts if the registration does not exist', async () => {
- await evmRevertCustomError(
- registry.connect(keeper1).unpauseUpkeep(upkeepId.add(1)),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
+ describe('when called by the admin', async () => {
+ 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)
- it('reverts if the upkeep is already canceled', async () => {
- await registry.connect(owner).cancelUpkeep(upkeepId)
+ await getTransmitTx(registry, keeper1, [upkeepId])
- await evmRevertCustomError(
- registry.connect(admin).unpauseUpkeep(upkeepId),
- registry,
- 'UpkeepCancelled',
- )
- })
+ for (let i = 0; i < cancellationDelay; i++) {
+ await ethers.provider.send('evm_mine', [])
+ }
- it('marks the contract as paused', async () => {
- assert.isFalse((await registry.getState()).state.paused)
+ const tx = await getTransmitTx(registry, keeper1, [upkeepId])
- await registry.connect(owner).pause()
+ const receipt = await tx.wait()
+ const cancelledUpkeepReportLogs =
+ parseCancelledUpkeepReportLogs(receipt)
+ // exactly 1 CancelledUpkeepReport log should be emitted
+ assert.equal(cancelledUpkeepReportLogs.length, 1)
+ })
- assert.isTrue((await registry.getState()).state.paused)
- })
+ 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('reverts if the upkeep is not paused', async () => {
- await evmRevertCustomError(
- registry.connect(admin).unpauseUpkeep(upkeepId),
- registry,
- 'OnlyPausedUpkeep',
- )
- })
+ it('deducts a cancellation fee from the upkeep and adds to reserve', async () => {
+ const newMinUpkeepSpend = toWei('10')
+ const financeAdminAddress = await financeAdmin.getAddress()
- it('reverts if the caller is not the upkeep admin', async () => {
- await registry.connect(admin).pauseUpkeep(upkeepId)
+ await registry.connect(owner).setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ {
+ checkGasLimit,
+ stalenessSeconds,
+ gasCeilingMultiplier,
+ maxCheckDataSize,
+ maxPerformDataSize,
+ maxRevertDataSize,
+ maxPerformGas,
+ fallbackGasPrice,
+ fallbackLinkPrice,
+ fallbackNativePrice,
+ transcoder: transcoder.address,
+ registrars: [],
+ upkeepPrivilegeManager: upkeepManager,
+ chainModule: chainModuleBase.address,
+ reorgProtectionEnabled: true,
+ financeAdmin: financeAdminAddress,
+ },
+ offchainVersion,
+ offchainBytes,
+ [linkToken.address],
+ [
+ {
+ gasFeePPB: paymentPremiumPPB,
+ flatFeeMilliCents,
+ priceFeed: linkUSDFeed.address,
+ fallbackPrice: fallbackLinkPrice,
+ minSpend: newMinUpkeepSpend,
+ decimals: 18,
+ },
+ ],
+ )
- const registration = await registry.getUpkeep(upkeepId)
+ const payee1Before = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance
+ const ownerBefore = await registry.linkAvailableForPayment()
- assert.equal(registration.paused, true)
+ const amountSpent = toWei('100').sub(upkeepBefore)
+ const cancellationFee = newMinUpkeepSpend.sub(amountSpent)
- await evmRevertCustomError(
- registry.connect(keeper1).unpauseUpkeep(upkeepId),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
+ await registry.connect(admin).cancelUpkeep(upkeepId)
- it('unpauses the upkeep and emits an event', async () => {
- const originalCount = (await registry.getActiveUpkeepIDs(0, 0)).length
+ const payee1After = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance
+ const ownerAfter = await registry.linkAvailableForPayment()
- await registry.connect(admin).pauseUpkeep(upkeepId)
+ // 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))
+ })
- const tx = await registry.connect(admin).unpauseUpkeep(upkeepId)
+ it('deducts up to balance as cancellation fee', async () => {
+ // Very high min spend, should deduct whole balance as cancellation fees
+ const newMinUpkeepSpend = toWei('1000')
+ const financeAdminAddress = await financeAdmin.getAddress()
- await expect(tx).to.emit(registry, 'UpkeepUnpaused').withArgs(upkeepId)
+ await registry.connect(owner).setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ {
+ checkGasLimit,
+ stalenessSeconds,
+ gasCeilingMultiplier,
+ maxCheckDataSize,
+ maxPerformDataSize,
+ maxRevertDataSize,
+ maxPerformGas,
+ fallbackGasPrice,
+ fallbackLinkPrice,
+ fallbackNativePrice,
+ transcoder: transcoder.address,
+ registrars: [],
+ upkeepPrivilegeManager: upkeepManager,
+ chainModule: chainModuleBase.address,
+ reorgProtectionEnabled: true,
+ financeAdmin: financeAdminAddress,
+ },
+ offchainVersion,
+ offchainBytes,
+ [linkToken.address],
+ [
+ {
+ gasFeePPB: paymentPremiumPPB,
+ flatFeeMilliCents,
+ priceFeed: linkUSDFeed.address,
+ fallbackPrice: fallbackLinkPrice,
+ minSpend: newMinUpkeepSpend,
+ decimals: 18,
+ },
+ ],
+ )
+ const payee1Before = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance
+ const ownerBefore = await registry.linkAvailableForPayment()
- const registration = await registry.getUpkeep(upkeepId)
- assert.equal(registration.paused, false)
+ await registry.connect(admin).cancelUpkeep(upkeepId)
+ const payee1After = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const ownerAfter = await registry.linkAvailableForPayment()
+ const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance
- const upkeepIds = await registry.getActiveUpkeepIDs(0, 0)
- assert.equal(upkeepIds.length, originalCount)
- })
- })
+ // all upkeep balance is deducted for cancellation fee
+ assert.equal(upkeepAfter.toNumber(), 0)
+ // 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))
+ })
- describe('#setUpkeepCheckData', () => {
- it('reverts if the registration does not exist', async () => {
- await evmRevertCustomError(
- registry
- .connect(keeper1)
- .setUpkeepCheckData(upkeepId.add(1), randomBytes),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if the caller is not upkeep admin', async () => {
- await evmRevertCustomError(
- registry.connect(keeper1).setUpkeepCheckData(upkeepId, randomBytes),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if the upkeep is cancelled', async () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
-
- await evmRevertCustomError(
- registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes),
- registry,
- '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 evmRevertCustomError(
- registry.connect(admin).setUpkeepCheckData(upkeepId, longBytes),
- registry,
- '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 evmRevertCustomError(
- registry.connect(admin).setUpkeepGasLimit(upkeepId.add(1), newGasLimit),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if the upkeep is canceled', async () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
- await evmRevertCustomError(
- registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit),
- registry,
- 'UpkeepCancelled',
- )
- })
-
- it('reverts if called by anyone but the admin', async () => {
- await evmRevertCustomError(
- registry.connect(owner).setUpkeepGasLimit(upkeepId, newGasLimit),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if new gas limit is out of bounds', async () => {
- await evmRevertCustomError(
- registry
- .connect(admin)
- .setUpkeepGasLimit(upkeepId, BigNumber.from('100')),
- registry,
- 'GasLimitOutsideRange',
- )
- await evmRevertCustomError(
- registry
- .connect(admin)
- .setUpkeepGasLimit(upkeepId, BigNumber.from('6000000')),
- registry,
- '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 evmRevertCustomError(
- registry
- .connect(admin)
- .setUpkeepOffchainConfig(upkeepId.add(1), newConfig),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if the upkeep is canceled', async () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
- await evmRevertCustomError(
- registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig),
- registry,
- 'UpkeepCancelled',
- )
- })
-
- it('reverts if called by anyone but the admin', async () => {
- await evmRevertCustomError(
- registry.connect(owner).setUpkeepOffchainConfig(upkeepId, newConfig),
- registry,
- '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 evmRevertCustomError(
- registry
- .connect(admin)
- .setUpkeepTriggerConfig(upkeepId.add(1), newConfig),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts if the upkeep is canceled', async () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
- await evmRevertCustomError(
- registry.connect(admin).setUpkeepTriggerConfig(upkeepId, newConfig),
- registry,
- 'UpkeepCancelled',
- )
- })
-
- it('reverts if called by anyone but the admin', async () => {
- await evmRevertCustomError(
- registry.connect(owner).setUpkeepTriggerConfig(upkeepId, newConfig),
- registry,
- '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 evmRevertCustomError(
- registry
- .connect(payee1)
- .transferUpkeepAdmin(upkeepId, await payee2.getAddress()),
- registry,
- 'OnlyCallableByAdmin',
- )
- })
-
- it('reverts when transferring to self', async () => {
- await evmRevertCustomError(
- registry
- .connect(admin)
- .transferUpkeepAdmin(upkeepId, await admin.getAddress()),
- registry,
- 'ValueNotChanged',
- )
- })
-
- it('reverts when the upkeep is cancelled', async () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
-
- await evmRevertCustomError(
- registry
- .connect(admin)
- .transferUpkeepAdmin(upkeepId, await keeper1.getAddress()),
- registry,
- '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(receipt.logs.length, 0)
- })
- })
-
- 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 evmRevertCustomError(
- registry.connect(payee2).acceptUpkeepAdmin(upkeepId),
- registry,
- 'OnlyCallableByProposedAdmin',
- )
- })
-
- it('reverts when the upkeep is cancelled', async () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
-
- await evmRevertCustomError(
- registry.connect(payee1).acceptUpkeepAdmin(upkeepId),
- registry,
- '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 finance admin', async () => {
- await evmRevertCustomError(
- registry.connect(keeper1).withdrawLink(zeroAddress, 1),
- registry,
- 'OnlyFinanceAdmin',
- )
- })
-
- itMaybe('withdraws the collected fees to owner', async () => {
- await registry.connect(admin).addFunds(upkeepId, toWei('100'))
- const financeAdminAddress = await financeAdmin.getAddress()
- // Very high min spend, whole balance as cancellation fees
- const newMinUpkeepSpend = toWei('1000')
- await registry.connect(owner).setConfigTypeSafe(
- signerAddresses,
- keeperAddresses,
- f,
- {
- checkGasLimit,
- stalenessSeconds,
- gasCeilingMultiplier,
- maxCheckDataSize,
- maxPerformDataSize,
- maxRevertDataSize,
- maxPerformGas,
- fallbackGasPrice,
- fallbackLinkPrice,
- fallbackNativePrice,
- transcoder: transcoder.address,
- registrars: [],
- upkeepPrivilegeManager: upkeepManager,
- chainModule: chainModuleBase.address,
- reorgProtectionEnabled: true,
- financeAdmin: financeAdminAddress,
- },
- offchainVersion,
- offchainBytes,
- [linkToken.address],
- [
- {
- gasFeePPB: paymentPremiumPPB,
- flatFeeMilliCents,
- priceFeed: linkUSDFeed.address,
- fallbackPrice: fallbackLinkPrice,
- minSpend: newMinUpkeepSpend,
- decimals: 18,
- },
- ],
- )
- 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.linkAvailableForPayment()
- assert.isTrue(ownerRegistryBalance.eq(upkeepBalance))
-
- // Now withdraw
- await registry
- .connect(financeAdmin)
- .withdrawLink(await owner.getAddress(), ownerRegistryBalance)
-
- ownerRegistryBalance = await registry.linkAvailableForPayment()
- 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 evmRevertCustomError(
- registry
- .connect(payee2)
- .transferPayeeship(
- await keeper1.getAddress(),
- await payee2.getAddress(),
- ),
- registry,
- 'OnlyCallableByPayee',
- )
- })
-
- it('reverts when transferring to self', async () => {
- await evmRevertCustomError(
- registry
- .connect(payee1)
- .transferPayeeship(
- await keeper1.getAddress(),
- await payee1.getAddress(),
- ),
- registry,
- '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(receipt.logs.length, 0)
- })
- })
-
- 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 evmRevertCustomError(
- registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()),
- registry,
- '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 evmRevertCustomError(
- getTransmitTx(registry, keeper1, [upkeepId]),
- registry,
- 'RegistryPaused',
- )
- })
-
- it('Does not allow creation of new upkeeps when paused', async () => {
- await registry.connect(owner).pause()
-
- await evmRevertCustomError(
- registry
- .connect(owner)
- .registerUpkeep(
- mock.address,
- performGas,
- await admin.getAddress(),
- Trigger.CONDITION,
- linkToken.address,
- '0x',
- '0x',
- '0x',
- ),
- registry,
- '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('#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 evmRevertCustomError(
- registry.connect(owner).setPayees([...payees, randomAddress()]),
- registry,
- 'ParameterLengthError',
- )
- })
-
- it('reverts if the payee is the zero address', async () => {
- await blankRegistry.connect(owner).setConfigTypeSafe(...baseConfig) // used to test initial config
-
- await evmRevertCustomError(
- blankRegistry // used to test initial config
- .connect(owner)
- .setPayees([ethers.constants.AddressZero, ...payees.slice(1)]),
- registry,
- 'InvalidPayee',
- )
- })
-
- itMaybe(
- 'sets the payees when exisitng payees are zero address',
- async () => {
- //Initial payees should be zero address
- await blankRegistry.connect(owner).setConfigTypeSafe(...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(ignored.active, true)
- })
-
- it('reverts if payee is non zero and owner tries to change payee', async () => {
- const newPayees = [randomAddress(), ...payees.slice(1)]
-
- await evmRevertCustomError(
- registry.connect(owner).setPayees(newPayees),
- registry,
- '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 evmRevertCustomError(
- registry.connect(owner).cancelUpkeep(upkeepId.add(1)),
- registry,
- 'CannotCancel',
- )
- })
-
- it('reverts if called by a non-owner/non-admin', async () => {
- await evmRevertCustomError(
- registry.connect(keeper1).cancelUpkeep(upkeepId),
- registry,
- '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 evmRevertCustomError(
- registry.connect(owner).cancelUpkeep(upkeepId),
- 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 () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
- const registration = await registry.getUpkeep(upkeepId)
- oldExpiration = registration.maxValidBlocknumber
- })
-
- it('reverts with proper error', async () => {
- await evmRevertCustomError(
- registry.connect(owner).cancelUpkeep(upkeepId),
- registry,
- 'UpkeepCancelled',
- )
- })
- })
- })
-
- describe('when called by the admin', async () => {
- it('reverts if called again by the admin', async () => {
- await registry.connect(admin).cancelUpkeep(upkeepId)
-
- await evmRevertCustomError(
- registry.connect(admin).cancelUpkeep(upkeepId),
- registry,
- 'UpkeepCancelled',
- )
- })
-
- 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 evmRevertCustomError(
- registry.connect(owner).cancelUpkeep(upkeepId),
- registry,
- 'UpkeepCancelled',
- )
- })
-
- 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 adds to reserve', async () => {
- const newMinUpkeepSpend = toWei('10')
- const financeAdminAddress = await financeAdmin.getAddress()
-
- await registry.connect(owner).setConfigTypeSafe(
- signerAddresses,
- keeperAddresses,
- f,
- {
- checkGasLimit,
- stalenessSeconds,
- gasCeilingMultiplier,
- maxCheckDataSize,
- maxPerformDataSize,
- maxRevertDataSize,
- maxPerformGas,
- fallbackGasPrice,
- fallbackLinkPrice,
- fallbackNativePrice,
- transcoder: transcoder.address,
- registrars: [],
- upkeepPrivilegeManager: upkeepManager,
- chainModule: chainModuleBase.address,
- reorgProtectionEnabled: true,
- financeAdmin: financeAdminAddress,
- },
- offchainVersion,
- offchainBytes,
- [linkToken.address],
- [
- {
- gasFeePPB: paymentPremiumPPB,
- flatFeeMilliCents,
- priceFeed: linkUSDFeed.address,
- fallbackPrice: fallbackLinkPrice,
- minSpend: newMinUpkeepSpend,
- decimals: 18,
- },
- ],
- )
-
- const payee1Before = await linkToken.balanceOf(
- await payee1.getAddress(),
- )
- const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance
- const ownerBefore = await registry.linkAvailableForPayment()
-
- const amountSpent = toWei('100').sub(upkeepBefore)
- const cancellationFee = newMinUpkeepSpend.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.linkAvailableForPayment()
-
- // 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 newMinUpkeepSpend = toWei('1000')
- const financeAdminAddress = await financeAdmin.getAddress()
-
- await registry.connect(owner).setConfigTypeSafe(
- signerAddresses,
- keeperAddresses,
- f,
- {
- checkGasLimit,
- stalenessSeconds,
- gasCeilingMultiplier,
- maxCheckDataSize,
- maxPerformDataSize,
- maxRevertDataSize,
- maxPerformGas,
- fallbackGasPrice,
- fallbackLinkPrice,
- fallbackNativePrice,
- transcoder: transcoder.address,
- registrars: [],
- upkeepPrivilegeManager: upkeepManager,
- chainModule: chainModuleBase.address,
- reorgProtectionEnabled: true,
- financeAdmin: financeAdminAddress,
- },
- offchainVersion,
- offchainBytes,
- [linkToken.address],
- [
- {
- gasFeePPB: paymentPremiumPPB,
- flatFeeMilliCents,
- priceFeed: linkUSDFeed.address,
- fallbackPrice: fallbackLinkPrice,
- minSpend: newMinUpkeepSpend,
- decimals: 18,
- },
- ],
- )
- const payee1Before = await linkToken.balanceOf(
- await payee1.getAddress(),
- )
- const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance
- const ownerBefore = await registry.linkAvailableForPayment()
-
- await registry.connect(admin).cancelUpkeep(upkeepId)
- const payee1After = await linkToken.balanceOf(
- await payee1.getAddress(),
- )
- const ownerAfter = await registry.linkAvailableForPayment()
- const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance
-
- // all upkeep balance is deducted for cancellation fee
- assert.equal(upkeepAfter.toNumber(), 0)
- // 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 minUpkeepSpendDollars is spent', async () => {
- // Very low min spend, already spent in one perform upkeep
- const newMinUpkeepSpend = BigNumber.from(420)
- const financeAdminAddress = await financeAdmin.getAddress()
+ it('does not deduct cancellation fee if more than minUpkeepSpendDollars is spent', async () => {
+ // Very low min spend, already spent in one perform upkeep
+ const newMinUpkeepSpend = BigNumber.from(420)
+ const financeAdminAddress = await financeAdmin.getAddress()
await registry.connect(owner).setConfigTypeSafe(
signerAddresses,
@@ -5595,62 +4556,6 @@ describe('AutomationRegistry2_3', () => {
})
})
- describe('#setUpkeepPrivilegeConfig() / #getUpkeepPrivilegeConfig()', () => {
- it('reverts when non manager tries to set privilege config', async () => {
- await evmRevertCustomError(
- registry.connect(payee3).setUpkeepPrivilegeConfig(upkeepId, '0x1234'),
- registry,
- '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 evmRevertCustomError(
- registry.connect(payee3).setAdminPrivilegeConfig(admin, '0x1234'),
- registry,
- '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'))
diff --git a/contracts/test/v0.8/automation/ZKSyncAutomationRegistry2_3.test.ts b/contracts/test/v0.8/automation/ZKSyncAutomationRegistry2_3.test.ts
new file mode 100644
index 00000000000..95210cf6444
--- /dev/null
+++ b/contracts/test/v0.8/automation/ZKSyncAutomationRegistry2_3.test.ts
@@ -0,0 +1,4403 @@
+import { ethers } from 'hardhat'
+import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'
+import { assert, expect } from 'chai'
+import {
+ BigNumber,
+ BigNumberish,
+ BytesLike,
+ Contract,
+ ContractFactory,
+ ContractReceipt,
+ ContractTransaction,
+ Signer,
+ Wallet,
+} from 'ethers'
+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'
+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 { MockZKSyncSystemContext__factory as MockZKSyncSystemContextFactory } from '../../../typechain/factories/MockZKSyncSystemContext__factory'
+import { ChainModuleBase__factory as ChainModuleBaseFactory } from '../../../typechain/factories/ChainModuleBase__factory'
+import { MockGasBoundCaller__factory as MockGasBoundCallerFactory } from '../../../typechain/factories/MockGasBoundCaller__factory'
+import { ILogAutomation__factory as ILogAutomationactory } from '../../../typechain/factories/ILogAutomation__factory'
+import { AutomationCompatibleUtils } from '../../../typechain/AutomationCompatibleUtils'
+import { StreamsLookupUpkeep } from '../../../typechain/StreamsLookupUpkeep'
+import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator'
+import { MockGasBoundCaller } from '../../../typechain/MockGasBoundCaller'
+import { UpkeepMock } from '../../../typechain/UpkeepMock'
+import { ChainModuleBase } from '../../../typechain/ChainModuleBase'
+import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder'
+import { MockZKSyncSystemContext } from '../../../typechain/MockZKSyncSystemContext'
+import { IChainModule, UpkeepAutoFunder } from '../../../typechain'
+import {
+ CancelledUpkeepReportEvent,
+ IAutomationRegistryMaster2_3 as IAutomationRegistry,
+ ReorgedUpkeepReportEvent,
+ StaleUpkeepReportEvent,
+ UpkeepPerformedEvent,
+} from '../../../typechain/IAutomationRegistryMaster2_3'
+import {
+ deployMockContract,
+ MockContract,
+} from '@ethereum-waffle/mock-contract'
+import { deployZKSyncRegistry23 } 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
+
+// copied from AutomationRegistryInterface2_3.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 AutomationRegistryBase2_3.sol
+enum Trigger {
+ CONDITION,
+ LOG,
+}
+
+// un-exported types that must be extracted from the utils contract
+type Report = Parameters[0]
+type LogTrigger = Parameters[0]
+type ConditionalTrigger = Parameters<
+ AutomationCompatibleUtils['_conditionalTrigger']
+>[0]
+type Log = Parameters[0]
+type OnChainConfig = Parameters[3]
+
+// -----------------------------------------------------------------------------------------------
+
+// These values should match the constants declared in registry
+let registryConditionalOverhead: BigNumber
+let registryLogOverhead: BigNumber
+let registryPerSignerGasOverhead: BigNumber
+// let registryPerPerformByteGasOverhead: BigNumber
+// let registryTransmitCalldataFixedBytesOverhead: BigNumber
+// let registryTransmitCalldataPerSignerBytesOverhead: 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(50_000)
+// This is the margin for gas overhead estimation in checkUpkeep. The estimated gas
+// overhead should be larger than actual gas overhead but should not increase beyond this margin
+// const gasEstimationMargin = BigNumber.from(50_000)
+
+// 1 Link = 0.005 Eth
+const linkUSD = BigNumber.from('2000000000') // 1 LINK = $20
+const nativeUSD = BigNumber.from('400000000000') // 1 ETH = $4000
+const gasWei = BigNumber.from(1000000000) // 1 gwei
+// -----------------------------------------------------------------------------------------------
+// test-wide configs for upkeeps
+const performGas = BigNumber.from('1000000')
+const paymentPremiumBase = BigNumber.from('1000000000')
+const paymentPremiumPPB = BigNumber.from('250000000')
+const flatFeeMilliCents = BigNumber.from(0)
+
+const randomBytes = '0x1234abcd'
+const emptyBytes = '0x'
+const emptyBytes32 =
+ '0x0000000000000000000000000000000000000000000000000000000000000000'
+
+const pubdataGas = BigNumber.from(500000)
+const transmitGasOverhead = 1_040_000
+const checkGasOverhead = 600_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 = linkUSD.div(BigNumber.from('2'))
+const fallbackNativePrice = nativeUSD.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 wrappedNativeTokenAddress = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'
+const epochAndRound5_1 =
+ '0x0000000000000000000000000000000000000000000000000000000000000501'
+
+let logTriggerConfig: string
+
+// -----------------------------------------------------------------------------------------------
+
+// Smart contract factories
+let linkTokenFactory: ContractFactory
+let mockV3AggregatorFactory: MockV3AggregatorFactory
+let mockGasBoundCallerFactory: MockGasBoundCallerFactory
+let upkeepMockFactory: UpkeepMockFactory
+let upkeepAutoFunderFactory: UpkeepAutoFunderFactory
+let moduleBaseFactory: ChainModuleBaseFactory
+let mockZKSyncSystemContextFactory: MockZKSyncSystemContextFactory
+let streamsLookupUpkeepFactory: StreamsLookupUpkeepFactory
+let personas: Personas
+
+// contracts
+let linkToken: Contract
+let linkUSDFeed: MockV3Aggregator
+let nativeUSDFeed: MockV3Aggregator
+let gasPriceFeed: MockV3Aggregator
+let registry: IAutomationRegistry // default registry, used for most tests
+let mgRegistry: IAutomationRegistry // "migrate registry" used in migration tests
+let mock: UpkeepMock
+let autoFunderUpkeep: UpkeepAutoFunder
+let ltUpkeep: MockContract
+let transcoder: UpkeepTranscoder
+let moduleBase: ChainModuleBase
+let mockGasBoundCaller: MockGasBoundCaller
+let mockZKSyncSystemContext: MockZKSyncSystemContext
+let streamsLookupUpkeep: StreamsLookupUpkeep
+let automationUtils: AutomationCompatibleUtils
+let automationUtils2_3: AutomationUtils2_3
+
+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 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' +
+ automationUtils2_3.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,
+ linkUSD,
+ 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 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('ZKSyncAutomationRegistry2_3', () => {
+ 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 financeAdmin: 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: OnChainConfig
+ let baseConfig: 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')
+ automationUtils2_3 = 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
+ mockZKSyncSystemContextFactory = await ethers.getContractFactory(
+ 'MockZKSyncSystemContext',
+ )
+ mockGasBoundCallerFactory =
+ await ethers.getContractFactory('MockGasBoundCaller')
+ upkeepMockFactory = await ethers.getContractFactory('UpkeepMock')
+ upkeepAutoFunderFactory =
+ await ethers.getContractFactory('UpkeepAutoFunder')
+ moduleBaseFactory = await ethers.getContractFactory('ChainModuleBase')
+ 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()
+ financeAdmin = personas.Nick
+ // 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)
+ })
+
+ // This function is similar to registry's _calculatePaymentAmount
+ // It uses global fastGasWei, linkEth, and assumes isExecution = false (gasFee = fastGasWei*multiplier)
+ // rest of the parameters are the same
+ const linkForGas = (
+ upkeepGasSpent: BigNumber,
+ gasOverhead: BigNumber,
+ gasMultiplier: BigNumber,
+ premiumPPB: BigNumber,
+ flatFee: BigNumber, // in millicents
+ ) => {
+ const gasSpent = gasOverhead.add(BigNumber.from(upkeepGasSpent))
+ const gasPayment = gasWei
+ .mul(gasMultiplier)
+ .mul(gasSpent)
+ .mul(nativeUSD)
+ .div(linkUSD)
+
+ const premium = gasWei
+ .mul(gasMultiplier)
+ .mul(upkeepGasSpent)
+ .mul(premiumPPB)
+ .mul(nativeUSD)
+ .div(paymentPremiumBase)
+ .add(flatFee.mul(BigNumber.from(10).pow(21)))
+ .div(linkUSD)
+
+ return {
+ total: gasPayment.add(premium),
+ gasPayment,
+ premium,
+ }
+ }
+
+ const verifyMaxPayment = async (
+ registry: IAutomationRegistry,
+ chainModule: IChainModule,
+ ) => {
+ 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 chainModuleOverheads = await chainModule.getGasOverhead()
+ const totalConditionalOverhead = registryConditionalOverhead
+ .add(registryPerSignerGasOverhead.mul(fPlusOne))
+ .add(chainModuleOverheads.chainModuleFixedOverhead)
+
+ const totalLogOverhead = registryLogOverhead
+ .add(registryPerSignerGasOverhead.mul(fPlusOne))
+ .add(chainModuleOverheads.chainModuleFixedOverhead)
+
+ const financeAdminAddress = await financeAdmin.getAddress()
+
+ for (const test of tests) {
+ await registry.connect(owner).setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ {
+ 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,
+ decimals: 18,
+ },
+ ],
+ )
+
+ const conditionalPrice = await registry.getMaxPaymentForGas(
+ upkeepId,
+ Trigger.CONDITION,
+ test.gas,
+ linkToken.address,
+ )
+ expect(conditionalPrice).to.equal(
+ linkForGas(
+ BigNumber.from(test.gas),
+ totalConditionalOverhead,
+ BigNumber.from(test.multiplier),
+ BigNumber.from(test.premium),
+ BigNumber.from(test.flatFee),
+ ).total,
+ )
+
+ const logPrice = await registry.getMaxPaymentForGas(
+ upkeepId,
+ Trigger.LOG,
+ test.gas,
+ linkToken.address,
+ )
+ expect(logPrice).to.equal(
+ linkForGas(
+ BigNumber.from(test.gas),
+ totalLogOverhead,
+ BigNumber.from(test.multiplier),
+ BigNumber.from(test.premium),
+ BigNumber.from(test.flatFee),
+ ).total,
+ )
+ }
+ }
+
+ const verifyConsistentAccounting = async (
+ maxAllowedSpareChange: BigNumber,
+ ) => {
+ 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)
+ for (let i = 0; i < keeperAddresses.length; i++) {
+ totalKeeperBalance = totalKeeperBalance.add(
+ (await registry.getTransmitterInfo(keeperAddresses[i])).balance,
+ )
+ }
+
+ const linkAvailableForPayment = await registry.linkAvailableForPayment()
+ assert.isTrue(expectedLinkBalance.eq(linkTokenBalance))
+ assert.isTrue(
+ upkeepIdBalance
+ .add(totalKeeperBalance)
+ .add(linkAvailableForPayment)
+ .lte(expectedLinkBalance),
+ )
+ assert.isTrue(
+ expectedLinkBalance
+ .sub(upkeepIdBalance)
+ .sub(totalKeeperBalance)
+ .sub(linkAvailableForPayment)
+ .lte(maxAllowedSpareChange),
+ )
+ }
+
+ interface GetTransmitTXOptions {
+ numSigners?: number
+ startingSignerIndex?: number
+ gasLimit?: BigNumberish
+ gasPrice?: BigNumberish
+ performGas?: BigNumberish
+ performDatas?: string[]
+ checkBlockNum?: number
+ checkBlockHash?: string
+ logBlockHash?: BytesLike
+ txHash?: BytesLike
+ logIndex?: number
+ timestamp?: number
+ }
+
+ const getTransmitTx = async (
+ registry: IAutomationRegistry,
+ 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,
+ performDatas: undefined,
+ 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.performDatas ? config.performDatas[i] : '0x',
+ })
+ }
+
+ 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: IAutomationRegistry,
+ 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)
+ linkUSDFeed = await mockV3AggregatorFactory
+ .connect(owner)
+ .deploy(8, linkUSD)
+ nativeUSDFeed = await mockV3AggregatorFactory
+ .connect(owner)
+ .deploy(8, nativeUSD)
+ const upkeepTranscoderFactory = await ethers.getContractFactory(
+ 'UpkeepTranscoder5_0',
+ )
+ transcoder = await upkeepTranscoderFactory.connect(owner).deploy()
+ mockZKSyncSystemContext = await mockZKSyncSystemContextFactory
+ .connect(owner)
+ .deploy()
+ mockGasBoundCaller = await mockGasBoundCallerFactory.connect(owner).deploy()
+ moduleBase = await moduleBaseFactory.connect(owner).deploy()
+ streamsLookupUpkeep = await streamsLookupUpkeepFactory
+ .connect(owner)
+ .deploy(
+ BigNumber.from('10000'),
+ BigNumber.from('100'),
+ false /* useArbBlock */,
+ true /* staging */,
+ false /* verify mercury response */,
+ )
+
+ const zksyncSystemContextCode = await ethers.provider.send('eth_getCode', [
+ mockZKSyncSystemContext.address,
+ ])
+ await ethers.provider.send('hardhat_setCode', [
+ '0x000000000000000000000000000000000000800B',
+ zksyncSystemContextCode,
+ ])
+
+ const gasBoundCallerCode = await ethers.provider.send('eth_getCode', [
+ mockGasBoundCaller.address,
+ ])
+ await ethers.provider.send('hardhat_setCode', [
+ '0xc706EC7dfA5D4Dc87f29f859094165E8290530f5',
+ gasBoundCallerCode,
+ ])
+
+ const financeAdminAddress = await financeAdmin.getAddress()
+
+ config = {
+ checkGasLimit,
+ stalenessSeconds,
+ gasCeilingMultiplier,
+ maxCheckDataSize,
+ maxPerformDataSize,
+ maxRevertDataSize,
+ maxPerformGas,
+ fallbackGasPrice,
+ fallbackLinkPrice,
+ fallbackNativePrice,
+ transcoder: transcoder.address,
+ registrars: [],
+ upkeepPrivilegeManager: upkeepManager,
+ chainModule: moduleBase.address,
+ reorgProtectionEnabled: true,
+ financeAdmin: financeAdminAddress,
+ }
+
+ baseConfig = [
+ signerAddresses,
+ keeperAddresses,
+ f,
+ config,
+ offchainVersion,
+ offchainBytes,
+ [linkToken.address],
+ [
+ {
+ gasFeePPB: paymentPremiumPPB,
+ flatFeeMilliCents,
+ priceFeed: linkUSDFeed.address,
+ fallbackPrice: fallbackLinkPrice,
+ minSpend: minUpkeepSpend,
+ decimals: 18,
+ },
+ ],
+ ]
+
+ const registryParams: Parameters = [
+ owner,
+ linkToken.address,
+ linkUSDFeed.address,
+ nativeUSDFeed.address,
+ gasPriceFeed.address,
+ zeroAddress,
+ 0, // onchain payout mode
+ wrappedNativeTokenAddress,
+ ]
+
+ registry = await deployZKSyncRegistry23(...registryParams)
+ mgRegistry = await deployZKSyncRegistry23(...registryParams)
+
+ registryConditionalOverhead = await registry.getConditionalGasOverhead()
+ registryLogOverhead = await registry.getLogGasOverhead()
+ registryPerSignerGasOverhead = await registry.getPerSignerGasOverhead()
+ // registryPerPerformByteGasOverhead =
+ // await registry.getPerPerformByteGasOverhead()
+ // registryTransmitCalldataFixedBytesOverhead =
+ // await registry.getTransmitCalldataFixedBytesOverhead()
+ // registryTransmitCalldataPerSignerBytesOverhead =
+ // await registry.getTransmitCalldataPerSignerBytesOverhead()
+ cancellationDelay = (await registry.getCancellationDelay()).toNumber()
+
+ await registry.connect(owner).setConfigTypeSafe(...baseConfig)
+ await mgRegistry.connect(owner).setConfigTypeSafe(...baseConfig)
+ for (const reg of [registry, mgRegistry]) {
+ 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(
+ mock.address,
+ performGas,
+ await admin.getAddress(),
+ Trigger.CONDITION,
+ linkToken.address,
+ randomBytes,
+ '0x',
+ '0x',
+ )
+ upkeepId = await getUpkeepID(tx)
+
+ autoFunderUpkeep = await upkeepAutoFunderFactory
+ .connect(owner)
+ .deploy(linkToken.address, registry.address)
+ tx = await registry
+ .connect(owner)
+ .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(
+ ltUpkeep.address,
+ performGas,
+ await admin.getAddress(),
+ Trigger.LOG,
+ linkToken.address,
+ '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(
+ streamsLookupUpkeep.address,
+ performGas,
+ await admin.getAddress(),
+ Trigger.CONDITION,
+ linkToken.address,
+ '0x',
+ '0x',
+ '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(
+ mock.address,
+ performGas,
+ await admin.getAddress(),
+ Trigger.CONDITION,
+ linkToken.address,
+ '0x',
+ '0x',
+ '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(
+ mock.address,
+ performGas,
+ await admin.getAddress(),
+ Trigger.LOG,
+ linkToken.address,
+ '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(
+ mock.address,
+ performGas,
+ await admin.getAddress(),
+ Trigger.CONDITION,
+ linkToken.address,
+ '0x',
+ '0x',
+ '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 evmRevertCustomError(
+ getTransmitTx(registry, keeper1, [upkeepId]),
+ registry,
+ 'RegistryPaused',
+ )
+ })
+
+ it('reverts when called by non active transmitter', async () => {
+ await evmRevertCustomError(
+ getTransmitTx(registry, payee1, [upkeepId]),
+ registry,
+ '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,
+ linkUSD: 0,
+ upkeepIds,
+ gasLimits,
+ triggers,
+ performDatas,
+ })
+
+ await evmRevertCustomError(
+ getTransmitTxWithReport(registry, keeper1, report),
+ registry,
+ '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('performs even when the upkeep has insufficient funds and the upkeep pays out all the remaining balance', async () => {
+ // add very little fund to this upkeep
+ await registry.connect(admin).addFunds(upkeepId, BigNumber.from(10))
+ const tx = await getTransmitTx(registry, keeper1, [upkeepId])
+ const receipt = await tx.wait()
+ // the upkeep is underfunded in transmit but still performed
+ const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt)
+ assert.equal(upkeepPerformedLogs.length, 1)
+ const balance = (await registry.getUpkeep(upkeepId)).balance
+ assert.equal(balance.toNumber(), 0)
+ })
+
+ 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 bypassing reorg protection with reorgProtectionEnabled false config', async () => {
+ const tests: [string, BigNumber][] = [
+ ['conditional', upkeepId],
+ ['log-trigger', logUpkeepId],
+ ]
+ const newConfig = config
+ newConfig.reorgProtectionEnabled = false
+ await registry // used to test initial configurations
+ .connect(owner)
+ .setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ newConfig,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ )
+
+ 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 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 reorgProtectionEnabled config', async () => {
+ const newConfig = config
+ newConfig.reorgProtectionEnabled = false
+ await registry // used to test initial configurations
+ .connect(owner)
+ .setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ newConfig,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ )
+ 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 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 future block number is provided as trigger, irrespective of reorgProtectionEnabled config', async () => {
+ const newConfig = config
+ newConfig.reorgProtectionEnabled = false
+ await registry // used to test initial configurations
+ .connect(owner)
+ .setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ newConfig,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ )
+ 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 mock.setCanPerform(true)
+ await evmRevert(
+ getTransmitTx(registry, keeper1, [upkeepId], {
+ gasLimit: BigNumber.from(150000),
+ }),
+ )
+ })
+
+ it('executes the data passed to the registry', async () => {
+ await mock.setCanPerform(true)
+
+ const tx = await getTransmitTx(registry, keeper1, [upkeepId], {
+ performDatas: [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 == gasWei
+ const gasPrice = gasWei
+ 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 // 14657 gasUsed
+ const gasOverhead = upkeepPerformedLog.args.gasOverhead // 137230 gasOverhead
+ const totalPayment = upkeepPerformedLog.args.totalPayment
+
+ assert.equal(
+ linkForGas(
+ gasUsed,
+ gasOverhead,
+ BigNumber.from('1'), // Not the config multiplier, but the actual gas used
+ paymentPremiumPPB,
+ flatFeeMilliCents,
+ // pubdataGas.mul(gasPrice),
+ ).total.toString(),
+ totalPayment.toString(),
+ )
+
+ assert.equal(
+ linkForGas(
+ gasUsed,
+ gasOverhead,
+ BigNumber.from('1'), // Not the config multiplier, but the actual gas used
+ paymentPremiumPPB,
+ flatFeeMilliCents,
+ // pubdataGas.mul(gasPrice),
+ ).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,
+ flatFeeMilliCents,
+ // pubdataGas.mul(gasPrice),
+ ).total.toString(),
+ totalPayment.toString(),
+ )
+ })
+
+ 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
+ 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 evmRevertCustomError(
+ registry
+ .connect(keeper1)
+ .transmit(
+ [reportContext[0], reportContext[1], reportContext[2]],
+ report,
+ sigs.rs,
+ sigs.ss,
+ sigs.vs,
+ ),
+ registry,
+ '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 evmRevertCustomError(
+ registry
+ .connect(keeper1)
+ .transmit(
+ [reportContext[0], reportContext[1], reportContext[2]],
+ report,
+ sigs.rs,
+ sigs.ss,
+ sigs.vs,
+ ),
+ registry,
+ '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 evmRevertCustomError(
+ registry
+ .connect(keeper1)
+ .transmit(
+ [reportContext[0], reportContext[1], reportContext[2]],
+ report,
+ sigs.rs,
+ sigs.ss,
+ sigs.vs,
+ ),
+ registry,
+ '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 evmRevertCustomError(
+ registry
+ .connect(keeper1)
+ .transmit(
+ [reportContext[0], reportContext[1], reportContext[2]],
+ report,
+ sigs.rs,
+ sigs.ss,
+ sigs.vs,
+ ),
+ registry,
+ '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,
+ 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 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,
+ performDatas: [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,
+ baseConfig[6],
+ baseConfig[7],
+ )
+ 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)
+ }
+ },
+ )
+
+ // describe.only('Gas benchmarking conditional upkeeps [ @skip-coverage ]', function () {
+ // const fs = [1]
+ // 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()
+ //
+ // await registry
+ // .connect(admin)
+ // .setUpkeepGasLimit(upkeepId, performGas.mul(3))
+ //
+ // // 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 moduleBase.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)
+ // .add(500000) // the amount of pubdataGas used returned by mock gas bound caller
+ // const estimatedGasOverhead = registryConditionalOverhead
+ // .add(
+ // registryPerSignerGasOverhead.mul(
+ // BigNumber.from(newF + 1),
+ // ),
+ // )
+ // .add(chainModuleOverheads.chainModuleFixedOverhead)
+ // .add(65_400)
+ //
+ // 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(), // 179800
+ // ' charged overhead: ',
+ // chargedGasOverhead.toString(), // 180560
+ // ' actual overhead: ',
+ // actualGasOverhead.toString(), // 632949
+ // ' calculation margin over gasUsed: ',
+ // chargedGasOverhead.sub(actualGasOverhead).toString(), // 18456
+ // ' estimation margin over gasUsed: ',
+ // estimatedGasOverhead.sub(actualGasOverhead).toString(), // -27744
+ // ' upkeepGasUsed: ',
+ // upkeepGasUsed, // 988620
+ // ' receipt.gasUsed: ',
+ // receipt.gasUsed, // 1121569
+ // )
+ //
+ // // 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 // 180560
+ // .sub(actualGasOverhead) // 132940
+ // .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)
+ // .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.only('Gas benchmarking log upkeeps [ @skip-coverage ]', function () {
+ // const fs = [1]
+ // 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 moduleBase.getGasOverhead()
+ //
+ // const upkeepGasUsed = upkeepPerformedLog.args.gasUsed
+ // const chargedGasOverhead = upkeepPerformedLog.args.gasOverhead
+ // const actualGasOverhead = receipt.gasUsed
+ // .sub(upkeepGasUsed)
+ // .add(500000) // the amount of pubdataGas used returned by mock gas bound caller
+ // const estimatedGasOverhead = registryLogOverhead
+ // .add(registryPerSignerGasOverhead.mul(BigNumber.from(newF + 1)))
+ // .add(chainModuleOverheads.chainModuleFixedOverhead)
+ // .add(65_400)
+ //
+ // 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(),
+ // ' upkeepGasUsed: ',
+ // upkeepGasUsed,
+ // ' receipt.gasUsed: ',
+ // receipt.gasUsed,
+ // )
+ //
+ // 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 ' +
+ // 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 ' +
+ // estimatedGasOverhead
+ // .sub(actualGasOverhead)
+ // .sub(gasEstimationMargin)
+ // .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
+ }),
+ )
+
+ // cancel upkeeps so they will fail in the transmit process
+ // must call the cancel upkeep as the owner to avoid the CANCELLATION_DELAY
+ for (let ldx = 0; ldx < failingUpkeepIds.length; ldx++) {
+ await registry
+ .connect(owner)
+ .cancelUpkeep(failingUpkeepIds[ldx])
+ }
+
+ 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 cancelledUpkeepReportLogs =
+ parseCancelledUpkeepReportLogs(receipt)
+ // exactly numFailingUpkeeps Upkeep Performed should be emitted
+ assert.equal(
+ cancelledUpkeepReportLogs.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++) {
+ // CancelledUpkeep log should be emitted
+ const id = cancelledUpkeepReportLogs[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()
+
+ // cancel upkeeps so they will fail in the transmit process
+ // must call the cancel upkeep as the owner to avoid the CANCELLATION_DELAY
+ for (let ldx = 0; ldx < failingUpkeepIds.length; ldx++) {
+ await registry
+ .connect(owner)
+ .cancelUpkeep(failingUpkeepIds[ldx])
+ }
+
+ // 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,
+ )
+
+ let netGasUsedPlusChargedOverhead = BigNumber.from('0')
+ for (let i = 0; i < numPassingConditionalUpkeeps; i++) {
+ const gasUsed = upkeepPerformedLogs[i].args.gasUsed
+ const chargedGasOverhead =
+ upkeepPerformedLogs[i].args.gasOverhead
+
+ assert.isTrue(gasUsed.gt(BigNumber.from('0')))
+ assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0')))
+
+ // Overhead should be same for every upkeep
+ assert.isTrue(
+ chargedGasOverhead.eq(
+ upkeepPerformedLogs[0].args.gasOverhead,
+ ),
+ )
+ netGasUsedPlusChargedOverhead = netGasUsedPlusChargedOverhead
+ .add(gasUsed)
+ .add(chargedGasOverhead)
+ }
+
+ for (let i = 0; i < numPassingLogUpkeeps; i++) {
+ const gasUsed =
+ upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args
+ .gasUsed
+ const chargedGasOverhead =
+ upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args
+ .gasOverhead
+
+ assert.isTrue(gasUsed.gt(BigNumber.from('0')))
+ assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0')))
+
+ // Overhead should be same for every upkeep
+ assert.isTrue(
+ chargedGasOverhead.eq(
+ upkeepPerformedLogs[numPassingConditionalUpkeeps].args
+ .gasOverhead,
+ ),
+ )
+ netGasUsedPlusChargedOverhead = netGasUsedPlusChargedOverhead
+ .add(gasUsed)
+ .add(chargedGasOverhead)
+ }
+
+ console.log(
+ 'Gas Benchmarking - batching (passedConditionalUpkeeps: ',
+ numPassingConditionalUpkeeps,
+ 'passedLogUpkeeps:',
+ numPassingLogUpkeeps,
+ 'failedUpkeeps:',
+ numFailingUpkeeps,
+ '): ',
+ numPassingConditionalUpkeeps > 0
+ ? 'charged conditional overhead'
+ : '',
+ numPassingConditionalUpkeeps > 0
+ ? upkeepPerformedLogs[0].args.gasOverhead.toString()
+ : '',
+ numPassingLogUpkeeps > 0 ? 'charged log overhead' : '',
+ numPassingLogUpkeeps > 0
+ ? upkeepPerformedLogs[
+ numPassingConditionalUpkeeps
+ ].args.gasOverhead.toString()
+ : '',
+ ' margin over gasUsed',
+ netGasUsedPlusChargedOverhead.sub(receipt.gasUsed).toString(),
+ )
+
+ // The total gas charged should be greater than tx gas
+ assert.isTrue(
+ netGasUsedPlusChargedOverhead.gt(receipt.gasUsed),
+ 'Charged gas overhead is too low for batch upkeeps, 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(
+ mock.address,
+ performGas,
+ await admin.getAddress(),
+ Trigger.CONDITION,
+ linkToken.address,
+ '0x',
+ '0x',
+ '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),
+ })
+ })
+ },
+ )
+
+ 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,
+ performGas,
+ await admin.getAddress(),
+ Trigger.CONDITION,
+ linkToken.address,
+ '0x',
+ '0x',
+ '0x',
+ )
+
+ 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(
+ 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'))
+
+ 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())
+ })
+ })
+
+ 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 tx = await registry
+ .connect(owner)
+ .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)
+
+ // upkeep is underfunded by 1 wei
+ const minBalance1 = (await registry.getMinBalanceForUpkeep(upkeepID)).sub(
+ 1,
+ )
+ await registry.connect(owner).addFunds(upkeepID, minBalance1)
+
+ // upkeep check should return false, 2 should return true
+ const checkUpkeepResult = await registry
+ .connect(zeroAddress)
+ .callStatic['checkUpkeep(uint256)'](upkeepID)
+ assert.equal(checkUpkeepResult.upkeepNeeded, false)
+ assert.equal(
+ checkUpkeepResult.upkeepFailureReason,
+ UpkeepFailureReason.INSUFFICIENT_BALANCE,
+ )
+
+ // however upkeep should perform and pay all the remaining balance
+ let maxPerformData = '0x'
+ for (let i = 0; i < maxPerformDataSize.toNumber(); i++) {
+ maxPerformData += '11'
+ }
+
+ const tx2 = await getTransmitTx(registry, keeper1, [upkeepID], {
+ gasPrice: gasWei.mul(gasCeilingMultiplier),
+ performDatas: [maxPerformData],
+ })
+
+ const receipt = await tx2.wait()
+ const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt)
+ assert.equal(upkeepPerformedLogs.length, 1)
+ })
+ })
+
+ describe('#withdrawFunds', () => {
+ let upkeepId2: BigNumber
+
+ beforeEach(async () => {
+ const tx = await registry
+ .connect(owner)
+ .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'))
+ 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])
+ })
+
+ 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(registration.balance.toNumber(), 0)
+ })
+ })
+ })
+
+ describe('#simulatePerformUpkeep', () => {
+ it('reverts if called by non zero address', async () => {
+ await evmRevertCustomError(
+ registry
+ .connect(await owner.getAddress())
+ .callStatic.simulatePerformUpkeep(upkeepId, '0x'),
+ registry,
+ 'OnlySimulatedBackend',
+ )
+ })
+
+ it('reverts when registry is paused', async () => {
+ await registry.connect(owner).pause()
+ await evmRevertCustomError(
+ registry
+ .connect(zeroAddress)
+ .callStatic.simulatePerformUpkeep(upkeepId, '0x'),
+ registry,
+ '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) // 1,000,000
+
+ // increase upkeep gas limit because the mock gas bound caller will always return 500,000 as the L1 gas used
+ // that brings the total gas used to about 1M + 0.5M = 1.5M
+ await registry
+ .connect(admin)
+ .setUpkeepGasLimit(upkeepId, BigNumber.from(2000000))
+
+ const simulatePerformResult = await registry
+ .connect(zeroAddress)
+ .callStatic.simulatePerformUpkeep(upkeepId, '0x')
+
+ // Full execute gas should be used, with some performGasBuffer(1000)
+ assert.isTrue(
+ simulatePerformResult.gasUsed.gt(
+ performGas.add(pubdataGas).sub(BigNumber.from('1000')),
+ ),
+ )
+ })
+ })
+
+ describe('#checkUpkeep', () => {
+ it('reverts if called by non zero address', async () => {
+ await evmRevertCustomError(
+ registry
+ .connect(await owner.getAddress())
+ .callStatic['checkUpkeep(uint256)'](upkeepId),
+ registry,
+ '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.linkUSD.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.linkUSD.eq(linkUSD))
+ })
+
+ 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('#getMaxPaymentForGas', () => {
+ itMaybe('calculates the max fee appropriately in ZKSync', async () => {
+ await verifyMaxPayment(registry, moduleBase)
+ })
+
+ it('uses the fallback gas price if the feed has issues in ZKSync', async () => {
+ const chainModuleOverheads = await moduleBase.getGasOverhead()
+ const expectedFallbackMaxPayment = linkForGas(
+ performGas,
+ registryConditionalOverhead
+ .add(registryPerSignerGasOverhead.mul(f + 1))
+ .add(chainModuleOverheads.chainModuleFixedOverhead),
+ gasCeilingMultiplier.mul('2'), // fallbackGasPrice is 2x gas price
+ paymentPremiumPPB,
+ flatFeeMilliCents,
+ ).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(
+ upkeepId,
+ Trigger.CONDITION,
+ performGas,
+ linkToken.address,
+ )
+ ).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(
+ upkeepId,
+ Trigger.CONDITION,
+ performGas,
+ linkToken.address,
+ )
+ ).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(
+ upkeepId,
+ Trigger.CONDITION,
+ performGas,
+ linkToken.address,
+ )
+ ).toString(),
+ )
+ })
+
+ it('uses the fallback link price if the feed has issues in ZKSync', async () => {
+ const chainModuleOverheads = await moduleBase.getGasOverhead()
+ const expectedFallbackMaxPayment = linkForGas(
+ performGas,
+ registryConditionalOverhead
+ .add(registryPerSignerGasOverhead.mul(f + 1))
+ .add(chainModuleOverheads.chainModuleFixedOverhead),
+ gasCeilingMultiplier.mul('2'), // fallbackLinkPrice is 1/2 link price, so multiply by 2
+ paymentPremiumPPB,
+ flatFeeMilliCents,
+ ).total
+
+ // Stale feed
+ let roundId = 99
+ const answer = 100
+ let updatedAt = 946684800 // New Years 2000 🥳
+ let startedAt = 946684799
+ await linkUSDFeed
+ .connect(owner)
+ .updateRoundData(roundId, answer, updatedAt, startedAt)
+
+ assert.equal(
+ expectedFallbackMaxPayment.toString(),
+ (
+ await registry.getMaxPaymentForGas(
+ upkeepId,
+ Trigger.CONDITION,
+ performGas,
+ linkToken.address,
+ )
+ ).toString(),
+ )
+
+ // Negative feed price
+ roundId = 100
+ updatedAt = now()
+ startedAt = 946684799
+ await linkUSDFeed
+ .connect(owner)
+ .updateRoundData(roundId, -100, updatedAt, startedAt)
+
+ assert.equal(
+ expectedFallbackMaxPayment.toString(),
+ (
+ await registry.getMaxPaymentForGas(
+ upkeepId,
+ Trigger.CONDITION,
+ performGas,
+ linkToken.address,
+ )
+ ).toString(),
+ )
+
+ // Zero feed price
+ roundId = 101
+ updatedAt = now()
+ startedAt = 946684799
+ await linkUSDFeed
+ .connect(owner)
+ .updateRoundData(roundId, 0, updatedAt, startedAt)
+
+ assert.equal(
+ expectedFallbackMaxPayment.toString(),
+ (
+ await registry.getMaxPaymentForGas(
+ upkeepId,
+ Trigger.CONDITION,
+ performGas,
+ linkToken.address,
+ )
+ ).toString(),
+ )
+ })
+ })
+
+ describe('#typeAndVersion', () => {
+ it('uses the correct type and version', async () => {
+ const typeAndVersion = await registry.typeAndVersion()
+ assert.equal(typeAndVersion, 'AutomationRegistry 2.3.0')
+ })
+ })
+
+ describeMaybe('#setConfig - onchain', async () => {
+ const maxGas = BigNumber.from(6)
+ const staleness = BigNumber.from(4)
+ const ceiling = BigNumber.from(5)
+ 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 fbNativeEth = BigNumber.from(100)
+ const newTranscoder = randomAddress()
+ const newRegistrars = [randomAddress(), randomAddress()]
+ const upkeepManager = randomAddress()
+ const financeAdminAddress = randomAddress()
+
+ const newConfig: OnChainConfig = {
+ checkGasLimit: maxGas,
+ stalenessSeconds: staleness,
+ gasCeilingMultiplier: ceiling,
+ maxCheckDataSize: newMaxCheckDataSize,
+ maxPerformDataSize: newMaxPerformDataSize,
+ maxRevertDataSize: newMaxRevertDataSize,
+ maxPerformGas: newMaxPerformGas,
+ fallbackGasPrice: fbGasEth,
+ fallbackLinkPrice: fbLinkEth,
+ fallbackNativePrice: fbNativeEth,
+ transcoder: newTranscoder,
+ registrars: newRegistrars,
+ upkeepPrivilegeManager: upkeepManager,
+ chainModule: moduleBase.address,
+ reorgProtectionEnabled: true,
+ financeAdmin: financeAdminAddress,
+ }
+
+ it('reverts when called by anyone but the proposed owner', async () => {
+ await evmRevert(
+ registry
+ .connect(payee1)
+ .setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ newConfig,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ 'Only callable by owner',
+ )
+ })
+
+ it('reverts if signers or transmitters are the zero address', async () => {
+ await evmRevertCustomError(
+ registry
+ .connect(owner)
+ .setConfigTypeSafe(
+ [randomAddress(), randomAddress(), randomAddress(), zeroAddress],
+ [
+ randomAddress(),
+ randomAddress(),
+ randomAddress(),
+ randomAddress(),
+ ],
+ f,
+ newConfig,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ registry,
+ 'InvalidSigner',
+ )
+
+ await evmRevertCustomError(
+ registry
+ .connect(owner)
+ .setConfigTypeSafe(
+ [
+ randomAddress(),
+ randomAddress(),
+ randomAddress(),
+ randomAddress(),
+ ],
+ [randomAddress(), randomAddress(), randomAddress(), zeroAddress],
+ f,
+ newConfig,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ registry,
+ 'InvalidTransmitter',
+ )
+ })
+
+ it('updates the onchainConfig and configDigest', async () => {
+ const old = await registry.getState()
+ const oldConfig = await registry.getConfig()
+ const oldState = old.state
+ 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.stalenessSeconds, staleness.toNumber())
+ assert.equal(updatedConfig.gasCeilingMultiplier, ceiling.toNumber())
+ 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,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ 'Only callable by owner',
+ )
+ })
+
+ it('reverts if too many keeperAddresses set', async () => {
+ for (let i = 0; i < 40; i++) {
+ newKeepers.push(randomAddress())
+ }
+ await evmRevertCustomError(
+ registry
+ .connect(owner)
+ .setConfigTypeSafe(
+ newKeepers,
+ newKeepers,
+ f,
+ config,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ registry,
+ 'TooManyOracles',
+ )
+ })
+
+ it('reverts if f=0', async () => {
+ await evmRevertCustomError(
+ registry
+ .connect(owner)
+ .setConfigTypeSafe(
+ newKeepers,
+ newKeepers,
+ 0,
+ config,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ registry,
+ 'IncorrectNumberOfFaultyOracles',
+ )
+ })
+
+ it('reverts if signers != transmitters length', async () => {
+ const signers = [randomAddress()]
+ await evmRevertCustomError(
+ registry
+ .connect(owner)
+ .setConfigTypeSafe(
+ signers,
+ newKeepers,
+ f,
+ config,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ registry,
+ 'IncorrectNumberOfSigners',
+ )
+ })
+
+ it('reverts if signers <= 3f', async () => {
+ newKeepers.pop()
+ await evmRevertCustomError(
+ registry
+ .connect(owner)
+ .setConfigTypeSafe(
+ newKeepers,
+ newKeepers,
+ f,
+ config,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ registry,
+ '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 evmRevertCustomError(
+ registry
+ .connect(owner)
+ .setConfigTypeSafe(
+ newSigners,
+ newKeepers,
+ f,
+ config,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ registry,
+ '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 evmRevertCustomError(
+ registry
+ .connect(owner)
+ .setConfigTypeSafe(
+ newKeepers,
+ newTransmitters,
+ f,
+ config,
+ offchainVersion,
+ offchainBytes,
+ baseConfig[6],
+ baseConfig[7],
+ ),
+ registry,
+ '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)
+ 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)
+ 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)
+ 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)
+ 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('#cancelUpkeep', () => {
+ describe('when called by the admin', async () => {
+ 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 adds to reserve', async () => {
+ const newMinUpkeepSpend = toWei('10')
+ const financeAdminAddress = await financeAdmin.getAddress()
+
+ await registry.connect(owner).setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ {
+ checkGasLimit,
+ stalenessSeconds,
+ gasCeilingMultiplier,
+ maxCheckDataSize,
+ maxPerformDataSize,
+ maxRevertDataSize,
+ maxPerformGas,
+ fallbackGasPrice,
+ fallbackLinkPrice,
+ fallbackNativePrice,
+ transcoder: transcoder.address,
+ registrars: [],
+ upkeepPrivilegeManager: upkeepManager,
+ chainModule: moduleBase.address,
+ reorgProtectionEnabled: true,
+ financeAdmin: financeAdminAddress,
+ },
+ offchainVersion,
+ offchainBytes,
+ [linkToken.address],
+ [
+ {
+ gasFeePPB: paymentPremiumPPB,
+ flatFeeMilliCents,
+ priceFeed: linkUSDFeed.address,
+ fallbackPrice: fallbackLinkPrice,
+ minSpend: newMinUpkeepSpend,
+ decimals: 18,
+ },
+ ],
+ )
+
+ const payee1Before = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance
+ const ownerBefore = await registry.linkAvailableForPayment()
+
+ const amountSpent = toWei('100').sub(upkeepBefore)
+ const cancellationFee = newMinUpkeepSpend.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.linkAvailableForPayment()
+
+ // 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 newMinUpkeepSpend = toWei('1000')
+ const financeAdminAddress = await financeAdmin.getAddress()
+
+ await registry.connect(owner).setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ {
+ checkGasLimit,
+ stalenessSeconds,
+ gasCeilingMultiplier,
+ maxCheckDataSize,
+ maxPerformDataSize,
+ maxRevertDataSize,
+ maxPerformGas,
+ fallbackGasPrice,
+ fallbackLinkPrice,
+ fallbackNativePrice,
+ transcoder: transcoder.address,
+ registrars: [],
+ upkeepPrivilegeManager: upkeepManager,
+ chainModule: moduleBase.address,
+ reorgProtectionEnabled: true,
+ financeAdmin: financeAdminAddress,
+ },
+ offchainVersion,
+ offchainBytes,
+ [linkToken.address],
+ [
+ {
+ gasFeePPB: paymentPremiumPPB,
+ flatFeeMilliCents,
+ priceFeed: linkUSDFeed.address,
+ fallbackPrice: fallbackLinkPrice,
+ minSpend: newMinUpkeepSpend,
+ decimals: 18,
+ },
+ ],
+ )
+ const payee1Before = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance
+ const ownerBefore = await registry.linkAvailableForPayment()
+
+ await registry.connect(admin).cancelUpkeep(upkeepId)
+ const payee1After = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const ownerAfter = await registry.linkAvailableForPayment()
+ const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance
+
+ // all upkeep balance is deducted for cancellation fee
+ assert.equal(upkeepAfter.toNumber(), 0)
+ // 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 minUpkeepSpendDollars is spent', async () => {
+ // Very low min spend, already spent in one perform upkeep
+ const newMinUpkeepSpend = BigNumber.from(420)
+ const financeAdminAddress = await financeAdmin.getAddress()
+
+ await registry.connect(owner).setConfigTypeSafe(
+ signerAddresses,
+ keeperAddresses,
+ f,
+ {
+ checkGasLimit,
+ stalenessSeconds,
+ gasCeilingMultiplier,
+ maxCheckDataSize,
+ maxPerformDataSize,
+ maxRevertDataSize,
+ maxPerformGas,
+ fallbackGasPrice,
+ fallbackLinkPrice,
+ fallbackNativePrice,
+ transcoder: transcoder.address,
+ registrars: [],
+ upkeepPrivilegeManager: upkeepManager,
+ chainModule: moduleBase.address,
+ reorgProtectionEnabled: true,
+ financeAdmin: financeAdminAddress,
+ },
+ offchainVersion,
+ offchainBytes,
+ [linkToken.address],
+ [
+ {
+ gasFeePPB: paymentPremiumPPB,
+ flatFeeMilliCents,
+ priceFeed: linkUSDFeed.address,
+ fallbackPrice: fallbackLinkPrice,
+ minSpend: newMinUpkeepSpend,
+ decimals: 18,
+ },
+ ],
+ )
+ const payee1Before = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance
+ const ownerBefore = await registry.linkAvailableForPayment()
+
+ await registry.connect(admin).cancelUpkeep(upkeepId)
+ const payee1After = await linkToken.balanceOf(
+ await payee1.getAddress(),
+ )
+ const ownerAfter = await registry.linkAvailableForPayment()
+ 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 evmRevertCustomError(
+ registry
+ .connect(payee2)
+ .withdrawPayment(
+ await keeper1.getAddress(),
+ await nonkeeper.getAddress(),
+ ),
+ registry,
+ 'OnlyCallableByPayee',
+ )
+ })
+
+ it('reverts if called with the 0 address', async () => {
+ await evmRevertCustomError(
+ registry
+ .connect(payee2)
+ .withdrawPayment(await keeper1.getAddress(), zeroAddress),
+ registry,
+ '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.linkAvailableForPayment()
+
+ // 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.linkAvailableForPayment()
+
+ // 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('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(
+ 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)
+
+ 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,
+ baseConfig[6],
+ baseConfig[7],
+ )
+ 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,
+ 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/helpers.ts b/contracts/test/v0.8/automation/helpers.ts
index 5a95fb482cd..99f2cef9b87 100644
--- a/contracts/test/v0.8/automation/helpers.ts
+++ b/contracts/test/v0.8/automation/helpers.ts
@@ -9,6 +9,7 @@ import { IAutomationRegistryMaster__factory as IAutomationRegistryMasterFactory
import { assert } from 'chai'
import { FunctionFragment } from '@ethersproject/abi'
import { AutomationRegistryLogicC2_3__factory as AutomationRegistryLogicC2_3Factory } from '../../../typechain/factories/AutomationRegistryLogicC2_3__factory'
+import { ZKSyncAutomationRegistryLogicC2_3__factory as ZKSyncAutomationRegistryLogicC2_3Factory } from '../../../typechain/factories/ZKSyncAutomationRegistryLogicC2_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'
@@ -170,10 +171,10 @@ export const deployRegistry23 = async (
link: Parameters[0],
linkUSD: Parameters[1],
nativeUSD: Parameters[2],
- fastgas: Parameters[2],
+ fastgas: Parameters[3],
allowedReadOnlyAddress: Parameters<
AutomationRegistryLogicC2_3Factory['deploy']
- >[3],
+ >[5],
payoutMode: Parameters[6],
wrappedNativeTokenAddress: Parameters<
AutomationRegistryLogicC2_3Factory['deploy']
@@ -212,3 +213,51 @@ export const deployRegistry23 = async (
const master = await registryFactory.connect(from).deploy(logicA.address)
return IAutomationRegistryMaster2_3Factory.connect(master.address, from)
}
+
+export const deployZKSyncRegistry23 = async (
+ from: Signer,
+ link: Parameters[0],
+ linkUSD: Parameters[1],
+ nativeUSD: Parameters[2],
+ fastgas: Parameters[3],
+ allowedReadOnlyAddress: Parameters<
+ AutomationRegistryLogicC2_3Factory['deploy']
+ >[5],
+ payoutMode: Parameters[6],
+ wrappedNativeTokenAddress: Parameters<
+ ZKSyncAutomationRegistryLogicC2_3Factory['deploy']
+ >[7],
+): Promise => {
+ const logicCFactory = await ethers.getContractFactory(
+ 'ZKSyncAutomationRegistryLogicC2_3',
+ )
+ const logicBFactory = await ethers.getContractFactory(
+ 'ZKSyncAutomationRegistryLogicB2_3',
+ )
+ const logicAFactory = await ethers.getContractFactory(
+ 'ZKSyncAutomationRegistryLogicA2_3',
+ )
+ const registryFactory = await ethers.getContractFactory(
+ 'ZKSyncAutomationRegistry2_3',
+ )
+ const forwarderLogicFactory = await ethers.getContractFactory(
+ 'AutomationForwarderLogic',
+ )
+ const forwarderLogic = await forwarderLogicFactory.connect(from).deploy()
+ const logicC = await logicCFactory
+ .connect(from)
+ .deploy(
+ link,
+ linkUSD,
+ nativeUSD,
+ 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/core/bridges/cache.go b/core/bridges/cache.go
index 4b5a6552447..e97874a35e5 100644
--- a/core/bridges/cache.go
+++ b/core/bridges/cache.go
@@ -10,11 +10,9 @@ import (
"golang.org/x/exp/maps"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
-
- "github.com/smartcontractkit/chainlink/v2/core/logger"
- "github.com/smartcontractkit/chainlink/v2/core/utils"
)
const (
@@ -25,13 +23,11 @@ const (
type Cache struct {
// dependencies and configurations
ORM
- lggr logger.Logger
interval time.Duration
// service state
- services.StateMachine
- wg sync.WaitGroup
- chStop services.StopChan
+ services.Service
+ eng *services.Engine
// data state
bridgeTypesCache sync.Map
@@ -43,17 +39,20 @@ var _ ORM = (*Cache)(nil)
var _ services.Service = (*Cache)(nil)
func NewCache(base ORM, lggr logger.Logger, upsertInterval time.Duration) *Cache {
- return &Cache{
+ c := &Cache{
ORM: base,
- lggr: lggr.Named(CacheServiceName),
interval: upsertInterval,
- chStop: make(chan struct{}),
bridgeLastValueCache: make(map[string]BridgeResponse),
}
+ c.Service, c.eng = services.Config{
+ Name: CacheServiceName,
+ Start: c.start,
+ }.NewServiceEngine(lggr)
+ return c
}
func (c *Cache) WithDataSource(ds sqlutil.DataSource) ORM {
- return NewCache(NewORM(ds), c.lggr, c.interval)
+ return NewCache(NewORM(ds), c.eng, c.interval)
}
func (c *Cache) FindBridge(ctx context.Context, name BridgeName) (BridgeType, error) {
@@ -190,51 +189,17 @@ func (c *Cache) UpsertBridgeResponse(ctx context.Context, dotId string, specId i
return nil
}
-func (c *Cache) Start(_ context.Context) error {
- return c.StartOnce(CacheServiceName, func() error {
- c.wg.Add(1)
-
- go c.run()
-
- return nil
- })
-}
-
-func (c *Cache) Close() error {
- return c.StopOnce(CacheServiceName, func() error {
- close(c.chStop)
- c.wg.Wait()
-
- return nil
- })
-}
-
-func (c *Cache) HealthReport() map[string]error {
- return map[string]error{c.Name(): c.Healthy()}
-}
-
-func (c *Cache) Name() string {
- return c.lggr.Name()
-}
-
-func (c *Cache) run() {
- defer c.wg.Done()
-
- for {
- timer := time.NewTimer(utils.WithJitter(c.interval))
+func (c *Cache) start(_ context.Context) error {
+ ticker := services.TickerConfig{
+ Initial: c.interval,
+ JitterPct: services.DefaultJitter,
+ }.NewTicker(c.interval)
+ c.eng.GoTick(ticker, c.doBulkUpsert)
- select {
- case <-timer.C:
- c.doBulkUpsert()
- case <-c.chStop:
- timer.Stop()
-
- return
- }
- }
+ return nil
}
-func (c *Cache) doBulkUpsert() {
+func (c *Cache) doBulkUpsert(ctx context.Context) {
c.mu.RLock()
values := maps.Values(c.bridgeLastValueCache)
c.mu.RUnlock()
@@ -243,11 +208,8 @@ func (c *Cache) doBulkUpsert() {
return
}
- ctx, cancel := c.chStop.NewCtx()
- defer cancel()
-
if err := c.ORM.BulkUpsertBridgeResponse(ctx, values); err != nil {
- c.lggr.Warnf("bulk upsert of bridge responses failed: %s", err.Error())
+ c.eng.Warnf("bulk upsert of bridge responses failed: %s", err.Error())
}
}
diff --git a/core/capabilities/ccip/ccip_integration_tests/.gitignore b/core/capabilities/ccip/ccip_integration_tests/.gitignore
new file mode 100644
index 00000000000..567609b1234
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/.gitignore
@@ -0,0 +1 @@
+build/
diff --git a/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go b/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go
new file mode 100644
index 00000000000..e0de0b801d9
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go
@@ -0,0 +1,420 @@
+package ccipreader
+
+import (
+ "context"
+ "math/big"
+ "sort"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap/zapcore"
+ "golang.org/x/exp/maps"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_reader_tester"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
+
+ "github.com/smartcontractkit/chainlink-ccip/pkg/consts"
+ "github.com/smartcontractkit/chainlink-ccip/pkg/contractreader"
+ ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+ "github.com/smartcontractkit/chainlink-ccip/plugintypes"
+)
+
+const (
+ chainS1 = cciptypes.ChainSelector(1)
+ chainS2 = cciptypes.ChainSelector(2)
+ chainS3 = cciptypes.ChainSelector(3)
+ chainD = cciptypes.ChainSelector(4)
+)
+
+func TestCCIPReader_CommitReportsGTETimestamp(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ cfg := evmtypes.ChainReaderConfig{
+ Contracts: map[string]evmtypes.ChainContractReader{
+ consts.ContractNameOffRamp: {
+ ContractPollingFilter: evmtypes.ContractPollingFilter{
+ GenericEventNames: []string{consts.EventNameCommitReportAccepted},
+ },
+ ContractABI: ccip_reader_tester.CCIPReaderTesterABI,
+ Configs: map[string]*evmtypes.ChainReaderDefinition{
+ consts.EventNameCommitReportAccepted: {
+ ChainSpecificName: consts.EventNameCommitReportAccepted,
+ ReadType: evmtypes.Event,
+ },
+ },
+ },
+ },
+ }
+
+ s := testSetup(ctx, t, chainD, chainD, nil, cfg)
+
+ tokenA := common.HexToAddress("123")
+ const numReports = 5
+
+ for i := uint8(0); i < numReports; i++ {
+ _, err := s.contract.EmitCommitReportAccepted(s.auth, ccip_reader_tester.EVM2EVMMultiOffRampCommitReport{
+ PriceUpdates: ccip_reader_tester.InternalPriceUpdates{
+ TokenPriceUpdates: []ccip_reader_tester.InternalTokenPriceUpdate{
+ {
+ SourceToken: tokenA,
+ UsdPerToken: big.NewInt(1000),
+ },
+ },
+ GasPriceUpdates: []ccip_reader_tester.InternalGasPriceUpdate{
+ {
+ DestChainSelector: uint64(chainD),
+ UsdPerUnitGas: big.NewInt(90),
+ },
+ },
+ },
+ MerkleRoots: []ccip_reader_tester.EVM2EVMMultiOffRampMerkleRoot{
+ {
+ SourceChainSelector: uint64(chainS1),
+ Interval: ccip_reader_tester.EVM2EVMMultiOffRampInterval{
+ Min: 10,
+ Max: 20,
+ },
+ MerkleRoot: [32]byte{i + 1},
+ },
+ },
+ })
+ assert.NoError(t, err)
+ s.sb.Commit()
+ }
+
+ var reports []plugintypes.CommitPluginReportWithMeta
+ var err error
+ require.Eventually(t, func() bool {
+ reports, err = s.reader.CommitReportsGTETimestamp(
+ ctx,
+ chainD,
+ time.Unix(30, 0), // Skips first report, simulated backend report timestamps are [20, 30, 40, ...]
+ 10,
+ )
+ require.NoError(t, err)
+ return len(reports) == numReports-1
+ }, 10*time.Second, 50*time.Millisecond)
+
+ assert.Len(t, reports[0].Report.MerkleRoots, 1)
+ assert.Equal(t, chainS1, reports[0].Report.MerkleRoots[0].ChainSel)
+ assert.Equal(t, cciptypes.SeqNum(10), reports[0].Report.MerkleRoots[0].SeqNumsRange.Start())
+ assert.Equal(t, cciptypes.SeqNum(20), reports[0].Report.MerkleRoots[0].SeqNumsRange.End())
+ assert.Equal(t, "0x0200000000000000000000000000000000000000000000000000000000000000",
+ reports[0].Report.MerkleRoots[0].MerkleRoot.String())
+
+ assert.Equal(t, tokenA.String(), string(reports[0].Report.PriceUpdates.TokenPriceUpdates[0].TokenID))
+ assert.Equal(t, uint64(1000), reports[0].Report.PriceUpdates.TokenPriceUpdates[0].Price.Uint64())
+
+ assert.Equal(t, chainD, reports[0].Report.PriceUpdates.GasPriceUpdates[0].ChainSel)
+ assert.Equal(t, uint64(90), reports[0].Report.PriceUpdates.GasPriceUpdates[0].GasPrice.Uint64())
+}
+
+func TestCCIPReader_ExecutedMessageRanges(t *testing.T) {
+ ctx := testutils.Context(t)
+ cfg := evmtypes.ChainReaderConfig{
+ Contracts: map[string]evmtypes.ChainContractReader{
+ consts.ContractNameOffRamp: {
+ ContractPollingFilter: evmtypes.ContractPollingFilter{
+ GenericEventNames: []string{consts.EventNameExecutionStateChanged},
+ },
+ ContractABI: ccip_reader_tester.CCIPReaderTesterABI,
+ Configs: map[string]*evmtypes.ChainReaderDefinition{
+ consts.EventNameExecutionStateChanged: {
+ ChainSpecificName: consts.EventNameExecutionStateChanged,
+ ReadType: evmtypes.Event,
+ },
+ },
+ },
+ },
+ }
+
+ s := testSetup(ctx, t, chainD, chainD, nil, cfg)
+
+ _, err := s.contract.EmitExecutionStateChanged(
+ s.auth,
+ uint64(chainS1),
+ 14,
+ cciptypes.Bytes32{1, 0, 0, 1},
+ 1,
+ []byte{1, 2, 3, 4},
+ )
+ assert.NoError(t, err)
+ s.sb.Commit()
+
+ _, err = s.contract.EmitExecutionStateChanged(
+ s.auth,
+ uint64(chainS1),
+ 15,
+ cciptypes.Bytes32{1, 0, 0, 2},
+ 1,
+ []byte{1, 2, 3, 4, 5},
+ )
+ assert.NoError(t, err)
+ s.sb.Commit()
+
+ // Need to replay as sometimes the logs are not picked up by the log poller (?)
+ // Maybe another situation where chain reader doesn't register filters as expected.
+ require.NoError(t, s.lp.Replay(ctx, 1))
+
+ var executedRanges []cciptypes.SeqNumRange
+ require.Eventually(t, func() bool {
+ executedRanges, err = s.reader.ExecutedMessageRanges(
+ ctx,
+ chainS1,
+ chainD,
+ cciptypes.NewSeqNumRange(14, 15),
+ )
+ require.NoError(t, err)
+ return len(executedRanges) == 2
+ }, testutils.WaitTimeout(t), 50*time.Millisecond)
+
+ assert.Equal(t, cciptypes.SeqNum(14), executedRanges[0].Start())
+ assert.Equal(t, cciptypes.SeqNum(14), executedRanges[0].End())
+
+ assert.Equal(t, cciptypes.SeqNum(15), executedRanges[1].Start())
+ assert.Equal(t, cciptypes.SeqNum(15), executedRanges[1].End())
+}
+
+func TestCCIPReader_MsgsBetweenSeqNums(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ cfg := evmtypes.ChainReaderConfig{
+ Contracts: map[string]evmtypes.ChainContractReader{
+ consts.ContractNameOnRamp: {
+ ContractPollingFilter: evmtypes.ContractPollingFilter{
+ GenericEventNames: []string{consts.EventNameCCIPSendRequested},
+ },
+ ContractABI: ccip_reader_tester.CCIPReaderTesterABI,
+ Configs: map[string]*evmtypes.ChainReaderDefinition{
+ consts.EventNameCCIPSendRequested: {
+ ChainSpecificName: consts.EventNameCCIPSendRequested,
+ ReadType: evmtypes.Event,
+ },
+ },
+ },
+ },
+ }
+
+ s := testSetup(ctx, t, chainS1, chainD, nil, cfg)
+
+ _, err := s.contract.EmitCCIPSendRequested(s.auth, uint64(chainD), ccip_reader_tester.InternalEVM2AnyRampMessage{
+ Header: ccip_reader_tester.InternalRampMessageHeader{
+ MessageId: [32]byte{1, 0, 0, 0, 0},
+ SourceChainSelector: uint64(chainS1),
+ DestChainSelector: uint64(chainD),
+ SequenceNumber: 10,
+ },
+ Sender: utils.RandomAddress(),
+ Data: make([]byte, 0),
+ Receiver: utils.RandomAddress().Bytes(),
+ ExtraArgs: make([]byte, 0),
+ FeeToken: utils.RandomAddress(),
+ FeeTokenAmount: big.NewInt(0),
+ TokenAmounts: make([]ccip_reader_tester.InternalRampTokenAmount, 0),
+ })
+ assert.NoError(t, err)
+
+ _, err = s.contract.EmitCCIPSendRequested(s.auth, uint64(chainD), ccip_reader_tester.InternalEVM2AnyRampMessage{
+ Header: ccip_reader_tester.InternalRampMessageHeader{
+ MessageId: [32]byte{1, 0, 0, 0, 1},
+ SourceChainSelector: uint64(chainS1),
+ DestChainSelector: uint64(chainD),
+ SequenceNumber: 15,
+ },
+ Sender: utils.RandomAddress(),
+ Data: make([]byte, 0),
+ Receiver: utils.RandomAddress().Bytes(),
+ ExtraArgs: make([]byte, 0),
+ FeeToken: utils.RandomAddress(),
+ FeeTokenAmount: big.NewInt(0),
+ TokenAmounts: make([]ccip_reader_tester.InternalRampTokenAmount, 0),
+ })
+ assert.NoError(t, err)
+
+ s.sb.Commit()
+
+ // Need to replay as sometimes the logs are not picked up by the log poller (?)
+ // Maybe another situation where chain reader doesn't register filters as expected.
+ require.NoError(t, s.lp.Replay(ctx, 1))
+
+ var msgs []cciptypes.Message
+ require.Eventually(t, func() bool {
+ msgs, err = s.reader.MsgsBetweenSeqNums(
+ ctx,
+ chainS1,
+ cciptypes.NewSeqNumRange(5, 20),
+ )
+ require.NoError(t, err)
+ return len(msgs) == 2
+ }, 10*time.Second, 100*time.Millisecond)
+
+ require.Len(t, msgs, 2)
+ // sort to ensure ascending order of sequence numbers.
+ sort.Slice(msgs, func(i, j int) bool {
+ return msgs[i].Header.SequenceNumber < msgs[j].Header.SequenceNumber
+ })
+ require.Equal(t, cciptypes.SeqNum(10), msgs[0].Header.SequenceNumber)
+ require.Equal(t, cciptypes.SeqNum(15), msgs[1].Header.SequenceNumber)
+ for _, msg := range msgs {
+ require.Equal(t, chainS1, msg.Header.SourceChainSelector)
+ require.Equal(t, chainD, msg.Header.DestChainSelector)
+ }
+}
+
+func TestCCIPReader_NextSeqNum(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ onChainSeqNums := map[cciptypes.ChainSelector]cciptypes.SeqNum{
+ chainS1: 10,
+ chainS2: 20,
+ chainS3: 30,
+ }
+
+ cfg := evmtypes.ChainReaderConfig{
+ Contracts: map[string]evmtypes.ChainContractReader{
+ consts.ContractNameOffRamp: {
+ ContractABI: ccip_reader_tester.CCIPReaderTesterABI,
+ Configs: map[string]*evmtypes.ChainReaderDefinition{
+ consts.MethodNameGetSourceChainConfig: {
+ ChainSpecificName: "getSourceChainConfig",
+ ReadType: evmtypes.Method,
+ },
+ },
+ },
+ },
+ }
+
+ s := testSetup(ctx, t, chainD, chainD, onChainSeqNums, cfg)
+
+ seqNums, err := s.reader.NextSeqNum(ctx, []cciptypes.ChainSelector{chainS1, chainS2, chainS3})
+ assert.NoError(t, err)
+ assert.Len(t, seqNums, 3)
+ assert.Equal(t, cciptypes.SeqNum(10), seqNums[0])
+ assert.Equal(t, cciptypes.SeqNum(20), seqNums[1])
+ assert.Equal(t, cciptypes.SeqNum(30), seqNums[2])
+}
+
+func testSetup(ctx context.Context, t *testing.T, readerChain, destChain cciptypes.ChainSelector, onChainSeqNums map[cciptypes.ChainSelector]cciptypes.SeqNum, cfg evmtypes.ChainReaderConfig) *testSetupData {
+ const chainID = 1337
+
+ // Generate a new key pair for the simulated account
+ privateKey, err := crypto.GenerateKey()
+ assert.NoError(t, err)
+ // Set up the genesis account with balance
+ blnc, ok := big.NewInt(0).SetString("999999999999999999999999999999999999", 10)
+ assert.True(t, ok)
+ alloc := map[common.Address]core.GenesisAccount{crypto.PubkeyToAddress(privateKey.PublicKey): {Balance: blnc}}
+ simulatedBackend := backends.NewSimulatedBackend(alloc, 0)
+ // Create a transactor
+
+ auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(chainID))
+ assert.NoError(t, err)
+ auth.GasLimit = uint64(0)
+
+ // Deploy the contract
+ address, _, _, err := ccip_reader_tester.DeployCCIPReaderTester(auth, simulatedBackend)
+ assert.NoError(t, err)
+ simulatedBackend.Commit()
+
+ // Setup contract client
+ contract, err := ccip_reader_tester.NewCCIPReaderTester(address, simulatedBackend)
+ assert.NoError(t, err)
+
+ lggr := logger.TestLogger(t)
+ lggr.SetLogLevel(zapcore.ErrorLevel)
+ db := pgtest.NewSqlxDB(t)
+ lpOpts := logpoller.Opts{
+ PollPeriod: time.Millisecond,
+ FinalityDepth: 0,
+ BackfillBatchSize: 10,
+ RpcBatchSize: 10,
+ KeepFinalizedBlocksDepth: 100000,
+ }
+ cl := client.NewSimulatedBackendClient(t, simulatedBackend, big.NewInt(0).SetUint64(uint64(readerChain)))
+ headTracker := headtracker.NewSimulatedHeadTracker(cl, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ lp := logpoller.NewLogPoller(logpoller.NewORM(big.NewInt(0).SetUint64(uint64(readerChain)), db, lggr),
+ cl,
+ lggr,
+ headTracker,
+ lpOpts,
+ )
+ assert.NoError(t, lp.Start(ctx))
+
+ for sourceChain, seqNum := range onChainSeqNums {
+ _, err1 := contract.SetSourceChainConfig(auth, uint64(sourceChain), ccip_reader_tester.EVM2EVMMultiOffRampSourceChainConfig{
+ IsEnabled: true,
+ MinSeqNr: uint64(seqNum),
+ })
+ assert.NoError(t, err1)
+ simulatedBackend.Commit()
+ scc, err1 := contract.GetSourceChainConfig(&bind.CallOpts{Context: ctx}, uint64(sourceChain))
+ assert.NoError(t, err1)
+ assert.Equal(t, seqNum, cciptypes.SeqNum(scc.MinSeqNr))
+ }
+
+ contractNames := maps.Keys(cfg.Contracts)
+ assert.Len(t, contractNames, 1, "test setup assumes there is only one contract")
+
+ cr, err := evm.NewChainReaderService(ctx, lggr, lp, headTracker, cl, cfg)
+ require.NoError(t, err)
+
+ extendedCr := contractreader.NewExtendedContractReader(cr)
+ err = extendedCr.Bind(ctx, []types.BoundContract{
+ {
+ Address: address.String(),
+ Name: contractNames[0],
+ },
+ })
+ require.NoError(t, err)
+
+ err = cr.Start(ctx)
+ require.NoError(t, err)
+
+ contractReaders := map[cciptypes.ChainSelector]contractreader.Extended{readerChain: extendedCr}
+ contractWriters := make(map[cciptypes.ChainSelector]types.ChainWriter)
+ reader := ccipreaderpkg.NewCCIPReaderWithExtendedContractReaders(lggr, contractReaders, contractWriters, destChain)
+
+ t.Cleanup(func() {
+ require.NoError(t, cr.Close())
+ require.NoError(t, lp.Close())
+ require.NoError(t, db.Close())
+ })
+
+ return &testSetupData{
+ contractAddr: address,
+ contract: contract,
+ sb: simulatedBackend,
+ auth: auth,
+ lp: lp,
+ cl: cl,
+ reader: reader,
+ }
+}
+
+type testSetupData struct {
+ contractAddr common.Address
+ contract *ccip_reader_tester.CCIPReaderTester
+ sb *backends.SimulatedBackend
+ auth *bind.TransactOpts
+ lp logpoller.LogPoller
+ cl client.Client
+ reader ccipreaderpkg.CCIPReader
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/chainreader/Makefile b/core/capabilities/ccip/ccip_integration_tests/chainreader/Makefile
new file mode 100644
index 00000000000..e9c88564e69
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/chainreader/Makefile
@@ -0,0 +1,12 @@
+
+# IMPORTANT: If you encounter any issues try using solc 0.8.18 and abigen 1.14.5
+
+.PHONY: build
+build:
+ rm -rf build/
+ solc --evm-version paris --abi --bin mycontract.sol -o build
+ abigen --abi build/mycontract_sol_SimpleContract.abi --bin build/mycontract_sol_SimpleContract.bin --pkg=chainreader --out=mycontract.go
+
+.PHONY: test
+test: build
+ go test -v --tags "playground" ./...
diff --git a/core/capabilities/ccip/ccip_integration_tests/chainreader/chainreader_test.go b/core/capabilities/ccip/ccip_integration_tests/chainreader/chainreader_test.go
new file mode 100644
index 00000000000..52a3de0dae9
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/chainreader/chainreader_test.go
@@ -0,0 +1,273 @@
+//go:build playground
+// +build playground
+
+package chainreader
+
+import (
+ "context"
+ _ "embed"
+ "math/big"
+ "strconv"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/stretchr/testify/assert"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/codec"
+ types2 "github.com/smartcontractkit/chainlink-common/pkg/types"
+ query2 "github.com/smartcontractkit/chainlink-common/pkg/types/query"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ logger2 "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
+)
+
+const chainID = 1337
+
+type testSetupData struct {
+ contractAddr common.Address
+ contract *Chainreader
+ sb *backends.SimulatedBackend
+ auth *bind.TransactOpts
+}
+
+func TestChainReader(t *testing.T) {
+ ctx := testutils.Context(t)
+ lggr := logger2.NullLogger
+ d := testSetup(t, ctx)
+
+ db := pgtest.NewSqlxDB(t)
+ lpOpts := logpoller.Opts{
+ PollPeriod: time.Millisecond,
+ FinalityDepth: 0,
+ BackfillBatchSize: 10,
+ RpcBatchSize: 10,
+ KeepFinalizedBlocksDepth: 100000,
+ }
+ cl := client.NewSimulatedBackendClient(t, d.sb, big.NewInt(chainID))
+ headTracker := headtracker.NewSimulatedHeadTracker(cl, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ lp := logpoller.NewLogPoller(logpoller.NewORM(big.NewInt(chainID), db, lggr),
+ cl,
+ lggr,
+ headTracker,
+ lpOpts,
+ )
+ assert.NoError(t, lp.Start(ctx))
+
+ const (
+ ContractNameAlias = "myCoolContract"
+
+ FnAliasGetCount = "myCoolFunction"
+ FnGetCount = "getEventCount"
+
+ FnAliasGetNumbers = "GetNumbers"
+ FnGetNumbers = "getNumbers"
+
+ FnAliasGetPerson = "GetPerson"
+ FnGetPerson = "getPerson"
+
+ EventNameAlias = "myCoolEvent"
+ EventName = "SimpleEvent"
+ )
+
+ // Initialize chainReader
+ cfg := evmtypes.ChainReaderConfig{
+ Contracts: map[string]evmtypes.ChainContractReader{
+ ContractNameAlias: {
+ ContractPollingFilter: evmtypes.ContractPollingFilter{
+ GenericEventNames: []string{EventNameAlias},
+ },
+ ContractABI: ChainreaderMetaData.ABI,
+ Configs: map[string]*evmtypes.ChainReaderDefinition{
+ EventNameAlias: {
+ ChainSpecificName: EventName,
+ ReadType: evmtypes.Event,
+ ConfidenceConfirmations: map[string]int{"0.0": 0, "1.0": 0},
+ },
+ FnAliasGetCount: {
+ ChainSpecificName: FnGetCount,
+ },
+ FnAliasGetNumbers: {
+ ChainSpecificName: FnGetNumbers,
+ OutputModifications: codec.ModifiersConfig{},
+ },
+ FnAliasGetPerson: {
+ ChainSpecificName: FnGetPerson,
+ OutputModifications: codec.ModifiersConfig{
+ &codec.RenameModifierConfig{
+ Fields: map[string]string{"Name": "NameField"}, // solidity name -> go struct name
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ cr, err := evm.NewChainReaderService(ctx, lggr, lp, cl, cfg)
+ assert.NoError(t, err)
+ err = cr.Bind(ctx, []types2.BoundContract{
+ {
+ Address: d.contractAddr.String(),
+ Name: ContractNameAlias,
+ Pending: false,
+ },
+ })
+ assert.NoError(t, err)
+
+ err = cr.Start(ctx)
+ assert.NoError(t, err)
+ for {
+ if err := cr.Ready(); err == nil {
+ break
+ }
+ }
+
+ emitEvents(t, d, ctx) // Calls the contract to emit events
+
+ // (hack) Sometimes LP logs are missing, commit several times and wait few seconds to make it work.
+ for i := 0; i < 100; i++ {
+ d.sb.Commit()
+ }
+ time.Sleep(5 * time.Second)
+
+ t.Run("simple contract read", func(t *testing.T) {
+ var cnt big.Int
+ err = cr.GetLatestValue(ctx, ContractNameAlias, FnAliasGetCount, map[string]interface{}{}, &cnt)
+ assert.NoError(t, err)
+ assert.Equal(t, int64(10), cnt.Int64())
+ })
+
+ t.Run("read array", func(t *testing.T) {
+ var nums []big.Int
+ err = cr.GetLatestValue(ctx, ContractNameAlias, FnAliasGetNumbers, map[string]interface{}{}, &nums)
+ assert.NoError(t, err)
+ assert.Len(t, nums, 10)
+ for i := 1; i <= 10; i++ {
+ assert.Equal(t, int64(i), nums[i-1].Int64())
+ }
+ })
+
+ t.Run("read struct", func(t *testing.T) {
+ person := struct {
+ NameField string
+ Age *big.Int // WARN: specifying a wrong data type e.g. int instead of *big.Int fails silently with a default value of 0
+ }{}
+ err = cr.GetLatestValue(ctx, ContractNameAlias, FnAliasGetPerson, map[string]interface{}{}, &person)
+ assert.Equal(t, "Dim", person.NameField)
+ assert.Equal(t, int64(18), person.Age.Int64())
+ })
+
+ t.Run("read events", func(t *testing.T) {
+ var myDataType *big.Int
+ seq, err := cr.QueryKey(
+ ctx,
+ ContractNameAlias,
+ query2.KeyFilter{
+ Key: EventNameAlias,
+ Expressions: []query2.Expression{},
+ },
+ query2.LimitAndSort{},
+ myDataType,
+ )
+ assert.NoError(t, err)
+ assert.Equal(t, 10, len(seq), "expected 10 events from chain reader")
+ for _, v := range seq {
+ // TODO: for some reason log poller does not populate event data
+ blockNum, err := strconv.ParseUint(v.Identifier, 10, 64)
+ assert.NoError(t, err)
+ assert.Positive(t, blockNum)
+ t.Logf("(chain reader) got event: (data=%v) (hash=%x)", v.Data, v.Hash)
+ }
+ })
+}
+
+func testSetup(t *testing.T, ctx context.Context) *testSetupData {
+ // Generate a new key pair for the simulated account
+ privateKey, err := crypto.GenerateKey()
+ assert.NoError(t, err)
+ // Set up the genesis account with balance
+ blnc, ok := big.NewInt(0).SetString("999999999999999999999999999999999999", 10)
+ assert.True(t, ok)
+ alloc := map[common.Address]core.GenesisAccount{crypto.PubkeyToAddress(privateKey.PublicKey): {Balance: blnc}}
+ simulatedBackend := backends.NewSimulatedBackend(alloc, 0)
+ // Create a transactor
+
+ auth, err := bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(chainID))
+ assert.NoError(t, err)
+ auth.GasLimit = uint64(0)
+
+ // Deploy the contract
+ address, tx, _, err := DeployChainreader(auth, simulatedBackend)
+ assert.NoError(t, err)
+ simulatedBackend.Commit()
+ t.Logf("contract deployed: addr=%s tx=%s", address.Hex(), tx.Hash())
+
+ // Setup contract client
+ contract, err := NewChainreader(address, simulatedBackend)
+ assert.NoError(t, err)
+
+ return &testSetupData{
+ contractAddr: address,
+ contract: contract,
+ sb: simulatedBackend,
+ auth: auth,
+ }
+}
+
+func emitEvents(t *testing.T, d *testSetupData, ctx context.Context) {
+ var wg sync.WaitGroup
+ wg.Add(2)
+
+ // Start emitting events
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 10; i++ {
+ _, err := d.contract.EmitEvent(d.auth)
+ assert.NoError(t, err)
+ d.sb.Commit()
+ }
+ }()
+
+ // Listen events using go-ethereum lib
+ go func() {
+ query := ethereum.FilterQuery{
+ FromBlock: big.NewInt(0),
+ Addresses: []common.Address{d.contractAddr},
+ }
+ logs := make(chan types.Log)
+ sub, err := d.sb.SubscribeFilterLogs(ctx, query, logs)
+ assert.NoError(t, err)
+
+ numLogs := 0
+ defer wg.Done()
+ for {
+ // Wait for the events
+ select {
+ case err := <-sub.Err():
+ assert.NoError(t, err, "got an unexpected error")
+ case vLog := <-logs:
+ assert.Equal(t, d.contractAddr, vLog.Address, "got an unexpected address")
+ t.Logf("(geth) got new log (cnt=%d) (data=%x) (topics=%s)", numLogs, vLog.Data, vLog.Topics)
+ numLogs++
+ if numLogs == 10 {
+ return
+ }
+ }
+ }
+ }()
+
+ wg.Wait() // wait for all the events to be consumed
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/chainreader/mycontract.go b/core/capabilities/ccip/ccip_integration_tests/chainreader/mycontract.go
new file mode 100644
index 00000000000..c7d480eed46
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/chainreader/mycontract.go
@@ -0,0 +1,519 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package chainreader
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+// SimpleContractPerson is an auto generated low-level Go binding around an user-defined struct.
+type SimpleContractPerson struct {
+ Name string
+ Age *big.Int
+}
+
+// ChainreaderMetaData contains all meta data concerning the Chainreader contract.
+var ChainreaderMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"SimpleEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"emitEvent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"eventCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEventCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNumbers\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPerson\",\"outputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"age\",\"type\":\"uint256\"}],\"internalType\":\"structSimpleContract.Person\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"numbers\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b506105a1806100206000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c806371be2e4a146100675780637b0cb8391461008557806389f915f61461008f5780638ec4dc95146100ad578063d39fa233146100cb578063d9e48f5c146100fb575b600080fd5b61006f610119565b60405161007c91906102ac565b60405180910390f35b61008d61011f565b005b61009761019c565b6040516100a49190610385565b60405180910390f35b6100b56101f4565b6040516100c29190610474565b60405180910390f35b6100e560048036038101906100e091906104c7565b61024c565b6040516100f291906102ac565b60405180910390f35b610103610270565b60405161011091906102ac565b60405180910390f35b60005481565b60008081548092919061013190610523565b9190505550600160005490806001815401808255809150506001900390600052602060002001600090919091909150557f12d199749b3f4c44df8d9386c63d725b7756ec47204f3aa0bf05ea832f89effb60005460405161019291906102ac565b60405180910390a1565b606060018054806020026020016040519081016040528092919081815260200182805480156101ea57602002820191906000526020600020905b8154815260200190600101908083116101d6575b5050505050905090565b6101fc610279565b60405180604001604052806040518060400160405280600381526020017f44696d000000000000000000000000000000000000000000000000000000000081525081526020016012815250905090565b6001818154811061025c57600080fd5b906000526020600020016000915090505481565b60008054905090565b604051806040016040528060608152602001600081525090565b6000819050919050565b6102a681610293565b82525050565b60006020820190506102c1600083018461029d565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6102fc81610293565b82525050565b600061030e83836102f3565b60208301905092915050565b6000602082019050919050565b6000610332826102c7565b61033c81856102d2565b9350610347836102e3565b8060005b8381101561037857815161035f8882610302565b975061036a8361031a565b92505060018101905061034b565b5085935050505092915050565b6000602082019050818103600083015261039f8184610327565b905092915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156103e15780820151818401526020810190506103c6565b60008484015250505050565b6000601f19601f8301169050919050565b6000610409826103a7565b61041381856103b2565b93506104238185602086016103c3565b61042c816103ed565b840191505092915050565b6000604083016000830151848203600086015261045482826103fe565b915050602083015161046960208601826102f3565b508091505092915050565b6000602082019050818103600083015261048e8184610437565b905092915050565b600080fd5b6104a481610293565b81146104af57600080fd5b50565b6000813590506104c18161049b565b92915050565b6000602082840312156104dd576104dc610496565b5b60006104eb848285016104b2565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061052e82610293565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036105605761055f6104f4565b5b60018201905091905056fea2646970667358221220f7986dc9efbc0d9ef58e2925ffddc62ea13a6bab8b3a2c03ad2d85d50653129664736f6c63430008120033",
+}
+
+// ChainreaderABI is the input ABI used to generate the binding from.
+// Deprecated: Use ChainreaderMetaData.ABI instead.
+var ChainreaderABI = ChainreaderMetaData.ABI
+
+// ChainreaderBin is the compiled bytecode used for deploying new contracts.
+// Deprecated: Use ChainreaderMetaData.Bin instead.
+var ChainreaderBin = ChainreaderMetaData.Bin
+
+// DeployChainreader deploys a new Ethereum contract, binding an instance of Chainreader to it.
+func DeployChainreader(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Chainreader, error) {
+ parsed, err := ChainreaderMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ChainreaderBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &Chainreader{ChainreaderCaller: ChainreaderCaller{contract: contract}, ChainreaderTransactor: ChainreaderTransactor{contract: contract}, ChainreaderFilterer: ChainreaderFilterer{contract: contract}}, nil
+}
+
+// Chainreader is an auto generated Go binding around an Ethereum contract.
+type Chainreader struct {
+ ChainreaderCaller // Read-only binding to the contract
+ ChainreaderTransactor // Write-only binding to the contract
+ ChainreaderFilterer // Log filterer for contract events
+}
+
+// ChainreaderCaller is an auto generated read-only Go binding around an Ethereum contract.
+type ChainreaderCaller struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ChainreaderTransactor is an auto generated write-only Go binding around an Ethereum contract.
+type ChainreaderTransactor struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ChainreaderFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
+type ChainreaderFilterer struct {
+ contract *bind.BoundContract // Generic contract wrapper for the low level calls
+}
+
+// ChainreaderSession is an auto generated Go binding around an Ethereum contract,
+// with pre-set call and transact options.
+type ChainreaderSession struct {
+ Contract *Chainreader // Generic contract binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ChainreaderCallerSession is an auto generated read-only Go binding around an Ethereum contract,
+// with pre-set call options.
+type ChainreaderCallerSession struct {
+ Contract *ChainreaderCaller // Generic contract caller binding to set the session for
+ CallOpts bind.CallOpts // Call options to use throughout this session
+}
+
+// ChainreaderTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
+// with pre-set transact options.
+type ChainreaderTransactorSession struct {
+ Contract *ChainreaderTransactor // Generic contract transactor binding to set the session for
+ TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
+}
+
+// ChainreaderRaw is an auto generated low-level Go binding around an Ethereum contract.
+type ChainreaderRaw struct {
+ Contract *Chainreader // Generic contract binding to access the raw methods on
+}
+
+// ChainreaderCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
+type ChainreaderCallerRaw struct {
+ Contract *ChainreaderCaller // Generic read-only contract binding to access the raw methods on
+}
+
+// ChainreaderTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
+type ChainreaderTransactorRaw struct {
+ Contract *ChainreaderTransactor // Generic write-only contract binding to access the raw methods on
+}
+
+// NewChainreader creates a new instance of Chainreader, bound to a specific deployed contract.
+func NewChainreader(address common.Address, backend bind.ContractBackend) (*Chainreader, error) {
+ contract, err := bindChainreader(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &Chainreader{ChainreaderCaller: ChainreaderCaller{contract: contract}, ChainreaderTransactor: ChainreaderTransactor{contract: contract}, ChainreaderFilterer: ChainreaderFilterer{contract: contract}}, nil
+}
+
+// NewChainreaderCaller creates a new read-only instance of Chainreader, bound to a specific deployed contract.
+func NewChainreaderCaller(address common.Address, caller bind.ContractCaller) (*ChainreaderCaller, error) {
+ contract, err := bindChainreader(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ChainreaderCaller{contract: contract}, nil
+}
+
+// NewChainreaderTransactor creates a new write-only instance of Chainreader, bound to a specific deployed contract.
+func NewChainreaderTransactor(address common.Address, transactor bind.ContractTransactor) (*ChainreaderTransactor, error) {
+ contract, err := bindChainreader(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ChainreaderTransactor{contract: contract}, nil
+}
+
+// NewChainreaderFilterer creates a new log filterer instance of Chainreader, bound to a specific deployed contract.
+func NewChainreaderFilterer(address common.Address, filterer bind.ContractFilterer) (*ChainreaderFilterer, error) {
+ contract, err := bindChainreader(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ChainreaderFilterer{contract: contract}, nil
+}
+
+// bindChainreader binds a generic wrapper to an already deployed contract.
+func bindChainreader(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ChainreaderMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Chainreader *ChainreaderRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _Chainreader.Contract.ChainreaderCaller.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Chainreader *ChainreaderRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Chainreader.Contract.ChainreaderTransactor.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Chainreader *ChainreaderRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Chainreader.Contract.ChainreaderTransactor.contract.Transact(opts, method, params...)
+}
+
+// Call invokes the (constant) contract method with params as input values and
+// sets the output to result. The result type might be a single field for simple
+// returns, a slice of interfaces for anonymous returns and a struct for named
+// returns.
+func (_Chainreader *ChainreaderCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _Chainreader.Contract.contract.Call(opts, result, method, params...)
+}
+
+// Transfer initiates a plain transaction to move funds to the contract, calling
+// its default method if one is available.
+func (_Chainreader *ChainreaderTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Chainreader.Contract.contract.Transfer(opts)
+}
+
+// Transact invokes the (paid) contract method with params as input values.
+func (_Chainreader *ChainreaderTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Chainreader.Contract.contract.Transact(opts, method, params...)
+}
+
+// EventCount is a free data retrieval call binding the contract method 0x71be2e4a.
+//
+// Solidity: function eventCount() view returns(uint256)
+func (_Chainreader *ChainreaderCaller) EventCount(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _Chainreader.contract.Call(opts, &out, "eventCount")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+// EventCount is a free data retrieval call binding the contract method 0x71be2e4a.
+//
+// Solidity: function eventCount() view returns(uint256)
+func (_Chainreader *ChainreaderSession) EventCount() (*big.Int, error) {
+ return _Chainreader.Contract.EventCount(&_Chainreader.CallOpts)
+}
+
+// EventCount is a free data retrieval call binding the contract method 0x71be2e4a.
+//
+// Solidity: function eventCount() view returns(uint256)
+func (_Chainreader *ChainreaderCallerSession) EventCount() (*big.Int, error) {
+ return _Chainreader.Contract.EventCount(&_Chainreader.CallOpts)
+}
+
+// GetEventCount is a free data retrieval call binding the contract method 0xd9e48f5c.
+//
+// Solidity: function getEventCount() view returns(uint256)
+func (_Chainreader *ChainreaderCaller) GetEventCount(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _Chainreader.contract.Call(opts, &out, "getEventCount")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+// GetEventCount is a free data retrieval call binding the contract method 0xd9e48f5c.
+//
+// Solidity: function getEventCount() view returns(uint256)
+func (_Chainreader *ChainreaderSession) GetEventCount() (*big.Int, error) {
+ return _Chainreader.Contract.GetEventCount(&_Chainreader.CallOpts)
+}
+
+// GetEventCount is a free data retrieval call binding the contract method 0xd9e48f5c.
+//
+// Solidity: function getEventCount() view returns(uint256)
+func (_Chainreader *ChainreaderCallerSession) GetEventCount() (*big.Int, error) {
+ return _Chainreader.Contract.GetEventCount(&_Chainreader.CallOpts)
+}
+
+// GetNumbers is a free data retrieval call binding the contract method 0x89f915f6.
+//
+// Solidity: function getNumbers() view returns(uint256[])
+func (_Chainreader *ChainreaderCaller) GetNumbers(opts *bind.CallOpts) ([]*big.Int, error) {
+ var out []interface{}
+ err := _Chainreader.contract.Call(opts, &out, "getNumbers")
+
+ if err != nil {
+ return *new([]*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int)
+
+ return out0, err
+
+}
+
+// GetNumbers is a free data retrieval call binding the contract method 0x89f915f6.
+//
+// Solidity: function getNumbers() view returns(uint256[])
+func (_Chainreader *ChainreaderSession) GetNumbers() ([]*big.Int, error) {
+ return _Chainreader.Contract.GetNumbers(&_Chainreader.CallOpts)
+}
+
+// GetNumbers is a free data retrieval call binding the contract method 0x89f915f6.
+//
+// Solidity: function getNumbers() view returns(uint256[])
+func (_Chainreader *ChainreaderCallerSession) GetNumbers() ([]*big.Int, error) {
+ return _Chainreader.Contract.GetNumbers(&_Chainreader.CallOpts)
+}
+
+// GetPerson is a free data retrieval call binding the contract method 0x8ec4dc95.
+//
+// Solidity: function getPerson() pure returns((string,uint256))
+func (_Chainreader *ChainreaderCaller) GetPerson(opts *bind.CallOpts) (SimpleContractPerson, error) {
+ var out []interface{}
+ err := _Chainreader.contract.Call(opts, &out, "getPerson")
+
+ if err != nil {
+ return *new(SimpleContractPerson), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(SimpleContractPerson)).(*SimpleContractPerson)
+
+ return out0, err
+
+}
+
+// GetPerson is a free data retrieval call binding the contract method 0x8ec4dc95.
+//
+// Solidity: function getPerson() pure returns((string,uint256))
+func (_Chainreader *ChainreaderSession) GetPerson() (SimpleContractPerson, error) {
+ return _Chainreader.Contract.GetPerson(&_Chainreader.CallOpts)
+}
+
+// GetPerson is a free data retrieval call binding the contract method 0x8ec4dc95.
+//
+// Solidity: function getPerson() pure returns((string,uint256))
+func (_Chainreader *ChainreaderCallerSession) GetPerson() (SimpleContractPerson, error) {
+ return _Chainreader.Contract.GetPerson(&_Chainreader.CallOpts)
+}
+
+// Numbers is a free data retrieval call binding the contract method 0xd39fa233.
+//
+// Solidity: function numbers(uint256 ) view returns(uint256)
+func (_Chainreader *ChainreaderCaller) Numbers(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _Chainreader.contract.Call(opts, &out, "numbers", arg0)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+// Numbers is a free data retrieval call binding the contract method 0xd39fa233.
+//
+// Solidity: function numbers(uint256 ) view returns(uint256)
+func (_Chainreader *ChainreaderSession) Numbers(arg0 *big.Int) (*big.Int, error) {
+ return _Chainreader.Contract.Numbers(&_Chainreader.CallOpts, arg0)
+}
+
+// Numbers is a free data retrieval call binding the contract method 0xd39fa233.
+//
+// Solidity: function numbers(uint256 ) view returns(uint256)
+func (_Chainreader *ChainreaderCallerSession) Numbers(arg0 *big.Int) (*big.Int, error) {
+ return _Chainreader.Contract.Numbers(&_Chainreader.CallOpts, arg0)
+}
+
+// EmitEvent is a paid mutator transaction binding the contract method 0x7b0cb839.
+//
+// Solidity: function emitEvent() returns()
+func (_Chainreader *ChainreaderTransactor) EmitEvent(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Chainreader.contract.Transact(opts, "emitEvent")
+}
+
+// EmitEvent is a paid mutator transaction binding the contract method 0x7b0cb839.
+//
+// Solidity: function emitEvent() returns()
+func (_Chainreader *ChainreaderSession) EmitEvent() (*types.Transaction, error) {
+ return _Chainreader.Contract.EmitEvent(&_Chainreader.TransactOpts)
+}
+
+// EmitEvent is a paid mutator transaction binding the contract method 0x7b0cb839.
+//
+// Solidity: function emitEvent() returns()
+func (_Chainreader *ChainreaderTransactorSession) EmitEvent() (*types.Transaction, error) {
+ return _Chainreader.Contract.EmitEvent(&_Chainreader.TransactOpts)
+}
+
+// ChainreaderSimpleEventIterator is returned from FilterSimpleEvent and is used to iterate over the raw logs and unpacked data for SimpleEvent events raised by the Chainreader contract.
+type ChainreaderSimpleEventIterator struct {
+ Event *ChainreaderSimpleEvent // Event containing the contract specifics and raw log
+
+ contract *bind.BoundContract // Generic contract to use for unpacking event data
+ event string // Event name to use for unpacking event data
+
+ logs chan types.Log // Log channel receiving the found contract events
+ sub ethereum.Subscription // Subscription for errors, completion and termination
+ done bool // Whether the subscription completed delivering logs
+ fail error // Occurred error to stop iteration
+}
+
+// Next advances the iterator to the subsequent event, returning whether there
+// are any more events found. In case of a retrieval or parsing error, false is
+// returned and Error() can be queried for the exact failure.
+func (it *ChainreaderSimpleEventIterator) Next() bool {
+ // If the iterator failed, stop iterating
+ if it.fail != nil {
+ return false
+ }
+ // If the iterator completed, deliver directly whatever's available
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ChainreaderSimpleEvent)
+ 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
+ }
+ }
+ // Iterator still in progress, wait for either a data or an error event
+ select {
+ case log := <-it.logs:
+ it.Event = new(ChainreaderSimpleEvent)
+ 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()
+ }
+}
+
+// Error returns any retrieval or parsing error occurred during filtering.
+func (it *ChainreaderSimpleEventIterator) Error() error {
+ return it.fail
+}
+
+// Close terminates the iteration process, releasing any pending underlying
+// resources.
+func (it *ChainreaderSimpleEventIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+// ChainreaderSimpleEvent represents a SimpleEvent event raised by the Chainreader contract.
+type ChainreaderSimpleEvent struct {
+ Value *big.Int
+ Raw types.Log // Blockchain specific contextual infos
+}
+
+// FilterSimpleEvent is a free log retrieval operation binding the contract event 0x12d199749b3f4c44df8d9386c63d725b7756ec47204f3aa0bf05ea832f89effb.
+//
+// Solidity: event SimpleEvent(uint256 value)
+func (_Chainreader *ChainreaderFilterer) FilterSimpleEvent(opts *bind.FilterOpts) (*ChainreaderSimpleEventIterator, error) {
+
+ logs, sub, err := _Chainreader.contract.FilterLogs(opts, "SimpleEvent")
+ if err != nil {
+ return nil, err
+ }
+ return &ChainreaderSimpleEventIterator{contract: _Chainreader.contract, event: "SimpleEvent", logs: logs, sub: sub}, nil
+}
+
+// WatchSimpleEvent is a free log subscription operation binding the contract event 0x12d199749b3f4c44df8d9386c63d725b7756ec47204f3aa0bf05ea832f89effb.
+//
+// Solidity: event SimpleEvent(uint256 value)
+func (_Chainreader *ChainreaderFilterer) WatchSimpleEvent(opts *bind.WatchOpts, sink chan<- *ChainreaderSimpleEvent) (event.Subscription, error) {
+
+ logs, sub, err := _Chainreader.contract.WatchLogs(opts, "SimpleEvent")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+ // New log arrived, parse the event and forward to the user
+ event := new(ChainreaderSimpleEvent)
+ if err := _Chainreader.contract.UnpackLog(event, "SimpleEvent", 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
+}
+
+// ParseSimpleEvent is a log parse operation binding the contract event 0x12d199749b3f4c44df8d9386c63d725b7756ec47204f3aa0bf05ea832f89effb.
+//
+// Solidity: event SimpleEvent(uint256 value)
+func (_Chainreader *ChainreaderFilterer) ParseSimpleEvent(log types.Log) (*ChainreaderSimpleEvent, error) {
+ event := new(ChainreaderSimpleEvent)
+ if err := _Chainreader.contract.UnpackLog(event, "SimpleEvent", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/chainreader/mycontract.sol b/core/capabilities/ccip/ccip_integration_tests/chainreader/mycontract.sol
new file mode 100644
index 00000000000..0fae1f4baac
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/chainreader/mycontract.sol
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: BUSL-1.1
+pragma solidity 0.8.18;
+
+contract SimpleContract {
+ event SimpleEvent(uint256 value);
+ uint256 public eventCount;
+ uint[] public numbers;
+
+ struct Person {
+ string name;
+ uint age;
+ }
+
+ function emitEvent() public {
+ eventCount++;
+ numbers.push(eventCount);
+ emit SimpleEvent(eventCount);
+ }
+
+ function getEventCount() public view returns (uint256) {
+ return eventCount;
+ }
+
+ function getNumbers() public view returns (uint256[] memory) {
+ return numbers;
+ }
+
+ function getPerson() public pure returns (Person memory) {
+ return Person("Dim", 18);
+ }
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/helpers.go b/core/capabilities/ccip/ccip_integration_tests/helpers.go
new file mode 100644
index 00000000000..7606c8bbebc
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/helpers.go
@@ -0,0 +1,938 @@
+package ccip_integration_tests
+
+import (
+ "bytes"
+ "encoding/hex"
+ "math/big"
+ "sort"
+ "testing"
+ "time"
+
+ "github.com/smartcontractkit/chainlink-ccip/chainconfig"
+ "github.com/smartcontractkit/chainlink-ccip/pluginconfig"
+ commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccip_integration_tests/integrationhelpers"
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+
+ confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_proxy_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_multi_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/nonce_manager"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ocr3_config_encoder"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9"
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/link_token"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+
+ chainsel "github.com/smartcontractkit/chain-selectors"
+
+ "github.com/stretchr/testify/require"
+)
+
+var (
+ homeChainID = chainsel.GETH_TESTNET.EvmChainID
+ ccipSendRequestedTopic = evm_2_evm_multi_onramp.EVM2EVMMultiOnRampCCIPSendRequested{}.Topic()
+ commitReportAcceptedTopic = evm_2_evm_multi_offramp.EVM2EVMMultiOffRampCommitReportAccepted{}.Topic()
+ executionStateChangedTopic = evm_2_evm_multi_offramp.EVM2EVMMultiOffRampExecutionStateChanged{}.Topic()
+)
+
+const (
+ CapabilityLabelledName = "ccip"
+ CapabilityVersion = "v1.0.0"
+ NodeOperatorID = 1
+
+ // These constants drive what is set in the plugin offchain configs.
+ FirstBlockAge = 8 * time.Hour
+ RemoteGasPriceBatchWriteFrequency = 30 * time.Minute
+ BatchGasLimit = 6_500_000
+ RelativeBoostPerWaitHour = 1.5
+ InflightCacheExpiry = 10 * time.Minute
+ RootSnoozeTime = 30 * time.Minute
+ BatchingStrategyID = 0
+ DeltaProgress = 30 * time.Second
+ DeltaResend = 10 * time.Second
+ DeltaInitial = 20 * time.Second
+ DeltaRound = 2 * time.Second
+ DeltaGrace = 2 * time.Second
+ DeltaCertifiedCommitRequest = 10 * time.Second
+ DeltaStage = 10 * time.Second
+ Rmax = 3
+ MaxDurationQuery = 50 * time.Millisecond
+ MaxDurationObservation = 5 * time.Second
+ MaxDurationShouldAcceptAttestedReport = 10 * time.Second
+ MaxDurationShouldTransmitAcceptedReport = 10 * time.Second
+)
+
+func e18Mult(amount uint64) *big.Int {
+ return new(big.Int).Mul(uBigInt(amount), uBigInt(1e18))
+}
+
+func uBigInt(i uint64) *big.Int {
+ return new(big.Int).SetUint64(i)
+}
+
+type homeChain struct {
+ backend *backends.SimulatedBackend
+ owner *bind.TransactOpts
+ chainID uint64
+ capabilityRegistry *kcr.CapabilitiesRegistry
+ ccipConfig *ccip_config.CCIPConfig
+}
+
+type onchainUniverse struct {
+ backend *backends.SimulatedBackend
+ owner *bind.TransactOpts
+ chainID uint64
+ linkToken *link_token.LinkToken
+ weth *weth9.WETH9
+ router *router.Router
+ rmnProxy *arm_proxy_contract.ARMProxyContract
+ rmn *mock_arm_contract.MockARMContract
+ onramp *evm_2_evm_multi_onramp.EVM2EVMMultiOnRamp
+ offramp *evm_2_evm_multi_offramp.EVM2EVMMultiOffRamp
+ priceRegistry *price_registry.PriceRegistry
+ tokenAdminRegistry *token_admin_registry.TokenAdminRegistry
+ nonceManager *nonce_manager.NonceManager
+ receiver *maybe_revert_message_receiver.MaybeRevertMessageReceiver
+}
+
+type requestData struct {
+ destChainSelector uint64
+ receiverAddress common.Address
+ data []byte
+}
+
+func (u *onchainUniverse) SendCCIPRequests(t *testing.T, requestDatas []requestData) {
+ for _, reqData := range requestDatas {
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: common.LeftPadBytes(reqData.receiverAddress.Bytes(), 32),
+ Data: reqData.data,
+ TokenAmounts: nil, // TODO: no tokens for now
+ FeeToken: u.weth.Address(),
+ ExtraArgs: nil, // TODO: no extra args for now, falls back to default
+ }
+ fee, err := u.router.GetFee(&bind.CallOpts{Context: testutils.Context(t)}, reqData.destChainSelector, msg)
+ require.NoError(t, err)
+ _, err = u.weth.Deposit(&bind.TransactOpts{
+ From: u.owner.From,
+ Signer: u.owner.Signer,
+ Value: fee,
+ })
+ require.NoError(t, err)
+ u.backend.Commit()
+ _, err = u.weth.Approve(u.owner, u.router.Address(), fee)
+ require.NoError(t, err)
+ u.backend.Commit()
+
+ t.Logf("Sending CCIP request from chain %d (selector %d) to chain selector %d",
+ u.chainID, getSelector(u.chainID), reqData.destChainSelector)
+ _, err = u.router.CcipSend(u.owner, reqData.destChainSelector, msg)
+ require.NoError(t, err)
+ u.backend.Commit()
+ }
+}
+
+type chainBase struct {
+ backend *backends.SimulatedBackend
+ owner *bind.TransactOpts
+}
+
+// createUniverses does the following:
+// 1. Creates 1 home chain and `numChains`-1 non-home chains
+// 2. Sets up home chain with the capability registry and the CCIP config contract
+// 2. Deploys the CCIP contracts to all chains.
+// 3. Sets up the initial configurations for the contracts on all chains.
+// 4. Wires the chains together.
+//
+// Conceptually one universe is ONE chain with all the contracts deployed on it and all the dependencies initialized.
+func createUniverses(
+ t *testing.T,
+ numChains int,
+) (homeChainUni homeChain, universes map[uint64]onchainUniverse) {
+ chains := createChains(t, numChains)
+
+ homeChainBase, ok := chains[homeChainID]
+ require.True(t, ok, "home chain backend not available")
+ // Set up home chain first
+ homeChainUniverse := setupHomeChain(t, homeChainBase.owner, homeChainBase.backend)
+
+ // deploy the ccip contracts on all chains
+ universes = make(map[uint64]onchainUniverse)
+ for chainID, base := range chains {
+ owner := base.owner
+ backend := base.backend
+ // deploy the CCIP contracts
+ linkToken := deployLinkToken(t, owner, backend, chainID)
+ rmn := deployMockARMContract(t, owner, backend, chainID)
+ rmnProxy := deployARMProxyContract(t, owner, backend, rmn.Address(), chainID)
+ weth := deployWETHContract(t, owner, backend, chainID)
+ rout := deployRouter(t, owner, backend, weth.Address(), rmnProxy.Address(), chainID)
+ priceRegistry := deployPriceRegistry(t, owner, backend, linkToken.Address(), weth.Address(), big.NewInt(1e18), chainID)
+ tokenAdminRegistry := deployTokenAdminRegistry(t, owner, backend, chainID)
+ nonceManager := deployNonceManager(t, owner, backend, chainID)
+
+ // ======================================================================
+ // OnRamp
+ // ======================================================================
+ onRampAddr, _, _, err := evm_2_evm_multi_onramp.DeployEVM2EVMMultiOnRamp(
+ owner,
+ backend,
+ evm_2_evm_multi_onramp.EVM2EVMMultiOnRampStaticConfig{
+ ChainSelector: getSelector(chainID),
+ RmnProxy: rmnProxy.Address(),
+ NonceManager: nonceManager.Address(),
+ TokenAdminRegistry: tokenAdminRegistry.Address(),
+ },
+ evm_2_evm_multi_onramp.EVM2EVMMultiOnRampDynamicConfig{
+ Router: rout.Address(),
+ PriceRegistry: priceRegistry.Address(),
+ // `withdrawFeeTokens` onRamp function is not part of the message flow
+ // so we can set this to any address
+ FeeAggregator: testutils.NewAddress(),
+ },
+ )
+ require.NoErrorf(t, err, "failed to deploy onramp on chain id %d", chainID)
+ backend.Commit()
+ onramp, err := evm_2_evm_multi_onramp.NewEVM2EVMMultiOnRamp(onRampAddr, backend)
+ require.NoError(t, err)
+
+ // ======================================================================
+ // OffRamp
+ // ======================================================================
+ offrampAddr, _, _, err := evm_2_evm_multi_offramp.DeployEVM2EVMMultiOffRamp(
+ owner,
+ backend,
+ evm_2_evm_multi_offramp.EVM2EVMMultiOffRampStaticConfig{
+ ChainSelector: getSelector(chainID),
+ RmnProxy: rmnProxy.Address(),
+ TokenAdminRegistry: tokenAdminRegistry.Address(),
+ NonceManager: nonceManager.Address(),
+ },
+ evm_2_evm_multi_offramp.EVM2EVMMultiOffRampDynamicConfig{
+ Router: rout.Address(),
+ PriceRegistry: priceRegistry.Address(),
+ },
+ // Source chain configs will be set up later once we have all chains
+ []evm_2_evm_multi_offramp.EVM2EVMMultiOffRampSourceChainConfigArgs{},
+ )
+ require.NoErrorf(t, err, "failed to deploy offramp on chain id %d", chainID)
+ backend.Commit()
+ offramp, err := evm_2_evm_multi_offramp.NewEVM2EVMMultiOffRamp(offrampAddr, backend)
+ require.NoError(t, err)
+
+ receiverAddress, _, _, err := maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver(
+ owner,
+ backend,
+ false,
+ )
+ require.NoError(t, err, "failed to deploy MaybeRevertMessageReceiver on chain id %d", chainID)
+ backend.Commit()
+ receiver, err := maybe_revert_message_receiver.NewMaybeRevertMessageReceiver(receiverAddress, backend)
+ require.NoError(t, err)
+
+ universe := onchainUniverse{
+ backend: backend,
+ owner: owner,
+ chainID: chainID,
+ linkToken: linkToken,
+ weth: weth,
+ router: rout,
+ rmnProxy: rmnProxy,
+ rmn: rmn,
+ onramp: onramp,
+ offramp: offramp,
+ priceRegistry: priceRegistry,
+ tokenAdminRegistry: tokenAdminRegistry,
+ nonceManager: nonceManager,
+ receiver: receiver,
+ }
+ // Set up the initial configurations for the contracts
+ setupUniverseBasics(t, universe)
+
+ universes[chainID] = universe
+ }
+
+ // Once we have all chains created and contracts deployed, we can set up the initial configurations and wire chains together
+ connectUniverses(t, universes)
+
+ // print out all contract addresses for debugging purposes
+ for chainID, uni := range universes {
+ t.Logf("Chain ID: %d\n Chain Selector: %d\n LinkToken: %s\n WETH: %s\n Router: %s\n RMNProxy: %s\n RMN: %s\n OnRamp: %s\n OffRamp: %s\n PriceRegistry: %s\n TokenAdminRegistry: %s\n NonceManager: %s\n",
+ chainID,
+ getSelector(chainID),
+ uni.linkToken.Address().Hex(),
+ uni.weth.Address().Hex(),
+ uni.router.Address().Hex(),
+ uni.rmnProxy.Address().Hex(),
+ uni.rmn.Address().Hex(),
+ uni.onramp.Address().Hex(),
+ uni.offramp.Address().Hex(),
+ uni.priceRegistry.Address().Hex(),
+ uni.tokenAdminRegistry.Address().Hex(),
+ uni.nonceManager.Address().Hex(),
+ )
+ }
+
+ // print out topic hashes of relevant events for debugging purposes
+ t.Logf("Topic hash of CommitReportAccepted: %s", commitReportAcceptedTopic.Hex())
+ t.Logf("Topic hash of ExecutionStateChanged: %s", executionStateChangedTopic.Hex())
+ t.Logf("Topic hash of CCIPSendRequested: %s", ccipSendRequestedTopic.Hex())
+
+ return homeChainUniverse, universes
+}
+
+// Creates 1 home chain and `numChains`-1 non-home chains
+func createChains(t *testing.T, numChains int) map[uint64]chainBase {
+ chains := make(map[uint64]chainBase)
+
+ homeChainOwner := testutils.MustNewSimTransactor(t)
+ homeChainBackend := backends.NewSimulatedBackend(core.GenesisAlloc{
+ homeChainOwner.From: core.GenesisAccount{
+ Balance: assets.Ether(10_000).ToInt(),
+ },
+ }, 30e6)
+ tweakChainTimestamp(t, homeChainBackend, FirstBlockAge)
+
+ chains[homeChainID] = chainBase{
+ owner: homeChainOwner,
+ backend: homeChainBackend,
+ }
+
+ for chainID := chainsel.TEST_90000001.EvmChainID; len(chains) < numChains && chainID < chainsel.TEST_90000020.EvmChainID; chainID++ {
+ owner := testutils.MustNewSimTransactor(t)
+ backend := backends.NewSimulatedBackend(core.GenesisAlloc{
+ owner.From: core.GenesisAccount{
+ Balance: assets.Ether(10_000).ToInt(),
+ },
+ }, 30e6)
+
+ tweakChainTimestamp(t, backend, FirstBlockAge)
+
+ chains[chainID] = chainBase{
+ owner: owner,
+ backend: backend,
+ }
+ }
+
+ return chains
+}
+
+// CCIP relies on block timestamps, but SimulatedBackend uses by default clock starting from 1970-01-01
+// This trick is used to move the clock closer to the current time. We set first block to be X hours ago.
+// Tests create plenty of transactions so this number can't be too low, every new block mined will tick the clock,
+// if you mine more than "X hours" transactions, SimulatedBackend will panic because generated timestamps will be in the future.
+func tweakChainTimestamp(t *testing.T, backend *backends.SimulatedBackend, tweak time.Duration) {
+ blockTime := time.Unix(int64(backend.Blockchain().CurrentHeader().Time), 0)
+ sinceBlockTime := time.Since(blockTime)
+ diff := sinceBlockTime - tweak
+ err := backend.AdjustTime(diff)
+ require.NoError(t, err, "unable to adjust time on simulated chain")
+ backend.Commit()
+ backend.Commit()
+}
+
+func setupHomeChain(t *testing.T, owner *bind.TransactOpts, backend *backends.SimulatedBackend) homeChain {
+ // deploy the capability registry on the home chain
+ crAddress, _, _, err := kcr.DeployCapabilitiesRegistry(owner, backend)
+ require.NoError(t, err, "failed to deploy capability registry on home chain")
+ backend.Commit()
+
+ capabilityRegistry, err := kcr.NewCapabilitiesRegistry(crAddress, backend)
+ require.NoError(t, err)
+
+ ccAddress, _, _, err := ccip_config.DeployCCIPConfig(owner, backend, crAddress)
+ require.NoError(t, err)
+ backend.Commit()
+
+ capabilityConfig, err := ccip_config.NewCCIPConfig(ccAddress, backend)
+ require.NoError(t, err)
+
+ _, err = capabilityRegistry.AddCapabilities(owner, []kcr.CapabilitiesRegistryCapability{
+ {
+ LabelledName: CapabilityLabelledName,
+ Version: CapabilityVersion,
+ CapabilityType: 2, // consensus. not used (?)
+ ResponseType: 0, // report. not used (?)
+ ConfigurationContract: ccAddress,
+ },
+ })
+ require.NoError(t, err, "failed to add capabilities to the capability registry")
+ backend.Commit()
+
+ // Add NodeOperator, for simplicity we'll add one NodeOperator only
+ // First NodeOperator will have NodeOperatorId = 1
+ _, err = capabilityRegistry.AddNodeOperators(owner, []kcr.CapabilitiesRegistryNodeOperator{
+ {
+ Admin: owner.From,
+ Name: "NodeOperator",
+ },
+ })
+ require.NoError(t, err, "failed to add node operator to the capability registry")
+ backend.Commit()
+
+ return homeChain{
+ backend: backend,
+ owner: owner,
+ chainID: homeChainID,
+ capabilityRegistry: capabilityRegistry,
+ ccipConfig: capabilityConfig,
+ }
+}
+
+func sortP2PIDS(p2pIDs [][32]byte) {
+ sort.Slice(p2pIDs, func(i, j int) bool {
+ return bytes.Compare(p2pIDs[i][:], p2pIDs[j][:]) < 0
+ })
+}
+
+func (h *homeChain) AddNodes(
+ t *testing.T,
+ p2pIDs [][32]byte,
+ capabilityIDs [][32]byte,
+) {
+ // Need to sort, otherwise _checkIsValidUniqueSubset onChain will fail
+ sortP2PIDS(p2pIDs)
+ var nodeParams []kcr.CapabilitiesRegistryNodeParams
+ for _, p2pID := range p2pIDs {
+ nodeParam := kcr.CapabilitiesRegistryNodeParams{
+ NodeOperatorId: NodeOperatorID,
+ Signer: p2pID, // Not used in tests
+ P2pId: p2pID,
+ HashedCapabilityIds: capabilityIDs,
+ }
+ nodeParams = append(nodeParams, nodeParam)
+ }
+ _, err := h.capabilityRegistry.AddNodes(h.owner, nodeParams)
+ require.NoError(t, err, "failed to add node operator oracles")
+ h.backend.Commit()
+}
+
+func AddChainConfig(
+ t *testing.T,
+ h homeChain,
+ chainSelector uint64,
+ p2pIDs [][32]byte,
+ f uint8,
+) ccip_config.CCIPConfigTypesChainConfigInfo {
+ // Need to sort, otherwise _checkIsValidUniqueSubset onChain will fail
+ sortP2PIDS(p2pIDs)
+ // First Add ChainConfig that includes all p2pIDs as readers
+ encodedExtraChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{
+ GasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(1000),
+ DAGasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(0),
+ FinalityDepth: 10,
+ OptimisticConfirmations: 1,
+ })
+ require.NoError(t, err)
+ chainConfig := integrationhelpers.SetupConfigInfo(chainSelector, p2pIDs, f, encodedExtraChainConfig)
+ inputConfig := []ccip_config.CCIPConfigTypesChainConfigInfo{
+ chainConfig,
+ }
+ _, err = h.ccipConfig.ApplyChainConfigUpdates(h.owner, nil, inputConfig)
+ require.NoError(t, err)
+ h.backend.Commit()
+ return chainConfig
+}
+
+func (h *homeChain) AddDON(
+ t *testing.T,
+ ccipCapabilityID [32]byte,
+ chainSelector uint64,
+ uni onchainUniverse,
+ f uint8,
+ bootstrapP2PID [32]byte,
+ p2pIDs [][32]byte,
+ oracles []confighelper2.OracleIdentityExtra,
+) {
+ // Get OCR3 Config from helper
+ var schedule []int
+ for range oracles {
+ schedule = append(schedule, 1)
+ }
+
+ tabi, err := ocr3_config_encoder.IOCR3ConfigEncoderMetaData.GetAbi()
+ require.NoError(t, err)
+
+ // Add DON on capability registry contract
+ var ocr3Configs []ocr3_config_encoder.CCIPConfigTypesOCR3Config
+ for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} {
+ var encodedOffchainConfig []byte
+ var err2 error
+ if pluginType == cctypes.PluginTypeCCIPCommit {
+ encodedOffchainConfig, err2 = pluginconfig.EncodeCommitOffchainConfig(pluginconfig.CommitOffchainConfig{
+ RemoteGasPriceBatchWriteFrequency: *commonconfig.MustNewDuration(RemoteGasPriceBatchWriteFrequency),
+ // TODO: implement token price writes
+ // TokenPriceBatchWriteFrequency: *commonconfig.MustNewDuration(tokenPriceBatchWriteFrequency),
+ })
+ require.NoError(t, err2)
+ } else {
+ encodedOffchainConfig, err2 = pluginconfig.EncodeExecuteOffchainConfig(pluginconfig.ExecuteOffchainConfig{
+ BatchGasLimit: BatchGasLimit,
+ RelativeBoostPerWaitHour: RelativeBoostPerWaitHour,
+ MessageVisibilityInterval: *commonconfig.MustNewDuration(FirstBlockAge),
+ InflightCacheExpiry: *commonconfig.MustNewDuration(InflightCacheExpiry),
+ RootSnoozeTime: *commonconfig.MustNewDuration(RootSnoozeTime),
+ BatchingStrategyID: BatchingStrategyID,
+ })
+ require.NoError(t, err2)
+ }
+ signers, transmitters, configF, _, offchainConfigVersion, offchainConfig, err2 := ocr3confighelper.ContractSetConfigArgsForTests(
+ DeltaProgress,
+ DeltaResend,
+ DeltaInitial,
+ DeltaRound,
+ DeltaGrace,
+ DeltaCertifiedCommitRequest,
+ DeltaStage,
+ Rmax,
+ schedule,
+ oracles,
+ encodedOffchainConfig,
+ MaxDurationQuery,
+ MaxDurationObservation,
+ MaxDurationShouldAcceptAttestedReport,
+ MaxDurationShouldTransmitAcceptedReport,
+ int(f),
+ []byte{}, // empty OnChainConfig
+ )
+ require.NoError(t, err2, "failed to create contract config")
+
+ signersBytes := make([][]byte, len(signers))
+ for i, signer := range signers {
+ signersBytes[i] = signer
+ }
+
+ transmittersBytes := make([][]byte, len(transmitters))
+ for i, transmitter := range transmitters {
+ // anotherErr because linting doesn't want to shadow err
+ parsed, anotherErr := common.ParseHexOrString(string(transmitter))
+ require.NoError(t, anotherErr)
+ transmittersBytes[i] = parsed
+ }
+
+ ocr3Configs = append(ocr3Configs, ocr3_config_encoder.CCIPConfigTypesOCR3Config{
+ PluginType: uint8(pluginType),
+ ChainSelector: chainSelector,
+ F: configF,
+ OffchainConfigVersion: offchainConfigVersion,
+ OfframpAddress: uni.offramp.Address().Bytes(),
+ BootstrapP2PIds: [][32]byte{bootstrapP2PID},
+ P2pIds: p2pIDs,
+ Signers: signersBytes,
+ Transmitters: transmittersBytes,
+ OffchainConfig: offchainConfig,
+ })
+ }
+
+ encodedCall, err := tabi.Pack("exposeOCR3Config", ocr3Configs)
+ require.NoError(t, err)
+
+ // Trim first four bytes to remove function selector.
+ encodedConfigs := encodedCall[4:]
+
+ // commit so that we have an empty block to filter events from
+ h.backend.Commit()
+
+ _, err = h.capabilityRegistry.AddDON(h.owner, p2pIDs, []kcr.CapabilitiesRegistryCapabilityConfiguration{
+ {
+ CapabilityId: ccipCapabilityID,
+ Config: encodedConfigs,
+ },
+ }, false, false, f)
+ require.NoError(t, err)
+ h.backend.Commit()
+
+ endBlock := h.backend.Blockchain().CurrentBlock().Number.Uint64()
+ iter, err := h.capabilityRegistry.FilterConfigSet(&bind.FilterOpts{
+ Start: h.backend.Blockchain().CurrentBlock().Number.Uint64() - 1,
+ End: &endBlock,
+ })
+ require.NoError(t, err, "failed to filter config set events")
+ var donID uint32
+ for iter.Next() {
+ donID = iter.Event.DonId
+ break
+ }
+ require.NotZero(t, donID, "failed to get donID from config set event")
+
+ var signerAddresses []common.Address
+ for _, oracle := range oracles {
+ signerAddresses = append(signerAddresses, common.BytesToAddress(oracle.OnchainPublicKey))
+ }
+
+ var transmitterAddresses []common.Address
+ for _, oracle := range oracles {
+ transmitterAddresses = append(transmitterAddresses, common.HexToAddress(string(oracle.TransmitAccount)))
+ }
+
+ // get the config digest from the ccip config contract and set config on the offramp.
+ var offrampOCR3Configs []evm_2_evm_multi_offramp.MultiOCR3BaseOCRConfigArgs
+ for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} {
+ ocrConfig, err1 := h.ccipConfig.GetOCRConfig(&bind.CallOpts{
+ Context: testutils.Context(t),
+ }, donID, uint8(pluginType))
+ require.NoError(t, err1, "failed to get OCR3 config from ccip config contract")
+ require.Len(t, ocrConfig, 1, "expected exactly one OCR3 config")
+ offrampOCR3Configs = append(offrampOCR3Configs, evm_2_evm_multi_offramp.MultiOCR3BaseOCRConfigArgs{
+ ConfigDigest: ocrConfig[0].ConfigDigest,
+ OcrPluginType: uint8(pluginType),
+ F: f,
+ IsSignatureVerificationEnabled: pluginType == cctypes.PluginTypeCCIPCommit,
+ Signers: signerAddresses,
+ Transmitters: transmitterAddresses,
+ })
+ }
+
+ uni.backend.Commit()
+
+ _, err = uni.offramp.SetOCR3Configs(uni.owner, offrampOCR3Configs)
+ require.NoError(t, err, "failed to set ocr3 configs on offramp")
+ uni.backend.Commit()
+
+ for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} {
+ ocrConfig, err := uni.offramp.LatestConfigDetails(&bind.CallOpts{
+ Context: testutils.Context(t),
+ }, uint8(pluginType))
+ require.NoError(t, err, "failed to get latest commit OCR3 config")
+ require.Equalf(t, offrampOCR3Configs[pluginType].ConfigDigest, ocrConfig.ConfigInfo.ConfigDigest, "%s OCR3 config digest mismatch", pluginType.String())
+ require.Equalf(t, offrampOCR3Configs[pluginType].F, ocrConfig.ConfigInfo.F, "%s OCR3 config F mismatch", pluginType.String())
+ require.Equalf(t, offrampOCR3Configs[pluginType].IsSignatureVerificationEnabled, ocrConfig.ConfigInfo.IsSignatureVerificationEnabled, "%s OCR3 config signature verification mismatch", pluginType.String())
+ if pluginType == cctypes.PluginTypeCCIPCommit {
+ // only commit will set signers, exec doesn't need them.
+ require.Equalf(t, offrampOCR3Configs[pluginType].Signers, ocrConfig.Signers, "%s OCR3 config signers mismatch", pluginType.String())
+ }
+ require.Equalf(t, offrampOCR3Configs[pluginType].Transmitters, ocrConfig.Transmitters, "%s OCR3 config transmitters mismatch", pluginType.String())
+ }
+
+ t.Logf("set ocr3 config on the offramp, signers: %+v, transmitters: %+v", signerAddresses, transmitterAddresses)
+}
+
+func connectUniverses(
+ t *testing.T,
+ universes map[uint64]onchainUniverse,
+) {
+ for _, uni := range universes {
+ wireRouter(t, uni, universes)
+ wirePriceRegistry(t, uni, universes)
+ wireOffRamp(t, uni, universes)
+ initRemoteChainsGasPrices(t, uni, universes)
+ }
+}
+
+// setupUniverseBasics sets up the initial configurations for the CCIP contracts on a single chain.
+// 1. Mint 1000 LINK to the owner
+// 2. Set the price registry with local token prices
+// 3. Authorize the onRamp and offRamp on the nonce manager
+func setupUniverseBasics(t *testing.T, uni onchainUniverse) {
+ // =============================================================================
+ // Universe specific updates/configs
+ // These updates are specific to each universe and are set up here
+ // These updates don't depend on other chains
+ // =============================================================================
+ owner := uni.owner
+ // =============================================================================
+ // Mint 1000 LINK to owner
+ // =============================================================================
+ _, err := uni.linkToken.GrantMintRole(owner, owner.From)
+ require.NoError(t, err)
+ _, err = uni.linkToken.Mint(owner, owner.From, e18Mult(1000))
+ require.NoError(t, err)
+ uni.backend.Commit()
+
+ // =============================================================================
+ // Price updates for tokens
+ // These are the prices of the fee tokens of local chain in USD
+ // =============================================================================
+ tokenPriceUpdates := []price_registry.InternalTokenPriceUpdate{
+ {
+ SourceToken: uni.linkToken.Address(),
+ UsdPerToken: e18Mult(20),
+ },
+ {
+ SourceToken: uni.weth.Address(),
+ UsdPerToken: e18Mult(4000),
+ },
+ }
+ _, err = uni.priceRegistry.UpdatePrices(owner, price_registry.InternalPriceUpdates{
+ TokenPriceUpdates: tokenPriceUpdates,
+ })
+ require.NoErrorf(t, err, "failed to update prices in price registry on chain id %d", uni.chainID)
+ uni.backend.Commit()
+
+ _, err = uni.priceRegistry.ApplyAuthorizedCallerUpdates(owner, price_registry.AuthorizedCallersAuthorizedCallerArgs{
+ AddedCallers: []common.Address{
+ uni.offramp.Address(),
+ },
+ })
+ require.NoError(t, err, "failed to authorize offramp on price registry")
+ uni.backend.Commit()
+
+ // =============================================================================
+ // Authorize OnRamp & OffRamp on NonceManager
+ // Otherwise the onramp will not be able to call the nonceManager to get next Nonce
+ // =============================================================================
+ authorizedCallersAuthorizedCallerArgs := nonce_manager.AuthorizedCallersAuthorizedCallerArgs{
+ AddedCallers: []common.Address{
+ uni.onramp.Address(),
+ uni.offramp.Address(),
+ },
+ }
+ _, err = uni.nonceManager.ApplyAuthorizedCallerUpdates(owner, authorizedCallersAuthorizedCallerArgs)
+ require.NoError(t, err)
+ uni.backend.Commit()
+}
+
+// As we can't change router contract. The contract was expecting onRamp and offRamp per lane and not per chain
+// In the new architecture we have only one onRamp and one offRamp per chain.
+// hence we add the mapping for all remote chains to the onRamp/offRamp contract of the local chain
+func wireRouter(t *testing.T, uni onchainUniverse, universes map[uint64]onchainUniverse) {
+ owner := uni.owner
+ var (
+ routerOnrampUpdates []router.RouterOnRamp
+ routerOfframpUpdates []router.RouterOffRamp
+ )
+ for remoteChainID := range universes {
+ if remoteChainID == uni.chainID {
+ continue
+ }
+ routerOnrampUpdates = append(routerOnrampUpdates, router.RouterOnRamp{
+ DestChainSelector: getSelector(remoteChainID),
+ OnRamp: uni.onramp.Address(),
+ })
+ routerOfframpUpdates = append(routerOfframpUpdates, router.RouterOffRamp{
+ SourceChainSelector: getSelector(remoteChainID),
+ OffRamp: uni.offramp.Address(),
+ })
+ }
+ _, err := uni.router.ApplyRampUpdates(owner, routerOnrampUpdates, []router.RouterOffRamp{}, routerOfframpUpdates)
+ require.NoErrorf(t, err, "failed to apply ramp updates on router on chain id %d", uni.chainID)
+ uni.backend.Commit()
+}
+
+// Setting OnRampDestChainConfigs
+func wirePriceRegistry(t *testing.T, uni onchainUniverse, universes map[uint64]onchainUniverse) {
+ owner := uni.owner
+ var priceRegistryDestChainConfigArgs []price_registry.PriceRegistryDestChainConfigArgs
+ for remoteChainID := range universes {
+ if remoteChainID == uni.chainID {
+ continue
+ }
+ priceRegistryDestChainConfigArgs = append(priceRegistryDestChainConfigArgs, price_registry.PriceRegistryDestChainConfigArgs{
+ DestChainSelector: getSelector(remoteChainID),
+ DestChainConfig: defaultPriceRegistryDestChainConfig(t),
+ })
+ }
+ _, err := uni.priceRegistry.ApplyDestChainConfigUpdates(owner, priceRegistryDestChainConfigArgs)
+ require.NoErrorf(t, err, "failed to apply dest chain config updates on price registry on chain id %d", uni.chainID)
+ uni.backend.Commit()
+}
+
+// Setting OffRampSourceChainConfigs
+func wireOffRamp(t *testing.T, uni onchainUniverse, universes map[uint64]onchainUniverse) {
+ owner := uni.owner
+ var offrampSourceChainConfigArgs []evm_2_evm_multi_offramp.EVM2EVMMultiOffRampSourceChainConfigArgs
+ for remoteChainID, remoteUniverse := range universes {
+ if remoteChainID == uni.chainID {
+ continue
+ }
+ offrampSourceChainConfigArgs = append(offrampSourceChainConfigArgs, evm_2_evm_multi_offramp.EVM2EVMMultiOffRampSourceChainConfigArgs{
+ SourceChainSelector: getSelector(remoteChainID), // for each destination chain, add a source chain config
+ IsEnabled: true,
+ OnRamp: remoteUniverse.onramp.Address().Bytes(),
+ })
+ }
+ _, err := uni.offramp.ApplySourceChainConfigUpdates(owner, offrampSourceChainConfigArgs)
+ require.NoErrorf(t, err, "failed to apply source chain config updates on offramp on chain id %d", uni.chainID)
+ uni.backend.Commit()
+ for remoteChainID, remoteUniverse := range universes {
+ if remoteChainID == uni.chainID {
+ continue
+ }
+ sourceCfg, err2 := uni.offramp.GetSourceChainConfig(&bind.CallOpts{}, getSelector(remoteChainID))
+ require.NoError(t, err2)
+ require.True(t, sourceCfg.IsEnabled, "source chain config should be enabled")
+ require.Equal(t, remoteUniverse.onramp.Address(), common.BytesToAddress(sourceCfg.OnRamp), "source chain config onRamp address mismatch")
+ }
+}
+
+func getSelector(chainID uint64) uint64 {
+ selector, err := chainsel.SelectorFromChainId(chainID)
+ if err != nil {
+ panic(err)
+ }
+ return selector
+}
+
+// initRemoteChainsGasPrices sets the gas prices for all chains except the local chain in the local price registry
+func initRemoteChainsGasPrices(t *testing.T, uni onchainUniverse, universes map[uint64]onchainUniverse) {
+ var gasPriceUpdates []price_registry.InternalGasPriceUpdate
+ for remoteChainID := range universes {
+ if remoteChainID == uni.chainID {
+ continue
+ }
+ gasPriceUpdates = append(gasPriceUpdates,
+ price_registry.InternalGasPriceUpdate{
+ DestChainSelector: getSelector(remoteChainID),
+ UsdPerUnitGas: big.NewInt(2e12),
+ },
+ )
+ }
+ _, err := uni.priceRegistry.UpdatePrices(uni.owner, price_registry.InternalPriceUpdates{
+ GasPriceUpdates: gasPriceUpdates,
+ })
+ require.NoError(t, err)
+}
+
+func defaultPriceRegistryDestChainConfig(t *testing.T) price_registry.PriceRegistryDestChainConfig {
+ // https://github.com/smartcontractkit/ccip/blob/c4856b64bd766f1ddbaf5d13b42d3c4b12efde3a/contracts/src/v0.8/ccip/libraries/Internal.sol#L337-L337
+ /*
+ ```Solidity
+ // bytes4(keccak256("CCIP ChainFamilySelector EVM"))
+ bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;
+ ```
+ */
+ evmFamilySelector, err := hex.DecodeString("2812d52c")
+ require.NoError(t, err)
+ return price_registry.PriceRegistryDestChainConfig{
+ IsEnabled: true,
+ MaxNumberOfTokensPerMsg: 10,
+ MaxDataBytes: 256,
+ MaxPerMsgGasLimit: 3_000_000,
+ DestGasOverhead: 50_000,
+ DefaultTokenFeeUSDCents: 1,
+ DestGasPerPayloadByte: 10,
+ DestDataAvailabilityOverheadGas: 0,
+ DestGasPerDataAvailabilityByte: 100,
+ DestDataAvailabilityMultiplierBps: 1,
+ DefaultTokenDestGasOverhead: 125_000,
+ DefaultTokenDestBytesOverhead: 32,
+ DefaultTxGasLimit: 200_000,
+ GasMultiplierWeiPerEth: 1,
+ NetworkFeeUSDCents: 1,
+ ChainFamilySelector: [4]byte(evmFamilySelector),
+ }
+}
+
+func deployLinkToken(t *testing.T, owner *bind.TransactOpts, backend *backends.SimulatedBackend, chainID uint64) *link_token.LinkToken {
+ linkAddr, _, _, err := link_token.DeployLinkToken(owner, backend)
+ require.NoErrorf(t, err, "failed to deploy link token on chain id %d", chainID)
+ backend.Commit()
+ linkToken, err := link_token.NewLinkToken(linkAddr, backend)
+ require.NoError(t, err)
+ return linkToken
+}
+
+func deployMockARMContract(t *testing.T, owner *bind.TransactOpts, backend *backends.SimulatedBackend, chainID uint64) *mock_arm_contract.MockARMContract {
+ rmnAddr, _, _, err := mock_arm_contract.DeployMockARMContract(owner, backend)
+ require.NoErrorf(t, err, "failed to deploy mock arm on chain id %d", chainID)
+ backend.Commit()
+ rmn, err := mock_arm_contract.NewMockARMContract(rmnAddr, backend)
+ require.NoError(t, err)
+ return rmn
+}
+
+func deployARMProxyContract(t *testing.T, owner *bind.TransactOpts, backend *backends.SimulatedBackend, rmnAddr common.Address, chainID uint64) *arm_proxy_contract.ARMProxyContract {
+ rmnProxyAddr, _, _, err := arm_proxy_contract.DeployARMProxyContract(owner, backend, rmnAddr)
+ require.NoErrorf(t, err, "failed to deploy arm proxy on chain id %d", chainID)
+ backend.Commit()
+ rmnProxy, err := arm_proxy_contract.NewARMProxyContract(rmnProxyAddr, backend)
+ require.NoError(t, err)
+ return rmnProxy
+}
+
+func deployWETHContract(t *testing.T, owner *bind.TransactOpts, backend *backends.SimulatedBackend, chainID uint64) *weth9.WETH9 {
+ wethAddr, _, _, err := weth9.DeployWETH9(owner, backend)
+ require.NoErrorf(t, err, "failed to deploy weth contract on chain id %d", chainID)
+ backend.Commit()
+ weth, err := weth9.NewWETH9(wethAddr, backend)
+ require.NoError(t, err)
+ return weth
+}
+
+func deployRouter(t *testing.T, owner *bind.TransactOpts, backend *backends.SimulatedBackend, wethAddr, rmnProxyAddr common.Address, chainID uint64) *router.Router {
+ routerAddr, _, _, err := router.DeployRouter(owner, backend, wethAddr, rmnProxyAddr)
+ require.NoErrorf(t, err, "failed to deploy router on chain id %d", chainID)
+ backend.Commit()
+ rout, err := router.NewRouter(routerAddr, backend)
+ require.NoError(t, err)
+ return rout
+}
+
+func deployPriceRegistry(
+ t *testing.T,
+ owner *bind.TransactOpts,
+ backend *backends.SimulatedBackend,
+ linkAddr,
+ wethAddr common.Address,
+ maxFeeJuelsPerMsg *big.Int,
+ chainID uint64,
+) *price_registry.PriceRegistry {
+ priceRegistryAddr, _, _, err := price_registry.DeployPriceRegistry(
+ owner,
+ backend,
+ price_registry.PriceRegistryStaticConfig{
+ MaxFeeJuelsPerMsg: maxFeeJuelsPerMsg,
+ LinkToken: linkAddr,
+ StalenessThreshold: 24 * 60 * 60, // 24 hours
+ },
+ []common.Address{
+ owner.From, // owner can update prices in this test
+ }, // price updaters, will be set to offramp later
+ []common.Address{linkAddr, wethAddr}, // fee tokens
+ // empty for now, need to fill in when testing token transfers
+ []price_registry.PriceRegistryTokenPriceFeedUpdate{},
+ // empty for now, need to fill in when testing token transfers
+ []price_registry.PriceRegistryTokenTransferFeeConfigArgs{},
+ []price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs{
+ {
+ PremiumMultiplierWeiPerEth: 9e17, // 0.9 ETH
+ Token: linkAddr,
+ },
+ {
+ PremiumMultiplierWeiPerEth: 1e18,
+ Token: wethAddr,
+ },
+ },
+ // Destination chain configs will be set up later once we have all chains
+ []price_registry.PriceRegistryDestChainConfigArgs{},
+ )
+ require.NoErrorf(t, err, "failed to deploy price registry on chain id %d", chainID)
+ backend.Commit()
+ priceRegistry, err := price_registry.NewPriceRegistry(priceRegistryAddr, backend)
+ require.NoError(t, err)
+ return priceRegistry
+}
+
+func deployTokenAdminRegistry(t *testing.T, owner *bind.TransactOpts, backend *backends.SimulatedBackend, chainID uint64) *token_admin_registry.TokenAdminRegistry {
+ tarAddr, _, _, err := token_admin_registry.DeployTokenAdminRegistry(owner, backend)
+ require.NoErrorf(t, err, "failed to deploy token admin registry on chain id %d", chainID)
+ backend.Commit()
+ tokenAdminRegistry, err := token_admin_registry.NewTokenAdminRegistry(tarAddr, backend)
+ require.NoError(t, err)
+ return tokenAdminRegistry
+}
+
+func deployNonceManager(t *testing.T, owner *bind.TransactOpts, backend *backends.SimulatedBackend, chainID uint64) *nonce_manager.NonceManager {
+ nonceManagerAddr, _, _, err := nonce_manager.DeployNonceManager(owner, backend, []common.Address{owner.From})
+ require.NoErrorf(t, err, "failed to deploy nonce_manager on chain id %d", chainID)
+ backend.Commit()
+ nonceManager, err := nonce_manager.NewNonceManager(nonceManagerAddr, backend)
+ require.NoError(t, err)
+ return nonceManager
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/home_chain_test.go b/core/capabilities/ccip/ccip_integration_tests/home_chain_test.go
new file mode 100644
index 00000000000..c78fd37b809
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/home_chain_test.go
@@ -0,0 +1,103 @@
+package ccip_integration_tests
+
+import (
+ "testing"
+ "time"
+
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccip_integration_tests/integrationhelpers"
+
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/onsi/gomega"
+
+ libocrtypes "github.com/smartcontractkit/libocr/ragep2p/types"
+
+ "github.com/smartcontractkit/chainlink-ccip/chainconfig"
+ ccipreader "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+
+ "github.com/stretchr/testify/require"
+
+ capcfg "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+func TestHomeChainReader(t *testing.T) {
+ ctx := testutils.Context(t)
+ lggr := logger.TestLogger(t)
+ uni := integrationhelpers.NewTestUniverse(ctx, t, lggr)
+ // We need 3*f + 1 p2pIDs to have enough nodes to bootstrap
+ var arr []int64
+ n := int(integrationhelpers.FChainA*3 + 1)
+ for i := 0; i <= n; i++ {
+ arr = append(arr, int64(i))
+ }
+ p2pIDs := integrationhelpers.P2pIDsFromInts(arr)
+ uni.AddCapability(p2pIDs)
+ //==============================Apply configs to Capability Contract=================================
+ encodedChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{
+ GasPriceDeviationPPB: cciptypes.NewBigIntFromInt64(1000),
+ DAGasPriceDeviationPPB: cciptypes.NewBigIntFromInt64(1_000_000),
+ FinalityDepth: -1,
+ OptimisticConfirmations: 1,
+ })
+ require.NoError(t, err)
+ chainAConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainA, p2pIDs, integrationhelpers.FChainA, encodedChainConfig)
+ chainBConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainB, p2pIDs[1:], integrationhelpers.FChainB, encodedChainConfig)
+ chainCConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainC, p2pIDs[2:], integrationhelpers.FChainC, encodedChainConfig)
+ inputConfig := []capcfg.CCIPConfigTypesChainConfigInfo{
+ chainAConf,
+ chainBConf,
+ chainCConf,
+ }
+ _, err = uni.CcipCfg.ApplyChainConfigUpdates(uni.Transactor, nil, inputConfig)
+ require.NoError(t, err)
+ uni.Backend.Commit()
+ //================================Setup HomeChainReader===============================
+
+ pollDuration := time.Second
+ homeChain := uni.HomeChainReader
+
+ gomega.NewWithT(t).Eventually(func() bool {
+ configs, _ := homeChain.GetAllChainConfigs()
+ return configs != nil
+ }, testutils.WaitTimeout(t), pollDuration*5).Should(gomega.BeTrue())
+
+ t.Logf("homchain reader is ready")
+ //================================Test HomeChain Reader===============================
+ expectedChainConfigs := map[cciptypes.ChainSelector]ccipreader.ChainConfig{}
+ for _, c := range inputConfig {
+ expectedChainConfigs[cciptypes.ChainSelector(c.ChainSelector)] = ccipreader.ChainConfig{
+ FChain: int(c.ChainConfig.FChain),
+ SupportedNodes: toPeerIDs(c.ChainConfig.Readers),
+ Config: mustDecodeChainConfig(t, c.ChainConfig.Config),
+ }
+ }
+ configs, err := homeChain.GetAllChainConfigs()
+ require.NoError(t, err)
+ require.Equal(t, expectedChainConfigs, configs)
+ //=================================Remove ChainC from OnChainConfig=========================================
+ _, err = uni.CcipCfg.ApplyChainConfigUpdates(uni.Transactor, []uint64{integrationhelpers.ChainC}, nil)
+ require.NoError(t, err)
+ uni.Backend.Commit()
+ time.Sleep(pollDuration * 5) // Wait for the chain reader to update
+ configs, err = homeChain.GetAllChainConfigs()
+ require.NoError(t, err)
+ delete(expectedChainConfigs, cciptypes.ChainSelector(integrationhelpers.ChainC))
+ require.Equal(t, expectedChainConfigs, configs)
+}
+
+func toPeerIDs(readers [][32]byte) mapset.Set[libocrtypes.PeerID] {
+ peerIDs := mapset.NewSet[libocrtypes.PeerID]()
+ for _, r := range readers {
+ peerIDs.Add(r)
+ }
+ return peerIDs
+}
+
+func mustDecodeChainConfig(t *testing.T, encodedChainConfig []byte) chainconfig.ChainConfig {
+ chainConfig, err := chainconfig.DecodeChainConfig(encodedChainConfig)
+ require.NoError(t, err)
+ return chainConfig
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/integrationhelpers/integration_helpers.go b/core/capabilities/ccip/ccip_integration_tests/integrationhelpers/integration_helpers.go
new file mode 100644
index 00000000000..7520b126336
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/integrationhelpers/integration_helpers.go
@@ -0,0 +1,304 @@
+package integrationhelpers
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "sort"
+ "testing"
+ "time"
+
+ configsevm "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/configs/evm"
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+
+ "github.com/smartcontractkit/chainlink-ccip/pkg/consts"
+ ccipreader "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ocr3_config_encoder"
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+ evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
+)
+
+const chainID = 1337
+
+func NewReader(
+ t *testing.T,
+ logPoller logpoller.LogPoller,
+ headTracker logpoller.HeadTracker,
+ client client.Client,
+ address common.Address,
+ chainReaderConfig evmrelaytypes.ChainReaderConfig,
+) types.ContractReader {
+ cr, err := evm.NewChainReaderService(testutils.Context(t), logger.TestLogger(t), logPoller, headTracker, client, chainReaderConfig)
+ require.NoError(t, err)
+ err = cr.Bind(testutils.Context(t), []types.BoundContract{
+ {
+ Address: address.String(),
+ Name: consts.ContractNameCCIPConfig,
+ },
+ })
+ require.NoError(t, err)
+ require.NoError(t, cr.Start(testutils.Context(t)))
+ for {
+ if err := cr.Ready(); err == nil {
+ break
+ }
+ }
+
+ return cr
+}
+
+const (
+ ChainA uint64 = 1
+ FChainA uint8 = 1
+
+ ChainB uint64 = 2
+ FChainB uint8 = 2
+
+ ChainC uint64 = 3
+ FChainC uint8 = 3
+
+ CcipCapabilityLabelledName = "ccip"
+ CcipCapabilityVersion = "v1.0"
+)
+
+var CapabilityID = fmt.Sprintf("%s@%s", CcipCapabilityLabelledName, CcipCapabilityVersion)
+
+type TestUniverse struct {
+ Transactor *bind.TransactOpts
+ Backend *backends.SimulatedBackend
+ CapReg *kcr.CapabilitiesRegistry
+ CcipCfg *ccip_config.CCIPConfig
+ TestingT *testing.T
+ LogPoller logpoller.LogPoller
+ HeadTracker logpoller.HeadTracker
+ SimClient client.Client
+ HomeChainReader ccipreader.HomeChain
+}
+
+func NewTestUniverse(ctx context.Context, t *testing.T, lggr logger.Logger) TestUniverse {
+ transactor := testutils.MustNewSimTransactor(t)
+ backend := backends.NewSimulatedBackend(core.GenesisAlloc{
+ transactor.From: {Balance: assets.Ether(1000).ToInt()},
+ }, 30e6)
+
+ crAddress, _, _, err := kcr.DeployCapabilitiesRegistry(transactor, backend)
+ require.NoError(t, err)
+ backend.Commit()
+
+ capReg, err := kcr.NewCapabilitiesRegistry(crAddress, backend)
+ require.NoError(t, err)
+
+ ccAddress, _, _, err := ccip_config.DeployCCIPConfig(transactor, backend, crAddress)
+ require.NoError(t, err)
+ backend.Commit()
+
+ cc, err := ccip_config.NewCCIPConfig(ccAddress, backend)
+ require.NoError(t, err)
+
+ db := pgtest.NewSqlxDB(t)
+ lpOpts := logpoller.Opts{
+ PollPeriod: time.Millisecond,
+ FinalityDepth: 0,
+ BackfillBatchSize: 10,
+ RpcBatchSize: 10,
+ KeepFinalizedBlocksDepth: 100000,
+ }
+ cl := client.NewSimulatedBackendClient(t, backend, big.NewInt(chainID))
+ headTracker := headtracker.NewSimulatedHeadTracker(cl, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ if lpOpts.PollPeriod == 0 {
+ lpOpts.PollPeriod = 1 * time.Hour
+ }
+ lp := logpoller.NewLogPoller(logpoller.NewORM(big.NewInt(chainID), db, lggr), cl, logger.NullLogger, headTracker, lpOpts)
+ require.NoError(t, lp.Start(ctx))
+ t.Cleanup(func() { require.NoError(t, lp.Close()) })
+
+ hcr := NewHomeChainReader(t, lp, headTracker, cl, ccAddress)
+ return TestUniverse{
+ Transactor: transactor,
+ Backend: backend,
+ CapReg: capReg,
+ CcipCfg: cc,
+ TestingT: t,
+ SimClient: cl,
+ LogPoller: lp,
+ HeadTracker: headTracker,
+ HomeChainReader: hcr,
+ }
+}
+
+func (t TestUniverse) NewContractReader(ctx context.Context, cfg []byte) (types.ContractReader, error) {
+ var config evmrelaytypes.ChainReaderConfig
+ err := json.Unmarshal(cfg, &config)
+ require.NoError(t.TestingT, err)
+ return evm.NewChainReaderService(ctx, logger.TestLogger(t.TestingT), t.LogPoller, t.HeadTracker, t.SimClient, config)
+}
+
+func P2pIDsFromInts(ints []int64) [][32]byte {
+ var p2pIDs [][32]byte
+ for _, i := range ints {
+ p2pID := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(i)).PeerID()
+ p2pIDs = append(p2pIDs, p2pID)
+ }
+ sort.Slice(p2pIDs, func(i, j int) bool {
+ for k := 0; k < 32; k++ {
+ if p2pIDs[i][k] < p2pIDs[j][k] {
+ return true
+ } else if p2pIDs[i][k] > p2pIDs[j][k] {
+ return false
+ }
+ }
+ return false
+ })
+ return p2pIDs
+}
+
+func (t *TestUniverse) AddCapability(p2pIDs [][32]byte) {
+ _, err := t.CapReg.AddCapabilities(t.Transactor, []kcr.CapabilitiesRegistryCapability{
+ {
+ LabelledName: CcipCapabilityLabelledName,
+ Version: CcipCapabilityVersion,
+ CapabilityType: 0,
+ ResponseType: 0,
+ ConfigurationContract: t.CcipCfg.Address(),
+ },
+ })
+ require.NoError(t.TestingT, err, "failed to add capability to registry")
+ t.Backend.Commit()
+
+ ccipCapabilityID, err := t.CapReg.GetHashedCapabilityId(nil, CcipCapabilityLabelledName, CcipCapabilityVersion)
+ require.NoError(t.TestingT, err)
+
+ for i := 0; i < len(p2pIDs); i++ {
+ _, err = t.CapReg.AddNodeOperators(t.Transactor, []kcr.CapabilitiesRegistryNodeOperator{
+ {
+ Admin: t.Transactor.From,
+ Name: fmt.Sprintf("nop-%d", i),
+ },
+ })
+ require.NoError(t.TestingT, err)
+ t.Backend.Commit()
+
+ // get the node operator id from the event
+ it, err := t.CapReg.FilterNodeOperatorAdded(nil, nil, nil)
+ require.NoError(t.TestingT, err)
+ var nodeOperatorID uint32
+ for it.Next() {
+ if it.Event.Name == fmt.Sprintf("nop-%d", i) {
+ nodeOperatorID = it.Event.NodeOperatorId
+ break
+ }
+ }
+ require.NotZero(t.TestingT, nodeOperatorID)
+
+ _, err = t.CapReg.AddNodes(t.Transactor, []kcr.CapabilitiesRegistryNodeParams{
+ {
+ NodeOperatorId: nodeOperatorID,
+ Signer: testutils.Random32Byte(),
+ P2pId: p2pIDs[i],
+ HashedCapabilityIds: [][32]byte{ccipCapabilityID},
+ },
+ })
+ require.NoError(t.TestingT, err)
+ t.Backend.Commit()
+
+ // verify that the node was added successfully
+ nodeInfo, err := t.CapReg.GetNode(nil, p2pIDs[i])
+ require.NoError(t.TestingT, err)
+
+ require.Equal(t.TestingT, nodeOperatorID, nodeInfo.NodeOperatorId)
+ require.Equal(t.TestingT, p2pIDs[i][:], nodeInfo.P2pId[:])
+ }
+}
+
+func NewHomeChainReader(t *testing.T, logPoller logpoller.LogPoller, headTracker logpoller.HeadTracker, client client.Client, ccAddress common.Address) ccipreader.HomeChain {
+ cr := NewReader(t, logPoller, headTracker, client, ccAddress, configsevm.HomeChainReaderConfigRaw())
+
+ hcr := ccipreader.NewHomeChainReader(cr, logger.TestLogger(t), 500*time.Millisecond)
+ require.NoError(t, hcr.Start(testutils.Context(t)))
+ t.Cleanup(func() { require.NoError(t, hcr.Close()) })
+
+ return hcr
+}
+
+func (t *TestUniverse) AddDONToRegistry(
+ ccipCapabilityID [32]byte,
+ chainSelector uint64,
+ f uint8,
+ bootstrapP2PID [32]byte,
+ p2pIDs [][32]byte,
+) {
+ tabi, err := ocr3_config_encoder.IOCR3ConfigEncoderMetaData.GetAbi()
+ require.NoError(t.TestingT, err)
+
+ var (
+ signers [][]byte
+ transmitters [][]byte
+ )
+ for range p2pIDs {
+ signers = append(signers, testutils.NewAddress().Bytes())
+ transmitters = append(transmitters, testutils.NewAddress().Bytes())
+ }
+
+ var ocr3Configs []ocr3_config_encoder.CCIPConfigTypesOCR3Config
+ for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} {
+ ocr3Configs = append(ocr3Configs, ocr3_config_encoder.CCIPConfigTypesOCR3Config{
+ PluginType: uint8(pluginType),
+ ChainSelector: chainSelector,
+ F: f,
+ OffchainConfigVersion: 30,
+ OfframpAddress: testutils.NewAddress().Bytes(),
+ BootstrapP2PIds: [][32]byte{bootstrapP2PID},
+ P2pIds: p2pIDs,
+ Signers: signers,
+ Transmitters: transmitters,
+ OffchainConfig: []byte("offchain config"),
+ })
+ }
+
+ encodedCall, err := tabi.Pack("exposeOCR3Config", ocr3Configs)
+ require.NoError(t.TestingT, err)
+
+ // Trim first four bytes to remove function selector.
+ encodedConfigs := encodedCall[4:]
+
+ _, err = t.CapReg.AddDON(t.Transactor, p2pIDs, []kcr.CapabilitiesRegistryCapabilityConfiguration{
+ {
+ CapabilityId: ccipCapabilityID,
+ Config: encodedConfigs,
+ },
+ }, false, false, f)
+ require.NoError(t.TestingT, err)
+ t.Backend.Commit()
+}
+
+func SetupConfigInfo(chainSelector uint64, readers [][32]byte, fChain uint8, cfg []byte) ccip_config.CCIPConfigTypesChainConfigInfo {
+ return ccip_config.CCIPConfigTypesChainConfigInfo{
+ ChainSelector: chainSelector,
+ ChainConfig: ccip_config.CCIPConfigTypesChainConfig{
+ Readers: readers,
+ FChain: fChain,
+ Config: cfg,
+ },
+ }
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/ocr3_node_test.go b/core/capabilities/ccip/ccip_integration_tests/ocr3_node_test.go
new file mode 100644
index 00000000000..8cafb901724
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/ocr3_node_test.go
@@ -0,0 +1,281 @@
+package ccip_integration_tests
+
+import (
+ "fmt"
+ "math/big"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/hashicorp/consul/sdk/freeport"
+ "go.uber.org/zap/zapcore"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp"
+ "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/p2pkey"
+
+ confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/stretchr/testify/require"
+)
+
+const STATE_SUCCESS = uint8(2)
+
+/*
+* If you want to debug, set log level to info and use the following commands for easier logs filtering.
+*
+* // Run the test and redirect logs to logs.txt
+* go test -v -run "^TestIntegration_OCR3Nodes" ./core/capabilities/ccip/ccip_integration_tests 2>&1 > logs.txt
+*
+* // Reads logs.txt as a stream and apply filters using grep
+* tail -fn0 logs.txt | grep "CCIPExecPlugin"
+ */
+func TestIntegration_OCR3Nodes(t *testing.T) {
+ const (
+ numChains = 3 // number of chains that this test will run on
+ numNodes = 4 // number of OCR3 nodes, test assumes that every node supports every chain
+
+ simulatedBackendBlockTime = 900 * time.Millisecond // Simulated backend blocks committing interval
+ oraclesBootWaitTime = 30 * time.Second // Time to wait for oracles to come up (HACK)
+ fChain = 1 // fChain value for all the chains
+ oracleLogLevel = zapcore.InfoLevel // Log level for the oracle / plugins.
+ )
+
+ t.Logf("creating %d universes", numChains)
+ homeChainUni, universes := createUniverses(t, numChains)
+
+ var (
+ oracles = make(map[uint64][]confighelper2.OracleIdentityExtra)
+ apps []chainlink.Application
+ nodes []*ocr3Node
+ p2pIDs [][32]byte
+
+ // The bootstrap node will be: nodes[0]
+ bootstrapPort int
+ bootstrapP2PID p2pkey.PeerID
+ )
+
+ ports := freeport.GetN(t, numNodes)
+ ctx := testutils.Context(t)
+ callCtx := &bind.CallOpts{Context: ctx}
+
+ for i := 0; i < numNodes; i++ {
+ t.Logf("Setting up ocr3 node:%d at port:%d", i, ports[i])
+ node := setupNodeOCR3(t, ports[i], universes, homeChainUni, oracleLogLevel)
+
+ for chainID, transmitter := range node.transmitters {
+ identity := confighelper2.OracleIdentityExtra{
+ OracleIdentity: confighelper2.OracleIdentity{
+ OnchainPublicKey: node.keybundle.PublicKey(), // Different for each chain
+ TransmitAccount: ocrtypes.Account(transmitter.Hex()),
+ OffchainPublicKey: node.keybundle.OffchainPublicKey(), // Same for each family
+ PeerID: node.peerID,
+ },
+ ConfigEncryptionPublicKey: node.keybundle.ConfigEncryptionPublicKey(), // Different for each chain
+ }
+ oracles[chainID] = append(oracles[chainID], identity)
+ }
+
+ apps = append(apps, node.app)
+ nodes = append(nodes, node)
+
+ peerID, err := p2pkey.MakePeerID(node.peerID)
+ require.NoError(t, err)
+ p2pIDs = append(p2pIDs, peerID)
+ }
+
+ bootstrapPort = ports[0]
+ bootstrapP2PID = p2pIDs[0]
+ bootstrapAddr := fmt.Sprintf("127.0.0.1:%d", bootstrapPort)
+ t.Logf("[bootstrap node] peerID:%s p2pID:%d address:%s", nodes[0].peerID, bootstrapP2PID, bootstrapAddr)
+
+ // Start committing periodically in the background for all the chains
+ tick := time.NewTicker(simulatedBackendBlockTime)
+ defer tick.Stop()
+ commitBlocksBackground(t, universes, tick)
+
+ ccipCapabilityID, err := homeChainUni.capabilityRegistry.GetHashedCapabilityId(
+ callCtx, CapabilityLabelledName, CapabilityVersion)
+ require.NoError(t, err, "failed to get hashed capability id for ccip")
+ require.NotEqual(t, [32]byte{}, ccipCapabilityID, "ccip capability id is empty")
+
+ // Need to Add nodes and assign capabilities to them before creating DONS
+ homeChainUni.AddNodes(t, p2pIDs, [][32]byte{ccipCapabilityID})
+
+ for _, uni := range universes {
+ t.Logf("Adding chainconfig for chain %d", uni.chainID)
+ AddChainConfig(t, homeChainUni, getSelector(uni.chainID), p2pIDs, fChain)
+ }
+
+ cfgs, err := homeChainUni.ccipConfig.GetAllChainConfigs(callCtx)
+ require.NoError(t, err)
+ require.Len(t, cfgs, numChains)
+
+ // Create a DON for each chain
+ for _, uni := range universes {
+ // Add nodes and give them the capability
+ t.Log("Adding DON for universe: ", uni.chainID)
+ chainSelector := getSelector(uni.chainID)
+ homeChainUni.AddDON(
+ t,
+ ccipCapabilityID,
+ chainSelector,
+ uni,
+ fChain,
+ bootstrapP2PID,
+ p2pIDs,
+ oracles[uni.chainID],
+ )
+ }
+
+ t.Log("Creating ocr3 jobs, starting oracles")
+ for i := 0; i < len(nodes); i++ {
+ err1 := nodes[i].app.Start(ctx)
+ require.NoError(t, err1)
+ tApp := apps[i]
+ t.Cleanup(func() { require.NoError(t, tApp.Stop()) })
+
+ jb := mustGetJobSpec(t, bootstrapP2PID, bootstrapPort, nodes[i].peerID, nodes[i].keybundle.ID())
+ require.NoErrorf(t, tApp.AddJobV2(ctx, &jb), "Wasn't able to create ccip job for node %d", i)
+ }
+
+ t.Logf("Sending ccip requests from each chain to all other chains")
+ for _, uni := range universes {
+ requests := genRequestData(uni.chainID, universes)
+ uni.SendCCIPRequests(t, requests)
+ }
+
+ // Wait for the oracles to come up.
+ // TODO: We need some data driven way to do this e.g. wait until LP filters to be registered.
+ time.Sleep(oraclesBootWaitTime)
+
+ // Replay the log poller on all the chains so that the logs are in the db.
+ // otherwise the plugins won't pick them up.
+ for _, node := range nodes {
+ for chainID := range universes {
+ t.Logf("Replaying logs for chain %d from block %d", chainID, 1)
+ require.NoError(t, node.app.ReplayFromBlock(big.NewInt(int64(chainID)), 1, false), "failed to replay logs")
+ }
+ }
+
+ // with only one request sent from each chain to each other chain,
+ // and with sequence numbers on incrementing by 1 on a per-dest chain
+ // basis, we expect the min sequence number to be 1 on all chains.
+ expectedSeqNrRange := ccipocr3.NewSeqNumRange(1, 1)
+ var wg sync.WaitGroup
+ for _, uni := range universes {
+ for remoteSelector := range universes {
+ if remoteSelector == uni.chainID {
+ continue
+ }
+ wg.Add(1)
+ go func(uni onchainUniverse, remoteSelector uint64) {
+ defer wg.Done()
+ waitForCommitWithInterval(t, uni, getSelector(remoteSelector), expectedSeqNrRange)
+ }(uni, remoteSelector)
+ }
+ }
+
+ start := time.Now()
+ wg.Wait()
+ t.Logf("All chains received the expected commit report in %s", time.Since(start))
+
+ // with only one request sent from each chain to each other chain,
+ // all ExecutionStateChanged events should have the sequence number 1.
+ expectedSeqNr := uint64(1)
+ for _, uni := range universes {
+ for remoteSelector := range universes {
+ if remoteSelector == uni.chainID {
+ continue
+ }
+ wg.Add(1)
+ go func(uni onchainUniverse, remoteSelector uint64) {
+ defer wg.Done()
+ waitForExecWithSeqNr(t, uni, getSelector(remoteSelector), expectedSeqNr)
+ }(uni, remoteSelector)
+ }
+ }
+
+ start = time.Now()
+ wg.Wait()
+ t.Logf("All chains received the expected ExecutionStateChanged event in %s", time.Since(start))
+}
+
+func genRequestData(chainID uint64, universes map[uint64]onchainUniverse) []requestData {
+ var res []requestData
+ for destChainID, destUni := range universes {
+ if destChainID == chainID {
+ continue
+ }
+ res = append(res, requestData{
+ destChainSelector: getSelector(destChainID),
+ receiverAddress: destUni.receiver.Address(),
+ data: []byte(fmt.Sprintf("msg from chain %d to chain %d", chainID, destChainID)),
+ })
+ }
+ return res
+}
+
+func waitForCommitWithInterval(
+ t *testing.T,
+ uni onchainUniverse,
+ expectedSourceChainSelector uint64,
+ expectedSeqNumRange ccipocr3.SeqNumRange,
+) {
+ sink := make(chan *evm_2_evm_multi_offramp.EVM2EVMMultiOffRampCommitReportAccepted)
+ subscription, err := uni.offramp.WatchCommitReportAccepted(&bind.WatchOpts{
+ Context: testutils.Context(t),
+ }, sink)
+ require.NoError(t, err)
+
+ for {
+ select {
+ case <-time.After(10 * time.Second):
+ t.Logf("Waiting for commit report on chain id %d (selector %d) from source selector %d expected seq nr range %s",
+ uni.chainID, getSelector(uni.chainID), expectedSourceChainSelector, expectedSeqNumRange.String())
+ case subErr := <-subscription.Err():
+ t.Fatalf("Subscription error: %+v", subErr)
+ case report := <-sink:
+ if len(report.Report.MerkleRoots) > 0 {
+ // Check the interval of sequence numbers and make sure it matches
+ // the expected range.
+ for _, mr := range report.Report.MerkleRoots {
+ if mr.SourceChainSelector == expectedSourceChainSelector &&
+ uint64(expectedSeqNumRange.Start()) == mr.Interval.Min &&
+ uint64(expectedSeqNumRange.End()) == mr.Interval.Max {
+ t.Logf("Received commit report on chain id %d (selector %d) from source selector %d expected seq nr range %s",
+ uni.chainID, getSelector(uni.chainID), expectedSourceChainSelector, expectedSeqNumRange.String())
+ return
+ }
+ }
+ }
+ }
+ }
+}
+
+func waitForExecWithSeqNr(t *testing.T, uni onchainUniverse, expectedSourceChainSelector, expectedSeqNr uint64) {
+ for {
+ scc, err := uni.offramp.GetSourceChainConfig(nil, expectedSourceChainSelector)
+ require.NoError(t, err)
+ t.Logf("Waiting for ExecutionStateChanged on chain %d (selector %d) from chain %d with expected sequence number %d, current onchain minSeqNr: %d",
+ uni.chainID, getSelector(uni.chainID), expectedSourceChainSelector, expectedSeqNr, scc.MinSeqNr)
+ iter, err := uni.offramp.FilterExecutionStateChanged(nil, []uint64{expectedSourceChainSelector}, []uint64{expectedSeqNr}, nil)
+ require.NoError(t, err)
+ var count int
+ for iter.Next() {
+ if iter.Event.SequenceNumber == expectedSeqNr && iter.Event.SourceChainSelector == expectedSourceChainSelector {
+ count++
+ }
+ }
+ if count == 1 {
+ t.Logf("Received ExecutionStateChanged on chain %d (selector %d) from chain %d with expected sequence number %d",
+ uni.chainID, getSelector(uni.chainID), expectedSourceChainSelector, expectedSeqNr)
+ return
+ }
+ time.Sleep(5 * time.Second)
+ }
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/ocr_node_helper.go b/core/capabilities/ccip/ccip_integration_tests/ocr_node_helper.go
new file mode 100644
index 00000000000..75b0e0ee947
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/ocr_node_helper.go
@@ -0,0 +1,316 @@
+package ccip_integration_tests
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "net/http"
+ "strconv"
+ "sync"
+ "testing"
+ "time"
+
+ coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ gethtypes "github.com/ethereum/go-ethereum/core/types"
+ "github.com/jmoiron/sqlx"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/loop"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ v2toml "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml"
+ evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
+ configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/logger/audit"
+ "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key"
+ "github.com/smartcontractkit/chainlink/v2/core/utils"
+ "github.com/smartcontractkit/chainlink/v2/plugins"
+
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap/zapcore"
+)
+
+type ocr3Node struct {
+ app chainlink.Application
+ peerID string
+ transmitters map[uint64]common.Address
+ keybundle ocr2key.KeyBundle
+ db *sqlx.DB
+}
+
+// setupNodeOCR3 creates a chainlink node and any associated keys in order to run
+// ccip.
+func setupNodeOCR3(
+ t *testing.T,
+ port int,
+ universes map[uint64]onchainUniverse,
+ homeChainUniverse homeChain,
+ logLevel zapcore.Level,
+) *ocr3Node {
+ // Do not want to load fixtures as they contain a dummy chainID.
+ cfg, db := heavyweight.FullTestDBNoFixturesV2(t, func(c *chainlink.Config, s *chainlink.Secrets) {
+ c.Insecure.OCRDevelopmentMode = ptr(true) // Disables ocr spec validation so we can have fast polling for the test.
+
+ c.Feature.LogPoller = ptr(true)
+
+ // P2P V2 configs.
+ c.P2P.V2.Enabled = ptr(true)
+ c.P2P.V2.DeltaDial = config.MustNewDuration(500 * time.Millisecond)
+ c.P2P.V2.DeltaReconcile = config.MustNewDuration(5 * time.Second)
+ c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)}
+
+ // Enable Capabilities, This is a pre-requisite for registrySyncer to work.
+ c.Capabilities.ExternalRegistry.NetworkID = ptr(relay.NetworkEVM)
+ c.Capabilities.ExternalRegistry.ChainID = ptr(strconv.FormatUint(homeChainUniverse.chainID, 10))
+ c.Capabilities.ExternalRegistry.Address = ptr(homeChainUniverse.capabilityRegistry.Address().String())
+
+ // OCR configs
+ c.OCR.Enabled = ptr(false)
+ c.OCR.DefaultTransactionQueueDepth = ptr(uint32(200))
+ c.OCR2.Enabled = ptr(true)
+ c.OCR2.ContractPollInterval = config.MustNewDuration(5 * time.Second)
+
+ c.Log.Level = ptr(configv2.LogLevel(logLevel))
+
+ var chains v2toml.EVMConfigs
+ for chainID := range universes {
+ chains = append(chains, createConfigV2Chain(uBigInt(chainID)))
+ }
+ c.EVM = chains
+ })
+
+ lggr := logger.TestLogger(t)
+ lggr.SetLogLevel(logLevel)
+ ctx := testutils.Context(t)
+ clients := make(map[uint64]client.Client)
+
+ for chainID, uni := range universes {
+ clients[chainID] = client.NewSimulatedBackendClient(t, uni.backend, uBigInt(chainID))
+ }
+
+ master := keystore.New(db, utils.FastScryptParams, lggr)
+
+ kStore := KeystoreSim{
+ eks: &EthKeystoreSim{
+ Eth: master.Eth(),
+ t: t,
+ },
+ csa: master.CSA(),
+ }
+ mailMon := mailbox.NewMonitor("ccip", lggr.Named("mailbox"))
+ evmOpts := chainlink.EVMFactoryConfig{
+ ChainOpts: legacyevm.ChainOpts{
+ AppConfig: cfg,
+ GenEthClient: func(i *big.Int) client.Client {
+ client, ok := clients[i.Uint64()]
+ if !ok {
+ t.Fatal("no backend for chainID", i)
+ }
+ return client
+ },
+ MailMon: mailMon,
+ DS: db,
+ },
+ CSAETHKeystore: kStore,
+ }
+ relayerFactory := chainlink.RelayerFactory{
+ Logger: lggr,
+ LoopRegistry: plugins.NewLoopRegistry(lggr.Named("LoopRegistry"), cfg.Tracing()),
+ GRPCOpts: loop.GRPCOpts{},
+ CapabilitiesRegistry: coretypes.NewCapabilitiesRegistry(t),
+ }
+ initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitEVM(testutils.Context(t), relayerFactory, evmOpts)}
+ rci, err := chainlink.NewCoreRelayerChainInteroperators(initOps...)
+ require.NoError(t, err)
+
+ app, err := chainlink.NewApplication(chainlink.ApplicationOpts{
+ Config: cfg,
+ DS: db,
+ KeyStore: master,
+ RelayerChainInteroperators: rci,
+ Logger: lggr,
+ ExternalInitiatorManager: nil,
+ CloseLogger: lggr.Sync,
+ UnrestrictedHTTPClient: &http.Client{},
+ RestrictedHTTPClient: &http.Client{},
+ AuditLogger: audit.NoopLogger,
+ MailMon: mailMon,
+ LoopRegistry: plugins.NewLoopRegistry(lggr, cfg.Tracing()),
+ })
+ require.NoError(t, err)
+ require.NoError(t, app.GetKeyStore().Unlock(ctx, "password"))
+ _, err = app.GetKeyStore().P2P().Create(ctx)
+ require.NoError(t, err)
+
+ p2pIDs, err := app.GetKeyStore().P2P().GetAll()
+ require.NoError(t, err)
+ require.Len(t, p2pIDs, 1)
+ peerID := p2pIDs[0].PeerID()
+ // create a transmitter for each chain
+ transmitters := make(map[uint64]common.Address)
+ for chainID, uni := range universes {
+ backend := uni.backend
+ owner := uni.owner
+ cID := uBigInt(chainID)
+ addrs, err2 := app.GetKeyStore().Eth().EnabledAddressesForChain(testutils.Context(t), cID)
+ require.NoError(t, err2)
+ if len(addrs) == 1 {
+ // just fund the address
+ fundAddress(t, owner, addrs[0], assets.Ether(10).ToInt(), backend)
+ transmitters[chainID] = addrs[0]
+ } else {
+ // create key and fund it
+ _, err3 := app.GetKeyStore().Eth().Create(testutils.Context(t), cID)
+ require.NoError(t, err3, "failed to create key for chain", chainID)
+ sendingKeys, err3 := app.GetKeyStore().Eth().EnabledAddressesForChain(testutils.Context(t), cID)
+ require.NoError(t, err3)
+ require.Len(t, sendingKeys, 1)
+ fundAddress(t, owner, sendingKeys[0], assets.Ether(10).ToInt(), backend)
+ transmitters[chainID] = sendingKeys[0]
+ }
+ }
+ require.Len(t, transmitters, len(universes))
+
+ keybundle, err := app.GetKeyStore().OCR2().Create(ctx, chaintype.EVM)
+ require.NoError(t, err)
+
+ t.Cleanup(func() {
+ require.NoError(t, db.Close())
+ })
+
+ return &ocr3Node{
+ // can't use this app because it doesn't have the right toml config
+ // missing bootstrapp
+ app: app,
+ peerID: peerID.Raw(),
+ transmitters: transmitters,
+ keybundle: keybundle,
+ db: db,
+ }
+}
+
+func ptr[T any](v T) *T { return &v }
+
+var _ keystore.Eth = &EthKeystoreSim{}
+
+type EthKeystoreSim struct {
+ keystore.Eth
+ t *testing.T
+}
+
+// override
+func (e *EthKeystoreSim) SignTx(ctx context.Context, address common.Address, tx *gethtypes.Transaction, chainID *big.Int) (*gethtypes.Transaction, error) {
+ // always sign with chain id 1337 for the simulated backend
+ return e.Eth.SignTx(ctx, address, tx, big.NewInt(1337))
+}
+
+type KeystoreSim struct {
+ eks keystore.Eth
+ csa keystore.CSA
+}
+
+func (e KeystoreSim) Eth() keystore.Eth {
+ return e.eks
+}
+
+func (e KeystoreSim) CSA() keystore.CSA {
+ return e.csa
+}
+
+func fundAddress(t *testing.T, from *bind.TransactOpts, to common.Address, amount *big.Int, backend *backends.SimulatedBackend) {
+ nonce, err := backend.PendingNonceAt(testutils.Context(t), from.From)
+ require.NoError(t, err)
+ gp, err := backend.SuggestGasPrice(testutils.Context(t))
+ require.NoError(t, err)
+ rawTx := gethtypes.NewTx(&gethtypes.LegacyTx{
+ Nonce: nonce,
+ GasPrice: gp,
+ Gas: 21000,
+ To: &to,
+ Value: amount,
+ })
+ signedTx, err := from.Signer(from.From, rawTx)
+ require.NoError(t, err)
+ err = backend.SendTransaction(testutils.Context(t), signedTx)
+ require.NoError(t, err)
+ backend.Commit()
+}
+
+func createConfigV2Chain(chainID *big.Int) *v2toml.EVMConfig {
+ chain := v2toml.Defaults((*evmutils.Big)(chainID))
+ chain.GasEstimator.LimitDefault = ptr(uint64(5e6))
+ chain.LogPollInterval = config.MustNewDuration(100 * time.Millisecond)
+ chain.Transactions.ForwardersEnabled = ptr(false)
+ chain.FinalityDepth = ptr(uint32(2))
+ return &v2toml.EVMConfig{
+ ChainID: (*evmutils.Big)(chainID),
+ Enabled: ptr(true),
+ Chain: chain,
+ Nodes: v2toml.EVMNodes{&v2toml.Node{}},
+ }
+}
+
+// Commit blocks periodically in the background for all chains
+func commitBlocksBackground(t *testing.T, universes map[uint64]onchainUniverse, tick *time.Ticker) {
+ t.Log("starting ticker to commit blocks")
+ tickCtx, tickCancel := context.WithCancel(testutils.Context(t))
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for {
+ select {
+ case <-tick.C:
+ for _, uni := range universes {
+ uni.backend.Commit()
+ }
+ case <-tickCtx.Done():
+ return
+ }
+ }
+ }()
+ t.Cleanup(func() {
+ tickCancel()
+ wg.Wait()
+ })
+}
+
+// p2pKeyID: nodes p2p id
+// ocrKeyBundleID: nodes ocr key bundle id
+func mustGetJobSpec(t *testing.T, bootstrapP2PID p2pkey.PeerID, bootstrapPort int, p2pKeyID string, ocrKeyBundleID string) job.Job {
+ specArgs := validate.SpecArgs{
+ P2PV2Bootstrappers: []string{
+ fmt.Sprintf("%s@127.0.0.1:%d", bootstrapP2PID.Raw(), bootstrapPort),
+ },
+ CapabilityVersion: CapabilityVersion,
+ CapabilityLabelledName: CapabilityLabelledName,
+ OCRKeyBundleIDs: map[string]string{
+ relay.NetworkEVM: ocrKeyBundleID,
+ },
+ P2PKeyID: p2pKeyID,
+ PluginConfig: map[string]any{},
+ }
+ specToml, err := validate.NewCCIPSpecToml(specArgs)
+ require.NoError(t, err)
+ jb, err := validate.ValidatedCCIPSpec(specToml)
+ require.NoError(t, err)
+ return jb
+}
diff --git a/core/capabilities/ccip/ccip_integration_tests/ping_pong_test.go b/core/capabilities/ccip/ccip_integration_tests/ping_pong_test.go
new file mode 100644
index 00000000000..8a65ff5167d
--- /dev/null
+++ b/core/capabilities/ccip/ccip_integration_tests/ping_pong_test.go
@@ -0,0 +1,95 @@
+package ccip_integration_tests
+
+import (
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ gethcommon "github.com/ethereum/go-ethereum/common"
+
+ "github.com/stretchr/testify/require"
+
+ "golang.org/x/exp/maps"
+
+ pp "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ping_pong_demo"
+)
+
+/*
+* Test is setting up 3 chains (let's call them A, B, C), each chain deploys and starts 2 ping pong contracts for the other 2.
+* A ---deploy+start---> (pingPongB, pingPongC)
+* B ---deploy+start---> (pingPongA, pingPongC)
+* C ---deploy+start---> (pingPongA, pingPongB)
+* and then checks that each ping pong contract emitted `CCIPSendRequested` event from the expected source to destination.
+* Test fails if any wiring between contracts is not correct.
+ */
+func TestPingPong(t *testing.T) {
+ _, universes := createUniverses(t, 3)
+ pingPongs := initializePingPongContracts(t, universes)
+ for chainID, universe := range universes {
+ for otherChain, pingPong := range pingPongs[chainID] {
+ t.Log("PingPong From: ", chainID, " To: ", otherChain)
+ _, err := pingPong.StartPingPong(universe.owner)
+ require.NoError(t, err)
+ universe.backend.Commit()
+
+ logIter, err := universe.onramp.FilterCCIPSendRequested(&bind.FilterOpts{Start: 0}, nil)
+ require.NoError(t, err)
+ // Iterate until latest event
+ for logIter.Next() {
+ }
+ log := logIter.Event
+ require.Equal(t, getSelector(otherChain), log.DestChainSelector)
+ require.Equal(t, pingPong.Address(), log.Message.Sender)
+ chainPingPongAddr := pingPongs[otherChain][chainID].Address().Bytes()
+ // With chain agnostic addresses we need to pad the address to the correct length if the receiver is zero prefixed
+ paddedAddr := gethcommon.LeftPadBytes(chainPingPongAddr, len(log.Message.Receiver))
+ require.Equal(t, paddedAddr, log.Message.Receiver)
+ }
+ }
+}
+
+// InitializeContracts initializes ping pong contracts on all chains and
+// connects them all to each other.
+func initializePingPongContracts(
+ t *testing.T,
+ chainUniverses map[uint64]onchainUniverse,
+) map[uint64]map[uint64]*pp.PingPongDemo {
+ pingPongs := make(map[uint64]map[uint64]*pp.PingPongDemo)
+ chainIDs := maps.Keys(chainUniverses)
+ // For each chain initialize N ping pong contracts, where N is the (number of chains - 1)
+ for chainID, universe := range chainUniverses {
+ pingPongs[chainID] = make(map[uint64]*pp.PingPongDemo)
+ for _, chainToConnect := range chainIDs {
+ if chainToConnect == chainID {
+ continue // don't connect chain to itself
+ }
+ backend := universe.backend
+ owner := universe.owner
+ pingPongAddr, _, _, err := pp.DeployPingPongDemo(owner, backend, universe.router.Address(), universe.linkToken.Address())
+ require.NoError(t, err)
+ backend.Commit()
+ pingPong, err := pp.NewPingPongDemo(pingPongAddr, backend)
+ require.NoError(t, err)
+ backend.Commit()
+ // Fund the ping pong contract with LINK
+ _, err = universe.linkToken.Transfer(owner, pingPong.Address(), e18Mult(10))
+ backend.Commit()
+ require.NoError(t, err)
+ pingPongs[chainID][chainToConnect] = pingPong
+ }
+ }
+
+ // Set up each ping pong contract to its counterpart on the other chain
+ for chainID, universe := range chainUniverses {
+ for chainToConnect, pingPong := range pingPongs[chainID] {
+ _, err := pingPong.SetCounterpart(
+ universe.owner,
+ getSelector(chainUniverses[chainToConnect].chainID),
+ // This is the address of the ping pong contract on the other chain
+ pingPongs[chainToConnect][chainID].Address(),
+ )
+ require.NoError(t, err)
+ universe.backend.Commit()
+ }
+ }
+ return pingPongs
+}
diff --git a/core/capabilities/ccip/ccipevm/commitcodec.go b/core/capabilities/ccip/ccipevm/commitcodec.go
new file mode 100644
index 00000000000..928cecd0a41
--- /dev/null
+++ b/core/capabilities/ccip/ccipevm/commitcodec.go
@@ -0,0 +1,138 @@
+package ccipevm
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+// CommitPluginCodecV1 is a codec for encoding and decoding commit plugin reports.
+// Compatible with:
+// - "EVM2EVMMultiOffRamp 1.6.0-dev"
+type CommitPluginCodecV1 struct {
+ commitReportAcceptedEventInputs abi.Arguments
+}
+
+func NewCommitPluginCodecV1() *CommitPluginCodecV1 {
+ abiParsed, err := abi.JSON(strings.NewReader(evm_2_evm_multi_offramp.EVM2EVMMultiOffRampABI))
+ if err != nil {
+ panic(fmt.Errorf("parse multi offramp abi: %s", err))
+ }
+ eventInputs := abihelpers.MustGetEventInputs("CommitReportAccepted", abiParsed)
+ return &CommitPluginCodecV1{commitReportAcceptedEventInputs: eventInputs}
+}
+
+func (c *CommitPluginCodecV1) Encode(ctx context.Context, report cciptypes.CommitPluginReport) ([]byte, error) {
+ merkleRoots := make([]evm_2_evm_multi_offramp.EVM2EVMMultiOffRampMerkleRoot, 0, len(report.MerkleRoots))
+ for _, root := range report.MerkleRoots {
+ merkleRoots = append(merkleRoots, evm_2_evm_multi_offramp.EVM2EVMMultiOffRampMerkleRoot{
+ SourceChainSelector: uint64(root.ChainSel),
+ Interval: evm_2_evm_multi_offramp.EVM2EVMMultiOffRampInterval{
+ Min: uint64(root.SeqNumsRange.Start()),
+ Max: uint64(root.SeqNumsRange.End()),
+ },
+ MerkleRoot: root.MerkleRoot,
+ })
+ }
+
+ tokenPriceUpdates := make([]evm_2_evm_multi_offramp.InternalTokenPriceUpdate, 0, len(report.PriceUpdates.TokenPriceUpdates))
+ for _, update := range report.PriceUpdates.TokenPriceUpdates {
+ if !common.IsHexAddress(string(update.TokenID)) {
+ return nil, fmt.Errorf("invalid token address: %s", update.TokenID)
+ }
+ if update.Price.IsEmpty() {
+ return nil, fmt.Errorf("empty price for token: %s", update.TokenID)
+ }
+ tokenPriceUpdates = append(tokenPriceUpdates, evm_2_evm_multi_offramp.InternalTokenPriceUpdate{
+ SourceToken: common.HexToAddress(string(update.TokenID)),
+ UsdPerToken: update.Price.Int,
+ })
+ }
+
+ gasPriceUpdates := make([]evm_2_evm_multi_offramp.InternalGasPriceUpdate, 0, len(report.PriceUpdates.GasPriceUpdates))
+ for _, update := range report.PriceUpdates.GasPriceUpdates {
+ if update.GasPrice.IsEmpty() {
+ return nil, fmt.Errorf("empty gas price for chain: %d", update.ChainSel)
+ }
+
+ gasPriceUpdates = append(gasPriceUpdates, evm_2_evm_multi_offramp.InternalGasPriceUpdate{
+ DestChainSelector: uint64(update.ChainSel),
+ UsdPerUnitGas: update.GasPrice.Int,
+ })
+ }
+
+ evmReport := evm_2_evm_multi_offramp.EVM2EVMMultiOffRampCommitReport{
+ PriceUpdates: evm_2_evm_multi_offramp.InternalPriceUpdates{
+ TokenPriceUpdates: tokenPriceUpdates,
+ GasPriceUpdates: gasPriceUpdates,
+ },
+ MerkleRoots: merkleRoots,
+ }
+
+ return c.commitReportAcceptedEventInputs.PackValues([]interface{}{evmReport})
+}
+
+func (c *CommitPluginCodecV1) Decode(ctx context.Context, bytes []byte) (cciptypes.CommitPluginReport, error) {
+ unpacked, err := c.commitReportAcceptedEventInputs.Unpack(bytes)
+ if err != nil {
+ return cciptypes.CommitPluginReport{}, err
+ }
+ if len(unpacked) != 1 {
+ return cciptypes.CommitPluginReport{}, fmt.Errorf("expected 1 argument, got %d", len(unpacked))
+ }
+
+ commitReportRaw := abi.ConvertType(unpacked[0], new(evm_2_evm_multi_offramp.EVM2EVMMultiOffRampCommitReport))
+ commitReport, is := commitReportRaw.(*evm_2_evm_multi_offramp.EVM2EVMMultiOffRampCommitReport)
+ if !is {
+ return cciptypes.CommitPluginReport{},
+ fmt.Errorf("expected EVM2EVMMultiOffRampCommitReport, got %T", unpacked[0])
+ }
+
+ merkleRoots := make([]cciptypes.MerkleRootChain, 0, len(commitReport.MerkleRoots))
+ for _, root := range commitReport.MerkleRoots {
+ merkleRoots = append(merkleRoots, cciptypes.MerkleRootChain{
+ ChainSel: cciptypes.ChainSelector(root.SourceChainSelector),
+ SeqNumsRange: cciptypes.NewSeqNumRange(
+ cciptypes.SeqNum(root.Interval.Min),
+ cciptypes.SeqNum(root.Interval.Max),
+ ),
+ MerkleRoot: root.MerkleRoot,
+ })
+ }
+
+ tokenPriceUpdates := make([]cciptypes.TokenPrice, 0, len(commitReport.PriceUpdates.TokenPriceUpdates))
+ for _, update := range commitReport.PriceUpdates.TokenPriceUpdates {
+ tokenPriceUpdates = append(tokenPriceUpdates, cciptypes.TokenPrice{
+ TokenID: types.Account(update.SourceToken.String()),
+ Price: cciptypes.NewBigInt(big.NewInt(0).Set(update.UsdPerToken)),
+ })
+ }
+
+ gasPriceUpdates := make([]cciptypes.GasPriceChain, 0, len(commitReport.PriceUpdates.GasPriceUpdates))
+ for _, update := range commitReport.PriceUpdates.GasPriceUpdates {
+ gasPriceUpdates = append(gasPriceUpdates, cciptypes.GasPriceChain{
+ GasPrice: cciptypes.NewBigInt(big.NewInt(0).Set(update.UsdPerUnitGas)),
+ ChainSel: cciptypes.ChainSelector(update.DestChainSelector),
+ })
+ }
+
+ return cciptypes.CommitPluginReport{
+ MerkleRoots: merkleRoots,
+ PriceUpdates: cciptypes.PriceUpdates{
+ TokenPriceUpdates: tokenPriceUpdates,
+ GasPriceUpdates: gasPriceUpdates,
+ },
+ }, nil
+}
+
+// Ensure CommitPluginCodec implements the CommitPluginCodec interface
+var _ cciptypes.CommitPluginCodec = (*CommitPluginCodecV1)(nil)
diff --git a/core/capabilities/ccip/ccipevm/commitcodec_test.go b/core/capabilities/ccip/ccipevm/commitcodec_test.go
new file mode 100644
index 00000000000..737f7be1d6e
--- /dev/null
+++ b/core/capabilities/ccip/ccipevm/commitcodec_test.go
@@ -0,0 +1,135 @@
+package ccipevm
+
+import (
+ "math/big"
+ "math/rand"
+ "testing"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+)
+
+var randomCommitReport = func() cciptypes.CommitPluginReport {
+ return cciptypes.CommitPluginReport{
+ MerkleRoots: []cciptypes.MerkleRootChain{
+ {
+ ChainSel: cciptypes.ChainSelector(rand.Uint64()),
+ SeqNumsRange: cciptypes.NewSeqNumRange(
+ cciptypes.SeqNum(rand.Uint64()),
+ cciptypes.SeqNum(rand.Uint64()),
+ ),
+ MerkleRoot: utils.RandomBytes32(),
+ },
+ {
+ ChainSel: cciptypes.ChainSelector(rand.Uint64()),
+ SeqNumsRange: cciptypes.NewSeqNumRange(
+ cciptypes.SeqNum(rand.Uint64()),
+ cciptypes.SeqNum(rand.Uint64()),
+ ),
+ MerkleRoot: utils.RandomBytes32(),
+ },
+ },
+ PriceUpdates: cciptypes.PriceUpdates{
+ TokenPriceUpdates: []cciptypes.TokenPrice{
+ {
+ TokenID: types.Account(utils.RandomAddress().String()),
+ Price: cciptypes.NewBigInt(utils.RandUint256()),
+ },
+ },
+ GasPriceUpdates: []cciptypes.GasPriceChain{
+ {GasPrice: cciptypes.NewBigInt(utils.RandUint256()), ChainSel: cciptypes.ChainSelector(rand.Uint64())},
+ {GasPrice: cciptypes.NewBigInt(utils.RandUint256()), ChainSel: cciptypes.ChainSelector(rand.Uint64())},
+ {GasPrice: cciptypes.NewBigInt(utils.RandUint256()), ChainSel: cciptypes.ChainSelector(rand.Uint64())},
+ },
+ },
+ }
+}
+
+func TestCommitPluginCodecV1(t *testing.T) {
+ testCases := []struct {
+ name string
+ report func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport
+ expErr bool
+ }{
+ {
+ name: "base report",
+ report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport {
+ return report
+ },
+ },
+ {
+ name: "empty token address",
+ report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport {
+ report.PriceUpdates.TokenPriceUpdates[0].TokenID = ""
+ return report
+ },
+ expErr: true,
+ },
+ {
+ name: "empty merkle root",
+ report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport {
+ report.MerkleRoots[0].MerkleRoot = cciptypes.Bytes32{}
+ return report
+ },
+ },
+ {
+ name: "zero token price",
+ report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport {
+ report.PriceUpdates.TokenPriceUpdates[0].Price = cciptypes.NewBigInt(big.NewInt(0))
+ return report
+ },
+ },
+ {
+ name: "zero gas price",
+ report: func(report cciptypes.CommitPluginReport) cciptypes.CommitPluginReport {
+ report.PriceUpdates.GasPriceUpdates[0].GasPrice = cciptypes.NewBigInt(big.NewInt(0))
+ return report
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ report := tc.report(randomCommitReport())
+ commitCodec := NewCommitPluginCodecV1()
+ ctx := testutils.Context(t)
+ encodedReport, err := commitCodec.Encode(ctx, report)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ require.NoError(t, err)
+ decodedReport, err := commitCodec.Decode(ctx, encodedReport)
+ require.NoError(t, err)
+ require.Equal(t, report, decodedReport)
+ })
+ }
+}
+
+func BenchmarkCommitPluginCodecV1_Encode(b *testing.B) {
+ commitCodec := NewCommitPluginCodecV1()
+ ctx := testutils.Context(b)
+
+ rep := randomCommitReport()
+ for i := 0; i < b.N; i++ {
+ _, err := commitCodec.Encode(ctx, rep)
+ require.NoError(b, err)
+ }
+}
+
+func BenchmarkCommitPluginCodecV1_Decode(b *testing.B) {
+ commitCodec := NewCommitPluginCodecV1()
+ ctx := testutils.Context(b)
+ encodedReport, err := commitCodec.Encode(ctx, randomCommitReport())
+ require.NoError(b, err)
+
+ for i := 0; i < b.N; i++ {
+ _, err := commitCodec.Decode(ctx, encodedReport)
+ require.NoError(b, err)
+ }
+}
diff --git a/core/capabilities/ccip/ccipevm/executecodec.go b/core/capabilities/ccip/ccipevm/executecodec.go
new file mode 100644
index 00000000000..a64c775112c
--- /dev/null
+++ b/core/capabilities/ccip/ccipevm/executecodec.go
@@ -0,0 +1,181 @@
+package ccipevm
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+// ExecutePluginCodecV1 is a codec for encoding and decoding execute plugin reports.
+// Compatible with:
+// - "EVM2EVMMultiOffRamp 1.6.0-dev"
+type ExecutePluginCodecV1 struct {
+ executeReportMethodInputs abi.Arguments
+}
+
+func NewExecutePluginCodecV1() *ExecutePluginCodecV1 {
+ abiParsed, err := abi.JSON(strings.NewReader(evm_2_evm_multi_offramp.EVM2EVMMultiOffRampABI))
+ if err != nil {
+ panic(fmt.Errorf("parse multi offramp abi: %s", err))
+ }
+ methodInputs := abihelpers.MustGetMethodInputs("manuallyExecute", abiParsed)
+ if len(methodInputs) == 0 {
+ panic("no inputs found for method: manuallyExecute")
+ }
+
+ return &ExecutePluginCodecV1{
+ executeReportMethodInputs: methodInputs[:1],
+ }
+}
+
+func (e *ExecutePluginCodecV1) Encode(ctx context.Context, report cciptypes.ExecutePluginReport) ([]byte, error) {
+ evmReport := make([]evm_2_evm_multi_offramp.InternalExecutionReportSingleChain, 0, len(report.ChainReports))
+
+ for _, chainReport := range report.ChainReports {
+ if chainReport.ProofFlagBits.IsEmpty() {
+ return nil, fmt.Errorf("proof flag bits are empty")
+ }
+
+ evmProofs := make([][32]byte, 0, len(chainReport.Proofs))
+ for _, proof := range chainReport.Proofs {
+ evmProofs = append(evmProofs, proof)
+ }
+
+ evmMessages := make([]evm_2_evm_multi_offramp.InternalAny2EVMRampMessage, 0, len(chainReport.Messages))
+ for _, message := range chainReport.Messages {
+ receiver := common.BytesToAddress(message.Receiver)
+
+ tokenAmounts := make([]evm_2_evm_multi_offramp.InternalRampTokenAmount, 0, len(message.TokenAmounts))
+ for _, tokenAmount := range message.TokenAmounts {
+ if tokenAmount.Amount.IsEmpty() {
+ return nil, fmt.Errorf("empty amount for token: %s", tokenAmount.DestTokenAddress)
+ }
+
+ tokenAmounts = append(tokenAmounts, evm_2_evm_multi_offramp.InternalRampTokenAmount{
+ SourcePoolAddress: tokenAmount.SourcePoolAddress,
+ DestTokenAddress: tokenAmount.DestTokenAddress,
+ ExtraData: tokenAmount.ExtraData,
+ Amount: tokenAmount.Amount.Int,
+ })
+ }
+
+ gasLimit, err := decodeExtraArgsV1V2(message.ExtraArgs)
+ if err != nil {
+ return nil, fmt.Errorf("decode extra args to get gas limit: %w", err)
+ }
+
+ evmMessages = append(evmMessages, evm_2_evm_multi_offramp.InternalAny2EVMRampMessage{
+ Header: evm_2_evm_multi_offramp.InternalRampMessageHeader{
+ MessageId: message.Header.MessageID,
+ SourceChainSelector: uint64(message.Header.SourceChainSelector),
+ DestChainSelector: uint64(message.Header.DestChainSelector),
+ SequenceNumber: uint64(message.Header.SequenceNumber),
+ Nonce: message.Header.Nonce,
+ },
+ Sender: message.Sender,
+ Data: message.Data,
+ Receiver: receiver,
+ GasLimit: gasLimit,
+ TokenAmounts: tokenAmounts,
+ })
+ }
+
+ evmChainReport := evm_2_evm_multi_offramp.InternalExecutionReportSingleChain{
+ SourceChainSelector: uint64(chainReport.SourceChainSelector),
+ Messages: evmMessages,
+ OffchainTokenData: chainReport.OffchainTokenData,
+ Proofs: evmProofs,
+ ProofFlagBits: chainReport.ProofFlagBits.Int,
+ }
+ evmReport = append(evmReport, evmChainReport)
+ }
+
+ return e.executeReportMethodInputs.PackValues([]interface{}{&evmReport})
+}
+
+func (e *ExecutePluginCodecV1) Decode(ctx context.Context, encodedReport []byte) (cciptypes.ExecutePluginReport, error) {
+ unpacked, err := e.executeReportMethodInputs.Unpack(encodedReport)
+ if err != nil {
+ return cciptypes.ExecutePluginReport{}, fmt.Errorf("unpack encoded report: %w", err)
+ }
+ if len(unpacked) != 1 {
+ return cciptypes.ExecutePluginReport{}, fmt.Errorf("unpacked report is empty")
+ }
+
+ evmReportRaw := abi.ConvertType(unpacked[0], new([]evm_2_evm_multi_offramp.InternalExecutionReportSingleChain))
+ evmReportPtr, is := evmReportRaw.(*[]evm_2_evm_multi_offramp.InternalExecutionReportSingleChain)
+ if !is {
+ return cciptypes.ExecutePluginReport{}, fmt.Errorf("got an unexpected report type %T", unpacked[0])
+ }
+ if evmReportPtr == nil {
+ return cciptypes.ExecutePluginReport{}, fmt.Errorf("evm report is nil")
+ }
+
+ evmReport := *evmReportPtr
+ executeReport := cciptypes.ExecutePluginReport{
+ ChainReports: make([]cciptypes.ExecutePluginReportSingleChain, 0, len(evmReport)),
+ }
+
+ for _, evmChainReport := range evmReport {
+ proofs := make([]cciptypes.Bytes32, 0, len(evmChainReport.Proofs))
+ for _, proof := range evmChainReport.Proofs {
+ proofs = append(proofs, proof)
+ }
+
+ messages := make([]cciptypes.Message, 0, len(evmChainReport.Messages))
+ for _, evmMessage := range evmChainReport.Messages {
+ tokenAmounts := make([]cciptypes.RampTokenAmount, 0, len(evmMessage.TokenAmounts))
+ for _, tokenAmount := range evmMessage.TokenAmounts {
+ tokenAmounts = append(tokenAmounts, cciptypes.RampTokenAmount{
+ SourcePoolAddress: tokenAmount.SourcePoolAddress,
+ DestTokenAddress: tokenAmount.DestTokenAddress,
+ ExtraData: tokenAmount.ExtraData,
+ Amount: cciptypes.NewBigInt(tokenAmount.Amount),
+ })
+ }
+
+ message := cciptypes.Message{
+ Header: cciptypes.RampMessageHeader{
+ MessageID: evmMessage.Header.MessageId,
+ SourceChainSelector: cciptypes.ChainSelector(evmMessage.Header.SourceChainSelector),
+ DestChainSelector: cciptypes.ChainSelector(evmMessage.Header.DestChainSelector),
+ SequenceNumber: cciptypes.SeqNum(evmMessage.Header.SequenceNumber),
+ Nonce: evmMessage.Header.Nonce,
+ MsgHash: cciptypes.Bytes32{}, // <-- todo: info not available, but not required atm
+ OnRamp: cciptypes.Bytes{}, // <-- todo: info not available, but not required atm
+ },
+ Sender: evmMessage.Sender,
+ Data: evmMessage.Data,
+ Receiver: evmMessage.Receiver.Bytes(),
+ ExtraArgs: cciptypes.Bytes{}, // <-- todo: info not available, but not required atm
+ FeeToken: cciptypes.Bytes{}, // <-- todo: info not available, but not required atm
+ FeeTokenAmount: cciptypes.BigInt{}, // <-- todo: info not available, but not required atm
+ TokenAmounts: tokenAmounts,
+ }
+ messages = append(messages, message)
+ }
+
+ chainReport := cciptypes.ExecutePluginReportSingleChain{
+ SourceChainSelector: cciptypes.ChainSelector(evmChainReport.SourceChainSelector),
+ Messages: messages,
+ OffchainTokenData: evmChainReport.OffchainTokenData,
+ Proofs: proofs,
+ ProofFlagBits: cciptypes.NewBigInt(evmChainReport.ProofFlagBits),
+ }
+
+ executeReport.ChainReports = append(executeReport.ChainReports, chainReport)
+ }
+
+ return executeReport, nil
+}
+
+// Ensure ExecutePluginCodec implements the ExecutePluginCodec interface
+var _ cciptypes.ExecutePluginCodec = (*ExecutePluginCodecV1)(nil)
diff --git a/core/capabilities/ccip/ccipevm/executecodec_test.go b/core/capabilities/ccip/ccipevm/executecodec_test.go
new file mode 100644
index 00000000000..4f207fdb0e2
--- /dev/null
+++ b/core/capabilities/ccip/ccipevm/executecodec_test.go
@@ -0,0 +1,174 @@
+package ccipevm
+
+import (
+ "math/rand"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/core"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/message_hasher"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/report_codec"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+var randomExecuteReport = func(t *testing.T, d *testSetupData) cciptypes.ExecutePluginReport {
+ const numChainReports = 10
+ const msgsPerReport = 10
+ const numTokensPerMsg = 3
+
+ chainReports := make([]cciptypes.ExecutePluginReportSingleChain, numChainReports)
+ for i := 0; i < numChainReports; i++ {
+ reportMessages := make([]cciptypes.Message, msgsPerReport)
+ for j := 0; j < msgsPerReport; j++ {
+ data, err := cciptypes.NewBytesFromString(utils.RandomAddress().String())
+ assert.NoError(t, err)
+
+ tokenAmounts := make([]cciptypes.RampTokenAmount, numTokensPerMsg)
+ for z := 0; z < numTokensPerMsg; z++ {
+ tokenAmounts[z] = cciptypes.RampTokenAmount{
+ SourcePoolAddress: utils.RandomAddress().Bytes(),
+ DestTokenAddress: utils.RandomAddress().Bytes(),
+ ExtraData: data,
+ Amount: cciptypes.NewBigInt(utils.RandUint256()),
+ }
+ }
+
+ extraArgs, err := d.contract.EncodeEVMExtraArgsV1(nil, message_hasher.ClientEVMExtraArgsV1{
+ GasLimit: utils.RandUint256(),
+ })
+ assert.NoError(t, err)
+
+ reportMessages[j] = cciptypes.Message{
+ Header: cciptypes.RampMessageHeader{
+ MessageID: utils.RandomBytes32(),
+ SourceChainSelector: cciptypes.ChainSelector(rand.Uint64()),
+ DestChainSelector: cciptypes.ChainSelector(rand.Uint64()),
+ SequenceNumber: cciptypes.SeqNum(rand.Uint64()),
+ Nonce: rand.Uint64(),
+ MsgHash: utils.RandomBytes32(),
+ OnRamp: utils.RandomAddress().Bytes(),
+ },
+ Sender: utils.RandomAddress().Bytes(),
+ Data: data,
+ Receiver: utils.RandomAddress().Bytes(),
+ ExtraArgs: extraArgs,
+ FeeToken: utils.RandomAddress().Bytes(),
+ FeeTokenAmount: cciptypes.NewBigInt(utils.RandUint256()),
+ TokenAmounts: tokenAmounts,
+ }
+ }
+
+ tokenData := make([][][]byte, numTokensPerMsg)
+ for j := 0; j < numTokensPerMsg; j++ {
+ tokenData[j] = [][]byte{{0x1}, {0x2, 0x3}}
+ }
+
+ chainReports[i] = cciptypes.ExecutePluginReportSingleChain{
+ SourceChainSelector: cciptypes.ChainSelector(rand.Uint64()),
+ Messages: reportMessages,
+ OffchainTokenData: tokenData,
+ Proofs: []cciptypes.Bytes32{utils.RandomBytes32(), utils.RandomBytes32()},
+ ProofFlagBits: cciptypes.NewBigInt(utils.RandUint256()),
+ }
+ }
+
+ return cciptypes.ExecutePluginReport{ChainReports: chainReports}
+}
+
+func TestExecutePluginCodecV1(t *testing.T) {
+ d := testSetup(t)
+
+ testCases := []struct {
+ name string
+ report func(report cciptypes.ExecutePluginReport) cciptypes.ExecutePluginReport
+ expErr bool
+ }{
+ {
+ name: "base report",
+ report: func(report cciptypes.ExecutePluginReport) cciptypes.ExecutePluginReport { return report },
+ expErr: false,
+ },
+ {
+ name: "reports have empty msgs",
+ report: func(report cciptypes.ExecutePluginReport) cciptypes.ExecutePluginReport {
+ report.ChainReports[0].Messages = []cciptypes.Message{}
+ report.ChainReports[4].Messages = []cciptypes.Message{}
+ return report
+ },
+ expErr: false,
+ },
+ {
+ name: "reports have empty offchain token data",
+ report: func(report cciptypes.ExecutePluginReport) cciptypes.ExecutePluginReport {
+ report.ChainReports[0].OffchainTokenData = [][][]byte{}
+ report.ChainReports[4].OffchainTokenData[1] = [][]byte{}
+ return report
+ },
+ expErr: false,
+ },
+ }
+
+ ctx := testutils.Context(t)
+
+ // Deploy the contract
+ transactor := testutils.MustNewSimTransactor(t)
+ simulatedBackend := backends.NewSimulatedBackend(core.GenesisAlloc{
+ transactor.From: {Balance: assets.Ether(1000).ToInt()},
+ }, 30e6)
+ address, _, _, err := report_codec.DeployReportCodec(transactor, simulatedBackend)
+ require.NoError(t, err)
+ simulatedBackend.Commit()
+ contract, err := report_codec.NewReportCodec(address, simulatedBackend)
+ require.NoError(t, err)
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ codec := NewExecutePluginCodecV1()
+ report := tc.report(randomExecuteReport(t, d))
+ bytes, err := codec.Encode(ctx, report)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+
+ testSetup(t)
+
+ // ignore msg hash in comparison
+ for i := range report.ChainReports {
+ for j := range report.ChainReports[i].Messages {
+ report.ChainReports[i].Messages[j].Header.MsgHash = cciptypes.Bytes32{}
+ report.ChainReports[i].Messages[j].Header.OnRamp = cciptypes.Bytes{}
+ report.ChainReports[i].Messages[j].FeeToken = cciptypes.Bytes{}
+ report.ChainReports[i].Messages[j].ExtraArgs = cciptypes.Bytes{}
+ report.ChainReports[i].Messages[j].FeeTokenAmount = cciptypes.BigInt{}
+ }
+ }
+
+ // decode using the contract
+ contractDecodedReport, err := contract.DecodeExecuteReport(&bind.CallOpts{Context: ctx}, bytes)
+ assert.NoError(t, err)
+ assert.Equal(t, len(report.ChainReports), len(contractDecodedReport))
+ for i, expReport := range report.ChainReports {
+ actReport := contractDecodedReport[i]
+ assert.Equal(t, expReport.OffchainTokenData, actReport.OffchainTokenData)
+ assert.Equal(t, len(expReport.Messages), len(actReport.Messages))
+ assert.Equal(t, uint64(expReport.SourceChainSelector), actReport.SourceChainSelector)
+ }
+
+ // decode using the codec
+ codecDecoded, err := codec.Decode(ctx, bytes)
+ assert.NoError(t, err)
+ assert.Equal(t, report, codecDecoded)
+ })
+ }
+}
diff --git a/core/capabilities/ccip/ccipevm/helpers.go b/core/capabilities/ccip/ccipevm/helpers.go
new file mode 100644
index 00000000000..ee83230a4ce
--- /dev/null
+++ b/core/capabilities/ccip/ccipevm/helpers.go
@@ -0,0 +1,33 @@
+package ccipevm
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+)
+
+func decodeExtraArgsV1V2(extraArgs []byte) (gasLimit *big.Int, err error) {
+ if len(extraArgs) < 4 {
+ return nil, fmt.Errorf("extra args too short: %d, should be at least 4 (i.e the extraArgs tag)", len(extraArgs))
+ }
+
+ var method string
+ if bytes.Equal(extraArgs[:4], evmExtraArgsV1Tag) {
+ method = "decodeEVMExtraArgsV1"
+ } else if bytes.Equal(extraArgs[:4], evmExtraArgsV2Tag) {
+ method = "decodeEVMExtraArgsV2"
+ } else {
+ return nil, fmt.Errorf("unknown extra args tag: %x", extraArgs)
+ }
+ ifaces, err := messageHasherABI.Methods[method].Inputs.UnpackValues(extraArgs[4:])
+ if err != nil {
+ return nil, fmt.Errorf("abi decode extra args v1: %w", err)
+ }
+ // gas limit is always the first argument, and allow OOO isn't set explicitly
+ // on the message.
+ _, ok := ifaces[0].(*big.Int)
+ if !ok {
+ return nil, fmt.Errorf("expected *big.Int, got %T", ifaces[0])
+ }
+ return ifaces[0].(*big.Int), nil
+}
diff --git a/core/capabilities/ccip/ccipevm/helpers_test.go b/core/capabilities/ccip/ccipevm/helpers_test.go
new file mode 100644
index 00000000000..95a5d4439bb
--- /dev/null
+++ b/core/capabilities/ccip/ccipevm/helpers_test.go
@@ -0,0 +1,41 @@
+package ccipevm
+
+import (
+ "math/big"
+ "math/rand"
+ "testing"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/message_hasher"
+
+ "github.com/stretchr/testify/require"
+)
+
+func Test_decodeExtraArgs(t *testing.T) {
+ d := testSetup(t)
+ gasLimit := big.NewInt(rand.Int63())
+
+ t.Run("v1", func(t *testing.T) {
+ encoded, err := d.contract.EncodeEVMExtraArgsV1(nil, message_hasher.ClientEVMExtraArgsV1{
+ GasLimit: gasLimit,
+ })
+ require.NoError(t, err)
+
+ decodedGasLimit, err := decodeExtraArgsV1V2(encoded)
+ require.NoError(t, err)
+
+ require.Equal(t, gasLimit, decodedGasLimit)
+ })
+
+ t.Run("v2", func(t *testing.T) {
+ encoded, err := d.contract.EncodeEVMExtraArgsV2(nil, message_hasher.ClientEVMExtraArgsV2{
+ GasLimit: gasLimit,
+ AllowOutOfOrderExecution: true,
+ })
+ require.NoError(t, err)
+
+ decodedGasLimit, err := decodeExtraArgsV1V2(encoded)
+ require.NoError(t, err)
+
+ require.Equal(t, gasLimit, decodedGasLimit)
+ })
+}
diff --git a/core/capabilities/ccip/ccipevm/msghasher.go b/core/capabilities/ccip/ccipevm/msghasher.go
new file mode 100644
index 00000000000..0df0a8254ac
--- /dev/null
+++ b/core/capabilities/ccip/ccipevm/msghasher.go
@@ -0,0 +1,127 @@
+package ccipevm
+
+import (
+ "context"
+ "fmt"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/message_hasher"
+)
+
+var (
+ // bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000;
+ leafDomainSeparator = [32]byte{}
+
+ // bytes32 internal constant ANY_2_EVM_MESSAGE_HASH = keccak256("Any2EVMMessageHashV1");
+ ANY_2_EVM_MESSAGE_HASH = utils.Keccak256Fixed([]byte("Any2EVMMessageHashV1"))
+
+ messageHasherABI = types.MustGetABI(message_hasher.MessageHasherABI)
+
+ // bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;
+ evmExtraArgsV1Tag = hexutil.MustDecode("0x97a657c9")
+
+ // bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10;
+ evmExtraArgsV2Tag = hexutil.MustDecode("0x181dcf10")
+)
+
+// MessageHasherV1 implements the MessageHasher interface.
+// Compatible with:
+// - "EVM2EVMMultiOnRamp 1.6.0-dev"
+type MessageHasherV1 struct{}
+
+func NewMessageHasherV1() *MessageHasherV1 {
+ return &MessageHasherV1{}
+}
+
+// Hash implements the MessageHasher interface.
+// It constructs all of the inputs to the final keccak256 hash in Internal._hash(Any2EVMRampMessage).
+// The main structure of the hash is as follows:
+/*
+ keccak256(
+ leafDomainSeparator,
+ keccak256(any_2_evm_message_hash, header.sourceChainSelector, header.destinationChainSelector, onRamp),
+ keccak256(fixedSizeMessageFields),
+ keccak256(messageData),
+ keccak256(encodedRampTokenAmounts),
+ )
+*/
+func (h *MessageHasherV1) Hash(_ context.Context, msg cciptypes.Message) (cciptypes.Bytes32, error) {
+ var rampTokenAmounts []message_hasher.InternalRampTokenAmount
+ for _, rta := range msg.TokenAmounts {
+ rampTokenAmounts = append(rampTokenAmounts, message_hasher.InternalRampTokenAmount{
+ SourcePoolAddress: rta.SourcePoolAddress,
+ DestTokenAddress: rta.DestTokenAddress,
+ ExtraData: rta.ExtraData,
+ Amount: rta.Amount.Int,
+ })
+ }
+ encodedRampTokenAmounts, err := abiEncode("encodeTokenAmountsHashPreimage", rampTokenAmounts)
+ if err != nil {
+ return [32]byte{}, fmt.Errorf("abi encode token amounts: %w", err)
+ }
+
+ metaDataHashInput, err := abiEncode(
+ "encodeMetadataHashPreimage",
+ ANY_2_EVM_MESSAGE_HASH,
+ uint64(msg.Header.SourceChainSelector),
+ uint64(msg.Header.DestChainSelector),
+ []byte(msg.Header.OnRamp),
+ )
+ if err != nil {
+ return [32]byte{}, fmt.Errorf("abi encode metadata hash input: %w", err)
+ }
+
+ // Need to decode the extra args to get the gas limit.
+ // TODO: we assume that extra args is always abi-encoded for now, but we need
+ // to decode according to source chain selector family. We should add a family
+ // lookup API to the chain-selectors library.
+ gasLimit, err := decodeExtraArgsV1V2(msg.ExtraArgs)
+ if err != nil {
+ return [32]byte{}, fmt.Errorf("decode extra args: %w", err)
+ }
+
+ fixedSizeFieldsEncoded, err := abiEncode(
+ "encodeFixedSizeFieldsHashPreimage",
+ msg.Header.MessageID,
+ []byte(msg.Sender),
+ common.BytesToAddress(msg.Receiver),
+ uint64(msg.Header.SequenceNumber),
+ gasLimit,
+ msg.Header.Nonce,
+ )
+ if err != nil {
+ return [32]byte{}, fmt.Errorf("abi encode fixed size values: %w", err)
+ }
+
+ packedValues, err := abiEncode(
+ "encodeFinalHashPreimage",
+ leafDomainSeparator,
+ utils.Keccak256Fixed(metaDataHashInput),
+ utils.Keccak256Fixed(fixedSizeFieldsEncoded),
+ utils.Keccak256Fixed(msg.Data),
+ utils.Keccak256Fixed(encodedRampTokenAmounts),
+ )
+ if err != nil {
+ return [32]byte{}, fmt.Errorf("abi encode packed values: %w", err)
+ }
+
+ return utils.Keccak256Fixed(packedValues), nil
+}
+
+func abiEncode(method string, values ...interface{}) ([]byte, error) {
+ res, err := messageHasherABI.Pack(method, values...)
+ if err != nil {
+ return nil, err
+ }
+ // trim the method selector.
+ return res[4:], nil
+}
+
+// Interface compliance check
+var _ cciptypes.MessageHasher = (*MessageHasherV1)(nil)
diff --git a/core/capabilities/ccip/ccipevm/msghasher_test.go b/core/capabilities/ccip/ccipevm/msghasher_test.go
new file mode 100644
index 00000000000..911a10b26a5
--- /dev/null
+++ b/core/capabilities/ccip/ccipevm/msghasher_test.go
@@ -0,0 +1,189 @@
+package ccipevm
+
+import (
+ "context"
+ cryptorand "crypto/rand"
+ "fmt"
+ "math/big"
+ "math/rand"
+ "strings"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/message_hasher"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+)
+
+// NOTE: these test cases are only EVM <-> EVM.
+// Update these cases once we have non-EVM examples.
+func TestMessageHasher_EVM2EVM(t *testing.T) {
+ ctx := testutils.Context(t)
+ d := testSetup(t)
+
+ testCases := []evmExtraArgs{
+ {version: "v1", gasLimit: big.NewInt(rand.Int63())},
+ {version: "v2", gasLimit: big.NewInt(rand.Int63()), allowOOO: false},
+ {version: "v2", gasLimit: big.NewInt(rand.Int63()), allowOOO: true},
+ }
+ for i, tc := range testCases {
+ t.Run(fmt.Sprintf("tc_%d", i), func(tt *testing.T) {
+ testHasherEVM2EVM(ctx, tt, d, tc)
+ })
+ }
+}
+
+func testHasherEVM2EVM(ctx context.Context, t *testing.T, d *testSetupData, evmExtraArgs evmExtraArgs) {
+ ccipMsg := createEVM2EVMMessage(t, d.contract, evmExtraArgs)
+
+ var tokenAmounts []message_hasher.InternalRampTokenAmount
+ for _, rta := range ccipMsg.TokenAmounts {
+ tokenAmounts = append(tokenAmounts, message_hasher.InternalRampTokenAmount{
+ SourcePoolAddress: rta.SourcePoolAddress,
+ DestTokenAddress: rta.DestTokenAddress,
+ ExtraData: rta.ExtraData[:],
+ Amount: rta.Amount.Int,
+ })
+ }
+ evmMsg := message_hasher.InternalAny2EVMRampMessage{
+ Header: message_hasher.InternalRampMessageHeader{
+ MessageId: ccipMsg.Header.MessageID,
+ SourceChainSelector: uint64(ccipMsg.Header.SourceChainSelector),
+ DestChainSelector: uint64(ccipMsg.Header.DestChainSelector),
+ SequenceNumber: uint64(ccipMsg.Header.SequenceNumber),
+ Nonce: ccipMsg.Header.Nonce,
+ },
+ Sender: ccipMsg.Sender,
+ Receiver: common.BytesToAddress(ccipMsg.Receiver),
+ GasLimit: evmExtraArgs.gasLimit,
+ Data: ccipMsg.Data,
+ TokenAmounts: tokenAmounts,
+ }
+
+ expectedHash, err := d.contract.Hash(&bind.CallOpts{Context: ctx}, evmMsg, ccipMsg.Header.OnRamp)
+ require.NoError(t, err)
+
+ evmMsgHasher := NewMessageHasherV1()
+ actualHash, err := evmMsgHasher.Hash(ctx, ccipMsg)
+ require.NoError(t, err)
+
+ require.Equal(t, fmt.Sprintf("%x", expectedHash), strings.TrimPrefix(actualHash.String(), "0x"))
+}
+
+type evmExtraArgs struct {
+ version string
+ gasLimit *big.Int
+ allowOOO bool
+}
+
+func createEVM2EVMMessage(t *testing.T, messageHasher *message_hasher.MessageHasher, evmExtraArgs evmExtraArgs) cciptypes.Message {
+ messageID := utils.RandomBytes32()
+
+ sourceTokenData := make([]byte, rand.Intn(2048))
+ _, err := cryptorand.Read(sourceTokenData)
+ require.NoError(t, err)
+
+ sourceChain := rand.Uint64()
+ seqNum := rand.Uint64()
+ nonce := rand.Uint64()
+ destChain := rand.Uint64()
+
+ var extraArgsBytes []byte
+ if evmExtraArgs.version == "v1" {
+ extraArgsBytes, err = messageHasher.EncodeEVMExtraArgsV1(nil, message_hasher.ClientEVMExtraArgsV1{
+ GasLimit: evmExtraArgs.gasLimit,
+ })
+ require.NoError(t, err)
+ } else if evmExtraArgs.version == "v2" {
+ extraArgsBytes, err = messageHasher.EncodeEVMExtraArgsV2(nil, message_hasher.ClientEVMExtraArgsV2{
+ GasLimit: evmExtraArgs.gasLimit,
+ AllowOutOfOrderExecution: evmExtraArgs.allowOOO,
+ })
+ require.NoError(t, err)
+ } else {
+ require.FailNowf(t, "unknown extra args version", "version: %s", evmExtraArgs.version)
+ }
+
+ messageData := make([]byte, rand.Intn(2048))
+ _, err = cryptorand.Read(messageData)
+ require.NoError(t, err)
+
+ numTokens := rand.Intn(10)
+ var sourceTokenDatas [][]byte
+ for i := 0; i < numTokens; i++ {
+ sourceTokenDatas = append(sourceTokenDatas, sourceTokenData)
+ }
+
+ var tokenAmounts []cciptypes.RampTokenAmount
+ for i := 0; i < len(sourceTokenDatas); i++ {
+ extraData := utils.RandomBytes32()
+ tokenAmounts = append(tokenAmounts, cciptypes.RampTokenAmount{
+ SourcePoolAddress: abiEncodedAddress(t),
+ DestTokenAddress: abiEncodedAddress(t),
+ ExtraData: extraData[:],
+ Amount: cciptypes.NewBigInt(big.NewInt(0).SetUint64(rand.Uint64())),
+ })
+ }
+
+ return cciptypes.Message{
+ Header: cciptypes.RampMessageHeader{
+ MessageID: messageID,
+ SourceChainSelector: cciptypes.ChainSelector(sourceChain),
+ DestChainSelector: cciptypes.ChainSelector(destChain),
+ SequenceNumber: cciptypes.SeqNum(seqNum),
+ Nonce: nonce,
+ OnRamp: abiEncodedAddress(t),
+ },
+ Sender: abiEncodedAddress(t),
+ Receiver: abiEncodedAddress(t),
+ Data: messageData,
+ TokenAmounts: tokenAmounts,
+ FeeToken: abiEncodedAddress(t),
+ FeeTokenAmount: cciptypes.NewBigInt(big.NewInt(0).SetUint64(rand.Uint64())),
+ ExtraArgs: extraArgsBytes,
+ }
+}
+
+func abiEncodedAddress(t *testing.T) []byte {
+ addr := utils.RandomAddress()
+ encoded, err := utils.ABIEncode(`[{"type": "address"}]`, addr)
+ require.NoError(t, err)
+ return encoded
+}
+
+type testSetupData struct {
+ contractAddr common.Address
+ contract *message_hasher.MessageHasher
+ sb *backends.SimulatedBackend
+ auth *bind.TransactOpts
+}
+
+func testSetup(t *testing.T) *testSetupData {
+ transactor := testutils.MustNewSimTransactor(t)
+ simulatedBackend := backends.NewSimulatedBackend(core.GenesisAlloc{
+ transactor.From: {Balance: assets.Ether(1000).ToInt()},
+ }, 30e6)
+
+ // Deploy the contract
+ address, _, _, err := message_hasher.DeployMessageHasher(transactor, simulatedBackend)
+ require.NoError(t, err)
+ simulatedBackend.Commit()
+
+ // Setup contract client
+ contract, err := message_hasher.NewMessageHasher(address, simulatedBackend)
+ require.NoError(t, err)
+
+ return &testSetupData{
+ contractAddr: address,
+ contract: contract,
+ sb: simulatedBackend,
+ auth: transactor,
+ }
+}
diff --git a/core/capabilities/ccip/common/common.go b/core/capabilities/ccip/common/common.go
new file mode 100644
index 00000000000..6409345ed93
--- /dev/null
+++ b/core/capabilities/ccip/common/common.go
@@ -0,0 +1,23 @@
+package common
+
+import (
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/crypto"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+)
+
+// HashedCapabilityID returns the hashed capability id in a manner equivalent to the capability registry.
+func HashedCapabilityID(capabilityLabelledName, capabilityVersion string) (r [32]byte, err error) {
+ // TODO: investigate how to avoid parsing the ABI everytime.
+ tabi := `[{"type": "string"}, {"type": "string"}]`
+ abiEncoded, err := utils.ABIEncode(tabi, capabilityLabelledName, capabilityVersion)
+ if err != nil {
+ return r, fmt.Errorf("failed to ABI encode capability version and labelled name: %w", err)
+ }
+
+ h := crypto.Keccak256(abiEncoded)
+ copy(r[:], h)
+ return r, nil
+}
diff --git a/core/capabilities/ccip/common/common_test.go b/core/capabilities/ccip/common/common_test.go
new file mode 100644
index 00000000000..a7484a83ad9
--- /dev/null
+++ b/core/capabilities/ccip/common/common_test.go
@@ -0,0 +1,51 @@
+package common_test
+
+import (
+ "testing"
+
+ capcommon "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/common"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+)
+
+func Test_HashedCapabilityId(t *testing.T) {
+ transactor := testutils.MustNewSimTransactor(t)
+ sb := backends.NewSimulatedBackend(core.GenesisAlloc{
+ transactor.From: {Balance: assets.Ether(1000).ToInt()},
+ }, 30e6)
+
+ crAddress, _, _, err := kcr.DeployCapabilitiesRegistry(transactor, sb)
+ require.NoError(t, err)
+ sb.Commit()
+
+ cr, err := kcr.NewCapabilitiesRegistry(crAddress, sb)
+ require.NoError(t, err)
+
+ // add a capability, ignore cap config for simplicity.
+ _, err = cr.AddCapabilities(transactor, []kcr.CapabilitiesRegistryCapability{
+ {
+ LabelledName: "ccip",
+ Version: "v1.0.0",
+ CapabilityType: 0,
+ ResponseType: 0,
+ ConfigurationContract: common.Address{},
+ },
+ })
+ require.NoError(t, err)
+ sb.Commit()
+
+ hidExpected, err := cr.GetHashedCapabilityId(nil, "ccip", "v1.0.0")
+ require.NoError(t, err)
+
+ hid, err := capcommon.HashedCapabilityID("ccip", "v1.0.0")
+ require.NoError(t, err)
+
+ require.Equal(t, hidExpected, hid)
+}
diff --git a/core/capabilities/ccip/configs/evm/chain_writer.go b/core/capabilities/ccip/configs/evm/chain_writer.go
new file mode 100644
index 00000000000..6d3b73c6f5c
--- /dev/null
+++ b/core/capabilities/ccip/configs/evm/chain_writer.go
@@ -0,0 +1,75 @@
+package evm
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common"
+
+ "github.com/smartcontractkit/chainlink-ccip/pkg/consts"
+ "github.com/smartcontractkit/chainlink/v2/common/txmgr"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp"
+ evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
+)
+
+var (
+ offrampABI = evmtypes.MustGetABI(evm_2_evm_multi_offramp.EVM2EVMMultiOffRampABI)
+)
+
+func MustChainWriterConfig(
+ fromAddress common.Address,
+ maxGasPrice *assets.Wei,
+ commitGasLimit,
+ execBatchGasLimit uint64,
+) []byte {
+ rawConfig := ChainWriterConfigRaw(fromAddress, maxGasPrice, commitGasLimit, execBatchGasLimit)
+ encoded, err := json.Marshal(rawConfig)
+ if err != nil {
+ panic(fmt.Errorf("failed to marshal ChainWriterConfig: %w", err))
+ }
+
+ return encoded
+}
+
+// ChainWriterConfigRaw returns a ChainWriterConfig that can be used to transmit commit and execute reports.
+func ChainWriterConfigRaw(
+ fromAddress common.Address,
+ maxGasPrice *assets.Wei,
+ commitGasLimit,
+ execBatchGasLimit uint64,
+) evmrelaytypes.ChainWriterConfig {
+ return evmrelaytypes.ChainWriterConfig{
+ Contracts: map[string]*evmrelaytypes.ContractConfig{
+ consts.ContractNameOffRamp: {
+ ContractABI: evm_2_evm_multi_offramp.EVM2EVMMultiOffRampABI,
+ Configs: map[string]*evmrelaytypes.ChainWriterDefinition{
+ consts.MethodCommit: {
+ ChainSpecificName: mustGetMethodName("commit", offrampABI),
+ FromAddress: fromAddress,
+ GasLimit: commitGasLimit,
+ },
+ consts.MethodExecute: {
+ ChainSpecificName: mustGetMethodName("execute", offrampABI),
+ FromAddress: fromAddress,
+ GasLimit: execBatchGasLimit,
+ },
+ },
+ },
+ },
+ SendStrategy: txmgr.NewSendEveryStrategy(),
+ MaxGasPrice: maxGasPrice,
+ }
+}
+
+// mustGetMethodName panics if the method name is not found in the provided ABI.
+func mustGetMethodName(name string, tabi abi.ABI) (methodName string) {
+ m, ok := tabi.Methods[name]
+ if !ok {
+ panic(fmt.Sprintf("missing method %s in the abi", name))
+ }
+ return m.Name
+}
diff --git a/core/capabilities/ccip/configs/evm/contract_reader.go b/core/capabilities/ccip/configs/evm/contract_reader.go
new file mode 100644
index 00000000000..085729690d5
--- /dev/null
+++ b/core/capabilities/ccip/configs/evm/contract_reader.go
@@ -0,0 +1,219 @@
+package evm
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+
+ "github.com/smartcontractkit/chainlink-ccip/pkg/consts"
+
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_multi_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry"
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+ evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
+)
+
+var (
+ onrampABI = evmtypes.MustGetABI(evm_2_evm_multi_onramp.EVM2EVMMultiOnRampABI)
+ capabilitiesRegsitryABI = evmtypes.MustGetABI(kcr.CapabilitiesRegistryABI)
+ ccipConfigABI = evmtypes.MustGetABI(ccip_config.CCIPConfigABI)
+ priceRegistryABI = evmtypes.MustGetABI(price_registry.PriceRegistryABI)
+)
+
+// MustSourceReaderConfig returns a ChainReaderConfig that can be used to read from the onramp.
+// The configuration is marshaled into JSON so that it can be passed to the relayer NewContractReader() method.
+func MustSourceReaderConfig() []byte {
+ rawConfig := SourceReaderConfig()
+ encoded, err := json.Marshal(rawConfig)
+ if err != nil {
+ panic(fmt.Errorf("failed to marshal ChainReaderConfig into JSON: %w", err))
+ }
+
+ return encoded
+}
+
+// MustDestReaderConfig returns a ChainReaderConfig that can be used to read from the offramp.
+// The configuration is marshaled into JSON so that it can be passed to the relayer NewContractReader() method.
+func MustDestReaderConfig() []byte {
+ rawConfig := DestReaderConfig()
+ encoded, err := json.Marshal(rawConfig)
+ if err != nil {
+ panic(fmt.Errorf("failed to marshal ChainReaderConfig into JSON: %w", err))
+ }
+
+ return encoded
+}
+
+// DestReaderConfig returns a ChainReaderConfig that can be used to read from the offramp.
+func DestReaderConfig() evmrelaytypes.ChainReaderConfig {
+ return evmrelaytypes.ChainReaderConfig{
+ Contracts: map[string]evmrelaytypes.ChainContractReader{
+ consts.ContractNameOffRamp: {
+ ContractABI: evm_2_evm_multi_offramp.EVM2EVMMultiOffRampABI,
+ ContractPollingFilter: evmrelaytypes.ContractPollingFilter{
+ GenericEventNames: []string{
+ mustGetEventName(consts.EventNameExecutionStateChanged, offrampABI),
+ mustGetEventName(consts.EventNameCommitReportAccepted, offrampABI),
+ },
+ },
+ Configs: map[string]*evmrelaytypes.ChainReaderDefinition{
+ consts.MethodNameGetExecutionState: {
+ ChainSpecificName: mustGetMethodName("getExecutionState", offrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.MethodNameGetMerkleRoot: {
+ ChainSpecificName: mustGetMethodName("getMerkleRoot", offrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.MethodNameIsBlessed: {
+ ChainSpecificName: mustGetMethodName("isBlessed", offrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.MethodNameGetLatestPriceSequenceNumber: {
+ ChainSpecificName: mustGetMethodName("getLatestPriceSequenceNumber", offrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.MethodNameOfframpGetStaticConfig: {
+ ChainSpecificName: mustGetMethodName("getStaticConfig", offrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.MethodNameOfframpGetDynamicConfig: {
+ ChainSpecificName: mustGetMethodName("getDynamicConfig", offrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.MethodNameGetSourceChainConfig: {
+ ChainSpecificName: mustGetMethodName("getSourceChainConfig", offrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.EventNameCommitReportAccepted: {
+ ChainSpecificName: mustGetEventName(consts.EventNameCommitReportAccepted, offrampABI),
+ ReadType: evmrelaytypes.Event,
+ },
+ consts.EventNameExecutionStateChanged: {
+ ChainSpecificName: mustGetEventName(consts.EventNameExecutionStateChanged, offrampABI),
+ ReadType: evmrelaytypes.Event,
+ },
+ },
+ },
+ },
+ }
+}
+
+// SourceReaderConfig returns a ChainReaderConfig that can be used to read from the onramp.
+func SourceReaderConfig() evmrelaytypes.ChainReaderConfig {
+ return evmrelaytypes.ChainReaderConfig{
+ Contracts: map[string]evmrelaytypes.ChainContractReader{
+ consts.ContractNameOnRamp: {
+ ContractABI: evm_2_evm_multi_onramp.EVM2EVMMultiOnRampABI,
+ ContractPollingFilter: evmrelaytypes.ContractPollingFilter{
+ GenericEventNames: []string{
+ mustGetEventName(consts.EventNameCCIPSendRequested, onrampABI),
+ },
+ },
+ Configs: map[string]*evmrelaytypes.ChainReaderDefinition{
+ // all "{external|public} view" functions in the onramp except for getFee and getPoolBySourceToken are here.
+ // getFee is not expected to get called offchain and is only called by end-user contracts.
+ consts.MethodNameGetExpectedNextSequenceNumber: {
+ ChainSpecificName: mustGetMethodName("getExpectedNextSequenceNumber", onrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.MethodNameOnrampGetStaticConfig: {
+ ChainSpecificName: mustGetMethodName("getStaticConfig", onrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.MethodNameOnrampGetDynamicConfig: {
+ ChainSpecificName: mustGetMethodName("getDynamicConfig", onrampABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ consts.EventNameCCIPSendRequested: {
+ ChainSpecificName: mustGetEventName(consts.EventNameCCIPSendRequested, onrampABI),
+ ReadType: evmrelaytypes.Event,
+ EventDefinitions: &evmrelaytypes.EventDefinitions{
+ GenericDataWordNames: map[string]uint8{
+ consts.EventAttributeSequenceNumber: 5,
+ },
+ },
+ },
+ },
+ },
+ consts.ContractNamePriceRegistry: {
+ ContractABI: price_registry.PriceRegistryABI,
+ Configs: map[string]*evmrelaytypes.ChainReaderDefinition{
+ // TODO: update with the consts from https://github.com/smartcontractkit/chainlink-ccip/pull/39
+ // in a followup.
+ "GetStaticConfig": {
+ ChainSpecificName: mustGetMethodName("getStaticConfig", priceRegistryABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ "GetDestChainConfig": {
+ ChainSpecificName: mustGetMethodName("getDestChainConfig", priceRegistryABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ "GetPremiumMultiplierWeiPerEth": {
+ ChainSpecificName: mustGetMethodName("getPremiumMultiplierWeiPerEth", priceRegistryABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ "GetTokenTransferFeeConfig": {
+ ChainSpecificName: mustGetMethodName("getTokenTransferFeeConfig", priceRegistryABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ "ProcessMessageArgs": {
+ ChainSpecificName: mustGetMethodName("processMessageArgs", priceRegistryABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ "ValidatePoolReturnData": {
+ ChainSpecificName: mustGetMethodName("validatePoolReturnData", priceRegistryABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ "GetValidatedTokenPrice": {
+ ChainSpecificName: mustGetMethodName("getValidatedTokenPrice", priceRegistryABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ "GetFeeTokens": {
+ ChainSpecificName: mustGetMethodName("getFeeTokens", priceRegistryABI),
+ ReadType: evmrelaytypes.Method,
+ },
+ },
+ },
+ },
+ }
+}
+
+// HomeChainReaderConfigRaw returns a ChainReaderConfig that can be used to read from the home chain.
+func HomeChainReaderConfigRaw() evmrelaytypes.ChainReaderConfig {
+ return evmrelaytypes.ChainReaderConfig{
+ Contracts: map[string]evmrelaytypes.ChainContractReader{
+ consts.ContractNameCapabilitiesRegistry: {
+ ContractABI: kcr.CapabilitiesRegistryABI,
+ Configs: map[string]*evmrelaytypes.ChainReaderDefinition{
+ consts.MethodNameGetCapability: {
+ ChainSpecificName: mustGetMethodName("getCapability", capabilitiesRegsitryABI),
+ },
+ },
+ },
+ consts.ContractNameCCIPConfig: {
+ ContractABI: ccip_config.CCIPConfigABI,
+ Configs: map[string]*evmrelaytypes.ChainReaderDefinition{
+ consts.MethodNameGetAllChainConfigs: {
+ ChainSpecificName: mustGetMethodName("getAllChainConfigs", ccipConfigABI),
+ },
+ consts.MethodNameGetOCRConfig: {
+ ChainSpecificName: mustGetMethodName("getOCRConfig", ccipConfigABI),
+ },
+ },
+ },
+ },
+ }
+}
+
+func mustGetEventName(event string, tabi abi.ABI) string {
+ e, ok := tabi.Events[event]
+ if !ok {
+ panic(fmt.Sprintf("missing event %s in onrampABI", event))
+ }
+ return e.Name
+}
diff --git a/core/capabilities/ccip/delegate.go b/core/capabilities/ccip/delegate.go
new file mode 100644
index 00000000000..187ae0c5811
--- /dev/null
+++ b/core/capabilities/ccip/delegate.go
@@ -0,0 +1,323 @@
+package ccip
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/loop"
+
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/common"
+ configsevm "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/configs/evm"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/launcher"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/oraclecreator"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
+ p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+
+ ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types"
+
+ "github.com/smartcontractkit/chainlink-ccip/pkg/consts"
+ ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+ "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
+ "github.com/smartcontractkit/chainlink/v2/core/config"
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+ "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/ocr2key"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2"
+ "github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+ "github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
+ "github.com/smartcontractkit/chainlink/v2/plugins"
+)
+
+type RelayGetter interface {
+ Get(types.RelayID) (loop.Relayer, error)
+ GetIDToRelayerMap() (map[types.RelayID]loop.Relayer, error)
+}
+
+type Delegate struct {
+ lggr logger.Logger
+ registrarConfig plugins.RegistrarConfig
+ pipelineRunner pipeline.Runner
+ chains legacyevm.LegacyChainContainer
+ relayers RelayGetter
+ keystore keystore.Master
+ ds sqlutil.DataSource
+ peerWrapper *ocrcommon.SingletonPeerWrapper
+ monitoringEndpointGen telemetry.MonitoringEndpointGenerator
+ capabilityConfig config.Capabilities
+
+ isNewlyCreatedJob bool
+}
+
+func NewDelegate(
+ lggr logger.Logger,
+ registrarConfig plugins.RegistrarConfig,
+ pipelineRunner pipeline.Runner,
+ chains legacyevm.LegacyChainContainer,
+ relayers RelayGetter,
+ keystore keystore.Master,
+ ds sqlutil.DataSource,
+ peerWrapper *ocrcommon.SingletonPeerWrapper,
+ monitoringEndpointGen telemetry.MonitoringEndpointGenerator,
+ capabilityConfig config.Capabilities,
+) *Delegate {
+ return &Delegate{
+ lggr: lggr,
+ registrarConfig: registrarConfig,
+ pipelineRunner: pipelineRunner,
+ chains: chains,
+ relayers: relayers,
+ ds: ds,
+ keystore: keystore,
+ peerWrapper: peerWrapper,
+ monitoringEndpointGen: monitoringEndpointGen,
+ capabilityConfig: capabilityConfig,
+ }
+}
+
+func (d *Delegate) JobType() job.Type {
+ return job.CCIP
+}
+
+func (d *Delegate) BeforeJobCreated(job.Job) {
+ // This is only called first time the job is created
+ d.isNewlyCreatedJob = true
+}
+
+func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services []job.ServiceCtx, err error) {
+ // In general there should only be one P2P key but the node may have multiple.
+ // The job spec should specify the correct P2P key to use.
+ peerID, err := p2pkey.MakePeerID(spec.CCIPSpec.P2PKeyID)
+ if err != nil {
+ return nil, fmt.Errorf("failed to make peer ID from provided spec p2p id (%s): %w", spec.CCIPSpec.P2PKeyID, err)
+ }
+
+ p2pID, err := d.keystore.P2P().Get(peerID)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get all p2p keys: %w", err)
+ }
+
+ cfg := d.capabilityConfig
+ rid := cfg.ExternalRegistry().RelayID()
+ relayer, err := d.relayers.Get(rid)
+ if err != nil {
+ return nil, fmt.Errorf("could not fetch relayer %s configured for capabilities registry: %w", rid, err)
+ }
+ registrySyncer, err := registrysyncer.New(
+ d.lggr,
+ func() (p2ptypes.PeerID, error) {
+ return p2ptypes.PeerID(p2pID.PeerID()), nil
+ },
+ relayer,
+ cfg.ExternalRegistry().Address(),
+ registrysyncer.NewORM(d.ds, d.lggr),
+ )
+ if err != nil {
+ return nil, fmt.Errorf("could not configure syncer: %w", err)
+ }
+
+ ocrKeys, err := d.getOCRKeys(spec.CCIPSpec.OCRKeyBundleIDs)
+ if err != nil {
+ return nil, err
+ }
+
+ transmitterKeys, err := d.getTransmitterKeys(ctx, d.chains)
+ if err != nil {
+ return nil, err
+ }
+
+ bootstrapperLocators, err := ocrcommon.ParseBootstrapPeers(spec.CCIPSpec.P2PV2Bootstrappers)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse bootstrapper locators: %w", err)
+ }
+
+ // NOTE: we can use the same DB for all plugin instances,
+ // since all queries are scoped by config digest.
+ ocrDB := ocr2.NewDB(d.ds, spec.ID, 0, d.lggr)
+
+ homeChainContractReader, err := d.getHomeChainContractReader(
+ ctx,
+ d.chains,
+ spec.CCIPSpec.CapabilityLabelledName,
+ spec.CCIPSpec.CapabilityVersion)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get home chain contract reader: %w", err)
+ }
+
+ hcr := ccipreaderpkg.NewHomeChainReader(
+ homeChainContractReader,
+ d.lggr.Named("HomeChainReader"),
+ 100*time.Millisecond,
+ )
+
+ oracleCreator := oraclecreator.New(
+ ocrKeys,
+ transmitterKeys,
+ d.chains,
+ d.peerWrapper,
+ spec.ExternalJobID,
+ spec.ID,
+ d.isNewlyCreatedJob,
+ spec.CCIPSpec.PluginConfig,
+ ocrDB,
+ d.lggr,
+ d.monitoringEndpointGen,
+ bootstrapperLocators,
+ hcr,
+ )
+
+ capabilityID := fmt.Sprintf("%s@%s", spec.CCIPSpec.CapabilityLabelledName, spec.CCIPSpec.CapabilityVersion)
+ capLauncher := launcher.New(
+ capabilityID,
+ ragep2ptypes.PeerID(p2pID.PeerID()),
+ d.lggr,
+ hcr,
+ oracleCreator,
+ 12*time.Second,
+ )
+
+ // register the capability launcher with the registry syncer
+ registrySyncer.AddLauncher(capLauncher)
+
+ return []job.ServiceCtx{
+ registrySyncer,
+ hcr,
+ capLauncher,
+ }, nil
+}
+
+func (d *Delegate) AfterJobCreated(spec job.Job) {}
+
+func (d *Delegate) BeforeJobDeleted(spec job.Job) {}
+
+func (d *Delegate) OnDeleteJob(ctx context.Context, spec job.Job) error {
+ // TODO: shut down needed services?
+ return nil
+}
+
+func (d *Delegate) getOCRKeys(ocrKeyBundleIDs job.JSONConfig) (map[string]ocr2key.KeyBundle, error) {
+ ocrKeys := make(map[string]ocr2key.KeyBundle)
+ for networkType, bundleIDRaw := range ocrKeyBundleIDs {
+ if networkType != relay.NetworkEVM {
+ return nil, fmt.Errorf("unsupported chain type: %s", networkType)
+ }
+
+ bundleID, ok := bundleIDRaw.(string)
+ if !ok {
+ return nil, fmt.Errorf("OCRKeyBundleIDs must be a map of chain types to OCR key bundle IDs, got: %T", bundleIDRaw)
+ }
+
+ bundle, err2 := d.keystore.OCR2().Get(bundleID)
+ if err2 != nil {
+ return nil, fmt.Errorf("OCR key bundle with ID %s not found: %w", bundleID, err2)
+ }
+
+ ocrKeys[networkType] = bundle
+ }
+ return ocrKeys, nil
+}
+
+func (d *Delegate) getTransmitterKeys(ctx context.Context, chains legacyevm.LegacyChainContainer) (map[types.RelayID][]string, error) {
+ transmitterKeys := make(map[types.RelayID][]string)
+ for _, chain := range chains.Slice() {
+ relayID := types.NewRelayID(relay.NetworkEVM, chain.ID().String())
+ ethKeys, err2 := d.keystore.Eth().EnabledAddressesForChain(ctx, chain.ID())
+ if err2 != nil {
+ return nil, fmt.Errorf("error getting enabled addresses for chain: %s %w", chain.ID().String(), err2)
+ }
+
+ transmitterKeys[relayID] = func() (r []string) {
+ for _, key := range ethKeys {
+ r = append(r, key.Hex())
+ }
+ return
+ }()
+ }
+ return transmitterKeys, nil
+}
+
+func (d *Delegate) getHomeChainContractReader(
+ ctx context.Context,
+ chains legacyevm.LegacyChainContainer,
+ capabilityLabelledName,
+ capabilityVersion string,
+) (types.ContractReader, error) {
+ // home chain is where the capability registry is deployed,
+ // which should be set correctly in toml config.
+ homeChainRelayID := d.capabilityConfig.ExternalRegistry().RelayID()
+ homeChain, err := chains.Get(homeChainRelayID.ChainID)
+ if err != nil {
+ return nil, fmt.Errorf("home chain relayer not found, chain id: %s, err: %w", homeChainRelayID.String(), err)
+ }
+
+ reader, err := evm.NewChainReaderService(
+ context.Background(),
+ d.lggr,
+ homeChain.LogPoller(),
+ homeChain.HeadTracker(),
+ homeChain.Client(),
+ configsevm.HomeChainReaderConfigRaw(),
+ )
+ if err != nil {
+ return nil, fmt.Errorf("failed to create home chain contract reader: %w", err)
+ }
+
+ reader, err = bindReader(ctx, reader, d.capabilityConfig.ExternalRegistry().Address(), capabilityLabelledName, capabilityVersion)
+ if err != nil {
+ return nil, fmt.Errorf("failed to bind home chain contract reader: %w", err)
+ }
+
+ return reader, nil
+}
+
+func bindReader(ctx context.Context,
+ reader types.ContractReader,
+ capRegAddress,
+ capabilityLabelledName,
+ capabilityVersion string) (types.ContractReader, error) {
+ err := reader.Bind(ctx, []types.BoundContract{
+ {
+ Address: capRegAddress,
+ Name: consts.ContractNameCapabilitiesRegistry,
+ },
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to bind home chain contract reader: %w", err)
+ }
+
+ hid, err := common.HashedCapabilityID(capabilityLabelledName, capabilityVersion)
+ if err != nil {
+ return nil, fmt.Errorf("failed to hash capability id: %w", err)
+ }
+
+ var ccipCapabilityInfo kcr.CapabilitiesRegistryCapabilityInfo
+ err = reader.GetLatestValue(ctx, consts.ContractNameCapabilitiesRegistry, consts.MethodNameGetCapability, primitives.Unconfirmed, map[string]any{
+ "hashedId": hid,
+ }, &ccipCapabilityInfo)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get CCIP capability info from chain reader: %w", err)
+ }
+
+ // bind the ccip capability configuration contract
+ err = reader.Bind(ctx, []types.BoundContract{
+ {
+ Address: ccipCapabilityInfo.ConfigurationContract.String(),
+ Name: consts.ContractNameCCIPConfig,
+ },
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to bind CCIP capability configuration contract: %w", err)
+ }
+
+ return reader, nil
+}
diff --git a/core/capabilities/ccip/delegate_test.go b/core/capabilities/ccip/delegate_test.go
new file mode 100644
index 00000000000..dd8a5124b57
--- /dev/null
+++ b/core/capabilities/ccip/delegate_test.go
@@ -0,0 +1 @@
+package ccip
diff --git a/core/capabilities/ccip/launcher/README.md b/core/capabilities/ccip/launcher/README.md
new file mode 100644
index 00000000000..41fbecfdbd8
--- /dev/null
+++ b/core/capabilities/ccip/launcher/README.md
@@ -0,0 +1,69 @@
+# CCIP Capability Launcher
+
+The CCIP capability launcher is responsible for listening to
+[Capabilities Registry](../../../../contracts/src/v0.8/keystone/CapabilitiesRegistry.sol) (CR) updates
+for the particular CCIP capability (labelled name, version) pair and reacting to them. In
+particular, there are three kinds of events that would affect a particular capability:
+
+1. DON Creation: when `addDON` is called on the CR, the capabilities of this new DON are specified.
+If CCIP is one of those capabilities, the launcher will launch a commit and an execution plugin
+with the OCR configuration specified in the DON creation process. See
+[Types.sol](../../../../contracts/src/v0.8/ccip/capability/libraries/Types.sol) for more details
+on what the OCR configuration contains.
+2. DON update: when `updateDON` is called on the CR, capabilities of the DON can be updated. In the
+CCIP use case specifically, `updateDON` is used to update OCR configuration of that DON. Updates
+follow the blue/green deployment pattern (explained in detail below with a state diagram). In this
+scenario the launcher must either launch brand new instances of the commit and execution plugins
+(in the event a green deployment is made) or promote the currently running green instance to be
+the blue instance.
+3. DON deletion: when `deleteDON` is called on the CR, the launcher must shut down all running plugins
+related to that DON. When a DON is deleted it effectively means that it should no longer function.
+DON deletion is permanent.
+
+## Architecture Diagram
+
+![CCIP Capability Launcher](ccip_capability_launcher.png)
+
+The above diagram shows how the CCIP capability launcher interacts with the rest of the components
+in the CCIP system.
+
+The CCIP capability job, which is created on the Chainlink node, will spin up the CCIP capability
+launcher alongside the home chain reader, which reads the [CCIPConfig.sol](../../../../contracts/src/v0.8/ccip/capability/CCIPConfig.sol)
+contract deployed on the home chain (typically Ethereum Mainnet, though could be "any chain" in theory).
+
+Injected into the launcher is the [OracleCreator](../types/types.go) object which knows how to spin up CCIP
+oracles (both bootstrap and plugin oracles). This is used by the launcher at the appropriate time in order
+to create oracle instances but not start them right away.
+
+After all the required oracles have been created, the launcher will start and shut them down as required
+in order to match the configuration that was posted on-chain in the CR and the CCIPConfig.sol contract.
+
+
+## Config State Diagram
+
+![CCIP Config State Machine](ccip_config_state_machine.png)
+
+CCIP's blue/green deployment paradigm is intentionally kept as simple as possible.
+
+Every CCIP DON starts in the `Init` state. Upon DON creation, which must provide a valid OCR
+configuration, the CCIP DON will move into the `Running` state. In this state, the DON is
+presumed to be fully functional from a configuration standpoint.
+
+When we want to update configuration, we propose a new configuration to the CR that consists of
+an array of two OCR configurations:
+
+1. The first element of the array is the current OCR configuration that is running (termed "blue").
+2. The second element of the array is the future OCR configuration that we want to run (termed "green").
+
+Various checks are done on-chain in order to validate this particular state transition, in particular,
+related to config counts. Doing this will move the state of the configuration to the `Staging` state.
+
+In the `Staging` state, there are effectively four plugins running - one (commit, execution) pair for the
+blue configuration, and one (commit, execution) pair for the green configuration. However, only the blue
+configuration will actually be writing on-chain, where as the green configuration will be "dry running",
+i.e doing everything except transmitting.
+
+This allows us to test out new configurations without committing to them immediately.
+
+Finally, from the `Staging` state, there is only one transition, which is to promote the green configuration
+to be the new blue configuration, and go back into the `Running` state.
diff --git a/core/capabilities/ccip/launcher/bluegreen.go b/core/capabilities/ccip/launcher/bluegreen.go
new file mode 100644
index 00000000000..62458466291
--- /dev/null
+++ b/core/capabilities/ccip/launcher/bluegreen.go
@@ -0,0 +1,178 @@
+package launcher
+
+import (
+ "fmt"
+
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+
+ "go.uber.org/multierr"
+
+ ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+)
+
+// blueGreenDeployment represents a blue-green deployment of OCR instances.
+type blueGreenDeployment struct {
+ // blue is the blue OCR instance.
+ // blue must always be present.
+ blue cctypes.CCIPOracle
+
+ // bootstrapBlue is the bootstrap node of the blue OCR instance.
+ // Only a subset of the DON will be running bootstrap instances,
+ // so this may be nil.
+ bootstrapBlue cctypes.CCIPOracle
+
+ // green is the green OCR instance.
+ // green may or may not be present.
+ // green must never be present if blue is not present.
+ // TODO: should we enforce this invariant somehow?
+ green cctypes.CCIPOracle
+
+ // bootstrapGreen is the bootstrap node of the green OCR instance.
+ // Only a subset of the DON will be running bootstrap instances,
+ // so this may be nil, even when green is not nil.
+ bootstrapGreen cctypes.CCIPOracle
+}
+
+// ccipDeployment represents blue-green deployments of both commit and exec
+// OCR instances.
+type ccipDeployment struct {
+ commit blueGreenDeployment
+ exec blueGreenDeployment
+}
+
+// Close shuts down all OCR instances in the deployment.
+func (c *ccipDeployment) Close() error {
+ var err error
+
+ // shutdown blue commit instances.
+ err = multierr.Append(err, c.commit.blue.Close())
+ if c.commit.bootstrapBlue != nil {
+ err = multierr.Append(err, c.commit.bootstrapBlue.Close())
+ }
+
+ // shutdown green commit instances.
+ if c.commit.green != nil {
+ err = multierr.Append(err, c.commit.green.Close())
+ }
+ if c.commit.bootstrapGreen != nil {
+ err = multierr.Append(err, c.commit.bootstrapGreen.Close())
+ }
+
+ // shutdown blue exec instances.
+ err = multierr.Append(err, c.exec.blue.Close())
+ if c.exec.bootstrapBlue != nil {
+ err = multierr.Append(err, c.exec.bootstrapBlue.Close())
+ }
+
+ // shutdown green exec instances.
+ if c.exec.green != nil {
+ err = multierr.Append(err, c.exec.green.Close())
+ }
+ if c.exec.bootstrapGreen != nil {
+ err = multierr.Append(err, c.exec.bootstrapGreen.Close())
+ }
+
+ return err
+}
+
+// StartBlue starts the blue OCR instances.
+func (c *ccipDeployment) StartBlue() error {
+ var err error
+
+ err = multierr.Append(err, c.commit.blue.Start())
+ if c.commit.bootstrapBlue != nil {
+ err = multierr.Append(err, c.commit.bootstrapBlue.Start())
+ }
+ err = multierr.Append(err, c.exec.blue.Start())
+ if c.exec.bootstrapBlue != nil {
+ err = multierr.Append(err, c.exec.bootstrapBlue.Start())
+ }
+
+ return err
+}
+
+// CloseBlue shuts down the blue OCR instances.
+func (c *ccipDeployment) CloseBlue() error {
+ var err error
+
+ err = multierr.Append(err, c.commit.blue.Close())
+ if c.commit.bootstrapBlue != nil {
+ err = multierr.Append(err, c.commit.bootstrapBlue.Close())
+ }
+ err = multierr.Append(err, c.exec.blue.Close())
+ if c.exec.bootstrapBlue != nil {
+ err = multierr.Append(err, c.exec.bootstrapBlue.Close())
+ }
+
+ return err
+}
+
+// HandleBlueGreen handles the blue-green deployment transition.
+// prevDeployment is the previous deployment state.
+// there are two possible cases:
+//
+// 1. both blue and green are present in prevDeployment, but only blue is present in c.
+// this is a promotion of green to blue, so we need to shut down the blue deployment
+// and make green the new blue. In this case green is already running, so there's no
+// need to start it. However, we need to shut down the blue deployment.
+//
+// 2. only blue is present in prevDeployment, both blue and green are present in c.
+// In this case, blue is already running, so there's no need to start it. We need to
+// start green.
+func (c *ccipDeployment) HandleBlueGreen(prevDeployment *ccipDeployment) error {
+ if prevDeployment == nil {
+ return fmt.Errorf("previous deployment is nil")
+ }
+
+ var err error
+ if prevDeployment.commit.green != nil && c.commit.green == nil {
+ err = multierr.Append(err, prevDeployment.commit.blue.Close())
+ if prevDeployment.commit.bootstrapBlue != nil {
+ err = multierr.Append(err, prevDeployment.commit.bootstrapBlue.Close())
+ }
+ } else if prevDeployment.commit.green == nil && c.commit.green != nil {
+ err = multierr.Append(err, c.commit.green.Start())
+ if c.commit.bootstrapGreen != nil {
+ err = multierr.Append(err, c.commit.bootstrapGreen.Start())
+ }
+ } else {
+ return fmt.Errorf("invalid blue-green deployment transition")
+ }
+
+ if prevDeployment.exec.green != nil && c.exec.green == nil {
+ err = multierr.Append(err, prevDeployment.exec.blue.Close())
+ if prevDeployment.exec.bootstrapBlue != nil {
+ err = multierr.Append(err, prevDeployment.exec.bootstrapBlue.Close())
+ }
+ } else if prevDeployment.exec.green == nil && c.exec.green != nil {
+ err = multierr.Append(err, c.exec.green.Start())
+ if c.exec.bootstrapGreen != nil {
+ err = multierr.Append(err, c.exec.bootstrapGreen.Start())
+ }
+ } else {
+ return fmt.Errorf("invalid blue-green deployment transition")
+ }
+
+ return err
+}
+
+// HasGreenInstance returns true if the deployment has a green instance for the
+// given plugin type.
+func (c *ccipDeployment) HasGreenInstance(pluginType cctypes.PluginType) bool {
+ switch pluginType {
+ case cctypes.PluginTypeCCIPCommit:
+ return c.commit.green != nil
+ case cctypes.PluginTypeCCIPExec:
+ return c.exec.green != nil
+ default:
+ return false
+ }
+}
+
+func isNewGreenInstance(pluginType cctypes.PluginType, ocrConfigs []ccipreaderpkg.OCR3ConfigWithMeta, prevDeployment ccipDeployment) bool {
+ return len(ocrConfigs) == 2 && !prevDeployment.HasGreenInstance(pluginType)
+}
+
+func isPromotion(pluginType cctypes.PluginType, ocrConfigs []ccipreaderpkg.OCR3ConfigWithMeta, prevDeployment ccipDeployment) bool {
+ return len(ocrConfigs) == 1 && prevDeployment.HasGreenInstance(pluginType)
+}
diff --git a/core/capabilities/ccip/launcher/bluegreen_test.go b/core/capabilities/ccip/launcher/bluegreen_test.go
new file mode 100644
index 00000000000..9fd71a0cb44
--- /dev/null
+++ b/core/capabilities/ccip/launcher/bluegreen_test.go
@@ -0,0 +1,1043 @@
+package launcher
+
+import (
+ "errors"
+ "testing"
+
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+ mocktypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types/mocks"
+
+ "github.com/stretchr/testify/require"
+
+ ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+)
+
+func Test_ccipDeployment_Close(t *testing.T) {
+ type args struct {
+ commitBlue *mocktypes.CCIPOracle
+ commitBlueBootstrap *mocktypes.CCIPOracle
+ commitGreen *mocktypes.CCIPOracle
+ commitGreenBootstrap *mocktypes.CCIPOracle
+ execBlue *mocktypes.CCIPOracle
+ execBlueBootstrap *mocktypes.CCIPOracle
+ execGreen *mocktypes.CCIPOracle
+ execGreenBootstrap *mocktypes.CCIPOracle
+ }
+ tests := []struct {
+ name string
+ args args
+ expect func(t *testing.T, args args)
+ asserts func(t *testing.T, args args)
+ wantErr bool
+ }{
+ {
+ name: "no errors, blue only",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ commitGreenBootstrap: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ execGreenBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "no errors, blue and green",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.commitGreen.On("Close").Return(nil).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ args.execGreen.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.commitGreen.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ args.execGreen.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "error on commit blue",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(errors.New("failed")).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "bootstrap blue also closed",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.commitBlueBootstrap.On("Close").Return(nil).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ args.execBlueBootstrap.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.commitBlueBootstrap.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ args.execBlueBootstrap.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "bootstrap green also closed",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ commitGreenBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ execGreenBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.commitBlueBootstrap.On("Close").Return(nil).Once()
+ args.commitGreen.On("Close").Return(nil).Once()
+ args.commitGreenBootstrap.On("Close").Return(nil).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ args.execBlueBootstrap.On("Close").Return(nil).Once()
+ args.execGreen.On("Close").Return(nil).Once()
+ args.execGreenBootstrap.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.commitBlueBootstrap.AssertExpectations(t)
+ args.commitGreen.AssertExpectations(t)
+ args.commitGreenBootstrap.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ args.execBlueBootstrap.AssertExpectations(t)
+ args.execGreen.AssertExpectations(t)
+ args.execGreenBootstrap.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ c := &ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: tt.args.commitBlue,
+ },
+ exec: blueGreenDeployment{
+ blue: tt.args.execBlue,
+ },
+ }
+ if tt.args.commitGreen != nil {
+ c.commit.green = tt.args.commitGreen
+ }
+ if tt.args.commitBlueBootstrap != nil {
+ c.commit.bootstrapBlue = tt.args.commitBlueBootstrap
+ }
+ if tt.args.commitGreenBootstrap != nil {
+ c.commit.bootstrapGreen = tt.args.commitGreenBootstrap
+ }
+
+ if tt.args.execGreen != nil {
+ c.exec.green = tt.args.execGreen
+ }
+ if tt.args.execBlueBootstrap != nil {
+ c.exec.bootstrapBlue = tt.args.execBlueBootstrap
+ }
+ if tt.args.execGreenBootstrap != nil {
+ c.exec.bootstrapGreen = tt.args.execGreenBootstrap
+ }
+
+ tt.expect(t, tt.args)
+ defer tt.asserts(t, tt.args)
+ err := c.Close()
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
+
+func Test_ccipDeployment_StartBlue(t *testing.T) {
+ type args struct {
+ commitBlue *mocktypes.CCIPOracle
+ commitBlueBootstrap *mocktypes.CCIPOracle
+ execBlue *mocktypes.CCIPOracle
+ execBlueBootstrap *mocktypes.CCIPOracle
+ }
+ tests := []struct {
+ name string
+ args args
+ expect func(t *testing.T, args args)
+ asserts func(t *testing.T, args args)
+ wantErr bool
+ }{
+ {
+ name: "no errors, no bootstrap",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: nil,
+ execBlueBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Start").Return(nil).Once()
+ args.execBlue.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "no errors, with bootstrap",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Start").Return(nil).Once()
+ args.commitBlueBootstrap.On("Start").Return(nil).Once()
+ args.execBlue.On("Start").Return(nil).Once()
+ args.execBlueBootstrap.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.commitBlueBootstrap.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ args.execBlueBootstrap.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "error on commit blue",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: nil,
+ execBlueBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Start").Return(errors.New("failed")).Once()
+ args.execBlue.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "error on exec blue",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: nil,
+ execBlueBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Start").Return(nil).Once()
+ args.execBlue.On("Start").Return(errors.New("failed")).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "error on commit blue bootstrap",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Start").Return(nil).Once()
+ args.commitBlueBootstrap.On("Start").Return(errors.New("failed")).Once()
+ args.execBlue.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.commitBlueBootstrap.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "error on exec blue bootstrap",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: nil,
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Start").Return(nil).Once()
+ args.execBlue.On("Start").Return(nil).Once()
+ args.execBlueBootstrap.On("Start").Return(errors.New("failed")).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ args.execBlueBootstrap.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ c := &ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: tt.args.commitBlue,
+ },
+ exec: blueGreenDeployment{
+ blue: tt.args.execBlue,
+ },
+ }
+ if tt.args.commitBlueBootstrap != nil {
+ c.commit.bootstrapBlue = tt.args.commitBlueBootstrap
+ }
+ if tt.args.execBlueBootstrap != nil {
+ c.exec.bootstrapBlue = tt.args.execBlueBootstrap
+ }
+
+ tt.expect(t, tt.args)
+ defer tt.asserts(t, tt.args)
+ err := c.StartBlue()
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
+
+func Test_ccipDeployment_CloseBlue(t *testing.T) {
+ type args struct {
+ commitBlue *mocktypes.CCIPOracle
+ commitBlueBootstrap *mocktypes.CCIPOracle
+ execBlue *mocktypes.CCIPOracle
+ execBlueBootstrap *mocktypes.CCIPOracle
+ }
+ tests := []struct {
+ name string
+ args args
+ expect func(t *testing.T, args args)
+ asserts func(t *testing.T, args args)
+ wantErr bool
+ }{
+ {
+ name: "no errors, no bootstrap",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: nil,
+ execBlueBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "no errors, with bootstrap",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.commitBlueBootstrap.On("Close").Return(nil).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ args.execBlueBootstrap.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.commitBlueBootstrap.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ args.execBlueBootstrap.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "error on commit blue",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: nil,
+ execBlueBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(errors.New("failed")).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "error on exec blue",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: nil,
+ execBlueBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.execBlue.On("Close").Return(errors.New("failed")).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "error on commit blue bootstrap",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.commitBlueBootstrap.On("Close").Return(errors.New("failed")).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.commitBlueBootstrap.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "error on exec blue bootstrap",
+ args: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: nil,
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args) {
+ args.commitBlue.On("Close").Return(nil).Once()
+ args.execBlue.On("Close").Return(nil).Once()
+ args.execBlueBootstrap.On("Close").Return(errors.New("failed")).Once()
+ },
+ asserts: func(t *testing.T, args args) {
+ args.commitBlue.AssertExpectations(t)
+ args.execBlue.AssertExpectations(t)
+ args.execBlueBootstrap.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ c := &ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: tt.args.commitBlue,
+ },
+ exec: blueGreenDeployment{
+ blue: tt.args.execBlue,
+ },
+ }
+ if tt.args.commitBlueBootstrap != nil {
+ c.commit.bootstrapBlue = tt.args.commitBlueBootstrap
+ }
+ if tt.args.execBlueBootstrap != nil {
+ c.exec.bootstrapBlue = tt.args.execBlueBootstrap
+ }
+
+ tt.expect(t, tt.args)
+ defer tt.asserts(t, tt.args)
+ err := c.CloseBlue()
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
+
+func Test_ccipDeployment_HandleBlueGreen_PrevDeploymentNil(t *testing.T) {
+ require.Error(t, (&ccipDeployment{}).HandleBlueGreen(nil))
+}
+
+func Test_ccipDeployment_HandleBlueGreen(t *testing.T) {
+ type args struct {
+ commitBlue *mocktypes.CCIPOracle
+ commitBlueBootstrap *mocktypes.CCIPOracle
+ commitGreen *mocktypes.CCIPOracle
+ commitGreenBootstrap *mocktypes.CCIPOracle
+ execBlue *mocktypes.CCIPOracle
+ execBlueBootstrap *mocktypes.CCIPOracle
+ execGreen *mocktypes.CCIPOracle
+ execGreenBootstrap *mocktypes.CCIPOracle
+ }
+ tests := []struct {
+ name string
+ argsPrevDeployment args
+ argsFutureDeployment args
+ expect func(t *testing.T, args args, argsPrevDeployment args)
+ asserts func(t *testing.T, args args, argsPrevDeployment args)
+ wantErr bool
+ }{
+ {
+ name: "promotion blue to green, no bootstrap",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {
+ argsPrevDeployment.commitBlue.On("Close").Return(nil).Once()
+ argsPrevDeployment.execBlue.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {
+ argsPrevDeployment.commitBlue.AssertExpectations(t)
+ argsPrevDeployment.execBlue.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "promotion blue to green, with bootstrap",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ commitGreenBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ execGreenBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ commitGreenBootstrap: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ execGreenBootstrap: nil,
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {
+ argsPrevDeployment.commitBlue.On("Close").Return(nil).Once()
+ argsPrevDeployment.commitBlueBootstrap.On("Close").Return(nil).Once()
+ argsPrevDeployment.execBlue.On("Close").Return(nil).Once()
+ argsPrevDeployment.execBlueBootstrap.On("Close").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {
+ argsPrevDeployment.commitBlue.AssertExpectations(t)
+ argsPrevDeployment.commitBlueBootstrap.AssertExpectations(t)
+ argsPrevDeployment.execBlue.AssertExpectations(t)
+ argsPrevDeployment.execBlueBootstrap.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "new green deployment, no bootstrap",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.On("Start").Return(nil).Once()
+ args.execGreen.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.AssertExpectations(t)
+ args.execGreen.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "new green deployment, with bootstrap",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ commitGreenBootstrap: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ execGreenBootstrap: nil,
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ commitGreenBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ execGreenBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.On("Start").Return(nil).Once()
+ args.commitGreenBootstrap.On("Start").Return(nil).Once()
+ args.execGreen.On("Start").Return(nil).Once()
+ args.execGreenBootstrap.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.AssertExpectations(t)
+ args.commitGreenBootstrap.AssertExpectations(t)
+ args.execGreen.AssertExpectations(t)
+ args.execGreenBootstrap.AssertExpectations(t)
+ },
+ wantErr: false,
+ },
+ {
+ name: "error on commit green start",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.On("Start").Return(errors.New("failed")).Once()
+ args.execGreen.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.AssertExpectations(t)
+ args.execGreen.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "error on exec green start",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.On("Start").Return(nil).Once()
+ args.execGreen.On("Start").Return(errors.New("failed")).Once()
+ },
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.AssertExpectations(t)
+ args.execGreen.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "error on commit green bootstrap start",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ commitGreenBootstrap: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execGreen: nil,
+ execGreenBootstrap: nil,
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ commitGreenBootstrap: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execBlueBootstrap: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ execGreenBootstrap: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.On("Start").Return(nil).Once()
+ args.commitGreenBootstrap.On("Start").Return(errors.New("failed")).Once()
+ args.execGreen.On("Start").Return(nil).Once()
+ args.execGreenBootstrap.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.AssertExpectations(t)
+ args.commitGreenBootstrap.AssertExpectations(t)
+ args.execGreen.AssertExpectations(t)
+ args.execGreenBootstrap.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ {
+ name: "invalid blue-green deployment transition commit: both prev and future deployment have green",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {},
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {},
+ wantErr: true,
+ },
+ {
+ name: "invalid blue-green deployment transition exec: both prev and future deployment have green",
+ argsPrevDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: nil,
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ argsFutureDeployment: args{
+ commitBlue: mocktypes.NewCCIPOracle(t),
+ commitGreen: mocktypes.NewCCIPOracle(t),
+ execBlue: mocktypes.NewCCIPOracle(t),
+ execGreen: mocktypes.NewCCIPOracle(t),
+ },
+ expect: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.On("Start").Return(nil).Once()
+ },
+ asserts: func(t *testing.T, args args, argsPrevDeployment args) {
+ args.commitGreen.AssertExpectations(t)
+ },
+ wantErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ futDeployment := &ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: tt.argsFutureDeployment.commitBlue,
+ },
+ exec: blueGreenDeployment{
+ blue: tt.argsFutureDeployment.execBlue,
+ },
+ }
+ if tt.argsFutureDeployment.commitGreen != nil {
+ futDeployment.commit.green = tt.argsFutureDeployment.commitGreen
+ }
+ if tt.argsFutureDeployment.commitBlueBootstrap != nil {
+ futDeployment.commit.bootstrapBlue = tt.argsFutureDeployment.commitBlueBootstrap
+ }
+ if tt.argsFutureDeployment.commitGreenBootstrap != nil {
+ futDeployment.commit.bootstrapGreen = tt.argsFutureDeployment.commitGreenBootstrap
+ }
+ if tt.argsFutureDeployment.execGreen != nil {
+ futDeployment.exec.green = tt.argsFutureDeployment.execGreen
+ }
+ if tt.argsFutureDeployment.execBlueBootstrap != nil {
+ futDeployment.exec.bootstrapBlue = tt.argsFutureDeployment.execBlueBootstrap
+ }
+ if tt.argsFutureDeployment.execGreenBootstrap != nil {
+ futDeployment.exec.bootstrapGreen = tt.argsFutureDeployment.execGreenBootstrap
+ }
+
+ prevDeployment := &ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: tt.argsPrevDeployment.commitBlue,
+ },
+ exec: blueGreenDeployment{
+ blue: tt.argsPrevDeployment.execBlue,
+ },
+ }
+ if tt.argsPrevDeployment.commitGreen != nil {
+ prevDeployment.commit.green = tt.argsPrevDeployment.commitGreen
+ }
+ if tt.argsPrevDeployment.commitBlueBootstrap != nil {
+ prevDeployment.commit.bootstrapBlue = tt.argsPrevDeployment.commitBlueBootstrap
+ }
+ if tt.argsPrevDeployment.commitGreenBootstrap != nil {
+ prevDeployment.commit.bootstrapGreen = tt.argsPrevDeployment.commitGreenBootstrap
+ }
+ if tt.argsPrevDeployment.execGreen != nil {
+ prevDeployment.exec.green = tt.argsPrevDeployment.execGreen
+ }
+ if tt.argsPrevDeployment.execBlueBootstrap != nil {
+ prevDeployment.exec.bootstrapBlue = tt.argsPrevDeployment.execBlueBootstrap
+ }
+ if tt.argsPrevDeployment.execGreenBootstrap != nil {
+ prevDeployment.exec.bootstrapGreen = tt.argsPrevDeployment.execGreenBootstrap
+ }
+
+ tt.expect(t, tt.argsFutureDeployment, tt.argsPrevDeployment)
+ defer tt.asserts(t, tt.argsFutureDeployment, tt.argsPrevDeployment)
+ err := futDeployment.HandleBlueGreen(prevDeployment)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
+
+func Test_isNewGreenInstance(t *testing.T) {
+ type args struct {
+ pluginType cctypes.PluginType
+ ocrConfigs []ccipreaderpkg.OCR3ConfigWithMeta
+ prevDeployment ccipDeployment
+ }
+ tests := []struct {
+ name string
+ args args
+ want bool
+ }{
+ {
+ "prev deployment only blue",
+ args{
+ pluginType: cctypes.PluginTypeCCIPCommit,
+ ocrConfigs: []ccipreaderpkg.OCR3ConfigWithMeta{
+ {}, {},
+ },
+ prevDeployment: ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: mocktypes.NewCCIPOracle(t),
+ },
+ },
+ },
+ true,
+ },
+ {
+ "green -> blue promotion",
+ args{
+ pluginType: cctypes.PluginTypeCCIPCommit,
+ ocrConfigs: []ccipreaderpkg.OCR3ConfigWithMeta{
+ {},
+ },
+ prevDeployment: ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: mocktypes.NewCCIPOracle(t),
+ green: mocktypes.NewCCIPOracle(t),
+ },
+ },
+ },
+ false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := isNewGreenInstance(tt.args.pluginType, tt.args.ocrConfigs, tt.args.prevDeployment)
+ require.Equal(t, tt.want, got)
+ })
+ }
+}
+
+func Test_isPromotion(t *testing.T) {
+ type args struct {
+ pluginType cctypes.PluginType
+ ocrConfigs []ccipreaderpkg.OCR3ConfigWithMeta
+ prevDeployment ccipDeployment
+ }
+ tests := []struct {
+ name string
+ args args
+ want bool
+ }{
+ {
+ "prev deployment only blue",
+ args{
+ pluginType: cctypes.PluginTypeCCIPCommit,
+ ocrConfigs: []ccipreaderpkg.OCR3ConfigWithMeta{
+ {}, {},
+ },
+ prevDeployment: ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: mocktypes.NewCCIPOracle(t),
+ },
+ },
+ },
+ false,
+ },
+ {
+ "green -> blue promotion",
+ args{
+ pluginType: cctypes.PluginTypeCCIPCommit,
+ ocrConfigs: []ccipreaderpkg.OCR3ConfigWithMeta{
+ {},
+ },
+ prevDeployment: ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: mocktypes.NewCCIPOracle(t),
+ green: mocktypes.NewCCIPOracle(t),
+ },
+ },
+ },
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := isPromotion(tt.args.pluginType, tt.args.ocrConfigs, tt.args.prevDeployment); got != tt.want {
+ t.Errorf("isPromotion() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func Test_ccipDeployment_HasGreenInstance(t *testing.T) {
+ type fields struct {
+ commit blueGreenDeployment
+ exec blueGreenDeployment
+ }
+ type args struct {
+ pluginType cctypes.PluginType
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ want bool
+ }{
+ {
+ "commit green present",
+ fields{
+ commit: blueGreenDeployment{
+ blue: mocktypes.NewCCIPOracle(t),
+ green: mocktypes.NewCCIPOracle(t),
+ },
+ },
+ args{
+ pluginType: cctypes.PluginTypeCCIPCommit,
+ },
+ true,
+ },
+ {
+ "commit green not present",
+ fields{
+ commit: blueGreenDeployment{
+ blue: mocktypes.NewCCIPOracle(t),
+ },
+ },
+ args{
+ pluginType: cctypes.PluginTypeCCIPCommit,
+ },
+ false,
+ },
+ {
+ "exec green present",
+ fields{
+ exec: blueGreenDeployment{
+ blue: mocktypes.NewCCIPOracle(t),
+ green: mocktypes.NewCCIPOracle(t),
+ },
+ },
+ args{
+ pluginType: cctypes.PluginTypeCCIPExec,
+ },
+ true,
+ },
+ {
+ "exec green not present",
+ fields{
+ exec: blueGreenDeployment{
+ blue: mocktypes.NewCCIPOracle(t),
+ },
+ },
+ args{
+ pluginType: cctypes.PluginTypeCCIPExec,
+ },
+ false,
+ },
+ {
+ "invalid plugin type",
+ fields{},
+ args{
+ pluginType: cctypes.PluginType(100),
+ },
+ false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ c := &ccipDeployment{}
+ if tt.fields.commit.blue != nil {
+ c.commit.blue = tt.fields.commit.blue
+ }
+ if tt.fields.commit.green != nil {
+ c.commit.green = tt.fields.commit.green
+ }
+ if tt.fields.exec.blue != nil {
+ c.exec.blue = tt.fields.exec.blue
+ }
+ if tt.fields.exec.green != nil {
+ c.exec.green = tt.fields.exec.green
+ }
+ got := c.HasGreenInstance(tt.args.pluginType)
+ require.Equal(t, tt.want, got)
+ })
+ }
+}
diff --git a/core/capabilities/ccip/launcher/ccip_capability_launcher.png b/core/capabilities/ccip/launcher/ccip_capability_launcher.png
new file mode 100644
index 00000000000..5e90d5ff7da
Binary files /dev/null and b/core/capabilities/ccip/launcher/ccip_capability_launcher.png differ
diff --git a/core/capabilities/ccip/launcher/ccip_config_state_machine.png b/core/capabilities/ccip/launcher/ccip_config_state_machine.png
new file mode 100644
index 00000000000..ece40e6c19e
Binary files /dev/null and b/core/capabilities/ccip/launcher/ccip_config_state_machine.png differ
diff --git a/core/capabilities/ccip/launcher/diff.go b/core/capabilities/ccip/launcher/diff.go
new file mode 100644
index 00000000000..e631ea9fc78
--- /dev/null
+++ b/core/capabilities/ccip/launcher/diff.go
@@ -0,0 +1,141 @@
+package launcher
+
+import (
+ "fmt"
+
+ ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+)
+
+// diffResult contains the added, removed and updated CCIP DONs.
+// It is determined by using the `diff` function below.
+type diffResult struct {
+ added map[registrysyncer.DonID]registrysyncer.DON
+ removed map[registrysyncer.DonID]registrysyncer.DON
+ updated map[registrysyncer.DonID]registrysyncer.DON
+}
+
+// diff compares the old and new state and returns the added, removed and updated CCIP DONs.
+func diff(
+ capabilityID string,
+ oldState,
+ newState registrysyncer.LocalRegistry,
+) (diffResult, error) {
+ ccipCapability, err := checkCapabilityPresence(capabilityID, newState)
+ if err != nil {
+ return diffResult{}, fmt.Errorf("failed to check capability presence: %w", err)
+ }
+
+ newCCIPDONs, err := filterCCIPDONs(ccipCapability, newState)
+ if err != nil {
+ return diffResult{}, fmt.Errorf("failed to filter CCIP DONs from new state: %w", err)
+ }
+
+ currCCIPDONs, err := filterCCIPDONs(ccipCapability, oldState)
+ if err != nil {
+ return diffResult{}, fmt.Errorf("failed to filter CCIP DONs from old state: %w", err)
+ }
+
+ // compare curr with new and launch or update OCR instances as needed
+ diffRes, err := compareDONs(currCCIPDONs, newCCIPDONs)
+ if err != nil {
+ return diffResult{}, fmt.Errorf("failed to compare CCIP DONs: %w", err)
+ }
+
+ return diffRes, nil
+}
+
+// compareDONs compares the current and new CCIP DONs and returns the added, removed and updated DONs.
+func compareDONs(
+ currCCIPDONs,
+ newCCIPDONs map[registrysyncer.DonID]registrysyncer.DON,
+) (
+ dr diffResult,
+ err error,
+) {
+ added := make(map[registrysyncer.DonID]registrysyncer.DON)
+ removed := make(map[registrysyncer.DonID]registrysyncer.DON)
+ updated := make(map[registrysyncer.DonID]registrysyncer.DON)
+
+ for id, don := range newCCIPDONs {
+ if currDONState, ok := currCCIPDONs[id]; !ok {
+ // Not in current state, so mark as added.
+ added[id] = don
+ } else {
+ // If its in the current state and the config count for the DON has changed, mark as updated.
+ // Since the registry returns the full state we need to compare the config count.
+ if don.ConfigVersion > currDONState.ConfigVersion {
+ updated[id] = don
+ }
+ }
+ }
+
+ for id, don := range currCCIPDONs {
+ if _, ok := newCCIPDONs[id]; !ok {
+ // In current state but not in latest registry state, so should remove.
+ removed[id] = don
+ }
+ }
+
+ return diffResult{
+ added: added,
+ removed: removed,
+ updated: updated,
+ }, nil
+}
+
+// filterCCIPDONs filters the CCIP DONs from the given state.
+func filterCCIPDONs(
+ ccipCapability registrysyncer.Capability,
+ state registrysyncer.LocalRegistry,
+) (map[registrysyncer.DonID]registrysyncer.DON, error) {
+ ccipDONs := make(map[registrysyncer.DonID]registrysyncer.DON)
+ for _, don := range state.IDsToDONs {
+ _, ok := don.CapabilityConfigurations[ccipCapability.ID]
+ if ok {
+ ccipDONs[registrysyncer.DonID(don.ID)] = don
+ }
+ }
+
+ return ccipDONs, nil
+}
+
+// checkCapabilityPresence checks if the capability with the given capabilityID
+// is present in the given capability registry state.
+func checkCapabilityPresence(
+ capabilityID string,
+ state registrysyncer.LocalRegistry,
+) (registrysyncer.Capability, error) {
+ // Sanity check to make sure the capability registry has the capability we are looking for.
+ ccipCapability, ok := state.IDsToCapabilities[capabilityID]
+ if !ok {
+ return registrysyncer.Capability{},
+ fmt.Errorf("failed to find capability with capabilityID %s in capability registry state", capabilityID)
+ }
+
+ return ccipCapability, nil
+}
+
+// isMemberOfDON returns true if and only if the given p2pID is a member of the given DON.
+func isMemberOfDON(don registrysyncer.DON, p2pID ragep2ptypes.PeerID) bool {
+ for _, node := range don.Members {
+ if node == p2pID {
+ return true
+ }
+ }
+ return false
+}
+
+// isMemberOfBootstrapSubcommittee returns true if and only if the given p2pID is a member of the given bootstrap subcommittee.
+func isMemberOfBootstrapSubcommittee(
+ bootstrapP2PIDs [][32]byte,
+ p2pID ragep2ptypes.PeerID,
+) bool {
+ for _, bootstrapID := range bootstrapP2PIDs {
+ if bootstrapID == p2pID {
+ return true
+ }
+ }
+ return false
+}
diff --git a/core/capabilities/ccip/launcher/diff_test.go b/core/capabilities/ccip/launcher/diff_test.go
new file mode 100644
index 00000000000..f3dd327fe91
--- /dev/null
+++ b/core/capabilities/ccip/launcher/diff_test.go
@@ -0,0 +1,352 @@
+package launcher
+
+import (
+ "math/big"
+ "reflect"
+ "testing"
+
+ ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types"
+
+ "github.com/stretchr/testify/require"
+
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
+ "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+)
+
+func Test_diff(t *testing.T) {
+ type args struct {
+ capabilityID string
+ oldState registrysyncer.LocalRegistry
+ newState registrysyncer.LocalRegistry
+ }
+ tests := []struct {
+ name string
+ args args
+ want diffResult
+ wantErr bool
+ }{
+ {
+ name: "no diff",
+ args: args{
+ capabilityID: defaultCapability.ID,
+ oldState: registrysyncer.LocalRegistry{
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ defaultCapability.ID: defaultCapability,
+ },
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ IDsToNodes: map[types.PeerID]kcr.CapabilitiesRegistryNodeInfo{},
+ },
+ newState: registrysyncer.LocalRegistry{
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ defaultCapability.ID: defaultCapability,
+ },
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ IDsToNodes: map[types.PeerID]kcr.CapabilitiesRegistryNodeInfo{},
+ },
+ },
+ want: diffResult{
+ added: map[registrysyncer.DonID]registrysyncer.DON{},
+ removed: map[registrysyncer.DonID]registrysyncer.DON{},
+ updated: map[registrysyncer.DonID]registrysyncer.DON{},
+ },
+ },
+ {
+ "capability not present",
+ args{
+ capabilityID: defaultCapability.ID,
+ oldState: registrysyncer.LocalRegistry{
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ newCapability.ID: newCapability,
+ },
+ },
+ newState: registrysyncer.LocalRegistry{
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ newCapability.ID: newCapability,
+ },
+ },
+ },
+ diffResult{},
+ true,
+ },
+ {
+ "diff present, new don",
+ args{
+ capabilityID: defaultCapability.ID,
+ oldState: registrysyncer.LocalRegistry{
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ defaultCapability.ID: defaultCapability,
+ },
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{},
+ },
+ newState: registrysyncer.LocalRegistry{
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ defaultCapability.ID: defaultCapability,
+ },
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ },
+ },
+ diffResult{
+ added: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ removed: map[registrysyncer.DonID]registrysyncer.DON{},
+ updated: map[registrysyncer.DonID]registrysyncer.DON{},
+ },
+ false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := diff(tt.args.capabilityID, tt.args.oldState, tt.args.newState)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.want, got)
+ }
+ })
+ }
+}
+
+func Test_compareDONs(t *testing.T) {
+ type args struct {
+ currCCIPDONs map[registrysyncer.DonID]registrysyncer.DON
+ newCCIPDONs map[registrysyncer.DonID]registrysyncer.DON
+ }
+ tests := []struct {
+ name string
+ args args
+ wantAdded map[registrysyncer.DonID]registrysyncer.DON
+ wantRemoved map[registrysyncer.DonID]registrysyncer.DON
+ wantUpdated map[registrysyncer.DonID]registrysyncer.DON
+ wantErr bool
+ }{
+ {
+ "added dons",
+ args{
+ currCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{},
+ newCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ },
+ map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ map[registrysyncer.DonID]registrysyncer.DON{},
+ map[registrysyncer.DonID]registrysyncer.DON{},
+ false,
+ },
+ {
+ "removed dons",
+ args{
+ currCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ newCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{},
+ },
+ map[registrysyncer.DonID]registrysyncer.DON{},
+ map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ map[registrysyncer.DonID]registrysyncer.DON{},
+ false,
+ },
+ {
+ "updated dons",
+ args{
+ currCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ newCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: {
+ DON: getDON(defaultRegistryDon.ID, defaultRegistryDon.Members, defaultRegistryDon.ConfigVersion+1),
+ CapabilityConfigurations: defaultCapCfgs,
+ },
+ },
+ },
+ map[registrysyncer.DonID]registrysyncer.DON{},
+ map[registrysyncer.DonID]registrysyncer.DON{},
+ map[registrysyncer.DonID]registrysyncer.DON{
+ 1: {
+ DON: getDON(defaultRegistryDon.ID, defaultRegistryDon.Members, defaultRegistryDon.ConfigVersion+1),
+ CapabilityConfigurations: defaultCapCfgs,
+ },
+ },
+ false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ dr, err := compareDONs(tt.args.currCCIPDONs, tt.args.newCCIPDONs)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.wantAdded, dr.added)
+ require.Equal(t, tt.wantRemoved, dr.removed)
+ require.Equal(t, tt.wantUpdated, dr.updated)
+ }
+ })
+ }
+}
+
+func Test_filterCCIPDONs(t *testing.T) {
+ type args struct {
+ ccipCapability registrysyncer.Capability
+ state registrysyncer.LocalRegistry
+ }
+ tests := []struct {
+ name string
+ args args
+ want map[registrysyncer.DonID]registrysyncer.DON
+ wantErr bool
+ }{
+ {
+ "one ccip don",
+ args{
+ ccipCapability: defaultCapability,
+ state: registrysyncer.LocalRegistry{
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ },
+ },
+ map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ false,
+ },
+ {
+ "no ccip dons - different capability",
+ args{
+ ccipCapability: newCapability,
+ state: registrysyncer.LocalRegistry{
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ },
+ },
+ map[registrysyncer.DonID]registrysyncer.DON{},
+ false,
+ },
+ {
+ "don with multiple capabilities, one of them ccip",
+ args{
+ ccipCapability: defaultCapability,
+ state: registrysyncer.LocalRegistry{
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: {
+ DON: getDON(1, []ragep2ptypes.PeerID{p2pID1}, 0),
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
+ defaultCapability.ID: {},
+ newCapability.ID: {},
+ },
+ },
+ },
+ },
+ },
+ map[registrysyncer.DonID]registrysyncer.DON{
+ 1: {
+ DON: getDON(1, []ragep2ptypes.PeerID{p2pID1}, 0),
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
+ defaultCapability.ID: {},
+ newCapability.ID: {},
+ },
+ },
+ },
+ false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := filterCCIPDONs(tt.args.ccipCapability, tt.args.state)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.want, got)
+ }
+ })
+ }
+}
+
+func Test_checkCapabilityPresence(t *testing.T) {
+ type args struct {
+ capabilityID string
+ state registrysyncer.LocalRegistry
+ }
+ tests := []struct {
+ name string
+ args args
+ want registrysyncer.Capability
+ wantErr bool
+ }{
+ {
+ "in registry state",
+ args{
+ capabilityID: defaultCapability.ID,
+ state: registrysyncer.LocalRegistry{
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ defaultCapability.ID: defaultCapability,
+ },
+ },
+ },
+ defaultCapability,
+ false,
+ },
+ {
+ "not in registry state",
+ args{
+ capabilityID: defaultCapability.ID,
+ state: registrysyncer.LocalRegistry{
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ newCapability.ID: newCapability,
+ },
+ },
+ },
+ registrysyncer.Capability{},
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := checkCapabilityPresence(tt.args.capabilityID, tt.args.state)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("checkCapabilityPresence() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("checkCapabilityPresence() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func Test_isMemberOfDON(t *testing.T) {
+ var p2pIDs []ragep2ptypes.PeerID
+ for i := range [4]struct{}{} {
+ p2pIDs = append(p2pIDs, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(i+1))).PeerID()))
+ }
+ don := registrysyncer.DON{
+ DON: getDON(1, p2pIDs, 0),
+ }
+ require.True(t, isMemberOfDON(don, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID())))
+ require.False(t, isMemberOfDON(don, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(5)).PeerID())))
+}
+
+func Test_isMemberOfBootstrapSubcommittee(t *testing.T) {
+ var bootstrapKeys [][32]byte
+ for i := range [4]struct{}{} {
+ bootstrapKeys = append(bootstrapKeys, p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(i+1))).PeerID())
+ }
+ require.True(t, isMemberOfBootstrapSubcommittee(bootstrapKeys, p2pID1))
+ require.False(t, isMemberOfBootstrapSubcommittee(bootstrapKeys, getP2PID(5)))
+}
diff --git a/core/capabilities/ccip/launcher/integration_test.go b/core/capabilities/ccip/launcher/integration_test.go
new file mode 100644
index 00000000000..7973316b31d
--- /dev/null
+++ b/core/capabilities/ccip/launcher/integration_test.go
@@ -0,0 +1,123 @@
+package launcher
+
+import (
+ "testing"
+ "time"
+
+ it "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccip_integration_tests/integrationhelpers"
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
+
+ "github.com/onsi/gomega"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+)
+
+func TestIntegration_Launcher(t *testing.T) {
+ ctx := testutils.Context(t)
+ lggr := logger.TestLogger(t)
+ uni := it.NewTestUniverse(ctx, t, lggr)
+ // We need 3*f + 1 p2pIDs to have enough nodes to bootstrap
+ var arr []int64
+ n := int(it.FChainA*3 + 1)
+ for i := 0; i <= n; i++ {
+ arr = append(arr, int64(i))
+ }
+ p2pIDs := it.P2pIDsFromInts(arr)
+ uni.AddCapability(p2pIDs)
+
+ db := pgtest.NewSqlxDB(t)
+ regSyncer, err := registrysyncer.New(lggr,
+ func() (p2ptypes.PeerID, error) {
+ return p2pIDs[0], nil
+ },
+ uni,
+ uni.CapReg.Address().String(),
+ registrysyncer.NewORM(db, lggr),
+ )
+ require.NoError(t, err)
+
+ hcr := uni.HomeChainReader
+
+ launcher := New(
+ it.CapabilityID,
+ p2pIDs[0],
+ logger.TestLogger(t),
+ hcr,
+ &oracleCreatorPrints{
+ t: t,
+ },
+ 1*time.Second,
+ )
+ regSyncer.AddLauncher(launcher)
+
+ require.NoError(t, launcher.Start(ctx))
+ require.NoError(t, regSyncer.Start(ctx))
+ t.Cleanup(func() { require.NoError(t, regSyncer.Close()) })
+ t.Cleanup(func() { require.NoError(t, launcher.Close()) })
+
+ chainAConf := it.SetupConfigInfo(it.ChainA, p2pIDs, it.FChainA, []byte("ChainA"))
+ chainBConf := it.SetupConfigInfo(it.ChainB, p2pIDs[1:], it.FChainB, []byte("ChainB"))
+ chainCConf := it.SetupConfigInfo(it.ChainC, p2pIDs[2:], it.FChainC, []byte("ChainC"))
+ inputConfig := []ccip_config.CCIPConfigTypesChainConfigInfo{
+ chainAConf,
+ chainBConf,
+ chainCConf,
+ }
+ _, err = uni.CcipCfg.ApplyChainConfigUpdates(uni.Transactor, nil, inputConfig)
+ require.NoError(t, err)
+ uni.Backend.Commit()
+
+ ccipCapabilityID, err := uni.CapReg.GetHashedCapabilityId(nil, it.CcipCapabilityLabelledName, it.CcipCapabilityVersion)
+ require.NoError(t, err)
+
+ uni.AddDONToRegistry(
+ ccipCapabilityID,
+ it.ChainA,
+ it.FChainA,
+ p2pIDs[1],
+ p2pIDs)
+
+ gomega.NewWithT(t).Eventually(func() bool {
+ return len(launcher.runningDONIDs()) == 1
+ }, testutils.WaitTimeout(t), testutils.TestInterval).Should(gomega.BeTrue())
+}
+
+type oraclePrints struct {
+ t *testing.T
+ pluginType cctypes.PluginType
+ config cctypes.OCR3ConfigWithMeta
+ isBootstrap bool
+}
+
+func (o *oraclePrints) Start() error {
+ o.t.Logf("Starting oracle (pluginType: %s, isBootstrap: %t) with config %+v\n", o.pluginType, o.isBootstrap, o.config)
+ return nil
+}
+
+func (o *oraclePrints) Close() error {
+ o.t.Logf("Closing oracle (pluginType: %s, isBootstrap: %t) with config %+v\n", o.pluginType, o.isBootstrap, o.config)
+ return nil
+}
+
+type oracleCreatorPrints struct {
+ t *testing.T
+}
+
+func (o *oracleCreatorPrints) CreatePluginOracle(pluginType cctypes.PluginType, config cctypes.OCR3ConfigWithMeta) (cctypes.CCIPOracle, error) {
+ o.t.Logf("Creating plugin oracle (pluginType: %s) with config %+v\n", pluginType, config)
+ return &oraclePrints{pluginType: pluginType, config: config, t: o.t}, nil
+}
+
+func (o *oracleCreatorPrints) CreateBootstrapOracle(config cctypes.OCR3ConfigWithMeta) (cctypes.CCIPOracle, error) {
+ o.t.Logf("Creating bootstrap oracle with config %+v\n", config)
+ return &oraclePrints{pluginType: cctypes.PluginTypeCCIPCommit, config: config, isBootstrap: true, t: o.t}, nil
+}
+
+var _ cctypes.OracleCreator = &oracleCreatorPrints{}
+var _ cctypes.CCIPOracle = &oraclePrints{}
diff --git a/core/capabilities/ccip/launcher/launcher.go b/core/capabilities/ccip/launcher/launcher.go
new file mode 100644
index 00000000000..2dc1a1954f5
--- /dev/null
+++ b/core/capabilities/ccip/launcher/launcher.go
@@ -0,0 +1,432 @@
+package launcher
+
+import (
+ "context"
+ "fmt"
+ "sync"
+ "time"
+
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+
+ "go.uber.org/multierr"
+
+ ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types"
+
+ ccipreader "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
+
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+)
+
+var (
+ _ job.ServiceCtx = (*launcher)(nil)
+ _ registrysyncer.Launcher = (*launcher)(nil)
+)
+
+func New(
+ capabilityID string,
+ p2pID ragep2ptypes.PeerID,
+ lggr logger.Logger,
+ homeChainReader ccipreader.HomeChain,
+ oracleCreator cctypes.OracleCreator,
+ tickInterval time.Duration,
+) *launcher {
+ return &launcher{
+ p2pID: p2pID,
+ capabilityID: capabilityID,
+ lggr: lggr,
+ homeChainReader: homeChainReader,
+ regState: registrysyncer.LocalRegistry{
+ IDsToDONs: make(map[registrysyncer.DonID]registrysyncer.DON),
+ IDsToNodes: make(map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo),
+ IDsToCapabilities: make(map[string]registrysyncer.Capability),
+ },
+ oracleCreator: oracleCreator,
+ dons: make(map[registrysyncer.DonID]*ccipDeployment),
+ tickInterval: tickInterval,
+ }
+}
+
+// launcher manages the lifecycles of the CCIP capability on all chains.
+type launcher struct {
+ services.StateMachine
+
+ capabilityID string
+ p2pID ragep2ptypes.PeerID
+ lggr logger.Logger
+ homeChainReader ccipreader.HomeChain
+ stopChan chan struct{}
+ // latestState is the latest capability registry state received from the syncer.
+ latestState registrysyncer.LocalRegistry
+ // regState is the latest capability registry state that we have successfully processed.
+ regState registrysyncer.LocalRegistry
+ oracleCreator cctypes.OracleCreator
+ lock sync.RWMutex
+ wg sync.WaitGroup
+ tickInterval time.Duration
+
+ // dons is a map of CCIP DON IDs to the OCR instances that are running on them.
+ // we can have up to two OCR instances per CCIP plugin, since we are running two plugins,
+ // thats four OCR instances per CCIP DON maximum.
+ dons map[registrysyncer.DonID]*ccipDeployment
+}
+
+// Launch implements registrysyncer.Launcher.
+func (l *launcher) Launch(ctx context.Context, state *registrysyncer.LocalRegistry) error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+ l.lggr.Debugw("Received new state from syncer", "dons", state.IDsToDONs)
+ l.latestState = *state
+ return nil
+}
+
+func (l *launcher) getLatestState() registrysyncer.LocalRegistry {
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ return l.latestState
+}
+
+func (l *launcher) runningDONIDs() []registrysyncer.DonID {
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ var runningDONs []registrysyncer.DonID
+ for id := range l.dons {
+ runningDONs = append(runningDONs, id)
+ }
+ return runningDONs
+}
+
+// Close implements job.ServiceCtx.
+func (l *launcher) Close() error {
+ return l.StateMachine.StopOnce("launcher", func() error {
+ // shut down the monitor goroutine.
+ close(l.stopChan)
+ l.wg.Wait()
+
+ // shut down all running oracles.
+ var err error
+ for _, ceDep := range l.dons {
+ err = multierr.Append(err, ceDep.Close())
+ }
+
+ return err
+ })
+}
+
+// Start implements job.ServiceCtx.
+func (l *launcher) Start(context.Context) error {
+ return l.StartOnce("launcher", func() error {
+ l.stopChan = make(chan struct{})
+ l.wg.Add(1)
+ go l.monitor()
+ return nil
+ })
+}
+
+func (l *launcher) monitor() {
+ defer l.wg.Done()
+ ticker := time.NewTicker(l.tickInterval)
+ for {
+ select {
+ case <-l.stopChan:
+ return
+ case <-ticker.C:
+ if err := l.tick(); err != nil {
+ l.lggr.Errorw("Failed to tick", "err", err)
+ }
+ }
+ }
+}
+
+func (l *launcher) tick() error {
+ // Ensure that the home chain reader is healthy.
+ // For new jobs it may be possible that the home chain reader is not yet ready
+ // so we won't be able to fetch configs and start any OCR instances.
+ if ready := l.homeChainReader.Ready(); ready != nil {
+ return fmt.Errorf("home chain reader is not ready: %w", ready)
+ }
+
+ // Fetch the latest state from the capability registry and determine if we need to
+ // launch or update any OCR instances.
+ latestState := l.getLatestState()
+
+ diffRes, err := diff(l.capabilityID, l.regState, latestState)
+ if err != nil {
+ return fmt.Errorf("failed to diff capability registry states: %w", err)
+ }
+
+ err = l.processDiff(diffRes)
+ if err != nil {
+ return fmt.Errorf("failed to process diff: %w", err)
+ }
+
+ return nil
+}
+
+// processDiff processes the diff between the current and latest capability registry states.
+// for any added OCR instances, it will launch them.
+// for any removed OCR instances, it will shut them down.
+// for any updated OCR instances, it will restart them with the new configuration.
+func (l *launcher) processDiff(diff diffResult) error {
+ err := l.processRemoved(diff.removed)
+ err = multierr.Append(err, l.processAdded(diff.added))
+ err = multierr.Append(err, l.processUpdate(diff.updated))
+
+ return err
+}
+
+func (l *launcher) processUpdate(updated map[registrysyncer.DonID]registrysyncer.DON) error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ for donID, don := range updated {
+ prevDeployment, ok := l.dons[registrysyncer.DonID(don.ID)]
+ if !ok {
+ return fmt.Errorf("invariant violation: expected to find CCIP DON %d in the map of running deployments", don.ID)
+ }
+
+ futDeployment, err := updateDON(
+ l.lggr,
+ l.p2pID,
+ l.homeChainReader,
+ l.oracleCreator,
+ *prevDeployment,
+ don,
+ )
+ if err != nil {
+ return err
+ }
+ if err := futDeployment.HandleBlueGreen(prevDeployment); err != nil {
+ // TODO: how to handle a failed blue-green deployment?
+ return fmt.Errorf("failed to handle blue-green deployment for CCIP DON %d: %w", donID, err)
+ }
+
+ // update state.
+ l.dons[donID] = futDeployment
+ // update the state with the latest config.
+ // this way if one of the starts errors, we don't retry all of them.
+ l.regState.IDsToDONs[donID] = updated[donID]
+ }
+
+ return nil
+}
+
+func (l *launcher) processAdded(added map[registrysyncer.DonID]registrysyncer.DON) error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ for donID, don := range added {
+ dep, err := createDON(
+ l.lggr,
+ l.p2pID,
+ l.homeChainReader,
+ l.oracleCreator,
+ don,
+ )
+ if err != nil {
+ return err
+ }
+ if dep == nil {
+ // not a member of this DON.
+ continue
+ }
+
+ if err := dep.StartBlue(); err != nil {
+ if shutdownErr := dep.CloseBlue(); shutdownErr != nil {
+ l.lggr.Errorw("Failed to shutdown blue instance after failed start", "donId", donID, "err", shutdownErr)
+ }
+ return fmt.Errorf("failed to start oracles for CCIP DON %d: %w", donID, err)
+ }
+
+ // update state.
+ l.dons[donID] = dep
+ // update the state with the latest config.
+ // this way if one of the starts errors, we don't retry all of them.
+ l.regState.IDsToDONs[donID] = added[donID]
+ }
+
+ return nil
+}
+
+func (l *launcher) processRemoved(removed map[registrysyncer.DonID]registrysyncer.DON) error {
+ l.lock.Lock()
+ defer l.lock.Unlock()
+
+ for id := range removed {
+ ceDep, ok := l.dons[id]
+ if !ok {
+ // not running this particular DON.
+ continue
+ }
+
+ if err := ceDep.Close(); err != nil {
+ return fmt.Errorf("failed to shutdown oracles for CCIP DON %d: %w", id, err)
+ }
+
+ // after a successful shutdown we can safely remove the DON deployment from the map.
+ delete(l.dons, id)
+ delete(l.regState.IDsToDONs, id)
+ }
+
+ return nil
+}
+
+// updateDON is a pure function that handles the case where a DON in the capability registry
+// has received a new configuration.
+// It returns a new ccipDeployment that can then be used to perform the blue-green deployment,
+// based on the previous deployment.
+func updateDON(
+ lggr logger.Logger,
+ p2pID ragep2ptypes.PeerID,
+ homeChainReader ccipreader.HomeChain,
+ oracleCreator cctypes.OracleCreator,
+ prevDeployment ccipDeployment,
+ don registrysyncer.DON,
+) (futDeployment *ccipDeployment, err error) {
+ if !isMemberOfDON(don, p2pID) {
+ lggr.Infow("Not a member of this DON, skipping", "donId", don.ID, "p2pId", p2pID.String())
+ return nil, nil
+ }
+
+ // this should be a retryable error.
+ commitOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.ID, uint8(cctypes.PluginTypeCCIPCommit))
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch OCR configs for CCIP commit plugin (don id: %d) from home chain config contract: %w",
+ don.ID, err)
+ }
+
+ execOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.ID, uint8(cctypes.PluginTypeCCIPExec))
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch OCR configs for CCIP exec plugin (don id: %d) from home chain config contract: %w",
+ don.ID, err)
+ }
+
+ commitBgd, err := createFutureBlueGreenDeployment(prevDeployment, commitOCRConfigs, oracleCreator, cctypes.PluginTypeCCIPCommit)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create future blue-green deployment for CCIP commit plugin: %w, don id: %d", err, don.ID)
+ }
+
+ execBgd, err := createFutureBlueGreenDeployment(prevDeployment, execOCRConfigs, oracleCreator, cctypes.PluginTypeCCIPExec)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create future blue-green deployment for CCIP exec plugin: %w, don id: %d", err, don.ID)
+ }
+
+ return &ccipDeployment{
+ commit: commitBgd,
+ exec: execBgd,
+ }, nil
+}
+
+// valid cases:
+// a) len(ocrConfigs) == 2 && !prevDeployment.HasGreenInstance(pluginType): this is a new green instance.
+// b) len(ocrConfigs) == 1 && prevDeployment.HasGreenInstance(): this is a promotion of green->blue.
+// All other cases are invalid. This is enforced in the ccip config contract.
+func createFutureBlueGreenDeployment(
+ prevDeployment ccipDeployment,
+ ocrConfigs []ccipreader.OCR3ConfigWithMeta,
+ oracleCreator cctypes.OracleCreator,
+ pluginType cctypes.PluginType,
+) (blueGreenDeployment, error) {
+ var deployment blueGreenDeployment
+ if isNewGreenInstance(pluginType, ocrConfigs, prevDeployment) {
+ // this is a new green instance.
+ greenOracle, err := oracleCreator.CreatePluginOracle(pluginType, cctypes.OCR3ConfigWithMeta(ocrConfigs[1]))
+ if err != nil {
+ return blueGreenDeployment{}, fmt.Errorf("failed to create CCIP commit oracle: %w", err)
+ }
+
+ deployment.blue = prevDeployment.commit.blue
+ deployment.green = greenOracle
+ } else if isPromotion(pluginType, ocrConfigs, prevDeployment) {
+ // this is a promotion of green->blue.
+ deployment.blue = prevDeployment.commit.green
+ } else {
+ return blueGreenDeployment{}, fmt.Errorf("invariant violation: expected 1 or 2 OCR configs for CCIP plugin (type: %d), got %d", pluginType, len(ocrConfigs))
+ }
+
+ return deployment, nil
+}
+
+// createDON is a pure function that handles the case where a new DON is added to the capability registry.
+// It returns a new ccipDeployment that can then be used to start the blue instance.
+func createDON(
+ lggr logger.Logger,
+ p2pID ragep2ptypes.PeerID,
+ homeChainReader ccipreader.HomeChain,
+ oracleCreator cctypes.OracleCreator,
+ don registrysyncer.DON,
+) (*ccipDeployment, error) {
+ if !isMemberOfDON(don, p2pID) {
+ lggr.Infow("Not a member of this DON, skipping", "donId", don.ID, "p2pId", p2pID.String())
+ return nil, nil
+ }
+
+ // this should be a retryable error.
+ commitOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.ID, uint8(cctypes.PluginTypeCCIPCommit))
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch OCR configs for CCIP commit plugin (don id: %d) from home chain config contract: %w",
+ don.ID, err)
+ }
+
+ execOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.ID, uint8(cctypes.PluginTypeCCIPExec))
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch OCR configs for CCIP exec plugin (don id: %d) from home chain config contract: %w",
+ don.ID, err)
+ }
+
+ // upon creation we should only have one OCR config per plugin type.
+ if len(commitOCRConfigs) != 1 {
+ return nil, fmt.Errorf("expected exactly one OCR config for CCIP commit plugin (don id: %d), got %d", don.ID, len(commitOCRConfigs))
+ }
+
+ if len(execOCRConfigs) != 1 {
+ return nil, fmt.Errorf("expected exactly one OCR config for CCIP exec plugin (don id: %d), got %d", don.ID, len(execOCRConfigs))
+ }
+
+ commitOracle, commitBootstrap, err := createOracle(p2pID, oracleCreator, cctypes.PluginTypeCCIPCommit, commitOCRConfigs)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create CCIP commit oracle: %w", err)
+ }
+
+ execOracle, execBootstrap, err := createOracle(p2pID, oracleCreator, cctypes.PluginTypeCCIPExec, execOCRConfigs)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create CCIP exec oracle: %w", err)
+ }
+
+ return &ccipDeployment{
+ commit: blueGreenDeployment{
+ blue: commitOracle,
+ bootstrapBlue: commitBootstrap,
+ },
+ exec: blueGreenDeployment{
+ blue: execOracle,
+ bootstrapBlue: execBootstrap,
+ },
+ }, nil
+}
+
+func createOracle(
+ p2pID ragep2ptypes.PeerID,
+ oracleCreator cctypes.OracleCreator,
+ pluginType cctypes.PluginType,
+ ocrConfigs []ccipreader.OCR3ConfigWithMeta,
+) (pluginOracle, bootstrapOracle cctypes.CCIPOracle, err error) {
+ pluginOracle, err = oracleCreator.CreatePluginOracle(pluginType, cctypes.OCR3ConfigWithMeta(ocrConfigs[0]))
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to create CCIP plugin oracle (plugintype: %d): %w", pluginType, err)
+ }
+
+ if isMemberOfBootstrapSubcommittee(ocrConfigs[0].Config.BootstrapP2PIds, p2pID) {
+ bootstrapOracle, err = oracleCreator.CreateBootstrapOracle(cctypes.OCR3ConfigWithMeta(ocrConfigs[0]))
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to create CCIP bootstrap oracle (plugintype: %d): %w", pluginType, err)
+ }
+ }
+
+ return pluginOracle, bootstrapOracle, nil
+}
diff --git a/core/capabilities/ccip/launcher/launcher_test.go b/core/capabilities/ccip/launcher/launcher_test.go
new file mode 100644
index 00000000000..242dd0be248
--- /dev/null
+++ b/core/capabilities/ccip/launcher/launcher_test.go
@@ -0,0 +1,472 @@
+package launcher
+
+import (
+ "errors"
+ "math/big"
+ "reflect"
+ "testing"
+
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types/mocks"
+
+ ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+)
+
+func Test_createOracle(t *testing.T) {
+ var p2pKeys []ragep2ptypes.PeerID
+ for i := 0; i < 3; i++ {
+ p2pKeys = append(p2pKeys, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(i+1))).PeerID()))
+ }
+ myP2PKey := p2pKeys[0]
+ type args struct {
+ p2pID ragep2ptypes.PeerID
+ oracleCreator *mocks.OracleCreator
+ pluginType cctypes.PluginType
+ ocrConfigs []ccipreaderpkg.OCR3ConfigWithMeta
+ }
+ tests := []struct {
+ name string
+ args args
+ expect func(t *testing.T, args args, oracleCreator *mocks.OracleCreator)
+ wantErr bool
+ }{
+ {
+ "success, no bootstrap",
+ args{
+ myP2PKey,
+ mocks.NewOracleCreator(t),
+ cctypes.PluginTypeCCIPCommit,
+ []ccipreaderpkg.OCR3ConfigWithMeta{
+ {
+ Config: ccipreaderpkg.OCR3Config{},
+ ConfigCount: 1,
+ ConfigDigest: testutils.Random32Byte(),
+ },
+ },
+ },
+ func(t *testing.T, args args, oracleCreator *mocks.OracleCreator) {
+ oracleCreator.
+ On("CreatePluginOracle", cctypes.PluginTypeCCIPCommit, cctypes.OCR3ConfigWithMeta(args.ocrConfigs[0])).
+ Return(mocks.NewCCIPOracle(t), nil)
+ },
+ false,
+ },
+ {
+ "success, with bootstrap",
+ args{
+ myP2PKey,
+ mocks.NewOracleCreator(t),
+ cctypes.PluginTypeCCIPCommit,
+ []ccipreaderpkg.OCR3ConfigWithMeta{
+ {
+ Config: ccipreaderpkg.OCR3Config{
+ BootstrapP2PIds: [][32]byte{myP2PKey},
+ },
+ ConfigCount: 1,
+ ConfigDigest: testutils.Random32Byte(),
+ },
+ },
+ },
+ func(t *testing.T, args args, oracleCreator *mocks.OracleCreator) {
+ oracleCreator.
+ On("CreatePluginOracle", cctypes.PluginTypeCCIPCommit, cctypes.OCR3ConfigWithMeta(args.ocrConfigs[0])).
+ Return(mocks.NewCCIPOracle(t), nil)
+ oracleCreator.
+ On("CreateBootstrapOracle", cctypes.OCR3ConfigWithMeta(args.ocrConfigs[0])).
+ Return(mocks.NewCCIPOracle(t), nil)
+ },
+ false,
+ },
+ {
+ "error creating plugin oracle",
+ args{
+ myP2PKey,
+ mocks.NewOracleCreator(t),
+ cctypes.PluginTypeCCIPCommit,
+ []ccipreaderpkg.OCR3ConfigWithMeta{
+ {
+ Config: ccipreaderpkg.OCR3Config{},
+ ConfigCount: 1,
+ ConfigDigest: testutils.Random32Byte(),
+ },
+ },
+ },
+ func(t *testing.T, args args, oracleCreator *mocks.OracleCreator) {
+ oracleCreator.
+ On("CreatePluginOracle", cctypes.PluginTypeCCIPCommit, cctypes.OCR3ConfigWithMeta(args.ocrConfigs[0])).
+ Return(nil, errors.New("error creating oracle"))
+ },
+ true,
+ },
+ {
+ "error creating bootstrap oracle",
+ args{
+ myP2PKey,
+ mocks.NewOracleCreator(t),
+ cctypes.PluginTypeCCIPCommit,
+ []ccipreaderpkg.OCR3ConfigWithMeta{
+ {
+ Config: ccipreaderpkg.OCR3Config{
+ BootstrapP2PIds: [][32]byte{myP2PKey},
+ },
+ ConfigCount: 1,
+ ConfigDigest: testutils.Random32Byte(),
+ },
+ },
+ },
+ func(t *testing.T, args args, oracleCreator *mocks.OracleCreator) {
+ oracleCreator.
+ On("CreatePluginOracle", cctypes.PluginTypeCCIPCommit, cctypes.OCR3ConfigWithMeta(args.ocrConfigs[0])).
+ Return(mocks.NewCCIPOracle(t), nil)
+ oracleCreator.
+ On("CreateBootstrapOracle", cctypes.OCR3ConfigWithMeta(args.ocrConfigs[0])).
+ Return(nil, errors.New("error creating oracle"))
+ },
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ tt.expect(t, tt.args, tt.args.oracleCreator)
+ _, _, err := createOracle(tt.args.p2pID, tt.args.oracleCreator, tt.args.pluginType, tt.args.ocrConfigs)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
+
+func Test_createDON(t *testing.T) {
+ type args struct {
+ lggr logger.Logger
+ p2pID ragep2ptypes.PeerID
+ homeChainReader *mocks.HomeChainReader
+ oracleCreator *mocks.OracleCreator
+ don registrysyncer.DON
+ }
+ tests := []struct {
+ name string
+ args args
+ expect func(t *testing.T, args args, oracleCreator *mocks.OracleCreator, homeChainReader *mocks.HomeChainReader)
+ wantErr bool
+ }{
+ {
+ "not a member of the DON",
+ args{
+ logger.TestLogger(t),
+ p2pID1,
+ mocks.NewHomeChainReader(t),
+ mocks.NewOracleCreator(t),
+ registrysyncer.DON{
+ DON: getDON(2, []ragep2ptypes.PeerID{p2pID2}, 0),
+ CapabilityConfigurations: defaultCapCfgs,
+ },
+ },
+ func(t *testing.T, args args, oracleCreator *mocks.OracleCreator, homeChainReader *mocks.HomeChainReader) {
+ },
+ false,
+ },
+ {
+ "success, no bootstrap",
+ args{
+ logger.TestLogger(t),
+ p2pID1,
+ mocks.NewHomeChainReader(t),
+ mocks.NewOracleCreator(t),
+ defaultRegistryDon,
+ },
+ func(t *testing.T, args args, oracleCreator *mocks.OracleCreator, homeChainReader *mocks.HomeChainReader) {
+ homeChainReader.
+ On("GetOCRConfigs", mock.Anything, uint32(1), uint8(cctypes.PluginTypeCCIPCommit)).
+ Return([]ccipreaderpkg.OCR3ConfigWithMeta{{}}, nil)
+ homeChainReader.
+ On("GetOCRConfigs", mock.Anything, uint32(1), uint8(cctypes.PluginTypeCCIPExec)).
+ Return([]ccipreaderpkg.OCR3ConfigWithMeta{{}}, nil)
+ oracleCreator.
+ On("CreatePluginOracle", cctypes.PluginTypeCCIPCommit, mock.Anything).
+ Return(mocks.NewCCIPOracle(t), nil)
+ oracleCreator.
+ On("CreatePluginOracle", cctypes.PluginTypeCCIPExec, mock.Anything).
+ Return(mocks.NewCCIPOracle(t), nil)
+ },
+ false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if tt.expect != nil {
+ tt.expect(t, tt.args, tt.args.oracleCreator, tt.args.homeChainReader)
+ }
+ _, err := createDON(tt.args.lggr, tt.args.p2pID, tt.args.homeChainReader, tt.args.oracleCreator, tt.args.don)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
+
+func Test_createFutureBlueGreenDeployment(t *testing.T) {
+ type args struct {
+ prevDeployment ccipDeployment
+ ocrConfigs []ccipreaderpkg.OCR3ConfigWithMeta
+ oracleCreator *mocks.OracleCreator
+ pluginType cctypes.PluginType
+ }
+ tests := []struct {
+ name string
+ args args
+ want blueGreenDeployment
+ wantErr bool
+ }{
+ // TODO: Add test cases.
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := createFutureBlueGreenDeployment(tt.args.prevDeployment, tt.args.ocrConfigs, tt.args.oracleCreator, tt.args.pluginType)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("createFutureBlueGreenDeployment() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("createFutureBlueGreenDeployment() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func Test_updateDON(t *testing.T) {
+ type args struct {
+ lggr logger.Logger
+ p2pID ragep2ptypes.PeerID
+ homeChainReader *mocks.HomeChainReader
+ oracleCreator *mocks.OracleCreator
+ prevDeployment ccipDeployment
+ don registrysyncer.DON
+ }
+ tests := []struct {
+ name string
+ args args
+ wantFutDeployment *ccipDeployment
+ wantErr bool
+ }{
+ // TODO: Add test cases.
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ gotFutDeployment, err := updateDON(tt.args.lggr, tt.args.p2pID, tt.args.homeChainReader, tt.args.oracleCreator, tt.args.prevDeployment, tt.args.don)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("updateDON() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if !reflect.DeepEqual(gotFutDeployment, tt.wantFutDeployment) {
+ t.Errorf("updateDON() = %v, want %v", gotFutDeployment, tt.wantFutDeployment)
+ }
+ })
+ }
+}
+
+func Test_launcher_processDiff(t *testing.T) {
+ type fields struct {
+ lggr logger.Logger
+ p2pID ragep2ptypes.PeerID
+ homeChainReader *mocks.HomeChainReader
+ oracleCreator *mocks.OracleCreator
+ dons map[registrysyncer.DonID]*ccipDeployment
+ regState registrysyncer.LocalRegistry
+ }
+ type args struct {
+ diff diffResult
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ assert func(t *testing.T, l *launcher)
+ wantErr bool
+ }{
+ {
+ "don removed success",
+ fields{
+ dons: map[registrysyncer.DonID]*ccipDeployment{
+ 1: {
+ commit: blueGreenDeployment{
+ blue: newMock(t,
+ func(t *testing.T) *mocks.CCIPOracle { return mocks.NewCCIPOracle(t) },
+ func(m *mocks.CCIPOracle) {
+ m.On("Close").Return(nil)
+ }),
+ },
+ exec: blueGreenDeployment{
+ blue: newMock(t,
+ func(t *testing.T) *mocks.CCIPOracle { return mocks.NewCCIPOracle(t) },
+ func(m *mocks.CCIPOracle) {
+ m.On("Close").Return(nil)
+ }),
+ },
+ },
+ },
+ regState: registrysyncer.LocalRegistry{
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ },
+ },
+ args{
+ diff: diffResult{
+ removed: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ },
+ },
+ func(t *testing.T, l *launcher) {
+ require.Len(t, l.dons, 0)
+ require.Len(t, l.regState.IDsToDONs, 0)
+ },
+ false,
+ },
+ {
+ "don added success",
+ fields{
+ lggr: logger.TestLogger(t),
+ p2pID: p2pID1,
+ homeChainReader: newMock(t, func(t *testing.T) *mocks.HomeChainReader {
+ return mocks.NewHomeChainReader(t)
+ }, func(m *mocks.HomeChainReader) {
+ m.On("GetOCRConfigs", mock.Anything, uint32(1), uint8(cctypes.PluginTypeCCIPCommit)).
+ Return([]ccipreaderpkg.OCR3ConfigWithMeta{{}}, nil)
+ m.On("GetOCRConfigs", mock.Anything, uint32(1), uint8(cctypes.PluginTypeCCIPExec)).
+ Return([]ccipreaderpkg.OCR3ConfigWithMeta{{}}, nil)
+ }),
+ oracleCreator: newMock(t, func(t *testing.T) *mocks.OracleCreator {
+ return mocks.NewOracleCreator(t)
+ }, func(m *mocks.OracleCreator) {
+ commitOracle := mocks.NewCCIPOracle(t)
+ commitOracle.On("Start").Return(nil)
+ execOracle := mocks.NewCCIPOracle(t)
+ execOracle.On("Start").Return(nil)
+ m.On("CreatePluginOracle", cctypes.PluginTypeCCIPCommit, mock.Anything).
+ Return(commitOracle, nil)
+ m.On("CreatePluginOracle", cctypes.PluginTypeCCIPExec, mock.Anything).
+ Return(execOracle, nil)
+ }),
+ dons: map[registrysyncer.DonID]*ccipDeployment{},
+ regState: registrysyncer.LocalRegistry{
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{},
+ },
+ },
+ args{
+ diff: diffResult{
+ added: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ },
+ },
+ func(t *testing.T, l *launcher) {
+ require.Len(t, l.dons, 1)
+ require.Len(t, l.regState.IDsToDONs, 1)
+ },
+ false,
+ },
+ {
+ "don updated new green instance success",
+ fields{
+ lggr: logger.TestLogger(t),
+ p2pID: p2pID1,
+ homeChainReader: newMock(t, func(t *testing.T) *mocks.HomeChainReader {
+ return mocks.NewHomeChainReader(t)
+ }, func(m *mocks.HomeChainReader) {
+ m.On("GetOCRConfigs", mock.Anything, uint32(1), uint8(cctypes.PluginTypeCCIPCommit)).
+ Return([]ccipreaderpkg.OCR3ConfigWithMeta{{}, {}}, nil)
+ m.On("GetOCRConfigs", mock.Anything, uint32(1), uint8(cctypes.PluginTypeCCIPExec)).
+ Return([]ccipreaderpkg.OCR3ConfigWithMeta{{}, {}}, nil)
+ }),
+ oracleCreator: newMock(t, func(t *testing.T) *mocks.OracleCreator {
+ return mocks.NewOracleCreator(t)
+ }, func(m *mocks.OracleCreator) {
+ commitOracle := mocks.NewCCIPOracle(t)
+ commitOracle.On("Start").Return(nil)
+ execOracle := mocks.NewCCIPOracle(t)
+ execOracle.On("Start").Return(nil)
+ m.On("CreatePluginOracle", cctypes.PluginTypeCCIPCommit, mock.Anything).
+ Return(commitOracle, nil)
+ m.On("CreatePluginOracle", cctypes.PluginTypeCCIPExec, mock.Anything).
+ Return(execOracle, nil)
+ }),
+ dons: map[registrysyncer.DonID]*ccipDeployment{
+ 1: {
+ commit: blueGreenDeployment{
+ blue: newMock(t, func(t *testing.T) *mocks.CCIPOracle {
+ return mocks.NewCCIPOracle(t)
+ }, func(m *mocks.CCIPOracle) {}),
+ },
+ exec: blueGreenDeployment{
+ blue: newMock(t, func(t *testing.T) *mocks.CCIPOracle {
+ return mocks.NewCCIPOracle(t)
+ }, func(m *mocks.CCIPOracle) {}),
+ },
+ },
+ },
+ regState: registrysyncer.LocalRegistry{
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: defaultRegistryDon,
+ },
+ },
+ },
+ args{
+ diff: diffResult{
+ updated: map[registrysyncer.DonID]registrysyncer.DON{
+ 1: {
+ // new Node in Don: p2pID2
+ DON: getDON(1, []ragep2ptypes.PeerID{p2pID1, p2pID2}, 0),
+ CapabilityConfigurations: defaultCapCfgs,
+ },
+ },
+ },
+ },
+ func(t *testing.T, l *launcher) {
+ require.Len(t, l.dons, 1)
+ require.Len(t, l.regState.IDsToDONs, 1)
+ require.Len(t, l.regState.IDsToDONs[1].Members, 2)
+ },
+ false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ l := &launcher{
+ dons: tt.fields.dons,
+ regState: tt.fields.regState,
+ p2pID: tt.fields.p2pID,
+ lggr: tt.fields.lggr,
+ homeChainReader: tt.fields.homeChainReader,
+ oracleCreator: tt.fields.oracleCreator,
+ }
+ err := l.processDiff(tt.args.diff)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ tt.assert(t, l)
+ })
+ }
+}
+
+func newMock[T any](t *testing.T, newer func(t *testing.T) T, expect func(m T)) T {
+ o := newer(t)
+ expect(o)
+ return o
+}
diff --git a/core/capabilities/ccip/launcher/test_helpers.go b/core/capabilities/ccip/launcher/test_helpers.go
new file mode 100644
index 00000000000..e1b47fa3521
--- /dev/null
+++ b/core/capabilities/ccip/launcher/test_helpers.go
@@ -0,0 +1,56 @@
+package launcher
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+
+ ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types"
+)
+
+const (
+ ccipCapVersion = "v1.0.0"
+ ccipCapNewVersion = "v1.1.0"
+ ccipCapName = "ccip"
+)
+
+var (
+ defaultCapability = getCapability(ccipCapName, ccipCapVersion)
+ newCapability = getCapability(ccipCapName, ccipCapNewVersion)
+ p2pID1 = getP2PID(1)
+ p2pID2 = getP2PID(2)
+ defaultCapCfgs = map[string]registrysyncer.CapabilityConfiguration{
+ defaultCapability.ID: {},
+ }
+ defaultRegistryDon = registrysyncer.DON{
+ DON: getDON(1, []ragep2ptypes.PeerID{p2pID1}, 0),
+ CapabilityConfigurations: defaultCapCfgs,
+ }
+)
+
+func getP2PID(id uint32) ragep2ptypes.PeerID {
+ return ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(id))).PeerID())
+}
+
+func getCapability(ccipCapName, ccipCapVersion string) registrysyncer.Capability {
+ id := fmt.Sprintf("%s@%s", ccipCapName, ccipCapVersion)
+ return registrysyncer.Capability{
+ CapabilityType: capabilities.CapabilityTypeTarget,
+ ID: id,
+ }
+}
+
+func getDON(id uint32, members []ragep2ptypes.PeerID, cfgVersion uint32) capabilities.DON {
+ return capabilities.DON{
+ ID: id,
+ ConfigVersion: cfgVersion,
+ F: uint8(1),
+ IsPublic: true,
+ AcceptsWorkflows: true,
+ Members: members,
+ }
+}
diff --git a/core/capabilities/ccip/ocrimpls/config_digester.go b/core/capabilities/ccip/ocrimpls/config_digester.go
new file mode 100644
index 00000000000..ef0c5e7ca32
--- /dev/null
+++ b/core/capabilities/ccip/ocrimpls/config_digester.go
@@ -0,0 +1,23 @@
+package ocrimpls
+
+import "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+type configDigester struct {
+ d types.ConfigDigest
+}
+
+func NewConfigDigester(d types.ConfigDigest) *configDigester {
+ return &configDigester{d: d}
+}
+
+// ConfigDigest implements types.OffchainConfigDigester.
+func (c *configDigester) ConfigDigest(types.ContractConfig) (types.ConfigDigest, error) {
+ return c.d, nil
+}
+
+// ConfigDigestPrefix implements types.OffchainConfigDigester.
+func (c *configDigester) ConfigDigestPrefix() (types.ConfigDigestPrefix, error) {
+ return types.ConfigDigestPrefixCCIPMultiRole, nil
+}
+
+var _ types.OffchainConfigDigester = (*configDigester)(nil)
diff --git a/core/capabilities/ccip/ocrimpls/config_tracker.go b/core/capabilities/ccip/ocrimpls/config_tracker.go
new file mode 100644
index 00000000000..3a6a27fa40c
--- /dev/null
+++ b/core/capabilities/ccip/ocrimpls/config_tracker.go
@@ -0,0 +1,77 @@
+package ocrimpls
+
+import (
+ "context"
+
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+
+ gethcommon "github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+)
+
+type configTracker struct {
+ cfg cctypes.OCR3ConfigWithMeta
+}
+
+func NewConfigTracker(cfg cctypes.OCR3ConfigWithMeta) *configTracker {
+ return &configTracker{cfg: cfg}
+}
+
+// LatestBlockHeight implements types.ContractConfigTracker.
+func (c *configTracker) LatestBlockHeight(ctx context.Context) (blockHeight uint64, err error) {
+ return 0, nil
+}
+
+// LatestConfig implements types.ContractConfigTracker.
+func (c *configTracker) LatestConfig(ctx context.Context, changedInBlock uint64) (types.ContractConfig, error) {
+ return c.contractConfig(), nil
+}
+
+// LatestConfigDetails implements types.ContractConfigTracker.
+func (c *configTracker) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest types.ConfigDigest, err error) {
+ return 0, c.cfg.ConfigDigest, nil
+}
+
+// Notify implements types.ContractConfigTracker.
+func (c *configTracker) Notify() <-chan struct{} {
+ return nil
+}
+
+func (c *configTracker) contractConfig() types.ContractConfig {
+ return types.ContractConfig{
+ ConfigDigest: c.cfg.ConfigDigest,
+ ConfigCount: c.cfg.ConfigCount,
+ Signers: toOnchainPublicKeys(c.cfg.Config.Signers),
+ Transmitters: toOCRAccounts(c.cfg.Config.Transmitters),
+ F: c.cfg.Config.F,
+ OnchainConfig: []byte{},
+ OffchainConfigVersion: c.cfg.Config.OffchainConfigVersion,
+ OffchainConfig: c.cfg.Config.OffchainConfig,
+ }
+}
+
+// PublicConfig returns the OCR configuration as a PublicConfig so that we can
+// access ReportingPluginConfig and other fields prior to launching the plugins.
+func (c *configTracker) PublicConfig() (ocr3confighelper.PublicConfig, error) {
+ return ocr3confighelper.PublicConfigFromContractConfig(false, c.contractConfig())
+}
+
+func toOnchainPublicKeys(signers [][]byte) []types.OnchainPublicKey {
+ keys := make([]types.OnchainPublicKey, len(signers))
+ for i, signer := range signers {
+ keys[i] = types.OnchainPublicKey(signer)
+ }
+ return keys
+}
+
+func toOCRAccounts(transmitters [][]byte) []types.Account {
+ accounts := make([]types.Account, len(transmitters))
+ for i, transmitter := range transmitters {
+ // TODO: string-encode the transmitter appropriately to the dest chain family.
+ accounts[i] = types.Account(gethcommon.BytesToAddress(transmitter).Hex())
+ }
+ return accounts
+}
+
+var _ types.ContractConfigTracker = (*configTracker)(nil)
diff --git a/core/capabilities/ccip/ocrimpls/contract_transmitter.go b/core/capabilities/ccip/ocrimpls/contract_transmitter.go
new file mode 100644
index 00000000000..fd8e206d0e3
--- /dev/null
+++ b/core/capabilities/ccip/ocrimpls/contract_transmitter.go
@@ -0,0 +1,188 @@
+package ocrimpls
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/google/uuid"
+ "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-ccip/pkg/consts"
+ commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
+)
+
+type ToCalldataFunc func(rawReportCtx [3][32]byte, report []byte, rs, ss [][32]byte, vs [32]byte) any
+
+func ToCommitCalldata(rawReportCtx [3][32]byte, report []byte, rs, ss [][32]byte, vs [32]byte) any {
+ // Note that the name of the struct field is very important, since the encoder used
+ // by the chainwriter uses mapstructure, which will use the struct field name to map
+ // to the argument name in the function call.
+ // If, for whatever reason, we want to change the field name, make sure to add a `mapstructure:""` tag
+ // for that field.
+ return struct {
+ ReportContext [3][32]byte
+ Report []byte
+ Rs [][32]byte
+ Ss [][32]byte
+ RawVs [32]byte
+ }{
+ ReportContext: rawReportCtx,
+ Report: report,
+ Rs: rs,
+ Ss: ss,
+ RawVs: vs,
+ }
+}
+
+func ToExecCalldata(rawReportCtx [3][32]byte, report []byte, _, _ [][32]byte, _ [32]byte) any {
+ // Note that the name of the struct field is very important, since the encoder used
+ // by the chainwriter uses mapstructure, which will use the struct field name to map
+ // to the argument name in the function call.
+ // If, for whatever reason, we want to change the field name, make sure to add a `mapstructure:""` tag
+ // for that field.
+ return struct {
+ ReportContext [3][32]byte
+ Report []byte
+ }{
+ ReportContext: rawReportCtx,
+ Report: report,
+ }
+}
+
+var _ ocr3types.ContractTransmitter[[]byte] = &commitTransmitter[[]byte]{}
+
+type commitTransmitter[RI any] struct {
+ cw commontypes.ChainWriter
+ fromAccount ocrtypes.Account
+ contractName string
+ method string
+ offrampAddress string
+ toCalldataFn ToCalldataFunc
+}
+
+func XXXNewContractTransmitterTestsOnly[RI any](
+ cw commontypes.ChainWriter,
+ fromAccount ocrtypes.Account,
+ contractName string,
+ method string,
+ offrampAddress string,
+ toCalldataFn ToCalldataFunc,
+) ocr3types.ContractTransmitter[RI] {
+ return &commitTransmitter[RI]{
+ cw: cw,
+ fromAccount: fromAccount,
+ contractName: contractName,
+ method: method,
+ offrampAddress: offrampAddress,
+ toCalldataFn: toCalldataFn,
+ }
+}
+
+func NewCommitContractTransmitter[RI any](
+ cw commontypes.ChainWriter,
+ fromAccount ocrtypes.Account,
+ offrampAddress string,
+) ocr3types.ContractTransmitter[RI] {
+ return &commitTransmitter[RI]{
+ cw: cw,
+ fromAccount: fromAccount,
+ contractName: consts.ContractNameOffRamp,
+ method: consts.MethodCommit,
+ offrampAddress: offrampAddress,
+ toCalldataFn: ToCommitCalldata,
+ }
+}
+
+func NewExecContractTransmitter[RI any](
+ cw commontypes.ChainWriter,
+ fromAccount ocrtypes.Account,
+ offrampAddress string,
+) ocr3types.ContractTransmitter[RI] {
+ return &commitTransmitter[RI]{
+ cw: cw,
+ fromAccount: fromAccount,
+ contractName: consts.ContractNameOffRamp,
+ method: consts.MethodExecute,
+ offrampAddress: offrampAddress,
+ toCalldataFn: ToExecCalldata,
+ }
+}
+
+// FromAccount implements ocr3types.ContractTransmitter.
+func (c *commitTransmitter[RI]) FromAccount() (ocrtypes.Account, error) {
+ return c.fromAccount, nil
+}
+
+// Transmit implements ocr3types.ContractTransmitter.
+func (c *commitTransmitter[RI]) Transmit(
+ ctx context.Context,
+ configDigest ocrtypes.ConfigDigest,
+ seqNr uint64,
+ reportWithInfo ocr3types.ReportWithInfo[RI],
+ sigs []ocrtypes.AttributedOnchainSignature,
+) error {
+ var rs [][32]byte
+ var ss [][32]byte
+ var vs [32]byte
+ if len(sigs) > 32 {
+ return errors.New("too many signatures, maximum is 32")
+ }
+ for i, as := range sigs {
+ r, s, v, err := evmutil.SplitSignature(as.Signature)
+ if err != nil {
+ return fmt.Errorf("failed to split signature: %w", err)
+ }
+ rs = append(rs, r)
+ ss = append(ss, s)
+ vs[i] = v
+ }
+
+ // report ctx for OCR3 consists of the following
+ // reportContext[0]: ConfigDigest
+ // reportContext[1]: 24 byte padding, 8 byte sequence number
+ // reportContext[2]: unused
+ // convert seqNum, which is a uint64, into a uint32 epoch and uint8 round
+ // while this does truncate the sequence number, it is not a problem because
+ // it still gives us 2^40 - 1 possible sequence numbers.
+ // assuming a sequence number is generated every second, this gives us
+ // 1099511627775 seconds, or approximately 34,865 years, before we run out
+ // of sequence numbers.
+ epoch, round := uint64ToUint32AndUint8(seqNr)
+ rawReportCtx := evmutil.RawReportContext(ocrtypes.ReportContext{
+ ReportTimestamp: ocrtypes.ReportTimestamp{
+ ConfigDigest: configDigest,
+ Epoch: epoch,
+ Round: round,
+ },
+ // ExtraData not used in OCR3
+ })
+
+ if c.toCalldataFn == nil {
+ return errors.New("toCalldataFn is nil")
+ }
+
+ // chain writer takes in the raw calldata and packs it on its own.
+ args := c.toCalldataFn(rawReportCtx, reportWithInfo.Report, rs, ss, vs)
+
+ // TODO: no meta fields yet, what should we add?
+ // probably whats in the info part of the report?
+ meta := commontypes.TxMeta{}
+ txID, err := uuid.NewRandom() // NOTE: CW expects us to generate an ID, rather than return one
+ if err != nil {
+ return fmt.Errorf("failed to generate UUID: %w", err)
+ }
+ zero := big.NewInt(0)
+ if err := c.cw.SubmitTransaction(ctx, c.contractName, c.method, args, fmt.Sprintf("%s-%s-%s", c.contractName, c.offrampAddress, txID.String()), c.offrampAddress, &meta, zero); err != nil {
+ return fmt.Errorf("failed to submit transaction thru chainwriter: %w", err)
+ }
+
+ return nil
+}
+
+func uint64ToUint32AndUint8(x uint64) (uint32, uint8) {
+ return uint32(x >> 32), uint8(x)
+}
diff --git a/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go b/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go
new file mode 100644
index 00000000000..0c1fa0d3845
--- /dev/null
+++ b/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go
@@ -0,0 +1,692 @@
+package ocrimpls_test
+
+import (
+ "crypto/rand"
+ "math/big"
+ "net/url"
+ "testing"
+ "time"
+
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ocrimpls"
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/jmoiron/sqlx"
+ "github.com/onsi/gomega"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/libocr/commontypes"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
+ txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/keystore"
+ "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"
+ "github.com/smartcontractkit/chainlink/v2/core/config"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/multi_ocr3_helper"
+ "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"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ kschaintype "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+ evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
+)
+
+func Test_ContractTransmitter_TransmitWithoutSignatures(t *testing.T) {
+ type testCase struct {
+ name string
+ pluginType uint8
+ withSigs bool
+ expectedSigsEnabled bool
+ report []byte
+ }
+
+ testCases := []testCase{
+ {
+ "empty report with sigs",
+ uint8(cctypes.PluginTypeCCIPCommit),
+ true,
+ true,
+ []byte{},
+ },
+ {
+ "empty report without sigs",
+ uint8(cctypes.PluginTypeCCIPExec),
+ false,
+ false,
+ []byte{},
+ },
+ {
+ "report with data with sigs",
+ uint8(cctypes.PluginTypeCCIPCommit),
+ true,
+ true,
+ randomReport(t, 96),
+ },
+ {
+ "report with data without sigs",
+ uint8(cctypes.PluginTypeCCIPExec),
+ false,
+ false,
+ randomReport(t, 96),
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ tc := tc
+ t.Parallel()
+ testTransmitter(t, tc.pluginType, tc.withSigs, tc.expectedSigsEnabled, tc.report)
+ })
+ }
+}
+
+func testTransmitter(
+ t *testing.T,
+ pluginType uint8,
+ withSigs bool,
+ expectedSigsEnabled bool,
+ report []byte,
+) {
+ uni := newTestUniverse[[]byte](t, nil)
+
+ c, err := uni.wrapper.LatestConfigDetails(nil, pluginType)
+ require.NoError(t, err, "failed to get latest config details")
+ configDigest := c.ConfigInfo.ConfigDigest
+ require.Equal(t, expectedSigsEnabled, c.ConfigInfo.IsSignatureVerificationEnabled, "signature verification enabled setting not correct")
+
+ // set the plugin type on the helper so it fetches the right config info.
+ // the important aspect is whether signatures should be enabled or not.
+ _, err = uni.wrapper.SetTransmitOcrPluginType(uni.deployer, pluginType)
+ require.NoError(t, err, "failed to set plugin type")
+ uni.backend.Commit()
+
+ // create attributed sigs
+ // only need f+1 which is 2 in this case
+ rwi := ocr3types.ReportWithInfo[[]byte]{
+ Report: report,
+ Info: []byte{},
+ }
+ seqNr := uint64(1)
+ attributedSigs := uni.SignReport(t, configDigest, rwi, seqNr)
+
+ account, err := uni.transmitterWithSigs.FromAccount()
+ require.NoError(t, err, "failed to get from account")
+ require.Equal(t, ocrtypes.Account(uni.transmitters[0].Hex()), account, "from account mismatch")
+ if withSigs {
+ err = uni.transmitterWithSigs.Transmit(testutils.Context(t), configDigest, seqNr, rwi, attributedSigs)
+ } else {
+ err = uni.transmitterWithoutSigs.Transmit(testutils.Context(t), configDigest, seqNr, rwi, attributedSigs)
+ }
+ require.NoError(t, err, "failed to transmit")
+ uni.backend.Commit()
+
+ var txStatus uint64
+ gomega.NewWithT(t).Eventually(func() bool {
+ uni.backend.Commit()
+ rows, err := uni.db.QueryContext(testutils.Context(t), `SELECT hash FROM evm.tx_attempts LIMIT 1`)
+ require.NoError(t, err, "failed to query txes")
+ defer rows.Close()
+ var txHash []byte
+ for rows.Next() {
+ require.NoError(t, rows.Scan(&txHash), "failed to scan")
+ }
+ t.Log("txHash:", txHash)
+ receipt, err := uni.simClient.TransactionReceipt(testutils.Context(t), common.BytesToHash(txHash))
+ if err != nil {
+ t.Log("tx not found yet:", hexutil.Encode(txHash))
+ return false
+ }
+ t.Log("tx found:", hexutil.Encode(txHash), "status:", receipt.Status)
+ txStatus = receipt.Status
+ return true
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue())
+
+ // wait for receipt to be written to the db
+ gomega.NewWithT(t).Eventually(func() bool {
+ rows, err := uni.db.QueryContext(testutils.Context(t), `SELECT count(*) as cnt FROM evm.receipts LIMIT 1`)
+ require.NoError(t, err, "failed to query receipts")
+ defer rows.Close()
+ var count int
+ for rows.Next() {
+ require.NoError(t, rows.Scan(&count), "failed to scan")
+ }
+ return count == 1
+ }, testutils.WaitTimeout(t), 2*time.Second).Should(gomega.BeTrue())
+
+ require.Equal(t, uint64(1), txStatus, "tx status should be success")
+
+ // check that the event was emitted
+ events := uni.TransmittedEvents(t)
+ require.Len(t, events, 1, "expected 1 event")
+ require.Equal(t, configDigest, events[0].ConfigDigest, "config digest mismatch")
+ require.Equal(t, seqNr, events[0].SequenceNumber, "seq num mismatch")
+}
+
+type testUniverse[RI any] struct {
+ simClient *client.SimulatedBackendClient
+ backend *backends.SimulatedBackend
+ deployer *bind.TransactOpts
+ transmitters []common.Address
+ signers []common.Address
+ wrapper *multi_ocr3_helper.MultiOCR3Helper
+ transmitterWithSigs ocr3types.ContractTransmitter[RI]
+ transmitterWithoutSigs ocr3types.ContractTransmitter[RI]
+ keyrings []ocr3types.OnchainKeyring[RI]
+ f uint8
+ db *sqlx.DB
+ txm txmgr.TxManager
+ gasEstimator gas.EvmFeeEstimator
+}
+
+type keyringsAndSigners[RI any] struct {
+ keyrings []ocr3types.OnchainKeyring[RI]
+ signers []common.Address
+}
+
+func newTestUniverse[RI any](t *testing.T, ks *keyringsAndSigners[RI]) *testUniverse[RI] {
+ t.Helper()
+
+ db := pgtest.NewSqlxDB(t)
+ owner := testutils.MustNewSimTransactor(t)
+
+ // create many transmitters but only need to fund one, rest are to get
+ // setOCR3Config to pass.
+ keyStore := cltest.NewKeyStore(t, db)
+ var transmitters []common.Address
+ for i := 0; i < 4; i++ {
+ key, err := keyStore.Eth().Create(testutils.Context(t), big.NewInt(1337))
+ require.NoError(t, err, "failed to create key")
+ transmitters = append(transmitters, key.Address)
+ }
+
+ backend := backends.NewSimulatedBackend(core.GenesisAlloc{
+ owner.From: core.GenesisAccount{
+ Balance: assets.Ether(1000).ToInt(),
+ },
+ transmitters[0]: core.GenesisAccount{
+ Balance: assets.Ether(1000).ToInt(),
+ },
+ }, 30e6)
+
+ ocr3HelperAddr, _, _, err := multi_ocr3_helper.DeployMultiOCR3Helper(owner, backend)
+ require.NoError(t, err)
+ backend.Commit()
+ wrapper, err := multi_ocr3_helper.NewMultiOCR3Helper(ocr3HelperAddr, backend)
+ require.NoError(t, err)
+
+ // create the oracle identities for setConfig
+ // need to create at least 4 identities otherwise setConfig will fail
+ var (
+ keyrings []ocr3types.OnchainKeyring[RI]
+ signers []common.Address
+ )
+ if ks != nil {
+ keyrings = ks.keyrings
+ signers = ks.signers
+ } else {
+ for i := 0; i < 4; i++ {
+ kb, err2 := ocr2key.New(kschaintype.EVM)
+ require.NoError(t, err2, "failed to create key")
+ kr := ocrimpls.NewOnchainKeyring[RI](kb, logger.TestLogger(t))
+ signers = append(signers, common.BytesToAddress(kr.PublicKey()))
+ keyrings = append(keyrings, kr)
+ }
+ }
+ f := uint8(1)
+ commitConfigDigest := testutils.Random32Byte()
+ execConfigDigest := testutils.Random32Byte()
+ _, err = wrapper.SetOCR3Configs(
+ owner,
+ []multi_ocr3_helper.MultiOCR3BaseOCRConfigArgs{
+ {
+ ConfigDigest: commitConfigDigest,
+ OcrPluginType: uint8(cctypes.PluginTypeCCIPCommit),
+ F: f,
+ IsSignatureVerificationEnabled: true,
+ Signers: signers,
+ Transmitters: []common.Address{
+ transmitters[0],
+ transmitters[1],
+ transmitters[2],
+ transmitters[3],
+ },
+ },
+ {
+ ConfigDigest: execConfigDigest,
+ OcrPluginType: uint8(cctypes.PluginTypeCCIPExec),
+ F: f,
+ IsSignatureVerificationEnabled: false,
+ Signers: signers,
+ Transmitters: []common.Address{
+ transmitters[0],
+ transmitters[1],
+ transmitters[2],
+ transmitters[3],
+ },
+ },
+ },
+ )
+ require.NoError(t, err)
+ backend.Commit()
+
+ commitConfig, err := wrapper.LatestConfigDetails(nil, uint8(cctypes.PluginTypeCCIPCommit))
+ require.NoError(t, err, "failed to get latest commit config")
+ require.Equal(t, commitConfigDigest, commitConfig.ConfigInfo.ConfigDigest, "commit config digest mismatch")
+ execConfig, err := wrapper.LatestConfigDetails(nil, uint8(cctypes.PluginTypeCCIPExec))
+ require.NoError(t, err, "failed to get latest exec config")
+ require.Equal(t, execConfigDigest, execConfig.ConfigInfo.ConfigDigest, "exec config digest mismatch")
+
+ simClient := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID)
+
+ // create the chain writer service
+ txm, gasEstimator := makeTestEvmTxm(t, db, simClient, keyStore.Eth())
+ require.NoError(t, txm.Start(testutils.Context(t)), "failed to start tx manager")
+ t.Cleanup(func() { require.NoError(t, txm.Close()) })
+
+ chainWriter, err := evm.NewChainWriterService(
+ logger.TestLogger(t),
+ simClient,
+ txm,
+ gasEstimator,
+ chainWriterConfigRaw(transmitters[0], assets.GWei(1)))
+ require.NoError(t, err, "failed to create chain writer")
+ require.NoError(t, chainWriter.Start(testutils.Context(t)), "failed to start chain writer")
+ t.Cleanup(func() { require.NoError(t, chainWriter.Close()) })
+
+ transmitterWithSigs := ocrimpls.XXXNewContractTransmitterTestsOnly[RI](
+ chainWriter,
+ ocrtypes.Account(transmitters[0].Hex()),
+ contractName,
+ methodTransmitWithSignatures,
+ ocr3HelperAddr.Hex(),
+ ocrimpls.ToCommitCalldata,
+ )
+ transmitterWithoutSigs := ocrimpls.XXXNewContractTransmitterTestsOnly[RI](
+ chainWriter,
+ ocrtypes.Account(transmitters[0].Hex()),
+ contractName,
+ methodTransmitWithoutSignatures,
+ ocr3HelperAddr.Hex(),
+ ocrimpls.ToExecCalldata,
+ )
+
+ return &testUniverse[RI]{
+ simClient: simClient,
+ backend: backend,
+ deployer: owner,
+ transmitters: transmitters,
+ signers: signers,
+ wrapper: wrapper,
+ transmitterWithSigs: transmitterWithSigs,
+ transmitterWithoutSigs: transmitterWithoutSigs,
+ keyrings: keyrings,
+ f: f,
+ db: db,
+ txm: txm,
+ gasEstimator: gasEstimator,
+ }
+}
+
+func (uni testUniverse[RI]) SignReport(t *testing.T, configDigest ocrtypes.ConfigDigest, rwi ocr3types.ReportWithInfo[RI], seqNum uint64) []ocrtypes.AttributedOnchainSignature {
+ var attributedSigs []ocrtypes.AttributedOnchainSignature
+ for i := uint8(0); i < uni.f+1; i++ {
+ t.Log("signing report with", hexutil.Encode(uni.keyrings[i].PublicKey()))
+ sig, err := uni.keyrings[i].Sign(configDigest, seqNum, rwi)
+ require.NoError(t, err, "failed to sign report")
+ attributedSigs = append(attributedSigs, ocrtypes.AttributedOnchainSignature{
+ Signature: sig,
+ Signer: commontypes.OracleID(i),
+ })
+ }
+ return attributedSigs
+}
+
+func (uni testUniverse[RI]) TransmittedEvents(t *testing.T) []*multi_ocr3_helper.MultiOCR3HelperTransmitted {
+ iter, err := uni.wrapper.FilterTransmitted(&bind.FilterOpts{
+ Start: 0,
+ }, nil)
+ require.NoError(t, err, "failed to create filter iterator")
+ var events []*multi_ocr3_helper.MultiOCR3HelperTransmitted
+ for iter.Next() {
+ event := iter.Event
+ events = append(events, event)
+ }
+ return events
+}
+
+func randomReport(t *testing.T, len int) []byte {
+ report := make([]byte, len)
+ _, err := rand.Reader.Read(report)
+ require.NoError(t, err, "failed to read random bytes")
+ return report
+}
+
+const (
+ contractName = "MultiOCR3Helper"
+ methodTransmitWithSignatures = "TransmitWithSignatures"
+ methodTransmitWithoutSignatures = "TransmitWithoutSignatures"
+)
+
+func chainWriterConfigRaw(fromAddress common.Address, maxGasPrice *assets.Wei) evmrelaytypes.ChainWriterConfig {
+ return evmrelaytypes.ChainWriterConfig{
+ Contracts: map[string]*evmrelaytypes.ContractConfig{
+ contractName: {
+ ContractABI: multi_ocr3_helper.MultiOCR3HelperABI,
+ Configs: map[string]*evmrelaytypes.ChainWriterDefinition{
+ methodTransmitWithSignatures: {
+ ChainSpecificName: "transmitWithSignatures",
+ GasLimit: 1e6,
+ FromAddress: fromAddress,
+ },
+ methodTransmitWithoutSignatures: {
+ ChainSpecificName: "transmitWithoutSignatures",
+ GasLimit: 1e6,
+ FromAddress: fromAddress,
+ },
+ },
+ },
+ },
+ SendStrategy: txmgrcommon.NewSendEveryStrategy(),
+ MaxGasPrice: maxGasPrice,
+ }
+}
+
+func makeTestEvmTxm(
+ t *testing.T,
+ db *sqlx.DB,
+ ethClient client.Client,
+ keyStore keystore.Eth) (txmgr.TxManager, gas.EvmFeeEstimator) {
+ config, dbConfig, evmConfig := MakeTestConfigs(t)
+
+ estimator, err := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator())
+ require.NoError(t, err, "failed to create gas estimator")
+
+ lggr := logger.TestLogger(t)
+ lpOpts := logpoller.Opts{
+ PollPeriod: 100 * time.Millisecond,
+ FinalityDepth: 2,
+ BackfillBatchSize: 3,
+ RpcBatchSize: 2,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+
+ chainID := big.NewInt(1337)
+ headSaver := headtracker.NewHeadSaver(
+ logger.NullLogger,
+ headtracker.NewORM(*chainID, db),
+ evmConfig,
+ evmConfig.HeadTrackerConfig,
+ )
+
+ broadcaster := headtracker.NewHeadBroadcaster(logger.NullLogger)
+ require.NoError(t, broadcaster.Start(testutils.Context(t)), "failed to start head broadcaster")
+ t.Cleanup(func() { require.NoError(t, broadcaster.Close()) })
+
+ ht := headtracker.NewHeadTracker(
+ logger.NullLogger,
+ ethClient,
+ evmConfig,
+ evmConfig.HeadTrackerConfig,
+ broadcaster,
+ headSaver,
+ mailbox.NewMonitor("contract_transmitter_test", logger.NullLogger),
+ )
+ require.NoError(t, ht.Start(testutils.Context(t)), "failed to start head tracker")
+ t.Cleanup(func() { require.NoError(t, ht.Close()) })
+
+ lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, logger.NullLogger),
+ ethClient, logger.NullLogger, ht, lpOpts)
+ require.NoError(t, lp.Start(testutils.Context(t)), "failed to start log poller")
+ t.Cleanup(func() { require.NoError(t, lp.Close()) })
+
+ // logic for building components (from evm/evm_txm.go) -------
+ lggr.Infow("Initializing EVM transaction manager",
+ "bumpTxDepth", evmConfig.GasEstimator().BumpTxDepth(),
+ "maxInFlightTransactions", config.EvmConfig.Transactions().MaxInFlight(),
+ "maxQueuedTransactions", config.EvmConfig.Transactions().MaxQueued(),
+ "nonceAutoSync", evmConfig.NonceAutoSync(),
+ "limitDefault", evmConfig.GasEstimator().LimitDefault(),
+ )
+
+ txm, err := txmgr.NewTxm(
+ db,
+ config,
+ config.EvmConfig.GasEstimator(),
+ config.EvmConfig.Transactions(),
+ nil,
+ dbConfig,
+ dbConfig.Listener(),
+ ethClient,
+ lggr,
+ lp,
+ keyStore,
+ estimator,
+ ht)
+ require.NoError(t, err, "can't create tx manager")
+
+ _, unsub := broadcaster.Subscribe(txm)
+ t.Cleanup(unsub)
+
+ return txm, estimator
+}
+
+// Code below copied/pasted and slightly modified in order to work from core/chains/evm/txmgr/test_helpers.go.
+
+func ptr[T any](t T) *T { return &t }
+
+type TestDatabaseConfig struct {
+ config.Database
+ defaultQueryTimeout time.Duration
+}
+
+func (d *TestDatabaseConfig) DefaultQueryTimeout() time.Duration {
+ return d.defaultQueryTimeout
+}
+
+func (d *TestDatabaseConfig) LogSQL() bool {
+ return false
+}
+
+type TestListenerConfig struct {
+ config.Listener
+}
+
+func (l *TestListenerConfig) FallbackPollInterval() time.Duration {
+ return 1 * time.Minute
+}
+
+func (d *TestDatabaseConfig) Listener() config.Listener {
+ return &TestListenerConfig{}
+}
+
+type TestHeadTrackerConfig struct{}
+
+// FinalityTagBypass implements config.HeadTracker.
+func (t *TestHeadTrackerConfig) FinalityTagBypass() bool {
+ return false
+}
+
+// HistoryDepth implements config.HeadTracker.
+func (t *TestHeadTrackerConfig) HistoryDepth() uint32 {
+ return 50
+}
+
+// MaxAllowedFinalityDepth implements config.HeadTracker.
+func (t *TestHeadTrackerConfig) MaxAllowedFinalityDepth() uint32 {
+ return 100
+}
+
+// MaxBufferSize implements config.HeadTracker.
+func (t *TestHeadTrackerConfig) MaxBufferSize() uint32 {
+ return 100
+}
+
+// SamplingInterval implements config.HeadTracker.
+func (t *TestHeadTrackerConfig) SamplingInterval() time.Duration {
+ return 1 * time.Second
+}
+
+var _ evmconfig.HeadTracker = (*TestHeadTrackerConfig)(nil)
+
+type TestEvmConfig struct {
+ evmconfig.EVM
+ HeadTrackerConfig evmconfig.HeadTracker
+ MaxInFlight uint32
+ ReaperInterval time.Duration
+ ReaperThreshold time.Duration
+ ResendAfterThreshold time.Duration
+ BumpThreshold uint64
+ MaxQueued uint64
+ Enabled bool
+ Threshold uint32
+ MinAttempts uint32
+ DetectionApiUrl *url.URL
+}
+
+func (e *TestEvmConfig) FinalityTagEnabled() bool {
+ return false
+}
+
+func (e *TestEvmConfig) FinalityDepth() uint32 {
+ return 42
+}
+
+func (e *TestEvmConfig) FinalizedBlockOffset() uint32 {
+ return 42
+}
+
+func (e *TestEvmConfig) BlockEmissionIdleWarningThreshold() time.Duration {
+ return 10 * time.Second
+}
+
+func (e *TestEvmConfig) Transactions() evmconfig.Transactions {
+ return &transactionsConfig{e: e, autoPurge: &autoPurgeConfig{}}
+}
+
+func (e *TestEvmConfig) NonceAutoSync() bool { return true }
+
+func (e *TestEvmConfig) ChainType() chaintype.ChainType { return "" }
+
+type TestGasEstimatorConfig struct {
+ bumpThreshold uint64
+}
+
+func (g *TestGasEstimatorConfig) BlockHistory() evmconfig.BlockHistory {
+ return &TestBlockHistoryConfig{}
+}
+
+func (g *TestGasEstimatorConfig) EIP1559DynamicFees() bool { return false }
+func (g *TestGasEstimatorConfig) LimitDefault() uint64 { return 1e6 }
+func (g *TestGasEstimatorConfig) BumpPercent() uint16 { return 2 }
+func (g *TestGasEstimatorConfig) BumpThreshold() uint64 { return g.bumpThreshold }
+func (g *TestGasEstimatorConfig) BumpMin() *assets.Wei { return assets.GWei(1) }
+func (g *TestGasEstimatorConfig) FeeCapDefault() *assets.Wei { return assets.GWei(1) }
+func (g *TestGasEstimatorConfig) PriceDefault() *assets.Wei { return assets.GWei(1) }
+func (g *TestGasEstimatorConfig) TipCapDefault() *assets.Wei { return assets.GWei(1) }
+func (g *TestGasEstimatorConfig) TipCapMin() *assets.Wei { return assets.GWei(1) }
+func (g *TestGasEstimatorConfig) LimitMax() uint64 { return 0 }
+func (g *TestGasEstimatorConfig) LimitMultiplier() float32 { return 1 }
+func (g *TestGasEstimatorConfig) BumpTxDepth() uint32 { return 42 }
+func (g *TestGasEstimatorConfig) LimitTransfer() uint64 { return 42 }
+func (g *TestGasEstimatorConfig) PriceMax() *assets.Wei { return assets.GWei(1) }
+func (g *TestGasEstimatorConfig) PriceMin() *assets.Wei { return assets.GWei(1) }
+func (g *TestGasEstimatorConfig) Mode() string { return "FixedPrice" }
+func (g *TestGasEstimatorConfig) LimitJobType() evmconfig.LimitJobType {
+ return &TestLimitJobTypeConfig{}
+}
+func (g *TestGasEstimatorConfig) PriceMaxKey(addr common.Address) *assets.Wei {
+ return assets.GWei(1)
+}
+func (g *TestGasEstimatorConfig) EstimateGasLimit() bool { return false }
+
+func (e *TestEvmConfig) GasEstimator() evmconfig.GasEstimator {
+ return &TestGasEstimatorConfig{bumpThreshold: e.BumpThreshold}
+}
+
+type TestLimitJobTypeConfig struct {
+}
+
+func (l *TestLimitJobTypeConfig) OCR() *uint32 { return ptr(uint32(0)) }
+func (l *TestLimitJobTypeConfig) OCR2() *uint32 { return ptr(uint32(0)) }
+func (l *TestLimitJobTypeConfig) DR() *uint32 { return ptr(uint32(0)) }
+func (l *TestLimitJobTypeConfig) FM() *uint32 { return ptr(uint32(0)) }
+func (l *TestLimitJobTypeConfig) Keeper() *uint32 { return ptr(uint32(0)) }
+func (l *TestLimitJobTypeConfig) VRF() *uint32 { return ptr(uint32(0)) }
+
+type TestBlockHistoryConfig struct {
+ evmconfig.BlockHistory
+}
+
+func (b *TestBlockHistoryConfig) BatchSize() uint32 { return 42 }
+func (b *TestBlockHistoryConfig) BlockDelay() uint16 { return 42 }
+func (b *TestBlockHistoryConfig) BlockHistorySize() uint16 { return 42 }
+func (b *TestBlockHistoryConfig) EIP1559FeeCapBufferBlocks() uint16 { return 42 }
+func (b *TestBlockHistoryConfig) TransactionPercentile() uint16 { return 42 }
+
+type transactionsConfig struct {
+ evmconfig.Transactions
+ e *TestEvmConfig
+ autoPurge evmconfig.AutoPurgeConfig
+}
+
+func (*transactionsConfig) ForwardersEnabled() bool { return false }
+func (t *transactionsConfig) MaxInFlight() uint32 { return t.e.MaxInFlight }
+func (t *transactionsConfig) MaxQueued() uint64 { return t.e.MaxQueued }
+func (t *transactionsConfig) ReaperInterval() time.Duration { return t.e.ReaperInterval }
+func (t *transactionsConfig) ReaperThreshold() time.Duration { return t.e.ReaperThreshold }
+func (t *transactionsConfig) ResendAfterThreshold() time.Duration { return t.e.ResendAfterThreshold }
+func (t *transactionsConfig) AutoPurge() evmconfig.AutoPurgeConfig { return t.autoPurge }
+
+type autoPurgeConfig struct {
+ evmconfig.AutoPurgeConfig
+}
+
+func (a *autoPurgeConfig) Enabled() bool { return false }
+
+type MockConfig struct {
+ EvmConfig *TestEvmConfig
+ RpcDefaultBatchSize uint32
+ finalityDepth uint32
+ finalityTagEnabled bool
+}
+
+func (c *MockConfig) EVM() evmconfig.EVM {
+ return c.EvmConfig
+}
+
+func (c *MockConfig) NonceAutoSync() bool { return true }
+func (c *MockConfig) ChainType() chaintype.ChainType { return "" }
+func (c *MockConfig) FinalityDepth() uint32 { return c.finalityDepth }
+func (c *MockConfig) SetFinalityDepth(fd uint32) { c.finalityDepth = fd }
+func (c *MockConfig) FinalityTagEnabled() bool { return c.finalityTagEnabled }
+func (c *MockConfig) RPCDefaultBatchSize() uint32 { return c.RpcDefaultBatchSize }
+
+func MakeTestConfigs(t *testing.T) (*MockConfig, *TestDatabaseConfig, *TestEvmConfig) {
+ db := &TestDatabaseConfig{defaultQueryTimeout: utils.DefaultQueryTimeout}
+ ec := &TestEvmConfig{
+ HeadTrackerConfig: &TestHeadTrackerConfig{},
+ 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/capabilities/ccip/ocrimpls/keyring.go b/core/capabilities/ccip/ocrimpls/keyring.go
new file mode 100644
index 00000000000..4b15c75b09a
--- /dev/null
+++ b/core/capabilities/ccip/ocrimpls/keyring.go
@@ -0,0 +1,61 @@
+package ocrimpls
+
+import (
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+var _ ocr3types.OnchainKeyring[[]byte] = &ocr3Keyring[[]byte]{}
+
+type ocr3Keyring[RI any] struct {
+ core types.OnchainKeyring
+ lggr logger.Logger
+}
+
+func NewOnchainKeyring[RI any](keyring types.OnchainKeyring, lggr logger.Logger) *ocr3Keyring[RI] {
+ return &ocr3Keyring[RI]{
+ core: keyring,
+ lggr: lggr.Named("OCR3Keyring"),
+ }
+}
+
+func (w *ocr3Keyring[RI]) PublicKey() types.OnchainPublicKey {
+ return w.core.PublicKey()
+}
+
+func (w *ocr3Keyring[RI]) MaxSignatureLength() int {
+ return w.core.MaxSignatureLength()
+}
+
+func (w *ocr3Keyring[RI]) Sign(configDigest types.ConfigDigest, seqNr uint64, r ocr3types.ReportWithInfo[RI]) (signature []byte, err error) {
+ epoch, round := uint64ToUint32AndUint8(seqNr)
+ rCtx := types.ReportContext{
+ ReportTimestamp: types.ReportTimestamp{
+ ConfigDigest: configDigest,
+ Epoch: epoch,
+ Round: round,
+ },
+ }
+
+ w.lggr.Debugw("signing report", "configDigest", configDigest.Hex(), "seqNr", seqNr, "report", hexutil.Encode(r.Report))
+
+ return w.core.Sign(rCtx, r.Report)
+}
+
+func (w *ocr3Keyring[RI]) Verify(key types.OnchainPublicKey, configDigest types.ConfigDigest, seqNr uint64, r ocr3types.ReportWithInfo[RI], signature []byte) bool {
+ epoch, round := uint64ToUint32AndUint8(seqNr)
+ rCtx := types.ReportContext{
+ ReportTimestamp: types.ReportTimestamp{
+ ConfigDigest: configDigest,
+ Epoch: epoch,
+ Round: round,
+ },
+ }
+
+ w.lggr.Debugw("verifying report", "configDigest", configDigest.Hex(), "seqNr", seqNr, "report", hexutil.Encode(r.Report))
+
+ return w.core.Verify(key, rCtx, r.Report, signature)
+}
diff --git a/core/capabilities/ccip/oraclecreator/inprocess.go b/core/capabilities/ccip/oraclecreator/inprocess.go
new file mode 100644
index 00000000000..6616d356756
--- /dev/null
+++ b/core/capabilities/ccip/oraclecreator/inprocess.go
@@ -0,0 +1,371 @@
+package oraclecreator
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccipevm"
+ evmconfig "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/configs/evm"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ocrimpls"
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/google/uuid"
+ "github.com/prometheus/client_golang/prometheus"
+
+ chainsel "github.com/smartcontractkit/chain-selectors"
+
+ "github.com/smartcontractkit/chainlink-ccip/pkg/consts"
+ "github.com/smartcontractkit/chainlink-ccip/pluginconfig"
+
+ "github.com/smartcontractkit/libocr/commontypes"
+ libocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+
+ commitocr3 "github.com/smartcontractkit/chainlink-ccip/commit"
+ execocr3 "github.com/smartcontractkit/chainlink-ccip/execute"
+ ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/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/chaintype"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+ evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
+ "github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
+ "github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
+)
+
+var _ cctypes.OracleCreator = &inprocessOracleCreator{}
+
+const (
+ defaultCommitGasLimit = 500_000
+)
+
+// inprocessOracleCreator creates oracles that reference plugins running
+// in the same process as the chainlink node, i.e not LOOPPs.
+type inprocessOracleCreator struct {
+ ocrKeyBundles map[string]ocr2key.KeyBundle
+ transmitters map[types.RelayID][]string
+ chains legacyevm.LegacyChainContainer
+ peerWrapper *ocrcommon.SingletonPeerWrapper
+ externalJobID uuid.UUID
+ jobID int32
+ isNewlyCreatedJob bool
+ pluginConfig job.JSONConfig
+ db ocr3types.Database
+ lggr logger.Logger
+ monitoringEndpointGen telemetry.MonitoringEndpointGenerator
+ bootstrapperLocators []commontypes.BootstrapperLocator
+ homeChainReader ccipreaderpkg.HomeChain
+}
+
+func New(
+ ocrKeyBundles map[string]ocr2key.KeyBundle,
+ transmitters map[types.RelayID][]string,
+ chains legacyevm.LegacyChainContainer,
+ peerWrapper *ocrcommon.SingletonPeerWrapper,
+ externalJobID uuid.UUID,
+ jobID int32,
+ isNewlyCreatedJob bool,
+ pluginConfig job.JSONConfig,
+ db ocr3types.Database,
+ lggr logger.Logger,
+ monitoringEndpointGen telemetry.MonitoringEndpointGenerator,
+ bootstrapperLocators []commontypes.BootstrapperLocator,
+ homeChainReader ccipreaderpkg.HomeChain,
+) cctypes.OracleCreator {
+ return &inprocessOracleCreator{
+ ocrKeyBundles: ocrKeyBundles,
+ transmitters: transmitters,
+ chains: chains,
+ peerWrapper: peerWrapper,
+ externalJobID: externalJobID,
+ jobID: jobID,
+ isNewlyCreatedJob: isNewlyCreatedJob,
+ pluginConfig: pluginConfig,
+ db: db,
+ lggr: lggr,
+ monitoringEndpointGen: monitoringEndpointGen,
+ bootstrapperLocators: bootstrapperLocators,
+ homeChainReader: homeChainReader,
+ }
+}
+
+// CreateBootstrapOracle implements types.OracleCreator.
+func (i *inprocessOracleCreator) CreateBootstrapOracle(config cctypes.OCR3ConfigWithMeta) (cctypes.CCIPOracle, error) {
+ // Assuming that the chain selector is referring to an evm chain for now.
+ // TODO: add an api that returns chain family.
+ chainID, err := chainsel.ChainIdFromSelector(uint64(config.Config.ChainSelector))
+ if err != nil {
+ return nil, fmt.Errorf("failed to get chain ID from selector: %w", err)
+ }
+
+ destChainFamily := chaintype.EVM
+ destRelayID := types.NewRelayID(string(destChainFamily), fmt.Sprintf("%d", chainID))
+
+ bootstrapperArgs := libocr3.BootstrapperArgs{
+ BootstrapperFactory: i.peerWrapper.Peer2,
+ V2Bootstrappers: i.bootstrapperLocators,
+ ContractConfigTracker: ocrimpls.NewConfigTracker(config),
+ Database: i.db,
+ LocalConfig: defaultLocalConfig(),
+ Logger: ocrcommon.NewOCRWrapper(
+ i.lggr.
+ Named("CCIPBootstrap").
+ Named(destRelayID.String()).
+ Named(config.Config.ChainSelector.String()).
+ Named(hexutil.Encode(config.Config.OfframpAddress)),
+ false, /* traceLogging */
+ func(ctx context.Context, msg string) {}),
+ MonitoringEndpoint: i.monitoringEndpointGen.GenMonitoringEndpoint(
+ string(destChainFamily),
+ destRelayID.ChainID,
+ hexutil.Encode(config.Config.OfframpAddress),
+ synchronization.OCR3CCIPBootstrap,
+ ),
+ OffchainConfigDigester: ocrimpls.NewConfigDigester(config.ConfigDigest),
+ }
+ bootstrapper, err := libocr3.NewBootstrapper(bootstrapperArgs)
+ if err != nil {
+ return nil, err
+ }
+ return bootstrapper, nil
+}
+
+// CreatePluginOracle implements types.OracleCreator.
+func (i *inprocessOracleCreator) CreatePluginOracle(pluginType cctypes.PluginType, config cctypes.OCR3ConfigWithMeta) (cctypes.CCIPOracle, error) {
+ // Assuming that the chain selector is referring to an evm chain for now.
+ // TODO: add an api that returns chain family.
+ destChainID, err := chainsel.ChainIdFromSelector(uint64(config.Config.ChainSelector))
+ if err != nil {
+ return nil, fmt.Errorf("failed to get chain ID from selector %d: %w", config.Config.ChainSelector, err)
+ }
+ destChainFamily := relay.NetworkEVM
+ destRelayID := types.NewRelayID(destChainFamily, fmt.Sprintf("%d", destChainID))
+
+ configTracker := ocrimpls.NewConfigTracker(config)
+ publicConfig, err := configTracker.PublicConfig()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get public config from OCR config: %w", err)
+ }
+ var execBatchGasLimit uint64
+ if pluginType == cctypes.PluginTypeCCIPExec {
+ execOffchainConfig, err2 := pluginconfig.DecodeExecuteOffchainConfig(publicConfig.ReportingPluginConfig)
+ if err2 != nil {
+ return nil, fmt.Errorf("failed to decode execute offchain config: %w, raw: %s",
+ err2, string(publicConfig.ReportingPluginConfig))
+ }
+ if execOffchainConfig.BatchGasLimit == 0 && destChainFamily == relay.NetworkEVM {
+ return nil, fmt.Errorf("BatchGasLimit not set in execute offchain config, must be > 0")
+ }
+ execBatchGasLimit = execOffchainConfig.BatchGasLimit
+ }
+
+ // this is so that we can use the msg hasher and report encoder from that dest chain relayer's provider.
+ contractReaders := make(map[cciptypes.ChainSelector]types.ContractReader)
+ chainWriters := make(map[cciptypes.ChainSelector]types.ChainWriter)
+ for _, chain := range i.chains.Slice() {
+ var chainReaderConfig evmrelaytypes.ChainReaderConfig
+ if chain.ID().Uint64() == destChainID {
+ chainReaderConfig = evmconfig.DestReaderConfig()
+ } else {
+ chainReaderConfig = evmconfig.SourceReaderConfig()
+ }
+ cr, err2 := evm.NewChainReaderService(
+ context.Background(),
+ i.lggr.
+ Named("EVMChainReaderService").
+ Named(chain.ID().String()).
+ Named(pluginType.String()),
+ chain.LogPoller(),
+ chain.HeadTracker(),
+ chain.Client(),
+ chainReaderConfig,
+ )
+ if err2 != nil {
+ return nil, fmt.Errorf("failed to create contract reader for chain %s: %w", chain.ID(), err2)
+ }
+
+ if chain.ID().Uint64() == destChainID {
+ // bind the chain reader to the dest chain's offramp.
+ offrampAddressHex := common.BytesToAddress(config.Config.OfframpAddress).Hex()
+ err3 := cr.Bind(context.Background(), []types.BoundContract{
+ {
+ Address: offrampAddressHex,
+ Name: consts.ContractNameOffRamp,
+ },
+ })
+ if err3 != nil {
+ return nil, fmt.Errorf("failed to bind chain reader for dest chain %s's offramp at %s: %w", chain.ID(), offrampAddressHex, err3)
+ }
+ }
+
+ // TODO: figure out shutdown.
+ // maybe from the plugin directly?
+ err2 = cr.Start(context.Background())
+ if err2 != nil {
+ return nil, fmt.Errorf("failed to start contract reader for chain %s: %w", chain.ID(), err2)
+ }
+
+ // Even though we only write to the dest chain, we need to create chain writers for all chains
+ // we know about in order to post gas prices on the dest.
+ var fromAddress common.Address
+ transmitter, ok := i.transmitters[types.NewRelayID(relay.NetworkEVM, chain.ID().String())]
+ if ok {
+ fromAddress = common.HexToAddress(transmitter[0])
+ }
+ cw, err2 := evm.NewChainWriterService(
+ i.lggr.Named("EVMChainWriterService").
+ Named(chain.ID().String()).
+ Named(pluginType.String()),
+ chain.Client(),
+ chain.TxManager(),
+ chain.GasEstimator(),
+ evmconfig.ChainWriterConfigRaw(
+ fromAddress,
+ chain.Config().EVM().GasEstimator().PriceMaxKey(fromAddress),
+ defaultCommitGasLimit,
+ execBatchGasLimit,
+ ),
+ )
+ if err2 != nil {
+ return nil, fmt.Errorf("failed to create chain writer for chain %s: %w", chain.ID(), err2)
+ }
+
+ // TODO: figure out shutdown.
+ // maybe from the plugin directly?
+ err2 = cw.Start(context.Background())
+ if err2 != nil {
+ return nil, fmt.Errorf("failed to start chain writer for chain %s: %w", chain.ID(), err2)
+ }
+
+ chainSelector, ok := chainsel.EvmChainIdToChainSelector()[chain.ID().Uint64()]
+ if !ok {
+ return nil, fmt.Errorf("failed to get chain selector from chain ID %s", chain.ID())
+ }
+
+ contractReaders[cciptypes.ChainSelector(chainSelector)] = cr
+ chainWriters[cciptypes.ChainSelector(chainSelector)] = cw
+ }
+
+ // build the onchain keyring. it will be the signing key for the destination chain family.
+ keybundle, ok := i.ocrKeyBundles[destChainFamily]
+ if !ok {
+ return nil, fmt.Errorf("no OCR key bundle found for chain family %s, forgot to create one?", destChainFamily)
+ }
+ onchainKeyring := ocrimpls.NewOnchainKeyring[[]byte](keybundle, i.lggr)
+
+ // build the contract transmitter
+ // assume that we are using the first account in the keybundle as the from account
+ // and that we are able to transmit to the dest chain.
+ // TODO: revisit this in the future, since not all oracles will be able to transmit to the dest chain.
+ destChainWriter, ok := chainWriters[config.Config.ChainSelector]
+ if !ok {
+ return nil, fmt.Errorf("no chain writer found for dest chain selector %d, can't create contract transmitter",
+ config.Config.ChainSelector)
+ }
+ destFromAccounts, ok := i.transmitters[destRelayID]
+ if !ok {
+ return nil, fmt.Errorf("no transmitter found for dest relay ID %s, can't create contract transmitter", destRelayID)
+ }
+
+ // TODO: Extract the correct transmitter address from the destsFromAccount
+ var factory ocr3types.ReportingPluginFactory[[]byte]
+ var transmitter ocr3types.ContractTransmitter[[]byte]
+ if config.Config.PluginType == uint8(cctypes.PluginTypeCCIPCommit) {
+ factory = commitocr3.NewPluginFactory(
+ i.lggr.
+ Named("CCIPCommitPlugin").
+ Named(destRelayID.String()).
+ Named(fmt.Sprintf("%d", config.Config.ChainSelector)).
+ Named(hexutil.Encode(config.Config.OfframpAddress)),
+ ccipreaderpkg.OCR3ConfigWithMeta(config),
+ ccipevm.NewCommitPluginCodecV1(),
+ ccipevm.NewMessageHasherV1(),
+ i.homeChainReader,
+ contractReaders,
+ chainWriters,
+ )
+ transmitter = ocrimpls.NewCommitContractTransmitter[[]byte](destChainWriter,
+ ocrtypes.Account(destFromAccounts[0]),
+ hexutil.Encode(config.Config.OfframpAddress), // TODO: this works for evm only, how about non-evm?
+ )
+ } else if config.Config.PluginType == uint8(cctypes.PluginTypeCCIPExec) {
+ factory = execocr3.NewPluginFactory(
+ i.lggr.
+ Named("CCIPExecPlugin").
+ Named(destRelayID.String()).
+ Named(hexutil.Encode(config.Config.OfframpAddress)),
+ ccipreaderpkg.OCR3ConfigWithMeta(config),
+ ccipevm.NewExecutePluginCodecV1(),
+ ccipevm.NewMessageHasherV1(),
+ i.homeChainReader,
+ contractReaders,
+ chainWriters,
+ )
+ transmitter = ocrimpls.NewExecContractTransmitter[[]byte](destChainWriter,
+ ocrtypes.Account(destFromAccounts[0]),
+ hexutil.Encode(config.Config.OfframpAddress), // TODO: this works for evm only, how about non-evm?
+ )
+ } else {
+ return nil, fmt.Errorf("unsupported plugin type %d", config.Config.PluginType)
+ }
+
+ oracleArgs := libocr3.OCR3OracleArgs[[]byte]{
+ BinaryNetworkEndpointFactory: i.peerWrapper.Peer2,
+ Database: i.db,
+ V2Bootstrappers: i.bootstrapperLocators,
+ ContractConfigTracker: configTracker,
+ ContractTransmitter: transmitter,
+ LocalConfig: defaultLocalConfig(),
+ Logger: ocrcommon.NewOCRWrapper(
+ i.lggr.
+ Named(fmt.Sprintf("CCIP%sOCR3", pluginType.String())).
+ Named(destRelayID.String()).
+ Named(hexutil.Encode(config.Config.OfframpAddress)),
+ false,
+ func(ctx context.Context, msg string) {}),
+ MetricsRegisterer: prometheus.WrapRegistererWith(map[string]string{"name": fmt.Sprintf("commit-%d", config.Config.ChainSelector)}, prometheus.DefaultRegisterer),
+ MonitoringEndpoint: i.monitoringEndpointGen.GenMonitoringEndpoint(
+ destChainFamily,
+ destRelayID.ChainID,
+ string(config.Config.OfframpAddress),
+ synchronization.OCR3CCIPCommit,
+ ),
+ OffchainConfigDigester: ocrimpls.NewConfigDigester(config.ConfigDigest),
+ OffchainKeyring: keybundle,
+ OnchainKeyring: onchainKeyring,
+ ReportingPluginFactory: factory,
+ }
+ oracle, err := libocr3.NewOracle(oracleArgs)
+ if err != nil {
+ return nil, err
+ }
+ return oracle, nil
+}
+
+func defaultLocalConfig() ocrtypes.LocalConfig {
+ return ocrtypes.LocalConfig{
+ BlockchainTimeout: 10 * time.Second,
+ // Config tracking is handled by the launcher, since we're doing blue-green
+ // deployments we're not going to be using OCR's built-in config switching,
+ // which always shuts down the previous instance.
+ ContractConfigConfirmations: 1,
+ SkipContractConfigConfirmations: true,
+ ContractConfigTrackerPollInterval: 10 * time.Second,
+ ContractTransmitterTransmitTimeout: 10 * time.Second,
+ DatabaseTimeout: 10 * time.Second,
+ MinOCR2MaxDurationQuery: 1 * time.Second,
+ DevelopmentMode: "false",
+ }
+}
diff --git a/core/capabilities/ccip/oraclecreator/inprocess_test.go b/core/capabilities/ccip/oraclecreator/inprocess_test.go
new file mode 100644
index 00000000000..639f01e62e3
--- /dev/null
+++ b/core/capabilities/ccip/oraclecreator/inprocess_test.go
@@ -0,0 +1,239 @@
+package oraclecreator_test
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/oraclecreator"
+ cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/google/uuid"
+ "github.com/hashicorp/consul/sdk/freeport"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "gopkg.in/guregu/null.v4"
+
+ chainsel "github.com/smartcontractkit/chain-selectors"
+ "github.com/smartcontractkit/libocr/offchainreporting2/types"
+ confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper"
+
+ "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+
+ "github.com/smartcontractkit/libocr/commontypes"
+
+ "github.com/smartcontractkit/chainlink/v2/core/bridges"
+ "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/chainlink"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2"
+ ocr2validate "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
+ "github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
+ "github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
+ "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs"
+ "github.com/smartcontractkit/chainlink/v2/core/utils"
+)
+
+func TestOracleCreator_CreateBootstrap(t *testing.T) {
+ db := pgtest.NewSqlxDB(t)
+
+ keyStore := keystore.New(db, utils.DefaultScryptParams, logger.NullLogger)
+ require.NoError(t, keyStore.Unlock(testutils.Context(t), cltest.Password), "unable to unlock keystore")
+ p2pKey, err := keyStore.P2P().Create(testutils.Context(t))
+ require.NoError(t, err)
+ peerID := p2pKey.PeerID()
+ listenPort := freeport.GetOne(t)
+ generalConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {
+ c.P2P.PeerID = ptr(peerID)
+ c.P2P.TraceLogging = ptr(false)
+ c.P2P.V2.Enabled = ptr(true)
+ c.P2P.V2.ListenAddresses = ptr([]string{fmt.Sprintf("127.0.0.1:%d", listenPort)})
+
+ c.OCR2.Enabled = ptr(true)
+ })
+ peerWrapper := ocrcommon.NewSingletonPeerWrapper(keyStore, generalConfig.P2P(), generalConfig.OCR(), db, logger.NullLogger)
+ require.NoError(t, peerWrapper.Start(testutils.Context(t)))
+ t.Cleanup(func() { assert.NoError(t, peerWrapper.Close()) })
+
+ // NOTE: this is a bit of a hack to get the OCR2 job created in order to use the ocr db
+ // the ocr2_contract_configs table has a foreign key constraint on ocr2_oracle_spec_id
+ // which is passed into ocr2.NewDB.
+ pipelineORM := pipeline.NewORM(db,
+ logger.NullLogger, generalConfig.JobPipeline().MaxSuccessfulRuns())
+ bridgesORM := bridges.NewORM(db)
+
+ jobORM := job.NewORM(db, pipelineORM, bridgesORM, keyStore, logger.TestLogger(t))
+ t.Cleanup(func() { assert.NoError(t, jobORM.Close()) })
+
+ jb, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), generalConfig.OCR2(), generalConfig.Insecure(), testspecs.GetOCR2EVMSpecMinimal(), nil)
+ require.NoError(t, err)
+ const juelsPerFeeCoinSource = `
+ ds [type=http method=GET url="https://chain.link/ETH-USD"];
+ ds_parse [type=jsonparse path="data.price" separator="."];
+ ds_multiply [type=multiply times=100];
+ ds -> ds_parse -> ds_multiply;`
+
+ _, address := cltest.MustInsertRandomKey(t, keyStore.Eth())
+ jb.Name = null.StringFrom("Job 1")
+ jb.OCR2OracleSpec.TransmitterID = null.StringFrom(address.String())
+ jb.OCR2OracleSpec.PluginConfig["juelsPerFeeCoinSource"] = juelsPerFeeCoinSource
+
+ err = jobORM.CreateJob(testutils.Context(t), &jb)
+ require.NoError(t, err)
+
+ cltest.AssertCount(t, db, "ocr2_oracle_specs", 1)
+ cltest.AssertCount(t, db, "jobs", 1)
+
+ var oracleSpecID int32
+ err = db.Get(&oracleSpecID, "SELECT id FROM ocr2_oracle_specs LIMIT 1")
+ require.NoError(t, err)
+
+ ocrdb := ocr2.NewDB(db, oracleSpecID, 0, logger.NullLogger)
+
+ oc := oraclecreator.New(
+ nil,
+ nil,
+ nil,
+ peerWrapper,
+ uuid.Max,
+ 0,
+ false,
+ nil,
+ ocrdb,
+ logger.TestLogger(t),
+ &mockEndpointGen{},
+ []commontypes.BootstrapperLocator{},
+ nil,
+ )
+
+ chainSelector := chainsel.GETH_TESTNET.Selector
+ oracles, offchainConfig := ocrOffchainConfig(t, keyStore)
+ bootstrapP2PID, err := p2pkey.MakePeerID(oracles[0].PeerID)
+ require.NoError(t, err)
+ transmitters := func() [][]byte {
+ var transmitters [][]byte
+ for _, o := range oracles {
+ transmitters = append(transmitters, hexutil.MustDecode(string(o.TransmitAccount)))
+ }
+ return transmitters
+ }()
+ configDigest := ccipConfigDigest()
+ bootstrap, err := oc.CreateBootstrapOracle(cctypes.OCR3ConfigWithMeta{
+ ConfigDigest: configDigest,
+ ConfigCount: 1,
+ Config: reader.OCR3Config{
+ ChainSelector: ccipocr3.ChainSelector(chainSelector),
+ OfframpAddress: testutils.NewAddress().Bytes(),
+ PluginType: uint8(cctypes.PluginTypeCCIPCommit),
+ F: 1,
+ OffchainConfigVersion: 30,
+ BootstrapP2PIds: [][32]byte{bootstrapP2PID},
+ P2PIds: func() [][32]byte {
+ var ids [][32]byte
+ for _, o := range oracles {
+ id, err2 := p2pkey.MakePeerID(o.PeerID)
+ require.NoError(t, err2)
+ ids = append(ids, id)
+ }
+ return ids
+ }(),
+ Signers: func() [][]byte {
+ var signers [][]byte
+ for _, o := range oracles {
+ signers = append(signers, o.OnchainPublicKey)
+ }
+ return signers
+ }(),
+ Transmitters: transmitters,
+ OffchainConfig: offchainConfig,
+ },
+ })
+ require.NoError(t, err)
+ require.NoError(t, bootstrap.Start())
+ t.Cleanup(func() { assert.NoError(t, bootstrap.Close()) })
+
+ tests.AssertEventually(t, func() bool {
+ c, err := ocrdb.ReadConfig(testutils.Context(t))
+ require.NoError(t, err)
+ return c.ConfigDigest == configDigest
+ })
+}
+
+func ccipConfigDigest() [32]byte {
+ rand32Bytes := testutils.Random32Byte()
+ // overwrite first four bytes to be 0x000a, to match the prefix in libocr.
+ rand32Bytes[0] = 0x00
+ rand32Bytes[1] = 0x0a
+ return rand32Bytes
+}
+
+type mockEndpointGen struct{}
+
+func (m *mockEndpointGen) GenMonitoringEndpoint(network string, chainID string, contractID string, telemType synchronization.TelemetryType) commontypes.MonitoringEndpoint {
+ return &telemetry.NoopAgent{}
+}
+
+func ptr[T any](b T) *T {
+ return &b
+}
+
+func ocrOffchainConfig(t *testing.T, ks keystore.Master) (oracles []confighelper2.OracleIdentityExtra, offchainConfig []byte) {
+ for i := 0; i < 4; i++ {
+ kb, err := ks.OCR2().Create(testutils.Context(t), chaintype.EVM)
+ require.NoError(t, err)
+ p2pKey, err := ks.P2P().Create(testutils.Context(t))
+ require.NoError(t, err)
+ ethKey, err := ks.Eth().Create(testutils.Context(t))
+ require.NoError(t, err)
+ oracles = append(oracles, confighelper2.OracleIdentityExtra{
+ OracleIdentity: confighelper2.OracleIdentity{
+ OffchainPublicKey: kb.OffchainPublicKey(),
+ OnchainPublicKey: types.OnchainPublicKey(kb.OnChainPublicKey()),
+ PeerID: p2pKey.ID(),
+ TransmitAccount: types.Account(ethKey.Address.Hex()),
+ },
+ ConfigEncryptionPublicKey: kb.ConfigEncryptionPublicKey(),
+ })
+ }
+ var schedule []int
+ for range oracles {
+ schedule = append(schedule, 1)
+ }
+ offchainConfig, onchainConfig := []byte{}, []byte{}
+ f := uint8(1)
+
+ _, _, _, _, _, offchainConfig, err := ocr3confighelper.ContractSetConfigArgsForTests(
+ 30*time.Second, // deltaProgress
+ 10*time.Second, // deltaResend
+ 20*time.Second, // deltaInitial
+ 2*time.Second, // deltaRound
+ 20*time.Second, // deltaGrace
+ 10*time.Second, // deltaCertifiedCommitRequest
+ 10*time.Second, // deltaStage
+ 3, // rmax
+ schedule,
+ oracles,
+ offchainConfig,
+ 50*time.Millisecond, // maxDurationQuery
+ 5*time.Second, // maxDurationObservation
+ 10*time.Second, // maxDurationShouldAcceptAttestedReport
+ 10*time.Second, // maxDurationShouldTransmitAcceptedReport
+ int(f),
+ onchainConfig)
+ require.NoError(t, err, "failed to create contract config")
+
+ return oracles, offchainConfig
+}
diff --git a/core/capabilities/ccip/types/mocks/ccip_oracle.go b/core/capabilities/ccip/types/mocks/ccip_oracle.go
new file mode 100644
index 00000000000..c849b3d9414
--- /dev/null
+++ b/core/capabilities/ccip/types/mocks/ccip_oracle.go
@@ -0,0 +1,122 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import mock "github.com/stretchr/testify/mock"
+
+// CCIPOracle is an autogenerated mock type for the CCIPOracle type
+type CCIPOracle struct {
+ mock.Mock
+}
+
+type CCIPOracle_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *CCIPOracle) EXPECT() *CCIPOracle_Expecter {
+ return &CCIPOracle_Expecter{mock: &_m.Mock}
+}
+
+// Close provides a mock function with given fields:
+func (_m *CCIPOracle) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CCIPOracle_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type CCIPOracle_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *CCIPOracle_Expecter) Close() *CCIPOracle_Close_Call {
+ return &CCIPOracle_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *CCIPOracle_Close_Call) Run(run func()) *CCIPOracle_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *CCIPOracle_Close_Call) Return(_a0 error) *CCIPOracle_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *CCIPOracle_Close_Call) RunAndReturn(run func() error) *CCIPOracle_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Start provides a mock function with given fields:
+func (_m *CCIPOracle) Start() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Start")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CCIPOracle_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
+type CCIPOracle_Start_Call struct {
+ *mock.Call
+}
+
+// Start is a helper method to define mock.On call
+func (_e *CCIPOracle_Expecter) Start() *CCIPOracle_Start_Call {
+ return &CCIPOracle_Start_Call{Call: _e.mock.On("Start")}
+}
+
+func (_c *CCIPOracle_Start_Call) Run(run func()) *CCIPOracle_Start_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *CCIPOracle_Start_Call) Return(_a0 error) *CCIPOracle_Start_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *CCIPOracle_Start_Call) RunAndReturn(run func() error) *CCIPOracle_Start_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewCCIPOracle creates a new instance of CCIPOracle. 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 NewCCIPOracle(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *CCIPOracle {
+ mock := &CCIPOracle{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/capabilities/ccip/types/mocks/home_chain_reader.go b/core/capabilities/ccip/types/mocks/home_chain_reader.go
new file mode 100644
index 00000000000..a5a581a1d2d
--- /dev/null
+++ b/core/capabilities/ccip/types/mocks/home_chain_reader.go
@@ -0,0 +1,129 @@
+package mocks
+
+import (
+ "context"
+
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/stretchr/testify/mock"
+
+ ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
+
+ "github.com/smartcontractkit/libocr/ragep2p/types"
+)
+
+var _ ccipreaderpkg.HomeChain = (*HomeChainReader)(nil)
+
+type HomeChainReader struct {
+ mock.Mock
+}
+
+func (_m *HomeChainReader) GetChainConfig(chainSelector cciptypes.ChainSelector) (ccipreaderpkg.ChainConfig, error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (_m *HomeChainReader) GetAllChainConfigs() (map[cciptypes.ChainSelector]ccipreaderpkg.ChainConfig, error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (_m *HomeChainReader) GetSupportedChainsForPeer(id types.PeerID) (mapset.Set[cciptypes.ChainSelector], error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (_m *HomeChainReader) GetKnownCCIPChains() (mapset.Set[cciptypes.ChainSelector], error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (_m *HomeChainReader) GetFChain() (map[cciptypes.ChainSelector]int, error) {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (_m *HomeChainReader) Start(ctx context.Context) error {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (_m *HomeChainReader) Close() error {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (_m *HomeChainReader) HealthReport() map[string]error {
+ //TODO implement me
+ panic("implement me")
+}
+
+func (_m *HomeChainReader) Name() string {
+ //TODO implement me
+ panic("implement me")
+}
+
+// GetOCRConfigs provides a mock function with given fields: ctx, donID, pluginType
+func (_m *HomeChainReader) GetOCRConfigs(ctx context.Context, donID uint32, pluginType uint8) ([]ccipreaderpkg.OCR3ConfigWithMeta, error) {
+ ret := _m.Called(ctx, donID, pluginType)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetOCRConfigs")
+ }
+
+ var r0 []ccipreaderpkg.OCR3ConfigWithMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(ctx context.Context, donID uint32, pluginType uint8) ([]ccipreaderpkg.OCR3ConfigWithMeta, error)); ok {
+ return rf(ctx, donID, pluginType)
+ }
+ if rf, ok := ret.Get(0).(func(ctx context.Context, donID uint32, pluginType uint8) []ccipreaderpkg.OCR3ConfigWithMeta); ok {
+ r0 = rf(ctx, donID, pluginType)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccipreaderpkg.OCR3ConfigWithMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(ctx context.Context, donID uint32, pluginType uint8) error); ok {
+ r1 = rf(ctx, donID, pluginType)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+func (_m *HomeChainReader) Ready() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Ready")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ return rf()
+ }
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// NewHomeChainReader creates a new instance of HomeChainReader. 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 NewHomeChainReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *HomeChainReader {
+ mock := &HomeChainReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/capabilities/ccip/types/mocks/oracle_creator.go b/core/capabilities/ccip/types/mocks/oracle_creator.go
new file mode 100644
index 00000000000..d83ad042bfe
--- /dev/null
+++ b/core/capabilities/ccip/types/mocks/oracle_creator.go
@@ -0,0 +1,152 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ types "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// OracleCreator is an autogenerated mock type for the OracleCreator type
+type OracleCreator struct {
+ mock.Mock
+}
+
+type OracleCreator_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *OracleCreator) EXPECT() *OracleCreator_Expecter {
+ return &OracleCreator_Expecter{mock: &_m.Mock}
+}
+
+// CreateBootstrapOracle provides a mock function with given fields: config
+func (_m *OracleCreator) CreateBootstrapOracle(config types.OCR3ConfigWithMeta) (types.CCIPOracle, error) {
+ ret := _m.Called(config)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CreateBootstrapOracle")
+ }
+
+ var r0 types.CCIPOracle
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.OCR3ConfigWithMeta) (types.CCIPOracle, error)); ok {
+ return rf(config)
+ }
+ if rf, ok := ret.Get(0).(func(types.OCR3ConfigWithMeta) types.CCIPOracle); ok {
+ r0 = rf(config)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(types.CCIPOracle)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.OCR3ConfigWithMeta) error); ok {
+ r1 = rf(config)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OracleCreator_CreateBootstrapOracle_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateBootstrapOracle'
+type OracleCreator_CreateBootstrapOracle_Call struct {
+ *mock.Call
+}
+
+// CreateBootstrapOracle is a helper method to define mock.On call
+// - config types.OCR3ConfigWithMeta
+func (_e *OracleCreator_Expecter) CreateBootstrapOracle(config interface{}) *OracleCreator_CreateBootstrapOracle_Call {
+ return &OracleCreator_CreateBootstrapOracle_Call{Call: _e.mock.On("CreateBootstrapOracle", config)}
+}
+
+func (_c *OracleCreator_CreateBootstrapOracle_Call) Run(run func(config types.OCR3ConfigWithMeta)) *OracleCreator_CreateBootstrapOracle_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.OCR3ConfigWithMeta))
+ })
+ return _c
+}
+
+func (_c *OracleCreator_CreateBootstrapOracle_Call) Return(_a0 types.CCIPOracle, _a1 error) *OracleCreator_CreateBootstrapOracle_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OracleCreator_CreateBootstrapOracle_Call) RunAndReturn(run func(types.OCR3ConfigWithMeta) (types.CCIPOracle, error)) *OracleCreator_CreateBootstrapOracle_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CreatePluginOracle provides a mock function with given fields: pluginType, config
+func (_m *OracleCreator) CreatePluginOracle(pluginType types.PluginType, config types.OCR3ConfigWithMeta) (types.CCIPOracle, error) {
+ ret := _m.Called(pluginType, config)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CreatePluginOracle")
+ }
+
+ var r0 types.CCIPOracle
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.PluginType, types.OCR3ConfigWithMeta) (types.CCIPOracle, error)); ok {
+ return rf(pluginType, config)
+ }
+ if rf, ok := ret.Get(0).(func(types.PluginType, types.OCR3ConfigWithMeta) types.CCIPOracle); ok {
+ r0 = rf(pluginType, config)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(types.CCIPOracle)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.PluginType, types.OCR3ConfigWithMeta) error); ok {
+ r1 = rf(pluginType, config)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OracleCreator_CreatePluginOracle_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreatePluginOracle'
+type OracleCreator_CreatePluginOracle_Call struct {
+ *mock.Call
+}
+
+// CreatePluginOracle is a helper method to define mock.On call
+// - pluginType types.PluginType
+// - config types.OCR3ConfigWithMeta
+func (_e *OracleCreator_Expecter) CreatePluginOracle(pluginType interface{}, config interface{}) *OracleCreator_CreatePluginOracle_Call {
+ return &OracleCreator_CreatePluginOracle_Call{Call: _e.mock.On("CreatePluginOracle", pluginType, config)}
+}
+
+func (_c *OracleCreator_CreatePluginOracle_Call) Run(run func(pluginType types.PluginType, config types.OCR3ConfigWithMeta)) *OracleCreator_CreatePluginOracle_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.PluginType), args[1].(types.OCR3ConfigWithMeta))
+ })
+ return _c
+}
+
+func (_c *OracleCreator_CreatePluginOracle_Call) Return(_a0 types.CCIPOracle, _a1 error) *OracleCreator_CreatePluginOracle_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OracleCreator_CreatePluginOracle_Call) RunAndReturn(run func(types.PluginType, types.OCR3ConfigWithMeta) (types.CCIPOracle, error)) *OracleCreator_CreatePluginOracle_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewOracleCreator creates a new instance of OracleCreator. 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 NewOracleCreator(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *OracleCreator {
+ mock := &OracleCreator{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/capabilities/ccip/types/types.go b/core/capabilities/ccip/types/types.go
new file mode 100644
index 00000000000..952b8fe4465
--- /dev/null
+++ b/core/capabilities/ccip/types/types.go
@@ -0,0 +1,46 @@
+package types
+
+import (
+ ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader"
+)
+
+// OCR3ConfigWithMeta is a type alias in order to generate correct mocks for the OracleCreator interface.
+type OCR3ConfigWithMeta ccipreaderpkg.OCR3ConfigWithMeta
+
+// PluginType represents the type of CCIP plugin.
+// It mirrors the OCRPluginType in Internal.sol.
+type PluginType uint8
+
+const (
+ PluginTypeCCIPCommit PluginType = 0
+ PluginTypeCCIPExec PluginType = 1
+)
+
+func (pt PluginType) String() string {
+ switch pt {
+ case PluginTypeCCIPCommit:
+ return "CCIPCommit"
+ case PluginTypeCCIPExec:
+ return "CCIPExec"
+ default:
+ return "Unknown"
+ }
+}
+
+// CCIPOracle represents either a CCIP commit or exec oracle or a bootstrap node.
+type CCIPOracle interface {
+ Close() error
+ Start() error
+}
+
+// OracleCreator is an interface for creating CCIP oracles.
+// Whether the oracle uses a LOOPP or not is an implementation detail.
+type OracleCreator interface {
+ // CreatePlugin creates a new oracle that will run either the commit or exec ccip plugin.
+ // The oracle must be returned unstarted.
+ CreatePluginOracle(pluginType PluginType, config OCR3ConfigWithMeta) (CCIPOracle, error)
+
+ // CreateBootstrapOracle creates a new bootstrap node with the given OCR config.
+ // The oracle must be returned unstarted.
+ CreateBootstrapOracle(config OCR3ConfigWithMeta) (CCIPOracle, error)
+}
diff --git a/core/capabilities/ccip/validate/validate.go b/core/capabilities/ccip/validate/validate.go
new file mode 100644
index 00000000000..04f4f4a4959
--- /dev/null
+++ b/core/capabilities/ccip/validate/validate.go
@@ -0,0 +1,94 @@
+package validate
+
+import (
+ "fmt"
+
+ "github.com/google/uuid"
+ "github.com/pelletier/go-toml"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
+)
+
+// ValidatedCCIPSpec validates the given toml string as a CCIP spec.
+func ValidatedCCIPSpec(tomlString string) (jb job.Job, err error) {
+ var spec job.CCIPSpec
+ tree, err := toml.Load(tomlString)
+ if err != nil {
+ return job.Job{}, fmt.Errorf("toml error on load: %w", err)
+ }
+ // Note this validates all the fields which implement an UnmarshalText
+ err = tree.Unmarshal(&spec)
+ if err != nil {
+ return job.Job{}, fmt.Errorf("toml unmarshal error on spec: %w", err)
+ }
+ err = tree.Unmarshal(&jb)
+ if err != nil {
+ return job.Job{}, fmt.Errorf("toml unmarshal error on job: %w", err)
+ }
+ jb.CCIPSpec = &spec
+
+ if jb.Type != job.CCIP {
+ return job.Job{}, fmt.Errorf("the only supported type is currently 'ccip', got %s", jb.Type)
+ }
+ if jb.CCIPSpec.CapabilityLabelledName == "" {
+ return job.Job{}, fmt.Errorf("capabilityLabelledName must be set")
+ }
+ if jb.CCIPSpec.CapabilityVersion == "" {
+ return job.Job{}, fmt.Errorf("capabilityVersion must be set")
+ }
+ if jb.CCIPSpec.P2PKeyID == "" {
+ return job.Job{}, fmt.Errorf("p2pKeyID must be set")
+ }
+ if len(jb.CCIPSpec.P2PV2Bootstrappers) == 0 {
+ return job.Job{}, fmt.Errorf("p2pV2Bootstrappers must be set")
+ }
+
+ // ensure that the P2PV2Bootstrappers is in the right format.
+ for _, bootstrapperLocator := range jb.CCIPSpec.P2PV2Bootstrappers {
+ // needs to be of the form @:
+ _, err := ocrcommon.ParseBootstrapPeers([]string{bootstrapperLocator})
+ if err != nil {
+ return job.Job{}, fmt.Errorf("p2p v2 bootstrapper locator %s is not in the correct format: %w", bootstrapperLocator, err)
+ }
+ }
+
+ return jb, nil
+}
+
+type SpecArgs struct {
+ P2PV2Bootstrappers []string `toml:"p2pV2Bootstrappers"`
+ CapabilityVersion string `toml:"capabilityVersion"`
+ CapabilityLabelledName string `toml:"capabilityLabelledName"`
+ OCRKeyBundleIDs map[string]string `toml:"ocrKeyBundleIDs"`
+ P2PKeyID string `toml:"p2pKeyID"`
+ RelayConfigs map[string]any `toml:"relayConfigs"`
+ PluginConfig map[string]any `toml:"pluginConfig"`
+}
+
+// NewCCIPSpecToml creates a new CCIP spec in toml format from the given spec args.
+func NewCCIPSpecToml(spec SpecArgs) (string, error) {
+ type fullSpec struct {
+ SpecArgs
+ Type string `toml:"type"`
+ SchemaVersion uint64 `toml:"schemaVersion"`
+ Name string `toml:"name"`
+ ExternalJobID string `toml:"externalJobID"`
+ }
+ extJobID, err := uuid.NewRandom()
+ if err != nil {
+ return "", fmt.Errorf("failed to generate external job id: %w", err)
+ }
+ marshaled, err := toml.Marshal(fullSpec{
+ SpecArgs: spec,
+ Type: "ccip",
+ SchemaVersion: 1,
+ Name: fmt.Sprintf("%s-%s", "ccip", extJobID.String()),
+ ExternalJobID: extJobID.String(),
+ })
+ if err != nil {
+ return "", fmt.Errorf("failed to marshal spec into toml: %w", err)
+ }
+
+ return string(marshaled), nil
+}
diff --git a/core/capabilities/ccip/validate/validate_test.go b/core/capabilities/ccip/validate/validate_test.go
new file mode 100644
index 00000000000..97958f4cf9d
--- /dev/null
+++ b/core/capabilities/ccip/validate/validate_test.go
@@ -0,0 +1,58 @@
+package validate_test
+
+import (
+ "testing"
+
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+)
+
+func TestNewCCIPSpecToml(t *testing.T) {
+ tests := []struct {
+ name string
+ specArgs validate.SpecArgs
+ want string
+ wantErr bool
+ }{
+ // TODO: Add test cases.
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := validate.NewCCIPSpecToml(tt.specArgs)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.want, got)
+ }
+ })
+ }
+}
+
+func TestValidatedCCIPSpec(t *testing.T) {
+ type args struct {
+ tomlString string
+ }
+ tests := []struct {
+ name string
+ args args
+ wantJb job.Job
+ wantErr bool
+ }{
+ // TODO: Add test cases.
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ gotJb, err := validate.ValidatedCCIPSpec(tt.args.tomlString)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.wantJb, gotJb)
+ }
+ })
+ }
+}
diff --git a/core/capabilities/integration_tests/keystone_contracts_setup.go b/core/capabilities/integration_tests/keystone_contracts_setup.go
index 42269d1bd45..b138b8f8127 100644
--- a/core/capabilities/integration_tests/keystone_contracts_setup.go
+++ b/core/capabilities/integration_tests/keystone_contracts_setup.go
@@ -26,7 +26,6 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink-common/pkg/values"
- "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
@@ -40,6 +39,13 @@ import (
kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
)
+const (
+ CapabilityTypeTrigger = 0
+ CapabilityTypeAction = 1
+ CapabilityTypeConsensus = 2
+ CapabilityTypeTarget = 3
+)
+
type peer struct {
PeerID string
Signer string
@@ -91,8 +97,8 @@ func peerToNode(nopID uint32, p peer) (kcr.CapabilitiesRegistryNodeParams, error
}, nil
}
-func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workflowDonPeers []peer, triggerDonPeers []peer,
- targetDonPeerIDs []peer,
+func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workflowDon donInfo, triggerDon donInfo,
+ targetDon donInfo,
transactOpts *bind.TransactOpts, backend *ethBackend) common.Address {
addr, _, reg, err := kcr.DeployCapabilitiesRegistry(transactOpts, backend)
require.NoError(t, err)
@@ -102,15 +108,16 @@ func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workfl
streamsTrigger := kcr.CapabilitiesRegistryCapability{
LabelledName: "streams-trigger",
Version: "1.0.0",
- CapabilityType: uint8(capabilities.CapabilityTypeTrigger),
+ CapabilityType: CapabilityTypeTrigger,
}
sid, err := reg.GetHashedCapabilityId(&bind.CallOpts{}, streamsTrigger.LabelledName, streamsTrigger.Version)
require.NoError(t, err)
writeChain := kcr.CapabilitiesRegistryCapability{
- LabelledName: "write_geth-testnet",
- Version: "1.0.0",
- CapabilityType: uint8(capabilities.CapabilityTypeTarget),
+ LabelledName: "write_geth-testnet",
+ Version: "1.0.0",
+
+ CapabilityType: CapabilityTypeTarget,
}
wid, err := reg.GetHashedCapabilityId(&bind.CallOpts{}, writeChain.LabelledName, writeChain.Version)
if err != nil {
@@ -120,7 +127,7 @@ func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workfl
ocr := kcr.CapabilitiesRegistryCapability{
LabelledName: "offchain_reporting",
Version: "1.0.0",
- CapabilityType: uint8(capabilities.CapabilityTypeConsensus),
+ CapabilityType: CapabilityTypeConsensus,
}
ocrid, err := reg.GetHashedCapabilityId(&bind.CallOpts{}, ocr.LabelledName, ocr.Version)
require.NoError(t, err)
@@ -157,7 +164,7 @@ func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workfl
nopID := recLog.NodeOperatorId
nodes := []kcr.CapabilitiesRegistryNodeParams{}
- for _, wfPeer := range workflowDonPeers {
+ for _, wfPeer := range workflowDon.peerIDs {
n, innerErr := peerToNode(nopID, wfPeer)
require.NoError(t, innerErr)
@@ -165,7 +172,7 @@ func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workfl
nodes = append(nodes, n)
}
- for _, triggerPeer := range triggerDonPeers {
+ for _, triggerPeer := range triggerDon.peerIDs {
n, innerErr := peerToNode(nopID, triggerPeer)
require.NoError(t, innerErr)
@@ -173,7 +180,7 @@ func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workfl
nodes = append(nodes, n)
}
- for _, targetPeer := range targetDonPeerIDs {
+ for _, targetPeer := range targetDon.peerIDs {
n, innerErr := peerToNode(nopID, targetPeer)
require.NoError(t, innerErr)
@@ -185,7 +192,7 @@ func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workfl
require.NoError(t, err)
// workflow DON
- ps, err := peers(workflowDonPeers)
+ ps, err := peers(workflowDon.peerIDs)
require.NoError(t, err)
cc := newCapabilityConfig()
@@ -199,22 +206,24 @@ func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workfl
},
}
- workflowDonF := uint8(2)
- _, err = reg.AddDON(transactOpts, ps, cfgs, false, true, workflowDonF)
+ _, err = reg.AddDON(transactOpts, ps, cfgs, false, true, workflowDon.F)
require.NoError(t, err)
// trigger DON
- ps, err = peers(triggerDonPeers)
+ ps, err = peers(triggerDon.peerIDs)
require.NoError(t, err)
- triggerDonF := 1
- config := &pb.RemoteTriggerConfig{
- RegistrationRefresh: durationpb.New(20000 * time.Millisecond),
- RegistrationExpiry: durationpb.New(60000 * time.Millisecond),
- // F + 1
- MinResponsesToAggregate: uint32(triggerDonF) + 1,
+ triggerCapabilityConfig := newCapabilityConfig()
+ triggerCapabilityConfig.RemoteConfig = &pb.CapabilityConfig_RemoteTriggerConfig{
+ RemoteTriggerConfig: &pb.RemoteTriggerConfig{
+ RegistrationRefresh: durationpb.New(1000 * time.Millisecond),
+ RegistrationExpiry: durationpb.New(60000 * time.Millisecond),
+ // F + 1
+ MinResponsesToAggregate: uint32(triggerDon.F) + 1,
+ },
}
- configb, err := proto.Marshal(config)
+
+ configb, err := proto.Marshal(triggerCapabilityConfig)
require.NoError(t, err)
cfgs = []kcr.CapabilitiesRegistryCapabilityConfiguration{
@@ -224,22 +233,31 @@ func setupCapabilitiesRegistryContract(ctx context.Context, t *testing.T, workfl
},
}
- _, err = reg.AddDON(transactOpts, ps, cfgs, true, false, uint8(triggerDonF))
+ _, err = reg.AddDON(transactOpts, ps, cfgs, true, false, triggerDon.F)
require.NoError(t, err)
// target DON
- ps, err = peers(targetDonPeerIDs)
+ ps, err = peers(targetDon.peerIDs)
+ require.NoError(t, err)
+
+ targetCapabilityConfig := newCapabilityConfig()
+ targetCapabilityConfig.RemoteConfig = &pb.CapabilityConfig_RemoteTargetConfig{
+ RemoteTargetConfig: &pb.RemoteTargetConfig{
+ RequestHashExcludedAttributes: []string{"signed_report.Signatures"},
+ },
+ }
+
+ remoteTargetConfigBytes, err := proto.Marshal(targetCapabilityConfig)
require.NoError(t, err)
cfgs = []kcr.CapabilitiesRegistryCapabilityConfiguration{
{
CapabilityId: wid,
- Config: ccb,
+ Config: remoteTargetConfigBytes,
},
}
- targetDonF := uint8(1)
- _, err = reg.AddDON(transactOpts, ps, cfgs, true, false, targetDonF)
+ _, err = reg.AddDON(transactOpts, ps, cfgs, true, false, targetDon.F)
require.NoError(t, err)
backend.Commit()
@@ -253,19 +271,18 @@ func newCapabilityConfig() *pb.CapabilityConfig {
}
}
-func setupForwarderContract(t *testing.T, workflowDonPeers []peer, workflowDonId uint32,
- configVersion uint32, f uint8,
+func setupForwarderContract(t *testing.T, workflowDon donInfo,
transactOpts *bind.TransactOpts, backend *ethBackend) (common.Address, *forwarder.KeystoneForwarder) {
addr, _, fwd, err := forwarder.DeployKeystoneForwarder(transactOpts, backend)
require.NoError(t, err)
backend.Commit()
var signers []common.Address
- for _, p := range workflowDonPeers {
+ for _, p := range workflowDon.peerIDs {
signers = append(signers, common.HexToAddress(p.Signer))
}
- _, err = fwd.SetConfig(transactOpts, workflowDonId, configVersion, f, signers)
+ _, err = fwd.SetConfig(transactOpts, workflowDon.ID, workflowDon.ConfigVersion, workflowDon.F, signers)
require.NoError(t, err)
backend.Commit()
diff --git a/core/capabilities/integration_tests/mock_dispatcher.go b/core/capabilities/integration_tests/mock_dispatcher.go
index f685f0ad2e9..1230e59427d 100644
--- a/core/capabilities/integration_tests/mock_dispatcher.go
+++ b/core/capabilities/integration_tests/mock_dispatcher.go
@@ -9,6 +9,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+ "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"
@@ -58,6 +59,7 @@ func (a *testAsyncMessageBroker) NewDispatcherForNode(nodePeerID p2ptypes.PeerID
return &brokerDispatcher{
callerPeerID: nodePeerID,
broker: a,
+ receivers: map[key]remotetypes.Receiver{},
}
}
@@ -158,6 +160,14 @@ type broker interface {
type brokerDispatcher struct {
callerPeerID p2ptypes.PeerID
broker broker
+
+ receivers map[key]remotetypes.Receiver
+ mu sync.Mutex
+}
+
+type key struct {
+ capId string
+ donId uint32
}
func (t *brokerDispatcher) Send(peerID p2ptypes.PeerID, msgBody *remotetypes.MessageBody) error {
@@ -171,6 +181,15 @@ func (t *brokerDispatcher) Send(peerID p2ptypes.PeerID, msgBody *remotetypes.Mes
}
func (t *brokerDispatcher) SetReceiver(capabilityId string, donId uint32, receiver remotetypes.Receiver) error {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ k := key{capabilityId, donId}
+ _, ok := t.receivers[k]
+ if ok {
+ return fmt.Errorf("%w: receiver already exists for capability %s and don %d", remote.ErrReceiverExists, capabilityId, donId)
+ }
+ t.receivers[k] = receiver
+
t.broker.(*testAsyncMessageBroker).registerReceiverNode(t.callerPeerID, capabilityId, donId, receiver)
return nil
}
diff --git a/core/capabilities/integration_tests/mock_libocr.go b/core/capabilities/integration_tests/mock_libocr.go
index 39c53d48aff..14ccdce6000 100644
--- a/core/capabilities/integration_tests/mock_libocr.go
+++ b/core/capabilities/integration_tests/mock_libocr.go
@@ -157,10 +157,6 @@ func (m *mockLibOCR) simulateProtocolRound(ctx context.Context) error {
Signer: commontypes.OracleID(i),
Signature: sig,
})
-
- if uint8(len(signatures)) == m.f+1 {
- break
- }
}
for _, node := range m.nodes {
@@ -181,7 +177,16 @@ func (m *mockLibOCR) simulateProtocolRound(ctx context.Context) error {
continue
}
- err = node.Transmit(ctx, types.ConfigDigest{}, 0, report, signatures)
+ // For each node select a random set of f+1 signatures to mimic libocr behaviour
+ s := rand.NewSource(time.Now().UnixNano())
+ r := rand.New(s)
+ indices := r.Perm(len(signatures))
+ selectedSignatures := make([]types.AttributedOnchainSignature, m.f+1)
+ for i := 0; i < int(m.f+1); i++ {
+ selectedSignatures[i] = signatures[indices[i]]
+ }
+
+ err = node.Transmit(ctx, types.ConfigDigest{}, 0, report, selectedSignatures)
if err != nil {
return fmt.Errorf("failed to transmit report: %w", err)
}
diff --git a/core/capabilities/integration_tests/mock_trigger.go b/core/capabilities/integration_tests/mock_trigger.go
index cb673f54ff6..0ed1fe5c8dd 100644
--- a/core/capabilities/integration_tests/mock_trigger.go
+++ b/core/capabilities/integration_tests/mock_trigger.go
@@ -88,18 +88,20 @@ func (s *streamsTrigger) RegisterTrigger(ctx context.Context, request capabiliti
responseCh := make(chan capabilities.CapabilityResponse)
- ctxWithCancel, cancel := context.WithCancel(ctx)
+ ctxWithCancel, cancel := context.WithCancel(context.Background())
s.cancel = cancel
s.wg.Add(1)
go func() {
defer s.wg.Done()
- select {
- case <-s.stopCh:
- return
- case <-ctxWithCancel.Done():
- return
- case resp := <-s.toSend:
- responseCh <- resp
+ for {
+ select {
+ case <-s.stopCh:
+ return
+ case <-ctxWithCancel.Done():
+ return
+ case resp := <-s.toSend:
+ responseCh <- resp
+ }
}
}()
diff --git a/core/capabilities/integration_tests/setup.go b/core/capabilities/integration_tests/setup.go
index 0095d2fd9de..69b8c3eaa0a 100644
--- a/core/capabilities/integration_tests/setup.go
+++ b/core/capabilities/integration_tests/setup.go
@@ -68,8 +68,8 @@ func setupStreamDonsWithTransmissionSchedule(ctx context.Context, t *testing.T,
lggr.SetLogLevel(TestLogLevel)
ethBlockchain, transactor := setupBlockchain(t, 1000, 1*time.Second)
- capabilitiesRegistryAddr := setupCapabilitiesRegistryContract(ctx, t, workflowDonInfo.peerIDs, triggerDonInfo.peerIDs, targetDonInfo.peerIDs, transactor, ethBlockchain)
- forwarderAddr, _ := setupForwarderContract(t, workflowDonInfo.peerIDs, workflowDonInfo.ID, 1, workflowDonInfo.F, transactor, ethBlockchain)
+ capabilitiesRegistryAddr := setupCapabilitiesRegistryContract(ctx, t, workflowDonInfo, triggerDonInfo, targetDonInfo, transactor, ethBlockchain)
+ forwarderAddr, _ := setupForwarderContract(t, workflowDonInfo, transactor, ethBlockchain)
consumerAddr, consumer := setupConsumerContract(t, transactor, ethBlockchain, forwarderAddr, workflowOwnerID, workflowName)
var feedIDs []string
@@ -259,9 +259,10 @@ func createDonInfo(t *testing.T, don don) donInfo {
triggerDonInfo := donInfo{
DON: commoncap.DON{
- ID: don.id,
- Members: donPeers,
- F: don.f,
+ ID: don.id,
+ Members: donPeers,
+ F: don.f,
+ ConfigVersion: 1,
},
peerIDs: peerIDs,
keys: donKeys,
diff --git a/core/capabilities/integration_tests/streams_test.go b/core/capabilities/integration_tests/streams_test.go
index 6216e36c856..8c8f51914c2 100644
--- a/core/capabilities/integration_tests/streams_test.go
+++ b/core/capabilities/integration_tests/streams_test.go
@@ -22,8 +22,8 @@ func Test_AllAtOnceTransmissionSchedule(t *testing.T) {
// The don IDs set in the below calls are inferred from the order in which the dons are added to the capabilities registry
// in the setupCapabilitiesRegistryContract function, should this order change the don IDs will need updating.
- workflowDonInfo := createDonInfo(t, don{id: 1, numNodes: 5, f: 1})
- triggerDonInfo := createDonInfo(t, don{id: 2, numNodes: 7, f: 1})
+ workflowDonInfo := createDonInfo(t, don{id: 1, numNodes: 7, f: 2})
+ triggerDonInfo := createDonInfo(t, don{id: 2, numNodes: 7, f: 2})
targetDonInfo := createDonInfo(t, don{id: 3, numNodes: 4, f: 1})
consumer, feedIDs, triggerSink := setupStreamDonsWithTransmissionSchedule(ctx, t, workflowDonInfo, triggerDonInfo, targetDonInfo, 3,
@@ -45,8 +45,8 @@ func Test_OneAtATimeTransmissionSchedule(t *testing.T) {
// The don IDs set in the below calls are inferred from the order in which the dons are added to the capabilities registry
// in the setupCapabilitiesRegistryContract function, should this order change the don IDs will need updating.
- workflowDonInfo := createDonInfo(t, don{id: 1, numNodes: 5, f: 1})
- triggerDonInfo := createDonInfo(t, don{id: 2, numNodes: 7, f: 1})
+ workflowDonInfo := createDonInfo(t, don{id: 1, numNodes: 7, f: 2})
+ triggerDonInfo := createDonInfo(t, don{id: 2, numNodes: 7, f: 2})
targetDonInfo := createDonInfo(t, don{id: 3, numNodes: 4, f: 1})
consumer, feedIDs, triggerSink := setupStreamDonsWithTransmissionSchedule(ctx, t, workflowDonInfo, triggerDonInfo, targetDonInfo, 3,
diff --git a/core/capabilities/launcher.go b/core/capabilities/launcher.go
index b4ade04127b..03a1dd54f02 100644
--- a/core/capabilities/launcher.go
+++ b/core/capabilities/launcher.go
@@ -4,16 +4,21 @@ import (
"context"
"errors"
"fmt"
+ "slices"
"strings"
"time"
+ "google.golang.org/protobuf/proto"
+
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers"
"github.com/smartcontractkit/chainlink-common/pkg/services"
+ "github.com/smartcontractkit/chainlink-common/pkg/values"
"github.com/smartcontractkit/libocr/ragep2p"
ragetypes "github.com/smartcontractkit/libocr/ragep2p/types"
+ capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/target"
remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types"
@@ -24,16 +29,16 @@ import (
)
var defaultStreamConfig = p2ptypes.StreamConfig{
- IncomingMessageBufferSize: 1000000,
- OutgoingMessageBufferSize: 1000000,
- MaxMessageLenBytes: 100000,
+ IncomingMessageBufferSize: 500,
+ OutgoingMessageBufferSize: 500,
+ MaxMessageLenBytes: 500000, // 500 KB; max capacity = 500 * 500000 = 250 MB
MessageRateLimiter: ragep2p.TokenBucketParams{
Rate: 100.0,
- Capacity: 1000,
+ Capacity: 500,
},
BytesRateLimiter: ragep2p.TokenBucketParams{
- Rate: 100000.0,
- Capacity: 1000000,
+ Rate: 5000000.0, // 5 MB/s
+ Capacity: 10000000, // 10 MB
},
}
@@ -46,6 +51,42 @@ type launcher struct {
subServices []services.Service
}
+func unmarshalCapabilityConfig(data []byte) (capabilities.CapabilityConfiguration, error) {
+ cconf := &capabilitiespb.CapabilityConfig{}
+ err := proto.Unmarshal(data, cconf)
+ if err != nil {
+ return capabilities.CapabilityConfiguration{}, err
+ }
+
+ var remoteTriggerConfig *capabilities.RemoteTriggerConfig
+ var remoteTargetConfig *capabilities.RemoteTargetConfig
+
+ switch cconf.GetRemoteConfig().(type) {
+ case *capabilitiespb.CapabilityConfig_RemoteTriggerConfig:
+ prtc := cconf.GetRemoteTriggerConfig()
+ remoteTriggerConfig = &capabilities.RemoteTriggerConfig{}
+ remoteTriggerConfig.RegistrationRefresh = prtc.RegistrationRefresh.AsDuration()
+ remoteTriggerConfig.RegistrationExpiry = prtc.RegistrationExpiry.AsDuration()
+ remoteTriggerConfig.MinResponsesToAggregate = prtc.MinResponsesToAggregate
+ remoteTriggerConfig.MessageExpiry = prtc.MessageExpiry.AsDuration()
+ case *capabilitiespb.CapabilityConfig_RemoteTargetConfig:
+ prtc := cconf.GetRemoteTargetConfig()
+ remoteTargetConfig = &capabilities.RemoteTargetConfig{}
+ remoteTargetConfig.RequestHashExcludedAttributes = prtc.RequestHashExcludedAttributes
+ }
+
+ dc, err := values.FromMapValueProto(cconf.DefaultConfig)
+ if err != nil {
+ return capabilities.CapabilityConfiguration{}, err
+ }
+
+ return capabilities.CapabilityConfiguration{
+ DefaultConfig: dc,
+ RemoteTriggerConfig: remoteTriggerConfig,
+ RemoteTargetConfig: remoteTargetConfig,
+ }, nil
+}
+
func NewLauncher(
lggr logger.Logger,
peerWrapper p2ptypes.PeerWrapper,
@@ -90,6 +131,12 @@ func (w *launcher) Name() string {
func (w *launcher) Launch(ctx context.Context, state *registrysyncer.LocalRegistry) error {
w.registry.SetLocalRegistry(state)
+ allDONIDs := []registrysyncer.DonID{}
+ for id := range state.IDsToDONs {
+ allDONIDs = append(allDONIDs, id)
+ }
+ slices.Sort(allDONIDs) // ensure deterministic order
+
// Let's start by updating the list of Peers
// We do this by creating a new entry for each node belonging
// to a public DON.
@@ -97,7 +144,8 @@ func (w *launcher) Launch(ctx context.Context, state *registrysyncer.LocalRegist
allPeers := make(map[ragetypes.PeerID]p2ptypes.StreamConfig)
publicDONs := []registrysyncer.DON{}
- for _, d := range state.IDsToDONs {
+ for _, id := range allDONIDs {
+ d := state.IDsToDONs[id]
if !d.DON.IsPublic {
continue
}
@@ -127,7 +175,8 @@ func (w *launcher) Launch(ctx context.Context, state *registrysyncer.LocalRegist
myWorkflowDONs := []registrysyncer.DON{}
remoteWorkflowDONs := []registrysyncer.DON{}
myDONs := map[uint32]bool{}
- for _, d := range state.IDsToDONs {
+ for _, id := range allDONIDs {
+ d := state.IDsToDONs[id]
for _, peerID := range d.Members {
if peerID == myID {
myDONs[d.ID] = true
@@ -164,7 +213,7 @@ func (w *launcher) Launch(ctx context.Context, state *registrysyncer.LocalRegist
// NOTE: this is enforced on-chain and so should never happen.
if len(myWorkflowDONs) > 1 {
- w.lggr.Error("invariant violation: node is part of more than one workflowDON: this shouldn't happen.")
+ return errors.New("invariant violation: node is part of more than one workflowDON")
}
for _, rcd := range remoteCapabilityDONs {
@@ -196,6 +245,11 @@ func (w *launcher) addRemoteCapabilities(ctx context.Context, myDON registrysync
return fmt.Errorf("could not find capability matching id %s", cid)
}
+ capabilityConfig, err := unmarshalCapabilityConfig(c.Config)
+ if err != nil {
+ return fmt.Errorf("could not unmarshal capability config for id %s", cid)
+ }
+
switch capability.CapabilityType {
case capabilities.CapabilityTypeTrigger:
newTriggerFn := func(info capabilities.CapabilityInfo) (capabilityService, error) {
@@ -216,6 +270,7 @@ func (w *launcher) addRemoteCapabilities(ctx context.Context, myDON registrysync
int(remoteDON.F+1),
w.lggr,
)
+
// TODO: We need to implement a custom, Mercury-specific
// aggregator here, because there is no guarantee that
// all trigger events in the workflow will have the same
@@ -223,7 +278,7 @@ func (w *launcher) addRemoteCapabilities(ctx context.Context, myDON registrysync
// When this is solved, we can move to a generic aggregator
// and remove this.
triggerCap := remote.NewTriggerSubscriber(
- c.RemoteTriggerConfig,
+ capabilityConfig.RemoteTriggerConfig,
info,
remoteDON.DON,
myDON.DON,
@@ -332,11 +387,16 @@ func (w *launcher) exposeCapabilities(ctx context.Context, myPeerID p2ptypes.Pee
return fmt.Errorf("could not find capability matching id %s", cid)
}
+ capabilityConfig, err := unmarshalCapabilityConfig(c.Config)
+ if err != nil {
+ return fmt.Errorf("could not unmarshal capability config for id %s", cid)
+ }
+
switch capability.CapabilityType {
case capabilities.CapabilityTypeTrigger:
newTriggerPublisher := func(capability capabilities.BaseCapability, info capabilities.CapabilityInfo) (receiverService, error) {
publisher := remote.NewTriggerPublisher(
- c.RemoteTriggerConfig,
+ capabilityConfig.RemoteTriggerConfig,
capability.(capabilities.TriggerCapability),
info,
don.DON,
@@ -358,6 +418,7 @@ func (w *launcher) exposeCapabilities(ctx context.Context, myPeerID p2ptypes.Pee
case capabilities.CapabilityTypeTarget:
newTargetServer := func(capability capabilities.BaseCapability, info capabilities.CapabilityInfo) (receiverService, error) {
return target.NewServer(
+ capabilityConfig.RemoteTargetConfig,
myPeerID,
capability.(capabilities.TargetCapability),
info,
diff --git a/core/capabilities/launcher_test.go b/core/capabilities/launcher_test.go
index fb3e6837d00..8bca3be0db1 100644
--- a/core/capabilities/launcher_test.go
+++ b/core/capabilities/launcher_test.go
@@ -4,14 +4,18 @@ import (
"context"
"crypto/rand"
"testing"
+ "time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/types/known/durationpb"
ragetypes "github.com/smartcontractkit/libocr/ragep2p/types"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
+ capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote"
remoteMocks "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types/mocks"
@@ -121,7 +125,7 @@ func TestLauncher_WiresUpExternalCapabilities(t *testing.T) {
AcceptsWorkflows: true,
Members: nodes,
},
- CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
fullTriggerCapID: {},
fullTargetID: {},
},
@@ -223,7 +227,7 @@ func TestSyncer_IgnoresCapabilitiesForPrivateDON(t *testing.T) {
AcceptsWorkflows: true,
Members: nodes,
},
- CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
triggerID: {},
targetID: {},
},
@@ -323,9 +327,18 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDON(t *testing.T) {
// The below state describes a Workflow DON (AcceptsWorkflows = true),
// which exposes the streams-trigger and write_chain capabilities.
// We expect receivers to be wired up and both capabilities to be added to the registry.
- var rtc capabilities.RemoteTriggerConfig
+ rtc := &capabilities.RemoteTriggerConfig{}
rtc.ApplyDefaults()
+ cfg, err := proto.Marshal(&capabilitiespb.CapabilityConfig{
+ RemoteConfig: &capabilitiespb.CapabilityConfig_RemoteTriggerConfig{
+ RemoteTriggerConfig: &capabilitiespb.RemoteTriggerConfig{
+ RegistrationRefresh: durationpb.New(1 * time.Second),
+ },
+ },
+ })
+ require.NoError(t, err)
+
state := ®istrysyncer.LocalRegistry{
IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
registrysyncer.DonID(dID): {
@@ -347,12 +360,12 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDON(t *testing.T) {
AcceptsWorkflows: false,
Members: capabilityDonNodes,
},
- CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
fullTriggerCapID: {
- RemoteTriggerConfig: rtc,
+ Config: cfg,
},
fullTargetID: {
- RemoteTriggerConfig: rtc,
+ Config: cfg,
},
},
},
@@ -496,7 +509,7 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDONButIgnoresPrivateCapabilitie
AcceptsWorkflows: false,
Members: capabilityDonNodes,
},
- CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
fullTriggerCapID: {},
},
},
@@ -509,7 +522,7 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDONButIgnoresPrivateCapabilitie
AcceptsWorkflows: false,
Members: capabilityDonNodes,
},
- CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
fullTargetID: {},
},
},
@@ -653,7 +666,7 @@ func TestLauncher_SucceedsEvenIfDispatcherAlreadyHasReceiver(t *testing.T) {
AcceptsWorkflows: false,
Members: capabilityDonNodes,
},
- CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
fullTriggerCapID: {},
},
},
diff --git a/core/capabilities/registry.go b/core/capabilities/registry.go
index 8a99450c096..47285505805 100644
--- a/core/capabilities/registry.go
+++ b/core/capabilities/registry.go
@@ -8,6 +8,8 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink/v2/core/logger"
+ p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
)
var (
@@ -16,7 +18,7 @@ var (
type metadataRegistry interface {
LocalNode(ctx context.Context) (capabilities.Node, error)
- ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error)
+ ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error)
}
// Registry is a struct for the registry of capabilities.
@@ -37,11 +39,18 @@ func (r *Registry) LocalNode(ctx context.Context) (capabilities.Node, error) {
}
func (r *Registry) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) {
+ r.mu.RLock()
+ defer r.mu.RUnlock()
if r.metadataRegistry == nil {
return capabilities.CapabilityConfiguration{}, errors.New("metadataRegistry information not available")
}
- return r.metadataRegistry.ConfigForCapability(ctx, capabilityID, donID)
+ cfc, err := r.metadataRegistry.ConfigForCapability(ctx, capabilityID, donID)
+ if err != nil {
+ return capabilities.CapabilityConfiguration{}, err
+ }
+
+ return unmarshalCapabilityConfig(cfc.Config)
}
// SetLocalRegistry sets a local copy of the offchain registry for the registry to use.
@@ -191,3 +200,30 @@ func NewRegistry(lggr logger.Logger) *Registry {
lggr: lggr.Named("CapabilitiesRegistry"),
}
}
+
+// TestMetadataRegistry is a test implementation of the metadataRegistry
+// interface. It is used when ExternalCapabilitiesRegistry is not available.
+type TestMetadataRegistry struct{}
+
+func (t *TestMetadataRegistry) LocalNode(ctx context.Context) (capabilities.Node, error) {
+ peerID := p2ptypes.PeerID{}
+ workflowDON := capabilities.DON{
+ ID: 1,
+ ConfigVersion: 1,
+ Members: []p2ptypes.PeerID{
+ peerID,
+ },
+ F: 0,
+ IsPublic: false,
+ AcceptsWorkflows: true,
+ }
+ return capabilities.Node{
+ PeerID: &peerID,
+ WorkflowDON: workflowDON,
+ CapabilityDONs: []capabilities.DON{},
+ }, nil
+}
+
+func (t *TestMetadataRegistry) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error) {
+ return registrysyncer.CapabilityConfiguration{}, nil
+}
diff --git a/core/capabilities/remote/dispatcher.go b/core/capabilities/remote/dispatcher.go
index c1ee5db2944..bed485c286e 100644
--- a/core/capabilities/remote/dispatcher.go
+++ b/core/capabilities/remote/dispatcher.go
@@ -13,7 +13,6 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/types/core"
-
"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"
@@ -180,7 +179,7 @@ func (d *dispatcher) receive() {
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.lggr.Debugw("received message for unregistered capability", "capabilityId", SanitizeLogString(k.capId), "donId", k.donId)
d.tryRespondWithError(msg.Sender, body, types.Error_CAPABILITY_NOT_FOUND)
continue
}
diff --git a/core/capabilities/remote/message_cache.go b/core/capabilities/remote/message_cache.go
index 27f909c5165..f3a3a79b2c6 100644
--- a/core/capabilities/remote/message_cache.go
+++ b/core/capabilities/remote/message_cache.go
@@ -60,12 +60,12 @@ func (c *messageCache[EventID, PeerID]) Ready(eventID EventID, minCount uint32,
if msg.timestamp >= minTimestamp {
countAboveMinTimestamp++
accPayloads = append(accPayloads, msg.payload)
- if countAboveMinTimestamp >= minCount {
- ev.wasReady = true
- return true, accPayloads
- }
}
}
+ if countAboveMinTimestamp >= minCount {
+ ev.wasReady = true
+ return true, accPayloads
+ }
return false, nil
}
diff --git a/core/capabilities/remote/target/client.go b/core/capabilities/remote/target/client.go
index 5b65bf63e44..8572efed155 100644
--- a/core/capabilities/remote/target/client.go
+++ b/core/capabilities/remote/target/client.go
@@ -9,8 +9,10 @@ import (
commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/services"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/target/request"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/validation"
"github.com/smartcontractkit/chainlink/v2/core/logger"
)
@@ -151,7 +153,11 @@ func (c *client) Receive(ctx context.Context, msg *types.MessageBody) {
c.mutex.Lock()
defer c.mutex.Unlock()
- messageID := GetMessageID(msg)
+ messageID, err := GetMessageID(msg)
+ if err != nil {
+ c.lggr.Errorw("invalid message ID", "err", err, "id", remote.SanitizeLogString(string(msg.MessageId)))
+ return
+ }
c.lggr.Debugw("Remote client target receiving message", "messageID", messageID)
@@ -167,8 +173,12 @@ func (c *client) Receive(ctx context.Context, msg *types.MessageBody) {
}
func GetMessageIDForRequest(req commoncap.CapabilityRequest) (string, error) {
- if req.Metadata.WorkflowID == "" || req.Metadata.WorkflowExecutionID == "" {
- return "", errors.New("workflow ID and workflow execution ID must be set in request metadata")
+ if err := validation.ValidateWorkflowOrExecutionID(req.Metadata.WorkflowID); err != nil {
+ return "", fmt.Errorf("workflow ID is invalid: %w", err)
+ }
+
+ if err := validation.ValidateWorkflowOrExecutionID(req.Metadata.WorkflowExecutionID); err != nil {
+ return "", fmt.Errorf("workflow execution ID is invalid: %w", err)
}
return req.Metadata.WorkflowID + req.Metadata.WorkflowExecutionID, nil
diff --git a/core/capabilities/remote/target/client_test.go b/core/capabilities/remote/target/client_test.go
index 6d26b51b8ae..2198636a7a2 100644
--- a/core/capabilities/remote/target/client_test.go
+++ b/core/capabilities/remote/target/client_test.go
@@ -21,6 +21,11 @@ import (
p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
)
+const (
+ workflowID1 = "15c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0"
+ workflowExecutionID1 = "95ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0abbadeed"
+)
+
func Test_Client_DonTopologies(t *testing.T) {
ctx := testutils.Context(t)
@@ -192,8 +197,8 @@ func testClient(ctx context.Context, t *testing.T, numWorkflowPeers int, workflo
responseCh, err := caller.Execute(ctx,
commoncap.CapabilityRequest{
Metadata: commoncap.RequestMetadata{
- WorkflowID: "workflowID",
- WorkflowExecutionID: "workflowExecutionID",
+ WorkflowID: workflowID1,
+ WorkflowExecutionID: workflowExecutionID1,
},
Config: transmissionSchedule,
Inputs: executeInputs,
@@ -234,7 +239,10 @@ func (t *clientTestServer) Receive(_ context.Context, msg *remotetypes.MessageBo
defer t.mux.Unlock()
sender := toPeerID(msg.Sender)
- messageID := target.GetMessageID(msg)
+ messageID, err := target.GetMessageID(msg)
+ if err != nil {
+ panic(err)
+ }
if t.messageIDToSenders[messageID] == nil {
t.messageIDToSenders[messageID] = make(map[p2ptypes.PeerID]bool)
diff --git a/core/capabilities/remote/target/endtoend_test.go b/core/capabilities/remote/target/endtoend_test.go
index 9bbb53d4f66..31bdc83e266 100644
--- a/core/capabilities/remote/target/endtoend_test.go
+++ b/core/capabilities/remote/target/endtoend_test.go
@@ -226,7 +226,7 @@ func testRemoteTarget(ctx context.Context, t *testing.T, underlying commoncap.Ta
for i := 0; i < numCapabilityPeers; i++ {
capabilityPeer := capabilityPeers[i]
capabilityDispatcher := broker.NewDispatcherForNode(capabilityPeer)
- capabilityNode := target.NewServer(capabilityPeer, underlying, capInfo, capDonInfo, workflowDONs, capabilityDispatcher,
+ capabilityNode := target.NewServer(&commoncap.RemoteTargetConfig{RequestHashExcludedAttributes: []string{}}, capabilityPeer, underlying, capInfo, capDonInfo, workflowDONs, capabilityDispatcher,
capabilityNodeResponseTimeout, lggr)
servicetest.Run(t, capabilityNode)
broker.RegisterReceiverNode(capabilityPeer, capabilityNode)
@@ -261,8 +261,8 @@ func testRemoteTarget(ctx context.Context, t *testing.T, underlying commoncap.Ta
responseCh, err := caller.Execute(ctx,
commoncap.CapabilityRequest{
Metadata: commoncap.RequestMetadata{
- WorkflowID: "workflowID",
- WorkflowExecutionID: "workflowExecutionID",
+ WorkflowID: workflowID1,
+ WorkflowExecutionID: workflowExecutionID1,
},
Config: transmissionSchedule,
Inputs: executeInputs,
diff --git a/core/capabilities/remote/target/request/client_request.go b/core/capabilities/remote/target/request/client_request.go
index 50a742c2188..c9f76fb25af 100644
--- a/core/capabilities/remote/target/request/client_request.go
+++ b/core/capabilities/remote/target/request/client_request.go
@@ -140,7 +140,10 @@ func (c *ClientRequest) OnMessage(_ context.Context, msg *types.MessageBody) err
c.lggr.Debugw("OnMessage called for client request", "messageID", msg.MessageId)
- sender := remote.ToPeerID(msg.Sender)
+ sender, err := remote.ToPeerID(msg.Sender)
+ if err != nil {
+ return fmt.Errorf("failed to convert message sender to PeerID: %w", err)
+ }
received, expected := c.responseReceived[sender]
if !expected {
@@ -170,7 +173,7 @@ func (c *ClientRequest) OnMessage(_ context.Context, msg *types.MessageBody) err
}
}
} else {
- c.lggr.Warnw("received error response", "error", msg.ErrorMsg)
+ c.lggr.Warnw("received error response", "error", remote.SanitizeLogString(msg.ErrorMsg))
c.errorCount[msg.ErrorMsg]++
if c.errorCount[msg.ErrorMsg] == c.requiredIdenticalResponses {
c.sendResponse(commoncap.CapabilityResponse{Err: errors.New(msg.ErrorMsg)})
diff --git a/core/capabilities/remote/target/request/client_request_test.go b/core/capabilities/remote/target/request/client_request_test.go
index 07f43dbc71f..7edb2f5e534 100644
--- a/core/capabilities/remote/target/request/client_request_test.go
+++ b/core/capabilities/remote/target/request/client_request_test.go
@@ -20,6 +20,11 @@ import (
p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
)
+const (
+ workflowID1 = "15c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0"
+ workflowExecutionID1 = "95ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0abbadeed"
+)
+
func Test_ClientRequest_MessageValidation(t *testing.T) {
lggr := logger.TestLogger(t)
@@ -68,8 +73,8 @@ func Test_ClientRequest_MessageValidation(t *testing.T) {
capabilityRequest := commoncap.CapabilityRequest{
Metadata: commoncap.RequestMetadata{
- WorkflowID: "workflowID",
- WorkflowExecutionID: "workflowExecutionID",
+ WorkflowID: workflowID1,
+ WorkflowExecutionID: workflowExecutionID1,
},
Inputs: executeInputs,
Config: transmissionSchedule,
diff --git a/core/capabilities/remote/target/request/server_request.go b/core/capabilities/remote/target/request/server_request.go
index b8ae05bc316..4aaee118541 100644
--- a/core/capabilities/remote/target/request/server_request.go
+++ b/core/capabilities/remote/target/request/server_request.go
@@ -74,7 +74,11 @@ func (e *ServerRequest) OnMessage(ctx context.Context, msg *types.MessageBody) e
return fmt.Errorf("sender missing from message")
}
- requester := remote.ToPeerID(msg.Sender)
+ requester, err := remote.ToPeerID(msg.Sender)
+ if err != nil {
+ return fmt.Errorf("failed to convert message sender to PeerID: %w", err)
+ }
+
if err := e.addRequester(requester); err != nil {
return fmt.Errorf("failed to add requester to request: %w", err)
}
@@ -134,7 +138,7 @@ func (e *ServerRequest) executeRequest(ctx context.Context, payload []byte) erro
return fmt.Errorf("failed to marshal capability response: %w", err)
}
- e.lggr.Debugw("received execution results", "metadata", capabilityRequest.Metadata, "error", capResponse.Err)
+ e.lggr.Debugw("received execution results", "workflowExecutionID", capabilityRequest.Metadata.WorkflowExecutionID, "error", capResponse.Err)
e.setResult(responsePayload)
return nil
}
diff --git a/core/capabilities/remote/target/server.go b/core/capabilities/remote/target/server.go
index ea9caf81eff..5324475b192 100644
--- a/core/capabilities/remote/target/server.go
+++ b/core/capabilities/remote/target/server.go
@@ -4,13 +4,17 @@ import (
"context"
"crypto/sha256"
"encoding/hex"
+ "fmt"
"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"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/target/request"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/validation"
p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
"github.com/smartcontractkit/chainlink/v2/core/logger"
@@ -24,7 +28,9 @@ import (
// server communicates with corresponding client on remote nodes.
type server struct {
services.StateMachine
- lggr logger.Logger
+ lggr logger.Logger
+
+ config *commoncap.RemoteTargetConfig
peerID p2ptypes.PeerID
underlying commoncap.TargetCapability
capInfo commoncap.CapabilityInfo
@@ -51,9 +57,14 @@ type requestAndMsgID struct {
messageID string
}
-func NewServer(peerID p2ptypes.PeerID, underlying commoncap.TargetCapability, capInfo commoncap.CapabilityInfo, localDonInfo commoncap.DON,
+func NewServer(config *commoncap.RemoteTargetConfig, peerID p2ptypes.PeerID, underlying commoncap.TargetCapability, capInfo commoncap.CapabilityInfo, localDonInfo commoncap.DON,
workflowDONs map[uint32]commoncap.DON, dispatcher types.Dispatcher, requestTimeout time.Duration, lggr logger.Logger) *server {
+ if config == nil {
+ lggr.Info("no config provided, using default values")
+ config = &commoncap.RemoteTargetConfig{}
+ }
return &server{
+ config: config,
underlying: underlying,
peerID: peerID,
capInfo: capInfo,
@@ -120,17 +131,28 @@ func (r *server) Receive(ctx context.Context, msg *types.MessageBody) {
r.receiveLock.Lock()
defer r.receiveLock.Unlock()
- r.lggr.Debugw("received request for msg", "msgId", msg.MessageId)
if msg.Method != types.MethodExecute {
- r.lggr.Errorw("received request for unsupported method type", "method", msg.Method)
+ r.lggr.Errorw("received request for unsupported method type", "method", remote.SanitizeLogString(msg.Method))
+ return
+ }
+
+ messageId, err := GetMessageID(msg)
+ if err != nil {
+ r.lggr.Errorw("invalid message id", "err", err, "id", remote.SanitizeLogString(string(msg.MessageId)))
+ return
+ }
+
+ msgHash, err := r.getMessageHash(msg)
+ if err != nil {
+ r.lggr.Errorw("failed to get message hash", "err", err)
return
}
// A request is uniquely identified by the message id and the hash of the payload to prevent a malicious
// actor from sending a different payload with the same message id
- messageId := GetMessageID(msg)
- hash := sha256.Sum256(msg.Payload)
- requestID := messageId + hex.EncodeToString(hash[:])
+ requestID := messageId + hex.EncodeToString(msgHash[:])
+
+ r.lggr.Debugw("received request", "msgId", msg.MessageId, "requestID", requestID)
if requestIDs, ok := r.messageIDToRequestIDsCount[messageId]; ok {
requestIDs[requestID] = requestIDs[requestID] + 1
@@ -142,7 +164,7 @@ func (r *server) Receive(ctx context.Context, msg *types.MessageBody) {
if len(requestIDs) > 1 {
// This is a potential attack vector as well as a situation that will occur if the client is sending non-deterministic payloads
// so a warning is logged
- r.lggr.Warnw("received messages with the same id and different payloads", "messageID", messageId, "requestIDToCount", requestIDs)
+ r.lggr.Warnw("received messages with the same id and different payloads", "messageID", messageId, "lenRequestIDs", len(requestIDs))
}
if _, ok := r.requestIDToRequest[requestID]; !ok {
@@ -161,14 +183,38 @@ func (r *server) Receive(ctx context.Context, msg *types.MessageBody) {
reqAndMsgID := r.requestIDToRequest[requestID]
- err := reqAndMsgID.request.OnMessage(ctx, msg)
+ err = reqAndMsgID.request.OnMessage(ctx, msg)
if err != nil {
- r.lggr.Errorw("request failed to OnMessage new message", "request", reqAndMsgID, "err", err)
+ r.lggr.Errorw("request failed to OnMessage new message", "messageID", reqAndMsgID.messageID, "err", err)
}
}
-func GetMessageID(msg *types.MessageBody) string {
- return string(msg.MessageId)
+func (r *server) getMessageHash(msg *types.MessageBody) ([32]byte, error) {
+ req, err := pb.UnmarshalCapabilityRequest(msg.Payload)
+ if err != nil {
+ return [32]byte{}, fmt.Errorf("failed to unmarshal capability request: %w", err)
+ }
+
+ for _, path := range r.config.RequestHashExcludedAttributes {
+ if !req.Inputs.DeleteAtPath(path) {
+ return [32]byte{}, fmt.Errorf("failed to delete attribute from map at path: %s", path)
+ }
+ }
+
+ reqBytes, err := pb.MarshalCapabilityRequest(req)
+ if err != nil {
+ return [32]byte{}, fmt.Errorf("failed to marshal capability request: %w", err)
+ }
+ hash := sha256.Sum256(reqBytes)
+ return hash, nil
+}
+
+func GetMessageID(msg *types.MessageBody) (string, error) {
+ idStr := string(msg.MessageId)
+ if !validation.IsValidID(idStr) {
+ return "", fmt.Errorf("invalid message id")
+ }
+ return idStr, nil
}
func (r *server) Ready() error {
diff --git a/core/capabilities/remote/target/server_test.go b/core/capabilities/remote/target/server_test.go
index a5aa45efd06..505a2dcce5d 100644
--- a/core/capabilities/remote/target/server_test.go
+++ b/core/capabilities/remote/target/server_test.go
@@ -2,6 +2,7 @@ package target_test
import (
"context"
+ "strconv"
"testing"
"time"
@@ -11,6 +12,7 @@ import (
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-common/pkg/values"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/target"
remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
@@ -18,19 +20,55 @@ import (
p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
)
+func Test_Server_ExcludesNonDeterministicInputAttributes(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ numCapabilityPeers := 4
+
+ callers, srvcs := testRemoteTargetServer(ctx, t, &commoncap.RemoteTargetConfig{RequestHashExcludedAttributes: []string{"signed_report.Signatures"}},
+ &TestCapability{}, 10, 9, numCapabilityPeers, 3, 10*time.Minute)
+
+ for idx, caller := range callers {
+ rawInputs := map[string]any{
+ "signed_report": map[string]any{"Signatures": "sig" + strconv.Itoa(idx), "Price": 20},
+ }
+
+ inputs, err := values.NewMap(rawInputs)
+ require.NoError(t, err)
+
+ _, err = caller.Execute(context.Background(),
+ commoncap.CapabilityRequest{
+ Metadata: commoncap.RequestMetadata{
+ WorkflowID: workflowID1,
+ WorkflowExecutionID: workflowExecutionID1,
+ },
+ Inputs: inputs,
+ })
+ require.NoError(t, err)
+ }
+
+ for _, caller := range callers {
+ for i := 0; i < numCapabilityPeers; i++ {
+ msg := <-caller.receivedMessages
+ assert.Equal(t, remotetypes.Error_OK, msg.Error)
+ }
+ }
+ closeServices(t, srvcs)
+}
+
func Test_Server_RespondsAfterSufficientRequests(t *testing.T) {
ctx := testutils.Context(t)
numCapabilityPeers := 4
- callers, srvcs := testRemoteTargetServer(ctx, t, &TestCapability{}, 10, 9, numCapabilityPeers, 3, 10*time.Minute)
+ callers, srvcs := testRemoteTargetServer(ctx, t, &commoncap.RemoteTargetConfig{}, &TestCapability{}, 10, 9, numCapabilityPeers, 3, 10*time.Minute)
for _, caller := range callers {
_, err := caller.Execute(context.Background(),
commoncap.CapabilityRequest{
Metadata: commoncap.RequestMetadata{
- WorkflowID: "workflowID",
- WorkflowExecutionID: "workflowExecutionID",
+ WorkflowID: workflowID1,
+ WorkflowExecutionID: workflowExecutionID1,
},
})
require.NoError(t, err)
@@ -50,14 +88,14 @@ func Test_Server_InsufficientCallers(t *testing.T) {
numCapabilityPeers := 4
- callers, srvcs := testRemoteTargetServer(ctx, t, &TestCapability{}, 10, 10, numCapabilityPeers, 3, 100*time.Millisecond)
+ callers, srvcs := testRemoteTargetServer(ctx, t, &commoncap.RemoteTargetConfig{}, &TestCapability{}, 10, 10, numCapabilityPeers, 3, 100*time.Millisecond)
for _, caller := range callers {
_, err := caller.Execute(context.Background(),
commoncap.CapabilityRequest{
Metadata: commoncap.RequestMetadata{
- WorkflowID: "workflowID",
- WorkflowExecutionID: "workflowExecutionID",
+ WorkflowID: workflowID1,
+ WorkflowExecutionID: workflowExecutionID1,
},
})
require.NoError(t, err)
@@ -77,14 +115,14 @@ func Test_Server_CapabilityError(t *testing.T) {
numCapabilityPeers := 4
- callers, srvcs := testRemoteTargetServer(ctx, t, &TestErrorCapability{}, 10, 9, numCapabilityPeers, 3, 100*time.Millisecond)
+ callers, srvcs := testRemoteTargetServer(ctx, t, &commoncap.RemoteTargetConfig{}, &TestErrorCapability{}, 10, 9, numCapabilityPeers, 3, 100*time.Millisecond)
for _, caller := range callers {
_, err := caller.Execute(context.Background(),
commoncap.CapabilityRequest{
Metadata: commoncap.RequestMetadata{
- WorkflowID: "workflowID",
- WorkflowExecutionID: "workflowExecutionID",
+ WorkflowID: workflowID1,
+ WorkflowExecutionID: workflowExecutionID1,
},
})
require.NoError(t, err)
@@ -100,6 +138,7 @@ func Test_Server_CapabilityError(t *testing.T) {
}
func testRemoteTargetServer(ctx context.Context, t *testing.T,
+ config *commoncap.RemoteTargetConfig,
underlying commoncap.TargetCapability,
numWorkflowPeers int, workflowDonF uint8,
numCapabilityPeers int, capabilityDonF uint8, capabilityNodeResponseTimeout time.Duration) ([]*serverTestClient, []services.Service) {
@@ -150,7 +189,7 @@ func testRemoteTargetServer(ctx context.Context, t *testing.T,
for i := 0; i < numCapabilityPeers; i++ {
capabilityPeer := capabilityPeers[i]
capabilityDispatcher := broker.NewDispatcherForNode(capabilityPeer)
- capabilityNode := target.NewServer(capabilityPeer, underlying, capInfo, capDonInfo, workflowDONs, capabilityDispatcher,
+ capabilityNode := target.NewServer(config, capabilityPeer, underlying, capInfo, capDonInfo, workflowDONs, capabilityDispatcher,
capabilityNodeResponseTimeout, lggr)
require.NoError(t, capabilityNode.Start(ctx))
broker.RegisterReceiverNode(capabilityPeer, capabilityNode)
diff --git a/core/capabilities/remote/trigger_publisher.go b/core/capabilities/remote/trigger_publisher.go
index 35ce41118f5..ad0b9b27c67 100644
--- a/core/capabilities/remote/trigger_publisher.go
+++ b/core/capabilities/remote/trigger_publisher.go
@@ -10,6 +10,7 @@ import (
"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/capabilities/validation"
"github.com/smartcontractkit/chainlink/v2/core/logger"
p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
)
@@ -21,11 +22,12 @@ import (
//
// TriggerPublisher communicates with corresponding TriggerSubscribers on remote nodes.
type triggerPublisher struct {
- config capabilities.RemoteTriggerConfig
+ config *capabilities.RemoteTriggerConfig
underlying commoncap.TriggerCapability
capInfo commoncap.CapabilityInfo
capDonInfo commoncap.DON
workflowDONs map[uint32]commoncap.DON
+ membersCache map[uint32]map[p2ptypes.PeerID]bool
dispatcher types.Dispatcher
messageCache *messageCache[registrationKey, p2ptypes.PeerID]
registrations map[registrationKey]*pubRegState
@@ -48,14 +50,27 @@ type pubRegState struct {
var _ types.Receiver = &triggerPublisher{}
var _ services.Service = &triggerPublisher{}
-func NewTriggerPublisher(config capabilities.RemoteTriggerConfig, underlying commoncap.TriggerCapability, capInfo commoncap.CapabilityInfo, capDonInfo commoncap.DON, workflowDONs map[uint32]commoncap.DON, dispatcher types.Dispatcher, lggr logger.Logger) *triggerPublisher {
+func NewTriggerPublisher(config *capabilities.RemoteTriggerConfig, underlying commoncap.TriggerCapability, capInfo commoncap.CapabilityInfo, capDonInfo commoncap.DON, workflowDONs map[uint32]commoncap.DON, dispatcher types.Dispatcher, lggr logger.Logger) *triggerPublisher {
+ if config == nil {
+ lggr.Info("no config provided, using default values")
+ config = &capabilities.RemoteTriggerConfig{}
+ }
config.ApplyDefaults()
+ membersCache := make(map[uint32]map[p2ptypes.PeerID]bool)
+ for id, don := range workflowDONs {
+ cache := make(map[p2ptypes.PeerID]bool)
+ for _, member := range don.Members {
+ cache[member] = true
+ }
+ membersCache[id] = cache
+ }
return &triggerPublisher{
config: config,
underlying: underlying,
capInfo: capInfo,
capDonInfo: capDonInfo,
workflowDONs: workflowDONs,
+ membersCache: membersCache,
dispatcher: dispatcher,
messageCache: NewMessageCache[registrationKey, p2ptypes.PeerID](),
registrations: make(map[registrationKey]*pubRegState),
@@ -72,7 +87,12 @@ func (p *triggerPublisher) Start(ctx context.Context) error {
}
func (p *triggerPublisher) Receive(_ context.Context, msg *types.MessageBody) {
- sender := ToPeerID(msg.Sender)
+ sender, err := ToPeerID(msg.Sender)
+ if err != nil {
+ p.lggr.Errorw("failed to convert message sender to PeerID", "err", err)
+ return
+ }
+
if msg.Method == types.MethodRegisterTrigger {
req, err := pb.UnmarshalCapabilityRequest(msg.Payload)
if err != nil {
@@ -84,6 +104,14 @@ func (p *triggerPublisher) Receive(_ context.Context, msg *types.MessageBody) {
p.lggr.Errorw("received a message from unsupported workflow DON", "capabilityId", p.capInfo.ID, "callerDonId", msg.CallerDonId)
return
}
+ if !p.membersCache[msg.CallerDonId][sender] {
+ p.lggr.Errorw("sender not a member of its workflow DON", "capabilityId", p.capInfo.ID, "callerDonId", msg.CallerDonId, "sender", sender)
+ return
+ }
+ if err = validation.ValidateWorkflowOrExecutionID(req.Metadata.WorkflowID); err != nil {
+ p.lggr.Errorw("received trigger request with invalid workflow ID", "capabilityId", p.capInfo.ID, "workflowId", SanitizeLogString(req.Metadata.WorkflowID), "err", err)
+ 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()
@@ -127,7 +155,7 @@ func (p *triggerPublisher) Receive(_ context.Context, msg *types.MessageBody) {
p.lggr.Errorw("failed to register trigger", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "err", err)
}
} else {
- p.lggr.Errorw("received trigger request with unknown method", "method", msg.Method, "sender", sender)
+ p.lggr.Errorw("received trigger request with unknown method", "method", SanitizeLogString(msg.Method), "sender", sender)
}
}
@@ -141,7 +169,7 @@ func (p *triggerPublisher) registrationCleanupLoop() {
return
case <-ticker.C:
now := time.Now().UnixMilli()
- p.mu.RLock()
+ p.mu.Lock()
for key, req := range p.registrations {
callerDon := p.workflowDONs[key.callerDonId]
ready, _ := p.messageCache.Ready(key, uint32(2*callerDon.F+1), now-p.config.RegistrationExpiry.Milliseconds(), false)
@@ -156,7 +184,7 @@ func (p *triggerPublisher) registrationCleanupLoop() {
p.messageCache.Delete(key)
}
}
- p.mu.RUnlock()
+ p.mu.Unlock()
}
}
}
diff --git a/core/capabilities/remote/trigger_publisher_test.go b/core/capabilities/remote/trigger_publisher_test.go
index 1e3000d20ca..32de37a95aa 100644
--- a/core/capabilities/remote/trigger_publisher_test.go
+++ b/core/capabilities/remote/trigger_publisher_test.go
@@ -7,7 +7,6 @@ import (
"github.com/stretchr/testify/require"
- "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote"
@@ -42,7 +41,7 @@ func TestTriggerPublisher_Register(t *testing.T) {
}
dispatcher := remoteMocks.NewDispatcher(t)
- config := capabilities.RemoteTriggerConfig{
+ config := &commoncap.RemoteTriggerConfig{
RegistrationRefresh: 100 * time.Millisecond,
RegistrationExpiry: 100 * time.Second,
MinResponsesToAggregate: 1,
@@ -73,6 +72,12 @@ func TestTriggerPublisher_Register(t *testing.T) {
Payload: marshaled,
}
publisher.Receive(ctx, regEvent)
+ // node p1 is not a member of the workflow DON so registration shoudn't happen
+ require.Empty(t, underlying.registrationsCh)
+
+ regEvent.Sender = p2[:]
+ publisher.Receive(ctx, regEvent)
+ require.NotEmpty(t, underlying.registrationsCh)
forwarded := <-underlying.registrationsCh
require.Equal(t, capRequest.Metadata.WorkflowID, forwarded.Metadata.WorkflowID)
diff --git a/core/capabilities/remote/trigger_subscriber.go b/core/capabilities/remote/trigger_subscriber.go
index 0ccbf37c61a..f880735f4f4 100644
--- a/core/capabilities/remote/trigger_subscriber.go
+++ b/core/capabilities/remote/trigger_subscriber.go
@@ -6,7 +6,6 @@ import (
sync "sync"
"time"
- "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink-common/pkg/services"
@@ -23,11 +22,11 @@ import (
//
// TriggerSubscriber communicates with corresponding TriggerReceivers on remote nodes.
type triggerSubscriber struct {
- config capabilities.RemoteTriggerConfig
+ config *commoncap.RemoteTriggerConfig
capInfo commoncap.CapabilityInfo
- capDonInfo capabilities.DON
+ capDonInfo commoncap.DON
capDonMembers map[p2ptypes.PeerID]struct{}
- localDonInfo capabilities.DON
+ localDonInfo commoncap.DON
dispatcher types.Dispatcher
aggregator types.Aggregator
messageCache *messageCache[triggerEventKey, p2ptypes.PeerID]
@@ -53,13 +52,20 @@ var _ types.Receiver = &triggerSubscriber{}
var _ services.Service = &triggerSubscriber{}
// TODO makes this configurable with a default
-const defaultSendChannelBufferSize = 1000
+const (
+ defaultSendChannelBufferSize = 1000
+ maxBatchedWorkflowIDs = 1000
+)
-func NewTriggerSubscriber(config capabilities.RemoteTriggerConfig, capInfo commoncap.CapabilityInfo, capDonInfo capabilities.DON, localDonInfo capabilities.DON, dispatcher types.Dispatcher, aggregator types.Aggregator, lggr logger.Logger) *triggerSubscriber {
+func NewTriggerSubscriber(config *commoncap.RemoteTriggerConfig, capInfo commoncap.CapabilityInfo, capDonInfo commoncap.DON, localDonInfo commoncap.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))
}
+ if config == nil {
+ lggr.Info("no config provided, using default values")
+ config = &commoncap.RemoteTriggerConfig{}
+ }
config.ApplyDefaults()
capDonMembers := make(map[p2ptypes.PeerID]struct{})
for _, member := range capDonInfo.Members {
@@ -169,7 +175,12 @@ func (s *triggerSubscriber) UnregisterTrigger(ctx context.Context, request commo
}
func (s *triggerSubscriber) Receive(_ context.Context, msg *types.MessageBody) {
- sender := ToPeerID(msg.Sender)
+ sender, err := ToPeerID(msg.Sender)
+ if err != nil {
+ s.lggr.Errorw("failed to convert message sender to PeerID", "err", err)
+ return
+ }
+
if _, found := s.capDonMembers[sender]; !found {
s.lggr.Errorw("received message from unexpected node", "capabilityId", s.capInfo.ID, "sender", sender)
return
@@ -180,12 +191,16 @@ func (s *triggerSubscriber) Receive(_ context.Context, msg *types.MessageBody) {
s.lggr.Errorw("received message with invalid trigger metadata", "capabilityId", s.capInfo.ID, "sender", sender)
return
}
+ if len(meta.WorkflowIds) > maxBatchedWorkflowIDs {
+ s.lggr.Errorw("received message with too many workflow IDs - truncating", "capabilityId", s.capInfo.ID, "nWorkflows", len(meta.WorkflowIds), "sender", sender)
+ meta.WorkflowIds = meta.WorkflowIds[:maxBatchedWorkflowIDs]
+ }
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)
+ s.lggr.Errorw("received message for unregistered workflow", "capabilityId", s.capInfo.ID, "workflowID", SanitizeLogString(workflowId), "sender", sender)
continue
}
key := triggerEventKey{
@@ -193,10 +208,10 @@ func (s *triggerSubscriber) Receive(_ context.Context, msg *types.MessageBody) {
workflowId: workflowId,
}
nowMs := time.Now().UnixMilli()
- s.mu.RLock()
+ s.mu.Lock()
creationTs := s.messageCache.Insert(key, sender, nowMs, msg.Payload)
ready, payloads := s.messageCache.Ready(key, s.config.MinResponsesToAggregate, nowMs-s.config.MessageExpiry.Milliseconds(), true)
- s.mu.RUnlock()
+ s.mu.Unlock()
if nowMs-creationTs > s.config.RegistrationExpiry.Milliseconds() {
s.lggr.Warnw("received trigger event for an expired ID", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId, "sender", sender)
continue
@@ -213,7 +228,7 @@ func (s *triggerSubscriber) Receive(_ context.Context, msg *types.MessageBody) {
}
}
} else {
- s.lggr.Errorw("received trigger event with unknown method", "method", msg.Method, "sender", sender)
+ s.lggr.Errorw("received trigger event with unknown method", "method", SanitizeLogString(msg.Method), "sender", sender)
}
}
diff --git a/core/capabilities/remote/trigger_subscriber_test.go b/core/capabilities/remote/trigger_subscriber_test.go
index 93e962215ab..c834a271d56 100644
--- a/core/capabilities/remote/trigger_subscriber_test.go
+++ b/core/capabilities/remote/trigger_subscriber_test.go
@@ -7,7 +7,6 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
- "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink-common/pkg/values"
@@ -22,7 +21,7 @@ import (
const (
peerID1 = "12D3KooWF3dVeJ6YoT5HFnYhmwQWWMoEwVFzJQ5kKCMX3ZityxMC"
peerID2 = "12D3KooWQsmok6aD8PZqt3RnJhQRrNzKHLficq7zYFRp7kZ1hHP8"
- workflowID1 = "workflowID1"
+ workflowID1 = "15c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0"
)
var (
@@ -63,7 +62,7 @@ func TestTriggerSubscriber_RegisterAndReceive(t *testing.T) {
})
// register trigger
- config := capabilities.RemoteTriggerConfig{
+ config := &commoncap.RemoteTriggerConfig{
RegistrationRefresh: 100 * time.Millisecond,
RegistrationExpiry: 100 * time.Second,
MinResponsesToAggregate: 1,
diff --git a/core/capabilities/remote/utils.go b/core/capabilities/remote/utils.go
index dba24b843cc..a1fe4dcb840 100644
--- a/core/capabilities/remote/utils.go
+++ b/core/capabilities/remote/utils.go
@@ -7,6 +7,7 @@ import (
"encoding/hex"
"errors"
"fmt"
+ "unicode"
"google.golang.org/protobuf/proto"
@@ -16,6 +17,10 @@ import (
p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
)
+const (
+ maxLoggedStringLen = 256
+)
+
func ValidateMessage(msg p2ptypes.Message, expectedReceiver p2ptypes.PeerID) (*remotetypes.MessageBody, error) {
var topLevelMessage remotetypes.Message
err := proto.Unmarshal(msg.Payload, &topLevelMessage)
@@ -43,10 +48,14 @@ func ValidateMessage(msg p2ptypes.Message, expectedReceiver p2ptypes.PeerID) (*r
return &body, nil
}
-func ToPeerID(peerID []byte) p2ptypes.PeerID {
+func ToPeerID(peerID []byte) (p2ptypes.PeerID, error) {
+ if len(peerID) != p2ptypes.PeerIDLength {
+ return p2ptypes.PeerID{}, fmt.Errorf("invalid peer ID length: %d", len(peerID))
+ }
+
var id p2ptypes.PeerID
copy(id[:], peerID)
- return id
+ return id, nil
}
// Default MODE Aggregator needs a configurable number of identical responses for aggregation to succeed
@@ -85,7 +94,8 @@ func AggregateModeRaw(elemList [][]byte, minIdenticalResponses uint32) ([]byte,
hashToCount[sha]++
if hashToCount[sha] >= minIdenticalResponses {
found = elem
- break
+ // update in case we find another elem with an even higher count
+ minIdenticalResponses = hashToCount[sha]
}
}
if found == nil {
@@ -93,3 +103,17 @@ func AggregateModeRaw(elemList [][]byte, minIdenticalResponses uint32) ([]byte,
}
return found, nil
}
+
+func SanitizeLogString(s string) string {
+ tooLongSuffix := ""
+ if len(s) > maxLoggedStringLen {
+ s = s[:maxLoggedStringLen]
+ tooLongSuffix = " [TRUNCATED]"
+ }
+ for i := 0; i < len(s); i++ {
+ if !unicode.IsPrint(rune(s[i])) {
+ return "[UNPRINTABLE] " + hex.EncodeToString([]byte(s)) + tooLongSuffix
+ }
+ }
+ return s + tooLongSuffix
+}
diff --git a/core/capabilities/remote/utils_test.go b/core/capabilities/remote/utils_test.go
index 8bebf71fb66..4a38a226e5b 100644
--- a/core/capabilities/remote/utils_test.go
+++ b/core/capabilities/remote/utils_test.go
@@ -84,7 +84,8 @@ func encodeAndSign(t *testing.T, senderPrivKey ed25519.PrivateKey, senderId p2pt
}
func TestToPeerID(t *testing.T) {
- id := remote.ToPeerID([]byte("12345678901234567890123456789012"))
+ id, err := remote.ToPeerID([]byte("12345678901234567890123456789012"))
+ require.NoError(t, err)
require.Equal(t, "12D3KooWD8QYTQVYjB6oog4Ej8PcPpqTrPRnxLQap8yY8KUQRVvq", id.String())
}
@@ -118,3 +119,14 @@ func TestDefaultModeAggregator_Aggregate(t *testing.T) {
require.NoError(t, err)
require.Equal(t, res, capResponse1)
}
+
+func TestSanitizeLogString(t *testing.T) {
+ require.Equal(t, "hello", remote.SanitizeLogString("hello"))
+ require.Equal(t, "[UNPRINTABLE] 0a", remote.SanitizeLogString("\n"))
+
+ longString := ""
+ for i := 0; i < 100; i++ {
+ longString += "aa-aa-aa-"
+ }
+ require.Equal(t, longString[:256]+" [TRUNCATED]", remote.SanitizeLogString(longString))
+}
diff --git a/core/capabilities/streams/codec.go b/core/capabilities/streams/codec.go
index d2bc451a39f..26011cb7f35 100644
--- a/core/capabilities/streams/codec.go
+++ b/core/capabilities/streams/codec.go
@@ -1,6 +1,7 @@
package streams
import (
+ "encoding/hex"
"fmt"
"github.com/ethereum/go-ethereum/common"
@@ -34,6 +35,9 @@ func (c *codec) Unwrap(wrapped values.Value) ([]datastreams.FeedReport, error) {
if err2 != nil {
return nil, fmt.Errorf("failed to decode: %v", err2)
}
+ if decoded.FeedId != id.Bytes() {
+ return nil, fmt.Errorf("feed ID mismatch: FeedID: %s, FullReport.FeedId: %s", id, hex.EncodeToString(decoded.FeedId[:]))
+ }
dest[i].BenchmarkPrice = decoded.BenchmarkPrice.Bytes()
dest[i].ObservationTimestamp = int64(decoded.ObservationsTimestamp)
}
diff --git a/core/capabilities/streams/codec_test.go b/core/capabilities/streams/codec_test.go
index e3ada731e43..02ec474fec9 100644
--- a/core/capabilities/streams/codec_test.go
+++ b/core/capabilities/streams/codec_test.go
@@ -69,7 +69,7 @@ func TestCodec_WrapUnwrap(t *testing.T) {
_, err = codec.Unwrap(values.NewBool(true))
require.Error(t, err)
- // correct reports byt wrong signatures
+ // correct reports but wrong signatures
unwrapped, err := codec.Unwrap(wrapped)
require.NoError(t, err)
require.Equal(t, 2, len(unwrapped))
@@ -85,6 +85,20 @@ func TestCodec_WrapUnwrap(t *testing.T) {
for _, report := range unwrapped {
require.NoError(t, codec.Validate(report, allowedSigners, 2))
}
+
+ // invalid FeedID
+ wrappedInvalid, err := codec.Wrap([]datastreams.FeedReport{
+ {
+ FeedID: id2Str, // ID #2 doesn't match what's in report #1
+ FullReport: report1,
+ ReportContext: rawCtx,
+ Signatures: [][]byte{signatureK1R1, signatureK2R1},
+ },
+ })
+ require.NoError(t, err)
+ _, err = codec.Unwrap(wrappedInvalid)
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "feed ID mismatch")
}
func newFeedID(t *testing.T) ([32]byte, string) {
diff --git a/core/capabilities/streams/trigger_test.go b/core/capabilities/streams/trigger_test.go
index cb4cfaa36bc..853f07f2aae 100644
--- a/core/capabilities/streams/trigger_test.go
+++ b/core/capabilities/streams/trigger_test.go
@@ -87,7 +87,7 @@ func TestStreamsTrigger(t *testing.T) {
Members: capMembers,
F: uint8(F),
}
- config := capabilities.RemoteTriggerConfig{
+ config := &capabilities.RemoteTriggerConfig{
MinResponsesToAggregate: uint32(F + 1),
}
subscriber := remote.NewTriggerSubscriber(config, capInfo, capDonInfo, capabilities.DON{}, nil, agg, lggr)
diff --git a/core/capabilities/targets/write_target.go b/core/capabilities/targets/write_target.go
index 330f15872d6..da9841948d5 100644
--- a/core/capabilities/targets/write_target.go
+++ b/core/capabilities/targets/write_target.go
@@ -1,7 +1,9 @@
package targets
import (
+ "bytes"
"context"
+ "encoding/binary"
"encoding/hex"
"fmt"
"math/big"
@@ -11,23 +13,21 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
- "github.com/smartcontractkit/chainlink-common/pkg/values"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
)
var (
_ capabilities.ActionCapability = &WriteTarget{}
)
-// required field of target's config in the workflow spec
-const signedReportField = "signed_report"
-
type WriteTarget struct {
cr commontypes.ContractReader
cw commontypes.ChainWriter
forwarderAddress string
+ // The minimum amount of gas that the receiver contract must get to process the forwarder report
+ receiverGasMinimum uint64
capabilities.CapabilityInfo
lggr logger.Logger
@@ -35,37 +35,137 @@ type WriteTarget struct {
bound bool
}
-func NewWriteTarget(lggr logger.Logger, id string, cr commontypes.ContractReader, cw commontypes.ChainWriter, forwarderAddress string) *WriteTarget {
+type TransmissionInfo struct {
+ GasLimit *big.Int
+ InvalidReceiver bool
+ State uint8
+ Success bool
+ TransmissionId [32]byte
+ Transmitter common.Address
+}
+
+// The gas cost of the forwarder contract logic, including state updates and event emission.
+// This is a rough estimate and should be updated if the forwarder contract logic changes.
+// TODO: Make this part of the on-chain capability configuration
+const FORWARDER_CONTRACT_LOGIC_GAS_COST = 100_000
+
+func NewWriteTarget(lggr logger.Logger, id string, cr commontypes.ContractReader, cw commontypes.ChainWriter, forwarderAddress string, txGasLimit uint64) *WriteTarget {
info := capabilities.MustNewCapabilityInfo(
id,
capabilities.CapabilityTypeTarget,
"Write target.",
)
- logger := lggr.Named("WriteTarget")
-
return &WriteTarget{
cr,
cw,
forwarderAddress,
+ txGasLimit - FORWARDER_CONTRACT_LOGIC_GAS_COST,
info,
- logger,
+ logger.Named(lggr, "WriteTarget"),
false,
}
}
-type EvmConfig struct {
+// Note: This should be a shared type that the OCR3 package validates as well
+type ReportV1Metadata struct {
+ Version uint8
+ WorkflowExecutionID [32]byte
+ Timestamp uint32
+ DonID uint32
+ DonConfigVersion uint32
+ WorkflowCID [32]byte
+ WorkflowName [10]byte
+ WorkflowOwner [20]byte
+ ReportID [2]byte
+}
+
+func (rm ReportV1Metadata) Encode() ([]byte, error) {
+ buf := new(bytes.Buffer)
+ err := binary.Write(buf, binary.BigEndian, rm)
+ if err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
+
+func (rm ReportV1Metadata) Length() int {
+ bytes, err := rm.Encode()
+ if err != nil {
+ return 0
+ }
+ return len(bytes)
+}
+
+func decodeReportMetadata(data []byte) (metadata ReportV1Metadata, err error) {
+ if len(data) < metadata.Length() {
+ return metadata, fmt.Errorf("data too short: %d bytes", len(data))
+ }
+ return metadata, binary.Read(bytes.NewReader(data[:metadata.Length()]), binary.BigEndian, &metadata)
+}
+
+type Config struct {
+ // Address of the contract that will get the forwarded report
Address string
}
-func parseConfig(rawConfig *values.Map) (config EvmConfig, err error) {
- if err := rawConfig.UnwrapTo(&config); err != nil {
- return config, err
+type Inputs struct {
+ SignedReport types.SignedReport
+}
+
+type Request struct {
+ Metadata capabilities.RequestMetadata
+ Config Config
+ Inputs Inputs
+}
+
+func evaluate(rawRequest capabilities.CapabilityRequest) (r Request, err error) {
+ r.Metadata = rawRequest.Metadata
+
+ if rawRequest.Config == nil {
+ return r, fmt.Errorf("missing config field")
}
- if !common.IsHexAddress(config.Address) {
- return config, fmt.Errorf("'%v' is not a valid address", config.Address)
+
+ if err = rawRequest.Config.UnwrapTo(&r.Config); err != nil {
+ return r, err
}
- return config, nil
+
+ if !common.IsHexAddress(r.Config.Address) {
+ return r, fmt.Errorf("'%v' is not a valid address", r.Config.Address)
+ }
+
+ if rawRequest.Inputs == nil {
+ return r, fmt.Errorf("missing inputs field")
+ }
+
+ // required field of target's config in the workflow spec
+ const signedReportField = "signed_report"
+ signedReport, ok := rawRequest.Inputs.Underlying[signedReportField]
+ if !ok {
+ return r, fmt.Errorf("missing required field %s", signedReportField)
+ }
+
+ if err = signedReport.UnwrapTo(&r.Inputs.SignedReport); err != nil {
+ return r, err
+ }
+
+ reportMetadata, err := decodeReportMetadata(r.Inputs.SignedReport.Report)
+ if err != nil {
+ return r, err
+ }
+
+ if reportMetadata.Version != 1 {
+ return r, fmt.Errorf("unsupported report version: %d", reportMetadata.Version)
+ }
+
+ if hex.EncodeToString(reportMetadata.WorkflowExecutionID[:]) != rawRequest.Metadata.WorkflowExecutionID ||
+ hex.EncodeToString(reportMetadata.WorkflowOwner[:]) != rawRequest.Metadata.WorkflowOwner ||
+ hex.EncodeToString(reportMetadata.WorkflowName[:]) != rawRequest.Metadata.WorkflowName ||
+ hex.EncodeToString(reportMetadata.WorkflowCID[:]) != rawRequest.Metadata.WorkflowID {
+ return r, fmt.Errorf("report metadata does not match request metadata. reportMetadata: %+v, requestMetadata: %+v", reportMetadata, rawRequest.Metadata)
+ }
+
+ return r, nil
}
func success() <-chan capabilities.CapabilityResponse {
@@ -77,7 +177,7 @@ func success() <-chan capabilities.CapabilityResponse {
return callback
}
-func (cap *WriteTarget) Execute(ctx context.Context, request capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) {
+func (cap *WriteTarget) Execute(ctx context.Context, rawRequest capabilities.CapabilityRequest) (<-chan capabilities.CapabilityResponse, error) {
// Bind to the contract address on the write path.
// Bind() requires a connection to the node's RPCs and
// cannot be run during initialization.
@@ -93,54 +193,53 @@ func (cap *WriteTarget) Execute(ctx context.Context, request capabilities.Capabi
cap.bound = true
}
- cap.lggr.Debugw("Execute", "request", request)
+ cap.lggr.Debugw("Execute", "rawRequest", rawRequest)
- reqConfig, err := parseConfig(request.Config)
+ request, err := evaluate(rawRequest)
if err != nil {
return nil, err
}
- signedReport, ok := request.Inputs.Underlying[signedReportField]
- if !ok {
- return nil, fmt.Errorf("missing required field %s", signedReportField)
- }
-
- inputs := types.SignedReport{}
- if err = signedReport.UnwrapTo(&inputs); err != nil {
- return nil, err
- }
-
- if len(inputs.Report) == 0 {
- // We received any empty report -- this means we should skip transmission.
- cap.lggr.Debugw("Skipping empty report", "request", request)
- return success(), nil
- }
- // TODO: validate encoded report is prefixed with workflowID and executionID that match the request meta
-
rawExecutionID, err := hex.DecodeString(request.Metadata.WorkflowExecutionID)
if err != nil {
return nil, err
}
+
// Check whether value was already transmitted on chain
queryInputs := struct {
Receiver string
WorkflowExecutionID []byte
ReportId []byte
}{
- Receiver: reqConfig.Address,
+ Receiver: request.Config.Address,
WorkflowExecutionID: rawExecutionID,
- ReportId: inputs.ID,
+ ReportId: request.Inputs.SignedReport.ID,
}
- var transmitter common.Address
- if err = cap.cr.GetLatestValue(ctx, "forwarder", "getTransmitter", primitives.Unconfirmed, queryInputs, &transmitter); err != nil {
- return nil, fmt.Errorf("failed to getTransmitter latest value: %w", err)
+ var transmissionInfo TransmissionInfo
+ if err = cap.cr.GetLatestValue(ctx, "forwarder", "getTransmissionInfo", primitives.Unconfirmed, queryInputs, &transmissionInfo); err != nil {
+ return nil, fmt.Errorf("failed to getTransmissionInfo latest value: %w", err)
}
- if transmitter != common.HexToAddress("0x0") {
- cap.lggr.Infow("WriteTarget report already onchain - returning without a tranmission attempt", "executionID", request.Metadata.WorkflowExecutionID)
+
+ switch {
+ case transmissionInfo.State == 0: // NOT_ATTEMPTED
+ cap.lggr.Infow("non-empty report - tranasmission not attempted - attempting to push to txmgr", "request", request, "reportLen", len(request.Inputs.SignedReport.Report), "reportContextLen", len(request.Inputs.SignedReport.Context), "nSignatures", len(request.Inputs.SignedReport.Signatures), "executionID", request.Metadata.WorkflowExecutionID)
+ case transmissionInfo.State == 1: // SUCCEEDED
+ cap.lggr.Infow("returning without a tranmission attempt - report already onchain ", "executionID", request.Metadata.WorkflowExecutionID)
+ return success(), nil
+ case transmissionInfo.State == 2: // INVALID_RECEIVER
+ cap.lggr.Infow("returning without a tranmission attempt - transmission already attempted, receiver was marked as invalid", "executionID", request.Metadata.WorkflowExecutionID)
return success(), nil
+ case transmissionInfo.State == 3: // FAILED
+ if transmissionInfo.GasLimit.Uint64() > cap.receiverGasMinimum {
+ cap.lggr.Infow("returning without a tranmission attempt - transmission already attempted and failed, sufficient gas was provided", "executionID", request.Metadata.WorkflowExecutionID, "receiverGasMinimum", cap.receiverGasMinimum, "transmissionGasLimit", transmissionInfo.GasLimit)
+ return success(), nil
+ } else {
+ cap.lggr.Infow("non-empty report - retrying a failed transmission - attempting to push to txmgr", "request", request, "reportLen", len(request.Inputs.SignedReport.Report), "reportContextLen", len(request.Inputs.SignedReport.Context), "nSignatures", len(request.Inputs.SignedReport.Signatures), "executionID", request.Metadata.WorkflowExecutionID, "receiverGasMinimum", cap.receiverGasMinimum, "transmissionGasLimit", transmissionInfo.GasLimit)
+ }
+ default:
+ return nil, fmt.Errorf("unexpected transmission state: %v", transmissionInfo.State)
}
- cap.lggr.Infow("WriteTarget non-empty report - attempting to push to txmgr", "request", request, "reportLen", len(inputs.Report), "reportContextLen", len(inputs.Context), "nSignatures", len(inputs.Signatures), "executionID", request.Metadata.WorkflowExecutionID)
txID, err := uuid.NewUUID() // NOTE: CW expects us to generate an ID, rather than return one
if err != nil {
return nil, err
@@ -154,7 +253,7 @@ func (cap *WriteTarget) Execute(ctx context.Context, request capabilities.Capabi
RawReport []byte
ReportContext []byte
Signatures [][]byte
- }{reqConfig.Address, inputs.Report, inputs.Context, inputs.Signatures}
+ }{request.Config.Address, request.Inputs.SignedReport.Report, request.Inputs.SignedReport.Context, request.Inputs.SignedReport.Signatures}
if req.RawReport == nil {
req.RawReport = make([]byte, 0)
diff --git a/core/capabilities/targets/write_target_test.go b/core/capabilities/targets/write_target_test.go
index e1184331778..522fee32513 100644
--- a/core/capabilities/targets/write_target_test.go
+++ b/core/capabilities/targets/write_target_test.go
@@ -2,7 +2,9 @@ package targets_test
import (
"context"
+ "encoding/hex"
"errors"
+ "math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
@@ -29,7 +31,7 @@ func TestWriteTarget(t *testing.T) {
forwarderA := testutils.NewAddress()
forwarderAddr := forwarderA.Hex()
- writeTarget := targets.NewWriteTarget(lggr, "test-write-target@1.0.0", cr, cw, forwarderAddr)
+ writeTarget := targets.NewWriteTarget(lggr, "test-write-target@1.0.0", cr, cw, forwarderAddr, 400_000)
require.NotNil(t, writeTarget)
config, err := values.NewMap(map[string]any{
@@ -37,14 +39,36 @@ func TestWriteTarget(t *testing.T) {
})
require.NoError(t, err)
+ reportMetadata := targets.ReportV1Metadata{
+ Version: 1,
+ WorkflowExecutionID: [32]byte{},
+ Timestamp: 0,
+ DonID: 0,
+ DonConfigVersion: 0,
+ WorkflowCID: [32]byte{},
+ WorkflowName: [10]byte{},
+ WorkflowOwner: [20]byte{},
+ ReportID: [2]byte{},
+ }
+
+ reportMetadataBytes, err := reportMetadata.Encode()
+ require.NoError(t, err)
+
validInputs, err := values.NewMap(map[string]any{
"signed_report": map[string]any{
- "report": []byte{1, 2, 3},
+ "report": reportMetadataBytes,
"signatures": [][]byte{},
},
})
require.NoError(t, err)
+ validMetadata := capabilities.RequestMetadata{
+ WorkflowID: hex.EncodeToString(reportMetadata.WorkflowCID[:]),
+ WorkflowOwner: hex.EncodeToString(reportMetadata.WorkflowOwner[:]),
+ WorkflowName: hex.EncodeToString(reportMetadata.WorkflowName[:]),
+ WorkflowExecutionID: hex.EncodeToString(reportMetadata.WorkflowExecutionID[:]),
+ }
+
cr.On("Bind", mock.Anything, []types.BoundContract{
{
Address: forwarderAddr,
@@ -52,20 +76,25 @@ func TestWriteTarget(t *testing.T) {
},
}).Return(nil)
- cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmitter", mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) {
- transmitter := args.Get(5).(*common.Address)
- *transmitter = common.HexToAddress("0x0")
+ cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmissionInfo", mock.Anything, mock.Anything, mock.Anything).Return(nil).Run(func(args mock.Arguments) {
+ transmissionInfo := args.Get(5).(*targets.TransmissionInfo)
+ *transmissionInfo = targets.TransmissionInfo{
+ GasLimit: big.NewInt(0),
+ InvalidReceiver: false,
+ State: 0,
+ Success: false,
+ TransmissionId: [32]byte{},
+ Transmitter: common.HexToAddress("0x0"),
+ }
}).Once()
cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, forwarderAddr, mock.Anything, mock.Anything).Return(nil).Once()
t.Run("succeeds with valid report", func(t *testing.T) {
req := capabilities.CapabilityRequest{
- Metadata: capabilities.RequestMetadata{
- WorkflowID: "test-id",
- },
- Config: config,
- Inputs: validInputs,
+ Metadata: validMetadata,
+ Config: config,
+ Inputs: validInputs,
}
ch, err2 := writeTarget.Execute(ctx, req)
@@ -74,38 +103,13 @@ func TestWriteTarget(t *testing.T) {
require.NotNil(t, response)
})
- t.Run("succeeds with empty report", func(t *testing.T) {
- emptyInputs, err2 := values.NewMap(map[string]any{
- "signed_report": map[string]any{
- "report": []byte{},
- },
- "signatures": [][]byte{},
- })
-
- require.NoError(t, err2)
- req := capabilities.CapabilityRequest{
- Metadata: capabilities.RequestMetadata{
- WorkflowExecutionID: "test-id",
- },
- Config: config,
- Inputs: emptyInputs,
- }
-
- ch, err2 := writeTarget.Execute(ctx, req)
- require.NoError(t, err2)
- response := <-ch
- require.Nil(t, response.Value)
- })
-
t.Run("fails when ChainReader's GetLatestValue returns error", func(t *testing.T) {
req := capabilities.CapabilityRequest{
- Metadata: capabilities.RequestMetadata{
- WorkflowID: "test-id",
- },
- Config: config,
- Inputs: validInputs,
+ Metadata: validMetadata,
+ Config: config,
+ Inputs: validInputs,
}
- cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmitter", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("reader error"))
+ cr.On("GetLatestValue", mock.Anything, "forwarder", "getTransmissionInfo", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("reader error"))
_, err = writeTarget.Execute(ctx, req)
require.Error(t, err)
@@ -113,11 +117,9 @@ func TestWriteTarget(t *testing.T) {
t.Run("fails when ChainWriter's SubmitTransaction returns error", func(t *testing.T) {
req := capabilities.CapabilityRequest{
- Metadata: capabilities.RequestMetadata{
- WorkflowID: "test-id",
- },
- Config: config,
- Inputs: validInputs,
+ Metadata: validMetadata,
+ Config: config,
+ Inputs: validInputs,
}
cw.On("SubmitTransaction", mock.Anything, "forwarder", "report", mock.Anything, mock.Anything, forwarderAddr, mock.Anything, mock.Anything).Return(errors.New("writer error"))
@@ -126,10 +128,10 @@ func TestWriteTarget(t *testing.T) {
})
t.Run("fails with invalid config", func(t *testing.T) {
- invalidConfig, err := values.NewMap(map[string]any{
+ invalidConfig, err2 := values.NewMap(map[string]any{
"Address": "invalid-address",
})
- require.NoError(t, err)
+ require.NoError(t, err2)
req := capabilities.CapabilityRequest{
Metadata: capabilities.RequestMetadata{
@@ -138,7 +140,27 @@ func TestWriteTarget(t *testing.T) {
Config: invalidConfig,
Inputs: validInputs,
}
- _, err = writeTarget.Execute(ctx, req)
- require.Error(t, err)
+ _, err2 = writeTarget.Execute(ctx, req)
+ require.Error(t, err2)
+ })
+
+ t.Run("fails with nil config", func(t *testing.T) {
+ req := capabilities.CapabilityRequest{
+ Metadata: validMetadata,
+ Config: nil,
+ Inputs: validInputs,
+ }
+ _, err2 := writeTarget.Execute(ctx, req)
+ require.Error(t, err2)
+ })
+
+ t.Run("fails with nil inputs", func(t *testing.T) {
+ req := capabilities.CapabilityRequest{
+ Metadata: validMetadata,
+ Config: config,
+ Inputs: nil,
+ }
+ _, err2 := writeTarget.Execute(ctx, req)
+ require.Error(t, err2)
})
}
diff --git a/core/capabilities/transmission/local_target_capability_test.go b/core/capabilities/transmission/local_target_capability_test.go
index 93bf708ccef..cdca854986b 100644
--- a/core/capabilities/transmission/local_target_capability_test.go
+++ b/core/capabilities/transmission/local_target_capability_test.go
@@ -54,8 +54,8 @@ func TestScheduledExecutionStrategy_LocalDON(t *testing.T) {
name: "position 0; oneAtATime",
position: 0,
schedule: "oneAtATime",
- low: 300 * time.Millisecond,
- high: 400 * time.Millisecond,
+ low: 200 * time.Millisecond,
+ high: 300 * time.Millisecond,
},
{
name: "position 1; oneAtATime",
@@ -68,15 +68,15 @@ func TestScheduledExecutionStrategy_LocalDON(t *testing.T) {
name: "position 2; oneAtATime",
position: 2,
schedule: "oneAtATime",
- low: 0 * time.Millisecond,
- high: 100 * time.Millisecond,
+ low: 300 * time.Millisecond,
+ high: 400 * time.Millisecond,
},
{
name: "position 3; oneAtATime",
position: 3,
schedule: "oneAtATime",
- low: 100 * time.Millisecond,
- high: 300 * time.Millisecond,
+ low: 0 * time.Millisecond,
+ high: 100 * time.Millisecond,
},
{
name: "position 0; allAtOnce",
@@ -121,8 +121,8 @@ func TestScheduledExecutionStrategy_LocalDON(t *testing.T) {
req := capabilities.CapabilityRequest{
Config: m,
Metadata: capabilities.RequestMetadata{
- WorkflowID: "mock-workflow-id",
- WorkflowExecutionID: "mock-execution-id-1",
+ WorkflowID: "15c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0",
+ WorkflowExecutionID: "32c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce1",
},
}
diff --git a/core/capabilities/transmission/transmission.go b/core/capabilities/transmission/transmission.go
index b41be5bcaa5..88ce0fa3edd 100644
--- a/core/capabilities/transmission/transmission.go
+++ b/core/capabilities/transmission/transmission.go
@@ -4,10 +4,10 @@ import (
"fmt"
"time"
- "github.com/pkg/errors"
-
"github.com/smartcontractkit/libocr/permutation"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/validation"
+
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/values"
"github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
@@ -56,8 +56,12 @@ func GetPeerIDToTransmissionDelay(donPeerIDs []types.PeerID, req capabilities.Ca
return nil, fmt.Errorf("failed to extract transmission config from request: %w", err)
}
- if req.Metadata.WorkflowID == "" || req.Metadata.WorkflowExecutionID == "" {
- return nil, errors.New("workflow ID and workflow execution ID must be set in request metadata")
+ if err = validation.ValidateWorkflowOrExecutionID(req.Metadata.WorkflowID); err != nil {
+ return nil, fmt.Errorf("workflow ID is invalid: %w", err)
+ }
+
+ if err = validation.ValidateWorkflowOrExecutionID(req.Metadata.WorkflowExecutionID); err != nil {
+ return nil, fmt.Errorf("workflow execution ID is invalid: %w", err)
}
transmissionID := req.Metadata.WorkflowID + req.Metadata.WorkflowExecutionID
diff --git a/core/capabilities/transmission/transmission_test.go b/core/capabilities/transmission/transmission_test.go
index fba233eadb0..aaa367e78cf 100644
--- a/core/capabilities/transmission/transmission_test.go
+++ b/core/capabilities/transmission/transmission_test.go
@@ -36,20 +36,21 @@ func Test_GetPeerIDToTransmissionDelay(t *testing.T) {
"one",
"oneAtATime",
"100ms",
- "mock-execution-id",
+ "15c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0",
map[string]time.Duration{
"one": 300 * time.Millisecond,
- "two": 100 * time.Millisecond,
- "three": 0 * time.Millisecond,
+ "two": 0 * time.Millisecond,
+ "three": 100 * time.Millisecond,
"four": 200 * time.Millisecond,
},
},
+
{
"TestAllAtOnce",
"one",
"allAtOnce",
"100ms",
- "mock-execution-id",
+ "15c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0",
map[string]time.Duration{
"one": 0 * time.Millisecond,
"two": 0 * time.Millisecond,
@@ -57,17 +58,18 @@ func Test_GetPeerIDToTransmissionDelay(t *testing.T) {
"four": 0 * time.Millisecond,
},
},
+
{
"TestOneAtATimeWithDifferentExecutionID",
"one",
"oneAtATime",
"100ms",
- "mock-execution-id2",
+ "16c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce1",
map[string]time.Duration{
- "one": 0 * time.Millisecond,
- "two": 200 * time.Millisecond,
- "three": 100 * time.Millisecond,
- "four": 300 * time.Millisecond,
+ "one": 300 * time.Millisecond,
+ "two": 100 * time.Millisecond,
+ "three": 200 * time.Millisecond,
+ "four": 0 * time.Millisecond,
},
},
}
@@ -83,7 +85,7 @@ func Test_GetPeerIDToTransmissionDelay(t *testing.T) {
capabilityRequest := capabilities.CapabilityRequest{
Config: transmissionCfg,
Metadata: capabilities.RequestMetadata{
- WorkflowID: "mock-workflow-id",
+ WorkflowID: "17c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0",
WorkflowExecutionID: tc.workflowExecutionID,
},
}
diff --git a/core/capabilities/validation/validation.go b/core/capabilities/validation/validation.go
new file mode 100644
index 00000000000..67ee3a504cf
--- /dev/null
+++ b/core/capabilities/validation/validation.go
@@ -0,0 +1,38 @@
+package validation
+
+import (
+ "encoding/hex"
+ "errors"
+ "unicode"
+)
+
+const (
+ validWorkflowIDLen = 64
+ maxIDLen = 128
+)
+
+// Workflow IDs and Execution IDs are 32-byte hex-encoded strings
+func ValidateWorkflowOrExecutionID(id string) error {
+ if len(id) != validWorkflowIDLen {
+ return errors.New("must be 32 bytes long")
+ }
+ _, err := hex.DecodeString(id)
+ if err != nil {
+ return errors.New("must be a hex-encoded string")
+ }
+
+ return nil
+}
+
+// Trigger event IDs and message IDs can only contain printable characters and must be non-empty
+func IsValidID(id string) bool {
+ if len(id) == 0 || len(id) > maxIDLen {
+ return false
+ }
+ for i := 0; i < len(id); i++ {
+ if !unicode.IsPrint(rune(id[i])) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/core/capabilities/validation/validation_test.go b/core/capabilities/validation/validation_test.go
new file mode 100644
index 00000000000..205898652fd
--- /dev/null
+++ b/core/capabilities/validation/validation_test.go
@@ -0,0 +1,19 @@
+package validation
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestIsValidWorkflowID(t *testing.T) {
+ require.NotNil(t, ValidateWorkflowOrExecutionID("too_short"))
+ require.NotNil(t, ValidateWorkflowOrExecutionID("nothex--95ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0"))
+ require.NoError(t, ValidateWorkflowOrExecutionID("15c631d295ef5e32deb99a10ee6804bc4af13855687559d7ff6552ac6dbb2ce0"))
+}
+
+func TestIsValidTriggerEventID(t *testing.T) {
+ require.False(t, IsValidID(""))
+ require.False(t, IsValidID("\n\n"))
+ require.True(t, IsValidID("id_id_2"))
+}
diff --git a/core/chainlink.goreleaser.Dockerfile b/core/chainlink.goreleaser.Dockerfile
index 5d172fd77e5..c35fe015cbd 100644
--- a/core/chainlink.goreleaser.Dockerfile
+++ b/core/chainlink.goreleaser.Dockerfile
@@ -20,8 +20,9 @@ COPY ./chainlink /usr/local/bin/
# Copy native libs if cgo is enabled
COPY ./tmp/linux_${TARGETARCH}/libs /usr/local/bin/libs
-# Copy plugins and enable them
-COPY ./tmp/linux_${TARGETARCH}/plugins/* /usr/local/bin/
+# Copy plugins if exist and enable them
+# https://stackoverflow.com/questions/70096208/dockerfile-copy-folder-if-it-exists-conditional-copy/70096420#70096420
+COPY ./tmp/linux_${TARGETARCH}/plugin[s] /usr/local/bin/
# Allow individual plugins to be enabled by supplying their path
ARG CL_MEDIAN_CMD
ARG CL_MERCURY_CMD
diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go
index 75973469140..c27d294ebfd 100644
--- a/core/chains/evm/client/chain_client.go
+++ b/core/chains/evm/client/chain_client.go
@@ -20,7 +20,6 @@ import (
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
)
-const queryTimeout = 10 * time.Second
const BALANCE_OF_ADDRESS_FUNCTION_SELECTOR = "0x70a08231"
var _ Client = (*chainClient)(nil)
@@ -99,7 +98,7 @@ type Client interface {
}
func ContextWithDefaultTimeout() (ctx context.Context, cancel context.CancelFunc) {
- return context.WithTimeout(context.Background(), queryTimeout)
+ return context.WithTimeout(context.Background(), commonclient.QueryTimeout)
}
type chainClient struct {
@@ -161,9 +160,13 @@ func (c *chainClient) BalanceAt(ctx context.Context, account common.Address, blo
return c.multiNode.BalanceAt(ctx, account, blockNumber)
}
+// BatchCallContext - sends all given requests as a single batch.
// Request specific errors for batch calls are returned to the individual BatchElem.
// Ensure the same BatchElem slice provided by the caller is passed through the call stack
// to ensure the caller has access to the errors.
+// Note: some chains (e.g Astar) have custom finality requests, so even when FinalityTagEnabled=true, finality tag
+// might not be properly handled and returned results might have weaker finality guarantees. It's highly recommended
+// to use HeadTracker to identify latest finalized block.
func (c *chainClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error {
return c.multiNode.BatchCallContext(ctx, b)
}
diff --git a/core/chains/evm/client/chain_client_test.go b/core/chains/evm/client/chain_client_test.go
index 33955c16451..47041e40e91 100644
--- a/core/chains/evm/client/chain_client_test.go
+++ b/core/chains/evm/client/chain_client_test.go
@@ -328,7 +328,7 @@ func TestEthClient_HeaderByNumber(t *testing.T) {
`{"difficulty":"0xf3a00","extraData":"0xd883010503846765746887676f312e372e318664617277696e","gasLimit":"0xffc001","gasUsed":"0x0","hash":"0x41800b5c3f1717687d85fc9018faac0a6e90b39deaa0b99e7fe4fe796ddeb26a","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xd1aeb42885a43b72b518182ef893125814811048","mixHash":"0x0f98b15f1a4901a7e9204f3c500a7bd527b3fb2c3340e12176a44b83e414a69e","nonce":"0x0ece08ea8c49dfd9","number":"0x1","parentHash":"0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x218","stateRoot":"0xc7b01007a10da045eacb90385887dd0c38fcb5db7393006bdde24b93873c334b","timestamp":"0x58318da2","totalDifficulty":"0x1f3a00","transactions":[],"transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","uncles":[]}`},
{"happy parity", expectedBlockNum, expectedBlockNum.Int64(), nil,
`{"author":"0xd1aeb42885a43b72b518182ef893125814811048","difficulty":"0xf3a00","extraData":"0xd883010503846765746887676f312e372e318664617277696e","gasLimit":"0xffc001","gasUsed":"0x0","hash":"0x41800b5c3f1717687d85fc9018faac0a6e90b39deaa0b99e7fe4fe796ddeb26a","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xd1aeb42885a43b72b518182ef893125814811048","mixHash":"0x0f98b15f1a4901a7e9204f3c500a7bd527b3fb2c3340e12176a44b83e414a69e","nonce":"0x0ece08ea8c49dfd9","number":"0x1","parentHash":"0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sealFields":["0xa00f98b15f1a4901a7e9204f3c500a7bd527b3fb2c3340e12176a44b83e414a69e","0x880ece08ea8c49dfd9"],"sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x218","stateRoot":"0xc7b01007a10da045eacb90385887dd0c38fcb5db7393006bdde24b93873c334b","timestamp":"0x58318da2","totalDifficulty":"0x1f3a00","transactions":[],"transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","uncles":[]}`},
- {"missing header", expectedBlockNum, 0, fmt.Errorf("no live nodes available for chain %s", testutils.FixtureChainID.String()),
+ {"missing header", expectedBlockNum, 0, fmt.Errorf("RPCClient returned error (eth-primary-rpc-0): not found"),
`null`},
}
@@ -366,7 +366,7 @@ func TestEthClient_HeaderByNumber(t *testing.T) {
ctx, cancel := context.WithTimeout(tests.Context(t), 5*time.Second)
result, err := ethClient.HeadByNumber(ctx, expectedBlockNum)
if test.error != nil {
- require.Error(t, err, test.error)
+ require.EqualError(t, err, test.error.Error())
} else {
require.NoError(t, err)
require.Equal(t, expectedBlockHash, result.Hash.Hex())
@@ -751,7 +751,7 @@ func newMockRpc(t *testing.T) *mocks.RPCClient {
mockRpc.On("Close").Return(nil).Once()
mockRpc.On("ChainID", mock.Anything).Return(testutils.FixtureChainID, nil).Once()
// node does not always manage to fully setup aliveLoop, so we have to make calls optional to avoid flakes
- mockRpc.On("SubscribeNewHead", mock.Anything, mock.Anything).Return(client.NewMockSubscription(), nil).Maybe()
+ mockRpc.On("SubscribeToHeads", mock.Anything).Return(nil, client.NewMockSubscription(), nil).Maybe()
mockRpc.On("SetAliveLoopSub", mock.Anything).Return().Maybe()
return mockRpc
}
diff --git a/core/chains/evm/client/config_builder.go b/core/chains/evm/client/config_builder.go
index 19e0f14fd67..fa702bac111 100644
--- a/core/chains/evm/client/config_builder.go
+++ b/core/chains/evm/client/config_builder.go
@@ -41,6 +41,8 @@ func NewClientConfigs(
finalizedBlockOffset *uint32,
enforceRepeatableRead *bool,
deathDeclarationDelay time.Duration,
+ noNewFinalizedHeadsThreshold time.Duration,
+ finalizedBlockPollInterval time.Duration,
) (commonclient.ChainConfig, evmconfig.NodePool, []*toml.Node, error) {
nodes, err := parseNodeConfigs(nodeCfgs)
@@ -48,24 +50,26 @@ func NewClientConfigs(
return nil, nil, nil, err
}
nodePool := toml.NodePool{
- SelectionMode: selectionMode,
- LeaseDuration: commonconfig.MustNewDuration(leaseDuration),
- PollFailureThreshold: pollFailureThreshold,
- PollInterval: commonconfig.MustNewDuration(pollInterval),
- SyncThreshold: syncThreshold,
- NodeIsSyncingEnabled: nodeIsSyncingEnabled,
- EnforceRepeatableRead: enforceRepeatableRead,
- DeathDeclarationDelay: commonconfig.MustNewDuration(deathDeclarationDelay),
+ SelectionMode: selectionMode,
+ LeaseDuration: commonconfig.MustNewDuration(leaseDuration),
+ PollFailureThreshold: pollFailureThreshold,
+ PollInterval: commonconfig.MustNewDuration(pollInterval),
+ SyncThreshold: syncThreshold,
+ NodeIsSyncingEnabled: nodeIsSyncingEnabled,
+ EnforceRepeatableRead: enforceRepeatableRead,
+ DeathDeclarationDelay: commonconfig.MustNewDuration(deathDeclarationDelay),
+ FinalizedBlockPollInterval: commonconfig.MustNewDuration(finalizedBlockPollInterval),
}
nodePoolCfg := &evmconfig.NodePoolConfig{C: nodePool}
chainConfig := &evmconfig.EVMConfig{
C: &toml.EVMConfig{
Chain: toml.Chain{
- ChainType: chaintype.NewChainTypeConfig(chainType),
- FinalityDepth: finalityDepth,
- FinalityTagEnabled: finalityTagEnabled,
- NoNewHeadsThreshold: commonconfig.MustNewDuration(noNewHeadsThreshold),
- FinalizedBlockOffset: finalizedBlockOffset,
+ ChainType: chaintype.NewChainTypeConfig(chainType),
+ FinalityDepth: finalityDepth,
+ FinalityTagEnabled: finalityTagEnabled,
+ NoNewHeadsThreshold: commonconfig.MustNewDuration(noNewHeadsThreshold),
+ FinalizedBlockOffset: finalizedBlockOffset,
+ NoNewFinalizedHeadsThreshold: commonconfig.MustNewDuration(noNewFinalizedHeadsThreshold),
},
},
}
diff --git a/core/chains/evm/client/config_builder_test.go b/core/chains/evm/client/config_builder_test.go
index 7c08bf18c1d..403c6c2d619 100644
--- a/core/chains/evm/client/config_builder_test.go
+++ b/core/chains/evm/client/config_builder_test.go
@@ -26,6 +26,7 @@ func TestClientConfigBuilder(t *testing.T) {
finalizedBlockOffset := ptr[uint32](16)
enforceRepeatableRead := ptr(true)
deathDeclarationDelay := time.Second * 3
+ noNewFinalizedBlocksThreshold := time.Second
nodeConfigs := []client.NodeConfig{
{
Name: ptr("foo"),
@@ -38,7 +39,7 @@ func TestClientConfigBuilder(t *testing.T) {
noNewHeadsThreshold := time.Second
chainCfg, nodePool, nodes, err := client.NewClientConfigs(selectionMode, leaseDuration, chainTypeStr, nodeConfigs,
pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled, noNewHeadsThreshold, finalityDepth,
- finalityTagEnabled, finalizedBlockOffset, enforceRepeatableRead, deathDeclarationDelay)
+ finalityTagEnabled, finalizedBlockOffset, enforceRepeatableRead, deathDeclarationDelay, noNewFinalizedBlocksThreshold, pollInterval)
require.NoError(t, err)
// Validate node pool configs
@@ -50,6 +51,7 @@ func TestClientConfigBuilder(t *testing.T) {
require.Equal(t, *nodeIsSyncingEnabled, nodePool.NodeIsSyncingEnabled())
require.Equal(t, *enforceRepeatableRead, nodePool.EnforceRepeatableRead())
require.Equal(t, deathDeclarationDelay, nodePool.DeathDeclarationDelay())
+ require.Equal(t, pollInterval, nodePool.FinalizedBlockPollInterval())
// Validate node configs
require.Equal(t, *nodeConfigs[0].Name, *nodes[0].Name)
@@ -61,6 +63,7 @@ func TestClientConfigBuilder(t *testing.T) {
require.Equal(t, *finalityDepth, chainCfg.FinalityDepth())
require.Equal(t, *finalityTagEnabled, chainCfg.FinalityTagEnabled())
require.Equal(t, *finalizedBlockOffset, chainCfg.FinalizedBlockOffset())
+ require.Equal(t, noNewFinalizedBlocksThreshold, chainCfg.NoNewFinalizedHeadsThreshold())
// let combiler tell us, when we do not have sufficient data to create evm client
_ = client.NewEvmClient(nodePool, chainCfg, nil, logger.Test(t), big.NewInt(10), nodes, chaintype.ChainType(chainTypeStr))
diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go
index 22fac5f7287..5980b0dd963 100644
--- a/core/chains/evm/client/errors.go
+++ b/core/chains/evm/client/errors.go
@@ -158,7 +158,13 @@ var arbitrum = ClientErrors{
Fatal: arbitrumFatal,
L2FeeTooLow: regexp.MustCompile(`(: |^)max fee per gas less than block base fee(:|$)`),
L2Full: regexp.MustCompile(`(: |^)(queue full|sequencer pending tx pool full, please try again)(:|$)`),
- ServiceUnavailable: regexp.MustCompile(`(: |^)502 Bad Gateway: [\s\S]*$`),
+ ServiceUnavailable: regexp.MustCompile(`(: |^)502 Bad Gateway: [\s\S]*$|network is unreachable|i/o timeout`),
+}
+
+// Treasure
+var treasureFatal = regexp.MustCompile(`(: |^)invalid chain id for signer(:|$)`)
+var treasure = ClientErrors{
+ Fatal: treasureFatal,
}
var celo = ClientErrors{
@@ -250,6 +256,19 @@ var zkEvm = ClientErrors{
TerminallyStuck: regexp.MustCompile(`(?:: |^)not enough .* counters to continue the execution$`),
}
+var aStar = ClientErrors{
+ TerminallyUnderpriced: regexp.MustCompile(`(?:: |^)(gas price less than block base fee)$`),
+}
+
+var mantle = ClientErrors{
+ InsufficientEth: regexp.MustCompile(`(: |^)'*insufficient funds for gas \* price \+ value`),
+ Fatal: regexp.MustCompile(`(: |^)'*invalid sender`),
+}
+
+var gnosis = ClientErrors{
+ TransactionAlreadyInMempool: regexp.MustCompile(`(: |^)(alreadyknown)`),
+}
+
const TerminallyStuckMsg = "transaction terminally stuck"
// Tx.Error messages that are set internally so they are not chain or client specific
@@ -257,7 +276,7 @@ var internal = ClientErrors{
TerminallyStuck: regexp.MustCompile(TerminallyStuckMsg),
}
-var clients = []ClientErrors{parity, geth, arbitrum, metis, substrate, avalanche, nethermind, harmony, besu, erigon, klaytn, celo, zkSync, zkEvm, internal}
+var clients = []ClientErrors{parity, geth, arbitrum, metis, substrate, avalanche, nethermind, harmony, besu, erigon, klaytn, celo, zkSync, zkEvm, treasure, mantle, aStar, gnosis, internal}
// ClientErrorRegexes returns a map of compiled regexes for each error type
func ClientErrorRegexes(errsRegex config.ClientErrors) *ClientErrors {
@@ -583,6 +602,11 @@ func ClassifySendError(err error, clientErrors config.ClientErrors, lggr logger.
)
return commonclient.ExceedsMaxFee
}
+ if sendError.IsTerminallyStuckConfigError(configErrors) {
+ lggr.Warnw("Transaction that would have been terminally stuck in the mempool detected on send. Marking as fatal error.", "err", sendError, "etx", tx)
+ // Attempt is thrown away in this case; we don't need it since it never got accepted by a node
+ return commonclient.TerminallyStuck
+ }
lggr.Criticalw("Unknown error encountered when sending transaction", "err", err, "etx", tx)
return commonclient.Unknown
}
diff --git a/core/chains/evm/client/errors_test.go b/core/chains/evm/client/errors_test.go
index cca54c2a4a9..095e291f5e9 100644
--- a/core/chains/evm/client/errors_test.go
+++ b/core/chains/evm/client/errors_test.go
@@ -136,6 +136,7 @@ func Test_Eth_Errors(t *testing.T) {
// 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"},
{"client error transaction already in mempool", true, "tomlConfig"},
+ {"alreadyknown", true, "Gnosis"},
}
for _, test := range tests {
err = evmclient.NewSendErrorS(test.message)
@@ -166,6 +167,7 @@ func Test_Eth_Errors(t *testing.T) {
{"max fee per gas less than block base fee", true, "zkSync"},
{"virtual machine entered unexpected state. please contact developers and provide transaction details that caused this error. Error description: The operator included transaction with an unacceptable gas price", true, "zkSync"},
{"client error terminally underpriced", true, "tomlConfig"},
+ {"gas price less than block base fee", true, "aStar"},
}
for _, test := range tests {
@@ -214,6 +216,7 @@ func Test_Eth_Errors(t *testing.T) {
{"insufficient funds for gas + value. balance: 42719769622667482000, fee: 48098250000000, value: 42719769622667482000", true, "celo"},
{"client error insufficient eth", true, "tomlConfig"},
{"transaction would cause overdraft", true, "Geth"},
+ {"failed to forward tx to sequencer, please try again. Error message: 'insufficient funds for gas * price + value'", true, "Mantle"},
}
for _, test := range tests {
err = evmclient.NewSendErrorS(test.message)
@@ -227,6 +230,8 @@ func Test_Eth_Errors(t *testing.T) {
tests := []errorCase{
{"call failed: 503 Service Unavailable: \r\n503 Service Temporarily Unavailable\r\n\r\n503 Service Temporarily Unavailable
\r\n\r\n\r\n", true, "Nethermind"},
{"call failed: 502 Bad Gateway: \r\n502 Bad Gateway\r\n\r\n502 Bad Gateway
\r\n
", true, "Arbitrum"},
+ {"i/o timeout", true, "Arbitrum"},
+ {"network is unreachable", true, "Arbitrum"},
{"client error service unavailable", true, "tomlConfig"},
}
for _, test := range tests {
@@ -285,7 +290,7 @@ func Test_Eth_Errors(t *testing.T) {
})
t.Run("Metis gas price errors", func(t *testing.T) {
- err := evmclient.NewSendErrorS("primary websocket (wss://ws-mainnet.metis.io) call failed: gas price too low: 18000000000 wei, use at least tx.gasPrice = 19500000000 wei")
+ err = evmclient.NewSendErrorS("primary websocket (wss://ws-mainnet.metis.io) call failed: gas price too low: 18000000000 wei, use at least tx.gasPrice = 19500000000 wei")
assert.True(t, err.L2FeeTooLow(clientErrors))
err = newSendErrorWrapped("primary websocket (wss://ws-mainnet.metis.io) call failed: gas price too low: 18000000000 wei, use at least tx.gasPrice = 19500000000 wei")
assert.True(t, err.L2FeeTooLow(clientErrors))
@@ -297,7 +302,7 @@ func Test_Eth_Errors(t *testing.T) {
})
t.Run("moonriver errors", func(t *testing.T) {
- err := evmclient.NewSendErrorS("primary http (http://***REDACTED***:9933) call failed: submit transaction to pool failed: Pool(Stale)")
+ err = evmclient.NewSendErrorS("primary http (http://***REDACTED***:9933) call failed: submit transaction to pool failed: Pool(Stale)")
assert.True(t, err.IsNonceTooLowError(clientErrors))
assert.False(t, err.IsTransactionAlreadyInMempool(clientErrors))
assert.False(t, err.Fatal(clientErrors))
@@ -306,6 +311,24 @@ func Test_Eth_Errors(t *testing.T) {
assert.False(t, err.IsNonceTooLowError(clientErrors))
assert.False(t, err.Fatal(clientErrors))
})
+
+ t.Run("IsTerminallyStuck", func(t *testing.T) {
+ tests := []errorCase{
+ {"failed to add tx to the pool: not enough step counters to continue the execution", true, "zkEVM"},
+ {"failed to add tx to the pool: not enough step counters to continue the execution", true, "Xlayer"},
+ {"failed to add tx to the pool: not enough keccak counters to continue the execution", true, "zkEVM"},
+ {"failed to add tx to the pool: not enough keccak counters to continue the execution", true, "Xlayer"},
+ }
+
+ for _, test := range tests {
+ t.Run(test.network, func(t *testing.T) {
+ err = evmclient.NewSendErrorS(test.message)
+ assert.Equal(t, err.IsTerminallyStuckConfigError(clientErrors), test.expect)
+ err = newSendErrorWrapped(test.message)
+ assert.Equal(t, err.IsTerminallyStuckConfigError(clientErrors), test.expect)
+ })
+ }
+ })
}
func Test_Eth_Errors_Fatal(t *testing.T) {
@@ -379,7 +402,10 @@ func Test_Eth_Errors_Fatal(t *testing.T) {
{"Failed to serialize transaction: max priority fee per gas higher than 2^64-1", true, "zkSync"},
{"Failed to serialize transaction: oversized data. max: 1000000; actual: 1000000", true, "zkSync"},
+ {"failed to forward tx to sequencer, please try again. Error message: 'invalid sender'", true, "Mantle"},
+
{"client error fatal", true, "tomlConfig"},
+ {"invalid chain id for signer", true, "Treasure"},
}
for _, test := range tests {
diff --git a/core/chains/evm/client/evm_client.go b/core/chains/evm/client/evm_client.go
index fd7fa5868a4..1fd533d6aab 100644
--- a/core/chains/evm/client/evm_client.go
+++ b/core/chains/evm/client/evm_client.go
@@ -3,6 +3,7 @@ package client
import (
"math/big"
"net/url"
+ "time"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
@@ -17,16 +18,17 @@ func NewEvmClient(cfg evmconfig.NodePool, chainCfg commonclient.ChainConfig, cli
var empty url.URL
var primaries []commonclient.Node[*big.Int, *evmtypes.Head, RPCClient]
var sendonlys []commonclient.SendOnlyNode[*big.Int, RPCClient]
+ largePayloadRPCTimeout, defaultRPCTimeout := getRPCTimeouts(chainType)
for i, node := range nodes {
if node.SendOnly != nil && *node.SendOnly {
rpc := NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID,
- commonclient.Secondary)
+ commonclient.Secondary, cfg.FinalizedBlockPollInterval(), largePayloadRPCTimeout, defaultRPCTimeout, chainType)
sendonly := commonclient.NewSendOnlyNode(lggr, (url.URL)(*node.HTTPURL),
*node.Name, chainID, rpc)
sendonlys = append(sendonlys, sendonly)
} else {
rpc := NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i),
- chainID, commonclient.Primary)
+ chainID, commonclient.Primary, cfg.FinalizedBlockPollInterval(), largePayloadRPCTimeout, defaultRPCTimeout, chainType)
primaryNode := commonclient.NewNode(cfg, chainCfg,
lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order,
rpc, "EVM")
@@ -37,3 +39,11 @@ func NewEvmClient(cfg evmconfig.NodePool, chainCfg commonclient.ChainConfig, cli
return NewChainClient(lggr, cfg.SelectionMode(), cfg.LeaseDuration(), chainCfg.NodeNoNewHeadsThreshold(),
primaries, sendonlys, chainID, chainType, clientErrors, cfg.DeathDeclarationDelay())
}
+
+func getRPCTimeouts(chainType chaintype.ChainType) (largePayload, defaultTimeout time.Duration) {
+ if chaintype.ChainHedera == chainType {
+ return 30 * time.Second, commonclient.QueryTimeout
+ }
+
+ return commonclient.QueryTimeout, commonclient.QueryTimeout
+}
diff --git a/core/chains/evm/client/evm_client_test.go b/core/chains/evm/client/evm_client_test.go
index 9ad25f96025..bdfcf426744 100644
--- a/core/chains/evm/client/evm_client_test.go
+++ b/core/chains/evm/client/evm_client_test.go
@@ -27,6 +27,8 @@ func TestNewEvmClient(t *testing.T) {
finalizedBlockOffset := ptr[uint32](16)
enforceRepeatableRead := ptr(true)
deathDeclarationDelay := time.Second * 3
+ noNewFinalizedBlocksThreshold := time.Second * 5
+ finalizedBlockPollInterval := time.Second * 4
nodeConfigs := []client.NodeConfig{
{
Name: ptr("foo"),
@@ -38,7 +40,7 @@ func TestNewEvmClient(t *testing.T) {
finalityTagEnabled := ptr(true)
chainCfg, nodePool, nodes, err := client.NewClientConfigs(selectionMode, leaseDuration, chainTypeStr, nodeConfigs,
pollFailureThreshold, pollInterval, syncThreshold, nodeIsSyncingEnabled, noNewHeadsThreshold, finalityDepth,
- finalityTagEnabled, finalizedBlockOffset, enforceRepeatableRead, deathDeclarationDelay)
+ finalityTagEnabled, finalizedBlockOffset, enforceRepeatableRead, deathDeclarationDelay, noNewFinalizedBlocksThreshold, finalizedBlockPollInterval)
require.NoError(t, err)
client := client.NewEvmClient(nodePool, chainCfg, nil, logger.Test(t), testutils.FixtureChainID, nodes, chaintype.ChainType(chainTypeStr))
diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go
index e1017a5564f..e996ccc5e4f 100644
--- a/core/chains/evm/client/helpers_test.go
+++ b/core/chains/evm/client/helpers_test.go
@@ -140,7 +140,7 @@ func NewChainClientWithTestNode(
}
lggr := logger.Test(t)
- rpc := NewRPCClient(lggr, *parsed, rpcHTTPURL, "eth-primary-rpc-0", id, chainID, commonclient.Primary)
+ rpc := NewRPCClient(lggr, *parsed, rpcHTTPURL, "eth-primary-rpc-0", id, chainID, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
n := commonclient.NewNode[*big.Int, *evmtypes.Head, RPCClient](
nodeCfg, clientMocks.ChainConfig{NoNewHeadsThresholdVal: noNewHeadsThreshold}, lggr, *parsed, rpcHTTPURL, "eth-primary-node-0", id, chainID, 1, rpc, "EVM")
@@ -152,7 +152,7 @@ func NewChainClientWithTestNode(
return nil, pkgerrors.Errorf("sendonly ethereum rpc url scheme must be http(s): %s", u.String())
}
var empty url.URL
- rpc := NewRPCClient(lggr, empty, &sendonlyRPCURLs[i], fmt.Sprintf("eth-sendonly-rpc-%d", i), id, chainID, commonclient.Secondary)
+ rpc := NewRPCClient(lggr, empty, &sendonlyRPCURLs[i], fmt.Sprintf("eth-sendonly-rpc-%d", i), id, chainID, commonclient.Secondary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
s := commonclient.NewSendOnlyNode[*big.Int, RPCClient](
lggr, u, fmt.Sprintf("eth-sendonly-%d", i), chainID, rpc)
sendonlys = append(sendonlys, s)
diff --git a/core/chains/evm/client/mocks/rpc_client.go b/core/chains/evm/client/mocks/rpc_client.go
index fa866af29e0..06f79efd551 100644
--- a/core/chains/evm/client/mocks/rpc_client.go
+++ b/core/chains/evm/client/mocks/rpc_client.go
@@ -1883,8 +1883,8 @@ func (_c *RPCClient_SubscribeNewHead_Call) Run(run func(ctx context.Context, cha
return _c
}
-func (_c *RPCClient_SubscribeNewHead_Call) Return(_a0 commontypes.Subscription, _a1 error) *RPCClient_SubscribeNewHead_Call {
- _c.Call.Return(_a0, _a1)
+func (_c *RPCClient_SubscribeNewHead_Call) Return(s commontypes.Subscription, err error) *RPCClient_SubscribeNewHead_Call {
+ _c.Call.Return(s, err)
return _c
}
@@ -1893,6 +1893,140 @@ func (_c *RPCClient_SubscribeNewHead_Call) RunAndReturn(run func(context.Context
return _c
}
+// SubscribeToFinalizedHeads provides a mock function with given fields: _a0
+func (_m *RPCClient) SubscribeToFinalizedHeads(_a0 context.Context) (<-chan *types.Head, commontypes.Subscription, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SubscribeToFinalizedHeads")
+ }
+
+ var r0 <-chan *types.Head
+ var r1 commontypes.Subscription
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context) (<-chan *types.Head, commontypes.Subscription, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) <-chan *types.Head); ok {
+ r0 = rf(_a0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(<-chan *types.Head)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) commontypes.Subscription); ok {
+ r1 = rf(_a0)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(commontypes.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context) error); ok {
+ r2 = rf(_a0)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// RPCClient_SubscribeToFinalizedHeads_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeToFinalizedHeads'
+type RPCClient_SubscribeToFinalizedHeads_Call struct {
+ *mock.Call
+}
+
+// SubscribeToFinalizedHeads is a helper method to define mock.On call
+// - _a0 context.Context
+func (_e *RPCClient_Expecter) SubscribeToFinalizedHeads(_a0 interface{}) *RPCClient_SubscribeToFinalizedHeads_Call {
+ return &RPCClient_SubscribeToFinalizedHeads_Call{Call: _e.mock.On("SubscribeToFinalizedHeads", _a0)}
+}
+
+func (_c *RPCClient_SubscribeToFinalizedHeads_Call) Run(run func(_a0 context.Context)) *RPCClient_SubscribeToFinalizedHeads_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *RPCClient_SubscribeToFinalizedHeads_Call) Return(_a0 <-chan *types.Head, _a1 commontypes.Subscription, _a2 error) *RPCClient_SubscribeToFinalizedHeads_Call {
+ _c.Call.Return(_a0, _a1, _a2)
+ return _c
+}
+
+func (_c *RPCClient_SubscribeToFinalizedHeads_Call) RunAndReturn(run func(context.Context) (<-chan *types.Head, commontypes.Subscription, error)) *RPCClient_SubscribeToFinalizedHeads_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SubscribeToHeads provides a mock function with given fields: ctx
+func (_m *RPCClient) SubscribeToHeads(ctx context.Context) (<-chan *types.Head, commontypes.Subscription, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SubscribeToHeads")
+ }
+
+ var r0 <-chan *types.Head
+ var r1 commontypes.Subscription
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context) (<-chan *types.Head, commontypes.Subscription, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) <-chan *types.Head); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(<-chan *types.Head)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) commontypes.Subscription); ok {
+ r1 = rf(ctx)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(commontypes.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context) error); ok {
+ r2 = rf(ctx)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// RPCClient_SubscribeToHeads_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeToHeads'
+type RPCClient_SubscribeToHeads_Call struct {
+ *mock.Call
+}
+
+// SubscribeToHeads is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *RPCClient_Expecter) SubscribeToHeads(ctx interface{}) *RPCClient_SubscribeToHeads_Call {
+ return &RPCClient_SubscribeToHeads_Call{Call: _e.mock.On("SubscribeToHeads", ctx)}
+}
+
+func (_c *RPCClient_SubscribeToHeads_Call) Run(run func(ctx context.Context)) *RPCClient_SubscribeToHeads_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *RPCClient_SubscribeToHeads_Call) Return(ch <-chan *types.Head, sub commontypes.Subscription, err error) *RPCClient_SubscribeToHeads_Call {
+ _c.Call.Return(ch, sub, err)
+ return _c
+}
+
+func (_c *RPCClient_SubscribeToHeads_Call) RunAndReturn(run func(context.Context) (<-chan *types.Head, commontypes.Subscription, error)) *RPCClient_SubscribeToHeads_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// SubscribersCount provides a mock function with given fields:
func (_m *RPCClient) SubscribersCount() int32 {
ret := _m.Called()
diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go
index 9ab5fd135b4..07aa86fc450 100644
--- a/core/chains/evm/client/rpc_client.go
+++ b/core/chains/evm/client/rpc_client.go
@@ -2,6 +2,8 @@ package client
import (
"context"
+ "encoding/json"
+ "errors"
"fmt"
"math/big"
"net/url"
@@ -27,6 +29,7 @@ import (
commonclient "github.com/smartcontractkit/chainlink/v2/common/client"
commontypes "github.com/smartcontractkit/chainlink/v2/common/types"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype"
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"
@@ -102,6 +105,8 @@ type RPCClient interface {
GetInterceptedChainInfo() (latest, highestUserObservations commonclient.ChainInfo)
}
+const rpcSubscriptionMethodNewHeads = "newHeads"
+
type rawclient struct {
rpc *rpc.Client
geth *ethclient.Client
@@ -109,11 +114,15 @@ type rawclient struct {
}
type rpcClient struct {
- rpcLog logger.SugaredLogger
- name string
- id int32
- chainID *big.Int
- tier commonclient.NodeTier
+ rpcLog logger.SugaredLogger
+ name string
+ id int32
+ chainID *big.Int
+ tier commonclient.NodeTier
+ largePayloadRpcTimeout time.Duration
+ rpcTimeout time.Duration
+ finalizedBlockPollInterval time.Duration
+ chainType chaintype.ChainType
ws rawclient
http *rawclient
@@ -147,13 +156,22 @@ func NewRPCClient(
id int32,
chainID *big.Int,
tier commonclient.NodeTier,
+ finalizedBlockPollInterval time.Duration,
+ largePayloadRpcTimeout time.Duration,
+ rpcTimeout time.Duration,
+ chainType chaintype.ChainType,
) RPCClient {
- r := new(rpcClient)
+ r := &rpcClient{
+ largePayloadRpcTimeout: largePayloadRpcTimeout,
+ rpcTimeout: rpcTimeout,
+ chainType: chainType,
+ }
r.name = name
r.id = id
r.chainID = chainID
r.tier = tier
r.ws.uri = wsuri
+ r.finalizedBlockPollInterval = finalizedBlockPollInterval
if httpuri != nil {
r.http = &rawclient{uri: *httpuri}
}
@@ -172,7 +190,7 @@ func NewRPCClient(
// Not thread-safe, pure dial.
func (r *rpcClient) Dial(callerCtx context.Context) error {
- ctx, cancel := r.makeQueryCtx(callerCtx)
+ ctx, cancel := r.makeQueryCtx(callerCtx, r.rpcTimeout)
defer cancel()
promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc()
@@ -361,7 +379,7 @@ func (r *rpcClient) UnsubscribeAllExceptAliveLoop() {
// CallContext implementation
func (r *rpcClient) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.largePayloadRpcTimeout)
defer cancel()
lggr := r.newRqLggr().With(
"method", method,
@@ -383,8 +401,28 @@ func (r *rpcClient) CallContext(ctx context.Context, result interface{}, method
return err
}
-func (r *rpcClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+func (r *rpcClient) BatchCallContext(rootCtx context.Context, b []rpc.BatchElem) error {
+ // Astar's finality tags provide weaker finality guarantees than we require.
+ // Fetch latest finalized block using Astar's custom requests and populate it after batch request completes
+ var astarRawLatestFinalizedBlock json.RawMessage
+ var requestedFinalizedBlock bool
+ if r.chainType == chaintype.ChainAstar {
+ for _, el := range b {
+ if !isRequestingFinalizedBlock(el) {
+ continue
+ }
+
+ requestedFinalizedBlock = true
+ err := r.astarLatestFinalizedBlock(rootCtx, &astarRawLatestFinalizedBlock)
+ if err != nil {
+ return fmt.Errorf("failed to get astar latest finalized block: %w", err)
+ }
+
+ break
+ }
+ }
+
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(rootCtx, r.largePayloadRpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("nBatchElems", len(b), "batchElems", b)
@@ -399,12 +437,51 @@ func (r *rpcClient) BatchCallContext(ctx context.Context, b []rpc.BatchElem) err
duration := time.Since(start)
r.logResult(lggr, err, duration, r.getRPCDomain(), "BatchCallContext")
+ if err != nil {
+ return err
+ }
- return err
+ if r.chainType == chaintype.ChainAstar && requestedFinalizedBlock {
+ // populate requested finalized block with correct value
+ for _, el := range b {
+ if !isRequestingFinalizedBlock(el) {
+ continue
+ }
+
+ el.Error = nil
+ err = json.Unmarshal(astarRawLatestFinalizedBlock, el.Result)
+ if err != nil {
+ el.Error = fmt.Errorf("failed to unmarshal astar finalized block into provided struct: %w", err)
+ }
+ }
+ }
+
+ return nil
}
+func isRequestingFinalizedBlock(el rpc.BatchElem) bool {
+ isGetBlock := el.Method == "eth_getBlockByNumber" && len(el.Args) > 0
+ if !isGetBlock {
+ return false
+ }
+
+ if el.Args[0] == rpc.FinalizedBlockNumber {
+ return true
+ }
+
+ switch arg := el.Args[0].(type) {
+ case string:
+ return arg == rpc.FinalizedBlockNumber.String()
+ case fmt.Stringer:
+ return arg.String() == rpc.FinalizedBlockNumber.String()
+ default:
+ return false
+ }
+}
+
+// TODO: Full transition from SubscribeNewHead to SubscribeToHeads is done in BCI-2875
func (r *rpcClient) SubscribeNewHead(ctx context.Context, channel chan<- *evmtypes.Head) (_ commontypes.Subscription, err error) {
- ctx, cancel, chStopInFlight, ws, _ := r.acquireQueryCtx(ctx)
+ ctx, cancel, chStopInFlight, ws, _ := r.acquireQueryCtx(ctx, r.rpcTimeout)
defer cancel()
args := []interface{}{"newHeads"}
lggr := r.newRqLggr().With("args", args)
@@ -434,6 +511,54 @@ func (r *rpcClient) SubscribeNewHead(ctx context.Context, channel chan<- *evmtyp
return subForwarder, nil
}
+func (r *rpcClient) SubscribeToHeads(ctx context.Context) (ch <-chan *evmtypes.Head, sub commontypes.Subscription, err error) {
+ ctx, cancel, chStopInFlight, ws, _ := r.acquireQueryCtx(ctx, r.rpcTimeout)
+ defer cancel()
+
+ args := []interface{}{rpcSubscriptionMethodNewHeads}
+ start := time.Now()
+ lggr := r.newRqLggr().With("args", args)
+
+ lggr.Debug("RPC call: evmclient.Client#EthSubscribe")
+ defer func() {
+ duration := time.Since(start)
+ r.logResult(lggr, err, duration, r.getRPCDomain(), "EthSubscribe")
+ err = r.wrapWS(err)
+ }()
+
+ channel := make(chan *evmtypes.Head)
+ forwarder := newSubForwarder(channel, func(head *evmtypes.Head) *evmtypes.Head {
+ head.EVMChainID = ubig.New(r.chainID)
+ r.onNewHead(ctx, chStopInFlight, head)
+ return head
+ }, r.wrapRPCClientError)
+
+ err = forwarder.start(ws.rpc.EthSubscribe(ctx, forwarder.srcCh, args...))
+ if err != nil {
+ return nil, nil, err
+ }
+
+ err = r.registerSub(forwarder, chStopInFlight)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return channel, forwarder, err
+}
+
+func (r *rpcClient) SubscribeToFinalizedHeads(_ context.Context) (<-chan *evmtypes.Head, commontypes.Subscription, error) {
+ interval := r.finalizedBlockPollInterval
+ if interval == 0 {
+ return nil, nil, errors.New("FinalizedBlockPollInterval is 0")
+ }
+ timeout := interval
+ poller, channel := commonclient.NewPoller[*evmtypes.Head](interval, r.LatestFinalizedBlock, timeout, r.rpcLog)
+ if err := poller.Start(); err != nil {
+ return nil, nil, err
+ }
+ return channel, &poller, nil
+}
+
// GethClient wrappers
func (r *rpcClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (receipt *evmtypes.Receipt, err error) {
@@ -449,7 +574,7 @@ func (r *rpcClient) TransactionReceipt(ctx context.Context, txHash common.Hash)
}
func (r *rpcClient) TransactionReceiptGeth(ctx context.Context, txHash common.Hash) (receipt *types.Receipt, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("txHash", txHash)
@@ -472,7 +597,7 @@ func (r *rpcClient) TransactionReceiptGeth(ctx context.Context, txHash common.Ha
return
}
func (r *rpcClient) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("txHash", txHash)
@@ -496,7 +621,7 @@ func (r *rpcClient) TransactionByHash(ctx context.Context, txHash common.Hash) (
}
func (r *rpcClient) HeaderByNumber(ctx context.Context, number *big.Int) (header *types.Header, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("number", number)
@@ -517,7 +642,7 @@ func (r *rpcClient) HeaderByNumber(ctx context.Context, number *big.Int) (header
}
func (r *rpcClient) HeaderByHash(ctx context.Context, hash common.Hash) (header *types.Header, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("hash", hash)
@@ -539,17 +664,84 @@ func (r *rpcClient) HeaderByHash(ctx context.Context, hash common.Hash) (header
return
}
-func (r *rpcClient) LatestFinalizedBlock(ctx context.Context) (*evmtypes.Head, error) {
- return r.blockByNumber(ctx, rpc.FinalizedBlockNumber.String())
+func (r *rpcClient) LatestFinalizedBlock(ctx context.Context) (head *evmtypes.Head, err error) {
+ // capture chStopInFlight to ensure we are not updating chainInfo with observations related to previous life cycle
+ ctx, cancel, chStopInFlight, _, _ := r.acquireQueryCtx(ctx, r.rpcTimeout)
+ defer cancel()
+ if r.chainType == chaintype.ChainAstar {
+ // astar's finality tags provide weaker guarantee. Use their custom request to request latest finalized block
+ err = r.astarLatestFinalizedBlock(ctx, &head)
+ } else {
+ err = r.ethGetBlockByNumber(ctx, rpc.FinalizedBlockNumber.String(), &head)
+ }
+
+ if err != nil {
+ return
+ }
+
+ if head == nil {
+ err = r.wrapRPCClientError(ethereum.NotFound)
+ return
+ }
+
+ head.EVMChainID = ubig.New(r.chainID)
+
+ r.onNewFinalizedHead(ctx, chStopInFlight, head)
+ return
+}
+
+func (r *rpcClient) astarLatestFinalizedBlock(ctx context.Context, result interface{}) (err error) {
+ var hashResult string
+ err = r.CallContext(ctx, &hashResult, "chain_getFinalizedHead")
+ if err != nil {
+ return fmt.Errorf("failed to get astar latest finalized hash: %w", err)
+ }
+
+ var astarHead struct {
+ Number *hexutil.Big `json:"number"`
+ }
+ err = r.CallContext(ctx, &astarHead, "chain_getHeader", hashResult, false)
+ if err != nil {
+ return fmt.Errorf("failed to get astar head by hash: %w", err)
+ }
+
+ if astarHead.Number == nil {
+ return r.wrapRPCClientError(fmt.Errorf("expected non empty head number of finalized block"))
+ }
+
+ err = r.ethGetBlockByNumber(ctx, astarHead.Number.String(), result)
+ if err != nil {
+ return fmt.Errorf("failed to get astar finalized block: %w", err)
+ }
+
+ return nil
}
func (r *rpcClient) BlockByNumber(ctx context.Context, number *big.Int) (head *evmtypes.Head, err error) {
- hex := ToBlockNumArg(number)
- return r.blockByNumber(ctx, hex)
+ ctx, cancel, chStopInFlight, _, _ := r.acquireQueryCtx(ctx, r.rpcTimeout)
+ defer cancel()
+ hexNumber := ToBlockNumArg(number)
+ err = r.ethGetBlockByNumber(ctx, hexNumber, &head)
+ if err != nil {
+ return
+ }
+
+ if head == nil {
+ err = r.wrapRPCClientError(ethereum.NotFound)
+ return
+ }
+
+ head.EVMChainID = ubig.New(r.chainID)
+
+ if hexNumber == rpc.LatestBlockNumber.String() {
+ r.onNewHead(ctx, chStopInFlight, head)
+ }
+
+ return
}
-func (r *rpcClient) blockByNumber(ctx context.Context, number string) (head *evmtypes.Head, err error) {
- ctx, cancel, chStopInFlight, ws, http := r.acquireQueryCtx(ctx)
+func (r *rpcClient) ethGetBlockByNumber(ctx context.Context, number string, result interface{}) (err error) {
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
const method = "eth_getBlockByNumber"
args := []interface{}{number, false}
@@ -561,30 +753,14 @@ func (r *rpcClient) blockByNumber(ctx context.Context, number string) (head *evm
lggr.Debug("RPC call: evmclient.Client#CallContext")
start := time.Now()
if http != nil {
- err = r.wrapHTTP(http.rpc.CallContext(ctx, &head, method, args...))
+ err = r.wrapHTTP(http.rpc.CallContext(ctx, result, method, args...))
} else {
- err = r.wrapWS(ws.rpc.CallContext(ctx, &head, method, args...))
+ err = r.wrapWS(ws.rpc.CallContext(ctx, result, method, args...))
}
duration := time.Since(start)
r.logResult(lggr, err, duration, r.getRPCDomain(), "CallContext")
- if err != nil {
- return nil, err
- }
- if head == nil {
- err = r.wrapRPCClientError(ethereum.NotFound)
- return
- }
- head.EVMChainID = ubig.New(r.chainID)
-
- switch number {
- case rpc.FinalizedBlockNumber.String():
- r.onNewFinalizedHead(ctx, chStopInFlight, head)
- case rpc.LatestBlockNumber.String():
- r.onNewHead(ctx, chStopInFlight, head)
- }
-
- return
+ return err
}
func (r *rpcClient) BlockByHash(ctx context.Context, hash common.Hash) (head *evmtypes.Head, err error) {
@@ -601,7 +777,7 @@ func (r *rpcClient) BlockByHash(ctx context.Context, hash common.Hash) (head *ev
}
func (r *rpcClient) BlockByHashGeth(ctx context.Context, hash common.Hash) (block *types.Block, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("hash", hash)
@@ -624,7 +800,7 @@ func (r *rpcClient) BlockByHashGeth(ctx context.Context, hash common.Hash) (bloc
}
func (r *rpcClient) BlockByNumberGeth(ctx context.Context, number *big.Int) (block *types.Block, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("number", number)
@@ -647,7 +823,7 @@ func (r *rpcClient) BlockByNumberGeth(ctx context.Context, number *big.Int) (blo
}
func (r *rpcClient) SendTransaction(ctx context.Context, tx *types.Transaction) error {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.largePayloadRpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("tx", tx)
@@ -685,7 +861,7 @@ func (r *rpcClient) SendEmptyTransaction(
// PendingSequenceAt returns one higher than the highest nonce from both mempool and mined transactions
func (r *rpcClient) PendingSequenceAt(ctx context.Context, account common.Address) (nonce evmtypes.Nonce, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("account", account)
@@ -714,7 +890,7 @@ func (r *rpcClient) PendingSequenceAt(ctx context.Context, account common.Addres
// mined nonce at the given block number, but it actually returns the total
// transaction count which is the highest mined nonce + 1
func (r *rpcClient) SequenceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (nonce evmtypes.Nonce, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber)
@@ -740,7 +916,7 @@ func (r *rpcClient) SequenceAt(ctx context.Context, account common.Address, bloc
}
func (r *rpcClient) PendingCodeAt(ctx context.Context, account common.Address) (code []byte, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("account", account)
@@ -763,7 +939,7 @@ func (r *rpcClient) PendingCodeAt(ctx context.Context, account common.Address) (
}
func (r *rpcClient) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) (code []byte, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber)
@@ -786,7 +962,7 @@ func (r *rpcClient) CodeAt(ctx context.Context, account common.Address, blockNum
}
func (r *rpcClient) EstimateGas(ctx context.Context, c interface{}) (gas uint64, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.largePayloadRpcTimeout)
defer cancel()
call := c.(ethereum.CallMsg)
lggr := r.newRqLggr().With("call", call)
@@ -810,7 +986,7 @@ func (r *rpcClient) EstimateGas(ctx context.Context, c interface{}) (gas uint64,
}
func (r *rpcClient) SuggestGasPrice(ctx context.Context) (price *big.Int, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr()
@@ -833,7 +1009,7 @@ func (r *rpcClient) SuggestGasPrice(ctx context.Context) (price *big.Int, err er
}
func (r *rpcClient) CallContract(ctx context.Context, msg interface{}, blockNumber *big.Int) (val []byte, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.largePayloadRpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("callMsg", msg, "blockNumber", blockNumber)
message := msg.(ethereum.CallMsg)
@@ -861,7 +1037,7 @@ func (r *rpcClient) CallContract(ctx context.Context, msg interface{}, blockNumb
}
func (r *rpcClient) PendingCallContract(ctx context.Context, msg interface{}) (val []byte, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.largePayloadRpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("callMsg", msg)
message := msg.(ethereum.CallMsg)
@@ -895,7 +1071,7 @@ func (r *rpcClient) LatestBlockHeight(ctx context.Context) (*big.Int, error) {
}
func (r *rpcClient) BlockNumber(ctx context.Context) (height uint64, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr()
@@ -918,7 +1094,7 @@ func (r *rpcClient) BlockNumber(ctx context.Context) (height uint64, err error)
}
func (r *rpcClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (balance *big.Int, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("account", account.Hex(), "blockNumber", blockNumber)
@@ -983,7 +1159,7 @@ func (r *rpcClient) FilterEvents(ctx context.Context, q ethereum.FilterQuery) ([
}
func (r *rpcClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) (l []types.Log, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("q", q)
@@ -1011,7 +1187,7 @@ func (r *rpcClient) ClientVersion(ctx context.Context) (version string, err erro
}
func (r *rpcClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (_ ethereum.Subscription, err error) {
- ctx, cancel, chStopInFlight, ws, _ := r.acquireQueryCtx(ctx)
+ ctx, cancel, chStopInFlight, ws, _ := r.acquireQueryCtx(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("q", q)
@@ -1037,7 +1213,7 @@ func (r *rpcClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQu
}
func (r *rpcClient) SuggestGasTipCap(ctx context.Context) (tipCap *big.Int, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr()
@@ -1062,7 +1238,7 @@ func (r *rpcClient) SuggestGasTipCap(ctx context.Context) (tipCap *big.Int, err
// Returns the ChainID according to the geth client. This is useful for functions like verify()
// the common node.
func (r *rpcClient) ChainID(ctx context.Context) (chainID *big.Int, err error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
@@ -1117,12 +1293,12 @@ func (r *rpcClient) wrapHTTP(err error) error {
}
// makeLiveQueryCtxAndSafeGetClients wraps makeQueryCtx
-func (r *rpcClient) makeLiveQueryCtxAndSafeGetClients(parentCtx context.Context) (ctx context.Context, cancel context.CancelFunc, ws rawclient, http *rawclient) {
- ctx, cancel, _, ws, http = r.acquireQueryCtx(parentCtx)
+func (r *rpcClient) makeLiveQueryCtxAndSafeGetClients(parentCtx context.Context, timeout time.Duration) (ctx context.Context, cancel context.CancelFunc, ws rawclient, http *rawclient) {
+ ctx, cancel, _, ws, http = r.acquireQueryCtx(parentCtx, timeout)
return
}
-func (r *rpcClient) acquireQueryCtx(parentCtx context.Context) (ctx context.Context, cancel context.CancelFunc,
+func (r *rpcClient) acquireQueryCtx(parentCtx context.Context, timeout time.Duration) (ctx context.Context, cancel context.CancelFunc,
chStopInFlight chan struct{}, ws rawclient, http *rawclient) {
// Need to wrap in mutex because state transition can cancel and replace the
// context
@@ -1134,7 +1310,7 @@ func (r *rpcClient) acquireQueryCtx(parentCtx context.Context) (ctx context.Cont
http = &cp
}
r.stateMu.RUnlock()
- ctx, cancel = makeQueryCtx(parentCtx, chStopInFlight)
+ ctx, cancel = makeQueryCtx(parentCtx, chStopInFlight, timeout)
return
}
@@ -1142,10 +1318,10 @@ func (r *rpcClient) acquireQueryCtx(parentCtx context.Context) (ctx context.Cont
// 1. Passed in ctx cancels
// 2. Passed in channel is closed
// 3. Default timeout is reached (queryTimeout)
-func makeQueryCtx(ctx context.Context, ch services.StopChan) (context.Context, context.CancelFunc) {
+func makeQueryCtx(ctx context.Context, ch services.StopChan, timeout time.Duration) (context.Context, context.CancelFunc) {
var chCancel, timeoutCancel context.CancelFunc
ctx, chCancel = ch.Ctx(ctx)
- ctx, timeoutCancel = context.WithTimeout(ctx, queryTimeout)
+ ctx, timeoutCancel = context.WithTimeout(ctx, timeout)
cancel := func() {
chCancel()
timeoutCancel()
@@ -1153,12 +1329,12 @@ func makeQueryCtx(ctx context.Context, ch services.StopChan) (context.Context, c
return ctx, cancel
}
-func (r *rpcClient) makeQueryCtx(ctx context.Context) (context.Context, context.CancelFunc) {
- return makeQueryCtx(ctx, r.getChStopInflight())
+func (r *rpcClient) makeQueryCtx(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
+ return makeQueryCtx(ctx, r.getChStopInflight(), timeout)
}
func (r *rpcClient) IsSyncing(ctx context.Context) (bool, error) {
- ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx)
+ ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr()
diff --git a/core/chains/evm/client/rpc_client_test.go b/core/chains/evm/client/rpc_client_test.go
index 682c4352457..12821880996 100644
--- a/core/chains/evm/client/rpc_client_test.go
+++ b/core/chains/evm/client/rpc_client_test.go
@@ -3,13 +3,16 @@ package client_test
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"math/big"
"net/url"
"testing"
+ "time"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
@@ -21,6 +24,7 @@ import (
commonclient "github.com/smartcontractkit/chainlink/v2/common/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/testutils"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
)
@@ -56,7 +60,7 @@ func TestRPCClient_SubscribeNewHead(t *testing.T) {
server := testutils.NewWSServer(t, chainId, serverCallBack)
wsURL := server.WSURL()
- rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary)
+ rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
defer rpc.Close()
require.NoError(t, rpc.Dial(ctx))
// set to default values
@@ -106,7 +110,7 @@ func TestRPCClient_SubscribeNewHead(t *testing.T) {
server := testutils.NewWSServer(t, chainId, serverCallBack)
wsURL := server.WSURL()
- rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary)
+ rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
defer rpc.Close()
require.NoError(t, rpc.Dial(ctx))
ch := make(chan *evmtypes.Head)
@@ -129,7 +133,7 @@ func TestRPCClient_SubscribeNewHead(t *testing.T) {
t.Run("Block's chain ID matched configured", func(t *testing.T) {
server := testutils.NewWSServer(t, chainId, serverCallBack)
wsURL := server.WSURL()
- rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary)
+ rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
defer rpc.Close()
require.NoError(t, rpc.Dial(ctx))
ch := make(chan *evmtypes.Head)
@@ -146,7 +150,7 @@ func TestRPCClient_SubscribeNewHead(t *testing.T) {
})
wsURL := server.WSURL()
observedLggr, observed := logger.TestObserved(t, zap.DebugLevel)
- rpc := client.NewRPCClient(observedLggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary)
+ rpc := client.NewRPCClient(observedLggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
require.NoError(t, rpc.Dial(ctx))
server.Close()
_, err := rpc.SubscribeNewHead(ctx, make(chan *evmtypes.Head))
@@ -156,7 +160,7 @@ func TestRPCClient_SubscribeNewHead(t *testing.T) {
t.Run("Subscription error is properly wrapper", func(t *testing.T) {
server := testutils.NewWSServer(t, chainId, serverCallBack)
wsURL := server.WSURL()
- rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary)
+ rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
defer rpc.Close()
require.NoError(t, rpc.Dial(ctx))
sub, err := rpc.SubscribeNewHead(ctx, make(chan *evmtypes.Head))
@@ -184,7 +188,7 @@ func TestRPCClient_SubscribeFilterLogs(t *testing.T) {
})
wsURL := server.WSURL()
observedLggr, observed := logger.TestObserved(t, zap.DebugLevel)
- rpc := client.NewRPCClient(observedLggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary)
+ rpc := client.NewRPCClient(observedLggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
require.NoError(t, rpc.Dial(ctx))
server.Close()
_, err := rpc.SubscribeFilterLogs(ctx, ethereum.FilterQuery{}, make(chan types.Log))
@@ -201,7 +205,7 @@ func TestRPCClient_SubscribeFilterLogs(t *testing.T) {
return resp
})
wsURL := server.WSURL()
- rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary)
+ rpc := client.NewRPCClient(lggr, *wsURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
defer rpc.Close()
require.NoError(t, rpc.Dial(ctx))
sub, err := rpc.SubscribeFilterLogs(ctx, ethereum.FilterQuery{}, make(chan types.Log))
@@ -250,7 +254,7 @@ func TestRPCClient_LatestFinalizedBlock(t *testing.T) {
}
server := createRPCServer()
- rpc := client.NewRPCClient(lggr, *server.URL, nil, "rpc", 1, chainId, commonclient.Primary)
+ rpc := client.NewRPCClient(lggr, *server.URL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "")
require.NoError(t, rpc.Dial(ctx))
defer rpc.Close()
server.Head = &evmtypes.Head{Number: 128}
@@ -298,3 +302,168 @@ func TestRPCClient_LatestFinalizedBlock(t *testing.T) {
assert.Equal(t, int64(0), latest.BlockNumber)
assert.Equal(t, int64(0), latest.FinalizedBlockNumber)
}
+
+func TestRpcClientLargePayloadTimeout(t *testing.T) {
+ t.Parallel()
+
+ testCases := []struct {
+ Name string
+ Fn func(ctx context.Context, rpc client.RPCClient) error
+ }{
+ {
+ Name: "SendTransaction",
+ Fn: func(ctx context.Context, rpc client.RPCClient) error {
+ return rpc.SendTransaction(ctx, types.NewTx(&types.LegacyTx{}))
+ },
+ },
+ {
+ Name: "EstimateGas",
+ Fn: func(ctx context.Context, rpc client.RPCClient) error {
+ _, err := rpc.EstimateGas(ctx, ethereum.CallMsg{})
+ return err
+ },
+ },
+ {
+ Name: "CallContract",
+ Fn: func(ctx context.Context, rpc client.RPCClient) error {
+ _, err := rpc.CallContract(ctx, ethereum.CallMsg{}, nil)
+ return err
+ },
+ },
+ {
+ Name: "CallContext",
+ Fn: func(ctx context.Context, rpc client.RPCClient) error {
+ err := rpc.CallContext(ctx, nil, "rpc_call", nil)
+ return err
+ },
+ },
+ {
+ Name: "BatchCallContext",
+ Fn: func(ctx context.Context, rpc client.RPCClient) error {
+ err := rpc.BatchCallContext(ctx, nil)
+ return err
+ },
+ },
+ }
+ for _, testCase := range testCases {
+ testCase := testCase
+ t.Run(testCase.Name, func(t *testing.T) {
+ t.Parallel()
+ // use background context to ensure that the DeadlineExceeded is caused by timeout we've set on request
+ // level, instead of one that was set on test level.
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ chainId := big.NewInt(123456)
+ rpcURL := testutils.NewWSServer(t, chainId, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) {
+ // block until test is done
+ <-ctx.Done()
+ return
+ }).WSURL()
+
+ // use something unreasonably large for RPC timeout to ensure that we use largePayloadRPCTimeout
+ const rpcTimeout = time.Hour
+ const largePayloadRPCTimeout = tests.TestInterval
+ rpc := client.NewRPCClient(logger.Test(t), *rpcURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, largePayloadRPCTimeout, rpcTimeout, "")
+ require.NoError(t, rpc.Dial(ctx))
+ defer rpc.Close()
+ err := testCase.Fn(ctx, rpc)
+ assert.True(t, errors.Is(err, context.DeadlineExceeded), fmt.Sprintf("Expected DedlineExceeded error, but got: %v", err))
+ })
+ }
+}
+
+func TestAstarCustomFinality(t *testing.T) {
+ t.Parallel()
+
+ chainId := big.NewInt(123456)
+ // create new server that returns 4 block for Astar custom finality and 8 block for finality tag.
+ wsURL := testutils.NewWSServer(t, chainId, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) {
+ switch method {
+ case "chain_getFinalizedHead":
+ resp.Result = `"0xf14c499253fd7bbcba142e5dd77dad8b5ad598c1dc414a66bacdd8dae14a6759"`
+ case "chain_getHeader":
+ if assert.True(t, params.IsArray()) && assert.Equal(t, "0xf14c499253fd7bbcba142e5dd77dad8b5ad598c1dc414a66bacdd8dae14a6759", params.Array()[0].String()) {
+ resp.Result = `{"parentHash":"0x1311773bc6b4efc8f438ed1f094524b2a1233baf8a35396f641fcc42a378fc62","number":"0x4","stateRoot":"0x0e4920dc5516b587e1f74a0b65963134523a12cc11478bb314e52895758fbfa2","extrinsicsRoot":"0x5b02446dcab0659eb07d4a38f28f181c1b78a71b2aba207bb0ea1f0f3468e6bd","digest":{"logs":["0x066175726120ad678e0800000000","0x04525053529023158dc8e8fd0180bf26d88233a3d94eed2f4e43480395f0809f28791965e4d34e9b3905","0x0466726f6e88017441e97acf83f555e0deefef86db636bc8a37eb84747603412884e4df4d2280400","0x056175726101018a0a57edf70cc5474323114a47ee1e7f645b8beea5a1560a996416458e89f42bdf4955e24d32b5da54e1bf628aaa7ce4b8c0fa2b95c175a139d88786af12a88c"]}}`
+ }
+ case "eth_getBlockByNumber":
+ assert.True(t, params.IsArray())
+ switch params.Array()[0].String() {
+ case "0x4":
+ resp.Result = `{"author":"0x5accb3bf9194a5f81b2087d4bd6ac47c62775d49","baseFeePerGas":"0xb576270823","difficulty":"0x0","extraData":"0x","gasLimit":"0xe4e1c0","gasUsed":"0x0","hash":"0x7441e97acf83f555e0deefef86db636bc8a37eb84747603412884e4df4d22804","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x5accb3bf9194a5f81b2087d4bd6ac47c62775d49","nonce":"0x0000000000000000","number":"0x4","parentHash":"0x6ba069c318b692bf2cc0bd7ea070a9382a20c2f52413c10554b57c2e381bf2bb","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x201","stateRoot":"0x17c46d359b9af773312c747f1d20032c67658d9a2923799f00533b73789cf49b","timestamp":"0x66acdc22","totalDifficulty":"0x0","transactions":[],"transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","uncles":[]}`
+ case "finalized":
+ resp.Result = `{"author":"0x1687736326c9fea17e25fc5287613693c912909c","baseFeePerGas":"0x3b9aca00","difficulty":"0x0","extraData":"0x","gasLimit":"0xe4e1c0","gasUsed":"0x0","hash":"0x62f03413681948b06882e7d9f91c4949bc39ded98d36336ab03faea038ec8e3d","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0x1687736326c9fea17e25fc5287613693c912909c","nonce":"0x0000000000000000","number":"0x8","parentHash":"0x43f504afdc639cbb8daf5fd5328a37762164b73f9c70ed54e1928c1fca6d8f23","receiptsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0x200","stateRoot":"0x0cb938d51ad83bdf401e3f5f7f989e60df64fdea620d394af41a3e72629f7495","timestamp":"0x61bd8d1a","totalDifficulty":"0x0","transactions":[],"transactionsRoot":"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421","uncles":[]}`
+ default:
+ assert.Fail(t, fmt.Sprintf("unexpected eth_getBlockByNumber param: %v", params.Array()))
+ }
+ default:
+ assert.Fail(t, fmt.Sprintf("unexpected method: %s", method))
+ }
+ return
+ }).WSURL()
+
+ const expectedFinalizedBlockNumber = int64(4)
+ const expectedFinalizedBlockHash = "0x7441e97acf83f555e0deefef86db636bc8a37eb84747603412884e4df4d22804"
+ rpcClient := client.NewRPCClient(logger.Test(t), *wsURL, nil, "rpc", 1, chainId, commonclient.Primary, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, chaintype.ChainAstar)
+ defer rpcClient.Close()
+ err := rpcClient.Dial(tests.Context(t))
+ require.NoError(t, err)
+
+ testCases := []struct {
+ Name string
+ GetLatestFinalized func(ctx context.Context) (*evmtypes.Head, error)
+ }{
+ {
+ Name: "Direct LatestFinalized call",
+ GetLatestFinalized: func(ctx context.Context) (*evmtypes.Head, error) {
+ return rpcClient.LatestFinalizedBlock(ctx)
+ },
+ },
+ {
+ Name: "BatchCallContext with Finalized tag as string",
+ GetLatestFinalized: func(ctx context.Context) (*evmtypes.Head, error) {
+ result := &evmtypes.Head{}
+ req := rpc.BatchElem{
+ Method: "eth_getBlockByNumber",
+ Args: []interface{}{rpc.FinalizedBlockNumber.String(), false},
+ Result: result,
+ }
+ err := rpcClient.BatchCallContext(ctx, []rpc.BatchElem{
+ req,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return result, req.Error
+ },
+ },
+ {
+ Name: "BatchCallContext with Finalized tag as BlockNumber",
+ GetLatestFinalized: func(ctx context.Context) (*evmtypes.Head, error) {
+ result := &evmtypes.Head{}
+ req := rpc.BatchElem{
+ Method: "eth_getBlockByNumber",
+ Args: []interface{}{rpc.FinalizedBlockNumber, false},
+ Result: result,
+ }
+ err := rpcClient.BatchCallContext(ctx, []rpc.BatchElem{req})
+ if err != nil {
+ return nil, err
+ }
+
+ return result, req.Error
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.Name, func(t *testing.T) {
+ lf, err := testCase.GetLatestFinalized(tests.Context(t))
+ require.NoError(t, err)
+ require.NotNil(t, lf)
+ assert.Equal(t, expectedFinalizedBlockHash, lf.Hash.String())
+ assert.Equal(t, expectedFinalizedBlockNumber, lf.Number)
+ })
+ }
+}
diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go
index 6bcc1f36960..7dfd39f444c 100644
--- a/core/chains/evm/client/simulated_backend_client.go
+++ b/core/chains/evm/client/simulated_backend_client.go
@@ -360,9 +360,18 @@ func (c *SimulatedBackendClient) SendTransactionReturnCode(ctx context.Context,
// SendTransaction sends a transaction.
func (c *SimulatedBackendClient) SendTransaction(ctx context.Context, tx *types.Transaction) error {
- sender, err := types.Sender(types.NewLondonSigner(c.chainId), tx)
+ var (
+ sender common.Address
+ err error
+ )
+ // try to recover the sender from the transaction using the configured chain id
+ // first. if that fails, try again with the simulated chain id (1337)
+ sender, err = types.Sender(types.NewLondonSigner(c.chainId), tx)
if err != nil {
- logger.Test(c.t).Panic(fmt.Errorf("invalid transaction: %v (tx: %#v)", err, tx))
+ sender, err = types.Sender(types.NewLondonSigner(big.NewInt(1337)), tx)
+ if err != nil {
+ logger.Test(c.t).Panic(fmt.Errorf("invalid transaction: %v (tx: %#v)", err, tx))
+ }
}
pendingNonce, err := c.b.PendingNonceAt(ctx, sender)
if err != nil {
diff --git a/core/chains/evm/config/chain_scoped.go b/core/chains/evm/config/chain_scoped.go
index db598e3e82b..b9b19cdc2c0 100644
--- a/core/chains/evm/config/chain_scoped.go
+++ b/core/chains/evm/config/chain_scoped.go
@@ -183,3 +183,7 @@ func (e *EVMConfig) LogPrunePageSize() uint32 {
func (e *EVMConfig) FinalizedBlockOffset() uint32 {
return *e.C.FinalizedBlockOffset
}
+
+func (e *EVMConfig) NoNewFinalizedHeadsThreshold() time.Duration {
+ return e.C.NoNewFinalizedHeadsThreshold.Duration()
+}
diff --git a/core/chains/evm/config/chain_scoped_gas_estimator.go b/core/chains/evm/config/chain_scoped_gas_estimator.go
index 689d5e38b81..4f2d8872d8c 100644
--- a/core/chains/evm/config/chain_scoped_gas_estimator.go
+++ b/core/chains/evm/config/chain_scoped_gas_estimator.go
@@ -108,6 +108,10 @@ func (g *gasEstimatorConfig) LimitJobType() LimitJobType {
return &limitJobTypeConfig{c: g.c.LimitJobType}
}
+func (g *gasEstimatorConfig) EstimateGasLimit() bool {
+ return *g.c.EstimateGasLimit
+}
+
type limitJobTypeConfig struct {
c toml.GasLimitJobType
}
diff --git a/core/chains/evm/config/chain_scoped_transactions.go b/core/chains/evm/config/chain_scoped_transactions.go
index 87031a4c66e..27edb12648a 100644
--- a/core/chains/evm/config/chain_scoped_transactions.go
+++ b/core/chains/evm/config/chain_scoped_transactions.go
@@ -47,12 +47,12 @@ func (a *autoPurgeConfig) Enabled() bool {
return *a.c.Enabled
}
-func (a *autoPurgeConfig) Threshold() uint32 {
- return *a.c.Threshold
+func (a *autoPurgeConfig) Threshold() *uint32 {
+ return a.c.Threshold
}
-func (a *autoPurgeConfig) MinAttempts() uint32 {
- return *a.c.MinAttempts
+func (a *autoPurgeConfig) MinAttempts() *uint32 {
+ return a.c.MinAttempts
}
func (a *autoPurgeConfig) DetectionApiUrl() *url.URL {
diff --git a/core/chains/evm/config/chaintype/chaintype.go b/core/chains/evm/config/chaintype/chaintype.go
index 9b845969e4b..35dd214b1f5 100644
--- a/core/chains/evm/config/chaintype/chaintype.go
+++ b/core/chains/evm/config/chaintype/chaintype.go
@@ -9,9 +9,12 @@ type ChainType string
const (
ChainArbitrum ChainType = "arbitrum"
+ ChainAstar ChainType = "astar"
ChainCelo ChainType = "celo"
ChainGnosis ChainType = "gnosis"
+ ChainHedera ChainType = "hedera"
ChainKroma ChainType = "kroma"
+ ChainMantle ChainType = "mantle"
ChainMetis ChainType = "metis"
ChainOptimismBedrock ChainType = "optimismBedrock"
ChainScroll ChainType = "scroll"
@@ -35,7 +38,7 @@ func (c ChainType) IsL2() bool {
func (c ChainType) IsValid() bool {
switch c {
- case "", ChainArbitrum, ChainCelo, ChainGnosis, ChainKroma, ChainMetis, ChainOptimismBedrock, ChainScroll, ChainWeMix, ChainXLayer, ChainZkEvm, ChainZkSync:
+ case "", ChainArbitrum, ChainAstar, ChainCelo, ChainGnosis, ChainHedera, ChainKroma, ChainMantle, ChainMetis, ChainOptimismBedrock, ChainScroll, ChainWeMix, ChainXLayer, ChainZkEvm, ChainZkSync:
return true
}
return false
@@ -45,12 +48,18 @@ func ChainTypeFromSlug(slug string) ChainType {
switch slug {
case "arbitrum":
return ChainArbitrum
+ case "astar":
+ return ChainAstar
case "celo":
return ChainCelo
case "gnosis":
return ChainGnosis
+ case "hedera":
+ return ChainHedera
case "kroma":
return ChainKroma
+ case "mantle":
+ return ChainMantle
case "metis":
return ChainMetis
case "optimismBedrock":
@@ -118,9 +127,12 @@ func (c *ChainTypeConfig) String() string {
var ErrInvalidChainType = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{
string(ChainArbitrum),
+ string(ChainAstar),
string(ChainCelo),
string(ChainGnosis),
+ string(ChainHedera),
string(ChainKroma),
+ string(ChainMantle),
string(ChainMetis),
string(ChainOptimismBedrock),
string(ChainScroll),
diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go
index ea0d52f5705..9517c68716f 100644
--- a/core/chains/evm/config/config.go
+++ b/core/chains/evm/config/config.go
@@ -46,6 +46,7 @@ type EVM interface {
RPCDefaultBatchSize() uint32
NodeNoNewHeadsThreshold() time.Duration
FinalizedBlockOffset() uint32
+ NoNewFinalizedHeadsThreshold() time.Duration
IsEnabled() bool
TOMLString() (string, error)
@@ -109,8 +110,8 @@ type Transactions interface {
type AutoPurgeConfig interface {
Enabled() bool
- Threshold() uint32
- MinAttempts() uint32
+ Threshold() *uint32
+ MinAttempts() *uint32
DetectionApiUrl() *url.URL
}
@@ -135,6 +136,7 @@ type GasEstimator interface {
PriceMin() *assets.Wei
Mode() string
PriceMaxKey(gethcommon.Address) *assets.Wei
+ EstimateGasLimit() bool
}
type LimitJobType interface {
diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go
index b8e813e8068..40c10757b85 100644
--- a/core/chains/evm/config/mocks/gas_estimator.go
+++ b/core/chains/evm/config/mocks/gas_estimator.go
@@ -298,6 +298,51 @@ func (_c *GasEstimator_EIP1559DynamicFees_Call) RunAndReturn(run func() bool) *G
return _c
}
+// EstimateGasLimit provides a mock function with given fields:
+func (_m *GasEstimator) EstimateGasLimit() bool {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for EstimateGasLimit")
+ }
+
+ var r0 bool
+ if rf, ok := ret.Get(0).(func() bool); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ return r0
+}
+
+// GasEstimator_EstimateGasLimit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EstimateGasLimit'
+type GasEstimator_EstimateGasLimit_Call struct {
+ *mock.Call
+}
+
+// EstimateGasLimit is a helper method to define mock.On call
+func (_e *GasEstimator_Expecter) EstimateGasLimit() *GasEstimator_EstimateGasLimit_Call {
+ return &GasEstimator_EstimateGasLimit_Call{Call: _e.mock.On("EstimateGasLimit")}
+}
+
+func (_c *GasEstimator_EstimateGasLimit_Call) Run(run func()) *GasEstimator_EstimateGasLimit_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *GasEstimator_EstimateGasLimit_Call) Return(_a0 bool) *GasEstimator_EstimateGasLimit_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *GasEstimator_EstimateGasLimit_Call) RunAndReturn(run func() bool) *GasEstimator_EstimateGasLimit_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// FeeCapDefault provides a mock function with given fields:
func (_m *GasEstimator) FeeCapDefault() *assets.Wei {
ret := _m.Called()
diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go
index 3e35bb4b55c..99e61a394ba 100644
--- a/core/chains/evm/config/toml/config.go
+++ b/core/chains/evm/config/toml/config.go
@@ -338,27 +338,28 @@ func (c *EVMConfig) TOMLString() (string, error) {
}
type Chain struct {
- AutoCreateKey *bool
- BlockBackfillDepth *uint32
- BlockBackfillSkip *bool
- ChainType *chaintype.ChainTypeConfig
- FinalityDepth *uint32
- FinalityTagEnabled *bool
- FlagsContractAddress *types.EIP55Address
- LinkContractAddress *types.EIP55Address
- LogBackfillBatchSize *uint32
- LogPollInterval *commonconfig.Duration
- LogKeepBlocksDepth *uint32
- LogPrunePageSize *uint32
- BackupLogPollerBlockDelay *uint64
- MinIncomingConfirmations *uint32
- MinContractPayment *commonassets.Link
- NonceAutoSync *bool
- NoNewHeadsThreshold *commonconfig.Duration
- OperatorFactoryAddress *types.EIP55Address
- RPCDefaultBatchSize *uint32
- RPCBlockQueryDelay *uint16
- FinalizedBlockOffset *uint32
+ AutoCreateKey *bool
+ BlockBackfillDepth *uint32
+ BlockBackfillSkip *bool
+ ChainType *chaintype.ChainTypeConfig
+ FinalityDepth *uint32
+ FinalityTagEnabled *bool
+ FlagsContractAddress *types.EIP55Address
+ LinkContractAddress *types.EIP55Address
+ LogBackfillBatchSize *uint32
+ LogPollInterval *commonconfig.Duration
+ LogKeepBlocksDepth *uint32
+ LogPrunePageSize *uint32
+ BackupLogPollerBlockDelay *uint64
+ MinIncomingConfirmations *uint32
+ MinContractPayment *commonassets.Link
+ NonceAutoSync *bool
+ NoNewHeadsThreshold *commonconfig.Duration
+ OperatorFactoryAddress *types.EIP55Address
+ RPCDefaultBatchSize *uint32
+ RPCBlockQueryDelay *uint16
+ FinalizedBlockOffset *uint32
+ NoNewFinalizedHeadsThreshold *commonconfig.Duration
Transactions Transactions `toml:",omitempty"`
BalanceMonitor BalanceMonitor `toml:",omitempty"`
@@ -411,8 +412,16 @@ func (c *Chain) ValidateConfig() (err error) {
err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Transactions.AutoPurge.DetectionApiUrl", Value: c.Transactions.AutoPurge.DetectionApiUrl.Scheme, Msg: "must be http or https"})
}
}
- case chaintype.ChainZkEvm:
- // No other configs are needed
+ case chaintype.ChainZkEvm, chaintype.ChainXLayer:
+ // MinAttempts is an optional config that can be used to delay the stuck tx detection for zkEVM or XLayer
+ // If MinAttempts is set, BumpThreshold cannot be 0
+ if c.Transactions.AutoPurge.MinAttempts != nil && *c.Transactions.AutoPurge.MinAttempts != 0 {
+ if c.GasEstimator.BumpThreshold == nil {
+ err = multierr.Append(err, commonconfig.ErrMissing{Name: "GasEstimator.BumpThreshold", Msg: fmt.Sprintf("must be set if Transactions.AutoPurge.MinAttempts is set for %s", chainType)})
+ } else if *c.GasEstimator.BumpThreshold == 0 {
+ err = multierr.Append(err, commonconfig.ErrInvalid{Name: "GasEstimator.BumpThreshold", Value: 0, Msg: fmt.Sprintf("cannot be 0 if Transactions.AutoPurge.MinAttempts is set for %s", chainType)})
+ }
+ }
default:
// Bump Threshold is required because the stuck tx heuristic relies on a minimum number of bump attempts to exist
if c.GasEstimator.BumpThreshold == nil {
@@ -540,11 +549,12 @@ type GasEstimator struct {
PriceMax *assets.Wei
PriceMin *assets.Wei
- LimitDefault *uint64
- LimitMax *uint64
- LimitMultiplier *decimal.Decimal
- LimitTransfer *uint64
- LimitJobType GasLimitJobType `toml:",omitempty"`
+ LimitDefault *uint64
+ LimitMax *uint64
+ LimitMultiplier *decimal.Decimal
+ LimitTransfer *uint64
+ LimitJobType GasLimitJobType `toml:",omitempty"`
+ EstimateGasLimit *bool
BumpMin *assets.Wei
BumpPercent *uint16
@@ -632,6 +642,9 @@ func (e *GasEstimator) setFrom(f *GasEstimator) {
if v := f.LimitTransfer; v != nil {
e.LimitTransfer = v
}
+ if v := f.EstimateGasLimit; v != nil {
+ e.EstimateGasLimit = v
+ }
if v := f.PriceDefault; v != nil {
e.PriceDefault = v
}
diff --git a/core/chains/evm/config/toml/defaults.go b/core/chains/evm/config/toml/defaults.go
index 38eef40bf76..c3f087da8c5 100644
--- a/core/chains/evm/config/toml/defaults.go
+++ b/core/chains/evm/config/toml/defaults.go
@@ -165,6 +165,10 @@ func (c *Chain) SetFrom(f *Chain) {
c.FinalizedBlockOffset = v
}
+ if v := f.NoNewFinalizedHeadsThreshold; v != nil {
+ c.NoNewFinalizedHeadsThreshold = v
+ }
+
c.Transactions.setFrom(&f.Transactions)
c.BalanceMonitor.setFrom(&f.BalanceMonitor)
c.GasEstimator.setFrom(&f.GasEstimator)
diff --git a/core/chains/evm/config/toml/defaults/Avalanche_Fuji.toml b/core/chains/evm/config/toml/defaults/Avalanche_Fuji.toml
index d7cbad8157c..882a91f1acc 100644
--- a/core/chains/evm/config/toml/defaults/Avalanche_Fuji.toml
+++ b/core/chains/evm/config/toml/defaults/Avalanche_Fuji.toml
@@ -6,6 +6,7 @@ MinIncomingConfirmations = 1
NoNewHeadsThreshold = '30s'
OCR.ContractConfirmations = 1
RPCBlockQueryDelay = 2
+NoNewFinalizedHeadsThreshold = '1m'
[GasEstimator]
PriceDefault = '25 gwei'
diff --git a/core/chains/evm/config/toml/defaults/Avalanche_Mainnet.toml b/core/chains/evm/config/toml/defaults/Avalanche_Mainnet.toml
index 95d4bf75460..78d3bbba77a 100644
--- a/core/chains/evm/config/toml/defaults/Avalanche_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/Avalanche_Mainnet.toml
@@ -6,6 +6,7 @@ MinIncomingConfirmations = 1
NoNewHeadsThreshold = '30s'
OCR.ContractConfirmations = 1
RPCBlockQueryDelay = 2
+NoNewFinalizedHeadsThreshold = '1m'
[GasEstimator]
PriceDefault = '25 gwei'
diff --git a/core/chains/evm/config/toml/defaults/BSC_Mainnet.toml b/core/chains/evm/config/toml/defaults/BSC_Mainnet.toml
index 384a798e32a..1b248a8c451 100644
--- a/core/chains/evm/config/toml/defaults/BSC_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/BSC_Mainnet.toml
@@ -6,6 +6,7 @@ LinkContractAddress = '0x404460C6A5EdE2D891e8297795264fDe62ADBB75'
LogPollInterval = '3s'
NoNewHeadsThreshold = '30s'
RPCBlockQueryDelay = 2
+NoNewFinalizedHeadsThreshold = '45s'
[GasEstimator]
PriceDefault = '5 gwei'
diff --git a/core/chains/evm/config/toml/defaults/BSC_Testnet.toml b/core/chains/evm/config/toml/defaults/BSC_Testnet.toml
index 364bae0c9f1..252f90accdd 100644
--- a/core/chains/evm/config/toml/defaults/BSC_Testnet.toml
+++ b/core/chains/evm/config/toml/defaults/BSC_Testnet.toml
@@ -6,6 +6,7 @@ LinkContractAddress = '0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06'
LogPollInterval = '3s'
NoNewHeadsThreshold = '30s'
RPCBlockQueryDelay = 2
+NoNewFinalizedHeadsThreshold = '40s'
[GasEstimator]
PriceDefault = '5 gwei'
diff --git a/core/chains/evm/config/toml/defaults/Base_Mainnet.toml b/core/chains/evm/config/toml/defaults/Base_Mainnet.toml
index 314c12f8c54..f0896fba414 100644
--- a/core/chains/evm/config/toml/defaults/Base_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/Base_Mainnet.toml
@@ -4,6 +4,7 @@ FinalityDepth = 200
LogPollInterval = '2s'
NoNewHeadsThreshold = '40s'
MinIncomingConfirmations = 1
+NoNewFinalizedHeadsThreshold = '15m'
[GasEstimator]
EIP1559DynamicFees = true
diff --git a/core/chains/evm/config/toml/defaults/Base_Sepolia.toml b/core/chains/evm/config/toml/defaults/Base_Sepolia.toml
index 6458dda87f7..1fc0b51f1f3 100644
--- a/core/chains/evm/config/toml/defaults/Base_Sepolia.toml
+++ b/core/chains/evm/config/toml/defaults/Base_Sepolia.toml
@@ -4,6 +4,7 @@ FinalityDepth = 200
LogPollInterval = '2s'
NoNewHeadsThreshold = '40s'
MinIncomingConfirmations = 1
+NoNewFinalizedHeadsThreshold = '12m'
[GasEstimator]
EIP1559DynamicFees = true
diff --git a/core/chains/evm/config/toml/defaults/Celo_Mainnet.toml b/core/chains/evm/config/toml/defaults/Celo_Mainnet.toml
index b48cb25b325..a4948620370 100644
--- a/core/chains/evm/config/toml/defaults/Celo_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/Celo_Mainnet.toml
@@ -5,6 +5,7 @@ LogPollInterval = '5s'
MinIncomingConfirmations = 1
NoNewHeadsThreshold = '1m'
OCR.ContractConfirmations = 1
+NoNewFinalizedHeadsThreshold = '1m'
[GasEstimator]
PriceDefault = '5 gwei'
diff --git a/core/chains/evm/config/toml/defaults/Celo_Testnet.toml b/core/chains/evm/config/toml/defaults/Celo_Testnet.toml
index d3f595baac6..eb43f080b7d 100644
--- a/core/chains/evm/config/toml/defaults/Celo_Testnet.toml
+++ b/core/chains/evm/config/toml/defaults/Celo_Testnet.toml
@@ -5,6 +5,7 @@ LogPollInterval = '5s'
MinIncomingConfirmations = 1
NoNewHeadsThreshold = '1m'
OCR.ContractConfirmations = 1
+NoNewFinalizedHeadsThreshold = '1m'
[GasEstimator]
PriceDefault = '5 gwei'
diff --git a/core/chains/evm/config/toml/defaults/Ethereum_Mainnet.toml b/core/chains/evm/config/toml/defaults/Ethereum_Mainnet.toml
index 2e65cce6330..20bb0d8e72a 100644
--- a/core/chains/evm/config/toml/defaults/Ethereum_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/Ethereum_Mainnet.toml
@@ -2,6 +2,7 @@ ChainID = '1'
LinkContractAddress = '0x514910771AF9Ca656af840dff83E8264EcF986CA'
MinContractPayment = '0.1 link'
OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
+NoNewFinalizedHeadsThreshold = '9m'
[GasEstimator]
EIP1559DynamicFees = true
diff --git a/core/chains/evm/config/toml/defaults/Gnosis_Chiado.toml b/core/chains/evm/config/toml/defaults/Gnosis_Chiado.toml
index 1b14da2b540..379377a2266 100644
--- a/core/chains/evm/config/toml/defaults/Gnosis_Chiado.toml
+++ b/core/chains/evm/config/toml/defaults/Gnosis_Chiado.toml
@@ -3,6 +3,7 @@ ChainID = '10200'
FinalityDepth = 100
ChainType = 'gnosis'
LogPollInterval = '5s'
+NoNewFinalizedHeadsThreshold = '2m'
[GasEstimator]
EIP1559DynamicFees = true
diff --git a/core/chains/evm/config/toml/defaults/Gnosis_Mainnet.toml b/core/chains/evm/config/toml/defaults/Gnosis_Mainnet.toml
index 587f0083b70..628646364f5 100644
--- a/core/chains/evm/config/toml/defaults/Gnosis_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/Gnosis_Mainnet.toml
@@ -9,6 +9,7 @@ ChainID = '100'
ChainType = 'gnosis'
LinkContractAddress = '0xE2e73A1c69ecF83F464EFCE6A5be353a37cA09b2'
LogPollInterval = '5s'
+NoNewFinalizedHeadsThreshold = '2m'
[GasEstimator]
PriceDefault = '1 gwei'
diff --git a/core/chains/evm/config/toml/defaults/L3X_Mainnet.toml b/core/chains/evm/config/toml/defaults/L3X_Mainnet.toml
new file mode 100644
index 00000000000..1fbda42fd2a
--- /dev/null
+++ b/core/chains/evm/config/toml/defaults/L3X_Mainnet.toml
@@ -0,0 +1,18 @@
+ChainID = '12324'
+ChainType = 'arbitrum'
+FinalityTagEnabled = true
+FinalityDepth = 10
+LinkContractAddress = '0x79f531a3D07214304F259DC28c7191513223bcf3'
+# Produces blocks on-demand
+NoNewHeadsThreshold = '0'
+OCR.ContractConfirmations = 1
+LogPollInterval = '10s'
+
+[GasEstimator]
+Mode = 'Arbitrum'
+LimitMax = 1_000_000_000
+# Arbitrum-based chains uses the suggested gas price, so we don't want to place any limits on the minimum
+PriceMin = '0'
+PriceDefault = '0.1 gwei'
+FeeCapDefault = '1000 gwei'
+BumpThreshold = 5
diff --git a/core/chains/evm/config/toml/defaults/L3X_Sepolia.toml b/core/chains/evm/config/toml/defaults/L3X_Sepolia.toml
new file mode 100644
index 00000000000..ee515bb72ba
--- /dev/null
+++ b/core/chains/evm/config/toml/defaults/L3X_Sepolia.toml
@@ -0,0 +1,18 @@
+ChainID = '12325'
+ChainType = 'arbitrum'
+FinalityTagEnabled = true
+FinalityDepth = 10
+LinkContractAddress = '0xa71848C99155DA0b245981E5ebD1C94C4be51c43'
+# Produces blocks on-demand
+NoNewHeadsThreshold = '0'
+OCR.ContractConfirmations = 1
+LogPollInterval = '10s'
+
+[GasEstimator]
+Mode = 'Arbitrum'
+LimitMax = 1_000_000_000
+# Arbitrum-based chains uses the suggested gas price, so we don't want to place any limits on the minimum
+PriceMin = '0'
+PriceDefault = '0.1 gwei'
+FeeCapDefault = '1000 gwei'
+BumpThreshold = 5
diff --git a/core/chains/evm/config/toml/defaults/Optimism_Mainnet.toml b/core/chains/evm/config/toml/defaults/Optimism_Mainnet.toml
index fd4dd9f32f0..3510aef7047 100644
--- a/core/chains/evm/config/toml/defaults/Optimism_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/Optimism_Mainnet.toml
@@ -5,6 +5,7 @@ LinkContractAddress = '0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6'
LogPollInterval = '2s'
NoNewHeadsThreshold = '40s'
MinIncomingConfirmations = 1
+NoNewFinalizedHeadsThreshold = '13m'
[GasEstimator]
EIP1559DynamicFees = true
diff --git a/core/chains/evm/config/toml/defaults/Optimism_Sepolia.toml b/core/chains/evm/config/toml/defaults/Optimism_Sepolia.toml
index 116ae9d680b..8da575a5936 100644
--- a/core/chains/evm/config/toml/defaults/Optimism_Sepolia.toml
+++ b/core/chains/evm/config/toml/defaults/Optimism_Sepolia.toml
@@ -4,6 +4,7 @@ FinalityDepth = 200
LogPollInterval = '2s'
NoNewHeadsThreshold = '40s'
MinIncomingConfirmations = 1
+NoNewFinalizedHeadsThreshold = '15m'
[GasEstimator]
EIP1559DynamicFees = true
diff --git a/core/chains/evm/config/toml/defaults/Polygon_Amoy.toml b/core/chains/evm/config/toml/defaults/Polygon_Amoy.toml
index 6a1687fec48..bca42d9b403 100644
--- a/core/chains/evm/config/toml/defaults/Polygon_Amoy.toml
+++ b/core/chains/evm/config/toml/defaults/Polygon_Amoy.toml
@@ -5,13 +5,16 @@ MinIncomingConfirmations = 5
NoNewHeadsThreshold = '30s'
RPCBlockQueryDelay = 10
RPCDefaultBatchSize = 100
+NoNewFinalizedHeadsThreshold = '12m'
[Transactions]
MaxQueued = 5000
[GasEstimator]
-EIP1559DynamicFees = true
+PriceDefault = '25 gwei'
PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether'
+PriceMin = '25 gwei'
+EIP1559DynamicFees = true
BumpMin = '20 gwei'
BumpThreshold = 5
diff --git a/core/chains/evm/config/toml/defaults/Polygon_Mainnet.toml b/core/chains/evm/config/toml/defaults/Polygon_Mainnet.toml
index 50057a6893a..2a520563302 100644
--- a/core/chains/evm/config/toml/defaults/Polygon_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/Polygon_Mainnet.toml
@@ -9,6 +9,7 @@ NoNewHeadsThreshold = '30s'
# Must be set to something large here because Polygon has so many re-orgs that otherwise we are constantly refetching
RPCBlockQueryDelay = 10
RPCDefaultBatchSize = 100
+NoNewFinalizedHeadsThreshold = '6m'
[Transactions]
# Matic nodes under high mempool pressure are liable to drop txes, we need to ensure we keep sending them
diff --git a/core/chains/evm/config/toml/defaults/Polygon_Mumbai.toml b/core/chains/evm/config/toml/defaults/Polygon_Mumbai.toml
index ce0f8861de2..b9c993c6b23 100644
--- a/core/chains/evm/config/toml/defaults/Polygon_Mumbai.toml
+++ b/core/chains/evm/config/toml/defaults/Polygon_Mumbai.toml
@@ -11,8 +11,9 @@ RPCDefaultBatchSize = 100
MaxQueued = 5000
[GasEstimator]
-PriceDefault = '1 gwei'
+PriceDefault = '25 gwei'
PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether'
+PriceMin = '25 gwei'
BumpMin = '20 gwei'
BumpThreshold = 5
diff --git a/core/chains/evm/config/toml/defaults/WeMix_Mainnet.toml b/core/chains/evm/config/toml/defaults/WeMix_Mainnet.toml
index 35cd4a90a2f..7fcbd18890b 100644
--- a/core/chains/evm/config/toml/defaults/WeMix_Mainnet.toml
+++ b/core/chains/evm/config/toml/defaults/WeMix_Mainnet.toml
@@ -5,6 +5,7 @@ MinIncomingConfirmations = 1
# WeMix emits a block every 1 second, regardless of transactions
LogPollInterval = '3s'
NoNewHeadsThreshold = '30s'
+NoNewFinalizedHeadsThreshold = '40s'
[OCR]
ContractConfirmations = 1
diff --git a/core/chains/evm/config/toml/defaults/WeMix_Testnet.toml b/core/chains/evm/config/toml/defaults/WeMix_Testnet.toml
index 417718d87eb..83c483d0348 100644
--- a/core/chains/evm/config/toml/defaults/WeMix_Testnet.toml
+++ b/core/chains/evm/config/toml/defaults/WeMix_Testnet.toml
@@ -5,6 +5,7 @@ MinIncomingConfirmations = 1
# WeMix emits a block every 1 second, regardless of transactions
LogPollInterval = '3s'
NoNewHeadsThreshold = '30s'
+NoNewFinalizedHeadsThreshold = '40s'
[OCR]
ContractConfirmations = 1
diff --git a/core/chains/evm/config/toml/defaults/fallback.toml b/core/chains/evm/config/toml/defaults/fallback.toml
index a11e646e08b..6dd02a8fd5b 100644
--- a/core/chains/evm/config/toml/defaults/fallback.toml
+++ b/core/chains/evm/config/toml/defaults/fallback.toml
@@ -15,6 +15,7 @@ NoNewHeadsThreshold = '3m'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0'
[Transactions]
ForwardersEnabled = false
@@ -46,6 +47,7 @@ EIP1559DynamicFees = false
FeeCapDefault = '100 gwei'
TipCapDefault = '1'
TipCapMin = '1'
+EstimateGasLimit = false
[GasEstimator.BlockHistory]
BatchSize = 25
diff --git a/core/chains/evm/gas/block_history_estimator.go b/core/chains/evm/gas/block_history_estimator.go
index 4075b46f901..b933ea23825 100644
--- a/core/chains/evm/gas/block_history_estimator.go
+++ b/core/chains/evm/gas/block_history_estimator.go
@@ -276,6 +276,8 @@ func (b *BlockHistoryEstimator) setMaxPercentileGasPrice(gasPrice *assets.Wei) {
}
func (b *BlockHistoryEstimator) getBlockHistoryNumbers() (numsInHistory []int64) {
+ b.blocksMu.RLock()
+ defer b.blocksMu.RUnlock()
for _, b := range b.blocks {
numsInHistory = append(numsInHistory, b.Number)
}
diff --git a/core/chains/evm/gas/helpers_test.go b/core/chains/evm/gas/helpers_test.go
index 2c12ed426a6..d6af645fe8f 100644
--- a/core/chains/evm/gas/helpers_test.go
+++ b/core/chains/evm/gas/helpers_test.go
@@ -157,6 +157,7 @@ type MockGasEstimatorConfig struct {
FeeCapDefaultF *assets.Wei
LimitMaxF uint64
ModeF string
+ EstimateGasLimitF bool
}
func NewMockGasConfig() *MockGasEstimatorConfig {
@@ -214,3 +215,7 @@ func (m *MockGasEstimatorConfig) LimitMax() uint64 {
func (m *MockGasEstimatorConfig) Mode() string {
return m.ModeF
}
+
+func (m *MockGasEstimatorConfig) EstimateGasLimit() bool {
+ return m.EstimateGasLimitF
+}
diff --git a/core/chains/evm/gas/mocks/evm_fee_estimator.go b/core/chains/evm/gas/mocks/evm_fee_estimator.go
index a9adc261ce3..603115a94c7 100644
--- a/core/chains/evm/gas/mocks/evm_fee_estimator.go
+++ b/core/chains/evm/gas/mocks/evm_fee_estimator.go
@@ -7,6 +7,8 @@ import (
assets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ common "github.com/ethereum/go-ethereum/common"
+
context "context"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
@@ -145,14 +147,14 @@ func (_c *EvmFeeEstimator_Close_Call) RunAndReturn(run func() error) *EvmFeeEsti
return _c
}
-// GetFee provides a mock function with given fields: ctx, calldata, feeLimit, maxFeePrice, opts
-func (_m *EvmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...types.Opt) (gas.EvmFee, uint64, error) {
+// GetFee provides a mock function with given fields: ctx, calldata, feeLimit, maxFeePrice, toAddress, opts
+func (_m *EvmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...types.Opt) (gas.EvmFee, uint64, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
- _ca = append(_ca, ctx, calldata, feeLimit, maxFeePrice)
+ _ca = append(_ca, ctx, calldata, feeLimit, maxFeePrice, toAddress)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
@@ -163,23 +165,23 @@ func (_m *EvmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit
var r0 gas.EvmFee
var r1 uint64
var r2 error
- if rf, ok := ret.Get(0).(func(context.Context, []byte, uint64, *assets.Wei, ...types.Opt) (gas.EvmFee, uint64, error)); ok {
- return rf(ctx, calldata, feeLimit, maxFeePrice, opts...)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) (gas.EvmFee, uint64, error)); ok {
+ return rf(ctx, calldata, feeLimit, maxFeePrice, toAddress, opts...)
}
- if rf, ok := ret.Get(0).(func(context.Context, []byte, uint64, *assets.Wei, ...types.Opt) gas.EvmFee); ok {
- r0 = rf(ctx, calldata, feeLimit, maxFeePrice, opts...)
+ if rf, ok := ret.Get(0).(func(context.Context, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) gas.EvmFee); ok {
+ r0 = rf(ctx, calldata, feeLimit, maxFeePrice, toAddress, opts...)
} else {
r0 = ret.Get(0).(gas.EvmFee)
}
- if rf, ok := ret.Get(1).(func(context.Context, []byte, uint64, *assets.Wei, ...types.Opt) uint64); ok {
- r1 = rf(ctx, calldata, feeLimit, maxFeePrice, opts...)
+ if rf, ok := ret.Get(1).(func(context.Context, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) uint64); ok {
+ r1 = rf(ctx, calldata, feeLimit, maxFeePrice, toAddress, opts...)
} else {
r1 = ret.Get(1).(uint64)
}
- if rf, ok := ret.Get(2).(func(context.Context, []byte, uint64, *assets.Wei, ...types.Opt) error); ok {
- r2 = rf(ctx, calldata, feeLimit, maxFeePrice, opts...)
+ if rf, ok := ret.Get(2).(func(context.Context, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) error); ok {
+ r2 = rf(ctx, calldata, feeLimit, maxFeePrice, toAddress, opts...)
} else {
r2 = ret.Error(2)
}
@@ -197,43 +199,44 @@ type EvmFeeEstimator_GetFee_Call struct {
// - calldata []byte
// - feeLimit uint64
// - maxFeePrice *assets.Wei
+// - toAddress *common.Address
// - opts ...types.Opt
-func (_e *EvmFeeEstimator_Expecter) GetFee(ctx interface{}, calldata interface{}, feeLimit interface{}, maxFeePrice interface{}, opts ...interface{}) *EvmFeeEstimator_GetFee_Call {
+func (_e *EvmFeeEstimator_Expecter) GetFee(ctx interface{}, calldata interface{}, feeLimit interface{}, maxFeePrice interface{}, toAddress interface{}, opts ...interface{}) *EvmFeeEstimator_GetFee_Call {
return &EvmFeeEstimator_GetFee_Call{Call: _e.mock.On("GetFee",
- append([]interface{}{ctx, calldata, feeLimit, maxFeePrice}, opts...)...)}
+ append([]interface{}{ctx, calldata, feeLimit, maxFeePrice, toAddress}, opts...)...)}
}
-func (_c *EvmFeeEstimator_GetFee_Call) Run(run func(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...types.Opt)) *EvmFeeEstimator_GetFee_Call {
+func (_c *EvmFeeEstimator_GetFee_Call) Run(run func(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...types.Opt)) *EvmFeeEstimator_GetFee_Call {
_c.Call.Run(func(args mock.Arguments) {
- variadicArgs := make([]types.Opt, len(args)-4)
- for i, a := range args[4:] {
+ variadicArgs := make([]types.Opt, len(args)-5)
+ for i, a := range args[5:] {
if a != nil {
variadicArgs[i] = a.(types.Opt)
}
}
- run(args[0].(context.Context), args[1].([]byte), args[2].(uint64), args[3].(*assets.Wei), variadicArgs...)
+ run(args[0].(context.Context), args[1].([]byte), args[2].(uint64), args[3].(*assets.Wei), args[4].(*common.Address), variadicArgs...)
})
return _c
}
-func (_c *EvmFeeEstimator_GetFee_Call) Return(fee gas.EvmFee, chainSpecificFeeLimit uint64, err error) *EvmFeeEstimator_GetFee_Call {
- _c.Call.Return(fee, chainSpecificFeeLimit, err)
+func (_c *EvmFeeEstimator_GetFee_Call) Return(fee gas.EvmFee, estimatedFeeLimit uint64, err error) *EvmFeeEstimator_GetFee_Call {
+ _c.Call.Return(fee, estimatedFeeLimit, err)
return _c
}
-func (_c *EvmFeeEstimator_GetFee_Call) RunAndReturn(run func(context.Context, []byte, uint64, *assets.Wei, ...types.Opt) (gas.EvmFee, uint64, error)) *EvmFeeEstimator_GetFee_Call {
+func (_c *EvmFeeEstimator_GetFee_Call) RunAndReturn(run func(context.Context, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) (gas.EvmFee, uint64, error)) *EvmFeeEstimator_GetFee_Call {
_c.Call.Return(run)
return _c
}
-// GetMaxCost provides a mock function with given fields: ctx, amount, calldata, feeLimit, maxFeePrice, opts
-func (_m *EvmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...types.Opt) (*big.Int, error) {
+// GetMaxCost provides a mock function with given fields: ctx, amount, calldata, feeLimit, maxFeePrice, toAddress, opts
+func (_m *EvmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...types.Opt) (*big.Int, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
- _ca = append(_ca, ctx, amount, calldata, feeLimit, maxFeePrice)
+ _ca = append(_ca, ctx, amount, calldata, feeLimit, maxFeePrice, toAddress)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
@@ -243,19 +246,19 @@ func (_m *EvmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, ca
var r0 *big.Int
var r1 error
- if rf, ok := ret.Get(0).(func(context.Context, assets.Eth, []byte, uint64, *assets.Wei, ...types.Opt) (*big.Int, error)); ok {
- return rf(ctx, amount, calldata, feeLimit, maxFeePrice, opts...)
+ if rf, ok := ret.Get(0).(func(context.Context, assets.Eth, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) (*big.Int, error)); ok {
+ return rf(ctx, amount, calldata, feeLimit, maxFeePrice, toAddress, opts...)
}
- if rf, ok := ret.Get(0).(func(context.Context, assets.Eth, []byte, uint64, *assets.Wei, ...types.Opt) *big.Int); ok {
- r0 = rf(ctx, amount, calldata, feeLimit, maxFeePrice, opts...)
+ if rf, ok := ret.Get(0).(func(context.Context, assets.Eth, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) *big.Int); ok {
+ r0 = rf(ctx, amount, calldata, feeLimit, maxFeePrice, toAddress, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*big.Int)
}
}
- if rf, ok := ret.Get(1).(func(context.Context, assets.Eth, []byte, uint64, *assets.Wei, ...types.Opt) error); ok {
- r1 = rf(ctx, amount, calldata, feeLimit, maxFeePrice, opts...)
+ if rf, ok := ret.Get(1).(func(context.Context, assets.Eth, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) error); ok {
+ r1 = rf(ctx, amount, calldata, feeLimit, maxFeePrice, toAddress, opts...)
} else {
r1 = ret.Error(1)
}
@@ -274,21 +277,22 @@ type EvmFeeEstimator_GetMaxCost_Call struct {
// - calldata []byte
// - feeLimit uint64
// - maxFeePrice *assets.Wei
+// - toAddress *common.Address
// - opts ...types.Opt
-func (_e *EvmFeeEstimator_Expecter) GetMaxCost(ctx interface{}, amount interface{}, calldata interface{}, feeLimit interface{}, maxFeePrice interface{}, opts ...interface{}) *EvmFeeEstimator_GetMaxCost_Call {
+func (_e *EvmFeeEstimator_Expecter) GetMaxCost(ctx interface{}, amount interface{}, calldata interface{}, feeLimit interface{}, maxFeePrice interface{}, toAddress interface{}, opts ...interface{}) *EvmFeeEstimator_GetMaxCost_Call {
return &EvmFeeEstimator_GetMaxCost_Call{Call: _e.mock.On("GetMaxCost",
- append([]interface{}{ctx, amount, calldata, feeLimit, maxFeePrice}, opts...)...)}
+ append([]interface{}{ctx, amount, calldata, feeLimit, maxFeePrice, toAddress}, opts...)...)}
}
-func (_c *EvmFeeEstimator_GetMaxCost_Call) Run(run func(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...types.Opt)) *EvmFeeEstimator_GetMaxCost_Call {
+func (_c *EvmFeeEstimator_GetMaxCost_Call) Run(run func(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...types.Opt)) *EvmFeeEstimator_GetMaxCost_Call {
_c.Call.Run(func(args mock.Arguments) {
- variadicArgs := make([]types.Opt, len(args)-5)
- for i, a := range args[5:] {
+ variadicArgs := make([]types.Opt, len(args)-6)
+ for i, a := range args[6:] {
if a != nil {
variadicArgs[i] = a.(types.Opt)
}
}
- run(args[0].(context.Context), args[1].(assets.Eth), args[2].([]byte), args[3].(uint64), args[4].(*assets.Wei), variadicArgs...)
+ run(args[0].(context.Context), args[1].(assets.Eth), args[2].([]byte), args[3].(uint64), args[4].(*assets.Wei), args[5].(*common.Address), variadicArgs...)
})
return _c
}
@@ -298,7 +302,7 @@ func (_c *EvmFeeEstimator_GetMaxCost_Call) Return(_a0 *big.Int, _a1 error) *EvmF
return _c
}
-func (_c *EvmFeeEstimator_GetMaxCost_Call) RunAndReturn(run func(context.Context, assets.Eth, []byte, uint64, *assets.Wei, ...types.Opt) (*big.Int, error)) *EvmFeeEstimator_GetMaxCost_Call {
+func (_c *EvmFeeEstimator_GetMaxCost_Call) RunAndReturn(run func(context.Context, assets.Eth, []byte, uint64, *assets.Wei, *common.Address, ...types.Opt) (*big.Int, error)) *EvmFeeEstimator_GetMaxCost_Call {
_c.Call.Return(run)
return _c
}
diff --git a/core/chains/evm/gas/mocks/fee_estimator_client.go b/core/chains/evm/gas/mocks/fee_estimator_client.go
index 8e10107597f..ab99eb7b0d8 100644
--- a/core/chains/evm/gas/mocks/fee_estimator_client.go
+++ b/core/chains/evm/gas/mocks/fee_estimator_client.go
@@ -241,6 +241,63 @@ func (_c *FeeEstimatorClient_ConfiguredChainID_Call) RunAndReturn(run func() *bi
return _c
}
+// EstimateGas provides a mock function with given fields: ctx, call
+func (_m *FeeEstimatorClient) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) {
+ ret := _m.Called(ctx, call)
+
+ if len(ret) == 0 {
+ panic("no return value specified for EstimateGas")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) (uint64, error)); ok {
+ return rf(ctx, call)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) uint64); ok {
+ r0 = rf(ctx, call)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, ethereum.CallMsg) error); ok {
+ r1 = rf(ctx, call)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// FeeEstimatorClient_EstimateGas_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EstimateGas'
+type FeeEstimatorClient_EstimateGas_Call struct {
+ *mock.Call
+}
+
+// EstimateGas is a helper method to define mock.On call
+// - ctx context.Context
+// - call ethereum.CallMsg
+func (_e *FeeEstimatorClient_Expecter) EstimateGas(ctx interface{}, call interface{}) *FeeEstimatorClient_EstimateGas_Call {
+ return &FeeEstimatorClient_EstimateGas_Call{Call: _e.mock.On("EstimateGas", ctx, call)}
+}
+
+func (_c *FeeEstimatorClient_EstimateGas_Call) Run(run func(ctx context.Context, call ethereum.CallMsg)) *FeeEstimatorClient_EstimateGas_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(ethereum.CallMsg))
+ })
+ return _c
+}
+
+func (_c *FeeEstimatorClient_EstimateGas_Call) Return(_a0 uint64, _a1 error) *FeeEstimatorClient_EstimateGas_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *FeeEstimatorClient_EstimateGas_Call) RunAndReturn(run func(context.Context, ethereum.CallMsg) (uint64, error)) *FeeEstimatorClient_EstimateGas_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// HeadByNumber provides a mock function with given fields: ctx, n
func (_m *FeeEstimatorClient) HeadByNumber(ctx context.Context, n *big.Int) (*types.Head, error) {
ret := _m.Called(ctx, n)
diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go
index 1ff8b66b1d0..15adfc0d7a7 100644
--- a/core/chains/evm/gas/models.go
+++ b/core/chains/evm/gas/models.go
@@ -26,6 +26,9 @@ import (
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
)
+// EstimateGasBuffer is a multiplier applied to estimated gas when the EstimateGasLimit feature is enabled
+const EstimateGasBuffer = float32(1.15)
+
// EvmFeeEstimator provides a unified interface that wraps EvmEstimator and can determine if legacy or dynamic fee estimation should be used
type EvmFeeEstimator interface {
services.Service
@@ -33,11 +36,11 @@ type EvmFeeEstimator interface {
// L1Oracle returns the L1 gas price oracle only if the chain has one, e.g. OP stack L2s and Arbitrum.
L1Oracle() rollups.L1Oracle
- GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (fee EvmFee, chainSpecificFeeLimit uint64, err error)
+ GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...feetypes.Opt) (fee EvmFee, estimatedFeeLimit uint64, err error)
BumpFee(ctx context.Context, originalFee EvmFee, feeLimit uint64, maxFeePrice *assets.Wei, attempts []EvmPriorAttempt) (bumpedFee EvmFee, chainSpecificFeeLimit uint64, err error)
// GetMaxCost returns the total value = max price x fee units + transferred value
- GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (*big.Int, error)
+ GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...feetypes.Opt) (*big.Int, error)
}
type feeEstimatorClient interface {
@@ -46,6 +49,7 @@ type feeEstimatorClient interface {
CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error
ConfiguredChainID() *big.Int
HeadByNumber(ctx context.Context, n *big.Int) (*evmtypes.Head, error)
+ EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error)
}
// NewEstimator returns the estimator for a given config
@@ -70,6 +74,7 @@ func NewEstimator(lggr logger.Logger, ethClient feeEstimatorClient, cfg Config,
"tipCapMin", geCfg.TipCapMin(),
"priceMax", geCfg.PriceMax(),
"priceMin", geCfg.PriceMin(),
+ "estimateGasLimit", geCfg.EstimateGasLimit(),
)
df := geCfg.EIP1559DynamicFees()
@@ -110,7 +115,7 @@ func NewEstimator(lggr logger.Logger, ethClient feeEstimatorClient, cfg Config,
return NewFixedPriceEstimator(geCfg, ethClient, bh, lggr, l1Oracle)
}
}
- return NewEvmFeeEstimator(lggr, newEstimator, df, geCfg), nil
+ return NewEvmFeeEstimator(lggr, newEstimator, df, geCfg, ethClient), nil
}
// DynamicFee encompasses both FeeCap and TipCap for EIP1559 transactions
@@ -181,17 +186,19 @@ type evmFeeEstimator struct {
EvmEstimator
EIP1559Enabled bool
geCfg GasEstimatorConfig
+ ethClient feeEstimatorClient
}
var _ EvmFeeEstimator = (*evmFeeEstimator)(nil)
-func NewEvmFeeEstimator(lggr logger.Logger, newEstimator func(logger.Logger) EvmEstimator, eip1559Enabled bool, geCfg GasEstimatorConfig) EvmFeeEstimator {
+func NewEvmFeeEstimator(lggr logger.Logger, newEstimator func(logger.Logger) EvmEstimator, eip1559Enabled bool, geCfg GasEstimatorConfig, ethClient feeEstimatorClient) EvmFeeEstimator {
lggr = logger.Named(lggr, "WrappedEvmEstimator")
return &evmFeeEstimator{
lggr: lggr,
EvmEstimator: newEstimator(lggr),
EIP1559Enabled: eip1559Enabled,
geCfg: geCfg,
+ ethClient: ethClient,
}
}
@@ -261,7 +268,10 @@ func (e *evmFeeEstimator) L1Oracle() rollups.L1Oracle {
return e.EvmEstimator.L1Oracle()
}
-func (e *evmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (fee EvmFee, chainSpecificFeeLimit uint64, err error) {
+// GetFee returns an initial estimated gas price and gas limit for a transaction
+// The gas limit provided by the caller can be adjusted by gas estimation or for 2D fees
+func (e *evmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...feetypes.Opt) (fee EvmFee, estimatedFeeLimit uint64, err error) {
+ var chainSpecificFeeLimit uint64
// get dynamic fee
if e.EIP1559Enabled {
var dynamicFee DynamicFee
@@ -269,24 +279,23 @@ func (e *evmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit
if err != nil {
return
}
- chainSpecificFeeLimit, err = commonfee.ApplyMultiplier(feeLimit, e.geCfg.LimitMultiplier())
fee.DynamicFeeCap = dynamicFee.FeeCap
fee.DynamicTipCap = dynamicFee.TipCap
- return
- }
-
- // get legacy fee
- fee.Legacy, chainSpecificFeeLimit, err = e.EvmEstimator.GetLegacyGas(ctx, calldata, feeLimit, maxFeePrice, opts...)
- if err != nil {
- return
+ chainSpecificFeeLimit = feeLimit
+ } else {
+ // 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())
+ estimatedFeeLimit, err = e.estimateFeeLimit(ctx, chainSpecificFeeLimit, calldata, toAddress)
return
}
-func (e *evmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (*big.Int, error) {
- fees, gasLimit, err := e.GetFee(ctx, calldata, feeLimit, maxFeePrice, opts...)
+func (e *evmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...feetypes.Opt) (*big.Int, error) {
+ fees, gasLimit, err := e.GetFee(ctx, calldata, feeLimit, maxFeePrice, toAddress, opts...)
if err != nil {
return nil, err
}
@@ -337,6 +346,53 @@ func (e *evmFeeEstimator) BumpFee(ctx context.Context, originalFee EvmFee, feeLi
return
}
+func (e *evmFeeEstimator) estimateFeeLimit(ctx context.Context, feeLimit uint64, calldata []byte, toAddress *common.Address) (estimatedFeeLimit uint64, err error) {
+ // Use the feeLimit * LimitMultiplier as the provided gas limit since this multiplier is applied on top of the caller specified gas limit
+ providedGasLimit, err := commonfee.ApplyMultiplier(feeLimit, e.geCfg.LimitMultiplier())
+ if err != nil {
+ return estimatedFeeLimit, err
+ }
+ // Use provided fee limit by default if EstimateGasLimit is disabled
+ if !e.geCfg.EstimateGasLimit() {
+ return providedGasLimit, nil
+ }
+ // Create call msg for gas limit estimation
+ // Skip setting Gas to avoid capping the results of the estimation
+ callMsg := ethereum.CallMsg{
+ To: toAddress,
+ Data: calldata,
+ }
+ estimatedGas, estimateErr := e.ethClient.EstimateGas(ctx, callMsg)
+ if estimateErr != nil {
+ if providedGasLimit > 0 {
+ // Do not return error if estimate gas failed, we can still use the provided limit instead since it is an upper limit
+ e.lggr.Errorw("failed to estimate gas limit. falling back to the provided gas limit with multiplier", "callMsg", callMsg, "providedGasLimitWithMultiplier", providedGasLimit, "error", estimateErr)
+ return providedGasLimit, nil
+ }
+ return estimatedFeeLimit, fmt.Errorf("gas estimation failed and provided gas limit is 0: %w", estimateErr)
+ }
+ e.lggr.Debugw("estimated gas", "estimatedGas", estimatedGas, "providedGasLimitWithMultiplier", providedGasLimit)
+ // Return error if estimated gas without the buffer exceeds the provided gas limit, if provided
+ // Transaction would be destined to run out of gas and fail
+ if providedGasLimit > 0 && estimatedGas > providedGasLimit {
+ e.lggr.Errorw("estimated gas exceeds provided gas limit with multiplier", "estimatedGas", estimatedGas, "providedGasLimitWithMultiplier", providedGasLimit)
+ return estimatedFeeLimit, commonfee.ErrFeeLimitTooLow
+ }
+ // Apply EstimateGasBuffer to the estimated gas limit
+ estimatedFeeLimit, err = commonfee.ApplyMultiplier(estimatedGas, EstimateGasBuffer)
+ if err != nil {
+ return
+ }
+ // If provided gas limit is not 0, fallback to it if the buffer causes the estimated gas limit to exceed it
+ // The provided gas limit should be used as an upper bound to avoid unexpected behavior for products
+ if providedGasLimit > 0 && estimatedFeeLimit > providedGasLimit {
+ e.lggr.Debugw("estimated gas limit with buffer exceeds the provided gas limit with multiplier. falling back to the provided gas limit with multiplier", "estimatedGasLimit", estimatedFeeLimit, "providedGasLimitWithMultiplier", providedGasLimit)
+ estimatedFeeLimit = providedGasLimit
+ }
+
+ return
+}
+
// Config defines an interface for configuration in the gas package
type Config interface {
ChainType() chaintype.ChainType
@@ -358,6 +414,7 @@ type GasEstimatorConfig interface {
PriceMin() *assets.Wei
PriceMax() *assets.Wei
Mode() string
+ EstimateGasLimit() bool
}
type BlockHistoryConfig interface {
diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go
index 92ea901596f..14ef0854975 100644
--- a/core/chains/evm/gas/models_test.go
+++ b/core/chains/evm/gas/models_test.go
@@ -1,6 +1,7 @@
package gas_test
import (
+ "errors"
"math/big"
"testing"
@@ -12,12 +13,14 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+ commonfee "github.com/smartcontractkit/chainlink/v2/common/fee"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups"
rollupMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/testutils"
)
func TestWrappedEvmEstimator(t *testing.T) {
@@ -35,9 +38,9 @@ func TestWrappedEvmEstimator(t *testing.T) {
est := mocks.NewEvmEstimator(t)
est.On("GetDynamicFee", mock.Anything, mock.Anything).
- Return(dynamicFee, nil).Twice()
+ Return(dynamicFee, nil).Times(6)
est.On("GetLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
- Return(legacyFee, gasLimit, nil).Twice()
+ Return(legacyFee, gasLimit, nil).Times(6)
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).
@@ -59,7 +62,7 @@ func TestWrappedEvmEstimator(t *testing.T) {
getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator }
// expect nil
- estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, nil)
+ estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, nil, nil)
l1Oracle := estimator.L1Oracle()
assert.Nil(t, l1Oracle)
@@ -68,7 +71,7 @@ func TestWrappedEvmEstimator(t *testing.T) {
oracle, err := rollups.NewL1GasOracle(lggr, nil, chaintype.ChainOptimismBedrock)
require.NoError(t, err)
// cast oracle to L1Oracle interface
- estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg)
+ estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg, nil)
evmEstimator.On("L1Oracle").Return(oracle).Once()
l1Oracle = estimator.L1Oracle()
@@ -80,8 +83,8 @@ func TestWrappedEvmEstimator(t *testing.T) {
lggr := logger.Test(t)
// expect legacy fee data
dynamicFees := false
- estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg)
- fee, max, err := estimator.GetFee(ctx, nil, 0, nil)
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, nil)
+ fee, max, err := estimator.GetFee(ctx, nil, 0, nil, nil)
require.NoError(t, err)
assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), max)
assert.True(t, legacyFee.Equal(fee.Legacy))
@@ -90,8 +93,8 @@ func TestWrappedEvmEstimator(t *testing.T) {
// expect dynamic fee data
dynamicFees = true
- estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg)
- fee, max, err = estimator.GetFee(ctx, nil, gasLimit, nil)
+ estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, nil)
+ fee, max, err = estimator.GetFee(ctx, nil, gasLimit, nil, nil)
require.NoError(t, err)
assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), max)
assert.True(t, dynamicFee.FeeCap.Equal(fee.DynamicFeeCap))
@@ -103,7 +106,7 @@ func TestWrappedEvmEstimator(t *testing.T) {
t.Run("BumpFee", func(t *testing.T) {
lggr := logger.Test(t)
dynamicFees := false
- estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg)
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, nil)
// expect legacy fee data
fee, max, err := estimator.BumpFee(ctx, gas.EvmFee{Legacy: assets.NewWeiI(0)}, 0, nil, nil)
@@ -141,8 +144,8 @@ func TestWrappedEvmEstimator(t *testing.T) {
// expect legacy fee data
dynamicFees := false
- estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg)
- total, err := estimator.GetMaxCost(ctx, val, nil, gasLimit, nil)
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, nil)
+ total, err := estimator.GetMaxCost(ctx, val, nil, gasLimit, nil, 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)
@@ -150,8 +153,8 @@ func TestWrappedEvmEstimator(t *testing.T) {
// expect dynamic fee data
dynamicFees = true
- estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg)
- total, err = estimator.GetMaxCost(ctx, val, nil, gasLimit, nil)
+ estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, nil)
+ total, err = estimator.GetMaxCost(ctx, val, nil, gasLimit, nil, 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)
@@ -166,7 +169,7 @@ func TestWrappedEvmEstimator(t *testing.T) {
estimator := gas.NewEvmFeeEstimator(lggr, func(logger.Logger) gas.EvmEstimator {
return evmEstimator
- }, false, geCfg)
+ }, false, geCfg, nil)
require.Equal(t, mockEstimatorName, estimator.Name())
require.Equal(t, mockEvmEstimatorName, evmEstimator.Name())
@@ -185,7 +188,7 @@ func TestWrappedEvmEstimator(t *testing.T) {
evmEstimator.On("L1Oracle", mock.Anything).Return(nil).Twice()
- estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg)
+ estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg, nil)
err := estimator.Start(ctx)
require.NoError(t, err)
err = estimator.Close()
@@ -193,7 +196,7 @@ func TestWrappedEvmEstimator(t *testing.T) {
evmEstimator.On("L1Oracle", mock.Anything).Return(oracle).Twice()
- estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg)
+ estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg, nil)
err = estimator.Start(ctx)
require.NoError(t, err)
err = estimator.Close()
@@ -210,11 +213,11 @@ func TestWrappedEvmEstimator(t *testing.T) {
oracle.On("Ready").Return(nil).Twice()
getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator }
- estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg)
+ estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg, nil)
err := estimator.Ready()
require.NoError(t, err)
- estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg)
+ estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg, nil)
err = estimator.Ready()
require.NoError(t, err)
})
@@ -235,7 +238,7 @@ 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.NewEvmFeeEstimator(lggr, getEst, false, geCfg)
+ estimator := gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg, nil)
report := estimator.HealthReport()
require.True(t, pkgerrors.Is(report[evmEstimatorKey], evmEstimatorError))
require.Nil(t, report[oracleKey])
@@ -243,10 +246,166 @@ func TestWrappedEvmEstimator(t *testing.T) {
evmEstimator.On("L1Oracle").Return(oracle).Once()
- estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg)
+ estimator = gas.NewEvmFeeEstimator(lggr, getEst, false, geCfg, nil)
report = estimator.HealthReport()
require.True(t, pkgerrors.Is(report[evmEstimatorKey], evmEstimatorError))
require.True(t, pkgerrors.Is(report[oracleKey], oracleError))
require.NotNil(t, report[mockEstimatorName])
})
+
+ t.Run("GetFee, estimate gas limit enabled, succeeds", func(t *testing.T) {
+ estimatedGasLimit := uint64(5)
+ lggr := logger.Test(t)
+ // expect legacy fee data
+ dynamicFees := false
+ geCfg.EstimateGasLimitF = true
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ ethClient.On("EstimateGas", mock.Anything, mock.Anything).Return(estimatedGasLimit, nil).Twice()
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ toAddress := testutils.NewAddress()
+ fee, limit, err := estimator.GetFee(ctx, []byte{}, gasLimit, nil, &toAddress)
+ require.NoError(t, err)
+ assert.Equal(t, uint64(float32(estimatedGasLimit)*gas.EstimateGasBuffer), limit)
+ 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.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ fee, limit, err = estimator.GetFee(ctx, []byte{}, gasLimit, nil, &toAddress)
+ require.NoError(t, err)
+ assert.Equal(t, uint64(float32(estimatedGasLimit)*gas.EstimateGasBuffer), limit)
+ assert.True(t, dynamicFee.FeeCap.Equal(fee.DynamicFeeCap))
+ assert.True(t, dynamicFee.TipCap.Equal(fee.DynamicTipCap))
+ assert.Nil(t, fee.Legacy)
+ })
+
+ t.Run("GetFee, estimate gas limit enabled, estimate exceeds provided limit, returns error", func(t *testing.T) {
+ estimatedGasLimit := uint64(100)
+ lggr := logger.Test(t)
+ // expect legacy fee data
+ dynamicFees := false
+ geCfg.EstimateGasLimitF = true
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ ethClient.On("EstimateGas", mock.Anything, mock.Anything).Return(estimatedGasLimit, nil).Twice()
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ toAddress := testutils.NewAddress()
+ _, _, err := estimator.GetFee(ctx, []byte{}, gasLimit, nil, &toAddress)
+ require.ErrorIs(t, err, commonfee.ErrFeeLimitTooLow)
+
+ // expect dynamic fee data
+ dynamicFees = true
+ estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ _, _, err = estimator.GetFee(ctx, []byte{}, gasLimit, nil, &toAddress)
+ require.ErrorIs(t, err, commonfee.ErrFeeLimitTooLow)
+ })
+
+ t.Run("GetFee, estimate gas limit enabled, buffer exceeds provided limit, fallsback to provided limit", func(t *testing.T) {
+ estimatedGasLimit := uint64(15) // same as provided limit
+ lggr := logger.Test(t)
+ dynamicFees := false // expect legacy fee data
+ geCfg.EstimateGasLimitF = true
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ ethClient.On("EstimateGas", mock.Anything, mock.Anything).Return(estimatedGasLimit, nil).Twice()
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ toAddress := testutils.NewAddress()
+ fee, limit, err := estimator.GetFee(ctx, []byte{}, gasLimit, nil, &toAddress)
+ require.NoError(t, err)
+ assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), limit)
+ assert.True(t, legacyFee.Equal(fee.Legacy))
+ assert.Nil(t, fee.DynamicTipCap)
+ assert.Nil(t, fee.DynamicFeeCap)
+
+ dynamicFees = true // expect dynamic fee data
+ estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ fee, limit, err = estimator.GetFee(ctx, []byte{}, gasLimit, nil, &toAddress)
+ require.NoError(t, err)
+ assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), limit)
+ assert.True(t, dynamicFee.FeeCap.Equal(fee.DynamicFeeCap))
+ assert.True(t, dynamicFee.TipCap.Equal(fee.DynamicTipCap))
+ assert.Nil(t, fee.Legacy)
+ })
+
+ t.Run("GetFee, estimate gas limit enabled, RPC fails and fallsback to provided gas limit", func(t *testing.T) {
+ lggr := logger.Test(t)
+ // expect legacy fee data
+ dynamicFees := false
+ geCfg.EstimateGasLimitF = true
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ ethClient.On("EstimateGas", mock.Anything, mock.Anything).Return(uint64(0), errors.New("something broke")).Twice()
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ toAddress := testutils.NewAddress()
+ fee, limit, err := estimator.GetFee(ctx, []byte{}, gasLimit, nil, &toAddress)
+ require.NoError(t, err)
+ assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), limit)
+ 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.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ fee, limit, err = estimator.GetFee(ctx, []byte{}, gasLimit, nil, &toAddress)
+ require.NoError(t, err)
+ assert.Equal(t, uint64(float32(gasLimit)*limitMultiplier), limit)
+ assert.True(t, dynamicFee.FeeCap.Equal(fee.DynamicFeeCap))
+ assert.True(t, dynamicFee.TipCap.Equal(fee.DynamicTipCap))
+ assert.Nil(t, fee.Legacy)
+ })
+
+ t.Run("GetFee, estimate gas limit enabled, provided fee limit 0, returns uncapped estimation", func(t *testing.T) {
+ est.On("GetDynamicFee", mock.Anything, mock.Anything).
+ Return(dynamicFee, nil).Once()
+ est.On("GetLegacyGas", mock.Anything, mock.Anything, uint64(0), mock.Anything).
+ Return(legacyFee, uint64(0), nil).Once()
+ estimatedGasLimit := uint64(100) // same as provided limit
+ lggr := logger.Test(t)
+ // expect legacy fee data
+ dynamicFees := false
+ geCfg.EstimateGasLimitF = true
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ ethClient.On("EstimateGas", mock.Anything, mock.Anything).Return(estimatedGasLimit, nil).Twice()
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ toAddress := testutils.NewAddress()
+ fee, limit, err := estimator.GetFee(ctx, []byte{}, uint64(0), nil, &toAddress)
+ require.NoError(t, err)
+ assert.Equal(t, uint64(float32(estimatedGasLimit)*gas.EstimateGasBuffer), limit)
+ 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.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ fee, limit, err = estimator.GetFee(ctx, []byte{}, 0, nil, &toAddress)
+ require.NoError(t, err)
+ assert.Equal(t, uint64(float32(estimatedGasLimit)*gas.EstimateGasBuffer), limit)
+ assert.True(t, dynamicFee.FeeCap.Equal(fee.DynamicFeeCap))
+ assert.True(t, dynamicFee.TipCap.Equal(fee.DynamicTipCap))
+ assert.Nil(t, fee.Legacy)
+ })
+
+ t.Run("GetFee, estimate gas limit enabled, provided fee limit 0, returns error on failure", func(t *testing.T) {
+ est.On("GetDynamicFee", mock.Anything, mock.Anything).
+ Return(dynamicFee, nil).Once()
+ est.On("GetLegacyGas", mock.Anything, mock.Anything, uint64(0), mock.Anything).
+ Return(legacyFee, uint64(0), nil).Once()
+ lggr := logger.Test(t)
+ // expect legacy fee data
+ dynamicFees := false
+ geCfg.EstimateGasLimitF = true
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ ethClient.On("EstimateGas", mock.Anything, mock.Anything).Return(uint64(0), errors.New("something broke")).Twice()
+ estimator := gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ toAddress := testutils.NewAddress()
+ _, _, err := estimator.GetFee(ctx, []byte{}, 0, nil, &toAddress)
+ require.Error(t, err)
+
+ // expect dynamic fee data
+ dynamicFees = true
+ estimator = gas.NewEvmFeeEstimator(lggr, getRootEst, dynamicFees, geCfg, ethClient)
+ _, _, err = estimator.GetFee(ctx, []byte{}, 0, nil, &toAddress)
+ require.Error(t, err)
+ })
}
diff --git a/core/chains/evm/gas/rollups/l1_oracle.go b/core/chains/evm/gas/rollups/l1_oracle.go
index f707fab6841..e1249fdb7e9 100644
--- a/core/chains/evm/gas/rollups/l1_oracle.go
+++ b/core/chains/evm/gas/rollups/l1_oracle.go
@@ -43,7 +43,7 @@ const (
PollPeriod = 6 * time.Second
)
-var supportedChainTypes = []chaintype.ChainType{chaintype.ChainArbitrum, chaintype.ChainOptimismBedrock, chaintype.ChainKroma, chaintype.ChainScroll, chaintype.ChainZkSync}
+var supportedChainTypes = []chaintype.ChainType{chaintype.ChainArbitrum, chaintype.ChainOptimismBedrock, chaintype.ChainKroma, chaintype.ChainScroll, chaintype.ChainZkSync, chaintype.ChainMantle}
func IsRollupWithL1Support(chainType chaintype.ChainType) bool {
return slices.Contains(supportedChainTypes, chainType)
@@ -56,7 +56,7 @@ func NewL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType chai
var l1Oracle L1Oracle
var err error
switch chainType {
- case chaintype.ChainOptimismBedrock, chaintype.ChainKroma, chaintype.ChainScroll:
+ case chaintype.ChainOptimismBedrock, chaintype.ChainKroma, chaintype.ChainScroll, chaintype.ChainMantle:
l1Oracle, err = NewOpStackL1GasOracle(lggr, ethClient, chainType)
case chaintype.ChainArbitrum:
l1Oracle, err = NewArbitrumL1GasOracle(lggr, ethClient)
diff --git a/core/chains/evm/gas/rollups/l1_oracle_abi.go b/core/chains/evm/gas/rollups/l1_oracle_abi.go
index fa5d9c85391..848957ce53a 100644
--- a/core/chains/evm/gas/rollups/l1_oracle_abi.go
+++ b/core/chains/evm/gas/rollups/l1_oracle_abi.go
@@ -19,3 +19,4 @@ const OPBaseFeeScalarAbiString = `[{"inputs":[],"name":"baseFeeScalar","outputs"
const OPBlobBaseFeeAbiString = `[{"inputs":[],"name":"blobBaseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]`
const OPBlobBaseFeeScalarAbiString = `[{"inputs":[],"name":"blobBaseFeeScalar","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"}]`
const OPDecimalsAbiString = `[{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}]`
+const MantleTokenRatioAbiString = `[{"inputs":[],"name":"tokenRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]`
diff --git a/core/chains/evm/gas/rollups/op_l1_oracle.go b/core/chains/evm/gas/rollups/op_l1_oracle.go
index 6805cd7095b..1b93f8fc3f9 100644
--- a/core/chains/evm/gas/rollups/op_l1_oracle.go
+++ b/core/chains/evm/gas/rollups/op_l1_oracle.go
@@ -50,6 +50,7 @@ type optimismL1Oracle struct {
blobBaseFeeCalldata []byte
blobBaseFeeScalarCalldata []byte
decimalsCalldata []byte
+ tokenRatioCalldata []byte
isEcotoneCalldata []byte
isEcotoneMethodAbi abi.ABI
isFjordCalldata []byte
@@ -87,7 +88,11 @@ const (
// decimals is a hex encoded call to:
// `function decimals() public pure returns (uint256);`
decimalsMethod = "decimals"
- // OPGasOracleAddress is the address of the precompiled contract that exists on Optimism and Base.
+ // tokenRatio fetches the tokenRatio used for Mantle's gas price calculation
+ // tokenRatio is a hex encoded call to:
+ // `function tokenRatio() public pure returns (uint256);`
+ tokenRatioMethod = "tokenRatio"
+ // OPGasOracleAddress is the address of the precompiled contract that exists on Optimism, Base and Mantle.
OPGasOracleAddress = "0x420000000000000000000000000000000000000F"
// KromaGasOracleAddress is the address of the precompiled contract that exists on Kroma.
KromaGasOracleAddress = "0x4200000000000000000000000000000000000005"
@@ -98,7 +103,7 @@ const (
func NewOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainType chaintype.ChainType) (*optimismL1Oracle, error) {
var precompileAddress string
switch chainType {
- case chaintype.ChainOptimismBedrock:
+ case chaintype.ChainOptimismBedrock, chaintype.ChainMantle:
precompileAddress = OPGasOracleAddress
case chaintype.ChainKroma:
precompileAddress = KromaGasOracleAddress
@@ -187,6 +192,16 @@ func newOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainTy
return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", decimalsMethod, chainType, err)
}
+ // Encode calldata for tokenRatio method
+ tokenRatioMethodAbi, err := abi.JSON(strings.NewReader(MantleTokenRatioAbiString))
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse GasPriceOracle %s() method ABI for chain: %s; %w", tokenRatioMethod, chainType, err)
+ }
+ tokenRatioCalldata, err := tokenRatioMethodAbi.Pack(tokenRatioMethod)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse GasPriceOracle %s() calldata for chain: %s; %w", tokenRatioMethod, chainType, err)
+ }
+
return &optimismL1Oracle{
client: ethClient,
pollPeriod: PollPeriod,
@@ -208,6 +223,7 @@ func newOpStackL1GasOracle(lggr logger.Logger, ethClient l1OracleClient, chainTy
blobBaseFeeCalldata: blobBaseFeeCalldata,
blobBaseFeeScalarCalldata: blobBaseFeeScalarCalldata,
decimalsCalldata: decimalsCalldata,
+ tokenRatioCalldata: tokenRatioCalldata,
isEcotoneCalldata: isEcotoneCalldata,
isEcotoneMethodAbi: isEcotoneMethodAbi,
isFjordCalldata: isFjordCalldata,
@@ -346,6 +362,10 @@ func (o *optimismL1Oracle) GetGasCost(ctx context.Context, tx *gethtypes.Transac
}
func (o *optimismL1Oracle) GetDAGasPrice(ctx context.Context) (*big.Int, error) {
+ if o.chainType == chaintype.ChainMantle {
+ return o.getMantleGasPrice(ctx)
+ }
+
err := o.checkForUpgrade(ctx)
if err != nil {
return nil, err
@@ -443,6 +463,69 @@ func (o *optimismL1Oracle) getV1GasPrice(ctx context.Context) (*big.Int, error)
return new(big.Int).SetBytes(b), nil
}
+// Returns the gas price for Mantle. The formula is the same as Optimism Bedrock (getV1GasPrice), but the tokenRatio parameter is multiplied
+func (o *optimismL1Oracle) getMantleGasPrice(ctx context.Context) (*big.Int, error) {
+ // call oracle to get l1BaseFee and tokenRatio
+ rpcBatchCalls := []rpc.BatchElem{
+ {
+ Method: "eth_call",
+ Args: []any{
+ map[string]interface{}{
+ "from": common.Address{},
+ "to": o.l1OracleAddress,
+ "data": hexutil.Bytes(o.l1BaseFeeCalldata),
+ },
+ "latest",
+ },
+ Result: new(string),
+ },
+ {
+ Method: "eth_call",
+ Args: []any{
+ map[string]interface{}{
+ "from": common.Address{},
+ "to": o.l1OracleAddress,
+ "data": hexutil.Bytes(o.tokenRatioCalldata),
+ },
+ "latest",
+ },
+ Result: new(string),
+ },
+ }
+
+ err := o.client.BatchCallContext(ctx, rpcBatchCalls)
+ if err != nil {
+ return nil, fmt.Errorf("fetch gas price parameters batch call failed: %w", err)
+ }
+ if rpcBatchCalls[0].Error != nil {
+ return nil, fmt.Errorf("%s call failed in a batch: %w", l1BaseFeeMethod, err)
+ }
+ if rpcBatchCalls[1].Error != nil {
+ return nil, fmt.Errorf("%s call failed in a batch: %w", tokenRatioMethod, err)
+ }
+
+ // Extract values from responses
+ l1BaseFeeResult := *(rpcBatchCalls[0].Result.(*string))
+ tokenRatioResult := *(rpcBatchCalls[1].Result.(*string))
+
+ // Decode the responses into bytes
+ l1BaseFeeBytes, err := hexutil.Decode(l1BaseFeeResult)
+ if err != nil {
+ return nil, fmt.Errorf("failed to decode %s rpc result: %w", l1BaseFeeMethod, err)
+ }
+ tokenRatioBytes, err := hexutil.Decode(tokenRatioResult)
+ if err != nil {
+ return nil, fmt.Errorf("failed to decode %s rpc result: %w", tokenRatioMethod, err)
+ }
+
+ // Convert bytes to big int for calculations
+ l1BaseFee := new(big.Int).SetBytes(l1BaseFeeBytes)
+ tokenRatio := new(big.Int).SetBytes(tokenRatioBytes)
+
+ // multiply l1BaseFee and tokenRatio and return
+ return new(big.Int).Mul(l1BaseFee, tokenRatio), nil
+}
+
// Returns the scaled gas price using baseFeeScalar, l1BaseFee, blobBaseFeeScalar, and blobBaseFee fields from the oracle
// Confirmed the same calculation is used to determine gas price for both Ecotone and Fjord
func (o *optimismL1Oracle) getEcotoneFjordGasPrice(ctx context.Context) (*big.Int, error) {
diff --git a/core/chains/evm/gas/rollups/op_l1_oracle_test.go b/core/chains/evm/gas/rollups/op_l1_oracle_test.go
index f5f009f1ea6..88bb96534d3 100644
--- a/core/chains/evm/gas/rollups/op_l1_oracle_test.go
+++ b/core/chains/evm/gas/rollups/op_l1_oracle_test.go
@@ -111,6 +111,94 @@ func TestOPL1Oracle_ReadV1GasPrice(t *testing.T) {
}
}
+func TestOPL1Oracle_ReadMantleGasPrice(t *testing.T) {
+ l1BaseFee := big.NewInt(100)
+ tokenRatio := big.NewInt(40)
+ oracleAddress := common.HexToAddress("0x1234").String()
+
+ t.Parallel()
+ t.Run("correctly fetches gas price if chain is Mantle", func(t *testing.T) {
+ // Encode calldata for l1BaseFee method
+ l1BaseFeeMethodAbi, err := abi.JSON(strings.NewReader(L1BaseFeeAbiString))
+ require.NoError(t, err)
+ l1BaseFeeCalldata, err := l1BaseFeeMethodAbi.Pack(l1BaseFeeMethod)
+ require.NoError(t, err)
+
+ // Encode calldata for tokenRatio method
+ tokenRatioMethodAbi, err := abi.JSON(strings.NewReader(MantleTokenRatioAbiString))
+ require.NoError(t, err)
+ tokenRatioCalldata, err := tokenRatioMethodAbi.Pack(tokenRatioMethod)
+ require.NoError(t, err)
+
+ ethClient := mocks.NewL1OracleClient(t)
+ 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"])
+ require.Equal(t, "latest", rE.Args[1])
+ }
+ require.Equal(t, hexutil.Bytes(l1BaseFeeCalldata), rpcElements[0].Args[0].(map[string]interface{})["data"])
+ require.Equal(t, hexutil.Bytes(tokenRatioCalldata), rpcElements[1].Args[0].(map[string]interface{})["data"])
+
+ res1 := common.BigToHash(l1BaseFee).Hex()
+ res2 := common.BigToHash(tokenRatio).Hex()
+
+ rpcElements[0].Result = &res1
+ rpcElements[1].Result = &res2
+ }).Return(nil).Once()
+
+ oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainMantle, oracleAddress)
+ require.NoError(t, err)
+
+ gasPrice, err := oracle.GetDAGasPrice(tests.Context(t))
+ require.NoError(t, err)
+
+ assert.Equal(t, new(big.Int).Mul(l1BaseFee, tokenRatio), gasPrice)
+ })
+
+ t.Run("fetching Mantle price but rpc returns bad data", func(t *testing.T) {
+ ethClient := mocks.NewL1OracleClient(t)
+ 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, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainMantle, oracleAddress)
+ require.NoError(t, err)
+ _, err = oracle.GetDAGasPrice(tests.Context(t))
+ assert.Error(t, err)
+ })
+
+ t.Run("fetching Mantle price but rpc parent call errors", func(t *testing.T) {
+ ethClient := mocks.NewL1OracleClient(t)
+ ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Return(fmt.Errorf("revert")).Once()
+
+ oracle, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainMantle, oracleAddress)
+ require.NoError(t, err)
+ _, err = oracle.GetDAGasPrice(tests.Context(t))
+ assert.Error(t, err)
+ })
+
+ t.Run("fetching Mantle price but one of the sub rpc call errors", func(t *testing.T) {
+ ethClient := mocks.NewL1OracleClient(t)
+ 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, err := newOpStackL1GasOracle(logger.Test(t), ethClient, chaintype.ChainMantle, oracleAddress)
+ require.NoError(t, err)
+ _, err = oracle.GetDAGasPrice(tests.Context(t))
+ assert.Error(t, err)
+ })
+}
+
func setupUpgradeCheck(t *testing.T, oracleAddress string, isFjord, isEcotone bool) *mocks.L1OracleClient {
trueHex := "0x0000000000000000000000000000000000000000000000000000000000000001"
falseHex := "0x0000000000000000000000000000000000000000000000000000000000000000"
diff --git a/core/chains/evm/headtracker/head_listener.go b/core/chains/evm/headtracker/head_listener.go
deleted file mode 100644
index 04535a34868..00000000000
--- a/core/chains/evm/headtracker/head_listener.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package headtracker
-
-import (
- "math/big"
-
- "github.com/ethereum/go-ethereum"
- "github.com/ethereum/go-ethereum/common"
-
- "github.com/smartcontractkit/chainlink-common/pkg/logger"
- "github.com/smartcontractkit/chainlink/v2/common/headtracker"
-
- htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types"
- evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
- evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
-)
-
-type headListener = headtracker.HeadListener[*evmtypes.Head, common.Hash]
-
-func NewHeadListener(
- lggr logger.Logger,
- ethClient evmclient.Client,
- config htrktypes.Config, chStop chan struct{},
-) headListener {
- return headtracker.NewHeadListener[
- *evmtypes.Head,
- ethereum.Subscription, *big.Int, common.Hash,
- ](lggr, ethClient, config, chStop)
-}
diff --git a/core/chains/evm/headtracker/head_listener_test.go b/core/chains/evm/headtracker/head_listener_test.go
index 29b090bbffe..2e459af2a2b 100644
--- a/core/chains/evm/headtracker/head_listener_test.go
+++ b/core/chains/evm/headtracker/head_listener_test.go
@@ -16,9 +16,9 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+ "github.com/smartcontractkit/chainlink/v2/common/headtracker"
commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml"
- "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/testutils"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
)
@@ -40,17 +40,10 @@ func Test_HeadListener_HappyPath(t *testing.T) {
evmcfg := testutils.NewTestChainScopedConfig(t, func(c *toml.EVMConfig) {
c.NoNewHeadsThreshold = &commonconfig.Duration{}
})
- chStop := make(chan struct{})
- hl := headtracker.NewHeadListener(lggr, ethClient, evmcfg.EVM(), chStop)
var headCount atomic.Int32
- handler := func(context.Context, *evmtypes.Head) error {
- headCount.Add(1)
- return nil
- }
-
- subscribeAwaiter := testutils.NewAwaiter()
unsubscribeAwaiter := testutils.NewAwaiter()
+ subscribeAwaiter := testutils.NewAwaiter()
var chHeads chan<- *evmtypes.Head
var chErr = make(chan error)
var chSubErr <-chan error = chErr
@@ -66,23 +59,23 @@ func Test_HeadListener_HappyPath(t *testing.T) {
close(chErr)
})
- doneAwaiter := testutils.NewAwaiter()
- done := func() {
- doneAwaiter.ItHappened()
- }
- go hl.ListenForNewHeads(func() {}, handler, done)
-
- subscribeAwaiter.AwaitOrFail(t, tests.WaitTimeout(t))
- require.Eventually(t, hl.Connected, tests.WaitTimeout(t), tests.TestInterval)
+ func() {
+ hl := headtracker.NewHeadListener(lggr, ethClient, evmcfg.EVM(), nil, func(context.Context, *evmtypes.Head) error {
+ headCount.Add(1)
+ return nil
+ })
+ require.NoError(t, hl.Start(tests.Context(t)))
+ defer func() { assert.NoError(t, hl.Close()) }()
- chHeads <- testutils.Head(0)
- chHeads <- testutils.Head(1)
- chHeads <- testutils.Head(2)
+ subscribeAwaiter.AwaitOrFail(t, tests.WaitTimeout(t))
+ require.Eventually(t, hl.Connected, tests.WaitTimeout(t), tests.TestInterval)
- require.True(t, hl.ReceivingHeads())
+ chHeads <- testutils.Head(0)
+ chHeads <- testutils.Head(1)
+ chHeads <- testutils.Head(2)
- close(chStop)
- doneAwaiter.AwaitOrFail(t)
+ require.True(t, hl.ReceivingHeads())
+ }()
unsubscribeAwaiter.AwaitOrFail(t)
require.Equal(t, int32(3), headCount.Load())
@@ -101,14 +94,8 @@ func Test_HeadListener_NotReceivingHeads(t *testing.T) {
evmcfg := testutils.NewTestChainScopedConfig(t, func(c *toml.EVMConfig) {
c.NoNewHeadsThreshold = commonconfig.MustNewDuration(time.Second)
})
- chStop := make(chan struct{})
- hl := headtracker.NewHeadListener(lggr, ethClient, evmcfg.EVM(), chStop)
firstHeadAwaiter := testutils.NewAwaiter()
- handler := func(context.Context, *evmtypes.Head) error {
- firstHeadAwaiter.ItHappened()
- return nil
- }
subscribeAwaiter := testutils.NewAwaiter()
var chHeads chan<- *evmtypes.Head
@@ -125,25 +112,25 @@ func Test_HeadListener_NotReceivingHeads(t *testing.T) {
close(chErr)
})
- doneAwaiter := testutils.NewAwaiter()
- done := func() {
- doneAwaiter.ItHappened()
- }
- go hl.ListenForNewHeads(func() {}, handler, done)
-
- subscribeAwaiter.AwaitOrFail(t, tests.WaitTimeout(t))
+ func() {
+ hl := headtracker.NewHeadListener(lggr, ethClient, evmcfg.EVM(), nil, func(context.Context, *evmtypes.Head) error {
+ firstHeadAwaiter.ItHappened()
+ return nil
+ })
+ require.NoError(t, hl.Start(tests.Context(t)))
+ defer func() { assert.NoError(t, hl.Close()) }()
- chHeads <- testutils.Head(0)
- firstHeadAwaiter.AwaitOrFail(t)
+ subscribeAwaiter.AwaitOrFail(t, tests.WaitTimeout(t))
- require.True(t, hl.ReceivingHeads())
+ chHeads <- testutils.Head(0)
+ firstHeadAwaiter.AwaitOrFail(t)
- time.Sleep(time.Second * 2)
+ require.True(t, hl.ReceivingHeads())
- require.False(t, hl.ReceivingHeads())
+ time.Sleep(time.Second * 2)
- close(chStop)
- doneAwaiter.AwaitOrFail(t)
+ require.False(t, hl.ReceivingHeads())
+ }()
}
func Test_HeadListener_SubscriptionErr(t *testing.T) {
@@ -161,19 +148,11 @@ func Test_HeadListener_SubscriptionErr(t *testing.T) {
for _, test := range cases {
test := test
t.Run(test.name, func(t *testing.T) {
- l := logger.Test(t)
+ lggr := logger.Test(t)
ethClient := testutils.NewEthClientMockWithDefaultChain(t)
evmcfg := testutils.NewTestChainScopedConfig(t, nil)
- chStop := make(chan struct{})
- hl := headtracker.NewHeadListener(l, ethClient, evmcfg.EVM(), chStop)
hnhCalled := make(chan *evmtypes.Head)
- hnh := func(_ context.Context, header *evmtypes.Head) error {
- hnhCalled <- header
- return nil
- }
- doneAwaiter := testutils.NewAwaiter()
- done := doneAwaiter.ItHappened
chSubErrTest := make(chan error)
var chSubErr <-chan error = chSubErrTest
@@ -189,63 +168,66 @@ func Test_HeadListener_SubscriptionErr(t *testing.T) {
headsCh = args.Get(1).(chan<- *evmtypes.Head)
subscribeAwaiter.ItHappened()
})
- go func() {
- hl.ListenForNewHeads(func() {}, hnh, done)
- }()
-
- // Put a head on the channel to ensure we test all code paths
- subscribeAwaiter.AwaitOrFail(t, tests.WaitTimeout(t))
- head := testutils.Head(0)
- headsCh <- head
-
- h := <-hnhCalled
- assert.Equal(t, head, h)
-
- // Expect a call to unsubscribe on error
- sub.On("Unsubscribe").Once().Run(func(_ mock.Arguments) {
- close(headsCh)
- // geth guarantees that Unsubscribe closes the errors channel
- if !test.closeErr {
+ func() {
+ hl := headtracker.NewHeadListener(lggr, ethClient, evmcfg.EVM(), nil, func(_ context.Context, header *evmtypes.Head) error {
+ hnhCalled <- header
+ return nil
+ })
+ require.NoError(t, hl.Start(tests.Context(t)))
+ defer func() { assert.NoError(t, hl.Close()) }()
+
+ // Put a head on the channel to ensure we test all code paths
+ subscribeAwaiter.AwaitOrFail(t, tests.WaitTimeout(t))
+ head := testutils.Head(0)
+ headsCh <- head
+
+ h := <-hnhCalled
+ assert.Equal(t, head, h)
+
+ // Expect a call to unsubscribe on error
+ sub.On("Unsubscribe").Once().Run(func(_ mock.Arguments) {
+ close(headsCh)
+ // geth guarantees that Unsubscribe closes the errors channel
+ if !test.closeErr {
+ close(chSubErrTest)
+ }
+ })
+ // Expect a resubscribe
+ chSubErrTest2 := make(chan error)
+ var chSubErr2 <-chan error = chSubErrTest2
+ sub2 := commonmocks.NewSubscription(t)
+ sub2.On("Err").Return(chSubErr2)
+ subscribeAwaiter2 := testutils.NewAwaiter()
+
+ var headsCh2 chan<- *evmtypes.Head
+ ethClient.On("SubscribeNewHead", mock.Anything, mock.AnythingOfType("chan<- *types.Head")).Return(sub2, nil).Once().Run(func(args mock.Arguments) {
+ headsCh2 = args.Get(1).(chan<- *evmtypes.Head)
+ subscribeAwaiter2.ItHappened()
+ })
+
+ // Sending test error
+ if test.closeErr {
close(chSubErrTest)
+ } else {
+ chSubErrTest <- test.err
}
- })
- // Expect a resubscribe
- chSubErrTest2 := make(chan error)
- var chSubErr2 <-chan error = chSubErrTest2
- sub2 := commonmocks.NewSubscription(t)
- sub2.On("Err").Return(chSubErr2)
- subscribeAwaiter2 := testutils.NewAwaiter()
-
- var headsCh2 chan<- *evmtypes.Head
- ethClient.On("SubscribeNewHead", mock.Anything, mock.AnythingOfType("chan<- *types.Head")).Return(sub2, nil).Once().Run(func(args mock.Arguments) {
- headsCh2 = args.Get(1).(chan<- *evmtypes.Head)
- subscribeAwaiter2.ItHappened()
- })
-
- // Sending test error
- if test.closeErr {
- close(chSubErrTest)
- } else {
- chSubErrTest <- test.err
- }
- // Wait for it to resubscribe
- subscribeAwaiter2.AwaitOrFail(t, tests.WaitTimeout(t))
+ // Wait for it to resubscribe
+ subscribeAwaiter2.AwaitOrFail(t, tests.WaitTimeout(t))
- head2 := testutils.Head(1)
- headsCh2 <- head2
+ head2 := testutils.Head(1)
+ headsCh2 <- head2
- h2 := <-hnhCalled
- assert.Equal(t, head2, h2)
+ h2 := <-hnhCalled
+ assert.Equal(t, head2, h2)
- // Second call to unsubscribe on close
- sub2.On("Unsubscribe").Once().Run(func(_ mock.Arguments) {
- close(headsCh2)
- // geth guarantees that Unsubscribe closes the errors channel
- close(chSubErrTest2)
- })
- close(chStop)
- doneAwaiter.AwaitOrFail(t)
+ // Second call to unsubscribe on close
+ sub2.On("Unsubscribe").Once().Run(func(_ mock.Arguments) {
+ close(headsCh2)
+ // geth guarantees that Unsubscribe closes the errors channel
+ close(chSubErrTest2)
+ })
+ }()
})
}
}
diff --git a/core/chains/evm/headtracker/head_tracker.go b/core/chains/evm/headtracker/head_tracker.go
index d6c2cdc64e7..f7607189f7e 100644
--- a/core/chains/evm/headtracker/head_tracker.go
+++ b/core/chains/evm/headtracker/head_tracker.go
@@ -2,10 +2,8 @@ package headtracker
import (
"context"
- "math/big"
"github.com/ethereum/go-ethereum"
- "github.com/ethereum/go-ethereum/common"
"go.uber.org/zap/zapcore"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
@@ -27,7 +25,7 @@ func NewHeadTracker(
headSaver httypes.HeadSaver,
mailMon *mailbox.Monitor,
) httypes.HeadTracker {
- return headtracker.NewHeadTracker[*evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash](
+ return headtracker.NewHeadTracker[*evmtypes.Head, ethereum.Subscription](
lggr,
ethClient,
config,
diff --git a/core/chains/evm/headtracker/simulated_head_tracker.go b/core/chains/evm/headtracker/simulated_head_tracker.go
index e1e550de992..62bb4968c2f 100644
--- a/core/chains/evm/headtracker/simulated_head_tracker.go
+++ b/core/chains/evm/headtracker/simulated_head_tracker.go
@@ -2,6 +2,7 @@ package headtracker
import (
"context"
+ "errors"
"fmt"
"math/big"
@@ -51,3 +52,31 @@ func (ht *simulatedHeadTracker) LatestAndFinalizedBlock(ctx context.Context) (*e
return latest, finalizedBlock, nil
}
+
+func (ht *simulatedHeadTracker) LatestChain() *evmtypes.Head {
+ return nil
+}
+
+func (ht *simulatedHeadTracker) HealthReport() map[string]error {
+ return nil
+}
+
+func (ht *simulatedHeadTracker) Start(_ context.Context) error {
+ return nil
+}
+
+func (ht *simulatedHeadTracker) Close() error {
+ return nil
+}
+
+func (ht *simulatedHeadTracker) Backfill(_ context.Context, _ *evmtypes.Head) error {
+ return errors.New("unimplemented")
+}
+
+func (ht *simulatedHeadTracker) Name() string {
+ return "SimulatedHeadTracker"
+}
+
+func (ht *simulatedHeadTracker) Ready() error {
+ return nil
+}
diff --git a/core/chains/evm/logpoller/observability.go b/core/chains/evm/logpoller/observability.go
index 7842a060eca..782307e7d06 100644
--- a/core/chains/evm/logpoller/observability.go
+++ b/core/chains/evm/logpoller/observability.go
@@ -285,7 +285,7 @@ func withObservedExecAndRowsAffected(o *ObservedORM, queryName string, queryType
WithLabelValues(o.chainId, queryName, string(queryType)).
Observe(float64(time.Since(queryStarted)))
- if err != nil {
+ if err == nil {
o.datasetSize.
WithLabelValues(o.chainId, queryName, string(queryType)).
Set(float64(rowsAffected))
diff --git a/core/chains/evm/logpoller/observability_test.go b/core/chains/evm/logpoller/observability_test.go
index 78c27b4b8f7..4ea7adceab0 100644
--- a/core/chains/evm/logpoller/observability_test.go
+++ b/core/chains/evm/logpoller/observability_test.go
@@ -16,6 +16,7 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"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/testutils"
@@ -117,6 +118,16 @@ func TestCountersAreProperlyPopulatedForWrites(t *testing.T) {
assert.Equal(t, float64(20), testutil.ToFloat64(orm.logsInserted.WithLabelValues("420")))
assert.Equal(t, float64(2), testutil.ToFloat64(orm.blocksInserted.WithLabelValues("420")))
+ rowsAffected, err := orm.DeleteExpiredLogs(ctx, 3)
+ require.NoError(t, err)
+ require.Equal(t, int64(3), rowsAffected)
+ assert.Equal(t, 3, counterFromGaugeByLabels(orm.datasetSize, "420", "DeleteExpiredLogs", "delete"))
+
+ rowsAffected, err = orm.DeleteBlocksBefore(ctx, 30, 0)
+ require.NoError(t, err)
+ require.Equal(t, int64(2), rowsAffected)
+ assert.Equal(t, 2, counterFromGaugeByLabels(orm.datasetSize, "420", "DeleteBlocksBefore", "delete"))
+
// Don't update counters in case of an error
require.Error(t, orm.InsertLogsWithBlock(ctx, logs, NewLogPollerBlock(utils.RandomBytes32(), 0, time.Now(), 0)))
assert.Equal(t, float64(20), testutil.ToFloat64(orm.logsInserted.WithLabelValues("420")))
diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go
index 1d249760736..22870efccf3 100644
--- a/core/chains/evm/logpoller/orm.go
+++ b/core/chains/evm/logpoller/orm.go
@@ -15,6 +15,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
@@ -313,34 +314,29 @@ type Exp struct {
ShouldDelete bool
}
+// DeleteExpiredLogs removes any logs which either:
+// - don't match any currently registered filters, or
+// - have a timestamp older than any matching filter's retention, UNLESS there is at
+// least one matching filter with retention=0
func (o *DSORM) DeleteExpiredLogs(ctx context.Context, limit int64) (int64, error) {
var err error
var result sql.Result
- if limit > 0 {
- result, err = o.ds.ExecContext(ctx, `
- DELETE FROM evm.logs
+ query := `DELETE FROM evm.logs
WHERE (evm_chain_id, address, event_sig, block_number) IN (
SELECT l.evm_chain_id, l.address, l.event_sig, l.block_number
FROM evm.logs l
- INNER JOIN (
- SELECT address, event, MAX(retention) AS retention
+ LEFT JOIN (
+ SELECT address, event, CASE WHEN MIN(retention) = 0 THEN 0 ELSE MAX(retention) END AS retention
FROM evm.log_poller_filters
WHERE evm_chain_id = $1
GROUP BY evm_chain_id, address, event
- HAVING NOT 0 = ANY(ARRAY_AGG(retention))
) r ON l.evm_chain_id = $1 AND l.address = r.address AND l.event_sig = r.event
- AND l.block_timestamp <= STATEMENT_TIMESTAMP() - (r.retention / 10^9 * interval '1 second')
- LIMIT $2
- )`, ubig.New(o.chainID), limit)
+ WHERE r.retention IS NULL OR (r.retention != 0 AND l.block_timestamp <= STATEMENT_TIMESTAMP() - (r.retention / 10^9 * interval '1 second')) %s)`
+
+ if limit > 0 {
+ result, err = o.ds.ExecContext(ctx, fmt.Sprintf(query, "LIMIT $2"), ubig.New(o.chainID), limit)
} else {
- result, err = o.ds.ExecContext(ctx, `WITH r AS
- ( SELECT address, event, MAX(retention) AS retention
- FROM evm.log_poller_filters WHERE evm_chain_id=$1
- GROUP BY evm_chain_id,address, event HAVING NOT 0 = ANY(ARRAY_AGG(retention))
- ) DELETE FROM evm.logs l USING r
- WHERE l.evm_chain_id = $1 AND l.address=r.address AND l.event_sig=r.event
- AND l.block_timestamp <= STATEMENT_TIMESTAMP() - (r.retention / 10^9 * interval '1 second')`, // retention is in nanoseconds (time.Duration aka BIGINT)
- ubig.New(o.chainID))
+ result, err = o.ds.ExecContext(ctx, fmt.Sprintf(query, ""), ubig.New(o.chainID))
}
if err != nil {
diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go
index ce56c799226..0df34196ff9 100644
--- a/core/chains/evm/logpoller/orm_test.go
+++ b/core/chains/evm/logpoller/orm_test.go
@@ -7,6 +7,7 @@ import (
"fmt"
"math"
"math/big"
+ "strconv"
"testing"
"time"
@@ -457,20 +458,21 @@ func TestORM(t *testing.T) {
time.Sleep(2 * time.Millisecond) // just in case we haven't reached the end of the 1ms retention period
deleted, err := o1.DeleteExpiredLogs(ctx, 0)
require.NoError(t, err)
- assert.Equal(t, int64(1), deleted)
+ assert.Equal(t, int64(4), deleted)
+
logs, err = o1.SelectLogsByBlockRange(ctx, 1, latest.BlockNumber)
require.NoError(t, err)
- // The only log which should be deleted is the one which matches filter1 (ret=1ms) but not filter12 (ret=1 hour)
- // Importantly, it shouldn't delete any logs matching only filter0 (ret=0 meaning permanent retention). Anything
- // matching filter12 should be kept regardless of what other filters it matches.
- assert.Len(t, logs, 7)
+ // It should have retained the log matching filter0 (due to ret=0 meaning permanent retention) as well as all
+ // 3 logs matching filter12 (ret=1 hour). It should have deleted 3 logs not matching any filter, as well as 1
+ // of the 2 logs matching filter1 (ret=1ms)--the one that doesn't also match filter12.
+ assert.Len(t, logs, 4)
// Delete logs after should delete all logs.
err = o1.DeleteLogsAndBlocksAfter(ctx, 1)
require.NoError(t, err)
logs, err = o1.SelectLogsByBlockRange(ctx, 1, latest.BlockNumber)
require.NoError(t, err)
- require.Zero(t, len(logs))
+ assert.Zero(t, len(logs))
}
type PgxLogger struct {
@@ -642,7 +644,7 @@ func TestORM_IndexedLogs(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 2, len(lgs))
- blockRangeFilter := func(start, end uint64, topicIdx uint64, topicValues []uint64) query.KeyFilter {
+ blockRangeFilter := func(start, end string, topicIdx uint64, topicValues []uint64) query.KeyFilter {
return query.KeyFilter{
Expressions: []query.Expression{
logpoller.NewAddressFilter(addr),
@@ -658,7 +660,7 @@ func TestORM_IndexedLogs(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 1, len(lgs))
- lgs, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 1, 1, []uint64{1}), limiter, "")
+ lgs, err = o1.FilteredLogs(ctx, blockRangeFilter("1", "1", 1, []uint64{1}), limiter, "")
require.NoError(t, err)
assert.Equal(t, 1, len(lgs))
@@ -666,7 +668,7 @@ func TestORM_IndexedLogs(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 1, len(lgs))
- lgs, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 2, 1, []uint64{2}), limiter, "")
+ lgs, err = o1.FilteredLogs(ctx, blockRangeFilter("1", "2", 1, []uint64{2}), limiter, "")
require.NoError(t, err)
assert.Equal(t, 1, len(lgs))
@@ -674,7 +676,7 @@ func TestORM_IndexedLogs(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 1, len(lgs))
- lgs, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 2, 1, []uint64{1}), limiter, "")
+ lgs, err = o1.FilteredLogs(ctx, blockRangeFilter("1", "2", 1, []uint64{1}), limiter, "")
require.NoError(t, err)
assert.Equal(t, 1, len(lgs))
@@ -682,7 +684,7 @@ func TestORM_IndexedLogs(t *testing.T) {
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid index for topic: 0")
- _, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 2, 0, []uint64{1}), limiter, "")
+ _, err = o1.FilteredLogs(ctx, blockRangeFilter("1", "2", 0, []uint64{1}), limiter, "")
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid index for topic: 0")
@@ -690,7 +692,7 @@ func TestORM_IndexedLogs(t *testing.T) {
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid index for topic: 4")
- _, err = o1.FilteredLogs(ctx, blockRangeFilter(1, 2, 4, []uint64{1}), limiter, "")
+ _, err = o1.FilteredLogs(ctx, blockRangeFilter("1", "2", 4, []uint64{1}), limiter, "")
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid index for topic: 4")
@@ -1042,7 +1044,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) {
}
require.NoError(t, o1.InsertLogs(ctx, inputLogs))
- filter := func(sigs []common.Hash, startBlock, endBlock int64) query.KeyFilter {
+ filter := func(sigs []common.Hash, startBlock, endBlock string) query.KeyFilter {
filters := []query.Expression{
logpoller.NewAddressFilter(sourceAddr),
}
@@ -1064,8 +1066,8 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) {
filters = append(filters, query.Expression{
BoolExpression: query.BoolExpression{
Expressions: []query.Expression{
- query.Block(uint64(startBlock), primitives.Gte),
- query.Block(uint64(endBlock), primitives.Lte),
+ query.Block(startBlock, primitives.Gte),
+ query.Block(endBlock, primitives.Lte),
},
BoolOperator: query.AND,
},
@@ -1097,8 +1099,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) {
})
assertion(t, logs, err, startBlock, endBlock)
-
- logs, err = th.ORM.FilteredLogs(ctx, filter([]common.Hash{topic, topic2}, startBlock, endBlock), limiter, "")
+ logs, err = th.ORM.FilteredLogs(ctx, filter([]common.Hash{topic, topic2}, strconv.Itoa(int(startBlock)), strconv.Itoa(int(endBlock))), limiter, "")
assertion(t, logs, err, startBlock, endBlock)
}
@@ -1160,7 +1161,7 @@ func TestLogPoller_Logs(t *testing.T) {
assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000005", lgs[4].BlockHash.String())
assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000005", lgs[5].BlockHash.String())
- logFilter := func(start, end uint64, address common.Address) query.KeyFilter {
+ logFilter := func(start, end string, address common.Address) query.KeyFilter {
return query.KeyFilter{
Expressions: []query.Expression{
logpoller.NewAddressFilter(address),
@@ -1181,7 +1182,7 @@ func TestLogPoller_Logs(t *testing.T) {
assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000005", lgs[1].BlockHash.String())
assert.Equal(t, address1, lgs[1].Address)
- lgs, err = th.ORM.FilteredLogs(ctx, logFilter(1, 3, address1), query.LimitAndSort{
+ lgs, err = th.ORM.FilteredLogs(ctx, logFilter("1", "3", address1), query.LimitAndSort{
SortBy: []query.SortBy{query.NewSortBySequence(query.Asc)},
}, "")
require.NoError(t, err)
@@ -1201,7 +1202,7 @@ func TestLogPoller_Logs(t *testing.T) {
assert.Equal(t, address2, lgs[0].Address)
assert.Equal(t, event1.Bytes(), lgs[0].Topics[0])
- lgs, err = th.ORM.FilteredLogs(ctx, logFilter(2, 2, address2), query.LimitAndSort{
+ lgs, err = th.ORM.FilteredLogs(ctx, logFilter("2", "2", address2), query.LimitAndSort{
SortBy: []query.SortBy{query.NewSortBySequence(query.Asc)},
}, "")
require.NoError(t, err)
diff --git a/core/chains/evm/logpoller/parser_test.go b/core/chains/evm/logpoller/parser_test.go
index 5e99ec7ba82..27af9e83188 100644
--- a/core/chains/evm/logpoller/parser_test.go
+++ b/core/chains/evm/logpoller/parser_test.go
@@ -141,7 +141,7 @@ func TestDSLParser(t *testing.T) {
expressions := []query.Expression{
query.Timestamp(10, primitives.Eq),
query.TxHash(common.HexToHash("0x84").String()),
- query.Block(99, primitives.Neq),
+ query.Block("99", primitives.Neq),
query.Confidence(primitives.Finalized),
}
limiter := query.NewLimitAndSort(query.CursorLimit("10-20-0x42", query.CursorPrevious, 20))
diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go
index b8194a38af9..1f5275c13fb 100644
--- a/core/chains/evm/monitor/balance.go
+++ b/core/chains/evm/monitor/balance.go
@@ -33,14 +33,15 @@ type (
}
balanceMonitor struct {
- services.StateMachine
- logger logger.Logger
+ services.Service
+ eng *services.Engine
+
ethClient evmclient.Client
chainID *big.Int
chainIDStr string
ethKeyStore keystore.Eth
ethBalances map[gethCommon.Address]*assets.Eth
- ethBalancesMtx *sync.RWMutex
+ ethBalancesMtx sync.RWMutex
sleeperTask *utils.SleeperTask
}
@@ -53,62 +54,41 @@ var _ BalanceMonitor = (*balanceMonitor)(nil)
func NewBalanceMonitor(ethClient evmclient.Client, ethKeyStore keystore.Eth, lggr logger.Logger) *balanceMonitor {
chainId := ethClient.ConfiguredChainID()
bm := &balanceMonitor{
- services.StateMachine{},
- logger.Named(lggr, "BalanceMonitor"),
- ethClient,
- chainId,
- chainId.String(),
- ethKeyStore,
- make(map[gethCommon.Address]*assets.Eth),
- new(sync.RWMutex),
- nil,
+ ethClient: ethClient,
+ chainID: chainId,
+ chainIDStr: chainId.String(),
+ ethKeyStore: ethKeyStore,
+ ethBalances: make(map[gethCommon.Address]*assets.Eth),
}
+ bm.Service, bm.eng = services.Config{
+ Name: "BalanceMonitor",
+ Start: bm.start,
+ Close: bm.close,
+ }.NewServiceEngine(lggr)
bm.sleeperTask = utils.NewSleeperTask(&worker{bm: bm})
return bm
}
-func (bm *balanceMonitor) Start(ctx context.Context) error {
- return bm.StartOnce("BalanceMonitor", func() error {
- // Always query latest balance on start
- (&worker{bm}).WorkCtx(ctx)
- return nil
- })
-}
-
-// Close shuts down the BalanceMonitor, should not be used after this
-func (bm *balanceMonitor) Close() error {
- return bm.StopOnce("BalanceMonitor", func() error {
- return bm.sleeperTask.Stop()
- })
-}
-
-func (bm *balanceMonitor) Ready() error {
+func (bm *balanceMonitor) start(ctx context.Context) error {
+ // Always query latest balance on start
+ (&worker{bm}).WorkCtx(ctx)
return nil
}
-func (bm *balanceMonitor) Name() string {
- return bm.logger.Name()
-}
-
-func (bm *balanceMonitor) HealthReport() map[string]error {
- return map[string]error{bm.Name(): bm.Healthy()}
+// Close shuts down the BalanceMonitor, should not be used after this
+func (bm *balanceMonitor) close() error {
+ return bm.sleeperTask.Stop()
}
// OnNewLongestChain checks the balance for each key
-func (bm *balanceMonitor) OnNewLongestChain(_ context.Context, head *evmtypes.Head) {
- ok := bm.IfStarted(func() {
- bm.checkBalance(head)
- })
+func (bm *balanceMonitor) OnNewLongestChain(_ context.Context, _ *evmtypes.Head) {
+ bm.eng.Debugw("BalanceMonitor: signalling balance worker")
+ ok := bm.sleeperTask.WakeUpIfStarted()
if !ok {
- bm.logger.Debugw("BalanceMonitor: ignoring OnNewLongestChain call, balance monitor is not started", "state", bm.State())
+ bm.eng.Debugw("BalanceMonitor: ignoring OnNewLongestChain call, balance monitor is not started", "state", bm.sleeperTask.State())
}
}
-func (bm *balanceMonitor) checkBalance(head *evmtypes.Head) {
- bm.logger.Debugw("BalanceMonitor: signalling balance worker")
- bm.sleeperTask.WakeUp()
-}
-
func (bm *balanceMonitor) updateBalance(ethBal assets.Eth, address gethCommon.Address) {
bm.promUpdateEthBalance(ðBal, address)
@@ -117,7 +97,7 @@ func (bm *balanceMonitor) updateBalance(ethBal assets.Eth, address gethCommon.Ad
bm.ethBalances[address] = ðBal
bm.ethBalancesMtx.Unlock()
- lgr := logger.Named(bm.logger, "BalanceLog")
+ lgr := logger.Named(bm.eng, "BalanceLog")
lgr = logger.With(lgr,
"address", address.Hex(),
"ethBalance", ethBal.String(),
@@ -151,7 +131,7 @@ func (bm *balanceMonitor) promUpdateEthBalance(balance *assets.Eth, from gethCom
balanceFloat, err := ApproximateFloat64(balance)
if err != nil {
- bm.logger.Error(fmt.Errorf("updatePrometheusEthBalance: %v", err))
+ bm.eng.Error(fmt.Errorf("updatePrometheusEthBalance: %v", err))
return
}
@@ -174,7 +154,7 @@ func (w *worker) Work() {
func (w *worker) WorkCtx(ctx context.Context) {
enabledAddresses, err := w.bm.ethKeyStore.EnabledAddressesForChain(ctx, w.bm.chainID)
if err != nil {
- w.bm.logger.Error("BalanceMonitor: error getting keys", err)
+ w.bm.eng.Error("BalanceMonitor: error getting keys", err)
}
var wg sync.WaitGroup
@@ -198,12 +178,12 @@ func (w *worker) checkAccountBalance(ctx context.Context, address gethCommon.Add
bal, err := w.bm.ethClient.BalanceAt(ctx, address, nil)
if err != nil {
- w.bm.logger.Errorw(fmt.Sprintf("BalanceMonitor: error getting balance for key %s", address.Hex()),
+ w.bm.eng.Errorw(fmt.Sprintf("BalanceMonitor: error getting balance for key %s", address.Hex()),
"err", err,
"address", address,
)
} else if bal == nil {
- w.bm.logger.Errorw(fmt.Sprintf("BalanceMonitor: error getting balance for key %s: invariant violation, bal may not be nil", address.Hex()),
+ w.bm.eng.Errorw(fmt.Sprintf("BalanceMonitor: error getting balance for key %s: invariant violation, bal may not be nil", address.Hex()),
"err", err,
"address", address,
)
diff --git a/core/chains/evm/testutils/client.go b/core/chains/evm/testutils/client.go
index 89c97b01e6d..1e5523fbff9 100644
--- a/core/chains/evm/testutils/client.go
+++ b/core/chains/evm/testutils/client.go
@@ -148,8 +148,12 @@ func (ts *testWSServer) newWSHandler(chainID *big.Int, callback JSONRPCHandler)
ts.t.Log("Received message", string(data))
req := gjson.ParseBytes(data)
if !req.IsObject() {
- ts.t.Logf("Request must be object: %v", req.Type)
- return
+ if isSingleObjectArray := req.IsArray() && len(req.Array()) == 1; !isSingleObjectArray {
+ ts.t.Logf("Request must be object: %v", req.Type)
+ return
+ }
+
+ req = req.Array()[0]
}
if e := req.Get("error"); e.Exists() {
ts.t.Logf("Received jsonrpc error: %v", e)
diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go
index 8566adcb5c5..c57ecc44124 100644
--- a/core/chains/evm/txmgr/attempts.go
+++ b/core/chains/evm/txmgr/attempts.go
@@ -58,7 +58,7 @@ func (c *evmTxAttemptBuilder) NewTxAttempt(ctx context.Context, etx Tx, lggr log
// used for L2 re-estimation on broadcasting (note EIP1559 must be disabled otherwise this will fail with mismatched fees + tx type)
func (c *evmTxAttemptBuilder) NewTxAttemptWithType(ctx context.Context, etx Tx, lggr logger.Logger, txType int, opts ...feetypes.Opt) (attempt TxAttempt, fee gas.EvmFee, feeLimit uint64, retryable bool, err error) {
keySpecificMaxGasPriceWei := c.feeConfig.PriceMaxKey(etx.FromAddress)
- fee, feeLimit, err = c.EvmFeeEstimator.GetFee(ctx, etx.EncodedPayload, etx.FeeLimit, keySpecificMaxGasPriceWei, opts...)
+ fee, feeLimit, err = c.EvmFeeEstimator.GetFee(ctx, etx.EncodedPayload, etx.FeeLimit, keySpecificMaxGasPriceWei, &etx.ToAddress, opts...)
if err != nil {
return attempt, fee, feeLimit, true, pkgerrors.Wrap(err, "failed to get fee") // estimator errors are retryable
}
@@ -71,8 +71,8 @@ func (c *evmTxAttemptBuilder) NewTxAttemptWithType(ctx context.Context, etx Tx,
// used in the txm broadcaster + confirmer when tx ix rejected for too low fee or is not included in a timely manner
func (c *evmTxAttemptBuilder) NewBumpTxAttempt(ctx context.Context, etx Tx, previousAttempt TxAttempt, priorAttempts []TxAttempt, lggr logger.Logger) (attempt TxAttempt, bumpedFee gas.EvmFee, bumpedFeeLimit uint64, retryable bool, err error) {
keySpecificMaxGasPriceWei := c.feeConfig.PriceMaxKey(etx.FromAddress)
-
- bumpedFee, bumpedFeeLimit, err = c.EvmFeeEstimator.BumpFee(ctx, previousAttempt.TxFee, etx.FeeLimit, keySpecificMaxGasPriceWei, newEvmPriorAttempts(priorAttempts))
+ // Use the fee limit from the previous attempt to maintain limits adjusted for 2D fees or by estimation
+ bumpedFee, bumpedFeeLimit, err = c.EvmFeeEstimator.BumpFee(ctx, previousAttempt.TxFee, previousAttempt.ChainSpecificFeeLimit, keySpecificMaxGasPriceWei, newEvmPriorAttempts(priorAttempts))
if err != nil {
return attempt, bumpedFee, bumpedFeeLimit, true, pkgerrors.Wrap(err, "failed to bump fee") // estimator errors are retryable
}
diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go
index 6be8cd7067b..ea00f7a3472 100644
--- a/core/chains/evm/txmgr/attempts_test.go
+++ b/core/chains/evm/txmgr/attempts_test.go
@@ -339,7 +339,7 @@ func TestTxm_NewCustomTxAttempt_NonRetryableErrors(t *testing.T) {
func TestTxm_EvmTxAttemptBuilder_RetryableEstimatorError(t *testing.T) {
est := gasmocks.NewEvmFeeEstimator(t)
- est.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint64(0), pkgerrors.New("fail"))
+ est.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint64(0), pkgerrors.New("fail"))
est.On("BumpFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint64(0), pkgerrors.New("fail"))
kst := ksmocks.NewEth(t)
diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go
index 3559c329dee..4edc5572f04 100644
--- a/core/chains/evm/txmgr/broadcaster_test.go
+++ b/core/chains/evm/txmgr/broadcaster_test.go
@@ -29,11 +29,14 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
commonclient "github.com/smartcontractkit/chainlink/v2/common/client"
+ commmonfee "github.com/smartcontractkit/chainlink/v2/common/fee"
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"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype"
"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"
@@ -68,9 +71,9 @@ func NewTestEthBroadcaster(
estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator {
return gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), nil, ge.BlockHistory(), lggr, nil)
- }, ge.EIP1559DynamicFees(), ge)
+ }, ge.EIP1559DynamicFees(), ge, ethClient)
txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator)
- ethBroadcaster := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), gconfig.Database().Listener(), keyStore, txBuilder, nonceTracker, lggr, checkerFactory, nonceAutoSync)
+ ethBroadcaster := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), gconfig.Database().Listener(), keyStore, txBuilder, nonceTracker, lggr, checkerFactory, nonceAutoSync, "")
// Mark instance as test
ethBroadcaster.XXXTestDisableUnstartedTxAutoProcessing()
@@ -101,6 +104,7 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) {
logger.Test(t),
&testCheckerFactory{},
false,
+ "",
)
// Can't close an unstarted instance
@@ -159,6 +163,7 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T)
logger.Test(t),
&testCheckerFactory{},
false,
+ "",
)
// Instance starts without error even if loading next sequence map fails
@@ -518,6 +523,25 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) {
assert.True(t, ethTx.Error.Valid)
assert.Equal(t, "transaction reverted during simulation: json-rpc error { Code = 42, Message = 'oh no, it reverted', Data = 'KqYi' }", ethTx.Error.String)
})
+
+ t.Run("terminally stuck transaction is marked as fatal", func(t *testing.T) {
+ terminallyStuckError := "failed to add tx to the pool: not enough step counters to continue the execution"
+ etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, []byte{42, 42, 0}, gasLimit, big.Int(assets.NewEthValue(243)), testutils.FixtureChainID)
+ ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool {
+ return tx.Nonce() == uint64(346) && tx.Value().Cmp(big.NewInt(243)) == 0
+ }), fromAddress).Return(commonclient.Fatal, errors.New(terminallyStuckError)).Once()
+
+ // Start processing unstarted transactions
+ retryable, err := eb.ProcessUnstartedTxs(tests.Context(t), fromAddress)
+ assert.NoError(t, err)
+ assert.False(t, retryable)
+
+ dbTx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
+ require.NoError(t, err)
+ assert.Equal(t, txmgrcommon.TxFatalError, dbTx.State)
+ assert.True(t, dbTx.Error.Valid)
+ assert.Equal(t, terminallyStuckError, dbTx.Error.String)
+ })
})
}
@@ -620,7 +644,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi
chStartEstimate := make(chan struct{})
chBlock := make(chan struct{})
- estimator.On("GetFee", mock.Anything, mock.Anything, mock.Anything, ccfg.EVM().GasEstimator().PriceMaxKey(fromAddress)).Return(gas.EvmFee{Legacy: assets.GWei(32)}, uint64(500), nil).Run(func(_ mock.Arguments) {
+ estimator.On("GetFee", mock.Anything, mock.Anything, mock.Anything, ccfg.EVM().GasEstimator().PriceMaxKey(fromAddress), mock.Anything).Return(gas.EvmFee{Legacy: assets.GWei(32)}, uint64(500), nil).Run(func(_ mock.Arguments) {
close(chStartEstimate)
<-chBlock
}).Once()
@@ -638,6 +662,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi
logger.Test(t),
&testCheckerFactory{},
false,
+ "",
)
eb.XXXTestDisableUnstartedTxAutoProcessing()
@@ -1154,10 +1179,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) {
t.Run("callback set by ctor", func(t *testing.T) {
estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator {
return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), nil, evmcfg.EVM().GasEstimator().BlockHistory(), lggr, nil)
- }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator())
+ }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator(), ethClient)
txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator)
localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress)
- eb2 := txmgr.NewEvmBroadcaster(txStore, txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, lggr, &testCheckerFactory{}, false)
+ eb2 := txmgr.NewEvmBroadcaster(txStore, txmClient, txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, lggr, &testCheckerFactory{}, false, "")
retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress)
assert.NoError(t, err)
assert.False(t, retryable)
@@ -1643,6 +1668,73 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) {
})
}
+func TestEthBroadcaster_ProcessUnstartedEthTxs_GasEstimationError(t *testing.T) {
+ toAddress := testutils.NewAddress()
+ value := big.Int(assets.NewEthValue(142))
+ gasLimit := uint64(242)
+ encodedPayload := []byte{0, 1}
+
+ db := pgtest.NewSqlxDB(t)
+ cfg := configtest.NewTestGeneralConfig(t)
+ cfg.EVMConfigs()[0].GasEstimator.EstimateGasLimit = ptr(true) // Enabled gas limit estimation
+ limitMultiplier := float32(1.25)
+ cfg.EVMConfigs()[0].GasEstimator.LimitMultiplier = ptr(decimal.NewFromFloat32(limitMultiplier)) // Set LimitMultiplier for the buffer
+ txStore := cltest.NewTestTxStore(t, db)
+
+ ethKeyStore := cltest.NewKeyStore(t, db).Eth()
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+
+ config := evmtest.NewChainScopedConfig(t, cfg)
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once()
+ lggr := logger.Test(t)
+ txmClient := txmgr.NewEvmTxmClient(ethClient, nil)
+ nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmClient)
+ ge := config.EVM().GasEstimator()
+ estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator {
+ return gas.NewFixedPriceEstimator(ge, nil, ge.BlockHistory(), lggr, nil)
+ }, ge.EIP1559DynamicFees(), ge, ethClient)
+ txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, estimator)
+ eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, nonceTracker, lggr, &testCheckerFactory{}, false, "")
+
+ // Mark instance as test
+ eb.XXXTestDisableUnstartedTxAutoProcessing()
+ servicetest.Run(t, eb)
+ ctx := tests.Context(t)
+ t.Run("gas limit lowered after estimation", func(t *testing.T) {
+ estimatedGasLimit := uint64(100)
+ etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID)
+ ethClient.On("EstimateGas", mock.Anything, mock.Anything).Return(estimatedGasLimit, nil).Once()
+ ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool {
+ return tx.Nonce() == uint64(0)
+ }), fromAddress).Return(commonclient.Successful, nil).Once()
+
+ // Do the thing
+ retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress)
+ assert.NoError(t, err)
+ assert.False(t, retryable)
+
+ dbEtx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
+ require.NoError(t, err)
+ attempt := dbEtx.TxAttempts[0]
+ require.Equal(t, uint64(float32(estimatedGasLimit)*gas.EstimateGasBuffer), attempt.ChainSpecificFeeLimit)
+ })
+ t.Run("provided gas limit too low, transaction marked as fatal error", func(t *testing.T) {
+ etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID)
+ ethClient.On("EstimateGas", mock.Anything, mock.Anything).Return(uint64(float32(gasLimit)*limitMultiplier)+1, nil).Once()
+
+ // Do the thing
+ retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress)
+ assert.NoError(t, err)
+ assert.False(t, retryable)
+
+ dbEtx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
+ require.NoError(t, err)
+ require.Equal(t, txmgrcommon.TxFatalError, dbEtx.State)
+ require.Equal(t, commmonfee.ErrFeeLimitTooLow.Error(), dbEtx.Error.String)
+ })
+}
+
func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) {
toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411")
value := big.Int(assets.NewEthValue(142))
@@ -1737,15 +1829,15 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) {
kst := cltest.NewKeyStore(t, db).Eth()
_, fromAddress := cltest.RandomKey{Disabled: false}.MustInsertWithState(t, kst)
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator {
return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), nil, evmcfg.EVM().GasEstimator().BlockHistory(), lggr, nil)
- }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator())
+ }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator(), ethClient)
checkerFactory := &testCheckerFactory{}
ge := evmcfg.EVM().GasEstimator()
t.Run("does nothing if nonce sync is disabled", func(t *testing.T) {
- ethClient := testutils.NewEthClientMockWithDefaultChain(t)
txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator)
kst := ksmocks.NewEth(t)
@@ -1753,7 +1845,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) {
kst.On("EnabledAddressesForChain", mock.Anything, testutils.FixtureChainID).Return(addresses, nil).Once()
ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once()
txmClient := txmgr.NewEvmTxmClient(ethClient, nil)
- eb := txmgr.NewEvmBroadcaster(txStore, txmClient, evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, lggr, checkerFactory, false)
+ 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)
@@ -1802,6 +1894,94 @@ func TestEthBroadcaster_NonceTracker_InProgressTx(t *testing.T) {
})
}
+func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) {
+ t.Parallel()
+
+ db := pgtest.NewSqlxDB(t)
+ cfg := configtest.NewTestGeneralConfig(t)
+ txStore := cltest.NewTestTxStore(t, db)
+ ethKeyStore := cltest.NewKeyStore(t, db).Eth()
+ evmcfg := evmtest.NewChainScopedConfig(t, cfg)
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ lggr, observed := logger.TestObserved(t, zapcore.DebugLevel)
+ ge := evmcfg.EVM().GasEstimator()
+ estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator {
+ return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), nil, ge.BlockHistory(), lggr, nil)
+ }, ge.EIP1559DynamicFees(), ge, ethClient)
+ txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, estimator)
+ checkerFactory := &txmgr.CheckerFactory{Client: ethClient}
+ ctx := tests.Context(t)
+
+ t.Run("transaction successfully broadcasted and increments on-chain nonce", func(t *testing.T) {
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ localNonce := uint64(0)
+ ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool {
+ return tx.Nonce() == localNonce
+ }), fromAddress).Return(commonclient.Successful, nil).Once()
+ ethClient.On("SequenceAt", mock.Anything, fromAddress, mock.Anything).Return(evmtypes.Nonce(1), nil).Once()
+
+ mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(localNonce), fromAddress)
+ nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil))
+ eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera))
+ // Mark instance as test
+ eb.XXXTestDisableUnstartedTxAutoProcessing()
+ servicetest.Run(t, eb)
+
+ retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress)
+ require.NoError(t, err)
+ require.False(t, retryable)
+ })
+
+ t.Run("transaction successfully broadcasted, failed to increment on-chain nonce, succeeded on bumped retry attempt", func(t *testing.T) {
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ localNonce := uint64(0)
+ ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool {
+ return tx.Nonce() == localNonce
+ }), fromAddress).Return(commonclient.Successful, nil).Twice()
+ ethClient.On("SequenceAt", mock.Anything, fromAddress, mock.Anything).Return(evmtypes.Nonce(0), nil).Once()
+ ethClient.On("SequenceAt", mock.Anything, fromAddress, mock.Anything).Return(evmtypes.Nonce(1), nil).Once()
+
+ mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(localNonce), fromAddress)
+ nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil))
+ eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera))
+ // Mark instance as test
+ eb.XXXTestDisableUnstartedTxAutoProcessing()
+ servicetest.Run(t, eb)
+
+ retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress)
+ tests.AssertLogEventually(t, observed, "Bumped fee on initial send")
+ require.NoError(t, err)
+ require.False(t, retryable)
+ })
+
+ t.Run("transaction successfully broadcasted, failed to increment on-chain nonce on every retry", func(t *testing.T) {
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ localNonce := uint64(0)
+ ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool {
+ return tx.Nonce() == localNonce
+ }), fromAddress).Return(commonclient.Successful, nil).Times(4)
+ ethClient.On("SequenceAt", mock.Anything, fromAddress, mock.Anything).Return(evmtypes.Nonce(0), nil).Times(4)
+
+ etx := mustInsertInProgressEthTxWithAttempt(t, txStore, evmtypes.Nonce(localNonce), fromAddress)
+ nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil))
+ eb := txmgrcommon.NewBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), ethKeyStore, txBuilder, nonceTracker, lggr, checkerFactory, false, string(chaintype.ChainHedera))
+ // Mark instance as test
+ eb.XXXTestDisableUnstartedTxAutoProcessing()
+ servicetest.Run(t, eb)
+
+ retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress)
+ tests.AssertLogEventually(t, observed, "Bumped fee on initial send")
+ require.NoError(t, err)
+ require.False(t, retryable)
+ tests.AssertLogEventually(t, observed, "failed to broadcast transaction on hedera after 3 retries")
+
+ etx, err = txStore.FindTxWithAttempts(ctx, etx.ID)
+ require.NoError(t, err)
+ require.Equal(t, txmgrcommon.TxFatalError, etx.State)
+ require.Error(t, etx.GetError(), "failed to broadcast transaction on hedera after 3 retries")
+ })
+}
+
type testCheckerFactory struct {
err error
}
diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go
index dcf15a4fa23..cbfb8775cfb 100644
--- a/core/chains/evm/txmgr/builder.go
+++ b/core/chains/evm/txmgr/builder.go
@@ -1,6 +1,7 @@
package txmgr
import (
+ "context"
"math/big"
"time"
@@ -10,6 +11,7 @@ import (
txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/config"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype"
"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"
@@ -17,6 +19,10 @@ import (
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
)
+type latestAndFinalizedBlockHeadTracker interface {
+ LatestAndFinalizedBlock(ctx context.Context) (latest, finalized *evmtypes.Head, err error)
+}
+
// NewTxm constructs the necessary dependencies for the EvmTxm (broadcaster, confirmer, etc) and returns a new EvmTxManager
func NewTxm(
ds sqlutil.DataSource,
@@ -31,6 +37,7 @@ func NewTxm(
logPoller logpoller.LogPoller,
keyStore keystore.Eth,
estimator gas.EvmFeeEstimator,
+ headTracker latestAndFinalizedBlockHeadTracker,
) (txm TxManager,
err error,
) {
@@ -49,15 +56,16 @@ func NewTxm(
feeCfg := NewEvmTxmFeeConfig(fCfg) // wrap Evm specific config
txmClient := NewEvmTxmClient(client, clientErrors) // wrap Evm specific client
chainID := txmClient.ConfiguredChainID()
- evmBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, txAttemptBuilder, lggr, checker, chainConfig.NonceAutoSync())
+ evmBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, txAttemptBuilder, lggr, checker, chainConfig.NonceAutoSync(), chainConfig.ChainType())
evmTracker := NewEvmTracker(txStore, keyStore, chainID, lggr)
stuckTxDetector := NewStuckTxDetector(lggr, client.ConfiguredChainID(), chainConfig.ChainType(), fCfg.PriceMax(), txConfig.AutoPurge(), estimator, txStore, client)
- evmConfirmer := NewEvmConfirmer(txStore, txmClient, txmCfg, feeCfg, txConfig, dbConfig, keyStore, txAttemptBuilder, lggr, stuckTxDetector)
+ evmConfirmer := NewEvmConfirmer(txStore, txmClient, txmCfg, feeCfg, txConfig, dbConfig, keyStore, txAttemptBuilder, lggr, stuckTxDetector, headTracker)
+ evmFinalizer := NewEvmFinalizer(lggr, client.ConfiguredChainID(), chainConfig.RPCDefaultBatchSize(), txStore, client, headTracker)
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, evmBroadcaster, evmConfirmer, evmResender, evmTracker)
+ txm = NewEvmTxm(chainID, txmCfg, txConfig, keyStore, lggr, checker, fwdMgr, txAttemptBuilder, txStore, evmBroadcaster, evmConfirmer, evmResender, evmTracker, evmFinalizer)
return txm, nil
}
@@ -76,8 +84,9 @@ func NewEvmTxm(
confirmer *Confirmer,
resender *Resender,
tracker *Tracker,
+ finalizer Finalizer,
) *Txm {
- return txmgr.NewTxm(chainId, cfg, txCfg, keyStore, lggr, checkerFactory, fwdMgr, txAttemptBuilder, txStore, broadcaster, confirmer, resender, tracker, client.NewTxError)
+ return txmgr.NewTxm(chainId, cfg, txCfg, keyStore, lggr, checkerFactory, fwdMgr, txAttemptBuilder, txStore, broadcaster, confirmer, resender, tracker, finalizer, client.NewTxError)
}
// NewEvmResender creates a new concrete EvmResender
@@ -95,8 +104,8 @@ func NewEvmResender(
}
// NewEvmReaper instantiates a new EVM-specific reaper object
-func NewEvmReaper(lggr logger.Logger, store txmgrtypes.TxHistoryReaper[*big.Int], config EvmReaperConfig, txConfig txmgrtypes.ReaperTransactionsConfig, chainID *big.Int) *Reaper {
- return txmgr.NewReaper(lggr, store, config, txConfig, chainID)
+func NewEvmReaper(lggr logger.Logger, store txmgrtypes.TxHistoryReaper[*big.Int], txConfig txmgrtypes.ReaperTransactionsConfig, chainID *big.Int) *Reaper {
+ return txmgr.NewReaper(lggr, store, txConfig, chainID)
}
// NewEvmConfirmer instantiates a new EVM confirmer
@@ -111,8 +120,9 @@ func NewEvmConfirmer(
txAttemptBuilder TxAttemptBuilder,
lggr logger.Logger,
stuckTxDetector StuckTxDetector,
+ headTracker latestAndFinalizedBlockHeadTracker,
) *Confirmer {
- return txmgr.NewConfirmer(txStore, client, chainConfig, feeConfig, txConfig, dbConfig, keystore, txAttemptBuilder, lggr, func(r *evmtypes.Receipt) bool { return r == nil }, stuckTxDetector)
+ return txmgr.NewConfirmer(txStore, client, chainConfig, feeConfig, txConfig, dbConfig, keystore, txAttemptBuilder, lggr, func(r *evmtypes.Receipt) bool { return r == nil }, stuckTxDetector, headTracker)
}
// NewEvmTracker instantiates a new EVM tracker for abandoned transactions
@@ -138,7 +148,8 @@ func NewEvmBroadcaster(
logger logger.Logger,
checkerFactory TransmitCheckerFactory,
autoSyncNonce bool,
+ chainType chaintype.ChainType,
) *Broadcaster {
nonceTracker := NewNonceTracker(logger, txStore, client)
- return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, txAttemptBuilder, nonceTracker, logger, checkerFactory, autoSyncNonce)
+ return txmgr.NewBroadcaster(txStore, client, chainConfig, feeConfig, txConfig, listenerConfig, keystore, txAttemptBuilder, nonceTracker, logger, checkerFactory, autoSyncNonce, string(chainType))
}
diff --git a/core/chains/evm/txmgr/client.go b/core/chains/evm/txmgr/client.go
index 661a180af50..e995080a260 100644
--- a/core/chains/evm/txmgr/client.go
+++ b/core/chains/evm/txmgr/client.go
@@ -183,3 +183,7 @@ func (c *evmTxmClient) CallContract(ctx context.Context, a TxAttempt, blockNumbe
}, blockNumber)
return client.ExtractRPCError(errCall)
}
+
+func (c *evmTxmClient) HeadByHash(ctx context.Context, hash common.Hash) (*evmtypes.Head, error) {
+ return c.client.HeadByHash(ctx, hash)
+}
diff --git a/core/chains/evm/txmgr/config.go b/core/chains/evm/txmgr/config.go
index b53f99840b9..af20c9a5901 100644
--- a/core/chains/evm/txmgr/config.go
+++ b/core/chains/evm/txmgr/config.go
@@ -48,7 +48,6 @@ type (
EvmBroadcasterConfig txmgrtypes.BroadcasterChainConfig
EvmConfirmerConfig txmgrtypes.ConfirmerChainConfig
EvmResenderConfig txmgrtypes.ResenderChainConfig
- EvmReaperConfig txmgrtypes.ReaperChainConfig
)
var _ EvmTxmConfig = (*evmTxmConfig)(nil)
diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go
index 6b107b222a6..24330172b93 100644
--- a/core/chains/evm/txmgr/confirmer_test.go
+++ b/core/chains/evm/txmgr/confirmer_test.go
@@ -34,6 +34,7 @@ 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/headtracker"
"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/testutils"
@@ -128,10 +129,11 @@ func TestEthConfirmer_Lifecycle(t *testing.T) {
newEst := func(logger.Logger) gas.EvmEstimator { return estimator }
lggr := logger.Test(t)
ge := config.EVM().GasEstimator()
- feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge)
+ feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge, ethClient)
txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator)
stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), config.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient)
- ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), gconfig.Database(), ethKeyStore, txBuilder, lggr, stuckTxDetector)
+ ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0)
+ ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), gconfig.Database(), ethKeyStore, txBuilder, lggr, stuckTxDetector, ht)
ctx := tests.Context(t)
// Can't close unstarted instance
@@ -145,19 +147,27 @@ func TestEthConfirmer_Lifecycle(t *testing.T) {
// Can't start an already started instance
err = ec.Start(ctx)
require.Error(t, err)
+
+ latestFinalizedHead := evmtypes.Head{
+ Number: 8,
+ Hash: testutils.NewHash(),
+ Parent: nil,
+ IsFinalized: true, // We are guaranteed to receive a latestFinalizedHead.
+ }
+
head := evmtypes.Head{
Hash: testutils.NewHash(),
Number: 10,
Parent: &evmtypes.Head{
Hash: testutils.NewHash(),
Number: 9,
- Parent: &evmtypes.Head{
- Number: 8,
- Hash: testutils.NewHash(),
- Parent: nil,
- },
+ Parent: &latestFinalizedHead,
},
}
+
+ ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(&head, nil).Once()
+ ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&latestFinalizedHead, nil).Once()
+
err = ec.ProcessHead(ctx, &head)
require.NoError(t, err)
// Can successfully close once
@@ -199,6 +209,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
nonce := int64(0)
ctx := tests.Context(t)
blockNum := int64(0)
+ latestFinalizedBlockNum := int64(0)
t.Run("only finds eth_txes in unconfirmed state with at least one broadcast attempt", func(t *testing.T) {
mustInsertFatalErrorEthTx(t, txStore, fromAddress)
@@ -211,7 +222,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID())
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
})
etx1 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress)
@@ -232,7 +243,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
var err error
etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID)
@@ -261,7 +272,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// No error because it is merely logged
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
etx, err := txStore.FindTxWithAttempts(ctx, etx1.ID)
require.NoError(t, err)
@@ -289,7 +300,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// No error because it is merely logged
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
etx, err := txStore.FindTxWithAttempts(ctx, etx1.ID)
require.NoError(t, err)
@@ -326,7 +337,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
// Check that the receipt was saved
etx, err := txStore.FindTxWithAttempts(ctx, etx1.ID)
@@ -388,7 +399,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
// Check that the state was updated
etx, err := txStore.FindTxWithAttempts(ctx, etx2.ID)
@@ -416,7 +427,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
// No receipt, but no error either
etx, err := txStore.FindTxWithAttempts(ctx, etx3.ID)
@@ -443,7 +454,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
// No receipt, but no error either
etx, err := txStore.FindTxWithAttempts(ctx, etx3.ID)
@@ -472,7 +483,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
// Check that the receipt was unchanged
etx, err := txStore.FindTxWithAttempts(ctx, etx3.ID)
@@ -523,7 +534,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
// Check that the state was updated
var err error
@@ -576,7 +587,7 @@ func TestEthConfirmer_CheckForReceipts(t *testing.T) {
}).Once()
// Do the thing
- require.NoError(t, ec.CheckForReceipts(ctx, blockNum))
+ require.NoError(t, ec.CheckForReceipts(ctx, blockNum, latestFinalizedBlockNum))
// Check that the state was updated
etx5, err = txStore.FindTxWithAttempts(ctx, etx5.ID)
@@ -614,6 +625,7 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) {
etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress)
var attempts []txmgr.TxAttempt
+ latestFinalizedBlockNum := int64(0)
// Total of 5 attempts should lead to 3 batched fetches (2, 2, 1)
for i := 0; i < 5; i++ {
@@ -650,7 +662,7 @@ func TestEthConfirmer_CheckForReceipts_batching(t *testing.T) {
elems[0].Result = &evmtypes.Receipt{}
}).Once()
- require.NoError(t, ec.CheckForReceipts(ctx, 42))
+ require.NoError(t, ec.CheckForReceipts(ctx, 42, latestFinalizedBlockNum))
}
func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t *testing.T) {
@@ -671,6 +683,8 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t *
_, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore)
ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil)
ctx := tests.Context(t)
+ latestFinalizedBlockNum := int64(0)
+
// tx is not forwarded and doesn't have meta set. EthConfirmer should handle nil meta values
etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 0, fromAddress)
attempt := newBroadcastLegacyEthTxAttempt(t, etx.ID, 2)
@@ -697,7 +711,7 @@ func TestEthConfirmer_CheckForReceipts_HandlesNonFwdTxsWithForwardingEnabled(t *
*(elems[0].Result.(*evmtypes.Receipt)) = txmReceipt // confirmed
}).Once()
- require.NoError(t, ec.CheckForReceipts(ctx, 42))
+ require.NoError(t, ec.CheckForReceipts(ctx, 42, latestFinalizedBlockNum))
// Check receipt is inserted correctly.
dbtx, err = txStore.FindTxWithAttempts(ctx, etx.ID)
@@ -724,6 +738,7 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) {
ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil)
ctx := tests.Context(t)
+ latestFinalizedBlockNum := int64(0)
var attempts []txmgr.TxAttempt
// inserting in DESC nonce order to test DB ASC ordering
@@ -755,7 +770,7 @@ func TestEthConfirmer_CheckForReceipts_only_likely_confirmed(t *testing.T) {
elems[3].Result = &evmtypes.Receipt{}
}).Once()
- require.NoError(t, ec.CheckForReceipts(ctx, 42))
+ require.NoError(t, ec.CheckForReceipts(ctx, 42, latestFinalizedBlockNum))
cltest.BatchElemMustMatchParams(t, captured[0], attempts[0].Hash, "eth_getTransactionReceipt")
cltest.BatchElemMustMatchParams(t, captured[1], attempts[1].Hash, "eth_getTransactionReceipt")
@@ -778,6 +793,7 @@ func TestEthConfirmer_CheckForReceipts_should_not_check_for_likely_unconfirmed(t
ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil)
ctx := tests.Context(t)
+ latestFinalizedBlockNum := int64(0)
etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, 1, fromAddress)
for i := 0; i < 4; i++ {
@@ -788,7 +804,7 @@ func TestEthConfirmer_CheckForReceipts_should_not_check_for_likely_unconfirmed(t
// latest nonce is lower that all attempts' nonces
ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(0), nil)
- require.NoError(t, ec.CheckForReceipts(ctx, 42))
+ require.NoError(t, ec.CheckForReceipts(ctx, 42, latestFinalizedBlockNum))
}
func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t *testing.T) {
@@ -809,6 +825,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t
ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil)
ctx := tests.Context(t)
+ latestFinalizedBlockNum := int64(0)
// STATE
// key 1, tx with nonce 0 is unconfirmed
@@ -832,7 +849,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t
*(elems[0].Result.(*evmtypes.Receipt)) = txmReceipt2_9
}).Once()
- require.NoError(t, ec.CheckForReceipts(ctx, 10))
+ require.NoError(t, ec.CheckForReceipts(ctx, 10, latestFinalizedBlockNum))
mustTxBeInState(t, txStore, etx1_0, txmgrcommon.TxUnconfirmed)
mustTxBeInState(t, txStore, etx1_1, txmgrcommon.TxUnconfirmed)
@@ -850,7 +867,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt_scoped_to_key(t
*(elems[0].Result.(*evmtypes.Receipt)) = txmReceipt1_1
}).Once()
- require.NoError(t, ec.CheckForReceipts(ctx, 11))
+ require.NoError(t, ec.CheckForReceipts(ctx, 11, latestFinalizedBlockNum))
mustTxBeInState(t, txStore, etx1_0, txmgrcommon.TxConfirmedMissingReceipt)
mustTxBeInState(t, txStore, etx1_1, txmgrcommon.TxConfirmed)
@@ -861,9 +878,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) {
t.Parallel()
db := pgtest.NewSqlxDB(t)
- cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {
- c.EVM[0].FinalityDepth = ptr[uint32](50)
- })
+ cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {})
txStore := cltest.NewTestTxStore(t, db)
ethKeyStore := cltest.NewKeyStore(t, db).Eth()
@@ -876,6 +891,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) {
ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil)
ctx := tests.Context(t)
+ latestFinalizedBlockNum := int64(0)
// STATE
// eth_txes with nonce 0 has two attempts (broadcast before block 21 and 41) the first of which will get a receipt
@@ -949,7 +965,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) {
// PERFORM
// Block num of 43 is one higher than the receipt (as would generally be expected)
- require.NoError(t, ec.CheckForReceipts(ctx, 43))
+ require.NoError(t, ec.CheckForReceipts(ctx, 43, latestFinalizedBlockNum))
// 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
@@ -1009,7 +1025,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) {
// PERFORM
// Block num of 44 is one higher than the receipt (as would generally be expected)
- require.NoError(t, ec.CheckForReceipts(ctx, 44))
+ require.NoError(t, ec.CheckForReceipts(ctx, 44, latestFinalizedBlockNum))
// 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
@@ -1038,7 +1054,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) {
// eth_txes with nonce 2 is confirmed
// eth_txes with nonce 3 is confirmed
- t.Run("continues to leave eth_txes with state 'confirmed_missing_receipt' unchanged if at least one attempt is above EVM.FinalityDepth", func(t *testing.T) {
+ t.Run("continues to leave eth_txes with state 'confirmed_missing_receipt' unchanged if at least one attempt is above LatestFinalizedBlockNum", func(t *testing.T) {
ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(10), nil)
ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool {
return len(b) == 2 &&
@@ -1051,9 +1067,11 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) {
elems[1].Result = &evmtypes.Receipt{}
}).Once()
+ latestFinalizedBlockNum = 30
+
// PERFORM
// Block num of 80 puts the first attempt (21) below threshold but second attempt (41) still above
- require.NoError(t, ec.CheckForReceipts(ctx, 80))
+ require.NoError(t, ec.CheckForReceipts(ctx, 80, latestFinalizedBlockNum))
// 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
@@ -1078,7 +1096,7 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) {
// eth_txes with nonce 2 is confirmed
// eth_txes with nonce 3 is confirmed
- t.Run("marks eth_Txes with state 'confirmed_missing_receipt' as 'errored' if a receipt fails to show up and all attempts are buried deeper than EVM.FinalityDepth", func(t *testing.T) {
+ t.Run("marks eth_Txes with state 'confirmed_missing_receipt' as 'errored' if a receipt fails to show up and all attempts are buried deeper than LatestFinalizedBlockNum", func(t *testing.T) {
ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(10), nil)
ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool {
return len(b) == 2 &&
@@ -1091,9 +1109,11 @@ func TestEthConfirmer_CheckForReceipts_confirmed_missing_receipt(t *testing.T) {
elems[1].Result = &evmtypes.Receipt{}
}).Once()
+ latestFinalizedBlockNum = 50
+
// PERFORM
// Block num of 100 puts the first attempt (21) and second attempt (41) below threshold
- require.NoError(t, ec.CheckForReceipts(ctx, 100))
+ require.NoError(t, ec.CheckForReceipts(ctx, 100, latestFinalizedBlockNum))
// 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
@@ -1117,9 +1137,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt(t *testing.T) {
t.Parallel()
db := pgtest.NewSqlxDB(t)
- cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {
- c.EVM[0].FinalityDepth = ptr[uint32](50)
- })
+ cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {})
txStore := cltest.NewTestTxStore(t, db)
ethKeyStore := cltest.NewKeyStore(t, db).Eth()
@@ -1197,9 +1215,7 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_batchSendTransactions_fails(t
t.Parallel()
db := pgtest.NewSqlxDB(t)
- cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {
- c.EVM[0].FinalityDepth = ptr[uint32](50)
- })
+ cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {})
txStore := cltest.NewTestTxStore(t, db)
ethKeyStore := cltest.NewKeyStore(t, db).Eth()
@@ -1262,7 +1278,6 @@ func TestEthConfirmer_CheckConfirmedMissingReceipt_smallEvmRPCBatchSize_middleBa
db := pgtest.NewSqlxDB(t)
cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) {
- c.EVM[0].FinalityDepth = ptr[uint32](50)
c.EVM[0].RPCDefaultBatchSize = ptr[uint32](1)
})
txStore := cltest.NewTestTxStore(t, db)
@@ -1646,13 +1661,14 @@ 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.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge)
+ feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge, ethClient)
txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator)
addresses := []gethCommon.Address{fromAddress}
kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe()
stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), ccfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient)
+ ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0)
// Create confirmer with necessary state
- ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr, stuckTxDetector)
+ ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr, stuckTxDetector, ht)
servicetest.Run(t, ec)
currentHead := int64(30)
oldEnough := int64(15)
@@ -1695,12 +1711,13 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing
newEst := func(logger.Logger) gas.EvmEstimator { return estimator }
// Create confirmer with necessary state
ge := ccfg.EVM().GasEstimator()
- feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge)
+ feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge, ethClient)
txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator)
addresses := []gethCommon.Address{fromAddress}
kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe()
stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), ccfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient)
- ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr, stuckTxDetector)
+ ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0)
+ ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr, stuckTxDetector, ht)
servicetest.Run(t, ec)
currentHead := int64(30)
oldEnough := int64(15)
@@ -2656,6 +2673,58 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) {
})
}
+func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyStuckError(t *testing.T) {
+ t.Parallel()
+
+ db := pgtest.NewSqlxDB(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)
+ ctx := tests.Context(t)
+
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ ethKeyStore := cltest.NewKeyStore(t, db).Eth()
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+
+ evmcfg := evmtest.NewChainScopedConfig(t, cfg)
+
+ // Use a mock keystore for this test
+ ec := newEthConfirmer(t, txStore, ethClient, cfg, evmcfg, ethKeyStore, nil)
+ currentHead := int64(30)
+ oldEnough := int64(19)
+ nonce := int64(0)
+ terminallyStuckError := "failed to add tx to the pool: not enough step counters to continue the execution"
+
+ t.Run("terminally stuck transaction replaced with purge attempt", func(t *testing.T) {
+ originalBroadcastAt := time.Unix(1616509100, 0)
+ etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, nonce, fromAddress, originalBroadcastAt)
+ nonce++
+ attempt1_1 := etx.TxAttempts[0]
+ var dbAttempt txmgr.DbEthTxAttempt
+ require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_1.ID))
+
+ // Return terminally stuck error on first rebroadcast
+ ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool {
+ return tx.Nonce() == uint64(*etx.Sequence)
+ }), fromAddress).Return(commonclient.TerminallyStuck, errors.New(terminallyStuckError)).Once()
+ // Return successful for purge attempt
+ ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool {
+ return tx.Nonce() == uint64(*etx.Sequence)
+ }), fromAddress).Return(commonclient.Successful, nil).Once()
+
+ // Start processing transactions for rebroadcast
+ require.NoError(t, ec.RebroadcastWhereNecessary(tests.Context(t), currentHead))
+ var err error
+ etx, err = txStore.FindTxWithAttempts(ctx, etx.ID)
+ require.NoError(t, err)
+
+ require.Len(t, etx.TxAttempts, 2)
+ purgeAttempt := etx.TxAttempts[0]
+ require.True(t, purgeAttempt.IsPurgeAttempt)
+ })
+}
+
func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
t.Parallel()
@@ -2672,6 +2741,13 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
gconfig, config := newTestChainScopedConfig(t)
ec := newEthConfirmer(t, txStore, ethClient, gconfig, config, ethKeyStore, nil)
+ latestFinalizedHead := evmtypes.Head{
+ Number: 8,
+ Hash: testutils.NewHash(),
+ Parent: nil,
+ IsFinalized: false, // We are guaranteed to receive a latestFinalizedHead.
+ }
+
head := evmtypes.Head{
Hash: testutils.NewHash(),
Number: 10,
@@ -2685,16 +2761,15 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
},
},
}
-
t.Run("does nothing if there aren't any transactions", func(t *testing.T) {
- require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head))
+ require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head, latestFinalizedHead.BlockNumber()))
})
t.Run("does nothing to unconfirmed transactions", func(t *testing.T) {
etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress)
// Do the thing
- require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head))
+ require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head, latestFinalizedHead.BlockNumber()))
etx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
require.NoError(t, err)
@@ -2706,7 +2781,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
mustInsertEthReceipt(t, txStore, head.Number, head.Hash, etx.TxAttempts[0].Hash)
// Do the thing
- require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head))
+ require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head, latestFinalizedHead.BlockNumber()))
etx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
require.NoError(t, err)
@@ -2719,7 +2794,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
mustInsertEthReceipt(t, txStore, head.Parent.Parent.Number-1, testutils.NewHash(), etx.TxAttempts[0].Hash)
// Do the thing
- require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head))
+ require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head, latestFinalizedHead.BlockNumber()))
etx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
require.NoError(t, err)
@@ -2740,7 +2815,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
}), fromAddress).Return(commonclient.Successful, nil).Once()
// Do the thing
- require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head))
+ require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head, latestFinalizedHead.BlockNumber()))
etx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
require.NoError(t, err)
@@ -2763,7 +2838,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
commonclient.Successful, nil).Once()
// Do the thing
- require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head))
+ require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head, latestFinalizedHead.BlockNumber()))
etx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
require.NoError(t, err)
@@ -2798,7 +2873,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
}), fromAddress).Return(commonclient.Successful, nil).Once()
// Do the thing
- require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head))
+ require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head, latestFinalizedHead.BlockNumber()))
etx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
require.NoError(t, err)
@@ -2818,7 +2893,7 @@ func TestEthConfirmer_EnsureConfirmedTransactionsInLongestChain(t *testing.T) {
// Add receipt that is higher than head
mustInsertEthReceipt(t, txStore, head.Number+1, testutils.NewHash(), attempt.Hash)
- require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head))
+ require.NoError(t, ec.EnsureConfirmedTransactionsInLongestChain(tests.Context(t), &head, latestFinalizedHead.BlockNumber()))
etx, err := txStore.FindTxWithAttempts(ctx, etx.ID)
require.NoError(t, err)
@@ -3143,7 +3218,7 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) {
fee := gas.EvmFee{Legacy: marketGasPrice}
bumpedLegacy := assets.GWei(30)
bumpedFee := gas.EvmFee{Legacy: bumpedLegacy}
- feeEstimator.On("GetFee", mock.Anything, []byte{}, uint64(0), mock.Anything).Return(fee, uint64(0), nil)
+ feeEstimator.On("GetFee", mock.Anything, []byte{}, uint64(0), mock.Anything, mock.Anything).Return(fee, uint64(0), nil)
feeEstimator.On("BumpFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(bumpedFee, uint64(10_000), nil)
autoPurgeThreshold := uint32(5)
autoPurgeMinAttempts := uint32(3)
@@ -3158,7 +3233,8 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) {
ge := evmcfg.EVM().GasEstimator()
txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator)
stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), evmcfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient)
- ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database(), ethKeyStore, txBuilder, lggr, stuckTxDetector)
+ ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0)
+ ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database(), ethKeyStore, txBuilder, lggr, stuckTxDetector, ht)
servicetest.Run(t, ec)
ctx := tests.Context(t)
@@ -3172,9 +3248,13 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) {
tx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, nonce, fromAddress, autoPurgeMinAttempts, blockNum-int64(autoPurgeThreshold), marketGasPrice.Add(oneGwei))
head := evmtypes.Head{
- Hash: testutils.NewHash(),
- Number: blockNum,
+ Hash: testutils.NewHash(),
+ Number: blockNum,
+ IsFinalized: true,
}
+
+ ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(&head, nil).Once()
+ ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&head, nil).Once()
ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(0), nil).Once()
ethClient.On("BatchCallContext", mock.Anything, mock.Anything).Return(nil).Once()
@@ -3196,9 +3276,12 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) {
require.Equal(t, bumpedFee.Legacy, latestAttempt.TxFee.Legacy)
head = evmtypes.Head{
- Hash: testutils.NewHash(),
- Number: blockNum + 1,
+ Hash: testutils.NewHash(),
+ Number: blockNum + 1,
+ IsFinalized: true,
}
+ ethClient.On("HeadByNumber", mock.Anything, (*big.Int)(nil)).Return(&head, nil).Once()
+ ethClient.On("LatestFinalizedBlock", mock.Anything).Return(&head, nil).Once()
ethClient.On("SequenceAt", mock.Anything, mock.Anything, mock.Anything).Return(evmtypes.Nonce(1), nil)
ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool {
return len(b) == 4 && cltest.BatchElemMatchesParams(b[0], latestAttempt.Hash, "eth_getTransactionReceipt")
@@ -3234,10 +3317,11 @@ func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Cl
ge := config.EVM().GasEstimator()
estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator {
return gas.NewFixedPriceEstimator(ge, nil, ge.BlockHistory(), lggr, nil)
- }, ge.EIP1559DynamicFees(), ge)
+ }, ge.EIP1559DynamicFees(), ge, ethClient)
txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator)
stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), config.EVM().Transactions().AutoPurge(), estimator, txStore, ethClient)
- ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), gconfig.Database(), ks, txBuilder, lggr, stuckTxDetector)
+ ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0)
+ ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), gconfig.Database(), ks, txBuilder, lggr, stuckTxDetector, ht)
ec.SetResumeCallback(fn)
servicetest.Run(t, ec)
return ec
diff --git a/core/chains/evm/txmgr/evm_tx_store.go b/core/chains/evm/txmgr/evm_tx_store.go
index e83a83907e4..fa2251168d9 100644
--- a/core/chains/evm/txmgr/evm_tx_store.go
+++ b/core/chains/evm/txmgr/evm_tx_store.go
@@ -34,8 +34,8 @@ import (
var (
ErrKeyNotUpdated = errors.New("evmTxStore: Key not updated")
- // 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 is the error string we save if we reach our LatestFinalizedBlockNum 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"
)
@@ -44,6 +44,10 @@ type EvmTxStore interface {
// redeclare TxStore for mockery
txmgrtypes.TxStore[common.Address, *big.Int, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee]
TxStoreWebApi
+
+ // methods used solely in EVM components
+ FindConfirmedTxesReceipts(ctx context.Context, finalizedBlockNum int64, chainID *big.Int) (receipts []Receipt, err error)
+ UpdateTxStatesToFinalizedUsingReceiptIds(ctx context.Context, etxIDs []int64, chainId *big.Int) error
}
// TxStoreWebApi encapsulates the methods that are not used by the txmgr and only used by the various web controllers, readers, or evm specific components
@@ -87,7 +91,7 @@ var _ TestEvmTxStore = (*evmTxStore)(nil)
// Directly maps to columns of database table "evm.receipts".
// Do not modify type unless you
// intend to modify the database schema
-type dbReceipt struct {
+type DbReceipt struct {
ID int64
TxHash common.Hash
BlockHash common.Hash
@@ -97,8 +101,8 @@ type dbReceipt struct {
CreatedAt time.Time
}
-func DbReceiptFromEvmReceipt(evmReceipt *evmtypes.Receipt) dbReceipt {
- return dbReceipt{
+func DbReceiptFromEvmReceipt(evmReceipt *evmtypes.Receipt) DbReceipt {
+ return DbReceipt{
TxHash: evmReceipt.TxHash,
BlockHash: evmReceipt.BlockHash,
BlockNumber: evmReceipt.BlockNumber.Int64(),
@@ -107,7 +111,7 @@ func DbReceiptFromEvmReceipt(evmReceipt *evmtypes.Receipt) dbReceipt {
}
}
-func DbReceiptToEvmReceipt(receipt *dbReceipt) *evmtypes.Receipt {
+func DbReceiptToEvmReceipt(receipt *DbReceipt) *evmtypes.Receipt {
return &receipt.Receipt
}
@@ -131,7 +135,7 @@ type dbReceiptPlus struct {
FailOnRevert bool `db:"FailOnRevert"`
}
-func fromDBReceipts(rs []dbReceipt) []*evmtypes.Receipt {
+func fromDBReceipts(rs []DbReceipt) []*evmtypes.Receipt {
receipts := make([]*evmtypes.Receipt, len(rs))
for i := 0; i < len(rs); i++ {
receipts[i] = DbReceiptToEvmReceipt(&rs[i])
@@ -665,10 +669,8 @@ func (o *evmTxStore) loadEthTxAttemptsReceipts(ctx context.Context, etx *Tx) (er
return o.loadEthTxesAttemptsReceipts(ctx, []*Tx{etx})
}
-func (o *evmTxStore) loadEthTxesAttemptsReceipts(ctx context.Context, etxs []*Tx) (err error) {
- if len(etxs) == 0 {
- return nil
- }
+// initEthTxesAttempts takes an input txes slice, return an initialized attempt map and attemptHashes slice
+func initEthTxesAttempts(etxs []*Tx) (map[common.Hash]*TxAttempt, [][]byte) {
attemptHashM := make(map[common.Hash]*TxAttempt, len(etxs)) // len here is lower bound
attemptHashes := make([][]byte, len(etxs)) // len here is lower bound
for _, etx := range etxs {
@@ -677,7 +679,17 @@ func (o *evmTxStore) loadEthTxesAttemptsReceipts(ctx context.Context, etxs []*Tx
attemptHashes = append(attemptHashes, attempt.Hash.Bytes())
}
}
- var rs []dbReceipt
+
+ return attemptHashM, attemptHashes
+}
+
+func (o *evmTxStore) loadEthTxesAttemptsReceipts(ctx context.Context, etxs []*Tx) (err error) {
+ if len(etxs) == 0 {
+ return nil
+ }
+
+ attemptHashM, attemptHashes := initEthTxesAttempts(etxs)
+ var rs []DbReceipt
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")
}
@@ -693,6 +705,37 @@ func (o *evmTxStore) loadEthTxesAttemptsReceipts(ctx context.Context, etxs []*Tx
return nil
}
+// loadEthTxesAttemptsWithPartialReceipts loads ethTxes with attempts and partial receipts values for optimization
+func (o *evmTxStore) loadEthTxesAttemptsWithPartialReceipts(ctx context.Context, etxs []*Tx) (err error) {
+ if len(etxs) == 0 {
+ return nil
+ }
+
+ attemptHashM, attemptHashes := initEthTxesAttempts(etxs)
+ var rs []DbReceipt
+ if err = o.q.SelectContext(ctx, &rs, `SELECT evm.receipts.block_hash, evm.receipts.block_number, evm.receipts.transaction_index, evm.receipts.tx_hash FROM evm.receipts WHERE tx_hash = ANY($1)`, pq.Array(attemptHashes)); err != nil {
+ return pkgerrors.Wrap(err, "loadEthTxesAttemptsReceipts failed to load evm.receipts")
+ }
+
+ receipts := make([]*evmtypes.Receipt, len(rs))
+ for i := 0; i < len(rs); i++ {
+ receipts[i] = &evmtypes.Receipt{
+ BlockHash: rs[i].BlockHash,
+ BlockNumber: big.NewInt(rs[i].BlockNumber),
+ TransactionIndex: rs[i].TransactionIndex,
+ TxHash: rs[i].TxHash,
+ }
+ }
+
+ for _, receipt := range receipts {
+ attempt := attemptHashM[receipt.TxHash]
+ // Although the attempts struct supports multiple receipts, the expectation for EVM is that there is only one receipt
+ // per tx and therefore attempt too.
+ attempt.Receipts = append(attempt.Receipts, receipt)
+ }
+ return nil
+}
+
func loadConfirmedAttemptsReceipts(ctx context.Context, q sqlutil.DataSource, attempts []TxAttempt) error {
byHash := make(map[string]*TxAttempt, len(attempts))
hashes := make([][]byte, len(attempts))
@@ -700,7 +743,7 @@ func loadConfirmedAttemptsReceipts(ctx context.Context, q sqlutil.DataSource, at
byHash[attempt.Hash.String()] = &attempts[i]
hashes = append(hashes, attempt.Hash.Bytes())
}
- var rs []dbReceipt
+ var rs []DbReceipt
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")
}
@@ -955,11 +998,11 @@ func (o *evmTxStore) SaveFetchedReceipts(ctx context.Context, r []*evmtypes.Rece
// NOTE: We continue to attempt to resend evm.txes in this state on
// every head to guard against the extremely rare scenario of nonce gap due to
// reorg that excludes the transaction (from another wallet) that had this
-// nonce (until finality depth is reached, after which we make the explicit
+// nonce (until LatestFinalizedBlockNum is reached, after which we make the explicit
// decision to give up). This is done in the EthResender.
//
// We will continue to try to fetch a receipt for these attempts until all
-// attempts are below the finality depth from current head.
+// attempts are equal to or below the LatestFinalizedBlockNum from current head.
func (o *evmTxStore) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) (err error) {
var cancel context.CancelFunc
ctx, cancel = o.stopCh.Ctx(ctx)
@@ -1116,7 +1159,7 @@ func updateEthTxAttemptUnbroadcast(ctx context.Context, orm *evmTxStore, attempt
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")
+ return errors.New("expected tx state to be confirmed")
}
_, err := orm.q.ExecContext(ctx, `UPDATE evm.txes SET state = 'unconfirmed' WHERE id = $1`, etx.ID)
return pkgerrors.Wrap(err, "updateEthTxUnconfirm failed")
@@ -1168,7 +1211,9 @@ ORDER BY nonce ASC
if err = orm.LoadTxesAttempts(ctx, etxs); err != nil {
return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load evm.tx_attempts")
}
- err = orm.loadEthTxesAttemptsReceipts(ctx, etxs)
+
+ // retrieve tx with attempts and partial receipt values for optimization purpose
+ err = orm.loadEthTxesAttemptsWithPartialReceipts(ctx, etxs)
return pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed to load evm.receipts")
})
return etxs, pkgerrors.Wrap(err, "FindTransactionsConfirmedInBlockRange failed")
@@ -1205,24 +1250,6 @@ AND evm_chain_id = $1`, chainID.String()).Scan(&earliestUnconfirmedTxBlock)
return earliestUnconfirmedTxBlock, err
}
-func (o *evmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID *big.Int) (finalized bool, err error) {
- var cancel context.CancelFunc
- ctx, cancel = o.stopCh.Ctx(ctx)
- defer cancel()
-
- var count int32
- 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
- WHERE evm.receipts.block_number <= ($1 - evm.txes.min_confirmations)
- AND evm.txes.id = $2 AND evm.txes.evm_chain_id = $3`, blockHeight, txID, chainID.String())
- if err != nil {
- return false, fmt.Errorf("failed to retrieve transaction reciepts: %w", err)
- }
- return count > 0, nil
-}
-
func (o *evmTxStore) saveAttemptWithNewState(ctx context.Context, attempt TxAttempt, broadcastAt time.Time) error {
var dbAttempt DbEthTxAttempt
dbAttempt.FromTxAttempt(&attempt)
@@ -1444,23 +1471,18 @@ ORDER BY nonce ASC
// markOldTxesMissingReceiptAsErrored
//
-// Once eth_tx has all of its attempts broadcast before some cutoff threshold
+// Once eth_tx has all of its attempts broadcast equal to or before latestFinalizedBlockNum
// without receiving any receipts, we mark it as fatally errored (never sent).
//
// The job run will also be marked as errored in this case since we never got a
// receipt and thus cannot pass on any transaction hash
-func (o *evmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID *big.Int) error {
+func (o *evmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, latestFinalizedBlockNum int64, chainID *big.Int) error {
var cancel context.CancelFunc
ctx, cancel = o.stopCh.Ctx(ctx)
defer cancel()
- // 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
- cutoff := blockNum - int64(finalityDepth)
- if cutoff <= 0 {
- return nil
- }
- if cutoff <= 0 {
+ // Any 'confirmed_missing_receipt' eth_tx with all attempts equal to or older than latestFinalizedBlockNum will be marked as errored
+ // We will not try to query for receipts for this transaction anymore
+ if latestFinalizedBlockNum <= 0 {
return nil
}
// note: if QOpt passes in a sql.Tx this will reuse it
@@ -1480,12 +1502,12 @@ FROM (
WHERE e2.state = 'confirmed_missing_receipt'
AND e2.evm_chain_id = $3
GROUP BY e2.id
- HAVING max(evm.tx_attempts.broadcast_before_block_num) < $2
+ HAVING max(evm.tx_attempts.broadcast_before_block_num) <= $2
)
FOR UPDATE OF e1
) e0
WHERE e0.id = evm.txes.id
-RETURNING e0.id, e0.nonce`, ErrCouldNotGetReceipt, cutoff, chainID.String())
+RETURNING e0.id, e0.nonce`, ErrCouldNotGetReceipt, latestFinalizedBlockNum, chainID.String())
if err != nil {
return pkgerrors.Wrap(err, "markOldTxesMissingReceiptAsErrored failed to query")
@@ -1872,7 +1894,7 @@ id < (
return
}
-func (o *evmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error {
+func (o *evmTxStore) ReapTxHistory(ctx context.Context, timeThreshold time.Time, chainID *big.Int) error {
var cancel context.CancelFunc
ctx, cancel = o.stopCh.Ctx(ctx)
defer cancel()
@@ -1885,19 +1907,18 @@ func (o *evmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int
res, err := o.q.ExecContext(ctx, `
WITH old_enough_receipts AS (
SELECT tx_hash FROM evm.receipts
- WHERE block_number < $1
ORDER BY block_number ASC, id ASC
- LIMIT $2
+ LIMIT $1
)
DELETE FROM evm.txes
USING old_enough_receipts, evm.tx_attempts
WHERE evm.tx_attempts.eth_tx_id = evm.txes.id
AND evm.tx_attempts.hash = old_enough_receipts.tx_hash
-AND evm.txes.created_at < $3
-AND evm.txes.state = 'confirmed'
-AND evm_chain_id = $4`, minBlockNumberToKeep, limit, timeThreshold, chainID.String())
+AND evm.txes.created_at < $2
+AND evm.txes.state = 'finalized'
+AND evm_chain_id = $3`, limit, timeThreshold, chainID.String())
if err != nil {
- return count, pkgerrors.Wrap(err, "ReapTxes failed to delete old confirmed evm.txes")
+ return count, pkgerrors.Wrap(err, "ReapTxes failed to delete old finalized evm.txes")
}
rowsAffected, err := res.RowsAffected()
if err != nil {
@@ -1906,7 +1927,7 @@ AND evm_chain_id = $4`, minBlockNumberToKeep, limit, timeThreshold, chainID.Stri
return uint(rowsAffected), err
}, batchSize)
if err != nil {
- return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of confirmed evm.txes failed")
+ return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of finalized evm.txes failed")
}
// Delete old 'fatal_error' evm.txes
err = sqlutil.Batch(func(_, limit uint) (count uint, err error) {
@@ -1927,6 +1948,38 @@ AND evm_chain_id = $2`, timeThreshold, chainID.String())
if err != nil {
return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of fatally errored evm.txes failed")
}
+ // Delete old 'confirmed' evm.txes that were never finalized
+ // This query should never result in changes but added just in case transactions slip through the cracks
+ // to avoid them building up in the DB
+ 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
+ ORDER BY block_number ASC, id ASC
+ LIMIT $1
+)
+DELETE FROM evm.txes
+USING old_enough_receipts, evm.tx_attempts
+WHERE evm.tx_attempts.eth_tx_id = evm.txes.id
+AND evm.tx_attempts.hash = old_enough_receipts.tx_hash
+AND evm.txes.created_at < $2
+AND evm.txes.state = 'confirmed'
+AND evm_chain_id = $3`, limit, timeThreshold, chainID.String())
+ if err != nil {
+ return count, pkgerrors.Wrap(err, "ReapTxes failed to delete old confirmed evm.txes")
+ }
+ rowsAffected, err := res.RowsAffected()
+ if err != nil {
+ return count, pkgerrors.Wrap(err, "ReapTxes failed to get rows affected")
+ }
+ if rowsAffected > 0 {
+ o.logger.Errorf("%d confirmed transactions were reaped before being marked as finalized. This should never happen unless the threshold is set too low or the transactions were lost track of", rowsAffected)
+ }
+ return uint(rowsAffected), err
+ }, batchSize)
+ if err != nil {
+ return pkgerrors.Wrap(err, "TxmReaper#reapEthTxes batch delete of confirmed evm.txes failed")
+ }
return nil
}
@@ -2055,3 +2108,36 @@ func (o *evmTxStore) UpdateTxAttemptBroadcastBeforeBlockNum(ctx context.Context,
_, err := o.q.ExecContext(ctx, sql, blockNum, id)
return err
}
+
+// FindConfirmedTxesReceipts Returns all confirmed transactions with receipt block nums older than or equal to the finalized block number
+func (o *evmTxStore) FindConfirmedTxesReceipts(ctx context.Context, finalizedBlockNum int64, chainID *big.Int) (receipts []Receipt, err error) {
+ var cancel context.CancelFunc
+ ctx, cancel = o.stopCh.Ctx(ctx)
+ defer cancel()
+
+ // note the receipts are partially loaded for performance reason
+ query := `SELECT evm.receipts.id, evm.receipts.tx_hash, evm.receipts.block_hash, evm.receipts.block_number FROM evm.receipts
+ INNER JOIN evm.tx_attempts ON evm.tx_attempts.hash = evm.receipts.tx_hash
+ INNER JOIN evm.txes ON evm.txes.id = evm.tx_attempts.eth_tx_id
+ WHERE evm.txes.state = 'confirmed' AND evm.receipts.block_number <= $1 AND evm.txes.evm_chain_id = $2`
+ err = o.q.SelectContext(ctx, &receipts, query, finalizedBlockNum, chainID.String())
+ return receipts, err
+}
+
+// Mark transactions corresponding to receipt IDs as finalized
+func (o *evmTxStore) UpdateTxStatesToFinalizedUsingReceiptIds(ctx context.Context, receiptIDs []int64, chainId *big.Int) error {
+ if len(receiptIDs) == 0 {
+ return nil
+ }
+ var cancel context.CancelFunc
+ ctx, cancel = o.stopCh.Ctx(ctx)
+ defer cancel()
+ sql := `
+UPDATE evm.txes SET state = 'finalized' WHERE evm.txes.evm_chain_id = $1 AND evm.txes.id IN (SELECT evm.txes.id FROM evm.txes
+ INNER JOIN evm.tx_attempts ON evm.tx_attempts.eth_tx_id = evm.txes.id
+ INNER JOIN evm.receipts ON evm.receipts.tx_hash = evm.tx_attempts.hash
+ WHERE evm.receipts.id = ANY($2))
+`
+ _, err := o.q.ExecContext(ctx, sql, chainId.String(), pq.Array(receiptIDs))
+ return err
+}
diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go
index afb8de4ca52..c711c2788e8 100644
--- a/core/chains/evm/txmgr/evm_tx_store_test.go
+++ b/core/chains/evm/txmgr/evm_tx_store_test.go
@@ -783,30 +783,6 @@ func TestORM_UpdateTxForRebroadcast(t *testing.T) {
})
}
-func TestORM_IsTxFinalized(t *testing.T) {
- t.Parallel()
-
- db := pgtest.NewSqlxDB(t)
- txStore := cltest.NewTestTxStore(t, db)
- ethClient := evmtest.NewEthClientMockWithDefaultChain(t)
-
- t.Run("confirmed tx not past finality_depth", func(t *testing.T) {
- confirmedAddr := cltest.MustGenerateRandomKey(t).Address
- tx := mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1)
- finalized, err := txStore.IsTxFinalized(tests.Context(t), 2, tx.ID, ethClient.ConfiguredChainID())
- require.NoError(t, err)
- require.False(t, finalized)
- })
-
- t.Run("confirmed tx past finality_depth", func(t *testing.T) {
- confirmedAddr := cltest.MustGenerateRandomKey(t).Address
- tx := mustInsertConfirmedEthTxWithReceipt(t, txStore, confirmedAddr, 123, 1)
- finalized, err := txStore.IsTxFinalized(tests.Context(t), 10, tx.ID, ethClient.ConfiguredChainID())
- require.NoError(t, err)
- require.True(t, finalized)
- })
-}
-
func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) {
t.Parallel()
@@ -840,6 +816,12 @@ func TestORM_FindTransactionsConfirmedInBlockRange(t *testing.T) {
assert.Equal(t, etxes[0].Sequence, etx_8.Sequence)
assert.Equal(t, etxes[1].Sequence, etx_9.Sequence)
})
+
+ t.Run("return empty txes when no transactions in range found", func(t *testing.T) {
+ etxes, err := txStore.FindTransactionsConfirmedInBlockRange(tests.Context(t), 0, 0, ethClient.ConfiguredChainID())
+ require.NoError(t, err)
+ assert.Len(t, etxes, 0)
+ })
}
func TestORM_FindEarliestUnconfirmedBroadcastTime(t *testing.T) {
@@ -1141,13 +1123,14 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) {
ethKeyStore := cltest.NewKeyStore(t, db).Eth()
ethClient := evmtest.NewEthClientMockWithDefaultChain(t)
_, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore)
+ latestFinalizedBlockNum := int64(8)
// tx state should be confirmed missing receipt
- // attempt should be broadcast before cutoff time
+ // attempt should be before latestFinalizedBlockNum
t.Run("successfully mark errored transactions", func(t *testing.T) {
etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress)
- err := txStore.MarkOldTxesMissingReceiptAsErrored(tests.Context(t), 10, 2, ethClient.ConfiguredChainID())
+ err := txStore.MarkOldTxesMissingReceiptAsErrored(tests.Context(t), 10, latestFinalizedBlockNum, ethClient.ConfiguredChainID())
require.NoError(t, err)
etx, err = txStore.FindTxWithAttempts(ctx, etx.ID)
@@ -1157,7 +1140,7 @@ func TestORM_MarkOldTxesMissingReceiptAsErrored(t *testing.T) {
t.Run("successfully mark errored transactions w/ qopt passing in sql.Tx", func(t *testing.T) {
etx := mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 1, 7, time.Now(), fromAddress)
- err := txStore.MarkOldTxesMissingReceiptAsErrored(tests.Context(t), 10, 2, ethClient.ConfiguredChainID())
+ err := txStore.MarkOldTxesMissingReceiptAsErrored(tests.Context(t), 10, latestFinalizedBlockNum, ethClient.ConfiguredChainID())
require.NoError(t, err)
// must run other query outside of postgres transaction so changes are committed
@@ -1382,7 +1365,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, txStore, nil, nil, nil, nil, nil)
err := txMgr.XXXTestAbandon(fromAddress) // mark transaction as abandoned
require.NoError(t, err)
@@ -1871,3 +1854,60 @@ func AssertCountPerSubject(t *testing.T, txStore txmgr.TestEvmTxStore, expected
require.NoError(t, err)
require.Equal(t, int(expected), count)
}
+
+func TestORM_FindTransactionsByState(t *testing.T) {
+ t.Parallel()
+
+ ctx := tests.Context(t)
+ db := pgtest.NewSqlxDB(t)
+ txStore := cltest.NewTestTxStore(t, db)
+ kst := cltest.NewKeyStore(t, db)
+ _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth())
+ finalizedBlockNum := int64(100)
+
+ mustInsertUnstartedTx(t, txStore, fromAddress)
+ mustInsertInProgressEthTxWithAttempt(t, txStore, 0, fromAddress)
+ mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 1, fromAddress, txmgrtypes.TxAttemptBroadcast)
+ mustInsertConfirmedMissingReceiptEthTxWithLegacyAttempt(t, txStore, 2, finalizedBlockNum, time.Now(), fromAddress)
+ mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 3, finalizedBlockNum+1)
+ mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 4, finalizedBlockNum)
+ mustInsertFatalErrorEthTx(t, txStore, fromAddress)
+
+ receipts, err := txStore.FindConfirmedTxesReceipts(ctx, finalizedBlockNum, testutils.FixtureChainID)
+ require.NoError(t, err)
+ require.Len(t, receipts, 1)
+}
+
+func TestORM_UpdateTxesFinalized(t *testing.T) {
+ t.Parallel()
+
+ ctx := tests.Context(t)
+ db := pgtest.NewSqlxDB(t)
+ txStore := cltest.NewTestTxStore(t, db)
+ kst := cltest.NewKeyStore(t, db)
+ broadcast := time.Now()
+ _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth())
+
+ t.Run("successfully finalizes a confirmed transaction", func(t *testing.T) {
+ nonce := evmtypes.Nonce(0)
+ tx := &txmgr.Tx{
+ Sequence: &nonce,
+ FromAddress: fromAddress,
+ EncodedPayload: []byte{1, 2, 3},
+ State: txmgrcommon.TxConfirmed,
+ BroadcastAt: &broadcast,
+ InitialBroadcastAt: &broadcast,
+ }
+ err := txStore.InsertTx(ctx, tx)
+ require.NoError(t, err)
+ attempt := newBroadcastLegacyEthTxAttempt(t, tx.ID)
+ err = txStore.InsertTxAttempt(ctx, &attempt)
+ require.NoError(t, err)
+ receipt := mustInsertEthReceipt(t, txStore, 100, testutils.NewHash(), attempt.Hash)
+ err = txStore.UpdateTxStatesToFinalizedUsingReceiptIds(ctx, []int64{receipt.ID}, testutils.FixtureChainID)
+ require.NoError(t, err)
+ etx, err := txStore.FindTxWithAttempts(ctx, tx.ID)
+ require.NoError(t, err)
+ require.Equal(t, txmgrcommon.TxFinalized, etx.State)
+ })
+}
diff --git a/core/chains/evm/txmgr/finalizer.go b/core/chains/evm/txmgr/finalizer.go
new file mode 100644
index 00000000000..60744636159
--- /dev/null
+++ b/core/chains/evm/txmgr/finalizer.go
@@ -0,0 +1,295 @@
+package txmgr
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/rpc"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
+
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+)
+
+var _ Finalizer = (*evmFinalizer)(nil)
+
+// processHeadTimeout represents a sanity limit on how long ProcessHead should take to complete
+const processHeadTimeout = 10 * time.Minute
+
+type finalizerTxStore interface {
+ FindConfirmedTxesReceipts(ctx context.Context, finalizedBlockNum int64, chainID *big.Int) ([]Receipt, error)
+ UpdateTxStatesToFinalizedUsingReceiptIds(ctx context.Context, txs []int64, chainId *big.Int) error
+}
+
+type finalizerChainClient interface {
+ BatchCallContext(ctx context.Context, elems []rpc.BatchElem) error
+}
+
+type finalizerHeadTracker interface {
+ LatestAndFinalizedBlock(ctx context.Context) (latest, finalized *evmtypes.Head, err error)
+}
+
+// Finalizer handles processing new finalized blocks and marking transactions as finalized accordingly in the TXM DB
+type evmFinalizer struct {
+ services.StateMachine
+ lggr logger.SugaredLogger
+ chainId *big.Int
+ rpcBatchSize int
+
+ txStore finalizerTxStore
+ client finalizerChainClient
+ headTracker finalizerHeadTracker
+
+ mb *mailbox.Mailbox[*evmtypes.Head]
+ stopCh services.StopChan
+ wg sync.WaitGroup
+
+ lastProcessedFinalizedBlockNum int64
+}
+
+func NewEvmFinalizer(
+ lggr logger.Logger,
+ chainId *big.Int,
+ rpcBatchSize uint32,
+ txStore finalizerTxStore,
+ client finalizerChainClient,
+ headTracker finalizerHeadTracker,
+) *evmFinalizer {
+ lggr = logger.Named(lggr, "Finalizer")
+ return &evmFinalizer{
+ lggr: logger.Sugared(lggr),
+ chainId: chainId,
+ rpcBatchSize: int(rpcBatchSize),
+ txStore: txStore,
+ client: client,
+ headTracker: headTracker,
+ mb: mailbox.NewSingle[*evmtypes.Head](),
+ }
+}
+
+// Start the finalizer
+func (f *evmFinalizer) Start(ctx context.Context) error {
+ return f.StartOnce("Finalizer", func() error {
+ f.lggr.Debugf("started Finalizer with RPC batch size limit: %d", f.rpcBatchSize)
+ f.stopCh = make(chan struct{})
+ f.wg.Add(1)
+ go f.runLoop()
+ return nil
+ })
+}
+
+// Close the finalizer
+func (f *evmFinalizer) Close() error {
+ return f.StopOnce("Finalizer", func() error {
+ f.lggr.Debug("closing Finalizer")
+ close(f.stopCh)
+ f.wg.Wait()
+ return nil
+ })
+}
+
+func (f *evmFinalizer) Name() string {
+ return f.lggr.Name()
+}
+
+func (f *evmFinalizer) HealthReport() map[string]error {
+ return map[string]error{f.Name(): f.Healthy()}
+}
+
+func (f *evmFinalizer) runLoop() {
+ defer f.wg.Done()
+ ctx, cancel := f.stopCh.NewCtx()
+ defer cancel()
+ for {
+ select {
+ case <-f.mb.Notify():
+ for {
+ if ctx.Err() != nil {
+ return
+ }
+ head, exists := f.mb.Retrieve()
+ if !exists {
+ break
+ }
+ if err := f.ProcessHead(ctx, head); err != nil {
+ f.lggr.Errorw("Error processing head", "err", err)
+ f.SvcErrBuffer.Append(err)
+ continue
+ }
+ }
+ case <-ctx.Done():
+ return
+ }
+ }
+}
+
+func (f *evmFinalizer) DeliverLatestHead(head *evmtypes.Head) bool {
+ return f.mb.Deliver(head)
+}
+
+func (f *evmFinalizer) ProcessHead(ctx context.Context, head *evmtypes.Head) error {
+ ctx, cancel := context.WithTimeout(ctx, processHeadTimeout)
+ defer cancel()
+ _, latestFinalizedHead, err := f.headTracker.LatestAndFinalizedBlock(ctx)
+ if err != nil {
+ return fmt.Errorf("failed to retrieve latest finalized head: %w", err)
+ }
+ return f.processFinalizedHead(ctx, latestFinalizedHead)
+}
+
+// Determines if any confirmed transactions can be marked as finalized by comparing their receipts against the latest finalized block
+func (f *evmFinalizer) processFinalizedHead(ctx context.Context, latestFinalizedHead *evmtypes.Head) error {
+ // Cannot determine finality without a finalized head for comparison
+ if latestFinalizedHead == nil || !latestFinalizedHead.IsValid() {
+ return fmt.Errorf("invalid latestFinalizedHead")
+ }
+ // Only continue processing if the latestFinalizedHead has not already been processed
+ // Helps avoid unnecessary processing on every head if blocks are finalized in batches
+ if latestFinalizedHead.BlockNumber() == f.lastProcessedFinalizedBlockNum {
+ return nil
+ }
+ if latestFinalizedHead.BlockNumber() < f.lastProcessedFinalizedBlockNum {
+ f.lggr.Errorw("Received finalized block older than one already processed. This should never happen and could be an issue with RPCs.", "lastProcessedFinalizedBlockNum", f.lastProcessedFinalizedBlockNum, "retrievedFinalizedBlockNum", latestFinalizedHead.BlockNumber())
+ return nil
+ }
+
+ earliestBlockNumInChain := latestFinalizedHead.EarliestHeadInChain().BlockNumber()
+ f.lggr.Debugw("processing latest finalized head", "blockNum", latestFinalizedHead.BlockNumber(), "blockHash", latestFinalizedHead.BlockHash(), "earliestBlockNumInChain", earliestBlockNumInChain)
+
+ // Retrieve all confirmed transactions with receipts older than or equal to the finalized block, loaded with attempts and receipts
+ unfinalizedReceipts, err := f.txStore.FindConfirmedTxesReceipts(ctx, latestFinalizedHead.BlockNumber(), f.chainId)
+ if err != nil {
+ return fmt.Errorf("failed to retrieve receipts for confirmed, unfinalized transactions: %w", err)
+ }
+
+ var finalizedReceipts []Receipt
+ // Group by block hash transactions whose receipts cannot be validated using the cached heads
+ blockNumToReceiptsMap := make(map[int64][]Receipt)
+ // Find transactions with receipt block nums older than the latest finalized block num and block hashes still in chain
+ for _, receipt := range unfinalizedReceipts {
+ // The tx store query ensures transactions have receipts but leaving this check here for a belts and braces approach
+ if receipt.TxHash == utils.EmptyHash || receipt.BlockHash == utils.EmptyHash {
+ f.lggr.AssumptionViolationw("invalid receipt found for confirmed transaction", "receipt", receipt)
+ continue
+ }
+ // The tx store query only returns transactions with receipts older than or equal to the finalized block but leaving this check here for a belts and braces approach
+ if receipt.BlockNumber > latestFinalizedHead.BlockNumber() {
+ continue
+ }
+ // Receipt block num older than earliest head in chain. Validate hash using RPC call later
+ if receipt.BlockNumber < earliestBlockNumInChain {
+ blockNumToReceiptsMap[receipt.BlockNumber] = append(blockNumToReceiptsMap[receipt.BlockNumber], receipt)
+ continue
+ }
+ blockHashInChain := latestFinalizedHead.HashAtHeight(receipt.BlockNumber)
+ // Receipt block hash does not match the block hash in chain. Transaction has been re-org'd out but DB state has not been updated yet
+ if blockHashInChain.String() != receipt.BlockHash.String() {
+ // Log error if a transaction is marked as confirmed with a receipt older than the finalized block
+ // This scenario could potentially point to a re-org'd transaction the Confirmer has lost track of
+ f.lggr.Errorw("found confirmed transaction with re-org'd receipt older than finalized block", "receipt", receipt, "onchainBlockHash", blockHashInChain.String())
+ continue
+ }
+ finalizedReceipts = append(finalizedReceipts, receipt)
+ }
+
+ // Check if block hashes exist for receipts on-chain older than the earliest cached head
+ // Transactions are grouped by their receipt block hash to avoid repeat requests on the same hash in case transactions were confirmed in the same block
+ validatedReceipts := f.batchCheckReceiptHashesOnchain(ctx, blockNumToReceiptsMap)
+ finalizedReceipts = append(finalizedReceipts, validatedReceipts...)
+
+ receiptIDs := f.buildReceiptIdList(finalizedReceipts)
+
+ err = f.txStore.UpdateTxStatesToFinalizedUsingReceiptIds(ctx, receiptIDs, f.chainId)
+ if err != nil {
+ return fmt.Errorf("failed to update transactions as finalized: %w", err)
+ }
+ // Update lastProcessedFinalizedBlockNum after processing has completed to allow failed processing to retry on subsequent heads
+ // Does not need to be protected with mutex lock because the Finalizer only runs in a single loop
+ f.lastProcessedFinalizedBlockNum = latestFinalizedHead.BlockNumber()
+ return nil
+}
+
+func (f *evmFinalizer) batchCheckReceiptHashesOnchain(ctx context.Context, blockNumToReceiptsMap map[int64][]Receipt) []Receipt {
+ if len(blockNumToReceiptsMap) == 0 {
+ return nil
+ }
+ // Group the RPC batch calls in groups of rpcBatchSize
+ var rpcBatchGroups [][]rpc.BatchElem
+ var rpcBatch []rpc.BatchElem
+ for blockNum := range blockNumToReceiptsMap {
+ elem := rpc.BatchElem{
+ Method: "eth_getBlockByNumber",
+ Args: []any{
+ hexutil.EncodeBig(big.NewInt(blockNum)),
+ false,
+ },
+ Result: new(evmtypes.Head),
+ }
+ rpcBatch = append(rpcBatch, elem)
+ if len(rpcBatch) >= f.rpcBatchSize {
+ rpcBatchGroups = append(rpcBatchGroups, rpcBatch)
+ rpcBatch = []rpc.BatchElem{}
+ }
+ }
+ if len(rpcBatch) > 0 {
+ rpcBatchGroups = append(rpcBatchGroups, rpcBatch)
+ }
+
+ var finalizedReceipts []Receipt
+ for _, rpcBatch := range rpcBatchGroups {
+ err := f.client.BatchCallContext(ctx, rpcBatch)
+ if err != nil {
+ // Continue if batch RPC call failed so other batches can still be considered for finalization
+ f.lggr.Errorw("failed to find blocks due to batch call failure", "error", err)
+ continue
+ }
+ for _, req := range rpcBatch {
+ if req.Error != nil {
+ // Continue if particular RPC call failed so other txs can still be considered for finalization
+ f.lggr.Errorw("failed to find block by number", "blockNum", req.Args[0], "error", req.Error)
+ continue
+ }
+ head, ok := req.Result.(*evmtypes.Head)
+ if !ok || !head.IsValid() {
+ // Continue if particular RPC call yielded a nil block so other txs can still be considered for finalization
+ f.lggr.Errorw("retrieved nil head for block number", "blockNum", req.Args[0])
+ continue
+ }
+ receipts := blockNumToReceiptsMap[head.BlockNumber()]
+ // Check if transaction receipts match the block hash at the given block num
+ // If they do not, the transactions may have been re-org'd out
+ // The expectation is for the Confirmer to pick up on these re-orgs and get the transaction included
+ for _, receipt := range receipts {
+ if receipt.BlockHash.String() == head.BlockHash().String() {
+ finalizedReceipts = append(finalizedReceipts, receipt)
+ } else {
+ // Log error if a transaction is marked as confirmed with a receipt older than the finalized block
+ // This scenario could potentially point to a re-org'd transaction the Confirmer has lost track of
+ f.lggr.Errorw("found confirmed transaction with re-org'd receipt older than finalized block", "receipt", receipt, "onchainBlockHash", head.BlockHash().String())
+ }
+ }
+ }
+ }
+ return finalizedReceipts
+}
+
+// Build list of transaction IDs
+func (f *evmFinalizer) buildReceiptIdList(finalizedReceipts []Receipt) []int64 {
+ receiptIds := make([]int64, len(finalizedReceipts))
+ for i, receipt := range finalizedReceipts {
+ f.lggr.Debugw("transaction considered finalized",
+ "txHash", receipt.TxHash.String(),
+ "receiptBlockNum", receipt.BlockNumber,
+ "receiptBlockHash", receipt.BlockHash.String(),
+ )
+ receiptIds[i] = receipt.ID
+ }
+ return receiptIds
+}
diff --git a/core/chains/evm/txmgr/finalizer_test.go b/core/chains/evm/txmgr/finalizer_test.go
new file mode 100644
index 00000000000..f83a53bf499
--- /dev/null
+++ b/core/chains/evm/txmgr/finalizer_test.go
@@ -0,0 +1,240 @@
+package txmgr_test
+
+import (
+ "errors"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+
+ txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/testutils"
+ "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"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/cltest"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+)
+
+func TestFinalizer_MarkTxFinalized(t *testing.T) {
+ t.Parallel()
+ ctx := tests.Context(t)
+ db := pgtest.NewSqlxDB(t)
+ txStore := cltest.NewTestTxStore(t, db)
+ ethKeyStore := cltest.NewKeyStore(t, db).Eth()
+ feeLimit := uint64(10_000)
+ ethClient := testutils.NewEthClientMockWithDefaultChain(t)
+ rpcBatchSize := uint32(1)
+ ht := headtracker.NewSimulatedHeadTracker(ethClient, true, 0)
+
+ head := &evmtypes.Head{
+ Hash: utils.NewHash(),
+ Number: 100,
+ Parent: &evmtypes.Head{
+ Hash: utils.NewHash(),
+ Number: 99,
+ IsFinalized: true,
+ },
+ }
+
+ t.Run("returns not finalized for tx with receipt newer than finalized block", func(t *testing.T) {
+ finalizer := txmgr.NewEvmFinalizer(logger.Test(t), testutils.FixtureChainID, rpcBatchSize, txStore, ethClient, ht)
+ servicetest.Run(t, finalizer)
+
+ idempotencyKey := uuid.New().String()
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ nonce := evmtypes.Nonce(0)
+ broadcast := time.Now()
+ tx := &txmgr.Tx{
+ Sequence: &nonce,
+ IdempotencyKey: &idempotencyKey,
+ FromAddress: fromAddress,
+ EncodedPayload: []byte{1, 2, 3},
+ FeeLimit: feeLimit,
+ State: txmgrcommon.TxConfirmed,
+ BroadcastAt: &broadcast,
+ InitialBroadcastAt: &broadcast,
+ }
+ attemptHash := insertTxAndAttemptWithIdempotencyKey(t, txStore, tx, idempotencyKey)
+ // Insert receipt for unfinalized block num
+ mustInsertEthReceipt(t, txStore, head.Number, head.Hash, attemptHash)
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil).Once()
+ ethClient.On("LatestFinalizedBlock", mock.Anything).Return(head.Parent, nil).Once()
+ err := finalizer.ProcessHead(ctx, head)
+ require.NoError(t, err)
+ tx, err = txStore.FindTxWithIdempotencyKey(ctx, idempotencyKey, testutils.FixtureChainID)
+ require.NoError(t, err)
+ require.Equal(t, txmgrcommon.TxConfirmed, tx.State)
+ })
+
+ t.Run("returns not finalized for tx with receipt re-org'd out", func(t *testing.T) {
+ finalizer := txmgr.NewEvmFinalizer(logger.Test(t), testutils.FixtureChainID, rpcBatchSize, txStore, ethClient, ht)
+ servicetest.Run(t, finalizer)
+
+ idempotencyKey := uuid.New().String()
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ nonce := evmtypes.Nonce(0)
+ broadcast := time.Now()
+ tx := &txmgr.Tx{
+ Sequence: &nonce,
+ IdempotencyKey: &idempotencyKey,
+ FromAddress: fromAddress,
+ EncodedPayload: []byte{1, 2, 3},
+ FeeLimit: feeLimit,
+ State: txmgrcommon.TxConfirmed,
+ BroadcastAt: &broadcast,
+ InitialBroadcastAt: &broadcast,
+ }
+ attemptHash := insertTxAndAttemptWithIdempotencyKey(t, txStore, tx, idempotencyKey)
+ // Insert receipt for finalized block num
+ mustInsertEthReceipt(t, txStore, head.Parent.Number, utils.NewHash(), attemptHash)
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil).Once()
+ ethClient.On("LatestFinalizedBlock", mock.Anything).Return(head.Parent, nil).Once()
+ err := finalizer.ProcessHead(ctx, head)
+ require.NoError(t, err)
+ tx, err = txStore.FindTxWithIdempotencyKey(ctx, idempotencyKey, testutils.FixtureChainID)
+ require.NoError(t, err)
+ require.Equal(t, txmgrcommon.TxConfirmed, tx.State)
+ })
+
+ t.Run("returns finalized for tx with receipt in a finalized block", func(t *testing.T) {
+ finalizer := txmgr.NewEvmFinalizer(logger.Test(t), testutils.FixtureChainID, rpcBatchSize, txStore, ethClient, ht)
+ servicetest.Run(t, finalizer)
+
+ idempotencyKey := uuid.New().String()
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ nonce := evmtypes.Nonce(0)
+ broadcast := time.Now()
+ tx := &txmgr.Tx{
+ Sequence: &nonce,
+ IdempotencyKey: &idempotencyKey,
+ FromAddress: fromAddress,
+ EncodedPayload: []byte{1, 2, 3},
+ FeeLimit: feeLimit,
+ State: txmgrcommon.TxConfirmed,
+ BroadcastAt: &broadcast,
+ InitialBroadcastAt: &broadcast,
+ }
+ attemptHash := insertTxAndAttemptWithIdempotencyKey(t, txStore, tx, idempotencyKey)
+ // Insert receipt for finalized block num
+ mustInsertEthReceipt(t, txStore, head.Parent.Number, head.Parent.Hash, attemptHash)
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil).Once()
+ ethClient.On("LatestFinalizedBlock", mock.Anything).Return(head.Parent, nil).Once()
+ err := finalizer.ProcessHead(ctx, head)
+ require.NoError(t, err)
+ tx, err = txStore.FindTxWithIdempotencyKey(ctx, idempotencyKey, testutils.FixtureChainID)
+ require.NoError(t, err)
+ require.Equal(t, txmgrcommon.TxFinalized, tx.State)
+ })
+
+ t.Run("returns finalized for tx with receipt older than block history depth", func(t *testing.T) {
+ finalizer := txmgr.NewEvmFinalizer(logger.Test(t), testutils.FixtureChainID, rpcBatchSize, txStore, ethClient, ht)
+ servicetest.Run(t, finalizer)
+
+ idempotencyKey := uuid.New().String()
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ nonce := evmtypes.Nonce(0)
+ broadcast := time.Now()
+ tx := &txmgr.Tx{
+ Sequence: &nonce,
+ IdempotencyKey: &idempotencyKey,
+ FromAddress: fromAddress,
+ EncodedPayload: []byte{1, 2, 3},
+ FeeLimit: feeLimit,
+ State: txmgrcommon.TxConfirmed,
+ BroadcastAt: &broadcast,
+ InitialBroadcastAt: &broadcast,
+ }
+ attemptHash := insertTxAndAttemptWithIdempotencyKey(t, txStore, tx, idempotencyKey)
+ // Insert receipt for finalized block num
+ receiptBlockHash1 := utils.NewHash()
+ mustInsertEthReceipt(t, txStore, head.Parent.Number-2, receiptBlockHash1, attemptHash)
+ idempotencyKey = uuid.New().String()
+ nonce = evmtypes.Nonce(1)
+ tx = &txmgr.Tx{
+ Sequence: &nonce,
+ IdempotencyKey: &idempotencyKey,
+ FromAddress: fromAddress,
+ EncodedPayload: []byte{1, 2, 3},
+ FeeLimit: feeLimit,
+ State: txmgrcommon.TxConfirmed,
+ BroadcastAt: &broadcast,
+ InitialBroadcastAt: &broadcast,
+ }
+ attemptHash = insertTxAndAttemptWithIdempotencyKey(t, txStore, tx, idempotencyKey)
+ // Insert receipt for finalized block num
+ receiptBlockHash2 := utils.NewHash()
+ mustInsertEthReceipt(t, txStore, head.Parent.Number-1, receiptBlockHash2, attemptHash)
+ // Separate batch calls will be made for each tx due to RPC batch size set to 1 when finalizer initialized above
+ ethClient.On("BatchCallContext", mock.Anything, mock.IsType([]rpc.BatchElem{})).Run(func(args mock.Arguments) {
+ rpcElements := args.Get(1).([]rpc.BatchElem)
+ require.Equal(t, 1, len(rpcElements))
+
+ require.Equal(t, "eth_getBlockByNumber", rpcElements[0].Method)
+ require.Equal(t, false, rpcElements[0].Args[1])
+
+ reqBlockNum := rpcElements[0].Args[0].(string)
+ req1BlockNum := hexutil.EncodeBig(big.NewInt(head.Parent.Number - 2))
+ req2BlockNum := hexutil.EncodeBig(big.NewInt(head.Parent.Number - 1))
+ var headResult evmtypes.Head
+ if req1BlockNum == reqBlockNum {
+ headResult = evmtypes.Head{Number: head.Parent.Number - 2, Hash: receiptBlockHash1}
+ } else if req2BlockNum == reqBlockNum {
+ headResult = evmtypes.Head{Number: head.Parent.Number - 1, Hash: receiptBlockHash2}
+ } else {
+ require.Fail(t, "unrecognized block hash")
+ }
+ rpcElements[0].Result = &headResult
+ }).Return(nil).Twice()
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil).Once()
+ ethClient.On("LatestFinalizedBlock", mock.Anything).Return(head.Parent, nil).Once()
+ err := finalizer.ProcessHead(ctx, head)
+ require.NoError(t, err)
+ tx, err = txStore.FindTxWithIdempotencyKey(ctx, idempotencyKey, testutils.FixtureChainID)
+ require.NoError(t, err)
+ require.Equal(t, txmgrcommon.TxFinalized, tx.State)
+ })
+
+ t.Run("returns error if failed to retrieve latest head in headtracker", func(t *testing.T) {
+ finalizer := txmgr.NewEvmFinalizer(logger.Test(t), testutils.FixtureChainID, rpcBatchSize, txStore, ethClient, ht)
+ servicetest.Run(t, finalizer)
+
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(nil, errors.New("failed to get latest head")).Once()
+ err := finalizer.ProcessHead(ctx, head)
+ require.Error(t, err)
+ })
+
+ t.Run("returns error if failed to calculate latest finalized head in headtracker", func(t *testing.T) {
+ finalizer := txmgr.NewEvmFinalizer(logger.Test(t), testutils.FixtureChainID, rpcBatchSize, txStore, ethClient, ht)
+ servicetest.Run(t, finalizer)
+
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil).Once()
+ ethClient.On("LatestFinalizedBlock", mock.Anything).Return(nil, errors.New("failed to calculate latest finalized head")).Once()
+ err := finalizer.ProcessHead(ctx, head)
+ require.Error(t, err)
+ })
+}
+
+func insertTxAndAttemptWithIdempotencyKey(t *testing.T, txStore txmgr.TestEvmTxStore, tx *txmgr.Tx, idempotencyKey string) common.Hash {
+ ctx := tests.Context(t)
+ err := txStore.InsertTx(ctx, tx)
+ require.NoError(t, err)
+ tx, err = txStore.FindTxWithIdempotencyKey(ctx, idempotencyKey, testutils.FixtureChainID)
+ require.NoError(t, err)
+ attempt := cltest.NewLegacyEthTxAttempt(t, tx.ID)
+ err = txStore.InsertTxAttempt(ctx, &attempt)
+ require.NoError(t, err)
+ return attempt.Hash
+}
diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go
index b28e55ec324..a9a175e3d94 100644
--- a/core/chains/evm/txmgr/mocks/evm_tx_store.go
+++ b/core/chains/evm/txmgr/mocks/evm_tx_store.go
@@ -18,6 +18,8 @@ import (
time "time"
+ txmgr "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
+
types "github.com/smartcontractkit/chainlink/v2/common/txmgr/types"
uuid "github.com/google/uuid"
@@ -444,6 +446,66 @@ func (_c *EvmTxStore_DeleteInProgressAttempt_Call) RunAndReturn(run func(context
return _c
}
+// FindConfirmedTxesReceipts provides a mock function with given fields: ctx, finalizedBlockNum, chainID
+func (_m *EvmTxStore) FindConfirmedTxesReceipts(ctx context.Context, finalizedBlockNum int64, chainID *big.Int) ([]txmgr.DbReceipt, error) {
+ ret := _m.Called(ctx, finalizedBlockNum, chainID)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FindConfirmedTxesReceipts")
+ }
+
+ var r0 []txmgr.DbReceipt
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) ([]txmgr.DbReceipt, error)); ok {
+ return rf(ctx, finalizedBlockNum, chainID)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) []txmgr.DbReceipt); ok {
+ r0 = rf(ctx, finalizedBlockNum, chainID)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]txmgr.DbReceipt)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, int64, *big.Int) error); ok {
+ r1 = rf(ctx, finalizedBlockNum, chainID)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EvmTxStore_FindConfirmedTxesReceipts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindConfirmedTxesReceipts'
+type EvmTxStore_FindConfirmedTxesReceipts_Call struct {
+ *mock.Call
+}
+
+// FindConfirmedTxesReceipts is a helper method to define mock.On call
+// - ctx context.Context
+// - finalizedBlockNum int64
+// - chainID *big.Int
+func (_e *EvmTxStore_Expecter) FindConfirmedTxesReceipts(ctx interface{}, finalizedBlockNum interface{}, chainID interface{}) *EvmTxStore_FindConfirmedTxesReceipts_Call {
+ return &EvmTxStore_FindConfirmedTxesReceipts_Call{Call: _e.mock.On("FindConfirmedTxesReceipts", ctx, finalizedBlockNum, chainID)}
+}
+
+func (_c *EvmTxStore_FindConfirmedTxesReceipts_Call) Run(run func(ctx context.Context, finalizedBlockNum int64, chainID *big.Int)) *EvmTxStore_FindConfirmedTxesReceipts_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(int64), args[2].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *EvmTxStore_FindConfirmedTxesReceipts_Call) Return(receipts []txmgr.DbReceipt, err error) *EvmTxStore_FindConfirmedTxesReceipts_Call {
+ _c.Call.Return(receipts, err)
+ return _c
+}
+
+func (_c *EvmTxStore_FindConfirmedTxesReceipts_Call) RunAndReturn(run func(context.Context, int64, *big.Int) ([]txmgr.DbReceipt, error)) *EvmTxStore_FindConfirmedTxesReceipts_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// FindEarliestUnconfirmedBroadcastTime provides a mock function with given fields: ctx, chainID
func (_m *EvmTxStore) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID *big.Int) (null.Time, error) {
ret := _m.Called(ctx, chainID)
@@ -2058,65 +2120,6 @@ func (_c *EvmTxStore_HasInProgressTransaction_Call) RunAndReturn(run func(contex
return _c
}
-// IsTxFinalized provides a mock function with given fields: ctx, blockHeight, txID, chainID
-func (_m *EvmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID *big.Int) (bool, error) {
- ret := _m.Called(ctx, blockHeight, txID, chainID)
-
- if len(ret) == 0 {
- panic("no return value specified for IsTxFinalized")
- }
-
- var r0 bool
- var r1 error
- if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) (bool, error)); ok {
- return rf(ctx, blockHeight, txID, chainID)
- }
- if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) bool); ok {
- r0 = rf(ctx, blockHeight, txID, chainID)
- } else {
- r0 = ret.Get(0).(bool)
- }
-
- if rf, ok := ret.Get(1).(func(context.Context, int64, int64, *big.Int) error); ok {
- r1 = rf(ctx, blockHeight, txID, chainID)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// EvmTxStore_IsTxFinalized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsTxFinalized'
-type EvmTxStore_IsTxFinalized_Call struct {
- *mock.Call
-}
-
-// IsTxFinalized is a helper method to define mock.On call
-// - ctx context.Context
-// - blockHeight int64
-// - txID int64
-// - chainID *big.Int
-func (_e *EvmTxStore_Expecter) IsTxFinalized(ctx interface{}, blockHeight interface{}, txID interface{}, chainID interface{}) *EvmTxStore_IsTxFinalized_Call {
- return &EvmTxStore_IsTxFinalized_Call{Call: _e.mock.On("IsTxFinalized", ctx, blockHeight, txID, chainID)}
-}
-
-func (_c *EvmTxStore_IsTxFinalized_Call) Run(run func(ctx context.Context, blockHeight int64, txID int64, chainID *big.Int)) *EvmTxStore_IsTxFinalized_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(int64), args[2].(int64), args[3].(*big.Int))
- })
- return _c
-}
-
-func (_c *EvmTxStore_IsTxFinalized_Call) Return(finalized bool, err error) *EvmTxStore_IsTxFinalized_Call {
- _c.Call.Return(finalized, err)
- return _c
-}
-
-func (_c *EvmTxStore_IsTxFinalized_Call) RunAndReturn(run func(context.Context, int64, int64, *big.Int) (bool, error)) *EvmTxStore_IsTxFinalized_Call {
- _c.Call.Return(run)
- return _c
-}
-
// LoadTxAttempts provides a mock function with given fields: ctx, etx
func (_m *EvmTxStore) LoadTxAttempts(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error {
ret := _m.Called(ctx, etx)
@@ -2211,17 +2214,17 @@ func (_c *EvmTxStore_MarkAllConfirmedMissingReceipt_Call) RunAndReturn(run func(
return _c
}
-// MarkOldTxesMissingReceiptAsErrored provides a mock function with given fields: ctx, blockNum, finalityDepth, chainID
-func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID *big.Int) error {
- ret := _m.Called(ctx, blockNum, finalityDepth, chainID)
+// MarkOldTxesMissingReceiptAsErrored provides a mock function with given fields: ctx, blockNum, latestFinalizedBlockNum, chainID
+func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, latestFinalizedBlockNum int64, chainID *big.Int) error {
+ ret := _m.Called(ctx, blockNum, latestFinalizedBlockNum, chainID)
if len(ret) == 0 {
panic("no return value specified for MarkOldTxesMissingReceiptAsErrored")
}
var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, int64, uint32, *big.Int) error); ok {
- r0 = rf(ctx, blockNum, finalityDepth, chainID)
+ if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) error); ok {
+ r0 = rf(ctx, blockNum, latestFinalizedBlockNum, chainID)
} else {
r0 = ret.Error(0)
}
@@ -2237,15 +2240,15 @@ type EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call struct {
// MarkOldTxesMissingReceiptAsErrored is a helper method to define mock.On call
// - ctx context.Context
// - blockNum int64
-// - finalityDepth uint32
+// - latestFinalizedBlockNum int64
// - chainID *big.Int
-func (_e *EvmTxStore_Expecter) MarkOldTxesMissingReceiptAsErrored(ctx interface{}, blockNum interface{}, finalityDepth interface{}, chainID interface{}) *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call {
- return &EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call{Call: _e.mock.On("MarkOldTxesMissingReceiptAsErrored", ctx, blockNum, finalityDepth, chainID)}
+func (_e *EvmTxStore_Expecter) MarkOldTxesMissingReceiptAsErrored(ctx interface{}, blockNum interface{}, latestFinalizedBlockNum interface{}, chainID interface{}) *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call {
+ return &EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call{Call: _e.mock.On("MarkOldTxesMissingReceiptAsErrored", ctx, blockNum, latestFinalizedBlockNum, chainID)}
}
-func (_c *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call) Run(run func(ctx context.Context, blockNum int64, finalityDepth uint32, chainID *big.Int)) *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call {
+func (_c *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call) Run(run func(ctx context.Context, blockNum int64, latestFinalizedBlockNum int64, chainID *big.Int)) *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call {
_c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(int64), args[2].(uint32), args[3].(*big.Int))
+ run(args[0].(context.Context), args[1].(int64), args[2].(int64), args[3].(*big.Int))
})
return _c
}
@@ -2255,7 +2258,7 @@ func (_c *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call) Return(_a0 error)
return _c
}
-func (_c *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call) RunAndReturn(run func(context.Context, int64, uint32, *big.Int) error) *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call {
+func (_c *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call) RunAndReturn(run func(context.Context, int64, int64, *big.Int) error) *EvmTxStore_MarkOldTxesMissingReceiptAsErrored_Call {
_c.Call.Return(run)
return _c
}
@@ -2367,17 +2370,17 @@ func (_c *EvmTxStore_PruneUnstartedTxQueue_Call) RunAndReturn(run func(context.C
return _c
}
-// ReapTxHistory provides a mock function with given fields: ctx, minBlockNumberToKeep, timeThreshold, chainID
-func (_m *EvmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error {
- ret := _m.Called(ctx, minBlockNumberToKeep, timeThreshold, chainID)
+// ReapTxHistory provides a mock function with given fields: ctx, timeThreshold, chainID
+func (_m *EvmTxStore) ReapTxHistory(ctx context.Context, timeThreshold time.Time, chainID *big.Int) error {
+ ret := _m.Called(ctx, timeThreshold, chainID)
if len(ret) == 0 {
panic("no return value specified for ReapTxHistory")
}
var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, int64, time.Time, *big.Int) error); ok {
- r0 = rf(ctx, minBlockNumberToKeep, timeThreshold, chainID)
+ if rf, ok := ret.Get(0).(func(context.Context, time.Time, *big.Int) error); ok {
+ r0 = rf(ctx, timeThreshold, chainID)
} else {
r0 = ret.Error(0)
}
@@ -2392,16 +2395,15 @@ type EvmTxStore_ReapTxHistory_Call struct {
// ReapTxHistory is a helper method to define mock.On call
// - ctx context.Context
-// - minBlockNumberToKeep int64
// - timeThreshold time.Time
// - chainID *big.Int
-func (_e *EvmTxStore_Expecter) ReapTxHistory(ctx interface{}, minBlockNumberToKeep interface{}, timeThreshold interface{}, chainID interface{}) *EvmTxStore_ReapTxHistory_Call {
- return &EvmTxStore_ReapTxHistory_Call{Call: _e.mock.On("ReapTxHistory", ctx, minBlockNumberToKeep, timeThreshold, chainID)}
+func (_e *EvmTxStore_Expecter) ReapTxHistory(ctx interface{}, timeThreshold interface{}, chainID interface{}) *EvmTxStore_ReapTxHistory_Call {
+ return &EvmTxStore_ReapTxHistory_Call{Call: _e.mock.On("ReapTxHistory", ctx, timeThreshold, chainID)}
}
-func (_c *EvmTxStore_ReapTxHistory_Call) Run(run func(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int)) *EvmTxStore_ReapTxHistory_Call {
+func (_c *EvmTxStore_ReapTxHistory_Call) Run(run func(ctx context.Context, timeThreshold time.Time, chainID *big.Int)) *EvmTxStore_ReapTxHistory_Call {
_c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(int64), args[2].(time.Time), args[3].(*big.Int))
+ run(args[0].(context.Context), args[1].(time.Time), args[2].(*big.Int))
})
return _c
}
@@ -2411,7 +2413,7 @@ func (_c *EvmTxStore_ReapTxHistory_Call) Return(_a0 error) *EvmTxStore_ReapTxHis
return _c
}
-func (_c *EvmTxStore_ReapTxHistory_Call) RunAndReturn(run func(context.Context, int64, time.Time, *big.Int) error) *EvmTxStore_ReapTxHistory_Call {
+func (_c *EvmTxStore_ReapTxHistory_Call) RunAndReturn(run func(context.Context, time.Time, *big.Int) error) *EvmTxStore_ReapTxHistory_Call {
_c.Call.Return(run)
return _c
}
@@ -3197,6 +3199,54 @@ func (_c *EvmTxStore_UpdateTxForRebroadcast_Call) RunAndReturn(run func(context.
return _c
}
+// UpdateTxStatesToFinalizedUsingReceiptIds provides a mock function with given fields: ctx, etxIDs, chainId
+func (_m *EvmTxStore) UpdateTxStatesToFinalizedUsingReceiptIds(ctx context.Context, etxIDs []int64, chainId *big.Int) error {
+ ret := _m.Called(ctx, etxIDs, chainId)
+
+ if len(ret) == 0 {
+ panic("no return value specified for UpdateTxStatesToFinalizedUsingReceiptIds")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, []int64, *big.Int) error); ok {
+ r0 = rf(ctx, etxIDs, chainId)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateTxStatesToFinalizedUsingReceiptIds'
+type EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call struct {
+ *mock.Call
+}
+
+// UpdateTxStatesToFinalizedUsingReceiptIds is a helper method to define mock.On call
+// - ctx context.Context
+// - etxIDs []int64
+// - chainId *big.Int
+func (_e *EvmTxStore_Expecter) UpdateTxStatesToFinalizedUsingReceiptIds(ctx interface{}, etxIDs interface{}, chainId interface{}) *EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call {
+ return &EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call{Call: _e.mock.On("UpdateTxStatesToFinalizedUsingReceiptIds", ctx, etxIDs, chainId)}
+}
+
+func (_c *EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call) Run(run func(ctx context.Context, etxIDs []int64, chainId *big.Int)) *EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]int64), args[2].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call) Return(_a0 error) *EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call) RunAndReturn(run func(context.Context, []int64, *big.Int) error) *EvmTxStore_UpdateTxStatesToFinalizedUsingReceiptIds_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// UpdateTxUnstartedToInProgress provides a mock function with given fields: ctx, etx, attempt
func (_m *EvmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error {
ret := _m.Called(ctx, etx, attempt)
diff --git a/core/chains/evm/txmgr/models.go b/core/chains/evm/txmgr/models.go
index f8682ffd500..1ba3d193cba 100644
--- a/core/chains/evm/txmgr/models.go
+++ b/core/chains/evm/txmgr/models.go
@@ -36,12 +36,13 @@ type (
Tx = txmgrtypes.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]
TxMeta = txmgrtypes.TxMeta[common.Address, common.Hash]
TxAttempt = txmgrtypes.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]
- Receipt = dbReceipt // EvmReceipt is the exported DB table model for receipts
+ Receipt = DbReceipt // DbReceipt is the exported DB table model for receipts
ReceiptPlus = txmgrtypes.ReceiptPlus[*evmtypes.Receipt]
StuckTxDetector = txmgrtypes.StuckTxDetector[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]
TxmClient = txmgrtypes.TxmClient[*big.Int, common.Address, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee]
TransactionClient = txmgrtypes.TransactionClient[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]
ChainReceipt = txmgrtypes.ChainReceipt[common.Hash, common.Hash]
+ Finalizer = txmgrtypes.Finalizer[common.Hash, *evmtypes.Head]
)
var _ KeyStore = (keystore.Eth)(nil) // check interface in txmgr to avoid circular import
diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go
index b3ce48b702c..cfaccdf04eb 100644
--- a/core/chains/evm/txmgr/reaper_test.go
+++ b/core/chains/evm/txmgr/reaper_test.go
@@ -12,18 +12,17 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/utils"
txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types"
- txmgrmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
"github.com/smartcontractkit/chainlink/v2/core/internal/cltest"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
)
-func newReaperWithChainID(t *testing.T, db txmgrtypes.TxHistoryReaper[*big.Int], cfg txmgrtypes.ReaperChainConfig, txConfig txmgrtypes.ReaperTransactionsConfig, cid *big.Int) *txmgr.Reaper {
- return txmgr.NewEvmReaper(logger.Test(t), db, cfg, txConfig, cid)
+func newReaperWithChainID(t *testing.T, db txmgrtypes.TxHistoryReaper[*big.Int], txConfig txmgrtypes.ReaperTransactionsConfig, cid *big.Int) *txmgr.Reaper {
+ return txmgr.NewEvmReaper(logger.Test(t), db, txConfig, cid)
}
-func newReaper(t *testing.T, db txmgrtypes.TxHistoryReaper[*big.Int], cfg txmgrtypes.ReaperChainConfig, txConfig txmgrtypes.ReaperTransactionsConfig) *txmgr.Reaper {
- return newReaperWithChainID(t, db, cfg, txConfig, &cltest.FixtureChainID)
+func newReaper(t *testing.T, db txmgrtypes.TxHistoryReaper[*big.Int], txConfig txmgrtypes.ReaperTransactionsConfig) *txmgr.Reaper {
+ return newReaperWithChainID(t, db, txConfig, &cltest.FixtureChainID)
}
type reaperConfig struct {
@@ -51,12 +50,9 @@ func TestReaper_ReapTxes(t *testing.T) {
oneDayAgo := time.Now().Add(-24 * time.Hour)
t.Run("with nothing in the database, doesn't error", func(t *testing.T) {
- config := txmgrmocks.NewReaperConfig(t)
- config.On("FinalityDepth").Return(uint32(10))
-
tc := &reaperConfig{reaperThreshold: 1 * time.Hour}
- r := newReaper(t, txStore, config, tc)
+ r := newReaper(t, txStore, tc)
err := r.ReapTxes(42)
assert.NoError(t, err)
@@ -66,11 +62,9 @@ func TestReaper_ReapTxes(t *testing.T) {
mustInsertConfirmedEthTxWithReceipt(t, txStore, from, nonce, 5)
t.Run("skips if threshold=0", func(t *testing.T) {
- config := txmgrmocks.NewReaperConfig(t)
-
tc := &reaperConfig{reaperThreshold: 0 * time.Second}
- r := newReaper(t, txStore, config, tc)
+ r := newReaper(t, txStore, tc)
err := r.ReapTxes(42)
assert.NoError(t, err)
@@ -79,12 +73,9 @@ func TestReaper_ReapTxes(t *testing.T) {
})
t.Run("doesn't touch ethtxes with different chain ID", func(t *testing.T) {
- config := txmgrmocks.NewReaperConfig(t)
- config.On("FinalityDepth").Return(uint32(10))
-
tc := &reaperConfig{reaperThreshold: 1 * time.Hour}
- r := newReaperWithChainID(t, txStore, config, tc, big.NewInt(42))
+ r := newReaperWithChainID(t, txStore, tc, big.NewInt(42))
err := r.ReapTxes(42)
assert.NoError(t, err)
@@ -92,41 +83,30 @@ func TestReaper_ReapTxes(t *testing.T) {
cltest.AssertCount(t, db, "evm.txes", 1)
})
- t.Run("deletes confirmed evm.txes that exceed the age threshold with at least EVM.FinalityDepth blocks above their receipt", func(t *testing.T) {
- config := txmgrmocks.NewReaperConfig(t)
- config.On("FinalityDepth").Return(uint32(10))
-
+ t.Run("deletes finalized evm.txes that exceed the age threshold", func(t *testing.T) {
tc := &reaperConfig{reaperThreshold: 1 * time.Hour}
- r := newReaper(t, txStore, config, tc)
+ r := newReaper(t, txStore, tc)
err := r.ReapTxes(42)
assert.NoError(t, err)
// Didn't delete because eth_tx was not old enough
cltest.AssertCount(t, db, "evm.txes", 1)
- pgtest.MustExec(t, db, `UPDATE evm.txes SET created_at=$1`, oneDayAgo)
-
- err = r.ReapTxes(12)
- assert.NoError(t, err)
- // Didn't delete because eth_tx although old enough, was still within EVM.FinalityDepth of the current head
- cltest.AssertCount(t, db, "evm.txes", 1)
+ pgtest.MustExec(t, db, `UPDATE evm.txes SET created_at=$1, state='finalized'`, oneDayAgo)
err = r.ReapTxes(42)
assert.NoError(t, err)
- // Now it deleted because the eth_tx was past EVM.FinalityDepth
+ // Now it deleted because the eth_tx was past the age threshold
cltest.AssertCount(t, db, "evm.txes", 0)
})
mustInsertFatalErrorEthTx(t, txStore, from)
t.Run("deletes errored evm.txes that exceed the age threshold", func(t *testing.T) {
- config := txmgrmocks.NewReaperConfig(t)
- config.On("FinalityDepth").Return(uint32(10))
-
tc := &reaperConfig{reaperThreshold: 1 * time.Hour}
- r := newReaper(t, txStore, config, tc)
+ r := newReaper(t, txStore, tc)
err := r.ReapTxes(42)
assert.NoError(t, err)
@@ -140,4 +120,24 @@ func TestReaper_ReapTxes(t *testing.T) {
// Deleted because it is old enough now
cltest.AssertCount(t, db, "evm.txes", 0)
})
+
+ mustInsertConfirmedEthTxWithReceipt(t, txStore, from, 0, 42)
+
+ t.Run("deletes confirmed evm.txes that exceed the age threshold", func(t *testing.T) {
+ tc := &reaperConfig{reaperThreshold: 1 * time.Hour}
+
+ r := newReaper(t, txStore, tc)
+
+ err := r.ReapTxes(42)
+ assert.NoError(t, err)
+ // Didn't delete because eth_tx was not old enough
+ cltest.AssertCount(t, db, "evm.txes", 1)
+
+ pgtest.MustExec(t, db, `UPDATE evm.txes SET created_at=$1`, oneDayAgo)
+
+ err = r.ReapTxes(42)
+ assert.NoError(t, err)
+ // Now it deleted because the eth_tx was past the age threshold
+ cltest.AssertCount(t, db, "evm.txes", 0)
+ })
}
diff --git a/core/chains/evm/txmgr/stuck_tx_detector.go b/core/chains/evm/txmgr/stuck_tx_detector.go
index 1beb857af8f..4e521d5f8ff 100644
--- a/core/chains/evm/txmgr/stuck_tx_detector.go
+++ b/core/chains/evm/txmgr/stuck_tx_detector.go
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
+ "errors"
"fmt"
"math/big"
"net/http"
@@ -24,7 +25,7 @@ import (
)
type stuckTxDetectorGasEstimator interface {
- GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, opts ...feetypes.Opt) (fee gas.EvmFee, chainSpecificFeeLimit uint64, err error)
+ GetFee(ctx context.Context, calldata []byte, feeLimit uint64, maxFeePrice *assets.Wei, toAddress *common.Address, opts ...feetypes.Opt) (fee gas.EvmFee, chainSpecificFeeLimit uint64, err error)
}
type stuckTxDetectorClient interface {
@@ -37,13 +38,13 @@ type stuckTxDetectorTxStore interface {
type stuckTxDetectorConfig interface {
Enabled() bool
- Threshold() uint32
- MinAttempts() uint32
+ Threshold() *uint32
+ MinAttempts() *uint32
DetectionApiUrl() *url.URL
}
type stuckTxDetector struct {
- lggr logger.Logger
+ lggr logger.SugaredLogger
chainID *big.Int
chainType chaintype.ChainType
maxPrice *assets.Wei
@@ -63,7 +64,7 @@ func NewStuckTxDetector(lggr logger.Logger, chainID *big.Int, chainType chaintyp
t.DisableCompression = true
httpClient := &http.Client{Transport: t}
return &stuckTxDetector{
- lggr: lggr,
+ lggr: logger.Sugared(lggr),
chainID: chainID,
chainType: chainType,
maxPrice: maxPrice,
@@ -78,7 +79,7 @@ func NewStuckTxDetector(lggr logger.Logger, chainID *big.Int, chainType chaintyp
func (d *stuckTxDetector) LoadPurgeBlockNumMap(ctx context.Context, addresses []common.Address) error {
// Skip loading purge block num map if auto-purge feature disabled or Threshold is set to 0
- if !d.cfg.Enabled() || d.cfg.Threshold() == 0 {
+ if !d.cfg.Enabled() || d.cfg.Threshold() == nil || *d.cfg.Threshold() == 0 {
return nil
}
d.purgeBlockNumLock.Lock()
@@ -127,7 +128,7 @@ func (d *stuckTxDetector) DetectStuckTransactions(ctx context.Context, enabledAd
switch d.chainType {
case chaintype.ChainScroll:
return d.detectStuckTransactionsScroll(ctx, txs)
- case chaintype.ChainZkEvm:
+ case chaintype.ChainZkEvm, chaintype.ChainXLayer:
return d.detectStuckTransactionsZkEVM(ctx, txs)
default:
return d.detectStuckTransactionsHeuristic(ctx, txs, blockNum)
@@ -152,11 +153,28 @@ func (d *stuckTxDetector) FindUnconfirmedTxWithLowestNonce(ctx context.Context,
}
}
- // Build list of potentially stuck tx but exclude any that are already marked for purge
+ // Build list of potentially stuck tx but exclude any that are already marked for purge or have non-broadcasted attempts
var stuckTxs []Tx
for _, tx := range lowestNonceTxMap {
- // Attempts are loaded newest to oldest so one marked for purge will always be first
- if len(tx.TxAttempts) > 0 && !tx.TxAttempts[0].IsPurgeAttempt {
+ if len(tx.TxAttempts) == 0 {
+ d.lggr.AssumptionViolationw("encountered an unconfirmed transaction without an attempt", "tx", tx)
+ continue
+ }
+ // Check the transaction's attempts in case any are already marked for purge or if any are not broadcasted
+ // We can only have one non-broadcasted attempt for a transaction at a time
+ // Skip purge detection until all attempts are broadcasted to avoid conflicts with the purge attempt
+ var foundPurgeAttempt, foundNonBroadcastAttempt bool
+ for _, attempt := range tx.TxAttempts {
+ if attempt.IsPurgeAttempt {
+ foundPurgeAttempt = true
+ break
+ }
+ if attempt.State != types.TxAttemptBroadcast {
+ foundNonBroadcastAttempt = true
+ break
+ }
+ }
+ if !foundPurgeAttempt && !foundNonBroadcastAttempt {
stuckTxs = append(stuckTxs, tx)
}
}
@@ -172,11 +190,16 @@ func (d *stuckTxDetector) FindUnconfirmedTxWithLowestNonce(ctx context.Context,
// 4. If 3 is true, check if the latest attempt's gas price is higher than what our gas estimator's GetFee method returns
// 5. If 4 is true, the transaction is likely stuck due to overflow
func (d *stuckTxDetector) detectStuckTransactionsHeuristic(ctx context.Context, txs []Tx, blockNum int64) ([]Tx, error) {
+ if d.cfg.Threshold() == nil || d.cfg.MinAttempts() == nil {
+ err := errors.New("missing required configs for the stuck transaction heuristic. Transactions.AutoPurge.Threshold and Transactions.AutoPurge.MinAttempts are required")
+ d.lggr.Error(err.Error())
+ return txs, err
+ }
d.purgeBlockNumLock.RLock()
defer d.purgeBlockNumLock.RUnlock()
// Get gas price from internal gas estimator
// Send with max gas price time 2 to prevent the results from being capped. Need the market gas price here.
- marketGasPrice, _, err := d.gasEstimator.GetFee(ctx, []byte{}, 0, d.maxPrice.Mul(big.NewInt(2)))
+ marketGasPrice, _, err := d.gasEstimator.GetFee(ctx, []byte{}, 0, d.maxPrice.Mul(big.NewInt(2)), nil)
if err != nil {
return txs, fmt.Errorf("failed to get market gas price for overflow detection: %w", err)
}
@@ -187,17 +210,17 @@ func (d *stuckTxDetector) detectStuckTransactionsHeuristic(ctx context.Context,
d.purgeBlockNumLock.RLock()
lastPurgeBlockNum := d.purgeBlockNumMap[tx.FromAddress]
d.purgeBlockNumLock.RUnlock()
- if lastPurgeBlockNum > blockNum-int64(d.cfg.Threshold()) {
+ if lastPurgeBlockNum > blockNum-int64(*d.cfg.Threshold()) {
continue
}
// Tx attempts are loaded from newest to oldest
oldestBroadcastAttempt, newestBroadcastAttempt, broadcastedAttemptsCount := findBroadcastedAttempts(tx)
// 2. Check if Threshold amount of blocks have passed since the oldest attempt's broadcast block num
- if *oldestBroadcastAttempt.BroadcastBeforeBlockNum > blockNum-int64(d.cfg.Threshold()) {
+ if *oldestBroadcastAttempt.BroadcastBeforeBlockNum > blockNum-int64(*d.cfg.Threshold()) {
continue
}
// 3. Check if the transaction has at least MinAttempts amount of broadcasted attempts
- if broadcastedAttemptsCount < d.cfg.MinAttempts() {
+ if broadcastedAttemptsCount < *d.cfg.MinAttempts() {
continue
}
// 4. Check if the newest broadcasted attempt's gas price is higher than what our gas estimator's GetFee method returns
@@ -278,6 +301,10 @@ func (d *stuckTxDetector) detectStuckTransactionsScroll(ctx context.Context, txs
if err != nil {
return nil, fmt.Errorf("failed to make new request with context: %w", err)
}
+
+ // Add Content-Type header
+ postReq.Header.Add("Content-Type", "application/json")
+
// Send request
resp, err := d.httpClient.Do(postReq)
if err != nil {
@@ -287,6 +314,7 @@ func (d *stuckTxDetector) detectStuckTransactionsScroll(ctx context.Context, txs
if resp.StatusCode != 200 {
return nil, fmt.Errorf("request failed with status %d", resp.StatusCode)
}
+
// Decode the response into expected type
scrollResp := new(scrollResponse)
err = json.NewDecoder(resp.Body).Decode(scrollResp)
@@ -311,14 +339,32 @@ func (d *stuckTxDetector) detectStuckTransactionsScroll(ctx context.Context, txs
// Uses eth_getTransactionByHash to detect that a transaction has been discarded due to overflow
// Currently only used by zkEVM but if other chains follow the same behavior in the future
func (d *stuckTxDetector) detectStuckTransactionsZkEVM(ctx context.Context, txs []Tx) ([]Tx, error) {
- txReqs := make([]rpc.BatchElem, len(txs))
+ minAttempts := 0
+ if d.cfg.MinAttempts() != nil {
+ minAttempts = int(*d.cfg.MinAttempts())
+ }
+ // Check transactions have MinAttempts to ensure it has enough time to return results for getTransactionByHash
+ // zkEVM has a significant delay between broadcasting a transaction and getting a proper result from the RPC
+ var filteredTx []Tx
+ for _, tx := range txs {
+ if len(tx.TxAttempts) >= minAttempts {
+ filteredTx = append(filteredTx, tx)
+ }
+ }
+
+ // No transactions to process
+ if len(filteredTx) == 0 {
+ return filteredTx, nil
+ }
+
+ txReqs := make([]rpc.BatchElem, len(filteredTx))
txHashMap := make(map[common.Hash]Tx)
- txRes := make([]*map[string]interface{}, len(txs))
+ txRes := make([]*map[string]interface{}, len(filteredTx))
// Build batch request elems to perform
// Does not need to be separated out into smaller batches
// Max number of transactions to check is equal to the number of enabled addresses which is a relatively small amount
- for i, tx := range txs {
+ for i, tx := range filteredTx {
latestAttemptHash := tx.TxAttempts[0].Hash
var result map[string]interface{}
txReqs[i] = rpc.BatchElem{
diff --git a/core/chains/evm/txmgr/stuck_tx_detector_test.go b/core/chains/evm/txmgr/stuck_tx_detector_test.go
index e980527c989..5e022091a67 100644
--- a/core/chains/evm/txmgr/stuck_tx_detector_test.go
+++ b/core/chains/evm/txmgr/stuck_tx_detector_test.go
@@ -73,13 +73,13 @@ func TestStuckTxDetector_LoadPurgeBlockNumMap(t *testing.T) {
feeEstimator := gasmocks.NewEvmFeeEstimator(t)
marketGasPrice := assets.GWei(15)
fee := gas.EvmFee{Legacy: marketGasPrice}
- feeEstimator.On("GetFee", mock.Anything, []byte{}, uint64(0), mock.Anything).Return(fee, uint64(0), nil)
+ feeEstimator.On("GetFee", mock.Anything, []byte{}, uint64(0), mock.Anything, mock.Anything).Return(fee, uint64(0), nil)
autoPurgeThreshold := uint32(5)
autoPurgeMinAttempts := uint32(3)
autoPurgeCfg := testAutoPurgeConfig{
enabled: true, // Enable auto-purge feature for testing
- threshold: autoPurgeThreshold,
- minAttempts: autoPurgeMinAttempts,
+ threshold: &autoPurgeThreshold,
+ minAttempts: &autoPurgeMinAttempts,
}
stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), autoPurgeCfg, feeEstimator, txStore, ethClient)
@@ -155,6 +155,30 @@ func TestStuckTxDetector_FindPotentialStuckTxs(t *testing.T) {
require.NoError(t, err)
require.Len(t, stuckTxs, 0)
})
+
+ t.Run("excludes transactions with a in-progress attempt", func(t *testing.T) {
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress)
+ attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID)
+ attempt.TxFee.Legacy = assets.NewWeiI(2)
+ attempt.State = txmgrtypes.TxAttemptInProgress
+ require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt))
+ stuckTxs, err := stuckTxDetector.FindUnconfirmedTxWithLowestNonce(ctx, []common.Address{fromAddress})
+ require.NoError(t, err)
+ require.Len(t, stuckTxs, 0)
+ })
+
+ t.Run("excludes transactions with an insufficient funds attempt", func(t *testing.T) {
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress)
+ attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID)
+ attempt.TxFee.Legacy = assets.NewWeiI(2)
+ attempt.State = txmgrtypes.TxAttemptInsufficientFunds
+ require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt))
+ stuckTxs, err := stuckTxDetector.FindUnconfirmedTxWithLowestNonce(ctx, []common.Address{fromAddress})
+ require.NoError(t, err)
+ require.Len(t, stuckTxs, 0)
+ })
}
func TestStuckTxDetector_DetectStuckTransactionsHeuristic(t *testing.T) {
@@ -170,14 +194,14 @@ func TestStuckTxDetector_DetectStuckTransactionsHeuristic(t *testing.T) {
// Return 10 gwei as market gas price
marketGasPrice := tenGwei
fee := gas.EvmFee{Legacy: marketGasPrice}
- feeEstimator.On("GetFee", mock.Anything, []byte{}, uint64(0), mock.Anything).Return(fee, uint64(0), nil)
+ feeEstimator.On("GetFee", mock.Anything, []byte{}, uint64(0), mock.Anything, mock.Anything).Return(fee, uint64(0), nil)
ethClient := testutils.NewEthClientMockWithDefaultChain(t)
autoPurgeThreshold := uint32(5)
autoPurgeMinAttempts := uint32(3)
autoPurgeCfg := testAutoPurgeConfig{
enabled: true, // Enable auto-purge feature for testing
- threshold: autoPurgeThreshold,
- minAttempts: autoPurgeMinAttempts,
+ threshold: &autoPurgeThreshold,
+ minAttempts: &autoPurgeMinAttempts,
}
blockNum := int64(100)
stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), autoPurgeCfg, feeEstimator, txStore, ethClient)
@@ -271,8 +295,9 @@ func TestStuckTxDetector_DetectStuckTransactionsZkEVM(t *testing.T) {
enabled: true,
}
blockNum := int64(100)
- stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, chaintype.ChainZkEvm, assets.NewWei(assets.NewEth(100).ToInt()), autoPurgeCfg, feeEstimator, txStore, ethClient)
+
t.Run("returns empty list if no stuck transactions identified", func(t *testing.T) {
+ stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, chaintype.ChainZkEvm, assets.NewWei(assets.NewEth(100).ToInt()), autoPurgeCfg, feeEstimator, txStore, ethClient)
_, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
tx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, blockNum, tenGwei)
attempts := tx.TxAttempts[0]
@@ -292,6 +317,7 @@ func TestStuckTxDetector_DetectStuckTransactionsZkEVM(t *testing.T) {
})
t.Run("returns stuck transactions discarded by chain", func(t *testing.T) {
+ stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, chaintype.ChainZkEvm, assets.NewWei(assets.NewEth(100).ToInt()), autoPurgeCfg, feeEstimator, txStore, ethClient)
// Insert tx that will be mocked as stuck
_, fromAddress1 := cltest.MustInsertRandomKey(t, ethKeyStore)
mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress1, 1, blockNum, tenGwei)
@@ -316,6 +342,34 @@ func TestStuckTxDetector_DetectStuckTransactionsZkEVM(t *testing.T) {
// Expect only 1 tx to return as stuck due to nil eth_getTransactionByHash response
require.Len(t, txs, 1)
})
+
+ t.Run("skips stuck tx detection for transactions that do not have enough attempts", func(t *testing.T) {
+ autoPurgeCfg.minAttempts = ptr(uint32(2))
+ stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, chaintype.ChainZkEvm, assets.NewWei(assets.NewEth(100).ToInt()), autoPurgeCfg, feeEstimator, txStore, ethClient)
+ // Insert tx with enough attempts for detection
+ _, fromAddress1 := cltest.MustInsertRandomKey(t, ethKeyStore)
+ etx1 := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress1, 1, blockNum, tenGwei)
+ attempt := cltest.NewLegacyEthTxAttempt(t, etx1.ID)
+ attempt.TxFee.Legacy = assets.NewWeiI(2)
+ attempt.State = txmgrtypes.TxAttemptBroadcast
+ require.NoError(t, txStore.InsertTxAttempt(ctx, &attempt))
+
+ // Insert tx that will be skipped for too few attempts
+ _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore)
+ mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress2, 1, blockNum, tenGwei)
+
+ // Return nil response for a tx and a normal response for the other
+ ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool {
+ return len(b) == 1
+ })).Return(nil).Run(func(args mock.Arguments) {
+ elems := args.Get(1).([]rpc.BatchElem)
+ elems[0].Result = nil // Return nil to signal discarded tx
+ }).Once()
+
+ txs, err := stuckTxDetector.DetectStuckTransactions(ctx, []common.Address{fromAddress1, fromAddress2}, blockNum)
+ require.NoError(t, err)
+ require.Len(t, txs, 1)
+ })
}
func TestStuckTxDetector_DetectStuckTransactionsScroll(t *testing.T) {
@@ -423,12 +477,12 @@ func mustInsertUnconfirmedEthTxWithBroadcastPurgeAttempt(t *testing.T, txStore t
type testAutoPurgeConfig struct {
enabled bool
- threshold uint32
- minAttempts uint32
+ threshold *uint32
+ minAttempts *uint32
detectionApiUrl *url.URL
}
func (t testAutoPurgeConfig) Enabled() bool { return t.enabled }
-func (t testAutoPurgeConfig) Threshold() uint32 { return t.threshold }
-func (t testAutoPurgeConfig) MinAttempts() uint32 { return t.minAttempts }
+func (t testAutoPurgeConfig) Threshold() *uint32 { return t.threshold }
+func (t testAutoPurgeConfig) MinAttempts() *uint32 { return t.minAttempts }
func (t testAutoPurgeConfig) DetectionApiUrl() *url.URL { return t.detectionApiUrl }
diff --git a/core/chains/evm/txmgr/test_helpers.go b/core/chains/evm/txmgr/test_helpers.go
index 3b3584a988b..3dea0243520 100644
--- a/core/chains/evm/txmgr/test_helpers.go
+++ b/core/chains/evm/txmgr/test_helpers.go
@@ -53,6 +53,7 @@ type TestEvmConfig struct {
Threshold uint32
MinAttempts uint32
DetectionApiUrl *url.URL
+ RpcDefaultBatchSize uint32
}
func (e *TestEvmConfig) Transactions() evmconfig.Transactions {
@@ -65,6 +66,8 @@ func (e *TestEvmConfig) FinalityDepth() uint32 { return 42 }
func (e *TestEvmConfig) ChainType() chaintype.ChainType { return "" }
+func (e *TestEvmConfig) RPCDefaultBatchSize() uint32 { return e.RpcDefaultBatchSize }
+
type TestGasEstimatorConfig struct {
bumpThreshold uint64
}
@@ -89,6 +92,7 @@ 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" }
+func (g *TestGasEstimatorConfig) EstimateGasLimit() bool { return false }
func (g *TestGasEstimatorConfig) LimitJobType() evmconfig.LimitJobType {
return &TestLimitJobTypeConfig{}
}
@@ -141,10 +145,9 @@ type autoPurgeConfig struct {
func (a *autoPurgeConfig) Enabled() bool { return false }
type MockConfig struct {
- EvmConfig *TestEvmConfig
- RpcDefaultBatchSize uint32
- finalityDepth uint32
- finalityTagEnabled bool
+ EvmConfig *TestEvmConfig
+ finalityDepth uint32
+ finalityTagEnabled bool
}
func (c *MockConfig) EVM() evmconfig.EVM {
@@ -156,11 +159,10 @@ func (c *MockConfig) ChainType() chaintype.ChainType { return "" }
func (c *MockConfig) FinalityDepth() uint32 { return c.finalityDepth }
func (c *MockConfig) SetFinalityDepth(fd uint32) { c.finalityDepth = fd }
func (c *MockConfig) FinalityTagEnabled() bool { return c.finalityTagEnabled }
-func (c *MockConfig) RPCDefaultBatchSize() uint32 { return c.RpcDefaultBatchSize }
func MakeTestConfigs(t *testing.T) (*MockConfig, *TestDatabaseConfig, *TestEvmConfig) {
db := &TestDatabaseConfig{defaultQueryTimeout: utils.DefaultQueryTimeout}
- ec := &TestEvmConfig{BumpThreshold: 42, MaxInFlight: uint32(42), MaxQueued: uint64(0), ReaperInterval: time.Duration(0), ReaperThreshold: time.Duration(0)}
+ ec := &TestEvmConfig{BumpThreshold: 42, MaxInFlight: uint32(42), MaxQueued: uint64(0), ReaperInterval: time.Duration(0), ReaperThreshold: time.Duration(0), RpcDefaultBatchSize: uint32(250)}
config := &MockConfig{EvmConfig: ec}
return config, db, ec
}
diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go
index 40df5616c99..d4bfbffd12f 100644
--- a/core/chains/evm/txmgr/txmgr_test.go
+++ b/core/chains/evm/txmgr/txmgr_test.go
@@ -85,7 +85,8 @@ func makeTestEvmTxm(
lggr,
lp,
keyStore,
- estimator)
+ estimator,
+ ht)
}
func TestTxm_SendNativeToken_DoesNotSendToZero(t *testing.T) {
@@ -489,14 +490,20 @@ func TestTxm_Lifecycle(t *testing.T) {
config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t)
config.SetFinalityDepth(uint32(42))
- config.RpcDefaultBatchSize = uint32(4)
+ evmConfig.RpcDefaultBatchSize = uint32(4)
evmConfig.ResendAfterThreshold = 1 * time.Hour
evmConfig.ReaperThreshold = 1 * time.Hour
evmConfig.ReaperInterval = 1 * time.Hour
kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return([]common.Address{}, nil)
+ head := cltest.Head(42)
+ finalizedHead := cltest.Head(0)
+
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil).Once()
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(finalizedHead, nil).Once()
+
keyChangeCh := make(chan struct{})
unsub := cltest.NewAwaiter()
kst.On("SubscribeToKeyChanges", mock.Anything).Return(keyChangeCh, unsub.ItHappened)
@@ -505,7 +512,6 @@ func TestTxm_Lifecycle(t *testing.T) {
txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst)
require.NoError(t, err)
- head := cltest.Head(42)
// It should not hang or panic
txm.OnNewLongestChain(tests.Context(t), head)
@@ -607,8 +613,21 @@ func TestTxm_GetTransactionStatus(t *testing.T) {
gcfg := configtest.NewTestGeneralConfig(t)
cfg := evmtest.NewChainScopedConfig(t, gcfg)
+ head := &evmtypes.Head{
+ Hash: utils.NewHash(),
+ Number: 100,
+ Parent: &evmtypes.Head{
+ Hash: utils.NewHash(),
+ Number: 99,
+ IsFinalized: true,
+ },
+ }
+
ethClient := evmtest.NewEthClientMockWithDefaultChain(t)
ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil).Maybe()
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil).Once()
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head.Parent, nil).Once()
+ ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil)
feeEstimator := gasmocks.NewEvmFeeEstimator(t)
feeEstimator.On("Start", mock.Anything).Return(nil).Once()
feeEstimator.On("Close", mock.Anything).Return(nil).Once()
@@ -617,15 +636,6 @@ func TestTxm_GetTransactionStatus(t *testing.T) {
require.NoError(t, err)
servicetest.Run(t, txm)
- head := &evmtypes.Head{
- Hash: utils.NewHash(),
- Number: 100,
- Parent: &evmtypes.Head{
- Hash: utils.NewHash(),
- Number: 99,
- IsFinalized: true,
- },
- }
txm.OnNewLongestChain(ctx, head)
t.Run("returns error if transaction not found", func(t *testing.T) {
@@ -671,7 +681,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) {
require.Equal(t, commontypes.Unknown, state)
})
- t.Run("returns unconfirmed for unconfirmed state", func(t *testing.T) {
+ t.Run("returns pending for unconfirmed state", func(t *testing.T) {
idempotencyKey := uuid.New().String()
_, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
nonce := evmtypes.Nonce(0)
@@ -690,7 +700,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) {
require.NoError(t, err)
state, err := txm.GetTransactionStatus(ctx, idempotencyKey)
require.NoError(t, err)
- require.Equal(t, commontypes.Unconfirmed, state)
+ require.Equal(t, commontypes.Pending, state)
})
t.Run("returns unconfirmed for confirmed state", func(t *testing.T) {
@@ -715,14 +725,43 @@ func TestTxm_GetTransactionStatus(t *testing.T) {
attempt := cltest.NewLegacyEthTxAttempt(t, tx.ID)
err = txStore.InsertTxAttempt(ctx, &attempt)
require.NoError(t, err)
- // Insert receipt for finalized block num
- mustInsertEthReceipt(t, txStore, head.Parent.Number, head.ParentHash, attempt.Hash)
+ // Insert receipt for unfinalized block num
+ mustInsertEthReceipt(t, txStore, head.Number, head.Hash, attempt.Hash)
state, err := txm.GetTransactionStatus(ctx, idempotencyKey)
require.NoError(t, err)
require.Equal(t, commontypes.Unconfirmed, state)
})
- t.Run("returns unconfirmed for confirmed missing receipt state", func(t *testing.T) {
+ t.Run("returns finalized for finalized state", func(t *testing.T) {
+ idempotencyKey := uuid.New().String()
+ _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ nonce := evmtypes.Nonce(0)
+ broadcast := time.Now()
+ tx := &txmgr.Tx{
+ Sequence: &nonce,
+ IdempotencyKey: &idempotencyKey,
+ FromAddress: fromAddress,
+ EncodedPayload: []byte{1, 2, 3},
+ FeeLimit: feeLimit,
+ State: txmgrcommon.TxFinalized,
+ BroadcastAt: &broadcast,
+ InitialBroadcastAt: &broadcast,
+ }
+ err := txStore.InsertTx(ctx, tx)
+ require.NoError(t, err)
+ tx, err = txStore.FindTxWithIdempotencyKey(ctx, idempotencyKey, testutils.FixtureChainID)
+ require.NoError(t, err)
+ attempt := cltest.NewLegacyEthTxAttempt(t, tx.ID)
+ err = txStore.InsertTxAttempt(ctx, &attempt)
+ require.NoError(t, err)
+ // Insert receipt for finalized block num
+ mustInsertEthReceipt(t, txStore, head.Parent.Number, head.Parent.Hash, attempt.Hash)
+ state, err := txm.GetTransactionStatus(ctx, idempotencyKey)
+ require.NoError(t, err)
+ require.Equal(t, commontypes.Finalized, state)
+ })
+
+ t.Run("returns pending for confirmed missing receipt state", func(t *testing.T) {
idempotencyKey := uuid.New().String()
_, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
nonce := evmtypes.Nonce(0)
@@ -741,12 +780,13 @@ func TestTxm_GetTransactionStatus(t *testing.T) {
require.NoError(t, err)
state, err := txm.GetTransactionStatus(ctx, idempotencyKey)
require.NoError(t, err)
- require.Equal(t, commontypes.Unconfirmed, state)
+ require.Equal(t, commontypes.Pending, state)
})
t.Run("returns fatal for fatal error state with terminally stuck error", func(t *testing.T) {
idempotencyKey := uuid.New().String()
_, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
+ // Test the internal terminally stuck error returns Fatal
nonce := evmtypes.Nonce(0)
broadcast := time.Now()
tx := &txmgr.Tx{
@@ -764,7 +804,30 @@ func TestTxm_GetTransactionStatus(t *testing.T) {
require.NoError(t, err)
state, err := txm.GetTransactionStatus(ctx, idempotencyKey)
require.Equal(t, commontypes.Fatal, state)
- require.Error(t, err, evmclient.TerminallyStuckMsg)
+ require.Error(t, err)
+ require.Equal(t, evmclient.TerminallyStuckMsg, err.Error())
+
+ // Test a terminally stuck client error returns Fatal
+ nonce = evmtypes.Nonce(1)
+ idempotencyKey = uuid.New().String()
+ terminallyStuckClientError := "failed to add tx to the pool: not enough step counters to continue the execution"
+ tx = &txmgr.Tx{
+ Sequence: &nonce,
+ IdempotencyKey: &idempotencyKey,
+ FromAddress: fromAddress,
+ EncodedPayload: []byte{1, 2, 3},
+ FeeLimit: feeLimit,
+ State: txmgrcommon.TxFatalError,
+ Error: null.NewString(terminallyStuckClientError, true),
+ BroadcastAt: &broadcast,
+ InitialBroadcastAt: &broadcast,
+ }
+ err = txStore.InsertTx(ctx, tx)
+ require.NoError(t, err)
+ state, err = txm.GetTransactionStatus(ctx, idempotencyKey)
+ require.Equal(t, commontypes.Fatal, state)
+ require.Error(t, err)
+ require.Equal(t, terminallyStuckClientError, err.Error())
})
t.Run("returns failed for fatal error state with other error", func(t *testing.T) {
@@ -1018,6 +1081,12 @@ func mustCreateUnstartedTxFromEvmTxRequest(t testing.TB, txStore txmgr.EvmTxStor
return tx
}
+func mustInsertUnstartedTx(t testing.TB, txStore txmgr.TestEvmTxStore, fromAddress common.Address) {
+ etx := cltest.NewEthTx(fromAddress)
+ ctx := tests.Context(t)
+ require.NoError(t, txStore.InsertTx(ctx, &etx))
+}
+
func txRequestWithStrategy(strategy txmgrtypes.TxStrategy) func(*txmgr.TxRequest) {
return func(tx *txmgr.TxRequest) {
tx.Strategy = strategy
diff --git a/core/chains/evm/types/types.go b/core/chains/evm/types/types.go
index 57a53bce67a..c834ffeb866 100644
--- a/core/chains/evm/types/types.go
+++ b/core/chains/evm/types/types.go
@@ -63,6 +63,7 @@ type Receipt struct {
BlockHash common.Hash `json:"blockHash,omitempty"`
BlockNumber *big.Int `json:"blockNumber,omitempty"`
TransactionIndex uint `json:"transactionIndex"`
+ RevertReason []byte `json:"revertReason,omitempty"` // Only provided by Hedera
}
// FromGethReceipt converts a gethTypes.Receipt to a Receipt
@@ -86,6 +87,7 @@ func FromGethReceipt(gr *gethTypes.Receipt) *Receipt {
gr.BlockHash,
gr.BlockNumber,
gr.TransactionIndex,
+ nil,
}
}
@@ -119,6 +121,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
BlockHash common.Hash `json:"blockHash,omitempty"`
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
TransactionIndex hexutil.Uint `json:"transactionIndex"`
+ RevertReason hexutil.Bytes `json:"revertReason,omitempty"` // Only provided by Hedera
}
var enc Receipt
enc.PostState = r.PostState
@@ -132,6 +135,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
enc.BlockHash = r.BlockHash
enc.BlockNumber = (*hexutil.Big)(r.BlockNumber)
enc.TransactionIndex = hexutil.Uint(r.TransactionIndex)
+ enc.RevertReason = r.RevertReason
return json.Marshal(&enc)
}
@@ -149,6 +153,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
BlockHash *common.Hash `json:"blockHash,omitempty"`
BlockNumber *hexutil.Big `json:"blockNumber,omitempty"`
TransactionIndex *hexutil.Uint `json:"transactionIndex"`
+ RevertReason *hexutil.Bytes `json:"revertReason,omitempty"` // Only provided by Hedera
}
var dec Receipt
if err := json.Unmarshal(input, &dec); err != nil {
@@ -185,6 +190,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
if dec.TransactionIndex != nil {
r.TransactionIndex = uint(*dec.TransactionIndex)
}
+ if dec.RevertReason != nil {
+ r.RevertReason = *dec.RevertReason
+ }
return nil
}
@@ -225,6 +233,14 @@ func (r *Receipt) GetBlockHash() common.Hash {
return r.BlockHash
}
+func (r *Receipt) GetRevertReason() *string {
+ if len(r.RevertReason) == 0 {
+ return nil
+ }
+ revertReason := string(r.RevertReason)
+ return &revertReason
+}
+
type Confirmations int
const (
diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go
index 129c0318820..68ff8d4e111 100644
--- a/core/chains/legacyevm/chain.go
+++ b/core/chains/legacyevm/chain.go
@@ -247,7 +247,7 @@ func newChain(ctx context.Context, cfg *evmconfig.ChainScoped, nodes []*toml.Nod
}
// note: gas estimator is started as a part of the txm
- txm, gasEstimator, err := newEvmTxm(opts.DS, cfg.EVM(), opts.AppConfig.EVMRPCEnabled(), opts.AppConfig.Database(), opts.AppConfig.Database().Listener(), client, l, logPoller, opts)
+ txm, gasEstimator, err := newEvmTxm(opts.DS, cfg.EVM(), opts.AppConfig.EVMRPCEnabled(), opts.AppConfig.Database(), opts.AppConfig.Database().Listener(), client, l, logPoller, opts, headTracker)
if err != nil {
return nil, fmt.Errorf("failed to instantiate EvmTxm for chain with ID %s: %w", chainID.String(), err)
}
diff --git a/core/chains/legacyevm/evm_txm.go b/core/chains/legacyevm/evm_txm.go
index cecfd4ffafe..ab116749665 100644
--- a/core/chains/legacyevm/evm_txm.go
+++ b/core/chains/legacyevm/evm_txm.go
@@ -7,6 +7,7 @@ import (
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ httypes "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/txmgr"
"github.com/smartcontractkit/chainlink/v2/core/logger"
@@ -22,6 +23,7 @@ func newEvmTxm(
lggr logger.Logger,
logPoller logpoller.LogPoller,
opts ChainRelayExtenderConfig,
+ headTracker httypes.HeadTracker,
) (txm txmgr.TxManager,
estimator gas.EvmFeeEstimator,
err error,
@@ -63,7 +65,8 @@ func newEvmTxm(
lggr,
logPoller,
opts.KeyStore,
- estimator)
+ estimator,
+ headTracker)
} else {
txm = opts.GenTxManager(chainID)
}
diff --git a/core/cmd/app.go b/core/cmd/app.go
index 1ccb3da9a01..53c96980de4 100644
--- a/core/cmd/app.go
+++ b/core/cmd/app.go
@@ -168,6 +168,10 @@ func NewApp(s *Shell) *cli.App {
Usage: "Prints a health report",
Action: s.Health,
Flags: []cli.Flag{
+ cli.BoolFlag{
+ Name: "failing, f",
+ Usage: "filter for failing services",
+ },
cli.BoolFlag{
Name: "json, j",
Usage: "json output",
diff --git a/core/cmd/shell.go b/core/cmd/shell.go
index 3d055bb03a9..5c864b82cd0 100644
--- a/core/cmd/shell.go
+++ b/core/cmd/shell.go
@@ -208,6 +208,13 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G
}
initOps = append(initOps, chainlink.InitStarknet(ctx, relayerFactory, starkCfg))
}
+ if cfg.AptosEnabled() {
+ aptosCfg := chainlink.AptosFactoryConfig{
+ Keystore: keyStore.Aptos(),
+ TOMLConfigs: cfg.AptosConfigs(),
+ }
+ initOps = append(initOps, chainlink.InitAptos(ctx, relayerFactory, aptosCfg))
+ }
relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...)
if err != nil {
diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go
index e19cc485d8b..604daf75683 100644
--- a/core/cmd/shell_local.go
+++ b/core/cmd/shell_local.go
@@ -435,6 +435,9 @@ func (s *Shell) runNode(c *cli.Context) error {
if s.Config.StarkNetEnabled() {
enabledChains = append(enabledChains, chaintype.StarkNet)
}
+ if s.Config.AptosEnabled() {
+ enabledChains = append(enabledChains, chaintype.Aptos)
+ }
err2 := app.GetKeyStore().OCR2().EnsureKeys(rootCtx, enabledChains...)
if err2 != nil {
return errors.Wrap(err2, "failed to ensure ocr key")
@@ -464,6 +467,12 @@ func (s *Shell) runNode(c *cli.Context) error {
return errors.Wrap(err2, "failed to ensure starknet key")
}
}
+ if s.Config.AptosEnabled() {
+ err2 := app.GetKeyStore().Aptos().EnsureKey(rootCtx)
+ if err2 != nil {
+ return errors.Wrap(err2, "failed to ensure aptos key")
+ }
+ }
err2 := app.GetKeyStore().CSA().EnsureKey(rootCtx)
if err2 != nil {
@@ -669,7 +678,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) {
feeCfg := txmgr.NewEvmTxmFeeConfig(chain.Config().EVM().GasEstimator())
stuckTxDetector := txmgr.NewStuckTxDetector(lggr, ethClient.ConfiguredChainID(), "", assets.NewWei(assets.NewEth(100).ToInt()), chain.Config().EVM().Transactions().AutoPurge(), nil, orm, ethClient)
ec := txmgr.NewEvmConfirmer(orm, txmgr.NewEvmTxmClient(ethClient, chain.Config().EVM().NodePool().Errors()),
- cfg, feeCfg, chain.Config().EVM().Transactions(), app.GetConfig().Database(), keyStore.Eth(), txBuilder, chain.Logger(), stuckTxDetector)
+ cfg, feeCfg, chain.Config().EVM().Transactions(), app.GetConfig().Database(), keyStore.Eth(), txBuilder, chain.Logger(), stuckTxDetector, chain.HeadTracker())
totalNonces := endingNonce - beginningNonce + 1
nonces := make([]evmtypes.Nonce, totalNonces)
for i := int64(0); i < totalNonces; i++ {
diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go
index 60545269e29..8ed48dcaa20 100644
--- a/core/cmd/shell_local_test.go
+++ b/core/cmd/shell_local_test.go
@@ -11,9 +11,8 @@ import (
commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
"github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
- "github.com/smartcontractkit/chainlink/v2/core/capabilities"
-
"github.com/smartcontractkit/chainlink/v2/common/client"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
"github.com/smartcontractkit/chainlink/v2/core/cmd"
cmdMocks "github.com/smartcontractkit/chainlink/v2/core/cmd/mocks"
diff --git a/core/cmd/shell_remote.go b/core/cmd/shell_remote.go
index aab4a94da6f..0aa3f3837dc 100644
--- a/core/cmd/shell_remote.go
+++ b/core/cmd/shell_remote.go
@@ -517,7 +517,11 @@ func (s *Shell) Health(c *cli.Context) error {
if c.Bool("json") {
mime = gin.MIMEJSON
}
- resp, err := s.HTTP.Get(s.ctx(), "/health", map[string]string{"Accept": mime})
+ u := "/health"
+ if c.Bool("failing") {
+ u += "?failing"
+ }
+ resp, err := s.HTTP.Get(s.ctx(), u, map[string]string{"Accept": mime})
if err != nil {
return s.errorOut(err)
}
diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml
index 38c8cb8354f..b9a256ddf4d 100644
--- a/core/config/docs/chains-evm.toml
+++ b/core/config/docs/chains-evm.toml
@@ -14,7 +14,7 @@ BlockBackfillDepth = 10 # Default
# BlockBackfillSkip enables skipping of very long backfills.
BlockBackfillSkip = false # Default
# ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID.
-# Available types: `arbitrum`, `celo`, `gnosis`, `kroma`, `metis`, `optimismBedrock`, `scroll`, `wemix`, `xlayer`, `zksync`
+# Available types: `arbitrum`, `celo`, `gnosis`, `hedera`, `kroma`, `metis`, `optimismBedrock`, `scroll`, `wemix`, `xlayer`, `zksync`
ChainType = 'arbitrum' # Example
# FinalityDepth is the number of blocks after which an ethereum transaction is considered "final". Note that the default is automatically set based on chain ID, so it should not be necessary to change this under normal operation.
# BlocksConsideredFinal determines how deeply we look back to ensure that transactions are confirmed onto the longest chain
@@ -97,6 +97,11 @@ RPCBlockQueryDelay = 1 # Default
# Block 64 will be treated as finalized by CL Node only when chain's latest finalized block is 65. As chain finalizes blocks in batches of 32,
# CL Node has to wait for a whole new batch to be finalized to treat block 64 as finalized.
FinalizedBlockOffset = 0 # Default
+# NoNewFinalizedHeadsThreshold controls how long to wait for new finalized block before `NodePool` marks rpc endpoints as
+# out-of-sync. Only applicable if `FinalityTagEnabled=true`
+#
+# Set to zero to disable.
+NoNewFinalizedHeadsThreshold = '0' # Default
[EVM.Transactions]
# ForwardersEnabled enables or disables sending transactions through forwarder contracts.
@@ -188,6 +193,8 @@ LimitMax = 500_000 # Default
LimitMultiplier = '1.0' # Default
# LimitTransfer is the gas limit used for an ordinary ETH transfer.
LimitTransfer = 21_000 # Default
+# EstimateGasLimit enables estimating gas limits for transactions. This feature respects the gas limit provided during transaction creation as an upper bound.
+EstimateGasLimit = false # Default
# BumpMin is the minimum fixed amount of wei by which gas is bumped on each transaction attempt.
BumpMin = '5 gwei' # Default
# BumpPercent is the percentage by which to bump gas on a transaction that has exceeded `BumpThreshold`. The larger of `BumpPercent` and `BumpMin` is taken for gas bumps.
diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml
index d1b922cf291..d0960779c6c 100644
--- a/core/config/docs/core.toml
+++ b/core/config/docs/core.toml
@@ -13,6 +13,8 @@ FeedsManager = true # Default
LogPoller = false # Default
# UICSAKeys enables CSA Keys in the UI.
UICSAKeys = false # Default
+# CCIP enables the CCIP service.
+CCIP = true # Default
[Database]
# DefaultIdleInTxSessionTimeout is the maximum time allowed for a transaction to be open and idle before timing out. See Postgres `idle_in_transaction_session_timeout` for more details.
diff --git a/core/config/toml/types.go b/core/config/toml/types.go
index f827f086225..0c91ddd81a9 100644
--- a/core/config/toml/types.go
+++ b/core/config/toml/types.go
@@ -303,6 +303,7 @@ type Feature struct {
FeedsManager *bool
LogPoller *bool
UICSAKeys *bool
+ CCIP *bool
}
func (f *Feature) setFrom(f2 *Feature) {
@@ -315,6 +316,9 @@ func (f *Feature) setFrom(f2 *Feature) {
if v := f2.UICSAKeys; v != nil {
f.UICSAKeys = v
}
+ if v := f2.CCIP; v != nil {
+ f.CCIP = v
+ }
}
type Database struct {
diff --git a/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go b/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go
new file mode 100644
index 00000000000..e5cb17ded07
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/arm_contract/arm_contract.go
@@ -0,0 +1,2849 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arm_contract
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type IRMNTaggedRoot struct {
+ CommitStore common.Address
+ Root [32]byte
+}
+
+type RMNConfig struct {
+ Voters []RMNVoter
+ BlessWeightThreshold uint16
+ CurseWeightThreshold uint16
+}
+
+type RMNOwnerUnvoteToCurseRequest struct {
+ CurseVoteAddr common.Address
+ Unit RMNUnvoteToCurseRequest
+ ForceUnvote bool
+}
+
+type RMNRecordedCurseRelatedOp struct {
+ Tag uint8
+ BlockTimestamp uint64
+ Cursed bool
+ CurseVoteAddr common.Address
+ Subject [16]byte
+ CurseId [16]byte
+}
+
+type RMNUnvoteToCurseRequest struct {
+ Subject [16]byte
+ CursesHash [28]byte
+}
+
+type RMNVoter struct {
+ BlessVoteAddr common.Address
+ CurseVoteAddr common.Address
+ BlessWeight uint8
+ CurseWeight uint8
+}
+
+var ARMContractMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"}],\"name\":\"ReusedCurseId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SubjectsMustBeStrictlyIncreasing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"}],\"name\":\"UnauthorizedVoter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnvoteToCurseNoop\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VoteToBlessForbiddenDuringActiveGlobalCurse\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VoteToBlessNoop\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VoteToCurseNoop\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"AlreadyBlessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"AlreadyVotedToBless\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"CurseLifted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"blockTimestamp\",\"type\":\"uint64\"}],\"name\":\"Cursed\",\"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\":\"commitStore\",\"type\":\"address\"}],\"name\":\"PermaBlessedCommitStoreAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"}],\"name\":\"PermaBlessedCommitStoreRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"bytes28\",\"name\":\"onchainCursesHash\",\"type\":\"bytes28\"},{\"indexed\":false,\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"}],\"name\":\"SkippedUnvoteToCurse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"wasBlessed\",\"type\":\"bool\"}],\"name\":\"TaggedRootBlessVotesReset\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"TaggedRootBlessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"remainingAccumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"UnvotedToCurse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"}],\"name\":\"VotedToBless\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"voter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"weight\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"blockTimestamp\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"}],\"name\":\"VotedToCurse\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"getBlessProgress\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"blessVoteAddrs\",\"type\":\"address[]\"},{\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"blessed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"getCurseProgress\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"curseVoteAddrs\",\"type\":\"address[]\"},{\"internalType\":\"bytes28[]\",\"name\":\"cursesHashes\",\"type\":\"bytes28[]\"},{\"internalType\":\"uint16\",\"name\":\"accumulatedWeight\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"cursed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCursedSubjectsCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPermaBlessedCommitStores\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"}],\"name\":\"getRecordedCurseRelatedOps\",\"outputs\":[{\"components\":[{\"internalType\":\"enumRMN.RecordedCurseRelatedOpTag\",\"name\":\"tag\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"blockTimestamp\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"cursed\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"}],\"internalType\":\"structRMN.RecordedCurseRelatedOp[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRecordedCurseRelatedOpsCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isCursed\",\"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\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"},{\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"name\":\"ownerCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"ownerRemoveThenAddPermaBlessedCommitStores\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot[]\",\"name\":\"taggedRoots\",\"type\":\"tuple[]\"}],\"name\":\"ownerResetBlessVotes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"}],\"internalType\":\"structRMN.UnvoteToCurseRequest\",\"name\":\"unit\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"forceUnvote\",\"type\":\"bool\"}],\"internalType\":\"structRMN.OwnerUnvoteToCurseRequest[]\",\"name\":\"ownerUnvoteToCurseRequests\",\"type\":\"tuple[]\"}],\"name\":\"ownerUnvoteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"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\":[{\"components\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"},{\"internalType\":\"bytes28\",\"name\":\"cursesHash\",\"type\":\"bytes28\"}],\"internalType\":\"structRMN.UnvoteToCurseRequest[]\",\"name\":\"unvoteToCurseRequests\",\"type\":\"tuple[]\"}],\"name\":\"unvoteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot[]\",\"name\":\"taggedRoots\",\"type\":\"tuple[]\"}],\"name\":\"voteToBless\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"curseId\",\"type\":\"bytes16\"},{\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"name\":\"voteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60806040523480156200001157600080fd5b506040516200596238038062005962833981016040819052620000349162000aff565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000138565b505060408051608081018252600080825260208201819052918101919091526001600160c81b03606082015290506001620000fb81601062000c7d565b82606001516001600160c81b0316901c6001600160c81b0316101562000125576200012562000c99565b506200013181620001e3565b5062000e14565b336001600160a01b03821603620001925760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001ee816200071d565b6200020c576040516306b7c75960e31b815260040160405180910390fd5b602081015160038054604084015161ffff908116620100000263ffffffff199092169316929092179190911790555b60025415620003465760028054600091906200025a9060019062000c7d565b815481106200026d576200026d62000caf565b6000918252602080832060408051608081018252600294850290920180546001600160a01b0390811680855260019092015480821685870190815260ff600160a01b8304811687870152600160a81b909204909116606086015291875260058552828720805465ffffffffffff19169055905116855260099092529220805461ffff191690558054919250908062000309576200030962000cc5565b60008281526020902060026000199092019182020180546001600160a01b031916815560010180546001600160b01b03191690559055506200023b565b60005b81515181101562000403578151805160029190839081106200036f576200036f62000caf565b602090810291909101810151825460018181018555600094855293839020825160029092020180546001600160a01b039283166001600160a01b0319909116178155928201519284018054604084015160609094015160ff908116600160a81b0260ff60a81b1991909516600160a01b026001600160a81b0319909216959093169490941793909317161790550162000349565b50600480546000906200041c9063ffffffff1662000cdb565b82546101009290920a63ffffffff8181021990931691831602179091556004541660005b82515160ff821610156200054157600083600001518260ff16815181106200046c576200046c62000caf565b602090810291909101810151604080516060808201835263ffffffff80891683528385015160ff90811684880190815289821685870190815287516001600160a01b03908116600090815260058b5288812097518854945193518616650100000000000260ff60281b199487166401000000000264ffffffffff1990961691909716179390931791909116939093179094558587015190911683526009909552919020805491909201519092166101000261ffff1990921691909117600117905550620005398162000d01565b905062000440565b506001600160a01b0360005260096020527f3bddde647ecb7992f4c710d4e1d59d07614508581f7c22c879a79d28544538a7805461ffff191660011790556004805463ffffffff4381166401000000000263ffffffff60201b1990921691909117909155604051908216907f8c49fda8177c5c8c768eb39634bc6773695c7181711537b822451c12b2efd2a990620005db90859062000d23565b60405180910390a26040805160c08101825260048082526001600160401b03421660208301526000928201839052606082018390526080820183905260a08201839052600c80546001808201835591909452825160029094027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7018054939490939092849260ff19909216919084908111156200067c576200067c62000dce565b021790555060208201518154604084015160608501516001600160a01b03166a010000000000000000000002600160501b600160f01b031991151569010000000000000000000260ff60481b196001600160401b039095166101000294909416610100600160501b031990931692909217929092179190911617815560808083015160a090930151811c600160801b0292901c919091176001909101555050565b80515160009015806200073257508151516010105b80620007445750602082015161ffff16155b80620007565750604082015161ffff16155b156200076457506000919050565b600080600084600001515160026200077d919062000de4565b6001600160401b0381111562000797576200079762000a24565b604051908082528060200260200182016040528015620007c1578160200160208202803683370190505b50905060005b8551518110156200095457600086600001518281518110620007ed57620007ed62000caf565b6020026020010151905060006001600160a01b031681600001516001600160a01b0316148062000828575060208101516001600160a01b0316155b806200083f575060208101516001600160a01b0316155b8062000858575060208101516001600160a01b03908116145b806200087a5750604081015160ff161580156200087a5750606081015160ff16155b156200088d575060009695505050505050565b8051836200089d84600262000de4565b620008aa90600062000dfe565b81518110620008bd57620008bd62000caf565b6001600160a01b0390921660209283029190910182015281015183620008e584600262000de4565b620008f290600162000dfe565b8151811062000905576200090562000caf565b6001600160a01b03909216602092830291909101909101526040810151620009319060ff168662000dfe565b9450806060015160ff168462000948919062000dfe565b935050600101620007c7565b5060005b8151811015620009f957600082828151811062000979576200097962000caf565b60200260200101519050600082600162000994919062000dfe565b90505b8351811015620009ee57838181518110620009b657620009b662000caf565b60200260200101516001600160a01b0316826001600160a01b031603620009e557506000979650505050505050565b60010162000997565b505060010162000958565b50846020015161ffff16831015801562000a1b5750846040015161ffff168210155b95945050505050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b038111828210171562000a5f5762000a5f62000a24565b60405290565b604051608081016001600160401b038111828210171562000a5f5762000a5f62000a24565b604051601f8201601f191681016001600160401b038111828210171562000ab55762000ab562000a24565b604052919050565b80516001600160a01b038116811462000ad557600080fd5b919050565b805160ff8116811462000ad557600080fd5b805161ffff8116811462000ad557600080fd5b6000602080838503121562000b1357600080fd5b82516001600160401b038082111562000b2b57600080fd5b8185019150606080838803121562000b4257600080fd5b62000b4c62000a3a565b83518381111562000b5c57600080fd5b8401601f8101891362000b6e57600080fd5b80518481111562000b835762000b8362000a24565b62000b93878260051b0162000a8a565b818152878101955060079190911b82018701908a82111562000bb457600080fd5b918701915b8183101562000c33576080838c03121562000bd45760008081fd5b62000bde62000a65565b62000be98462000abd565b815262000bf889850162000abd565b89820152604062000c0b81860162000ada565b9082015262000c1c84870162000ada565b818701528652948701946080929092019162000bb9565b83525062000c45905084860162000aec565b8582015262000c576040850162000aec565b6040820152979650505050505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111562000c935762000c9362000c67565b92915050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b600063ffffffff80831681810362000cf75762000cf762000c67565b6001019392505050565b600060ff821660ff810362000d1a5762000d1a62000c67565b60010192915050565b60006020808352608080840185516060808588015282825180855260a0890191508684019450600093505b8084101562000da157845180516001600160a01b03908116845288820151168884015260408082015160ff9081169185019190915290840151168383015293860193600193909301929085019062000d4e565b509488015161ffff8116604089015294604089015161ffff811660608a0152955098975050505050505050565b634e487b7160e01b600052602160045260246000fd5b808202811582820484141762000c935762000c9362000c67565b8082018082111562000c935762000c9362000c67565b614b3e8062000e246000396000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c8063631ec73e116100d8578063979986111161008c578063d927f26711610066578063d927f26714610354578063f2fde38b14610374578063f33f28951461038757600080fd5b8063979986111461030b578063ba86a1f01461031e578063bd147ef41461033157600080fd5b806379ba5097116100bd57806379ba5097146102d35780638da5cb5b146102db578063970b8fc21461030357600080fd5b8063631ec73e146102ad5780636ba0526d146102c057600080fd5b8063397796f71161013a5780634102e4f4116101145780634102e4f4146102745780634d61677114610287578063586abe3c1461029a57600080fd5b8063397796f7146102425780633d0cf6101461024a5780633f42ab731461025d57600080fd5b8063181f5a771161016b578063181f5a77146101ba5780632cbc26bb14610203578063328d716c1461022657600080fd5b80630b009be21461018757806315c65588146101a5575b600080fd5b61018f6103a9565b60405161019c9190613e3f565b60405180910390f35b6101b86101b3366004613fdd565b6103ba565b005b6101f66040518060400160405280600d81526020017f524d4e20312e352e302d6465760000000000000000000000000000000000000081525081565b60405161019c9190614083565b6102166102113660046140f0565b6104e6565b604051901515815260200161019c565b600b5467ffffffffffffffff165b60405190815260200161019c565b6102166105b1565b6101b86102583660046141a0565b61068b565b6102656107ff565b60405161019c939291906142b3565b6101b86102823660046142ff565b610929565b610216610295366004614439565b61093d565b6101b86102a8366004614451565b6109cd565b6101b86102bb3660046144fc565b610a87565b6101b86102ce366004614451565b610ca0565b6101b8610d13565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019c565b600c54610234565b6101b86103193660046145d0565b610e10565b6101b861032c3660046145d0565b611368565b61034461033f3660046140f0565b61150d565b60405161019c9493929190614645565b6103676103623660046146b6565b611946565b60405161019c9190614707565b6101b8610382366004614800565b611b68565b61039a610395366004614439565b611b79565b60405161019c9392919061481b565b60606103b56007611de1565b905090565b336000818152600960205260409020805460ff16610421576040517f85412e7f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024015b60405180910390fd5b60045463ffffffff166000805b85518110156104a757600086828151811061044b5761044b614849565b602002602001015190506000610465858360000151611df5565b905060008061047b6001888b8760008d89611fd6565b91509150801561048d5761048d614878565b85806104965750815b95505050505080600101905061042e565b50806104df576040517ffb106b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b600b5460009067ffffffffffffffff16810361050457506000919050565b7f0100000000000000000000000000000100000000000000000000000000000000600052600a6020527fcf943f0e419056430919a3fdfd72276bc0b123ebdd670f4152b82bffbfb8bb385468010000000000000000900460ff16806105a657507fffffffffffffffffffffffffffffffff0000000000000000000000000000000082166000908152600a602052604090205468010000000000000000900460ff165b92915050565b919050565b600b5460009067ffffffffffffffff1681036105cd5750600090565b7f0100000000000000000000000000000100000000000000000000000000000000600052600a6020527fcf943f0e419056430919a3fdfd72276bc0b123ebdd670f4152b82bffbfb8bb385468010000000000000000900460ff16806103b55750507f0100000000000000000000000000000000000000000000000000000000000000600052600a6020527f1d4cd6d2639449a552dbfb463b59316946d78c518b3170daa4a4c217bef019ba5468010000000000000000900460ff1690565b6106936126a4565b60005b8251811015610746576106cc8382815181106106b4576106b4614849565b6020026020010151600761272790919063ffffffff16565b1561073e577fdca892154bbc36d0c05ccd01b3d0411875cb1b841fcdeebb384e5d0d6eb06b4483828151811061070457610704614849565b6020026020010151604051610735919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a15b600101610696565b5060005b81518110156107fa5761078082828151811061076857610768614849565b6020026020010151600761274990919063ffffffff16565b156107f2577f66b4b4752c65ae8cd2f3a0a48c7dc8b2118c60d5ea15514992eb2ddf56c9cb158282815181106107b8576107b8614849565b60200260200101516040516107e9919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a15b60010161074a565b505050565b6040805160608082018352808252600060208084018290528385018290526004548551600280549384028201608090810190985294810183815263ffffffff808416986401000000009094041696959194919385939192859285015b828210156108f95760008481526020908190206040805160808101825260028602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001918201549081168486015260ff740100000000000000000000000000000000000000008204811693850193909352750100000000000000000000000000000000000000000090049091166060830152908352909201910161085b565b505050908252506001919091015461ffff8082166020840152620100009091041660409091015292939192919050565b6109316126a4565b61093a8161276b565b50565b600060068161099b610954368690038601866148a7565b80516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b815260208101919091526040016000205460ff16806105a657506105a66109c56020840184614800565b600790612eef565b337fffffffffffffffffffffffff000000000000000000000000000000000000000181016109fd576109fd614878565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600960205260409020805460ff16610a75576040517f85412e7f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610418565b610a8182858584612f1e565b50505050565b610a8f6126a4565b600454600090819063ffffffff16815b8451811015610b66576000858281518110610abc57610abc614849565b602002602001015190506000610ada84836020015160000151611df5565b9050600080610b3d600087866000015187602001518860400151600960008b6000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002089611fd6565b915091508680610b4a5750815b96508780610b555750805b975050505050806001019050610a9f565b508215610c615760408051600280546080602082028401810190945260608301818152610c61948492849160009085015b82821015610c355760008481526020908190206040805160808101825260028602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001918201549081168486015260ff7401000000000000000000000000000000000000000082048116938501939093527501000000000000000000000000000000000000000000900490911660608301529083529092019101610b97565b505050908252506001919091015461ffff8082166020840152620100009091041660409091015261276b565b8180610c6a5750825b610a81576040517ffb106b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ca86126a4565b73ffffffffffffffffffffffffffffffffffffffff60005260096020527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f3bddde647ecb7992f4c710d4e1d59d07614508581f7c22c879a79d28544538a7610a8182858584612f1e565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610418565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610e397f01000000000000000000000000000001000000000000000000000000000000006104e6565b15610e70576040517fcde2d97c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600454336000908152600560209081526040918290208251606081018452905463ffffffff81811680845260ff64010000000084048116958501959095526501000000000090920490931693820193909352921691908214610f00576040517f85412e7f000000000000000000000000000000000000000000000000000000008152336004820152602401610418565b600160005b8481101561132f576000868683818110610f2157610f21614849565b905060400201803603810190610f3791906148a7565b90506000610f868280516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b6000818152600660209081526040918290208251608081018452905460ff81161580158352610100820463ffffffff169383019390935265010000000000810461ffff169382019390935267010000000000000090920478ffffffffffffffffffffffffffffffffffffffffffffffffff16606083015291925090611062573373ffffffffffffffffffffffffffffffffffffffff168763ffffffff167f274d6d5b916b0a53974b7ab86c844b97a2e03a60f658cd9a4b1c028b604d7bf18560405161105291906148e0565b60405180910390a3505050611327565b8663ffffffff16816020015163ffffffff16146110a8575060408051608081018252600080825263ffffffff89166020830152918101829052606081019190915261110c565b6110ba816060015187604001516136d6565b1561110c573373ffffffffffffffffffffffffffffffffffffffff168763ffffffff167f6dfbb745226fa630aeb1b9557d17d508ddb789a04f0cb873ec16e58beb8beead8560405161105291906148e0565b6000945061112281606001518760400151613718565b78ffffffffffffffffffffffffffffffffffffffffffffffffff166060820152602086015160408201805160ff9092169161115e90839061493c565b61ffff1690525060208681015160408051865173ffffffffffffffffffffffffffffffffffffffff168152868401519381019390935260ff9091168282015251339163ffffffff8a16917f2a08a2bd2798f0aae9a843f0f4ad4de488c1b3d5f04049940cfed736ad69fb979181900360600190a3600354604082015161ffff91821691161061125757600181526040808201518151855173ffffffffffffffffffffffffffffffffffffffff1681526020808701519082015261ffff90911681830152905163ffffffff8916917f8257378aa73bf8e4ada848713526584a3dcee0fd3db3beed7397f7a7f5067cc9919081900360600190a25b60009182526006602090815260409283902082518154928401519484015160609094015178ffffffffffffffffffffffffffffffffffffffffffffffffff166701000000000000000266ffffffffffffff61ffff90951665010000000000029490941664ffffffffff63ffffffff909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090941693909317179390931617179055505b600101610f05565b5080156104df576040517f604c767700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113706126a4565b60045463ffffffff1660005b82811015610a8157600084848381811061139857611398614849565b9050604002018036038101906113ae91906148a7565b905060006113fd8280516020918201516040805173ffffffffffffffffffffffffffffffffffffffff909316838501528281019190915280518083038201815260609092019052805191012090565b60008181526006602081815260408084208151608081018352815460ff811615158252610100810463ffffffff90811683870190815265010000000000830461ffff169584019590955267010000000000000090910478ffffffffffffffffffffffffffffffffffffffffffffffffff16606083015287875294909352939093558051925193945092878216911614806114945750805b156114fe5760408051855173ffffffffffffffffffffffffffffffffffffffff1681526020808701519082015282151581830152905163ffffffff8816917f7d15a6eebaa019ea7d5b7d38937c51ebd3befbfdf51bb630a694fd28635bbcba919081900360600190a25b5050505080600101905061137c565b600454604080516002805460806020820284018101909452606083810182815290958695600095869563ffffffff9093169486949193928492918491879085015b828210156115ec5760008481526020908190206040805160808101825260028602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001918201549081168486015260ff740100000000000000000000000000000000000000008204811693850193909352750100000000000000000000000000000000000000000090049091166060830152908352909201910161154e565b505050908252506001919091015461ffff80821660208085019190915262010000909204166040928301527fffffffffffffffffffffffffffffffff000000000000000000000000000000008a166000908152600a909152908120805460ff6801000000000000000082041696509293509163ffffffff80861691161080156116725750845b6000965090508560015b60028111611939578451515b6000808760000151518310156116e35787518051849081106116ac576116ac614849565b6020026020010151602001519150876000015183815181106116d0576116d0614849565b602002602001015160600151905061170a565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905060005b73ffffffffffffffffffffffffffffffffffffffff82166000908152600188016020908152604080832081518083019092525463ffffffff811682526401000000009004821b63ffffffff19169181019190915290878061177a57508a63ffffffff16826000015163ffffffff16145b8061179a575073ffffffffffffffffffffffffffffffffffffffff848116145b80156117b05750602082015163ffffffff191615155b9050801561186d57856001036117d0576117c987614957565b965061186d565b85600203610182576117e560ff84168e61493c565b9c506117f08761498f565b9650838f888151811061180557611805614849565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081602001518e888151811061185657611856614849565b63ffffffff19909216602092830291909101909101525b84156118835761187c8561498f565b945061188c565b50505050611895565b50505050611688565b81600103611928578267ffffffffffffffff8111156118b6576118b6613e52565b6040519080825280602002602001820160405280156118df578160200160208202803683370190505b509a508267ffffffffffffffff8111156118fb576118fb613e52565b604051908082528060200260200182016040528015611924578160200160208202803683370190505b5099505b5061193281614957565b905061167c565b5050505050509193509193565b600c5460609060009061195984866149c4565b11611965575081611988565b600c5484101561198457600c5461197d9085906149d7565b9050611988565b5060005b60008167ffffffffffffffff8111156119a3576119a3613e52565b604051908082528060200260200182016040528015611a2157816020015b6040805160c08101825260008082526020808301829052928201819052606082018190526080820181905260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816119c15790505b50905060005b82811015611b5f57600c611a3b82886149c4565b81548110611a4b57611a4b614849565b600091825260209091206040805160c081019091526002909202018054829060ff166004811115611a7e57611a7e6146d8565b6004811115611a8f57611a8f6146d8565b81528154610100810467ffffffffffffffff1660208301526901000000000000000000810460ff16151560408301526a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166060820152600190910154608081811b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000090811682850152700100000000000000000000000000000000909204901b1660a0909101528251839083908110611b4c57611b4c614849565b6020908102919091010152600101611a27565b50949350505050565b611b706126a4565b61093a8161373b565b606060008080611b91610954368790038701876148a7565b6000818152600660209081526040918290208251608081018452905460ff81161515808352610100820463ffffffff90811694840185905265010000000000830461ffff169584019590955267010000000000000090910478ffffffffffffffffffffffffffffffffffffffffffffffffff166060830152600454909650939450929091169003611dd85760408101516060820151909450611c3281613830565b60ff1667ffffffffffffffff811115611c4d57611c4d613e52565b604051908082528060200260200182016040528015611c76578160200160208202803683370190505b506002805460408051602080840282018101909252828152939950600093929190849084015b82821015611d3a5760008481526020908190206040805160808101825260028602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001918201549081168486015260ff7401000000000000000000000000000000000000000082048116938501939093527501000000000000000000000000000000000000000000900490911660608301529083529092019101611c9c565b5050505090506000805b82518160ff161015611dd357611d5a84826136d6565b15611dc357828160ff1681518110611d7457611d74614849565b602002602001015160000151898381518110611d9257611d92614849565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152611dc082614957565b91505b611dcc816149ea565b9050611d44565b505050505b50509193909250565b60606000611dee8361389f565b9392505050565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166000908152600a60205260408120805463ffffffff858116911614611dee57805463ffffffff19811663ffffffff861690811783556003547fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000909216176201000090910461ffff1664010000000002177fffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffff1680825568010000000000000000900460ff1615611dee57600260005b8154811015611fcd576000826000018281548110611ee657611ee6614849565b6000918252602080832060016002909302018281015473ffffffffffffffffffffffffffffffffffffffff1684529187019052604090912080549192509063ffffffff808a169116108015611f4d57508054640100000000900460201b63ffffffff191615155b15611fc357805463ffffffff191663ffffffff891617815560018201548554750100000000000000000000000000000000000000000090910460ff16908690600690611fa89084906601000000000000900461ffff1661493c565b92506101000a81548161ffff021916908361ffff1602179055505b5050600101611ec6565b50509392505050565b6000806001896001811115611fed57611fed6146d8565b148061200a57506000896001811115612008576120086146d8565b145b61201657612016614878565b8480612037575073ffffffffffffffffffffffffffffffffffffffff878116145b80612056575073ffffffffffffffffffffffffffffffffffffffff8716155b1561207c57600089600181111561206f5761206f6146d8565b1461207c5761207c614878565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260018401602090815260409182902082518084019093525463ffffffff811683526401000000009004811b63ffffffff191690820152845460ff16801561210d575073ffffffffffffffffffffffffffffffffffffffff888116148061210d57508863ffffffff16816000015163ffffffff16145b80156121235750602081015163ffffffff191615155b801561214b5750866020015163ffffffff1916816020015163ffffffff1916148061214b5750855b156122765773ffffffffffffffffffffffffffffffffffffffff881660009081526001858101602052604082209190915585548554919450610100900460ff169085906006906121aa9084906601000000000000900461ffff16614a09565b825461010092830a61ffff818102199092169282160291909117909255895188546020808d01518a54604080517fffffffffffffffffffffffffffffffff0000000000000000000000000000000090961686529590930460ff169184019190915263ffffffff1916828401526601000000000000900490921660608301525173ffffffffffffffffffffffffffffffffffffffff8b16925063ffffffff8c16917fa96a155bd67c927a6c056befbd979b78465e2b2f1276bf7d4e90a31d4f430aa8919081900360800190a35b6000808b600181111561228b5761228b6146d8565b1480156122b3575083806122b3575073ffffffffffffffffffffffffffffffffffffffff8916155b90508080156122cf5750845468010000000000000000900460ff165b80156122e157506122df856138fb565b155b156123b45784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555600b80546001945060009061232a9067ffffffffffffffff16614a24565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055507f65d0e78c3625f0956f58610cf0fb157eaf627683258875ef29af2f71d25ac8fd88600001516040516123ab91907fffffffffffffffffffffffffffffffff0000000000000000000000000000000091909116815260200190565b60405180910390a15b83806123bd5750825b15612605576000808c60018111156123d7576123d76146d8565b036123f25787156123ea5750600361240f565b50600261240f565b60018c6001811115612406576124066146d8565b03610182575060015b600c6040518060c0016040528083600481111561242e5761242e6146d8565b81526020014267ffffffffffffffff168152885468010000000000000000900460ff16151560208083019190915273ffffffffffffffffffffffffffffffffffffffff8e1660408301528c517fffffffffffffffffffffffffffffffff00000000000000000000000000000000166060830152600060809092018290528354600180820186559483529120825160029092020180549293909283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911690836004811115612500576125006146d8565b0217905550602082015181546040840151606085015173ffffffffffffffffffffffffffffffffffffffff166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff9115156901000000000000000000027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff67ffffffffffffffff90951661010002949094167fffffffffffffffffffffffffffffffffffffffffffff000000000000000000ff90931692909217929092179190911617815560808083015160a090930151811c7001000000000000000000000000000000000292901c9190911760019091015550612696565b8751602080840151818b0151604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000909516855263ffffffff1992831693850193909352169082015273ffffffffffffffffffffffffffffffffffffffff8a16907fbabb0d7099e6ca14a29fad2a2cfb4fda2bd30f97cb3c27e546174bfb4277c1cc9060600160405180910390a25b505097509795505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612725576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610418565b565b6000611dee8373ffffffffffffffffffffffffffffffffffffffff841661395c565b6000611dee8373ffffffffffffffffffffffffffffffffffffffff8416613a56565b61277481613aa5565b6127aa576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081015160038054604084015161ffff908116620100000263ffffffff199092169316929092179190911790555b6002541561298e5760028054600091906127f5906001906149d7565b8154811061280557612805614849565b60009182526020808320604080516080810182526002948502909201805473ffffffffffffffffffffffffffffffffffffffff90811680855260019092015480821685870190815260ff740100000000000000000000000000000000000000008304811687870152750100000000000000000000000000000000000000000090920490911660608601529187526005855282872080547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000016905590511685526009909252922080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690558054919250908061290457612904614a66565b60008281526020902060027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019182020180547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560010180547fffffffffffffffffffff000000000000000000000000000000000000000000001690559055506127d9565b60005b815151811015612ac1578151805160029190839081106129b3576129b3614849565b6020908102919091018101518254600181810185556000948552938390208251600290920201805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116178155928201519284018054604084015160609094015160ff9081167501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff9190951674010000000000000000000000000000000000000000027fffffffffffffffffffffff0000000000000000000000000000000000000000009092169590931694909417939093171617905501612991565b5060048054600090612ad89063ffffffff16614a95565b82546101009290920a63ffffffff8181021990931691831602179091556004541660005b82515160ff82161015612c5557600083600001518260ff1681518110612b2457612b24614849565b602090810291909101810151604080516060808201835263ffffffff80891683528385015160ff908116848801908152898216858701908152875173ffffffffffffffffffffffffffffffffffffffff908116600090815260058b528881209751885494519351861665010000000000027fffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffff948716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009096169190971617939093179190911693909317909455858701519091168352600990955291902080549190920151909216610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090921691909117600117905550612c4e816149ea565b9050612afc565b5073ffffffffffffffffffffffffffffffffffffffff60005260096020527f3bddde647ecb7992f4c710d4e1d59d07614508581f7c22c879a79d28544538a780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660011790556004805463ffffffff438116640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff90921691909117909155604051908216907f8c49fda8177c5c8c768eb39634bc6773695c7181711537b822451c12b2efd2a990612d2f908590614ab8565b60405180910390a26040805160c081018252600480825267ffffffffffffffff421660208301526000928201839052606082018390526080820183905260a08201839052600c80546001808201835591909452825160029094027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701805493949093909284927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090921691908490811115612dec57612dec6146d8565b0217905550602082015181546040840151606085015173ffffffffffffffffffffffffffffffffffffffff166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff9115156901000000000000000000027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff67ffffffffffffffff90951661010002949094167fffffffffffffffffffffffffffffffffffffffffffff000000000000000000ff90931692909217929092179190911617815560808083015160a090930151811c7001000000000000000000000000000000000292901c919091176001909101555050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515611dee565b8151600003612f59576040517f55e9b08b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008316600090815260018201602052604090205460ff1615613007576040517f078f340000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201527fffffffffffffffffffffffffffffffff0000000000000000000000000000000084166024820152604401610418565b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008316600090815260018281016020526040822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905560045463ffffffff16905b83518110156136ce57600181101580156130ed575083818151811061309657613096614849565b60200260200101516fffffffffffffffffffffffffffffffff1916846001836130bf91906149d7565b815181106130cf576130cf614849565b60200260200101516fffffffffffffffffffffffffffffffff191610155b15613124576040517f2432d8ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084828151811061313857613138614849565b60200260200101519050600061314e8483611df5565b73ffffffffffffffffffffffffffffffffffffffff8981166000818152600184016020908152604080832081518083019092525463ffffffff811682526401000000009004821b63ffffffff19169181019190915293945091148015906131be5750815163ffffffff8088169116105b806131d25750602082015163ffffffff1916155b15613225575085548254600091610100900460ff169084906006906132069084906601000000000000900461ffff1661493c565b92506101000a81548161ffff021916908361ffff16021790555061322c565b5060208101515b60408051808201825263ffffffff88168152815163ffffffff1984166020828101919091527fffffffffffffffffffffffffffffffff000000000000000000000000000000008d16828501528351808303850181526060909201909352805190830120909182019063ffffffff1916905273ffffffffffffffffffffffffffffffffffffffff8b166000818152600186016020908152604090912083518285015190921c6401000000000263ffffffff92831617905589549294509091908816907f8137bc8a8d712aaa27bfc6506d5566ac405618bd53f9831b8ca6b6fe5442ee7a9087908d9060ff610100909104166133234290565b6020898101518b54604080517fffffffffffffffffffffffffffffffff000000000000000000000000000000009889168152979096169287019290925260ff9093169385019390935267ffffffffffffffff16606084015263ffffffff191660808301526601000000000000900461ffff1660a082015260c00160405180910390a363ffffffff1981161580156133c85750825468010000000000000000900460ff16155b80156133d857506133d8836138fb565b156134c35782547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff1668010000000000000000178355600b80546000906134289067ffffffffffffffff16614acb565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508563ffffffff167fcfdbfd8ce9a56b5f7c202c0e102184d24f47ca87121dc165063fc4c290957bde8561347e4290565b604080517fffffffffffffffffffffffffffffffff00000000000000000000000000000000909316835267ffffffffffffffff90911660208301520160405180910390a25b6040805160c081018252600080825267ffffffffffffffff42166020830152855460ff680100000000000000009091041615159282019290925273ffffffffffffffffffffffffffffffffffffffff8c1660608201527fffffffffffffffffffffffffffffffff0000000000000000000000000000000086811660808301528b1660a0820152600c80546001808201835591909352815160029093027fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701805492939092909183917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016908360048111156135c0576135c06146d8565b0217905550602082015181546040840151606085015173ffffffffffffffffffffffffffffffffffffffff166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff9115156901000000000000000000027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff67ffffffffffffffff90951661010002949094167fffffffffffffffffffffffffffffffffffffffffffff000000000000000000ff90931692909217929092179190911617815560808083015160a090930151811c7001000000000000000000000000000000000292901c9190911760019182015594909401935061306f92505050565b505050505050565b600060108260ff16106136eb576136eb614878565b50600160ff82161b821678ffffffffffffffffffffffffffffffffffffffffffffffffff16151592915050565b600060108260ff161061372d5761372d614878565b50600160ff919091161b1790565b3373ffffffffffffffffffffffffffffffffffffffff8216036137ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610418565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006201000078ffffffffffffffffffffffffffffffffffffffffffffffffff83161061385f5761385f614878565b78ffffffffffffffffffffffffffffffffffffffffffffffffff8216156105ac5761388b600183614ae8565b90911690613898816149ea565b905061385f565b6060816000018054806020026020016040519081016040528092919081815260200182805480156138ef57602002820191906000526020600020905b8154815260200190600101908083116138db575b50505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff600090815260018201602090815260408220546401000000009004901b63ffffffff19161515806105a65750505461ffff64010000000082048116660100000000000090920416101590565b60008181526001830160205260408120548015613a455760006139806001836149d7565b8554909150600090613994906001906149d7565b90508181146139f95760008660000182815481106139b4576139b4614849565b90600052602060002001549050808760000184815481106139d7576139d7614849565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613a0a57613a0a614a66565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105a6565b60009150506105a6565b5092915050565b6000818152600183016020526040812054613a9d575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105a6565b5060006105a6565b8051516000901580613ab957508151516010105b80613aca5750602082015161ffff16155b80613adb5750604082015161ffff16155b15613ae857506000919050565b60008060008460000151516002613aff9190614b1a565b67ffffffffffffffff811115613b1757613b17613e52565b604051908082528060200260200182016040528015613b40578160200160208202803683370190505b50905060005b855151811015613d1157600086600001518281518110613b6857613b68614849565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff161480613bc95750602081015173ffffffffffffffffffffffffffffffffffffffff16155b80613bec5750602081015173ffffffffffffffffffffffffffffffffffffffff16155b80613c115750602081015173ffffffffffffffffffffffffffffffffffffffff908116145b80613c315750604081015160ff16158015613c315750606081015160ff16155b15613c43575060009695505050505050565b805183613c51846002614b1a565b613c5c9060006149c4565b81518110613c6c57613c6c614849565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015281015183613c9f846002614b1a565b613caa9060016149c4565b81518110613cba57613cba614849565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526040810151613cf19060ff16866149c4565b9450806060015160ff1684613d0691906149c4565b935050600101613b46565b5060005b8151811015613dc3576000828281518110613d3257613d32614849565b602002602001015190506000826001613d4b91906149c4565b90505b8351811015613db957838181518110613d6957613d69614849565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603613db157506000979650505050505050565b600101613d4e565b5050600101613d15565b50846020015161ffff168310158015613de45750846040015161ffff168210155b95945050505050565b60008151808452602080850194506020840160005b83811015613e3457815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613e02565b509495945050505050565b602081526000611dee6020830184613ded565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715613ea457613ea4613e52565b60405290565b6040516060810167ffffffffffffffff81118282101715613ea457613ea4613e52565b6040516080810167ffffffffffffffff81118282101715613ea457613ea4613e52565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613f3757613f37613e52565b604052919050565b600067ffffffffffffffff821115613f5957613f59613e52565b5060051b60200190565b80357fffffffffffffffffffffffffffffffff00000000000000000000000000000000811681146105ac57600080fd5b600060408284031215613fa557600080fd5b613fad613e81565b9050613fb882613f63565b8152602082013563ffffffff1981168114613fd257600080fd5b602082015292915050565b60006020808385031215613ff057600080fd5b823567ffffffffffffffff81111561400757600080fd5b8301601f8101851361401857600080fd5b803561402b61402682613f3f565b613ef0565b8082825260208201915060208360061b85010192508783111561404d57600080fd5b6020840193505b82841015614078576140668885613f93565b82528482019150604084019350614054565b979650505050505050565b60006020808352835180602085015260005b818110156140b157858101830151858201604001528201614095565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60006020828403121561410257600080fd5b611dee82613f63565b803573ffffffffffffffffffffffffffffffffffffffff811681146105ac57600080fd5b600082601f83011261414057600080fd5b8135602061415061402683613f3f565b8083825260208201915060208460051b87010193508684111561417257600080fd5b602086015b84811015614195576141888161410b565b8352918301918301614177565b509695505050505050565b600080604083850312156141b357600080fd5b823567ffffffffffffffff808211156141cb57600080fd5b6141d78683870161412f565b935060208501359150808211156141ed57600080fd5b506141fa8582860161412f565b9150509250929050565b8051606080845281518482018190526000926080916020918201918388019190865b82811015614280578451805173ffffffffffffffffffffffffffffffffffffffff908116865283820151168386015260408082015160ff908116918701919091529088015116878501529381019392850192600101614226565b508781015161ffff81168a83015295505050604086015193506142a9604088018561ffff169052565b9695505050505050565b600063ffffffff808616835280851660208401525060606040830152613de46060830184614204565b803560ff811681146105ac57600080fd5b803561ffff811681146105ac57600080fd5b6000602080838503121561431257600080fd5b823567ffffffffffffffff8082111561432a57600080fd5b8185019150606080838803121561434057600080fd5b614348613eaa565b83358381111561435757600080fd5b84019250601f8301881361436a57600080fd5b823561437861402682613f3f565b81815260079190911b8401860190868101908a83111561439757600080fd5b948701945b82861015614409576080868c0312156143b55760008081fd5b6143bd613ecd565b6143c68761410b565b81526143d389880161410b565b8982015260406143e48189016142dc565b908201526143f38787016142dc565b818701528252608095909501949087019061439c565b83525061441990508486016142ed565b85820152614429604085016142ed565b6040820152979650505050505050565b60006040828403121561444b57600080fd5b50919050565b6000806040838503121561446457600080fd5b61446d83613f63565b915060208084013567ffffffffffffffff81111561448a57600080fd5b8401601f8101861361449b57600080fd5b80356144a961402682613f3f565b81815260059190911b820183019083810190888311156144c857600080fd5b928401925b828410156144ed576144de84613f63565b825292840192908401906144cd565b80955050505050509250929050565b6000602080838503121561450f57600080fd5b823567ffffffffffffffff81111561452657600080fd5b8301601f8101851361453757600080fd5b803561454561402682613f3f565b81815260079190911b8201830190838101908783111561456457600080fd5b928401925b8284101561407857608084890312156145825760008081fd5b61458a613eaa565b6145938561410b565b81526145a189878701613f93565b86820152606085013580151581146145b95760008081fd5b604082015282526080939093019290840190614569565b600080602083850312156145e357600080fd5b823567ffffffffffffffff808211156145fb57600080fd5b818501915085601f83011261460f57600080fd5b81358181111561461e57600080fd5b8660208260061b850101111561463357600080fd5b60209290920196919550909350505050565b6080815260006146586080830187613ded565b82810360208481019190915286518083528782019282019060005b8181101561469657845163ffffffff191683529383019391830191600101614673565b505061ffff96909616604085015250505090151560609091015292915050565b600080604083850312156146c957600080fd5b50508035926020909101359150565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208082528251828201819052600091906040908185019086840185805b838110156147f2578251805160058110614766577f4e487b710000000000000000000000000000000000000000000000000000000084526021600452602484fd5b86528088015167ffffffffffffffff16888701528681015115158787015260608082015173ffffffffffffffffffffffffffffffffffffffff16908701526080808201517fffffffffffffffffffffffffffffffff000000000000000000000000000000009081169188019190915260a091820151169086015260c09094019391860191600101614725565b509298975050505050505050565b60006020828403121561481257600080fd5b611dee8261410b565b60608152600061482e6060830186613ded565b61ffff94909416602083015250901515604090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b6000604082840312156148b957600080fd5b6148c1613e81565b6148ca8361410b565b8152602083013560208201528091505092915050565b815173ffffffffffffffffffffffffffffffffffffffff16815260208083015190820152604081016105a6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b61ffff818116838216019080821115613a4f57613a4f61490d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036149885761498861490d565b5060010190565b60008161499e5761499e61490d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b808201808211156105a6576105a661490d565b818103818111156105a6576105a661490d565b600060ff821660ff8103614a0057614a0061490d565b60010192915050565b61ffff828116828216039080821115613a4f57613a4f61490d565b600067ffffffffffffffff821680614a3e57614a3e61490d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600063ffffffff808316818103614aae57614aae61490d565b6001019392505050565b602081526000611dee6020830184614204565b600067ffffffffffffffff808316818103614aae57614aae61490d565b78ffffffffffffffffffffffffffffffffffffffffffffffffff828116828216039080821115613a4f57613a4f61490d565b80820281158282048414176105a6576105a661490d56fea164736f6c6343000818000a",
+}
+
+var ARMContractABI = ARMContractMetaData.ABI
+
+var ARMContractBin = ARMContractMetaData.Bin
+
+func DeployARMContract(auth *bind.TransactOpts, backend bind.ContractBackend, config RMNConfig) (common.Address, *types.Transaction, *ARMContract, error) {
+ parsed, err := ARMContractMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ARMContractBin), backend, config)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &ARMContract{address: address, abi: *parsed, ARMContractCaller: ARMContractCaller{contract: contract}, ARMContractTransactor: ARMContractTransactor{contract: contract}, ARMContractFilterer: ARMContractFilterer{contract: contract}}, nil
+}
+
+type ARMContract struct {
+ address common.Address
+ abi abi.ABI
+ ARMContractCaller
+ ARMContractTransactor
+ ARMContractFilterer
+}
+
+type ARMContractCaller struct {
+ contract *bind.BoundContract
+}
+
+type ARMContractTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ARMContractFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ARMContractSession struct {
+ Contract *ARMContract
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ARMContractCallerSession struct {
+ Contract *ARMContractCaller
+ CallOpts bind.CallOpts
+}
+
+type ARMContractTransactorSession struct {
+ Contract *ARMContractTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ARMContractRaw struct {
+ Contract *ARMContract
+}
+
+type ARMContractCallerRaw struct {
+ Contract *ARMContractCaller
+}
+
+type ARMContractTransactorRaw struct {
+ Contract *ARMContractTransactor
+}
+
+func NewARMContract(address common.Address, backend bind.ContractBackend) (*ARMContract, error) {
+ abi, err := abi.JSON(strings.NewReader(ARMContractABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindARMContract(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContract{address: address, abi: abi, ARMContractCaller: ARMContractCaller{contract: contract}, ARMContractTransactor: ARMContractTransactor{contract: contract}, ARMContractFilterer: ARMContractFilterer{contract: contract}}, nil
+}
+
+func NewARMContractCaller(address common.Address, caller bind.ContractCaller) (*ARMContractCaller, error) {
+ contract, err := bindARMContract(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractCaller{contract: contract}, nil
+}
+
+func NewARMContractTransactor(address common.Address, transactor bind.ContractTransactor) (*ARMContractTransactor, error) {
+ contract, err := bindARMContract(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractTransactor{contract: contract}, nil
+}
+
+func NewARMContractFilterer(address common.Address, filterer bind.ContractFilterer) (*ARMContractFilterer, error) {
+ contract, err := bindARMContract(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractFilterer{contract: contract}, nil
+}
+
+func bindARMContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ARMContractMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ARMContract *ARMContractRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ARMContract.Contract.ARMContractCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ARMContract *ARMContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ARMContract.Contract.ARMContractTransactor.contract.Transfer(opts)
+}
+
+func (_ARMContract *ARMContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ARMContract.Contract.ARMContractTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ARMContract *ARMContractCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ARMContract.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ARMContract *ARMContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ARMContract.Contract.contract.Transfer(opts)
+}
+
+func (_ARMContract *ARMContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ARMContract.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ARMContract *ARMContractCaller) GetBlessProgress(opts *bind.CallOpts, taggedRoot IRMNTaggedRoot) (GetBlessProgress,
+
+ error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "getBlessProgress", taggedRoot)
+
+ outstruct := new(GetBlessProgress)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.BlessVoteAddrs = *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+ outstruct.AccumulatedWeight = *abi.ConvertType(out[1], new(uint16)).(*uint16)
+ outstruct.Blessed = *abi.ConvertType(out[2], new(bool)).(*bool)
+
+ return *outstruct, err
+
+}
+
+func (_ARMContract *ARMContractSession) GetBlessProgress(taggedRoot IRMNTaggedRoot) (GetBlessProgress,
+
+ error) {
+ return _ARMContract.Contract.GetBlessProgress(&_ARMContract.CallOpts, taggedRoot)
+}
+
+func (_ARMContract *ARMContractCallerSession) GetBlessProgress(taggedRoot IRMNTaggedRoot) (GetBlessProgress,
+
+ error) {
+ return _ARMContract.Contract.GetBlessProgress(&_ARMContract.CallOpts, taggedRoot)
+}
+
+func (_ARMContract *ARMContractCaller) GetConfigDetails(opts *bind.CallOpts) (GetConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "getConfigDetails")
+
+ outstruct := new(GetConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.Version = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.Config = *abi.ConvertType(out[2], new(RMNConfig)).(*RMNConfig)
+
+ return *outstruct, err
+
+}
+
+func (_ARMContract *ARMContractSession) GetConfigDetails() (GetConfigDetails,
+
+ error) {
+ return _ARMContract.Contract.GetConfigDetails(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCallerSession) GetConfigDetails() (GetConfigDetails,
+
+ error) {
+ return _ARMContract.Contract.GetConfigDetails(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCaller) GetCurseProgress(opts *bind.CallOpts, subject [16]byte) (GetCurseProgress,
+
+ error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "getCurseProgress", subject)
+
+ outstruct := new(GetCurseProgress)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.CurseVoteAddrs = *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+ outstruct.CursesHashes = *abi.ConvertType(out[1], new([][28]byte)).(*[][28]byte)
+ outstruct.AccumulatedWeight = *abi.ConvertType(out[2], new(uint16)).(*uint16)
+ outstruct.Cursed = *abi.ConvertType(out[3], new(bool)).(*bool)
+
+ return *outstruct, err
+
+}
+
+func (_ARMContract *ARMContractSession) GetCurseProgress(subject [16]byte) (GetCurseProgress,
+
+ error) {
+ return _ARMContract.Contract.GetCurseProgress(&_ARMContract.CallOpts, subject)
+}
+
+func (_ARMContract *ARMContractCallerSession) GetCurseProgress(subject [16]byte) (GetCurseProgress,
+
+ error) {
+ return _ARMContract.Contract.GetCurseProgress(&_ARMContract.CallOpts, subject)
+}
+
+func (_ARMContract *ARMContractCaller) GetCursedSubjectsCount(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "getCursedSubjectsCount")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) GetCursedSubjectsCount() (*big.Int, error) {
+ return _ARMContract.Contract.GetCursedSubjectsCount(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCallerSession) GetCursedSubjectsCount() (*big.Int, error) {
+ return _ARMContract.Contract.GetCursedSubjectsCount(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCaller) GetPermaBlessedCommitStores(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "getPermaBlessedCommitStores")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) GetPermaBlessedCommitStores() ([]common.Address, error) {
+ return _ARMContract.Contract.GetPermaBlessedCommitStores(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCallerSession) GetPermaBlessedCommitStores() ([]common.Address, error) {
+ return _ARMContract.Contract.GetPermaBlessedCommitStores(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCaller) GetRecordedCurseRelatedOps(opts *bind.CallOpts, offset *big.Int, limit *big.Int) ([]RMNRecordedCurseRelatedOp, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "getRecordedCurseRelatedOps", offset, limit)
+
+ if err != nil {
+ return *new([]RMNRecordedCurseRelatedOp), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]RMNRecordedCurseRelatedOp)).(*[]RMNRecordedCurseRelatedOp)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) GetRecordedCurseRelatedOps(offset *big.Int, limit *big.Int) ([]RMNRecordedCurseRelatedOp, error) {
+ return _ARMContract.Contract.GetRecordedCurseRelatedOps(&_ARMContract.CallOpts, offset, limit)
+}
+
+func (_ARMContract *ARMContractCallerSession) GetRecordedCurseRelatedOps(offset *big.Int, limit *big.Int) ([]RMNRecordedCurseRelatedOp, error) {
+ return _ARMContract.Contract.GetRecordedCurseRelatedOps(&_ARMContract.CallOpts, offset, limit)
+}
+
+func (_ARMContract *ARMContractCaller) GetRecordedCurseRelatedOpsCount(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "getRecordedCurseRelatedOpsCount")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) GetRecordedCurseRelatedOpsCount() (*big.Int, error) {
+ return _ARMContract.Contract.GetRecordedCurseRelatedOpsCount(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCallerSession) GetRecordedCurseRelatedOpsCount() (*big.Int, error) {
+ return _ARMContract.Contract.GetRecordedCurseRelatedOpsCount(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCaller) IsBlessed(opts *bind.CallOpts, taggedRoot IRMNTaggedRoot) (bool, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "isBlessed", taggedRoot)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) IsBlessed(taggedRoot IRMNTaggedRoot) (bool, error) {
+ return _ARMContract.Contract.IsBlessed(&_ARMContract.CallOpts, taggedRoot)
+}
+
+func (_ARMContract *ARMContractCallerSession) IsBlessed(taggedRoot IRMNTaggedRoot) (bool, error) {
+ return _ARMContract.Contract.IsBlessed(&_ARMContract.CallOpts, taggedRoot)
+}
+
+func (_ARMContract *ARMContractCaller) IsCursed(opts *bind.CallOpts, subject [16]byte) (bool, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "isCursed", subject)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) IsCursed(subject [16]byte) (bool, error) {
+ return _ARMContract.Contract.IsCursed(&_ARMContract.CallOpts, subject)
+}
+
+func (_ARMContract *ARMContractCallerSession) IsCursed(subject [16]byte) (bool, error) {
+ return _ARMContract.Contract.IsCursed(&_ARMContract.CallOpts, subject)
+}
+
+func (_ARMContract *ARMContractCaller) IsCursed0(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "isCursed0")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) IsCursed0() (bool, error) {
+ return _ARMContract.Contract.IsCursed0(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCallerSession) IsCursed0() (bool, error) {
+ return _ARMContract.Contract.IsCursed0(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) Owner() (common.Address, error) {
+ return _ARMContract.Contract.Owner(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCallerSession) Owner() (common.Address, error) {
+ return _ARMContract.Contract.Owner(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _ARMContract.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_ARMContract *ARMContractSession) TypeAndVersion() (string, error) {
+ return _ARMContract.Contract.TypeAndVersion(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractCallerSession) TypeAndVersion() (string, error) {
+ return _ARMContract.Contract.TypeAndVersion(&_ARMContract.CallOpts)
+}
+
+func (_ARMContract *ARMContractTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_ARMContract *ARMContractSession) AcceptOwnership() (*types.Transaction, error) {
+ return _ARMContract.Contract.AcceptOwnership(&_ARMContract.TransactOpts)
+}
+
+func (_ARMContract *ARMContractTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _ARMContract.Contract.AcceptOwnership(&_ARMContract.TransactOpts)
+}
+
+func (_ARMContract *ARMContractTransactor) OwnerCurse(opts *bind.TransactOpts, curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "ownerCurse", curseId, subjects)
+}
+
+func (_ARMContract *ARMContractSession) OwnerCurse(curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) {
+ return _ARMContract.Contract.OwnerCurse(&_ARMContract.TransactOpts, curseId, subjects)
+}
+
+func (_ARMContract *ARMContractTransactorSession) OwnerCurse(curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) {
+ return _ARMContract.Contract.OwnerCurse(&_ARMContract.TransactOpts, curseId, subjects)
+}
+
+func (_ARMContract *ARMContractTransactor) OwnerRemoveThenAddPermaBlessedCommitStores(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "ownerRemoveThenAddPermaBlessedCommitStores", removes, adds)
+}
+
+func (_ARMContract *ARMContractSession) OwnerRemoveThenAddPermaBlessedCommitStores(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _ARMContract.Contract.OwnerRemoveThenAddPermaBlessedCommitStores(&_ARMContract.TransactOpts, removes, adds)
+}
+
+func (_ARMContract *ARMContractTransactorSession) OwnerRemoveThenAddPermaBlessedCommitStores(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _ARMContract.Contract.OwnerRemoveThenAddPermaBlessedCommitStores(&_ARMContract.TransactOpts, removes, adds)
+}
+
+func (_ARMContract *ARMContractTransactor) OwnerResetBlessVotes(opts *bind.TransactOpts, taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "ownerResetBlessVotes", taggedRoots)
+}
+
+func (_ARMContract *ARMContractSession) OwnerResetBlessVotes(taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) {
+ return _ARMContract.Contract.OwnerResetBlessVotes(&_ARMContract.TransactOpts, taggedRoots)
+}
+
+func (_ARMContract *ARMContractTransactorSession) OwnerResetBlessVotes(taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) {
+ return _ARMContract.Contract.OwnerResetBlessVotes(&_ARMContract.TransactOpts, taggedRoots)
+}
+
+func (_ARMContract *ARMContractTransactor) OwnerUnvoteToCurse(opts *bind.TransactOpts, ownerUnvoteToCurseRequests []RMNOwnerUnvoteToCurseRequest) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "ownerUnvoteToCurse", ownerUnvoteToCurseRequests)
+}
+
+func (_ARMContract *ARMContractSession) OwnerUnvoteToCurse(ownerUnvoteToCurseRequests []RMNOwnerUnvoteToCurseRequest) (*types.Transaction, error) {
+ return _ARMContract.Contract.OwnerUnvoteToCurse(&_ARMContract.TransactOpts, ownerUnvoteToCurseRequests)
+}
+
+func (_ARMContract *ARMContractTransactorSession) OwnerUnvoteToCurse(ownerUnvoteToCurseRequests []RMNOwnerUnvoteToCurseRequest) (*types.Transaction, error) {
+ return _ARMContract.Contract.OwnerUnvoteToCurse(&_ARMContract.TransactOpts, ownerUnvoteToCurseRequests)
+}
+
+func (_ARMContract *ARMContractTransactor) SetConfig(opts *bind.TransactOpts, config RMNConfig) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "setConfig", config)
+}
+
+func (_ARMContract *ARMContractSession) SetConfig(config RMNConfig) (*types.Transaction, error) {
+ return _ARMContract.Contract.SetConfig(&_ARMContract.TransactOpts, config)
+}
+
+func (_ARMContract *ARMContractTransactorSession) SetConfig(config RMNConfig) (*types.Transaction, error) {
+ return _ARMContract.Contract.SetConfig(&_ARMContract.TransactOpts, config)
+}
+
+func (_ARMContract *ARMContractTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_ARMContract *ARMContractSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _ARMContract.Contract.TransferOwnership(&_ARMContract.TransactOpts, to)
+}
+
+func (_ARMContract *ARMContractTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _ARMContract.Contract.TransferOwnership(&_ARMContract.TransactOpts, to)
+}
+
+func (_ARMContract *ARMContractTransactor) UnvoteToCurse(opts *bind.TransactOpts, unvoteToCurseRequests []RMNUnvoteToCurseRequest) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "unvoteToCurse", unvoteToCurseRequests)
+}
+
+func (_ARMContract *ARMContractSession) UnvoteToCurse(unvoteToCurseRequests []RMNUnvoteToCurseRequest) (*types.Transaction, error) {
+ return _ARMContract.Contract.UnvoteToCurse(&_ARMContract.TransactOpts, unvoteToCurseRequests)
+}
+
+func (_ARMContract *ARMContractTransactorSession) UnvoteToCurse(unvoteToCurseRequests []RMNUnvoteToCurseRequest) (*types.Transaction, error) {
+ return _ARMContract.Contract.UnvoteToCurse(&_ARMContract.TransactOpts, unvoteToCurseRequests)
+}
+
+func (_ARMContract *ARMContractTransactor) VoteToBless(opts *bind.TransactOpts, taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "voteToBless", taggedRoots)
+}
+
+func (_ARMContract *ARMContractSession) VoteToBless(taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) {
+ return _ARMContract.Contract.VoteToBless(&_ARMContract.TransactOpts, taggedRoots)
+}
+
+func (_ARMContract *ARMContractTransactorSession) VoteToBless(taggedRoots []IRMNTaggedRoot) (*types.Transaction, error) {
+ return _ARMContract.Contract.VoteToBless(&_ARMContract.TransactOpts, taggedRoots)
+}
+
+func (_ARMContract *ARMContractTransactor) VoteToCurse(opts *bind.TransactOpts, curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) {
+ return _ARMContract.contract.Transact(opts, "voteToCurse", curseId, subjects)
+}
+
+func (_ARMContract *ARMContractSession) VoteToCurse(curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) {
+ return _ARMContract.Contract.VoteToCurse(&_ARMContract.TransactOpts, curseId, subjects)
+}
+
+func (_ARMContract *ARMContractTransactorSession) VoteToCurse(curseId [16]byte, subjects [][16]byte) (*types.Transaction, error) {
+ return _ARMContract.Contract.VoteToCurse(&_ARMContract.TransactOpts, curseId, subjects)
+}
+
+type ARMContractAlreadyBlessedIterator struct {
+ Event *ARMContractAlreadyBlessed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractAlreadyBlessedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractAlreadyBlessed)
+ 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(ARMContractAlreadyBlessed)
+ 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 *ARMContractAlreadyBlessedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractAlreadyBlessedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractAlreadyBlessed struct {
+ ConfigVersion uint32
+ Voter common.Address
+ TaggedRoot IRMNTaggedRoot
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterAlreadyBlessed(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractAlreadyBlessedIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "AlreadyBlessed", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractAlreadyBlessedIterator{contract: _ARMContract.contract, event: "AlreadyBlessed", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchAlreadyBlessed(opts *bind.WatchOpts, sink chan<- *ARMContractAlreadyBlessed, configVersion []uint32, voter []common.Address) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "AlreadyBlessed", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractAlreadyBlessed)
+ if err := _ARMContract.contract.UnpackLog(event, "AlreadyBlessed", 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 (_ARMContract *ARMContractFilterer) ParseAlreadyBlessed(log types.Log) (*ARMContractAlreadyBlessed, error) {
+ event := new(ARMContractAlreadyBlessed)
+ if err := _ARMContract.contract.UnpackLog(event, "AlreadyBlessed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractAlreadyVotedToBlessIterator struct {
+ Event *ARMContractAlreadyVotedToBless
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractAlreadyVotedToBlessIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractAlreadyVotedToBless)
+ 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(ARMContractAlreadyVotedToBless)
+ 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 *ARMContractAlreadyVotedToBlessIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractAlreadyVotedToBlessIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractAlreadyVotedToBless struct {
+ ConfigVersion uint32
+ Voter common.Address
+ TaggedRoot IRMNTaggedRoot
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterAlreadyVotedToBless(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractAlreadyVotedToBlessIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "AlreadyVotedToBless", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractAlreadyVotedToBlessIterator{contract: _ARMContract.contract, event: "AlreadyVotedToBless", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchAlreadyVotedToBless(opts *bind.WatchOpts, sink chan<- *ARMContractAlreadyVotedToBless, configVersion []uint32, voter []common.Address) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "AlreadyVotedToBless", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractAlreadyVotedToBless)
+ if err := _ARMContract.contract.UnpackLog(event, "AlreadyVotedToBless", 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 (_ARMContract *ARMContractFilterer) ParseAlreadyVotedToBless(log types.Log) (*ARMContractAlreadyVotedToBless, error) {
+ event := new(ARMContractAlreadyVotedToBless)
+ if err := _ARMContract.contract.UnpackLog(event, "AlreadyVotedToBless", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractConfigSetIterator struct {
+ Event *ARMContractConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractConfigSet)
+ 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(ARMContractConfigSet)
+ 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 *ARMContractConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractConfigSet struct {
+ ConfigVersion uint32
+ Config RMNConfig
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterConfigSet(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractConfigSetIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "ConfigSet", configVersionRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractConfigSetIterator{contract: _ARMContract.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *ARMContractConfigSet, configVersion []uint32) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "ConfigSet", configVersionRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractConfigSet)
+ if err := _ARMContract.contract.UnpackLog(event, "ConfigSet", 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 (_ARMContract *ARMContractFilterer) ParseConfigSet(log types.Log) (*ARMContractConfigSet, error) {
+ event := new(ARMContractConfigSet)
+ if err := _ARMContract.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractCurseLiftedIterator struct {
+ Event *ARMContractCurseLifted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractCurseLiftedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractCurseLifted)
+ 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(ARMContractCurseLifted)
+ 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 *ARMContractCurseLiftedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractCurseLiftedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractCurseLifted struct {
+ Subject [16]byte
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterCurseLifted(opts *bind.FilterOpts) (*ARMContractCurseLiftedIterator, error) {
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "CurseLifted")
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractCurseLiftedIterator{contract: _ARMContract.contract, event: "CurseLifted", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchCurseLifted(opts *bind.WatchOpts, sink chan<- *ARMContractCurseLifted) (event.Subscription, error) {
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "CurseLifted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractCurseLifted)
+ if err := _ARMContract.contract.UnpackLog(event, "CurseLifted", 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 (_ARMContract *ARMContractFilterer) ParseCurseLifted(log types.Log) (*ARMContractCurseLifted, error) {
+ event := new(ARMContractCurseLifted)
+ if err := _ARMContract.contract.UnpackLog(event, "CurseLifted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractCursedIterator struct {
+ Event *ARMContractCursed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractCursedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractCursed)
+ 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(ARMContractCursed)
+ 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 *ARMContractCursedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractCursedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractCursed struct {
+ ConfigVersion uint32
+ Subject [16]byte
+ BlockTimestamp uint64
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterCursed(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractCursedIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "Cursed", configVersionRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractCursedIterator{contract: _ARMContract.contract, event: "Cursed", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchCursed(opts *bind.WatchOpts, sink chan<- *ARMContractCursed, configVersion []uint32) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "Cursed", configVersionRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractCursed)
+ if err := _ARMContract.contract.UnpackLog(event, "Cursed", 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 (_ARMContract *ARMContractFilterer) ParseCursed(log types.Log) (*ARMContractCursed, error) {
+ event := new(ARMContractCursed)
+ if err := _ARMContract.contract.UnpackLog(event, "Cursed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractOwnershipTransferRequestedIterator struct {
+ Event *ARMContractOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractOwnershipTransferRequested)
+ 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(ARMContractOwnershipTransferRequested)
+ 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 *ARMContractOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMContractOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractOwnershipTransferRequestedIterator{contract: _ARMContract.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *ARMContractOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractOwnershipTransferRequested)
+ if err := _ARMContract.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_ARMContract *ARMContractFilterer) ParseOwnershipTransferRequested(log types.Log) (*ARMContractOwnershipTransferRequested, error) {
+ event := new(ARMContractOwnershipTransferRequested)
+ if err := _ARMContract.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractOwnershipTransferredIterator struct {
+ Event *ARMContractOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractOwnershipTransferred)
+ 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(ARMContractOwnershipTransferred)
+ 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 *ARMContractOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMContractOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractOwnershipTransferredIterator{contract: _ARMContract.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *ARMContractOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractOwnershipTransferred)
+ if err := _ARMContract.contract.UnpackLog(event, "OwnershipTransferred", 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 (_ARMContract *ARMContractFilterer) ParseOwnershipTransferred(log types.Log) (*ARMContractOwnershipTransferred, error) {
+ event := new(ARMContractOwnershipTransferred)
+ if err := _ARMContract.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractPermaBlessedCommitStoreAddedIterator struct {
+ Event *ARMContractPermaBlessedCommitStoreAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractPermaBlessedCommitStoreAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractPermaBlessedCommitStoreAdded)
+ 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(ARMContractPermaBlessedCommitStoreAdded)
+ 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 *ARMContractPermaBlessedCommitStoreAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractPermaBlessedCommitStoreAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractPermaBlessedCommitStoreAdded struct {
+ CommitStore common.Address
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterPermaBlessedCommitStoreAdded(opts *bind.FilterOpts) (*ARMContractPermaBlessedCommitStoreAddedIterator, error) {
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "PermaBlessedCommitStoreAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractPermaBlessedCommitStoreAddedIterator{contract: _ARMContract.contract, event: "PermaBlessedCommitStoreAdded", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchPermaBlessedCommitStoreAdded(opts *bind.WatchOpts, sink chan<- *ARMContractPermaBlessedCommitStoreAdded) (event.Subscription, error) {
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "PermaBlessedCommitStoreAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractPermaBlessedCommitStoreAdded)
+ if err := _ARMContract.contract.UnpackLog(event, "PermaBlessedCommitStoreAdded", 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 (_ARMContract *ARMContractFilterer) ParsePermaBlessedCommitStoreAdded(log types.Log) (*ARMContractPermaBlessedCommitStoreAdded, error) {
+ event := new(ARMContractPermaBlessedCommitStoreAdded)
+ if err := _ARMContract.contract.UnpackLog(event, "PermaBlessedCommitStoreAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractPermaBlessedCommitStoreRemovedIterator struct {
+ Event *ARMContractPermaBlessedCommitStoreRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractPermaBlessedCommitStoreRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractPermaBlessedCommitStoreRemoved)
+ 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(ARMContractPermaBlessedCommitStoreRemoved)
+ 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 *ARMContractPermaBlessedCommitStoreRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractPermaBlessedCommitStoreRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractPermaBlessedCommitStoreRemoved struct {
+ CommitStore common.Address
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterPermaBlessedCommitStoreRemoved(opts *bind.FilterOpts) (*ARMContractPermaBlessedCommitStoreRemovedIterator, error) {
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "PermaBlessedCommitStoreRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractPermaBlessedCommitStoreRemovedIterator{contract: _ARMContract.contract, event: "PermaBlessedCommitStoreRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchPermaBlessedCommitStoreRemoved(opts *bind.WatchOpts, sink chan<- *ARMContractPermaBlessedCommitStoreRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "PermaBlessedCommitStoreRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractPermaBlessedCommitStoreRemoved)
+ if err := _ARMContract.contract.UnpackLog(event, "PermaBlessedCommitStoreRemoved", 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 (_ARMContract *ARMContractFilterer) ParsePermaBlessedCommitStoreRemoved(log types.Log) (*ARMContractPermaBlessedCommitStoreRemoved, error) {
+ event := new(ARMContractPermaBlessedCommitStoreRemoved)
+ if err := _ARMContract.contract.UnpackLog(event, "PermaBlessedCommitStoreRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractSkippedUnvoteToCurseIterator struct {
+ Event *ARMContractSkippedUnvoteToCurse
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractSkippedUnvoteToCurseIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractSkippedUnvoteToCurse)
+ 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(ARMContractSkippedUnvoteToCurse)
+ 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 *ARMContractSkippedUnvoteToCurseIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractSkippedUnvoteToCurseIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractSkippedUnvoteToCurse struct {
+ Voter common.Address
+ Subject [16]byte
+ OnchainCursesHash [28]byte
+ CursesHash [28]byte
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterSkippedUnvoteToCurse(opts *bind.FilterOpts, voter []common.Address) (*ARMContractSkippedUnvoteToCurseIterator, error) {
+
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "SkippedUnvoteToCurse", voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractSkippedUnvoteToCurseIterator{contract: _ARMContract.contract, event: "SkippedUnvoteToCurse", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchSkippedUnvoteToCurse(opts *bind.WatchOpts, sink chan<- *ARMContractSkippedUnvoteToCurse, voter []common.Address) (event.Subscription, error) {
+
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "SkippedUnvoteToCurse", voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractSkippedUnvoteToCurse)
+ if err := _ARMContract.contract.UnpackLog(event, "SkippedUnvoteToCurse", 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 (_ARMContract *ARMContractFilterer) ParseSkippedUnvoteToCurse(log types.Log) (*ARMContractSkippedUnvoteToCurse, error) {
+ event := new(ARMContractSkippedUnvoteToCurse)
+ if err := _ARMContract.contract.UnpackLog(event, "SkippedUnvoteToCurse", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractTaggedRootBlessVotesResetIterator struct {
+ Event *ARMContractTaggedRootBlessVotesReset
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractTaggedRootBlessVotesResetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractTaggedRootBlessVotesReset)
+ 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(ARMContractTaggedRootBlessVotesReset)
+ 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 *ARMContractTaggedRootBlessVotesResetIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractTaggedRootBlessVotesResetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractTaggedRootBlessVotesReset struct {
+ ConfigVersion uint32
+ TaggedRoot IRMNTaggedRoot
+ WasBlessed bool
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterTaggedRootBlessVotesReset(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractTaggedRootBlessVotesResetIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "TaggedRootBlessVotesReset", configVersionRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractTaggedRootBlessVotesResetIterator{contract: _ARMContract.contract, event: "TaggedRootBlessVotesReset", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchTaggedRootBlessVotesReset(opts *bind.WatchOpts, sink chan<- *ARMContractTaggedRootBlessVotesReset, configVersion []uint32) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "TaggedRootBlessVotesReset", configVersionRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractTaggedRootBlessVotesReset)
+ if err := _ARMContract.contract.UnpackLog(event, "TaggedRootBlessVotesReset", 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 (_ARMContract *ARMContractFilterer) ParseTaggedRootBlessVotesReset(log types.Log) (*ARMContractTaggedRootBlessVotesReset, error) {
+ event := new(ARMContractTaggedRootBlessVotesReset)
+ if err := _ARMContract.contract.UnpackLog(event, "TaggedRootBlessVotesReset", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractTaggedRootBlessedIterator struct {
+ Event *ARMContractTaggedRootBlessed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractTaggedRootBlessedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractTaggedRootBlessed)
+ 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(ARMContractTaggedRootBlessed)
+ 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 *ARMContractTaggedRootBlessedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractTaggedRootBlessedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractTaggedRootBlessed struct {
+ ConfigVersion uint32
+ TaggedRoot IRMNTaggedRoot
+ AccumulatedWeight uint16
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterTaggedRootBlessed(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractTaggedRootBlessedIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "TaggedRootBlessed", configVersionRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractTaggedRootBlessedIterator{contract: _ARMContract.contract, event: "TaggedRootBlessed", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchTaggedRootBlessed(opts *bind.WatchOpts, sink chan<- *ARMContractTaggedRootBlessed, configVersion []uint32) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "TaggedRootBlessed", configVersionRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractTaggedRootBlessed)
+ if err := _ARMContract.contract.UnpackLog(event, "TaggedRootBlessed", 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 (_ARMContract *ARMContractFilterer) ParseTaggedRootBlessed(log types.Log) (*ARMContractTaggedRootBlessed, error) {
+ event := new(ARMContractTaggedRootBlessed)
+ if err := _ARMContract.contract.UnpackLog(event, "TaggedRootBlessed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractUnvotedToCurseIterator struct {
+ Event *ARMContractUnvotedToCurse
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractUnvotedToCurseIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractUnvotedToCurse)
+ 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(ARMContractUnvotedToCurse)
+ 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 *ARMContractUnvotedToCurseIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractUnvotedToCurseIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractUnvotedToCurse struct {
+ ConfigVersion uint32
+ Voter common.Address
+ Subject [16]byte
+ Weight uint8
+ CursesHash [28]byte
+ RemainingAccumulatedWeight uint16
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterUnvotedToCurse(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractUnvotedToCurseIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "UnvotedToCurse", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractUnvotedToCurseIterator{contract: _ARMContract.contract, event: "UnvotedToCurse", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchUnvotedToCurse(opts *bind.WatchOpts, sink chan<- *ARMContractUnvotedToCurse, configVersion []uint32, voter []common.Address) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "UnvotedToCurse", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractUnvotedToCurse)
+ if err := _ARMContract.contract.UnpackLog(event, "UnvotedToCurse", 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 (_ARMContract *ARMContractFilterer) ParseUnvotedToCurse(log types.Log) (*ARMContractUnvotedToCurse, error) {
+ event := new(ARMContractUnvotedToCurse)
+ if err := _ARMContract.contract.UnpackLog(event, "UnvotedToCurse", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractVotedToBlessIterator struct {
+ Event *ARMContractVotedToBless
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractVotedToBlessIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractVotedToBless)
+ 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(ARMContractVotedToBless)
+ 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 *ARMContractVotedToBlessIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractVotedToBlessIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractVotedToBless struct {
+ ConfigVersion uint32
+ Voter common.Address
+ TaggedRoot IRMNTaggedRoot
+ Weight uint8
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterVotedToBless(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractVotedToBlessIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "VotedToBless", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractVotedToBlessIterator{contract: _ARMContract.contract, event: "VotedToBless", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchVotedToBless(opts *bind.WatchOpts, sink chan<- *ARMContractVotedToBless, configVersion []uint32, voter []common.Address) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "VotedToBless", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractVotedToBless)
+ if err := _ARMContract.contract.UnpackLog(event, "VotedToBless", 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 (_ARMContract *ARMContractFilterer) ParseVotedToBless(log types.Log) (*ARMContractVotedToBless, error) {
+ event := new(ARMContractVotedToBless)
+ if err := _ARMContract.contract.UnpackLog(event, "VotedToBless", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMContractVotedToCurseIterator struct {
+ Event *ARMContractVotedToCurse
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMContractVotedToCurseIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMContractVotedToCurse)
+ 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(ARMContractVotedToCurse)
+ 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 *ARMContractVotedToCurseIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMContractVotedToCurseIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMContractVotedToCurse struct {
+ ConfigVersion uint32
+ Voter common.Address
+ Subject [16]byte
+ CurseId [16]byte
+ Weight uint8
+ BlockTimestamp uint64
+ CursesHash [28]byte
+ AccumulatedWeight uint16
+ Raw types.Log
+}
+
+func (_ARMContract *ARMContractFilterer) FilterVotedToCurse(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractVotedToCurseIterator, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.FilterLogs(opts, "VotedToCurse", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMContractVotedToCurseIterator{contract: _ARMContract.contract, event: "VotedToCurse", logs: logs, sub: sub}, nil
+}
+
+func (_ARMContract *ARMContractFilterer) WatchVotedToCurse(opts *bind.WatchOpts, sink chan<- *ARMContractVotedToCurse, configVersion []uint32, voter []common.Address) (event.Subscription, error) {
+
+ var configVersionRule []interface{}
+ for _, configVersionItem := range configVersion {
+ configVersionRule = append(configVersionRule, configVersionItem)
+ }
+ var voterRule []interface{}
+ for _, voterItem := range voter {
+ voterRule = append(voterRule, voterItem)
+ }
+
+ logs, sub, err := _ARMContract.contract.WatchLogs(opts, "VotedToCurse", configVersionRule, voterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMContractVotedToCurse)
+ if err := _ARMContract.contract.UnpackLog(event, "VotedToCurse", 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 (_ARMContract *ARMContractFilterer) ParseVotedToCurse(log types.Log) (*ARMContractVotedToCurse, error) {
+ event := new(ARMContractVotedToCurse)
+ if err := _ARMContract.contract.UnpackLog(event, "VotedToCurse", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetBlessProgress struct {
+ BlessVoteAddrs []common.Address
+ AccumulatedWeight uint16
+ Blessed bool
+}
+type GetConfigDetails struct {
+ Version uint32
+ BlockNumber uint32
+ Config RMNConfig
+}
+type GetCurseProgress struct {
+ CurseVoteAddrs []common.Address
+ CursesHashes [][28]byte
+ AccumulatedWeight uint16
+ Cursed bool
+}
+
+func (_ARMContract *ARMContract) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _ARMContract.abi.Events["AlreadyBlessed"].ID:
+ return _ARMContract.ParseAlreadyBlessed(log)
+ case _ARMContract.abi.Events["AlreadyVotedToBless"].ID:
+ return _ARMContract.ParseAlreadyVotedToBless(log)
+ case _ARMContract.abi.Events["ConfigSet"].ID:
+ return _ARMContract.ParseConfigSet(log)
+ case _ARMContract.abi.Events["CurseLifted"].ID:
+ return _ARMContract.ParseCurseLifted(log)
+ case _ARMContract.abi.Events["Cursed"].ID:
+ return _ARMContract.ParseCursed(log)
+ case _ARMContract.abi.Events["OwnershipTransferRequested"].ID:
+ return _ARMContract.ParseOwnershipTransferRequested(log)
+ case _ARMContract.abi.Events["OwnershipTransferred"].ID:
+ return _ARMContract.ParseOwnershipTransferred(log)
+ case _ARMContract.abi.Events["PermaBlessedCommitStoreAdded"].ID:
+ return _ARMContract.ParsePermaBlessedCommitStoreAdded(log)
+ case _ARMContract.abi.Events["PermaBlessedCommitStoreRemoved"].ID:
+ return _ARMContract.ParsePermaBlessedCommitStoreRemoved(log)
+ case _ARMContract.abi.Events["SkippedUnvoteToCurse"].ID:
+ return _ARMContract.ParseSkippedUnvoteToCurse(log)
+ case _ARMContract.abi.Events["TaggedRootBlessVotesReset"].ID:
+ return _ARMContract.ParseTaggedRootBlessVotesReset(log)
+ case _ARMContract.abi.Events["TaggedRootBlessed"].ID:
+ return _ARMContract.ParseTaggedRootBlessed(log)
+ case _ARMContract.abi.Events["UnvotedToCurse"].ID:
+ return _ARMContract.ParseUnvotedToCurse(log)
+ case _ARMContract.abi.Events["VotedToBless"].ID:
+ return _ARMContract.ParseVotedToBless(log)
+ case _ARMContract.abi.Events["VotedToCurse"].ID:
+ return _ARMContract.ParseVotedToCurse(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (ARMContractAlreadyBlessed) Topic() common.Hash {
+ return common.HexToHash("0x274d6d5b916b0a53974b7ab86c844b97a2e03a60f658cd9a4b1c028b604d7bf1")
+}
+
+func (ARMContractAlreadyVotedToBless) Topic() common.Hash {
+ return common.HexToHash("0x6dfbb745226fa630aeb1b9557d17d508ddb789a04f0cb873ec16e58beb8beead")
+}
+
+func (ARMContractConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x8c49fda8177c5c8c768eb39634bc6773695c7181711537b822451c12b2efd2a9")
+}
+
+func (ARMContractCurseLifted) Topic() common.Hash {
+ return common.HexToHash("0x65d0e78c3625f0956f58610cf0fb157eaf627683258875ef29af2f71d25ac8fd")
+}
+
+func (ARMContractCursed) Topic() common.Hash {
+ return common.HexToHash("0xcfdbfd8ce9a56b5f7c202c0e102184d24f47ca87121dc165063fc4c290957bde")
+}
+
+func (ARMContractOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (ARMContractOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (ARMContractPermaBlessedCommitStoreAdded) Topic() common.Hash {
+ return common.HexToHash("0x66b4b4752c65ae8cd2f3a0a48c7dc8b2118c60d5ea15514992eb2ddf56c9cb15")
+}
+
+func (ARMContractPermaBlessedCommitStoreRemoved) Topic() common.Hash {
+ return common.HexToHash("0xdca892154bbc36d0c05ccd01b3d0411875cb1b841fcdeebb384e5d0d6eb06b44")
+}
+
+func (ARMContractSkippedUnvoteToCurse) Topic() common.Hash {
+ return common.HexToHash("0xbabb0d7099e6ca14a29fad2a2cfb4fda2bd30f97cb3c27e546174bfb4277c1cc")
+}
+
+func (ARMContractTaggedRootBlessVotesReset) Topic() common.Hash {
+ return common.HexToHash("0x7d15a6eebaa019ea7d5b7d38937c51ebd3befbfdf51bb630a694fd28635bbcba")
+}
+
+func (ARMContractTaggedRootBlessed) Topic() common.Hash {
+ return common.HexToHash("0x8257378aa73bf8e4ada848713526584a3dcee0fd3db3beed7397f7a7f5067cc9")
+}
+
+func (ARMContractUnvotedToCurse) Topic() common.Hash {
+ return common.HexToHash("0xa96a155bd67c927a6c056befbd979b78465e2b2f1276bf7d4e90a31d4f430aa8")
+}
+
+func (ARMContractVotedToBless) Topic() common.Hash {
+ return common.HexToHash("0x2a08a2bd2798f0aae9a843f0f4ad4de488c1b3d5f04049940cfed736ad69fb97")
+}
+
+func (ARMContractVotedToCurse) Topic() common.Hash {
+ return common.HexToHash("0x8137bc8a8d712aaa27bfc6506d5566ac405618bd53f9831b8ca6b6fe5442ee7a")
+}
+
+func (_ARMContract *ARMContract) Address() common.Address {
+ return _ARMContract.address
+}
+
+type ARMContractInterface interface {
+ GetBlessProgress(opts *bind.CallOpts, taggedRoot IRMNTaggedRoot) (GetBlessProgress,
+
+ error)
+
+ GetConfigDetails(opts *bind.CallOpts) (GetConfigDetails,
+
+ error)
+
+ GetCurseProgress(opts *bind.CallOpts, subject [16]byte) (GetCurseProgress,
+
+ error)
+
+ GetCursedSubjectsCount(opts *bind.CallOpts) (*big.Int, error)
+
+ GetPermaBlessedCommitStores(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetRecordedCurseRelatedOps(opts *bind.CallOpts, offset *big.Int, limit *big.Int) ([]RMNRecordedCurseRelatedOp, error)
+
+ GetRecordedCurseRelatedOpsCount(opts *bind.CallOpts) (*big.Int, error)
+
+ IsBlessed(opts *bind.CallOpts, taggedRoot IRMNTaggedRoot) (bool, error)
+
+ IsCursed(opts *bind.CallOpts, subject [16]byte) (bool, error)
+
+ IsCursed0(opts *bind.CallOpts) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ OwnerCurse(opts *bind.TransactOpts, curseId [16]byte, subjects [][16]byte) (*types.Transaction, error)
+
+ OwnerRemoveThenAddPermaBlessedCommitStores(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ OwnerResetBlessVotes(opts *bind.TransactOpts, taggedRoots []IRMNTaggedRoot) (*types.Transaction, error)
+
+ OwnerUnvoteToCurse(opts *bind.TransactOpts, ownerUnvoteToCurseRequests []RMNOwnerUnvoteToCurseRequest) (*types.Transaction, error)
+
+ SetConfig(opts *bind.TransactOpts, config RMNConfig) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ UnvoteToCurse(opts *bind.TransactOpts, unvoteToCurseRequests []RMNUnvoteToCurseRequest) (*types.Transaction, error)
+
+ VoteToBless(opts *bind.TransactOpts, taggedRoots []IRMNTaggedRoot) (*types.Transaction, error)
+
+ VoteToCurse(opts *bind.TransactOpts, curseId [16]byte, subjects [][16]byte) (*types.Transaction, error)
+
+ FilterAlreadyBlessed(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractAlreadyBlessedIterator, error)
+
+ WatchAlreadyBlessed(opts *bind.WatchOpts, sink chan<- *ARMContractAlreadyBlessed, configVersion []uint32, voter []common.Address) (event.Subscription, error)
+
+ ParseAlreadyBlessed(log types.Log) (*ARMContractAlreadyBlessed, error)
+
+ FilterAlreadyVotedToBless(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractAlreadyVotedToBlessIterator, error)
+
+ WatchAlreadyVotedToBless(opts *bind.WatchOpts, sink chan<- *ARMContractAlreadyVotedToBless, configVersion []uint32, voter []common.Address) (event.Subscription, error)
+
+ ParseAlreadyVotedToBless(log types.Log) (*ARMContractAlreadyVotedToBless, error)
+
+ FilterConfigSet(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *ARMContractConfigSet, configVersion []uint32) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*ARMContractConfigSet, error)
+
+ FilterCurseLifted(opts *bind.FilterOpts) (*ARMContractCurseLiftedIterator, error)
+
+ WatchCurseLifted(opts *bind.WatchOpts, sink chan<- *ARMContractCurseLifted) (event.Subscription, error)
+
+ ParseCurseLifted(log types.Log) (*ARMContractCurseLifted, error)
+
+ FilterCursed(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractCursedIterator, error)
+
+ WatchCursed(opts *bind.WatchOpts, sink chan<- *ARMContractCursed, configVersion []uint32) (event.Subscription, error)
+
+ ParseCursed(log types.Log) (*ARMContractCursed, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMContractOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *ARMContractOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*ARMContractOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMContractOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *ARMContractOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*ARMContractOwnershipTransferred, error)
+
+ FilterPermaBlessedCommitStoreAdded(opts *bind.FilterOpts) (*ARMContractPermaBlessedCommitStoreAddedIterator, error)
+
+ WatchPermaBlessedCommitStoreAdded(opts *bind.WatchOpts, sink chan<- *ARMContractPermaBlessedCommitStoreAdded) (event.Subscription, error)
+
+ ParsePermaBlessedCommitStoreAdded(log types.Log) (*ARMContractPermaBlessedCommitStoreAdded, error)
+
+ FilterPermaBlessedCommitStoreRemoved(opts *bind.FilterOpts) (*ARMContractPermaBlessedCommitStoreRemovedIterator, error)
+
+ WatchPermaBlessedCommitStoreRemoved(opts *bind.WatchOpts, sink chan<- *ARMContractPermaBlessedCommitStoreRemoved) (event.Subscription, error)
+
+ ParsePermaBlessedCommitStoreRemoved(log types.Log) (*ARMContractPermaBlessedCommitStoreRemoved, error)
+
+ FilterSkippedUnvoteToCurse(opts *bind.FilterOpts, voter []common.Address) (*ARMContractSkippedUnvoteToCurseIterator, error)
+
+ WatchSkippedUnvoteToCurse(opts *bind.WatchOpts, sink chan<- *ARMContractSkippedUnvoteToCurse, voter []common.Address) (event.Subscription, error)
+
+ ParseSkippedUnvoteToCurse(log types.Log) (*ARMContractSkippedUnvoteToCurse, error)
+
+ FilterTaggedRootBlessVotesReset(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractTaggedRootBlessVotesResetIterator, error)
+
+ WatchTaggedRootBlessVotesReset(opts *bind.WatchOpts, sink chan<- *ARMContractTaggedRootBlessVotesReset, configVersion []uint32) (event.Subscription, error)
+
+ ParseTaggedRootBlessVotesReset(log types.Log) (*ARMContractTaggedRootBlessVotesReset, error)
+
+ FilterTaggedRootBlessed(opts *bind.FilterOpts, configVersion []uint32) (*ARMContractTaggedRootBlessedIterator, error)
+
+ WatchTaggedRootBlessed(opts *bind.WatchOpts, sink chan<- *ARMContractTaggedRootBlessed, configVersion []uint32) (event.Subscription, error)
+
+ ParseTaggedRootBlessed(log types.Log) (*ARMContractTaggedRootBlessed, error)
+
+ FilterUnvotedToCurse(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractUnvotedToCurseIterator, error)
+
+ WatchUnvotedToCurse(opts *bind.WatchOpts, sink chan<- *ARMContractUnvotedToCurse, configVersion []uint32, voter []common.Address) (event.Subscription, error)
+
+ ParseUnvotedToCurse(log types.Log) (*ARMContractUnvotedToCurse, error)
+
+ FilterVotedToBless(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractVotedToBlessIterator, error)
+
+ WatchVotedToBless(opts *bind.WatchOpts, sink chan<- *ARMContractVotedToBless, configVersion []uint32, voter []common.Address) (event.Subscription, error)
+
+ ParseVotedToBless(log types.Log) (*ARMContractVotedToBless, error)
+
+ FilterVotedToCurse(opts *bind.FilterOpts, configVersion []uint32, voter []common.Address) (*ARMContractVotedToCurseIterator, error)
+
+ WatchVotedToCurse(opts *bind.WatchOpts, sink chan<- *ARMContractVotedToCurse, configVersion []uint32, voter []common.Address) (event.Subscription, error)
+
+ ParseVotedToCurse(log types.Log) (*ARMContractVotedToCurse, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/arm_proxy_contract/arm_proxy_contract.go b/core/gethwrappers/ccip/generated/arm_proxy_contract/arm_proxy_contract.go
new file mode 100644
index 00000000000..e2ba9246216
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/arm_proxy_contract/arm_proxy_contract.go
@@ -0,0 +1,743 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arm_proxy_contract
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var ARMProxyContractMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"arm\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"arm\",\"type\":\"address\"}],\"name\":\"ARMSet\",\"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\"},{\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getARM\",\"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\":\"address\",\"name\":\"arm\",\"type\":\"address\"}],\"name\":\"setARM\",\"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: "0x608060405234801561001057600080fd5b5060405161084138038061084183398101604081905261002f91610255565b33806000816100855760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100b5576100b5816100cd565b5050506100c78161017660201b60201c565b50610285565b336001600160a01b038216036101255760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161007c565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b61017e6101f9565b6001600160a01b0381166101a5576040516342bcdf7f60e11b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527fef31f568d741a833c6a9dc85a6e1c65e06fa772740d5dc94d1da21827a4e0cab9060200160405180910390a150565b6000546001600160a01b031633146102535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161007c565b565b60006020828403121561026757600080fd5b81516001600160a01b038116811461027e57600080fd5b9392505050565b6105ad806102946000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c806379ba50971161005057806379ba5097146101615780638da5cb5b14610169578063f2fde38b1461018757610072565b8063181f5a77146100bb5780632e90aa211461010d578063458fec3b1461014c575b60025473ffffffffffffffffffffffffffffffffffffffff16803b61009657600080fd5b366000803760008036600080855af13d6000803e80156100b5573d6000f35b503d6000fd5b6100f76040518060400160405280600e81526020017f41524d50726f787920312e302e3000000000000000000000000000000000000081525081565b60405161010491906104f6565b60405180910390f35b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610104565b61015f61015a366004610563565b61019a565b005b61015f610268565b60005473ffffffffffffffffffffffffffffffffffffffff16610127565b61015f610195366004610563565b61036a565b6101a261037e565b73ffffffffffffffffffffffffffffffffffffffff81166101ef576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fef31f568d741a833c6a9dc85a6e1c65e06fa772740d5dc94d1da21827a4e0cab9060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff1633146102ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61037261037e565b61037b81610401565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016102e5565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610480576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016102e5565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006020808352835180602085015260005b8181101561052457858101830151858201604001528201610508565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60006020828403121561057557600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461059957600080fd5b939250505056fea164736f6c6343000818000a",
+}
+
+var ARMProxyContractABI = ARMProxyContractMetaData.ABI
+
+var ARMProxyContractBin = ARMProxyContractMetaData.Bin
+
+func DeployARMProxyContract(auth *bind.TransactOpts, backend bind.ContractBackend, arm common.Address) (common.Address, *types.Transaction, *ARMProxyContract, error) {
+ parsed, err := ARMProxyContractMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ARMProxyContractBin), backend, arm)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &ARMProxyContract{address: address, abi: *parsed, ARMProxyContractCaller: ARMProxyContractCaller{contract: contract}, ARMProxyContractTransactor: ARMProxyContractTransactor{contract: contract}, ARMProxyContractFilterer: ARMProxyContractFilterer{contract: contract}}, nil
+}
+
+type ARMProxyContract struct {
+ address common.Address
+ abi abi.ABI
+ ARMProxyContractCaller
+ ARMProxyContractTransactor
+ ARMProxyContractFilterer
+}
+
+type ARMProxyContractCaller struct {
+ contract *bind.BoundContract
+}
+
+type ARMProxyContractTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ARMProxyContractFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ARMProxyContractSession struct {
+ Contract *ARMProxyContract
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ARMProxyContractCallerSession struct {
+ Contract *ARMProxyContractCaller
+ CallOpts bind.CallOpts
+}
+
+type ARMProxyContractTransactorSession struct {
+ Contract *ARMProxyContractTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ARMProxyContractRaw struct {
+ Contract *ARMProxyContract
+}
+
+type ARMProxyContractCallerRaw struct {
+ Contract *ARMProxyContractCaller
+}
+
+type ARMProxyContractTransactorRaw struct {
+ Contract *ARMProxyContractTransactor
+}
+
+func NewARMProxyContract(address common.Address, backend bind.ContractBackend) (*ARMProxyContract, error) {
+ abi, err := abi.JSON(strings.NewReader(ARMProxyContractABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindARMProxyContract(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMProxyContract{address: address, abi: abi, ARMProxyContractCaller: ARMProxyContractCaller{contract: contract}, ARMProxyContractTransactor: ARMProxyContractTransactor{contract: contract}, ARMProxyContractFilterer: ARMProxyContractFilterer{contract: contract}}, nil
+}
+
+func NewARMProxyContractCaller(address common.Address, caller bind.ContractCaller) (*ARMProxyContractCaller, error) {
+ contract, err := bindARMProxyContract(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMProxyContractCaller{contract: contract}, nil
+}
+
+func NewARMProxyContractTransactor(address common.Address, transactor bind.ContractTransactor) (*ARMProxyContractTransactor, error) {
+ contract, err := bindARMProxyContract(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMProxyContractTransactor{contract: contract}, nil
+}
+
+func NewARMProxyContractFilterer(address common.Address, filterer bind.ContractFilterer) (*ARMProxyContractFilterer, error) {
+ contract, err := bindARMProxyContract(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMProxyContractFilterer{contract: contract}, nil
+}
+
+func bindARMProxyContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ARMProxyContractMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ARMProxyContract *ARMProxyContractRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ARMProxyContract.Contract.ARMProxyContractCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ARMProxyContract *ARMProxyContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.ARMProxyContractTransactor.contract.Transfer(opts)
+}
+
+func (_ARMProxyContract *ARMProxyContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.ARMProxyContractTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ARMProxyContract *ARMProxyContractCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ARMProxyContract.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.contract.Transfer(opts)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ARMProxyContract *ARMProxyContractCaller) GetARM(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ARMProxyContract.contract.Call(opts, &out, "getARM")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ARMProxyContract *ARMProxyContractSession) GetARM() (common.Address, error) {
+ return _ARMProxyContract.Contract.GetARM(&_ARMProxyContract.CallOpts)
+}
+
+func (_ARMProxyContract *ARMProxyContractCallerSession) GetARM() (common.Address, error) {
+ return _ARMProxyContract.Contract.GetARM(&_ARMProxyContract.CallOpts)
+}
+
+func (_ARMProxyContract *ARMProxyContractCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ARMProxyContract.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ARMProxyContract *ARMProxyContractSession) Owner() (common.Address, error) {
+ return _ARMProxyContract.Contract.Owner(&_ARMProxyContract.CallOpts)
+}
+
+func (_ARMProxyContract *ARMProxyContractCallerSession) Owner() (common.Address, error) {
+ return _ARMProxyContract.Contract.Owner(&_ARMProxyContract.CallOpts)
+}
+
+func (_ARMProxyContract *ARMProxyContractCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _ARMProxyContract.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_ARMProxyContract *ARMProxyContractSession) TypeAndVersion() (string, error) {
+ return _ARMProxyContract.Contract.TypeAndVersion(&_ARMProxyContract.CallOpts)
+}
+
+func (_ARMProxyContract *ARMProxyContractCallerSession) TypeAndVersion() (string, error) {
+ return _ARMProxyContract.Contract.TypeAndVersion(&_ARMProxyContract.CallOpts)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ARMProxyContract.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_ARMProxyContract *ARMProxyContractSession) AcceptOwnership() (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.AcceptOwnership(&_ARMProxyContract.TransactOpts)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.AcceptOwnership(&_ARMProxyContract.TransactOpts)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactor) SetARM(opts *bind.TransactOpts, arm common.Address) (*types.Transaction, error) {
+ return _ARMProxyContract.contract.Transact(opts, "setARM", arm)
+}
+
+func (_ARMProxyContract *ARMProxyContractSession) SetARM(arm common.Address) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.SetARM(&_ARMProxyContract.TransactOpts, arm)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactorSession) SetARM(arm common.Address) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.SetARM(&_ARMProxyContract.TransactOpts, arm)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _ARMProxyContract.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_ARMProxyContract *ARMProxyContractSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.TransferOwnership(&_ARMProxyContract.TransactOpts, to)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.TransferOwnership(&_ARMProxyContract.TransactOpts, to)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) {
+ return _ARMProxyContract.contract.RawTransact(opts, calldata)
+}
+
+func (_ARMProxyContract *ARMProxyContractSession) Fallback(calldata []byte) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.Fallback(&_ARMProxyContract.TransactOpts, calldata)
+}
+
+func (_ARMProxyContract *ARMProxyContractTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) {
+ return _ARMProxyContract.Contract.Fallback(&_ARMProxyContract.TransactOpts, calldata)
+}
+
+type ARMProxyContractARMSetIterator struct {
+ Event *ARMProxyContractARMSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMProxyContractARMSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMProxyContractARMSet)
+ 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(ARMProxyContractARMSet)
+ 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 *ARMProxyContractARMSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMProxyContractARMSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMProxyContractARMSet struct {
+ Arm common.Address
+ Raw types.Log
+}
+
+func (_ARMProxyContract *ARMProxyContractFilterer) FilterARMSet(opts *bind.FilterOpts) (*ARMProxyContractARMSetIterator, error) {
+
+ logs, sub, err := _ARMProxyContract.contract.FilterLogs(opts, "ARMSet")
+ if err != nil {
+ return nil, err
+ }
+ return &ARMProxyContractARMSetIterator{contract: _ARMProxyContract.contract, event: "ARMSet", logs: logs, sub: sub}, nil
+}
+
+func (_ARMProxyContract *ARMProxyContractFilterer) WatchARMSet(opts *bind.WatchOpts, sink chan<- *ARMProxyContractARMSet) (event.Subscription, error) {
+
+ logs, sub, err := _ARMProxyContract.contract.WatchLogs(opts, "ARMSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMProxyContractARMSet)
+ if err := _ARMProxyContract.contract.UnpackLog(event, "ARMSet", 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 (_ARMProxyContract *ARMProxyContractFilterer) ParseARMSet(log types.Log) (*ARMProxyContractARMSet, error) {
+ event := new(ARMProxyContractARMSet)
+ if err := _ARMProxyContract.contract.UnpackLog(event, "ARMSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMProxyContractOwnershipTransferRequestedIterator struct {
+ Event *ARMProxyContractOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMProxyContractOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMProxyContractOwnershipTransferRequested)
+ 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(ARMProxyContractOwnershipTransferRequested)
+ 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 *ARMProxyContractOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMProxyContractOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMProxyContractOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_ARMProxyContract *ARMProxyContractFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMProxyContractOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ARMProxyContract.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMProxyContractOwnershipTransferRequestedIterator{contract: _ARMProxyContract.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_ARMProxyContract *ARMProxyContractFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *ARMProxyContractOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ARMProxyContract.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMProxyContractOwnershipTransferRequested)
+ if err := _ARMProxyContract.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_ARMProxyContract *ARMProxyContractFilterer) ParseOwnershipTransferRequested(log types.Log) (*ARMProxyContractOwnershipTransferRequested, error) {
+ event := new(ARMProxyContractOwnershipTransferRequested)
+ if err := _ARMProxyContract.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ARMProxyContractOwnershipTransferredIterator struct {
+ Event *ARMProxyContractOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ARMProxyContractOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ARMProxyContractOwnershipTransferred)
+ 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(ARMProxyContractOwnershipTransferred)
+ 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 *ARMProxyContractOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *ARMProxyContractOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ARMProxyContractOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_ARMProxyContract *ARMProxyContractFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMProxyContractOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ARMProxyContract.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ARMProxyContractOwnershipTransferredIterator{contract: _ARMProxyContract.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_ARMProxyContract *ARMProxyContractFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *ARMProxyContractOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ARMProxyContract.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ARMProxyContractOwnershipTransferred)
+ if err := _ARMProxyContract.contract.UnpackLog(event, "OwnershipTransferred", 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 (_ARMProxyContract *ARMProxyContractFilterer) ParseOwnershipTransferred(log types.Log) (*ARMProxyContractOwnershipTransferred, error) {
+ event := new(ARMProxyContractOwnershipTransferred)
+ if err := _ARMProxyContract.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_ARMProxyContract *ARMProxyContract) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _ARMProxyContract.abi.Events["ARMSet"].ID:
+ return _ARMProxyContract.ParseARMSet(log)
+ case _ARMProxyContract.abi.Events["OwnershipTransferRequested"].ID:
+ return _ARMProxyContract.ParseOwnershipTransferRequested(log)
+ case _ARMProxyContract.abi.Events["OwnershipTransferred"].ID:
+ return _ARMProxyContract.ParseOwnershipTransferred(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (ARMProxyContractARMSet) Topic() common.Hash {
+ return common.HexToHash("0xef31f568d741a833c6a9dc85a6e1c65e06fa772740d5dc94d1da21827a4e0cab")
+}
+
+func (ARMProxyContractOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (ARMProxyContractOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (_ARMProxyContract *ARMProxyContract) Address() common.Address {
+ return _ARMProxyContract.address
+}
+
+type ARMProxyContractInterface interface {
+ GetARM(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)
+
+ SetARM(opts *bind.TransactOpts, arm common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error)
+
+ FilterARMSet(opts *bind.FilterOpts) (*ARMProxyContractARMSetIterator, error)
+
+ WatchARMSet(opts *bind.WatchOpts, sink chan<- *ARMProxyContractARMSet) (event.Subscription, error)
+
+ ParseARMSet(log types.Log) (*ARMProxyContractARMSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMProxyContractOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *ARMProxyContractOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*ARMProxyContractOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ARMProxyContractOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *ARMProxyContractOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*ARMProxyContractOwnershipTransferred, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/burn_from_mint_token_pool/burn_from_mint_token_pool.go b/core/gethwrappers/ccip/generated/burn_from_mint_token_pool/burn_from_mint_token_pool.go
new file mode 100644
index 00000000000..28e67b0dff7
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/burn_from_mint_token_pool/burn_from_mint_token_pool.go
@@ -0,0 +1,2780 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package burn_from_mint_token_pool
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type PoolLockOrBurnInV1 struct {
+ Receiver []byte
+ RemoteChainSelector uint64
+ OriginalSender common.Address
+ Amount *big.Int
+ LocalToken common.Address
+}
+
+type PoolLockOrBurnOutV1 struct {
+ DestTokenAddress []byte
+ DestPoolData []byte
+}
+
+type PoolReleaseOrMintInV1 struct {
+ OriginalSender []byte
+ RemoteChainSelector uint64
+ Receiver common.Address
+ Amount *big.Int
+ LocalToken common.Address
+ SourcePoolAddress []byte
+ SourcePoolData []byte
+ OffchainTokenData []byte
+}
+
+type PoolReleaseOrMintOutV1 struct {
+ DestinationAmount *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ RemotePoolAddress []byte
+ RemoteTokenAddress []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var BurnFromMintTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIBurnMintERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRateLimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidSourcePoolAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remoteToken\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousPoolAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"RemotePoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"remoteTokenAddress\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemotePool\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemoteToken\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRmnProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"isSupportedToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structPool.LockOrBurnInV1\",\"name\":\"lockOrBurnIn\",\"type\":\"tuple\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destPoolData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.LockOrBurnOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainTokenData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.ReleaseOrMintInV1\",\"name\":\"releaseOrMintIn\",\"type\":\"tuple\"}],\"name\":\"releaseOrMint\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destinationAmount\",\"type\":\"uint256\"}],\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"setRemotePool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x60e06040523480156200001157600080fd5b50604051620043d9380380620043d98339810160408190526200003491620008c0565b8383838333806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c2816200018f565b5050506001600160a01b0384161580620000e357506001600160a01b038116155b80620000f657506001600160a01b038216155b1562000115576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c05262000168576040805160008152602081019091526200016890846200023a565b5062000185925050506001600160a01b0385163060001962000397565b5050505062000afc565b336001600160a01b03821603620001e95760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c0516200025b576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002e65760008382815181106200027f576200027f620009d0565b60209081029190910101519050620002996002826200047d565b15620002dc576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506001016200025e565b5060005b8151811015620003925760008282815181106200030b576200030b620009d0565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000337575062000389565b620003446002826200049d565b1562000387576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101620002ea565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015620003e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200040f9190620009e6565b6200041b919062000a16565b604080516001600160a01b038616602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091529192506200047791869190620004b416565b50505050565b600062000494836001600160a01b03841662000585565b90505b92915050565b600062000494836001600160a01b03841662000689565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65649082015260009062000503906001600160a01b038516908490620006db565b80519091501562000392578080602001905181019062000524919062000a2c565b620003925760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000086565b600081815260018301602052604081205480156200067e576000620005ac60018362000a57565b8554909150600090620005c29060019062000a57565b90508181146200062e576000866000018281548110620005e657620005e6620009d0565b90600052602060002001549050808760000184815481106200060c576200060c620009d0565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000642576200064262000a6d565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000497565b600091505062000497565b6000818152600183016020526040812054620006d25750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000497565b50600062000497565b6060620006ec8484600085620006f4565b949350505050565b606082471015620007575760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000086565b600080866001600160a01b0316858760405162000775919062000aa9565b60006040518083038185875af1925050503d8060008114620007b4576040519150601f19603f3d011682016040523d82523d6000602084013e620007b9565b606091505b509092509050620007cd87838387620007d8565b979650505050505050565b606083156200084c57825160000362000844576001600160a01b0385163b620008445760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000086565b5081620006ec565b620006ec8383815115620008635781518083602001fd5b8060405162461bcd60e51b815260040162000086919062000ac7565b6001600160a01b03811681146200089557600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b8051620008bb816200087f565b919050565b60008060008060808587031215620008d757600080fd5b8451620008e4816200087f565b602086810151919550906001600160401b03808211156200090457600080fd5b818801915088601f8301126200091957600080fd5b8151818111156200092e576200092e62000898565b8060051b604051601f19603f8301168101818110858211171562000956576200095662000898565b60405291825284820192508381018501918b8311156200097557600080fd5b938501935b828510156200099e576200098e85620008ae565b845293850193928501926200097a565b809850505050505050620009b560408601620008ae565b9150620009c560608601620008ae565b905092959194509250565b634e487b7160e01b600052603260045260246000fd5b600060208284031215620009f957600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111562000497576200049762000a00565b60006020828403121562000a3f57600080fd5b8151801515811462000a5057600080fd5b9392505050565b8181038181111562000497576200049762000a00565b634e487b7160e01b600052603160045260246000fd5b60005b8381101562000aa057818101518382015260200162000a86565b50506000910152565b6000825162000abd81846020870162000a83565b9190910192915050565b602081526000825180602084015262000ae881604085016020870162000a83565b601f01601f19169190910160400192915050565b60805160a05160c05161386062000b79600039600081816104960152818161164501526120290152600081816104700152818161147601526118fb01526000818161022301528181610278015281816106ba015281816113960152818161181b01528181611a1301528181611fbf015261221401526138606000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c8063a7cd63b7116100e3578063c75eea9c1161008c578063dc0bd97111610066578063dc0bd9711461046e578063e0351e1314610494578063f2fde38b146104ba57600080fd5b8063c75eea9c14610435578063cf7401f314610448578063db6327dc1461045b57600080fd5b8063b7946580116100bd578063b7946580146103fa578063c0d786551461040d578063c4bffe2b1461042057600080fd5b8063a7cd63b714610358578063af58d59f1461036d578063b0f479a1146103dc57600080fd5b806354c8a4f3116101455780638926f54f1161011f5780638926f54f146103075780638da5cb5b1461031a5780639a4575b91461033857600080fd5b806354c8a4f3146102d757806378a010b2146102ec57806379ba5097146102ff57600080fd5b806321df0da71161017657806321df0da714610221578063240028e81461026857806339077537146102b557600080fd5b806301ffc9a71461019d5780630a2fd493146101c5578063181f5a77146101e5575b600080fd5b6101b06101ab3660046129b7565b6104cd565b60405190151581526020015b60405180910390f35b6101d86101d3366004612a16565b6105b2565b6040516101bc9190612a95565b6101d86040518060400160405280601f81526020017f4275726e46726f6d4d696e74546f6b656e506f6f6c20312e352e302d6465760081525081565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b6101b0610276366004612ad5565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b6102c86102c3366004612af2565b610662565b604051905181526020016101bc565b6102ea6102e5366004612b7a565b6107bd565b005b6102ea6102fa366004612be6565b610838565b6102ea6109ac565b6101b0610315366004612a16565b610aa9565b60005473ffffffffffffffffffffffffffffffffffffffff16610243565b61034b610346366004612c69565b610ac0565b6040516101bc9190612ca4565b610360610b67565b6040516101bc9190612d04565b61038061037b366004612a16565b610b78565b6040516101bc919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610243565b6101d8610408366004612a16565b610c4d565b6102ea61041b366004612ad5565b610c78565b610428610d53565b6040516101bc9190612d5e565b610380610443366004612a16565b610e0b565b6102ea610456366004612ec6565b610edd565b6102ea610469366004612f0b565b610ef5565b7f0000000000000000000000000000000000000000000000000000000000000000610243565b7f00000000000000000000000000000000000000000000000000000000000000006101b0565b6102ea6104c8366004612ad5565b61137b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf00000000000000000000000000000000000000000000000000000000148061056057507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b806105ac57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b67ffffffffffffffff811660009081526007602052604090206004018054606091906105dd90612f4d565b80601f016020809104026020016040519081016040528092919081815260200182805461060990612f4d565b80156106565780601f1061062b57610100808354040283529160200191610656565b820191906000526020600020905b81548152906001019060200180831161063957829003601f168201915b50505050509050919050565b60408051602081019091526000815261068261067d8361304b565b61138f565b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152606083013560248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906340c10f1990604401600060405180830381600087803b15801561071357600080fd5b505af1158015610727573d6000803e3d6000fd5b5061073c925050506060830160408401612ad5565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0846060013560405161079e91815260200190565b60405180910390a3506040805160208101909152606090910135815290565b6107c56115c0565b6108328484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061164392505050565b50505050565b6108406115c0565b61084983610aa9565b610890576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b67ffffffffffffffff8316600090815260076020526040812060040180546108b790612f4d565b80601f01602080910402602001604051908101604052809291908181526020018280546108e390612f4d565b80156109305780601f1061090557610100808354040283529160200191610930565b820191906000526020600020905b81548152906001019060200180831161091357829003601f168201915b5050505067ffffffffffffffff861660009081526007602052604090209192505060040161095f838583613190565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf82858560405161099e939291906132aa565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a2d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610887565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60006105ac600567ffffffffffffffff84166117f9565b6040805180820190915260608082526020820152610ae5610ae08361330e565b611814565b610af282606001356119de565b6040516060830135815233907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a26040518060400160405280610b4c8460200160208101906104089190612a16565b81526040805160208181019092526000815291015292915050565b6060610b736002611a87565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260039091015480841660608301529190910490911660808201526105ac90611a94565b67ffffffffffffffff811660009081526007602052604090206005018054606091906105dd90612f4d565b610c806115c0565b73ffffffffffffffffffffffffffffffffffffffff8116610ccd576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684910160405180910390a15050565b60606000610d616005611a87565b90506000815167ffffffffffffffff811115610d7f57610d7f612da0565b604051908082528060200260200182016040528015610da8578160200160208202803683370190505b50905060005b8251811015610e0457828181518110610dc957610dc96133b0565b6020026020010151828281518110610de357610de36133b0565b67ffffffffffffffff90921660209283029190910190910152600101610dae565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526105ac90611a94565b610ee56115c0565b610ef0838383611b46565b505050565b610efd6115c0565b60005b81811015610ef0576000838383818110610f1c57610f1c6133b0565b9050602002810190610f2e91906133df565b610f379061341d565b9050610f4c8160800151826020015115611c30565b610f5f8160a00151826020015115611c30565b80602001511561125b578051610f819060059067ffffffffffffffff16611d69565b610fc65780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610887565b6040810151511580610fdb5750606081015151155b15611012576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c179091169615150295909517909855908101519401519381169316909102919091176003820155915190919060048201906111f390826134d1565b506060820151600582019061120890826134d1565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2955061124e94939291906135eb565b60405180910390a1611372565b80516112739060059067ffffffffffffffff16611d75565b6112b85780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610887565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906113216004830182612969565b61132f600583016000612969565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b50600101610f00565b6113836115c0565b61138c81611d81565b50565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146114245760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610887565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa1580156114d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f69190613684565b1561152d576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61153a8160200151611e76565b600061154982602001516105b2565b905080516000148061156d575080805190602001208260a001518051906020012014155b156115aa578160a001516040517f24eb47e50000000000000000000000000000000000000000000000000000000081526004016108879190612a95565b6115bc82602001518360600151611f9c565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611641576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610887565b565b7f000000000000000000000000000000000000000000000000000000000000000061169a576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82518110156117305760008382815181106116ba576116ba6133b0565b602002602001015190506116d8816002611fe390919063ffffffff16565b156117275760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b5060010161169d565b5060005b8151811015610ef0576000828281518110611751576117516133b0565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361179557506117f1565b6117a0600282612005565b156117ef5760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101611734565b600081815260018301602052604081205415155b9392505050565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146118a95760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610887565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197b9190613684565b156119b2576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119bf8160400151612027565b6119cc81602001516120a6565b61138c816020015182606001516121f4565b6040517f79cc6790000000000000000000000000000000000000000000000000000000008152306004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906379cc679090604401600060405180830381600087803b158015611a6c57600080fd5b505af1158015611a80573d6000803e3d6000fd5b5050505050565b6060600061180d83612238565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611b2282606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611b0691906136d0565b85608001516fffffffffffffffffffffffffffffffff16612293565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b611b4f83610aa9565b611b91576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401610887565b611b9c826000611c30565b67ffffffffffffffff83166000908152600760205260409020611bbf90836122bd565b611bca816000611c30565b67ffffffffffffffff83166000908152600760205260409020611bf090600201826122bd565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051611c23939291906136e3565b60405180910390a1505050565b815115611cf75781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580611c86575060408201516fffffffffffffffffffffffffffffffff16155b15611cbf57816040517f8020d1240000000000000000000000000000000000000000000000000000000081526004016108879190613766565b80156115bc576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff16151580611d30575060208201516fffffffffffffffffffffffffffffffff1615155b156115bc57816040517fd68af9cc0000000000000000000000000000000000000000000000000000000081526004016108879190613766565b600061180d838361245f565b600061180d83836124ae565b3373ffffffffffffffffffffffffffffffffffffffff821603611e00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610887565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b611e7f81610aa9565b611ec1576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610887565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015611f40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f649190613684565b61138c576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610887565b67ffffffffffffffff821660009081526007602052604090206115bc90600201827f00000000000000000000000000000000000000000000000000000000000000006125a1565b600061180d8373ffffffffffffffffffffffffffffffffffffffff84166124ae565b600061180d8373ffffffffffffffffffffffffffffffffffffffff841661245f565b7f00000000000000000000000000000000000000000000000000000000000000001561138c57612058600282612924565b61138c576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610887565b6120af81610aa9565b6120f1576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610887565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa15801561216a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218e91906137a2565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461138c576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610887565b67ffffffffffffffff821660009081526007602052604090206115bc90827f00000000000000000000000000000000000000000000000000000000000000006125a1565b60608160000180548060200260200160405190810160405280929190818152602001828054801561065657602002820191906000526020600020905b8154815260200190600101908083116122745750505050509050919050565b60006122b2856122a384866137bf565b6122ad90876137d6565b612953565b90505b949350505050565b81546000906122e690700100000000000000000000000000000000900463ffffffff16426136d0565b90508015612388576001830154835461232e916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612293565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b602082015183546123ae916fffffffffffffffffffffffffffffffff9081169116612953565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990611c23908490613766565b60008181526001830160205260408120546124a6575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105ac565b5060006105ac565b600081815260018301602052604081205480156125975760006124d26001836136d0565b85549091506000906124e6906001906136d0565b905081811461254b576000866000018281548110612506576125066133b0565b9060005260206000200154905080876000018481548110612529576125296133b0565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061255c5761255c6137e9565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105ac565b60009150506105ac565b825474010000000000000000000000000000000000000000900460ff1615806125c8575081155b156125d257505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061261890700100000000000000000000000000000000900463ffffffff16426136d0565b905080156126d8578183111561265a576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546126949083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612293565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b8482101561278f5773ffffffffffffffffffffffffffffffffffffffff8416612737576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610887565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff85166044820152606401610887565b848310156128a25760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906127d390826136d0565b6127dd878a6136d0565b6127e791906137d6565b6127f19190613818565b905073ffffffffffffffffffffffffffffffffffffffff861661284a576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610887565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff87166044820152606401610887565b6128ac85846136d0565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561180d565b6000818310612962578161180d565b5090919050565b50805461297590612f4d565b6000825580601f10612985575050565b601f01602090049060005260206000209081019061138c91905b808211156129b3576000815560010161299f565b5090565b6000602082840312156129c957600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461180d57600080fd5b803567ffffffffffffffff81168114612a1157600080fd5b919050565b600060208284031215612a2857600080fd5b61180d826129f9565b6000815180845260005b81811015612a5757602081850181015186830182015201612a3b565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061180d6020830184612a31565b73ffffffffffffffffffffffffffffffffffffffff8116811461138c57600080fd5b8035612a1181612aa8565b600060208284031215612ae757600080fd5b813561180d81612aa8565b600060208284031215612b0457600080fd5b813567ffffffffffffffff811115612b1b57600080fd5b8201610100818503121561180d57600080fd5b60008083601f840112612b4057600080fd5b50813567ffffffffffffffff811115612b5857600080fd5b6020830191508360208260051b8501011115612b7357600080fd5b9250929050565b60008060008060408587031215612b9057600080fd5b843567ffffffffffffffff80821115612ba857600080fd5b612bb488838901612b2e565b90965094506020870135915080821115612bcd57600080fd5b50612bda87828801612b2e565b95989497509550505050565b600080600060408486031215612bfb57600080fd5b612c04846129f9565b9250602084013567ffffffffffffffff80821115612c2157600080fd5b818601915086601f830112612c3557600080fd5b813581811115612c4457600080fd5b876020828501011115612c5657600080fd5b6020830194508093505050509250925092565b600060208284031215612c7b57600080fd5b813567ffffffffffffffff811115612c9257600080fd5b820160a0818503121561180d57600080fd5b602081526000825160406020840152612cc06060840182612a31565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016040850152612cfb8282612a31565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015612d5257835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612d20565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612d5257835167ffffffffffffffff1683529284019291840191600101612d7a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715612df357612df3612da0565b60405290565b60405160c0810167ffffffffffffffff81118282101715612df357612df3612da0565b801515811461138c57600080fd5b8035612a1181612e1c565b80356fffffffffffffffffffffffffffffffff81168114612a1157600080fd5b600060608284031215612e6757600080fd5b6040516060810181811067ffffffffffffffff82111715612e8a57612e8a612da0565b6040529050808235612e9b81612e1c565b8152612ea960208401612e35565b6020820152612eba60408401612e35565b60408201525092915050565b600080600060e08486031215612edb57600080fd5b612ee4846129f9565b9250612ef38560208601612e55565b9150612f028560808601612e55565b90509250925092565b60008060208385031215612f1e57600080fd5b823567ffffffffffffffff811115612f3557600080fd5b612f4185828601612b2e565b90969095509350505050565b600181811c90821680612f6157607f821691505b602082108103612f9a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f830112612fb157600080fd5b813567ffffffffffffffff80821115612fcc57612fcc612da0565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561301257613012612da0565b8160405283815286602085880101111561302b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000610100823603121561305e57600080fd5b613066612dcf565b823567ffffffffffffffff8082111561307e57600080fd5b61308a36838701612fa0565b8352613098602086016129f9565b60208401526130a960408601612aca565b6040840152606085013560608401526130c460808601612aca565b608084015260a08501359150808211156130dd57600080fd5b6130e936838701612fa0565b60a084015260c085013591508082111561310257600080fd5b61310e36838701612fa0565b60c084015260e085013591508082111561312757600080fd5b5061313436828601612fa0565b60e08301525092915050565b601f821115610ef0576000816000526020600020601f850160051c810160208610156131695750805b601f850160051c820191505b8181101561318857828155600101613175565b505050505050565b67ffffffffffffffff8311156131a8576131a8612da0565b6131bc836131b68354612f4d565b83613140565b6000601f84116001811461320e57600085156131d85750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611a80565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101561325d578685013582556020948501946001909201910161323d565b5086821015613298577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b6040815260006132bd6040830186612a31565b82810360208401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116820101915050949350505050565b600060a0823603121561332057600080fd5b60405160a0810167ffffffffffffffff828210818311171561334457613344612da0565b81604052843591508082111561335957600080fd5b5061336636828601612fa0565b825250613375602084016129f9565b6020820152604083013561338881612aa8565b60408201526060838101359082015260808301356133a581612aa8565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec183360301811261341357600080fd5b9190910192915050565b6000610140823603121561343057600080fd5b613438612df9565b613441836129f9565b815261344f60208401612e2a565b6020820152604083013567ffffffffffffffff8082111561346f57600080fd5b61347b36838701612fa0565b6040840152606085013591508082111561349457600080fd5b506134a136828601612fa0565b6060830152506134b43660808501612e55565b60808201526134c63660e08501612e55565b60a082015292915050565b815167ffffffffffffffff8111156134eb576134eb612da0565b6134ff816134f98454612f4d565b84613140565b602080601f831160018114613552576000841561351c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613188565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561359f57888601518255948401946001909101908401613580565b50858210156135db57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff8716835280602084015261360f81840187612a31565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff908116606087015290870151166080850152915061364d9050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e0830152612cfb565b60006020828403121561369657600080fd5b815161180d81612e1c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105ac576105ac6136a1565b67ffffffffffffffff8416815260e0810161372f60208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c08301526122b5565b606081016105ac82848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b6000602082840312156137b457600080fd5b815161180d81612aa8565b80820281158282048414176105ac576105ac6136a1565b808201808211156105ac576105ac6136a1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008261384e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea164736f6c6343000818000a",
+}
+
+var BurnFromMintTokenPoolABI = BurnFromMintTokenPoolMetaData.ABI
+
+var BurnFromMintTokenPoolBin = BurnFromMintTokenPoolMetaData.Bin
+
+func DeployBurnFromMintTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, rmnProxy common.Address, router common.Address) (common.Address, *types.Transaction, *BurnFromMintTokenPool, error) {
+ parsed, err := BurnFromMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BurnFromMintTokenPoolBin), backend, token, allowlist, rmnProxy, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &BurnFromMintTokenPool{address: address, abi: *parsed, BurnFromMintTokenPoolCaller: BurnFromMintTokenPoolCaller{contract: contract}, BurnFromMintTokenPoolTransactor: BurnFromMintTokenPoolTransactor{contract: contract}, BurnFromMintTokenPoolFilterer: BurnFromMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+type BurnFromMintTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ BurnFromMintTokenPoolCaller
+ BurnFromMintTokenPoolTransactor
+ BurnFromMintTokenPoolFilterer
+}
+
+type BurnFromMintTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type BurnFromMintTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type BurnFromMintTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type BurnFromMintTokenPoolSession struct {
+ Contract *BurnFromMintTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type BurnFromMintTokenPoolCallerSession struct {
+ Contract *BurnFromMintTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type BurnFromMintTokenPoolTransactorSession struct {
+ Contract *BurnFromMintTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type BurnFromMintTokenPoolRaw struct {
+ Contract *BurnFromMintTokenPool
+}
+
+type BurnFromMintTokenPoolCallerRaw struct {
+ Contract *BurnFromMintTokenPoolCaller
+}
+
+type BurnFromMintTokenPoolTransactorRaw struct {
+ Contract *BurnFromMintTokenPoolTransactor
+}
+
+func NewBurnFromMintTokenPool(address common.Address, backend bind.ContractBackend) (*BurnFromMintTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(BurnFromMintTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindBurnFromMintTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPool{address: address, abi: abi, BurnFromMintTokenPoolCaller: BurnFromMintTokenPoolCaller{contract: contract}, BurnFromMintTokenPoolTransactor: BurnFromMintTokenPoolTransactor{contract: contract}, BurnFromMintTokenPoolFilterer: BurnFromMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewBurnFromMintTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*BurnFromMintTokenPoolCaller, error) {
+ contract, err := bindBurnFromMintTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolCaller{contract: contract}, nil
+}
+
+func NewBurnFromMintTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*BurnFromMintTokenPoolTransactor, error) {
+ contract, err := bindBurnFromMintTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewBurnFromMintTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*BurnFromMintTokenPoolFilterer, error) {
+ contract, err := bindBurnFromMintTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindBurnFromMintTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := BurnFromMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnFromMintTokenPool.Contract.BurnFromMintTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.BurnFromMintTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.BurnFromMintTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnFromMintTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.GetAllowList(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.GetAllowList(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _BurnFromMintTokenPool.Contract.GetAllowListEnabled(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _BurnFromMintTokenPool.Contract.GetAllowListEnabled(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnFromMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnFromMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnFromMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnFromMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getRemotePool", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnFromMintTokenPool.Contract.GetRemotePool(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnFromMintTokenPool.Contract.GetRemotePool(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnFromMintTokenPool.Contract.GetRemoteToken(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnFromMintTokenPool.Contract.GetRemoteToken(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getRmnProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetRmnProxy() (common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.GetRmnProxy(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetRmnProxy() (common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.GetRmnProxy(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetRouter() (common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.GetRouter(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.GetRouter(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnFromMintTokenPool.Contract.GetSupportedChains(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnFromMintTokenPool.Contract.GetSupportedChains(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) GetToken() (common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.GetToken(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.GetToken(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnFromMintTokenPool.Contract.IsSupportedChain(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnFromMintTokenPool.Contract.IsSupportedChain(&_BurnFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "isSupportedToken", token)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _BurnFromMintTokenPool.Contract.IsSupportedToken(&_BurnFromMintTokenPool.CallOpts, token)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _BurnFromMintTokenPool.Contract.IsSupportedToken(&_BurnFromMintTokenPool.CallOpts, token)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) Owner() (common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.Owner(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _BurnFromMintTokenPool.Contract.Owner(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnFromMintTokenPool.Contract.SupportsInterface(&_BurnFromMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnFromMintTokenPool.Contract.SupportsInterface(&_BurnFromMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _BurnFromMintTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) TypeAndVersion() (string, error) {
+ return _BurnFromMintTokenPool.Contract.TypeAndVersion(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _BurnFromMintTokenPool.Contract.TypeAndVersion(&_BurnFromMintTokenPool.CallOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.AcceptOwnership(&_BurnFromMintTokenPool.TransactOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.AcceptOwnership(&_BurnFromMintTokenPool.TransactOpts)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnFromMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnFromMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.ApplyChainUpdates(&_BurnFromMintTokenPool.TransactOpts, chains)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.ApplyChainUpdates(&_BurnFromMintTokenPool.TransactOpts, chains)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "lockOrBurn", lockOrBurnIn)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.LockOrBurn(&_BurnFromMintTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.LockOrBurn(&_BurnFromMintTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "releaseOrMint", releaseOrMintIn)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.ReleaseOrMint(&_BurnFromMintTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.ReleaseOrMint(&_BurnFromMintTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnFromMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnFromMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "setRemotePool", remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.SetRemotePool(&_BurnFromMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.SetRemotePool(&_BurnFromMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.SetRouter(&_BurnFromMintTokenPool.TransactOpts, newRouter)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.SetRouter(&_BurnFromMintTokenPool.TransactOpts, newRouter)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.TransferOwnership(&_BurnFromMintTokenPool.TransactOpts, to)
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnFromMintTokenPool.Contract.TransferOwnership(&_BurnFromMintTokenPool.TransactOpts, to)
+}
+
+type BurnFromMintTokenPoolAllowListAddIterator struct {
+ Event *BurnFromMintTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolAllowListAdd)
+ 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(BurnFromMintTokenPoolAllowListAdd)
+ 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 *BurnFromMintTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*BurnFromMintTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolAllowListAddIterator{contract: _BurnFromMintTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolAllowListAdd)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*BurnFromMintTokenPoolAllowListAdd, error) {
+ event := new(BurnFromMintTokenPoolAllowListAdd)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolAllowListRemoveIterator struct {
+ Event *BurnFromMintTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolAllowListRemove)
+ 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(BurnFromMintTokenPoolAllowListRemove)
+ 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 *BurnFromMintTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*BurnFromMintTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolAllowListRemoveIterator{contract: _BurnFromMintTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolAllowListRemove)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*BurnFromMintTokenPoolAllowListRemove, error) {
+ event := new(BurnFromMintTokenPoolAllowListRemove)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolBurnedIterator struct {
+ Event *BurnFromMintTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolBurned)
+ 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(BurnFromMintTokenPoolBurned)
+ 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 *BurnFromMintTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnFromMintTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolBurnedIterator{contract: _BurnFromMintTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolBurned)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "Burned", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseBurned(log types.Log) (*BurnFromMintTokenPoolBurned, error) {
+ event := new(BurnFromMintTokenPoolBurned)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolChainAddedIterator struct {
+ Event *BurnFromMintTokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolChainAdded)
+ 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(BurnFromMintTokenPoolChainAdded)
+ 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 *BurnFromMintTokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*BurnFromMintTokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolChainAddedIterator{contract: _BurnFromMintTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolChainAdded)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseChainAdded(log types.Log) (*BurnFromMintTokenPoolChainAdded, error) {
+ event := new(BurnFromMintTokenPoolChainAdded)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolChainConfiguredIterator struct {
+ Event *BurnFromMintTokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolChainConfigured)
+ 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(BurnFromMintTokenPoolChainConfigured)
+ 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 *BurnFromMintTokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*BurnFromMintTokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolChainConfiguredIterator{contract: _BurnFromMintTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolChainConfigured)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseChainConfigured(log types.Log) (*BurnFromMintTokenPoolChainConfigured, error) {
+ event := new(BurnFromMintTokenPoolChainConfigured)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolChainRemovedIterator struct {
+ Event *BurnFromMintTokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolChainRemoved)
+ 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(BurnFromMintTokenPoolChainRemoved)
+ 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 *BurnFromMintTokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*BurnFromMintTokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolChainRemovedIterator{contract: _BurnFromMintTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolChainRemoved)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseChainRemoved(log types.Log) (*BurnFromMintTokenPoolChainRemoved, error) {
+ event := new(BurnFromMintTokenPoolChainRemoved)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolConfigChangedIterator struct {
+ Event *BurnFromMintTokenPoolConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolConfigChanged)
+ 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(BurnFromMintTokenPoolConfigChanged)
+ 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 *BurnFromMintTokenPoolConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*BurnFromMintTokenPoolConfigChangedIterator, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolConfigChangedIterator{contract: _BurnFromMintTokenPool.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolConfigChanged)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "ConfigChanged", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseConfigChanged(log types.Log) (*BurnFromMintTokenPoolConfigChanged, error) {
+ event := new(BurnFromMintTokenPoolConfigChanged)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolLockedIterator struct {
+ Event *BurnFromMintTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolLocked)
+ 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(BurnFromMintTokenPoolLocked)
+ 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 *BurnFromMintTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnFromMintTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolLockedIterator{contract: _BurnFromMintTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolLocked)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "Locked", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseLocked(log types.Log) (*BurnFromMintTokenPoolLocked, error) {
+ event := new(BurnFromMintTokenPoolLocked)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolMintedIterator struct {
+ Event *BurnFromMintTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolMinted)
+ 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(BurnFromMintTokenPoolMinted)
+ 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 *BurnFromMintTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnFromMintTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolMintedIterator{contract: _BurnFromMintTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolMinted)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "Minted", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseMinted(log types.Log) (*BurnFromMintTokenPoolMinted, error) {
+ event := new(BurnFromMintTokenPoolMinted)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *BurnFromMintTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolOwnershipTransferRequested)
+ 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(BurnFromMintTokenPoolOwnershipTransferRequested)
+ 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 *BurnFromMintTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnFromMintTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolOwnershipTransferRequestedIterator{contract: _BurnFromMintTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*BurnFromMintTokenPoolOwnershipTransferRequested, error) {
+ event := new(BurnFromMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolOwnershipTransferredIterator struct {
+ Event *BurnFromMintTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolOwnershipTransferred)
+ 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(BurnFromMintTokenPoolOwnershipTransferred)
+ 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 *BurnFromMintTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnFromMintTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolOwnershipTransferredIterator{contract: _BurnFromMintTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolOwnershipTransferred)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*BurnFromMintTokenPoolOwnershipTransferred, error) {
+ event := new(BurnFromMintTokenPoolOwnershipTransferred)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolReleasedIterator struct {
+ Event *BurnFromMintTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolReleased)
+ 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(BurnFromMintTokenPoolReleased)
+ 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 *BurnFromMintTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnFromMintTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolReleasedIterator{contract: _BurnFromMintTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolReleased)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "Released", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseReleased(log types.Log) (*BurnFromMintTokenPoolReleased, error) {
+ event := new(BurnFromMintTokenPoolReleased)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolRemotePoolSetIterator struct {
+ Event *BurnFromMintTokenPoolRemotePoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolRemotePoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolRemotePoolSet)
+ 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(BurnFromMintTokenPoolRemotePoolSet)
+ 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 *BurnFromMintTokenPoolRemotePoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolRemotePoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolRemotePoolSet struct {
+ RemoteChainSelector uint64
+ PreviousPoolAddress []byte
+ RemotePoolAddress []byte
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnFromMintTokenPoolRemotePoolSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolRemotePoolSetIterator{contract: _BurnFromMintTokenPool.contract, event: "RemotePoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolRemotePoolSet)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "RemotePoolSet", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseRemotePoolSet(log types.Log) (*BurnFromMintTokenPoolRemotePoolSet, error) {
+ event := new(BurnFromMintTokenPoolRemotePoolSet)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "RemotePoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolRouterUpdatedIterator struct {
+ Event *BurnFromMintTokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolRouterUpdated)
+ 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(BurnFromMintTokenPoolRouterUpdated)
+ 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 *BurnFromMintTokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*BurnFromMintTokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolRouterUpdatedIterator{contract: _BurnFromMintTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolRouterUpdated)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*BurnFromMintTokenPoolRouterUpdated, error) {
+ event := new(BurnFromMintTokenPoolRouterUpdated)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnFromMintTokenPoolTokensConsumedIterator struct {
+ Event *BurnFromMintTokenPoolTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnFromMintTokenPoolTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnFromMintTokenPoolTokensConsumed)
+ 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(BurnFromMintTokenPoolTokensConsumed)
+ 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 *BurnFromMintTokenPoolTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnFromMintTokenPoolTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnFromMintTokenPoolTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*BurnFromMintTokenPoolTokensConsumedIterator, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnFromMintTokenPoolTokensConsumedIterator{contract: _BurnFromMintTokenPool.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _BurnFromMintTokenPool.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnFromMintTokenPoolTokensConsumed)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "TokensConsumed", 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 (_BurnFromMintTokenPool *BurnFromMintTokenPoolFilterer) ParseTokensConsumed(log types.Log) (*BurnFromMintTokenPoolTokensConsumed, error) {
+ event := new(BurnFromMintTokenPoolTokensConsumed)
+ if err := _BurnFromMintTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _BurnFromMintTokenPool.abi.Events["AllowListAdd"].ID:
+ return _BurnFromMintTokenPool.ParseAllowListAdd(log)
+ case _BurnFromMintTokenPool.abi.Events["AllowListRemove"].ID:
+ return _BurnFromMintTokenPool.ParseAllowListRemove(log)
+ case _BurnFromMintTokenPool.abi.Events["Burned"].ID:
+ return _BurnFromMintTokenPool.ParseBurned(log)
+ case _BurnFromMintTokenPool.abi.Events["ChainAdded"].ID:
+ return _BurnFromMintTokenPool.ParseChainAdded(log)
+ case _BurnFromMintTokenPool.abi.Events["ChainConfigured"].ID:
+ return _BurnFromMintTokenPool.ParseChainConfigured(log)
+ case _BurnFromMintTokenPool.abi.Events["ChainRemoved"].ID:
+ return _BurnFromMintTokenPool.ParseChainRemoved(log)
+ case _BurnFromMintTokenPool.abi.Events["ConfigChanged"].ID:
+ return _BurnFromMintTokenPool.ParseConfigChanged(log)
+ case _BurnFromMintTokenPool.abi.Events["Locked"].ID:
+ return _BurnFromMintTokenPool.ParseLocked(log)
+ case _BurnFromMintTokenPool.abi.Events["Minted"].ID:
+ return _BurnFromMintTokenPool.ParseMinted(log)
+ case _BurnFromMintTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _BurnFromMintTokenPool.ParseOwnershipTransferRequested(log)
+ case _BurnFromMintTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _BurnFromMintTokenPool.ParseOwnershipTransferred(log)
+ case _BurnFromMintTokenPool.abi.Events["Released"].ID:
+ return _BurnFromMintTokenPool.ParseReleased(log)
+ case _BurnFromMintTokenPool.abi.Events["RemotePoolSet"].ID:
+ return _BurnFromMintTokenPool.ParseRemotePoolSet(log)
+ case _BurnFromMintTokenPool.abi.Events["RouterUpdated"].ID:
+ return _BurnFromMintTokenPool.ParseRouterUpdated(log)
+ case _BurnFromMintTokenPool.abi.Events["TokensConsumed"].ID:
+ return _BurnFromMintTokenPool.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (BurnFromMintTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (BurnFromMintTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (BurnFromMintTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (BurnFromMintTokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2")
+}
+
+func (BurnFromMintTokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (BurnFromMintTokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (BurnFromMintTokenPoolConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (BurnFromMintTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (BurnFromMintTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (BurnFromMintTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (BurnFromMintTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (BurnFromMintTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (BurnFromMintTokenPoolRemotePoolSet) Topic() common.Hash {
+ return common.HexToHash("0xdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf")
+}
+
+func (BurnFromMintTokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (BurnFromMintTokenPoolTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_BurnFromMintTokenPool *BurnFromMintTokenPool) Address() common.Address {
+ return _BurnFromMintTokenPool.address
+}
+
+type BurnFromMintTokenPoolInterface interface {
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRmnProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*BurnFromMintTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*BurnFromMintTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*BurnFromMintTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*BurnFromMintTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnFromMintTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*BurnFromMintTokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*BurnFromMintTokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*BurnFromMintTokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*BurnFromMintTokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*BurnFromMintTokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*BurnFromMintTokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*BurnFromMintTokenPoolChainRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*BurnFromMintTokenPoolConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*BurnFromMintTokenPoolConfigChanged, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnFromMintTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*BurnFromMintTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnFromMintTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*BurnFromMintTokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnFromMintTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*BurnFromMintTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnFromMintTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*BurnFromMintTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnFromMintTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*BurnFromMintTokenPoolReleased, error)
+
+ FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnFromMintTokenPoolRemotePoolSetIterator, error)
+
+ WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRemotePoolSet(log types.Log) (*BurnFromMintTokenPoolRemotePoolSet, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*BurnFromMintTokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*BurnFromMintTokenPoolRouterUpdated, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*BurnFromMintTokenPoolTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnFromMintTokenPoolTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*BurnFromMintTokenPoolTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/burn_mint_token_pool/burn_mint_token_pool.go b/core/gethwrappers/ccip/generated/burn_mint_token_pool/burn_mint_token_pool.go
new file mode 100644
index 00000000000..70e2f9393e1
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/burn_mint_token_pool/burn_mint_token_pool.go
@@ -0,0 +1,2780 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package burn_mint_token_pool
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type PoolLockOrBurnInV1 struct {
+ Receiver []byte
+ RemoteChainSelector uint64
+ OriginalSender common.Address
+ Amount *big.Int
+ LocalToken common.Address
+}
+
+type PoolLockOrBurnOutV1 struct {
+ DestTokenAddress []byte
+ DestPoolData []byte
+}
+
+type PoolReleaseOrMintInV1 struct {
+ OriginalSender []byte
+ RemoteChainSelector uint64
+ Receiver common.Address
+ Amount *big.Int
+ LocalToken common.Address
+ SourcePoolAddress []byte
+ SourcePoolData []byte
+ OffchainTokenData []byte
+}
+
+type PoolReleaseOrMintOutV1 struct {
+ DestinationAmount *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ RemotePoolAddress []byte
+ RemoteTokenAddress []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var BurnMintTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIBurnMintERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRateLimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidSourcePoolAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remoteToken\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousPoolAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"RemotePoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"remoteTokenAddress\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemotePool\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemoteToken\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRmnProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"isSupportedToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structPool.LockOrBurnInV1\",\"name\":\"lockOrBurnIn\",\"type\":\"tuple\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destPoolData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.LockOrBurnOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainTokenData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.ReleaseOrMintInV1\",\"name\":\"releaseOrMintIn\",\"type\":\"tuple\"}],\"name\":\"releaseOrMint\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destinationAmount\",\"type\":\"uint256\"}],\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"setRemotePool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x60e06040523480156200001157600080fd5b5060405162003f8138038062003f8183398101604081905262000034916200054c565b8383838333806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000176565b5050506001600160a01b0384161580620000e357506001600160a01b038116155b80620000f657506001600160a01b038216155b1562000115576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c052620001685760408051600081526020810190915262000168908462000221565b5050505050505050620006aa565b336001600160a01b03821603620001d05760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c05162000242576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002cd5760008382815181106200026657620002666200065c565b60209081029190910101519050620002806002826200037e565b15620002c3576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b5060010162000245565b5060005b815181101562000379576000828281518110620002f257620002f26200065c565b6020026020010151905060006001600160a01b0316816001600160a01b0316036200031e575062000370565b6200032b6002826200039e565b156200036e576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101620002d1565b505050565b600062000395836001600160a01b038416620003b5565b90505b92915050565b600062000395836001600160a01b038416620004b9565b60008181526001830160205260408120548015620004ae576000620003dc60018362000672565b8554909150600090620003f29060019062000672565b90508181146200045e5760008660000182815481106200041657620004166200065c565b90600052602060002001549050808760000184815481106200043c576200043c6200065c565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000472576200047262000694565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000398565b600091505062000398565b6000818152600183016020526040812054620005025750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000398565b50600062000398565b6001600160a01b03811681146200052157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b805162000547816200050b565b919050565b600080600080608085870312156200056357600080fd5b845162000570816200050b565b602086810151919550906001600160401b03808211156200059057600080fd5b818801915088601f830112620005a557600080fd5b815181811115620005ba57620005ba62000524565b8060051b604051601f19603f83011681018181108582111715620005e257620005e262000524565b60405291825284820192508381018501918b8311156200060157600080fd5b938501935b828510156200062a576200061a856200053a565b8452938501939285019262000606565b80985050505050505062000641604086016200053a565b915062000651606086016200053a565b905092959194509250565b634e487b7160e01b600052603260045260246000fd5b818103818111156200039857634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05161385a62000727600039600081816104960152818161164501526120230152600081816104700152818161147601526118fb01526000818161022301528181610278015281816106ba015281816113960152818161181b01528181611a0d01528181611fb9015261220e015261385a6000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c8063a7cd63b7116100e3578063c75eea9c1161008c578063dc0bd97111610066578063dc0bd9711461046e578063e0351e1314610494578063f2fde38b146104ba57600080fd5b8063c75eea9c14610435578063cf7401f314610448578063db6327dc1461045b57600080fd5b8063b7946580116100bd578063b7946580146103fa578063c0d786551461040d578063c4bffe2b1461042057600080fd5b8063a7cd63b714610358578063af58d59f1461036d578063b0f479a1146103dc57600080fd5b806354c8a4f3116101455780638926f54f1161011f5780638926f54f146103075780638da5cb5b1461031a5780639a4575b91461033857600080fd5b806354c8a4f3146102d757806378a010b2146102ec57806379ba5097146102ff57600080fd5b806321df0da71161017657806321df0da714610221578063240028e81461026857806339077537146102b557600080fd5b806301ffc9a71461019d5780630a2fd493146101c5578063181f5a77146101e5575b600080fd5b6101b06101ab3660046129b1565b6104cd565b60405190151581526020015b60405180910390f35b6101d86101d3366004612a10565b6105b2565b6040516101bc9190612a8f565b6101d86040518060400160405280601b81526020017f4275726e4d696e74546f6b656e506f6f6c20312e352e302d646576000000000081525081565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b6101b0610276366004612acf565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b6102c86102c3366004612aec565b610662565b604051905181526020016101bc565b6102ea6102e5366004612b74565b6107bd565b005b6102ea6102fa366004612be0565b610838565b6102ea6109ac565b6101b0610315366004612a10565b610aa9565b60005473ffffffffffffffffffffffffffffffffffffffff16610243565b61034b610346366004612c63565b610ac0565b6040516101bc9190612c9e565b610360610b67565b6040516101bc9190612cfe565b61038061037b366004612a10565b610b78565b6040516101bc919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610243565b6101d8610408366004612a10565b610c4d565b6102ea61041b366004612acf565b610c78565b610428610d53565b6040516101bc9190612d58565b610380610443366004612a10565b610e0b565b6102ea610456366004612ec0565b610edd565b6102ea610469366004612f05565b610ef5565b7f0000000000000000000000000000000000000000000000000000000000000000610243565b7f00000000000000000000000000000000000000000000000000000000000000006101b0565b6102ea6104c8366004612acf565b61137b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf00000000000000000000000000000000000000000000000000000000148061056057507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b806105ac57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b67ffffffffffffffff811660009081526007602052604090206004018054606091906105dd90612f47565b80601f016020809104026020016040519081016040528092919081815260200182805461060990612f47565b80156106565780601f1061062b57610100808354040283529160200191610656565b820191906000526020600020905b81548152906001019060200180831161063957829003601f168201915b50505050509050919050565b60408051602081019091526000815261068261067d83613045565b61138f565b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152606083013560248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906340c10f1990604401600060405180830381600087803b15801561071357600080fd5b505af1158015610727573d6000803e3d6000fd5b5061073c925050506060830160408401612acf565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0846060013560405161079e91815260200190565b60405180910390a3506040805160208101909152606090910135815290565b6107c56115c0565b6108328484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061164392505050565b50505050565b6108406115c0565b61084983610aa9565b610890576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b67ffffffffffffffff8316600090815260076020526040812060040180546108b790612f47565b80601f01602080910402602001604051908101604052809291908181526020018280546108e390612f47565b80156109305780601f1061090557610100808354040283529160200191610930565b820191906000526020600020905b81548152906001019060200180831161091357829003601f168201915b5050505067ffffffffffffffff861660009081526007602052604090209192505060040161095f83858361318a565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf82858560405161099e939291906132a4565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a2d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610887565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60006105ac600567ffffffffffffffff84166117f9565b6040805180820190915260608082526020820152610ae5610ae083613308565b611814565b610af282606001356119de565b6040516060830135815233907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a26040518060400160405280610b4c8460200160208101906104089190612a10565b81526040805160208181019092526000815291015292915050565b6060610b736002611a81565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260039091015480841660608301529190910490911660808201526105ac90611a8e565b67ffffffffffffffff811660009081526007602052604090206005018054606091906105dd90612f47565b610c806115c0565b73ffffffffffffffffffffffffffffffffffffffff8116610ccd576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684910160405180910390a15050565b60606000610d616005611a81565b90506000815167ffffffffffffffff811115610d7f57610d7f612d9a565b604051908082528060200260200182016040528015610da8578160200160208202803683370190505b50905060005b8251811015610e0457828181518110610dc957610dc96133aa565b6020026020010151828281518110610de357610de36133aa565b67ffffffffffffffff90921660209283029190910190910152600101610dae565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526105ac90611a8e565b610ee56115c0565b610ef0838383611b40565b505050565b610efd6115c0565b60005b81811015610ef0576000838383818110610f1c57610f1c6133aa565b9050602002810190610f2e91906133d9565b610f3790613417565b9050610f4c8160800151826020015115611c2a565b610f5f8160a00151826020015115611c2a565b80602001511561125b578051610f819060059067ffffffffffffffff16611d63565b610fc65780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610887565b6040810151511580610fdb5750606081015151155b15611012576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c179091169615150295909517909855908101519401519381169316909102919091176003820155915190919060048201906111f390826134cb565b506060820151600582019061120890826134cb565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2955061124e94939291906135e5565b60405180910390a1611372565b80516112739060059067ffffffffffffffff16611d6f565b6112b85780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610887565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906113216004830182612963565b61132f600583016000612963565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b50600101610f00565b6113836115c0565b61138c81611d7b565b50565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146114245760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610887565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa1580156114d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f6919061367e565b1561152d576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61153a8160200151611e70565b600061154982602001516105b2565b905080516000148061156d575080805190602001208260a001518051906020012014155b156115aa578160a001516040517f24eb47e50000000000000000000000000000000000000000000000000000000081526004016108879190612a8f565b6115bc82602001518360600151611f96565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611641576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610887565b565b7f000000000000000000000000000000000000000000000000000000000000000061169a576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82518110156117305760008382815181106116ba576116ba6133aa565b602002602001015190506116d8816002611fdd90919063ffffffff16565b156117275760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b5060010161169d565b5060005b8151811015610ef0576000828281518110611751576117516133aa565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361179557506117f1565b6117a0600282611fff565b156117ef5760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101611734565b600081815260018301602052604081205415155b9392505050565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146118a95760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610887565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611957573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197b919061367e565b156119b2576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119bf8160400151612021565b6119cc81602001516120a0565b61138c816020015182606001516121ee565b6040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906342966c6890602401600060405180830381600087803b158015611a6657600080fd5b505af1158015611a7a573d6000803e3d6000fd5b5050505050565b6060600061180d83612232565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611b1c82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611b0091906136ca565b85608001516fffffffffffffffffffffffffffffffff1661228d565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b611b4983610aa9565b611b8b576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401610887565b611b96826000611c2a565b67ffffffffffffffff83166000908152600760205260409020611bb990836122b7565b611bc4816000611c2a565b67ffffffffffffffff83166000908152600760205260409020611bea90600201826122b7565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051611c1d939291906136dd565b60405180910390a1505050565b815115611cf15781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580611c80575060408201516fffffffffffffffffffffffffffffffff16155b15611cb957816040517f8020d1240000000000000000000000000000000000000000000000000000000081526004016108879190613760565b80156115bc576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff16151580611d2a575060208201516fffffffffffffffffffffffffffffffff1615155b156115bc57816040517fd68af9cc0000000000000000000000000000000000000000000000000000000081526004016108879190613760565b600061180d8383612459565b600061180d83836124a8565b3373ffffffffffffffffffffffffffffffffffffffff821603611dfa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610887565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b611e7981610aa9565b611ebb576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610887565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015611f3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f5e919061367e565b61138c576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610887565b67ffffffffffffffff821660009081526007602052604090206115bc90600201827f000000000000000000000000000000000000000000000000000000000000000061259b565b600061180d8373ffffffffffffffffffffffffffffffffffffffff84166124a8565b600061180d8373ffffffffffffffffffffffffffffffffffffffff8416612459565b7f00000000000000000000000000000000000000000000000000000000000000001561138c5761205260028261291e565b61138c576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610887565b6120a981610aa9565b6120eb576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610887565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015612164573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612188919061379c565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461138c576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610887565b67ffffffffffffffff821660009081526007602052604090206115bc90827f000000000000000000000000000000000000000000000000000000000000000061259b565b60608160000180548060200260200160405190810160405280929190818152602001828054801561065657602002820191906000526020600020905b81548152602001906001019080831161226e5750505050509050919050565b60006122ac8561229d84866137b9565b6122a790876137d0565b61294d565b90505b949350505050565b81546000906122e090700100000000000000000000000000000000900463ffffffff16426136ca565b905080156123825760018301548354612328916fffffffffffffffffffffffffffffffff8082169281169185917001000000000000000000000000000000009091041661228d565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b602082015183546123a8916fffffffffffffffffffffffffffffffff908116911661294d565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990611c1d908490613760565b60008181526001830160205260408120546124a0575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105ac565b5060006105ac565b600081815260018301602052604081205480156125915760006124cc6001836136ca565b85549091506000906124e0906001906136ca565b9050818114612545576000866000018281548110612500576125006133aa565b9060005260206000200154905080876000018481548110612523576125236133aa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612556576125566137e3565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105ac565b60009150506105ac565b825474010000000000000000000000000000000000000000900460ff1615806125c2575081155b156125cc57505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061261290700100000000000000000000000000000000900463ffffffff16426136ca565b905080156126d25781831115612654576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186015461268e9083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1661228d565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156127895773ffffffffffffffffffffffffffffffffffffffff8416612731576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610887565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff85166044820152606401610887565b8483101561289c5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906127cd90826136ca565b6127d7878a6136ca565b6127e191906137d0565b6127eb9190613812565b905073ffffffffffffffffffffffffffffffffffffffff8616612844576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610887565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff87166044820152606401610887565b6128a685846136ca565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561180d565b600081831061295c578161180d565b5090919050565b50805461296f90612f47565b6000825580601f1061297f575050565b601f01602090049060005260206000209081019061138c91905b808211156129ad5760008155600101612999565b5090565b6000602082840312156129c357600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461180d57600080fd5b803567ffffffffffffffff81168114612a0b57600080fd5b919050565b600060208284031215612a2257600080fd5b61180d826129f3565b6000815180845260005b81811015612a5157602081850181015186830182015201612a35565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061180d6020830184612a2b565b73ffffffffffffffffffffffffffffffffffffffff8116811461138c57600080fd5b8035612a0b81612aa2565b600060208284031215612ae157600080fd5b813561180d81612aa2565b600060208284031215612afe57600080fd5b813567ffffffffffffffff811115612b1557600080fd5b8201610100818503121561180d57600080fd5b60008083601f840112612b3a57600080fd5b50813567ffffffffffffffff811115612b5257600080fd5b6020830191508360208260051b8501011115612b6d57600080fd5b9250929050565b60008060008060408587031215612b8a57600080fd5b843567ffffffffffffffff80821115612ba257600080fd5b612bae88838901612b28565b90965094506020870135915080821115612bc757600080fd5b50612bd487828801612b28565b95989497509550505050565b600080600060408486031215612bf557600080fd5b612bfe846129f3565b9250602084013567ffffffffffffffff80821115612c1b57600080fd5b818601915086601f830112612c2f57600080fd5b813581811115612c3e57600080fd5b876020828501011115612c5057600080fd5b6020830194508093505050509250925092565b600060208284031215612c7557600080fd5b813567ffffffffffffffff811115612c8c57600080fd5b820160a0818503121561180d57600080fd5b602081526000825160406020840152612cba6060840182612a2b565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016040850152612cf58282612a2b565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015612d4c57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612d1a565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612d4c57835167ffffffffffffffff1683529284019291840191600101612d74565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715612ded57612ded612d9a565b60405290565b60405160c0810167ffffffffffffffff81118282101715612ded57612ded612d9a565b801515811461138c57600080fd5b8035612a0b81612e16565b80356fffffffffffffffffffffffffffffffff81168114612a0b57600080fd5b600060608284031215612e6157600080fd5b6040516060810181811067ffffffffffffffff82111715612e8457612e84612d9a565b6040529050808235612e9581612e16565b8152612ea360208401612e2f565b6020820152612eb460408401612e2f565b60408201525092915050565b600080600060e08486031215612ed557600080fd5b612ede846129f3565b9250612eed8560208601612e4f565b9150612efc8560808601612e4f565b90509250925092565b60008060208385031215612f1857600080fd5b823567ffffffffffffffff811115612f2f57600080fd5b612f3b85828601612b28565b90969095509350505050565b600181811c90821680612f5b57607f821691505b602082108103612f94577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f830112612fab57600080fd5b813567ffffffffffffffff80821115612fc657612fc6612d9a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561300c5761300c612d9a565b8160405283815286602085880101111561302557600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000610100823603121561305857600080fd5b613060612dc9565b823567ffffffffffffffff8082111561307857600080fd5b61308436838701612f9a565b8352613092602086016129f3565b60208401526130a360408601612ac4565b6040840152606085013560608401526130be60808601612ac4565b608084015260a08501359150808211156130d757600080fd5b6130e336838701612f9a565b60a084015260c08501359150808211156130fc57600080fd5b61310836838701612f9a565b60c084015260e085013591508082111561312157600080fd5b5061312e36828601612f9a565b60e08301525092915050565b601f821115610ef0576000816000526020600020601f850160051c810160208610156131635750805b601f850160051c820191505b818110156131825782815560010161316f565b505050505050565b67ffffffffffffffff8311156131a2576131a2612d9a565b6131b6836131b08354612f47565b8361313a565b6000601f84116001811461320857600085156131d25750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611a7a565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156132575786850135825560209485019460019092019101613237565b5086821015613292577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b6040815260006132b76040830186612a2b565b82810360208401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116820101915050949350505050565b600060a0823603121561331a57600080fd5b60405160a0810167ffffffffffffffff828210818311171561333e5761333e612d9a565b81604052843591508082111561335357600080fd5b5061336036828601612f9a565b82525061336f602084016129f3565b6020820152604083013561338281612aa2565b604082015260608381013590820152608083013561339f81612aa2565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec183360301811261340d57600080fd5b9190910192915050565b6000610140823603121561342a57600080fd5b613432612df3565b61343b836129f3565b815261344960208401612e24565b6020820152604083013567ffffffffffffffff8082111561346957600080fd5b61347536838701612f9a565b6040840152606085013591508082111561348e57600080fd5b5061349b36828601612f9a565b6060830152506134ae3660808501612e4f565b60808201526134c03660e08501612e4f565b60a082015292915050565b815167ffffffffffffffff8111156134e5576134e5612d9a565b6134f9816134f38454612f47565b8461313a565b602080601f83116001811461354c57600084156135165750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613182565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156135995788860151825594840194600190910190840161357a565b50858210156135d557878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff8716835280602084015261360981840187612a2b565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff90811660608701529087015116608085015291506136479050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e0830152612cf5565b60006020828403121561369057600080fd5b815161180d81612e16565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105ac576105ac61369b565b67ffffffffffffffff8416815260e0810161372960208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c08301526122af565b606081016105ac82848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b6000602082840312156137ae57600080fd5b815161180d81612aa2565b80820281158282048414176105ac576105ac61369b565b808201808211156105ac576105ac61369b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600082613848577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea164736f6c6343000818000a",
+}
+
+var BurnMintTokenPoolABI = BurnMintTokenPoolMetaData.ABI
+
+var BurnMintTokenPoolBin = BurnMintTokenPoolMetaData.Bin
+
+func DeployBurnMintTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, rmnProxy common.Address, router common.Address) (common.Address, *types.Transaction, *BurnMintTokenPool, error) {
+ parsed, err := BurnMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BurnMintTokenPoolBin), backend, token, allowlist, rmnProxy, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &BurnMintTokenPool{address: address, abi: *parsed, BurnMintTokenPoolCaller: BurnMintTokenPoolCaller{contract: contract}, BurnMintTokenPoolTransactor: BurnMintTokenPoolTransactor{contract: contract}, BurnMintTokenPoolFilterer: BurnMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+type BurnMintTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ BurnMintTokenPoolCaller
+ BurnMintTokenPoolTransactor
+ BurnMintTokenPoolFilterer
+}
+
+type BurnMintTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolSession struct {
+ Contract *BurnMintTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type BurnMintTokenPoolCallerSession struct {
+ Contract *BurnMintTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type BurnMintTokenPoolTransactorSession struct {
+ Contract *BurnMintTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type BurnMintTokenPoolRaw struct {
+ Contract *BurnMintTokenPool
+}
+
+type BurnMintTokenPoolCallerRaw struct {
+ Contract *BurnMintTokenPoolCaller
+}
+
+type BurnMintTokenPoolTransactorRaw struct {
+ Contract *BurnMintTokenPoolTransactor
+}
+
+func NewBurnMintTokenPool(address common.Address, backend bind.ContractBackend) (*BurnMintTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(BurnMintTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindBurnMintTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPool{address: address, abi: abi, BurnMintTokenPoolCaller: BurnMintTokenPoolCaller{contract: contract}, BurnMintTokenPoolTransactor: BurnMintTokenPoolTransactor{contract: contract}, BurnMintTokenPoolFilterer: BurnMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewBurnMintTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*BurnMintTokenPoolCaller, error) {
+ contract, err := bindBurnMintTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolCaller{contract: contract}, nil
+}
+
+func NewBurnMintTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*BurnMintTokenPoolTransactor, error) {
+ contract, err := bindBurnMintTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewBurnMintTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*BurnMintTokenPoolFilterer, error) {
+ contract, err := bindBurnMintTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindBurnMintTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := BurnMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnMintTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetAllowList(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetAllowList(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _BurnMintTokenPool.Contract.GetAllowListEnabled(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _BurnMintTokenPool.Contract.GetAllowListEnabled(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getRemotePool", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnMintTokenPool.Contract.GetRemotePool(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnMintTokenPool.Contract.GetRemotePool(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnMintTokenPool.Contract.GetRemoteToken(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnMintTokenPool.Contract.GetRemoteToken(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getRmnProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetRmnProxy() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetRmnProxy(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetRmnProxy() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetRmnProxy(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetRouter() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetRouter(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetRouter(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnMintTokenPool.Contract.GetSupportedChains(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnMintTokenPool.Contract.GetSupportedChains(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetToken() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetToken(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetToken(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsSupportedChain(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsSupportedChain(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "isSupportedToken", token)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsSupportedToken(&_BurnMintTokenPool.CallOpts, token)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsSupportedToken(&_BurnMintTokenPool.CallOpts, token)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) Owner() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.Owner(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.Owner(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnMintTokenPool.Contract.SupportsInterface(&_BurnMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnMintTokenPool.Contract.SupportsInterface(&_BurnMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) TypeAndVersion() (string, error) {
+ return _BurnMintTokenPool.Contract.TypeAndVersion(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _BurnMintTokenPool.Contract.TypeAndVersion(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.AcceptOwnership(&_BurnMintTokenPool.TransactOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.AcceptOwnership(&_BurnMintTokenPool.TransactOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyChainUpdates(&_BurnMintTokenPool.TransactOpts, chains)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyChainUpdates(&_BurnMintTokenPool.TransactOpts, chains)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "lockOrBurn", lockOrBurnIn)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.LockOrBurn(&_BurnMintTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.LockOrBurn(&_BurnMintTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "releaseOrMint", releaseOrMintIn)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ReleaseOrMint(&_BurnMintTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ReleaseOrMint(&_BurnMintTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "setRemotePool", remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetRemotePool(&_BurnMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetRemotePool(&_BurnMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetRouter(&_BurnMintTokenPool.TransactOpts, newRouter)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetRouter(&_BurnMintTokenPool.TransactOpts, newRouter)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.TransferOwnership(&_BurnMintTokenPool.TransactOpts, to)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.TransferOwnership(&_BurnMintTokenPool.TransactOpts, to)
+}
+
+type BurnMintTokenPoolAllowListAddIterator struct {
+ Event *BurnMintTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAllowListAdd)
+ 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(BurnMintTokenPoolAllowListAdd)
+ 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 *BurnMintTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAllowListAddIterator{contract: _BurnMintTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAllowListAdd)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*BurnMintTokenPoolAllowListAdd, error) {
+ event := new(BurnMintTokenPoolAllowListAdd)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAllowListRemoveIterator struct {
+ Event *BurnMintTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAllowListRemove)
+ 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(BurnMintTokenPoolAllowListRemove)
+ 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 *BurnMintTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAllowListRemoveIterator{contract: _BurnMintTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAllowListRemove)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*BurnMintTokenPoolAllowListRemove, error) {
+ event := new(BurnMintTokenPoolAllowListRemove)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolBurnedIterator struct {
+ Event *BurnMintTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolBurned)
+ 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(BurnMintTokenPoolBurned)
+ 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 *BurnMintTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolBurnedIterator{contract: _BurnMintTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolBurned)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Burned", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseBurned(log types.Log) (*BurnMintTokenPoolBurned, error) {
+ event := new(BurnMintTokenPoolBurned)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolChainAddedIterator struct {
+ Event *BurnMintTokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolChainAdded)
+ 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(BurnMintTokenPoolChainAdded)
+ 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 *BurnMintTokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolChainAddedIterator{contract: _BurnMintTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolChainAdded)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseChainAdded(log types.Log) (*BurnMintTokenPoolChainAdded, error) {
+ event := new(BurnMintTokenPoolChainAdded)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolChainConfiguredIterator struct {
+ Event *BurnMintTokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolChainConfigured)
+ 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(BurnMintTokenPoolChainConfigured)
+ 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 *BurnMintTokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolChainConfiguredIterator{contract: _BurnMintTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolChainConfigured)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseChainConfigured(log types.Log) (*BurnMintTokenPoolChainConfigured, error) {
+ event := new(BurnMintTokenPoolChainConfigured)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolChainRemovedIterator struct {
+ Event *BurnMintTokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolChainRemoved)
+ 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(BurnMintTokenPoolChainRemoved)
+ 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 *BurnMintTokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolChainRemovedIterator{contract: _BurnMintTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolChainRemoved)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseChainRemoved(log types.Log) (*BurnMintTokenPoolChainRemoved, error) {
+ event := new(BurnMintTokenPoolChainRemoved)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolConfigChangedIterator struct {
+ Event *BurnMintTokenPoolConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolConfigChanged)
+ 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(BurnMintTokenPoolConfigChanged)
+ 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 *BurnMintTokenPoolConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*BurnMintTokenPoolConfigChangedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolConfigChangedIterator{contract: _BurnMintTokenPool.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolConfigChanged)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ConfigChanged", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseConfigChanged(log types.Log) (*BurnMintTokenPoolConfigChanged, error) {
+ event := new(BurnMintTokenPoolConfigChanged)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolLockedIterator struct {
+ Event *BurnMintTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolLocked)
+ 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(BurnMintTokenPoolLocked)
+ 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 *BurnMintTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolLockedIterator{contract: _BurnMintTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolLocked)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Locked", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseLocked(log types.Log) (*BurnMintTokenPoolLocked, error) {
+ event := new(BurnMintTokenPoolLocked)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolMintedIterator struct {
+ Event *BurnMintTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolMinted)
+ 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(BurnMintTokenPoolMinted)
+ 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 *BurnMintTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolMintedIterator{contract: _BurnMintTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolMinted)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Minted", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseMinted(log types.Log) (*BurnMintTokenPoolMinted, error) {
+ event := new(BurnMintTokenPoolMinted)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *BurnMintTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOwnershipTransferRequested)
+ 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(BurnMintTokenPoolOwnershipTransferRequested)
+ 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 *BurnMintTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOwnershipTransferRequestedIterator{contract: _BurnMintTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*BurnMintTokenPoolOwnershipTransferRequested, error) {
+ event := new(BurnMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOwnershipTransferredIterator struct {
+ Event *BurnMintTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOwnershipTransferred)
+ 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(BurnMintTokenPoolOwnershipTransferred)
+ 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 *BurnMintTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOwnershipTransferredIterator{contract: _BurnMintTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOwnershipTransferred)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*BurnMintTokenPoolOwnershipTransferred, error) {
+ event := new(BurnMintTokenPoolOwnershipTransferred)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolReleasedIterator struct {
+ Event *BurnMintTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolReleased)
+ 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(BurnMintTokenPoolReleased)
+ 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 *BurnMintTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolReleasedIterator{contract: _BurnMintTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolReleased)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Released", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseReleased(log types.Log) (*BurnMintTokenPoolReleased, error) {
+ event := new(BurnMintTokenPoolReleased)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolRemotePoolSetIterator struct {
+ Event *BurnMintTokenPoolRemotePoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolRemotePoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolRemotePoolSet)
+ 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(BurnMintTokenPoolRemotePoolSet)
+ 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 *BurnMintTokenPoolRemotePoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolRemotePoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolRemotePoolSet struct {
+ RemoteChainSelector uint64
+ PreviousPoolAddress []byte
+ RemotePoolAddress []byte
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnMintTokenPoolRemotePoolSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolRemotePoolSetIterator{contract: _BurnMintTokenPool.contract, event: "RemotePoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolRemotePoolSet)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "RemotePoolSet", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseRemotePoolSet(log types.Log) (*BurnMintTokenPoolRemotePoolSet, error) {
+ event := new(BurnMintTokenPoolRemotePoolSet)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "RemotePoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolRouterUpdatedIterator struct {
+ Event *BurnMintTokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolRouterUpdated)
+ 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(BurnMintTokenPoolRouterUpdated)
+ 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 *BurnMintTokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*BurnMintTokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolRouterUpdatedIterator{contract: _BurnMintTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolRouterUpdated)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*BurnMintTokenPoolRouterUpdated, error) {
+ event := new(BurnMintTokenPoolRouterUpdated)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolTokensConsumedIterator struct {
+ Event *BurnMintTokenPoolTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolTokensConsumed)
+ 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(BurnMintTokenPoolTokensConsumed)
+ 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 *BurnMintTokenPoolTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*BurnMintTokenPoolTokensConsumedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolTokensConsumedIterator{contract: _BurnMintTokenPool.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolTokensConsumed)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "TokensConsumed", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseTokensConsumed(log types.Log) (*BurnMintTokenPoolTokensConsumed, error) {
+ event := new(BurnMintTokenPoolTokensConsumed)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _BurnMintTokenPool.abi.Events["AllowListAdd"].ID:
+ return _BurnMintTokenPool.ParseAllowListAdd(log)
+ case _BurnMintTokenPool.abi.Events["AllowListRemove"].ID:
+ return _BurnMintTokenPool.ParseAllowListRemove(log)
+ case _BurnMintTokenPool.abi.Events["Burned"].ID:
+ return _BurnMintTokenPool.ParseBurned(log)
+ case _BurnMintTokenPool.abi.Events["ChainAdded"].ID:
+ return _BurnMintTokenPool.ParseChainAdded(log)
+ case _BurnMintTokenPool.abi.Events["ChainConfigured"].ID:
+ return _BurnMintTokenPool.ParseChainConfigured(log)
+ case _BurnMintTokenPool.abi.Events["ChainRemoved"].ID:
+ return _BurnMintTokenPool.ParseChainRemoved(log)
+ case _BurnMintTokenPool.abi.Events["ConfigChanged"].ID:
+ return _BurnMintTokenPool.ParseConfigChanged(log)
+ case _BurnMintTokenPool.abi.Events["Locked"].ID:
+ return _BurnMintTokenPool.ParseLocked(log)
+ case _BurnMintTokenPool.abi.Events["Minted"].ID:
+ return _BurnMintTokenPool.ParseMinted(log)
+ case _BurnMintTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _BurnMintTokenPool.ParseOwnershipTransferRequested(log)
+ case _BurnMintTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _BurnMintTokenPool.ParseOwnershipTransferred(log)
+ case _BurnMintTokenPool.abi.Events["Released"].ID:
+ return _BurnMintTokenPool.ParseReleased(log)
+ case _BurnMintTokenPool.abi.Events["RemotePoolSet"].ID:
+ return _BurnMintTokenPool.ParseRemotePoolSet(log)
+ case _BurnMintTokenPool.abi.Events["RouterUpdated"].ID:
+ return _BurnMintTokenPool.ParseRouterUpdated(log)
+ case _BurnMintTokenPool.abi.Events["TokensConsumed"].ID:
+ return _BurnMintTokenPool.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (BurnMintTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (BurnMintTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (BurnMintTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (BurnMintTokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2")
+}
+
+func (BurnMintTokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (BurnMintTokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (BurnMintTokenPoolConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (BurnMintTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (BurnMintTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (BurnMintTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (BurnMintTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (BurnMintTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (BurnMintTokenPoolRemotePoolSet) Topic() common.Hash {
+ return common.HexToHash("0xdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf")
+}
+
+func (BurnMintTokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (BurnMintTokenPoolTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPool) Address() common.Address {
+ return _BurnMintTokenPool.address
+}
+
+type BurnMintTokenPoolInterface interface {
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRmnProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*BurnMintTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*BurnMintTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*BurnMintTokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*BurnMintTokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*BurnMintTokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*BurnMintTokenPoolChainRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*BurnMintTokenPoolConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*BurnMintTokenPoolConfigChanged, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*BurnMintTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*BurnMintTokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*BurnMintTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*BurnMintTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*BurnMintTokenPoolReleased, error)
+
+ FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnMintTokenPoolRemotePoolSetIterator, error)
+
+ WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRemotePoolSet(log types.Log) (*BurnMintTokenPoolRemotePoolSet, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*BurnMintTokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*BurnMintTokenPoolRouterUpdated, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*BurnMintTokenPoolTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*BurnMintTokenPoolTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_2_0/burn_mint_token_pool_1_2_0.go b/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_2_0/burn_mint_token_pool_1_2_0.go
new file mode 100644
index 00000000000..d11a7db6e60
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_2_0/burn_mint_token_pool_1_2_0.go
@@ -0,0 +1,2544 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package burn_mint_token_pool_1_2_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolRampUpdate struct {
+ Ramp common.Address
+ Allowed bool
+ RateLimiterConfig RateLimiterConfig
+}
+
+var BurnMintTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIBurnMintERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"ramp\",\"type\":\"address\"}],\"name\":\"NonExistentRamp\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PermissionsError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"ramp\",\"type\":\"address\"}],\"name\":\"RampAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"OffRampAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"OffRampConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"OffRampRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"OnRampAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"OnRampConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"}],\"name\":\"OnRampRemoved\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"ramp\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.RampUpdate[]\",\"name\":\"onRamps\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"ramp\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.RampUpdate[]\",\"name\":\"offRamps\",\"type\":\"tuple[]\"}],\"name\":\"applyRampUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"currentOffRampRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"}],\"name\":\"currentOnRampRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getArmProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOffRamps\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOnRamps\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"isOffRamp\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"}],\"name\":\"isOnRamp\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"releaseOrMint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setOffRampRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setOnRampRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x60e06040523480156200001157600080fd5b5060405162002f3338038062002f3383398101604081905262000034916200051d565b82828233806000816200008e5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c157620000c18162000133565b5050506001600160a01b038316620000ec576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b03808416608052811660a052815115801560c0526200012757604080516000815260208101909152620001279083620001de565b5050505050506200068e565b336001600160a01b038216036200018d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000085565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c051620001ff576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002945760008382815181106200022357620002236200061a565b602090810291909101015190506200023d6002826200034f565b1562000280576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506200028c8162000646565b905062000202565b5060005b81518110156200034a576000828281518110620002b957620002b96200061a565b6020026020010151905060006001600160a01b0316816001600160a01b031603620002e5575062000337565b620002f26002826200036f565b1562000335576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b620003428162000646565b905062000298565b505050565b600062000366836001600160a01b03841662000386565b90505b92915050565b600062000366836001600160a01b0384166200048a565b600081815260018301602052604081205480156200047f576000620003ad60018362000662565b8554909150600090620003c39060019062000662565b90508181146200042f576000866000018281548110620003e757620003e76200061a565b90600052602060002001549050808760000184815481106200040d576200040d6200061a565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000443576200044362000678565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000369565b600091505062000369565b6000818152600183016020526040812054620004d35750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000369565b50600062000369565b6001600160a01b0381168114620004f257600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b80516200051881620004dc565b919050565b6000806000606084860312156200053357600080fd5b83516200054081620004dc565b602085810151919450906001600160401b03808211156200056057600080fd5b818701915087601f8301126200057557600080fd5b8151818111156200058a576200058a620004f5565b8060051b604051601f19603f83011681018181108582111715620005b257620005b2620004f5565b60405291825284820192508381018501918a831115620005d157600080fd5b938501935b82851015620005fa57620005ea856200050b565b84529385019392850192620005d6565b80975050505050505062000611604085016200050b565b90509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016200065b576200065b62000630565b5060010190565b8181038181111562000369576200036962000630565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05161283d620006f6600039600081816103c301528181610a320152610e71015260008181610249015281816107d50152610ab60152600081816102020152818161092d015281816112b1015281816112f8015261134b015261283d6000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c80638627fad6116100d8578063a7cd63b71161008c578063d612b94511610066578063d612b945146103ae578063e0351e13146103c1578063f2fde38b146103e757600080fd5b8063a7cd63b714610380578063b3a3fb4114610388578063c49907b51461039b57600080fd5b80638da5cb5b116100bd5780638da5cb5b146103475780639687544514610365578063a40e69c71461037857600080fd5b80638627fad61461031f578063873813141461033257600080fd5b806354c8a4f31161012f5780637448b3c7116101145780637448b3c7146102955780637787e7ab146102a857806379ba50971461031757600080fd5b806354c8a4f31461026d5780636f32b8721461028257600080fd5b80631d7a74a0116101605780631d7a74a0146101ed57806321df0da7146102005780635246492f1461024757600080fd5b806301ffc9a71461017c578063181f5a77146101a4575b600080fd5b61018f61018a366004612000565b6103fa565b60405190151581526020015b60405180910390f35b6101e06040518060400160405280601781526020017f4275726e4d696e74546f6b656e506f6f6c20312e322e3000000000000000000081525081565b60405161019b91906120a6565b61018f6101fb3660046120e2565b610493565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b7f0000000000000000000000000000000000000000000000000000000000000000610222565b61028061027b366004612149565b6104a0565b005b61018f6102903660046120e2565b61051b565b6102806102a336600461228c565b610528565b6102bb6102b63660046120e2565b6105f8565b60405161019b919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6102806106d6565b61028061032d366004612383565b6107d3565b61033a6109dd565b60405161019b9190612412565b60005473ffffffffffffffffffffffffffffffffffffffff16610222565b6101e06103733660046124ae565b6109ee565b61033a610bdd565b61033a610be9565b6102bb6103963660046120e2565b610bf5565b6102806103a9366004612591565b610cd3565b6102806103bc36600461228c565b610ce7565b7f000000000000000000000000000000000000000000000000000000000000000061018f565b6102806103f53660046120e2565b610da6565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f317fa33400000000000000000000000000000000000000000000000000000000148061048d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b600061048d600783610dba565b6104a8610dec565b61051584848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250610e6f92505050565b50505050565b600061048d600483610dba565b610530610dec565b6105398261051b565b61058c576040517f498f12f600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604090206105bb908261103a565b7f578db78e348076074dbff64a94073a83e9a65aa6766b8c75fdc89282b0e30ed682826040516105ec9291906125f1565b60405180910390a15050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff8216600090815260066020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600190910154808416606083015291909104909116608082015261048d906111e9565b60015473ffffffffffffffffffffffffffffffffffffffff163314610757576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610583565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561083e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108629190612649565b15610899576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108a233610493565b6108d8576040517f5307f5ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108e18361129b565b6040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018590527f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b15801561097157600080fd5b505af1158015610985573d6000803e3d6000fd5b505060405185815273ffffffffffffffffffffffffffffffffffffffff871692503391507f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f09060200160405180910390a35050505050565b60606109e960046112d5565b905090565b60606109f93361051b565b610a2f576040517f5307f5ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b877f00000000000000000000000000000000000000000000000000000000000000008015610a655750610a63600282610dba565b155b15610ab4576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610583565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b439190612649565b15610b7a576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b83866112e2565b610b8c8661131c565b60405186815233907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a25050604080516020810190915260008152979650505050505050565b60606109e960076112d5565b60606109e960026112d5565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff8216600090815260096020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600190910154808416606083015291909104909116608082015261048d906111e9565b610cdb610dec565b610515848484846113bf565b610cef610dec565b610cf882610493565b610d46576040517f498f12f600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610583565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600960205260409020610d75908261103a565b7fb3ba339cfbb8ef80d7a29ce5493051cb90e64fcfa85d7124efc1adfa4c68399f82826040516105ec9291906125f1565b610dae610dec565b610db781611968565b50565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e6d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610583565b565b7f0000000000000000000000000000000000000000000000000000000000000000610ec6576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610f64576000838281518110610ee657610ee6612666565b60200260200101519050610f04816002611a5d90919063ffffffff16565b15610f535760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50610f5d816126c4565b9050610ec9565b5060005b8151811015611035576000828281518110610f8557610f85612666565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610fc95750611025565b610fd4600282611a7f565b156110235760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b61102e816126c4565b9050610f68565b505050565b815460009061106390700100000000000000000000000000000000900463ffffffff16426126fc565b9050801561110557600183015483546110ab916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416611aa1565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b6020820151835461112b916fffffffffffffffffffffffffffffffff9081169116611ac9565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19906111dc90849061270f565b60405180910390a1505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261127782606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff164261125b91906126fc565b85608001516fffffffffffffffffffffffffffffffff16611aa1565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b336000908152600960205260409020610db790827f0000000000000000000000000000000000000000000000000000000000000000611adf565b60606000610de583611e62565b336000908152600660205260409020610db790827f0000000000000000000000000000000000000000000000000000000000000000611adf565b6040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906342966c6890602401600060405180830381600087803b1580156113a457600080fd5b505af11580156113b8573d6000803e3d6000fd5b5050505050565b6113c7610dec565b60005b838110156116e45760008585838181106113e6576113e6612666565b905060a002018036038101906113fc919061274b565b90508060200151156115d457805161141690600490611a7f565b15611587576040805160a08101825282820180516020908101516fffffffffffffffffffffffffffffffff908116845263ffffffff4281168386019081528451511515868801908152855185015184166060880190815286518901518516608089019081528a5173ffffffffffffffffffffffffffffffffffffffff1660009081526006909752958990209751885493519251151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff939095167001000000000000000000000000000000009081027fffffffffffffffffffffffff0000000000000000000000000000000000000000909516918716919091179390931791909116929092178655905192518216029116176001909201919091558251905191517f0b594bb0555ff7b252e0c789ccc9d8903fec294172064308727d570505cee1ac9261157a92916125f1565b60405180910390a16116d3565b80516040517fd3eb6bc500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610583565b80516115e290600490611a5d565b1561168657805173ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604080822080547fffffffffffffffffffffff00000000000000000000000000000000000000000016815560010191909155815190517f7fd064821314ad863a0714a3f1229375ace6b6427ed5544b7b2ba1c47b1b52949161157a9173ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b80516040517f498f12f600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610583565b506116dd816126c4565b90506113ca565b5060005b818110156113b857600083838381811061170457611704612666565b905060a0020180360381019061171a919061274b565b90508060200151156118a557805161173490600790611a7f565b15611587576040805160a08101825282820180516020908101516fffffffffffffffffffffffffffffffff908116845263ffffffff4281168386019081528451511515868801908152855185015184166060880190815286518901518516608089019081528a5173ffffffffffffffffffffffffffffffffffffffff1660009081526009909752958990209751885493519251151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff939095167001000000000000000000000000000000009081027fffffffffffffffffffffffff0000000000000000000000000000000000000000909516918716919091179390931791909116929092178655905192518216029116176001909201919091558251905191517f395b7374909d2b54e5796f53c898ebf41d767c86c78ea86519acf2b805852d889261189892916125f1565b60405180910390a1611957565b80516118b390600790611a5d565b1561168657805173ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604080822080547fffffffffffffffffffffff00000000000000000000000000000000000000000016815560010191909155815190517fcf91daec21e3510e2f2aea4b09d08c235d5c6844980be709f282ef591dbf420c916118989173ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b50611961816126c4565b90506116e8565b3373ffffffffffffffffffffffffffffffffffffffff8216036119e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610583565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000610de58373ffffffffffffffffffffffffffffffffffffffff8416611ebe565b6000610de58373ffffffffffffffffffffffffffffffffffffffff8416611fb1565b6000611ac085611ab1848661279c565b611abb90876127b3565b611ac9565b95945050505050565b6000818310611ad85781610de5565b5090919050565b825474010000000000000000000000000000000000000000900460ff161580611b06575081155b15611b1057505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090611b5690700100000000000000000000000000000000900463ffffffff16426126fc565b90508015611c165781831115611b98576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001860154611bd29083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16611aa1565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b84821015611ccd5773ffffffffffffffffffffffffffffffffffffffff8416611c75576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610583565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff85166044820152606401610583565b84831015611de05760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16906000908290611d1190826126fc565b611d1b878a6126fc565b611d2591906127b3565b611d2f91906127c6565b905073ffffffffffffffffffffffffffffffffffffffff8616611d88576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610583565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff87166044820152606401610583565b611dea85846126fc565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b606081600001805480602002602001604051908101604052809291908181526020018280548015611eb257602002820191906000526020600020905b815481526020019060010190808311611e9e575b50505050509050919050565b60008181526001830160205260408120548015611fa7576000611ee26001836126fc565b8554909150600090611ef6906001906126fc565b9050818114611f5b576000866000018281548110611f1657611f16612666565b9060005260206000200154905080876000018481548110611f3957611f39612666565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611f6c57611f6c612801565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061048d565b600091505061048d565b6000818152600183016020526040812054611ff85750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561048d565b50600061048d565b60006020828403121561201257600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610de557600080fd5b6000815180845260005b818110156120685760208185018101518683018201520161204c565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610de56020830184612042565b803573ffffffffffffffffffffffffffffffffffffffff811681146120dd57600080fd5b919050565b6000602082840312156120f457600080fd5b610de5826120b9565b60008083601f84011261210f57600080fd5b50813567ffffffffffffffff81111561212757600080fd5b6020830191508360208260051b850101111561214257600080fd5b9250929050565b6000806000806040858703121561215f57600080fd5b843567ffffffffffffffff8082111561217757600080fd5b612183888389016120fd565b9096509450602087013591508082111561219c57600080fd5b506121a9878288016120fd565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715612207576122076121b5565b60405290565b8015158114610db757600080fd5b80356fffffffffffffffffffffffffffffffff811681146120dd57600080fd5b60006060828403121561224d57600080fd5b6122556121e4565b905081356122628161220d565b81526122706020830161221b565b60208201526122816040830161221b565b604082015292915050565b6000806080838503121561229f57600080fd5b6122a8836120b9565b91506122b7846020850161223b565b90509250929050565b600082601f8301126122d157600080fd5b813567ffffffffffffffff808211156122ec576122ec6121b5565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715612332576123326121b5565b8160405283815286602085880101111561234b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b803567ffffffffffffffff811681146120dd57600080fd5b600080600080600060a0868803121561239b57600080fd5b853567ffffffffffffffff808211156123b357600080fd5b6123bf89838a016122c0565b96506123cd602089016120b9565b9550604088013594506123e26060890161236b565b935060808801359150808211156123f857600080fd5b50612405888289016122c0565b9150509295509295909350565b6020808252825182820181905260009190848201906040850190845b8181101561246057835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161242e565b50909695505050505050565b60008083601f84011261247e57600080fd5b50813567ffffffffffffffff81111561249657600080fd5b60208301915083602082850101111561214257600080fd5b600080600080600080600060a0888a0312156124c957600080fd5b6124d2886120b9565b9650602088013567ffffffffffffffff808211156124ef57600080fd5b6124fb8b838c0161246c565b909850965060408a0135955086915061251660608b0161236b565b945060808a013591508082111561252c57600080fd5b506125398a828b0161246c565b989b979a50959850939692959293505050565b60008083601f84011261255e57600080fd5b50813567ffffffffffffffff81111561257657600080fd5b60208301915083602060a08302850101111561214257600080fd5b600080600080604085870312156125a757600080fd5b843567ffffffffffffffff808211156125bf57600080fd5b6125cb8883890161254c565b909650945060208701359150808211156125e457600080fd5b506121a98782880161254c565b73ffffffffffffffffffffffffffffffffffffffff8316815260808101610de560208301848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b60006020828403121561265b57600080fd5b8151610de58161220d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036126f5576126f5612695565b5060010190565b8181038181111561048d5761048d612695565b6060810161048d82848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b600060a0828403121561275d57600080fd5b6127656121e4565b61276e836120b9565b8152602083013561277e8161220d565b6020820152612790846040850161223b565b60408201529392505050565b808202811582820484141761048d5761048d612695565b8082018082111561048d5761048d612695565b6000826127fc577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a",
+}
+
+var BurnMintTokenPoolABI = BurnMintTokenPoolMetaData.ABI
+
+var BurnMintTokenPoolBin = BurnMintTokenPoolMetaData.Bin
+
+func DeployBurnMintTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, armProxy common.Address) (common.Address, *types.Transaction, *BurnMintTokenPool, error) {
+ parsed, err := BurnMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BurnMintTokenPoolBin), backend, token, allowlist, armProxy)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &BurnMintTokenPool{address: address, abi: *parsed, BurnMintTokenPoolCaller: BurnMintTokenPoolCaller{contract: contract}, BurnMintTokenPoolTransactor: BurnMintTokenPoolTransactor{contract: contract}, BurnMintTokenPoolFilterer: BurnMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+type BurnMintTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ BurnMintTokenPoolCaller
+ BurnMintTokenPoolTransactor
+ BurnMintTokenPoolFilterer
+}
+
+type BurnMintTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolSession struct {
+ Contract *BurnMintTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type BurnMintTokenPoolCallerSession struct {
+ Contract *BurnMintTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type BurnMintTokenPoolTransactorSession struct {
+ Contract *BurnMintTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type BurnMintTokenPoolRaw struct {
+ Contract *BurnMintTokenPool
+}
+
+type BurnMintTokenPoolCallerRaw struct {
+ Contract *BurnMintTokenPoolCaller
+}
+
+type BurnMintTokenPoolTransactorRaw struct {
+ Contract *BurnMintTokenPoolTransactor
+}
+
+func NewBurnMintTokenPool(address common.Address, backend bind.ContractBackend) (*BurnMintTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(BurnMintTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindBurnMintTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPool{address: address, abi: abi, BurnMintTokenPoolCaller: BurnMintTokenPoolCaller{contract: contract}, BurnMintTokenPoolTransactor: BurnMintTokenPoolTransactor{contract: contract}, BurnMintTokenPoolFilterer: BurnMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewBurnMintTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*BurnMintTokenPoolCaller, error) {
+ contract, err := bindBurnMintTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolCaller{contract: contract}, nil
+}
+
+func NewBurnMintTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*BurnMintTokenPoolTransactor, error) {
+ contract, err := bindBurnMintTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewBurnMintTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*BurnMintTokenPoolFilterer, error) {
+ contract, err := bindBurnMintTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindBurnMintTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := BurnMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnMintTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) CurrentOffRampRateLimiterState(opts *bind.CallOpts, offRamp common.Address) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "currentOffRampRateLimiterState", offRamp)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) CurrentOffRampRateLimiterState(offRamp common.Address) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.CurrentOffRampRateLimiterState(&_BurnMintTokenPool.CallOpts, offRamp)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) CurrentOffRampRateLimiterState(offRamp common.Address) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.CurrentOffRampRateLimiterState(&_BurnMintTokenPool.CallOpts, offRamp)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) CurrentOnRampRateLimiterState(opts *bind.CallOpts, onRamp common.Address) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "currentOnRampRateLimiterState", onRamp)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) CurrentOnRampRateLimiterState(onRamp common.Address) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.CurrentOnRampRateLimiterState(&_BurnMintTokenPool.CallOpts, onRamp)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) CurrentOnRampRateLimiterState(onRamp common.Address) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.CurrentOnRampRateLimiterState(&_BurnMintTokenPool.CallOpts, onRamp)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetAllowList(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetAllowList(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _BurnMintTokenPool.Contract.GetAllowListEnabled(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _BurnMintTokenPool.Contract.GetAllowListEnabled(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetArmProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getArmProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetArmProxy() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetArmProxy(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetArmProxy() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetArmProxy(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetOffRamps(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getOffRamps")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetOffRamps() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetOffRamps(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetOffRamps() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetOffRamps(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetOnRamps(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getOnRamps")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetOnRamps() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetOnRamps(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetOnRamps() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetOnRamps(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetToken() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetToken(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetToken(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) IsOffRamp(opts *bind.CallOpts, offRamp common.Address) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "isOffRamp", offRamp)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) IsOffRamp(offRamp common.Address) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsOffRamp(&_BurnMintTokenPool.CallOpts, offRamp)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) IsOffRamp(offRamp common.Address) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsOffRamp(&_BurnMintTokenPool.CallOpts, offRamp)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) IsOnRamp(opts *bind.CallOpts, onRamp common.Address) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "isOnRamp", onRamp)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) IsOnRamp(onRamp common.Address) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsOnRamp(&_BurnMintTokenPool.CallOpts, onRamp)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) IsOnRamp(onRamp common.Address) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsOnRamp(&_BurnMintTokenPool.CallOpts, onRamp)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) Owner() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.Owner(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.Owner(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnMintTokenPool.Contract.SupportsInterface(&_BurnMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnMintTokenPool.Contract.SupportsInterface(&_BurnMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) TypeAndVersion() (string, error) {
+ return _BurnMintTokenPool.Contract.TypeAndVersion(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _BurnMintTokenPool.Contract.TypeAndVersion(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.AcceptOwnership(&_BurnMintTokenPool.TransactOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.AcceptOwnership(&_BurnMintTokenPool.TransactOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ApplyRampUpdates(opts *bind.TransactOpts, onRamps []TokenPoolRampUpdate, offRamps []TokenPoolRampUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "applyRampUpdates", onRamps, offRamps)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ApplyRampUpdates(onRamps []TokenPoolRampUpdate, offRamps []TokenPoolRampUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyRampUpdates(&_BurnMintTokenPool.TransactOpts, onRamps, offRamps)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ApplyRampUpdates(onRamps []TokenPoolRampUpdate, offRamps []TokenPoolRampUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyRampUpdates(&_BurnMintTokenPool.TransactOpts, onRamps, offRamps)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, arg1 []byte, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "lockOrBurn", originalSender, arg1, amount, arg3, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) LockOrBurn(originalSender common.Address, arg1 []byte, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.LockOrBurn(&_BurnMintTokenPool.TransactOpts, originalSender, arg1, amount, arg3, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) LockOrBurn(originalSender common.Address, arg1 []byte, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.LockOrBurn(&_BurnMintTokenPool.TransactOpts, originalSender, arg1, amount, arg3, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "releaseOrMint", arg0, receiver, amount, arg3, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ReleaseOrMint(&_BurnMintTokenPool.TransactOpts, arg0, receiver, amount, arg3, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ReleaseOrMint(&_BurnMintTokenPool.TransactOpts, arg0, receiver, amount, arg3, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) SetOffRampRateLimiterConfig(opts *bind.TransactOpts, offRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "setOffRampRateLimiterConfig", offRamp, config)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SetOffRampRateLimiterConfig(offRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetOffRampRateLimiterConfig(&_BurnMintTokenPool.TransactOpts, offRamp, config)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) SetOffRampRateLimiterConfig(offRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetOffRampRateLimiterConfig(&_BurnMintTokenPool.TransactOpts, offRamp, config)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) SetOnRampRateLimiterConfig(opts *bind.TransactOpts, onRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "setOnRampRateLimiterConfig", onRamp, config)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SetOnRampRateLimiterConfig(onRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetOnRampRateLimiterConfig(&_BurnMintTokenPool.TransactOpts, onRamp, config)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) SetOnRampRateLimiterConfig(onRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetOnRampRateLimiterConfig(&_BurnMintTokenPool.TransactOpts, onRamp, config)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.TransferOwnership(&_BurnMintTokenPool.TransactOpts, to)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.TransferOwnership(&_BurnMintTokenPool.TransactOpts, to)
+}
+
+type BurnMintTokenPoolAllowListAddIterator struct {
+ Event *BurnMintTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAllowListAdd)
+ 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(BurnMintTokenPoolAllowListAdd)
+ 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 *BurnMintTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAllowListAddIterator{contract: _BurnMintTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAllowListAdd)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*BurnMintTokenPoolAllowListAdd, error) {
+ event := new(BurnMintTokenPoolAllowListAdd)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAllowListRemoveIterator struct {
+ Event *BurnMintTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAllowListRemove)
+ 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(BurnMintTokenPoolAllowListRemove)
+ 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 *BurnMintTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAllowListRemoveIterator{contract: _BurnMintTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAllowListRemove)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*BurnMintTokenPoolAllowListRemove, error) {
+ event := new(BurnMintTokenPoolAllowListRemove)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolBurnedIterator struct {
+ Event *BurnMintTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolBurned)
+ 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(BurnMintTokenPoolBurned)
+ 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 *BurnMintTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolBurnedIterator{contract: _BurnMintTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolBurned)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Burned", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseBurned(log types.Log) (*BurnMintTokenPoolBurned, error) {
+ event := new(BurnMintTokenPoolBurned)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolLockedIterator struct {
+ Event *BurnMintTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolLocked)
+ 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(BurnMintTokenPoolLocked)
+ 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 *BurnMintTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolLockedIterator{contract: _BurnMintTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolLocked)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Locked", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseLocked(log types.Log) (*BurnMintTokenPoolLocked, error) {
+ event := new(BurnMintTokenPoolLocked)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolMintedIterator struct {
+ Event *BurnMintTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolMinted)
+ 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(BurnMintTokenPoolMinted)
+ 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 *BurnMintTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolMintedIterator{contract: _BurnMintTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolMinted)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Minted", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseMinted(log types.Log) (*BurnMintTokenPoolMinted, error) {
+ event := new(BurnMintTokenPoolMinted)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOffRampAddedIterator struct {
+ Event *BurnMintTokenPoolOffRampAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOffRampAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOffRampAdded)
+ 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(BurnMintTokenPoolOffRampAdded)
+ 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 *BurnMintTokenPoolOffRampAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOffRampAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOffRampAdded struct {
+ OffRamp common.Address
+ RateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOffRampAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolOffRampAddedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OffRampAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOffRampAddedIterator{contract: _BurnMintTokenPool.contract, event: "OffRampAdded", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOffRampAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOffRampAdded) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OffRampAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOffRampAdded)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OffRampAdded", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOffRampAdded(log types.Log) (*BurnMintTokenPoolOffRampAdded, error) {
+ event := new(BurnMintTokenPoolOffRampAdded)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OffRampAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOffRampConfiguredIterator struct {
+ Event *BurnMintTokenPoolOffRampConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOffRampConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOffRampConfigured)
+ 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(BurnMintTokenPoolOffRampConfigured)
+ 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 *BurnMintTokenPoolOffRampConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOffRampConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOffRampConfigured struct {
+ OffRamp common.Address
+ RateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOffRampConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolOffRampConfiguredIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OffRampConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOffRampConfiguredIterator{contract: _BurnMintTokenPool.contract, event: "OffRampConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOffRampConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOffRampConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OffRampConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOffRampConfigured)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OffRampConfigured", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOffRampConfigured(log types.Log) (*BurnMintTokenPoolOffRampConfigured, error) {
+ event := new(BurnMintTokenPoolOffRampConfigured)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OffRampConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOffRampRemovedIterator struct {
+ Event *BurnMintTokenPoolOffRampRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOffRampRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOffRampRemoved)
+ 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(BurnMintTokenPoolOffRampRemoved)
+ 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 *BurnMintTokenPoolOffRampRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOffRampRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOffRampRemoved struct {
+ OffRamp common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOffRampRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolOffRampRemovedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OffRampRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOffRampRemovedIterator{contract: _BurnMintTokenPool.contract, event: "OffRampRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOffRampRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOffRampRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OffRampRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOffRampRemoved)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OffRampRemoved", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOffRampRemoved(log types.Log) (*BurnMintTokenPoolOffRampRemoved, error) {
+ event := new(BurnMintTokenPoolOffRampRemoved)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OffRampRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOnRampAddedIterator struct {
+ Event *BurnMintTokenPoolOnRampAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOnRampAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOnRampAdded)
+ 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(BurnMintTokenPoolOnRampAdded)
+ 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 *BurnMintTokenPoolOnRampAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOnRampAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOnRampAdded struct {
+ OnRamp common.Address
+ RateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOnRampAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolOnRampAddedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OnRampAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOnRampAddedIterator{contract: _BurnMintTokenPool.contract, event: "OnRampAdded", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOnRampAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOnRampAdded) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OnRampAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOnRampAdded)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OnRampAdded", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOnRampAdded(log types.Log) (*BurnMintTokenPoolOnRampAdded, error) {
+ event := new(BurnMintTokenPoolOnRampAdded)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OnRampAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOnRampConfiguredIterator struct {
+ Event *BurnMintTokenPoolOnRampConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOnRampConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOnRampConfigured)
+ 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(BurnMintTokenPoolOnRampConfigured)
+ 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 *BurnMintTokenPoolOnRampConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOnRampConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOnRampConfigured struct {
+ OnRamp common.Address
+ RateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOnRampConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolOnRampConfiguredIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OnRampConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOnRampConfiguredIterator{contract: _BurnMintTokenPool.contract, event: "OnRampConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOnRampConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOnRampConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OnRampConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOnRampConfigured)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OnRampConfigured", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOnRampConfigured(log types.Log) (*BurnMintTokenPoolOnRampConfigured, error) {
+ event := new(BurnMintTokenPoolOnRampConfigured)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OnRampConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOnRampRemovedIterator struct {
+ Event *BurnMintTokenPoolOnRampRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOnRampRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOnRampRemoved)
+ 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(BurnMintTokenPoolOnRampRemoved)
+ 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 *BurnMintTokenPoolOnRampRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOnRampRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOnRampRemoved struct {
+ OnRamp common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOnRampRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolOnRampRemovedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OnRampRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOnRampRemovedIterator{contract: _BurnMintTokenPool.contract, event: "OnRampRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOnRampRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOnRampRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OnRampRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOnRampRemoved)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OnRampRemoved", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOnRampRemoved(log types.Log) (*BurnMintTokenPoolOnRampRemoved, error) {
+ event := new(BurnMintTokenPoolOnRampRemoved)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OnRampRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *BurnMintTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOwnershipTransferRequested)
+ 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(BurnMintTokenPoolOwnershipTransferRequested)
+ 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 *BurnMintTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOwnershipTransferRequestedIterator{contract: _BurnMintTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*BurnMintTokenPoolOwnershipTransferRequested, error) {
+ event := new(BurnMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOwnershipTransferredIterator struct {
+ Event *BurnMintTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOwnershipTransferred)
+ 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(BurnMintTokenPoolOwnershipTransferred)
+ 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 *BurnMintTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOwnershipTransferredIterator{contract: _BurnMintTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOwnershipTransferred)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*BurnMintTokenPoolOwnershipTransferred, error) {
+ event := new(BurnMintTokenPoolOwnershipTransferred)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolReleasedIterator struct {
+ Event *BurnMintTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolReleased)
+ 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(BurnMintTokenPoolReleased)
+ 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 *BurnMintTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolReleasedIterator{contract: _BurnMintTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolReleased)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Released", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseReleased(log types.Log) (*BurnMintTokenPoolReleased, error) {
+ event := new(BurnMintTokenPoolReleased)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _BurnMintTokenPool.abi.Events["AllowListAdd"].ID:
+ return _BurnMintTokenPool.ParseAllowListAdd(log)
+ case _BurnMintTokenPool.abi.Events["AllowListRemove"].ID:
+ return _BurnMintTokenPool.ParseAllowListRemove(log)
+ case _BurnMintTokenPool.abi.Events["Burned"].ID:
+ return _BurnMintTokenPool.ParseBurned(log)
+ case _BurnMintTokenPool.abi.Events["Locked"].ID:
+ return _BurnMintTokenPool.ParseLocked(log)
+ case _BurnMintTokenPool.abi.Events["Minted"].ID:
+ return _BurnMintTokenPool.ParseMinted(log)
+ case _BurnMintTokenPool.abi.Events["OffRampAdded"].ID:
+ return _BurnMintTokenPool.ParseOffRampAdded(log)
+ case _BurnMintTokenPool.abi.Events["OffRampConfigured"].ID:
+ return _BurnMintTokenPool.ParseOffRampConfigured(log)
+ case _BurnMintTokenPool.abi.Events["OffRampRemoved"].ID:
+ return _BurnMintTokenPool.ParseOffRampRemoved(log)
+ case _BurnMintTokenPool.abi.Events["OnRampAdded"].ID:
+ return _BurnMintTokenPool.ParseOnRampAdded(log)
+ case _BurnMintTokenPool.abi.Events["OnRampConfigured"].ID:
+ return _BurnMintTokenPool.ParseOnRampConfigured(log)
+ case _BurnMintTokenPool.abi.Events["OnRampRemoved"].ID:
+ return _BurnMintTokenPool.ParseOnRampRemoved(log)
+ case _BurnMintTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _BurnMintTokenPool.ParseOwnershipTransferRequested(log)
+ case _BurnMintTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _BurnMintTokenPool.ParseOwnershipTransferred(log)
+ case _BurnMintTokenPool.abi.Events["Released"].ID:
+ return _BurnMintTokenPool.ParseReleased(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (BurnMintTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (BurnMintTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (BurnMintTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (BurnMintTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (BurnMintTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (BurnMintTokenPoolOffRampAdded) Topic() common.Hash {
+ return common.HexToHash("0x395b7374909d2b54e5796f53c898ebf41d767c86c78ea86519acf2b805852d88")
+}
+
+func (BurnMintTokenPoolOffRampConfigured) Topic() common.Hash {
+ return common.HexToHash("0xb3ba339cfbb8ef80d7a29ce5493051cb90e64fcfa85d7124efc1adfa4c68399f")
+}
+
+func (BurnMintTokenPoolOffRampRemoved) Topic() common.Hash {
+ return common.HexToHash("0xcf91daec21e3510e2f2aea4b09d08c235d5c6844980be709f282ef591dbf420c")
+}
+
+func (BurnMintTokenPoolOnRampAdded) Topic() common.Hash {
+ return common.HexToHash("0x0b594bb0555ff7b252e0c789ccc9d8903fec294172064308727d570505cee1ac")
+}
+
+func (BurnMintTokenPoolOnRampConfigured) Topic() common.Hash {
+ return common.HexToHash("0x578db78e348076074dbff64a94073a83e9a65aa6766b8c75fdc89282b0e30ed6")
+}
+
+func (BurnMintTokenPoolOnRampRemoved) Topic() common.Hash {
+ return common.HexToHash("0x7fd064821314ad863a0714a3f1229375ace6b6427ed5544b7b2ba1c47b1b5294")
+}
+
+func (BurnMintTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (BurnMintTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (BurnMintTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPool) Address() common.Address {
+ return _BurnMintTokenPool.address
+}
+
+type BurnMintTokenPoolInterface interface {
+ CurrentOffRampRateLimiterState(opts *bind.CallOpts, offRamp common.Address) (RateLimiterTokenBucket, error)
+
+ CurrentOnRampRateLimiterState(opts *bind.CallOpts, onRamp common.Address) (RateLimiterTokenBucket, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetArmProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetOffRamps(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetOnRamps(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsOffRamp(opts *bind.CallOpts, offRamp common.Address) (bool, error)
+
+ IsOnRamp(opts *bind.CallOpts, onRamp common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyRampUpdates(opts *bind.TransactOpts, onRamps []TokenPoolRampUpdate, offRamps []TokenPoolRampUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, arg1 []byte, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error)
+
+ SetOffRampRateLimiterConfig(opts *bind.TransactOpts, offRamp common.Address, config RateLimiterConfig) (*types.Transaction, error)
+
+ SetOnRampRateLimiterConfig(opts *bind.TransactOpts, onRamp common.Address, config RateLimiterConfig) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*BurnMintTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*BurnMintTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*BurnMintTokenPoolBurned, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*BurnMintTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*BurnMintTokenPoolMinted, error)
+
+ FilterOffRampAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolOffRampAddedIterator, error)
+
+ WatchOffRampAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOffRampAdded) (event.Subscription, error)
+
+ ParseOffRampAdded(log types.Log) (*BurnMintTokenPoolOffRampAdded, error)
+
+ FilterOffRampConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolOffRampConfiguredIterator, error)
+
+ WatchOffRampConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOffRampConfigured) (event.Subscription, error)
+
+ ParseOffRampConfigured(log types.Log) (*BurnMintTokenPoolOffRampConfigured, error)
+
+ FilterOffRampRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolOffRampRemovedIterator, error)
+
+ WatchOffRampRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOffRampRemoved) (event.Subscription, error)
+
+ ParseOffRampRemoved(log types.Log) (*BurnMintTokenPoolOffRampRemoved, error)
+
+ FilterOnRampAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolOnRampAddedIterator, error)
+
+ WatchOnRampAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOnRampAdded) (event.Subscription, error)
+
+ ParseOnRampAdded(log types.Log) (*BurnMintTokenPoolOnRampAdded, error)
+
+ FilterOnRampConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolOnRampConfiguredIterator, error)
+
+ WatchOnRampConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOnRampConfigured) (event.Subscription, error)
+
+ ParseOnRampConfigured(log types.Log) (*BurnMintTokenPoolOnRampConfigured, error)
+
+ FilterOnRampRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolOnRampRemovedIterator, error)
+
+ WatchOnRampRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOnRampRemoved) (event.Subscription, error)
+
+ ParseOnRampRemoved(log types.Log) (*BurnMintTokenPoolOnRampRemoved, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*BurnMintTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*BurnMintTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*BurnMintTokenPoolReleased, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_4_0/burn_mint_token_pool_1_4_0.go b/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_4_0/burn_mint_token_pool_1_4_0.go
new file mode 100644
index 00000000000..5beb58e096d
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_4_0/burn_mint_token_pool_1_4_0.go
@@ -0,0 +1,2264 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package burn_mint_token_pool_1_4_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var BurnMintTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIBurnMintERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRatelimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getArmProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"releaseOrMint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x60e06040523480156200001157600080fd5b50604051620034503803806200345083398101604081905262000034916200054d565b8383838333806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000163565b5050506001600160a01b0384161580620000e357506001600160a01b038116155b1562000102576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c05262000155576040805160008152602081019091526200015590846200020e565b5050505050505050620006d1565b336001600160a01b03821603620001bd5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c0516200022f576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002c45760008382815181106200025357620002536200065d565b602090810291909101015190506200026d6002826200037f565b15620002b0576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50620002bc8162000689565b905062000232565b5060005b81518110156200037a576000828281518110620002e957620002e96200065d565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000315575062000367565b620003226002826200039f565b1562000365576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b620003728162000689565b9050620002c8565b505050565b600062000396836001600160a01b038416620003b6565b90505b92915050565b600062000396836001600160a01b038416620004ba565b60008181526001830160205260408120548015620004af576000620003dd600183620006a5565b8554909150600090620003f390600190620006a5565b90508181146200045f5760008660000182815481106200041757620004176200065d565b90600052602060002001549050808760000184815481106200043d576200043d6200065d565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620004735762000473620006bb565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000399565b600091505062000399565b6000818152600183016020526040812054620005035750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000399565b50600062000399565b6001600160a01b03811681146200052257600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b805162000548816200050c565b919050565b600080600080608085870312156200056457600080fd5b845162000571816200050c565b602086810151919550906001600160401b03808211156200059157600080fd5b818801915088601f830112620005a657600080fd5b815181811115620005bb57620005bb62000525565b8060051b604051601f19603f83011681018181108582111715620005e357620005e362000525565b60405291825284820192508381018501918b8311156200060257600080fd5b938501935b828510156200062b576200061b856200053b565b8452938501939285019262000607565b80985050505050505062000642604086016200053b565b915062000652606086016200053b565b905092959194509250565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016200069e576200069e62000673565b5060010190565b8181038181111562000399576200039962000673565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c051612d1762000739600039600081816103c80152818161100c01526115b501526000818161022b01528181610baf01526110900152600081816101e401528181610df0015281816118f50152818161198001526119d30152612d176000f3fe608060405234801561001057600080fd5b506004361061016c5760003560e01c806396875445116100cd578063c4bffe2b11610081578063cf7401f311610066578063cf7401f3146103b3578063e0351e13146103c6578063f2fde38b146103ec57600080fd5b8063c4bffe2b1461038b578063c75eea9c146103a057600080fd5b8063af58d59f116100b2578063af58d59f146102eb578063b0f479a11461035a578063c0d786551461037857600080fd5b806396875445146102c3578063a7cd63b7146102d657600080fd5b80635995f063116101245780638627fad6116101095780638627fad61461027f5780638926f54f146102925780638da5cb5b146102a557600080fd5b80635995f0631461026457806379ba50971461027757600080fd5b806321df0da71161015557806321df0da7146101e25780635246492f1461022957806354c8a4f31461024f57600080fd5b806301ffc9a714610171578063181f5a7714610199575b600080fd5b61018461017f366004612425565b6103ff565b60405190151581526020015b60405180910390f35b6101d56040518060400160405280601781526020017f4275726e4d696e74546f6b656e506f6f6c20312e342e3000000000000000000081525081565b60405161019091906124cb565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610190565b7f0000000000000000000000000000000000000000000000000000000000000000610204565b61026261025d36600461252a565b610498565b005b610262610272366004612596565b610513565b610262610ab0565b61026261028d366004612724565b610bad565b6101846102a03660046127b8565b610ea1565b60005473ffffffffffffffffffffffffffffffffffffffff16610204565b6101d56102d1366004612815565b610eb8565b6102de6111b9565b60405161019091906128b5565b6102fe6102f93660046127b8565b6111ca565b604051610190919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610204565b61026261038636600461290f565b61129c565b610393611377565b604051610190919061292c565b6102fe6103ae3660046127b8565b611437565b6102626103c1366004612a0d565b611509565b7f0000000000000000000000000000000000000000000000000000000000000000610184565b6102626103fa36600461290f565b61151c565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f317fa33400000000000000000000000000000000000000000000000000000000148061049257507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6104a0611530565b61050d848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208088028281018201909352878252909350879250869182918501908490808284376000920191909152506115b392505050565b50505050565b61051b611530565b60005b81811015610aab57600083838381811061053a5761053a612a52565b905061010002018036038101906105519190612a81565b90506105668160400151826020015115611779565b6105798160600151826020015115611779565b80602001511561099f57805161059b9060059067ffffffffffffffff166118b6565b6105e55780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024015b60405180910390fd5b6040518060a001604052808260400151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff168152602001826040015160000151151581526020018260400151602001516fffffffffffffffffffffffffffffffff1681526020018260400151604001516fffffffffffffffffffffffffffffffff1681525060076000836000015167ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548160ff02191690831515021790555060608201518160010160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050506040518060a001604052808260600151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff168152602001826060015160000151151581526020018260600151602001516fffffffffffffffffffffffffffffffff1681526020018260600151604001516fffffffffffffffffffffffffffffffff1681525060086000836000015167ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548160ff02191690831515021790555060608201518160010160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050507f0f135cbb9afa12a8bf3bbd071c117bcca4ddeca6160ef7f33d012a81b9c0c47181600001518260400151836060015160405161099293929190612b03565b60405180910390a1610a9a565b80516109b79060059067ffffffffffffffff166118c9565b6109fc5780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016105dc565b805167ffffffffffffffff908116600090815260086020908152604080832080547fffffffffffffffffffffff0000000000000000000000000000000000000000009081168255600191820185905586518616855260078452828520805490911681550192909255835191519190921681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916910160405180910390a15b50610aa481612bb5565b905061051e565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b31576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105dc565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3c9190612bed565b15610c73576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81610c7d81610ea1565b610cbf576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201526024016105dc565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015610d3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d629190612bed565b610d9a576040517f728fe07b0000000000000000000000000000000000000000000000000000000081523360048201526024016105dc565b610da483856118d5565b6040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b158015610e3457600080fd5b505af1158015610e48573d6000803e3d6000fd5b505060405186815273ffffffffffffffffffffffffffffffffffffffff881692503391507f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f09060200160405180910390a3505050505050565b6000610492600567ffffffffffffffff8416611919565b606083610ec481610ea1565b610f06576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201526024016105dc565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015610f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa39190612c0a565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611009576040517f728fe07b0000000000000000000000000000000000000000000000000000000081523360048201526024016105dc565b887f0000000000000000000000000000000000000000000000000000000000000000801561103f575061103d600282611931565b155b1561108e576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016105dc565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111d9190612bed565b15611154576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61115e8688611960565b611167876119a4565b60405187815233907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a2505060408051602081019091526000815298975050505050505050565b60606111c56002611a47565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260086020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600190910154808416606083015291909104909116608082015261049290611a54565b6112a4611530565b73ffffffffffffffffffffffffffffffffffffffff81166112f1576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684910160405180910390a15050565b606060006113856005611a47565b90506000815167ffffffffffffffff8111156113a3576113a361260b565b6040519080825280602002602001820160405280156113cc578160200160208202803683370190505b50905060005b8251811015611430578281815181106113ed576113ed612a52565b602002602001015182828151811061140757611407612a52565b67ffffffffffffffff9092166020928302919091019091015261142981612bb5565b90506113d2565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600190910154808416606083015291909104909116608082015261049290611a54565b611511611530565b610aab838383611b06565b611524611530565b61152d81611bed565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146115b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105dc565b565b7f000000000000000000000000000000000000000000000000000000000000000061160a576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82518110156116a857600083828151811061162a5761162a612a52565b60200260200101519050611648816002611ce290919063ffffffff16565b156116975760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506116a181612bb5565b905061160d565b5060005b8151811015610aab5760008282815181106116c9576116c9612a52565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361170d5750611769565b611718600282611d04565b156117675760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b61177281612bb5565b90506116ac565b8151156118445781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff161015806117cf575060408201516fffffffffffffffffffffffffffffffff16155b1561180857816040517f70505e560000000000000000000000000000000000000000000000000000000081526004016105dc9190612c27565b8015611840576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60408201516fffffffffffffffffffffffffffffffff1615158061187d575060208201516fffffffffffffffffffffffffffffffff1615155b1561184057816040517fd68af9cc0000000000000000000000000000000000000000000000000000000081526004016105dc9190612c27565b60006118c28383611d22565b9392505050565b60006118c28383611d71565b67ffffffffffffffff8216600090815260086020526040902061184090827f0000000000000000000000000000000000000000000000000000000000000000611e64565b600081815260018301602052604081205415156118c2565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156118c2565b67ffffffffffffffff8216600090815260076020526040902061184090827f0000000000000000000000000000000000000000000000000000000000000000611e64565b6040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906342966c6890602401600060405180830381600087803b158015611a2c57600080fd5b505af1158015611a40573d6000803e3d6000fd5b5050505050565b606060006118c2836121e7565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611ae282606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611ac69190612c63565b85608001516fffffffffffffffffffffffffffffffff16612243565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b611b0f83610ea1565b611b51576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024016105dc565b611b5c826000611779565b67ffffffffffffffff83166000908152600760205260409020611b7f908361226d565b611b8a816000611779565b67ffffffffffffffff83166000908152600860205260409020611bad908261226d565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051611be093929190612b03565b60405180910390a1505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611c6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105dc565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006118c28373ffffffffffffffffffffffffffffffffffffffff8416611d71565b60006118c28373ffffffffffffffffffffffffffffffffffffffff84165b6000818152600183016020526040812054611d6957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610492565b506000610492565b60008181526001830160205260408120548015611e5a576000611d95600183612c63565b8554909150600090611da990600190612c63565b9050818114611e0e576000866000018281548110611dc957611dc9612a52565b9060005260206000200154905080876000018481548110611dec57611dec612a52565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611e1f57611e1f612c76565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610492565b6000915050610492565b825474010000000000000000000000000000000000000000900460ff161580611e8b575081155b15611e9557505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090611edb90700100000000000000000000000000000000900463ffffffff1642612c63565b90508015611f9b5781831115611f1d576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001860154611f579083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612243565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156120525773ffffffffffffffffffffffffffffffffffffffff8416611ffa576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016105dc565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff851660448201526064016105dc565b848310156121655760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906120969082612c63565b6120a0878a612c63565b6120aa9190612ca5565b6120b49190612cb8565b905073ffffffffffffffffffffffffffffffffffffffff861661210d576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016105dc565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff871660448201526064016105dc565b61216f8584612c63565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561223757602002820191906000526020600020905b815481526020019060010190808311612223575b50505050509050919050565b6000612262856122538486612cf3565b61225d9087612ca5565b61240f565b90505b949350505050565b815460009061229690700100000000000000000000000000000000900463ffffffff1642612c63565b9050801561233857600183015483546122de916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612243565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b6020820151835461235e916fffffffffffffffffffffffffffffffff908116911661240f565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990611be0908490612c27565b600081831061241e57816118c2565b5090919050565b60006020828403121561243757600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146118c257600080fd5b6000815180845260005b8181101561248d57602081850181015186830182015201612471565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006118c26020830184612467565b60008083601f8401126124f057600080fd5b50813567ffffffffffffffff81111561250857600080fd5b6020830191508360208260051b850101111561252357600080fd5b9250929050565b6000806000806040858703121561254057600080fd5b843567ffffffffffffffff8082111561255857600080fd5b612564888389016124de565b9096509450602087013591508082111561257d57600080fd5b5061258a878288016124de565b95989497509550505050565b600080602083850312156125a957600080fd5b823567ffffffffffffffff808211156125c157600080fd5b818501915085601f8301126125d557600080fd5b8135818111156125e457600080fd5b8660208260081b85010111156125f957600080fd5b60209290920196919550909350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261264b57600080fd5b813567ffffffffffffffff808211156126665761266661260b565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156126ac576126ac61260b565b816040528381528660208588010111156126c557600080fd5b836020870160208301376000602085830101528094505050505092915050565b73ffffffffffffffffffffffffffffffffffffffff8116811461152d57600080fd5b803567ffffffffffffffff8116811461271f57600080fd5b919050565b600080600080600060a0868803121561273c57600080fd5b853567ffffffffffffffff8082111561275457600080fd5b61276089838a0161263a565b965060208801359150612772826126e5565b8195506040880135945061278860608901612707565b9350608088013591508082111561279e57600080fd5b506127ab8882890161263a565b9150509295509295909350565b6000602082840312156127ca57600080fd5b6118c282612707565b60008083601f8401126127e557600080fd5b50813567ffffffffffffffff8111156127fd57600080fd5b60208301915083602082850101111561252357600080fd5b600080600080600080600060a0888a03121561283057600080fd5b873561283b816126e5565b9650602088013567ffffffffffffffff8082111561285857600080fd5b6128648b838c016127d3565b909850965060408a0135955086915061287f60608b01612707565b945060808a013591508082111561289557600080fd5b506128a28a828b016127d3565b989b979a50959850939692959293505050565b6020808252825182820181905260009190848201906040850190845b8181101561290357835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016128d1565b50909695505050505050565b60006020828403121561292157600080fd5b81356118c2816126e5565b6020808252825182820181905260009190848201906040850190845b8181101561290357835167ffffffffffffffff1683529284019291840191600101612948565b801515811461152d57600080fd5b80356fffffffffffffffffffffffffffffffff8116811461271f57600080fd5b6000606082840312156129ae57600080fd5b6040516060810181811067ffffffffffffffff821117156129d1576129d161260b565b60405290508082356129e28161296e565b81526129f06020840161297c565b6020820152612a016040840161297c565b60408201525092915050565b600080600060e08486031215612a2257600080fd5b612a2b84612707565b9250612a3a856020860161299c565b9150612a49856080860161299c565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006101008284031215612a9457600080fd5b6040516080810181811067ffffffffffffffff82111715612ab757612ab761260b565b604052612ac383612707565b81526020830135612ad38161296e565b6020820152612ae5846040850161299c565b6040820152612af78460a0850161299c565b60608201529392505050565b67ffffffffffffffff8416815260e08101612b4f60208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c0830152612265565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612be657612be6612b86565b5060010190565b600060208284031215612bff57600080fd5b81516118c28161296e565b600060208284031215612c1c57600080fd5b81516118c2816126e5565b6060810161049282848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b8181038181111561049257610492612b86565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b8082018082111561049257610492612b86565b600082612cee577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b808202811582820484141761049257610492612b8656fea164736f6c6343000813000a",
+}
+
+var BurnMintTokenPoolABI = BurnMintTokenPoolMetaData.ABI
+
+var BurnMintTokenPoolBin = BurnMintTokenPoolMetaData.Bin
+
+func DeployBurnMintTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, armProxy common.Address, router common.Address) (common.Address, *types.Transaction, *BurnMintTokenPool, error) {
+ parsed, err := BurnMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BurnMintTokenPoolBin), backend, token, allowlist, armProxy, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &BurnMintTokenPool{address: address, abi: *parsed, BurnMintTokenPoolCaller: BurnMintTokenPoolCaller{contract: contract}, BurnMintTokenPoolTransactor: BurnMintTokenPoolTransactor{contract: contract}, BurnMintTokenPoolFilterer: BurnMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+type BurnMintTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ BurnMintTokenPoolCaller
+ BurnMintTokenPoolTransactor
+ BurnMintTokenPoolFilterer
+}
+
+type BurnMintTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolSession struct {
+ Contract *BurnMintTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type BurnMintTokenPoolCallerSession struct {
+ Contract *BurnMintTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type BurnMintTokenPoolTransactorSession struct {
+ Contract *BurnMintTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type BurnMintTokenPoolRaw struct {
+ Contract *BurnMintTokenPool
+}
+
+type BurnMintTokenPoolCallerRaw struct {
+ Contract *BurnMintTokenPoolCaller
+}
+
+type BurnMintTokenPoolTransactorRaw struct {
+ Contract *BurnMintTokenPoolTransactor
+}
+
+func NewBurnMintTokenPool(address common.Address, backend bind.ContractBackend) (*BurnMintTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(BurnMintTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindBurnMintTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPool{address: address, abi: abi, BurnMintTokenPoolCaller: BurnMintTokenPoolCaller{contract: contract}, BurnMintTokenPoolTransactor: BurnMintTokenPoolTransactor{contract: contract}, BurnMintTokenPoolFilterer: BurnMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewBurnMintTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*BurnMintTokenPoolCaller, error) {
+ contract, err := bindBurnMintTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolCaller{contract: contract}, nil
+}
+
+func NewBurnMintTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*BurnMintTokenPoolTransactor, error) {
+ contract, err := bindBurnMintTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewBurnMintTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*BurnMintTokenPoolFilterer, error) {
+ contract, err := bindBurnMintTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindBurnMintTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := BurnMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.BurnMintTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnMintTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetAllowList(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetAllowList(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _BurnMintTokenPool.Contract.GetAllowListEnabled(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _BurnMintTokenPool.Contract.GetAllowListEnabled(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetArmProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getArmProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetArmProxy() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetArmProxy(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetArmProxy() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetArmProxy(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetRouter() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetRouter(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetRouter(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnMintTokenPool.Contract.GetSupportedChains(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnMintTokenPool.Contract.GetSupportedChains(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) GetToken() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetToken(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.GetToken(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsSupportedChain(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnMintTokenPool.Contract.IsSupportedChain(&_BurnMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) Owner() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.Owner(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _BurnMintTokenPool.Contract.Owner(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnMintTokenPool.Contract.SupportsInterface(&_BurnMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnMintTokenPool.Contract.SupportsInterface(&_BurnMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _BurnMintTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) TypeAndVersion() (string, error) {
+ return _BurnMintTokenPool.Contract.TypeAndVersion(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _BurnMintTokenPool.Contract.TypeAndVersion(&_BurnMintTokenPool.CallOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.AcceptOwnership(&_BurnMintTokenPool.TransactOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.AcceptOwnership(&_BurnMintTokenPool.TransactOpts)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyChainUpdates(&_BurnMintTokenPool.TransactOpts, chains)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ApplyChainUpdates(&_BurnMintTokenPool.TransactOpts, chains)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, arg1 []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "lockOrBurn", originalSender, arg1, amount, remoteChainSelector, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) LockOrBurn(originalSender common.Address, arg1 []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.LockOrBurn(&_BurnMintTokenPool.TransactOpts, originalSender, arg1, amount, remoteChainSelector, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) LockOrBurn(originalSender common.Address, arg1 []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.LockOrBurn(&_BurnMintTokenPool.TransactOpts, originalSender, arg1, amount, remoteChainSelector, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "releaseOrMint", arg0, receiver, amount, remoteChainSelector, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ReleaseOrMint(&_BurnMintTokenPool.TransactOpts, arg0, receiver, amount, remoteChainSelector, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.ReleaseOrMint(&_BurnMintTokenPool.TransactOpts, arg0, receiver, amount, remoteChainSelector, arg4)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetRouter(&_BurnMintTokenPool.TransactOpts, newRouter)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.SetRouter(&_BurnMintTokenPool.TransactOpts, newRouter)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.TransferOwnership(&_BurnMintTokenPool.TransactOpts, to)
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPool.Contract.TransferOwnership(&_BurnMintTokenPool.TransactOpts, to)
+}
+
+type BurnMintTokenPoolAllowListAddIterator struct {
+ Event *BurnMintTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAllowListAdd)
+ 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(BurnMintTokenPoolAllowListAdd)
+ 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 *BurnMintTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAllowListAddIterator{contract: _BurnMintTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAllowListAdd)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*BurnMintTokenPoolAllowListAdd, error) {
+ event := new(BurnMintTokenPoolAllowListAdd)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAllowListRemoveIterator struct {
+ Event *BurnMintTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAllowListRemove)
+ 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(BurnMintTokenPoolAllowListRemove)
+ 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 *BurnMintTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAllowListRemoveIterator{contract: _BurnMintTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAllowListRemove)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*BurnMintTokenPoolAllowListRemove, error) {
+ event := new(BurnMintTokenPoolAllowListRemove)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolBurnedIterator struct {
+ Event *BurnMintTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolBurned)
+ 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(BurnMintTokenPoolBurned)
+ 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 *BurnMintTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolBurnedIterator{contract: _BurnMintTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolBurned)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Burned", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseBurned(log types.Log) (*BurnMintTokenPoolBurned, error) {
+ event := new(BurnMintTokenPoolBurned)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolChainAddedIterator struct {
+ Event *BurnMintTokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolChainAdded)
+ 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(BurnMintTokenPoolChainAdded)
+ 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 *BurnMintTokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolChainAddedIterator{contract: _BurnMintTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolChainAdded)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseChainAdded(log types.Log) (*BurnMintTokenPoolChainAdded, error) {
+ event := new(BurnMintTokenPoolChainAdded)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolChainConfiguredIterator struct {
+ Event *BurnMintTokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolChainConfigured)
+ 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(BurnMintTokenPoolChainConfigured)
+ 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 *BurnMintTokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolChainConfiguredIterator{contract: _BurnMintTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolChainConfigured)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseChainConfigured(log types.Log) (*BurnMintTokenPoolChainConfigured, error) {
+ event := new(BurnMintTokenPoolChainConfigured)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolChainRemovedIterator struct {
+ Event *BurnMintTokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolChainRemoved)
+ 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(BurnMintTokenPoolChainRemoved)
+ 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 *BurnMintTokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolChainRemovedIterator{contract: _BurnMintTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolChainRemoved)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseChainRemoved(log types.Log) (*BurnMintTokenPoolChainRemoved, error) {
+ event := new(BurnMintTokenPoolChainRemoved)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolLockedIterator struct {
+ Event *BurnMintTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolLocked)
+ 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(BurnMintTokenPoolLocked)
+ 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 *BurnMintTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolLockedIterator{contract: _BurnMintTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolLocked)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Locked", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseLocked(log types.Log) (*BurnMintTokenPoolLocked, error) {
+ event := new(BurnMintTokenPoolLocked)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolMintedIterator struct {
+ Event *BurnMintTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolMinted)
+ 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(BurnMintTokenPoolMinted)
+ 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 *BurnMintTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolMintedIterator{contract: _BurnMintTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolMinted)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Minted", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseMinted(log types.Log) (*BurnMintTokenPoolMinted, error) {
+ event := new(BurnMintTokenPoolMinted)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *BurnMintTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOwnershipTransferRequested)
+ 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(BurnMintTokenPoolOwnershipTransferRequested)
+ 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 *BurnMintTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOwnershipTransferRequestedIterator{contract: _BurnMintTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*BurnMintTokenPoolOwnershipTransferRequested, error) {
+ event := new(BurnMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolOwnershipTransferredIterator struct {
+ Event *BurnMintTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolOwnershipTransferred)
+ 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(BurnMintTokenPoolOwnershipTransferred)
+ 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 *BurnMintTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolOwnershipTransferredIterator{contract: _BurnMintTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolOwnershipTransferred)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*BurnMintTokenPoolOwnershipTransferred, error) {
+ event := new(BurnMintTokenPoolOwnershipTransferred)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolReleasedIterator struct {
+ Event *BurnMintTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolReleased)
+ 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(BurnMintTokenPoolReleased)
+ 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 *BurnMintTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolReleasedIterator{contract: _BurnMintTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolReleased)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Released", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseReleased(log types.Log) (*BurnMintTokenPoolReleased, error) {
+ event := new(BurnMintTokenPoolReleased)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolRouterUpdatedIterator struct {
+ Event *BurnMintTokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolRouterUpdated)
+ 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(BurnMintTokenPoolRouterUpdated)
+ 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 *BurnMintTokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*BurnMintTokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolRouterUpdatedIterator{contract: _BurnMintTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolRouterUpdated)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_BurnMintTokenPool *BurnMintTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*BurnMintTokenPoolRouterUpdated, error) {
+ event := new(BurnMintTokenPoolRouterUpdated)
+ if err := _BurnMintTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _BurnMintTokenPool.abi.Events["AllowListAdd"].ID:
+ return _BurnMintTokenPool.ParseAllowListAdd(log)
+ case _BurnMintTokenPool.abi.Events["AllowListRemove"].ID:
+ return _BurnMintTokenPool.ParseAllowListRemove(log)
+ case _BurnMintTokenPool.abi.Events["Burned"].ID:
+ return _BurnMintTokenPool.ParseBurned(log)
+ case _BurnMintTokenPool.abi.Events["ChainAdded"].ID:
+ return _BurnMintTokenPool.ParseChainAdded(log)
+ case _BurnMintTokenPool.abi.Events["ChainConfigured"].ID:
+ return _BurnMintTokenPool.ParseChainConfigured(log)
+ case _BurnMintTokenPool.abi.Events["ChainRemoved"].ID:
+ return _BurnMintTokenPool.ParseChainRemoved(log)
+ case _BurnMintTokenPool.abi.Events["Locked"].ID:
+ return _BurnMintTokenPool.ParseLocked(log)
+ case _BurnMintTokenPool.abi.Events["Minted"].ID:
+ return _BurnMintTokenPool.ParseMinted(log)
+ case _BurnMintTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _BurnMintTokenPool.ParseOwnershipTransferRequested(log)
+ case _BurnMintTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _BurnMintTokenPool.ParseOwnershipTransferred(log)
+ case _BurnMintTokenPool.abi.Events["Released"].ID:
+ return _BurnMintTokenPool.ParseReleased(log)
+ case _BurnMintTokenPool.abi.Events["RouterUpdated"].ID:
+ return _BurnMintTokenPool.ParseRouterUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (BurnMintTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (BurnMintTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (BurnMintTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (BurnMintTokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x0f135cbb9afa12a8bf3bbd071c117bcca4ddeca6160ef7f33d012a81b9c0c471")
+}
+
+func (BurnMintTokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (BurnMintTokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (BurnMintTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (BurnMintTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (BurnMintTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (BurnMintTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (BurnMintTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (BurnMintTokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (_BurnMintTokenPool *BurnMintTokenPool) Address() common.Address {
+ return _BurnMintTokenPool.address
+}
+
+type BurnMintTokenPoolInterface interface {
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetArmProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, arg1 []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*BurnMintTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*BurnMintTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*BurnMintTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*BurnMintTokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*BurnMintTokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*BurnMintTokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*BurnMintTokenPoolChainRemoved, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*BurnMintTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*BurnMintTokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*BurnMintTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*BurnMintTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*BurnMintTokenPoolReleased, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*BurnMintTokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*BurnMintTokenPoolRouterUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/burn_mint_token_pool_and_proxy/burn_mint_token_pool_and_proxy.go b/core/gethwrappers/ccip/generated/burn_mint_token_pool_and_proxy/burn_mint_token_pool_and_proxy.go
new file mode 100644
index 00000000000..b7ef3167646
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/burn_mint_token_pool_and_proxy/burn_mint_token_pool_and_proxy.go
@@ -0,0 +1,2972 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package burn_mint_token_pool_and_proxy
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type PoolLockOrBurnInV1 struct {
+ Receiver []byte
+ RemoteChainSelector uint64
+ OriginalSender common.Address
+ Amount *big.Int
+ LocalToken common.Address
+}
+
+type PoolLockOrBurnOutV1 struct {
+ DestTokenAddress []byte
+ DestPoolData []byte
+}
+
+type PoolReleaseOrMintInV1 struct {
+ OriginalSender []byte
+ RemoteChainSelector uint64
+ Receiver common.Address
+ Amount *big.Int
+ LocalToken common.Address
+ SourcePoolAddress []byte
+ SourcePoolData []byte
+ OffchainTokenData []byte
+}
+
+type PoolReleaseOrMintOutV1 struct {
+ DestinationAmount *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ RemotePoolAddress []byte
+ RemoteTokenAddress []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var BurnMintTokenPoolAndProxyMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIBurnMintERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRateLimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidSourcePoolAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remoteToken\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contractIPoolPriorTo1_5\",\"name\":\"oldPool\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"contractIPoolPriorTo1_5\",\"name\":\"newPool\",\"type\":\"address\"}],\"name\":\"LegacyPoolChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousPoolAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"RemotePoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"remoteTokenAddress\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"getOnRamp\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"onRampAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemotePool\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemoteToken\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRmnProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"isOffRamp\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"isSupportedToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structPool.LockOrBurnInV1\",\"name\":\"lockOrBurnIn\",\"type\":\"tuple\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destPoolData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.LockOrBurnOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainTokenData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.ReleaseOrMintInV1\",\"name\":\"releaseOrMintIn\",\"type\":\"tuple\"}],\"name\":\"releaseOrMint\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destinationAmount\",\"type\":\"uint256\"}],\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIPoolPriorTo1_5\",\"name\":\"prevPool\",\"type\":\"address\"}],\"name\":\"setPreviousPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"setRemotePool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x60e06040523480156200001157600080fd5b506040516200481e3803806200481e833981016040819052620000349162000554565b83838383838383833380600081620000935760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c657620000c6816200017e565b5050506001600160a01b0384161580620000e757506001600160a01b038116155b80620000fa57506001600160a01b038216155b1562000119576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c0526200016c576040805160008152602081019091526200016c908462000229565b505050505050505050505050620006b2565b336001600160a01b03821603620001d85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008a565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c0516200024a576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002d55760008382815181106200026e576200026e62000664565b602090810291909101015190506200028860028262000386565b15620002cb576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506001016200024d565b5060005b815181101562000381576000828281518110620002fa57620002fa62000664565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000326575062000378565b62000333600282620003a6565b1562000376576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101620002d9565b505050565b60006200039d836001600160a01b038416620003bd565b90505b92915050565b60006200039d836001600160a01b038416620004c1565b60008181526001830160205260408120548015620004b6576000620003e46001836200067a565b8554909150600090620003fa906001906200067a565b9050818114620004665760008660000182815481106200041e576200041e62000664565b906000526020600020015490508087600001848154811062000444576200044462000664565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806200047a576200047a6200069c565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050620003a0565b6000915050620003a0565b60008181526001830160205260408120546200050a57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620003a0565b506000620003a0565b6001600160a01b03811681146200052957600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b80516200054f8162000513565b919050565b600080600080608085870312156200056b57600080fd5b8451620005788162000513565b602086810151919550906001600160401b03808211156200059857600080fd5b818801915088601f830112620005ad57600080fd5b815181811115620005c257620005c26200052c565b8060051b604051601f19603f83011681018181108582111715620005ea57620005ea6200052c565b60405291825284820192508381018501918b8311156200060957600080fd5b938501935b828510156200063257620006228562000542565b845293850193928501926200060e565b809850505050505050620006496040860162000542565b9150620006596060860162000542565b905092959194509250565b634e487b7160e01b600052603260045260246000fd5b81810381811115620003a057634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c0516140e862000736600039600081816104bc0152818161197001526123c2015260008181610496015281816117080152611c23015260008181610210015281816102650152818161071901528181610d040152818161162801528181611b4301528181611d290152818161235801526125ad01526140e86000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80639a4575b9116100f9578063c4bffe2b11610097578063db6327dc11610071578063db6327dc14610481578063dc0bd97114610494578063e0351e13146104ba578063f2fde38b146104e057600080fd5b8063c4bffe2b14610446578063c75eea9c1461045b578063cf7401f31461046e57600080fd5b8063af58d59f116100d3578063af58d59f14610393578063b0f479a114610402578063b794658014610420578063c0d786551461043357600080fd5b80639a4575b91461034b578063a7cd63b71461036b578063a8d87a3b1461038057600080fd5b806354c8a4f31161016657806383826b2b1161014057806383826b2b146102f45780638926f54f146103075780638da5cb5b1461031a5780639766b9321461033857600080fd5b806354c8a4f3146102c457806378a010b2146102d957806379ba5097146102ec57600080fd5b806321df0da71161019757806321df0da71461020e578063240028e81461025557806339077537146102a257600080fd5b806301ffc9a7146101be5780630a2fd493146101e6578063181f5a7714610206575b600080fd5b6101d16101cc36600461305a565b6104f3565b60405190151581526020015b60405180910390f35b6101f96101f43660046130b9565b6105d8565b6040516101dd9190613142565b6101f9610688565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101dd565b6101d1610263366004613182565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b6102b56102b036600461319f565b6106a4565b604051905181526020016101dd565b6102d76102d2366004613227565b610831565b005b6102d76102e7366004613293565b6108ac565b6102d7610a20565b6101d1610302366004613316565b610b1d565b6101d16103153660046130b9565b610bea565b60005473ffffffffffffffffffffffffffffffffffffffff16610230565b6102d7610346366004613182565b610c01565b61035e61035936600461334d565b610c90565b6040516101dd9190613388565b610373610e00565b6040516101dd91906133e8565b61023061038e3660046130b9565b503090565b6103a66103a13660046130b9565b610e11565b6040516101dd919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610230565b6101f961042e3660046130b9565b610ee6565b6102d7610441366004613182565b610f11565b61044e610fe5565b6040516101dd9190613442565b6103a66104693660046130b9565b61109d565b6102d761047c3660046135f9565b61116f565b6102d761048f36600461363e565b611187565b7f0000000000000000000000000000000000000000000000000000000000000000610230565b7f00000000000000000000000000000000000000000000000000000000000000006101d1565b6102d76104ee366004613182565b61160d565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf00000000000000000000000000000000000000000000000000000000148061058657507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b806105d257507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b67ffffffffffffffff8116600090815260076020526040902060040180546060919061060390613680565b80601f016020809104026020016040519081016040528092919081815260200182805461062f90613680565b801561067c5780601f106106515761010080835404028352916020019161067c565b820191906000526020600020905b81548152906001019060200180831161065f57829003601f168201915b50505050509050919050565b6040518060600160405280602381526020016140b96023913981565b6040805160208101909152600081526106c46106bf8361376f565b611621565b60085473ffffffffffffffffffffffffffffffffffffffff1661078f576040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152606083013560248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906340c10f1990604401600060405180830381600087803b15801561077257600080fd5b505af1158015610786573d6000803e3d6000fd5b505050506107a0565b6107a061079b8361376f565b611852565b6107b06060830160408401613182565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0846060013560405161081291815260200190565b60405180910390a3506040805160208101909152606090910135815290565b6108396118eb565b6108a68484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061196e92505050565b50505050565b6108b46118eb565b6108bd83610bea565b610904576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b67ffffffffffffffff83166000908152600760205260408120600401805461092b90613680565b80601f016020809104026020016040519081016040528092919081815260200182805461095790613680565b80156109a45780601f10610979576101008083540402835291602001916109a4565b820191906000526020600020905b81548152906001019060200180831161098757829003601f168201915b5050505067ffffffffffffffff86166000908152600760205260409020919250506004016109d38385836138b4565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf828585604051610a12939291906139ce565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610aa1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108fb565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600073ffffffffffffffffffffffffffffffffffffffff8216301480610be35750600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff86169281019290925273ffffffffffffffffffffffffffffffffffffffff848116602484015216906383826b2b90604401602060405180830381865afa158015610bbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be39190613a32565b9392505050565b60006105d2600567ffffffffffffffff8416611b24565b610c096118eb565b6008805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f81accd0a7023865eaa51b3399dd0eafc488bf3ba238402911e1659cfe860f22891015b60405180910390a15050565b6040805180820190915260608082526020820152610cb5610cb083613a4f565b611b3c565b60085473ffffffffffffffffffffffffffffffffffffffff16610d7a576040517f42966c68000000000000000000000000000000000000000000000000000000008152606083013560048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906342966c6890602401600060405180830381600087803b158015610d5d57600080fd5b505af1158015610d71573d6000803e3d6000fd5b50505050610d8b565b610d8b610d8683613a4f565b611d06565b6040516060830135815233907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a26040518060400160405280610de584602001602081019061042e91906130b9565b81526040805160208181019092526000815291015292915050565b6060610e0c6002611e20565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260039091015480841660608301529190910490911660808201526105d290611e2d565b67ffffffffffffffff8116600090815260076020526040902060050180546060919061060390613680565b610f196118eb565b73ffffffffffffffffffffffffffffffffffffffff8116610f66576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f16849101610c84565b60606000610ff36005611e20565b90506000815167ffffffffffffffff81111561101157611011613484565b60405190808252806020026020018201604052801561103a578160200160208202803683370190505b50905060005b82518110156110965782818151811061105b5761105b613af1565b602002602001015182828151811061107557611075613af1565b67ffffffffffffffff90921660209283029190910190910152600101611040565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526105d290611e2d565b6111776118eb565b611182838383611edf565b505050565b61118f6118eb565b60005b818110156111825760008383838181106111ae576111ae613af1565b90506020028101906111c09190613b20565b6111c990613b5e565b90506111de8160800151826020015115611fc9565b6111f18160a00151826020015115611fc9565b8060200151156114ed5780516112139060059067ffffffffffffffff16612102565b6112585780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108fb565b604081015151158061126d5750606081015151155b156112a4576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c179091169615150295909517909855908101519401519381169316909102919091176003820155915190919060048201906114859082613c12565b506060820151600582019061149a9082613c12565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c295506114e09493929190613d2c565b60405180910390a1611604565b80516115059060059067ffffffffffffffff1661210e565b61154a5780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108fb565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906115b3600483018261300c565b6115c160058301600061300c565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b50600101611192565b6116156118eb565b61161e8161211a565b50565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146116b65760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016108fb565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611764573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117889190613a32565b156117bf576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117cc816020015161220f565b60006117db82602001516105d8565b90508051600014806117ff575080805190602001208260a001518051906020012014155b1561183c578160a001516040517f24eb47e50000000000000000000000000000000000000000000000000000000081526004016108fb9190613142565b61184e82602001518360600151612335565b5050565b6008548151606083015160208401516040517f8627fad600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90941693638627fad6936118b69390923392600401613dc5565b600060405180830381600087803b1580156118d057600080fd5b505af11580156118e4573d6000803e3d6000fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461196c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108fb565b565b7f00000000000000000000000000000000000000000000000000000000000000006119c5576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015611a5b5760008382815181106119e5576119e5613af1565b60200260200101519050611a0381600261237c90919063ffffffff16565b15611a525760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506001016119c8565b5060005b8151811015611182576000828281518110611a7c57611a7c613af1565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611ac05750611b1c565b611acb60028261239e565b15611b1a5760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101611a5f565b60008181526001830160205260408120541515610be3565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff908116911614611bd15760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016108fb565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ca39190613a32565b15611cda576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ce781604001516123c0565b611cf4816020015161243f565b61161e8160200151826060015161258d565b6008546060820151611d539173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116929116906125d1565b60085460408083015183516060850151602086015193517f9687544500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90951694639687544594611dbb94939291600401613e26565b6000604051808303816000875af1158015611dda573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261184e9190810190613e86565b60606000610be38361265e565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611ebb82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611e9f9190613f23565b85608001516fffffffffffffffffffffffffffffffff166126b9565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b611ee883610bea565b611f2a576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024016108fb565b611f35826000611fc9565b67ffffffffffffffff83166000908152600760205260409020611f5890836126e3565b611f63816000611fc9565b67ffffffffffffffff83166000908152600760205260409020611f8990600201826126e3565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051611fbc93929190613f36565b60405180910390a1505050565b8151156120905781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff1610158061201f575060408201516fffffffffffffffffffffffffffffffff16155b1561205857816040517f8020d1240000000000000000000000000000000000000000000000000000000081526004016108fb9190613fb9565b801561184e576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff161515806120c9575060208201516fffffffffffffffffffffffffffffffff1615155b1561184e57816040517fd68af9cc0000000000000000000000000000000000000000000000000000000081526004016108fb9190613fb9565b6000610be38383612885565b6000610be383836128d4565b3373ffffffffffffffffffffffffffffffffffffffff821603612199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108fb565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b61221881610bea565b61225a576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201526024016108fb565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa1580156122d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122fd9190613a32565b61161e576040517f728fe07b0000000000000000000000000000000000000000000000000000000081523360048201526024016108fb565b67ffffffffffffffff8216600090815260076020526040902061184e90600201827f00000000000000000000000000000000000000000000000000000000000000006129c7565b6000610be38373ffffffffffffffffffffffffffffffffffffffff84166128d4565b6000610be38373ffffffffffffffffffffffffffffffffffffffff8416612885565b7f00000000000000000000000000000000000000000000000000000000000000001561161e576123f1600282612d4a565b61161e576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016108fb565b61244881610bea565b61248a576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201526024016108fb565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015612503573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125279190613ff5565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461161e576040517f728fe07b0000000000000000000000000000000000000000000000000000000081523360048201526024016108fb565b67ffffffffffffffff8216600090815260076020526040902061184e90827f00000000000000000000000000000000000000000000000000000000000000006129c7565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611182908490612d79565b60608160000180548060200260200160405190810160405280929190818152602001828054801561067c57602002820191906000526020600020905b81548152602001906001019080831161269a5750505050509050919050565b60006126d8856126c98486614012565b6126d39087614029565b612e85565b90505b949350505050565b815460009061270c90700100000000000000000000000000000000900463ffffffff1642613f23565b905080156127ae5760018301548354612754916fffffffffffffffffffffffffffffffff808216928116918591700100000000000000000000000000000000909104166126b9565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b602082015183546127d4916fffffffffffffffffffffffffffffffff9081169116612e85565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990611fbc908490613fb9565b60008181526001830160205260408120546128cc575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105d2565b5060006105d2565b600081815260018301602052604081205480156129bd5760006128f8600183613f23565b855490915060009061290c90600190613f23565b905081811461297157600086600001828154811061292c5761292c613af1565b906000526020600020015490508087600001848154811061294f5761294f613af1565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806129825761298261403c565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105d2565b60009150506105d2565b825474010000000000000000000000000000000000000000900460ff1615806129ee575081155b156129f857505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090612a3e90700100000000000000000000000000000000900463ffffffff1642613f23565b90508015612afe5781831115612a80576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001860154612aba9083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166126b9565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b84821015612bb55773ffffffffffffffffffffffffffffffffffffffff8416612b5d576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016108fb565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff851660448201526064016108fb565b84831015612cc85760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16906000908290612bf99082613f23565b612c03878a613f23565b612c0d9190614029565b612c17919061406b565b905073ffffffffffffffffffffffffffffffffffffffff8616612c70576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016108fb565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff871660448201526064016108fb565b612cd28584613f23565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515610be3565b6000612ddb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612e9b9092919063ffffffff16565b8051909150156111825780806020019051810190612df99190613a32565b611182576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016108fb565b6000818310612e945781610be3565b5090919050565b60606126db8484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051612ecf91906140a6565b60006040518083038185875af1925050503d8060008114612f0c576040519150601f19603f3d011682016040523d82523d6000602084013e612f11565b606091505b5091509150612f2287838387612f2d565b979650505050505050565b60608315612fc3578251600003612fbc5773ffffffffffffffffffffffffffffffffffffffff85163b612fbc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108fb565b50816126db565b6126db8383815115612fd85781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108fb9190613142565b50805461301890613680565b6000825580601f10613028575050565b601f01602090049060005260206000209081019061161e91905b808211156130565760008155600101613042565b5090565b60006020828403121561306c57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610be357600080fd5b803567ffffffffffffffff811681146130b457600080fd5b919050565b6000602082840312156130cb57600080fd5b610be38261309c565b60005b838110156130ef5781810151838201526020016130d7565b50506000910152565b600081518084526131108160208601602086016130d4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610be360208301846130f8565b73ffffffffffffffffffffffffffffffffffffffff8116811461161e57600080fd5b80356130b481613155565b60006020828403121561319457600080fd5b8135610be381613155565b6000602082840312156131b157600080fd5b813567ffffffffffffffff8111156131c857600080fd5b82016101008185031215610be357600080fd5b60008083601f8401126131ed57600080fd5b50813567ffffffffffffffff81111561320557600080fd5b6020830191508360208260051b850101111561322057600080fd5b9250929050565b6000806000806040858703121561323d57600080fd5b843567ffffffffffffffff8082111561325557600080fd5b613261888389016131db565b9096509450602087013591508082111561327a57600080fd5b50613287878288016131db565b95989497509550505050565b6000806000604084860312156132a857600080fd5b6132b18461309c565b9250602084013567ffffffffffffffff808211156132ce57600080fd5b818601915086601f8301126132e257600080fd5b8135818111156132f157600080fd5b87602082850101111561330357600080fd5b6020830194508093505050509250925092565b6000806040838503121561332957600080fd5b6133328361309c565b9150602083013561334281613155565b809150509250929050565b60006020828403121561335f57600080fd5b813567ffffffffffffffff81111561337657600080fd5b820160a08185031215610be357600080fd5b6020815260008251604060208401526133a460608401826130f8565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160408501526133df82826130f8565b95945050505050565b6020808252825182820181905260009190848201906040850190845b8181101561343657835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101613404565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561343657835167ffffffffffffffff168352928401929184019160010161345e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff811182821017156134d7576134d7613484565b60405290565b60405160c0810167ffffffffffffffff811182821017156134d7576134d7613484565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561354757613547613484565b604052919050565b801515811461161e57600080fd5b80356130b48161354f565b80356fffffffffffffffffffffffffffffffff811681146130b457600080fd5b60006060828403121561359a57600080fd5b6040516060810181811067ffffffffffffffff821117156135bd576135bd613484565b60405290508082356135ce8161354f565b81526135dc60208401613568565b60208201526135ed60408401613568565b60408201525092915050565b600080600060e0848603121561360e57600080fd5b6136178461309c565b92506136268560208601613588565b91506136358560808601613588565b90509250925092565b6000806020838503121561365157600080fd5b823567ffffffffffffffff81111561366857600080fd5b613674858286016131db565b90969095509350505050565b600181811c9082168061369457607f821691505b6020821081036136cd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600067ffffffffffffffff8211156136ed576136ed613484565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f83011261372a57600080fd5b813561373d613738826136d3565b613500565b81815284602083860101111561375257600080fd5b816020850160208301376000918101602001919091529392505050565b6000610100823603121561378257600080fd5b61378a6134b3565b823567ffffffffffffffff808211156137a257600080fd5b6137ae36838701613719565b83526137bc6020860161309c565b60208401526137cd60408601613177565b6040840152606085013560608401526137e860808601613177565b608084015260a085013591508082111561380157600080fd5b61380d36838701613719565b60a084015260c085013591508082111561382657600080fd5b61383236838701613719565b60c084015260e085013591508082111561384b57600080fd5b5061385836828601613719565b60e08301525092915050565b601f821115611182576000816000526020600020601f850160051c8101602086101561388d5750805b601f850160051c820191505b818110156138ac57828155600101613899565b505050505050565b67ffffffffffffffff8311156138cc576138cc613484565b6138e0836138da8354613680565b83613864565b6000601f84116001811461393257600085156138fc5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556118e4565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156139815786850135825560209485019460019092019101613961565b50868210156139bc577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b6040815260006139e160408301866130f8565b82810360208401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116820101915050949350505050565b600060208284031215613a4457600080fd5b8151610be38161354f565b600060a08236031215613a6157600080fd5b60405160a0810167ffffffffffffffff8282108183111715613a8557613a85613484565b816040528435915080821115613a9a57600080fd5b50613aa736828601613719565b825250613ab66020840161309c565b60208201526040830135613ac981613155565b6040820152606083810135908201526080830135613ae681613155565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1833603018112613b5457600080fd5b9190910192915050565b60006101408236031215613b7157600080fd5b613b796134dd565b613b828361309c565b8152613b906020840161355d565b6020820152604083013567ffffffffffffffff80821115613bb057600080fd5b613bbc36838701613719565b60408401526060850135915080821115613bd557600080fd5b50613be236828601613719565b606083015250613bf53660808501613588565b6080820152613c073660e08501613588565b60a082015292915050565b815167ffffffffffffffff811115613c2c57613c2c613484565b613c4081613c3a8454613680565b84613864565b602080601f831160018114613c935760008415613c5d5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556138ac565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015613ce057888601518255948401946001909101908401613cc1565b5085821015613d1c57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff87168352806020840152613d50818401876130f8565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff9081166060870152908701511660808501529150613d8e9050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e08301526133df565b60a081526000613dd860a08301876130f8565b73ffffffffffffffffffffffffffffffffffffffff8616602084015284604084015267ffffffffffffffff841660608401528281036080840152600081526020810191505095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8516815260a060208201526000613e5560a08301866130f8565b60408301949094525067ffffffffffffffff9190911660608201528082036080909101526000815260200192915050565b600060208284031215613e9857600080fd5b815167ffffffffffffffff811115613eaf57600080fd5b8201601f81018413613ec057600080fd5b8051613ece613738826136d3565b818152856020838501011115613ee357600080fd5b6133df8260208301602086016130d4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105d2576105d2613ef4565b67ffffffffffffffff8416815260e08101613f8260208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c08301526126db565b606081016105d282848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b60006020828403121561400757600080fd5b8151610be381613155565b80820281158282048414176105d2576105d2613ef4565b808201808211156105d2576105d2613ef4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000826140a1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008251613b548184602087016130d456fe4275726e4d696e74546f6b656e506f6f6c416e6450726f787920312e352e302d646576a164736f6c6343000818000a",
+}
+
+var BurnMintTokenPoolAndProxyABI = BurnMintTokenPoolAndProxyMetaData.ABI
+
+var BurnMintTokenPoolAndProxyBin = BurnMintTokenPoolAndProxyMetaData.Bin
+
+func DeployBurnMintTokenPoolAndProxy(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, rmnProxy common.Address, router common.Address) (common.Address, *types.Transaction, *BurnMintTokenPoolAndProxy, error) {
+ parsed, err := BurnMintTokenPoolAndProxyMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BurnMintTokenPoolAndProxyBin), backend, token, allowlist, rmnProxy, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &BurnMintTokenPoolAndProxy{address: address, abi: *parsed, BurnMintTokenPoolAndProxyCaller: BurnMintTokenPoolAndProxyCaller{contract: contract}, BurnMintTokenPoolAndProxyTransactor: BurnMintTokenPoolAndProxyTransactor{contract: contract}, BurnMintTokenPoolAndProxyFilterer: BurnMintTokenPoolAndProxyFilterer{contract: contract}}, nil
+}
+
+type BurnMintTokenPoolAndProxy struct {
+ address common.Address
+ abi abi.ABI
+ BurnMintTokenPoolAndProxyCaller
+ BurnMintTokenPoolAndProxyTransactor
+ BurnMintTokenPoolAndProxyFilterer
+}
+
+type BurnMintTokenPoolAndProxyCaller struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolAndProxyTransactor struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolAndProxyFilterer struct {
+ contract *bind.BoundContract
+}
+
+type BurnMintTokenPoolAndProxySession struct {
+ Contract *BurnMintTokenPoolAndProxy
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type BurnMintTokenPoolAndProxyCallerSession struct {
+ Contract *BurnMintTokenPoolAndProxyCaller
+ CallOpts bind.CallOpts
+}
+
+type BurnMintTokenPoolAndProxyTransactorSession struct {
+ Contract *BurnMintTokenPoolAndProxyTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type BurnMintTokenPoolAndProxyRaw struct {
+ Contract *BurnMintTokenPoolAndProxy
+}
+
+type BurnMintTokenPoolAndProxyCallerRaw struct {
+ Contract *BurnMintTokenPoolAndProxyCaller
+}
+
+type BurnMintTokenPoolAndProxyTransactorRaw struct {
+ Contract *BurnMintTokenPoolAndProxyTransactor
+}
+
+func NewBurnMintTokenPoolAndProxy(address common.Address, backend bind.ContractBackend) (*BurnMintTokenPoolAndProxy, error) {
+ abi, err := abi.JSON(strings.NewReader(BurnMintTokenPoolAndProxyABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindBurnMintTokenPoolAndProxy(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxy{address: address, abi: abi, BurnMintTokenPoolAndProxyCaller: BurnMintTokenPoolAndProxyCaller{contract: contract}, BurnMintTokenPoolAndProxyTransactor: BurnMintTokenPoolAndProxyTransactor{contract: contract}, BurnMintTokenPoolAndProxyFilterer: BurnMintTokenPoolAndProxyFilterer{contract: contract}}, nil
+}
+
+func NewBurnMintTokenPoolAndProxyCaller(address common.Address, caller bind.ContractCaller) (*BurnMintTokenPoolAndProxyCaller, error) {
+ contract, err := bindBurnMintTokenPoolAndProxy(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyCaller{contract: contract}, nil
+}
+
+func NewBurnMintTokenPoolAndProxyTransactor(address common.Address, transactor bind.ContractTransactor) (*BurnMintTokenPoolAndProxyTransactor, error) {
+ contract, err := bindBurnMintTokenPoolAndProxy(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyTransactor{contract: contract}, nil
+}
+
+func NewBurnMintTokenPoolAndProxyFilterer(address common.Address, filterer bind.ContractFilterer) (*BurnMintTokenPoolAndProxyFilterer, error) {
+ contract, err := bindBurnMintTokenPoolAndProxy(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyFilterer{contract: contract}, nil
+}
+
+func bindBurnMintTokenPoolAndProxy(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := BurnMintTokenPoolAndProxyMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnMintTokenPoolAndProxy.Contract.BurnMintTokenPoolAndProxyCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.BurnMintTokenPoolAndProxyTransactor.contract.Transfer(opts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.BurnMintTokenPoolAndProxyTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnMintTokenPoolAndProxy.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.contract.Transfer(opts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetAllowList() ([]common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetAllowList(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetAllowList() ([]common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetAllowList(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetAllowListEnabled() (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetAllowListEnabled(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetAllowListEnabled() (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetAllowListEnabled(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetCurrentInboundRateLimiterState(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetCurrentInboundRateLimiterState(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetCurrentOutboundRateLimiterState(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetCurrentOutboundRateLimiterState(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetOnRamp(opts *bind.CallOpts, arg0 uint64) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getOnRamp", arg0)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetOnRamp(arg0 uint64) (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetOnRamp(&_BurnMintTokenPoolAndProxy.CallOpts, arg0)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetOnRamp(arg0 uint64) (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetOnRamp(&_BurnMintTokenPoolAndProxy.CallOpts, arg0)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getRemotePool", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetRemotePool(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetRemotePool(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetRemoteToken(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetRemoteToken(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getRmnProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetRmnProxy() (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetRmnProxy(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetRmnProxy() (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetRmnProxy(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetRouter() (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetRouter(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetRouter() (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetRouter(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetSupportedChains() ([]uint64, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetSupportedChains(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetSupportedChains(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) GetToken() (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetToken(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) GetToken() (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.GetToken(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) IsOffRamp(opts *bind.CallOpts, sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "isOffRamp", sourceChainSelector, offRamp)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) IsOffRamp(sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.IsOffRamp(&_BurnMintTokenPoolAndProxy.CallOpts, sourceChainSelector, offRamp)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) IsOffRamp(sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.IsOffRamp(&_BurnMintTokenPoolAndProxy.CallOpts, sourceChainSelector, offRamp)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.IsSupportedChain(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.IsSupportedChain(&_BurnMintTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "isSupportedToken", token)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) IsSupportedToken(token common.Address) (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.IsSupportedToken(&_BurnMintTokenPoolAndProxy.CallOpts, token)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.IsSupportedToken(&_BurnMintTokenPoolAndProxy.CallOpts, token)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) Owner() (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.Owner(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) Owner() (common.Address, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.Owner(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SupportsInterface(&_BurnMintTokenPoolAndProxy.CallOpts, interfaceId)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SupportsInterface(&_BurnMintTokenPoolAndProxy.CallOpts, interfaceId)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _BurnMintTokenPoolAndProxy.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) TypeAndVersion() (string, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.TypeAndVersion(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyCallerSession) TypeAndVersion() (string, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.TypeAndVersion(&_BurnMintTokenPoolAndProxy.CallOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.AcceptOwnership(&_BurnMintTokenPoolAndProxy.TransactOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.AcceptOwnership(&_BurnMintTokenPoolAndProxy.TransactOpts)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.ApplyAllowListUpdates(&_BurnMintTokenPoolAndProxy.TransactOpts, removes, adds)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.ApplyAllowListUpdates(&_BurnMintTokenPoolAndProxy.TransactOpts, removes, adds)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.ApplyChainUpdates(&_BurnMintTokenPoolAndProxy.TransactOpts, chains)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.ApplyChainUpdates(&_BurnMintTokenPoolAndProxy.TransactOpts, chains)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "lockOrBurn", lockOrBurnIn)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.LockOrBurn(&_BurnMintTokenPoolAndProxy.TransactOpts, lockOrBurnIn)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.LockOrBurn(&_BurnMintTokenPoolAndProxy.TransactOpts, lockOrBurnIn)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "releaseOrMint", releaseOrMintIn)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.ReleaseOrMint(&_BurnMintTokenPoolAndProxy.TransactOpts, releaseOrMintIn)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.ReleaseOrMint(&_BurnMintTokenPoolAndProxy.TransactOpts, releaseOrMintIn)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SetChainRateLimiterConfig(&_BurnMintTokenPoolAndProxy.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SetChainRateLimiterConfig(&_BurnMintTokenPoolAndProxy.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) SetPreviousPool(opts *bind.TransactOpts, prevPool common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "setPreviousPool", prevPool)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) SetPreviousPool(prevPool common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SetPreviousPool(&_BurnMintTokenPoolAndProxy.TransactOpts, prevPool)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) SetPreviousPool(prevPool common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SetPreviousPool(&_BurnMintTokenPoolAndProxy.TransactOpts, prevPool)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "setRemotePool", remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SetRemotePool(&_BurnMintTokenPoolAndProxy.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SetRemotePool(&_BurnMintTokenPoolAndProxy.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SetRouter(&_BurnMintTokenPoolAndProxy.TransactOpts, newRouter)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.SetRouter(&_BurnMintTokenPoolAndProxy.TransactOpts, newRouter)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxySession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.TransferOwnership(&_BurnMintTokenPoolAndProxy.TransactOpts, to)
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnMintTokenPoolAndProxy.Contract.TransferOwnership(&_BurnMintTokenPoolAndProxy.TransactOpts, to)
+}
+
+type BurnMintTokenPoolAndProxyAllowListAddIterator struct {
+ Event *BurnMintTokenPoolAndProxyAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyAllowListAdd)
+ 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(BurnMintTokenPoolAndProxyAllowListAdd)
+ 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 *BurnMintTokenPoolAndProxyAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyAllowListAddIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyAllowListAddIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyAllowListAdd)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "AllowListAdd", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseAllowListAdd(log types.Log) (*BurnMintTokenPoolAndProxyAllowListAdd, error) {
+ event := new(BurnMintTokenPoolAndProxyAllowListAdd)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyAllowListRemoveIterator struct {
+ Event *BurnMintTokenPoolAndProxyAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyAllowListRemove)
+ 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(BurnMintTokenPoolAndProxyAllowListRemove)
+ 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 *BurnMintTokenPoolAndProxyAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyAllowListRemoveIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyAllowListRemoveIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyAllowListRemove)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "AllowListRemove", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseAllowListRemove(log types.Log) (*BurnMintTokenPoolAndProxyAllowListRemove, error) {
+ event := new(BurnMintTokenPoolAndProxyAllowListRemove)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyBurnedIterator struct {
+ Event *BurnMintTokenPoolAndProxyBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyBurned)
+ 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(BurnMintTokenPoolAndProxyBurned)
+ 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 *BurnMintTokenPoolAndProxyBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolAndProxyBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyBurnedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyBurned)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "Burned", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseBurned(log types.Log) (*BurnMintTokenPoolAndProxyBurned, error) {
+ event := new(BurnMintTokenPoolAndProxyBurned)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyChainAddedIterator struct {
+ Event *BurnMintTokenPoolAndProxyChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyChainAdded)
+ 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(BurnMintTokenPoolAndProxyChainAdded)
+ 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 *BurnMintTokenPoolAndProxyChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyChainAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterChainAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyChainAddedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyChainAddedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyChainAdded)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "ChainAdded", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseChainAdded(log types.Log) (*BurnMintTokenPoolAndProxyChainAdded, error) {
+ event := new(BurnMintTokenPoolAndProxyChainAdded)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyChainConfiguredIterator struct {
+ Event *BurnMintTokenPoolAndProxyChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyChainConfigured)
+ 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(BurnMintTokenPoolAndProxyChainConfigured)
+ 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 *BurnMintTokenPoolAndProxyChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyChainConfiguredIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyChainConfiguredIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyChainConfigured)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "ChainConfigured", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseChainConfigured(log types.Log) (*BurnMintTokenPoolAndProxyChainConfigured, error) {
+ event := new(BurnMintTokenPoolAndProxyChainConfigured)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyChainRemovedIterator struct {
+ Event *BurnMintTokenPoolAndProxyChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyChainRemoved)
+ 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(BurnMintTokenPoolAndProxyChainRemoved)
+ 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 *BurnMintTokenPoolAndProxyChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyChainRemovedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyChainRemovedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyChainRemoved)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "ChainRemoved", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseChainRemoved(log types.Log) (*BurnMintTokenPoolAndProxyChainRemoved, error) {
+ event := new(BurnMintTokenPoolAndProxyChainRemoved)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyConfigChangedIterator struct {
+ Event *BurnMintTokenPoolAndProxyConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyConfigChanged)
+ 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(BurnMintTokenPoolAndProxyConfigChanged)
+ 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 *BurnMintTokenPoolAndProxyConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyConfigChangedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyConfigChangedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyConfigChanged)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "ConfigChanged", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseConfigChanged(log types.Log) (*BurnMintTokenPoolAndProxyConfigChanged, error) {
+ event := new(BurnMintTokenPoolAndProxyConfigChanged)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyLegacyPoolChangedIterator struct {
+ Event *BurnMintTokenPoolAndProxyLegacyPoolChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyLegacyPoolChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyLegacyPoolChanged)
+ 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(BurnMintTokenPoolAndProxyLegacyPoolChanged)
+ 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 *BurnMintTokenPoolAndProxyLegacyPoolChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyLegacyPoolChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyLegacyPoolChanged struct {
+ OldPool common.Address
+ NewPool common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterLegacyPoolChanged(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyLegacyPoolChangedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "LegacyPoolChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyLegacyPoolChangedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "LegacyPoolChanged", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchLegacyPoolChanged(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyLegacyPoolChanged) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "LegacyPoolChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyLegacyPoolChanged)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "LegacyPoolChanged", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseLegacyPoolChanged(log types.Log) (*BurnMintTokenPoolAndProxyLegacyPoolChanged, error) {
+ event := new(BurnMintTokenPoolAndProxyLegacyPoolChanged)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "LegacyPoolChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyLockedIterator struct {
+ Event *BurnMintTokenPoolAndProxyLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyLocked)
+ 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(BurnMintTokenPoolAndProxyLocked)
+ 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 *BurnMintTokenPoolAndProxyLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolAndProxyLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyLockedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyLocked)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "Locked", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseLocked(log types.Log) (*BurnMintTokenPoolAndProxyLocked, error) {
+ event := new(BurnMintTokenPoolAndProxyLocked)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyMintedIterator struct {
+ Event *BurnMintTokenPoolAndProxyMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyMinted)
+ 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(BurnMintTokenPoolAndProxyMinted)
+ 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 *BurnMintTokenPoolAndProxyMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolAndProxyMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyMintedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyMinted)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "Minted", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseMinted(log types.Log) (*BurnMintTokenPoolAndProxyMinted, error) {
+ event := new(BurnMintTokenPoolAndProxyMinted)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyOwnershipTransferRequestedIterator struct {
+ Event *BurnMintTokenPoolAndProxyOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyOwnershipTransferRequested)
+ 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(BurnMintTokenPoolAndProxyOwnershipTransferRequested)
+ 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 *BurnMintTokenPoolAndProxyOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolAndProxyOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyOwnershipTransferRequestedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyOwnershipTransferRequested)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseOwnershipTransferRequested(log types.Log) (*BurnMintTokenPoolAndProxyOwnershipTransferRequested, error) {
+ event := new(BurnMintTokenPoolAndProxyOwnershipTransferRequested)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyOwnershipTransferredIterator struct {
+ Event *BurnMintTokenPoolAndProxyOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyOwnershipTransferred)
+ 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(BurnMintTokenPoolAndProxyOwnershipTransferred)
+ 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 *BurnMintTokenPoolAndProxyOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolAndProxyOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyOwnershipTransferredIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyOwnershipTransferred)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "OwnershipTransferred", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseOwnershipTransferred(log types.Log) (*BurnMintTokenPoolAndProxyOwnershipTransferred, error) {
+ event := new(BurnMintTokenPoolAndProxyOwnershipTransferred)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyReleasedIterator struct {
+ Event *BurnMintTokenPoolAndProxyReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyReleased)
+ 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(BurnMintTokenPoolAndProxyReleased)
+ 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 *BurnMintTokenPoolAndProxyReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolAndProxyReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyReleasedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyReleased)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "Released", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseReleased(log types.Log) (*BurnMintTokenPoolAndProxyReleased, error) {
+ event := new(BurnMintTokenPoolAndProxyReleased)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyRemotePoolSetIterator struct {
+ Event *BurnMintTokenPoolAndProxyRemotePoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyRemotePoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyRemotePoolSet)
+ 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(BurnMintTokenPoolAndProxyRemotePoolSet)
+ 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 *BurnMintTokenPoolAndProxyRemotePoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyRemotePoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyRemotePoolSet struct {
+ RemoteChainSelector uint64
+ PreviousPoolAddress []byte
+ RemotePoolAddress []byte
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnMintTokenPoolAndProxyRemotePoolSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyRemotePoolSetIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "RemotePoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyRemotePoolSet)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "RemotePoolSet", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseRemotePoolSet(log types.Log) (*BurnMintTokenPoolAndProxyRemotePoolSet, error) {
+ event := new(BurnMintTokenPoolAndProxyRemotePoolSet)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "RemotePoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyRouterUpdatedIterator struct {
+ Event *BurnMintTokenPoolAndProxyRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyRouterUpdated)
+ 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(BurnMintTokenPoolAndProxyRouterUpdated)
+ 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 *BurnMintTokenPoolAndProxyRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyRouterUpdatedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyRouterUpdatedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyRouterUpdated)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "RouterUpdated", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseRouterUpdated(log types.Log) (*BurnMintTokenPoolAndProxyRouterUpdated, error) {
+ event := new(BurnMintTokenPoolAndProxyRouterUpdated)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnMintTokenPoolAndProxyTokensConsumedIterator struct {
+ Event *BurnMintTokenPoolAndProxyTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnMintTokenPoolAndProxyTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnMintTokenPoolAndProxyTokensConsumed)
+ 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(BurnMintTokenPoolAndProxyTokensConsumed)
+ 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 *BurnMintTokenPoolAndProxyTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnMintTokenPoolAndProxyTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnMintTokenPoolAndProxyTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyTokensConsumedIterator, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnMintTokenPoolAndProxyTokensConsumedIterator{contract: _BurnMintTokenPoolAndProxy.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _BurnMintTokenPoolAndProxy.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnMintTokenPoolAndProxyTokensConsumed)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "TokensConsumed", 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 (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxyFilterer) ParseTokensConsumed(log types.Log) (*BurnMintTokenPoolAndProxyTokensConsumed, error) {
+ event := new(BurnMintTokenPoolAndProxyTokensConsumed)
+ if err := _BurnMintTokenPoolAndProxy.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxy) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _BurnMintTokenPoolAndProxy.abi.Events["AllowListAdd"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseAllowListAdd(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["AllowListRemove"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseAllowListRemove(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["Burned"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseBurned(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["ChainAdded"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseChainAdded(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["ChainConfigured"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseChainConfigured(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["ChainRemoved"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseChainRemoved(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["ConfigChanged"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseConfigChanged(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["LegacyPoolChanged"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseLegacyPoolChanged(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["Locked"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseLocked(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["Minted"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseMinted(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["OwnershipTransferRequested"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseOwnershipTransferRequested(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["OwnershipTransferred"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseOwnershipTransferred(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["Released"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseReleased(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["RemotePoolSet"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseRemotePoolSet(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["RouterUpdated"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseRouterUpdated(log)
+ case _BurnMintTokenPoolAndProxy.abi.Events["TokensConsumed"].ID:
+ return _BurnMintTokenPoolAndProxy.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (BurnMintTokenPoolAndProxyAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (BurnMintTokenPoolAndProxyAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (BurnMintTokenPoolAndProxyBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (BurnMintTokenPoolAndProxyChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2")
+}
+
+func (BurnMintTokenPoolAndProxyChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (BurnMintTokenPoolAndProxyChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (BurnMintTokenPoolAndProxyConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (BurnMintTokenPoolAndProxyLegacyPoolChanged) Topic() common.Hash {
+ return common.HexToHash("0x81accd0a7023865eaa51b3399dd0eafc488bf3ba238402911e1659cfe860f228")
+}
+
+func (BurnMintTokenPoolAndProxyLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (BurnMintTokenPoolAndProxyMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (BurnMintTokenPoolAndProxyOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (BurnMintTokenPoolAndProxyOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (BurnMintTokenPoolAndProxyReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (BurnMintTokenPoolAndProxyRemotePoolSet) Topic() common.Hash {
+ return common.HexToHash("0xdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf")
+}
+
+func (BurnMintTokenPoolAndProxyRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (BurnMintTokenPoolAndProxyTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_BurnMintTokenPoolAndProxy *BurnMintTokenPoolAndProxy) Address() common.Address {
+ return _BurnMintTokenPoolAndProxy.address
+}
+
+type BurnMintTokenPoolAndProxyInterface interface {
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetOnRamp(opts *bind.CallOpts, arg0 uint64) (common.Address, error)
+
+ GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRmnProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsOffRamp(opts *bind.CallOpts, sourceChainSelector uint64, offRamp common.Address) (bool, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetPreviousPool(opts *bind.TransactOpts, prevPool common.Address) (*types.Transaction, error)
+
+ SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*BurnMintTokenPoolAndProxyAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*BurnMintTokenPoolAndProxyAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolAndProxyBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*BurnMintTokenPoolAndProxyBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*BurnMintTokenPoolAndProxyChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*BurnMintTokenPoolAndProxyChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*BurnMintTokenPoolAndProxyChainRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*BurnMintTokenPoolAndProxyConfigChanged, error)
+
+ FilterLegacyPoolChanged(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyLegacyPoolChangedIterator, error)
+
+ WatchLegacyPoolChanged(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyLegacyPoolChanged) (event.Subscription, error)
+
+ ParseLegacyPoolChanged(log types.Log) (*BurnMintTokenPoolAndProxyLegacyPoolChanged, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnMintTokenPoolAndProxyLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*BurnMintTokenPoolAndProxyLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolAndProxyMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*BurnMintTokenPoolAndProxyMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolAndProxyOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*BurnMintTokenPoolAndProxyOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnMintTokenPoolAndProxyOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*BurnMintTokenPoolAndProxyOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnMintTokenPoolAndProxyReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*BurnMintTokenPoolAndProxyReleased, error)
+
+ FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnMintTokenPoolAndProxyRemotePoolSetIterator, error)
+
+ WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRemotePoolSet(log types.Log) (*BurnMintTokenPoolAndProxyRemotePoolSet, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*BurnMintTokenPoolAndProxyRouterUpdated, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*BurnMintTokenPoolAndProxyTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnMintTokenPoolAndProxyTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*BurnMintTokenPoolAndProxyTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool/burn_with_from_mint_token_pool.go b/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool/burn_with_from_mint_token_pool.go
new file mode 100644
index 00000000000..07489bbb01a
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool/burn_with_from_mint_token_pool.go
@@ -0,0 +1,2780 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package burn_with_from_mint_token_pool
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type PoolLockOrBurnInV1 struct {
+ Receiver []byte
+ RemoteChainSelector uint64
+ OriginalSender common.Address
+ Amount *big.Int
+ LocalToken common.Address
+}
+
+type PoolLockOrBurnOutV1 struct {
+ DestTokenAddress []byte
+ DestPoolData []byte
+}
+
+type PoolReleaseOrMintInV1 struct {
+ OriginalSender []byte
+ RemoteChainSelector uint64
+ Receiver common.Address
+ Amount *big.Int
+ LocalToken common.Address
+ SourcePoolAddress []byte
+ SourcePoolData []byte
+ OffchainTokenData []byte
+}
+
+type PoolReleaseOrMintOutV1 struct {
+ DestinationAmount *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ RemotePoolAddress []byte
+ RemoteTokenAddress []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var BurnWithFromMintTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIBurnMintERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRateLimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidSourcePoolAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remoteToken\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousPoolAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"RemotePoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"remoteTokenAddress\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemotePool\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemoteToken\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRmnProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"isSupportedToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structPool.LockOrBurnInV1\",\"name\":\"lockOrBurnIn\",\"type\":\"tuple\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destPoolData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.LockOrBurnOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainTokenData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.ReleaseOrMintInV1\",\"name\":\"releaseOrMintIn\",\"type\":\"tuple\"}],\"name\":\"releaseOrMint\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destinationAmount\",\"type\":\"uint256\"}],\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"setRemotePool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x60e06040523480156200001157600080fd5b50604051620043e4380380620043e48339810160408190526200003491620008c0565b8383838333806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c2816200018f565b5050506001600160a01b0384161580620000e357506001600160a01b038116155b80620000f657506001600160a01b038216155b1562000115576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c05262000168576040805160008152602081019091526200016890846200023a565b5062000185925050506001600160a01b0385163060001962000397565b5050505062000afc565b336001600160a01b03821603620001e95760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c0516200025b576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002e65760008382815181106200027f576200027f620009d0565b60209081029190910101519050620002996002826200047d565b15620002dc576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506001016200025e565b5060005b8151811015620003925760008282815181106200030b576200030b620009d0565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000337575062000389565b620003446002826200049d565b1562000387576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101620002ea565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015620003e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200040f9190620009e6565b6200041b919062000a16565b604080516001600160a01b038616602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091529192506200047791869190620004b416565b50505050565b600062000494836001600160a01b03841662000585565b90505b92915050565b600062000494836001600160a01b03841662000689565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65649082015260009062000503906001600160a01b038516908490620006db565b80519091501562000392578080602001905181019062000524919062000a2c565b620003925760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000086565b600081815260018301602052604081205480156200067e576000620005ac60018362000a57565b8554909150600090620005c29060019062000a57565b90508181146200062e576000866000018281548110620005e657620005e6620009d0565b90600052602060002001549050808760000184815481106200060c576200060c620009d0565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000642576200064262000a6d565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000497565b600091505062000497565b6000818152600183016020526040812054620006d25750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000497565b50600062000497565b6060620006ec8484600085620006f4565b949350505050565b606082471015620007575760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000086565b600080866001600160a01b0316858760405162000775919062000aa9565b60006040518083038185875af1925050503d8060008114620007b4576040519150601f19603f3d011682016040523d82523d6000602084013e620007b9565b606091505b509092509050620007cd87838387620007d8565b979650505050505050565b606083156200084c57825160000362000844576001600160a01b0385163b620008445760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000086565b5081620006ec565b620006ec8383815115620008635781518083602001fd5b8060405162461bcd60e51b815260040162000086919062000ac7565b6001600160a01b03811681146200089557600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b8051620008bb816200087f565b919050565b60008060008060808587031215620008d757600080fd5b8451620008e4816200087f565b602086810151919550906001600160401b03808211156200090457600080fd5b818801915088601f8301126200091957600080fd5b8151818111156200092e576200092e62000898565b8060051b604051601f19603f8301168101818110858211171562000956576200095662000898565b60405291825284820192508381018501918b8311156200097557600080fd5b938501935b828510156200099e576200098e85620008ae565b845293850193928501926200097a565b809850505050505050620009b560408601620008ae565b9150620009c560608601620008ae565b905092959194509250565b634e487b7160e01b600052603260045260246000fd5b600060208284031215620009f957600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111562000497576200049762000a00565b60006020828403121562000a3f57600080fd5b8151801515811462000a5057600080fd5b9392505050565b8181038181111562000497576200049762000a00565b634e487b7160e01b600052603160045260246000fd5b60005b8381101562000aa057818101518382015260200162000a86565b50506000910152565b6000825162000abd81846020870162000a83565b9190910192915050565b602081526000825180602084015262000ae881604085016020870162000a83565b601f01601f19169190910160400192915050565b60805160a05160c05161386b62000b79600039600081816104620152818161162d015261201101526000818161043c0152818161145e01526118e30152600081816101ef01528181610244015281816106a20152818161137e01528181611803015281816119fb01528181611fa701526121fc015261386b6000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c8063a7cd63b7116100e3578063c75eea9c1161008c578063dc0bd97111610066578063dc0bd9711461043a578063e0351e1314610460578063f2fde38b1461048657600080fd5b8063c75eea9c14610401578063cf7401f314610414578063db6327dc1461042757600080fd5b8063b7946580116100bd578063b7946580146103c6578063c0d78655146103d9578063c4bffe2b146103ec57600080fd5b8063a7cd63b714610324578063af58d59f14610339578063b0f479a1146103a857600080fd5b806354c8a4f3116101455780638926f54f1161011f5780638926f54f146102d35780638da5cb5b146102e65780639a4575b91461030457600080fd5b806354c8a4f3146102a357806378a010b2146102b857806379ba5097146102cb57600080fd5b806321df0da71161017657806321df0da7146101ed578063240028e814610234578063390775371461028157600080fd5b806301ffc9a71461019d5780630a2fd493146101c5578063181f5a77146101e5575b600080fd5b6101b06101ab36600461299f565b610499565b60405190151581526020015b60405180910390f35b6101d86101d33660046129fe565b61057e565b6040516101bc9190612a7d565b6101d861062e565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b6101b0610242366004612abd565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b61029461028f366004612ada565b61064a565b604051905181526020016101bc565b6102b66102b1366004612b62565b6107a5565b005b6102b66102c6366004612bce565b610820565b6102b6610994565b6101b06102e13660046129fe565b610a91565b60005473ffffffffffffffffffffffffffffffffffffffff1661020f565b610317610312366004612c51565b610aa8565b6040516101bc9190612c8c565b61032c610b4f565b6040516101bc9190612cec565b61034c6103473660046129fe565b610b60565b6040516101bc919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff1661020f565b6101d86103d43660046129fe565b610c35565b6102b66103e7366004612abd565b610c60565b6103f4610d3b565b6040516101bc9190612d46565b61034c61040f3660046129fe565b610df3565b6102b6610422366004612eae565b610ec5565b6102b6610435366004612ef3565b610edd565b7f000000000000000000000000000000000000000000000000000000000000000061020f565b7f00000000000000000000000000000000000000000000000000000000000000006101b0565b6102b6610494366004612abd565b611363565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf00000000000000000000000000000000000000000000000000000000148061052c57507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b8061057857507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b67ffffffffffffffff811660009081526007602052604090206004018054606091906105a990612f35565b80601f01602080910402602001604051908101604052809291908181526020018280546105d590612f35565b80156106225780601f106105f757610100808354040283529160200191610622565b820191906000526020600020905b81548152906001019060200180831161060557829003601f168201915b50505050509050919050565b60405180606001604052806023815260200161383c6023913981565b60408051602081019091526000815261066a61066583613033565b611377565b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152336004820152606083013560248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906340c10f1990604401600060405180830381600087803b1580156106fb57600080fd5b505af115801561070f573d6000803e3d6000fd5b50610724925050506060830160408401612abd565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0846060013560405161078691815260200190565b60405180910390a3506040805160208101909152606090910135815290565b6107ad6115a8565b61081a8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061162b92505050565b50505050565b6108286115a8565b61083183610a91565b610878576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b67ffffffffffffffff83166000908152600760205260408120600401805461089f90612f35565b80601f01602080910402602001604051908101604052809291908181526020018280546108cb90612f35565b80156109185780601f106108ed57610100808354040283529160200191610918565b820191906000526020600020905b8154815290600101906020018083116108fb57829003601f168201915b5050505067ffffffffffffffff8616600090815260076020526040902091925050600401610947838583613178565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf82858560405161098693929190613292565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161086f565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000610578600567ffffffffffffffff84166117e1565b6040805180820190915260608082526020820152610acd610ac8836132f6565b6117fc565b610ada82606001356119c6565b6040516060830135815233907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a26040518060400160405280610b348460200160208101906103d491906129fe565b81526040805160208181019092526000815291015292915050565b6060610b5b6002611a6f565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600390910154808416606083015291909104909116608082015261057890611a7c565b67ffffffffffffffff811660009081526007602052604090206005018054606091906105a990612f35565b610c686115a8565b73ffffffffffffffffffffffffffffffffffffffff8116610cb5576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684910160405180910390a15050565b60606000610d496005611a6f565b90506000815167ffffffffffffffff811115610d6757610d67612d88565b604051908082528060200260200182016040528015610d90578160200160208202803683370190505b50905060005b8251811015610dec57828181518110610db157610db1613398565b6020026020010151828281518110610dcb57610dcb613398565b67ffffffffffffffff90921660209283029190910190910152600101610d96565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600190910154808416606083015291909104909116608082015261057890611a7c565b610ecd6115a8565b610ed8838383611b2e565b505050565b610ee56115a8565b60005b81811015610ed8576000838383818110610f0457610f04613398565b9050602002810190610f1691906133c7565b610f1f90613405565b9050610f348160800151826020015115611c18565b610f478160a00151826020015115611c18565b806020015115611243578051610f699060059067ffffffffffffffff16611d51565b610fae5780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff909116600482015260240161086f565b6040810151511580610fc35750606081015151155b15610ffa576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c179091169615150295909517909855908101519401519381169316909102919091176003820155915190919060048201906111db90826134b9565b50606082015160058201906111f090826134b9565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2955061123694939291906135d3565b60405180910390a161135a565b805161125b9060059067ffffffffffffffff16611d5d565b6112a05780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff909116600482015260240161086f565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906113096004830182612951565b611317600583016000612951565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b50600101610ee8565b61136b6115a8565b61137481611d69565b50565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161461140c5760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015260240161086f565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa1580156114ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114de919061366c565b15611515576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115228160200151611e5e565b6000611531826020015161057e565b9050805160001480611555575080805190602001208260a001518051906020012014155b15611592578160a001516040517f24eb47e500000000000000000000000000000000000000000000000000000000815260040161086f9190612a7d565b6115a482602001518360600151611f84565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611629576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161086f565b565b7f0000000000000000000000000000000000000000000000000000000000000000611682576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82518110156117185760008382815181106116a2576116a2613398565b602002602001015190506116c0816002611fcb90919063ffffffff16565b1561170f5760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50600101611685565b5060005b8151811015610ed857600082828151811061173957611739613398565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361177d57506117d9565b611788600282611fed565b156117d75760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b60010161171c565b600081815260018301602052604081205415155b9392505050565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146118915760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116600482015260240161086f565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa15801561193f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611963919061366c565b1561199a576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119a7816040015161200f565b6119b4816020015161208e565b611374816020015182606001516121dc565b6040517f9dc29fac000000000000000000000000000000000000000000000000000000008152306004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639dc29fac90604401600060405180830381600087803b158015611a5457600080fd5b505af1158015611a68573d6000803e3d6000fd5b5050505050565b606060006117f583612220565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611b0a82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611aee91906136b8565b85608001516fffffffffffffffffffffffffffffffff1661227b565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b611b3783610a91565b611b79576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8416600482015260240161086f565b611b84826000611c18565b67ffffffffffffffff83166000908152600760205260409020611ba790836122a5565b611bb2816000611c18565b67ffffffffffffffff83166000908152600760205260409020611bd890600201826122a5565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b838383604051611c0b939291906136cb565b60405180910390a1505050565b815115611cdf5781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580611c6e575060408201516fffffffffffffffffffffffffffffffff16155b15611ca757816040517f8020d12400000000000000000000000000000000000000000000000000000000815260040161086f919061374e565b80156115a4576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff16151580611d18575060208201516fffffffffffffffffffffffffffffffff1615155b156115a457816040517fd68af9cc00000000000000000000000000000000000000000000000000000000815260040161086f919061374e565b60006117f58383612447565b60006117f58383612496565b3373ffffffffffffffffffffffffffffffffffffffff821603611de8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161086f565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b611e6781610a91565b611ea9576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8216600482015260240161086f565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015611f28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4c919061366c565b611374576040517f728fe07b00000000000000000000000000000000000000000000000000000000815233600482015260240161086f565b67ffffffffffffffff821660009081526007602052604090206115a490600201827f0000000000000000000000000000000000000000000000000000000000000000612589565b60006117f58373ffffffffffffffffffffffffffffffffffffffff8416612496565b60006117f58373ffffffffffffffffffffffffffffffffffffffff8416612447565b7f0000000000000000000000000000000000000000000000000000000000000000156113745761204060028261290c565b611374576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161086f565b61209781610a91565b6120d9576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8216600482015260240161086f565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015612152573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612176919061378a565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611374576040517f728fe07b00000000000000000000000000000000000000000000000000000000815233600482015260240161086f565b67ffffffffffffffff821660009081526007602052604090206115a490827f0000000000000000000000000000000000000000000000000000000000000000612589565b60608160000180548060200260200160405190810160405280929190818152602001828054801561062257602002820191906000526020600020905b81548152602001906001019080831161225c5750505050509050919050565b600061229a8561228b84866137a7565b61229590876137be565b61293b565b90505b949350505050565b81546000906122ce90700100000000000000000000000000000000900463ffffffff16426136b8565b905080156123705760018301548354612316916fffffffffffffffffffffffffffffffff8082169281169185917001000000000000000000000000000000009091041661227b565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612396916fffffffffffffffffffffffffffffffff908116911661293b565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990611c0b90849061374e565b600081815260018301602052604081205461248e57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610578565b506000610578565b6000818152600183016020526040812054801561257f5760006124ba6001836136b8565b85549091506000906124ce906001906136b8565b90508181146125335760008660000182815481106124ee576124ee613398565b906000526020600020015490508087600001848154811061251157612511613398565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612544576125446137d1565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610578565b6000915050610578565b825474010000000000000000000000000000000000000000900460ff1615806125b0575081155b156125ba57505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061260090700100000000000000000000000000000000900463ffffffff16426136b8565b905080156126c05781831115612642576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186015461267c9083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1661227b565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156127775773ffffffffffffffffffffffffffffffffffffffff841661271f576040517ff94ebcd1000000000000000000000000000000000000000000000000000000008152600481018390526024810186905260440161086f565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff8516604482015260640161086f565b8483101561288a5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906127bb90826136b8565b6127c5878a6136b8565b6127cf91906137be565b6127d99190613800565b905073ffffffffffffffffffffffffffffffffffffffff8616612832576040517f15279c08000000000000000000000000000000000000000000000000000000008152600481018290526024810186905260440161086f565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff8716604482015260640161086f565b61289485846136b8565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156117f5565b600081831061294a57816117f5565b5090919050565b50805461295d90612f35565b6000825580601f1061296d575050565b601f01602090049060005260206000209081019061137491905b8082111561299b5760008155600101612987565b5090565b6000602082840312156129b157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146117f557600080fd5b803567ffffffffffffffff811681146129f957600080fd5b919050565b600060208284031215612a1057600080fd5b6117f5826129e1565b6000815180845260005b81811015612a3f57602081850181015186830182015201612a23565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006117f56020830184612a19565b73ffffffffffffffffffffffffffffffffffffffff8116811461137457600080fd5b80356129f981612a90565b600060208284031215612acf57600080fd5b81356117f581612a90565b600060208284031215612aec57600080fd5b813567ffffffffffffffff811115612b0357600080fd5b820161010081850312156117f557600080fd5b60008083601f840112612b2857600080fd5b50813567ffffffffffffffff811115612b4057600080fd5b6020830191508360208260051b8501011115612b5b57600080fd5b9250929050565b60008060008060408587031215612b7857600080fd5b843567ffffffffffffffff80821115612b9057600080fd5b612b9c88838901612b16565b90965094506020870135915080821115612bb557600080fd5b50612bc287828801612b16565b95989497509550505050565b600080600060408486031215612be357600080fd5b612bec846129e1565b9250602084013567ffffffffffffffff80821115612c0957600080fd5b818601915086601f830112612c1d57600080fd5b813581811115612c2c57600080fd5b876020828501011115612c3e57600080fd5b6020830194508093505050509250925092565b600060208284031215612c6357600080fd5b813567ffffffffffffffff811115612c7a57600080fd5b820160a081850312156117f557600080fd5b602081526000825160406020840152612ca86060840182612a19565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848303016040850152612ce38282612a19565b95945050505050565b6020808252825182820181905260009190848201906040850190845b81811015612d3a57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612d08565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015612d3a57835167ffffffffffffffff1683529284019291840191600101612d62565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715612ddb57612ddb612d88565b60405290565b60405160c0810167ffffffffffffffff81118282101715612ddb57612ddb612d88565b801515811461137457600080fd5b80356129f981612e04565b80356fffffffffffffffffffffffffffffffff811681146129f957600080fd5b600060608284031215612e4f57600080fd5b6040516060810181811067ffffffffffffffff82111715612e7257612e72612d88565b6040529050808235612e8381612e04565b8152612e9160208401612e1d565b6020820152612ea260408401612e1d565b60408201525092915050565b600080600060e08486031215612ec357600080fd5b612ecc846129e1565b9250612edb8560208601612e3d565b9150612eea8560808601612e3d565b90509250925092565b60008060208385031215612f0657600080fd5b823567ffffffffffffffff811115612f1d57600080fd5b612f2985828601612b16565b90969095509350505050565b600181811c90821680612f4957607f821691505b602082108103612f82577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f830112612f9957600080fd5b813567ffffffffffffffff80821115612fb457612fb4612d88565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715612ffa57612ffa612d88565b8160405283815286602085880101111561301357600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000610100823603121561304657600080fd5b61304e612db7565b823567ffffffffffffffff8082111561306657600080fd5b61307236838701612f88565b8352613080602086016129e1565b602084015261309160408601612ab2565b6040840152606085013560608401526130ac60808601612ab2565b608084015260a08501359150808211156130c557600080fd5b6130d136838701612f88565b60a084015260c08501359150808211156130ea57600080fd5b6130f636838701612f88565b60c084015260e085013591508082111561310f57600080fd5b5061311c36828601612f88565b60e08301525092915050565b601f821115610ed8576000816000526020600020601f850160051c810160208610156131515750805b601f850160051c820191505b818110156131705782815560010161315d565b505050505050565b67ffffffffffffffff83111561319057613190612d88565b6131a48361319e8354612f35565b83613128565b6000601f8411600181146131f657600085156131c05750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611a68565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156132455786850135825560209485019460019092019101613225565b5086821015613280577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b6040815260006132a56040830186612a19565b82810360208401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116820101915050949350505050565b600060a0823603121561330857600080fd5b60405160a0810167ffffffffffffffff828210818311171561332c5761332c612d88565b81604052843591508082111561334157600080fd5b5061334e36828601612f88565b82525061335d602084016129e1565b6020820152604083013561337081612a90565b604082015260608381013590820152608083013561338d81612a90565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec18336030181126133fb57600080fd5b9190910192915050565b6000610140823603121561341857600080fd5b613420612de1565b613429836129e1565b815261343760208401612e12565b6020820152604083013567ffffffffffffffff8082111561345757600080fd5b61346336838701612f88565b6040840152606085013591508082111561347c57600080fd5b5061348936828601612f88565b60608301525061349c3660808501612e3d565b60808201526134ae3660e08501612e3d565b60a082015292915050565b815167ffffffffffffffff8111156134d3576134d3612d88565b6134e7816134e18454612f35565b84613128565b602080601f83116001811461353a57600084156135045750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613170565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561358757888601518255948401946001909101908401613568565b50858210156135c357878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff871683528060208401526135f781840187612a19565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff90811660608701529087015116608085015291506136359050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e0830152612ce3565b60006020828403121561367e57600080fd5b81516117f581612e04565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561057857610578613689565b67ffffffffffffffff8416815260e0810161371760208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c083015261229d565b6060810161057882848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b60006020828403121561379c57600080fd5b81516117f581612a90565b808202811582820484141761057857610578613689565b8082018082111561057857610578613689565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600082613836577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fe4275726e5769746846726f6d4d696e74546f6b656e506f6f6c20312e352e302d646576a164736f6c6343000818000a",
+}
+
+var BurnWithFromMintTokenPoolABI = BurnWithFromMintTokenPoolMetaData.ABI
+
+var BurnWithFromMintTokenPoolBin = BurnWithFromMintTokenPoolMetaData.Bin
+
+func DeployBurnWithFromMintTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, rmnProxy common.Address, router common.Address) (common.Address, *types.Transaction, *BurnWithFromMintTokenPool, error) {
+ parsed, err := BurnWithFromMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BurnWithFromMintTokenPoolBin), backend, token, allowlist, rmnProxy, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &BurnWithFromMintTokenPool{address: address, abi: *parsed, BurnWithFromMintTokenPoolCaller: BurnWithFromMintTokenPoolCaller{contract: contract}, BurnWithFromMintTokenPoolTransactor: BurnWithFromMintTokenPoolTransactor{contract: contract}, BurnWithFromMintTokenPoolFilterer: BurnWithFromMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+type BurnWithFromMintTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ BurnWithFromMintTokenPoolCaller
+ BurnWithFromMintTokenPoolTransactor
+ BurnWithFromMintTokenPoolFilterer
+}
+
+type BurnWithFromMintTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type BurnWithFromMintTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type BurnWithFromMintTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type BurnWithFromMintTokenPoolSession struct {
+ Contract *BurnWithFromMintTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type BurnWithFromMintTokenPoolCallerSession struct {
+ Contract *BurnWithFromMintTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type BurnWithFromMintTokenPoolTransactorSession struct {
+ Contract *BurnWithFromMintTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type BurnWithFromMintTokenPoolRaw struct {
+ Contract *BurnWithFromMintTokenPool
+}
+
+type BurnWithFromMintTokenPoolCallerRaw struct {
+ Contract *BurnWithFromMintTokenPoolCaller
+}
+
+type BurnWithFromMintTokenPoolTransactorRaw struct {
+ Contract *BurnWithFromMintTokenPoolTransactor
+}
+
+func NewBurnWithFromMintTokenPool(address common.Address, backend bind.ContractBackend) (*BurnWithFromMintTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(BurnWithFromMintTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindBurnWithFromMintTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPool{address: address, abi: abi, BurnWithFromMintTokenPoolCaller: BurnWithFromMintTokenPoolCaller{contract: contract}, BurnWithFromMintTokenPoolTransactor: BurnWithFromMintTokenPoolTransactor{contract: contract}, BurnWithFromMintTokenPoolFilterer: BurnWithFromMintTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewBurnWithFromMintTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*BurnWithFromMintTokenPoolCaller, error) {
+ contract, err := bindBurnWithFromMintTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolCaller{contract: contract}, nil
+}
+
+func NewBurnWithFromMintTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*BurnWithFromMintTokenPoolTransactor, error) {
+ contract, err := bindBurnWithFromMintTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewBurnWithFromMintTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*BurnWithFromMintTokenPoolFilterer, error) {
+ contract, err := bindBurnWithFromMintTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindBurnWithFromMintTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := BurnWithFromMintTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnWithFromMintTokenPool.Contract.BurnWithFromMintTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.BurnWithFromMintTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.BurnWithFromMintTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _BurnWithFromMintTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetAllowList(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetAllowList(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetAllowListEnabled(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetAllowListEnabled(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetCurrentInboundRateLimiterState(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getRemotePool", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetRemotePool(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetRemotePool(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetRemoteToken(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetRemoteToken(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getRmnProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetRmnProxy() (common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetRmnProxy(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetRmnProxy() (common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetRmnProxy(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetRouter() (common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetRouter(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetRouter(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetSupportedChains(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetSupportedChains(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) GetToken() (common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetToken(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.GetToken(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnWithFromMintTokenPool.Contract.IsSupportedChain(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _BurnWithFromMintTokenPool.Contract.IsSupportedChain(&_BurnWithFromMintTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "isSupportedToken", token)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _BurnWithFromMintTokenPool.Contract.IsSupportedToken(&_BurnWithFromMintTokenPool.CallOpts, token)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _BurnWithFromMintTokenPool.Contract.IsSupportedToken(&_BurnWithFromMintTokenPool.CallOpts, token)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) Owner() (common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.Owner(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _BurnWithFromMintTokenPool.Contract.Owner(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnWithFromMintTokenPool.Contract.SupportsInterface(&_BurnWithFromMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _BurnWithFromMintTokenPool.Contract.SupportsInterface(&_BurnWithFromMintTokenPool.CallOpts, interfaceId)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _BurnWithFromMintTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) TypeAndVersion() (string, error) {
+ return _BurnWithFromMintTokenPool.Contract.TypeAndVersion(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _BurnWithFromMintTokenPool.Contract.TypeAndVersion(&_BurnWithFromMintTokenPool.CallOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.AcceptOwnership(&_BurnWithFromMintTokenPool.TransactOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.AcceptOwnership(&_BurnWithFromMintTokenPool.TransactOpts)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnWithFromMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.ApplyAllowListUpdates(&_BurnWithFromMintTokenPool.TransactOpts, removes, adds)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.ApplyChainUpdates(&_BurnWithFromMintTokenPool.TransactOpts, chains)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.ApplyChainUpdates(&_BurnWithFromMintTokenPool.TransactOpts, chains)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "lockOrBurn", lockOrBurnIn)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.LockOrBurn(&_BurnWithFromMintTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.LockOrBurn(&_BurnWithFromMintTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "releaseOrMint", releaseOrMintIn)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.ReleaseOrMint(&_BurnWithFromMintTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.ReleaseOrMint(&_BurnWithFromMintTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnWithFromMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.SetChainRateLimiterConfig(&_BurnWithFromMintTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "setRemotePool", remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.SetRemotePool(&_BurnWithFromMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.SetRemotePool(&_BurnWithFromMintTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.SetRouter(&_BurnWithFromMintTokenPool.TransactOpts, newRouter)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.SetRouter(&_BurnWithFromMintTokenPool.TransactOpts, newRouter)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.TransferOwnership(&_BurnWithFromMintTokenPool.TransactOpts, to)
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _BurnWithFromMintTokenPool.Contract.TransferOwnership(&_BurnWithFromMintTokenPool.TransactOpts, to)
+}
+
+type BurnWithFromMintTokenPoolAllowListAddIterator struct {
+ Event *BurnWithFromMintTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolAllowListAdd)
+ 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(BurnWithFromMintTokenPoolAllowListAdd)
+ 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 *BurnWithFromMintTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolAllowListAddIterator{contract: _BurnWithFromMintTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolAllowListAdd)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*BurnWithFromMintTokenPoolAllowListAdd, error) {
+ event := new(BurnWithFromMintTokenPoolAllowListAdd)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolAllowListRemoveIterator struct {
+ Event *BurnWithFromMintTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolAllowListRemove)
+ 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(BurnWithFromMintTokenPoolAllowListRemove)
+ 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 *BurnWithFromMintTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolAllowListRemoveIterator{contract: _BurnWithFromMintTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolAllowListRemove)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*BurnWithFromMintTokenPoolAllowListRemove, error) {
+ event := new(BurnWithFromMintTokenPoolAllowListRemove)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolBurnedIterator struct {
+ Event *BurnWithFromMintTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolBurned)
+ 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(BurnWithFromMintTokenPoolBurned)
+ 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 *BurnWithFromMintTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnWithFromMintTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolBurnedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolBurned)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "Burned", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseBurned(log types.Log) (*BurnWithFromMintTokenPoolBurned, error) {
+ event := new(BurnWithFromMintTokenPoolBurned)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolChainAddedIterator struct {
+ Event *BurnWithFromMintTokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolChainAdded)
+ 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(BurnWithFromMintTokenPoolChainAdded)
+ 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 *BurnWithFromMintTokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolChainAddedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolChainAdded)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseChainAdded(log types.Log) (*BurnWithFromMintTokenPoolChainAdded, error) {
+ event := new(BurnWithFromMintTokenPoolChainAdded)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolChainConfiguredIterator struct {
+ Event *BurnWithFromMintTokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolChainConfigured)
+ 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(BurnWithFromMintTokenPoolChainConfigured)
+ 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 *BurnWithFromMintTokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolChainConfiguredIterator{contract: _BurnWithFromMintTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolChainConfigured)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseChainConfigured(log types.Log) (*BurnWithFromMintTokenPoolChainConfigured, error) {
+ event := new(BurnWithFromMintTokenPoolChainConfigured)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolChainRemovedIterator struct {
+ Event *BurnWithFromMintTokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolChainRemoved)
+ 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(BurnWithFromMintTokenPoolChainRemoved)
+ 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 *BurnWithFromMintTokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolChainRemovedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolChainRemoved)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseChainRemoved(log types.Log) (*BurnWithFromMintTokenPoolChainRemoved, error) {
+ event := new(BurnWithFromMintTokenPoolChainRemoved)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolConfigChangedIterator struct {
+ Event *BurnWithFromMintTokenPoolConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolConfigChanged)
+ 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(BurnWithFromMintTokenPoolConfigChanged)
+ 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 *BurnWithFromMintTokenPoolConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolConfigChangedIterator, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolConfigChangedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolConfigChanged)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "ConfigChanged", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseConfigChanged(log types.Log) (*BurnWithFromMintTokenPoolConfigChanged, error) {
+ event := new(BurnWithFromMintTokenPoolConfigChanged)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolLockedIterator struct {
+ Event *BurnWithFromMintTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolLocked)
+ 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(BurnWithFromMintTokenPoolLocked)
+ 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 *BurnWithFromMintTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnWithFromMintTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolLockedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolLocked)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "Locked", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseLocked(log types.Log) (*BurnWithFromMintTokenPoolLocked, error) {
+ event := new(BurnWithFromMintTokenPoolLocked)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolMintedIterator struct {
+ Event *BurnWithFromMintTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolMinted)
+ 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(BurnWithFromMintTokenPoolMinted)
+ 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 *BurnWithFromMintTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnWithFromMintTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolMintedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolMinted)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "Minted", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseMinted(log types.Log) (*BurnWithFromMintTokenPoolMinted, error) {
+ event := new(BurnWithFromMintTokenPoolMinted)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *BurnWithFromMintTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolOwnershipTransferRequested)
+ 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(BurnWithFromMintTokenPoolOwnershipTransferRequested)
+ 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 *BurnWithFromMintTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnWithFromMintTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolOwnershipTransferRequestedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*BurnWithFromMintTokenPoolOwnershipTransferRequested, error) {
+ event := new(BurnWithFromMintTokenPoolOwnershipTransferRequested)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolOwnershipTransferredIterator struct {
+ Event *BurnWithFromMintTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolOwnershipTransferred)
+ 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(BurnWithFromMintTokenPoolOwnershipTransferred)
+ 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 *BurnWithFromMintTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnWithFromMintTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolOwnershipTransferredIterator{contract: _BurnWithFromMintTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolOwnershipTransferred)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*BurnWithFromMintTokenPoolOwnershipTransferred, error) {
+ event := new(BurnWithFromMintTokenPoolOwnershipTransferred)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolReleasedIterator struct {
+ Event *BurnWithFromMintTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolReleased)
+ 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(BurnWithFromMintTokenPoolReleased)
+ 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 *BurnWithFromMintTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnWithFromMintTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolReleasedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolReleased)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "Released", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseReleased(log types.Log) (*BurnWithFromMintTokenPoolReleased, error) {
+ event := new(BurnWithFromMintTokenPoolReleased)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolRemotePoolSetIterator struct {
+ Event *BurnWithFromMintTokenPoolRemotePoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolRemotePoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolRemotePoolSet)
+ 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(BurnWithFromMintTokenPoolRemotePoolSet)
+ 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 *BurnWithFromMintTokenPoolRemotePoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolRemotePoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolRemotePoolSet struct {
+ RemoteChainSelector uint64
+ PreviousPoolAddress []byte
+ RemotePoolAddress []byte
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnWithFromMintTokenPoolRemotePoolSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolRemotePoolSetIterator{contract: _BurnWithFromMintTokenPool.contract, event: "RemotePoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolRemotePoolSet)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "RemotePoolSet", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseRemotePoolSet(log types.Log) (*BurnWithFromMintTokenPoolRemotePoolSet, error) {
+ event := new(BurnWithFromMintTokenPoolRemotePoolSet)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "RemotePoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolRouterUpdatedIterator struct {
+ Event *BurnWithFromMintTokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolRouterUpdated)
+ 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(BurnWithFromMintTokenPoolRouterUpdated)
+ 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 *BurnWithFromMintTokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolRouterUpdatedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolRouterUpdated)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*BurnWithFromMintTokenPoolRouterUpdated, error) {
+ event := new(BurnWithFromMintTokenPoolRouterUpdated)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type BurnWithFromMintTokenPoolTokensConsumedIterator struct {
+ Event *BurnWithFromMintTokenPoolTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *BurnWithFromMintTokenPoolTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(BurnWithFromMintTokenPoolTokensConsumed)
+ 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(BurnWithFromMintTokenPoolTokensConsumed)
+ 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 *BurnWithFromMintTokenPoolTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *BurnWithFromMintTokenPoolTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type BurnWithFromMintTokenPoolTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolTokensConsumedIterator, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &BurnWithFromMintTokenPoolTokensConsumedIterator{contract: _BurnWithFromMintTokenPool.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _BurnWithFromMintTokenPool.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(BurnWithFromMintTokenPoolTokensConsumed)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "TokensConsumed", 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 (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPoolFilterer) ParseTokensConsumed(log types.Log) (*BurnWithFromMintTokenPoolTokensConsumed, error) {
+ event := new(BurnWithFromMintTokenPoolTokensConsumed)
+ if err := _BurnWithFromMintTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _BurnWithFromMintTokenPool.abi.Events["AllowListAdd"].ID:
+ return _BurnWithFromMintTokenPool.ParseAllowListAdd(log)
+ case _BurnWithFromMintTokenPool.abi.Events["AllowListRemove"].ID:
+ return _BurnWithFromMintTokenPool.ParseAllowListRemove(log)
+ case _BurnWithFromMintTokenPool.abi.Events["Burned"].ID:
+ return _BurnWithFromMintTokenPool.ParseBurned(log)
+ case _BurnWithFromMintTokenPool.abi.Events["ChainAdded"].ID:
+ return _BurnWithFromMintTokenPool.ParseChainAdded(log)
+ case _BurnWithFromMintTokenPool.abi.Events["ChainConfigured"].ID:
+ return _BurnWithFromMintTokenPool.ParseChainConfigured(log)
+ case _BurnWithFromMintTokenPool.abi.Events["ChainRemoved"].ID:
+ return _BurnWithFromMintTokenPool.ParseChainRemoved(log)
+ case _BurnWithFromMintTokenPool.abi.Events["ConfigChanged"].ID:
+ return _BurnWithFromMintTokenPool.ParseConfigChanged(log)
+ case _BurnWithFromMintTokenPool.abi.Events["Locked"].ID:
+ return _BurnWithFromMintTokenPool.ParseLocked(log)
+ case _BurnWithFromMintTokenPool.abi.Events["Minted"].ID:
+ return _BurnWithFromMintTokenPool.ParseMinted(log)
+ case _BurnWithFromMintTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _BurnWithFromMintTokenPool.ParseOwnershipTransferRequested(log)
+ case _BurnWithFromMintTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _BurnWithFromMintTokenPool.ParseOwnershipTransferred(log)
+ case _BurnWithFromMintTokenPool.abi.Events["Released"].ID:
+ return _BurnWithFromMintTokenPool.ParseReleased(log)
+ case _BurnWithFromMintTokenPool.abi.Events["RemotePoolSet"].ID:
+ return _BurnWithFromMintTokenPool.ParseRemotePoolSet(log)
+ case _BurnWithFromMintTokenPool.abi.Events["RouterUpdated"].ID:
+ return _BurnWithFromMintTokenPool.ParseRouterUpdated(log)
+ case _BurnWithFromMintTokenPool.abi.Events["TokensConsumed"].ID:
+ return _BurnWithFromMintTokenPool.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (BurnWithFromMintTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (BurnWithFromMintTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (BurnWithFromMintTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (BurnWithFromMintTokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2")
+}
+
+func (BurnWithFromMintTokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (BurnWithFromMintTokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (BurnWithFromMintTokenPoolConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (BurnWithFromMintTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (BurnWithFromMintTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (BurnWithFromMintTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (BurnWithFromMintTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (BurnWithFromMintTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (BurnWithFromMintTokenPoolRemotePoolSet) Topic() common.Hash {
+ return common.HexToHash("0xdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf")
+}
+
+func (BurnWithFromMintTokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (BurnWithFromMintTokenPoolTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_BurnWithFromMintTokenPool *BurnWithFromMintTokenPool) Address() common.Address {
+ return _BurnWithFromMintTokenPool.address
+}
+
+type BurnWithFromMintTokenPoolInterface interface {
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRmnProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*BurnWithFromMintTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*BurnWithFromMintTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*BurnWithFromMintTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*BurnWithFromMintTokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*BurnWithFromMintTokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*BurnWithFromMintTokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*BurnWithFromMintTokenPoolChainRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*BurnWithFromMintTokenPoolConfigChanged, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*BurnWithFromMintTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*BurnWithFromMintTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnWithFromMintTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*BurnWithFromMintTokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnWithFromMintTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*BurnWithFromMintTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*BurnWithFromMintTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*BurnWithFromMintTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*BurnWithFromMintTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*BurnWithFromMintTokenPoolReleased, error)
+
+ FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*BurnWithFromMintTokenPoolRemotePoolSetIterator, error)
+
+ WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRemotePoolSet(log types.Log) (*BurnWithFromMintTokenPoolRemotePoolSet, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*BurnWithFromMintTokenPoolRouterUpdated, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*BurnWithFromMintTokenPoolTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *BurnWithFromMintTokenPoolTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*BurnWithFromMintTokenPoolTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/ccip_config/ccip_config.go b/core/gethwrappers/ccip/generated/ccip_config/ccip_config.go
new file mode 100644
index 00000000000..e35a8726dec
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/ccip_config/ccip_config.go
@@ -0,0 +1,1103 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package ccip_config
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CCIPConfigTypesChainConfig struct {
+ Readers [][32]byte
+ FChain uint8
+ Config []byte
+}
+
+type CCIPConfigTypesChainConfigInfo struct {
+ ChainSelector uint64
+ ChainConfig CCIPConfigTypesChainConfig
+}
+
+type CCIPConfigTypesOCR3Config struct {
+ PluginType uint8
+ ChainSelector uint64
+ F uint8
+ OffchainConfigVersion uint64
+ OfframpAddress []byte
+ BootstrapP2PIds [][32]byte
+ P2pIds [][32]byte
+ Signers [][]byte
+ Transmitters [][]byte
+ OffchainConfig []byte
+}
+
+type CCIPConfigTypesOCR3ConfigWithMeta struct {
+ Config CCIPConfigTypesOCR3Config
+ ConfigCount uint64
+ ConfigDigest [32]byte
+}
+
+var CCIPConfigMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"capabilitiesRegistry\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainConfigNotSetForChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainSelectorNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainSelectorNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptySet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FChainMustBePositive\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FMustBePositive\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"InvalidConfigLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enumCCIPConfigTypes.ConfigState\",\"name\":\"currentState\",\"type\":\"uint8\"},{\"internalType\":\"enumCCIPConfigTypes.ConfigState\",\"name\":\"proposedState\",\"type\":\"uint8\"}],\"name\":\"InvalidConfigStateTransition\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPluginType\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"}],\"name\":\"NodeNotInRegistry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonExistentConfigTransition\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"set\",\"type\":\"bytes32[]\"}],\"name\":\"NotASortedSet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"subset\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"superset\",\"type\":\"bytes32[]\"}],\"name\":\"NotASubset\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minimum\",\"type\":\"uint256\"}],\"name\":\"NotEnoughTransmitters\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OfframpAddressCannotBeZero\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCapabilitiesRegistryCanCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"p2pIdsLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"signersLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"transmittersLength\",\"type\":\"uint256\"}],\"name\":\"P2PIdsLengthNotMatching\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyBootstrapP2PIds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyOCR3Configs\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManySigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyTransmitters\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"got\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"expected\",\"type\":\"uint64\"}],\"name\":\"WrongConfigCount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"got\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"}],\"name\":\"WrongConfigDigest\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"got\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"}],\"name\":\"WrongConfigDigestBlueGreen\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"CapabilityConfigurationSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainConfigRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32[]\",\"name\":\"readers\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint8\",\"name\":\"fChain\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structCCIPConfigTypes.ChainConfig\",\"name\":\"chainConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigSet\",\"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\":\"uint64[]\",\"name\":\"chainSelectorRemoves\",\"type\":\"uint64[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32[]\",\"name\":\"readers\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint8\",\"name\":\"fChain\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCCIPConfigTypes.ChainConfig\",\"name\":\"chainConfig\",\"type\":\"tuple\"}],\"internalType\":\"structCCIPConfigTypes.ChainConfigInfo[]\",\"name\":\"chainConfigAdds\",\"type\":\"tuple[]\"}],\"name\":\"applyChainConfigUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"}],\"name\":\"beforeCapabilityConfigSet\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllChainConfigs\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32[]\",\"name\":\"readers\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint8\",\"name\":\"fChain\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCCIPConfigTypes.ChainConfig\",\"name\":\"chainConfig\",\"type\":\"tuple\"}],\"internalType\":\"structCCIPConfigTypes.ChainConfigInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"name\":\"getCapabilityConfiguration\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"configuration\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"enumInternal.OCRPluginType\",\"name\":\"pluginType\",\"type\":\"uint8\"}],\"name\":\"getOCRConfig\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"enumInternal.OCRPluginType\",\"name\":\"pluginType\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"F\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offrampAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"bootstrapP2PIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"p2pIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes[]\",\"name\":\"signers\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes[]\",\"name\":\"transmitters\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structCCIPConfigTypes.OCR3Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"internalType\":\"structCCIPConfigTypes.OCR3ConfigWithMeta[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x60a06040523480156200001157600080fd5b50604051620043cc380380620043cc83398101604081905262000034916200017e565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d3565b5050506001600160a01b0316608052620001b0565b336001600160a01b038216036200012d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019157600080fd5b81516001600160a01b0381168114620001a957600080fd5b9392505050565b6080516141f9620001d360003960008181610e4e01526110e301526141f96000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80638da5cb5b11610076578063f2fde38b1161005b578063f2fde38b146101bc578063f442c89a146101cf578063fba64a7c146101e257600080fd5b80638da5cb5b1461017f578063ddc042a8146101a757600080fd5b80634bd0473f116100a75780634bd0473f1461013457806379ba5097146101545780638318ed5d1461015e57600080fd5b806301ffc9a7146100c3578063181f5a77146100eb575b600080fd5b6100d66100d1366004612f77565b6101f5565b60405190151581526020015b60405180910390f35b6101276040518060400160405280601481526020017f43434950436f6e66696720312e362e302d64657600000000000000000000000081525081565b6040516100e2919061301d565b610147610142366004613061565b61028e565b6040516100e2919061318d565b61015c61075e565b005b61012761016c36600461336a565b5060408051602081019091526000815290565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e2565b6101af610860565b6040516100e291906133cb565b61015c6101ca36600461345b565b610a52565b61015c6101dd3660046134dd565b610a66565b61015c6101f0366004613561565b610e36565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f78bea72100000000000000000000000000000000000000000000000000000000148061028857507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b63ffffffff821660009081526005602052604081206060918360018111156102b8576102b8613096565b60018111156102c9576102c9613096565b8152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b8282101561075257600084815260209020604080516101a08101909152600984029091018054829060608201908390829060ff16600181111561033c5761033c613096565b600181111561034d5761034d613096565b8152815467ffffffffffffffff61010082048116602084015260ff690100000000000000000083041660408401526a01000000000000000000009091041660608201526001820180546080909201916103a59061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546103d19061361e565b801561041e5780601f106103f35761010080835404028352916020019161041e565b820191906000526020600020905b81548152906001019060200180831161040157829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561047657602002820191906000526020600020905b815481526020019060010190808311610462575b50505050508152602001600382018054806020026020016040519081016040528092919081815260200182805480156104ce57602002820191906000526020600020905b8154815260200190600101908083116104ba575b5050505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156105a857838290600052602060002001805461051b9061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546105479061361e565b80156105945780601f1061056957610100808354040283529160200191610594565b820191906000526020600020905b81548152906001019060200180831161057757829003601f168201915b5050505050815260200190600101906104fc565b50505050815260200160058201805480602002602001604051908101604052809291908181526020016000905b828210156106815783829060005260206000200180546105f49061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546106209061361e565b801561066d5780601f106106425761010080835404028352916020019161066d565b820191906000526020600020905b81548152906001019060200180831161065057829003601f168201915b5050505050815260200190600101906105d5565b5050505081526020016006820180546106999061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546106c59061361e565b80156107125780601f106106e757610100808354040283529160200191610712565b820191906000526020600020905b8154815290600101906020018083116106f557829003601f168201915b505050919092525050508152600782015467ffffffffffffffff1660208083019190915260089092015460409091015290825260019290920191016102f7565b50505050905092915050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6060600061086e6003610ef7565b9050600061087c6003610f0b565b67ffffffffffffffff81111561089457610894613671565b6040519080825280602002602001820160405280156108cd57816020015b6108ba612d08565b8152602001906001900390816108b25790505b50905060005b8251811015610a4b5760008382815181106108f0576108f06136a0565b60209081029190910181015160408051808201825267ffffffffffffffff83168082526000908152600285528290208251815460808188028301810190955260608201818152959750929586019490939192849284919084018282801561097657602002820191906000526020600020905b815481526020019060010190808311610962575b5050509183525050600182015460ff1660208201526002820180546040909201916109a09061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546109cc9061361e565b8015610a195780601f106109ee57610100808354040283529160200191610a19565b820191906000526020600020905b8154815290600101906020018083116109fc57829003601f168201915b505050505081525050815250838381518110610a3757610a376136a0565b6020908102919091010152506001016108d3565b5092915050565b610a5a610f15565b610a6381610f98565b50565b610a6e610f15565b60005b83811015610c5457610ab5858583818110610a8e57610a8e6136a0565b9050602002016020810190610aa391906136cf565b60039067ffffffffffffffff1661108d565b610b1f57848482818110610acb57610acb6136a0565b9050602002016020810190610ae091906136cf565b6040517f1bd4d2d200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107db565b60026000868684818110610b3557610b356136a0565b9050602002016020810190610b4a91906136cf565b67ffffffffffffffff1681526020810191909152604001600090812090610b718282612d50565b6001820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055610ba9600283016000612d6e565b5050610be7858583818110610bc057610bc06136a0565b9050602002016020810190610bd591906136cf565b60039067ffffffffffffffff166110a5565b507f2a680691fef3b2d105196805935232c661ce703e92d464ef0b94a7bc62d714f0858583818110610c1b57610c1b6136a0565b9050602002016020810190610c3091906136cf565b60405167ffffffffffffffff909116815260200160405180910390a1600101610a71565b5060005b81811015610e2f576000838383818110610c7457610c746136a0565b9050602002810190610c8691906136ea565b610c94906020810190613728565b610c9d9061392a565b80519091506000858585818110610cb657610cb66136a0565b9050602002810190610cc891906136ea565b610cd69060208101906136cf565b905060005b8251811015610d0e57610d06838281518110610cf957610cf96136a0565b60200260200101516110b1565b600101610cdb565b50826020015160ff16600003610d50576040517fa9b3766e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600260209081526040909120845180518693610d80928492910190612da8565b5060208201516001820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff90921691909117905560408201516002820190610dcd9082613a11565b50610de791506003905067ffffffffffffffff83166111ca565b507f05dd57854af2c291a94ea52e7c43d80bc3be7fa73022f98b735dea86642fa5e08184604051610e19929190613b2b565b60405180910390a1505050806001019050610c58565b5050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610ea5576040517fac7a7efd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610eb384860186613bd6565b9050600080610ec1836111d6565b8151919350915015610ed957610ed98460008461142f565b805115610eec57610eec8460018361142f565b505050505050505050565b60606000610f0483611c10565b9392505050565b6000610288825490565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107db565b565b3373ffffffffffffffffffffffffffffffffffffffff821603611017576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107db565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008181526001830160205260408120541515610f04565b6000610f048383611c6c565b6040517f50c946fe000000000000000000000000000000000000000000000000000000008152600481018290526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906350c946fe90602401600060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526111859190810190613e47565b60808101519091506111c6576040517f8907a4fa000000000000000000000000000000000000000000000000000000008152600481018390526024016107db565b5050565b6000610f048383611d5f565b606080600460ff1683511115611218576040517f8854586400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160028082526060820190925290816020015b61129c6040805161014081019091528060008152602001600067ffffffffffffffff168152602001600060ff168152602001600067ffffffffffffffff1681526020016060815260200160608152602001606081526020016060815260200160608152602001606081525090565b81526020019060019003908161122e57505060408051600280825260608201909252919350602082015b6113346040805161014081019091528060008152602001600067ffffffffffffffff168152602001600060ff168152602001600067ffffffffffffffff1681526020016060815260200160608152602001606081526020016060815260200160608152602001606081525090565b8152602001906001900390816112c657905050905060008060005b855181101561142257600086828151811061136c5761136c6136a0565b602002602001015160000151600181111561138957611389613096565b036113d6578581815181106113a0576113a06136a0565b60200260200101518584815181106113ba576113ba6136a0565b6020026020010181905250826113cf90613f4e565b925061141a565b8581815181106113e8576113e86136a0565b6020026020010151848381518110611402576114026136a0565b60200260200101819052508161141790613f4e565b91505b60010161134f565b5090835281529092909150565b63ffffffff831660009081526005602052604081208184600181111561145757611457613096565b600181111561146857611468613096565b8152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156118f157600084815260209020604080516101a08101909152600984029091018054829060608201908390829060ff1660018111156114db576114db613096565b60018111156114ec576114ec613096565b8152815467ffffffffffffffff61010082048116602084015260ff690100000000000000000083041660408401526a01000000000000000000009091041660608201526001820180546080909201916115449061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546115709061361e565b80156115bd5780601f10611592576101008083540402835291602001916115bd565b820191906000526020600020905b8154815290600101906020018083116115a057829003601f168201915b505050505081526020016002820180548060200260200160405190810160405280929190818152602001828054801561161557602002820191906000526020600020905b815481526020019060010190808311611601575b505050505081526020016003820180548060200260200160405190810160405280929190818152602001828054801561166d57602002820191906000526020600020905b815481526020019060010190808311611659575b5050505050815260200160048201805480602002602001604051908101604052809291908181526020016000905b828210156117475783829060005260206000200180546116ba9061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546116e69061361e565b80156117335780601f1061170857610100808354040283529160200191611733565b820191906000526020600020905b81548152906001019060200180831161171657829003601f168201915b50505050508152602001906001019061169b565b50505050815260200160058201805480602002602001604051908101604052809291908181526020016000905b828210156118205783829060005260206000200180546117939061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546117bf9061361e565b801561180c5780601f106117e15761010080835404028352916020019161180c565b820191906000526020600020905b8154815290600101906020018083116117ef57829003601f168201915b505050505081526020019060010190611774565b5050505081526020016006820180546118389061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546118649061361e565b80156118b15780601f10611886576101008083540402835291602001916118b1565b820191906000526020600020905b81548152906001019060200180831161189457829003601f168201915b505050919092525050508152600782015467ffffffffffffffff166020808301919091526008909201546040909101529082526001929092019101611496565b50505050905060006119038251611dae565b905060006119118451611dae565b905061191d8282611e00565b600061192c8785878686611ebc565b905061193884826122a8565b63ffffffff871660009081526005602052604081209087600181111561196057611960613096565b600181111561197157611971613096565b8152602001908152602001600020600061198b9190612df3565b60005b8151811015611c065763ffffffff88166000908152600560205260408120908860018111156119bf576119bf613096565b60018111156119d0576119d0613096565b81526020019081526020016000208282815181106119f0576119f06136a0565b6020908102919091018101518254600181810185556000948552929093208151805160099095029091018054929490939192849283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016908381811115611a5a57611a5a613096565b021790555060208201518154604084015160608501517fffffffffffffffffffffffffffffffffffffffffffff000000000000000000ff90921661010067ffffffffffffffff948516027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff1617690100000000000000000060ff90921691909102177fffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffff166a0100000000000000000000929091169190910217815560808201516001820190611b299082613a11565b5060a08201518051611b45916002840191602090910190612da8565b5060c08201518051611b61916003840191602090910190612da8565b5060e08201518051611b7d916004840191602090910190612e14565b506101008201518051611b9a916005840191602090910190612e14565b506101208201516006820190611bb09082613a11565b50505060208201516007820180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff90921691909117905560409091015160089091015560010161198e565b5050505050505050565b606081600001805480602002602001604051908101604052809291908181526020018280548015611c6057602002820191906000526020600020905b815481526020019060010190808311611c4c575b50505050509050919050565b60008181526001830160205260408120548015611d55576000611c90600183613f86565b8554909150600090611ca490600190613f86565b9050818114611d09576000866000018281548110611cc457611cc46136a0565b9060005260206000200154905080876000018481548110611ce757611ce76136a0565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611d1a57611d1a613f99565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610288565b6000915050610288565b6000818152600183016020526040812054611da657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610288565b506000610288565b60006002821115611dee576040517f3e478526000000000000000000000000000000000000000000000000000000008152600481018390526024016107db565b81600281111561028857610288613096565b6000826002811115611e1457611e14613096565b826002811115611e2657611e26613096565b611e309190613fc8565b90508060011480611e7c5750807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff148015611e7c57506002836002811115611e7a57611e7a613096565b145b15611e8657505050565b82826040517f0a6b675b0000000000000000000000000000000000000000000000000000000081526004016107db929190613ff8565b60606000845167ffffffffffffffff811115611eda57611eda613671565b604051908082528060200260200182016040528015611f03578160200160208202803683370190505b5090506000846002811115611f1a57611f1a613096565b148015611f3857506001836002811115611f3657611f36613096565b145b15611f7957600181600081518110611f5257611f526136a0565b602002602001019067ffffffffffffffff16908167ffffffffffffffff16815250506120e1565b6001846002811115611f8d57611f8d613096565b148015611fab57506002836002811115611fa957611fa9613096565b145b156120425785600081518110611fc357611fc36136a0565b60200260200101516020015181600081518110611fe257611fe26136a0565b602002602001019067ffffffffffffffff16908167ffffffffffffffff168152505085600081518110612017576120176136a0565b602002602001015160200151600161202f9190614013565b81600181518110611f5257611f526136a0565b600284600281111561205657612056613096565b1480156120745750600183600281111561207257612072613096565b145b156120ab578560018151811061208c5761208c6136a0565b60200260200101516020015181600081518110611f5257611f526136a0565b83836040517f0a6b675b0000000000000000000000000000000000000000000000000000000081526004016107db929190613ff8565b6000855167ffffffffffffffff8111156120fd576120fd613671565b6040519080825280602002602001820160405280156121b357816020015b604080516101a081018252600060608083018281526080840183905260a0840183905260c0840183905260e084018290526101008401829052610120840182905261014084018290526101608401829052610180840191909152825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161211b5790505b50905060005b825181101561229c576121e48782815181106121d7576121d76136a0565b6020026020010151612627565b6040518060600160405280888381518110612201576122016136a0565b60200260200101518152602001848381518110612220576122206136a0565b602002602001015167ffffffffffffffff1681526020016122748b86858151811061224d5761224d6136a0565b60200260200101518b8681518110612267576122676136a0565b6020026020010151612a2d565b815250828281518110612289576122896136a0565b60209081029190910101526001016121b9565b50979650505050505050565b81518151811580156122ba5750806001145b1561235c57826000815181106122d2576122d26136a0565b60200260200101516020015167ffffffffffffffff166001146123565782600081518110612302576123026136a0565b60209081029190910181015101516040517fc1658eb800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152600160248201526044016107db565b50505050565b81600114801561236c5750806002145b156125225783600081518110612384576123846136a0565b602002602001015160400151836000815181106123a3576123a36136a0565b6020026020010151604001511461242f57826000815181106123c7576123c76136a0565b602002602001015160400151846000815181106123e6576123e66136a0565b6020026020010151604001516040517fc7ccdd7f0000000000000000000000000000000000000000000000000000000081526004016107db929190918252602082015260400190565b83600081518110612442576124426136a0565b602002602001015160200151600161245a9190614013565b67ffffffffffffffff1683600181518110612477576124776136a0565b60200260200101516020015167ffffffffffffffff161461235657826001815181106124a5576124a56136a0565b602002602001015160200151846000815181106124c4576124c46136a0565b60200260200101516020015160016124dc9190614013565b6040517fc1658eb800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9283166004820152911660248201526044016107db565b8160021480156125325750806001145b156125f5578360018151811061254a5761254a6136a0565b60200260200101516040015183600081518110612569576125696136a0565b60200260200101516040015114612356578260008151811061258d5761258d6136a0565b602002602001015160400151846001815181106125ac576125ac6136a0565b6020026020010151604001516040517f9e9756700000000000000000000000000000000000000000000000000000000081526004016107db929190918252602082015260400190565b6040517f1f1b2bb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806020015167ffffffffffffffff1660000361266f576040517f698cf8e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008151600181111561268457612684613096565b141580156126a557506001815160018111156126a2576126a2613096565b14155b156126dc576040517f3302dbd700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80608001515160000361271b576040517f358c192700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516127369060039067ffffffffffffffff1661108d565b61277e5760208101516040517f1bd4d2d200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107db565b60e081015151601f10156127be576040517f1b925da600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010081015151601f10156127ff576040517f645960ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208082015167ffffffffffffffff1660009081526002909152604081206001015461282f9060ff166003614034565b61283a906001614050565b60ff1690508082610100015151101561289157610100820151516040517f548dd21f0000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016107db565b816040015160ff166000036128d2576040517f39d1a4d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516128e2906003614034565b60ff168260e001515111612922576040517f4856694e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160e00151518260c00151511415806129465750816101000151518260c001515114155b156129a15760c08201515160e083015151610100840151516040517fba900f6d0000000000000000000000000000000000000000000000000000000081526004810193909352602483019190915260448201526064016107db565b8160c00151518260a001515111156129e5576040517f8473d80700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129f78260a001518360c00151612b02565b60005b8260e0015151811015612a2857612a208360c001518281518110610cf957610cf96136a0565b6001016129fa565b505050565b60008082602001518584600001518560800151878760a001518860c001518960e001518a61010001518b604001518c606001518d6101200151604051602001612a819c9b9a999897969594939291906140d4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e0a000000000000000000000000000000000000000000000000000000000000179150509392505050565b81511580612b0f57508051155b15612b46576040517fe249684100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b4f82612c7d565b612b5881612c7d565b6000805b835182108015612b6c5750825181105b15612c3e57828181518110612b8357612b836136a0565b6020026020010151848381518110612b9d57612b9d6136a0565b60200260200101511115612bbb57612bb481613f4e565b9050612b5c565b828181518110612bcd57612bcd6136a0565b6020026020010151848381518110612be757612be76136a0565b602002602001015103612c0857612bfd82613f4e565b9150612bb481613f4e565b83836040517fd671700c0000000000000000000000000000000000000000000000000000000081526004016107db9291906141b4565b83518210156123565783836040517fd671700c0000000000000000000000000000000000000000000000000000000081526004016107db9291906141b4565b60015b81518110156111c65781612c95600183613f86565b81518110612ca557612ca56136a0565b6020026020010151828281518110612cbf57612cbf6136a0565b602002602001015111612d0057816040517f1bc41b420000000000000000000000000000000000000000000000000000000081526004016107db91906141d9565b600101612c80565b6040518060400160405280600067ffffffffffffffff168152602001612d4b604051806060016040528060608152602001600060ff168152602001606081525090565b905290565b5080546000825590600052602060002090810190610a639190612e66565b508054612d7a9061361e565b6000825580601f10612d8a575050565b601f016020900490600052602060002090810190610a639190612e66565b828054828255906000526020600020908101928215612de3579160200282015b82811115612de3578251825591602001919060010190612dc8565b50612def929150612e66565b5090565b5080546000825560090290600052602060002090810190610a639190612e7b565b828054828255906000526020600020908101928215612e5a579160200282015b82811115612e5a5782518290612e4a9082613a11565b5091602001919060010190612e34565b50612def929150612f3c565b5b80821115612def5760008155600101612e67565b80821115612def5780547fffffffffffffffffffffffffffff00000000000000000000000000000000000016815560008181612eba6001830182612d6e565b612ec8600283016000612d50565b612ed6600383016000612d50565b612ee4600483016000612f59565b612ef2600583016000612f59565b612f00600683016000612d6e565b5050506007810180547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016905560006008820155600901612e7b565b80821115612def576000612f508282612d6e565b50600101612f3c565b5080546000825590600052602060002090810190610a639190612f3c565b600060208284031215612f8957600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610f0457600080fd5b6000815180845260005b81811015612fdf57602081850181015186830182015201612fc3565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610f046020830184612fb9565b63ffffffff81168114610a6357600080fd5b803561304d81613030565b919050565b80356002811061304d57600080fd5b6000806040838503121561307457600080fd5b823561307f81613030565b915061308d60208401613052565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600281106130d5576130d5613096565b9052565b60008151808452602080850194506020840160005b8381101561310a578151875295820195908201906001016130ee565b509495945050505050565b60008282518085526020808601955060208260051b8401016020860160005b84811015613180577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086840301895261316e838351612fb9565b98840198925090830190600101613134565b5090979650505050505050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b8381101561335c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08984030185528151606081518186526131fb82870182516130c5565b8981015160806132168189018367ffffffffffffffff169052565b8a830151915060a061322c818a018460ff169052565b938301519360c0925061324a8984018667ffffffffffffffff169052565b818401519450610140915060e082818b015261326a6101a08b0187612fb9565b95508185015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0610100818c890301818d01526132a988856130d9565b97508587015195506101209350818c890301848d01526132c988876130d9565b9750828701519550818c890301858d01526132e48887613115565b975080870151955050808b8803016101608c01526133028786613115565b9650828601519550808b8803016101808c015250505050506133248282612fb9565b915050888201516133408a87018267ffffffffffffffff169052565b50908701519387019390935293860193908601906001016131b6565b509098975050505050505050565b60006020828403121561337c57600080fd5b8135610f0481613030565b600081516060845261339c60608501826130d9565b905060ff6020840151166020850152604083015184820360408601526133c28282612fb9565b95945050505050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b8381101561335c578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00185528151805167ffffffffffffffff16845287015187840187905261344887850182613387565b95880195935050908601906001016133f4565b60006020828403121561346d57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610f0457600080fd5b60008083601f8401126134a357600080fd5b50813567ffffffffffffffff8111156134bb57600080fd5b6020830191508360208260051b85010111156134d657600080fd5b9250929050565b600080600080604085870312156134f357600080fd5b843567ffffffffffffffff8082111561350b57600080fd5b61351788838901613491565b9096509450602087013591508082111561353057600080fd5b5061353d87828801613491565b95989497509550505050565b803567ffffffffffffffff8116811461304d57600080fd5b6000806000806000806080878903121561357a57600080fd5b863567ffffffffffffffff8082111561359257600080fd5b61359e8a838b01613491565b909850965060208901359150808211156135b757600080fd5b818901915089601f8301126135cb57600080fd5b8135818111156135da57600080fd5b8a60208285010111156135ec57600080fd5b60208301965080955050505061360460408801613549565b915061361260608801613042565b90509295509295509295565b600181811c9082168061363257607f821691505b60208210810361366b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156136e157600080fd5b610f0482613549565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261371e57600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261371e57600080fd5b604051610140810167ffffffffffffffff8111828210171561378057613780613671565b60405290565b60405160e0810167ffffffffffffffff8111828210171561378057613780613671565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156137f0576137f0613671565b604052919050565b600067ffffffffffffffff82111561381257613812613671565b5060051b60200190565b600082601f83011261382d57600080fd5b8135602061384261383d836137f8565b6137a9565b8083825260208201915060208460051b87010193508684111561386457600080fd5b602086015b848110156138805780358352918301918301613869565b509695505050505050565b803560ff8116811461304d57600080fd5b600082601f8301126138ad57600080fd5b813567ffffffffffffffff8111156138c7576138c7613671565b6138f860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016137a9565b81815284602083860101111561390d57600080fd5b816020850160208301376000918101602001919091529392505050565b60006060823603121561393c57600080fd5b6040516060810167ffffffffffffffff828210818311171561396057613960613671565b81604052843591508082111561397557600080fd5b6139813683870161381c565b835261398f6020860161388b565b602084015260408501359150808211156139a857600080fd5b506139b53682860161389c565b60408301525092915050565b601f821115612a28576000816000526020600020601f850160051c810160208610156139ea5750805b601f850160051c820191505b81811015613a09578281556001016139f6565b505050505050565b815167ffffffffffffffff811115613a2b57613a2b613671565b613a3f81613a39845461361e565b846139c1565b602080601f831160018114613a925760008415613a5c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613a09565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015613adf57888601518255948401946001909101908401613ac0565b5085821015613b1b57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b67ffffffffffffffff83168152604060208201526000613b4e6040830184613387565b949350505050565b600082601f830112613b6757600080fd5b81356020613b7761383d836137f8565b82815260059290921b84018101918181019086841115613b9657600080fd5b8286015b8481101561388057803567ffffffffffffffff811115613bba5760008081fd5b613bc88986838b010161389c565b845250918301918301613b9a565b60006020808385031215613be957600080fd5b823567ffffffffffffffff80821115613c0157600080fd5b818501915085601f830112613c1557600080fd5b8135613c2361383d826137f8565b81815260059190911b83018401908481019088831115613c4257600080fd5b8585015b83811015613dd057803585811115613c5d57600080fd5b8601610140818c037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011215613c9257600080fd5b613c9a61375c565b613ca5898301613052565b8152613cb360408301613549565b89820152613cc36060830161388b565b6040820152613cd460808301613549565b606082015260a082013587811115613ceb57600080fd5b613cf98d8b8386010161389c565b60808301525060c082013587811115613d1157600080fd5b613d1f8d8b8386010161381c565b60a08301525060e082013587811115613d3757600080fd5b613d458d8b8386010161381c565b60c0830152506101008083013588811115613d5f57600080fd5b613d6d8e8c83870101613b56565b60e0840152506101208084013589811115613d8757600080fd5b613d958f8d83880101613b56565b8385015250610140840135915088821115613daf57600080fd5b613dbd8e8c8487010161389c565b9083015250845250918601918601613c46565b5098975050505050505050565b805161304d81613030565b600082601f830112613df957600080fd5b81516020613e0961383d836137f8565b8083825260208201915060208460051b870101935086841115613e2b57600080fd5b602086015b848110156138805780518352918301918301613e30565b600060208284031215613e5957600080fd5b815167ffffffffffffffff80821115613e7157600080fd5b9083019060e08286031215613e8557600080fd5b613e8d613786565b613e9683613ddd565b8152613ea460208401613ddd565b6020820152613eb560408401613ddd565b6040820152606083015160608201526080830151608082015260a083015182811115613ee057600080fd5b613eec87828601613de8565b60a08301525060c083015182811115613f0457600080fd5b613f1087828601613de8565b60c08301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613f7f57613f7f613f1f565b5060010190565b8181038181111561028857610288613f1f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b8181036000831280158383131683831282161715610a4b57610a4b613f1f565b600381106130d5576130d5613096565b604081016140068285613fe8565b610f046020830184613fe8565b67ffffffffffffffff818116838216019080821115610a4b57610a4b613f1f565b60ff8181168382160290811690818114610a4b57610a4b613f1f565b60ff818116838216019081111561028857610288613f1f565b60008282518085526020808601955060208260051b8401016020860160005b84811015613180577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08684030189526140c2838351612fb9565b98840198925090830190600101614088565b67ffffffffffffffff8d16815263ffffffff8c1660208201526140fa604082018c6130c5565b6101806060820152600061411261018083018c612fb9565b67ffffffffffffffff8b16608084015282810360a0840152614134818b6130d9565b905082810360c0840152614148818a6130d9565b905082810360e084015261415c8189614069565b90508281036101008401526141718188614069565b60ff8716610120850152905067ffffffffffffffff85166101408401528281036101608401526141a18185612fb9565b9f9e505050505050505050505050505050565b6040815260006141c760408301856130d9565b82810360208401526133c281856130d9565b602081526000610f0460208301846130d956fea164736f6c6343000818000a",
+}
+
+var CCIPConfigABI = CCIPConfigMetaData.ABI
+
+var CCIPConfigBin = CCIPConfigMetaData.Bin
+
+func DeployCCIPConfig(auth *bind.TransactOpts, backend bind.ContractBackend, capabilitiesRegistry common.Address) (common.Address, *types.Transaction, *CCIPConfig, error) {
+ parsed, err := CCIPConfigMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CCIPConfigBin), backend, capabilitiesRegistry)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &CCIPConfig{address: address, abi: *parsed, CCIPConfigCaller: CCIPConfigCaller{contract: contract}, CCIPConfigTransactor: CCIPConfigTransactor{contract: contract}, CCIPConfigFilterer: CCIPConfigFilterer{contract: contract}}, nil
+}
+
+type CCIPConfig struct {
+ address common.Address
+ abi abi.ABI
+ CCIPConfigCaller
+ CCIPConfigTransactor
+ CCIPConfigFilterer
+}
+
+type CCIPConfigCaller struct {
+ contract *bind.BoundContract
+}
+
+type CCIPConfigTransactor struct {
+ contract *bind.BoundContract
+}
+
+type CCIPConfigFilterer struct {
+ contract *bind.BoundContract
+}
+
+type CCIPConfigSession struct {
+ Contract *CCIPConfig
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type CCIPConfigCallerSession struct {
+ Contract *CCIPConfigCaller
+ CallOpts bind.CallOpts
+}
+
+type CCIPConfigTransactorSession struct {
+ Contract *CCIPConfigTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type CCIPConfigRaw struct {
+ Contract *CCIPConfig
+}
+
+type CCIPConfigCallerRaw struct {
+ Contract *CCIPConfigCaller
+}
+
+type CCIPConfigTransactorRaw struct {
+ Contract *CCIPConfigTransactor
+}
+
+func NewCCIPConfig(address common.Address, backend bind.ContractBackend) (*CCIPConfig, error) {
+ abi, err := abi.JSON(strings.NewReader(CCIPConfigABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindCCIPConfig(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfig{address: address, abi: abi, CCIPConfigCaller: CCIPConfigCaller{contract: contract}, CCIPConfigTransactor: CCIPConfigTransactor{contract: contract}, CCIPConfigFilterer: CCIPConfigFilterer{contract: contract}}, nil
+}
+
+func NewCCIPConfigCaller(address common.Address, caller bind.ContractCaller) (*CCIPConfigCaller, error) {
+ contract, err := bindCCIPConfig(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfigCaller{contract: contract}, nil
+}
+
+func NewCCIPConfigTransactor(address common.Address, transactor bind.ContractTransactor) (*CCIPConfigTransactor, error) {
+ contract, err := bindCCIPConfig(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfigTransactor{contract: contract}, nil
+}
+
+func NewCCIPConfigFilterer(address common.Address, filterer bind.ContractFilterer) (*CCIPConfigFilterer, error) {
+ contract, err := bindCCIPConfig(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfigFilterer{contract: contract}, nil
+}
+
+func bindCCIPConfig(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := CCIPConfigMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_CCIPConfig *CCIPConfigRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CCIPConfig.Contract.CCIPConfigCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_CCIPConfig *CCIPConfigRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.CCIPConfigTransactor.contract.Transfer(opts)
+}
+
+func (_CCIPConfig *CCIPConfigRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.CCIPConfigTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_CCIPConfig *CCIPConfigCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CCIPConfig.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_CCIPConfig *CCIPConfigTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.contract.Transfer(opts)
+}
+
+func (_CCIPConfig *CCIPConfigTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_CCIPConfig *CCIPConfigCaller) GetAllChainConfigs(opts *bind.CallOpts) ([]CCIPConfigTypesChainConfigInfo, error) {
+ var out []interface{}
+ err := _CCIPConfig.contract.Call(opts, &out, "getAllChainConfigs")
+
+ if err != nil {
+ return *new([]CCIPConfigTypesChainConfigInfo), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]CCIPConfigTypesChainConfigInfo)).(*[]CCIPConfigTypesChainConfigInfo)
+
+ return out0, err
+
+}
+
+func (_CCIPConfig *CCIPConfigSession) GetAllChainConfigs() ([]CCIPConfigTypesChainConfigInfo, error) {
+ return _CCIPConfig.Contract.GetAllChainConfigs(&_CCIPConfig.CallOpts)
+}
+
+func (_CCIPConfig *CCIPConfigCallerSession) GetAllChainConfigs() ([]CCIPConfigTypesChainConfigInfo, error) {
+ return _CCIPConfig.Contract.GetAllChainConfigs(&_CCIPConfig.CallOpts)
+}
+
+func (_CCIPConfig *CCIPConfigCaller) GetCapabilityConfiguration(opts *bind.CallOpts, arg0 uint32) ([]byte, error) {
+ var out []interface{}
+ err := _CCIPConfig.contract.Call(opts, &out, "getCapabilityConfiguration", arg0)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_CCIPConfig *CCIPConfigSession) GetCapabilityConfiguration(arg0 uint32) ([]byte, error) {
+ return _CCIPConfig.Contract.GetCapabilityConfiguration(&_CCIPConfig.CallOpts, arg0)
+}
+
+func (_CCIPConfig *CCIPConfigCallerSession) GetCapabilityConfiguration(arg0 uint32) ([]byte, error) {
+ return _CCIPConfig.Contract.GetCapabilityConfiguration(&_CCIPConfig.CallOpts, arg0)
+}
+
+func (_CCIPConfig *CCIPConfigCaller) GetOCRConfig(opts *bind.CallOpts, donId uint32, pluginType uint8) ([]CCIPConfigTypesOCR3ConfigWithMeta, error) {
+ var out []interface{}
+ err := _CCIPConfig.contract.Call(opts, &out, "getOCRConfig", donId, pluginType)
+
+ if err != nil {
+ return *new([]CCIPConfigTypesOCR3ConfigWithMeta), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]CCIPConfigTypesOCR3ConfigWithMeta)).(*[]CCIPConfigTypesOCR3ConfigWithMeta)
+
+ return out0, err
+
+}
+
+func (_CCIPConfig *CCIPConfigSession) GetOCRConfig(donId uint32, pluginType uint8) ([]CCIPConfigTypesOCR3ConfigWithMeta, error) {
+ return _CCIPConfig.Contract.GetOCRConfig(&_CCIPConfig.CallOpts, donId, pluginType)
+}
+
+func (_CCIPConfig *CCIPConfigCallerSession) GetOCRConfig(donId uint32, pluginType uint8) ([]CCIPConfigTypesOCR3ConfigWithMeta, error) {
+ return _CCIPConfig.Contract.GetOCRConfig(&_CCIPConfig.CallOpts, donId, pluginType)
+}
+
+func (_CCIPConfig *CCIPConfigCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _CCIPConfig.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_CCIPConfig *CCIPConfigSession) Owner() (common.Address, error) {
+ return _CCIPConfig.Contract.Owner(&_CCIPConfig.CallOpts)
+}
+
+func (_CCIPConfig *CCIPConfigCallerSession) Owner() (common.Address, error) {
+ return _CCIPConfig.Contract.Owner(&_CCIPConfig.CallOpts)
+}
+
+func (_CCIPConfig *CCIPConfigCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _CCIPConfig.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CCIPConfig *CCIPConfigSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _CCIPConfig.Contract.SupportsInterface(&_CCIPConfig.CallOpts, interfaceId)
+}
+
+func (_CCIPConfig *CCIPConfigCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _CCIPConfig.Contract.SupportsInterface(&_CCIPConfig.CallOpts, interfaceId)
+}
+
+func (_CCIPConfig *CCIPConfigCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _CCIPConfig.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_CCIPConfig *CCIPConfigSession) TypeAndVersion() (string, error) {
+ return _CCIPConfig.Contract.TypeAndVersion(&_CCIPConfig.CallOpts)
+}
+
+func (_CCIPConfig *CCIPConfigCallerSession) TypeAndVersion() (string, error) {
+ return _CCIPConfig.Contract.TypeAndVersion(&_CCIPConfig.CallOpts)
+}
+
+func (_CCIPConfig *CCIPConfigTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CCIPConfig.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_CCIPConfig *CCIPConfigSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CCIPConfig.Contract.AcceptOwnership(&_CCIPConfig.TransactOpts)
+}
+
+func (_CCIPConfig *CCIPConfigTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CCIPConfig.Contract.AcceptOwnership(&_CCIPConfig.TransactOpts)
+}
+
+func (_CCIPConfig *CCIPConfigTransactor) ApplyChainConfigUpdates(opts *bind.TransactOpts, chainSelectorRemoves []uint64, chainConfigAdds []CCIPConfigTypesChainConfigInfo) (*types.Transaction, error) {
+ return _CCIPConfig.contract.Transact(opts, "applyChainConfigUpdates", chainSelectorRemoves, chainConfigAdds)
+}
+
+func (_CCIPConfig *CCIPConfigSession) ApplyChainConfigUpdates(chainSelectorRemoves []uint64, chainConfigAdds []CCIPConfigTypesChainConfigInfo) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.ApplyChainConfigUpdates(&_CCIPConfig.TransactOpts, chainSelectorRemoves, chainConfigAdds)
+}
+
+func (_CCIPConfig *CCIPConfigTransactorSession) ApplyChainConfigUpdates(chainSelectorRemoves []uint64, chainConfigAdds []CCIPConfigTypesChainConfigInfo) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.ApplyChainConfigUpdates(&_CCIPConfig.TransactOpts, chainSelectorRemoves, chainConfigAdds)
+}
+
+func (_CCIPConfig *CCIPConfigTransactor) BeforeCapabilityConfigSet(opts *bind.TransactOpts, arg0 [][32]byte, config []byte, arg2 uint64, donId uint32) (*types.Transaction, error) {
+ return _CCIPConfig.contract.Transact(opts, "beforeCapabilityConfigSet", arg0, config, arg2, donId)
+}
+
+func (_CCIPConfig *CCIPConfigSession) BeforeCapabilityConfigSet(arg0 [][32]byte, config []byte, arg2 uint64, donId uint32) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.BeforeCapabilityConfigSet(&_CCIPConfig.TransactOpts, arg0, config, arg2, donId)
+}
+
+func (_CCIPConfig *CCIPConfigTransactorSession) BeforeCapabilityConfigSet(arg0 [][32]byte, config []byte, arg2 uint64, donId uint32) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.BeforeCapabilityConfigSet(&_CCIPConfig.TransactOpts, arg0, config, arg2, donId)
+}
+
+func (_CCIPConfig *CCIPConfigTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _CCIPConfig.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_CCIPConfig *CCIPConfigSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.TransferOwnership(&_CCIPConfig.TransactOpts, to)
+}
+
+func (_CCIPConfig *CCIPConfigTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CCIPConfig.Contract.TransferOwnership(&_CCIPConfig.TransactOpts, to)
+}
+
+type CCIPConfigCapabilityConfigurationSetIterator struct {
+ Event *CCIPConfigCapabilityConfigurationSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CCIPConfigCapabilityConfigurationSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CCIPConfigCapabilityConfigurationSet)
+ 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(CCIPConfigCapabilityConfigurationSet)
+ 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 *CCIPConfigCapabilityConfigurationSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CCIPConfigCapabilityConfigurationSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CCIPConfigCapabilityConfigurationSet struct {
+ Raw types.Log
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) FilterCapabilityConfigurationSet(opts *bind.FilterOpts) (*CCIPConfigCapabilityConfigurationSetIterator, error) {
+
+ logs, sub, err := _CCIPConfig.contract.FilterLogs(opts, "CapabilityConfigurationSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfigCapabilityConfigurationSetIterator{contract: _CCIPConfig.contract, event: "CapabilityConfigurationSet", logs: logs, sub: sub}, nil
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) WatchCapabilityConfigurationSet(opts *bind.WatchOpts, sink chan<- *CCIPConfigCapabilityConfigurationSet) (event.Subscription, error) {
+
+ logs, sub, err := _CCIPConfig.contract.WatchLogs(opts, "CapabilityConfigurationSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CCIPConfigCapabilityConfigurationSet)
+ if err := _CCIPConfig.contract.UnpackLog(event, "CapabilityConfigurationSet", 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 (_CCIPConfig *CCIPConfigFilterer) ParseCapabilityConfigurationSet(log types.Log) (*CCIPConfigCapabilityConfigurationSet, error) {
+ event := new(CCIPConfigCapabilityConfigurationSet)
+ if err := _CCIPConfig.contract.UnpackLog(event, "CapabilityConfigurationSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CCIPConfigChainConfigRemovedIterator struct {
+ Event *CCIPConfigChainConfigRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CCIPConfigChainConfigRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CCIPConfigChainConfigRemoved)
+ 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(CCIPConfigChainConfigRemoved)
+ 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 *CCIPConfigChainConfigRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CCIPConfigChainConfigRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CCIPConfigChainConfigRemoved struct {
+ ChainSelector uint64
+ Raw types.Log
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) FilterChainConfigRemoved(opts *bind.FilterOpts) (*CCIPConfigChainConfigRemovedIterator, error) {
+
+ logs, sub, err := _CCIPConfig.contract.FilterLogs(opts, "ChainConfigRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfigChainConfigRemovedIterator{contract: _CCIPConfig.contract, event: "ChainConfigRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) WatchChainConfigRemoved(opts *bind.WatchOpts, sink chan<- *CCIPConfigChainConfigRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _CCIPConfig.contract.WatchLogs(opts, "ChainConfigRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CCIPConfigChainConfigRemoved)
+ if err := _CCIPConfig.contract.UnpackLog(event, "ChainConfigRemoved", 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 (_CCIPConfig *CCIPConfigFilterer) ParseChainConfigRemoved(log types.Log) (*CCIPConfigChainConfigRemoved, error) {
+ event := new(CCIPConfigChainConfigRemoved)
+ if err := _CCIPConfig.contract.UnpackLog(event, "ChainConfigRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CCIPConfigChainConfigSetIterator struct {
+ Event *CCIPConfigChainConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CCIPConfigChainConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CCIPConfigChainConfigSet)
+ 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(CCIPConfigChainConfigSet)
+ 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 *CCIPConfigChainConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CCIPConfigChainConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CCIPConfigChainConfigSet struct {
+ ChainSelector uint64
+ ChainConfig CCIPConfigTypesChainConfig
+ Raw types.Log
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) FilterChainConfigSet(opts *bind.FilterOpts) (*CCIPConfigChainConfigSetIterator, error) {
+
+ logs, sub, err := _CCIPConfig.contract.FilterLogs(opts, "ChainConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfigChainConfigSetIterator{contract: _CCIPConfig.contract, event: "ChainConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) WatchChainConfigSet(opts *bind.WatchOpts, sink chan<- *CCIPConfigChainConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _CCIPConfig.contract.WatchLogs(opts, "ChainConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CCIPConfigChainConfigSet)
+ if err := _CCIPConfig.contract.UnpackLog(event, "ChainConfigSet", 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 (_CCIPConfig *CCIPConfigFilterer) ParseChainConfigSet(log types.Log) (*CCIPConfigChainConfigSet, error) {
+ event := new(CCIPConfigChainConfigSet)
+ if err := _CCIPConfig.contract.UnpackLog(event, "ChainConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CCIPConfigOwnershipTransferRequestedIterator struct {
+ Event *CCIPConfigOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CCIPConfigOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CCIPConfigOwnershipTransferRequested)
+ 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(CCIPConfigOwnershipTransferRequested)
+ 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 *CCIPConfigOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CCIPConfigOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CCIPConfigOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CCIPConfigOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CCIPConfig.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfigOwnershipTransferRequestedIterator{contract: _CCIPConfig.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CCIPConfigOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CCIPConfig.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CCIPConfigOwnershipTransferRequested)
+ if err := _CCIPConfig.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_CCIPConfig *CCIPConfigFilterer) ParseOwnershipTransferRequested(log types.Log) (*CCIPConfigOwnershipTransferRequested, error) {
+ event := new(CCIPConfigOwnershipTransferRequested)
+ if err := _CCIPConfig.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CCIPConfigOwnershipTransferredIterator struct {
+ Event *CCIPConfigOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CCIPConfigOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CCIPConfigOwnershipTransferred)
+ 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(CCIPConfigOwnershipTransferred)
+ 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 *CCIPConfigOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *CCIPConfigOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CCIPConfigOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CCIPConfigOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CCIPConfig.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPConfigOwnershipTransferredIterator{contract: _CCIPConfig.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_CCIPConfig *CCIPConfigFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CCIPConfigOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CCIPConfig.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CCIPConfigOwnershipTransferred)
+ if err := _CCIPConfig.contract.UnpackLog(event, "OwnershipTransferred", 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 (_CCIPConfig *CCIPConfigFilterer) ParseOwnershipTransferred(log types.Log) (*CCIPConfigOwnershipTransferred, error) {
+ event := new(CCIPConfigOwnershipTransferred)
+ if err := _CCIPConfig.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_CCIPConfig *CCIPConfig) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _CCIPConfig.abi.Events["CapabilityConfigurationSet"].ID:
+ return _CCIPConfig.ParseCapabilityConfigurationSet(log)
+ case _CCIPConfig.abi.Events["ChainConfigRemoved"].ID:
+ return _CCIPConfig.ParseChainConfigRemoved(log)
+ case _CCIPConfig.abi.Events["ChainConfigSet"].ID:
+ return _CCIPConfig.ParseChainConfigSet(log)
+ case _CCIPConfig.abi.Events["OwnershipTransferRequested"].ID:
+ return _CCIPConfig.ParseOwnershipTransferRequested(log)
+ case _CCIPConfig.abi.Events["OwnershipTransferred"].ID:
+ return _CCIPConfig.ParseOwnershipTransferred(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (CCIPConfigCapabilityConfigurationSet) Topic() common.Hash {
+ return common.HexToHash("0x84ad7751b744c9e2ee77da1d902b428aec7f0a343d67a24bbe2142e6f58a8d0f")
+}
+
+func (CCIPConfigChainConfigRemoved) Topic() common.Hash {
+ return common.HexToHash("0x2a680691fef3b2d105196805935232c661ce703e92d464ef0b94a7bc62d714f0")
+}
+
+func (CCIPConfigChainConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x05dd57854af2c291a94ea52e7c43d80bc3be7fa73022f98b735dea86642fa5e0")
+}
+
+func (CCIPConfigOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (CCIPConfigOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (_CCIPConfig *CCIPConfig) Address() common.Address {
+ return _CCIPConfig.address
+}
+
+type CCIPConfigInterface interface {
+ GetAllChainConfigs(opts *bind.CallOpts) ([]CCIPConfigTypesChainConfigInfo, error)
+
+ GetCapabilityConfiguration(opts *bind.CallOpts, arg0 uint32) ([]byte, error)
+
+ GetOCRConfig(opts *bind.CallOpts, donId uint32, pluginType uint8) ([]CCIPConfigTypesOCR3ConfigWithMeta, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyChainConfigUpdates(opts *bind.TransactOpts, chainSelectorRemoves []uint64, chainConfigAdds []CCIPConfigTypesChainConfigInfo) (*types.Transaction, error)
+
+ BeforeCapabilityConfigSet(opts *bind.TransactOpts, arg0 [][32]byte, config []byte, arg2 uint64, donId uint32) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterCapabilityConfigurationSet(opts *bind.FilterOpts) (*CCIPConfigCapabilityConfigurationSetIterator, error)
+
+ WatchCapabilityConfigurationSet(opts *bind.WatchOpts, sink chan<- *CCIPConfigCapabilityConfigurationSet) (event.Subscription, error)
+
+ ParseCapabilityConfigurationSet(log types.Log) (*CCIPConfigCapabilityConfigurationSet, error)
+
+ FilterChainConfigRemoved(opts *bind.FilterOpts) (*CCIPConfigChainConfigRemovedIterator, error)
+
+ WatchChainConfigRemoved(opts *bind.WatchOpts, sink chan<- *CCIPConfigChainConfigRemoved) (event.Subscription, error)
+
+ ParseChainConfigRemoved(log types.Log) (*CCIPConfigChainConfigRemoved, error)
+
+ FilterChainConfigSet(opts *bind.FilterOpts) (*CCIPConfigChainConfigSetIterator, error)
+
+ WatchChainConfigSet(opts *bind.WatchOpts, sink chan<- *CCIPConfigChainConfigSet) (event.Subscription, error)
+
+ ParseChainConfigSet(log types.Log) (*CCIPConfigChainConfigSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CCIPConfigOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CCIPConfigOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*CCIPConfigOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CCIPConfigOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CCIPConfigOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*CCIPConfigOwnershipTransferred, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/ccip_reader_tester/ccip_reader_tester.go b/core/gethwrappers/ccip/generated/ccip_reader_tester/ccip_reader_tester.go
new file mode 100644
index 00000000000..fdef1385280
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/ccip_reader_tester/ccip_reader_tester.go
@@ -0,0 +1,761 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package ccip_reader_tester
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type EVM2EVMMultiOffRampCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ MerkleRoots []EVM2EVMMultiOffRampMerkleRoot
+}
+
+type EVM2EVMMultiOffRampInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type EVM2EVMMultiOffRampMerkleRoot struct {
+ SourceChainSelector uint64
+ Interval EVM2EVMMultiOffRampInterval
+ MerkleRoot [32]byte
+}
+
+type EVM2EVMMultiOffRampSourceChainConfig struct {
+ IsEnabled bool
+ MinSeqNr uint64
+ OnRamp []byte
+}
+
+type InternalEVM2AnyRampMessage struct {
+ Header InternalRampMessageHeader
+ Sender common.Address
+ Data []byte
+ Receiver []byte
+ ExtraArgs []byte
+ FeeToken common.Address
+ FeeTokenAmount *big.Int
+ TokenAmounts []InternalRampTokenAmount
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalRampMessageHeader struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ DestChainSelector uint64
+ SequenceNumber uint64
+ Nonce uint64
+}
+
+type InternalRampTokenAmount struct {
+ SourcePoolAddress []byte
+ DestTokenAddress []byte
+ ExtraData []byte
+ Amount *big.Int
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var CCIPReaderTesterMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"structInternal.EVM2AnyRampMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"CCIPSendRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.MerkleRoot[]\",\"name\":\"merkleRoots\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMMultiOffRamp.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"CommitReportAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"state\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"name\":\"ExecutionStateChanged\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.EVM2AnyRampMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"emitCCIPSendRequested\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.MerkleRoot[]\",\"name\":\"merkleRoots\",\"type\":\"tuple[]\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"emitCommitReportAccepted\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"state\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"name\":\"emitExecutionStateChanged\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"getSourceChainConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.SourceChainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.SourceChainConfig\",\"name\":\"sourceChainConfig\",\"type\":\"tuple\"}],\"name\":\"setSourceChainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b506110cc806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80634cf66e361461005c578063a65558f614610071578063e44302b714610084578063e9d68a8e14610097578063f831af81146100c0575b600080fd5b61006f61006a366004610462565b6100d3565b005b61006f61007f3660046106c7565b610128565b61006f610092366004610965565b61016d565b6100aa6100a5366004610acd565b6101a7565b6040516100b79190610b35565b60405180910390f35b61006f6100ce366004610b76565b610297565b82846001600160401b0316866001600160401b03167f8c324ce1367b83031769f6a813e3bb4c117aba2185789d66b98b791405be6df28585604051610119929190610c1e565b60405180910390a45050505050565b816001600160401b03167f0f07cd31e53232da9125e517f09550fdde74bf43d6a0a76ebd41674dafe2ab29826040516101619190610d06565b60405180910390a25050565b7f3a3950e13dd607cc37980db0ef14266c40d2bba9c01b2e44bfe549808883095d8160405161019c9190610ec0565b60405180910390a150565b6040805160608082018352600080835260208084018290528385018390526001600160401b0386811683528282529185902085519384018652805460ff81161515855261010090049092169083015260018101805493949293919284019161020e90610f75565b80601f016020809104026020016040519081016040528092919081815260200182805461023a90610f75565b80156102875780601f1061025c57610100808354040283529160200191610287565b820191906000526020600020905b81548152906001019060200180831161026a57829003601f168201915b5050505050815250509050919050565b6001600160401b038281166000908152602081815260409182902084518154928601516001600160481b0319909316901515610100600160481b03191617610100929094169190910292909217825582015182919060018201906102fb9082611000565b5050505050565b80356001600160401b038116811461031957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156103565761035661031e565b60405290565b60405161010081016001600160401b03811182821017156103565761035661031e565b604080519081016001600160401b03811182821017156103565761035661031e565b604051606081016001600160401b03811182821017156103565761035661031e565b604051601f8201601f191681016001600160401b03811182821017156103eb576103eb61031e565b604052919050565b600082601f83011261040457600080fd5b81356001600160401b0381111561041d5761041d61031e565b610430601f8201601f19166020016103c3565b81815284602083860101111561044557600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a0868803121561047a57600080fd5b61048386610302565b945061049160208701610302565b9350604086013592506060860135600481106104ac57600080fd5b915060808601356001600160401b038111156104c757600080fd5b6104d3888289016103f3565b9150509295509295909350565b600060a082840312156104f257600080fd5b60405160a081016001600160401b03811182821017156105145761051461031e565b6040528235815290508061052a60208401610302565b602082015261053b60408401610302565b604082015261054c60608401610302565b606082015261055d60808401610302565b60808201525092915050565b80356001600160a01b038116811461031957600080fd5b60006001600160401b038211156105995761059961031e565b5060051b60200190565b600082601f8301126105b457600080fd5b813560206105c96105c483610580565b6103c3565b82815260059290921b840181019181810190868411156105e857600080fd5b8286015b848110156106bc5780356001600160401b038082111561060c5760008081fd5b908801906080828b03601f19018113156106265760008081fd5b61062e610334565b87840135838111156106405760008081fd5b61064e8d8a838801016103f3565b825250604080850135848111156106655760008081fd5b6106738e8b838901016103f3565b8a840152506060808601358581111561068c5760008081fd5b61069a8f8c838a01016103f3565b92840192909252949092013593810193909352505083529183019183016105ec565b509695505050505050565b600080604083850312156106da57600080fd5b6106e383610302565b915060208301356001600160401b03808211156106ff57600080fd5b90840190610180828703121561071457600080fd5b61071c61035c565b61072687846104e0565b815261073460a08401610569565b602082015260c08301358281111561074b57600080fd5b610757888286016103f3565b60408301525060e08301358281111561076f57600080fd5b61077b888286016103f3565b6060830152506101008301358281111561079457600080fd5b6107a0888286016103f3565b6080830152506107b36101208401610569565b60a082015261014083013560c0820152610160830135828111156107d657600080fd5b6107e2888286016105a3565b60e0830152508093505050509250929050565b80356001600160e01b038116811461031957600080fd5b600082601f83011261081d57600080fd5b8135602061082d6105c483610580565b82815260069290921b8401810191818101908684111561084c57600080fd5b8286015b848110156106bc57604081890312156108695760008081fd5b61087161037f565b61087a82610302565b81526108878583016107f5565b81860152835291830191604001610850565b600082601f8301126108aa57600080fd5b813560206108ba6105c483610580565b82815260079290921b840181019181810190868411156108d957600080fd5b8286015b848110156106bc5780880360808112156108f75760008081fd5b6108ff6103a1565b61090883610302565b8152604080601f198401121561091e5760008081fd5b61092661037f565b9250610933878501610302565b8352610940818501610302565b83880152818701929092526060830135918101919091528352918301916080016108dd565b6000602080838503121561097857600080fd5b82356001600160401b038082111561098f57600080fd5b818501915060408083880312156109a557600080fd5b6109ad61037f565b8335838111156109bc57600080fd5b84016040818a0312156109ce57600080fd5b6109d661037f565b8135858111156109e557600080fd5b8201601f81018b136109f657600080fd5b8035610a046105c482610580565b81815260069190911b8201890190898101908d831115610a2357600080fd5b928a01925b82841015610a715787848f031215610a405760008081fd5b610a4861037f565b610a5185610569565b8152610a5e8c86016107f5565b818d0152825292870192908a0190610a28565b845250505081870135935084841115610a8957600080fd5b610a958a85840161080c565b8188015282525083850135915082821115610aaf57600080fd5b610abb88838601610899565b85820152809550505050505092915050565b600060208284031215610adf57600080fd5b610ae882610302565b9392505050565b6000815180845260005b81811015610b1557602081850181015186830182015201610af9565b506000602082860101526020601f19601f83011685010191505092915050565b6020815281511515602082015260018060401b03602083015116604082015260006040830151606080840152610b6e6080840182610aef565b949350505050565b60008060408385031215610b8957600080fd5b610b9283610302565b915060208301356001600160401b0380821115610bae57600080fd5b9084019060608287031215610bc257600080fd5b610bca6103a1565b82358015158114610bda57600080fd5b8152610be860208401610302565b6020820152604083013582811115610bff57600080fd5b610c0b888286016103f3565b6040830152508093505050509250929050565b600060048410610c3e57634e487b7160e01b600052602160045260246000fd5b83825260406020830152610b6e6040830184610aef565b6001600160a01b03169052565b600082825180855260208086019550808260051b84010181860160005b84811015610cf957601f19868403018952815160808151818652610ca582870182610aef565b9150508582015185820387870152610cbd8282610aef565b91505060408083015186830382880152610cd78382610aef565b6060948501519790940196909652505098840198925090830190600101610c7f565b5090979650505050505050565b60208152610d53602082018351805182526020808201516001600160401b039081169184019190915260408083015182169084015260608083015182169084015260809182015116910152565b60006020830151610d6760c0840182610c55565b5060408301516101808060e0850152610d846101a0850183610aef565b91506060850151601f198086850301610100870152610da38483610aef565b9350608087015191508086850301610120870152610dc18483610aef565b935060a08701519150610dd8610140870183610c55565b60c087015161016087015260e0870151915080868503018387015250610dfe8382610c62565b9695505050505050565b60008151808452602080850194506020840160005b83811015610e5657815180516001600160401b031688528301516001600160e01b03168388015260409096019590820190600101610e1d565b509495945050505050565b600081518084526020808501945080840160005b83811015610e5657815180516001600160401b0390811689528482015180518216868b0152850151166040898101919091520151606088015260809096019590820190600101610e75565b6000602080835283516040808386015260a0850182516040606088015281815180845260c0890191508683019350600092505b80831015610f2e57835180516001600160a01b031683528701516001600160e01b031687830152928601926001929092019190840190610ef3565b5093850151878503605f1901608089015293610f4a8186610e08565b945050505050818501519150601f19848203016040850152610f6c8183610e61565b95945050505050565b600181811c90821680610f8957607f821691505b602082108103610fa957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610ffb576000816000526020600020601f850160051c81016020861015610fd85750805b601f850160051c820191505b81811015610ff757828155600101610fe4565b5050505b505050565b81516001600160401b038111156110195761101961031e565b61102d816110278454610f75565b84610faf565b602080601f831160018114611062576000841561104a5750858301515b600019600386901b1c1916600185901b178555610ff7565b600085815260208120601f198616915b8281101561109157888601518255948401946001909101908401611072565b50858210156110af5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c6343000818000a",
+}
+
+var CCIPReaderTesterABI = CCIPReaderTesterMetaData.ABI
+
+var CCIPReaderTesterBin = CCIPReaderTesterMetaData.Bin
+
+func DeployCCIPReaderTester(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *CCIPReaderTester, error) {
+ parsed, err := CCIPReaderTesterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CCIPReaderTesterBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &CCIPReaderTester{address: address, abi: *parsed, CCIPReaderTesterCaller: CCIPReaderTesterCaller{contract: contract}, CCIPReaderTesterTransactor: CCIPReaderTesterTransactor{contract: contract}, CCIPReaderTesterFilterer: CCIPReaderTesterFilterer{contract: contract}}, nil
+}
+
+type CCIPReaderTester struct {
+ address common.Address
+ abi abi.ABI
+ CCIPReaderTesterCaller
+ CCIPReaderTesterTransactor
+ CCIPReaderTesterFilterer
+}
+
+type CCIPReaderTesterCaller struct {
+ contract *bind.BoundContract
+}
+
+type CCIPReaderTesterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type CCIPReaderTesterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type CCIPReaderTesterSession struct {
+ Contract *CCIPReaderTester
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type CCIPReaderTesterCallerSession struct {
+ Contract *CCIPReaderTesterCaller
+ CallOpts bind.CallOpts
+}
+
+type CCIPReaderTesterTransactorSession struct {
+ Contract *CCIPReaderTesterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type CCIPReaderTesterRaw struct {
+ Contract *CCIPReaderTester
+}
+
+type CCIPReaderTesterCallerRaw struct {
+ Contract *CCIPReaderTesterCaller
+}
+
+type CCIPReaderTesterTransactorRaw struct {
+ Contract *CCIPReaderTesterTransactor
+}
+
+func NewCCIPReaderTester(address common.Address, backend bind.ContractBackend) (*CCIPReaderTester, error) {
+ abi, err := abi.JSON(strings.NewReader(CCIPReaderTesterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindCCIPReaderTester(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPReaderTester{address: address, abi: abi, CCIPReaderTesterCaller: CCIPReaderTesterCaller{contract: contract}, CCIPReaderTesterTransactor: CCIPReaderTesterTransactor{contract: contract}, CCIPReaderTesterFilterer: CCIPReaderTesterFilterer{contract: contract}}, nil
+}
+
+func NewCCIPReaderTesterCaller(address common.Address, caller bind.ContractCaller) (*CCIPReaderTesterCaller, error) {
+ contract, err := bindCCIPReaderTester(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPReaderTesterCaller{contract: contract}, nil
+}
+
+func NewCCIPReaderTesterTransactor(address common.Address, transactor bind.ContractTransactor) (*CCIPReaderTesterTransactor, error) {
+ contract, err := bindCCIPReaderTester(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPReaderTesterTransactor{contract: contract}, nil
+}
+
+func NewCCIPReaderTesterFilterer(address common.Address, filterer bind.ContractFilterer) (*CCIPReaderTesterFilterer, error) {
+ contract, err := bindCCIPReaderTester(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPReaderTesterFilterer{contract: contract}, nil
+}
+
+func bindCCIPReaderTester(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := CCIPReaderTesterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CCIPReaderTester.Contract.CCIPReaderTesterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.CCIPReaderTesterTransactor.contract.Transfer(opts)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.CCIPReaderTesterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CCIPReaderTester.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.contract.Transfer(opts)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterCaller) GetSourceChainConfig(opts *bind.CallOpts, sourceChainSelector uint64) (EVM2EVMMultiOffRampSourceChainConfig, error) {
+ var out []interface{}
+ err := _CCIPReaderTester.contract.Call(opts, &out, "getSourceChainConfig", sourceChainSelector)
+
+ if err != nil {
+ return *new(EVM2EVMMultiOffRampSourceChainConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMMultiOffRampSourceChainConfig)).(*EVM2EVMMultiOffRampSourceChainConfig)
+
+ return out0, err
+
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterSession) GetSourceChainConfig(sourceChainSelector uint64) (EVM2EVMMultiOffRampSourceChainConfig, error) {
+ return _CCIPReaderTester.Contract.GetSourceChainConfig(&_CCIPReaderTester.CallOpts, sourceChainSelector)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterCallerSession) GetSourceChainConfig(sourceChainSelector uint64) (EVM2EVMMultiOffRampSourceChainConfig, error) {
+ return _CCIPReaderTester.Contract.GetSourceChainConfig(&_CCIPReaderTester.CallOpts, sourceChainSelector)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactor) EmitCCIPSendRequested(opts *bind.TransactOpts, destChainSelector uint64, message InternalEVM2AnyRampMessage) (*types.Transaction, error) {
+ return _CCIPReaderTester.contract.Transact(opts, "emitCCIPSendRequested", destChainSelector, message)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterSession) EmitCCIPSendRequested(destChainSelector uint64, message InternalEVM2AnyRampMessage) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.EmitCCIPSendRequested(&_CCIPReaderTester.TransactOpts, destChainSelector, message)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactorSession) EmitCCIPSendRequested(destChainSelector uint64, message InternalEVM2AnyRampMessage) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.EmitCCIPSendRequested(&_CCIPReaderTester.TransactOpts, destChainSelector, message)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactor) EmitCommitReportAccepted(opts *bind.TransactOpts, report EVM2EVMMultiOffRampCommitReport) (*types.Transaction, error) {
+ return _CCIPReaderTester.contract.Transact(opts, "emitCommitReportAccepted", report)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterSession) EmitCommitReportAccepted(report EVM2EVMMultiOffRampCommitReport) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.EmitCommitReportAccepted(&_CCIPReaderTester.TransactOpts, report)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactorSession) EmitCommitReportAccepted(report EVM2EVMMultiOffRampCommitReport) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.EmitCommitReportAccepted(&_CCIPReaderTester.TransactOpts, report)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactor) EmitExecutionStateChanged(opts *bind.TransactOpts, sourceChainSelector uint64, sequenceNumber uint64, messageId [32]byte, state uint8, returnData []byte) (*types.Transaction, error) {
+ return _CCIPReaderTester.contract.Transact(opts, "emitExecutionStateChanged", sourceChainSelector, sequenceNumber, messageId, state, returnData)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterSession) EmitExecutionStateChanged(sourceChainSelector uint64, sequenceNumber uint64, messageId [32]byte, state uint8, returnData []byte) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.EmitExecutionStateChanged(&_CCIPReaderTester.TransactOpts, sourceChainSelector, sequenceNumber, messageId, state, returnData)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactorSession) EmitExecutionStateChanged(sourceChainSelector uint64, sequenceNumber uint64, messageId [32]byte, state uint8, returnData []byte) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.EmitExecutionStateChanged(&_CCIPReaderTester.TransactOpts, sourceChainSelector, sequenceNumber, messageId, state, returnData)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactor) SetSourceChainConfig(opts *bind.TransactOpts, sourceChainSelector uint64, sourceChainConfig EVM2EVMMultiOffRampSourceChainConfig) (*types.Transaction, error) {
+ return _CCIPReaderTester.contract.Transact(opts, "setSourceChainConfig", sourceChainSelector, sourceChainConfig)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterSession) SetSourceChainConfig(sourceChainSelector uint64, sourceChainConfig EVM2EVMMultiOffRampSourceChainConfig) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.SetSourceChainConfig(&_CCIPReaderTester.TransactOpts, sourceChainSelector, sourceChainConfig)
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterTransactorSession) SetSourceChainConfig(sourceChainSelector uint64, sourceChainConfig EVM2EVMMultiOffRampSourceChainConfig) (*types.Transaction, error) {
+ return _CCIPReaderTester.Contract.SetSourceChainConfig(&_CCIPReaderTester.TransactOpts, sourceChainSelector, sourceChainConfig)
+}
+
+type CCIPReaderTesterCCIPSendRequestedIterator struct {
+ Event *CCIPReaderTesterCCIPSendRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CCIPReaderTesterCCIPSendRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CCIPReaderTesterCCIPSendRequested)
+ 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(CCIPReaderTesterCCIPSendRequested)
+ 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 *CCIPReaderTesterCCIPSendRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CCIPReaderTesterCCIPSendRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CCIPReaderTesterCCIPSendRequested struct {
+ DestChainSelector uint64
+ Message InternalEVM2AnyRampMessage
+ Raw types.Log
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterFilterer) FilterCCIPSendRequested(opts *bind.FilterOpts, destChainSelector []uint64) (*CCIPReaderTesterCCIPSendRequestedIterator, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _CCIPReaderTester.contract.FilterLogs(opts, "CCIPSendRequested", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPReaderTesterCCIPSendRequestedIterator{contract: _CCIPReaderTester.contract, event: "CCIPSendRequested", logs: logs, sub: sub}, nil
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterFilterer) WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *CCIPReaderTesterCCIPSendRequested, destChainSelector []uint64) (event.Subscription, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _CCIPReaderTester.contract.WatchLogs(opts, "CCIPSendRequested", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CCIPReaderTesterCCIPSendRequested)
+ if err := _CCIPReaderTester.contract.UnpackLog(event, "CCIPSendRequested", 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 (_CCIPReaderTester *CCIPReaderTesterFilterer) ParseCCIPSendRequested(log types.Log) (*CCIPReaderTesterCCIPSendRequested, error) {
+ event := new(CCIPReaderTesterCCIPSendRequested)
+ if err := _CCIPReaderTester.contract.UnpackLog(event, "CCIPSendRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CCIPReaderTesterCommitReportAcceptedIterator struct {
+ Event *CCIPReaderTesterCommitReportAccepted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CCIPReaderTesterCommitReportAcceptedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CCIPReaderTesterCommitReportAccepted)
+ 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(CCIPReaderTesterCommitReportAccepted)
+ 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 *CCIPReaderTesterCommitReportAcceptedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CCIPReaderTesterCommitReportAcceptedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CCIPReaderTesterCommitReportAccepted struct {
+ Report EVM2EVMMultiOffRampCommitReport
+ Raw types.Log
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterFilterer) FilterCommitReportAccepted(opts *bind.FilterOpts) (*CCIPReaderTesterCommitReportAcceptedIterator, error) {
+
+ logs, sub, err := _CCIPReaderTester.contract.FilterLogs(opts, "CommitReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPReaderTesterCommitReportAcceptedIterator{contract: _CCIPReaderTester.contract, event: "CommitReportAccepted", logs: logs, sub: sub}, nil
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterFilterer) WatchCommitReportAccepted(opts *bind.WatchOpts, sink chan<- *CCIPReaderTesterCommitReportAccepted) (event.Subscription, error) {
+
+ logs, sub, err := _CCIPReaderTester.contract.WatchLogs(opts, "CommitReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CCIPReaderTesterCommitReportAccepted)
+ if err := _CCIPReaderTester.contract.UnpackLog(event, "CommitReportAccepted", 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 (_CCIPReaderTester *CCIPReaderTesterFilterer) ParseCommitReportAccepted(log types.Log) (*CCIPReaderTesterCommitReportAccepted, error) {
+ event := new(CCIPReaderTesterCommitReportAccepted)
+ if err := _CCIPReaderTester.contract.UnpackLog(event, "CommitReportAccepted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CCIPReaderTesterExecutionStateChangedIterator struct {
+ Event *CCIPReaderTesterExecutionStateChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CCIPReaderTesterExecutionStateChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CCIPReaderTesterExecutionStateChanged)
+ 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(CCIPReaderTesterExecutionStateChanged)
+ 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 *CCIPReaderTesterExecutionStateChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CCIPReaderTesterExecutionStateChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CCIPReaderTesterExecutionStateChanged struct {
+ SourceChainSelector uint64
+ SequenceNumber uint64
+ MessageId [32]byte
+ State uint8
+ ReturnData []byte
+ Raw types.Log
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterFilterer) FilterExecutionStateChanged(opts *bind.FilterOpts, sourceChainSelector []uint64, sequenceNumber []uint64, messageId [][32]byte) (*CCIPReaderTesterExecutionStateChangedIterator, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _CCIPReaderTester.contract.FilterLogs(opts, "ExecutionStateChanged", sourceChainSelectorRule, sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPReaderTesterExecutionStateChangedIterator{contract: _CCIPReaderTester.contract, event: "ExecutionStateChanged", logs: logs, sub: sub}, nil
+}
+
+func (_CCIPReaderTester *CCIPReaderTesterFilterer) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *CCIPReaderTesterExecutionStateChanged, sourceChainSelector []uint64, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _CCIPReaderTester.contract.WatchLogs(opts, "ExecutionStateChanged", sourceChainSelectorRule, sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CCIPReaderTesterExecutionStateChanged)
+ if err := _CCIPReaderTester.contract.UnpackLog(event, "ExecutionStateChanged", 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 (_CCIPReaderTester *CCIPReaderTesterFilterer) ParseExecutionStateChanged(log types.Log) (*CCIPReaderTesterExecutionStateChanged, error) {
+ event := new(CCIPReaderTesterExecutionStateChanged)
+ if err := _CCIPReaderTester.contract.UnpackLog(event, "ExecutionStateChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_CCIPReaderTester *CCIPReaderTester) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _CCIPReaderTester.abi.Events["CCIPSendRequested"].ID:
+ return _CCIPReaderTester.ParseCCIPSendRequested(log)
+ case _CCIPReaderTester.abi.Events["CommitReportAccepted"].ID:
+ return _CCIPReaderTester.ParseCommitReportAccepted(log)
+ case _CCIPReaderTester.abi.Events["ExecutionStateChanged"].ID:
+ return _CCIPReaderTester.ParseExecutionStateChanged(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (CCIPReaderTesterCCIPSendRequested) Topic() common.Hash {
+ return common.HexToHash("0x0f07cd31e53232da9125e517f09550fdde74bf43d6a0a76ebd41674dafe2ab29")
+}
+
+func (CCIPReaderTesterCommitReportAccepted) Topic() common.Hash {
+ return common.HexToHash("0x3a3950e13dd607cc37980db0ef14266c40d2bba9c01b2e44bfe549808883095d")
+}
+
+func (CCIPReaderTesterExecutionStateChanged) Topic() common.Hash {
+ return common.HexToHash("0x8c324ce1367b83031769f6a813e3bb4c117aba2185789d66b98b791405be6df2")
+}
+
+func (_CCIPReaderTester *CCIPReaderTester) Address() common.Address {
+ return _CCIPReaderTester.address
+}
+
+type CCIPReaderTesterInterface interface {
+ GetSourceChainConfig(opts *bind.CallOpts, sourceChainSelector uint64) (EVM2EVMMultiOffRampSourceChainConfig, error)
+
+ EmitCCIPSendRequested(opts *bind.TransactOpts, destChainSelector uint64, message InternalEVM2AnyRampMessage) (*types.Transaction, error)
+
+ EmitCommitReportAccepted(opts *bind.TransactOpts, report EVM2EVMMultiOffRampCommitReport) (*types.Transaction, error)
+
+ EmitExecutionStateChanged(opts *bind.TransactOpts, sourceChainSelector uint64, sequenceNumber uint64, messageId [32]byte, state uint8, returnData []byte) (*types.Transaction, error)
+
+ SetSourceChainConfig(opts *bind.TransactOpts, sourceChainSelector uint64, sourceChainConfig EVM2EVMMultiOffRampSourceChainConfig) (*types.Transaction, error)
+
+ FilterCCIPSendRequested(opts *bind.FilterOpts, destChainSelector []uint64) (*CCIPReaderTesterCCIPSendRequestedIterator, error)
+
+ WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *CCIPReaderTesterCCIPSendRequested, destChainSelector []uint64) (event.Subscription, error)
+
+ ParseCCIPSendRequested(log types.Log) (*CCIPReaderTesterCCIPSendRequested, error)
+
+ FilterCommitReportAccepted(opts *bind.FilterOpts) (*CCIPReaderTesterCommitReportAcceptedIterator, error)
+
+ WatchCommitReportAccepted(opts *bind.WatchOpts, sink chan<- *CCIPReaderTesterCommitReportAccepted) (event.Subscription, error)
+
+ ParseCommitReportAccepted(log types.Log) (*CCIPReaderTesterCommitReportAccepted, error)
+
+ FilterExecutionStateChanged(opts *bind.FilterOpts, sourceChainSelector []uint64, sequenceNumber []uint64, messageId [][32]byte) (*CCIPReaderTesterExecutionStateChangedIterator, error)
+
+ WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *CCIPReaderTesterExecutionStateChanged, sourceChainSelector []uint64, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error)
+
+ ParseExecutionStateChanged(log types.Log) (*CCIPReaderTesterExecutionStateChanged, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/commit_store/commit_store.go b/core/gethwrappers/ccip/generated/commit_store/commit_store.go
new file mode 100644
index 00000000000..940f4208d43
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/commit_store/commit_store.go
@@ -0,0 +1,2191 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package commit_store
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommitStoreCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ Interval CommitStoreInterval
+ MerkleRoot [32]byte
+}
+
+type CommitStoreDynamicConfig struct {
+ PriceRegistry common.Address
+}
+
+type CommitStoreInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type CommitStoreStaticConfig struct {
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ RmnProxy common.Address
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var CommitStoreMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCommitStoreConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enumOCR2Base.InvalidConfigErrorType\",\"name\":\"errorType\",\"type\":\"uint8\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"}],\"name\":\"InvalidInterval\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRoot\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LeavesCannotBeEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PausedError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootAlreadyCommitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":false,\"internalType\":\"uint40\",\"name\":\"oldEpochAndRound\",\"type\":\"uint40\"},{\"indexed\":false,\"internalType\":\"uint40\",\"name\":\"newEpochAndRound\",\"type\":\"uint40\"}],\"name\":\"LatestPriceEpochAndRoundSet\",\"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\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structCommitStore.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"ReportAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"RootRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"oldSeqNum\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSeqNum\",\"type\":\"uint64\"}],\"name\":\"SequenceNumberSet\",\"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\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLatestPriceEpochAndRound\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"getMerkleRoot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isUnpausedAndNotCursed\",\"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\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"rootToReset\",\"type\":\"bytes32[]\"}],\"name\":\"resetUnblessedRoots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint40\",\"name\":\"latestPriceEpochAndRound\",\"type\":\"uint40\"}],\"name\":\"setLatestPriceEpochAndRound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"}],\"name\":\"setMinSeqNr\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"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\":\"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\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedLeaves\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x61014060405260098054600165ff000000000160401b03191660011790553480156200002a57600080fd5b506040516200378e3803806200378e8339810160408190526200004d9162000272565b600033808281620000a55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d857620000d88162000192565b50505015156080524660a05260408101516001600160a01b0316158062000107575080516001600160401b0316155b806200011e575060208101516001600160401b0316155b8062000135575060608101516001600160a01b0316155b156200015457604051631fc5f15f60e11b815260040160405180910390fd5b80516001600160401b0390811660c05260208201511660e05260408101516001600160a01b0390811661010052606090910151166101205262000306565b336001600160a01b03821603620001ec5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009c565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160401b03811681146200025557600080fd5b919050565b80516001600160a01b03811681146200025557600080fd5b6000608082840312156200028557600080fd5b604051608081016001600160401b0381118282101715620002b657634e487b7160e01b600052604160045260246000fd5b604052620002c4836200023d565b8152620002d4602084016200023d565b6020820152620002e7604084016200025a565b6040820152620002fa606084016200025a565b60608201529392505050565b60805160a05160c05160e05161010051610120516133f26200039c60003960008181610262015281816116c80152818161187c01528181611acb0152611fa50152600081816102260152611aa40152600081816101f60152818161168201528181611a7d0152611f620152600081816101c60152611a4e0152600081816110c801526111140152600061118f01526133f26000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806379ba5097116100e3578063afcb95d71161008c578063f2fde38b11610066578063f2fde38b146104e3578063f47a8690146104f6578063ff888fb11461050957600080fd5b8063afcb95d7146104a8578063b1dc65a4146104c8578063e89d039f146104db57600080fd5b80638da5cb5b116100bd5780638da5cb5b1461044d578063a7206cd614610475578063ad7a22f81461049557600080fd5b806379ba50971461040d57806381ff7048146104155780638456cb591461044557600080fd5b806332048875116101455780635c975abb1161011f5780635c975abb14610391578063666cab8d146103b95780637437ff9f146103ce57600080fd5b806332048875146103565780633f4ba83a146103775780634120fccd1461037f57600080fd5b8063181f5a7711610176578063181f5a77146102e55780631ef381741461032e57806329b980e41461034357600080fd5b806306285c691461019257806310c374ed146102b5575b600080fd5b61029f60408051608081018252600080825260208201819052918101829052606081019190915260405180608001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516102ac9190612583565b60405180910390f35b60095468010000000000000000900464ffffffffff165b60405167ffffffffffffffff90911681526020016102ac565b6103216040518060400160405280601581526020017f436f6d6d697453746f726520312e352e302d646576000000000000000000000081525081565b6040516102ac9190612640565b61034161033c366004612897565b61051c565b005b610341610351366004612964565b610c00565b6103696103643660046129d7565b610c90565b6040519081526020016102ac565b610341610d86565b60095467ffffffffffffffff166102cc565b6009546d0100000000000000000000000000900460ff165b60405190151581526020016102ac565b6103c1610dec565b6040516102ac9190612a9d565b604080516020808201835260009091528151808201835260085473ffffffffffffffffffffffffffffffffffffffff16908190529151918252016102ac565b610341610e5b565b6004546002546040805163ffffffff808516825264010000000090940490931660208401528201526060016102ac565b610341610f58565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102ac565b610369610483366004612ab0565b6000908152600a602052604090205490565b6103416104a3366004612ac9565b610fc8565b6040805160018152600060208201819052918101919091526060016102ac565b6103416104d6366004612ae4565b611043565b6103a961165a565b6103416104f1366004612bc9565b61176e565b610341610504366004612be6565b611782565b6103a9610517366004612ab0565b611819565b855185518560ff16601f83111561056b5760016040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105629190612c57565b60405180910390fd5b806000036105a85760006040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105629190612c57565b8183146105e45760046040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105629190612c57565b6105ef816003612cc7565b831161062a5760026040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105629190612c57565b6106326118ed565b61063b86611970565b60065460005b8181101561072f57600560006006838154811061066057610660612cde565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055600780546005929190849081106106d0576106d0612cde565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055600101610641565b50895160005b81811015610aa85760008c828151811061075157610751612cde565b602002602001015190506000600281111561076e5761076e612c28565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff1660028111156107ad576107ad612c28565b146107e75760036040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105629190612c57565b73ffffffffffffffffffffffffffffffffffffffff8116610834576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016001905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156108e4576108e4612c28565b021790555090505060008c838151811061090057610900612cde565b602002602001015190506000600281111561091d5761091d612c28565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff16600281111561095c5761095c612c28565b146109965760036040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105629190612c57565b73ffffffffffffffffffffffffffffffffffffffff81166109e3576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff84168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610a9357610a93612c28565b02179055509050505050806001019050610735565b508a51610abc9060069060208e01906124c5565b508951610ad09060079060208d01906124c5565b506003805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908c161717905560048054610b56914691309190600090610b289063ffffffff16612d0d565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168e8e8e8e8e8e611b20565b600260000181905550600060048054906101000a900463ffffffff169050436004806101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600260000154600460009054906101000a900463ffffffff168f8f8f8f8f8f604051610bea99989796959493929190612d30565b60405180910390a1505050505050505050505050565b610c086118ed565b6009805464ffffffffff838116680100000000000000008181027fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff85161790945560408051949093049091168084526020840191909152917ff0d557bfce33e354b41885eb9264448726cfe51f486ffa69809d2bf56545644491015b60405180910390a15050565b6009546000906d0100000000000000000000000000900460ff1615610ce1576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d5287878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250889250611bcb915050565b9050610d5d81611819565b610d6b576000915050610d7d565b6000908152600a602052604090205490505b95945050505050565b610d8e6118ed565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60606007805480602002602001604051908101604052809291908181526020018280548015610e5157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e26575b5050505050905090565b60015473ffffffffffffffffffffffffffffffffffffffff163314610edc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610562565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610f606118ed565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff166d01000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610de2565b610fd06118ed565b6009805467ffffffffffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000083168117909355604080519190921680825260208201939093527fea59e8027e41fda1525220008cf2416797405065eb21b0ebd417bfc6d361b8de9101610c84565b611052878760208b0135611eec565b6040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925289359182146110c55780516040517f93df584c000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610562565b467f000000000000000000000000000000000000000000000000000000000000000014611146576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610562565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a160007f0000000000000000000000000000000000000000000000000000000000000000156111e8576002826020015183604001516111c99190612dc6565b6111d39190612ddf565b6111de906001612dc6565b60ff1690506111fe565b60208201516111f8906001612dc6565b60ff1690505b868114611237576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b868514611270576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156112b3576112b3612c28565b60028111156112c4576112c4612c28565b90525090506002816020015160028111156112e1576112e1612c28565b14801561132857506007816000015160ff168154811061130357611303612cde565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b61135e576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600061136c866020612cc7565b611377896020612cc7565b6113838c610144612e28565b61138d9190612e28565b6113979190612e28565b90503681146113db576040517f8e1192e100000000000000000000000000000000000000000000000000000000815260048101829052366024820152604401610562565b5060008a8a6040516113ee929190612e3b565b604051908190038120611405918e90602001612e4b565b60405160208183030381529060405280519060200120905061142561254f565b8860005b818110156116495760006001858a846020811061144857611448612cde565b61145591901a601b612dc6565b8f8f8681811061146757611467612cde565b905060200201358e8e8781811061148057611480612cde565b90506020020135604051600081526020016040526040516114bd949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156114df573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152848220848601909552845460ff808216865293975091955092939284019161010090910416600281111561156257611562612c28565b600281111561157357611573612c28565b905250905060018160200151600281111561159057611590612c28565b146115c7576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f81106115de576115de612cde565b60200201511561161a576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f811061163557611635612cde565b911515602090920201525050600101611429565b505050505050505050505050505050565b6040517f2cbc26bb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060801b77ffffffffffffffff000000000000000000000000000000001660048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611724573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117489190612e5f565b15801561176957506009546d0100000000000000000000000000900460ff16155b905090565b6117766118ed565b61177f81612355565b50565b61178a6118ed565b60005b818110156118145760008383838181106117a9576117a9612cde565b9050602002013590506117bb81611819565b61180b576000818152600a602052604080822091909155517f202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12906118029083815260200190565b60405180910390a15b5060010161178d565b505050565b6040805180820182523081526020810183815291517f4d616771000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9081166004830152915160248201526000917f00000000000000000000000000000000000000000000000000000000000000001690634d61677190604401602060405180830381865afa1580156118c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e79190612e5f565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461196e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610562565b565b6000818060200190518101906119869190612e81565b805190915073ffffffffffffffffffffffffffffffffffffffff166119d7576040517f3f8be2be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff169055604080516080810182527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff90811682527f00000000000000000000000000000000000000000000000000000000000000001660208201527f00000000000000000000000000000000000000000000000000000000000000008316818301527f00000000000000000000000000000000000000000000000000000000000000009092166060830152517fc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec391610c84918490612ecd565b6000808a8a8a8a8a8a8a8a8a604051602001611b4499989796959493929190612f4a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b8251825160009190818303611c0c576040517f11a6b26400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101018211801590611c2057506101018111155b611c56576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82820101610100811115611cb7576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003611ce45786600081518110611cd257611cd2612cde565b60200260200101519350505050611ee5565b60008167ffffffffffffffff811115611cff57611cff612653565b604051908082528060200260200182016040528015611d28578160200160208202803683370190505b50905060008080805b85811015611e6b5760006001821b8b811603611d8c5788851015611d75578c5160018601958e918110611d6657611d66612cde565b60200260200101519050611dae565b8551600185019487918110611d6657611d66612cde565b8b5160018401938d918110611da357611da3612cde565b602002602001015190505b600089861015611dde578d5160018701968f918110611dcf57611dcf612cde565b60200260200101519050611e00565b8651600186019588918110611df557611df5612cde565b602002602001015190505b82851115611e3a576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e44828261244a565b878481518110611e5657611e56612cde565b60209081029190910101525050600101611d31565b506001850382148015611e7d57508683145b8015611e8857508581145b611ebe576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836001860381518110611ed357611ed3612cde565b60200260200101519750505050505050505b9392505050565b6009546d0100000000000000000000000000900460ff1615611f3a576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f2cbc26bb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060801b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015612001573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120259190612e5f565b1561205c576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061206a838501856130d6565b8051515190915015158061208357508051602001515115155b156121bb5760095464ffffffffff8084166801000000000000000090920416101561218057600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff166801000000000000000064ffffffffff85160217905560085481516040517f3937306f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691633937306f9161213a91600401613329565b600060405180830381600087803b15801561215457600080fd5b505af1158015612168573d6000803e3d6000fd5b50505050604081015161217b5750505050565b6121bb565b60408101516121bb576040517ff803a2ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101515160095467ffffffffffffffff90811691161415806121f6575060208082015190810151905167ffffffffffffffff9182169116115b156122335780602001516040517fbb1ae18d000000000000000000000000000000000000000000000000000000008152600401610562919061333c565b604081015161226e576040517f504570e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040808201516000908152600a6020522054156122b7576040517fa0bce24f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208082015101516122ca906001613361565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790556040818101516000908152600a602052819020429055517f291698c01aa71f912280535d88a00d2c59fb63530a3f5d0098560468acb9ebf590612347908390613389565b60405180910390a150505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036123d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610562565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600081831061248c5760408051600160208083019190915281830185905260608083018790528351808403909101815260809092019092528051910120611ee5565b60408051600160208083019190915281830186905260608083018690528351808403909101815260809092019092528051910120611ee5565b82805482825590600052602060002090810192821561253f579160200282015b8281111561253f57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906124e5565b5061254b92915061256e565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b8082111561254b576000815560010161256f565b608081016118e7828467ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b6000815180845260005b81811015612602576020818501810151868301820152016125e6565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611ee560208301846125dc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156126a5576126a5612653565b60405290565b6040516060810167ffffffffffffffff811182821017156126a5576126a5612653565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561271557612715612653565b604052919050565b600067ffffffffffffffff82111561273757612737612653565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461177f57600080fd5b600082601f83011261277457600080fd5b813560206127896127848361271d565b6126ce565b8083825260208201915060208460051b8701019350868411156127ab57600080fd5b602086015b848110156127d05780356127c381612741565b83529183019183016127b0565b509695505050505050565b803560ff811681146127ec57600080fd5b919050565b600082601f83011261280257600080fd5b813567ffffffffffffffff81111561281c5761281c612653565b61284d60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016126ce565b81815284602083860101111561286257600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff811681146127ec57600080fd5b60008060008060008060c087890312156128b057600080fd5b863567ffffffffffffffff808211156128c857600080fd5b6128d48a838b01612763565b975060208901359150808211156128ea57600080fd5b6128f68a838b01612763565b965061290460408a016127db565b9550606089013591508082111561291a57600080fd5b6129268a838b016127f1565b945061293460808a0161287f565b935060a089013591508082111561294a57600080fd5b5061295789828a016127f1565b9150509295509295509295565b60006020828403121561297657600080fd5b813564ffffffffff81168114611ee557600080fd5b60008083601f84011261299d57600080fd5b50813567ffffffffffffffff8111156129b557600080fd5b6020830191508360208260051b85010111156129d057600080fd5b9250929050565b6000806000806000606086880312156129ef57600080fd5b853567ffffffffffffffff80821115612a0757600080fd5b612a1389838a0161298b565b90975095506020880135915080821115612a2c57600080fd5b50612a398882890161298b565b96999598509660400135949350505050565b60008151808452602080850194506020840160005b83811015612a9257815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101612a60565b509495945050505050565b602081526000611ee56020830184612a4b565b600060208284031215612ac257600080fd5b5035919050565b600060208284031215612adb57600080fd5b611ee58261287f565b60008060008060008060008060e0898b031215612b0057600080fd5b606089018a811115612b1157600080fd5b8998503567ffffffffffffffff80821115612b2b57600080fd5b818b0191508b601f830112612b3f57600080fd5b813581811115612b4e57600080fd5b8c6020828501011115612b6057600080fd5b6020830199508098505060808b0135915080821115612b7e57600080fd5b612b8a8c838d0161298b565b909750955060a08b0135915080821115612ba357600080fd5b50612bb08b828c0161298b565b999c989b50969995989497949560c00135949350505050565b600060208284031215612bdb57600080fd5b8135611ee581612741565b60008060208385031215612bf957600080fd5b823567ffffffffffffffff811115612c1057600080fd5b612c1c8582860161298b565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160058310612c92577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176118e7576118e7612c98565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff808316818103612d2657612d26612c98565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152612d608184018a612a4b565b90508281036080840152612d748189612a4b565b905060ff871660a084015282810360c0840152612d9181876125dc565b905067ffffffffffffffff851660e0840152828103610100840152612db681856125dc565b9c9b505050505050505050505050565b60ff81811683821601908111156118e7576118e7612c98565b600060ff831680612e19577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b808201808211156118e7576118e7612c98565b8183823760009101908152919050565b828152606082602083013760800192915050565b600060208284031215612e7157600080fd5b81518015158114611ee557600080fd5b600060208284031215612e9357600080fd5b6040516020810181811067ffffffffffffffff82111715612eb657612eb6612653565b6040528251612ec481612741565b81529392505050565b60a08101612f26828567ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b73ffffffffffffffffffffffffffffffffffffffff83511660808301529392505050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152612f918285018b612a4b565b91508382036080850152612fa5828a612a4b565b915060ff881660a085015283820360c0850152612fc282886125dc565b90861660e08501528381036101008501529050612db681856125dc565b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146127ec57600080fd5b600082601f83011261301c57600080fd5b8135602061302c6127848361271d565b82815260069290921b8401810191818101908684111561304b57600080fd5b8286015b848110156127d057604081890312156130685760008081fd5b613070612682565b6130798261287f565b8152613086858301612fdf565b8186015283529183019160400161304f565b6000604082840312156130aa57600080fd5b6130b2612682565b90506130bd8261287f565b81526130cb6020830161287f565b602082015292915050565b600060208083850312156130e957600080fd5b823567ffffffffffffffff8082111561310157600080fd5b908401906080828703121561311557600080fd5b61311d6126ab565b82358281111561312c57600080fd5b8301604081890381131561313f57600080fd5b613147612682565b82358581111561315657600080fd5b8301601f81018b1361316757600080fd5b80356131756127848261271d565b81815260069190911b8201890190898101908d83111561319457600080fd5b928a01925b828410156131e45785848f0312156131b15760008081fd5b6131b9612682565b84356131c481612741565b81526131d1858d01612fdf565b818d0152825292850192908a0190613199565b8452505050828701359150848211156131fc57600080fd5b6132088a83850161300b565b8188015283525061321d905087848601613098565b93810193909352506060013560408201529392505050565b805160408084528151848201819052600092602091908201906060870190855b818110156132ae578351805173ffffffffffffffffffffffffffffffffffffffff1684528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16858401529284019291850191600101613255565b50508583015187820388850152805180835290840192506000918401905b8083101561331d578351805167ffffffffffffffff1683528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16858301529284019260019290920191908501906132cc565b50979650505050505050565b602081526000611ee56020830184613235565b604081016118e78284805167ffffffffffffffff908116835260209182015116910152565b67ffffffffffffffff81811683821601908082111561338257613382612c98565b5092915050565b6020815260008251608060208401526133a560a0840182613235565b905060208401516133d06040850182805167ffffffffffffffff908116835260209182015116910152565b5060408401516080840152809150509291505056fea164736f6c6343000818000a",
+}
+
+var CommitStoreABI = CommitStoreMetaData.ABI
+
+var CommitStoreBin = CommitStoreMetaData.Bin
+
+func DeployCommitStore(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig CommitStoreStaticConfig) (common.Address, *types.Transaction, *CommitStore, error) {
+ parsed, err := CommitStoreMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CommitStoreBin), backend, staticConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &CommitStore{address: address, abi: *parsed, CommitStoreCaller: CommitStoreCaller{contract: contract}, CommitStoreTransactor: CommitStoreTransactor{contract: contract}, CommitStoreFilterer: CommitStoreFilterer{contract: contract}}, nil
+}
+
+type CommitStore struct {
+ address common.Address
+ abi abi.ABI
+ CommitStoreCaller
+ CommitStoreTransactor
+ CommitStoreFilterer
+}
+
+type CommitStoreCaller struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreTransactor struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreFilterer struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreSession struct {
+ Contract *CommitStore
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreCallerSession struct {
+ Contract *CommitStoreCaller
+ CallOpts bind.CallOpts
+}
+
+type CommitStoreTransactorSession struct {
+ Contract *CommitStoreTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreRaw struct {
+ Contract *CommitStore
+}
+
+type CommitStoreCallerRaw struct {
+ Contract *CommitStoreCaller
+}
+
+type CommitStoreTransactorRaw struct {
+ Contract *CommitStoreTransactor
+}
+
+func NewCommitStore(address common.Address, backend bind.ContractBackend) (*CommitStore, error) {
+ abi, err := abi.JSON(strings.NewReader(CommitStoreABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindCommitStore(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStore{address: address, abi: abi, CommitStoreCaller: CommitStoreCaller{contract: contract}, CommitStoreTransactor: CommitStoreTransactor{contract: contract}, CommitStoreFilterer: CommitStoreFilterer{contract: contract}}, nil
+}
+
+func NewCommitStoreCaller(address common.Address, caller bind.ContractCaller) (*CommitStoreCaller, error) {
+ contract, err := bindCommitStore(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreCaller{contract: contract}, nil
+}
+
+func NewCommitStoreTransactor(address common.Address, transactor bind.ContractTransactor) (*CommitStoreTransactor, error) {
+ contract, err := bindCommitStore(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreTransactor{contract: contract}, nil
+}
+
+func NewCommitStoreFilterer(address common.Address, filterer bind.ContractFilterer) (*CommitStoreFilterer, error) {
+ contract, err := bindCommitStore(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreFilterer{contract: contract}, nil
+}
+
+func bindCommitStore(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := CommitStoreMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_CommitStore *CommitStoreRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStore.Contract.CommitStoreCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStore *CommitStoreRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.Contract.CommitStoreTransactor.contract.Transfer(opts)
+}
+
+func (_CommitStore *CommitStoreRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStore.Contract.CommitStoreTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStore *CommitStoreCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStore.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStore *CommitStoreTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.Contract.contract.Transfer(opts)
+}
+
+func (_CommitStore *CommitStoreTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStore.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStore *CommitStoreCaller) GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(CommitStoreDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreDynamicConfig)).(*CommitStoreDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStore.Contract.GetDynamicConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStore.Contract.GetDynamicConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStore.Contract.GetExpectedNextSequenceNumber(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStore.Contract.GetExpectedNextSequenceNumber(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getLatestPriceEpochAndRound")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStore.Contract.GetLatestPriceEpochAndRound(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStore.Contract.GetLatestPriceEpochAndRound(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getMerkleRoot", root)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStore.Contract.GetMerkleRoot(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStore.Contract.GetMerkleRoot(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCaller) GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(CommitStoreStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreStaticConfig)).(*CommitStoreStaticConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStore.Contract.GetStaticConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStore.Contract.GetStaticConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStore.Contract.GetTransmitters(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStore.Contract.GetTransmitters(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "isBlessed", root)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStore.Contract.IsBlessed(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCallerSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStore.Contract.IsBlessed(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCaller) IsUnpausedAndNotCursed(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "isUnpausedAndNotCursed")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) IsUnpausedAndNotCursed() (bool, error) {
+ return _CommitStore.Contract.IsUnpausedAndNotCursed(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) IsUnpausedAndNotCursed() (bool, error) {
+ return _CommitStore.Contract.IsUnpausedAndNotCursed(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStore *CommitStoreSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDetails(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDetails(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStore *CommitStoreSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDigestAndEpoch(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDigestAndEpoch(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Owner() (common.Address, error) {
+ return _CommitStore.Contract.Owner(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Owner() (common.Address, error) {
+ return _CommitStore.Contract.Owner(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Paused(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "paused")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Paused() (bool, error) {
+ return _CommitStore.Contract.Paused(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Paused() (bool, error) {
+ return _CommitStore.Contract.Paused(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) TypeAndVersion() (string, error) {
+ return _CommitStore.Contract.TypeAndVersion(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) TypeAndVersion() (string, error) {
+ return _CommitStore.Contract.TypeAndVersion(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "verify", hashedLeaves, proofs, proofFlagBits)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStore.Contract.Verify(&_CommitStore.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStore.Contract.Verify(&_CommitStore.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStore *CommitStoreTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_CommitStore *CommitStoreSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStore.Contract.AcceptOwnership(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStore.Contract.AcceptOwnership(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "pause")
+}
+
+func (_CommitStore *CommitStoreSession) Pause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Pause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Pause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Pause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactor) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "resetUnblessedRoots", rootToReset)
+}
+
+func (_CommitStore *CommitStoreSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.ResetUnblessedRoots(&_CommitStore.TransactOpts, rootToReset)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.ResetUnblessedRoots(&_CommitStore.TransactOpts, rootToReset)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setLatestPriceEpochAndRound", latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetLatestPriceEpochAndRound(&_CommitStore.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetLatestPriceEpochAndRound(&_CommitStore.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setMinSeqNr", minSeqNr)
+}
+
+func (_CommitStore *CommitStoreSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetMinSeqNr(&_CommitStore.TransactOpts, minSeqNr)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetMinSeqNr(&_CommitStore.TransactOpts, minSeqNr)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetOCR2Config(&_CommitStore.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetOCR2Config(&_CommitStore.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_CommitStore *CommitStoreSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStore.Contract.TransferOwnership(&_CommitStore.TransactOpts, to)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStore.Contract.TransferOwnership(&_CommitStore.TransactOpts, to)
+}
+
+func (_CommitStore *CommitStoreTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.Transmit(&_CommitStore.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.Transmit(&_CommitStore.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "unpause")
+}
+
+func (_CommitStore *CommitStoreSession) Unpause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Unpause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Unpause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Unpause(&_CommitStore.TransactOpts)
+}
+
+type CommitStoreConfigSetIterator struct {
+ Event *CommitStoreConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreConfigSet)
+ 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(CommitStoreConfigSet)
+ 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 *CommitStoreConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreConfigSet struct {
+ StaticConfig CommitStoreStaticConfig
+ DynamicConfig CommitStoreDynamicConfig
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreConfigSetIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreConfigSetIterator{contract: _CommitStore.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreConfigSet)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet", 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 (_CommitStore *CommitStoreFilterer) ParseConfigSet(log types.Log) (*CommitStoreConfigSet, error) {
+ event := new(CommitStoreConfigSet)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreConfigSet0Iterator struct {
+ Event *CommitStoreConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreConfigSet0)
+ 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(CommitStoreConfigSet0)
+ 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 *CommitStoreConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreConfigSet0Iterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreConfigSet0Iterator{contract: _CommitStore.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreConfigSet0)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet0", 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 (_CommitStore *CommitStoreFilterer) ParseConfigSet0(log types.Log) (*CommitStoreConfigSet0, error) {
+ event := new(CommitStoreConfigSet0)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreLatestPriceEpochAndRoundSetIterator struct {
+ Event *CommitStoreLatestPriceEpochAndRoundSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreLatestPriceEpochAndRoundSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreLatestPriceEpochAndRoundSet)
+ 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(CommitStoreLatestPriceEpochAndRoundSet)
+ 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 *CommitStoreLatestPriceEpochAndRoundSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreLatestPriceEpochAndRoundSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreLatestPriceEpochAndRoundSet struct {
+ OldEpochAndRound *big.Int
+ NewEpochAndRound *big.Int
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterLatestPriceEpochAndRoundSet(opts *bind.FilterOpts) (*CommitStoreLatestPriceEpochAndRoundSetIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "LatestPriceEpochAndRoundSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreLatestPriceEpochAndRoundSetIterator{contract: _CommitStore.contract, event: "LatestPriceEpochAndRoundSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchLatestPriceEpochAndRoundSet(opts *bind.WatchOpts, sink chan<- *CommitStoreLatestPriceEpochAndRoundSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "LatestPriceEpochAndRoundSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreLatestPriceEpochAndRoundSet)
+ if err := _CommitStore.contract.UnpackLog(event, "LatestPriceEpochAndRoundSet", 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 (_CommitStore *CommitStoreFilterer) ParseLatestPriceEpochAndRoundSet(log types.Log) (*CommitStoreLatestPriceEpochAndRoundSet, error) {
+ event := new(CommitStoreLatestPriceEpochAndRoundSet)
+ if err := _CommitStore.contract.UnpackLog(event, "LatestPriceEpochAndRoundSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreOwnershipTransferRequestedIterator struct {
+ Event *CommitStoreOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreOwnershipTransferRequested)
+ 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(CommitStoreOwnershipTransferRequested)
+ 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 *CommitStoreOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreOwnershipTransferRequestedIterator{contract: _CommitStore.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreOwnershipTransferRequested)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_CommitStore *CommitStoreFilterer) ParseOwnershipTransferRequested(log types.Log) (*CommitStoreOwnershipTransferRequested, error) {
+ event := new(CommitStoreOwnershipTransferRequested)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreOwnershipTransferredIterator struct {
+ Event *CommitStoreOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreOwnershipTransferred)
+ 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(CommitStoreOwnershipTransferred)
+ 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 *CommitStoreOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreOwnershipTransferredIterator{contract: _CommitStore.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreOwnershipTransferred)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferred", 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 (_CommitStore *CommitStoreFilterer) ParseOwnershipTransferred(log types.Log) (*CommitStoreOwnershipTransferred, error) {
+ event := new(CommitStoreOwnershipTransferred)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStorePausedIterator struct {
+ Event *CommitStorePaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStorePausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStorePaused)
+ 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(CommitStorePaused)
+ 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 *CommitStorePausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStorePausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStorePaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterPaused(opts *bind.FilterOpts) (*CommitStorePausedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStorePausedIterator{contract: _CommitStore.contract, event: "Paused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStorePaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStorePaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Paused", 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 (_CommitStore *CommitStoreFilterer) ParsePaused(log types.Log) (*CommitStorePaused, error) {
+ event := new(CommitStorePaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Paused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreReportAcceptedIterator struct {
+ Event *CommitStoreReportAccepted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreReportAcceptedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreReportAccepted)
+ 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(CommitStoreReportAccepted)
+ 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 *CommitStoreReportAcceptedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreReportAcceptedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreReportAccepted struct {
+ Report CommitStoreCommitReport
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreReportAcceptedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreReportAcceptedIterator{contract: _CommitStore.contract, event: "ReportAccepted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreReportAccepted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreReportAccepted)
+ if err := _CommitStore.contract.UnpackLog(event, "ReportAccepted", 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 (_CommitStore *CommitStoreFilterer) ParseReportAccepted(log types.Log) (*CommitStoreReportAccepted, error) {
+ event := new(CommitStoreReportAccepted)
+ if err := _CommitStore.contract.UnpackLog(event, "ReportAccepted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreRootRemovedIterator struct {
+ Event *CommitStoreRootRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreRootRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreRootRemoved)
+ 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(CommitStoreRootRemoved)
+ 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 *CommitStoreRootRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreRootRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreRootRemoved struct {
+ Root [32]byte
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreRootRemovedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreRootRemovedIterator{contract: _CommitStore.contract, event: "RootRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreRootRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreRootRemoved)
+ if err := _CommitStore.contract.UnpackLog(event, "RootRemoved", 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 (_CommitStore *CommitStoreFilterer) ParseRootRemoved(log types.Log) (*CommitStoreRootRemoved, error) {
+ event := new(CommitStoreRootRemoved)
+ if err := _CommitStore.contract.UnpackLog(event, "RootRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreSequenceNumberSetIterator struct {
+ Event *CommitStoreSequenceNumberSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreSequenceNumberSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreSequenceNumberSet)
+ 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(CommitStoreSequenceNumberSet)
+ 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 *CommitStoreSequenceNumberSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreSequenceNumberSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreSequenceNumberSet struct {
+ OldSeqNum uint64
+ NewSeqNum uint64
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterSequenceNumberSet(opts *bind.FilterOpts) (*CommitStoreSequenceNumberSetIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "SequenceNumberSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreSequenceNumberSetIterator{contract: _CommitStore.contract, event: "SequenceNumberSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchSequenceNumberSet(opts *bind.WatchOpts, sink chan<- *CommitStoreSequenceNumberSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "SequenceNumberSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreSequenceNumberSet)
+ if err := _CommitStore.contract.UnpackLog(event, "SequenceNumberSet", 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 (_CommitStore *CommitStoreFilterer) ParseSequenceNumberSet(log types.Log) (*CommitStoreSequenceNumberSet, error) {
+ event := new(CommitStoreSequenceNumberSet)
+ if err := _CommitStore.contract.UnpackLog(event, "SequenceNumberSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreTransmittedIterator struct {
+ Event *CommitStoreTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreTransmitted)
+ 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(CommitStoreTransmitted)
+ 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 *CommitStoreTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreTransmittedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreTransmittedIterator{contract: _CommitStore.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreTransmitted)
+ if err := _CommitStore.contract.UnpackLog(event, "Transmitted", 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 (_CommitStore *CommitStoreFilterer) ParseTransmitted(log types.Log) (*CommitStoreTransmitted, error) {
+ event := new(CommitStoreTransmitted)
+ if err := _CommitStore.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreUnpausedIterator struct {
+ Event *CommitStoreUnpaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreUnpausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreUnpaused)
+ 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(CommitStoreUnpaused)
+ 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 *CommitStoreUnpausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreUnpausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreUnpaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreUnpausedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreUnpausedIterator{contract: _CommitStore.contract, event: "Unpaused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreUnpaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreUnpaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Unpaused", 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 (_CommitStore *CommitStoreFilterer) ParseUnpaused(log types.Log) (*CommitStoreUnpaused, error) {
+ event := new(CommitStoreUnpaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Unpaused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_CommitStore *CommitStore) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _CommitStore.abi.Events["ConfigSet"].ID:
+ return _CommitStore.ParseConfigSet(log)
+ case _CommitStore.abi.Events["ConfigSet0"].ID:
+ return _CommitStore.ParseConfigSet0(log)
+ case _CommitStore.abi.Events["LatestPriceEpochAndRoundSet"].ID:
+ return _CommitStore.ParseLatestPriceEpochAndRoundSet(log)
+ case _CommitStore.abi.Events["OwnershipTransferRequested"].ID:
+ return _CommitStore.ParseOwnershipTransferRequested(log)
+ case _CommitStore.abi.Events["OwnershipTransferred"].ID:
+ return _CommitStore.ParseOwnershipTransferred(log)
+ case _CommitStore.abi.Events["Paused"].ID:
+ return _CommitStore.ParsePaused(log)
+ case _CommitStore.abi.Events["ReportAccepted"].ID:
+ return _CommitStore.ParseReportAccepted(log)
+ case _CommitStore.abi.Events["RootRemoved"].ID:
+ return _CommitStore.ParseRootRemoved(log)
+ case _CommitStore.abi.Events["SequenceNumberSet"].ID:
+ return _CommitStore.ParseSequenceNumberSet(log)
+ case _CommitStore.abi.Events["Transmitted"].ID:
+ return _CommitStore.ParseTransmitted(log)
+ case _CommitStore.abi.Events["Unpaused"].ID:
+ return _CommitStore.ParseUnpaused(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (CommitStoreConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec3")
+}
+
+func (CommitStoreConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (CommitStoreLatestPriceEpochAndRoundSet) Topic() common.Hash {
+ return common.HexToHash("0xf0d557bfce33e354b41885eb9264448726cfe51f486ffa69809d2bf565456444")
+}
+
+func (CommitStoreOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (CommitStoreOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (CommitStorePaused) Topic() common.Hash {
+ return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258")
+}
+
+func (CommitStoreReportAccepted) Topic() common.Hash {
+ return common.HexToHash("0x291698c01aa71f912280535d88a00d2c59fb63530a3f5d0098560468acb9ebf5")
+}
+
+func (CommitStoreRootRemoved) Topic() common.Hash {
+ return common.HexToHash("0x202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12")
+}
+
+func (CommitStoreSequenceNumberSet) Topic() common.Hash {
+ return common.HexToHash("0xea59e8027e41fda1525220008cf2416797405065eb21b0ebd417bfc6d361b8de")
+}
+
+func (CommitStoreTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (CommitStoreUnpaused) Topic() common.Hash {
+ return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa")
+}
+
+func (_CommitStore *CommitStore) Address() common.Address {
+ return _CommitStore.address
+}
+
+type CommitStoreInterface interface {
+ GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error)
+
+ GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error)
+
+ IsUnpausedAndNotCursed(opts *bind.CallOpts) (bool, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ Paused(opts *bind.CallOpts) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Pause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error)
+
+ SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error)
+
+ SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ Unpause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*CommitStoreConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*CommitStoreConfigSet0, error)
+
+ FilterLatestPriceEpochAndRoundSet(opts *bind.FilterOpts) (*CommitStoreLatestPriceEpochAndRoundSetIterator, error)
+
+ WatchLatestPriceEpochAndRoundSet(opts *bind.WatchOpts, sink chan<- *CommitStoreLatestPriceEpochAndRoundSet) (event.Subscription, error)
+
+ ParseLatestPriceEpochAndRoundSet(log types.Log) (*CommitStoreLatestPriceEpochAndRoundSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*CommitStoreOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*CommitStoreOwnershipTransferred, error)
+
+ FilterPaused(opts *bind.FilterOpts) (*CommitStorePausedIterator, error)
+
+ WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStorePaused) (event.Subscription, error)
+
+ ParsePaused(log types.Log) (*CommitStorePaused, error)
+
+ FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreReportAcceptedIterator, error)
+
+ WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreReportAccepted) (event.Subscription, error)
+
+ ParseReportAccepted(log types.Log) (*CommitStoreReportAccepted, error)
+
+ FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreRootRemovedIterator, error)
+
+ WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreRootRemoved) (event.Subscription, error)
+
+ ParseRootRemoved(log types.Log) (*CommitStoreRootRemoved, error)
+
+ FilterSequenceNumberSet(opts *bind.FilterOpts) (*CommitStoreSequenceNumberSetIterator, error)
+
+ WatchSequenceNumberSet(opts *bind.WatchOpts, sink chan<- *CommitStoreSequenceNumberSet) (event.Subscription, error)
+
+ ParseSequenceNumberSet(log types.Log) (*CommitStoreSequenceNumberSet, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*CommitStoreTransmitted, error)
+
+ FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreUnpausedIterator, error)
+
+ WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreUnpaused) (event.Subscription, error)
+
+ ParseUnpaused(log types.Log) (*CommitStoreUnpaused, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/commit_store_1_0_0/commit_store_1_0_0.go b/core/gethwrappers/ccip/generated/commit_store_1_0_0/commit_store_1_0_0.go
new file mode 100644
index 00000000000..30716b257cb
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/commit_store_1_0_0/commit_store_1_0_0.go
@@ -0,0 +1,1951 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package commit_store_1_0_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommitStoreCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ Interval CommitStoreInterval
+ MerkleRoot [32]byte
+}
+
+type CommitStoreDynamicConfig struct {
+ PriceRegistry common.Address
+}
+
+type CommitStoreInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type CommitStoreStaticConfig struct {
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ ArmProxy common.Address
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var CommitStoreMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCommitStoreConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"}],\"name\":\"InvalidInterval\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRoot\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LeavesCannotBeEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PausedError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootAlreadyCommitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":\"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\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"usdPerToken\",\"type\":\"uint192\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint192\",\"name\":\"usdPerUnitGas\",\"type\":\"uint192\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structCommitStore.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"ReportAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"RootRemoved\",\"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\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLatestPriceEpochAndRound\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"getMerkleRoot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isARMHealthy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isUnpausedAndARMHealthy\",\"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\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"rootToReset\",\"type\":\"bytes32[]\"}],\"name\":\"resetUnblessedRoots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint40\",\"name\":\"latestPriceEpochAndRound\",\"type\":\"uint40\"}],\"name\":\"setLatestPriceEpochAndRound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"}],\"name\":\"setMinSeqNr\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"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\":\"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\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedLeaves\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x61014060405260098054600165ff000000000160401b03191660011790553480156200002a57600080fd5b5060405162003788380380620037888339810160408190526200004d9162000272565b600033808281620000a55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d857620000d88162000192565b50505015156080524660a05260408101516001600160a01b0316158062000107575080516001600160401b0316155b806200011e575060208101516001600160401b0316155b8062000135575060608101516001600160a01b0316155b156200015457604051631fc5f15f60e11b815260040160405180910390fd5b80516001600160401b0390811660c05260208201511660e05260408101516001600160a01b0390811661010052606090910151166101205262000306565b336001600160a01b03821603620001ec5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009c565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160401b03811681146200025557600080fd5b919050565b80516001600160a01b03811681146200025557600080fd5b6000608082840312156200028557600080fd5b604051608081016001600160401b0381118282101715620002b657634e487b7160e01b600052604160045260246000fd5b604052620002c4836200023d565b8152620002d4602084016200023d565b6020820152620002e7604084016200025a565b6040820152620002fa606084016200025a565b60608201529392505050565b60805160a05160c05160e05161010051610120516133f3620003956000396000818161026d01528181610537015281816111730152818161199f01528181611bee015261206b0152600081816102310152611bc70152600081816102010152611ba00152600081816101d10152611b710152600081816112ee015261133a015260006113b501526133f36000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c806379ba5097116100e3578063ad7a22f81161008c578063f2fde38b11610066578063f2fde38b146104fa578063f47a86901461050d578063ff888fb11461052057600080fd5b8063ad7a22f8146104b4578063afcb95d7146104c7578063b1dc65a4146104e757600080fd5b80638da5cb5b116100bd5780638da5cb5b146104645780638db94e441461048c578063a7206cd61461049457600080fd5b806379ba50971461042457806381ff70481461042c5780638456cb591461045c57600080fd5b806332048875116101455780635c975abb1161011f5780635c975abb146103b4578063666cab8d146103d05780637437ff9f146103e557600080fd5b806332048875146103795780633f4ba83a1461039a5780634120fccd146103a257600080fd5b8063181f5a7711610176578063181f5a77146103085780631ef381741461035157806329b980e41461036657600080fd5b806306285c691461019d5780630a6cd30d146102c057806310c374ed146102d8575b600080fd5b6102aa60408051608081018252600080825260208201819052918101829052606081019190915260405180608001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516102b7919061265f565b60405180910390f35b6102c8610533565b60405190151581526020016102b7565b60095468010000000000000000900464ffffffffff165b60405167ffffffffffffffff90911681526020016102b7565b6103446040518060400160405280601181526020017f436f6d6d697453746f726520312e302e3000000000000000000000000000000081525081565b6040516102b7919061271c565b61036461035f36600461296f565b6105ca565b005b610364610374366004612a3c565b610deb565b61038c610387366004612aaf565b610e37565b6040519081526020016102b7565b610364610f2d565b60095467ffffffffffffffff166102ef565b6009546d0100000000000000000000000000900460ff166102c8565b6103d8610f93565b6040516102b79190612b74565b604080516020808201835260009091528151808201835260085473ffffffffffffffffffffffffffffffffffffffff16908190529151918252016102b7565b610364611002565b6004546002546040805163ffffffff808516825264010000000090940490931660208401528201526060016102b7565b6103646110ff565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102b7565b6102c861116f565b61038c6104a2366004612b87565b6000908152600a602052604090205490565b6103646104c2366004612ba0565b611226565b6040805160018152600060208201819052918101919091526060016102b7565b6103646104f5366004612bbb565b611269565b610364610508366004612ca0565b611889565b61036461051b366004612cbd565b61189d565b6102c861052e366004612b87565b61193c565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c49190612cff565b15905090565b855185518560ff16601f831115610642576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064015b60405180910390fd5b806000036106ac576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610639565b81831461073a576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610639565b610745816003612d50565b83116107ad576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610639565b6107b5611a10565b6107be86611a93565b60065460005b818110156108ba5760056000600683815481106107e3576107e3612d67565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556007805460059291908490811061085357610853612d67565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556108b381612d96565b90506107c4565b50895160005b81811015610c935760008c82815181106108dc576108dc612d67565b60200260200101519050600060028111156108f9576108f9612dce565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff16600281111561093857610938612dce565b1461099f576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610639565b73ffffffffffffffffffffffffffffffffffffffff81166109ec576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016001905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610a9c57610a9c612dce565b021790555090505060008c8381518110610ab857610ab8612d67565b6020026020010151905060006002811115610ad557610ad5612dce565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff166002811115610b1457610b14612dce565b14610b7b576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610639565b73ffffffffffffffffffffffffffffffffffffffff8116610bc8576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff84168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610c7857610c78612dce565b0217905550905050505080610c8c90612d96565b90506108c0565b508a51610ca79060069060208e01906125a1565b508951610cbb9060079060208d01906125a1565b506003805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908c161717905560048054610d41914691309190600090610d139063ffffffff16612dfd565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168e8e8e8e8e8e611c4f565b600260000181905550600060048054906101000a900463ffffffff169050436004806101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600260000154600460009054906101000a900463ffffffff168f8f8f8f8f8f604051610dd599989796959493929190612e20565b60405180910390a1505050505050505050505050565b610df3611a10565b6009805464ffffffffff90921668010000000000000000027fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff909216919091179055565b6009546000906d0100000000000000000000000000900460ff1615610e88576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610ef987878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250889250611cfa915050565b9050610f048161193c565b610f12576000915050610f24565b6000908152600a602052604090205490505b95945050505050565b610f35611a10565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60606007805480602002602001604051908101604052809291908181526020018280548015610ff857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610fcd575b5050505050905090565b60015473ffffffffffffffffffffffffffffffffffffffff163314611083576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610639565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611107611a10565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff166d01000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610f89565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112009190612cff565b15801561122157506009546d0100000000000000000000000000900460ff16155b905090565b61122e611a10565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055565b611278878760208b013561201b565b6040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925289359182146112eb5780516040517f93df584c000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610639565b467f00000000000000000000000000000000000000000000000000000000000000001461136c576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610639565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a160007f00000000000000000000000000000000000000000000000000000000000000001561140e576002826020015183604001516113ef9190612eb6565b6113f99190612ecf565b611404906001612eb6565b60ff169050611424565b602082015161141e906001612eb6565b60ff1690505b86811461145d576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b868514611496576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156114d9576114d9612dce565b60028111156114ea576114ea612dce565b905250905060028160200151600281111561150757611507612dce565b14801561154e57506007816000015160ff168154811061152957611529612d67565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b611584576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000611592866020612d50565b61159d896020612d50565b6115a98c610144612f18565b6115b39190612f18565b6115bd9190612f18565b9050368114611601576040517f8e1192e100000000000000000000000000000000000000000000000000000000815260048101829052366024820152604401610639565b5060008a8a604051611614929190612f2b565b60405190819003812061162b918e90602001612f3b565b60405160208183030381529060405280519060200120905061164b61262b565b8860005b818110156118785760006001858a846020811061166e5761166e612d67565b61167b91901a601b612eb6565b8f8f8681811061168d5761168d612d67565b905060200201358e8e878181106116a6576116a6612d67565b90506020020135604051600081526020016040526040516116e3949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611705573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152848220848601909552845460ff808216865293975091955092939284019161010090910416600281111561178857611788612dce565b600281111561179957611799612dce565b90525090506001816020015160028111156117b6576117b6612dce565b146117ed576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f811061180457611804612d67565b602002015115611840576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f811061185b5761185b612d67565b9115156020909202015250611871905081612d96565b905061164f565b505050505050505050505050505050565b611891611a10565b61189a81612431565b50565b6118a5611a10565b60005b818110156119375760008383838181106118c4576118c4612d67565b9050602002013590506118d68161193c565b611926576000818152600a602052604080822091909155517f202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f129061191d9083815260200190565b60405180910390a15b5061193081612d96565b90506118a8565b505050565b6040805180820182523081526020810183815291517f4d616771000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9081166004830152915160248201526000917f00000000000000000000000000000000000000000000000000000000000000001690634d61677190604401602060405180830381865afa1580156119e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a0a9190612cff565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610639565b565b600081806020019051810190611aa99190612f4f565b805190915073ffffffffffffffffffffffffffffffffffffffff16611afa576040517f3f8be2be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff169055604080516080810182527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff90811682527f00000000000000000000000000000000000000000000000000000000000000001660208201527f00000000000000000000000000000000000000000000000000000000000000008316818301527f00000000000000000000000000000000000000000000000000000000000000009092166060830152517fc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec391611c43918490612f9b565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a604051602001611c7399989796959493929190613018565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b8251825160009190818303611d3b576040517f11a6b26400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101018211801590611d4f57506101018111155b611d85576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82820101610100811115611de6576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003611e135786600081518110611e0157611e01612d67565b60200260200101519350505050612014565b60008167ffffffffffffffff811115611e2e57611e2e61272f565b604051908082528060200260200182016040528015611e57578160200160208202803683370190505b50905060008080805b85811015611f9a5760006001821b8b811603611ebb5788851015611ea4578c5160018601958e918110611e9557611e95612d67565b60200260200101519050611edd565b8551600185019487918110611e9557611e95612d67565b8b5160018401938d918110611ed257611ed2612d67565b602002602001015190505b600089861015611f0d578d5160018701968f918110611efe57611efe612d67565b60200260200101519050611f2f565b8651600186019588918110611f2457611f24612d67565b602002602001015190505b82851115611f69576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f738282612526565b878481518110611f8557611f85612d67565b60209081029190910101525050600101611e60565b506001850382148015611fac57508683145b8015611fb757508581145b611fed576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600186038151811061200257612002612d67565b60200260200101519750505050505050505b9392505050565b6009546d0100000000000000000000000000900460ff1615612069576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f89190612cff565b1561212f576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061213d83850185613113565b8051515190915015158061215f575080516020015167ffffffffffffffff1615155b156122975760095464ffffffffff8084166801000000000000000090920416101561225c57600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff166801000000000000000064ffffffffff85160217905560085481516040517f866548c900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9092169163866548c9916122169160040161332a565b600060405180830381600087803b15801561223057600080fd5b505af1158015612244573d6000803e3d6000fd5b5050505060408101516122575750505050565b612297565b6040810151612297576040517ff803a2ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101515160095467ffffffffffffffff90811691161415806122d2575060208082015190810151905167ffffffffffffffff9182169116115b1561230f5780602001516040517fbb1ae18d000000000000000000000000000000000000000000000000000000008152600401610639919061333d565b604081015161234a576040517f504570e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040808201516000908152600a602052205415612393576040517fa0bce24f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208082015101516123a6906001613362565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790556040818101516000908152600a602052819020429055517fe81b49e583122eb290c46fc255c962b9a2dec468816c00fb7a2e6ebc42dc92d49061242390839061338a565b60405180910390a150505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036124b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610639565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008183106125685760408051600160208083019190915281830185905260608083018790528351808403909101815260809092019092528051910120612014565b60408051600160208083019190915281830186905260608083018690528351808403909101815260809092019092528051910120612014565b82805482825590600052602060002090810192821561261b579160200282015b8281111561261b57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906125c1565b5061262792915061264a565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b80821115612627576000815560010161264b565b60808101611a0a828467ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b6000815180845260005b818110156126de576020818501810151868301820152016126c2565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061201460208301846126b8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156127815761278161272f565b60405290565b6040516060810167ffffffffffffffff811182821017156127815761278161272f565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156127f1576127f161272f565b604052919050565b600067ffffffffffffffff8211156128135761281361272f565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461189a57600080fd5b600082601f83011261285057600080fd5b81356020612865612860836127f9565b6127aa565b82815260059290921b8401810191818101908684111561288457600080fd5b8286015b848110156128a857803561289b8161281d565b8352918301918301612888565b509695505050505050565b803560ff811681146128c457600080fd5b919050565b600082601f8301126128da57600080fd5b813567ffffffffffffffff8111156128f4576128f461272f565b61292560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016127aa565b81815284602083860101111561293a57600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff811681146128c457600080fd5b60008060008060008060c0878903121561298857600080fd5b863567ffffffffffffffff808211156129a057600080fd5b6129ac8a838b0161283f565b975060208901359150808211156129c257600080fd5b6129ce8a838b0161283f565b96506129dc60408a016128b3565b955060608901359150808211156129f257600080fd5b6129fe8a838b016128c9565b9450612a0c60808a01612957565b935060a0890135915080821115612a2257600080fd5b50612a2f89828a016128c9565b9150509295509295509295565b600060208284031215612a4e57600080fd5b813564ffffffffff8116811461201457600080fd5b60008083601f840112612a7557600080fd5b50813567ffffffffffffffff811115612a8d57600080fd5b6020830191508360208260051b8501011115612aa857600080fd5b9250929050565b600080600080600060608688031215612ac757600080fd5b853567ffffffffffffffff80821115612adf57600080fd5b612aeb89838a01612a63565b90975095506020880135915080821115612b0457600080fd5b50612b1188828901612a63565b96999598509660400135949350505050565b600081518084526020808501945080840160005b83811015612b6957815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101612b37565b509495945050505050565b6020815260006120146020830184612b23565b600060208284031215612b9957600080fd5b5035919050565b600060208284031215612bb257600080fd5b61201482612957565b60008060008060008060008060e0898b031215612bd757600080fd5b606089018a811115612be857600080fd5b8998503567ffffffffffffffff80821115612c0257600080fd5b818b0191508b601f830112612c1657600080fd5b813581811115612c2557600080fd5b8c6020828501011115612c3757600080fd5b6020830199508098505060808b0135915080821115612c5557600080fd5b612c618c838d01612a63565b909750955060a08b0135915080821115612c7a57600080fd5b50612c878b828c01612a63565b999c989b50969995989497949560c00135949350505050565b600060208284031215612cb257600080fd5b81356120148161281d565b60008060208385031215612cd057600080fd5b823567ffffffffffffffff811115612ce757600080fd5b612cf385828601612a63565b90969095509350505050565b600060208284031215612d1157600080fd5b8151801515811461201457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417611a0a57611a0a612d21565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dc757612dc7612d21565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600063ffffffff808316818103612e1657612e16612d21565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152612e508184018a612b23565b90508281036080840152612e648189612b23565b905060ff871660a084015282810360c0840152612e8181876126b8565b905067ffffffffffffffff851660e0840152828103610100840152612ea681856126b8565b9c9b505050505050505050505050565b60ff8181168382160190811115611a0a57611a0a612d21565b600060ff831680612f09577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b80820180821115611a0a57611a0a612d21565b8183823760009101908152919050565b828152606082602083013760800192915050565b600060208284031215612f6157600080fd5b6040516020810181811067ffffffffffffffff82111715612f8457612f8461272f565b6040528251612f928161281d565b81529392505050565b60a08101612ff4828567ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b73ffffffffffffffffffffffffffffffffffffffff83511660808301529392505050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b16604085015281606085015261305f8285018b612b23565b91508382036080850152613073828a612b23565b915060ff881660a085015283820360c085015261309082886126b8565b90861660e08501528381036101008501529050612ea681856126b8565b803577ffffffffffffffffffffffffffffffffffffffffffffffff811681146128c457600080fd5b6000604082840312156130e757600080fd5b6130ef61275e565b90506130fa82612957565b815261310860208301612957565b602082015292915050565b6000602080838503121561312657600080fd5b823567ffffffffffffffff8082111561313e57600080fd5b908401906080828703121561315257600080fd5b61315a612787565b82358281111561316957600080fd5b83016060818903121561317b57600080fd5b613183612787565b81358481111561319257600080fd5b82019350601f840189136131a557600080fd5b83356131b3612860826127f9565b81815260069190911b8501870190878101908b8311156131d257600080fd5b958801955b82871015613226576040878d0312156131f05760008081fd5b6131f861275e565b87356132038161281d565b8152613210888b016130ad565b818b0152825260409690960195908801906131d7565b8352506132369050828701612957565b86820152613246604083016130ad565b604082015282525061325a878486016130d5565b93810193909352506060013560408201529392505050565b805160608084528151908401819052600091602091908201906080860190845b818110156132e9578351805173ffffffffffffffffffffffffffffffffffffffff16845285015177ffffffffffffffffffffffffffffffffffffffffffffffff168584015292840192604090920191600101613292565b505067ffffffffffffffff83860151168387015260408501519250610f24604087018477ffffffffffffffffffffffffffffffffffffffffffffffff169052565b6020815260006120146020830184613272565b60408101611a0a8284805167ffffffffffffffff908116835260209182015116910152565b67ffffffffffffffff81811683821601908082111561338357613383612d21565b5092915050565b6020815260008251608060208401526133a660a0840182613272565b905060208401516133d16040850182805167ffffffffffffffff908116835260209182015116910152565b5060408401516080840152809150509291505056fea164736f6c6343000813000a",
+}
+
+var CommitStoreABI = CommitStoreMetaData.ABI
+
+var CommitStoreBin = CommitStoreMetaData.Bin
+
+func DeployCommitStore(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig CommitStoreStaticConfig) (common.Address, *types.Transaction, *CommitStore, error) {
+ parsed, err := CommitStoreMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CommitStoreBin), backend, staticConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &CommitStore{CommitStoreCaller: CommitStoreCaller{contract: contract}, CommitStoreTransactor: CommitStoreTransactor{contract: contract}, CommitStoreFilterer: CommitStoreFilterer{contract: contract}}, nil
+}
+
+type CommitStore struct {
+ address common.Address
+ abi abi.ABI
+ CommitStoreCaller
+ CommitStoreTransactor
+ CommitStoreFilterer
+}
+
+type CommitStoreCaller struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreTransactor struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreFilterer struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreSession struct {
+ Contract *CommitStore
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreCallerSession struct {
+ Contract *CommitStoreCaller
+ CallOpts bind.CallOpts
+}
+
+type CommitStoreTransactorSession struct {
+ Contract *CommitStoreTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreRaw struct {
+ Contract *CommitStore
+}
+
+type CommitStoreCallerRaw struct {
+ Contract *CommitStoreCaller
+}
+
+type CommitStoreTransactorRaw struct {
+ Contract *CommitStoreTransactor
+}
+
+func NewCommitStore(address common.Address, backend bind.ContractBackend) (*CommitStore, error) {
+ abi, err := abi.JSON(strings.NewReader(CommitStoreABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindCommitStore(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStore{address: address, abi: abi, CommitStoreCaller: CommitStoreCaller{contract: contract}, CommitStoreTransactor: CommitStoreTransactor{contract: contract}, CommitStoreFilterer: CommitStoreFilterer{contract: contract}}, nil
+}
+
+func NewCommitStoreCaller(address common.Address, caller bind.ContractCaller) (*CommitStoreCaller, error) {
+ contract, err := bindCommitStore(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreCaller{contract: contract}, nil
+}
+
+func NewCommitStoreTransactor(address common.Address, transactor bind.ContractTransactor) (*CommitStoreTransactor, error) {
+ contract, err := bindCommitStore(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreTransactor{contract: contract}, nil
+}
+
+func NewCommitStoreFilterer(address common.Address, filterer bind.ContractFilterer) (*CommitStoreFilterer, error) {
+ contract, err := bindCommitStore(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreFilterer{contract: contract}, nil
+}
+
+func bindCommitStore(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := CommitStoreMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_CommitStore *CommitStoreRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStore.Contract.CommitStoreCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStore *CommitStoreRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.Contract.CommitStoreTransactor.contract.Transfer(opts)
+}
+
+func (_CommitStore *CommitStoreRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStore.Contract.CommitStoreTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStore *CommitStoreCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStore.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStore *CommitStoreTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.Contract.contract.Transfer(opts)
+}
+
+func (_CommitStore *CommitStoreTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStore.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStore *CommitStoreCaller) GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(CommitStoreDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreDynamicConfig)).(*CommitStoreDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStore.Contract.GetDynamicConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStore.Contract.GetDynamicConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStore.Contract.GetExpectedNextSequenceNumber(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStore.Contract.GetExpectedNextSequenceNumber(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getLatestPriceEpochAndRound")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStore.Contract.GetLatestPriceEpochAndRound(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStore.Contract.GetLatestPriceEpochAndRound(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getMerkleRoot", root)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStore.Contract.GetMerkleRoot(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStore.Contract.GetMerkleRoot(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCaller) GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(CommitStoreStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreStaticConfig)).(*CommitStoreStaticConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStore.Contract.GetStaticConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStore.Contract.GetStaticConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStore.Contract.GetTransmitters(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStore.Contract.GetTransmitters(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) IsARMHealthy(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "isARMHealthy")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) IsARMHealthy() (bool, error) {
+ return _CommitStore.Contract.IsARMHealthy(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) IsARMHealthy() (bool, error) {
+ return _CommitStore.Contract.IsARMHealthy(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "isBlessed", root)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStore.Contract.IsBlessed(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCallerSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStore.Contract.IsBlessed(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCaller) IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "isUnpausedAndARMHealthy")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) IsUnpausedAndARMHealthy() (bool, error) {
+ return _CommitStore.Contract.IsUnpausedAndARMHealthy(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) IsUnpausedAndARMHealthy() (bool, error) {
+ return _CommitStore.Contract.IsUnpausedAndARMHealthy(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStore *CommitStoreSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDetails(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDetails(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStore *CommitStoreSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDigestAndEpoch(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDigestAndEpoch(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Owner() (common.Address, error) {
+ return _CommitStore.Contract.Owner(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Owner() (common.Address, error) {
+ return _CommitStore.Contract.Owner(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Paused(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "paused")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Paused() (bool, error) {
+ return _CommitStore.Contract.Paused(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Paused() (bool, error) {
+ return _CommitStore.Contract.Paused(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) TypeAndVersion() (string, error) {
+ return _CommitStore.Contract.TypeAndVersion(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) TypeAndVersion() (string, error) {
+ return _CommitStore.Contract.TypeAndVersion(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "verify", hashedLeaves, proofs, proofFlagBits)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStore.Contract.Verify(&_CommitStore.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStore.Contract.Verify(&_CommitStore.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStore *CommitStoreTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_CommitStore *CommitStoreSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStore.Contract.AcceptOwnership(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStore.Contract.AcceptOwnership(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "pause")
+}
+
+func (_CommitStore *CommitStoreSession) Pause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Pause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Pause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Pause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactor) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "resetUnblessedRoots", rootToReset)
+}
+
+func (_CommitStore *CommitStoreSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.ResetUnblessedRoots(&_CommitStore.TransactOpts, rootToReset)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.ResetUnblessedRoots(&_CommitStore.TransactOpts, rootToReset)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setLatestPriceEpochAndRound", latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetLatestPriceEpochAndRound(&_CommitStore.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetLatestPriceEpochAndRound(&_CommitStore.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setMinSeqNr", minSeqNr)
+}
+
+func (_CommitStore *CommitStoreSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetMinSeqNr(&_CommitStore.TransactOpts, minSeqNr)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetMinSeqNr(&_CommitStore.TransactOpts, minSeqNr)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetOCR2Config(&_CommitStore.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetOCR2Config(&_CommitStore.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_CommitStore *CommitStoreSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStore.Contract.TransferOwnership(&_CommitStore.TransactOpts, to)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStore.Contract.TransferOwnership(&_CommitStore.TransactOpts, to)
+}
+
+func (_CommitStore *CommitStoreTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.Transmit(&_CommitStore.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.Transmit(&_CommitStore.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "unpause")
+}
+
+func (_CommitStore *CommitStoreSession) Unpause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Unpause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Unpause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Unpause(&_CommitStore.TransactOpts)
+}
+
+type CommitStoreConfigSetIterator struct {
+ Event *CommitStoreConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreConfigSet)
+ 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(CommitStoreConfigSet)
+ 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 *CommitStoreConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreConfigSet struct {
+ StaticConfig CommitStoreStaticConfig
+ DynamicConfig CommitStoreDynamicConfig
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreConfigSetIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreConfigSetIterator{contract: _CommitStore.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreConfigSet)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet", 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 (_CommitStore *CommitStoreFilterer) ParseConfigSet(log types.Log) (*CommitStoreConfigSet, error) {
+ event := new(CommitStoreConfigSet)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreConfigSet0Iterator struct {
+ Event *CommitStoreConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreConfigSet0)
+ 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(CommitStoreConfigSet0)
+ 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 *CommitStoreConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreConfigSet0Iterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreConfigSet0Iterator{contract: _CommitStore.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreConfigSet0)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet0", 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 (_CommitStore *CommitStoreFilterer) ParseConfigSet0(log types.Log) (*CommitStoreConfigSet0, error) {
+ event := new(CommitStoreConfigSet0)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreOwnershipTransferRequestedIterator struct {
+ Event *CommitStoreOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreOwnershipTransferRequested)
+ 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(CommitStoreOwnershipTransferRequested)
+ 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 *CommitStoreOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreOwnershipTransferRequestedIterator{contract: _CommitStore.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreOwnershipTransferRequested)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_CommitStore *CommitStoreFilterer) ParseOwnershipTransferRequested(log types.Log) (*CommitStoreOwnershipTransferRequested, error) {
+ event := new(CommitStoreOwnershipTransferRequested)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreOwnershipTransferredIterator struct {
+ Event *CommitStoreOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreOwnershipTransferred)
+ 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(CommitStoreOwnershipTransferred)
+ 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 *CommitStoreOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreOwnershipTransferredIterator{contract: _CommitStore.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreOwnershipTransferred)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferred", 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 (_CommitStore *CommitStoreFilterer) ParseOwnershipTransferred(log types.Log) (*CommitStoreOwnershipTransferred, error) {
+ event := new(CommitStoreOwnershipTransferred)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStorePausedIterator struct {
+ Event *CommitStorePaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStorePausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStorePaused)
+ 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(CommitStorePaused)
+ 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 *CommitStorePausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStorePausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStorePaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterPaused(opts *bind.FilterOpts) (*CommitStorePausedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStorePausedIterator{contract: _CommitStore.contract, event: "Paused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStorePaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStorePaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Paused", 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 (_CommitStore *CommitStoreFilterer) ParsePaused(log types.Log) (*CommitStorePaused, error) {
+ event := new(CommitStorePaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Paused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreReportAcceptedIterator struct {
+ Event *CommitStoreReportAccepted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreReportAcceptedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreReportAccepted)
+ 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(CommitStoreReportAccepted)
+ 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 *CommitStoreReportAcceptedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreReportAcceptedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreReportAccepted struct {
+ Report CommitStoreCommitReport
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreReportAcceptedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreReportAcceptedIterator{contract: _CommitStore.contract, event: "ReportAccepted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreReportAccepted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreReportAccepted)
+ if err := _CommitStore.contract.UnpackLog(event, "ReportAccepted", 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 (_CommitStore *CommitStoreFilterer) ParseReportAccepted(log types.Log) (*CommitStoreReportAccepted, error) {
+ event := new(CommitStoreReportAccepted)
+ if err := _CommitStore.contract.UnpackLog(event, "ReportAccepted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreRootRemovedIterator struct {
+ Event *CommitStoreRootRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreRootRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreRootRemoved)
+ 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(CommitStoreRootRemoved)
+ 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 *CommitStoreRootRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreRootRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreRootRemoved struct {
+ Root [32]byte
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreRootRemovedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreRootRemovedIterator{contract: _CommitStore.contract, event: "RootRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreRootRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreRootRemoved)
+ if err := _CommitStore.contract.UnpackLog(event, "RootRemoved", 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 (_CommitStore *CommitStoreFilterer) ParseRootRemoved(log types.Log) (*CommitStoreRootRemoved, error) {
+ event := new(CommitStoreRootRemoved)
+ if err := _CommitStore.contract.UnpackLog(event, "RootRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreTransmittedIterator struct {
+ Event *CommitStoreTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreTransmitted)
+ 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(CommitStoreTransmitted)
+ 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 *CommitStoreTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreTransmittedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreTransmittedIterator{contract: _CommitStore.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreTransmitted)
+ if err := _CommitStore.contract.UnpackLog(event, "Transmitted", 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 (_CommitStore *CommitStoreFilterer) ParseTransmitted(log types.Log) (*CommitStoreTransmitted, error) {
+ event := new(CommitStoreTransmitted)
+ if err := _CommitStore.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreUnpausedIterator struct {
+ Event *CommitStoreUnpaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreUnpausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreUnpaused)
+ 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(CommitStoreUnpaused)
+ 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 *CommitStoreUnpausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreUnpausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreUnpaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreUnpausedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreUnpausedIterator{contract: _CommitStore.contract, event: "Unpaused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreUnpaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreUnpaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Unpaused", 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 (_CommitStore *CommitStoreFilterer) ParseUnpaused(log types.Log) (*CommitStoreUnpaused, error) {
+ event := new(CommitStoreUnpaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Unpaused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_CommitStore *CommitStore) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _CommitStore.abi.Events["ConfigSet"].ID:
+ return _CommitStore.ParseConfigSet(log)
+ case _CommitStore.abi.Events["ConfigSet0"].ID:
+ return _CommitStore.ParseConfigSet0(log)
+ case _CommitStore.abi.Events["OwnershipTransferRequested"].ID:
+ return _CommitStore.ParseOwnershipTransferRequested(log)
+ case _CommitStore.abi.Events["OwnershipTransferred"].ID:
+ return _CommitStore.ParseOwnershipTransferred(log)
+ case _CommitStore.abi.Events["Paused"].ID:
+ return _CommitStore.ParsePaused(log)
+ case _CommitStore.abi.Events["ReportAccepted"].ID:
+ return _CommitStore.ParseReportAccepted(log)
+ case _CommitStore.abi.Events["RootRemoved"].ID:
+ return _CommitStore.ParseRootRemoved(log)
+ case _CommitStore.abi.Events["Transmitted"].ID:
+ return _CommitStore.ParseTransmitted(log)
+ case _CommitStore.abi.Events["Unpaused"].ID:
+ return _CommitStore.ParseUnpaused(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (CommitStoreConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec3")
+}
+
+func (CommitStoreConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (CommitStoreOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (CommitStoreOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (CommitStorePaused) Topic() common.Hash {
+ return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258")
+}
+
+func (CommitStoreReportAccepted) Topic() common.Hash {
+ return common.HexToHash("0xe81b49e583122eb290c46fc255c962b9a2dec468816c00fb7a2e6ebc42dc92d4")
+}
+
+func (CommitStoreRootRemoved) Topic() common.Hash {
+ return common.HexToHash("0x202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12")
+}
+
+func (CommitStoreTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (CommitStoreUnpaused) Topic() common.Hash {
+ return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa")
+}
+
+func (_CommitStore *CommitStore) Address() common.Address {
+ return _CommitStore.address
+}
+
+type CommitStoreInterface interface {
+ GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error)
+
+ GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ IsARMHealthy(opts *bind.CallOpts) (bool, error)
+
+ IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error)
+
+ IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ Paused(opts *bind.CallOpts) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Pause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error)
+
+ SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error)
+
+ SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ Unpause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*CommitStoreConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*CommitStoreConfigSet0, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*CommitStoreOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*CommitStoreOwnershipTransferred, error)
+
+ FilterPaused(opts *bind.FilterOpts) (*CommitStorePausedIterator, error)
+
+ WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStorePaused) (event.Subscription, error)
+
+ ParsePaused(log types.Log) (*CommitStorePaused, error)
+
+ FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreReportAcceptedIterator, error)
+
+ WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreReportAccepted) (event.Subscription, error)
+
+ ParseReportAccepted(log types.Log) (*CommitStoreReportAccepted, error)
+
+ FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreRootRemovedIterator, error)
+
+ WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreRootRemoved) (event.Subscription, error)
+
+ ParseRootRemoved(log types.Log) (*CommitStoreRootRemoved, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*CommitStoreTransmitted, error)
+
+ FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreUnpausedIterator, error)
+
+ WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreUnpaused) (event.Subscription, error)
+
+ ParseUnpaused(log types.Log) (*CommitStoreUnpaused, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/commit_store_1_2_0/commit_store.go b/core/gethwrappers/ccip/generated/commit_store_1_2_0/commit_store.go
new file mode 100644
index 00000000000..fa757f287d3
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/commit_store_1_2_0/commit_store.go
@@ -0,0 +1,1955 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package commit_store_1_2_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommitStoreCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ Interval CommitStoreInterval
+ MerkleRoot [32]byte
+}
+
+type CommitStoreDynamicConfig struct {
+ PriceRegistry common.Address
+}
+
+type CommitStoreInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type CommitStoreStaticConfig struct {
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ ArmProxy common.Address
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var CommitStoreMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCommitStoreConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"}],\"name\":\"InvalidInterval\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRoot\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LeavesCannotBeEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PausedError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootAlreadyCommitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":\"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\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structCommitStore.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"ReportAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"RootRemoved\",\"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\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLatestPriceEpochAndRound\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"getMerkleRoot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isARMHealthy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isUnpausedAndARMHealthy\",\"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\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"rootToReset\",\"type\":\"bytes32[]\"}],\"name\":\"resetUnblessedRoots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint40\",\"name\":\"latestPriceEpochAndRound\",\"type\":\"uint40\"}],\"name\":\"setLatestPriceEpochAndRound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"}],\"name\":\"setMinSeqNr\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"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\":\"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\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedLeaves\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x61014060405260098054600165ff000000000160401b03191660011790553480156200002a57600080fd5b506040516200384c3803806200384c8339810160408190526200004d9162000272565b600033808281620000a55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d857620000d88162000192565b50505015156080524660a05260408101516001600160a01b0316158062000107575080516001600160401b0316155b806200011e575060208101516001600160401b0316155b8062000135575060608101516001600160a01b0316155b156200015457604051631fc5f15f60e11b815260040160405180910390fd5b80516001600160401b0390811660c05260208201511660e05260408101516001600160a01b0390811661010052606090910151166101205262000306565b336001600160a01b03821603620001ec5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009c565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160401b03811681146200025557600080fd5b919050565b80516001600160a01b03811681146200025557600080fd5b6000608082840312156200028557600080fd5b604051608081016001600160401b0381118282101715620002b657634e487b7160e01b600052604160045260246000fd5b604052620002c4836200023d565b8152620002d4602084016200023d565b6020820152620002e7604084016200025a565b6040820152620002fa606084016200025a565b60608201529392505050565b60805160a05160c05160e05161010051610120516134b7620003956000396000818161026d01528181610537015281816111730152818161199f01528181611bee015261206b0152600081816102310152611bc70152600081816102010152611ba00152600081816101d10152611b710152600081816112ee015261133a015260006113b501526134b76000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c806379ba5097116100e3578063ad7a22f81161008c578063f2fde38b11610066578063f2fde38b146104fa578063f47a86901461050d578063ff888fb11461052057600080fd5b8063ad7a22f8146104b4578063afcb95d7146104c7578063b1dc65a4146104e757600080fd5b80638da5cb5b116100bd5780638da5cb5b146104645780638db94e441461048c578063a7206cd61461049457600080fd5b806379ba50971461042457806381ff70481461042c5780638456cb591461045c57600080fd5b806332048875116101455780635c975abb1161011f5780635c975abb146103b4578063666cab8d146103d05780637437ff9f146103e557600080fd5b806332048875146103795780633f4ba83a1461039a5780634120fccd146103a257600080fd5b8063181f5a7711610176578063181f5a77146103085780631ef381741461035157806329b980e41461036657600080fd5b806306285c691461019d5780630a6cd30d146102c057806310c374ed146102d8575b600080fd5b6102aa60408051608081018252600080825260208201819052918101829052606081019190915260405180608001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516102b79190612656565b60405180910390f35b6102c8610533565b60405190151581526020016102b7565b60095468010000000000000000900464ffffffffff165b60405167ffffffffffffffff90911681526020016102b7565b6103446040518060400160405280601181526020017f436f6d6d697453746f726520312e322e3000000000000000000000000000000081525081565b6040516102b79190612713565b61036461035f366004612966565b6105ca565b005b610364610374366004612a33565b610deb565b61038c610387366004612aa6565b610e37565b6040519081526020016102b7565b610364610f2d565b60095467ffffffffffffffff166102ef565b6009546d0100000000000000000000000000900460ff166102c8565b6103d8610f93565b6040516102b79190612b6b565b604080516020808201835260009091528151808201835260085473ffffffffffffffffffffffffffffffffffffffff16908190529151918252016102b7565b610364611002565b6004546002546040805163ffffffff808516825264010000000090940490931660208401528201526060016102b7565b6103646110ff565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102b7565b6102c861116f565b61038c6104a2366004612b7e565b6000908152600a602052604090205490565b6103646104c2366004612b97565b611226565b6040805160018152600060208201819052918101919091526060016102b7565b6103646104f5366004612bb2565b611269565b610364610508366004612c97565b611889565b61036461051b366004612cb4565b61189d565b6102c861052e366004612b7e565b61193c565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c49190612cf6565b15905090565b855185518560ff16601f831115610642576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064015b60405180910390fd5b806000036106ac576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610639565b81831461073a576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610639565b610745816003612d47565b83116107ad576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610639565b6107b5611a10565b6107be86611a93565b60065460005b818110156108ba5760056000600683815481106107e3576107e3612d5e565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556007805460059291908490811061085357610853612d5e565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556108b381612d8d565b90506107c4565b50895160005b81811015610c935760008c82815181106108dc576108dc612d5e565b60200260200101519050600060028111156108f9576108f9612dc5565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff16600281111561093857610938612dc5565b1461099f576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610639565b73ffffffffffffffffffffffffffffffffffffffff81166109ec576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016001905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610a9c57610a9c612dc5565b021790555090505060008c8381518110610ab857610ab8612d5e565b6020026020010151905060006002811115610ad557610ad5612dc5565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff166002811115610b1457610b14612dc5565b14610b7b576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610639565b73ffffffffffffffffffffffffffffffffffffffff8116610bc8576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff84168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610c7857610c78612dc5565b0217905550905050505080610c8c90612d8d565b90506108c0565b508a51610ca79060069060208e0190612598565b508951610cbb9060079060208d0190612598565b506003805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908c161717905560048054610d41914691309190600090610d139063ffffffff16612df4565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168e8e8e8e8e8e611c4f565b600260000181905550600060048054906101000a900463ffffffff169050436004806101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600260000154600460009054906101000a900463ffffffff168f8f8f8f8f8f604051610dd599989796959493929190612e17565b60405180910390a1505050505050505050505050565b610df3611a10565b6009805464ffffffffff90921668010000000000000000027fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff909216919091179055565b6009546000906d0100000000000000000000000000900460ff1615610e88576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610ef987878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250889250611cfa915050565b9050610f048161193c565b610f12576000915050610f24565b6000908152600a602052604090205490505b95945050505050565b610f35611a10565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60606007805480602002602001604051908101604052809291908181526020018280548015610ff857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610fcd575b5050505050905090565b60015473ffffffffffffffffffffffffffffffffffffffff163314611083576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610639565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611107611a10565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff166d01000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610f89565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112009190612cf6565b15801561122157506009546d0100000000000000000000000000900460ff16155b905090565b61122e611a10565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055565b611278878760208b013561201b565b6040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925289359182146112eb5780516040517f93df584c000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610639565b467f00000000000000000000000000000000000000000000000000000000000000001461136c576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610639565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a160007f00000000000000000000000000000000000000000000000000000000000000001561140e576002826020015183604001516113ef9190612ead565b6113f99190612ec6565b611404906001612ead565b60ff169050611424565b602082015161141e906001612ead565b60ff1690505b86811461145d576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b868514611496576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156114d9576114d9612dc5565b60028111156114ea576114ea612dc5565b905250905060028160200151600281111561150757611507612dc5565b14801561154e57506007816000015160ff168154811061152957611529612d5e565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b611584576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000611592866020612d47565b61159d896020612d47565b6115a98c610144612f0f565b6115b39190612f0f565b6115bd9190612f0f565b9050368114611601576040517f8e1192e100000000000000000000000000000000000000000000000000000000815260048101829052366024820152604401610639565b5060008a8a604051611614929190612f22565b60405190819003812061162b918e90602001612f32565b60405160208183030381529060405280519060200120905061164b612622565b8860005b818110156118785760006001858a846020811061166e5761166e612d5e565b61167b91901a601b612ead565b8f8f8681811061168d5761168d612d5e565b905060200201358e8e878181106116a6576116a6612d5e565b90506020020135604051600081526020016040526040516116e3949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611705573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152848220848601909552845460ff808216865293975091955092939284019161010090910416600281111561178857611788612dc5565b600281111561179957611799612dc5565b90525090506001816020015160028111156117b6576117b6612dc5565b146117ed576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f811061180457611804612d5e565b602002015115611840576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f811061185b5761185b612d5e565b9115156020909202015250611871905081612d8d565b905061164f565b505050505050505050505050505050565b611891611a10565b61189a81612428565b50565b6118a5611a10565b60005b818110156119375760008383838181106118c4576118c4612d5e565b9050602002013590506118d68161193c565b611926576000818152600a602052604080822091909155517f202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f129061191d9083815260200190565b60405180910390a15b5061193081612d8d565b90506118a8565b505050565b6040805180820182523081526020810183815291517f4d616771000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9081166004830152915160248201526000917f00000000000000000000000000000000000000000000000000000000000000001690634d61677190604401602060405180830381865afa1580156119e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a0a9190612cf6565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611a91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610639565b565b600081806020019051810190611aa99190612f46565b805190915073ffffffffffffffffffffffffffffffffffffffff16611afa576040517f3f8be2be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff169055604080516080810182527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff90811682527f00000000000000000000000000000000000000000000000000000000000000001660208201527f00000000000000000000000000000000000000000000000000000000000000008316818301527f00000000000000000000000000000000000000000000000000000000000000009092166060830152517fc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec391611c43918490612f92565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a604051602001611c739998979695949392919061300f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b8251825160009190818303611d3b576040517f11a6b26400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101018211801590611d4f57506101018111155b611d85576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82820101610100811115611de6576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003611e135786600081518110611e0157611e01612d5e565b60200260200101519350505050612014565b60008167ffffffffffffffff811115611e2e57611e2e612726565b604051908082528060200260200182016040528015611e57578160200160208202803683370190505b50905060008080805b85811015611f9a5760006001821b8b811603611ebb5788851015611ea4578c5160018601958e918110611e9557611e95612d5e565b60200260200101519050611edd565b8551600185019487918110611e9557611e95612d5e565b8b5160018401938d918110611ed257611ed2612d5e565b602002602001015190505b600089861015611f0d578d5160018701968f918110611efe57611efe612d5e565b60200260200101519050611f2f565b8651600186019588918110611f2457611f24612d5e565b602002602001015190505b82851115611f69576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f73828261251d565b878481518110611f8557611f85612d5e565b60209081029190910101525050600101611e60565b506001850382148015611fac57508683145b8015611fb757508581145b611fed576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600186038151811061200257612002612d5e565b60200260200101519750505050505050505b9392505050565b6009546d0100000000000000000000000000900460ff1615612069576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f89190612cf6565b1561212f576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061213d8385018561319b565b8051515190915015158061215657508051602001515115155b1561228e5760095464ffffffffff8084166801000000000000000090920416101561225357600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff166801000000000000000064ffffffffff85160217905560085481516040517f3937306f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691633937306f9161220d916004016133ee565b600060405180830381600087803b15801561222757600080fd5b505af115801561223b573d6000803e3d6000fd5b50505050604081015161224e5750505050565b61228e565b604081015161228e576040517ff803a2ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101515160095467ffffffffffffffff90811691161415806122c9575060208082015190810151905167ffffffffffffffff9182169116115b156123065780602001516040517fbb1ae18d0000000000000000000000000000000000000000000000000000000081526004016106399190613401565b6040810151612341576040517f504570e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040808201516000908152600a60205220541561238a576040517fa0bce24f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602080820151015161239d906001613426565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790556040818101516000908152600a602052819020429055517f291698c01aa71f912280535d88a00d2c59fb63530a3f5d0098560468acb9ebf59061241a90839061344e565b60405180910390a150505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036124a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610639565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600081831061255f5760408051600160208083019190915281830185905260608083018790528351808403909101815260809092019092528051910120612014565b60408051600160208083019190915281830186905260608083018690528351808403909101815260809092019092528051910120612014565b828054828255906000526020600020908101928215612612579160200282015b8281111561261257825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906125b8565b5061261e929150612641565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b8082111561261e5760008155600101612642565b60808101611a0a828467ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b6000815180845260005b818110156126d5576020818501810151868301820152016126b9565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061201460208301846126af565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561277857612778612726565b60405290565b6040516060810167ffffffffffffffff8111828210171561277857612778612726565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156127e8576127e8612726565b604052919050565b600067ffffffffffffffff82111561280a5761280a612726565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461189a57600080fd5b600082601f83011261284757600080fd5b8135602061285c612857836127f0565b6127a1565b82815260059290921b8401810191818101908684111561287b57600080fd5b8286015b8481101561289f57803561289281612814565b835291830191830161287f565b509695505050505050565b803560ff811681146128bb57600080fd5b919050565b600082601f8301126128d157600080fd5b813567ffffffffffffffff8111156128eb576128eb612726565b61291c60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016127a1565b81815284602083860101111561293157600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff811681146128bb57600080fd5b60008060008060008060c0878903121561297f57600080fd5b863567ffffffffffffffff8082111561299757600080fd5b6129a38a838b01612836565b975060208901359150808211156129b957600080fd5b6129c58a838b01612836565b96506129d360408a016128aa565b955060608901359150808211156129e957600080fd5b6129f58a838b016128c0565b9450612a0360808a0161294e565b935060a0890135915080821115612a1957600080fd5b50612a2689828a016128c0565b9150509295509295509295565b600060208284031215612a4557600080fd5b813564ffffffffff8116811461201457600080fd5b60008083601f840112612a6c57600080fd5b50813567ffffffffffffffff811115612a8457600080fd5b6020830191508360208260051b8501011115612a9f57600080fd5b9250929050565b600080600080600060608688031215612abe57600080fd5b853567ffffffffffffffff80821115612ad657600080fd5b612ae289838a01612a5a565b90975095506020880135915080821115612afb57600080fd5b50612b0888828901612a5a565b96999598509660400135949350505050565b600081518084526020808501945080840160005b83811015612b6057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101612b2e565b509495945050505050565b6020815260006120146020830184612b1a565b600060208284031215612b9057600080fd5b5035919050565b600060208284031215612ba957600080fd5b6120148261294e565b60008060008060008060008060e0898b031215612bce57600080fd5b606089018a811115612bdf57600080fd5b8998503567ffffffffffffffff80821115612bf957600080fd5b818b0191508b601f830112612c0d57600080fd5b813581811115612c1c57600080fd5b8c6020828501011115612c2e57600080fd5b6020830199508098505060808b0135915080821115612c4c57600080fd5b612c588c838d01612a5a565b909750955060a08b0135915080821115612c7157600080fd5b50612c7e8b828c01612a5a565b999c989b50969995989497949560c00135949350505050565b600060208284031215612ca957600080fd5b813561201481612814565b60008060208385031215612cc757600080fd5b823567ffffffffffffffff811115612cde57600080fd5b612cea85828601612a5a565b90969095509350505050565b600060208284031215612d0857600080fd5b8151801515811461201457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417611a0a57611a0a612d18565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dbe57612dbe612d18565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600063ffffffff808316818103612e0d57612e0d612d18565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152612e478184018a612b1a565b90508281036080840152612e5b8189612b1a565b905060ff871660a084015282810360c0840152612e7881876126af565b905067ffffffffffffffff851660e0840152828103610100840152612e9d81856126af565b9c9b505050505050505050505050565b60ff8181168382160190811115611a0a57611a0a612d18565b600060ff831680612f00577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b80820180821115611a0a57611a0a612d18565b8183823760009101908152919050565b828152606082602083013760800192915050565b600060208284031215612f5857600080fd5b6040516020810181811067ffffffffffffffff82111715612f7b57612f7b612726565b6040528251612f8981612814565b81529392505050565b60a08101612feb828567ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b73ffffffffffffffffffffffffffffffffffffffff83511660808301529392505050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526130568285018b612b1a565b9150838203608085015261306a828a612b1a565b915060ff881660a085015283820360c085015261308782886126af565b90861660e08501528381036101008501529050612e9d81856126af565b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146128bb57600080fd5b600082601f8301126130e157600080fd5b813560206130f1612857836127f0565b82815260069290921b8401810191818101908684111561311057600080fd5b8286015b8481101561289f576040818903121561312d5760008081fd5b613135612755565b61313e8261294e565b815261314b8583016130a4565b81860152835291830191604001613114565b60006040828403121561316f57600080fd5b613177612755565b90506131828261294e565b81526131906020830161294e565b602082015292915050565b600060208083850312156131ae57600080fd5b823567ffffffffffffffff808211156131c657600080fd5b90840190608082870312156131da57600080fd5b6131e261277e565b8235828111156131f157600080fd5b8301604081890381131561320457600080fd5b61320c612755565b82358581111561321b57600080fd5b8301601f81018b1361322c57600080fd5b803561323a612857826127f0565b81815260069190911b8201890190898101908d83111561325957600080fd5b928a01925b828410156132a95785848f0312156132765760008081fd5b61327e612755565b843561328981612814565b8152613296858d016130a4565b818d0152825292850192908a019061325e565b845250505082870135858111156132bf57600080fd5b6132cb8b8286016130d0565b828901525083526132de8986880161315d565b8684015260608501358184015250508094505050505092915050565b805160408084528151848201819052600092602091908201906060870190855b81811015613373578351805173ffffffffffffffffffffffffffffffffffffffff1684528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1685840152928401929185019160010161331a565b50508583015187820388850152805180835290840192506000918401905b808310156133e2578351805167ffffffffffffffff1683528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1685830152928401926001929092019190850190613391565b50979650505050505050565b60208152600061201460208301846132fa565b60408101611a0a8284805167ffffffffffffffff908116835260209182015116910152565b67ffffffffffffffff81811683821601908082111561344757613447612d18565b5092915050565b60208152600082516080602084015261346a60a08401826132fa565b905060208401516134956040850182805167ffffffffffffffff908116835260209182015116910152565b5060408401516080840152809150509291505056fea164736f6c6343000813000a",
+}
+
+var CommitStoreABI = CommitStoreMetaData.ABI
+
+var CommitStoreBin = CommitStoreMetaData.Bin
+
+func DeployCommitStore(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig CommitStoreStaticConfig) (common.Address, *types.Transaction, *CommitStore, error) {
+ parsed, err := CommitStoreMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CommitStoreBin), backend, staticConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &CommitStore{address: address, abi: *parsed, CommitStoreCaller: CommitStoreCaller{contract: contract}, CommitStoreTransactor: CommitStoreTransactor{contract: contract}, CommitStoreFilterer: CommitStoreFilterer{contract: contract}}, nil
+}
+
+type CommitStore struct {
+ address common.Address
+ abi abi.ABI
+ CommitStoreCaller
+ CommitStoreTransactor
+ CommitStoreFilterer
+}
+
+type CommitStoreCaller struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreTransactor struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreFilterer struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreSession struct {
+ Contract *CommitStore
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreCallerSession struct {
+ Contract *CommitStoreCaller
+ CallOpts bind.CallOpts
+}
+
+type CommitStoreTransactorSession struct {
+ Contract *CommitStoreTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreRaw struct {
+ Contract *CommitStore
+}
+
+type CommitStoreCallerRaw struct {
+ Contract *CommitStoreCaller
+}
+
+type CommitStoreTransactorRaw struct {
+ Contract *CommitStoreTransactor
+}
+
+func NewCommitStore(address common.Address, backend bind.ContractBackend) (*CommitStore, error) {
+ abi, err := abi.JSON(strings.NewReader(CommitStoreABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindCommitStore(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStore{address: address, abi: abi, CommitStoreCaller: CommitStoreCaller{contract: contract}, CommitStoreTransactor: CommitStoreTransactor{contract: contract}, CommitStoreFilterer: CommitStoreFilterer{contract: contract}}, nil
+}
+
+func NewCommitStoreCaller(address common.Address, caller bind.ContractCaller) (*CommitStoreCaller, error) {
+ contract, err := bindCommitStore(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreCaller{contract: contract}, nil
+}
+
+func NewCommitStoreTransactor(address common.Address, transactor bind.ContractTransactor) (*CommitStoreTransactor, error) {
+ contract, err := bindCommitStore(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreTransactor{contract: contract}, nil
+}
+
+func NewCommitStoreFilterer(address common.Address, filterer bind.ContractFilterer) (*CommitStoreFilterer, error) {
+ contract, err := bindCommitStore(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreFilterer{contract: contract}, nil
+}
+
+func bindCommitStore(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := CommitStoreMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_CommitStore *CommitStoreRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStore.Contract.CommitStoreCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStore *CommitStoreRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.Contract.CommitStoreTransactor.contract.Transfer(opts)
+}
+
+func (_CommitStore *CommitStoreRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStore.Contract.CommitStoreTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStore *CommitStoreCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStore.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStore *CommitStoreTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.Contract.contract.Transfer(opts)
+}
+
+func (_CommitStore *CommitStoreTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStore.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStore *CommitStoreCaller) GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(CommitStoreDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreDynamicConfig)).(*CommitStoreDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStore.Contract.GetDynamicConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStore.Contract.GetDynamicConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStore.Contract.GetExpectedNextSequenceNumber(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStore.Contract.GetExpectedNextSequenceNumber(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getLatestPriceEpochAndRound")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStore.Contract.GetLatestPriceEpochAndRound(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStore.Contract.GetLatestPriceEpochAndRound(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getMerkleRoot", root)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStore.Contract.GetMerkleRoot(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStore.Contract.GetMerkleRoot(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCaller) GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(CommitStoreStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreStaticConfig)).(*CommitStoreStaticConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStore.Contract.GetStaticConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStore.Contract.GetStaticConfig(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStore.Contract.GetTransmitters(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStore.Contract.GetTransmitters(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) IsARMHealthy(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "isARMHealthy")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) IsARMHealthy() (bool, error) {
+ return _CommitStore.Contract.IsARMHealthy(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) IsARMHealthy() (bool, error) {
+ return _CommitStore.Contract.IsARMHealthy(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "isBlessed", root)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStore.Contract.IsBlessed(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCallerSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStore.Contract.IsBlessed(&_CommitStore.CallOpts, root)
+}
+
+func (_CommitStore *CommitStoreCaller) IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "isUnpausedAndARMHealthy")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) IsUnpausedAndARMHealthy() (bool, error) {
+ return _CommitStore.Contract.IsUnpausedAndARMHealthy(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) IsUnpausedAndARMHealthy() (bool, error) {
+ return _CommitStore.Contract.IsUnpausedAndARMHealthy(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStore *CommitStoreSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDetails(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDetails(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStore *CommitStoreSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDigestAndEpoch(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStore.Contract.LatestConfigDigestAndEpoch(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Owner() (common.Address, error) {
+ return _CommitStore.Contract.Owner(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Owner() (common.Address, error) {
+ return _CommitStore.Contract.Owner(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Paused(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "paused")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Paused() (bool, error) {
+ return _CommitStore.Contract.Paused(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Paused() (bool, error) {
+ return _CommitStore.Contract.Paused(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) TypeAndVersion() (string, error) {
+ return _CommitStore.Contract.TypeAndVersion(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCallerSession) TypeAndVersion() (string, error) {
+ return _CommitStore.Contract.TypeAndVersion(&_CommitStore.CallOpts)
+}
+
+func (_CommitStore *CommitStoreCaller) Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStore.contract.Call(opts, &out, "verify", hashedLeaves, proofs, proofFlagBits)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStore *CommitStoreSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStore.Contract.Verify(&_CommitStore.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStore *CommitStoreCallerSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStore.Contract.Verify(&_CommitStore.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStore *CommitStoreTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_CommitStore *CommitStoreSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStore.Contract.AcceptOwnership(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStore.Contract.AcceptOwnership(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "pause")
+}
+
+func (_CommitStore *CommitStoreSession) Pause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Pause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Pause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Pause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactor) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "resetUnblessedRoots", rootToReset)
+}
+
+func (_CommitStore *CommitStoreSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.ResetUnblessedRoots(&_CommitStore.TransactOpts, rootToReset)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.ResetUnblessedRoots(&_CommitStore.TransactOpts, rootToReset)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setLatestPriceEpochAndRound", latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetLatestPriceEpochAndRound(&_CommitStore.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetLatestPriceEpochAndRound(&_CommitStore.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setMinSeqNr", minSeqNr)
+}
+
+func (_CommitStore *CommitStoreSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetMinSeqNr(&_CommitStore.TransactOpts, minSeqNr)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetMinSeqNr(&_CommitStore.TransactOpts, minSeqNr)
+}
+
+func (_CommitStore *CommitStoreTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetOCR2Config(&_CommitStore.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.SetOCR2Config(&_CommitStore.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStore *CommitStoreTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_CommitStore *CommitStoreSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStore.Contract.TransferOwnership(&_CommitStore.TransactOpts, to)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStore.Contract.TransferOwnership(&_CommitStore.TransactOpts, to)
+}
+
+func (_CommitStore *CommitStoreTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.Transmit(&_CommitStore.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStore.Contract.Transmit(&_CommitStore.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStore *CommitStoreTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStore.contract.Transact(opts, "unpause")
+}
+
+func (_CommitStore *CommitStoreSession) Unpause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Unpause(&_CommitStore.TransactOpts)
+}
+
+func (_CommitStore *CommitStoreTransactorSession) Unpause() (*types.Transaction, error) {
+ return _CommitStore.Contract.Unpause(&_CommitStore.TransactOpts)
+}
+
+type CommitStoreConfigSetIterator struct {
+ Event *CommitStoreConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreConfigSet)
+ 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(CommitStoreConfigSet)
+ 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 *CommitStoreConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreConfigSet struct {
+ StaticConfig CommitStoreStaticConfig
+ DynamicConfig CommitStoreDynamicConfig
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreConfigSetIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreConfigSetIterator{contract: _CommitStore.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreConfigSet)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet", 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 (_CommitStore *CommitStoreFilterer) ParseConfigSet(log types.Log) (*CommitStoreConfigSet, error) {
+ event := new(CommitStoreConfigSet)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreConfigSet0Iterator struct {
+ Event *CommitStoreConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreConfigSet0)
+ 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(CommitStoreConfigSet0)
+ 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 *CommitStoreConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreConfigSet0Iterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreConfigSet0Iterator{contract: _CommitStore.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreConfigSet0)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet0", 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 (_CommitStore *CommitStoreFilterer) ParseConfigSet0(log types.Log) (*CommitStoreConfigSet0, error) {
+ event := new(CommitStoreConfigSet0)
+ if err := _CommitStore.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreOwnershipTransferRequestedIterator struct {
+ Event *CommitStoreOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreOwnershipTransferRequested)
+ 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(CommitStoreOwnershipTransferRequested)
+ 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 *CommitStoreOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreOwnershipTransferRequestedIterator{contract: _CommitStore.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreOwnershipTransferRequested)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_CommitStore *CommitStoreFilterer) ParseOwnershipTransferRequested(log types.Log) (*CommitStoreOwnershipTransferRequested, error) {
+ event := new(CommitStoreOwnershipTransferRequested)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreOwnershipTransferredIterator struct {
+ Event *CommitStoreOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreOwnershipTransferred)
+ 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(CommitStoreOwnershipTransferred)
+ 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 *CommitStoreOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreOwnershipTransferredIterator{contract: _CommitStore.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreOwnershipTransferred)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferred", 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 (_CommitStore *CommitStoreFilterer) ParseOwnershipTransferred(log types.Log) (*CommitStoreOwnershipTransferred, error) {
+ event := new(CommitStoreOwnershipTransferred)
+ if err := _CommitStore.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStorePausedIterator struct {
+ Event *CommitStorePaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStorePausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStorePaused)
+ 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(CommitStorePaused)
+ 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 *CommitStorePausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStorePausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStorePaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterPaused(opts *bind.FilterOpts) (*CommitStorePausedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStorePausedIterator{contract: _CommitStore.contract, event: "Paused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStorePaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStorePaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Paused", 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 (_CommitStore *CommitStoreFilterer) ParsePaused(log types.Log) (*CommitStorePaused, error) {
+ event := new(CommitStorePaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Paused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreReportAcceptedIterator struct {
+ Event *CommitStoreReportAccepted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreReportAcceptedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreReportAccepted)
+ 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(CommitStoreReportAccepted)
+ 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 *CommitStoreReportAcceptedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreReportAcceptedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreReportAccepted struct {
+ Report CommitStoreCommitReport
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreReportAcceptedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreReportAcceptedIterator{contract: _CommitStore.contract, event: "ReportAccepted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreReportAccepted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreReportAccepted)
+ if err := _CommitStore.contract.UnpackLog(event, "ReportAccepted", 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 (_CommitStore *CommitStoreFilterer) ParseReportAccepted(log types.Log) (*CommitStoreReportAccepted, error) {
+ event := new(CommitStoreReportAccepted)
+ if err := _CommitStore.contract.UnpackLog(event, "ReportAccepted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreRootRemovedIterator struct {
+ Event *CommitStoreRootRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreRootRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreRootRemoved)
+ 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(CommitStoreRootRemoved)
+ 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 *CommitStoreRootRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreRootRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreRootRemoved struct {
+ Root [32]byte
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreRootRemovedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreRootRemovedIterator{contract: _CommitStore.contract, event: "RootRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreRootRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreRootRemoved)
+ if err := _CommitStore.contract.UnpackLog(event, "RootRemoved", 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 (_CommitStore *CommitStoreFilterer) ParseRootRemoved(log types.Log) (*CommitStoreRootRemoved, error) {
+ event := new(CommitStoreRootRemoved)
+ if err := _CommitStore.contract.UnpackLog(event, "RootRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreTransmittedIterator struct {
+ Event *CommitStoreTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreTransmitted)
+ 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(CommitStoreTransmitted)
+ 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 *CommitStoreTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreTransmittedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreTransmittedIterator{contract: _CommitStore.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreTransmitted)
+ if err := _CommitStore.contract.UnpackLog(event, "Transmitted", 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 (_CommitStore *CommitStoreFilterer) ParseTransmitted(log types.Log) (*CommitStoreTransmitted, error) {
+ event := new(CommitStoreTransmitted)
+ if err := _CommitStore.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreUnpausedIterator struct {
+ Event *CommitStoreUnpaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreUnpausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreUnpaused)
+ 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(CommitStoreUnpaused)
+ 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 *CommitStoreUnpausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreUnpausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreUnpaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStore *CommitStoreFilterer) FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreUnpausedIterator, error) {
+
+ logs, sub, err := _CommitStore.contract.FilterLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreUnpausedIterator{contract: _CommitStore.contract, event: "Unpaused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStore *CommitStoreFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreUnpaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStore.contract.WatchLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreUnpaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Unpaused", 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 (_CommitStore *CommitStoreFilterer) ParseUnpaused(log types.Log) (*CommitStoreUnpaused, error) {
+ event := new(CommitStoreUnpaused)
+ if err := _CommitStore.contract.UnpackLog(event, "Unpaused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_CommitStore *CommitStore) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _CommitStore.abi.Events["ConfigSet"].ID:
+ return _CommitStore.ParseConfigSet(log)
+ case _CommitStore.abi.Events["ConfigSet0"].ID:
+ return _CommitStore.ParseConfigSet0(log)
+ case _CommitStore.abi.Events["OwnershipTransferRequested"].ID:
+ return _CommitStore.ParseOwnershipTransferRequested(log)
+ case _CommitStore.abi.Events["OwnershipTransferred"].ID:
+ return _CommitStore.ParseOwnershipTransferred(log)
+ case _CommitStore.abi.Events["Paused"].ID:
+ return _CommitStore.ParsePaused(log)
+ case _CommitStore.abi.Events["ReportAccepted"].ID:
+ return _CommitStore.ParseReportAccepted(log)
+ case _CommitStore.abi.Events["RootRemoved"].ID:
+ return _CommitStore.ParseRootRemoved(log)
+ case _CommitStore.abi.Events["Transmitted"].ID:
+ return _CommitStore.ParseTransmitted(log)
+ case _CommitStore.abi.Events["Unpaused"].ID:
+ return _CommitStore.ParseUnpaused(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (CommitStoreConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec3")
+}
+
+func (CommitStoreConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (CommitStoreOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (CommitStoreOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (CommitStorePaused) Topic() common.Hash {
+ return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258")
+}
+
+func (CommitStoreReportAccepted) Topic() common.Hash {
+ return common.HexToHash("0x291698c01aa71f912280535d88a00d2c59fb63530a3f5d0098560468acb9ebf5")
+}
+
+func (CommitStoreRootRemoved) Topic() common.Hash {
+ return common.HexToHash("0x202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12")
+}
+
+func (CommitStoreTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (CommitStoreUnpaused) Topic() common.Hash {
+ return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa")
+}
+
+func (_CommitStore *CommitStore) Address() common.Address {
+ return _CommitStore.address
+}
+
+type CommitStoreInterface interface {
+ GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error)
+
+ GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ IsARMHealthy(opts *bind.CallOpts) (bool, error)
+
+ IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error)
+
+ IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ Paused(opts *bind.CallOpts) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Pause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error)
+
+ SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error)
+
+ SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ Unpause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*CommitStoreConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*CommitStoreConfigSet0, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*CommitStoreOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*CommitStoreOwnershipTransferred, error)
+
+ FilterPaused(opts *bind.FilterOpts) (*CommitStorePausedIterator, error)
+
+ WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStorePaused) (event.Subscription, error)
+
+ ParsePaused(log types.Log) (*CommitStorePaused, error)
+
+ FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreReportAcceptedIterator, error)
+
+ WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreReportAccepted) (event.Subscription, error)
+
+ ParseReportAccepted(log types.Log) (*CommitStoreReportAccepted, error)
+
+ FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreRootRemovedIterator, error)
+
+ WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreRootRemoved) (event.Subscription, error)
+
+ ParseRootRemoved(log types.Log) (*CommitStoreRootRemoved, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*CommitStoreTransmitted, error)
+
+ FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreUnpausedIterator, error)
+
+ WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreUnpaused) (event.Subscription, error)
+
+ ParseUnpaused(log types.Log) (*CommitStoreUnpaused, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/commit_store_helper/commit_store_helper.go b/core/gethwrappers/ccip/generated/commit_store_helper/commit_store_helper.go
new file mode 100644
index 00000000000..b314d6c75b4
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/commit_store_helper/commit_store_helper.go
@@ -0,0 +1,2205 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package commit_store_helper
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommitStoreCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ Interval CommitStoreInterval
+ MerkleRoot [32]byte
+}
+
+type CommitStoreDynamicConfig struct {
+ PriceRegistry common.Address
+}
+
+type CommitStoreInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type CommitStoreStaticConfig struct {
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ RmnProxy common.Address
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var CommitStoreHelperMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCommitStoreConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enumOCR2Base.InvalidConfigErrorType\",\"name\":\"errorType\",\"type\":\"uint8\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"}],\"name\":\"InvalidInterval\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRoot\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LeavesCannotBeEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PausedError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootAlreadyCommitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":false,\"internalType\":\"uint40\",\"name\":\"oldEpochAndRound\",\"type\":\"uint40\"},{\"indexed\":false,\"internalType\":\"uint40\",\"name\":\"newEpochAndRound\",\"type\":\"uint40\"}],\"name\":\"LatestPriceEpochAndRoundSet\",\"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\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structCommitStore.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"ReportAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"RootRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"oldSeqNum\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSeqNum\",\"type\":\"uint64\"}],\"name\":\"SequenceNumberSet\",\"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\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLatestPriceEpochAndRound\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"getMerkleRoot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isUnpausedAndNotCursed\",\"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\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"commitReport\",\"type\":\"bytes\"},{\"internalType\":\"uint40\",\"name\":\"epochAndRound\",\"type\":\"uint40\"}],\"name\":\"report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"rootToReset\",\"type\":\"bytes32[]\"}],\"name\":\"resetUnblessedRoots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint40\",\"name\":\"latestPriceEpochAndRound\",\"type\":\"uint40\"}],\"name\":\"setLatestPriceEpochAndRound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"}],\"name\":\"setMinSeqNr\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"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\":\"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\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedLeaves\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x61014060405260098054600165ff000000000160401b03191660011790553480156200002a57600080fd5b506040516200382a3803806200382a8339810160408190526200004d9162000274565b80600033808281620000a65760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d957620000d98162000194565b50505015156080524660a05260408101516001600160a01b0316158062000108575080516001600160401b0316155b806200011f575060208101516001600160401b0316155b8062000136575060608101516001600160a01b0316155b156200015557604051631fc5f15f60e11b815260040160405180910390fd5b80516001600160401b0390811660c05260208201511660e05260408101516001600160a01b039081166101005260609091015116610120525062000308565b336001600160a01b03821603620001ee5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160401b03811681146200025757600080fd5b919050565b80516001600160a01b03811681146200025757600080fd5b6000608082840312156200028757600080fd5b604051608081016001600160401b0381118282101715620002b857634e487b7160e01b600052604160045260246000fd5b604052620002c6836200023f565b8152620002d6602084016200023f565b6020820152620002e9604084016200025c565b6040820152620002fc606084016200025c565b60608201529392505050565b60805160a05160c05160e051610100516101205161348c6200039e6000396000818161026d015281816116f6015281816118a5015281816119cf0152611f5d0152600081816102310152611f36015260008181610201015281816116b00152818161198c0152611f0f0152600081816101d10152611ee00152600081816110f60152611142015260006111bd015261348c6000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c806379ba5097116100e3578063afcb95d71161008c578063f2fde38b11610066578063f2fde38b14610501578063f47a869014610514578063ff888fb11461052757600080fd5b8063afcb95d7146104c6578063b1dc65a4146104e6578063e89d039f146104f957600080fd5b80638da5cb5b116100bd5780638da5cb5b1461046b578063a7206cd614610493578063ad7a22f8146104b357600080fd5b806379ba50971461042b57806381ff7048146104335780638456cb591461046357600080fd5b806332048875116101455780635c975abb1161011f5780635c975abb146103af578063666cab8d146103d75780637437ff9f146103ec57600080fd5b806332048875146103745780633f4ba83a146103955780634120fccd1461039d57600080fd5b80631dc18e56116101765780631dc18e56146103395780631ef381741461034e57806329b980e41461036157600080fd5b806306285c691461019d57806310c374ed146102c0578063181f5a77146102f0575b600080fd5b6102aa60408051608081018252600080825260208201819052918101829052606081019190915260405180608001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516102b791906125ac565b60405180910390f35b60095468010000000000000000900464ffffffffff165b60405167ffffffffffffffff90911681526020016102b7565b61032c6040518060400160405280601581526020017f436f6d6d697453746f726520312e352e302d646576000000000000000000000081525081565b6040516102b79190612669565b61034c6103473660046126df565b61053a565b005b61034c61035c366004612972565b61054a565b61034c61036f366004612a3f565b610c2e565b610387610382366004612a9f565b610cbe565b6040519081526020016102b7565b61034c610db4565b60095467ffffffffffffffff166102d7565b6009546d0100000000000000000000000000900460ff165b60405190151581526020016102b7565b6103df610e1a565b6040516102b79190612b65565b604080516020808201835260009091528151808201835260085473ffffffffffffffffffffffffffffffffffffffff16908190529151918252016102b7565b61034c610e89565b6004546002546040805163ffffffff808516825264010000000090940490931660208401528201526060016102b7565b61034c610f86565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102b7565b6103876104a1366004612b78565b6000908152600a602052604090205490565b61034c6104c1366004612b91565b610ff6565b6040805160018152600060208201819052918101919091526060016102b7565b61034c6104f4366004612bac565b611071565b6103c7611688565b61034c61050f366004612c63565b61179c565b61034c610522366004612c80565b6117b0565b6103c7610535366004612b78565b611842565b610545838383611916565b505050565b855185518560ff16601f8311156105995760016040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105909190612cf1565b60405180910390fd5b806000036105d65760006040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105909190612cf1565b8183146106125760046040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105909190612cf1565b61061d816003612d61565b83116106585760026040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105909190612cf1565b610660611d7f565b61066986611e02565b60065460005b8181101561075d57600560006006838154811061068e5761068e612d78565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055600780546005929190849081106106fe576106fe612d78565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560010161066f565b50895160005b81811015610ad65760008c828151811061077f5761077f612d78565b602002602001015190506000600281111561079c5761079c612cc2565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff1660028111156107db576107db612cc2565b146108155760036040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105909190612cf1565b73ffffffffffffffffffffffffffffffffffffffff8116610862576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016001905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561091257610912612cc2565b021790555090505060008c838151811061092e5761092e612d78565b602002602001015190506000600281111561094b5761094b612cc2565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff16600281111561098a5761098a612cc2565b146109c45760036040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016105909190612cf1565b73ffffffffffffffffffffffffffffffffffffffff8116610a11576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff84168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610ac157610ac1612cc2565b02179055509050505050806001019050610763565b508a51610aea9060069060208e01906124ee565b508951610afe9060079060208d01906124ee565b506003805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908c161717905560048054610b84914691309190600090610b569063ffffffff16612da7565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168e8e8e8e8e8e611fb2565b600260000181905550600060048054906101000a900463ffffffff169050436004806101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600260000154600460009054906101000a900463ffffffff168f8f8f8f8f8f604051610c1899989796959493929190612dca565b60405180910390a1505050505050505050505050565b610c36611d7f565b6009805464ffffffffff838116680100000000000000008181027fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff85161790945560408051949093049091168084526020840191909152917ff0d557bfce33e354b41885eb9264448726cfe51f486ffa69809d2bf56545644491015b60405180910390a15050565b6009546000906d0100000000000000000000000000900460ff1615610d0f576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d8087878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a92508991829185019084908082843760009201919091525088925061205d915050565b9050610d8b81611842565b610d99576000915050610dab565b6000908152600a602052604090205490505b95945050505050565b610dbc611d7f565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b60606007805480602002602001604051908101604052809291908181526020018280548015610e7f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e54575b5050505050905090565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610590565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610f8e611d7f565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff166d01000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610e10565b610ffe611d7f565b6009805467ffffffffffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000083168117909355604080519190921680825260208201939093527fea59e8027e41fda1525220008cf2416797405065eb21b0ebd417bfc6d361b8de9101610cb2565b611080878760208b0135611916565b6040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925289359182146110f35780516040517f93df584c000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610590565b467f000000000000000000000000000000000000000000000000000000000000000014611174576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610590565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a160007f000000000000000000000000000000000000000000000000000000000000000015611216576002826020015183604001516111f79190612e60565b6112019190612e79565b61120c906001612e60565b60ff16905061122c565b6020820151611226906001612e60565b60ff1690505b868114611265576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b86851461129e576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156112e1576112e1612cc2565b60028111156112f2576112f2612cc2565b905250905060028160200151600281111561130f5761130f612cc2565b14801561135657506007816000015160ff168154811061133157611331612d78565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b61138c576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600061139a866020612d61565b6113a5896020612d61565b6113b18c610144612ec2565b6113bb9190612ec2565b6113c59190612ec2565b9050368114611409576040517f8e1192e100000000000000000000000000000000000000000000000000000000815260048101829052366024820152604401610590565b5060008a8a60405161141c929190612ed5565b604051908190038120611433918e90602001612ee5565b604051602081830303815290604052805190602001209050611453612578565b8860005b818110156116775760006001858a846020811061147657611476612d78565b61148391901a601b612e60565b8f8f8681811061149557611495612d78565b905060200201358e8e878181106114ae576114ae612d78565b90506020020135604051600081526020016040526040516114eb949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561150d573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152848220848601909552845460ff808216865293975091955092939284019161010090910416600281111561159057611590612cc2565b60028111156115a1576115a1612cc2565b90525090506001816020015160028111156115be576115be612cc2565b146115f5576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f811061160c5761160c612d78565b602002015115611648576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f811061166357611663612d78565b911515602090920201525050600101611457565b505050505050505050505050505050565b6040517f2cbc26bb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060801b77ffffffffffffffff000000000000000000000000000000001660048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611752573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117769190612ef9565b15801561179757506009546d0100000000000000000000000000900460ff16155b905090565b6117a4611d7f565b6117ad8161237e565b50565b6117b8611d7f565b60005b818110156105455760008383838181106117d7576117d7612d78565b9050602002013590506117e981611842565b611839576000818152600a602052604080822091909155517f202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12906118309083815260200190565b60405180910390a15b506001016117bb565b6040805180820182523081526020810183815291517f4d616771000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9081166004830152915160248201526000917f00000000000000000000000000000000000000000000000000000000000000001690634d61677190604401602060405180830381865afa1580156118ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119109190612ef9565b92915050565b6009546d0100000000000000000000000000900460ff1615611964576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f2cbc26bb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060801b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611a2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4f9190612ef9565b15611a86576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611a9483850185613012565b80515151909150151580611aad57508051602001515115155b15611be55760095464ffffffffff80841668010000000000000000909204161015611baa57600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff166801000000000000000064ffffffffff85160217905560085481516040517f3937306f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691633937306f91611b6491600401613265565b600060405180830381600087803b158015611b7e57600080fd5b505af1158015611b92573d6000803e3d6000fd5b505050506040810151611ba55750505050565b611be5565b6040810151611be5576040517ff803a2ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101515160095467ffffffffffffffff9081169116141580611c20575060208082015190810151905167ffffffffffffffff9182169116115b15611c5d5780602001516040517fbb1ae18d0000000000000000000000000000000000000000000000000000000081526004016105909190613278565b6040810151611c98576040517f504570e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040808201516000908152600a602052205415611ce1576040517fa0bce24f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808201510151611cf490600161329d565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790556040818101516000908152600a602052819020429055517f291698c01aa71f912280535d88a00d2c59fb63530a3f5d0098560468acb9ebf590611d719083906132c5565b60405180910390a150505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611e00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610590565b565b600081806020019051810190611e189190613321565b805190915073ffffffffffffffffffffffffffffffffffffffff16611e69576040517f3f8be2be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff169055604080516080810182527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff90811682527f00000000000000000000000000000000000000000000000000000000000000001660208201527f00000000000000000000000000000000000000000000000000000000000000008316818301527f00000000000000000000000000000000000000000000000000000000000000009092166060830152517fc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec391610cb291849061336d565b6000808a8a8a8a8a8a8a8a8a604051602001611fd6999897969594939291906133ea565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b825182516000919081830361209e576040517f11a6b26400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61010182118015906120b257506101018111155b6120e8576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82820101610100811115612149576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003612176578660008151811061216457612164612d78565b60200260200101519350505050612377565b60008167ffffffffffffffff81111561219157612191612733565b6040519080825280602002602001820160405280156121ba578160200160208202803683370190505b50905060008080805b858110156122fd5760006001821b8b81160361221e5788851015612207578c5160018601958e9181106121f8576121f8612d78565b60200260200101519050612240565b85516001850194879181106121f8576121f8612d78565b8b5160018401938d91811061223557612235612d78565b602002602001015190505b600089861015612270578d5160018701968f91811061226157612261612d78565b60200260200101519050612292565b865160018601958891811061228757612287612d78565b602002602001015190505b828511156122cc576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6122d68282612473565b8784815181106122e8576122e8612d78565b602090810291909101015250506001016121c3565b50600185038214801561230f57508683145b801561231a57508581145b612350576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600186038151811061236557612365612d78565b60200260200101519750505050505050505b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036123fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610590565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008183106124b55760408051600160208083019190915281830185905260608083018790528351808403909101815260809092019092528051910120612377565b60408051600160208083019190915281830186905260608083018690528351808403909101815260809092019092528051910120612377565b828054828255906000526020600020908101928215612568579160200282015b8281111561256857825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90911617825560209092019160019091019061250e565b50612574929150612597565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b808211156125745760008155600101612598565b60808101611910828467ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b6000815180845260005b8181101561262b5760208185018101518683018201520161260f565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006123776020830184612605565b60008083601f84011261268e57600080fd5b50813567ffffffffffffffff8111156126a657600080fd5b6020830191508360208285010111156126be57600080fd5b9250929050565b803564ffffffffff811681146126da57600080fd5b919050565b6000806000604084860312156126f457600080fd5b833567ffffffffffffffff81111561270b57600080fd5b6127178682870161267c565b909450925061272a9050602085016126c5565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561278557612785612733565b60405290565b6040516060810167ffffffffffffffff8111828210171561278557612785612733565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156127f5576127f5612733565b604052919050565b600067ffffffffffffffff82111561281757612817612733565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff811681146117ad57600080fd5b600082601f83011261285457600080fd5b81356020612869612864836127fd565b6127ae565b8083825260208201915060208460051b87010193508684111561288b57600080fd5b602086015b848110156128b05780356128a381612821565b8352918301918301612890565b509695505050505050565b803560ff811681146126da57600080fd5b600082601f8301126128dd57600080fd5b813567ffffffffffffffff8111156128f7576128f7612733565b61292860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016127ae565b81815284602083860101111561293d57600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff811681146126da57600080fd5b60008060008060008060c0878903121561298b57600080fd5b863567ffffffffffffffff808211156129a357600080fd5b6129af8a838b01612843565b975060208901359150808211156129c557600080fd5b6129d18a838b01612843565b96506129df60408a016128bb565b955060608901359150808211156129f557600080fd5b612a018a838b016128cc565b9450612a0f60808a0161295a565b935060a0890135915080821115612a2557600080fd5b50612a3289828a016128cc565b9150509295509295509295565b600060208284031215612a5157600080fd5b612377826126c5565b60008083601f840112612a6c57600080fd5b50813567ffffffffffffffff811115612a8457600080fd5b6020830191508360208260051b85010111156126be57600080fd5b600080600080600060608688031215612ab757600080fd5b853567ffffffffffffffff80821115612acf57600080fd5b612adb89838a01612a5a565b90975095506020880135915080821115612af457600080fd5b50612b0188828901612a5a565b96999598509660400135949350505050565b60008151808452602080850194506020840160005b83811015612b5a57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101612b28565b509495945050505050565b6020815260006123776020830184612b13565b600060208284031215612b8a57600080fd5b5035919050565b600060208284031215612ba357600080fd5b6123778261295a565b60008060008060008060008060e0898b031215612bc857600080fd5b606089018a811115612bd957600080fd5b8998503567ffffffffffffffff80821115612bf357600080fd5b612bff8c838d0161267c565b909950975060808b0135915080821115612c1857600080fd5b612c248c838d01612a5a565b909750955060a08b0135915080821115612c3d57600080fd5b50612c4a8b828c01612a5a565b999c989b50969995989497949560c00135949350505050565b600060208284031215612c7557600080fd5b813561237781612821565b60008060208385031215612c9357600080fd5b823567ffffffffffffffff811115612caa57600080fd5b612cb685828601612a5a565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160058310612d2c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761191057611910612d32565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff808316818103612dc057612dc0612d32565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152612dfa8184018a612b13565b90508281036080840152612e0e8189612b13565b905060ff871660a084015282810360c0840152612e2b8187612605565b905067ffffffffffffffff851660e0840152828103610100840152612e508185612605565b9c9b505050505050505050505050565b60ff818116838216019081111561191057611910612d32565b600060ff831680612eb3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b8082018082111561191057611910612d32565b8183823760009101908152919050565b828152606082602083013760800192915050565b600060208284031215612f0b57600080fd5b8151801515811461237757600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146126da57600080fd5b600082601f830112612f5857600080fd5b81356020612f68612864836127fd565b82815260069290921b84018101918181019086841115612f8757600080fd5b8286015b848110156128b05760408189031215612fa45760008081fd5b612fac612762565b612fb58261295a565b8152612fc2858301612f1b565b81860152835291830191604001612f8b565b600060408284031215612fe657600080fd5b612fee612762565b9050612ff98261295a565b81526130076020830161295a565b602082015292915050565b6000602080838503121561302557600080fd5b823567ffffffffffffffff8082111561303d57600080fd5b908401906080828703121561305157600080fd5b61305961278b565b82358281111561306857600080fd5b8301604081890381131561307b57600080fd5b613083612762565b82358581111561309257600080fd5b8301601f81018b136130a357600080fd5b80356130b1612864826127fd565b81815260069190911b8201890190898101908d8311156130d057600080fd5b928a01925b828410156131205785848f0312156130ed5760008081fd5b6130f5612762565b843561310081612821565b815261310d858d01612f1b565b818d0152825292850192908a01906130d5565b84525050508287013591508482111561313857600080fd5b6131448a838501612f47565b81880152835250613159905087848601612fd4565b93810193909352506060013560408201529392505050565b805160408084528151848201819052600092602091908201906060870190855b818110156131ea578351805173ffffffffffffffffffffffffffffffffffffffff1684528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16858401529284019291850191600101613191565b50508583015187820388850152805180835290840192506000918401905b80831015613259578351805167ffffffffffffffff1683528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1685830152928401926001929092019190850190613208565b50979650505050505050565b6020815260006123776020830184613171565b604081016119108284805167ffffffffffffffff908116835260209182015116910152565b67ffffffffffffffff8181168382160190808211156132be576132be612d32565b5092915050565b6020815260008251608060208401526132e160a0840182613171565b9050602084015161330c6040850182805167ffffffffffffffff908116835260209182015116910152565b50604084015160808401528091505092915050565b60006020828403121561333357600080fd5b6040516020810181811067ffffffffffffffff8211171561335657613356612733565b604052825161336481612821565b81529392505050565b60a081016133c6828567ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b73ffffffffffffffffffffffffffffffffffffffff83511660808301529392505050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526134318285018b612b13565b91508382036080850152613445828a612b13565b915060ff881660a085015283820360c08501526134628288612605565b90861660e08501528381036101008501529050612e50818561260556fea164736f6c6343000818000a",
+}
+
+var CommitStoreHelperABI = CommitStoreHelperMetaData.ABI
+
+var CommitStoreHelperBin = CommitStoreHelperMetaData.Bin
+
+func DeployCommitStoreHelper(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig CommitStoreStaticConfig) (common.Address, *types.Transaction, *CommitStoreHelper, error) {
+ parsed, err := CommitStoreHelperMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CommitStoreHelperBin), backend, staticConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &CommitStoreHelper{address: address, abi: *parsed, CommitStoreHelperCaller: CommitStoreHelperCaller{contract: contract}, CommitStoreHelperTransactor: CommitStoreHelperTransactor{contract: contract}, CommitStoreHelperFilterer: CommitStoreHelperFilterer{contract: contract}}, nil
+}
+
+type CommitStoreHelper struct {
+ address common.Address
+ abi abi.ABI
+ CommitStoreHelperCaller
+ CommitStoreHelperTransactor
+ CommitStoreHelperFilterer
+}
+
+type CommitStoreHelperCaller struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperTransactor struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperFilterer struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperSession struct {
+ Contract *CommitStoreHelper
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreHelperCallerSession struct {
+ Contract *CommitStoreHelperCaller
+ CallOpts bind.CallOpts
+}
+
+type CommitStoreHelperTransactorSession struct {
+ Contract *CommitStoreHelperTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreHelperRaw struct {
+ Contract *CommitStoreHelper
+}
+
+type CommitStoreHelperCallerRaw struct {
+ Contract *CommitStoreHelperCaller
+}
+
+type CommitStoreHelperTransactorRaw struct {
+ Contract *CommitStoreHelperTransactor
+}
+
+func NewCommitStoreHelper(address common.Address, backend bind.ContractBackend) (*CommitStoreHelper, error) {
+ abi, err := abi.JSON(strings.NewReader(CommitStoreHelperABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindCommitStoreHelper(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelper{address: address, abi: abi, CommitStoreHelperCaller: CommitStoreHelperCaller{contract: contract}, CommitStoreHelperTransactor: CommitStoreHelperTransactor{contract: contract}, CommitStoreHelperFilterer: CommitStoreHelperFilterer{contract: contract}}, nil
+}
+
+func NewCommitStoreHelperCaller(address common.Address, caller bind.ContractCaller) (*CommitStoreHelperCaller, error) {
+ contract, err := bindCommitStoreHelper(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperCaller{contract: contract}, nil
+}
+
+func NewCommitStoreHelperTransactor(address common.Address, transactor bind.ContractTransactor) (*CommitStoreHelperTransactor, error) {
+ contract, err := bindCommitStoreHelper(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperTransactor{contract: contract}, nil
+}
+
+func NewCommitStoreHelperFilterer(address common.Address, filterer bind.ContractFilterer) (*CommitStoreHelperFilterer, error) {
+ contract, err := bindCommitStoreHelper(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperFilterer{contract: contract}, nil
+}
+
+func bindCommitStoreHelper(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := CommitStoreHelperMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStoreHelper.Contract.CommitStoreHelperCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.CommitStoreHelperTransactor.contract.Transfer(opts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.CommitStoreHelperTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStoreHelper.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.contract.Transfer(opts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(CommitStoreDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreDynamicConfig)).(*CommitStoreDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStoreHelper.Contract.GetDynamicConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStoreHelper.Contract.GetDynamicConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetExpectedNextSequenceNumber(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetExpectedNextSequenceNumber(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getLatestPriceEpochAndRound")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetLatestPriceEpochAndRound(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetLatestPriceEpochAndRound(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getMerkleRoot", root)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.GetMerkleRoot(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.GetMerkleRoot(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(CommitStoreStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreStaticConfig)).(*CommitStoreStaticConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStoreHelper.Contract.GetStaticConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStoreHelper.Contract.GetStaticConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStoreHelper.Contract.GetTransmitters(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStoreHelper.Contract.GetTransmitters(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "isBlessed", root)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStoreHelper.Contract.IsBlessed(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStoreHelper.Contract.IsBlessed(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) IsUnpausedAndNotCursed(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "isUnpausedAndNotCursed")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) IsUnpausedAndNotCursed() (bool, error) {
+ return _CommitStoreHelper.Contract.IsUnpausedAndNotCursed(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) IsUnpausedAndNotCursed() (bool, error) {
+ return _CommitStoreHelper.Contract.IsUnpausedAndNotCursed(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDetails(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDetails(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDigestAndEpoch(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDigestAndEpoch(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Owner() (common.Address, error) {
+ return _CommitStoreHelper.Contract.Owner(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Owner() (common.Address, error) {
+ return _CommitStoreHelper.Contract.Owner(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Paused(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "paused")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Paused() (bool, error) {
+ return _CommitStoreHelper.Contract.Paused(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Paused() (bool, error) {
+ return _CommitStoreHelper.Contract.Paused(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) TypeAndVersion() (string, error) {
+ return _CommitStoreHelper.Contract.TypeAndVersion(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) TypeAndVersion() (string, error) {
+ return _CommitStoreHelper.Contract.TypeAndVersion(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "verify", hashedLeaves, proofs, proofFlagBits)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.Verify(&_CommitStoreHelper.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.Verify(&_CommitStoreHelper.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.AcceptOwnership(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.AcceptOwnership(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "pause")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Pause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Pause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Pause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Pause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Report(opts *bind.TransactOpts, commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "report", commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Report(commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Report(&_CommitStoreHelper.TransactOpts, commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Report(commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Report(&_CommitStoreHelper.TransactOpts, commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "resetUnblessedRoots", rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.ResetUnblessedRoots(&_CommitStoreHelper.TransactOpts, rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.ResetUnblessedRoots(&_CommitStoreHelper.TransactOpts, rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setLatestPriceEpochAndRound", latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetLatestPriceEpochAndRound(&_CommitStoreHelper.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetLatestPriceEpochAndRound(&_CommitStoreHelper.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setMinSeqNr", minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetMinSeqNr(&_CommitStoreHelper.TransactOpts, minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetMinSeqNr(&_CommitStoreHelper.TransactOpts, minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetOCR2Config(&_CommitStoreHelper.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetOCR2Config(&_CommitStoreHelper.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.TransferOwnership(&_CommitStoreHelper.TransactOpts, to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.TransferOwnership(&_CommitStoreHelper.TransactOpts, to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Transmit(&_CommitStoreHelper.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Transmit(&_CommitStoreHelper.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "unpause")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Unpause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Unpause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Unpause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Unpause(&_CommitStoreHelper.TransactOpts)
+}
+
+type CommitStoreHelperConfigSetIterator struct {
+ Event *CommitStoreHelperConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperConfigSet)
+ 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(CommitStoreHelperConfigSet)
+ 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 *CommitStoreHelperConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperConfigSet struct {
+ StaticConfig CommitStoreStaticConfig
+ DynamicConfig CommitStoreDynamicConfig
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreHelperConfigSetIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperConfigSetIterator{contract: _CommitStoreHelper.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperConfigSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseConfigSet(log types.Log) (*CommitStoreHelperConfigSet, error) {
+ event := new(CommitStoreHelperConfigSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperConfigSet0Iterator struct {
+ Event *CommitStoreHelperConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperConfigSet0)
+ 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(CommitStoreHelperConfigSet0)
+ 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 *CommitStoreHelperConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreHelperConfigSet0Iterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperConfigSet0Iterator{contract: _CommitStoreHelper.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperConfigSet0)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet0", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseConfigSet0(log types.Log) (*CommitStoreHelperConfigSet0, error) {
+ event := new(CommitStoreHelperConfigSet0)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperLatestPriceEpochAndRoundSetIterator struct {
+ Event *CommitStoreHelperLatestPriceEpochAndRoundSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperLatestPriceEpochAndRoundSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperLatestPriceEpochAndRoundSet)
+ 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(CommitStoreHelperLatestPriceEpochAndRoundSet)
+ 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 *CommitStoreHelperLatestPriceEpochAndRoundSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperLatestPriceEpochAndRoundSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperLatestPriceEpochAndRoundSet struct {
+ OldEpochAndRound *big.Int
+ NewEpochAndRound *big.Int
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterLatestPriceEpochAndRoundSet(opts *bind.FilterOpts) (*CommitStoreHelperLatestPriceEpochAndRoundSetIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "LatestPriceEpochAndRoundSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperLatestPriceEpochAndRoundSetIterator{contract: _CommitStoreHelper.contract, event: "LatestPriceEpochAndRoundSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchLatestPriceEpochAndRoundSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperLatestPriceEpochAndRoundSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "LatestPriceEpochAndRoundSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperLatestPriceEpochAndRoundSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "LatestPriceEpochAndRoundSet", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseLatestPriceEpochAndRoundSet(log types.Log) (*CommitStoreHelperLatestPriceEpochAndRoundSet, error) {
+ event := new(CommitStoreHelperLatestPriceEpochAndRoundSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "LatestPriceEpochAndRoundSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperOwnershipTransferRequestedIterator struct {
+ Event *CommitStoreHelperOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperOwnershipTransferRequested)
+ 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(CommitStoreHelperOwnershipTransferRequested)
+ 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 *CommitStoreHelperOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperOwnershipTransferRequestedIterator{contract: _CommitStoreHelper.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperOwnershipTransferRequested)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseOwnershipTransferRequested(log types.Log) (*CommitStoreHelperOwnershipTransferRequested, error) {
+ event := new(CommitStoreHelperOwnershipTransferRequested)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperOwnershipTransferredIterator struct {
+ Event *CommitStoreHelperOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperOwnershipTransferred)
+ 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(CommitStoreHelperOwnershipTransferred)
+ 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 *CommitStoreHelperOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperOwnershipTransferredIterator{contract: _CommitStoreHelper.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperOwnershipTransferred)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferred", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseOwnershipTransferred(log types.Log) (*CommitStoreHelperOwnershipTransferred, error) {
+ event := new(CommitStoreHelperOwnershipTransferred)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperPausedIterator struct {
+ Event *CommitStoreHelperPaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperPausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperPaused)
+ 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(CommitStoreHelperPaused)
+ 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 *CommitStoreHelperPausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperPausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperPaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterPaused(opts *bind.FilterOpts) (*CommitStoreHelperPausedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperPausedIterator{contract: _CommitStoreHelper.contract, event: "Paused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperPaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperPaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Paused", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParsePaused(log types.Log) (*CommitStoreHelperPaused, error) {
+ event := new(CommitStoreHelperPaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Paused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperReportAcceptedIterator struct {
+ Event *CommitStoreHelperReportAccepted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperReportAcceptedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperReportAccepted)
+ 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(CommitStoreHelperReportAccepted)
+ 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 *CommitStoreHelperReportAcceptedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperReportAcceptedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperReportAccepted struct {
+ Report CommitStoreCommitReport
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreHelperReportAcceptedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperReportAcceptedIterator{contract: _CommitStoreHelper.contract, event: "ReportAccepted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperReportAccepted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperReportAccepted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ReportAccepted", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseReportAccepted(log types.Log) (*CommitStoreHelperReportAccepted, error) {
+ event := new(CommitStoreHelperReportAccepted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ReportAccepted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperRootRemovedIterator struct {
+ Event *CommitStoreHelperRootRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperRootRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperRootRemoved)
+ 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(CommitStoreHelperRootRemoved)
+ 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 *CommitStoreHelperRootRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperRootRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperRootRemoved struct {
+ Root [32]byte
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreHelperRootRemovedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperRootRemovedIterator{contract: _CommitStoreHelper.contract, event: "RootRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperRootRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperRootRemoved)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "RootRemoved", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseRootRemoved(log types.Log) (*CommitStoreHelperRootRemoved, error) {
+ event := new(CommitStoreHelperRootRemoved)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "RootRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperSequenceNumberSetIterator struct {
+ Event *CommitStoreHelperSequenceNumberSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperSequenceNumberSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperSequenceNumberSet)
+ 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(CommitStoreHelperSequenceNumberSet)
+ 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 *CommitStoreHelperSequenceNumberSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperSequenceNumberSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperSequenceNumberSet struct {
+ OldSeqNum uint64
+ NewSeqNum uint64
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterSequenceNumberSet(opts *bind.FilterOpts) (*CommitStoreHelperSequenceNumberSetIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "SequenceNumberSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperSequenceNumberSetIterator{contract: _CommitStoreHelper.contract, event: "SequenceNumberSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchSequenceNumberSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperSequenceNumberSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "SequenceNumberSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperSequenceNumberSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "SequenceNumberSet", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseSequenceNumberSet(log types.Log) (*CommitStoreHelperSequenceNumberSet, error) {
+ event := new(CommitStoreHelperSequenceNumberSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "SequenceNumberSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperTransmittedIterator struct {
+ Event *CommitStoreHelperTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperTransmitted)
+ 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(CommitStoreHelperTransmitted)
+ 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 *CommitStoreHelperTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreHelperTransmittedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperTransmittedIterator{contract: _CommitStoreHelper.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperTransmitted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Transmitted", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseTransmitted(log types.Log) (*CommitStoreHelperTransmitted, error) {
+ event := new(CommitStoreHelperTransmitted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperUnpausedIterator struct {
+ Event *CommitStoreHelperUnpaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperUnpausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperUnpaused)
+ 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(CommitStoreHelperUnpaused)
+ 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 *CommitStoreHelperUnpausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperUnpausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperUnpaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreHelperUnpausedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperUnpausedIterator{contract: _CommitStoreHelper.contract, event: "Unpaused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperUnpaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperUnpaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Unpaused", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseUnpaused(log types.Log) (*CommitStoreHelperUnpaused, error) {
+ event := new(CommitStoreHelperUnpaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Unpaused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_CommitStoreHelper *CommitStoreHelper) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _CommitStoreHelper.abi.Events["ConfigSet"].ID:
+ return _CommitStoreHelper.ParseConfigSet(log)
+ case _CommitStoreHelper.abi.Events["ConfigSet0"].ID:
+ return _CommitStoreHelper.ParseConfigSet0(log)
+ case _CommitStoreHelper.abi.Events["LatestPriceEpochAndRoundSet"].ID:
+ return _CommitStoreHelper.ParseLatestPriceEpochAndRoundSet(log)
+ case _CommitStoreHelper.abi.Events["OwnershipTransferRequested"].ID:
+ return _CommitStoreHelper.ParseOwnershipTransferRequested(log)
+ case _CommitStoreHelper.abi.Events["OwnershipTransferred"].ID:
+ return _CommitStoreHelper.ParseOwnershipTransferred(log)
+ case _CommitStoreHelper.abi.Events["Paused"].ID:
+ return _CommitStoreHelper.ParsePaused(log)
+ case _CommitStoreHelper.abi.Events["ReportAccepted"].ID:
+ return _CommitStoreHelper.ParseReportAccepted(log)
+ case _CommitStoreHelper.abi.Events["RootRemoved"].ID:
+ return _CommitStoreHelper.ParseRootRemoved(log)
+ case _CommitStoreHelper.abi.Events["SequenceNumberSet"].ID:
+ return _CommitStoreHelper.ParseSequenceNumberSet(log)
+ case _CommitStoreHelper.abi.Events["Transmitted"].ID:
+ return _CommitStoreHelper.ParseTransmitted(log)
+ case _CommitStoreHelper.abi.Events["Unpaused"].ID:
+ return _CommitStoreHelper.ParseUnpaused(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (CommitStoreHelperConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec3")
+}
+
+func (CommitStoreHelperConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (CommitStoreHelperLatestPriceEpochAndRoundSet) Topic() common.Hash {
+ return common.HexToHash("0xf0d557bfce33e354b41885eb9264448726cfe51f486ffa69809d2bf565456444")
+}
+
+func (CommitStoreHelperOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (CommitStoreHelperOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (CommitStoreHelperPaused) Topic() common.Hash {
+ return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258")
+}
+
+func (CommitStoreHelperReportAccepted) Topic() common.Hash {
+ return common.HexToHash("0x291698c01aa71f912280535d88a00d2c59fb63530a3f5d0098560468acb9ebf5")
+}
+
+func (CommitStoreHelperRootRemoved) Topic() common.Hash {
+ return common.HexToHash("0x202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12")
+}
+
+func (CommitStoreHelperSequenceNumberSet) Topic() common.Hash {
+ return common.HexToHash("0xea59e8027e41fda1525220008cf2416797405065eb21b0ebd417bfc6d361b8de")
+}
+
+func (CommitStoreHelperTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (CommitStoreHelperUnpaused) Topic() common.Hash {
+ return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa")
+}
+
+func (_CommitStoreHelper *CommitStoreHelper) Address() common.Address {
+ return _CommitStoreHelper.address
+}
+
+type CommitStoreHelperInterface interface {
+ GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error)
+
+ GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error)
+
+ IsUnpausedAndNotCursed(opts *bind.CallOpts) (bool, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ Paused(opts *bind.CallOpts) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Pause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Report(opts *bind.TransactOpts, commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error)
+
+ ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error)
+
+ SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error)
+
+ SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ Unpause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreHelperConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*CommitStoreHelperConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreHelperConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*CommitStoreHelperConfigSet0, error)
+
+ FilterLatestPriceEpochAndRoundSet(opts *bind.FilterOpts) (*CommitStoreHelperLatestPriceEpochAndRoundSetIterator, error)
+
+ WatchLatestPriceEpochAndRoundSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperLatestPriceEpochAndRoundSet) (event.Subscription, error)
+
+ ParseLatestPriceEpochAndRoundSet(log types.Log) (*CommitStoreHelperLatestPriceEpochAndRoundSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*CommitStoreHelperOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*CommitStoreHelperOwnershipTransferred, error)
+
+ FilterPaused(opts *bind.FilterOpts) (*CommitStoreHelperPausedIterator, error)
+
+ WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperPaused) (event.Subscription, error)
+
+ ParsePaused(log types.Log) (*CommitStoreHelperPaused, error)
+
+ FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreHelperReportAcceptedIterator, error)
+
+ WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperReportAccepted) (event.Subscription, error)
+
+ ParseReportAccepted(log types.Log) (*CommitStoreHelperReportAccepted, error)
+
+ FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreHelperRootRemovedIterator, error)
+
+ WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperRootRemoved) (event.Subscription, error)
+
+ ParseRootRemoved(log types.Log) (*CommitStoreHelperRootRemoved, error)
+
+ FilterSequenceNumberSet(opts *bind.FilterOpts) (*CommitStoreHelperSequenceNumberSetIterator, error)
+
+ WatchSequenceNumberSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperSequenceNumberSet) (event.Subscription, error)
+
+ ParseSequenceNumberSet(log types.Log) (*CommitStoreHelperSequenceNumberSet, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreHelperTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*CommitStoreHelperTransmitted, error)
+
+ FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreHelperUnpausedIterator, error)
+
+ WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperUnpaused) (event.Subscription, error)
+
+ ParseUnpaused(log types.Log) (*CommitStoreHelperUnpaused, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/commit_store_helper_1_0_0/commit_store_helper_1_0_0.go b/core/gethwrappers/ccip/generated/commit_store_helper_1_0_0/commit_store_helper_1_0_0.go
new file mode 100644
index 00000000000..5a1e15b2530
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/commit_store_helper_1_0_0/commit_store_helper_1_0_0.go
@@ -0,0 +1,1966 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package commit_store_helper_1_0_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommitStoreCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ Interval CommitStoreInterval
+ MerkleRoot [32]byte
+}
+
+type CommitStoreDynamicConfig struct {
+ PriceRegistry common.Address
+}
+
+type CommitStoreInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type CommitStoreStaticConfig struct {
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ ArmProxy common.Address
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var CommitStoreHelperMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCommitStoreConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"}],\"name\":\"InvalidInterval\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRoot\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LeavesCannotBeEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PausedError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootAlreadyCommitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":\"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\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"usdPerToken\",\"type\":\"uint192\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint192\",\"name\":\"usdPerUnitGas\",\"type\":\"uint192\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structCommitStore.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"ReportAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"RootRemoved\",\"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\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLatestPriceEpochAndRound\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"getMerkleRoot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isARMHealthy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isUnpausedAndARMHealthy\",\"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\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"commitReport\",\"type\":\"bytes\"},{\"internalType\":\"uint40\",\"name\":\"epochAndRound\",\"type\":\"uint40\"}],\"name\":\"report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"rootToReset\",\"type\":\"bytes32[]\"}],\"name\":\"resetUnblessedRoots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint40\",\"name\":\"latestPriceEpochAndRound\",\"type\":\"uint40\"}],\"name\":\"setLatestPriceEpochAndRound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"}],\"name\":\"setMinSeqNr\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"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\":\"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\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedLeaves\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x61014060405260098054600165ff000000000160401b03191660011790553480156200002a57600080fd5b5060405162003824380380620038248339810160408190526200004d9162000274565b80600033808281620000a65760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d957620000d98162000194565b50505015156080524660a05260408101516001600160a01b0316158062000108575080516001600160401b0316155b806200011f575060208101516001600160401b0316155b8062000136575060608101516001600160a01b0316155b156200015557604051631fc5f15f60e11b815260040160405180910390fd5b80516001600160401b0390811660c05260208201511660e05260408101516001600160a01b039081166101005260609091015116610120525062000308565b336001600160a01b03821603620001ee5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160401b03811681146200025757600080fd5b919050565b80516001600160a01b03811681146200025757600080fd5b6000608082840312156200028757600080fd5b604051608081016001600160401b0381118282101715620002b857634e487b7160e01b600052604160045260246000fd5b604052620002c6836200023f565b8152620002d6602084016200023f565b6020820152620002e9604084016200025c565b6040820152620002fc606084016200025c565b60608201529392505050565b60805160a05160c05160e051610100516101205161348d620003976000396000818161027801528181610555015281816111a1015281816119c801528181611a89015261202d01526000818161023c015261200601526000818161020c0152611fdf0152600081816101dc0152611fb001526000818161131c0152611368015260006113e3015261348d6000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80637437ff9f116100ee578063a7206cd611610097578063b1dc65a411610071578063b1dc65a414610505578063f2fde38b14610518578063f47a86901461052b578063ff888fb11461053e57600080fd5b8063a7206cd6146104b2578063ad7a22f8146104d2578063afcb95d7146104e557600080fd5b80638456cb59116100c85780638456cb591461047a5780638da5cb5b146104825780638db94e44146104aa57600080fd5b80637437ff9f1461040357806379ba50971461044257806381ff70481461044a57600080fd5b806329b980e4116101505780634120fccd1161012a5780634120fccd146103c05780635c975abb146103d2578063666cab8d146103ee57600080fd5b806329b980e41461038457806332048875146103975780633f4ba83a146103b857600080fd5b8063181f5a7711610181578063181f5a77146103135780631dc18e561461035c5780631ef381741461037157600080fd5b806306285c69146101a85780630a6cd30d146102cb57806310c374ed146102e3575b600080fd5b6102b560408051608081018252600080825260208201819052918101829052606081019190915260405180608001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516102c29190612688565b60405180910390f35b6102d3610551565b60405190151581526020016102c2565b60095468010000000000000000900464ffffffffff165b60405167ffffffffffffffff90911681526020016102c2565b61034f6040518060400160405280601181526020017f436f6d6d697453746f726520312e302e3000000000000000000000000000000081525081565b6040516102c29190612745565b61036f61036a3660046127bb565b6105e8565b005b61036f61037f366004612a4a565b6105f8565b61036f610392366004612b17565b610e19565b6103aa6103a5366004612b77565b610e65565b6040519081526020016102c2565b61036f610f5b565b60095467ffffffffffffffff166102fa565b6009546d0100000000000000000000000000900460ff166102d3565b6103f6610fc1565b6040516102c29190612c3c565b604080516020808201835260009091528151808201835260085473ffffffffffffffffffffffffffffffffffffffff16908190529151918252016102c2565b61036f611030565b6004546002546040805163ffffffff808516825264010000000090940490931660208401528201526060016102c2565b61036f61112d565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102c2565b6102d361119d565b6103aa6104c0366004612c4f565b6000908152600a602052604090205490565b61036f6104e0366004612c68565b611254565b6040805160018152600060208201819052918101919091526060016102c2565b61036f610513366004612c83565b611297565b61036f610526366004612d3a565b6118b7565b61036f610539366004612d57565b6118cb565b6102d361054c366004612c4f565b611965565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e29190612d99565b15905090565b6105f3838383611a39565b505050565b855185518560ff16601f831115610670576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064015b60405180910390fd5b806000036106da576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610667565b818314610768576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610667565b610773816003612dea565b83116107db576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610667565b6107e3611e4f565b6107ec86611ed2565b60065460005b818110156108e857600560006006838154811061081157610811612e01565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556007805460059291908490811061088157610881612e01565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556108e181612e30565b90506107f2565b50895160005b81811015610cc15760008c828151811061090a5761090a612e01565b602002602001015190506000600281111561092757610927612e68565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff16600281111561096657610966612e68565b146109cd576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610667565b73ffffffffffffffffffffffffffffffffffffffff8116610a1a576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016001905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610aca57610aca612e68565b021790555090505060008c8381518110610ae657610ae6612e01565b6020026020010151905060006002811115610b0357610b03612e68565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff166002811115610b4257610b42612e68565b14610ba9576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610667565b73ffffffffffffffffffffffffffffffffffffffff8116610bf6576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff84168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610ca657610ca6612e68565b0217905550905050505080610cba90612e30565b90506108ee565b508a51610cd59060069060208e01906125ca565b508951610ce99060079060208d01906125ca565b506003805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908c161717905560048054610d6f914691309190600090610d419063ffffffff16612e97565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168e8e8e8e8e8e61208e565b600260000181905550600060048054906101000a900463ffffffff169050436004806101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600260000154600460009054906101000a900463ffffffff168f8f8f8f8f8f604051610e0399989796959493929190612eba565b60405180910390a1505050505050505050505050565b610e21611e4f565b6009805464ffffffffff90921668010000000000000000027fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff909216919091179055565b6009546000906d0100000000000000000000000000900460ff1615610eb6576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610f2787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250889250612139915050565b9050610f3281611965565b610f40576000915050610f52565b6000908152600a602052604090205490505b95945050505050565b610f63611e4f565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b6060600780548060200260200160405190810160405280929190818152602001828054801561102657602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610ffb575b5050505050905090565b60015473ffffffffffffffffffffffffffffffffffffffff1633146110b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610667565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611135611e4f565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff166d01000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610fb7565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561120a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122e9190612d99565b15801561124f57506009546d0100000000000000000000000000900460ff16155b905090565b61125c611e4f565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055565b6112a6878760208b0135611a39565b6040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925289359182146113195780516040517f93df584c000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610667565b467f00000000000000000000000000000000000000000000000000000000000000001461139a576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610667565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a160007f00000000000000000000000000000000000000000000000000000000000000001561143c5760028260200151836040015161141d9190612f50565b6114279190612f69565b611432906001612f50565b60ff169050611452565b602082015161144c906001612f50565b60ff1690505b86811461148b576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8685146114c4576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561150757611507612e68565b600281111561151857611518612e68565b905250905060028160200151600281111561153557611535612e68565b14801561157c57506007816000015160ff168154811061155757611557612e01565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6115b2576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060006115c0866020612dea565b6115cb896020612dea565b6115d78c610144612fb2565b6115e19190612fb2565b6115eb9190612fb2565b905036811461162f576040517f8e1192e100000000000000000000000000000000000000000000000000000000815260048101829052366024820152604401610667565b5060008a8a604051611642929190612fc5565b604051908190038120611659918e90602001612fd5565b604051602081830303815290604052805190602001209050611679612654565b8860005b818110156118a65760006001858a846020811061169c5761169c612e01565b6116a991901a601b612f50565b8f8f868181106116bb576116bb612e01565b905060200201358e8e878181106116d4576116d4612e01565b9050602002013560405160008152602001604052604051611711949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611733573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152848220848601909552845460ff80821686529397509195509293928401916101009091041660028111156117b6576117b6612e68565b60028111156117c7576117c7612e68565b90525090506001816020015160028111156117e4576117e4612e68565b1461181b576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f811061183257611832612e01565b60200201511561186e576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f811061188957611889612e01565b911515602090920201525061189f905081612e30565b905061167d565b505050505050505050505050505050565b6118bf611e4f565b6118c88161245a565b50565b6118d3611e4f565b60005b818110156105f35760008383838181106118f2576118f2612e01565b90506020020135905061190481611965565b611954576000818152600a602052604080822091909155517f202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f129061194b9083815260200190565b60405180910390a15b5061195e81612e30565b90506118d6565b6040805180820182523081526020810183815291517f4d616771000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9081166004830152915160248201526000917f00000000000000000000000000000000000000000000000000000000000000001690634d61677190604401602060405180830381865afa158015611a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a339190612d99565b92915050565b6009546d0100000000000000000000000000900460ff1615611a87576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b169190612d99565b15611b4d576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611b5b8385018561304f565b80515151909150151580611b7d575080516020015167ffffffffffffffff1615155b15611cb55760095464ffffffffff80841668010000000000000000909204161015611c7a57600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff166801000000000000000064ffffffffff85160217905560085481516040517f866548c900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9092169163866548c991611c3491600401613266565b600060405180830381600087803b158015611c4e57600080fd5b505af1158015611c62573d6000803e3d6000fd5b505050506040810151611c755750505050565b611cb5565b6040810151611cb5576040517ff803a2ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101515160095467ffffffffffffffff9081169116141580611cf0575060208082015190810151905167ffffffffffffffff9182169116115b15611d2d5780602001516040517fbb1ae18d0000000000000000000000000000000000000000000000000000000081526004016106679190613279565b6040810151611d68576040517f504570e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040808201516000908152600a602052205415611db1576040517fa0bce24f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808201510151611dc490600161329e565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790556040818101516000908152600a602052819020429055517fe81b49e583122eb290c46fc255c962b9a2dec468816c00fb7a2e6ebc42dc92d490611e419083906132c6565b60405180910390a150505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611ed0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610667565b565b600081806020019051810190611ee89190613322565b805190915073ffffffffffffffffffffffffffffffffffffffff16611f39576040517f3f8be2be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff169055604080516080810182527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff90811682527f00000000000000000000000000000000000000000000000000000000000000001660208201527f00000000000000000000000000000000000000000000000000000000000000008316818301527f00000000000000000000000000000000000000000000000000000000000000009092166060830152517fc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec39161208291849061336e565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a6040516020016120b2999897969594939291906133eb565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b825182516000919081830361217a576040517f11a6b26400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610101821180159061218e57506101018111155b6121c4576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82820101610100811115612225576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003612252578660008151811061224057612240612e01565b60200260200101519350505050612453565b60008167ffffffffffffffff81111561226d5761226d61280f565b604051908082528060200260200182016040528015612296578160200160208202803683370190505b50905060008080805b858110156123d95760006001821b8b8116036122fa57888510156122e3578c5160018601958e9181106122d4576122d4612e01565b6020026020010151905061231c565b85516001850194879181106122d4576122d4612e01565b8b5160018401938d91811061231157612311612e01565b602002602001015190505b60008986101561234c578d5160018701968f91811061233d5761233d612e01565b6020026020010151905061236e565b865160018601958891811061236357612363612e01565b602002602001015190505b828511156123a8576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6123b2828261254f565b8784815181106123c4576123c4612e01565b6020908102919091010152505060010161229f565b5060018503821480156123eb57508683145b80156123f657508581145b61242c576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600186038151811061244157612441612e01565b60200260200101519750505050505050505b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036124d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610667565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008183106125915760408051600160208083019190915281830185905260608083018790528351808403909101815260809092019092528051910120612453565b60408051600160208083019190915281830186905260608083018690528351808403909101815260809092019092528051910120612453565b828054828255906000526020600020908101928215612644579160200282015b8281111561264457825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906125ea565b50612650929150612673565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b808211156126505760008155600101612674565b60808101611a33828467ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b6000815180845260005b81811015612707576020818501810151868301820152016126eb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061245360208301846126e1565b60008083601f84011261276a57600080fd5b50813567ffffffffffffffff81111561278257600080fd5b60208301915083602082850101111561279a57600080fd5b9250929050565b803564ffffffffff811681146127b657600080fd5b919050565b6000806000604084860312156127d057600080fd5b833567ffffffffffffffff8111156127e757600080fd5b6127f386828701612758565b90945092506128069050602085016127a1565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156128615761286161280f565b60405290565b6040516060810167ffffffffffffffff811182821017156128615761286161280f565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156128d1576128d161280f565b604052919050565b600067ffffffffffffffff8211156128f3576128f361280f565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff811681146118c857600080fd5b600082601f83011261293057600080fd5b81356020612945612940836128d9565b61288a565b82815260059290921b8401810191818101908684111561296457600080fd5b8286015b8481101561298857803561297b816128fd565b8352918301918301612968565b509695505050505050565b803560ff811681146127b657600080fd5b600082601f8301126129b557600080fd5b813567ffffffffffffffff8111156129cf576129cf61280f565b612a0060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161288a565b818152846020838601011115612a1557600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff811681146127b657600080fd5b60008060008060008060c08789031215612a6357600080fd5b863567ffffffffffffffff80821115612a7b57600080fd5b612a878a838b0161291f565b97506020890135915080821115612a9d57600080fd5b612aa98a838b0161291f565b9650612ab760408a01612993565b95506060890135915080821115612acd57600080fd5b612ad98a838b016129a4565b9450612ae760808a01612a32565b935060a0890135915080821115612afd57600080fd5b50612b0a89828a016129a4565b9150509295509295509295565b600060208284031215612b2957600080fd5b612453826127a1565b60008083601f840112612b4457600080fd5b50813567ffffffffffffffff811115612b5c57600080fd5b6020830191508360208260051b850101111561279a57600080fd5b600080600080600060608688031215612b8f57600080fd5b853567ffffffffffffffff80821115612ba757600080fd5b612bb389838a01612b32565b90975095506020880135915080821115612bcc57600080fd5b50612bd988828901612b32565b96999598509660400135949350505050565b600081518084526020808501945080840160005b83811015612c3157815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101612bff565b509495945050505050565b6020815260006124536020830184612beb565b600060208284031215612c6157600080fd5b5035919050565b600060208284031215612c7a57600080fd5b61245382612a32565b60008060008060008060008060e0898b031215612c9f57600080fd5b606089018a811115612cb057600080fd5b8998503567ffffffffffffffff80821115612cca57600080fd5b612cd68c838d01612758565b909950975060808b0135915080821115612cef57600080fd5b612cfb8c838d01612b32565b909750955060a08b0135915080821115612d1457600080fd5b50612d218b828c01612b32565b999c989b50969995989497949560c00135949350505050565b600060208284031215612d4c57600080fd5b8135612453816128fd565b60008060208385031215612d6a57600080fd5b823567ffffffffffffffff811115612d8157600080fd5b612d8d85828601612b32565b90969095509350505050565b600060208284031215612dab57600080fd5b8151801515811461245357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417611a3357611a33612dbb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612e6157612e61612dbb565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600063ffffffff808316818103612eb057612eb0612dbb565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152612eea8184018a612beb565b90508281036080840152612efe8189612beb565b905060ff871660a084015282810360c0840152612f1b81876126e1565b905067ffffffffffffffff851660e0840152828103610100840152612f4081856126e1565b9c9b505050505050505050505050565b60ff8181168382160190811115611a3357611a33612dbb565b600060ff831680612fa3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b80820180821115611a3357611a33612dbb565b8183823760009101908152919050565b828152606082602083013760800192915050565b803577ffffffffffffffffffffffffffffffffffffffffffffffff811681146127b657600080fd5b60006040828403121561302357600080fd5b61302b61283e565b905061303682612a32565b815261304460208301612a32565b602082015292915050565b6000602080838503121561306257600080fd5b823567ffffffffffffffff8082111561307a57600080fd5b908401906080828703121561308e57600080fd5b613096612867565b8235828111156130a557600080fd5b8301606081890312156130b757600080fd5b6130bf612867565b8135848111156130ce57600080fd5b82019350601f840189136130e157600080fd5b83356130ef612940826128d9565b81815260069190911b8501870190878101908b83111561310e57600080fd5b958801955b82871015613162576040878d03121561312c5760008081fd5b61313461283e565b873561313f816128fd565b815261314c888b01612fe9565b818b015282526040969096019590880190613113565b8352506131729050828701612a32565b8682015261318260408301612fe9565b604082015282525061319687848601613011565b93810193909352506060013560408201529392505050565b805160608084528151908401819052600091602091908201906080860190845b81811015613225578351805173ffffffffffffffffffffffffffffffffffffffff16845285015177ffffffffffffffffffffffffffffffffffffffffffffffff1685840152928401926040909201916001016131ce565b505067ffffffffffffffff83860151168387015260408501519250610f52604087018477ffffffffffffffffffffffffffffffffffffffffffffffff169052565b60208152600061245360208301846131ae565b60408101611a338284805167ffffffffffffffff908116835260209182015116910152565b67ffffffffffffffff8181168382160190808211156132bf576132bf612dbb565b5092915050565b6020815260008251608060208401526132e260a08401826131ae565b9050602084015161330d6040850182805167ffffffffffffffff908116835260209182015116910152565b50604084015160808401528091505092915050565b60006020828403121561333457600080fd5b6040516020810181811067ffffffffffffffff821117156133575761335761280f565b6040528251613365816128fd565b81529392505050565b60a081016133c7828567ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b73ffffffffffffffffffffffffffffffffffffffff83511660808301529392505050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526134328285018b612beb565b91508382036080850152613446828a612beb565b915060ff881660a085015283820360c085015261346382886126e1565b90861660e08501528381036101008501529050612f4081856126e156fea164736f6c6343000813000a",
+}
+
+var CommitStoreHelperABI = CommitStoreHelperMetaData.ABI
+
+var CommitStoreHelperBin = CommitStoreHelperMetaData.Bin
+
+func DeployCommitStoreHelper(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig CommitStoreStaticConfig) (common.Address, *types.Transaction, *CommitStoreHelper, error) {
+ parsed, err := CommitStoreHelperMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CommitStoreHelperBin), backend, staticConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &CommitStoreHelper{CommitStoreHelperCaller: CommitStoreHelperCaller{contract: contract}, CommitStoreHelperTransactor: CommitStoreHelperTransactor{contract: contract}, CommitStoreHelperFilterer: CommitStoreHelperFilterer{contract: contract}}, nil
+}
+
+type CommitStoreHelper struct {
+ address common.Address
+ abi abi.ABI
+ CommitStoreHelperCaller
+ CommitStoreHelperTransactor
+ CommitStoreHelperFilterer
+}
+
+type CommitStoreHelperCaller struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperTransactor struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperFilterer struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperSession struct {
+ Contract *CommitStoreHelper
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreHelperCallerSession struct {
+ Contract *CommitStoreHelperCaller
+ CallOpts bind.CallOpts
+}
+
+type CommitStoreHelperTransactorSession struct {
+ Contract *CommitStoreHelperTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreHelperRaw struct {
+ Contract *CommitStoreHelper
+}
+
+type CommitStoreHelperCallerRaw struct {
+ Contract *CommitStoreHelperCaller
+}
+
+type CommitStoreHelperTransactorRaw struct {
+ Contract *CommitStoreHelperTransactor
+}
+
+func NewCommitStoreHelper(address common.Address, backend bind.ContractBackend) (*CommitStoreHelper, error) {
+ abi, err := abi.JSON(strings.NewReader(CommitStoreHelperABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindCommitStoreHelper(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelper{address: address, abi: abi, CommitStoreHelperCaller: CommitStoreHelperCaller{contract: contract}, CommitStoreHelperTransactor: CommitStoreHelperTransactor{contract: contract}, CommitStoreHelperFilterer: CommitStoreHelperFilterer{contract: contract}}, nil
+}
+
+func NewCommitStoreHelperCaller(address common.Address, caller bind.ContractCaller) (*CommitStoreHelperCaller, error) {
+ contract, err := bindCommitStoreHelper(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperCaller{contract: contract}, nil
+}
+
+func NewCommitStoreHelperTransactor(address common.Address, transactor bind.ContractTransactor) (*CommitStoreHelperTransactor, error) {
+ contract, err := bindCommitStoreHelper(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperTransactor{contract: contract}, nil
+}
+
+func NewCommitStoreHelperFilterer(address common.Address, filterer bind.ContractFilterer) (*CommitStoreHelperFilterer, error) {
+ contract, err := bindCommitStoreHelper(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperFilterer{contract: contract}, nil
+}
+
+func bindCommitStoreHelper(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := CommitStoreHelperMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStoreHelper.Contract.CommitStoreHelperCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.CommitStoreHelperTransactor.contract.Transfer(opts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.CommitStoreHelperTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStoreHelper.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.contract.Transfer(opts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(CommitStoreDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreDynamicConfig)).(*CommitStoreDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStoreHelper.Contract.GetDynamicConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStoreHelper.Contract.GetDynamicConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetExpectedNextSequenceNumber(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetExpectedNextSequenceNumber(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getLatestPriceEpochAndRound")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetLatestPriceEpochAndRound(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetLatestPriceEpochAndRound(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getMerkleRoot", root)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.GetMerkleRoot(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.GetMerkleRoot(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(CommitStoreStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreStaticConfig)).(*CommitStoreStaticConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStoreHelper.Contract.GetStaticConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStoreHelper.Contract.GetStaticConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStoreHelper.Contract.GetTransmitters(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStoreHelper.Contract.GetTransmitters(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) IsARMHealthy(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "isARMHealthy")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) IsARMHealthy() (bool, error) {
+ return _CommitStoreHelper.Contract.IsARMHealthy(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) IsARMHealthy() (bool, error) {
+ return _CommitStoreHelper.Contract.IsARMHealthy(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "isBlessed", root)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStoreHelper.Contract.IsBlessed(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStoreHelper.Contract.IsBlessed(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "isUnpausedAndARMHealthy")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) IsUnpausedAndARMHealthy() (bool, error) {
+ return _CommitStoreHelper.Contract.IsUnpausedAndARMHealthy(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) IsUnpausedAndARMHealthy() (bool, error) {
+ return _CommitStoreHelper.Contract.IsUnpausedAndARMHealthy(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDetails(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDetails(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDigestAndEpoch(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDigestAndEpoch(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Owner() (common.Address, error) {
+ return _CommitStoreHelper.Contract.Owner(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Owner() (common.Address, error) {
+ return _CommitStoreHelper.Contract.Owner(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Paused(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "paused")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Paused() (bool, error) {
+ return _CommitStoreHelper.Contract.Paused(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Paused() (bool, error) {
+ return _CommitStoreHelper.Contract.Paused(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) TypeAndVersion() (string, error) {
+ return _CommitStoreHelper.Contract.TypeAndVersion(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) TypeAndVersion() (string, error) {
+ return _CommitStoreHelper.Contract.TypeAndVersion(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "verify", hashedLeaves, proofs, proofFlagBits)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.Verify(&_CommitStoreHelper.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.Verify(&_CommitStoreHelper.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.AcceptOwnership(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.AcceptOwnership(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "pause")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Pause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Pause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Pause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Pause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Report(opts *bind.TransactOpts, commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "report", commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Report(commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Report(&_CommitStoreHelper.TransactOpts, commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Report(commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Report(&_CommitStoreHelper.TransactOpts, commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "resetUnblessedRoots", rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.ResetUnblessedRoots(&_CommitStoreHelper.TransactOpts, rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.ResetUnblessedRoots(&_CommitStoreHelper.TransactOpts, rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setLatestPriceEpochAndRound", latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetLatestPriceEpochAndRound(&_CommitStoreHelper.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetLatestPriceEpochAndRound(&_CommitStoreHelper.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setMinSeqNr", minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetMinSeqNr(&_CommitStoreHelper.TransactOpts, minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetMinSeqNr(&_CommitStoreHelper.TransactOpts, minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetOCR2Config(&_CommitStoreHelper.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetOCR2Config(&_CommitStoreHelper.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.TransferOwnership(&_CommitStoreHelper.TransactOpts, to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.TransferOwnership(&_CommitStoreHelper.TransactOpts, to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Transmit(&_CommitStoreHelper.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Transmit(&_CommitStoreHelper.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "unpause")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Unpause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Unpause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Unpause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Unpause(&_CommitStoreHelper.TransactOpts)
+}
+
+type CommitStoreHelperConfigSetIterator struct {
+ Event *CommitStoreHelperConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperConfigSet)
+ 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(CommitStoreHelperConfigSet)
+ 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 *CommitStoreHelperConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperConfigSet struct {
+ StaticConfig CommitStoreStaticConfig
+ DynamicConfig CommitStoreDynamicConfig
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreHelperConfigSetIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperConfigSetIterator{contract: _CommitStoreHelper.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperConfigSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseConfigSet(log types.Log) (*CommitStoreHelperConfigSet, error) {
+ event := new(CommitStoreHelperConfigSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperConfigSet0Iterator struct {
+ Event *CommitStoreHelperConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperConfigSet0)
+ 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(CommitStoreHelperConfigSet0)
+ 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 *CommitStoreHelperConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreHelperConfigSet0Iterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperConfigSet0Iterator{contract: _CommitStoreHelper.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperConfigSet0)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet0", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseConfigSet0(log types.Log) (*CommitStoreHelperConfigSet0, error) {
+ event := new(CommitStoreHelperConfigSet0)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperOwnershipTransferRequestedIterator struct {
+ Event *CommitStoreHelperOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperOwnershipTransferRequested)
+ 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(CommitStoreHelperOwnershipTransferRequested)
+ 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 *CommitStoreHelperOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperOwnershipTransferRequestedIterator{contract: _CommitStoreHelper.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperOwnershipTransferRequested)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseOwnershipTransferRequested(log types.Log) (*CommitStoreHelperOwnershipTransferRequested, error) {
+ event := new(CommitStoreHelperOwnershipTransferRequested)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperOwnershipTransferredIterator struct {
+ Event *CommitStoreHelperOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperOwnershipTransferred)
+ 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(CommitStoreHelperOwnershipTransferred)
+ 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 *CommitStoreHelperOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperOwnershipTransferredIterator{contract: _CommitStoreHelper.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperOwnershipTransferred)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferred", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseOwnershipTransferred(log types.Log) (*CommitStoreHelperOwnershipTransferred, error) {
+ event := new(CommitStoreHelperOwnershipTransferred)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperPausedIterator struct {
+ Event *CommitStoreHelperPaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperPausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperPaused)
+ 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(CommitStoreHelperPaused)
+ 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 *CommitStoreHelperPausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperPausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperPaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterPaused(opts *bind.FilterOpts) (*CommitStoreHelperPausedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperPausedIterator{contract: _CommitStoreHelper.contract, event: "Paused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperPaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperPaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Paused", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParsePaused(log types.Log) (*CommitStoreHelperPaused, error) {
+ event := new(CommitStoreHelperPaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Paused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperReportAcceptedIterator struct {
+ Event *CommitStoreHelperReportAccepted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperReportAcceptedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperReportAccepted)
+ 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(CommitStoreHelperReportAccepted)
+ 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 *CommitStoreHelperReportAcceptedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperReportAcceptedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperReportAccepted struct {
+ Report CommitStoreCommitReport
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreHelperReportAcceptedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperReportAcceptedIterator{contract: _CommitStoreHelper.contract, event: "ReportAccepted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperReportAccepted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperReportAccepted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ReportAccepted", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseReportAccepted(log types.Log) (*CommitStoreHelperReportAccepted, error) {
+ event := new(CommitStoreHelperReportAccepted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ReportAccepted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperRootRemovedIterator struct {
+ Event *CommitStoreHelperRootRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperRootRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperRootRemoved)
+ 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(CommitStoreHelperRootRemoved)
+ 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 *CommitStoreHelperRootRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperRootRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperRootRemoved struct {
+ Root [32]byte
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreHelperRootRemovedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperRootRemovedIterator{contract: _CommitStoreHelper.contract, event: "RootRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperRootRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperRootRemoved)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "RootRemoved", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseRootRemoved(log types.Log) (*CommitStoreHelperRootRemoved, error) {
+ event := new(CommitStoreHelperRootRemoved)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "RootRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperTransmittedIterator struct {
+ Event *CommitStoreHelperTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperTransmitted)
+ 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(CommitStoreHelperTransmitted)
+ 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 *CommitStoreHelperTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreHelperTransmittedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperTransmittedIterator{contract: _CommitStoreHelper.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperTransmitted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Transmitted", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseTransmitted(log types.Log) (*CommitStoreHelperTransmitted, error) {
+ event := new(CommitStoreHelperTransmitted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperUnpausedIterator struct {
+ Event *CommitStoreHelperUnpaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperUnpausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperUnpaused)
+ 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(CommitStoreHelperUnpaused)
+ 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 *CommitStoreHelperUnpausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperUnpausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperUnpaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreHelperUnpausedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperUnpausedIterator{contract: _CommitStoreHelper.contract, event: "Unpaused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperUnpaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperUnpaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Unpaused", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseUnpaused(log types.Log) (*CommitStoreHelperUnpaused, error) {
+ event := new(CommitStoreHelperUnpaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Unpaused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_CommitStoreHelper *CommitStoreHelper) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _CommitStoreHelper.abi.Events["ConfigSet"].ID:
+ return _CommitStoreHelper.ParseConfigSet(log)
+ case _CommitStoreHelper.abi.Events["ConfigSet0"].ID:
+ return _CommitStoreHelper.ParseConfigSet0(log)
+ case _CommitStoreHelper.abi.Events["OwnershipTransferRequested"].ID:
+ return _CommitStoreHelper.ParseOwnershipTransferRequested(log)
+ case _CommitStoreHelper.abi.Events["OwnershipTransferred"].ID:
+ return _CommitStoreHelper.ParseOwnershipTransferred(log)
+ case _CommitStoreHelper.abi.Events["Paused"].ID:
+ return _CommitStoreHelper.ParsePaused(log)
+ case _CommitStoreHelper.abi.Events["ReportAccepted"].ID:
+ return _CommitStoreHelper.ParseReportAccepted(log)
+ case _CommitStoreHelper.abi.Events["RootRemoved"].ID:
+ return _CommitStoreHelper.ParseRootRemoved(log)
+ case _CommitStoreHelper.abi.Events["Transmitted"].ID:
+ return _CommitStoreHelper.ParseTransmitted(log)
+ case _CommitStoreHelper.abi.Events["Unpaused"].ID:
+ return _CommitStoreHelper.ParseUnpaused(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (CommitStoreHelperConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec3")
+}
+
+func (CommitStoreHelperConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (CommitStoreHelperOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (CommitStoreHelperOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (CommitStoreHelperPaused) Topic() common.Hash {
+ return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258")
+}
+
+func (CommitStoreHelperReportAccepted) Topic() common.Hash {
+ return common.HexToHash("0xe81b49e583122eb290c46fc255c962b9a2dec468816c00fb7a2e6ebc42dc92d4")
+}
+
+func (CommitStoreHelperRootRemoved) Topic() common.Hash {
+ return common.HexToHash("0x202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12")
+}
+
+func (CommitStoreHelperTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (CommitStoreHelperUnpaused) Topic() common.Hash {
+ return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa")
+}
+
+func (_CommitStoreHelper *CommitStoreHelper) Address() common.Address {
+ return _CommitStoreHelper.address
+}
+
+type CommitStoreHelperInterface interface {
+ GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error)
+
+ GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ IsARMHealthy(opts *bind.CallOpts) (bool, error)
+
+ IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error)
+
+ IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ Paused(opts *bind.CallOpts) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Pause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Report(opts *bind.TransactOpts, commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error)
+
+ ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error)
+
+ SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error)
+
+ SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ Unpause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreHelperConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*CommitStoreHelperConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreHelperConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*CommitStoreHelperConfigSet0, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*CommitStoreHelperOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*CommitStoreHelperOwnershipTransferred, error)
+
+ FilterPaused(opts *bind.FilterOpts) (*CommitStoreHelperPausedIterator, error)
+
+ WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperPaused) (event.Subscription, error)
+
+ ParsePaused(log types.Log) (*CommitStoreHelperPaused, error)
+
+ FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreHelperReportAcceptedIterator, error)
+
+ WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperReportAccepted) (event.Subscription, error)
+
+ ParseReportAccepted(log types.Log) (*CommitStoreHelperReportAccepted, error)
+
+ FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreHelperRootRemovedIterator, error)
+
+ WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperRootRemoved) (event.Subscription, error)
+
+ ParseRootRemoved(log types.Log) (*CommitStoreHelperRootRemoved, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreHelperTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*CommitStoreHelperTransmitted, error)
+
+ FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreHelperUnpausedIterator, error)
+
+ WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperUnpaused) (event.Subscription, error)
+
+ ParseUnpaused(log types.Log) (*CommitStoreHelperUnpaused, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/commit_store_helper_1_2_0/commit_store_helper_1_2_0.go b/core/gethwrappers/ccip/generated/commit_store_helper_1_2_0/commit_store_helper_1_2_0.go
new file mode 100644
index 00000000000..be974665981
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/commit_store_helper_1_2_0/commit_store_helper_1_2_0.go
@@ -0,0 +1,1969 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package commit_store_helper_1_2_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommitStoreCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ Interval CommitStoreInterval
+ MerkleRoot [32]byte
+}
+
+type CommitStoreDynamicConfig struct {
+ PriceRegistry common.Address
+}
+
+type CommitStoreInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type CommitStoreStaticConfig struct {
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ ArmProxy common.Address
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var CommitStoreHelperMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCommitStoreConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"}],\"name\":\"InvalidInterval\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRoot\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LeavesCannotBeEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PausedError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootAlreadyCommitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":\"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\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structCommitStore.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structCommitStore.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"ReportAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"RootRemoved\",\"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\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLatestPriceEpochAndRound\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"getMerkleRoot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structCommitStore.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isARMHealthy\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isUnpausedAndARMHealthy\",\"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\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"commitReport\",\"type\":\"bytes\"},{\"internalType\":\"uint40\",\"name\":\"epochAndRound\",\"type\":\"uint40\"}],\"name\":\"report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"rootToReset\",\"type\":\"bytes32[]\"}],\"name\":\"resetUnblessedRoots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint40\",\"name\":\"latestPriceEpochAndRound\",\"type\":\"uint40\"}],\"name\":\"setLatestPriceEpochAndRound\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"}],\"name\":\"setMinSeqNr\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"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\":\"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\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedLeaves\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x61014060405260098054600165ff000000000160401b03191660011790553480156200002a57600080fd5b50604051620038e8380380620038e88339810160408190526200004d9162000274565b80600033808281620000a65760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000d957620000d98162000194565b50505015156080524660a05260408101516001600160a01b0316158062000108575080516001600160401b0316155b806200011f575060208101516001600160401b0316155b8062000136575060608101516001600160a01b0316155b156200015557604051631fc5f15f60e11b815260040160405180910390fd5b80516001600160401b0390811660c05260208201511660e05260408101516001600160a01b039081166101005260609091015116610120525062000308565b336001600160a01b03821603620001ee5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200009d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160401b03811681146200025757600080fd5b919050565b80516001600160a01b03811681146200025757600080fd5b6000608082840312156200028757600080fd5b604051608081016001600160401b0381118282101715620002b857634e487b7160e01b600052604160045260246000fd5b604052620002c6836200023f565b8152620002d6602084016200023f565b6020820152620002e9604084016200025c565b6040820152620002fc606084016200025c565b60608201529392505050565b60805160a05160c05160e0516101005161012051613551620003976000396000818161027801528181610555015281816111a1015281816119c801528181611a89015261202401526000818161023c0152611ffd01526000818161020c0152611fd60152600081816101dc0152611fa701526000818161131c0152611368015260006113e301526135516000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80637437ff9f116100ee578063a7206cd611610097578063b1dc65a411610071578063b1dc65a414610505578063f2fde38b14610518578063f47a86901461052b578063ff888fb11461053e57600080fd5b8063a7206cd6146104b2578063ad7a22f8146104d2578063afcb95d7146104e557600080fd5b80638456cb59116100c85780638456cb591461047a5780638da5cb5b146104825780638db94e44146104aa57600080fd5b80637437ff9f1461040357806379ba50971461044257806381ff70481461044a57600080fd5b806329b980e4116101505780634120fccd1161012a5780634120fccd146103c05780635c975abb146103d2578063666cab8d146103ee57600080fd5b806329b980e41461038457806332048875146103975780633f4ba83a146103b857600080fd5b8063181f5a7711610181578063181f5a77146103135780631dc18e561461035c5780631ef381741461037157600080fd5b806306285c69146101a85780630a6cd30d146102cb57806310c374ed146102e3575b600080fd5b6102b560408051608081018252600080825260208201819052918101829052606081019190915260405180608001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516102c2919061267f565b60405180910390f35b6102d3610551565b60405190151581526020016102c2565b60095468010000000000000000900464ffffffffff165b60405167ffffffffffffffff90911681526020016102c2565b61034f6040518060400160405280601181526020017f436f6d6d697453746f726520312e322e3000000000000000000000000000000081525081565b6040516102c2919061273c565b61036f61036a3660046127b2565b6105e8565b005b61036f61037f366004612a41565b6105f8565b61036f610392366004612b0e565b610e19565b6103aa6103a5366004612b6e565b610e65565b6040519081526020016102c2565b61036f610f5b565b60095467ffffffffffffffff166102fa565b6009546d0100000000000000000000000000900460ff166102d3565b6103f6610fc1565b6040516102c29190612c33565b604080516020808201835260009091528151808201835260085473ffffffffffffffffffffffffffffffffffffffff16908190529151918252016102c2565b61036f611030565b6004546002546040805163ffffffff808516825264010000000090940490931660208401528201526060016102c2565b61036f61112d565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102c2565b6102d361119d565b6103aa6104c0366004612c46565b6000908152600a602052604090205490565b61036f6104e0366004612c5f565b611254565b6040805160018152600060208201819052918101919091526060016102c2565b61036f610513366004612c7a565b611297565b61036f610526366004612d31565b6118b7565b61036f610539366004612d4e565b6118cb565b6102d361054c366004612c46565b611965565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e29190612d90565b15905090565b6105f3838383611a39565b505050565b855185518560ff16601f831115610670576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064015b60405180910390fd5b806000036106da576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610667565b818314610768576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610667565b610773816003612de1565b83116107db576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610667565b6107e3611e46565b6107ec86611ec9565b60065460005b818110156108e857600560006006838154811061081157610811612df8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556007805460059291908490811061088157610881612df8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556108e181612e27565b90506107f2565b50895160005b81811015610cc15760008c828151811061090a5761090a612df8565b602002602001015190506000600281111561092757610927612e5f565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff16600281111561096657610966612e5f565b146109cd576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610667565b73ffffffffffffffffffffffffffffffffffffffff8116610a1a576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016001905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610aca57610aca612e5f565b021790555090505060008c8381518110610ae657610ae6612df8565b6020026020010151905060006002811115610b0357610b03612e5f565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff166002811115610b4257610b42612e5f565b14610ba9576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610667565b73ffffffffffffffffffffffffffffffffffffffff8116610bf6576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff84168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610ca657610ca6612e5f565b0217905550905050505080610cba90612e27565b90506108ee565b508a51610cd59060069060208e01906125c1565b508951610ce99060079060208d01906125c1565b506003805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908c161717905560048054610d6f914691309190600090610d419063ffffffff16612e8e565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168e8e8e8e8e8e612085565b600260000181905550600060048054906101000a900463ffffffff169050436004806101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600260000154600460009054906101000a900463ffffffff168f8f8f8f8f8f604051610e0399989796959493929190612eb1565b60405180910390a1505050505050505050505050565b610e21611e46565b6009805464ffffffffff90921668010000000000000000027fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff909216919091179055565b6009546000906d0100000000000000000000000000900460ff1615610eb6576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610f2787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250889250612130915050565b9050610f3281611965565b610f40576000915050610f52565b6000908152600a602052604090205490505b95945050505050565b610f63611e46565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b6060600780548060200260200160405190810160405280929190818152602001828054801561102657602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610ffb575b5050505050905090565b60015473ffffffffffffffffffffffffffffffffffffffff1633146110b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610667565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611135611e46565b600980547fffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffff166d01000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602001610fb7565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561120a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122e9190612d90565b15801561124f57506009546d0100000000000000000000000000900460ff16155b905090565b61125c611e46565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055565b6112a6878760208b0135611a39565b6040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925289359182146113195780516040517f93df584c000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610667565b467f00000000000000000000000000000000000000000000000000000000000000001461139a576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610667565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a160007f00000000000000000000000000000000000000000000000000000000000000001561143c5760028260200151836040015161141d9190612f47565b6114279190612f60565b611432906001612f47565b60ff169050611452565b602082015161144c906001612f47565b60ff1690505b86811461148b576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8685146114c4576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561150757611507612e5f565b600281111561151857611518612e5f565b905250905060028160200151600281111561153557611535612e5f565b14801561157c57506007816000015160ff168154811061155757611557612df8565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6115b2576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060006115c0866020612de1565b6115cb896020612de1565b6115d78c610144612fa9565b6115e19190612fa9565b6115eb9190612fa9565b905036811461162f576040517f8e1192e100000000000000000000000000000000000000000000000000000000815260048101829052366024820152604401610667565b5060008a8a604051611642929190612fbc565b604051908190038120611659918e90602001612fcc565b60405160208183030381529060405280519060200120905061167961264b565b8860005b818110156118a65760006001858a846020811061169c5761169c612df8565b6116a991901a601b612f47565b8f8f868181106116bb576116bb612df8565b905060200201358e8e878181106116d4576116d4612df8565b9050602002013560405160008152602001604052604051611711949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611733573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152848220848601909552845460ff80821686529397509195509293928401916101009091041660028111156117b6576117b6612e5f565b60028111156117c7576117c7612e5f565b90525090506001816020015160028111156117e4576117e4612e5f565b1461181b576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f811061183257611832612df8565b60200201511561186e576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f811061188957611889612df8565b911515602090920201525061189f905081612e27565b905061167d565b505050505050505050505050505050565b6118bf611e46565b6118c881612451565b50565b6118d3611e46565b60005b818110156105f35760008383838181106118f2576118f2612df8565b90506020020135905061190481611965565b611954576000818152600a602052604080822091909155517f202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f129061194b9083815260200190565b60405180910390a15b5061195e81612e27565b90506118d6565b6040805180820182523081526020810183815291517f4d616771000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9081166004830152915160248201526000917f00000000000000000000000000000000000000000000000000000000000000001690634d61677190604401602060405180830381865afa158015611a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a339190612d90565b92915050565b6009546d0100000000000000000000000000900460ff1615611a87576040517feced32bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b169190612d90565b15611b4d576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611b5b838501856130d7565b80515151909150151580611b7457508051602001515115155b15611cac5760095464ffffffffff80841668010000000000000000909204161015611c7157600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff166801000000000000000064ffffffffff85160217905560085481516040517f3937306f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691633937306f91611c2b9160040161332a565b600060405180830381600087803b158015611c4557600080fd5b505af1158015611c59573d6000803e3d6000fd5b505050506040810151611c6c5750505050565b611cac565b6040810151611cac576040517ff803a2ca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101515160095467ffffffffffffffff9081169116141580611ce7575060208082015190810151905167ffffffffffffffff9182169116115b15611d245780602001516040517fbb1ae18d000000000000000000000000000000000000000000000000000000008152600401610667919061333d565b6040810151611d5f576040517f504570e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040808201516000908152600a602052205415611da8576040517fa0bce24f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808201510151611dbb906001613362565b600980547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790556040818101516000908152600a602052819020429055517f291698c01aa71f912280535d88a00d2c59fb63530a3f5d0098560468acb9ebf590611e3890839061338a565b60405180910390a150505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611ec7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610667565b565b600081806020019051810190611edf91906133e6565b805190915073ffffffffffffffffffffffffffffffffffffffff16611f30576040517f3f8be2be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff928316179055600980547fffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffffff169055604080516080810182527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff90811682527f00000000000000000000000000000000000000000000000000000000000000001660208201527f00000000000000000000000000000000000000000000000000000000000000008316818301527f00000000000000000000000000000000000000000000000000000000000000009092166060830152517fc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec391612079918490613432565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a6040516020016120a9999897969594939291906134af565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b8251825160009190818303612171576040517f11a6b26400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610101821180159061218557506101018111155b6121bb576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8282010161010081111561221c576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600003612249578660008151811061223757612237612df8565b6020026020010151935050505061244a565b60008167ffffffffffffffff81111561226457612264612806565b60405190808252806020026020018201604052801561228d578160200160208202803683370190505b50905060008080805b858110156123d05760006001821b8b8116036122f157888510156122da578c5160018601958e9181106122cb576122cb612df8565b60200260200101519050612313565b85516001850194879181106122cb576122cb612df8565b8b5160018401938d91811061230857612308612df8565b602002602001015190505b600089861015612343578d5160018701968f91811061233457612334612df8565b60200260200101519050612365565b865160018601958891811061235a5761235a612df8565b602002602001015190505b8285111561239f576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6123a98282612546565b8784815181106123bb576123bb612df8565b60209081029190910101525050600101612296565b5060018503821480156123e257508683145b80156123ed57508581145b612423576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600186038151811061243857612438612df8565b60200260200101519750505050505050505b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036124d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610667565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818310612588576040805160016020808301919091528183018590526060808301879052835180840390910181526080909201909252805191012061244a565b6040805160016020808301919091528183018690526060808301869052835180840390910181526080909201909252805191012061244a565b82805482825590600052602060002090810192821561263b579160200282015b8281111561263b57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906125e1565b5061264792915061266a565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b80821115612647576000815560010161266b565b60808101611a33828467ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b6000815180845260005b818110156126fe576020818501810151868301820152016126e2565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061244a60208301846126d8565b60008083601f84011261276157600080fd5b50813567ffffffffffffffff81111561277957600080fd5b60208301915083602082850101111561279157600080fd5b9250929050565b803564ffffffffff811681146127ad57600080fd5b919050565b6000806000604084860312156127c757600080fd5b833567ffffffffffffffff8111156127de57600080fd5b6127ea8682870161274f565b90945092506127fd905060208501612798565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561285857612858612806565b60405290565b6040516060810167ffffffffffffffff8111828210171561285857612858612806565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156128c8576128c8612806565b604052919050565b600067ffffffffffffffff8211156128ea576128ea612806565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff811681146118c857600080fd5b600082601f83011261292757600080fd5b8135602061293c612937836128d0565b612881565b82815260059290921b8401810191818101908684111561295b57600080fd5b8286015b8481101561297f578035612972816128f4565b835291830191830161295f565b509695505050505050565b803560ff811681146127ad57600080fd5b600082601f8301126129ac57600080fd5b813567ffffffffffffffff8111156129c6576129c6612806565b6129f760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612881565b818152846020838601011115612a0c57600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff811681146127ad57600080fd5b60008060008060008060c08789031215612a5a57600080fd5b863567ffffffffffffffff80821115612a7257600080fd5b612a7e8a838b01612916565b97506020890135915080821115612a9457600080fd5b612aa08a838b01612916565b9650612aae60408a0161298a565b95506060890135915080821115612ac457600080fd5b612ad08a838b0161299b565b9450612ade60808a01612a29565b935060a0890135915080821115612af457600080fd5b50612b0189828a0161299b565b9150509295509295509295565b600060208284031215612b2057600080fd5b61244a82612798565b60008083601f840112612b3b57600080fd5b50813567ffffffffffffffff811115612b5357600080fd5b6020830191508360208260051b850101111561279157600080fd5b600080600080600060608688031215612b8657600080fd5b853567ffffffffffffffff80821115612b9e57600080fd5b612baa89838a01612b29565b90975095506020880135915080821115612bc357600080fd5b50612bd088828901612b29565b96999598509660400135949350505050565b600081518084526020808501945080840160005b83811015612c2857815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101612bf6565b509495945050505050565b60208152600061244a6020830184612be2565b600060208284031215612c5857600080fd5b5035919050565b600060208284031215612c7157600080fd5b61244a82612a29565b60008060008060008060008060e0898b031215612c9657600080fd5b606089018a811115612ca757600080fd5b8998503567ffffffffffffffff80821115612cc157600080fd5b612ccd8c838d0161274f565b909950975060808b0135915080821115612ce657600080fd5b612cf28c838d01612b29565b909750955060a08b0135915080821115612d0b57600080fd5b50612d188b828c01612b29565b999c989b50969995989497949560c00135949350505050565b600060208284031215612d4357600080fd5b813561244a816128f4565b60008060208385031215612d6157600080fd5b823567ffffffffffffffff811115612d7857600080fd5b612d8485828601612b29565b90969095509350505050565b600060208284031215612da257600080fd5b8151801515811461244a57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417611a3357611a33612db2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612e5857612e58612db2565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600063ffffffff808316818103612ea757612ea7612db2565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152612ee18184018a612be2565b90508281036080840152612ef58189612be2565b905060ff871660a084015282810360c0840152612f1281876126d8565b905067ffffffffffffffff851660e0840152828103610100840152612f3781856126d8565b9c9b505050505050505050505050565b60ff8181168382160190811115611a3357611a33612db2565b600060ff831680612f9a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b80820180821115611a3357611a33612db2565b8183823760009101908152919050565b828152606082602083013760800192915050565b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146127ad57600080fd5b600082601f83011261301d57600080fd5b8135602061302d612937836128d0565b82815260069290921b8401810191818101908684111561304c57600080fd5b8286015b8481101561297f57604081890312156130695760008081fd5b613071612835565b61307a82612a29565b8152613087858301612fe0565b81860152835291830191604001613050565b6000604082840312156130ab57600080fd5b6130b3612835565b90506130be82612a29565b81526130cc60208301612a29565b602082015292915050565b600060208083850312156130ea57600080fd5b823567ffffffffffffffff8082111561310257600080fd5b908401906080828703121561311657600080fd5b61311e61285e565b82358281111561312d57600080fd5b8301604081890381131561314057600080fd5b613148612835565b82358581111561315757600080fd5b8301601f81018b1361316857600080fd5b8035613176612937826128d0565b81815260069190911b8201890190898101908d83111561319557600080fd5b928a01925b828410156131e55785848f0312156131b25760008081fd5b6131ba612835565b84356131c5816128f4565b81526131d2858d01612fe0565b818d0152825292850192908a019061319a565b845250505082870135858111156131fb57600080fd5b6132078b82860161300c565b8289015250835261321a89868801613099565b8684015260608501358184015250508094505050505092915050565b805160408084528151848201819052600092602091908201906060870190855b818110156132af578351805173ffffffffffffffffffffffffffffffffffffffff1684528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16858401529284019291850191600101613256565b50508583015187820388850152805180835290840192506000918401905b8083101561331e578351805167ffffffffffffffff1683528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16858301529284019260019290920191908501906132cd565b50979650505050505050565b60208152600061244a6020830184613236565b60408101611a338284805167ffffffffffffffff908116835260209182015116910152565b67ffffffffffffffff81811683821601908082111561338357613383612db2565b5092915050565b6020815260008251608060208401526133a660a0840182613236565b905060208401516133d16040850182805167ffffffffffffffff908116835260209182015116910152565b50604084015160808401528091505092915050565b6000602082840312156133f857600080fd5b6040516020810181811067ffffffffffffffff8211171561341b5761341b612806565b6040528251613429816128f4565b81529392505050565b60a0810161348b828567ffffffffffffffff80825116835280602083015116602084015250604081015173ffffffffffffffffffffffffffffffffffffffff808216604085015280606084015116606085015250505050565b73ffffffffffffffffffffffffffffffffffffffff83511660808301529392505050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526134f68285018b612be2565b9150838203608085015261350a828a612be2565b915060ff881660a085015283820360c085015261352782886126d8565b90861660e08501528381036101008501529050612f3781856126d856fea164736f6c6343000813000a",
+}
+
+var CommitStoreHelperABI = CommitStoreHelperMetaData.ABI
+
+var CommitStoreHelperBin = CommitStoreHelperMetaData.Bin
+
+func DeployCommitStoreHelper(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig CommitStoreStaticConfig) (common.Address, *types.Transaction, *CommitStoreHelper, error) {
+ parsed, err := CommitStoreHelperMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(CommitStoreHelperBin), backend, staticConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &CommitStoreHelper{address: address, abi: *parsed, CommitStoreHelperCaller: CommitStoreHelperCaller{contract: contract}, CommitStoreHelperTransactor: CommitStoreHelperTransactor{contract: contract}, CommitStoreHelperFilterer: CommitStoreHelperFilterer{contract: contract}}, nil
+}
+
+type CommitStoreHelper struct {
+ address common.Address
+ abi abi.ABI
+ CommitStoreHelperCaller
+ CommitStoreHelperTransactor
+ CommitStoreHelperFilterer
+}
+
+type CommitStoreHelperCaller struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperTransactor struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperFilterer struct {
+ contract *bind.BoundContract
+}
+
+type CommitStoreHelperSession struct {
+ Contract *CommitStoreHelper
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreHelperCallerSession struct {
+ Contract *CommitStoreHelperCaller
+ CallOpts bind.CallOpts
+}
+
+type CommitStoreHelperTransactorSession struct {
+ Contract *CommitStoreHelperTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type CommitStoreHelperRaw struct {
+ Contract *CommitStoreHelper
+}
+
+type CommitStoreHelperCallerRaw struct {
+ Contract *CommitStoreHelperCaller
+}
+
+type CommitStoreHelperTransactorRaw struct {
+ Contract *CommitStoreHelperTransactor
+}
+
+func NewCommitStoreHelper(address common.Address, backend bind.ContractBackend) (*CommitStoreHelper, error) {
+ abi, err := abi.JSON(strings.NewReader(CommitStoreHelperABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindCommitStoreHelper(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelper{address: address, abi: abi, CommitStoreHelperCaller: CommitStoreHelperCaller{contract: contract}, CommitStoreHelperTransactor: CommitStoreHelperTransactor{contract: contract}, CommitStoreHelperFilterer: CommitStoreHelperFilterer{contract: contract}}, nil
+}
+
+func NewCommitStoreHelperCaller(address common.Address, caller bind.ContractCaller) (*CommitStoreHelperCaller, error) {
+ contract, err := bindCommitStoreHelper(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperCaller{contract: contract}, nil
+}
+
+func NewCommitStoreHelperTransactor(address common.Address, transactor bind.ContractTransactor) (*CommitStoreHelperTransactor, error) {
+ contract, err := bindCommitStoreHelper(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperTransactor{contract: contract}, nil
+}
+
+func NewCommitStoreHelperFilterer(address common.Address, filterer bind.ContractFilterer) (*CommitStoreHelperFilterer, error) {
+ contract, err := bindCommitStoreHelper(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperFilterer{contract: contract}, nil
+}
+
+func bindCommitStoreHelper(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := CommitStoreHelperMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStoreHelper.Contract.CommitStoreHelperCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.CommitStoreHelperTransactor.contract.Transfer(opts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.CommitStoreHelperTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _CommitStoreHelper.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.contract.Transfer(opts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(CommitStoreDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreDynamicConfig)).(*CommitStoreDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStoreHelper.Contract.GetDynamicConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetDynamicConfig() (CommitStoreDynamicConfig, error) {
+ return _CommitStoreHelper.Contract.GetDynamicConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetExpectedNextSequenceNumber(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetExpectedNextSequenceNumber(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getLatestPriceEpochAndRound")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetLatestPriceEpochAndRound(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetLatestPriceEpochAndRound() (uint64, error) {
+ return _CommitStoreHelper.Contract.GetLatestPriceEpochAndRound(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getMerkleRoot", root)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.GetMerkleRoot(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetMerkleRoot(root [32]byte) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.GetMerkleRoot(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(CommitStoreStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommitStoreStaticConfig)).(*CommitStoreStaticConfig)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStoreHelper.Contract.GetStaticConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetStaticConfig() (CommitStoreStaticConfig, error) {
+ return _CommitStoreHelper.Contract.GetStaticConfig(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStoreHelper.Contract.GetTransmitters(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _CommitStoreHelper.Contract.GetTransmitters(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) IsARMHealthy(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "isARMHealthy")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) IsARMHealthy() (bool, error) {
+ return _CommitStoreHelper.Contract.IsARMHealthy(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) IsARMHealthy() (bool, error) {
+ return _CommitStoreHelper.Contract.IsARMHealthy(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "isBlessed", root)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStoreHelper.Contract.IsBlessed(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) IsBlessed(root [32]byte) (bool, error) {
+ return _CommitStoreHelper.Contract.IsBlessed(&_CommitStoreHelper.CallOpts, root)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "isUnpausedAndARMHealthy")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) IsUnpausedAndARMHealthy() (bool, error) {
+ return _CommitStoreHelper.Contract.IsUnpausedAndARMHealthy(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) IsUnpausedAndARMHealthy() (bool, error) {
+ return _CommitStoreHelper.Contract.IsUnpausedAndARMHealthy(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDetails(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDetails(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDigestAndEpoch(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _CommitStoreHelper.Contract.LatestConfigDigestAndEpoch(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Owner() (common.Address, error) {
+ return _CommitStoreHelper.Contract.Owner(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Owner() (common.Address, error) {
+ return _CommitStoreHelper.Contract.Owner(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Paused(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "paused")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Paused() (bool, error) {
+ return _CommitStoreHelper.Contract.Paused(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Paused() (bool, error) {
+ return _CommitStoreHelper.Contract.Paused(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) TypeAndVersion() (string, error) {
+ return _CommitStoreHelper.Contract.TypeAndVersion(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) TypeAndVersion() (string, error) {
+ return _CommitStoreHelper.Contract.TypeAndVersion(&_CommitStoreHelper.CallOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCaller) Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _CommitStoreHelper.contract.Call(opts, &out, "verify", hashedLeaves, proofs, proofFlagBits)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.Verify(&_CommitStoreHelper.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperCallerSession) Verify(hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ return _CommitStoreHelper.Contract.Verify(&_CommitStoreHelper.CallOpts, hashedLeaves, proofs, proofFlagBits)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.AcceptOwnership(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.AcceptOwnership(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "pause")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Pause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Pause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Pause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Pause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Report(opts *bind.TransactOpts, commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "report", commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Report(commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Report(&_CommitStoreHelper.TransactOpts, commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Report(commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Report(&_CommitStoreHelper.TransactOpts, commitReport, epochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "resetUnblessedRoots", rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.ResetUnblessedRoots(&_CommitStoreHelper.TransactOpts, rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) ResetUnblessedRoots(rootToReset [][32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.ResetUnblessedRoots(&_CommitStoreHelper.TransactOpts, rootToReset)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setLatestPriceEpochAndRound", latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetLatestPriceEpochAndRound(&_CommitStoreHelper.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetLatestPriceEpochAndRound(latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetLatestPriceEpochAndRound(&_CommitStoreHelper.TransactOpts, latestPriceEpochAndRound)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setMinSeqNr", minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetMinSeqNr(&_CommitStoreHelper.TransactOpts, minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetMinSeqNr(minSeqNr uint64) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetMinSeqNr(&_CommitStoreHelper.TransactOpts, minSeqNr)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetOCR2Config(&_CommitStoreHelper.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.SetOCR2Config(&_CommitStoreHelper.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.TransferOwnership(&_CommitStoreHelper.TransactOpts, to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.TransferOwnership(&_CommitStoreHelper.TransactOpts, to)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Transmit(&_CommitStoreHelper.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Transmit(&_CommitStoreHelper.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _CommitStoreHelper.contract.Transact(opts, "unpause")
+}
+
+func (_CommitStoreHelper *CommitStoreHelperSession) Unpause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Unpause(&_CommitStoreHelper.TransactOpts)
+}
+
+func (_CommitStoreHelper *CommitStoreHelperTransactorSession) Unpause() (*types.Transaction, error) {
+ return _CommitStoreHelper.Contract.Unpause(&_CommitStoreHelper.TransactOpts)
+}
+
+type CommitStoreHelperConfigSetIterator struct {
+ Event *CommitStoreHelperConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperConfigSet)
+ 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(CommitStoreHelperConfigSet)
+ 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 *CommitStoreHelperConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperConfigSet struct {
+ StaticConfig CommitStoreStaticConfig
+ DynamicConfig CommitStoreDynamicConfig
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreHelperConfigSetIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperConfigSetIterator{contract: _CommitStoreHelper.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperConfigSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseConfigSet(log types.Log) (*CommitStoreHelperConfigSet, error) {
+ event := new(CommitStoreHelperConfigSet)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperConfigSet0Iterator struct {
+ Event *CommitStoreHelperConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperConfigSet0)
+ 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(CommitStoreHelperConfigSet0)
+ 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 *CommitStoreHelperConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreHelperConfigSet0Iterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperConfigSet0Iterator{contract: _CommitStoreHelper.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperConfigSet0)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet0", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseConfigSet0(log types.Log) (*CommitStoreHelperConfigSet0, error) {
+ event := new(CommitStoreHelperConfigSet0)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperOwnershipTransferRequestedIterator struct {
+ Event *CommitStoreHelperOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperOwnershipTransferRequested)
+ 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(CommitStoreHelperOwnershipTransferRequested)
+ 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 *CommitStoreHelperOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperOwnershipTransferRequestedIterator{contract: _CommitStoreHelper.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperOwnershipTransferRequested)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseOwnershipTransferRequested(log types.Log) (*CommitStoreHelperOwnershipTransferRequested, error) {
+ event := new(CommitStoreHelperOwnershipTransferRequested)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperOwnershipTransferredIterator struct {
+ Event *CommitStoreHelperOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperOwnershipTransferred)
+ 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(CommitStoreHelperOwnershipTransferred)
+ 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 *CommitStoreHelperOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperOwnershipTransferredIterator{contract: _CommitStoreHelper.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperOwnershipTransferred)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferred", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseOwnershipTransferred(log types.Log) (*CommitStoreHelperOwnershipTransferred, error) {
+ event := new(CommitStoreHelperOwnershipTransferred)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperPausedIterator struct {
+ Event *CommitStoreHelperPaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperPausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperPaused)
+ 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(CommitStoreHelperPaused)
+ 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 *CommitStoreHelperPausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperPausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperPaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterPaused(opts *bind.FilterOpts) (*CommitStoreHelperPausedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperPausedIterator{contract: _CommitStoreHelper.contract, event: "Paused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperPaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Paused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperPaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Paused", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParsePaused(log types.Log) (*CommitStoreHelperPaused, error) {
+ event := new(CommitStoreHelperPaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Paused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperReportAcceptedIterator struct {
+ Event *CommitStoreHelperReportAccepted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperReportAcceptedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperReportAccepted)
+ 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(CommitStoreHelperReportAccepted)
+ 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 *CommitStoreHelperReportAcceptedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperReportAcceptedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperReportAccepted struct {
+ Report CommitStoreCommitReport
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreHelperReportAcceptedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperReportAcceptedIterator{contract: _CommitStoreHelper.contract, event: "ReportAccepted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperReportAccepted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "ReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperReportAccepted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ReportAccepted", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseReportAccepted(log types.Log) (*CommitStoreHelperReportAccepted, error) {
+ event := new(CommitStoreHelperReportAccepted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "ReportAccepted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperRootRemovedIterator struct {
+ Event *CommitStoreHelperRootRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperRootRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperRootRemoved)
+ 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(CommitStoreHelperRootRemoved)
+ 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 *CommitStoreHelperRootRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperRootRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperRootRemoved struct {
+ Root [32]byte
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreHelperRootRemovedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperRootRemovedIterator{contract: _CommitStoreHelper.contract, event: "RootRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperRootRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperRootRemoved)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "RootRemoved", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseRootRemoved(log types.Log) (*CommitStoreHelperRootRemoved, error) {
+ event := new(CommitStoreHelperRootRemoved)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "RootRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperTransmittedIterator struct {
+ Event *CommitStoreHelperTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperTransmitted)
+ 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(CommitStoreHelperTransmitted)
+ 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 *CommitStoreHelperTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreHelperTransmittedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperTransmittedIterator{contract: _CommitStoreHelper.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperTransmitted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Transmitted", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseTransmitted(log types.Log) (*CommitStoreHelperTransmitted, error) {
+ event := new(CommitStoreHelperTransmitted)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type CommitStoreHelperUnpausedIterator struct {
+ Event *CommitStoreHelperUnpaused
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *CommitStoreHelperUnpausedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(CommitStoreHelperUnpaused)
+ 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(CommitStoreHelperUnpaused)
+ 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 *CommitStoreHelperUnpausedIterator) Error() error {
+ return it.fail
+}
+
+func (it *CommitStoreHelperUnpausedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type CommitStoreHelperUnpaused struct {
+ Account common.Address
+ Raw types.Log
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreHelperUnpausedIterator, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.FilterLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStoreHelperUnpausedIterator{contract: _CommitStoreHelper.contract, event: "Unpaused", logs: logs, sub: sub}, nil
+}
+
+func (_CommitStoreHelper *CommitStoreHelperFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperUnpaused) (event.Subscription, error) {
+
+ logs, sub, err := _CommitStoreHelper.contract.WatchLogs(opts, "Unpaused")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(CommitStoreHelperUnpaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Unpaused", 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 (_CommitStoreHelper *CommitStoreHelperFilterer) ParseUnpaused(log types.Log) (*CommitStoreHelperUnpaused, error) {
+ event := new(CommitStoreHelperUnpaused)
+ if err := _CommitStoreHelper.contract.UnpackLog(event, "Unpaused", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_CommitStoreHelper *CommitStoreHelper) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _CommitStoreHelper.abi.Events["ConfigSet"].ID:
+ return _CommitStoreHelper.ParseConfigSet(log)
+ case _CommitStoreHelper.abi.Events["ConfigSet0"].ID:
+ return _CommitStoreHelper.ParseConfigSet0(log)
+ case _CommitStoreHelper.abi.Events["OwnershipTransferRequested"].ID:
+ return _CommitStoreHelper.ParseOwnershipTransferRequested(log)
+ case _CommitStoreHelper.abi.Events["OwnershipTransferred"].ID:
+ return _CommitStoreHelper.ParseOwnershipTransferred(log)
+ case _CommitStoreHelper.abi.Events["Paused"].ID:
+ return _CommitStoreHelper.ParsePaused(log)
+ case _CommitStoreHelper.abi.Events["ReportAccepted"].ID:
+ return _CommitStoreHelper.ParseReportAccepted(log)
+ case _CommitStoreHelper.abi.Events["RootRemoved"].ID:
+ return _CommitStoreHelper.ParseRootRemoved(log)
+ case _CommitStoreHelper.abi.Events["Transmitted"].ID:
+ return _CommitStoreHelper.ParseTransmitted(log)
+ case _CommitStoreHelper.abi.Events["Unpaused"].ID:
+ return _CommitStoreHelper.ParseUnpaused(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (CommitStoreHelperConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xc9d7123efd4203e60b0f0a4b1dbc4800fc97ce63679f71c3a27279b24a7ddec3")
+}
+
+func (CommitStoreHelperConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (CommitStoreHelperOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (CommitStoreHelperOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (CommitStoreHelperPaused) Topic() common.Hash {
+ return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258")
+}
+
+func (CommitStoreHelperReportAccepted) Topic() common.Hash {
+ return common.HexToHash("0x291698c01aa71f912280535d88a00d2c59fb63530a3f5d0098560468acb9ebf5")
+}
+
+func (CommitStoreHelperRootRemoved) Topic() common.Hash {
+ return common.HexToHash("0x202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12")
+}
+
+func (CommitStoreHelperTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (CommitStoreHelperUnpaused) Topic() common.Hash {
+ return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa")
+}
+
+func (_CommitStoreHelper *CommitStoreHelper) Address() common.Address {
+ return _CommitStoreHelper.address
+}
+
+type CommitStoreHelperInterface interface {
+ GetDynamicConfig(opts *bind.CallOpts) (CommitStoreDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error)
+
+ GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (CommitStoreStaticConfig, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ IsARMHealthy(opts *bind.CallOpts) (bool, error)
+
+ IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error)
+
+ IsUnpausedAndARMHealthy(opts *bind.CallOpts) (bool, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ Paused(opts *bind.CallOpts) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Pause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Report(opts *bind.TransactOpts, commitReport []byte, epochAndRound *big.Int) (*types.Transaction, error)
+
+ ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error)
+
+ SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error)
+
+ SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ Unpause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*CommitStoreHelperConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*CommitStoreHelperConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*CommitStoreHelperConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*CommitStoreHelperConfigSet0, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*CommitStoreHelperOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*CommitStoreHelperOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*CommitStoreHelperOwnershipTransferred, error)
+
+ FilterPaused(opts *bind.FilterOpts) (*CommitStoreHelperPausedIterator, error)
+
+ WatchPaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperPaused) (event.Subscription, error)
+
+ ParsePaused(log types.Log) (*CommitStoreHelperPaused, error)
+
+ FilterReportAccepted(opts *bind.FilterOpts) (*CommitStoreHelperReportAcceptedIterator, error)
+
+ WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperReportAccepted) (event.Subscription, error)
+
+ ParseReportAccepted(log types.Log) (*CommitStoreHelperReportAccepted, error)
+
+ FilterRootRemoved(opts *bind.FilterOpts) (*CommitStoreHelperRootRemovedIterator, error)
+
+ WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperRootRemoved) (event.Subscription, error)
+
+ ParseRootRemoved(log types.Log) (*CommitStoreHelperRootRemoved, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*CommitStoreHelperTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*CommitStoreHelperTransmitted, error)
+
+ FilterUnpaused(opts *bind.FilterOpts) (*CommitStoreHelperUnpausedIterator, error)
+
+ WatchUnpaused(opts *bind.WatchOpts, sink chan<- *CommitStoreHelperUnpaused) (event.Subscription, error)
+
+ ParseUnpaused(log types.Log) (*CommitStoreHelperUnpaused, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/ether_sender_receiver/ether_sender_receiver.go b/core/gethwrappers/ccip/generated/ether_sender_receiver/ether_sender_receiver.go
new file mode 100644
index 00000000000..505e42e98ec
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/ether_sender_receiver/ether_sender_receiver.go
@@ -0,0 +1,361 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package ether_sender_receiver
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+var EtherSenderReceiverMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"name\":\"InvalidRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"gotToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"expectedToken\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gotAmounts\",\"type\":\"uint256\"}],\"name\":\"InvalidTokenAmounts\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gotAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"msgValue\",\"type\":\"uint256\"}],\"name\":\"TokenAmountNotEqualToMsgValue\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"ccipReceive\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destinationChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"ccipSend\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destinationChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_weth\",\"outputs\":[{\"internalType\":\"contractIWrappedNative\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
+ Bin: "0x60c06040523480156200001157600080fd5b5060405162001a9838038062001a98833981016040819052620000349162000169565b806001600160a01b03811662000064576040516335fdcccd60e21b81526000600482015260240160405180910390fd5b806001600160a01b03166080816001600160a01b03168152505050806001600160a01b031663e861e9076040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000be573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e4919062000169565b6001600160a01b0390811660a081905260405163095ea7b360e01b8152918316600483015260001960248301529063095ea7b3906044016020604051808303816000875af11580156200013b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016191906200019b565b5050620001bf565b6000602082840312156200017c57600080fd5b81516001600160a01b03811681146200019457600080fd5b9392505050565b600060208284031215620001ae57600080fd5b815180151581146200019457600080fd5b60805160a051611851620002476000396000818161014b015281816104030152818161059401528181610905015281816109cc01528181610a6401528181610b0201528181610bf70152610cbf0152600081816101d6015281816102df01528181610377015281816104ab0152818161060b015281816106ff01526107bf01526118516000f3fe6080604052600436106100745760003560e01c80634dbe7e921161004e5780634dbe7e921461013957806385572ffb1461019257806396f4e9f9146101b4578063b0f479a1146101c757600080fd5b806301ffc9a714610080578063181f5a77146100b557806320487ded1461010b57600080fd5b3661007b57005b600080fd5b34801561008c57600080fd5b506100a061009b3660046110e3565b6101fa565b60405190151581526020015b60405180910390f35b3480156100c157600080fd5b506100fe6040518060400160405280601981526020017f457468657253656e646572526563656976657220312e352e300000000000000081525081565b6040516100ac919061119a565b34801561011757600080fd5b5061012b6101263660046111e2565b610293565b6040519081526020016100ac565b34801561014557600080fd5b5061016d7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100ac565b34801561019e57600080fd5b506101b26101ad366004611230565b61035f565b005b61012b6101c23660046111e2565b6103e9565b3480156101d357600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061016d565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f85572ffb00000000000000000000000000000000000000000000000000000000148061028d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b60008061029f83610844565b6040517f20487ded00000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906320487ded906103169087908590600401611265565b602060405180830381865afa158015610333573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610357919061137a565b949350505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146103d5576040517fd7f733340000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b6103e66103e1826115c5565b610966565b50565b60006103f482610d38565b60006103ff83610844565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040015160008151811061045457610454611672565b6020026020010151602001516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561048b57600080fd5b505af115801561049f573d6000803e3d6000fd5b505050505060006104cd7f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166320487ded86846040518363ffffffff1660e01b8152600401610507929190611265565b602060405180830381865afa158015610524573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610548919061137a565b606083015190915073ffffffffffffffffffffffffffffffffffffffff16156107825760608201516105929073ffffffffffffffffffffffffffffffffffffffff16333084610df0565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16826060015173ffffffffffffffffffffffffffffffffffffffff16146106c257606082015173ffffffffffffffffffffffffffffffffffffffff1663095ea7b37f00000000000000000000000000000000000000000000000000000000000000006040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602481018490526044016020604051808303816000875af115801561069c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c091906116a1565b505b6040517f96f4e9f900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906396f4e9f9906107369088908690600401611265565b6020604051808303816000875af1158015610755573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610779919061137a565b9250505061028d565b6040517f96f4e9f900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906396f4e9f99047906107f89089908790600401611265565b60206040518083038185885af1158015610816573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061083b919061137a565b95945050505050565b61088c6040518060a00160405280606081526020016060815260200160608152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b6000610897836116c3565b90508060400151516001146108e1578060400151516040517f83b9f0ae0000000000000000000000000000000000000000000000000000000081526004016103cc91815260200190565b604080513360208201520160405160208183030381529060405281602001819052507f0000000000000000000000000000000000000000000000000000000000000000816040015160008151811061093b5761093b611672565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff909116905292915050565b60008160600151806020019051810190610980919061177f565b90508160800151516001146109ca578160800151516040517f83b9f0ae0000000000000000000000000000000000000000000000000000000081526004016103cc91815260200190565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168260800151600081518110610a1857610a18611672565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614610ad9578160800151600081518110610a5657610a56611672565b6020026020010151600001517f00000000000000000000000000000000000000000000000000000000000000006040517f0fc746a10000000000000000000000000000000000000000000000000000000081526004016103cc92919073ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b60008260800151600081518110610af257610af2611672565b60200260200101516020015190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b8152600401610b5b91815260200190565b600060405180830381600087803b158015610b7557600080fd5b505af1158015610b89573d6000803e3d6000fd5b5050505060008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610be7576040519150601f19603f3d011682016040523d82523d6000602084013e610bec565b606091505b5050905080610d32577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610c5d57600080fd5b505af1158015610c71573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152602482018790527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af1158015610d0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3091906116a1565b505b50505050565b6000610d47604083018361179c565b6000818110610d5857610d58611672565b905060400201602001359050600073ffffffffffffffffffffffffffffffffffffffff16826060016020810190610d8f919061180b565b73ffffffffffffffffffffffffffffffffffffffff1614610dec57803414610dec576040517fba2f7467000000000000000000000000000000000000000000000000000000008152600481018290523460248201526044016103cc565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8581166024830152848116604483015260648083018590528351808403909101815260849092018352602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905283518085019094528084527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490840152610d3292879291600091610ec3918516908490610f72565b805190915015610f6d5780806020019051810190610ee191906116a1565b610f6d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016103cc565b505050565b60606103578484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051610fa69190611828565b60006040518083038185875af1925050503d8060008114610fe3576040519150601f19603f3d011682016040523d82523d6000602084013e610fe8565b606091505b5091509150610ff987838387611004565b979650505050505050565b6060831561109a5782516000036110935773ffffffffffffffffffffffffffffffffffffffff85163b611093576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103cc565b5081610357565b61035783838151156110af5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103cc919061119a565b6000602082840312156110f557600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461112557600080fd5b9392505050565b60005b8381101561114757818101518382015260200161112f565b50506000910152565b6000815180845261116881602086016020860161112c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006111256020830184611150565b803567ffffffffffffffff811681146111c557600080fd5b919050565b600060a082840312156111dc57600080fd5b50919050565b600080604083850312156111f557600080fd5b6111fe836111ad565b9150602083013567ffffffffffffffff81111561121a57600080fd5b611226858286016111ca565b9150509250929050565b60006020828403121561124257600080fd5b813567ffffffffffffffff81111561125957600080fd5b610357848285016111ca565b6000604067ffffffffffffffff851683526020604081850152845160a0604086015261129460e0860182611150565b9050818601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0808784030160608801526112cf8383611150565b6040890151888203830160808a01528051808352908601945060009350908501905b80841015611330578451805173ffffffffffffffffffffffffffffffffffffffff168352860151868301529385019360019390930192908601906112f1565b50606089015173ffffffffffffffffffffffffffffffffffffffff1660a08901526080890151888203830160c08a0152955061136c8187611150565b9a9950505050505050505050565b60006020828403121561138c57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156113e5576113e5611393565b60405290565b60405160a0810167ffffffffffffffff811182821017156113e5576113e5611393565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561145557611455611393565b604052919050565b600082601f83011261146e57600080fd5b813567ffffffffffffffff81111561148857611488611393565b6114b960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161140e565b8181528460208386010111156114ce57600080fd5b816020850160208301376000918101602001919091529392505050565b73ffffffffffffffffffffffffffffffffffffffff811681146103e657600080fd5b80356111c5816114eb565b600082601f83011261152957600080fd5b8135602067ffffffffffffffff82111561154557611545611393565b611553818360051b0161140e565b82815260069290921b8401810191818101908684111561157257600080fd5b8286015b848110156115ba576040818903121561158f5760008081fd5b6115976113c2565b81356115a2816114eb565b81528185013585820152835291830191604001611576565b509695505050505050565b600060a082360312156115d757600080fd5b6115df6113eb565b823581526115ef602084016111ad565b6020820152604083013567ffffffffffffffff8082111561160f57600080fd5b61161b3683870161145d565b6040840152606085013591508082111561163457600080fd5b6116403683870161145d565b6060840152608085013591508082111561165957600080fd5b5061166636828601611518565b60808301525092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156116b357600080fd5b8151801515811461112557600080fd5b600060a082360312156116d557600080fd5b6116dd6113eb565b823567ffffffffffffffff808211156116f557600080fd5b6117013683870161145d565b8352602085013591508082111561171757600080fd5b6117233683870161145d565b6020840152604085013591508082111561173c57600080fd5b61174836838701611518565b60408401526117596060860161150d565b6060840152608085013591508082111561177257600080fd5b506116663682860161145d565b60006020828403121561179157600080fd5b8151611125816114eb565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126117d157600080fd5b83018035915067ffffffffffffffff8211156117ec57600080fd5b6020019150600681901b360382131561180457600080fd5b9250929050565b60006020828403121561181d57600080fd5b8135611125816114eb565b6000825161183a81846020870161112c565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var EtherSenderReceiverABI = EtherSenderReceiverMetaData.ABI
+
+var EtherSenderReceiverBin = EtherSenderReceiverMetaData.Bin
+
+func DeployEtherSenderReceiver(auth *bind.TransactOpts, backend bind.ContractBackend, router common.Address) (common.Address, *types.Transaction, *EtherSenderReceiver, error) {
+ parsed, err := EtherSenderReceiverMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EtherSenderReceiverBin), backend, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EtherSenderReceiver{address: address, abi: *parsed, EtherSenderReceiverCaller: EtherSenderReceiverCaller{contract: contract}, EtherSenderReceiverTransactor: EtherSenderReceiverTransactor{contract: contract}, EtherSenderReceiverFilterer: EtherSenderReceiverFilterer{contract: contract}}, nil
+}
+
+type EtherSenderReceiver struct {
+ address common.Address
+ abi abi.ABI
+ EtherSenderReceiverCaller
+ EtherSenderReceiverTransactor
+ EtherSenderReceiverFilterer
+}
+
+type EtherSenderReceiverCaller struct {
+ contract *bind.BoundContract
+}
+
+type EtherSenderReceiverTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EtherSenderReceiverFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EtherSenderReceiverSession struct {
+ Contract *EtherSenderReceiver
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EtherSenderReceiverCallerSession struct {
+ Contract *EtherSenderReceiverCaller
+ CallOpts bind.CallOpts
+}
+
+type EtherSenderReceiverTransactorSession struct {
+ Contract *EtherSenderReceiverTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EtherSenderReceiverRaw struct {
+ Contract *EtherSenderReceiver
+}
+
+type EtherSenderReceiverCallerRaw struct {
+ Contract *EtherSenderReceiverCaller
+}
+
+type EtherSenderReceiverTransactorRaw struct {
+ Contract *EtherSenderReceiverTransactor
+}
+
+func NewEtherSenderReceiver(address common.Address, backend bind.ContractBackend) (*EtherSenderReceiver, error) {
+ abi, err := abi.JSON(strings.NewReader(EtherSenderReceiverABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEtherSenderReceiver(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EtherSenderReceiver{address: address, abi: abi, EtherSenderReceiverCaller: EtherSenderReceiverCaller{contract: contract}, EtherSenderReceiverTransactor: EtherSenderReceiverTransactor{contract: contract}, EtherSenderReceiverFilterer: EtherSenderReceiverFilterer{contract: contract}}, nil
+}
+
+func NewEtherSenderReceiverCaller(address common.Address, caller bind.ContractCaller) (*EtherSenderReceiverCaller, error) {
+ contract, err := bindEtherSenderReceiver(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EtherSenderReceiverCaller{contract: contract}, nil
+}
+
+func NewEtherSenderReceiverTransactor(address common.Address, transactor bind.ContractTransactor) (*EtherSenderReceiverTransactor, error) {
+ contract, err := bindEtherSenderReceiver(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EtherSenderReceiverTransactor{contract: contract}, nil
+}
+
+func NewEtherSenderReceiverFilterer(address common.Address, filterer bind.ContractFilterer) (*EtherSenderReceiverFilterer, error) {
+ contract, err := bindEtherSenderReceiver(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EtherSenderReceiverFilterer{contract: contract}, nil
+}
+
+func bindEtherSenderReceiver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EtherSenderReceiverMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EtherSenderReceiver.Contract.EtherSenderReceiverCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.EtherSenderReceiverTransactor.contract.Transfer(opts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.EtherSenderReceiverTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EtherSenderReceiver.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.contract.Transfer(opts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCaller) GetFee(opts *bind.CallOpts, destinationChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ var out []interface{}
+ err := _EtherSenderReceiver.contract.Call(opts, &out, "getFee", destinationChainSelector, message)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverSession) GetFee(destinationChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EtherSenderReceiver.Contract.GetFee(&_EtherSenderReceiver.CallOpts, destinationChainSelector, message)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCallerSession) GetFee(destinationChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EtherSenderReceiver.Contract.GetFee(&_EtherSenderReceiver.CallOpts, destinationChainSelector, message)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EtherSenderReceiver.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverSession) GetRouter() (common.Address, error) {
+ return _EtherSenderReceiver.Contract.GetRouter(&_EtherSenderReceiver.CallOpts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCallerSession) GetRouter() (common.Address, error) {
+ return _EtherSenderReceiver.Contract.GetRouter(&_EtherSenderReceiver.CallOpts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCaller) IWeth(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EtherSenderReceiver.contract.Call(opts, &out, "i_weth")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverSession) IWeth() (common.Address, error) {
+ return _EtherSenderReceiver.Contract.IWeth(&_EtherSenderReceiver.CallOpts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCallerSession) IWeth() (common.Address, error) {
+ return _EtherSenderReceiver.Contract.IWeth(&_EtherSenderReceiver.CallOpts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _EtherSenderReceiver.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _EtherSenderReceiver.Contract.SupportsInterface(&_EtherSenderReceiver.CallOpts, interfaceId)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _EtherSenderReceiver.Contract.SupportsInterface(&_EtherSenderReceiver.CallOpts, interfaceId)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EtherSenderReceiver.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverSession) TypeAndVersion() (string, error) {
+ return _EtherSenderReceiver.Contract.TypeAndVersion(&_EtherSenderReceiver.CallOpts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverCallerSession) TypeAndVersion() (string, error) {
+ return _EtherSenderReceiver.Contract.TypeAndVersion(&_EtherSenderReceiver.CallOpts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverTransactor) CcipReceive(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _EtherSenderReceiver.contract.Transact(opts, "ccipReceive", message)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverSession) CcipReceive(message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.CcipReceive(&_EtherSenderReceiver.TransactOpts, message)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverTransactorSession) CcipReceive(message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.CcipReceive(&_EtherSenderReceiver.TransactOpts, message)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverTransactor) CcipSend(opts *bind.TransactOpts, destinationChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _EtherSenderReceiver.contract.Transact(opts, "ccipSend", destinationChainSelector, message)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverSession) CcipSend(destinationChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.CcipSend(&_EtherSenderReceiver.TransactOpts, destinationChainSelector, message)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverTransactorSession) CcipSend(destinationChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.CcipSend(&_EtherSenderReceiver.TransactOpts, destinationChainSelector, message)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EtherSenderReceiver.contract.RawTransact(opts, nil)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverSession) Receive() (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.Receive(&_EtherSenderReceiver.TransactOpts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiverTransactorSession) Receive() (*types.Transaction, error) {
+ return _EtherSenderReceiver.Contract.Receive(&_EtherSenderReceiver.TransactOpts)
+}
+
+func (_EtherSenderReceiver *EtherSenderReceiver) Address() common.Address {
+ return _EtherSenderReceiver.address
+}
+
+type EtherSenderReceiverInterface interface {
+ GetFee(opts *bind.CallOpts, destinationChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ IWeth(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ CcipReceive(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error)
+
+ CcipSend(opts *bind.TransactOpts, destinationChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error)
+
+ Receive(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp/evm_2_evm_multi_offramp.go b/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp/evm_2_evm_multi_offramp.go
new file mode 100644
index 00000000000..9d5e7a4aa78
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_multi_offramp/evm_2_evm_multi_offramp.go
@@ -0,0 +1,2367 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_multi_offramp
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMMultiOffRampCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ MerkleRoots []EVM2EVMMultiOffRampMerkleRoot
+}
+
+type EVM2EVMMultiOffRampDynamicConfig struct {
+ Router common.Address
+ PermissionLessExecutionThresholdSeconds uint32
+ MaxTokenTransferGas uint32
+ MaxPoolReleaseOrMintGas uint32
+ MessageValidator common.Address
+ PriceRegistry common.Address
+}
+
+type EVM2EVMMultiOffRampInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type EVM2EVMMultiOffRampMerkleRoot struct {
+ SourceChainSelector uint64
+ Interval EVM2EVMMultiOffRampInterval
+ MerkleRoot [32]byte
+}
+
+type EVM2EVMMultiOffRampSourceChainConfig struct {
+ IsEnabled bool
+ MinSeqNr uint64
+ OnRamp []byte
+}
+
+type EVM2EVMMultiOffRampSourceChainConfigArgs struct {
+ SourceChainSelector uint64
+ IsEnabled bool
+ OnRamp []byte
+}
+
+type EVM2EVMMultiOffRampStaticConfig struct {
+ ChainSelector uint64
+ RmnProxy common.Address
+ TokenAdminRegistry common.Address
+ NonceManager common.Address
+}
+
+type EVM2EVMMultiOffRampUnblessedRoot struct {
+ SourceChainSelector uint64
+ MerkleRoot [32]byte
+}
+
+type InternalAny2EVMRampMessage struct {
+ Header InternalRampMessageHeader
+ Sender []byte
+ Data []byte
+ Receiver common.Address
+ GasLimit *big.Int
+ TokenAmounts []InternalRampTokenAmount
+}
+
+type InternalExecutionReportSingleChain struct {
+ SourceChainSelector uint64
+ Messages []InternalAny2EVMRampMessage
+ OffchainTokenData [][][]byte
+ Proofs [][32]byte
+ ProofFlagBits *big.Int
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalRampMessageHeader struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ DestChainSelector uint64
+ SequenceNumber uint64
+ Nonce uint64
+}
+
+type InternalRampTokenAmount struct {
+ SourcePoolAddress []byte
+ DestTokenAddress []byte
+ ExtraData []byte
+ Amount *big.Int
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+type MultiOCR3BaseConfigInfo struct {
+ ConfigDigest [32]byte
+ F uint8
+ N uint8
+ IsSignatureVerificationEnabled bool
+}
+
+type MultiOCR3BaseOCRConfig struct {
+ ConfigInfo MultiOCR3BaseConfigInfo
+ Signers []common.Address
+ Transmitters []common.Address
+}
+
+type MultiOCR3BaseOCRConfigArgs struct {
+ ConfigDigest [32]byte
+ OcrPluginType uint8
+ F uint8
+ IsSignatureVerificationEnabled bool
+ Signers []common.Address
+ Transmitters []common.Address
+}
+
+var EVM2EVMMultiOffRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"nonceManager\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPoolReleaseOrMintGas\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"messageValidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.SourceChainConfigArgs[]\",\"name\":\"sourceChainConfigs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"AlreadyAttempted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"AlreadyExecuted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CanOnlySelfCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyReport\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"ExecutionError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enumMultiOCR3Base.InvalidConfigErrorType\",\"name\":\"errorType\",\"type\":\"uint8\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"}],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidEVMAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.Interval\",\"name\":\"interval\",\"type\":\"tuple\"}],\"name\":\"InvalidInterval\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newLimit\",\"type\":\"uint256\"}],\"name\":\"InvalidManualExecutionGasLimit\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"messageDestChainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidMessageDestChainSelector\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"newState\",\"type\":\"uint8\"}],\"name\":\"InvalidNewState\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRoot\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidStaticConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LeavesCannotBeEmpty\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ManualExecutionGasLimitMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"ManualExecutionNotYetEnabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorReason\",\"type\":\"bytes\"}],\"name\":\"MessageValidationError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"notPool\",\"type\":\"address\"}],\"name\":\"NotACompatiblePool\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"ReceiverError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"name\":\"RootAlreadyCommitted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"RootNotCommitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"SourceChainNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleCommitReport\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"}],\"name\":\"StaticConfigCannotBeChanged\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"TokenDataMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"TokenHandlingError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnexpectedTokenData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroChainSelectorNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.MerkleRoot[]\",\"name\":\"merkleRoots\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMMultiOffRamp.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"CommitReportAccepted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"F\",\"type\":\"uint8\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPoolReleaseOrMintGas\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"messageValidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMMultiOffRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"DynamicConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"state\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"name\":\"ExecutionStateChanged\",\"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\":\"root\",\"type\":\"bytes32\"}],\"name\":\"RootRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"SkippedAlreadyExecutedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMMultiOffRamp.SourceChainConfig\",\"name\":\"sourceConfig\",\"type\":\"tuple\"}],\"name\":\"SourceChainConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"SourceChainSelectorAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"nonceManager\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMMultiOffRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"}],\"name\":\"StaticConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.SourceChainConfigArgs[]\",\"name\":\"sourceChainConfigUpdates\",\"type\":\"tuple[]\"}],\"name\":\"applySourceChainConfigUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ccipReceive\",\"outputs\":[],\"stateMutability\":\"pure\",\"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\":\"commit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"execute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.Any2EVMRampMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[]\"}],\"name\":\"executeSingleMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPoolReleaseOrMintGas\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"messageValidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"getExecutionState\",\"outputs\":[{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLatestPriceSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"getMerkleRoot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"getSourceChainConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.SourceChainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"nonceManager\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"}],\"name\":\"latestConfigDetails\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"F\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"n\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isSignatureVerificationEnabled\",\"type\":\"bool\"}],\"internalType\":\"structMultiOCR3Base.ConfigInfo\",\"name\":\"configInfo\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"}],\"internalType\":\"structMultiOCR3Base.OCRConfig\",\"name\":\"ocrConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.Any2EVMRampMessage[]\",\"name\":\"messages\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[][]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[][]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.ExecutionReportSingleChain[]\",\"name\":\"reports\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256[][]\",\"name\":\"gasLimitOverrides\",\"type\":\"uint256[][]\"}],\"name\":\"manuallyExecute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.UnblessedRoot[]\",\"name\":\"rootToReset\",\"type\":\"tuple[]\"}],\"name\":\"resetUnblessedRoots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPoolReleaseOrMintGas\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"messageValidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"setDynamicConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"F\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isSignatureVerificationEnabled\",\"type\":\"bool\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"}],\"internalType\":\"structMultiOCR3Base.OCRConfigArgs[]\",\"name\":\"ocrConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setOCR3Configs\",\"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: "0x6101206040523480156200001257600080fd5b5060405162006af738038062006af78339810160408190526200003591620008e2565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620001fa565b5050466080525060208301516001600160a01b03161580620000ec575060408301516001600160a01b0316155b8062000103575060608301516001600160a01b0316155b1562000122576040516342bcdf7f60e11b815260040160405180910390fd5b82516001600160401b03166000036200014e5760405163c656089560e01b815260040160405180910390fd5b82516001600160401b0390811660a052602080850180516001600160a01b0390811660c05260408088018051831660e0526060808a01805185166101005283518b519098168852945184169587019590955251821690850152905116908201527f683eb52ee924eb817377cfa8f41f238f4bb7a877da5267869dfffbad85f564d89060800160405180910390a1620001e682620002a5565b620001f181620003fc565b50505062000c57565b336001600160a01b03821603620002545760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60a08101516001600160a01b03161580620002c8575080516001600160a01b0316155b15620002e7576040516342bcdf7f60e11b815260040160405180910390fd5b80516004805460208085018051604080880180516060808b0180516001600160a01b039b8c166001600160c01b0319909a168a17600160a01b63ffffffff98891602176001600160c01b0316600160c01b948816949094026001600160e01b031693909317600160e01b93871693909302929092179098556080808b018051600580546001600160a01b0319908116928e1692909217905560a0808e01805160068054909416908f161790925586519a8b5297518716988a0198909852925185169388019390935251909216958501959095525185169383019390935251909216908201527f0da37fd00459f4f5f0b8210d31525e4910ae674b8bab34b561d146bb45773a4c9060c00160405180910390a150565b60005b81518110156200064e57600082828151811062000420576200042062000a20565b60200260200101519050600081600001519050806001600160401b03166000036200045e5760405163c656089560e01b815260040160405180910390fd5b6001600160401b03811660009081526007602052604081206001810180549192916200048a9062000a36565b80601f0160208091040260200160405190810160405280929190818152602001828054620004b89062000a36565b8015620005095780601f10620004dd5761010080835404028352916020019162000509565b820191906000526020600020905b815481529060010190602001808311620004eb57829003601f168201915b505050505090506000846040015190508151600003620005ac57805160000362000546576040516342bcdf7f60e11b815260040160405180910390fd5b6001830162000556828262000ac7565b508254610100600160481b0319166101001783556040516001600160401b03851681527ff4c1390c70e5c0f491ae1ccbc06f9117cbbadf2767b247b3bc203280f24c0fb99060200160405180910390a1620005e7565b8080519060200120828051906020012014620005e75760405163c39a620560e01b81526001600160401b038516600482015260240162000083565b6020850151835460ff19169015151783556040516001600160401b038516907f4f49973170c548fddd4a48341b75e131818913f38f44d47af57e8735eee588ba906200063590869062000b93565b60405180910390a25050505050806001019050620003ff565b5050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156200068d576200068d62000652565b60405290565b604051608081016001600160401b03811182821017156200068d576200068d62000652565b60405160c081016001600160401b03811182821017156200068d576200068d62000652565b604051601f8201601f191681016001600160401b038111828210171562000708576200070862000652565b604052919050565b80516001600160401b03811681146200072857600080fd5b919050565b80516001600160a01b03811681146200072857600080fd5b805163ffffffff811681146200072857600080fd5b6000601f83601f8401126200076e57600080fd5b825160206001600160401b03808311156200078d576200078d62000652565b8260051b6200079e838201620006dd565b9384528681018301938381019089861115620007b957600080fd5b84890192505b85831015620008d557825184811115620007d95760008081fd5b89016060601f19828d038101821315620007f35760008081fd5b620007fd62000668565b6200080a89850162000710565b81526040808501518015158114620008225760008081fd5b828b01529284015192888411156200083a5760008081fd5b83850194508e603f8601126200085257600093508384fd5b898501519350888411156200086b576200086b62000652565b6200087c8a848e87011601620006dd565b92508383528e81858701011115620008945760008081fd5b60005b84811015620008b4578581018201518482018c01528a0162000897565b5060009383018a0193909352918201528352509184019190840190620007bf565b9998505050505050505050565b6000806000838503610160811215620008fa57600080fd5b60808112156200090957600080fd5b6200091362000693565b6200091e8662000710565b81526200092e602087016200072d565b602082015262000941604087016200072d565b604082015262000954606087016200072d565b6060820152935060c0607f19820112156200096e57600080fd5b5062000979620006b8565b62000987608086016200072d565b81526200099760a0860162000745565b6020820152620009aa60c0860162000745565b6040820152620009bd60e0860162000745565b6060820152620009d161010086016200072d565b6080820152620009e561012086016200072d565b60a08201526101408501519092506001600160401b0381111562000a0857600080fd5b62000a16868287016200075a565b9150509250925092565b634e487b7160e01b600052603260045260246000fd5b600181811c9082168062000a4b57607f821691505b60208210810362000a6c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000ac2576000816000526020600020601f850160051c8101602086101562000a9d5750805b601f850160051c820191505b8181101562000abe5782815560010162000aa9565b5050505b505050565b81516001600160401b0381111562000ae35762000ae362000652565b62000afb8162000af4845462000a36565b8462000a72565b602080601f83116001811462000b33576000841562000b1a5750858301515b600019600386901b1c1916600185901b17855562000abe565b600085815260208120601f198616915b8281101562000b645788860151825594840194600190910190840162000b43565b508582101562000b835787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6020808252825460ff811615158383015260081c6001600160401b0316604083015260608083015260018084018054600093929190849062000bd58162000a36565b80608089015260a0600183166000811462000bf9576001811462000c165762000c48565b60ff19841660a08b015260a083151560051b8b0101945062000c48565b85600052602060002060005b8481101562000c3f5781548c820185015290880190890162000c22565b8b0160a0019550505b50929998505050505050505050565b60805160a05160c05160e05161010051615e3162000cc66000396000818161023e0152612c5201526000818161020f0152612f2c0152600081816101e00152818161141801526114cf0152600081816101b001526127cc015260008181611caa0152611cf60152615e316000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806385572ffb116100d8578063d2a15d351161008c578063f2fde38b11610066578063f2fde38b146105ca578063f716f99f146105dd578063ff888fb1146105f057600080fd5b8063d2a15d3514610584578063e9d68a8e14610597578063ece670b6146105b757600080fd5b8063a12a9870116100bd578063a12a98701461050c578063c673e5841461051f578063ccd37ba31461053f57600080fd5b806385572ffb146104e35780638da5cb5b146104f157600080fd5b8063403b2d631161012f5780637437ff9f116101145780637437ff9f1461038557806379ba5097146104c85780637d4eef60146104d057600080fd5b8063403b2d63146103525780635e36480c1461036557600080fd5b80632d04ab76116101605780632d04ab761461030e578063311cd513146103235780633f4b04aa1461033657600080fd5b806306285c691461017c578063181f5a77146102c5575b600080fd5b61026e60408051608081018252600080825260208201819052918101829052606081019190915260405180608001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b6040516102bc9190815167ffffffffffffffff1681526020808301516001600160a01b0390811691830191909152604080840151821690830152606092830151169181019190915260800190565b60405180910390f35b6103016040518060400160405280601d81526020017f45564d3245564d4d756c74694f666652616d7020312e362e302d64657600000081525081565b6040516102bc9190613e9e565b61032161031c366004613f49565b610613565b005b610321610331366004613ffc565b6109d9565b600a5460405167ffffffffffffffff90911681526020016102bc565b610321610360366004614185565b610a42565b610378610373366004614224565b610a56565b6040516102bc9190614281565b61045f6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c0810182526004546001600160a01b03808216835263ffffffff74010000000000000000000000000000000000000000830481166020850152780100000000000000000000000000000000000000000000000083048116948401949094527c010000000000000000000000000000000000000000000000000000000090910490921660608201526005548216608082015260065490911660a082015290565b6040516102bc9190600060c0820190506001600160a01b03808451168352602084015163ffffffff808216602086015280604087015116604086015280606087015116606086015250508060808501511660808401528060a08501511660a08401525092915050565b610321610aac565b6103216104de366004614885565b610b6a565b6103216101773660046149b0565b6000546040516001600160a01b0390911681526020016102bc565b61032161051a366004614a04565b610d0a565b61053261052d366004614b1e565b610d1b565b6040516102bc9190614b7e565b61057661054d366004614bf3565b67ffffffffffffffff919091166000908152600960209081526040808320938352929052205490565b6040519081526020016102bc565b610321610592366004614c1d565b610e79565b6105aa6105a5366004614c92565b610f33565b6040516102bc9190614cad565b6103216105c5366004614ce8565b61101c565b6103216105d8366004614d4c565b61136f565b6103216105eb366004614dd1565b611380565b6106036105fe366004614f0f565b6113c2565b60405190151581526020016102bc565b6000610621878901896150ad565b8051515190915015158061063a57508051602001515115155b1561073a57600a5460208a01359067ffffffffffffffff808316911610156106f957600a805467ffffffffffffffff191667ffffffffffffffff831617905560065482516040517f3937306f0000000000000000000000000000000000000000000000000000000081526001600160a01b0390921691633937306f916106c291600401615315565b600060405180830381600087803b1580156106dc57600080fd5b505af11580156106f0573d6000803e3d6000fd5b50505050610738565b816020015151600003610738576040517f2261116700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b60005b8160200151518110156109225760008260200151828151811061076257610762615218565b6020026020010151905060008160000151905061077e81611483565b600061078982611585565b602084015151815491925067ffffffffffffffff908116610100909204161415806107cb575060208084015190810151905167ffffffffffffffff9182169116115b1561081457825160208401516040517feefb0cac00000000000000000000000000000000000000000000000000000000815261080b929190600401615328565b60405180910390fd5b604083015180610850576040517f504570e300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835167ffffffffffffffff166000908152600960209081526040808320848452909152902054156108c35783516040517f32cf0cbf00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024810182905260440161080b565b60208085015101516108d6906001615373565b825468ffffffffffffffff00191661010067ffffffffffffffff92831602179092559251166000908152600960209081526040808320948352939052919091204290555060010161073d565b507f3a3950e13dd607cc37980db0ef14266c40d2bba9c01b2e44bfe549808883095d81604051610952919061539b565b60405180910390a16109ce60008a8a8a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b92506115e5915050565b505050505050505050565b610a196109e882840184615438565b6040805160008082526020820190925290610a13565b60608152602001906001900390816109fe5790505b5061195c565b604080516000808252602082019092529050610a3c6001858585858660006115e5565b50505050565b610a4a611a0c565b610a5381611a68565b50565b6000610a646001600461546d565b6002610a71608085615496565b67ffffffffffffffff16610a8591906154bd565b610a8f8585611c60565b901c166003811115610aa357610aa3614257565b90505b92915050565b6001546001600160a01b03163314610b065760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161080b565b600080543373ffffffffffffffffffffffffffffffffffffffff19808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b72611ca7565b815181518114610bae576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610cfa576000848281518110610bcd57610bcd615218565b60200260200101519050600081602001515190506000858481518110610bf557610bf5615218565b6020026020010151905080518214610c39576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82811015610ceb576000828281518110610c5857610c58615218565b6020026020010151905080600014610ce25784602001518281518110610c8057610c80615218565b602002602001015160800151811015610ce25784516040517fc8e9605100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602481018390526044810182905260640161080b565b50600101610c3c565b50505050806001019050610bb1565b50610d05838361195c565b505050565b610d12611a0c565b610a5381611d28565b610d5e6040805160e081019091526000606082018181526080830182905260a0830182905260c08301919091528190815260200160608152602001606081525090565b60ff808316600090815260026020818152604092839020835160e081018552815460608201908152600183015480881660808401526101008104881660a0840152620100009004909616151560c082015294855291820180548451818402810184019095528085529293858301939092830182828015610e0757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610de9575b5050505050815260200160038201805480602002602001604051908101604052809291908181526020018280548015610e6957602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610e4b575b5050505050815250509050919050565b610e81611a0c565b60005b81811015610d05576000838383818110610ea057610ea0615218565b905060400201803603810190610eb691906154d4565b9050610ec581602001516113c2565b610f2a57805167ffffffffffffffff1660009081526009602090815260408083208285018051855290835281842093909355915191519182527f202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12910160405180910390a15b50600101610e84565b60408051606080820183526000808352602080840182905283850183905267ffffffffffffffff8681168352600782529185902085519384018652805460ff811615158552610100900490921690830152600181018054939492939192840191610f9c9061550d565b80601f0160208091040260200160405190810160405280929190818152602001828054610fc89061550d565b8015610e695780601f10610fea57610100808354040283529160200191610e69565b820191906000526020600020905b815481529060010190602001808311610ff857505050919092525091949350505050565b333014611055576040517f371a732800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160008082526020820190925281611092565b604080518082019091526000808252602082015281526020019060019003908161106b5790505b5060a084015151909150156110c5576110c28360a001518460200151856060015186600001516020015186611fb4565b90505b6040805160a0810182528451518152845160209081015167ffffffffffffffff1681830152808601518351600094840192611101929101613e9e565b60408051601f19818403018152918152908252868101516020830152018390526005549091506001600160a01b0316801561120e576040517f08d450a10000000000000000000000000000000000000000000000000000000081526001600160a01b038216906308d450a19061117b9085906004016155e9565b600060405180830381600087803b15801561119557600080fd5b505af19250505080156111a6575060015b61120e573d8080156111d4576040519150601f19603f3d011682016040523d82523d6000602084013e6111d9565b606091505b50806040517f09c2532500000000000000000000000000000000000000000000000000000000815260040161080b9190613e9e565b60408501515115801561122357506080850151155b8061123a575060608501516001600160a01b03163b155b8061127a57506060850151611278906001600160a01b03167f85572ffb00000000000000000000000000000000000000000000000000000000612092565b155b15611286575050505050565b60048054608087015160608801516040517f3cf9798300000000000000000000000000000000000000000000000000000000815260009485946001600160a01b031693633cf97983936112e1938a93611388939291016155fc565b6000604051808303816000875af1158015611300573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113289190810190615638565b50915091508161136657806040517f0a8d6e8c00000000000000000000000000000000000000000000000000000000815260040161080b9190613e9e565b50505050505050565b611377611a0c565b610a53816120ae565b611388611a0c565b60005b81518110156113be576113b68282815181106113a9576113a9615218565b6020026020010151612164565b60010161138b565b5050565b6040805180820182523081526020810183815291517f4d61677100000000000000000000000000000000000000000000000000000000815290516001600160a01b039081166004830152915160248201526000917f00000000000000000000000000000000000000000000000000000000000000001690634d61677190604401602060405180830381865afa15801561145f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa691906156ce565b6040517f2cbc26bb000000000000000000000000000000000000000000000000000000008152608082901b77ffffffffffffffff000000000000000000000000000000001660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632cbc26bb90602401602060405180830381865afa15801561151e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154291906156ce565b15610a53576040517ffdbd6a7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8216600482015260240161080b565b67ffffffffffffffff81166000908152600760205260408120805460ff16610aa6576040517fed053c5900000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8416600482015260240161080b565b60ff878116600090815260026020908152604080832081516080810183528154815260019091015480861693820193909352610100830485169181019190915262010000909104909216151560608301528735906116448760a46156eb565b905082606001511561168c57845161165d9060206154bd565b865161166a9060206154bd565b6116759060a06156eb565b61167f91906156eb565b61168990826156eb565b90505b3681146116ce576040517f8e1192e10000000000000000000000000000000000000000000000000000000081526004810182905236602482015260440161080b565b50815181146117165781516040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101919091526024810182905260440161080b565b61171e611ca7565b60ff808a166000908152600360209081526040808320338452825280832081518083019092528054808616835293949193909284019161010090910416600281111561176c5761176c614257565b600281111561177d5761177d614257565b905250905060028160200151600281111561179a5761179a614257565b1480156117ee5750600260008b60ff1660ff168152602001908152602001600020600301816000015160ff16815481106117d6576117d6615218565b6000918252602090912001546001600160a01b031633145b611824576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5081606001511561190657602082015161183f9060016156fe565b60ff1685511461187b576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83518551146118b6576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600087876040516118c8929190615717565b6040519081900381206118df918b90602001615727565b6040516020818303038152906040528051906020012090506119048a828888886124a8565b505b6040805182815260208a81013567ffffffffffffffff169082015260ff8b16917f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef0910160405180910390a2505050505050505050565b8151600003611996576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160408051600080825260208201909252911591905b8451811015611a05576119fd8582815181106119cb576119cb615218565b6020026020010151846119f7578583815181106119ea576119ea615218565b60200260200101516126bf565b836126bf565b6001016119ad565b5050505050565b6000546001600160a01b03163314611a665760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161080b565b565b60a08101516001600160a01b03161580611a8a575080516001600160a01b0316155b15611ac1576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516004805460208085018051604080880180516060808b0180516001600160a01b039b8c167fffffffffffffffff000000000000000000000000000000000000000000000000909a168a177401000000000000000000000000000000000000000063ffffffff988916021777ffffffffffffffffffffffffffffffffffffffffffffffff167801000000000000000000000000000000000000000000000000948816949094027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16939093177c010000000000000000000000000000000000000000000000000000000093871693909302929092179098556080808b0180516005805473ffffffffffffffffffffffffffffffffffffffff19908116928e1692909217905560a0808e01805160068054909416908f161790925586519a8b5297518716988a0198909852925185169388019390935251909216958501959095525185169383019390935251909216908201527f0da37fd00459f4f5f0b8210d31525e4910ae674b8bab34b561d146bb45773a4c9060c00160405180910390a150565b67ffffffffffffffff8216600090815260086020526040812081611c8560808561573b565b67ffffffffffffffff1681526020810191909152604001600020549392505050565b467f000000000000000000000000000000000000000000000000000000000000000014611a66576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600482015246602482015260440161080b565b60005b81518110156113be576000828281518110611d4857611d48615218565b602002602001015190506000816000015190508067ffffffffffffffff16600003611d9f576040517fc656089500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600760205260408120600181018054919291611dca9061550d565b80601f0160208091040260200160405190810160405280929190818152602001828054611df69061550d565b8015611e435780601f10611e1857610100808354040283529160200191611e43565b820191906000526020600020905b815481529060010190602001808311611e2657829003601f168201915b505050505090506000846040015190508151600003611efc578051600003611e97576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018301611ea582826157aa565b50825468ffffffffffffffff00191661010017835560405167ffffffffffffffff851681527ff4c1390c70e5c0f491ae1ccbc06f9117cbbadf2767b247b3bc203280f24c0fb99060200160405180910390a1611f4f565b8080519060200120828051906020012014611f4f576040517fc39a620500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8516600482015260240161080b565b6020850151835460ff191690151517835560405167ffffffffffffffff8516907f4f49973170c548fddd4a48341b75e131818913f38f44d47af57e8735eee588ba90611f9c90869061586a565b60405180910390a25050505050806001019050611d2b565b6060855167ffffffffffffffff811115611fd057611fd0614050565b60405190808252806020026020018201604052801561201557816020015b6040805180820190915260008082526020820152815260200190600190039081611fee5790505b50905060005b86518110156120885761206387828151811061203957612039615218565b602002602001015187878787868151811061205657612056615218565b6020026020010151612ecb565b82828151811061207557612075615218565b602090810291909101015260010161201b565b5095945050505050565b600061209d836132da565b8015610aa35750610aa3838361333e565b336001600160a01b038216036121065760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161080b565b6001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b806040015160ff1660000361218f576000604051631b3fab5160e11b815260040161080b9190615926565b60208082015160ff808216600090815260029093526040832060018101549293909283921690036121fc57606084015160018201805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055612251565b6060840151600182015460ff6201000090910416151590151514612251576040517f87f6037c00000000000000000000000000000000000000000000000000000000815260ff8416600482015260240161080b565b60a08401518051601f60ff82161115612280576001604051631b3fab5160e11b815260040161080b9190615926565b6122e685856003018054806020026020016040519081016040528092919081815260200182805480156122dc57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122be575b505050505061340d565b8560600151156124155761235485856002018054806020026020016040519081016040528092919081815260200182805480156122dc576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116122be57505050505061340d565b6080860151805161236e9060028701906020840190613da8565b5080516001850180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff841690810291909117909155601f10156123ce576002604051631b3fab5160e11b815260040161080b9190615926565b60408801516123de906003615940565b60ff168160ff1611612406576003604051631b3fab5160e11b815260040161080b9190615926565b61241287836001613476565b50505b61242185836002613476565b81516124369060038601906020850190613da8565b5060408681015160018501805460ff191660ff8316179055875180865560a089015192517fab8b1b57514019638d7b5ce9c638fe71366fe8e2be1c40a7a80f1733d0e9f5479361248f938a939260028b0192919061595c565b60405180910390a16124a0856135f6565b505050505050565b6124b0613e1a565b835160005b818110156126b55760006001888684602081106124d4576124d4615218565b6124e191901a601b6156fe565b8985815181106124f3576124f3615218565b602002602001015189868151811061250d5761250d615218565b60200260200101516040516000815260200160405260405161254b949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561256d573d6000803e3d6000fd5b505060408051601f1981015160ff808e166000908152600360209081528582206001600160a01b038516835281528582208587019096528554808416865293975090955092939284019161010090041660028111156125ce576125ce614257565b60028111156125df576125df614257565b90525090506001816020015160028111156125fc576125fc614257565b14612633576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f811061264a5761264a615218565b602002015115612686576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f81106126a1576126a1615218565b9115156020909202015250506001016124b5565b5050505050505050565b81516126ca81611483565b60006126d582611585565b6020850151519091506000819003612718576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460400151518114612756576040517f57e0e08300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561277157612771614050565b60405190808252806020026020018201604052801561279a578160200160208202803683370190505b50905060005b8281101561290f576000876020015182815181106127c0576127c0615218565b602002602001015190507f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681600001516040015167ffffffffffffffff161461285357805160409081015190517f38432a2200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff909116600482015260240161080b565b6128e9818660010180546128669061550d565b80601f01602080910402602001604051908101604052809291908181526020018280546128929061550d565b80156128df5780601f106128b4576101008083540402835291602001916128df565b820191906000526020600020905b8154815290600101906020018083116128c257829003601f168201915b5050505050613612565b8383815181106128fb576128fb615218565b6020908102919091010152506001016127a0565b506000612926858389606001518a60800151613734565b90508060000361296e576040517f7dd17a7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8616600482015260240161080b565b8551151560005b848110156109ce5760008960200151828151811061299557612995615218565b6020026020010151905060006129b389836000015160600151610a56565b905060028160038111156129c9576129c9614257565b03612a20578151606001516040805167ffffffffffffffff808d16825290921660208301527f3b575419319662b2a6f5e2467d84521517a3382b908eb3d557bb3fdb0c50e23c910160405180910390a15050612ec3565b6000816003811115612a3457612a34614257565b1480612a5157506003816003811115612a4f57612a4f614257565b145b612aa2578151606001516040517f25507e7f00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff808c166004830152909116602482015260440161080b565b8315612b835760045460009074010000000000000000000000000000000000000000900463ffffffff16612ad6874261546d565b1190508080612af657506003826003811115612af457612af4614257565b145b612b38576040517fa9cfc86200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8b16600482015260240161080b565b8a8481518110612b4a57612b4a615218565b6020026020010151600014612b7d578a8481518110612b6b57612b6b615218565b60200260200101518360800181815250505b50612be9565b6000816003811115612b9757612b97614257565b14612be9578151606001516040517f3ef2a99c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff808c166004830152909116602482015260440161080b565b81516080015167ffffffffffffffff1615612cd7576000816003811115612c1257612c12614257565b03612cd75781516080015160208301516040517fe0e03cae0000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263e0e03cae92612c89928e9291906004016159e2565b6020604051808303816000875af1158015612ca8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ccc91906156ce565b612cd7575050612ec3565b60008b604001518481518110612cef57612cef615218565b6020026020010151905080518360a001515114612d53578251606001516040517f1cfe6d8b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff808d166004830152909116602482015260440161080b565b612d678a846000015160600151600161378a565b600080612d748584613832565b91509150612d8b8c8660000151606001518461378a565b8615612dfb576003826003811115612da557612da5614257565b03612dfb576000846003811115612dbe57612dbe614257565b14612dfb578451516040517f2b11b8d900000000000000000000000000000000000000000000000000000000815261080b91908390600401615a0f565b6002826003811115612e0f57612e0f614257565b14612e69576003826003811115612e2857612e28614257565b14612e69578451606001516040517f926c5a3e00000000000000000000000000000000000000000000000000000000815261080b918e918590600401615a28565b8451805160609091015160405167ffffffffffffffff918216918f16907f8c324ce1367b83031769f6a813e3bb4c117aba2185789d66b98b791405be6df290612eb59087908790615a4e565b60405180910390a450505050505b600101612975565b60408051808201909152600080825260208201526000612eee87602001516138fc565b6040517fbbe4f6db0000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bbe4f6db90602401602060405180830381865afa158015612f73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f979190615a6e565b90506001600160a01b0381161580612fdf5750612fdd6001600160a01b0382167faff2afbf00000000000000000000000000000000000000000000000000000000612092565b155b15613021576040517fae9b4ce90000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260240161080b565b6000806131276040518061010001604052808b81526020018967ffffffffffffffff1681526020018a6001600160a01b031681526020018c606001518152602001866001600160a01b031681526020018c6000015181526020018c604001518152602001888152506040516024016130999190615a8b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f3907753700000000000000000000000000000000000000000000000000000000179052600454859063ffffffff7c01000000000000000000000000000000000000000000000000000000009091041661138860846139a2565b50915091508161316557806040517fe1cd550900000000000000000000000000000000000000000000000000000000815260040161080b9190613e9e565b80516020146131ad5780516040517f78ef802400000000000000000000000000000000000000000000000000000000815260206004820152602481019190915260440161080b565b6000818060200190518101906131c39190615b62565b6040516001600160a01b038b166024820152604481018290529091506132709060640160408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600454879063ffffffff78010000000000000000000000000000000000000000000000009091041661138860846139a2565b509093509150826132af57816040517fe1cd550900000000000000000000000000000000000000000000000000000000815260040161080b9190613e9e565b604080518082019091526001600160a01b039095168552602085015250919250505095945050505050565b6000613306827f01ffc9a70000000000000000000000000000000000000000000000000000000061333e565b8015610aa65750613337827fffffffff0000000000000000000000000000000000000000000000000000000061333e565b1592915050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d915060005190508280156133f6575060208210155b80156134025750600081115b979650505050505050565b60005b8151811015610d055760ff83166000908152600360205260408120835190919084908490811061344257613442615218565b6020908102919091018101516001600160a01b03168252810191909152604001600020805461ffff19169055600101613410565b60005b82518160ff161015610a3c576000838260ff168151811061349c5761349c615218565b60200260200101519050600060028111156134b9576134b9614257565b60ff80871660009081526003602090815260408083206001600160a01b038716845290915290205461010090041660028111156134f8576134f8614257565b14613519576004604051631b3fab5160e11b815260040161080b9190615926565b6001600160a01b038116613559576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052808360ff16815260200184600281111561357f5761357f614257565b905260ff80871660009081526003602090815260408083206001600160a01b0387168452825290912083518154931660ff198416811782559184015190929091839161ffff1916176101008360028111156135dc576135dc614257565b021790555090505050806135ef90615b7b565b9050613479565b60ff8116610a5357600a805467ffffffffffffffff1916905550565b815160208082015160409283015192516000938493613658937f2425b0b9f9054c76ff151b0a175b18f37a4a4e82013a72e9f15c9caa095ed21f93909291889101615b9a565b60408051601f1981840301815290829052805160209182012086518051888401516060808b0151908401516080808d015195015195976136a19794969395929491939101615bcd565b604051602081830303815290604052805190602001208560400151805190602001208660a001516040516020016136d89190615cc4565b60408051601f198184030181528282528051602091820120908301969096528101939093526060830191909152608082015260a081019190915260c0015b60405160208183030381529060405280519060200120905092915050565b600080613742858585613ac8565b905061374d816113c2565b61375b576000915050613782565b67ffffffffffffffff86166000908152600960209081526040808320938352929052205490505b949350505050565b60006002613799608085615496565b67ffffffffffffffff166137ad91906154bd565b905060006137bb8585611c60565b9050816137ca6001600461546d565b901b1916818360038111156137e1576137e1614257565b67ffffffffffffffff871660009081526008602052604081209190921b9290921791829161381060808861573b565b67ffffffffffffffff1681526020810191909152604001600020555050505050565b6040517fece670b6000000000000000000000000000000000000000000000000000000008152600090606090309063ece670b6906138769087908790600401615d24565b600060405180830381600087803b15801561389057600080fd5b505af19250505080156138a1575060015b6138e0573d8080156138cf576040519150601f19603f3d011682016040523d82523d6000602084013e6138d4565b606091505b506003925090506138f5565b50506040805160208101909152600081526002905b9250929050565b6000815160201461393b57816040517f8d666f6000000000000000000000000000000000000000000000000000000000815260040161080b9190613e9e565b6000828060200190518101906139519190615b62565b90506001600160a01b03811180613969575061040081105b15610aa657826040517f8d666f6000000000000000000000000000000000000000000000000000000000815260040161080b9190613e9e565b6000606060008361ffff1667ffffffffffffffff8111156139c5576139c5614050565b6040519080825280601f01601f1916602001820160405280156139ef576020820181803683370190505b509150863b613a22577f0c3b563c0000000000000000000000000000000000000000000000000000000060005260046000fd5b5a85811015613a55577fafa32a2c0000000000000000000000000000000000000000000000000000000060005260046000fd5b8590036040810481038710613a8e577f37c3be290000000000000000000000000000000000000000000000000000000060005260046000fd5b505a6000808a5160208c0160008c8cf193505a900390503d84811115613ab15750835b808352806000602085013e50955095509592505050565b8251825160009190818303613b09576040517f11a6b26400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101018211801590613b1d57506101018111155b613b3a576040516309bde33960e01b815260040160405180910390fd5b60001982820101610100811115613b64576040516309bde33960e01b815260040160405180910390fd5b80600003613b915786600081518110613b7f57613b7f615218565b60200260200101519350505050613d60565b60008167ffffffffffffffff811115613bac57613bac614050565b604051908082528060200260200182016040528015613bd5578160200160208202803683370190505b50905060008080805b85811015613cff5760006001821b8b811603613c395788851015613c22578c5160018601958e918110613c1357613c13615218565b60200260200101519050613c5b565b8551600185019487918110613c1357613c13615218565b8b5160018401938d918110613c5057613c50615218565b602002602001015190505b600089861015613c8b578d5160018701968f918110613c7c57613c7c615218565b60200260200101519050613cad565b8651600186019588918110613ca257613ca2615218565b602002602001015190505b82851115613cce576040516309bde33960e01b815260040160405180910390fd5b613cd88282613d67565b878481518110613cea57613cea615218565b60209081029190910101525050600101613bde565b506001850382148015613d1157508683145b8015613d1c57508581145b613d39576040516309bde33960e01b815260040160405180910390fd5b836001860381518110613d4e57613d4e615218565b60200260200101519750505050505050505b9392505050565b6000818310613d7f57613d7a8284613d85565b610aa3565b610aa383835b604080516001602082015290810183905260608101829052600090608001613716565b828054828255906000526020600020908101928215613e0a579160200282015b82811115613e0a578251825473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909116178255602090920191600190910190613dc8565b50613e16929150613e39565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b80821115613e165760008155600101613e3a565b60005b83811015613e69578181015183820152602001613e51565b50506000910152565b60008151808452613e8a816020860160208601613e4e565b601f01601f19169290920160200192915050565b602081526000610aa36020830184613e72565b8060608101831015610aa657600080fd5b60008083601f840112613ed457600080fd5b50813567ffffffffffffffff811115613eec57600080fd5b6020830191508360208285010111156138f557600080fd5b60008083601f840112613f1657600080fd5b50813567ffffffffffffffff811115613f2e57600080fd5b6020830191508360208260051b85010111156138f557600080fd5b60008060008060008060008060e0898b031215613f6557600080fd5b613f6f8a8a613eb1565b9750606089013567ffffffffffffffff80821115613f8c57600080fd5b613f988c838d01613ec2565b909950975060808b0135915080821115613fb157600080fd5b613fbd8c838d01613f04565b909750955060a08b0135915080821115613fd657600080fd5b50613fe38b828c01613f04565b999c989b50969995989497949560c00135949350505050565b60008060006080848603121561401157600080fd5b61401b8585613eb1565b9250606084013567ffffffffffffffff81111561403757600080fd5b61404386828701613ec2565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561408957614089614050565b60405290565b60405160a0810167ffffffffffffffff8111828210171561408957614089614050565b6040516080810167ffffffffffffffff8111828210171561408957614089614050565b6040516060810167ffffffffffffffff8111828210171561408957614089614050565b6040805190810167ffffffffffffffff8111828210171561408957614089614050565b604051601f8201601f1916810167ffffffffffffffff8111828210171561414457614144614050565b604052919050565b6001600160a01b0381168114610a5357600080fd5b803561416c8161414c565b919050565b803563ffffffff8116811461416c57600080fd5b600060c0828403121561419757600080fd5b61419f614066565b82356141aa8161414c565b81526141b860208401614171565b60208201526141c960408401614171565b60408201526141da60608401614171565b606082015260808301356141ed8161414c565b608082015260a08301356142008161414c565b60a08201529392505050565b803567ffffffffffffffff8116811461416c57600080fd5b6000806040838503121561423757600080fd5b6142408361420c565b915061424e6020840161420c565b90509250929050565b634e487b7160e01b600052602160045260246000fd5b6004811061427d5761427d614257565b9052565b60208101610aa6828461426d565b600067ffffffffffffffff8211156142a9576142a9614050565b5060051b60200190565b600060a082840312156142c557600080fd5b6142cd61408f565b9050813581526142df6020830161420c565b60208201526142f06040830161420c565b60408201526143016060830161420c565b60608201526143126080830161420c565b608082015292915050565b600067ffffffffffffffff82111561433757614337614050565b50601f01601f191660200190565b600082601f83011261435657600080fd5b81356143696143648261431d565b61411b565b81815284602083860101111561437e57600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126143ac57600080fd5b813560206143bc6143648361428f565b82815260059290921b840181019181810190868411156143db57600080fd5b8286015b848110156144b157803567ffffffffffffffff808211156144005760008081fd5b8189019150608080601f19848d0301121561441b5760008081fd5b6144236140b2565b87840135838111156144355760008081fd5b6144438d8a83880101614345565b8252506040808501358481111561445a5760008081fd5b6144688e8b83890101614345565b8a84015250606080860135858111156144815760008081fd5b61448f8f8c838a0101614345565b92840192909252949092013593810193909352505083529183019183016143df565b509695505050505050565b600061014082840312156144cf57600080fd5b6144d7614066565b90506144e383836142b3565b815260a082013567ffffffffffffffff8082111561450057600080fd5b61450c85838601614345565b602084015260c084013591508082111561452557600080fd5b61453185838601614345565b604084015261454260e08501614161565b6060840152610100840135608084015261012084013591508082111561456757600080fd5b506145748482850161439b565b60a08301525092915050565b600082601f83011261459157600080fd5b813560206145a16143648361428f565b82815260059290921b840181019181810190868411156145c057600080fd5b8286015b848110156144b157803567ffffffffffffffff8111156145e45760008081fd5b6145f28986838b01016144bc565b8452509183019183016145c4565b600082601f83011261461157600080fd5b813560206146216143648361428f565b82815260059290921b8401810191818101908684111561464057600080fd5b8286015b848110156144b157803567ffffffffffffffff8111156146645760008081fd5b6146728986838b0101614345565b845250918301918301614644565b600082601f83011261469157600080fd5b813560206146a16143648361428f565b82815260059290921b840181019181810190868411156146c057600080fd5b8286015b848110156144b157803567ffffffffffffffff8111156146e45760008081fd5b6146f28986838b0101614600565b8452509183019183016146c4565b600082601f83011261471157600080fd5b813560206147216143648361428f565b8083825260208201915060208460051b87010193508684111561474357600080fd5b602086015b848110156144b15780358352918301918301614748565b600082601f83011261477057600080fd5b813560206147806143648361428f565b82815260059290921b8401810191818101908684111561479f57600080fd5b8286015b848110156144b157803567ffffffffffffffff808211156147c45760008081fd5b818901915060a080601f19848d030112156147df5760008081fd5b6147e761408f565b6147f288850161420c565b8152604080850135848111156148085760008081fd5b6148168e8b83890101614580565b8a840152506060808601358581111561482f5760008081fd5b61483d8f8c838a0101614680565b83850152506080915081860135858111156148585760008081fd5b6148668f8c838a0101614700565b91840191909152509190930135908301525083529183019183016147a3565b600080604080848603121561489957600080fd5b833567ffffffffffffffff808211156148b157600080fd5b6148bd8783880161475f565b94506020915081860135818111156148d457600080fd5b8601601f810188136148e557600080fd5b80356148f36143648261428f565b81815260059190911b8201840190848101908a83111561491257600080fd5b8584015b8381101561499e5780358681111561492e5760008081fd5b8501603f81018d136149405760008081fd5b878101356149506143648261428f565b81815260059190911b82018a0190898101908f8311156149705760008081fd5b928b01925b8284101561498e5783358252928a0192908a0190614975565b8652505050918601918601614916565b50809750505050505050509250929050565b6000602082840312156149c257600080fd5b813567ffffffffffffffff8111156149d957600080fd5b820160a08185031215613d6057600080fd5b8015158114610a5357600080fd5b803561416c816149eb565b60006020808385031215614a1757600080fd5b823567ffffffffffffffff80821115614a2f57600080fd5b818501915085601f830112614a4357600080fd5b8135614a516143648261428f565b81815260059190911b83018401908481019088831115614a7057600080fd5b8585015b83811015614b0057803585811115614a8c5760008081fd5b86016060818c03601f1901811315614aa45760008081fd5b614aac6140d5565b614ab78a840161420c565b8152604080840135614ac8816149eb565b828c0152918301359188831115614adf5760008081fd5b614aed8e8c85870101614345565b9082015285525050918601918601614a74565b5098975050505050505050565b803560ff8116811461416c57600080fd5b600060208284031215614b3057600080fd5b610aa382614b0d565b60008151808452602080850194506020840160005b83811015614b735781516001600160a01b031687529582019590820190600101614b4e565b509495945050505050565b60208152600082518051602084015260ff602082015116604084015260ff604082015116606084015260608101511515608084015250602083015160c060a0840152614bcd60e0840182614b39565b90506040840151601f198483030160c0850152614bea8282614b39565b95945050505050565b60008060408385031215614c0657600080fd5b614c0f8361420c565b946020939093013593505050565b60008060208385031215614c3057600080fd5b823567ffffffffffffffff80821115614c4857600080fd5b818501915085601f830112614c5c57600080fd5b813581811115614c6b57600080fd5b8660208260061b8501011115614c8057600080fd5b60209290920196919550909350505050565b600060208284031215614ca457600080fd5b610aa38261420c565b6020815281511515602082015267ffffffffffffffff6020830151166040820152600060408301516060808401526137826080840182613e72565b60008060408385031215614cfb57600080fd5b823567ffffffffffffffff80821115614d1357600080fd5b614d1f868387016144bc565b93506020850135915080821115614d3557600080fd5b50614d4285828601614600565b9150509250929050565b600060208284031215614d5e57600080fd5b8135613d608161414c565b600082601f830112614d7a57600080fd5b81356020614d8a6143648361428f565b8083825260208201915060208460051b870101935086841115614dac57600080fd5b602086015b848110156144b1578035614dc48161414c565b8352918301918301614db1565b60006020808385031215614de457600080fd5b823567ffffffffffffffff80821115614dfc57600080fd5b818501915085601f830112614e1057600080fd5b8135614e1e6143648261428f565b81815260059190911b83018401908481019088831115614e3d57600080fd5b8585015b83811015614b0057803585811115614e5857600080fd5b860160c0818c03601f19011215614e6f5760008081fd5b614e77614066565b8882013581526040614e8a818401614b0d565b8a8301526060614e9b818501614b0d565b8284015260809150614eae8285016149f9565b9083015260a08381013589811115614ec65760008081fd5b614ed48f8d83880101614d69565b838501525060c0840135915088821115614eee5760008081fd5b614efc8e8c84870101614d69565b9083015250845250918601918601614e41565b600060208284031215614f2157600080fd5b5035919050565b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461416c57600080fd5b600082601f830112614f6557600080fd5b81356020614f756143648361428f565b82815260069290921b84018101918181019086841115614f9457600080fd5b8286015b848110156144b15760408189031215614fb15760008081fd5b614fb96140f8565b614fc28261420c565b8152614fcf858301614f28565b81860152835291830191604001614f98565b600082601f830112614ff257600080fd5b813560206150026143648361428f565b82815260079290921b8401810191818101908684111561502157600080fd5b8286015b848110156144b157808803608081121561503f5760008081fd5b6150476140d5565b6150508361420c565b8152604080601f19840112156150665760008081fd5b61506e6140f8565b925061507b87850161420c565b835261508881850161420c565b8388015281870192909252606083013591810191909152835291830191608001615025565b600060208083850312156150c057600080fd5b823567ffffffffffffffff808211156150d857600080fd5b818501915060408083880312156150ee57600080fd5b6150f66140f8565b83358381111561510557600080fd5b84016040818a03121561511757600080fd5b61511f6140f8565b81358581111561512e57600080fd5b8201601f81018b1361513f57600080fd5b803561514d6143648261428f565b81815260069190911b8201890190898101908d83111561516c57600080fd5b928a01925b828410156151bc5787848f0312156151895760008081fd5b6151916140f8565b843561519c8161414c565b81526151a9858d01614f28565b818d0152825292870192908a0190615171565b8452505050818701359350848411156151d457600080fd5b6151e08a858401614f54565b81880152825250838501359150828211156151fa57600080fd5b61520688838601614fe1565b85820152809550505050505092915050565b634e487b7160e01b600052603260045260246000fd5b805160408084528151848201819052600092602091908201906060870190855b8181101561529a57835180516001600160a01b031684528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1685840152928401929185019160010161524e565b50508583015187820388850152805180835290840192506000918401905b80831015615309578351805167ffffffffffffffff1683528501517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16858301529284019260019290920191908501906152b8565b50979650505050505050565b602081526000610aa3602083018461522e565b67ffffffffffffffff8316815260608101613d606020830184805167ffffffffffffffff908116835260209182015116910152565b634e487b7160e01b600052601160045260246000fd5b67ffffffffffffffff8181168382160190808211156153945761539461535d565b5092915050565b6000602080835260608451604080848701526153ba606087018361522e565b87850151878203601f19016040890152805180835290860193506000918601905b80831015614b0057845167ffffffffffffffff81511683528781015161541a89850182805167ffffffffffffffff908116835260209182015116910152565b508401518287015293860193600192909201916080909101906153db565b60006020828403121561544a57600080fd5b813567ffffffffffffffff81111561546157600080fd5b6137828482850161475f565b81810381811115610aa657610aa661535d565b634e487b7160e01b600052601260045260246000fd5b600067ffffffffffffffff808416806154b1576154b1615480565b92169190910692915050565b8082028115828204841417610aa657610aa661535d565b6000604082840312156154e657600080fd5b6154ee6140f8565b6154f78361420c565b8152602083013560208201528091505092915050565b600181811c9082168061552157607f821691505b60208210810361554157634e487b7160e01b600052602260045260246000fd5b50919050565b805182526000602067ffffffffffffffff81840151168185015260408084015160a0604087015261557b60a0870182613e72565b9050606085015186820360608801526155948282613e72565b608087810151898303918a01919091528051808352908601935060009250908501905b8083101561530957835180516001600160a01b03168352860151868301529285019260019290920191908401906155b7565b602081526000610aa36020830184615547565b60808152600061560f6080830187615547565b61ffff9590951660208301525060408101929092526001600160a01b0316606090910152919050565b60008060006060848603121561564d57600080fd5b8351615658816149eb565b602085015190935067ffffffffffffffff81111561567557600080fd5b8401601f8101861361568657600080fd5b80516156946143648261431d565b8181528760208385010111156156a957600080fd5b6156ba826020830160208601613e4e565b809450505050604084015190509250925092565b6000602082840312156156e057600080fd5b8151613d60816149eb565b80820180821115610aa657610aa661535d565b60ff8181168382160190811115610aa657610aa661535d565b8183823760009101908152919050565b828152606082602083013760800192915050565b600067ffffffffffffffff8084168061575657615756615480565b92169190910492915050565b601f821115610d05576000816000526020600020601f850160051c8101602086101561578b5750805b601f850160051c820191505b818110156124a057828155600101615797565b815167ffffffffffffffff8111156157c4576157c4614050565b6157d8816157d2845461550d565b84615762565b602080601f83116001811461580d57600084156157f55750858301515b600019600386901b1c1916600185901b1785556124a0565b600085815260208120601f198616915b8281101561583c5788860151825594840194600190910190840161581d565b508582101561585a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808352835460ff81161515602085015267ffffffffffffffff8160081c166040850152506001808501606080860152600081546158aa8161550d565b80608089015260a060018316600081146158cb57600181146158e757615917565b60ff19841660a08b015260a083151560051b8b01019450615917565b85600052602060002060005b8481101561590e5781548c82018501529088019089016158f3565b8b0160a0019550505b50929998505050505050505050565b602081016005831061593a5761593a614257565b91905290565b60ff81811683821602908116908181146153945761539461535d565b600060a0820160ff88168352602087602085015260a0604085015281875480845260c086019150886000526020600020935060005b818110156159b65784546001600160a01b031683526001948501949284019201615991565b505084810360608601526159ca8188614b39565b935050505060ff831660808301529695505050505050565b600067ffffffffffffffff808616835280851660208401525060606040830152614bea6060830184613e72565b8281526040602082015260006137826040830184613e72565b67ffffffffffffffff84811682528316602082015260608101613782604083018461426d565b615a58818461426d565b6040602082015260006137826040830184613e72565b600060208284031215615a8057600080fd5b8151613d608161414c565b6020815260008251610100806020850152615aaa610120850183613e72565b91506020850151615ac7604086018267ffffffffffffffff169052565b5060408501516001600160a01b038116606086015250606085015160808501526080850151615b0160a08601826001600160a01b03169052565b5060a0850151601f19808685030160c0870152615b1e8483613e72565b935060c08701519150808685030160e0870152615b3b8483613e72565b935060e0870151915080868503018387015250615b588382613e72565b9695505050505050565b600060208284031215615b7457600080fd5b5051919050565b600060ff821660ff8103615b9157615b9161535d565b60010192915050565b848152600067ffffffffffffffff808616602084015280851660408401525060806060830152615b586080830184613e72565b86815260c060208201526000615be660c0830188613e72565b6001600160a01b039690961660408301525067ffffffffffffffff9384166060820152608081019290925290911660a09091015292915050565b600082825180855260208086019550808260051b84010181860160005b84811015615cb757601f19868403018952815160808151818652615c6382870182613e72565b9150508582015185820387870152615c7b8282613e72565b91505060408083015186830382880152615c958382613e72565b6060948501519790940196909652505098840198925090830190600101615c3d565b5090979650505050505050565b602081526000610aa36020830184615c20565b60008282518085526020808601955060208260051b8401016020860160005b84811015615cb757601f19868403018952615d12838351613e72565b98840198925090830190600101615cf6565b604081526000835180516040840152602081015167ffffffffffffffff80821660608601528060408401511660808601528060608401511660a08601528060808401511660c086015250505060208401516101408060e0850152615d8c610180850183613e72565b915060408601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08086850301610100870152615dc98483613e72565b935060608801519150615de86101208701836001600160a01b03169052565b60808801518387015260a0880151925080868503016101608701525050615e0f8282615c20565b9150508281036020840152614bea8185615cd756fea164736f6c6343000818000a",
+}
+
+var EVM2EVMMultiOffRampABI = EVM2EVMMultiOffRampMetaData.ABI
+
+var EVM2EVMMultiOffRampBin = EVM2EVMMultiOffRampMetaData.Bin
+
+func DeployEVM2EVMMultiOffRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMMultiOffRampStaticConfig, dynamicConfig EVM2EVMMultiOffRampDynamicConfig, sourceChainConfigs []EVM2EVMMultiOffRampSourceChainConfigArgs) (common.Address, *types.Transaction, *EVM2EVMMultiOffRamp, error) {
+ parsed, err := EVM2EVMMultiOffRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMMultiOffRampBin), backend, staticConfig, dynamicConfig, sourceChainConfigs)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMMultiOffRamp{address: address, abi: *parsed, EVM2EVMMultiOffRampCaller: EVM2EVMMultiOffRampCaller{contract: contract}, EVM2EVMMultiOffRampTransactor: EVM2EVMMultiOffRampTransactor{contract: contract}, EVM2EVMMultiOffRampFilterer: EVM2EVMMultiOffRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMMultiOffRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMMultiOffRampCaller
+ EVM2EVMMultiOffRampTransactor
+ EVM2EVMMultiOffRampFilterer
+}
+
+type EVM2EVMMultiOffRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMMultiOffRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMMultiOffRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMMultiOffRampSession struct {
+ Contract *EVM2EVMMultiOffRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMMultiOffRampCallerSession struct {
+ Contract *EVM2EVMMultiOffRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMMultiOffRampTransactorSession struct {
+ Contract *EVM2EVMMultiOffRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMMultiOffRampRaw struct {
+ Contract *EVM2EVMMultiOffRamp
+}
+
+type EVM2EVMMultiOffRampCallerRaw struct {
+ Contract *EVM2EVMMultiOffRampCaller
+}
+
+type EVM2EVMMultiOffRampTransactorRaw struct {
+ Contract *EVM2EVMMultiOffRampTransactor
+}
+
+func NewEVM2EVMMultiOffRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMMultiOffRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMMultiOffRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMMultiOffRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRamp{address: address, abi: abi, EVM2EVMMultiOffRampCaller: EVM2EVMMultiOffRampCaller{contract: contract}, EVM2EVMMultiOffRampTransactor: EVM2EVMMultiOffRampTransactor{contract: contract}, EVM2EVMMultiOffRampFilterer: EVM2EVMMultiOffRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMMultiOffRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMMultiOffRampCaller, error) {
+ contract, err := bindEVM2EVMMultiOffRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMMultiOffRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMMultiOffRampTransactor, error) {
+ contract, err := bindEVM2EVMMultiOffRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMMultiOffRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMMultiOffRampFilterer, error) {
+ contract, err := bindEVM2EVMMultiOffRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMMultiOffRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMMultiOffRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMMultiOffRamp.Contract.EVM2EVMMultiOffRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.EVM2EVMMultiOffRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.EVM2EVMMultiOffRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMMultiOffRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) CcipReceive(opts *bind.CallOpts, arg0 ClientAny2EVMMessage) error {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "ccipReceive", arg0)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) CcipReceive(arg0 ClientAny2EVMMessage) error {
+ return _EVM2EVMMultiOffRamp.Contract.CcipReceive(&_EVM2EVMMultiOffRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) CcipReceive(arg0 ClientAny2EVMMessage) error {
+ return _EVM2EVMMultiOffRamp.Contract.CcipReceive(&_EVM2EVMMultiOffRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMMultiOffRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMMultiOffRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMMultiOffRampDynamicConfig)).(*EVM2EVMMultiOffRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) GetDynamicConfig() (EVM2EVMMultiOffRampDynamicConfig, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetDynamicConfig(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) GetDynamicConfig() (EVM2EVMMultiOffRampDynamicConfig, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetDynamicConfig(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) GetExecutionState(opts *bind.CallOpts, sourceChainSelector uint64, sequenceNumber uint64) (uint8, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "getExecutionState", sourceChainSelector, sequenceNumber)
+
+ if err != nil {
+ return *new(uint8), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) GetExecutionState(sourceChainSelector uint64, sequenceNumber uint64) (uint8, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetExecutionState(&_EVM2EVMMultiOffRamp.CallOpts, sourceChainSelector, sequenceNumber)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) GetExecutionState(sourceChainSelector uint64, sequenceNumber uint64) (uint8, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetExecutionState(&_EVM2EVMMultiOffRamp.CallOpts, sourceChainSelector, sequenceNumber)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) GetLatestPriceSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "getLatestPriceSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) GetLatestPriceSequenceNumber() (uint64, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetLatestPriceSequenceNumber(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) GetLatestPriceSequenceNumber() (uint64, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetLatestPriceSequenceNumber(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) GetMerkleRoot(opts *bind.CallOpts, sourceChainSelector uint64, root [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "getMerkleRoot", sourceChainSelector, root)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) GetMerkleRoot(sourceChainSelector uint64, root [32]byte) (*big.Int, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetMerkleRoot(&_EVM2EVMMultiOffRamp.CallOpts, sourceChainSelector, root)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) GetMerkleRoot(sourceChainSelector uint64, root [32]byte) (*big.Int, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetMerkleRoot(&_EVM2EVMMultiOffRamp.CallOpts, sourceChainSelector, root)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) GetSourceChainConfig(opts *bind.CallOpts, sourceChainSelector uint64) (EVM2EVMMultiOffRampSourceChainConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "getSourceChainConfig", sourceChainSelector)
+
+ if err != nil {
+ return *new(EVM2EVMMultiOffRampSourceChainConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMMultiOffRampSourceChainConfig)).(*EVM2EVMMultiOffRampSourceChainConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) GetSourceChainConfig(sourceChainSelector uint64) (EVM2EVMMultiOffRampSourceChainConfig, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetSourceChainConfig(&_EVM2EVMMultiOffRamp.CallOpts, sourceChainSelector)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) GetSourceChainConfig(sourceChainSelector uint64) (EVM2EVMMultiOffRampSourceChainConfig, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetSourceChainConfig(&_EVM2EVMMultiOffRamp.CallOpts, sourceChainSelector)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMMultiOffRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMMultiOffRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMMultiOffRampStaticConfig)).(*EVM2EVMMultiOffRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) GetStaticConfig() (EVM2EVMMultiOffRampStaticConfig, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetStaticConfig(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) GetStaticConfig() (EVM2EVMMultiOffRampStaticConfig, error) {
+ return _EVM2EVMMultiOffRamp.Contract.GetStaticConfig(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "isBlessed", root)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) IsBlessed(root [32]byte) (bool, error) {
+ return _EVM2EVMMultiOffRamp.Contract.IsBlessed(&_EVM2EVMMultiOffRamp.CallOpts, root)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) IsBlessed(root [32]byte) (bool, error) {
+ return _EVM2EVMMultiOffRamp.Contract.IsBlessed(&_EVM2EVMMultiOffRamp.CallOpts, root)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) LatestConfigDetails(opts *bind.CallOpts, ocrPluginType uint8) (MultiOCR3BaseOCRConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "latestConfigDetails", ocrPluginType)
+
+ if err != nil {
+ return *new(MultiOCR3BaseOCRConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(MultiOCR3BaseOCRConfig)).(*MultiOCR3BaseOCRConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) LatestConfigDetails(ocrPluginType uint8) (MultiOCR3BaseOCRConfig, error) {
+ return _EVM2EVMMultiOffRamp.Contract.LatestConfigDetails(&_EVM2EVMMultiOffRamp.CallOpts, ocrPluginType)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) LatestConfigDetails(ocrPluginType uint8) (MultiOCR3BaseOCRConfig, error) {
+ return _EVM2EVMMultiOffRamp.Contract.LatestConfigDetails(&_EVM2EVMMultiOffRamp.CallOpts, ocrPluginType)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMMultiOffRamp.Contract.Owner(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMMultiOffRamp.Contract.Owner(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOffRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMMultiOffRamp.Contract.TypeAndVersion(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMMultiOffRamp.Contract.TypeAndVersion(&_EVM2EVMMultiOffRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.AcceptOwnership(&_EVM2EVMMultiOffRamp.TransactOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.AcceptOwnership(&_EVM2EVMMultiOffRamp.TransactOpts)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) ApplySourceChainConfigUpdates(opts *bind.TransactOpts, sourceChainConfigUpdates []EVM2EVMMultiOffRampSourceChainConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "applySourceChainConfigUpdates", sourceChainConfigUpdates)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) ApplySourceChainConfigUpdates(sourceChainConfigUpdates []EVM2EVMMultiOffRampSourceChainConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.ApplySourceChainConfigUpdates(&_EVM2EVMMultiOffRamp.TransactOpts, sourceChainConfigUpdates)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) ApplySourceChainConfigUpdates(sourceChainConfigUpdates []EVM2EVMMultiOffRampSourceChainConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.ApplySourceChainConfigUpdates(&_EVM2EVMMultiOffRamp.TransactOpts, sourceChainConfigUpdates)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) Commit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "commit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) Commit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.Commit(&_EVM2EVMMultiOffRamp.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) Commit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.Commit(&_EVM2EVMMultiOffRamp.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) Execute(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "execute", reportContext, report)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) Execute(reportContext [3][32]byte, report []byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.Execute(&_EVM2EVMMultiOffRamp.TransactOpts, reportContext, report)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) Execute(reportContext [3][32]byte, report []byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.Execute(&_EVM2EVMMultiOffRamp.TransactOpts, reportContext, report)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) ExecuteSingleMessage(opts *bind.TransactOpts, message InternalAny2EVMRampMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "executeSingleMessage", message, offchainTokenData)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) ExecuteSingleMessage(message InternalAny2EVMRampMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.ExecuteSingleMessage(&_EVM2EVMMultiOffRamp.TransactOpts, message, offchainTokenData)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) ExecuteSingleMessage(message InternalAny2EVMRampMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.ExecuteSingleMessage(&_EVM2EVMMultiOffRamp.TransactOpts, message, offchainTokenData)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) ManuallyExecute(opts *bind.TransactOpts, reports []InternalExecutionReportSingleChain, gasLimitOverrides [][]*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "manuallyExecute", reports, gasLimitOverrides)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) ManuallyExecute(reports []InternalExecutionReportSingleChain, gasLimitOverrides [][]*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.ManuallyExecute(&_EVM2EVMMultiOffRamp.TransactOpts, reports, gasLimitOverrides)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) ManuallyExecute(reports []InternalExecutionReportSingleChain, gasLimitOverrides [][]*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.ManuallyExecute(&_EVM2EVMMultiOffRamp.TransactOpts, reports, gasLimitOverrides)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset []EVM2EVMMultiOffRampUnblessedRoot) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "resetUnblessedRoots", rootToReset)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) ResetUnblessedRoots(rootToReset []EVM2EVMMultiOffRampUnblessedRoot) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.ResetUnblessedRoots(&_EVM2EVMMultiOffRamp.TransactOpts, rootToReset)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) ResetUnblessedRoots(rootToReset []EVM2EVMMultiOffRampUnblessedRoot) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.ResetUnblessedRoots(&_EVM2EVMMultiOffRamp.TransactOpts, rootToReset)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMMultiOffRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "setDynamicConfig", dynamicConfig)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) SetDynamicConfig(dynamicConfig EVM2EVMMultiOffRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.SetDynamicConfig(&_EVM2EVMMultiOffRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) SetDynamicConfig(dynamicConfig EVM2EVMMultiOffRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.SetDynamicConfig(&_EVM2EVMMultiOffRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) SetOCR3Configs(opts *bind.TransactOpts, ocrConfigArgs []MultiOCR3BaseOCRConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "setOCR3Configs", ocrConfigArgs)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) SetOCR3Configs(ocrConfigArgs []MultiOCR3BaseOCRConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.SetOCR3Configs(&_EVM2EVMMultiOffRamp.TransactOpts, ocrConfigArgs)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) SetOCR3Configs(ocrConfigArgs []MultiOCR3BaseOCRConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.SetOCR3Configs(&_EVM2EVMMultiOffRamp.TransactOpts, ocrConfigArgs)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.TransferOwnership(&_EVM2EVMMultiOffRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOffRamp.Contract.TransferOwnership(&_EVM2EVMMultiOffRamp.TransactOpts, to)
+}
+
+type EVM2EVMMultiOffRampCommitReportAcceptedIterator struct {
+ Event *EVM2EVMMultiOffRampCommitReportAccepted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampCommitReportAcceptedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampCommitReportAccepted)
+ 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(EVM2EVMMultiOffRampCommitReportAccepted)
+ 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 *EVM2EVMMultiOffRampCommitReportAcceptedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampCommitReportAcceptedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampCommitReportAccepted struct {
+ Report EVM2EVMMultiOffRampCommitReport
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterCommitReportAccepted(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampCommitReportAcceptedIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "CommitReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampCommitReportAcceptedIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "CommitReportAccepted", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchCommitReportAccepted(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampCommitReportAccepted) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "CommitReportAccepted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampCommitReportAccepted)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "CommitReportAccepted", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseCommitReportAccepted(log types.Log) (*EVM2EVMMultiOffRampCommitReportAccepted, error) {
+ event := new(EVM2EVMMultiOffRampCommitReportAccepted)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "CommitReportAccepted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampConfigSetIterator struct {
+ Event *EVM2EVMMultiOffRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampConfigSet)
+ 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(EVM2EVMMultiOffRampConfigSet)
+ 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 *EVM2EVMMultiOffRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampConfigSet struct {
+ OcrPluginType uint8
+ ConfigDigest [32]byte
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampConfigSetIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampConfigSet)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMMultiOffRampConfigSet, error) {
+ event := new(EVM2EVMMultiOffRampConfigSet)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampDynamicConfigSetIterator struct {
+ Event *EVM2EVMMultiOffRampDynamicConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampDynamicConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampDynamicConfigSet)
+ 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(EVM2EVMMultiOffRampDynamicConfigSet)
+ 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 *EVM2EVMMultiOffRampDynamicConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampDynamicConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampDynamicConfigSet struct {
+ DynamicConfig EVM2EVMMultiOffRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterDynamicConfigSet(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampDynamicConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "DynamicConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampDynamicConfigSetIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "DynamicConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchDynamicConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampDynamicConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "DynamicConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampDynamicConfigSet)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "DynamicConfigSet", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseDynamicConfigSet(log types.Log) (*EVM2EVMMultiOffRampDynamicConfigSet, error) {
+ event := new(EVM2EVMMultiOffRampDynamicConfigSet)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "DynamicConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampExecutionStateChangedIterator struct {
+ Event *EVM2EVMMultiOffRampExecutionStateChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampExecutionStateChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampExecutionStateChanged)
+ 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(EVM2EVMMultiOffRampExecutionStateChanged)
+ 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 *EVM2EVMMultiOffRampExecutionStateChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampExecutionStateChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampExecutionStateChanged struct {
+ SourceChainSelector uint64
+ SequenceNumber uint64
+ MessageId [32]byte
+ State uint8
+ ReturnData []byte
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterExecutionStateChanged(opts *bind.FilterOpts, sourceChainSelector []uint64, sequenceNumber []uint64, messageId [][32]byte) (*EVM2EVMMultiOffRampExecutionStateChangedIterator, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "ExecutionStateChanged", sourceChainSelectorRule, sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampExecutionStateChangedIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "ExecutionStateChanged", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampExecutionStateChanged, sourceChainSelector []uint64, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "ExecutionStateChanged", sourceChainSelectorRule, sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampExecutionStateChanged)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "ExecutionStateChanged", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseExecutionStateChanged(log types.Log) (*EVM2EVMMultiOffRampExecutionStateChanged, error) {
+ event := new(EVM2EVMMultiOffRampExecutionStateChanged)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "ExecutionStateChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMMultiOffRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampOwnershipTransferRequested)
+ 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(EVM2EVMMultiOffRampOwnershipTransferRequested)
+ 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 *EVM2EVMMultiOffRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMMultiOffRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampOwnershipTransferRequestedIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampOwnershipTransferRequested)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMMultiOffRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMMultiOffRampOwnershipTransferRequested)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMMultiOffRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampOwnershipTransferred)
+ 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(EVM2EVMMultiOffRampOwnershipTransferred)
+ 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 *EVM2EVMMultiOffRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMMultiOffRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampOwnershipTransferredIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampOwnershipTransferred)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMMultiOffRampOwnershipTransferred, error) {
+ event := new(EVM2EVMMultiOffRampOwnershipTransferred)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampRootRemovedIterator struct {
+ Event *EVM2EVMMultiOffRampRootRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampRootRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampRootRemoved)
+ 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(EVM2EVMMultiOffRampRootRemoved)
+ 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 *EVM2EVMMultiOffRampRootRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampRootRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampRootRemoved struct {
+ Root [32]byte
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterRootRemoved(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampRootRemovedIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampRootRemovedIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "RootRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampRootRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "RootRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampRootRemoved)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "RootRemoved", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseRootRemoved(log types.Log) (*EVM2EVMMultiOffRampRootRemoved, error) {
+ event := new(EVM2EVMMultiOffRampRootRemoved)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "RootRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampSkippedAlreadyExecutedMessageIterator struct {
+ Event *EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampSkippedAlreadyExecutedMessageIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage)
+ 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(EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage)
+ 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 *EVM2EVMMultiOffRampSkippedAlreadyExecutedMessageIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampSkippedAlreadyExecutedMessageIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage struct {
+ SourceChainSelector uint64
+ SequenceNumber uint64
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterSkippedAlreadyExecutedMessage(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampSkippedAlreadyExecutedMessageIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "SkippedAlreadyExecutedMessage")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampSkippedAlreadyExecutedMessageIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "SkippedAlreadyExecutedMessage", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchSkippedAlreadyExecutedMessage(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "SkippedAlreadyExecutedMessage")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "SkippedAlreadyExecutedMessage", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseSkippedAlreadyExecutedMessage(log types.Log) (*EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage, error) {
+ event := new(EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "SkippedAlreadyExecutedMessage", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampSourceChainConfigSetIterator struct {
+ Event *EVM2EVMMultiOffRampSourceChainConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampSourceChainConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampSourceChainConfigSet)
+ 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(EVM2EVMMultiOffRampSourceChainConfigSet)
+ 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 *EVM2EVMMultiOffRampSourceChainConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampSourceChainConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampSourceChainConfigSet struct {
+ SourceChainSelector uint64
+ SourceConfig EVM2EVMMultiOffRampSourceChainConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterSourceChainConfigSet(opts *bind.FilterOpts, sourceChainSelector []uint64) (*EVM2EVMMultiOffRampSourceChainConfigSetIterator, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "SourceChainConfigSet", sourceChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampSourceChainConfigSetIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "SourceChainConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchSourceChainConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampSourceChainConfigSet, sourceChainSelector []uint64) (event.Subscription, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "SourceChainConfigSet", sourceChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampSourceChainConfigSet)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "SourceChainConfigSet", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseSourceChainConfigSet(log types.Log) (*EVM2EVMMultiOffRampSourceChainConfigSet, error) {
+ event := new(EVM2EVMMultiOffRampSourceChainConfigSet)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "SourceChainConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampSourceChainSelectorAddedIterator struct {
+ Event *EVM2EVMMultiOffRampSourceChainSelectorAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampSourceChainSelectorAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampSourceChainSelectorAdded)
+ 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(EVM2EVMMultiOffRampSourceChainSelectorAdded)
+ 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 *EVM2EVMMultiOffRampSourceChainSelectorAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampSourceChainSelectorAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampSourceChainSelectorAdded struct {
+ SourceChainSelector uint64
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterSourceChainSelectorAdded(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampSourceChainSelectorAddedIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "SourceChainSelectorAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampSourceChainSelectorAddedIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "SourceChainSelectorAdded", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchSourceChainSelectorAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampSourceChainSelectorAdded) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "SourceChainSelectorAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampSourceChainSelectorAdded)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "SourceChainSelectorAdded", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseSourceChainSelectorAdded(log types.Log) (*EVM2EVMMultiOffRampSourceChainSelectorAdded, error) {
+ event := new(EVM2EVMMultiOffRampSourceChainSelectorAdded)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "SourceChainSelectorAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampStaticConfigSetIterator struct {
+ Event *EVM2EVMMultiOffRampStaticConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampStaticConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampStaticConfigSet)
+ 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(EVM2EVMMultiOffRampStaticConfigSet)
+ 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 *EVM2EVMMultiOffRampStaticConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampStaticConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampStaticConfigSet struct {
+ StaticConfig EVM2EVMMultiOffRampStaticConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterStaticConfigSet(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampStaticConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "StaticConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampStaticConfigSetIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "StaticConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchStaticConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampStaticConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "StaticConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampStaticConfigSet)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "StaticConfigSet", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseStaticConfigSet(log types.Log) (*EVM2EVMMultiOffRampStaticConfigSet, error) {
+ event := new(EVM2EVMMultiOffRampStaticConfigSet)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "StaticConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOffRampTransmittedIterator struct {
+ Event *EVM2EVMMultiOffRampTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOffRampTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOffRampTransmitted)
+ 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(EVM2EVMMultiOffRampTransmitted)
+ 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 *EVM2EVMMultiOffRampTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOffRampTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOffRampTransmitted struct {
+ OcrPluginType uint8
+ ConfigDigest [32]byte
+ SequenceNumber uint64
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) FilterTransmitted(opts *bind.FilterOpts, ocrPluginType []uint8) (*EVM2EVMMultiOffRampTransmittedIterator, error) {
+
+ var ocrPluginTypeRule []interface{}
+ for _, ocrPluginTypeItem := range ocrPluginType {
+ ocrPluginTypeRule = append(ocrPluginTypeRule, ocrPluginTypeItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.FilterLogs(opts, "Transmitted", ocrPluginTypeRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOffRampTransmittedIterator{contract: _EVM2EVMMultiOffRamp.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampTransmitted, ocrPluginType []uint8) (event.Subscription, error) {
+
+ var ocrPluginTypeRule []interface{}
+ for _, ocrPluginTypeItem := range ocrPluginType {
+ ocrPluginTypeRule = append(ocrPluginTypeRule, ocrPluginTypeItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOffRamp.contract.WatchLogs(opts, "Transmitted", ocrPluginTypeRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOffRampTransmitted)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "Transmitted", 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 (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRampFilterer) ParseTransmitted(log types.Log) (*EVM2EVMMultiOffRampTransmitted, error) {
+ event := new(EVM2EVMMultiOffRampTransmitted)
+ if err := _EVM2EVMMultiOffRamp.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMMultiOffRamp.abi.Events["CommitReportAccepted"].ID:
+ return _EVM2EVMMultiOffRamp.ParseCommitReportAccepted(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMMultiOffRamp.ParseConfigSet(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["DynamicConfigSet"].ID:
+ return _EVM2EVMMultiOffRamp.ParseDynamicConfigSet(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["ExecutionStateChanged"].ID:
+ return _EVM2EVMMultiOffRamp.ParseExecutionStateChanged(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMMultiOffRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMMultiOffRamp.ParseOwnershipTransferred(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["RootRemoved"].ID:
+ return _EVM2EVMMultiOffRamp.ParseRootRemoved(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["SkippedAlreadyExecutedMessage"].ID:
+ return _EVM2EVMMultiOffRamp.ParseSkippedAlreadyExecutedMessage(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["SourceChainConfigSet"].ID:
+ return _EVM2EVMMultiOffRamp.ParseSourceChainConfigSet(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["SourceChainSelectorAdded"].ID:
+ return _EVM2EVMMultiOffRamp.ParseSourceChainSelectorAdded(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["StaticConfigSet"].ID:
+ return _EVM2EVMMultiOffRamp.ParseStaticConfigSet(log)
+ case _EVM2EVMMultiOffRamp.abi.Events["Transmitted"].ID:
+ return _EVM2EVMMultiOffRamp.ParseTransmitted(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMMultiOffRampCommitReportAccepted) Topic() common.Hash {
+ return common.HexToHash("0x3a3950e13dd607cc37980db0ef14266c40d2bba9c01b2e44bfe549808883095d")
+}
+
+func (EVM2EVMMultiOffRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xab8b1b57514019638d7b5ce9c638fe71366fe8e2be1c40a7a80f1733d0e9f547")
+}
+
+func (EVM2EVMMultiOffRampDynamicConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x0da37fd00459f4f5f0b8210d31525e4910ae674b8bab34b561d146bb45773a4c")
+}
+
+func (EVM2EVMMultiOffRampExecutionStateChanged) Topic() common.Hash {
+ return common.HexToHash("0x8c324ce1367b83031769f6a813e3bb4c117aba2185789d66b98b791405be6df2")
+}
+
+func (EVM2EVMMultiOffRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMMultiOffRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (EVM2EVMMultiOffRampRootRemoved) Topic() common.Hash {
+ return common.HexToHash("0x202f1139a3e334b6056064c0e9b19fd07e44a88d8f6e5ded571b24cf8c371f12")
+}
+
+func (EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage) Topic() common.Hash {
+ return common.HexToHash("0x3b575419319662b2a6f5e2467d84521517a3382b908eb3d557bb3fdb0c50e23c")
+}
+
+func (EVM2EVMMultiOffRampSourceChainConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x4f49973170c548fddd4a48341b75e131818913f38f44d47af57e8735eee588ba")
+}
+
+func (EVM2EVMMultiOffRampSourceChainSelectorAdded) Topic() common.Hash {
+ return common.HexToHash("0xf4c1390c70e5c0f491ae1ccbc06f9117cbbadf2767b247b3bc203280f24c0fb9")
+}
+
+func (EVM2EVMMultiOffRampStaticConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x683eb52ee924eb817377cfa8f41f238f4bb7a877da5267869dfffbad85f564d8")
+}
+
+func (EVM2EVMMultiOffRampTransmitted) Topic() common.Hash {
+ return common.HexToHash("0x198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef0")
+}
+
+func (_EVM2EVMMultiOffRamp *EVM2EVMMultiOffRamp) Address() common.Address {
+ return _EVM2EVMMultiOffRamp.address
+}
+
+type EVM2EVMMultiOffRampInterface interface {
+ CcipReceive(opts *bind.CallOpts, arg0 ClientAny2EVMMessage) error
+
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMMultiOffRampDynamicConfig, error)
+
+ GetExecutionState(opts *bind.CallOpts, sourceChainSelector uint64, sequenceNumber uint64) (uint8, error)
+
+ GetLatestPriceSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetMerkleRoot(opts *bind.CallOpts, sourceChainSelector uint64, root [32]byte) (*big.Int, error)
+
+ GetSourceChainConfig(opts *bind.CallOpts, sourceChainSelector uint64) (EVM2EVMMultiOffRampSourceChainConfig, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMMultiOffRampStaticConfig, error)
+
+ IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error)
+
+ LatestConfigDetails(opts *bind.CallOpts, ocrPluginType uint8) (MultiOCR3BaseOCRConfig, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplySourceChainConfigUpdates(opts *bind.TransactOpts, sourceChainConfigUpdates []EVM2EVMMultiOffRampSourceChainConfigArgs) (*types.Transaction, error)
+
+ Commit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ Execute(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte) (*types.Transaction, error)
+
+ ExecuteSingleMessage(opts *bind.TransactOpts, message InternalAny2EVMRampMessage, offchainTokenData [][]byte) (*types.Transaction, error)
+
+ ManuallyExecute(opts *bind.TransactOpts, reports []InternalExecutionReportSingleChain, gasLimitOverrides [][]*big.Int) (*types.Transaction, error)
+
+ ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset []EVM2EVMMultiOffRampUnblessedRoot) (*types.Transaction, error)
+
+ SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMMultiOffRampDynamicConfig) (*types.Transaction, error)
+
+ SetOCR3Configs(opts *bind.TransactOpts, ocrConfigArgs []MultiOCR3BaseOCRConfigArgs) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterCommitReportAccepted(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampCommitReportAcceptedIterator, error)
+
+ WatchCommitReportAccepted(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampCommitReportAccepted) (event.Subscription, error)
+
+ ParseCommitReportAccepted(log types.Log) (*EVM2EVMMultiOffRampCommitReportAccepted, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMMultiOffRampConfigSet, error)
+
+ FilterDynamicConfigSet(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampDynamicConfigSetIterator, error)
+
+ WatchDynamicConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampDynamicConfigSet) (event.Subscription, error)
+
+ ParseDynamicConfigSet(log types.Log) (*EVM2EVMMultiOffRampDynamicConfigSet, error)
+
+ FilterExecutionStateChanged(opts *bind.FilterOpts, sourceChainSelector []uint64, sequenceNumber []uint64, messageId [][32]byte) (*EVM2EVMMultiOffRampExecutionStateChangedIterator, error)
+
+ WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampExecutionStateChanged, sourceChainSelector []uint64, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error)
+
+ ParseExecutionStateChanged(log types.Log) (*EVM2EVMMultiOffRampExecutionStateChanged, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMMultiOffRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMMultiOffRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMMultiOffRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMMultiOffRampOwnershipTransferred, error)
+
+ FilterRootRemoved(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampRootRemovedIterator, error)
+
+ WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampRootRemoved) (event.Subscription, error)
+
+ ParseRootRemoved(log types.Log) (*EVM2EVMMultiOffRampRootRemoved, error)
+
+ FilterSkippedAlreadyExecutedMessage(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampSkippedAlreadyExecutedMessageIterator, error)
+
+ WatchSkippedAlreadyExecutedMessage(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage) (event.Subscription, error)
+
+ ParseSkippedAlreadyExecutedMessage(log types.Log) (*EVM2EVMMultiOffRampSkippedAlreadyExecutedMessage, error)
+
+ FilterSourceChainConfigSet(opts *bind.FilterOpts, sourceChainSelector []uint64) (*EVM2EVMMultiOffRampSourceChainConfigSetIterator, error)
+
+ WatchSourceChainConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampSourceChainConfigSet, sourceChainSelector []uint64) (event.Subscription, error)
+
+ ParseSourceChainConfigSet(log types.Log) (*EVM2EVMMultiOffRampSourceChainConfigSet, error)
+
+ FilterSourceChainSelectorAdded(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampSourceChainSelectorAddedIterator, error)
+
+ WatchSourceChainSelectorAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampSourceChainSelectorAdded) (event.Subscription, error)
+
+ ParseSourceChainSelectorAdded(log types.Log) (*EVM2EVMMultiOffRampSourceChainSelectorAdded, error)
+
+ FilterStaticConfigSet(opts *bind.FilterOpts) (*EVM2EVMMultiOffRampStaticConfigSetIterator, error)
+
+ WatchStaticConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampStaticConfigSet) (event.Subscription, error)
+
+ ParseStaticConfigSet(log types.Log) (*EVM2EVMMultiOffRampStaticConfigSet, error)
+
+ FilterTransmitted(opts *bind.FilterOpts, ocrPluginType []uint8) (*EVM2EVMMultiOffRampTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOffRampTransmitted, ocrPluginType []uint8) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*EVM2EVMMultiOffRampTransmitted, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_multi_onramp/evm_2_evm_multi_onramp.go b/core/gethwrappers/ccip/generated/evm_2_evm_multi_onramp/evm_2_evm_multi_onramp.go
new file mode 100644
index 00000000000..e8c07cb93d6
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_multi_onramp/evm_2_evm_multi_onramp.go
@@ -0,0 +1,1489 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_multi_onramp
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMMultiOnRampDynamicConfig struct {
+ Router common.Address
+ PriceRegistry common.Address
+ MessageValidator common.Address
+ FeeAggregator common.Address
+}
+
+type EVM2EVMMultiOnRampStaticConfig struct {
+ ChainSelector uint64
+ RmnProxy common.Address
+ NonceManager common.Address
+ TokenAdminRegistry common.Address
+}
+
+type InternalEVM2AnyRampMessage struct {
+ Header InternalRampMessageHeader
+ Sender common.Address
+ Data []byte
+ Receiver []byte
+ ExtraArgs []byte
+ FeeToken common.Address
+ FeeTokenAmount *big.Int
+ TokenAmounts []InternalRampTokenAmount
+}
+
+type InternalRampMessageHeader struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ DestChainSelector uint64
+ SequenceNumber uint64
+ Nonce uint64
+}
+
+type InternalRampTokenAmount struct {
+ SourcePoolAddress []byte
+ DestTokenAddress []byte
+ ExtraData []byte
+ Amount *big.Int
+}
+
+var EVM2EVMMultiOnRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"nonceManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"messageValidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeAggregator\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotSendZeroTokens\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExtraArgOutOfOrderExecutionMustBeTrue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GetSupportedTokensFunctionalityRemovedCheckAdminRegistry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MessageGasLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeCalledByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustSetOriginalSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"UnsupportedToken\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"structInternal.EVM2AnyRampMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"CCIPSendRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"nonceManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMMultiOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"messageValidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeAggregator\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMMultiOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeValueJuels\",\"type\":\"uint256\"}],\"name\":\"FeePaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeAggregator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeeTokenWithdrawn\",\"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\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"}],\"name\":\"forwardFromRouter\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"messageValidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeAggregator\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getPoolBySourceToken\",\"outputs\":[{\"internalType\":\"contractIPoolV1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"nonceManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOnRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"getSupportedTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"messageValidator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"feeAggregator\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMMultiOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"setDynamicConfig\",\"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\":[],\"name\":\"withdrawFeeTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101006040523480156200001257600080fd5b5060405162003161380380620031618339810160408190526200003591620003db565b33806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf816200017a565b505082516001600160401b031615905080620000e6575060208201516001600160a01b0316155b80620000fd575060408201516001600160a01b0316155b8062000114575060608201516001600160a01b0316155b1562000133576040516306b7c75960e31b815260040160405180910390fd5b81516001600160401b031660805260208201516001600160a01b0390811660a0526040830151811660c05260608301511660e052620001728162000225565b5050620004d1565b336001600160a01b03821603620001d45760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60208101516001600160a01b031615806200024b575060608101516001600160a01b0316155b156200026a576040516306b7c75960e31b815260040160405180910390fd5b8051600280546001600160a01b03199081166001600160a01b0393841617909155602080840180516003805485169186169190911790556040808601805160048054871691881691909117905560608088018051600580549098169089161790965582516080808201855280516001600160401b031680835260a080518b16848a0190815260c080518d16868a0190815260e080518f169789019788528a5195865292518e169b85019b909b5299518c169783019790975292518a169381019390935289518916908301529351871693810193909352518516928201929092529151909216918101919091527f23a1adf8ad7fad6091a4803227af2cee848c01a7c812404cade7c25636925e32906101000160405180910390a150565b604051608081016001600160401b0381118282101715620003b857634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160a01b0381168114620003d657600080fd5b919050565b600080828403610100811215620003f157600080fd5b60808112156200040057600080fd5b6200040a62000387565b84516001600160401b03811681146200042257600080fd5b81526200043260208601620003be565b60208201526200044560408601620003be565b60408201526200045860608601620003be565b606082015292506080607f19820112156200047257600080fd5b506200047d62000387565b6200048b60808501620003be565b81526200049b60a08501620003be565b6020820152620004ae60c08501620003be565b6040820152620004c160e08501620003be565b6060820152809150509250929050565b60805160a05160c05160e051612c176200054a600039600081816101c00152818161081b015261147901526000818161018401528181610d3801526114520152600081816101480152818161044e015261142801526000818161011801528181610c55015281816110ee01526113fb0152612c176000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806379ba50971161008c578063a6f3ab6c11610066578063a6f3ab6c14610391578063df0aa9e9146103a4578063f2fde38b146103b7578063fbca3b74146103ca57600080fd5b806379ba50971461033f5780638da5cb5b146103475780639041be3d1461036557600080fd5b80633a019940116100bd5780633a0199401461027d57806348a98aa4146102875780637437ff9f146102bf57600080fd5b806306285c69146100e4578063181f5a771461021357806320487ded1461025c575b600080fd5b6101fd60408051608081018252600080825260208201819052918101829052606081019190915260405180608001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b60405161020a9190611cf8565b60405180910390f35b61024f6040518060400160405280601c81526020017f45564d3245564d4d756c74694f6e52616d7020312e362e302d6465760000000081525081565b60405161020a9190611dbd565b61026f61026a366004611dfe565b6103ea565b60405190815260200161020a565b6102856105a3565b005b61029a610295366004611e70565b6107d3565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161020a565b610332604080516080810182526000808252602082018190529181018290526060810191909152506040805160808101825260025473ffffffffffffffffffffffffffffffffffffffff908116825260035481166020830152600454811692820192909252600554909116606082015290565b60405161020a9190611ea9565b610285610888565b60005473ffffffffffffffffffffffffffffffffffffffff1661029a565b610378610373366004611ef2565b610985565b60405167ffffffffffffffff909116815260200161020a565b61028561039f366004611fc6565b6109ae565b61026f6103b236600461204b565b6109c2565b6102856103c53660046120b7565b6111a2565b6103dd6103d8366004611ef2565b6111b3565b60405161020a91906120d4565b6040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815277ffffffffffffffff00000000000000000000000000000000608084901b16600482015260009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690632cbc26bb90602401602060405180830381865afa158015610495573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b9919061213e565b15610501576040517ffdbd6a7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b6003546040517fd8694ccd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063d8694ccd90610559908690869060040161226d565b602060405180830381865afa158015610576573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059a91906123b6565b90505b92915050565b600354604080517fcdc73d51000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff169163cdc73d5191600480830192869291908290030181865afa158015610612573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261065891908101906123cf565b60055490915073ffffffffffffffffffffffffffffffffffffffff1660005b82518110156107ce57600083828151811061069457610694612481565b60209081029190910101516040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290915060009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa15801561070f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061073391906123b6565b905080156107c45761075c73ffffffffffffffffffffffffffffffffffffffff831685836111e7565b8173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f508d7d183612c18fc339b42618912b9fa3239f631dd7ec0671f950200a0fa66e836040516107bb91815260200190565b60405180910390a35b5050600101610677565b505050565b6040517fbbe4f6db00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063bbe4f6db90602401602060405180830381865afa158015610864573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061059a91906124b0565b60015473ffffffffffffffffffffffffffffffffffffffff163314610909576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016104f8565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b67ffffffffffffffff808216600090815260066020526040812054909161059d911660016124fc565b6109b6611274565b6109bf816112f7565b50565b600073ffffffffffffffffffffffffffffffffffffffff8216610a11576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025473ffffffffffffffffffffffffffffffffffffffff163314610a62576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045473ffffffffffffffffffffffffffffffffffffffff168015610b08576040517fe0a0e50600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063e0a0e50690610ad5908990899060040161226d565b600060405180830381600087803b158015610aef57600080fd5b505af1158015610b03573d6000803e3d6000fd5b505050505b6003546000908190819073ffffffffffffffffffffffffffffffffffffffff1663c4276bfc8a610b3e60808c0160608d016120b7565b8a610b4c60808e018e612524565b6040518663ffffffff1660e01b8152600401610b6c959493929190612589565b600060405180830381865afa158015610b89573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610bcf9190810190612651565b91945092509050610be66080890160608a016120b7565b73ffffffffffffffffffffffffffffffffffffffff167f075a2720282fdf622141dae0b048ef90a21a7e57c134c76912d19d006b3b3f6f84604051610c2d91815260200190565b60405180910390a2604080516101a0810182526000610100820181815267ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166101208501528d8116610140850181905283526006602052938220805492948493610160850192918791610caa91166126a8565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905567ffffffffffffffff16815260200186610daa576040517fea458c0c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8f16600482015273ffffffffffffffffffffffffffffffffffffffff8c811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063ea458c0c906044016020604051808303816000875af1158015610d81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da591906126cf565b610dad565b60005b67ffffffffffffffff1681525081526020018873ffffffffffffffffffffffffffffffffffffffff1681526020018a8060200190610deb9190612524565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001610e2f8b80612524565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001610e7660808c018c612524565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001610ec060808c0160608d016120b7565b73ffffffffffffffffffffffffffffffffffffffff1681526020018981526020018a8060400190610ef191906126ec565b905067ffffffffffffffff811115610f0b57610f0b611f0f565b604051908082528060200260200182016040528015610f6757816020015b610f546040518060800160405280606081526020016060815260200160608152602001600081525090565b815260200190600190039081610f295790505b509052905060005b610f7c60408b018b6126ec565b905081101561102b57611002610f9560408c018c6126ec565b83818110610fa557610fa5612481565b905060400201803603810190610fbb9190612754565b8c610fc68d80612524565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92506114dc915050565b8260e00151828151811061101857611018612481565b6020908102919091010152600101610f6f565b5060035460e082015173ffffffffffffffffffffffffffffffffffffffff9091169063cc88924c908c9061106260408e018e6126ec565b6040518563ffffffff1660e01b81526004016110819493929190612850565b60006040518083038186803b15801561109957600080fd5b505afa1580156110ad573d6000803e3d6000fd5b505050506080808201839052604080517f130ac867e79e2789f923760a88743d292acdf7002139a588206e2260f73f7321602082015267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811692820192909252908c166060820152309181019190915261114a90829060a001604051602081830303815290604052805190602001206117e6565b81515260405167ffffffffffffffff8b16907f0f07cd31e53232da9125e517f09550fdde74bf43d6a0a76ebd41674dafe2ab2990611189908490612886565b60405180910390a251519450505050505b949350505050565b6111aa611274565b6109bf816118e6565b60606040517f9e7177c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526107ce9084906119db565b60005473ffffffffffffffffffffffffffffffffffffffff1633146112f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016104f8565b565b602081015173ffffffffffffffffffffffffffffffffffffffff1615806113365750606081015173ffffffffffffffffffffffffffffffffffffffff16155b1561136d576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600280547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff93841617909155602080840151600380548416918516919091179055604080850151600480548516918616919091179055606080860151600580549095169086161790935580516080810182527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681527f00000000000000000000000000000000000000000000000000000000000000008516928101929092527f00000000000000000000000000000000000000000000000000000000000000008416828201527f00000000000000000000000000000000000000000000000000000000000000009093169181019190915290517f23a1adf8ad7fad6091a4803227af2cee848c01a7c812404cade7c25636925e32916114d19184906129d4565b60405180910390a150565b6115076040518060800160405280606081526020016060815260200160608152602001600081525090565b8460200151600003611545576040517f5cf0444900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006115558587600001516107d3565b905073ffffffffffffffffffffffffffffffffffffffff8116158061162557506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527faff2afbf00000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa1580156115ff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611623919061213e565b155b156116775785516040517fbf16aab600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016104f8565b60008173ffffffffffffffffffffffffffffffffffffffff16639a4575b96040518060a001604052808881526020018967ffffffffffffffff1681526020018773ffffffffffffffffffffffffffffffffffffffff1681526020018a6020015181526020018a6000015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b81526004016117169190612a73565b6000604051808303816000875af1158015611735573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261177b9190810190612ae9565b604080516080810190915273ffffffffffffffffffffffffffffffffffffffff841660a08201529091508060c0810160405160208183030381529060405281526020018260000151815260200182602001518152602001886020015181525092505050949350505050565b60008060001b82846020015185606001518660000151606001518760000151608001518860a001518960c0015160405160200161182896959493929190612b7a565b604051602081830303815290604052805190602001208560400151805190602001208660e0015160405160200161185f9190612bdb565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206080808c0151805190840120928501989098529183019590955260608201939093529384015260a083015260c082015260e00160405160208183030381529060405280519060200120905092915050565b3373ffffffffffffffffffffffffffffffffffffffff821603611965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016104f8565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611a3d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611ae79092919063ffffffff16565b8051909150156107ce5780806020019051810190611a5b919061213e565b6107ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016104f8565b6060611af68484600085611b00565b90505b9392505050565b606082471015611b92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016104f8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611bbb9190612bee565b60006040518083038185875af1925050503d8060008114611bf8576040519150601f19603f3d011682016040523d82523d6000602084013e611bfd565b606091505b5091509150611c0e87838387611c19565b979650505050505050565b60608315611caf578251600003611ca85773ffffffffffffffffffffffffffffffffffffffff85163b611ca8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104f8565b508161119a565b61119a8383815115611cc45781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f89190611dbd565b6080810161059d828467ffffffffffffffff8151168252602081015173ffffffffffffffffffffffffffffffffffffffff808216602085015280604084015116604085015280606084015116606085015250505050565b60005b83811015611d6a578181015183820152602001611d52565b50506000910152565b60008151808452611d8b816020860160208601611d4f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061059a6020830184611d73565b67ffffffffffffffff811681146109bf57600080fd5b600060a08284031215611df857600080fd5b50919050565b60008060408385031215611e1157600080fd5b8235611e1c81611dd0565b9150602083013567ffffffffffffffff811115611e3857600080fd5b611e4485828601611de6565b9150509250929050565b73ffffffffffffffffffffffffffffffffffffffff811681146109bf57600080fd5b60008060408385031215611e8357600080fd5b8235611e8e81611dd0565b91506020830135611e9e81611e4e565b809150509250929050565b6080810161059d8284805173ffffffffffffffffffffffffffffffffffffffff908116835260208083015182169084015260408083015182169084015260609182015116910152565b600060208284031215611f0457600080fd5b8135611af981611dd0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611f6157611f61611f0f565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611fae57611fae611f0f565b604052919050565b8035611fc181611e4e565b919050565b600060808284031215611fd857600080fd5b6040516080810181811067ffffffffffffffff82111715611ffb57611ffb611f0f565b604052823561200981611e4e565b8152602083013561201981611e4e565b6020820152604083013561202c81611e4e565b6040820152606083013561203f81611e4e565b60608201529392505050565b6000806000806080858703121561206157600080fd5b843561206c81611dd0565b9350602085013567ffffffffffffffff81111561208857600080fd5b61209487828801611de6565b9350506040850135915060608501356120ac81611e4e565b939692955090935050565b6000602082840312156120c957600080fd5b8135611af981611e4e565b6020808252825182820181905260009190848201906040850190845b8181101561212257835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016120f0565b50909695505050505050565b80518015158114611fc157600080fd5b60006020828403121561215057600080fd5b61059a8261212e565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261218e57600080fd5b830160208101925035905067ffffffffffffffff8111156121ae57600080fd5b8036038213156121bd57600080fd5b9250929050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b8183526000602080850194508260005b8581101561226257813561223081611e4e565b73ffffffffffffffffffffffffffffffffffffffff16875281830135838801526040968701969091019060010161221d565b509495945050505050565b600067ffffffffffffffff80851683526040602084015261228e8485612159565b60a060408601526122a360e0860182846121c4565b9150506122b36020860186612159565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0808785030160608801526122e98483856121c4565b9350604088013592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe188360301831261232257600080fd5b6020928801928301923591508482111561233b57600080fd5b8160061b360383131561234d57600080fd5b8087850301608088015261236284838561220d565b945061237060608901611fb6565b73ffffffffffffffffffffffffffffffffffffffff811660a0890152935061239b6080890189612159565b94509250808786030160c08801525050611c0e8383836121c4565b6000602082840312156123c857600080fd5b5051919050565b600060208083850312156123e257600080fd5b825167ffffffffffffffff808211156123fa57600080fd5b818501915085601f83011261240e57600080fd5b81518181111561242057612420611f0f565b8060051b9150612431848301611f67565b818152918301840191848101908884111561244b57600080fd5b938501935b83851015612475578451925061246583611e4e565b8282529385019390850190612450565b98975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156124c257600080fd5b8151611af981611e4e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff81811683821601908082111561251d5761251d6124cd565b5092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261255957600080fd5b83018035915067ffffffffffffffff82111561257457600080fd5b6020019150368190038213156121bd57600080fd5b67ffffffffffffffff8616815273ffffffffffffffffffffffffffffffffffffffff85166020820152836040820152608060608201526000611c0e6080830184866121c4565b600082601f8301126125e057600080fd5b815167ffffffffffffffff8111156125fa576125fa611f0f565b61262b60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611f67565b81815284602083860101111561264057600080fd5b61119a826020830160208701611d4f565b60008060006060848603121561266657600080fd5b835192506126766020850161212e565b9150604084015167ffffffffffffffff81111561269257600080fd5b61269e868287016125cf565b9150509250925092565b600067ffffffffffffffff8083168181036126c5576126c56124cd565b6001019392505050565b6000602082840312156126e157600080fd5b8151611af981611dd0565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261272157600080fd5b83018035915067ffffffffffffffff82111561273c57600080fd5b6020019150600681901b36038213156121bd57600080fd5b60006040828403121561276657600080fd5b61276e611f3e565b823561277981611e4e565b81526020928301359281019290925250919050565b600082825180855260208086019550808260051b84010181860160005b84811015612843577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08684030189528151608081518186526127ef82870182611d73565b91505085820151858203878701526128078282611d73565b915050604080830151868303828801526128218382611d73565b60609485015197909401969096525050988401989250908301906001016127ab565b5090979650505050505050565b67ffffffffffffffff85168152606060208201526000612873606083018661278e565b8281036040840152611c0e81858761220d565b602081526128d760208201835180518252602081015167ffffffffffffffff808216602085015280604084015116604085015280606084015116606085015280608084015116608085015250505050565b6000602083015161290060c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060408301516101808060e085015261291d6101a0850183611d73565b915060608501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808685030161010087015261295a8483611d73565b93506080870151915080868503016101208701526129788483611d73565b935060a087015191506129a461014087018373ffffffffffffffffffffffffffffffffffffffff169052565b60c087015161016087015260e08701519150808685030183870152506129ca838261278e565b9695505050505050565b6101008101612a2c828567ffffffffffffffff8151168252602081015173ffffffffffffffffffffffffffffffffffffffff808216602085015280604084015116604085015280606084015116606085015250505050565b825173ffffffffffffffffffffffffffffffffffffffff90811660808401526020840151811660a08401526040840151811660c084015260608401511660e0830152611af9565b602081526000825160a06020840152612a8f60c0840182611d73565b905067ffffffffffffffff6020850151166040840152604084015173ffffffffffffffffffffffffffffffffffffffff8082166060860152606086015160808601528060808701511660a086015250508091505092915050565b600060208284031215612afb57600080fd5b815167ffffffffffffffff80821115612b1357600080fd5b9083019060408286031215612b2757600080fd5b612b2f611f3e565b825182811115612b3e57600080fd5b612b4a878286016125cf565b825250602083015182811115612b5f57600080fd5b612b6b878286016125cf565b60208301525095945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808916835260c06020840152612baa60c0840189611d73565b67ffffffffffffffff97881660408501529590961660608301525091909316608082015260a0019190915292915050565b60208152600061059a602083018461278e565b60008251612c00818460208701611d4f565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var EVM2EVMMultiOnRampABI = EVM2EVMMultiOnRampMetaData.ABI
+
+var EVM2EVMMultiOnRampBin = EVM2EVMMultiOnRampMetaData.Bin
+
+func DeployEVM2EVMMultiOnRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMMultiOnRampStaticConfig, dynamicConfig EVM2EVMMultiOnRampDynamicConfig) (common.Address, *types.Transaction, *EVM2EVMMultiOnRamp, error) {
+ parsed, err := EVM2EVMMultiOnRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMMultiOnRampBin), backend, staticConfig, dynamicConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMMultiOnRamp{address: address, abi: *parsed, EVM2EVMMultiOnRampCaller: EVM2EVMMultiOnRampCaller{contract: contract}, EVM2EVMMultiOnRampTransactor: EVM2EVMMultiOnRampTransactor{contract: contract}, EVM2EVMMultiOnRampFilterer: EVM2EVMMultiOnRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMMultiOnRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMMultiOnRampCaller
+ EVM2EVMMultiOnRampTransactor
+ EVM2EVMMultiOnRampFilterer
+}
+
+type EVM2EVMMultiOnRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMMultiOnRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMMultiOnRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMMultiOnRampSession struct {
+ Contract *EVM2EVMMultiOnRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMMultiOnRampCallerSession struct {
+ Contract *EVM2EVMMultiOnRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMMultiOnRampTransactorSession struct {
+ Contract *EVM2EVMMultiOnRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMMultiOnRampRaw struct {
+ Contract *EVM2EVMMultiOnRamp
+}
+
+type EVM2EVMMultiOnRampCallerRaw struct {
+ Contract *EVM2EVMMultiOnRampCaller
+}
+
+type EVM2EVMMultiOnRampTransactorRaw struct {
+ Contract *EVM2EVMMultiOnRampTransactor
+}
+
+func NewEVM2EVMMultiOnRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMMultiOnRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMMultiOnRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMMultiOnRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRamp{address: address, abi: abi, EVM2EVMMultiOnRampCaller: EVM2EVMMultiOnRampCaller{contract: contract}, EVM2EVMMultiOnRampTransactor: EVM2EVMMultiOnRampTransactor{contract: contract}, EVM2EVMMultiOnRampFilterer: EVM2EVMMultiOnRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMMultiOnRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMMultiOnRampCaller, error) {
+ contract, err := bindEVM2EVMMultiOnRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMMultiOnRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMMultiOnRampTransactor, error) {
+ contract, err := bindEVM2EVMMultiOnRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMMultiOnRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMMultiOnRampFilterer, error) {
+ contract, err := bindEVM2EVMMultiOnRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMMultiOnRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMMultiOnRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMMultiOnRamp.Contract.EVM2EVMMultiOnRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.EVM2EVMMultiOnRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.EVM2EVMMultiOnRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMMultiOnRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMMultiOnRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOnRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMMultiOnRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMMultiOnRampDynamicConfig)).(*EVM2EVMMultiOnRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) GetDynamicConfig() (EVM2EVMMultiOnRampDynamicConfig, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetDynamicConfig(&_EVM2EVMMultiOnRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerSession) GetDynamicConfig() (EVM2EVMMultiOnRampDynamicConfig, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetDynamicConfig(&_EVM2EVMMultiOnRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts, destChainSelector uint64) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOnRamp.contract.Call(opts, &out, "getExpectedNextSequenceNumber", destChainSelector)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) GetExpectedNextSequenceNumber(destChainSelector uint64) (uint64, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMMultiOnRamp.CallOpts, destChainSelector)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerSession) GetExpectedNextSequenceNumber(destChainSelector uint64) (uint64, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMMultiOnRamp.CallOpts, destChainSelector)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCaller) GetFee(opts *bind.CallOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOnRamp.contract.Call(opts, &out, "getFee", destChainSelector, message)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) GetFee(destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetFee(&_EVM2EVMMultiOnRamp.CallOpts, destChainSelector, message)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerSession) GetFee(destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetFee(&_EVM2EVMMultiOnRamp.CallOpts, destChainSelector, message)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCaller) GetPoolBySourceToken(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOnRamp.contract.Call(opts, &out, "getPoolBySourceToken", arg0, sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) GetPoolBySourceToken(arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMMultiOnRamp.CallOpts, arg0, sourceToken)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerSession) GetPoolBySourceToken(arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMMultiOnRamp.CallOpts, arg0, sourceToken)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMMultiOnRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOnRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMMultiOnRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMMultiOnRampStaticConfig)).(*EVM2EVMMultiOnRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) GetStaticConfig() (EVM2EVMMultiOnRampStaticConfig, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetStaticConfig(&_EVM2EVMMultiOnRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerSession) GetStaticConfig() (EVM2EVMMultiOnRampStaticConfig, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetStaticConfig(&_EVM2EVMMultiOnRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCaller) GetSupportedTokens(opts *bind.CallOpts, arg0 uint64) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOnRamp.contract.Call(opts, &out, "getSupportedTokens", arg0)
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) GetSupportedTokens(arg0 uint64) ([]common.Address, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetSupportedTokens(&_EVM2EVMMultiOnRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerSession) GetSupportedTokens(arg0 uint64) ([]common.Address, error) {
+ return _EVM2EVMMultiOnRamp.Contract.GetSupportedTokens(&_EVM2EVMMultiOnRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOnRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMMultiOnRamp.Contract.Owner(&_EVM2EVMMultiOnRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMMultiOnRamp.Contract.Owner(&_EVM2EVMMultiOnRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMMultiOnRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMMultiOnRamp.Contract.TypeAndVersion(&_EVM2EVMMultiOnRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMMultiOnRamp.Contract.TypeAndVersion(&_EVM2EVMMultiOnRamp.CallOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.AcceptOwnership(&_EVM2EVMMultiOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.AcceptOwnership(&_EVM2EVMMultiOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactor) ForwardFromRouter(opts *bind.TransactOpts, destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.contract.Transact(opts, "forwardFromRouter", destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) ForwardFromRouter(destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.ForwardFromRouter(&_EVM2EVMMultiOnRamp.TransactOpts, destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactorSession) ForwardFromRouter(destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.ForwardFromRouter(&_EVM2EVMMultiOnRamp.TransactOpts, destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactor) SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMMultiOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.contract.Transact(opts, "setDynamicConfig", dynamicConfig)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) SetDynamicConfig(dynamicConfig EVM2EVMMultiOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.SetDynamicConfig(&_EVM2EVMMultiOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactorSession) SetDynamicConfig(dynamicConfig EVM2EVMMultiOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.SetDynamicConfig(&_EVM2EVMMultiOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.TransferOwnership(&_EVM2EVMMultiOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.TransferOwnership(&_EVM2EVMMultiOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactor) WithdrawFeeTokens(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.contract.Transact(opts, "withdrawFeeTokens")
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampSession) WithdrawFeeTokens() (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.WithdrawFeeTokens(&_EVM2EVMMultiOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampTransactorSession) WithdrawFeeTokens() (*types.Transaction, error) {
+ return _EVM2EVMMultiOnRamp.Contract.WithdrawFeeTokens(&_EVM2EVMMultiOnRamp.TransactOpts)
+}
+
+type EVM2EVMMultiOnRampAdminSetIterator struct {
+ Event *EVM2EVMMultiOnRampAdminSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOnRampAdminSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOnRampAdminSet)
+ 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(EVM2EVMMultiOnRampAdminSet)
+ 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 *EVM2EVMMultiOnRampAdminSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOnRampAdminSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOnRampAdminSet struct {
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMMultiOnRampAdminSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.FilterLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampAdminSetIterator{contract: _EVM2EVMMultiOnRamp.contract, event: "AdminSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampAdminSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.WatchLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOnRampAdminSet)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "AdminSet", 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 (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) ParseAdminSet(log types.Log) (*EVM2EVMMultiOnRampAdminSet, error) {
+ event := new(EVM2EVMMultiOnRampAdminSet)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "AdminSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOnRampCCIPSendRequestedIterator struct {
+ Event *EVM2EVMMultiOnRampCCIPSendRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOnRampCCIPSendRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOnRampCCIPSendRequested)
+ 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(EVM2EVMMultiOnRampCCIPSendRequested)
+ 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 *EVM2EVMMultiOnRampCCIPSendRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOnRampCCIPSendRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOnRampCCIPSendRequested struct {
+ DestChainSelector uint64
+ Message InternalEVM2AnyRampMessage
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) FilterCCIPSendRequested(opts *bind.FilterOpts, destChainSelector []uint64) (*EVM2EVMMultiOnRampCCIPSendRequestedIterator, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.FilterLogs(opts, "CCIPSendRequested", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampCCIPSendRequestedIterator{contract: _EVM2EVMMultiOnRamp.contract, event: "CCIPSendRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampCCIPSendRequested, destChainSelector []uint64) (event.Subscription, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.WatchLogs(opts, "CCIPSendRequested", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOnRampCCIPSendRequested)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "CCIPSendRequested", 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 (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) ParseCCIPSendRequested(log types.Log) (*EVM2EVMMultiOnRampCCIPSendRequested, error) {
+ event := new(EVM2EVMMultiOnRampCCIPSendRequested)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "CCIPSendRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOnRampConfigSetIterator struct {
+ Event *EVM2EVMMultiOnRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOnRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOnRampConfigSet)
+ 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(EVM2EVMMultiOnRampConfigSet)
+ 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 *EVM2EVMMultiOnRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOnRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOnRampConfigSet struct {
+ StaticConfig EVM2EVMMultiOnRampStaticConfig
+ DynamicConfig EVM2EVMMultiOnRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMMultiOnRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampConfigSetIterator{contract: _EVM2EVMMultiOnRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOnRampConfigSet)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMMultiOnRampConfigSet, error) {
+ event := new(EVM2EVMMultiOnRampConfigSet)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOnRampFeePaidIterator struct {
+ Event *EVM2EVMMultiOnRampFeePaid
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOnRampFeePaidIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOnRampFeePaid)
+ 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(EVM2EVMMultiOnRampFeePaid)
+ 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 *EVM2EVMMultiOnRampFeePaidIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOnRampFeePaidIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOnRampFeePaid struct {
+ FeeToken common.Address
+ FeeValueJuels *big.Int
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) FilterFeePaid(opts *bind.FilterOpts, feeToken []common.Address) (*EVM2EVMMultiOnRampFeePaidIterator, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.FilterLogs(opts, "FeePaid", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampFeePaidIterator{contract: _EVM2EVMMultiOnRamp.contract, event: "FeePaid", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) WatchFeePaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampFeePaid, feeToken []common.Address) (event.Subscription, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.WatchLogs(opts, "FeePaid", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOnRampFeePaid)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "FeePaid", 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 (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) ParseFeePaid(log types.Log) (*EVM2EVMMultiOnRampFeePaid, error) {
+ event := new(EVM2EVMMultiOnRampFeePaid)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "FeePaid", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOnRampFeeTokenWithdrawnIterator struct {
+ Event *EVM2EVMMultiOnRampFeeTokenWithdrawn
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOnRampFeeTokenWithdrawnIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOnRampFeeTokenWithdrawn)
+ 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(EVM2EVMMultiOnRampFeeTokenWithdrawn)
+ 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 *EVM2EVMMultiOnRampFeeTokenWithdrawnIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOnRampFeeTokenWithdrawnIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOnRampFeeTokenWithdrawn struct {
+ FeeAggregator common.Address
+ FeeToken common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) FilterFeeTokenWithdrawn(opts *bind.FilterOpts, feeAggregator []common.Address, feeToken []common.Address) (*EVM2EVMMultiOnRampFeeTokenWithdrawnIterator, error) {
+
+ var feeAggregatorRule []interface{}
+ for _, feeAggregatorItem := range feeAggregator {
+ feeAggregatorRule = append(feeAggregatorRule, feeAggregatorItem)
+ }
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.FilterLogs(opts, "FeeTokenWithdrawn", feeAggregatorRule, feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampFeeTokenWithdrawnIterator{contract: _EVM2EVMMultiOnRamp.contract, event: "FeeTokenWithdrawn", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) WatchFeeTokenWithdrawn(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampFeeTokenWithdrawn, feeAggregator []common.Address, feeToken []common.Address) (event.Subscription, error) {
+
+ var feeAggregatorRule []interface{}
+ for _, feeAggregatorItem := range feeAggregator {
+ feeAggregatorRule = append(feeAggregatorRule, feeAggregatorItem)
+ }
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.WatchLogs(opts, "FeeTokenWithdrawn", feeAggregatorRule, feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOnRampFeeTokenWithdrawn)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "FeeTokenWithdrawn", 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 (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) ParseFeeTokenWithdrawn(log types.Log) (*EVM2EVMMultiOnRampFeeTokenWithdrawn, error) {
+ event := new(EVM2EVMMultiOnRampFeeTokenWithdrawn)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "FeeTokenWithdrawn", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOnRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMMultiOnRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOnRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOnRampOwnershipTransferRequested)
+ 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(EVM2EVMMultiOnRampOwnershipTransferRequested)
+ 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 *EVM2EVMMultiOnRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOnRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOnRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMMultiOnRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampOwnershipTransferRequestedIterator{contract: _EVM2EVMMultiOnRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMMultiOnRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMMultiOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMMultiOnRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMMultiOnRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMMultiOnRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMMultiOnRampOwnershipTransferred)
+ 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(EVM2EVMMultiOnRampOwnershipTransferred)
+ 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 *EVM2EVMMultiOnRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMMultiOnRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMMultiOnRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMMultiOnRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMMultiOnRampOwnershipTransferredIterator{contract: _EVM2EVMMultiOnRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMMultiOnRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMMultiOnRampOwnershipTransferred)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMMultiOnRampOwnershipTransferred, error) {
+ event := new(EVM2EVMMultiOnRampOwnershipTransferred)
+ if err := _EVM2EVMMultiOnRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMMultiOnRamp.abi.Events["AdminSet"].ID:
+ return _EVM2EVMMultiOnRamp.ParseAdminSet(log)
+ case _EVM2EVMMultiOnRamp.abi.Events["CCIPSendRequested"].ID:
+ return _EVM2EVMMultiOnRamp.ParseCCIPSendRequested(log)
+ case _EVM2EVMMultiOnRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMMultiOnRamp.ParseConfigSet(log)
+ case _EVM2EVMMultiOnRamp.abi.Events["FeePaid"].ID:
+ return _EVM2EVMMultiOnRamp.ParseFeePaid(log)
+ case _EVM2EVMMultiOnRamp.abi.Events["FeeTokenWithdrawn"].ID:
+ return _EVM2EVMMultiOnRamp.ParseFeeTokenWithdrawn(log)
+ case _EVM2EVMMultiOnRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMMultiOnRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMMultiOnRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMMultiOnRamp.ParseOwnershipTransferred(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMMultiOnRampAdminSet) Topic() common.Hash {
+ return common.HexToHash("0x8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c")
+}
+
+func (EVM2EVMMultiOnRampCCIPSendRequested) Topic() common.Hash {
+ return common.HexToHash("0x0f07cd31e53232da9125e517f09550fdde74bf43d6a0a76ebd41674dafe2ab29")
+}
+
+func (EVM2EVMMultiOnRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x23a1adf8ad7fad6091a4803227af2cee848c01a7c812404cade7c25636925e32")
+}
+
+func (EVM2EVMMultiOnRampFeePaid) Topic() common.Hash {
+ return common.HexToHash("0x075a2720282fdf622141dae0b048ef90a21a7e57c134c76912d19d006b3b3f6f")
+}
+
+func (EVM2EVMMultiOnRampFeeTokenWithdrawn) Topic() common.Hash {
+ return common.HexToHash("0x508d7d183612c18fc339b42618912b9fa3239f631dd7ec0671f950200a0fa66e")
+}
+
+func (EVM2EVMMultiOnRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMMultiOnRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (_EVM2EVMMultiOnRamp *EVM2EVMMultiOnRamp) Address() common.Address {
+ return _EVM2EVMMultiOnRamp.address
+}
+
+type EVM2EVMMultiOnRampInterface interface {
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMMultiOnRampDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts, destChainSelector uint64) (uint64, error)
+
+ GetFee(opts *bind.CallOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error)
+
+ GetPoolBySourceToken(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address) (common.Address, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMMultiOnRampStaticConfig, error)
+
+ GetSupportedTokens(opts *bind.CallOpts, arg0 uint64) ([]common.Address, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ForwardFromRouter(opts *bind.TransactOpts, destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error)
+
+ SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMMultiOnRampDynamicConfig) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ WithdrawFeeTokens(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMMultiOnRampAdminSetIterator, error)
+
+ WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampAdminSet) (event.Subscription, error)
+
+ ParseAdminSet(log types.Log) (*EVM2EVMMultiOnRampAdminSet, error)
+
+ FilterCCIPSendRequested(opts *bind.FilterOpts, destChainSelector []uint64) (*EVM2EVMMultiOnRampCCIPSendRequestedIterator, error)
+
+ WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampCCIPSendRequested, destChainSelector []uint64) (event.Subscription, error)
+
+ ParseCCIPSendRequested(log types.Log) (*EVM2EVMMultiOnRampCCIPSendRequested, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMMultiOnRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMMultiOnRampConfigSet, error)
+
+ FilterFeePaid(opts *bind.FilterOpts, feeToken []common.Address) (*EVM2EVMMultiOnRampFeePaidIterator, error)
+
+ WatchFeePaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampFeePaid, feeToken []common.Address) (event.Subscription, error)
+
+ ParseFeePaid(log types.Log) (*EVM2EVMMultiOnRampFeePaid, error)
+
+ FilterFeeTokenWithdrawn(opts *bind.FilterOpts, feeAggregator []common.Address, feeToken []common.Address) (*EVM2EVMMultiOnRampFeeTokenWithdrawnIterator, error)
+
+ WatchFeeTokenWithdrawn(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampFeeTokenWithdrawn, feeAggregator []common.Address, feeToken []common.Address) (event.Subscription, error)
+
+ ParseFeeTokenWithdrawn(log types.Log) (*EVM2EVMMultiOnRampFeeTokenWithdrawn, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMMultiOnRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMMultiOnRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMMultiOnRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMMultiOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMMultiOnRampOwnershipTransferred, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_offramp/evm_2_evm_offramp.go b/core/gethwrappers/ccip/generated/evm_2_evm_offramp/evm_2_evm_offramp.go
new file mode 100644
index 00000000000..e4f47eb0a59
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_offramp/evm_2_evm_offramp.go
@@ -0,0 +1,2673 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_offramp
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMOffRampDynamicConfig struct {
+ PermissionLessExecutionThresholdSeconds uint32
+ MaxDataBytes uint32
+ MaxNumberOfTokensPerMsg uint16
+ Router common.Address
+ PriceRegistry common.Address
+ MaxPoolReleaseOrMintGas uint32
+ MaxTokenTransferGas uint32
+}
+
+type EVM2EVMOffRampRateLimitToken struct {
+ SourceToken common.Address
+ DestToken common.Address
+}
+
+type EVM2EVMOffRampStaticConfig struct {
+ CommitStore common.Address
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ PrevOffRamp common.Address
+ RmnProxy common.Address
+ TokenAdminRegistry common.Address
+}
+
+type InternalEVM2EVMMessage struct {
+ SourceChainSelector uint64
+ Sender common.Address
+ Receiver common.Address
+ SequenceNumber uint64
+ GasLimit *big.Int
+ Strict bool
+ Nonce uint64
+ FeeToken common.Address
+ FeeTokenAmount *big.Int
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ SourceTokenData [][]byte
+ MessageId [32]byte
+}
+
+type InternalExecutionReport struct {
+ Messages []InternalEVM2EVMMessage
+ OffchainTokenData [][][]byte
+ Proofs [][32]byte
+ ProofFlagBits *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+var EVM2EVMOffRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"AlreadyAttempted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"AlreadyExecuted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CanOnlySelfCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitStoreAlreadyInUse\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyReport\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"ExecutionError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enumOCR2BaseNoChecks.InvalidConfigErrorType\",\"name\":\"errorType\",\"type\":\"uint8\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"}],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidEVMAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newLimit\",\"type\":\"uint256\"}],\"name\":\"InvalidManualExecutionGasLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMessageId\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"newState\",\"type\":\"uint8\"}],\"name\":\"InvalidNewState\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidSourceChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ManualExecutionGasLimitMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ManualExecutionNotYetEnabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"notPool\",\"type\":\"address\"}],\"name\":\"NotACompatiblePool\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PriceNotFoundForToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"ReceiverError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootNotCommitted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"TokenDataMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"TokenHandlingError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnexpectedTokenData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxPoolReleaseOrMintGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferGas\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOffRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"state\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"name\":\"ExecutionStateChanged\",\"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\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"SkippedAlreadyExecutedMessage\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SkippedIncorrectNonce\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SkippedSenderWithPreviousRampMessageInflight\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"}],\"name\":\"TokenAggregateRateLimitAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"}],\"name\":\"TokenAggregateRateLimitRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"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\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ccipReceive\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[]\",\"name\":\"sourceTokenData\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"internalType\":\"structInternal.EVM2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[]\"}],\"name\":\"executeSingleMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllRateLimitTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"sourceTokens\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"destTokens\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxPoolReleaseOrMintGas\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferGas\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOffRamp.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"getExecutionState\",\"outputs\":[{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getSenderNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"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\":[{\"components\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[]\",\"name\":\"sourceTokenData\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"internalType\":\"structInternal.EVM2EVMMessage[]\",\"name\":\"messages\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[][]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[][]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.ExecutionReport\",\"name\":\"report\",\"type\":\"tuple\"},{\"internalType\":\"uint256[]\",\"name\":\"gasLimitOverrides\",\"type\":\"uint256[]\"}],\"name\":\"manuallyExecute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setRateLimiterConfig\",\"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\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOffRamp.RateLimitToken[]\",\"name\":\"removes\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOffRamp.RateLimitToken[]\",\"name\":\"adds\",\"type\":\"tuple[]\"}],\"name\":\"updateRateLimitTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101a06040523480156200001257600080fd5b5060405162006213380380620062138339810160408190526200003591620004ec565b8033806000816200008d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c057620000c081620002ca565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606080870182905298909601519091166080948501819052600380546001600160a01b031916909217600160801b9485021760ff60a01b1916600160a01b90930292909217905502909117600455469052508201516001600160a01b031615806200016f575081516001600160a01b0316155b8062000186575060c08201516001600160a01b0316155b15620001a5576040516342bcdf7f60e11b815260040160405180910390fd5b81600001516001600160a01b0316634120fccd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001e8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020e9190620005b5565b6001600160401b03166001146200023857604051636fc2a20760e11b815260040160405180910390fd5b81516001600160a01b0390811660a090815260408401516001600160401b0390811660c0908152602086015190911660e05260608501518316610100526080850151831661014052908401518216610160528301511661018052620002bd7f8acd72527118c8324937b1a42e02cd246697c3b633f1742f3cae11de233722b362000375565b6101205250620005da9050565b336001600160a01b03821603620003245760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000084565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008160c05160e05161010051604051602001620003bf94939291909384526001600160401b039283166020850152911660408301526001600160a01b0316606082015260800190565b604051602081830303815290604052805190602001209050919050565b60405160e081016001600160401b03811182821017156200040d57634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160a01b03811681146200042b57600080fd5b919050565b80516001600160401b03811681146200042b57600080fd5b80516001600160801b03811681146200042b57600080fd5b6000606082840312156200047357600080fd5b604051606081016001600160401b0381118282101715620004a457634e487b7160e01b600052604160045260246000fd5b806040525080915082518015158114620004bd57600080fd5b8152620004cd6020840162000448565b6020820152620004e06040840162000448565b60408201525092915050565b6000808284036101408112156200050257600080fd5b60e08112156200051157600080fd5b506200051c620003dc565b620005278462000413565b8152620005376020850162000430565b60208201526200054a6040850162000430565b60408201526200055d6060850162000413565b6060820152620005706080850162000413565b60808201526200058360a0850162000413565b60a08201526200059660c0850162000413565b60c08201529150620005ac8460e0850162000460565b90509250929050565b600060208284031215620005c857600080fd5b620005d38262000430565b9392505050565b60805160a05160c05160e0516101005161012051610140516101605161018051615b4a620006c9600039600081816102ec01528181611b1201526133890152600081816102bd01528181611aeb0152611d9d01526000818161028e01528181610ed201528181610f3701528181611ac40152818161234501526123af01526000611f3c01526000818161025f0152611a9a0152600081816101ff0152611a4801526000818161022f01528181611a7201528181611d5a01528181612dc101526134980152600081816101d001528181611a1a015261201c015260008181611cb40152611d000152615b4a6000f3fe608060405234801561001057600080fd5b50600436106101825760003560e01c806381ff7048116100d8578063afcb95d71161008c578063f077b59211610066578063f077b59214610646578063f2fde38b1461065c578063f52121a51461066f57600080fd5b8063afcb95d714610600578063b1dc65a414610620578063c92b28321461063357600080fd5b8063856c8247116100bd578063856c8247146105b0578063873504d7146105dc5780638da5cb5b146105ef57600080fd5b806381ff70481461057257806385572ffb146105a257600080fd5b8063599f64311161013a578063740f415011610114578063740f4150146104615780637437ff9f1461047457806379ba50971461056a57600080fd5b8063599f643114610414578063666cab8d14610439578063704b6c021461044e57600080fd5b8063181f5a771161016b578063181f5a77146103525780631ef381741461039b578063546719cd146103b057600080fd5b806306285c6914610187578063142a98fc14610332575b600080fd5b61031c6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b60405161032991906141e7565b60405180910390f35b61034561034036600461427d565b610682565b60405161032991906142dd565b61038e6040518060400160405280601881526020017f45564d3245564d4f666652616d7020312e352e302d646576000000000000000081525081565b604051610329919061433b565b6103ae6103a93660046145aa565b6106fd565b005b6103b8610af1565b604051610329919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6002546001600160a01b03165b6040516001600160a01b039091168152602001610329565b610441610ba6565b60405161032991906146bc565b6103ae61045c3660046146cf565b610c08565b6103ae61046f366004614b2f565b610cd1565b61055d6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152506040805160e081018252600a5463ffffffff808216835264010000000082048116602084015261ffff68010000000000000000830416938301939093526001600160a01b036a010000000000000000000090910481166060830152600b549081166080830152740100000000000000000000000000000000000000008104831660a08301527801000000000000000000000000000000000000000000000000900490911660c082015290565b6040516103299190614bea565b6103ae610dc3565b6007546005546040805163ffffffff80851682526401000000009094049093166020840152820152606001610329565b6103ae610182366004614c58565b6105c36105be3660046146cf565b610ea6565b60405167ffffffffffffffff9091168152602001610329565b6103ae6105ea366004614d24565b610fa9565b6000546001600160a01b0316610421565b604080516001815260006020820181905291810191909152606001610329565b6103ae61062e366004614dcd565b611177565b6103ae610641366004614ed2565b611382565b61064e6113ed565b604051610329929190614f22565b6103ae61066a3660046146cf565b611513565b6103ae61067d366004614f47565b611524565b600061069060016004614fd0565b600261069d608085615012565b67ffffffffffffffff166106b19190615039565b601060006106c0608087615050565b67ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002054901c1660038111156106f7576106f761429a565b92915050565b84518460ff16601f82111561074a5760016040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016107419190615077565b60405180910390fd5b806000036107875760006040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016107419190615077565b61078f6117c4565b6107988561183a565b60095460005b8181101561080f5760086000600983815481106107bd576107bd615091565b60009182526020808320909101546001600160a01b03168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560010161079e565b5050865160005b818110156109b257600089828151811061083257610832615091565b602002602001015190506000600281111561084f5761084f61429a565b6001600160a01b038216600090815260086020526040902054610100900460ff1660028111156108815761088161429a565b146108bb5760026040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016107419190615077565b6001600160a01b0381166108fb576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff8316815260208101600290526001600160a01b03821660009081526008602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561099e5761099e61429a565b021790555090505050806001019050610816565b5087516109c69060099060208b0190614155565b506006805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908a161717905560078054610a4c914691309190600090610a1e9063ffffffff166150c0565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168c8c8c8c8c8c611b72565b6005819055600780544363ffffffff9081166401000000009081027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff841681179094556040519083048216947f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0594610add9487949293918316921691909117908f908f908f908f908f908f906150e3565b60405180910390a150505050505050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff161515938301939093526004548084166060840152049091166080820152610ba190611bff565b905090565b60606009805480602002602001604051908101604052809291908181526020018280548015610bfe57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610be0575b5050505050905090565b6000546001600160a01b03163314801590610c2e57506002546001600160a01b03163314155b15610c65576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c9060200160405180910390a150565b610cd9611cb1565b81515181518114610d16576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610db3576000838281518110610d3557610d35615091565b6020026020010151905080600014610daa578451805183908110610d5b57610d5b615091565b602002602001015160800151811015610daa576040517f085e39cf0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401610741565b50600101610d19565b50610dbe8383611d32565b505050565b6001546001600160a01b03163314610e37576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610741565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b0381166000908152600f602052604081205467ffffffffffffffff168082036106f7577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316156106f7576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015610f7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa29190615179565b9392505050565b610fb16117c4565b60005b825181101561108457610fee838281518110610fd257610fd2615091565b602002602001015160200151600c6127b590919063ffffffff16565b1561107c577fcbf3cbeaed4ac1d605ed30f4af06c35acaeff2379db7f6146c9cceee83d5878283828151811061102657611026615091565b60200260200101516000015184838151811061104457611044615091565b6020026020010151602001516040516110739291906001600160a01b0392831681529116602082015260400190565b60405180910390a15b600101610fb4565b5060005b8151811015610dbe576110e18282815181106110a6576110a6615091565b6020026020010151602001518383815181106110c4576110c4615091565b602002602001015160000151600c6127ca9092919063ffffffff16565b1561116f577ffc23abf7ddbd3c02b1420dafa2355c56c1a06fbb8723862ac14d6bd74177361a82828151811061111957611119615091565b60200260200101516000015183838151811061113757611137615091565b6020026020010151602001516040516111669291906001600160a01b0392831681529116602082015260400190565b60405180910390a15b600101611088565b61118187876127e8565b6005548835908082146111ca576040517f93df584c0000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610741565b6111d2611cb1565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a13360009081526008602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561125a5761125a61429a565b600281111561126b5761126b61429a565b90525090506002816020015160028111156112885761128861429a565b1480156112c257506009816000015160ff16815481106112aa576112aa615091565b6000918252602090912001546001600160a01b031633145b6112f8576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000611306856020615039565b611311886020615039565b61131d8b610144615196565b6113279190615196565b6113319190615196565b9050368114611375576040517f8e1192e100000000000000000000000000000000000000000000000000000000815260048101829052366024820152604401610741565b5050505050505050505050565b6000546001600160a01b031633148015906113a857506002546001600160a01b03163314155b156113df576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113ea60038261280f565b50565b60608060006113fc600c6129f4565b90508067ffffffffffffffff8111156114175761141761434e565b604051908082528060200260200182016040528015611440578160200160208202803683370190505b5092508067ffffffffffffffff81111561145c5761145c61434e565b604051908082528060200260200182016040528015611485578160200160208202803683370190505b50915060005b8181101561150d576000806114a1600c846129ff565b91509150808684815181106114b8576114b8615091565b60200260200101906001600160a01b031690816001600160a01b031681525050818584815181106114eb576114eb615091565b6001600160a01b0390921660209283029190910190910152505060010161148b565b50509091565b61151b6117c4565b6113ea81612a1d565b33301461155d576040517f371a732800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516000808252602082019092528161159a565b60408051808201909152600080825260208201528152602001906001900390816115735790505b5061014084015151909150156115fa576115f783610140015184602001516040516020016115d791906001600160a01b0391909116815260200190565b604051602081830303815290604052856040015186610160015186612af8565b90505b6101208301515115801561161057506080830151155b80611627575060408301516001600160a01b03163b155b8061166757506040830151611665906001600160a01b03167f85572ffb00000000000000000000000000000000000000000000000000000000612c29565b155b1561167157505050565b600080600a600001600a9054906101000a90046001600160a01b03166001600160a01b0316633cf979836040518060a001604052808861018001518152602001886000015167ffffffffffffffff16815260200188602001516040516020016116e991906001600160a01b0391909116815260200190565b6040516020818303038152906040528152602001886101200151815260200186815250611388886080015189604001516040518563ffffffff1660e01b815260040161173894939291906151ee565b6000604051808303816000875af1158015611757573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261177f91908101906152f8565b5091509150816117bd57806040517f0a8d6e8c000000000000000000000000000000000000000000000000000000008152600401610741919061433b565b5050505050565b6000546001600160a01b03163314611838576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610741565b565b6000818060200190518101906118509190615371565b60608101519091506001600160a01b0316611897576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600a80546020808501516040808701516060808901516001600160a01b039081166a0100000000000000000000027fffff0000000000000000000000000000000000000000ffffffffffffffffffff61ffff9094166801000000000000000002939093167fffff00000000000000000000000000000000000000000000ffffffffffffffff63ffffffff968716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169a87169a909a1797909717989098169590951717909455608080870151600b805460a0808b015160c0808d015188167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9290981674010000000000000000000000000000000000000000027fffffffffffffffff000000000000000000000000000000000000000000000000909416958c16959095179290921791909116949094179055855160e0810187527f00000000000000000000000000000000000000000000000000000000000000008816815267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116958201959095527f0000000000000000000000000000000000000000000000000000000000000000909416848701527f00000000000000000000000000000000000000000000000000000000000000008716948401949094527f00000000000000000000000000000000000000000000000000000000000000008616908301527f00000000000000000000000000000000000000000000000000000000000000008516908201527f000000000000000000000000000000000000000000000000000000000000000090931690830152517ff02fcc22535d64d92d17b995475893d63edd51da163fed74a6ee9b4bc4895cc491611b6691849061540c565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a604051602001611b96999897969594939291906154e8565b60408051601f1981840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152611c8d82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611c719190614fd0565b85608001516fffffffffffffffffffffffffffffffff16612c45565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b467f000000000000000000000000000000000000000000000000000000000000000014611838576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610741565b6040517f2cbc26bb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060801b77ffffffffffffffff000000000000000000000000000000001660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632cbc26bb90602401602060405180830381865afa158015611dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e109190615570565b15611e47576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151516000819003611e84576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260200151518114611ec2576040517f57e0e08300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff811115611edd57611edd61434e565b604051908082528060200260200182016040528015611f06578160200160208202803683370190505b50905060005b82811015611fde57600085600001518281518110611f2c57611f2c615091565b60200260200101519050611f60817f0000000000000000000000000000000000000000000000000000000000000000612c64565b838381518110611f7257611f72615091565b602002602001018181525050806101800151838381518110611f9657611f96615091565b602002602001015114611fd5576040517f7185cf6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600101611f0c565b50604080850151606086015191517f320488750000000000000000000000000000000000000000000000000000000081526000926001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692633204887592612052928792916004016155be565b602060405180830381865afa15801561206f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209391906155f4565b9050806000036120cf576040517fea75680100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351151560005b848110156127ac576000876000015182815181106120f6576120f6615091565b60200260200101519050600061210f8260600151610682565b905060028160038111156121255761212561429a565b0361216c57816060015167ffffffffffffffff167fe3dd0bec917c965a133ddb2c84874725ee1e2fd8d763c19efa36d6a11cd82b1f60405160405180910390a250506127a4565b60008160038111156121805761218061429a565b148061219d5750600381600381111561219b5761219b61429a565b145b6121e55760608201516040517f50a6e05200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610741565b83156122a257600a5460009063ffffffff166122018742614fd0565b11905080806122215750600382600381111561221f5761221f61429a565b145b612257576040517f6358b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88848151811061226957612269615091565b602002602001015160001461229c5788848151811061228a5761228a615091565b60200260200101518360800181815250505b506122ff565b60008160038111156122b6576122b661429a565b146122ff5760608201516040517f67d9ba0f00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610741565b60c082015167ffffffffffffffff161561257e576020808301516001600160a01b03166000908152600f909152604081205467ffffffffffffffff16908190036124e9577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316156124e95760208301516040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063856c824790602401602060405180830381865afa1580156123f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061241c9190615179565b60c084015190915067ffffffffffffffff1661243982600161560d565b67ffffffffffffffff16146124995782602001516001600160a01b03168360c0015167ffffffffffffffff167fe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d60405160405180910390a35050506127a4565b6020838101516001600160a01b03166000908152600f9091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790555b60008260038111156124fd576124fd61429a565b0361257c5760c083015167ffffffffffffffff1661251c82600161560d565b67ffffffffffffffff161461257c5782602001516001600160a01b03168360c0015167ffffffffffffffff167fd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf4123760405160405180910390a35050506127a4565b505b60008960200151848151811061259657612596615091565b602002602001015190506125c28360600151846000015185610140015151866101200151518551612dbf565b6125d183606001516001612f39565b6000806125de8584612fe3565b915091506125f0856060015183612f39565b861561265c57600382600381111561260a5761260a61429a565b0361265c5760008460038111156126235761262361429a565b1461265c57806040517fcf19edfd000000000000000000000000000000000000000000000000000000008152600401610741919061433b565b60028260038111156126705761267061429a565b146126c85760038260038111156126895761268961429a565b146126c8578460600151826040517f9e26160300000000000000000000000000000000000000000000000000000000815260040161074192919061562e565b60c085015167ffffffffffffffff16156127505760008460038111156126f0576126f061429a565b03612750576020808601516001600160a01b03166000908152600f90915260408120805467ffffffffffffffff16916127288361564c565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b846101800151856060015167ffffffffffffffff167fd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef658484604051612796929190615669565b60405180910390a350505050505b6001016120d6565b50505050505050565b6000610fa2836001600160a01b0384166132d6565b60006127e0846001600160a01b038516846132e2565b949350505050565b61280b6127f782840184615689565b604080516000815260208101909152611d32565b5050565b815460009061283890700100000000000000000000000000000000900463ffffffff1642614fd0565b905080156128da5760018301548354612880916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612c45565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612900916fffffffffffffffffffffffffffffffff90811691166132f8565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19906129e79084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b60405180910390a1505050565b60006106f78261330e565b6000808080612a0e8686613319565b909450925050505b9250929050565b336001600160a01b03821603612a8f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610741565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b846000805b8751811015612c0e57612b75888281518110612b1b57612b1b615091565b6020026020010151602001518888888581518110612b3b57612b3b615091565b6020026020010151806020019051810190612b5691906156be565b888681518110612b6857612b68615091565b6020026020010151613328565b838281518110612b8757612b87615091565b6020026020010181905250612bc3838281518110612ba757612ba7615091565b602002602001015160000151600c61374b90919063ffffffff16565b15612c0657612bf9838281518110612bdd57612bdd615091565b6020908102919091010151600b546001600160a01b0316613760565b612c039083615196565b91505b600101612afd565b508015612c1e57612c1e81613881565b505b95945050505050565b6000612c348361388e565b8015610fa25750610fa283836138f2565b6000612c2085612c558486615039565b612c5f9087615196565b6132f8565b60008060001b8284602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151604051602001612cfa9897969594939291906001600160a01b039889168152968816602088015267ffffffffffffffff95861660408801526060870194909452911515608086015290921660a0840152921660c082015260e08101919091526101000190565b6040516020818303038152906040528051906020012085610120015180519060200120866101400151604051602001612d339190615773565b60405160208183030381529060405280519060200120876101600151604051602001612d5f91906157e0565b60408051601f198184030181528282528051602091820120908301979097528101949094526060840192909252608083015260a082015260c081019190915260e00160405160208183030381529060405280519060200120905092915050565b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168467ffffffffffffffff1614612e38576040517f1279ec8a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff85166004820152602401610741565b600a5468010000000000000000900461ffff16831115612e90576040517f099d3f7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff86166004820152602401610741565b808314612ed5576040517f8808f8e700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff86166004820152602401610741565b600a54640100000000900463ffffffff168211156117bd57600a546040517f8693378900000000000000000000000000000000000000000000000000000000815264010000000090910463ffffffff16600482015260248101839052604401610741565b60006002612f48608085615012565b67ffffffffffffffff16612f5c9190615039565b90506000601081612f6e608087615050565b67ffffffffffffffff168152602081019190915260400160002054905081612f9860016004614fd0565b901b191681836003811115612faf57612faf61429a565b901b178060106000612fc2608088615050565b67ffffffffffffffff16815260208101919091526040016000205550505050565b6040517ff52121a5000000000000000000000000000000000000000000000000000000008152600090606090309063f52121a59061302790879087906004016157f3565b600060405180830381600087803b15801561304157600080fd5b505af1925050508015613052575060015b6132bb573d808015613080576040519150601f19603f3d011682016040523d82523d6000602084013e613085565b606091505b5061308f81615956565b7fffffffff00000000000000000000000000000000000000000000000000000000167f0a8d6e8c00000000000000000000000000000000000000000000000000000000148061312757506130e281615956565b7fffffffff00000000000000000000000000000000000000000000000000000000167fe1cd550900000000000000000000000000000000000000000000000000000000145b8061317b575061313681615956565b7fffffffff00000000000000000000000000000000000000000000000000000000167f8d666f6000000000000000000000000000000000000000000000000000000000145b806131cf575061318a81615956565b7fffffffff00000000000000000000000000000000000000000000000000000000167f78ef802400000000000000000000000000000000000000000000000000000000145b8061322357506131de81615956565b7fffffffff00000000000000000000000000000000000000000000000000000000167f0c3b563c00000000000000000000000000000000000000000000000000000000145b80613277575061323281615956565b7fffffffff00000000000000000000000000000000000000000000000000000000167fae9b4ce900000000000000000000000000000000000000000000000000000000145b1561328757600392509050612a16565b806040517fcf19edfd000000000000000000000000000000000000000000000000000000008152600401610741919061433b565b50506040805160208101909152600081526002909250929050565b6000610fa283836139c1565b60006127e084846001600160a01b0385166139de565b60008183106133075781610fa2565b5090919050565b60006106f7826139fb565b6000808080612a0e8686613a06565b6040805180820190915260008082526020820152600061334b8460200151613a31565b6040517fbbe4f6db0000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063bbe4f6db90602401602060405180830381865afa1580156133d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f491906159a6565b90506001600160a01b038116158061343c575061343a6001600160a01b0382167faff2afbf00000000000000000000000000000000000000000000000000000000612c29565b155b1561347e576040517fae9b4ce90000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610741565b6000806135986040518061010001604052808b81526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020018a6001600160a01b031681526020018c8152602001866001600160a01b0316815260200189600001518152602001896040015181526020018881525060405160240161351291906159c3565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f3907753700000000000000000000000000000000000000000000000000000000179052600b54859063ffffffff74010000000000000000000000000000000000000000909104166113886084613ad7565b5091509150816135d657806040517fe1cd5509000000000000000000000000000000000000000000000000000000008152600401610741919061433b565b805160201461361e5780516040517f78ef8024000000000000000000000000000000000000000000000000000000008152602060048201526024810191909152604401610741565b60008180602001905181019061363491906155f4565b6040516001600160a01b038b166024820152604481018290529091506136e19060640160408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052600b54879063ffffffff7801000000000000000000000000000000000000000000000000909104166113886084613ad7565b5090935091508261372057816040517fe1cd5509000000000000000000000000000000000000000000000000000000008152600401610741919061433b565b604080518082019091526001600160a01b039095168552602085015250919250505095945050505050565b6000610fa2836001600160a01b038416613bfd565b81516040517fd02641a00000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260009182919084169063d02641a0906024016040805180830381865afa1580156137c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137ea9190615a9a565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81166000036138535783516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610741565b60208401516127e0907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff831690613c09565b6113ea6003826000613c46565b60006138ba827f01ffc9a7000000000000000000000000000000000000000000000000000000006138f2565b80156106f757506138eb827fffffffff000000000000000000000000000000000000000000000000000000006138f2565b1592915050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d915060005190508280156139aa575060208210155b80156139b65750600081115b979650505050505050565b60008181526002830160205260408120819055610fa28383613f95565b600082815260028401602052604081208290556127e08484613fa1565b60006106f782613fad565b60008080613a148585613fb7565b600081815260029690960160205260409095205494959350505050565b60008151602014613a7057816040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610741919061433b565b600082806020019051810190613a8691906155f4565b90506001600160a01b03811180613a9e575061040081105b156106f757826040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610741919061433b565b6000606060008361ffff1667ffffffffffffffff811115613afa57613afa61434e565b6040519080825280601f01601f191660200182016040528015613b24576020820181803683370190505b509150863b613b57577f0c3b563c0000000000000000000000000000000000000000000000000000000060005260046000fd5b5a85811015613b8a577fafa32a2c0000000000000000000000000000000000000000000000000000000060005260046000fd5b8590036040810481038710613bc3577f37c3be290000000000000000000000000000000000000000000000000000000060005260046000fd5b505a6000808a5160208c0160008c8cf193505a900390503d84811115613be65750835b808352806000602085013e50955095509592505050565b6000610fa28383613fc3565b6000670de0b6b3a7640000613c3c837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8616615039565b610fa29190615afa565b825474010000000000000000000000000000000000000000900460ff161580613c6d575081155b15613c7757505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090613cbd90700100000000000000000000000000000000900463ffffffff1642614fd0565b90508015613d7d5781831115613cff576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001860154613d399083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612c45565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b84821015613e1a576001600160a01b038416613dcf576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610741565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b0385166044820152606401610741565b84831015613f135760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16906000908290613e5e9082614fd0565b613e68878a614fd0565b613e729190615196565b613e7c9190615afa565b90506001600160a01b038616613ec8576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610741565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b0387166044820152606401610741565b613f1d8584614fd0565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6000610fa28383613fe2565b6000610fa283836140dc565b60006106f7825490565b6000610fa2838361412b565b6000610fa2838360008181526001830160205260408120541515610fa2565b600081815260018301602052604081205480156140cb576000614006600183614fd0565b855490915060009061401a90600190614fd0565b905081811461407f57600086600001828154811061403a5761403a615091565b906000526020600020015490508087600001848154811061405d5761405d615091565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061409057614090615b0e565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106f7565b60009150506106f7565b5092915050565b6000818152600183016020526040812054614123575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106f7565b5060006106f7565b600082600001828154811061414257614142615091565b9060005260206000200154905092915050565b8280548282559060005260206000209081019282156141c2579160200282015b828111156141c257825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909116178255602090920191600190910190614175565b506141ce9291506141d2565b5090565b5b808211156141ce57600081556001016141d3565b60e081016106f782846001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b67ffffffffffffffff811681146113ea57600080fd5b803561427881614257565b919050565b60006020828403121561428f57600080fd5b8135610fa281614257565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600481106142d9576142d961429a565b9052565b602081016106f782846142c9565b60005b838110156143065781810151838201526020016142ee565b50506000910152565b600081518084526143278160208601602086016142eb565b601f01601f19169290920160200192915050565b602081526000610fa2602083018461430f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156143a0576143a061434e565b60405290565b6040516101a0810167ffffffffffffffff811182821017156143a0576143a061434e565b6040516080810167ffffffffffffffff811182821017156143a0576143a061434e565b6040516060810167ffffffffffffffff811182821017156143a0576143a061434e565b60405160e0810167ffffffffffffffff811182821017156143a0576143a061434e565b604051601f8201601f1916810167ffffffffffffffff8111828210171561445c5761445c61434e565b604052919050565b600067ffffffffffffffff82111561447e5761447e61434e565b5060051b60200190565b6001600160a01b03811681146113ea57600080fd5b803561427881614488565b600082601f8301126144b957600080fd5b813560206144ce6144c983614464565b614433565b8083825260208201915060208460051b8701019350868411156144f057600080fd5b602086015b8481101561451557803561450881614488565b83529183019183016144f5565b509695505050505050565b803560ff8116811461427857600080fd5b600067ffffffffffffffff82111561454b5761454b61434e565b50601f01601f191660200190565b600082601f83011261456a57600080fd5b81356145786144c982614531565b81815284602083860101111561458d57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156145c357600080fd5b863567ffffffffffffffff808211156145db57600080fd5b6145e78a838b016144a8565b975060208901359150808211156145fd57600080fd5b6146098a838b016144a8565b965061461760408a01614520565b9550606089013591508082111561462d57600080fd5b6146398a838b01614559565b945061464760808a0161426d565b935060a089013591508082111561465d57600080fd5b5061466a89828a01614559565b9150509295509295509295565b60008151808452602080850194506020840160005b838110156146b15781516001600160a01b03168752958201959082019060010161468c565b509495945050505050565b602081526000610fa26020830184614677565b6000602082840312156146e157600080fd5b8135610fa281614488565b80151581146113ea57600080fd5b8035614278816146ec565b600082601f83011261471657600080fd5b813560206147266144c983614464565b82815260069290921b8401810191818101908684111561474557600080fd5b8286015b8481101561451557604081890312156147625760008081fd5b61476a61437d565b813561477581614488565b81528185013585820152835291830191604001614749565b600082601f83011261479e57600080fd5b813560206147ae6144c983614464565b82815260059290921b840181019181810190868411156147cd57600080fd5b8286015b8481101561451557803567ffffffffffffffff8111156147f15760008081fd5b6147ff8986838b0101614559565b8452509183019183016147d1565b60006101a0828403121561482057600080fd5b6148286143a6565b90506148338261426d565b81526148416020830161449d565b60208201526148526040830161449d565b60408201526148636060830161426d565b60608201526080820135608082015261487e60a083016146fa565b60a082015261488f60c0830161426d565b60c08201526148a060e0830161449d565b60e082015261010082810135908201526101208083013567ffffffffffffffff808211156148cd57600080fd5b6148d986838701614559565b838501526101409250828501359150808211156148f557600080fd5b61490186838701614705565b8385015261016092508285013591508082111561491d57600080fd5b5061492a8582860161478d565b82840152505061018080830135818301525092915050565b600082601f83011261495357600080fd5b813560206149636144c983614464565b82815260059290921b8401810191818101908684111561498257600080fd5b8286015b8481101561451557803567ffffffffffffffff8111156149a65760008081fd5b6149b48986838b010161478d565b845250918301918301614986565b600082601f8301126149d357600080fd5b813560206149e36144c983614464565b8083825260208201915060208460051b870101935086841115614a0557600080fd5b602086015b848110156145155780358352918301918301614a0a565b600060808284031215614a3357600080fd5b614a3b6143ca565b9050813567ffffffffffffffff80821115614a5557600080fd5b818401915084601f830112614a6957600080fd5b81356020614a796144c983614464565b82815260059290921b84018101918181019088841115614a9857600080fd5b8286015b84811015614ad057803586811115614ab45760008081fd5b614ac28b86838b010161480d565b845250918301918301614a9c565b5086525085810135935082841115614ae757600080fd5b614af387858801614942565b90850152506040840135915080821115614b0c57600080fd5b50614b19848285016149c2565b6040830152506060820135606082015292915050565b60008060408385031215614b4257600080fd5b823567ffffffffffffffff80821115614b5a57600080fd5b614b6686838701614a21565b9350602091508185013581811115614b7d57600080fd5b85019050601f81018613614b9057600080fd5b8035614b9e6144c982614464565b81815260059190911b82018301908381019088831115614bbd57600080fd5b928401925b82841015614bdb57833582529284019290840190614bc2565b80955050505050509250929050565b60e081016106f7828463ffffffff80825116835280602083015116602084015261ffff604083015116604084015260608201516001600160a01b03808216606086015280608085015116608086015250508060a08301511660a08401528060c08301511660c0840152505050565b600060208284031215614c6a57600080fd5b813567ffffffffffffffff811115614c8157600080fd5b820160a08185031215610fa257600080fd5b600082601f830112614ca457600080fd5b81356020614cb46144c983614464565b82815260069290921b84018101918181019086841115614cd357600080fd5b8286015b848110156145155760408189031215614cf05760008081fd5b614cf861437d565b8135614d0381614488565b815281850135614d1281614488565b81860152835291830191604001614cd7565b60008060408385031215614d3757600080fd5b823567ffffffffffffffff80821115614d4f57600080fd5b614d5b86838701614c93565b93506020850135915080821115614d7157600080fd5b50614d7e85828601614c93565b9150509250929050565b60008083601f840112614d9a57600080fd5b50813567ffffffffffffffff811115614db257600080fd5b6020830191508360208260051b8501011115612a1657600080fd5b60008060008060008060008060e0898b031215614de957600080fd5b606089018a811115614dfa57600080fd5b8998503567ffffffffffffffff80821115614e1457600080fd5b818b0191508b601f830112614e2857600080fd5b813581811115614e3757600080fd5b8c6020828501011115614e4957600080fd5b6020830199508098505060808b0135915080821115614e6757600080fd5b614e738c838d01614d88565b909750955060a08b0135915080821115614e8c57600080fd5b50614e998b828c01614d88565b999c989b50969995989497949560c00135949350505050565b80356fffffffffffffffffffffffffffffffff8116811461427857600080fd5b600060608284031215614ee457600080fd5b614eec6143ed565b8235614ef7816146ec565b8152614f0560208401614eb2565b6020820152614f1660408401614eb2565b60408201529392505050565b604081526000614f356040830185614677565b8281036020840152612c208185614677565b60008060408385031215614f5a57600080fd5b823567ffffffffffffffff80821115614f7257600080fd5b614f7e8683870161480d565b93506020850135915080821115614f9457600080fd5b50614d7e8582860161478d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156106f7576106f7614fa1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff8084168061502d5761502d614fe3565b92169190910692915050565b80820281158282048414176106f7576106f7614fa1565b600067ffffffffffffffff8084168061506b5761506b614fe3565b92169190910492915050565b602081016003831061508b5761508b61429a565b91905290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff8083168181036150d9576150d9614fa1565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526151138184018a614677565b905082810360808401526151278189614677565b905060ff871660a084015282810360c0840152615144818761430f565b905067ffffffffffffffff851660e0840152828103610100840152615169818561430f565b9c9b505050505050505050505050565b60006020828403121561518b57600080fd5b8151610fa281614257565b808201808211156106f7576106f7614fa1565b60008151808452602080850194506020840160005b838110156146b157815180516001600160a01b0316885283015183880152604090960195908201906001016151be565b608081528451608082015267ffffffffffffffff60208601511660a08201526000604086015160a060c084015261522961012084018261430f565b905060608701517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808584030160e0860152615265838361430f565b92506080890151915080858403016101008601525061528482826151a9565b92505050615298602083018661ffff169052565b836040830152612c2060608301846001600160a01b03169052565b600082601f8301126152c457600080fd5b81516152d26144c982614531565b8181528460208386010111156152e757600080fd5b6127e08260208301602087016142eb565b60008060006060848603121561530d57600080fd5b8351615318816146ec565b602085015190935067ffffffffffffffff81111561533557600080fd5b615341868287016152b3565b925050604084015190509250925092565b805163ffffffff8116811461427857600080fd5b805161427881614488565b600060e0828403121561538357600080fd5b61538b614410565b61539483615352565b81526153a260208401615352565b6020820152604083015161ffff811681146153bc57600080fd5b60408201526153cd60608401615366565b60608201526153de60808401615366565b60808201526153ef60a08401615352565b60a082015261540060c08401615352565b60c08201529392505050565b6101c0810161547d82856001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b825163ffffffff90811660e084015260208401518116610100840152604084015161ffff1661012084015260608401516001600160a01b0390811661014085015260808501511661016084015260a0840151811661018084015260c0840151166101a0830152610fa2565b60006101208b83526001600160a01b038b16602084015267ffffffffffffffff808b1660408501528160608501526155228285018b614677565b91508382036080850152615536828a614677565b915060ff881660a085015283820360c0850152615553828861430f565b90861660e08501528381036101008501529050615169818561430f565b60006020828403121561558257600080fd5b8151610fa2816146ec565b60008151808452602080850194506020840160005b838110156146b1578151875295820195908201906001016155a2565b6060815260006155d1606083018661558d565b82810360208401526155e3818661558d565b915050826040830152949350505050565b60006020828403121561560657600080fd5b5051919050565b67ffffffffffffffff8181168382160190808211156140d5576140d5614fa1565b67ffffffffffffffff8316815260408101610fa260208301846142c9565b600067ffffffffffffffff8083168181036150d9576150d9614fa1565b61567381846142c9565b6040602082015260006127e0604083018461430f565b60006020828403121561569b57600080fd5b813567ffffffffffffffff8111156156b257600080fd5b6127e084828501614a21565b6000602082840312156156d057600080fd5b815167ffffffffffffffff808211156156e857600080fd5b90830190606082860312156156fc57600080fd5b6157046143ed565b82518281111561571357600080fd5b61571f878286016152b3565b82525060208301518281111561573457600080fd5b615740878286016152b3565b60208301525060408301518281111561575857600080fd5b615764878286016152b3565b60408301525095945050505050565b602081526000610fa260208301846151a9565b60008282518085526020808601955060208260051b8401016020860160005b848110156157d357601f198684030189526157c183835161430f565b988401989250908301906001016157a5565b5090979650505050505050565b602081526000610fa26020830184615786565b6040815261580e60408201845167ffffffffffffffff169052565b6000602084015161582a60608401826001600160a01b03169052565b5060408401516001600160a01b038116608084015250606084015167ffffffffffffffff811660a084015250608084015160c083015260a084015180151560e08401525060c084015161010061588b8185018367ffffffffffffffff169052565b60e086015191506101206158a9818601846001600160a01b03169052565b81870151925061014091508282860152808701519250506101a061016081818701526158d96101e087018561430f565b93508288015192507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc061018081888703018189015261591886866151a9565b9550828a015194508188870301848901526159338686615786565b9550808a01516101c089015250505050508281036020840152612c208185615786565b6000815160208301517fffffffff000000000000000000000000000000000000000000000000000000008082169350600483101561599e5780818460040360031b1b83161693505b505050919050565b6000602082840312156159b857600080fd5b8151610fa281614488565b60208152600082516101008060208501526159e261012085018361430f565b915060208501516159ff604086018267ffffffffffffffff169052565b5060408501516001600160a01b038116606086015250606085015160808501526080850151615a3960a08601826001600160a01b03169052565b5060a0850151601f19808685030160c0870152615a56848361430f565b935060c08701519150808685030160e0870152615a73848361430f565b935060e0870151915080868503018387015250615a90838261430f565b9695505050505050565b600060408284031215615aac57600080fd5b615ab461437d565b82517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114615ae057600080fd5b8152615aee60208401615352565b60208201529392505050565b600082615b0957615b09614fe3565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a",
+}
+
+var EVM2EVMOffRampABI = EVM2EVMOffRampMetaData.ABI
+
+var EVM2EVMOffRampBin = EVM2EVMOffRampMetaData.Bin
+
+func DeployEVM2EVMOffRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMOffRampStaticConfig, rateLimiterConfig RateLimiterConfig) (common.Address, *types.Transaction, *EVM2EVMOffRamp, error) {
+ parsed, err := EVM2EVMOffRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMOffRampBin), backend, staticConfig, rateLimiterConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMOffRamp{address: address, abi: *parsed, EVM2EVMOffRampCaller: EVM2EVMOffRampCaller{contract: contract}, EVM2EVMOffRampTransactor: EVM2EVMOffRampTransactor{contract: contract}, EVM2EVMOffRampFilterer: EVM2EVMOffRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMOffRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMOffRampCaller
+ EVM2EVMOffRampTransactor
+ EVM2EVMOffRampFilterer
+}
+
+type EVM2EVMOffRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampSession struct {
+ Contract *EVM2EVMOffRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOffRampCallerSession struct {
+ Contract *EVM2EVMOffRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMOffRampTransactorSession struct {
+ Contract *EVM2EVMOffRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOffRampRaw struct {
+ Contract *EVM2EVMOffRamp
+}
+
+type EVM2EVMOffRampCallerRaw struct {
+ Contract *EVM2EVMOffRampCaller
+}
+
+type EVM2EVMOffRampTransactorRaw struct {
+ Contract *EVM2EVMOffRampTransactor
+}
+
+func NewEVM2EVMOffRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMOffRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMOffRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMOffRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRamp{address: address, abi: abi, EVM2EVMOffRampCaller: EVM2EVMOffRampCaller{contract: contract}, EVM2EVMOffRampTransactor: EVM2EVMOffRampTransactor{contract: contract}, EVM2EVMOffRampFilterer: EVM2EVMOffRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMOffRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMOffRampCaller, error) {
+ contract, err := bindEVM2EVMOffRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMOffRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMOffRampTransactor, error) {
+ contract, err := bindEVM2EVMOffRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMOffRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMOffRampFilterer, error) {
+ contract, err := bindEVM2EVMOffRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMOffRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMOffRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOffRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) CcipReceive(opts *bind.CallOpts, arg0 ClientAny2EVMMessage) error {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "ccipReceive", arg0)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) CcipReceive(arg0 ClientAny2EVMMessage) error {
+ return _EVM2EVMOffRamp.Contract.CcipReceive(&_EVM2EVMOffRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) CcipReceive(arg0 ClientAny2EVMMessage) error {
+ return _EVM2EVMOffRamp.Contract.CcipReceive(&_EVM2EVMOffRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "currentRateLimiterState")
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOffRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOffRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetAllRateLimitTokens(opts *bind.CallOpts) (GetAllRateLimitTokens,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getAllRateLimitTokens")
+
+ outstruct := new(GetAllRateLimitTokens)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.SourceTokens = *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+ outstruct.DestTokens = *abi.ConvertType(out[1], new([]common.Address)).(*[]common.Address)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetAllRateLimitTokens() (GetAllRateLimitTokens,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.GetAllRateLimitTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetAllRateLimitTokens() (GetAllRateLimitTokens,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.GetAllRateLimitTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOffRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOffRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOffRampDynamicConfig)).(*EVM2EVMOffRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetDynamicConfig() (EVM2EVMOffRampDynamicConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetDynamicConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetDynamicConfig() (EVM2EVMOffRampDynamicConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetDynamicConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getExecutionState", sequenceNumber)
+
+ if err != nil {
+ return *new(uint8), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetExecutionState(sequenceNumber uint64) (uint8, error) {
+ return _EVM2EVMOffRamp.Contract.GetExecutionState(&_EVM2EVMOffRamp.CallOpts, sequenceNumber)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetExecutionState(sequenceNumber uint64) (uint8, error) {
+ return _EVM2EVMOffRamp.Contract.GetExecutionState(&_EVM2EVMOffRamp.CallOpts, sequenceNumber)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getSenderNonce", sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOffRamp.Contract.GetSenderNonce(&_EVM2EVMOffRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOffRamp.Contract.GetSenderNonce(&_EVM2EVMOffRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOffRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOffRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOffRampStaticConfig)).(*EVM2EVMOffRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetStaticConfig() (EVM2EVMOffRampStaticConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetStaticConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetStaticConfig() (EVM2EVMOffRampStaticConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetStaticConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getTokenLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetTransmitters() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTransmitters(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTransmitters(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDetails(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDetails(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDigestAndEpoch(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDigestAndEpoch(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.Owner(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.Owner(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOffRamp.Contract.TypeAndVersion(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOffRamp.Contract.TypeAndVersion(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.AcceptOwnership(&_EVM2EVMOffRamp.TransactOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.AcceptOwnership(&_EVM2EVMOffRamp.TransactOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) ExecuteSingleMessage(opts *bind.TransactOpts, message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "executeSingleMessage", message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) ExecuteSingleMessage(message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ExecuteSingleMessage(&_EVM2EVMOffRamp.TransactOpts, message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) ExecuteSingleMessage(message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ExecuteSingleMessage(&_EVM2EVMOffRamp.TransactOpts, message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) ManuallyExecute(opts *bind.TransactOpts, report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "manuallyExecute", report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) ManuallyExecute(report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ManuallyExecute(&_EVM2EVMOffRamp.TransactOpts, report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) ManuallyExecute(report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ManuallyExecute(&_EVM2EVMOffRamp.TransactOpts, report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setAdmin", newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetAdmin(&_EVM2EVMOffRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetAdmin(&_EVM2EVMOffRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetOCR2Config(&_EVM2EVMOffRamp.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetOCR2Config(&_EVM2EVMOffRamp.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setRateLimiterConfig", config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOffRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOffRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.TransferOwnership(&_EVM2EVMOffRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.TransferOwnership(&_EVM2EVMOffRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "transmit", reportContext, report, rs, ss, arg4)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.Transmit(&_EVM2EVMOffRamp.TransactOpts, reportContext, report, rs, ss, arg4)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.Transmit(&_EVM2EVMOffRamp.TransactOpts, reportContext, report, rs, ss, arg4)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) UpdateRateLimitTokens(opts *bind.TransactOpts, removes []EVM2EVMOffRampRateLimitToken, adds []EVM2EVMOffRampRateLimitToken) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "updateRateLimitTokens", removes, adds)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) UpdateRateLimitTokens(removes []EVM2EVMOffRampRateLimitToken, adds []EVM2EVMOffRampRateLimitToken) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.UpdateRateLimitTokens(&_EVM2EVMOffRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) UpdateRateLimitTokens(removes []EVM2EVMOffRampRateLimitToken, adds []EVM2EVMOffRampRateLimitToken) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.UpdateRateLimitTokens(&_EVM2EVMOffRamp.TransactOpts, removes, adds)
+}
+
+type EVM2EVMOffRampAdminSetIterator struct {
+ Event *EVM2EVMOffRampAdminSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampAdminSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampAdminSet)
+ 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(EVM2EVMOffRampAdminSet)
+ 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 *EVM2EVMOffRampAdminSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampAdminSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampAdminSet struct {
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOffRampAdminSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampAdminSetIterator{contract: _EVM2EVMOffRamp.contract, event: "AdminSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampAdminSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampAdminSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "AdminSet", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseAdminSet(log types.Log) (*EVM2EVMOffRampAdminSet, error) {
+ event := new(EVM2EVMOffRampAdminSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "AdminSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampConfigChangedIterator struct {
+ Event *EVM2EVMOffRampConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampConfigChanged)
+ 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(EVM2EVMOffRampConfigChanged)
+ 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 *EVM2EVMOffRampConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigChangedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampConfigChangedIterator{contract: _EVM2EVMOffRamp.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampConfigChanged)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigChanged", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseConfigChanged(log types.Log) (*EVM2EVMOffRampConfigChanged, error) {
+ event := new(EVM2EVMOffRampConfigChanged)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampConfigSetIterator struct {
+ Event *EVM2EVMOffRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampConfigSet)
+ 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(EVM2EVMOffRampConfigSet)
+ 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 *EVM2EVMOffRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampConfigSet struct {
+ StaticConfig EVM2EVMOffRampStaticConfig
+ DynamicConfig EVM2EVMOffRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampConfigSetIterator{contract: _EVM2EVMOffRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampConfigSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMOffRampConfigSet, error) {
+ event := new(EVM2EVMOffRampConfigSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampConfigSet0Iterator struct {
+ Event *EVM2EVMOffRampConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampConfigSet0)
+ 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(EVM2EVMOffRampConfigSet0)
+ 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 *EVM2EVMOffRampConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSet0Iterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampConfigSet0Iterator{contract: _EVM2EVMOffRamp.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampConfigSet0)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet0", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseConfigSet0(log types.Log) (*EVM2EVMOffRampConfigSet0, error) {
+ event := new(EVM2EVMOffRampConfigSet0)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampExecutionStateChangedIterator struct {
+ Event *EVM2EVMOffRampExecutionStateChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampExecutionStateChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampExecutionStateChanged)
+ 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(EVM2EVMOffRampExecutionStateChanged)
+ 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 *EVM2EVMOffRampExecutionStateChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampExecutionStateChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampExecutionStateChanged struct {
+ SequenceNumber uint64
+ MessageId [32]byte
+ State uint8
+ ReturnData []byte
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*EVM2EVMOffRampExecutionStateChangedIterator, error) {
+
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ExecutionStateChanged", sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampExecutionStateChangedIterator{contract: _EVM2EVMOffRamp.contract, event: "ExecutionStateChanged", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) {
+
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ExecutionStateChanged", sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampExecutionStateChanged)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ExecutionStateChanged", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseExecutionStateChanged(log types.Log) (*EVM2EVMOffRampExecutionStateChanged, error) {
+ event := new(EVM2EVMOffRampExecutionStateChanged)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ExecutionStateChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMOffRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampOwnershipTransferRequested)
+ 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(EVM2EVMOffRampOwnershipTransferRequested)
+ 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 *EVM2EVMOffRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampOwnershipTransferRequestedIterator{contract: _EVM2EVMOffRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampOwnershipTransferRequested)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOffRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMOffRampOwnershipTransferRequested)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMOffRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampOwnershipTransferred)
+ 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(EVM2EVMOffRampOwnershipTransferred)
+ 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 *EVM2EVMOffRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampOwnershipTransferredIterator{contract: _EVM2EVMOffRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampOwnershipTransferred)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMOffRampOwnershipTransferred, error) {
+ event := new(EVM2EVMOffRampOwnershipTransferred)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator struct {
+ Event *EVM2EVMOffRampSkippedAlreadyExecutedMessage
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampSkippedAlreadyExecutedMessage)
+ 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(EVM2EVMOffRampSkippedAlreadyExecutedMessage)
+ 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 *EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampSkippedAlreadyExecutedMessage struct {
+ SequenceNumber uint64
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterSkippedAlreadyExecutedMessage(opts *bind.FilterOpts, sequenceNumber []uint64) (*EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator, error) {
+
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "SkippedAlreadyExecutedMessage", sequenceNumberRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator{contract: _EVM2EVMOffRamp.contract, event: "SkippedAlreadyExecutedMessage", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchSkippedAlreadyExecutedMessage(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedAlreadyExecutedMessage, sequenceNumber []uint64) (event.Subscription, error) {
+
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "SkippedAlreadyExecutedMessage", sequenceNumberRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampSkippedAlreadyExecutedMessage)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedAlreadyExecutedMessage", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseSkippedAlreadyExecutedMessage(log types.Log) (*EVM2EVMOffRampSkippedAlreadyExecutedMessage, error) {
+ event := new(EVM2EVMOffRampSkippedAlreadyExecutedMessage)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedAlreadyExecutedMessage", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampSkippedIncorrectNonceIterator struct {
+ Event *EVM2EVMOffRampSkippedIncorrectNonce
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampSkippedIncorrectNonceIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampSkippedIncorrectNonce)
+ 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(EVM2EVMOffRampSkippedIncorrectNonce)
+ 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 *EVM2EVMOffRampSkippedIncorrectNonceIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampSkippedIncorrectNonceIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampSkippedIncorrectNonce struct {
+ Nonce uint64
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedIncorrectNonceIterator, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "SkippedIncorrectNonce", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampSkippedIncorrectNonceIterator{contract: _EVM2EVMOffRamp.contract, event: "SkippedIncorrectNonce", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "SkippedIncorrectNonce", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampSkippedIncorrectNonce)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedIncorrectNonce", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseSkippedIncorrectNonce(log types.Log) (*EVM2EVMOffRampSkippedIncorrectNonce, error) {
+ event := new(EVM2EVMOffRampSkippedIncorrectNonce)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedIncorrectNonce", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator struct {
+ Event *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ 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(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ 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 *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight struct {
+ Nonce uint64
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "SkippedSenderWithPreviousRampMessageInflight", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator{contract: _EVM2EVMOffRamp.contract, event: "SkippedSenderWithPreviousRampMessageInflight", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "SkippedSenderWithPreviousRampMessageInflight", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedSenderWithPreviousRampMessageInflight", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error) {
+ event := new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedSenderWithPreviousRampMessageInflight", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampTokenAggregateRateLimitAddedIterator struct {
+ Event *EVM2EVMOffRampTokenAggregateRateLimitAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampTokenAggregateRateLimitAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampTokenAggregateRateLimitAdded)
+ 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(EVM2EVMOffRampTokenAggregateRateLimitAdded)
+ 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 *EVM2EVMOffRampTokenAggregateRateLimitAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampTokenAggregateRateLimitAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampTokenAggregateRateLimitAdded struct {
+ SourceToken common.Address
+ DestToken common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterTokenAggregateRateLimitAdded(opts *bind.FilterOpts) (*EVM2EVMOffRampTokenAggregateRateLimitAddedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "TokenAggregateRateLimitAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTokenAggregateRateLimitAddedIterator{contract: _EVM2EVMOffRamp.contract, event: "TokenAggregateRateLimitAdded", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchTokenAggregateRateLimitAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTokenAggregateRateLimitAdded) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "TokenAggregateRateLimitAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampTokenAggregateRateLimitAdded)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "TokenAggregateRateLimitAdded", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseTokenAggregateRateLimitAdded(log types.Log) (*EVM2EVMOffRampTokenAggregateRateLimitAdded, error) {
+ event := new(EVM2EVMOffRampTokenAggregateRateLimitAdded)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "TokenAggregateRateLimitAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator struct {
+ Event *EVM2EVMOffRampTokenAggregateRateLimitRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampTokenAggregateRateLimitRemoved)
+ 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(EVM2EVMOffRampTokenAggregateRateLimitRemoved)
+ 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 *EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampTokenAggregateRateLimitRemoved struct {
+ SourceToken common.Address
+ DestToken common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterTokenAggregateRateLimitRemoved(opts *bind.FilterOpts) (*EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "TokenAggregateRateLimitRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator{contract: _EVM2EVMOffRamp.contract, event: "TokenAggregateRateLimitRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchTokenAggregateRateLimitRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTokenAggregateRateLimitRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "TokenAggregateRateLimitRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampTokenAggregateRateLimitRemoved)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "TokenAggregateRateLimitRemoved", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseTokenAggregateRateLimitRemoved(log types.Log) (*EVM2EVMOffRampTokenAggregateRateLimitRemoved, error) {
+ event := new(EVM2EVMOffRampTokenAggregateRateLimitRemoved)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "TokenAggregateRateLimitRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampTokensConsumedIterator struct {
+ Event *EVM2EVMOffRampTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampTokensConsumed)
+ 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(EVM2EVMOffRampTokensConsumed)
+ 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 *EVM2EVMOffRampTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*EVM2EVMOffRampTokensConsumedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTokensConsumedIterator{contract: _EVM2EVMOffRamp.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampTokensConsumed)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "TokensConsumed", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseTokensConsumed(log types.Log) (*EVM2EVMOffRampTokensConsumed, error) {
+ event := new(EVM2EVMOffRampTokensConsumed)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampTransmittedIterator struct {
+ Event *EVM2EVMOffRampTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampTransmitted)
+ 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(EVM2EVMOffRampTransmitted)
+ 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 *EVM2EVMOffRampTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterTransmitted(opts *bind.FilterOpts) (*EVM2EVMOffRampTransmittedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTransmittedIterator{contract: _EVM2EVMOffRamp.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampTransmitted)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "Transmitted", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseTransmitted(log types.Log) (*EVM2EVMOffRampTransmitted, error) {
+ event := new(EVM2EVMOffRampTransmitted)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetAllRateLimitTokens struct {
+ SourceTokens []common.Address
+ DestTokens []common.Address
+}
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMOffRamp.abi.Events["AdminSet"].ID:
+ return _EVM2EVMOffRamp.ParseAdminSet(log)
+ case _EVM2EVMOffRamp.abi.Events["ConfigChanged"].ID:
+ return _EVM2EVMOffRamp.ParseConfigChanged(log)
+ case _EVM2EVMOffRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMOffRamp.ParseConfigSet(log)
+ case _EVM2EVMOffRamp.abi.Events["ConfigSet0"].ID:
+ return _EVM2EVMOffRamp.ParseConfigSet0(log)
+ case _EVM2EVMOffRamp.abi.Events["ExecutionStateChanged"].ID:
+ return _EVM2EVMOffRamp.ParseExecutionStateChanged(log)
+ case _EVM2EVMOffRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMOffRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMOffRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMOffRamp.ParseOwnershipTransferred(log)
+ case _EVM2EVMOffRamp.abi.Events["SkippedAlreadyExecutedMessage"].ID:
+ return _EVM2EVMOffRamp.ParseSkippedAlreadyExecutedMessage(log)
+ case _EVM2EVMOffRamp.abi.Events["SkippedIncorrectNonce"].ID:
+ return _EVM2EVMOffRamp.ParseSkippedIncorrectNonce(log)
+ case _EVM2EVMOffRamp.abi.Events["SkippedSenderWithPreviousRampMessageInflight"].ID:
+ return _EVM2EVMOffRamp.ParseSkippedSenderWithPreviousRampMessageInflight(log)
+ case _EVM2EVMOffRamp.abi.Events["TokenAggregateRateLimitAdded"].ID:
+ return _EVM2EVMOffRamp.ParseTokenAggregateRateLimitAdded(log)
+ case _EVM2EVMOffRamp.abi.Events["TokenAggregateRateLimitRemoved"].ID:
+ return _EVM2EVMOffRamp.ParseTokenAggregateRateLimitRemoved(log)
+ case _EVM2EVMOffRamp.abi.Events["TokensConsumed"].ID:
+ return _EVM2EVMOffRamp.ParseTokensConsumed(log)
+ case _EVM2EVMOffRamp.abi.Events["Transmitted"].ID:
+ return _EVM2EVMOffRamp.ParseTransmitted(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMOffRampAdminSet) Topic() common.Hash {
+ return common.HexToHash("0x8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c")
+}
+
+func (EVM2EVMOffRampConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (EVM2EVMOffRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xf02fcc22535d64d92d17b995475893d63edd51da163fed74a6ee9b4bc4895cc4")
+}
+
+func (EVM2EVMOffRampConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (EVM2EVMOffRampExecutionStateChanged) Topic() common.Hash {
+ return common.HexToHash("0xd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef65")
+}
+
+func (EVM2EVMOffRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMOffRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (EVM2EVMOffRampSkippedAlreadyExecutedMessage) Topic() common.Hash {
+ return common.HexToHash("0xe3dd0bec917c965a133ddb2c84874725ee1e2fd8d763c19efa36d6a11cd82b1f")
+}
+
+func (EVM2EVMOffRampSkippedIncorrectNonce) Topic() common.Hash {
+ return common.HexToHash("0xd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf41237")
+}
+
+func (EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight) Topic() common.Hash {
+ return common.HexToHash("0xe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d")
+}
+
+func (EVM2EVMOffRampTokenAggregateRateLimitAdded) Topic() common.Hash {
+ return common.HexToHash("0xfc23abf7ddbd3c02b1420dafa2355c56c1a06fbb8723862ac14d6bd74177361a")
+}
+
+func (EVM2EVMOffRampTokenAggregateRateLimitRemoved) Topic() common.Hash {
+ return common.HexToHash("0xcbf3cbeaed4ac1d605ed30f4af06c35acaeff2379db7f6146c9cceee83d58782")
+}
+
+func (EVM2EVMOffRampTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (EVM2EVMOffRampTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRamp) Address() common.Address {
+ return _EVM2EVMOffRamp.address
+}
+
+type EVM2EVMOffRampInterface interface {
+ CcipReceive(opts *bind.CallOpts, arg0 ClientAny2EVMMessage) error
+
+ CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error)
+
+ GetAllRateLimitTokens(opts *bind.CallOpts) (GetAllRateLimitTokens,
+
+ error)
+
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOffRampDynamicConfig, error)
+
+ GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error)
+
+ GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOffRampStaticConfig, error)
+
+ GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ExecuteSingleMessage(opts *bind.TransactOpts, message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error)
+
+ ManuallyExecute(opts *bind.TransactOpts, report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error)
+
+ SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error)
+
+ UpdateRateLimitTokens(opts *bind.TransactOpts, removes []EVM2EVMOffRampRateLimitToken, adds []EVM2EVMOffRampRateLimitToken) (*types.Transaction, error)
+
+ FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOffRampAdminSetIterator, error)
+
+ WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampAdminSet) (event.Subscription, error)
+
+ ParseAdminSet(log types.Log) (*EVM2EVMOffRampAdminSet, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*EVM2EVMOffRampConfigChanged, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMOffRampConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*EVM2EVMOffRampConfigSet0, error)
+
+ FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*EVM2EVMOffRampExecutionStateChangedIterator, error)
+
+ WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error)
+
+ ParseExecutionStateChanged(log types.Log) (*EVM2EVMOffRampExecutionStateChanged, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOffRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMOffRampOwnershipTransferred, error)
+
+ FilterSkippedAlreadyExecutedMessage(opts *bind.FilterOpts, sequenceNumber []uint64) (*EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator, error)
+
+ WatchSkippedAlreadyExecutedMessage(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedAlreadyExecutedMessage, sequenceNumber []uint64) (event.Subscription, error)
+
+ ParseSkippedAlreadyExecutedMessage(log types.Log) (*EVM2EVMOffRampSkippedAlreadyExecutedMessage, error)
+
+ FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedIncorrectNonceIterator, error)
+
+ WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error)
+
+ ParseSkippedIncorrectNonce(log types.Log) (*EVM2EVMOffRampSkippedIncorrectNonce, error)
+
+ FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)
+
+ WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error)
+
+ ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)
+
+ FilterTokenAggregateRateLimitAdded(opts *bind.FilterOpts) (*EVM2EVMOffRampTokenAggregateRateLimitAddedIterator, error)
+
+ WatchTokenAggregateRateLimitAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTokenAggregateRateLimitAdded) (event.Subscription, error)
+
+ ParseTokenAggregateRateLimitAdded(log types.Log) (*EVM2EVMOffRampTokenAggregateRateLimitAdded, error)
+
+ FilterTokenAggregateRateLimitRemoved(opts *bind.FilterOpts) (*EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator, error)
+
+ WatchTokenAggregateRateLimitRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTokenAggregateRateLimitRemoved) (event.Subscription, error)
+
+ ParseTokenAggregateRateLimitRemoved(log types.Log) (*EVM2EVMOffRampTokenAggregateRateLimitRemoved, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*EVM2EVMOffRampTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*EVM2EVMOffRampTokensConsumed, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*EVM2EVMOffRampTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*EVM2EVMOffRampTransmitted, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0/evm_2_evm_offramp_1_0_0.go b/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0/evm_2_evm_offramp_1_0_0.go
new file mode 100644
index 00000000000..3f140f8a3a5
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0/evm_2_evm_offramp_1_0_0.go
@@ -0,0 +1,2354 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_offramp_1_0_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMOffRampDynamicConfig struct {
+ PermissionLessExecutionThresholdSeconds uint32
+ Router common.Address
+ PriceRegistry common.Address
+ MaxTokensLength uint16
+ MaxDataSize uint32
+}
+
+type EVM2EVMOffRampStaticConfig struct {
+ CommitStore common.Address
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ PrevOffRamp common.Address
+ ArmProxy common.Address
+}
+
+type InternalEVM2EVMMessage struct {
+ SourceChainSelector uint64
+ SequenceNumber uint64
+ FeeTokenAmount *big.Int
+ Sender common.Address
+ Nonce uint64
+ GasLimit *big.Int
+ Strict bool
+ Receiver common.Address
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ MessageId [32]byte
+}
+
+type InternalExecutionReport struct {
+ Messages []InternalEVM2EVMMessage
+ OffchainTokenData [][][]byte
+ Proofs [][32]byte
+ ProofFlagBits *big.Int
+}
+
+type InternalPoolUpdate struct {
+ Token common.Address
+ Pool common.Address
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+var EVM2EVMOffRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"sourceTokens\",\"type\":\"address[]\"},{\"internalType\":\"contractIPool[]\",\"name\":\"pools\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"AlreadyAttempted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"AlreadyExecuted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CanOnlySelfCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitStoreAlreadyInUse\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyReport\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"error\",\"type\":\"bytes\"}],\"name\":\"ExecutionError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newLimit\",\"type\":\"uint256\"}],\"name\":\"InvalidManualExecutionGasLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMessageId\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"newState\",\"type\":\"uint8\"}],\"name\":\"InvalidNewState\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidSourceChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTokenPoolConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ManualExecutionGasLimitMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ManualExecutionNotYetEnabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PoolAlreadyAdded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PoolDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PriceNotFoundForToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"error\",\"type\":\"bytes\"}],\"name\":\"ReceiverError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootNotCommitted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"TokenDataMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"error\",\"type\":\"bytes\"}],\"name\":\"TokenHandlingError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenPoolMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"error\",\"type\":\"bytes\"}],\"name\":\"TokenRateLimitError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnexpectedTokenData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"UnsupportedToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOffRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"state\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"name\":\"ExecutionStateChanged\",\"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\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SkippedIncorrectNonce\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SkippedSenderWithPreviousRampMessageInflight\",\"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\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"removes\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"adds\",\"type\":\"tuple[]\"}],\"name\":\"applyPoolUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ccipReceive\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"internalType\":\"structInternal.EVM2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[]\"}],\"name\":\"executeSingleMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getDestinationToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDestinationTokens\",\"outputs\":[{\"internalType\":\"contractIERC20[]\",\"name\":\"destTokens\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOffRamp.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"getExecutionState\",\"outputs\":[{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"destToken\",\"type\":\"address\"}],\"name\":\"getPoolByDestToken\",\"outputs\":[{\"internalType\":\"contractIPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getPoolBySourceToken\",\"outputs\":[{\"internalType\":\"contractIPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getSenderNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedTokens\",\"outputs\":[{\"internalType\":\"contractIERC20[]\",\"name\":\"sourceTokens\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"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\":[{\"components\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"internalType\":\"structInternal.EVM2EVMMessage[]\",\"name\":\"messages\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[][]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[][]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.ExecutionReport\",\"name\":\"report\",\"type\":\"tuple\"},{\"internalType\":\"uint256[]\",\"name\":\"gasLimitOverrides\",\"type\":\"uint256[]\"}],\"name\":\"manuallyExecute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setRateLimiterConfig\",\"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\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x6101806040523480156200001257600080fd5b506040516200698638038062006986833981016040819052620000359162000891565b8033806000816200008d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c057620000c08162000478565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080938401819052600380546001600160a01b031916909517600160801b9384021760ff60a01b1916600160a01b90920291909117909355909102909217600455504690528151835114620001705760405162d8548360e71b815260040160405180910390fd5b60608401516001600160a01b0316158062000193575083516001600160a01b0316155b15620001b2576040516342bcdf7f60e11b815260040160405180910390fd5b83600001516001600160a01b0316634120fccd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200021b9190620009a8565b6001600160401b03166001146200024557604051636fc2a20760e11b815260040160405180910390fd5b83516001600160a01b0390811660a090815260408601516001600160401b0390811660c05260208701511660e052606086015182166101005260808601518216610140528501511661016052620002bc7fbdd59ac4dd1d82276c9a9c5d2656546346b9dcdb1f9b4204aed4ec15c23d7d3a62000523565b6101205260005b83518110156200046d576200031d848281518110620002e657620002e6620009c6565b6020026020010151848381518110620003035762000303620009c6565b6020026020010151600c6200058a60201b9092919060201c565b50620003d2838281518110620003375762000337620009c6565b60200260200101516001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200037d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003a39190620009dc565b848381518110620003b857620003b8620009c6565b6020026020010151600f6200058a60201b9092919060201c565b507f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c848281518110620004095762000409620009c6565b6020026020010151848381518110620004265762000426620009c6565b6020026020010151604051620004529291906001600160a01b0392831681529116602082015260400190565b60405180910390a1620004658162000a03565b9050620002c3565b505050505062000a2b565b336001600160a01b03821603620004d25760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000084565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008160c05160e051610100516040516020016200056d94939291909384526001600160401b039283166020850152911660408301526001600160a01b0316606082015260800190565b604051602081830303815290604052805190602001209050919050565b6000620005a2846001600160a01b03851684620005aa565b949350505050565b6000620005a284846001600160a01b03851660008281526002840160205260408120829055620005a284846000620005e38383620005ec565b90505b92915050565b60008181526001830160205260408120546200063557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620005e6565b506000620005e6565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b03811182821017156200067957620006796200063e565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620006aa57620006aa6200063e565b604052919050565b6001600160a01b0381168114620006c857600080fd5b50565b80516001600160401b0381168114620006e357600080fd5b919050565b60006001600160401b038211156200070457620007046200063e565b5060051b60200190565b600082601f8301126200072057600080fd5b81516020620007396200073383620006e8565b6200067f565b82815260059290921b840181019181810190868411156200075957600080fd5b8286015b84811015620007815780516200077381620006b2565b83529183019183016200075d565b509695505050505050565b600082601f8301126200079e57600080fd5b81516020620007b16200073383620006e8565b82815260059290921b84018101918181019086841115620007d157600080fd5b8286015b8481101562000781578051620007eb81620006b2565b8352918301918301620007d5565b80516001600160801b0381168114620006e357600080fd5b6000606082840312156200082457600080fd5b604051606081016001600160401b03811182821017156200084957620008496200063e565b8060405250809150825180151581146200086257600080fd5b81526200087260208401620007f9565b60208201526200088560408401620007f9565b60408201525092915050565b600080600080848603610160811215620008aa57600080fd5b60c0811215620008b957600080fd5b50620008c462000654565b8551620008d181620006b2565b8152620008e160208701620006cb565b6020820152620008f460408701620006cb565b604082015260608601516200090981620006b2565b606082015260808601516200091e81620006b2565b608082015260a08601516200093381620006b2565b60a082015260c08601519094506001600160401b03808211156200095657600080fd5b62000964888389016200070e565b945060e08701519150808211156200097b57600080fd5b506200098a878288016200078c565b9250506200099d86610100870162000811565b905092959194509250565b600060208284031215620009bb57600080fd5b620005e382620006cb565b634e487b7160e01b600052603260045260246000fd5b600060208284031215620009ef57600080fd5b8151620009fc81620006b2565b9392505050565b60006001820162000a2457634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a05160c05160e05161010051610120516101405161016051615e7e62000b0860003960008181610309015281816120ef0152612b0b0152600081816102cd015281816114a001528181611522015281816120c501528181613080015261310701526000612cc4015260008181610291015261209e015260008181610231015261204c01526000818161026101528181612076015281816124650152613a7c0152600081816101f50152818161201e0152612db901526000818161182f0152818161187b01528181611c8f0152611cdb0152615e7e6000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c806381ff7048116100ee578063b1dc65a411610097578063d3c7c2c711610071578063d3c7c2c7146106a7578063d7e2bb50146106af578063e65bf00a146106c2578063f2fde38b146106d557600080fd5b8063b1dc65a41461066e578063b4069b3114610681578063c92b28321461069457600080fd5b80638da5cb5b116100c85780638da5cb5b1461061d578063afa0d3791461063b578063afcb95d71461064e57600080fd5b806381ff7048146105b357806385572ffb146105e3578063856c8247146105f157600080fd5b8063599f64311161015b578063681fba1611610135578063681fba16146104b8578063704b6c02146104cd5780637437ff9f146104e057806379ba5097146105ab57600080fd5b8063599f6431146104515780635d86f14114610490578063666cab8d146104a357600080fd5b80631ef381741161018c5780631ef38174146103c55780633a87ac53146103da578063546719cd146103ed57600080fd5b806306285c69146101b3578063142a98fc1461035c578063181f5a771461037c575b600080fd5b6103466040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526040518060c001604052807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b60405161035391906145e8565b60405180910390f35b61036f61036a36600461467f565b6106e8565b6040516103539190614706565b6103b86040518060400160405280601481526020017f45564d3245564d4f666652616d7020312e302e3000000000000000000000000081525081565b6040516103539190614782565b6103d86103d33660046149f0565b610763565b005b6103d86103e8366004614b02565b610c22565b6103f5611032565b604051610353919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610353565b61046b61049e366004614b6e565b6110e7565b6104ab611150565b6040516103539190614bdc565b6104c06111bf565b6040516103539190614bef565b6103d86104db366004614b6e565b611278565b61059e6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a081018252600a5463ffffffff808216835273ffffffffffffffffffffffffffffffffffffffff64010000000090920482166020840152600b549182169383019390935261ffff7401000000000000000000000000000000000000000082041660608301527601000000000000000000000000000000000000000000009004909116608082015290565b6040516103539190614c49565b6103d8611368565b6007546005546040805163ffffffff80851682526401000000009094049093166020840152820152606001610353565b6103d86101ae366004614cac565b6106046105ff366004614b6e565b611465565b60405167ffffffffffffffff9091168152602001610353565b60005473ffffffffffffffffffffffffffffffffffffffff1661046b565b6103d8610649366004614f16565b61158d565b604080516001815260006020820181905291810191909152606001610353565b6103d861067c366004614fbf565b6117d9565b61046b61068f366004614b6e565b611a6a565b6103d86106a23660046150c4565b611b43565b6104c0611bc8565b61046b6106bd366004614b6e565b611c7d565b6103d86106d036600461531b565b611c8c565b6103d86106e3366004614b6e565b611e0e565b60006106f660016004615405565b6002610703608085615447565b67ffffffffffffffff16610717919061546e565b60136000610726608087615485565b67ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002054901c16600381111561075d5761075d61469c565b92915050565b84518460ff16601f8211156107d9576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f6f206d616e79207472616e736d697474657273000000000000000000000060448201526064015b60405180910390fd5b80600003610843576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016107d0565b61084b611e1f565b61085485611ea2565b60095460005b818110156108e0576008600060098381548110610879576108796154ac565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556108d9816154db565b905061085a565b50875160005b81811015610adc5760008a8281518110610902576109026154ac565b602002602001015190506000600281111561091f5761091f61469c565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020526040902054610100900460ff16600281111561095e5761095e61469c565b146109c5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016107d0565b73ffffffffffffffffffffffffffffffffffffffff8116610a12576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526008602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610ac257610ac261469c565b02179055509050505080610ad5906154db565b90506108e6565b508851610af09060099060208c0190614552565b506006805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908b161717905560078054610b76914691309190600090610b489063ffffffff16615513565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168d8d8d8d8d8d61214f565b6005600001819055506000600760049054906101000a900463ffffffff16905043600760046101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600560000154600760009054906101000a900463ffffffff168e8e8e8e8e8e604051610c0d99989796959493929190615536565b60405180910390a15050505050505050505050565b610c2a611e1f565b60005b83811015610e29576000858583818110610c4957610c496154ac565b610c5f9260206040909202019081019150614b6e565b90506000868684818110610c7557610c756154ac565b9050604002016020016020810190610c8d9190614b6e565b9050610c9a600c836121fa565b610cd0576040517f9c8787c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610cf2600c8461221c565b73ffffffffffffffffffffffffffffffffffffffff1614610d3f576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d4a600c8361223e565b50610dc58173ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbd91906155cc565b600f9061223e565b506040805173ffffffffffffffffffffffffffffffffffffffff8085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a1505080610e22906154db565b9050610c2d565b5060005b8181101561102b576000838383818110610e4957610e496154ac565b610e5f9260206040909202019081019150614b6e565b90506000848484818110610e7557610e756154ac565b9050604002016020016020810190610e8d9190614b6e565b905073ffffffffffffffffffffffffffffffffffffffff82161580610ec6575073ffffffffffffffffffffffffffffffffffffffff8116155b15610efd576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f08600c836121fa565b15610f3f576040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f4b600c8383612260565b50610fc78173ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbe91906155cc565b600f9083612260565b506040805173ffffffffffffffffffffffffffffffffffffffff8085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a1505080611024906154db565b9050610e2d565b5050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff1615159383019390935260045480841660608401520490911660808201526110e290612283565b905090565b600080806110f6600c85612335565b9150915081611149576040517fbf16aab600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016107d0565b9392505050565b606060098054806020026020016040519081016040528092919081815260200182805480156111b557602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161118a575b5050505050905090565b60606111cb600f612364565b67ffffffffffffffff8111156111e3576111e3614795565b60405190808252806020026020018201604052801561120c578160200160208202803683370190505b50905060005b8151811015611274576000611228600f8361236f565b5090508083838151811061123e5761123e6154ac565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101525061126d816154db565b9050611212565b5090565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906112b8575060025473ffffffffffffffffffffffffffffffffffffffff163314155b156112ef576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c9060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff1633146113e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107d0565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b73ffffffffffffffffffffffffffffffffffffffff811660009081526012602052604081205467ffffffffffffffff16801580156114d857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1615155b1561075d576040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611569573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114991906155e9565b3330146115c6576040517f371a732800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160008082526020820190925281611603565b60408051808201909152600080825260208201528152602001906001900390816115dc5790505b5061012084015151909150156116625761012083015160608401516040805173ffffffffffffffffffffffffffffffffffffffff909216602083015261165f9291016040516020818303038152906040528560e001518561238b565b90505b60e083015173ffffffffffffffffffffffffffffffffffffffff163b15806116cc575060e08301516116ca9073ffffffffffffffffffffffffffffffffffffffff167f85572ffb00000000000000000000000000000000000000000000000000000000612831565b155b156116d657505050565b600a546000908190640100000000900473ffffffffffffffffffffffffffffffffffffffff16633cf9798361170b878661284d565b6113888860a001518960e001516040518563ffffffff1660e01b81526004016117379493929190615657565b6000604051808303816000875af1158015611756573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261179c9190810190615729565b915091508161102b57806040517f0a8d6e8c0000000000000000000000000000000000000000000000000000000081526004016107d09190614782565b6117e387876128fd565b60055488359080821461182c576040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016107d0565b467f0000000000000000000000000000000000000000000000000000000000000000146118ad576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201526044016107d0565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a13360009081526008602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156119355761193561469c565b60028111156119465761194661469c565b90525090506002816020015160028111156119635761196361469c565b1480156119aa57506009816000015160ff1681548110611985576119856154ac565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6119e0576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060006119ee85602061546e565b6119f988602061546e565b611a058b6101446157b6565b611a0f91906157b6565b611a1991906157b6565b9050368114611a5d576040517f8e1192e1000000000000000000000000000000000000000000000000000000008152600481018290523660248201526044016107d0565b5050505050505050505050565b60008080611a79600c85612335565b9150915081611acc576040517fbf16aab600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016107d0565b8073ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3b91906155cc565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611b83575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15611bba576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bc5600382612924565b50565b6060611bd4600c612364565b67ffffffffffffffff811115611bec57611bec614795565b604051908082528060200260200182016040528015611c15578160200160208202803683370190505b50905060005b8151811015611274576000611c31600c8361236f565b50905080838381518110611c4757611c476154ac565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250611c76816154db565b9050611c1b565b600080806110f6600f85612335565b467f000000000000000000000000000000000000000000000000000000000000000014611d17576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600482015267ffffffffffffffff461660248201526044016107d0565b81515181518114611d54576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015611dfe576000838281518110611d7357611d736154ac565b6020026020010151905080600014158015611dac57508451805183908110611d9d57611d9d6154ac565b602002602001015160a0015181105b15611ded576040517f085e39cf00000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016107d0565b50611df7816154db565b9050611d57565b50611e098383612b09565b505050565b611e16611e1f565b611bc5816134b6565b60005473ffffffffffffffffffffffffffffffffffffffff163314611ea0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107d0565b565b600081806020019051810190611eb891906157dd565b602081015190915073ffffffffffffffffffffffffffffffffffffffff16611f0c576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600a805460208085015173ffffffffffffffffffffffffffffffffffffffff908116640100000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931663ffffffff9586161792909217909255604080850151600b80546060808901516080808b0151909916760100000000000000000000000000000000000000000000027fffffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffff61ffff90921674010000000000000000000000000000000000000000027fffffffffffffffffffff00000000000000000000000000000000000000000000909416958816959095179290921791909116929092179055815160c0810183527f00000000000000000000000000000000000000000000000000000000000000008416815267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116958201959095527f0000000000000000000000000000000000000000000000000000000000000000909416848301527f00000000000000000000000000000000000000000000000000000000000000008316908401527f00000000000000000000000000000000000000000000000000000000000000008216938301939093527f00000000000000000000000000000000000000000000000000000000000000001660a082015290517f737ef22d3f6615e342ed21c69e06620dbc5c8a261ed7cfb2ce214806b1f76eda91612143918490615878565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a60405160200161217399989796959493929190615947565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b60006111498373ffffffffffffffffffffffffffffffffffffffff84166135ab565b60006111498373ffffffffffffffffffffffffffffffffffffffff84166135b7565b60006111498373ffffffffffffffffffffffffffffffffffffffff84166135c3565b6000611b3b8473ffffffffffffffffffffffffffffffffffffffff8516846135cf565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261231182606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426122f59190615405565b85608001516fffffffffffffffffffffffffffffffff166135f2565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6000806123588473ffffffffffffffffffffffffffffffffffffffff8516613611565b915091505b9250929050565b600061075d82613620565b600080808061237e868661362b565b9097909650945050505050565b60606000855167ffffffffffffffff8111156123a9576123a9614795565b6040519080825280602002602001820160405280156123ee57816020015b60408051808201909152600080825260208201528152602001906001900390816123c75790505b50905060005b8651811015612803576000612425888381518110612414576124146154ac565b6020026020010151600001516110e7565b90508073ffffffffffffffffffffffffffffffffffffffff16638627fad688888b8681518110612457576124576154ac565b6020026020010151602001517f00000000000000000000000000000000000000000000000000000000000000008a8881518110612496576124966154ac565b60200260200101516040518663ffffffff1660e01b81526004016124be9594939291906159dc565b600060405180830381600087803b1580156124d857600080fd5b505af19250505080156124e9575060015b61270c573d808015612517576040519150601f19603f3d011682016040523d82523d6000602084013e61251c565b606091505b50600061252882615a3f565b90507f9725942a000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821614806125bb57507ff94ebcd1000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061260757507f15279c08000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061265357507f1a76572a000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b8061269f57507fd0c8d23a000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216145b156126d857816040517f30dabb590000000000000000000000000000000000000000000000000000000081526004016107d09190614782565b816040517fe1cd55090000000000000000000000000000000000000000000000000000000081526004016107d09190614782565b8073ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061277b91906155cc565b83838151811061278d5761278d6154ac565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff909116905287518890839081106127c6576127c66154ac565b6020026020010151602001518383815181106127e4576127e46154ac565b6020908102919091018101510152506127fc816154db565b90506123f4565b50600b5461282890829073ffffffffffffffffffffffffffffffffffffffff1661363a565b95945050505050565b600061283c8361381a565b80156111495750611149838361387e565b6040805160a08101825260008082526020820152606091810182905281810182905260808101919091526040518060a001604052808461016001518152602001846000015167ffffffffffffffff16815260200184606001516040516020016128d2919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6040516020818303038152906040528152602001846101000151815260200183815250905092915050565b61292061290c82840184615a8f565b604080516000815260208101909152612b09565b5050565b815460009061294d90700100000000000000000000000000000000900463ffffffff1642615405565b905080156129ef5760018301548354612995916fffffffffffffffffffffffffffffffff808216928116918591700100000000000000000000000000000000909104166135f2565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612a15916fffffffffffffffffffffffffffffffff908116911661394d565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990612afc9084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b989190615ac4565b15612bcf576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151516000819003612c0c576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260200151518114612c4a576040517f57e0e08300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff811115612c6557612c65614795565b604051908082528060200260200182016040528015612c8e578160200160208202803683370190505b50905060005b82811015612d6e57600085600001518281518110612cb457612cb46154ac565b60200260200101519050612ce8817f0000000000000000000000000000000000000000000000000000000000000000613963565b838381518110612cfa57612cfa6154ac565b602002602001018181525050806101600151838381518110612d1e57612d1e6154ac565b602002602001015114612d5d576040517f7185cf6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50612d67816154db565b9050612c94565b50604080850151606086015191517f3204887500000000000000000000000000000000000000000000000000000000815260009273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001692633204887592612def92879291600401615b11565b602060405180830381865afa158015612e0c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e309190615b47565b905080600003612e6c576040517fea75680100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351151560005b848110156134ad57600087600001518281518110612e9357612e936154ac565b602002602001015190506000612eac82602001516106e8565b90506000816003811115612ec257612ec261469c565b1480612edf57506003816003811115612edd57612edd61469c565b145b612f275760208201516040517f50a6e05200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b8315612fe457600a5460009063ffffffff16612f438742615405565b1190508080612f6357506003826003811115612f6157612f6161469c565b145b612f99576040517f6358b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b888481518110612fab57612fab6154ac565b6020026020010151600014612fde57888481518110612fcc57612fcc6154ac565b60200260200101518360a00181815250505b50613041565b6000816003811115612ff857612ff861469c565b146130415760208201516040517f67d9ba0f00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b606082015173ffffffffffffffffffffffffffffffffffffffff1660009081526012602052604090205467ffffffffffffffff16801580156130b857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1615155b1561325a5760608301516040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063856c824790602401602060405180830381865afa158015613150573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317491906155e9565b608084015190915067ffffffffffffffff16613191826001615b60565b67ffffffffffffffff16146131fe57826060015173ffffffffffffffffffffffffffffffffffffffff16836080015167ffffffffffffffff167fe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d60405160405180910390a350505061349d565b606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260126020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790555b600082600381111561326e5761326e61469c565b036132fa57608083015167ffffffffffffffff1661328d826001615b60565b67ffffffffffffffff16146132fa57826060015173ffffffffffffffffffffffffffffffffffffffff16836080015167ffffffffffffffff167fd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf4123760405160405180910390a350505061349d565b60008a602001518581518110613312576133126154ac565b60200260200101519050613327848251613a7a565b61333684602001516001613c50565b6000806133438684613cfa565b91509150613355866020015183613c50565b60038260038111156133695761336961469c565b14158015613389575060028260038111156133865761338661469c565b14155b156133c8578560200151826040517f9e2616030000000000000000000000000000000000000000000000000000000081526004016107d0929190615b81565b60008560038111156133dc576133dc61469c565b0361344857606086015173ffffffffffffffffffffffffffffffffffffffff166000908152601260205260408120805467ffffffffffffffff169161342083615b9f565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b856101600151866020015167ffffffffffffffff167fd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef65848460405161348e929190615bbc565b60405180910390a35050505050505b6134a6816154db565b9050612e73565b50505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107d0565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006111498383613e9d565b60006111498383613ea9565b60006111498383613f33565b6000611b3b848473ffffffffffffffffffffffffffffffffffffffff8516613f50565b600061282885613602848661546e565b61360c90876157b6565b61394d565b600080808061237e8686613f6d565b600061075d82613fa7565b600080808061237e8686613fb2565b81516000805b828110156138065760008473ffffffffffffffffffffffffffffffffffffffff1663d02641a0878481518110613678576136786154ac565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016040805180830381865afa1580156136ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137109190615bdc565b51905077ffffffffffffffffffffffffffffffffffffffffffffffff811660000361379e57858281518110613747576137476154ac565b6020908102919091010151516040517f9a655f7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016107d0565b6137e88683815181106137b3576137b36154ac565b6020026020010151602001518277ffffffffffffffffffffffffffffffffffffffffffffffff16613fdd90919063ffffffff16565b6137f290846157b6565b925050806137ff906154db565b9050613640565b506138146003826000614016565b50505050565b6000613846827f01ffc9a70000000000000000000000000000000000000000000000000000000061387e565b801561075d5750613877827fffffffff0000000000000000000000000000000000000000000000000000000061387e565b1592915050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d91506000519050828015613936575060208210155b80156139425750600081115b979650505050505050565b600081831061395c5781611149565b5090919050565b60008060001b828460200151856080015186606001518760e00151886101000151805190602001208961012001516040516020016139a19190615c3a565b604051602081830303815290604052805190602001208a60a001518b60c001518c61014001518d60400151604051602001613a5c9c9b9a999897969594939291909b8c5260208c019a909a5267ffffffffffffffff98891660408c01529690971660608a015273ffffffffffffffffffffffffffffffffffffffff94851660808a015292841660a089015260c088019190915260e0870152610100860152911515610120850152166101408301526101608201526101800190565b60405160208183030381529060405280519060200120905092915050565b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff16826000015167ffffffffffffffff1614613afa5781516040517f1279ec8a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b600b54610120830151517401000000000000000000000000000000000000000090910461ffff161015613b6b5760208201516040517f099d3f7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b808261012001515114613bbc5760208201516040517f8808f8e700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107d0565b600b546101008301515176010000000000000000000000000000000000000000000090910463ffffffff16101561292057600b54610100830151516040517f8693378900000000000000000000000000000000000000000000000000000000815276010000000000000000000000000000000000000000000090920463ffffffff16600483015260248201526044016107d0565b60006002613c5f608085615447565b67ffffffffffffffff16613c73919061546e565b90506000601381613c85608087615485565b67ffffffffffffffff168152602081019190915260400160002054905081613caf60016004615405565b901b191681836003811115613cc657613cc661469c565b901b178060136000613cd9608088615485565b67ffffffffffffffff16815260208101919091526040016000205550505050565b6040517fafa0d379000000000000000000000000000000000000000000000000000000008152600090606090309063afa0d37990613d3e9087908790600401615cc3565b600060405180830381600087803b158015613d5857600080fd5b505af1925050508015613d69575060015b613e82573d808015613d97576040519150601f19603f3d011682016040523d82523d6000602084013e613d9c565b606091505b50613da681615a3f565b7fffffffff00000000000000000000000000000000000000000000000000000000167f0a8d6e8c000000000000000000000000000000000000000000000000000000001480613e3e5750613df981615a3f565b7fffffffff00000000000000000000000000000000000000000000000000000000167fe1cd550900000000000000000000000000000000000000000000000000000000145b15613e4e5760039250905061235d565b806040517fcf19edfd0000000000000000000000000000000000000000000000000000000081526004016107d09190614782565b50506040805160208101909152600081526002909250929050565b60006111498383614399565b600081815260028301602052604081205480151580613ecd5750613ecd8484613e9d565b611149576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b6579000060448201526064016107d0565b6000818152600283016020526040812081905561114983836143b1565b60008281526002840160205260408120829055611b3b84846143bd565b6000818152600283016020526040812054819080613f9c57613f8f8585613e9d565b92506000915061235d9050565b60019250905061235d565b600061075d826143c9565b60008080613fc085856143d3565b600081815260029690960160205260409095205494959350505050565b6000670de0b6b3a764000061400c8377ffffffffffffffffffffffffffffffffffffffffffffffff861661546e565b6111499190615e2e565b825474010000000000000000000000000000000000000000900460ff16158061403d575081155b1561404757505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061408d90700100000000000000000000000000000000900463ffffffff1642615405565b9050801561414d57818311156140cf576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546141099083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166135f2565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156142045773ffffffffffffffffffffffffffffffffffffffff84166141ac576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016107d0565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff851660448201526064016107d0565b848310156143175760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906142489082615405565b614252878a615405565b61425c91906157b6565b6142669190615e2e565b905073ffffffffffffffffffffffffffffffffffffffff86166142bf576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016107d0565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff871660448201526064016107d0565b6143218584615405565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60008181526001830160205260408120541515611149565b600061114983836143df565b600061114983836144d9565b600061075d825490565b60006111498383614528565b600081815260018301602052604081205480156144c8576000614403600183615405565b855490915060009061441790600190615405565b905081811461447c576000866000018281548110614437576144376154ac565b906000526020600020015490508087600001848154811061445a5761445a6154ac565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061448d5761448d615e42565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061075d565b600091505061075d565b5092915050565b60008181526001830160205260408120546145205750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561075d565b50600061075d565b600082600001828154811061453f5761453f6154ac565b9060005260206000200154905092915050565b8280548282559060005260206000209081019282156145cc579160200282015b828111156145cc57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614572565b506112749291505b8082111561127457600081556001016145d4565b60c0810161075d828473ffffffffffffffffffffffffffffffffffffffff808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a0840152505050565b67ffffffffffffffff81168114611bc557600080fd5b803561467a81614659565b919050565b60006020828403121561469157600080fd5b813561114981614659565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60048110614702577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6020810161075d82846146cb565b60005b8381101561472f578181015183820152602001614717565b50506000910152565b60008151808452614750816020860160208601614714565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006111496020830184614738565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156147e7576147e7614795565b60405290565b604051610180810167ffffffffffffffff811182821017156147e7576147e7614795565b6040516080810167ffffffffffffffff811182821017156147e7576147e7614795565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561487b5761487b614795565b604052919050565b600067ffffffffffffffff82111561489d5761489d614795565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611bc557600080fd5b803561467a816148a7565b600082601f8301126148e557600080fd5b813560206148fa6148f583614883565b614834565b82815260059290921b8401810191818101908684111561491957600080fd5b8286015b8481101561493d578035614930816148a7565b835291830191830161491d565b509695505050505050565b803560ff8116811461467a57600080fd5b600067ffffffffffffffff82111561497357614973614795565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126149b057600080fd5b81356149be6148f582614959565b8181528460208386010111156149d357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c08789031215614a0957600080fd5b863567ffffffffffffffff80821115614a2157600080fd5b614a2d8a838b016148d4565b97506020890135915080821115614a4357600080fd5b614a4f8a838b016148d4565b9650614a5d60408a01614948565b95506060890135915080821115614a7357600080fd5b614a7f8a838b0161499f565b9450614a8d60808a0161466f565b935060a0890135915080821115614aa357600080fd5b50614ab089828a0161499f565b9150509295509295509295565b60008083601f840112614acf57600080fd5b50813567ffffffffffffffff811115614ae757600080fd5b6020830191508360208260061b850101111561235d57600080fd5b60008060008060408587031215614b1857600080fd5b843567ffffffffffffffff80821115614b3057600080fd5b614b3c88838901614abd565b90965094506020870135915080821115614b5557600080fd5b50614b6287828801614abd565b95989497509550505050565b600060208284031215614b8057600080fd5b8135611149816148a7565b600081518084526020808501945080840160005b83811015614bd157815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614b9f565b509495945050505050565b6020815260006111496020830184614b8b565b6020808252825182820181905260009190848201906040850190845b81811015614c3d57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614c0b565b50909695505050505050565b60a0810161075d828463ffffffff808251168352602082015173ffffffffffffffffffffffffffffffffffffffff8082166020860152806040850151166040860152505061ffff6060830151166060840152806080830151166080840152505050565b600060208284031215614cbe57600080fd5b813567ffffffffffffffff811115614cd557600080fd5b820160a0818503121561114957600080fd5b8015158114611bc557600080fd5b803561467a81614ce7565b600082601f830112614d1157600080fd5b81356020614d216148f583614883565b82815260069290921b84018101918181019086841115614d4057600080fd5b8286015b8481101561493d5760408189031215614d5d5760008081fd5b614d656147c4565b8135614d70816148a7565b81528185013585820152835291830191604001614d44565b60006101808284031215614d9b57600080fd5b614da36147ed565b9050614dae8261466f565b8152614dbc6020830161466f565b602082015260408201356040820152614dd7606083016148c9565b6060820152614de86080830161466f565b608082015260a082013560a0820152614e0360c08301614cf5565b60c0820152614e1460e083016148c9565b60e08201526101008083013567ffffffffffffffff80821115614e3657600080fd5b614e428683870161499f565b83850152610120925082850135915080821115614e5e57600080fd5b50614e6b85828601614d00565b828401525050610140614e7f8184016148c9565b818301525061016080830135818301525092915050565b600082601f830112614ea757600080fd5b81356020614eb76148f583614883565b82815260059290921b84018101918181019086841115614ed657600080fd5b8286015b8481101561493d57803567ffffffffffffffff811115614efa5760008081fd5b614f088986838b010161499f565b845250918301918301614eda565b60008060408385031215614f2957600080fd5b823567ffffffffffffffff80821115614f4157600080fd5b614f4d86838701614d88565b93506020850135915080821115614f6357600080fd5b50614f7085828601614e96565b9150509250929050565b60008083601f840112614f8c57600080fd5b50813567ffffffffffffffff811115614fa457600080fd5b6020830191508360208260051b850101111561235d57600080fd5b60008060008060008060008060e0898b031215614fdb57600080fd5b606089018a811115614fec57600080fd5b8998503567ffffffffffffffff8082111561500657600080fd5b818b0191508b601f83011261501a57600080fd5b81358181111561502957600080fd5b8c602082850101111561503b57600080fd5b6020830199508098505060808b013591508082111561505957600080fd5b6150658c838d01614f7a565b909750955060a08b013591508082111561507e57600080fd5b5061508b8b828c01614f7a565b999c989b50969995989497949560c00135949350505050565b80356fffffffffffffffffffffffffffffffff8116811461467a57600080fd5b6000606082840312156150d657600080fd5b6040516060810181811067ffffffffffffffff821117156150f9576150f9614795565b604052823561510781614ce7565b8152615115602084016150a4565b6020820152615126604084016150a4565b60408201529392505050565b600082601f83011261514357600080fd5b813560206151536148f583614883565b82815260059290921b8401810191818101908684111561517257600080fd5b8286015b8481101561493d57803567ffffffffffffffff8111156151965760008081fd5b6151a48986838b0101614e96565b845250918301918301615176565b600082601f8301126151c357600080fd5b813560206151d36148f583614883565b82815260059290921b840181019181810190868411156151f257600080fd5b8286015b8481101561493d57803583529183019183016151f6565b60006080828403121561521f57600080fd5b615227614811565b9050813567ffffffffffffffff8082111561524157600080fd5b818401915084601f83011261525557600080fd5b813560206152656148f583614883565b82815260059290921b8401810191818101908884111561528457600080fd5b8286015b848110156152bc578035868111156152a05760008081fd5b6152ae8b86838b0101614d88565b845250918301918301615288565b50865250858101359350828411156152d357600080fd5b6152df87858801615132565b908501525060408401359150808211156152f857600080fd5b50615305848285016151b2565b6040830152506060820135606082015292915050565b6000806040838503121561532e57600080fd5b823567ffffffffffffffff8082111561534657600080fd5b6153528683870161520d565b935060209150818501358181111561536957600080fd5b85019050601f8101861361537c57600080fd5b803561538a6148f582614883565b81815260059190911b820183019083810190888311156153a957600080fd5b928401925b828410156153c7578335825292840192908401906153ae565b80955050505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561075d5761075d6153d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff8084168061546257615462615418565b92169190910692915050565b808202811582820484141761075d5761075d6153d6565b600067ffffffffffffffff808416806154a0576154a0615418565b92169190910492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361550c5761550c6153d6565b5060010190565b600063ffffffff80831681810361552c5761552c6153d6565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526155668184018a614b8b565b9050828103608084015261557a8189614b8b565b905060ff871660a084015282810360c08401526155978187614738565b905067ffffffffffffffff851660e08401528281036101008401526155bc8185614738565b9c9b505050505050505050505050565b6000602082840312156155de57600080fd5b8151611149816148a7565b6000602082840312156155fb57600080fd5b815161114981614659565b600081518084526020808501945080840160005b83811015614bd1578151805173ffffffffffffffffffffffffffffffffffffffff168852830151838801526040909601959082019060010161561a565b608081528451608082015267ffffffffffffffff60208601511660a08201526000604086015160a060c0840152615692610120840182614738565b905060608701517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808584030160e08601526156ce8383614738565b9250608089015191508085840301610100860152506156ed8282615606565b92505050615701602083018661ffff169052565b836040830152612828606083018473ffffffffffffffffffffffffffffffffffffffff169052565b6000806040838503121561573c57600080fd5b825161574781614ce7565b602084015190925067ffffffffffffffff81111561576457600080fd5b8301601f8101851361577557600080fd5b80516157836148f582614959565b81815286602083850101111561579857600080fd5b6157a9826020830160208601614714565b8093505050509250929050565b8082018082111561075d5761075d6153d6565b805163ffffffff8116811461467a57600080fd5b600060a082840312156157ef57600080fd5b60405160a0810181811067ffffffffffffffff8211171561581257615812614795565b60405261581e836157c9565b8152602083015161582e816148a7565b60208201526040830151615841816148a7565b6040820152606083015161ffff8116811461585b57600080fd5b606082015261586c608084016157c9565b60808201529392505050565b61016081016158ea828573ffffffffffffffffffffffffffffffffffffffff808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a0840152505050565b825163ffffffff90811660c0840152602084015173ffffffffffffffffffffffffffffffffffffffff90811660e0850152604085015116610100840152606084015161ffff16610120840152608084015116610140830152611149565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b16604085015281606085015261598e8285018b614b8b565b915083820360808501526159a2828a614b8b565b915060ff881660a085015283820360c08501526159bf8288614738565b90861660e085015283810361010085015290506155bc8185614738565b60a0815260006159ef60a0830188614738565b73ffffffffffffffffffffffffffffffffffffffff8716602084015285604084015267ffffffffffffffff851660608401528281036080840152615a338185614738565b98975050505050505050565b6000815160208301517fffffffff0000000000000000000000000000000000000000000000000000000080821693506004831015615a875780818460040360031b1b83161693505b505050919050565b600060208284031215615aa157600080fd5b813567ffffffffffffffff811115615ab857600080fd5b611b3b8482850161520d565b600060208284031215615ad657600080fd5b815161114981614ce7565b600081518084526020808501945080840160005b83811015614bd157815187529582019590820190600101615af5565b606081526000615b246060830186615ae1565b8281036020840152615b368186615ae1565b915050826040830152949350505050565b600060208284031215615b5957600080fd5b5051919050565b67ffffffffffffffff8181168382160190808211156144d2576144d26153d6565b67ffffffffffffffff831681526040810161114960208301846146cb565b600067ffffffffffffffff80831681810361552c5761552c6153d6565b615bc681846146cb565b604060208201526000611b3b6040830184614738565b600060408284031215615bee57600080fd5b615bf66147c4565b825177ffffffffffffffffffffffffffffffffffffffffffffffff81168114615c1e57600080fd5b81526020830151615c2e81614659565b60208201529392505050565b6020815260006111496020830184615606565b600082825180855260208086019550808260051b84010181860160005b84811015615cb6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018952615ca4838351614738565b98840198925090830190600101615c6a565b5090979650505050505050565b60408152615cde60408201845167ffffffffffffffff169052565b60006020840151615cfb606084018267ffffffffffffffff169052565b5060408401516080830152606084015173ffffffffffffffffffffffffffffffffffffffff811660a084015250608084015167ffffffffffffffff811660c08401525060a084015160e083015260c0840151610100615d5d8185018315159052565b60e08601519150610120615d888186018473ffffffffffffffffffffffffffffffffffffffff169052565b81870151925061018091506101408281870152615da96101c0870185614738565b93508188015191506101607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030181880152615de78584615606565b9450818901519250615e108488018473ffffffffffffffffffffffffffffffffffffffff169052565b8801516101a087015250505082810360208401526128288185615c4d565b600082615e3d57615e3d615418565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a",
+}
+
+var EVM2EVMOffRampABI = EVM2EVMOffRampMetaData.ABI
+
+var EVM2EVMOffRampBin = EVM2EVMOffRampMetaData.Bin
+
+func DeployEVM2EVMOffRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMOffRampStaticConfig, sourceTokens []common.Address, pools []common.Address, rateLimiterConfig RateLimiterConfig) (common.Address, *types.Transaction, *EVM2EVMOffRamp, error) {
+ parsed, err := EVM2EVMOffRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMOffRampBin), backend, staticConfig, sourceTokens, pools, rateLimiterConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMOffRamp{EVM2EVMOffRampCaller: EVM2EVMOffRampCaller{contract: contract}, EVM2EVMOffRampTransactor: EVM2EVMOffRampTransactor{contract: contract}, EVM2EVMOffRampFilterer: EVM2EVMOffRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMOffRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMOffRampCaller
+ EVM2EVMOffRampTransactor
+ EVM2EVMOffRampFilterer
+}
+
+type EVM2EVMOffRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampSession struct {
+ Contract *EVM2EVMOffRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOffRampCallerSession struct {
+ Contract *EVM2EVMOffRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMOffRampTransactorSession struct {
+ Contract *EVM2EVMOffRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOffRampRaw struct {
+ Contract *EVM2EVMOffRamp
+}
+
+type EVM2EVMOffRampCallerRaw struct {
+ Contract *EVM2EVMOffRampCaller
+}
+
+type EVM2EVMOffRampTransactorRaw struct {
+ Contract *EVM2EVMOffRampTransactor
+}
+
+func NewEVM2EVMOffRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMOffRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMOffRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMOffRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRamp{address: address, abi: abi, EVM2EVMOffRampCaller: EVM2EVMOffRampCaller{contract: contract}, EVM2EVMOffRampTransactor: EVM2EVMOffRampTransactor{contract: contract}, EVM2EVMOffRampFilterer: EVM2EVMOffRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMOffRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMOffRampCaller, error) {
+ contract, err := bindEVM2EVMOffRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMOffRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMOffRampTransactor, error) {
+ contract, err := bindEVM2EVMOffRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMOffRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMOffRampFilterer, error) {
+ contract, err := bindEVM2EVMOffRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMOffRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMOffRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOffRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) CcipReceive(opts *bind.CallOpts, arg0 ClientAny2EVMMessage) error {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "ccipReceive", arg0)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) CcipReceive(arg0 ClientAny2EVMMessage) error {
+ return _EVM2EVMOffRamp.Contract.CcipReceive(&_EVM2EVMOffRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) CcipReceive(arg0 ClientAny2EVMMessage) error {
+ return _EVM2EVMOffRamp.Contract.CcipReceive(&_EVM2EVMOffRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "currentRateLimiterState")
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOffRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOffRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetDestinationToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getDestinationToken", sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetDestinationToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetDestinationToken(&_EVM2EVMOffRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetDestinationToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetDestinationToken(&_EVM2EVMOffRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetDestinationTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getDestinationTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetDestinationTokens() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetDestinationTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetDestinationTokens() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetDestinationTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOffRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOffRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOffRampDynamicConfig)).(*EVM2EVMOffRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetDynamicConfig() (EVM2EVMOffRampDynamicConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetDynamicConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetDynamicConfig() (EVM2EVMOffRampDynamicConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetDynamicConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getExecutionState", sequenceNumber)
+
+ if err != nil {
+ return *new(uint8), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetExecutionState(sequenceNumber uint64) (uint8, error) {
+ return _EVM2EVMOffRamp.Contract.GetExecutionState(&_EVM2EVMOffRamp.CallOpts, sequenceNumber)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetExecutionState(sequenceNumber uint64) (uint8, error) {
+ return _EVM2EVMOffRamp.Contract.GetExecutionState(&_EVM2EVMOffRamp.CallOpts, sequenceNumber)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetPoolByDestToken(opts *bind.CallOpts, destToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getPoolByDestToken", destToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetPoolByDestToken(destToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetPoolByDestToken(&_EVM2EVMOffRamp.CallOpts, destToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetPoolByDestToken(destToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetPoolByDestToken(&_EVM2EVMOffRamp.CallOpts, destToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getPoolBySourceToken", sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetPoolBySourceToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOffRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetPoolBySourceToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOffRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getSenderNonce", sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOffRamp.Contract.GetSenderNonce(&_EVM2EVMOffRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOffRamp.Contract.GetSenderNonce(&_EVM2EVMOffRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOffRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOffRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOffRampStaticConfig)).(*EVM2EVMOffRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetStaticConfig() (EVM2EVMOffRampStaticConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetStaticConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetStaticConfig() (EVM2EVMOffRampStaticConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetStaticConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getSupportedTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetSupportedTokens() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetSupportedTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetSupportedTokens() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetSupportedTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getTokenLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetTransmitters() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTransmitters(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTransmitters(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDetails(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDetails(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDigestAndEpoch(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDigestAndEpoch(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.Owner(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.Owner(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOffRamp.Contract.TypeAndVersion(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOffRamp.Contract.TypeAndVersion(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.AcceptOwnership(&_EVM2EVMOffRamp.TransactOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.AcceptOwnership(&_EVM2EVMOffRamp.TransactOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "applyPoolUpdates", removes, adds)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOffRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOffRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) ExecuteSingleMessage(opts *bind.TransactOpts, message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "executeSingleMessage", message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) ExecuteSingleMessage(message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ExecuteSingleMessage(&_EVM2EVMOffRamp.TransactOpts, message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) ExecuteSingleMessage(message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ExecuteSingleMessage(&_EVM2EVMOffRamp.TransactOpts, message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) ManuallyExecute(opts *bind.TransactOpts, report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "manuallyExecute", report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) ManuallyExecute(report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ManuallyExecute(&_EVM2EVMOffRamp.TransactOpts, report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) ManuallyExecute(report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ManuallyExecute(&_EVM2EVMOffRamp.TransactOpts, report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setAdmin", newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetAdmin(&_EVM2EVMOffRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetAdmin(&_EVM2EVMOffRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetOCR2Config(&_EVM2EVMOffRamp.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetOCR2Config(&_EVM2EVMOffRamp.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setRateLimiterConfig", config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOffRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOffRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.TransferOwnership(&_EVM2EVMOffRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.TransferOwnership(&_EVM2EVMOffRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "transmit", reportContext, report, rs, ss, arg4)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.Transmit(&_EVM2EVMOffRamp.TransactOpts, reportContext, report, rs, ss, arg4)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.Transmit(&_EVM2EVMOffRamp.TransactOpts, reportContext, report, rs, ss, arg4)
+}
+
+type EVM2EVMOffRampAdminSetIterator struct {
+ Event *EVM2EVMOffRampAdminSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampAdminSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampAdminSet)
+ 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(EVM2EVMOffRampAdminSet)
+ 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 *EVM2EVMOffRampAdminSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampAdminSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampAdminSet struct {
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOffRampAdminSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampAdminSetIterator{contract: _EVM2EVMOffRamp.contract, event: "AdminSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampAdminSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampAdminSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "AdminSet", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseAdminSet(log types.Log) (*EVM2EVMOffRampAdminSet, error) {
+ event := new(EVM2EVMOffRampAdminSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "AdminSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampConfigSetIterator struct {
+ Event *EVM2EVMOffRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampConfigSet)
+ 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(EVM2EVMOffRampConfigSet)
+ 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 *EVM2EVMOffRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampConfigSet struct {
+ StaticConfig EVM2EVMOffRampStaticConfig
+ DynamicConfig EVM2EVMOffRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampConfigSetIterator{contract: _EVM2EVMOffRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampConfigSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMOffRampConfigSet, error) {
+ event := new(EVM2EVMOffRampConfigSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampConfigSet0Iterator struct {
+ Event *EVM2EVMOffRampConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampConfigSet0)
+ 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(EVM2EVMOffRampConfigSet0)
+ 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 *EVM2EVMOffRampConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSet0Iterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampConfigSet0Iterator{contract: _EVM2EVMOffRamp.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampConfigSet0)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet0", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseConfigSet0(log types.Log) (*EVM2EVMOffRampConfigSet0, error) {
+ event := new(EVM2EVMOffRampConfigSet0)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampExecutionStateChangedIterator struct {
+ Event *EVM2EVMOffRampExecutionStateChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampExecutionStateChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampExecutionStateChanged)
+ 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(EVM2EVMOffRampExecutionStateChanged)
+ 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 *EVM2EVMOffRampExecutionStateChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampExecutionStateChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampExecutionStateChanged struct {
+ SequenceNumber uint64
+ MessageId [32]byte
+ State uint8
+ ReturnData []byte
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*EVM2EVMOffRampExecutionStateChangedIterator, error) {
+
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ExecutionStateChanged", sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampExecutionStateChangedIterator{contract: _EVM2EVMOffRamp.contract, event: "ExecutionStateChanged", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) {
+
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ExecutionStateChanged", sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampExecutionStateChanged)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ExecutionStateChanged", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseExecutionStateChanged(log types.Log) (*EVM2EVMOffRampExecutionStateChanged, error) {
+ event := new(EVM2EVMOffRampExecutionStateChanged)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ExecutionStateChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMOffRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampOwnershipTransferRequested)
+ 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(EVM2EVMOffRampOwnershipTransferRequested)
+ 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 *EVM2EVMOffRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampOwnershipTransferRequestedIterator{contract: _EVM2EVMOffRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampOwnershipTransferRequested)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOffRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMOffRampOwnershipTransferRequested)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMOffRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampOwnershipTransferred)
+ 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(EVM2EVMOffRampOwnershipTransferred)
+ 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 *EVM2EVMOffRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampOwnershipTransferredIterator{contract: _EVM2EVMOffRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampOwnershipTransferred)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMOffRampOwnershipTransferred, error) {
+ event := new(EVM2EVMOffRampOwnershipTransferred)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampPoolAddedIterator struct {
+ Event *EVM2EVMOffRampPoolAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampPoolAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampPoolAdded)
+ 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(EVM2EVMOffRampPoolAdded)
+ 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 *EVM2EVMOffRampPoolAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampPoolAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampPoolAdded struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOffRampPoolAddedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampPoolAddedIterator{contract: _EVM2EVMOffRamp.contract, event: "PoolAdded", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampPoolAdded) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampPoolAdded)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "PoolAdded", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParsePoolAdded(log types.Log) (*EVM2EVMOffRampPoolAdded, error) {
+ event := new(EVM2EVMOffRampPoolAdded)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "PoolAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampPoolRemovedIterator struct {
+ Event *EVM2EVMOffRampPoolRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampPoolRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampPoolRemoved)
+ 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(EVM2EVMOffRampPoolRemoved)
+ 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 *EVM2EVMOffRampPoolRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampPoolRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampPoolRemoved struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOffRampPoolRemovedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampPoolRemovedIterator{contract: _EVM2EVMOffRamp.contract, event: "PoolRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampPoolRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampPoolRemoved)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "PoolRemoved", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParsePoolRemoved(log types.Log) (*EVM2EVMOffRampPoolRemoved, error) {
+ event := new(EVM2EVMOffRampPoolRemoved)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "PoolRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampSkippedIncorrectNonceIterator struct {
+ Event *EVM2EVMOffRampSkippedIncorrectNonce
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampSkippedIncorrectNonceIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampSkippedIncorrectNonce)
+ 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(EVM2EVMOffRampSkippedIncorrectNonce)
+ 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 *EVM2EVMOffRampSkippedIncorrectNonceIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampSkippedIncorrectNonceIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampSkippedIncorrectNonce struct {
+ Nonce uint64
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedIncorrectNonceIterator, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "SkippedIncorrectNonce", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampSkippedIncorrectNonceIterator{contract: _EVM2EVMOffRamp.contract, event: "SkippedIncorrectNonce", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "SkippedIncorrectNonce", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampSkippedIncorrectNonce)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedIncorrectNonce", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseSkippedIncorrectNonce(log types.Log) (*EVM2EVMOffRampSkippedIncorrectNonce, error) {
+ event := new(EVM2EVMOffRampSkippedIncorrectNonce)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedIncorrectNonce", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator struct {
+ Event *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ 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(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ 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 *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight struct {
+ Nonce uint64
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "SkippedSenderWithPreviousRampMessageInflight", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator{contract: _EVM2EVMOffRamp.contract, event: "SkippedSenderWithPreviousRampMessageInflight", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "SkippedSenderWithPreviousRampMessageInflight", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedSenderWithPreviousRampMessageInflight", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error) {
+ event := new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedSenderWithPreviousRampMessageInflight", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampTransmittedIterator struct {
+ Event *EVM2EVMOffRampTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampTransmitted)
+ 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(EVM2EVMOffRampTransmitted)
+ 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 *EVM2EVMOffRampTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterTransmitted(opts *bind.FilterOpts) (*EVM2EVMOffRampTransmittedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTransmittedIterator{contract: _EVM2EVMOffRamp.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampTransmitted)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "Transmitted", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseTransmitted(log types.Log) (*EVM2EVMOffRampTransmitted, error) {
+ event := new(EVM2EVMOffRampTransmitted)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMOffRamp.abi.Events["AdminSet"].ID:
+ return _EVM2EVMOffRamp.ParseAdminSet(log)
+ case _EVM2EVMOffRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMOffRamp.ParseConfigSet(log)
+ case _EVM2EVMOffRamp.abi.Events["ConfigSet0"].ID:
+ return _EVM2EVMOffRamp.ParseConfigSet0(log)
+ case _EVM2EVMOffRamp.abi.Events["ExecutionStateChanged"].ID:
+ return _EVM2EVMOffRamp.ParseExecutionStateChanged(log)
+ case _EVM2EVMOffRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMOffRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMOffRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMOffRamp.ParseOwnershipTransferred(log)
+ case _EVM2EVMOffRamp.abi.Events["PoolAdded"].ID:
+ return _EVM2EVMOffRamp.ParsePoolAdded(log)
+ case _EVM2EVMOffRamp.abi.Events["PoolRemoved"].ID:
+ return _EVM2EVMOffRamp.ParsePoolRemoved(log)
+ case _EVM2EVMOffRamp.abi.Events["SkippedIncorrectNonce"].ID:
+ return _EVM2EVMOffRamp.ParseSkippedIncorrectNonce(log)
+ case _EVM2EVMOffRamp.abi.Events["SkippedSenderWithPreviousRampMessageInflight"].ID:
+ return _EVM2EVMOffRamp.ParseSkippedSenderWithPreviousRampMessageInflight(log)
+ case _EVM2EVMOffRamp.abi.Events["Transmitted"].ID:
+ return _EVM2EVMOffRamp.ParseTransmitted(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMOffRampAdminSet) Topic() common.Hash {
+ return common.HexToHash("0x8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c")
+}
+
+func (EVM2EVMOffRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x737ef22d3f6615e342ed21c69e06620dbc5c8a261ed7cfb2ce214806b1f76eda")
+}
+
+func (EVM2EVMOffRampConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (EVM2EVMOffRampExecutionStateChanged) Topic() common.Hash {
+ return common.HexToHash("0xd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef65")
+}
+
+func (EVM2EVMOffRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMOffRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (EVM2EVMOffRampPoolAdded) Topic() common.Hash {
+ return common.HexToHash("0x95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c")
+}
+
+func (EVM2EVMOffRampPoolRemoved) Topic() common.Hash {
+ return common.HexToHash("0x987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c")
+}
+
+func (EVM2EVMOffRampSkippedIncorrectNonce) Topic() common.Hash {
+ return common.HexToHash("0xd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf41237")
+}
+
+func (EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight) Topic() common.Hash {
+ return common.HexToHash("0xe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d")
+}
+
+func (EVM2EVMOffRampTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRamp) Address() common.Address {
+ return _EVM2EVMOffRamp.address
+}
+
+type EVM2EVMOffRampInterface interface {
+ CcipReceive(opts *bind.CallOpts, arg0 ClientAny2EVMMessage) error
+
+ CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error)
+
+ GetDestinationToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error)
+
+ GetDestinationTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOffRampDynamicConfig, error)
+
+ GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error)
+
+ GetPoolByDestToken(opts *bind.CallOpts, destToken common.Address) (common.Address, error)
+
+ GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error)
+
+ GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOffRampStaticConfig, error)
+
+ GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error)
+
+ ExecuteSingleMessage(opts *bind.TransactOpts, message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error)
+
+ ManuallyExecute(opts *bind.TransactOpts, report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error)
+
+ SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error)
+
+ FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOffRampAdminSetIterator, error)
+
+ WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampAdminSet) (event.Subscription, error)
+
+ ParseAdminSet(log types.Log) (*EVM2EVMOffRampAdminSet, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMOffRampConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*EVM2EVMOffRampConfigSet0, error)
+
+ FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*EVM2EVMOffRampExecutionStateChangedIterator, error)
+
+ WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error)
+
+ ParseExecutionStateChanged(log types.Log) (*EVM2EVMOffRampExecutionStateChanged, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOffRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMOffRampOwnershipTransferred, error)
+
+ FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOffRampPoolAddedIterator, error)
+
+ WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampPoolAdded) (event.Subscription, error)
+
+ ParsePoolAdded(log types.Log) (*EVM2EVMOffRampPoolAdded, error)
+
+ FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOffRampPoolRemovedIterator, error)
+
+ WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampPoolRemoved) (event.Subscription, error)
+
+ ParsePoolRemoved(log types.Log) (*EVM2EVMOffRampPoolRemoved, error)
+
+ FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedIncorrectNonceIterator, error)
+
+ WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error)
+
+ ParseSkippedIncorrectNonce(log types.Log) (*EVM2EVMOffRampSkippedIncorrectNonce, error)
+
+ FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)
+
+ WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error)
+
+ ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*EVM2EVMOffRampTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*EVM2EVMOffRampTransmitted, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0/evm_2_evm_offramp_1_2_0.go b/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0/evm_2_evm_offramp_1_2_0.go
new file mode 100644
index 00000000000..beeaee1bb76
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0/evm_2_evm_offramp_1_2_0.go
@@ -0,0 +1,2356 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_offramp_1_2_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMOffRampDynamicConfig struct {
+ PermissionLessExecutionThresholdSeconds uint32
+ Router common.Address
+ PriceRegistry common.Address
+ MaxNumberOfTokensPerMsg uint16
+ MaxDataBytes uint32
+ MaxPoolReleaseOrMintGas uint32
+}
+
+type EVM2EVMOffRampStaticConfig struct {
+ CommitStore common.Address
+ ChainSelector uint64
+ SourceChainSelector uint64
+ OnRamp common.Address
+ PrevOffRamp common.Address
+ ArmProxy common.Address
+}
+
+type InternalEVM2EVMMessage struct {
+ SourceChainSelector uint64
+ Sender common.Address
+ Receiver common.Address
+ SequenceNumber uint64
+ GasLimit *big.Int
+ Strict bool
+ Nonce uint64
+ FeeToken common.Address
+ FeeTokenAmount *big.Int
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ SourceTokenData [][]byte
+ MessageId [32]byte
+}
+
+type InternalExecutionReport struct {
+ Messages []InternalEVM2EVMMessage
+ OffchainTokenData [][][]byte
+ Proofs [][32]byte
+ ProofFlagBits *big.Int
+}
+
+type InternalPoolUpdate struct {
+ Token common.Address
+ Pool common.Address
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+var EVM2EVMOffRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"internalType\":\"contractIERC20[]\",\"name\":\"sourceTokens\",\"type\":\"address[]\"},{\"internalType\":\"contractIPool[]\",\"name\":\"pools\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"AlreadyAttempted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"AlreadyExecuted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CanOnlySelfCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CommitStoreAlreadyInUse\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyReport\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"error\",\"type\":\"bytes\"}],\"name\":\"ExecutionError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newLimit\",\"type\":\"uint256\"}],\"name\":\"InvalidManualExecutionGasLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMessageId\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"newState\",\"type\":\"uint8\"}],\"name\":\"InvalidNewState\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidSourceChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTokenPoolConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ManualExecutionGasLimitMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ManualExecutionNotYetEnabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PoolAlreadyAdded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PoolDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PriceNotFoundForToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"error\",\"type\":\"bytes\"}],\"name\":\"ReceiverError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RootNotCommitted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"TokenDataMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"error\",\"type\":\"bytes\"}],\"name\":\"TokenHandlingError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenPoolMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnexpectedTokenData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"UnsupportedToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPoolReleaseOrMintGas\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOffRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"state\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"name\":\"ExecutionStateChanged\",\"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\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SkippedIncorrectNonce\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SkippedSenderWithPreviousRampMessageInflight\",\"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\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"removes\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"adds\",\"type\":\"tuple[]\"}],\"name\":\"applyPoolUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ccipReceive\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[]\",\"name\":\"sourceTokenData\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"internalType\":\"structInternal.EVM2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[]\"}],\"name\":\"executeSingleMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getDestinationToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDestinationTokens\",\"outputs\":[{\"internalType\":\"contractIERC20[]\",\"name\":\"destTokens\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"permissionLessExecutionThresholdSeconds\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPoolReleaseOrMintGas\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOffRamp.DynamicConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"getExecutionState\",\"outputs\":[{\"internalType\":\"enumInternal.MessageExecutionState\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"destToken\",\"type\":\"address\"}],\"name\":\"getPoolByDestToken\",\"outputs\":[{\"internalType\":\"contractIPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getPoolBySourceToken\",\"outputs\":[{\"internalType\":\"contractIPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getSenderNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOffRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedTokens\",\"outputs\":[{\"internalType\":\"contractIERC20[]\",\"name\":\"sourceTokens\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"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\":[{\"components\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[]\",\"name\":\"sourceTokenData\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"internalType\":\"structInternal.EVM2EVMMessage[]\",\"name\":\"messages\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[][]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[][]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.ExecutionReport\",\"name\":\"report\",\"type\":\"tuple\"},{\"internalType\":\"uint256[]\",\"name\":\"gasLimitOverrides\",\"type\":\"uint256[]\"}],\"name\":\"manuallyExecute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR2Config\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setRateLimiterConfig\",\"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\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x6101806040523480156200001257600080fd5b5060405162006ac338038062006ac3833981016040819052620000359162000891565b8033806000816200008d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c057620000c08162000478565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080938401819052600380546001600160a01b031916909517600160801b9384021760ff60a01b1916600160a01b90920291909117909355909102909217600455504690528151835114620001705760405162d8548360e71b815260040160405180910390fd5b60608401516001600160a01b0316158062000193575083516001600160a01b0316155b15620001b2576040516342bcdf7f60e11b815260040160405180910390fd5b83600001516001600160a01b0316634120fccd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200021b9190620009a8565b6001600160401b03166001146200024557604051636fc2a20760e11b815260040160405180910390fd5b83516001600160a01b0390811660a090815260408601516001600160401b0390811660c05260208701511660e052606086015182166101005260808601518216610140528501511661016052620002bc7f8acd72527118c8324937b1a42e02cd246697c3b633f1742f3cae11de233722b362000523565b6101205260005b83518110156200046d576200031d848281518110620002e657620002e6620009c6565b6020026020010151848381518110620003035762000303620009c6565b6020026020010151600c6200058a60201b9092919060201c565b50620003d2838281518110620003375762000337620009c6565b60200260200101516001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200037d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003a39190620009dc565b848381518110620003b857620003b8620009c6565b6020026020010151600f6200058a60201b9092919060201c565b507f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c848281518110620004095762000409620009c6565b6020026020010151848381518110620004265762000426620009c6565b6020026020010151604051620004529291906001600160a01b0392831681529116602082015260400190565b60405180910390a1620004658162000a03565b9050620002c3565b505050505062000a2b565b336001600160a01b03821603620004d25760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000084565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008160c05160e051610100516040516020016200056d94939291909384526001600160401b039283166020850152911660408301526001600160a01b0316606082015260800190565b604051602081830303815290604052805190602001209050919050565b6000620005a2846001600160a01b03851684620005aa565b949350505050565b6000620005a284846001600160a01b03851660008281526002840160205260408120829055620005a284846000620005e38383620005ec565b90505b92915050565b60008181526001830160205260408120546200063557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620005e6565b506000620005e6565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b03811182821017156200067957620006796200063e565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620006aa57620006aa6200063e565b604052919050565b6001600160a01b0381168114620006c857600080fd5b50565b80516001600160401b0381168114620006e357600080fd5b919050565b60006001600160401b038211156200070457620007046200063e565b5060051b60200190565b600082601f8301126200072057600080fd5b81516020620007396200073383620006e8565b6200067f565b82815260059290921b840181019181810190868411156200075957600080fd5b8286015b84811015620007815780516200077381620006b2565b83529183019183016200075d565b509695505050505050565b600082601f8301126200079e57600080fd5b81516020620007b16200073383620006e8565b82815260059290921b84018101918181019086841115620007d157600080fd5b8286015b8481101562000781578051620007eb81620006b2565b8352918301918301620007d5565b80516001600160801b0381168114620006e357600080fd5b6000606082840312156200082457600080fd5b604051606081016001600160401b03811182821017156200084957620008496200063e565b8060405250809150825180151581146200086257600080fd5b81526200087260208401620007f9565b60208201526200088560408401620007f9565b60408201525092915050565b600080600080848603610160811215620008aa57600080fd5b60c0811215620008b957600080fd5b50620008c462000654565b8551620008d181620006b2565b8152620008e160208701620006cb565b6020820152620008f460408701620006cb565b604082015260608601516200090981620006b2565b606082015260808601516200091e81620006b2565b608082015260a08601516200093381620006b2565b60a082015260c08601519094506001600160401b03808211156200095657600080fd5b62000964888389016200070e565b945060e08701519150808211156200097b57600080fd5b506200098a878288016200078c565b9250506200099d86610100870162000811565b905092959194509250565b600060208284031215620009bb57600080fd5b620005e382620006cb565b634e487b7160e01b600052603260045260246000fd5b600060208284031215620009ef57600080fd5b8151620009fc81620006b2565b9392505050565b60006001820162000a2457634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a05160c05160e05161010051610120516101405161016051615fbb62000b08600039600081816103090152818161211a01526123c40152600081816102cd0152818161164e015281816116d0015281816120f30152818161293a01526129c10152600061257d01526000818161029101526120c90152600081816102310152612077015260008181610261015281816120a10152818161315b01526136f80152600081816101f5015281816120490152612672015260008181611397015281816113e30152818161179101526117dd0152615fbb6000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c806379ba5097116100ee578063b1dc65a411610097578063d3c7c2c711610071578063d3c7c2c7146106d3578063d7e2bb50146106db578063f2fde38b146106ee578063f52121a51461070157600080fd5b8063b1dc65a41461069a578063b4069b31146106ad578063c92b2832146106c057600080fd5b8063856c8247116100c8578063856c8247146106305780638da5cb5b1461065c578063afcb95d71461067a57600080fd5b806379ba5097146105ea57806381ff7048146105f257806385572ffb1461062257600080fd5b8063599f64311161015b578063681fba1611610135578063681fba16146104b8578063704b6c02146104cd578063740f4150146104e05780637437ff9f146104f357600080fd5b8063599f6431146104515780635d86f14114610490578063666cab8d146104a357600080fd5b80631ef381741161018c5780631ef38174146103c55780633a87ac53146103da578063546719cd146103ed57600080fd5b806306285c69146101b3578063142a98fc1461035c578063181f5a771461037c575b600080fd5b6103466040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526040518060c001604052807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815250905090565b6040516103539190614693565b60405180910390f35b61036f61036a36600461472a565b610714565b60405161035391906147b1565b6103b86040518060400160405280601481526020017f45564d3245564d4f666652616d7020312e322e3000000000000000000000000081525081565b604051610353919061482d565b6103d86103d3366004614a9b565b61078f565b005b6103d86103e8366004614bad565b610c4e565b6103f561105e565b604051610353919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610353565b61046b61049e366004614c19565b611113565b6104ab61117c565b6040516103539190614c87565b6104c06111eb565b6040516103539190614c9a565b6103d86104db366004614c19565b6112a4565b6103d86104ee366004615133565b611394565b6105dd6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c081018252600a5463ffffffff808216835273ffffffffffffffffffffffffffffffffffffffff64010000000090920482166020840152600b549182169383019390935261ffff7401000000000000000000000000000000000000000082041660608301527601000000000000000000000000000000000000000000008104831660808301527a010000000000000000000000000000000000000000000000000000900490911660a082015290565b60405161035391906151ee565b6103d8611516565b6007546005546040805163ffffffff80851682526401000000009094049093166020840152820152606001610353565b6103d86101ae36600461525d565b61064361063e366004614c19565b611613565b60405167ffffffffffffffff9091168152602001610353565b60005473ffffffffffffffffffffffffffffffffffffffff1661046b565b604080516001815260006020820181905291810191909152606001610353565b6103d86106a83660046152dd565b61173b565b61046b6106bb366004614c19565b6119cc565b6103d86106ce3660046153e2565b611a45565b6104c0611aca565b61046b6106e9366004614c19565b611b7f565b6103d86106fc366004614c19565b611b8e565b6103d861070f366004615450565b611b9f565b6000610722600160046154e3565b600261072f608085615525565b67ffffffffffffffff16610743919061554c565b60136000610752608087615563565b67ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002054901c16600381111561078957610789614747565b92915050565b84518460ff16601f821115610805576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f6f206d616e79207472616e736d697474657273000000000000000000000060448201526064015b60405180910390fd5b8060000361086f576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016107fc565b610877611dfa565b61088085611e7d565b60095460005b8181101561090c5760086000600983815481106108a5576108a561558a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055610905816155b9565b9050610886565b50875160005b81811015610b085760008a828151811061092e5761092e61558a565b602002602001015190506000600281111561094b5761094b614747565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020526040902054610100900460ff16600281111561098a5761098a614747565b146109f1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016107fc565b73ffffffffffffffffffffffffffffffffffffffff8116610a3e576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526008602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115610aee57610aee614747565b02179055509050505080610b01906155b9565b9050610912565b508851610b1c9060099060208c01906145fd565b506006805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908b161717905560078054610ba2914691309190600090610b749063ffffffff166155f1565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168d8d8d8d8d8d61217e565b6005600001819055506000600760049054906101000a900463ffffffff16905043600760046101000a81548163ffffffff021916908363ffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600560000154600760009054906101000a900463ffffffff168e8e8e8e8e8e604051610c3999989796959493929190615614565b60405180910390a15050505050505050505050565b610c56611dfa565b60005b83811015610e55576000858583818110610c7557610c7561558a565b610c8b9260206040909202019081019150614c19565b90506000868684818110610ca157610ca161558a565b9050604002016020016020810190610cb99190614c19565b9050610cc6600c83612229565b610cfc576040517f9c8787c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116610d1e600c8461224b565b73ffffffffffffffffffffffffffffffffffffffff1614610d6b576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d76600c8361226d565b50610df18173ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de991906156aa565b600f9061226d565b506040805173ffffffffffffffffffffffffffffffffffffffff8085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a1505080610e4e906155b9565b9050610c59565b5060005b81811015611057576000838383818110610e7557610e7561558a565b610e8b9260206040909202019081019150614c19565b90506000848484818110610ea157610ea161558a565b9050604002016020016020810190610eb99190614c19565b905073ffffffffffffffffffffffffffffffffffffffff82161580610ef2575073ffffffffffffffffffffffffffffffffffffffff8116155b15610f29576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f34600c83612229565b15610f6b576040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f77600c838361228f565b50610ff38173ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fea91906156aa565b600f908361228f565b506040805173ffffffffffffffffffffffffffffffffffffffff8085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a1505080611050906155b9565b9050610e59565b5050505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff16151593830193909352600454808416606084015204909116608082015261110e906122ba565b905090565b60008080611122600c8561236c565b9150915081611175576040517fbf16aab600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016107fc565b9392505050565b606060098054806020026020016040519081016040528092919081815260200182805480156111e157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116111b6575b5050505050905090565b60606111f7600f61239b565b67ffffffffffffffff81111561120f5761120f614840565b604051908082528060200260200182016040528015611238578160200160208202803683370190505b50905060005b81518110156112a0576000611254600f836123a6565b5090508083838151811061126a5761126a61558a565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250611299816155b9565b905061123e565b5090565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906112e4575060025473ffffffffffffffffffffffffffffffffffffffff163314155b1561131b576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c9060200160405180910390a150565b467f00000000000000000000000000000000000000000000000000000000000000001461141f576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000600482015267ffffffffffffffff461660248201526044016107fc565b8151518151811461145c576040517f83e3f56400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561150657600083828151811061147b5761147b61558a565b60200260200101519050806000141580156114b4575084518051839081106114a5576114a561558a565b60200260200101516080015181105b156114f5576040517f085e39cf00000000000000000000000000000000000000000000000000000000815260048101839052602481018290526044016107fc565b506114ff816155b9565b905061145f565b5061151183836123c2565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611597576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107fc565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b73ffffffffffffffffffffffffffffffffffffffff811660009081526012602052604081205467ffffffffffffffff168015801561168657507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1615155b15610789576040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611717573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117591906156c7565b6117458787612d89565b60055488359080821461178e576040517f93df584c00000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016107fc565b467f00000000000000000000000000000000000000000000000000000000000000001461180f576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201526044016107fc565b6040805183815260208c81013560081c63ffffffff16908201527fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a13360009081526008602090815260408083208151808301909252805460ff8082168452929391929184019161010090910416600281111561189757611897614747565b60028111156118a8576118a8614747565b90525090506002816020015160028111156118c5576118c5614747565b14801561190c57506009816000015160ff16815481106118e7576118e761558a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b611942576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600061195085602061554c565b61195b88602061554c565b6119678b6101446156e4565b61197191906156e4565b61197b91906156e4565b90503681146119bf576040517f8e1192e1000000000000000000000000000000000000000000000000000000008152600481018290523660248201526044016107fc565b5050505050505050505050565b60006119d782611113565b73ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a21573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078991906156aa565b60005473ffffffffffffffffffffffffffffffffffffffff163314801590611a85575060025473ffffffffffffffffffffffffffffffffffffffff163314155b15611abc576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ac7600382612db0565b50565b6060611ad6600c61239b565b67ffffffffffffffff811115611aee57611aee614840565b604051908082528060200260200182016040528015611b17578160200160208202803683370190505b50905060005b81518110156112a0576000611b33600c836123a6565b50905080838381518110611b4957611b4961558a565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015250611b78816155b9565b9050611b1d565b60008080611122600f8561236c565b611b96611dfa565b611ac781612f95565b333014611bd8576040517f371a732800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160008082526020820190925281611c15565b6040805180820190915260008082526020820152815260200190600190039081611bee5790505b506101408401515190915015611c8257611c7f8361014001518460200151604051602001611c5f919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405160208183030381529060405285604001518661016001518661308a565b90505b604083015173ffffffffffffffffffffffffffffffffffffffff163b1580611cec57506040830151611cea9073ffffffffffffffffffffffffffffffffffffffff167f85572ffb00000000000000000000000000000000000000000000000000000000613415565b155b15611cf657505050565b600a546000908190640100000000900473ffffffffffffffffffffffffffffffffffffffff16633cf97983611d2b8786613431565b611388886080015189604001516040518563ffffffff1660e01b8152600401611d579493929190615748565b6000604051808303816000875af1158015611d76573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611dbc919081019061581a565b50915091508161105757806040517f0a8d6e8c0000000000000000000000000000000000000000000000000000000081526004016107fc919061482d565b60005473ffffffffffffffffffffffffffffffffffffffff163314611e7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107fc565b565b600081806020019051810190611e9391906158c4565b602081015190915073ffffffffffffffffffffffffffffffffffffffff16611ee7576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600a805460208085015173ffffffffffffffffffffffffffffffffffffffff908116640100000000027fffffffffffffffff00000000000000000000000000000000000000000000000090931663ffffffff9586161792909217909255604080850151600b80546060808901516080808b015160a0808d01518c167a010000000000000000000000000000000000000000000000000000027fffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffff92909c1676010000000000000000000000000000000000000000000002919091167fffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffff61ffff90941674010000000000000000000000000000000000000000027fffffffffffffffffffff00000000000000000000000000000000000000000000909616978a169790971794909417919091169490941797909717909155825160c0810184527f00000000000000000000000000000000000000000000000000000000000000008516815267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116968201969096527f0000000000000000000000000000000000000000000000000000000000000000909516858401527f00000000000000000000000000000000000000000000000000000000000000008416958501959095527f00000000000000000000000000000000000000000000000000000000000000008316908401527f00000000000000000000000000000000000000000000000000000000000000009091169282019290925290517fe668e1a4644c1a030b909bbfd837f5cfa914994ed5e0bb2e9c34a5c37753128a91612172918490615970565b60405180910390a15050565b6000808a8a8a8a8a8a8a8a8a6040516020016121a299989796959493929190615a4c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b60006111758373ffffffffffffffffffffffffffffffffffffffff84166134e1565b60006111758373ffffffffffffffffffffffffffffffffffffffff84166134ed565b60006111758373ffffffffffffffffffffffffffffffffffffffff84166134f9565b60006122b28473ffffffffffffffffffffffffffffffffffffffff851684613505565b949350505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261234882606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff164261232c91906154e3565b85608001516fffffffffffffffffffffffffffffffff16613528565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b60008061238f8473ffffffffffffffffffffffffffffffffffffffff8516613547565b915091505b9250929050565b600061078982613556565b60008080806123b58686613561565b9097909650945050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561242d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124519190615ae1565b15612488576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81515160008190036124c5576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260200151518114612503576040517f57e0e08300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008167ffffffffffffffff81111561251e5761251e614840565b604051908082528060200260200182016040528015612547578160200160208202803683370190505b50905060005b828110156126275760008560000151828151811061256d5761256d61558a565b602002602001015190506125a1817f0000000000000000000000000000000000000000000000000000000000000000613570565b8383815181106125b3576125b361558a565b6020026020010181815250508061018001518383815181106125d7576125d761558a565b602002602001015114612616576040517f7185cf6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50612620816155b9565b905061254d565b50604080850151606086015191517f3204887500000000000000000000000000000000000000000000000000000000815260009273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016926332048875926126a892879291600401615b2e565b602060405180830381865afa1580156126c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126e99190615b64565b905080600003612725576040517fea75680100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8351151560005b84811015612d805760008760000151828151811061274c5761274c61558a565b6020026020010151905060006127658260600151610714565b9050600081600381111561277b5761277b614747565b14806127985750600381600381111561279657612796614747565b145b6127e05760608201516040517f50a6e05200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107fc565b831561289d57600a5460009063ffffffff166127fc87426154e3565b119050808061281c5750600382600381111561281a5761281a614747565b145b612852576040517f6358b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8884815181106128645761286461558a565b6020026020010151600014612897578884815181106128855761288561558a565b60200260200101518360800181815250505b506128fa565b60008160038111156128b1576128b1614747565b146128fa5760608201516040517f67d9ba0f00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016107fc565b60208083015173ffffffffffffffffffffffffffffffffffffffff1660009081526012909152604090205467ffffffffffffffff168015801561297257507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1615155b15612b155760208301516040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063856c824790602401602060405180830381865afa158015612a0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a2e91906156c7565b60c084015190915067ffffffffffffffff16612a4b826001615b7d565b67ffffffffffffffff1614612ab857826020015173ffffffffffffffffffffffffffffffffffffffff168360c0015167ffffffffffffffff167fe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d60405160405180910390a3505050612d70565b60208381015173ffffffffffffffffffffffffffffffffffffffff16600090815260129091526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83161790555b6000826003811115612b2957612b29614747565b03612bb55760c083015167ffffffffffffffff16612b48826001615b7d565b67ffffffffffffffff1614612bb557826020015173ffffffffffffffffffffffffffffffffffffffff168360c0015167ffffffffffffffff167fd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf4123760405160405180910390a3505050612d70565b60008a602001518581518110612bcd57612bcd61558a565b60200260200101519050612bf984606001518560000151866101400151518761012001515185516136f6565b612c08846060015160016138a0565b600080612c15868461394a565b91509150612c278660600151836138a0565b6003826003811115612c3b57612c3b614747565b14158015612c5b57506002826003811115612c5857612c58614747565b14155b15612c9a578560600151826040517f9e2616030000000000000000000000000000000000000000000000000000000081526004016107fc929190615b9e565b6000856003811115612cae57612cae614747565b03612d1b5760208087015173ffffffffffffffffffffffffffffffffffffffff166000908152601290915260408120805467ffffffffffffffff1691612cf383615bbc565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b856101800151866060015167ffffffffffffffff167fd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef658484604051612d61929190615bd9565b60405180910390a35050505050505b612d79816155b9565b905061272c565b50505050505050565b612dac612d9882840184615bf9565b6040805160008152602081019091526123c2565b5050565b8154600090612dd990700100000000000000000000000000000000900463ffffffff16426154e3565b90508015612e7b5760018301548354612e21916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416613528565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612ea1916fffffffffffffffffffffffffffffffff9081169116613aed565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990612f889084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b60405180910390a1505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613014576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107fc565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60606000865167ffffffffffffffff8111156130a8576130a8614840565b6040519080825280602002602001820160405280156130ed57816020015b60408051808201909152600080825260208201528152602001906001900390816130c65790505b50905060005b87518110156133e45760006131248983815181106131135761311361558a565b602002602001015160000151611113565b9050600089838151811061313a5761313a61558a565b60200260200101516020015190506000806132af638627fad660e01b8c8c867f00000000000000000000000000000000000000000000000000000000000000008e8b8151811061318c5761318c61558a565b60200260200101518e8c815181106131a6576131a661558a565b60200260200101516040516020016131bf929190615c2e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526131fe9594939291602401615c53565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152600b54869063ffffffff7a010000000000000000000000000000000000000000000000000000909104166113886084613b03565b5091509150816132ed57806040517fe1cd55090000000000000000000000000000000000000000000000000000000081526004016107fc919061482d565b8373ffffffffffffffffffffffffffffffffffffffff166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015613338573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061335c91906156aa565b86868151811061336e5761336e61558a565b60200260200101516000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828686815181106133bf576133bf61558a565b6020026020010151602001818152505050505050806133dd906155b9565b90506130f3565b50600b5461340990829073ffffffffffffffffffffffffffffffffffffffff16613c29565b90505b95945050505050565b600061342083613e11565b801561117557506111758383613e75565b6040805160a08101825260008082526020820152606091810182905281810182905260808101919091526040518060a001604052808461018001518152602001846000015167ffffffffffffffff16815260200184602001516040516020016134b6919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6040516020818303038152906040528152602001846101200151815260200183815250905092915050565b60006111758383613f44565b60006111758383613f50565b60006111758383613fda565b60006122b2848473ffffffffffffffffffffffffffffffffffffffff8516613ff7565b600061340c85613538848661554c565b61354290876156e4565b613aed565b60008080806123b58686614014565b60006107898261404e565b60008080806123b58686614059565b60008060001b8284602001518560400151866060015187608001518860a001518960c001518a60e001518b610100015160405160200161361398979695949392919073ffffffffffffffffffffffffffffffffffffffff9889168152968816602088015267ffffffffffffffff95861660408801526060870194909452911515608086015290921660a0840152921660c082015260e08101919091526101000190565b604051602081830303815290604052805190602001208561012001518051906020012086610140015160405160200161364c9190615cb6565b604051602081830303815290604052805190602001208761016001516040516020016136789190615d1e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120908301979097528101949094526060840192909252608083015260a082015260c081019190915260e00160405160208183030381529060405280519060200120905092915050565b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168467ffffffffffffffff161461376f576040517f1279ec8a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526024016107fc565b600b5474010000000000000000000000000000000000000000900461ffff168311156137d3576040517f099d3f7200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff861660048201526024016107fc565b808314613818576040517f8808f8e700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff861660048201526024016107fc565b600b54760100000000000000000000000000000000000000000000900463ffffffff1682111561105757600b546040517f8693378900000000000000000000000000000000000000000000000000000000815276010000000000000000000000000000000000000000000090910463ffffffff166004820152602481018390526044016107fc565b600060026138af608085615525565b67ffffffffffffffff166138c3919061554c565b905060006013816138d5608087615563565b67ffffffffffffffff1681526020810191909152604001600020549050816138ff600160046154e3565b901b19168183600381111561391657613916614747565b901b178060136000613929608088615563565b67ffffffffffffffff16815260208101919091526040016000205550505050565b6040517ff52121a5000000000000000000000000000000000000000000000000000000008152600090606090309063f52121a59061398e9087908790600401615d31565b600060405180830381600087803b1580156139a857600080fd5b505af19250505080156139b9575060015b613ad2573d8080156139e7576040519150601f19603f3d011682016040523d82523d6000602084013e6139ec565b606091505b506139f681615ebb565b7fffffffff00000000000000000000000000000000000000000000000000000000167f0a8d6e8c000000000000000000000000000000000000000000000000000000001480613a8e5750613a4981615ebb565b7fffffffff00000000000000000000000000000000000000000000000000000000167fe1cd550900000000000000000000000000000000000000000000000000000000145b15613a9e57600392509050612394565b806040517fcf19edfd0000000000000000000000000000000000000000000000000000000081526004016107fc919061482d565b50506040805160208101909152600081526002909250929050565b6000818310613afc5781611175565b5090919050565b6000606060008361ffff1667ffffffffffffffff811115613b2657613b26614840565b6040519080825280601f01601f191660200182016040528015613b50576020820181803683370190505b509150863b613b83577f0c3b563c0000000000000000000000000000000000000000000000000000000060005260046000fd5b5a85811015613bb6577fafa32a2c0000000000000000000000000000000000000000000000000000000060005260046000fd5b8590036040810481038710613bef577f37c3be290000000000000000000000000000000000000000000000000000000060005260046000fd5b505a6000808a5160208c0160008c8cf193505a900390503d84811115613c125750835b808352806000602085013e50955095509592505050565b81516000805b82811015613dfd5760008473ffffffffffffffffffffffffffffffffffffffff1663d02641a0878481518110613c6757613c6761558a565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016040805180830381865afa158015613cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cff9190615f0b565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116600003613d9157858281518110613d3a57613d3a61558a565b6020908102919091010151516040517f9a655f7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016107fc565b613ddf868381518110613da657613da661558a565b602002602001015160200151827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661408490919063ffffffff16565b613de990846156e4565b92505080613df6906155b9565b9050613c2f565b50613e0b60038260006140c1565b50505050565b6000613e3d827f01ffc9a700000000000000000000000000000000000000000000000000000000613e75565b80156107895750613e6e827fffffffff00000000000000000000000000000000000000000000000000000000613e75565b1592915050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d91506000519050828015613f2d575060208210155b8015613f395750600081115b979650505050505050565b60006111758383614444565b600081815260028301602052604081205480151580613f745750613f748484613f44565b611175576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b6579000060448201526064016107fc565b60008181526002830160205260408120819055611175838361445c565b600082815260028401602052604081208290556122b28484614468565b6000818152600283016020526040812054819080614043576140368585613f44565b9250600091506123949050565b600192509050612394565b600061078982614474565b60008080614067858561447e565b600081815260029690960160205260409095205494959350505050565b6000670de0b6b3a76400006140b7837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff861661554c565b6111759190615f6b565b825474010000000000000000000000000000000000000000900460ff1615806140e8575081155b156140f257505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061413890700100000000000000000000000000000000900463ffffffff16426154e3565b905080156141f8578183111561417a576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546141b49083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613528565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156142af5773ffffffffffffffffffffffffffffffffffffffff8416614257576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016107fc565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff851660448201526064016107fc565b848310156143c25760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906142f390826154e3565b6142fd878a6154e3565b61430791906156e4565b6143119190615f6b565b905073ffffffffffffffffffffffffffffffffffffffff861661436a576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016107fc565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff871660448201526064016107fc565b6143cc85846154e3565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60008181526001830160205260408120541515611175565b6000611175838361448a565b60006111758383614584565b6000610789825490565b600061117583836145d3565b600081815260018301602052604081205480156145735760006144ae6001836154e3565b85549091506000906144c2906001906154e3565b90508181146145275760008660000182815481106144e2576144e261558a565b90600052602060002001549050808760000184815481106145055761450561558a565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061453857614538615f7f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610789565b6000915050610789565b5092915050565b60008181526001830160205260408120546145cb57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610789565b506000610789565b60008260000182815481106145ea576145ea61558a565b9060005260206000200154905092915050565b828054828255906000526020600020908101928215614677579160200282015b8281111561467757825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90911617825560209092019160019091019061461d565b506112a09291505b808211156112a0576000815560010161467f565b60c08101610789828473ffffffffffffffffffffffffffffffffffffffff808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a0840152505050565b67ffffffffffffffff81168114611ac757600080fd5b803561472581614704565b919050565b60006020828403121561473c57600080fd5b813561117581614704565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600481106147ad577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b602081016107898284614776565b60005b838110156147da5781810151838201526020016147c2565b50506000910152565b600081518084526147fb8160208601602086016147bf565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061117560208301846147e3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561489257614892614840565b60405290565b6040516101a0810167ffffffffffffffff8111828210171561489257614892614840565b6040516080810167ffffffffffffffff8111828210171561489257614892614840565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561492657614926614840565b604052919050565b600067ffffffffffffffff82111561494857614948614840565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114611ac757600080fd5b803561472581614952565b600082601f83011261499057600080fd5b813560206149a56149a08361492e565b6148df565b82815260059290921b840181019181810190868411156149c457600080fd5b8286015b848110156149e85780356149db81614952565b83529183019183016149c8565b509695505050505050565b803560ff8116811461472557600080fd5b600067ffffffffffffffff821115614a1e57614a1e614840565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112614a5b57600080fd5b8135614a696149a082614a04565b818152846020838601011115614a7e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c08789031215614ab457600080fd5b863567ffffffffffffffff80821115614acc57600080fd5b614ad88a838b0161497f565b97506020890135915080821115614aee57600080fd5b614afa8a838b0161497f565b9650614b0860408a016149f3565b95506060890135915080821115614b1e57600080fd5b614b2a8a838b01614a4a565b9450614b3860808a0161471a565b935060a0890135915080821115614b4e57600080fd5b50614b5b89828a01614a4a565b9150509295509295509295565b60008083601f840112614b7a57600080fd5b50813567ffffffffffffffff811115614b9257600080fd5b6020830191508360208260061b850101111561239457600080fd5b60008060008060408587031215614bc357600080fd5b843567ffffffffffffffff80821115614bdb57600080fd5b614be788838901614b68565b90965094506020870135915080821115614c0057600080fd5b50614c0d87828801614b68565b95989497509550505050565b600060208284031215614c2b57600080fd5b813561117581614952565b600081518084526020808501945080840160005b83811015614c7c57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614c4a565b509495945050505050565b6020815260006111756020830184614c36565b6020808252825182820181905260009190848201906040850190845b81811015614ce857835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614cb6565b50909695505050505050565b8015158114611ac757600080fd5b803561472581614cf4565b600082601f830112614d1e57600080fd5b81356020614d2e6149a08361492e565b82815260069290921b84018101918181019086841115614d4d57600080fd5b8286015b848110156149e85760408189031215614d6a5760008081fd5b614d7261486f565b8135614d7d81614952565b81528185013585820152835291830191604001614d51565b600082601f830112614da657600080fd5b81356020614db66149a08361492e565b82815260059290921b84018101918181019086841115614dd557600080fd5b8286015b848110156149e857803567ffffffffffffffff811115614df95760008081fd5b614e078986838b0101614a4a565b845250918301918301614dd9565b60006101a08284031215614e2857600080fd5b614e30614898565b9050614e3b8261471a565b8152614e4960208301614974565b6020820152614e5a60408301614974565b6040820152614e6b6060830161471a565b606082015260808201356080820152614e8660a08301614d02565b60a0820152614e9760c0830161471a565b60c0820152614ea860e08301614974565b60e082015261010082810135908201526101208083013567ffffffffffffffff80821115614ed557600080fd5b614ee186838701614a4a565b83850152610140925082850135915080821115614efd57600080fd5b614f0986838701614d0d565b83850152610160925082850135915080821115614f2557600080fd5b50614f3285828601614d95565b82840152505061018080830135818301525092915050565b600082601f830112614f5b57600080fd5b81356020614f6b6149a08361492e565b82815260059290921b84018101918181019086841115614f8a57600080fd5b8286015b848110156149e857803567ffffffffffffffff811115614fae5760008081fd5b614fbc8986838b0101614d95565b845250918301918301614f8e565b600082601f830112614fdb57600080fd5b81356020614feb6149a08361492e565b82815260059290921b8401810191818101908684111561500a57600080fd5b8286015b848110156149e8578035835291830191830161500e565b60006080828403121561503757600080fd5b61503f6148bc565b9050813567ffffffffffffffff8082111561505957600080fd5b818401915084601f83011261506d57600080fd5b8135602061507d6149a08361492e565b82815260059290921b8401810191818101908884111561509c57600080fd5b8286015b848110156150d4578035868111156150b85760008081fd5b6150c68b86838b0101614e15565b8452509183019183016150a0565b50865250858101359350828411156150eb57600080fd5b6150f787858801614f4a565b9085015250604084013591508082111561511057600080fd5b5061511d84828501614fca565b6040830152506060820135606082015292915050565b6000806040838503121561514657600080fd5b823567ffffffffffffffff8082111561515e57600080fd5b61516a86838701615025565b935060209150818501358181111561518157600080fd5b85019050601f8101861361519457600080fd5b80356151a26149a08261492e565b81815260059190911b820183019083810190888311156151c157600080fd5b928401925b828410156151df578335825292840192908401906151c6565b80955050505050509250929050565b60c08101610789828463ffffffff808251168352602082015173ffffffffffffffffffffffffffffffffffffffff8082166020860152806040850151166040860152505061ffff60608301511660608401528060808301511660808401528060a08301511660a0840152505050565b60006020828403121561526f57600080fd5b813567ffffffffffffffff81111561528657600080fd5b820160a0818503121561117557600080fd5b60008083601f8401126152aa57600080fd5b50813567ffffffffffffffff8111156152c257600080fd5b6020830191508360208260051b850101111561239457600080fd5b60008060008060008060008060e0898b0312156152f957600080fd5b606089018a81111561530a57600080fd5b8998503567ffffffffffffffff8082111561532457600080fd5b818b0191508b601f83011261533857600080fd5b81358181111561534757600080fd5b8c602082850101111561535957600080fd5b6020830199508098505060808b013591508082111561537757600080fd5b6153838c838d01615298565b909750955060a08b013591508082111561539c57600080fd5b506153a98b828c01615298565b999c989b50969995989497949560c00135949350505050565b80356fffffffffffffffffffffffffffffffff8116811461472557600080fd5b6000606082840312156153f457600080fd5b6040516060810181811067ffffffffffffffff8211171561541757615417614840565b604052823561542581614cf4565b8152615433602084016153c2565b6020820152615444604084016153c2565b60408201529392505050565b6000806040838503121561546357600080fd5b823567ffffffffffffffff8082111561547b57600080fd5b61548786838701614e15565b9350602085013591508082111561549d57600080fd5b506154aa85828601614d95565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610789576107896154b4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff80841680615540576155406154f6565b92169190910692915050565b8082028115828204841417610789576107896154b4565b600067ffffffffffffffff8084168061557e5761557e6154f6565b92169190910492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036155ea576155ea6154b4565b5060010190565b600063ffffffff80831681810361560a5761560a6154b4565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526156448184018a614c36565b905082810360808401526156588189614c36565b905060ff871660a084015282810360c084015261567581876147e3565b905067ffffffffffffffff851660e084015282810361010084015261569a81856147e3565b9c9b505050505050505050505050565b6000602082840312156156bc57600080fd5b815161117581614952565b6000602082840312156156d957600080fd5b815161117581614704565b80820180821115610789576107896154b4565b600081518084526020808501945080840160005b83811015614c7c578151805173ffffffffffffffffffffffffffffffffffffffff168852830151838801526040909601959082019060010161570b565b608081528451608082015267ffffffffffffffff60208601511660a08201526000604086015160a060c08401526157836101208401826147e3565b905060608701517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808584030160e08601526157bf83836147e3565b9250608089015191508085840301610100860152506157de82826156f7565b925050506157f2602083018661ffff169052565b83604083015261340c606083018473ffffffffffffffffffffffffffffffffffffffff169052565b60008060006060848603121561582f57600080fd5b835161583a81614cf4565b602085015190935067ffffffffffffffff81111561585757600080fd5b8401601f8101861361586857600080fd5b80516158766149a082614a04565b81815287602083850101111561588b57600080fd5b61589c8260208301602086016147bf565b809450505050604084015190509250925092565b805163ffffffff8116811461472557600080fd5b600060c082840312156158d657600080fd5b60405160c0810181811067ffffffffffffffff821117156158f9576158f9614840565b604052615905836158b0565b8152602083015161591581614952565b6020820152604083015161592881614952565b6040820152606083015161ffff8116811461594257600080fd5b6060820152615953608084016158b0565b608082015261596460a084016158b0565b60a08201529392505050565b61018081016159e2828573ffffffffffffffffffffffffffffffffffffffff808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015250508060608301511660608401528060808301511660808401528060a08301511660a0840152505050565b825163ffffffff90811660c0840152602084015173ffffffffffffffffffffffffffffffffffffffff90811660e0850152604085015116610100840152606084015161ffff166101208401526080840151811661014084015260a084015116610160830152611175565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152615a938285018b614c36565b91508382036080850152615aa7828a614c36565b915060ff881660a085015283820360c0850152615ac482886147e3565b90861660e0850152838103610100850152905061569a81856147e3565b600060208284031215615af357600080fd5b815161117581614cf4565b600081518084526020808501945080840160005b83811015614c7c57815187529582019590820190600101615b12565b606081526000615b416060830186615afe565b8281036020840152615b538186615afe565b915050826040830152949350505050565b600060208284031215615b7657600080fd5b5051919050565b67ffffffffffffffff81811683821601908082111561457d5761457d6154b4565b67ffffffffffffffff83168152604081016111756020830184614776565b600067ffffffffffffffff80831681810361560a5761560a6154b4565b615be38184614776565b6040602082015260006122b260408301846147e3565b600060208284031215615c0b57600080fd5b813567ffffffffffffffff811115615c2257600080fd5b6122b284828501615025565b604081526000615c4160408301856147e3565b828103602084015261340c81856147e3565b60a081526000615c6660a08301886147e3565b73ffffffffffffffffffffffffffffffffffffffff8716602084015285604084015267ffffffffffffffff851660608401528281036080840152615caa81856147e3565b98975050505050505050565b60208152600061117560208301846156f7565b600081518084526020808501808196508360051b8101915082860160005b85811015615d11578284038952615cff8483516147e3565b98850198935090840190600101615ce7565b5091979650505050505050565b6020815260006111756020830184615cc9565b60408152615d4c60408201845167ffffffffffffffff169052565b60006020840151615d75606084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604084015173ffffffffffffffffffffffffffffffffffffffff8116608084015250606084015167ffffffffffffffff811660a084015250608084015160c083015260a084015180151560e08401525060c0840151610100615de38185018367ffffffffffffffff169052565b60e08601519150610120615e0e8186018473ffffffffffffffffffffffffffffffffffffffff169052565b81870151925061014091508282860152808701519250506101a06101608181870152615e3e6101e08701856147e3565b93508288015192507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0610180818887030181890152615e7d86866156f7565b9550828a01519450818887030184890152615e988686615cc9565b9550808a01516101c08901525050505050828103602084015261340c8185615cc9565b6000815160208301517fffffffff0000000000000000000000000000000000000000000000000000000080821693506004831015615f035780818460040360031b1b83161693505b505050919050565b600060408284031215615f1d57600080fd5b615f2561486f565b82517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114615f5157600080fd5b8152615f5f602084016158b0565b60208201529392505050565b600082615f7a57615f7a6154f6565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a",
+}
+
+var EVM2EVMOffRampABI = EVM2EVMOffRampMetaData.ABI
+
+var EVM2EVMOffRampBin = EVM2EVMOffRampMetaData.Bin
+
+func DeployEVM2EVMOffRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMOffRampStaticConfig, sourceTokens []common.Address, pools []common.Address, rateLimiterConfig RateLimiterConfig) (common.Address, *types.Transaction, *EVM2EVMOffRamp, error) {
+ parsed, err := EVM2EVMOffRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMOffRampBin), backend, staticConfig, sourceTokens, pools, rateLimiterConfig)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMOffRamp{EVM2EVMOffRampCaller: EVM2EVMOffRampCaller{contract: contract}, EVM2EVMOffRampTransactor: EVM2EVMOffRampTransactor{contract: contract}, EVM2EVMOffRampFilterer: EVM2EVMOffRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMOffRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMOffRampCaller
+ EVM2EVMOffRampTransactor
+ EVM2EVMOffRampFilterer
+}
+
+type EVM2EVMOffRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOffRampSession struct {
+ Contract *EVM2EVMOffRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOffRampCallerSession struct {
+ Contract *EVM2EVMOffRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMOffRampTransactorSession struct {
+ Contract *EVM2EVMOffRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOffRampRaw struct {
+ Contract *EVM2EVMOffRamp
+}
+
+type EVM2EVMOffRampCallerRaw struct {
+ Contract *EVM2EVMOffRampCaller
+}
+
+type EVM2EVMOffRampTransactorRaw struct {
+ Contract *EVM2EVMOffRampTransactor
+}
+
+func NewEVM2EVMOffRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMOffRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMOffRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMOffRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRamp{address: address, abi: abi, EVM2EVMOffRampCaller: EVM2EVMOffRampCaller{contract: contract}, EVM2EVMOffRampTransactor: EVM2EVMOffRampTransactor{contract: contract}, EVM2EVMOffRampFilterer: EVM2EVMOffRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMOffRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMOffRampCaller, error) {
+ contract, err := bindEVM2EVMOffRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMOffRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMOffRampTransactor, error) {
+ contract, err := bindEVM2EVMOffRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMOffRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMOffRampFilterer, error) {
+ contract, err := bindEVM2EVMOffRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMOffRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMOffRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.EVM2EVMOffRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOffRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) CcipReceive(opts *bind.CallOpts, arg0 ClientAny2EVMMessage) error {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "ccipReceive", arg0)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) CcipReceive(arg0 ClientAny2EVMMessage) error {
+ return _EVM2EVMOffRamp.Contract.CcipReceive(&_EVM2EVMOffRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) CcipReceive(arg0 ClientAny2EVMMessage) error {
+ return _EVM2EVMOffRamp.Contract.CcipReceive(&_EVM2EVMOffRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "currentRateLimiterState")
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOffRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOffRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetDestinationToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getDestinationToken", sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetDestinationToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetDestinationToken(&_EVM2EVMOffRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetDestinationToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetDestinationToken(&_EVM2EVMOffRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetDestinationTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getDestinationTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetDestinationTokens() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetDestinationTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetDestinationTokens() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetDestinationTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOffRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOffRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOffRampDynamicConfig)).(*EVM2EVMOffRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetDynamicConfig() (EVM2EVMOffRampDynamicConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetDynamicConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetDynamicConfig() (EVM2EVMOffRampDynamicConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetDynamicConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getExecutionState", sequenceNumber)
+
+ if err != nil {
+ return *new(uint8), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetExecutionState(sequenceNumber uint64) (uint8, error) {
+ return _EVM2EVMOffRamp.Contract.GetExecutionState(&_EVM2EVMOffRamp.CallOpts, sequenceNumber)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetExecutionState(sequenceNumber uint64) (uint8, error) {
+ return _EVM2EVMOffRamp.Contract.GetExecutionState(&_EVM2EVMOffRamp.CallOpts, sequenceNumber)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetPoolByDestToken(opts *bind.CallOpts, destToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getPoolByDestToken", destToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetPoolByDestToken(destToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetPoolByDestToken(&_EVM2EVMOffRamp.CallOpts, destToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetPoolByDestToken(destToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetPoolByDestToken(&_EVM2EVMOffRamp.CallOpts, destToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getPoolBySourceToken", sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetPoolBySourceToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOffRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetPoolBySourceToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOffRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getSenderNonce", sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOffRamp.Contract.GetSenderNonce(&_EVM2EVMOffRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOffRamp.Contract.GetSenderNonce(&_EVM2EVMOffRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOffRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOffRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOffRampStaticConfig)).(*EVM2EVMOffRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetStaticConfig() (EVM2EVMOffRampStaticConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetStaticConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetStaticConfig() (EVM2EVMOffRampStaticConfig, error) {
+ return _EVM2EVMOffRamp.Contract.GetStaticConfig(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getSupportedTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetSupportedTokens() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetSupportedTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetSupportedTokens() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetSupportedTokens(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getTokenLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) GetTransmitters() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTransmitters(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.GetTransmitters(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDetails(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDetails(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "latestConfigDigestAndEpoch")
+
+ outstruct := new(LatestConfigDigestAndEpoch)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool)
+ outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDigestAndEpoch(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch,
+
+ error) {
+ return _EVM2EVMOffRamp.Contract.LatestConfigDigestAndEpoch(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.Owner(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMOffRamp.Contract.Owner(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMOffRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOffRamp.Contract.TypeAndVersion(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOffRamp.Contract.TypeAndVersion(&_EVM2EVMOffRamp.CallOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.AcceptOwnership(&_EVM2EVMOffRamp.TransactOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.AcceptOwnership(&_EVM2EVMOffRamp.TransactOpts)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "applyPoolUpdates", removes, adds)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOffRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOffRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) ExecuteSingleMessage(opts *bind.TransactOpts, message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "executeSingleMessage", message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) ExecuteSingleMessage(message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ExecuteSingleMessage(&_EVM2EVMOffRamp.TransactOpts, message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) ExecuteSingleMessage(message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ExecuteSingleMessage(&_EVM2EVMOffRamp.TransactOpts, message, offchainTokenData)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) ManuallyExecute(opts *bind.TransactOpts, report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "manuallyExecute", report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) ManuallyExecute(report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ManuallyExecute(&_EVM2EVMOffRamp.TransactOpts, report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) ManuallyExecute(report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.ManuallyExecute(&_EVM2EVMOffRamp.TransactOpts, report, gasLimitOverrides)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setAdmin", newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetAdmin(&_EVM2EVMOffRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetAdmin(&_EVM2EVMOffRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setOCR2Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetOCR2Config(&_EVM2EVMOffRamp.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetOCR2Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetOCR2Config(&_EVM2EVMOffRamp.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "setRateLimiterConfig", config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOffRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOffRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.TransferOwnership(&_EVM2EVMOffRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.TransferOwnership(&_EVM2EVMOffRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.contract.Transact(opts, "transmit", reportContext, report, rs, ss, arg4)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.Transmit(&_EVM2EVMOffRamp.TransactOpts, reportContext, report, rs, ss, arg4)
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ return _EVM2EVMOffRamp.Contract.Transmit(&_EVM2EVMOffRamp.TransactOpts, reportContext, report, rs, ss, arg4)
+}
+
+type EVM2EVMOffRampAdminSetIterator struct {
+ Event *EVM2EVMOffRampAdminSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampAdminSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampAdminSet)
+ 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(EVM2EVMOffRampAdminSet)
+ 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 *EVM2EVMOffRampAdminSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampAdminSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampAdminSet struct {
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOffRampAdminSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampAdminSetIterator{contract: _EVM2EVMOffRamp.contract, event: "AdminSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampAdminSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampAdminSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "AdminSet", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseAdminSet(log types.Log) (*EVM2EVMOffRampAdminSet, error) {
+ event := new(EVM2EVMOffRampAdminSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "AdminSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampConfigSetIterator struct {
+ Event *EVM2EVMOffRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampConfigSet)
+ 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(EVM2EVMOffRampConfigSet)
+ 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 *EVM2EVMOffRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampConfigSet struct {
+ StaticConfig EVM2EVMOffRampStaticConfig
+ DynamicConfig EVM2EVMOffRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampConfigSetIterator{contract: _EVM2EVMOffRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampConfigSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMOffRampConfigSet, error) {
+ event := new(EVM2EVMOffRampConfigSet)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampConfigSet0Iterator struct {
+ Event *EVM2EVMOffRampConfigSet0
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampConfigSet0Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampConfigSet0)
+ 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(EVM2EVMOffRampConfigSet0)
+ 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 *EVM2EVMOffRampConfigSet0Iterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampConfigSet0Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampConfigSet0 struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterConfigSet0(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSet0Iterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampConfigSet0Iterator{contract: _EVM2EVMOffRamp.contract, event: "ConfigSet0", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet0) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ConfigSet0")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampConfigSet0)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet0", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseConfigSet0(log types.Log) (*EVM2EVMOffRampConfigSet0, error) {
+ event := new(EVM2EVMOffRampConfigSet0)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ConfigSet0", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampExecutionStateChangedIterator struct {
+ Event *EVM2EVMOffRampExecutionStateChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampExecutionStateChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampExecutionStateChanged)
+ 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(EVM2EVMOffRampExecutionStateChanged)
+ 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 *EVM2EVMOffRampExecutionStateChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampExecutionStateChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampExecutionStateChanged struct {
+ SequenceNumber uint64
+ MessageId [32]byte
+ State uint8
+ ReturnData []byte
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*EVM2EVMOffRampExecutionStateChangedIterator, error) {
+
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "ExecutionStateChanged", sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampExecutionStateChangedIterator{contract: _EVM2EVMOffRamp.contract, event: "ExecutionStateChanged", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) {
+
+ var sequenceNumberRule []interface{}
+ for _, sequenceNumberItem := range sequenceNumber {
+ sequenceNumberRule = append(sequenceNumberRule, sequenceNumberItem)
+ }
+ var messageIdRule []interface{}
+ for _, messageIdItem := range messageId {
+ messageIdRule = append(messageIdRule, messageIdItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "ExecutionStateChanged", sequenceNumberRule, messageIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampExecutionStateChanged)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ExecutionStateChanged", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseExecutionStateChanged(log types.Log) (*EVM2EVMOffRampExecutionStateChanged, error) {
+ event := new(EVM2EVMOffRampExecutionStateChanged)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "ExecutionStateChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMOffRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampOwnershipTransferRequested)
+ 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(EVM2EVMOffRampOwnershipTransferRequested)
+ 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 *EVM2EVMOffRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampOwnershipTransferRequestedIterator{contract: _EVM2EVMOffRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampOwnershipTransferRequested)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOffRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMOffRampOwnershipTransferRequested)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMOffRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampOwnershipTransferred)
+ 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(EVM2EVMOffRampOwnershipTransferred)
+ 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 *EVM2EVMOffRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampOwnershipTransferredIterator{contract: _EVM2EVMOffRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampOwnershipTransferred)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMOffRampOwnershipTransferred, error) {
+ event := new(EVM2EVMOffRampOwnershipTransferred)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampPoolAddedIterator struct {
+ Event *EVM2EVMOffRampPoolAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampPoolAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampPoolAdded)
+ 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(EVM2EVMOffRampPoolAdded)
+ 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 *EVM2EVMOffRampPoolAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampPoolAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampPoolAdded struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOffRampPoolAddedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampPoolAddedIterator{contract: _EVM2EVMOffRamp.contract, event: "PoolAdded", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampPoolAdded) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampPoolAdded)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "PoolAdded", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParsePoolAdded(log types.Log) (*EVM2EVMOffRampPoolAdded, error) {
+ event := new(EVM2EVMOffRampPoolAdded)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "PoolAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampPoolRemovedIterator struct {
+ Event *EVM2EVMOffRampPoolRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampPoolRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampPoolRemoved)
+ 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(EVM2EVMOffRampPoolRemoved)
+ 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 *EVM2EVMOffRampPoolRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampPoolRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampPoolRemoved struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOffRampPoolRemovedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampPoolRemovedIterator{contract: _EVM2EVMOffRamp.contract, event: "PoolRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampPoolRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampPoolRemoved)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "PoolRemoved", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParsePoolRemoved(log types.Log) (*EVM2EVMOffRampPoolRemoved, error) {
+ event := new(EVM2EVMOffRampPoolRemoved)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "PoolRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampSkippedIncorrectNonceIterator struct {
+ Event *EVM2EVMOffRampSkippedIncorrectNonce
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampSkippedIncorrectNonceIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampSkippedIncorrectNonce)
+ 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(EVM2EVMOffRampSkippedIncorrectNonce)
+ 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 *EVM2EVMOffRampSkippedIncorrectNonceIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampSkippedIncorrectNonceIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampSkippedIncorrectNonce struct {
+ Nonce uint64
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedIncorrectNonceIterator, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "SkippedIncorrectNonce", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampSkippedIncorrectNonceIterator{contract: _EVM2EVMOffRamp.contract, event: "SkippedIncorrectNonce", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "SkippedIncorrectNonce", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampSkippedIncorrectNonce)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedIncorrectNonce", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseSkippedIncorrectNonce(log types.Log) (*EVM2EVMOffRampSkippedIncorrectNonce, error) {
+ event := new(EVM2EVMOffRampSkippedIncorrectNonce)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedIncorrectNonce", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator struct {
+ Event *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ 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(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ 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 *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight struct {
+ Nonce uint64
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "SkippedSenderWithPreviousRampMessageInflight", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator{contract: _EVM2EVMOffRamp.contract, event: "SkippedSenderWithPreviousRampMessageInflight", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "SkippedSenderWithPreviousRampMessageInflight", nonceRule, senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedSenderWithPreviousRampMessageInflight", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error) {
+ event := new(EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "SkippedSenderWithPreviousRampMessageInflight", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOffRampTransmittedIterator struct {
+ Event *EVM2EVMOffRampTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOffRampTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOffRampTransmitted)
+ 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(EVM2EVMOffRampTransmitted)
+ 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 *EVM2EVMOffRampTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOffRampTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOffRampTransmitted struct {
+ ConfigDigest [32]byte
+ Epoch uint32
+ Raw types.Log
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) FilterTransmitted(opts *bind.FilterOpts) (*EVM2EVMOffRampTransmittedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOffRampTransmittedIterator{contract: _EVM2EVMOffRamp.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOffRamp.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOffRampTransmitted)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "Transmitted", 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 (_EVM2EVMOffRamp *EVM2EVMOffRampFilterer) ParseTransmitted(log types.Log) (*EVM2EVMOffRampTransmitted, error) {
+ event := new(EVM2EVMOffRampTransmitted)
+ if err := _EVM2EVMOffRamp.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+type LatestConfigDigestAndEpoch struct {
+ ScanLogs bool
+ ConfigDigest [32]byte
+ Epoch uint32
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMOffRamp.abi.Events["AdminSet"].ID:
+ return _EVM2EVMOffRamp.ParseAdminSet(log)
+ case _EVM2EVMOffRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMOffRamp.ParseConfigSet(log)
+ case _EVM2EVMOffRamp.abi.Events["ConfigSet0"].ID:
+ return _EVM2EVMOffRamp.ParseConfigSet0(log)
+ case _EVM2EVMOffRamp.abi.Events["ExecutionStateChanged"].ID:
+ return _EVM2EVMOffRamp.ParseExecutionStateChanged(log)
+ case _EVM2EVMOffRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMOffRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMOffRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMOffRamp.ParseOwnershipTransferred(log)
+ case _EVM2EVMOffRamp.abi.Events["PoolAdded"].ID:
+ return _EVM2EVMOffRamp.ParsePoolAdded(log)
+ case _EVM2EVMOffRamp.abi.Events["PoolRemoved"].ID:
+ return _EVM2EVMOffRamp.ParsePoolRemoved(log)
+ case _EVM2EVMOffRamp.abi.Events["SkippedIncorrectNonce"].ID:
+ return _EVM2EVMOffRamp.ParseSkippedIncorrectNonce(log)
+ case _EVM2EVMOffRamp.abi.Events["SkippedSenderWithPreviousRampMessageInflight"].ID:
+ return _EVM2EVMOffRamp.ParseSkippedSenderWithPreviousRampMessageInflight(log)
+ case _EVM2EVMOffRamp.abi.Events["Transmitted"].ID:
+ return _EVM2EVMOffRamp.ParseTransmitted(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMOffRampAdminSet) Topic() common.Hash {
+ return common.HexToHash("0x8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c")
+}
+
+func (EVM2EVMOffRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xe668e1a4644c1a030b909bbfd837f5cfa914994ed5e0bb2e9c34a5c37753128a")
+}
+
+func (EVM2EVMOffRampConfigSet0) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (EVM2EVMOffRampExecutionStateChanged) Topic() common.Hash {
+ return common.HexToHash("0xd4f851956a5d67c3997d1c9205045fef79bae2947fdee7e9e2641abc7391ef65")
+}
+
+func (EVM2EVMOffRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMOffRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (EVM2EVMOffRampPoolAdded) Topic() common.Hash {
+ return common.HexToHash("0x95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c")
+}
+
+func (EVM2EVMOffRampPoolRemoved) Topic() common.Hash {
+ return common.HexToHash("0x987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c")
+}
+
+func (EVM2EVMOffRampSkippedIncorrectNonce) Topic() common.Hash {
+ return common.HexToHash("0xd32ddb11d71e3d63411d37b09f9a8b28664f1cb1338bfd1413c173b0ebf41237")
+}
+
+func (EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight) Topic() common.Hash {
+ return common.HexToHash("0xe44a20935573a783dd0d5991c92d7b6a0eb3173566530364db3ec10e9a990b5d")
+}
+
+func (EVM2EVMOffRampTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62")
+}
+
+func (_EVM2EVMOffRamp *EVM2EVMOffRamp) Address() common.Address {
+ return _EVM2EVMOffRamp.address
+}
+
+type EVM2EVMOffRampInterface interface {
+ CcipReceive(opts *bind.CallOpts, arg0 ClientAny2EVMMessage) error
+
+ CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error)
+
+ GetDestinationToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error)
+
+ GetDestinationTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOffRampDynamicConfig, error)
+
+ GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error)
+
+ GetPoolByDestToken(opts *bind.CallOpts, destToken common.Address) (common.Address, error)
+
+ GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error)
+
+ GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOffRampStaticConfig, error)
+
+ GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch,
+
+ error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error)
+
+ ExecuteSingleMessage(opts *bind.TransactOpts, message InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error)
+
+ ManuallyExecute(opts *bind.TransactOpts, report InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error)
+
+ SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error)
+
+ SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error)
+
+ FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOffRampAdminSetIterator, error)
+
+ WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampAdminSet) (event.Subscription, error)
+
+ ParseAdminSet(log types.Log) (*EVM2EVMOffRampAdminSet, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMOffRampConfigSet, error)
+
+ FilterConfigSet0(opts *bind.FilterOpts) (*EVM2EVMOffRampConfigSet0Iterator, error)
+
+ WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampConfigSet0) (event.Subscription, error)
+
+ ParseConfigSet0(log types.Log) (*EVM2EVMOffRampConfigSet0, error)
+
+ FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*EVM2EVMOffRampExecutionStateChangedIterator, error)
+
+ WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error)
+
+ ParseExecutionStateChanged(log types.Log) (*EVM2EVMOffRampExecutionStateChanged, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOffRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOffRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMOffRampOwnershipTransferred, error)
+
+ FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOffRampPoolAddedIterator, error)
+
+ WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampPoolAdded) (event.Subscription, error)
+
+ ParsePoolAdded(log types.Log) (*EVM2EVMOffRampPoolAdded, error)
+
+ FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOffRampPoolRemovedIterator, error)
+
+ WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampPoolRemoved) (event.Subscription, error)
+
+ ParsePoolRemoved(log types.Log) (*EVM2EVMOffRampPoolRemoved, error)
+
+ FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedIncorrectNonceIterator, error)
+
+ WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error)
+
+ ParseSkippedIncorrectNonce(log types.Log) (*EVM2EVMOffRampSkippedIncorrectNonce, error)
+
+ FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)
+
+ WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error)
+
+ ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*EVM2EVMOffRampTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *EVM2EVMOffRampTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*EVM2EVMOffRampTransmitted, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_onramp/evm_2_evm_onramp.go b/core/gethwrappers/ccip/generated/evm_2_evm_onramp/evm_2_evm_onramp.go
new file mode 100644
index 00000000000..be9c2395a05
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_onramp/evm_2_evm_onramp.go
@@ -0,0 +1,2453 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_onramp
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMOnRampDynamicConfig struct {
+ Router common.Address
+ MaxNumberOfTokensPerMsg uint16
+ DestGasOverhead uint32
+ DestGasPerPayloadByte uint16
+ DestDataAvailabilityOverheadGas uint32
+ DestGasPerDataAvailabilityByte uint16
+ DestDataAvailabilityMultiplierBps uint16
+ PriceRegistry common.Address
+ MaxDataBytes uint32
+ MaxPerMsgGasLimit uint32
+ DefaultTokenFeeUSDCents uint16
+ DefaultTokenDestGasOverhead uint32
+ DefaultTokenDestBytesOverhead uint32
+ EnforceOutOfOrder bool
+}
+
+type EVM2EVMOnRampFeeTokenConfig struct {
+ NetworkFeeUSDCents uint32
+ GasMultiplierWeiPerEth uint64
+ PremiumMultiplierWeiPerEth uint64
+ Enabled bool
+}
+
+type EVM2EVMOnRampFeeTokenConfigArgs struct {
+ Token common.Address
+ NetworkFeeUSDCents uint32
+ GasMultiplierWeiPerEth uint64
+ PremiumMultiplierWeiPerEth uint64
+ Enabled bool
+}
+
+type EVM2EVMOnRampNopAndWeight struct {
+ Nop common.Address
+ Weight uint16
+}
+
+type EVM2EVMOnRampStaticConfig struct {
+ LinkToken common.Address
+ ChainSelector uint64
+ DestChainSelector uint64
+ DefaultTxGasLimit uint64
+ MaxNopFeesJuels *big.Int
+ PrevOnRamp common.Address
+ RmnProxy common.Address
+ TokenAdminRegistry common.Address
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfig struct {
+ MinFeeUSDCents uint32
+ MaxFeeUSDCents uint32
+ DeciBps uint16
+ DestGasOverhead uint32
+ DestBytesOverhead uint32
+ AggregateRateLimitEnabled bool
+ IsEnabled bool
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigArgs struct {
+ Token common.Address
+ MinFeeUSDCents uint32
+ MaxFeeUSDCents uint32
+ DeciBps uint16
+ DestGasOverhead uint32
+ DestBytesOverhead uint32
+ AggregateRateLimitEnabled bool
+}
+
+type InternalEVM2EVMMessage struct {
+ SourceChainSelector uint64
+ Sender common.Address
+ Receiver common.Address
+ SequenceNumber uint64
+ GasLimit *big.Int
+ Strict bool
+ Nonce uint64
+ FeeToken common.Address
+ FeeTokenAmount *big.Int
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ SourceTokenData [][]byte
+ MessageId [32]byte
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+var EVM2EVMOnRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeTokenConfigs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"aggregateRateLimitEnabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotSendZeroTokens\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExtraArgOutOfOrderExecutionMustBeTrue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GetSupportedTokensFunctionalityRemovedCheckAdminRegistry\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidChainSelector\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"}],\"name\":\"InvalidDestBytesOverhead\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidEVMAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"}],\"name\":\"InvalidNopAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWithdrawParams\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkBalanceNotSettled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxFeeBalanceReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MessageGasLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeCalledByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoFeesToPay\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoNopsToPay\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"NotAFeeToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdminOrNop\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PriceNotFoundForToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustSetOriginalSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SourceTokenDataTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyNops\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"UnsupportedToken\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[]\",\"name\":\"sourceTokenData\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structInternal.EVM2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"CCIPSendRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeConfig\",\"type\":\"tuple[]\"}],\"name\":\"FeeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NopPaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nopWeightsTotal\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"NopsSet\",\"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\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"TokenTransferFeeConfigDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"aggregateRateLimitEnabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"transferFeeConfig\",\"type\":\"tuple[]\"}],\"name\":\"TokenTransferFeeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"}],\"name\":\"forwardFromRouter\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getFeeTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfig\",\"name\":\"feeTokenConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNopFeesJuels\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNops\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"weightsTotal\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getPoolBySourceToken\",\"outputs\":[{\"internalType\":\"contractIPoolV1\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getSenderNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"getSupportedTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenTransferFeeConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"aggregateRateLimitEnabled\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"payNops\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"setDynamicConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeTokenConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setFeeTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setNops\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"aggregateRateLimitEnabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"internalType\":\"address[]\",\"name\":\"tokensToUseDefaultFeeConfigs\",\"type\":\"address[]\"}],\"name\":\"setTokenTransferFeeConfig\",\"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\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawNonLinkFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101a06040523480156200001257600080fd5b50604051620082d4380380620082d4833981016040819052620000359162001b0e565b8333806000816200008d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c057620000c0816200030b565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080909301839052600380546001600160a01b031916909417600160801b9283021760ff60a01b1916600160a01b90910217909255029091176004555085516001600160a01b0316158062000169575060208601516001600160401b0316155b8062000180575060408601516001600160401b0316155b8062000197575060608601516001600160401b0316155b80620001ae575060c08601516001600160a01b0316155b80620001c5575060e08601516001600160a01b0316155b15620001e4576040516306b7c75960e31b815260040160405180910390fd5b60208087015160408089015181517f8acd72527118c8324937b1a42e02cd246697c3b633f1742f3cae11de233722b3948101949094526001600160401b039283169184019190915216606082015230608082015260a00160408051601f198184030181529181528151602092830120608090815288516001600160a01b0390811660e0908152938a01516001600160401b0390811661010052928a015183166101205260608a015190921660a0908152908901516001600160601b031660c090815290890151821661014052880151811661016052908701511661018052620002cd85620003b6565b620002d8836200071a565b604080516000815260208101909152620002f49083906200084a565b620002ff8162000aea565b50505050505062002212565b336001600160a01b03821603620003655760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000084565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60e08101516001600160a01b0316620003e2576040516306b7c75960e31b815260040160405180910390fd5b602081610180015163ffffffff16101562000427576101808101516040516312766e0160e11b81526000600482015263ffffffff909116602482015260440162000084565b80600560008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601a6101000a81548161ffff021916908361ffff160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160006101000a81548161ffff021916908361ffff16021790555060c08201518160010160026101000a81548161ffff021916908361ffff16021790555060e08201518160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555061012082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160006101000a81548161ffff021916908361ffff1602179055506101608201518160020160026101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160020160066101000a81548163ffffffff021916908363ffffffff1602179055506101a082015181600201600a6101000a81548160ff0219169083151502179055509050507fe375c8cb6ea9807cd0371503b632b93da5ee0f1f64205db8b5b28b95d6b588b060405180610100016040528060e0516001600160a01b03168152602001610100516001600160401b03168152602001610120516001600160401b0316815260200160a0516001600160401b0316815260200160c0516001600160601b03168152602001610140516001600160a01b03168152602001610160516001600160a01b03168152602001610180516001600160a01b0316815250826040516200070f92919062001da4565b60405180910390a150565b60005b8151811015620008185760008282815181106200073e576200073e62001e69565b60209081029190910181015160408051608080820183528385015163ffffffff9081168352838501516001600160401b03908116848801908152606080880151831686880190815294880151151590860190815296516001600160a01b03166000908152600b90985294909620925183549451925195511515600160a01b0260ff60a01b199688166c010000000000000000000000000296909616600160601b600160a81b031993909716640100000000026001600160601b0319909516911617929092179190911692909217179055506001016200071d565b507f067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e816040516200070f919062001e7f565b60005b825181101562000a095760008382815181106200086e576200086e62001e69565b6020026020010151905060208160a0015163ffffffff161015620008c457805160a08201516040516312766e0160e11b81526001600160a01b03909216600483015263ffffffff16602482015260440162000084565b6040805160e08101825260208381015163ffffffff908116835284840151811682840190815260608087015161ffff9081168688019081526080808a0151861693880193845260a0808b0151871691890191825260c0808c01511515918a019182526001908a018181529b516001600160a01b03166000908152600c9099529990972097518854955192519451915197519a519087166001600160401b031990961695909517640100000000928716929092029190911765ffffffffffff60401b191668010000000000000000939092169290920263ffffffff60501b1916176a0100000000000000000000918416919091021764ffffffffff60701b1916600160701b939092169290920260ff60901b191617600160901b941515949094029390931760ff60981b1916600160981b9315159390930292909217909155016200084d565b507ff5791bc457b3bb990493cf5f655db46c25ccf5764c9b99b8969b4c72ea7df9d08260405162000a3b919062001f0e565b60405180910390a160005b815181101562000aa357600c600083838151811062000a695762000a6962001e69565b6020908102919091018101516001600160a01b0316825281019190915260400160002080546001600160a01b031916905560010162000a46565b5080511562000ae6577ffb95a0042158e60a33e7b5bec100f3d95407b1a71bee6633bd54b8887449750b8160405162000add919062001fa3565b60405180910390a15b5050565b8051604081111562000b0f57604051635ad0867d60e11b815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff161562000b6257600e5463ffffffff6c010000000000000000000000008204166001600160601b039091161062000b625762000b6262000d05565b600062000b70600862000ef1565b90505b801562000bbc57600062000b9662000b8d60018462002008565b60089062000f04565b50905062000ba660088262000f22565b50508062000bb4906200201e565b905062000b73565b506000805b8281101562000c9c57600084828151811062000be15762000be162001e69565b6020026020010151600001519050600085838151811062000c065762000c0662001e69565b602002602001015160200151905060e0516001600160a01b0316826001600160a01b0316148062000c3e57506001600160a01b038216155b1562000c6957604051634de938d160e01b81526001600160a01b038316600482015260240162000084565b62000c7b60088361ffff841662000f40565b5062000c8c61ffff82168562002038565b9350505080600101905062000bc1565b50600e805463ffffffff60601b19166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd249062000cf8908390869062002058565b60405180910390a1505050565b6000546001600160a01b0316331462000d56576002546001600160a01b0316331462000d565762000d3860083362000f60565b62000d565760405163032bb72b60e31b815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff16600081900362000d925760405163990e30bf60e01b815260040160405180910390fd5b600e546001600160601b03168181101562000dc0576040516311a1ee3b60e31b815260040160405180910390fd5b600062000dcc62000f77565b121562000dec57604051631e9acf1760e31b815260040160405180910390fd5b80600062000dfb600862000ef1565b905060005b8181101562000ecb5760008062000e1960088462000f04565b909250905060008762000e36836001600160601b038a16620020c8565b62000e429190620020e2565b905062000e50818762002105565b60e05190965062000e75906001600160a01b0316846001600160601b03841662001005565b6040516001600160601b03821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a250505080600101905062000e00565b5050600e80546001600160601b0319166001600160601b03929092169190911790555050565b600062000efe8262001062565b92915050565b600080808062000f1586866200106f565b9097909650945050505050565b600062000f39836001600160a01b0384166200109c565b9392505050565b600062000f58846001600160a01b03851684620010bb565b949350505050565b600062000f39836001600160a01b038416620010da565b600e5460e0516040516370a0823160e01b81523060048201526000926001600160601b0316916001600160a01b0316906370a0823190602401602060405180830381865afa15801562000fce573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ff4919062002128565b62001000919062002142565b905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663a9059cbb60e01b179091526200105d918591620010e816565b505050565b600062000efe82620011b9565b600080806200107f8585620011c4565b600081815260029690960160205260409095205494959350505050565b6000818152600283016020526040812081905562000f398383620011d2565b6000828152600284016020526040812082905562000f588484620011e0565b600062000f398383620011ee565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65649082015260009062001137906001600160a01b03851690849062001207565b8051909150156200105d578080602001905181019062001158919062002165565b6200105d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000084565b600062000efe825490565b600062000f39838362001218565b600062000f39838362001245565b600062000f39838362001350565b6000818152600183016020526040812054151562000f39565b606062000f588484600085620013a2565b600082600001828154811062001232576200123262001e69565b9060005260206000200154905092915050565b600081815260018301602052604081205480156200133e5760006200126c60018362002008565b8554909150600090620012829060019062002008565b9050818114620012ee576000866000018281548110620012a657620012a662001e69565b9060005260206000200154905080876000018481548110620012cc57620012cc62001e69565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062001302576200130262002183565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000efe565b600091505062000efe565b5092915050565b6000818152600183016020526040812054620013995750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000efe565b50600062000efe565b606082471015620014055760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000084565b600080866001600160a01b03168587604051620014239190620021bf565b60006040518083038185875af1925050503d806000811462001462576040519150601f19603f3d011682016040523d82523d6000602084013e62001467565b606091505b5090925090506200147b8783838762001486565b979650505050505050565b60608315620014fa578251600003620014f2576001600160a01b0385163b620014f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000084565b508162000f58565b62000f588383815115620015115781518083602001fd5b8060405162461bcd60e51b8152600401620000849190620021dd565b634e487b7160e01b600052604160045260246000fd5b6040516101c081016001600160401b03811182821017156200156957620015696200152d565b60405290565b60405160a081016001600160401b03811182821017156200156957620015696200152d565b60405160e081016001600160401b03811182821017156200156957620015696200152d565b604080519081016001600160401b03811182821017156200156957620015696200152d565b60405161010081016001600160401b03811182821017156200156957620015696200152d565b604051601f8201601f191681016001600160401b03811182821017156200162f576200162f6200152d565b604052919050565b80516001600160a01b03811681146200164f57600080fd5b919050565b80516001600160401b03811681146200164f57600080fd5b805161ffff811681146200164f57600080fd5b805163ffffffff811681146200164f57600080fd5b805180151581146200164f57600080fd5b60006101c08284031215620016b957600080fd5b620016c362001543565b9050620016d08262001637565b8152620016e0602083016200166c565b6020820152620016f3604083016200167f565b604082015262001706606083016200166c565b606082015262001719608083016200167f565b60808201526200172c60a083016200166c565b60a08201526200173f60c083016200166c565b60c08201526200175260e0830162001637565b60e0820152610100620017678184016200167f565b908201526101206200177b8382016200167f565b908201526101406200178f8382016200166c565b90820152610160620017a38382016200167f565b90820152610180620017b78382016200167f565b908201526101a0620017cb83820162001694565b9082015292915050565b80516001600160801b03811681146200164f57600080fd5b6000606082840312156200180057600080fd5b604051606081016001600160401b03811182821017156200182557620018256200152d565b604052905080620018368362001694565b81526200184660208401620017d5565b60208201526200185960408401620017d5565b60408201525092915050565b60006001600160401b038211156200188157620018816200152d565b5060051b60200190565b600082601f8301126200189d57600080fd5b81516020620018b6620018b08362001865565b62001604565b82815260a09283028501820192828201919087851115620018d657600080fd5b8387015b85811015620019635781818a031215620018f45760008081fd5b620018fe6200156f565b620019098262001637565b8152620019188683016200167f565b8682015260406200192b81840162001654565b9082015260606200193e83820162001654565b9082015260806200195183820162001694565b908201528452928401928101620018da565b5090979650505050505050565b600082601f8301126200198257600080fd5b8151602062001995620018b08362001865565b82815260e09283028501820192828201919087851115620019b557600080fd5b8387015b85811015620019635781818a031215620019d35760008081fd5b620019dd62001594565b620019e88262001637565b8152620019f78683016200167f565b86820152604062001a0a8184016200167f565b90820152606062001a1d8382016200166c565b90820152608062001a308382016200167f565b9082015260a062001a438382016200167f565b9082015260c062001a5683820162001694565b908201528452928401928101620019b9565b600082601f83011262001a7a57600080fd5b8151602062001a8d620018b08362001865565b82815260069290921b8401810191818101908684111562001aad57600080fd5b8286015b8481101562001b03576040818903121562001acc5760008081fd5b62001ad6620015b9565b62001ae18262001637565b815262001af08583016200166c565b8186015283529183019160400162001ab1565b509695505050505050565b60008060008060008086880361038081121562001b2a57600080fd5b6101008082121562001b3b57600080fd5b62001b45620015de565b915062001b528962001637565b825262001b6260208a0162001654565b602083015262001b7560408a0162001654565b604083015262001b8860608a0162001654565b606083015260808901516001600160601b038116811462001ba857600080fd5b608083015262001bbb60a08a0162001637565b60a083015262001bce60c08a0162001637565b60c083015262001be160e08a0162001637565b60e083015281975062001bf78a828b01620016a5565b9650505062001c0b886102c08901620017ed565b6103208801519094506001600160401b038082111562001c2a57600080fd5b62001c388a838b016200188b565b945061034089015191508082111562001c5057600080fd5b62001c5e8a838b0162001970565b935061036089015191508082111562001c7657600080fd5b5062001c8589828a0162001a68565b9150509295509295509295565b80516001600160a01b03168252602081015162001cb5602084018261ffff169052565b50604081015162001cce604084018263ffffffff169052565b50606081015162001ce5606084018261ffff169052565b50608081015162001cfe608084018263ffffffff169052565b5060a081015162001d1560a084018261ffff169052565b5060c081015162001d2c60c084018261ffff169052565b5060e081015162001d4860e08401826001600160a01b03169052565b506101008181015163ffffffff90811691840191909152610120808301518216908401526101408083015161ffff16908401526101608083015182169084015261018080830151909116908301526101a0908101511515910152565b82516001600160a01b031681526020808401516001600160401b0390811691830191909152604080850151821690830152606080850151918216908301526102c082019050608084015162001e0460808401826001600160601b03169052565b5060a084015162001e2060a08401826001600160a01b03169052565b5060c084015162001e3c60c08401826001600160a01b03169052565b5060e084015162001e5860e08401826001600160a01b03169052565b5062000f3961010083018462001c92565b634e487b7160e01b600052603260045260246000fd5b602080825282518282018190526000919060409081850190868401855b8281101562001f0157815180516001600160a01b031685528681015163ffffffff1687860152858101516001600160401b03908116878701526060808301519091169086015260809081015115159085015260a0909301929085019060010162001e9c565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b8281101562001f0157815180516001600160a01b031685528681015163ffffffff908116888701528682015181168787015260608083015161ffff169087015260808083015182169087015260a0808301519091169086015260c09081015115159085015260e0909301929085019060010162001f2b565b6020808252825182820181905260009190848201906040850190845b8181101562001fe65783516001600160a01b03168352928401929184019160010162001fbf565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111562000efe5762000efe62001ff2565b60008162002030576200203062001ff2565b506000190190565b63ffffffff81811683821601908082111562001349576200134962001ff2565b6000604080830163ffffffff8616845260206040602086015281865180845260608701915060208801935060005b81811015620020ba57845180516001600160a01b0316845284015161ffff1684840152938301939185019160010162002086565b509098975050505050505050565b808202811582820484141762000efe5762000efe62001ff2565b6000826200210057634e487b7160e01b600052601260045260246000fd5b500490565b6001600160601b0382811682821603908082111562001349576200134962001ff2565b6000602082840312156200213b57600080fd5b5051919050565b818103600083128015838313168383128216171562001349576200134962001ff2565b6000602082840312156200217857600080fd5b62000f398262001694565b634e487b7160e01b600052603160045260246000fd5b60005b83811015620021b65781810151838201526020016200219c565b50506000910152565b60008251620021d381846020870162002199565b9190910192915050565b6020815260008251806020840152620021fe81604085016020870162002199565b601f01601f19169190910160400192915050565b60805160a05160c05160e0516101005161012051610140516101605161018051615f94620023406000396000818161036101528181610f1801526137a3015260008181610332015281816117160152613774015260008181610303015281816113cc0152818161143101528181611c8901528181611d17015261374501526000818161026f01528181610a4e0152818161183e0152818161223701528181612acf01526136b101526000818161023f01528181611de80152613681015260008181610210015281816110c30152818161164201528181611a5f01528181611b6001528181612666015281816136520152613a410152600081816102cf01528181611c2c015261371101526000818161029f015281816127c101526136e10152600061243f0152615f946000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80637437ff9f116100f9578063c92b283211610097578063eff7cc4811610071578063eff7cc48146109fc578063f25561fd14610a04578063f2fde38b14610a17578063fbca3b7414610a2a57600080fd5b8063c92b2832146109ce578063d09dc339146109e1578063df0aa9e9146109e957600080fd5b8063856c8247116100d3578063856c8247146108a05780638da5cb5b146108b35780639a113c36146108c4578063b06d41bc146109b857600080fd5b80637437ff9f146106c057806376f6ae761461088557806379ba50971461089857600080fd5b806348a98aa411610166578063549e946f11610140578063549e946f1461066957806354b714681461067c578063599f64311461069c578063704b6c02146106ad57600080fd5b806348a98aa4146105c7578063528d4a92146105f2578063546719cd1461060557600080fd5b806320487ded1161019757806320487ded146105705780634120fccd146105915780634816f4f7146105b257600080fd5b806306285c69146101be5780631772047e146103a7578063181f5a7714610527575b600080fd5b6103916040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101919091526040518061010001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b60405161039e9190614ba3565b60405180910390f35b6104bb6103b5366004614bd7565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152506001600160a01b03166000908152600c6020908152604091829020825160e081018452905463ffffffff8082168352640100000000820481169383019390935261ffff68010000000000000000820416938201939093526a01000000000000000000008304821660608201526e0100000000000000000000000000008304909116608082015260ff720100000000000000000000000000000000000083048116151560a0830152730100000000000000000000000000000000000000909204909116151560c082015290565b60405161039e9190600060e08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015260c0830151151560c083015292915050565b6105636040518060400160405280601781526020017f45564d3245564d4f6e52616d7020312e352e302d64657600000000000000000081525081565b60405161039e9190614c44565b61058361057e366004614c85565b610a4a565b60405190815260200161039e565b610599610ea0565b60405167ffffffffffffffff909116815260200161039e565b6105c56105c0366004614e93565b610ec7565b005b6105da6105d5366004614fd0565b610edd565b6040516001600160a01b03909116815260200161039e565b6105c5610600366004615009565b610f8c565b61060d610fa0565b60405161039e919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6105c5610677366004615119565b611032565b600e546040516bffffffffffffffffffffffff909116815260200161039e565b6002546001600160a01b03166105da565b6105c56106bb366004614bd7565b6111ab565b610878604080516101c081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081019190915250604080516101c0810182526005546001600160a01b038082168352600160a01b820461ffff9081166020850152760100000000000000000000000000000000000000000000830463ffffffff908116958501959095527a0100000000000000000000000000000000000000000000000000008304811660608501527c0100000000000000000000000000000000000000000000000000000000928390048516608085015260065480821660a086015262010000808204831660c0870152640100000000820490931660e086015278010000000000000000000000000000000000000000000000008104861661010086015292909204841661012084015260075491821661014084015281048316610160830152660100000000000081049092166101808201526a010000000000000000000090910460ff1615156101a082015290565b60405161039e9190615242565b6105c5610893366004615251565b611275565b6105c56112d8565b6105996108ae366004614bd7565b6113a1565b6000546001600160a01b03166105da565b61096e6108d2366004614bd7565b604080516080810182526000808252602082018190529181018290526060810191909152506001600160a01b03166000908152600b60209081526040918290208251608081018452905463ffffffff8116825267ffffffffffffffff64010000000082048116938301939093526c0100000000000000000000000081049092169281019290925260ff600160a01b909104161515606082015290565b60408051825163ffffffff16815260208084015167ffffffffffffffff9081169183019190915283830151169181019190915260609182015115159181019190915260800161039e565b6109c061149c565b60405161039e92919061531a565b6105c56109dc36600461535c565b611597565b6105836115ff565b6105836109f73660046153ca565b6116bf565b6105c56124b3565b6105c5610a12366004615436565b612738565b6105c5610a25366004614bd7565b612749565b610a3d610a38366004615535565b61275a565b60405161039e9190615552565b60007f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168367ffffffffffffffff1614610aca576040517fd9a9cd6800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b6000610ae1610adc608085018561559f565b61278e565b9050610b11610af3602085018561559f565b8351909150610b056040870187615604565b9050846020015161291b565b6000600b81610b266080870160608801614bd7565b6001600160a01b0316815260208082019290925260409081016000208151608081018352905463ffffffff81168252640100000000810467ffffffffffffffff908116948301949094526c01000000000000000000000000810490931691810191909152600160a01b90910460ff16151560608201819052909150610bf357610bb56080850160608601614bd7565b6040517fa7499d200000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610ac1565b600654600090819064010000000090046001600160a01b031663ffdb4b37610c216080890160608a01614bd7565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015267ffffffffffffffff8a1660248201526044016040805180830381865afa158015610c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb09190615698565b90925090506000808080610cc760408b018b615604565b90501115610d0157610cf5610ce260808b0160608c01614bd7565b86610cf060408d018d615604565b612a84565b91945092509050610d1d565b8551610d1a9063ffffffff16662386f26fc100006156e1565b92505b60065460009062010000900461ffff1615610d7157610d6e6dffffffffffffffffffffffffffff607087901c16610d5760208d018d61559f565b9050610d6660408e018e615604565b905085612e66565b90505b60208781015160055460009267ffffffffffffffff9092169163ffffffff8716917a010000000000000000000000000000000000000000000000000000900461ffff1690610dc1908f018f61559f565b610dcc9291506156e1565b6005548c51610dfb91760100000000000000000000000000000000000000000000900463ffffffff16906156f8565b610e0591906156f8565b610e0f91906156f8565b610e29906dffffffffffffffffffffffffffff89166156e1565b610e3391906156e1565b9050867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1682828a6040015167ffffffffffffffff1688610e7091906156e1565b610e7a91906156f8565b610e8491906156f8565b610e8e919061570b565b99505050505050505050505b92915050565b600e54600090610ec290600160801b900467ffffffffffffffff16600161572d565b905090565b610ecf612f36565b610ed98282612f8e565b5050565b6040517fbbe4f6db0000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063bbe4f6db90602401602060405180830381865afa158015610f61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f85919061574e565b9392505050565b610f9461330a565b610f9d81613364565b50565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff8082168352600160801b80830463ffffffff166020850152600160a01b90920460ff161515938301939093526004548084166060840152049091166080820152610ec2906137dd565b61103a612f36565b6001600160a01b03811661107a576040517f232cb97f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006110846115ff565b905060008112156110c1576040517f02075e0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316036111135761110e6001600160a01b038416838361388f565b505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015261110e9083906001600160a01b038616906370a0823190602401602060405180830381865afa158015611176573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119a919061576b565b6001600160a01b038616919061388f565b6000546001600160a01b031633148015906111d157506002546001600160a01b03163314155b15611208576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c906020015b60405180910390a150565b61127d612f36565b610ed98282808060200260200160405190810160405280939291908181526020016000905b828210156112ce576112bf60408302860136819003810190615784565b815260200190600101906112a2565b505050505061390f565b6001546001600160a01b031633146113325760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610ac1565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b038082166000908152600d6020526040812054909167ffffffffffffffff909116907f00000000000000000000000000000000000000000000000000000000000000001615610e9a5780600003610e9a576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611478573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8591906157c3565b60606000806114ab6008613b75565b90508067ffffffffffffffff8111156114c6576114c6614cd5565b60405190808252806020026020018201604052801561150b57816020015b60408051808201909152600080825260208201528152602001906001900390816114e45790505b50925060005b8181101561157457600080611527600884613b80565b915091506040518060400160405280836001600160a01b031681526020018261ffff1681525086848151811061155f5761155f6157e0565b60209081029190910101525050600101611511565b5050600e5491926c0100000000000000000000000090920463ffffffff16919050565b6000546001600160a01b031633148015906115bd57506002546001600160a01b03163314155b156115f4576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f9d600382613b9e565b600e546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916bffffffffffffffffffffffff16907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611691573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b5919061576b565b610ec291906157f6565b6040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815277ffffffffffffffff00000000000000000000000000000000608086901b1660048201526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632cbc26bb90602401602060405180830381865afa15801561175d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117819190615816565b156117b8576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382166117f8576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b0316331461183c576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168567ffffffffffffffff16146118b5576040517fd9a9cd6800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff86166004820152602401610ac1565b60006118c7610adc608087018761559f565b905060006118d86040870187615604565b91506118fe90506118ec602088018861559f565b9050836000015183856020015161291b565b8015611a55576000805b82811015611a435761191d6040890189615604565b8281811061192d5761192d6157e0565b90506040020160200135600003611970576040517f5cf0444900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c600061198160408b018b615604565b84818110611991576119916157e0565b6119a79260206040909202019081019150614bd7565b6001600160a01b031681526020810191909152604001600020547201000000000000000000000000000000000000900460ff1615611a3b57611a2e6119ef60408a018a615604565b838181106119ff576119ff6157e0565b905060400201803603810190611a159190615833565b60065464010000000090046001600160a01b0316613d31565b611a3890836156f8565b91505b600101611908565b508015611a5357611a5381613e52565b505b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611a8f6080880160608901614bd7565b6001600160a01b031603611af357600e8054869190600090611ac09084906bffffffffffffffffffffffff1661586d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550611c1a565b60065464010000000090046001600160a01b03166241e5be611b1b6080890160608a01614bd7565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039182166004820152602481018990527f00000000000000000000000000000000000000000000000000000000000000009091166044820152606401602060405180830381865afa158015611ba7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bcb919061576b565b600e8054600090611beb9084906bffffffffffffffffffffffff1661586d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b600e546bffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691161115611c87576040517fe5c7a49100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615611dd2576001600160a01b0384166000908152600d602052604081205467ffffffffffffffff169003611dd2576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611d5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8291906157c3565b6001600160a01b0385166000908152600d6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790555b604080516101a08101825267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526001600160a01b03861660208201526000918101611e65611e2b8a8061559f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613e5f92505050565b6001600160a01b03168152602001600e601081819054906101000a900467ffffffffffffffff16611e9590615892565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905567ffffffffffffffff168152602001846000015181526020016000151581526020018460200151611f3f576001600160a01b0387166000908152600d602052604081208054909190611f159067ffffffffffffffff16615892565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055611f42565b60005b67ffffffffffffffff168152602001611f6160808a0160608b01614bd7565b6001600160a01b03168152602001878152602001888060200190611f85919061559f565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001611fcc60408a018a615604565b808060200260200160405190810160405280939291908181526020016000905b828210156120185761200960408302860136819003810190615833565b81526020019060010190611fec565b505050505081526020018367ffffffffffffffff81111561203b5761203b614cd5565b60405190808252806020026020018201604052801561206e57816020015b60608152602001906001900390816120595790505b508152600060209091018190529091505b8281101561243857600061209660408a018a615604565b838181106120a6576120a66157e0565b9050604002018036038101906120bc9190615833565b905060006120ce8b8360000151610edd565b90506001600160a01b038116158061218457506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527faff2afbf0000000000000000000000000000000000000000000000000000000060048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa15801561215e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121829190615816565b155b156121c95781516040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610ac1565b6000816001600160a01b0316639a4575b96040518060a001604052808e80600001906121f5919061559f565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525067ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166020808301919091526001600160a01b03808f16604080850191909152918901516060840152885116608090920191909152517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526122c091906004016158b9565b6000604051808303816000875af11580156122df573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123079190810190615986565b9050602081602001515111156123985782516001600160a01b03166000908152600c602090815260409091205490820151516e01000000000000000000000000000090910463ffffffff1610156123985782516040517f36f536ca0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610ac1565b80516123a390613e5f565b5060408051606081019091526001600160a01b03831660808201528060a0810160405160208183030381529060405281526020018260000151815260200182602001518152506040516020016123f99190615a17565b604051602081830303815290604052856101600151858151811061241f5761241f6157e0565b602002602001018190525050505080600101905061207f565b50612463817f0000000000000000000000000000000000000000000000000000000000000000613f05565b6101808201526040517fd0c3c799bf9e2639de44391e7f524d229b2b55f5b1ea94b2bf7da42f7243dddd90612499908390615b0e565b60405180910390a16101800151925050505b949350505050565b6000546001600160a01b03163314612518576002546001600160a01b03163314612518576124e2600833614060565b612518576040517f195db95800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff16600081900361256c576040517f990e30bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546bffffffffffffffffffffffff16818110156125b7576040517f8d0f71d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006125c16115ff565b12156125f9576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060006126066008613b75565b905060005b818110156126f557600080612621600884613b80565b9092509050600087612641836bffffffffffffffffffffffff8a166156e1565b61264b919061570b565b90506126578187615c43565b955061269b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016846bffffffffffffffffffffffff841661388f565b6040516bffffffffffffffffffffffff821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a250505080600101905061260b565b5050600e80547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790555050565b612740612f36565b610f9d81614075565b61275161330a565b610f9d816141e7565b60606040517f9e7177c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518082019091526000808252602082015260008290036127ef57506040805180820190915267ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016815260006020820152610e9a565b60006127fb8385615c68565b90507fe7e230f0000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000821601612868576128538360048187615cb0565b8101906128609190615cda565b915050610e9a565b7f6859a837000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008216016128e95760408051808201909152806128c98560048189615cb0565b8101906128d69190615d06565b815260006020909101529150610e9a9050565b6040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006547801000000000000000000000000000000000000000000000000900463ffffffff1680851115612984576040517f869337890000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610ac1565b6006547c0100000000000000000000000000000000000000000000000000000000900463ffffffff168411156129e6576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554600160a01b900461ffff16831115612a2d576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81612a7d576007546a0100000000000000000000900460ff1615612a7d576040517fee433e9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6000808083815b81811015612e5a576000878783818110612aa757612aa76157e0565b905060400201803603810190612abd9190615833565b905060006001600160a01b0316612af87f00000000000000000000000000000000000000000000000000000000000000008360000151610edd565b6001600160a01b031603612b465780516040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610ac1565b80516001600160a01b03166000908152600c6020908152604091829020825160e081018452905463ffffffff8082168352640100000000820481169383019390935261ffff68010000000000000000820416938201939093526a01000000000000000000008304821660608201526e0100000000000000000000000000008304909116608082015260ff720100000000000000000000000000000000000083048116151560a0830152730100000000000000000000000000000000000000909204909116151560c08201819052612c7e57600754612c2f9061ffff16662386f26fc100006156e1565b612c3990886156f8565b600754909750612c559062010000900463ffffffff1687615d1f565b600754909650612c75906601000000000000900463ffffffff1686615d1f565b94505050612e52565b604081015160009061ffff1615612da25760008c6001600160a01b031684600001516001600160a01b031614612d455760065484516040517f4ab35b0b0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526401000000009092041690634ab35b0b90602401602060405180830381865afa158015612d1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3e9190615d3c565b9050612d48565b508a5b620186a0836040015161ffff16612d8a8660200151847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166142a890919063ffffffff16565b612d9491906156e1565b612d9e919061570b565b9150505b6060820151612db19088615d1f565b9650816080015186612dc39190615d1f565b8251909650600090612de29063ffffffff16662386f26fc100006156e1565b905080821015612e0157612df6818a6156f8565b985050505050612e52565b6000836020015163ffffffff16662386f26fc10000612e2091906156e1565b905080831115612e4057612e34818b6156f8565b99505050505050612e52565b612e4a838b6156f8565b995050505050505b600101612a8b565b50509450945094915050565b60008063ffffffff8316612e7b6080866156e1565b612e87876102206156f8565b612e9191906156f8565b612e9b91906156f8565b6005546006549192506000917c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690612edd9061ffff16846156e1565b612ee791906156f8565b60065490915062010000900461ffff16612f116dffffffffffffffffffffffffffff8916836156e1565b612f1b91906156e1565b612f2b90655af3107a40006156e1565b979650505050505050565b6000546001600160a01b03163314612f8c576002546001600160a01b03163314612f8c576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60005b825181101561321c576000838281518110612fae57612fae6157e0565b6020026020010151905060208160a0015163ffffffff16101561301b57805160a08201516040517f24ecdc020000000000000000000000000000000000000000000000000000000081526001600160a01b03909216600483015263ffffffff166024820152604401610ac1565b6040805160e08101825260208381015163ffffffff908116835284840151811682840190815260608087015161ffff9081168688019081526080808a0151861693880193845260a0808b0151871691890191825260c0808c01511515918a019182526001908a018181529b516001600160a01b03166000908152600c9099529990972097518854955192519451915197519a519087167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009096169590951764010000000092871692909202919091177fffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffff166801000000000000000093909216929092027fffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffff16176a010000000000000000000091841691909102177fffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffff166e01000000000000000000000000000093909216929092027fffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff1617720100000000000000000000000000000000000094151594909402939093177fffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffff16730100000000000000000000000000000000000000931515939093029290921790915501612f91565b507ff5791bc457b3bb990493cf5f655db46c25ccf5764c9b99b8969b4c72ea7df9d08260405161324c9190615d57565b60405180910390a160005b81518110156132c757600c6000838381518110613276576132766157e0565b6020908102919091018101516001600160a01b0316825281019190915260400160002080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600101613257565b50805115610ed9577ffb95a0042158e60a33e7b5bec100f3d95407b1a71bee6633bd54b8887449750b816040516132fe9190615552565b60405180910390a15050565b6000546001600160a01b03163314612f8c5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610ac1565b60e08101516001600160a01b03166133a8576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081610180015163ffffffff161015613404576101808101516040517f24ecdc020000000000000000000000000000000000000000000000000000000081526000600482015263ffffffff9091166024820152604401610ac1565b80600560008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601a6101000a81548161ffff021916908361ffff160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160006101000a81548161ffff021916908361ffff16021790555060c08201518160010160026101000a81548161ffff021916908361ffff16021790555060e08201518160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555061012082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160006101000a81548161ffff021916908361ffff1602179055506101608201518160020160026101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160020160066101000a81548163ffffffff021916908363ffffffff1602179055506101a082015181600201600a6101000a81548160ff0219169083151502179055509050507fe375c8cb6ea9807cd0371503b632b93da5ee0f1f64205db8b5b28b95d6b588b06040518061010001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152508260405161126a929190615df7565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261386b82606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff164261384f9190615e14565b85608001516fffffffffffffffffffffffffffffffff166142e5565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261110e90849061430d565b8051604081111561394c576040517fb5a10cfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e546c01000000000000000000000000900463ffffffff16156139a057600e5463ffffffff6c010000000000000000000000008204166bffffffffffffffffffffffff909116106139a0576139a06124b3565b60006139ac6008613b75565b90505b80156139ee5760006139cd6139c5600184615e14565b600890613b80565b5090506139db6008826143f2565b5050806139e790615e27565b90506139af565b506000805b82811015613af6576000848281518110613a0f57613a0f6157e0565b60200260200101516000015190506000858381518110613a3157613a316157e0565b60200260200101516020015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480613a8657506001600160a01b038216155b15613ac8576040517f4de938d10000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610ac1565b613ad860088361ffff8416614407565b50613ae761ffff821685615d1f565b935050508060010190506139f3565b50600e80547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd2490613b689083908690615e5c565b60405180910390a1505050565b6000610e9a8261441d565b6000808080613b8f8686614428565b909450925050505b9250929050565b8154600090613bba90600160801b900463ffffffff1642615e14565b90508015613c425760018301548354613bf5916fffffffffffffffffffffffffffffffff808216928116918591600160801b909104166142e5565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff000000000000000000000000000000000000000090911617600160801b4263ffffffff16021783555b60208201518354613c68916fffffffffffffffffffffffffffffffff9081169116614453565b835483511515600160a01b027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff9283161717845560208301516040808501518316600160801b0291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990613b689084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b81516040517fd02641a00000000000000000000000000000000000000000000000000000000081526001600160a01b03918216600482015260009182919084169063d02641a0906024016040805180830381865afa158015613d97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dbb9190615e7b565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116600003613e245783516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610ac1565b60208401516124ab907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316906142a8565b610f9d6003826000614469565b60008151602014613e9e57816040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610ac19190614c44565b600082806020019051810190613eb4919061576b565b90506001600160a01b03811180613ecc575061040081105b15610e9a57826040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610ac19190614c44565b60008060001b8284602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151604051602001613f9b9897969594939291906001600160a01b039889168152968816602088015267ffffffffffffffff95861660408801526060870194909452911515608086015290921660a0840152921660c082015260e08101919091526101000190565b6040516020818303038152906040528051906020012085610120015180519060200120866101400151604051602001613fd49190615eae565b604051602081830303815290604052805190602001208761016001516040516020016140009190615ec1565b60408051601f198184030181528282528051602091820120908301979097528101949094526060840192909252608083015260a082015260c081019190915260e00160405160208183030381529060405280519060200120905092915050565b6000610f85836001600160a01b038416614773565b60005b81518110156141b7576000828281518110614095576140956157e0565b60209081029190910181015160408051608080820183528385015163ffffffff90811683528385015167ffffffffffffffff908116848801908152606080880151831686880190815294880151151590860190815296516001600160a01b03166000908152600b90985294909620925183549451925195511515600160a01b027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9688166c0100000000000000000000000002969096167fffffffffffffffffffffff000000000000000000ffffffffffffffffffffffff93909716640100000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090951691161792909217919091169290921717905550600101614078565b507f067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e8160405161126a9190615ed4565b336001600160a01b0382160361423f5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610ac1565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000670de0b6b3a76400006142db837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff86166156e1565b610f85919061570b565b6000614304856142f584866156e1565b6142ff90876156f8565b614453565b95945050505050565b6000614362826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661477f9092919063ffffffff16565b80519091501561110e57808060200190518101906143809190615816565b61110e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610ac1565b6000610f85836001600160a01b03841661478e565b60006124ab846001600160a01b038516846147ab565b6000610e9a826147c8565b6000808061443685856147d2565b600081815260029690960160205260409095205494959350505050565b60008183106144625781610f85565b5090919050565b8254600160a01b900460ff16158061447f575081155b1561448957505050565b825460018401546fffffffffffffffffffffffffffffffff808316929116906000906144c290600160801b900463ffffffff1642615e14565b905080156145685781831115614504576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186015461453190839085908490600160801b90046fffffffffffffffffffffffffffffffff166142e5565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff16600160801b4263ffffffff160217875592505b84821015614605576001600160a01b0384166145ba576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610ac1565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b0385166044820152606401610ac1565b848310156146f157600186810154600160801b90046fffffffffffffffffffffffffffffffff1690600090829061463c9082615e14565b614646878a615e14565b61465091906156f8565b61465a919061570b565b90506001600160a01b0386166146a6576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610ac1565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b0387166044820152606401610ac1565b6146fb8584615e14565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6000610f8583836147de565b60606124ab84846000856147f6565b60008181526002830160205260408120819055610f8583836148dd565b600082815260028401602052604081208290556124ab84846148e9565b6000610e9a825490565b6000610f8583836148f5565b60008181526001830160205260408120541515610f85565b60608247101561486e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610ac1565b600080866001600160a01b0316858760405161488a9190615f55565b60006040518083038185875af1925050503d80600081146148c7576040519150601f19603f3d011682016040523d82523d6000602084013e6148cc565b606091505b5091509150612f2b8783838761491f565b6000610f858383614998565b6000610f858383614a92565b600082600001828154811061490c5761490c6157e0565b9060005260206000200154905092915050565b6060831561498e578251600003614987576001600160a01b0385163b6149875760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ac1565b50816124ab565b6124ab8383614ae1565b60008181526001830160205260408120548015614a815760006149bc600183615e14565b85549091506000906149d090600190615e14565b9050818114614a355760008660000182815481106149f0576149f06157e0565b9060005260206000200154905080876000018481548110614a1357614a136157e0565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614a4657614a46615f71565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610e9a565b6000915050610e9a565b5092915050565b6000818152600183016020526040812054614ad957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610e9a565b506000610e9a565b815115614af15781518083602001fd5b8060405162461bcd60e51b8152600401610ac19190614c44565b6001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401525060c0810151614b8860c08401826001600160a01b03169052565b5060e081015161110e60e08401826001600160a01b03169052565b6101008101610e9a8284614b0b565b6001600160a01b0381168114610f9d57600080fd5b8035614bd281614bb2565b919050565b600060208284031215614be957600080fd5b8135610f8581614bb2565b60005b83811015614c0f578181015183820152602001614bf7565b50506000910152565b60008151808452614c30816020860160208601614bf4565b601f01601f19169290920160200192915050565b602081526000610f856020830184614c18565b67ffffffffffffffff81168114610f9d57600080fd5b600060a08284031215614c7f57600080fd5b50919050565b60008060408385031215614c9857600080fd5b8235614ca381614c57565b9150602083013567ffffffffffffffff811115614cbf57600080fd5b614ccb85828601614c6d565b9150509250929050565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715614d0e57614d0e614cd5565b60405290565b6040516101c0810167ffffffffffffffff81118282101715614d0e57614d0e614cd5565b60405160a0810167ffffffffffffffff81118282101715614d0e57614d0e614cd5565b6040805190810167ffffffffffffffff81118282101715614d0e57614d0e614cd5565b604051601f8201601f1916810167ffffffffffffffff81118282101715614da757614da7614cd5565b604052919050565b600067ffffffffffffffff821115614dc957614dc9614cd5565b5060051b60200190565b63ffffffff81168114610f9d57600080fd5b8035614bd281614dd3565b803561ffff81168114614bd257600080fd5b8015158114610f9d57600080fd5b8035614bd281614e02565b600082601f830112614e2c57600080fd5b81356020614e41614e3c83614daf565b614d7e565b8083825260208201915060208460051b870101935086841115614e6357600080fd5b602086015b84811015614e88578035614e7b81614bb2565b8352918301918301614e68565b509695505050505050565b6000806040808486031215614ea757600080fd5b833567ffffffffffffffff80821115614ebf57600080fd5b818601915086601f830112614ed357600080fd5b81356020614ee3614e3c83614daf565b82815260e0928302850182019282820191908b851115614f0257600080fd5b958301955b84871015614fab5780878d031215614f1f5760008081fd5b614f27614ceb565b8735614f3281614bb2565b815287850135614f4181614dd3565b8186015287890135614f5281614dd3565b818a01526060614f63898201614df0565b90820152608088810135614f7681614dd3565b9082015260a0614f87898201614de5565b9082015260c0614f98898201614e10565b9082015283529586019591830191614f07565b5097505087013593505080831115614fc257600080fd5b5050614ccb85828601614e1b565b60008060408385031215614fe357600080fd5b8235614fee81614c57565b91506020830135614ffe81614bb2565b809150509250929050565b60006101c0828403121561501c57600080fd5b615024614d14565b61502d83614bc7565b815261503b60208401614df0565b602082015261504c60408401614de5565b604082015261505d60608401614df0565b606082015261506e60808401614de5565b608082015261507f60a08401614df0565b60a082015261509060c08401614df0565b60c08201526150a160e08401614bc7565b60e08201526101006150b4818501614de5565b908201526101206150c6848201614de5565b908201526101406150d8848201614df0565b908201526101606150ea848201614de5565b908201526101806150fc848201614de5565b908201526101a061510e848201614e10565b908201529392505050565b6000806040838503121561512c57600080fd5b8235614fee81614bb2565b80516001600160a01b031682526020810151615159602084018261ffff169052565b506040810151615171604084018263ffffffff169052565b506060810151615187606084018261ffff169052565b50608081015161519f608084018263ffffffff169052565b5060a08101516151b560a084018261ffff169052565b5060c08101516151cb60c084018261ffff169052565b5060e08101516151e660e08401826001600160a01b03169052565b506101008181015163ffffffff90811691840191909152610120808301518216908401526101408083015161ffff16908401526101608083015182169084015261018080830151909116908301526101a0908101511515910152565b6101c08101610e9a8284615137565b6000806020838503121561526457600080fd5b823567ffffffffffffffff8082111561527c57600080fd5b818501915085601f83011261529057600080fd5b81358181111561529f57600080fd5b8660208260061b85010111156152b457600080fd5b60209290920196919550909350505050565b60008151808452602080850194506020840160005b8381101561530f57815180516001600160a01b0316885283015161ffff1683880152604090960195908201906001016152db565b509495945050505050565b60408152600061532d60408301856152c6565b90508260208301529392505050565b80356fffffffffffffffffffffffffffffffff81168114614bd257600080fd5b60006060828403121561536e57600080fd5b6040516060810181811067ffffffffffffffff8211171561539157615391614cd5565b604052823561539f81614e02565b81526153ad6020840161533c565b60208201526153be6040840161533c565b60408201529392505050565b600080600080608085870312156153e057600080fd5b84356153eb81614c57565b9350602085013567ffffffffffffffff81111561540757600080fd5b61541387828801614c6d565b93505060408501359150606085013561542b81614bb2565b939692955090935050565b6000602080838503121561544957600080fd5b823567ffffffffffffffff81111561546057600080fd5b8301601f8101851361547157600080fd5b803561547f614e3c82614daf565b81815260a0918202830184019184820191908884111561549e57600080fd5b938501935b838510156155295780858a0312156154bb5760008081fd5b6154c3614d38565b85356154ce81614bb2565b8152858701356154dd81614dd3565b818801526040868101356154f081614c57565b9082015260608681013561550381614c57565b9082015260808681013561551681614e02565b90820152835293840193918501916154a3565b50979650505050505050565b60006020828403121561554757600080fd5b8135610f8581614c57565b6020808252825182820181905260009190848201906040850190845b818110156155935783516001600160a01b03168352928401929184019160010161556e565b50909695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126155d457600080fd5b83018035915067ffffffffffffffff8211156155ef57600080fd5b602001915036819003821315613b9757600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261563957600080fd5b83018035915067ffffffffffffffff82111561565457600080fd5b6020019150600681901b3603821315613b9757600080fd5b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114614bd257600080fd5b600080604083850312156156ab57600080fd5b6156b48361566c565b91506156c26020840161566c565b90509250929050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610e9a57610e9a6156cb565b80820180821115610e9a57610e9a6156cb565b60008261572857634e487b7160e01b600052601260045260246000fd5b500490565b67ffffffffffffffff818116838216019080821115614a8b57614a8b6156cb565b60006020828403121561576057600080fd5b8151610f8581614bb2565b60006020828403121561577d57600080fd5b5051919050565b60006040828403121561579657600080fd5b61579e614d5b565b82356157a981614bb2565b81526157b760208401614df0565b60208201529392505050565b6000602082840312156157d557600080fd5b8151610f8581614c57565b634e487b7160e01b600052603260045260246000fd5b8181036000831280158383131683831282161715614a8b57614a8b6156cb565b60006020828403121561582857600080fd5b8151610f8581614e02565b60006040828403121561584557600080fd5b61584d614d5b565b823561585881614bb2565b81526020928301359281019290925250919050565b6bffffffffffffffffffffffff818116838216019080821115614a8b57614a8b6156cb565b600067ffffffffffffffff8083168181036158af576158af6156cb565b6001019392505050565b602081526000825160a060208401526158d560c0840182614c18565b905067ffffffffffffffff602085015116604084015260408401516001600160a01b038082166060860152606086015160808601528060808701511660a086015250508091505092915050565b600082601f83011261593357600080fd5b815167ffffffffffffffff81111561594d5761594d614cd5565b6159606020601f19601f84011601614d7e565b81815284602083860101111561597557600080fd5b6124ab826020830160208701614bf4565b60006020828403121561599857600080fd5b815167ffffffffffffffff808211156159b057600080fd5b90830190604082860312156159c457600080fd5b6159cc614d5b565b8251828111156159db57600080fd5b6159e787828601615922565b8252506020830151828111156159fc57600080fd5b615a0887828601615922565b60208301525095945050505050565b602081526000825160606020840152615a336080840182614c18565b90506020840151601f1980858403016040860152615a518383614c18565b92506040860151915080858403016060860152506143048282614c18565b60008151808452602080850194506020840160005b8381101561530f57815180516001600160a01b031688528301518388015260409096019590820190600101615a84565b60008282518085526020808601955060208260051b8401016020860160005b84811015615b0157601f19868403018952615aef838351614c18565b98840198925090830190600101615ad3565b5090979650505050505050565b60208152615b2960208201835167ffffffffffffffff169052565b60006020830151615b4560408401826001600160a01b03169052565b5060408301516001600160a01b038116606084015250606083015167ffffffffffffffff8116608084015250608083015160a083015260a0830151615b8e60c084018215159052565b5060c083015167ffffffffffffffff811660e08401525060e0830151610100615bc1818501836001600160a01b03169052565b840151610120848101919091528401516101a061014080860182905291925090615bef6101c0860184614c18565b9250808601519050601f19610160818786030181880152615c108584615a6f565b945080880151925050610180818786030181880152615c2f8584615ab4565b970151959092019490945250929392505050565b6bffffffffffffffffffffffff828116828216039080821115614a8b57614a8b6156cb565b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015615ca85780818660040360031b1b83161692505b505092915050565b60008085851115615cc057600080fd5b83861115615ccd57600080fd5b5050820193919092039150565b600060408284031215615cec57600080fd5b615cf4614d5b565b8235815260208301356157b781614e02565b600060208284031215615d1857600080fd5b5035919050565b63ffffffff818116838216019080821115614a8b57614a8b6156cb565b600060208284031215615d4e57600080fd5b610f858261566c565b602080825282518282018190526000919060409081850190868401855b82811015615dea57815180516001600160a01b031685528681015163ffffffff908116888701528682015181168787015260608083015161ffff169087015260808083015182169087015260a0808301519091169086015260c09081015115159085015260e09093019290850190600101615d74565b5091979650505050505050565b6102c08101615e068285614b0b565b610f85610100830184615137565b81810381811115610e9a57610e9a6156cb565b600081615e3657615e366156cb565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b63ffffffff831681526040602082015260006124ab60408301846152c6565b600060408284031215615e8d57600080fd5b615e95614d5b565b615e9e8361566c565b815260208301516157b781614dd3565b602081526000610f856020830184615a6f565b602081526000610f856020830184615ab4565b602080825282518282018190526000919060409081850190868401855b82811015615dea57815180516001600160a01b031685528681015163ffffffff16878601528581015167ffffffffffffffff908116878701526060808301519091169086015260809081015115159085015260a09093019290850190600101615ef1565b60008251615f67818460208701614bf4565b9190910192915050565b634e487b7160e01b600052603160045260246000fdfea164736f6c6343000818000a",
+}
+
+var EVM2EVMOnRampABI = EVM2EVMOnRampMetaData.ABI
+
+var EVM2EVMOnRampBin = EVM2EVMOnRampMetaData.Bin
+
+func DeployEVM2EVMOnRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMOnRampStaticConfig, dynamicConfig EVM2EVMOnRampDynamicConfig, rateLimiterConfig RateLimiterConfig, feeTokenConfigs []EVM2EVMOnRampFeeTokenConfigArgs, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (common.Address, *types.Transaction, *EVM2EVMOnRamp, error) {
+ parsed, err := EVM2EVMOnRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMOnRampBin), backend, staticConfig, dynamicConfig, rateLimiterConfig, feeTokenConfigs, tokenTransferFeeConfigArgs, nopsAndWeights)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMOnRamp{address: address, abi: *parsed, EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMOnRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMOnRampCaller
+ EVM2EVMOnRampTransactor
+ EVM2EVMOnRampFilterer
+}
+
+type EVM2EVMOnRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampSession struct {
+ Contract *EVM2EVMOnRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOnRampCallerSession struct {
+ Contract *EVM2EVMOnRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMOnRampTransactorSession struct {
+ Contract *EVM2EVMOnRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOnRampRaw struct {
+ Contract *EVM2EVMOnRamp
+}
+
+type EVM2EVMOnRampCallerRaw struct {
+ Contract *EVM2EVMOnRampCaller
+}
+
+type EVM2EVMOnRampTransactorRaw struct {
+ Contract *EVM2EVMOnRampTransactor
+}
+
+func NewEVM2EVMOnRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMOnRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMOnRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMOnRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRamp{address: address, abi: abi, EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMOnRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMOnRampCaller, error) {
+ contract, err := bindEVM2EVMOnRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMOnRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMOnRampTransactor, error) {
+ contract, err := bindEVM2EVMOnRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMOnRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMOnRampFilterer, error) {
+ contract, err := bindEVM2EVMOnRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMOnRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMOnRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOnRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "currentRateLimiterState")
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOnRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOnRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOnRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOnRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampDynamicConfig)).(*EVM2EVMOnRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetDynamicConfig() (EVM2EVMOnRampDynamicConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetDynamicConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetDynamicConfig() (EVM2EVMOnRampDynamicConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetDynamicConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetFee(opts *bind.CallOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getFee", destChainSelector, message)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetFee(destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetFee(&_EVM2EVMOnRamp.CallOpts, destChainSelector, message)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetFee(destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetFee(&_EVM2EVMOnRamp.CallOpts, destChainSelector, message)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getFeeTokenConfig", token)
+
+ if err != nil {
+ return *new(EVM2EVMOnRampFeeTokenConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampFeeTokenConfig)).(*EVM2EVMOnRampFeeTokenConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetFeeTokenConfig(token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetFeeTokenConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetFeeTokenConfig(token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetFeeTokenConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getNopFeesJuels")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetNopFeesJuels() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetNopFeesJuels(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetNopFeesJuels() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetNopFeesJuels(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetNops(opts *bind.CallOpts) (GetNops,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getNops")
+
+ outstruct := new(GetNops)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.NopsAndWeights = *abi.ConvertType(out[0], new([]EVM2EVMOnRampNopAndWeight)).(*[]EVM2EVMOnRampNopAndWeight)
+ outstruct.WeightsTotal = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetNops() (GetNops,
+
+ error) {
+ return _EVM2EVMOnRamp.Contract.GetNops(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetNops() (GetNops,
+
+ error) {
+ return _EVM2EVMOnRamp.Contract.GetNops(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetPoolBySourceToken(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getPoolBySourceToken", arg0, sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetPoolBySourceToken(arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOnRamp.CallOpts, arg0, sourceToken)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetPoolBySourceToken(arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOnRamp.CallOpts, arg0, sourceToken)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getSenderNonce", sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetSenderNonce(&_EVM2EVMOnRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetSenderNonce(&_EVM2EVMOnRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOnRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOnRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampStaticConfig)).(*EVM2EVMOnRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetStaticConfig() (EVM2EVMOnRampStaticConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetStaticConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetStaticConfig() (EVM2EVMOnRampStaticConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetStaticConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetSupportedTokens(opts *bind.CallOpts, arg0 uint64) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getSupportedTokens", arg0)
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetSupportedTokens(arg0 uint64) ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetSupportedTokens(&_EVM2EVMOnRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetSupportedTokens(arg0 uint64) ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetSupportedTokens(&_EVM2EVMOnRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getTokenLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getTokenTransferFeeConfig", token)
+
+ if err != nil {
+ return *new(EVM2EVMOnRampTokenTransferFeeConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampTokenTransferFeeConfig)).(*EVM2EVMOnRampTokenTransferFeeConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetTokenTransferFeeConfig(token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenTransferFeeConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetTokenTransferFeeConfig(token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenTransferFeeConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.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
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.LinkAvailableForPayment(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.LinkAvailableForPayment(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.Owner(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.Owner(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOnRamp.Contract.TypeAndVersion(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOnRamp.Contract.TypeAndVersion(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.AcceptOwnership(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.AcceptOwnership(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ForwardFromRouter(opts *bind.TransactOpts, destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "forwardFromRouter", destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ForwardFromRouter(destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ForwardFromRouter(&_EVM2EVMOnRamp.TransactOpts, destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ForwardFromRouter(destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ForwardFromRouter(&_EVM2EVMOnRamp.TransactOpts, destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) PayNops(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "payNops")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) PayNops() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.PayNops(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) PayNops() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.PayNops(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setAdmin", newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAdmin(&_EVM2EVMOnRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAdmin(&_EVM2EVMOnRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setDynamicConfig", dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetDynamicConfig(dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetDynamicConfig(&_EVM2EVMOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetDynamicConfig(dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetDynamicConfig(&_EVM2EVMOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setFeeTokenConfig", feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetFeeTokenConfig(feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetFeeTokenConfig(&_EVM2EVMOnRamp.TransactOpts, feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetFeeTokenConfig(feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetFeeTokenConfig(&_EVM2EVMOnRamp.TransactOpts, feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetNops(opts *bind.TransactOpts, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setNops", nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetNops(nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetNops(&_EVM2EVMOnRamp.TransactOpts, nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetNops(nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetNops(&_EVM2EVMOnRamp.TransactOpts, nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setRateLimiterConfig", config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOnRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOnRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setTokenTransferFeeConfig", tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetTokenTransferFeeConfig(tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetTokenTransferFeeConfig(&_EVM2EVMOnRamp.TransactOpts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetTokenTransferFeeConfig(tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetTokenTransferFeeConfig(&_EVM2EVMOnRamp.TransactOpts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.TransferOwnership(&_EVM2EVMOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.TransferOwnership(&_EVM2EVMOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "withdrawNonLinkFees", feeToken, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) WithdrawNonLinkFees(feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.WithdrawNonLinkFees(&_EVM2EVMOnRamp.TransactOpts, feeToken, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) WithdrawNonLinkFees(feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.WithdrawNonLinkFees(&_EVM2EVMOnRamp.TransactOpts, feeToken, to)
+}
+
+type EVM2EVMOnRampAdminSetIterator struct {
+ Event *EVM2EVMOnRampAdminSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAdminSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAdminSet)
+ 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(EVM2EVMOnRampAdminSet)
+ 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 *EVM2EVMOnRampAdminSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAdminSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAdminSet struct {
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAdminSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAdminSetIterator{contract: _EVM2EVMOnRamp.contract, event: "AdminSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAdminSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAdminSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AdminSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAdminSet(log types.Log) (*EVM2EVMOnRampAdminSet, error) {
+ event := new(EVM2EVMOnRampAdminSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AdminSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampCCIPSendRequestedIterator struct {
+ Event *EVM2EVMOnRampCCIPSendRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampCCIPSendRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampCCIPSendRequested)
+ 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(EVM2EVMOnRampCCIPSendRequested)
+ 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 *EVM2EVMOnRampCCIPSendRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampCCIPSendRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampCCIPSendRequested struct {
+ Message InternalEVM2EVMMessage
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterCCIPSendRequested(opts *bind.FilterOpts) (*EVM2EVMOnRampCCIPSendRequestedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "CCIPSendRequested")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampCCIPSendRequestedIterator{contract: _EVM2EVMOnRamp.contract, event: "CCIPSendRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "CCIPSendRequested")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampCCIPSendRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "CCIPSendRequested", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseCCIPSendRequested(log types.Log) (*EVM2EVMOnRampCCIPSendRequested, error) {
+ event := new(EVM2EVMOnRampCCIPSendRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "CCIPSendRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampConfigChangedIterator struct {
+ Event *EVM2EVMOnRampConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampConfigChanged)
+ 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(EVM2EVMOnRampConfigChanged)
+ 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 *EVM2EVMOnRampConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigChangedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampConfigChangedIterator{contract: _EVM2EVMOnRamp.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampConfigChanged)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigChanged", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseConfigChanged(log types.Log) (*EVM2EVMOnRampConfigChanged, error) {
+ event := new(EVM2EVMOnRampConfigChanged)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampConfigSetIterator struct {
+ Event *EVM2EVMOnRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampConfigSet)
+ 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(EVM2EVMOnRampConfigSet)
+ 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 *EVM2EVMOnRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampConfigSet struct {
+ StaticConfig EVM2EVMOnRampStaticConfig
+ DynamicConfig EVM2EVMOnRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMOnRampConfigSet, error) {
+ event := new(EVM2EVMOnRampConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampFeeConfigSetIterator struct {
+ Event *EVM2EVMOnRampFeeConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampFeeConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampFeeConfigSet)
+ 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(EVM2EVMOnRampFeeConfigSet)
+ 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 *EVM2EVMOnRampFeeConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampFeeConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampFeeConfigSet struct {
+ FeeConfig []EVM2EVMOnRampFeeTokenConfigArgs
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampFeeConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "FeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampFeeConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "FeeConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampFeeConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "FeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "FeeConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseFeeConfigSet(log types.Log) (*EVM2EVMOnRampFeeConfigSet, error) {
+ event := new(EVM2EVMOnRampFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "FeeConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampNopPaidIterator struct {
+ Event *EVM2EVMOnRampNopPaid
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampNopPaidIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampNopPaid)
+ 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(EVM2EVMOnRampNopPaid)
+ 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 *EVM2EVMOnRampNopPaidIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampNopPaidIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampNopPaid struct {
+ Nop common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*EVM2EVMOnRampNopPaidIterator, error) {
+
+ var nopRule []interface{}
+ for _, nopItem := range nop {
+ nopRule = append(nopRule, nopItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "NopPaid", nopRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampNopPaidIterator{contract: _EVM2EVMOnRamp.contract, event: "NopPaid", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchNopPaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error) {
+
+ var nopRule []interface{}
+ for _, nopItem := range nop {
+ nopRule = append(nopRule, nopItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "NopPaid", nopRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampNopPaid)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopPaid", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseNopPaid(log types.Log) (*EVM2EVMOnRampNopPaid, error) {
+ event := new(EVM2EVMOnRampNopPaid)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopPaid", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampNopsSetIterator struct {
+ Event *EVM2EVMOnRampNopsSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampNopsSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampNopsSet)
+ 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(EVM2EVMOnRampNopsSet)
+ 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 *EVM2EVMOnRampNopsSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampNopsSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampNopsSet struct {
+ NopWeightsTotal *big.Int
+ NopsAndWeights []EVM2EVMOnRampNopAndWeight
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterNopsSet(opts *bind.FilterOpts) (*EVM2EVMOnRampNopsSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "NopsSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampNopsSetIterator{contract: _EVM2EVMOnRamp.contract, event: "NopsSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchNopsSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopsSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "NopsSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampNopsSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopsSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseNopsSet(log types.Log) (*EVM2EVMOnRampNopsSet, error) {
+ event := new(EVM2EVMOnRampNopsSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopsSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMOnRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampOwnershipTransferRequested)
+ 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(EVM2EVMOnRampOwnershipTransferRequested)
+ 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 *EVM2EVMOnRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampOwnershipTransferRequestedIterator{contract: _EVM2EVMOnRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOnRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMOnRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampOwnershipTransferred)
+ 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(EVM2EVMOnRampOwnershipTransferred)
+ 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 *EVM2EVMOnRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampOwnershipTransferredIterator{contract: _EVM2EVMOnRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampOwnershipTransferred)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMOnRampOwnershipTransferred, error) {
+ event := new(EVM2EVMOnRampOwnershipTransferred)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator struct {
+ Event *EVM2EVMOnRampTokenTransferFeeConfigDeleted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampTokenTransferFeeConfigDeleted)
+ 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(EVM2EVMOnRampTokenTransferFeeConfigDeleted)
+ 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 *EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigDeleted struct {
+ Tokens []common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterTokenTransferFeeConfigDeleted(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "TokenTransferFeeConfigDeleted")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator{contract: _EVM2EVMOnRamp.contract, event: "TokenTransferFeeConfigDeleted", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchTokenTransferFeeConfigDeleted(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigDeleted) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "TokenTransferFeeConfigDeleted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigDeleted)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigDeleted", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseTokenTransferFeeConfigDeleted(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigDeleted, error) {
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigDeleted)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigDeleted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigSetIterator struct {
+ Event *EVM2EVMOnRampTokenTransferFeeConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ 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(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ 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 *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigSet struct {
+ TransferFeeConfig []EVM2EVMOnRampTokenTransferFeeConfigArgs
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "TokenTransferFeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTokenTransferFeeConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "TokenTransferFeeConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "TokenTransferFeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseTokenTransferFeeConfigSet(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigSet, error) {
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampTokensConsumedIterator struct {
+ Event *EVM2EVMOnRampTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampTokensConsumed)
+ 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(EVM2EVMOnRampTokensConsumed)
+ 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 *EVM2EVMOnRampTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*EVM2EVMOnRampTokensConsumedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTokensConsumedIterator{contract: _EVM2EVMOnRamp.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampTokensConsumed)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokensConsumed", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseTokensConsumed(log types.Log) (*EVM2EVMOnRampTokensConsumed, error) {
+ event := new(EVM2EVMOnRampTokensConsumed)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetNops struct {
+ NopsAndWeights []EVM2EVMOnRampNopAndWeight
+ WeightsTotal *big.Int
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMOnRamp.abi.Events["AdminSet"].ID:
+ return _EVM2EVMOnRamp.ParseAdminSet(log)
+ case _EVM2EVMOnRamp.abi.Events["CCIPSendRequested"].ID:
+ return _EVM2EVMOnRamp.ParseCCIPSendRequested(log)
+ case _EVM2EVMOnRamp.abi.Events["ConfigChanged"].ID:
+ return _EVM2EVMOnRamp.ParseConfigChanged(log)
+ case _EVM2EVMOnRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["FeeConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseFeeConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["NopPaid"].ID:
+ return _EVM2EVMOnRamp.ParseNopPaid(log)
+ case _EVM2EVMOnRamp.abi.Events["NopsSet"].ID:
+ return _EVM2EVMOnRamp.ParseNopsSet(log)
+ case _EVM2EVMOnRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMOnRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMOnRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMOnRamp.ParseOwnershipTransferred(log)
+ case _EVM2EVMOnRamp.abi.Events["TokenTransferFeeConfigDeleted"].ID:
+ return _EVM2EVMOnRamp.ParseTokenTransferFeeConfigDeleted(log)
+ case _EVM2EVMOnRamp.abi.Events["TokenTransferFeeConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseTokenTransferFeeConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["TokensConsumed"].ID:
+ return _EVM2EVMOnRamp.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMOnRampAdminSet) Topic() common.Hash {
+ return common.HexToHash("0x8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c")
+}
+
+func (EVM2EVMOnRampCCIPSendRequested) Topic() common.Hash {
+ return common.HexToHash("0xd0c3c799bf9e2639de44391e7f524d229b2b55f5b1ea94b2bf7da42f7243dddd")
+}
+
+func (EVM2EVMOnRampConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (EVM2EVMOnRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xe375c8cb6ea9807cd0371503b632b93da5ee0f1f64205db8b5b28b95d6b588b0")
+}
+
+func (EVM2EVMOnRampFeeConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e")
+}
+
+func (EVM2EVMOnRampNopPaid) Topic() common.Hash {
+ return common.HexToHash("0x55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f")
+}
+
+func (EVM2EVMOnRampNopsSet) Topic() common.Hash {
+ return common.HexToHash("0x8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd24")
+}
+
+func (EVM2EVMOnRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMOnRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (EVM2EVMOnRampTokenTransferFeeConfigDeleted) Topic() common.Hash {
+ return common.HexToHash("0xfb95a0042158e60a33e7b5bec100f3d95407b1a71bee6633bd54b8887449750b")
+}
+
+func (EVM2EVMOnRampTokenTransferFeeConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xf5791bc457b3bb990493cf5f655db46c25ccf5764c9b99b8969b4c72ea7df9d0")
+}
+
+func (EVM2EVMOnRampTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRamp) Address() common.Address {
+ return _EVM2EVMOnRamp.address
+}
+
+type EVM2EVMOnRampInterface interface {
+ CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error)
+
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOnRampDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetFee(opts *bind.CallOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error)
+
+ GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampFeeTokenConfig, error)
+
+ GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error)
+
+ GetNops(opts *bind.CallOpts) (GetNops,
+
+ error)
+
+ GetPoolBySourceToken(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address) (common.Address, error)
+
+ GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOnRampStaticConfig, error)
+
+ GetSupportedTokens(opts *bind.CallOpts, arg0 uint64) ([]common.Address, error)
+
+ GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error)
+
+ LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ForwardFromRouter(opts *bind.TransactOpts, destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error)
+
+ PayNops(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error)
+
+ SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error)
+
+ SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error)
+
+ SetNops(opts *bind.TransactOpts, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error)
+
+ SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error)
+
+ SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error)
+
+ FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAdminSetIterator, error)
+
+ WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAdminSet) (event.Subscription, error)
+
+ ParseAdminSet(log types.Log) (*EVM2EVMOnRampAdminSet, error)
+
+ FilterCCIPSendRequested(opts *bind.FilterOpts) (*EVM2EVMOnRampCCIPSendRequestedIterator, error)
+
+ WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error)
+
+ ParseCCIPSendRequested(log types.Log) (*EVM2EVMOnRampCCIPSendRequested, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*EVM2EVMOnRampConfigChanged, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMOnRampConfigSet, error)
+
+ FilterFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampFeeConfigSetIterator, error)
+
+ WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampFeeConfigSet) (event.Subscription, error)
+
+ ParseFeeConfigSet(log types.Log) (*EVM2EVMOnRampFeeConfigSet, error)
+
+ FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*EVM2EVMOnRampNopPaidIterator, error)
+
+ WatchNopPaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error)
+
+ ParseNopPaid(log types.Log) (*EVM2EVMOnRampNopPaid, error)
+
+ FilterNopsSet(opts *bind.FilterOpts) (*EVM2EVMOnRampNopsSetIterator, error)
+
+ WatchNopsSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopsSet) (event.Subscription, error)
+
+ ParseNopsSet(log types.Log) (*EVM2EVMOnRampNopsSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOnRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMOnRampOwnershipTransferred, error)
+
+ FilterTokenTransferFeeConfigDeleted(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator, error)
+
+ WatchTokenTransferFeeConfigDeleted(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigDeleted) (event.Subscription, error)
+
+ ParseTokenTransferFeeConfigDeleted(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigDeleted, error)
+
+ FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error)
+
+ WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error)
+
+ ParseTokenTransferFeeConfigSet(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigSet, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*EVM2EVMOnRampTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*EVM2EVMOnRampTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_0_0/evm_2_evm_onramp_1_0_0.go b/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_0_0/evm_2_evm_onramp_1_0_0.go
new file mode 100644
index 00000000000..6fd05d693a3
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_0_0/evm_2_evm_onramp_1_0_0.go
@@ -0,0 +1,2792 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_onramp_1_0_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMOnRampDynamicConfig struct {
+ Router common.Address
+ MaxTokensLength uint16
+ PriceRegistry common.Address
+ MaxDataSize uint32
+ MaxGasLimit uint64
+}
+
+type EVM2EVMOnRampFeeTokenConfig struct {
+ NetworkFeeAmountUSD *big.Int
+ GasMultiplier uint64
+ DestGasOverhead uint32
+ DestGasPerPayloadByte uint16
+ Enabled bool
+}
+
+type EVM2EVMOnRampFeeTokenConfigArgs struct {
+ Token common.Address
+ GasMultiplier uint64
+ NetworkFeeAmountUSD *big.Int
+ DestGasOverhead uint32
+ DestGasPerPayloadByte uint16
+ Enabled bool
+}
+
+type EVM2EVMOnRampNopAndWeight struct {
+ Nop common.Address
+ Weight uint16
+}
+
+type EVM2EVMOnRampStaticConfig struct {
+ LinkToken common.Address
+ ChainSelector uint64
+ DestChainSelector uint64
+ DefaultTxGasLimit uint64
+ MaxNopFeesJuels *big.Int
+ PrevOnRamp common.Address
+ ArmProxy common.Address
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfig struct {
+ MinFee uint32
+ MaxFee uint32
+ Ratio uint16
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigArgs struct {
+ Token common.Address
+ MinFee uint32
+ MaxFee uint32
+ Ratio uint16
+}
+
+type InternalEVM2EVMMessage struct {
+ SourceChainSelector uint64
+ SequenceNumber uint64
+ FeeTokenAmount *big.Int
+ Sender common.Address
+ Nonce uint64
+ GasLimit *big.Int
+ Strict bool
+ Receiver common.Address
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ MessageId [32]byte
+}
+
+type InternalPoolUpdate struct {
+ Token common.Address
+ Pool common.Address
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+var EVM2EVMOnRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"maxGasLimit\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"tokensAndPools\",\"type\":\"tuple[]\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"networkFeeAmountUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeTokenConfigs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFee\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"ratio\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"}],\"name\":\"InvalidNopAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTokenPoolConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWithdrawParams\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkBalanceNotSettled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxFeeBalanceReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MessageGasLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeCalledByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoFeesToPay\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoNopsToPay\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"NotAFeeToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdminOrNop\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PoolAlreadyAdded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PoolDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PriceNotFoundForToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustSetOriginalSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenPoolMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyNops\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"UnsupportedToken\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"AllowListEnabledSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structInternal.EVM2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"CCIPSendRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"maxGasLimit\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"networkFeeAmountUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeConfig\",\"type\":\"tuple[]\"}],\"name\":\"FeeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NopPaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nopWeightsTotal\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"NopsSet\",\"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\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFee\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"ratio\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"transferFeeConfig\",\"type\":\"tuple[]\"}],\"name\":\"TokenTransferFeeConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"removes\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"adds\",\"type\":\"tuple[]\"}],\"name\":\"applyPoolUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"}],\"name\":\"forwardFromRouter\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"maxGasLimit\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getFeeTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"networkFeeAmountUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfig\",\"name\":\"feeTokenConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNopFeesJuels\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNops\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"weightsTotal\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getPoolBySourceToken\",\"outputs\":[{\"internalType\":\"contractIPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getSenderNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenTransferFeeConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFee\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"ratio\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"payNops\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setAllowListEnabled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"maxGasLimit\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"setDynamicConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"networkFeeAmountUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeTokenConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setFeeTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setNops\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFee\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFee\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"ratio\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setTokenTransferFeeConfig\",\"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\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawNonLinkFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101806040526012805460ff60c01b191690553480156200001f57600080fd5b50604051620081c9380380620081c9833981016040819052620000429162001eb3565b8333806000816200009a5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cd57620000cd8162000369565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080909301839052600380546001600160a01b031916909417600160801b9283021760ff60a01b1916600160a01b90910217909255029091176004555087516001600160a01b0316158062000176575060208801516001600160401b0316155b806200018d575060408801516001600160401b0316155b80620001a4575060608801516001600160401b0316155b80620001bb575060c08801516001600160a01b0316155b15620001da576040516306b7c75960e31b815260040160405180910390fd5b6020808901516040808b015181517fbdd59ac4dd1d82276c9a9c5d2656546346b9dcdb1f9b4204aed4ec15c23d7d3a948101949094526001600160401b039283169184019190915216606082015230608082015260a00160408051601f19818403018152918152815160209283012060809081528a516001600160a01b0390811660e052928b01516001600160401b0390811661010052918b015182166101205260608b015190911660a0908152908a01516001600160601b031660c0908152908a01518216610140528901511661016052620002b78762000414565b620002c28362000566565b620002cd82620006d8565b620002d881620007e5565b6040805160008082526020820190925262000323916200031b565b6040805180820190915260008082526020820152815260200190600190039081620002f35790505b508762000a0f565b8451156200035b576012805460ff60c81b1916600160c81b179055604080516000808252602082019092526200035b91508662000d12565b505050505050505062002405565b336001600160a01b03821603620003c35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000091565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60408101516001600160a01b031662000440576040516306b7c75960e31b815260040160405180910390fd5b8051600580546020808501516001600160a01b039485166001600160b01b031990931692909217600160a01b61ffff909316830217909255604080850151600680546060808901516080808b0151958a166001600160c01b03199094169390931763ffffffff909116909602959095176001600160c01b0316600160c01b6001600160401b039485160217909155825160e080820185525187168152610100518316958101959095526101205182168584015260a080519092169385019390935260c080516001600160601b03169385019390935261014051851690840152610160519093169082015290517fdd226617d8d287f40a64c54741bbcdc492b3e096ef16bc5273a18cb6ab85f124916200055b91849062001fd6565b60405180910390a150565b60005b8151811015620006a65760008282815181106200058a576200058a62002086565b6020908102919091018101516040805160a08082018352828401516001600160601b039081168352848601516001600160401b0390811684880190815260608088015163ffffffff9081168789019081526080808b015161ffff908116948a01948552978b0151151590890190815299516001600160a01b03166000908152600f909b52979099209551865492519751915198511515600160d01b0260ff60d01b1999909616600160c01b0261ffff60c01b1992909a16600160a01b029190911665ffffffffffff60a01b19979093166c01000000000000000000000000026001600160a01b03199092169316929092179190911793909316929092179390931791909116179055506200069e81620020b2565b905062000569565b507ffba339fca97870ffdfaedbae3745db5e6de1a6909dfd0e0dbb56917469ffe236816040516200055b9190620020ce565b60005b8151811015620007b3576000828281518110620006fc57620006fc62002086565b60209081029190910181015160408051606080820183528385015163ffffffff90811683528385015181168387019081529185015161ffff90811684860190815295516001600160a01b031660009081526010909752939095209151825491519451909316680100000000000000000261ffff60401b19948616640100000000026001600160401b03199092169390951692909217919091179190911691909117905550620007ab81620020b2565b9050620006db565b507fcb0c5f472d325cf0c56953fc81870ddd80d0d3c9a3fbfe777002d75f380dfb81816040516200055b91906200216f565b805160408111156200080a57604051635ad0867d60e11b815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff161580159062000854575060125463ffffffff6c010000000000000000000000008204166001600160601b0390911610155b1562000864576200086462000e5d565b60006200087260076200105d565b90505b8015620008be576000620008986200088f600184620021de565b60079062001070565b509050620008a86007826200108e565b505080620008b690620021f4565b905062000875565b506000805b82811015620009a6576000848281518110620008e357620008e362002086565b6020026020010151600001519050600085838151811062000908576200090862002086565b602002602001015160200151905060e0516001600160a01b0316826001600160a01b031614806200094057506001600160a01b038216155b156200096b57604051634de938d160e01b81526001600160a01b038316600482015260240162000091565b6200097d60078361ffff8416620010ac565b506200098e61ffff8216856200220e565b93505050806200099e90620020b2565b9050620008c3565b506012805463ffffffff60601b19166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd249062000a0290839086906200222e565b60405180910390a1505050565b60005b825181101562000b4b57600083828151811062000a335762000a3362002086565b6020026020010151600001519050600084838151811062000a585762000a5862002086565b6020908102919091018101510151905062000a75600a83620010cc565b62000a9f576040516373913ebd60e01b81526001600160a01b038316600482015260240162000091565b6001600160a01b03811662000ab6600a84620010e3565b6001600160a01b03161462000ade57604051630d98f73360e31b815260040160405180910390fd5b62000aeb600a83620010fa565b1562000b3557604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b50508062000b4390620020b2565b905062000a12565b5060005b815181101562000d0d57600082828151811062000b705762000b7062002086565b6020026020010151600001519050600083838151811062000b955762000b9562002086565b602002602001015160200151905060006001600160a01b0316826001600160a01b0316148062000bcc57506001600160a01b038116155b1562000bea5760405162d8548360e71b815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000c29573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c4f91906200229b565b6001600160a01b0316826001600160a01b03161462000c8157604051630d98f73360e31b815260040160405180910390fd5b62000c8f600a838362001111565b1562000cde57604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a162000cf7565b604051633caf458560e01b815260040160405180910390fd5b50508062000d0590620020b2565b905062000b4f565b505050565b60005b825181101562000da757600083828151811062000d365762000d3662002086565b6020908102919091010151905062000d50600d8262001129565b1562000d93576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b5062000d9f81620020b2565b905062000d15565b5060005b815181101562000d0d57600082828151811062000dcc5762000dcc62002086565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000df8575062000e4a565b62000e05600d8262001140565b1562000e48576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b62000e5581620020b2565b905062000dab565b6000546001600160a01b0316331480159062000e8457506002546001600160a01b03163314155b801562000e9b575062000e9960073362001157565b155b1562000eba5760405163032bb72b60e31b815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff16600081900362000ef65760405163990e30bf60e01b815260040160405180910390fd5b6012546001600160601b03168181101562000f24576040516311a1ee3b60e31b815260040160405180910390fd5b600062000f306200116e565b121562000f5057604051631e9acf1760e31b815260040160405180910390fd5b80600062000f5f60076200105d565b905060005b81811015620010375760008062000f7d60078462001070565b909250905060008762000f9a836001600160601b038a16620022bb565b62000fa69190620022d5565b905062000fb48187620022f8565b60e05190965062000fd9906001600160a01b0316846001600160601b038416620011fc565b6040516001600160601b03821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a2505050806200102f90620020b2565b905062000f64565b5050601280546001600160601b0319166001600160601b03929092169190911790555050565b60006200106a8262001254565b92915050565b600080808062001081868662001261565b9097909650945050505050565b6000620010a5836001600160a01b0384166200128e565b9392505050565b6000620010c4846001600160a01b03851684620012ad565b949350505050565b6000620010a5836001600160a01b038416620012cc565b6000620010a5836001600160a01b038416620012da565b6000620010a5836001600160a01b038416620012e8565b6000620010c4846001600160a01b03851684620012f6565b6000620010a5836001600160a01b0384166200130e565b6000620010a5836001600160a01b03841662001419565b6000620010a5836001600160a01b0384166200146b565b60125460e0516040516370a0823160e01b81523060048201526000926001600160601b0316916001600160a01b0316906370a0823190602401602060405180830381865afa158015620011c5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620011eb91906200231b565b620011f7919062002335565b905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663a9059cbb60e01b1790915262000d0d9185916200147916565b60006200106a826200154a565b6000808062001271858562001555565b600081815260029690960160205260409095205494959350505050565b60008181526002830160205260408120819055620010a5838362001563565b60008281526002840160205260408120829055620010c4848462001571565b6000620010a583836200146b565b6000620010a583836200157f565b6000620010a583836200128e565b6000620010c484846001600160a01b038516620012ad565b600081815260018301602052604081205480156200140757600062001335600183620021de565b85549091506000906200134b90600190620021de565b9050818114620013b75760008660000182815481106200136f576200136f62002086565b906000526020600020015490508087600001848154811062001395576200139562002086565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620013cb57620013cb62002358565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506200106a565b60009150506200106a565b5092915050565b600081815260018301602052604081205462001462575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200106a565b5060006200106a565b6000620010a58383620015f4565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490820152600090620014c8906001600160a01b0385169084906200160d565b80519091501562000d0d5780806020019051810190620014e991906200236e565b62000d0d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000091565b60006200106a825490565b6000620010a583836200161e565b6000620010a583836200130e565b6000620010a5838362001419565b600081815260028301602052604081205480151580620015a65750620015a684846200146b565b620010a55760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b65790000604482015260640162000091565b60008181526001830160205260408120541515620010a5565b6060620010c484846000856200164b565b600082600001828154811062001638576200163862002086565b9060005260206000200154905092915050565b606082471015620016ae5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000091565b600080866001600160a01b03168587604051620016cc9190620023b2565b60006040518083038185875af1925050503d80600081146200170b576040519150601f19603f3d011682016040523d82523d6000602084013e62001710565b606091505b50909250905062001724878383876200172f565b979650505050505050565b60608315620017a35782516000036200179b576001600160a01b0385163b6200179b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000091565b5081620010c4565b620010c48383815115620017ba5781518083602001fd5b8060405162461bcd60e51b8152600401620000919190620023d0565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715620018115762001811620017d6565b60405290565b60405160c081016001600160401b0381118282101715620018115762001811620017d6565b604051608081016001600160401b0381118282101715620018115762001811620017d6565b604051601f8201601f191681016001600160401b03811182821017156200188c576200188c620017d6565b604052919050565b6001600160a01b0381168114620018aa57600080fd5b50565b80516001600160401b0381168114620018c557600080fd5b919050565b80516001600160601b0381168114620018c557600080fd5b600060e08284031215620018f557600080fd5b60405160e081016001600160401b03811182821017156200191a576200191a620017d6565b806040525080915082516200192f8162001894565b81526200193f60208401620018ad565b60208201526200195260408401620018ad565b60408201526200196560608401620018ad565b60608201526200197860808401620018ca565b608082015260a08301516200198d8162001894565b60a082015260c0830151620019a28162001894565b60c0919091015292915050565b805161ffff81168114620018c557600080fd5b805163ffffffff81168114620018c557600080fd5b600060a08284031215620019ea57600080fd5b60405160a081016001600160401b038111828210171562001a0f5762001a0f620017d6565b8060405250809150825162001a248162001894565b815262001a3460208401620019af565b6020820152604083015162001a498162001894565b604082015262001a5c60608401620019c2565b606082015262001a6f60808401620018ad565b60808201525092915050565b60006001600160401b0382111562001a975762001a97620017d6565b5060051b60200190565b600082601f83011262001ab357600080fd5b8151602062001acc62001ac68362001a7b565b62001861565b82815260069290921b8401810191818101908684111562001aec57600080fd5b8286015b8481101562001b46576040818903121562001b0b5760008081fd5b62001b15620017ec565b815162001b228162001894565b81528185015162001b338162001894565b8186015283529183019160400162001af0565b509695505050505050565b600082601f83011262001b6357600080fd5b8151602062001b7662001ac68362001a7b565b82815260059290921b8401810191818101908684111562001b9657600080fd5b8286015b8481101562001b4657805162001bb08162001894565b835291830191830162001b9a565b80518015158114620018c557600080fd5b80516001600160801b0381168114620018c557600080fd5b60006060828403121562001bfa57600080fd5b604051606081016001600160401b038111828210171562001c1f5762001c1f620017d6565b60405290508062001c308362001bbe565b815262001c406020840162001bcf565b602082015262001c536040840162001bcf565b60408201525092915050565b600082601f83011262001c7157600080fd5b8151602062001c8462001ac68362001a7b565b82815260c0928302850182019282820191908785111562001ca457600080fd5b8387015b8581101562001d465781818a03121562001cc25760008081fd5b62001ccc62001817565b815162001cd98162001894565b815262001ce8828701620018ad565b86820152604062001cfb818401620018ca565b90820152606062001d0e838201620019c2565b90820152608062001d21838201620019af565b9082015260a062001d3483820162001bbe565b90820152845292840192810162001ca8565b5090979650505050505050565b600082601f83011262001d6557600080fd5b8151602062001d7862001ac68362001a7b565b82815260079290921b8401810191818101908684111562001d9857600080fd5b8286015b8481101562001b46576080818903121562001db75760008081fd5b62001dc16200183c565b815162001dce8162001894565b815262001ddd828601620019c2565b85820152604062001df0818401620019c2565b90820152606062001e03838201620019af565b9082015283529183019160800162001d9c565b600082601f83011262001e2857600080fd5b8151602062001e3b62001ac68362001a7b565b82815260069290921b8401810191818101908684111562001e5b57600080fd5b8286015b8481101562001b46576040818903121562001e7a5760008081fd5b62001e84620017ec565b815162001e918162001894565b815262001ea0828601620019af565b8186015283529183019160400162001e5f565b600080600080600080600080610280898b03121562001ed157600080fd5b62001edd8a8a620018e2565b975062001eee8a60e08b01620019d7565b6101808a01519097506001600160401b038082111562001f0d57600080fd5b62001f1b8c838d0162001aa1565b97506101a08b015191508082111562001f3357600080fd5b62001f418c838d0162001b51565b965062001f538c6101c08d0162001be7565b95506102208b015191508082111562001f6b57600080fd5b62001f798c838d0162001c5f565b94506102408b015191508082111562001f9157600080fd5b62001f9f8c838d0162001d53565b93506102608b015191508082111562001fb757600080fd5b5062001fc68b828c0162001e16565b9150509295985092959890939650565b82516001600160a01b0390811682526020808501516001600160401b03908116828501526040808701518216818601526060808801518316818701526080808901516001600160601b03168188015260a0808a015187169088015260c0808a01518716908801528751861660e08801529387015161ffff16610100870152908601519093166101208501529184015163ffffffff16610140840152830151166101608201526101808101620010a5565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620020c757620020c76200209c565b5060010190565b602080825282518282018190526000919060409081850190868401855b828110156200216257815180516001600160a01b03168552868101516001600160401b031687860152858101516001600160601b03168686015260608082015163ffffffff169086015260808082015161ffff169086015260a09081015115159085015260c09093019290850190600101620020eb565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b828110156200216257815180516001600160a01b031685528681015163ffffffff9081168887015286820151168686015260609081015161ffff1690850152608090930192908501906001016200218c565b818103818111156200106a576200106a6200209c565b6000816200220657620022066200209c565b506000190190565b63ffffffff8181168382160190808211156200141257620014126200209c565b6000604080830163ffffffff8616845260208281860152818651808452606087019150828801935060005b818110156200228d57845180516001600160a01b0316845284015161ffff1684840152938301939185019160010162002259565b509098975050505050505050565b600060208284031215620022ae57600080fd5b8151620010a58162001894565b80820281158282048414176200106a576200106a6200209c565b600082620022f357634e487b7160e01b600052601260045260246000fd5b500490565b6001600160601b038281168282160390808211156200141257620014126200209c565b6000602082840312156200232e57600080fd5b5051919050565b81810360008312801583831316838312821617156200141257620014126200209c565b634e487b7160e01b600052603160045260246000fd5b6000602082840312156200238157600080fd5b620010a58262001bbe565b60005b83811015620023a95781810151838201526020016200238f565b50506000910152565b60008251620023c68184602087016200238c565b9190910192915050565b6020815260008251806020840152620023f18160408501602087016200238c565b601f01601f19169190910160400192915050565b60805160a05160c05160e05161010051610120516101405161016051615cbd6200250c600039600081816103600152818161140a0152612c2001526000818161033101528181611320015281816113880152818161185a015281816118c20152612bf801526000818161029d01528181610af901528181611c520152612b7001526000818161026d0152818161198d0152612b4601526000818161023e01528181610dfa0152818161160d01528181611706015281816121a501528181612b2101528181612d6b015261323c0152600081816102fd015281816117d20152612bc20152600081816102cd015281816122bd0152612b9701526000611b6c0152615cbd6000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806376f6ae761161010f578063b06d41bc116100a2578063e0351e1311610071578063e0351e13146108ee578063efeadb6d14610921578063eff7cc4814610934578063f2fde38b1461093c57600080fd5b8063b06d41bc146108b5578063c92b2832146108cb578063d09dc339146108de578063d3c7c2c7146108e657600080fd5b80638da5cb5b116100de5780638da5cb5b146107105780639a113c3614610721578063a7cd63b71461088d578063a7d3e02f146108a257600080fd5b806376f6ae76146106cf578063799c3a67146106e257806379ba5097146106f5578063856c8247146106fd57600080fd5b8063549e946f116101875780635d86f141116101565780635d86f141146105d45780635ebbd9f8146105e7578063704b6c02146105fa5780637437ff9f1461060d57600080fd5b8063549e946f1461056957806354b714681461057c57806354c8a4f31461059c578063599f6431146105af57600080fd5b80633a87ac53116101c35780633a87ac53146104bc5780633a9bf949146104d15780634120fccd146104e4578063546719cd1461050557600080fd5b806306285c69146101f55780631772047e146103a6578063181f5a771461045257806338724a951461049b575b600080fd5b6103906040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b60405161039d9190614822565b60405180910390f35b6104216103b43660046148b3565b6040805160608082018352600080835260208084018290529284018190526001600160a01b039490941684526010825292829020825193840183525463ffffffff80821685526401000000008204169184019190915268010000000000000000900461ffff169082015290565b60408051825163ffffffff9081168252602080850151909116908201529181015161ffff169082015260600161039d565b61048e6040518060400160405280601381526020017f45564d3245564d4f6e52616d7020312e302e300000000000000000000000000081525081565b60405161039d919061493e565b6104ae6104a9366004614963565b61094f565b60405190815260200161039d565b6104cf6104ca366004614b4a565b610c8d565b005b6104cf6104df366004614bef565b610ca3565b6104ec610cb7565b60405167ffffffffffffffff909116815260200161039d565b61050d610ceb565b60405161039d919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6104cf610577366004614c83565b610d9b565b6012546040516bffffffffffffffffffffffff909116815260200161039d565b6104cf6105aa366004614d20565b610f50565b6002546001600160a01b03165b6040516001600160a01b03909116815260200161039d565b6105bc6105e23660046148b3565b610f62565b6104cf6105f5366004614d7a565b610fc1565b6104cf6106083660046148b3565b611027565b6106c26040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506040805160a0810182526005546001600160a01b038082168352740100000000000000000000000000000000000000009182900461ffff16602084015260065490811693830193909352820463ffffffff166060820152780100000000000000000000000000000000000000000000000090910467ffffffffffffffff16608082015290565b60405161039d9190614e58565b6104cf6106dd366004614eb2565b6110f1565b6104cf6106f0366004614f40565b6111a9565b6104cf61120f565b6104ec61070b3660046148b3565b6112f2565b6000546001600160a01b03166105bc565b61082761072f3660046148b3565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506001600160a01b03166000908152600f6020908152604091829020825160a08101845290546bffffffffffffffffffffffff811682526c01000000000000000000000000810467ffffffffffffffff169282019290925274010000000000000000000000000000000000000000820463ffffffff16928101929092527801000000000000000000000000000000000000000000000000810461ffff1660608301527a010000000000000000000000000000000000000000000000000000900460ff161515608082015290565b60405161039d9190600060a0820190506bffffffffffffffffffffffff835116825267ffffffffffffffff602084015116602083015263ffffffff604084015116604083015261ffff606084015116606083015260808301511515608083015292915050565b6108956113fa565b60405161039d919061505e565b6104ae6108b03660046150ab565b611406565b6108bd611d39565b60405161039d929190615159565b6104cf6108d936600461519b565b611e3d565b6104ae611ea5565b610895611eaf565b601254790100000000000000000000000000000000000000000000000000900460ff16604051901515815260200161039d565b6104cf61092f366004615209565b611f60565b6104cf611fe6565b6104cf61094a3660046148b3565b61227d565b600080600f8161096560808601606087016148b3565b6001600160a01b031681526020808201929092526040908101600020815160a08101835290546bffffffffffffffffffffffff811682526c01000000000000000000000000810467ffffffffffffffff169382019390935274010000000000000000000000000000000000000000830463ffffffff16918101919091527801000000000000000000000000000000000000000000000000820461ffff1660608201527a01000000000000000000000000000000000000000000000000000090910460ff16151560808201819052909150610a8c57610a4960808401606085016148b3565b6040517fa7499d200000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024015b60405180910390fd5b60065460009081906001600160a01b031663ffdb4b37610ab260808801606089016148b3565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044016040805180830381865afa158015610b3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b61919061524e565b91509150600083600001516bffffffffffffffffffffffff16670de0b6b3a7640000856020015167ffffffffffffffff16866060015161ffff16898060200190610bab9190615281565b610bb6929150615315565b604088015163ffffffff16610bd6610bd160808d018d615281565b61228e565b51610be1919061532c565b610beb919061532c565b610bf59190615315565b610c199077ffffffffffffffffffffffffffffffffffffffffffffffff8616615315565b610c23919061533f565b610c2d919061532c565b9050610c55610c4260808801606089016148b3565b84610c5060408a018a61537a565b612382565b610c7977ffffffffffffffffffffffffffffffffffffffffffffffff8516836125ce565b610c83919061532c565b9695505050505050565b610c95612607565b610c9f828261267d565b5050565b610cab612607565b610cb4816129dd565b50565b601254600090610ce690700100000000000000000000000000000000900467ffffffffffffffff1660016153e2565b905090565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff161515938301939093526004548084166060840152049091166080820152610ce690612c76565b6000546001600160a01b03163314801590610dc157506002546001600160a01b03163314155b15610df8576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480610e3f57506001600160a01b038116155b15610e76576040517f232cb97f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e80612d28565b1215610eb8576040517f02075e0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610c9f9082906001600160a01b038516906370a0823190602401602060405180830381865afa158015610f1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f3f9190615403565b6001600160a01b0385169190612de8565b610f58612607565b610c9f8282612e68565b6000610f6f600a83612fa3565b610fb0576040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b610fbb600a83612fb8565b92915050565b6000546001600160a01b03163314801590610fe757506002546001600160a01b03163314155b1561101e576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb481612fcd565b6000546001600160a01b0316331480159061104d57506002546001600160a01b03163314155b15611084576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c906020015b60405180910390a150565b6000546001600160a01b0316331480159061111757506002546001600160a01b03163314155b1561114e576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c9f8282808060200260200160405190810160405280939291908181526020016000905b8282101561119f576111906040830286013681900381019061541c565b81526020019060010190611173565b5050505050613103565b6000546001600160a01b031633148015906111cf57506002546001600160a01b03163314155b15611206576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb481613376565b6001546001600160a01b03163314611283576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610a83565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b03811660009081526011602052604081205467ffffffffffffffff168015801561134b57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b15610fbb576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa1580156113cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f3919061545b565b9392505050565b6060610ce6600d613585565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148a9190615478565b156114c1576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114cb8480615281565b9050602014611512576114de8480615281565b6040517f370d875f000000000000000000000000000000000000000000000000000000008152600401610a839291906154de565b600061151e8580615281565b81019061152b91906154f2565b90506001600160a01b038111806115425750600a81105b15611551576114de8580615281565b6000611563610bd16080880188615281565b905061158f6115756020880188615281565b835190915061158760408a018a61537a565b905087613592565b61160361159f604088018861537a565b808060200260200160405190810160405280939291908181526020016000905b828210156115eb576115dc6040830286013681900381019061550b565b815260200190600101906115bf565b50506006546001600160a01b031692506137b5915050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001661163d60808801606089016148b3565b6001600160a01b0316036116a1576012805486919060009061166e9084906bffffffffffffffffffffffff16615545565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506117c0565b6006546001600160a01b03166241e5be6116c16080890160608a016148b3565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039182166004820152602481018990527f00000000000000000000000000000000000000000000000000000000000000009091166044820152606401602060405180830381865afa15801561174d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117719190615403565b601280546000906117919084906bffffffffffffffffffffffff16615545565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b6012546bffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116111561182d576040517fe5c7a49100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660009081526011602052604090205467ffffffffffffffff1615801561188557507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b1561197d576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611909573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192d919061545b565b6001600160a01b038516600090815260116020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790555b60006040518061018001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020016012601081819054906101000a900467ffffffffffffffff166119dd9061556a565b825467ffffffffffffffff9182166101009390930a8381029083021990911617909255825260208083018a90526001600160a01b03891660408085018290526000918252601190925290812080546060909401939092611a3d911661556a565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905567ffffffffffffffff16815260200183600001518152602001600015158152602001846001600160a01b03168152602001888060200190611aa39190615281565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001611aea60408a018a61537a565b808060200260200160405190810160405280939291908181526020016000905b82821015611b3657611b276040830286013681900381019061550b565b81526020019060010190611b0a565b5050509183525050602001611b5160808a0160608b016148b3565b6001600160a01b0316815260006020909101529050611b90817f000000000000000000000000000000000000000000000000000000000000000061396e565b61016082015260005b611ba6604089018961537a565b9050811015611cf2576000611bbe60408a018a61537a565b83818110611bce57611bce615591565b905060400201803603810190611be4919061550b565b9050611bf38160000151610f62565b6001600160a01b0316639687544588611c0c8c80615281565b60208087015160408051928301815260008352517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b168152611c7a959493927f0000000000000000000000000000000000000000000000000000000000000000916004016155c0565b6000604051808303816000875af1158015611c99573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cdf9190810190615618565b505080611ceb906156ca565b9050611b99565b507faffc45517195d6499808c643bd4a7b0ffeedf95bea5852840d7bfcf63f59e82181604051611d229190615746565b60405180910390a161016001519695505050505050565b6060600080611d486007613a78565b90508067ffffffffffffffff811115611d6357611d63614998565b604051908082528060200260200182016040528015611da857816020015b6040805180820190915260008082526020820152815260200190600190039081611d815790505b50925060005b81811015611e1a57600080611dc4600784613a83565b915091506040518060400160405280836001600160a01b031681526020018261ffff16815250868481518110611dfc57611dfc615591565b6020026020010181905250505080611e13906156ca565b9050611dae565b505060125491926c0100000000000000000000000090920463ffffffff16919050565b6000546001600160a01b03163314801590611e6357506002546001600160a01b03163314155b15611e9a576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610cb4600382613aa1565b6000610ce6612d28565b60606000611ebd600a613c79565b67ffffffffffffffff811115611ed557611ed5614998565b604051908082528060200260200182016040528015611efe578160200160208202803683370190505b50905060005b8151811015611f5a57611f18600a82613c84565b50828281518110611f2b57611f2b615591565b60200260200101816001600160a01b03166001600160a01b03168152505080611f53906156ca565b9050611f04565b50919050565b611f68612607565b60128054821515790100000000000000000000000000000000000000000000000000027fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff9091161790556040517fccf4daf6ab6430389f26b970595dab82a5881ad454770907e415ede27c8df032906110e690831515815260200190565b6000546001600160a01b0316331480159061200c57506002546001600160a01b03163314155b8015612020575061201e600733613c93565b155b15612057576040517f195db95800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff1660008190036120ab576040517f990e30bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546bffffffffffffffffffffffff16818110156120f6576040517f8d0f71d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612100612d28565b1215612138576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060006121456007613a78565b905060005b8181101561223a57600080612160600784613a83565b9092509050600087612180836bffffffffffffffffffffffff8a16615315565b61218a919061533f565b90506121968187615883565b95506121da6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016846bffffffffffffffffffffffff8416612de8565b6040516bffffffffffffffffffffffff821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a250505080612233906156ca565b905061214a565b5050601280547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790555050565b612285612607565b610cb481613ca8565b60408051602081019091526000815260008290036122e45750604080516020810190915267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152610fbb565b7f97a657c90000000000000000000000000000000000000000000000000000000061230f83856158a8565b7fffffffff000000000000000000000000000000000000000000000000000000001614612368576040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61237582600481866158f0565b8101906113f3919061591a565b6000818082036123965760009150506125c6565b60005b818110156125c35760008585838181106123b5576123b5615591565b9050604002018036038101906123cb919061550b565b80516001600160a01b031660009081526010602090815260408083208151606081018352905463ffffffff8082168352640100000000820416938201939093526801000000000000000090920461ffff16908201819052929350911561252257825189906001600160a01b038c81169116146124cc5760065484516040517f4ab35b0b0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152911690634ab35b0b90602401602060405180830381865afa1580156124a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124c9919061595c565b90505b620186a0836040015161ffff1661250a86602001518477ffffffffffffffffffffffffffffffffffffffffffffffff16613d8390919063ffffffff16565b6125149190615315565b61251e919061533f565b9150505b815160009061253e9063ffffffff16662386f26fc10000615315565b90506000836020015163ffffffff16662386f26fc1000061255f9190615315565b9050818310156125715781925061257d565b8083111561257d578092505b6125a177ffffffffffffffffffffffffffffffffffffffffffffffff8c16846125ce565b6125ab908961532c565b97505050505050806125bc906156ca565b9050612399565b50505b949350505050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff83166125fd83670de0b6b3a7640000615315565b6113f3919061533f565b6000546001600160a01b0316331461267b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610a83565b565b60005b82518110156127de57600083828151811061269d5761269d615591565b602002602001015160000151905060008483815181106126bf576126bf615591565b60200260200101516020015190506126e182600a612fa390919063ffffffff16565b612722576040517f73913ebd0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b6001600160a01b038116612737600a84612fb8565b6001600160a01b031614612777576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612782600a83613db2565b156127cb57604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b5050806127d7906156ca565b9050612680565b5060005b81518110156129d85760008282815181106127ff576127ff615591565b6020026020010151600001519050600083838151811061282157612821615591565b602002602001015160200151905060006001600160a01b0316826001600160a01b0316148061285757506001600160a01b038116155b1561288e576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f09190615977565b6001600160a01b0316826001600160a01b03161461293a576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612946600a8383613dc7565b1561299357604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a16129c5565b6040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050806129d1906156ca565b90506127e2565b505050565b60408101516001600160a01b0316612a21576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600580546020808501516001600160a01b039485167fffffffffffffffffffff00000000000000000000000000000000000000000000909316929092177401000000000000000000000000000000000000000061ffff909316830217909255604080850151600680546060808901516080808b0151958a167fffffffffffffffff0000000000000000000000000000000000000000000000009094169390931763ffffffff9091169096029590951777ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff9485160217909155825160e0810184527f0000000000000000000000000000000000000000000000000000000000000000871681527f00000000000000000000000000000000000000000000000000000000000000008316958101959095527f00000000000000000000000000000000000000000000000000000000000000008216858401527f0000000000000000000000000000000000000000000000000000000000000000909116928401929092527f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff16918301919091527f0000000000000000000000000000000000000000000000000000000000000000831660a08301527f000000000000000000000000000000000000000000000000000000000000000090921660c082015290517fdd226617d8d287f40a64c54741bbcdc492b3e096ef16bc5273a18cb6ab85f124916110e6918490615994565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152612d0482606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642612ce89190615a69565b85608001516fffffffffffffffffffffffffffffffff16613ddd565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6012546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916bffffffffffffffffffffffff16907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612dba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dde9190615403565b610ce69190615a7c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526129d8908490613e05565b60005b8251811015612ef9576000838281518110612e8857612e88615591565b60200260200101519050612ea681600d613f0490919063ffffffff16565b15612ee8576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50612ef2816156ca565b9050612e6b565b5060005b81518110156129d8576000828281518110612f1a57612f1a615591565b6020026020010151905060006001600160a01b0316816001600160a01b031603612f445750612f93565b612f4f600d82613f19565b15612f91576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b612f9c816156ca565b9050612efd565b60006113f3836001600160a01b038416613f2e565b60006113f3836001600160a01b038416613f3a565b60005b81518110156130d3576000828281518110612fed57612fed615591565b60209081029190910181015160408051606080820183528385015163ffffffff90811683528385015181168387019081529185015161ffff90811684860190815295516001600160a01b03166000908152601090975293909520915182549151945190931668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff948616640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921693909516929092179190911791909116919091179055506130cc816156ca565b9050612fd0565b507fcb0c5f472d325cf0c56953fc81870ddd80d0d3c9a3fbfe777002d75f380dfb81816040516110e69190615a9c565b80516040811115613140576040517fb5a10cfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff161580159061318e575060125463ffffffff6c010000000000000000000000008204166bffffffffffffffffffffffff90911610155b1561319b5761319b611fe6565b60006131a76007613a78565b90505b80156131e95760006131c86131c0600184615a69565b600790613a83565b5090506131d6600782613f46565b5050806131e290615b16565b90506131aa565b506000805b828110156132f757600084828151811061320a5761320a615591565b6020026020010151600001519050600085838151811061322c5761322c615591565b60200260200101516020015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316148061328157506001600160a01b038216155b156132c3576040517f4de938d10000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b6132d360078361ffff8416613f5b565b506132e261ffff821685615b4b565b93505050806132f0906156ca565b90506131ee565b50601280547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd24906133699083908690615b68565b60405180910390a1505050565b60005b815181101561355557600082828151811061339657613396615591565b6020908102919091018101516040805160a08082018352828401516bffffffffffffffffffffffff90811683528486015167ffffffffffffffff90811684880190815260608088015163ffffffff9081168789019081526080808b015161ffff908116948a01948552978b0151151590890190815299516001600160a01b03166000908152600f909b529790992095518654925197519151985115157a010000000000000000000000000000000000000000000000000000027fffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffff999096167801000000000000000000000000000000000000000000000000027fffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffff92909a167401000000000000000000000000000000000000000002919091167fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff979093166c01000000000000000000000000027fffffffffffffffffffffffff000000000000000000000000000000000000000090921693169290921791909117939093169290921793909317919091161790555061354e816156ca565b9050613379565b507ffba339fca97870ffdfaedbae3745db5e6de1a6909dfd0e0dbb56917469ffe236816040516110e69190615b87565b606060006113f383613f71565b6001600160a01b0381166135d2576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b03163314613616576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065474010000000000000000000000000000000000000000900463ffffffff168085111561367b576040517f869337890000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610a83565b6006547801000000000000000000000000000000000000000000000000900467ffffffffffffffff168411156136dd576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055474010000000000000000000000000000000000000000900461ffff16831115613735576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254790100000000000000000000000000000000000000000000000000900460ff16801561376c575061376a600d83613fcd565b155b156137ae576040517fd0d259760000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610a83565b5050505050565b81516000805b8281101561395a576000846001600160a01b031663d02641a08784815181106137e6576137e6615591565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0390911660048201526024016040805180830381865afa15801561384d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138719190615c1f565b51905077ffffffffffffffffffffffffffffffffffffffffffffffff81166000036138f2578582815181106138a8576138a8615591565b6020908102919091010151516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610a83565b61393c86838151811061390757613907615591565b6020026020010151602001518277ffffffffffffffffffffffffffffffffffffffffffffffff16613d8390919063ffffffff16565b613946908461532c565b92505080613953906156ca565b90506137bb565b506139686003826000613fef565b50505050565b60008060001b828460200151856080015186606001518760e00151886101000151805190602001208961012001516040516020016139ac9190615c52565b604051602081830303815290604052805190602001208a60a001518b60c001518c61014001518d60400151604051602001613a5a9c9b9a999897969594939291909b8c5260208c019a909a5267ffffffffffffffff98891660408c01529690971660608a01526001600160a01b0394851660808a015292841660a089015260c088019190915260e0870152610100860152911515610120850152166101408301526101608201526101800190565b60405160208183030381529060405280519060200120905092915050565b6000610fbb8261433e565b6000808080613a928686614349565b909450925050505b9250929050565b8154600090613aca90700100000000000000000000000000000000900463ffffffff1642615a69565b90508015613b6c5760018301548354613b12916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416613ddd565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354613b92916fffffffffffffffffffffffffffffffff9081169116614374565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19906133699084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b6000610fbb82613a78565b6000808080613a928686613a83565b60006113f3836001600160a01b03841661438a565b336001600160a01b03821603613d1a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610a83565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000670de0b6b3a76400006125fd8377ffffffffffffffffffffffffffffffffffffffffffffffff8616615315565b60006113f3836001600160a01b038416614396565b60006125c6846001600160a01b038516846143a2565b6000613dfc85613ded8486615315565b613df7908761532c565b614374565b95945050505050565b6000613e5a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166143b89092919063ffffffff16565b8051909150156129d85780806020019051810190613e789190615478565b6129d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a83565b60006113f3836001600160a01b0384166143c7565b60006113f3836001600160a01b0384166144c1565b60006113f3838361438a565b60006113f38383614510565b60006113f3836001600160a01b03841661459a565b60006125c6846001600160a01b038516846145b7565b606081600001805480602002602001604051908101604052809291908181526020018280548015613fc157602002820191906000526020600020905b815481526020019060010190808311613fad575b50505050509050919050565b6001600160a01b038116600090815260018301602052604081205415156113f3565b825474010000000000000000000000000000000000000000900460ff161580614016575081155b1561402057505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061406690700100000000000000000000000000000000900463ffffffff1642615a69565b9050801561412657818311156140a8576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546140e29083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613ddd565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156141c3576001600160a01b038416614178576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610a83565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b0385166044820152606401610a83565b848310156142bc5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906142079082615a69565b614211878a615a69565b61421b919061532c565b614225919061533f565b90506001600160a01b038616614271576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610a83565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b0387166044820152606401610a83565b6142c68584615a69565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6000610fbb826145d4565b6000808061435785856145de565b600081815260029690960160205260409095205494959350505050565b600081831061438357816113f3565b5090919050565b60006113f383836145ea565b60006113f3838361459a565b60006125c684846001600160a01b0385166145b7565b60606125c68484600085614602565b600081815260018301602052604081205480156144b05760006143eb600183615a69565b85549091506000906143ff90600190615a69565b905081811461446457600086600001828154811061441f5761441f615591565b906000526020600020015490508087600001848154811061444257614442615591565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061447557614475615c65565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610fbb565b6000915050610fbb565b5092915050565b600081815260018301602052604081205461450857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610fbb565b506000610fbb565b6000818152600283016020526040812054801515806145345750614534848461438a565b6113f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610a83565b600081815260028301602052604081208190556113f3838361470e565b600082815260028401602052604081208290556125c6848461471a565b6000610fbb825490565b60006113f38383614726565b600081815260018301602052604081205415156113f3565b606082471015614694576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610a83565b600080866001600160a01b031685876040516146b09190615c94565b60006040518083038185875af1925050503d80600081146146ed576040519150601f19603f3d011682016040523d82523d6000602084013e6146f2565b606091505b509150915061470387838387614750565b979650505050505050565b60006113f383836143c7565b60006113f383836144c1565b600082600001828154811061473d5761473d615591565b9060005260206000200154905092915050565b606083156147d95782516000036147d2576001600160a01b0385163b6147d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a83565b50816125c6565b6125c683838151156147ee5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a83919061493e565b60e08101610fbb82846001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b6001600160a01b0381168114610cb457600080fd5b6000602082840312156148c557600080fd5b81356113f38161489e565b60005b838110156148eb5781810151838201526020016148d3565b50506000910152565b6000815180845261490c8160208601602086016148d0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006113f360208301846148f4565b600060a08284031215611f5a57600080fd5b60006020828403121561497557600080fd5b813567ffffffffffffffff81111561498c57600080fd5b6125c684828501614951565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156149ea576149ea614998565b60405290565b6040516080810167ffffffffffffffff811182821017156149ea576149ea614998565b60405160c0810167ffffffffffffffff811182821017156149ea576149ea614998565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614a7d57614a7d614998565b604052919050565b600067ffffffffffffffff821115614a9f57614a9f614998565b5060051b60200190565b600082601f830112614aba57600080fd5b81356020614acf614aca83614a85565b614a36565b82815260069290921b84018101918181019086841115614aee57600080fd5b8286015b84811015614b3f5760408189031215614b0b5760008081fd5b614b136149c7565b8135614b1e8161489e565b815281850135614b2d8161489e565b81860152835291830191604001614af2565b509695505050505050565b60008060408385031215614b5d57600080fd5b823567ffffffffffffffff80821115614b7557600080fd5b614b8186838701614aa9565b93506020850135915080821115614b9757600080fd5b50614ba485828601614aa9565b9150509250929050565b803561ffff81168114614bc057600080fd5b919050565b803563ffffffff81168114614bc057600080fd5b67ffffffffffffffff81168114610cb457600080fd5b600060a08284031215614c0157600080fd5b60405160a0810181811067ffffffffffffffff82111715614c2457614c24614998565b6040528235614c328161489e565b8152614c4060208401614bae565b60208201526040830135614c538161489e565b6040820152614c6460608401614bc5565b60608201526080830135614c7781614bd9565b60808201529392505050565b60008060408385031215614c9657600080fd5b8235614ca18161489e565b91506020830135614cb18161489e565b809150509250929050565b600082601f830112614ccd57600080fd5b81356020614cdd614aca83614a85565b82815260059290921b84018101918181019086841115614cfc57600080fd5b8286015b84811015614b3f578035614d138161489e565b8352918301918301614d00565b60008060408385031215614d3357600080fd5b823567ffffffffffffffff80821115614d4b57600080fd5b614d5786838701614cbc565b93506020850135915080821115614d6d57600080fd5b50614ba485828601614cbc565b60006020808385031215614d8d57600080fd5b823567ffffffffffffffff811115614da457600080fd5b8301601f81018513614db557600080fd5b8035614dc3614aca82614a85565b81815260079190911b82018301908381019087831115614de257600080fd5b928401925b828410156147035760808489031215614e005760008081fd5b614e086149f0565b8435614e138161489e565b8152614e20858701614bc5565b868201526040614e31818701614bc5565b908201526060614e42868201614bae565b9082015282526080939093019290840190614de7565b60a08101610fbb82846001600160a01b0380825116835261ffff60208301511660208401528060408301511660408401525063ffffffff606082015116606083015267ffffffffffffffff60808201511660808301525050565b60008060208385031215614ec557600080fd5b823567ffffffffffffffff80821115614edd57600080fd5b818501915085601f830112614ef157600080fd5b813581811115614f0057600080fd5b8660208260061b8501011115614f1557600080fd5b60209290920196919550909350505050565b8015158114610cb457600080fd5b8035614bc081614f27565b60006020808385031215614f5357600080fd5b823567ffffffffffffffff811115614f6a57600080fd5b8301601f81018513614f7b57600080fd5b8035614f89614aca82614a85565b81815260c09182028301840191848201919088841115614fa857600080fd5b938501935b838510156150525780858a031215614fc55760008081fd5b614fcd614a13565b8535614fd88161489e565b815285870135614fe781614bd9565b818801526040868101356bffffffffffffffffffffffff8116811461500c5760008081fd5b90820152606061501d878201614bc5565b90820152608061502e878201614bae565b9082015260a061503f878201614f35565b9082015283529384019391850191614fad565b50979650505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561509f5783516001600160a01b03168352928401929184019160010161507a565b50909695505050505050565b6000806000606084860312156150c057600080fd5b833567ffffffffffffffff8111156150d757600080fd5b6150e386828701614951565b9350506020840135915060408401356150fb8161489e565b809150509250925092565b600081518084526020808501945080840160005b8381101561514e57815180516001600160a01b0316885283015161ffff16838801526040909601959082019060010161511a565b509495945050505050565b60408152600061516c6040830185615106565b90508260208301529392505050565b80356fffffffffffffffffffffffffffffffff81168114614bc057600080fd5b6000606082840312156151ad57600080fd5b6040516060810181811067ffffffffffffffff821117156151d0576151d0614998565b60405282356151de81614f27565b81526151ec6020840161517b565b60208201526151fd6040840161517b565b60408201529392505050565b60006020828403121561521b57600080fd5b81356113f381614f27565b805177ffffffffffffffffffffffffffffffffffffffffffffffff81168114614bc057600080fd5b6000806040838503121561526157600080fd5b61526a83615226565b915061527860208401615226565b90509250929050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126152b657600080fd5b83018035915067ffffffffffffffff8211156152d157600080fd5b602001915036819003821315613a9a57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610fbb57610fbb6152e6565b80820180821115610fbb57610fbb6152e6565b600082615375577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126153af57600080fd5b83018035915067ffffffffffffffff8211156153ca57600080fd5b6020019150600681901b3603821315613a9a57600080fd5b67ffffffffffffffff8181168382160190808211156144ba576144ba6152e6565b60006020828403121561541557600080fd5b5051919050565b60006040828403121561542e57600080fd5b6154366149c7565b82356154418161489e565b815261544f60208401614bae565b60208201529392505050565b60006020828403121561546d57600080fd5b81516113f381614bd9565b60006020828403121561548a57600080fd5b81516113f381614f27565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6020815260006125c6602083018486615495565b60006020828403121561550457600080fd5b5035919050565b60006040828403121561551d57600080fd5b6155256149c7565b82356155308161489e565b81526020928301359281019290925250919050565b6bffffffffffffffffffffffff8181168382160190808211156144ba576144ba6152e6565b600067ffffffffffffffff808316818103615587576155876152e6565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6001600160a01b038716815260a0602082015260006155e360a083018789615495565b85604084015267ffffffffffffffff85166060840152828103608084015261560b81856148f4565b9998505050505050505050565b60006020828403121561562a57600080fd5b815167ffffffffffffffff8082111561564257600080fd5b818401915084601f83011261565657600080fd5b81518181111561566857615668614998565b61569960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614a36565b91508082528560208285010111156156b057600080fd5b6156c18160208401602086016148d0565b50949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036156fb576156fb6152e6565b5060010190565b600081518084526020808501945080840160005b8381101561514e57815180516001600160a01b031688528301518388015260409096019590820190600101615716565b6020815261576160208201835167ffffffffffffffff169052565b6000602083015161577e604084018267ffffffffffffffff169052565b506040830151606083015260608301516157a360808401826001600160a01b03169052565b50608083015167ffffffffffffffff811660a08401525060a083015160c083015260c08301516157d760e084018215159052565b5060e08301516101006157f4818501836001600160a01b03169052565b8085015191505061018061012081818601526158146101a08601846148f4565b92508086015190506101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086850301818701526158528483615702565b935080870151915050610160615872818701836001600160a01b03169052565b959095015193019290925250919050565b6bffffffffffffffffffffffff8281168282160390808211156144ba576144ba6152e6565b7fffffffff0000000000000000000000000000000000000000000000000000000081358181169160048510156158e85780818660040360031b1b83161692505b505092915050565b6000808585111561590057600080fd5b8386111561590d57600080fd5b5050820193919092039150565b60006020828403121561592c57600080fd5b6040516020810181811067ffffffffffffffff8211171561594f5761594f614998565b6040529135825250919050565b60006020828403121561596e57600080fd5b6113f382615226565b60006020828403121561598957600080fd5b81516113f38161489e565b6101808101615a1182856001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b82516001600160a01b0390811660e0840152602084015161ffff16610100840152604084015116610120830152606083015163ffffffff16610140830152608083015167ffffffffffffffff166101608301526113f3565b81810381811115610fbb57610fbb6152e6565b81810360008312801583831316838312821617156144ba576144ba6152e6565b602080825282518282018190526000919060409081850190868401855b82811015615b0957815180516001600160a01b031685528681015163ffffffff9081168887015286820151168686015260609081015161ffff169085015260809093019290850190600101615ab9565b5091979650505050505050565b600081615b2557615b256152e6565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b63ffffffff8181168382160190808211156144ba576144ba6152e6565b63ffffffff831681526040602082015260006125c66040830184615106565b602080825282518282018190526000919060409081850190868401855b82811015615b0957815180516001600160a01b031685528681015167ffffffffffffffff1687860152858101516bffffffffffffffffffffffff168686015260608082015163ffffffff169086015260808082015161ffff169086015260a09081015115159085015260c09093019290850190600101615ba4565b600060408284031215615c3157600080fd5b615c396149c7565b615c4283615226565b8152602083015161544f81614bd9565b6020815260006113f36020830184615702565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251615ca68184602087016148d0565b919091019291505056fea164736f6c6343000813000a",
+}
+
+var EVM2EVMOnRampABI = EVM2EVMOnRampMetaData.ABI
+
+var EVM2EVMOnRampBin = EVM2EVMOnRampMetaData.Bin
+
+func DeployEVM2EVMOnRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMOnRampStaticConfig, dynamicConfig EVM2EVMOnRampDynamicConfig, tokensAndPools []InternalPoolUpdate, allowlist []common.Address, rateLimiterConfig RateLimiterConfig, feeTokenConfigs []EVM2EVMOnRampFeeTokenConfigArgs, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (common.Address, *types.Transaction, *EVM2EVMOnRamp, error) {
+ parsed, err := EVM2EVMOnRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMOnRampBin), backend, staticConfig, dynamicConfig, tokensAndPools, allowlist, rateLimiterConfig, feeTokenConfigs, tokenTransferFeeConfigArgs, nopsAndWeights)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMOnRamp{EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMOnRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMOnRampCaller
+ EVM2EVMOnRampTransactor
+ EVM2EVMOnRampFilterer
+}
+
+type EVM2EVMOnRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampSession struct {
+ Contract *EVM2EVMOnRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOnRampCallerSession struct {
+ Contract *EVM2EVMOnRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMOnRampTransactorSession struct {
+ Contract *EVM2EVMOnRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOnRampRaw struct {
+ Contract *EVM2EVMOnRamp
+}
+
+type EVM2EVMOnRampCallerRaw struct {
+ Contract *EVM2EVMOnRampCaller
+}
+
+type EVM2EVMOnRampTransactorRaw struct {
+ Contract *EVM2EVMOnRampTransactor
+}
+
+func NewEVM2EVMOnRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMOnRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMOnRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMOnRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRamp{address: address, abi: abi, EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMOnRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMOnRampCaller, error) {
+ contract, err := bindEVM2EVMOnRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMOnRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMOnRampTransactor, error) {
+ contract, err := bindEVM2EVMOnRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMOnRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMOnRampFilterer, error) {
+ contract, err := bindEVM2EVMOnRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMOnRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMOnRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOnRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "currentRateLimiterState")
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOnRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOnRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetAllowList() ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetAllowList(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetAllowList() ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetAllowList(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetAllowListEnabled() (bool, error) {
+ return _EVM2EVMOnRamp.Contract.GetAllowListEnabled(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetAllowListEnabled() (bool, error) {
+ return _EVM2EVMOnRamp.Contract.GetAllowListEnabled(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOnRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOnRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampDynamicConfig)).(*EVM2EVMOnRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetDynamicConfig() (EVM2EVMOnRampDynamicConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetDynamicConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetDynamicConfig() (EVM2EVMOnRampDynamicConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetDynamicConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetFee(opts *bind.CallOpts, message ClientEVM2AnyMessage) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getFee", message)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetFee(message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetFee(&_EVM2EVMOnRamp.CallOpts, message)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetFee(message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetFee(&_EVM2EVMOnRamp.CallOpts, message)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getFeeTokenConfig", token)
+
+ if err != nil {
+ return *new(EVM2EVMOnRampFeeTokenConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampFeeTokenConfig)).(*EVM2EVMOnRampFeeTokenConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetFeeTokenConfig(token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetFeeTokenConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetFeeTokenConfig(token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetFeeTokenConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getNopFeesJuels")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetNopFeesJuels() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetNopFeesJuels(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetNopFeesJuels() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetNopFeesJuels(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetNops(opts *bind.CallOpts) (GetNops,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getNops")
+
+ outstruct := new(GetNops)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.NopsAndWeights = *abi.ConvertType(out[0], new([]EVM2EVMOnRampNopAndWeight)).(*[]EVM2EVMOnRampNopAndWeight)
+ outstruct.WeightsTotal = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetNops() (GetNops,
+
+ error) {
+ return _EVM2EVMOnRamp.Contract.GetNops(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetNops() (GetNops,
+
+ error) {
+ return _EVM2EVMOnRamp.Contract.GetNops(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getPoolBySourceToken", sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetPoolBySourceToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOnRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetPoolBySourceToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOnRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getSenderNonce", sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetSenderNonce(&_EVM2EVMOnRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetSenderNonce(&_EVM2EVMOnRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOnRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOnRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampStaticConfig)).(*EVM2EVMOnRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetStaticConfig() (EVM2EVMOnRampStaticConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetStaticConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetStaticConfig() (EVM2EVMOnRampStaticConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetStaticConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getSupportedTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetSupportedTokens() ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetSupportedTokens(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetSupportedTokens() ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetSupportedTokens(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getTokenLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getTokenTransferFeeConfig", token)
+
+ if err != nil {
+ return *new(EVM2EVMOnRampTokenTransferFeeConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampTokenTransferFeeConfig)).(*EVM2EVMOnRampTokenTransferFeeConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetTokenTransferFeeConfig(token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenTransferFeeConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetTokenTransferFeeConfig(token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenTransferFeeConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.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
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.LinkAvailableForPayment(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.LinkAvailableForPayment(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.Owner(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.Owner(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOnRamp.Contract.TypeAndVersion(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOnRamp.Contract.TypeAndVersion(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.AcceptOwnership(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.AcceptOwnership(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyAllowListUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyAllowListUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "applyPoolUpdates", removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ForwardFromRouter(opts *bind.TransactOpts, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "forwardFromRouter", message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ForwardFromRouter(message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ForwardFromRouter(&_EVM2EVMOnRamp.TransactOpts, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ForwardFromRouter(message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ForwardFromRouter(&_EVM2EVMOnRamp.TransactOpts, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) PayNops(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "payNops")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) PayNops() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.PayNops(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) PayNops() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.PayNops(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setAdmin", newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAdmin(&_EVM2EVMOnRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAdmin(&_EVM2EVMOnRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetAllowListEnabled(opts *bind.TransactOpts, enabled bool) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setAllowListEnabled", enabled)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetAllowListEnabled(enabled bool) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAllowListEnabled(&_EVM2EVMOnRamp.TransactOpts, enabled)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetAllowListEnabled(enabled bool) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAllowListEnabled(&_EVM2EVMOnRamp.TransactOpts, enabled)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setDynamicConfig", dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetDynamicConfig(dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetDynamicConfig(&_EVM2EVMOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetDynamicConfig(dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetDynamicConfig(&_EVM2EVMOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setFeeTokenConfig", feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetFeeTokenConfig(feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetFeeTokenConfig(&_EVM2EVMOnRamp.TransactOpts, feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetFeeTokenConfig(feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetFeeTokenConfig(&_EVM2EVMOnRamp.TransactOpts, feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetNops(opts *bind.TransactOpts, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setNops", nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetNops(nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetNops(&_EVM2EVMOnRamp.TransactOpts, nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetNops(nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetNops(&_EVM2EVMOnRamp.TransactOpts, nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setRateLimiterConfig", config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOnRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOnRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setTokenTransferFeeConfig", tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetTokenTransferFeeConfig(tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetTokenTransferFeeConfig(&_EVM2EVMOnRamp.TransactOpts, tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetTokenTransferFeeConfig(tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetTokenTransferFeeConfig(&_EVM2EVMOnRamp.TransactOpts, tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.TransferOwnership(&_EVM2EVMOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.TransferOwnership(&_EVM2EVMOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "withdrawNonLinkFees", feeToken, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) WithdrawNonLinkFees(feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.WithdrawNonLinkFees(&_EVM2EVMOnRamp.TransactOpts, feeToken, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) WithdrawNonLinkFees(feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.WithdrawNonLinkFees(&_EVM2EVMOnRamp.TransactOpts, feeToken, to)
+}
+
+type EVM2EVMOnRampAdminSetIterator struct {
+ Event *EVM2EVMOnRampAdminSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAdminSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAdminSet)
+ 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(EVM2EVMOnRampAdminSet)
+ 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 *EVM2EVMOnRampAdminSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAdminSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAdminSet struct {
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAdminSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAdminSetIterator{contract: _EVM2EVMOnRamp.contract, event: "AdminSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAdminSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAdminSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AdminSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAdminSet(log types.Log) (*EVM2EVMOnRampAdminSet, error) {
+ event := new(EVM2EVMOnRampAdminSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AdminSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampAllowListAddIterator struct {
+ Event *EVM2EVMOnRampAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAllowListAdd)
+ 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(EVM2EVMOnRampAllowListAdd)
+ 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 *EVM2EVMOnRampAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListAddIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAllowListAddIterator{contract: _EVM2EVMOnRamp.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAllowListAdd)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListAdd", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAllowListAdd(log types.Log) (*EVM2EVMOnRampAllowListAdd, error) {
+ event := new(EVM2EVMOnRampAllowListAdd)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampAllowListEnabledSetIterator struct {
+ Event *EVM2EVMOnRampAllowListEnabledSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAllowListEnabledSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAllowListEnabledSet)
+ 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(EVM2EVMOnRampAllowListEnabledSet)
+ 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 *EVM2EVMOnRampAllowListEnabledSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAllowListEnabledSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAllowListEnabledSet struct {
+ Enabled bool
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAllowListEnabledSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListEnabledSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AllowListEnabledSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAllowListEnabledSetIterator{contract: _EVM2EVMOnRamp.contract, event: "AllowListEnabledSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAllowListEnabledSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListEnabledSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AllowListEnabledSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAllowListEnabledSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListEnabledSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAllowListEnabledSet(log types.Log) (*EVM2EVMOnRampAllowListEnabledSet, error) {
+ event := new(EVM2EVMOnRampAllowListEnabledSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListEnabledSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampAllowListRemoveIterator struct {
+ Event *EVM2EVMOnRampAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAllowListRemove)
+ 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(EVM2EVMOnRampAllowListRemove)
+ 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 *EVM2EVMOnRampAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListRemoveIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAllowListRemoveIterator{contract: _EVM2EVMOnRamp.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAllowListRemove)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListRemove", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAllowListRemove(log types.Log) (*EVM2EVMOnRampAllowListRemove, error) {
+ event := new(EVM2EVMOnRampAllowListRemove)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampCCIPSendRequestedIterator struct {
+ Event *EVM2EVMOnRampCCIPSendRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampCCIPSendRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampCCIPSendRequested)
+ 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(EVM2EVMOnRampCCIPSendRequested)
+ 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 *EVM2EVMOnRampCCIPSendRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampCCIPSendRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampCCIPSendRequested struct {
+ Message InternalEVM2EVMMessage
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterCCIPSendRequested(opts *bind.FilterOpts) (*EVM2EVMOnRampCCIPSendRequestedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "CCIPSendRequested")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampCCIPSendRequestedIterator{contract: _EVM2EVMOnRamp.contract, event: "CCIPSendRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "CCIPSendRequested")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampCCIPSendRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "CCIPSendRequested", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseCCIPSendRequested(log types.Log) (*EVM2EVMOnRampCCIPSendRequested, error) {
+ event := new(EVM2EVMOnRampCCIPSendRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "CCIPSendRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampConfigSetIterator struct {
+ Event *EVM2EVMOnRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampConfigSet)
+ 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(EVM2EVMOnRampConfigSet)
+ 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 *EVM2EVMOnRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampConfigSet struct {
+ StaticConfig EVM2EVMOnRampStaticConfig
+ DynamicConfig EVM2EVMOnRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMOnRampConfigSet, error) {
+ event := new(EVM2EVMOnRampConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampFeeConfigSetIterator struct {
+ Event *EVM2EVMOnRampFeeConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampFeeConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampFeeConfigSet)
+ 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(EVM2EVMOnRampFeeConfigSet)
+ 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 *EVM2EVMOnRampFeeConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampFeeConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampFeeConfigSet struct {
+ FeeConfig []EVM2EVMOnRampFeeTokenConfigArgs
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampFeeConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "FeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampFeeConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "FeeConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampFeeConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "FeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "FeeConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseFeeConfigSet(log types.Log) (*EVM2EVMOnRampFeeConfigSet, error) {
+ event := new(EVM2EVMOnRampFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "FeeConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampNopPaidIterator struct {
+ Event *EVM2EVMOnRampNopPaid
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampNopPaidIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampNopPaid)
+ 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(EVM2EVMOnRampNopPaid)
+ 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 *EVM2EVMOnRampNopPaidIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampNopPaidIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampNopPaid struct {
+ Nop common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*EVM2EVMOnRampNopPaidIterator, error) {
+
+ var nopRule []interface{}
+ for _, nopItem := range nop {
+ nopRule = append(nopRule, nopItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "NopPaid", nopRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampNopPaidIterator{contract: _EVM2EVMOnRamp.contract, event: "NopPaid", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchNopPaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error) {
+
+ var nopRule []interface{}
+ for _, nopItem := range nop {
+ nopRule = append(nopRule, nopItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "NopPaid", nopRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampNopPaid)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopPaid", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseNopPaid(log types.Log) (*EVM2EVMOnRampNopPaid, error) {
+ event := new(EVM2EVMOnRampNopPaid)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopPaid", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampNopsSetIterator struct {
+ Event *EVM2EVMOnRampNopsSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampNopsSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampNopsSet)
+ 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(EVM2EVMOnRampNopsSet)
+ 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 *EVM2EVMOnRampNopsSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampNopsSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampNopsSet struct {
+ NopWeightsTotal *big.Int
+ NopsAndWeights []EVM2EVMOnRampNopAndWeight
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterNopsSet(opts *bind.FilterOpts) (*EVM2EVMOnRampNopsSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "NopsSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampNopsSetIterator{contract: _EVM2EVMOnRamp.contract, event: "NopsSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchNopsSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopsSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "NopsSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampNopsSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopsSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseNopsSet(log types.Log) (*EVM2EVMOnRampNopsSet, error) {
+ event := new(EVM2EVMOnRampNopsSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopsSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMOnRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampOwnershipTransferRequested)
+ 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(EVM2EVMOnRampOwnershipTransferRequested)
+ 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 *EVM2EVMOnRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampOwnershipTransferRequestedIterator{contract: _EVM2EVMOnRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOnRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMOnRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampOwnershipTransferred)
+ 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(EVM2EVMOnRampOwnershipTransferred)
+ 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 *EVM2EVMOnRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampOwnershipTransferredIterator{contract: _EVM2EVMOnRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampOwnershipTransferred)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMOnRampOwnershipTransferred, error) {
+ event := new(EVM2EVMOnRampOwnershipTransferred)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampPoolAddedIterator struct {
+ Event *EVM2EVMOnRampPoolAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampPoolAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampPoolAdded)
+ 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(EVM2EVMOnRampPoolAdded)
+ 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 *EVM2EVMOnRampPoolAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampPoolAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampPoolAdded struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolAddedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampPoolAddedIterator{contract: _EVM2EVMOnRamp.contract, event: "PoolAdded", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolAdded) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampPoolAdded)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolAdded", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParsePoolAdded(log types.Log) (*EVM2EVMOnRampPoolAdded, error) {
+ event := new(EVM2EVMOnRampPoolAdded)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampPoolRemovedIterator struct {
+ Event *EVM2EVMOnRampPoolRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampPoolRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampPoolRemoved)
+ 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(EVM2EVMOnRampPoolRemoved)
+ 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 *EVM2EVMOnRampPoolRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampPoolRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampPoolRemoved struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolRemovedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampPoolRemovedIterator{contract: _EVM2EVMOnRamp.contract, event: "PoolRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampPoolRemoved)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolRemoved", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParsePoolRemoved(log types.Log) (*EVM2EVMOnRampPoolRemoved, error) {
+ event := new(EVM2EVMOnRampPoolRemoved)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigSetIterator struct {
+ Event *EVM2EVMOnRampTokenTransferFeeConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ 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(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ 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 *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigSet struct {
+ TransferFeeConfig []EVM2EVMOnRampTokenTransferFeeConfigArgs
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "TokenTransferFeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTokenTransferFeeConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "TokenTransferFeeConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "TokenTransferFeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseTokenTransferFeeConfigSet(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigSet, error) {
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetNops struct {
+ NopsAndWeights []EVM2EVMOnRampNopAndWeight
+ WeightsTotal *big.Int
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMOnRamp.abi.Events["AdminSet"].ID:
+ return _EVM2EVMOnRamp.ParseAdminSet(log)
+ case _EVM2EVMOnRamp.abi.Events["AllowListAdd"].ID:
+ return _EVM2EVMOnRamp.ParseAllowListAdd(log)
+ case _EVM2EVMOnRamp.abi.Events["AllowListEnabledSet"].ID:
+ return _EVM2EVMOnRamp.ParseAllowListEnabledSet(log)
+ case _EVM2EVMOnRamp.abi.Events["AllowListRemove"].ID:
+ return _EVM2EVMOnRamp.ParseAllowListRemove(log)
+ case _EVM2EVMOnRamp.abi.Events["CCIPSendRequested"].ID:
+ return _EVM2EVMOnRamp.ParseCCIPSendRequested(log)
+ case _EVM2EVMOnRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["FeeConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseFeeConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["NopPaid"].ID:
+ return _EVM2EVMOnRamp.ParseNopPaid(log)
+ case _EVM2EVMOnRamp.abi.Events["NopsSet"].ID:
+ return _EVM2EVMOnRamp.ParseNopsSet(log)
+ case _EVM2EVMOnRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMOnRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMOnRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMOnRamp.ParseOwnershipTransferred(log)
+ case _EVM2EVMOnRamp.abi.Events["PoolAdded"].ID:
+ return _EVM2EVMOnRamp.ParsePoolAdded(log)
+ case _EVM2EVMOnRamp.abi.Events["PoolRemoved"].ID:
+ return _EVM2EVMOnRamp.ParsePoolRemoved(log)
+ case _EVM2EVMOnRamp.abi.Events["TokenTransferFeeConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseTokenTransferFeeConfigSet(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMOnRampAdminSet) Topic() common.Hash {
+ return common.HexToHash("0x8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c")
+}
+
+func (EVM2EVMOnRampAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (EVM2EVMOnRampAllowListEnabledSet) Topic() common.Hash {
+ return common.HexToHash("0xccf4daf6ab6430389f26b970595dab82a5881ad454770907e415ede27c8df032")
+}
+
+func (EVM2EVMOnRampAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (EVM2EVMOnRampCCIPSendRequested) Topic() common.Hash {
+ return common.HexToHash("0xaffc45517195d6499808c643bd4a7b0ffeedf95bea5852840d7bfcf63f59e821")
+}
+
+func (EVM2EVMOnRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xdd226617d8d287f40a64c54741bbcdc492b3e096ef16bc5273a18cb6ab85f124")
+}
+
+func (EVM2EVMOnRampFeeConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xfba339fca97870ffdfaedbae3745db5e6de1a6909dfd0e0dbb56917469ffe236")
+}
+
+func (EVM2EVMOnRampNopPaid) Topic() common.Hash {
+ return common.HexToHash("0x55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f")
+}
+
+func (EVM2EVMOnRampNopsSet) Topic() common.Hash {
+ return common.HexToHash("0x8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd24")
+}
+
+func (EVM2EVMOnRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMOnRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (EVM2EVMOnRampPoolAdded) Topic() common.Hash {
+ return common.HexToHash("0x95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c")
+}
+
+func (EVM2EVMOnRampPoolRemoved) Topic() common.Hash {
+ return common.HexToHash("0x987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c")
+}
+
+func (EVM2EVMOnRampTokenTransferFeeConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xcb0c5f472d325cf0c56953fc81870ddd80d0d3c9a3fbfe777002d75f380dfb81")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRamp) Address() common.Address {
+ return _EVM2EVMOnRamp.address
+}
+
+type EVM2EVMOnRampInterface interface {
+ CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOnRampDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetFee(opts *bind.CallOpts, message ClientEVM2AnyMessage) (*big.Int, error)
+
+ GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampFeeTokenConfig, error)
+
+ GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error)
+
+ GetNops(opts *bind.CallOpts) (GetNops,
+
+ error)
+
+ GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error)
+
+ GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOnRampStaticConfig, error)
+
+ GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error)
+
+ LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error)
+
+ ForwardFromRouter(opts *bind.TransactOpts, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error)
+
+ PayNops(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error)
+
+ SetAllowListEnabled(opts *bind.TransactOpts, enabled bool) (*types.Transaction, error)
+
+ SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error)
+
+ SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error)
+
+ SetNops(opts *bind.TransactOpts, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error)
+
+ SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error)
+
+ SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error)
+
+ FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAdminSetIterator, error)
+
+ WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAdminSet) (event.Subscription, error)
+
+ ParseAdminSet(log types.Log) (*EVM2EVMOnRampAdminSet, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*EVM2EVMOnRampAllowListAdd, error)
+
+ FilterAllowListEnabledSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListEnabledSetIterator, error)
+
+ WatchAllowListEnabledSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListEnabledSet) (event.Subscription, error)
+
+ ParseAllowListEnabledSet(log types.Log) (*EVM2EVMOnRampAllowListEnabledSet, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*EVM2EVMOnRampAllowListRemove, error)
+
+ FilterCCIPSendRequested(opts *bind.FilterOpts) (*EVM2EVMOnRampCCIPSendRequestedIterator, error)
+
+ WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error)
+
+ ParseCCIPSendRequested(log types.Log) (*EVM2EVMOnRampCCIPSendRequested, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMOnRampConfigSet, error)
+
+ FilterFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampFeeConfigSetIterator, error)
+
+ WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampFeeConfigSet) (event.Subscription, error)
+
+ ParseFeeConfigSet(log types.Log) (*EVM2EVMOnRampFeeConfigSet, error)
+
+ FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*EVM2EVMOnRampNopPaidIterator, error)
+
+ WatchNopPaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error)
+
+ ParseNopPaid(log types.Log) (*EVM2EVMOnRampNopPaid, error)
+
+ FilterNopsSet(opts *bind.FilterOpts) (*EVM2EVMOnRampNopsSetIterator, error)
+
+ WatchNopsSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopsSet) (event.Subscription, error)
+
+ ParseNopsSet(log types.Log) (*EVM2EVMOnRampNopsSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOnRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMOnRampOwnershipTransferred, error)
+
+ FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolAddedIterator, error)
+
+ WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolAdded) (event.Subscription, error)
+
+ ParsePoolAdded(log types.Log) (*EVM2EVMOnRampPoolAdded, error)
+
+ FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolRemovedIterator, error)
+
+ WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolRemoved) (event.Subscription, error)
+
+ ParsePoolRemoved(log types.Log) (*EVM2EVMOnRampPoolRemoved, error)
+
+ FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error)
+
+ WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error)
+
+ ParseTokenTransferFeeConfigSet(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigSet, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_1_0/evm_2_evm_onramp_1_1_0.go b/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_1_0/evm_2_evm_onramp_1_1_0.go
new file mode 100644
index 00000000000..fb5aa512ac9
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_1_0/evm_2_evm_onramp_1_1_0.go
@@ -0,0 +1,2794 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_onramp_1_1_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMOnRampDynamicConfig struct {
+ Router common.Address
+ MaxTokensLength uint16
+ DestGasOverhead uint32
+ DestGasPerPayloadByte uint16
+ PriceRegistry common.Address
+ MaxDataSize uint32
+ MaxGasLimit uint64
+}
+
+type EVM2EVMOnRampFeeTokenConfig struct {
+ NetworkFeeUSD uint32
+ MinTokenTransferFeeUSD uint32
+ MaxTokenTransferFeeUSD uint32
+ GasMultiplier uint64
+ PremiumMultiplier uint64
+ Enabled bool
+}
+
+type EVM2EVMOnRampFeeTokenConfigArgs struct {
+ Token common.Address
+ NetworkFeeUSD uint32
+ MinTokenTransferFeeUSD uint32
+ MaxTokenTransferFeeUSD uint32
+ GasMultiplier uint64
+ PremiumMultiplier uint64
+ Enabled bool
+}
+
+type EVM2EVMOnRampNopAndWeight struct {
+ Nop common.Address
+ Weight uint16
+}
+
+type EVM2EVMOnRampStaticConfig struct {
+ LinkToken common.Address
+ ChainSelector uint64
+ DestChainSelector uint64
+ DefaultTxGasLimit uint64
+ MaxNopFeesJuels *big.Int
+ PrevOnRamp common.Address
+ ArmProxy common.Address
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfig struct {
+ Ratio uint16
+ DestGasOverhead uint32
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigArgs struct {
+ Token common.Address
+ Ratio uint16
+ DestGasOverhead uint32
+}
+
+type InternalEVM2EVMMessage struct {
+ SourceChainSelector uint64
+ SequenceNumber uint64
+ FeeTokenAmount *big.Int
+ Sender common.Address
+ Nonce uint64
+ GasLimit *big.Int
+ Strict bool
+ Receiver common.Address
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ MessageId [32]byte
+}
+
+type InternalPoolUpdate struct {
+ Token common.Address
+ Pool common.Address
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+var EVM2EVMOnRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"maxGasLimit\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"tokensAndPools\",\"type\":\"tuple[]\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"minTokenTransferFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeTokenConfigs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"ratio\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"}],\"name\":\"InvalidNopAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTokenPoolConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWithdrawParams\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkBalanceNotSettled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxFeeBalanceReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MessageGasLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeCalledByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoFeesToPay\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoNopsToPay\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"NotAFeeToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdminOrNop\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PoolAlreadyAdded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PoolDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PriceNotFoundForToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustSetOriginalSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenPoolMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyNops\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"UnsupportedToken\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"AllowListEnabledSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structInternal.EVM2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"CCIPSendRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"maxGasLimit\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"minTokenTransferFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeConfig\",\"type\":\"tuple[]\"}],\"name\":\"FeeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NopPaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nopWeightsTotal\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"NopsSet\",\"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\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"ratio\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"transferFeeConfig\",\"type\":\"tuple[]\"}],\"name\":\"TokenTransferFeeConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"removes\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"adds\",\"type\":\"tuple[]\"}],\"name\":\"applyPoolUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"}],\"name\":\"forwardFromRouter\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"maxGasLimit\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getFeeTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"networkFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"minTokenTransferFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfig\",\"name\":\"feeTokenConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNopFeesJuels\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNops\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"weightsTotal\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getPoolBySourceToken\",\"outputs\":[{\"internalType\":\"contractIPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getSenderNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenTransferFeeConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"ratio\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"payNops\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"setAllowListEnabled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxTokensLength\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataSize\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"maxGasLimit\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"setDynamicConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"minTokenTransferFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxTokenTransferFeeUSD\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplier\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeTokenConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setFeeTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setNops\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"ratio\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setTokenTransferFeeConfig\",\"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\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawNonLinkFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101806040526012805460ff60c01b191690553480156200001f57600080fd5b506040516200834538038062008345833981016040819052620000429162001e90565b8333806000816200009a5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000cd57620000cd8162000369565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080909301839052600380546001600160a01b031916909417600160801b9283021760ff60a01b1916600160a01b90910217909255029091176004555087516001600160a01b0316158062000176575060208801516001600160401b0316155b806200018d575060408801516001600160401b0316155b80620001a4575060608801516001600160401b0316155b80620001bb575060c08801516001600160a01b0316155b15620001da576040516306b7c75960e31b815260040160405180910390fd5b6020808901516040808b015181517fbdd59ac4dd1d82276c9a9c5d2656546346b9dcdb1f9b4204aed4ec15c23d7d3a948101949094526001600160401b039283169184019190915216606082015230608082015260a00160408051601f19818403018152918152815160209283012060809081528a516001600160a01b0390811660e052928b01516001600160401b0390811661010052918b015182166101205260608b015190911660a0908152908a01516001600160601b031660c0908152908a01518216610140528901511661016052620002b78762000414565b620002c2836200059e565b620002cd8262000739565b620002d88162000810565b6040805160008082526020820190925262000323916200031b565b6040805180820190915260008082526020820152815260200190600190039081620002f35790505b508762000a3a565b8451156200035b576012805460ff60c81b1916600160c81b179055604080516000808252602082019092526200035b91508662000d3d565b505050505050505062002407565b336001600160a01b03821603620003c35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000091565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60808101516001600160a01b031662000440576040516306b7c75960e31b815260040160405180910390fd5b8051600580546020808501516040808701516060808901516001600160a01b039889166001600160b01b031990971696909617600160a01b61ffff95861681029190911765ffffffffffff60b01b1916600160b01b63ffffffff9485160261ffff60d01b191617600160d01b9590971694909402959095179095556080808801516006805460a0808c015160c0808e0151958d166001600160c01b0319909416939093179a16909602989098176001600160c01b0316600160c01b6001600160401b0393841602179055825160e08082018552518916815261010051821695810195909552610120518116858401528351169484019490945284516001600160601b031693830193909352610140518516908201526101605190931691830191909152517f72c6aaba4dde02f77d291123a76185c418ba63f8c217a2d56b08aec84e9bbfb8916200059391849062001fb3565b60405180910390a150565b60005b815181101562000707576000828281518110620005c257620005c26200207f565b6020908102919091018101516040805160c080820183528385015163ffffffff908116835283850151811683870190815260608087015183168587019081526080808901516001600160401b0390811693880193845260a0808b01518216928901928352968a0151151596880196875298516001600160a01b03166000908152600f909a529690982094518554925198519151965194511515600160e01b0260ff60e01b19958916600160a01b0295909516600160a01b600160e81b0319979098166c0100000000000000000000000002600160601b600160a01b0319928516680100000000000000000292909216600160401b600160a01b0319998516640100000000026001600160401b0319909416919094161791909117969096161794909417919091169190911791909117905550620006ff81620020ab565b9050620005a1565b507f2386f61ab5cafc3fed44f9f614f721ab53479ef64067fd16c1a2491b63ddf1a881604051620005939190620020c7565b60005b8151811015620007de5760008282815181106200075d576200075d6200207f565b6020908102919091018101516040805180820182528284015161ffff90811682528284015163ffffffff90811683870190815294516001600160a01b03166000908152601090965292909420905181549351909216620100000265ffffffffffff19909316919093161717905550620007d681620020ab565b90506200073c565b507f4230c60a9725eb5fb992cf6a215398b4e81b4606d4a1e6be8dfe0b60dc172ec1816040516200059391906200217f565b805160408111156200083557604051635ad0867d60e11b815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff16158015906200087f575060125463ffffffff6c010000000000000000000000008204166001600160601b0390911610155b156200088f576200088f62000e88565b60006200089d600762001088565b90505b8015620008e9576000620008c3620008ba600184620021e0565b6007906200109b565b509050620008d3600782620010b9565b505080620008e190620021f6565b9050620008a0565b506000805b82811015620009d15760008482815181106200090e576200090e6200207f565b602002602001015160000151905060008583815181106200093357620009336200207f565b602002602001015160200151905060e0516001600160a01b0316826001600160a01b031614806200096b57506001600160a01b038216155b156200099657604051634de938d160e01b81526001600160a01b038316600482015260240162000091565b620009a860078361ffff8416620010d7565b50620009b961ffff82168562002210565b9350505080620009c990620020ab565b9050620008ee565b506012805463ffffffff60601b19166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd249062000a2d908390869062002230565b60405180910390a1505050565b60005b825181101562000b7657600083828151811062000a5e5762000a5e6200207f565b6020026020010151600001519050600084838151811062000a835762000a836200207f565b6020908102919091018101510151905062000aa0600a83620010f7565b62000aca576040516373913ebd60e01b81526001600160a01b038316600482015260240162000091565b6001600160a01b03811662000ae1600a846200110e565b6001600160a01b03161462000b0957604051630d98f73360e31b815260040160405180910390fd5b62000b16600a8362001125565b1562000b6057604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b50508062000b6e90620020ab565b905062000a3d565b5060005b815181101562000d3857600082828151811062000b9b5762000b9b6200207f565b6020026020010151600001519050600083838151811062000bc05762000bc06200207f565b602002602001015160200151905060006001600160a01b0316826001600160a01b0316148062000bf757506001600160a01b038116155b1562000c155760405162d8548360e71b815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000c54573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c7a91906200229d565b6001600160a01b0316826001600160a01b03161462000cac57604051630d98f73360e31b815260040160405180910390fd5b62000cba600a83836200113c565b1562000d0957604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a162000d22565b604051633caf458560e01b815260040160405180910390fd5b50508062000d3090620020ab565b905062000b7a565b505050565b60005b825181101562000dd257600083828151811062000d615762000d616200207f565b6020908102919091010151905062000d7b600d8262001154565b1562000dbe576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b5062000dca81620020ab565b905062000d40565b5060005b815181101562000d3857600082828151811062000df75762000df76200207f565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000e23575062000e75565b62000e30600d826200116b565b1562000e73576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b62000e8081620020ab565b905062000dd6565b6000546001600160a01b0316331480159062000eaf57506002546001600160a01b03163314155b801562000ec6575062000ec460073362001182565b155b1562000ee55760405163032bb72b60e31b815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff16600081900362000f215760405163990e30bf60e01b815260040160405180910390fd5b6012546001600160601b03168181101562000f4f576040516311a1ee3b60e31b815260040160405180910390fd5b600062000f5b62001199565b121562000f7b57604051631e9acf1760e31b815260040160405180910390fd5b80600062000f8a600762001088565b905060005b81811015620010625760008062000fa86007846200109b565b909250905060008762000fc5836001600160601b038a16620022bd565b62000fd19190620022d7565b905062000fdf8187620022fa565b60e05190965062001004906001600160a01b0316846001600160601b03841662001227565b6040516001600160601b03821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a2505050806200105a90620020ab565b905062000f8f565b5050601280546001600160601b0319166001600160601b03929092169190911790555050565b600062001095826200127f565b92915050565b6000808080620010ac86866200128c565b9097909650945050505050565b6000620010d0836001600160a01b038416620012b9565b9392505050565b6000620010ef846001600160a01b03851684620012d8565b949350505050565b6000620010d0836001600160a01b038416620012f7565b6000620010d0836001600160a01b03841662001305565b6000620010d0836001600160a01b03841662001313565b6000620010ef846001600160a01b0385168462001321565b6000620010d0836001600160a01b03841662001339565b6000620010d0836001600160a01b03841662001444565b6000620010d0836001600160a01b03841662001496565b60125460e0516040516370a0823160e01b81523060048201526000926001600160601b0316916001600160a01b0316906370a0823190602401602060405180830381865afa158015620011f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200121691906200231d565b62001222919062002337565b905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663a9059cbb60e01b1790915262000d38918591620014a416565b6000620010958262001575565b600080806200129c858562001580565b600081815260029690960160205260409095205494959350505050565b60008181526002830160205260408120819055620010d083836200158e565b60008281526002840160205260408120829055620010ef84846200159c565b6000620010d0838362001496565b6000620010d08383620015aa565b6000620010d08383620012b9565b6000620010ef84846001600160a01b038516620012d8565b600081815260018301602052604081205480156200143257600062001360600183620021e0565b85549091506000906200137690600190620021e0565b9050818114620013e25760008660000182815481106200139a576200139a6200207f565b9060005260206000200154905080876000018481548110620013c057620013c06200207f565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620013f657620013f66200235a565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062001095565b600091505062001095565b5092915050565b60008181526001830160205260408120546200148d5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562001095565b50600062001095565b6000620010d083836200161f565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490820152600090620014f3906001600160a01b03851690849062001638565b80519091501562000d38578080602001905181019062001514919062002370565b62000d385760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000091565b600062001095825490565b6000620010d0838362001649565b6000620010d0838362001339565b6000620010d0838362001444565b600081815260028301602052604081205480151580620015d15750620015d1848462001496565b620010d05760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b65790000604482015260640162000091565b60008181526001830160205260408120541515620010d0565b6060620010ef848460008562001676565b60008260000182815481106200166357620016636200207f565b9060005260206000200154905092915050565b606082471015620016d95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000091565b600080866001600160a01b03168587604051620016f79190620023b4565b60006040518083038185875af1925050503d806000811462001736576040519150601f19603f3d011682016040523d82523d6000602084013e6200173b565b606091505b5090925090506200174f878383876200175a565b979650505050505050565b60608315620017ce578251600003620017c6576001600160a01b0385163b620017c65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000091565b5081620010ef565b620010ef8383815115620017e55781518083602001fd5b8060405162461bcd60e51b8152600401620000919190620023d2565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156200183c576200183c62001801565b60405290565b604080519081016001600160401b03811182821017156200183c576200183c62001801565b604051606081016001600160401b03811182821017156200183c576200183c62001801565b604051601f8201601f191681016001600160401b0381118282101715620018b757620018b762001801565b604052919050565b6001600160a01b0381168114620018d557600080fd5b50565b8051620018e581620018bf565b919050565b80516001600160401b0381168114620018e557600080fd5b600060e082840312156200191557600080fd5b6200191f62001817565b905081516200192e81620018bf565b81526200193e60208301620018ea565b60208201526200195160408301620018ea565b60408201526200196460608301620018ea565b606082015260808201516001600160601b03811681146200198457600080fd5b60808201526200199760a08301620018d8565b60a0820152620019aa60c08301620018d8565b60c082015292915050565b805161ffff81168114620018e557600080fd5b805163ffffffff81168114620018e557600080fd5b600060e08284031215620019f057600080fd5b620019fa62001817565b9050815162001a0981620018bf565b815262001a1960208301620019b5565b602082015262001a2c60408301620019c8565b604082015262001a3f60608301620019b5565b6060820152608082015162001a5481620018bf565b608082015262001a6760a08301620019c8565b60a0820152620019aa60c08301620018ea565b60006001600160401b0382111562001a965762001a9662001801565b5060051b60200190565b600082601f83011262001ab257600080fd5b8151602062001acb62001ac58362001a7a565b6200188c565b82815260069290921b8401810191818101908684111562001aeb57600080fd5b8286015b8481101562001b45576040818903121562001b0a5760008081fd5b62001b1462001842565b815162001b2181620018bf565b81528185015162001b3281620018bf565b8186015283529183019160400162001aef565b509695505050505050565b600082601f83011262001b6257600080fd5b8151602062001b7562001ac58362001a7a565b82815260059290921b8401810191818101908684111562001b9557600080fd5b8286015b8481101562001b4557805162001baf81620018bf565b835291830191830162001b99565b80518015158114620018e557600080fd5b80516001600160801b0381168114620018e557600080fd5b60006060828403121562001bf957600080fd5b62001c0362001867565b905062001c108262001bbd565b815262001c206020830162001bce565b602082015262001c336040830162001bce565b604082015292915050565b600082601f83011262001c5057600080fd5b8151602062001c6362001ac58362001a7a565b82815260e0928302850182019282820191908785111562001c8357600080fd5b8387015b8581101562001d385781818a03121562001ca15760008081fd5b62001cab62001817565b815162001cb881620018bf565b815262001cc7828701620019c8565b86820152604062001cda818401620019c8565b90820152606062001ced838201620019c8565b90820152608062001d00838201620018ea565b9082015260a062001d13838201620018ea565b9082015260c062001d2683820162001bbd565b90820152845292840192810162001c87565b5090979650505050505050565b600082601f83011262001d5757600080fd5b8151602062001d6a62001ac58362001a7a565b8281526060928302850182019282820191908785111562001d8a57600080fd5b8387015b8581101562001d385781818a03121562001da85760008081fd5b62001db262001867565b815162001dbf81620018bf565b815262001dce828701620019b5565b86820152604062001de1818401620019c8565b90820152845292840192810162001d8e565b600082601f83011262001e0557600080fd5b8151602062001e1862001ac58362001a7a565b82815260069290921b8401810191818101908684111562001e3857600080fd5b8286015b8481101562001b45576040818903121562001e575760008081fd5b62001e6162001842565b815162001e6e81620018bf565b815262001e7d828601620019b5565b8186015283529183019160400162001e3c565b6000806000806000806000806102c0898b03121562001eae57600080fd5b62001eba8a8a62001902565b975062001ecb8a60e08b01620019dd565b6101c08a01519097506001600160401b038082111562001eea57600080fd5b62001ef88c838d0162001aa0565b97506101e08b015191508082111562001f1057600080fd5b62001f1e8c838d0162001b50565b965062001f308c6102008d0162001be6565b95506102608b015191508082111562001f4857600080fd5b62001f568c838d0162001c3e565b94506102808b015191508082111562001f6e57600080fd5b62001f7c8c838d0162001d45565b93506102a08b015191508082111562001f9457600080fd5b5062001fa38b828c0162001df3565b9150509295985092959890939650565b82516001600160a01b0390811682526020808501516001600160401b03908116828501526040808701518216818601526060808801518316818701526080808901516001600160601b03168188015260a0808a015187168189015260c0808b01518816818a01528951881660e08a01529589015161ffff9081166101008a01529389015163ffffffff9081166101208a015292890151909316610140880152870151909416610160860152850151909216610180840152830151166101a08201526101c08101620010d0565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620020c057620020c062002095565b5060010190565b602080825282518282018190526000919060409081850190868401855b828110156200217257815180516001600160a01b031685528681015163ffffffff9081168887015286820151811687870152606080830151909116908601526080808201516001600160401b03169086015260a08082015162002151878301826001600160401b03169052565b505060c09081015115159085015260e09093019290850190600101620020e4565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b828110156200217257815180516001600160a01b031685528681015161ffff168786015285015163ffffffff1685850152606090930192908501906001016200219c565b8181038181111562001095576200109562002095565b60008162002208576200220862002095565b506000190190565b63ffffffff8181168382160190808211156200143d576200143d62002095565b6000604080830163ffffffff8616845260208281860152818651808452606087019150828801935060005b818110156200228f57845180516001600160a01b0316845284015161ffff168484015293830193918501916001016200225b565b509098975050505050505050565b600060208284031215620022b057600080fd5b8151620010d081620018bf565b808202811582820484141762001095576200109562002095565b600082620022f557634e487b7160e01b600052601260045260246000fd5b500490565b6001600160601b038281168282160390808211156200143d576200143d62002095565b6000602082840312156200233057600080fd5b5051919050565b81810360008312801583831316838312821617156200143d576200143d62002095565b634e487b7160e01b600052603160045260246000fd5b6000602082840312156200238357600080fd5b620010d08262001bbd565b60005b83811015620023ab57818101518382015260200162002391565b50506000910152565b60008251620023c88184602087016200238e565b9190910192915050565b6020815260008251806020840152620023f38160408501602087016200238e565b601f01601f19169190910160400192915050565b60805160a05160c05160e05161010051610120516101405161016051615e376200250e600039600081816103600152818161148701526135700152600081816103310152818161139d01528181611405015281816119cc01528181611a34015261354901526000818161029d01528181610bcf01528181611dc401526134c301526000818161026d01528181611aff015261349901526000818161023e01528181610f320152818161177f015281816118780152818161237d015281816130380152818161347401526137000152600081816102fd0152818161194401526135130152600081816102cd015281816126c401526134ea01526000611cde0152615e376000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806376f6ae761161010f578063c92b2832116100a2578063e76c0b0611610071578063e76c0b0614610943578063efeadb6d14610956578063eff7cc4814610969578063f2fde38b1461097157600080fd5b8063c92b2832146108ed578063d09dc33914610900578063d3c7c2c714610908578063e0351e131461091057600080fd5b80639a113c36116100de5780639a113c3614610742578063a7cd63b7146108af578063a7d3e02f146108c4578063b06d41bc146108d757600080fd5b806376f6ae761461070357806379ba509714610716578063856c82471461071e5780638da5cb5b1461073157600080fd5b8063549e946f116101875780635d86f141116101565780635d86f141146105ae578063704b6c02146105c15780637132721a146105d45780637437ff9f146105e757600080fd5b8063549e946f1461054357806354b714681461055657806354c8a4f314610576578063599f64311461058957600080fd5b806338724a95116101c357806338724a951461048a5780633a87ac53146104ab5780634120fccd146104be578063546719cd146104df57600080fd5b806306285c69146101f55780631772047e146103a6578063181f5a771461042c578063352e4bc814610475575b600080fd5b6103906040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b60405161039d919061499d565b60405180910390f35b6104076103b4366004614a2e565b6040805180820190915260008082526020820152506001600160a01b031660009081526010602090815260409182902082518084019093525461ffff8116835262010000900463ffffffff169082015290565b60408051825161ffff16815260209283015163ffffffff16928101929092520161039d565b6104686040518060400160405280601381526020017f45564d3245564d4f6e52616d7020312e312e300000000000000000000000000081525081565b60405161039d9190614ab9565b610488610483366004614c1a565b610984565b005b61049d610498366004614d50565b6109ed565b60405190815260200161039d565b6104886104b9366004614e21565b610dd9565b6104c6610def565b60405167ffffffffffffffff909116815260200161039d565b6104e7610e23565b60405161039d919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b610488610551366004614e85565b610ed3565b6012546040516bffffffffffffffffffffffff909116815260200161039d565b610488610584366004614f22565b611088565b6002546001600160a01b03165b6040516001600160a01b03909116815260200161039d565b6105966105bc366004614a2e565b61109a565b6104886105cf366004614a2e565b6110f9565b6104886105e2366004614f8e565b6111c3565b6106f66040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810191909152506040805160e0810182526005546001600160a01b03808216835261ffff740100000000000000000000000000000000000000008084048216602086015263ffffffff76010000000000000000000000000000000000000000000085048116968601969096527a010000000000000000000000000000000000000000000000000000909304166060840152600654908116608084015290810490921660a082015267ffffffffffffffff78010000000000000000000000000000000000000000000000009092049190911660c082015290565b60405161039d9190615026565b6104886107113660046150a1565b6111d4565b61048861128c565b6104c661072c366004614a2e565b61136f565b6000546001600160a01b0316610596565b610845610750366004614a2e565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506001600160a01b03166000908152600f6020908152604091829020825160c081018452905463ffffffff808216835264010000000082048116938301939093526801000000000000000081049092169281019290925267ffffffffffffffff6c0100000000000000000000000082048116606084015274010000000000000000000000000000000000000000820416608083015260ff7c010000000000000000000000000000000000000000000000000000000090910416151560a082015290565b60405161039d9190600060c08201905063ffffffff80845116835280602085015116602084015280604085015116604084015250606083015167ffffffffffffffff8082166060850152806080860151166080850152505060a0830151151560a083015292915050565b6108b7611477565b60405161039d9190615116565b61049d6108d2366004615163565b611483565b6108df611eab565b60405161039d929190615211565b6104886108fb366004615253565b611faf565b61049d612017565b6108b7612021565b601254790100000000000000000000000000000000000000000000000000900460ff16604051901515815260200161039d565b6104886109513660046152a3565b6120d2565b61048861096436600461536c565b612138565b6104886121be565b61048861097f366004614a2e565b612455565b6000546001600160a01b031633148015906109aa57506002546001600160a01b03163314155b156109e1576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109ea81612466565b50565b600080610a05610a006080850185615389565b612695565b9050610a30610a176020850185615389565b8351909150610a2960408701876153ee565b9050612789565b6000600f81610a456080870160608801614a2e565b6001600160a01b031681526020808201929092526040908101600020815160c081018352905463ffffffff80821683526401000000008204811694830194909452680100000000000000008104909316918101919091526c01000000000000000000000000820467ffffffffffffffff90811660608301527401000000000000000000000000000000000000000083041660808201527c010000000000000000000000000000000000000000000000000000000090910460ff16151560a08201819052909150610b6257610b1f6080850160608601614a2e565b6040517fa7499d200000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024015b60405180910390fd5b60065460009081906001600160a01b031663ffdb4b37610b886080890160608a01614a2e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044016040805180830381865afa158015610c13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c37919061547e565b909250905060008080610c4d60408a018a6153ee565b90501115610c8657610c7c610c6860808a0160608b01614a2e565b85610c7660408c018c6153ee565b896128ae565b9092509050610ca2565b8451610c9f9063ffffffff16662386f26fc100006154e0565b91505b6080850151610cbb9067ffffffffffffffff16836154e0565b606086015160055491935060009167ffffffffffffffff9091169063ffffffff8416907a010000000000000000000000000000000000000000000000000000900461ffff16610d0d60208d018d615389565b610d189291506154e0565b6005548a51610d4791760100000000000000000000000000000000000000000000900463ffffffff16906154f7565b610d5191906154f7565b610d5b91906154f7565b610d6591906154e0565b610d899077ffffffffffffffffffffffffffffffffffffffffffffffff86166154e0565b9050610dcc670de0b6b3a7640000610da183866154f7565b610dab919061550a565b77ffffffffffffffffffffffffffffffffffffffffffffffff871690612b34565b9998505050505050505050565b610de1612b6d565b610deb8282612be3565b5050565b601254600090610e1e90700100000000000000000000000000000000900467ffffffffffffffff166001615545565b905090565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff161515938301939093526004548084166060840152049091166080820152610e1e90612f43565b6000546001600160a01b03163314801590610ef957506002546001600160a01b03163314155b15610f30576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480610f7757506001600160a01b038116155b15610fae576040517f232cb97f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610fb8612ff5565b1215610ff0576040517f02075e0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610deb9082906001600160a01b038516906370a0823190602401602060405180830381865afa158015611053573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110779190615566565b6001600160a01b03851691906130b5565b611090612b6d565b610deb8282613135565b60006110a7600a83613270565b6110e8576040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610b59565b6110f3600a83613285565b92915050565b6000546001600160a01b0316331480159061111f57506002546001600160a01b03163314155b15611156576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c906020015b60405180910390a150565b6111cb612b6d565b6109ea8161329a565b6000546001600160a01b031633148015906111fa57506002546001600160a01b03163314155b15611231576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610deb8282808060200260200160405190810160405280939291908181526020016000905b82821015611282576112736040830286013681900381019061557f565b81526020019060010190611256565b50505050506135c7565b6001546001600160a01b03163314611300576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610b59565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6001600160a01b03811660009081526011602052604081205467ffffffffffffffff16801580156113c857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b156110f3576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa15801561144c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147091906155be565b9392505050565b6060610e1e600d61383a565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150791906155db565b1561153e576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03821661157e576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254790100000000000000000000000000000000000000000000000000900460ff1680156115b557506115b3600d83613847565b155b156115f7576040517fd0d259760000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610b59565b6005546001600160a01b0316331461163b576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116458480615389565b905060201461168c576116588480615389565b6040517f370d875f000000000000000000000000000000000000000000000000000000008152600401610b59929190615641565b60006116988580615389565b8101906116a59190615655565b90506001600160a01b038111806116bc5750600a81105b156116cb576116588580615389565b60006116dd610a006080880188615389565b90506117016116ef6020880188615389565b8351909150610a2960408a018a6153ee565b61177561171160408801886153ee565b808060200260200160405190810160405280939291908181526020016000905b8282101561175d5761174e6040830286013681900381019061566e565b81526020019060010190611731565b50506006546001600160a01b03169250613869915050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166117af6080880160608901614a2e565b6001600160a01b03160361181357601280548691906000906117e09084906bffffffffffffffffffffffff166156a8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550611932565b6006546001600160a01b03166241e5be6118336080890160608a01614a2e565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039182166004820152602481018990527f00000000000000000000000000000000000000000000000000000000000000009091166044820152606401602060405180830381865afa1580156118bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118e39190615566565b601280546000906119039084906bffffffffffffffffffffffff166156a8565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b6012546bffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116111561199f576040517fe5c7a49100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03841660009081526011602052604090205467ffffffffffffffff161580156119f757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b15611aef576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611a7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9f91906155be565b6001600160a01b038516600090815260116020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790555b60006040518061018001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020016012601081819054906101000a900467ffffffffffffffff16611b4f906156cd565b825467ffffffffffffffff9182166101009390930a8381029083021990911617909255825260208083018a90526001600160a01b03891660408085018290526000918252601190925290812080546060909401939092611baf91166156cd565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905567ffffffffffffffff16815260200183600001518152602001600015158152602001846001600160a01b03168152602001888060200190611c159190615389565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001611c5c60408a018a6153ee565b808060200260200160405190810160405280939291908181526020016000905b82821015611ca857611c996040830286013681900381019061566e565b81526020019060010190611c7c565b5050509183525050602001611cc360808a0160608b01614a2e565b6001600160a01b0316815260006020909101529050611d02817f0000000000000000000000000000000000000000000000000000000000000000613a1c565b61016082015260005b611d1860408901896153ee565b9050811015611e64576000611d3060408a018a6153ee565b83818110611d4057611d406156f4565b905060400201803603810190611d56919061566e565b9050611d65816000015161109a565b6001600160a01b0316639687544588611d7e8c80615389565b60208087015160408051928301815260008352517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b168152611dec959493927f000000000000000000000000000000000000000000000000000000000000000091600401615723565b6000604051808303816000875af1158015611e0b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611e51919081019061576e565b505080611e5d90615820565b9050611d0b565b507faffc45517195d6499808c643bd4a7b0ffeedf95bea5852840d7bfcf63f59e82181604051611e94919061589c565b60405180910390a161016001519695505050505050565b6060600080611eba6007613b26565b90508067ffffffffffffffff811115611ed557611ed5614acc565b604051908082528060200260200182016040528015611f1a57816020015b6040805180820190915260008082526020820152815260200190600190039081611ef35790505b50925060005b81811015611f8c57600080611f36600784613b31565b915091506040518060400160405280836001600160a01b031681526020018261ffff16815250868481518110611f6e57611f6e6156f4565b6020026020010181905250505080611f8590615820565b9050611f20565b505060125491926c0100000000000000000000000090920463ffffffff16919050565b6000546001600160a01b03163314801590611fd557506002546001600160a01b03163314155b1561200c576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109ea600382613b4f565b6000610e1e612ff5565b6060600061202f600a613d27565b67ffffffffffffffff81111561204757612047614acc565b604051908082528060200260200182016040528015612070578160200160208202803683370190505b50905060005b81518110156120cc5761208a600a82613d32565b5082828151811061209d5761209d6156f4565b60200260200101816001600160a01b03166001600160a01b031681525050806120c590615820565b9050612076565b50919050565b6000546001600160a01b031633148015906120f857506002546001600160a01b03163314155b1561212f576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109ea81613d41565b612140612b6d565b60128054821515790100000000000000000000000000000000000000000000000000027fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff9091161790556040517fccf4daf6ab6430389f26b970595dab82a5881ad454770907e415ede27c8df032906111b890831515815260200190565b6000546001600160a01b031633148015906121e457506002546001600160a01b03163314155b80156121f857506121f6600733613e28565b155b1561222f576040517f195db95800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff166000819003612283576040517f990e30bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546bffffffffffffffffffffffff16818110156122ce576040517f8d0f71d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006122d8612ff5565b1215612310576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600061231d6007613b26565b905060005b8181101561241257600080612338600784613b31565b9092509050600087612358836bffffffffffffffffffffffff8a166154e0565b612362919061550a565b905061236e81876159d9565b95506123b26001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016846bffffffffffffffffffffffff84166130b5565b6040516bffffffffffffffffffffffff821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a25050508061240b90615820565b9050612322565b5050601280547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790555050565b61245d612b6d565b6109ea81613e3d565b60005b8151811015612665576000828281518110612486576124866156f4565b6020908102919091018101516040805160c080820183528385015163ffffffff9081168352838501518116838701908152606080870151831685870190815260808089015167ffffffffffffffff90811693880193845260a0808b01518216928901928352968a0151151596880196875298516001600160a01b03166000908152600f909a5296909820945185549251985191519651945115157c0100000000000000000000000000000000000000000000000000000000027fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9589167401000000000000000000000000000000000000000002959095167fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff979098166c01000000000000000000000000027fffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffff9285166801000000000000000002929092167fffffffffffffffffffffffff000000000000000000000000ffffffffffffffff998516640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090941691909416179190911796909616179490941791909116919091179190911790555061265e81615820565b9050612469565b507f2386f61ab5cafc3fed44f9f614f721ab53479ef64067fd16c1a2491b63ddf1a8816040516111b891906159fe565b60408051602081019091526000815260008290036126eb5750604080516020810190915267ffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526110f3565b7f97a657c9000000000000000000000000000000000000000000000000000000006127168385615ab5565b7fffffffff00000000000000000000000000000000000000000000000000000000161461276f576040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61277c8260048186615afd565b8101906114709190615b27565b60065474010000000000000000000000000000000000000000900463ffffffff16808411156127ee576040517f869337890000000000000000000000000000000000000000000000000000000081526004810182905260248101859052604401610b59565b6006547801000000000000000000000000000000000000000000000000900467ffffffffffffffff16831115612850576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055474010000000000000000000000000000000000000000900461ffff168211156128a8576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60008083815b81811015612ac05760008787838181106128d0576128d06156f4565b9050604002018036038101906128e6919061566e565b80516001600160a01b031660009081526010602090815260409182902082518084019093525461ffff8116835263ffffffff620100009091048116918301919091528251929350909161293d91600a919061327016565b6129815781516040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610b59565b805160009061ffff1615612a8e5760008c6001600160a01b031684600001516001600160a01b031614612a3d5760065484516040517f4ab35b0b0000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152911690634ab35b0b90602401602060405180830381865afa158015612a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a369190615b69565b9050612a40565b508a5b82516020850151620186a09161ffff1690612a769077ffffffffffffffffffffffffffffffffffffffffffffffff851690613f18565b612a8091906154e0565b612a8a919061550a565b9150505b612a9881886154f7565b9650816020015186612aaa9190615b84565b955050505080612ab990615820565b90506128b4565b506000846020015163ffffffff16662386f26fc10000612ae091906154e0565b905080841015612af3579250612b2a9050565b6000856040015163ffffffff16662386f26fc10000612b1291906154e0565b905080851115612b26579350612b2a915050565b5050505b9550959350505050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff8316612b6383670de0b6b3a76400006154e0565b611470919061550a565b6000546001600160a01b03163314612be1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b59565b565b60005b8251811015612d44576000838281518110612c0357612c036156f4565b60200260200101516000015190506000848381518110612c2557612c256156f4565b6020026020010151602001519050612c4782600a61327090919063ffffffff16565b612c88576040517f73913ebd0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610b59565b6001600160a01b038116612c9d600a84613285565b6001600160a01b031614612cdd576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612ce8600a83613f47565b15612d3157604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b505080612d3d90615820565b9050612be6565b5060005b8151811015612f3e576000828281518110612d6557612d656156f4565b60200260200101516000015190506000838381518110612d8757612d876156f4565b602002602001015160200151905060006001600160a01b0316826001600160a01b03161480612dbd57506001600160a01b038116155b15612df4576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e569190615ba1565b6001600160a01b0316826001600160a01b031614612ea0576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612eac600a8383613f5c565b15612ef957604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a1612f2b565b6040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505080612f3790615820565b9050612d48565b505050565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152612fd182606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642612fb59190615bbe565b85608001516fffffffffffffffffffffffffffffffff16613f7a565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6012546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916bffffffffffffffffffffffff16907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613087573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ab9190615566565b610e1e9190615bd1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052612f3e908490613fa2565b60005b82518110156131c6576000838281518110613155576131556156f4565b6020026020010151905061317381600d6140a190919063ffffffff16565b156131b5576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506131bf81615820565b9050613138565b5060005b8151811015612f3e5760008282815181106131e7576131e76156f4565b6020026020010151905060006001600160a01b0316816001600160a01b0316036132115750613260565b61321c600d826140b6565b1561325e576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b61326981615820565b90506131ca565b6000611470836001600160a01b0384166140cb565b6000611470836001600160a01b0384166140d7565b60808101516001600160a01b03166132de576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600580546020808501516040808701516060808901516001600160a01b039889167fffffffffffffffffffff00000000000000000000000000000000000000000000909716969096177401000000000000000000000000000000000000000061ffff9586168102919091177fffffffff000000000000ffffffffffffffffffffffffffffffffffffffffffff1676010000000000000000000000000000000000000000000063ffffffff948516027fffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009590971694909402959095179095556080808801516006805460a0808c015160c0808e0151958d167fffffffffffffffff000000000000000000000000000000000000000000000000909416939093179a169096029890981777ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000067ffffffffffffffff93841602179055825160e0810184527f0000000000000000000000000000000000000000000000000000000000000000891681527f00000000000000000000000000000000000000000000000000000000000000008216958101959095527f00000000000000000000000000000000000000000000000000000000000000008116858401527f000000000000000000000000000000000000000000000000000000000000000016948401949094527f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff16938301939093527f00000000000000000000000000000000000000000000000000000000000000008516908201527f000000000000000000000000000000000000000000000000000000000000000090931691830191909152517f72c6aaba4dde02f77d291123a76185c418ba63f8c217a2d56b08aec84e9bbfb8916111b8918490615bf1565b80516040811115613604576040517fb5a10cfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6012546c01000000000000000000000000900463ffffffff1615801590613652575060125463ffffffff6c010000000000000000000000008204166bffffffffffffffffffffffff90911610155b1561365f5761365f6121be565b600061366b6007613b26565b90505b80156136ad57600061368c613684600184615bbe565b600790613b31565b50905061369a6007826140e3565b5050806136a690615ce6565b905061366e565b506000805b828110156137bb5760008482815181106136ce576136ce6156f4565b602002602001015160000151905060008583815181106136f0576136f06156f4565b60200260200101516020015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316148061374557506001600160a01b038216155b15613787576040517f4de938d10000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610b59565b61379760078361ffff84166140f8565b506137a661ffff821685615b84565b93505050806137b490615820565b90506136b2565b50601280547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd249061382d9083908690615d1b565b60405180910390a1505050565b606060006114708361410e565b6001600160a01b03811660009081526001830160205260408120541515611470565b81516000805b82811015613a0e576000846001600160a01b031663d02641a087848151811061389a5761389a6156f4565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0390911660048201526024016040805180830381865afa158015613901573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139259190615d3a565b51905077ffffffffffffffffffffffffffffffffffffffffffffffff81166000036139a65785828151811061395c5761395c6156f4565b6020908102919091010151516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610b59565b6139f08683815181106139bb576139bb6156f4565b6020026020010151602001518277ffffffffffffffffffffffffffffffffffffffffffffffff16613f1890919063ffffffff16565b6139fa90846154f7565b92505080613a0790615820565b905061386f565b506128a8600382600061416a565b60008060001b828460200151856080015186606001518760e0015188610100015180519060200120896101200151604051602001613a5a9190615d6d565b604051602081830303815290604052805190602001208a60a001518b60c001518c61014001518d60400151604051602001613b089c9b9a999897969594939291909b8c5260208c019a909a5267ffffffffffffffff98891660408c01529690971660608a01526001600160a01b0394851660808a015292841660a089015260c088019190915260e0870152610100860152911515610120850152166101408301526101608201526101800190565b60405160208183030381529060405280519060200120905092915050565b60006110f3826144b9565b6000808080613b4086866144c4565b909450925050505b9250929050565b8154600090613b7890700100000000000000000000000000000000900463ffffffff1642615bbe565b90508015613c1a5760018301548354613bc0916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416613f7a565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354613c40916fffffffffffffffffffffffffffffffff90811691166144ef565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199061382d9084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b60006110f382613b26565b6000808080613b408686613b31565b60005b8151811015613df8576000828281518110613d6157613d616156f4565b6020908102919091018101516040805180820182528284015161ffff90811682528284015163ffffffff90811683870190815294516001600160a01b0316600090815260109096529290942090518154935190921662010000027fffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000909316919093161717905550613df181615820565b9050613d44565b507f4230c60a9725eb5fb992cf6a215398b4e81b4606d4a1e6be8dfe0b60dc172ec1816040516111b89190615d80565b6000611470836001600160a01b038416614505565b336001600160a01b03821603613eaf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b59565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000670de0b6b3a7640000612b638377ffffffffffffffffffffffffffffffffffffffffffffffff86166154e0565b6000611470836001600160a01b038416614511565b6000613f72846001600160a01b0385168461451d565b949350505050565b6000613f9985613f8a84866154e0565b613f9490876154f7565b6144ef565b95945050505050565b6000613ff7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166145339092919063ffffffff16565b805190915015612f3e578080602001905181019061401591906155db565b612f3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b59565b6000611470836001600160a01b038416614542565b6000611470836001600160a01b03841661463c565b60006114708383614505565b6000611470838361468b565b6000611470836001600160a01b038416614715565b6000613f72846001600160a01b03851684614732565b60608160000180548060200260200160405190810160405280929190818152602001828054801561415e57602002820191906000526020600020905b81548152602001906001019080831161414a575b50505050509050919050565b825474010000000000000000000000000000000000000000900460ff161580614191575081155b1561419b57505050565b825460018401546fffffffffffffffffffffffffffffffff808316929116906000906141e190700100000000000000000000000000000000900463ffffffff1642615bbe565b905080156142a15781831115614223576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186015461425d9083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16613f7a565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b8482101561433e576001600160a01b0384166142f3576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610b59565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b0385166044820152606401610b59565b848310156144375760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906143829082615bbe565b61438c878a615bbe565b61439691906154f7565b6143a0919061550a565b90506001600160a01b0386166143ec576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610b59565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b0387166044820152606401610b59565b6144418584615bbe565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60006110f38261474f565b600080806144d28585614759565b600081815260029690960160205260409095205494959350505050565b60008183106144fe5781611470565b5090919050565b60006114708383614765565b60006114708383614715565b6000613f7284846001600160a01b038516614732565b6060613f72848460008561477d565b6000818152600183016020526040812054801561462b576000614566600183615bbe565b855490915060009061457a90600190615bbe565b90508181146145df57600086600001828154811061459a5761459a6156f4565b90600052602060002001549050808760000184815481106145bd576145bd6156f4565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806145f0576145f0615ddf565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506110f3565b60009150506110f3565b5092915050565b6000818152600183016020526040812054614683575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556110f3565b5060006110f3565b6000818152600283016020526040812054801515806146af57506146af8484614505565b611470576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b657900006044820152606401610b59565b600081815260028301602052604081208190556114708383614889565b60008281526002840160205260408120829055613f728484614895565b60006110f3825490565b600061147083836148a1565b60008181526001830160205260408120541515611470565b60608247101561480f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b59565b600080866001600160a01b0316858760405161482b9190615e0e565b60006040518083038185875af1925050503d8060008114614868576040519150601f19603f3d011682016040523d82523d6000602084013e61486d565b606091505b509150915061487e878383876148cb565b979650505050505050565b60006114708383614542565b6000611470838361463c565b60008260000182815481106148b8576148b86156f4565b9060005260206000200154905092915050565b6060831561495457825160000361494d576001600160a01b0385163b61494d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b59565b5081613f72565b613f7283838151156149695781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b599190614ab9565b60e081016110f382846001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b6001600160a01b03811681146109ea57600080fd5b600060208284031215614a4057600080fd5b813561147081614a19565b60005b83811015614a66578181015183820152602001614a4e565b50506000910152565b60008151808452614a87816020860160208601614a4b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006114706020830184614a6f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715614b1e57614b1e614acc565b60405290565b6040805190810167ffffffffffffffff81118282101715614b1e57614b1e614acc565b6040516060810167ffffffffffffffff81118282101715614b1e57614b1e614acc565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614bb157614bb1614acc565b604052919050565b600067ffffffffffffffff821115614bd357614bd3614acc565b5060051b60200190565b803563ffffffff81168114614bf157600080fd5b919050565b67ffffffffffffffff811681146109ea57600080fd5b80151581146109ea57600080fd5b60006020808385031215614c2d57600080fd5b823567ffffffffffffffff811115614c4457600080fd5b8301601f81018513614c5557600080fd5b8035614c68614c6382614bb9565b614b6a565b81815260e09182028301840191848201919088841115614c8757600080fd5b938501935b83851015614d325780858a031215614ca45760008081fd5b614cac614afb565b8535614cb781614a19565b8152614cc4868801614bdd565b878201526040614cd5818801614bdd565b908201526060614ce6878201614bdd565b90820152608086810135614cf981614bf6565b9082015260a086810135614d0c81614bf6565b9082015260c086810135614d1f81614c0c565b9082015283529384019391850191614c8c565b50979650505050505050565b600060a082840312156120cc57600080fd5b600060208284031215614d6257600080fd5b813567ffffffffffffffff811115614d7957600080fd5b613f7284828501614d3e565b600082601f830112614d9657600080fd5b81356020614da6614c6383614bb9565b82815260069290921b84018101918181019086841115614dc557600080fd5b8286015b84811015614e165760408189031215614de25760008081fd5b614dea614b24565b8135614df581614a19565b815281850135614e0481614a19565b81860152835291830191604001614dc9565b509695505050505050565b60008060408385031215614e3457600080fd5b823567ffffffffffffffff80821115614e4c57600080fd5b614e5886838701614d85565b93506020850135915080821115614e6e57600080fd5b50614e7b85828601614d85565b9150509250929050565b60008060408385031215614e9857600080fd5b8235614ea381614a19565b91506020830135614eb381614a19565b809150509250929050565b600082601f830112614ecf57600080fd5b81356020614edf614c6383614bb9565b82815260059290921b84018101918181019086841115614efe57600080fd5b8286015b84811015614e16578035614f1581614a19565b8352918301918301614f02565b60008060408385031215614f3557600080fd5b823567ffffffffffffffff80821115614f4d57600080fd5b614f5986838701614ebe565b93506020850135915080821115614f6f57600080fd5b50614e7b85828601614ebe565b803561ffff81168114614bf157600080fd5b600060e08284031215614fa057600080fd5b614fa8614afb565b8235614fb381614a19565b8152614fc160208401614f7c565b6020820152614fd260408401614bdd565b6040820152614fe360608401614f7c565b60608201526080830135614ff681614a19565b608082015261500760a08401614bdd565b60a082015260c083013561501a81614bf6565b60c08201529392505050565b60e081016110f382846001600160a01b03808251168352602082015161ffff80821660208601526040840151915063ffffffff80831660408701528160608601511660608701528360808601511660808701528060a08601511660a08701525050505067ffffffffffffffff60c08201511660c08301525050565b600080602083850312156150b457600080fd5b823567ffffffffffffffff808211156150cc57600080fd5b818501915085601f8301126150e057600080fd5b8135818111156150ef57600080fd5b8660208260061b850101111561510457600080fd5b60209290920196919550909350505050565b6020808252825182820181905260009190848201906040850190845b818110156151575783516001600160a01b031683529284019291840191600101615132565b50909695505050505050565b60008060006060848603121561517857600080fd5b833567ffffffffffffffff81111561518f57600080fd5b61519b86828701614d3e565b9350506020840135915060408401356151b381614a19565b809150509250925092565b600081518084526020808501945080840160005b8381101561520657815180516001600160a01b0316885283015161ffff1683880152604090960195908201906001016151d2565b509495945050505050565b60408152600061522460408301856151be565b90508260208301529392505050565b80356fffffffffffffffffffffffffffffffff81168114614bf157600080fd5b60006060828403121561526557600080fd5b61526d614b47565b823561527881614c0c565b815261528660208401615233565b602082015261529760408401615233565b60408201529392505050565b600060208083850312156152b657600080fd5b823567ffffffffffffffff8111156152cd57600080fd5b8301601f810185136152de57600080fd5b80356152ec614c6382614bb9565b8181526060918202830184019184820191908884111561530b57600080fd5b938501935b83851015614d325780858a0312156153285760008081fd5b615330614b47565b853561533b81614a19565b8152615348868801614f7c565b878201526040615359818801614bdd565b9082015283529384019391850191615310565b60006020828403121561537e57600080fd5b813561147081614c0c565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126153be57600080fd5b83018035915067ffffffffffffffff8211156153d957600080fd5b602001915036819003821315613b4857600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261542357600080fd5b83018035915067ffffffffffffffff82111561543e57600080fd5b6020019150600681901b3603821315613b4857600080fd5b805177ffffffffffffffffffffffffffffffffffffffffffffffff81168114614bf157600080fd5b6000806040838503121561549157600080fd5b61549a83615456565b91506154a860208401615456565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176110f3576110f36154b1565b808201808211156110f3576110f36154b1565b600082615540577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b67ffffffffffffffff818116838216019080821115614635576146356154b1565b60006020828403121561557857600080fd5b5051919050565b60006040828403121561559157600080fd5b615599614b24565b82356155a481614a19565b81526155b260208401614f7c565b60208201529392505050565b6000602082840312156155d057600080fd5b815161147081614bf6565b6000602082840312156155ed57600080fd5b815161147081614c0c565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000613f726020830184866155f8565b60006020828403121561566757600080fd5b5035919050565b60006040828403121561568057600080fd5b615688614b24565b823561569381614a19565b81526020928301359281019290925250919050565b6bffffffffffffffffffffffff818116838216019080821115614635576146356154b1565b600067ffffffffffffffff8083168181036156ea576156ea6154b1565b6001019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6001600160a01b038716815260a06020820152600061574660a0830187896155f8565b85604084015267ffffffffffffffff851660608401528281036080840152610dcc8185614a6f565b60006020828403121561578057600080fd5b815167ffffffffffffffff8082111561579857600080fd5b818401915084601f8301126157ac57600080fd5b8151818111156157be576157be614acc565b6157ef60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b6a565b915080825285602082850101111561580657600080fd5b615817816020840160208601614a4b565b50949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615851576158516154b1565b5060010190565b600081518084526020808501945080840160005b8381101561520657815180516001600160a01b03168852830151838801526040909601959082019060010161586c565b602081526158b760208201835167ffffffffffffffff169052565b600060208301516158d4604084018267ffffffffffffffff169052565b506040830151606083015260608301516158f960808401826001600160a01b03169052565b50608083015167ffffffffffffffff811660a08401525060a083015160c083015260c083015161592d60e084018215159052565b5060e083015161010061594a818501836001600160a01b03169052565b80850151915050610180610120818186015261596a6101a0860184614a6f565b92508086015190506101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086850301818701526159a88483615858565b9350808701519150506101606159c8818701836001600160a01b03169052565b959095015193019290925250919050565b6bffffffffffffffffffffffff828116828216039080821115614635576146356154b1565b602080825282518282018190526000919060409081850190868401855b82811015615aa857815180516001600160a01b031685528681015163ffffffff90811688870152868201518116878701526060808301519091169086015260808082015167ffffffffffffffff169086015260a080820151615a888288018267ffffffffffffffff169052565b505060c09081015115159085015260e09093019290850190600101615a1b565b5091979650505050505050565b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015615af55780818660040360031b1b83161692505b505092915050565b60008085851115615b0d57600080fd5b83861115615b1a57600080fd5b5050820193919092039150565b600060208284031215615b3957600080fd5b6040516020810181811067ffffffffffffffff82111715615b5c57615b5c614acc565b6040529135825250919050565b600060208284031215615b7b57600080fd5b61147082615456565b63ffffffff818116838216019080821115614635576146356154b1565b600060208284031215615bb357600080fd5b815161147081614a19565b818103818111156110f3576110f36154b1565b8181036000831280158383131683831282161715614635576146356154b1565b6101c08101615c6e82856001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b82516001600160a01b0390811660e0840152602084015161ffff908116610100850152604085015163ffffffff9081166101208601526060860151909116610140850152608085015190911661016084015260a08401511661018083015260c083015167ffffffffffffffff166101a0830152611470565b600081615cf557615cf56154b1565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b63ffffffff83168152604060208201526000613f7260408301846151be565b600060408284031215615d4c57600080fd5b615d54614b24565b615d5d83615456565b815260208301516155b281614bf6565b6020815260006114706020830184615858565b602080825282518282018190526000919060409081850190868401855b82811015615aa857815180516001600160a01b031685528681015161ffff168786015285015163ffffffff168585015260609093019290850190600101615d9d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251615e20818460208701614a4b565b919091019291505056fea164736f6c6343000813000a",
+}
+
+var EVM2EVMOnRampABI = EVM2EVMOnRampMetaData.ABI
+
+var EVM2EVMOnRampBin = EVM2EVMOnRampMetaData.Bin
+
+func DeployEVM2EVMOnRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMOnRampStaticConfig, dynamicConfig EVM2EVMOnRampDynamicConfig, tokensAndPools []InternalPoolUpdate, allowlist []common.Address, rateLimiterConfig RateLimiterConfig, feeTokenConfigs []EVM2EVMOnRampFeeTokenConfigArgs, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (common.Address, *types.Transaction, *EVM2EVMOnRamp, error) {
+ parsed, err := EVM2EVMOnRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMOnRampBin), backend, staticConfig, dynamicConfig, tokensAndPools, allowlist, rateLimiterConfig, feeTokenConfigs, tokenTransferFeeConfigArgs, nopsAndWeights)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMOnRamp{EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMOnRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMOnRampCaller
+ EVM2EVMOnRampTransactor
+ EVM2EVMOnRampFilterer
+}
+
+type EVM2EVMOnRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampSession struct {
+ Contract *EVM2EVMOnRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOnRampCallerSession struct {
+ Contract *EVM2EVMOnRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMOnRampTransactorSession struct {
+ Contract *EVM2EVMOnRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOnRampRaw struct {
+ Contract *EVM2EVMOnRamp
+}
+
+type EVM2EVMOnRampCallerRaw struct {
+ Contract *EVM2EVMOnRampCaller
+}
+
+type EVM2EVMOnRampTransactorRaw struct {
+ Contract *EVM2EVMOnRampTransactor
+}
+
+func NewEVM2EVMOnRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMOnRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMOnRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMOnRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRamp{address: address, abi: abi, EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMOnRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMOnRampCaller, error) {
+ contract, err := bindEVM2EVMOnRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMOnRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMOnRampTransactor, error) {
+ contract, err := bindEVM2EVMOnRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMOnRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMOnRampFilterer, error) {
+ contract, err := bindEVM2EVMOnRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMOnRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMOnRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOnRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "currentRateLimiterState")
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOnRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOnRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetAllowList() ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetAllowList(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetAllowList() ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetAllowList(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetAllowListEnabled() (bool, error) {
+ return _EVM2EVMOnRamp.Contract.GetAllowListEnabled(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetAllowListEnabled() (bool, error) {
+ return _EVM2EVMOnRamp.Contract.GetAllowListEnabled(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOnRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOnRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampDynamicConfig)).(*EVM2EVMOnRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetDynamicConfig() (EVM2EVMOnRampDynamicConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetDynamicConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetDynamicConfig() (EVM2EVMOnRampDynamicConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetDynamicConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetFee(opts *bind.CallOpts, message ClientEVM2AnyMessage) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getFee", message)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetFee(message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetFee(&_EVM2EVMOnRamp.CallOpts, message)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetFee(message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetFee(&_EVM2EVMOnRamp.CallOpts, message)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getFeeTokenConfig", token)
+
+ if err != nil {
+ return *new(EVM2EVMOnRampFeeTokenConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampFeeTokenConfig)).(*EVM2EVMOnRampFeeTokenConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetFeeTokenConfig(token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetFeeTokenConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetFeeTokenConfig(token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetFeeTokenConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getNopFeesJuels")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetNopFeesJuels() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetNopFeesJuels(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetNopFeesJuels() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetNopFeesJuels(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetNops(opts *bind.CallOpts) (GetNops,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getNops")
+
+ outstruct := new(GetNops)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.NopsAndWeights = *abi.ConvertType(out[0], new([]EVM2EVMOnRampNopAndWeight)).(*[]EVM2EVMOnRampNopAndWeight)
+ outstruct.WeightsTotal = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetNops() (GetNops,
+
+ error) {
+ return _EVM2EVMOnRamp.Contract.GetNops(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetNops() (GetNops,
+
+ error) {
+ return _EVM2EVMOnRamp.Contract.GetNops(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getPoolBySourceToken", sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetPoolBySourceToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOnRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetPoolBySourceToken(sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOnRamp.CallOpts, sourceToken)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getSenderNonce", sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetSenderNonce(&_EVM2EVMOnRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetSenderNonce(&_EVM2EVMOnRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOnRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOnRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampStaticConfig)).(*EVM2EVMOnRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetStaticConfig() (EVM2EVMOnRampStaticConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetStaticConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetStaticConfig() (EVM2EVMOnRampStaticConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetStaticConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getSupportedTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetSupportedTokens() ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetSupportedTokens(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetSupportedTokens() ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetSupportedTokens(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getTokenLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getTokenTransferFeeConfig", token)
+
+ if err != nil {
+ return *new(EVM2EVMOnRampTokenTransferFeeConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampTokenTransferFeeConfig)).(*EVM2EVMOnRampTokenTransferFeeConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetTokenTransferFeeConfig(token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenTransferFeeConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetTokenTransferFeeConfig(token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenTransferFeeConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.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
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.LinkAvailableForPayment(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.LinkAvailableForPayment(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.Owner(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.Owner(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOnRamp.Contract.TypeAndVersion(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOnRamp.Contract.TypeAndVersion(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.AcceptOwnership(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.AcceptOwnership(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyAllowListUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyAllowListUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "applyPoolUpdates", removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ForwardFromRouter(opts *bind.TransactOpts, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "forwardFromRouter", message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ForwardFromRouter(message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ForwardFromRouter(&_EVM2EVMOnRamp.TransactOpts, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ForwardFromRouter(message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ForwardFromRouter(&_EVM2EVMOnRamp.TransactOpts, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) PayNops(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "payNops")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) PayNops() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.PayNops(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) PayNops() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.PayNops(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setAdmin", newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAdmin(&_EVM2EVMOnRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAdmin(&_EVM2EVMOnRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetAllowListEnabled(opts *bind.TransactOpts, enabled bool) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setAllowListEnabled", enabled)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetAllowListEnabled(enabled bool) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAllowListEnabled(&_EVM2EVMOnRamp.TransactOpts, enabled)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetAllowListEnabled(enabled bool) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAllowListEnabled(&_EVM2EVMOnRamp.TransactOpts, enabled)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setDynamicConfig", dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetDynamicConfig(dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetDynamicConfig(&_EVM2EVMOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetDynamicConfig(dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetDynamicConfig(&_EVM2EVMOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setFeeTokenConfig", feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetFeeTokenConfig(feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetFeeTokenConfig(&_EVM2EVMOnRamp.TransactOpts, feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetFeeTokenConfig(feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetFeeTokenConfig(&_EVM2EVMOnRamp.TransactOpts, feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetNops(opts *bind.TransactOpts, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setNops", nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetNops(nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetNops(&_EVM2EVMOnRamp.TransactOpts, nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetNops(nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetNops(&_EVM2EVMOnRamp.TransactOpts, nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setRateLimiterConfig", config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOnRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOnRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setTokenTransferFeeConfig", tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetTokenTransferFeeConfig(tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetTokenTransferFeeConfig(&_EVM2EVMOnRamp.TransactOpts, tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetTokenTransferFeeConfig(tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetTokenTransferFeeConfig(&_EVM2EVMOnRamp.TransactOpts, tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.TransferOwnership(&_EVM2EVMOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.TransferOwnership(&_EVM2EVMOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "withdrawNonLinkFees", feeToken, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) WithdrawNonLinkFees(feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.WithdrawNonLinkFees(&_EVM2EVMOnRamp.TransactOpts, feeToken, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) WithdrawNonLinkFees(feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.WithdrawNonLinkFees(&_EVM2EVMOnRamp.TransactOpts, feeToken, to)
+}
+
+type EVM2EVMOnRampAdminSetIterator struct {
+ Event *EVM2EVMOnRampAdminSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAdminSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAdminSet)
+ 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(EVM2EVMOnRampAdminSet)
+ 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 *EVM2EVMOnRampAdminSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAdminSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAdminSet struct {
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAdminSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAdminSetIterator{contract: _EVM2EVMOnRamp.contract, event: "AdminSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAdminSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAdminSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AdminSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAdminSet(log types.Log) (*EVM2EVMOnRampAdminSet, error) {
+ event := new(EVM2EVMOnRampAdminSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AdminSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampAllowListAddIterator struct {
+ Event *EVM2EVMOnRampAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAllowListAdd)
+ 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(EVM2EVMOnRampAllowListAdd)
+ 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 *EVM2EVMOnRampAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListAddIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAllowListAddIterator{contract: _EVM2EVMOnRamp.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAllowListAdd)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListAdd", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAllowListAdd(log types.Log) (*EVM2EVMOnRampAllowListAdd, error) {
+ event := new(EVM2EVMOnRampAllowListAdd)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampAllowListEnabledSetIterator struct {
+ Event *EVM2EVMOnRampAllowListEnabledSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAllowListEnabledSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAllowListEnabledSet)
+ 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(EVM2EVMOnRampAllowListEnabledSet)
+ 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 *EVM2EVMOnRampAllowListEnabledSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAllowListEnabledSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAllowListEnabledSet struct {
+ Enabled bool
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAllowListEnabledSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListEnabledSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AllowListEnabledSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAllowListEnabledSetIterator{contract: _EVM2EVMOnRamp.contract, event: "AllowListEnabledSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAllowListEnabledSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListEnabledSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AllowListEnabledSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAllowListEnabledSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListEnabledSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAllowListEnabledSet(log types.Log) (*EVM2EVMOnRampAllowListEnabledSet, error) {
+ event := new(EVM2EVMOnRampAllowListEnabledSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListEnabledSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampAllowListRemoveIterator struct {
+ Event *EVM2EVMOnRampAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAllowListRemove)
+ 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(EVM2EVMOnRampAllowListRemove)
+ 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 *EVM2EVMOnRampAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListRemoveIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAllowListRemoveIterator{contract: _EVM2EVMOnRamp.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAllowListRemove)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListRemove", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAllowListRemove(log types.Log) (*EVM2EVMOnRampAllowListRemove, error) {
+ event := new(EVM2EVMOnRampAllowListRemove)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampCCIPSendRequestedIterator struct {
+ Event *EVM2EVMOnRampCCIPSendRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampCCIPSendRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampCCIPSendRequested)
+ 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(EVM2EVMOnRampCCIPSendRequested)
+ 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 *EVM2EVMOnRampCCIPSendRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampCCIPSendRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampCCIPSendRequested struct {
+ Message InternalEVM2EVMMessage
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterCCIPSendRequested(opts *bind.FilterOpts) (*EVM2EVMOnRampCCIPSendRequestedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "CCIPSendRequested")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampCCIPSendRequestedIterator{contract: _EVM2EVMOnRamp.contract, event: "CCIPSendRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "CCIPSendRequested")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampCCIPSendRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "CCIPSendRequested", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseCCIPSendRequested(log types.Log) (*EVM2EVMOnRampCCIPSendRequested, error) {
+ event := new(EVM2EVMOnRampCCIPSendRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "CCIPSendRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampConfigSetIterator struct {
+ Event *EVM2EVMOnRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampConfigSet)
+ 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(EVM2EVMOnRampConfigSet)
+ 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 *EVM2EVMOnRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampConfigSet struct {
+ StaticConfig EVM2EVMOnRampStaticConfig
+ DynamicConfig EVM2EVMOnRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMOnRampConfigSet, error) {
+ event := new(EVM2EVMOnRampConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampFeeConfigSetIterator struct {
+ Event *EVM2EVMOnRampFeeConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampFeeConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampFeeConfigSet)
+ 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(EVM2EVMOnRampFeeConfigSet)
+ 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 *EVM2EVMOnRampFeeConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampFeeConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampFeeConfigSet struct {
+ FeeConfig []EVM2EVMOnRampFeeTokenConfigArgs
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampFeeConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "FeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampFeeConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "FeeConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampFeeConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "FeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "FeeConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseFeeConfigSet(log types.Log) (*EVM2EVMOnRampFeeConfigSet, error) {
+ event := new(EVM2EVMOnRampFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "FeeConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampNopPaidIterator struct {
+ Event *EVM2EVMOnRampNopPaid
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampNopPaidIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampNopPaid)
+ 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(EVM2EVMOnRampNopPaid)
+ 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 *EVM2EVMOnRampNopPaidIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampNopPaidIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampNopPaid struct {
+ Nop common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*EVM2EVMOnRampNopPaidIterator, error) {
+
+ var nopRule []interface{}
+ for _, nopItem := range nop {
+ nopRule = append(nopRule, nopItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "NopPaid", nopRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampNopPaidIterator{contract: _EVM2EVMOnRamp.contract, event: "NopPaid", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchNopPaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error) {
+
+ var nopRule []interface{}
+ for _, nopItem := range nop {
+ nopRule = append(nopRule, nopItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "NopPaid", nopRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampNopPaid)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopPaid", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseNopPaid(log types.Log) (*EVM2EVMOnRampNopPaid, error) {
+ event := new(EVM2EVMOnRampNopPaid)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopPaid", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampNopsSetIterator struct {
+ Event *EVM2EVMOnRampNopsSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampNopsSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampNopsSet)
+ 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(EVM2EVMOnRampNopsSet)
+ 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 *EVM2EVMOnRampNopsSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampNopsSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampNopsSet struct {
+ NopWeightsTotal *big.Int
+ NopsAndWeights []EVM2EVMOnRampNopAndWeight
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterNopsSet(opts *bind.FilterOpts) (*EVM2EVMOnRampNopsSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "NopsSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampNopsSetIterator{contract: _EVM2EVMOnRamp.contract, event: "NopsSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchNopsSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopsSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "NopsSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampNopsSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopsSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseNopsSet(log types.Log) (*EVM2EVMOnRampNopsSet, error) {
+ event := new(EVM2EVMOnRampNopsSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopsSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMOnRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampOwnershipTransferRequested)
+ 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(EVM2EVMOnRampOwnershipTransferRequested)
+ 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 *EVM2EVMOnRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampOwnershipTransferRequestedIterator{contract: _EVM2EVMOnRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOnRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMOnRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampOwnershipTransferred)
+ 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(EVM2EVMOnRampOwnershipTransferred)
+ 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 *EVM2EVMOnRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampOwnershipTransferredIterator{contract: _EVM2EVMOnRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampOwnershipTransferred)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMOnRampOwnershipTransferred, error) {
+ event := new(EVM2EVMOnRampOwnershipTransferred)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampPoolAddedIterator struct {
+ Event *EVM2EVMOnRampPoolAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampPoolAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampPoolAdded)
+ 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(EVM2EVMOnRampPoolAdded)
+ 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 *EVM2EVMOnRampPoolAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampPoolAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampPoolAdded struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolAddedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampPoolAddedIterator{contract: _EVM2EVMOnRamp.contract, event: "PoolAdded", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolAdded) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampPoolAdded)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolAdded", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParsePoolAdded(log types.Log) (*EVM2EVMOnRampPoolAdded, error) {
+ event := new(EVM2EVMOnRampPoolAdded)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampPoolRemovedIterator struct {
+ Event *EVM2EVMOnRampPoolRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampPoolRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampPoolRemoved)
+ 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(EVM2EVMOnRampPoolRemoved)
+ 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 *EVM2EVMOnRampPoolRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampPoolRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampPoolRemoved struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolRemovedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampPoolRemovedIterator{contract: _EVM2EVMOnRamp.contract, event: "PoolRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampPoolRemoved)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolRemoved", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParsePoolRemoved(log types.Log) (*EVM2EVMOnRampPoolRemoved, error) {
+ event := new(EVM2EVMOnRampPoolRemoved)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigSetIterator struct {
+ Event *EVM2EVMOnRampTokenTransferFeeConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ 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(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ 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 *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigSet struct {
+ TransferFeeConfig []EVM2EVMOnRampTokenTransferFeeConfigArgs
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "TokenTransferFeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTokenTransferFeeConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "TokenTransferFeeConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "TokenTransferFeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseTokenTransferFeeConfigSet(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigSet, error) {
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetNops struct {
+ NopsAndWeights []EVM2EVMOnRampNopAndWeight
+ WeightsTotal *big.Int
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMOnRamp.abi.Events["AdminSet"].ID:
+ return _EVM2EVMOnRamp.ParseAdminSet(log)
+ case _EVM2EVMOnRamp.abi.Events["AllowListAdd"].ID:
+ return _EVM2EVMOnRamp.ParseAllowListAdd(log)
+ case _EVM2EVMOnRamp.abi.Events["AllowListEnabledSet"].ID:
+ return _EVM2EVMOnRamp.ParseAllowListEnabledSet(log)
+ case _EVM2EVMOnRamp.abi.Events["AllowListRemove"].ID:
+ return _EVM2EVMOnRamp.ParseAllowListRemove(log)
+ case _EVM2EVMOnRamp.abi.Events["CCIPSendRequested"].ID:
+ return _EVM2EVMOnRamp.ParseCCIPSendRequested(log)
+ case _EVM2EVMOnRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["FeeConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseFeeConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["NopPaid"].ID:
+ return _EVM2EVMOnRamp.ParseNopPaid(log)
+ case _EVM2EVMOnRamp.abi.Events["NopsSet"].ID:
+ return _EVM2EVMOnRamp.ParseNopsSet(log)
+ case _EVM2EVMOnRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMOnRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMOnRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMOnRamp.ParseOwnershipTransferred(log)
+ case _EVM2EVMOnRamp.abi.Events["PoolAdded"].ID:
+ return _EVM2EVMOnRamp.ParsePoolAdded(log)
+ case _EVM2EVMOnRamp.abi.Events["PoolRemoved"].ID:
+ return _EVM2EVMOnRamp.ParsePoolRemoved(log)
+ case _EVM2EVMOnRamp.abi.Events["TokenTransferFeeConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseTokenTransferFeeConfigSet(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMOnRampAdminSet) Topic() common.Hash {
+ return common.HexToHash("0x8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c")
+}
+
+func (EVM2EVMOnRampAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (EVM2EVMOnRampAllowListEnabledSet) Topic() common.Hash {
+ return common.HexToHash("0xccf4daf6ab6430389f26b970595dab82a5881ad454770907e415ede27c8df032")
+}
+
+func (EVM2EVMOnRampAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (EVM2EVMOnRampCCIPSendRequested) Topic() common.Hash {
+ return common.HexToHash("0xaffc45517195d6499808c643bd4a7b0ffeedf95bea5852840d7bfcf63f59e821")
+}
+
+func (EVM2EVMOnRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x72c6aaba4dde02f77d291123a76185c418ba63f8c217a2d56b08aec84e9bbfb8")
+}
+
+func (EVM2EVMOnRampFeeConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x2386f61ab5cafc3fed44f9f614f721ab53479ef64067fd16c1a2491b63ddf1a8")
+}
+
+func (EVM2EVMOnRampNopPaid) Topic() common.Hash {
+ return common.HexToHash("0x55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f")
+}
+
+func (EVM2EVMOnRampNopsSet) Topic() common.Hash {
+ return common.HexToHash("0x8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd24")
+}
+
+func (EVM2EVMOnRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMOnRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (EVM2EVMOnRampPoolAdded) Topic() common.Hash {
+ return common.HexToHash("0x95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c")
+}
+
+func (EVM2EVMOnRampPoolRemoved) Topic() common.Hash {
+ return common.HexToHash("0x987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c")
+}
+
+func (EVM2EVMOnRampTokenTransferFeeConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x4230c60a9725eb5fb992cf6a215398b4e81b4606d4a1e6be8dfe0b60dc172ec1")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRamp) Address() common.Address {
+ return _EVM2EVMOnRamp.address
+}
+
+type EVM2EVMOnRampInterface interface {
+ CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOnRampDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetFee(opts *bind.CallOpts, message ClientEVM2AnyMessage) (*big.Int, error)
+
+ GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampFeeTokenConfig, error)
+
+ GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error)
+
+ GetNops(opts *bind.CallOpts) (GetNops,
+
+ error)
+
+ GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error)
+
+ GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOnRampStaticConfig, error)
+
+ GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error)
+
+ LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error)
+
+ ForwardFromRouter(opts *bind.TransactOpts, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error)
+
+ PayNops(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error)
+
+ SetAllowListEnabled(opts *bind.TransactOpts, enabled bool) (*types.Transaction, error)
+
+ SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error)
+
+ SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error)
+
+ SetNops(opts *bind.TransactOpts, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error)
+
+ SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error)
+
+ SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error)
+
+ FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAdminSetIterator, error)
+
+ WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAdminSet) (event.Subscription, error)
+
+ ParseAdminSet(log types.Log) (*EVM2EVMOnRampAdminSet, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*EVM2EVMOnRampAllowListAdd, error)
+
+ FilterAllowListEnabledSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListEnabledSetIterator, error)
+
+ WatchAllowListEnabledSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListEnabledSet) (event.Subscription, error)
+
+ ParseAllowListEnabledSet(log types.Log) (*EVM2EVMOnRampAllowListEnabledSet, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*EVM2EVMOnRampAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*EVM2EVMOnRampAllowListRemove, error)
+
+ FilterCCIPSendRequested(opts *bind.FilterOpts) (*EVM2EVMOnRampCCIPSendRequestedIterator, error)
+
+ WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error)
+
+ ParseCCIPSendRequested(log types.Log) (*EVM2EVMOnRampCCIPSendRequested, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMOnRampConfigSet, error)
+
+ FilterFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampFeeConfigSetIterator, error)
+
+ WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampFeeConfigSet) (event.Subscription, error)
+
+ ParseFeeConfigSet(log types.Log) (*EVM2EVMOnRampFeeConfigSet, error)
+
+ FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*EVM2EVMOnRampNopPaidIterator, error)
+
+ WatchNopPaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error)
+
+ ParseNopPaid(log types.Log) (*EVM2EVMOnRampNopPaid, error)
+
+ FilterNopsSet(opts *bind.FilterOpts) (*EVM2EVMOnRampNopsSetIterator, error)
+
+ WatchNopsSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopsSet) (event.Subscription, error)
+
+ ParseNopsSet(log types.Log) (*EVM2EVMOnRampNopsSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOnRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMOnRampOwnershipTransferred, error)
+
+ FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolAddedIterator, error)
+
+ WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolAdded) (event.Subscription, error)
+
+ ParsePoolAdded(log types.Log) (*EVM2EVMOnRampPoolAdded, error)
+
+ FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolRemovedIterator, error)
+
+ WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolRemoved) (event.Subscription, error)
+
+ ParsePoolRemoved(log types.Log) (*EVM2EVMOnRampPoolRemoved, error)
+
+ FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error)
+
+ WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error)
+
+ ParseTokenTransferFeeConfigSet(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigSet, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0/evm_2_evm_onramp_1_2_0.go b/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0/evm_2_evm_onramp_1_2_0.go
new file mode 100644
index 00000000000..8c652e140d3
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0/evm_2_evm_onramp_1_2_0.go
@@ -0,0 +1,2337 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package evm_2_evm_onramp_1_2_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type EVM2EVMOnRampDynamicConfig struct {
+ Router common.Address
+ MaxNumberOfTokensPerMsg uint16
+ DestGasOverhead uint32
+ DestGasPerPayloadByte uint16
+ DestDataAvailabilityOverheadGas uint32
+ DestGasPerDataAvailabilityByte uint16
+ DestDataAvailabilityMultiplierBps uint16
+ PriceRegistry common.Address
+ MaxDataBytes uint32
+ MaxPerMsgGasLimit uint32
+}
+
+type EVM2EVMOnRampFeeTokenConfig struct {
+ NetworkFeeUSDCents uint32
+ GasMultiplierWeiPerEth uint64
+ PremiumMultiplierWeiPerEth uint64
+ Enabled bool
+}
+
+type EVM2EVMOnRampFeeTokenConfigArgs struct {
+ Token common.Address
+ NetworkFeeUSDCents uint32
+ GasMultiplierWeiPerEth uint64
+ PremiumMultiplierWeiPerEth uint64
+ Enabled bool
+}
+
+type EVM2EVMOnRampNopAndWeight struct {
+ Nop common.Address
+ Weight uint16
+}
+
+type EVM2EVMOnRampStaticConfig struct {
+ LinkToken common.Address
+ ChainSelector uint64
+ DestChainSelector uint64
+ DefaultTxGasLimit uint64
+ MaxNopFeesJuels *big.Int
+ PrevOnRamp common.Address
+ ArmProxy common.Address
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfig struct {
+ MinFeeUSDCents uint32
+ MaxFeeUSDCents uint32
+ DeciBps uint16
+ DestGasOverhead uint32
+ DestBytesOverhead uint32
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigArgs struct {
+ Token common.Address
+ MinFeeUSDCents uint32
+ MaxFeeUSDCents uint32
+ DeciBps uint16
+ DestGasOverhead uint32
+ DestBytesOverhead uint32
+}
+
+type InternalEVM2EVMMessage struct {
+ SourceChainSelector uint64
+ Sender common.Address
+ Receiver common.Address
+ SequenceNumber uint64
+ GasLimit *big.Int
+ Strict bool
+ Nonce uint64
+ FeeToken common.Address
+ FeeTokenAmount *big.Int
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ SourceTokenData [][]byte
+ MessageId [32]byte
+}
+
+type InternalPoolUpdate struct {
+ Token common.Address
+ Pool common.Address
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+var EVM2EVMOnRampMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"tokensAndPools\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeTokenConfigs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotSendZeroTokens\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidChainSelector\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"}],\"name\":\"InvalidNopAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTokenPoolConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWithdrawParams\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LinkBalanceNotSettled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxFeeBalanceReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MessageGasLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeCalledByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoFeesToPay\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoNopsToPay\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"NotAFeeToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdmin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwnerOrAdminOrNop\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PoolAlreadyAdded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PoolDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PriceNotFoundForToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustSetOriginalSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SourceTokenDataTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenPoolMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TooManyNops\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"UnsupportedToken\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"strict\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[]\",\"name\":\"sourceTokenData\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"}],\"indexed\":false,\"internalType\":\"structInternal.EVM2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"CCIPSendRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeConfig\",\"type\":\"tuple[]\"}],\"name\":\"FeeConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"NopPaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"nopWeightsTotal\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"NopsSet\",\"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\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"transferFeeConfig\",\"type\":\"tuple[]\"}],\"name\":\"TokenTransferFeeConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"removes\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"internalType\":\"structInternal.PoolUpdate[]\",\"name\":\"adds\",\"type\":\"tuple[]\"}],\"name\":\"applyPoolUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"}],\"name\":\"forwardFromRouter\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDynamicConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getExpectedNextSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getFeeTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfig\",\"name\":\"feeTokenConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNopFeesJuels\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNops\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"},{\"internalType\":\"uint256\",\"name\":\"weightsTotal\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"contractIERC20\",\"name\":\"sourceToken\",\"type\":\"address\"}],\"name\":\"getPoolBySourceToken\",\"outputs\":[{\"internalType\":\"contractIPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getSenderNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint64\"},{\"internalType\":\"uint96\",\"name\":\"maxNopFeesJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"internalType\":\"structEVM2EVMOnRamp.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"getSupportedTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTokenLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenTransferFeeConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"payNops\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.DynamicConfig\",\"name\":\"dynamicConfig\",\"type\":\"tuple\"}],\"name\":\"setDynamicConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structEVM2EVMOnRamp.FeeTokenConfigArgs[]\",\"name\":\"feeTokenConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setFeeTokenConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"nop\",\"type\":\"address\"},{\"internalType\":\"uint16\",\"name\":\"weight\",\"type\":\"uint16\"}],\"internalType\":\"structEVM2EVMOnRamp.NopAndWeight[]\",\"name\":\"nopsAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setNops\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"}],\"internalType\":\"structEVM2EVMOnRamp.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setTokenTransferFeeConfig\",\"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\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawNonLinkFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101806040523480156200001257600080fd5b506040516200849a3803806200849a833981016040819052620000359162001e40565b8333806000816200008d5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c057620000c08162000323565b50506040805160a081018252602084810180516001600160801b039081168085524263ffffffff169385018490528751151585870181905292518216606086018190529790950151166080909301839052600380546001600160a01b031916909417600160801b9283021760ff60a01b1916600160a01b90910217909255029091176004555086516001600160a01b0316158062000169575060208701516001600160401b0316155b8062000180575060408701516001600160401b0316155b8062000197575060608701516001600160401b0316155b80620001ae575060c08701516001600160a01b0316155b15620001cd576040516306b7c75960e31b815260040160405180910390fd5b6020808801516040808a015181517f8acd72527118c8324937b1a42e02cd246697c3b633f1742f3cae11de233722b3948101949094526001600160401b039283169184019190915216606082015230608082015260a00160408051601f198184030181529181528151602092830120608090815289516001600160a01b0390811660e052928a01516001600160401b0390811661010052918a015182166101205260608a015190911660a0908152908901516001600160601b031660c0908152908901518216610140528801511661016052620002aa86620003ce565b620002b58362000645565b620002c0826200077f565b620002cb81620008e5565b6040805160008082526020820190925262000316916200030e565b6040805180820190915260008082526020820152815260200190600190039081620002e65790505b508662000b0f565b505050505050506200241a565b336001600160a01b038216036200037d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000084565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60e08101516001600160a01b0316620003fa576040516306b7c75960e31b815260040160405180910390fd5b80600560008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601a6101000a81548161ffff021916908361ffff160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160006101000a81548161ffff021916908361ffff16021790555060c08201518160010160026101000a81548161ffff021916908361ffff16021790555060e08201518160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555061012082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055509050507f2a57f7c2027cf032c78b77d4d8d2fbd20ad22e5d5e5b5fb23ac7d7820d44adc66040518060e0016040528060e0516001600160a01b03168152602001610100516001600160401b03168152602001610120516001600160401b0316815260200160a0516001600160401b0316815260200160c0516001600160601b03168152602001610140516001600160a01b03168152602001610160516001600160a01b0316815250826040516200063a92919062002015565b60405180910390a150565b60005b81518110156200074d57600082828151811062000669576200066962002095565b60209081029190910181015160408051608080820183528385015163ffffffff9081168352838501516001600160401b03908116848801908152606080880151831686880190815294880151151590860190815296516001600160a01b03166000908152600d90985294909620925183549451925195511515600160a01b0260ff60a01b199688166c010000000000000000000000000296909616600160601b600160a81b031993909716640100000000026001600160601b0319909516911617929092179190911692909217179055506200074581620020c1565b905062000648565b507f067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e816040516200063a9190620020dd565b60005b8151811015620008b3576000828281518110620007a357620007a362002095565b6020908102919091018101516040805160a080820183528385015163ffffffff908116835283850151811683870190815260608087015161ffff9081168688019081526080808a0151861693880193845295890151851695870195865297516001600160a01b03166000908152600e909952959097209351845491519651975193518316600160701b0263ffffffff60701b199484166a01000000000000000000000263ffffffff60501b199990971668010000000000000000029890981665ffffffffffff60401b19978416640100000000026001600160401b03199093169190931617179490941693909317919091179190911691909117905550620008ab81620020c1565b905062000782565b507f555c74101f7a15746d31c6731170310e667bcc607996b2fc0b981a7b26a416e9816040516200063a91906200216c565b805160408111156200090a57604051635ad0867d60e11b815260040160405180910390fd5b6010546c01000000000000000000000000900463ffffffff161580159062000954575060105463ffffffff6c010000000000000000000000008204166001600160601b0390911610155b1562000964576200096462000e12565b600062000972600762001012565b90505b8015620009be576000620009986200098f600184620021f3565b60079062001025565b509050620009a860078262001043565b505080620009b69062002209565b905062000975565b506000805b8281101562000aa6576000848281518110620009e357620009e362002095565b6020026020010151600001519050600085838151811062000a085762000a0862002095565b602002602001015160200151905060e0516001600160a01b0316826001600160a01b0316148062000a4057506001600160a01b038216155b1562000a6b57604051634de938d160e01b81526001600160a01b038316600482015260240162000084565b62000a7d60078361ffff841662001061565b5062000a8e61ffff82168562002223565b935050508062000a9e90620020c1565b9050620009c3565b506010805463ffffffff60601b19166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd249062000b02908390869062002243565b60405180910390a1505050565b60005b825181101562000c4b57600083828151811062000b335762000b3362002095565b6020026020010151600001519050600084838151811062000b585762000b5862002095565b6020908102919091018101510151905062000b75600a8362001081565b62000b9f576040516373913ebd60e01b81526001600160a01b038316600482015260240162000084565b6001600160a01b03811662000bb6600a8462001098565b6001600160a01b03161462000bde57604051630d98f73360e31b815260040160405180910390fd5b62000beb600a83620010af565b1562000c3557604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b50508062000c4390620020c1565b905062000b12565b5060005b815181101562000e0d57600082828151811062000c705762000c7062002095565b6020026020010151600001519050600083838151811062000c955762000c9562002095565b602002602001015160200151905060006001600160a01b0316826001600160a01b0316148062000ccc57506001600160a01b038116155b1562000cea5760405162d8548360e71b815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000d29573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d4f9190620022b0565b6001600160a01b0316826001600160a01b03161462000d8157604051630d98f73360e31b815260040160405180910390fd5b62000d8f600a8383620010c6565b1562000dde57604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a162000df7565b604051633caf458560e01b815260040160405180910390fd5b50508062000e0590620020c1565b905062000c4f565b505050565b6000546001600160a01b0316331480159062000e3957506002546001600160a01b03163314155b801562000e50575062000e4e600733620010de565b155b1562000e6f5760405163032bb72b60e31b815260040160405180910390fd5b6010546c01000000000000000000000000900463ffffffff16600081900362000eab5760405163990e30bf60e01b815260040160405180910390fd5b6010546001600160601b03168181101562000ed9576040516311a1ee3b60e31b815260040160405180910390fd5b600062000ee5620010f5565b121562000f0557604051631e9acf1760e31b815260040160405180910390fd5b80600062000f14600762001012565b905060005b8181101562000fec5760008062000f3260078462001025565b909250905060008762000f4f836001600160601b038a16620022d0565b62000f5b9190620022ea565b905062000f6981876200230d565b60e05190965062000f8e906001600160a01b0316846001600160601b03841662001183565b6040516001600160601b03821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a25050508062000fe490620020c1565b905062000f19565b5050601080546001600160601b0319166001600160601b03929092169190911790555050565b60006200101f82620011db565b92915050565b6000808080620010368686620011e8565b9097909650945050505050565b60006200105a836001600160a01b03841662001215565b9392505050565b600062001079846001600160a01b0385168462001234565b949350505050565b60006200105a836001600160a01b03841662001253565b60006200105a836001600160a01b03841662001261565b60006200105a836001600160a01b0384166200126f565b600062001079846001600160a01b038516846200127d565b60006200105a836001600160a01b03841662001295565b60105460e0516040516370a0823160e01b81523060048201526000926001600160601b0316916001600160a01b0316906370a0823190602401602060405180830381865afa1580156200114c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001172919062002330565b6200117e91906200234a565b905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663a9059cbb60e01b1790915262000e0d918591620012a316565b60006200101f8262001374565b60008080620011f885856200137f565b600081815260029690960160205260409095205494959350505050565b600081815260028301602052604081208190556200105a83836200138d565b600082815260028401602052604081208290556200107984846200139b565b60006200105a838362001295565b60006200105a8383620013a9565b60006200105a838362001215565b60006200107984846001600160a01b03851662001234565b60006200105a83836200141e565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656490820152600090620012f2906001600160a01b03851690849062001437565b80519091501562000e0d57808060200190518101906200131391906200236d565b62000e0d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000084565b60006200101f825490565b60006200105a838362001448565b60006200105a838362001475565b60006200105a838362001580565b600081815260028301602052604081205480151580620013d05750620013d0848462001295565b6200105a5760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b65790000604482015260640162000084565b600081815260018301602052604081205415156200105a565b6060620010798484600085620015d2565b600082600001828154811062001462576200146262002095565b9060005260206000200154905092915050565b600081815260018301602052604081205480156200156e5760006200149c600183620021f3565b8554909150600090620014b290600190620021f3565b90508181146200151e576000866000018281548110620014d657620014d662002095565b9060005260206000200154905080876000018481548110620014fc57620014fc62002095565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806200153257620015326200238b565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506200101f565b60009150506200101f565b5092915050565b6000818152600183016020526040812054620015c9575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200101f565b5060006200101f565b606082471015620016355760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000084565b600080866001600160a01b03168587604051620016539190620023c7565b60006040518083038185875af1925050503d806000811462001692576040519150601f19603f3d011682016040523d82523d6000602084013e62001697565b606091505b509092509050620016ab87838387620016b6565b979650505050505050565b606083156200172a57825160000362001722576001600160a01b0385163b620017225760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000084565b508162001079565b620010798383815115620017415781518083602001fd5b8060405162461bcd60e51b8152600401620000849190620023e5565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156200179857620017986200175d565b60405290565b60405161014081016001600160401b03811182821017156200179857620017986200175d565b604080519081016001600160401b03811182821017156200179857620017986200175d565b60405160a081016001600160401b03811182821017156200179857620017986200175d565b60405160c081016001600160401b03811182821017156200179857620017986200175d565b604051601f8201601f191681016001600160401b03811182821017156200185e576200185e6200175d565b604052919050565b6001600160a01b03811681146200187c57600080fd5b50565b80516200188c8162001866565b919050565b80516001600160401b03811681146200188c57600080fd5b600060e08284031215620018bc57600080fd5b620018c662001773565b90508151620018d58162001866565b8152620018e56020830162001891565b6020820152620018f86040830162001891565b60408201526200190b6060830162001891565b606082015260808201516001600160601b03811681146200192b57600080fd5b60808201526200193e60a083016200187f565b60a08201526200195160c083016200187f565b60c082015292915050565b805161ffff811681146200188c57600080fd5b805163ffffffff811681146200188c57600080fd5b600061014082840312156200199857600080fd5b620019a26200179e565b9050620019af826200187f565b8152620019bf602083016200195c565b6020820152620019d2604083016200196f565b6040820152620019e5606083016200195c565b6060820152620019f8608083016200196f565b608082015262001a0b60a083016200195c565b60a082015262001a1e60c083016200195c565b60c082015262001a3160e083016200187f565b60e082015261010062001a468184016200196f565b9082015261012062001a5a8382016200196f565b9082015292915050565b60006001600160401b0382111562001a805762001a806200175d565b5060051b60200190565b600082601f83011262001a9c57600080fd5b8151602062001ab562001aaf8362001a64565b62001833565b82815260069290921b8401810191818101908684111562001ad557600080fd5b8286015b8481101562001b2f576040818903121562001af45760008081fd5b62001afe620017c4565b815162001b0b8162001866565b81528185015162001b1c8162001866565b8186015283529183019160400162001ad9565b509695505050505050565b805180151581146200188c57600080fd5b80516001600160801b03811681146200188c57600080fd5b60006060828403121562001b7657600080fd5b604051606081016001600160401b038111828210171562001b9b5762001b9b6200175d565b60405290508062001bac8362001b3a565b815262001bbc6020840162001b4b565b602082015262001bcf6040840162001b4b565b60408201525092915050565b600082601f83011262001bed57600080fd5b8151602062001c0062001aaf8362001a64565b82815260a0928302850182019282820191908785111562001c2057600080fd5b8387015b8581101562001caf5781818a03121562001c3e5760008081fd5b62001c48620017e9565b815162001c558162001866565b815262001c648287016200196f565b86820152604062001c7781840162001891565b90820152606062001c8a83820162001891565b90820152608062001c9d83820162001b3a565b90820152845292840192810162001c24565b5090979650505050505050565b600082601f83011262001cce57600080fd5b8151602062001ce162001aaf8362001a64565b82815260c0928302850182019282820191908785111562001d0157600080fd5b8387015b8581101562001caf5781818a03121562001d1f5760008081fd5b62001d296200180e565b815162001d368162001866565b815262001d458287016200196f565b86820152604062001d588184016200196f565b90820152606062001d6b8382016200195c565b90820152608062001d7e8382016200196f565b9082015260a062001d918382016200196f565b90820152845292840192810162001d05565b600082601f83011262001db557600080fd5b8151602062001dc862001aaf8362001a64565b82815260069290921b8401810191818101908684111562001de857600080fd5b8286015b8481101562001b2f576040818903121562001e075760008081fd5b62001e11620017c4565b815162001e1e8162001866565b815262001e2d8286016200195c565b8186015283529183019160400162001dec565b6000806000806000806000610300888a03121562001e5d57600080fd5b62001e698989620018a9565b965062001e7a8960e08a0162001984565b6102208901519096506001600160401b038082111562001e9957600080fd5b62001ea78b838c0162001a8a565b965062001eb98b6102408c0162001b63565b95506102a08a015191508082111562001ed157600080fd5b62001edf8b838c0162001bdb565b94506102c08a015191508082111562001ef757600080fd5b62001f058b838c0162001cbc565b93506102e08a015191508082111562001f1d57600080fd5b5062001f2c8a828b0162001da3565b91505092959891949750929550565b80516001600160a01b03168252602081015162001f5e602084018261ffff169052565b50604081015162001f77604084018263ffffffff169052565b50606081015162001f8e606084018261ffff169052565b50608081015162001fa7608084018263ffffffff169052565b5060a081015162001fbe60a084018261ffff169052565b5060c081015162001fd560c084018261ffff169052565b5060e081015162001ff160e08401826001600160a01b03169052565b506101008181015163ffffffff908116918401919091526101209182015116910152565b82516001600160a01b0390811682526020808501516001600160401b0390811691840191909152604080860151821690840152606080860151909116908301526080808501516001600160601b03169083015260a08085015182169083015260c0808501519091169082015261022081016200105a60e083018462001f3b565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620020d657620020d6620020ab565b5060010190565b602080825282518282018190526000919060409081850190868401855b828110156200215f57815180516001600160a01b031685528681015163ffffffff1687860152858101516001600160401b03908116878701526060808301519091169086015260809081015115159085015260a09093019290850190600101620020fa565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b828110156200215f57815180516001600160a01b031685528681015163ffffffff908116888701528682015181168787015260608083015161ffff169087015260808083015182169087015260a091820151169085015260c0909301929085019060010162002189565b818103818111156200101f576200101f620020ab565b6000816200221b576200221b620020ab565b506000190190565b63ffffffff818116838216019080821115620015795762001579620020ab565b6000604080830163ffffffff8616845260208281860152818651808452606087019150828801935060005b81811015620022a257845180516001600160a01b0316845284015161ffff168484015293830193918501916001016200226e565b509098975050505050505050565b600060208284031215620022c357600080fd5b81516200105a8162001866565b80820281158282048414176200101f576200101f620020ab565b6000826200230857634e487b7160e01b600052601260045260246000fd5b500490565b6001600160601b03828116828216039080821115620015795762001579620020ab565b6000602082840312156200234357600080fd5b5051919050565b8181036000831280158383131683831282161715620015795762001579620020ab565b6000602082840312156200238057600080fd5b6200105a8262001b3a565b634e487b7160e01b600052603160045260246000fd5b60005b83811015620023be578181015183820152602001620023a4565b50506000910152565b60008251620023db818460208701620023a1565b9190910192915050565b602081526000825180602084015262002406816040850160208701620023a1565b601f01601f19169190910160400192915050565b60805160a05160c05160e05161010051610120516101405161016051615f726200252860003960008181610334015281816116530152613dfb015260008181610305015281816114060152818161146e01528181611c3501528181611c9d0152613dcc0152600081816102710152818161097f01528181611790015281816120350152613d3801526000818161024101528181611d680152613d0801526000818161021201528181610fb4015281816119e001528181611ae1015281816123a301528181613090015281816132c60152613cd90152600081816102d101528181611bad0152613d980152600081816102a1015281816125d30152613d680152600061215e0152615f726000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c806379ba5097116100f9578063d09dc33911610097578063eff7cc4811610071578063eff7cc481461092d578063f25561fd14610935578063f2fde38b14610948578063fbca3b741461095b57600080fd5b8063d09dc339146108ff578063df0aa9e914610907578063e687b40a1461091a57600080fd5b80638da5cb5b116100d35780638da5cb5b146107c05780639a113c36146107d1578063b06d41bc146108d6578063c92b2832146108ec57600080fd5b806379ba5097146107925780637ec757511461079a578063856c8247146107ad57600080fd5b8063546719cd11610166578063599f643111610140578063599f6431146105ec578063704b6c02146105fd5780637437ff9f1461061057806376f6ae761461077f57600080fd5b8063546719cd14610555578063549e946f146105b957806354b71468146105cc57600080fd5b806320487ded116101a257806320487ded146104d35780633a87ac53146104f45780634120fccd1461050957806348a98aa41461052a57600080fd5b806306285c69146101c95780631772047e1461037a578063181f5a771461048a575b600080fd5b6103646040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091526040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250905090565b6040516103719190614ac2565b60405180910390f35b61043c610388366004614b63565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506001600160a01b03166000908152600e6020908152604091829020825160a081018452905463ffffffff8082168352640100000000820481169383019390935261ffff68010000000000000000820416938201939093526a01000000000000000000008304821660608201526e01000000000000000000000000000090920416608082015290565b6040516103719190815163ffffffff908116825260208084015182169083015260408084015161ffff1690830152606080840151821690830152608092830151169181019190915260a00190565b6104c66040518060400160405280601381526020017f45564d3245564d4f6e52616d7020312e322e300000000000000000000000000081525081565b6040516103719190614bd0565b6104e66104e1366004614c11565b61097b565b604051908152602001610371565b610507610502366004614e19565b610dfb565b005b610511610e11565b60405167ffffffffffffffff9091168152602001610371565b61053d610538366004614e73565b610e45565b6040516001600160a01b039091168152602001610371565b61055d610ea5565b604051610371919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6105076105c7366004614eac565b610f55565b6010546040516bffffffffffffffffffffffff9091168152602001610371565b6002546001600160a01b031661053d565b61050761060b366004614b63565b61110a565b6107726040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101919091525060408051610140810182526005546001600160a01b03808216835261ffff7401000000000000000000000000000000000000000083048116602085015263ffffffff76010000000000000000000000000000000000000000000084048116958501959095527a0100000000000000000000000000000000000000000000000000008304811660608501527c0100000000000000000000000000000000000000000000000000000000928390048516608085015260065480821660a086015262010000810490911660c0850152640100000000810490911660e08401527801000000000000000000000000000000000000000000000000810484166101008401520490911661012082015290565b6040516103719190614fa5565b61050761078d366004614fb4565b6111d4565b61050761128c565b6105076107a8366004615058565b61136f565b6105116107bb366004614b63565b6113d8565b6000546001600160a01b031661053d565b61088c6107df366004614b63565b604080516080810182526000808252602082018190529181018290526060810191909152506001600160a01b03166000908152600d60209081526040918290208251608081018452905463ffffffff8116825267ffffffffffffffff64010000000082048116938301939093526c0100000000000000000000000081049092169281019290925260ff74010000000000000000000000000000000000000000909104161515606082015290565b60408051825163ffffffff16815260208084015167ffffffffffffffff90811691830191909152838301511691810191909152606091820151151591810191909152608001610371565b6108de6114d9565b6040516103719291906151bb565b6105076108fa36600461520b565b6115dd565b6104e6611645565b6104e6610915366004615279565b61164f565b6105076109283660046152e5565b6121d3565b6105076121e4565b6105076109433660046153ad565b61247b565b610507610956366004614b63565b6124e1565b61096e6109693660046154a0565b6124f2565b60405161037191906154bd565b60007f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168367ffffffffffffffff16146109fb576040517fd9a9cd6800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b6000610a12610a0d608085018561550a565b6125a4565b519050610a3c610a25602085018561550a565b905082610a35604087018761556f565b9050612698565b6000600d81610a516080870160608801614b63565b6001600160a01b0316815260208082019290925260409081016000208151608081018352905463ffffffff81168252640100000000810467ffffffffffffffff908116948301949094526c010000000000000000000000008104909316918101919091527401000000000000000000000000000000000000000090910460ff16151560608201819052909150610b2f57610af16080850160608601614b63565b6040517fa7499d200000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016109f2565b600654600090819064010000000090046001600160a01b031663ffdb4b37610b5d6080890160608a01614b63565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015267ffffffffffffffff8a1660248201526044016040805180830381865afa158015610bc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bec9190615603565b9092509050806000808080610c0460408c018c61556f565b90501115610c3e57610c32610c1f60808c0160608d01614b63565b87610c2d60408e018e61556f565b6127c1565b91945092509050610c5a565b8651610c579063ffffffff16662386f26fc10000615665565b92505b6040870151610c739067ffffffffffffffff1684615665565b60208881015160055492955060009267ffffffffffffffff9091169163ffffffff8616917a010000000000000000000000000000000000000000000000000000900461ffff1690610cc6908f018f61550a565b610cd1929150615665565b600554610cfe90760100000000000000000000000000000000000000000000900463ffffffff168d61567c565b610d08919061567c565b610d12919061567c565b610d1c9190615665565b610d36906dffffffffffffffffffffffffffff8716615665565b60065490915060009062010000900461ffff1615610daa576000607060ff16887bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16901c9050610da6818e8060200190610d8c919061550a565b90508f8060400190610d9e919061556f565b905087612acb565b9150505b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff881681610dd4848861567c565b610dde919061567c565b610de8919061568f565b9a50505050505050505050505b92915050565b610e03612b9b565b610e0d8282612c11565b5050565b601054600090610e4090700100000000000000000000000000000000900467ffffffffffffffff1660016156ca565b905090565b6000610e52600a83612f71565b610e93576040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024016109f2565b610e9e600a83612f86565b9392505050565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526040805160a0810182526003546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff161515938301939093526004548084166060840152049091166080820152610e4090612f9b565b6000546001600160a01b03163314801590610f7b57506002546001600160a01b03163314155b15610fb2576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480610ff957506001600160a01b038116155b15611030576040517f232cb97f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061103a61304d565b1215611072576040517f02075e0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610e0d9082906001600160a01b038516906370a0823190602401602060405180830381865afa1580156110d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f991906156eb565b6001600160a01b038516919061310d565b6000546001600160a01b0316331480159061113057506002546001600160a01b03163314155b15611167576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c906020015b60405180910390a150565b6000546001600160a01b031633148015906111fa57506002546001600160a01b03163314155b15611231576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e0d8282808060200260200160405190810160405280939291908181526020016000905b828210156112825761127360408302860136819003810190615704565b81526020019060010190611256565b505050505061318d565b6001546001600160a01b03163314611300576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016109f2565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000546001600160a01b0316331480159061139557506002546001600160a01b03163314155b156113cc576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113d581613400565b50565b6001600160a01b0381166000908152600f602052604081205467ffffffffffffffff168015801561143157507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b15610df5576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa1580156114b5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9e9190615743565b60606000806114e860076135c6565b90508067ffffffffffffffff81111561150357611503614c61565b60405190808252806020026020018201604052801561154857816020015b60408051808201909152600080825260208201528152602001906001900390816115215790505b50925060005b818110156115ba576000806115646007846135d1565b915091506040518060400160405280836001600160a01b031681526020018261ffff1681525086848151811061159c5761159c615760565b60200260200101819052505050806115b39061578f565b905061154e565b505060105491926c0100000000000000000000000090920463ffffffff16919050565b6000546001600160a01b0316331480159061160357506002546001600160a01b03163314155b1561163a576040517ff6cd562000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113d56003826135ef565b6000610e4061304d565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d391906157c7565b1561170a576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03821661174a576040517fa4ec747900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546001600160a01b0316331461178e576040517f1c0a352900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168567ffffffffffffffff1614611807576040517fd9a9cd6800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff861660048201526024016109f2565b611811848061550a565b905060201461185857611824848061550a565b6040517f370d875f0000000000000000000000000000000000000000000000000000000081526004016109f292919061580f565b6000611864858061550a565b8101906118719190615823565b90506001600160a01b038111806118885750600a81105b1561189757611824858061550a565b60006118a9610a0d608088018861550a565b51905060006118bb604088018861556f565b91506118d890506118cf602089018961550a565b90508383612698565b80156119d65760005b81811015611959576118f6604089018961556f565b8281811061190657611906615760565b90506040020160200135600003611949576040517f5cf0444900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119528161578f565b90506118e1565b506119d661196a604089018961556f565b808060200260200160405190810160405280939291908181526020016000905b828210156119b6576119a76040830286013681900381019061583c565b8152602001906001019061198a565b505060065464010000000090046001600160a01b031692506137c7915050565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611a106080890160608a01614b63565b6001600160a01b031603611a745760108054879190600090611a419084906bffffffffffffffffffffffff16615876565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550611b9b565b60065464010000000090046001600160a01b03166241e5be611a9c60808a0160608b01614b63565b60405160e083901b7fffffffff000000000000000000000000000000000000000000000000000000001681526001600160a01b039182166004820152602481018a90527f00000000000000000000000000000000000000000000000000000000000000009091166044820152606401602060405180830381865afa158015611b28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b4c91906156eb565b60108054600090611b6c9084906bffffffffffffffffffffffff16615876565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b6010546bffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691161115611c08576040517fe5c7a49100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0385166000908152600f602052604090205467ffffffffffffffff16158015611c6057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031615155b15611d58576040517f856c82470000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063856c824790602401602060405180830381865afa158015611ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d089190615743565b6001600160a01b0386166000908152600f6020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169190911790555b6000604051806101a001604052807f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168152602001876001600160a01b03168152602001856001600160a01b0316815260200160108081819054906101000a900467ffffffffffffffff16611dd59061589b565b825467ffffffffffffffff9182166101009390930a838102908302199091161790925582526020808301879052600060408085018290526001600160a01b038c168252600f90925290812080546060909401939092611e34911661589b565b825467ffffffffffffffff9182166101009390930a83810292021916179091558152602001611e6960808b0160608c01614b63565b6001600160a01b03168152602001888152602001898060200190611e8d919061550a565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001611ed460408b018b61556f565b808060200260200160405190810160405280939291908181526020016000905b82821015611f2057611f116040830286013681900381019061583c565b81526020019060010190611ef4565b505050505081526020018367ffffffffffffffff811115611f4357611f43614c61565b604051908082528060200260200182016040528015611f7657816020015b6060815260200190600190039081611f615790505b508152600060209091018190529091505b82811015612157576000611f9e60408b018b61556f565b83818110611fae57611fae615760565b905060400201803603810190611fc4919061583c565b90506000611fd68c8360000151610e45565b6001600160a01b031663968754458a611fef8e8061550a565b60208088015160408051928301815260008352517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815261205d959493927f0000000000000000000000000000000000000000000000000000000000000000916004016158c2565b6000604051808303816000875af115801561207c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120a4919081019061591a565b82516001600160a01b03166000908152600e602052604090205481519192506e010000000000000000000000000000900463ffffffff1610156121215781516040517f36f536ca0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016109f2565b80846101600151848151811061213957612139615760565b60200260200101819052505050806121509061578f565b9050611f87565b50612182817f0000000000000000000000000000000000000000000000000000000000000000613982565b6101808201526040517fd0c3c799bf9e2639de44391e7f524d229b2b55f5b1ea94b2bf7da42f7243dddd906121b8908390615a47565b60405180910390a1610180015193505050505b949350505050565b6121db612b9b565b6113d581613add565b6000546001600160a01b0316331480159061220a57506002546001600160a01b03163314155b801561221e575061221c600733613e35565b155b15612255576040517f195db95800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6010546c01000000000000000000000000900463ffffffff1660008190036122a9576040517f990e30bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6010546bffffffffffffffffffffffff16818110156122f4576040517f8d0f71d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006122fe61304d565b1215612336576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600061234360076135c6565b905060005b818110156124385760008061235e6007846135d1565b909250905060008761237e836bffffffffffffffffffffffff8a16615665565b612388919061568f565b90506123948187615b7c565b95506123d86001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016846bffffffffffffffffffffffff841661310d565b6040516bffffffffffffffffffffffff821681526001600160a01b038416907f55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f9060200160405180910390a2505050806124319061578f565b9050612348565b5050601080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff929092169190911790555050565b6000546001600160a01b031633148015906124a157506002546001600160a01b03163314155b156124d8576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113d581613e4a565b6124e9612b9b565b6113d581613fd5565b60606000612500600a6140b0565b67ffffffffffffffff81111561251857612518614c61565b604051908082528060200260200182016040528015612541578160200160208202803683370190505b50905060005b815181101561259d5761255b600a826140bb565b5082828151811061256e5761256e615760565b60200260200101816001600160a01b03166001600160a01b031681525050806125969061578f565b9050612547565b5092915050565b60408051602081019091526000815260008290036125fa5750604080516020810190915267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152610df5565b7f97a657c9000000000000000000000000000000000000000000000000000000006126258385615ba1565b7fffffffff00000000000000000000000000000000000000000000000000000000161461267e576040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61268b8260048186615be9565b810190610e9e9190615c13565b6006547801000000000000000000000000000000000000000000000000900463ffffffff1680841115612701576040517f8693378900000000000000000000000000000000000000000000000000000000815260048101829052602481018590526044016109f2565b6006547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16831115612763576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055474010000000000000000000000000000000000000000900461ffff168211156127bb576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000808083815b81811015612abf5760008787838181106127e4576127e4615760565b9050604002018036038101906127fa919061583c565b80516001600160a01b03166000908152600e6020908152604091829020825160a081018452905463ffffffff8082168352640100000000820481169383019390935261ffff68010000000000000000820416938201939093526a01000000000000000000008304821660608201526e010000000000000000000000000000909204811660808301528251929350909161289791600a9190612f7116565b6128db5781516040517fbf16aab60000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016109f2565b604081015160009061ffff16156129ff5760008c6001600160a01b031684600001516001600160a01b0316146129a25760065484516040517f4ab35b0b0000000000000000000000000000000000000000000000000000000081526001600160a01b0391821660048201526401000000009092041690634ab35b0b90602401602060405180830381865afa158015612977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299b9190615c55565b90506129a5565b508a5b620186a0836040015161ffff166129e78660200151847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166140ca90919063ffffffff16565b6129f19190615665565b6129fb919061568f565b9150505b6060820151612a0e9088615c70565b9650816080015186612a209190615c70565b8251909650600090612a3f9063ffffffff16662386f26fc10000615665565b905080821015612a5e57612a53818a61567c565b985050505050612aaf565b6000836020015163ffffffff16662386f26fc10000612a7d9190615665565b905080831115612a9d57612a91818b61567c565b99505050505050612aaf565b612aa7838b61567c565b995050505050505b612ab88161578f565b90506127c8565b50509450945094915050565b60008063ffffffff8316612ae0608086615665565b612aec8761022061567c565b612af6919061567c565b612b00919061567c565b6005546006549192506000917c010000000000000000000000000000000000000000000000000000000090910463ffffffff1690612b429061ffff1684615665565b612b4c919061567c565b60065490915062010000900461ffff16612b766dffffffffffffffffffffffffffff891683615665565b612b809190615665565b612b9090655af3107a4000615665565b979650505050505050565b6000546001600160a01b03163314612c0f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109f2565b565b60005b8251811015612d72576000838281518110612c3157612c31615760565b60200260200101516000015190506000848381518110612c5357612c53615760565b6020026020010151602001519050612c7582600a612f7190919063ffffffff16565b612cb6576040517f73913ebd0000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024016109f2565b6001600160a01b038116612ccb600a84612f86565b6001600160a01b031614612d0b576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d16600a83614107565b15612d5f57604080516001600160a01b038085168252831660208201527f987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c910160405180910390a15b505080612d6b9061578f565b9050612c14565b5060005b8151811015612f6c576000828281518110612d9357612d93615760565b60200260200101516000015190506000838381518110612db557612db5615760565b602002602001015160200151905060006001600160a01b0316826001600160a01b03161480612deb57506001600160a01b038116155b15612e22576040517f6c2a418000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03166321df0da76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e849190615c8d565b6001600160a01b0316826001600160a01b031614612ece576040517f6cc7b99800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612eda600a838361411c565b15612f2757604080516001600160a01b038085168252831660208201527f95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c910160405180910390a1612f59565b6040517f3caf458500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505080612f659061578f565b9050612d76565b505050565b6000610e9e836001600160a01b038416614132565b6000610e9e836001600160a01b03841661413e565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261302982606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff164261300d9190615caa565b85608001516fffffffffffffffffffffffffffffffff1661414a565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6010546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000916bffffffffffffffffffffffff16907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156130df573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310391906156eb565b610e409190615cbd565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052612f6c908490614172565b805160408111156131ca576040517fb5a10cfa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6010546c01000000000000000000000000900463ffffffff1615801590613218575060105463ffffffff6c010000000000000000000000008204166bffffffffffffffffffffffff90911610155b15613225576132256121e4565b600061323160076135c6565b90505b801561327357600061325261324a600184615caa565b6007906135d1565b509050613260600782614271565b50508061326c90615cdd565b9050613234565b506000805b8281101561338157600084828151811061329457613294615760565b602002602001015160000151905060008583815181106132b6576132b6615760565b60200260200101516020015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316148061330b57506001600160a01b038216155b1561334d576040517f4de938d10000000000000000000000000000000000000000000000000000000081526001600160a01b03831660048201526024016109f2565b61335d60078361ffff8416614286565b5061336c61ffff821685615c70565b935050508061337a9061578f565b9050613278565b50601080547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790556040517f8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd24906133f39083908690615d12565b60405180910390a1505050565b60005b815181101561359657600082828151811061342057613420615760565b6020908102919091018101516040805160a080820183528385015163ffffffff908116835283850151811683870190815260608087015161ffff9081168688019081526080808a0151861693880193845295890151851695870195865297516001600160a01b03166000908152600e9099529590972093518454915196519751935183166e010000000000000000000000000000027fffffffffffffffffffffffffffff00000000ffffffffffffffffffffffffffff9484166a0100000000000000000000027fffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffff999097166801000000000000000002989098167fffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffff978416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909316919093161717949094169390931791909117919091169190911790555061358f8161578f565b9050613403565b507f555c74101f7a15746d31c6731170310e667bcc607996b2fc0b981a7b26a416e9816040516111c99190615d31565b6000610df58261429c565b60008080806135e086866142a7565b909450925050505b9250929050565b815460009061361890700100000000000000000000000000000000900463ffffffff1642615caa565b905080156136ba5760018301548354613660916fffffffffffffffffffffffffffffffff8082169281169185917001000000000000000000000000000000009091041661414a565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b602082015183546136e0916fffffffffffffffffffffffffffffffff90811691166142d2565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19906133f39084908151151581526020808301516fffffffffffffffffffffffffffffffff90811691830191909152604092830151169181019190915260600190565b81516000805b82811015613974576000846001600160a01b031663d02641a08784815181106137f8576137f8615760565b6020908102919091010151516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0390911660048201526024016040805180830381865afa15801561385f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138839190615db6565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116600003613908578582815181106138be576138be615760565b6020908102919091010151516040517f9a655f7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016109f2565b61395686838151811061391d5761391d615760565b602002602001015160200151827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166140ca90919063ffffffff16565b613960908461567c565b9250508061396d9061578f565b90506137cd565b506127bb60038260006142e8565b60008060001b8284602001518560400151866060015187608001518860a001518960c001518a60e001518b6101000151604051602001613a189897969594939291906001600160a01b039889168152968816602088015267ffffffffffffffff95861660408801526060870194909452911515608086015290921660a0840152921660c082015260e08101919091526101000190565b6040516020818303038152906040528051906020012085610120015180519060200120866101400151604051602001613a519190615de9565b60405160208183030381529060405280519060200120876101600151604051602001613a7d9190615dfc565b60408051601f198184030181528282528051602091820120908301979097528101949094526060840192909252608083015260a082015260c081019190915260e00160405160208183030381529060405280519060200120905092915050565b60e08101516001600160a01b0316613b21576040517f35be3ac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600560008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601a6101000a81548161ffff021916908361ffff160217905550608082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160006101000a81548161ffff021916908361ffff16021790555060c08201518160010160026101000a81548161ffff021916908361ffff16021790555060e08201518160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555061012082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055509050507f2a57f7c2027cf032c78b77d4d8d2fbd20ad22e5d5e5b5fb23ac7d7820d44adc66040518060e001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815250826040516111c9929190615e0f565b6000610e9e836001600160a01b038416614637565b60005b8151811015613fa5576000828281518110613e6a57613e6a615760565b60209081029190910181015160408051608080820183528385015163ffffffff90811683528385015167ffffffffffffffff908116848801908152606080880151831686880190815294880151151590860190815296516001600160a01b03166000908152600d9098529490962092518354945192519551151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9688166c0100000000000000000000000002969096167fffffffffffffffffffffff000000000000000000ffffffffffffffffffffffff93909716640100000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090951691161792909217919091169290921717905550613f9e8161578f565b9050613e4d565b507f067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e816040516111c99190615e99565b336001600160a01b03821603614047576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109f2565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000610df5826135c6565b60008080806135e086866135d1565b6000670de0b6b3a76400006140fd837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8616615665565b610e9e919061568f565b6000610e9e836001600160a01b038416614643565b60006121cb846001600160a01b0385168461464f565b6000610e9e8383614637565b6000610e9e8383614665565b60006141698561415a8486615665565b614164908761567c565b6142d2565b95945050505050565b60006141c7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166146ef9092919063ffffffff16565b805190915015612f6c57808060200190518101906141e591906157c7565b612f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016109f2565b6000610e9e836001600160a01b0384166146fe565b60006121cb846001600160a01b0385168461471b565b6000610df582614738565b600080806142b58585614742565b600081815260029690960160205260409095205494959350505050565b60008183106142e15781610e9e565b5090919050565b825474010000000000000000000000000000000000000000900460ff16158061430f575081155b1561431957505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061435f90700100000000000000000000000000000000900463ffffffff1642615caa565b9050801561441f57818311156143a1576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546143db9083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1661414a565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156144bc576001600160a01b038416614471576040517ff94ebcd100000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016109f2565b6040517f1a76572a00000000000000000000000000000000000000000000000000000000815260048101839052602481018690526001600160a01b03851660448201526064016109f2565b848310156145b55760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906145009082615caa565b61450a878a615caa565b614514919061567c565b61451e919061568f565b90506001600160a01b03861661456a576040517f15279c0800000000000000000000000000000000000000000000000000000000815260048101829052602481018690526044016109f2565b6040517fd0c8d23a00000000000000000000000000000000000000000000000000000000815260048101829052602481018690526001600160a01b03871660448201526064016109f2565b6145bf8584615caa565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6000610e9e838361474e565b6000610e9e83836146fe565b60006121cb84846001600160a01b03851661471b565b60008181526002830160205260408120548015158061468957506146898484614637565b610e9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b6579000060448201526064016109f2565b60606121cb8484600085614766565b60008181526002830160205260408120819055610e9e8383614867565b600082815260028401602052604081208290556121cb8484614873565b6000610df5825490565b6000610e9e838361487f565b60008181526001830160205260408120541515610e9e565b6060824710156147f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016109f2565b600080866001600160a01b031685876040516148149190615f1a565b60006040518083038185875af1925050503d8060008114614851576040519150601f19603f3d011682016040523d82523d6000602084013e614856565b606091505b5091509150612b90878383876148a9565b6000610e9e838361493c565b6000610e9e8383614a2f565b600082600001828154811061489657614896615760565b9060005260206000200154905092915050565b6060831561493257825160000361492b576001600160a01b0385163b61492b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109f2565b50816121cb565b6121cb8383614a7e565b60008181526001830160205260408120548015614a25576000614960600183615caa565b855490915060009061497490600190615caa565b90508181146149d957600086600001828154811061499457614994615760565b90600052602060002001549050808760000184815481106149b7576149b7615760565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806149ea576149ea615f36565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610df5565b6000915050610df5565b6000818152600183016020526040812054614a7657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610df5565b506000610df5565b815115614a8e5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109f29190614bd0565b60e08101610df582846001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b6001600160a01b03811681146113d557600080fd5b8035614b5e81614b3e565b919050565b600060208284031215614b7557600080fd5b8135610e9e81614b3e565b60005b83811015614b9b578181015183820152602001614b83565b50506000910152565b60008151808452614bbc816020860160208601614b80565b601f01601f19169290920160200192915050565b602081526000610e9e6020830184614ba4565b67ffffffffffffffff811681146113d557600080fd5b600060a08284031215614c0b57600080fd5b50919050565b60008060408385031215614c2457600080fd5b8235614c2f81614be3565b9150602083013567ffffffffffffffff811115614c4b57600080fd5b614c5785828601614bf9565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715614cb357614cb3614c61565b60405290565b60405160c0810167ffffffffffffffff81118282101715614cb357614cb3614c61565b604051610140810167ffffffffffffffff81118282101715614cb357614cb3614c61565b60405160a0810167ffffffffffffffff81118282101715614cb357614cb3614c61565b604051601f8201601f1916810167ffffffffffffffff81118282101715614d4c57614d4c614c61565b604052919050565b600067ffffffffffffffff821115614d6e57614d6e614c61565b5060051b60200190565b600082601f830112614d8957600080fd5b81356020614d9e614d9983614d54565b614d23565b82815260069290921b84018101918181019086841115614dbd57600080fd5b8286015b84811015614e0e5760408189031215614dda5760008081fd5b614de2614c90565b8135614ded81614b3e565b815281850135614dfc81614b3e565b81860152835291830191604001614dc1565b509695505050505050565b60008060408385031215614e2c57600080fd5b823567ffffffffffffffff80821115614e4457600080fd5b614e5086838701614d78565b93506020850135915080821115614e6657600080fd5b50614c5785828601614d78565b60008060408385031215614e8657600080fd5b8235614e9181614be3565b91506020830135614ea181614b3e565b809150509250929050565b60008060408385031215614ebf57600080fd5b8235614e9181614b3e565b80516001600160a01b031682526020810151614eec602084018261ffff169052565b506040810151614f04604084018263ffffffff169052565b506060810151614f1a606084018261ffff169052565b506080810151614f32608084018263ffffffff169052565b5060a0810151614f4860a084018261ffff169052565b5060c0810151614f5e60c084018261ffff169052565b5060e0810151614f7960e08401826001600160a01b03169052565b506101008181015163ffffffff81168483015250506101208181015163ffffffff8116848301526127bb565b6101408101610df58284614eca565b60008060208385031215614fc757600080fd5b823567ffffffffffffffff80821115614fdf57600080fd5b818501915085601f830112614ff357600080fd5b81358181111561500257600080fd5b8660208260061b850101111561501757600080fd5b60209290920196919550909350505050565b63ffffffff811681146113d557600080fd5b8035614b5e81615029565b803561ffff81168114614b5e57600080fd5b6000602080838503121561506b57600080fd5b823567ffffffffffffffff81111561508257600080fd5b8301601f8101851361509357600080fd5b80356150a1614d9982614d54565b81815260c091820283018401918482019190888411156150c057600080fd5b938501935b8385101561515c5780858a0312156150dd5760008081fd5b6150e5614cb9565b85356150f081614b3e565b8152858701356150ff81615029565b8188015260408681013561511281615029565b908201526060615123878201615046565b9082015260808681013561513681615029565b9082015260a08681013561514981615029565b90820152835293840193918501916150c5565b50979650505050505050565b600081518084526020808501945080840160005b838110156151b057815180516001600160a01b0316885283015161ffff16838801526040909601959082019060010161517c565b509495945050505050565b6040815260006151ce6040830185615168565b90508260208301529392505050565b80151581146113d557600080fd5b80356fffffffffffffffffffffffffffffffff81168114614b5e57600080fd5b60006060828403121561521d57600080fd5b6040516060810181811067ffffffffffffffff8211171561524057615240614c61565b604052823561524e816151dd565b815261525c602084016151eb565b602082015261526d604084016151eb565b60408201529392505050565b6000806000806080858703121561528f57600080fd5b843561529a81614be3565b9350602085013567ffffffffffffffff8111156152b657600080fd5b6152c287828801614bf9565b9350506040850135915060608501356152da81614b3e565b939692955090935050565b600061014082840312156152f857600080fd5b615300614cdc565b61530983614b53565b815261531760208401615046565b60208201526153286040840161503b565b604082015261533960608401615046565b606082015261534a6080840161503b565b608082015261535b60a08401615046565b60a082015261536c60c08401615046565b60c082015261537d60e08401614b53565b60e082015261010061539081850161503b565b908201526101206153a284820161503b565b908201529392505050565b600060208083850312156153c057600080fd5b823567ffffffffffffffff8111156153d757600080fd5b8301601f810185136153e857600080fd5b80356153f6614d9982614d54565b81815260a0918202830184019184820191908884111561541557600080fd5b938501935b8385101561515c5780858a0312156154325760008081fd5b61543a614d00565b853561544581614b3e565b81528587013561545481615029565b8188015260408681013561546781614be3565b9082015260608681013561547a81614be3565b9082015260808681013561548d816151dd565b908201528352938401939185019161541a565b6000602082840312156154b257600080fd5b8135610e9e81614be3565b6020808252825182820181905260009190848201906040850190845b818110156154fe5783516001600160a01b0316835292840192918401916001016154d9565b50909695505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261553f57600080fd5b83018035915067ffffffffffffffff82111561555a57600080fd5b6020019150368190038213156135e857600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126155a457600080fd5b83018035915067ffffffffffffffff8211156155bf57600080fd5b6020019150600681901b36038213156135e857600080fd5b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168114614b5e57600080fd5b6000806040838503121561561657600080fd5b61561f836155d7565b915061562d602084016155d7565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610df557610df5615636565b80820180821115610df557610df5615636565b6000826156c5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b67ffffffffffffffff81811683821601908082111561259d5761259d615636565b6000602082840312156156fd57600080fd5b5051919050565b60006040828403121561571657600080fd5b61571e614c90565b823561572981614b3e565b815261573760208401615046565b60208201529392505050565b60006020828403121561575557600080fd5b8151610e9e81614be3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036157c0576157c0615636565b5060010190565b6000602082840312156157d957600080fd5b8151610e9e816151dd565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6020815260006121cb6020830184866157e4565b60006020828403121561583557600080fd5b5035919050565b60006040828403121561584e57600080fd5b615856614c90565b823561586181614b3e565b81526020928301359281019290925250919050565b6bffffffffffffffffffffffff81811683821601908082111561259d5761259d615636565b600067ffffffffffffffff8083168181036158b8576158b8615636565b6001019392505050565b6001600160a01b038716815260a0602082015260006158e560a0830187896157e4565b85604084015267ffffffffffffffff85166060840152828103608084015261590d8185614ba4565b9998505050505050505050565b60006020828403121561592c57600080fd5b815167ffffffffffffffff8082111561594457600080fd5b818401915084601f83011261595857600080fd5b81518181111561596a5761596a614c61565b61597d6020601f19601f84011601614d23565b915080825285602082850101111561599457600080fd5b6159a5816020840160208601614b80565b50949350505050565b600081518084526020808501945080840160005b838110156151b057815180516001600160a01b0316885283015183880152604090960195908201906001016159c2565b600081518084526020808501808196508360051b8101915082860160005b85811015615a3a578284038952615a28848351614ba4565b98850198935090840190600101615a10565b5091979650505050505050565b60208152615a6260208201835167ffffffffffffffff169052565b60006020830151615a7e60408401826001600160a01b03169052565b5060408301516001600160a01b038116606084015250606083015167ffffffffffffffff8116608084015250608083015160a083015260a0830151615ac760c084018215159052565b5060c083015167ffffffffffffffff811660e08401525060e0830151610100615afa818501836001600160a01b03169052565b840151610120848101919091528401516101a061014080860182905291925090615b286101c0860184614ba4565b9250808601519050601f19610160818786030181880152615b4985846159ae565b945080880151925050610180818786030181880152615b6885846159f2565b970151959092019490945250929392505050565b6bffffffffffffffffffffffff82811682821603908082111561259d5761259d615636565b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015615be15780818660040360031b1b83161692505b505092915050565b60008085851115615bf957600080fd5b83861115615c0657600080fd5b5050820193919092039150565b600060208284031215615c2557600080fd5b6040516020810181811067ffffffffffffffff82111715615c4857615c48614c61565b6040529135825250919050565b600060208284031215615c6757600080fd5b610e9e826155d7565b63ffffffff81811683821601908082111561259d5761259d615636565b600060208284031215615c9f57600080fd5b8151610e9e81614b3e565b81810381811115610df557610df5615636565b818103600083128015838313168383128216171561259d5761259d615636565b600081615cec57615cec615636565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b63ffffffff831681526040602082015260006121cb6040830184615168565b602080825282518282018190526000919060409081850190868401855b82811015615a3a57815180516001600160a01b031685528681015163ffffffff908116888701528682015181168787015260608083015161ffff169087015260808083015182169087015260a091820151169085015260c09093019290850190600101615d4e565b600060408284031215615dc857600080fd5b615dd0614c90565b615dd9836155d7565b8152602083015161573781615029565b602081526000610e9e60208301846159ae565b602081526000610e9e60208301846159f2565b6102208101615e8c82856001600160a01b03808251168352602082015167ffffffffffffffff808216602086015280604085015116604086015280606085015116606086015250506bffffffffffffffffffffffff60808301511660808401528060a08301511660a08401528060c08301511660c0840152505050565b610e9e60e0830184614eca565b602080825282518282018190526000919060409081850190868401855b82811015615a3a57815180516001600160a01b031685528681015163ffffffff16878601528581015167ffffffffffffffff908116878701526060808301519091169086015260809081015115159085015260a09093019290850190600101615eb6565b60008251615f2c818460208701614b80565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a",
+}
+
+var EVM2EVMOnRampABI = EVM2EVMOnRampMetaData.ABI
+
+var EVM2EVMOnRampBin = EVM2EVMOnRampMetaData.Bin
+
+func DeployEVM2EVMOnRamp(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig EVM2EVMOnRampStaticConfig, dynamicConfig EVM2EVMOnRampDynamicConfig, tokensAndPools []InternalPoolUpdate, rateLimiterConfig RateLimiterConfig, feeTokenConfigs []EVM2EVMOnRampFeeTokenConfigArgs, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (common.Address, *types.Transaction, *EVM2EVMOnRamp, error) {
+ parsed, err := EVM2EVMOnRampMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EVM2EVMOnRampBin), backend, staticConfig, dynamicConfig, tokensAndPools, rateLimiterConfig, feeTokenConfigs, tokenTransferFeeConfigArgs, nopsAndWeights)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &EVM2EVMOnRamp{EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil
+}
+
+type EVM2EVMOnRamp struct {
+ address common.Address
+ abi abi.ABI
+ EVM2EVMOnRampCaller
+ EVM2EVMOnRampTransactor
+ EVM2EVMOnRampFilterer
+}
+
+type EVM2EVMOnRampCaller struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampTransactor struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampFilterer struct {
+ contract *bind.BoundContract
+}
+
+type EVM2EVMOnRampSession struct {
+ Contract *EVM2EVMOnRamp
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOnRampCallerSession struct {
+ Contract *EVM2EVMOnRampCaller
+ CallOpts bind.CallOpts
+}
+
+type EVM2EVMOnRampTransactorSession struct {
+ Contract *EVM2EVMOnRampTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type EVM2EVMOnRampRaw struct {
+ Contract *EVM2EVMOnRamp
+}
+
+type EVM2EVMOnRampCallerRaw struct {
+ Contract *EVM2EVMOnRampCaller
+}
+
+type EVM2EVMOnRampTransactorRaw struct {
+ Contract *EVM2EVMOnRampTransactor
+}
+
+func NewEVM2EVMOnRamp(address common.Address, backend bind.ContractBackend) (*EVM2EVMOnRamp, error) {
+ abi, err := abi.JSON(strings.NewReader(EVM2EVMOnRampABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindEVM2EVMOnRamp(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRamp{address: address, abi: abi, EVM2EVMOnRampCaller: EVM2EVMOnRampCaller{contract: contract}, EVM2EVMOnRampTransactor: EVM2EVMOnRampTransactor{contract: contract}, EVM2EVMOnRampFilterer: EVM2EVMOnRampFilterer{contract: contract}}, nil
+}
+
+func NewEVM2EVMOnRampCaller(address common.Address, caller bind.ContractCaller) (*EVM2EVMOnRampCaller, error) {
+ contract, err := bindEVM2EVMOnRamp(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampCaller{contract: contract}, nil
+}
+
+func NewEVM2EVMOnRampTransactor(address common.Address, transactor bind.ContractTransactor) (*EVM2EVMOnRampTransactor, error) {
+ contract, err := bindEVM2EVMOnRamp(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTransactor{contract: contract}, nil
+}
+
+func NewEVM2EVMOnRampFilterer(address common.Address, filterer bind.ContractFilterer) (*EVM2EVMOnRampFilterer, error) {
+ contract, err := bindEVM2EVMOnRamp(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampFilterer{contract: contract}, nil
+}
+
+func bindEVM2EVMOnRamp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := EVM2EVMOnRampMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampTransactor.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.EVM2EVMOnRampTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _EVM2EVMOnRamp.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.contract.Transfer(opts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "currentRateLimiterState")
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOnRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) CurrentRateLimiterState() (RateLimiterTokenBucket, error) {
+ return _EVM2EVMOnRamp.Contract.CurrentRateLimiterState(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOnRampDynamicConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getDynamicConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOnRampDynamicConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampDynamicConfig)).(*EVM2EVMOnRampDynamicConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetDynamicConfig() (EVM2EVMOnRampDynamicConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetDynamicConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetDynamicConfig() (EVM2EVMOnRampDynamicConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetDynamicConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getExpectedNextSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetExpectedNextSequenceNumber() (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetExpectedNextSequenceNumber(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetFee(opts *bind.CallOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getFee", destChainSelector, message)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetFee(destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetFee(&_EVM2EVMOnRamp.CallOpts, destChainSelector, message)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetFee(destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetFee(&_EVM2EVMOnRamp.CallOpts, destChainSelector, message)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getFeeTokenConfig", token)
+
+ if err != nil {
+ return *new(EVM2EVMOnRampFeeTokenConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampFeeTokenConfig)).(*EVM2EVMOnRampFeeTokenConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetFeeTokenConfig(token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetFeeTokenConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetFeeTokenConfig(token common.Address) (EVM2EVMOnRampFeeTokenConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetFeeTokenConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getNopFeesJuels")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetNopFeesJuels() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetNopFeesJuels(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetNopFeesJuels() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.GetNopFeesJuels(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetNops(opts *bind.CallOpts) (GetNops,
+
+ error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getNops")
+
+ outstruct := new(GetNops)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.NopsAndWeights = *abi.ConvertType(out[0], new([]EVM2EVMOnRampNopAndWeight)).(*[]EVM2EVMOnRampNopAndWeight)
+ outstruct.WeightsTotal = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetNops() (GetNops,
+
+ error) {
+ return _EVM2EVMOnRamp.Contract.GetNops(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetNops() (GetNops,
+
+ error) {
+ return _EVM2EVMOnRamp.Contract.GetNops(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetPoolBySourceToken(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getPoolBySourceToken", arg0, sourceToken)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetPoolBySourceToken(arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOnRamp.CallOpts, arg0, sourceToken)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetPoolBySourceToken(arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetPoolBySourceToken(&_EVM2EVMOnRamp.CallOpts, arg0, sourceToken)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getSenderNonce", sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetSenderNonce(&_EVM2EVMOnRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetSenderNonce(sender common.Address) (uint64, error) {
+ return _EVM2EVMOnRamp.Contract.GetSenderNonce(&_EVM2EVMOnRamp.CallOpts, sender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOnRampStaticConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(EVM2EVMOnRampStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampStaticConfig)).(*EVM2EVMOnRampStaticConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetStaticConfig() (EVM2EVMOnRampStaticConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetStaticConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetStaticConfig() (EVM2EVMOnRampStaticConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetStaticConfig(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetSupportedTokens(opts *bind.CallOpts, arg0 uint64) ([]common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getSupportedTokens", arg0)
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetSupportedTokens(arg0 uint64) ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetSupportedTokens(&_EVM2EVMOnRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetSupportedTokens(arg0 uint64) ([]common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetSupportedTokens(&_EVM2EVMOnRamp.CallOpts, arg0)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getTokenLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetTokenLimitAdmin() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenLimitAdmin(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "getTokenTransferFeeConfig", token)
+
+ if err != nil {
+ return *new(EVM2EVMOnRampTokenTransferFeeConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMOnRampTokenTransferFeeConfig)).(*EVM2EVMOnRampTokenTransferFeeConfig)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) GetTokenTransferFeeConfig(token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenTransferFeeConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) GetTokenTransferFeeConfig(token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ return _EVM2EVMOnRamp.Contract.GetTokenTransferFeeConfig(&_EVM2EVMOnRamp.CallOpts, token)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.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
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.LinkAvailableForPayment(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _EVM2EVMOnRamp.Contract.LinkAvailableForPayment(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) Owner() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.Owner(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) Owner() (common.Address, error) {
+ return _EVM2EVMOnRamp.Contract.Owner(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _EVM2EVMOnRamp.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOnRamp.Contract.TypeAndVersion(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampCallerSession) TypeAndVersion() (string, error) {
+ return _EVM2EVMOnRamp.Contract.TypeAndVersion(&_EVM2EVMOnRamp.CallOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.AcceptOwnership(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.AcceptOwnership(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "applyPoolUpdates", removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ApplyPoolUpdates(removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ApplyPoolUpdates(&_EVM2EVMOnRamp.TransactOpts, removes, adds)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) ForwardFromRouter(opts *bind.TransactOpts, destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "forwardFromRouter", destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) ForwardFromRouter(destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ForwardFromRouter(&_EVM2EVMOnRamp.TransactOpts, destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) ForwardFromRouter(destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.ForwardFromRouter(&_EVM2EVMOnRamp.TransactOpts, destChainSelector, message, feeTokenAmount, originalSender)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) PayNops(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "payNops")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) PayNops() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.PayNops(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) PayNops() (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.PayNops(&_EVM2EVMOnRamp.TransactOpts)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setAdmin", newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAdmin(&_EVM2EVMOnRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetAdmin(newAdmin common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetAdmin(&_EVM2EVMOnRamp.TransactOpts, newAdmin)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setDynamicConfig", dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetDynamicConfig(dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetDynamicConfig(&_EVM2EVMOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetDynamicConfig(dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetDynamicConfig(&_EVM2EVMOnRamp.TransactOpts, dynamicConfig)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setFeeTokenConfig", feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetFeeTokenConfig(feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetFeeTokenConfig(&_EVM2EVMOnRamp.TransactOpts, feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetFeeTokenConfig(feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetFeeTokenConfig(&_EVM2EVMOnRamp.TransactOpts, feeTokenConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetNops(opts *bind.TransactOpts, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setNops", nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetNops(nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetNops(&_EVM2EVMOnRamp.TransactOpts, nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetNops(nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetNops(&_EVM2EVMOnRamp.TransactOpts, nopsAndWeights)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setRateLimiterConfig", config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOnRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetRateLimiterConfig(config RateLimiterConfig) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetRateLimiterConfig(&_EVM2EVMOnRamp.TransactOpts, config)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "setTokenTransferFeeConfig", tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) SetTokenTransferFeeConfig(tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetTokenTransferFeeConfig(&_EVM2EVMOnRamp.TransactOpts, tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) SetTokenTransferFeeConfig(tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.SetTokenTransferFeeConfig(&_EVM2EVMOnRamp.TransactOpts, tokenTransferFeeConfigArgs)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.TransferOwnership(&_EVM2EVMOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.TransferOwnership(&_EVM2EVMOnRamp.TransactOpts, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactor) WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.contract.Transact(opts, "withdrawNonLinkFees", feeToken, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampSession) WithdrawNonLinkFees(feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.WithdrawNonLinkFees(&_EVM2EVMOnRamp.TransactOpts, feeToken, to)
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampTransactorSession) WithdrawNonLinkFees(feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ return _EVM2EVMOnRamp.Contract.WithdrawNonLinkFees(&_EVM2EVMOnRamp.TransactOpts, feeToken, to)
+}
+
+type EVM2EVMOnRampAdminSetIterator struct {
+ Event *EVM2EVMOnRampAdminSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampAdminSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampAdminSet)
+ 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(EVM2EVMOnRampAdminSet)
+ 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 *EVM2EVMOnRampAdminSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampAdminSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampAdminSet struct {
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAdminSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampAdminSetIterator{contract: _EVM2EVMOnRamp.contract, event: "AdminSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAdminSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "AdminSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampAdminSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AdminSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseAdminSet(log types.Log) (*EVM2EVMOnRampAdminSet, error) {
+ event := new(EVM2EVMOnRampAdminSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "AdminSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampCCIPSendRequestedIterator struct {
+ Event *EVM2EVMOnRampCCIPSendRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampCCIPSendRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampCCIPSendRequested)
+ 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(EVM2EVMOnRampCCIPSendRequested)
+ 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 *EVM2EVMOnRampCCIPSendRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampCCIPSendRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampCCIPSendRequested struct {
+ Message InternalEVM2EVMMessage
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterCCIPSendRequested(opts *bind.FilterOpts) (*EVM2EVMOnRampCCIPSendRequestedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "CCIPSendRequested")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampCCIPSendRequestedIterator{contract: _EVM2EVMOnRamp.contract, event: "CCIPSendRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "CCIPSendRequested")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampCCIPSendRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "CCIPSendRequested", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseCCIPSendRequested(log types.Log) (*EVM2EVMOnRampCCIPSendRequested, error) {
+ event := new(EVM2EVMOnRampCCIPSendRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "CCIPSendRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampConfigSetIterator struct {
+ Event *EVM2EVMOnRampConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampConfigSet)
+ 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(EVM2EVMOnRampConfigSet)
+ 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 *EVM2EVMOnRampConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampConfigSet struct {
+ StaticConfig EVM2EVMOnRampStaticConfig
+ DynamicConfig EVM2EVMOnRampDynamicConfig
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseConfigSet(log types.Log) (*EVM2EVMOnRampConfigSet, error) {
+ event := new(EVM2EVMOnRampConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampFeeConfigSetIterator struct {
+ Event *EVM2EVMOnRampFeeConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampFeeConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampFeeConfigSet)
+ 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(EVM2EVMOnRampFeeConfigSet)
+ 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 *EVM2EVMOnRampFeeConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampFeeConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampFeeConfigSet struct {
+ FeeConfig []EVM2EVMOnRampFeeTokenConfigArgs
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampFeeConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "FeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampFeeConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "FeeConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampFeeConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "FeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "FeeConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseFeeConfigSet(log types.Log) (*EVM2EVMOnRampFeeConfigSet, error) {
+ event := new(EVM2EVMOnRampFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "FeeConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampNopPaidIterator struct {
+ Event *EVM2EVMOnRampNopPaid
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampNopPaidIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampNopPaid)
+ 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(EVM2EVMOnRampNopPaid)
+ 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 *EVM2EVMOnRampNopPaidIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampNopPaidIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampNopPaid struct {
+ Nop common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*EVM2EVMOnRampNopPaidIterator, error) {
+
+ var nopRule []interface{}
+ for _, nopItem := range nop {
+ nopRule = append(nopRule, nopItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "NopPaid", nopRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampNopPaidIterator{contract: _EVM2EVMOnRamp.contract, event: "NopPaid", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchNopPaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error) {
+
+ var nopRule []interface{}
+ for _, nopItem := range nop {
+ nopRule = append(nopRule, nopItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "NopPaid", nopRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampNopPaid)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopPaid", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseNopPaid(log types.Log) (*EVM2EVMOnRampNopPaid, error) {
+ event := new(EVM2EVMOnRampNopPaid)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopPaid", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampNopsSetIterator struct {
+ Event *EVM2EVMOnRampNopsSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampNopsSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampNopsSet)
+ 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(EVM2EVMOnRampNopsSet)
+ 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 *EVM2EVMOnRampNopsSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampNopsSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampNopsSet struct {
+ NopWeightsTotal *big.Int
+ NopsAndWeights []EVM2EVMOnRampNopAndWeight
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterNopsSet(opts *bind.FilterOpts) (*EVM2EVMOnRampNopsSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "NopsSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampNopsSetIterator{contract: _EVM2EVMOnRamp.contract, event: "NopsSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchNopsSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopsSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "NopsSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampNopsSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopsSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseNopsSet(log types.Log) (*EVM2EVMOnRampNopsSet, error) {
+ event := new(EVM2EVMOnRampNopsSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "NopsSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampOwnershipTransferRequestedIterator struct {
+ Event *EVM2EVMOnRampOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampOwnershipTransferRequested)
+ 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(EVM2EVMOnRampOwnershipTransferRequested)
+ 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 *EVM2EVMOnRampOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampOwnershipTransferRequestedIterator{contract: _EVM2EVMOnRamp.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOnRampOwnershipTransferRequested, error) {
+ event := new(EVM2EVMOnRampOwnershipTransferRequested)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampOwnershipTransferredIterator struct {
+ Event *EVM2EVMOnRampOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampOwnershipTransferred)
+ 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(EVM2EVMOnRampOwnershipTransferred)
+ 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 *EVM2EVMOnRampOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampOwnershipTransferredIterator{contract: _EVM2EVMOnRamp.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampOwnershipTransferred)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferred", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseOwnershipTransferred(log types.Log) (*EVM2EVMOnRampOwnershipTransferred, error) {
+ event := new(EVM2EVMOnRampOwnershipTransferred)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampPoolAddedIterator struct {
+ Event *EVM2EVMOnRampPoolAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampPoolAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampPoolAdded)
+ 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(EVM2EVMOnRampPoolAdded)
+ 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 *EVM2EVMOnRampPoolAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampPoolAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampPoolAdded struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolAddedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampPoolAddedIterator{contract: _EVM2EVMOnRamp.contract, event: "PoolAdded", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolAdded) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "PoolAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampPoolAdded)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolAdded", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParsePoolAdded(log types.Log) (*EVM2EVMOnRampPoolAdded, error) {
+ event := new(EVM2EVMOnRampPoolAdded)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampPoolRemovedIterator struct {
+ Event *EVM2EVMOnRampPoolRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampPoolRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampPoolRemoved)
+ 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(EVM2EVMOnRampPoolRemoved)
+ 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 *EVM2EVMOnRampPoolRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampPoolRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampPoolRemoved struct {
+ Token common.Address
+ Pool common.Address
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolRemovedIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampPoolRemovedIterator{contract: _EVM2EVMOnRamp.contract, event: "PoolRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "PoolRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampPoolRemoved)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolRemoved", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParsePoolRemoved(log types.Log) (*EVM2EVMOnRampPoolRemoved, error) {
+ event := new(EVM2EVMOnRampPoolRemoved)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "PoolRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigSetIterator struct {
+ Event *EVM2EVMOnRampTokenTransferFeeConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ 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(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ 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 *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *EVM2EVMOnRampTokenTransferFeeConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type EVM2EVMOnRampTokenTransferFeeConfigSet struct {
+ TransferFeeConfig []EVM2EVMOnRampTokenTransferFeeConfigArgs
+ Raw types.Log
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.FilterLogs(opts, "TokenTransferFeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &EVM2EVMOnRampTokenTransferFeeConfigSetIterator{contract: _EVM2EVMOnRamp.contract, event: "TokenTransferFeeConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _EVM2EVMOnRamp.contract.WatchLogs(opts, "TokenTransferFeeConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigSet", 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 (_EVM2EVMOnRamp *EVM2EVMOnRampFilterer) ParseTokenTransferFeeConfigSet(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigSet, error) {
+ event := new(EVM2EVMOnRampTokenTransferFeeConfigSet)
+ if err := _EVM2EVMOnRamp.contract.UnpackLog(event, "TokenTransferFeeConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetNops struct {
+ NopsAndWeights []EVM2EVMOnRampNopAndWeight
+ WeightsTotal *big.Int
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRamp) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _EVM2EVMOnRamp.abi.Events["AdminSet"].ID:
+ return _EVM2EVMOnRamp.ParseAdminSet(log)
+ case _EVM2EVMOnRamp.abi.Events["CCIPSendRequested"].ID:
+ return _EVM2EVMOnRamp.ParseCCIPSendRequested(log)
+ case _EVM2EVMOnRamp.abi.Events["ConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["FeeConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseFeeConfigSet(log)
+ case _EVM2EVMOnRamp.abi.Events["NopPaid"].ID:
+ return _EVM2EVMOnRamp.ParseNopPaid(log)
+ case _EVM2EVMOnRamp.abi.Events["NopsSet"].ID:
+ return _EVM2EVMOnRamp.ParseNopsSet(log)
+ case _EVM2EVMOnRamp.abi.Events["OwnershipTransferRequested"].ID:
+ return _EVM2EVMOnRamp.ParseOwnershipTransferRequested(log)
+ case _EVM2EVMOnRamp.abi.Events["OwnershipTransferred"].ID:
+ return _EVM2EVMOnRamp.ParseOwnershipTransferred(log)
+ case _EVM2EVMOnRamp.abi.Events["PoolAdded"].ID:
+ return _EVM2EVMOnRamp.ParsePoolAdded(log)
+ case _EVM2EVMOnRamp.abi.Events["PoolRemoved"].ID:
+ return _EVM2EVMOnRamp.ParsePoolRemoved(log)
+ case _EVM2EVMOnRamp.abi.Events["TokenTransferFeeConfigSet"].ID:
+ return _EVM2EVMOnRamp.ParseTokenTransferFeeConfigSet(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (EVM2EVMOnRampAdminSet) Topic() common.Hash {
+ return common.HexToHash("0x8fe72c3e0020beb3234e76ae6676fa576fbfcae600af1c4fea44784cf0db329c")
+}
+
+func (EVM2EVMOnRampCCIPSendRequested) Topic() common.Hash {
+ return common.HexToHash("0xd0c3c799bf9e2639de44391e7f524d229b2b55f5b1ea94b2bf7da42f7243dddd")
+}
+
+func (EVM2EVMOnRampConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x2a57f7c2027cf032c78b77d4d8d2fbd20ad22e5d5e5b5fb23ac7d7820d44adc6")
+}
+
+func (EVM2EVMOnRampFeeConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x067924bf9277d905a9a4631a06d959bc032ace86b3caa835ae7e403d4f39010e")
+}
+
+func (EVM2EVMOnRampNopPaid) Topic() common.Hash {
+ return common.HexToHash("0x55fdec2aab60a41fa5abb106670eb1006f5aeaee1ba7afea2bc89b5b3ec7678f")
+}
+
+func (EVM2EVMOnRampNopsSet) Topic() common.Hash {
+ return common.HexToHash("0x8c337bff38141c507abd25c547606bdde78fe8c12e941ab613f3a565fea6cd24")
+}
+
+func (EVM2EVMOnRampOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (EVM2EVMOnRampOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (EVM2EVMOnRampPoolAdded) Topic() common.Hash {
+ return common.HexToHash("0x95f865c2808f8b2a85eea2611db7843150ee7835ef1403f9755918a97d76933c")
+}
+
+func (EVM2EVMOnRampPoolRemoved) Topic() common.Hash {
+ return common.HexToHash("0x987eb3c2f78454541205f72f34839b434c306c9eaf4922efd7c0c3060fdb2e4c")
+}
+
+func (EVM2EVMOnRampTokenTransferFeeConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x555c74101f7a15746d31c6731170310e667bcc607996b2fc0b981a7b26a416e9")
+}
+
+func (_EVM2EVMOnRamp *EVM2EVMOnRamp) Address() common.Address {
+ return _EVM2EVMOnRamp.address
+}
+
+type EVM2EVMOnRampInterface interface {
+ CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterTokenBucket, error)
+
+ GetDynamicConfig(opts *bind.CallOpts) (EVM2EVMOnRampDynamicConfig, error)
+
+ GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ GetFee(opts *bind.CallOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error)
+
+ GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampFeeTokenConfig, error)
+
+ GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error)
+
+ GetNops(opts *bind.CallOpts) (GetNops,
+
+ error)
+
+ GetPoolBySourceToken(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address) (common.Address, error)
+
+ GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (EVM2EVMOnRampStaticConfig, error)
+
+ GetSupportedTokens(opts *bind.CallOpts, arg0 uint64) ([]common.Address, error)
+
+ GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (EVM2EVMOnRampTokenTransferFeeConfig, error)
+
+ LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyPoolUpdates(opts *bind.TransactOpts, removes []InternalPoolUpdate, adds []InternalPoolUpdate) (*types.Transaction, error)
+
+ ForwardFromRouter(opts *bind.TransactOpts, destChainSelector uint64, message ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error)
+
+ PayNops(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error)
+
+ SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig EVM2EVMOnRampDynamicConfig) (*types.Transaction, error)
+
+ SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error)
+
+ SetNops(opts *bind.TransactOpts, nopsAndWeights []EVM2EVMOnRampNopAndWeight) (*types.Transaction, error)
+
+ SetRateLimiterConfig(opts *bind.TransactOpts, config RateLimiterConfig) (*types.Transaction, error)
+
+ SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []EVM2EVMOnRampTokenTransferFeeConfigArgs) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error)
+
+ FilterAdminSet(opts *bind.FilterOpts) (*EVM2EVMOnRampAdminSetIterator, error)
+
+ WatchAdminSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampAdminSet) (event.Subscription, error)
+
+ ParseAdminSet(log types.Log) (*EVM2EVMOnRampAdminSet, error)
+
+ FilterCCIPSendRequested(opts *bind.FilterOpts) (*EVM2EVMOnRampCCIPSendRequestedIterator, error)
+
+ WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error)
+
+ ParseCCIPSendRequested(log types.Log) (*EVM2EVMOnRampCCIPSendRequested, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*EVM2EVMOnRampConfigSet, error)
+
+ FilterFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampFeeConfigSetIterator, error)
+
+ WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampFeeConfigSet) (event.Subscription, error)
+
+ ParseFeeConfigSet(log types.Log) (*EVM2EVMOnRampFeeConfigSet, error)
+
+ FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*EVM2EVMOnRampNopPaidIterator, error)
+
+ WatchNopPaid(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error)
+
+ ParseNopPaid(log types.Log) (*EVM2EVMOnRampNopPaid, error)
+
+ FilterNopsSet(opts *bind.FilterOpts) (*EVM2EVMOnRampNopsSetIterator, error)
+
+ WatchNopsSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampNopsSet) (event.Subscription, error)
+
+ ParseNopsSet(log types.Log) (*EVM2EVMOnRampNopsSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*EVM2EVMOnRampOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*EVM2EVMOnRampOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*EVM2EVMOnRampOwnershipTransferred, error)
+
+ FilterPoolAdded(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolAddedIterator, error)
+
+ WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolAdded) (event.Subscription, error)
+
+ ParsePoolAdded(log types.Log) (*EVM2EVMOnRampPoolAdded, error)
+
+ FilterPoolRemoved(opts *bind.FilterOpts) (*EVM2EVMOnRampPoolRemovedIterator, error)
+
+ WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampPoolRemoved) (event.Subscription, error)
+
+ ParsePoolRemoved(log types.Log) (*EVM2EVMOnRampPoolRemoved, error)
+
+ FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error)
+
+ WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error)
+
+ ParseTokenTransferFeeConfigSet(log types.Log) (*EVM2EVMOnRampTokenTransferFeeConfigSet, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/lock_release_token_pool/lock_release_token_pool.go b/core/gethwrappers/ccip/generated/lock_release_token_pool/lock_release_token_pool.go
new file mode 100644
index 00000000000..fe2ac3f87e7
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/lock_release_token_pool/lock_release_token_pool.go
@@ -0,0 +1,3204 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package lock_release_token_pool
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type PoolLockOrBurnInV1 struct {
+ Receiver []byte
+ RemoteChainSelector uint64
+ OriginalSender common.Address
+ Amount *big.Int
+ LocalToken common.Address
+}
+
+type PoolLockOrBurnOutV1 struct {
+ DestTokenAddress []byte
+ DestPoolData []byte
+}
+
+type PoolReleaseOrMintInV1 struct {
+ OriginalSender []byte
+ RemoteChainSelector uint64
+ Receiver common.Address
+ Amount *big.Int
+ LocalToken common.Address
+ SourcePoolAddress []byte
+ SourcePoolData []byte
+ OffchainTokenData []byte
+}
+
+type PoolReleaseOrMintOutV1 struct {
+ DestinationAmount *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ RemotePoolAddress []byte
+ RemoteTokenAddress []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var LockReleaseTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"acceptLiquidity\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLiquidity\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRateLimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidSourcePoolAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LiquidityNotAccepted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remoteToken\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousPoolAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"RemotePoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"remoteTokenAddress\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"canAcceptLiquidity\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRateLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRebalancer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemotePool\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemoteToken\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRmnProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"isSupportedToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structPool.LockOrBurnInV1\",\"name\":\"lockOrBurnIn\",\"type\":\"tuple\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destPoolData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.LockOrBurnOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"provideLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainTokenData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.ReleaseOrMintInV1\",\"name\":\"releaseOrMintIn\",\"type\":\"tuple\"}],\"name\":\"releaseOrMint\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destinationAmount\",\"type\":\"uint256\"}],\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"rateLimitAdmin\",\"type\":\"address\"}],\"name\":\"setRateLimitAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"rebalancer\",\"type\":\"address\"}],\"name\":\"setRebalancer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"setRemotePool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101006040523480156200001257600080fd5b506040516200487838038062004878833981016040819052620000359162000565565b848484833380600081620000905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c357620000c3816200017e565b5050506001600160a01b0384161580620000e457506001600160a01b038116155b80620000f757506001600160a01b038216155b1562000116576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c052620001695760408051600081526020810190915262000169908462000229565b5050505090151560e05250620006d692505050565b336001600160a01b03821603620001d85760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000087565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c0516200024a576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002d55760008382815181106200026e576200026e62000688565b602090810291909101015190506200028860028262000386565b15620002cb576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506001016200024d565b5060005b815181101562000381576000828281518110620002fa57620002fa62000688565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000326575062000378565b62000333600282620003a6565b1562000376576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101620002d9565b505050565b60006200039d836001600160a01b038416620003bd565b90505b92915050565b60006200039d836001600160a01b038416620004c1565b60008181526001830160205260408120548015620004b6576000620003e46001836200069e565b8554909150600090620003fa906001906200069e565b9050818114620004665760008660000182815481106200041e576200041e62000688565b906000526020600020015490508087600001848154811062000444576200044462000688565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806200047a576200047a620006c0565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050620003a0565b6000915050620003a0565b60008181526001830160205260408120546200050a57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620003a0565b506000620003a0565b6001600160a01b03811681146200052957600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b80516200054f8162000513565b919050565b805180151581146200054f57600080fd5b600080600080600060a086880312156200057e57600080fd5b85516200058b8162000513565b602087810151919650906001600160401b0380821115620005ab57600080fd5b818901915089601f830112620005c057600080fd5b815181811115620005d557620005d56200052c565b8060051b604051601f19603f83011681018181108582111715620005fd57620005fd6200052c565b60405291825284820192508381018501918c8311156200061c57600080fd5b938501935b828510156200064557620006358562000542565b8452938501939285019262000621565b8099505050505050506200065c6040870162000542565b92506200066c6060870162000554565b91506200067c6080870162000542565b90509295509295909350565b634e487b7160e01b600052603260045260246000fd5b81810381811115620003a057634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05160e05161410662000772600039600081816104d1015261163801526000818161057e01528181611bd4015261267901526000818161055801528181611a050152611e8a015260008181610285015281816102da0152818161075c0152818161082e015281816108bf015281816116fa0152818161192501528181611daa0152818161260f015261286401526141066000f3fe608060405234801561001057600080fd5b50600436106101e55760003560e01c80638da5cb5b1161010f578063c4bffe2b116100a2578063dc0bd97111610071578063dc0bd97114610556578063e0351e131461057c578063eb521a4c146105a2578063f2fde38b146105b557600080fd5b8063c4bffe2b14610508578063c75eea9c1461051d578063cf7401f314610530578063db6327dc1461054357600080fd5b8063b0f479a1116100de578063b0f479a11461049e578063b7946580146104bc578063bb98546b146104cf578063c0d78655146104f557600080fd5b80638da5cb5b146103dc5780639a4575b9146103fa578063a7cd63b71461041a578063af58d59f1461042f57600080fd5b8063432a6ba31161018757806378a010b21161015657806378a010b21461039b57806379ba5097146103ae5780637d54534e146103b65780638926f54f146103c957600080fd5b8063432a6ba31461033957806354c8a4f3146103575780636cfd15531461036a5780636d3d1a581461037d57600080fd5b8063181f5a77116101c3578063181f5a771461024757806321df0da714610283578063240028e8146102ca578063390775371461031757600080fd5b806301ffc9a7146101ea5780630a2fd493146102125780630a861f2a14610232575b600080fd5b6101fd6101f836600461320e565b6105c8565b60405190151581526020015b60405180910390f35b61022561022036600461326d565b610624565b60405161020991906132f6565b610245610240366004613309565b6106d4565b005b6102256040518060400160405280601e81526020017f4c6f636b52656c65617365546f6b656e506f6f6c20312e352e302d646576000081525081565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610209565b6101fd6102d836600461334f565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b61032a61032536600461336c565b610885565b60405190518152602001610209565b60085473ffffffffffffffffffffffffffffffffffffffff166102a5565b6102456103653660046133f4565b61097b565b61024561037836600461334f565b6109f6565b60095473ffffffffffffffffffffffffffffffffffffffff166102a5565b6102456103a9366004613460565b610a45565b610245610bb4565b6102456103c436600461334f565b610cb1565b6101fd6103d736600461326d565b610d00565b60005473ffffffffffffffffffffffffffffffffffffffff166102a5565b61040d6104083660046134e3565b610d17565b604051610209919061351e565b610422610db1565b604051610209919061357e565b61044261043d36600461326d565b610dc2565b604051610209919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff166102a5565b6102256104ca36600461326d565b610e97565b7f00000000000000000000000000000000000000000000000000000000000000006101fd565b61024561050336600461334f565b610ec2565b610510610f9d565b60405161020991906135d8565b61044261052b36600461326d565b611055565b61024561053e366004613740565b611127565b610245610551366004613785565b6111b0565b7f00000000000000000000000000000000000000000000000000000000000000006102a5565b7f00000000000000000000000000000000000000000000000000000000000000006101fd565b6102456105b0366004613309565b611636565b6102456105c336600461334f565b611752565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fe1d4056600000000000000000000000000000000000000000000000000000000148061061e575061061e82611766565b92915050565b67ffffffffffffffff8116600090815260076020526040902060040180546060919061064f906137c7565b80601f016020809104026020016040519081016040528092919081815260200182805461067b906137c7565b80156106c85780601f1061069d576101008083540402835291602001916106c8565b820191906000526020600020905b8154815290600101906020018083116106ab57829003601f168201915b50505050509050919050565b60085473ffffffffffffffffffffffffffffffffffffffff16331461072c576040517f8e4a23d60000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156107b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107dc919061381a565b1015610814576040517fbb55fd2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61085573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016338361184a565b604051819033907fc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf984017171990600090a350565b6040805160208101909152600081526108a56108a0836138de565b61191e565b6108ea73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633606085013561184a565b6108fa606083016040840161334f565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52846060013560405161095c91815260200190565b60405180910390a3506040805160208101909152606090910135815290565b610983611b4f565b6109f084848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250611bd292505050565b50505050565b6109fe611b4f565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610a4d611b4f565b610a5683610d00565b610a98576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401610723565b67ffffffffffffffff831660009081526007602052604081206004018054610abf906137c7565b80601f0160208091040260200160405190810160405280929190818152602001828054610aeb906137c7565b8015610b385780601f10610b0d57610100808354040283529160200191610b38565b820191906000526020600020905b815481529060010190602001808311610b1b57829003601f168201915b5050505067ffffffffffffffff8616600090815260076020526040902091925050600401610b67838583613a23565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf828585604051610ba693929190613b3e565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610723565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610cb9611b4f565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600061061e600567ffffffffffffffff8416611d88565b6040805180820190915260608082526020820152610d3c610d3783613ba2565b611da3565b6040516060830135815233907f9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd600089060200160405180910390a26040518060400160405280610d968460200160208101906104ca919061326d565b81526040805160208181019092526000815291015292915050565b6060610dbd6002611f6d565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600390910154808416606083015291909104909116608082015261061e90611f7a565b67ffffffffffffffff8116600090815260076020526040902060050180546060919061064f906137c7565b610eca611b4f565b73ffffffffffffffffffffffffffffffffffffffff8116610f17576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684910160405180910390a15050565b60606000610fab6005611f6d565b90506000815167ffffffffffffffff811115610fc957610fc961361a565b604051908082528060200260200182016040528015610ff2578160200160208202803683370190505b50905060005b825181101561104e5782818151811061101357611013613c44565b602002602001015182828151811061102d5761102d613c44565b67ffffffffffffffff90921660209283029190910190910152600101610ff8565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600190910154808416606083015291909104909116608082015261061e90611f7a565b60095473ffffffffffffffffffffffffffffffffffffffff163314801590611167575060005473ffffffffffffffffffffffffffffffffffffffff163314155b156111a0576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610723565b6111ab83838361202c565b505050565b6111b8611b4f565b60005b818110156111ab5760008383838181106111d7576111d7613c44565b90506020028101906111e99190613c73565b6111f290613cb1565b90506112078160800151826020015115612116565b61121a8160a00151826020015115612116565b80602001511561151657805161123c9060059067ffffffffffffffff1661224f565b6112815780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610723565b60408101515115806112965750606081015151155b156112cd576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c179091169615150295909517909855908101519401519381169316909102919091176003820155915190919060048201906114ae9082613d65565b50606082015160058201906114c39082613d65565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c295506115099493929190613e7f565b60405180910390a161162d565b805161152e9060059067ffffffffffffffff1661225b565b6115735780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610723565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906115dc60048301826131c0565b6115ea6005830160006131c0565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b506001016111bb565b7f000000000000000000000000000000000000000000000000000000000000000061168d576040517fe93f8fa400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60085473ffffffffffffffffffffffffffffffffffffffff1633146116e0576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610723565b61172273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084612267565b604051819033907fc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb31208890600090a350565b61175a611b4f565b611763816122c5565b50565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf0000000000000000000000000000000000000000000000000000000014806117f957507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b8061061e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526111ab9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526123ba565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146119b35760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610723565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a859190613f18565b15611abc576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ac981602001516124c6565b6000611ad88260200151610624565b9050805160001480611afc575080805190602001208260a001518051906020012014155b15611b39578160a001516040517f24eb47e500000000000000000000000000000000000000000000000000000000815260040161072391906132f6565b611b4b826020015183606001516125ec565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611bd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610723565b565b7f0000000000000000000000000000000000000000000000000000000000000000611c29576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015611cbf576000838281518110611c4957611c49613c44565b60200260200101519050611c6781600261263390919063ffffffff16565b15611cb65760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50600101611c2c565b5060005b81518110156111ab576000828281518110611ce057611ce0613c44565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611d245750611d80565b611d2f600282612655565b15611d7e5760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101611cc3565b600081815260018301602052604081205415155b9392505050565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff908116911614611e385760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610723565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611ee6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0a9190613f18565b15611f41576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f4e8160400151612677565b611f5b81602001516126f6565b61176381602001518260600151612844565b60606000611d9c83612888565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261200882606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642611fec9190613f64565b85608001516fffffffffffffffffffffffffffffffff166128e3565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b61203583610d00565b612077576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401610723565b612082826000612116565b67ffffffffffffffff831660009081526007602052604090206120a5908361290d565b6120b0816000612116565b67ffffffffffffffff831660009081526007602052604090206120d6906002018261290d565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b83838360405161210993929190613f77565b60405180910390a1505050565b8151156121dd5781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff1610158061216c575060408201516fffffffffffffffffffffffffffffffff16155b156121a557816040517f8020d1240000000000000000000000000000000000000000000000000000000081526004016107239190613ffa565b8015611b4b576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff16151580612216575060208201516fffffffffffffffffffffffffffffffff1615155b15611b4b57816040517fd68af9cc0000000000000000000000000000000000000000000000000000000081526004016107239190613ffa565b6000611d9c8383612aaf565b6000611d9c8383612afe565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526109f09085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161189c565b3373ffffffffffffffffffffffffffffffffffffffff821603612344576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610723565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061241c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612bf19092919063ffffffff16565b8051909150156111ab578080602001905181019061243a9190613f18565b6111ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610723565b6124cf81610d00565b612511576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610723565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015612590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b49190613f18565b611763576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610723565b67ffffffffffffffff82166000908152600760205260409020611b4b90600201827f0000000000000000000000000000000000000000000000000000000000000000612c00565b6000611d9c8373ffffffffffffffffffffffffffffffffffffffff8416612afe565b6000611d9c8373ffffffffffffffffffffffffffffffffffffffff8416612aaf565b7f000000000000000000000000000000000000000000000000000000000000000015611763576126a8600282612f83565b611763576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610723565b6126ff81610d00565b612741576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610723565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa1580156127ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127de9190614036565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611763576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610723565b67ffffffffffffffff82166000908152600760205260409020611b4b90827f0000000000000000000000000000000000000000000000000000000000000000612c00565b6060816000018054806020026020016040519081016040528092919081815260200182805480156106c857602002820191906000526020600020905b8154815260200190600101908083116128c45750505050509050919050565b6000612902856128f38486614053565b6128fd908761406a565b612fb2565b90505b949350505050565b815460009061293690700100000000000000000000000000000000900463ffffffff1642613f64565b905080156129d8576001830154835461297e916fffffffffffffffffffffffffffffffff808216928116918591700100000000000000000000000000000000909104166128e3565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b602082015183546129fe916fffffffffffffffffffffffffffffffff9081169116612fb2565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990612109908490613ffa565b6000818152600183016020526040812054612af65750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561061e565b50600061061e565b60008181526001830160205260408120548015612be7576000612b22600183613f64565b8554909150600090612b3690600190613f64565b9050818114612b9b576000866000018281548110612b5657612b56613c44565b9060005260206000200154905080876000018481548110612b7957612b79613c44565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612bac57612bac61407d565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061061e565b600091505061061e565b60606129058484600085612fc8565b825474010000000000000000000000000000000000000000900460ff161580612c27575081155b15612c3157505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090612c7790700100000000000000000000000000000000900463ffffffff1642613f64565b90508015612d375781831115612cb9576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001860154612cf39083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166128e3565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b84821015612dee5773ffffffffffffffffffffffffffffffffffffffff8416612d96576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610723565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff85166044820152606401610723565b84831015612f015760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16906000908290612e329082613f64565b612e3c878a613f64565b612e46919061406a565b612e5091906140ac565b905073ffffffffffffffffffffffffffffffffffffffff8616612ea9576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610723565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff87166044820152606401610723565b612f0b8584613f64565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515611d9c565b6000818310612fc15781611d9c565b5090919050565b60608247101561305a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610723565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161308391906140e7565b60006040518083038185875af1925050503d80600081146130c0576040519150601f19603f3d011682016040523d82523d6000602084013e6130c5565b606091505b50915091506130d6878383876130e1565b979650505050505050565b606083156131775782516000036131705773ffffffffffffffffffffffffffffffffffffffff85163b613170576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610723565b5081612905565b612905838381511561318c5781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072391906132f6565b5080546131cc906137c7565b6000825580601f106131dc575050565b601f01602090049060005260206000209081019061176391905b8082111561320a57600081556001016131f6565b5090565b60006020828403121561322057600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611d9c57600080fd5b803567ffffffffffffffff8116811461326857600080fd5b919050565b60006020828403121561327f57600080fd5b611d9c82613250565b60005b838110156132a357818101518382015260200161328b565b50506000910152565b600081518084526132c4816020860160208601613288565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611d9c60208301846132ac565b60006020828403121561331b57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461176357600080fd5b803561326881613322565b60006020828403121561336157600080fd5b8135611d9c81613322565b60006020828403121561337e57600080fd5b813567ffffffffffffffff81111561339557600080fd5b82016101008185031215611d9c57600080fd5b60008083601f8401126133ba57600080fd5b50813567ffffffffffffffff8111156133d257600080fd5b6020830191508360208260051b85010111156133ed57600080fd5b9250929050565b6000806000806040858703121561340a57600080fd5b843567ffffffffffffffff8082111561342257600080fd5b61342e888389016133a8565b9096509450602087013591508082111561344757600080fd5b50613454878288016133a8565b95989497509550505050565b60008060006040848603121561347557600080fd5b61347e84613250565b9250602084013567ffffffffffffffff8082111561349b57600080fd5b818601915086601f8301126134af57600080fd5b8135818111156134be57600080fd5b8760208285010111156134d057600080fd5b6020830194508093505050509250925092565b6000602082840312156134f557600080fd5b813567ffffffffffffffff81111561350c57600080fd5b820160a08185031215611d9c57600080fd5b60208152600082516040602084015261353a60608401826132ac565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084830301604085015261357582826132ac565b95945050505050565b6020808252825182820181905260009190848201906040850190845b818110156135cc57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161359a565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156135cc57835167ffffffffffffffff16835292840192918401916001016135f4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff8111828210171561366d5761366d61361a565b60405290565b60405160c0810167ffffffffffffffff8111828210171561366d5761366d61361a565b801515811461176357600080fd5b803561326881613696565b80356fffffffffffffffffffffffffffffffff8116811461326857600080fd5b6000606082840312156136e157600080fd5b6040516060810181811067ffffffffffffffff821117156137045761370461361a565b604052905080823561371581613696565b8152613723602084016136af565b6020820152613734604084016136af565b60408201525092915050565b600080600060e0848603121561375557600080fd5b61375e84613250565b925061376d85602086016136cf565b915061377c85608086016136cf565b90509250925092565b6000806020838503121561379857600080fd5b823567ffffffffffffffff8111156137af57600080fd5b6137bb858286016133a8565b90969095509350505050565b600181811c908216806137db57607f821691505b602082108103613814577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b60006020828403121561382c57600080fd5b5051919050565b600082601f83011261384457600080fd5b813567ffffffffffffffff8082111561385f5761385f61361a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156138a5576138a561361a565b816040528381528660208588010111156138be57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600061010082360312156138f157600080fd5b6138f9613649565b823567ffffffffffffffff8082111561391157600080fd5b61391d36838701613833565b835261392b60208601613250565b602084015261393c60408601613344565b60408401526060850135606084015261395760808601613344565b608084015260a085013591508082111561397057600080fd5b61397c36838701613833565b60a084015260c085013591508082111561399557600080fd5b6139a136838701613833565b60c084015260e08501359150808211156139ba57600080fd5b506139c736828601613833565b60e08301525092915050565b601f8211156111ab576000816000526020600020601f850160051c810160208610156139fc5750805b601f850160051c820191505b81811015613a1b57828155600101613a08565b505050505050565b67ffffffffffffffff831115613a3b57613a3b61361a565b613a4f83613a4983546137c7565b836139d3565b6000601f841160018114613aa15760008515613a6b5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355613b37565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015613af05786850135825560209485019460019092019101613ad0565b5086821015613b2b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b604081526000613b5160408301866132ac565b82810360208401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116820101915050949350505050565b600060a08236031215613bb457600080fd5b60405160a0810167ffffffffffffffff8282108183111715613bd857613bd861361a565b816040528435915080821115613bed57600080fd5b50613bfa36828601613833565b825250613c0960208401613250565b60208201526040830135613c1c81613322565b6040820152606083810135908201526080830135613c3981613322565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec1833603018112613ca757600080fd5b9190910192915050565b60006101408236031215613cc457600080fd5b613ccc613673565b613cd583613250565b8152613ce3602084016136a4565b6020820152604083013567ffffffffffffffff80821115613d0357600080fd5b613d0f36838701613833565b60408401526060850135915080821115613d2857600080fd5b50613d3536828601613833565b606083015250613d4836608085016136cf565b6080820152613d5a3660e085016136cf565b60a082015292915050565b815167ffffffffffffffff811115613d7f57613d7f61361a565b613d9381613d8d84546137c7565b846139d3565b602080601f831160018114613de65760008415613db05750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613a1b565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015613e3357888601518255948401946001909101908401613e14565b5085821015613e6f57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff87168352806020840152613ea3818401876132ac565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff9081166060870152908701511660808501529150613ee19050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e0830152613575565b600060208284031215613f2a57600080fd5b8151611d9c81613696565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561061e5761061e613f35565b67ffffffffffffffff8416815260e08101613fc360208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c0830152612905565b6060810161061e82848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b60006020828403121561404857600080fd5b8151611d9c81613322565b808202811582820484141761061e5761061e613f35565b8082018082111561061e5761061e613f35565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000826140e2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008251613ca781846020870161328856fea164736f6c6343000818000a",
+}
+
+var LockReleaseTokenPoolABI = LockReleaseTokenPoolMetaData.ABI
+
+var LockReleaseTokenPoolBin = LockReleaseTokenPoolMetaData.Bin
+
+func DeployLockReleaseTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, rmnProxy common.Address, acceptLiquidity bool, router common.Address) (common.Address, *types.Transaction, *LockReleaseTokenPool, error) {
+ parsed, err := LockReleaseTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(LockReleaseTokenPoolBin), backend, token, allowlist, rmnProxy, acceptLiquidity, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &LockReleaseTokenPool{address: address, abi: *parsed, LockReleaseTokenPoolCaller: LockReleaseTokenPoolCaller{contract: contract}, LockReleaseTokenPoolTransactor: LockReleaseTokenPoolTransactor{contract: contract}, LockReleaseTokenPoolFilterer: LockReleaseTokenPoolFilterer{contract: contract}}, nil
+}
+
+type LockReleaseTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ LockReleaseTokenPoolCaller
+ LockReleaseTokenPoolTransactor
+ LockReleaseTokenPoolFilterer
+}
+
+type LockReleaseTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolSession struct {
+ Contract *LockReleaseTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type LockReleaseTokenPoolCallerSession struct {
+ Contract *LockReleaseTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type LockReleaseTokenPoolTransactorSession struct {
+ Contract *LockReleaseTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type LockReleaseTokenPoolRaw struct {
+ Contract *LockReleaseTokenPool
+}
+
+type LockReleaseTokenPoolCallerRaw struct {
+ Contract *LockReleaseTokenPoolCaller
+}
+
+type LockReleaseTokenPoolTransactorRaw struct {
+ Contract *LockReleaseTokenPoolTransactor
+}
+
+func NewLockReleaseTokenPool(address common.Address, backend bind.ContractBackend) (*LockReleaseTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(LockReleaseTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindLockReleaseTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPool{address: address, abi: abi, LockReleaseTokenPoolCaller: LockReleaseTokenPoolCaller{contract: contract}, LockReleaseTokenPoolTransactor: LockReleaseTokenPoolTransactor{contract: contract}, LockReleaseTokenPoolFilterer: LockReleaseTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewLockReleaseTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*LockReleaseTokenPoolCaller, error) {
+ contract, err := bindLockReleaseTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolCaller{contract: contract}, nil
+}
+
+func NewLockReleaseTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*LockReleaseTokenPoolTransactor, error) {
+ contract, err := bindLockReleaseTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewLockReleaseTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*LockReleaseTokenPoolFilterer, error) {
+ contract, err := bindLockReleaseTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindLockReleaseTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := LockReleaseTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LockReleaseTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) CanAcceptLiquidity(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "canAcceptLiquidity")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) CanAcceptLiquidity() (bool, error) {
+ return _LockReleaseTokenPool.Contract.CanAcceptLiquidity(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) CanAcceptLiquidity() (bool, error) {
+ return _LockReleaseTokenPool.Contract.CanAcceptLiquidity(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowList(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowList(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowListEnabled(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowListEnabled(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.GetCurrentInboundRateLimiterState(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.GetCurrentInboundRateLimiterState(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRateLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRateLimitAdmin() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRateLimitAdmin(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRateLimitAdmin() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRateLimitAdmin(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRebalancer(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRebalancer")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRebalancer() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRebalancer(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRebalancer() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRebalancer(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRemotePool", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _LockReleaseTokenPool.Contract.GetRemotePool(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _LockReleaseTokenPool.Contract.GetRemotePool(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _LockReleaseTokenPool.Contract.GetRemoteToken(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _LockReleaseTokenPool.Contract.GetRemoteToken(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRmnProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRmnProxy() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRmnProxy(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRmnProxy() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRmnProxy(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRouter() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRouter(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRouter(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _LockReleaseTokenPool.Contract.GetSupportedChains(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _LockReleaseTokenPool.Contract.GetSupportedChains(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetToken() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetToken(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetToken(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsSupportedChain(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsSupportedChain(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "isSupportedToken", token)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsSupportedToken(&_LockReleaseTokenPool.CallOpts, token)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsSupportedToken(&_LockReleaseTokenPool.CallOpts, token)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) Owner() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.Owner(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.Owner(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _LockReleaseTokenPool.Contract.SupportsInterface(&_LockReleaseTokenPool.CallOpts, interfaceId)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _LockReleaseTokenPool.Contract.SupportsInterface(&_LockReleaseTokenPool.CallOpts, interfaceId)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) TypeAndVersion() (string, error) {
+ return _LockReleaseTokenPool.Contract.TypeAndVersion(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _LockReleaseTokenPool.Contract.TypeAndVersion(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.AcceptOwnership(&_LockReleaseTokenPool.TransactOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.AcceptOwnership(&_LockReleaseTokenPool.TransactOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyAllowListUpdates(&_LockReleaseTokenPool.TransactOpts, removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyAllowListUpdates(&_LockReleaseTokenPool.TransactOpts, removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyChainUpdates(&_LockReleaseTokenPool.TransactOpts, chains)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyChainUpdates(&_LockReleaseTokenPool.TransactOpts, chains)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "lockOrBurn", lockOrBurnIn)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockOrBurn(&_LockReleaseTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockOrBurn(&_LockReleaseTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "provideLiquidity", amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ProvideLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ProvideLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "releaseOrMint", releaseOrMintIn)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ReleaseOrMint(&_LockReleaseTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ReleaseOrMint(&_LockReleaseTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetChainRateLimiterConfig(&_LockReleaseTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetChainRateLimiterConfig(&_LockReleaseTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setRateLimitAdmin", rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRateLimitAdmin(&_LockReleaseTokenPool.TransactOpts, rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRateLimitAdmin(&_LockReleaseTokenPool.TransactOpts, rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetRebalancer(opts *bind.TransactOpts, rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setRebalancer", rebalancer)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetRebalancer(rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRebalancer(&_LockReleaseTokenPool.TransactOpts, rebalancer)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetRebalancer(rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRebalancer(&_LockReleaseTokenPool.TransactOpts, rebalancer)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setRemotePool", remoteChainSelector, remotePoolAddress)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRemotePool(&_LockReleaseTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRemotePool(&_LockReleaseTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRouter(&_LockReleaseTokenPool.TransactOpts, newRouter)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRouter(&_LockReleaseTokenPool.TransactOpts, newRouter)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.TransferOwnership(&_LockReleaseTokenPool.TransactOpts, to)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.TransferOwnership(&_LockReleaseTokenPool.TransactOpts, to)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "withdrawLiquidity", amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.WithdrawLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.WithdrawLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+type LockReleaseTokenPoolAllowListAddIterator struct {
+ Event *LockReleaseTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAllowListAdd)
+ 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(LockReleaseTokenPoolAllowListAdd)
+ 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 *LockReleaseTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAllowListAddIterator{contract: _LockReleaseTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAllowListAdd)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*LockReleaseTokenPoolAllowListAdd, error) {
+ event := new(LockReleaseTokenPoolAllowListAdd)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAllowListRemoveIterator struct {
+ Event *LockReleaseTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAllowListRemove)
+ 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(LockReleaseTokenPoolAllowListRemove)
+ 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 *LockReleaseTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAllowListRemoveIterator{contract: _LockReleaseTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAllowListRemove)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*LockReleaseTokenPoolAllowListRemove, error) {
+ event := new(LockReleaseTokenPoolAllowListRemove)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolBurnedIterator struct {
+ Event *LockReleaseTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolBurned)
+ 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(LockReleaseTokenPoolBurned)
+ 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 *LockReleaseTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolBurnedIterator{contract: _LockReleaseTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolBurned)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Burned", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseBurned(log types.Log) (*LockReleaseTokenPoolBurned, error) {
+ event := new(LockReleaseTokenPoolBurned)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolChainAddedIterator struct {
+ Event *LockReleaseTokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolChainAdded)
+ 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(LockReleaseTokenPoolChainAdded)
+ 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 *LockReleaseTokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolChainAddedIterator{contract: _LockReleaseTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolChainAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseChainAdded(log types.Log) (*LockReleaseTokenPoolChainAdded, error) {
+ event := new(LockReleaseTokenPoolChainAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolChainConfiguredIterator struct {
+ Event *LockReleaseTokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolChainConfigured)
+ 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(LockReleaseTokenPoolChainConfigured)
+ 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 *LockReleaseTokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolChainConfiguredIterator{contract: _LockReleaseTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolChainConfigured)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseChainConfigured(log types.Log) (*LockReleaseTokenPoolChainConfigured, error) {
+ event := new(LockReleaseTokenPoolChainConfigured)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolChainRemovedIterator struct {
+ Event *LockReleaseTokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolChainRemoved)
+ 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(LockReleaseTokenPoolChainRemoved)
+ 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 *LockReleaseTokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolChainRemovedIterator{contract: _LockReleaseTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolChainRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseChainRemoved(log types.Log) (*LockReleaseTokenPoolChainRemoved, error) {
+ event := new(LockReleaseTokenPoolChainRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolConfigChangedIterator struct {
+ Event *LockReleaseTokenPoolConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolConfigChanged)
+ 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(LockReleaseTokenPoolConfigChanged)
+ 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 *LockReleaseTokenPoolConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*LockReleaseTokenPoolConfigChangedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolConfigChangedIterator{contract: _LockReleaseTokenPool.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolConfigChanged)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ConfigChanged", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseConfigChanged(log types.Log) (*LockReleaseTokenPoolConfigChanged, error) {
+ event := new(LockReleaseTokenPoolConfigChanged)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLiquidityAddedIterator struct {
+ Event *LockReleaseTokenPoolLiquidityAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLiquidityAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLiquidityAdded)
+ 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(LockReleaseTokenPoolLiquidityAdded)
+ 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 *LockReleaseTokenPoolLiquidityAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLiquidityAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLiquidityAdded struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityAddedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLiquidityAddedIterator{contract: _LockReleaseTokenPool.contract, event: "LiquidityAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLiquidityAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityAdded", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLiquidityAdded(log types.Log) (*LockReleaseTokenPoolLiquidityAdded, error) {
+ event := new(LockReleaseTokenPoolLiquidityAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLiquidityRemovedIterator struct {
+ Event *LockReleaseTokenPoolLiquidityRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLiquidityRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLiquidityRemoved)
+ 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(LockReleaseTokenPoolLiquidityRemoved)
+ 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 *LockReleaseTokenPoolLiquidityRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLiquidityRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLiquidityRemoved struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityRemovedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLiquidityRemovedIterator{contract: _LockReleaseTokenPool.contract, event: "LiquidityRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLiquidityRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityRemoved", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLiquidityRemoved(log types.Log) (*LockReleaseTokenPoolLiquidityRemoved, error) {
+ event := new(LockReleaseTokenPoolLiquidityRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLockedIterator struct {
+ Event *LockReleaseTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLocked)
+ 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(LockReleaseTokenPoolLocked)
+ 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 *LockReleaseTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLockedIterator{contract: _LockReleaseTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLocked)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Locked", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLocked(log types.Log) (*LockReleaseTokenPoolLocked, error) {
+ event := new(LockReleaseTokenPoolLocked)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolMintedIterator struct {
+ Event *LockReleaseTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolMinted)
+ 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(LockReleaseTokenPoolMinted)
+ 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 *LockReleaseTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolMintedIterator{contract: _LockReleaseTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolMinted)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Minted", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseMinted(log types.Log) (*LockReleaseTokenPoolMinted, error) {
+ event := new(LockReleaseTokenPoolMinted)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *LockReleaseTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOwnershipTransferRequested)
+ 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(LockReleaseTokenPoolOwnershipTransferRequested)
+ 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 *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOwnershipTransferRequestedIterator{contract: _LockReleaseTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOwnershipTransferRequested)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*LockReleaseTokenPoolOwnershipTransferRequested, error) {
+ event := new(LockReleaseTokenPoolOwnershipTransferRequested)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferredIterator struct {
+ Event *LockReleaseTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOwnershipTransferred)
+ 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(LockReleaseTokenPoolOwnershipTransferred)
+ 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 *LockReleaseTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOwnershipTransferredIterator{contract: _LockReleaseTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOwnershipTransferred)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*LockReleaseTokenPoolOwnershipTransferred, error) {
+ event := new(LockReleaseTokenPoolOwnershipTransferred)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolReleasedIterator struct {
+ Event *LockReleaseTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolReleased)
+ 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(LockReleaseTokenPoolReleased)
+ 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 *LockReleaseTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolReleasedIterator{contract: _LockReleaseTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolReleased)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Released", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseReleased(log types.Log) (*LockReleaseTokenPoolReleased, error) {
+ event := new(LockReleaseTokenPoolReleased)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolRemotePoolSetIterator struct {
+ Event *LockReleaseTokenPoolRemotePoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolRemotePoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolRemotePoolSet)
+ 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(LockReleaseTokenPoolRemotePoolSet)
+ 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 *LockReleaseTokenPoolRemotePoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolRemotePoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolRemotePoolSet struct {
+ RemoteChainSelector uint64
+ PreviousPoolAddress []byte
+ RemotePoolAddress []byte
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*LockReleaseTokenPoolRemotePoolSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolRemotePoolSetIterator{contract: _LockReleaseTokenPool.contract, event: "RemotePoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolRemotePoolSet)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "RemotePoolSet", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseRemotePoolSet(log types.Log) (*LockReleaseTokenPoolRemotePoolSet, error) {
+ event := new(LockReleaseTokenPoolRemotePoolSet)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "RemotePoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolRouterUpdatedIterator struct {
+ Event *LockReleaseTokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolRouterUpdated)
+ 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(LockReleaseTokenPoolRouterUpdated)
+ 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 *LockReleaseTokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*LockReleaseTokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolRouterUpdatedIterator{contract: _LockReleaseTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolRouterUpdated)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*LockReleaseTokenPoolRouterUpdated, error) {
+ event := new(LockReleaseTokenPoolRouterUpdated)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolTokensConsumedIterator struct {
+ Event *LockReleaseTokenPoolTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolTokensConsumed)
+ 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(LockReleaseTokenPoolTokensConsumed)
+ 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 *LockReleaseTokenPoolTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*LockReleaseTokenPoolTokensConsumedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolTokensConsumedIterator{contract: _LockReleaseTokenPool.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolTokensConsumed)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "TokensConsumed", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseTokensConsumed(log types.Log) (*LockReleaseTokenPoolTokensConsumed, error) {
+ event := new(LockReleaseTokenPoolTokensConsumed)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _LockReleaseTokenPool.abi.Events["AllowListAdd"].ID:
+ return _LockReleaseTokenPool.ParseAllowListAdd(log)
+ case _LockReleaseTokenPool.abi.Events["AllowListRemove"].ID:
+ return _LockReleaseTokenPool.ParseAllowListRemove(log)
+ case _LockReleaseTokenPool.abi.Events["Burned"].ID:
+ return _LockReleaseTokenPool.ParseBurned(log)
+ case _LockReleaseTokenPool.abi.Events["ChainAdded"].ID:
+ return _LockReleaseTokenPool.ParseChainAdded(log)
+ case _LockReleaseTokenPool.abi.Events["ChainConfigured"].ID:
+ return _LockReleaseTokenPool.ParseChainConfigured(log)
+ case _LockReleaseTokenPool.abi.Events["ChainRemoved"].ID:
+ return _LockReleaseTokenPool.ParseChainRemoved(log)
+ case _LockReleaseTokenPool.abi.Events["ConfigChanged"].ID:
+ return _LockReleaseTokenPool.ParseConfigChanged(log)
+ case _LockReleaseTokenPool.abi.Events["LiquidityAdded"].ID:
+ return _LockReleaseTokenPool.ParseLiquidityAdded(log)
+ case _LockReleaseTokenPool.abi.Events["LiquidityRemoved"].ID:
+ return _LockReleaseTokenPool.ParseLiquidityRemoved(log)
+ case _LockReleaseTokenPool.abi.Events["Locked"].ID:
+ return _LockReleaseTokenPool.ParseLocked(log)
+ case _LockReleaseTokenPool.abi.Events["Minted"].ID:
+ return _LockReleaseTokenPool.ParseMinted(log)
+ case _LockReleaseTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _LockReleaseTokenPool.ParseOwnershipTransferRequested(log)
+ case _LockReleaseTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _LockReleaseTokenPool.ParseOwnershipTransferred(log)
+ case _LockReleaseTokenPool.abi.Events["Released"].ID:
+ return _LockReleaseTokenPool.ParseReleased(log)
+ case _LockReleaseTokenPool.abi.Events["RemotePoolSet"].ID:
+ return _LockReleaseTokenPool.ParseRemotePoolSet(log)
+ case _LockReleaseTokenPool.abi.Events["RouterUpdated"].ID:
+ return _LockReleaseTokenPool.ParseRouterUpdated(log)
+ case _LockReleaseTokenPool.abi.Events["TokensConsumed"].ID:
+ return _LockReleaseTokenPool.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (LockReleaseTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (LockReleaseTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (LockReleaseTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (LockReleaseTokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2")
+}
+
+func (LockReleaseTokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (LockReleaseTokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (LockReleaseTokenPoolConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (LockReleaseTokenPoolLiquidityAdded) Topic() common.Hash {
+ return common.HexToHash("0xc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb312088")
+}
+
+func (LockReleaseTokenPoolLiquidityRemoved) Topic() common.Hash {
+ return common.HexToHash("0xc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf9840171719")
+}
+
+func (LockReleaseTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (LockReleaseTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (LockReleaseTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (LockReleaseTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (LockReleaseTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (LockReleaseTokenPoolRemotePoolSet) Topic() common.Hash {
+ return common.HexToHash("0xdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf")
+}
+
+func (LockReleaseTokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (LockReleaseTokenPoolTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPool) Address() common.Address {
+ return _LockReleaseTokenPool.address
+}
+
+type LockReleaseTokenPoolInterface interface {
+ CanAcceptLiquidity(opts *bind.CallOpts) (bool, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetRebalancer(opts *bind.CallOpts) (common.Address, error)
+
+ GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRmnProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error)
+
+ ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error)
+
+ SetRebalancer(opts *bind.TransactOpts, rebalancer common.Address) (*types.Transaction, error)
+
+ SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*LockReleaseTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*LockReleaseTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*LockReleaseTokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*LockReleaseTokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*LockReleaseTokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*LockReleaseTokenPoolChainRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*LockReleaseTokenPoolConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*LockReleaseTokenPoolConfigChanged, error)
+
+ FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityAddedIterator, error)
+
+ WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityAdded(log types.Log) (*LockReleaseTokenPoolLiquidityAdded, error)
+
+ FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityRemovedIterator, error)
+
+ WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityRemoved(log types.Log) (*LockReleaseTokenPoolLiquidityRemoved, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*LockReleaseTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*LockReleaseTokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*LockReleaseTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*LockReleaseTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*LockReleaseTokenPoolReleased, error)
+
+ FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*LockReleaseTokenPoolRemotePoolSetIterator, error)
+
+ WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRemotePoolSet(log types.Log) (*LockReleaseTokenPoolRemotePoolSet, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*LockReleaseTokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*LockReleaseTokenPoolRouterUpdated, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*LockReleaseTokenPoolTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*LockReleaseTokenPoolTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/lock_release_token_pool_1_0_0/lock_release_token_pool.go b/core/gethwrappers/ccip/generated/lock_release_token_pool_1_0_0/lock_release_token_pool.go
new file mode 100644
index 00000000000..30ea97eb99e
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/lock_release_token_pool_1_0_0/lock_release_token_pool.go
@@ -0,0 +1,2892 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package lock_release_token_pool_1_0_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolRampUpdate struct {
+ Ramp common.Address
+ Allowed bool
+ RateLimiterConfig RateLimiterConfig
+}
+
+var LockReleaseTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLiquidity\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"ramp\",\"type\":\"address\"}],\"name\":\"NonExistentRamp\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PermissionsError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"ramp\",\"type\":\"address\"}],\"name\":\"RampAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WithdrawalTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"OffRampAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"OffRampConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"OffRampRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"OnRampAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"OnRampConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"}],\"name\":\"OnRampRemoved\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"addLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"ramp\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.RampUpdate[]\",\"name\":\"onRamps\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"ramp\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.RampUpdate[]\",\"name\":\"offRamps\",\"type\":\"tuple[]\"}],\"name\":\"applyRampUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"currentOffRampRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"}],\"name\":\"currentOnRampRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getArmProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLockReleaseInterfaceId\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOffRamps\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOnRamps\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"}],\"name\":\"getProvidedLiquidity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"isOffRamp\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"}],\"name\":\"isOnRamp\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"releaseOrMint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"removeLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setOffRampRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"setOnRampRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60e06040523480156200001157600080fd5b50604051620036093803806200360983398101604081905262000034916200051d565b82828233806000816200008e5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c157620000c18162000133565b5050506001600160a01b038316620000ec576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b03808416608052811660a052815115801560c0526200012757604080516000815260208101909152620001279083620001de565b5050505050506200068e565b336001600160a01b038216036200018d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000085565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c051620001ff576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002945760008382815181106200022357620002236200061a565b602090810291909101015190506200023d6002826200034f565b1562000280576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506200028c8162000646565b905062000202565b5060005b81518110156200034a576000828281518110620002b957620002b96200061a565b6020026020010151905060006001600160a01b0316816001600160a01b031603620002e5575062000337565b620002f26002826200036f565b1562000335576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b620003428162000646565b905062000298565b505050565b600062000366836001600160a01b03841662000386565b90505b92915050565b600062000366836001600160a01b0384166200048a565b600081815260018301602052604081205480156200047f576000620003ad60018362000662565b8554909150600090620003c39060019062000662565b90508181146200042f576000866000018281548110620003e757620003e76200061a565b90600052602060002001549050808760000184815481106200040d576200040d6200061a565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000443576200044362000678565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000369565b600091505062000369565b6000818152600183016020526040812054620004d35750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000369565b50600062000369565b6001600160a01b0381168114620004f257600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b80516200051881620004dc565b919050565b6000806000606084860312156200053357600080fd5b83516200054081620004dc565b602085810151919450906001600160401b03808211156200056057600080fd5b818701915087601f8301126200057557600080fd5b8151818111156200058a576200058a620004f5565b8060051b604051601f19603f83011681018181108582111715620005b257620005b2620004f5565b60405291825284820192508381018501918a831115620005d157600080fd5b938501935b82851015620005fa57620005ea856200050b565b84529385019392850192620005d6565b80975050505050505062000611604085016200050b565b90509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016200065b576200065b62000630565b5060010190565b8181038181111562000369576200036962000630565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c051612f05620007046000396000818161044001528181610aa10152611212015260008181610236015281816108ea0152610b250152600081816101da015281816104fa015281816109d101528181610cbc01528181610db30152818161165201526116ef0152612f056000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c806387381314116100e3578063a7cd63b71161008c578063d612b94511610066578063d612b9451461042b578063e0351e131461043e578063f2fde38b1461046457600080fd5b8063a7cd63b7146103fd578063b3a3fb4114610405578063c49907b51461041857600080fd5b806396875445116100bd57806396875445146103c25780639c8f9f23146103e2578063a40e69c7146103f557600080fd5b806387381314146103615780638bfca18c146103765780638da5cb5b146103a457600080fd5b806356dd1e81116101455780637787e7ab1161011f5780637787e7ab146102d757806379ba5097146103465780638627fad61461034e57600080fd5b806356dd1e811461026d5780636f32b872146102b15780637448b3c7146102c457600080fd5b806351c6590a1161017657806351c6590a1461021f5780635246492f1461023457806354c8a4f31461025a57600080fd5b806301ffc9a71461019d5780631d7a74a0146101c557806321df0da7146101d8575b600080fd5b6101b06101ab366004612670565b610477565b60405190151581526020015b60405180910390f35b6101b06101d33660046126db565b6104d3565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bc565b61023261022d3660046126f6565b6104e0565b005b7f00000000000000000000000000000000000000000000000000000000000000006101fa565b61023261026836600461275b565b610576565b6102a361027b3660046126db565b73ffffffffffffffffffffffffffffffffffffffff166000908152600a602052604090205490565b6040519081526020016101bc565b6101b06102bf3660046126db565b6105f1565b6102326102d236600461289e565b6105fe565b6102ea6102e53660046126db565b6106ce565b6040516101bc919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b6102326107ac565b61023261035c366004612995565b6108a9565b610369610a4c565b6040516101bc9190612a24565b6040517f98a471770000000000000000000000000000000000000000000000000000000081526020016101bc565b60005473ffffffffffffffffffffffffffffffffffffffff166101fa565b6103d56103d0366004612ac0565b610a5d565b6040516101bc9190612bcc565b6102326103f03660046126f6565b610c43565b610369610e0a565b610369610e16565b6102ea6104133660046126db565b610e22565b610232610426366004612c24565b610f00565b61023261043936600461289e565b610f14565b7f00000000000000000000000000000000000000000000000000000000000000006101b0565b6102326104723660046126db565b610fd3565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f98a471770000000000000000000000000000000000000000000000000000000014806104cd57506104cd82610fe7565b92915050565b60006104cd60078361107f565b61052273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330846110b1565b336000908152600a602052604081208054839290610541908490612cb3565b9091555050604051819033907fc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb31208890600090a350565b61057e61118d565b6105eb8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061121092505050565b50505050565b60006104cd60048361107f565b61060661118d565b61060f826105f1565b610662576040517f498f12f600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260066020526040902061069190826113db565b7f578db78e348076074dbff64a94073a83e9a65aa6766b8c75fdc89282b0e30ed682826040516106c2929190612cc6565b60405180910390a15050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff8216600090815260066020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526104cd9061158a565b60015473ffffffffffffffffffffffffffffffffffffffff16331461082d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610659565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6108b2336104d3565b6108e8576040517f5307f5ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610953573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109779190612d1e565b156109ae576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109b78361163c565b6109f873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168585611676565b60405183815273ffffffffffffffffffffffffffffffffffffffff85169033907f2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f529060200160405180910390a35050505050565b6060610a5860046116cc565b905090565b6060610a68336105f1565b610a9e576040517f5307f5ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b877f00000000000000000000000000000000000000000000000000000000000000008015610ad45750610ad260028261107f565b155b15610b23576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610659565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb29190612d1e565b15610be9576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bf2866116d9565b60405186815233907f9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd600089060200160405180910390a25050604080516020810190915260008152979650505050505050565b336000908152600a6020526040902054811115610c8c576040517f6982012000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015610d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3c9190612d3b565b1015610d74576040517fbb55fd2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a602052604081208054839290610d93908490612d54565b90915550610dda905073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163383611676565b604051819033907fc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf984017171990600090a350565b6060610a5860076116cc565b6060610a5860026116cc565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915273ffffffffffffffffffffffffffffffffffffffff8216600090815260096020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526104cd9061158a565b610f0861118d565b6105eb84848484611713565b610f1c61118d565b610f25826104d3565b610f73576040517f498f12f600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610659565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600960205260409020610fa290826113db565b7fb3ba339cfbb8ef80d7a29ce5493051cb90e64fcfa85d7124efc1adfa4c68399f82826040516106c2929190612cc6565b610fdb61118d565b610fe481611cc3565b50565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f317fa3340000000000000000000000000000000000000000000000000000000014806104cd57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b9392505050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526105eb9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611db8565b60005473ffffffffffffffffffffffffffffffffffffffff16331461120e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610659565b565b7f0000000000000000000000000000000000000000000000000000000000000000611267576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b825181101561130557600083828151811061128757611287612d67565b602002602001015190506112a5816002611ec490919063ffffffff16565b156112f45760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b506112fe81612d96565b905061126a565b5060005b81518110156113d657600082828151811061132657611326612d67565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361136a57506113c6565b611375600282611ee6565b156113c45760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b6113cf81612d96565b9050611309565b505050565b815460009061140490700100000000000000000000000000000000900463ffffffff1642612d54565b905080156114a6576001830154835461144c916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416611f08565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b602082015183546114cc916fffffffffffffffffffffffffffffffff9081169116611f32565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199061157d908490612dce565b60405180910390a1505050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261161882606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426115fc9190612d54565b85608001516fffffffffffffffffffffffffffffffff16611f08565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b336000908152600960205260409020610fe490827f0000000000000000000000000000000000000000000000000000000000000000611f48565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526113d69084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161110b565b606060006110aa836122cb565b336000908152600660205260409020610fe490827f0000000000000000000000000000000000000000000000000000000000000000611f48565b61171b61118d565b60005b83811015611a3857600085858381811061173a5761173a612d67565b905060a002018036038101906117509190612e0a565b905080602001511561192857805161176a90600490611ee6565b156118db576040805160a08101825282820180516020908101516fffffffffffffffffffffffffffffffff908116845263ffffffff4281168386019081528451511515868801908152855185015184166060880190815286518901518516608089019081528a5173ffffffffffffffffffffffffffffffffffffffff1660009081526006909752958990209751885493519251151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff939095167001000000000000000000000000000000009081027fffffffffffffffffffffffff0000000000000000000000000000000000000000909516918716919091179390931791909116929092178655905192518216029116176001909201919091558251905191517f0b594bb0555ff7b252e0c789ccc9d8903fec294172064308727d570505cee1ac926118ce9291612cc6565b60405180910390a1611a27565b80516040517fd3eb6bc500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610659565b805161193690600490611ec4565b156119da57805173ffffffffffffffffffffffffffffffffffffffff1660009081526006602052604080822080547fffffffffffffffffffffff00000000000000000000000000000000000000000016815560010191909155815190517f7fd064821314ad863a0714a3f1229375ace6b6427ed5544b7b2ba1c47b1b5294916118ce9173ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b80516040517f498f12f600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610659565b50611a3181612d96565b905061171e565b5060005b81811015611cbc576000838383818110611a5857611a58612d67565b905060a00201803603810190611a6e9190612e0a565b9050806020015115611bf9578051611a8890600790611ee6565b156118db576040805160a08101825282820180516020908101516fffffffffffffffffffffffffffffffff908116845263ffffffff4281168386019081528451511515868801908152855185015184166060880190815286518901518516608089019081528a5173ffffffffffffffffffffffffffffffffffffffff1660009081526009909752958990209751885493519251151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff939095167001000000000000000000000000000000009081027fffffffffffffffffffffffff0000000000000000000000000000000000000000909516918716919091179390931791909116929092178655905192518216029116176001909201919091558251905191517f395b7374909d2b54e5796f53c898ebf41d767c86c78ea86519acf2b805852d8892611bec9291612cc6565b60405180910390a1611cab565b8051611c0790600790611ec4565b156119da57805173ffffffffffffffffffffffffffffffffffffffff1660009081526009602052604080822080547fffffffffffffffffffffff00000000000000000000000000000000000000000016815560010191909155815190517fcf91daec21e3510e2f2aea4b09d08c235d5c6844980be709f282ef591dbf420c91611bec9173ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b50611cb581612d96565b9050611a3c565b5050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611d42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610659565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611e1a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166123279092919063ffffffff16565b8051909150156113d65780806020019051810190611e389190612d1e565b6113d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610659565b60006110aa8373ffffffffffffffffffffffffffffffffffffffff8416612336565b60006110aa8373ffffffffffffffffffffffffffffffffffffffff8416612429565b6000611f2785611f188486612e5b565b611f229087612cb3565b611f32565b90505b949350505050565b6000818310611f4157816110aa565b5090919050565b825474010000000000000000000000000000000000000000900460ff161580611f6f575081155b15611f7957505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090611fbf90700100000000000000000000000000000000900463ffffffff1642612d54565b9050801561207f5781831115612001576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186015461203b9083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16611f08565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156121365773ffffffffffffffffffffffffffffffffffffffff84166120de576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610659565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff85166044820152606401610659565b848310156122495760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1690600090829061217a9082612d54565b612184878a612d54565b61218e9190612cb3565b6121989190612e72565b905073ffffffffffffffffffffffffffffffffffffffff86166121f1576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610659565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff87166044820152606401610659565b6122538584612d54565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561231b57602002820191906000526020600020905b815481526020019060010190808311612307575b50505050509050919050565b6060611f2a8484600085612478565b6000818152600183016020526040812054801561241f57600061235a600183612d54565b855490915060009061236e90600190612d54565b90508181146123d357600086600001828154811061238e5761238e612d67565b90600052602060002001549050808760000184815481106123b1576123b1612d67565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123e4576123e4612ead565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104cd565b60009150506104cd565b6000818152600183016020526040812054612470575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104cd565b5060006104cd565b60608247101561250a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610659565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516125339190612edc565b60006040518083038185875af1925050503d8060008114612570576040519150601f19603f3d011682016040523d82523d6000602084013e612575565b606091505b509150915061258687838387612591565b979650505050505050565b606083156126275782516000036126205773ffffffffffffffffffffffffffffffffffffffff85163b612620576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610659565b5081611f2a565b611f2a838381511561263c5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106599190612bcc565b60006020828403121561268257600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146110aa57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff811681146126d657600080fd5b919050565b6000602082840312156126ed57600080fd5b6110aa826126b2565b60006020828403121561270857600080fd5b5035919050565b60008083601f84011261272157600080fd5b50813567ffffffffffffffff81111561273957600080fd5b6020830191508360208260051b850101111561275457600080fd5b9250929050565b6000806000806040858703121561277157600080fd5b843567ffffffffffffffff8082111561278957600080fd5b6127958883890161270f565b909650945060208701359150808211156127ae57600080fd5b506127bb8782880161270f565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715612819576128196127c7565b60405290565b8015158114610fe457600080fd5b80356fffffffffffffffffffffffffffffffff811681146126d657600080fd5b60006060828403121561285f57600080fd5b6128676127f6565b905081356128748161281f565b81526128826020830161282d565b60208201526128936040830161282d565b604082015292915050565b600080608083850312156128b157600080fd5b6128ba836126b2565b91506128c9846020850161284d565b90509250929050565b600082601f8301126128e357600080fd5b813567ffffffffffffffff808211156128fe576128fe6127c7565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715612944576129446127c7565b8160405283815286602085880101111561295d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b803567ffffffffffffffff811681146126d657600080fd5b600080600080600060a086880312156129ad57600080fd5b853567ffffffffffffffff808211156129c557600080fd5b6129d189838a016128d2565b96506129df602089016126b2565b9550604088013594506129f46060890161297d565b93506080880135915080821115612a0a57600080fd5b50612a17888289016128d2565b9150509295509295909350565b6020808252825182820181905260009190848201906040850190845b81811015612a7257835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612a40565b50909695505050505050565b60008083601f840112612a9057600080fd5b50813567ffffffffffffffff811115612aa857600080fd5b60208301915083602082850101111561275457600080fd5b600080600080600080600060a0888a031215612adb57600080fd5b612ae4886126b2565b9650602088013567ffffffffffffffff80821115612b0157600080fd5b612b0d8b838c01612a7e565b909850965060408a01359550869150612b2860608b0161297d565b945060808a0135915080821115612b3e57600080fd5b50612b4b8a828b01612a7e565b989b979a50959850939692959293505050565b60005b83811015612b79578181015183820152602001612b61565b50506000910152565b60008151808452612b9a816020860160208601612b5e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006110aa6020830184612b82565b60008083601f840112612bf157600080fd5b50813567ffffffffffffffff811115612c0957600080fd5b60208301915083602060a08302850101111561275457600080fd5b60008060008060408587031215612c3a57600080fd5b843567ffffffffffffffff80821115612c5257600080fd5b612c5e88838901612bdf565b90965094506020870135915080821115612c7757600080fd5b506127bb87828801612bdf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156104cd576104cd612c84565b73ffffffffffffffffffffffffffffffffffffffff83168152608081016110aa60208301848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b600060208284031215612d3057600080fd5b81516110aa8161281f565b600060208284031215612d4d57600080fd5b5051919050565b818103818111156104cd576104cd612c84565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dc757612dc7612c84565b5060010190565b606081016104cd82848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b600060a08284031215612e1c57600080fd5b612e246127f6565b612e2d836126b2565b81526020830135612e3d8161281f565b6020820152612e4f846040850161284d565b60408201529392505050565b80820281158282048414176104cd576104cd612c84565b600082612ea8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612eee818460208701612b5e565b919091019291505056fea164736f6c6343000813000a",
+}
+
+var LockReleaseTokenPoolABI = LockReleaseTokenPoolMetaData.ABI
+
+var LockReleaseTokenPoolBin = LockReleaseTokenPoolMetaData.Bin
+
+func DeployLockReleaseTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, armProxy common.Address) (common.Address, *types.Transaction, *LockReleaseTokenPool, error) {
+ parsed, err := LockReleaseTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(LockReleaseTokenPoolBin), backend, token, allowlist, armProxy)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &LockReleaseTokenPool{LockReleaseTokenPoolCaller: LockReleaseTokenPoolCaller{contract: contract}, LockReleaseTokenPoolTransactor: LockReleaseTokenPoolTransactor{contract: contract}, LockReleaseTokenPoolFilterer: LockReleaseTokenPoolFilterer{contract: contract}}, nil
+}
+
+type LockReleaseTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ LockReleaseTokenPoolCaller
+ LockReleaseTokenPoolTransactor
+ LockReleaseTokenPoolFilterer
+}
+
+type LockReleaseTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolSession struct {
+ Contract *LockReleaseTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type LockReleaseTokenPoolCallerSession struct {
+ Contract *LockReleaseTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type LockReleaseTokenPoolTransactorSession struct {
+ Contract *LockReleaseTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type LockReleaseTokenPoolRaw struct {
+ Contract *LockReleaseTokenPool
+}
+
+type LockReleaseTokenPoolCallerRaw struct {
+ Contract *LockReleaseTokenPoolCaller
+}
+
+type LockReleaseTokenPoolTransactorRaw struct {
+ Contract *LockReleaseTokenPoolTransactor
+}
+
+func NewLockReleaseTokenPool(address common.Address, backend bind.ContractBackend) (*LockReleaseTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(LockReleaseTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindLockReleaseTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPool{address: address, abi: abi, LockReleaseTokenPoolCaller: LockReleaseTokenPoolCaller{contract: contract}, LockReleaseTokenPoolTransactor: LockReleaseTokenPoolTransactor{contract: contract}, LockReleaseTokenPoolFilterer: LockReleaseTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewLockReleaseTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*LockReleaseTokenPoolCaller, error) {
+ contract, err := bindLockReleaseTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolCaller{contract: contract}, nil
+}
+
+func NewLockReleaseTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*LockReleaseTokenPoolTransactor, error) {
+ contract, err := bindLockReleaseTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewLockReleaseTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*LockReleaseTokenPoolFilterer, error) {
+ contract, err := bindLockReleaseTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindLockReleaseTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := LockReleaseTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LockReleaseTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) CurrentOffRampRateLimiterState(opts *bind.CallOpts, offRamp common.Address) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "currentOffRampRateLimiterState", offRamp)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) CurrentOffRampRateLimiterState(offRamp common.Address) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.CurrentOffRampRateLimiterState(&_LockReleaseTokenPool.CallOpts, offRamp)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) CurrentOffRampRateLimiterState(offRamp common.Address) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.CurrentOffRampRateLimiterState(&_LockReleaseTokenPool.CallOpts, offRamp)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) CurrentOnRampRateLimiterState(opts *bind.CallOpts, onRamp common.Address) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "currentOnRampRateLimiterState", onRamp)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) CurrentOnRampRateLimiterState(onRamp common.Address) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.CurrentOnRampRateLimiterState(&_LockReleaseTokenPool.CallOpts, onRamp)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) CurrentOnRampRateLimiterState(onRamp common.Address) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.CurrentOnRampRateLimiterState(&_LockReleaseTokenPool.CallOpts, onRamp)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowList(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowList(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowListEnabled(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowListEnabled(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetArmProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getArmProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetArmProxy() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetArmProxy(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetArmProxy() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetArmProxy(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetLockReleaseInterfaceId(opts *bind.CallOpts) ([4]byte, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getLockReleaseInterfaceId")
+
+ if err != nil {
+ return *new([4]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([4]byte)).(*[4]byte)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetLockReleaseInterfaceId() ([4]byte, error) {
+ return _LockReleaseTokenPool.Contract.GetLockReleaseInterfaceId(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetLockReleaseInterfaceId() ([4]byte, error) {
+ return _LockReleaseTokenPool.Contract.GetLockReleaseInterfaceId(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetOffRamps(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getOffRamps")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetOffRamps() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetOffRamps(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetOffRamps() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetOffRamps(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetOnRamps(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getOnRamps")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetOnRamps() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetOnRamps(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetOnRamps() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetOnRamps(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetProvidedLiquidity(opts *bind.CallOpts, provider common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getProvidedLiquidity", provider)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetProvidedLiquidity(provider common.Address) (*big.Int, error) {
+ return _LockReleaseTokenPool.Contract.GetProvidedLiquidity(&_LockReleaseTokenPool.CallOpts, provider)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetProvidedLiquidity(provider common.Address) (*big.Int, error) {
+ return _LockReleaseTokenPool.Contract.GetProvidedLiquidity(&_LockReleaseTokenPool.CallOpts, provider)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetToken() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetToken(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetToken(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) IsOffRamp(opts *bind.CallOpts, offRamp common.Address) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "isOffRamp", offRamp)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) IsOffRamp(offRamp common.Address) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsOffRamp(&_LockReleaseTokenPool.CallOpts, offRamp)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) IsOffRamp(offRamp common.Address) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsOffRamp(&_LockReleaseTokenPool.CallOpts, offRamp)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) IsOnRamp(opts *bind.CallOpts, onRamp common.Address) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "isOnRamp", onRamp)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) IsOnRamp(onRamp common.Address) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsOnRamp(&_LockReleaseTokenPool.CallOpts, onRamp)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) IsOnRamp(onRamp common.Address) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsOnRamp(&_LockReleaseTokenPool.CallOpts, onRamp)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) Owner() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.Owner(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.Owner(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _LockReleaseTokenPool.Contract.SupportsInterface(&_LockReleaseTokenPool.CallOpts, interfaceId)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _LockReleaseTokenPool.Contract.SupportsInterface(&_LockReleaseTokenPool.CallOpts, interfaceId)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.AcceptOwnership(&_LockReleaseTokenPool.TransactOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.AcceptOwnership(&_LockReleaseTokenPool.TransactOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) AddLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "addLiquidity", amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) AddLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.AddLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) AddLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.AddLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyAllowListUpdates(&_LockReleaseTokenPool.TransactOpts, removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyAllowListUpdates(&_LockReleaseTokenPool.TransactOpts, removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ApplyRampUpdates(opts *bind.TransactOpts, onRamps []TokenPoolRampUpdate, offRamps []TokenPoolRampUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "applyRampUpdates", onRamps, offRamps)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ApplyRampUpdates(onRamps []TokenPoolRampUpdate, offRamps []TokenPoolRampUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyRampUpdates(&_LockReleaseTokenPool.TransactOpts, onRamps, offRamps)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ApplyRampUpdates(onRamps []TokenPoolRampUpdate, offRamps []TokenPoolRampUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyRampUpdates(&_LockReleaseTokenPool.TransactOpts, onRamps, offRamps)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, arg1 []byte, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "lockOrBurn", originalSender, arg1, amount, arg3, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) LockOrBurn(originalSender common.Address, arg1 []byte, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockOrBurn(&_LockReleaseTokenPool.TransactOpts, originalSender, arg1, amount, arg3, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) LockOrBurn(originalSender common.Address, arg1 []byte, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockOrBurn(&_LockReleaseTokenPool.TransactOpts, originalSender, arg1, amount, arg3, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "releaseOrMint", arg0, receiver, amount, arg3, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ReleaseOrMint(&_LockReleaseTokenPool.TransactOpts, arg0, receiver, amount, arg3, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ReleaseOrMint(&_LockReleaseTokenPool.TransactOpts, arg0, receiver, amount, arg3, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) RemoveLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "removeLiquidity", amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) RemoveLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.RemoveLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) RemoveLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.RemoveLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetOffRampRateLimiterConfig(opts *bind.TransactOpts, offRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setOffRampRateLimiterConfig", offRamp, config)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetOffRampRateLimiterConfig(offRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetOffRampRateLimiterConfig(&_LockReleaseTokenPool.TransactOpts, offRamp, config)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetOffRampRateLimiterConfig(offRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetOffRampRateLimiterConfig(&_LockReleaseTokenPool.TransactOpts, offRamp, config)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetOnRampRateLimiterConfig(opts *bind.TransactOpts, onRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setOnRampRateLimiterConfig", onRamp, config)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetOnRampRateLimiterConfig(onRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetOnRampRateLimiterConfig(&_LockReleaseTokenPool.TransactOpts, onRamp, config)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetOnRampRateLimiterConfig(onRamp common.Address, config RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetOnRampRateLimiterConfig(&_LockReleaseTokenPool.TransactOpts, onRamp, config)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.TransferOwnership(&_LockReleaseTokenPool.TransactOpts, to)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.TransferOwnership(&_LockReleaseTokenPool.TransactOpts, to)
+}
+
+type LockReleaseTokenPoolAllowListAddIterator struct {
+ Event *LockReleaseTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAllowListAdd)
+ 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(LockReleaseTokenPoolAllowListAdd)
+ 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 *LockReleaseTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAllowListAddIterator{contract: _LockReleaseTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAllowListAdd)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*LockReleaseTokenPoolAllowListAdd, error) {
+ event := new(LockReleaseTokenPoolAllowListAdd)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAllowListRemoveIterator struct {
+ Event *LockReleaseTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAllowListRemove)
+ 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(LockReleaseTokenPoolAllowListRemove)
+ 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 *LockReleaseTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAllowListRemoveIterator{contract: _LockReleaseTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAllowListRemove)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*LockReleaseTokenPoolAllowListRemove, error) {
+ event := new(LockReleaseTokenPoolAllowListRemove)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolBurnedIterator struct {
+ Event *LockReleaseTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolBurned)
+ 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(LockReleaseTokenPoolBurned)
+ 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 *LockReleaseTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolBurnedIterator{contract: _LockReleaseTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolBurned)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Burned", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseBurned(log types.Log) (*LockReleaseTokenPoolBurned, error) {
+ event := new(LockReleaseTokenPoolBurned)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLiquidityAddedIterator struct {
+ Event *LockReleaseTokenPoolLiquidityAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLiquidityAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLiquidityAdded)
+ 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(LockReleaseTokenPoolLiquidityAdded)
+ 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 *LockReleaseTokenPoolLiquidityAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLiquidityAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLiquidityAdded struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityAddedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLiquidityAddedIterator{contract: _LockReleaseTokenPool.contract, event: "LiquidityAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLiquidityAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityAdded", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLiquidityAdded(log types.Log) (*LockReleaseTokenPoolLiquidityAdded, error) {
+ event := new(LockReleaseTokenPoolLiquidityAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLiquidityRemovedIterator struct {
+ Event *LockReleaseTokenPoolLiquidityRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLiquidityRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLiquidityRemoved)
+ 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(LockReleaseTokenPoolLiquidityRemoved)
+ 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 *LockReleaseTokenPoolLiquidityRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLiquidityRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLiquidityRemoved struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityRemovedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLiquidityRemovedIterator{contract: _LockReleaseTokenPool.contract, event: "LiquidityRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLiquidityRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityRemoved", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLiquidityRemoved(log types.Log) (*LockReleaseTokenPoolLiquidityRemoved, error) {
+ event := new(LockReleaseTokenPoolLiquidityRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLockedIterator struct {
+ Event *LockReleaseTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLocked)
+ 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(LockReleaseTokenPoolLocked)
+ 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 *LockReleaseTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLockedIterator{contract: _LockReleaseTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLocked)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Locked", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLocked(log types.Log) (*LockReleaseTokenPoolLocked, error) {
+ event := new(LockReleaseTokenPoolLocked)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolMintedIterator struct {
+ Event *LockReleaseTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolMinted)
+ 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(LockReleaseTokenPoolMinted)
+ 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 *LockReleaseTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolMintedIterator{contract: _LockReleaseTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolMinted)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Minted", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseMinted(log types.Log) (*LockReleaseTokenPoolMinted, error) {
+ event := new(LockReleaseTokenPoolMinted)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOffRampAddedIterator struct {
+ Event *LockReleaseTokenPoolOffRampAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOffRampAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOffRampAdded)
+ 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(LockReleaseTokenPoolOffRampAdded)
+ 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 *LockReleaseTokenPoolOffRampAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOffRampAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOffRampAdded struct {
+ OffRamp common.Address
+ RateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOffRampAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolOffRampAddedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OffRampAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOffRampAddedIterator{contract: _LockReleaseTokenPool.contract, event: "OffRampAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOffRampAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOffRampAdded) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OffRampAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOffRampAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OffRampAdded", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOffRampAdded(log types.Log) (*LockReleaseTokenPoolOffRampAdded, error) {
+ event := new(LockReleaseTokenPoolOffRampAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OffRampAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOffRampConfiguredIterator struct {
+ Event *LockReleaseTokenPoolOffRampConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOffRampConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOffRampConfigured)
+ 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(LockReleaseTokenPoolOffRampConfigured)
+ 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 *LockReleaseTokenPoolOffRampConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOffRampConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOffRampConfigured struct {
+ OffRamp common.Address
+ RateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOffRampConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolOffRampConfiguredIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OffRampConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOffRampConfiguredIterator{contract: _LockReleaseTokenPool.contract, event: "OffRampConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOffRampConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOffRampConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OffRampConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOffRampConfigured)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OffRampConfigured", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOffRampConfigured(log types.Log) (*LockReleaseTokenPoolOffRampConfigured, error) {
+ event := new(LockReleaseTokenPoolOffRampConfigured)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OffRampConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOffRampRemovedIterator struct {
+ Event *LockReleaseTokenPoolOffRampRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOffRampRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOffRampRemoved)
+ 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(LockReleaseTokenPoolOffRampRemoved)
+ 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 *LockReleaseTokenPoolOffRampRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOffRampRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOffRampRemoved struct {
+ OffRamp common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOffRampRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolOffRampRemovedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OffRampRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOffRampRemovedIterator{contract: _LockReleaseTokenPool.contract, event: "OffRampRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOffRampRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOffRampRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OffRampRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOffRampRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OffRampRemoved", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOffRampRemoved(log types.Log) (*LockReleaseTokenPoolOffRampRemoved, error) {
+ event := new(LockReleaseTokenPoolOffRampRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OffRampRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOnRampAddedIterator struct {
+ Event *LockReleaseTokenPoolOnRampAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOnRampAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOnRampAdded)
+ 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(LockReleaseTokenPoolOnRampAdded)
+ 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 *LockReleaseTokenPoolOnRampAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOnRampAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOnRampAdded struct {
+ OnRamp common.Address
+ RateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOnRampAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolOnRampAddedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OnRampAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOnRampAddedIterator{contract: _LockReleaseTokenPool.contract, event: "OnRampAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOnRampAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOnRampAdded) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OnRampAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOnRampAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OnRampAdded", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOnRampAdded(log types.Log) (*LockReleaseTokenPoolOnRampAdded, error) {
+ event := new(LockReleaseTokenPoolOnRampAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OnRampAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOnRampConfiguredIterator struct {
+ Event *LockReleaseTokenPoolOnRampConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOnRampConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOnRampConfigured)
+ 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(LockReleaseTokenPoolOnRampConfigured)
+ 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 *LockReleaseTokenPoolOnRampConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOnRampConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOnRampConfigured struct {
+ OnRamp common.Address
+ RateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOnRampConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolOnRampConfiguredIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OnRampConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOnRampConfiguredIterator{contract: _LockReleaseTokenPool.contract, event: "OnRampConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOnRampConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOnRampConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OnRampConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOnRampConfigured)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OnRampConfigured", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOnRampConfigured(log types.Log) (*LockReleaseTokenPoolOnRampConfigured, error) {
+ event := new(LockReleaseTokenPoolOnRampConfigured)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OnRampConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOnRampRemovedIterator struct {
+ Event *LockReleaseTokenPoolOnRampRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOnRampRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOnRampRemoved)
+ 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(LockReleaseTokenPoolOnRampRemoved)
+ 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 *LockReleaseTokenPoolOnRampRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOnRampRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOnRampRemoved struct {
+ OnRamp common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOnRampRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolOnRampRemovedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OnRampRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOnRampRemovedIterator{contract: _LockReleaseTokenPool.contract, event: "OnRampRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOnRampRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOnRampRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OnRampRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOnRampRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OnRampRemoved", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOnRampRemoved(log types.Log) (*LockReleaseTokenPoolOnRampRemoved, error) {
+ event := new(LockReleaseTokenPoolOnRampRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OnRampRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *LockReleaseTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOwnershipTransferRequested)
+ 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(LockReleaseTokenPoolOwnershipTransferRequested)
+ 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 *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOwnershipTransferRequestedIterator{contract: _LockReleaseTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOwnershipTransferRequested)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*LockReleaseTokenPoolOwnershipTransferRequested, error) {
+ event := new(LockReleaseTokenPoolOwnershipTransferRequested)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferredIterator struct {
+ Event *LockReleaseTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOwnershipTransferred)
+ 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(LockReleaseTokenPoolOwnershipTransferred)
+ 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 *LockReleaseTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOwnershipTransferredIterator{contract: _LockReleaseTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOwnershipTransferred)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*LockReleaseTokenPoolOwnershipTransferred, error) {
+ event := new(LockReleaseTokenPoolOwnershipTransferred)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolReleasedIterator struct {
+ Event *LockReleaseTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolReleased)
+ 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(LockReleaseTokenPoolReleased)
+ 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 *LockReleaseTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolReleasedIterator{contract: _LockReleaseTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolReleased)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Released", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseReleased(log types.Log) (*LockReleaseTokenPoolReleased, error) {
+ event := new(LockReleaseTokenPoolReleased)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _LockReleaseTokenPool.abi.Events["AllowListAdd"].ID:
+ return _LockReleaseTokenPool.ParseAllowListAdd(log)
+ case _LockReleaseTokenPool.abi.Events["AllowListRemove"].ID:
+ return _LockReleaseTokenPool.ParseAllowListRemove(log)
+ case _LockReleaseTokenPool.abi.Events["Burned"].ID:
+ return _LockReleaseTokenPool.ParseBurned(log)
+ case _LockReleaseTokenPool.abi.Events["LiquidityAdded"].ID:
+ return _LockReleaseTokenPool.ParseLiquidityAdded(log)
+ case _LockReleaseTokenPool.abi.Events["LiquidityRemoved"].ID:
+ return _LockReleaseTokenPool.ParseLiquidityRemoved(log)
+ case _LockReleaseTokenPool.abi.Events["Locked"].ID:
+ return _LockReleaseTokenPool.ParseLocked(log)
+ case _LockReleaseTokenPool.abi.Events["Minted"].ID:
+ return _LockReleaseTokenPool.ParseMinted(log)
+ case _LockReleaseTokenPool.abi.Events["OffRampAdded"].ID:
+ return _LockReleaseTokenPool.ParseOffRampAdded(log)
+ case _LockReleaseTokenPool.abi.Events["OffRampConfigured"].ID:
+ return _LockReleaseTokenPool.ParseOffRampConfigured(log)
+ case _LockReleaseTokenPool.abi.Events["OffRampRemoved"].ID:
+ return _LockReleaseTokenPool.ParseOffRampRemoved(log)
+ case _LockReleaseTokenPool.abi.Events["OnRampAdded"].ID:
+ return _LockReleaseTokenPool.ParseOnRampAdded(log)
+ case _LockReleaseTokenPool.abi.Events["OnRampConfigured"].ID:
+ return _LockReleaseTokenPool.ParseOnRampConfigured(log)
+ case _LockReleaseTokenPool.abi.Events["OnRampRemoved"].ID:
+ return _LockReleaseTokenPool.ParseOnRampRemoved(log)
+ case _LockReleaseTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _LockReleaseTokenPool.ParseOwnershipTransferRequested(log)
+ case _LockReleaseTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _LockReleaseTokenPool.ParseOwnershipTransferred(log)
+ case _LockReleaseTokenPool.abi.Events["Released"].ID:
+ return _LockReleaseTokenPool.ParseReleased(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (LockReleaseTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (LockReleaseTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (LockReleaseTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (LockReleaseTokenPoolLiquidityAdded) Topic() common.Hash {
+ return common.HexToHash("0xc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb312088")
+}
+
+func (LockReleaseTokenPoolLiquidityRemoved) Topic() common.Hash {
+ return common.HexToHash("0xc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf9840171719")
+}
+
+func (LockReleaseTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (LockReleaseTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (LockReleaseTokenPoolOffRampAdded) Topic() common.Hash {
+ return common.HexToHash("0x395b7374909d2b54e5796f53c898ebf41d767c86c78ea86519acf2b805852d88")
+}
+
+func (LockReleaseTokenPoolOffRampConfigured) Topic() common.Hash {
+ return common.HexToHash("0xb3ba339cfbb8ef80d7a29ce5493051cb90e64fcfa85d7124efc1adfa4c68399f")
+}
+
+func (LockReleaseTokenPoolOffRampRemoved) Topic() common.Hash {
+ return common.HexToHash("0xcf91daec21e3510e2f2aea4b09d08c235d5c6844980be709f282ef591dbf420c")
+}
+
+func (LockReleaseTokenPoolOnRampAdded) Topic() common.Hash {
+ return common.HexToHash("0x0b594bb0555ff7b252e0c789ccc9d8903fec294172064308727d570505cee1ac")
+}
+
+func (LockReleaseTokenPoolOnRampConfigured) Topic() common.Hash {
+ return common.HexToHash("0x578db78e348076074dbff64a94073a83e9a65aa6766b8c75fdc89282b0e30ed6")
+}
+
+func (LockReleaseTokenPoolOnRampRemoved) Topic() common.Hash {
+ return common.HexToHash("0x7fd064821314ad863a0714a3f1229375ace6b6427ed5544b7b2ba1c47b1b5294")
+}
+
+func (LockReleaseTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (LockReleaseTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (LockReleaseTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPool) Address() common.Address {
+ return _LockReleaseTokenPool.address
+}
+
+type LockReleaseTokenPoolInterface interface {
+ CurrentOffRampRateLimiterState(opts *bind.CallOpts, offRamp common.Address) (RateLimiterTokenBucket, error)
+
+ CurrentOnRampRateLimiterState(opts *bind.CallOpts, onRamp common.Address) (RateLimiterTokenBucket, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetArmProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetLockReleaseInterfaceId(opts *bind.CallOpts) ([4]byte, error)
+
+ GetOffRamps(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetOnRamps(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetProvidedLiquidity(opts *bind.CallOpts, provider common.Address) (*big.Int, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsOffRamp(opts *bind.CallOpts, offRamp common.Address) (bool, error)
+
+ IsOnRamp(opts *bind.CallOpts, onRamp common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ AddLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyRampUpdates(opts *bind.TransactOpts, onRamps []TokenPoolRampUpdate, offRamps []TokenPoolRampUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, arg1 []byte, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, arg3 uint64, arg4 []byte) (*types.Transaction, error)
+
+ RemoveLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ SetOffRampRateLimiterConfig(opts *bind.TransactOpts, offRamp common.Address, config RateLimiterConfig) (*types.Transaction, error)
+
+ SetOnRampRateLimiterConfig(opts *bind.TransactOpts, onRamp common.Address, config RateLimiterConfig) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*LockReleaseTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*LockReleaseTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*LockReleaseTokenPoolBurned, error)
+
+ FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityAddedIterator, error)
+
+ WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityAdded(log types.Log) (*LockReleaseTokenPoolLiquidityAdded, error)
+
+ FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityRemovedIterator, error)
+
+ WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityRemoved(log types.Log) (*LockReleaseTokenPoolLiquidityRemoved, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*LockReleaseTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*LockReleaseTokenPoolMinted, error)
+
+ FilterOffRampAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolOffRampAddedIterator, error)
+
+ WatchOffRampAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOffRampAdded) (event.Subscription, error)
+
+ ParseOffRampAdded(log types.Log) (*LockReleaseTokenPoolOffRampAdded, error)
+
+ FilterOffRampConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolOffRampConfiguredIterator, error)
+
+ WatchOffRampConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOffRampConfigured) (event.Subscription, error)
+
+ ParseOffRampConfigured(log types.Log) (*LockReleaseTokenPoolOffRampConfigured, error)
+
+ FilterOffRampRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolOffRampRemovedIterator, error)
+
+ WatchOffRampRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOffRampRemoved) (event.Subscription, error)
+
+ ParseOffRampRemoved(log types.Log) (*LockReleaseTokenPoolOffRampRemoved, error)
+
+ FilterOnRampAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolOnRampAddedIterator, error)
+
+ WatchOnRampAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOnRampAdded) (event.Subscription, error)
+
+ ParseOnRampAdded(log types.Log) (*LockReleaseTokenPoolOnRampAdded, error)
+
+ FilterOnRampConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolOnRampConfiguredIterator, error)
+
+ WatchOnRampConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOnRampConfigured) (event.Subscription, error)
+
+ ParseOnRampConfigured(log types.Log) (*LockReleaseTokenPoolOnRampConfigured, error)
+
+ FilterOnRampRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolOnRampRemovedIterator, error)
+
+ WatchOnRampRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOnRampRemoved) (event.Subscription, error)
+
+ ParseOnRampRemoved(log types.Log) (*LockReleaseTokenPoolOnRampRemoved, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*LockReleaseTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*LockReleaseTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*LockReleaseTokenPoolReleased, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/lock_release_token_pool_1_4_0/lock_release_token_pool_1_4_0.go b/core/gethwrappers/ccip/generated/lock_release_token_pool_1_4_0/lock_release_token_pool_1_4_0.go
new file mode 100644
index 00000000000..8d3377f25be
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/lock_release_token_pool_1_4_0/lock_release_token_pool_1_4_0.go
@@ -0,0 +1,2712 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package lock_release_token_pool_1_4_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var LockReleaseTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"acceptLiquidity\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLiquidity\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRatelimitRate\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LiquidityNotAccepted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"canAcceptLiquidity\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getArmProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLockReleaseInterfaceId\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRateLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRebalancer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"provideLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"releaseOrMint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"rateLimitAdmin\",\"type\":\"address\"}],\"name\":\"setRateLimitAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"rebalancer\",\"type\":\"address\"}],\"name\":\"setRebalancer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101006040523480156200001257600080fd5b5060405162003dd738038062003dd7833981016040819052620000359162000566565b848484833380600081620000905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c357620000c3816200016b565b5050506001600160a01b0384161580620000e457506001600160a01b038116155b1562000103576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c052620001565760408051600081526020810190915262000156908462000216565b5050505090151560e05250620006fd92505050565b336001600160a01b03821603620001c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000087565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c05162000237576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002cc5760008382815181106200025b576200025b62000689565b602090810291909101015190506200027560028262000387565b15620002b8576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50620002c481620006b5565b90506200023a565b5060005b815181101562000382576000828281518110620002f157620002f162000689565b6020026020010151905060006001600160a01b0316816001600160a01b0316036200031d57506200036f565b6200032a600282620003a7565b156200036d576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b6200037a81620006b5565b9050620002d0565b505050565b60006200039e836001600160a01b038416620003be565b90505b92915050565b60006200039e836001600160a01b038416620004c2565b60008181526001830160205260408120548015620004b7576000620003e5600183620006d1565b8554909150600090620003fb90600190620006d1565b9050818114620004675760008660000182815481106200041f576200041f62000689565b906000526020600020015490508087600001848154811062000445576200044562000689565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806200047b576200047b620006e7565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050620003a1565b6000915050620003a1565b60008181526001830160205260408120546200050b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620003a1565b506000620003a1565b6001600160a01b03811681146200052a57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b8051620005508162000514565b919050565b805180151581146200055057600080fd5b600080600080600060a086880312156200057f57600080fd5b85516200058c8162000514565b602087810151919650906001600160401b0380821115620005ac57600080fd5b818901915089601f830112620005c157600080fd5b815181811115620005d657620005d66200052d565b8060051b604051601f19603f83011681018181108582111715620005fe57620005fe6200052d565b60405291825284820192508381018501918c8311156200061d57600080fd5b938501935b828510156200064657620006368562000543565b8452938501939285019262000622565b8099505050505050506200065d6040870162000543565b92506200066d6060870162000555565b91506200067d6080870162000543565b90509295509295909350565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620006ca57620006ca6200069f565b5060010190565b81810381811115620003a157620003a16200069f565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05160e051613653620007846000396000818161047501526118ac0152600081816104e9015281816113320152611bcb0152600081816102b60152818161106301526113b601526000818161025101528181610663015281816107350152818161114b0152818161196e01528181611f0b0152611f9601526136536000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80638bfca18c116100f9578063c0d7865511610097578063cf7401f311610071578063cf7401f3146104d4578063e0351e13146104e7578063eb521a4c1461050d578063f2fde38b1461052057600080fd5b8063c0d7865514610499578063c4bffe2b146104ac578063c75eea9c146104c157600080fd5b8063a7cd63b7116100d3578063a7cd63b7146103d1578063af58d59f146103e6578063b0f479a114610455578063bb98546b1461047357600080fd5b80638bfca18c146103725780638da5cb5b146103a057806396875445146103be57600080fd5b80635995f0631161016657806379ba50971161014057806379ba5097146103315780637d54534e146103395780638627fad61461034c5780638926f54f1461035f57600080fd5b80635995f063146102ed5780636cfd1553146103005780636d3d1a581461031357600080fd5b806321df0da7116101a257806321df0da71461024f578063432a6ba3146102965780635246492f146102b457806354c8a4f3146102da57600080fd5b806301ffc9a7146101c95780630a861f2a146101f1578063181f5a7714610206575b600080fd5b6101dc6101d7366004612d09565b610533565b60405190151581526020015b60405180910390f35b6102046101ff366004612d4b565b6105db565b005b6102426040518060400160405280601a81526020017f4c6f636b52656c65617365546f6b656e506f6f6c20312e342e3000000000000081525081565b6040516101e89190612dd2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101e8565b60095473ffffffffffffffffffffffffffffffffffffffff16610271565b7f0000000000000000000000000000000000000000000000000000000000000000610271565b6102046102e8366004612e31565b61078c565b6102046102fb366004612e9d565b610807565b61020461030e366004612f34565b610d9f565b600a5473ffffffffffffffffffffffffffffffffffffffff16610271565b610204610dee565b610204610347366004612f34565b610eeb565b61020461035a366004613048565b610f3a565b6101dc61036d3660046130dc565b6111c7565b6040517f98a471770000000000000000000000000000000000000000000000000000000081526020016101e8565b60005473ffffffffffffffffffffffffffffffffffffffff16610271565b6102426103cc366004613139565b6111de565b6103d96114d6565b6040516101e891906131d9565b6103f96103f43660046130dc565b6114e7565b6040516101e8919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610271565b7f00000000000000000000000000000000000000000000000000000000000000006101dc565b6102046104a7366004612f34565b6115b9565b6104b4611694565b6040516101e89190613233565b6103f96104cf3660046130dc565b611754565b6102046104e2366004613314565b611826565b7f00000000000000000000000000000000000000000000000000000000000000006101dc565b61020461051b366004612d4b565b6118aa565b61020461052e366004612f34565b6119c6565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f98a471770000000000000000000000000000000000000000000000000000000014806105c657507fffffffff0000000000000000000000000000000000000000000000000000000082167fe1d4056600000000000000000000000000000000000000000000000000000000145b806105d557506105d5826119da565b92915050565b60095473ffffffffffffffffffffffffffffffffffffffff163314610633576040517f8e4a23d60000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156106bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e39190613359565b101561071b576040517fbb55fd2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61075c73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163383611a72565b604051819033907fc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf984017171990600090a350565b610794611b46565b61080184848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250611bc992505050565b50505050565b61080f611b46565b60005b81811015610d9a57600083838381811061082e5761082e613372565b9050610100020180360381019061084591906133a1565b905061085a8160400151826020015115611d8f565b61086d8160600151826020015115611d8f565b806020015115610c8e57805161088f9060059067ffffffffffffffff16611ecc565b6108d45780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff909116600482015260240161062a565b6040518060a001604052808260400151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff168152602001826040015160000151151581526020018260400151602001516fffffffffffffffffffffffffffffffff1681526020018260400151604001516fffffffffffffffffffffffffffffffff1681525060076000836000015167ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548160ff02191690831515021790555060608201518160010160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050506040518060a001604052808260600151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff168152602001826060015160000151151581526020018260600151602001516fffffffffffffffffffffffffffffffff1681526020018260600151604001516fffffffffffffffffffffffffffffffff1681525060086000836000015167ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548160ff02191690831515021790555060608201518160010160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050507f0f135cbb9afa12a8bf3bbd071c117bcca4ddeca6160ef7f33d012a81b9c0c471816000015182604001518360600151604051610c8193929190613423565b60405180910390a1610d89565b8051610ca69060059067ffffffffffffffff16611edf565b610ceb5780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff909116600482015260240161062a565b805167ffffffffffffffff908116600090815260086020908152604080832080547fffffffffffffffffffffff0000000000000000000000000000000000000000009081168255600191820185905586518616855260078452828520805490911681550192909255835191519190921681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916910160405180910390a15b50610d93816134d5565b9050610812565b505050565b610da7611b46565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610e6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161062a565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610ef3611b46565b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b81610f44816111c7565b610f86576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8216600482015260240161062a565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015611005573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611029919061350d565b611061576040517f728fe07b00000000000000000000000000000000000000000000000000000000815233600482015260240161062a565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f0919061350d565b15611127576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111318385611eeb565b61117273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168686611a72565b60405184815273ffffffffffffffffffffffffffffffffffffffff86169033907f2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f529060200160405180910390a3505050505050565b60006105d5600567ffffffffffffffff8416611f2f565b6060836111ea816111c7565b61122c576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8216600482015260240161062a565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa1580156112a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c9919061352a565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461132f576040517f728fe07b00000000000000000000000000000000000000000000000000000000815233600482015260240161062a565b887f000000000000000000000000000000000000000000000000000000000000000080156113655750611363600282611f47565b155b156113b4576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161062a565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561141f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611443919061350d565b1561147a576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114848688611f76565b60405187815233907f9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd600089060200160405180910390a2505060408051602081019091526000815298975050505050505050565b60606114e26002611fba565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260086020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526105d590611fc7565b6115c1611b46565b73ffffffffffffffffffffffffffffffffffffffff811661160e576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684910160405180910390a15050565b606060006116a26005611fba565b90506000815167ffffffffffffffff8111156116c0576116c0612f51565b6040519080825280602002602001820160405280156116e9578160200160208202803683370190505b50905060005b825181101561174d5782818151811061170a5761170a613372565b602002602001015182828151811061172457611724613372565b67ffffffffffffffff90921660209283029190910190910152611746816134d5565b90506116ef565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526105d590611fc7565b600a5473ffffffffffffffffffffffffffffffffffffffff163314801590611866575060005473ffffffffffffffffffffffffffffffffffffffff163314155b1561189f576040517f8e4a23d600000000000000000000000000000000000000000000000000000000815233600482015260240161062a565b610d9a838383612079565b7f0000000000000000000000000000000000000000000000000000000000000000611901576040517fe93f8fa400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095473ffffffffffffffffffffffffffffffffffffffff163314611954576040517f8e4a23d600000000000000000000000000000000000000000000000000000000815233600482015260240161062a565b61199673ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084612160565b604051819033907fc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb31208890600090a350565b6119ce611b46565b6119d7816121be565b50565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f317fa3340000000000000000000000000000000000000000000000000000000014806105d557507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610d9a9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526122b3565b60005473ffffffffffffffffffffffffffffffffffffffff163314611bc7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161062a565b565b7f0000000000000000000000000000000000000000000000000000000000000000611c20576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015611cbe576000838281518110611c4057611c40613372565b60200260200101519050611c5e8160026123bf90919063ffffffff16565b15611cad5760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50611cb7816134d5565b9050611c23565b5060005b8151811015610d9a576000828281518110611cdf57611cdf613372565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611d235750611d7f565b611d2e6002826123e1565b15611d7d5760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b611d88816134d5565b9050611cc2565b815115611e5a5781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580611de5575060408201516fffffffffffffffffffffffffffffffff16155b15611e1e57816040517f70505e5600000000000000000000000000000000000000000000000000000000815260040161062a9190613547565b8015611e56576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60408201516fffffffffffffffffffffffffffffffff16151580611e93575060208201516fffffffffffffffffffffffffffffffff1615155b15611e5657816040517fd68af9cc00000000000000000000000000000000000000000000000000000000815260040161062a9190613547565b6000611ed883836123ff565b9392505050565b6000611ed8838361244e565b67ffffffffffffffff82166000908152600860205260409020611e5690827f0000000000000000000000000000000000000000000000000000000000000000612541565b60008181526001830160205260408120541515611ed8565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515611ed8565b67ffffffffffffffff82166000908152600760205260409020611e5690827f0000000000000000000000000000000000000000000000000000000000000000612541565b60606000611ed8836128c4565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261205582606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426120399190613583565b85608001516fffffffffffffffffffffffffffffffff16612920565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b612082836111c7565b6120c4576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8416600482015260240161062a565b6120cf826000611d8f565b67ffffffffffffffff831660009081526007602052604090206120f2908361294a565b6120fd816000611d8f565b67ffffffffffffffff83166000908152600860205260409020612120908261294a565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b83838360405161215393929190613423565b60405180910390a1505050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526108019085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611ac4565b3373ffffffffffffffffffffffffffffffffffffffff82160361223d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161062a565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000612315826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612aec9092919063ffffffff16565b805190915015610d9a5780806020019051810190612333919061350d565b610d9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161062a565b6000611ed88373ffffffffffffffffffffffffffffffffffffffff841661244e565b6000611ed88373ffffffffffffffffffffffffffffffffffffffff84165b6000818152600183016020526040812054612446575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105d5565b5060006105d5565b60008181526001830160205260408120548015612537576000612472600183613583565b855490915060009061248690600190613583565b90508181146124eb5760008660000182815481106124a6576124a6613372565b90600052602060002001549050808760000184815481106124c9576124c9613372565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806124fc576124fc613596565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105d5565b60009150506105d5565b825474010000000000000000000000000000000000000000900460ff161580612568575081155b1561257257505050565b825460018401546fffffffffffffffffffffffffffffffff808316929116906000906125b890700100000000000000000000000000000000900463ffffffff1642613583565b9050801561267857818311156125fa576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546126349083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612920565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b8482101561272f5773ffffffffffffffffffffffffffffffffffffffff84166126d7576040517ff94ebcd1000000000000000000000000000000000000000000000000000000008152600481018390526024810186905260440161062a565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff8516604482015260640161062a565b848310156128425760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906127739082613583565b61277d878a613583565b61278791906135c5565b61279191906135d8565b905073ffffffffffffffffffffffffffffffffffffffff86166127ea576040517f15279c08000000000000000000000000000000000000000000000000000000008152600481018290526024810186905260440161062a565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff8716604482015260640161062a565b61284c8584613583565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561291457602002820191906000526020600020905b815481526020019060010190808311612900575b50505050509050919050565b600061293f856129308486613613565b61293a90876135c5565b612afb565b90505b949350505050565b815460009061297390700100000000000000000000000000000000900463ffffffff1642613583565b90508015612a1557600183015483546129bb916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612920565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612a3b916fffffffffffffffffffffffffffffffff9081169116612afb565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c1990612153908490613547565b60606129428484600085612b11565b6000818310612b0a5781611ed8565b5090919050565b606082471015612ba3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161062a565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612bcc919061362a565b60006040518083038185875af1925050503d8060008114612c09576040519150601f19603f3d011682016040523d82523d6000602084013e612c0e565b606091505b5091509150612c1f87838387612c2a565b979650505050505050565b60608315612cc0578251600003612cb95773ffffffffffffffffffffffffffffffffffffffff85163b612cb9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161062a565b5081612942565b6129428383815115612cd55781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161062a9190612dd2565b600060208284031215612d1b57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611ed857600080fd5b600060208284031215612d5d57600080fd5b5035919050565b60005b83811015612d7f578181015183820152602001612d67565b50506000910152565b60008151808452612da0816020860160208601612d64565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611ed86020830184612d88565b60008083601f840112612df757600080fd5b50813567ffffffffffffffff811115612e0f57600080fd5b6020830191508360208260051b8501011115612e2a57600080fd5b9250929050565b60008060008060408587031215612e4757600080fd5b843567ffffffffffffffff80821115612e5f57600080fd5b612e6b88838901612de5565b90965094506020870135915080821115612e8457600080fd5b50612e9187828801612de5565b95989497509550505050565b60008060208385031215612eb057600080fd5b823567ffffffffffffffff80821115612ec857600080fd5b818501915085601f830112612edc57600080fd5b813581811115612eeb57600080fd5b8660208260081b8501011115612f0057600080fd5b60209290920196919550909350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146119d757600080fd5b600060208284031215612f4657600080fd5b8135611ed881612f12565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112612f9157600080fd5b813567ffffffffffffffff80821115612fac57612fac612f51565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715612ff257612ff2612f51565b8160405283815286602085880101111561300b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b803567ffffffffffffffff8116811461304357600080fd5b919050565b600080600080600060a0868803121561306057600080fd5b853567ffffffffffffffff8082111561307857600080fd5b61308489838a01612f80565b96506020880135915061309682612f12565b819550604088013594506130ac6060890161302b565b935060808801359150808211156130c257600080fd5b506130cf88828901612f80565b9150509295509295909350565b6000602082840312156130ee57600080fd5b611ed88261302b565b60008083601f84011261310957600080fd5b50813567ffffffffffffffff81111561312157600080fd5b602083019150836020828501011115612e2a57600080fd5b600080600080600080600060a0888a03121561315457600080fd5b873561315f81612f12565b9650602088013567ffffffffffffffff8082111561317c57600080fd5b6131888b838c016130f7565b909850965060408a013595508691506131a360608b0161302b565b945060808a01359150808211156131b957600080fd5b506131c68a828b016130f7565b989b979a50959850939692959293505050565b6020808252825182820181905260009190848201906040850190845b8181101561322757835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016131f5565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561322757835167ffffffffffffffff168352928401929184019160010161324f565b80151581146119d757600080fd5b80356fffffffffffffffffffffffffffffffff8116811461304357600080fd5b6000606082840312156132b557600080fd5b6040516060810181811067ffffffffffffffff821117156132d8576132d8612f51565b60405290508082356132e981613275565b81526132f760208401613283565b602082015261330860408401613283565b60408201525092915050565b600080600060e0848603121561332957600080fd5b6133328461302b565b925061334185602086016132a3565b915061335085608086016132a3565b90509250925092565b60006020828403121561336b57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061010082840312156133b457600080fd5b6040516080810181811067ffffffffffffffff821117156133d7576133d7612f51565b6040526133e38361302b565b815260208301356133f381613275565b602082015261340584604085016132a3565b60408201526134178460a085016132a3565b60608201529392505050565b67ffffffffffffffff8416815260e0810161346f60208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c0830152612942565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613506576135066134a6565b5060010190565b60006020828403121561351f57600080fd5b8151611ed881613275565b60006020828403121561353c57600080fd5b8151611ed881612f12565b606081016105d582848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b818103818111156105d5576105d56134a6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b808201808211156105d5576105d56134a6565b60008261360e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b80820281158282048414176105d5576105d56134a6565b6000825161363c818460208701612d64565b919091019291505056fea164736f6c6343000813000a",
+}
+
+var LockReleaseTokenPoolABI = LockReleaseTokenPoolMetaData.ABI
+
+var LockReleaseTokenPoolBin = LockReleaseTokenPoolMetaData.Bin
+
+func DeployLockReleaseTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, armProxy common.Address, acceptLiquidity bool, router common.Address) (common.Address, *types.Transaction, *LockReleaseTokenPool, error) {
+ parsed, err := LockReleaseTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(LockReleaseTokenPoolBin), backend, token, allowlist, armProxy, acceptLiquidity, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &LockReleaseTokenPool{address: address, abi: *parsed, LockReleaseTokenPoolCaller: LockReleaseTokenPoolCaller{contract: contract}, LockReleaseTokenPoolTransactor: LockReleaseTokenPoolTransactor{contract: contract}, LockReleaseTokenPoolFilterer: LockReleaseTokenPoolFilterer{contract: contract}}, nil
+}
+
+type LockReleaseTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ LockReleaseTokenPoolCaller
+ LockReleaseTokenPoolTransactor
+ LockReleaseTokenPoolFilterer
+}
+
+type LockReleaseTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolSession struct {
+ Contract *LockReleaseTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type LockReleaseTokenPoolCallerSession struct {
+ Contract *LockReleaseTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type LockReleaseTokenPoolTransactorSession struct {
+ Contract *LockReleaseTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type LockReleaseTokenPoolRaw struct {
+ Contract *LockReleaseTokenPool
+}
+
+type LockReleaseTokenPoolCallerRaw struct {
+ Contract *LockReleaseTokenPoolCaller
+}
+
+type LockReleaseTokenPoolTransactorRaw struct {
+ Contract *LockReleaseTokenPoolTransactor
+}
+
+func NewLockReleaseTokenPool(address common.Address, backend bind.ContractBackend) (*LockReleaseTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(LockReleaseTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindLockReleaseTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPool{address: address, abi: abi, LockReleaseTokenPoolCaller: LockReleaseTokenPoolCaller{contract: contract}, LockReleaseTokenPoolTransactor: LockReleaseTokenPoolTransactor{contract: contract}, LockReleaseTokenPoolFilterer: LockReleaseTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewLockReleaseTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*LockReleaseTokenPoolCaller, error) {
+ contract, err := bindLockReleaseTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolCaller{contract: contract}, nil
+}
+
+func NewLockReleaseTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*LockReleaseTokenPoolTransactor, error) {
+ contract, err := bindLockReleaseTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewLockReleaseTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*LockReleaseTokenPoolFilterer, error) {
+ contract, err := bindLockReleaseTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindLockReleaseTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := LockReleaseTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockReleaseTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LockReleaseTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) CanAcceptLiquidity(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "canAcceptLiquidity")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) CanAcceptLiquidity() (bool, error) {
+ return _LockReleaseTokenPool.Contract.CanAcceptLiquidity(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) CanAcceptLiquidity() (bool, error) {
+ return _LockReleaseTokenPool.Contract.CanAcceptLiquidity(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowList(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowList(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowListEnabled(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _LockReleaseTokenPool.Contract.GetAllowListEnabled(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetArmProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getArmProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetArmProxy() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetArmProxy(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetArmProxy() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetArmProxy(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.GetCurrentInboundRateLimiterState(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.GetCurrentInboundRateLimiterState(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetLockReleaseInterfaceId(opts *bind.CallOpts) ([4]byte, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getLockReleaseInterfaceId")
+
+ if err != nil {
+ return *new([4]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([4]byte)).(*[4]byte)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetLockReleaseInterfaceId() ([4]byte, error) {
+ return _LockReleaseTokenPool.Contract.GetLockReleaseInterfaceId(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetLockReleaseInterfaceId() ([4]byte, error) {
+ return _LockReleaseTokenPool.Contract.GetLockReleaseInterfaceId(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRateLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRateLimitAdmin() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRateLimitAdmin(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRateLimitAdmin() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRateLimitAdmin(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRebalancer(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRebalancer")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRebalancer() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRebalancer(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRebalancer() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRebalancer(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetRouter() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRouter(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetRouter(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _LockReleaseTokenPool.Contract.GetSupportedChains(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _LockReleaseTokenPool.Contract.GetSupportedChains(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) GetToken() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetToken(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.GetToken(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsSupportedChain(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _LockReleaseTokenPool.Contract.IsSupportedChain(&_LockReleaseTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) Owner() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.Owner(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _LockReleaseTokenPool.Contract.Owner(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _LockReleaseTokenPool.Contract.SupportsInterface(&_LockReleaseTokenPool.CallOpts, interfaceId)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _LockReleaseTokenPool.Contract.SupportsInterface(&_LockReleaseTokenPool.CallOpts, interfaceId)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) TypeAndVersion() (string, error) {
+ return _LockReleaseTokenPool.Contract.TypeAndVersion(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _LockReleaseTokenPool.Contract.TypeAndVersion(&_LockReleaseTokenPool.CallOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.AcceptOwnership(&_LockReleaseTokenPool.TransactOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.AcceptOwnership(&_LockReleaseTokenPool.TransactOpts)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyAllowListUpdates(&_LockReleaseTokenPool.TransactOpts, removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyAllowListUpdates(&_LockReleaseTokenPool.TransactOpts, removes, adds)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyChainUpdates(&_LockReleaseTokenPool.TransactOpts, chains)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ApplyChainUpdates(&_LockReleaseTokenPool.TransactOpts, chains)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, arg1 []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "lockOrBurn", originalSender, arg1, amount, remoteChainSelector, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) LockOrBurn(originalSender common.Address, arg1 []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockOrBurn(&_LockReleaseTokenPool.TransactOpts, originalSender, arg1, amount, remoteChainSelector, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) LockOrBurn(originalSender common.Address, arg1 []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.LockOrBurn(&_LockReleaseTokenPool.TransactOpts, originalSender, arg1, amount, remoteChainSelector, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "provideLiquidity", amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ProvideLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ProvideLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "releaseOrMint", arg0, receiver, amount, remoteChainSelector, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ReleaseOrMint(&_LockReleaseTokenPool.TransactOpts, arg0, receiver, amount, remoteChainSelector, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.ReleaseOrMint(&_LockReleaseTokenPool.TransactOpts, arg0, receiver, amount, remoteChainSelector, arg4)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetChainRateLimiterConfig(&_LockReleaseTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetChainRateLimiterConfig(&_LockReleaseTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setRateLimitAdmin", rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRateLimitAdmin(&_LockReleaseTokenPool.TransactOpts, rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRateLimitAdmin(&_LockReleaseTokenPool.TransactOpts, rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetRebalancer(opts *bind.TransactOpts, rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setRebalancer", rebalancer)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetRebalancer(rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRebalancer(&_LockReleaseTokenPool.TransactOpts, rebalancer)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetRebalancer(rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRebalancer(&_LockReleaseTokenPool.TransactOpts, rebalancer)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRouter(&_LockReleaseTokenPool.TransactOpts, newRouter)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.SetRouter(&_LockReleaseTokenPool.TransactOpts, newRouter)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.TransferOwnership(&_LockReleaseTokenPool.TransactOpts, to)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.TransferOwnership(&_LockReleaseTokenPool.TransactOpts, to)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactor) WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.contract.Transact(opts, "withdrawLiquidity", amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.WithdrawLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolTransactorSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPool.Contract.WithdrawLiquidity(&_LockReleaseTokenPool.TransactOpts, amount)
+}
+
+type LockReleaseTokenPoolAllowListAddIterator struct {
+ Event *LockReleaseTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAllowListAdd)
+ 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(LockReleaseTokenPoolAllowListAdd)
+ 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 *LockReleaseTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAllowListAddIterator{contract: _LockReleaseTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAllowListAdd)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*LockReleaseTokenPoolAllowListAdd, error) {
+ event := new(LockReleaseTokenPoolAllowListAdd)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAllowListRemoveIterator struct {
+ Event *LockReleaseTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAllowListRemove)
+ 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(LockReleaseTokenPoolAllowListRemove)
+ 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 *LockReleaseTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAllowListRemoveIterator{contract: _LockReleaseTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAllowListRemove)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*LockReleaseTokenPoolAllowListRemove, error) {
+ event := new(LockReleaseTokenPoolAllowListRemove)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolBurnedIterator struct {
+ Event *LockReleaseTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolBurned)
+ 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(LockReleaseTokenPoolBurned)
+ 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 *LockReleaseTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolBurnedIterator{contract: _LockReleaseTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolBurned)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Burned", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseBurned(log types.Log) (*LockReleaseTokenPoolBurned, error) {
+ event := new(LockReleaseTokenPoolBurned)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolChainAddedIterator struct {
+ Event *LockReleaseTokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolChainAdded)
+ 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(LockReleaseTokenPoolChainAdded)
+ 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 *LockReleaseTokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolChainAddedIterator{contract: _LockReleaseTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolChainAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseChainAdded(log types.Log) (*LockReleaseTokenPoolChainAdded, error) {
+ event := new(LockReleaseTokenPoolChainAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolChainConfiguredIterator struct {
+ Event *LockReleaseTokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolChainConfigured)
+ 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(LockReleaseTokenPoolChainConfigured)
+ 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 *LockReleaseTokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolChainConfiguredIterator{contract: _LockReleaseTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolChainConfigured)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseChainConfigured(log types.Log) (*LockReleaseTokenPoolChainConfigured, error) {
+ event := new(LockReleaseTokenPoolChainConfigured)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolChainRemovedIterator struct {
+ Event *LockReleaseTokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolChainRemoved)
+ 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(LockReleaseTokenPoolChainRemoved)
+ 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 *LockReleaseTokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolChainRemovedIterator{contract: _LockReleaseTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolChainRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseChainRemoved(log types.Log) (*LockReleaseTokenPoolChainRemoved, error) {
+ event := new(LockReleaseTokenPoolChainRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLiquidityAddedIterator struct {
+ Event *LockReleaseTokenPoolLiquidityAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLiquidityAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLiquidityAdded)
+ 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(LockReleaseTokenPoolLiquidityAdded)
+ 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 *LockReleaseTokenPoolLiquidityAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLiquidityAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLiquidityAdded struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityAddedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLiquidityAddedIterator{contract: _LockReleaseTokenPool.contract, event: "LiquidityAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLiquidityAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityAdded", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLiquidityAdded(log types.Log) (*LockReleaseTokenPoolLiquidityAdded, error) {
+ event := new(LockReleaseTokenPoolLiquidityAdded)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLiquidityRemovedIterator struct {
+ Event *LockReleaseTokenPoolLiquidityRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLiquidityRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLiquidityRemoved)
+ 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(LockReleaseTokenPoolLiquidityRemoved)
+ 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 *LockReleaseTokenPoolLiquidityRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLiquidityRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLiquidityRemoved struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityRemovedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLiquidityRemovedIterator{contract: _LockReleaseTokenPool.contract, event: "LiquidityRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLiquidityRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityRemoved", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLiquidityRemoved(log types.Log) (*LockReleaseTokenPoolLiquidityRemoved, error) {
+ event := new(LockReleaseTokenPoolLiquidityRemoved)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "LiquidityRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolLockedIterator struct {
+ Event *LockReleaseTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolLocked)
+ 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(LockReleaseTokenPoolLocked)
+ 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 *LockReleaseTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolLockedIterator{contract: _LockReleaseTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolLocked)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Locked", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseLocked(log types.Log) (*LockReleaseTokenPoolLocked, error) {
+ event := new(LockReleaseTokenPoolLocked)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolMintedIterator struct {
+ Event *LockReleaseTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolMinted)
+ 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(LockReleaseTokenPoolMinted)
+ 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 *LockReleaseTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolMintedIterator{contract: _LockReleaseTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolMinted)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Minted", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseMinted(log types.Log) (*LockReleaseTokenPoolMinted, error) {
+ event := new(LockReleaseTokenPoolMinted)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *LockReleaseTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOwnershipTransferRequested)
+ 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(LockReleaseTokenPoolOwnershipTransferRequested)
+ 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 *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOwnershipTransferRequestedIterator{contract: _LockReleaseTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOwnershipTransferRequested)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*LockReleaseTokenPoolOwnershipTransferRequested, error) {
+ event := new(LockReleaseTokenPoolOwnershipTransferRequested)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferredIterator struct {
+ Event *LockReleaseTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolOwnershipTransferred)
+ 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(LockReleaseTokenPoolOwnershipTransferred)
+ 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 *LockReleaseTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolOwnershipTransferredIterator{contract: _LockReleaseTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolOwnershipTransferred)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*LockReleaseTokenPoolOwnershipTransferred, error) {
+ event := new(LockReleaseTokenPoolOwnershipTransferred)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolReleasedIterator struct {
+ Event *LockReleaseTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolReleased)
+ 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(LockReleaseTokenPoolReleased)
+ 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 *LockReleaseTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolReleasedIterator{contract: _LockReleaseTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolReleased)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Released", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseReleased(log types.Log) (*LockReleaseTokenPoolReleased, error) {
+ event := new(LockReleaseTokenPoolReleased)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolRouterUpdatedIterator struct {
+ Event *LockReleaseTokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolRouterUpdated)
+ 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(LockReleaseTokenPoolRouterUpdated)
+ 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 *LockReleaseTokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*LockReleaseTokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolRouterUpdatedIterator{contract: _LockReleaseTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolRouterUpdated)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_LockReleaseTokenPool *LockReleaseTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*LockReleaseTokenPoolRouterUpdated, error) {
+ event := new(LockReleaseTokenPoolRouterUpdated)
+ if err := _LockReleaseTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _LockReleaseTokenPool.abi.Events["AllowListAdd"].ID:
+ return _LockReleaseTokenPool.ParseAllowListAdd(log)
+ case _LockReleaseTokenPool.abi.Events["AllowListRemove"].ID:
+ return _LockReleaseTokenPool.ParseAllowListRemove(log)
+ case _LockReleaseTokenPool.abi.Events["Burned"].ID:
+ return _LockReleaseTokenPool.ParseBurned(log)
+ case _LockReleaseTokenPool.abi.Events["ChainAdded"].ID:
+ return _LockReleaseTokenPool.ParseChainAdded(log)
+ case _LockReleaseTokenPool.abi.Events["ChainConfigured"].ID:
+ return _LockReleaseTokenPool.ParseChainConfigured(log)
+ case _LockReleaseTokenPool.abi.Events["ChainRemoved"].ID:
+ return _LockReleaseTokenPool.ParseChainRemoved(log)
+ case _LockReleaseTokenPool.abi.Events["LiquidityAdded"].ID:
+ return _LockReleaseTokenPool.ParseLiquidityAdded(log)
+ case _LockReleaseTokenPool.abi.Events["LiquidityRemoved"].ID:
+ return _LockReleaseTokenPool.ParseLiquidityRemoved(log)
+ case _LockReleaseTokenPool.abi.Events["Locked"].ID:
+ return _LockReleaseTokenPool.ParseLocked(log)
+ case _LockReleaseTokenPool.abi.Events["Minted"].ID:
+ return _LockReleaseTokenPool.ParseMinted(log)
+ case _LockReleaseTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _LockReleaseTokenPool.ParseOwnershipTransferRequested(log)
+ case _LockReleaseTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _LockReleaseTokenPool.ParseOwnershipTransferred(log)
+ case _LockReleaseTokenPool.abi.Events["Released"].ID:
+ return _LockReleaseTokenPool.ParseReleased(log)
+ case _LockReleaseTokenPool.abi.Events["RouterUpdated"].ID:
+ return _LockReleaseTokenPool.ParseRouterUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (LockReleaseTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (LockReleaseTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (LockReleaseTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (LockReleaseTokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x0f135cbb9afa12a8bf3bbd071c117bcca4ddeca6160ef7f33d012a81b9c0c471")
+}
+
+func (LockReleaseTokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (LockReleaseTokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (LockReleaseTokenPoolLiquidityAdded) Topic() common.Hash {
+ return common.HexToHash("0xc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb312088")
+}
+
+func (LockReleaseTokenPoolLiquidityRemoved) Topic() common.Hash {
+ return common.HexToHash("0xc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf9840171719")
+}
+
+func (LockReleaseTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (LockReleaseTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (LockReleaseTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (LockReleaseTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (LockReleaseTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (LockReleaseTokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (_LockReleaseTokenPool *LockReleaseTokenPool) Address() common.Address {
+ return _LockReleaseTokenPool.address
+}
+
+type LockReleaseTokenPoolInterface interface {
+ CanAcceptLiquidity(opts *bind.CallOpts) (bool, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetArmProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetLockReleaseInterfaceId(opts *bind.CallOpts) ([4]byte, error)
+
+ GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetRebalancer(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, arg1 []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error)
+
+ ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error)
+
+ SetRebalancer(opts *bind.TransactOpts, rebalancer common.Address) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*LockReleaseTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*LockReleaseTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*LockReleaseTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*LockReleaseTokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*LockReleaseTokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*LockReleaseTokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*LockReleaseTokenPoolChainRemoved, error)
+
+ FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityAddedIterator, error)
+
+ WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityAdded(log types.Log) (*LockReleaseTokenPoolLiquidityAdded, error)
+
+ FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolLiquidityRemovedIterator, error)
+
+ WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityRemoved(log types.Log) (*LockReleaseTokenPoolLiquidityRemoved, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*LockReleaseTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*LockReleaseTokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*LockReleaseTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*LockReleaseTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*LockReleaseTokenPoolReleased, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*LockReleaseTokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*LockReleaseTokenPoolRouterUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/lock_release_token_pool_and_proxy/lock_release_token_pool_and_proxy.go b/core/gethwrappers/ccip/generated/lock_release_token_pool_and_proxy/lock_release_token_pool_and_proxy.go
new file mode 100644
index 00000000000..15dd411741d
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/lock_release_token_pool_and_proxy/lock_release_token_pool_and_proxy.go
@@ -0,0 +1,3396 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package lock_release_token_pool_and_proxy
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type PoolLockOrBurnInV1 struct {
+ Receiver []byte
+ RemoteChainSelector uint64
+ OriginalSender common.Address
+ Amount *big.Int
+ LocalToken common.Address
+}
+
+type PoolLockOrBurnOutV1 struct {
+ DestTokenAddress []byte
+ DestPoolData []byte
+}
+
+type PoolReleaseOrMintInV1 struct {
+ OriginalSender []byte
+ RemoteChainSelector uint64
+ Receiver common.Address
+ Amount *big.Int
+ LocalToken common.Address
+ SourcePoolAddress []byte
+ SourcePoolData []byte
+ OffchainTokenData []byte
+}
+
+type PoolReleaseOrMintOutV1 struct {
+ DestinationAmount *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ RemotePoolAddress []byte
+ RemoteTokenAddress []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var LockReleaseTokenPoolAndProxyMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"acceptLiquidity\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLiquidity\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRateLimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidSourcePoolAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"LiquidityNotAccepted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remoteToken\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"contractIPoolPriorTo1_5\",\"name\":\"oldPool\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"contractIPoolPriorTo1_5\",\"name\":\"newPool\",\"type\":\"address\"}],\"name\":\"LegacyPoolChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousPoolAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"RemotePoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"remoteTokenAddress\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"canAcceptLiquidity\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"getOnRamp\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"onRampAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRateLimitAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRebalancer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemotePool\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemoteToken\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRmnProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"isOffRamp\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"isSupportedToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structPool.LockOrBurnInV1\",\"name\":\"lockOrBurnIn\",\"type\":\"tuple\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destPoolData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.LockOrBurnOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"provideLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainTokenData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.ReleaseOrMintInV1\",\"name\":\"releaseOrMintIn\",\"type\":\"tuple\"}],\"name\":\"releaseOrMint\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destinationAmount\",\"type\":\"uint256\"}],\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIPoolPriorTo1_5\",\"name\":\"prevPool\",\"type\":\"address\"}],\"name\":\"setPreviousPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"rateLimitAdmin\",\"type\":\"address\"}],\"name\":\"setRateLimitAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"rebalancer\",\"type\":\"address\"}],\"name\":\"setRebalancer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"setRemotePool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6101006040523480156200001257600080fd5b5060405162004e1b38038062004e1b83398101604081905262000035916200056d565b84848483838383833380600081620000945760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c757620000c78162000186565b5050506001600160a01b0384161580620000e857506001600160a01b038116155b80620000fb57506001600160a01b038216155b156200011a576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c0526200016d576040805160008152602081019091526200016d908462000231565b5050505094151560e05250620006de9650505050505050565b336001600160a01b03821603620001e05760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008b565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c05162000252576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620002dd57600083828151811062000276576200027662000690565b60209081029190910101519050620002906002826200038e565b15620002d3576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b5060010162000255565b5060005b81518110156200038957600082828151811062000302576200030262000690565b6020026020010151905060006001600160a01b0316816001600160a01b0316036200032e575062000380565b6200033b600282620003ae565b156200037e576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101620002e1565b505050565b6000620003a5836001600160a01b038416620003c5565b90505b92915050565b6000620003a5836001600160a01b038416620004c9565b60008181526001830160205260408120548015620004be576000620003ec600183620006a6565b85549091506000906200040290600190620006a6565b90508181146200046e57600086600001828154811062000426576200042662000690565b90600052602060002001549050808760000184815481106200044c576200044c62000690565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620004825762000482620006c8565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050620003a8565b6000915050620003a8565b60008181526001830160205260408120546200051257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620003a8565b506000620003a8565b6001600160a01b03811681146200053157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b805162000557816200051b565b919050565b805180151581146200055757600080fd5b600080600080600060a086880312156200058657600080fd5b855162000593816200051b565b602087810151919650906001600160401b0380821115620005b357600080fd5b818901915089601f830112620005c857600080fd5b815181811115620005dd57620005dd62000534565b8060051b604051601f19603f8301168101818110858211171562000605576200060562000534565b60405291825284820192508381018501918c8311156200062457600080fd5b938501935b828510156200064d576200063d856200054a565b8452938501939285019262000629565b80995050505050505062000664604087016200054a565b925062000674606087016200055c565b915062000684608087016200054a565b90509295509295909350565b634e487b7160e01b600052603260045260246000fd5b81810381811115620003a857634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05160e05161469a620007816000396000818161051701526118510152600081816105c401528181611e860152612a4201526000818161059e01528181611c1e0152612139015260008181610292015281816102e7015281816107a2015281816108740152818161093e0152818161191301528181611b3e015281816120590152818161223f015281816129d80152612c2d015261469a6000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c80639766b9321161012a578063c0d78655116100bd578063db6327dc1161008c578063e0351e1311610071578063e0351e13146105c2578063eb521a4c146105e8578063f2fde38b146105fb57600080fd5b8063db6327dc14610589578063dc0bd9711461059c57600080fd5b8063c0d786551461053b578063c4bffe2b1461054e578063c75eea9c14610563578063cf7401f31461057657600080fd5b8063af58d59f116100f9578063af58d59f14610475578063b0f479a1146104e4578063b794658014610502578063bb98546b1461051557600080fd5b80639766b9321461041a5780639a4575b91461042d578063a7cd63b71461044d578063a8d87a3b1461046257600080fd5b806354c8a4f3116101bd57806379ba50971161018c57806383826b2b1161017157806383826b2b146103d65780638926f54f146103e95780638da5cb5b146103fc57600080fd5b806379ba5097146103bb5780637d54534e146103c357600080fd5b806354c8a4f3146103645780636cfd1553146103775780636d3d1a581461038a57806378a010b2146103a857600080fd5b806321df0da7116101f957806321df0da714610290578063240028e8146102d75780633907753714610324578063432a6ba31461034657600080fd5b806301ffc9a71461022b5780630a2fd493146102535780630a861f2a14610273578063181f5a7714610288575b600080fd5b61023e6102393660046135d7565b61060e565b60405190151581526020015b60405180910390f35b610266610261366004613636565b61066a565b60405161024a91906136bf565b6102866102813660046136d2565b61071a565b005b6102666108cb565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161024a565b61023e6102e5366004613718565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b610337610332366004613735565b6108e7565b6040519051815260200161024a565b60095473ffffffffffffffffffffffffffffffffffffffff166102b2565b6102866103723660046137bd565b610a10565b610286610385366004613718565b610a8b565b600a5473ffffffffffffffffffffffffffffffffffffffff166102b2565b6102866103b6366004613829565b610ada565b610286610c49565b6102866103d1366004613718565b610d46565b61023e6103e43660046138ac565b610d95565b61023e6103f7366004613636565b610e62565b60005473ffffffffffffffffffffffffffffffffffffffff166102b2565b610286610428366004613718565b610e79565b61044061043b3660046138e3565b610f08565b60405161024a919061391e565b610455610fd1565b60405161024a919061397e565b6102b2610470366004613636565b503090565b610488610483366004613636565b610fe2565b60405161024a919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff166102b2565b610266610510366004613636565b6110b7565b7f000000000000000000000000000000000000000000000000000000000000000061023e565b610286610549366004613718565b6110e2565b6105566111b6565b60405161024a91906139d8565b610488610571366004613636565b61126e565b610286610584366004613b8f565b611340565b610286610597366004613bd4565b6113c9565b7f00000000000000000000000000000000000000000000000000000000000000006102b2565b7f000000000000000000000000000000000000000000000000000000000000000061023e565b6102866105f63660046136d2565b61184f565b610286610609366004613718565b61196b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fe1d4056600000000000000000000000000000000000000000000000000000000148061066457506106648261197f565b92915050565b67ffffffffffffffff8116600090815260076020526040902060040180546060919061069590613c16565b80601f01602080910402602001604051908101604052809291908181526020018280546106c190613c16565b801561070e5780601f106106e35761010080835404028352916020019161070e565b820191906000526020600020905b8154815290600101906020018083116106f157829003601f168201915b50505050509050919050565b60095473ffffffffffffffffffffffffffffffffffffffff163314610772576040517f8e4a23d60000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156107fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108229190613c69565b101561085a576040517fbb55fd2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61089b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163383611a63565b604051819033907fc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf984017171990600090a350565b6040518060600160405280602681526020016146686026913981565b60408051602081019091526000815261090761090283613d1e565b611b37565b60085473ffffffffffffffffffffffffffffffffffffffff1661096e5761096973ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016336060850135611a63565b61097f565b61097f61097a83613d1e565b611d68565b61098f6060830160408401613718565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f5284606001356040516109f191815260200190565b60405180910390a3506040805160208101909152606090910135815290565b610a18611e01565b610a8584848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250611e8492505050565b50505050565b610a93611e01565b600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610ae2611e01565b610aeb83610e62565b610b2d576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401610769565b67ffffffffffffffff831660009081526007602052604081206004018054610b5490613c16565b80601f0160208091040260200160405190810160405280929190818152602001828054610b8090613c16565b8015610bcd5780601f10610ba257610100808354040283529160200191610bcd565b820191906000526020600020905b815481529060010190602001808311610bb057829003601f168201915b5050505067ffffffffffffffff8616600090815260076020526040902091925050600401610bfc838583613e63565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf828585604051610c3b93929190613f7d565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610cca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610769565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610d4e611e01565b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600073ffffffffffffffffffffffffffffffffffffffff8216301480610e5b5750600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff86169281019290925273ffffffffffffffffffffffffffffffffffffffff848116602484015216906383826b2b90604401602060405180830381865afa158015610e37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5b9190613fe1565b9392505050565b6000610664600567ffffffffffffffff841661203a565b610e81611e01565b6008805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f81accd0a7023865eaa51b3399dd0eafc488bf3ba238402911e1659cfe860f22891015b60405180910390a15050565b6040805180820190915260608082526020820152610f2d610f2883613ffe565b612052565b60085473ffffffffffffffffffffffffffffffffffffffff1615610f5c57610f5c610f5783613ffe565b61221c565b6040516060830135815233907f9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd600089060200160405180910390a26040518060400160405280610fb68460200160208101906105109190613636565b81526040805160208181019092526000815291015292915050565b6060610fdd6002612336565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600390910154808416606083015291909104909116608082015261066490612343565b67ffffffffffffffff8116600090815260076020526040902060050180546060919061069590613c16565b6110ea611e01565b73ffffffffffffffffffffffffffffffffffffffff8116611137576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f16849101610efc565b606060006111c46005612336565b90506000815167ffffffffffffffff8111156111e2576111e2613a1a565b60405190808252806020026020018201604052801561120b578160200160208202803683370190505b50905060005b82518110156112675782818151811061122c5761122c6140a0565b6020026020010151828281518110611246576112466140a0565b67ffffffffffffffff90921660209283029190910190910152600101611211565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff16151594820194909452600190910154808416606083015291909104909116608082015261066490612343565b600a5473ffffffffffffffffffffffffffffffffffffffff163314801590611380575060005473ffffffffffffffffffffffffffffffffffffffff163314155b156113b9576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610769565b6113c48383836123f5565b505050565b6113d1611e01565b60005b818110156113c45760008383838181106113f0576113f06140a0565b905060200281019061140291906140cf565b61140b9061410d565b905061142081608001518260200151156124df565b6114338160a001518260200151156124df565b80602001511561172f5780516114559060059067ffffffffffffffff16612618565b61149a5780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610769565b60408101515115806114af5750606081015151155b156114e6576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c179091169615150295909517909855908101519401519381169316909102919091176003820155915190919060048201906116c790826141c1565b50606082015160058201906116dc90826141c1565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2955061172294939291906142db565b60405180910390a1611846565b80516117479060059067ffffffffffffffff16612624565b61178c5780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610769565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906117f56004830182613589565b611803600583016000613589565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b506001016113d4565b7f00000000000000000000000000000000000000000000000000000000000000006118a6576040517fe93f8fa400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095473ffffffffffffffffffffffffffffffffffffffff1633146118f9576040517f8e4a23d6000000000000000000000000000000000000000000000000000000008152336004820152602401610769565b61193b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084612630565b604051819033907fc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb31208890600090a350565b611973611e01565b61197c8161268e565b50565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf000000000000000000000000000000000000000000000000000000001480611a1257507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b8061066457507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526113c49084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612783565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff908116911614611bcc5760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610769565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9e9190613fe1565b15611cd5576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ce2816020015161288f565b6000611cf1826020015161066a565b9050805160001480611d15575080805190602001208260a001518051906020012014155b15611d52578160a001516040517f24eb47e500000000000000000000000000000000000000000000000000000000815260040161076991906136bf565b611d64826020015183606001516129b5565b5050565b6008548151606083015160208401516040517f8627fad600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90941693638627fad693611dcc9390923392600401614374565b600060405180830381600087803b158015611de657600080fd5b505af1158015611dfa573d6000803e3d6000fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611e82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610769565b565b7f0000000000000000000000000000000000000000000000000000000000000000611edb576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015611f71576000838281518110611efb57611efb6140a0565b60200260200101519050611f198160026129fc90919063ffffffff16565b15611f685760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50600101611ede565b5060005b81518110156113c4576000828281518110611f9257611f926140a0565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611fd65750612032565b611fe1600282612a1e565b156120305760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101611f75565b60008181526001830160205260408120541515610e5b565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146120e75760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610769565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015612195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b99190613fe1565b156121f0576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121fd8160400151612a40565b61220a8160200151612abf565b61197c81602001518260600151612c0d565b60085460608201516122699173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811692911690611a63565b60085460408083015183516060850151602086015193517f9687544500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909516946396875445946122d1949392916004016143d5565b6000604051808303816000875af11580156122f0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611d649190810190614435565b60606000610e5b83612c51565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526123d182606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426123b591906144d2565b85608001516fffffffffffffffffffffffffffffffff16612cac565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6123fe83610e62565b612440576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401610769565b61244b8260006124df565b67ffffffffffffffff8316600090815260076020526040902061246e9083612cd6565b6124798160006124df565b67ffffffffffffffff8316600090815260076020526040902061249f9060020182612cd6565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b8383836040516124d2939291906144e5565b60405180910390a1505050565b8151156125a65781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580612535575060408201516fffffffffffffffffffffffffffffffff16155b1561256e57816040517f8020d1240000000000000000000000000000000000000000000000000000000081526004016107699190614568565b8015611d64576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff161515806125df575060208201516fffffffffffffffffffffffffffffffff1615155b15611d6457816040517fd68af9cc0000000000000000000000000000000000000000000000000000000081526004016107699190614568565b6000610e5b8383612e78565b6000610e5b8383612ec7565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610a859085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611ab5565b3373ffffffffffffffffffffffffffffffffffffffff82160361270d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610769565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006127e5826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612fba9092919063ffffffff16565b8051909150156113c457808060200190518101906128039190613fe1565b6113c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610769565b61289881610e62565b6128da576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610769565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015612959573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061297d9190613fe1565b61197c576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610769565b67ffffffffffffffff82166000908152600760205260409020611d6490600201827f0000000000000000000000000000000000000000000000000000000000000000612fc9565b6000610e5b8373ffffffffffffffffffffffffffffffffffffffff8416612ec7565b6000610e5b8373ffffffffffffffffffffffffffffffffffffffff8416612e78565b7f00000000000000000000000000000000000000000000000000000000000000001561197c57612a7160028261334c565b61197c576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610769565b612ac881610e62565b612b0a576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610769565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015612b83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ba791906145a4565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461197c576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610769565b67ffffffffffffffff82166000908152600760205260409020611d6490827f0000000000000000000000000000000000000000000000000000000000000000612fc9565b60608160000180548060200260200160405190810160405280929190818152602001828054801561070e57602002820191906000526020600020905b815481526020019060010190808311612c8d5750505050509050919050565b6000612ccb85612cbc84866145c1565b612cc690876145d8565b61337b565b90505b949350505050565b8154600090612cff90700100000000000000000000000000000000900463ffffffff16426144d2565b90508015612da15760018301548354612d47916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612cac565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612dc7916fffffffffffffffffffffffffffffffff908116911661337b565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19906124d2908490614568565b6000818152600183016020526040812054612ebf57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610664565b506000610664565b60008181526001830160205260408120548015612fb0576000612eeb6001836144d2565b8554909150600090612eff906001906144d2565b9050818114612f64576000866000018281548110612f1f57612f1f6140a0565b9060005260206000200154905080876000018481548110612f4257612f426140a0565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612f7557612f756145eb565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610664565b6000915050610664565b6060612cce8484600085613391565b825474010000000000000000000000000000000000000000900460ff161580612ff0575081155b15612ffa57505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061304090700100000000000000000000000000000000900463ffffffff16426144d2565b905080156131005781831115613082576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546130bc9083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612cac565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156131b75773ffffffffffffffffffffffffffffffffffffffff841661315f576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610769565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff85166044820152606401610769565b848310156132ca5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906131fb90826144d2565b613205878a6144d2565b61320f91906145d8565b613219919061461a565b905073ffffffffffffffffffffffffffffffffffffffff8616613272576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610769565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff87166044820152606401610769565b6132d485846144d2565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515610e5b565b600081831061338a5781610e5b565b5090919050565b606082471015613423576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610769565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161344c9190614655565b60006040518083038185875af1925050503d8060008114613489576040519150601f19603f3d011682016040523d82523d6000602084013e61348e565b606091505b509150915061349f878383876134aa565b979650505050505050565b606083156135405782516000036135395773ffffffffffffffffffffffffffffffffffffffff85163b613539576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610769565b5081612cce565b612cce83838151156135555781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161076991906136bf565b50805461359590613c16565b6000825580601f106135a5575050565b601f01602090049060005260206000209081019061197c91905b808211156135d357600081556001016135bf565b5090565b6000602082840312156135e957600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610e5b57600080fd5b803567ffffffffffffffff8116811461363157600080fd5b919050565b60006020828403121561364857600080fd5b610e5b82613619565b60005b8381101561366c578181015183820152602001613654565b50506000910152565b6000815180845261368d816020860160208601613651565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610e5b6020830184613675565b6000602082840312156136e457600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461197c57600080fd5b8035613631816136eb565b60006020828403121561372a57600080fd5b8135610e5b816136eb565b60006020828403121561374757600080fd5b813567ffffffffffffffff81111561375e57600080fd5b82016101008185031215610e5b57600080fd5b60008083601f84011261378357600080fd5b50813567ffffffffffffffff81111561379b57600080fd5b6020830191508360208260051b85010111156137b657600080fd5b9250929050565b600080600080604085870312156137d357600080fd5b843567ffffffffffffffff808211156137eb57600080fd5b6137f788838901613771565b9096509450602087013591508082111561381057600080fd5b5061381d87828801613771565b95989497509550505050565b60008060006040848603121561383e57600080fd5b61384784613619565b9250602084013567ffffffffffffffff8082111561386457600080fd5b818601915086601f83011261387857600080fd5b81358181111561388757600080fd5b87602082850101111561389957600080fd5b6020830194508093505050509250925092565b600080604083850312156138bf57600080fd5b6138c883613619565b915060208301356138d8816136eb565b809150509250929050565b6000602082840312156138f557600080fd5b813567ffffffffffffffff81111561390c57600080fd5b820160a08185031215610e5b57600080fd5b60208152600082516040602084015261393a6060840182613675565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160408501526139758282613675565b95945050505050565b6020808252825182820181905260009190848201906040850190845b818110156139cc57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161399a565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156139cc57835167ffffffffffffffff16835292840192918401916001016139f4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715613a6d57613a6d613a1a565b60405290565b60405160c0810167ffffffffffffffff81118282101715613a6d57613a6d613a1a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613add57613add613a1a565b604052919050565b801515811461197c57600080fd5b803561363181613ae5565b80356fffffffffffffffffffffffffffffffff8116811461363157600080fd5b600060608284031215613b3057600080fd5b6040516060810181811067ffffffffffffffff82111715613b5357613b53613a1a565b6040529050808235613b6481613ae5565b8152613b7260208401613afe565b6020820152613b8360408401613afe565b60408201525092915050565b600080600060e08486031215613ba457600080fd5b613bad84613619565b9250613bbc8560208601613b1e565b9150613bcb8560808601613b1e565b90509250925092565b60008060208385031215613be757600080fd5b823567ffffffffffffffff811115613bfe57600080fd5b613c0a85828601613771565b90969095509350505050565b600181811c90821680613c2a57607f821691505b602082108103613c63577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600060208284031215613c7b57600080fd5b5051919050565b600067ffffffffffffffff821115613c9c57613c9c613a1a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613cd957600080fd5b8135613cec613ce782613c82565b613a96565b818152846020838601011115613d0157600080fd5b816020850160208301376000918101602001919091529392505050565b60006101008236031215613d3157600080fd5b613d39613a49565b823567ffffffffffffffff80821115613d5157600080fd5b613d5d36838701613cc8565b8352613d6b60208601613619565b6020840152613d7c6040860161370d565b604084015260608501356060840152613d976080860161370d565b608084015260a0850135915080821115613db057600080fd5b613dbc36838701613cc8565b60a084015260c0850135915080821115613dd557600080fd5b613de136838701613cc8565b60c084015260e0850135915080821115613dfa57600080fd5b50613e0736828601613cc8565b60e08301525092915050565b601f8211156113c4576000816000526020600020601f850160051c81016020861015613e3c5750805b601f850160051c820191505b81811015613e5b57828155600101613e48565b505050505050565b67ffffffffffffffff831115613e7b57613e7b613a1a565b613e8f83613e898354613c16565b83613e13565b6000601f841160018114613ee15760008515613eab5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611dfa565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015613f305786850135825560209485019460019092019101613f10565b5086821015613f6b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b604081526000613f906040830186613675565b82810360208401528381528385602083013760006020858301015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116820101915050949350505050565b600060208284031215613ff357600080fd5b8151610e5b81613ae5565b600060a0823603121561401057600080fd5b60405160a0810167ffffffffffffffff828210818311171561403457614034613a1a565b81604052843591508082111561404957600080fd5b5061405636828601613cc8565b82525061406560208401613619565b60208201526040830135614078816136eb565b6040820152606083810135908201526080830135614095816136eb565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec183360301811261410357600080fd5b9190910192915050565b6000610140823603121561412057600080fd5b614128613a73565b61413183613619565b815261413f60208401613af3565b6020820152604083013567ffffffffffffffff8082111561415f57600080fd5b61416b36838701613cc8565b6040840152606085013591508082111561418457600080fd5b5061419136828601613cc8565b6060830152506141a43660808501613b1e565b60808201526141b63660e08501613b1e565b60a082015292915050565b815167ffffffffffffffff8111156141db576141db613a1a565b6141ef816141e98454613c16565b84613e13565b602080601f831160018114614242576000841561420c5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555613e5b565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561428f57888601518255948401946001909101908401614270565b50858210156142cb57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff871683528060208401526142ff81840187613675565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff908116606087015290870151166080850152915061433d9050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e0830152613975565b60a08152600061438760a0830187613675565b73ffffffffffffffffffffffffffffffffffffffff8616602084015284604084015267ffffffffffffffff841660608401528281036080840152600081526020810191505095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8516815260a06020820152600061440460a0830186613675565b60408301949094525067ffffffffffffffff9190911660608201528082036080909101526000815260200192915050565b60006020828403121561444757600080fd5b815167ffffffffffffffff81111561445e57600080fd5b8201601f8101841361446f57600080fd5b805161447d613ce782613c82565b81815285602083850101111561449257600080fd5b613975826020830160208601613651565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610664576106646144a3565b67ffffffffffffffff8416815260e0810161453160208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c0830152612cce565b6060810161066482848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b6000602082840312156145b657600080fd5b8151610e5b816136eb565b8082028115828204841417610664576106646144a3565b80820180821115610664576106646144a3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600082614650577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000825161410381846020870161365156fe4c6f636b52656c65617365546f6b656e506f6f6c416e6450726f787920312e352e302d646576a164736f6c6343000818000a",
+}
+
+var LockReleaseTokenPoolAndProxyABI = LockReleaseTokenPoolAndProxyMetaData.ABI
+
+var LockReleaseTokenPoolAndProxyBin = LockReleaseTokenPoolAndProxyMetaData.Bin
+
+func DeployLockReleaseTokenPoolAndProxy(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, allowlist []common.Address, rmnProxy common.Address, acceptLiquidity bool, router common.Address) (common.Address, *types.Transaction, *LockReleaseTokenPoolAndProxy, error) {
+ parsed, err := LockReleaseTokenPoolAndProxyMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(LockReleaseTokenPoolAndProxyBin), backend, token, allowlist, rmnProxy, acceptLiquidity, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &LockReleaseTokenPoolAndProxy{address: address, abi: *parsed, LockReleaseTokenPoolAndProxyCaller: LockReleaseTokenPoolAndProxyCaller{contract: contract}, LockReleaseTokenPoolAndProxyTransactor: LockReleaseTokenPoolAndProxyTransactor{contract: contract}, LockReleaseTokenPoolAndProxyFilterer: LockReleaseTokenPoolAndProxyFilterer{contract: contract}}, nil
+}
+
+type LockReleaseTokenPoolAndProxy struct {
+ address common.Address
+ abi abi.ABI
+ LockReleaseTokenPoolAndProxyCaller
+ LockReleaseTokenPoolAndProxyTransactor
+ LockReleaseTokenPoolAndProxyFilterer
+}
+
+type LockReleaseTokenPoolAndProxyCaller struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolAndProxyTransactor struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolAndProxyFilterer struct {
+ contract *bind.BoundContract
+}
+
+type LockReleaseTokenPoolAndProxySession struct {
+ Contract *LockReleaseTokenPoolAndProxy
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type LockReleaseTokenPoolAndProxyCallerSession struct {
+ Contract *LockReleaseTokenPoolAndProxyCaller
+ CallOpts bind.CallOpts
+}
+
+type LockReleaseTokenPoolAndProxyTransactorSession struct {
+ Contract *LockReleaseTokenPoolAndProxyTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type LockReleaseTokenPoolAndProxyRaw struct {
+ Contract *LockReleaseTokenPoolAndProxy
+}
+
+type LockReleaseTokenPoolAndProxyCallerRaw struct {
+ Contract *LockReleaseTokenPoolAndProxyCaller
+}
+
+type LockReleaseTokenPoolAndProxyTransactorRaw struct {
+ Contract *LockReleaseTokenPoolAndProxyTransactor
+}
+
+func NewLockReleaseTokenPoolAndProxy(address common.Address, backend bind.ContractBackend) (*LockReleaseTokenPoolAndProxy, error) {
+ abi, err := abi.JSON(strings.NewReader(LockReleaseTokenPoolAndProxyABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindLockReleaseTokenPoolAndProxy(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxy{address: address, abi: abi, LockReleaseTokenPoolAndProxyCaller: LockReleaseTokenPoolAndProxyCaller{contract: contract}, LockReleaseTokenPoolAndProxyTransactor: LockReleaseTokenPoolAndProxyTransactor{contract: contract}, LockReleaseTokenPoolAndProxyFilterer: LockReleaseTokenPoolAndProxyFilterer{contract: contract}}, nil
+}
+
+func NewLockReleaseTokenPoolAndProxyCaller(address common.Address, caller bind.ContractCaller) (*LockReleaseTokenPoolAndProxyCaller, error) {
+ contract, err := bindLockReleaseTokenPoolAndProxy(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyCaller{contract: contract}, nil
+}
+
+func NewLockReleaseTokenPoolAndProxyTransactor(address common.Address, transactor bind.ContractTransactor) (*LockReleaseTokenPoolAndProxyTransactor, error) {
+ contract, err := bindLockReleaseTokenPoolAndProxy(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyTransactor{contract: contract}, nil
+}
+
+func NewLockReleaseTokenPoolAndProxyFilterer(address common.Address, filterer bind.ContractFilterer) (*LockReleaseTokenPoolAndProxyFilterer, error) {
+ contract, err := bindLockReleaseTokenPoolAndProxy(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyFilterer{contract: contract}, nil
+}
+
+func bindLockReleaseTokenPoolAndProxy(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := LockReleaseTokenPoolAndProxyMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LockReleaseTokenPoolAndProxy.Contract.LockReleaseTokenPoolAndProxyCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.LockReleaseTokenPoolAndProxyTransactor.contract.Transfer(opts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.LockReleaseTokenPoolAndProxyTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LockReleaseTokenPoolAndProxy.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.contract.Transfer(opts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) CanAcceptLiquidity(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "canAcceptLiquidity")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) CanAcceptLiquidity() (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.CanAcceptLiquidity(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) CanAcceptLiquidity() (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.CanAcceptLiquidity(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetAllowList() ([]common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetAllowList(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetAllowList() ([]common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetAllowList(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetAllowListEnabled() (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetAllowListEnabled(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetAllowListEnabled() (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetAllowListEnabled(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetCurrentInboundRateLimiterState(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetCurrentInboundRateLimiterState(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetCurrentOutboundRateLimiterState(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetCurrentOutboundRateLimiterState(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetOnRamp(opts *bind.CallOpts, arg0 uint64) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getOnRamp", arg0)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetOnRamp(arg0 uint64) (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetOnRamp(&_LockReleaseTokenPoolAndProxy.CallOpts, arg0)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetOnRamp(arg0 uint64) (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetOnRamp(&_LockReleaseTokenPoolAndProxy.CallOpts, arg0)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getRateLimitAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetRateLimitAdmin() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRateLimitAdmin(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetRateLimitAdmin() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRateLimitAdmin(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetRebalancer(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getRebalancer")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetRebalancer() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRebalancer(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetRebalancer() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRebalancer(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getRemotePool", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRemotePool(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRemotePool(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRemoteToken(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRemoteToken(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getRmnProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetRmnProxy() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRmnProxy(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetRmnProxy() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRmnProxy(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetRouter() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRouter(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetRouter() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetRouter(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetSupportedChains() ([]uint64, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetSupportedChains(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetSupportedChains(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) GetToken() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetToken(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) GetToken() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.GetToken(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) IsOffRamp(opts *bind.CallOpts, sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "isOffRamp", sourceChainSelector, offRamp)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) IsOffRamp(sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.IsOffRamp(&_LockReleaseTokenPoolAndProxy.CallOpts, sourceChainSelector, offRamp)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) IsOffRamp(sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.IsOffRamp(&_LockReleaseTokenPoolAndProxy.CallOpts, sourceChainSelector, offRamp)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.IsSupportedChain(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.IsSupportedChain(&_LockReleaseTokenPoolAndProxy.CallOpts, remoteChainSelector)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "isSupportedToken", token)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) IsSupportedToken(token common.Address) (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.IsSupportedToken(&_LockReleaseTokenPoolAndProxy.CallOpts, token)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.IsSupportedToken(&_LockReleaseTokenPoolAndProxy.CallOpts, token)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) Owner() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.Owner(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) Owner() (common.Address, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.Owner(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SupportsInterface(&_LockReleaseTokenPoolAndProxy.CallOpts, interfaceId)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SupportsInterface(&_LockReleaseTokenPoolAndProxy.CallOpts, interfaceId)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _LockReleaseTokenPoolAndProxy.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) TypeAndVersion() (string, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.TypeAndVersion(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyCallerSession) TypeAndVersion() (string, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.TypeAndVersion(&_LockReleaseTokenPoolAndProxy.CallOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) AcceptOwnership() (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.AcceptOwnership(&_LockReleaseTokenPoolAndProxy.TransactOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.AcceptOwnership(&_LockReleaseTokenPoolAndProxy.TransactOpts)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.ApplyAllowListUpdates(&_LockReleaseTokenPoolAndProxy.TransactOpts, removes, adds)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.ApplyAllowListUpdates(&_LockReleaseTokenPoolAndProxy.TransactOpts, removes, adds)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.ApplyChainUpdates(&_LockReleaseTokenPoolAndProxy.TransactOpts, chains)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.ApplyChainUpdates(&_LockReleaseTokenPoolAndProxy.TransactOpts, chains)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "lockOrBurn", lockOrBurnIn)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.LockOrBurn(&_LockReleaseTokenPoolAndProxy.TransactOpts, lockOrBurnIn)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.LockOrBurn(&_LockReleaseTokenPoolAndProxy.TransactOpts, lockOrBurnIn)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "provideLiquidity", amount)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.ProvideLiquidity(&_LockReleaseTokenPoolAndProxy.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.ProvideLiquidity(&_LockReleaseTokenPoolAndProxy.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "releaseOrMint", releaseOrMintIn)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.ReleaseOrMint(&_LockReleaseTokenPoolAndProxy.TransactOpts, releaseOrMintIn)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.ReleaseOrMint(&_LockReleaseTokenPoolAndProxy.TransactOpts, releaseOrMintIn)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetChainRateLimiterConfig(&_LockReleaseTokenPoolAndProxy.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetChainRateLimiterConfig(&_LockReleaseTokenPoolAndProxy.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) SetPreviousPool(opts *bind.TransactOpts, prevPool common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "setPreviousPool", prevPool)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) SetPreviousPool(prevPool common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetPreviousPool(&_LockReleaseTokenPoolAndProxy.TransactOpts, prevPool)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) SetPreviousPool(prevPool common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetPreviousPool(&_LockReleaseTokenPoolAndProxy.TransactOpts, prevPool)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "setRateLimitAdmin", rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetRateLimitAdmin(&_LockReleaseTokenPoolAndProxy.TransactOpts, rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) SetRateLimitAdmin(rateLimitAdmin common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetRateLimitAdmin(&_LockReleaseTokenPoolAndProxy.TransactOpts, rateLimitAdmin)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) SetRebalancer(opts *bind.TransactOpts, rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "setRebalancer", rebalancer)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) SetRebalancer(rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetRebalancer(&_LockReleaseTokenPoolAndProxy.TransactOpts, rebalancer)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) SetRebalancer(rebalancer common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetRebalancer(&_LockReleaseTokenPoolAndProxy.TransactOpts, rebalancer)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "setRemotePool", remoteChainSelector, remotePoolAddress)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetRemotePool(&_LockReleaseTokenPoolAndProxy.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetRemotePool(&_LockReleaseTokenPoolAndProxy.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetRouter(&_LockReleaseTokenPoolAndProxy.TransactOpts, newRouter)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.SetRouter(&_LockReleaseTokenPoolAndProxy.TransactOpts, newRouter)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.TransferOwnership(&_LockReleaseTokenPoolAndProxy.TransactOpts, to)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.TransferOwnership(&_LockReleaseTokenPoolAndProxy.TransactOpts, to)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactor) WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.contract.Transact(opts, "withdrawLiquidity", amount)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxySession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.WithdrawLiquidity(&_LockReleaseTokenPoolAndProxy.TransactOpts, amount)
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyTransactorSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LockReleaseTokenPoolAndProxy.Contract.WithdrawLiquidity(&_LockReleaseTokenPoolAndProxy.TransactOpts, amount)
+}
+
+type LockReleaseTokenPoolAndProxyAllowListAddIterator struct {
+ Event *LockReleaseTokenPoolAndProxyAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyAllowListAdd)
+ 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(LockReleaseTokenPoolAndProxyAllowListAdd)
+ 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 *LockReleaseTokenPoolAndProxyAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyAllowListAddIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyAllowListAddIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyAllowListAdd)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "AllowListAdd", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseAllowListAdd(log types.Log) (*LockReleaseTokenPoolAndProxyAllowListAdd, error) {
+ event := new(LockReleaseTokenPoolAndProxyAllowListAdd)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyAllowListRemoveIterator struct {
+ Event *LockReleaseTokenPoolAndProxyAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyAllowListRemove)
+ 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(LockReleaseTokenPoolAndProxyAllowListRemove)
+ 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 *LockReleaseTokenPoolAndProxyAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyAllowListRemoveIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyAllowListRemoveIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyAllowListRemove)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "AllowListRemove", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseAllowListRemove(log types.Log) (*LockReleaseTokenPoolAndProxyAllowListRemove, error) {
+ event := new(LockReleaseTokenPoolAndProxyAllowListRemove)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyBurnedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyBurned)
+ 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(LockReleaseTokenPoolAndProxyBurned)
+ 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 *LockReleaseTokenPoolAndProxyBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolAndProxyBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyBurnedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyBurned)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "Burned", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseBurned(log types.Log) (*LockReleaseTokenPoolAndProxyBurned, error) {
+ event := new(LockReleaseTokenPoolAndProxyBurned)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyChainAddedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyChainAdded)
+ 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(LockReleaseTokenPoolAndProxyChainAdded)
+ 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 *LockReleaseTokenPoolAndProxyChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyChainAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterChainAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyChainAddedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyChainAddedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyChainAdded)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "ChainAdded", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseChainAdded(log types.Log) (*LockReleaseTokenPoolAndProxyChainAdded, error) {
+ event := new(LockReleaseTokenPoolAndProxyChainAdded)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyChainConfiguredIterator struct {
+ Event *LockReleaseTokenPoolAndProxyChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyChainConfigured)
+ 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(LockReleaseTokenPoolAndProxyChainConfigured)
+ 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 *LockReleaseTokenPoolAndProxyChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyChainConfiguredIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyChainConfiguredIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyChainConfigured)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "ChainConfigured", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseChainConfigured(log types.Log) (*LockReleaseTokenPoolAndProxyChainConfigured, error) {
+ event := new(LockReleaseTokenPoolAndProxyChainConfigured)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyChainRemovedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyChainRemoved)
+ 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(LockReleaseTokenPoolAndProxyChainRemoved)
+ 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 *LockReleaseTokenPoolAndProxyChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyChainRemovedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyChainRemovedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyChainRemoved)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "ChainRemoved", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseChainRemoved(log types.Log) (*LockReleaseTokenPoolAndProxyChainRemoved, error) {
+ event := new(LockReleaseTokenPoolAndProxyChainRemoved)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyConfigChangedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyConfigChanged)
+ 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(LockReleaseTokenPoolAndProxyConfigChanged)
+ 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 *LockReleaseTokenPoolAndProxyConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyConfigChangedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyConfigChangedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyConfigChanged)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "ConfigChanged", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseConfigChanged(log types.Log) (*LockReleaseTokenPoolAndProxyConfigChanged, error) {
+ event := new(LockReleaseTokenPoolAndProxyConfigChanged)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyLegacyPoolChangedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyLegacyPoolChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyLegacyPoolChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyLegacyPoolChanged)
+ 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(LockReleaseTokenPoolAndProxyLegacyPoolChanged)
+ 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 *LockReleaseTokenPoolAndProxyLegacyPoolChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyLegacyPoolChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyLegacyPoolChanged struct {
+ OldPool common.Address
+ NewPool common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterLegacyPoolChanged(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyLegacyPoolChangedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "LegacyPoolChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyLegacyPoolChangedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "LegacyPoolChanged", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchLegacyPoolChanged(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyLegacyPoolChanged) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "LegacyPoolChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyLegacyPoolChanged)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "LegacyPoolChanged", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseLegacyPoolChanged(log types.Log) (*LockReleaseTokenPoolAndProxyLegacyPoolChanged, error) {
+ event := new(LockReleaseTokenPoolAndProxyLegacyPoolChanged)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "LegacyPoolChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyLiquidityAddedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyLiquidityAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyLiquidityAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyLiquidityAdded)
+ 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(LockReleaseTokenPoolAndProxyLiquidityAdded)
+ 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 *LockReleaseTokenPoolAndProxyLiquidityAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyLiquidityAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyLiquidityAdded struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolAndProxyLiquidityAddedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyLiquidityAddedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "LiquidityAdded", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyLiquidityAdded)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "LiquidityAdded", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseLiquidityAdded(log types.Log) (*LockReleaseTokenPoolAndProxyLiquidityAdded, error) {
+ event := new(LockReleaseTokenPoolAndProxyLiquidityAdded)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "LiquidityAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyLiquidityRemovedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyLiquidityRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyLiquidityRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyLiquidityRemoved)
+ 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(LockReleaseTokenPoolAndProxyLiquidityRemoved)
+ 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 *LockReleaseTokenPoolAndProxyLiquidityRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyLiquidityRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyLiquidityRemoved struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolAndProxyLiquidityRemovedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyLiquidityRemovedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "LiquidityRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyLiquidityRemoved)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "LiquidityRemoved", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseLiquidityRemoved(log types.Log) (*LockReleaseTokenPoolAndProxyLiquidityRemoved, error) {
+ event := new(LockReleaseTokenPoolAndProxyLiquidityRemoved)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "LiquidityRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyLockedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyLocked)
+ 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(LockReleaseTokenPoolAndProxyLocked)
+ 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 *LockReleaseTokenPoolAndProxyLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolAndProxyLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyLockedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyLocked)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "Locked", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseLocked(log types.Log) (*LockReleaseTokenPoolAndProxyLocked, error) {
+ event := new(LockReleaseTokenPoolAndProxyLocked)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyMintedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyMinted)
+ 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(LockReleaseTokenPoolAndProxyMinted)
+ 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 *LockReleaseTokenPoolAndProxyMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolAndProxyMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyMintedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyMinted)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "Minted", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseMinted(log types.Log) (*LockReleaseTokenPoolAndProxyMinted, error) {
+ event := new(LockReleaseTokenPoolAndProxyMinted)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyOwnershipTransferRequestedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyOwnershipTransferRequested)
+ 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(LockReleaseTokenPoolAndProxyOwnershipTransferRequested)
+ 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 *LockReleaseTokenPoolAndProxyOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolAndProxyOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyOwnershipTransferRequestedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyOwnershipTransferRequested)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseOwnershipTransferRequested(log types.Log) (*LockReleaseTokenPoolAndProxyOwnershipTransferRequested, error) {
+ event := new(LockReleaseTokenPoolAndProxyOwnershipTransferRequested)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyOwnershipTransferredIterator struct {
+ Event *LockReleaseTokenPoolAndProxyOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyOwnershipTransferred)
+ 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(LockReleaseTokenPoolAndProxyOwnershipTransferred)
+ 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 *LockReleaseTokenPoolAndProxyOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolAndProxyOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyOwnershipTransferredIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyOwnershipTransferred)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "OwnershipTransferred", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseOwnershipTransferred(log types.Log) (*LockReleaseTokenPoolAndProxyOwnershipTransferred, error) {
+ event := new(LockReleaseTokenPoolAndProxyOwnershipTransferred)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyReleasedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyReleased)
+ 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(LockReleaseTokenPoolAndProxyReleased)
+ 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 *LockReleaseTokenPoolAndProxyReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolAndProxyReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyReleasedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyReleased)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "Released", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseReleased(log types.Log) (*LockReleaseTokenPoolAndProxyReleased, error) {
+ event := new(LockReleaseTokenPoolAndProxyReleased)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyRemotePoolSetIterator struct {
+ Event *LockReleaseTokenPoolAndProxyRemotePoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyRemotePoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyRemotePoolSet)
+ 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(LockReleaseTokenPoolAndProxyRemotePoolSet)
+ 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 *LockReleaseTokenPoolAndProxyRemotePoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyRemotePoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyRemotePoolSet struct {
+ RemoteChainSelector uint64
+ PreviousPoolAddress []byte
+ RemotePoolAddress []byte
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*LockReleaseTokenPoolAndProxyRemotePoolSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyRemotePoolSetIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "RemotePoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyRemotePoolSet)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "RemotePoolSet", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseRemotePoolSet(log types.Log) (*LockReleaseTokenPoolAndProxyRemotePoolSet, error) {
+ event := new(LockReleaseTokenPoolAndProxyRemotePoolSet)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "RemotePoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyRouterUpdatedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyRouterUpdated)
+ 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(LockReleaseTokenPoolAndProxyRouterUpdated)
+ 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 *LockReleaseTokenPoolAndProxyRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyRouterUpdatedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyRouterUpdatedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyRouterUpdated)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "RouterUpdated", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseRouterUpdated(log types.Log) (*LockReleaseTokenPoolAndProxyRouterUpdated, error) {
+ event := new(LockReleaseTokenPoolAndProxyRouterUpdated)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LockReleaseTokenPoolAndProxyTokensConsumedIterator struct {
+ Event *LockReleaseTokenPoolAndProxyTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LockReleaseTokenPoolAndProxyTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LockReleaseTokenPoolAndProxyTokensConsumed)
+ 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(LockReleaseTokenPoolAndProxyTokensConsumed)
+ 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 *LockReleaseTokenPoolAndProxyTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LockReleaseTokenPoolAndProxyTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LockReleaseTokenPoolAndProxyTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyTokensConsumedIterator, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &LockReleaseTokenPoolAndProxyTokensConsumedIterator{contract: _LockReleaseTokenPoolAndProxy.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _LockReleaseTokenPoolAndProxy.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LockReleaseTokenPoolAndProxyTokensConsumed)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "TokensConsumed", 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 (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxyFilterer) ParseTokensConsumed(log types.Log) (*LockReleaseTokenPoolAndProxyTokensConsumed, error) {
+ event := new(LockReleaseTokenPoolAndProxyTokensConsumed)
+ if err := _LockReleaseTokenPoolAndProxy.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxy) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _LockReleaseTokenPoolAndProxy.abi.Events["AllowListAdd"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseAllowListAdd(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["AllowListRemove"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseAllowListRemove(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["Burned"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseBurned(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["ChainAdded"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseChainAdded(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["ChainConfigured"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseChainConfigured(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["ChainRemoved"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseChainRemoved(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["ConfigChanged"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseConfigChanged(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["LegacyPoolChanged"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseLegacyPoolChanged(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["LiquidityAdded"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseLiquidityAdded(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["LiquidityRemoved"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseLiquidityRemoved(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["Locked"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseLocked(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["Minted"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseMinted(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["OwnershipTransferRequested"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseOwnershipTransferRequested(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["OwnershipTransferred"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseOwnershipTransferred(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["Released"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseReleased(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["RemotePoolSet"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseRemotePoolSet(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["RouterUpdated"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseRouterUpdated(log)
+ case _LockReleaseTokenPoolAndProxy.abi.Events["TokensConsumed"].ID:
+ return _LockReleaseTokenPoolAndProxy.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (LockReleaseTokenPoolAndProxyAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (LockReleaseTokenPoolAndProxyAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (LockReleaseTokenPoolAndProxyBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (LockReleaseTokenPoolAndProxyChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2")
+}
+
+func (LockReleaseTokenPoolAndProxyChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (LockReleaseTokenPoolAndProxyChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (LockReleaseTokenPoolAndProxyConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (LockReleaseTokenPoolAndProxyLegacyPoolChanged) Topic() common.Hash {
+ return common.HexToHash("0x81accd0a7023865eaa51b3399dd0eafc488bf3ba238402911e1659cfe860f228")
+}
+
+func (LockReleaseTokenPoolAndProxyLiquidityAdded) Topic() common.Hash {
+ return common.HexToHash("0xc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb312088")
+}
+
+func (LockReleaseTokenPoolAndProxyLiquidityRemoved) Topic() common.Hash {
+ return common.HexToHash("0xc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf9840171719")
+}
+
+func (LockReleaseTokenPoolAndProxyLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (LockReleaseTokenPoolAndProxyMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (LockReleaseTokenPoolAndProxyOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (LockReleaseTokenPoolAndProxyOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (LockReleaseTokenPoolAndProxyReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (LockReleaseTokenPoolAndProxyRemotePoolSet) Topic() common.Hash {
+ return common.HexToHash("0xdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf")
+}
+
+func (LockReleaseTokenPoolAndProxyRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (LockReleaseTokenPoolAndProxyTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_LockReleaseTokenPoolAndProxy *LockReleaseTokenPoolAndProxy) Address() common.Address {
+ return _LockReleaseTokenPoolAndProxy.address
+}
+
+type LockReleaseTokenPoolAndProxyInterface interface {
+ CanAcceptLiquidity(opts *bind.CallOpts) (bool, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetOnRamp(opts *bind.CallOpts, arg0 uint64) (common.Address, error)
+
+ GetRateLimitAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ GetRebalancer(opts *bind.CallOpts) (common.Address, error)
+
+ GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRmnProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsOffRamp(opts *bind.CallOpts, sourceChainSelector uint64, offRamp common.Address) (bool, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error)
+
+ ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetPreviousPool(opts *bind.TransactOpts, prevPool common.Address) (*types.Transaction, error)
+
+ SetRateLimitAdmin(opts *bind.TransactOpts, rateLimitAdmin common.Address) (*types.Transaction, error)
+
+ SetRebalancer(opts *bind.TransactOpts, rebalancer common.Address) (*types.Transaction, error)
+
+ SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*LockReleaseTokenPoolAndProxyAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*LockReleaseTokenPoolAndProxyAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolAndProxyBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*LockReleaseTokenPoolAndProxyBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*LockReleaseTokenPoolAndProxyChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*LockReleaseTokenPoolAndProxyChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*LockReleaseTokenPoolAndProxyChainRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*LockReleaseTokenPoolAndProxyConfigChanged, error)
+
+ FilterLegacyPoolChanged(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyLegacyPoolChangedIterator, error)
+
+ WatchLegacyPoolChanged(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyLegacyPoolChanged) (event.Subscription, error)
+
+ ParseLegacyPoolChanged(log types.Log) (*LockReleaseTokenPoolAndProxyLegacyPoolChanged, error)
+
+ FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolAndProxyLiquidityAddedIterator, error)
+
+ WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityAdded(log types.Log) (*LockReleaseTokenPoolAndProxyLiquidityAdded, error)
+
+ FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LockReleaseTokenPoolAndProxyLiquidityRemovedIterator, error)
+
+ WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityRemoved(log types.Log) (*LockReleaseTokenPoolAndProxyLiquidityRemoved, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*LockReleaseTokenPoolAndProxyLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*LockReleaseTokenPoolAndProxyLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolAndProxyMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*LockReleaseTokenPoolAndProxyMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolAndProxyOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*LockReleaseTokenPoolAndProxyOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LockReleaseTokenPoolAndProxyOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*LockReleaseTokenPoolAndProxyOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*LockReleaseTokenPoolAndProxyReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*LockReleaseTokenPoolAndProxyReleased, error)
+
+ FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*LockReleaseTokenPoolAndProxyRemotePoolSetIterator, error)
+
+ WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRemotePoolSet(log types.Log) (*LockReleaseTokenPoolAndProxyRemotePoolSet, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*LockReleaseTokenPoolAndProxyRouterUpdated, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*LockReleaseTokenPoolAndProxyTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *LockReleaseTokenPoolAndProxyTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*LockReleaseTokenPoolAndProxyTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go b/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go
new file mode 100644
index 00000000000..3b52e8c871b
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/maybe_revert_message_receiver/maybe_revert_message_receiver.go
@@ -0,0 +1,564 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package maybe_revert_message_receiver
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+var MaybeRevertMessageReceiverMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"toRevert\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"CustomError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReceiveRevert\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"MessageReceived\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ValueReceived\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ccipReceive\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_toRevert\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"setErr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"toRevert\",\"type\":\"bool\"}],\"name\":\"setRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
+ Bin: "0x608060405234801561001057600080fd5b506040516107e73803806107e783398101604081905261002f9161005d565b600080546001600160a81b0319163360ff60a01b191617600160a01b92151592909202919091179055610086565b60006020828403121561006f57600080fd5b8151801515811461007f57600080fd5b9392505050565b610752806100956000396000f3fe60806040526004361061005e5760003560e01c806377f5b0e61161004357806377f5b0e61461015857806385572ffb1461017a5780638fb5f1711461019a57600080fd5b806301ffc9a7146100f25780635100fc211461012657600080fd5b366100ed5760005474010000000000000000000000000000000000000000900460ff16156100b8576040517f3085b8db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040513481527fe12e3b7047ff60a2dd763cf536a43597e5ce7fe7aa7476345bd4cd079912bcef9060200160405180910390a1005b600080fd5b3480156100fe57600080fd5b5061011261010d366004610335565b6101ff565b604051901515815260200160405180910390f35b34801561013257600080fd5b506000546101129074010000000000000000000000000000000000000000900460ff1681565b34801561016457600080fd5b506101786101733660046103ad565b610298565b005b34801561018657600080fd5b5061017861019536600461047c565b6102a8565b3480156101a657600080fd5b506101786101b53660046104b7565b6000805491151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f85572ffb00000000000000000000000000000000000000000000000000000000148061029257507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b60016102a4828261057d565b5050565b60005474010000000000000000000000000000000000000000900460ff16156103095760016040517f5a4ff6710000000000000000000000000000000000000000000000000000000081526004016103009190610697565b60405180910390fd5b6040517fd82ce31e3523f6eeb2d24317b2b4133001e8472729657f663b68624c45f8f3e890600090a150565b60006020828403121561034757600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461037757600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156103bf57600080fd5b813567ffffffffffffffff808211156103d757600080fd5b818401915084601f8301126103eb57600080fd5b8135818111156103fd576103fd61037e565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104435761044361037e565b8160405282815287602084870101111561045c57600080fd5b826020860160208301376000928101602001929092525095945050505050565b60006020828403121561048e57600080fd5b813567ffffffffffffffff8111156104a557600080fd5b820160a0818503121561037757600080fd5b6000602082840312156104c957600080fd5b8135801515811461037757600080fd5b600181811c908216806104ed57607f821691505b602082108103610526577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610578576000816000526020600020601f850160051c810160208610156105555750805b601f850160051c820191505b8181101561057457828155600101610561565b5050505b505050565b815167ffffffffffffffff8111156105975761059761037e565b6105ab816105a584546104d9565b8461052c565b602080601f8311600181146105fe57600084156105c85750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610574565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561064b5788860151825594840194600190910190840161062c565b508582101561068757878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60006020808352600084546106ab816104d9565b80602087015260406001808416600081146106cd576001811461070757610737565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00851660408a0152604084151560051b8a01019550610737565b89600052602060002060005b8581101561072e5781548b8201860152908301908801610713565b8a016040019650505b50939897505050505050505056fea164736f6c6343000818000a",
+}
+
+var MaybeRevertMessageReceiverABI = MaybeRevertMessageReceiverMetaData.ABI
+
+var MaybeRevertMessageReceiverBin = MaybeRevertMessageReceiverMetaData.Bin
+
+func DeployMaybeRevertMessageReceiver(auth *bind.TransactOpts, backend bind.ContractBackend, toRevert bool) (common.Address, *types.Transaction, *MaybeRevertMessageReceiver, error) {
+ parsed, err := MaybeRevertMessageReceiverMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MaybeRevertMessageReceiverBin), backend, toRevert)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MaybeRevertMessageReceiver{address: address, abi: *parsed, MaybeRevertMessageReceiverCaller: MaybeRevertMessageReceiverCaller{contract: contract}, MaybeRevertMessageReceiverTransactor: MaybeRevertMessageReceiverTransactor{contract: contract}, MaybeRevertMessageReceiverFilterer: MaybeRevertMessageReceiverFilterer{contract: contract}}, nil
+}
+
+type MaybeRevertMessageReceiver struct {
+ address common.Address
+ abi abi.ABI
+ MaybeRevertMessageReceiverCaller
+ MaybeRevertMessageReceiverTransactor
+ MaybeRevertMessageReceiverFilterer
+}
+
+type MaybeRevertMessageReceiverCaller struct {
+ contract *bind.BoundContract
+}
+
+type MaybeRevertMessageReceiverTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MaybeRevertMessageReceiverFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MaybeRevertMessageReceiverSession struct {
+ Contract *MaybeRevertMessageReceiver
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MaybeRevertMessageReceiverCallerSession struct {
+ Contract *MaybeRevertMessageReceiverCaller
+ CallOpts bind.CallOpts
+}
+
+type MaybeRevertMessageReceiverTransactorSession struct {
+ Contract *MaybeRevertMessageReceiverTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MaybeRevertMessageReceiverRaw struct {
+ Contract *MaybeRevertMessageReceiver
+}
+
+type MaybeRevertMessageReceiverCallerRaw struct {
+ Contract *MaybeRevertMessageReceiverCaller
+}
+
+type MaybeRevertMessageReceiverTransactorRaw struct {
+ Contract *MaybeRevertMessageReceiverTransactor
+}
+
+func NewMaybeRevertMessageReceiver(address common.Address, backend bind.ContractBackend) (*MaybeRevertMessageReceiver, error) {
+ abi, err := abi.JSON(strings.NewReader(MaybeRevertMessageReceiverABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMaybeRevertMessageReceiver(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MaybeRevertMessageReceiver{address: address, abi: abi, MaybeRevertMessageReceiverCaller: MaybeRevertMessageReceiverCaller{contract: contract}, MaybeRevertMessageReceiverTransactor: MaybeRevertMessageReceiverTransactor{contract: contract}, MaybeRevertMessageReceiverFilterer: MaybeRevertMessageReceiverFilterer{contract: contract}}, nil
+}
+
+func NewMaybeRevertMessageReceiverCaller(address common.Address, caller bind.ContractCaller) (*MaybeRevertMessageReceiverCaller, error) {
+ contract, err := bindMaybeRevertMessageReceiver(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MaybeRevertMessageReceiverCaller{contract: contract}, nil
+}
+
+func NewMaybeRevertMessageReceiverTransactor(address common.Address, transactor bind.ContractTransactor) (*MaybeRevertMessageReceiverTransactor, error) {
+ contract, err := bindMaybeRevertMessageReceiver(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MaybeRevertMessageReceiverTransactor{contract: contract}, nil
+}
+
+func NewMaybeRevertMessageReceiverFilterer(address common.Address, filterer bind.ContractFilterer) (*MaybeRevertMessageReceiverFilterer, error) {
+ contract, err := bindMaybeRevertMessageReceiver(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MaybeRevertMessageReceiverFilterer{contract: contract}, nil
+}
+
+func bindMaybeRevertMessageReceiver(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MaybeRevertMessageReceiverMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MaybeRevertMessageReceiver.Contract.MaybeRevertMessageReceiverCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.MaybeRevertMessageReceiverTransactor.contract.Transfer(opts)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.MaybeRevertMessageReceiverTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MaybeRevertMessageReceiver.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.contract.Transfer(opts)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCaller) SToRevert(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _MaybeRevertMessageReceiver.contract.Call(opts, &out, "s_toRevert")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) SToRevert() (bool, error) {
+ return _MaybeRevertMessageReceiver.Contract.SToRevert(&_MaybeRevertMessageReceiver.CallOpts)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCallerSession) SToRevert() (bool, error) {
+ return _MaybeRevertMessageReceiver.Contract.SToRevert(&_MaybeRevertMessageReceiver.CallOpts)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _MaybeRevertMessageReceiver.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _MaybeRevertMessageReceiver.Contract.SupportsInterface(&_MaybeRevertMessageReceiver.CallOpts, interfaceId)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _MaybeRevertMessageReceiver.Contract.SupportsInterface(&_MaybeRevertMessageReceiver.CallOpts, interfaceId)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) CcipReceive(opts *bind.TransactOpts, arg0 ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.contract.Transact(opts, "ccipReceive", arg0)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) CcipReceive(arg0 ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.CcipReceive(&_MaybeRevertMessageReceiver.TransactOpts, arg0)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) CcipReceive(arg0 ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.CcipReceive(&_MaybeRevertMessageReceiver.TransactOpts, arg0)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) SetErr(opts *bind.TransactOpts, err []byte) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.contract.Transact(opts, "setErr", err)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) SetErr(err []byte) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.SetErr(&_MaybeRevertMessageReceiver.TransactOpts, err)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) SetErr(err []byte) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.SetErr(&_MaybeRevertMessageReceiver.TransactOpts, err)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) SetRevert(opts *bind.TransactOpts, toRevert bool) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.contract.Transact(opts, "setRevert", toRevert)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) SetRevert(toRevert bool) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.SetRevert(&_MaybeRevertMessageReceiver.TransactOpts, toRevert)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) SetRevert(toRevert bool) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.SetRevert(&_MaybeRevertMessageReceiver.TransactOpts, toRevert)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.contract.RawTransact(opts, nil)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverSession) Receive() (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.Receive(&_MaybeRevertMessageReceiver.TransactOpts)
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverTransactorSession) Receive() (*types.Transaction, error) {
+ return _MaybeRevertMessageReceiver.Contract.Receive(&_MaybeRevertMessageReceiver.TransactOpts)
+}
+
+type MaybeRevertMessageReceiverMessageReceivedIterator struct {
+ Event *MaybeRevertMessageReceiverMessageReceived
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MaybeRevertMessageReceiverMessageReceivedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MaybeRevertMessageReceiverMessageReceived)
+ 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(MaybeRevertMessageReceiverMessageReceived)
+ 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 *MaybeRevertMessageReceiverMessageReceivedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MaybeRevertMessageReceiverMessageReceivedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MaybeRevertMessageReceiverMessageReceived struct {
+ Raw types.Log
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) FilterMessageReceived(opts *bind.FilterOpts) (*MaybeRevertMessageReceiverMessageReceivedIterator, error) {
+
+ logs, sub, err := _MaybeRevertMessageReceiver.contract.FilterLogs(opts, "MessageReceived")
+ if err != nil {
+ return nil, err
+ }
+ return &MaybeRevertMessageReceiverMessageReceivedIterator{contract: _MaybeRevertMessageReceiver.contract, event: "MessageReceived", logs: logs, sub: sub}, nil
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) WatchMessageReceived(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverMessageReceived) (event.Subscription, error) {
+
+ logs, sub, err := _MaybeRevertMessageReceiver.contract.WatchLogs(opts, "MessageReceived")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MaybeRevertMessageReceiverMessageReceived)
+ if err := _MaybeRevertMessageReceiver.contract.UnpackLog(event, "MessageReceived", 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 (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) ParseMessageReceived(log types.Log) (*MaybeRevertMessageReceiverMessageReceived, error) {
+ event := new(MaybeRevertMessageReceiverMessageReceived)
+ if err := _MaybeRevertMessageReceiver.contract.UnpackLog(event, "MessageReceived", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MaybeRevertMessageReceiverValueReceivedIterator struct {
+ Event *MaybeRevertMessageReceiverValueReceived
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MaybeRevertMessageReceiverValueReceivedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MaybeRevertMessageReceiverValueReceived)
+ 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(MaybeRevertMessageReceiverValueReceived)
+ 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 *MaybeRevertMessageReceiverValueReceivedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MaybeRevertMessageReceiverValueReceivedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MaybeRevertMessageReceiverValueReceived struct {
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) FilterValueReceived(opts *bind.FilterOpts) (*MaybeRevertMessageReceiverValueReceivedIterator, error) {
+
+ logs, sub, err := _MaybeRevertMessageReceiver.contract.FilterLogs(opts, "ValueReceived")
+ if err != nil {
+ return nil, err
+ }
+ return &MaybeRevertMessageReceiverValueReceivedIterator{contract: _MaybeRevertMessageReceiver.contract, event: "ValueReceived", logs: logs, sub: sub}, nil
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) WatchValueReceived(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverValueReceived) (event.Subscription, error) {
+
+ logs, sub, err := _MaybeRevertMessageReceiver.contract.WatchLogs(opts, "ValueReceived")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MaybeRevertMessageReceiverValueReceived)
+ if err := _MaybeRevertMessageReceiver.contract.UnpackLog(event, "ValueReceived", 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 (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiverFilterer) ParseValueReceived(log types.Log) (*MaybeRevertMessageReceiverValueReceived, error) {
+ event := new(MaybeRevertMessageReceiverValueReceived)
+ if err := _MaybeRevertMessageReceiver.contract.UnpackLog(event, "ValueReceived", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiver) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _MaybeRevertMessageReceiver.abi.Events["MessageReceived"].ID:
+ return _MaybeRevertMessageReceiver.ParseMessageReceived(log)
+ case _MaybeRevertMessageReceiver.abi.Events["ValueReceived"].ID:
+ return _MaybeRevertMessageReceiver.ParseValueReceived(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (MaybeRevertMessageReceiverMessageReceived) Topic() common.Hash {
+ return common.HexToHash("0xd82ce31e3523f6eeb2d24317b2b4133001e8472729657f663b68624c45f8f3e8")
+}
+
+func (MaybeRevertMessageReceiverValueReceived) Topic() common.Hash {
+ return common.HexToHash("0xe12e3b7047ff60a2dd763cf536a43597e5ce7fe7aa7476345bd4cd079912bcef")
+}
+
+func (_MaybeRevertMessageReceiver *MaybeRevertMessageReceiver) Address() common.Address {
+ return _MaybeRevertMessageReceiver.address
+}
+
+type MaybeRevertMessageReceiverInterface interface {
+ SToRevert(opts *bind.CallOpts) (bool, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ CcipReceive(opts *bind.TransactOpts, arg0 ClientAny2EVMMessage) (*types.Transaction, error)
+
+ SetErr(opts *bind.TransactOpts, err []byte) (*types.Transaction, error)
+
+ SetRevert(opts *bind.TransactOpts, toRevert bool) (*types.Transaction, error)
+
+ Receive(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterMessageReceived(opts *bind.FilterOpts) (*MaybeRevertMessageReceiverMessageReceivedIterator, error)
+
+ WatchMessageReceived(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverMessageReceived) (event.Subscription, error)
+
+ ParseMessageReceived(log types.Log) (*MaybeRevertMessageReceiverMessageReceived, error)
+
+ FilterValueReceived(opts *bind.FilterOpts) (*MaybeRevertMessageReceiverValueReceivedIterator, error)
+
+ WatchValueReceived(opts *bind.WatchOpts, sink chan<- *MaybeRevertMessageReceiverValueReceived) (event.Subscription, error)
+
+ ParseValueReceived(log types.Log) (*MaybeRevertMessageReceiverValueReceived, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/message_hasher/message_hasher.go b/core/gethwrappers/ccip/generated/message_hasher/message_hasher.go
new file mode 100644
index 00000000000..52434b50493
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/message_hasher/message_hasher.go
@@ -0,0 +1,427 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package message_hasher
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientEVMExtraArgsV1 struct {
+ GasLimit *big.Int
+}
+
+type ClientEVMExtraArgsV2 struct {
+ GasLimit *big.Int
+ AllowOutOfOrderExecution bool
+}
+
+type InternalAny2EVMRampMessage struct {
+ Header InternalRampMessageHeader
+ Sender []byte
+ Data []byte
+ Receiver common.Address
+ GasLimit *big.Int
+ TokenAmounts []InternalRampTokenAmount
+}
+
+type InternalRampMessageHeader struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ DestChainSelector uint64
+ SequenceNumber uint64
+ Nonce uint64
+}
+
+type InternalRampTokenAmount struct {
+ SourcePoolAddress []byte
+ DestTokenAddress []byte
+ ExtraData []byte
+ Amount *big.Int
+}
+
+var MessageHasherMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"decodeEVMExtraArgsV1\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMExtraArgsV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"allowOutOfOrderExecution\",\"type\":\"bool\"}],\"name\":\"decodeEVMExtraArgsV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"allowOutOfOrderExecution\",\"type\":\"bool\"}],\"internalType\":\"structClient.EVMExtraArgsV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMExtraArgsV1\",\"name\":\"extraArgs\",\"type\":\"tuple\"}],\"name\":\"encodeEVMExtraArgsV1\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"allowOutOfOrderExecution\",\"type\":\"bool\"}],\"internalType\":\"structClient.EVMExtraArgsV2\",\"name\":\"extraArgs\",\"type\":\"tuple\"}],\"name\":\"encodeEVMExtraArgsV2\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"leafDomainSeparator\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"implicitMetadataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"fixedSizeFieldsHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"tokenAmountsHash\",\"type\":\"bytes32\"}],\"name\":\"encodeFinalHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"name\":\"encodeFixedSizeFieldsHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"any2EVMMessageHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"name\":\"encodeMetadataHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"rampTokenAmounts\",\"type\":\"tuple[]\"}],\"name\":\"encodeTokenAmountsHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.Any2EVMRampMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"name\":\"hash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b50610de7806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063a91d3aeb11610076578063c63641bd1161005b578063c63641bd1461019e578063c7ca9a18146101f5578063e733d2091461020857600080fd5b8063a91d3aeb14610150578063b17df7141461016357600080fd5b8063902e94a0146100a85780639511afaa146100d157806399df8d05146100f2578063a1e747df1461013d575b600080fd5b6100bb6100b63660046107d9565b61021b565b6040516100c8919061087a565b60405180910390f35b6100e46100df366004610958565b610244565b6040519081526020016100c8565b6100bb610100366004610a62565b604080516020810196909652858101949094526060850192909252608084015260a0808401919091528151808403909101815260c0909201905290565b6100bb61014b366004610a9d565b610257565b6100bb61015e366004610b05565b610289565b61018f610171366004610b86565b60408051602080820183526000909152815190810190915290815290565b604051905181526020016100c8565b6101d86101ac366004610baf565b604080518082019091526000808252602082015250604080518082019091529182521515602082015290565b6040805182518152602092830151151592810192909252016100c8565b6100bb610203366004610bdb565b6102c1565b6100bb610216366004610c2f565b6102d2565b60608160405160200161022e9190610c71565b6040516020818303038152906040529050919050565b600061025083836102dd565b9392505050565b6060848484846040516020016102709493929190610d3d565b6040516020818303038152906040529050949350505050565b60608686868686866040516020016102a696959493929190610d7a565b60405160208183030381529060405290509695505050505050565b60606102cc8261043a565b92915050565b60606102cc826104fc565b815160208082015160409283015192516000938493610323937f2425b0b9f9054c76ff151b0a175b18f37a4a4e82013a72e9f15c9caa095ed21f93909291889101610d3d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052805160209182012086518051888401516060808b0151908401516080808d0151950151959761038a9794969395929491939101610d7a565b604051602081830303815290604052805190602001208560400151805190602001208660a001516040516020016103c19190610c71565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120908301969096528101939093526060830191909152608082015260a081019190915260c00160405160208183030381529060405280519060200120905092915050565b604051815160248201526020820151151560448201526060907f181dcf1000000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b604051815160248201526060907f97a657c90000000000000000000000000000000000000000000000000000000090604401610479565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff8111828210171561058557610585610533565b60405290565b60405160c0810167ffffffffffffffff8111828210171561058557610585610533565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156105f5576105f5610533565b604052919050565b600082601f83011261060e57600080fd5b813567ffffffffffffffff81111561062857610628610533565b61065960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016105ae565b81815284602083860101111561066e57600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261069c57600080fd5b8135602067ffffffffffffffff808311156106b9576106b9610533565b8260051b6106c88382016105ae565b93845285810183019383810190888611156106e257600080fd5b84880192505b858310156107cd578235848111156107005760008081fd5b88016080818b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018113156107365760008081fd5b61073e610562565b87830135878111156107505760008081fd5b61075e8d8a838701016105fd565b825250604080840135888111156107755760008081fd5b6107838e8b838801016105fd565b8a840152506060808501358981111561079c5760008081fd5b6107aa8f8c838901016105fd565b9284019290925293909201359281019290925250825291840191908401906106e8565b98975050505050505050565b6000602082840312156107eb57600080fd5b813567ffffffffffffffff81111561080257600080fd5b61080e8482850161068b565b949350505050565b6000815180845260005b8181101561083c57602081850181015186830182015201610820565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006102506020830184610816565b803567ffffffffffffffff811681146108a557600080fd5b919050565b600060a082840312156108bc57600080fd5b60405160a0810181811067ffffffffffffffff821117156108df576108df610533565b604052823581529050806108f56020840161088d565b60208201526109066040840161088d565b60408201526109176060840161088d565b60608201526109286080840161088d565b60808201525092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146108a557600080fd5b6000806040838503121561096b57600080fd5b823567ffffffffffffffff8082111561098357600080fd5b90840190610140828703121561099857600080fd5b6109a061058b565b6109aa87846108aa565b815260a0830135828111156109be57600080fd5b6109ca888286016105fd565b60208301525060c0830135828111156109e257600080fd5b6109ee888286016105fd565b604083015250610a0060e08401610934565b6060820152610100830135608082015261012083013582811115610a2357600080fd5b610a2f8882860161068b565b60a08301525093506020850135915080821115610a4b57600080fd5b50610a58858286016105fd565b9150509250929050565b600080600080600060a08688031215610a7a57600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60008060008060808587031215610ab357600080fd5b84359350610ac36020860161088d565b9250610ad16040860161088d565b9150606085013567ffffffffffffffff811115610aed57600080fd5b610af9878288016105fd565b91505092959194509250565b60008060008060008060c08789031215610b1e57600080fd5b86359550602087013567ffffffffffffffff811115610b3c57600080fd5b610b4889828a016105fd565b955050610b5760408801610934565b9350610b656060880161088d565b925060808701359150610b7a60a0880161088d565b90509295509295509295565b600060208284031215610b9857600080fd5b5035919050565b803580151581146108a557600080fd5b60008060408385031215610bc257600080fd5b82359150610bd260208401610b9f565b90509250929050565b600060408284031215610bed57600080fd5b6040516040810181811067ffffffffffffffff82111715610c1057610c10610533565b60405282358152610c2360208401610b9f565b60208201529392505050565b600060208284031215610c4157600080fd5b6040516020810181811067ffffffffffffffff82111715610c6457610c64610533565b6040529135825250919050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015610d2f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0898403018552815160808151818652610cde82870182610816565b915050888201518582038a870152610cf68282610816565b9150508782015185820389870152610d0e8282610816565b60609384015196909301959095525094870194925090860190600101610c9a565b509098975050505050505050565b848152600067ffffffffffffffff808616602084015280851660408401525060806060830152610d706080830184610816565b9695505050505050565b86815260c060208201526000610d9360c0830188610816565b73ffffffffffffffffffffffffffffffffffffffff9690961660408301525067ffffffffffffffff9384166060820152608081019290925290911660a0909101529291505056fea164736f6c6343000818000a",
+}
+
+var MessageHasherABI = MessageHasherMetaData.ABI
+
+var MessageHasherBin = MessageHasherMetaData.Bin
+
+func DeployMessageHasher(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MessageHasher, error) {
+ parsed, err := MessageHasherMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MessageHasherBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MessageHasher{address: address, abi: *parsed, MessageHasherCaller: MessageHasherCaller{contract: contract}, MessageHasherTransactor: MessageHasherTransactor{contract: contract}, MessageHasherFilterer: MessageHasherFilterer{contract: contract}}, nil
+}
+
+type MessageHasher struct {
+ address common.Address
+ abi abi.ABI
+ MessageHasherCaller
+ MessageHasherTransactor
+ MessageHasherFilterer
+}
+
+type MessageHasherCaller struct {
+ contract *bind.BoundContract
+}
+
+type MessageHasherTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MessageHasherFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MessageHasherSession struct {
+ Contract *MessageHasher
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MessageHasherCallerSession struct {
+ Contract *MessageHasherCaller
+ CallOpts bind.CallOpts
+}
+
+type MessageHasherTransactorSession struct {
+ Contract *MessageHasherTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MessageHasherRaw struct {
+ Contract *MessageHasher
+}
+
+type MessageHasherCallerRaw struct {
+ Contract *MessageHasherCaller
+}
+
+type MessageHasherTransactorRaw struct {
+ Contract *MessageHasherTransactor
+}
+
+func NewMessageHasher(address common.Address, backend bind.ContractBackend) (*MessageHasher, error) {
+ abi, err := abi.JSON(strings.NewReader(MessageHasherABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMessageHasher(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MessageHasher{address: address, abi: abi, MessageHasherCaller: MessageHasherCaller{contract: contract}, MessageHasherTransactor: MessageHasherTransactor{contract: contract}, MessageHasherFilterer: MessageHasherFilterer{contract: contract}}, nil
+}
+
+func NewMessageHasherCaller(address common.Address, caller bind.ContractCaller) (*MessageHasherCaller, error) {
+ contract, err := bindMessageHasher(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MessageHasherCaller{contract: contract}, nil
+}
+
+func NewMessageHasherTransactor(address common.Address, transactor bind.ContractTransactor) (*MessageHasherTransactor, error) {
+ contract, err := bindMessageHasher(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MessageHasherTransactor{contract: contract}, nil
+}
+
+func NewMessageHasherFilterer(address common.Address, filterer bind.ContractFilterer) (*MessageHasherFilterer, error) {
+ contract, err := bindMessageHasher(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MessageHasherFilterer{contract: contract}, nil
+}
+
+func bindMessageHasher(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MessageHasherMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MessageHasher *MessageHasherRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MessageHasher.Contract.MessageHasherCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MessageHasher *MessageHasherRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MessageHasher.Contract.MessageHasherTransactor.contract.Transfer(opts)
+}
+
+func (_MessageHasher *MessageHasherRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MessageHasher.Contract.MessageHasherTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MessageHasher *MessageHasherCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MessageHasher.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MessageHasher *MessageHasherTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MessageHasher.Contract.contract.Transfer(opts)
+}
+
+func (_MessageHasher *MessageHasherTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MessageHasher.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MessageHasher *MessageHasherCaller) DecodeEVMExtraArgsV1(opts *bind.CallOpts, gasLimit *big.Int) (ClientEVMExtraArgsV1, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "decodeEVMExtraArgsV1", gasLimit)
+
+ if err != nil {
+ return *new(ClientEVMExtraArgsV1), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(ClientEVMExtraArgsV1)).(*ClientEVMExtraArgsV1)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) DecodeEVMExtraArgsV1(gasLimit *big.Int) (ClientEVMExtraArgsV1, error) {
+ return _MessageHasher.Contract.DecodeEVMExtraArgsV1(&_MessageHasher.CallOpts, gasLimit)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) DecodeEVMExtraArgsV1(gasLimit *big.Int) (ClientEVMExtraArgsV1, error) {
+ return _MessageHasher.Contract.DecodeEVMExtraArgsV1(&_MessageHasher.CallOpts, gasLimit)
+}
+
+func (_MessageHasher *MessageHasherCaller) DecodeEVMExtraArgsV2(opts *bind.CallOpts, gasLimit *big.Int, allowOutOfOrderExecution bool) (ClientEVMExtraArgsV2, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "decodeEVMExtraArgsV2", gasLimit, allowOutOfOrderExecution)
+
+ if err != nil {
+ return *new(ClientEVMExtraArgsV2), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(ClientEVMExtraArgsV2)).(*ClientEVMExtraArgsV2)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) DecodeEVMExtraArgsV2(gasLimit *big.Int, allowOutOfOrderExecution bool) (ClientEVMExtraArgsV2, error) {
+ return _MessageHasher.Contract.DecodeEVMExtraArgsV2(&_MessageHasher.CallOpts, gasLimit, allowOutOfOrderExecution)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) DecodeEVMExtraArgsV2(gasLimit *big.Int, allowOutOfOrderExecution bool) (ClientEVMExtraArgsV2, error) {
+ return _MessageHasher.Contract.DecodeEVMExtraArgsV2(&_MessageHasher.CallOpts, gasLimit, allowOutOfOrderExecution)
+}
+
+func (_MessageHasher *MessageHasherCaller) EncodeEVMExtraArgsV1(opts *bind.CallOpts, extraArgs ClientEVMExtraArgsV1) ([]byte, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "encodeEVMExtraArgsV1", extraArgs)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) EncodeEVMExtraArgsV1(extraArgs ClientEVMExtraArgsV1) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeEVMExtraArgsV1(&_MessageHasher.CallOpts, extraArgs)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) EncodeEVMExtraArgsV1(extraArgs ClientEVMExtraArgsV1) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeEVMExtraArgsV1(&_MessageHasher.CallOpts, extraArgs)
+}
+
+func (_MessageHasher *MessageHasherCaller) EncodeEVMExtraArgsV2(opts *bind.CallOpts, extraArgs ClientEVMExtraArgsV2) ([]byte, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "encodeEVMExtraArgsV2", extraArgs)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) EncodeEVMExtraArgsV2(extraArgs ClientEVMExtraArgsV2) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeEVMExtraArgsV2(&_MessageHasher.CallOpts, extraArgs)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) EncodeEVMExtraArgsV2(extraArgs ClientEVMExtraArgsV2) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeEVMExtraArgsV2(&_MessageHasher.CallOpts, extraArgs)
+}
+
+func (_MessageHasher *MessageHasherCaller) EncodeFinalHashPreimage(opts *bind.CallOpts, leafDomainSeparator [32]byte, implicitMetadataHash [32]byte, fixedSizeFieldsHash [32]byte, dataHash [32]byte, tokenAmountsHash [32]byte) ([]byte, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "encodeFinalHashPreimage", leafDomainSeparator, implicitMetadataHash, fixedSizeFieldsHash, dataHash, tokenAmountsHash)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) EncodeFinalHashPreimage(leafDomainSeparator [32]byte, implicitMetadataHash [32]byte, fixedSizeFieldsHash [32]byte, dataHash [32]byte, tokenAmountsHash [32]byte) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeFinalHashPreimage(&_MessageHasher.CallOpts, leafDomainSeparator, implicitMetadataHash, fixedSizeFieldsHash, dataHash, tokenAmountsHash)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) EncodeFinalHashPreimage(leafDomainSeparator [32]byte, implicitMetadataHash [32]byte, fixedSizeFieldsHash [32]byte, dataHash [32]byte, tokenAmountsHash [32]byte) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeFinalHashPreimage(&_MessageHasher.CallOpts, leafDomainSeparator, implicitMetadataHash, fixedSizeFieldsHash, dataHash, tokenAmountsHash)
+}
+
+func (_MessageHasher *MessageHasherCaller) EncodeFixedSizeFieldsHashPreimage(opts *bind.CallOpts, messageId [32]byte, sender []byte, receiver common.Address, sequenceNumber uint64, gasLimit *big.Int, nonce uint64) ([]byte, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "encodeFixedSizeFieldsHashPreimage", messageId, sender, receiver, sequenceNumber, gasLimit, nonce)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) EncodeFixedSizeFieldsHashPreimage(messageId [32]byte, sender []byte, receiver common.Address, sequenceNumber uint64, gasLimit *big.Int, nonce uint64) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeFixedSizeFieldsHashPreimage(&_MessageHasher.CallOpts, messageId, sender, receiver, sequenceNumber, gasLimit, nonce)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) EncodeFixedSizeFieldsHashPreimage(messageId [32]byte, sender []byte, receiver common.Address, sequenceNumber uint64, gasLimit *big.Int, nonce uint64) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeFixedSizeFieldsHashPreimage(&_MessageHasher.CallOpts, messageId, sender, receiver, sequenceNumber, gasLimit, nonce)
+}
+
+func (_MessageHasher *MessageHasherCaller) EncodeMetadataHashPreimage(opts *bind.CallOpts, any2EVMMessageHash [32]byte, sourceChainSelector uint64, destChainSelector uint64, onRamp []byte) ([]byte, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "encodeMetadataHashPreimage", any2EVMMessageHash, sourceChainSelector, destChainSelector, onRamp)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) EncodeMetadataHashPreimage(any2EVMMessageHash [32]byte, sourceChainSelector uint64, destChainSelector uint64, onRamp []byte) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeMetadataHashPreimage(&_MessageHasher.CallOpts, any2EVMMessageHash, sourceChainSelector, destChainSelector, onRamp)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) EncodeMetadataHashPreimage(any2EVMMessageHash [32]byte, sourceChainSelector uint64, destChainSelector uint64, onRamp []byte) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeMetadataHashPreimage(&_MessageHasher.CallOpts, any2EVMMessageHash, sourceChainSelector, destChainSelector, onRamp)
+}
+
+func (_MessageHasher *MessageHasherCaller) EncodeTokenAmountsHashPreimage(opts *bind.CallOpts, rampTokenAmounts []InternalRampTokenAmount) ([]byte, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "encodeTokenAmountsHashPreimage", rampTokenAmounts)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) EncodeTokenAmountsHashPreimage(rampTokenAmounts []InternalRampTokenAmount) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeTokenAmountsHashPreimage(&_MessageHasher.CallOpts, rampTokenAmounts)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) EncodeTokenAmountsHashPreimage(rampTokenAmounts []InternalRampTokenAmount) ([]byte, error) {
+ return _MessageHasher.Contract.EncodeTokenAmountsHashPreimage(&_MessageHasher.CallOpts, rampTokenAmounts)
+}
+
+func (_MessageHasher *MessageHasherCaller) Hash(opts *bind.CallOpts, message InternalAny2EVMRampMessage, onRamp []byte) ([32]byte, error) {
+ var out []interface{}
+ err := _MessageHasher.contract.Call(opts, &out, "hash", message, onRamp)
+
+ if err != nil {
+ return *new([32]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
+
+ return out0, err
+
+}
+
+func (_MessageHasher *MessageHasherSession) Hash(message InternalAny2EVMRampMessage, onRamp []byte) ([32]byte, error) {
+ return _MessageHasher.Contract.Hash(&_MessageHasher.CallOpts, message, onRamp)
+}
+
+func (_MessageHasher *MessageHasherCallerSession) Hash(message InternalAny2EVMRampMessage, onRamp []byte) ([32]byte, error) {
+ return _MessageHasher.Contract.Hash(&_MessageHasher.CallOpts, message, onRamp)
+}
+
+func (_MessageHasher *MessageHasher) Address() common.Address {
+ return _MessageHasher.address
+}
+
+type MessageHasherInterface interface {
+ DecodeEVMExtraArgsV1(opts *bind.CallOpts, gasLimit *big.Int) (ClientEVMExtraArgsV1, error)
+
+ DecodeEVMExtraArgsV2(opts *bind.CallOpts, gasLimit *big.Int, allowOutOfOrderExecution bool) (ClientEVMExtraArgsV2, error)
+
+ EncodeEVMExtraArgsV1(opts *bind.CallOpts, extraArgs ClientEVMExtraArgsV1) ([]byte, error)
+
+ EncodeEVMExtraArgsV2(opts *bind.CallOpts, extraArgs ClientEVMExtraArgsV2) ([]byte, error)
+
+ EncodeFinalHashPreimage(opts *bind.CallOpts, leafDomainSeparator [32]byte, implicitMetadataHash [32]byte, fixedSizeFieldsHash [32]byte, dataHash [32]byte, tokenAmountsHash [32]byte) ([]byte, error)
+
+ EncodeFixedSizeFieldsHashPreimage(opts *bind.CallOpts, messageId [32]byte, sender []byte, receiver common.Address, sequenceNumber uint64, gasLimit *big.Int, nonce uint64) ([]byte, error)
+
+ EncodeMetadataHashPreimage(opts *bind.CallOpts, any2EVMMessageHash [32]byte, sourceChainSelector uint64, destChainSelector uint64, onRamp []byte) ([]byte, error)
+
+ EncodeTokenAmountsHashPreimage(opts *bind.CallOpts, rampTokenAmounts []InternalRampTokenAmount) ([]byte, error)
+
+ Hash(opts *bind.CallOpts, message InternalAny2EVMRampMessage, onRamp []byte) ([32]byte, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/mock_arm_contract/mock_arm_contract.go b/core/gethwrappers/ccip/generated/mock_arm_contract/mock_arm_contract.go
new file mode 100644
index 00000000000..fff63bef801
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/mock_arm_contract/mock_arm_contract.go
@@ -0,0 +1,746 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package mock_arm_contract
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type IRMNTaggedRoot struct {
+ CommitStore common.Address
+ Root [32]byte
+}
+
+type RMNConfig struct {
+ Voters []RMNVoter
+ BlessWeightThreshold uint16
+ CurseWeightThreshold uint16
+}
+
+type RMNUnvoteToCurseRecord struct {
+ CurseVoteAddr common.Address
+ CursesHash [32]byte
+ ForceUnvote bool
+}
+
+type RMNVoter struct {
+ BlessVoteAddr common.Address
+ CurseVoteAddr common.Address
+ CurseUnvoteAddr common.Address
+ BlessWeight uint8
+ CurseWeight uint8
+}
+
+var MockARMContractMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"CustomError\",\"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\":\"getConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"blessVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"curseUnvoteAddr\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"blessWeight\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"curseWeight\",\"type\":\"uint8\"}],\"internalType\":\"structRMN.Voter[]\",\"name\":\"voters\",\"type\":\"tuple[]\"},{\"internalType\":\"uint16\",\"name\":\"blessWeightThreshold\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"curseWeightThreshold\",\"type\":\"uint16\"}],\"internalType\":\"structRMN.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"cursesHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"forceUnvote\",\"type\":\"bool\"}],\"internalType\":\"structRMN.UnvoteToCurseRecord[]\",\"name\":\"\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"ownerUnvoteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"curseVoteAddr\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"cursesHash\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"forceUnvote\",\"type\":\"bool\"}],\"internalType\":\"structRMN.UnvoteToCurseRecord[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"ownerUnvoteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"}],\"name\":\"setRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"voteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"voteToCurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615610097576100978161009f565b505050610148565b336001600160a01b038216036100f75760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b610ed7806101576000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063618af128116100815780637a7c27491161005b5780637a7c2749146102b55780638da5cb5b146102c8578063f2fde38b146102f057600080fd5b8063618af1281461020a578063794860871461024357806379ba5097146102ad57600080fd5b8063397796f7116100b2578063397796f7146101ba5780633f42ab73146101c25780634d616771146101d957600080fd5b8063119a3527146100d9578063257174dc1461012b5780632cbc26bb14610192575b600080fd5b6101296100e73660046107fe565b50600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b005b6101296101393660046109db565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905550565b6101a56101a0366004610a29565b610303565b60405190151581526020015b60405180910390f35b6101a56103b7565b6101ca610424565b6040516101b193929190610a4b565b6101a56101e7366004610b1e565b5060015474010000000000000000000000000000000000000000900460ff161590565b610129610218366004610b36565b50600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b610129610251366004610b73565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016600090815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905550565b610129610565565b6101296102c3366004610b96565b610662565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b1565b6101296102fe366004610c49565b610672565b60006002805461031290610c64565b1590506103575760026040517f5a4ff67100000000000000000000000000000000000000000000000000000000815260040161034e9190610cb1565b60405180910390fd5b60015474010000000000000000000000000000000000000000900460ff16806103b157507fffffffffffffffffffffffffffffffff00000000000000000000000000000000821660009081526006602052604090205460ff165b92915050565b6000600280546103c690610c64565b1590506104025760026040517f5a4ff67100000000000000000000000000000000000000000000000000000000815260040161034e9190610cb1565b5060015474010000000000000000000000000000000000000000900460ff1690565b6040805160608082018352815260006020820181905291810182905281906005546040805160038054608060208202840181019094526060830181815263ffffffff8087169664010000000090041694929392849284929184919060009085015b828210156105315760008481526020908190206040805160a08101825260038602909201805473ffffffffffffffffffffffffffffffffffffffff90811684526001808301548216858701526002909201549081169284019290925260ff74010000000000000000000000000000000000000000830481166060850152750100000000000000000000000000000000000000000090920490911660808301529083529092019101610485565b505050908252506001919091015461ffff808216602084015262010000909104166040909101529296919550919350915050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161034e565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600261066e8282610db0565b5050565b61067a610686565b61068381610709565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610707576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161034e565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610788576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161034e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006020828403121561081057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561086957610869610817565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156108b6576108b6610817565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146108e257600080fd5b919050565b600082601f8301126108f857600080fd5b8135602067ffffffffffffffff82111561091457610914610817565b610922818360051b0161086f565b8281526060928302850182019282820191908785111561094157600080fd5b8387015b8581101561099e5781818a03121561095d5760008081fd5b610965610846565b61096e826108be565b81528582013586820152604080830135801515811461098d5760008081fd5b908201528452928401928101610945565b5090979650505050505050565b80357fffffffffffffffffffffffffffffffff00000000000000000000000000000000811681146108e257600080fd5b600080604083850312156109ee57600080fd5b823567ffffffffffffffff811115610a0557600080fd5b610a11858286016108e7565b925050610a20602084016109ab565b90509250929050565b600060208284031215610a3b57600080fd5b610a44826109ab565b9392505050565b63ffffffff84811682528316602080830191909152606060408084018290528451848301839052805160c0860181905260009491820190859060e08801905b80831015610af1578351805173ffffffffffffffffffffffffffffffffffffffff9081168452868201518116878501528782015116878401528781015160ff908116898501526080918201511690830152928401926001929092019160a090910190610a8a565b509288015161ffff908116608089015260409098015190971660a090960195909552979650505050505050565b600060408284031215610b3057600080fd5b50919050565b600060208284031215610b4857600080fd5b813567ffffffffffffffff811115610b5f57600080fd5b610b6b848285016108e7565b949350505050565b60008060408385031215610b8657600080fd5b82359150610a20602084016109ab565b60006020808385031215610ba957600080fd5b823567ffffffffffffffff80821115610bc157600080fd5b818501915085601f830112610bd557600080fd5b813581811115610be757610be7610817565b610c17847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161086f565b91508082528684828501011115610c2d57600080fd5b8084840185840137600090820190930192909252509392505050565b600060208284031215610c5b57600080fd5b610a44826108be565b600181811c90821680610c7857607f821691505b602082108103610b30577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000602080835260008454610cc581610c64565b8060208701526040600180841660008114610ce75760018114610d2157610d51565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00851660408a0152604084151560051b8a01019550610d51565b89600052602060002060005b85811015610d485781548b8201860152908301908801610d2d565b8a016040019650505b509398975050505050505050565b601f821115610dab576000816000526020600020601f850160051c81016020861015610d885750805b601f850160051c820191505b81811015610da757828155600101610d94565b5050505b505050565b815167ffffffffffffffff811115610dca57610dca610817565b610dde81610dd88454610c64565b84610d5f565b602080601f831160018114610e315760008415610dfb5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610da7565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015610e7e57888601518255948401946001909101908401610e5f565b5085821015610eba57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea164736f6c6343000818000a",
+}
+
+var MockARMContractABI = MockARMContractMetaData.ABI
+
+var MockARMContractBin = MockARMContractMetaData.Bin
+
+func DeployMockARMContract(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MockARMContract, error) {
+ parsed, err := MockARMContractMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MockARMContractBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MockARMContract{address: address, abi: *parsed, MockARMContractCaller: MockARMContractCaller{contract: contract}, MockARMContractTransactor: MockARMContractTransactor{contract: contract}, MockARMContractFilterer: MockARMContractFilterer{contract: contract}}, nil
+}
+
+type MockARMContract struct {
+ address common.Address
+ abi abi.ABI
+ MockARMContractCaller
+ MockARMContractTransactor
+ MockARMContractFilterer
+}
+
+type MockARMContractCaller struct {
+ contract *bind.BoundContract
+}
+
+type MockARMContractTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MockARMContractFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MockARMContractSession struct {
+ Contract *MockARMContract
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MockARMContractCallerSession struct {
+ Contract *MockARMContractCaller
+ CallOpts bind.CallOpts
+}
+
+type MockARMContractTransactorSession struct {
+ Contract *MockARMContractTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MockARMContractRaw struct {
+ Contract *MockARMContract
+}
+
+type MockARMContractCallerRaw struct {
+ Contract *MockARMContractCaller
+}
+
+type MockARMContractTransactorRaw struct {
+ Contract *MockARMContractTransactor
+}
+
+func NewMockARMContract(address common.Address, backend bind.ContractBackend) (*MockARMContract, error) {
+ abi, err := abi.JSON(strings.NewReader(MockARMContractABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMockARMContract(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MockARMContract{address: address, abi: abi, MockARMContractCaller: MockARMContractCaller{contract: contract}, MockARMContractTransactor: MockARMContractTransactor{contract: contract}, MockARMContractFilterer: MockARMContractFilterer{contract: contract}}, nil
+}
+
+func NewMockARMContractCaller(address common.Address, caller bind.ContractCaller) (*MockARMContractCaller, error) {
+ contract, err := bindMockARMContract(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockARMContractCaller{contract: contract}, nil
+}
+
+func NewMockARMContractTransactor(address common.Address, transactor bind.ContractTransactor) (*MockARMContractTransactor, error) {
+ contract, err := bindMockARMContract(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockARMContractTransactor{contract: contract}, nil
+}
+
+func NewMockARMContractFilterer(address common.Address, filterer bind.ContractFilterer) (*MockARMContractFilterer, error) {
+ contract, err := bindMockARMContract(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MockARMContractFilterer{contract: contract}, nil
+}
+
+func bindMockARMContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MockARMContractMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MockARMContract *MockARMContractRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockARMContract.Contract.MockARMContractCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MockARMContract *MockARMContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockARMContract.Contract.MockARMContractTransactor.contract.Transfer(opts)
+}
+
+func (_MockARMContract *MockARMContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockARMContract.Contract.MockARMContractTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MockARMContract *MockARMContractCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockARMContract.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MockARMContract *MockARMContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockARMContract.Contract.contract.Transfer(opts)
+}
+
+func (_MockARMContract *MockARMContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockARMContract.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MockARMContract *MockARMContractCaller) GetConfigDetails(opts *bind.CallOpts) (GetConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _MockARMContract.contract.Call(opts, &out, "getConfigDetails")
+
+ outstruct := new(GetConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.Version = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.Config = *abi.ConvertType(out[2], new(RMNConfig)).(*RMNConfig)
+
+ return *outstruct, err
+
+}
+
+func (_MockARMContract *MockARMContractSession) GetConfigDetails() (GetConfigDetails,
+
+ error) {
+ return _MockARMContract.Contract.GetConfigDetails(&_MockARMContract.CallOpts)
+}
+
+func (_MockARMContract *MockARMContractCallerSession) GetConfigDetails() (GetConfigDetails,
+
+ error) {
+ return _MockARMContract.Contract.GetConfigDetails(&_MockARMContract.CallOpts)
+}
+
+func (_MockARMContract *MockARMContractCaller) IsBlessed(opts *bind.CallOpts, arg0 IRMNTaggedRoot) (bool, error) {
+ var out []interface{}
+ err := _MockARMContract.contract.Call(opts, &out, "isBlessed", arg0)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_MockARMContract *MockARMContractSession) IsBlessed(arg0 IRMNTaggedRoot) (bool, error) {
+ return _MockARMContract.Contract.IsBlessed(&_MockARMContract.CallOpts, arg0)
+}
+
+func (_MockARMContract *MockARMContractCallerSession) IsBlessed(arg0 IRMNTaggedRoot) (bool, error) {
+ return _MockARMContract.Contract.IsBlessed(&_MockARMContract.CallOpts, arg0)
+}
+
+func (_MockARMContract *MockARMContractCaller) IsCursed(opts *bind.CallOpts, subject [16]byte) (bool, error) {
+ var out []interface{}
+ err := _MockARMContract.contract.Call(opts, &out, "isCursed", subject)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_MockARMContract *MockARMContractSession) IsCursed(subject [16]byte) (bool, error) {
+ return _MockARMContract.Contract.IsCursed(&_MockARMContract.CallOpts, subject)
+}
+
+func (_MockARMContract *MockARMContractCallerSession) IsCursed(subject [16]byte) (bool, error) {
+ return _MockARMContract.Contract.IsCursed(&_MockARMContract.CallOpts, subject)
+}
+
+func (_MockARMContract *MockARMContractCaller) IsCursed0(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _MockARMContract.contract.Call(opts, &out, "isCursed0")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_MockARMContract *MockARMContractSession) IsCursed0() (bool, error) {
+ return _MockARMContract.Contract.IsCursed0(&_MockARMContract.CallOpts)
+}
+
+func (_MockARMContract *MockARMContractCallerSession) IsCursed0() (bool, error) {
+ return _MockARMContract.Contract.IsCursed0(&_MockARMContract.CallOpts)
+}
+
+func (_MockARMContract *MockARMContractCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _MockARMContract.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_MockARMContract *MockARMContractSession) Owner() (common.Address, error) {
+ return _MockARMContract.Contract.Owner(&_MockARMContract.CallOpts)
+}
+
+func (_MockARMContract *MockARMContractCallerSession) Owner() (common.Address, error) {
+ return _MockARMContract.Contract.Owner(&_MockARMContract.CallOpts)
+}
+
+func (_MockARMContract *MockARMContractTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockARMContract.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_MockARMContract *MockARMContractSession) AcceptOwnership() (*types.Transaction, error) {
+ return _MockARMContract.Contract.AcceptOwnership(&_MockARMContract.TransactOpts)
+}
+
+func (_MockARMContract *MockARMContractTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _MockARMContract.Contract.AcceptOwnership(&_MockARMContract.TransactOpts)
+}
+
+func (_MockARMContract *MockARMContractTransactor) OwnerUnvoteToCurse(opts *bind.TransactOpts, arg0 []RMNUnvoteToCurseRecord, subject [16]byte) (*types.Transaction, error) {
+ return _MockARMContract.contract.Transact(opts, "ownerUnvoteToCurse", arg0, subject)
+}
+
+func (_MockARMContract *MockARMContractSession) OwnerUnvoteToCurse(arg0 []RMNUnvoteToCurseRecord, subject [16]byte) (*types.Transaction, error) {
+ return _MockARMContract.Contract.OwnerUnvoteToCurse(&_MockARMContract.TransactOpts, arg0, subject)
+}
+
+func (_MockARMContract *MockARMContractTransactorSession) OwnerUnvoteToCurse(arg0 []RMNUnvoteToCurseRecord, subject [16]byte) (*types.Transaction, error) {
+ return _MockARMContract.Contract.OwnerUnvoteToCurse(&_MockARMContract.TransactOpts, arg0, subject)
+}
+
+func (_MockARMContract *MockARMContractTransactor) OwnerUnvoteToCurse0(opts *bind.TransactOpts, arg0 []RMNUnvoteToCurseRecord) (*types.Transaction, error) {
+ return _MockARMContract.contract.Transact(opts, "ownerUnvoteToCurse0", arg0)
+}
+
+func (_MockARMContract *MockARMContractSession) OwnerUnvoteToCurse0(arg0 []RMNUnvoteToCurseRecord) (*types.Transaction, error) {
+ return _MockARMContract.Contract.OwnerUnvoteToCurse0(&_MockARMContract.TransactOpts, arg0)
+}
+
+func (_MockARMContract *MockARMContractTransactorSession) OwnerUnvoteToCurse0(arg0 []RMNUnvoteToCurseRecord) (*types.Transaction, error) {
+ return _MockARMContract.Contract.OwnerUnvoteToCurse0(&_MockARMContract.TransactOpts, arg0)
+}
+
+func (_MockARMContract *MockARMContractTransactor) SetRevert(opts *bind.TransactOpts, err []byte) (*types.Transaction, error) {
+ return _MockARMContract.contract.Transact(opts, "setRevert", err)
+}
+
+func (_MockARMContract *MockARMContractSession) SetRevert(err []byte) (*types.Transaction, error) {
+ return _MockARMContract.Contract.SetRevert(&_MockARMContract.TransactOpts, err)
+}
+
+func (_MockARMContract *MockARMContractTransactorSession) SetRevert(err []byte) (*types.Transaction, error) {
+ return _MockARMContract.Contract.SetRevert(&_MockARMContract.TransactOpts, err)
+}
+
+func (_MockARMContract *MockARMContractTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _MockARMContract.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_MockARMContract *MockARMContractSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _MockARMContract.Contract.TransferOwnership(&_MockARMContract.TransactOpts, to)
+}
+
+func (_MockARMContract *MockARMContractTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _MockARMContract.Contract.TransferOwnership(&_MockARMContract.TransactOpts, to)
+}
+
+func (_MockARMContract *MockARMContractTransactor) VoteToCurse(opts *bind.TransactOpts, arg0 [32]byte) (*types.Transaction, error) {
+ return _MockARMContract.contract.Transact(opts, "voteToCurse", arg0)
+}
+
+func (_MockARMContract *MockARMContractSession) VoteToCurse(arg0 [32]byte) (*types.Transaction, error) {
+ return _MockARMContract.Contract.VoteToCurse(&_MockARMContract.TransactOpts, arg0)
+}
+
+func (_MockARMContract *MockARMContractTransactorSession) VoteToCurse(arg0 [32]byte) (*types.Transaction, error) {
+ return _MockARMContract.Contract.VoteToCurse(&_MockARMContract.TransactOpts, arg0)
+}
+
+func (_MockARMContract *MockARMContractTransactor) VoteToCurse0(opts *bind.TransactOpts, arg0 [32]byte, subject [16]byte) (*types.Transaction, error) {
+ return _MockARMContract.contract.Transact(opts, "voteToCurse0", arg0, subject)
+}
+
+func (_MockARMContract *MockARMContractSession) VoteToCurse0(arg0 [32]byte, subject [16]byte) (*types.Transaction, error) {
+ return _MockARMContract.Contract.VoteToCurse0(&_MockARMContract.TransactOpts, arg0, subject)
+}
+
+func (_MockARMContract *MockARMContractTransactorSession) VoteToCurse0(arg0 [32]byte, subject [16]byte) (*types.Transaction, error) {
+ return _MockARMContract.Contract.VoteToCurse0(&_MockARMContract.TransactOpts, arg0, subject)
+}
+
+type MockARMContractOwnershipTransferRequestedIterator struct {
+ Event *MockARMContractOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MockARMContractOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MockARMContractOwnershipTransferRequested)
+ 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(MockARMContractOwnershipTransferRequested)
+ 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 *MockARMContractOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MockARMContractOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MockARMContractOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_MockARMContract *MockARMContractFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MockARMContractOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MockARMContract.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MockARMContractOwnershipTransferRequestedIterator{contract: _MockARMContract.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_MockARMContract *MockARMContractFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *MockARMContractOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MockARMContract.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MockARMContractOwnershipTransferRequested)
+ if err := _MockARMContract.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_MockARMContract *MockARMContractFilterer) ParseOwnershipTransferRequested(log types.Log) (*MockARMContractOwnershipTransferRequested, error) {
+ event := new(MockARMContractOwnershipTransferRequested)
+ if err := _MockARMContract.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MockARMContractOwnershipTransferredIterator struct {
+ Event *MockARMContractOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MockARMContractOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MockARMContractOwnershipTransferred)
+ 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(MockARMContractOwnershipTransferred)
+ 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 *MockARMContractOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *MockARMContractOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MockARMContractOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_MockARMContract *MockARMContractFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MockARMContractOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MockARMContract.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MockARMContractOwnershipTransferredIterator{contract: _MockARMContract.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_MockARMContract *MockARMContractFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *MockARMContractOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MockARMContract.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MockARMContractOwnershipTransferred)
+ if err := _MockARMContract.contract.UnpackLog(event, "OwnershipTransferred", 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 (_MockARMContract *MockARMContractFilterer) ParseOwnershipTransferred(log types.Log) (*MockARMContractOwnershipTransferred, error) {
+ event := new(MockARMContractOwnershipTransferred)
+ if err := _MockARMContract.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetConfigDetails struct {
+ Version uint32
+ BlockNumber uint32
+ Config RMNConfig
+}
+
+func (_MockARMContract *MockARMContract) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _MockARMContract.abi.Events["OwnershipTransferRequested"].ID:
+ return _MockARMContract.ParseOwnershipTransferRequested(log)
+ case _MockARMContract.abi.Events["OwnershipTransferred"].ID:
+ return _MockARMContract.ParseOwnershipTransferred(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (MockARMContractOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (MockARMContractOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (_MockARMContract *MockARMContract) Address() common.Address {
+ return _MockARMContract.address
+}
+
+type MockARMContractInterface interface {
+ GetConfigDetails(opts *bind.CallOpts) (GetConfigDetails,
+
+ error)
+
+ IsBlessed(opts *bind.CallOpts, arg0 IRMNTaggedRoot) (bool, error)
+
+ IsCursed(opts *bind.CallOpts, subject [16]byte) (bool, error)
+
+ IsCursed0(opts *bind.CallOpts) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ OwnerUnvoteToCurse(opts *bind.TransactOpts, arg0 []RMNUnvoteToCurseRecord, subject [16]byte) (*types.Transaction, error)
+
+ OwnerUnvoteToCurse0(opts *bind.TransactOpts, arg0 []RMNUnvoteToCurseRecord) (*types.Transaction, error)
+
+ SetRevert(opts *bind.TransactOpts, err []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ VoteToCurse(opts *bind.TransactOpts, arg0 [32]byte) (*types.Transaction, error)
+
+ VoteToCurse0(opts *bind.TransactOpts, arg0 [32]byte, subject [16]byte) (*types.Transaction, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MockARMContractOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *MockARMContractOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*MockARMContractOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MockARMContractOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *MockARMContractOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*MockARMContractOwnershipTransferred, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/mock_usdc_token_messenger/mock_usdc_token_messenger.go b/core/gethwrappers/ccip/generated/mock_usdc_token_messenger/mock_usdc_token_messenger.go
new file mode 100644
index 00000000000..cdd66b76cbe
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/mock_usdc_token_messenger/mock_usdc_token_messenger.go
@@ -0,0 +1,488 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package mock_usdc_token_messenger
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var MockE2EUSDCTokenMessengerMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"burnToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"mintRecipient\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"destinationTokenMessenger\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"destinationCaller\",\"type\":\"bytes32\"}],\"name\":\"DepositForBurn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DESTINATION_TOKEN_MESSENGER\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"mintRecipient\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"burnToken\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"destinationCaller\",\"type\":\"bytes32\"}],\"name\":\"depositForBurnWithCaller\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localMessageTransmitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"localMessageTransmitterWithRelay\",\"outputs\":[{\"internalType\":\"contractIMessageTransmitterWithRelay\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"messageBodyVersion\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x60e060405234801561001057600080fd5b5060405161083c38038061083c83398101604081905261002f91610063565b63ffffffff909116608052600080546001600160401b03191660011790556001600160a01b031660a081905260c0526100b2565b6000806040838503121561007657600080fd5b825163ffffffff8116811461008a57600080fd5b60208401519092506001600160a01b03811681146100a757600080fd5b809150509250929050565b60805160a05160c0516107486100f460003960008181610129015281816104aa015261056a01526000607901526000818160fa01526102d801526107486000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063a250c66a11610050578063a250c66a14610124578063f856ddb61461014b578063fb8406a91461015e57600080fd5b80632c121921146100775780637eccf63e146100c35780639cdbb181146100f0575b600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6000546100d79067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100ba565b60405163ffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100ba565b6100997f000000000000000000000000000000000000000000000000000000000000000081565b6100d76101593660046105ad565b610193565b6101857f17c71eed51b181d8ae1908b4743526c6dbf099c201f158a1acd5f6718e82e8f681565b6040519081526020016100ba565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810186905260009073ffffffffffffffffffffffffffffffffffffffff8416906323b872dd906064016020604051808303816000875af115801561020f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102339190610621565b506040517f42966c680000000000000000000000000000000000000000000000000000000081526004810187905273ffffffffffffffffffffffffffffffffffffffff8416906342966c6890602401600060405180830381600087803b15801561029c57600080fd5b505af11580156102b0573d6000803e3d6000fd5b50506040517fffffffff000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000060e01b1660208201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606087901b16602482015260388101879052605881018990523360788201526000925060980190506040516020818303038152906040529050610386867f17c71eed51b181d8ae1908b4743526c6dbf099c201f158a1acd5f6718e82e8f68584610466565b600080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff929092169182179055604080518981526020810188905263ffffffff8916918101919091527f17c71eed51b181d8ae1908b4743526c6dbf099c201f158a1acd5f6718e82e8f6606082015260808101859052339173ffffffffffffffffffffffffffffffffffffffff8716917f2fa9ca894982930190727e75500a97d8dc500233a5065e0f3126c48fbe0343c09060a00160405180910390a4505060005467ffffffffffffffff1695945050505050565b60008261052d576040517f0ba469bc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690630ba469bc906104e3908890889087906004016106ae565b6020604051808303816000875af1158015610502573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052691906106dc565b90506105a5565b6040517ff7259a7500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f7259a75906104e3908890889088908890600401610706565b949350505050565b600080600080600060a086880312156105c557600080fd5b85359450602086013563ffffffff811681146105e057600080fd5b935060408601359250606086013573ffffffffffffffffffffffffffffffffffffffff8116811461061057600080fd5b949793965091946080013592915050565b60006020828403121561063357600080fd5b8151801515811461064357600080fd5b9392505050565b6000815180845260005b8181101561067057602081850181015186830182015201610654565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b63ffffffff841681528260208201526060604082015260006106d3606083018461064a565b95945050505050565b6000602082840312156106ee57600080fd5b815167ffffffffffffffff8116811461064357600080fd5b63ffffffff85168152836020820152826040820152608060608201526000610731608083018461064a565b969550505050505056fea164736f6c6343000818000a",
+}
+
+var MockE2EUSDCTokenMessengerABI = MockE2EUSDCTokenMessengerMetaData.ABI
+
+var MockE2EUSDCTokenMessengerBin = MockE2EUSDCTokenMessengerMetaData.Bin
+
+func DeployMockE2EUSDCTokenMessenger(auth *bind.TransactOpts, backend bind.ContractBackend, version uint32, transmitter common.Address) (common.Address, *types.Transaction, *MockE2EUSDCTokenMessenger, error) {
+ parsed, err := MockE2EUSDCTokenMessengerMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MockE2EUSDCTokenMessengerBin), backend, version, transmitter)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MockE2EUSDCTokenMessenger{address: address, abi: *parsed, MockE2EUSDCTokenMessengerCaller: MockE2EUSDCTokenMessengerCaller{contract: contract}, MockE2EUSDCTokenMessengerTransactor: MockE2EUSDCTokenMessengerTransactor{contract: contract}, MockE2EUSDCTokenMessengerFilterer: MockE2EUSDCTokenMessengerFilterer{contract: contract}}, nil
+}
+
+type MockE2EUSDCTokenMessenger struct {
+ address common.Address
+ abi abi.ABI
+ MockE2EUSDCTokenMessengerCaller
+ MockE2EUSDCTokenMessengerTransactor
+ MockE2EUSDCTokenMessengerFilterer
+}
+
+type MockE2EUSDCTokenMessengerCaller struct {
+ contract *bind.BoundContract
+}
+
+type MockE2EUSDCTokenMessengerTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MockE2EUSDCTokenMessengerFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MockE2EUSDCTokenMessengerSession struct {
+ Contract *MockE2EUSDCTokenMessenger
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MockE2EUSDCTokenMessengerCallerSession struct {
+ Contract *MockE2EUSDCTokenMessengerCaller
+ CallOpts bind.CallOpts
+}
+
+type MockE2EUSDCTokenMessengerTransactorSession struct {
+ Contract *MockE2EUSDCTokenMessengerTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MockE2EUSDCTokenMessengerRaw struct {
+ Contract *MockE2EUSDCTokenMessenger
+}
+
+type MockE2EUSDCTokenMessengerCallerRaw struct {
+ Contract *MockE2EUSDCTokenMessengerCaller
+}
+
+type MockE2EUSDCTokenMessengerTransactorRaw struct {
+ Contract *MockE2EUSDCTokenMessengerTransactor
+}
+
+func NewMockE2EUSDCTokenMessenger(address common.Address, backend bind.ContractBackend) (*MockE2EUSDCTokenMessenger, error) {
+ abi, err := abi.JSON(strings.NewReader(MockE2EUSDCTokenMessengerABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMockE2EUSDCTokenMessenger(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTokenMessenger{address: address, abi: abi, MockE2EUSDCTokenMessengerCaller: MockE2EUSDCTokenMessengerCaller{contract: contract}, MockE2EUSDCTokenMessengerTransactor: MockE2EUSDCTokenMessengerTransactor{contract: contract}, MockE2EUSDCTokenMessengerFilterer: MockE2EUSDCTokenMessengerFilterer{contract: contract}}, nil
+}
+
+func NewMockE2EUSDCTokenMessengerCaller(address common.Address, caller bind.ContractCaller) (*MockE2EUSDCTokenMessengerCaller, error) {
+ contract, err := bindMockE2EUSDCTokenMessenger(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTokenMessengerCaller{contract: contract}, nil
+}
+
+func NewMockE2EUSDCTokenMessengerTransactor(address common.Address, transactor bind.ContractTransactor) (*MockE2EUSDCTokenMessengerTransactor, error) {
+ contract, err := bindMockE2EUSDCTokenMessenger(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTokenMessengerTransactor{contract: contract}, nil
+}
+
+func NewMockE2EUSDCTokenMessengerFilterer(address common.Address, filterer bind.ContractFilterer) (*MockE2EUSDCTokenMessengerFilterer, error) {
+ contract, err := bindMockE2EUSDCTokenMessenger(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTokenMessengerFilterer{contract: contract}, nil
+}
+
+func bindMockE2EUSDCTokenMessenger(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MockE2EUSDCTokenMessengerMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockE2EUSDCTokenMessenger.Contract.MockE2EUSDCTokenMessengerCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.MockE2EUSDCTokenMessengerTransactor.contract.Transfer(opts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.MockE2EUSDCTokenMessengerTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockE2EUSDCTokenMessenger.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.contract.Transfer(opts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCaller) DESTINATIONTOKENMESSENGER(opts *bind.CallOpts) ([32]byte, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTokenMessenger.contract.Call(opts, &out, "DESTINATION_TOKEN_MESSENGER")
+
+ if err != nil {
+ return *new([32]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerSession) DESTINATIONTOKENMESSENGER() ([32]byte, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.DESTINATIONTOKENMESSENGER(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCallerSession) DESTINATIONTOKENMESSENGER() ([32]byte, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.DESTINATIONTOKENMESSENGER(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCaller) LocalMessageTransmitter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTokenMessenger.contract.Call(opts, &out, "localMessageTransmitter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerSession) LocalMessageTransmitter() (common.Address, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.LocalMessageTransmitter(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCallerSession) LocalMessageTransmitter() (common.Address, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.LocalMessageTransmitter(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCaller) LocalMessageTransmitterWithRelay(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTokenMessenger.contract.Call(opts, &out, "localMessageTransmitterWithRelay")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerSession) LocalMessageTransmitterWithRelay() (common.Address, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.LocalMessageTransmitterWithRelay(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCallerSession) LocalMessageTransmitterWithRelay() (common.Address, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.LocalMessageTransmitterWithRelay(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCaller) MessageBodyVersion(opts *bind.CallOpts) (uint32, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTokenMessenger.contract.Call(opts, &out, "messageBodyVersion")
+
+ if err != nil {
+ return *new(uint32), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerSession) MessageBodyVersion() (uint32, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.MessageBodyVersion(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCallerSession) MessageBodyVersion() (uint32, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.MessageBodyVersion(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCaller) SNonce(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTokenMessenger.contract.Call(opts, &out, "s_nonce")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerSession) SNonce() (uint64, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.SNonce(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerCallerSession) SNonce() (uint64, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.SNonce(&_MockE2EUSDCTokenMessenger.CallOpts)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerTransactor) DepositForBurnWithCaller(opts *bind.TransactOpts, amount *big.Int, destinationDomain uint32, mintRecipient [32]byte, burnToken common.Address, destinationCaller [32]byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTokenMessenger.contract.Transact(opts, "depositForBurnWithCaller", amount, destinationDomain, mintRecipient, burnToken, destinationCaller)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerSession) DepositForBurnWithCaller(amount *big.Int, destinationDomain uint32, mintRecipient [32]byte, burnToken common.Address, destinationCaller [32]byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.DepositForBurnWithCaller(&_MockE2EUSDCTokenMessenger.TransactOpts, amount, destinationDomain, mintRecipient, burnToken, destinationCaller)
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerTransactorSession) DepositForBurnWithCaller(amount *big.Int, destinationDomain uint32, mintRecipient [32]byte, burnToken common.Address, destinationCaller [32]byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTokenMessenger.Contract.DepositForBurnWithCaller(&_MockE2EUSDCTokenMessenger.TransactOpts, amount, destinationDomain, mintRecipient, burnToken, destinationCaller)
+}
+
+type MockE2EUSDCTokenMessengerDepositForBurnIterator struct {
+ Event *MockE2EUSDCTokenMessengerDepositForBurn
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MockE2EUSDCTokenMessengerDepositForBurnIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MockE2EUSDCTokenMessengerDepositForBurn)
+ 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(MockE2EUSDCTokenMessengerDepositForBurn)
+ 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 *MockE2EUSDCTokenMessengerDepositForBurnIterator) Error() error {
+ return it.fail
+}
+
+func (it *MockE2EUSDCTokenMessengerDepositForBurnIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MockE2EUSDCTokenMessengerDepositForBurn struct {
+ Nonce uint64
+ BurnToken common.Address
+ Amount *big.Int
+ Depositor common.Address
+ MintRecipient [32]byte
+ DestinationDomain uint32
+ DestinationTokenMessenger [32]byte
+ DestinationCaller [32]byte
+ Raw types.Log
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerFilterer) FilterDepositForBurn(opts *bind.FilterOpts, nonce []uint64, burnToken []common.Address, depositor []common.Address) (*MockE2EUSDCTokenMessengerDepositForBurnIterator, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var burnTokenRule []interface{}
+ for _, burnTokenItem := range burnToken {
+ burnTokenRule = append(burnTokenRule, burnTokenItem)
+ }
+
+ var depositorRule []interface{}
+ for _, depositorItem := range depositor {
+ depositorRule = append(depositorRule, depositorItem)
+ }
+
+ logs, sub, err := _MockE2EUSDCTokenMessenger.contract.FilterLogs(opts, "DepositForBurn", nonceRule, burnTokenRule, depositorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTokenMessengerDepositForBurnIterator{contract: _MockE2EUSDCTokenMessenger.contract, event: "DepositForBurn", logs: logs, sub: sub}, nil
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerFilterer) WatchDepositForBurn(opts *bind.WatchOpts, sink chan<- *MockE2EUSDCTokenMessengerDepositForBurn, nonce []uint64, burnToken []common.Address, depositor []common.Address) (event.Subscription, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var burnTokenRule []interface{}
+ for _, burnTokenItem := range burnToken {
+ burnTokenRule = append(burnTokenRule, burnTokenItem)
+ }
+
+ var depositorRule []interface{}
+ for _, depositorItem := range depositor {
+ depositorRule = append(depositorRule, depositorItem)
+ }
+
+ logs, sub, err := _MockE2EUSDCTokenMessenger.contract.WatchLogs(opts, "DepositForBurn", nonceRule, burnTokenRule, depositorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MockE2EUSDCTokenMessengerDepositForBurn)
+ if err := _MockE2EUSDCTokenMessenger.contract.UnpackLog(event, "DepositForBurn", 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 (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessengerFilterer) ParseDepositForBurn(log types.Log) (*MockE2EUSDCTokenMessengerDepositForBurn, error) {
+ event := new(MockE2EUSDCTokenMessengerDepositForBurn)
+ if err := _MockE2EUSDCTokenMessenger.contract.UnpackLog(event, "DepositForBurn", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessenger) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _MockE2EUSDCTokenMessenger.abi.Events["DepositForBurn"].ID:
+ return _MockE2EUSDCTokenMessenger.ParseDepositForBurn(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (MockE2EUSDCTokenMessengerDepositForBurn) Topic() common.Hash {
+ return common.HexToHash("0x2fa9ca894982930190727e75500a97d8dc500233a5065e0f3126c48fbe0343c0")
+}
+
+func (_MockE2EUSDCTokenMessenger *MockE2EUSDCTokenMessenger) Address() common.Address {
+ return _MockE2EUSDCTokenMessenger.address
+}
+
+type MockE2EUSDCTokenMessengerInterface interface {
+ DESTINATIONTOKENMESSENGER(opts *bind.CallOpts) ([32]byte, error)
+
+ LocalMessageTransmitter(opts *bind.CallOpts) (common.Address, error)
+
+ LocalMessageTransmitterWithRelay(opts *bind.CallOpts) (common.Address, error)
+
+ MessageBodyVersion(opts *bind.CallOpts) (uint32, error)
+
+ SNonce(opts *bind.CallOpts) (uint64, error)
+
+ DepositForBurnWithCaller(opts *bind.TransactOpts, amount *big.Int, destinationDomain uint32, mintRecipient [32]byte, burnToken common.Address, destinationCaller [32]byte) (*types.Transaction, error)
+
+ FilterDepositForBurn(opts *bind.FilterOpts, nonce []uint64, burnToken []common.Address, depositor []common.Address) (*MockE2EUSDCTokenMessengerDepositForBurnIterator, error)
+
+ WatchDepositForBurn(opts *bind.WatchOpts, sink chan<- *MockE2EUSDCTokenMessengerDepositForBurn, nonce []uint64, burnToken []common.Address, depositor []common.Address) (event.Subscription, error)
+
+ ParseDepositForBurn(log types.Log) (*MockE2EUSDCTokenMessengerDepositForBurn, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/mock_usdc_token_transmitter/mock_usdc_token_transmitter.go b/core/gethwrappers/ccip/generated/mock_usdc_token_transmitter/mock_usdc_token_transmitter.go
new file mode 100644
index 00000000000..b31a834407b
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/mock_usdc_token_transmitter/mock_usdc_token_transmitter.go
@@ -0,0 +1,471 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package mock_usdc_token_transmitter
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var MockE2EUSDCTransmitterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_version\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_localDomain\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"MessageSent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"localDomain\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextAvailableNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"receiveMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_shouldSucceed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"recipient\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"messageBody\",\"type\":\"bytes\"}],\"name\":\"sendMessage\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"destinationDomain\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"recipient\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destinationCaller\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"messageBody\",\"type\":\"bytes\"}],\"name\":\"sendMessageWithCaller\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"shouldSucceed\",\"type\":\"bool\"}],\"name\":\"setShouldSucceed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x60e060405234801561001057600080fd5b5060405161097b38038061097b83398101604081905261002f91610076565b63ffffffff928316608052911660a0526000805460ff191660011790556001600160a01b031660c0526100ca565b805163ffffffff8116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005d565b92506100a26020850161005d565b60408501519092506001600160a01b03811681146100bf57600080fd5b809150509250925092565b60805160a05160c0516108756101066000396000610256015260008181610140015261046001526000818160c0015261043f01526108756000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c80638371744e1161005b5780638371744e146101255780638d3638f41461013e5780639e31ddb614610164578063f7259a75146101a557600080fd5b80630ba469bc1461008d57806354fd4d50146100be57806357ecfd28146100f55780637a64293514610118575b600080fd5b6100a061009b366004610552565b6101b8565b60405167ffffffffffffffff90911681526020015b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000005b60405163ffffffff90911681526020016100b5565b6101086101033660046105ac565b6101e1565b60405190151581526020016100b5565b6000546101089060ff1681565b6000546100a090610100900467ffffffffffffffff1681565b7f00000000000000000000000000000000000000000000000000000000000000006100e0565b6101a361017236600461060c565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b005b6100a06101b3366004610635565b6102c2565b600080806101c4610372565b9050336101d688888584868b8b6103d4565b509695505050505050565b6000806101f260546040878961069d565b6101fb916106c7565b6040517f40c10f1900000000000000000000000000000000000000000000000000000000815260609190911c60048201819052683635c9adc5dea000006024830152915073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b15801561029a57600080fd5b505af11580156102ae573d6000803e3d6000fd5b505060005460ff1698975050505050505050565b600083610356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f44657374696e6174696f6e2063616c6c6572206d757374206265206e6f6e7a6560448201527f726f00000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6000610360610372565b9050336101d688888884868a8a6103d4565b60008054610100900467ffffffffffffffff1661039081600161070f565b6000805467ffffffffffffffff92909216610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff909216919091179055919050565b8561043b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f526563697069656e74206d757374206265206e6f6e7a65726f00000000000000604482015260640161034d565b60007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008986888b8b898960405160200161049e9998979695949392919061075e565b60405160208183030381529060405290507f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036816040516104de91906107fb565b60405180910390a15050505050505050565b803563ffffffff8116811461050457600080fd5b919050565b60008083601f84011261051b57600080fd5b50813567ffffffffffffffff81111561053357600080fd5b60208301915083602082850101111561054b57600080fd5b9250929050565b6000806000806060858703121561056857600080fd5b610571856104f0565b935060208501359250604085013567ffffffffffffffff81111561059457600080fd5b6105a087828801610509565b95989497509550505050565b600080600080604085870312156105c257600080fd5b843567ffffffffffffffff808211156105da57600080fd5b6105e688838901610509565b909650945060208701359150808211156105ff57600080fd5b506105a087828801610509565b60006020828403121561061e57600080fd5b8135801515811461062e57600080fd5b9392505050565b60008060008060006080868803121561064d57600080fd5b610656866104f0565b94506020860135935060408601359250606086013567ffffffffffffffff81111561068057600080fd5b61068c88828901610509565b969995985093965092949392505050565b600080858511156106ad57600080fd5b838611156106ba57600080fd5b5050820193919092039150565b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081358181169160148510156107075780818660140360031b1b83161692505b505092915050565b67ffffffffffffffff818116838216019080821115610757577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b60007fffffffff00000000000000000000000000000000000000000000000000000000808c60e01b168352808b60e01b166004840152808a60e01b166008840152507fffffffffffffffff0000000000000000000000000000000000000000000000008860c01b16600c83015286601483015285603483015284605483015282846074840137506000910160740190815298975050505050505050565b60006020808352835180602085015260005b818110156108295785810183015185820160400152820161080d565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509291505056fea164736f6c6343000818000a",
+}
+
+var MockE2EUSDCTransmitterABI = MockE2EUSDCTransmitterMetaData.ABI
+
+var MockE2EUSDCTransmitterBin = MockE2EUSDCTransmitterMetaData.Bin
+
+func DeployMockE2EUSDCTransmitter(auth *bind.TransactOpts, backend bind.ContractBackend, _version uint32, _localDomain uint32, token common.Address) (common.Address, *types.Transaction, *MockE2EUSDCTransmitter, error) {
+ parsed, err := MockE2EUSDCTransmitterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MockE2EUSDCTransmitterBin), backend, _version, _localDomain, token)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MockE2EUSDCTransmitter{address: address, abi: *parsed, MockE2EUSDCTransmitterCaller: MockE2EUSDCTransmitterCaller{contract: contract}, MockE2EUSDCTransmitterTransactor: MockE2EUSDCTransmitterTransactor{contract: contract}, MockE2EUSDCTransmitterFilterer: MockE2EUSDCTransmitterFilterer{contract: contract}}, nil
+}
+
+type MockE2EUSDCTransmitter struct {
+ address common.Address
+ abi abi.ABI
+ MockE2EUSDCTransmitterCaller
+ MockE2EUSDCTransmitterTransactor
+ MockE2EUSDCTransmitterFilterer
+}
+
+type MockE2EUSDCTransmitterCaller struct {
+ contract *bind.BoundContract
+}
+
+type MockE2EUSDCTransmitterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MockE2EUSDCTransmitterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MockE2EUSDCTransmitterSession struct {
+ Contract *MockE2EUSDCTransmitter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MockE2EUSDCTransmitterCallerSession struct {
+ Contract *MockE2EUSDCTransmitterCaller
+ CallOpts bind.CallOpts
+}
+
+type MockE2EUSDCTransmitterTransactorSession struct {
+ Contract *MockE2EUSDCTransmitterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MockE2EUSDCTransmitterRaw struct {
+ Contract *MockE2EUSDCTransmitter
+}
+
+type MockE2EUSDCTransmitterCallerRaw struct {
+ Contract *MockE2EUSDCTransmitterCaller
+}
+
+type MockE2EUSDCTransmitterTransactorRaw struct {
+ Contract *MockE2EUSDCTransmitterTransactor
+}
+
+func NewMockE2EUSDCTransmitter(address common.Address, backend bind.ContractBackend) (*MockE2EUSDCTransmitter, error) {
+ abi, err := abi.JSON(strings.NewReader(MockE2EUSDCTransmitterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMockE2EUSDCTransmitter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTransmitter{address: address, abi: abi, MockE2EUSDCTransmitterCaller: MockE2EUSDCTransmitterCaller{contract: contract}, MockE2EUSDCTransmitterTransactor: MockE2EUSDCTransmitterTransactor{contract: contract}, MockE2EUSDCTransmitterFilterer: MockE2EUSDCTransmitterFilterer{contract: contract}}, nil
+}
+
+func NewMockE2EUSDCTransmitterCaller(address common.Address, caller bind.ContractCaller) (*MockE2EUSDCTransmitterCaller, error) {
+ contract, err := bindMockE2EUSDCTransmitter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTransmitterCaller{contract: contract}, nil
+}
+
+func NewMockE2EUSDCTransmitterTransactor(address common.Address, transactor bind.ContractTransactor) (*MockE2EUSDCTransmitterTransactor, error) {
+ contract, err := bindMockE2EUSDCTransmitter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTransmitterTransactor{contract: contract}, nil
+}
+
+func NewMockE2EUSDCTransmitterFilterer(address common.Address, filterer bind.ContractFilterer) (*MockE2EUSDCTransmitterFilterer, error) {
+ contract, err := bindMockE2EUSDCTransmitter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTransmitterFilterer{contract: contract}, nil
+}
+
+func bindMockE2EUSDCTransmitter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MockE2EUSDCTransmitterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockE2EUSDCTransmitter.Contract.MockE2EUSDCTransmitterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.MockE2EUSDCTransmitterTransactor.contract.Transfer(opts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.MockE2EUSDCTransmitterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockE2EUSDCTransmitter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.contract.Transfer(opts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCaller) LocalDomain(opts *bind.CallOpts) (uint32, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTransmitter.contract.Call(opts, &out, "localDomain")
+
+ if err != nil {
+ return *new(uint32), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterSession) LocalDomain() (uint32, error) {
+ return _MockE2EUSDCTransmitter.Contract.LocalDomain(&_MockE2EUSDCTransmitter.CallOpts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCallerSession) LocalDomain() (uint32, error) {
+ return _MockE2EUSDCTransmitter.Contract.LocalDomain(&_MockE2EUSDCTransmitter.CallOpts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCaller) NextAvailableNonce(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTransmitter.contract.Call(opts, &out, "nextAvailableNonce")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterSession) NextAvailableNonce() (uint64, error) {
+ return _MockE2EUSDCTransmitter.Contract.NextAvailableNonce(&_MockE2EUSDCTransmitter.CallOpts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCallerSession) NextAvailableNonce() (uint64, error) {
+ return _MockE2EUSDCTransmitter.Contract.NextAvailableNonce(&_MockE2EUSDCTransmitter.CallOpts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCaller) SShouldSucceed(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTransmitter.contract.Call(opts, &out, "s_shouldSucceed")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterSession) SShouldSucceed() (bool, error) {
+ return _MockE2EUSDCTransmitter.Contract.SShouldSucceed(&_MockE2EUSDCTransmitter.CallOpts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCallerSession) SShouldSucceed() (bool, error) {
+ return _MockE2EUSDCTransmitter.Contract.SShouldSucceed(&_MockE2EUSDCTransmitter.CallOpts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCaller) Version(opts *bind.CallOpts) (uint32, error) {
+ var out []interface{}
+ err := _MockE2EUSDCTransmitter.contract.Call(opts, &out, "version")
+
+ if err != nil {
+ return *new(uint32), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
+
+ return out0, err
+
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterSession) Version() (uint32, error) {
+ return _MockE2EUSDCTransmitter.Contract.Version(&_MockE2EUSDCTransmitter.CallOpts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterCallerSession) Version() (uint32, error) {
+ return _MockE2EUSDCTransmitter.Contract.Version(&_MockE2EUSDCTransmitter.CallOpts)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactor) ReceiveMessage(opts *bind.TransactOpts, message []byte, arg1 []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.contract.Transact(opts, "receiveMessage", message, arg1)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterSession) ReceiveMessage(message []byte, arg1 []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.ReceiveMessage(&_MockE2EUSDCTransmitter.TransactOpts, message, arg1)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactorSession) ReceiveMessage(message []byte, arg1 []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.ReceiveMessage(&_MockE2EUSDCTransmitter.TransactOpts, message, arg1)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactor) SendMessage(opts *bind.TransactOpts, destinationDomain uint32, recipient [32]byte, messageBody []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.contract.Transact(opts, "sendMessage", destinationDomain, recipient, messageBody)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterSession) SendMessage(destinationDomain uint32, recipient [32]byte, messageBody []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.SendMessage(&_MockE2EUSDCTransmitter.TransactOpts, destinationDomain, recipient, messageBody)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactorSession) SendMessage(destinationDomain uint32, recipient [32]byte, messageBody []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.SendMessage(&_MockE2EUSDCTransmitter.TransactOpts, destinationDomain, recipient, messageBody)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactor) SendMessageWithCaller(opts *bind.TransactOpts, destinationDomain uint32, recipient [32]byte, destinationCaller [32]byte, messageBody []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.contract.Transact(opts, "sendMessageWithCaller", destinationDomain, recipient, destinationCaller, messageBody)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterSession) SendMessageWithCaller(destinationDomain uint32, recipient [32]byte, destinationCaller [32]byte, messageBody []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.SendMessageWithCaller(&_MockE2EUSDCTransmitter.TransactOpts, destinationDomain, recipient, destinationCaller, messageBody)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactorSession) SendMessageWithCaller(destinationDomain uint32, recipient [32]byte, destinationCaller [32]byte, messageBody []byte) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.SendMessageWithCaller(&_MockE2EUSDCTransmitter.TransactOpts, destinationDomain, recipient, destinationCaller, messageBody)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactor) SetShouldSucceed(opts *bind.TransactOpts, shouldSucceed bool) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.contract.Transact(opts, "setShouldSucceed", shouldSucceed)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterSession) SetShouldSucceed(shouldSucceed bool) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.SetShouldSucceed(&_MockE2EUSDCTransmitter.TransactOpts, shouldSucceed)
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterTransactorSession) SetShouldSucceed(shouldSucceed bool) (*types.Transaction, error) {
+ return _MockE2EUSDCTransmitter.Contract.SetShouldSucceed(&_MockE2EUSDCTransmitter.TransactOpts, shouldSucceed)
+}
+
+type MockE2EUSDCTransmitterMessageSentIterator struct {
+ Event *MockE2EUSDCTransmitterMessageSent
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MockE2EUSDCTransmitterMessageSentIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MockE2EUSDCTransmitterMessageSent)
+ 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(MockE2EUSDCTransmitterMessageSent)
+ 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 *MockE2EUSDCTransmitterMessageSentIterator) Error() error {
+ return it.fail
+}
+
+func (it *MockE2EUSDCTransmitterMessageSentIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MockE2EUSDCTransmitterMessageSent struct {
+ Message []byte
+ Raw types.Log
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterFilterer) FilterMessageSent(opts *bind.FilterOpts) (*MockE2EUSDCTransmitterMessageSentIterator, error) {
+
+ logs, sub, err := _MockE2EUSDCTransmitter.contract.FilterLogs(opts, "MessageSent")
+ if err != nil {
+ return nil, err
+ }
+ return &MockE2EUSDCTransmitterMessageSentIterator{contract: _MockE2EUSDCTransmitter.contract, event: "MessageSent", logs: logs, sub: sub}, nil
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterFilterer) WatchMessageSent(opts *bind.WatchOpts, sink chan<- *MockE2EUSDCTransmitterMessageSent) (event.Subscription, error) {
+
+ logs, sub, err := _MockE2EUSDCTransmitter.contract.WatchLogs(opts, "MessageSent")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MockE2EUSDCTransmitterMessageSent)
+ if err := _MockE2EUSDCTransmitter.contract.UnpackLog(event, "MessageSent", 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 (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitterFilterer) ParseMessageSent(log types.Log) (*MockE2EUSDCTransmitterMessageSent, error) {
+ event := new(MockE2EUSDCTransmitterMessageSent)
+ if err := _MockE2EUSDCTransmitter.contract.UnpackLog(event, "MessageSent", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitter) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _MockE2EUSDCTransmitter.abi.Events["MessageSent"].ID:
+ return _MockE2EUSDCTransmitter.ParseMessageSent(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (MockE2EUSDCTransmitterMessageSent) Topic() common.Hash {
+ return common.HexToHash("0x8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036")
+}
+
+func (_MockE2EUSDCTransmitter *MockE2EUSDCTransmitter) Address() common.Address {
+ return _MockE2EUSDCTransmitter.address
+}
+
+type MockE2EUSDCTransmitterInterface interface {
+ LocalDomain(opts *bind.CallOpts) (uint32, error)
+
+ NextAvailableNonce(opts *bind.CallOpts) (uint64, error)
+
+ SShouldSucceed(opts *bind.CallOpts) (bool, error)
+
+ Version(opts *bind.CallOpts) (uint32, error)
+
+ ReceiveMessage(opts *bind.TransactOpts, message []byte, arg1 []byte) (*types.Transaction, error)
+
+ SendMessage(opts *bind.TransactOpts, destinationDomain uint32, recipient [32]byte, messageBody []byte) (*types.Transaction, error)
+
+ SendMessageWithCaller(opts *bind.TransactOpts, destinationDomain uint32, recipient [32]byte, destinationCaller [32]byte, messageBody []byte) (*types.Transaction, error)
+
+ SetShouldSucceed(opts *bind.TransactOpts, shouldSucceed bool) (*types.Transaction, error)
+
+ FilterMessageSent(opts *bind.FilterOpts) (*MockE2EUSDCTransmitterMessageSentIterator, error)
+
+ WatchMessageSent(opts *bind.WatchOpts, sink chan<- *MockE2EUSDCTransmitterMessageSent) (event.Subscription, error)
+
+ ParseMessageSent(log types.Log) (*MockE2EUSDCTransmitterMessageSent, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/mock_v3_aggregator_contract/mock_v3_aggregator_contract.go b/core/gethwrappers/ccip/generated/mock_v3_aggregator_contract/mock_v3_aggregator_contract.go
new file mode 100644
index 00000000000..c3521d35151
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/mock_v3_aggregator_contract/mock_v3_aggregator_contract.go
@@ -0,0 +1,797 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package mock_v3_aggregator_contract
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var MockV3AggregatorMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"_decimals\",\"type\":\"uint8\"},{\"internalType\":\"int256\",\"name\":\"_initialAnswer\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int256\",\"name\":\"current\",\"type\":\"int256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"roundId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"updatedAt\",\"type\":\"uint256\"}],\"name\":\"AnswerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"roundId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"startedBy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startedAt\",\"type\":\"uint256\"}],\"name\":\"NewRound\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"description\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getAnswer\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint80\",\"name\":\"_roundId\",\"type\":\"uint80\"}],\"name\":\"getRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"answer\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"startedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint80\",\"name\":\"answeredInRound\",\"type\":\"uint80\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestAnswer\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestRound\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"answer\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"startedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint80\",\"name\":\"answeredInRound\",\"type\":\"uint80\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_answer\",\"type\":\"int256\"}],\"name\":\"updateAnswer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint80\",\"name\":\"_roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"_answer\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"_timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_startedAt\",\"type\":\"uint256\"}],\"name\":\"updateRoundData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b5060405161059638038061059683398101604081905261002f916100a4565b6000805460ff191660ff84161790556100478161004e565b50506100ff565b60018190554260025560038054906000610067836100d8565b9091555050600380546000908152600460209081526040808320949094558254825260058152838220429081905592548252600690529190912055565b600080604083850312156100b757600080fd5b825160ff811681146100c857600080fd5b6020939093015192949293505050565b6000600182016100f857634e487b7160e01b600052601160045260246000fd5b5060010190565b6104888061010e6000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80638205bf6a11610081578063b5ab58dc1161005b578063b5ab58dc1461025b578063b633620c1461027b578063feaf968c1461029b57600080fd5b80638205bf6a146101c15780639a6fc8f5146101ca578063a87a20ce1461024857600080fd5b806354fd4d50116100b257806354fd4d5014610171578063668a0f02146101795780637284e4161461018257600080fd5b8063313ce567146100d95780634aa2011f146100fd57806350d25bcd1461015a575b600080fd5b6000546100e69060ff1681565b60405160ff90911681526020015b60405180910390f35b61015861010b36600461033b565b69ffffffffffffffffffff90931660038181556001849055600283905560009182526004602090815260408084209590955581548352600581528483209390935554815260069091522055565b005b61016360015481565b6040519081526020016100f4565b610163600081565b61016360035481565b604080518082018252601f81527f76302e382f74657374732f4d6f636b563341676772656761746f722e736f6c00602082015290516100f49190610374565b61016360025481565b6102116101d83660046103e1565b69ffffffffffffffffffff8116600090815260046020908152604080832054600683528184205460059093529220549293919290918490565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a0016100f4565b610158610256366004610403565b6102c6565b610163610269366004610403565b60046020526000908152604090205481565b610163610289366004610403565b60056020526000908152604090205481565b6003546000818152600460209081526040808320546006835281842054600590935292205483610211565b600181905542600255600380549060006102df8361041c565b9091555050600380546000908152600460209081526040808320949094558254825260058152838220429081905592548252600690529190912055565b803569ffffffffffffffffffff8116811461033657600080fd5b919050565b6000806000806080858703121561035157600080fd5b61035a8561031c565b966020860135965060408601359560600135945092505050565b60006020808352835180602085015260005b818110156103a257858101830151858201604001528201610386565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6000602082840312156103f357600080fd5b6103fc8261031c565b9392505050565b60006020828403121561041557600080fd5b5035919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610474577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c6343000818000a",
+}
+
+var MockV3AggregatorABI = MockV3AggregatorMetaData.ABI
+
+var MockV3AggregatorBin = MockV3AggregatorMetaData.Bin
+
+func DeployMockV3Aggregator(auth *bind.TransactOpts, backend bind.ContractBackend, _decimals uint8, _initialAnswer *big.Int) (common.Address, *types.Transaction, *MockV3Aggregator, error) {
+ parsed, err := MockV3AggregatorMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MockV3AggregatorBin), backend, _decimals, _initialAnswer)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MockV3Aggregator{address: address, abi: *parsed, MockV3AggregatorCaller: MockV3AggregatorCaller{contract: contract}, MockV3AggregatorTransactor: MockV3AggregatorTransactor{contract: contract}, MockV3AggregatorFilterer: MockV3AggregatorFilterer{contract: contract}}, nil
+}
+
+type MockV3Aggregator struct {
+ address common.Address
+ abi abi.ABI
+ MockV3AggregatorCaller
+ MockV3AggregatorTransactor
+ MockV3AggregatorFilterer
+}
+
+type MockV3AggregatorCaller struct {
+ contract *bind.BoundContract
+}
+
+type MockV3AggregatorTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MockV3AggregatorFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MockV3AggregatorSession struct {
+ Contract *MockV3Aggregator
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MockV3AggregatorCallerSession struct {
+ Contract *MockV3AggregatorCaller
+ CallOpts bind.CallOpts
+}
+
+type MockV3AggregatorTransactorSession struct {
+ Contract *MockV3AggregatorTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MockV3AggregatorRaw struct {
+ Contract *MockV3Aggregator
+}
+
+type MockV3AggregatorCallerRaw struct {
+ Contract *MockV3AggregatorCaller
+}
+
+type MockV3AggregatorTransactorRaw struct {
+ Contract *MockV3AggregatorTransactor
+}
+
+func NewMockV3Aggregator(address common.Address, backend bind.ContractBackend) (*MockV3Aggregator, error) {
+ abi, err := abi.JSON(strings.NewReader(MockV3AggregatorABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMockV3Aggregator(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MockV3Aggregator{address: address, abi: abi, MockV3AggregatorCaller: MockV3AggregatorCaller{contract: contract}, MockV3AggregatorTransactor: MockV3AggregatorTransactor{contract: contract}, MockV3AggregatorFilterer: MockV3AggregatorFilterer{contract: contract}}, nil
+}
+
+func NewMockV3AggregatorCaller(address common.Address, caller bind.ContractCaller) (*MockV3AggregatorCaller, error) {
+ contract, err := bindMockV3Aggregator(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockV3AggregatorCaller{contract: contract}, nil
+}
+
+func NewMockV3AggregatorTransactor(address common.Address, transactor bind.ContractTransactor) (*MockV3AggregatorTransactor, error) {
+ contract, err := bindMockV3Aggregator(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockV3AggregatorTransactor{contract: contract}, nil
+}
+
+func NewMockV3AggregatorFilterer(address common.Address, filterer bind.ContractFilterer) (*MockV3AggregatorFilterer, error) {
+ contract, err := bindMockV3Aggregator(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MockV3AggregatorFilterer{contract: contract}, nil
+}
+
+func bindMockV3Aggregator(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MockV3AggregatorMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MockV3Aggregator *MockV3AggregatorRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockV3Aggregator.Contract.MockV3AggregatorCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockV3Aggregator.Contract.MockV3AggregatorTransactor.contract.Transfer(opts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockV3Aggregator.Contract.MockV3AggregatorTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockV3Aggregator.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockV3Aggregator.Contract.contract.Transfer(opts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockV3Aggregator.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) Decimals(opts *bind.CallOpts) (uint8, error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "decimals")
+
+ if err != nil {
+ return *new(uint8), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
+
+ return out0, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) Decimals() (uint8, error) {
+ return _MockV3Aggregator.Contract.Decimals(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) Decimals() (uint8, error) {
+ return _MockV3Aggregator.Contract.Decimals(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) Description(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "description")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) Description() (string, error) {
+ return _MockV3Aggregator.Contract.Description(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) Description() (string, error) {
+ return _MockV3Aggregator.Contract.Description(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) GetAnswer(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "getAnswer", arg0)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) GetAnswer(arg0 *big.Int) (*big.Int, error) {
+ return _MockV3Aggregator.Contract.GetAnswer(&_MockV3Aggregator.CallOpts, arg0)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) GetAnswer(arg0 *big.Int) (*big.Int, error) {
+ return _MockV3Aggregator.Contract.GetAnswer(&_MockV3Aggregator.CallOpts, arg0)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (GetRoundData,
+
+ error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "getRoundData", _roundId)
+
+ outstruct := new(GetRoundData)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.RoundId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+ outstruct.Answer = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+ outstruct.StartedAt = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int)
+ outstruct.UpdatedAt = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int)
+ outstruct.AnsweredInRound = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) GetRoundData(_roundId *big.Int) (GetRoundData,
+
+ error) {
+ return _MockV3Aggregator.Contract.GetRoundData(&_MockV3Aggregator.CallOpts, _roundId)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) GetRoundData(_roundId *big.Int) (GetRoundData,
+
+ error) {
+ return _MockV3Aggregator.Contract.GetRoundData(&_MockV3Aggregator.CallOpts, _roundId)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) GetTimestamp(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "getTimestamp", arg0)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) GetTimestamp(arg0 *big.Int) (*big.Int, error) {
+ return _MockV3Aggregator.Contract.GetTimestamp(&_MockV3Aggregator.CallOpts, arg0)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) GetTimestamp(arg0 *big.Int) (*big.Int, error) {
+ return _MockV3Aggregator.Contract.GetTimestamp(&_MockV3Aggregator.CallOpts, arg0)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) LatestAnswer(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "latestAnswer")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) LatestAnswer() (*big.Int, error) {
+ return _MockV3Aggregator.Contract.LatestAnswer(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) LatestAnswer() (*big.Int, error) {
+ return _MockV3Aggregator.Contract.LatestAnswer(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) LatestRound(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "latestRound")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) LatestRound() (*big.Int, error) {
+ return _MockV3Aggregator.Contract.LatestRound(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) LatestRound() (*big.Int, error) {
+ return _MockV3Aggregator.Contract.LatestRound(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) LatestRoundData(opts *bind.CallOpts) (LatestRoundData,
+
+ error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "latestRoundData")
+
+ outstruct := new(LatestRoundData)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.RoundId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+ outstruct.Answer = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+ outstruct.StartedAt = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int)
+ outstruct.UpdatedAt = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int)
+ outstruct.AnsweredInRound = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) LatestRoundData() (LatestRoundData,
+
+ error) {
+ return _MockV3Aggregator.Contract.LatestRoundData(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) LatestRoundData() (LatestRoundData,
+
+ error) {
+ return _MockV3Aggregator.Contract.LatestRoundData(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) LatestTimestamp(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "latestTimestamp")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) LatestTimestamp() (*big.Int, error) {
+ return _MockV3Aggregator.Contract.LatestTimestamp(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) LatestTimestamp() (*big.Int, error) {
+ return _MockV3Aggregator.Contract.LatestTimestamp(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCaller) Version(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _MockV3Aggregator.contract.Call(opts, &out, "version")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) Version() (*big.Int, error) {
+ return _MockV3Aggregator.Contract.Version(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorCallerSession) Version() (*big.Int, error) {
+ return _MockV3Aggregator.Contract.Version(&_MockV3Aggregator.CallOpts)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorTransactor) UpdateAnswer(opts *bind.TransactOpts, _answer *big.Int) (*types.Transaction, error) {
+ return _MockV3Aggregator.contract.Transact(opts, "updateAnswer", _answer)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) UpdateAnswer(_answer *big.Int) (*types.Transaction, error) {
+ return _MockV3Aggregator.Contract.UpdateAnswer(&_MockV3Aggregator.TransactOpts, _answer)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorTransactorSession) UpdateAnswer(_answer *big.Int) (*types.Transaction, error) {
+ return _MockV3Aggregator.Contract.UpdateAnswer(&_MockV3Aggregator.TransactOpts, _answer)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorTransactor) UpdateRoundData(opts *bind.TransactOpts, _roundId *big.Int, _answer *big.Int, _timestamp *big.Int, _startedAt *big.Int) (*types.Transaction, error) {
+ return _MockV3Aggregator.contract.Transact(opts, "updateRoundData", _roundId, _answer, _timestamp, _startedAt)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorSession) UpdateRoundData(_roundId *big.Int, _answer *big.Int, _timestamp *big.Int, _startedAt *big.Int) (*types.Transaction, error) {
+ return _MockV3Aggregator.Contract.UpdateRoundData(&_MockV3Aggregator.TransactOpts, _roundId, _answer, _timestamp, _startedAt)
+}
+
+func (_MockV3Aggregator *MockV3AggregatorTransactorSession) UpdateRoundData(_roundId *big.Int, _answer *big.Int, _timestamp *big.Int, _startedAt *big.Int) (*types.Transaction, error) {
+ return _MockV3Aggregator.Contract.UpdateRoundData(&_MockV3Aggregator.TransactOpts, _roundId, _answer, _timestamp, _startedAt)
+}
+
+type MockV3AggregatorAnswerUpdatedIterator struct {
+ Event *MockV3AggregatorAnswerUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MockV3AggregatorAnswerUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MockV3AggregatorAnswerUpdated)
+ 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(MockV3AggregatorAnswerUpdated)
+ 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 *MockV3AggregatorAnswerUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MockV3AggregatorAnswerUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MockV3AggregatorAnswerUpdated struct {
+ Current *big.Int
+ RoundId *big.Int
+ UpdatedAt *big.Int
+ Raw types.Log
+}
+
+func (_MockV3Aggregator *MockV3AggregatorFilterer) FilterAnswerUpdated(opts *bind.FilterOpts, current []*big.Int, roundId []*big.Int) (*MockV3AggregatorAnswerUpdatedIterator, error) {
+
+ var currentRule []interface{}
+ for _, currentItem := range current {
+ currentRule = append(currentRule, currentItem)
+ }
+ var roundIdRule []interface{}
+ for _, roundIdItem := range roundId {
+ roundIdRule = append(roundIdRule, roundIdItem)
+ }
+
+ logs, sub, err := _MockV3Aggregator.contract.FilterLogs(opts, "AnswerUpdated", currentRule, roundIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MockV3AggregatorAnswerUpdatedIterator{contract: _MockV3Aggregator.contract, event: "AnswerUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_MockV3Aggregator *MockV3AggregatorFilterer) WatchAnswerUpdated(opts *bind.WatchOpts, sink chan<- *MockV3AggregatorAnswerUpdated, current []*big.Int, roundId []*big.Int) (event.Subscription, error) {
+
+ var currentRule []interface{}
+ for _, currentItem := range current {
+ currentRule = append(currentRule, currentItem)
+ }
+ var roundIdRule []interface{}
+ for _, roundIdItem := range roundId {
+ roundIdRule = append(roundIdRule, roundIdItem)
+ }
+
+ logs, sub, err := _MockV3Aggregator.contract.WatchLogs(opts, "AnswerUpdated", currentRule, roundIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MockV3AggregatorAnswerUpdated)
+ if err := _MockV3Aggregator.contract.UnpackLog(event, "AnswerUpdated", 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 (_MockV3Aggregator *MockV3AggregatorFilterer) ParseAnswerUpdated(log types.Log) (*MockV3AggregatorAnswerUpdated, error) {
+ event := new(MockV3AggregatorAnswerUpdated)
+ if err := _MockV3Aggregator.contract.UnpackLog(event, "AnswerUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MockV3AggregatorNewRoundIterator struct {
+ Event *MockV3AggregatorNewRound
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MockV3AggregatorNewRoundIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MockV3AggregatorNewRound)
+ 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(MockV3AggregatorNewRound)
+ 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 *MockV3AggregatorNewRoundIterator) Error() error {
+ return it.fail
+}
+
+func (it *MockV3AggregatorNewRoundIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MockV3AggregatorNewRound struct {
+ RoundId *big.Int
+ StartedBy common.Address
+ StartedAt *big.Int
+ Raw types.Log
+}
+
+func (_MockV3Aggregator *MockV3AggregatorFilterer) FilterNewRound(opts *bind.FilterOpts, roundId []*big.Int, startedBy []common.Address) (*MockV3AggregatorNewRoundIterator, error) {
+
+ var roundIdRule []interface{}
+ for _, roundIdItem := range roundId {
+ roundIdRule = append(roundIdRule, roundIdItem)
+ }
+ var startedByRule []interface{}
+ for _, startedByItem := range startedBy {
+ startedByRule = append(startedByRule, startedByItem)
+ }
+
+ logs, sub, err := _MockV3Aggregator.contract.FilterLogs(opts, "NewRound", roundIdRule, startedByRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MockV3AggregatorNewRoundIterator{contract: _MockV3Aggregator.contract, event: "NewRound", logs: logs, sub: sub}, nil
+}
+
+func (_MockV3Aggregator *MockV3AggregatorFilterer) WatchNewRound(opts *bind.WatchOpts, sink chan<- *MockV3AggregatorNewRound, roundId []*big.Int, startedBy []common.Address) (event.Subscription, error) {
+
+ var roundIdRule []interface{}
+ for _, roundIdItem := range roundId {
+ roundIdRule = append(roundIdRule, roundIdItem)
+ }
+ var startedByRule []interface{}
+ for _, startedByItem := range startedBy {
+ startedByRule = append(startedByRule, startedByItem)
+ }
+
+ logs, sub, err := _MockV3Aggregator.contract.WatchLogs(opts, "NewRound", roundIdRule, startedByRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MockV3AggregatorNewRound)
+ if err := _MockV3Aggregator.contract.UnpackLog(event, "NewRound", 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 (_MockV3Aggregator *MockV3AggregatorFilterer) ParseNewRound(log types.Log) (*MockV3AggregatorNewRound, error) {
+ event := new(MockV3AggregatorNewRound)
+ if err := _MockV3Aggregator.contract.UnpackLog(event, "NewRound", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetRoundData struct {
+ RoundId *big.Int
+ Answer *big.Int
+ StartedAt *big.Int
+ UpdatedAt *big.Int
+ AnsweredInRound *big.Int
+}
+type LatestRoundData struct {
+ RoundId *big.Int
+ Answer *big.Int
+ StartedAt *big.Int
+ UpdatedAt *big.Int
+ AnsweredInRound *big.Int
+}
+
+func (_MockV3Aggregator *MockV3Aggregator) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _MockV3Aggregator.abi.Events["AnswerUpdated"].ID:
+ return _MockV3Aggregator.ParseAnswerUpdated(log)
+ case _MockV3Aggregator.abi.Events["NewRound"].ID:
+ return _MockV3Aggregator.ParseNewRound(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (MockV3AggregatorAnswerUpdated) Topic() common.Hash {
+ return common.HexToHash("0x0559884fd3a460db3073b7fc896cc77986f16e378210ded43186175bf646fc5f")
+}
+
+func (MockV3AggregatorNewRound) Topic() common.Hash {
+ return common.HexToHash("0x0109fc6f55cf40689f02fbaad7af7fe7bbac8a3d2186600afc7d3e10cac60271")
+}
+
+func (_MockV3Aggregator *MockV3Aggregator) Address() common.Address {
+ return _MockV3Aggregator.address
+}
+
+type MockV3AggregatorInterface interface {
+ Decimals(opts *bind.CallOpts) (uint8, error)
+
+ Description(opts *bind.CallOpts) (string, error)
+
+ GetAnswer(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error)
+
+ GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (GetRoundData,
+
+ error)
+
+ GetTimestamp(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error)
+
+ LatestAnswer(opts *bind.CallOpts) (*big.Int, error)
+
+ LatestRound(opts *bind.CallOpts) (*big.Int, error)
+
+ LatestRoundData(opts *bind.CallOpts) (LatestRoundData,
+
+ error)
+
+ LatestTimestamp(opts *bind.CallOpts) (*big.Int, error)
+
+ Version(opts *bind.CallOpts) (*big.Int, error)
+
+ UpdateAnswer(opts *bind.TransactOpts, _answer *big.Int) (*types.Transaction, error)
+
+ UpdateRoundData(opts *bind.TransactOpts, _roundId *big.Int, _answer *big.Int, _timestamp *big.Int, _startedAt *big.Int) (*types.Transaction, error)
+
+ FilterAnswerUpdated(opts *bind.FilterOpts, current []*big.Int, roundId []*big.Int) (*MockV3AggregatorAnswerUpdatedIterator, error)
+
+ WatchAnswerUpdated(opts *bind.WatchOpts, sink chan<- *MockV3AggregatorAnswerUpdated, current []*big.Int, roundId []*big.Int) (event.Subscription, error)
+
+ ParseAnswerUpdated(log types.Log) (*MockV3AggregatorAnswerUpdated, error)
+
+ FilterNewRound(opts *bind.FilterOpts, roundId []*big.Int, startedBy []common.Address) (*MockV3AggregatorNewRoundIterator, error)
+
+ WatchNewRound(opts *bind.WatchOpts, sink chan<- *MockV3AggregatorNewRound, roundId []*big.Int, startedBy []common.Address) (event.Subscription, error)
+
+ ParseNewRound(log types.Log) (*MockV3AggregatorNewRound, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/multi_aggregate_rate_limiter/multi_aggregate_rate_limiter.go b/core/gethwrappers/ccip/generated/multi_aggregate_rate_limiter/multi_aggregate_rate_limiter.go
new file mode 100644
index 00000000000..9fca2d1d369
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/multi_aggregate_rate_limiter/multi_aggregate_rate_limiter.go
@@ -0,0 +1,1836 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package multi_aggregate_rate_limiter
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type AuthorizedCallersAuthorizedCallerArgs struct {
+ AddedCallers []common.Address
+ RemovedCallers []common.Address
+}
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type MultiAggregateRateLimiterLocalRateLimitToken struct {
+ RemoteChainSelector uint64
+ LocalToken common.Address
+}
+
+type MultiAggregateRateLimiterRateLimitTokenArgs struct {
+ LocalTokenArgs MultiAggregateRateLimiterLocalRateLimitToken
+ RemoteToken [32]byte
+}
+
+type MultiAggregateRateLimiterRateLimiterConfigArgs struct {
+ RemoteChainSelector uint64
+ IsOutboundLane bool
+ RateLimiterConfig RateLimiterConfig
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+var MultiAggregateRateLimiterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"priceRegistry\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"authorizedCallers\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"errorReason\",\"type\":\"bytes\"}],\"name\":\"MessageValidationError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"PriceNotFoundForToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"UnauthorizedCaller\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroChainSelectorNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AuthorizedCallerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AuthorizedCallerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"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\":false,\"internalType\":\"address\",\"name\":\"newPriceRegistry\",\"type\":\"address\"}],\"name\":\"PriceRegistrySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isOutboundLane\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"RateLimiterConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"remoteToken\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"name\":\"TokenAggregateRateLimitAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"name\":\"TokenAggregateRateLimitRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address[]\",\"name\":\"addedCallers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"removedCallers\",\"type\":\"address[]\"}],\"internalType\":\"structAuthorizedCallers.AuthorizedCallerArgs\",\"name\":\"authorizedCallerArgs\",\"type\":\"tuple\"}],\"name\":\"applyAuthorizedCallerUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"isOutboundLane\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structMultiAggregateRateLimiter.RateLimiterConfigArgs[]\",\"name\":\"rateLimiterUpdates\",\"type\":\"tuple[]\"}],\"name\":\"applyRateLimiterConfigUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"isOutboundLane\",\"type\":\"bool\"}],\"name\":\"currentRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAuthorizedCallers\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getAllRateLimitTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"localTokens\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"remoteTokens\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPriceRegistry\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"onInboundMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"onOutboundMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newPriceRegistry\",\"type\":\"address\"}],\"name\":\"setPriceRegistry\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structMultiAggregateRateLimiter.LocalRateLimitToken[]\",\"name\":\"removes\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structMultiAggregateRateLimiter.LocalRateLimitToken\",\"name\":\"localTokenArgs\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"remoteToken\",\"type\":\"bytes32\"}],\"internalType\":\"structMultiAggregateRateLimiter.RateLimitTokenArgs[]\",\"name\":\"adds\",\"type\":\"tuple[]\"}],\"name\":\"updateRateLimitTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60806040523480156200001157600080fd5b5060405162002e2f38038062002e2f833981016040819052620000349162000538565b8033806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf8162000102565b5050604080518082018252838152815160008152602080820190935291810191909152620000ee9150620001ad565b50620000fa82620002fc565b50506200066f565b336001600160a01b038216036200015c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b602081015160005b81518110156200023d576000828281518110620001d657620001d662000621565b60209081029190910101519050620001f060028262000378565b1562000233576040516001600160a01b03821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b50600101620001b5565b50815160005b8151811015620002f657600082828151811062000264576200026462000621565b6020026020010151905060006001600160a01b0316816001600160a01b031603620002a2576040516342bcdf7f60e11b815260040160405180910390fd5b620002af60028262000398565b506040516001600160a01b03821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a15060010162000243565b50505050565b6001600160a01b03811662000324576040516342bcdf7f60e11b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527fdeaac1a8daeabcc5254b10b54edf3678fdfcd1cea89fe9d364b6285f6ace2df99060200160405180910390a150565b60006200038f836001600160a01b038416620003af565b90505b92915050565b60006200038f836001600160a01b038416620004b3565b60008181526001830160205260408120548015620004a8576000620003d660018362000637565b8554909150600090620003ec9060019062000637565b90508181146200045857600086600001828154811062000410576200041062000621565b906000526020600020015490508087600001848154811062000436576200043662000621565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806200046c576200046c62000659565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000392565b600091505062000392565b6000818152600183016020526040812054620004fc5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000392565b50600062000392565b80516001600160a01b03811681146200051d57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200054c57600080fd5b620005578362000505565b602084810151919350906001600160401b03808211156200057757600080fd5b818601915086601f8301126200058c57600080fd5b815181811115620005a157620005a162000522565b8060051b604051601f19603f83011681018181108582111715620005c957620005c962000522565b604052918252848201925083810185019189831115620005e857600080fd5b938501935b828510156200061157620006018562000505565b84529385019392850192620005ed565b8096505050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b818103818111156200039257634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b6127b0806200067f6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806379ba50971161008c57806391a2749a1161006657806391a2749a14610232578063e0a0e50614610245578063f2fde38b14610258578063fe843cd01461026b57600080fd5b806379ba5097146101f95780637c8b5e9a146102015780638da5cb5b1461021457600080fd5b80632451a627116100bd5780632451a627146101b0578063508ee9de146101c5578063537e304e146101d857600080fd5b806308d450a1146100e45780630a35bcc4146100f95780630d6c107e14610171575b600080fd5b6100f76100f2366004611ef5565b61027e565b005b61010c610107366004611fd5565b61029d565b604051610168919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60405180910390f35b60055473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610168565b6101b8610362565b604051610168919061205a565b6100f76101d336600461206d565b610373565b6101eb6101e6366004612088565b610384565b6040516101689291906120a3565b6100f76104e7565b6100f761020f3660046121c4565b6105e9565b60005473ffffffffffffffffffffffffffffffffffffffff1661018b565b6100f76102403660046122f5565b610838565b6100f7610253366004612386565b610849565b6100f761026636600461206d565b6108be565b6100f76102793660046123fb565b6108cf565b610286610c0e565b61029a816020015182608001516000610c53565b50565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526103596102d58484610d2a565b6040805160a08101825282546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff1660208501527401000000000000000000000000000000000000000090920460ff16151593830193909352600190930154808316606083015292909204166080820152610d5a565b90505b92915050565b606061036e6002610e0c565b905090565b61037b610e20565b61029a81610ea1565b67ffffffffffffffff8116600090815260046020526040812060609182916103ab90610f67565b90508067ffffffffffffffff8111156103c6576103c6611c66565b6040519080825280602002602001820160405280156103ef578160200160208202803683370190505b5092508067ffffffffffffffff81111561040b5761040b611c66565b604051908082528060200260200182016040528015610434578160200160208202803683370190505b50915060005b818110156104e05767ffffffffffffffff8516600090815260046020526040812081906104679084610f72565b915091508186848151811061047e5761047e61252f565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050808584815181106104cb576104cb61252f565b6020908102919091010152505060010161043a565b5050915091565b60015473ffffffffffffffffffffffffffffffffffffffff16331461056d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6105f1610e20565b60005b82518110156106cf5760008382815181106106115761061161252f565b602002602001015160200151905060008483815181106106335761063361252f565b6020908102919091018101515167ffffffffffffffff81166000908152600490925260409091209091506106679083610f90565b156106c5576040805167ffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff841660208201527f530cabd30786b7235e124a6c0db77e0b685ef22813b1fe87554247f404eb8ed6910160405180910390a15b50506001016105f4565b5060005b81518110156108335760008282815181106106f0576106f061252f565b602002602001015160000151905060008383815181106107125761071261252f565b6020026020010151602001519050600082602001519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610762575081155b15610799576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825167ffffffffffffffff811660009081526004602052604090206107bf908385610fb2565b15610824576040805167ffffffffffffffff831681526020810185905273ffffffffffffffffffffffffffffffffffffffff84168183015290517ffd96f5ca8894a9584abba5645131a95480f9340bd5e0046ceff789111ff16c6d9181900360600190a15b505050508060010190506106d3565b505050565b610840610e20565b61029a81610fdd565b610851610c0e565b6108ba82610862604084018461255e565b808060200260200160405190810160405280939291908181526020016000905b828210156108ae5761089f604083028601368190038101906125c6565b81526020019060010190610882565b50505050506001610c53565b5050565b6108c6610e20565b61029a81611169565b6108d7610e20565b60005b81518110156108ba5760008282815181106108f7576108f761252f565b6020908102919091010151604081015181519192509067ffffffffffffffff8116600003610951576040517fc656089500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602083015160006109628383610d2a565b8054909150700100000000000000000000000000000000900463ffffffff16600003610bb0576040805160a081018252602080870180516fffffffffffffffffffffffffffffffff908116845263ffffffff421692840192909252875115158385015251811660608301529186015190911660808201528215610ac95767ffffffffffffffff8416600090815260066020908152604091829020835160028201805493860151948601516fffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff00000000000000000000000000000000000000009095169490941770010000000000000000000000000000000063ffffffff9096168602177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000941515949094029390931790925560608401516080850151908316921690920217600390910155610baa565b67ffffffffffffffff84166000908152600660209081526040918290208351815492850151938501516fffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffff00000000000000000000000000000000000000009094169390931770010000000000000000000000000000000063ffffffff9095168502177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000093151593909302929092178155606084015160808501519083169216909202176001909101555b50610bba565b610bba818561125e565b8267ffffffffffffffff167ff14a5415ce6988a9e870a85fff0b9d7b7dd79bbc228cb63cad610daf6f7b6b978386604051610bf69291906125e2565b60405180910390a250505050508060010190506108da565b610c1960023361140d565b610c51576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610564565b565b6000610c5f8483610d2a565b805490915074010000000000000000000000000000000000000000900460ff1615610d24576000805b8451811015610d0f57610cd3858281518110610ca657610ca661252f565b6020908102919091018101515167ffffffffffffffff89166000908152600490925260409091209061143c565b15610d0757610cfa858281518110610ced57610ced61252f565b602002602001015161145e565b610d049083612655565b91505b600101610c88565b508015610d2257610d228282600061159a565b505b50505050565b67ffffffffffffffff821660009081526006602052604081208215610d5357600201905061035c565b905061035c565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152610de882606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff1642610dcc9190612668565b85608001516fffffffffffffffffffffffffffffffff1661191d565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b60606000610e1983611945565b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610564565b73ffffffffffffffffffffffffffffffffffffffff8116610eee576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fdeaac1a8daeabcc5254b10b54edf3678fdfcd1cea89fe9d364b6285f6ace2df99060200160405180910390a150565b600061035c826119a1565b6000808080610f8186866119ac565b909450925050505b9250929050565b60006103598373ffffffffffffffffffffffffffffffffffffffff84166119d7565b6000610fd58473ffffffffffffffffffffffffffffffffffffffff8516846119f4565b949350505050565b602081015160005b81518110156110785760008282815181106110025761100261252f565b60200260200101519050611020816002611a1190919063ffffffff16565b1561106f5760405173ffffffffffffffffffffffffffffffffffffffff821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b50600101610fe5565b50815160005b8151811015610d2457600082828151811061109b5761109b61252f565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361110b576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611116600282611a33565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a15060010161107e565b3373ffffffffffffffffffffffffffffffffffffffff8216036111e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610564565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b815460009061128790700100000000000000000000000000000000900463ffffffff1642612668565b9050801561132957600183015483546112cf916fffffffffffffffffffffffffffffffff8082169281169185917001000000000000000000000000000000009091041661191d565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b6020820151835461134f916fffffffffffffffffffffffffffffffff9081169116611a55565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199061140090849061267b565b60405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515610359565b60006103598373ffffffffffffffffffffffffffffffffffffffff8416611a6b565b60055481516040517fd02641a000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000928392169063d02641a0906024016040805180830381865afa1580156114d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f691906126b7565b5190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660000361156c5782516040517f9a655f7b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610564565b6020830151610e19907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff831690611a77565b825474010000000000000000000000000000000000000000900460ff1615806115c1575081155b156115cb57505050565b825460018401546fffffffffffffffffffffffffffffffff8083169291169060009061161190700100000000000000000000000000000000900463ffffffff1642612668565b905080156116d15781831115611653576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600186015461168d9083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1661191d565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156117885773ffffffffffffffffffffffffffffffffffffffff8416611730576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610564565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff85166044820152606401610564565b8483101561189b5760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906117cc9082612668565b6117d6878a612668565b6117e09190612655565b6117ea9190612722565b905073ffffffffffffffffffffffffffffffffffffffff8616611843576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610564565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff87166044820152606401610564565b6118a58584612668565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b600061193c8561192d848661275d565b6119379087612655565b611a55565b95945050505050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561199557602002820191906000526020600020905b815481526020019060010190808311611981575b50505050509050919050565b600061035c82611ab4565b600080806119ba8585611abe565b600081815260029690960160205260409095205494959350505050565b600081815260028301602052604081208190556103598383611aca565b60008281526002840160205260408120829055610fd58484611ad6565b60006103598373ffffffffffffffffffffffffffffffffffffffff8416611ae2565b60006103598373ffffffffffffffffffffffffffffffffffffffff8416611bd5565b6000818310611a645781610359565b5090919050565b60006103598383611c24565b6000670de0b6b3a7640000611aaa837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff861661275d565b6103599190612722565b600061035c825490565b60006103598383611c3c565b60006103598383611ae2565b60006103598383611bd5565b60008181526001830160205260408120548015611bcb576000611b06600183612668565b8554909150600090611b1a90600190612668565b9050818114611b7f576000866000018281548110611b3a57611b3a61252f565b9060005260206000200154905080876000018481548110611b5d57611b5d61252f565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611b9057611b90612774565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061035c565b600091505061035c565b6000818152600183016020526040812054611c1c5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561035c565b50600061035c565b60008181526001830160205260408120541515610359565b6000826000018281548110611c5357611c5361252f565b9060005260206000200154905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611cb857611cb8611c66565b60405290565b60405160a0810167ffffffffffffffff81118282101715611cb857611cb8611c66565b6040516060810167ffffffffffffffff81118282101715611cb857611cb8611c66565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d4b57611d4b611c66565b604052919050565b803567ffffffffffffffff81168114611d6b57600080fd5b919050565b600082601f830112611d8157600080fd5b813567ffffffffffffffff811115611d9b57611d9b611c66565b611dcc60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611d04565b818152846020838601011115611de157600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff821115611e1857611e18611c66565b5060051b60200190565b803573ffffffffffffffffffffffffffffffffffffffff81168114611d6b57600080fd5b600060408284031215611e5857600080fd5b611e60611c95565b9050611e6b82611e22565b81526020820135602082015292915050565b600082601f830112611e8e57600080fd5b81356020611ea3611e9e83611dfe565b611d04565b8083825260208201915060208460061b870101935086841115611ec557600080fd5b602086015b84811015611eea57611edc8882611e46565b835291830191604001611eca565b509695505050505050565b600060208284031215611f0757600080fd5b813567ffffffffffffffff80821115611f1f57600080fd5b9083019060a08286031215611f3357600080fd5b611f3b611cbe565b82358152611f4b60208401611d53565b6020820152604083013582811115611f6257600080fd5b611f6e87828601611d70565b604083015250606083013582811115611f8657600080fd5b611f9287828601611d70565b606083015250608083013582811115611faa57600080fd5b611fb687828601611e7d565b60808301525095945050505050565b80358015158114611d6b57600080fd5b60008060408385031215611fe857600080fd5b611ff183611d53565b9150611fff60208401611fc5565b90509250929050565b60008151808452602080850194506020840160005b8381101561204f57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161201d565b509495945050505050565b6020815260006103596020830184612008565b60006020828403121561207f57600080fd5b61035982611e22565b60006020828403121561209a57600080fd5b61035982611d53565b6040815260006120b66040830185612008565b82810360208481019190915284518083528582019282019060005b818110156120ed578451835293830193918301916001016120d1565b5090979650505050505050565b60006040828403121561210c57600080fd5b612114611c95565b905061211f82611d53565b815261212d60208301611e22565b602082015292915050565b600082601f83011261214957600080fd5b81356020612159611e9e83611dfe565b80838252602082019150606060206060860288010194508785111561217d57600080fd5b602087015b858110156120ed5781818a03121561219a5760008081fd5b6121a2611c95565b6121ac8a836120fa565b81526040820135868201528452928401928101612182565b60008060408084860312156121d857600080fd5b833567ffffffffffffffff808211156121f057600080fd5b818601915086601f83011261220457600080fd5b81356020612214611e9e83611dfe565b8083825260208201915060208460061b87010193508a84111561223657600080fd5b6020860195505b8386101561225e5761224f8b876120fa565b8252948601949082019061223d565b9750505050602086013592508083111561227757600080fd5b505061228585828601612138565b9150509250929050565b600082601f8301126122a057600080fd5b813560206122b0611e9e83611dfe565b8083825260208201915060208460051b8701019350868411156122d257600080fd5b602086015b84811015611eea576122e881611e22565b83529183019183016122d7565b60006020828403121561230757600080fd5b813567ffffffffffffffff8082111561231f57600080fd5b908301906040828603121561233357600080fd5b61233b611c95565b82358281111561234a57600080fd5b6123568782860161228f565b82525060208301358281111561236b57600080fd5b6123778782860161228f565b60208301525095945050505050565b6000806040838503121561239957600080fd5b6123a283611d53565b9150602083013567ffffffffffffffff8111156123be57600080fd5b830160a081860312156123d057600080fd5b809150509250929050565b80356fffffffffffffffffffffffffffffffff81168114611d6b57600080fd5b6000602080838503121561240e57600080fd5b823567ffffffffffffffff81111561242557600080fd5b8301601f8101851361243657600080fd5b8035612444611e9e82611dfe565b81815260a0918202830184019184820191908884111561246357600080fd5b938501935b8385101561252357848903818112156124815760008081fd5b612489611ce1565b61249287611d53565b815261249f888801611fc5565b8882015260406060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0850112156124d75760008081fd5b6124df611ce1565b93506124ec828a01611fc5565b84526124f9818a016123db565b8a8501525061250a608089016123db565b8382015281019190915283529384019391850191612468565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261259357600080fd5b83018035915067ffffffffffffffff8211156125ae57600080fd5b6020019150600681901b3603821315610f8957600080fd5b6000604082840312156125d857600080fd5b6103598383611e46565b821515815260808101610e1960208301848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561035c5761035c612626565b8181038181111561035c5761035c612626565b6060810161035c82848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b6000604082840312156126c957600080fd5b6126d1611c95565b82517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146126fd57600080fd5b8152602083015163ffffffff8116811461271657600080fd5b60208201529392505050565b600082612758577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b808202811582820484141761035c5761035c612626565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a",
+}
+
+var MultiAggregateRateLimiterABI = MultiAggregateRateLimiterMetaData.ABI
+
+var MultiAggregateRateLimiterBin = MultiAggregateRateLimiterMetaData.Bin
+
+func DeployMultiAggregateRateLimiter(auth *bind.TransactOpts, backend bind.ContractBackend, priceRegistry common.Address, authorizedCallers []common.Address) (common.Address, *types.Transaction, *MultiAggregateRateLimiter, error) {
+ parsed, err := MultiAggregateRateLimiterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MultiAggregateRateLimiterBin), backend, priceRegistry, authorizedCallers)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MultiAggregateRateLimiter{address: address, abi: *parsed, MultiAggregateRateLimiterCaller: MultiAggregateRateLimiterCaller{contract: contract}, MultiAggregateRateLimiterTransactor: MultiAggregateRateLimiterTransactor{contract: contract}, MultiAggregateRateLimiterFilterer: MultiAggregateRateLimiterFilterer{contract: contract}}, nil
+}
+
+type MultiAggregateRateLimiter struct {
+ address common.Address
+ abi abi.ABI
+ MultiAggregateRateLimiterCaller
+ MultiAggregateRateLimiterTransactor
+ MultiAggregateRateLimiterFilterer
+}
+
+type MultiAggregateRateLimiterCaller struct {
+ contract *bind.BoundContract
+}
+
+type MultiAggregateRateLimiterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MultiAggregateRateLimiterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MultiAggregateRateLimiterSession struct {
+ Contract *MultiAggregateRateLimiter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MultiAggregateRateLimiterCallerSession struct {
+ Contract *MultiAggregateRateLimiterCaller
+ CallOpts bind.CallOpts
+}
+
+type MultiAggregateRateLimiterTransactorSession struct {
+ Contract *MultiAggregateRateLimiterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MultiAggregateRateLimiterRaw struct {
+ Contract *MultiAggregateRateLimiter
+}
+
+type MultiAggregateRateLimiterCallerRaw struct {
+ Contract *MultiAggregateRateLimiterCaller
+}
+
+type MultiAggregateRateLimiterTransactorRaw struct {
+ Contract *MultiAggregateRateLimiterTransactor
+}
+
+func NewMultiAggregateRateLimiter(address common.Address, backend bind.ContractBackend) (*MultiAggregateRateLimiter, error) {
+ abi, err := abi.JSON(strings.NewReader(MultiAggregateRateLimiterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMultiAggregateRateLimiter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiter{address: address, abi: abi, MultiAggregateRateLimiterCaller: MultiAggregateRateLimiterCaller{contract: contract}, MultiAggregateRateLimiterTransactor: MultiAggregateRateLimiterTransactor{contract: contract}, MultiAggregateRateLimiterFilterer: MultiAggregateRateLimiterFilterer{contract: contract}}, nil
+}
+
+func NewMultiAggregateRateLimiterCaller(address common.Address, caller bind.ContractCaller) (*MultiAggregateRateLimiterCaller, error) {
+ contract, err := bindMultiAggregateRateLimiter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterCaller{contract: contract}, nil
+}
+
+func NewMultiAggregateRateLimiterTransactor(address common.Address, transactor bind.ContractTransactor) (*MultiAggregateRateLimiterTransactor, error) {
+ contract, err := bindMultiAggregateRateLimiter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterTransactor{contract: contract}, nil
+}
+
+func NewMultiAggregateRateLimiterFilterer(address common.Address, filterer bind.ContractFilterer) (*MultiAggregateRateLimiterFilterer, error) {
+ contract, err := bindMultiAggregateRateLimiter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterFilterer{contract: contract}, nil
+}
+
+func bindMultiAggregateRateLimiter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MultiAggregateRateLimiterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MultiAggregateRateLimiter.Contract.MultiAggregateRateLimiterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.MultiAggregateRateLimiterTransactor.contract.Transfer(opts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.MultiAggregateRateLimiterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MultiAggregateRateLimiter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.contract.Transfer(opts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCaller) CurrentRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64, isOutboundLane bool) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _MultiAggregateRateLimiter.contract.Call(opts, &out, "currentRateLimiterState", remoteChainSelector, isOutboundLane)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) CurrentRateLimiterState(remoteChainSelector uint64, isOutboundLane bool) (RateLimiterTokenBucket, error) {
+ return _MultiAggregateRateLimiter.Contract.CurrentRateLimiterState(&_MultiAggregateRateLimiter.CallOpts, remoteChainSelector, isOutboundLane)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCallerSession) CurrentRateLimiterState(remoteChainSelector uint64, isOutboundLane bool) (RateLimiterTokenBucket, error) {
+ return _MultiAggregateRateLimiter.Contract.CurrentRateLimiterState(&_MultiAggregateRateLimiter.CallOpts, remoteChainSelector, isOutboundLane)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCaller) GetAllAuthorizedCallers(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _MultiAggregateRateLimiter.contract.Call(opts, &out, "getAllAuthorizedCallers")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) GetAllAuthorizedCallers() ([]common.Address, error) {
+ return _MultiAggregateRateLimiter.Contract.GetAllAuthorizedCallers(&_MultiAggregateRateLimiter.CallOpts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCallerSession) GetAllAuthorizedCallers() ([]common.Address, error) {
+ return _MultiAggregateRateLimiter.Contract.GetAllAuthorizedCallers(&_MultiAggregateRateLimiter.CallOpts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCaller) GetAllRateLimitTokens(opts *bind.CallOpts, remoteChainSelector uint64) (GetAllRateLimitTokens,
+
+ error) {
+ var out []interface{}
+ err := _MultiAggregateRateLimiter.contract.Call(opts, &out, "getAllRateLimitTokens", remoteChainSelector)
+
+ outstruct := new(GetAllRateLimitTokens)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.LocalTokens = *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+ outstruct.RemoteTokens = *abi.ConvertType(out[1], new([][32]byte)).(*[][32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) GetAllRateLimitTokens(remoteChainSelector uint64) (GetAllRateLimitTokens,
+
+ error) {
+ return _MultiAggregateRateLimiter.Contract.GetAllRateLimitTokens(&_MultiAggregateRateLimiter.CallOpts, remoteChainSelector)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCallerSession) GetAllRateLimitTokens(remoteChainSelector uint64) (GetAllRateLimitTokens,
+
+ error) {
+ return _MultiAggregateRateLimiter.Contract.GetAllRateLimitTokens(&_MultiAggregateRateLimiter.CallOpts, remoteChainSelector)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCaller) GetPriceRegistry(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _MultiAggregateRateLimiter.contract.Call(opts, &out, "getPriceRegistry")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) GetPriceRegistry() (common.Address, error) {
+ return _MultiAggregateRateLimiter.Contract.GetPriceRegistry(&_MultiAggregateRateLimiter.CallOpts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCallerSession) GetPriceRegistry() (common.Address, error) {
+ return _MultiAggregateRateLimiter.Contract.GetPriceRegistry(&_MultiAggregateRateLimiter.CallOpts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _MultiAggregateRateLimiter.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) Owner() (common.Address, error) {
+ return _MultiAggregateRateLimiter.Contract.Owner(&_MultiAggregateRateLimiter.CallOpts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterCallerSession) Owner() (common.Address, error) {
+ return _MultiAggregateRateLimiter.Contract.Owner(&_MultiAggregateRateLimiter.CallOpts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) AcceptOwnership() (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.AcceptOwnership(&_MultiAggregateRateLimiter.TransactOpts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.AcceptOwnership(&_MultiAggregateRateLimiter.TransactOpts)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactor) ApplyAuthorizedCallerUpdates(opts *bind.TransactOpts, authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.contract.Transact(opts, "applyAuthorizedCallerUpdates", authorizedCallerArgs)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) ApplyAuthorizedCallerUpdates(authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.ApplyAuthorizedCallerUpdates(&_MultiAggregateRateLimiter.TransactOpts, authorizedCallerArgs)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorSession) ApplyAuthorizedCallerUpdates(authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.ApplyAuthorizedCallerUpdates(&_MultiAggregateRateLimiter.TransactOpts, authorizedCallerArgs)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactor) ApplyRateLimiterConfigUpdates(opts *bind.TransactOpts, rateLimiterUpdates []MultiAggregateRateLimiterRateLimiterConfigArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.contract.Transact(opts, "applyRateLimiterConfigUpdates", rateLimiterUpdates)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) ApplyRateLimiterConfigUpdates(rateLimiterUpdates []MultiAggregateRateLimiterRateLimiterConfigArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.ApplyRateLimiterConfigUpdates(&_MultiAggregateRateLimiter.TransactOpts, rateLimiterUpdates)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorSession) ApplyRateLimiterConfigUpdates(rateLimiterUpdates []MultiAggregateRateLimiterRateLimiterConfigArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.ApplyRateLimiterConfigUpdates(&_MultiAggregateRateLimiter.TransactOpts, rateLimiterUpdates)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactor) OnInboundMessage(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.contract.Transact(opts, "onInboundMessage", message)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) OnInboundMessage(message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.OnInboundMessage(&_MultiAggregateRateLimiter.TransactOpts, message)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorSession) OnInboundMessage(message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.OnInboundMessage(&_MultiAggregateRateLimiter.TransactOpts, message)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactor) OnOutboundMessage(opts *bind.TransactOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.contract.Transact(opts, "onOutboundMessage", destChainSelector, message)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) OnOutboundMessage(destChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.OnOutboundMessage(&_MultiAggregateRateLimiter.TransactOpts, destChainSelector, message)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorSession) OnOutboundMessage(destChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.OnOutboundMessage(&_MultiAggregateRateLimiter.TransactOpts, destChainSelector, message)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactor) SetPriceRegistry(opts *bind.TransactOpts, newPriceRegistry common.Address) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.contract.Transact(opts, "setPriceRegistry", newPriceRegistry)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) SetPriceRegistry(newPriceRegistry common.Address) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.SetPriceRegistry(&_MultiAggregateRateLimiter.TransactOpts, newPriceRegistry)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorSession) SetPriceRegistry(newPriceRegistry common.Address) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.SetPriceRegistry(&_MultiAggregateRateLimiter.TransactOpts, newPriceRegistry)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.TransferOwnership(&_MultiAggregateRateLimiter.TransactOpts, to)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.TransferOwnership(&_MultiAggregateRateLimiter.TransactOpts, to)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactor) UpdateRateLimitTokens(opts *bind.TransactOpts, removes []MultiAggregateRateLimiterLocalRateLimitToken, adds []MultiAggregateRateLimiterRateLimitTokenArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.contract.Transact(opts, "updateRateLimitTokens", removes, adds)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterSession) UpdateRateLimitTokens(removes []MultiAggregateRateLimiterLocalRateLimitToken, adds []MultiAggregateRateLimiterRateLimitTokenArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.UpdateRateLimitTokens(&_MultiAggregateRateLimiter.TransactOpts, removes, adds)
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterTransactorSession) UpdateRateLimitTokens(removes []MultiAggregateRateLimiterLocalRateLimitToken, adds []MultiAggregateRateLimiterRateLimitTokenArgs) (*types.Transaction, error) {
+ return _MultiAggregateRateLimiter.Contract.UpdateRateLimitTokens(&_MultiAggregateRateLimiter.TransactOpts, removes, adds)
+}
+
+type MultiAggregateRateLimiterAuthorizedCallerAddedIterator struct {
+ Event *MultiAggregateRateLimiterAuthorizedCallerAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterAuthorizedCallerAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterAuthorizedCallerAdded)
+ 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(MultiAggregateRateLimiterAuthorizedCallerAdded)
+ 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 *MultiAggregateRateLimiterAuthorizedCallerAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterAuthorizedCallerAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterAuthorizedCallerAdded struct {
+ Caller common.Address
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterAuthorizedCallerAdded(opts *bind.FilterOpts) (*MultiAggregateRateLimiterAuthorizedCallerAddedIterator, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "AuthorizedCallerAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterAuthorizedCallerAddedIterator{contract: _MultiAggregateRateLimiter.contract, event: "AuthorizedCallerAdded", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchAuthorizedCallerAdded(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterAuthorizedCallerAdded) (event.Subscription, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "AuthorizedCallerAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterAuthorizedCallerAdded)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "AuthorizedCallerAdded", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseAuthorizedCallerAdded(log types.Log) (*MultiAggregateRateLimiterAuthorizedCallerAdded, error) {
+ event := new(MultiAggregateRateLimiterAuthorizedCallerAdded)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "AuthorizedCallerAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterAuthorizedCallerRemovedIterator struct {
+ Event *MultiAggregateRateLimiterAuthorizedCallerRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterAuthorizedCallerRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterAuthorizedCallerRemoved)
+ 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(MultiAggregateRateLimiterAuthorizedCallerRemoved)
+ 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 *MultiAggregateRateLimiterAuthorizedCallerRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterAuthorizedCallerRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterAuthorizedCallerRemoved struct {
+ Caller common.Address
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterAuthorizedCallerRemoved(opts *bind.FilterOpts) (*MultiAggregateRateLimiterAuthorizedCallerRemovedIterator, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "AuthorizedCallerRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterAuthorizedCallerRemovedIterator{contract: _MultiAggregateRateLimiter.contract, event: "AuthorizedCallerRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchAuthorizedCallerRemoved(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterAuthorizedCallerRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "AuthorizedCallerRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterAuthorizedCallerRemoved)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "AuthorizedCallerRemoved", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseAuthorizedCallerRemoved(log types.Log) (*MultiAggregateRateLimiterAuthorizedCallerRemoved, error) {
+ event := new(MultiAggregateRateLimiterAuthorizedCallerRemoved)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "AuthorizedCallerRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterConfigChangedIterator struct {
+ Event *MultiAggregateRateLimiterConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterConfigChanged)
+ 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(MultiAggregateRateLimiterConfigChanged)
+ 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 *MultiAggregateRateLimiterConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*MultiAggregateRateLimiterConfigChangedIterator, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterConfigChangedIterator{contract: _MultiAggregateRateLimiter.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterConfigChanged)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "ConfigChanged", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseConfigChanged(log types.Log) (*MultiAggregateRateLimiterConfigChanged, error) {
+ event := new(MultiAggregateRateLimiterConfigChanged)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterOwnershipTransferRequestedIterator struct {
+ Event *MultiAggregateRateLimiterOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterOwnershipTransferRequested)
+ 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(MultiAggregateRateLimiterOwnershipTransferRequested)
+ 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 *MultiAggregateRateLimiterOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MultiAggregateRateLimiterOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterOwnershipTransferRequestedIterator{contract: _MultiAggregateRateLimiter.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterOwnershipTransferRequested)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseOwnershipTransferRequested(log types.Log) (*MultiAggregateRateLimiterOwnershipTransferRequested, error) {
+ event := new(MultiAggregateRateLimiterOwnershipTransferRequested)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterOwnershipTransferredIterator struct {
+ Event *MultiAggregateRateLimiterOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterOwnershipTransferred)
+ 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(MultiAggregateRateLimiterOwnershipTransferred)
+ 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 *MultiAggregateRateLimiterOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MultiAggregateRateLimiterOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterOwnershipTransferredIterator{contract: _MultiAggregateRateLimiter.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterOwnershipTransferred)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "OwnershipTransferred", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseOwnershipTransferred(log types.Log) (*MultiAggregateRateLimiterOwnershipTransferred, error) {
+ event := new(MultiAggregateRateLimiterOwnershipTransferred)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterPriceRegistrySetIterator struct {
+ Event *MultiAggregateRateLimiterPriceRegistrySet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterPriceRegistrySetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterPriceRegistrySet)
+ 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(MultiAggregateRateLimiterPriceRegistrySet)
+ 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 *MultiAggregateRateLimiterPriceRegistrySetIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterPriceRegistrySetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterPriceRegistrySet struct {
+ NewPriceRegistry common.Address
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterPriceRegistrySet(opts *bind.FilterOpts) (*MultiAggregateRateLimiterPriceRegistrySetIterator, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "PriceRegistrySet")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterPriceRegistrySetIterator{contract: _MultiAggregateRateLimiter.contract, event: "PriceRegistrySet", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchPriceRegistrySet(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterPriceRegistrySet) (event.Subscription, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "PriceRegistrySet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterPriceRegistrySet)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "PriceRegistrySet", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParsePriceRegistrySet(log types.Log) (*MultiAggregateRateLimiterPriceRegistrySet, error) {
+ event := new(MultiAggregateRateLimiterPriceRegistrySet)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "PriceRegistrySet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterRateLimiterConfigUpdatedIterator struct {
+ Event *MultiAggregateRateLimiterRateLimiterConfigUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterRateLimiterConfigUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterRateLimiterConfigUpdated)
+ 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(MultiAggregateRateLimiterRateLimiterConfigUpdated)
+ 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 *MultiAggregateRateLimiterRateLimiterConfigUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterRateLimiterConfigUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterRateLimiterConfigUpdated struct {
+ RemoteChainSelector uint64
+ IsOutboundLane bool
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterRateLimiterConfigUpdated(opts *bind.FilterOpts, remoteChainSelector []uint64) (*MultiAggregateRateLimiterRateLimiterConfigUpdatedIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "RateLimiterConfigUpdated", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterRateLimiterConfigUpdatedIterator{contract: _MultiAggregateRateLimiter.contract, event: "RateLimiterConfigUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchRateLimiterConfigUpdated(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterRateLimiterConfigUpdated, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "RateLimiterConfigUpdated", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterRateLimiterConfigUpdated)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "RateLimiterConfigUpdated", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseRateLimiterConfigUpdated(log types.Log) (*MultiAggregateRateLimiterRateLimiterConfigUpdated, error) {
+ event := new(MultiAggregateRateLimiterRateLimiterConfigUpdated)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "RateLimiterConfigUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterTokenAggregateRateLimitAddedIterator struct {
+ Event *MultiAggregateRateLimiterTokenAggregateRateLimitAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterTokenAggregateRateLimitAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterTokenAggregateRateLimitAdded)
+ 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(MultiAggregateRateLimiterTokenAggregateRateLimitAdded)
+ 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 *MultiAggregateRateLimiterTokenAggregateRateLimitAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterTokenAggregateRateLimitAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterTokenAggregateRateLimitAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken [32]byte
+ LocalToken common.Address
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterTokenAggregateRateLimitAdded(opts *bind.FilterOpts) (*MultiAggregateRateLimiterTokenAggregateRateLimitAddedIterator, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "TokenAggregateRateLimitAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterTokenAggregateRateLimitAddedIterator{contract: _MultiAggregateRateLimiter.contract, event: "TokenAggregateRateLimitAdded", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchTokenAggregateRateLimitAdded(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterTokenAggregateRateLimitAdded) (event.Subscription, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "TokenAggregateRateLimitAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterTokenAggregateRateLimitAdded)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "TokenAggregateRateLimitAdded", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseTokenAggregateRateLimitAdded(log types.Log) (*MultiAggregateRateLimiterTokenAggregateRateLimitAdded, error) {
+ event := new(MultiAggregateRateLimiterTokenAggregateRateLimitAdded)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "TokenAggregateRateLimitAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterTokenAggregateRateLimitRemovedIterator struct {
+ Event *MultiAggregateRateLimiterTokenAggregateRateLimitRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterTokenAggregateRateLimitRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterTokenAggregateRateLimitRemoved)
+ 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(MultiAggregateRateLimiterTokenAggregateRateLimitRemoved)
+ 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 *MultiAggregateRateLimiterTokenAggregateRateLimitRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterTokenAggregateRateLimitRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterTokenAggregateRateLimitRemoved struct {
+ RemoteChainSelector uint64
+ LocalToken common.Address
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterTokenAggregateRateLimitRemoved(opts *bind.FilterOpts) (*MultiAggregateRateLimiterTokenAggregateRateLimitRemovedIterator, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "TokenAggregateRateLimitRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterTokenAggregateRateLimitRemovedIterator{contract: _MultiAggregateRateLimiter.contract, event: "TokenAggregateRateLimitRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchTokenAggregateRateLimitRemoved(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterTokenAggregateRateLimitRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "TokenAggregateRateLimitRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterTokenAggregateRateLimitRemoved)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "TokenAggregateRateLimitRemoved", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseTokenAggregateRateLimitRemoved(log types.Log) (*MultiAggregateRateLimiterTokenAggregateRateLimitRemoved, error) {
+ event := new(MultiAggregateRateLimiterTokenAggregateRateLimitRemoved)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "TokenAggregateRateLimitRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiAggregateRateLimiterTokensConsumedIterator struct {
+ Event *MultiAggregateRateLimiterTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiAggregateRateLimiterTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiAggregateRateLimiterTokensConsumed)
+ 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(MultiAggregateRateLimiterTokensConsumed)
+ 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 *MultiAggregateRateLimiterTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiAggregateRateLimiterTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiAggregateRateLimiterTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*MultiAggregateRateLimiterTokensConsumedIterator, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiAggregateRateLimiterTokensConsumedIterator{contract: _MultiAggregateRateLimiter.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _MultiAggregateRateLimiter.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiAggregateRateLimiterTokensConsumed)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "TokensConsumed", 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 (_MultiAggregateRateLimiter *MultiAggregateRateLimiterFilterer) ParseTokensConsumed(log types.Log) (*MultiAggregateRateLimiterTokensConsumed, error) {
+ event := new(MultiAggregateRateLimiterTokensConsumed)
+ if err := _MultiAggregateRateLimiter.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetAllRateLimitTokens struct {
+ LocalTokens []common.Address
+ RemoteTokens [][32]byte
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiter) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _MultiAggregateRateLimiter.abi.Events["AuthorizedCallerAdded"].ID:
+ return _MultiAggregateRateLimiter.ParseAuthorizedCallerAdded(log)
+ case _MultiAggregateRateLimiter.abi.Events["AuthorizedCallerRemoved"].ID:
+ return _MultiAggregateRateLimiter.ParseAuthorizedCallerRemoved(log)
+ case _MultiAggregateRateLimiter.abi.Events["ConfigChanged"].ID:
+ return _MultiAggregateRateLimiter.ParseConfigChanged(log)
+ case _MultiAggregateRateLimiter.abi.Events["OwnershipTransferRequested"].ID:
+ return _MultiAggregateRateLimiter.ParseOwnershipTransferRequested(log)
+ case _MultiAggregateRateLimiter.abi.Events["OwnershipTransferred"].ID:
+ return _MultiAggregateRateLimiter.ParseOwnershipTransferred(log)
+ case _MultiAggregateRateLimiter.abi.Events["PriceRegistrySet"].ID:
+ return _MultiAggregateRateLimiter.ParsePriceRegistrySet(log)
+ case _MultiAggregateRateLimiter.abi.Events["RateLimiterConfigUpdated"].ID:
+ return _MultiAggregateRateLimiter.ParseRateLimiterConfigUpdated(log)
+ case _MultiAggregateRateLimiter.abi.Events["TokenAggregateRateLimitAdded"].ID:
+ return _MultiAggregateRateLimiter.ParseTokenAggregateRateLimitAdded(log)
+ case _MultiAggregateRateLimiter.abi.Events["TokenAggregateRateLimitRemoved"].ID:
+ return _MultiAggregateRateLimiter.ParseTokenAggregateRateLimitRemoved(log)
+ case _MultiAggregateRateLimiter.abi.Events["TokensConsumed"].ID:
+ return _MultiAggregateRateLimiter.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (MultiAggregateRateLimiterAuthorizedCallerAdded) Topic() common.Hash {
+ return common.HexToHash("0xeb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef")
+}
+
+func (MultiAggregateRateLimiterAuthorizedCallerRemoved) Topic() common.Hash {
+ return common.HexToHash("0xc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda77580")
+}
+
+func (MultiAggregateRateLimiterConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (MultiAggregateRateLimiterOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (MultiAggregateRateLimiterOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (MultiAggregateRateLimiterPriceRegistrySet) Topic() common.Hash {
+ return common.HexToHash("0xdeaac1a8daeabcc5254b10b54edf3678fdfcd1cea89fe9d364b6285f6ace2df9")
+}
+
+func (MultiAggregateRateLimiterRateLimiterConfigUpdated) Topic() common.Hash {
+ return common.HexToHash("0xf14a5415ce6988a9e870a85fff0b9d7b7dd79bbc228cb63cad610daf6f7b6b97")
+}
+
+func (MultiAggregateRateLimiterTokenAggregateRateLimitAdded) Topic() common.Hash {
+ return common.HexToHash("0xfd96f5ca8894a9584abba5645131a95480f9340bd5e0046ceff789111ff16c6d")
+}
+
+func (MultiAggregateRateLimiterTokenAggregateRateLimitRemoved) Topic() common.Hash {
+ return common.HexToHash("0x530cabd30786b7235e124a6c0db77e0b685ef22813b1fe87554247f404eb8ed6")
+}
+
+func (MultiAggregateRateLimiterTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_MultiAggregateRateLimiter *MultiAggregateRateLimiter) Address() common.Address {
+ return _MultiAggregateRateLimiter.address
+}
+
+type MultiAggregateRateLimiterInterface interface {
+ CurrentRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64, isOutboundLane bool) (RateLimiterTokenBucket, error)
+
+ GetAllAuthorizedCallers(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllRateLimitTokens(opts *bind.CallOpts, remoteChainSelector uint64) (GetAllRateLimitTokens,
+
+ error)
+
+ GetPriceRegistry(opts *bind.CallOpts) (common.Address, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAuthorizedCallerUpdates(opts *bind.TransactOpts, authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error)
+
+ ApplyRateLimiterConfigUpdates(opts *bind.TransactOpts, rateLimiterUpdates []MultiAggregateRateLimiterRateLimiterConfigArgs) (*types.Transaction, error)
+
+ OnInboundMessage(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error)
+
+ OnOutboundMessage(opts *bind.TransactOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error)
+
+ SetPriceRegistry(opts *bind.TransactOpts, newPriceRegistry common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ UpdateRateLimitTokens(opts *bind.TransactOpts, removes []MultiAggregateRateLimiterLocalRateLimitToken, adds []MultiAggregateRateLimiterRateLimitTokenArgs) (*types.Transaction, error)
+
+ FilterAuthorizedCallerAdded(opts *bind.FilterOpts) (*MultiAggregateRateLimiterAuthorizedCallerAddedIterator, error)
+
+ WatchAuthorizedCallerAdded(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterAuthorizedCallerAdded) (event.Subscription, error)
+
+ ParseAuthorizedCallerAdded(log types.Log) (*MultiAggregateRateLimiterAuthorizedCallerAdded, error)
+
+ FilterAuthorizedCallerRemoved(opts *bind.FilterOpts) (*MultiAggregateRateLimiterAuthorizedCallerRemovedIterator, error)
+
+ WatchAuthorizedCallerRemoved(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterAuthorizedCallerRemoved) (event.Subscription, error)
+
+ ParseAuthorizedCallerRemoved(log types.Log) (*MultiAggregateRateLimiterAuthorizedCallerRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*MultiAggregateRateLimiterConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*MultiAggregateRateLimiterConfigChanged, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MultiAggregateRateLimiterOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*MultiAggregateRateLimiterOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MultiAggregateRateLimiterOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*MultiAggregateRateLimiterOwnershipTransferred, error)
+
+ FilterPriceRegistrySet(opts *bind.FilterOpts) (*MultiAggregateRateLimiterPriceRegistrySetIterator, error)
+
+ WatchPriceRegistrySet(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterPriceRegistrySet) (event.Subscription, error)
+
+ ParsePriceRegistrySet(log types.Log) (*MultiAggregateRateLimiterPriceRegistrySet, error)
+
+ FilterRateLimiterConfigUpdated(opts *bind.FilterOpts, remoteChainSelector []uint64) (*MultiAggregateRateLimiterRateLimiterConfigUpdatedIterator, error)
+
+ WatchRateLimiterConfigUpdated(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterRateLimiterConfigUpdated, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRateLimiterConfigUpdated(log types.Log) (*MultiAggregateRateLimiterRateLimiterConfigUpdated, error)
+
+ FilterTokenAggregateRateLimitAdded(opts *bind.FilterOpts) (*MultiAggregateRateLimiterTokenAggregateRateLimitAddedIterator, error)
+
+ WatchTokenAggregateRateLimitAdded(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterTokenAggregateRateLimitAdded) (event.Subscription, error)
+
+ ParseTokenAggregateRateLimitAdded(log types.Log) (*MultiAggregateRateLimiterTokenAggregateRateLimitAdded, error)
+
+ FilterTokenAggregateRateLimitRemoved(opts *bind.FilterOpts) (*MultiAggregateRateLimiterTokenAggregateRateLimitRemovedIterator, error)
+
+ WatchTokenAggregateRateLimitRemoved(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterTokenAggregateRateLimitRemoved) (event.Subscription, error)
+
+ ParseTokenAggregateRateLimitRemoved(log types.Log) (*MultiAggregateRateLimiterTokenAggregateRateLimitRemoved, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*MultiAggregateRateLimiterTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *MultiAggregateRateLimiterTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*MultiAggregateRateLimiterTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/multi_ocr3_helper/multi_ocr3_helper.go b/core/gethwrappers/ccip/generated/multi_ocr3_helper/multi_ocr3_helper.go
new file mode 100644
index 00000000000..d51e398b433
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/multi_ocr3_helper/multi_ocr3_helper.go
@@ -0,0 +1,1096 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package multi_ocr3_helper
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type MultiOCR3BaseConfigInfo struct {
+ ConfigDigest [32]byte
+ F uint8
+ N uint8
+ IsSignatureVerificationEnabled bool
+}
+
+type MultiOCR3BaseOCRConfig struct {
+ ConfigInfo MultiOCR3BaseConfigInfo
+ Signers []common.Address
+ Transmitters []common.Address
+}
+
+type MultiOCR3BaseOCRConfigArgs struct {
+ ConfigDigest [32]byte
+ OcrPluginType uint8
+ F uint8
+ IsSignatureVerificationEnabled bool
+ Signers []common.Address
+ Transmitters []common.Address
+}
+
+type MultiOCR3BaseOracle struct {
+ Index uint8
+ Role uint8
+}
+
+var MultiOCR3HelperMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"enumMultiOCR3Base.InvalidConfigErrorType\",\"name\":\"errorType\",\"type\":\"uint8\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"}],\"name\":\"StaticConfigCannotBeChanged\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"}],\"name\":\"AfterConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"F\",\"type\":\"uint8\"}],\"name\":\"ConfigSet\",\"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\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"oracleAddress\",\"type\":\"address\"}],\"name\":\"getOracle\",\"outputs\":[{\"components\":[{\"internalType\":\"uint8\",\"name\":\"index\",\"type\":\"uint8\"},{\"internalType\":\"enumMultiOCR3Base.Role\",\"name\":\"role\",\"type\":\"uint8\"}],\"internalType\":\"structMultiOCR3Base.Oracle\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"}],\"name\":\"latestConfigDetails\",\"outputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"F\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"n\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isSignatureVerificationEnabled\",\"type\":\"bool\"}],\"internalType\":\"structMultiOCR3Base.ConfigInfo\",\"name\":\"configInfo\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"}],\"internalType\":\"structMultiOCR3Base.OCRConfig\",\"name\":\"ocrConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"F\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isSignatureVerificationEnabled\",\"type\":\"bool\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"}],\"internalType\":\"structMultiOCR3Base.OCRConfigArgs[]\",\"name\":\"ocrConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"setOCR3Configs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"ocrPluginType\",\"type\":\"uint8\"}],\"name\":\"setTransmitOcrPluginType\",\"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\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmitWithSignatures\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"transmitWithoutSignatures\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
+ Bin: "0x60a06040523480156200001157600080fd5b503380600081620000695760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200009c576200009c81620000a9565b5050466080525062000154565b336001600160a01b03821603620001035760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000060565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b608051611db66200017760003960008181610efc0152610f480152611db66000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80637ac0aa1a11610076578063c673e5841161005b578063c673e584146101c5578063f2fde38b146101e5578063f716f99f146101f857600080fd5b80637ac0aa1a1461015b5780638da5cb5b1461019d57600080fd5b806334a9c92e116100a757806334a9c92e1461012057806344e65e551461014057806379ba50971461015357600080fd5b8063181f5a77146100c357806326bf9d261461010b575b600080fd5b604080518082018252601981527f4d756c74694f4352334261736548656c70657220312e302e300000000000000060208201529051610102919061153c565b60405180910390f35b61011e610119366004611603565b61020b565b005b61013361012e366004611691565b61023a565b60405161010291906116f3565b61011e61014e366004611766565b6102ca565b61011e61034d565b61011e610169366004611819565b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff92909216919091179055565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610102565b6101d86101d3366004611819565b61044f565b604051610102919061188d565b61011e6101f3366004611920565b6105c7565b61011e610206366004611a8c565b6105db565b604080516000808252602082019092526004549091506102349060ff168585858580600061061d565b50505050565b6040805180820182526000808252602080830182905260ff86811683526003825284832073ffffffffffffffffffffffffffffffffffffffff871684528252918490208451808601909552805480841686529394939092918401916101009091041660028111156102ad576102ad6116c4565b60028111156102be576102be6116c4565b90525090505b92915050565b60045460408051602080880282810182019093528782526103439360ff16928c928c928c928c918c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b9182918501908490808284376000920191909152508a925061061d915050565b5050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146103d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104926040805160e081019091526000606082018181526080830182905260a0830182905260c08301919091528190815260200160608152602001606081525090565b60ff808316600090815260026020818152604092839020835160e081018552815460608201908152600183015480881660808401526101008104881660a0840152620100009004909616151560c08201529485529182018054845181840281018401909552808552929385830193909283018282801561054857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161051d575b50505050508152602001600382018054806020026020016040519081016040528092919081815260200182805480156105b757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161058c575b5050505050815250509050919050565b6105cf6109a1565b6105d881610a24565b50565b6105e36109a1565b60005b81518110156106195761061182828151811061060457610604611bf5565b6020026020010151610b19565b6001016105e6565b5050565b60ff8781166000908152600260209081526040808320815160808101835281548152600190910154808616938201939093526101008304851691810191909152620100009091049092161515606083015287359061067c8760a4611c53565b90508260600151156106c4578451610695906020611c66565b86516106a2906020611c66565b6106ad9060a0611c53565b6106b79190611c53565b6106c19082611c53565b90505b368114610706576040517f8e1192e1000000000000000000000000000000000000000000000000000000008152600481018290523660248201526044016103ca565b508151811461074e5781516040517f93df584c0000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016103ca565b610756610ef9565b60ff808a16600090815260036020908152604080832033845282528083208151808301909252805480861683529394919390928401916101009091041660028111156107a4576107a46116c4565b60028111156107b5576107b56116c4565b90525090506002816020015160028111156107d2576107d26116c4565b1480156108335750600260008b60ff1660ff168152602001908152602001600020600301816000015160ff168154811061080e5761080e611bf5565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b610869576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5081606001511561094b576020820151610884906001611c7d565b60ff168551146108c0576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83518551146108fb576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000878760405161090d929190611c96565b604051908190038120610924918b90602001611ca6565b6040516020818303038152906040528051906020012090506109498a82888888610f7a565b505b6040805182815260208a81013567ffffffffffffffff169082015260ff8b16917f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef0910160405180910390a2505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103ca565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610aa3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103ca565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b806040015160ff16600003610b5d5760006040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016103ca9190611cba565b60208082015160ff80821660009081526002909352604083206001810154929390928392169003610bca57606084015160018201805491151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff909216919091179055610c1f565b6060840151600182015460ff6201000090910416151590151514610c1f576040517f87f6037c00000000000000000000000000000000000000000000000000000000815260ff841660048201526024016103ca565b60a08401518051601f60ff82161115610c675760016040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016103ca9190611cba565b610cda8585600301805480602002602001604051908101604052809291908181526020018280548015610cd057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610ca5575b50505050506111b2565b856060015115610e4857610d558585600201805480602002602001604051908101604052809291908181526020018280548015610cd05760200282019190600052602060002090815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610ca55750505050506111b2565b60808601518051610d6f906002870190602084019061147e565b5080516001850180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff841690810291909117909155601f1015610de85760026040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016103ca9190611cba565b6040880151610df8906003611cd4565b60ff168160ff1611610e395760036040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016103ca9190611cba565b610e458783600161124a565b50505b610e548583600261124a565b8151610e69906003860190602085019061147e565b506040868101516001850180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff8316179055875180865560a089015192517fab8b1b57514019638d7b5ce9c638fe71366fe8e2be1c40a7a80f1733d0e9f54793610ee0938a939260028b01929190611cf7565b60405180910390a1610ef185611445565b505050505050565b467f000000000000000000000000000000000000000000000000000000000000000014610a22576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201526044016103ca565b610f82611508565b835160005b81811015610343576000600188868460208110610fa657610fa6611bf5565b610fb391901a601b611c7d565b898581518110610fc557610fc5611bf5565b6020026020010151898681518110610fdf57610fdf611bf5565b60200260200101516040516000815260200160405260405161101d949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561103f573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015160ff808e1660009081526003602090815285822073ffffffffffffffffffffffffffffffffffffffff8516835281528582208587019096528554808416865293975090955092939284019161010090041660028111156110cb576110cb6116c4565b60028111156110dc576110dc6116c4565b90525090506001816020015160028111156110f9576110f96116c4565b14611130576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f811061114757611147611bf5565b602002015115611183576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f811061119e5761119e611bf5565b911515602090920201525050600101610f87565b60005b81518110156112455760ff8316600090815260036020526040812083519091908490849081106111e7576111e7611bf5565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690556001016111b5565b505050565b60005b82518160ff161015610234576000838260ff168151811061127057611270611bf5565b602002602001015190506000600281111561128d5761128d6116c4565b60ff808716600090815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915290205461010090041660028111156112d9576112d96116c4565b146113135760046040517f367f56a20000000000000000000000000000000000000000000000000000000081526004016103ca9190611cba565b73ffffffffffffffffffffffffffffffffffffffff8116611360576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052808360ff168152602001846002811115611386576113866116c4565b905260ff808716600090815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845282529091208351815493167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841681178255918401519092909183917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561142b5761142b6116c4565b0217905550905050508061143e90611d8a565b905061124d565b60405160ff821681527f897ac1b2c12867721b284f3eb147bd4ab046d4eef1cf31c1d8988bfcfb962b539060200160405180910390a150565b8280548282559060005260206000209081019282156114f8579160200282015b828111156114f857825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90911617825560209092019160019091019061149e565b50611504929150611527565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b808211156115045760008155600101611528565b60006020808352835180602085015260005b8181101561156a5785810183015185820160400152820161154e565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b80606081018310156102c457600080fd5b60008083601f8401126115cc57600080fd5b50813567ffffffffffffffff8111156115e457600080fd5b6020830191508360208285010111156115fc57600080fd5b9250929050565b60008060006080848603121561161857600080fd5b61162285856115a9565b9250606084013567ffffffffffffffff81111561163e57600080fd5b61164a868287016115ba565b9497909650939450505050565b803560ff8116811461166857600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461166857600080fd5b600080604083850312156116a457600080fd5b6116ad83611657565b91506116bb6020840161166d565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b815160ff1681526020820151604082019060038110611714576117146116c4565b8060208401525092915050565b60008083601f84011261173357600080fd5b50813567ffffffffffffffff81111561174b57600080fd5b6020830191508360208260051b85010111156115fc57600080fd5b60008060008060008060008060e0898b03121561178257600080fd5b61178c8a8a6115a9565b9750606089013567ffffffffffffffff808211156117a957600080fd5b6117b58c838d016115ba565b909950975060808b01359150808211156117ce57600080fd5b6117da8c838d01611721565b909750955060a08b01359150808211156117f357600080fd5b506118008b828c01611721565b999c989b50969995989497949560c00135949350505050565b60006020828403121561182b57600080fd5b61183482611657565b9392505050565b60008151808452602080850194506020840160005b8381101561188257815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101611850565b509495945050505050565b60208152600082518051602084015260ff602082015116604084015260ff604082015116606084015260608101511515608084015250602083015160c060a08401526118dc60e084018261183b565b905060408401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160c0850152611917828261183b565b95945050505050565b60006020828403121561193257600080fd5b6118348261166d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff8111828210171561198d5761198d61193b565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156119da576119da61193b565b604052919050565b600067ffffffffffffffff8211156119fc576119fc61193b565b5060051b60200190565b8035801515811461166857600080fd5b600082601f830112611a2757600080fd5b81356020611a3c611a37836119e2565b611993565b8083825260208201915060208460051b870101935086841115611a5e57600080fd5b602086015b84811015611a8157611a748161166d565b8352918301918301611a63565b509695505050505050565b60006020808385031215611a9f57600080fd5b823567ffffffffffffffff80821115611ab757600080fd5b818501915085601f830112611acb57600080fd5b8135611ad9611a37826119e2565b81815260059190911b83018401908481019088831115611af857600080fd5b8585015b83811015611be857803585811115611b1357600080fd5b860160c0818c037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011215611b485760008081fd5b611b5061196a565b8882013581526040611b63818401611657565b8a8301526060611b74818501611657565b8284015260809150611b87828501611a06565b9083015260a08381013589811115611b9f5760008081fd5b611bad8f8d83880101611a16565b838501525060c0840135915088821115611bc75760008081fd5b611bd58e8c84870101611a16565b9083015250845250918601918601611afc565b5098975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156102c4576102c4611c24565b80820281158282048414176102c4576102c4611c24565b60ff81811683821601908111156102c4576102c4611c24565b8183823760009101908152919050565b828152606082602083013760800192915050565b6020810160058310611cce57611cce6116c4565b91905290565b60ff8181168382160290811690818114611cf057611cf0611c24565b5092915050565b600060a0820160ff88168352602087602085015260a0604085015281875480845260c086019150886000526020600020935060005b81811015611d5e57845473ffffffffffffffffffffffffffffffffffffffff1683526001948501949284019201611d2c565b50508481036060860152611d72818861183b565b935050505060ff831660808301529695505050505050565b600060ff821660ff8103611da057611da0611c24565b6001019291505056fea164736f6c6343000818000a",
+}
+
+var MultiOCR3HelperABI = MultiOCR3HelperMetaData.ABI
+
+var MultiOCR3HelperBin = MultiOCR3HelperMetaData.Bin
+
+func DeployMultiOCR3Helper(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MultiOCR3Helper, error) {
+ parsed, err := MultiOCR3HelperMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MultiOCR3HelperBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MultiOCR3Helper{address: address, abi: *parsed, MultiOCR3HelperCaller: MultiOCR3HelperCaller{contract: contract}, MultiOCR3HelperTransactor: MultiOCR3HelperTransactor{contract: contract}, MultiOCR3HelperFilterer: MultiOCR3HelperFilterer{contract: contract}}, nil
+}
+
+type MultiOCR3Helper struct {
+ address common.Address
+ abi abi.ABI
+ MultiOCR3HelperCaller
+ MultiOCR3HelperTransactor
+ MultiOCR3HelperFilterer
+}
+
+type MultiOCR3HelperCaller struct {
+ contract *bind.BoundContract
+}
+
+type MultiOCR3HelperTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MultiOCR3HelperFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MultiOCR3HelperSession struct {
+ Contract *MultiOCR3Helper
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MultiOCR3HelperCallerSession struct {
+ Contract *MultiOCR3HelperCaller
+ CallOpts bind.CallOpts
+}
+
+type MultiOCR3HelperTransactorSession struct {
+ Contract *MultiOCR3HelperTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MultiOCR3HelperRaw struct {
+ Contract *MultiOCR3Helper
+}
+
+type MultiOCR3HelperCallerRaw struct {
+ Contract *MultiOCR3HelperCaller
+}
+
+type MultiOCR3HelperTransactorRaw struct {
+ Contract *MultiOCR3HelperTransactor
+}
+
+func NewMultiOCR3Helper(address common.Address, backend bind.ContractBackend) (*MultiOCR3Helper, error) {
+ abi, err := abi.JSON(strings.NewReader(MultiOCR3HelperABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMultiOCR3Helper(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3Helper{address: address, abi: abi, MultiOCR3HelperCaller: MultiOCR3HelperCaller{contract: contract}, MultiOCR3HelperTransactor: MultiOCR3HelperTransactor{contract: contract}, MultiOCR3HelperFilterer: MultiOCR3HelperFilterer{contract: contract}}, nil
+}
+
+func NewMultiOCR3HelperCaller(address common.Address, caller bind.ContractCaller) (*MultiOCR3HelperCaller, error) {
+ contract, err := bindMultiOCR3Helper(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3HelperCaller{contract: contract}, nil
+}
+
+func NewMultiOCR3HelperTransactor(address common.Address, transactor bind.ContractTransactor) (*MultiOCR3HelperTransactor, error) {
+ contract, err := bindMultiOCR3Helper(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3HelperTransactor{contract: contract}, nil
+}
+
+func NewMultiOCR3HelperFilterer(address common.Address, filterer bind.ContractFilterer) (*MultiOCR3HelperFilterer, error) {
+ contract, err := bindMultiOCR3Helper(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3HelperFilterer{contract: contract}, nil
+}
+
+func bindMultiOCR3Helper(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MultiOCR3HelperMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MultiOCR3Helper.Contract.MultiOCR3HelperCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.MultiOCR3HelperTransactor.contract.Transfer(opts)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.MultiOCR3HelperTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MultiOCR3Helper.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.contract.Transfer(opts)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCaller) GetOracle(opts *bind.CallOpts, ocrPluginType uint8, oracleAddress common.Address) (MultiOCR3BaseOracle, error) {
+ var out []interface{}
+ err := _MultiOCR3Helper.contract.Call(opts, &out, "getOracle", ocrPluginType, oracleAddress)
+
+ if err != nil {
+ return *new(MultiOCR3BaseOracle), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(MultiOCR3BaseOracle)).(*MultiOCR3BaseOracle)
+
+ return out0, err
+
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) GetOracle(ocrPluginType uint8, oracleAddress common.Address) (MultiOCR3BaseOracle, error) {
+ return _MultiOCR3Helper.Contract.GetOracle(&_MultiOCR3Helper.CallOpts, ocrPluginType, oracleAddress)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCallerSession) GetOracle(ocrPluginType uint8, oracleAddress common.Address) (MultiOCR3BaseOracle, error) {
+ return _MultiOCR3Helper.Contract.GetOracle(&_MultiOCR3Helper.CallOpts, ocrPluginType, oracleAddress)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCaller) LatestConfigDetails(opts *bind.CallOpts, ocrPluginType uint8) (MultiOCR3BaseOCRConfig, error) {
+ var out []interface{}
+ err := _MultiOCR3Helper.contract.Call(opts, &out, "latestConfigDetails", ocrPluginType)
+
+ if err != nil {
+ return *new(MultiOCR3BaseOCRConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(MultiOCR3BaseOCRConfig)).(*MultiOCR3BaseOCRConfig)
+
+ return out0, err
+
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) LatestConfigDetails(ocrPluginType uint8) (MultiOCR3BaseOCRConfig, error) {
+ return _MultiOCR3Helper.Contract.LatestConfigDetails(&_MultiOCR3Helper.CallOpts, ocrPluginType)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCallerSession) LatestConfigDetails(ocrPluginType uint8) (MultiOCR3BaseOCRConfig, error) {
+ return _MultiOCR3Helper.Contract.LatestConfigDetails(&_MultiOCR3Helper.CallOpts, ocrPluginType)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _MultiOCR3Helper.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) Owner() (common.Address, error) {
+ return _MultiOCR3Helper.Contract.Owner(&_MultiOCR3Helper.CallOpts)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCallerSession) Owner() (common.Address, error) {
+ return _MultiOCR3Helper.Contract.Owner(&_MultiOCR3Helper.CallOpts)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _MultiOCR3Helper.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) TypeAndVersion() (string, error) {
+ return _MultiOCR3Helper.Contract.TypeAndVersion(&_MultiOCR3Helper.CallOpts)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperCallerSession) TypeAndVersion() (string, error) {
+ return _MultiOCR3Helper.Contract.TypeAndVersion(&_MultiOCR3Helper.CallOpts)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MultiOCR3Helper.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) AcceptOwnership() (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.AcceptOwnership(&_MultiOCR3Helper.TransactOpts)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.AcceptOwnership(&_MultiOCR3Helper.TransactOpts)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactor) SetOCR3Configs(opts *bind.TransactOpts, ocrConfigArgs []MultiOCR3BaseOCRConfigArgs) (*types.Transaction, error) {
+ return _MultiOCR3Helper.contract.Transact(opts, "setOCR3Configs", ocrConfigArgs)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) SetOCR3Configs(ocrConfigArgs []MultiOCR3BaseOCRConfigArgs) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.SetOCR3Configs(&_MultiOCR3Helper.TransactOpts, ocrConfigArgs)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactorSession) SetOCR3Configs(ocrConfigArgs []MultiOCR3BaseOCRConfigArgs) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.SetOCR3Configs(&_MultiOCR3Helper.TransactOpts, ocrConfigArgs)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactor) SetTransmitOcrPluginType(opts *bind.TransactOpts, ocrPluginType uint8) (*types.Transaction, error) {
+ return _MultiOCR3Helper.contract.Transact(opts, "setTransmitOcrPluginType", ocrPluginType)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) SetTransmitOcrPluginType(ocrPluginType uint8) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.SetTransmitOcrPluginType(&_MultiOCR3Helper.TransactOpts, ocrPluginType)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactorSession) SetTransmitOcrPluginType(ocrPluginType uint8) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.SetTransmitOcrPluginType(&_MultiOCR3Helper.TransactOpts, ocrPluginType)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _MultiOCR3Helper.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.TransferOwnership(&_MultiOCR3Helper.TransactOpts, to)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.TransferOwnership(&_MultiOCR3Helper.TransactOpts, to)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactor) TransmitWithSignatures(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _MultiOCR3Helper.contract.Transact(opts, "transmitWithSignatures", reportContext, report, rs, ss, rawVs)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) TransmitWithSignatures(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.TransmitWithSignatures(&_MultiOCR3Helper.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactorSession) TransmitWithSignatures(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.TransmitWithSignatures(&_MultiOCR3Helper.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactor) TransmitWithoutSignatures(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte) (*types.Transaction, error) {
+ return _MultiOCR3Helper.contract.Transact(opts, "transmitWithoutSignatures", reportContext, report)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperSession) TransmitWithoutSignatures(reportContext [3][32]byte, report []byte) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.TransmitWithoutSignatures(&_MultiOCR3Helper.TransactOpts, reportContext, report)
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperTransactorSession) TransmitWithoutSignatures(reportContext [3][32]byte, report []byte) (*types.Transaction, error) {
+ return _MultiOCR3Helper.Contract.TransmitWithoutSignatures(&_MultiOCR3Helper.TransactOpts, reportContext, report)
+}
+
+type MultiOCR3HelperAfterConfigSetIterator struct {
+ Event *MultiOCR3HelperAfterConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiOCR3HelperAfterConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiOCR3HelperAfterConfigSet)
+ 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(MultiOCR3HelperAfterConfigSet)
+ 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 *MultiOCR3HelperAfterConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiOCR3HelperAfterConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiOCR3HelperAfterConfigSet struct {
+ OcrPluginType uint8
+ Raw types.Log
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) FilterAfterConfigSet(opts *bind.FilterOpts) (*MultiOCR3HelperAfterConfigSetIterator, error) {
+
+ logs, sub, err := _MultiOCR3Helper.contract.FilterLogs(opts, "AfterConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3HelperAfterConfigSetIterator{contract: _MultiOCR3Helper.contract, event: "AfterConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) WatchAfterConfigSet(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperAfterConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _MultiOCR3Helper.contract.WatchLogs(opts, "AfterConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiOCR3HelperAfterConfigSet)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "AfterConfigSet", 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 (_MultiOCR3Helper *MultiOCR3HelperFilterer) ParseAfterConfigSet(log types.Log) (*MultiOCR3HelperAfterConfigSet, error) {
+ event := new(MultiOCR3HelperAfterConfigSet)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "AfterConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiOCR3HelperConfigSetIterator struct {
+ Event *MultiOCR3HelperConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiOCR3HelperConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiOCR3HelperConfigSet)
+ 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(MultiOCR3HelperConfigSet)
+ 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 *MultiOCR3HelperConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiOCR3HelperConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiOCR3HelperConfigSet struct {
+ OcrPluginType uint8
+ ConfigDigest [32]byte
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ Raw types.Log
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) FilterConfigSet(opts *bind.FilterOpts) (*MultiOCR3HelperConfigSetIterator, error) {
+
+ logs, sub, err := _MultiOCR3Helper.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3HelperConfigSetIterator{contract: _MultiOCR3Helper.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _MultiOCR3Helper.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiOCR3HelperConfigSet)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "ConfigSet", 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 (_MultiOCR3Helper *MultiOCR3HelperFilterer) ParseConfigSet(log types.Log) (*MultiOCR3HelperConfigSet, error) {
+ event := new(MultiOCR3HelperConfigSet)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiOCR3HelperOwnershipTransferRequestedIterator struct {
+ Event *MultiOCR3HelperOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiOCR3HelperOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiOCR3HelperOwnershipTransferRequested)
+ 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(MultiOCR3HelperOwnershipTransferRequested)
+ 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 *MultiOCR3HelperOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiOCR3HelperOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiOCR3HelperOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MultiOCR3HelperOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MultiOCR3Helper.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3HelperOwnershipTransferRequestedIterator{contract: _MultiOCR3Helper.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MultiOCR3Helper.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiOCR3HelperOwnershipTransferRequested)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_MultiOCR3Helper *MultiOCR3HelperFilterer) ParseOwnershipTransferRequested(log types.Log) (*MultiOCR3HelperOwnershipTransferRequested, error) {
+ event := new(MultiOCR3HelperOwnershipTransferRequested)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiOCR3HelperOwnershipTransferredIterator struct {
+ Event *MultiOCR3HelperOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiOCR3HelperOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiOCR3HelperOwnershipTransferred)
+ 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(MultiOCR3HelperOwnershipTransferred)
+ 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 *MultiOCR3HelperOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiOCR3HelperOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiOCR3HelperOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MultiOCR3HelperOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MultiOCR3Helper.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3HelperOwnershipTransferredIterator{contract: _MultiOCR3Helper.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _MultiOCR3Helper.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiOCR3HelperOwnershipTransferred)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "OwnershipTransferred", 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 (_MultiOCR3Helper *MultiOCR3HelperFilterer) ParseOwnershipTransferred(log types.Log) (*MultiOCR3HelperOwnershipTransferred, error) {
+ event := new(MultiOCR3HelperOwnershipTransferred)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MultiOCR3HelperTransmittedIterator struct {
+ Event *MultiOCR3HelperTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MultiOCR3HelperTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MultiOCR3HelperTransmitted)
+ 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(MultiOCR3HelperTransmitted)
+ 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 *MultiOCR3HelperTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MultiOCR3HelperTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MultiOCR3HelperTransmitted struct {
+ OcrPluginType uint8
+ ConfigDigest [32]byte
+ SequenceNumber uint64
+ Raw types.Log
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) FilterTransmitted(opts *bind.FilterOpts, ocrPluginType []uint8) (*MultiOCR3HelperTransmittedIterator, error) {
+
+ var ocrPluginTypeRule []interface{}
+ for _, ocrPluginTypeItem := range ocrPluginType {
+ ocrPluginTypeRule = append(ocrPluginTypeRule, ocrPluginTypeItem)
+ }
+
+ logs, sub, err := _MultiOCR3Helper.contract.FilterLogs(opts, "Transmitted", ocrPluginTypeRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MultiOCR3HelperTransmittedIterator{contract: _MultiOCR3Helper.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_MultiOCR3Helper *MultiOCR3HelperFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperTransmitted, ocrPluginType []uint8) (event.Subscription, error) {
+
+ var ocrPluginTypeRule []interface{}
+ for _, ocrPluginTypeItem := range ocrPluginType {
+ ocrPluginTypeRule = append(ocrPluginTypeRule, ocrPluginTypeItem)
+ }
+
+ logs, sub, err := _MultiOCR3Helper.contract.WatchLogs(opts, "Transmitted", ocrPluginTypeRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MultiOCR3HelperTransmitted)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "Transmitted", 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 (_MultiOCR3Helper *MultiOCR3HelperFilterer) ParseTransmitted(log types.Log) (*MultiOCR3HelperTransmitted, error) {
+ event := new(MultiOCR3HelperTransmitted)
+ if err := _MultiOCR3Helper.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_MultiOCR3Helper *MultiOCR3Helper) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _MultiOCR3Helper.abi.Events["AfterConfigSet"].ID:
+ return _MultiOCR3Helper.ParseAfterConfigSet(log)
+ case _MultiOCR3Helper.abi.Events["ConfigSet"].ID:
+ return _MultiOCR3Helper.ParseConfigSet(log)
+ case _MultiOCR3Helper.abi.Events["OwnershipTransferRequested"].ID:
+ return _MultiOCR3Helper.ParseOwnershipTransferRequested(log)
+ case _MultiOCR3Helper.abi.Events["OwnershipTransferred"].ID:
+ return _MultiOCR3Helper.ParseOwnershipTransferred(log)
+ case _MultiOCR3Helper.abi.Events["Transmitted"].ID:
+ return _MultiOCR3Helper.ParseTransmitted(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (MultiOCR3HelperAfterConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x897ac1b2c12867721b284f3eb147bd4ab046d4eef1cf31c1d8988bfcfb962b53")
+}
+
+func (MultiOCR3HelperConfigSet) Topic() common.Hash {
+ return common.HexToHash("0xab8b1b57514019638d7b5ce9c638fe71366fe8e2be1c40a7a80f1733d0e9f547")
+}
+
+func (MultiOCR3HelperOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (MultiOCR3HelperOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (MultiOCR3HelperTransmitted) Topic() common.Hash {
+ return common.HexToHash("0x198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef0")
+}
+
+func (_MultiOCR3Helper *MultiOCR3Helper) Address() common.Address {
+ return _MultiOCR3Helper.address
+}
+
+type MultiOCR3HelperInterface interface {
+ GetOracle(opts *bind.CallOpts, ocrPluginType uint8, oracleAddress common.Address) (MultiOCR3BaseOracle, error)
+
+ LatestConfigDetails(opts *bind.CallOpts, ocrPluginType uint8) (MultiOCR3BaseOCRConfig, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetOCR3Configs(opts *bind.TransactOpts, ocrConfigArgs []MultiOCR3BaseOCRConfigArgs) (*types.Transaction, error)
+
+ SetTransmitOcrPluginType(opts *bind.TransactOpts, ocrPluginType uint8) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ TransmitWithSignatures(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ TransmitWithoutSignatures(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte) (*types.Transaction, error)
+
+ FilterAfterConfigSet(opts *bind.FilterOpts) (*MultiOCR3HelperAfterConfigSetIterator, error)
+
+ WatchAfterConfigSet(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperAfterConfigSet) (event.Subscription, error)
+
+ ParseAfterConfigSet(log types.Log) (*MultiOCR3HelperAfterConfigSet, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*MultiOCR3HelperConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*MultiOCR3HelperConfigSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MultiOCR3HelperOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*MultiOCR3HelperOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*MultiOCR3HelperOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*MultiOCR3HelperOwnershipTransferred, error)
+
+ FilterTransmitted(opts *bind.FilterOpts, ocrPluginType []uint8) (*MultiOCR3HelperTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *MultiOCR3HelperTransmitted, ocrPluginType []uint8) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*MultiOCR3HelperTransmitted, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/nonce_manager/nonce_manager.go b/core/gethwrappers/ccip/generated/nonce_manager/nonce_manager.go
new file mode 100644
index 00000000000..14979b4fe30
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/nonce_manager/nonce_manager.go
@@ -0,0 +1,1234 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package nonce_manager
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type AuthorizedCallersAuthorizedCallerArgs struct {
+ AddedCallers []common.Address
+ RemovedCallers []common.Address
+}
+
+type NonceManagerPreviousRamps struct {
+ PrevOnRamp common.Address
+ PrevOffRamp common.Address
+}
+
+type NonceManagerPreviousRampsArgs struct {
+ RemoteChainSelector uint64
+ PrevRamps NonceManagerPreviousRamps
+}
+
+var NonceManagerMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"authorizedCallers\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"PreviousRampAlreadySet\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"UnauthorizedCaller\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AuthorizedCallerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AuthorizedCallerRemoved\",\"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\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structNonceManager.PreviousRamps\",\"name\":\"prevRamp\",\"type\":\"tuple\"}],\"name\":\"PreviousRampsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"}],\"name\":\"SkippedIncorrectNonce\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address[]\",\"name\":\"addedCallers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"removedCallers\",\"type\":\"address[]\"}],\"internalType\":\"structAuthorizedCallers.AuthorizedCallerArgs\",\"name\":\"authorizedCallerArgs\",\"type\":\"tuple\"}],\"name\":\"applyAuthorizedCallerUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"}],\"internalType\":\"structNonceManager.PreviousRamps\",\"name\":\"prevRamps\",\"type\":\"tuple\"}],\"internalType\":\"structNonceManager.PreviousRampsArgs[]\",\"name\":\"previousRampsArgs\",\"type\":\"tuple[]\"}],\"name\":\"applyPreviousRampsUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAuthorizedCallers\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"}],\"name\":\"getInboundNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getIncrementedOutboundNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getOutboundNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"getPreviousRamps\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"prevOnRamp\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"prevOffRamp\",\"type\":\"address\"}],\"internalType\":\"structNonceManager.PreviousRamps\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"expectedNonce\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"}],\"name\":\"incrementInboundNonce\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"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\"}]",
+ Bin: "0x60806040523480156200001157600080fd5b5060405162001ad538038062001ad58339810160408190526200003491620004b0565b8033806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf81620000f6565b5050604080518082018252838152815160008152602080820190935291810191909152620000ee9150620001a1565b5050620005d0565b336001600160a01b03821603620001505760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b602081015160005b815181101562000231576000828281518110620001ca57620001ca62000582565b60209081029190910101519050620001e4600282620002f0565b1562000227576040516001600160a01b03821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b50600101620001a9565b50815160005b8151811015620002ea57600082828151811062000258576200025862000582565b6020026020010151905060006001600160a01b0316816001600160a01b03160362000296576040516342bcdf7f60e11b815260040160405180910390fd5b620002a360028262000310565b506040516001600160a01b03821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a15060010162000237565b50505050565b600062000307836001600160a01b03841662000327565b90505b92915050565b600062000307836001600160a01b0384166200042b565b60008181526001830160205260408120548015620004205760006200034e60018362000598565b8554909150600090620003649060019062000598565b9050818114620003d057600086600001828154811062000388576200038862000582565b9060005260206000200154905080876000018481548110620003ae57620003ae62000582565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620003e457620003e4620005ba565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506200030a565b60009150506200030a565b600081815260018301602052604081205462000474575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200030a565b5060006200030a565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b0381168114620004ab57600080fd5b919050565b60006020808385031215620004c457600080fd5b82516001600160401b0380821115620004dc57600080fd5b818501915085601f830112620004f157600080fd5b8151818111156200050657620005066200047d565b8060051b604051601f19603f830116810181811085821117156200052e576200052e6200047d565b6040529182528482019250838101850191888311156200054d57600080fd5b938501935b828510156200057657620005668562000493565b8452938501939285019262000552565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b818103818111156200030a57634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b6114f580620005e06000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c806391a2749a11610081578063e0e03cae1161005b578063e0e03cae14610228578063ea458c0c1461024b578063f2fde38b1461025e57600080fd5b806391a2749a146101d6578063bf18402a146101e9578063c92236251461021557600080fd5b806379ba5097116100b257806379ba50971461019157806384d8acf71461019b5780638da5cb5b146101ae57600080fd5b80632451a627146100ce578063294b5630146100ec575b600080fd5b6100d6610271565b6040516100e39190610f2e565b60405180910390f35b61015d6100fa366004610f9e565b60408051808201909152600080825260208201525067ffffffffffffffff166000908152600460209081526040918290208251808401909352805473ffffffffffffffffffffffffffffffffffffffff9081168452600190910154169082015290565b60408051825173ffffffffffffffffffffffffffffffffffffffff90811682526020938401511692810192909252016100e3565b610199610282565b005b6101996101a9366004610fbb565b610384565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e3565b6101996101e4366004611146565b610560565b6101fc6101f73660046111ed565b610574565b60405167ffffffffffffffff90911681526020016100e3565b6101fc61022336600461126f565b610589565b61023b6102363660046112c4565b6105a0565b60405190151581526020016100e3565b6101fc6102593660046111ed565b6106a9565b61019961026c366004611329565b61073d565b606061027d600261074e565b905090565b60015473ffffffffffffffffffffffffffffffffffffffff163314610308576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61038c61075b565b60005b8181101561055b57368383838181106103aa576103aa611346565b606002919091019150600090506004816103c76020850185610f9e565b67ffffffffffffffff1681526020810191909152604001600020805490915073ffffffffffffffffffffffffffffffffffffffff161515806104225750600181015473ffffffffffffffffffffffffffffffffffffffff1615155b15610459576040517fc6117ae200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104696040830160208401611329565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff919091161781556104b96060830160408401611329565b6001820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905561050d6020830183610f9e565b67ffffffffffffffff167fa2e43edcbc4fd175ae4bebbe3fd6139871ed1f1783cd4a1ace59b90d302c3319836020016040516105499190611375565b60405180910390a2505060010161038f565b505050565b61056861075b565b610571816107de565b50565b60006105808383610970565b90505b92915050565b6000610596848484610a8d565b90505b9392505050565b60006105aa610bde565b60006105b7868585610a8d565b6105c29060016113ec565b90508467ffffffffffffffff168167ffffffffffffffff1614610626577f606ff8179e5e3c059b82df931acc496b7b6053e8879042f8267f930e0595f69f86868686604051610614949392919061140d565b60405180910390a160009150506106a1565b67ffffffffffffffff86166000908152600660205260409081902090518291906106539087908790611479565b908152604051908190036020019020805467ffffffffffffffff929092167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921691909117905550600190505b949350505050565b60006106b3610bde565b60006106bf8484610970565b6106ca9060016113ec565b67ffffffffffffffff808616600090815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff89168452909152902080549183167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090921691909117905591505092915050565b61074561075b565b61057181610c21565b6060600061059983610d16565b60005473ffffffffffffffffffffffffffffffffffffffff1633146107dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016102ff565b565b602081015160005b815181101561087957600082828151811061080357610803611346565b60200260200101519050610821816002610d7290919063ffffffff16565b156108705760405173ffffffffffffffffffffffffffffffffffffffff821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b506001016107e6565b50815160005b815181101561096a57600082828151811061089c5761089c611346565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361090c576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610917600282610d94565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a15060010161087f565b50505050565b67ffffffffffffffff808316600090815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091528120549091168082036105805767ffffffffffffffff841660009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff168015610a85576040517f856c824700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015282169063856c824790602401602060405180830381865afa158015610a58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7c9190611489565b92505050610583565b509392505050565b67ffffffffffffffff83166000908152600660205260408082209051829190610ab99086908690611479565b9081526040519081900360200190205467ffffffffffffffff16905060008190036105965767ffffffffffffffff851660009081526004602052604090206001015473ffffffffffffffffffffffffffffffffffffffff168015610bd55773ffffffffffffffffffffffffffffffffffffffff811663856c8247610b3f86880188611329565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015610ba8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcc9190611489565b92505050610599565b50949350505050565b610be9600233610db6565b6107dc576040517fd86ad9cf0000000000000000000000000000000000000000000000000000000081523360048201526024016102ff565b3373ffffffffffffffffffffffffffffffffffffffff821603610ca0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016102ff565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b606081600001805480602002602001604051908101604052809291908181526020018280548015610d6657602002820191906000526020600020905b815481526020019060010190808311610d52575b50505050509050919050565b60006105808373ffffffffffffffffffffffffffffffffffffffff8416610de5565b60006105808373ffffffffffffffffffffffffffffffffffffffff8416610edf565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515610580565b60008181526001830160205260408120548015610ece576000610e096001836114a6565b8554909150600090610e1d906001906114a6565b9050818114610e82576000866000018281548110610e3d57610e3d611346565b9060005260206000200154905080876000018481548110610e6057610e60611346565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e9357610e936114b9565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610583565b6000915050610583565b5092915050565b6000818152600183016020526040812054610f2657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610583565b506000610583565b6020808252825182820181905260009190848201906040850190845b81811015610f7c57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f4a565b50909695505050505050565b67ffffffffffffffff8116811461057157600080fd5b600060208284031215610fb057600080fd5b813561058081610f88565b60008060208385031215610fce57600080fd5b823567ffffffffffffffff80821115610fe657600080fd5b818501915085601f830112610ffa57600080fd5b81358181111561100957600080fd5b86602060608302850101111561101e57600080fd5b60209290920196919550909350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461057157600080fd5b600082601f83011261109257600080fd5b8135602067ffffffffffffffff808311156110af576110af611030565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811084821117156110f2576110f2611030565b604052938452602081870181019490810192508785111561111257600080fd5b6020870191505b8482101561113b57813561112c8161105f565b83529183019190830190611119565b979650505050505050565b60006020828403121561115857600080fd5b813567ffffffffffffffff8082111561117057600080fd5b908301906040828603121561118457600080fd5b60405160408101818110838211171561119f5761119f611030565b6040528235828111156111b157600080fd5b6111bd87828601611081565b8252506020830135828111156111d257600080fd5b6111de87828601611081565b60208301525095945050505050565b6000806040838503121561120057600080fd5b823561120b81610f88565b9150602083013561121b8161105f565b809150509250929050565b60008083601f84011261123857600080fd5b50813567ffffffffffffffff81111561125057600080fd5b60208301915083602082850101111561126857600080fd5b9250929050565b60008060006040848603121561128457600080fd5b833561128f81610f88565b9250602084013567ffffffffffffffff8111156112ab57600080fd5b6112b786828701611226565b9497909650939450505050565b600080600080606085870312156112da57600080fd5b84356112e581610f88565b935060208501356112f581610f88565b9250604085013567ffffffffffffffff81111561131157600080fd5b61131d87828801611226565b95989497509550505050565b60006020828403121561133b57600080fd5b81356105808161105f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6040810182356113848161105f565b73ffffffffffffffffffffffffffffffffffffffff90811683526020840135906113ad8261105f565b8082166020850152505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff818116838216019080821115610ed857610ed86113bd565b600067ffffffffffffffff8087168352808616602084015250606060408301528260608301528284608084013760006080848401015260807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116830101905095945050505050565b8183823760009101908152919050565b60006020828403121561149b57600080fd5b815161058081610f88565b81810381811115610583576105836113bd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a",
+}
+
+var NonceManagerABI = NonceManagerMetaData.ABI
+
+var NonceManagerBin = NonceManagerMetaData.Bin
+
+func DeployNonceManager(auth *bind.TransactOpts, backend bind.ContractBackend, authorizedCallers []common.Address) (common.Address, *types.Transaction, *NonceManager, error) {
+ parsed, err := NonceManagerMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(NonceManagerBin), backend, authorizedCallers)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &NonceManager{address: address, abi: *parsed, NonceManagerCaller: NonceManagerCaller{contract: contract}, NonceManagerTransactor: NonceManagerTransactor{contract: contract}, NonceManagerFilterer: NonceManagerFilterer{contract: contract}}, nil
+}
+
+type NonceManager struct {
+ address common.Address
+ abi abi.ABI
+ NonceManagerCaller
+ NonceManagerTransactor
+ NonceManagerFilterer
+}
+
+type NonceManagerCaller struct {
+ contract *bind.BoundContract
+}
+
+type NonceManagerTransactor struct {
+ contract *bind.BoundContract
+}
+
+type NonceManagerFilterer struct {
+ contract *bind.BoundContract
+}
+
+type NonceManagerSession struct {
+ Contract *NonceManager
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type NonceManagerCallerSession struct {
+ Contract *NonceManagerCaller
+ CallOpts bind.CallOpts
+}
+
+type NonceManagerTransactorSession struct {
+ Contract *NonceManagerTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type NonceManagerRaw struct {
+ Contract *NonceManager
+}
+
+type NonceManagerCallerRaw struct {
+ Contract *NonceManagerCaller
+}
+
+type NonceManagerTransactorRaw struct {
+ Contract *NonceManagerTransactor
+}
+
+func NewNonceManager(address common.Address, backend bind.ContractBackend) (*NonceManager, error) {
+ abi, err := abi.JSON(strings.NewReader(NonceManagerABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindNonceManager(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManager{address: address, abi: abi, NonceManagerCaller: NonceManagerCaller{contract: contract}, NonceManagerTransactor: NonceManagerTransactor{contract: contract}, NonceManagerFilterer: NonceManagerFilterer{contract: contract}}, nil
+}
+
+func NewNonceManagerCaller(address common.Address, caller bind.ContractCaller) (*NonceManagerCaller, error) {
+ contract, err := bindNonceManager(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerCaller{contract: contract}, nil
+}
+
+func NewNonceManagerTransactor(address common.Address, transactor bind.ContractTransactor) (*NonceManagerTransactor, error) {
+ contract, err := bindNonceManager(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerTransactor{contract: contract}, nil
+}
+
+func NewNonceManagerFilterer(address common.Address, filterer bind.ContractFilterer) (*NonceManagerFilterer, error) {
+ contract, err := bindNonceManager(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerFilterer{contract: contract}, nil
+}
+
+func bindNonceManager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := NonceManagerMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_NonceManager *NonceManagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _NonceManager.Contract.NonceManagerCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_NonceManager *NonceManagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _NonceManager.Contract.NonceManagerTransactor.contract.Transfer(opts)
+}
+
+func (_NonceManager *NonceManagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _NonceManager.Contract.NonceManagerTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_NonceManager *NonceManagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _NonceManager.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_NonceManager *NonceManagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _NonceManager.Contract.contract.Transfer(opts)
+}
+
+func (_NonceManager *NonceManagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _NonceManager.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_NonceManager *NonceManagerCaller) GetAllAuthorizedCallers(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _NonceManager.contract.Call(opts, &out, "getAllAuthorizedCallers")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_NonceManager *NonceManagerSession) GetAllAuthorizedCallers() ([]common.Address, error) {
+ return _NonceManager.Contract.GetAllAuthorizedCallers(&_NonceManager.CallOpts)
+}
+
+func (_NonceManager *NonceManagerCallerSession) GetAllAuthorizedCallers() ([]common.Address, error) {
+ return _NonceManager.Contract.GetAllAuthorizedCallers(&_NonceManager.CallOpts)
+}
+
+func (_NonceManager *NonceManagerCaller) GetInboundNonce(opts *bind.CallOpts, sourceChainSelector uint64, sender []byte) (uint64, error) {
+ var out []interface{}
+ err := _NonceManager.contract.Call(opts, &out, "getInboundNonce", sourceChainSelector, sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_NonceManager *NonceManagerSession) GetInboundNonce(sourceChainSelector uint64, sender []byte) (uint64, error) {
+ return _NonceManager.Contract.GetInboundNonce(&_NonceManager.CallOpts, sourceChainSelector, sender)
+}
+
+func (_NonceManager *NonceManagerCallerSession) GetInboundNonce(sourceChainSelector uint64, sender []byte) (uint64, error) {
+ return _NonceManager.Contract.GetInboundNonce(&_NonceManager.CallOpts, sourceChainSelector, sender)
+}
+
+func (_NonceManager *NonceManagerCaller) GetOutboundNonce(opts *bind.CallOpts, destChainSelector uint64, sender common.Address) (uint64, error) {
+ var out []interface{}
+ err := _NonceManager.contract.Call(opts, &out, "getOutboundNonce", destChainSelector, sender)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_NonceManager *NonceManagerSession) GetOutboundNonce(destChainSelector uint64, sender common.Address) (uint64, error) {
+ return _NonceManager.Contract.GetOutboundNonce(&_NonceManager.CallOpts, destChainSelector, sender)
+}
+
+func (_NonceManager *NonceManagerCallerSession) GetOutboundNonce(destChainSelector uint64, sender common.Address) (uint64, error) {
+ return _NonceManager.Contract.GetOutboundNonce(&_NonceManager.CallOpts, destChainSelector, sender)
+}
+
+func (_NonceManager *NonceManagerCaller) GetPreviousRamps(opts *bind.CallOpts, chainSelector uint64) (NonceManagerPreviousRamps, error) {
+ var out []interface{}
+ err := _NonceManager.contract.Call(opts, &out, "getPreviousRamps", chainSelector)
+
+ if err != nil {
+ return *new(NonceManagerPreviousRamps), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(NonceManagerPreviousRamps)).(*NonceManagerPreviousRamps)
+
+ return out0, err
+
+}
+
+func (_NonceManager *NonceManagerSession) GetPreviousRamps(chainSelector uint64) (NonceManagerPreviousRamps, error) {
+ return _NonceManager.Contract.GetPreviousRamps(&_NonceManager.CallOpts, chainSelector)
+}
+
+func (_NonceManager *NonceManagerCallerSession) GetPreviousRamps(chainSelector uint64) (NonceManagerPreviousRamps, error) {
+ return _NonceManager.Contract.GetPreviousRamps(&_NonceManager.CallOpts, chainSelector)
+}
+
+func (_NonceManager *NonceManagerCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _NonceManager.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_NonceManager *NonceManagerSession) Owner() (common.Address, error) {
+ return _NonceManager.Contract.Owner(&_NonceManager.CallOpts)
+}
+
+func (_NonceManager *NonceManagerCallerSession) Owner() (common.Address, error) {
+ return _NonceManager.Contract.Owner(&_NonceManager.CallOpts)
+}
+
+func (_NonceManager *NonceManagerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _NonceManager.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_NonceManager *NonceManagerSession) AcceptOwnership() (*types.Transaction, error) {
+ return _NonceManager.Contract.AcceptOwnership(&_NonceManager.TransactOpts)
+}
+
+func (_NonceManager *NonceManagerTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _NonceManager.Contract.AcceptOwnership(&_NonceManager.TransactOpts)
+}
+
+func (_NonceManager *NonceManagerTransactor) ApplyAuthorizedCallerUpdates(opts *bind.TransactOpts, authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _NonceManager.contract.Transact(opts, "applyAuthorizedCallerUpdates", authorizedCallerArgs)
+}
+
+func (_NonceManager *NonceManagerSession) ApplyAuthorizedCallerUpdates(authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _NonceManager.Contract.ApplyAuthorizedCallerUpdates(&_NonceManager.TransactOpts, authorizedCallerArgs)
+}
+
+func (_NonceManager *NonceManagerTransactorSession) ApplyAuthorizedCallerUpdates(authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _NonceManager.Contract.ApplyAuthorizedCallerUpdates(&_NonceManager.TransactOpts, authorizedCallerArgs)
+}
+
+func (_NonceManager *NonceManagerTransactor) ApplyPreviousRampsUpdates(opts *bind.TransactOpts, previousRampsArgs []NonceManagerPreviousRampsArgs) (*types.Transaction, error) {
+ return _NonceManager.contract.Transact(opts, "applyPreviousRampsUpdates", previousRampsArgs)
+}
+
+func (_NonceManager *NonceManagerSession) ApplyPreviousRampsUpdates(previousRampsArgs []NonceManagerPreviousRampsArgs) (*types.Transaction, error) {
+ return _NonceManager.Contract.ApplyPreviousRampsUpdates(&_NonceManager.TransactOpts, previousRampsArgs)
+}
+
+func (_NonceManager *NonceManagerTransactorSession) ApplyPreviousRampsUpdates(previousRampsArgs []NonceManagerPreviousRampsArgs) (*types.Transaction, error) {
+ return _NonceManager.Contract.ApplyPreviousRampsUpdates(&_NonceManager.TransactOpts, previousRampsArgs)
+}
+
+func (_NonceManager *NonceManagerTransactor) GetIncrementedOutboundNonce(opts *bind.TransactOpts, destChainSelector uint64, sender common.Address) (*types.Transaction, error) {
+ return _NonceManager.contract.Transact(opts, "getIncrementedOutboundNonce", destChainSelector, sender)
+}
+
+func (_NonceManager *NonceManagerSession) GetIncrementedOutboundNonce(destChainSelector uint64, sender common.Address) (*types.Transaction, error) {
+ return _NonceManager.Contract.GetIncrementedOutboundNonce(&_NonceManager.TransactOpts, destChainSelector, sender)
+}
+
+func (_NonceManager *NonceManagerTransactorSession) GetIncrementedOutboundNonce(destChainSelector uint64, sender common.Address) (*types.Transaction, error) {
+ return _NonceManager.Contract.GetIncrementedOutboundNonce(&_NonceManager.TransactOpts, destChainSelector, sender)
+}
+
+func (_NonceManager *NonceManagerTransactor) IncrementInboundNonce(opts *bind.TransactOpts, sourceChainSelector uint64, expectedNonce uint64, sender []byte) (*types.Transaction, error) {
+ return _NonceManager.contract.Transact(opts, "incrementInboundNonce", sourceChainSelector, expectedNonce, sender)
+}
+
+func (_NonceManager *NonceManagerSession) IncrementInboundNonce(sourceChainSelector uint64, expectedNonce uint64, sender []byte) (*types.Transaction, error) {
+ return _NonceManager.Contract.IncrementInboundNonce(&_NonceManager.TransactOpts, sourceChainSelector, expectedNonce, sender)
+}
+
+func (_NonceManager *NonceManagerTransactorSession) IncrementInboundNonce(sourceChainSelector uint64, expectedNonce uint64, sender []byte) (*types.Transaction, error) {
+ return _NonceManager.Contract.IncrementInboundNonce(&_NonceManager.TransactOpts, sourceChainSelector, expectedNonce, sender)
+}
+
+func (_NonceManager *NonceManagerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _NonceManager.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_NonceManager *NonceManagerSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _NonceManager.Contract.TransferOwnership(&_NonceManager.TransactOpts, to)
+}
+
+func (_NonceManager *NonceManagerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _NonceManager.Contract.TransferOwnership(&_NonceManager.TransactOpts, to)
+}
+
+type NonceManagerAuthorizedCallerAddedIterator struct {
+ Event *NonceManagerAuthorizedCallerAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NonceManagerAuthorizedCallerAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NonceManagerAuthorizedCallerAdded)
+ 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(NonceManagerAuthorizedCallerAdded)
+ 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 *NonceManagerAuthorizedCallerAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *NonceManagerAuthorizedCallerAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NonceManagerAuthorizedCallerAdded struct {
+ Caller common.Address
+ Raw types.Log
+}
+
+func (_NonceManager *NonceManagerFilterer) FilterAuthorizedCallerAdded(opts *bind.FilterOpts) (*NonceManagerAuthorizedCallerAddedIterator, error) {
+
+ logs, sub, err := _NonceManager.contract.FilterLogs(opts, "AuthorizedCallerAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerAuthorizedCallerAddedIterator{contract: _NonceManager.contract, event: "AuthorizedCallerAdded", logs: logs, sub: sub}, nil
+}
+
+func (_NonceManager *NonceManagerFilterer) WatchAuthorizedCallerAdded(opts *bind.WatchOpts, sink chan<- *NonceManagerAuthorizedCallerAdded) (event.Subscription, error) {
+
+ logs, sub, err := _NonceManager.contract.WatchLogs(opts, "AuthorizedCallerAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NonceManagerAuthorizedCallerAdded)
+ if err := _NonceManager.contract.UnpackLog(event, "AuthorizedCallerAdded", 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 (_NonceManager *NonceManagerFilterer) ParseAuthorizedCallerAdded(log types.Log) (*NonceManagerAuthorizedCallerAdded, error) {
+ event := new(NonceManagerAuthorizedCallerAdded)
+ if err := _NonceManager.contract.UnpackLog(event, "AuthorizedCallerAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type NonceManagerAuthorizedCallerRemovedIterator struct {
+ Event *NonceManagerAuthorizedCallerRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NonceManagerAuthorizedCallerRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NonceManagerAuthorizedCallerRemoved)
+ 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(NonceManagerAuthorizedCallerRemoved)
+ 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 *NonceManagerAuthorizedCallerRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *NonceManagerAuthorizedCallerRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NonceManagerAuthorizedCallerRemoved struct {
+ Caller common.Address
+ Raw types.Log
+}
+
+func (_NonceManager *NonceManagerFilterer) FilterAuthorizedCallerRemoved(opts *bind.FilterOpts) (*NonceManagerAuthorizedCallerRemovedIterator, error) {
+
+ logs, sub, err := _NonceManager.contract.FilterLogs(opts, "AuthorizedCallerRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerAuthorizedCallerRemovedIterator{contract: _NonceManager.contract, event: "AuthorizedCallerRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_NonceManager *NonceManagerFilterer) WatchAuthorizedCallerRemoved(opts *bind.WatchOpts, sink chan<- *NonceManagerAuthorizedCallerRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _NonceManager.contract.WatchLogs(opts, "AuthorizedCallerRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NonceManagerAuthorizedCallerRemoved)
+ if err := _NonceManager.contract.UnpackLog(event, "AuthorizedCallerRemoved", 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 (_NonceManager *NonceManagerFilterer) ParseAuthorizedCallerRemoved(log types.Log) (*NonceManagerAuthorizedCallerRemoved, error) {
+ event := new(NonceManagerAuthorizedCallerRemoved)
+ if err := _NonceManager.contract.UnpackLog(event, "AuthorizedCallerRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type NonceManagerOwnershipTransferRequestedIterator struct {
+ Event *NonceManagerOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NonceManagerOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NonceManagerOwnershipTransferRequested)
+ 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(NonceManagerOwnershipTransferRequested)
+ 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 *NonceManagerOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *NonceManagerOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NonceManagerOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_NonceManager *NonceManagerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NonceManagerOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _NonceManager.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerOwnershipTransferRequestedIterator{contract: _NonceManager.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_NonceManager *NonceManagerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *NonceManagerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _NonceManager.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NonceManagerOwnershipTransferRequested)
+ if err := _NonceManager.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_NonceManager *NonceManagerFilterer) ParseOwnershipTransferRequested(log types.Log) (*NonceManagerOwnershipTransferRequested, error) {
+ event := new(NonceManagerOwnershipTransferRequested)
+ if err := _NonceManager.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type NonceManagerOwnershipTransferredIterator struct {
+ Event *NonceManagerOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NonceManagerOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NonceManagerOwnershipTransferred)
+ 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(NonceManagerOwnershipTransferred)
+ 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 *NonceManagerOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *NonceManagerOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NonceManagerOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_NonceManager *NonceManagerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NonceManagerOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _NonceManager.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerOwnershipTransferredIterator{contract: _NonceManager.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_NonceManager *NonceManagerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *NonceManagerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _NonceManager.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NonceManagerOwnershipTransferred)
+ if err := _NonceManager.contract.UnpackLog(event, "OwnershipTransferred", 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 (_NonceManager *NonceManagerFilterer) ParseOwnershipTransferred(log types.Log) (*NonceManagerOwnershipTransferred, error) {
+ event := new(NonceManagerOwnershipTransferred)
+ if err := _NonceManager.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type NonceManagerPreviousRampsUpdatedIterator struct {
+ Event *NonceManagerPreviousRampsUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NonceManagerPreviousRampsUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NonceManagerPreviousRampsUpdated)
+ 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(NonceManagerPreviousRampsUpdated)
+ 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 *NonceManagerPreviousRampsUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *NonceManagerPreviousRampsUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NonceManagerPreviousRampsUpdated struct {
+ RemoteChainSelector uint64
+ PrevRamp NonceManagerPreviousRamps
+ Raw types.Log
+}
+
+func (_NonceManager *NonceManagerFilterer) FilterPreviousRampsUpdated(opts *bind.FilterOpts, remoteChainSelector []uint64) (*NonceManagerPreviousRampsUpdatedIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _NonceManager.contract.FilterLogs(opts, "PreviousRampsUpdated", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerPreviousRampsUpdatedIterator{contract: _NonceManager.contract, event: "PreviousRampsUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_NonceManager *NonceManagerFilterer) WatchPreviousRampsUpdated(opts *bind.WatchOpts, sink chan<- *NonceManagerPreviousRampsUpdated, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _NonceManager.contract.WatchLogs(opts, "PreviousRampsUpdated", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NonceManagerPreviousRampsUpdated)
+ if err := _NonceManager.contract.UnpackLog(event, "PreviousRampsUpdated", 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 (_NonceManager *NonceManagerFilterer) ParsePreviousRampsUpdated(log types.Log) (*NonceManagerPreviousRampsUpdated, error) {
+ event := new(NonceManagerPreviousRampsUpdated)
+ if err := _NonceManager.contract.UnpackLog(event, "PreviousRampsUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type NonceManagerSkippedIncorrectNonceIterator struct {
+ Event *NonceManagerSkippedIncorrectNonce
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NonceManagerSkippedIncorrectNonceIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NonceManagerSkippedIncorrectNonce)
+ 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(NonceManagerSkippedIncorrectNonce)
+ 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 *NonceManagerSkippedIncorrectNonceIterator) Error() error {
+ return it.fail
+}
+
+func (it *NonceManagerSkippedIncorrectNonceIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NonceManagerSkippedIncorrectNonce struct {
+ SourceChainSelector uint64
+ Nonce uint64
+ Sender []byte
+ Raw types.Log
+}
+
+func (_NonceManager *NonceManagerFilterer) FilterSkippedIncorrectNonce(opts *bind.FilterOpts) (*NonceManagerSkippedIncorrectNonceIterator, error) {
+
+ logs, sub, err := _NonceManager.contract.FilterLogs(opts, "SkippedIncorrectNonce")
+ if err != nil {
+ return nil, err
+ }
+ return &NonceManagerSkippedIncorrectNonceIterator{contract: _NonceManager.contract, event: "SkippedIncorrectNonce", logs: logs, sub: sub}, nil
+}
+
+func (_NonceManager *NonceManagerFilterer) WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *NonceManagerSkippedIncorrectNonce) (event.Subscription, error) {
+
+ logs, sub, err := _NonceManager.contract.WatchLogs(opts, "SkippedIncorrectNonce")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NonceManagerSkippedIncorrectNonce)
+ if err := _NonceManager.contract.UnpackLog(event, "SkippedIncorrectNonce", 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 (_NonceManager *NonceManagerFilterer) ParseSkippedIncorrectNonce(log types.Log) (*NonceManagerSkippedIncorrectNonce, error) {
+ event := new(NonceManagerSkippedIncorrectNonce)
+ if err := _NonceManager.contract.UnpackLog(event, "SkippedIncorrectNonce", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_NonceManager *NonceManager) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _NonceManager.abi.Events["AuthorizedCallerAdded"].ID:
+ return _NonceManager.ParseAuthorizedCallerAdded(log)
+ case _NonceManager.abi.Events["AuthorizedCallerRemoved"].ID:
+ return _NonceManager.ParseAuthorizedCallerRemoved(log)
+ case _NonceManager.abi.Events["OwnershipTransferRequested"].ID:
+ return _NonceManager.ParseOwnershipTransferRequested(log)
+ case _NonceManager.abi.Events["OwnershipTransferred"].ID:
+ return _NonceManager.ParseOwnershipTransferred(log)
+ case _NonceManager.abi.Events["PreviousRampsUpdated"].ID:
+ return _NonceManager.ParsePreviousRampsUpdated(log)
+ case _NonceManager.abi.Events["SkippedIncorrectNonce"].ID:
+ return _NonceManager.ParseSkippedIncorrectNonce(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (NonceManagerAuthorizedCallerAdded) Topic() common.Hash {
+ return common.HexToHash("0xeb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef")
+}
+
+func (NonceManagerAuthorizedCallerRemoved) Topic() common.Hash {
+ return common.HexToHash("0xc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda77580")
+}
+
+func (NonceManagerOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (NonceManagerOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (NonceManagerPreviousRampsUpdated) Topic() common.Hash {
+ return common.HexToHash("0xa2e43edcbc4fd175ae4bebbe3fd6139871ed1f1783cd4a1ace59b90d302c3319")
+}
+
+func (NonceManagerSkippedIncorrectNonce) Topic() common.Hash {
+ return common.HexToHash("0x606ff8179e5e3c059b82df931acc496b7b6053e8879042f8267f930e0595f69f")
+}
+
+func (_NonceManager *NonceManager) Address() common.Address {
+ return _NonceManager.address
+}
+
+type NonceManagerInterface interface {
+ GetAllAuthorizedCallers(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetInboundNonce(opts *bind.CallOpts, sourceChainSelector uint64, sender []byte) (uint64, error)
+
+ GetOutboundNonce(opts *bind.CallOpts, destChainSelector uint64, sender common.Address) (uint64, error)
+
+ GetPreviousRamps(opts *bind.CallOpts, chainSelector uint64) (NonceManagerPreviousRamps, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAuthorizedCallerUpdates(opts *bind.TransactOpts, authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error)
+
+ ApplyPreviousRampsUpdates(opts *bind.TransactOpts, previousRampsArgs []NonceManagerPreviousRampsArgs) (*types.Transaction, error)
+
+ GetIncrementedOutboundNonce(opts *bind.TransactOpts, destChainSelector uint64, sender common.Address) (*types.Transaction, error)
+
+ IncrementInboundNonce(opts *bind.TransactOpts, sourceChainSelector uint64, expectedNonce uint64, sender []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAuthorizedCallerAdded(opts *bind.FilterOpts) (*NonceManagerAuthorizedCallerAddedIterator, error)
+
+ WatchAuthorizedCallerAdded(opts *bind.WatchOpts, sink chan<- *NonceManagerAuthorizedCallerAdded) (event.Subscription, error)
+
+ ParseAuthorizedCallerAdded(log types.Log) (*NonceManagerAuthorizedCallerAdded, error)
+
+ FilterAuthorizedCallerRemoved(opts *bind.FilterOpts) (*NonceManagerAuthorizedCallerRemovedIterator, error)
+
+ WatchAuthorizedCallerRemoved(opts *bind.WatchOpts, sink chan<- *NonceManagerAuthorizedCallerRemoved) (event.Subscription, error)
+
+ ParseAuthorizedCallerRemoved(log types.Log) (*NonceManagerAuthorizedCallerRemoved, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NonceManagerOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *NonceManagerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*NonceManagerOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NonceManagerOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *NonceManagerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*NonceManagerOwnershipTransferred, error)
+
+ FilterPreviousRampsUpdated(opts *bind.FilterOpts, remoteChainSelector []uint64) (*NonceManagerPreviousRampsUpdatedIterator, error)
+
+ WatchPreviousRampsUpdated(opts *bind.WatchOpts, sink chan<- *NonceManagerPreviousRampsUpdated, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParsePreviousRampsUpdated(log types.Log) (*NonceManagerPreviousRampsUpdated, error)
+
+ FilterSkippedIncorrectNonce(opts *bind.FilterOpts) (*NonceManagerSkippedIncorrectNonceIterator, error)
+
+ WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *NonceManagerSkippedIncorrectNonce) (event.Subscription, error)
+
+ ParseSkippedIncorrectNonce(log types.Log) (*NonceManagerSkippedIncorrectNonce, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/ocr3_config_encoder/ocr3_config_encoder.go b/core/gethwrappers/ccip/generated/ocr3_config_encoder/ocr3_config_encoder.go
new file mode 100644
index 00000000000..399ae5dbd62
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/ocr3_config_encoder/ocr3_config_encoder.go
@@ -0,0 +1,196 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package ocr3_config_encoder
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CCIPConfigTypesOCR3Config struct {
+ PluginType uint8
+ ChainSelector uint64
+ F uint8
+ OffchainConfigVersion uint64
+ OfframpAddress []byte
+ BootstrapP2PIds [][32]byte
+ P2pIds [][32]byte
+ Signers [][]byte
+ Transmitters [][]byte
+ OffchainConfig []byte
+}
+
+var IOCR3ConfigEncoderMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"enumInternal.OCRPluginType\",\"name\":\"pluginType\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"F\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offrampAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"bootstrapP2PIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"p2pIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes[]\",\"name\":\"signers\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes[]\",\"name\":\"transmitters\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"internalType\":\"structCCIPConfigTypes.OCR3Config[]\",\"name\":\"config\",\"type\":\"tuple[]\"}],\"name\":\"exposeOCR3Config\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var IOCR3ConfigEncoderABI = IOCR3ConfigEncoderMetaData.ABI
+
+type IOCR3ConfigEncoder struct {
+ address common.Address
+ abi abi.ABI
+ IOCR3ConfigEncoderCaller
+ IOCR3ConfigEncoderTransactor
+ IOCR3ConfigEncoderFilterer
+}
+
+type IOCR3ConfigEncoderCaller struct {
+ contract *bind.BoundContract
+}
+
+type IOCR3ConfigEncoderTransactor struct {
+ contract *bind.BoundContract
+}
+
+type IOCR3ConfigEncoderFilterer struct {
+ contract *bind.BoundContract
+}
+
+type IOCR3ConfigEncoderSession struct {
+ Contract *IOCR3ConfigEncoder
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type IOCR3ConfigEncoderCallerSession struct {
+ Contract *IOCR3ConfigEncoderCaller
+ CallOpts bind.CallOpts
+}
+
+type IOCR3ConfigEncoderTransactorSession struct {
+ Contract *IOCR3ConfigEncoderTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type IOCR3ConfigEncoderRaw struct {
+ Contract *IOCR3ConfigEncoder
+}
+
+type IOCR3ConfigEncoderCallerRaw struct {
+ Contract *IOCR3ConfigEncoderCaller
+}
+
+type IOCR3ConfigEncoderTransactorRaw struct {
+ Contract *IOCR3ConfigEncoderTransactor
+}
+
+func NewIOCR3ConfigEncoder(address common.Address, backend bind.ContractBackend) (*IOCR3ConfigEncoder, error) {
+ abi, err := abi.JSON(strings.NewReader(IOCR3ConfigEncoderABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindIOCR3ConfigEncoder(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &IOCR3ConfigEncoder{address: address, abi: abi, IOCR3ConfigEncoderCaller: IOCR3ConfigEncoderCaller{contract: contract}, IOCR3ConfigEncoderTransactor: IOCR3ConfigEncoderTransactor{contract: contract}, IOCR3ConfigEncoderFilterer: IOCR3ConfigEncoderFilterer{contract: contract}}, nil
+}
+
+func NewIOCR3ConfigEncoderCaller(address common.Address, caller bind.ContractCaller) (*IOCR3ConfigEncoderCaller, error) {
+ contract, err := bindIOCR3ConfigEncoder(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &IOCR3ConfigEncoderCaller{contract: contract}, nil
+}
+
+func NewIOCR3ConfigEncoderTransactor(address common.Address, transactor bind.ContractTransactor) (*IOCR3ConfigEncoderTransactor, error) {
+ contract, err := bindIOCR3ConfigEncoder(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &IOCR3ConfigEncoderTransactor{contract: contract}, nil
+}
+
+func NewIOCR3ConfigEncoderFilterer(address common.Address, filterer bind.ContractFilterer) (*IOCR3ConfigEncoderFilterer, error) {
+ contract, err := bindIOCR3ConfigEncoder(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &IOCR3ConfigEncoderFilterer{contract: contract}, nil
+}
+
+func bindIOCR3ConfigEncoder(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := IOCR3ConfigEncoderMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _IOCR3ConfigEncoder.Contract.IOCR3ConfigEncoderCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _IOCR3ConfigEncoder.Contract.IOCR3ConfigEncoderTransactor.contract.Transfer(opts)
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _IOCR3ConfigEncoder.Contract.IOCR3ConfigEncoderTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _IOCR3ConfigEncoder.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _IOCR3ConfigEncoder.Contract.contract.Transfer(opts)
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _IOCR3ConfigEncoder.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderCaller) ExposeOCR3Config(opts *bind.CallOpts, config []CCIPConfigTypesOCR3Config) ([]byte, error) {
+ var out []interface{}
+ err := _IOCR3ConfigEncoder.contract.Call(opts, &out, "exposeOCR3Config", config)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderSession) ExposeOCR3Config(config []CCIPConfigTypesOCR3Config) ([]byte, error) {
+ return _IOCR3ConfigEncoder.Contract.ExposeOCR3Config(&_IOCR3ConfigEncoder.CallOpts, config)
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoderCallerSession) ExposeOCR3Config(config []CCIPConfigTypesOCR3Config) ([]byte, error) {
+ return _IOCR3ConfigEncoder.Contract.ExposeOCR3Config(&_IOCR3ConfigEncoder.CallOpts, config)
+}
+
+func (_IOCR3ConfigEncoder *IOCR3ConfigEncoder) Address() common.Address {
+ return _IOCR3ConfigEncoder.address
+}
+
+type IOCR3ConfigEncoderInterface interface {
+ ExposeOCR3Config(opts *bind.CallOpts, config []CCIPConfigTypesOCR3Config) ([]byte, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/ping_pong_demo/ping_pong_demo.go b/core/gethwrappers/ccip/generated/ping_pong_demo/ping_pong_demo.go
new file mode 100644
index 00000000000..4387dd3080c
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/ping_pong_demo/ping_pong_demo.go
@@ -0,0 +1,1061 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package ping_pong_demo
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+var PingPongDemoMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"contractIERC20\",\"name\":\"feeToken\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"name\":\"InvalidRouter\",\"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\":\"pingPongCount\",\"type\":\"uint256\"}],\"name\":\"Ping\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"pingPongCount\",\"type\":\"uint256\"}],\"name\":\"Pong\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"ccipReceive\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCounterpartAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCounterpartChainSelector\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isPaused\",\"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\":\"uint64\",\"name\":\"counterpartChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"counterpartAddress\",\"type\":\"address\"}],\"name\":\"setCounterpart\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setCounterpartAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"setCounterpartChainSelector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"pause\",\"type\":\"bool\"}],\"name\":\"setPaused\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startPingPong\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"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\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
+ Bin: "0x60a06040523480156200001157600080fd5b50604051620013d8380380620013d8833981016040819052620000349162000263565b33806000846001600160a01b03811662000069576040516335fdcccd60e21b8152600060048201526024015b60405180910390fd5b6001600160a01b039081166080528216620000c75760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f0000000000000000604482015260640162000060565b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000fa57620000fa816200019f565b50506002805460ff60a01b1916905550600380546001600160a01b0319166001600160a01b0383811691821790925560405163095ea7b360e01b8152918416600483015260001960248301529063095ea7b3906044016020604051808303816000875af115801562000170573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001969190620002a2565b505050620002cd565b336001600160a01b03821603620001f95760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000060565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200026057600080fd5b50565b600080604083850312156200027757600080fd5b825162000284816200024a565b602084015190925062000297816200024a565b809150509250929050565b600060208284031215620002b557600080fd5b81518015158114620002c657600080fd5b9392505050565b6080516110e1620002f7600039600081816102290152818161058e01526108f201526110e16000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80638da5cb5b11610097578063b5a1101111610066578063b5a1101114610270578063bee518a414610283578063ca709a25146102c1578063f2fde38b146102df57600080fd5b80638da5cb5b146101f65780639d2aede514610214578063b0f479a114610227578063b187bd261461024d57600080fd5b80632874d8bf116100d35780632874d8bf146101945780632b6e5d631461019c57806379ba5097146101db57806385572ffb146101e357600080fd5b806301ffc9a71461010557806316c38b3c1461012d578063181f5a77146101425780631892b90614610181575b600080fd5b610118610113366004610af5565b6102f2565b60405190151581526020015b60405180910390f35b61014061013b366004610b3e565b61038b565b005b604080518082018252601281527f50696e67506f6e6744656d6f20312e322e300000000000000000000000000000602082015290516101249190610bc4565b61014061018f366004610bf4565b6103dd565b610140610438565b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b610140610474565b6101406101f1366004610c0f565b610576565b60005473ffffffffffffffffffffffffffffffffffffffff166101b6565b610140610222366004610c6e565b6105fb565b7f00000000000000000000000000000000000000000000000000000000000000006101b6565b60025474010000000000000000000000000000000000000000900460ff16610118565b61014061027e366004610c89565b61064a565b60015474010000000000000000000000000000000000000000900467ffffffffffffffff1660405167ffffffffffffffff9091168152602001610124565b60035473ffffffffffffffffffffffffffffffffffffffff166101b6565b6101406102ed366004610c6e565b6106ec565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f85572ffb00000000000000000000000000000000000000000000000000000000148061038557507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6103936106fd565b6002805491151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6103e56106fd565b6001805467ffffffffffffffff90921674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6104406106fd565b600280547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055610472600161077e565b565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146105e7576040517fd7f733340000000000000000000000000000000000000000000000000000000081523360048201526024016104f1565b6105f86105f382610ebf565b6109aa565b50565b6106036106fd565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6106526106fd565b6001805467ffffffffffffffff90931674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff909316929092179091556002805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216919091179055565b6106f46106fd565b6105f881610a00565b60005473ffffffffffffffffffffffffffffffffffffffff163314610472576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016104f1565b806001166001036107c1576040518181527f48257dc961b6f792c2b78a080dacfed693b660960a702de21cee364e20270e2f9060200160405180910390a16107f5565b6040518181527f58b69f57828e6962d216502094c54f6562f3bf082ba758966c3454f9e37b15259060200160405180910390a15b60008160405160200161080a91815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815260a08301825260025473ffffffffffffffffffffffffffffffffffffffff1660c0808501919091528251808503909101815260e084018352835260208084018290528251600080825291810184529194509291820190836108b8565b60408051808201909152600080825260208201528152602001906001900390816108915790505b50815260035473ffffffffffffffffffffffffffffffffffffffff16602080830191909152604080519182018152600082529091015290507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166396f4e9f9600160149054906101000a900467ffffffffffffffff16836040518363ffffffff1660e01b8152600401610961929190610f6c565b6020604051808303816000875af1158015610980573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a49190611081565b50505050565b600081606001518060200190518101906109c49190611081565b60025490915074010000000000000000000000000000000000000000900460ff166109fc576109fc6109f782600161109a565b61077e565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603610a7f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016104f1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215610b0757600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b3757600080fd5b9392505050565b600060208284031215610b5057600080fd5b81358015158114610b3757600080fd5b6000815180845260005b81811015610b8657602081850181015186830182015201610b6a565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610b376020830184610b60565b803567ffffffffffffffff81168114610bef57600080fd5b919050565b600060208284031215610c0657600080fd5b610b3782610bd7565b600060208284031215610c2157600080fd5b813567ffffffffffffffff811115610c3857600080fd5b820160a08185031215610b3757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff81168114610bef57600080fd5b600060208284031215610c8057600080fd5b610b3782610c4a565b60008060408385031215610c9c57600080fd5b610ca583610bd7565b9150610cb360208401610c4a565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610d0e57610d0e610cbc565b60405290565b60405160a0810167ffffffffffffffff81118282101715610d0e57610d0e610cbc565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d7e57610d7e610cbc565b604052919050565b600082601f830112610d9757600080fd5b813567ffffffffffffffff811115610db157610db1610cbc565b610de260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610d37565b818152846020838601011115610df757600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f830112610e2557600080fd5b8135602067ffffffffffffffff821115610e4157610e41610cbc565b610e4f818360051b01610d37565b82815260069290921b84018101918181019086841115610e6e57600080fd5b8286015b84811015610eb45760408189031215610e8b5760008081fd5b610e93610ceb565b610e9c82610c4a565b81528185013585820152835291830191604001610e72565b509695505050505050565b600060a08236031215610ed157600080fd5b610ed9610d14565b82358152610ee960208401610bd7565b6020820152604083013567ffffffffffffffff80821115610f0957600080fd5b610f1536838701610d86565b60408401526060850135915080821115610f2e57600080fd5b610f3a36838701610d86565b60608401526080850135915080821115610f5357600080fd5b50610f6036828601610e14565b60808301525092915050565b6000604067ffffffffffffffff851683526020604081850152845160a06040860152610f9b60e0860182610b60565b9050818601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc080878403016060880152610fd68383610b60565b6040890151888203830160808a01528051808352908601945060009350908501905b80841015611037578451805173ffffffffffffffffffffffffffffffffffffffff16835286015186830152938501936001939093019290860190610ff8565b50606089015173ffffffffffffffffffffffffffffffffffffffff1660a08901526080890151888203830160c08a015295506110738187610b60565b9a9950505050505050505050565b60006020828403121561109357600080fd5b5051919050565b80820180821115610385577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea164736f6c6343000818000a",
+}
+
+var PingPongDemoABI = PingPongDemoMetaData.ABI
+
+var PingPongDemoBin = PingPongDemoMetaData.Bin
+
+func DeployPingPongDemo(auth *bind.TransactOpts, backend bind.ContractBackend, router common.Address, feeToken common.Address) (common.Address, *types.Transaction, *PingPongDemo, error) {
+ parsed, err := PingPongDemoMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(PingPongDemoBin), backend, router, feeToken)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &PingPongDemo{address: address, abi: *parsed, PingPongDemoCaller: PingPongDemoCaller{contract: contract}, PingPongDemoTransactor: PingPongDemoTransactor{contract: contract}, PingPongDemoFilterer: PingPongDemoFilterer{contract: contract}}, nil
+}
+
+type PingPongDemo struct {
+ address common.Address
+ abi abi.ABI
+ PingPongDemoCaller
+ PingPongDemoTransactor
+ PingPongDemoFilterer
+}
+
+type PingPongDemoCaller struct {
+ contract *bind.BoundContract
+}
+
+type PingPongDemoTransactor struct {
+ contract *bind.BoundContract
+}
+
+type PingPongDemoFilterer struct {
+ contract *bind.BoundContract
+}
+
+type PingPongDemoSession struct {
+ Contract *PingPongDemo
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type PingPongDemoCallerSession struct {
+ Contract *PingPongDemoCaller
+ CallOpts bind.CallOpts
+}
+
+type PingPongDemoTransactorSession struct {
+ Contract *PingPongDemoTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type PingPongDemoRaw struct {
+ Contract *PingPongDemo
+}
+
+type PingPongDemoCallerRaw struct {
+ Contract *PingPongDemoCaller
+}
+
+type PingPongDemoTransactorRaw struct {
+ Contract *PingPongDemoTransactor
+}
+
+func NewPingPongDemo(address common.Address, backend bind.ContractBackend) (*PingPongDemo, error) {
+ abi, err := abi.JSON(strings.NewReader(PingPongDemoABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindPingPongDemo(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &PingPongDemo{address: address, abi: abi, PingPongDemoCaller: PingPongDemoCaller{contract: contract}, PingPongDemoTransactor: PingPongDemoTransactor{contract: contract}, PingPongDemoFilterer: PingPongDemoFilterer{contract: contract}}, nil
+}
+
+func NewPingPongDemoCaller(address common.Address, caller bind.ContractCaller) (*PingPongDemoCaller, error) {
+ contract, err := bindPingPongDemo(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PingPongDemoCaller{contract: contract}, nil
+}
+
+func NewPingPongDemoTransactor(address common.Address, transactor bind.ContractTransactor) (*PingPongDemoTransactor, error) {
+ contract, err := bindPingPongDemo(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PingPongDemoTransactor{contract: contract}, nil
+}
+
+func NewPingPongDemoFilterer(address common.Address, filterer bind.ContractFilterer) (*PingPongDemoFilterer, error) {
+ contract, err := bindPingPongDemo(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &PingPongDemoFilterer{contract: contract}, nil
+}
+
+func bindPingPongDemo(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := PingPongDemoMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_PingPongDemo *PingPongDemoRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _PingPongDemo.Contract.PingPongDemoCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_PingPongDemo *PingPongDemoRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.PingPongDemoTransactor.contract.Transfer(opts)
+}
+
+func (_PingPongDemo *PingPongDemoRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.PingPongDemoTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_PingPongDemo *PingPongDemoCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _PingPongDemo.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.contract.Transfer(opts)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_PingPongDemo *PingPongDemoCaller) GetCounterpartAddress(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _PingPongDemo.contract.Call(opts, &out, "getCounterpartAddress")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_PingPongDemo *PingPongDemoSession) GetCounterpartAddress() (common.Address, error) {
+ return _PingPongDemo.Contract.GetCounterpartAddress(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCallerSession) GetCounterpartAddress() (common.Address, error) {
+ return _PingPongDemo.Contract.GetCounterpartAddress(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCaller) GetCounterpartChainSelector(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _PingPongDemo.contract.Call(opts, &out, "getCounterpartChainSelector")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_PingPongDemo *PingPongDemoSession) GetCounterpartChainSelector() (uint64, error) {
+ return _PingPongDemo.Contract.GetCounterpartChainSelector(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCallerSession) GetCounterpartChainSelector() (uint64, error) {
+ return _PingPongDemo.Contract.GetCounterpartChainSelector(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCaller) GetFeeToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _PingPongDemo.contract.Call(opts, &out, "getFeeToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_PingPongDemo *PingPongDemoSession) GetFeeToken() (common.Address, error) {
+ return _PingPongDemo.Contract.GetFeeToken(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCallerSession) GetFeeToken() (common.Address, error) {
+ return _PingPongDemo.Contract.GetFeeToken(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _PingPongDemo.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_PingPongDemo *PingPongDemoSession) GetRouter() (common.Address, error) {
+ return _PingPongDemo.Contract.GetRouter(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCallerSession) GetRouter() (common.Address, error) {
+ return _PingPongDemo.Contract.GetRouter(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCaller) IsPaused(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _PingPongDemo.contract.Call(opts, &out, "isPaused")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_PingPongDemo *PingPongDemoSession) IsPaused() (bool, error) {
+ return _PingPongDemo.Contract.IsPaused(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCallerSession) IsPaused() (bool, error) {
+ return _PingPongDemo.Contract.IsPaused(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _PingPongDemo.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_PingPongDemo *PingPongDemoSession) Owner() (common.Address, error) {
+ return _PingPongDemo.Contract.Owner(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCallerSession) Owner() (common.Address, error) {
+ return _PingPongDemo.Contract.Owner(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _PingPongDemo.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_PingPongDemo *PingPongDemoSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _PingPongDemo.Contract.SupportsInterface(&_PingPongDemo.CallOpts, interfaceId)
+}
+
+func (_PingPongDemo *PingPongDemoCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _PingPongDemo.Contract.SupportsInterface(&_PingPongDemo.CallOpts, interfaceId)
+}
+
+func (_PingPongDemo *PingPongDemoCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _PingPongDemo.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_PingPongDemo *PingPongDemoSession) TypeAndVersion() (string, error) {
+ return _PingPongDemo.Contract.TypeAndVersion(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoCallerSession) TypeAndVersion() (string, error) {
+ return _PingPongDemo.Contract.TypeAndVersion(&_PingPongDemo.CallOpts)
+}
+
+func (_PingPongDemo *PingPongDemoTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PingPongDemo.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_PingPongDemo *PingPongDemoSession) AcceptOwnership() (*types.Transaction, error) {
+ return _PingPongDemo.Contract.AcceptOwnership(&_PingPongDemo.TransactOpts)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _PingPongDemo.Contract.AcceptOwnership(&_PingPongDemo.TransactOpts)
+}
+
+func (_PingPongDemo *PingPongDemoTransactor) CcipReceive(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _PingPongDemo.contract.Transact(opts, "ccipReceive", message)
+}
+
+func (_PingPongDemo *PingPongDemoSession) CcipReceive(message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.CcipReceive(&_PingPongDemo.TransactOpts, message)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorSession) CcipReceive(message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.CcipReceive(&_PingPongDemo.TransactOpts, message)
+}
+
+func (_PingPongDemo *PingPongDemoTransactor) SetCounterpart(opts *bind.TransactOpts, counterpartChainSelector uint64, counterpartAddress common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.contract.Transact(opts, "setCounterpart", counterpartChainSelector, counterpartAddress)
+}
+
+func (_PingPongDemo *PingPongDemoSession) SetCounterpart(counterpartChainSelector uint64, counterpartAddress common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.SetCounterpart(&_PingPongDemo.TransactOpts, counterpartChainSelector, counterpartAddress)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorSession) SetCounterpart(counterpartChainSelector uint64, counterpartAddress common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.SetCounterpart(&_PingPongDemo.TransactOpts, counterpartChainSelector, counterpartAddress)
+}
+
+func (_PingPongDemo *PingPongDemoTransactor) SetCounterpartAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.contract.Transact(opts, "setCounterpartAddress", addr)
+}
+
+func (_PingPongDemo *PingPongDemoSession) SetCounterpartAddress(addr common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.SetCounterpartAddress(&_PingPongDemo.TransactOpts, addr)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorSession) SetCounterpartAddress(addr common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.SetCounterpartAddress(&_PingPongDemo.TransactOpts, addr)
+}
+
+func (_PingPongDemo *PingPongDemoTransactor) SetCounterpartChainSelector(opts *bind.TransactOpts, chainSelector uint64) (*types.Transaction, error) {
+ return _PingPongDemo.contract.Transact(opts, "setCounterpartChainSelector", chainSelector)
+}
+
+func (_PingPongDemo *PingPongDemoSession) SetCounterpartChainSelector(chainSelector uint64) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.SetCounterpartChainSelector(&_PingPongDemo.TransactOpts, chainSelector)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorSession) SetCounterpartChainSelector(chainSelector uint64) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.SetCounterpartChainSelector(&_PingPongDemo.TransactOpts, chainSelector)
+}
+
+func (_PingPongDemo *PingPongDemoTransactor) SetPaused(opts *bind.TransactOpts, pause bool) (*types.Transaction, error) {
+ return _PingPongDemo.contract.Transact(opts, "setPaused", pause)
+}
+
+func (_PingPongDemo *PingPongDemoSession) SetPaused(pause bool) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.SetPaused(&_PingPongDemo.TransactOpts, pause)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorSession) SetPaused(pause bool) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.SetPaused(&_PingPongDemo.TransactOpts, pause)
+}
+
+func (_PingPongDemo *PingPongDemoTransactor) StartPingPong(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PingPongDemo.contract.Transact(opts, "startPingPong")
+}
+
+func (_PingPongDemo *PingPongDemoSession) StartPingPong() (*types.Transaction, error) {
+ return _PingPongDemo.Contract.StartPingPong(&_PingPongDemo.TransactOpts)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorSession) StartPingPong() (*types.Transaction, error) {
+ return _PingPongDemo.Contract.StartPingPong(&_PingPongDemo.TransactOpts)
+}
+
+func (_PingPongDemo *PingPongDemoTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_PingPongDemo *PingPongDemoSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.TransferOwnership(&_PingPongDemo.TransactOpts, to)
+}
+
+func (_PingPongDemo *PingPongDemoTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _PingPongDemo.Contract.TransferOwnership(&_PingPongDemo.TransactOpts, to)
+}
+
+type PingPongDemoOwnershipTransferRequestedIterator struct {
+ Event *PingPongDemoOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PingPongDemoOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PingPongDemoOwnershipTransferRequested)
+ 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(PingPongDemoOwnershipTransferRequested)
+ 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 *PingPongDemoOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PingPongDemoOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PingPongDemoOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_PingPongDemo *PingPongDemoFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PingPongDemoOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PingPongDemo.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PingPongDemoOwnershipTransferRequestedIterator{contract: _PingPongDemo.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_PingPongDemo *PingPongDemoFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *PingPongDemoOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PingPongDemo.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PingPongDemoOwnershipTransferRequested)
+ if err := _PingPongDemo.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_PingPongDemo *PingPongDemoFilterer) ParseOwnershipTransferRequested(log types.Log) (*PingPongDemoOwnershipTransferRequested, error) {
+ event := new(PingPongDemoOwnershipTransferRequested)
+ if err := _PingPongDemo.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PingPongDemoOwnershipTransferredIterator struct {
+ Event *PingPongDemoOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PingPongDemoOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PingPongDemoOwnershipTransferred)
+ 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(PingPongDemoOwnershipTransferred)
+ 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 *PingPongDemoOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *PingPongDemoOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PingPongDemoOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_PingPongDemo *PingPongDemoFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PingPongDemoOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PingPongDemo.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PingPongDemoOwnershipTransferredIterator{contract: _PingPongDemo.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_PingPongDemo *PingPongDemoFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *PingPongDemoOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PingPongDemo.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PingPongDemoOwnershipTransferred)
+ if err := _PingPongDemo.contract.UnpackLog(event, "OwnershipTransferred", 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 (_PingPongDemo *PingPongDemoFilterer) ParseOwnershipTransferred(log types.Log) (*PingPongDemoOwnershipTransferred, error) {
+ event := new(PingPongDemoOwnershipTransferred)
+ if err := _PingPongDemo.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PingPongDemoPingIterator struct {
+ Event *PingPongDemoPing
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PingPongDemoPingIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PingPongDemoPing)
+ 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(PingPongDemoPing)
+ 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 *PingPongDemoPingIterator) Error() error {
+ return it.fail
+}
+
+func (it *PingPongDemoPingIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PingPongDemoPing struct {
+ PingPongCount *big.Int
+ Raw types.Log
+}
+
+func (_PingPongDemo *PingPongDemoFilterer) FilterPing(opts *bind.FilterOpts) (*PingPongDemoPingIterator, error) {
+
+ logs, sub, err := _PingPongDemo.contract.FilterLogs(opts, "Ping")
+ if err != nil {
+ return nil, err
+ }
+ return &PingPongDemoPingIterator{contract: _PingPongDemo.contract, event: "Ping", logs: logs, sub: sub}, nil
+}
+
+func (_PingPongDemo *PingPongDemoFilterer) WatchPing(opts *bind.WatchOpts, sink chan<- *PingPongDemoPing) (event.Subscription, error) {
+
+ logs, sub, err := _PingPongDemo.contract.WatchLogs(opts, "Ping")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PingPongDemoPing)
+ if err := _PingPongDemo.contract.UnpackLog(event, "Ping", 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 (_PingPongDemo *PingPongDemoFilterer) ParsePing(log types.Log) (*PingPongDemoPing, error) {
+ event := new(PingPongDemoPing)
+ if err := _PingPongDemo.contract.UnpackLog(event, "Ping", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PingPongDemoPongIterator struct {
+ Event *PingPongDemoPong
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PingPongDemoPongIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PingPongDemoPong)
+ 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(PingPongDemoPong)
+ 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 *PingPongDemoPongIterator) Error() error {
+ return it.fail
+}
+
+func (it *PingPongDemoPongIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PingPongDemoPong struct {
+ PingPongCount *big.Int
+ Raw types.Log
+}
+
+func (_PingPongDemo *PingPongDemoFilterer) FilterPong(opts *bind.FilterOpts) (*PingPongDemoPongIterator, error) {
+
+ logs, sub, err := _PingPongDemo.contract.FilterLogs(opts, "Pong")
+ if err != nil {
+ return nil, err
+ }
+ return &PingPongDemoPongIterator{contract: _PingPongDemo.contract, event: "Pong", logs: logs, sub: sub}, nil
+}
+
+func (_PingPongDemo *PingPongDemoFilterer) WatchPong(opts *bind.WatchOpts, sink chan<- *PingPongDemoPong) (event.Subscription, error) {
+
+ logs, sub, err := _PingPongDemo.contract.WatchLogs(opts, "Pong")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PingPongDemoPong)
+ if err := _PingPongDemo.contract.UnpackLog(event, "Pong", 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 (_PingPongDemo *PingPongDemoFilterer) ParsePong(log types.Log) (*PingPongDemoPong, error) {
+ event := new(PingPongDemoPong)
+ if err := _PingPongDemo.contract.UnpackLog(event, "Pong", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_PingPongDemo *PingPongDemo) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _PingPongDemo.abi.Events["OwnershipTransferRequested"].ID:
+ return _PingPongDemo.ParseOwnershipTransferRequested(log)
+ case _PingPongDemo.abi.Events["OwnershipTransferred"].ID:
+ return _PingPongDemo.ParseOwnershipTransferred(log)
+ case _PingPongDemo.abi.Events["Ping"].ID:
+ return _PingPongDemo.ParsePing(log)
+ case _PingPongDemo.abi.Events["Pong"].ID:
+ return _PingPongDemo.ParsePong(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (PingPongDemoOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (PingPongDemoOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (PingPongDemoPing) Topic() common.Hash {
+ return common.HexToHash("0x48257dc961b6f792c2b78a080dacfed693b660960a702de21cee364e20270e2f")
+}
+
+func (PingPongDemoPong) Topic() common.Hash {
+ return common.HexToHash("0x58b69f57828e6962d216502094c54f6562f3bf082ba758966c3454f9e37b1525")
+}
+
+func (_PingPongDemo *PingPongDemo) Address() common.Address {
+ return _PingPongDemo.address
+}
+
+type PingPongDemoInterface interface {
+ GetCounterpartAddress(opts *bind.CallOpts) (common.Address, error)
+
+ GetCounterpartChainSelector(opts *bind.CallOpts) (uint64, error)
+
+ GetFeeToken(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ IsPaused(opts *bind.CallOpts) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ CcipReceive(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error)
+
+ SetCounterpart(opts *bind.TransactOpts, counterpartChainSelector uint64, counterpartAddress common.Address) (*types.Transaction, error)
+
+ SetCounterpartAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error)
+
+ SetCounterpartChainSelector(opts *bind.TransactOpts, chainSelector uint64) (*types.Transaction, error)
+
+ SetPaused(opts *bind.TransactOpts, pause bool) (*types.Transaction, error)
+
+ StartPingPong(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PingPongDemoOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *PingPongDemoOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*PingPongDemoOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PingPongDemoOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *PingPongDemoOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*PingPongDemoOwnershipTransferred, error)
+
+ FilterPing(opts *bind.FilterOpts) (*PingPongDemoPingIterator, error)
+
+ WatchPing(opts *bind.WatchOpts, sink chan<- *PingPongDemoPing) (event.Subscription, error)
+
+ ParsePing(log types.Log) (*PingPongDemoPing, error)
+
+ FilterPong(opts *bind.FilterOpts) (*PingPongDemoPongIterator, error)
+
+ WatchPong(opts *bind.WatchOpts, sink chan<- *PingPongDemoPong) (event.Subscription, error)
+
+ ParsePong(log types.Log) (*PingPongDemoPong, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/price_registry/price_registry.go b/core/gethwrappers/ccip/generated/price_registry/price_registry.go
new file mode 100644
index 00000000000..19f1bd4a190
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/price_registry/price_registry.go
@@ -0,0 +1,3141 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package price_registry
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type AuthorizedCallersAuthorizedCallerArgs struct {
+ AddedCallers []common.Address
+ RemovedCallers []common.Address
+}
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type IPriceRegistryTokenPriceFeedConfig struct {
+ DataFeedAddress common.Address
+ TokenDecimals uint8
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalRampTokenAmount struct {
+ SourcePoolAddress []byte
+ DestTokenAddress []byte
+ ExtraData []byte
+ Amount *big.Int
+}
+
+type InternalTimestampedPackedUint224 struct {
+ Value *big.Int
+ Timestamp uint32
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+type PriceRegistryDestChainConfig struct {
+ IsEnabled bool
+ MaxNumberOfTokensPerMsg uint16
+ MaxDataBytes uint32
+ MaxPerMsgGasLimit uint32
+ DestGasOverhead uint32
+ DestGasPerPayloadByte uint16
+ DestDataAvailabilityOverheadGas uint32
+ DestGasPerDataAvailabilityByte uint16
+ DestDataAvailabilityMultiplierBps uint16
+ DefaultTokenFeeUSDCents uint16
+ DefaultTokenDestGasOverhead uint32
+ DefaultTokenDestBytesOverhead uint32
+ DefaultTxGasLimit uint32
+ GasMultiplierWeiPerEth uint64
+ NetworkFeeUSDCents uint32
+ EnforceOutOfOrder bool
+ ChainFamilySelector [4]byte
+}
+
+type PriceRegistryDestChainConfigArgs struct {
+ DestChainSelector uint64
+ DestChainConfig PriceRegistryDestChainConfig
+}
+
+type PriceRegistryPremiumMultiplierWeiPerEthArgs struct {
+ Token common.Address
+ PremiumMultiplierWeiPerEth uint64
+}
+
+type PriceRegistryStaticConfig struct {
+ MaxFeeJuelsPerMsg *big.Int
+ LinkToken common.Address
+ StalenessThreshold uint32
+}
+
+type PriceRegistryTokenPriceFeedUpdate struct {
+ SourceToken common.Address
+ FeedConfig IPriceRegistryTokenPriceFeedConfig
+}
+
+type PriceRegistryTokenTransferFeeConfig struct {
+ MinFeeUSDCents uint32
+ MaxFeeUSDCents uint32
+ DeciBps uint16
+ DestGasOverhead uint32
+ DestBytesOverhead uint32
+ IsEnabled bool
+}
+
+type PriceRegistryTokenTransferFeeConfigArgs struct {
+ DestChainSelector uint64
+ TokenTransferFeeConfigs []PriceRegistryTokenTransferFeeConfigSingleTokenArgs
+}
+
+type PriceRegistryTokenTransferFeeConfigRemoveArgs struct {
+ DestChainSelector uint64
+ Token common.Address
+}
+
+type PriceRegistryTokenTransferFeeConfigSingleTokenArgs struct {
+ Token common.Address
+ TokenTransferFeeConfig PriceRegistryTokenTransferFeeConfig
+}
+
+var PriceRegistryMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"maxFeeJuelsPerMsg\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"stalenessThreshold\",\"type\":\"uint32\"}],\"internalType\":\"structPriceRegistry.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"priceUpdaters\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"feeTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"dataFeedAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"tokenDecimals\",\"type\":\"uint8\"}],\"internalType\":\"structIPriceRegistry.TokenPriceFeedConfig\",\"name\":\"feedConfig\",\"type\":\"tuple\"}],\"internalType\":\"structPriceRegistry.TokenPriceFeedUpdate[]\",\"name\":\"tokenPriceFeeds\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structPriceRegistry.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"internalType\":\"structPriceRegistry.TokenTransferFeeConfigSingleTokenArgs[]\",\"name\":\"tokenTransferFeeConfigs\",\"type\":\"tuple[]\"}],\"internalType\":\"structPriceRegistry.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"}],\"internalType\":\"structPriceRegistry.PremiumMultiplierWeiPerEthArgs[]\",\"name\":\"premiumMultiplierWeiPerEthArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"internalType\":\"structPriceRegistry.DestChainConfig\",\"name\":\"destChainConfig\",\"type\":\"tuple\"}],\"internalType\":\"structPriceRegistry.DestChainConfigArgs[]\",\"name\":\"destChainConfigArgs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chain\",\"type\":\"uint64\"}],\"name\":\"ChainNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DataFeedValueOutOfUint224Range\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"DestinationChainNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExtraArgOutOfOrderExecutionMustBeTrue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"}],\"name\":\"InvalidDestBytesOverhead\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidDestChainConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidEVMAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidStaticConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"msgFeeJuels\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeeJuelsPerMsg\",\"type\":\"uint256\"}],\"name\":\"MessageFeeTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MessageGasLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SourceTokenDataTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePassed\",\"type\":\"uint256\"}],\"name\":\"StaleGasPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenNotSupported\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"UnauthorizedCaller\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AuthorizedCallerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AuthorizedCallerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"indexed\":false,\"internalType\":\"structPriceRegistry.DestChainConfig\",\"name\":\"destChainConfig\",\"type\":\"tuple\"}],\"name\":\"DestChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"indexed\":false,\"internalType\":\"structPriceRegistry.DestChainConfig\",\"name\":\"destChainConfig\",\"type\":\"tuple\"}],\"name\":\"DestChainConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"FeeTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"FeeTokenRemoved\",\"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\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"}],\"name\":\"PremiumMultiplierWeiPerEthUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"dataFeedAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"tokenDecimals\",\"type\":\"uint8\"}],\"indexed\":false,\"internalType\":\"structIPriceRegistry.TokenPriceFeedConfig\",\"name\":\"priceFeedConfig\",\"type\":\"tuple\"}],\"name\":\"PriceFeedPerTokenUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"priceUpdater\",\"type\":\"address\"}],\"name\":\"PriceUpdaterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"priceUpdater\",\"type\":\"address\"}],\"name\":\"PriceUpdaterSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenTransferFeeConfigDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structPriceRegistry.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"name\":\"TokenTransferFeeConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UsdPerTokenUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChain\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UsdPerUnitGasUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address[]\",\"name\":\"addedCallers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"removedCallers\",\"type\":\"address[]\"}],\"internalType\":\"structAuthorizedCallers.AuthorizedCallerArgs\",\"name\":\"authorizedCallerArgs\",\"type\":\"tuple\"}],\"name\":\"applyAuthorizedCallerUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"internalType\":\"structPriceRegistry.DestChainConfig\",\"name\":\"destChainConfig\",\"type\":\"tuple\"}],\"internalType\":\"structPriceRegistry.DestChainConfigArgs[]\",\"name\":\"destChainConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"applyDestChainConfigUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"feeTokensToAdd\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"feeTokensToRemove\",\"type\":\"address[]\"}],\"name\":\"applyFeeTokensUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"}],\"internalType\":\"structPriceRegistry.PremiumMultiplierWeiPerEthArgs[]\",\"name\":\"premiumMultiplierWeiPerEthArgs\",\"type\":\"tuple[]\"}],\"name\":\"applyPremiumMultiplierWeiPerEthUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structPriceRegistry.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"internalType\":\"structPriceRegistry.TokenTransferFeeConfigSingleTokenArgs[]\",\"name\":\"tokenTransferFeeConfigs\",\"type\":\"tuple[]\"}],\"internalType\":\"structPriceRegistry.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"internalType\":\"structPriceRegistry.TokenTransferFeeConfigRemoveArgs[]\",\"name\":\"tokensToUseDefaultFeeConfigs\",\"type\":\"tuple[]\"}],\"name\":\"applyTokenTransferFeeConfigUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"fromToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fromTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"toToken\",\"type\":\"address\"}],\"name\":\"convertTokenAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAuthorizedCallers\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getDestChainConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"internalType\":\"structPriceRegistry.DestChainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getDestinationChainGasPrice\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getPremiumMultiplierWeiPerEth\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"maxFeeJuelsPerMsg\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"stalenessThreshold\",\"type\":\"uint32\"}],\"internalType\":\"structPriceRegistry.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getTokenAndGasPrices\",\"outputs\":[{\"internalType\":\"uint224\",\"name\":\"tokenPrice\",\"type\":\"uint224\"},{\"internalType\":\"uint224\",\"name\":\"gasPriceValue\",\"type\":\"uint224\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenPrice\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenPriceFeedConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"dataFeedAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"tokenDecimals\",\"type\":\"uint8\"}],\"internalType\":\"structIPriceRegistry.TokenPriceFeedConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getTokenPrices\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenTransferFeeConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structPriceRegistry.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getValidatedFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getValidatedTokenPrice\",\"outputs\":[{\"internalType\":\"uint224\",\"name\":\"\",\"type\":\"uint224\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"name\":\"processMessageArgs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"msgFeeJuels\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isOutOfOrderExecution\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"convertedExtraArgs\",\"type\":\"bytes\"}],\"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\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"}],\"name\":\"updatePrices\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"dataFeedAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"tokenDecimals\",\"type\":\"uint8\"}],\"internalType\":\"structIPriceRegistry.TokenPriceFeedConfig\",\"name\":\"feedConfig\",\"type\":\"tuple\"}],\"internalType\":\"structPriceRegistry.TokenPriceFeedUpdate[]\",\"name\":\"tokenPriceFeedUpdates\",\"type\":\"tuple[]\"}],\"name\":\"updateTokenPriceFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"rampTokenAmounts\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"sourceTokenAmounts\",\"type\":\"tuple[]\"}],\"name\":\"validatePoolReturnData\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x60e06040523480156200001157600080fd5b50604051620069373803806200693783398101604081905262000034916200180a565b8533806000816200008c5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000bf57620000bf8162000207565b5050604080518082018252838152815160008152602080820190935291810191909152620000ee9150620002b2565b5060208701516001600160a01b0316158062000112575086516001600160601b0316155b80620001265750604087015163ffffffff16155b15620001455760405163d794ef9560e01b815260040160405180910390fd5b6020878101516001600160a01b031660a05287516001600160601b031660805260408089015163ffffffff1660c05280516000815291820190526200018c90869062000401565b620001978462000549565b620001a2816200061a565b620001ad8262000a99565b60408051600080825260208201909252620001fa91859190620001f3565b6040805180820190915260008082526020820152815260200190600190039081620001cb5790505b5062000b65565b5050505050505062001ac8565b336001600160a01b03821603620002615760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000083565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b602081015160005b815181101562000342576000828281518110620002db57620002db62001929565b60209081029190910101519050620002f560028262000e98565b1562000338576040516001600160a01b03821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b50600101620002ba565b50815160005b8151811015620003fb57600082828151811062000369576200036962001929565b6020026020010151905060006001600160a01b0316816001600160a01b031603620003a7576040516342bcdf7f60e11b815260040160405180910390fd5b620003b460028262000eb8565b506040516001600160a01b03821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a15060010162000348565b50505050565b60005b8251811015620004a2576200044083828151811062000427576200042762001929565b6020026020010151600c62000eb860201b90919060201c565b1562000499578281815181106200045b576200045b62001929565b60200260200101516001600160a01b03167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b60010162000404565b5060005b81518110156200054457620004e2828281518110620004c957620004c962001929565b6020026020010151600c62000e9860201b90919060201c565b156200053b57818181518110620004fd57620004fd62001929565b60200260200101516001600160a01b03167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b600101620004a6565b505050565b60005b8151811015620006165760008282815181106200056d576200056d62001929565b6020908102919091018101518051818301516001600160a01b0380831660008181526006875260409081902084518154868a018051929096166001600160a81b03199091168117600160a01b60ff9384160217909255825191825293519093169683019690965293955091939092917f08a5f7f5bb38a81d8e43aca13ecd76431dbf8816ae4699affff7b00b2fc1c464910160405180910390a25050508060010190506200054c565b5050565b60005b8151811015620006165760008282815181106200063e576200063e62001929565b6020026020010151905060008383815181106200065f576200065f62001929565b6020026020010151600001519050600082602001519050816001600160401b03166000148062000698575061018081015163ffffffff16155b80620006ba57506102008101516001600160e01b031916630a04b54b60e21b14155b80620006d15750602081610160015163ffffffff16105b80620006f15750806060015163ffffffff1681610180015163ffffffff16115b156200071c5760405163c35aa79d60e01b81526001600160401b038316600482015260240162000083565b6001600160401b038216600090815260086020526040812060010154600160a81b900460e01b6001600160e01b03191690036200079c57816001600160401b03167fa937382a486d993de71c220bc8b559242deb4e286a353fa732330b4aa7d13577826040516200078e91906200193f565b60405180910390a2620007e0565b816001600160401b03167fa7b607fc10d28a1caf39ab7d27f4c94945db708a576d572781a455c5894fad9382604051620007d791906200193f565b60405180910390a25b8060086000846001600160401b03166001600160401b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548161ffff021916908361ffff16021790555060408201518160000160036101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160076101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600b6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600f6101000a81548161ffff021916908361ffff16021790555060c08201518160000160116101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160156101000a81548161ffff021916908361ffff1602179055506101008201518160000160176101000a81548161ffff021916908361ffff1602179055506101208201518160000160196101000a81548161ffff021916908361ffff16021790555061014082015181600001601b6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160010160046101000a81548163ffffffff021916908363ffffffff1602179055506101a08201518160010160086101000a8154816001600160401b0302191690836001600160401b031602179055506101c08201518160010160106101000a81548163ffffffff021916908363ffffffff1602179055506101e08201518160010160146101000a81548160ff0219169083151502179055506102008201518160010160156101000a81548163ffffffff021916908360e01c02179055509050505050508060010190506200061d565b60005b81518110156200061657600082828151811062000abd5762000abd62001929565b6020026020010151600001519050600083838151811062000ae25762000ae262001929565b6020908102919091018101518101516001600160a01b03841660008181526007845260409081902080546001600160401b0319166001600160401b0385169081179091559051908152919350917fbb77da6f7210cdd16904228a9360133d1d7dfff99b1bc75f128da5b53e28f97d910160405180910390a2505060010162000a9c565b60005b825181101562000dd257600083828151811062000b895762000b8962001929565b6020026020010151905060008160000151905060005b82602001515181101562000dc35760008360200151828151811062000bc85762000bc862001929565b602002602001015160200151905060008460200151838151811062000bf15762000bf162001929565b60200260200101516000015190506020826080015163ffffffff16101562000c4a5760808201516040516312766e0160e11b81526001600160a01b038316600482015263ffffffff909116602482015260440162000083565b6001600160401b03841660008181526009602090815260408083206001600160a01b0386168085529083529281902086518154938801518389015160608a015160808b015160a08c01511515600160901b0260ff60901b1963ffffffff928316600160701b021664ffffffffff60701b199383166a01000000000000000000000263ffffffff60501b1961ffff90961668010000000000000000029590951665ffffffffffff60401b19968416640100000000026001600160401b0319909b16939097169290921798909817939093169390931717919091161792909217909155519091907f94967ae9ea7729ad4f54021c1981765d2b1d954f7c92fbec340aa0a54f46b8b59062000db0908690600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60405180910390a3505060010162000b9f565b50505080600101905062000b68565b5060005b81518110156200054457600082828151811062000df75762000df762001929565b6020026020010151600001519050600083838151811062000e1c5762000e1c62001929565b6020908102919091018101518101516001600160401b03841660008181526009845260408082206001600160a01b038516808452955280822080546001600160981b03191690555192945090917f4de5b1bcbca6018c11303a2c3f4a4b4f22a1c741d8c4ba430d246ac06c5ddf8b9190a3505060010162000dd6565b600062000eaf836001600160a01b03841662000ecf565b90505b92915050565b600062000eaf836001600160a01b03841662000fd3565b6000818152600183016020526040812054801562000fc857600062000ef660018362001a90565b855490915060009062000f0c9060019062001a90565b905081811462000f7857600086600001828154811062000f305762000f3062001929565b906000526020600020015490508087600001848154811062000f565762000f5662001929565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000f8c5762000f8c62001ab2565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000eb2565b600091505062000eb2565b60008181526001830160205260408120546200101c5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000eb2565b50600062000eb2565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171562001060576200106062001025565b60405290565b60405160c081016001600160401b038111828210171562001060576200106062001025565b60405161022081016001600160401b038111828210171562001060576200106062001025565b604051601f8201601f191681016001600160401b0381118282101715620010dc57620010dc62001025565b604052919050565b80516001600160a01b0381168114620010fc57600080fd5b919050565b805163ffffffff81168114620010fc57600080fd5b6000606082840312156200112957600080fd5b604051606081016001600160401b03811182821017156200114e576200114e62001025565b604052825190915081906001600160601b03811681146200116e57600080fd5b81526200117e60208401620010e4565b6020820152620011916040840162001101565b60408201525092915050565b60006001600160401b03821115620011b957620011b962001025565b5060051b60200190565b600082601f830112620011d557600080fd5b81516020620011ee620011e8836200119d565b620010b1565b8083825260208201915060208460051b8701019350868411156200121157600080fd5b602086015b8481101562001238576200122a81620010e4565b835291830191830162001216565b509695505050505050565b600082601f8301126200125557600080fd5b8151602062001268620011e8836200119d565b828152606092830285018201928282019190878511156200128857600080fd5b8387015b858110156200131b5780890382811215620012a75760008081fd5b620012b16200103b565b620012bc83620010e4565b8152604080601f1984011215620012d35760008081fd5b620012dd6200103b565b9250620012ec888501620010e4565b835283015160ff81168114620013025760008081fd5b828801528087019190915284529284019281016200128c565b5090979650505050505050565b80516001600160401b0381168114620010fc57600080fd5b805161ffff81168114620010fc57600080fd5b80518015158114620010fc57600080fd5b600082601f8301126200137657600080fd5b8151602062001389620011e8836200119d565b82815260059290921b84018101918181019086841115620013a957600080fd5b8286015b84811015620012385780516001600160401b0380821115620013ce57600080fd5b908801906040601f19838c038101821315620013e957600080fd5b620013f36200103b565b6200140089860162001328565b815282850151848111156200141457600080fd5b8086019550508c603f8601126200142a57600080fd5b8885015193506200143f620011e8856200119d565b84815260e09094028501830193898101908e8611156200145e57600080fd5b958401955b858710156200153757868f0360e08112156200147e57600080fd5b620014886200103b565b6200149389620010e4565b815260c08683011215620014a657600080fd5b620014b062001066565b9150620014bf8d8a0162001101565b8252620014ce878a0162001101565b8d830152620014e060608a0162001340565b87830152620014f260808a0162001101565b60608301526200150560a08a0162001101565b60808301526200151860c08a0162001353565b60a0830152808d0191909152825260e09690960195908a019062001463565b828b015250875250505092840192508301620013ad565b600082601f8301126200156057600080fd5b8151602062001573620011e8836200119d565b82815260069290921b840181019181810190868411156200159357600080fd5b8286015b84811015620012385760408189031215620015b25760008081fd5b620015bc6200103b565b620015c782620010e4565b8152620015d685830162001328565b8186015283529183019160400162001597565b80516001600160e01b031981168114620010fc57600080fd5b600082601f8301126200161457600080fd5b8151602062001627620011e8836200119d565b82815261024092830285018201928282019190878511156200164857600080fd5b8387015b858110156200131b5780890382811215620016675760008081fd5b620016716200103b565b6200167c8362001328565b815261022080601f1984011215620016945760008081fd5b6200169e6200108b565b9250620016ad88850162001353565b83526040620016be81860162001340565b898501526060620016d181870162001101565b8286015260809150620016e682870162001101565b9085015260a0620016f986820162001101565b8286015260c091506200170e82870162001340565b9085015260e06200172186820162001101565b8286015261010091506200173782870162001340565b908501526101206200174b86820162001340565b8286015261014091506200176182870162001340565b908501526101606200177586820162001101565b8286015261018091506200178b82870162001101565b908501526101a06200179f86820162001101565b828601526101c09150620017b582870162001328565b908501526101e0620017c986820162001101565b828601526102009150620017df82870162001353565b90850152620017f0858301620015e9565b90840152508087019190915284529284019281016200164c565b6000806000806000806000610120888a0312156200182757600080fd5b62001833898962001116565b60608901519097506001600160401b03808211156200185157600080fd5b6200185f8b838c01620011c3565b975060808a01519150808211156200187657600080fd5b620018848b838c01620011c3565b965060a08a01519150808211156200189b57600080fd5b620018a98b838c0162001243565b955060c08a0151915080821115620018c057600080fd5b620018ce8b838c0162001364565b945060e08a0151915080821115620018e557600080fd5b620018f38b838c016200154e565b93506101008a01519150808211156200190b57600080fd5b506200191a8a828b0162001602565b91505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b8151151581526102208101602083015162001960602084018261ffff169052565b50604083015162001979604084018263ffffffff169052565b50606083015162001992606084018263ffffffff169052565b506080830151620019ab608084018263ffffffff169052565b5060a0830151620019c260a084018261ffff169052565b5060c0830151620019db60c084018263ffffffff169052565b5060e0830151620019f260e084018261ffff169052565b506101008381015161ffff9081169184019190915261012080850151909116908301526101408084015163ffffffff9081169184019190915261016080850151821690840152610180808501518216908401526101a0808501516001600160401b0316908401526101c080850151909116908301526101e080840151151590830152610200928301516001600160e01b031916929091019190915290565b8181038181111562000eb257634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c051614e1562001b22600039600081816102d901528181611ad30152611b3c01526000818161029d0152818161104e01526110ae015260008181610269015281816110d701526111470152614e156000f3fe608060405234801561001057600080fd5b50600436106101b85760003560e01c80637afac322116100f9578063cc88924c11610097578063d8694ccd11610071578063d8694ccd14610a5c578063f2fde38b14610a6f578063f700042a14610a82578063ffdb4b3714610a9557600080fd5b8063cc88924c14610a2e578063cdc73d5114610a41578063d02641a014610a4957600080fd5b806391a2749a116100d357806391a2749a14610939578063a69c64c01461094c578063bf78e03f1461095f578063c4276bfc14610a0c57600080fd5b80637afac3221461078e57806382b49eb0146107a15780638da5cb5b1461091157600080fd5b8063407e108611610166578063514e8cff11610140578063514e8cff146104385780636def4ce7146104db578063770e2dc41461077357806379ba50971461078657600080fd5b8063407e1086146103c557806345ac924d146103d85780634ab35b0b146103f857600080fd5b8063181f5a7711610197578063181f5a77146103525780632451a6271461039b5780633937306f146103b057600080fd5b806241e5be146101bd578063061877e3146101e357806306285c691461023c575b600080fd5b6101d06101cb366004613802565b610add565b6040519081526020015b60405180910390f35b6102236101f136600461383e565b73ffffffffffffffffffffffffffffffffffffffff1660009081526007602052604090205467ffffffffffffffff1690565b60405167ffffffffffffffff90911681526020016101da565b610306604080516060810182526000808252602082018190529181019190915260405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000063ffffffff16815250905090565b6040805182516bffffffffffffffffffffffff16815260208084015173ffffffffffffffffffffffffffffffffffffffff16908201529181015163ffffffff16908201526060016101da565b61038e6040518060400160405280601781526020017f5072696365526567697374727920312e362e302d64657600000000000000000081525081565b6040516101da91906138bd565b6103a3610b4b565b6040516101da91906138d0565b6103c36103be36600461392a565b610b5c565b005b6103c36103d3366004613a86565b610e11565b6103eb6103e6366004613be4565b610e25565b6040516101da9190613c26565b61040b61040636600461383e565b610ef0565b6040517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911681526020016101da565b6104ce610446366004613cb9565b60408051808201909152600080825260208201525067ffffffffffffffff166000908152600460209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811683527c0100000000000000000000000000000000000000000000000000000000900463ffffffff169082015290565b6040516101da9190613cd4565b6107666104e9366004613cb9565b6040805161022081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e081018290526102008101919091525067ffffffffffffffff908116600090815260086020908152604091829020825161022081018452815460ff8082161515835261ffff61010080840482169685019690965263ffffffff630100000084048116978501979097526701000000000000008304871660608501526b0100000000000000000000008304871660808501526f010000000000000000000000000000008304811660a0850152710100000000000000000000000000000000008304871660c08501527501000000000000000000000000000000000000000000808404821660e08087019190915277010000000000000000000000000000000000000000000000850483169786019790975279010000000000000000000000000000000000000000000000000084049091166101208501527b010000000000000000000000000000000000000000000000000000009092048616610140840152600190930154808616610160840152640100000000810486166101808401526801000000000000000081049096166101a083015270010000000000000000000000000000000086049094166101c082015274010000000000000000000000000000000000000000850490911615156101e08201527fffffffff0000000000000000000000000000000000000000000000000000000092909304901b1661020082015290565b6040516101da9190613d0f565b6103c3610781366004613f4c565b610efb565b6103c3610f11565b6103c361079c366004614266565b611013565b6108b16107af3660046142ca565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091525067ffffffffffffffff91909116600090815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff94909416835292815290829020825160c081018452905463ffffffff8082168352640100000000820481169383019390935268010000000000000000810461ffff16938201939093526a01000000000000000000008304821660608201526e01000000000000000000000000000083049091166080820152720100000000000000000000000000000000000090910460ff16151560a082015290565b6040516101da9190600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101da565b6103c36109473660046142f4565b611025565b6103c361095a366004614385565b611036565b6109d861096d36600461383e565b6040805180820182526000808252602091820181905273ffffffffffffffffffffffffffffffffffffffff93841681526006825282902082518084019093525492831682527401000000000000000000000000000000000000000090920460ff169181019190915290565b60408051825173ffffffffffffffffffffffffffffffffffffffff16815260209283015160ff1692810192909252016101da565b610a1f610a1a36600461444a565b611047565b6040516101da939291906144e5565b6103c3610a3c36600461450f565b611245565b6103a361141b565b6104ce610a5736600461383e565b611427565b6101d0610a6a3660046145aa565b611523565b6103c3610a7d36600461383e565b6119dd565b6103c3610a9036600461462f565b6119ee565b610aa8610aa336600461484f565b6119ff565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9384168152929091166020830152016101da565b6000610ae882611b8a565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16610b0f85611b8a565b610b37907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16856148a8565b610b4191906148bf565b90505b9392505050565b6060610b576002611c24565b905090565b610b64611c31565b6000610b7082806148fa565b9050905060005b81811015610cba576000610b8b84806148fa565b83818110610b9b57610b9b614962565b905060400201803603810190610bb191906149bd565b604080518082018252602080840180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff908116845263ffffffff42818116858701908152885173ffffffffffffffffffffffffffffffffffffffff9081166000908152600590975295889020965190519092167c010000000000000000000000000000000000000000000000000000000002919092161790935584519051935194955016927f52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a92610ca99290917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a250600101610b77565b506000610cca60208401846148fa565b9050905060005b81811015610e0b576000610ce860208601866148fa565b83818110610cf857610cf8614962565b905060400201803603810190610d0e91906149fa565b604080518082018252602080840180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff908116845263ffffffff42818116858701908152885167ffffffffffffffff9081166000908152600490975295889020965190519092167c010000000000000000000000000000000000000000000000000000000002919092161790935584519051935194955016927fdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e92610dfa9290917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a250600101610cd1565b50505050565b610e19611c76565b610e2281611cf7565b50565b60608160008167ffffffffffffffff811115610e4357610e43613965565b604051908082528060200260200182016040528015610e8857816020015b6040805180820190915260008082526020820152815260200190600190039081610e615790505b50905060005b82811015610ee557610ec0868683818110610eab57610eab614962565b9050602002016020810190610a57919061383e565b828281518110610ed257610ed2614962565b6020908102919091010152600101610e8e565b509150505b92915050565b6000610eea82611b8a565b610f03611c76565b610f0d8282611df5565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61101b611c76565b610f0d8282612201565b61102d611c76565b610e2281612348565b61103e611c76565b610e22816124d4565b60008060607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16036110a7578592506110d5565b6110d287877f0000000000000000000000000000000000000000000000000000000000000000610add565b92505b7f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff16831115611174576040517f6a92a483000000000000000000000000000000000000000000000000000000008152600481018490526bffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166024820152604401610f8e565b67ffffffffffffffff8816600090815260086020526040812060010154640100000000900463ffffffff16906111ab8787846125be565b9050806020015193508484611232836040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f181dcf100000000000000000000000000000000000000000000000000000000017905290565b9450945094505050955095509592505050565b67ffffffffffffffff85166000908152600860205260408120600101547501000000000000000000000000000000000000000000900460e01b905b8481101561141257600084848381811061129c5761129c614962565b6112b2926020604090920201908101915061383e565b905060008787848181106112c8576112c8614962565b90506020028101906112da9190614a1d565b6112e8906040810190614a5b565b91505060208111156113985767ffffffffffffffff8916600090815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091529020546e010000000000000000000000000000900463ffffffff16811115611398576040517f36f536ca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610f8e565b611408848989868181106113ae576113ae614962565b90506020028101906113c09190614a1d565b6113ce906020810190614a5b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061276792505050565b5050600101611280565b50505050505050565b6060610b57600c611c24565b604080518082019091526000808252602082015273ffffffffffffffffffffffffffffffffffffffff8281166000908152600660209081526040918290208251808401909352549283168083527401000000000000000000000000000000000000000090930460ff16908201529061151a57505073ffffffffffffffffffffffffffffffffffffffff166000908152600560209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811683527c0100000000000000000000000000000000000000000000000000000000900463ffffffff169082015290565b610b44816127b9565b67ffffffffffffffff8083166000908152600860209081526040808320815161022081018352815460ff808216151580845261ffff61010080850482169886019890985263ffffffff630100000085048116978601979097526701000000000000008404871660608601526b0100000000000000000000008404871660808601526f010000000000000000000000000000008404811660a0860152710100000000000000000000000000000000008404871660c08601527501000000000000000000000000000000000000000000808504821660e08088019190915277010000000000000000000000000000000000000000000000860483169987019990995279010000000000000000000000000000000000000000000000000085049091166101208601527b010000000000000000000000000000000000000000000000000000009093048616610140850152600190940154808616610160850152640100000000810486166101808501526801000000000000000081049098166101a084015270010000000000000000000000000000000088049094166101c083015274010000000000000000000000000000000000000000870490931615156101e08201527fffffffff000000000000000000000000000000000000000000000000000000009290950490921b16610200840152909190611759576040517f99ac52f200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff85166004820152602401610f8e565b600061176860408501856148fa565b91506117c490508261177d6020870187614a5b565b90508361178a8880614a5b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506129fc92505050565b60006007816117d9608088016060890161383e565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160009081205467ffffffffffffffff169150806118286118226080890160608a0161383e565b896119ff565b909250905060008080861561186e57611862888c61184c60808e0160608f0161383e565b888e806040019061185d91906148fa565b612aa6565b9194509250905061188e565b6101c088015161188b9063ffffffff16662386f26fc100006148a8565b92505b61010088015160009061ffff16156118d2576118cf896dffffffffffffffffffffffffffff607088901c166118c660208f018f614a5b565b90508b86612d84565b90505b6101a089015160009067ffffffffffffffff166118fb6118f560808f018f614a5b565b8d612e33565b600001518563ffffffff168c60a0015161ffff168f806020019061191f9190614a5b565b61192a9291506148a8565b8d6080015163ffffffff1661193f9190614ac0565b6119499190614ac0565b6119539190614ac0565b61196d906dffffffffffffffffffffffffffff89166148a8565b61197791906148a8565b90507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff871682826119ae67ffffffffffffffff8c16896148a8565b6119b89190614ac0565b6119c29190614ac0565b6119cc91906148bf565b9d9c50505050505050505050505050565b6119e5611c76565b610e2281612ef4565b6119f6611c76565b610e2281612fe9565b67ffffffffffffffff811660009081526004602090815260408083208151808301909252547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811682527c0100000000000000000000000000000000000000000000000000000000900463ffffffff1691810182905282918203611ab7576040517f2e59db3a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff85166004820152602401610f8e565b6000816020015163ffffffff1642611acf9190614ad3565b90507f000000000000000000000000000000000000000000000000000000000000000063ffffffff16811115611b70576040517ff08bcb3e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8616600482015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260448101829052606401610f8e565b611b7986611b8a565b9151919350909150505b9250929050565b600080611b9683611427565b9050806020015163ffffffff1660001480611bce575080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16155b15611c1d576040517f06439c6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610f8e565b5192915050565b60606000610b44836134d1565b611c3c60023361352d565b611c74576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401610f8e565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314611c74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610f8e565b60005b8151811015610f0d576000828281518110611d1757611d17614962565b60209081029190910181015180518183015173ffffffffffffffffffffffffffffffffffffffff80831660008181526006875260409081902084518154868a018051929096167fffffffffffffffffffffff00000000000000000000000000000000000000000090911681177401000000000000000000000000000000000000000060ff9384160217909255825191825293519093169683019690965293955091939092917f08a5f7f5bb38a81d8e43aca13ecd76431dbf8816ae4699affff7b00b2fc1c464910160405180910390a2505050806001019050611cfa565b60005b8251811015612118576000838281518110611e1557611e15614962565b6020026020010151905060008160000151905060005b82602001515181101561210a57600083602001518281518110611e5057611e50614962565b6020026020010151602001519050600084602001518381518110611e7657611e76614962565b60200260200101516000015190506020826080015163ffffffff161015611ef35760808201516040517f24ecdc0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015263ffffffff9091166024820152604401610f8e565b67ffffffffffffffff8416600081815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168085529083529281902086518154938801518389015160608a015160808b015160a08c015115157201000000000000000000000000000000000000027fffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff63ffffffff9283166e01000000000000000000000000000002167fffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffff9383166a0100000000000000000000027fffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffff61ffff9096166801000000000000000002959095167fffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffff968416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b16939097169290921798909817939093169390931717919091161792909217909155519091907f94967ae9ea7729ad4f54021c1981765d2b1d954f7c92fbec340aa0a54f46b8b5906120f8908690600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60405180910390a35050600101611e2b565b505050806001019050611df8565b5060005b81518110156121fc57600082828151811061213957612139614962565b6020026020010151600001519050600083838151811061215b5761215b614962565b60209081029190910181015181015167ffffffffffffffff8416600081815260098452604080822073ffffffffffffffffffffffffffffffffffffffff8516808452955280822080547fffffffffffffffffffffffffff000000000000000000000000000000000000001690555192945090917f4de5b1bcbca6018c11303a2c3f4a4b4f22a1c741d8c4ba430d246ac06c5ddf8b9190a3505060010161211c565b505050565b60005b82518110156122a45761223a83828151811061222257612222614962565b6020026020010151600c61355c90919063ffffffff16565b1561229c5782818151811061225157612251614962565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b600101612204565b5060005b81518110156121fc576122de8282815181106122c6576122c6614962565b6020026020010151600c61357e90919063ffffffff16565b15612340578181815181106122f5576122f5614962565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b6001016122a8565b602081015160005b81518110156123e357600082828151811061236d5761236d614962565b6020026020010151905061238b81600261357e90919063ffffffff16565b156123da5760405173ffffffffffffffffffffffffffffffffffffffff821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b50600101612350565b50815160005b8151811015610e0b57600082828151811061240657612406614962565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612476576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61248160028261355c565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a1506001016123e9565b60005b8151811015610f0d5760008282815181106124f4576124f4614962565b6020026020010151600001519050600083838151811061251657612516614962565b60209081029190910181015181015173ffffffffffffffffffffffffffffffffffffffff841660008181526007845260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff85169081179091559051908152919350917fbb77da6f7210cdd16904228a9360133d1d7dfff99b1bc75f128da5b53e28f97d910160405180910390a250506001016124d7565b604080518082019091526000808252602082015260008390036125ff57506040805180820190915267ffffffffffffffff8216815260006020820152610b44565b600061260b8486614ae6565b9050600061261c8560048189614b2c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050507fffffffff0000000000000000000000000000000000000000000000000000000082167fe7e230f000000000000000000000000000000000000000000000000000000000016126b957808060200190518101906126b09190614b56565b92505050610b44565b7f6859a837000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601612735576040518060400160405280828060200190518101906127219190614b82565b815260006020909101529250610b44915050565b6040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fd7ed2ad4000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601610f0d576121fc816135a0565b604080518082019091526000808252602082015260008260000151905060008173ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612823573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128479190614bb5565b5050509150506000811215612888576040517f10cb51d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000819050600085602001518473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129039190614c05565b61290d9190614c22565b905060248160ff16111561294257612926602482614c3b565b61293190600a614d74565b61293b90836148bf565b9150612965565b61294d816024614c3b565b61295890600a614d74565b61296290836148a8565b91505b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8211156129bb576040517f10cb51d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50604080518082019091527bffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116815263ffffffff42166020820152949350505050565b836040015163ffffffff16831115612a555760408085015190517f8693378900000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015260248101849052604401610f8e565b836020015161ffff16821115612a97576040517f4c056b6a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e0b84610200015182612767565b6000808083815b81811015612d76576000878783818110612ac957612ac9614962565b905060400201803603810190612adf9190614d83565b67ffffffffffffffff8c166000908152600960209081526040808320845173ffffffffffffffffffffffffffffffffffffffff168452825291829020825160c081018452905463ffffffff8082168352640100000000820481169383019390935268010000000000000000810461ffff16938201939093526a01000000000000000000008304821660608201526e01000000000000000000000000000083049091166080820152720100000000000000000000000000000000000090910460ff16151560a0820181905291925090612c05576101208d0151612bcc9061ffff16662386f26fc100006148a8565b612bd69088614ac0565b96508c610140015186612be99190614dbc565b95508c610160015185612bfc9190614dbc565b94505050612d6e565b604081015160009061ffff1615612cbe5760008c73ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff1614612c61578351612c5a90611b8a565b9050612c64565b508a5b620186a0836040015161ffff16612ca68660200151847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661365390919063ffffffff16565b612cb091906148a8565b612cba91906148bf565b9150505b6060820151612ccd9088614dbc565b9650816080015186612cdf9190614dbc565b8251909650600090612cfe9063ffffffff16662386f26fc100006148a8565b905080821015612d1d57612d12818a614ac0565b985050505050612d6e565b6000836020015163ffffffff16662386f26fc10000612d3c91906148a8565b905080831115612d5c57612d50818b614ac0565b99505050505050612d6e565b612d66838b614ac0565b995050505050505b600101612aad565b505096509650969350505050565b60008063ffffffff8316612d9960e0866148a8565b612da5876101c0614ac0565b612daf9190614ac0565b612db99190614ac0565b905060008760c0015163ffffffff168860e0015161ffff1683612ddc91906148a8565b612de69190614ac0565b61010089015190915061ffff16612e0d6dffffffffffffffffffffffffffff8916836148a8565b612e1791906148a8565b612e2790655af3107a40006148a8565b98975050505050505050565b60408051808201909152600080825260208201526000612e5f858585610180015163ffffffff166125be565b9050826060015163ffffffff1681600001511115612ea9576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826101e001518015612ebd57508060200151155b15610b41576040517fee433e9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821603612f73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610f8e565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b8151811015610f0d57600082828151811061300957613009614962565b60200260200101519050600083838151811061302757613027614962565b60200260200101516000015190506000826020015190508167ffffffffffffffff1660001480613060575061018081015163ffffffff16155b806130b257506102008101517fffffffff00000000000000000000000000000000000000000000000000000000167f2812d52c0000000000000000000000000000000000000000000000000000000014155b806130c85750602081610160015163ffffffff16105b806130e75750806060015163ffffffff1681610180015163ffffffff16115b1561312a576040517fc35aa79d00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff83166004820152602401610f8e565b67ffffffffffffffff82166000908152600860205260408120600101547501000000000000000000000000000000000000000000900460e01b7fffffffff000000000000000000000000000000000000000000000000000000001690036131d2578167ffffffffffffffff167fa937382a486d993de71c220bc8b559242deb4e286a353fa732330b4aa7d13577826040516131c59190613d0f565b60405180910390a2613215565b8167ffffffffffffffff167fa7b607fc10d28a1caf39ab7d27f4c94945db708a576d572781a455c5894fad938260405161320c9190613d0f565b60405180910390a25b80600860008467ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548161ffff021916908361ffff16021790555060408201518160000160036101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160076101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600b6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600f6101000a81548161ffff021916908361ffff16021790555060c08201518160000160116101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160156101000a81548161ffff021916908361ffff1602179055506101008201518160000160176101000a81548161ffff021916908361ffff1602179055506101208201518160000160196101000a81548161ffff021916908361ffff16021790555061014082015181600001601b6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160010160046101000a81548163ffffffff021916908363ffffffff1602179055506101a08201518160010160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506101c08201518160010160106101000a81548163ffffffff021916908363ffffffff1602179055506101e08201518160010160146101000a81548160ff0219169083151502179055506102008201518160010160156101000a81548163ffffffff021916908360e01c0217905550905050505050806001019050612fec565b60608160000180548060200260200160405190810160405280929190818152602001828054801561352157602002820191906000526020600020905b81548152602001906001019080831161350d575b50505050509050919050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515610b44565b6000610b448373ffffffffffffffffffffffffffffffffffffffff8416613690565b6000610b448373ffffffffffffffffffffffffffffffffffffffff84166136df565b600081516020146135df57816040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610f8e91906138bd565b6000828060200190518101906135f59190614b82565b905073ffffffffffffffffffffffffffffffffffffffff81118061361a575061040081105b15610eea57826040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401610f8e91906138bd565b6000670de0b6b3a7640000613686837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff86166148a8565b610b4491906148bf565b60008181526001830160205260408120546136d757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610eea565b506000610eea565b600081815260018301602052604081205480156137c8576000613703600183614ad3565b855490915060009061371790600190614ad3565b905081811461377c57600086600001828154811061373757613737614962565b906000526020600020015490508087600001848154811061375a5761375a614962565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061378d5761378d614dd9565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610eea565b6000915050610eea565b5092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146137fd57600080fd5b919050565b60008060006060848603121561381757600080fd5b613820846137d9565b925060208401359150613835604085016137d9565b90509250925092565b60006020828403121561385057600080fd5b610b44826137d9565b6000815180845260005b8181101561387f57602081850181015186830182015201613863565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610b446020830184613859565b6020808252825182820181905260009190848201906040850190845b8181101561391e57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016138ec565b50909695505050505050565b60006020828403121561393c57600080fd5b813567ffffffffffffffff81111561395357600080fd5b820160408185031215610b4457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156139b7576139b7613965565b60405290565b60405160c0810167ffffffffffffffff811182821017156139b7576139b7613965565b604051610220810167ffffffffffffffff811182821017156139b7576139b7613965565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a4b57613a4b613965565b604052919050565b600067ffffffffffffffff821115613a6d57613a6d613965565b5060051b60200190565b60ff81168114610e2257600080fd5b60006020808385031215613a9957600080fd5b823567ffffffffffffffff811115613ab057600080fd5b8301601f81018513613ac157600080fd5b8035613ad4613acf82613a53565b613a04565b81815260609182028301840191848201919088841115613af357600080fd5b938501935b83851015613b935784890381811215613b115760008081fd5b613b19613994565b613b22876137d9565b81526040807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084011215613b565760008081fd5b613b5e613994565b9250613b6b8989016137d9565b8352870135613b7981613a77565b828901528088019190915283529384019391850191613af8565b50979650505050505050565b60008083601f840112613bb157600080fd5b50813567ffffffffffffffff811115613bc957600080fd5b6020830191508360208260051b8501011115611b8357600080fd5b60008060208385031215613bf757600080fd5b823567ffffffffffffffff811115613c0e57600080fd5b613c1a85828601613b9f565b90969095509350505050565b602080825282518282018190526000919060409081850190868401855b82811015613c9457613c8484835180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16825260209081015163ffffffff16910152565b9284019290850190600101613c43565b5091979650505050505050565b803567ffffffffffffffff811681146137fd57600080fd5b600060208284031215613ccb57600080fd5b610b4482613ca1565b81517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815260208083015163ffffffff169082015260408101610eea565b81511515815261022081016020830151613d2f602084018261ffff169052565b506040830151613d47604084018263ffffffff169052565b506060830151613d5f606084018263ffffffff169052565b506080830151613d77608084018263ffffffff169052565b5060a0830151613d8d60a084018261ffff169052565b5060c0830151613da560c084018263ffffffff169052565b5060e0830151613dbb60e084018261ffff169052565b506101008381015161ffff9081169184019190915261012080850151909116908301526101408084015163ffffffff9081169184019190915261016080850151821690840152610180808501518216908401526101a08085015167ffffffffffffffff16908401526101c080850151909116908301526101e080840151151590830152610200808401517fffffffff000000000000000000000000000000000000000000000000000000008116828501525b505092915050565b803563ffffffff811681146137fd57600080fd5b803561ffff811681146137fd57600080fd5b8015158114610e2257600080fd5b80356137fd81613e9b565b600082601f830112613ec557600080fd5b81356020613ed5613acf83613a53565b82815260069290921b84018101918181019086841115613ef457600080fd5b8286015b84811015613f415760408189031215613f115760008081fd5b613f19613994565b613f2282613ca1565b8152613f2f8583016137d9565b81860152835291830191604001613ef8565b509695505050505050565b60008060408385031215613f5f57600080fd5b67ffffffffffffffff83351115613f7557600080fd5b83601f843585010112613f8757600080fd5b613f97613acf8435850135613a53565b8335840180358083526020808401939260059290921b90910101861015613fbd57600080fd5b602085358601015b85358601803560051b016020018110156141ca5767ffffffffffffffff81351115613fef57600080fd5b8035863587010160407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0828a0301121561402857600080fd5b614030613994565b61403c60208301613ca1565b815267ffffffffffffffff6040830135111561405757600080fd5b88603f60408401358401011261406c57600080fd5b614082613acf6020604085013585010135613a53565b6020604084810135850182810135808552928401939260e00201018b10156140a957600080fd5b6040808501358501015b6040858101358601602081013560e00201018110156141ab5760e0818d0312156140dc57600080fd5b6140e4613994565b6140ed826137d9565b815260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838f0301121561412157600080fd5b6141296139bd565b61413560208401613e75565b815261414360408401613e75565b602082015261415460608401613e89565b604082015261416560808401613e75565b606082015261417660a08401613e75565b608082015261418860c0840135613e9b565b60c083013560a0820152602082810191909152908452929092019160e0016140b3565b5080602084015250508085525050602083019250602081019050613fc5565b5092505067ffffffffffffffff602084013511156141e757600080fd5b6141f78460208501358501613eb4565b90509250929050565b600082601f83011261421157600080fd5b81356020614221613acf83613a53565b8083825260208201915060208460051b87010193508684111561424357600080fd5b602086015b84811015613f4157614259816137d9565b8352918301918301614248565b6000806040838503121561427957600080fd5b823567ffffffffffffffff8082111561429157600080fd5b61429d86838701614200565b935060208501359150808211156142b357600080fd5b506142c085828601614200565b9150509250929050565b600080604083850312156142dd57600080fd5b6142e683613ca1565b91506141f7602084016137d9565b60006020828403121561430657600080fd5b813567ffffffffffffffff8082111561431e57600080fd5b908301906040828603121561433257600080fd5b61433a613994565b82358281111561434957600080fd5b61435587828601614200565b82525060208301358281111561436a57600080fd5b61437687828601614200565b60208301525095945050505050565b6000602080838503121561439857600080fd5b823567ffffffffffffffff8111156143af57600080fd5b8301601f810185136143c057600080fd5b80356143ce613acf82613a53565b81815260069190911b820183019083810190878311156143ed57600080fd5b928401925b8284101561443f576040848903121561440b5760008081fd5b614413613994565b61441c856137d9565b8152614429868601613ca1565b81870152825260409390930192908401906143f2565b979650505050505050565b60008060008060006080868803121561446257600080fd5b61446b86613ca1565b9450614479602087016137d9565b935060408601359250606086013567ffffffffffffffff8082111561449d57600080fd5b818801915088601f8301126144b157600080fd5b8135818111156144c057600080fd5b8960208285010111156144d257600080fd5b9699959850939650602001949392505050565b83815282151560208201526060604082015260006145066060830184613859565b95945050505050565b60008060008060006060868803121561452757600080fd5b61453086613ca1565b9450602086013567ffffffffffffffff8082111561454d57600080fd5b61455989838a01613b9f565b9096509450604088013591508082111561457257600080fd5b818801915088601f83011261458657600080fd5b81358181111561459557600080fd5b8960208260061b85010111156144d257600080fd5b600080604083850312156145bd57600080fd5b6145c683613ca1565b9150602083013567ffffffffffffffff8111156145e257600080fd5b830160a081860312156145f457600080fd5b809150509250929050565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146137fd57600080fd5b6000602080838503121561464257600080fd5b823567ffffffffffffffff81111561465957600080fd5b8301601f8101851361466a57600080fd5b8035614678613acf82613a53565b818152610240918202830184019184820191908884111561469857600080fd5b938501935b83851015613b9357848903818112156146b65760008081fd5b6146be613994565b6146c787613ca1565b8152610220807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0840112156146fc5760008081fd5b6147046139e0565b9250614711898901613ea9565b83526040614720818a01613e89565b8a8501526060614731818b01613e75565b8286015260809150614744828b01613e75565b9085015260a06147558a8201613e75565b8286015260c09150614768828b01613e89565b9085015260e06147798a8201613e75565b82860152610100915061478d828b01613e89565b9085015261012061479f8a8201613e89565b8286015261014091506147b3828b01613e89565b908501526101606147c58a8201613e75565b8286015261018091506147d9828b01613e75565b908501526101a06147eb8a8201613e75565b828601526101c091506147ff828b01613ca1565b908501526101e06148118a8201613e75565b828601526102009150614825828b01613ea9565b908501526148348983016145ff565b9084015250808801919091528352938401939185019161469d565b6000806040838503121561486257600080fd5b61486b836137d9565b91506141f760208401613ca1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610eea57610eea614879565b6000826148f5577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261492f57600080fd5b83018035915067ffffffffffffffff82111561494a57600080fd5b6020019150600681901b3603821315611b8357600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146137fd57600080fd5b6000604082840312156149cf57600080fd5b6149d7613994565b6149e0836137d9565b81526149ee60208401614991565b60208201529392505050565b600060408284031215614a0c57600080fd5b614a14613994565b6149e083613ca1565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112614a5157600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614a9057600080fd5b83018035915067ffffffffffffffff821115614aab57600080fd5b602001915036819003821315611b8357600080fd5b80820180821115610eea57610eea614879565b81810381811115610eea57610eea614879565b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015613e6d5760049490940360031b84901b1690921692915050565b60008085851115614b3c57600080fd5b83861115614b4957600080fd5b5050820193919092039150565b600060408284031215614b6857600080fd5b614b70613994565b8251815260208301516149ee81613e9b565b600060208284031215614b9457600080fd5b5051919050565b805169ffffffffffffffffffff811681146137fd57600080fd5b600080600080600060a08688031215614bcd57600080fd5b614bd686614b9b565b9450602086015193506040860151925060608601519150614bf960808701614b9b565b90509295509295909350565b600060208284031215614c1757600080fd5b8151610b4481613a77565b60ff8181168382160190811115610eea57610eea614879565b60ff8281168282160390811115610eea57610eea614879565b600181815b80851115614cad57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115614c9357614c93614879565b80851615614ca057918102915b93841c9390800290614c59565b509250929050565b600082614cc457506001610eea565b81614cd157506000610eea565b8160018114614ce75760028114614cf157614d0d565b6001915050610eea565b60ff841115614d0257614d02614879565b50506001821b610eea565b5060208310610133831016604e8410600b8410161715614d30575081810a610eea565b614d3a8383614c54565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115614d6c57614d6c614879565b029392505050565b6000610b4460ff841683614cb5565b600060408284031215614d9557600080fd5b614d9d613994565b614da6836137d9565b8152602083013560208201528091505092915050565b63ffffffff8181168382160190808211156137d2576137d2614879565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a",
+}
+
+var PriceRegistryABI = PriceRegistryMetaData.ABI
+
+var PriceRegistryBin = PriceRegistryMetaData.Bin
+
+func DeployPriceRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, staticConfig PriceRegistryStaticConfig, priceUpdaters []common.Address, feeTokens []common.Address, tokenPriceFeeds []PriceRegistryTokenPriceFeedUpdate, tokenTransferFeeConfigArgs []PriceRegistryTokenTransferFeeConfigArgs, premiumMultiplierWeiPerEthArgs []PriceRegistryPremiumMultiplierWeiPerEthArgs, destChainConfigArgs []PriceRegistryDestChainConfigArgs) (common.Address, *types.Transaction, *PriceRegistry, error) {
+ parsed, err := PriceRegistryMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(PriceRegistryBin), backend, staticConfig, priceUpdaters, feeTokens, tokenPriceFeeds, tokenTransferFeeConfigArgs, premiumMultiplierWeiPerEthArgs, destChainConfigArgs)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &PriceRegistry{address: address, abi: *parsed, PriceRegistryCaller: PriceRegistryCaller{contract: contract}, PriceRegistryTransactor: PriceRegistryTransactor{contract: contract}, PriceRegistryFilterer: PriceRegistryFilterer{contract: contract}}, nil
+}
+
+type PriceRegistry struct {
+ address common.Address
+ abi abi.ABI
+ PriceRegistryCaller
+ PriceRegistryTransactor
+ PriceRegistryFilterer
+}
+
+type PriceRegistryCaller struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistryTransactor struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistryFilterer struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistrySession struct {
+ Contract *PriceRegistry
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type PriceRegistryCallerSession struct {
+ Contract *PriceRegistryCaller
+ CallOpts bind.CallOpts
+}
+
+type PriceRegistryTransactorSession struct {
+ Contract *PriceRegistryTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type PriceRegistryRaw struct {
+ Contract *PriceRegistry
+}
+
+type PriceRegistryCallerRaw struct {
+ Contract *PriceRegistryCaller
+}
+
+type PriceRegistryTransactorRaw struct {
+ Contract *PriceRegistryTransactor
+}
+
+func NewPriceRegistry(address common.Address, backend bind.ContractBackend) (*PriceRegistry, error) {
+ abi, err := abi.JSON(strings.NewReader(PriceRegistryABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindPriceRegistry(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistry{address: address, abi: abi, PriceRegistryCaller: PriceRegistryCaller{contract: contract}, PriceRegistryTransactor: PriceRegistryTransactor{contract: contract}, PriceRegistryFilterer: PriceRegistryFilterer{contract: contract}}, nil
+}
+
+func NewPriceRegistryCaller(address common.Address, caller bind.ContractCaller) (*PriceRegistryCaller, error) {
+ contract, err := bindPriceRegistry(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryCaller{contract: contract}, nil
+}
+
+func NewPriceRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*PriceRegistryTransactor, error) {
+ contract, err := bindPriceRegistry(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryTransactor{contract: contract}, nil
+}
+
+func NewPriceRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*PriceRegistryFilterer, error) {
+ contract, err := bindPriceRegistry(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFilterer{contract: contract}, nil
+}
+
+func bindPriceRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := PriceRegistryMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _PriceRegistry.Contract.PriceRegistryCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.PriceRegistryTransactor.contract.Transfer(opts)
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.PriceRegistryTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _PriceRegistry.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.contract.Transfer(opts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) ConvertTokenAmount(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "convertTokenAmount", fromToken, fromTokenAmount, toToken)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) ConvertTokenAmount(fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.ConvertTokenAmount(&_PriceRegistry.CallOpts, fromToken, fromTokenAmount, toToken)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) ConvertTokenAmount(fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.ConvertTokenAmount(&_PriceRegistry.CallOpts, fromToken, fromTokenAmount, toToken)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetAllAuthorizedCallers(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getAllAuthorizedCallers")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetAllAuthorizedCallers() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetAllAuthorizedCallers(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetAllAuthorizedCallers() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetAllAuthorizedCallers(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetDestChainConfig(opts *bind.CallOpts, destChainSelector uint64) (PriceRegistryDestChainConfig, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getDestChainConfig", destChainSelector)
+
+ if err != nil {
+ return *new(PriceRegistryDestChainConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(PriceRegistryDestChainConfig)).(*PriceRegistryDestChainConfig)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetDestChainConfig(destChainSelector uint64) (PriceRegistryDestChainConfig, error) {
+ return _PriceRegistry.Contract.GetDestChainConfig(&_PriceRegistry.CallOpts, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetDestChainConfig(destChainSelector uint64) (PriceRegistryDestChainConfig, error) {
+ return _PriceRegistry.Contract.GetDestChainConfig(&_PriceRegistry.CallOpts, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetDestinationChainGasPrice(opts *bind.CallOpts, destChainSelector uint64) (InternalTimestampedPackedUint224, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getDestinationChainGasPrice", destChainSelector)
+
+ if err != nil {
+ return *new(InternalTimestampedPackedUint224), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(InternalTimestampedPackedUint224)).(*InternalTimestampedPackedUint224)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetDestinationChainGasPrice(destChainSelector uint64) (InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetDestinationChainGasPrice(&_PriceRegistry.CallOpts, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetDestinationChainGasPrice(destChainSelector uint64) (InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetDestinationChainGasPrice(&_PriceRegistry.CallOpts, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetFeeTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getFeeTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetFeeTokens() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetFeeTokens(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetFeeTokens() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetFeeTokens(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetPremiumMultiplierWeiPerEth(opts *bind.CallOpts, token common.Address) (uint64, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getPremiumMultiplierWeiPerEth", token)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetPremiumMultiplierWeiPerEth(token common.Address) (uint64, error) {
+ return _PriceRegistry.Contract.GetPremiumMultiplierWeiPerEth(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetPremiumMultiplierWeiPerEth(token common.Address) (uint64, error) {
+ return _PriceRegistry.Contract.GetPremiumMultiplierWeiPerEth(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetStaticConfig(opts *bind.CallOpts) (PriceRegistryStaticConfig, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getStaticConfig")
+
+ if err != nil {
+ return *new(PriceRegistryStaticConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(PriceRegistryStaticConfig)).(*PriceRegistryStaticConfig)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetStaticConfig() (PriceRegistryStaticConfig, error) {
+ return _PriceRegistry.Contract.GetStaticConfig(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetStaticConfig() (PriceRegistryStaticConfig, error) {
+ return _PriceRegistry.Contract.GetStaticConfig(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenAndGasPrices(opts *bind.CallOpts, token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenAndGasPrices", token, destChainSelector)
+
+ outstruct := new(GetTokenAndGasPrices)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.TokenPrice = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+ outstruct.GasPriceValue = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenAndGasPrices(token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ return _PriceRegistry.Contract.GetTokenAndGasPrices(&_PriceRegistry.CallOpts, token, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenAndGasPrices(token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ return _PriceRegistry.Contract.GetTokenAndGasPrices(&_PriceRegistry.CallOpts, token, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenPrice(opts *bind.CallOpts, token common.Address) (InternalTimestampedPackedUint224, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenPrice", token)
+
+ if err != nil {
+ return *new(InternalTimestampedPackedUint224), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(InternalTimestampedPackedUint224)).(*InternalTimestampedPackedUint224)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenPrice(token common.Address) (InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenPrice(token common.Address) (InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenPriceFeedConfig(opts *bind.CallOpts, token common.Address) (IPriceRegistryTokenPriceFeedConfig, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenPriceFeedConfig", token)
+
+ if err != nil {
+ return *new(IPriceRegistryTokenPriceFeedConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(IPriceRegistryTokenPriceFeedConfig)).(*IPriceRegistryTokenPriceFeedConfig)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenPriceFeedConfig(token common.Address) (IPriceRegistryTokenPriceFeedConfig, error) {
+ return _PriceRegistry.Contract.GetTokenPriceFeedConfig(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenPriceFeedConfig(token common.Address) (IPriceRegistryTokenPriceFeedConfig, error) {
+ return _PriceRegistry.Contract.GetTokenPriceFeedConfig(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenPrices(opts *bind.CallOpts, tokens []common.Address) ([]InternalTimestampedPackedUint224, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenPrices", tokens)
+
+ if err != nil {
+ return *new([]InternalTimestampedPackedUint224), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]InternalTimestampedPackedUint224)).(*[]InternalTimestampedPackedUint224)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenPrices(tokens []common.Address) ([]InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetTokenPrices(&_PriceRegistry.CallOpts, tokens)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenPrices(tokens []common.Address) ([]InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetTokenPrices(&_PriceRegistry.CallOpts, tokens)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenTransferFeeConfig(opts *bind.CallOpts, destChainSelector uint64, token common.Address) (PriceRegistryTokenTransferFeeConfig, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenTransferFeeConfig", destChainSelector, token)
+
+ if err != nil {
+ return *new(PriceRegistryTokenTransferFeeConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(PriceRegistryTokenTransferFeeConfig)).(*PriceRegistryTokenTransferFeeConfig)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenTransferFeeConfig(destChainSelector uint64, token common.Address) (PriceRegistryTokenTransferFeeConfig, error) {
+ return _PriceRegistry.Contract.GetTokenTransferFeeConfig(&_PriceRegistry.CallOpts, destChainSelector, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenTransferFeeConfig(destChainSelector uint64, token common.Address) (PriceRegistryTokenTransferFeeConfig, error) {
+ return _PriceRegistry.Contract.GetTokenTransferFeeConfig(&_PriceRegistry.CallOpts, destChainSelector, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetValidatedFee(opts *bind.CallOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getValidatedFee", destChainSelector, message)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetValidatedFee(destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _PriceRegistry.Contract.GetValidatedFee(&_PriceRegistry.CallOpts, destChainSelector, message)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetValidatedFee(destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _PriceRegistry.Contract.GetValidatedFee(&_PriceRegistry.CallOpts, destChainSelector, message)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetValidatedTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getValidatedTokenPrice", token)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetValidatedTokenPrice(token common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.GetValidatedTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetValidatedTokenPrice(token common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.GetValidatedTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) Owner() (common.Address, error) {
+ return _PriceRegistry.Contract.Owner(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) Owner() (common.Address, error) {
+ return _PriceRegistry.Contract.Owner(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) ProcessMessageArgs(opts *bind.CallOpts, destChainSelector uint64, feeToken common.Address, feeTokenAmount *big.Int, extraArgs []byte) (ProcessMessageArgs,
+
+ error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "processMessageArgs", destChainSelector, feeToken, feeTokenAmount, extraArgs)
+
+ outstruct := new(ProcessMessageArgs)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.MsgFeeJuels = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+ outstruct.IsOutOfOrderExecution = *abi.ConvertType(out[1], new(bool)).(*bool)
+ outstruct.ConvertedExtraArgs = *abi.ConvertType(out[2], new([]byte)).(*[]byte)
+
+ return *outstruct, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) ProcessMessageArgs(destChainSelector uint64, feeToken common.Address, feeTokenAmount *big.Int, extraArgs []byte) (ProcessMessageArgs,
+
+ error) {
+ return _PriceRegistry.Contract.ProcessMessageArgs(&_PriceRegistry.CallOpts, destChainSelector, feeToken, feeTokenAmount, extraArgs)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) ProcessMessageArgs(destChainSelector uint64, feeToken common.Address, feeTokenAmount *big.Int, extraArgs []byte) (ProcessMessageArgs,
+
+ error) {
+ return _PriceRegistry.Contract.ProcessMessageArgs(&_PriceRegistry.CallOpts, destChainSelector, feeToken, feeTokenAmount, extraArgs)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) TypeAndVersion() (string, error) {
+ return _PriceRegistry.Contract.TypeAndVersion(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) TypeAndVersion() (string, error) {
+ return _PriceRegistry.Contract.TypeAndVersion(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) ValidatePoolReturnData(opts *bind.CallOpts, destChainSelector uint64, rampTokenAmounts []InternalRampTokenAmount, sourceTokenAmounts []ClientEVMTokenAmount) error {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "validatePoolReturnData", destChainSelector, rampTokenAmounts, sourceTokenAmounts)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) ValidatePoolReturnData(destChainSelector uint64, rampTokenAmounts []InternalRampTokenAmount, sourceTokenAmounts []ClientEVMTokenAmount) error {
+ return _PriceRegistry.Contract.ValidatePoolReturnData(&_PriceRegistry.CallOpts, destChainSelector, rampTokenAmounts, sourceTokenAmounts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) ValidatePoolReturnData(destChainSelector uint64, rampTokenAmounts []InternalRampTokenAmount, sourceTokenAmounts []ClientEVMTokenAmount) error {
+ return _PriceRegistry.Contract.ValidatePoolReturnData(&_PriceRegistry.CallOpts, destChainSelector, rampTokenAmounts, sourceTokenAmounts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_PriceRegistry *PriceRegistrySession) AcceptOwnership() (*types.Transaction, error) {
+ return _PriceRegistry.Contract.AcceptOwnership(&_PriceRegistry.TransactOpts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _PriceRegistry.Contract.AcceptOwnership(&_PriceRegistry.TransactOpts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyAuthorizedCallerUpdates(opts *bind.TransactOpts, authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyAuthorizedCallerUpdates", authorizedCallerArgs)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyAuthorizedCallerUpdates(authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyAuthorizedCallerUpdates(&_PriceRegistry.TransactOpts, authorizedCallerArgs)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyAuthorizedCallerUpdates(authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyAuthorizedCallerUpdates(&_PriceRegistry.TransactOpts, authorizedCallerArgs)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyDestChainConfigUpdates(opts *bind.TransactOpts, destChainConfigArgs []PriceRegistryDestChainConfigArgs) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyDestChainConfigUpdates", destChainConfigArgs)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyDestChainConfigUpdates(destChainConfigArgs []PriceRegistryDestChainConfigArgs) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyDestChainConfigUpdates(&_PriceRegistry.TransactOpts, destChainConfigArgs)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyDestChainConfigUpdates(destChainConfigArgs []PriceRegistryDestChainConfigArgs) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyDestChainConfigUpdates(&_PriceRegistry.TransactOpts, destChainConfigArgs)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyFeeTokensUpdates(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyFeeTokensUpdates", feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyFeeTokensUpdates(feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyFeeTokensUpdates(&_PriceRegistry.TransactOpts, feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyFeeTokensUpdates(feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyFeeTokensUpdates(&_PriceRegistry.TransactOpts, feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyPremiumMultiplierWeiPerEthUpdates(opts *bind.TransactOpts, premiumMultiplierWeiPerEthArgs []PriceRegistryPremiumMultiplierWeiPerEthArgs) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyPremiumMultiplierWeiPerEthUpdates", premiumMultiplierWeiPerEthArgs)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyPremiumMultiplierWeiPerEthUpdates(premiumMultiplierWeiPerEthArgs []PriceRegistryPremiumMultiplierWeiPerEthArgs) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyPremiumMultiplierWeiPerEthUpdates(&_PriceRegistry.TransactOpts, premiumMultiplierWeiPerEthArgs)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyPremiumMultiplierWeiPerEthUpdates(premiumMultiplierWeiPerEthArgs []PriceRegistryPremiumMultiplierWeiPerEthArgs) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyPremiumMultiplierWeiPerEthUpdates(&_PriceRegistry.TransactOpts, premiumMultiplierWeiPerEthArgs)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyTokenTransferFeeConfigUpdates(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []PriceRegistryTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []PriceRegistryTokenTransferFeeConfigRemoveArgs) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyTokenTransferFeeConfigUpdates", tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyTokenTransferFeeConfigUpdates(tokenTransferFeeConfigArgs []PriceRegistryTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []PriceRegistryTokenTransferFeeConfigRemoveArgs) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyTokenTransferFeeConfigUpdates(&_PriceRegistry.TransactOpts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyTokenTransferFeeConfigUpdates(tokenTransferFeeConfigArgs []PriceRegistryTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []PriceRegistryTokenTransferFeeConfigRemoveArgs) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyTokenTransferFeeConfigUpdates(&_PriceRegistry.TransactOpts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_PriceRegistry *PriceRegistrySession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.TransferOwnership(&_PriceRegistry.TransactOpts, to)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.TransferOwnership(&_PriceRegistry.TransactOpts, to)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) UpdatePrices(opts *bind.TransactOpts, priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "updatePrices", priceUpdates)
+}
+
+func (_PriceRegistry *PriceRegistrySession) UpdatePrices(priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.UpdatePrices(&_PriceRegistry.TransactOpts, priceUpdates)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) UpdatePrices(priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.UpdatePrices(&_PriceRegistry.TransactOpts, priceUpdates)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) UpdateTokenPriceFeeds(opts *bind.TransactOpts, tokenPriceFeedUpdates []PriceRegistryTokenPriceFeedUpdate) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "updateTokenPriceFeeds", tokenPriceFeedUpdates)
+}
+
+func (_PriceRegistry *PriceRegistrySession) UpdateTokenPriceFeeds(tokenPriceFeedUpdates []PriceRegistryTokenPriceFeedUpdate) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.UpdateTokenPriceFeeds(&_PriceRegistry.TransactOpts, tokenPriceFeedUpdates)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) UpdateTokenPriceFeeds(tokenPriceFeedUpdates []PriceRegistryTokenPriceFeedUpdate) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.UpdateTokenPriceFeeds(&_PriceRegistry.TransactOpts, tokenPriceFeedUpdates)
+}
+
+type PriceRegistryAuthorizedCallerAddedIterator struct {
+ Event *PriceRegistryAuthorizedCallerAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryAuthorizedCallerAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryAuthorizedCallerAdded)
+ 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(PriceRegistryAuthorizedCallerAdded)
+ 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 *PriceRegistryAuthorizedCallerAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryAuthorizedCallerAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryAuthorizedCallerAdded struct {
+ Caller common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterAuthorizedCallerAdded(opts *bind.FilterOpts) (*PriceRegistryAuthorizedCallerAddedIterator, error) {
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "AuthorizedCallerAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryAuthorizedCallerAddedIterator{contract: _PriceRegistry.contract, event: "AuthorizedCallerAdded", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchAuthorizedCallerAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryAuthorizedCallerAdded) (event.Subscription, error) {
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "AuthorizedCallerAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryAuthorizedCallerAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "AuthorizedCallerAdded", 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 (_PriceRegistry *PriceRegistryFilterer) ParseAuthorizedCallerAdded(log types.Log) (*PriceRegistryAuthorizedCallerAdded, error) {
+ event := new(PriceRegistryAuthorizedCallerAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "AuthorizedCallerAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryAuthorizedCallerRemovedIterator struct {
+ Event *PriceRegistryAuthorizedCallerRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryAuthorizedCallerRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryAuthorizedCallerRemoved)
+ 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(PriceRegistryAuthorizedCallerRemoved)
+ 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 *PriceRegistryAuthorizedCallerRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryAuthorizedCallerRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryAuthorizedCallerRemoved struct {
+ Caller common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterAuthorizedCallerRemoved(opts *bind.FilterOpts) (*PriceRegistryAuthorizedCallerRemovedIterator, error) {
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "AuthorizedCallerRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryAuthorizedCallerRemovedIterator{contract: _PriceRegistry.contract, event: "AuthorizedCallerRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchAuthorizedCallerRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryAuthorizedCallerRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "AuthorizedCallerRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryAuthorizedCallerRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "AuthorizedCallerRemoved", 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 (_PriceRegistry *PriceRegistryFilterer) ParseAuthorizedCallerRemoved(log types.Log) (*PriceRegistryAuthorizedCallerRemoved, error) {
+ event := new(PriceRegistryAuthorizedCallerRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "AuthorizedCallerRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryDestChainAddedIterator struct {
+ Event *PriceRegistryDestChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryDestChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryDestChainAdded)
+ 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(PriceRegistryDestChainAdded)
+ 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 *PriceRegistryDestChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryDestChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryDestChainAdded struct {
+ DestChainSelector uint64
+ DestChainConfig PriceRegistryDestChainConfig
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterDestChainAdded(opts *bind.FilterOpts, destChainSelector []uint64) (*PriceRegistryDestChainAddedIterator, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "DestChainAdded", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryDestChainAddedIterator{contract: _PriceRegistry.contract, event: "DestChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchDestChainAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryDestChainAdded, destChainSelector []uint64) (event.Subscription, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "DestChainAdded", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryDestChainAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "DestChainAdded", 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 (_PriceRegistry *PriceRegistryFilterer) ParseDestChainAdded(log types.Log) (*PriceRegistryDestChainAdded, error) {
+ event := new(PriceRegistryDestChainAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "DestChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryDestChainConfigUpdatedIterator struct {
+ Event *PriceRegistryDestChainConfigUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryDestChainConfigUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryDestChainConfigUpdated)
+ 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(PriceRegistryDestChainConfigUpdated)
+ 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 *PriceRegistryDestChainConfigUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryDestChainConfigUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryDestChainConfigUpdated struct {
+ DestChainSelector uint64
+ DestChainConfig PriceRegistryDestChainConfig
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterDestChainConfigUpdated(opts *bind.FilterOpts, destChainSelector []uint64) (*PriceRegistryDestChainConfigUpdatedIterator, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "DestChainConfigUpdated", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryDestChainConfigUpdatedIterator{contract: _PriceRegistry.contract, event: "DestChainConfigUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchDestChainConfigUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryDestChainConfigUpdated, destChainSelector []uint64) (event.Subscription, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "DestChainConfigUpdated", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryDestChainConfigUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "DestChainConfigUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParseDestChainConfigUpdated(log types.Log) (*PriceRegistryDestChainConfigUpdated, error) {
+ event := new(PriceRegistryDestChainConfigUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "DestChainConfigUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryFeeTokenAddedIterator struct {
+ Event *PriceRegistryFeeTokenAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryFeeTokenAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryFeeTokenAdded)
+ 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(PriceRegistryFeeTokenAdded)
+ 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 *PriceRegistryFeeTokenAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryFeeTokenAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryFeeTokenAdded struct {
+ FeeToken common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterFeeTokenAdded(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenAddedIterator, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "FeeTokenAdded", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFeeTokenAddedIterator{contract: _PriceRegistry.contract, event: "FeeTokenAdded", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchFeeTokenAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenAdded, feeToken []common.Address) (event.Subscription, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "FeeTokenAdded", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryFeeTokenAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenAdded", 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 (_PriceRegistry *PriceRegistryFilterer) ParseFeeTokenAdded(log types.Log) (*PriceRegistryFeeTokenAdded, error) {
+ event := new(PriceRegistryFeeTokenAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryFeeTokenRemovedIterator struct {
+ Event *PriceRegistryFeeTokenRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryFeeTokenRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryFeeTokenRemoved)
+ 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(PriceRegistryFeeTokenRemoved)
+ 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 *PriceRegistryFeeTokenRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryFeeTokenRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryFeeTokenRemoved struct {
+ FeeToken common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterFeeTokenRemoved(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenRemovedIterator, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "FeeTokenRemoved", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFeeTokenRemovedIterator{contract: _PriceRegistry.contract, event: "FeeTokenRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchFeeTokenRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenRemoved, feeToken []common.Address) (event.Subscription, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "FeeTokenRemoved", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryFeeTokenRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenRemoved", 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 (_PriceRegistry *PriceRegistryFilterer) ParseFeeTokenRemoved(log types.Log) (*PriceRegistryFeeTokenRemoved, error) {
+ event := new(PriceRegistryFeeTokenRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryOwnershipTransferRequestedIterator struct {
+ Event *PriceRegistryOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryOwnershipTransferRequested)
+ 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(PriceRegistryOwnershipTransferRequested)
+ 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 *PriceRegistryOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryOwnershipTransferRequestedIterator{contract: _PriceRegistry.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryOwnershipTransferRequested)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_PriceRegistry *PriceRegistryFilterer) ParseOwnershipTransferRequested(log types.Log) (*PriceRegistryOwnershipTransferRequested, error) {
+ event := new(PriceRegistryOwnershipTransferRequested)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryOwnershipTransferredIterator struct {
+ Event *PriceRegistryOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryOwnershipTransferred)
+ 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(PriceRegistryOwnershipTransferred)
+ 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 *PriceRegistryOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryOwnershipTransferredIterator{contract: _PriceRegistry.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryOwnershipTransferred)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferred", 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 (_PriceRegistry *PriceRegistryFilterer) ParseOwnershipTransferred(log types.Log) (*PriceRegistryOwnershipTransferred, error) {
+ event := new(PriceRegistryOwnershipTransferred)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator struct {
+ Event *PriceRegistryPremiumMultiplierWeiPerEthUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryPremiumMultiplierWeiPerEthUpdated)
+ 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(PriceRegistryPremiumMultiplierWeiPerEthUpdated)
+ 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 *PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryPremiumMultiplierWeiPerEthUpdated struct {
+ Token common.Address
+ PremiumMultiplierWeiPerEth uint64
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterPremiumMultiplierWeiPerEthUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "PremiumMultiplierWeiPerEthUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator{contract: _PriceRegistry.contract, event: "PremiumMultiplierWeiPerEthUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchPremiumMultiplierWeiPerEthUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryPremiumMultiplierWeiPerEthUpdated, token []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "PremiumMultiplierWeiPerEthUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryPremiumMultiplierWeiPerEthUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PremiumMultiplierWeiPerEthUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParsePremiumMultiplierWeiPerEthUpdated(log types.Log) (*PriceRegistryPremiumMultiplierWeiPerEthUpdated, error) {
+ event := new(PriceRegistryPremiumMultiplierWeiPerEthUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PremiumMultiplierWeiPerEthUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryPriceFeedPerTokenUpdatedIterator struct {
+ Event *PriceRegistryPriceFeedPerTokenUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryPriceFeedPerTokenUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryPriceFeedPerTokenUpdated)
+ 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(PriceRegistryPriceFeedPerTokenUpdated)
+ 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 *PriceRegistryPriceFeedPerTokenUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryPriceFeedPerTokenUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryPriceFeedPerTokenUpdated struct {
+ Token common.Address
+ PriceFeedConfig IPriceRegistryTokenPriceFeedConfig
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterPriceFeedPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryPriceFeedPerTokenUpdatedIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "PriceFeedPerTokenUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryPriceFeedPerTokenUpdatedIterator{contract: _PriceRegistry.contract, event: "PriceFeedPerTokenUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchPriceFeedPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceFeedPerTokenUpdated, token []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "PriceFeedPerTokenUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryPriceFeedPerTokenUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceFeedPerTokenUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParsePriceFeedPerTokenUpdated(log types.Log) (*PriceRegistryPriceFeedPerTokenUpdated, error) {
+ event := new(PriceRegistryPriceFeedPerTokenUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceFeedPerTokenUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryPriceUpdaterRemovedIterator struct {
+ Event *PriceRegistryPriceUpdaterRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryPriceUpdaterRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryPriceUpdaterRemoved)
+ 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(PriceRegistryPriceUpdaterRemoved)
+ 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 *PriceRegistryPriceUpdaterRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryPriceUpdaterRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryPriceUpdaterRemoved struct {
+ PriceUpdater common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterPriceUpdaterRemoved(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterRemovedIterator, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "PriceUpdaterRemoved", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryPriceUpdaterRemovedIterator{contract: _PriceRegistry.contract, event: "PriceUpdaterRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchPriceUpdaterRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address) (event.Subscription, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "PriceUpdaterRemoved", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryPriceUpdaterRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterRemoved", 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 (_PriceRegistry *PriceRegistryFilterer) ParsePriceUpdaterRemoved(log types.Log) (*PriceRegistryPriceUpdaterRemoved, error) {
+ event := new(PriceRegistryPriceUpdaterRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryPriceUpdaterSetIterator struct {
+ Event *PriceRegistryPriceUpdaterSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryPriceUpdaterSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryPriceUpdaterSet)
+ 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(PriceRegistryPriceUpdaterSet)
+ 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 *PriceRegistryPriceUpdaterSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryPriceUpdaterSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryPriceUpdaterSet struct {
+ PriceUpdater common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterPriceUpdaterSet(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterSetIterator, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "PriceUpdaterSet", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryPriceUpdaterSetIterator{contract: _PriceRegistry.contract, event: "PriceUpdaterSet", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchPriceUpdaterSet(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterSet, priceUpdater []common.Address) (event.Subscription, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "PriceUpdaterSet", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryPriceUpdaterSet)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterSet", 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 (_PriceRegistry *PriceRegistryFilterer) ParsePriceUpdaterSet(log types.Log) (*PriceRegistryPriceUpdaterSet, error) {
+ event := new(PriceRegistryPriceUpdaterSet)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryTokenTransferFeeConfigDeletedIterator struct {
+ Event *PriceRegistryTokenTransferFeeConfigDeleted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryTokenTransferFeeConfigDeletedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryTokenTransferFeeConfigDeleted)
+ 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(PriceRegistryTokenTransferFeeConfigDeleted)
+ 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 *PriceRegistryTokenTransferFeeConfigDeletedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryTokenTransferFeeConfigDeletedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryTokenTransferFeeConfigDeleted struct {
+ DestChainSelector uint64
+ Token common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterTokenTransferFeeConfigDeleted(opts *bind.FilterOpts, destChainSelector []uint64, token []common.Address) (*PriceRegistryTokenTransferFeeConfigDeletedIterator, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "TokenTransferFeeConfigDeleted", destChainSelectorRule, tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryTokenTransferFeeConfigDeletedIterator{contract: _PriceRegistry.contract, event: "TokenTransferFeeConfigDeleted", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchTokenTransferFeeConfigDeleted(opts *bind.WatchOpts, sink chan<- *PriceRegistryTokenTransferFeeConfigDeleted, destChainSelector []uint64, token []common.Address) (event.Subscription, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "TokenTransferFeeConfigDeleted", destChainSelectorRule, tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryTokenTransferFeeConfigDeleted)
+ if err := _PriceRegistry.contract.UnpackLog(event, "TokenTransferFeeConfigDeleted", 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 (_PriceRegistry *PriceRegistryFilterer) ParseTokenTransferFeeConfigDeleted(log types.Log) (*PriceRegistryTokenTransferFeeConfigDeleted, error) {
+ event := new(PriceRegistryTokenTransferFeeConfigDeleted)
+ if err := _PriceRegistry.contract.UnpackLog(event, "TokenTransferFeeConfigDeleted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryTokenTransferFeeConfigUpdatedIterator struct {
+ Event *PriceRegistryTokenTransferFeeConfigUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryTokenTransferFeeConfigUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryTokenTransferFeeConfigUpdated)
+ 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(PriceRegistryTokenTransferFeeConfigUpdated)
+ 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 *PriceRegistryTokenTransferFeeConfigUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryTokenTransferFeeConfigUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryTokenTransferFeeConfigUpdated struct {
+ DestChainSelector uint64
+ Token common.Address
+ TokenTransferFeeConfig PriceRegistryTokenTransferFeeConfig
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterTokenTransferFeeConfigUpdated(opts *bind.FilterOpts, destChainSelector []uint64, token []common.Address) (*PriceRegistryTokenTransferFeeConfigUpdatedIterator, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "TokenTransferFeeConfigUpdated", destChainSelectorRule, tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryTokenTransferFeeConfigUpdatedIterator{contract: _PriceRegistry.contract, event: "TokenTransferFeeConfigUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchTokenTransferFeeConfigUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryTokenTransferFeeConfigUpdated, destChainSelector []uint64, token []common.Address) (event.Subscription, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "TokenTransferFeeConfigUpdated", destChainSelectorRule, tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryTokenTransferFeeConfigUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "TokenTransferFeeConfigUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParseTokenTransferFeeConfigUpdated(log types.Log) (*PriceRegistryTokenTransferFeeConfigUpdated, error) {
+ event := new(PriceRegistryTokenTransferFeeConfigUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "TokenTransferFeeConfigUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryUsdPerTokenUpdatedIterator struct {
+ Event *PriceRegistryUsdPerTokenUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryUsdPerTokenUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryUsdPerTokenUpdated)
+ 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(PriceRegistryUsdPerTokenUpdated)
+ 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 *PriceRegistryUsdPerTokenUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryUsdPerTokenUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryUsdPerTokenUpdated struct {
+ Token common.Address
+ Value *big.Int
+ Timestamp *big.Int
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterUsdPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryUsdPerTokenUpdatedIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "UsdPerTokenUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryUsdPerTokenUpdatedIterator{contract: _PriceRegistry.contract, event: "UsdPerTokenUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchUsdPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerTokenUpdated, token []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "UsdPerTokenUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryUsdPerTokenUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerTokenUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParseUsdPerTokenUpdated(log types.Log) (*PriceRegistryUsdPerTokenUpdated, error) {
+ event := new(PriceRegistryUsdPerTokenUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerTokenUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryUsdPerUnitGasUpdatedIterator struct {
+ Event *PriceRegistryUsdPerUnitGasUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryUsdPerUnitGasUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryUsdPerUnitGasUpdated)
+ 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(PriceRegistryUsdPerUnitGasUpdated)
+ 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 *PriceRegistryUsdPerUnitGasUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryUsdPerUnitGasUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryUsdPerUnitGasUpdated struct {
+ DestChain uint64
+ Value *big.Int
+ Timestamp *big.Int
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterUsdPerUnitGasUpdated(opts *bind.FilterOpts, destChain []uint64) (*PriceRegistryUsdPerUnitGasUpdatedIterator, error) {
+
+ var destChainRule []interface{}
+ for _, destChainItem := range destChain {
+ destChainRule = append(destChainRule, destChainItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "UsdPerUnitGasUpdated", destChainRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryUsdPerUnitGasUpdatedIterator{contract: _PriceRegistry.contract, event: "UsdPerUnitGasUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error) {
+
+ var destChainRule []interface{}
+ for _, destChainItem := range destChain {
+ destChainRule = append(destChainRule, destChainItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "UsdPerUnitGasUpdated", destChainRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryUsdPerUnitGasUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerUnitGasUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParseUsdPerUnitGasUpdated(log types.Log) (*PriceRegistryUsdPerUnitGasUpdated, error) {
+ event := new(PriceRegistryUsdPerUnitGasUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerUnitGasUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetTokenAndGasPrices struct {
+ TokenPrice *big.Int
+ GasPriceValue *big.Int
+}
+type ProcessMessageArgs struct {
+ MsgFeeJuels *big.Int
+ IsOutOfOrderExecution bool
+ ConvertedExtraArgs []byte
+}
+
+func (_PriceRegistry *PriceRegistry) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _PriceRegistry.abi.Events["AuthorizedCallerAdded"].ID:
+ return _PriceRegistry.ParseAuthorizedCallerAdded(log)
+ case _PriceRegistry.abi.Events["AuthorizedCallerRemoved"].ID:
+ return _PriceRegistry.ParseAuthorizedCallerRemoved(log)
+ case _PriceRegistry.abi.Events["DestChainAdded"].ID:
+ return _PriceRegistry.ParseDestChainAdded(log)
+ case _PriceRegistry.abi.Events["DestChainConfigUpdated"].ID:
+ return _PriceRegistry.ParseDestChainConfigUpdated(log)
+ case _PriceRegistry.abi.Events["FeeTokenAdded"].ID:
+ return _PriceRegistry.ParseFeeTokenAdded(log)
+ case _PriceRegistry.abi.Events["FeeTokenRemoved"].ID:
+ return _PriceRegistry.ParseFeeTokenRemoved(log)
+ case _PriceRegistry.abi.Events["OwnershipTransferRequested"].ID:
+ return _PriceRegistry.ParseOwnershipTransferRequested(log)
+ case _PriceRegistry.abi.Events["OwnershipTransferred"].ID:
+ return _PriceRegistry.ParseOwnershipTransferred(log)
+ case _PriceRegistry.abi.Events["PremiumMultiplierWeiPerEthUpdated"].ID:
+ return _PriceRegistry.ParsePremiumMultiplierWeiPerEthUpdated(log)
+ case _PriceRegistry.abi.Events["PriceFeedPerTokenUpdated"].ID:
+ return _PriceRegistry.ParsePriceFeedPerTokenUpdated(log)
+ case _PriceRegistry.abi.Events["PriceUpdaterRemoved"].ID:
+ return _PriceRegistry.ParsePriceUpdaterRemoved(log)
+ case _PriceRegistry.abi.Events["PriceUpdaterSet"].ID:
+ return _PriceRegistry.ParsePriceUpdaterSet(log)
+ case _PriceRegistry.abi.Events["TokenTransferFeeConfigDeleted"].ID:
+ return _PriceRegistry.ParseTokenTransferFeeConfigDeleted(log)
+ case _PriceRegistry.abi.Events["TokenTransferFeeConfigUpdated"].ID:
+ return _PriceRegistry.ParseTokenTransferFeeConfigUpdated(log)
+ case _PriceRegistry.abi.Events["UsdPerTokenUpdated"].ID:
+ return _PriceRegistry.ParseUsdPerTokenUpdated(log)
+ case _PriceRegistry.abi.Events["UsdPerUnitGasUpdated"].ID:
+ return _PriceRegistry.ParseUsdPerUnitGasUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (PriceRegistryAuthorizedCallerAdded) Topic() common.Hash {
+ return common.HexToHash("0xeb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef")
+}
+
+func (PriceRegistryAuthorizedCallerRemoved) Topic() common.Hash {
+ return common.HexToHash("0xc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda77580")
+}
+
+func (PriceRegistryDestChainAdded) Topic() common.Hash {
+ return common.HexToHash("0xa937382a486d993de71c220bc8b559242deb4e286a353fa732330b4aa7d13577")
+}
+
+func (PriceRegistryDestChainConfigUpdated) Topic() common.Hash {
+ return common.HexToHash("0xa7b607fc10d28a1caf39ab7d27f4c94945db708a576d572781a455c5894fad93")
+}
+
+func (PriceRegistryFeeTokenAdded) Topic() common.Hash {
+ return common.HexToHash("0xdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba23")
+}
+
+func (PriceRegistryFeeTokenRemoved) Topic() common.Hash {
+ return common.HexToHash("0x1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f91")
+}
+
+func (PriceRegistryOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (PriceRegistryOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (PriceRegistryPremiumMultiplierWeiPerEthUpdated) Topic() common.Hash {
+ return common.HexToHash("0xbb77da6f7210cdd16904228a9360133d1d7dfff99b1bc75f128da5b53e28f97d")
+}
+
+func (PriceRegistryPriceFeedPerTokenUpdated) Topic() common.Hash {
+ return common.HexToHash("0x08a5f7f5bb38a81d8e43aca13ecd76431dbf8816ae4699affff7b00b2fc1c464")
+}
+
+func (PriceRegistryPriceUpdaterRemoved) Topic() common.Hash {
+ return common.HexToHash("0xff7dbb85c77ca68ca1f894d6498570e3d5095cd19466f07ee8d222b337e4068c")
+}
+
+func (PriceRegistryPriceUpdaterSet) Topic() common.Hash {
+ return common.HexToHash("0x34a02290b7920078c19f58e94b78c77eb9cc10195b20676e19bd3b82085893b8")
+}
+
+func (PriceRegistryTokenTransferFeeConfigDeleted) Topic() common.Hash {
+ return common.HexToHash("0x4de5b1bcbca6018c11303a2c3f4a4b4f22a1c741d8c4ba430d246ac06c5ddf8b")
+}
+
+func (PriceRegistryTokenTransferFeeConfigUpdated) Topic() common.Hash {
+ return common.HexToHash("0x94967ae9ea7729ad4f54021c1981765d2b1d954f7c92fbec340aa0a54f46b8b5")
+}
+
+func (PriceRegistryUsdPerTokenUpdated) Topic() common.Hash {
+ return common.HexToHash("0x52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a")
+}
+
+func (PriceRegistryUsdPerUnitGasUpdated) Topic() common.Hash {
+ return common.HexToHash("0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e")
+}
+
+func (_PriceRegistry *PriceRegistry) Address() common.Address {
+ return _PriceRegistry.address
+}
+
+type PriceRegistryInterface interface {
+ ConvertTokenAmount(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error)
+
+ GetAllAuthorizedCallers(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetDestChainConfig(opts *bind.CallOpts, destChainSelector uint64) (PriceRegistryDestChainConfig, error)
+
+ GetDestinationChainGasPrice(opts *bind.CallOpts, destChainSelector uint64) (InternalTimestampedPackedUint224, error)
+
+ GetFeeTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetPremiumMultiplierWeiPerEth(opts *bind.CallOpts, token common.Address) (uint64, error)
+
+ GetStaticConfig(opts *bind.CallOpts) (PriceRegistryStaticConfig, error)
+
+ GetTokenAndGasPrices(opts *bind.CallOpts, token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error)
+
+ GetTokenPrice(opts *bind.CallOpts, token common.Address) (InternalTimestampedPackedUint224, error)
+
+ GetTokenPriceFeedConfig(opts *bind.CallOpts, token common.Address) (IPriceRegistryTokenPriceFeedConfig, error)
+
+ GetTokenPrices(opts *bind.CallOpts, tokens []common.Address) ([]InternalTimestampedPackedUint224, error)
+
+ GetTokenTransferFeeConfig(opts *bind.CallOpts, destChainSelector uint64, token common.Address) (PriceRegistryTokenTransferFeeConfig, error)
+
+ GetValidatedFee(opts *bind.CallOpts, destChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error)
+
+ GetValidatedTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ ProcessMessageArgs(opts *bind.CallOpts, destChainSelector uint64, feeToken common.Address, feeTokenAmount *big.Int, extraArgs []byte) (ProcessMessageArgs,
+
+ error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ ValidatePoolReturnData(opts *bind.CallOpts, destChainSelector uint64, rampTokenAmounts []InternalRampTokenAmount, sourceTokenAmounts []ClientEVMTokenAmount) error
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAuthorizedCallerUpdates(opts *bind.TransactOpts, authorizedCallerArgs AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error)
+
+ ApplyDestChainConfigUpdates(opts *bind.TransactOpts, destChainConfigArgs []PriceRegistryDestChainConfigArgs) (*types.Transaction, error)
+
+ ApplyFeeTokensUpdates(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error)
+
+ ApplyPremiumMultiplierWeiPerEthUpdates(opts *bind.TransactOpts, premiumMultiplierWeiPerEthArgs []PriceRegistryPremiumMultiplierWeiPerEthArgs) (*types.Transaction, error)
+
+ ApplyTokenTransferFeeConfigUpdates(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []PriceRegistryTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []PriceRegistryTokenTransferFeeConfigRemoveArgs) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ UpdatePrices(opts *bind.TransactOpts, priceUpdates InternalPriceUpdates) (*types.Transaction, error)
+
+ UpdateTokenPriceFeeds(opts *bind.TransactOpts, tokenPriceFeedUpdates []PriceRegistryTokenPriceFeedUpdate) (*types.Transaction, error)
+
+ FilterAuthorizedCallerAdded(opts *bind.FilterOpts) (*PriceRegistryAuthorizedCallerAddedIterator, error)
+
+ WatchAuthorizedCallerAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryAuthorizedCallerAdded) (event.Subscription, error)
+
+ ParseAuthorizedCallerAdded(log types.Log) (*PriceRegistryAuthorizedCallerAdded, error)
+
+ FilterAuthorizedCallerRemoved(opts *bind.FilterOpts) (*PriceRegistryAuthorizedCallerRemovedIterator, error)
+
+ WatchAuthorizedCallerRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryAuthorizedCallerRemoved) (event.Subscription, error)
+
+ ParseAuthorizedCallerRemoved(log types.Log) (*PriceRegistryAuthorizedCallerRemoved, error)
+
+ FilterDestChainAdded(opts *bind.FilterOpts, destChainSelector []uint64) (*PriceRegistryDestChainAddedIterator, error)
+
+ WatchDestChainAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryDestChainAdded, destChainSelector []uint64) (event.Subscription, error)
+
+ ParseDestChainAdded(log types.Log) (*PriceRegistryDestChainAdded, error)
+
+ FilterDestChainConfigUpdated(opts *bind.FilterOpts, destChainSelector []uint64) (*PriceRegistryDestChainConfigUpdatedIterator, error)
+
+ WatchDestChainConfigUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryDestChainConfigUpdated, destChainSelector []uint64) (event.Subscription, error)
+
+ ParseDestChainConfigUpdated(log types.Log) (*PriceRegistryDestChainConfigUpdated, error)
+
+ FilterFeeTokenAdded(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenAddedIterator, error)
+
+ WatchFeeTokenAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenAdded, feeToken []common.Address) (event.Subscription, error)
+
+ ParseFeeTokenAdded(log types.Log) (*PriceRegistryFeeTokenAdded, error)
+
+ FilterFeeTokenRemoved(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenRemovedIterator, error)
+
+ WatchFeeTokenRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenRemoved, feeToken []common.Address) (event.Subscription, error)
+
+ ParseFeeTokenRemoved(log types.Log) (*PriceRegistryFeeTokenRemoved, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*PriceRegistryOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*PriceRegistryOwnershipTransferred, error)
+
+ FilterPremiumMultiplierWeiPerEthUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator, error)
+
+ WatchPremiumMultiplierWeiPerEthUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryPremiumMultiplierWeiPerEthUpdated, token []common.Address) (event.Subscription, error)
+
+ ParsePremiumMultiplierWeiPerEthUpdated(log types.Log) (*PriceRegistryPremiumMultiplierWeiPerEthUpdated, error)
+
+ FilterPriceFeedPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryPriceFeedPerTokenUpdatedIterator, error)
+
+ WatchPriceFeedPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceFeedPerTokenUpdated, token []common.Address) (event.Subscription, error)
+
+ ParsePriceFeedPerTokenUpdated(log types.Log) (*PriceRegistryPriceFeedPerTokenUpdated, error)
+
+ FilterPriceUpdaterRemoved(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterRemovedIterator, error)
+
+ WatchPriceUpdaterRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address) (event.Subscription, error)
+
+ ParsePriceUpdaterRemoved(log types.Log) (*PriceRegistryPriceUpdaterRemoved, error)
+
+ FilterPriceUpdaterSet(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterSetIterator, error)
+
+ WatchPriceUpdaterSet(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterSet, priceUpdater []common.Address) (event.Subscription, error)
+
+ ParsePriceUpdaterSet(log types.Log) (*PriceRegistryPriceUpdaterSet, error)
+
+ FilterTokenTransferFeeConfigDeleted(opts *bind.FilterOpts, destChainSelector []uint64, token []common.Address) (*PriceRegistryTokenTransferFeeConfigDeletedIterator, error)
+
+ WatchTokenTransferFeeConfigDeleted(opts *bind.WatchOpts, sink chan<- *PriceRegistryTokenTransferFeeConfigDeleted, destChainSelector []uint64, token []common.Address) (event.Subscription, error)
+
+ ParseTokenTransferFeeConfigDeleted(log types.Log) (*PriceRegistryTokenTransferFeeConfigDeleted, error)
+
+ FilterTokenTransferFeeConfigUpdated(opts *bind.FilterOpts, destChainSelector []uint64, token []common.Address) (*PriceRegistryTokenTransferFeeConfigUpdatedIterator, error)
+
+ WatchTokenTransferFeeConfigUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryTokenTransferFeeConfigUpdated, destChainSelector []uint64, token []common.Address) (event.Subscription, error)
+
+ ParseTokenTransferFeeConfigUpdated(log types.Log) (*PriceRegistryTokenTransferFeeConfigUpdated, error)
+
+ FilterUsdPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryUsdPerTokenUpdatedIterator, error)
+
+ WatchUsdPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerTokenUpdated, token []common.Address) (event.Subscription, error)
+
+ ParseUsdPerTokenUpdated(log types.Log) (*PriceRegistryUsdPerTokenUpdated, error)
+
+ FilterUsdPerUnitGasUpdated(opts *bind.FilterOpts, destChain []uint64) (*PriceRegistryUsdPerUnitGasUpdatedIterator, error)
+
+ WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error)
+
+ ParseUsdPerUnitGasUpdated(log types.Log) (*PriceRegistryUsdPerUnitGasUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/price_registry_1_0_0/price_registry.go b/core/gethwrappers/ccip/generated/price_registry_1_0_0/price_registry.go
new file mode 100644
index 00000000000..212d01aee44
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/price_registry_1_0_0/price_registry.go
@@ -0,0 +1,1665 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package price_registry_1_0_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalTimestampedUint192Value struct {
+ Value *big.Int
+ Timestamp uint64
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var PriceRegistryMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"priceUpdaters\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"feeTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint32\",\"name\":\"stalenessThreshold\",\"type\":\"uint32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chain\",\"type\":\"uint64\"}],\"name\":\"ChainNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidStalenessThreshold\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpdaterOrOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePassed\",\"type\":\"uint256\"}],\"name\":\"StaleGasPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePassed\",\"type\":\"uint256\"}],\"name\":\"StaleTokenPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenNotSupported\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"FeeTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"FeeTokenRemoved\",\"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\":\"priceUpdater\",\"type\":\"address\"}],\"name\":\"PriceUpdaterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"priceUpdater\",\"type\":\"address\"}],\"name\":\"PriceUpdaterSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UsdPerTokenUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChain\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UsdPerUnitGasUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"feeTokensToAdd\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"feeTokensToRemove\",\"type\":\"address[]\"}],\"name\":\"applyFeeTokensUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"priceUpdatersToAdd\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"priceUpdatersToRemove\",\"type\":\"address[]\"}],\"name\":\"applyPriceUpdatersUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"fromToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fromTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"toToken\",\"type\":\"address\"}],\"name\":\"convertTokenAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getDestinationChainGasPrice\",\"outputs\":[{\"components\":[{\"internalType\":\"uint192\",\"name\":\"value\",\"type\":\"uint192\"},{\"internalType\":\"uint64\",\"name\":\"timestamp\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.TimestampedUint192Value\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPriceUpdaters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStalenessThreshold\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getTokenAndGasPrices\",\"outputs\":[{\"internalType\":\"uint192\",\"name\":\"tokenPrice\",\"type\":\"uint192\"},{\"internalType\":\"uint192\",\"name\":\"gasPriceValue\",\"type\":\"uint192\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenPrice\",\"outputs\":[{\"components\":[{\"internalType\":\"uint192\",\"name\":\"value\",\"type\":\"uint192\"},{\"internalType\":\"uint64\",\"name\":\"timestamp\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.TimestampedUint192Value\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getTokenPrices\",\"outputs\":[{\"components\":[{\"internalType\":\"uint192\",\"name\":\"value\",\"type\":\"uint192\"},{\"internalType\":\"uint64\",\"name\":\"timestamp\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.TimestampedUint192Value[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getValidatedTokenPrice\",\"outputs\":[{\"internalType\":\"uint192\",\"name\":\"\",\"type\":\"uint192\"}],\"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\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"usdPerToken\",\"type\":\"uint192\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint192\",\"name\":\"usdPerUnitGas\",\"type\":\"uint192\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"}],\"name\":\"updatePrices\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60a06040523480156200001157600080fd5b506040516200217d3803806200217d8339810160408190526200003491620006fe565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000133565b5050604080516000815260208101909152620000dd91508490620001de565b604080516000815260208101909152620000f99083906200033a565b8063ffffffff166000036200012157604051631151410960e11b815260040160405180910390fd5b63ffffffff1660805250620007fa9050565b336001600160a01b038216036200018d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b825181101562000289576200021d83828151811062000204576200020462000786565b602002602001015160046200049160201b90919060201c565b15620002765782818151811062000238576200023862000786565b60200260200101516001600160a01b03167f34a02290b7920078c19f58e94b78c77eb9cc10195b20676e19bd3b82085893b860405160405180910390a25b6200028181620007b2565b9050620001e1565b5060005b81518110156200033557620002c9828281518110620002b057620002b062000786565b60200260200101516004620004b160201b90919060201c565b156200032257818181518110620002e457620002e462000786565b60200260200101516001600160a01b03167fff7dbb85c77ca68ca1f894d6498570e3d5095cd19466f07ee8d222b337e4068c60405160405180910390a25b6200032d81620007b2565b90506200028d565b505050565b60005b8251811015620003e5576200037983828151811062000360576200036062000786565b602002602001015160066200049160201b90919060201c565b15620003d25782818151811062000394576200039462000786565b60200260200101516001600160a01b03167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b620003dd81620007b2565b90506200033d565b5060005b81518110156200033557620004258282815181106200040c576200040c62000786565b60200260200101516006620004b160201b90919060201c565b156200047e5781818151811062000440576200044062000786565b60200260200101516001600160a01b03167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b6200048981620007b2565b9050620003e9565b6000620004a8836001600160a01b038416620004c8565b90505b92915050565b6000620004a8836001600160a01b0384166200051a565b60008181526001830160205260408120546200051157508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620004ab565b506000620004ab565b600081815260018301602052604081205480156200061357600062000541600183620007ce565b85549091506000906200055790600190620007ce565b9050818114620005c35760008660000182815481106200057b576200057b62000786565b9060005260206000200154905080876000018481548110620005a157620005a162000786565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620005d757620005d7620007e4565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050620004ab565b6000915050620004ab565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200064c57600080fd5b919050565b600082601f8301126200066357600080fd5b815160206001600160401b03808311156200068257620006826200061e565b8260051b604051601f19603f83011681018181108482111715620006aa57620006aa6200061e565b604052938452858101830193838101925087851115620006c957600080fd5b83870191505b84821015620006f357620006e38262000634565b83529183019190830190620006cf565b979650505050505050565b6000806000606084860312156200071457600080fd5b83516001600160401b03808211156200072c57600080fd5b6200073a8783880162000651565b945060208601519150808211156200075157600080fd5b50620007608682870162000651565b925050604084015163ffffffff811681146200077b57600080fd5b809150509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620007c757620007c76200079c565b5060010190565b81810381811115620004ab57620004ab6200079c565b634e487b7160e01b600052603160045260246000fd5b60805161194b620008326000396000818161028501528181610a5201528181610abb01528181610c180152610c8d015261194b6000f3fe608060405234801561001057600080fd5b50600436106100f45760003560e01c8063866548c911610097578063cdc73d5111610066578063cdc73d51146102c4578063d02641a0146102cc578063f2fde38b1461036a578063ffdb4b371461037d57600080fd5b8063866548c9146102405780638da5cb5b14610253578063a6c94a731461027b578063bfcd4566146102af57600080fd5b8063514e8cff116100d3578063514e8cff1461017b57806352877af01461021057806379ba5097146102255780637afac3221461022d57600080fd5b806241e5be146100f957806345ac924d1461011f5780634ab35b0b1461013f575b600080fd5b61010c61010736600461133e565b6103c1565b6040519081526020015b60405180910390f35b61013261012d36600461137a565b610425565b60405161011691906113ef565b61015261014d36600461146a565b6104f9565b60405177ffffffffffffffffffffffffffffffffffffffffffffffff9091168152602001610116565b61020361018936600461149d565b6040805180820182526000808252602091820181905267ffffffffffffffff93841681526002825282902082518084019093525477ffffffffffffffffffffffffffffffffffffffffffffffff81168352780100000000000000000000000000000000000000000000000090049092169181019190915290565b60405161011691906114b8565b61022361021e3660046115e2565b610504565b005b61022361051a565b61022361023b3660046115e2565b61061c565b61022361024e366004611646565b61062e565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610116565b60405163ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610116565b6102b7610951565b6040516101169190611681565b6102b7610962565b6102036102da36600461146a565b60408051808201909152600080825260208201525073ffffffffffffffffffffffffffffffffffffffff1660009081526003602090815260409182902082518084019093525477ffffffffffffffffffffffffffffffffffffffffffffffff811683527801000000000000000000000000000000000000000000000000900467ffffffffffffffff169082015290565b61022361037836600461146a565b61096e565b61039061038b3660046116db565b610982565b6040805177ffffffffffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610116565b60006103cc82610b09565b77ffffffffffffffffffffffffffffffffffffffffffffffff166103ef85610b09565b6104139077ffffffffffffffffffffffffffffffffffffffffffffffff168561173d565b61041d9190611754565b949350505050565b60608160008167ffffffffffffffff811115610443576104436114f3565b60405190808252806020026020018201604052801561048857816020015b60408051808201909152600080825260208201528152602001906001900390816104615790505b50905060005b828110156104ee576104c08686838181106104ab576104ab61178f565b90506020020160208101906102da919061146a565b8282815181106104d2576104d261178f565b6020026020010181905250806104e7906117be565b905061048e565b509150505b92915050565b60006104f382610b09565b61050c610cc9565b6105168282610d4c565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610624610cc9565b6105168282610ea8565b60005473ffffffffffffffffffffffffffffffffffffffff16331480159061065e575061065c600433610fff565b155b15610695576040517f46f0815400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006106a182806117f6565b9050905060005b818110156107eb5760006106bc84806117f6565b838181106106cc576106cc61178f565b9050604002018036038101906106e29190611886565b6040805180820182526020808401805177ffffffffffffffffffffffffffffffffffffffffffffffff908116845267ffffffffffffffff42818116858701908152885173ffffffffffffffffffffffffffffffffffffffff908116600090815260039097529588902096519051909216780100000000000000000000000000000000000000000000000002919092161790935584519051935194955016927f52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a926107d292909177ffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a2506107e4816117be565b90506106a8565b506107fc604083016020840161149d565b67ffffffffffffffff161561051657604051806040016040528083604001602081019061082991906118e1565b77ffffffffffffffffffffffffffffffffffffffffffffffff1681526020014267ffffffffffffffff168152506002600084602001602081019061086d919061149d565b67ffffffffffffffff9081168252602080830193909352604091820160002084519484015190911678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff909416939093179092556108e191840190840161149d565b67ffffffffffffffff167fdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e61091c60608501604086016118e1565b6040805177ffffffffffffffffffffffffffffffffffffffffffffffff90921682524260208301520160405180910390a25050565b606061095d6004611031565b905090565b606061095d6006611031565b610976610cc9565b61097f8161103e565b50565b67ffffffffffffffff808216600090815260026020908152604080832081518083019092525477ffffffffffffffffffffffffffffffffffffffffffffffff8116825278010000000000000000000000000000000000000000000000009004909316908301819052909182918203610a32576040517f2e59db3a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff85166004820152602401610597565b6000816020015167ffffffffffffffff1642610a4e91906118fc565b90507f000000000000000000000000000000000000000000000000000000000000000063ffffffff16811115610aef576040517ff08bcb3e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8616600482015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260448101829052606401610597565b610af886610b09565b9151919350909150505b9250929050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020908152604080832081518083019092525477ffffffffffffffffffffffffffffffffffffffffffffffff811682527801000000000000000000000000000000000000000000000000900467ffffffffffffffff16918101829052901580610ba95750805177ffffffffffffffffffffffffffffffffffffffffffffffff16155b15610bf8576040517f06439c6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610597565b6000816020015167ffffffffffffffff1642610c1491906118fc565b90507f000000000000000000000000000000000000000000000000000000000000000063ffffffff16811115610cc1576040517fc65fdfca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260448101829052606401610597565b505192915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610597565b565b60005b8251811015610df757610d85838281518110610d6d57610d6d61178f565b6020026020010151600461113390919063ffffffff16565b15610de757828181518110610d9c57610d9c61178f565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f34a02290b7920078c19f58e94b78c77eb9cc10195b20676e19bd3b82085893b860405160405180910390a25b610df0816117be565b9050610d4f565b5060005b8151811015610ea357610e31828281518110610e1957610e1961178f565b6020026020010151600461115590919063ffffffff16565b15610e9357818181518110610e4857610e4861178f565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167fff7dbb85c77ca68ca1f894d6498570e3d5095cd19466f07ee8d222b337e4068c60405160405180910390a25b610e9c816117be565b9050610dfb565b505050565b60005b8251811015610f5357610ee1838281518110610ec957610ec961178f565b6020026020010151600661113390919063ffffffff16565b15610f4357828181518110610ef857610ef861178f565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b610f4c816117be565b9050610eab565b5060005b8151811015610ea357610f8d828281518110610f7557610f7561178f565b6020026020010151600661115590919063ffffffff16565b15610fef57818181518110610fa457610fa461178f565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b610ff8816117be565b9050610f57565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b9392505050565b6060600061102a83611177565b3373ffffffffffffffffffffffffffffffffffffffff8216036110bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610597565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061102a8373ffffffffffffffffffffffffffffffffffffffff84166111d3565b600061102a8373ffffffffffffffffffffffffffffffffffffffff8416611222565b6060816000018054806020026020016040519081016040528092919081815260200182805480156111c757602002820191906000526020600020905b8154815260200190600101908083116111b3575b50505050509050919050565b600081815260018301602052604081205461121a575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104f3565b5060006104f3565b6000818152600183016020526040812054801561130b5760006112466001836118fc565b855490915060009061125a906001906118fc565b90508181146112bf57600086600001828154811061127a5761127a61178f565b906000526020600020015490508087600001848154811061129d5761129d61178f565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806112d0576112d061190f565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104f3565b60009150506104f3565b803573ffffffffffffffffffffffffffffffffffffffff8116811461133957600080fd5b919050565b60008060006060848603121561135357600080fd5b61135c84611315565b92506020840135915061137160408501611315565b90509250925092565b6000806020838503121561138d57600080fd5b823567ffffffffffffffff808211156113a557600080fd5b818501915085601f8301126113b957600080fd5b8135818111156113c857600080fd5b8660208260051b85010111156113dd57600080fd5b60209290920196919550909350505050565b602080825282518282018190526000919060409081850190868401855b8281101561145d5761144d848351805177ffffffffffffffffffffffffffffffffffffffffffffffff16825260209081015167ffffffffffffffff16910152565b928401929085019060010161140c565b5091979650505050505050565b60006020828403121561147c57600080fd5b61102a82611315565b803567ffffffffffffffff8116811461133957600080fd5b6000602082840312156114af57600080fd5b61102a82611485565b815177ffffffffffffffffffffffffffffffffffffffffffffffff16815260208083015167ffffffffffffffff1690820152604081016104f3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011261153357600080fd5b8135602067ffffffffffffffff80831115611550576115506114f3565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108482111715611593576115936114f3565b6040529384528581018301938381019250878511156115b157600080fd5b83870191505b848210156115d7576115c882611315565b835291830191908301906115b7565b979650505050505050565b600080604083850312156115f557600080fd5b823567ffffffffffffffff8082111561160d57600080fd5b61161986838701611522565b9350602085013591508082111561162f57600080fd5b5061163c85828601611522565b9150509250929050565b60006020828403121561165857600080fd5b813567ffffffffffffffff81111561166f57600080fd5b82016060818503121561102a57600080fd5b6020808252825182820181905260009190848201906040850190845b818110156116cf57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161169d565b50909695505050505050565b600080604083850312156116ee57600080fd5b6116f783611315565b915061170560208401611485565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176104f3576104f361170e565b60008261178a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036117ef576117ef61170e565b5060010190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261182b57600080fd5b83018035915067ffffffffffffffff82111561184657600080fd5b6020019150600681901b3603821315610b0257600080fd5b803577ffffffffffffffffffffffffffffffffffffffffffffffff8116811461133957600080fd5b60006040828403121561189857600080fd5b6040516040810181811067ffffffffffffffff821117156118bb576118bb6114f3565b6040526118c783611315565b81526118d56020840161185e565b60208201529392505050565b6000602082840312156118f357600080fd5b61102a8261185e565b818103818111156104f3576104f361170e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a",
+}
+
+var PriceRegistryABI = PriceRegistryMetaData.ABI
+
+var PriceRegistryBin = PriceRegistryMetaData.Bin
+
+func DeployPriceRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, priceUpdaters []common.Address, feeTokens []common.Address, stalenessThreshold uint32) (common.Address, *types.Transaction, *PriceRegistry, error) {
+ parsed, err := PriceRegistryMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(PriceRegistryBin), backend, priceUpdaters, feeTokens, stalenessThreshold)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &PriceRegistry{PriceRegistryCaller: PriceRegistryCaller{contract: contract}, PriceRegistryTransactor: PriceRegistryTransactor{contract: contract}, PriceRegistryFilterer: PriceRegistryFilterer{contract: contract}}, nil
+}
+
+type PriceRegistry struct {
+ address common.Address
+ abi abi.ABI
+ PriceRegistryCaller
+ PriceRegistryTransactor
+ PriceRegistryFilterer
+}
+
+type PriceRegistryCaller struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistryTransactor struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistryFilterer struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistrySession struct {
+ Contract *PriceRegistry
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type PriceRegistryCallerSession struct {
+ Contract *PriceRegistryCaller
+ CallOpts bind.CallOpts
+}
+
+type PriceRegistryTransactorSession struct {
+ Contract *PriceRegistryTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type PriceRegistryRaw struct {
+ Contract *PriceRegistry
+}
+
+type PriceRegistryCallerRaw struct {
+ Contract *PriceRegistryCaller
+}
+
+type PriceRegistryTransactorRaw struct {
+ Contract *PriceRegistryTransactor
+}
+
+func NewPriceRegistry(address common.Address, backend bind.ContractBackend) (*PriceRegistry, error) {
+ abi, err := abi.JSON(strings.NewReader(PriceRegistryABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindPriceRegistry(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistry{address: address, abi: abi, PriceRegistryCaller: PriceRegistryCaller{contract: contract}, PriceRegistryTransactor: PriceRegistryTransactor{contract: contract}, PriceRegistryFilterer: PriceRegistryFilterer{contract: contract}}, nil
+}
+
+func NewPriceRegistryCaller(address common.Address, caller bind.ContractCaller) (*PriceRegistryCaller, error) {
+ contract, err := bindPriceRegistry(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryCaller{contract: contract}, nil
+}
+
+func NewPriceRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*PriceRegistryTransactor, error) {
+ contract, err := bindPriceRegistry(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryTransactor{contract: contract}, nil
+}
+
+func NewPriceRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*PriceRegistryFilterer, error) {
+ contract, err := bindPriceRegistry(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFilterer{contract: contract}, nil
+}
+
+func bindPriceRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := PriceRegistryMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _PriceRegistry.Contract.PriceRegistryCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.PriceRegistryTransactor.contract.Transfer(opts)
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.PriceRegistryTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _PriceRegistry.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.contract.Transfer(opts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) ConvertTokenAmount(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "convertTokenAmount", fromToken, fromTokenAmount, toToken)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) ConvertTokenAmount(fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.ConvertTokenAmount(&_PriceRegistry.CallOpts, fromToken, fromTokenAmount, toToken)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) ConvertTokenAmount(fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.ConvertTokenAmount(&_PriceRegistry.CallOpts, fromToken, fromTokenAmount, toToken)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetDestinationChainGasPrice(opts *bind.CallOpts, destChainSelector uint64) (InternalTimestampedUint192Value, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getDestinationChainGasPrice", destChainSelector)
+
+ if err != nil {
+ return *new(InternalTimestampedUint192Value), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(InternalTimestampedUint192Value)).(*InternalTimestampedUint192Value)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetDestinationChainGasPrice(destChainSelector uint64) (InternalTimestampedUint192Value, error) {
+ return _PriceRegistry.Contract.GetDestinationChainGasPrice(&_PriceRegistry.CallOpts, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetDestinationChainGasPrice(destChainSelector uint64) (InternalTimestampedUint192Value, error) {
+ return _PriceRegistry.Contract.GetDestinationChainGasPrice(&_PriceRegistry.CallOpts, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetFeeTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getFeeTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetFeeTokens() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetFeeTokens(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetFeeTokens() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetFeeTokens(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetPriceUpdaters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getPriceUpdaters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetPriceUpdaters() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetPriceUpdaters(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetPriceUpdaters() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetPriceUpdaters(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetStalenessThreshold(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getStalenessThreshold")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetStalenessThreshold() (*big.Int, error) {
+ return _PriceRegistry.Contract.GetStalenessThreshold(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetStalenessThreshold() (*big.Int, error) {
+ return _PriceRegistry.Contract.GetStalenessThreshold(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenAndGasPrices(opts *bind.CallOpts, token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenAndGasPrices", token, destChainSelector)
+
+ outstruct := new(GetTokenAndGasPrices)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.TokenPrice = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+ outstruct.GasPriceValue = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenAndGasPrices(token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ return _PriceRegistry.Contract.GetTokenAndGasPrices(&_PriceRegistry.CallOpts, token, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenAndGasPrices(token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ return _PriceRegistry.Contract.GetTokenAndGasPrices(&_PriceRegistry.CallOpts, token, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenPrice(opts *bind.CallOpts, token common.Address) (InternalTimestampedUint192Value, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenPrice", token)
+
+ if err != nil {
+ return *new(InternalTimestampedUint192Value), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(InternalTimestampedUint192Value)).(*InternalTimestampedUint192Value)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenPrice(token common.Address) (InternalTimestampedUint192Value, error) {
+ return _PriceRegistry.Contract.GetTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenPrice(token common.Address) (InternalTimestampedUint192Value, error) {
+ return _PriceRegistry.Contract.GetTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenPrices(opts *bind.CallOpts, tokens []common.Address) ([]InternalTimestampedUint192Value, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenPrices", tokens)
+
+ if err != nil {
+ return *new([]InternalTimestampedUint192Value), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]InternalTimestampedUint192Value)).(*[]InternalTimestampedUint192Value)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenPrices(tokens []common.Address) ([]InternalTimestampedUint192Value, error) {
+ return _PriceRegistry.Contract.GetTokenPrices(&_PriceRegistry.CallOpts, tokens)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenPrices(tokens []common.Address) ([]InternalTimestampedUint192Value, error) {
+ return _PriceRegistry.Contract.GetTokenPrices(&_PriceRegistry.CallOpts, tokens)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetValidatedTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getValidatedTokenPrice", token)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetValidatedTokenPrice(token common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.GetValidatedTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetValidatedTokenPrice(token common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.GetValidatedTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) Owner() (common.Address, error) {
+ return _PriceRegistry.Contract.Owner(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) Owner() (common.Address, error) {
+ return _PriceRegistry.Contract.Owner(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_PriceRegistry *PriceRegistrySession) AcceptOwnership() (*types.Transaction, error) {
+ return _PriceRegistry.Contract.AcceptOwnership(&_PriceRegistry.TransactOpts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _PriceRegistry.Contract.AcceptOwnership(&_PriceRegistry.TransactOpts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyFeeTokensUpdates(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyFeeTokensUpdates", feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyFeeTokensUpdates(feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyFeeTokensUpdates(&_PriceRegistry.TransactOpts, feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyFeeTokensUpdates(feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyFeeTokensUpdates(&_PriceRegistry.TransactOpts, feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyPriceUpdatersUpdates(opts *bind.TransactOpts, priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyPriceUpdatersUpdates", priceUpdatersToAdd, priceUpdatersToRemove)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyPriceUpdatersUpdates(priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyPriceUpdatersUpdates(&_PriceRegistry.TransactOpts, priceUpdatersToAdd, priceUpdatersToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyPriceUpdatersUpdates(priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyPriceUpdatersUpdates(&_PriceRegistry.TransactOpts, priceUpdatersToAdd, priceUpdatersToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_PriceRegistry *PriceRegistrySession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.TransferOwnership(&_PriceRegistry.TransactOpts, to)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.TransferOwnership(&_PriceRegistry.TransactOpts, to)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) UpdatePrices(opts *bind.TransactOpts, priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "updatePrices", priceUpdates)
+}
+
+func (_PriceRegistry *PriceRegistrySession) UpdatePrices(priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.UpdatePrices(&_PriceRegistry.TransactOpts, priceUpdates)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) UpdatePrices(priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.UpdatePrices(&_PriceRegistry.TransactOpts, priceUpdates)
+}
+
+type PriceRegistryFeeTokenAddedIterator struct {
+ Event *PriceRegistryFeeTokenAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryFeeTokenAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryFeeTokenAdded)
+ 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(PriceRegistryFeeTokenAdded)
+ 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 *PriceRegistryFeeTokenAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryFeeTokenAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryFeeTokenAdded struct {
+ FeeToken common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterFeeTokenAdded(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenAddedIterator, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "FeeTokenAdded", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFeeTokenAddedIterator{contract: _PriceRegistry.contract, event: "FeeTokenAdded", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchFeeTokenAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenAdded, feeToken []common.Address) (event.Subscription, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "FeeTokenAdded", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryFeeTokenAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenAdded", 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 (_PriceRegistry *PriceRegistryFilterer) ParseFeeTokenAdded(log types.Log) (*PriceRegistryFeeTokenAdded, error) {
+ event := new(PriceRegistryFeeTokenAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryFeeTokenRemovedIterator struct {
+ Event *PriceRegistryFeeTokenRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryFeeTokenRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryFeeTokenRemoved)
+ 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(PriceRegistryFeeTokenRemoved)
+ 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 *PriceRegistryFeeTokenRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryFeeTokenRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryFeeTokenRemoved struct {
+ FeeToken common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterFeeTokenRemoved(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenRemovedIterator, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "FeeTokenRemoved", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFeeTokenRemovedIterator{contract: _PriceRegistry.contract, event: "FeeTokenRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchFeeTokenRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenRemoved, feeToken []common.Address) (event.Subscription, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "FeeTokenRemoved", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryFeeTokenRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenRemoved", 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 (_PriceRegistry *PriceRegistryFilterer) ParseFeeTokenRemoved(log types.Log) (*PriceRegistryFeeTokenRemoved, error) {
+ event := new(PriceRegistryFeeTokenRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryOwnershipTransferRequestedIterator struct {
+ Event *PriceRegistryOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryOwnershipTransferRequested)
+ 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(PriceRegistryOwnershipTransferRequested)
+ 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 *PriceRegistryOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryOwnershipTransferRequestedIterator{contract: _PriceRegistry.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryOwnershipTransferRequested)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_PriceRegistry *PriceRegistryFilterer) ParseOwnershipTransferRequested(log types.Log) (*PriceRegistryOwnershipTransferRequested, error) {
+ event := new(PriceRegistryOwnershipTransferRequested)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryOwnershipTransferredIterator struct {
+ Event *PriceRegistryOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryOwnershipTransferred)
+ 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(PriceRegistryOwnershipTransferred)
+ 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 *PriceRegistryOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryOwnershipTransferredIterator{contract: _PriceRegistry.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryOwnershipTransferred)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferred", 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 (_PriceRegistry *PriceRegistryFilterer) ParseOwnershipTransferred(log types.Log) (*PriceRegistryOwnershipTransferred, error) {
+ event := new(PriceRegistryOwnershipTransferred)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryPriceUpdaterRemovedIterator struct {
+ Event *PriceRegistryPriceUpdaterRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryPriceUpdaterRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryPriceUpdaterRemoved)
+ 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(PriceRegistryPriceUpdaterRemoved)
+ 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 *PriceRegistryPriceUpdaterRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryPriceUpdaterRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryPriceUpdaterRemoved struct {
+ PriceUpdater common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterPriceUpdaterRemoved(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterRemovedIterator, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "PriceUpdaterRemoved", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryPriceUpdaterRemovedIterator{contract: _PriceRegistry.contract, event: "PriceUpdaterRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchPriceUpdaterRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address) (event.Subscription, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "PriceUpdaterRemoved", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryPriceUpdaterRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterRemoved", 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 (_PriceRegistry *PriceRegistryFilterer) ParsePriceUpdaterRemoved(log types.Log) (*PriceRegistryPriceUpdaterRemoved, error) {
+ event := new(PriceRegistryPriceUpdaterRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryPriceUpdaterSetIterator struct {
+ Event *PriceRegistryPriceUpdaterSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryPriceUpdaterSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryPriceUpdaterSet)
+ 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(PriceRegistryPriceUpdaterSet)
+ 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 *PriceRegistryPriceUpdaterSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryPriceUpdaterSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryPriceUpdaterSet struct {
+ PriceUpdater common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterPriceUpdaterSet(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterSetIterator, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "PriceUpdaterSet", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryPriceUpdaterSetIterator{contract: _PriceRegistry.contract, event: "PriceUpdaterSet", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchPriceUpdaterSet(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterSet, priceUpdater []common.Address) (event.Subscription, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "PriceUpdaterSet", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryPriceUpdaterSet)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterSet", 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 (_PriceRegistry *PriceRegistryFilterer) ParsePriceUpdaterSet(log types.Log) (*PriceRegistryPriceUpdaterSet, error) {
+ event := new(PriceRegistryPriceUpdaterSet)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryUsdPerTokenUpdatedIterator struct {
+ Event *PriceRegistryUsdPerTokenUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryUsdPerTokenUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryUsdPerTokenUpdated)
+ 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(PriceRegistryUsdPerTokenUpdated)
+ 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 *PriceRegistryUsdPerTokenUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryUsdPerTokenUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryUsdPerTokenUpdated struct {
+ Token common.Address
+ Value *big.Int
+ Timestamp *big.Int
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterUsdPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryUsdPerTokenUpdatedIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "UsdPerTokenUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryUsdPerTokenUpdatedIterator{contract: _PriceRegistry.contract, event: "UsdPerTokenUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchUsdPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerTokenUpdated, token []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "UsdPerTokenUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryUsdPerTokenUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerTokenUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParseUsdPerTokenUpdated(log types.Log) (*PriceRegistryUsdPerTokenUpdated, error) {
+ event := new(PriceRegistryUsdPerTokenUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerTokenUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryUsdPerUnitGasUpdatedIterator struct {
+ Event *PriceRegistryUsdPerUnitGasUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryUsdPerUnitGasUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryUsdPerUnitGasUpdated)
+ 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(PriceRegistryUsdPerUnitGasUpdated)
+ 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 *PriceRegistryUsdPerUnitGasUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryUsdPerUnitGasUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryUsdPerUnitGasUpdated struct {
+ DestChain uint64
+ Value *big.Int
+ Timestamp *big.Int
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterUsdPerUnitGasUpdated(opts *bind.FilterOpts, destChain []uint64) (*PriceRegistryUsdPerUnitGasUpdatedIterator, error) {
+
+ var destChainRule []interface{}
+ for _, destChainItem := range destChain {
+ destChainRule = append(destChainRule, destChainItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "UsdPerUnitGasUpdated", destChainRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryUsdPerUnitGasUpdatedIterator{contract: _PriceRegistry.contract, event: "UsdPerUnitGasUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error) {
+
+ var destChainRule []interface{}
+ for _, destChainItem := range destChain {
+ destChainRule = append(destChainRule, destChainItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "UsdPerUnitGasUpdated", destChainRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryUsdPerUnitGasUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerUnitGasUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParseUsdPerUnitGasUpdated(log types.Log) (*PriceRegistryUsdPerUnitGasUpdated, error) {
+ event := new(PriceRegistryUsdPerUnitGasUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerUnitGasUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetTokenAndGasPrices struct {
+ TokenPrice *big.Int
+ GasPriceValue *big.Int
+}
+
+func (_PriceRegistry *PriceRegistry) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _PriceRegistry.abi.Events["FeeTokenAdded"].ID:
+ return _PriceRegistry.ParseFeeTokenAdded(log)
+ case _PriceRegistry.abi.Events["FeeTokenRemoved"].ID:
+ return _PriceRegistry.ParseFeeTokenRemoved(log)
+ case _PriceRegistry.abi.Events["OwnershipTransferRequested"].ID:
+ return _PriceRegistry.ParseOwnershipTransferRequested(log)
+ case _PriceRegistry.abi.Events["OwnershipTransferred"].ID:
+ return _PriceRegistry.ParseOwnershipTransferred(log)
+ case _PriceRegistry.abi.Events["PriceUpdaterRemoved"].ID:
+ return _PriceRegistry.ParsePriceUpdaterRemoved(log)
+ case _PriceRegistry.abi.Events["PriceUpdaterSet"].ID:
+ return _PriceRegistry.ParsePriceUpdaterSet(log)
+ case _PriceRegistry.abi.Events["UsdPerTokenUpdated"].ID:
+ return _PriceRegistry.ParseUsdPerTokenUpdated(log)
+ case _PriceRegistry.abi.Events["UsdPerUnitGasUpdated"].ID:
+ return _PriceRegistry.ParseUsdPerUnitGasUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (PriceRegistryFeeTokenAdded) Topic() common.Hash {
+ return common.HexToHash("0xdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba23")
+}
+
+func (PriceRegistryFeeTokenRemoved) Topic() common.Hash {
+ return common.HexToHash("0x1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f91")
+}
+
+func (PriceRegistryOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (PriceRegistryOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (PriceRegistryPriceUpdaterRemoved) Topic() common.Hash {
+ return common.HexToHash("0xff7dbb85c77ca68ca1f894d6498570e3d5095cd19466f07ee8d222b337e4068c")
+}
+
+func (PriceRegistryPriceUpdaterSet) Topic() common.Hash {
+ return common.HexToHash("0x34a02290b7920078c19f58e94b78c77eb9cc10195b20676e19bd3b82085893b8")
+}
+
+func (PriceRegistryUsdPerTokenUpdated) Topic() common.Hash {
+ return common.HexToHash("0x52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a")
+}
+
+func (PriceRegistryUsdPerUnitGasUpdated) Topic() common.Hash {
+ return common.HexToHash("0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e")
+}
+
+func (_PriceRegistry *PriceRegistry) Address() common.Address {
+ return _PriceRegistry.address
+}
+
+type PriceRegistryInterface interface {
+ ConvertTokenAmount(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error)
+
+ GetDestinationChainGasPrice(opts *bind.CallOpts, destChainSelector uint64) (InternalTimestampedUint192Value, error)
+
+ GetFeeTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetPriceUpdaters(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetStalenessThreshold(opts *bind.CallOpts) (*big.Int, error)
+
+ GetTokenAndGasPrices(opts *bind.CallOpts, token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error)
+
+ GetTokenPrice(opts *bind.CallOpts, token common.Address) (InternalTimestampedUint192Value, error)
+
+ GetTokenPrices(opts *bind.CallOpts, tokens []common.Address) ([]InternalTimestampedUint192Value, error)
+
+ GetValidatedTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyFeeTokensUpdates(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error)
+
+ ApplyPriceUpdatersUpdates(opts *bind.TransactOpts, priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ UpdatePrices(opts *bind.TransactOpts, priceUpdates InternalPriceUpdates) (*types.Transaction, error)
+
+ FilterFeeTokenAdded(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenAddedIterator, error)
+
+ WatchFeeTokenAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenAdded, feeToken []common.Address) (event.Subscription, error)
+
+ ParseFeeTokenAdded(log types.Log) (*PriceRegistryFeeTokenAdded, error)
+
+ FilterFeeTokenRemoved(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenRemovedIterator, error)
+
+ WatchFeeTokenRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenRemoved, feeToken []common.Address) (event.Subscription, error)
+
+ ParseFeeTokenRemoved(log types.Log) (*PriceRegistryFeeTokenRemoved, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*PriceRegistryOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*PriceRegistryOwnershipTransferred, error)
+
+ FilterPriceUpdaterRemoved(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterRemovedIterator, error)
+
+ WatchPriceUpdaterRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address) (event.Subscription, error)
+
+ ParsePriceUpdaterRemoved(log types.Log) (*PriceRegistryPriceUpdaterRemoved, error)
+
+ FilterPriceUpdaterSet(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterSetIterator, error)
+
+ WatchPriceUpdaterSet(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterSet, priceUpdater []common.Address) (event.Subscription, error)
+
+ ParsePriceUpdaterSet(log types.Log) (*PriceRegistryPriceUpdaterSet, error)
+
+ FilterUsdPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryUsdPerTokenUpdatedIterator, error)
+
+ WatchUsdPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerTokenUpdated, token []common.Address) (event.Subscription, error)
+
+ ParseUsdPerTokenUpdated(log types.Log) (*PriceRegistryUsdPerTokenUpdated, error)
+
+ FilterUsdPerUnitGasUpdated(opts *bind.FilterOpts, destChain []uint64) (*PriceRegistryUsdPerUnitGasUpdatedIterator, error)
+
+ WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error)
+
+ ParseUsdPerUnitGasUpdated(log types.Log) (*PriceRegistryUsdPerUnitGasUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/price_registry_1_2_0/price_registry.go b/core/gethwrappers/ccip/generated/price_registry_1_2_0/price_registry.go
new file mode 100644
index 00000000000..64e16bd1dcf
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/price_registry_1_2_0/price_registry.go
@@ -0,0 +1,1693 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package price_registry_1_2_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalTimestampedPackedUint224 struct {
+ Value *big.Int
+ Timestamp uint32
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var PriceRegistryMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"priceUpdaters\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"feeTokens\",\"type\":\"address[]\"},{\"internalType\":\"uint32\",\"name\":\"stalenessThreshold\",\"type\":\"uint32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chain\",\"type\":\"uint64\"}],\"name\":\"ChainNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidStalenessThreshold\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByUpdaterOrOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePassed\",\"type\":\"uint256\"}],\"name\":\"StaleGasPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePassed\",\"type\":\"uint256\"}],\"name\":\"StaleTokenPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenNotSupported\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"FeeTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"FeeTokenRemoved\",\"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\":\"priceUpdater\",\"type\":\"address\"}],\"name\":\"PriceUpdaterRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"priceUpdater\",\"type\":\"address\"}],\"name\":\"PriceUpdaterSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UsdPerTokenUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChain\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UsdPerUnitGasUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"feeTokensToAdd\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"feeTokensToRemove\",\"type\":\"address[]\"}],\"name\":\"applyFeeTokensUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"priceUpdatersToAdd\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"priceUpdatersToRemove\",\"type\":\"address[]\"}],\"name\":\"applyPriceUpdatersUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"fromToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fromTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"toToken\",\"type\":\"address\"}],\"name\":\"convertTokenAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getDestinationChainGasPrice\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPriceUpdaters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStalenessThreshold\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getTokenAndGasPrices\",\"outputs\":[{\"internalType\":\"uint224\",\"name\":\"tokenPrice\",\"type\":\"uint224\"},{\"internalType\":\"uint224\",\"name\":\"gasPriceValue\",\"type\":\"uint224\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenPrice\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getTokenPrices\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getValidatedTokenPrice\",\"outputs\":[{\"internalType\":\"uint224\",\"name\":\"\",\"type\":\"uint224\"}],\"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\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"}],\"name\":\"updatePrices\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60a06040523480156200001157600080fd5b506040516200227f3803806200227f8339810160408190526200003491620006fe565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000133565b5050604080516000815260208101909152620000dd91508490620001de565b604080516000815260208101909152620000f99083906200033a565b8063ffffffff166000036200012157604051631151410960e11b815260040160405180910390fd5b63ffffffff1660805250620007fa9050565b336001600160a01b038216036200018d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b825181101562000289576200021d83828151811062000204576200020462000786565b602002602001015160046200049160201b90919060201c565b15620002765782818151811062000238576200023862000786565b60200260200101516001600160a01b03167f34a02290b7920078c19f58e94b78c77eb9cc10195b20676e19bd3b82085893b860405160405180910390a25b6200028181620007b2565b9050620001e1565b5060005b81518110156200033557620002c9828281518110620002b057620002b062000786565b60200260200101516004620004b160201b90919060201c565b156200032257818181518110620002e457620002e462000786565b60200260200101516001600160a01b03167fff7dbb85c77ca68ca1f894d6498570e3d5095cd19466f07ee8d222b337e4068c60405160405180910390a25b6200032d81620007b2565b90506200028d565b505050565b60005b8251811015620003e5576200037983828151811062000360576200036062000786565b602002602001015160066200049160201b90919060201c565b15620003d25782818151811062000394576200039462000786565b60200260200101516001600160a01b03167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b620003dd81620007b2565b90506200033d565b5060005b81518110156200033557620004258282815181106200040c576200040c62000786565b60200260200101516006620004b160201b90919060201c565b156200047e5781818151811062000440576200044062000786565b60200260200101516001600160a01b03167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b6200048981620007b2565b9050620003e9565b6000620004a8836001600160a01b038416620004c8565b90505b92915050565b6000620004a8836001600160a01b0384166200051a565b60008181526001830160205260408120546200051157508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620004ab565b506000620004ab565b600081815260018301602052604081205480156200061357600062000541600183620007ce565b85549091506000906200055790600190620007ce565b9050818114620005c35760008660000182815481106200057b576200057b62000786565b9060005260206000200154905080876000018481548110620005a157620005a162000786565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620005d757620005d7620007e4565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050620004ab565b6000915050620004ab565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200064c57600080fd5b919050565b600082601f8301126200066357600080fd5b815160206001600160401b03808311156200068257620006826200061e565b8260051b604051601f19603f83011681018181108482111715620006aa57620006aa6200061e565b604052938452858101830193838101925087851115620006c957600080fd5b83870191505b84821015620006f357620006e38262000634565b83529183019190830190620006cf565b979650505050505050565b6000806000606084860312156200071457600080fd5b83516001600160401b03808211156200072c57600080fd5b6200073a8783880162000651565b945060208601519150808211156200075157600080fd5b50620007608682870162000651565b925050604084015163ffffffff811681146200077b57600080fd5b809150509250925092565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620007c757620007c76200079c565b5060010190565b81810381811115620004ab57620004ab6200079c565b634e487b7160e01b600052603160045260246000fd5b608051611a4d62000832600039600081816102eb01528181610acd01528181610b3601528181610c970152610d0c0152611a4d6000f3fe608060405234801561001057600080fd5b50600436106100ff5760003560e01c80637afac32211610097578063cdc73d5111610066578063cdc73d511461032a578063d02641a014610332578063f2fde38b146103d4578063ffdb4b37146103e757600080fd5b80637afac322146102a65780638da5cb5b146102b9578063a6c94a73146102e1578063bfcd45661461031557600080fd5b80634ab35b0b116100d35780634ab35b0b146101a8578063514e8cff146101e857806352877af01461028b57806379ba50971461029e57600080fd5b806241e5be14610104578063181f5a771461012a5780633937306f1461017357806345ac924d14610188575b600080fd5b6101176101123660046113bd565b61042f565b6040519081526020015b60405180910390f35b6101666040518060400160405280601381526020017f5072696365526567697374727920312e322e300000000000000000000000000081525081565b60405161012191906113f9565b610186610181366004611465565b61049b565b005b61019b6101963660046114a0565b6107bf565b6040516101219190611515565b6101bb6101b6366004611590565b610893565b6040517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b61027e6101f63660046115c3565b60408051808201909152600080825260208201525067ffffffffffffffff166000908152600260209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811683527c0100000000000000000000000000000000000000000000000000000000900463ffffffff169082015290565b60405161012191906115de565b610186610299366004611731565b61089e565b6101866108b4565b6101866102b4366004611731565b6109b6565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610121565b60405163ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610121565b61031d6109c8565b6040516101219190611795565b61031d6109d9565b61027e610340366004611590565b60408051808201909152600080825260208201525073ffffffffffffffffffffffffffffffffffffffff166000908152600360209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811683527c0100000000000000000000000000000000000000000000000000000000900463ffffffff169082015290565b6101866103e2366004611590565b6109e5565b6103fa6103f53660046117ef565b6109f9565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610121565b600061043a82610b84565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1661046185610b84565b610489907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1685611851565b6104939190611868565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906104cb57506104c9600433610d48565b155b15610502576040517f46f0815400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061050e82806118a3565b9050905060005b8181101561066057600061052984806118a3565b838181106105395761053961190b565b90506040020180360381019061054f9190611966565b604080518082018252602080840180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff908116845263ffffffff42818116858701908152885173ffffffffffffffffffffffffffffffffffffffff9081166000908152600390975295889020965190519092167c010000000000000000000000000000000000000000000000000000000002919092161790935584519051935194955016927f52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a926106479290917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a250610659816119a3565b9050610515565b50600061067060208401846118a3565b9050905060005b818110156107b957600061068e60208601866118a3565b8381811061069e5761069e61190b565b9050604002018036038101906106b491906119db565b604080518082018252602080840180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff908116845263ffffffff42818116858701908152885167ffffffffffffffff9081166000908152600290975295889020965190519092167c010000000000000000000000000000000000000000000000000000000002919092161790935584519051935194955016927fdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e926107a09290917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a2506107b2816119a3565b9050610677565b50505050565b60608160008167ffffffffffffffff8111156107dd576107dd611619565b60405190808252806020026020018201604052801561082257816020015b60408051808201909152600080825260208201528152602001906001900390816107fb5790505b50905060005b828110156108885761085a8686838181106108455761084561190b565b90506020020160208101906103409190611590565b82828151811061086c5761086c61190b565b602002602001018190525080610881906119a3565b9050610828565b509150505b92915050565b600061088d82610b84565b6108a6610d7a565b6108b08282610dfd565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461093a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6109be610d7a565b6108b08282610f59565b60606109d460046110b0565b905090565b60606109d460066110b0565b6109ed610d7a565b6109f6816110bd565b50565b67ffffffffffffffff811660009081526002602090815260408083208151808301909252547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811682527c0100000000000000000000000000000000000000000000000000000000900463ffffffff1691810182905282918203610ab1576040517f2e59db3a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff85166004820152602401610931565b6000816020015163ffffffff1642610ac991906119fe565b90507f000000000000000000000000000000000000000000000000000000000000000063ffffffff16811115610b6a576040517ff08bcb3e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8616600482015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260448101829052606401610931565b610b7386610b84565b9151919350909150505b9250929050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526003602090815260408083208151808301909252547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811682527c0100000000000000000000000000000000000000000000000000000000900463ffffffff16918101829052901580610c2c575080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16155b15610c7b576040517f06439c6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610931565b6000816020015163ffffffff1642610c9391906119fe565b90507f000000000000000000000000000000000000000000000000000000000000000063ffffffff16811115610d40576040517fc65fdfca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015263ffffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260448101829052606401610931565b505192915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610dfb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610931565b565b60005b8251811015610ea857610e36838281518110610e1e57610e1e61190b565b602002602001015160046111b290919063ffffffff16565b15610e9857828181518110610e4d57610e4d61190b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f34a02290b7920078c19f58e94b78c77eb9cc10195b20676e19bd3b82085893b860405160405180910390a25b610ea1816119a3565b9050610e00565b5060005b8151811015610f5457610ee2828281518110610eca57610eca61190b565b602002602001015160046111d490919063ffffffff16565b15610f4457818181518110610ef957610ef961190b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167fff7dbb85c77ca68ca1f894d6498570e3d5095cd19466f07ee8d222b337e4068c60405160405180910390a25b610f4d816119a3565b9050610eac565b505050565b60005b825181101561100457610f92838281518110610f7a57610f7a61190b565b602002602001015160066111b290919063ffffffff16565b15610ff457828181518110610fa957610fa961190b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b610ffd816119a3565b9050610f5c565b5060005b8151811015610f545761103e8282815181106110265761102661190b565b602002602001015160066111d490919063ffffffff16565b156110a0578181815181106110555761105561190b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b6110a9816119a3565b9050611008565b60606000610d73836111f6565b3373ffffffffffffffffffffffffffffffffffffffff82160361113c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610931565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000610d738373ffffffffffffffffffffffffffffffffffffffff8416611252565b6000610d738373ffffffffffffffffffffffffffffffffffffffff84166112a1565b60608160000180548060200260200160405190810160405280929190818152602001828054801561124657602002820191906000526020600020905b815481526020019060010190808311611232575b50505050509050919050565b60008181526001830160205260408120546112995750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561088d565b50600061088d565b6000818152600183016020526040812054801561138a5760006112c56001836119fe565b85549091506000906112d9906001906119fe565b905081811461133e5760008660000182815481106112f9576112f961190b565b906000526020600020015490508087600001848154811061131c5761131c61190b565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061134f5761134f611a11565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061088d565b600091505061088d565b803573ffffffffffffffffffffffffffffffffffffffff811681146113b857600080fd5b919050565b6000806000606084860312156113d257600080fd5b6113db84611394565b9250602084013591506113f060408501611394565b90509250925092565b600060208083528351808285015260005b818110156114265785810183015185820160400152820161140a565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60006020828403121561147757600080fd5b813567ffffffffffffffff81111561148e57600080fd5b820160408185031215610d7357600080fd5b600080602083850312156114b357600080fd5b823567ffffffffffffffff808211156114cb57600080fd5b818501915085601f8301126114df57600080fd5b8135818111156114ee57600080fd5b8660208260051b850101111561150357600080fd5b60209290920196919550909350505050565b602080825282518282018190526000919060409081850190868401855b828110156115835761157384835180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16825260209081015163ffffffff16910152565b9284019290850190600101611532565b5091979650505050505050565b6000602082840312156115a257600080fd5b610d7382611394565b803567ffffffffffffffff811681146113b857600080fd5b6000602082840312156115d557600080fd5b610d73826115ab565b81517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815260208083015163ffffffff16908201526040810161088d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561166b5761166b611619565b60405290565b600082601f83011261168257600080fd5b8135602067ffffffffffffffff8083111561169f5761169f611619565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811084821117156116e2576116e2611619565b60405293845285810183019383810192508785111561170057600080fd5b83870191505b848210156117265761171782611394565b83529183019190830190611706565b979650505050505050565b6000806040838503121561174457600080fd5b823567ffffffffffffffff8082111561175c57600080fd5b61176886838701611671565b9350602085013591508082111561177e57600080fd5b5061178b85828601611671565b9150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156117e357835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016117b1565b50909695505050505050565b6000806040838503121561180257600080fd5b61180b83611394565b9150611819602084016115ab565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761088d5761088d611822565b60008261189e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126118d857600080fd5b83018035915067ffffffffffffffff8211156118f357600080fd5b6020019150600681901b3603821315610b7d57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146113b857600080fd5b60006040828403121561197857600080fd5b611980611648565b61198983611394565b81526119976020840161193a565b60208201529392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036119d4576119d4611822565b5060010190565b6000604082840312156119ed57600080fd5b6119f5611648565b611989836115ab565b8181038181111561088d5761088d611822565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a",
+}
+
+var PriceRegistryABI = PriceRegistryMetaData.ABI
+
+var PriceRegistryBin = PriceRegistryMetaData.Bin
+
+func DeployPriceRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, priceUpdaters []common.Address, feeTokens []common.Address, stalenessThreshold uint32) (common.Address, *types.Transaction, *PriceRegistry, error) {
+ parsed, err := PriceRegistryMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(PriceRegistryBin), backend, priceUpdaters, feeTokens, stalenessThreshold)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &PriceRegistry{address: address, abi: *parsed, PriceRegistryCaller: PriceRegistryCaller{contract: contract}, PriceRegistryTransactor: PriceRegistryTransactor{contract: contract}, PriceRegistryFilterer: PriceRegistryFilterer{contract: contract}}, nil
+}
+
+type PriceRegistry struct {
+ address common.Address
+ abi abi.ABI
+ PriceRegistryCaller
+ PriceRegistryTransactor
+ PriceRegistryFilterer
+}
+
+type PriceRegistryCaller struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistryTransactor struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistryFilterer struct {
+ contract *bind.BoundContract
+}
+
+type PriceRegistrySession struct {
+ Contract *PriceRegistry
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type PriceRegistryCallerSession struct {
+ Contract *PriceRegistryCaller
+ CallOpts bind.CallOpts
+}
+
+type PriceRegistryTransactorSession struct {
+ Contract *PriceRegistryTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type PriceRegistryRaw struct {
+ Contract *PriceRegistry
+}
+
+type PriceRegistryCallerRaw struct {
+ Contract *PriceRegistryCaller
+}
+
+type PriceRegistryTransactorRaw struct {
+ Contract *PriceRegistryTransactor
+}
+
+func NewPriceRegistry(address common.Address, backend bind.ContractBackend) (*PriceRegistry, error) {
+ abi, err := abi.JSON(strings.NewReader(PriceRegistryABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindPriceRegistry(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistry{address: address, abi: abi, PriceRegistryCaller: PriceRegistryCaller{contract: contract}, PriceRegistryTransactor: PriceRegistryTransactor{contract: contract}, PriceRegistryFilterer: PriceRegistryFilterer{contract: contract}}, nil
+}
+
+func NewPriceRegistryCaller(address common.Address, caller bind.ContractCaller) (*PriceRegistryCaller, error) {
+ contract, err := bindPriceRegistry(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryCaller{contract: contract}, nil
+}
+
+func NewPriceRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*PriceRegistryTransactor, error) {
+ contract, err := bindPriceRegistry(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryTransactor{contract: contract}, nil
+}
+
+func NewPriceRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*PriceRegistryFilterer, error) {
+ contract, err := bindPriceRegistry(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFilterer{contract: contract}, nil
+}
+
+func bindPriceRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := PriceRegistryMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _PriceRegistry.Contract.PriceRegistryCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.PriceRegistryTransactor.contract.Transfer(opts)
+}
+
+func (_PriceRegistry *PriceRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.PriceRegistryTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _PriceRegistry.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.contract.Transfer(opts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) ConvertTokenAmount(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "convertTokenAmount", fromToken, fromTokenAmount, toToken)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) ConvertTokenAmount(fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.ConvertTokenAmount(&_PriceRegistry.CallOpts, fromToken, fromTokenAmount, toToken)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) ConvertTokenAmount(fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.ConvertTokenAmount(&_PriceRegistry.CallOpts, fromToken, fromTokenAmount, toToken)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetDestinationChainGasPrice(opts *bind.CallOpts, destChainSelector uint64) (InternalTimestampedPackedUint224, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getDestinationChainGasPrice", destChainSelector)
+
+ if err != nil {
+ return *new(InternalTimestampedPackedUint224), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(InternalTimestampedPackedUint224)).(*InternalTimestampedPackedUint224)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetDestinationChainGasPrice(destChainSelector uint64) (InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetDestinationChainGasPrice(&_PriceRegistry.CallOpts, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetDestinationChainGasPrice(destChainSelector uint64) (InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetDestinationChainGasPrice(&_PriceRegistry.CallOpts, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetFeeTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getFeeTokens")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetFeeTokens() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetFeeTokens(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetFeeTokens() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetFeeTokens(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetPriceUpdaters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getPriceUpdaters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetPriceUpdaters() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetPriceUpdaters(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetPriceUpdaters() ([]common.Address, error) {
+ return _PriceRegistry.Contract.GetPriceUpdaters(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetStalenessThreshold(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getStalenessThreshold")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetStalenessThreshold() (*big.Int, error) {
+ return _PriceRegistry.Contract.GetStalenessThreshold(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetStalenessThreshold() (*big.Int, error) {
+ return _PriceRegistry.Contract.GetStalenessThreshold(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenAndGasPrices(opts *bind.CallOpts, token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenAndGasPrices", token, destChainSelector)
+
+ outstruct := new(GetTokenAndGasPrices)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.TokenPrice = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+ outstruct.GasPriceValue = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenAndGasPrices(token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ return _PriceRegistry.Contract.GetTokenAndGasPrices(&_PriceRegistry.CallOpts, token, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenAndGasPrices(token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error) {
+ return _PriceRegistry.Contract.GetTokenAndGasPrices(&_PriceRegistry.CallOpts, token, destChainSelector)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenPrice(opts *bind.CallOpts, token common.Address) (InternalTimestampedPackedUint224, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenPrice", token)
+
+ if err != nil {
+ return *new(InternalTimestampedPackedUint224), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(InternalTimestampedPackedUint224)).(*InternalTimestampedPackedUint224)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenPrice(token common.Address) (InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenPrice(token common.Address) (InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetTokenPrices(opts *bind.CallOpts, tokens []common.Address) ([]InternalTimestampedPackedUint224, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getTokenPrices", tokens)
+
+ if err != nil {
+ return *new([]InternalTimestampedPackedUint224), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]InternalTimestampedPackedUint224)).(*[]InternalTimestampedPackedUint224)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetTokenPrices(tokens []common.Address) ([]InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetTokenPrices(&_PriceRegistry.CallOpts, tokens)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetTokenPrices(tokens []common.Address) ([]InternalTimestampedPackedUint224, error) {
+ return _PriceRegistry.Contract.GetTokenPrices(&_PriceRegistry.CallOpts, tokens)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) GetValidatedTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "getValidatedTokenPrice", token)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) GetValidatedTokenPrice(token common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.GetValidatedTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) GetValidatedTokenPrice(token common.Address) (*big.Int, error) {
+ return _PriceRegistry.Contract.GetValidatedTokenPrice(&_PriceRegistry.CallOpts, token)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) Owner() (common.Address, error) {
+ return _PriceRegistry.Contract.Owner(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) Owner() (common.Address, error) {
+ return _PriceRegistry.Contract.Owner(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _PriceRegistry.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_PriceRegistry *PriceRegistrySession) TypeAndVersion() (string, error) {
+ return _PriceRegistry.Contract.TypeAndVersion(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryCallerSession) TypeAndVersion() (string, error) {
+ return _PriceRegistry.Contract.TypeAndVersion(&_PriceRegistry.CallOpts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_PriceRegistry *PriceRegistrySession) AcceptOwnership() (*types.Transaction, error) {
+ return _PriceRegistry.Contract.AcceptOwnership(&_PriceRegistry.TransactOpts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _PriceRegistry.Contract.AcceptOwnership(&_PriceRegistry.TransactOpts)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyFeeTokensUpdates(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyFeeTokensUpdates", feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyFeeTokensUpdates(feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyFeeTokensUpdates(&_PriceRegistry.TransactOpts, feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyFeeTokensUpdates(feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyFeeTokensUpdates(&_PriceRegistry.TransactOpts, feeTokensToAdd, feeTokensToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) ApplyPriceUpdatersUpdates(opts *bind.TransactOpts, priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "applyPriceUpdatersUpdates", priceUpdatersToAdd, priceUpdatersToRemove)
+}
+
+func (_PriceRegistry *PriceRegistrySession) ApplyPriceUpdatersUpdates(priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyPriceUpdatersUpdates(&_PriceRegistry.TransactOpts, priceUpdatersToAdd, priceUpdatersToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) ApplyPriceUpdatersUpdates(priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.ApplyPriceUpdatersUpdates(&_PriceRegistry.TransactOpts, priceUpdatersToAdd, priceUpdatersToRemove)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_PriceRegistry *PriceRegistrySession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.TransferOwnership(&_PriceRegistry.TransactOpts, to)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.TransferOwnership(&_PriceRegistry.TransactOpts, to)
+}
+
+func (_PriceRegistry *PriceRegistryTransactor) UpdatePrices(opts *bind.TransactOpts, priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.contract.Transact(opts, "updatePrices", priceUpdates)
+}
+
+func (_PriceRegistry *PriceRegistrySession) UpdatePrices(priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.UpdatePrices(&_PriceRegistry.TransactOpts, priceUpdates)
+}
+
+func (_PriceRegistry *PriceRegistryTransactorSession) UpdatePrices(priceUpdates InternalPriceUpdates) (*types.Transaction, error) {
+ return _PriceRegistry.Contract.UpdatePrices(&_PriceRegistry.TransactOpts, priceUpdates)
+}
+
+type PriceRegistryFeeTokenAddedIterator struct {
+ Event *PriceRegistryFeeTokenAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryFeeTokenAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryFeeTokenAdded)
+ 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(PriceRegistryFeeTokenAdded)
+ 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 *PriceRegistryFeeTokenAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryFeeTokenAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryFeeTokenAdded struct {
+ FeeToken common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterFeeTokenAdded(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenAddedIterator, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "FeeTokenAdded", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFeeTokenAddedIterator{contract: _PriceRegistry.contract, event: "FeeTokenAdded", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchFeeTokenAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenAdded, feeToken []common.Address) (event.Subscription, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "FeeTokenAdded", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryFeeTokenAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenAdded", 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 (_PriceRegistry *PriceRegistryFilterer) ParseFeeTokenAdded(log types.Log) (*PriceRegistryFeeTokenAdded, error) {
+ event := new(PriceRegistryFeeTokenAdded)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryFeeTokenRemovedIterator struct {
+ Event *PriceRegistryFeeTokenRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryFeeTokenRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryFeeTokenRemoved)
+ 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(PriceRegistryFeeTokenRemoved)
+ 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 *PriceRegistryFeeTokenRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryFeeTokenRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryFeeTokenRemoved struct {
+ FeeToken common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterFeeTokenRemoved(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenRemovedIterator, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "FeeTokenRemoved", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryFeeTokenRemovedIterator{contract: _PriceRegistry.contract, event: "FeeTokenRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchFeeTokenRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenRemoved, feeToken []common.Address) (event.Subscription, error) {
+
+ var feeTokenRule []interface{}
+ for _, feeTokenItem := range feeToken {
+ feeTokenRule = append(feeTokenRule, feeTokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "FeeTokenRemoved", feeTokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryFeeTokenRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenRemoved", 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 (_PriceRegistry *PriceRegistryFilterer) ParseFeeTokenRemoved(log types.Log) (*PriceRegistryFeeTokenRemoved, error) {
+ event := new(PriceRegistryFeeTokenRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "FeeTokenRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryOwnershipTransferRequestedIterator struct {
+ Event *PriceRegistryOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryOwnershipTransferRequested)
+ 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(PriceRegistryOwnershipTransferRequested)
+ 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 *PriceRegistryOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryOwnershipTransferRequestedIterator{contract: _PriceRegistry.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryOwnershipTransferRequested)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_PriceRegistry *PriceRegistryFilterer) ParseOwnershipTransferRequested(log types.Log) (*PriceRegistryOwnershipTransferRequested, error) {
+ event := new(PriceRegistryOwnershipTransferRequested)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryOwnershipTransferredIterator struct {
+ Event *PriceRegistryOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryOwnershipTransferred)
+ 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(PriceRegistryOwnershipTransferred)
+ 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 *PriceRegistryOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryOwnershipTransferredIterator{contract: _PriceRegistry.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryOwnershipTransferred)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferred", 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 (_PriceRegistry *PriceRegistryFilterer) ParseOwnershipTransferred(log types.Log) (*PriceRegistryOwnershipTransferred, error) {
+ event := new(PriceRegistryOwnershipTransferred)
+ if err := _PriceRegistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryPriceUpdaterRemovedIterator struct {
+ Event *PriceRegistryPriceUpdaterRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryPriceUpdaterRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryPriceUpdaterRemoved)
+ 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(PriceRegistryPriceUpdaterRemoved)
+ 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 *PriceRegistryPriceUpdaterRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryPriceUpdaterRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryPriceUpdaterRemoved struct {
+ PriceUpdater common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterPriceUpdaterRemoved(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterRemovedIterator, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "PriceUpdaterRemoved", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryPriceUpdaterRemovedIterator{contract: _PriceRegistry.contract, event: "PriceUpdaterRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchPriceUpdaterRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address) (event.Subscription, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "PriceUpdaterRemoved", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryPriceUpdaterRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterRemoved", 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 (_PriceRegistry *PriceRegistryFilterer) ParsePriceUpdaterRemoved(log types.Log) (*PriceRegistryPriceUpdaterRemoved, error) {
+ event := new(PriceRegistryPriceUpdaterRemoved)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryPriceUpdaterSetIterator struct {
+ Event *PriceRegistryPriceUpdaterSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryPriceUpdaterSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryPriceUpdaterSet)
+ 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(PriceRegistryPriceUpdaterSet)
+ 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 *PriceRegistryPriceUpdaterSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryPriceUpdaterSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryPriceUpdaterSet struct {
+ PriceUpdater common.Address
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterPriceUpdaterSet(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterSetIterator, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "PriceUpdaterSet", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryPriceUpdaterSetIterator{contract: _PriceRegistry.contract, event: "PriceUpdaterSet", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchPriceUpdaterSet(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterSet, priceUpdater []common.Address) (event.Subscription, error) {
+
+ var priceUpdaterRule []interface{}
+ for _, priceUpdaterItem := range priceUpdater {
+ priceUpdaterRule = append(priceUpdaterRule, priceUpdaterItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "PriceUpdaterSet", priceUpdaterRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryPriceUpdaterSet)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterSet", 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 (_PriceRegistry *PriceRegistryFilterer) ParsePriceUpdaterSet(log types.Log) (*PriceRegistryPriceUpdaterSet, error) {
+ event := new(PriceRegistryPriceUpdaterSet)
+ if err := _PriceRegistry.contract.UnpackLog(event, "PriceUpdaterSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryUsdPerTokenUpdatedIterator struct {
+ Event *PriceRegistryUsdPerTokenUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryUsdPerTokenUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryUsdPerTokenUpdated)
+ 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(PriceRegistryUsdPerTokenUpdated)
+ 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 *PriceRegistryUsdPerTokenUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryUsdPerTokenUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryUsdPerTokenUpdated struct {
+ Token common.Address
+ Value *big.Int
+ Timestamp *big.Int
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterUsdPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryUsdPerTokenUpdatedIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "UsdPerTokenUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryUsdPerTokenUpdatedIterator{contract: _PriceRegistry.contract, event: "UsdPerTokenUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchUsdPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerTokenUpdated, token []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "UsdPerTokenUpdated", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryUsdPerTokenUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerTokenUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParseUsdPerTokenUpdated(log types.Log) (*PriceRegistryUsdPerTokenUpdated, error) {
+ event := new(PriceRegistryUsdPerTokenUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerTokenUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type PriceRegistryUsdPerUnitGasUpdatedIterator struct {
+ Event *PriceRegistryUsdPerUnitGasUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *PriceRegistryUsdPerUnitGasUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(PriceRegistryUsdPerUnitGasUpdated)
+ 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(PriceRegistryUsdPerUnitGasUpdated)
+ 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 *PriceRegistryUsdPerUnitGasUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *PriceRegistryUsdPerUnitGasUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type PriceRegistryUsdPerUnitGasUpdated struct {
+ DestChain uint64
+ Value *big.Int
+ Timestamp *big.Int
+ Raw types.Log
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) FilterUsdPerUnitGasUpdated(opts *bind.FilterOpts, destChain []uint64) (*PriceRegistryUsdPerUnitGasUpdatedIterator, error) {
+
+ var destChainRule []interface{}
+ for _, destChainItem := range destChain {
+ destChainRule = append(destChainRule, destChainItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.FilterLogs(opts, "UsdPerUnitGasUpdated", destChainRule)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistryUsdPerUnitGasUpdatedIterator{contract: _PriceRegistry.contract, event: "UsdPerUnitGasUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_PriceRegistry *PriceRegistryFilterer) WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error) {
+
+ var destChainRule []interface{}
+ for _, destChainItem := range destChain {
+ destChainRule = append(destChainRule, destChainItem)
+ }
+
+ logs, sub, err := _PriceRegistry.contract.WatchLogs(opts, "UsdPerUnitGasUpdated", destChainRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(PriceRegistryUsdPerUnitGasUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerUnitGasUpdated", 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 (_PriceRegistry *PriceRegistryFilterer) ParseUsdPerUnitGasUpdated(log types.Log) (*PriceRegistryUsdPerUnitGasUpdated, error) {
+ event := new(PriceRegistryUsdPerUnitGasUpdated)
+ if err := _PriceRegistry.contract.UnpackLog(event, "UsdPerUnitGasUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetTokenAndGasPrices struct {
+ TokenPrice *big.Int
+ GasPriceValue *big.Int
+}
+
+func (_PriceRegistry *PriceRegistry) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _PriceRegistry.abi.Events["FeeTokenAdded"].ID:
+ return _PriceRegistry.ParseFeeTokenAdded(log)
+ case _PriceRegistry.abi.Events["FeeTokenRemoved"].ID:
+ return _PriceRegistry.ParseFeeTokenRemoved(log)
+ case _PriceRegistry.abi.Events["OwnershipTransferRequested"].ID:
+ return _PriceRegistry.ParseOwnershipTransferRequested(log)
+ case _PriceRegistry.abi.Events["OwnershipTransferred"].ID:
+ return _PriceRegistry.ParseOwnershipTransferred(log)
+ case _PriceRegistry.abi.Events["PriceUpdaterRemoved"].ID:
+ return _PriceRegistry.ParsePriceUpdaterRemoved(log)
+ case _PriceRegistry.abi.Events["PriceUpdaterSet"].ID:
+ return _PriceRegistry.ParsePriceUpdaterSet(log)
+ case _PriceRegistry.abi.Events["UsdPerTokenUpdated"].ID:
+ return _PriceRegistry.ParseUsdPerTokenUpdated(log)
+ case _PriceRegistry.abi.Events["UsdPerUnitGasUpdated"].ID:
+ return _PriceRegistry.ParseUsdPerUnitGasUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (PriceRegistryFeeTokenAdded) Topic() common.Hash {
+ return common.HexToHash("0xdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba23")
+}
+
+func (PriceRegistryFeeTokenRemoved) Topic() common.Hash {
+ return common.HexToHash("0x1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f91")
+}
+
+func (PriceRegistryOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (PriceRegistryOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (PriceRegistryPriceUpdaterRemoved) Topic() common.Hash {
+ return common.HexToHash("0xff7dbb85c77ca68ca1f894d6498570e3d5095cd19466f07ee8d222b337e4068c")
+}
+
+func (PriceRegistryPriceUpdaterSet) Topic() common.Hash {
+ return common.HexToHash("0x34a02290b7920078c19f58e94b78c77eb9cc10195b20676e19bd3b82085893b8")
+}
+
+func (PriceRegistryUsdPerTokenUpdated) Topic() common.Hash {
+ return common.HexToHash("0x52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a")
+}
+
+func (PriceRegistryUsdPerUnitGasUpdated) Topic() common.Hash {
+ return common.HexToHash("0xdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e")
+}
+
+func (_PriceRegistry *PriceRegistry) Address() common.Address {
+ return _PriceRegistry.address
+}
+
+type PriceRegistryInterface interface {
+ ConvertTokenAmount(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error)
+
+ GetDestinationChainGasPrice(opts *bind.CallOpts, destChainSelector uint64) (InternalTimestampedPackedUint224, error)
+
+ GetFeeTokens(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetPriceUpdaters(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetStalenessThreshold(opts *bind.CallOpts) (*big.Int, error)
+
+ GetTokenAndGasPrices(opts *bind.CallOpts, token common.Address, destChainSelector uint64) (GetTokenAndGasPrices,
+
+ error)
+
+ GetTokenPrice(opts *bind.CallOpts, token common.Address) (InternalTimestampedPackedUint224, error)
+
+ GetTokenPrices(opts *bind.CallOpts, tokens []common.Address) ([]InternalTimestampedPackedUint224, error)
+
+ GetValidatedTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyFeeTokensUpdates(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error)
+
+ ApplyPriceUpdatersUpdates(opts *bind.TransactOpts, priceUpdatersToAdd []common.Address, priceUpdatersToRemove []common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ UpdatePrices(opts *bind.TransactOpts, priceUpdates InternalPriceUpdates) (*types.Transaction, error)
+
+ FilterFeeTokenAdded(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenAddedIterator, error)
+
+ WatchFeeTokenAdded(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenAdded, feeToken []common.Address) (event.Subscription, error)
+
+ ParseFeeTokenAdded(log types.Log) (*PriceRegistryFeeTokenAdded, error)
+
+ FilterFeeTokenRemoved(opts *bind.FilterOpts, feeToken []common.Address) (*PriceRegistryFeeTokenRemovedIterator, error)
+
+ WatchFeeTokenRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryFeeTokenRemoved, feeToken []common.Address) (event.Subscription, error)
+
+ ParseFeeTokenRemoved(log types.Log) (*PriceRegistryFeeTokenRemoved, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*PriceRegistryOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*PriceRegistryOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*PriceRegistryOwnershipTransferred, error)
+
+ FilterPriceUpdaterRemoved(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterRemovedIterator, error)
+
+ WatchPriceUpdaterRemoved(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address) (event.Subscription, error)
+
+ ParsePriceUpdaterRemoved(log types.Log) (*PriceRegistryPriceUpdaterRemoved, error)
+
+ FilterPriceUpdaterSet(opts *bind.FilterOpts, priceUpdater []common.Address) (*PriceRegistryPriceUpdaterSetIterator, error)
+
+ WatchPriceUpdaterSet(opts *bind.WatchOpts, sink chan<- *PriceRegistryPriceUpdaterSet, priceUpdater []common.Address) (event.Subscription, error)
+
+ ParsePriceUpdaterSet(log types.Log) (*PriceRegistryPriceUpdaterSet, error)
+
+ FilterUsdPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*PriceRegistryUsdPerTokenUpdatedIterator, error)
+
+ WatchUsdPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerTokenUpdated, token []common.Address) (event.Subscription, error)
+
+ ParseUsdPerTokenUpdated(log types.Log) (*PriceRegistryUsdPerTokenUpdated, error)
+
+ FilterUsdPerUnitGasUpdated(opts *bind.FilterOpts, destChain []uint64) (*PriceRegistryUsdPerUnitGasUpdatedIterator, error)
+
+ WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, sink chan<- *PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error)
+
+ ParseUsdPerUnitGasUpdated(log types.Log) (*PriceRegistryUsdPerUnitGasUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
\ No newline at end of file
diff --git a/core/gethwrappers/ccip/generated/registry_module_owner_custom/registry_module_owner_custom.go b/core/gethwrappers/ccip/generated/registry_module_owner_custom/registry_module_owner_custom.go
new file mode 100644
index 00000000000..bab8100d6f8
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/registry_module_owner_custom/registry_module_owner_custom.go
@@ -0,0 +1,390 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package registry_module_owner_custom
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var RegistryModuleOwnerCustomMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenAdminRegistry\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AddressZero\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"CanOnlySelfRegister\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"administrator\",\"type\":\"address\"}],\"name\":\"AdministratorRegistered\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerAdminViaGetCCIPAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"registerAdminViaOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x60a060405234801561001057600080fd5b5060405161048938038061048983398101604081905261002f91610067565b6001600160a01b03811661005657604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b0316608052610097565b60006020828403121561007957600080fd5b81516001600160a01b038116811461009057600080fd5b9392505050565b6080516103d76100b2600039600061023201526103d76000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063181f5a771461004657806396ea2f7a14610064578063ff12c35414610079575b600080fd5b61004e61008c565b60405161005b91906102d7565b60405180910390f35b610077610072366004610366565b6100a8565b005b610077610087366004610366565b610123565b6040518060600160405280602381526020016103a86023913981565b610120818273ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061011b919061038a565b610172565b50565b610120818273ffffffffffffffffffffffffffffffffffffffff16638fd6a6ac6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100f7573d6000803e3d6000fd5b73ffffffffffffffffffffffffffffffffffffffff811633146101e5576040517fc454d18200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80831660048301528316602482015260440160405180910390fd5b6040517fe677ae3700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff838116600483015282811660248301527f0000000000000000000000000000000000000000000000000000000000000000169063e677ae3790604401600060405180830381600087803b15801561027657600080fd5b505af115801561028a573d6000803e3d6000fd5b505060405173ffffffffffffffffffffffffffffffffffffffff8085169350851691507f09590fb70af4b833346363965e043a9339e8c7d378b8a2b903c75c277faec4f990600090a35050565b60006020808352835180602085015260005b81811015610305578581018301518582016040015282016102e9565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b73ffffffffffffffffffffffffffffffffffffffff8116811461012057600080fd5b60006020828403121561037857600080fd5b813561038381610344565b9392505050565b60006020828403121561039c57600080fd5b81516103838161034456fe52656769737472794d6f64756c654f776e6572437573746f6d20312e352e302d646576a164736f6c6343000818000a",
+}
+
+var RegistryModuleOwnerCustomABI = RegistryModuleOwnerCustomMetaData.ABI
+
+var RegistryModuleOwnerCustomBin = RegistryModuleOwnerCustomMetaData.Bin
+
+func DeployRegistryModuleOwnerCustom(auth *bind.TransactOpts, backend bind.ContractBackend, tokenAdminRegistry common.Address) (common.Address, *types.Transaction, *RegistryModuleOwnerCustom, error) {
+ parsed, err := RegistryModuleOwnerCustomMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(RegistryModuleOwnerCustomBin), backend, tokenAdminRegistry)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &RegistryModuleOwnerCustom{address: address, abi: *parsed, RegistryModuleOwnerCustomCaller: RegistryModuleOwnerCustomCaller{contract: contract}, RegistryModuleOwnerCustomTransactor: RegistryModuleOwnerCustomTransactor{contract: contract}, RegistryModuleOwnerCustomFilterer: RegistryModuleOwnerCustomFilterer{contract: contract}}, nil
+}
+
+type RegistryModuleOwnerCustom struct {
+ address common.Address
+ abi abi.ABI
+ RegistryModuleOwnerCustomCaller
+ RegistryModuleOwnerCustomTransactor
+ RegistryModuleOwnerCustomFilterer
+}
+
+type RegistryModuleOwnerCustomCaller struct {
+ contract *bind.BoundContract
+}
+
+type RegistryModuleOwnerCustomTransactor struct {
+ contract *bind.BoundContract
+}
+
+type RegistryModuleOwnerCustomFilterer struct {
+ contract *bind.BoundContract
+}
+
+type RegistryModuleOwnerCustomSession struct {
+ Contract *RegistryModuleOwnerCustom
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type RegistryModuleOwnerCustomCallerSession struct {
+ Contract *RegistryModuleOwnerCustomCaller
+ CallOpts bind.CallOpts
+}
+
+type RegistryModuleOwnerCustomTransactorSession struct {
+ Contract *RegistryModuleOwnerCustomTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type RegistryModuleOwnerCustomRaw struct {
+ Contract *RegistryModuleOwnerCustom
+}
+
+type RegistryModuleOwnerCustomCallerRaw struct {
+ Contract *RegistryModuleOwnerCustomCaller
+}
+
+type RegistryModuleOwnerCustomTransactorRaw struct {
+ Contract *RegistryModuleOwnerCustomTransactor
+}
+
+func NewRegistryModuleOwnerCustom(address common.Address, backend bind.ContractBackend) (*RegistryModuleOwnerCustom, error) {
+ abi, err := abi.JSON(strings.NewReader(RegistryModuleOwnerCustomABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindRegistryModuleOwnerCustom(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &RegistryModuleOwnerCustom{address: address, abi: abi, RegistryModuleOwnerCustomCaller: RegistryModuleOwnerCustomCaller{contract: contract}, RegistryModuleOwnerCustomTransactor: RegistryModuleOwnerCustomTransactor{contract: contract}, RegistryModuleOwnerCustomFilterer: RegistryModuleOwnerCustomFilterer{contract: contract}}, nil
+}
+
+func NewRegistryModuleOwnerCustomCaller(address common.Address, caller bind.ContractCaller) (*RegistryModuleOwnerCustomCaller, error) {
+ contract, err := bindRegistryModuleOwnerCustom(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &RegistryModuleOwnerCustomCaller{contract: contract}, nil
+}
+
+func NewRegistryModuleOwnerCustomTransactor(address common.Address, transactor bind.ContractTransactor) (*RegistryModuleOwnerCustomTransactor, error) {
+ contract, err := bindRegistryModuleOwnerCustom(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &RegistryModuleOwnerCustomTransactor{contract: contract}, nil
+}
+
+func NewRegistryModuleOwnerCustomFilterer(address common.Address, filterer bind.ContractFilterer) (*RegistryModuleOwnerCustomFilterer, error) {
+ contract, err := bindRegistryModuleOwnerCustom(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &RegistryModuleOwnerCustomFilterer{contract: contract}, nil
+}
+
+func bindRegistryModuleOwnerCustom(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := RegistryModuleOwnerCustomMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _RegistryModuleOwnerCustom.Contract.RegistryModuleOwnerCustomCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.Contract.RegistryModuleOwnerCustomTransactor.contract.Transfer(opts)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.Contract.RegistryModuleOwnerCustomTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _RegistryModuleOwnerCustom.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.Contract.contract.Transfer(opts)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _RegistryModuleOwnerCustom.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomSession) TypeAndVersion() (string, error) {
+ return _RegistryModuleOwnerCustom.Contract.TypeAndVersion(&_RegistryModuleOwnerCustom.CallOpts)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomCallerSession) TypeAndVersion() (string, error) {
+ return _RegistryModuleOwnerCustom.Contract.TypeAndVersion(&_RegistryModuleOwnerCustom.CallOpts)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomTransactor) RegisterAdminViaGetCCIPAdmin(opts *bind.TransactOpts, token common.Address) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.contract.Transact(opts, "registerAdminViaGetCCIPAdmin", token)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomSession) RegisterAdminViaGetCCIPAdmin(token common.Address) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.Contract.RegisterAdminViaGetCCIPAdmin(&_RegistryModuleOwnerCustom.TransactOpts, token)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomTransactorSession) RegisterAdminViaGetCCIPAdmin(token common.Address) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.Contract.RegisterAdminViaGetCCIPAdmin(&_RegistryModuleOwnerCustom.TransactOpts, token)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomTransactor) RegisterAdminViaOwner(opts *bind.TransactOpts, token common.Address) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.contract.Transact(opts, "registerAdminViaOwner", token)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomSession) RegisterAdminViaOwner(token common.Address) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.Contract.RegisterAdminViaOwner(&_RegistryModuleOwnerCustom.TransactOpts, token)
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomTransactorSession) RegisterAdminViaOwner(token common.Address) (*types.Transaction, error) {
+ return _RegistryModuleOwnerCustom.Contract.RegisterAdminViaOwner(&_RegistryModuleOwnerCustom.TransactOpts, token)
+}
+
+type RegistryModuleOwnerCustomAdministratorRegisteredIterator struct {
+ Event *RegistryModuleOwnerCustomAdministratorRegistered
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *RegistryModuleOwnerCustomAdministratorRegisteredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(RegistryModuleOwnerCustomAdministratorRegistered)
+ 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(RegistryModuleOwnerCustomAdministratorRegistered)
+ 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 *RegistryModuleOwnerCustomAdministratorRegisteredIterator) Error() error {
+ return it.fail
+}
+
+func (it *RegistryModuleOwnerCustomAdministratorRegisteredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type RegistryModuleOwnerCustomAdministratorRegistered struct {
+ Token common.Address
+ Administrator common.Address
+ Raw types.Log
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomFilterer) FilterAdministratorRegistered(opts *bind.FilterOpts, token []common.Address, administrator []common.Address) (*RegistryModuleOwnerCustomAdministratorRegisteredIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var administratorRule []interface{}
+ for _, administratorItem := range administrator {
+ administratorRule = append(administratorRule, administratorItem)
+ }
+
+ logs, sub, err := _RegistryModuleOwnerCustom.contract.FilterLogs(opts, "AdministratorRegistered", tokenRule, administratorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &RegistryModuleOwnerCustomAdministratorRegisteredIterator{contract: _RegistryModuleOwnerCustom.contract, event: "AdministratorRegistered", logs: logs, sub: sub}, nil
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomFilterer) WatchAdministratorRegistered(opts *bind.WatchOpts, sink chan<- *RegistryModuleOwnerCustomAdministratorRegistered, token []common.Address, administrator []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var administratorRule []interface{}
+ for _, administratorItem := range administrator {
+ administratorRule = append(administratorRule, administratorItem)
+ }
+
+ logs, sub, err := _RegistryModuleOwnerCustom.contract.WatchLogs(opts, "AdministratorRegistered", tokenRule, administratorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(RegistryModuleOwnerCustomAdministratorRegistered)
+ if err := _RegistryModuleOwnerCustom.contract.UnpackLog(event, "AdministratorRegistered", 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 (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustomFilterer) ParseAdministratorRegistered(log types.Log) (*RegistryModuleOwnerCustomAdministratorRegistered, error) {
+ event := new(RegistryModuleOwnerCustomAdministratorRegistered)
+ if err := _RegistryModuleOwnerCustom.contract.UnpackLog(event, "AdministratorRegistered", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustom) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _RegistryModuleOwnerCustom.abi.Events["AdministratorRegistered"].ID:
+ return _RegistryModuleOwnerCustom.ParseAdministratorRegistered(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (RegistryModuleOwnerCustomAdministratorRegistered) Topic() common.Hash {
+ return common.HexToHash("0x09590fb70af4b833346363965e043a9339e8c7d378b8a2b903c75c277faec4f9")
+}
+
+func (_RegistryModuleOwnerCustom *RegistryModuleOwnerCustom) Address() common.Address {
+ return _RegistryModuleOwnerCustom.address
+}
+
+type RegistryModuleOwnerCustomInterface interface {
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ RegisterAdminViaGetCCIPAdmin(opts *bind.TransactOpts, token common.Address) (*types.Transaction, error)
+
+ RegisterAdminViaOwner(opts *bind.TransactOpts, token common.Address) (*types.Transaction, error)
+
+ FilterAdministratorRegistered(opts *bind.FilterOpts, token []common.Address, administrator []common.Address) (*RegistryModuleOwnerCustomAdministratorRegisteredIterator, error)
+
+ WatchAdministratorRegistered(opts *bind.WatchOpts, sink chan<- *RegistryModuleOwnerCustomAdministratorRegistered, token []common.Address, administrator []common.Address) (event.Subscription, error)
+
+ ParseAdministratorRegistered(log types.Log) (*RegistryModuleOwnerCustomAdministratorRegistered, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/report_codec/report_codec.go b/core/gethwrappers/ccip/generated/report_codec/report_codec.go
new file mode 100644
index 00000000000..1648ea9ba51
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/report_codec/report_codec.go
@@ -0,0 +1,559 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package report_codec
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type EVM2EVMMultiOffRampCommitReport struct {
+ PriceUpdates InternalPriceUpdates
+ MerkleRoots []EVM2EVMMultiOffRampMerkleRoot
+}
+
+type EVM2EVMMultiOffRampInterval struct {
+ Min uint64
+ Max uint64
+}
+
+type EVM2EVMMultiOffRampMerkleRoot struct {
+ SourceChainSelector uint64
+ Interval EVM2EVMMultiOffRampInterval
+ MerkleRoot [32]byte
+}
+
+type InternalAny2EVMRampMessage struct {
+ Header InternalRampMessageHeader
+ Sender []byte
+ Data []byte
+ Receiver common.Address
+ GasLimit *big.Int
+ TokenAmounts []InternalRampTokenAmount
+}
+
+type InternalExecutionReportSingleChain struct {
+ SourceChainSelector uint64
+ Messages []InternalAny2EVMRampMessage
+ OffchainTokenData [][][]byte
+ Proofs [][32]byte
+ ProofFlagBits *big.Int
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalPriceUpdates struct {
+ TokenPriceUpdates []InternalTokenPriceUpdate
+ GasPriceUpdates []InternalGasPriceUpdate
+}
+
+type InternalRampMessageHeader struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ DestChainSelector uint64
+ SequenceNumber uint64
+ Nonce uint64
+}
+
+type InternalRampTokenAmount struct {
+ SourcePoolAddress []byte
+ DestTokenAddress []byte
+ ExtraData []byte
+ Amount *big.Int
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+var ReportCodecMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.MerkleRoot[]\",\"name\":\"merkleRoots\",\"type\":\"tuple[]\"}],\"indexed\":false,\"internalType\":\"structEVM2EVMMultiOffRamp.CommitReport\",\"name\":\"report\",\"type\":\"tuple\"}],\"name\":\"CommitReportDecoded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.Any2EVMRampMessage[]\",\"name\":\"messages\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[][]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[][]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structInternal.ExecutionReportSingleChain[]\",\"name\":\"report\",\"type\":\"tuple[]\"}],\"name\":\"ExecuteReportDecoded\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"decodeCommitReport\",\"outputs\":[{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"min\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"max\",\"type\":\"uint64\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.Interval\",\"name\":\"interval\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.MerkleRoot[]\",\"name\":\"merkleRoots\",\"type\":\"tuple[]\"}],\"internalType\":\"structEVM2EVMMultiOffRamp.CommitReport\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"decodeExecuteReport\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.Any2EVMRampMessage[]\",\"name\":\"messages\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes[][]\",\"name\":\"offchainTokenData\",\"type\":\"bytes[][]\"},{\"internalType\":\"bytes32[]\",\"name\":\"proofs\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofFlagBits\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.ExecutionReportSingleChain[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b5061124f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636fb349561461003b578063f816ec6014610064575b600080fd5b61004e61004936600461024f565b610084565b60405161005b91906104f5565b60405180910390f35b61007761007236600461024f565b6100a0565b60405161005b91906107ae565b60608180602001905181019061009a9190610dc3565b92915050565b604080516080810182526060918101828152828201839052815260208101919091528180602001905181019061009a91906110d9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff81118282101715610128576101286100d6565b60405290565b6040516080810167ffffffffffffffff81118282101715610128576101286100d6565b60405160c0810167ffffffffffffffff81118282101715610128576101286100d6565b6040805190810167ffffffffffffffff81118282101715610128576101286100d6565b6040516060810167ffffffffffffffff81118282101715610128576101286100d6565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610201576102016100d6565b604052919050565b600067ffffffffffffffff821115610223576102236100d6565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006020828403121561026157600080fd5b813567ffffffffffffffff81111561027857600080fd5b8201601f8101841361028957600080fd5b803561029c61029782610209565b6101ba565b8181528560208385010111156102b157600080fd5b81602084016020830137600091810160200191909152949350505050565b60005b838110156102ea5781810151838201526020016102d2565b50506000910152565b6000815180845261030b8160208601602086016102cf565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b848110156103f2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086840301895281516080815181865261039e828701826102f3565b91505085820151858203878701526103b682826102f3565b915050604080830151868303828801526103d083826102f3565b606094850151979094019690965250509884019892509083019060010161035a565b5090979650505050505050565b6000828251808552602080860195506005818360051b8501018287016000805b868110156104aa577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe088850381018c5283518051808752908801908887019080891b88018a01865b8281101561049357858a83030184526104818286516102f3565b948c0194938c01939150600101610467565b509e8a019e9750505093870193505060010161041f565b50919998505050505050505050565b60008151808452602080850194506020840160005b838110156104ea578151875295820195908201906001016104ce565b509495945050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156106dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452815160a0860167ffffffffffffffff8083511688528883015160a08a8a015282815180855260c08b01915060c08160051b8c010194508b8301925060005b81811015610686577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408c87030183528351805180518852868f820151168f890152866040820151166040890152866060820151166060890152866080820151166080890152508d81015161014060a08901526106096101408901826102f3565b9050604082015188820360c08a015261062282826102f3565b915050606082015161064c60e08a018273ffffffffffffffffffffffffffffffffffffffff169052565b50608082015161010089015260a08201519150878103610120890152610672818361033d565b97505050928c0192918c0191600101610589565b5050505050604082015187820360408901526106a282826103ff565b915050606082015187820360608901526106bc82826104b9565b6080938401519890930197909752509450928501929085019060010161051c565b5092979650505050505050565b60008151808452602080850194506020840160005b838110156104ea578151805167ffffffffffffffff1688528301517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1683880152604090960195908201906001016106ff565b600081518084526020808501945080840160005b838110156104ea578151805167ffffffffffffffff90811689528482015180518216868b0152850151166040808a01919091520151606088015260809096019590820190600101610762565b6000602080835283516040808386015260a0850182516040606088015281815180845260c0890191508683019350600092505b8083101561083e578351805173ffffffffffffffffffffffffffffffffffffffff1683528701517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16878301529286019260019290920191908401906107e1565b50938501518785037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa00160808901529361087881866106ea565b9450505050508185015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08482030160408501526108b8818361074e565b95945050505050565b600067ffffffffffffffff8211156108db576108db6100d6565b5060051b60200190565b805167ffffffffffffffff811681146108fd57600080fd5b919050565b600060a0828403121561091457600080fd5b61091c610105565b90508151815261092e602083016108e5565b602082015261093f604083016108e5565b6040820152610950606083016108e5565b6060820152610961608083016108e5565b608082015292915050565b600082601f83011261097d57600080fd5b815161098b61029782610209565b8181528460208386010111156109a057600080fd5b6109b18260208301602087016102cf565b949350505050565b805173ffffffffffffffffffffffffffffffffffffffff811681146108fd57600080fd5b600082601f8301126109ee57600080fd5b815160206109fe610297836108c1565b82815260059290921b84018101918181019086841115610a1d57600080fd5b8286015b84811015610b1157805167ffffffffffffffff80821115610a425760008081fd5b81890191506080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848d03011215610a7b5760008081fd5b610a8361012e565b8784015183811115610a955760008081fd5b610aa38d8a8388010161096c565b82525060408085015184811115610aba5760008081fd5b610ac88e8b8389010161096c565b8a8401525060608086015185811115610ae15760008081fd5b610aef8f8c838a010161096c565b9284019290925294909201519381019390935250508352918301918301610a21565b509695505050505050565b600082601f830112610b2d57600080fd5b81516020610b3d610297836108c1565b82815260059290921b84018101918181019086841115610b5c57600080fd5b8286015b84811015610b1157805167ffffffffffffffff80821115610b815760008081fd5b8189019150610140807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848d03011215610bbb5760008081fd5b610bc3610151565b610bcf8c898601610902565b815260c084015183811115610be45760008081fd5b610bf28d8a8388010161096c565b898301525060e084015183811115610c0a5760008081fd5b610c188d8a8388010161096c565b604083015250610c2b61010085016109b9565b60608201526101208401516080820152908301519082821115610c4e5760008081fd5b610c5c8c89848701016109dd565b60a08201528652505050918301918301610b60565b600082601f830112610c8257600080fd5b81516020610c92610297836108c1565b82815260059290921b84018101918181019086841115610cb157600080fd5b8286015b84811015610b1157805167ffffffffffffffff80821115610cd557600080fd5b818901915089603f830112610ce957600080fd5b85820151610cf9610297826108c1565b81815260059190911b830160400190878101908c831115610d1957600080fd5b604085015b83811015610d5257805185811115610d3557600080fd5b610d448f6040838a010161096c565b845250918901918901610d1e565b50875250505092840192508301610cb5565b600082601f830112610d7557600080fd5b81516020610d85610297836108c1565b8083825260208201915060208460051b870101935086841115610da757600080fd5b602086015b84811015610b115780518352918301918301610dac565b60006020808385031215610dd657600080fd5b825167ffffffffffffffff80821115610dee57600080fd5b818501915085601f830112610e0257600080fd5b8151610e10610297826108c1565b81815260059190911b83018401908481019088831115610e2f57600080fd5b8585015b83811015610f2957805185811115610e4a57600080fd5b860160a0818c037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011215610e7f5760008081fd5b610e87610105565b610e928983016108e5565b815260408083015188811115610ea85760008081fd5b610eb68e8c83870101610b1c565b8b8401525060608084015189811115610ecf5760008081fd5b610edd8f8d83880101610c71565b8385015250608091508184015189811115610ef85760008081fd5b610f068f8d83880101610d64565b918401919091525060a09290920151918101919091528352918601918601610e33565b5098975050505050505050565b80517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146108fd57600080fd5b600082601f830112610f7357600080fd5b81516020610f83610297836108c1565b82815260069290921b84018101918181019086841115610fa257600080fd5b8286015b84811015610b115760408189031215610fbf5760008081fd5b610fc7610174565b610fd0826108e5565b8152610fdd858301610f36565b81860152835291830191604001610fa6565b600082601f83011261100057600080fd5b81516020611010610297836108c1565b82815260079290921b8401810191818101908684111561102f57600080fd5b8286015b84811015610b1157808803608081121561104d5760008081fd5b611055610197565b61105e836108e5565b81526040807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0840112156110925760008081fd5b61109a610174565b92506110a78785016108e5565b83526110b48185016108e5565b8388015281870192909252606083015191810191909152835291830191608001611033565b600060208083850312156110ec57600080fd5b825167ffffffffffffffff8082111561110457600080fd5b8185019150604080838803121561111a57600080fd5b611122610174565b83518381111561113157600080fd5b84016040818a03121561114357600080fd5b61114b610174565b81518581111561115a57600080fd5b8201601f81018b1361116b57600080fd5b8051611179610297826108c1565b81815260069190911b8201890190898101908d83111561119857600080fd5b928a01925b828410156111e65787848f0312156111b55760008081fd5b6111bd610174565b6111c6856109b9565b81526111d38c8601610f36565b818d0152825292870192908a019061119d565b8452505050818701519350848411156111fe57600080fd5b61120a8a858401610f62565b818801528252508385015191508282111561122457600080fd5b61123088838601610fef565b8582015280955050505050509291505056fea164736f6c6343000818000a",
+}
+
+var ReportCodecABI = ReportCodecMetaData.ABI
+
+var ReportCodecBin = ReportCodecMetaData.Bin
+
+func DeployReportCodec(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ReportCodec, error) {
+ parsed, err := ReportCodecMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ReportCodecBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &ReportCodec{address: address, abi: *parsed, ReportCodecCaller: ReportCodecCaller{contract: contract}, ReportCodecTransactor: ReportCodecTransactor{contract: contract}, ReportCodecFilterer: ReportCodecFilterer{contract: contract}}, nil
+}
+
+type ReportCodec struct {
+ address common.Address
+ abi abi.ABI
+ ReportCodecCaller
+ ReportCodecTransactor
+ ReportCodecFilterer
+}
+
+type ReportCodecCaller struct {
+ contract *bind.BoundContract
+}
+
+type ReportCodecTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ReportCodecFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ReportCodecSession struct {
+ Contract *ReportCodec
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ReportCodecCallerSession struct {
+ Contract *ReportCodecCaller
+ CallOpts bind.CallOpts
+}
+
+type ReportCodecTransactorSession struct {
+ Contract *ReportCodecTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ReportCodecRaw struct {
+ Contract *ReportCodec
+}
+
+type ReportCodecCallerRaw struct {
+ Contract *ReportCodecCaller
+}
+
+type ReportCodecTransactorRaw struct {
+ Contract *ReportCodecTransactor
+}
+
+func NewReportCodec(address common.Address, backend bind.ContractBackend) (*ReportCodec, error) {
+ abi, err := abi.JSON(strings.NewReader(ReportCodecABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindReportCodec(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ReportCodec{address: address, abi: abi, ReportCodecCaller: ReportCodecCaller{contract: contract}, ReportCodecTransactor: ReportCodecTransactor{contract: contract}, ReportCodecFilterer: ReportCodecFilterer{contract: contract}}, nil
+}
+
+func NewReportCodecCaller(address common.Address, caller bind.ContractCaller) (*ReportCodecCaller, error) {
+ contract, err := bindReportCodec(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ReportCodecCaller{contract: contract}, nil
+}
+
+func NewReportCodecTransactor(address common.Address, transactor bind.ContractTransactor) (*ReportCodecTransactor, error) {
+ contract, err := bindReportCodec(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ReportCodecTransactor{contract: contract}, nil
+}
+
+func NewReportCodecFilterer(address common.Address, filterer bind.ContractFilterer) (*ReportCodecFilterer, error) {
+ contract, err := bindReportCodec(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ReportCodecFilterer{contract: contract}, nil
+}
+
+func bindReportCodec(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ReportCodecMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ReportCodec *ReportCodecRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ReportCodec.Contract.ReportCodecCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ReportCodec *ReportCodecRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ReportCodec.Contract.ReportCodecTransactor.contract.Transfer(opts)
+}
+
+func (_ReportCodec *ReportCodecRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ReportCodec.Contract.ReportCodecTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ReportCodec *ReportCodecCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ReportCodec.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ReportCodec *ReportCodecTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ReportCodec.Contract.contract.Transfer(opts)
+}
+
+func (_ReportCodec *ReportCodecTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ReportCodec.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ReportCodec *ReportCodecCaller) DecodeCommitReport(opts *bind.CallOpts, report []byte) (EVM2EVMMultiOffRampCommitReport, error) {
+ var out []interface{}
+ err := _ReportCodec.contract.Call(opts, &out, "decodeCommitReport", report)
+
+ if err != nil {
+ return *new(EVM2EVMMultiOffRampCommitReport), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(EVM2EVMMultiOffRampCommitReport)).(*EVM2EVMMultiOffRampCommitReport)
+
+ return out0, err
+
+}
+
+func (_ReportCodec *ReportCodecSession) DecodeCommitReport(report []byte) (EVM2EVMMultiOffRampCommitReport, error) {
+ return _ReportCodec.Contract.DecodeCommitReport(&_ReportCodec.CallOpts, report)
+}
+
+func (_ReportCodec *ReportCodecCallerSession) DecodeCommitReport(report []byte) (EVM2EVMMultiOffRampCommitReport, error) {
+ return _ReportCodec.Contract.DecodeCommitReport(&_ReportCodec.CallOpts, report)
+}
+
+func (_ReportCodec *ReportCodecCaller) DecodeExecuteReport(opts *bind.CallOpts, report []byte) ([]InternalExecutionReportSingleChain, error) {
+ var out []interface{}
+ err := _ReportCodec.contract.Call(opts, &out, "decodeExecuteReport", report)
+
+ if err != nil {
+ return *new([]InternalExecutionReportSingleChain), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]InternalExecutionReportSingleChain)).(*[]InternalExecutionReportSingleChain)
+
+ return out0, err
+
+}
+
+func (_ReportCodec *ReportCodecSession) DecodeExecuteReport(report []byte) ([]InternalExecutionReportSingleChain, error) {
+ return _ReportCodec.Contract.DecodeExecuteReport(&_ReportCodec.CallOpts, report)
+}
+
+func (_ReportCodec *ReportCodecCallerSession) DecodeExecuteReport(report []byte) ([]InternalExecutionReportSingleChain, error) {
+ return _ReportCodec.Contract.DecodeExecuteReport(&_ReportCodec.CallOpts, report)
+}
+
+type ReportCodecCommitReportDecodedIterator struct {
+ Event *ReportCodecCommitReportDecoded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ReportCodecCommitReportDecodedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ReportCodecCommitReportDecoded)
+ 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(ReportCodecCommitReportDecoded)
+ 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 *ReportCodecCommitReportDecodedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ReportCodecCommitReportDecodedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ReportCodecCommitReportDecoded struct {
+ Report EVM2EVMMultiOffRampCommitReport
+ Raw types.Log
+}
+
+func (_ReportCodec *ReportCodecFilterer) FilterCommitReportDecoded(opts *bind.FilterOpts) (*ReportCodecCommitReportDecodedIterator, error) {
+
+ logs, sub, err := _ReportCodec.contract.FilterLogs(opts, "CommitReportDecoded")
+ if err != nil {
+ return nil, err
+ }
+ return &ReportCodecCommitReportDecodedIterator{contract: _ReportCodec.contract, event: "CommitReportDecoded", logs: logs, sub: sub}, nil
+}
+
+func (_ReportCodec *ReportCodecFilterer) WatchCommitReportDecoded(opts *bind.WatchOpts, sink chan<- *ReportCodecCommitReportDecoded) (event.Subscription, error) {
+
+ logs, sub, err := _ReportCodec.contract.WatchLogs(opts, "CommitReportDecoded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ReportCodecCommitReportDecoded)
+ if err := _ReportCodec.contract.UnpackLog(event, "CommitReportDecoded", 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 (_ReportCodec *ReportCodecFilterer) ParseCommitReportDecoded(log types.Log) (*ReportCodecCommitReportDecoded, error) {
+ event := new(ReportCodecCommitReportDecoded)
+ if err := _ReportCodec.contract.UnpackLog(event, "CommitReportDecoded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ReportCodecExecuteReportDecodedIterator struct {
+ Event *ReportCodecExecuteReportDecoded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ReportCodecExecuteReportDecodedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ReportCodecExecuteReportDecoded)
+ 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(ReportCodecExecuteReportDecoded)
+ 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 *ReportCodecExecuteReportDecodedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ReportCodecExecuteReportDecodedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ReportCodecExecuteReportDecoded struct {
+ Report []InternalExecutionReportSingleChain
+ Raw types.Log
+}
+
+func (_ReportCodec *ReportCodecFilterer) FilterExecuteReportDecoded(opts *bind.FilterOpts) (*ReportCodecExecuteReportDecodedIterator, error) {
+
+ logs, sub, err := _ReportCodec.contract.FilterLogs(opts, "ExecuteReportDecoded")
+ if err != nil {
+ return nil, err
+ }
+ return &ReportCodecExecuteReportDecodedIterator{contract: _ReportCodec.contract, event: "ExecuteReportDecoded", logs: logs, sub: sub}, nil
+}
+
+func (_ReportCodec *ReportCodecFilterer) WatchExecuteReportDecoded(opts *bind.WatchOpts, sink chan<- *ReportCodecExecuteReportDecoded) (event.Subscription, error) {
+
+ logs, sub, err := _ReportCodec.contract.WatchLogs(opts, "ExecuteReportDecoded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ReportCodecExecuteReportDecoded)
+ if err := _ReportCodec.contract.UnpackLog(event, "ExecuteReportDecoded", 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 (_ReportCodec *ReportCodecFilterer) ParseExecuteReportDecoded(log types.Log) (*ReportCodecExecuteReportDecoded, error) {
+ event := new(ReportCodecExecuteReportDecoded)
+ if err := _ReportCodec.contract.UnpackLog(event, "ExecuteReportDecoded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_ReportCodec *ReportCodec) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _ReportCodec.abi.Events["CommitReportDecoded"].ID:
+ return _ReportCodec.ParseCommitReportDecoded(log)
+ case _ReportCodec.abi.Events["ExecuteReportDecoded"].ID:
+ return _ReportCodec.ParseExecuteReportDecoded(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (ReportCodecCommitReportDecoded) Topic() common.Hash {
+ return common.HexToHash("0x1b2cb5e9d31bdaabb2ae07532436ae669406f84003ca27179b4dfb72f127f7dc")
+}
+
+func (ReportCodecExecuteReportDecoded) Topic() common.Hash {
+ return common.HexToHash("0x7f4f1032eaaa1f5c3fc02d56071d69a09a2595d9a5fa4704f0eb298792908abb")
+}
+
+func (_ReportCodec *ReportCodec) Address() common.Address {
+ return _ReportCodec.address
+}
+
+type ReportCodecInterface interface {
+ DecodeCommitReport(opts *bind.CallOpts, report []byte) (EVM2EVMMultiOffRampCommitReport, error)
+
+ DecodeExecuteReport(opts *bind.CallOpts, report []byte) ([]InternalExecutionReportSingleChain, error)
+
+ FilterCommitReportDecoded(opts *bind.FilterOpts) (*ReportCodecCommitReportDecodedIterator, error)
+
+ WatchCommitReportDecoded(opts *bind.WatchOpts, sink chan<- *ReportCodecCommitReportDecoded) (event.Subscription, error)
+
+ ParseCommitReportDecoded(log types.Log) (*ReportCodecCommitReportDecoded, error)
+
+ FilterExecuteReportDecoded(opts *bind.FilterOpts) (*ReportCodecExecuteReportDecodedIterator, error)
+
+ WatchExecuteReportDecoded(opts *bind.WatchOpts, sink chan<- *ReportCodecExecuteReportDecoded) (event.Subscription, error)
+
+ ParseExecuteReportDecoded(log types.Log) (*ReportCodecExecuteReportDecoded, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/router/router.go b/core/gethwrappers/ccip/generated/router/router.go
new file mode 100644
index 00000000000..c53d4824b16
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/router/router.go
@@ -0,0 +1,1431 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package router
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVM2AnyMessage struct {
+ Receiver []byte
+ Data []byte
+ TokenAmounts []ClientEVMTokenAmount
+ FeeToken common.Address
+ ExtraArgs []byte
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+type RouterOffRamp struct {
+ SourceChainSelector uint64
+ OffRamp common.Address
+}
+
+type RouterOnRamp struct {
+ DestChainSelector uint64
+ OnRamp common.Address
+}
+
+var RouterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"wrappedNative\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSendValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientFeeTokenAmount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMsgValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"InvalidRecipientAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"OffRampMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyOffRamp\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"UnsupportedDestinationChain\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"calldataHash\",\"type\":\"bytes32\"}],\"name\":\"MessageExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"OffRampAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"OffRampRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"}],\"name\":\"OnRampSet\",\"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\":\"MAX_RET_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"onRamp\",\"type\":\"address\"}],\"internalType\":\"structRouter.OnRamp[]\",\"name\":\"onRampUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"internalType\":\"structRouter.OffRamp[]\",\"name\":\"offRampRemoves\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"internalType\":\"structRouter.OffRamp[]\",\"name\":\"offRampAdds\",\"type\":\"tuple[]\"}],\"name\":\"applyRampUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destinationChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"ccipSend\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getArmProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destinationChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"fee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOffRamps\",\"outputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"internalType\":\"structRouter.OffRamp[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getOnRamp\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"getSupportedTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWrappedNative\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"isChainSupported\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"offRamp\",\"type\":\"address\"}],\"name\":\"isOffRamp\",\"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\":\"tokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"recoverTokens\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"routeMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"retData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"wrappedNative\",\"type\":\"address\"}],\"name\":\"setWrappedNative\",\"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: "0x60a06040523480156200001157600080fd5b5060405162002d2838038062002d288339810160408190526200003491620001af565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e7565b5050600280546001600160a01b0319166001600160a01b039485161790555016608052620001e7565b336001600160a01b03821603620001415760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001aa57600080fd5b919050565b60008060408385031215620001c357600080fd5b620001ce8362000192565b9150620001de6020840162000192565b90509250929050565b608051612b1762000211600039600081816101f9015281816105e10152610af20152612b176000f3fe6080604052600436106101295760003560e01c80638da5cb5b116100a5578063a8d87a3b11610074578063e861e90711610059578063e861e90714610409578063f2fde38b14610434578063fbca3b741461045457600080fd5b8063a8d87a3b1461039c578063da5fcac8146103e957600080fd5b80638da5cb5b146102ed57806396f4e9f914610318578063a40e69c71461032b578063a48a90581461034d57600080fd5b806352cb60ca116100fc578063787350e3116100e1578063787350e31461028057806379ba5097146102a857806383826b2b146102bd57600080fd5b806352cb60ca1461023e5780635f3e849f1461026057600080fd5b8063181f5a771461012e57806320487ded1461018d5780633cf97983146101bb5780635246492f146101ea575b600080fd5b34801561013a57600080fd5b506101776040518060400160405280600c81526020017f526f7574657220312e322e30000000000000000000000000000000000000000081525081565b6040516101849190611f3c565b60405180910390f35b34801561019957600080fd5b506101ad6101a83660046121ad565b610481565b604051908152602001610184565b3480156101c757600080fd5b506101db6101d63660046122aa565b6105d9565b60405161018493929190612322565b3480156101f657600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610184565b34801561024a57600080fd5b5061025e61025936600461234d565b610836565b005b34801561026c57600080fd5b5061025e61027b36600461236a565b610885565b34801561028c57600080fd5b50610295608481565b60405161ffff9091168152602001610184565b3480156102b457600080fd5b5061025e6109d3565b3480156102c957600080fd5b506102dd6102d83660046123ab565b610ad0565b6040519015158152602001610184565b3480156102f957600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610219565b6101ad6103263660046121ad565b610aee565b34801561033757600080fd5b50610340611087565b60405161018491906123e2565b34801561035957600080fd5b506102dd610368366004612451565b67ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16151590565b3480156103a857600080fd5b506102196103b7366004612451565b67ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b3480156103f557600080fd5b5061025e6104043660046124b8565b61118b565b34801561041557600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff16610219565b34801561044057600080fd5b5061025e61044f36600461234d565b611490565b34801561046057600080fd5b5061047461046f366004612451565b6114a4565b6040516101849190612552565b606081015160009073ffffffffffffffffffffffffffffffffffffffff166104c25760025473ffffffffffffffffffffffffffffffffffffffff1660608301525b67ffffffffffffffff831660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff168061053a576040517fae236d9c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526024015b60405180910390fd5b6040517f20487ded00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216906320487ded9061058e9087908790600401612689565b602060405180830381865afa1580156105ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cf91906126ac565b9150505b92915050565b6000606060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa15801561064a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066e91906126c5565b156106a5576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106be6106b86040890160208a01612451565b33610ad0565b6106f4576040517fd2316ede00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006385572ffb60e01b8860405160240161070f91906127f4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905061079c8186888a60846115c4565b919550935091507f9b877de93ea9895756e337442c657f95a34fc68e7eb988bdfa693d5be83016b688356107d660408b0160208c01612451565b83516020850120604051610823939291339193845267ffffffffffffffff92909216602084015273ffffffffffffffffffffffffffffffffffffffff166040830152606082015260800190565b60405180910390a1509450945094915050565b61083e6116ea565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b61088d6116ea565b73ffffffffffffffffffffffffffffffffffffffff82166108f2576040517f26a78f8f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610531565b73ffffffffffffffffffffffffffffffffffffffff83166109ad5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610967576040519150601f19603f3d011682016040523d82523d6000602084013e61096c565b606091505b50509050806109a7576040517fe417b80b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6109ce73ffffffffffffffffffffffffffffffffffffffff8416838361176d565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a54576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610531565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000610ae7610adf8484611841565b600490611885565b9392505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7f91906126c5565b15610bb6576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff831660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610c29576040517fae236d9c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff85166004820152602401610531565b606083015160009073ffffffffffffffffffffffffffffffffffffffff16610dbb5760025473ffffffffffffffffffffffffffffffffffffffff90811660608601526040517f20487ded000000000000000000000000000000000000000000000000000000008152908316906320487ded90610cab9088908890600401612689565b602060405180830381865afa158015610cc8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cec91906126ac565b905080341015610d28576040517f07da6ee600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b349050836060015173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610d7757600080fd5b505af1158015610d8b573d6000803e3d6000fd5b505050506060850151610db6915073ffffffffffffffffffffffffffffffffffffffff16838361176d565b610eb2565b3415610df3576040517f1841b4e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f20487ded00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316906320487ded90610e479088908890600401612689565b602060405180830381865afa158015610e64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e8891906126ac565b6060850151909150610eb29073ffffffffffffffffffffffffffffffffffffffff1633848461189d565b60005b846040015151811015610fe257600085604001518281518110610eda57610eda612900565b6020908102919091010151516040517f48a98aa400000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8916600482015273ffffffffffffffffffffffffffffffffffffffff8083166024830152919250610fd9913391908716906348a98aa490604401602060405180830381865afa158015610f6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f90919061292f565b88604001518581518110610fa657610fa6612900565b6020026020010151602001518473ffffffffffffffffffffffffffffffffffffffff1661189d909392919063ffffffff16565b50600101610eb5565b506040517fdf0aa9e900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063df0aa9e99061103b90889088908690339060040161294c565b6020604051808303816000875af115801561105a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107e91906126ac565b95945050505050565b6060600061109560046118fb565b90506000815167ffffffffffffffff8111156110b3576110b3611f6c565b6040519080825280602002602001820160405280156110f857816020015b60408051808201909152600080825260208201528152602001906001900390816110d15790505b50905060005b825181101561118457600083828151811061111b5761111b612900565b60200260200101519050604051806040016040528060a083901c67ffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1681525083838151811061117057611170612900565b6020908102919091010152506001016110fe565b5092915050565b6111936116ea565b60005b8581101561126f5760008787838181106111b2576111b2612900565b9050604002018036038101906111c8919061299c565b60208181018051835167ffffffffffffffff90811660009081526003855260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055855193519051921682529394509216917f1f7d0ec248b80e5c0dde0ee531c4fc8fdb6ce9a2b3d90f560c74acd6a7202f23910160405180910390a250600101611196565b5060005b838110156113a757600085858381811061128f5761128f612900565b6112a59260206040909202019081019150612451565b905060008686848181106112bb576112bb612900565b90506040020160200160208101906112d3919061234d565b90506112ea6112e28383611841565b600490611908565b611348576040517f4964779000000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8316600482015273ffffffffffffffffffffffffffffffffffffffff82166024820152604401610531565b60405173ffffffffffffffffffffffffffffffffffffffff8216815267ffffffffffffffff8316907fa823809efda3ba66c873364eec120fa0923d9fabda73bc97dd5663341e2d9bcb9060200160405180910390a25050600101611273565b5060005b818110156114875760008383838181106113c7576113c7612900565b6113dd9260206040909202019081019150612451565b905060008484848181106113f3576113f3612900565b905060400201602001602081019061140b919061234d565b905061142261141a8383611841565b600490611914565b1561147d5760405173ffffffffffffffffffffffffffffffffffffffff8216815267ffffffffffffffff8316907fa4bdf64ebdf3316320601a081916a75aa144bcef6c4beeb0e9fb1982cacc6b949060200160405180910390a25b50506001016113ab565b50505050505050565b6114986116ea565b6114a181611920565b50565b60606114de8267ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16151590565b6114f8576040805160008082526020820190925290611184565b67ffffffffffffffff8216600081815260036020526040908190205490517ffbca3b74000000000000000000000000000000000000000000000000000000008152600481019290925273ffffffffffffffffffffffffffffffffffffffff169063fbca3b7490602401600060405180830381865afa15801561157e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526105d391908101906129db565b6000606060008361ffff1667ffffffffffffffff8111156115e7576115e7611f6c565b6040519080825280601f01601f191660200182016040528015611611576020820181803683370190505b509150863b611644577f0c3b563c0000000000000000000000000000000000000000000000000000000060005260046000fd5b5a85811015611677577fafa32a2c0000000000000000000000000000000000000000000000000000000060005260046000fd5b85900360408104810387106116b0577f37c3be290000000000000000000000000000000000000000000000000000000060005260046000fd5b505a6000808a5160208c0160008c8cf193505a900390503d848111156116d35750835b808352806000602085013e50955095509592505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331461176b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610531565b565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526109ce9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611a15565b6000610ae773ffffffffffffffffffffffffffffffffffffffff83167bffffffffffffffff000000000000000000000000000000000000000060a086901b16612a99565b60008181526001830160205260408120541515610ae7565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526109a79085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016117bf565b60606000610ae783611b21565b6000610ae78383611b7d565b6000610ae78383611c70565b3373ffffffffffffffffffffffffffffffffffffffff82160361199f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610531565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611a77826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611cbf9092919063ffffffff16565b8051909150156109ce5780806020019051810190611a9591906126c5565b6109ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610531565b606081600001805480602002602001604051908101604052809291908181526020018280548015611b7157602002820191906000526020600020905b815481526020019060010190808311611b5d575b50505050509050919050565b60008181526001830160205260408120548015611c66576000611ba1600183612aac565b8554909150600090611bb590600190612aac565b9050818114611c1a576000866000018281548110611bd557611bd5612900565b9060005260206000200154905080876000018481548110611bf857611bf8612900565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611c2b57611c2b612abf565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105d3565b60009150506105d3565b6000818152600183016020526040812054611cb7575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105d3565b5060006105d3565b6060611cce8484600085611cd6565b949350505050565b606082471015611d68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610531565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611d919190612aee565b60006040518083038185875af1925050503d8060008114611dce576040519150601f19603f3d011682016040523d82523d6000602084013e611dd3565b606091505b5091509150611de487838387611def565b979650505050505050565b60608315611e85578251600003611e7e5773ffffffffffffffffffffffffffffffffffffffff85163b611e7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610531565b5081611cce565b611cce8383815115611e9a5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105319190611f3c565b60005b83811015611ee9578181015183820152602001611ed1565b50506000910152565b60008151808452611f0a816020860160208601611ece565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610ae76020830184611ef2565b803567ffffffffffffffff81168114611f6757600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611fbe57611fbe611f6c565b60405290565b60405160a0810167ffffffffffffffff81118282101715611fbe57611fbe611f6c565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561202e5761202e611f6c565b604052919050565b600082601f83011261204757600080fd5b813567ffffffffffffffff81111561206157612061611f6c565b61209260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611fe7565b8181528460208386010111156120a757600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff8211156120de576120de611f6c565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff811681146114a157600080fd5b8035611f67816120e8565b600082601f83011261212657600080fd5b8135602061213b612136836120c4565b611fe7565b82815260069290921b8401810191818101908684111561215a57600080fd5b8286015b848110156121a257604081890312156121775760008081fd5b61217f611f9b565b813561218a816120e8565b8152818501358582015283529183019160400161215e565b509695505050505050565b600080604083850312156121c057600080fd5b6121c983611f4f565b9150602083013567ffffffffffffffff808211156121e657600080fd5b9084019060a082870312156121fa57600080fd5b612202611fc4565b82358281111561221157600080fd5b61221d88828601612036565b82525060208301358281111561223257600080fd5b61223e88828601612036565b60208301525060408301358281111561225657600080fd5b61226288828601612115565b6040830152506122746060840161210a565b606082015260808301358281111561228b57600080fd5b61229788828601612036565b6080830152508093505050509250929050565b600080600080608085870312156122c057600080fd5b843567ffffffffffffffff8111156122d757600080fd5b850160a081880312156122e957600080fd5b9350602085013561ffff8116811461230057600080fd5b9250604085013591506060850135612317816120e8565b939692955090935050565b831515815260606020820152600061233d6060830185611ef2565b9050826040830152949350505050565b60006020828403121561235f57600080fd5b8135610ae7816120e8565b60008060006060848603121561237f57600080fd5b833561238a816120e8565b9250602084013561239a816120e8565b929592945050506040919091013590565b600080604083850312156123be57600080fd5b6123c783611f4f565b915060208301356123d7816120e8565b809150509250929050565b602080825282518282018190526000919060409081850190868401855b82811015612444578151805167ffffffffffffffff16855286015173ffffffffffffffffffffffffffffffffffffffff168685015292840192908501906001016123ff565b5091979650505050505050565b60006020828403121561246357600080fd5b610ae782611f4f565b60008083601f84011261247e57600080fd5b50813567ffffffffffffffff81111561249657600080fd5b6020830191508360208260061b85010111156124b157600080fd5b9250929050565b600080600080600080606087890312156124d157600080fd5b863567ffffffffffffffff808211156124e957600080fd5b6124f58a838b0161246c565b9098509650602089013591508082111561250e57600080fd5b61251a8a838b0161246c565b9096509450604089013591508082111561253357600080fd5b5061254089828a0161246c565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b818110156125a057835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161256e565b50909695505050505050565b6000815160a084526125c160a0850182611ef2565b9050602080840151858303828701526125da8382611ef2565b60408681015188830389830152805180845290850195509092506000918401905b8083101561263a578551805173ffffffffffffffffffffffffffffffffffffffff168352850151858301529484019460019290920191908301906125fb565b5060608701519450612664606089018673ffffffffffffffffffffffffffffffffffffffff169052565b60808701519450878103608089015261267d8186611ef2565b98975050505050505050565b67ffffffffffffffff83168152604060208201526000611cce60408301846125ac565b6000602082840312156126be57600080fd5b5051919050565b6000602082840312156126d757600080fd5b81518015158114610ae757600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261271c57600080fd5b830160208101925035905067ffffffffffffffff81111561273c57600080fd5b8036038213156124b157600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b8183526000602080850194508260005b858110156127e95781356127b7816120e8565b73ffffffffffffffffffffffffffffffffffffffff1687528183013583880152604096870196909101906001016127a4565b509495945050505050565b6020815281356020820152600061280d60208401611f4f565b67ffffffffffffffff808216604085015261282b60408601866126e7565b925060a0606086015261284260c08601848361274b565b92505061285260608601866126e7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08087860301608088015261288885838561274b565b9450608088013592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030183126128c157600080fd5b602092880192830192359150838211156128da57600080fd5b8160061b36038313156128ec57600080fd5b8685030160a0870152611de4848284612794565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561294157600080fd5b8151610ae7816120e8565b67ffffffffffffffff8516815260806020820152600061296f60808301866125ac565b905083604083015273ffffffffffffffffffffffffffffffffffffffff8316606083015295945050505050565b6000604082840312156129ae57600080fd5b6129b6611f9b565b6129bf83611f4f565b815260208301356129cf816120e8565b60208201529392505050565b600060208083850312156129ee57600080fd5b825167ffffffffffffffff811115612a0557600080fd5b8301601f81018513612a1657600080fd5b8051612a24612136826120c4565b81815260059190911b82018301908381019087831115612a4357600080fd5b928401925b82841015611de4578351612a5b816120e8565b82529284019290840190612a48565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156105d3576105d3612a6a565b818103818111156105d3576105d3612a6a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612b00818460208701611ece565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var RouterABI = RouterMetaData.ABI
+
+var RouterBin = RouterMetaData.Bin
+
+func DeployRouter(auth *bind.TransactOpts, backend bind.ContractBackend, wrappedNative common.Address, armProxy common.Address) (common.Address, *types.Transaction, *Router, error) {
+ parsed, err := RouterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(RouterBin), backend, wrappedNative, armProxy)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &Router{address: address, abi: *parsed, RouterCaller: RouterCaller{contract: contract}, RouterTransactor: RouterTransactor{contract: contract}, RouterFilterer: RouterFilterer{contract: contract}}, nil
+}
+
+type Router struct {
+ address common.Address
+ abi abi.ABI
+ RouterCaller
+ RouterTransactor
+ RouterFilterer
+}
+
+type RouterCaller struct {
+ contract *bind.BoundContract
+}
+
+type RouterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type RouterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type RouterSession struct {
+ Contract *Router
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type RouterCallerSession struct {
+ Contract *RouterCaller
+ CallOpts bind.CallOpts
+}
+
+type RouterTransactorSession struct {
+ Contract *RouterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type RouterRaw struct {
+ Contract *Router
+}
+
+type RouterCallerRaw struct {
+ Contract *RouterCaller
+}
+
+type RouterTransactorRaw struct {
+ Contract *RouterTransactor
+}
+
+func NewRouter(address common.Address, backend bind.ContractBackend) (*Router, error) {
+ abi, err := abi.JSON(strings.NewReader(RouterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindRouter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &Router{address: address, abi: abi, RouterCaller: RouterCaller{contract: contract}, RouterTransactor: RouterTransactor{contract: contract}, RouterFilterer: RouterFilterer{contract: contract}}, nil
+}
+
+func NewRouterCaller(address common.Address, caller bind.ContractCaller) (*RouterCaller, error) {
+ contract, err := bindRouter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &RouterCaller{contract: contract}, nil
+}
+
+func NewRouterTransactor(address common.Address, transactor bind.ContractTransactor) (*RouterTransactor, error) {
+ contract, err := bindRouter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &RouterTransactor{contract: contract}, nil
+}
+
+func NewRouterFilterer(address common.Address, filterer bind.ContractFilterer) (*RouterFilterer, error) {
+ contract, err := bindRouter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &RouterFilterer{contract: contract}, nil
+}
+
+func bindRouter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := RouterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_Router *RouterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _Router.Contract.RouterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_Router *RouterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Router.Contract.RouterTransactor.contract.Transfer(opts)
+}
+
+func (_Router *RouterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Router.Contract.RouterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_Router *RouterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _Router.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_Router *RouterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Router.Contract.contract.Transfer(opts)
+}
+
+func (_Router *RouterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _Router.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_Router *RouterCaller) MAXRETBYTES(opts *bind.CallOpts) (uint16, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "MAX_RET_BYTES")
+
+ if err != nil {
+ return *new(uint16), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) MAXRETBYTES() (uint16, error) {
+ return _Router.Contract.MAXRETBYTES(&_Router.CallOpts)
+}
+
+func (_Router *RouterCallerSession) MAXRETBYTES() (uint16, error) {
+ return _Router.Contract.MAXRETBYTES(&_Router.CallOpts)
+}
+
+func (_Router *RouterCaller) GetArmProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "getArmProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) GetArmProxy() (common.Address, error) {
+ return _Router.Contract.GetArmProxy(&_Router.CallOpts)
+}
+
+func (_Router *RouterCallerSession) GetArmProxy() (common.Address, error) {
+ return _Router.Contract.GetArmProxy(&_Router.CallOpts)
+}
+
+func (_Router *RouterCaller) GetFee(opts *bind.CallOpts, destinationChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "getFee", destinationChainSelector, message)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) GetFee(destinationChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _Router.Contract.GetFee(&_Router.CallOpts, destinationChainSelector, message)
+}
+
+func (_Router *RouterCallerSession) GetFee(destinationChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error) {
+ return _Router.Contract.GetFee(&_Router.CallOpts, destinationChainSelector, message)
+}
+
+func (_Router *RouterCaller) GetOffRamps(opts *bind.CallOpts) ([]RouterOffRamp, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "getOffRamps")
+
+ if err != nil {
+ return *new([]RouterOffRamp), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]RouterOffRamp)).(*[]RouterOffRamp)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) GetOffRamps() ([]RouterOffRamp, error) {
+ return _Router.Contract.GetOffRamps(&_Router.CallOpts)
+}
+
+func (_Router *RouterCallerSession) GetOffRamps() ([]RouterOffRamp, error) {
+ return _Router.Contract.GetOffRamps(&_Router.CallOpts)
+}
+
+func (_Router *RouterCaller) GetOnRamp(opts *bind.CallOpts, destChainSelector uint64) (common.Address, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "getOnRamp", destChainSelector)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) GetOnRamp(destChainSelector uint64) (common.Address, error) {
+ return _Router.Contract.GetOnRamp(&_Router.CallOpts, destChainSelector)
+}
+
+func (_Router *RouterCallerSession) GetOnRamp(destChainSelector uint64) (common.Address, error) {
+ return _Router.Contract.GetOnRamp(&_Router.CallOpts, destChainSelector)
+}
+
+func (_Router *RouterCaller) GetSupportedTokens(opts *bind.CallOpts, chainSelector uint64) ([]common.Address, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "getSupportedTokens", chainSelector)
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) GetSupportedTokens(chainSelector uint64) ([]common.Address, error) {
+ return _Router.Contract.GetSupportedTokens(&_Router.CallOpts, chainSelector)
+}
+
+func (_Router *RouterCallerSession) GetSupportedTokens(chainSelector uint64) ([]common.Address, error) {
+ return _Router.Contract.GetSupportedTokens(&_Router.CallOpts, chainSelector)
+}
+
+func (_Router *RouterCaller) GetWrappedNative(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "getWrappedNative")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) GetWrappedNative() (common.Address, error) {
+ return _Router.Contract.GetWrappedNative(&_Router.CallOpts)
+}
+
+func (_Router *RouterCallerSession) GetWrappedNative() (common.Address, error) {
+ return _Router.Contract.GetWrappedNative(&_Router.CallOpts)
+}
+
+func (_Router *RouterCaller) IsChainSupported(opts *bind.CallOpts, chainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "isChainSupported", chainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) IsChainSupported(chainSelector uint64) (bool, error) {
+ return _Router.Contract.IsChainSupported(&_Router.CallOpts, chainSelector)
+}
+
+func (_Router *RouterCallerSession) IsChainSupported(chainSelector uint64) (bool, error) {
+ return _Router.Contract.IsChainSupported(&_Router.CallOpts, chainSelector)
+}
+
+func (_Router *RouterCaller) IsOffRamp(opts *bind.CallOpts, sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "isOffRamp", sourceChainSelector, offRamp)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) IsOffRamp(sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ return _Router.Contract.IsOffRamp(&_Router.CallOpts, sourceChainSelector, offRamp)
+}
+
+func (_Router *RouterCallerSession) IsOffRamp(sourceChainSelector uint64, offRamp common.Address) (bool, error) {
+ return _Router.Contract.IsOffRamp(&_Router.CallOpts, sourceChainSelector, offRamp)
+}
+
+func (_Router *RouterCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) Owner() (common.Address, error) {
+ return _Router.Contract.Owner(&_Router.CallOpts)
+}
+
+func (_Router *RouterCallerSession) Owner() (common.Address, error) {
+ return _Router.Contract.Owner(&_Router.CallOpts)
+}
+
+func (_Router *RouterCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _Router.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_Router *RouterSession) TypeAndVersion() (string, error) {
+ return _Router.Contract.TypeAndVersion(&_Router.CallOpts)
+}
+
+func (_Router *RouterCallerSession) TypeAndVersion() (string, error) {
+ return _Router.Contract.TypeAndVersion(&_Router.CallOpts)
+}
+
+func (_Router *RouterTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _Router.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_Router *RouterSession) AcceptOwnership() (*types.Transaction, error) {
+ return _Router.Contract.AcceptOwnership(&_Router.TransactOpts)
+}
+
+func (_Router *RouterTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _Router.Contract.AcceptOwnership(&_Router.TransactOpts)
+}
+
+func (_Router *RouterTransactor) ApplyRampUpdates(opts *bind.TransactOpts, onRampUpdates []RouterOnRamp, offRampRemoves []RouterOffRamp, offRampAdds []RouterOffRamp) (*types.Transaction, error) {
+ return _Router.contract.Transact(opts, "applyRampUpdates", onRampUpdates, offRampRemoves, offRampAdds)
+}
+
+func (_Router *RouterSession) ApplyRampUpdates(onRampUpdates []RouterOnRamp, offRampRemoves []RouterOffRamp, offRampAdds []RouterOffRamp) (*types.Transaction, error) {
+ return _Router.Contract.ApplyRampUpdates(&_Router.TransactOpts, onRampUpdates, offRampRemoves, offRampAdds)
+}
+
+func (_Router *RouterTransactorSession) ApplyRampUpdates(onRampUpdates []RouterOnRamp, offRampRemoves []RouterOffRamp, offRampAdds []RouterOffRamp) (*types.Transaction, error) {
+ return _Router.Contract.ApplyRampUpdates(&_Router.TransactOpts, onRampUpdates, offRampRemoves, offRampAdds)
+}
+
+func (_Router *RouterTransactor) CcipSend(opts *bind.TransactOpts, destinationChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _Router.contract.Transact(opts, "ccipSend", destinationChainSelector, message)
+}
+
+func (_Router *RouterSession) CcipSend(destinationChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _Router.Contract.CcipSend(&_Router.TransactOpts, destinationChainSelector, message)
+}
+
+func (_Router *RouterTransactorSession) CcipSend(destinationChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error) {
+ return _Router.Contract.CcipSend(&_Router.TransactOpts, destinationChainSelector, message)
+}
+
+func (_Router *RouterTransactor) RecoverTokens(opts *bind.TransactOpts, tokenAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) {
+ return _Router.contract.Transact(opts, "recoverTokens", tokenAddress, to, amount)
+}
+
+func (_Router *RouterSession) RecoverTokens(tokenAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) {
+ return _Router.Contract.RecoverTokens(&_Router.TransactOpts, tokenAddress, to, amount)
+}
+
+func (_Router *RouterTransactorSession) RecoverTokens(tokenAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) {
+ return _Router.Contract.RecoverTokens(&_Router.TransactOpts, tokenAddress, to, amount)
+}
+
+func (_Router *RouterTransactor) RouteMessage(opts *bind.TransactOpts, message ClientAny2EVMMessage, gasForCallExactCheck uint16, gasLimit *big.Int, receiver common.Address) (*types.Transaction, error) {
+ return _Router.contract.Transact(opts, "routeMessage", message, gasForCallExactCheck, gasLimit, receiver)
+}
+
+func (_Router *RouterSession) RouteMessage(message ClientAny2EVMMessage, gasForCallExactCheck uint16, gasLimit *big.Int, receiver common.Address) (*types.Transaction, error) {
+ return _Router.Contract.RouteMessage(&_Router.TransactOpts, message, gasForCallExactCheck, gasLimit, receiver)
+}
+
+func (_Router *RouterTransactorSession) RouteMessage(message ClientAny2EVMMessage, gasForCallExactCheck uint16, gasLimit *big.Int, receiver common.Address) (*types.Transaction, error) {
+ return _Router.Contract.RouteMessage(&_Router.TransactOpts, message, gasForCallExactCheck, gasLimit, receiver)
+}
+
+func (_Router *RouterTransactor) SetWrappedNative(opts *bind.TransactOpts, wrappedNative common.Address) (*types.Transaction, error) {
+ return _Router.contract.Transact(opts, "setWrappedNative", wrappedNative)
+}
+
+func (_Router *RouterSession) SetWrappedNative(wrappedNative common.Address) (*types.Transaction, error) {
+ return _Router.Contract.SetWrappedNative(&_Router.TransactOpts, wrappedNative)
+}
+
+func (_Router *RouterTransactorSession) SetWrappedNative(wrappedNative common.Address) (*types.Transaction, error) {
+ return _Router.Contract.SetWrappedNative(&_Router.TransactOpts, wrappedNative)
+}
+
+func (_Router *RouterTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _Router.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_Router *RouterSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _Router.Contract.TransferOwnership(&_Router.TransactOpts, to)
+}
+
+func (_Router *RouterTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _Router.Contract.TransferOwnership(&_Router.TransactOpts, to)
+}
+
+type RouterMessageExecutedIterator struct {
+ Event *RouterMessageExecuted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *RouterMessageExecutedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(RouterMessageExecuted)
+ 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(RouterMessageExecuted)
+ 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 *RouterMessageExecutedIterator) Error() error {
+ return it.fail
+}
+
+func (it *RouterMessageExecutedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type RouterMessageExecuted struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ OffRamp common.Address
+ CalldataHash [32]byte
+ Raw types.Log
+}
+
+func (_Router *RouterFilterer) FilterMessageExecuted(opts *bind.FilterOpts) (*RouterMessageExecutedIterator, error) {
+
+ logs, sub, err := _Router.contract.FilterLogs(opts, "MessageExecuted")
+ if err != nil {
+ return nil, err
+ }
+ return &RouterMessageExecutedIterator{contract: _Router.contract, event: "MessageExecuted", logs: logs, sub: sub}, nil
+}
+
+func (_Router *RouterFilterer) WatchMessageExecuted(opts *bind.WatchOpts, sink chan<- *RouterMessageExecuted) (event.Subscription, error) {
+
+ logs, sub, err := _Router.contract.WatchLogs(opts, "MessageExecuted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(RouterMessageExecuted)
+ if err := _Router.contract.UnpackLog(event, "MessageExecuted", 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 (_Router *RouterFilterer) ParseMessageExecuted(log types.Log) (*RouterMessageExecuted, error) {
+ event := new(RouterMessageExecuted)
+ if err := _Router.contract.UnpackLog(event, "MessageExecuted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type RouterOffRampAddedIterator struct {
+ Event *RouterOffRampAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *RouterOffRampAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(RouterOffRampAdded)
+ 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(RouterOffRampAdded)
+ 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 *RouterOffRampAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *RouterOffRampAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type RouterOffRampAdded struct {
+ SourceChainSelector uint64
+ OffRamp common.Address
+ Raw types.Log
+}
+
+func (_Router *RouterFilterer) FilterOffRampAdded(opts *bind.FilterOpts, sourceChainSelector []uint64) (*RouterOffRampAddedIterator, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+
+ logs, sub, err := _Router.contract.FilterLogs(opts, "OffRampAdded", sourceChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &RouterOffRampAddedIterator{contract: _Router.contract, event: "OffRampAdded", logs: logs, sub: sub}, nil
+}
+
+func (_Router *RouterFilterer) WatchOffRampAdded(opts *bind.WatchOpts, sink chan<- *RouterOffRampAdded, sourceChainSelector []uint64) (event.Subscription, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+
+ logs, sub, err := _Router.contract.WatchLogs(opts, "OffRampAdded", sourceChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(RouterOffRampAdded)
+ if err := _Router.contract.UnpackLog(event, "OffRampAdded", 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 (_Router *RouterFilterer) ParseOffRampAdded(log types.Log) (*RouterOffRampAdded, error) {
+ event := new(RouterOffRampAdded)
+ if err := _Router.contract.UnpackLog(event, "OffRampAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type RouterOffRampRemovedIterator struct {
+ Event *RouterOffRampRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *RouterOffRampRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(RouterOffRampRemoved)
+ 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(RouterOffRampRemoved)
+ 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 *RouterOffRampRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *RouterOffRampRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type RouterOffRampRemoved struct {
+ SourceChainSelector uint64
+ OffRamp common.Address
+ Raw types.Log
+}
+
+func (_Router *RouterFilterer) FilterOffRampRemoved(opts *bind.FilterOpts, sourceChainSelector []uint64) (*RouterOffRampRemovedIterator, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+
+ logs, sub, err := _Router.contract.FilterLogs(opts, "OffRampRemoved", sourceChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &RouterOffRampRemovedIterator{contract: _Router.contract, event: "OffRampRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_Router *RouterFilterer) WatchOffRampRemoved(opts *bind.WatchOpts, sink chan<- *RouterOffRampRemoved, sourceChainSelector []uint64) (event.Subscription, error) {
+
+ var sourceChainSelectorRule []interface{}
+ for _, sourceChainSelectorItem := range sourceChainSelector {
+ sourceChainSelectorRule = append(sourceChainSelectorRule, sourceChainSelectorItem)
+ }
+
+ logs, sub, err := _Router.contract.WatchLogs(opts, "OffRampRemoved", sourceChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(RouterOffRampRemoved)
+ if err := _Router.contract.UnpackLog(event, "OffRampRemoved", 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 (_Router *RouterFilterer) ParseOffRampRemoved(log types.Log) (*RouterOffRampRemoved, error) {
+ event := new(RouterOffRampRemoved)
+ if err := _Router.contract.UnpackLog(event, "OffRampRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type RouterOnRampSetIterator struct {
+ Event *RouterOnRampSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *RouterOnRampSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(RouterOnRampSet)
+ 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(RouterOnRampSet)
+ 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 *RouterOnRampSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *RouterOnRampSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type RouterOnRampSet struct {
+ DestChainSelector uint64
+ OnRamp common.Address
+ Raw types.Log
+}
+
+func (_Router *RouterFilterer) FilterOnRampSet(opts *bind.FilterOpts, destChainSelector []uint64) (*RouterOnRampSetIterator, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _Router.contract.FilterLogs(opts, "OnRampSet", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &RouterOnRampSetIterator{contract: _Router.contract, event: "OnRampSet", logs: logs, sub: sub}, nil
+}
+
+func (_Router *RouterFilterer) WatchOnRampSet(opts *bind.WatchOpts, sink chan<- *RouterOnRampSet, destChainSelector []uint64) (event.Subscription, error) {
+
+ var destChainSelectorRule []interface{}
+ for _, destChainSelectorItem := range destChainSelector {
+ destChainSelectorRule = append(destChainSelectorRule, destChainSelectorItem)
+ }
+
+ logs, sub, err := _Router.contract.WatchLogs(opts, "OnRampSet", destChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(RouterOnRampSet)
+ if err := _Router.contract.UnpackLog(event, "OnRampSet", 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 (_Router *RouterFilterer) ParseOnRampSet(log types.Log) (*RouterOnRampSet, error) {
+ event := new(RouterOnRampSet)
+ if err := _Router.contract.UnpackLog(event, "OnRampSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type RouterOwnershipTransferRequestedIterator struct {
+ Event *RouterOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *RouterOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(RouterOwnershipTransferRequested)
+ 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(RouterOwnershipTransferRequested)
+ 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 *RouterOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *RouterOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type RouterOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_Router *RouterFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*RouterOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _Router.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &RouterOwnershipTransferRequestedIterator{contract: _Router.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_Router *RouterFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *RouterOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _Router.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(RouterOwnershipTransferRequested)
+ if err := _Router.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_Router *RouterFilterer) ParseOwnershipTransferRequested(log types.Log) (*RouterOwnershipTransferRequested, error) {
+ event := new(RouterOwnershipTransferRequested)
+ if err := _Router.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type RouterOwnershipTransferredIterator struct {
+ Event *RouterOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *RouterOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(RouterOwnershipTransferred)
+ 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(RouterOwnershipTransferred)
+ 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 *RouterOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *RouterOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type RouterOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_Router *RouterFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*RouterOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _Router.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &RouterOwnershipTransferredIterator{contract: _Router.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_Router *RouterFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *RouterOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _Router.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(RouterOwnershipTransferred)
+ if err := _Router.contract.UnpackLog(event, "OwnershipTransferred", 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 (_Router *RouterFilterer) ParseOwnershipTransferred(log types.Log) (*RouterOwnershipTransferred, error) {
+ event := new(RouterOwnershipTransferred)
+ if err := _Router.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_Router *Router) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _Router.abi.Events["MessageExecuted"].ID:
+ return _Router.ParseMessageExecuted(log)
+ case _Router.abi.Events["OffRampAdded"].ID:
+ return _Router.ParseOffRampAdded(log)
+ case _Router.abi.Events["OffRampRemoved"].ID:
+ return _Router.ParseOffRampRemoved(log)
+ case _Router.abi.Events["OnRampSet"].ID:
+ return _Router.ParseOnRampSet(log)
+ case _Router.abi.Events["OwnershipTransferRequested"].ID:
+ return _Router.ParseOwnershipTransferRequested(log)
+ case _Router.abi.Events["OwnershipTransferred"].ID:
+ return _Router.ParseOwnershipTransferred(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (RouterMessageExecuted) Topic() common.Hash {
+ return common.HexToHash("0x9b877de93ea9895756e337442c657f95a34fc68e7eb988bdfa693d5be83016b6")
+}
+
+func (RouterOffRampAdded) Topic() common.Hash {
+ return common.HexToHash("0xa4bdf64ebdf3316320601a081916a75aa144bcef6c4beeb0e9fb1982cacc6b94")
+}
+
+func (RouterOffRampRemoved) Topic() common.Hash {
+ return common.HexToHash("0xa823809efda3ba66c873364eec120fa0923d9fabda73bc97dd5663341e2d9bcb")
+}
+
+func (RouterOnRampSet) Topic() common.Hash {
+ return common.HexToHash("0x1f7d0ec248b80e5c0dde0ee531c4fc8fdb6ce9a2b3d90f560c74acd6a7202f23")
+}
+
+func (RouterOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (RouterOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (_Router *Router) Address() common.Address {
+ return _Router.address
+}
+
+type RouterInterface interface {
+ MAXRETBYTES(opts *bind.CallOpts) (uint16, error)
+
+ GetArmProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetFee(opts *bind.CallOpts, destinationChainSelector uint64, message ClientEVM2AnyMessage) (*big.Int, error)
+
+ GetOffRamps(opts *bind.CallOpts) ([]RouterOffRamp, error)
+
+ GetOnRamp(opts *bind.CallOpts, destChainSelector uint64) (common.Address, error)
+
+ GetSupportedTokens(opts *bind.CallOpts, chainSelector uint64) ([]common.Address, error)
+
+ GetWrappedNative(opts *bind.CallOpts) (common.Address, error)
+
+ IsChainSupported(opts *bind.CallOpts, chainSelector uint64) (bool, error)
+
+ IsOffRamp(opts *bind.CallOpts, sourceChainSelector uint64, offRamp common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyRampUpdates(opts *bind.TransactOpts, onRampUpdates []RouterOnRamp, offRampRemoves []RouterOffRamp, offRampAdds []RouterOffRamp) (*types.Transaction, error)
+
+ CcipSend(opts *bind.TransactOpts, destinationChainSelector uint64, message ClientEVM2AnyMessage) (*types.Transaction, error)
+
+ RecoverTokens(opts *bind.TransactOpts, tokenAddress common.Address, to common.Address, amount *big.Int) (*types.Transaction, error)
+
+ RouteMessage(opts *bind.TransactOpts, message ClientAny2EVMMessage, gasForCallExactCheck uint16, gasLimit *big.Int, receiver common.Address) (*types.Transaction, error)
+
+ SetWrappedNative(opts *bind.TransactOpts, wrappedNative common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterMessageExecuted(opts *bind.FilterOpts) (*RouterMessageExecutedIterator, error)
+
+ WatchMessageExecuted(opts *bind.WatchOpts, sink chan<- *RouterMessageExecuted) (event.Subscription, error)
+
+ ParseMessageExecuted(log types.Log) (*RouterMessageExecuted, error)
+
+ FilterOffRampAdded(opts *bind.FilterOpts, sourceChainSelector []uint64) (*RouterOffRampAddedIterator, error)
+
+ WatchOffRampAdded(opts *bind.WatchOpts, sink chan<- *RouterOffRampAdded, sourceChainSelector []uint64) (event.Subscription, error)
+
+ ParseOffRampAdded(log types.Log) (*RouterOffRampAdded, error)
+
+ FilterOffRampRemoved(opts *bind.FilterOpts, sourceChainSelector []uint64) (*RouterOffRampRemovedIterator, error)
+
+ WatchOffRampRemoved(opts *bind.WatchOpts, sink chan<- *RouterOffRampRemoved, sourceChainSelector []uint64) (event.Subscription, error)
+
+ ParseOffRampRemoved(log types.Log) (*RouterOffRampRemoved, error)
+
+ FilterOnRampSet(opts *bind.FilterOpts, destChainSelector []uint64) (*RouterOnRampSetIterator, error)
+
+ WatchOnRampSet(opts *bind.WatchOpts, sink chan<- *RouterOnRampSet, destChainSelector []uint64) (event.Subscription, error)
+
+ ParseOnRampSet(log types.Log) (*RouterOnRampSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*RouterOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *RouterOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*RouterOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*RouterOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *RouterOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*RouterOwnershipTransferred, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/self_funded_ping_pong/self_funded_ping_pong.go b/core/gethwrappers/ccip/generated/self_funded_ping_pong/self_funded_ping_pong.go
new file mode 100644
index 00000000000..d6e2db6bf37
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/self_funded_ping_pong/self_funded_ping_pong.go
@@ -0,0 +1,1370 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package self_funded_ping_pong
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ClientAny2EVMMessage struct {
+ MessageId [32]byte
+ SourceChainSelector uint64
+ Sender []byte
+ Data []byte
+ DestTokenAmounts []ClientEVMTokenAmount
+}
+
+type ClientEVMTokenAmount struct {
+ Token common.Address
+ Amount *big.Int
+}
+
+var SelfFundedPingPongMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"internalType\":\"contractIERC20\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"roundTripsBeforeFunding\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"name\":\"InvalidRouter\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"countIncrBeforeFunding\",\"type\":\"uint8\"}],\"name\":\"CountIncrBeforeFundingSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[],\"name\":\"Funded\",\"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\":\"pingPongCount\",\"type\":\"uint256\"}],\"name\":\"Ping\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"pingPongCount\",\"type\":\"uint256\"}],\"name\":\"Pong\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"destTokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structClient.Any2EVMMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"ccipReceive\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"pingPongCount\",\"type\":\"uint256\"}],\"name\":\"fundPingPong\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCountIncrBeforeFunding\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCounterpartAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCounterpartChainSelector\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isPaused\",\"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\":\"uint8\",\"name\":\"countIncrBeforeFunding\",\"type\":\"uint8\"}],\"name\":\"setCountIncrBeforeFunding\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"counterpartChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"counterpartAddress\",\"type\":\"address\"}],\"name\":\"setCounterpart\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setCounterpartAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"setCounterpartChainSelector\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"pause\",\"type\":\"bool\"}],\"name\":\"setPaused\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startPingPong\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"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\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x60a06040523480156200001157600080fd5b506040516200182238038062001822833981016040819052620000349162000291565b828233806000846001600160a01b0381166200006b576040516335fdcccd60e21b8152600060048201526024015b60405180910390fd5b6001600160a01b039081166080528216620000c95760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f0000000000000000604482015260640162000062565b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000fc57620000fc81620001cd565b50506002805460ff60a01b1916905550600380546001600160a01b0319166001600160a01b0383811691821790925560405163095ea7b360e01b8152918416600483015260001960248301529063095ea7b3906044016020604051808303816000875af115801562000172573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001989190620002ea565b505050806002620001aa919062000315565b600360146101000a81548160ff021916908360ff16021790555050505062000347565b336001600160a01b03821603620002275760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000062565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200028e57600080fd5b50565b600080600060608486031215620002a757600080fd5b8351620002b48162000278565b6020850151909350620002c78162000278565b604085015190925060ff81168114620002df57600080fd5b809150509250925092565b600060208284031215620002fd57600080fd5b815180151581146200030e57600080fd5b9392505050565b60ff81811683821602908116908181146200034057634e487b7160e01b600052601160045260246000fd5b5092915050565b6080516114aa62000378600039600081816102970152818161063f0152818161072c0152610c2201526114aa6000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c80638f491cba116100cd578063bee518a411610081578063e6c725f511610066578063e6c725f51461034d578063ef686d8e1461037d578063f2fde38b1461039057600080fd5b8063bee518a4146102f1578063ca709a251461032f57600080fd5b8063b0f479a1116100b2578063b0f479a114610295578063b187bd26146102bb578063b5a11011146102de57600080fd5b80638f491cba1461026f5780639d2aede51461028257600080fd5b80632874d8bf1161012457806379ba50971161010957806379ba50971461023657806385572ffb1461023e5780638da5cb5b1461025157600080fd5b80632874d8bf146101ef5780632b6e5d63146101f757600080fd5b806301ffc9a71461015657806316c38b3c1461017e578063181f5a77146101935780631892b906146101dc575b600080fd5b610169610164366004610e24565b6103a3565b60405190151581526020015b60405180910390f35b61019161018c366004610e6d565b61043c565b005b6101cf6040518060400160405280601881526020017f53656c6646756e64656450696e67506f6e6720312e322e30000000000000000081525081565b6040516101759190610ef3565b6101916101ea366004610f23565b61048e565b6101916104e9565b60025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610175565b610191610525565b61019161024c366004610f3e565b610627565b60005473ffffffffffffffffffffffffffffffffffffffff16610211565b61019161027d366004610f79565b6106ac565b610191610290366004610fb4565b61088b565b7f0000000000000000000000000000000000000000000000000000000000000000610211565b60025474010000000000000000000000000000000000000000900460ff16610169565b6101916102ec366004610fd1565b6108da565b60015474010000000000000000000000000000000000000000900467ffffffffffffffff1660405167ffffffffffffffff9091168152602001610175565b60035473ffffffffffffffffffffffffffffffffffffffff16610211565b60035474010000000000000000000000000000000000000000900460ff1660405160ff9091168152602001610175565b61019161038b366004611008565b61097c565b61019161039e366004610fb4565b610a04565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f85572ffb00000000000000000000000000000000000000000000000000000000148061043657507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b610444610a15565b6002805491151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179055565b610496610a15565b6001805467ffffffffffffffff90921674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff909216919091179055565b6104f1610a15565b600280547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556105236001610a96565b565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105ab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610698576040517fd7f733340000000000000000000000000000000000000000000000000000000081523360048201526024016105a2565b6106a96106a482611230565b610cd9565b50565b60035474010000000000000000000000000000000000000000900460ff1615806106f2575060035474010000000000000000000000000000000000000000900460ff1681105b156106fa5750565b6003546001906107259074010000000000000000000000000000000000000000900460ff16836112dd565b116106a9577f00000000000000000000000000000000000000000000000000000000000000006001546040517fa8d87a3b0000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910467ffffffffffffffff16600482015273ffffffffffffffffffffffffffffffffffffffff919091169063a8d87a3b90602401602060405180830381865afa1580156107dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108009190611318565b73ffffffffffffffffffffffffffffffffffffffff1663eff7cc486040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561084757600080fd5b505af115801561085b573d6000803e3d6000fd5b50506040517f302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c925060009150a150565b610893610a15565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6108e2610a15565b6001805467ffffffffffffffff90931674010000000000000000000000000000000000000000027fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff909316929092179091556002805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216919091179055565b610984610a15565b600380547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000060ff8416908102919091179091556040519081527f4768dbf8645b24c54f2887651545d24f748c0d0d1d4c689eb810fb19f0befcf39060200160405180910390a150565b610a0c610a15565b6106a981610d2f565b60005473ffffffffffffffffffffffffffffffffffffffff163314610523576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105a2565b80600116600103610ad9576040518181527f48257dc961b6f792c2b78a080dacfed693b660960a702de21cee364e20270e2f9060200160405180910390a1610b0d565b6040518181527f58b69f57828e6962d216502094c54f6562f3bf082ba758966c3454f9e37b15259060200160405180910390a15b610b16816106ac565b6040805160a0810190915260025473ffffffffffffffffffffffffffffffffffffffff1660c08201526000908060e08101604051602081830303815290604052815260200183604051602001610b6e91815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905281526020016000604051908082528060200260200182016040528015610be857816020015b6040805180820190915260008082526020820152815260200190600190039081610bc15790505b50815260035473ffffffffffffffffffffffffffffffffffffffff16602080830191909152604080519182018152600082529091015290507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166396f4e9f9600160149054906101000a900467ffffffffffffffff16836040518363ffffffff1660e01b8152600401610c91929190611335565b6020604051808303816000875af1158015610cb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd4919061144a565b505050565b60008160600151806020019051810190610cf3919061144a565b60025490915074010000000000000000000000000000000000000000900460ff16610d2b57610d2b610d26826001611463565b610a96565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603610dae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105a2565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215610e3657600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610e6657600080fd5b9392505050565b600060208284031215610e7f57600080fd5b81358015158114610e6657600080fd5b6000815180845260005b81811015610eb557602081850181015186830182015201610e99565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610e666020830184610e8f565b803567ffffffffffffffff81168114610f1e57600080fd5b919050565b600060208284031215610f3557600080fd5b610e6682610f06565b600060208284031215610f5057600080fd5b813567ffffffffffffffff811115610f6757600080fd5b820160a08185031215610e6657600080fd5b600060208284031215610f8b57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146106a957600080fd5b600060208284031215610fc657600080fd5b8135610e6681610f92565b60008060408385031215610fe457600080fd5b610fed83610f06565b91506020830135610ffd81610f92565b809150509250929050565b60006020828403121561101a57600080fd5b813560ff81168114610e6657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561107d5761107d61102b565b60405290565b60405160a0810167ffffffffffffffff8111828210171561107d5761107d61102b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156110ed576110ed61102b565b604052919050565b600082601f83011261110657600080fd5b813567ffffffffffffffff8111156111205761112061102b565b61115160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016110a6565b81815284602083860101111561116657600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261119457600080fd5b8135602067ffffffffffffffff8211156111b0576111b061102b565b6111be818360051b016110a6565b82815260069290921b840181019181810190868411156111dd57600080fd5b8286015b8481101561122557604081890312156111fa5760008081fd5b61120261105a565b813561120d81610f92565b815281850135858201528352918301916040016111e1565b509695505050505050565b600060a0823603121561124257600080fd5b61124a611083565b8235815261125a60208401610f06565b6020820152604083013567ffffffffffffffff8082111561127a57600080fd5b611286368387016110f5565b6040840152606085013591508082111561129f57600080fd5b6112ab368387016110f5565b606084015260808501359150808211156112c457600080fd5b506112d136828601611183565b60808301525092915050565b600082611313577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b60006020828403121561132a57600080fd5b8151610e6681610f92565b6000604067ffffffffffffffff851683526020604081850152845160a0604086015261136460e0860182610e8f565b9050818601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08087840301606088015261139f8383610e8f565b6040890151888203830160808a01528051808352908601945060009350908501905b80841015611400578451805173ffffffffffffffffffffffffffffffffffffffff168352860151868301529385019360019390930192908601906113c1565b50606089015173ffffffffffffffffffffffffffffffffffffffff1660a08901526080890151888203830160c08a0152955061143c8187610e8f565b9a9950505050505050505050565b60006020828403121561145c57600080fd5b5051919050565b80820180821115610436577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea164736f6c6343000818000a",
+}
+
+var SelfFundedPingPongABI = SelfFundedPingPongMetaData.ABI
+
+var SelfFundedPingPongBin = SelfFundedPingPongMetaData.Bin
+
+func DeploySelfFundedPingPong(auth *bind.TransactOpts, backend bind.ContractBackend, router common.Address, feeToken common.Address, roundTripsBeforeFunding uint8) (common.Address, *types.Transaction, *SelfFundedPingPong, error) {
+ parsed, err := SelfFundedPingPongMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SelfFundedPingPongBin), backend, router, feeToken, roundTripsBeforeFunding)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &SelfFundedPingPong{address: address, abi: *parsed, SelfFundedPingPongCaller: SelfFundedPingPongCaller{contract: contract}, SelfFundedPingPongTransactor: SelfFundedPingPongTransactor{contract: contract}, SelfFundedPingPongFilterer: SelfFundedPingPongFilterer{contract: contract}}, nil
+}
+
+type SelfFundedPingPong struct {
+ address common.Address
+ abi abi.ABI
+ SelfFundedPingPongCaller
+ SelfFundedPingPongTransactor
+ SelfFundedPingPongFilterer
+}
+
+type SelfFundedPingPongCaller struct {
+ contract *bind.BoundContract
+}
+
+type SelfFundedPingPongTransactor struct {
+ contract *bind.BoundContract
+}
+
+type SelfFundedPingPongFilterer struct {
+ contract *bind.BoundContract
+}
+
+type SelfFundedPingPongSession struct {
+ Contract *SelfFundedPingPong
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type SelfFundedPingPongCallerSession struct {
+ Contract *SelfFundedPingPongCaller
+ CallOpts bind.CallOpts
+}
+
+type SelfFundedPingPongTransactorSession struct {
+ Contract *SelfFundedPingPongTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type SelfFundedPingPongRaw struct {
+ Contract *SelfFundedPingPong
+}
+
+type SelfFundedPingPongCallerRaw struct {
+ Contract *SelfFundedPingPongCaller
+}
+
+type SelfFundedPingPongTransactorRaw struct {
+ Contract *SelfFundedPingPongTransactor
+}
+
+func NewSelfFundedPingPong(address common.Address, backend bind.ContractBackend) (*SelfFundedPingPong, error) {
+ abi, err := abi.JSON(strings.NewReader(SelfFundedPingPongABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindSelfFundedPingPong(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPong{address: address, abi: abi, SelfFundedPingPongCaller: SelfFundedPingPongCaller{contract: contract}, SelfFundedPingPongTransactor: SelfFundedPingPongTransactor{contract: contract}, SelfFundedPingPongFilterer: SelfFundedPingPongFilterer{contract: contract}}, nil
+}
+
+func NewSelfFundedPingPongCaller(address common.Address, caller bind.ContractCaller) (*SelfFundedPingPongCaller, error) {
+ contract, err := bindSelfFundedPingPong(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongCaller{contract: contract}, nil
+}
+
+func NewSelfFundedPingPongTransactor(address common.Address, transactor bind.ContractTransactor) (*SelfFundedPingPongTransactor, error) {
+ contract, err := bindSelfFundedPingPong(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongTransactor{contract: contract}, nil
+}
+
+func NewSelfFundedPingPongFilterer(address common.Address, filterer bind.ContractFilterer) (*SelfFundedPingPongFilterer, error) {
+ contract, err := bindSelfFundedPingPong(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongFilterer{contract: contract}, nil
+}
+
+func bindSelfFundedPingPong(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := SelfFundedPingPongMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _SelfFundedPingPong.Contract.SelfFundedPingPongCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SelfFundedPingPongTransactor.contract.Transfer(opts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SelfFundedPingPongTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _SelfFundedPingPong.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.contract.Transfer(opts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) GetCountIncrBeforeFunding(opts *bind.CallOpts) (uint8, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "getCountIncrBeforeFunding")
+
+ if err != nil {
+ return *new(uint8), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) GetCountIncrBeforeFunding() (uint8, error) {
+ return _SelfFundedPingPong.Contract.GetCountIncrBeforeFunding(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) GetCountIncrBeforeFunding() (uint8, error) {
+ return _SelfFundedPingPong.Contract.GetCountIncrBeforeFunding(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) GetCounterpartAddress(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "getCounterpartAddress")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) GetCounterpartAddress() (common.Address, error) {
+ return _SelfFundedPingPong.Contract.GetCounterpartAddress(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) GetCounterpartAddress() (common.Address, error) {
+ return _SelfFundedPingPong.Contract.GetCounterpartAddress(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) GetCounterpartChainSelector(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "getCounterpartChainSelector")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) GetCounterpartChainSelector() (uint64, error) {
+ return _SelfFundedPingPong.Contract.GetCounterpartChainSelector(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) GetCounterpartChainSelector() (uint64, error) {
+ return _SelfFundedPingPong.Contract.GetCounterpartChainSelector(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) GetFeeToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "getFeeToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) GetFeeToken() (common.Address, error) {
+ return _SelfFundedPingPong.Contract.GetFeeToken(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) GetFeeToken() (common.Address, error) {
+ return _SelfFundedPingPong.Contract.GetFeeToken(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) GetRouter() (common.Address, error) {
+ return _SelfFundedPingPong.Contract.GetRouter(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) GetRouter() (common.Address, error) {
+ return _SelfFundedPingPong.Contract.GetRouter(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) IsPaused(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "isPaused")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) IsPaused() (bool, error) {
+ return _SelfFundedPingPong.Contract.IsPaused(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) IsPaused() (bool, error) {
+ return _SelfFundedPingPong.Contract.IsPaused(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) Owner() (common.Address, error) {
+ return _SelfFundedPingPong.Contract.Owner(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) Owner() (common.Address, error) {
+ return _SelfFundedPingPong.Contract.Owner(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _SelfFundedPingPong.Contract.SupportsInterface(&_SelfFundedPingPong.CallOpts, interfaceId)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _SelfFundedPingPong.Contract.SupportsInterface(&_SelfFundedPingPong.CallOpts, interfaceId)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _SelfFundedPingPong.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) TypeAndVersion() (string, error) {
+ return _SelfFundedPingPong.Contract.TypeAndVersion(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongCallerSession) TypeAndVersion() (string, error) {
+ return _SelfFundedPingPong.Contract.TypeAndVersion(&_SelfFundedPingPong.CallOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) AcceptOwnership() (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.AcceptOwnership(&_SelfFundedPingPong.TransactOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.AcceptOwnership(&_SelfFundedPingPong.TransactOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) CcipReceive(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "ccipReceive", message)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) CcipReceive(message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.CcipReceive(&_SelfFundedPingPong.TransactOpts, message)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) CcipReceive(message ClientAny2EVMMessage) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.CcipReceive(&_SelfFundedPingPong.TransactOpts, message)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) FundPingPong(opts *bind.TransactOpts, pingPongCount *big.Int) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "fundPingPong", pingPongCount)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) FundPingPong(pingPongCount *big.Int) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.FundPingPong(&_SelfFundedPingPong.TransactOpts, pingPongCount)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) FundPingPong(pingPongCount *big.Int) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.FundPingPong(&_SelfFundedPingPong.TransactOpts, pingPongCount)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) SetCountIncrBeforeFunding(opts *bind.TransactOpts, countIncrBeforeFunding uint8) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "setCountIncrBeforeFunding", countIncrBeforeFunding)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) SetCountIncrBeforeFunding(countIncrBeforeFunding uint8) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetCountIncrBeforeFunding(&_SelfFundedPingPong.TransactOpts, countIncrBeforeFunding)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) SetCountIncrBeforeFunding(countIncrBeforeFunding uint8) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetCountIncrBeforeFunding(&_SelfFundedPingPong.TransactOpts, countIncrBeforeFunding)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) SetCounterpart(opts *bind.TransactOpts, counterpartChainSelector uint64, counterpartAddress common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "setCounterpart", counterpartChainSelector, counterpartAddress)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) SetCounterpart(counterpartChainSelector uint64, counterpartAddress common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetCounterpart(&_SelfFundedPingPong.TransactOpts, counterpartChainSelector, counterpartAddress)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) SetCounterpart(counterpartChainSelector uint64, counterpartAddress common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetCounterpart(&_SelfFundedPingPong.TransactOpts, counterpartChainSelector, counterpartAddress)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) SetCounterpartAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "setCounterpartAddress", addr)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) SetCounterpartAddress(addr common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetCounterpartAddress(&_SelfFundedPingPong.TransactOpts, addr)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) SetCounterpartAddress(addr common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetCounterpartAddress(&_SelfFundedPingPong.TransactOpts, addr)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) SetCounterpartChainSelector(opts *bind.TransactOpts, chainSelector uint64) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "setCounterpartChainSelector", chainSelector)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) SetCounterpartChainSelector(chainSelector uint64) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetCounterpartChainSelector(&_SelfFundedPingPong.TransactOpts, chainSelector)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) SetCounterpartChainSelector(chainSelector uint64) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetCounterpartChainSelector(&_SelfFundedPingPong.TransactOpts, chainSelector)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) SetPaused(opts *bind.TransactOpts, pause bool) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "setPaused", pause)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) SetPaused(pause bool) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetPaused(&_SelfFundedPingPong.TransactOpts, pause)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) SetPaused(pause bool) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.SetPaused(&_SelfFundedPingPong.TransactOpts, pause)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) StartPingPong(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "startPingPong")
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) StartPingPong() (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.StartPingPong(&_SelfFundedPingPong.TransactOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) StartPingPong() (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.StartPingPong(&_SelfFundedPingPong.TransactOpts)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.TransferOwnership(&_SelfFundedPingPong.TransactOpts, to)
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _SelfFundedPingPong.Contract.TransferOwnership(&_SelfFundedPingPong.TransactOpts, to)
+}
+
+type SelfFundedPingPongCountIncrBeforeFundingSetIterator struct {
+ Event *SelfFundedPingPongCountIncrBeforeFundingSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *SelfFundedPingPongCountIncrBeforeFundingSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(SelfFundedPingPongCountIncrBeforeFundingSet)
+ 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(SelfFundedPingPongCountIncrBeforeFundingSet)
+ 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 *SelfFundedPingPongCountIncrBeforeFundingSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *SelfFundedPingPongCountIncrBeforeFundingSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type SelfFundedPingPongCountIncrBeforeFundingSet struct {
+ CountIncrBeforeFunding uint8
+ Raw types.Log
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) FilterCountIncrBeforeFundingSet(opts *bind.FilterOpts) (*SelfFundedPingPongCountIncrBeforeFundingSetIterator, error) {
+
+ logs, sub, err := _SelfFundedPingPong.contract.FilterLogs(opts, "CountIncrBeforeFundingSet")
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongCountIncrBeforeFundingSetIterator{contract: _SelfFundedPingPong.contract, event: "CountIncrBeforeFundingSet", logs: logs, sub: sub}, nil
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) WatchCountIncrBeforeFundingSet(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongCountIncrBeforeFundingSet) (event.Subscription, error) {
+
+ logs, sub, err := _SelfFundedPingPong.contract.WatchLogs(opts, "CountIncrBeforeFundingSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(SelfFundedPingPongCountIncrBeforeFundingSet)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "CountIncrBeforeFundingSet", 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 (_SelfFundedPingPong *SelfFundedPingPongFilterer) ParseCountIncrBeforeFundingSet(log types.Log) (*SelfFundedPingPongCountIncrBeforeFundingSet, error) {
+ event := new(SelfFundedPingPongCountIncrBeforeFundingSet)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "CountIncrBeforeFundingSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type SelfFundedPingPongFundedIterator struct {
+ Event *SelfFundedPingPongFunded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *SelfFundedPingPongFundedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(SelfFundedPingPongFunded)
+ 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(SelfFundedPingPongFunded)
+ 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 *SelfFundedPingPongFundedIterator) Error() error {
+ return it.fail
+}
+
+func (it *SelfFundedPingPongFundedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type SelfFundedPingPongFunded struct {
+ Raw types.Log
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) FilterFunded(opts *bind.FilterOpts) (*SelfFundedPingPongFundedIterator, error) {
+
+ logs, sub, err := _SelfFundedPingPong.contract.FilterLogs(opts, "Funded")
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongFundedIterator{contract: _SelfFundedPingPong.contract, event: "Funded", logs: logs, sub: sub}, nil
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) WatchFunded(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongFunded) (event.Subscription, error) {
+
+ logs, sub, err := _SelfFundedPingPong.contract.WatchLogs(opts, "Funded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(SelfFundedPingPongFunded)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "Funded", 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 (_SelfFundedPingPong *SelfFundedPingPongFilterer) ParseFunded(log types.Log) (*SelfFundedPingPongFunded, error) {
+ event := new(SelfFundedPingPongFunded)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "Funded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type SelfFundedPingPongOwnershipTransferRequestedIterator struct {
+ Event *SelfFundedPingPongOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *SelfFundedPingPongOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(SelfFundedPingPongOwnershipTransferRequested)
+ 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(SelfFundedPingPongOwnershipTransferRequested)
+ 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 *SelfFundedPingPongOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *SelfFundedPingPongOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type SelfFundedPingPongOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*SelfFundedPingPongOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _SelfFundedPingPong.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongOwnershipTransferRequestedIterator{contract: _SelfFundedPingPong.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _SelfFundedPingPong.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(SelfFundedPingPongOwnershipTransferRequested)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_SelfFundedPingPong *SelfFundedPingPongFilterer) ParseOwnershipTransferRequested(log types.Log) (*SelfFundedPingPongOwnershipTransferRequested, error) {
+ event := new(SelfFundedPingPongOwnershipTransferRequested)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type SelfFundedPingPongOwnershipTransferredIterator struct {
+ Event *SelfFundedPingPongOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *SelfFundedPingPongOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(SelfFundedPingPongOwnershipTransferred)
+ 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(SelfFundedPingPongOwnershipTransferred)
+ 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 *SelfFundedPingPongOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *SelfFundedPingPongOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type SelfFundedPingPongOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*SelfFundedPingPongOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _SelfFundedPingPong.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongOwnershipTransferredIterator{contract: _SelfFundedPingPong.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _SelfFundedPingPong.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(SelfFundedPingPongOwnershipTransferred)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "OwnershipTransferred", 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 (_SelfFundedPingPong *SelfFundedPingPongFilterer) ParseOwnershipTransferred(log types.Log) (*SelfFundedPingPongOwnershipTransferred, error) {
+ event := new(SelfFundedPingPongOwnershipTransferred)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type SelfFundedPingPongPingIterator struct {
+ Event *SelfFundedPingPongPing
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *SelfFundedPingPongPingIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(SelfFundedPingPongPing)
+ 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(SelfFundedPingPongPing)
+ 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 *SelfFundedPingPongPingIterator) Error() error {
+ return it.fail
+}
+
+func (it *SelfFundedPingPongPingIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type SelfFundedPingPongPing struct {
+ PingPongCount *big.Int
+ Raw types.Log
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) FilterPing(opts *bind.FilterOpts) (*SelfFundedPingPongPingIterator, error) {
+
+ logs, sub, err := _SelfFundedPingPong.contract.FilterLogs(opts, "Ping")
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongPingIterator{contract: _SelfFundedPingPong.contract, event: "Ping", logs: logs, sub: sub}, nil
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) WatchPing(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongPing) (event.Subscription, error) {
+
+ logs, sub, err := _SelfFundedPingPong.contract.WatchLogs(opts, "Ping")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(SelfFundedPingPongPing)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "Ping", 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 (_SelfFundedPingPong *SelfFundedPingPongFilterer) ParsePing(log types.Log) (*SelfFundedPingPongPing, error) {
+ event := new(SelfFundedPingPongPing)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "Ping", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type SelfFundedPingPongPongIterator struct {
+ Event *SelfFundedPingPongPong
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *SelfFundedPingPongPongIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(SelfFundedPingPongPong)
+ 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(SelfFundedPingPongPong)
+ 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 *SelfFundedPingPongPongIterator) Error() error {
+ return it.fail
+}
+
+func (it *SelfFundedPingPongPongIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type SelfFundedPingPongPong struct {
+ PingPongCount *big.Int
+ Raw types.Log
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) FilterPong(opts *bind.FilterOpts) (*SelfFundedPingPongPongIterator, error) {
+
+ logs, sub, err := _SelfFundedPingPong.contract.FilterLogs(opts, "Pong")
+ if err != nil {
+ return nil, err
+ }
+ return &SelfFundedPingPongPongIterator{contract: _SelfFundedPingPong.contract, event: "Pong", logs: logs, sub: sub}, nil
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPongFilterer) WatchPong(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongPong) (event.Subscription, error) {
+
+ logs, sub, err := _SelfFundedPingPong.contract.WatchLogs(opts, "Pong")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(SelfFundedPingPongPong)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "Pong", 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 (_SelfFundedPingPong *SelfFundedPingPongFilterer) ParsePong(log types.Log) (*SelfFundedPingPongPong, error) {
+ event := new(SelfFundedPingPongPong)
+ if err := _SelfFundedPingPong.contract.UnpackLog(event, "Pong", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPong) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _SelfFundedPingPong.abi.Events["CountIncrBeforeFundingSet"].ID:
+ return _SelfFundedPingPong.ParseCountIncrBeforeFundingSet(log)
+ case _SelfFundedPingPong.abi.Events["Funded"].ID:
+ return _SelfFundedPingPong.ParseFunded(log)
+ case _SelfFundedPingPong.abi.Events["OwnershipTransferRequested"].ID:
+ return _SelfFundedPingPong.ParseOwnershipTransferRequested(log)
+ case _SelfFundedPingPong.abi.Events["OwnershipTransferred"].ID:
+ return _SelfFundedPingPong.ParseOwnershipTransferred(log)
+ case _SelfFundedPingPong.abi.Events["Ping"].ID:
+ return _SelfFundedPingPong.ParsePing(log)
+ case _SelfFundedPingPong.abi.Events["Pong"].ID:
+ return _SelfFundedPingPong.ParsePong(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (SelfFundedPingPongCountIncrBeforeFundingSet) Topic() common.Hash {
+ return common.HexToHash("0x4768dbf8645b24c54f2887651545d24f748c0d0d1d4c689eb810fb19f0befcf3")
+}
+
+func (SelfFundedPingPongFunded) Topic() common.Hash {
+ return common.HexToHash("0x302777af5d26fab9dd5120c5f1307c65193ebc51daf33244ada4365fab10602c")
+}
+
+func (SelfFundedPingPongOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (SelfFundedPingPongOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (SelfFundedPingPongPing) Topic() common.Hash {
+ return common.HexToHash("0x48257dc961b6f792c2b78a080dacfed693b660960a702de21cee364e20270e2f")
+}
+
+func (SelfFundedPingPongPong) Topic() common.Hash {
+ return common.HexToHash("0x58b69f57828e6962d216502094c54f6562f3bf082ba758966c3454f9e37b1525")
+}
+
+func (_SelfFundedPingPong *SelfFundedPingPong) Address() common.Address {
+ return _SelfFundedPingPong.address
+}
+
+type SelfFundedPingPongInterface interface {
+ GetCountIncrBeforeFunding(opts *bind.CallOpts) (uint8, error)
+
+ GetCounterpartAddress(opts *bind.CallOpts) (common.Address, error)
+
+ GetCounterpartChainSelector(opts *bind.CallOpts) (uint64, error)
+
+ GetFeeToken(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ IsPaused(opts *bind.CallOpts) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ CcipReceive(opts *bind.TransactOpts, message ClientAny2EVMMessage) (*types.Transaction, error)
+
+ FundPingPong(opts *bind.TransactOpts, pingPongCount *big.Int) (*types.Transaction, error)
+
+ SetCountIncrBeforeFunding(opts *bind.TransactOpts, countIncrBeforeFunding uint8) (*types.Transaction, error)
+
+ SetCounterpart(opts *bind.TransactOpts, counterpartChainSelector uint64, counterpartAddress common.Address) (*types.Transaction, error)
+
+ SetCounterpartAddress(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error)
+
+ SetCounterpartChainSelector(opts *bind.TransactOpts, chainSelector uint64) (*types.Transaction, error)
+
+ SetPaused(opts *bind.TransactOpts, pause bool) (*types.Transaction, error)
+
+ StartPingPong(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterCountIncrBeforeFundingSet(opts *bind.FilterOpts) (*SelfFundedPingPongCountIncrBeforeFundingSetIterator, error)
+
+ WatchCountIncrBeforeFundingSet(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongCountIncrBeforeFundingSet) (event.Subscription, error)
+
+ ParseCountIncrBeforeFundingSet(log types.Log) (*SelfFundedPingPongCountIncrBeforeFundingSet, error)
+
+ FilterFunded(opts *bind.FilterOpts) (*SelfFundedPingPongFundedIterator, error)
+
+ WatchFunded(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongFunded) (event.Subscription, error)
+
+ ParseFunded(log types.Log) (*SelfFundedPingPongFunded, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*SelfFundedPingPongOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*SelfFundedPingPongOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*SelfFundedPingPongOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*SelfFundedPingPongOwnershipTransferred, error)
+
+ FilterPing(opts *bind.FilterOpts) (*SelfFundedPingPongPingIterator, error)
+
+ WatchPing(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongPing) (event.Subscription, error)
+
+ ParsePing(log types.Log) (*SelfFundedPingPongPing, error)
+
+ FilterPong(opts *bind.FilterOpts) (*SelfFundedPingPongPongIterator, error)
+
+ WatchPong(opts *bind.WatchOpts, sink chan<- *SelfFundedPingPongPong) (event.Subscription, error)
+
+ ParsePong(log types.Log) (*SelfFundedPingPongPong, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/token_admin_registry/token_admin_registry.go b/core/gethwrappers/ccip/generated/token_admin_registry/token_admin_registry.go
new file mode 100644
index 00000000000..189b4b600b4
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/token_admin_registry/token_admin_registry.go
@@ -0,0 +1,1795 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package token_admin_registry
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type TokenAdminRegistryTokenConfig struct {
+ Administrator common.Address
+ PendingAdministrator common.Address
+ TokenPool common.Address
+}
+
+var TokenAdminRegistryMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"AlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidTokenPoolToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"OnlyAdministrator\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"OnlyPendingAdministrator\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"OnlyRegistryModuleOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"currentAdmin\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdministratorTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdministratorTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"disabled\",\"type\":\"bool\"}],\"name\":\"DisableReRegistrationSet\",\"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\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousPool\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newPool\",\"type\":\"address\"}],\"name\":\"PoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"module\",\"type\":\"address\"}],\"name\":\"RegistryModuleAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"module\",\"type\":\"address\"}],\"name\":\"RegistryModuleRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"RemovedAdministrator\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"name\":\"acceptAdminRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"module\",\"type\":\"address\"}],\"name\":\"addRegistryModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"startIndex\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"maxCount\",\"type\":\"uint64\"}],\"name\":\"getAllConfiguredTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getPools\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"administrator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pendingAdministrator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenPool\",\"type\":\"address\"}],\"internalType\":\"structTokenAdminRegistry.TokenConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"administrator\",\"type\":\"address\"}],\"name\":\"isAdministrator\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"module\",\"type\":\"address\"}],\"name\":\"isRegistryModule\",\"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\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"administrator\",\"type\":\"address\"}],\"name\":\"proposeAdministrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"module\",\"type\":\"address\"}],\"name\":\"removeRegistryModule\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"setPool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"transferAdminRole\",\"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: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615610097576100978161009f565b505050610148565b336001600160a01b038216036100f75760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b611449806101576000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c80637d3f255211610097578063cb67e3b111610066578063cb67e3b1146102bc578063ddadfa8e14610374578063e677ae3714610387578063f2fde38b1461039a57600080fd5b80637d3f2552146101e05780638da5cb5b14610203578063bbe4f6db14610242578063c1af6e031461027f57600080fd5b80634e847fc7116100d35780634e847fc7146101925780635e63547a146101a557806372d64a81146101c557806379ba5097146101d857600080fd5b806310cbcf1814610105578063156194da1461011a578063181f5a771461012d5780633dc457721461017f575b600080fd5b61011861011336600461116c565b6103ad565b005b61011861012836600461116c565b61040a565b6101696040518060400160405280601c81526020017f546f6b656e41646d696e526567697374727920312e352e302d6465760000000081525081565b6040516101769190611187565b60405180910390f35b61011861018d36600461116c565b61050f565b6101186101a03660046111f4565b610573565b6101b86101b3366004611227565b6107d3565b604051610176919061129c565b6101b86101d336600461130e565b6108cc565b6101186109e2565b6101f36101ee36600461116c565b610adf565b6040519015158152602001610176565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610176565b61021d61025036600461116c565b73ffffffffffffffffffffffffffffffffffffffff908116600090815260026020819052604090912001541690565b6101f361028d3660046111f4565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020526040902054821691161490565b6103356102ca36600461116c565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff948516815260028084529084902084519283018552805486168352600181015486169383019390935291909101549092169082015290565b60408051825173ffffffffffffffffffffffffffffffffffffffff90811682526020808501518216908301529282015190921690820152606001610176565b6101186103823660046111f4565b610aec565b6101186103953660046111f4565b610bf6565b6101186103a836600461116c565b610dbe565b6103b5610dcf565b6103c0600582610e52565b156104075760405173ffffffffffffffffffffffffffffffffffffffff8216907f93eaa26dcb9275e56bacb1d33fdbf402262da6f0f4baf2a6e2cd154b73f387f890600090a25b50565b73ffffffffffffffffffffffffffffffffffffffff808216600090815260026020526040902060018101549091163314610493576040517f3edffe7500000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff831660248201526044015b60405180910390fd5b8054337fffffffffffffffffffffffff00000000000000000000000000000000000000009182168117835560018301805490921690915560405173ffffffffffffffffffffffffffffffffffffffff8416907f399b55200f7f639a63d76efe3dcfa9156ce367058d6b673041b84a628885f5a790600090a35050565b610517610dcf565b610522600582610e7b565b156104075760405173ffffffffffffffffffffffffffffffffffffffff821681527f3cabf004338366bfeaeb610ad827cb58d16b588017c509501f2c97c83caae7b29060200160405180910390a150565b73ffffffffffffffffffffffffffffffffffffffff80831660009081526002602052604090205483911633146105f3576040517fed5d85b500000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8216602482015260440161048a565b73ffffffffffffffffffffffffffffffffffffffff8216158015906106a557506040517f240028e800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015283169063240028e890602401602060405180830381865afa15801561067f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a39190611338565b155b156106f4576040517f962b60e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161048a565b73ffffffffffffffffffffffffffffffffffffffff808416600090815260026020819052604090912090810180548584167fffffffffffffffffffffffff0000000000000000000000000000000000000000821681179092559192919091169081146107cc578373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f754449ec3aff3bd528bfce43ae9319c4a381b67fcd1d20097b3b24dacaecc35d60405160405180910390a45b5050505050565b606060008267ffffffffffffffff8111156107f0576107f061135a565b604051908082528060200260200182016040528015610819578160200160208202803683370190505b50905060005b838110156108c2576002600086868481811061083d5761083d611389565b9050602002016020810190610852919061116c565b73ffffffffffffffffffffffffffffffffffffffff9081168252602082019290925260400160002060020154835191169083908390811061089557610895611389565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260010161081f565b5090505b92915050565b606060006108da6003610e9d565b9050808467ffffffffffffffff16106108f357506108c6565b67ffffffffffffffff80841690829061090e908716836113e7565b111561092b5761092867ffffffffffffffff8616836113fa565b90505b8067ffffffffffffffff8111156109445761094461135a565b60405190808252806020026020018201604052801561096d578160200160208202803683370190505b50925060005b818110156109d95761099a6109928267ffffffffffffffff89166113e7565b600390610ea7565b8482815181106109ac576109ac611389565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910190910152600101610973565b50505092915050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161048a565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60006108c6600583610eb3565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600260205260409020548391163314610b6c576040517fed5d85b500000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff8216602482015260440161048a565b73ffffffffffffffffffffffffffffffffffffffff8381166000818152600260205260408082206001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001695881695861790559051909392339290917fc54c3051ff16e63bb9203214432372aca006c589e3653619b577a3265675b7169190a450505050565b610bff33610adf565b158015610c24575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15610c5d576040517f51ca1ec300000000000000000000000000000000000000000000000000000000815233600482015260240161048a565b73ffffffffffffffffffffffffffffffffffffffff8116610caa576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600260205260409020805490911615610d24576040517f45ed80e900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161048a565b6001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416179055610d71600384610e7b565b5060405173ffffffffffffffffffffffffffffffffffffffff808416916000918616907fc54c3051ff16e63bb9203214432372aca006c589e3653619b577a3265675b716908390a4505050565b610dc6610dcf565b61040781610ee2565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e50576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161048a565b565b6000610e748373ffffffffffffffffffffffffffffffffffffffff8416610fd7565b9392505050565b6000610e748373ffffffffffffffffffffffffffffffffffffffff84166110ca565b60006108c6825490565b6000610e748383611119565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515610e74565b3373ffffffffffffffffffffffffffffffffffffffff821603610f61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161048a565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600081815260018301602052604081205480156110c0576000610ffb6001836113fa565b855490915060009061100f906001906113fa565b905081811461107457600086600001828154811061102f5761102f611389565b906000526020600020015490508087600001848154811061105257611052611389565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806110855761108561140d565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506108c6565b60009150506108c6565b6000818152600183016020526040812054611111575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556108c6565b5060006108c6565b600082600001828154811061113057611130611389565b9060005260206000200154905092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461116757600080fd5b919050565b60006020828403121561117e57600080fd5b610e7482611143565b60006020808352835180602085015260005b818110156111b557858101830151858201604001528201611199565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6000806040838503121561120757600080fd5b61121083611143565b915061121e60208401611143565b90509250929050565b6000806020838503121561123a57600080fd5b823567ffffffffffffffff8082111561125257600080fd5b818501915085601f83011261126657600080fd5b81358181111561127557600080fd5b8660208260051b850101111561128a57600080fd5b60209290920196919550909350505050565b6020808252825182820181905260009190848201906040850190845b818110156112ea57835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016112b8565b50909695505050505050565b803567ffffffffffffffff8116811461116757600080fd5b6000806040838503121561132157600080fd5b61132a836112f6565b915061121e602084016112f6565b60006020828403121561134a57600080fd5b81518015158114610e7457600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156108c6576108c66113b8565b818103818111156108c6576108c66113b8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a",
+}
+
+var TokenAdminRegistryABI = TokenAdminRegistryMetaData.ABI
+
+var TokenAdminRegistryBin = TokenAdminRegistryMetaData.Bin
+
+func DeployTokenAdminRegistry(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *TokenAdminRegistry, error) {
+ parsed, err := TokenAdminRegistryMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(TokenAdminRegistryBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &TokenAdminRegistry{address: address, abi: *parsed, TokenAdminRegistryCaller: TokenAdminRegistryCaller{contract: contract}, TokenAdminRegistryTransactor: TokenAdminRegistryTransactor{contract: contract}, TokenAdminRegistryFilterer: TokenAdminRegistryFilterer{contract: contract}}, nil
+}
+
+type TokenAdminRegistry struct {
+ address common.Address
+ abi abi.ABI
+ TokenAdminRegistryCaller
+ TokenAdminRegistryTransactor
+ TokenAdminRegistryFilterer
+}
+
+type TokenAdminRegistryCaller struct {
+ contract *bind.BoundContract
+}
+
+type TokenAdminRegistryTransactor struct {
+ contract *bind.BoundContract
+}
+
+type TokenAdminRegistryFilterer struct {
+ contract *bind.BoundContract
+}
+
+type TokenAdminRegistrySession struct {
+ Contract *TokenAdminRegistry
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type TokenAdminRegistryCallerSession struct {
+ Contract *TokenAdminRegistryCaller
+ CallOpts bind.CallOpts
+}
+
+type TokenAdminRegistryTransactorSession struct {
+ Contract *TokenAdminRegistryTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type TokenAdminRegistryRaw struct {
+ Contract *TokenAdminRegistry
+}
+
+type TokenAdminRegistryCallerRaw struct {
+ Contract *TokenAdminRegistryCaller
+}
+
+type TokenAdminRegistryTransactorRaw struct {
+ Contract *TokenAdminRegistryTransactor
+}
+
+func NewTokenAdminRegistry(address common.Address, backend bind.ContractBackend) (*TokenAdminRegistry, error) {
+ abi, err := abi.JSON(strings.NewReader(TokenAdminRegistryABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindTokenAdminRegistry(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistry{address: address, abi: abi, TokenAdminRegistryCaller: TokenAdminRegistryCaller{contract: contract}, TokenAdminRegistryTransactor: TokenAdminRegistryTransactor{contract: contract}, TokenAdminRegistryFilterer: TokenAdminRegistryFilterer{contract: contract}}, nil
+}
+
+func NewTokenAdminRegistryCaller(address common.Address, caller bind.ContractCaller) (*TokenAdminRegistryCaller, error) {
+ contract, err := bindTokenAdminRegistry(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryCaller{contract: contract}, nil
+}
+
+func NewTokenAdminRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*TokenAdminRegistryTransactor, error) {
+ contract, err := bindTokenAdminRegistry(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryTransactor{contract: contract}, nil
+}
+
+func NewTokenAdminRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*TokenAdminRegistryFilterer, error) {
+ contract, err := bindTokenAdminRegistry(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryFilterer{contract: contract}, nil
+}
+
+func bindTokenAdminRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := TokenAdminRegistryMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _TokenAdminRegistry.Contract.TokenAdminRegistryCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.TokenAdminRegistryTransactor.contract.Transfer(opts)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.TokenAdminRegistryTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _TokenAdminRegistry.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.contract.Transfer(opts)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCaller) GetAllConfiguredTokens(opts *bind.CallOpts, startIndex uint64, maxCount uint64) ([]common.Address, error) {
+ var out []interface{}
+ err := _TokenAdminRegistry.contract.Call(opts, &out, "getAllConfiguredTokens", startIndex, maxCount)
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) GetAllConfiguredTokens(startIndex uint64, maxCount uint64) ([]common.Address, error) {
+ return _TokenAdminRegistry.Contract.GetAllConfiguredTokens(&_TokenAdminRegistry.CallOpts, startIndex, maxCount)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerSession) GetAllConfiguredTokens(startIndex uint64, maxCount uint64) ([]common.Address, error) {
+ return _TokenAdminRegistry.Contract.GetAllConfiguredTokens(&_TokenAdminRegistry.CallOpts, startIndex, maxCount)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCaller) GetPool(opts *bind.CallOpts, token common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _TokenAdminRegistry.contract.Call(opts, &out, "getPool", token)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) GetPool(token common.Address) (common.Address, error) {
+ return _TokenAdminRegistry.Contract.GetPool(&_TokenAdminRegistry.CallOpts, token)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerSession) GetPool(token common.Address) (common.Address, error) {
+ return _TokenAdminRegistry.Contract.GetPool(&_TokenAdminRegistry.CallOpts, token)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCaller) GetPools(opts *bind.CallOpts, tokens []common.Address) ([]common.Address, error) {
+ var out []interface{}
+ err := _TokenAdminRegistry.contract.Call(opts, &out, "getPools", tokens)
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) GetPools(tokens []common.Address) ([]common.Address, error) {
+ return _TokenAdminRegistry.Contract.GetPools(&_TokenAdminRegistry.CallOpts, tokens)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerSession) GetPools(tokens []common.Address) ([]common.Address, error) {
+ return _TokenAdminRegistry.Contract.GetPools(&_TokenAdminRegistry.CallOpts, tokens)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCaller) GetTokenConfig(opts *bind.CallOpts, token common.Address) (TokenAdminRegistryTokenConfig, error) {
+ var out []interface{}
+ err := _TokenAdminRegistry.contract.Call(opts, &out, "getTokenConfig", token)
+
+ if err != nil {
+ return *new(TokenAdminRegistryTokenConfig), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(TokenAdminRegistryTokenConfig)).(*TokenAdminRegistryTokenConfig)
+
+ return out0, err
+
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) GetTokenConfig(token common.Address) (TokenAdminRegistryTokenConfig, error) {
+ return _TokenAdminRegistry.Contract.GetTokenConfig(&_TokenAdminRegistry.CallOpts, token)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerSession) GetTokenConfig(token common.Address) (TokenAdminRegistryTokenConfig, error) {
+ return _TokenAdminRegistry.Contract.GetTokenConfig(&_TokenAdminRegistry.CallOpts, token)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCaller) IsAdministrator(opts *bind.CallOpts, localToken common.Address, administrator common.Address) (bool, error) {
+ var out []interface{}
+ err := _TokenAdminRegistry.contract.Call(opts, &out, "isAdministrator", localToken, administrator)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) IsAdministrator(localToken common.Address, administrator common.Address) (bool, error) {
+ return _TokenAdminRegistry.Contract.IsAdministrator(&_TokenAdminRegistry.CallOpts, localToken, administrator)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerSession) IsAdministrator(localToken common.Address, administrator common.Address) (bool, error) {
+ return _TokenAdminRegistry.Contract.IsAdministrator(&_TokenAdminRegistry.CallOpts, localToken, administrator)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCaller) IsRegistryModule(opts *bind.CallOpts, module common.Address) (bool, error) {
+ var out []interface{}
+ err := _TokenAdminRegistry.contract.Call(opts, &out, "isRegistryModule", module)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) IsRegistryModule(module common.Address) (bool, error) {
+ return _TokenAdminRegistry.Contract.IsRegistryModule(&_TokenAdminRegistry.CallOpts, module)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerSession) IsRegistryModule(module common.Address) (bool, error) {
+ return _TokenAdminRegistry.Contract.IsRegistryModule(&_TokenAdminRegistry.CallOpts, module)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenAdminRegistry.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) Owner() (common.Address, error) {
+ return _TokenAdminRegistry.Contract.Owner(&_TokenAdminRegistry.CallOpts)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerSession) Owner() (common.Address, error) {
+ return _TokenAdminRegistry.Contract.Owner(&_TokenAdminRegistry.CallOpts)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _TokenAdminRegistry.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) TypeAndVersion() (string, error) {
+ return _TokenAdminRegistry.Contract.TypeAndVersion(&_TokenAdminRegistry.CallOpts)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryCallerSession) TypeAndVersion() (string, error) {
+ return _TokenAdminRegistry.Contract.TypeAndVersion(&_TokenAdminRegistry.CallOpts)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactor) AcceptAdminRole(opts *bind.TransactOpts, localToken common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.contract.Transact(opts, "acceptAdminRole", localToken)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) AcceptAdminRole(localToken common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.AcceptAdminRole(&_TokenAdminRegistry.TransactOpts, localToken)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorSession) AcceptAdminRole(localToken common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.AcceptAdminRole(&_TokenAdminRegistry.TransactOpts, localToken)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenAdminRegistry.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) AcceptOwnership() (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.AcceptOwnership(&_TokenAdminRegistry.TransactOpts)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.AcceptOwnership(&_TokenAdminRegistry.TransactOpts)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactor) AddRegistryModule(opts *bind.TransactOpts, module common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.contract.Transact(opts, "addRegistryModule", module)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) AddRegistryModule(module common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.AddRegistryModule(&_TokenAdminRegistry.TransactOpts, module)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorSession) AddRegistryModule(module common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.AddRegistryModule(&_TokenAdminRegistry.TransactOpts, module)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactor) ProposeAdministrator(opts *bind.TransactOpts, localToken common.Address, administrator common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.contract.Transact(opts, "proposeAdministrator", localToken, administrator)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) ProposeAdministrator(localToken common.Address, administrator common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.ProposeAdministrator(&_TokenAdminRegistry.TransactOpts, localToken, administrator)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorSession) ProposeAdministrator(localToken common.Address, administrator common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.ProposeAdministrator(&_TokenAdminRegistry.TransactOpts, localToken, administrator)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactor) RemoveRegistryModule(opts *bind.TransactOpts, module common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.contract.Transact(opts, "removeRegistryModule", module)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) RemoveRegistryModule(module common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.RemoveRegistryModule(&_TokenAdminRegistry.TransactOpts, module)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorSession) RemoveRegistryModule(module common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.RemoveRegistryModule(&_TokenAdminRegistry.TransactOpts, module)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactor) SetPool(opts *bind.TransactOpts, localToken common.Address, pool common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.contract.Transact(opts, "setPool", localToken, pool)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) SetPool(localToken common.Address, pool common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.SetPool(&_TokenAdminRegistry.TransactOpts, localToken, pool)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorSession) SetPool(localToken common.Address, pool common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.SetPool(&_TokenAdminRegistry.TransactOpts, localToken, pool)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactor) TransferAdminRole(opts *bind.TransactOpts, localToken common.Address, newAdmin common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.contract.Transact(opts, "transferAdminRole", localToken, newAdmin)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) TransferAdminRole(localToken common.Address, newAdmin common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.TransferAdminRole(&_TokenAdminRegistry.TransactOpts, localToken, newAdmin)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorSession) TransferAdminRole(localToken common.Address, newAdmin common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.TransferAdminRole(&_TokenAdminRegistry.TransactOpts, localToken, newAdmin)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistrySession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.TransferOwnership(&_TokenAdminRegistry.TransactOpts, to)
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _TokenAdminRegistry.Contract.TransferOwnership(&_TokenAdminRegistry.TransactOpts, to)
+}
+
+type TokenAdminRegistryAdministratorTransferRequestedIterator struct {
+ Event *TokenAdminRegistryAdministratorTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryAdministratorTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryAdministratorTransferRequested)
+ 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(TokenAdminRegistryAdministratorTransferRequested)
+ 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 *TokenAdminRegistryAdministratorTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryAdministratorTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryAdministratorTransferRequested struct {
+ Token common.Address
+ CurrentAdmin common.Address
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterAdministratorTransferRequested(opts *bind.FilterOpts, token []common.Address, currentAdmin []common.Address, newAdmin []common.Address) (*TokenAdminRegistryAdministratorTransferRequestedIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var currentAdminRule []interface{}
+ for _, currentAdminItem := range currentAdmin {
+ currentAdminRule = append(currentAdminRule, currentAdminItem)
+ }
+ var newAdminRule []interface{}
+ for _, newAdminItem := range newAdmin {
+ newAdminRule = append(newAdminRule, newAdminItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "AdministratorTransferRequested", tokenRule, currentAdminRule, newAdminRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryAdministratorTransferRequestedIterator{contract: _TokenAdminRegistry.contract, event: "AdministratorTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchAdministratorTransferRequested(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryAdministratorTransferRequested, token []common.Address, currentAdmin []common.Address, newAdmin []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var currentAdminRule []interface{}
+ for _, currentAdminItem := range currentAdmin {
+ currentAdminRule = append(currentAdminRule, currentAdminItem)
+ }
+ var newAdminRule []interface{}
+ for _, newAdminItem := range newAdmin {
+ newAdminRule = append(newAdminRule, newAdminItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "AdministratorTransferRequested", tokenRule, currentAdminRule, newAdminRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryAdministratorTransferRequested)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "AdministratorTransferRequested", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParseAdministratorTransferRequested(log types.Log) (*TokenAdminRegistryAdministratorTransferRequested, error) {
+ event := new(TokenAdminRegistryAdministratorTransferRequested)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "AdministratorTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenAdminRegistryAdministratorTransferredIterator struct {
+ Event *TokenAdminRegistryAdministratorTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryAdministratorTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryAdministratorTransferred)
+ 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(TokenAdminRegistryAdministratorTransferred)
+ 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 *TokenAdminRegistryAdministratorTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryAdministratorTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryAdministratorTransferred struct {
+ Token common.Address
+ NewAdmin common.Address
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterAdministratorTransferred(opts *bind.FilterOpts, token []common.Address, newAdmin []common.Address) (*TokenAdminRegistryAdministratorTransferredIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var newAdminRule []interface{}
+ for _, newAdminItem := range newAdmin {
+ newAdminRule = append(newAdminRule, newAdminItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "AdministratorTransferred", tokenRule, newAdminRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryAdministratorTransferredIterator{contract: _TokenAdminRegistry.contract, event: "AdministratorTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchAdministratorTransferred(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryAdministratorTransferred, token []common.Address, newAdmin []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var newAdminRule []interface{}
+ for _, newAdminItem := range newAdmin {
+ newAdminRule = append(newAdminRule, newAdminItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "AdministratorTransferred", tokenRule, newAdminRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryAdministratorTransferred)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "AdministratorTransferred", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParseAdministratorTransferred(log types.Log) (*TokenAdminRegistryAdministratorTransferred, error) {
+ event := new(TokenAdminRegistryAdministratorTransferred)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "AdministratorTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenAdminRegistryDisableReRegistrationSetIterator struct {
+ Event *TokenAdminRegistryDisableReRegistrationSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryDisableReRegistrationSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryDisableReRegistrationSet)
+ 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(TokenAdminRegistryDisableReRegistrationSet)
+ 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 *TokenAdminRegistryDisableReRegistrationSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryDisableReRegistrationSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryDisableReRegistrationSet struct {
+ Token common.Address
+ Disabled bool
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterDisableReRegistrationSet(opts *bind.FilterOpts, token []common.Address) (*TokenAdminRegistryDisableReRegistrationSetIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "DisableReRegistrationSet", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryDisableReRegistrationSetIterator{contract: _TokenAdminRegistry.contract, event: "DisableReRegistrationSet", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchDisableReRegistrationSet(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryDisableReRegistrationSet, token []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "DisableReRegistrationSet", tokenRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryDisableReRegistrationSet)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "DisableReRegistrationSet", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParseDisableReRegistrationSet(log types.Log) (*TokenAdminRegistryDisableReRegistrationSet, error) {
+ event := new(TokenAdminRegistryDisableReRegistrationSet)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "DisableReRegistrationSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenAdminRegistryOwnershipTransferRequestedIterator struct {
+ Event *TokenAdminRegistryOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryOwnershipTransferRequested)
+ 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(TokenAdminRegistryOwnershipTransferRequested)
+ 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 *TokenAdminRegistryOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenAdminRegistryOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryOwnershipTransferRequestedIterator{contract: _TokenAdminRegistry.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryOwnershipTransferRequested)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParseOwnershipTransferRequested(log types.Log) (*TokenAdminRegistryOwnershipTransferRequested, error) {
+ event := new(TokenAdminRegistryOwnershipTransferRequested)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenAdminRegistryOwnershipTransferredIterator struct {
+ Event *TokenAdminRegistryOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryOwnershipTransferred)
+ 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(TokenAdminRegistryOwnershipTransferred)
+ 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 *TokenAdminRegistryOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenAdminRegistryOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryOwnershipTransferredIterator{contract: _TokenAdminRegistry.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryOwnershipTransferred)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "OwnershipTransferred", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParseOwnershipTransferred(log types.Log) (*TokenAdminRegistryOwnershipTransferred, error) {
+ event := new(TokenAdminRegistryOwnershipTransferred)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenAdminRegistryPoolSetIterator struct {
+ Event *TokenAdminRegistryPoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryPoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryPoolSet)
+ 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(TokenAdminRegistryPoolSet)
+ 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 *TokenAdminRegistryPoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryPoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryPoolSet struct {
+ Token common.Address
+ PreviousPool common.Address
+ NewPool common.Address
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterPoolSet(opts *bind.FilterOpts, token []common.Address, previousPool []common.Address, newPool []common.Address) (*TokenAdminRegistryPoolSetIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var previousPoolRule []interface{}
+ for _, previousPoolItem := range previousPool {
+ previousPoolRule = append(previousPoolRule, previousPoolItem)
+ }
+ var newPoolRule []interface{}
+ for _, newPoolItem := range newPool {
+ newPoolRule = append(newPoolRule, newPoolItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "PoolSet", tokenRule, previousPoolRule, newPoolRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryPoolSetIterator{contract: _TokenAdminRegistry.contract, event: "PoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchPoolSet(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryPoolSet, token []common.Address, previousPool []common.Address, newPool []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var previousPoolRule []interface{}
+ for _, previousPoolItem := range previousPool {
+ previousPoolRule = append(previousPoolRule, previousPoolItem)
+ }
+ var newPoolRule []interface{}
+ for _, newPoolItem := range newPool {
+ newPoolRule = append(newPoolRule, newPoolItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "PoolSet", tokenRule, previousPoolRule, newPoolRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryPoolSet)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "PoolSet", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParsePoolSet(log types.Log) (*TokenAdminRegistryPoolSet, error) {
+ event := new(TokenAdminRegistryPoolSet)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "PoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenAdminRegistryRegistryModuleAddedIterator struct {
+ Event *TokenAdminRegistryRegistryModuleAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryRegistryModuleAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryRegistryModuleAdded)
+ 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(TokenAdminRegistryRegistryModuleAdded)
+ 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 *TokenAdminRegistryRegistryModuleAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryRegistryModuleAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryRegistryModuleAdded struct {
+ Module common.Address
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterRegistryModuleAdded(opts *bind.FilterOpts) (*TokenAdminRegistryRegistryModuleAddedIterator, error) {
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "RegistryModuleAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryRegistryModuleAddedIterator{contract: _TokenAdminRegistry.contract, event: "RegistryModuleAdded", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchRegistryModuleAdded(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryRegistryModuleAdded) (event.Subscription, error) {
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "RegistryModuleAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryRegistryModuleAdded)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "RegistryModuleAdded", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParseRegistryModuleAdded(log types.Log) (*TokenAdminRegistryRegistryModuleAdded, error) {
+ event := new(TokenAdminRegistryRegistryModuleAdded)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "RegistryModuleAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenAdminRegistryRegistryModuleRemovedIterator struct {
+ Event *TokenAdminRegistryRegistryModuleRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryRegistryModuleRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryRegistryModuleRemoved)
+ 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(TokenAdminRegistryRegistryModuleRemoved)
+ 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 *TokenAdminRegistryRegistryModuleRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryRegistryModuleRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryRegistryModuleRemoved struct {
+ Module common.Address
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterRegistryModuleRemoved(opts *bind.FilterOpts, module []common.Address) (*TokenAdminRegistryRegistryModuleRemovedIterator, error) {
+
+ var moduleRule []interface{}
+ for _, moduleItem := range module {
+ moduleRule = append(moduleRule, moduleItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "RegistryModuleRemoved", moduleRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryRegistryModuleRemovedIterator{contract: _TokenAdminRegistry.contract, event: "RegistryModuleRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchRegistryModuleRemoved(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryRegistryModuleRemoved, module []common.Address) (event.Subscription, error) {
+
+ var moduleRule []interface{}
+ for _, moduleItem := range module {
+ moduleRule = append(moduleRule, moduleItem)
+ }
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "RegistryModuleRemoved", moduleRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryRegistryModuleRemoved)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "RegistryModuleRemoved", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParseRegistryModuleRemoved(log types.Log) (*TokenAdminRegistryRegistryModuleRemoved, error) {
+ event := new(TokenAdminRegistryRegistryModuleRemoved)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "RegistryModuleRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenAdminRegistryRemovedAdministratorIterator struct {
+ Event *TokenAdminRegistryRemovedAdministrator
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenAdminRegistryRemovedAdministratorIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenAdminRegistryRemovedAdministrator)
+ 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(TokenAdminRegistryRemovedAdministrator)
+ 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 *TokenAdminRegistryRemovedAdministratorIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenAdminRegistryRemovedAdministratorIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenAdminRegistryRemovedAdministrator struct {
+ Token common.Address
+ Raw types.Log
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) FilterRemovedAdministrator(opts *bind.FilterOpts) (*TokenAdminRegistryRemovedAdministratorIterator, error) {
+
+ logs, sub, err := _TokenAdminRegistry.contract.FilterLogs(opts, "RemovedAdministrator")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistryRemovedAdministratorIterator{contract: _TokenAdminRegistry.contract, event: "RemovedAdministrator", logs: logs, sub: sub}, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistryFilterer) WatchRemovedAdministrator(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryRemovedAdministrator) (event.Subscription, error) {
+
+ logs, sub, err := _TokenAdminRegistry.contract.WatchLogs(opts, "RemovedAdministrator")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenAdminRegistryRemovedAdministrator)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "RemovedAdministrator", 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 (_TokenAdminRegistry *TokenAdminRegistryFilterer) ParseRemovedAdministrator(log types.Log) (*TokenAdminRegistryRemovedAdministrator, error) {
+ event := new(TokenAdminRegistryRemovedAdministrator)
+ if err := _TokenAdminRegistry.contract.UnpackLog(event, "RemovedAdministrator", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistry) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _TokenAdminRegistry.abi.Events["AdministratorTransferRequested"].ID:
+ return _TokenAdminRegistry.ParseAdministratorTransferRequested(log)
+ case _TokenAdminRegistry.abi.Events["AdministratorTransferred"].ID:
+ return _TokenAdminRegistry.ParseAdministratorTransferred(log)
+ case _TokenAdminRegistry.abi.Events["DisableReRegistrationSet"].ID:
+ return _TokenAdminRegistry.ParseDisableReRegistrationSet(log)
+ case _TokenAdminRegistry.abi.Events["OwnershipTransferRequested"].ID:
+ return _TokenAdminRegistry.ParseOwnershipTransferRequested(log)
+ case _TokenAdminRegistry.abi.Events["OwnershipTransferred"].ID:
+ return _TokenAdminRegistry.ParseOwnershipTransferred(log)
+ case _TokenAdminRegistry.abi.Events["PoolSet"].ID:
+ return _TokenAdminRegistry.ParsePoolSet(log)
+ case _TokenAdminRegistry.abi.Events["RegistryModuleAdded"].ID:
+ return _TokenAdminRegistry.ParseRegistryModuleAdded(log)
+ case _TokenAdminRegistry.abi.Events["RegistryModuleRemoved"].ID:
+ return _TokenAdminRegistry.ParseRegistryModuleRemoved(log)
+ case _TokenAdminRegistry.abi.Events["RemovedAdministrator"].ID:
+ return _TokenAdminRegistry.ParseRemovedAdministrator(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (TokenAdminRegistryAdministratorTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xc54c3051ff16e63bb9203214432372aca006c589e3653619b577a3265675b716")
+}
+
+func (TokenAdminRegistryAdministratorTransferred) Topic() common.Hash {
+ return common.HexToHash("0x399b55200f7f639a63d76efe3dcfa9156ce367058d6b673041b84a628885f5a7")
+}
+
+func (TokenAdminRegistryDisableReRegistrationSet) Topic() common.Hash {
+ return common.HexToHash("0x4f1ce406d38233729d1052ad9f0c2b56bd742cd4fb59781573b51fa1f268a92e")
+}
+
+func (TokenAdminRegistryOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (TokenAdminRegistryOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (TokenAdminRegistryPoolSet) Topic() common.Hash {
+ return common.HexToHash("0x754449ec3aff3bd528bfce43ae9319c4a381b67fcd1d20097b3b24dacaecc35d")
+}
+
+func (TokenAdminRegistryRegistryModuleAdded) Topic() common.Hash {
+ return common.HexToHash("0x3cabf004338366bfeaeb610ad827cb58d16b588017c509501f2c97c83caae7b2")
+}
+
+func (TokenAdminRegistryRegistryModuleRemoved) Topic() common.Hash {
+ return common.HexToHash("0x93eaa26dcb9275e56bacb1d33fdbf402262da6f0f4baf2a6e2cd154b73f387f8")
+}
+
+func (TokenAdminRegistryRemovedAdministrator) Topic() common.Hash {
+ return common.HexToHash("0x7b309bf0232684e703b0a791653cc857835761a0365ccade0e2aa66ef02ca530")
+}
+
+func (_TokenAdminRegistry *TokenAdminRegistry) Address() common.Address {
+ return _TokenAdminRegistry.address
+}
+
+type TokenAdminRegistryInterface interface {
+ GetAllConfiguredTokens(opts *bind.CallOpts, startIndex uint64, maxCount uint64) ([]common.Address, error)
+
+ GetPool(opts *bind.CallOpts, token common.Address) (common.Address, error)
+
+ GetPools(opts *bind.CallOpts, tokens []common.Address) ([]common.Address, error)
+
+ GetTokenConfig(opts *bind.CallOpts, token common.Address) (TokenAdminRegistryTokenConfig, error)
+
+ IsAdministrator(opts *bind.CallOpts, localToken common.Address, administrator common.Address) (bool, error)
+
+ IsRegistryModule(opts *bind.CallOpts, module common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptAdminRole(opts *bind.TransactOpts, localToken common.Address) (*types.Transaction, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ AddRegistryModule(opts *bind.TransactOpts, module common.Address) (*types.Transaction, error)
+
+ ProposeAdministrator(opts *bind.TransactOpts, localToken common.Address, administrator common.Address) (*types.Transaction, error)
+
+ RemoveRegistryModule(opts *bind.TransactOpts, module common.Address) (*types.Transaction, error)
+
+ SetPool(opts *bind.TransactOpts, localToken common.Address, pool common.Address) (*types.Transaction, error)
+
+ TransferAdminRole(opts *bind.TransactOpts, localToken common.Address, newAdmin common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAdministratorTransferRequested(opts *bind.FilterOpts, token []common.Address, currentAdmin []common.Address, newAdmin []common.Address) (*TokenAdminRegistryAdministratorTransferRequestedIterator, error)
+
+ WatchAdministratorTransferRequested(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryAdministratorTransferRequested, token []common.Address, currentAdmin []common.Address, newAdmin []common.Address) (event.Subscription, error)
+
+ ParseAdministratorTransferRequested(log types.Log) (*TokenAdminRegistryAdministratorTransferRequested, error)
+
+ FilterAdministratorTransferred(opts *bind.FilterOpts, token []common.Address, newAdmin []common.Address) (*TokenAdminRegistryAdministratorTransferredIterator, error)
+
+ WatchAdministratorTransferred(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryAdministratorTransferred, token []common.Address, newAdmin []common.Address) (event.Subscription, error)
+
+ ParseAdministratorTransferred(log types.Log) (*TokenAdminRegistryAdministratorTransferred, error)
+
+ FilterDisableReRegistrationSet(opts *bind.FilterOpts, token []common.Address) (*TokenAdminRegistryDisableReRegistrationSetIterator, error)
+
+ WatchDisableReRegistrationSet(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryDisableReRegistrationSet, token []common.Address) (event.Subscription, error)
+
+ ParseDisableReRegistrationSet(log types.Log) (*TokenAdminRegistryDisableReRegistrationSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenAdminRegistryOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*TokenAdminRegistryOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenAdminRegistryOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*TokenAdminRegistryOwnershipTransferred, error)
+
+ FilterPoolSet(opts *bind.FilterOpts, token []common.Address, previousPool []common.Address, newPool []common.Address) (*TokenAdminRegistryPoolSetIterator, error)
+
+ WatchPoolSet(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryPoolSet, token []common.Address, previousPool []common.Address, newPool []common.Address) (event.Subscription, error)
+
+ ParsePoolSet(log types.Log) (*TokenAdminRegistryPoolSet, error)
+
+ FilterRegistryModuleAdded(opts *bind.FilterOpts) (*TokenAdminRegistryRegistryModuleAddedIterator, error)
+
+ WatchRegistryModuleAdded(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryRegistryModuleAdded) (event.Subscription, error)
+
+ ParseRegistryModuleAdded(log types.Log) (*TokenAdminRegistryRegistryModuleAdded, error)
+
+ FilterRegistryModuleRemoved(opts *bind.FilterOpts, module []common.Address) (*TokenAdminRegistryRegistryModuleRemovedIterator, error)
+
+ WatchRegistryModuleRemoved(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryRegistryModuleRemoved, module []common.Address) (event.Subscription, error)
+
+ ParseRegistryModuleRemoved(log types.Log) (*TokenAdminRegistryRegistryModuleRemoved, error)
+
+ FilterRemovedAdministrator(opts *bind.FilterOpts) (*TokenAdminRegistryRemovedAdministratorIterator, error)
+
+ WatchRemovedAdministrator(opts *bind.WatchOpts, sink chan<- *TokenAdminRegistryRemovedAdministrator) (event.Subscription, error)
+
+ ParseRemovedAdministrator(log types.Log) (*TokenAdminRegistryRemovedAdministrator, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/token_pool/token_pool.go b/core/gethwrappers/ccip/generated/token_pool/token_pool.go
new file mode 100644
index 00000000000..0fb4c4e087a
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/token_pool/token_pool.go
@@ -0,0 +1,2608 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package token_pool
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type PoolLockOrBurnInV1 struct {
+ Receiver []byte
+ RemoteChainSelector uint64
+ OriginalSender common.Address
+ Amount *big.Int
+ LocalToken common.Address
+}
+
+type PoolLockOrBurnOutV1 struct {
+ DestTokenAddress []byte
+ DestPoolData []byte
+}
+
+type PoolReleaseOrMintInV1 struct {
+ OriginalSender []byte
+ RemoteChainSelector uint64
+ Receiver common.Address
+ Amount *big.Int
+ LocalToken common.Address
+ SourcePoolAddress []byte
+ SourcePoolData []byte
+ OffchainTokenData []byte
+}
+
+type PoolReleaseOrMintOutV1 struct {
+ DestinationAmount *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ RemotePoolAddress []byte
+ RemoteTokenAddress []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var TokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRateLimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidSourcePoolAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remoteToken\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousPoolAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"RemotePoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"remoteTokenAddress\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemotePool\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemoteToken\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRmnProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"isSupportedToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structPool.LockOrBurnInV1\",\"name\":\"lockOrBurnIn\",\"type\":\"tuple\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destPoolData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.LockOrBurnOutV1\",\"name\":\"lockOrBurnOut\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainTokenData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.ReleaseOrMintInV1\",\"name\":\"releaseOrMintIn\",\"type\":\"tuple\"}],\"name\":\"releaseOrMint\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destinationAmount\",\"type\":\"uint256\"}],\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"setRemotePool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+}
+
+var TokenPoolABI = TokenPoolMetaData.ABI
+
+type TokenPool struct {
+ address common.Address
+ abi abi.ABI
+ TokenPoolCaller
+ TokenPoolTransactor
+ TokenPoolFilterer
+}
+
+type TokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type TokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type TokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type TokenPoolSession struct {
+ Contract *TokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type TokenPoolCallerSession struct {
+ Contract *TokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type TokenPoolTransactorSession struct {
+ Contract *TokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type TokenPoolRaw struct {
+ Contract *TokenPool
+}
+
+type TokenPoolCallerRaw struct {
+ Contract *TokenPoolCaller
+}
+
+type TokenPoolTransactorRaw struct {
+ Contract *TokenPoolTransactor
+}
+
+func NewTokenPool(address common.Address, backend bind.ContractBackend) (*TokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(TokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPool{address: address, abi: abi, TokenPoolCaller: TokenPoolCaller{contract: contract}, TokenPoolTransactor: TokenPoolTransactor{contract: contract}, TokenPoolFilterer: TokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*TokenPoolCaller, error) {
+ contract, err := bindTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolCaller{contract: contract}, nil
+}
+
+func NewTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*TokenPoolTransactor, error) {
+ contract, err := bindTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolTransactor{contract: contract}, nil
+}
+
+func NewTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*TokenPoolFilterer, error) {
+ contract, err := bindTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolFilterer{contract: contract}, nil
+}
+
+func bindTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := TokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_TokenPool *TokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _TokenPool.Contract.TokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_TokenPool *TokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenPool.Contract.TokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_TokenPool *TokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _TokenPool.Contract.TokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_TokenPool *TokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _TokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_TokenPool *TokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_TokenPool *TokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _TokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_TokenPool *TokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _TokenPool.Contract.GetAllowList(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _TokenPool.Contract.GetAllowList(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _TokenPool.Contract.GetAllowListEnabled(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _TokenPool.Contract.GetAllowListEnabled(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _TokenPool.Contract.GetCurrentInboundRateLimiterState(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _TokenPool.Contract.GetCurrentInboundRateLimiterState(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _TokenPool.Contract.GetCurrentOutboundRateLimiterState(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _TokenPool.Contract.GetCurrentOutboundRateLimiterState(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCaller) GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getRemotePool", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _TokenPool.Contract.GetRemotePool(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _TokenPool.Contract.GetRemotePool(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _TokenPool.Contract.GetRemoteToken(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _TokenPool.Contract.GetRemoteToken(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getRmnProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetRmnProxy() (common.Address, error) {
+ return _TokenPool.Contract.GetRmnProxy(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetRmnProxy() (common.Address, error) {
+ return _TokenPool.Contract.GetRmnProxy(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetRouter() (common.Address, error) {
+ return _TokenPool.Contract.GetRouter(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _TokenPool.Contract.GetRouter(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _TokenPool.Contract.GetSupportedChains(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _TokenPool.Contract.GetSupportedChains(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetToken() (common.Address, error) {
+ return _TokenPool.Contract.GetToken(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _TokenPool.Contract.GetToken(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _TokenPool.Contract.IsSupportedChain(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _TokenPool.Contract.IsSupportedChain(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "isSupportedToken", token)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _TokenPool.Contract.IsSupportedToken(&_TokenPool.CallOpts, token)
+}
+
+func (_TokenPool *TokenPoolCallerSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _TokenPool.Contract.IsSupportedToken(&_TokenPool.CallOpts, token)
+}
+
+func (_TokenPool *TokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) Owner() (common.Address, error) {
+ return _TokenPool.Contract.Owner(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) Owner() (common.Address, error) {
+ return _TokenPool.Contract.Owner(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _TokenPool.Contract.SupportsInterface(&_TokenPool.CallOpts, interfaceId)
+}
+
+func (_TokenPool *TokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _TokenPool.Contract.SupportsInterface(&_TokenPool.CallOpts, interfaceId)
+}
+
+func (_TokenPool *TokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_TokenPool *TokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _TokenPool.Contract.AcceptOwnership(&_TokenPool.TransactOpts)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _TokenPool.Contract.AcceptOwnership(&_TokenPool.TransactOpts)
+}
+
+func (_TokenPool *TokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_TokenPool *TokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.ApplyAllowListUpdates(&_TokenPool.TransactOpts, removes, adds)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.ApplyAllowListUpdates(&_TokenPool.TransactOpts, removes, adds)
+}
+
+func (_TokenPool *TokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_TokenPool *TokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _TokenPool.Contract.ApplyChainUpdates(&_TokenPool.TransactOpts, chains)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _TokenPool.Contract.ApplyChainUpdates(&_TokenPool.TransactOpts, chains)
+}
+
+func (_TokenPool *TokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "lockOrBurn", lockOrBurnIn)
+}
+
+func (_TokenPool *TokenPoolSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _TokenPool.Contract.LockOrBurn(&_TokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _TokenPool.Contract.LockOrBurn(&_TokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_TokenPool *TokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "releaseOrMint", releaseOrMintIn)
+}
+
+func (_TokenPool *TokenPoolSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _TokenPool.Contract.ReleaseOrMint(&_TokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _TokenPool.Contract.ReleaseOrMint(&_TokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_TokenPool *TokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_TokenPool *TokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetChainRateLimiterConfig(&_TokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetChainRateLimiterConfig(&_TokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_TokenPool *TokenPoolTransactor) SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "setRemotePool", remoteChainSelector, remotePoolAddress)
+}
+
+func (_TokenPool *TokenPoolSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetRemotePool(&_TokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetRemotePool(&_TokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_TokenPool *TokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_TokenPool *TokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetRouter(&_TokenPool.TransactOpts, newRouter)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetRouter(&_TokenPool.TransactOpts, newRouter)
+}
+
+func (_TokenPool *TokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_TokenPool *TokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.TransferOwnership(&_TokenPool.TransactOpts, to)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.TransferOwnership(&_TokenPool.TransactOpts, to)
+}
+
+type TokenPoolAllowListAddIterator struct {
+ Event *TokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolAllowListAdd)
+ 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(TokenPoolAllowListAdd)
+ 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 *TokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*TokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolAllowListAddIterator{contract: _TokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *TokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolAllowListAdd)
+ if err := _TokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_TokenPool *TokenPoolFilterer) ParseAllowListAdd(log types.Log) (*TokenPoolAllowListAdd, error) {
+ event := new(TokenPoolAllowListAdd)
+ if err := _TokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolAllowListRemoveIterator struct {
+ Event *TokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolAllowListRemove)
+ 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(TokenPoolAllowListRemove)
+ 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 *TokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*TokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolAllowListRemoveIterator{contract: _TokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *TokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolAllowListRemove)
+ if err := _TokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_TokenPool *TokenPoolFilterer) ParseAllowListRemove(log types.Log) (*TokenPoolAllowListRemove, error) {
+ event := new(TokenPoolAllowListRemove)
+ if err := _TokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolBurnedIterator struct {
+ Event *TokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolBurned)
+ 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(TokenPoolBurned)
+ 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 *TokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*TokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolBurnedIterator{contract: _TokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *TokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolBurned)
+ if err := _TokenPool.contract.UnpackLog(event, "Burned", 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 (_TokenPool *TokenPoolFilterer) ParseBurned(log types.Log) (*TokenPoolBurned, error) {
+ event := new(TokenPoolBurned)
+ if err := _TokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolChainAddedIterator struct {
+ Event *TokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolChainAdded)
+ 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(TokenPoolChainAdded)
+ 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 *TokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*TokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolChainAddedIterator{contract: _TokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *TokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolChainAdded)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_TokenPool *TokenPoolFilterer) ParseChainAdded(log types.Log) (*TokenPoolChainAdded, error) {
+ event := new(TokenPoolChainAdded)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolChainConfiguredIterator struct {
+ Event *TokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolChainConfigured)
+ 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(TokenPoolChainConfigured)
+ 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 *TokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*TokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolChainConfiguredIterator{contract: _TokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *TokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolChainConfigured)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_TokenPool *TokenPoolFilterer) ParseChainConfigured(log types.Log) (*TokenPoolChainConfigured, error) {
+ event := new(TokenPoolChainConfigured)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolChainRemovedIterator struct {
+ Event *TokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolChainRemoved)
+ 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(TokenPoolChainRemoved)
+ 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 *TokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*TokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolChainRemovedIterator{contract: _TokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *TokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolChainRemoved)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_TokenPool *TokenPoolFilterer) ParseChainRemoved(log types.Log) (*TokenPoolChainRemoved, error) {
+ event := new(TokenPoolChainRemoved)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolConfigChangedIterator struct {
+ Event *TokenPoolConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolConfigChanged)
+ 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(TokenPoolConfigChanged)
+ 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 *TokenPoolConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*TokenPoolConfigChangedIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolConfigChangedIterator{contract: _TokenPool.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *TokenPoolConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolConfigChanged)
+ if err := _TokenPool.contract.UnpackLog(event, "ConfigChanged", 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 (_TokenPool *TokenPoolFilterer) ParseConfigChanged(log types.Log) (*TokenPoolConfigChanged, error) {
+ event := new(TokenPoolConfigChanged)
+ if err := _TokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolLockedIterator struct {
+ Event *TokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolLocked)
+ 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(TokenPoolLocked)
+ 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 *TokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*TokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolLockedIterator{contract: _TokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *TokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolLocked)
+ if err := _TokenPool.contract.UnpackLog(event, "Locked", 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 (_TokenPool *TokenPoolFilterer) ParseLocked(log types.Log) (*TokenPoolLocked, error) {
+ event := new(TokenPoolLocked)
+ if err := _TokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolMintedIterator struct {
+ Event *TokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolMinted)
+ 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(TokenPoolMinted)
+ 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 *TokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*TokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolMintedIterator{contract: _TokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *TokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolMinted)
+ if err := _TokenPool.contract.UnpackLog(event, "Minted", 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 (_TokenPool *TokenPoolFilterer) ParseMinted(log types.Log) (*TokenPoolMinted, error) {
+ event := new(TokenPoolMinted)
+ if err := _TokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolOwnershipTransferRequestedIterator struct {
+ Event *TokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolOwnershipTransferRequested)
+ 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(TokenPoolOwnershipTransferRequested)
+ 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 *TokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolOwnershipTransferRequestedIterator{contract: _TokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *TokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolOwnershipTransferRequested)
+ if err := _TokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_TokenPool *TokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*TokenPoolOwnershipTransferRequested, error) {
+ event := new(TokenPoolOwnershipTransferRequested)
+ if err := _TokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolOwnershipTransferredIterator struct {
+ Event *TokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolOwnershipTransferred)
+ 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(TokenPoolOwnershipTransferred)
+ 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 *TokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolOwnershipTransferredIterator{contract: _TokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *TokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolOwnershipTransferred)
+ if err := _TokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_TokenPool *TokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*TokenPoolOwnershipTransferred, error) {
+ event := new(TokenPoolOwnershipTransferred)
+ if err := _TokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolReleasedIterator struct {
+ Event *TokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolReleased)
+ 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(TokenPoolReleased)
+ 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 *TokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*TokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolReleasedIterator{contract: _TokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *TokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolReleased)
+ if err := _TokenPool.contract.UnpackLog(event, "Released", 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 (_TokenPool *TokenPoolFilterer) ParseReleased(log types.Log) (*TokenPoolReleased, error) {
+ event := new(TokenPoolReleased)
+ if err := _TokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolRemotePoolSetIterator struct {
+ Event *TokenPoolRemotePoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolRemotePoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolRemotePoolSet)
+ 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(TokenPoolRemotePoolSet)
+ 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 *TokenPoolRemotePoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolRemotePoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolRemotePoolSet struct {
+ RemoteChainSelector uint64
+ PreviousPoolAddress []byte
+ RemotePoolAddress []byte
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*TokenPoolRemotePoolSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolRemotePoolSetIterator{contract: _TokenPool.contract, event: "RemotePoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *TokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolRemotePoolSet)
+ if err := _TokenPool.contract.UnpackLog(event, "RemotePoolSet", 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 (_TokenPool *TokenPoolFilterer) ParseRemotePoolSet(log types.Log) (*TokenPoolRemotePoolSet, error) {
+ event := new(TokenPoolRemotePoolSet)
+ if err := _TokenPool.contract.UnpackLog(event, "RemotePoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolRouterUpdatedIterator struct {
+ Event *TokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolRouterUpdated)
+ 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(TokenPoolRouterUpdated)
+ 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 *TokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*TokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolRouterUpdatedIterator{contract: _TokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *TokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolRouterUpdated)
+ if err := _TokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_TokenPool *TokenPoolFilterer) ParseRouterUpdated(log types.Log) (*TokenPoolRouterUpdated, error) {
+ event := new(TokenPoolRouterUpdated)
+ if err := _TokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_TokenPool *TokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _TokenPool.abi.Events["AllowListAdd"].ID:
+ return _TokenPool.ParseAllowListAdd(log)
+ case _TokenPool.abi.Events["AllowListRemove"].ID:
+ return _TokenPool.ParseAllowListRemove(log)
+ case _TokenPool.abi.Events["Burned"].ID:
+ return _TokenPool.ParseBurned(log)
+ case _TokenPool.abi.Events["ChainAdded"].ID:
+ return _TokenPool.ParseChainAdded(log)
+ case _TokenPool.abi.Events["ChainConfigured"].ID:
+ return _TokenPool.ParseChainConfigured(log)
+ case _TokenPool.abi.Events["ChainRemoved"].ID:
+ return _TokenPool.ParseChainRemoved(log)
+ case _TokenPool.abi.Events["ConfigChanged"].ID:
+ return _TokenPool.ParseConfigChanged(log)
+ case _TokenPool.abi.Events["Locked"].ID:
+ return _TokenPool.ParseLocked(log)
+ case _TokenPool.abi.Events["Minted"].ID:
+ return _TokenPool.ParseMinted(log)
+ case _TokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _TokenPool.ParseOwnershipTransferRequested(log)
+ case _TokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _TokenPool.ParseOwnershipTransferred(log)
+ case _TokenPool.abi.Events["Released"].ID:
+ return _TokenPool.ParseReleased(log)
+ case _TokenPool.abi.Events["RemotePoolSet"].ID:
+ return _TokenPool.ParseRemotePoolSet(log)
+ case _TokenPool.abi.Events["RouterUpdated"].ID:
+ return _TokenPool.ParseRouterUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (TokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (TokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (TokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (TokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2")
+}
+
+func (TokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (TokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (TokenPoolConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (TokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (TokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (TokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (TokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (TokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (TokenPoolRemotePoolSet) Topic() common.Hash {
+ return common.HexToHash("0xdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf")
+}
+
+func (TokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (_TokenPool *TokenPool) Address() common.Address {
+ return _TokenPool.address
+}
+
+type TokenPoolInterface interface {
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRmnProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*TokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *TokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*TokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*TokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *TokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*TokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*TokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *TokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*TokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*TokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *TokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*TokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*TokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *TokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*TokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*TokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *TokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*TokenPoolChainRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*TokenPoolConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *TokenPoolConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*TokenPoolConfigChanged, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*TokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *TokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*TokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*TokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *TokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*TokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *TokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*TokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *TokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*TokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*TokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *TokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*TokenPoolReleased, error)
+
+ FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*TokenPoolRemotePoolSetIterator, error)
+
+ WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *TokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRemotePoolSet(log types.Log) (*TokenPoolRemotePoolSet, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*TokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *TokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*TokenPoolRouterUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/token_pool_1_4_0/token_pool_1_4_0.go b/core/gethwrappers/ccip/generated/token_pool_1_4_0/token_pool_1_4_0.go
new file mode 100644
index 00000000000..477a32d0fd2
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/token_pool_1_4_0/token_pool_1_4_0.go
@@ -0,0 +1,2221 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package token_pool_1_4_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+var TokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRatelimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getArmProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"releaseOrMint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+}
+
+var TokenPoolABI = TokenPoolMetaData.ABI
+
+type TokenPool struct {
+ address common.Address
+ abi abi.ABI
+ TokenPoolCaller
+ TokenPoolTransactor
+ TokenPoolFilterer
+}
+
+type TokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type TokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type TokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type TokenPoolSession struct {
+ Contract *TokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type TokenPoolCallerSession struct {
+ Contract *TokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type TokenPoolTransactorSession struct {
+ Contract *TokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type TokenPoolRaw struct {
+ Contract *TokenPool
+}
+
+type TokenPoolCallerRaw struct {
+ Contract *TokenPoolCaller
+}
+
+type TokenPoolTransactorRaw struct {
+ Contract *TokenPoolTransactor
+}
+
+func NewTokenPool(address common.Address, backend bind.ContractBackend) (*TokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(TokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPool{address: address, abi: abi, TokenPoolCaller: TokenPoolCaller{contract: contract}, TokenPoolTransactor: TokenPoolTransactor{contract: contract}, TokenPoolFilterer: TokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*TokenPoolCaller, error) {
+ contract, err := bindTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolCaller{contract: contract}, nil
+}
+
+func NewTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*TokenPoolTransactor, error) {
+ contract, err := bindTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolTransactor{contract: contract}, nil
+}
+
+func NewTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*TokenPoolFilterer, error) {
+ contract, err := bindTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolFilterer{contract: contract}, nil
+}
+
+func bindTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := TokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_TokenPool *TokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _TokenPool.Contract.TokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_TokenPool *TokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenPool.Contract.TokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_TokenPool *TokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _TokenPool.Contract.TokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_TokenPool *TokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _TokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_TokenPool *TokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_TokenPool *TokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _TokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_TokenPool *TokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _TokenPool.Contract.GetAllowList(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _TokenPool.Contract.GetAllowList(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _TokenPool.Contract.GetAllowListEnabled(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _TokenPool.Contract.GetAllowListEnabled(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetArmProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getArmProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetArmProxy() (common.Address, error) {
+ return _TokenPool.Contract.GetArmProxy(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetArmProxy() (common.Address, error) {
+ return _TokenPool.Contract.GetArmProxy(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _TokenPool.Contract.GetCurrentInboundRateLimiterState(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _TokenPool.Contract.GetCurrentInboundRateLimiterState(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _TokenPool.Contract.GetCurrentOutboundRateLimiterState(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _TokenPool.Contract.GetCurrentOutboundRateLimiterState(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetRouter() (common.Address, error) {
+ return _TokenPool.Contract.GetRouter(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _TokenPool.Contract.GetRouter(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _TokenPool.Contract.GetSupportedChains(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _TokenPool.Contract.GetSupportedChains(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) GetToken() (common.Address, error) {
+ return _TokenPool.Contract.GetToken(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _TokenPool.Contract.GetToken(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _TokenPool.Contract.IsSupportedChain(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _TokenPool.Contract.IsSupportedChain(&_TokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_TokenPool *TokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) Owner() (common.Address, error) {
+ return _TokenPool.Contract.Owner(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCallerSession) Owner() (common.Address, error) {
+ return _TokenPool.Contract.Owner(&_TokenPool.CallOpts)
+}
+
+func (_TokenPool *TokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _TokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_TokenPool *TokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _TokenPool.Contract.SupportsInterface(&_TokenPool.CallOpts, interfaceId)
+}
+
+func (_TokenPool *TokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _TokenPool.Contract.SupportsInterface(&_TokenPool.CallOpts, interfaceId)
+}
+
+func (_TokenPool *TokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_TokenPool *TokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _TokenPool.Contract.AcceptOwnership(&_TokenPool.TransactOpts)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _TokenPool.Contract.AcceptOwnership(&_TokenPool.TransactOpts)
+}
+
+func (_TokenPool *TokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_TokenPool *TokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.ApplyAllowListUpdates(&_TokenPool.TransactOpts, removes, adds)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.ApplyAllowListUpdates(&_TokenPool.TransactOpts, removes, adds)
+}
+
+func (_TokenPool *TokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_TokenPool *TokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _TokenPool.Contract.ApplyChainUpdates(&_TokenPool.TransactOpts, chains)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _TokenPool.Contract.ApplyChainUpdates(&_TokenPool.TransactOpts, chains)
+}
+
+func (_TokenPool *TokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, receiver []byte, amount *big.Int, remoteChainSelector uint64, extraArgs []byte) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "lockOrBurn", originalSender, receiver, amount, remoteChainSelector, extraArgs)
+}
+
+func (_TokenPool *TokenPoolSession) LockOrBurn(originalSender common.Address, receiver []byte, amount *big.Int, remoteChainSelector uint64, extraArgs []byte) (*types.Transaction, error) {
+ return _TokenPool.Contract.LockOrBurn(&_TokenPool.TransactOpts, originalSender, receiver, amount, remoteChainSelector, extraArgs)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) LockOrBurn(originalSender common.Address, receiver []byte, amount *big.Int, remoteChainSelector uint64, extraArgs []byte) (*types.Transaction, error) {
+ return _TokenPool.Contract.LockOrBurn(&_TokenPool.TransactOpts, originalSender, receiver, amount, remoteChainSelector, extraArgs)
+}
+
+func (_TokenPool *TokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, originalSender []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, extraData []byte) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "releaseOrMint", originalSender, receiver, amount, remoteChainSelector, extraData)
+}
+
+func (_TokenPool *TokenPoolSession) ReleaseOrMint(originalSender []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, extraData []byte) (*types.Transaction, error) {
+ return _TokenPool.Contract.ReleaseOrMint(&_TokenPool.TransactOpts, originalSender, receiver, amount, remoteChainSelector, extraData)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) ReleaseOrMint(originalSender []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, extraData []byte) (*types.Transaction, error) {
+ return _TokenPool.Contract.ReleaseOrMint(&_TokenPool.TransactOpts, originalSender, receiver, amount, remoteChainSelector, extraData)
+}
+
+func (_TokenPool *TokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_TokenPool *TokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetChainRateLimiterConfig(&_TokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetChainRateLimiterConfig(&_TokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_TokenPool *TokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_TokenPool *TokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetRouter(&_TokenPool.TransactOpts, newRouter)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.SetRouter(&_TokenPool.TransactOpts, newRouter)
+}
+
+func (_TokenPool *TokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _TokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_TokenPool *TokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.TransferOwnership(&_TokenPool.TransactOpts, to)
+}
+
+func (_TokenPool *TokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _TokenPool.Contract.TransferOwnership(&_TokenPool.TransactOpts, to)
+}
+
+type TokenPoolAllowListAddIterator struct {
+ Event *TokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolAllowListAdd)
+ 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(TokenPoolAllowListAdd)
+ 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 *TokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*TokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolAllowListAddIterator{contract: _TokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *TokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolAllowListAdd)
+ if err := _TokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_TokenPool *TokenPoolFilterer) ParseAllowListAdd(log types.Log) (*TokenPoolAllowListAdd, error) {
+ event := new(TokenPoolAllowListAdd)
+ if err := _TokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolAllowListRemoveIterator struct {
+ Event *TokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolAllowListRemove)
+ 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(TokenPoolAllowListRemove)
+ 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 *TokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*TokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolAllowListRemoveIterator{contract: _TokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *TokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolAllowListRemove)
+ if err := _TokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_TokenPool *TokenPoolFilterer) ParseAllowListRemove(log types.Log) (*TokenPoolAllowListRemove, error) {
+ event := new(TokenPoolAllowListRemove)
+ if err := _TokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolBurnedIterator struct {
+ Event *TokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolBurned)
+ 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(TokenPoolBurned)
+ 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 *TokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*TokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolBurnedIterator{contract: _TokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *TokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolBurned)
+ if err := _TokenPool.contract.UnpackLog(event, "Burned", 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 (_TokenPool *TokenPoolFilterer) ParseBurned(log types.Log) (*TokenPoolBurned, error) {
+ event := new(TokenPoolBurned)
+ if err := _TokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolChainAddedIterator struct {
+ Event *TokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolChainAdded)
+ 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(TokenPoolChainAdded)
+ 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 *TokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*TokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolChainAddedIterator{contract: _TokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *TokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolChainAdded)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_TokenPool *TokenPoolFilterer) ParseChainAdded(log types.Log) (*TokenPoolChainAdded, error) {
+ event := new(TokenPoolChainAdded)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolChainConfiguredIterator struct {
+ Event *TokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolChainConfigured)
+ 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(TokenPoolChainConfigured)
+ 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 *TokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*TokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolChainConfiguredIterator{contract: _TokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *TokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolChainConfigured)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_TokenPool *TokenPoolFilterer) ParseChainConfigured(log types.Log) (*TokenPoolChainConfigured, error) {
+ event := new(TokenPoolChainConfigured)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolChainRemovedIterator struct {
+ Event *TokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolChainRemoved)
+ 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(TokenPoolChainRemoved)
+ 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 *TokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*TokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolChainRemovedIterator{contract: _TokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *TokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolChainRemoved)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_TokenPool *TokenPoolFilterer) ParseChainRemoved(log types.Log) (*TokenPoolChainRemoved, error) {
+ event := new(TokenPoolChainRemoved)
+ if err := _TokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolLockedIterator struct {
+ Event *TokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolLocked)
+ 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(TokenPoolLocked)
+ 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 *TokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*TokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolLockedIterator{contract: _TokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *TokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolLocked)
+ if err := _TokenPool.contract.UnpackLog(event, "Locked", 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 (_TokenPool *TokenPoolFilterer) ParseLocked(log types.Log) (*TokenPoolLocked, error) {
+ event := new(TokenPoolLocked)
+ if err := _TokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolMintedIterator struct {
+ Event *TokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolMinted)
+ 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(TokenPoolMinted)
+ 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 *TokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*TokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolMintedIterator{contract: _TokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *TokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolMinted)
+ if err := _TokenPool.contract.UnpackLog(event, "Minted", 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 (_TokenPool *TokenPoolFilterer) ParseMinted(log types.Log) (*TokenPoolMinted, error) {
+ event := new(TokenPoolMinted)
+ if err := _TokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolOwnershipTransferRequestedIterator struct {
+ Event *TokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolOwnershipTransferRequested)
+ 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(TokenPoolOwnershipTransferRequested)
+ 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 *TokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolOwnershipTransferRequestedIterator{contract: _TokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *TokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolOwnershipTransferRequested)
+ if err := _TokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_TokenPool *TokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*TokenPoolOwnershipTransferRequested, error) {
+ event := new(TokenPoolOwnershipTransferRequested)
+ if err := _TokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolOwnershipTransferredIterator struct {
+ Event *TokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolOwnershipTransferred)
+ 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(TokenPoolOwnershipTransferred)
+ 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 *TokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolOwnershipTransferredIterator{contract: _TokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *TokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolOwnershipTransferred)
+ if err := _TokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_TokenPool *TokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*TokenPoolOwnershipTransferred, error) {
+ event := new(TokenPoolOwnershipTransferred)
+ if err := _TokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolReleasedIterator struct {
+ Event *TokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolReleased)
+ 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(TokenPoolReleased)
+ 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 *TokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*TokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolReleasedIterator{contract: _TokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *TokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolReleased)
+ if err := _TokenPool.contract.UnpackLog(event, "Released", 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 (_TokenPool *TokenPoolFilterer) ParseReleased(log types.Log) (*TokenPoolReleased, error) {
+ event := new(TokenPoolReleased)
+ if err := _TokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type TokenPoolRouterUpdatedIterator struct {
+ Event *TokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *TokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(TokenPoolRouterUpdated)
+ 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(TokenPoolRouterUpdated)
+ 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 *TokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *TokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type TokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_TokenPool *TokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*TokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _TokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPoolRouterUpdatedIterator{contract: _TokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_TokenPool *TokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *TokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _TokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(TokenPoolRouterUpdated)
+ if err := _TokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_TokenPool *TokenPoolFilterer) ParseRouterUpdated(log types.Log) (*TokenPoolRouterUpdated, error) {
+ event := new(TokenPoolRouterUpdated)
+ if err := _TokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_TokenPool *TokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _TokenPool.abi.Events["AllowListAdd"].ID:
+ return _TokenPool.ParseAllowListAdd(log)
+ case _TokenPool.abi.Events["AllowListRemove"].ID:
+ return _TokenPool.ParseAllowListRemove(log)
+ case _TokenPool.abi.Events["Burned"].ID:
+ return _TokenPool.ParseBurned(log)
+ case _TokenPool.abi.Events["ChainAdded"].ID:
+ return _TokenPool.ParseChainAdded(log)
+ case _TokenPool.abi.Events["ChainConfigured"].ID:
+ return _TokenPool.ParseChainConfigured(log)
+ case _TokenPool.abi.Events["ChainRemoved"].ID:
+ return _TokenPool.ParseChainRemoved(log)
+ case _TokenPool.abi.Events["Locked"].ID:
+ return _TokenPool.ParseLocked(log)
+ case _TokenPool.abi.Events["Minted"].ID:
+ return _TokenPool.ParseMinted(log)
+ case _TokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _TokenPool.ParseOwnershipTransferRequested(log)
+ case _TokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _TokenPool.ParseOwnershipTransferred(log)
+ case _TokenPool.abi.Events["Released"].ID:
+ return _TokenPool.ParseReleased(log)
+ case _TokenPool.abi.Events["RouterUpdated"].ID:
+ return _TokenPool.ParseRouterUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (TokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (TokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (TokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (TokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x0f135cbb9afa12a8bf3bbd071c117bcca4ddeca6160ef7f33d012a81b9c0c471")
+}
+
+func (TokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (TokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (TokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (TokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (TokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (TokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (TokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (TokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (_TokenPool *TokenPool) Address() common.Address {
+ return _TokenPool.address
+}
+
+type TokenPoolInterface interface {
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetArmProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, receiver []byte, amount *big.Int, remoteChainSelector uint64, extraArgs []byte) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, originalSender []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, extraData []byte) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*TokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *TokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*TokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*TokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *TokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*TokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*TokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *TokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*TokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*TokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *TokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*TokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*TokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *TokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*TokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*TokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *TokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*TokenPoolChainRemoved, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*TokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *TokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*TokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*TokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *TokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*TokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *TokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*TokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *TokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*TokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*TokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *TokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*TokenPoolReleased, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*TokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *TokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*TokenPoolRouterUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/usdc_token_pool/usdc_token_pool.go b/core/gethwrappers/ccip/generated/usdc_token_pool/usdc_token_pool.go
new file mode 100644
index 00000000000..1e15b6b6cde
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/usdc_token_pool/usdc_token_pool.go
@@ -0,0 +1,3185 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package usdc_token_pool
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type PoolLockOrBurnInV1 struct {
+ Receiver []byte
+ RemoteChainSelector uint64
+ OriginalSender common.Address
+ Amount *big.Int
+ LocalToken common.Address
+}
+
+type PoolLockOrBurnOutV1 struct {
+ DestTokenAddress []byte
+ DestPoolData []byte
+}
+
+type PoolReleaseOrMintInV1 struct {
+ OriginalSender []byte
+ RemoteChainSelector uint64
+ Receiver common.Address
+ Amount *big.Int
+ LocalToken common.Address
+ SourcePoolAddress []byte
+ SourcePoolData []byte
+ OffchainTokenData []byte
+}
+
+type PoolReleaseOrMintOutV1 struct {
+ DestinationAmount *big.Int
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ RemotePoolAddress []byte
+ RemoteTokenAddress []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+type USDCTokenPoolDomain struct {
+ AllowedCaller [32]byte
+ DomainIdentifier uint32
+ Enabled bool
+}
+
+type USDCTokenPoolDomainUpdate struct {
+ AllowedCaller [32]byte
+ DomainIdentifier uint32
+ DestChainSelector uint64
+ Enabled bool
+}
+
+var USDCTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractITokenMessenger\",\"name\":\"tokenMessenger\",\"type\":\"address\"},{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CursedByRMN\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"expected\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"got\",\"type\":\"uint32\"}],\"name\":\"InvalidDestinationDomain\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"allowedCaller\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"domainIdentifier\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structUSDCTokenPool.DomainUpdate\",\"name\":\"domain\",\"type\":\"tuple\"}],\"name\":\"InvalidDomain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"}],\"name\":\"InvalidMessageVersion\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"expected\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"got\",\"type\":\"uint64\"}],\"name\":\"InvalidNonce\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRateLimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"}],\"name\":\"InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"expected\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"got\",\"type\":\"uint32\"}],\"name\":\"InvalidSourceDomain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidSourcePoolAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"InvalidToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"}],\"name\":\"InvalidTokenMessengerVersion\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"domain\",\"type\":\"uint64\"}],\"name\":\"UnknownDomain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnlockingUSDCFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remoteToken\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenMessenger\",\"type\":\"address\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"allowedCaller\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"domainIdentifier\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structUSDCTokenPool.DomainUpdate[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"DomainsSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"previousPoolAddress\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"RemotePoolSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokens\",\"type\":\"uint256\"}],\"name\":\"TokensConsumed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SUPPORTED_USDC_VERSION\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"remoteTokenAddress\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"getDomain\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"allowedCaller\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"domainIdentifier\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structUSDCTokenPool.Domain\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemotePool\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getRemoteToken\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRmnProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rmnProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_localDomainIdentifier\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_messageTransmitter\",\"outputs\":[{\"internalType\":\"contractIMessageTransmitter\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_tokenMessenger\",\"outputs\":[{\"internalType\":\"contractITokenMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"isSupportedToken\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"}],\"internalType\":\"structPool.LockOrBurnInV1\",\"name\":\"lockOrBurnIn\",\"type\":\"tuple\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destPoolData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.LockOrBurnOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"originalSender\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"sourcePoolData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainTokenData\",\"type\":\"bytes\"}],\"internalType\":\"structPool.ReleaseOrMintInV1\",\"name\":\"releaseOrMintIn\",\"type\":\"tuple\"}],\"name\":\"releaseOrMint\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"destinationAmount\",\"type\":\"uint256\"}],\"internalType\":\"structPool.ReleaseOrMintOutV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"allowedCaller\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"domainIdentifier\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structUSDCTokenPool.DomainUpdate[]\",\"name\":\"domains\",\"type\":\"tuple[]\"}],\"name\":\"setDomains\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"remotePoolAddress\",\"type\":\"bytes\"}],\"name\":\"setRemotePool\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x6101406040523480156200001257600080fd5b506040516200559338038062005593833981016040819052620000359162000b4c565b838383833380600081620000905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c357620000c3816200041b565b5050506001600160a01b0384161580620000e457506001600160a01b038116155b80620000f757506001600160a01b038216155b1562000116576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c0526200016957604080516000815260208101909152620001699084620004c6565b5050506001600160a01b038616905062000196576040516306b7c75960e31b815260040160405180910390fd5b6000856001600160a01b0316632c1219216040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001d7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001fd919062000c72565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000240573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000266919062000c99565b905063ffffffff81161562000297576040516334697c6b60e11b815263ffffffff8216600482015260240162000087565b6000876001600160a01b0316639cdbb1816040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fe919062000c99565b905063ffffffff8116156200032f576040516316ba39c560e31b815263ffffffff8216600482015260240162000087565b6001600160a01b0380891660e05283166101008190526040805163234d8e3d60e21b81529051638d3638f4916004808201926020929091908290030181865afa15801562000381573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003a7919062000c99565b63ffffffff166101205260e051608051620003d1916001600160a01b039091169060001962000623565b6040516001600160a01b03891681527f2e902d38f15b233cbb63711add0fca4545334d3a169d60c0a616494d7eea95449060200160405180910390a1505050505050505062000de6565b336001600160a01b03821603620004755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000087565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c051620004e7576040516335f4a7b360e01b815260040160405180910390fd5b60005b8251811015620005725760008382815181106200050b576200050b62000cc1565b602090810291909101015190506200052560028262000709565b1562000568576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50600101620004ea565b5060005b81518110156200061e57600082828151811062000597576200059762000cc1565b6020026020010151905060006001600160a01b0316816001600160a01b031603620005c3575062000615565b620005d060028262000729565b1562000613576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b60010162000576565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801562000675573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200069b919062000cd7565b620006a7919062000d07565b604080516001600160a01b038616602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b1790915291925062000703918691906200074016565b50505050565b600062000720836001600160a01b03841662000811565b90505b92915050565b600062000720836001600160a01b03841662000915565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564908201526000906200078f906001600160a01b03851690849062000967565b8051909150156200061e5780806020019051810190620007b0919062000d1d565b6200061e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000087565b600081815260018301602052604081205480156200090a5760006200083860018362000d41565b85549091506000906200084e9060019062000d41565b9050818114620008ba57600086600001828154811062000872576200087262000cc1565b906000526020600020015490508087600001848154811062000898576200089862000cc1565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620008ce57620008ce62000d57565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000723565b600091505062000723565b60008181526001830160205260408120546200095e5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000723565b50600062000723565b606062000978848460008562000980565b949350505050565b606082471015620009e35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000087565b600080866001600160a01b0316858760405162000a01919062000d93565b60006040518083038185875af1925050503d806000811462000a40576040519150601f19603f3d011682016040523d82523d6000602084013e62000a45565b606091505b50909250905062000a598783838762000a64565b979650505050505050565b6060831562000ad857825160000362000ad0576001600160a01b0385163b62000ad05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000087565b508162000978565b62000978838381511562000aef5781518083602001fd5b8060405162461bcd60e51b815260040162000087919062000db1565b6001600160a01b038116811462000b2157600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b805162000b478162000b0b565b919050565b600080600080600060a0868803121562000b6557600080fd5b855162000b728162000b0b565b8095505060208087015162000b878162000b0b565b60408801519095506001600160401b038082111562000ba557600080fd5b818901915089601f83011262000bba57600080fd5b81518181111562000bcf5762000bcf62000b24565b8060051b604051601f19603f8301168101818110858211171562000bf75762000bf762000b24565b60405291825284820192508381018501918c83111562000c1657600080fd5b938501935b8285101562000c3f5762000c2f8562000b3a565b8452938501939285019262000c1b565b80985050505050505062000c566060870162000b3a565b915062000c666080870162000b3a565b90509295509295909350565b60006020828403121562000c8557600080fd5b815162000c928162000b0b565b9392505050565b60006020828403121562000cac57600080fd5b815163ffffffff8116811462000c9257600080fd5b634e487b7160e01b600052603260045260246000fd5b60006020828403121562000cea57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8082018082111562000723576200072362000cf1565b60006020828403121562000d3057600080fd5b8151801515811462000c9257600080fd5b8181038181111562000723576200072362000cf1565b634e487b7160e01b600052603160045260246000fd5b60005b8381101562000d8a57818101518382015260200162000d70565b50506000910152565b6000825162000da781846020870162000d6d565b9190910192915050565b602081526000825180602084015262000dd281604085016020870162000d6d565b601f01601f19169190910160400192915050565b60805160a05160c05160e05161010051610120516146ed62000ea66000396000818161036c0152818161116601528181611d6d0152611dcb01526000818161062f0152610a31015260008181610345015261107a0152600081816105f301528181611ef5015261293c01526000818161052f01528181611b6b01526121ab015260008181610279015281816102ce01528181610af70152818161104701528181611a8b015281816120cb015281816127c60152612b2701526146ed6000f3fe608060405234801561001057600080fd5b50600436106101d95760003560e01c80639fdf13ff11610104578063c75eea9c116100a2578063dfadfa3511610071578063dfadfa3514610553578063e0351e13146105f1578063f2fde38b14610617578063fbf84dd71461062a57600080fd5b8063c75eea9c146104f4578063cf7401f314610507578063db6327dc1461051a578063dc0bd9711461052d57600080fd5b8063b0f479a1116100de578063b0f479a11461049b578063b7946580146104b9578063c0d78655146104cc578063c4bffe2b146104df57600080fd5b80639fdf13ff1461040f578063a7cd63b714610417578063af58d59f1461042c57600080fd5b806354c8a4f31161017c57806379ba50971161014b57806379ba5097146103b65780638926f54f146103be5780638da5cb5b146103d15780639a4575b9146103ef57600080fd5b806354c8a4f31461032d5780636155cda0146103405780636b716b0d1461036757806378a010b2146103a357600080fd5b8063181f5a77116101b8578063181f5a771461023b57806321df0da714610277578063240028e8146102be578063390775371461030b57600080fd5b806241d3c1146101de57806301ffc9a7146101f35780630a2fd4931461021b575b600080fd5b6101f16101ec3660046134d1565b610651565b005b610206610201366004613546565b6107ee565b60405190151581526020015b60405180910390f35b61022e6102293660046135ae565b6108d3565b6040516102129190613639565b61022e6040518060400160405280601381526020017f55534443546f6b656e506f6f6c20312e342e300000000000000000000000000081525081565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610212565b6102066102cc366004613679565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b61031e610319366004613696565b610983565b60405190518152602001610212565b6101f161033b36600461371e565b610bb5565b6102997f000000000000000000000000000000000000000000000000000000000000000081565b61038e7f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff9091168152602001610212565b6101f16103b136600461378a565b610c30565b6101f1610d9f565b6102066103cc3660046135ae565b610e9c565b60005473ffffffffffffffffffffffffffffffffffffffff16610299565b6104026103fd36600461380f565b610eb3565b604051610212919061384a565b61038e600081565b61041f6111e0565b60405161021291906138aa565b61043f61043a3660046135ae565b6111f1565b604051610212919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610299565b61022e6104c73660046135ae565b6112c6565b6101f16104da366004613679565b6112f1565b6104e76113c5565b6040516102129190613904565b61043f6105023660046135ae565b61147d565b6101f1610515366004613a8f565b61154f565b6101f1610528366004613ad6565b611567565b7f0000000000000000000000000000000000000000000000000000000000000000610299565b6105c76105613660046135ae565b60408051606080820183526000808352602080840182905292840181905267ffffffffffffffff949094168452600882529282902082519384018352805484526001015463ffffffff811691840191909152640100000000900460ff1615159082015290565b604080518251815260208084015163ffffffff169082015291810151151590820152606001610212565b7f0000000000000000000000000000000000000000000000000000000000000000610206565b6101f1610625366004613679565b6119ed565b6102997f000000000000000000000000000000000000000000000000000000000000000081565b610659611a01565b60005b818110156107b057600083838381811061067857610678613b18565b90506080020180360381019061068e9190613b5b565b805190915015806106ab5750604081015167ffffffffffffffff16155b1561071a57604080517fa087bd2900000000000000000000000000000000000000000000000000000000815282516004820152602083015163ffffffff1660248201529082015167ffffffffffffffff1660448201526060820151151560648201526084015b60405180910390fd5b60408051606080820183528351825260208085015163ffffffff9081168285019081529286015115158486019081529585015167ffffffffffffffff166000908152600890925293902091518255516001918201805494511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090951691909316179290921790550161065c565b507f1889010d2535a0ab1643678d1da87fbbe8b87b2f585b47ddb72ec622aef9ee5682826040516107e2929190613bd5565b60405180910390a15050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167faff2afbf00000000000000000000000000000000000000000000000000000000148061088157507fffffffff0000000000000000000000000000000000000000000000000000000082167f0e64dd2900000000000000000000000000000000000000000000000000000000145b806108cd57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b67ffffffffffffffff811660009081526007602052604090206004018054606091906108fe90613c5c565b80601f016020809104026020016040519081016040528092919081815260200182805461092a90613c5c565b80156109775780601f1061094c57610100808354040283529160200191610977565b820191906000526020600020905b81548152906001019060200180831161095a57829003601f168201915b50505050509050919050565b6040805160208101909152600081526109a361099e83613d5a565b611a84565b60006109b260c0840184613e4f565b8101906109bf9190613eb4565b905060006109d060e0850185613e4f565b8101906109dd9190613ef3565b90506109ed816000015183611cb5565b805160208201516040517f57ecfd2800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016926357ecfd2892610a6492600401613f84565b6020604051808303816000875af1158015610a83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa79190613fa9565b610add576040517fbf969f2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b2273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016336060870135611e66565b610b326060850160408601613679565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f08660600135604051610b9491815260200190565b60405180910390a35050604080516020810190915260609092013582525090565b610bbd611a01565b610c2a84848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250611ef392505050565b50505050565b610c38611a01565b610c4183610e9c565b610c83576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401610711565b67ffffffffffffffff831660009081526007602052604081206004018054610caa90613c5c565b80601f0160208091040260200160405190810160405280929190818152602001828054610cd690613c5c565b8015610d235780601f10610cf857610100808354040283529160200191610d23565b820191906000526020600020905b815481529060010190602001808311610d0657829003601f168201915b5050505067ffffffffffffffff8616600090815260076020526040902091925050600401610d5283858361400e565b508367ffffffffffffffff167fdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf828585604051610d9193929190614172565b60405180910390a250505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610e20576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610711565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60006108cd600567ffffffffffffffff84166120a9565b6040805180820190915260608082526020820152610ed8610ed3836141a2565b6120c4565b6000600881610eed60408601602087016135ae565b67ffffffffffffffff168152602080820192909252604090810160002081516060810183528154815260019091015463ffffffff81169382019390935264010000000090920460ff161515908201819052909150610f9457610f5560408401602085016135ae565b6040517fd201c48a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610711565b610f9e8380613e4f565b9050602014610fe557610fb18380613e4f565b6040517fa3c8cf09000000000000000000000000000000000000000000000000000000008152600401610711929190614246565b602081015181516040517ff856ddb60000000000000000000000000000000000000000000000000000000081526060860135600482015263ffffffff90921660248301526044820181905273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116606484015260848301919091526000917f00000000000000000000000000000000000000000000000000000000000000009091169063f856ddb69060a4016020604051808303816000875af11580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e9919061425a565b6040516060860135815290915033907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a260405180604001604052806111468660200160208101906104c791906135ae565b815260408051808201825267ffffffffffffffff851680825263ffffffff7f00000000000000000000000000000000000000000000000000000000000000008116602093840190815284518085019390935251169281019290925290910190606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190529052949350505050565b60606111ec600261228e565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845260028201546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260039091015480841660608301529190910490911660808201526108cd9061229b565b67ffffffffffffffff811660009081526007602052604090206005018054606091906108fe90613c5c565b6112f9611a01565b73ffffffffffffffffffffffffffffffffffffffff8116611346576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f168491016107e2565b606060006113d3600561228e565b90506000815167ffffffffffffffff8111156113f1576113f1613946565b60405190808252806020026020018201604052801561141a578160200160208202803683370190505b50905060005b82518110156114765782818151811061143b5761143b613b18565b602002602001015182828151811061145557611455613b18565b67ffffffffffffffff90921660209283029190910190910152600101611420565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526108cd9061229b565b611557611a01565b61156283838361234d565b505050565b61156f611a01565b60005b8181101561156257600083838381811061158e5761158e613b18565b90506020028101906115a09190614277565b6115a9906142b5565b90506115be8160800151826020015115612437565b6115d18160a00151826020015115612437565b8060200151156118cd5780516115f39060059067ffffffffffffffff16612570565b6116385780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610711565b604081015151158061164d5750606081015151155b15611684576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805161012081018252608083810180516020908101516fffffffffffffffffffffffffffffffff9081168486019081524263ffffffff90811660a0808901829052865151151560c08a01528651860151851660e08a015295518901518416610100890152918752875180860189529489018051850151841686528585019290925281515115158589015281518401518316606080870191909152915188015183168587015283870194855288880151878901908152828a015183890152895167ffffffffffffffff1660009081526007865289902088518051825482890151838e01519289167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316177001000000000000000000000000000000009188168202177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff90811674010000000000000000000000000000000000000000941515850217865584890151948d0151948a16948a168202949094176001860155995180516002860180549b8301519f830151918b169b9093169a909a179d9096168a029c909c179091169615150295909517909855908101519401519381169316909102919091176003820155915190919060048201906118659082614369565b506060820151600582019061187a9082614369565b505081516060830151608084015160a08501516040517f8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c295506118c09493929190614483565b60405180910390a16119e4565b80516118e59060059067ffffffffffffffff1661257c565b61192a5780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610711565b805167ffffffffffffffff16600090815260076020526040812080547fffffffffffffffffffffff000000000000000000000000000000000000000000908116825560018201839055600282018054909116905560038101829055906119936004830182613483565b6119a1600583016000613483565b5050805160405167ffffffffffffffff90911681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d8599169060200160405180910390a15b50600101611572565b6119f5611a01565b6119fe81612588565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611a82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610711565b565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff908116911614611b195760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610711565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015611bc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611beb9190613fa9565b15611c22576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c2f816020015161267d565b6000611c3e82602001516108d3565b9050805160001480611c62575080805190602001208260a001518051906020012014155b15611c9f578160a001516040517f24eb47e50000000000000000000000000000000000000000000000000000000081526004016107119190613639565b611cb1826020015183606001516127a3565b5050565b600482015163ffffffff811615611d00576040517f68d2f8d600000000000000000000000000000000000000000000000000000000815263ffffffff82166004820152602401610711565b6008830151600c8401516014850151602085015163ffffffff808516911614611d6b5760208501516040517fe366a11700000000000000000000000000000000000000000000000000000000815263ffffffff91821660048201529084166024820152604401610711565b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff168263ffffffff1614611e00576040517f77e4802600000000000000000000000000000000000000000000000000000000815263ffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015283166024820152604401610711565b845167ffffffffffffffff828116911614611e5e5784516040517ff917ffea00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff91821660048201529082166024820152604401610711565b505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526115629084906127ea565b7f0000000000000000000000000000000000000000000000000000000000000000611f4a576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015611fe0576000838281518110611f6a57611f6a613b18565b60200260200101519050611f888160026128f690919063ffffffff16565b15611fd75760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50600101611f4d565b5060005b815181101561156257600082828151811061200157612001613b18565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361204557506120a1565b612050600282612918565b1561209f5760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b600101611fe4565b600081815260018301602052604081205415155b9392505050565b60808101517f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9081169116146121595760808101516040517f961c9a4f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610711565b60208101516040517f2cbc26bb00000000000000000000000000000000000000000000000000000000815260809190911b77ffffffffffffffff000000000000000000000000000000001660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632cbc26bb90602401602060405180830381865afa158015612207573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222b9190613fa9565b15612262576040517f53ad11d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61226f816040015161293a565b61227c81602001516129b9565b6119fe81602001518260600151612b07565b606060006120bd83612b4b565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915261232982606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff164261230d919061454b565b85608001516fffffffffffffffffffffffffffffffff16612ba6565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b61235683610e9c565b612398576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401610711565b6123a3826000612437565b67ffffffffffffffff831660009081526007602052604090206123c69083612bd0565b6123d1816000612437565b67ffffffffffffffff831660009081526007602052604090206123f79060020182612bd0565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b83838360405161242a9392919061455e565b60405180910390a1505050565b8151156124fe5781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff1610158061248d575060408201516fffffffffffffffffffffffffffffffff16155b156124c657816040517f8020d12400000000000000000000000000000000000000000000000000000000815260040161071191906145e1565b8015611cb1576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516fffffffffffffffffffffffffffffffff16151580612537575060208201516fffffffffffffffffffffffffffffffff1615155b15611cb157816040517fd68af9cc00000000000000000000000000000000000000000000000000000000815260040161071191906145e1565b60006120bd8383612d72565b60006120bd8383612dc1565b3373ffffffffffffffffffffffffffffffffffffffff821603612607576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610711565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b61268681610e9c565b6126c8576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610711565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015612747573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061276b9190613fa9565b6119fe576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610711565b67ffffffffffffffff82166000908152600760205260409020611cb190600201827f0000000000000000000000000000000000000000000000000000000000000000612eb4565b600061284c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166132379092919063ffffffff16565b805190915015611562578080602001905181019061286a9190613fa9565b611562576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610711565b60006120bd8373ffffffffffffffffffffffffffffffffffffffff8416612dc1565b60006120bd8373ffffffffffffffffffffffffffffffffffffffff8416612d72565b7f0000000000000000000000000000000000000000000000000000000000000000156119fe5761296b600282613246565b6119fe576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610711565b6129c281610e9c565b612a04576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff82166004820152602401610711565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015612a7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aa1919061461d565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146119fe576040517f728fe07b000000000000000000000000000000000000000000000000000000008152336004820152602401610711565b67ffffffffffffffff82166000908152600760205260409020611cb190827f0000000000000000000000000000000000000000000000000000000000000000612eb4565b60608160000180548060200260200160405190810160405280929190818152602001828054801561097757602002820191906000526020600020905b815481526020019060010190808311612b875750505050509050919050565b6000612bc585612bb6848661463a565b612bc09087614651565b613275565b90505b949350505050565b8154600090612bf990700100000000000000000000000000000000900463ffffffff164261454b565b90508015612c9b5760018301548354612c41916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612ba6565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b60208201518354612cc1916fffffffffffffffffffffffffffffffff9081169116613275565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c199061242a9084906145e1565b6000818152600183016020526040812054612db9575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556108cd565b5060006108cd565b60008181526001830160205260408120548015612eaa576000612de560018361454b565b8554909150600090612df99060019061454b565b9050818114612e5e576000866000018281548110612e1957612e19613b18565b9060005260206000200154905080876000018481548110612e3c57612e3c613b18565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612e6f57612e6f614664565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506108cd565b60009150506108cd565b825474010000000000000000000000000000000000000000900460ff161580612edb575081155b15612ee557505050565b825460018401546fffffffffffffffffffffffffffffffff80831692911690600090612f2b90700100000000000000000000000000000000900463ffffffff164261454b565b90508015612feb5781831115612f6d576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001860154612fa79083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612ba6565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156130a25773ffffffffffffffffffffffffffffffffffffffff841661304a576040517ff94ebcd10000000000000000000000000000000000000000000000000000000081526004810183905260248101869052604401610711565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff85166044820152606401610711565b848310156131b55760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169060009082906130e6908261454b565b6130f0878a61454b565b6130fa9190614651565b6131049190614693565b905073ffffffffffffffffffffffffffffffffffffffff861661315d576040517f15279c080000000000000000000000000000000000000000000000000000000081526004810182905260248101869052604401610711565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff87166044820152606401610711565b6131bf858461454b565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b6060612bc8848460008561328b565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156120bd565b600081831061328457816120bd565b5090919050565b60608247101561331d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610711565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161334691906146ce565b60006040518083038185875af1925050503d8060008114613383576040519150601f19603f3d011682016040523d82523d6000602084013e613388565b606091505b5091509150613399878383876133a4565b979650505050505050565b6060831561343a5782516000036134335773ffffffffffffffffffffffffffffffffffffffff85163b613433576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610711565b5081612bc8565b612bc8838381511561344f5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107119190613639565b50805461348f90613c5c565b6000825580601f1061349f575050565b601f0160209004906000526020600020908101906119fe91905b808211156134cd57600081556001016134b9565b5090565b600080602083850312156134e457600080fd5b823567ffffffffffffffff808211156134fc57600080fd5b818501915085601f83011261351057600080fd5b81358181111561351f57600080fd5b8660208260071b850101111561353457600080fd5b60209290920196919550909350505050565b60006020828403121561355857600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146120bd57600080fd5b67ffffffffffffffff811681146119fe57600080fd5b80356135a981613588565b919050565b6000602082840312156135c057600080fd5b81356120bd81613588565b60005b838110156135e65781810151838201526020016135ce565b50506000910152565b600081518084526136078160208601602086016135cb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006120bd60208301846135ef565b73ffffffffffffffffffffffffffffffffffffffff811681146119fe57600080fd5b80356135a98161364c565b60006020828403121561368b57600080fd5b81356120bd8161364c565b6000602082840312156136a857600080fd5b813567ffffffffffffffff8111156136bf57600080fd5b820161010081850312156120bd57600080fd5b60008083601f8401126136e457600080fd5b50813567ffffffffffffffff8111156136fc57600080fd5b6020830191508360208260051b850101111561371757600080fd5b9250929050565b6000806000806040858703121561373457600080fd5b843567ffffffffffffffff8082111561374c57600080fd5b613758888389016136d2565b9096509450602087013591508082111561377157600080fd5b5061377e878288016136d2565b95989497509550505050565b60008060006040848603121561379f57600080fd5b83356137aa81613588565b9250602084013567ffffffffffffffff808211156137c757600080fd5b818601915086601f8301126137db57600080fd5b8135818111156137ea57600080fd5b8760208285010111156137fc57600080fd5b6020830194508093505050509250925092565b60006020828403121561382157600080fd5b813567ffffffffffffffff81111561383857600080fd5b820160a081850312156120bd57600080fd5b60208152600082516040602084015261386660608401826135ef565b905060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08483030160408501526138a182826135ef565b95945050505050565b6020808252825182820181905260009190848201906040850190845b818110156138f857835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016138c6565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156138f857835167ffffffffffffffff1683529284019291840191600101613920565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff8111828210171561399957613999613946565b60405290565b6040805190810167ffffffffffffffff8111828210171561399957613999613946565b60405160c0810167ffffffffffffffff8111828210171561399957613999613946565b80151581146119fe57600080fd5b80356135a9816139e5565b80356fffffffffffffffffffffffffffffffff811681146135a957600080fd5b600060608284031215613a3057600080fd5b6040516060810181811067ffffffffffffffff82111715613a5357613a53613946565b6040529050808235613a64816139e5565b8152613a72602084016139fe565b6020820152613a83604084016139fe565b60408201525092915050565b600080600060e08486031215613aa457600080fd5b8335613aaf81613588565b9250613abe8560208601613a1e565b9150613acd8560808601613a1e565b90509250925092565b60008060208385031215613ae957600080fd5b823567ffffffffffffffff811115613b0057600080fd5b613b0c858286016136d2565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b803563ffffffff811681146135a957600080fd5b600060808284031215613b6d57600080fd5b6040516080810181811067ffffffffffffffff82111715613b9057613b90613946565b60405282358152613ba360208401613b47565b60208201526040830135613bb681613588565b60408201526060830135613bc9816139e5565b60608201529392505050565b6020808252818101839052600090604080840186845b87811015613c4f578135835263ffffffff613c07868401613b47565b168584015283820135613c1981613588565b67ffffffffffffffff1683850152606082810135613c36816139e5565b1515908401526080928301929190910190600101613beb565b5090979650505050505050565b600181811c90821680613c7057607f821691505b602082108103613ca9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600082601f830112613cc057600080fd5b813567ffffffffffffffff80821115613cdb57613cdb613946565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715613d2157613d21613946565b81604052838152866020858801011115613d3a57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60006101008236031215613d6d57600080fd5b613d75613975565b823567ffffffffffffffff80821115613d8d57600080fd5b613d9936838701613caf565b8352613da76020860161359e565b6020840152613db86040860161366e565b604084015260608501356060840152613dd36080860161366e565b608084015260a0850135915080821115613dec57600080fd5b613df836838701613caf565b60a084015260c0850135915080821115613e1157600080fd5b613e1d36838701613caf565b60c084015260e0850135915080821115613e3657600080fd5b50613e4336828601613caf565b60e08301525092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e8457600080fd5b83018035915067ffffffffffffffff821115613e9f57600080fd5b60200191503681900382131561371757600080fd5b600060408284031215613ec657600080fd5b613ece61399f565b8235613ed981613588565b8152613ee760208401613b47565b60208201529392505050565b600060208284031215613f0557600080fd5b813567ffffffffffffffff80821115613f1d57600080fd5b9083019060408286031215613f3157600080fd5b613f3961399f565b823582811115613f4857600080fd5b613f5487828601613caf565b825250602083013582811115613f6957600080fd5b613f7587828601613caf565b60208301525095945050505050565b604081526000613f9760408301856135ef565b82810360208401526138a181856135ef565b600060208284031215613fbb57600080fd5b81516120bd816139e5565b601f821115611562576000816000526020600020601f850160051c81016020861015613fef5750805b601f850160051c820191505b81811015611e5e57828155600101613ffb565b67ffffffffffffffff83111561402657614026613946565b61403a836140348354613c5c565b83613fc6565b6000601f84116001811461408c57600085156140565750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614122565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156140db57868501358255602094850194600190920191016140bb565b5086821015614116577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60408152600061418560408301866135ef565b8281036020840152614198818587614129565b9695505050505050565b600060a082360312156141b457600080fd5b60405160a0810167ffffffffffffffff82821081831117156141d8576141d8613946565b8160405284359150808211156141ed57600080fd5b506141fa36828601613caf565b825250602083013561420b81613588565b6020820152604083013561421e8161364c565b604082015260608381013590820152608083013561423b8161364c565b608082015292915050565b602081526000612bc8602083018486614129565b60006020828403121561426c57600080fd5b81516120bd81613588565b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec18336030181126142ab57600080fd5b9190910192915050565b600061014082360312156142c857600080fd5b6142d06139c2565b6142d98361359e565b81526142e7602084016139f3565b6020820152604083013567ffffffffffffffff8082111561430757600080fd5b61431336838701613caf565b6040840152606085013591508082111561432c57600080fd5b5061433936828601613caf565b60608301525061434c3660808501613a1e565b608082015261435e3660e08501613a1e565b60a082015292915050565b815167ffffffffffffffff81111561438357614383613946565b614397816143918454613c5c565b84613fc6565b602080601f8311600181146143ea57600084156143b45750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611e5e565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561443757888601518255948401946001909101908401614418565b508582101561447357878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600061010067ffffffffffffffff871683528060208401526144a7818401876135ef565b8551151560408581019190915260208701516fffffffffffffffffffffffffffffffff90811660608701529087015116608085015291506144e59050565b8251151560a083015260208301516fffffffffffffffffffffffffffffffff90811660c084015260408401511660e08301526138a1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156108cd576108cd61451c565b67ffffffffffffffff8416815260e081016145aa60208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c0830152612bc8565b606081016108cd82848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b60006020828403121561462f57600080fd5b81516120bd8161364c565b80820281158282048414176108cd576108cd61451c565b808201808211156108cd576108cd61451c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000826146c9577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600082516142ab8184602087016135cb56fea164736f6c6343000818000a",
+}
+
+var USDCTokenPoolABI = USDCTokenPoolMetaData.ABI
+
+var USDCTokenPoolBin = USDCTokenPoolMetaData.Bin
+
+func DeployUSDCTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, tokenMessenger common.Address, token common.Address, allowlist []common.Address, rmnProxy common.Address, router common.Address) (common.Address, *types.Transaction, *USDCTokenPool, error) {
+ parsed, err := USDCTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(USDCTokenPoolBin), backend, tokenMessenger, token, allowlist, rmnProxy, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &USDCTokenPool{address: address, abi: *parsed, USDCTokenPoolCaller: USDCTokenPoolCaller{contract: contract}, USDCTokenPoolTransactor: USDCTokenPoolTransactor{contract: contract}, USDCTokenPoolFilterer: USDCTokenPoolFilterer{contract: contract}}, nil
+}
+
+type USDCTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ USDCTokenPoolCaller
+ USDCTokenPoolTransactor
+ USDCTokenPoolFilterer
+}
+
+type USDCTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type USDCTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type USDCTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type USDCTokenPoolSession struct {
+ Contract *USDCTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type USDCTokenPoolCallerSession struct {
+ Contract *USDCTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type USDCTokenPoolTransactorSession struct {
+ Contract *USDCTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type USDCTokenPoolRaw struct {
+ Contract *USDCTokenPool
+}
+
+type USDCTokenPoolCallerRaw struct {
+ Contract *USDCTokenPoolCaller
+}
+
+type USDCTokenPoolTransactorRaw struct {
+ Contract *USDCTokenPoolTransactor
+}
+
+func NewUSDCTokenPool(address common.Address, backend bind.ContractBackend) (*USDCTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(USDCTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindUSDCTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPool{address: address, abi: abi, USDCTokenPoolCaller: USDCTokenPoolCaller{contract: contract}, USDCTokenPoolTransactor: USDCTokenPoolTransactor{contract: contract}, USDCTokenPoolFilterer: USDCTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewUSDCTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*USDCTokenPoolCaller, error) {
+ contract, err := bindUSDCTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolCaller{contract: contract}, nil
+}
+
+func NewUSDCTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*USDCTokenPoolTransactor, error) {
+ contract, err := bindUSDCTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewUSDCTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*USDCTokenPoolFilterer, error) {
+ contract, err := bindUSDCTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindUSDCTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := USDCTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _USDCTokenPool.Contract.USDCTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_USDCTokenPool *USDCTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.USDCTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.USDCTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _USDCTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) SUPPORTEDUSDCVERSION(opts *bind.CallOpts) (uint32, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "SUPPORTED_USDC_VERSION")
+
+ if err != nil {
+ return *new(uint32), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SUPPORTEDUSDCVERSION() (uint32, error) {
+ return _USDCTokenPool.Contract.SUPPORTEDUSDCVERSION(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) SUPPORTEDUSDCVERSION() (uint32, error) {
+ return _USDCTokenPool.Contract.SUPPORTEDUSDCVERSION(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _USDCTokenPool.Contract.GetAllowList(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _USDCTokenPool.Contract.GetAllowList(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _USDCTokenPool.Contract.GetAllowListEnabled(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _USDCTokenPool.Contract.GetAllowListEnabled(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _USDCTokenPool.Contract.GetCurrentInboundRateLimiterState(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _USDCTokenPool.Contract.GetCurrentInboundRateLimiterState(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _USDCTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _USDCTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetDomain(opts *bind.CallOpts, chainSelector uint64) (USDCTokenPoolDomain, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getDomain", chainSelector)
+
+ if err != nil {
+ return *new(USDCTokenPoolDomain), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(USDCTokenPoolDomain)).(*USDCTokenPoolDomain)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetDomain(chainSelector uint64) (USDCTokenPoolDomain, error) {
+ return _USDCTokenPool.Contract.GetDomain(&_USDCTokenPool.CallOpts, chainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetDomain(chainSelector uint64) (USDCTokenPoolDomain, error) {
+ return _USDCTokenPool.Contract.GetDomain(&_USDCTokenPool.CallOpts, chainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getRemotePool", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _USDCTokenPool.Contract.GetRemotePool(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetRemotePool(remoteChainSelector uint64) ([]byte, error) {
+ return _USDCTokenPool.Contract.GetRemotePool(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getRemoteToken", remoteChainSelector)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _USDCTokenPool.Contract.GetRemoteToken(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetRemoteToken(remoteChainSelector uint64) ([]byte, error) {
+ return _USDCTokenPool.Contract.GetRemoteToken(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetRmnProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getRmnProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetRmnProxy() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetRmnProxy(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetRmnProxy() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetRmnProxy(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetRouter() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetRouter(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetRouter(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _USDCTokenPool.Contract.GetSupportedChains(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _USDCTokenPool.Contract.GetSupportedChains(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetToken() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetToken(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetToken(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) ILocalDomainIdentifier(opts *bind.CallOpts) (uint32, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "i_localDomainIdentifier")
+
+ if err != nil {
+ return *new(uint32), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ILocalDomainIdentifier() (uint32, error) {
+ return _USDCTokenPool.Contract.ILocalDomainIdentifier(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) ILocalDomainIdentifier() (uint32, error) {
+ return _USDCTokenPool.Contract.ILocalDomainIdentifier(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) IMessageTransmitter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "i_messageTransmitter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) IMessageTransmitter() (common.Address, error) {
+ return _USDCTokenPool.Contract.IMessageTransmitter(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) IMessageTransmitter() (common.Address, error) {
+ return _USDCTokenPool.Contract.IMessageTransmitter(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) ITokenMessenger(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "i_tokenMessenger")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ITokenMessenger() (common.Address, error) {
+ return _USDCTokenPool.Contract.ITokenMessenger(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) ITokenMessenger() (common.Address, error) {
+ return _USDCTokenPool.Contract.ITokenMessenger(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _USDCTokenPool.Contract.IsSupportedChain(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _USDCTokenPool.Contract.IsSupportedChain(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "isSupportedToken", token)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _USDCTokenPool.Contract.IsSupportedToken(&_USDCTokenPool.CallOpts, token)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) IsSupportedToken(token common.Address) (bool, error) {
+ return _USDCTokenPool.Contract.IsSupportedToken(&_USDCTokenPool.CallOpts, token)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) Owner() (common.Address, error) {
+ return _USDCTokenPool.Contract.Owner(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _USDCTokenPool.Contract.Owner(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _USDCTokenPool.Contract.SupportsInterface(&_USDCTokenPool.CallOpts, interfaceId)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _USDCTokenPool.Contract.SupportsInterface(&_USDCTokenPool.CallOpts, interfaceId)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) TypeAndVersion() (string, error) {
+ return _USDCTokenPool.Contract.TypeAndVersion(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _USDCTokenPool.Contract.TypeAndVersion(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.AcceptOwnership(&_USDCTokenPool.TransactOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.AcceptOwnership(&_USDCTokenPool.TransactOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ApplyAllowListUpdates(&_USDCTokenPool.TransactOpts, removes, adds)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ApplyAllowListUpdates(&_USDCTokenPool.TransactOpts, removes, adds)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ApplyChainUpdates(&_USDCTokenPool.TransactOpts, chains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ApplyChainUpdates(&_USDCTokenPool.TransactOpts, chains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "lockOrBurn", lockOrBurnIn)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.LockOrBurn(&_USDCTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) LockOrBurn(lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.LockOrBurn(&_USDCTokenPool.TransactOpts, lockOrBurnIn)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "releaseOrMint", releaseOrMintIn)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ReleaseOrMint(&_USDCTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) ReleaseOrMint(releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ReleaseOrMint(&_USDCTokenPool.TransactOpts, releaseOrMintIn)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetChainRateLimiterConfig(&_USDCTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetChainRateLimiterConfig(&_USDCTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) SetDomains(opts *bind.TransactOpts, domains []USDCTokenPoolDomainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "setDomains", domains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SetDomains(domains []USDCTokenPoolDomainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetDomains(&_USDCTokenPool.TransactOpts, domains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) SetDomains(domains []USDCTokenPoolDomainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetDomains(&_USDCTokenPool.TransactOpts, domains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "setRemotePool", remoteChainSelector, remotePoolAddress)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetRemotePool(&_USDCTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) SetRemotePool(remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetRemotePool(&_USDCTokenPool.TransactOpts, remoteChainSelector, remotePoolAddress)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetRouter(&_USDCTokenPool.TransactOpts, newRouter)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetRouter(&_USDCTokenPool.TransactOpts, newRouter)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.TransferOwnership(&_USDCTokenPool.TransactOpts, to)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.TransferOwnership(&_USDCTokenPool.TransactOpts, to)
+}
+
+type USDCTokenPoolAllowListAddIterator struct {
+ Event *USDCTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolAllowListAdd)
+ 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(USDCTokenPoolAllowListAdd)
+ 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 *USDCTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*USDCTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolAllowListAddIterator{contract: _USDCTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolAllowListAdd)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*USDCTokenPoolAllowListAdd, error) {
+ event := new(USDCTokenPoolAllowListAdd)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolAllowListRemoveIterator struct {
+ Event *USDCTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolAllowListRemove)
+ 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(USDCTokenPoolAllowListRemove)
+ 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 *USDCTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*USDCTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolAllowListRemoveIterator{contract: _USDCTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolAllowListRemove)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*USDCTokenPoolAllowListRemove, error) {
+ event := new(USDCTokenPoolAllowListRemove)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolBurnedIterator struct {
+ Event *USDCTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolBurned)
+ 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(USDCTokenPoolBurned)
+ 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 *USDCTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*USDCTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolBurnedIterator{contract: _USDCTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolBurned)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Burned", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseBurned(log types.Log) (*USDCTokenPoolBurned, error) {
+ event := new(USDCTokenPoolBurned)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolChainAddedIterator struct {
+ Event *USDCTokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolChainAdded)
+ 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(USDCTokenPoolChainAdded)
+ 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 *USDCTokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ RemoteToken []byte
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*USDCTokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolChainAddedIterator{contract: _USDCTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolChainAdded)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseChainAdded(log types.Log) (*USDCTokenPoolChainAdded, error) {
+ event := new(USDCTokenPoolChainAdded)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolChainConfiguredIterator struct {
+ Event *USDCTokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolChainConfigured)
+ 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(USDCTokenPoolChainConfigured)
+ 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 *USDCTokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*USDCTokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolChainConfiguredIterator{contract: _USDCTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolChainConfigured)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseChainConfigured(log types.Log) (*USDCTokenPoolChainConfigured, error) {
+ event := new(USDCTokenPoolChainConfigured)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolChainRemovedIterator struct {
+ Event *USDCTokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolChainRemoved)
+ 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(USDCTokenPoolChainRemoved)
+ 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 *USDCTokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*USDCTokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolChainRemovedIterator{contract: _USDCTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolChainRemoved)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseChainRemoved(log types.Log) (*USDCTokenPoolChainRemoved, error) {
+ event := new(USDCTokenPoolChainRemoved)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolConfigChangedIterator struct {
+ Event *USDCTokenPoolConfigChanged
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolConfigChangedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolConfigChanged)
+ 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(USDCTokenPoolConfigChanged)
+ 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 *USDCTokenPoolConfigChangedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolConfigChangedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolConfigChanged struct {
+ Config RateLimiterConfig
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*USDCTokenPoolConfigChangedIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolConfigChangedIterator{contract: _USDCTokenPool.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolConfigChanged) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ConfigChanged")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolConfigChanged)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ConfigChanged", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseConfigChanged(log types.Log) (*USDCTokenPoolConfigChanged, error) {
+ event := new(USDCTokenPoolConfigChanged)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ConfigChanged", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolConfigSetIterator struct {
+ Event *USDCTokenPoolConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolConfigSet)
+ 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(USDCTokenPoolConfigSet)
+ 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 *USDCTokenPoolConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolConfigSet struct {
+ TokenMessenger common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterConfigSet(opts *bind.FilterOpts) (*USDCTokenPoolConfigSetIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolConfigSetIterator{contract: _USDCTokenPool.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolConfigSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ConfigSet", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseConfigSet(log types.Log) (*USDCTokenPoolConfigSet, error) {
+ event := new(USDCTokenPoolConfigSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolDomainsSetIterator struct {
+ Event *USDCTokenPoolDomainsSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolDomainsSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolDomainsSet)
+ 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(USDCTokenPoolDomainsSet)
+ 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 *USDCTokenPoolDomainsSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolDomainsSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolDomainsSet struct {
+ Arg0 []USDCTokenPoolDomainUpdate
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterDomainsSet(opts *bind.FilterOpts) (*USDCTokenPoolDomainsSetIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "DomainsSet")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolDomainsSetIterator{contract: _USDCTokenPool.contract, event: "DomainsSet", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchDomainsSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolDomainsSet) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "DomainsSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolDomainsSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "DomainsSet", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseDomainsSet(log types.Log) (*USDCTokenPoolDomainsSet, error) {
+ event := new(USDCTokenPoolDomainsSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "DomainsSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolLockedIterator struct {
+ Event *USDCTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolLocked)
+ 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(USDCTokenPoolLocked)
+ 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 *USDCTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*USDCTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolLockedIterator{contract: _USDCTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolLocked)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Locked", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseLocked(log types.Log) (*USDCTokenPoolLocked, error) {
+ event := new(USDCTokenPoolLocked)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolMintedIterator struct {
+ Event *USDCTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolMinted)
+ 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(USDCTokenPoolMinted)
+ 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 *USDCTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*USDCTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolMintedIterator{contract: _USDCTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolMinted)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Minted", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseMinted(log types.Log) (*USDCTokenPoolMinted, error) {
+ event := new(USDCTokenPoolMinted)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *USDCTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolOwnershipTransferRequested)
+ 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(USDCTokenPoolOwnershipTransferRequested)
+ 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 *USDCTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*USDCTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolOwnershipTransferRequestedIterator{contract: _USDCTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolOwnershipTransferRequested)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*USDCTokenPoolOwnershipTransferRequested, error) {
+ event := new(USDCTokenPoolOwnershipTransferRequested)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolOwnershipTransferredIterator struct {
+ Event *USDCTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolOwnershipTransferred)
+ 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(USDCTokenPoolOwnershipTransferred)
+ 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 *USDCTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*USDCTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolOwnershipTransferredIterator{contract: _USDCTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolOwnershipTransferred)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*USDCTokenPoolOwnershipTransferred, error) {
+ event := new(USDCTokenPoolOwnershipTransferred)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolReleasedIterator struct {
+ Event *USDCTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolReleased)
+ 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(USDCTokenPoolReleased)
+ 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 *USDCTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*USDCTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolReleasedIterator{contract: _USDCTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolReleased)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Released", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseReleased(log types.Log) (*USDCTokenPoolReleased, error) {
+ event := new(USDCTokenPoolReleased)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolRemotePoolSetIterator struct {
+ Event *USDCTokenPoolRemotePoolSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolRemotePoolSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolRemotePoolSet)
+ 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(USDCTokenPoolRemotePoolSet)
+ 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 *USDCTokenPoolRemotePoolSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolRemotePoolSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolRemotePoolSet struct {
+ RemoteChainSelector uint64
+ PreviousPoolAddress []byte
+ RemotePoolAddress []byte
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*USDCTokenPoolRemotePoolSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolRemotePoolSetIterator{contract: _USDCTokenPool.contract, event: "RemotePoolSet", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "RemotePoolSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolRemotePoolSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "RemotePoolSet", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseRemotePoolSet(log types.Log) (*USDCTokenPoolRemotePoolSet, error) {
+ event := new(USDCTokenPoolRemotePoolSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "RemotePoolSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolRouterUpdatedIterator struct {
+ Event *USDCTokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolRouterUpdated)
+ 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(USDCTokenPoolRouterUpdated)
+ 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 *USDCTokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*USDCTokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolRouterUpdatedIterator{contract: _USDCTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolRouterUpdated)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*USDCTokenPoolRouterUpdated, error) {
+ event := new(USDCTokenPoolRouterUpdated)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolTokensConsumedIterator struct {
+ Event *USDCTokenPoolTokensConsumed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolTokensConsumedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolTokensConsumed)
+ 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(USDCTokenPoolTokensConsumed)
+ 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 *USDCTokenPoolTokensConsumedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolTokensConsumedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolTokensConsumed struct {
+ Tokens *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterTokensConsumed(opts *bind.FilterOpts) (*USDCTokenPoolTokensConsumedIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolTokensConsumedIterator{contract: _USDCTokenPool.contract, event: "TokensConsumed", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolTokensConsumed) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "TokensConsumed")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolTokensConsumed)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "TokensConsumed", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseTokensConsumed(log types.Log) (*USDCTokenPoolTokensConsumed, error) {
+ event := new(USDCTokenPoolTokensConsumed)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "TokensConsumed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_USDCTokenPool *USDCTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _USDCTokenPool.abi.Events["AllowListAdd"].ID:
+ return _USDCTokenPool.ParseAllowListAdd(log)
+ case _USDCTokenPool.abi.Events["AllowListRemove"].ID:
+ return _USDCTokenPool.ParseAllowListRemove(log)
+ case _USDCTokenPool.abi.Events["Burned"].ID:
+ return _USDCTokenPool.ParseBurned(log)
+ case _USDCTokenPool.abi.Events["ChainAdded"].ID:
+ return _USDCTokenPool.ParseChainAdded(log)
+ case _USDCTokenPool.abi.Events["ChainConfigured"].ID:
+ return _USDCTokenPool.ParseChainConfigured(log)
+ case _USDCTokenPool.abi.Events["ChainRemoved"].ID:
+ return _USDCTokenPool.ParseChainRemoved(log)
+ case _USDCTokenPool.abi.Events["ConfigChanged"].ID:
+ return _USDCTokenPool.ParseConfigChanged(log)
+ case _USDCTokenPool.abi.Events["ConfigSet"].ID:
+ return _USDCTokenPool.ParseConfigSet(log)
+ case _USDCTokenPool.abi.Events["DomainsSet"].ID:
+ return _USDCTokenPool.ParseDomainsSet(log)
+ case _USDCTokenPool.abi.Events["Locked"].ID:
+ return _USDCTokenPool.ParseLocked(log)
+ case _USDCTokenPool.abi.Events["Minted"].ID:
+ return _USDCTokenPool.ParseMinted(log)
+ case _USDCTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _USDCTokenPool.ParseOwnershipTransferRequested(log)
+ case _USDCTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _USDCTokenPool.ParseOwnershipTransferred(log)
+ case _USDCTokenPool.abi.Events["Released"].ID:
+ return _USDCTokenPool.ParseReleased(log)
+ case _USDCTokenPool.abi.Events["RemotePoolSet"].ID:
+ return _USDCTokenPool.ParseRemotePoolSet(log)
+ case _USDCTokenPool.abi.Events["RouterUpdated"].ID:
+ return _USDCTokenPool.ParseRouterUpdated(log)
+ case _USDCTokenPool.abi.Events["TokensConsumed"].ID:
+ return _USDCTokenPool.ParseTokensConsumed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (USDCTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (USDCTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (USDCTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (USDCTokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x8d340f17e19058004c20453540862a9c62778504476f6756755cb33bcd6c38c2")
+}
+
+func (USDCTokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (USDCTokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (USDCTokenPoolConfigChanged) Topic() common.Hash {
+ return common.HexToHash("0x9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19")
+}
+
+func (USDCTokenPoolConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x2e902d38f15b233cbb63711add0fca4545334d3a169d60c0a616494d7eea9544")
+}
+
+func (USDCTokenPoolDomainsSet) Topic() common.Hash {
+ return common.HexToHash("0x1889010d2535a0ab1643678d1da87fbbe8b87b2f585b47ddb72ec622aef9ee56")
+}
+
+func (USDCTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (USDCTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (USDCTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (USDCTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (USDCTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (USDCTokenPoolRemotePoolSet) Topic() common.Hash {
+ return common.HexToHash("0xdb4d6220746a38cbc5335f7e108f7de80f482f4d23350253dfd0917df75a14bf")
+}
+
+func (USDCTokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (USDCTokenPoolTokensConsumed) Topic() common.Hash {
+ return common.HexToHash("0x1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a")
+}
+
+func (_USDCTokenPool *USDCTokenPool) Address() common.Address {
+ return _USDCTokenPool.address
+}
+
+type USDCTokenPoolInterface interface {
+ SUPPORTEDUSDCVERSION(opts *bind.CallOpts) (uint32, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetDomain(opts *bind.CallOpts, chainSelector uint64) (USDCTokenPoolDomain, error)
+
+ GetRemotePool(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
+
+ GetRmnProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ ILocalDomainIdentifier(opts *bind.CallOpts) (uint32, error)
+
+ IMessageTransmitter(opts *bind.CallOpts) (common.Address, error)
+
+ ITokenMessenger(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ IsSupportedToken(opts *bind.CallOpts, token common.Address) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, lockOrBurnIn PoolLockOrBurnInV1) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, releaseOrMintIn PoolReleaseOrMintInV1) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetDomains(opts *bind.TransactOpts, domains []USDCTokenPoolDomainUpdate) (*types.Transaction, error)
+
+ SetRemotePool(opts *bind.TransactOpts, remoteChainSelector uint64, remotePoolAddress []byte) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*USDCTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*USDCTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*USDCTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*USDCTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*USDCTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*USDCTokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*USDCTokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*USDCTokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*USDCTokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*USDCTokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*USDCTokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*USDCTokenPoolChainRemoved, error)
+
+ FilterConfigChanged(opts *bind.FilterOpts) (*USDCTokenPoolConfigChangedIterator, error)
+
+ WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolConfigChanged) (event.Subscription, error)
+
+ ParseConfigChanged(log types.Log) (*USDCTokenPoolConfigChanged, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*USDCTokenPoolConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*USDCTokenPoolConfigSet, error)
+
+ FilterDomainsSet(opts *bind.FilterOpts) (*USDCTokenPoolDomainsSetIterator, error)
+
+ WatchDomainsSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolDomainsSet) (event.Subscription, error)
+
+ ParseDomainsSet(log types.Log) (*USDCTokenPoolDomainsSet, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*USDCTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*USDCTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*USDCTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*USDCTokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*USDCTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*USDCTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*USDCTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*USDCTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*USDCTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*USDCTokenPoolReleased, error)
+
+ FilterRemotePoolSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*USDCTokenPoolRemotePoolSetIterator, error)
+
+ WatchRemotePoolSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolRemotePoolSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseRemotePoolSet(log types.Log) (*USDCTokenPoolRemotePoolSet, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*USDCTokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*USDCTokenPoolRouterUpdated, error)
+
+ FilterTokensConsumed(opts *bind.FilterOpts) (*USDCTokenPoolTokensConsumedIterator, error)
+
+ WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolTokensConsumed) (event.Subscription, error)
+
+ ParseTokensConsumed(log types.Log) (*USDCTokenPoolTokensConsumed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/usdc_token_pool_1_4_0/usdc_token_pool_1_4_0.go b/core/gethwrappers/ccip/generated/usdc_token_pool_1_4_0/usdc_token_pool_1_4_0.go
new file mode 100644
index 00000000000..67250b86e60
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/usdc_token_pool_1_4_0/usdc_token_pool_1_4_0.go
@@ -0,0 +1,2693 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package usdc_token_pool_1_4_0
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type RateLimiterTokenBucket struct {
+ Tokens *big.Int
+ LastUpdated uint32
+ IsEnabled bool
+ Capacity *big.Int
+ Rate *big.Int
+}
+
+type TokenPoolChainUpdate struct {
+ RemoteChainSelector uint64
+ Allowed bool
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+}
+
+type USDCTokenPoolDomain struct {
+ AllowedCaller [32]byte
+ DomainIdentifier uint32
+ Enabled bool
+}
+
+type USDCTokenPoolDomainUpdate struct {
+ AllowedCaller [32]byte
+ DomainIdentifier uint32
+ DestChainSelector uint64
+ Enabled bool
+}
+
+var USDCTokenPoolMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractITokenMessenger\",\"name\":\"tokenMessenger\",\"type\":\"address\"},{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"allowlist\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"}],\"name\":\"AggregateValueMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"}],\"name\":\"AggregateValueRateLimitReached\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AllowListNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadARMSignal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BucketOverfilled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"CallerIsNotARampOnRouter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"DisabledNonZeroRateLimit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"expected\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"got\",\"type\":\"uint32\"}],\"name\":\"InvalidDestinationDomain\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"allowedCaller\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"domainIdentifier\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structUSDCTokenPool.DomainUpdate\",\"name\":\"domain\",\"type\":\"tuple\"}],\"name\":\"InvalidDomain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"}],\"name\":\"InvalidMessageVersion\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"expected\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"got\",\"type\":\"uint64\"}],\"name\":\"InvalidNonce\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"rateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"InvalidRatelimitRate\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"expected\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"got\",\"type\":\"uint32\"}],\"name\":\"InvalidSourceDomain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"}],\"name\":\"InvalidTokenMessengerVersion\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"NonExistentChain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RateLimitMustBeDisabled\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderNotAllowed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"capacity\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenMaxCapacityExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minWaitInSeconds\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenAddress\",\"type\":\"address\"}],\"name\":\"TokenRateLimitReached\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"domain\",\"type\":\"uint64\"}],\"name\":\"UnknownDomain\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnlockingUSDCFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListAdd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AllowListRemove\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Burned\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"indexed\":false,\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"name\":\"ChainConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"ChainRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"tokenMessenger\",\"type\":\"address\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"allowedCaller\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"domainIdentifier\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structUSDCTokenPool.DomainUpdate[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"DomainsSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Locked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Minted\",\"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\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Released\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldRouter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"RouterUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"SUPPORTED_USDC_VERSION\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"removes\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"adds\",\"type\":\"address[]\"}],\"name\":\"applyAllowListUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundRateLimiterConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundRateLimiterConfig\",\"type\":\"tuple\"}],\"internalType\":\"structTokenPool.ChainUpdate[]\",\"name\":\"chains\",\"type\":\"tuple[]\"}],\"name\":\"applyChainUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowList\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getArmProxy\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"armProxy\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentInboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"getCurrentOutboundRateLimiterState\",\"outputs\":[{\"components\":[{\"internalType\":\"uint128\",\"name\":\"tokens\",\"type\":\"uint128\"},{\"internalType\":\"uint32\",\"name\":\"lastUpdated\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.TokenBucket\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"getDomain\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"allowedCaller\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"domainIdentifier\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structUSDCTokenPool.Domain\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRouter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getUSDCInterfaceId\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_localDomainIdentifier\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_messageTransmitter\",\"outputs\":[{\"internalType\":\"contractIMessageTransmitter\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_tokenMessenger\",\"outputs\":[{\"internalType\":\"contractITokenMessenger\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"}],\"name\":\"isSupportedChain\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"originalSender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"destinationReceiver\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"lockOrBurn\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"releaseOrMint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"outboundConfig\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint128\",\"name\":\"capacity\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"rate\",\"type\":\"uint128\"}],\"internalType\":\"structRateLimiter.Config\",\"name\":\"inboundConfig\",\"type\":\"tuple\"}],\"name\":\"setChainRateLimiterConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"allowedCaller\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"domainIdentifier\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structUSDCTokenPool.DomainUpdate[]\",\"name\":\"domains\",\"type\":\"tuple[]\"}],\"name\":\"setDomains\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newRouter\",\"type\":\"address\"}],\"name\":\"setRouter\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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: "0x6101406040523480156200001257600080fd5b506040516200458a3803806200458a833981016040819052620000359162000b4d565b838383833380600081620000905760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c357620000c38162000408565b5050506001600160a01b0384161580620000e457506001600160a01b038116155b1562000103576040516342bcdf7f60e11b815260040160405180910390fd5b6001600160a01b0384811660805282811660a052600480546001600160a01b031916918316919091179055825115801560c0526200015657604080516000815260208101909152620001569084620004b3565b5050506001600160a01b038616905062000183576040516306b7c75960e31b815260040160405180910390fd5b6000856001600160a01b0316632c1219216040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001c4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ea919062000c73565b90506000816001600160a01b03166354fd4d506040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200022d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000253919062000c9a565b905063ffffffff81161562000284576040516334697c6b60e11b815263ffffffff8216600482015260240162000087565b6000876001600160a01b0316639cdbb1816040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002c5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002eb919062000c9a565b905063ffffffff8116156200031c576040516316ba39c560e31b815263ffffffff8216600482015260240162000087565b6001600160a01b0380891660e05283166101008190526040805163234d8e3d60e21b81529051638d3638f4916004808201926020929091908290030181865afa1580156200036e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000394919062000c9a565b63ffffffff166101205260e051608051620003be916001600160a01b039091169060001962000624565b6040516001600160a01b03891681527f2e902d38f15b233cbb63711add0fca4545334d3a169d60c0a616494d7eea95449060200160405180910390a1505050505050505062000e03565b336001600160a01b03821603620004625760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000087565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60c051620004d4576040516335f4a7b360e01b815260040160405180910390fd5b60005b825181101562000569576000838281518110620004f857620004f862000cc2565b60209081029190910101519050620005126002826200070a565b1562000555576040516001600160a01b03821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50620005618162000cee565b9050620004d7565b5060005b81518110156200061f5760008282815181106200058e576200058e62000cc2565b6020026020010151905060006001600160a01b0316816001600160a01b031603620005ba57506200060c565b620005c76002826200072a565b156200060a576040516001600160a01b03821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b620006178162000cee565b90506200056d565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa15801562000676573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200069c919062000d0a565b620006a8919062000d24565b604080516001600160a01b038616602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b1790915291925062000704918691906200074116565b50505050565b600062000721836001600160a01b03841662000812565b90505b92915050565b600062000721836001600160a01b03841662000916565b6040805180820190915260208082527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65649082015260009062000790906001600160a01b03851690849062000968565b8051909150156200061f5780806020019051810190620007b1919062000d3a565b6200061f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000087565b600081815260018301602052604081205480156200090b5760006200083960018362000d5e565b85549091506000906200084f9060019062000d5e565b9050818114620008bb57600086600001828154811062000873576200087362000cc2565b906000526020600020015490508087600001848154811062000899576200089962000cc2565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080620008cf57620008cf62000d74565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000724565b600091505062000724565b60008181526001830160205260408120546200095f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000724565b50600062000724565b606062000979848460008562000981565b949350505050565b606082471015620009e45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000087565b600080866001600160a01b0316858760405162000a02919062000db0565b60006040518083038185875af1925050503d806000811462000a41576040519150601f19603f3d011682016040523d82523d6000602084013e62000a46565b606091505b50909250905062000a5a8783838762000a65565b979650505050505050565b6060831562000ad957825160000362000ad1576001600160a01b0385163b62000ad15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000087565b508162000979565b62000979838381511562000af05781518083602001fd5b8060405162461bcd60e51b815260040162000087919062000dce565b6001600160a01b038116811462000b2257600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b805162000b488162000b0c565b919050565b600080600080600060a0868803121562000b6657600080fd5b855162000b738162000b0c565b8095505060208087015162000b888162000b0c565b60408801519095506001600160401b038082111562000ba657600080fd5b818901915089601f83011262000bbb57600080fd5b81518181111562000bd05762000bd062000b25565b8060051b604051601f19603f8301168101818110858211171562000bf85762000bf862000b25565b60405291825284820192508381018501918c83111562000c1757600080fd5b938501935b8285101562000c405762000c308562000b3b565b8452938501939285019262000c1c565b80985050505050505062000c576060870162000b3b565b915062000c676080870162000b3b565b90509295509295909350565b60006020828403121562000c8657600080fd5b815162000c938162000b0c565b9392505050565b60006020828403121562000cad57600080fd5b815163ffffffff8116811462000c9357600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820162000d035762000d0362000cd8565b5060010190565b60006020828403121562000d1d57600080fd5b5051919050565b8082018082111562000724576200072462000cd8565b60006020828403121562000d4d57600080fd5b8151801515811462000c9357600080fd5b8181038181111562000724576200072462000cd8565b634e487b7160e01b600052603160045260246000fd5b60005b8381101562000da757818101518382015260200162000d8d565b50506000910152565b6000825162000dc481846020870162000d8a565b9190910192915050565b602081526000825180602084015262000def81604085016020870162000d8a565b601f01601f19169190910160400192915050565b60805160a05160c05160e05161010051610120516136f162000e99600039600081816103020152818161159f01528181611ea10152611eff01526000818161059a015261109d0152600081816102db01526114da01526000818161055e0152818161130d0152611a850152600061028c015260008181610245015281816114a401528181611dc5015261200101526136f16000f3fe608060405234801561001057600080fd5b50600436106101b85760003560e01c80638da5cb5b116100f9578063c4bffe2b11610097578063dfadfa3511610071578063dfadfa35146104be578063e0351e131461055c578063f2fde38b14610582578063fbf84dd71461059557600080fd5b8063c4bffe2b14610483578063c75eea9c14610498578063cf7401f3146104ab57600080fd5b8063a7cd63b7116100d3578063a7cd63b7146103ce578063af58d59f146103e3578063b0f479a114610452578063c0d786551461047057600080fd5b80638da5cb5b1461039557806396875445146103b35780639fdf13ff146103c657600080fd5b80635995f063116101665780636d108139116101405780636d1081391461033957806379ba5097146103675780638627fad61461036f5780638926f54f1461038257600080fd5b80635995f063146102c35780636155cda0146102d65780636b716b0d146102fd57600080fd5b806321df0da71161019757806321df0da7146102435780635246492f1461028a57806354c8a4f3146102b057600080fd5b806241d3c1146101bd57806301ffc9a7146101d2578063181f5a77146101fa575b600080fd5b6101d06101cb366004612a03565b6105bc565b005b6101e56101e0366004612a78565b610763565b60405190151581526020015b60405180910390f35b6102366040518060400160405280601381526020017f55534443546f6b656e506f6f6c20312e342e300000000000000000000000000081525081565b6040516101f19190612b28565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f1565b7f0000000000000000000000000000000000000000000000000000000000000000610265565b6101d06102be366004612b87565b6107bf565b6101d06102d1366004612bf3565b61083a565b6102657f000000000000000000000000000000000000000000000000000000000000000081565b6103247f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016101f1565b6040517fd6aca1be0000000000000000000000000000000000000000000000000000000081526020016101f1565b6101d0610dd2565b6101d061037d366004612df4565b610ecf565b6101e5610390366004612e8b565b6111a2565b60005473ffffffffffffffffffffffffffffffffffffffff16610265565b6102366103c1366004612eea565b6111b9565b610324600081565b6103d66115f8565b6040516101f19190612f8b565b6103f66103f1366004612e8b565b611609565b6040516101f1919081516fffffffffffffffffffffffffffffffff908116825260208084015163ffffffff1690830152604080840151151590830152606080840151821690830152608092830151169181019190915260a00190565b60045473ffffffffffffffffffffffffffffffffffffffff16610265565b6101d061047e366004612fe5565b6116db565b61048b6117af565b6040516101f19190613002565b6103f66104a6366004612e8b565b61186f565b6101d06104b93660046130e8565b611941565b6105326104cc366004612e8b565b60408051606080820183526000808352602080840182905292840181905267ffffffffffffffff949094168452600982529282902082519384018352805484526001015463ffffffff811691840191909152640100000000900460ff1615159082015290565b604080518251815260208084015163ffffffff1690820152918101511515908201526060016101f1565b7f00000000000000000000000000000000000000000000000000000000000000006101e5565b6101d0610590366004612fe5565b611954565b6102657f000000000000000000000000000000000000000000000000000000000000000081565b6105c4611968565b60005b818110156107255760008383838181106105e3576105e361312f565b9050608002018036038101906105f99190613170565b805190915015806106165750604081015167ffffffffffffffff16155b1561068557604080517fa087bd2900000000000000000000000000000000000000000000000000000000815282516004820152602083015163ffffffff1660248201529082015167ffffffffffffffff1660448201526060820151151560648201526084015b60405180910390fd5b60408051606080820183528351825260208085015163ffffffff9081168285019081529286015115158486019081529585015167ffffffffffffffff166000908152600990925293902091518255516001909101805493511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000909416919092161791909117905561071e816131fd565b90506105c7565b507f1889010d2535a0ab1643678d1da87fbbe8b87b2f585b47ddb72ec622aef9ee568282604051610757929190613235565b60405180910390a15050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fd6aca1be0000000000000000000000000000000000000000000000000000000014806107b957506107b9826119eb565b92915050565b6107c7611968565b61083484848080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808802828101820190935287825290935087925086918291850190849080828437600092019190915250611a8392505050565b50505050565b610842611968565b60005b81811015610dcd5760008383838181106108615761086161312f565b9050610100020180360381019061087891906132be565b905061088d8160400151826020015115611c49565b6108a08160600151826020015115611c49565b806020015115610cc15780516108c29060059067ffffffffffffffff16611d86565b6109075780516040517f1d5ad3c500000000000000000000000000000000000000000000000000000000815267ffffffffffffffff909116600482015260240161067c565b6040518060a001604052808260400151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff168152602001826040015160000151151581526020018260400151602001516fffffffffffffffffffffffffffffffff1681526020018260400151604001516fffffffffffffffffffffffffffffffff1681525060076000836000015167ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548160ff02191690831515021790555060608201518160010160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050506040518060a001604052808260600151602001516fffffffffffffffffffffffffffffffff1681526020014263ffffffff168152602001826060015160000151151581526020018260600151602001516fffffffffffffffffffffffffffffffff1681526020018260600151604001516fffffffffffffffffffffffffffffffff1681525060086000836000015167ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548160ff02191690831515021790555060608201518160010160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff16021790555060808201518160010160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055509050507f0f135cbb9afa12a8bf3bbd071c117bcca4ddeca6160ef7f33d012a81b9c0c471816000015182604001518360600151604051610cb493929190613318565b60405180910390a1610dbc565b8051610cd99060059067ffffffffffffffff16611d99565b610d1e5780516040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff909116600482015260240161067c565b805167ffffffffffffffff908116600090815260086020908152604080832080547fffffffffffffffffffffff0000000000000000000000000000000000000000009081168255600191820185905586518616855260078452828520805490911681550192909255835191519190921681527f5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916910160405180910390a15b50610dc6816131fd565b9050610845565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610e53576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161067c565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b81610ed9816111a2565b610f1b576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8216600482015260240161067c565b600480546040517f83826b2b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925233602483015273ffffffffffffffffffffffffffffffffffffffff16906383826b2b90604401602060405180830381865afa158015610f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbe919061339b565b610ff6576040517f728fe07b00000000000000000000000000000000000000000000000000000000815233600482015260240161067c565b6110008385611da5565b6000808380602001905181019061101791906133fd565b915091506000828060200190518101906110319190613461565b905060008280602001905181019061104991906134a2565b9050611059816000015183611de9565b805160208201516040517f57ecfd2800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016926357ecfd28926110d092600401613533565b6020604051808303816000875af11580156110ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611113919061339b565b611149576040517fbf969f2200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405188815273ffffffffffffffffffffffffffffffffffffffff8a169033907f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f09060200160405180910390a350505050505050505050565b60006107b9600567ffffffffffffffff8416611f9a565b6060836111c5816111a2565b611207576040517fa9902c7e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8216600482015260240161067c565b600480546040517fa8d87a3b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84169281019290925273ffffffffffffffffffffffffffffffffffffffff169063a8d87a3b90602401602060405180830381865afa158015611280573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112a49190613561565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461130a576040517f728fe07b00000000000000000000000000000000000000000000000000000000815233600482015260240161067c565b887f00000000000000000000000000000000000000000000000000000000000000008015611340575061133e600282611fb2565b155b1561138f576040517fd0d2597600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161067c565b67ffffffffffffffff861660009081526009602090815260409182902082516060810184528154815260019091015463ffffffff81169282019290925264010000000090910460ff16151591810182905290611423576040517fd201c48a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015260240161067c565b61142d8789611fe1565b600061143c6020828c8e61357e565b611445916135a8565b602083015183516040517ff856ddb6000000000000000000000000000000000000000000000000000000008152600481018d905263ffffffff90921660248301526044820183905273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116606484015260848301919091529192506000917f0000000000000000000000000000000000000000000000000000000000000000169063f856ddb69060a4016020604051808303816000875af1158015611523573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154791906135e4565b6040518b815290915033907f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df79060200160405180910390a260408051808201825267ffffffffffffffff9290921680835263ffffffff7f00000000000000000000000000000000000000000000000000000000000000008116602094850190815283519485019290925290511682820152805180830382018152606090920190529c9b505050505050505050505050565b60606116046002612025565b905090565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260086020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526107b990612032565b6116e3611968565b73ffffffffffffffffffffffffffffffffffffffff8116611730576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f16849101610757565b606060006117bd6005612025565b90506000815167ffffffffffffffff8111156117db576117db612c56565b604051908082528060200260200182016040528015611804578160200160208202803683370190505b50905060005b8251811015611868578281815181106118255761182561312f565b602002602001015182828151811061183f5761183f61312f565b67ffffffffffffffff90921660209283029190910190910152611861816131fd565b905061180a565b5092915050565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff8216600090815260076020908152604091829020825160a08101845281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000080830463ffffffff16958401959095527401000000000000000000000000000000000000000090910460ff1615159482019490945260019091015480841660608301529190910490911660808201526107b990612032565b611949611968565b610dcd8383836120e4565b61195c611968565b611965816121cb565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146119e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161067c565b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f317fa3340000000000000000000000000000000000000000000000000000000014806107b957507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a7000000000000000000000000000000000000000000000000000000001492915050565b7f0000000000000000000000000000000000000000000000000000000000000000611ada576040517f35f4a7b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015611b78576000838281518110611afa57611afa61312f565b60200260200101519050611b188160026122c090919063ffffffff16565b15611b675760405173ffffffffffffffffffffffffffffffffffffffff821681527f800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf75669060200160405180910390a15b50611b71816131fd565b9050611add565b5060005b8151811015610dcd576000828281518110611b9957611b9961312f565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611bdd5750611c39565b611be86002826122e2565b15611c375760405173ffffffffffffffffffffffffffffffffffffffff821681527f2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d89060200160405180910390a15b505b611c42816131fd565b9050611b7c565b815115611d145781602001516fffffffffffffffffffffffffffffffff1682604001516fffffffffffffffffffffffffffffffff16101580611c9f575060408201516fffffffffffffffffffffffffffffffff16155b15611cd857816040517f70505e5600000000000000000000000000000000000000000000000000000000815260040161067c9190613601565b8015611d10576040517f433fc33d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60408201516fffffffffffffffffffffffffffffffff16151580611d4d575060208201516fffffffffffffffffffffffffffffffff1615155b15611d1057816040517fd68af9cc00000000000000000000000000000000000000000000000000000000815260040161067c9190613601565b6000611d928383612300565b9392505050565b6000611d92838361234f565b67ffffffffffffffff82166000908152600860205260409020611d1090827f0000000000000000000000000000000000000000000000000000000000000000612442565b600482015163ffffffff811615611e34576040517f68d2f8d600000000000000000000000000000000000000000000000000000000815263ffffffff8216600482015260240161067c565b6008830151600c8401516014850151602085015163ffffffff808516911614611e9f5760208501516040517fe366a11700000000000000000000000000000000000000000000000000000000815263ffffffff9182166004820152908416602482015260440161067c565b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff168263ffffffff1614611f34576040517f77e4802600000000000000000000000000000000000000000000000000000000815263ffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301528316602482015260440161067c565b845167ffffffffffffffff828116911614611f925784516040517ff917ffea00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9182166004820152908216602482015260440161067c565b505050505050565b60008181526001830160205260408120541515611d92565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515611d92565b67ffffffffffffffff82166000908152600760205260409020611d1090827f0000000000000000000000000000000000000000000000000000000000000000612442565b60606000611d92836127c5565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091526120c082606001516fffffffffffffffffffffffffffffffff1683600001516fffffffffffffffffffffffffffffffff16846020015163ffffffff16426120a4919061363d565b85608001516fffffffffffffffffffffffffffffffff16612821565b6fffffffffffffffffffffffffffffffff1682525063ffffffff4216602082015290565b6120ed836111a2565b61212f576040517f1e670e4b00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8416600482015260240161067c565b61213a826000611c49565b67ffffffffffffffff8316600090815260076020526040902061215d908361284b565b612168816000611c49565b67ffffffffffffffff8316600090815260086020526040902061218b908261284b565b7f0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b8383836040516121be93929190613318565b60405180910390a1505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361224a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161067c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000611d928373ffffffffffffffffffffffffffffffffffffffff841661234f565b6000611d928373ffffffffffffffffffffffffffffffffffffffff84165b6000818152600183016020526040812054612347575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107b9565b5060006107b9565b6000818152600183016020526040812054801561243857600061237360018361363d565b85549091506000906123879060019061363d565b90508181146123ec5760008660000182815481106123a7576123a761312f565b90600052602060002001549050808760000184815481106123ca576123ca61312f565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806123fd576123fd613650565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107b9565b60009150506107b9565b825474010000000000000000000000000000000000000000900460ff161580612469575081155b1561247357505050565b825460018401546fffffffffffffffffffffffffffffffff808316929116906000906124b990700100000000000000000000000000000000900463ffffffff164261363d565b9050801561257957818311156124fb576040517f9725942a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018601546125359083908590849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16612821565b86547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000004263ffffffff160217875592505b848210156126305773ffffffffffffffffffffffffffffffffffffffff84166125d8576040517ff94ebcd1000000000000000000000000000000000000000000000000000000008152600481018390526024810186905260440161067c565b6040517f1a76572a000000000000000000000000000000000000000000000000000000008152600481018390526024810186905273ffffffffffffffffffffffffffffffffffffffff8516604482015260640161067c565b848310156127435760018681015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16906000908290612674908261363d565b61267e878a61363d565b612688919061367f565b6126929190613692565b905073ffffffffffffffffffffffffffffffffffffffff86166126eb576040517f15279c08000000000000000000000000000000000000000000000000000000008152600481018290526024810186905260440161067c565b6040517fd0c8d23a000000000000000000000000000000000000000000000000000000008152600481018290526024810186905273ffffffffffffffffffffffffffffffffffffffff8716604482015260640161067c565b61274d858461363d565b86547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff82161787556040518681529093507f1871cdf8010e63f2eb8384381a68dfa7416dc571a5517e66e88b2d2d0c0a690a9060200160405180910390a1505050505050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561281557602002820191906000526020600020905b815481526020019060010190808311612801575b50505050509050919050565b60006128408561283184866136cd565b61283b908761367f565b6129ed565b90505b949350505050565b815460009061287490700100000000000000000000000000000000900463ffffffff164261363d565b9050801561291657600183015483546128bc916fffffffffffffffffffffffffffffffff80821692811691859170010000000000000000000000000000000090910416612821565b83546fffffffffffffffffffffffffffffffff919091167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116177001000000000000000000000000000000004263ffffffff16021783555b6020820151835461293c916fffffffffffffffffffffffffffffffff90811691166129ed565b83548351151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffff000000000000000000000000000000009091166fffffffffffffffffffffffffffffffff92831617178455602083015160408085015183167001000000000000000000000000000000000291909216176001850155517f9ea3374b67bf275e6bb9c8ae68f9cae023e1c528b4b27e092f0bb209d3531c19906121be908490613601565b60008183106129fc5781611d92565b5090919050565b60008060208385031215612a1657600080fd5b823567ffffffffffffffff80821115612a2e57600080fd5b818501915085601f830112612a4257600080fd5b813581811115612a5157600080fd5b8660208260071b8501011115612a6657600080fd5b60209290920196919550909350505050565b600060208284031215612a8a57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611d9257600080fd5b60005b83811015612ad5578181015183820152602001612abd565b50506000910152565b60008151808452612af6816020860160208601612aba565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611d926020830184612ade565b60008083601f840112612b4d57600080fd5b50813567ffffffffffffffff811115612b6557600080fd5b6020830191508360208260051b8501011115612b8057600080fd5b9250929050565b60008060008060408587031215612b9d57600080fd5b843567ffffffffffffffff80821115612bb557600080fd5b612bc188838901612b3b565b90965094506020870135915080821115612bda57600080fd5b50612be787828801612b3b565b95989497509550505050565b60008060208385031215612c0657600080fd5b823567ffffffffffffffff80821115612c1e57600080fd5b818501915085601f830112612c3257600080fd5b813581811115612c4157600080fd5b8660208260081b8501011115612a6657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715612ca857612ca8612c56565b60405290565b6040805190810167ffffffffffffffff81118282101715612ca857612ca8612c56565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612d1857612d18612c56565b604052919050565b600067ffffffffffffffff821115612d3a57612d3a612c56565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112612d7757600080fd5b8135612d8a612d8582612d20565b612cd1565b818152846020838601011115612d9f57600080fd5b816020850160208301376000918101602001919091529392505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461196557600080fd5b67ffffffffffffffff8116811461196557600080fd5b600080600080600060a08688031215612e0c57600080fd5b853567ffffffffffffffff80821115612e2457600080fd5b612e3089838a01612d66565b965060208801359150612e4282612dbc565b90945060408701359350606087013590612e5b82612dde565b90925060808701359080821115612e7157600080fd5b50612e7e88828901612d66565b9150509295509295909350565b600060208284031215612e9d57600080fd5b8135611d9281612dde565b60008083601f840112612eba57600080fd5b50813567ffffffffffffffff811115612ed257600080fd5b602083019150836020828501011115612b8057600080fd5b600080600080600080600060a0888a031215612f0557600080fd5b8735612f1081612dbc565b9650602088013567ffffffffffffffff80821115612f2d57600080fd5b612f398b838c01612ea8565b909850965060408a0135955060608a01359150612f5582612dde565b90935060808901359080821115612f6b57600080fd5b50612f788a828b01612ea8565b989b979a50959850939692959293505050565b6020808252825182820181905260009190848201906040850190845b81811015612fd957835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612fa7565b50909695505050505050565b600060208284031215612ff757600080fd5b8135611d9281612dbc565b6020808252825182820181905260009190848201906040850190845b81811015612fd957835167ffffffffffffffff168352928401929184019160010161301e565b801515811461196557600080fd5b80356fffffffffffffffffffffffffffffffff8116811461307257600080fd5b919050565b60006060828403121561308957600080fd5b6040516060810181811067ffffffffffffffff821117156130ac576130ac612c56565b60405290508082356130bd81613044565b81526130cb60208401613052565b60208201526130dc60408401613052565b60408201525092915050565b600080600060e084860312156130fd57600080fd5b833561310881612dde565b92506131178560208601613077565b91506131268560808601613077565b90509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b63ffffffff8116811461196557600080fd5b60006080828403121561318257600080fd5b61318a612c85565b82358152602083013561319c8161315e565b602082015260408301356131af81612dde565b604082015260608301356131c281613044565b60608201529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361322e5761322e6131ce565b5060010190565b6020808252818101839052600090604080840186845b878110156132b15781358352848201356132648161315e565b63ffffffff16838601528184013561327b81612dde565b67ffffffffffffffff168385015260608281013561329881613044565b151590840152608092830192919091019060010161324b565b5090979650505050505050565b600061010082840312156132d157600080fd5b6132d9612c85565b82356132e481612dde565b815260208301356132f481613044565b60208201526133068460408501613077565b60408201526131c28460a08501613077565b67ffffffffffffffff8416815260e0810161336460208301858051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b82511515608083015260208301516fffffffffffffffffffffffffffffffff90811660a084015260408401511660c0830152612843565b6000602082840312156133ad57600080fd5b8151611d9281613044565b600082601f8301126133c957600080fd5b81516133d7612d8582612d20565b8181528460208386010111156133ec57600080fd5b612843826020830160208701612aba565b6000806040838503121561341057600080fd5b825167ffffffffffffffff8082111561342857600080fd5b613434868387016133b8565b9350602085015191508082111561344a57600080fd5b50613457858286016133b8565b9150509250929050565b60006040828403121561347357600080fd5b61347b612cae565b825161348681612dde565b815260208301516134968161315e565b60208201529392505050565b6000602082840312156134b457600080fd5b815167ffffffffffffffff808211156134cc57600080fd5b90830190604082860312156134e057600080fd5b6134e8612cae565b8251828111156134f757600080fd5b613503878286016133b8565b82525060208301518281111561351857600080fd5b613524878286016133b8565b60208301525095945050505050565b6040815260006135466040830185612ade565b82810360208401526135588185612ade565b95945050505050565b60006020828403121561357357600080fd5b8151611d9281612dbc565b6000808585111561358e57600080fd5b8386111561359b57600080fd5b5050820193919092039150565b803560208310156107b9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b6000602082840312156135f657600080fd5b8151611d9281612dde565b606081016107b982848051151582526020808201516fffffffffffffffffffffffffffffffff9081169184019190915260409182015116910152565b818103818111156107b9576107b96131ce565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b808201808211156107b9576107b96131ce565b6000826136c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b80820281158282048414176107b9576107b96131ce56fea164736f6c6343000813000a",
+}
+
+var USDCTokenPoolABI = USDCTokenPoolMetaData.ABI
+
+var USDCTokenPoolBin = USDCTokenPoolMetaData.Bin
+
+func DeployUSDCTokenPool(auth *bind.TransactOpts, backend bind.ContractBackend, tokenMessenger common.Address, token common.Address, allowlist []common.Address, armProxy common.Address, router common.Address) (common.Address, *types.Transaction, *USDCTokenPool, error) {
+ parsed, err := USDCTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(USDCTokenPoolBin), backend, tokenMessenger, token, allowlist, armProxy, router)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &USDCTokenPool{address: address, abi: *parsed, USDCTokenPoolCaller: USDCTokenPoolCaller{contract: contract}, USDCTokenPoolTransactor: USDCTokenPoolTransactor{contract: contract}, USDCTokenPoolFilterer: USDCTokenPoolFilterer{contract: contract}}, nil
+}
+
+type USDCTokenPool struct {
+ address common.Address
+ abi abi.ABI
+ USDCTokenPoolCaller
+ USDCTokenPoolTransactor
+ USDCTokenPoolFilterer
+}
+
+type USDCTokenPoolCaller struct {
+ contract *bind.BoundContract
+}
+
+type USDCTokenPoolTransactor struct {
+ contract *bind.BoundContract
+}
+
+type USDCTokenPoolFilterer struct {
+ contract *bind.BoundContract
+}
+
+type USDCTokenPoolSession struct {
+ Contract *USDCTokenPool
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type USDCTokenPoolCallerSession struct {
+ Contract *USDCTokenPoolCaller
+ CallOpts bind.CallOpts
+}
+
+type USDCTokenPoolTransactorSession struct {
+ Contract *USDCTokenPoolTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type USDCTokenPoolRaw struct {
+ Contract *USDCTokenPool
+}
+
+type USDCTokenPoolCallerRaw struct {
+ Contract *USDCTokenPoolCaller
+}
+
+type USDCTokenPoolTransactorRaw struct {
+ Contract *USDCTokenPoolTransactor
+}
+
+func NewUSDCTokenPool(address common.Address, backend bind.ContractBackend) (*USDCTokenPool, error) {
+ abi, err := abi.JSON(strings.NewReader(USDCTokenPoolABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindUSDCTokenPool(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPool{address: address, abi: abi, USDCTokenPoolCaller: USDCTokenPoolCaller{contract: contract}, USDCTokenPoolTransactor: USDCTokenPoolTransactor{contract: contract}, USDCTokenPoolFilterer: USDCTokenPoolFilterer{contract: contract}}, nil
+}
+
+func NewUSDCTokenPoolCaller(address common.Address, caller bind.ContractCaller) (*USDCTokenPoolCaller, error) {
+ contract, err := bindUSDCTokenPool(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolCaller{contract: contract}, nil
+}
+
+func NewUSDCTokenPoolTransactor(address common.Address, transactor bind.ContractTransactor) (*USDCTokenPoolTransactor, error) {
+ contract, err := bindUSDCTokenPool(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolTransactor{contract: contract}, nil
+}
+
+func NewUSDCTokenPoolFilterer(address common.Address, filterer bind.ContractFilterer) (*USDCTokenPoolFilterer, error) {
+ contract, err := bindUSDCTokenPool(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolFilterer{contract: contract}, nil
+}
+
+func bindUSDCTokenPool(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := USDCTokenPoolMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _USDCTokenPool.Contract.USDCTokenPoolCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_USDCTokenPool *USDCTokenPoolRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.USDCTokenPoolTransactor.contract.Transfer(opts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.USDCTokenPoolTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _USDCTokenPool.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.contract.Transfer(opts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) SUPPORTEDUSDCVERSION(opts *bind.CallOpts) (uint32, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "SUPPORTED_USDC_VERSION")
+
+ if err != nil {
+ return *new(uint32), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SUPPORTEDUSDCVERSION() (uint32, error) {
+ return _USDCTokenPool.Contract.SUPPORTEDUSDCVERSION(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) SUPPORTEDUSDCVERSION() (uint32, error) {
+ return _USDCTokenPool.Contract.SUPPORTEDUSDCVERSION(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetAllowList(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getAllowList")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetAllowList() ([]common.Address, error) {
+ return _USDCTokenPool.Contract.GetAllowList(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetAllowList() ([]common.Address, error) {
+ return _USDCTokenPool.Contract.GetAllowList(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetAllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getAllowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetAllowListEnabled() (bool, error) {
+ return _USDCTokenPool.Contract.GetAllowListEnabled(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetAllowListEnabled() (bool, error) {
+ return _USDCTokenPool.Contract.GetAllowListEnabled(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetArmProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getArmProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetArmProxy() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetArmProxy(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetArmProxy() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetArmProxy(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getCurrentInboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _USDCTokenPool.Contract.GetCurrentInboundRateLimiterState(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetCurrentInboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _USDCTokenPool.Contract.GetCurrentInboundRateLimiterState(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getCurrentOutboundRateLimiterState", remoteChainSelector)
+
+ if err != nil {
+ return *new(RateLimiterTokenBucket), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(RateLimiterTokenBucket)).(*RateLimiterTokenBucket)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _USDCTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetCurrentOutboundRateLimiterState(remoteChainSelector uint64) (RateLimiterTokenBucket, error) {
+ return _USDCTokenPool.Contract.GetCurrentOutboundRateLimiterState(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetDomain(opts *bind.CallOpts, chainSelector uint64) (USDCTokenPoolDomain, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getDomain", chainSelector)
+
+ if err != nil {
+ return *new(USDCTokenPoolDomain), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(USDCTokenPoolDomain)).(*USDCTokenPoolDomain)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetDomain(chainSelector uint64) (USDCTokenPoolDomain, error) {
+ return _USDCTokenPool.Contract.GetDomain(&_USDCTokenPool.CallOpts, chainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetDomain(chainSelector uint64) (USDCTokenPoolDomain, error) {
+ return _USDCTokenPool.Contract.GetDomain(&_USDCTokenPool.CallOpts, chainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getRouter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetRouter() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetRouter(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetRouter() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetRouter(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetSupportedChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getSupportedChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetSupportedChains() ([]uint64, error) {
+ return _USDCTokenPool.Contract.GetSupportedChains(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetSupportedChains() ([]uint64, error) {
+ return _USDCTokenPool.Contract.GetSupportedChains(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetToken() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetToken(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetToken() (common.Address, error) {
+ return _USDCTokenPool.Contract.GetToken(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) GetUSDCInterfaceId(opts *bind.CallOpts) ([4]byte, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "getUSDCInterfaceId")
+
+ if err != nil {
+ return *new([4]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([4]byte)).(*[4]byte)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) GetUSDCInterfaceId() ([4]byte, error) {
+ return _USDCTokenPool.Contract.GetUSDCInterfaceId(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) GetUSDCInterfaceId() ([4]byte, error) {
+ return _USDCTokenPool.Contract.GetUSDCInterfaceId(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) ILocalDomainIdentifier(opts *bind.CallOpts) (uint32, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "i_localDomainIdentifier")
+
+ if err != nil {
+ return *new(uint32), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ILocalDomainIdentifier() (uint32, error) {
+ return _USDCTokenPool.Contract.ILocalDomainIdentifier(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) ILocalDomainIdentifier() (uint32, error) {
+ return _USDCTokenPool.Contract.ILocalDomainIdentifier(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) IMessageTransmitter(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "i_messageTransmitter")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) IMessageTransmitter() (common.Address, error) {
+ return _USDCTokenPool.Contract.IMessageTransmitter(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) IMessageTransmitter() (common.Address, error) {
+ return _USDCTokenPool.Contract.IMessageTransmitter(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) ITokenMessenger(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "i_tokenMessenger")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ITokenMessenger() (common.Address, error) {
+ return _USDCTokenPool.Contract.ITokenMessenger(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) ITokenMessenger() (common.Address, error) {
+ return _USDCTokenPool.Contract.ITokenMessenger(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "isSupportedChain", remoteChainSelector)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _USDCTokenPool.Contract.IsSupportedChain(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) IsSupportedChain(remoteChainSelector uint64) (bool, error) {
+ return _USDCTokenPool.Contract.IsSupportedChain(&_USDCTokenPool.CallOpts, remoteChainSelector)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) Owner() (common.Address, error) {
+ return _USDCTokenPool.Contract.Owner(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) Owner() (common.Address, error) {
+ return _USDCTokenPool.Contract.Owner(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _USDCTokenPool.Contract.SupportsInterface(&_USDCTokenPool.CallOpts, interfaceId)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _USDCTokenPool.Contract.SupportsInterface(&_USDCTokenPool.CallOpts, interfaceId)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _USDCTokenPool.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) TypeAndVersion() (string, error) {
+ return _USDCTokenPool.Contract.TypeAndVersion(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolCallerSession) TypeAndVersion() (string, error) {
+ return _USDCTokenPool.Contract.TypeAndVersion(&_USDCTokenPool.CallOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) AcceptOwnership() (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.AcceptOwnership(&_USDCTokenPool.TransactOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.AcceptOwnership(&_USDCTokenPool.TransactOpts)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "applyAllowListUpdates", removes, adds)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ApplyAllowListUpdates(&_USDCTokenPool.TransactOpts, removes, adds)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) ApplyAllowListUpdates(removes []common.Address, adds []common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ApplyAllowListUpdates(&_USDCTokenPool.TransactOpts, removes, adds)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "applyChainUpdates", chains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ApplyChainUpdates(&_USDCTokenPool.TransactOpts, chains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) ApplyChainUpdates(chains []TokenPoolChainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ApplyChainUpdates(&_USDCTokenPool.TransactOpts, chains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, destinationReceiver []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "lockOrBurn", originalSender, destinationReceiver, amount, remoteChainSelector, arg4)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) LockOrBurn(originalSender common.Address, destinationReceiver []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.LockOrBurn(&_USDCTokenPool.TransactOpts, originalSender, destinationReceiver, amount, remoteChainSelector, arg4)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) LockOrBurn(originalSender common.Address, destinationReceiver []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.LockOrBurn(&_USDCTokenPool.TransactOpts, originalSender, destinationReceiver, amount, remoteChainSelector, arg4)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, extraData []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "releaseOrMint", arg0, receiver, amount, remoteChainSelector, extraData)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, extraData []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ReleaseOrMint(&_USDCTokenPool.TransactOpts, arg0, receiver, amount, remoteChainSelector, extraData)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) ReleaseOrMint(arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, extraData []byte) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.ReleaseOrMint(&_USDCTokenPool.TransactOpts, arg0, receiver, amount, remoteChainSelector, extraData)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "setChainRateLimiterConfig", remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetChainRateLimiterConfig(&_USDCTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) SetChainRateLimiterConfig(remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetChainRateLimiterConfig(&_USDCTokenPool.TransactOpts, remoteChainSelector, outboundConfig, inboundConfig)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) SetDomains(opts *bind.TransactOpts, domains []USDCTokenPoolDomainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "setDomains", domains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SetDomains(domains []USDCTokenPoolDomainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetDomains(&_USDCTokenPool.TransactOpts, domains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) SetDomains(domains []USDCTokenPoolDomainUpdate) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetDomains(&_USDCTokenPool.TransactOpts, domains)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "setRouter", newRouter)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetRouter(&_USDCTokenPool.TransactOpts, newRouter)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) SetRouter(newRouter common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.SetRouter(&_USDCTokenPool.TransactOpts, newRouter)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_USDCTokenPool *USDCTokenPoolSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.TransferOwnership(&_USDCTokenPool.TransactOpts, to)
+}
+
+func (_USDCTokenPool *USDCTokenPoolTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _USDCTokenPool.Contract.TransferOwnership(&_USDCTokenPool.TransactOpts, to)
+}
+
+type USDCTokenPoolAllowListAddIterator struct {
+ Event *USDCTokenPoolAllowListAdd
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolAllowListAddIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolAllowListAdd)
+ 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(USDCTokenPoolAllowListAdd)
+ 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 *USDCTokenPoolAllowListAddIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolAllowListAddIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolAllowListAdd struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterAllowListAdd(opts *bind.FilterOpts) (*USDCTokenPoolAllowListAddIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolAllowListAddIterator{contract: _USDCTokenPool.contract, event: "AllowListAdd", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolAllowListAdd) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "AllowListAdd")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolAllowListAdd)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "AllowListAdd", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseAllowListAdd(log types.Log) (*USDCTokenPoolAllowListAdd, error) {
+ event := new(USDCTokenPoolAllowListAdd)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "AllowListAdd", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolAllowListRemoveIterator struct {
+ Event *USDCTokenPoolAllowListRemove
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolAllowListRemoveIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolAllowListRemove)
+ 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(USDCTokenPoolAllowListRemove)
+ 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 *USDCTokenPoolAllowListRemoveIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolAllowListRemoveIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolAllowListRemove struct {
+ Sender common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterAllowListRemove(opts *bind.FilterOpts) (*USDCTokenPoolAllowListRemoveIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolAllowListRemoveIterator{contract: _USDCTokenPool.contract, event: "AllowListRemove", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolAllowListRemove) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "AllowListRemove")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolAllowListRemove)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "AllowListRemove", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseAllowListRemove(log types.Log) (*USDCTokenPoolAllowListRemove, error) {
+ event := new(USDCTokenPoolAllowListRemove)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "AllowListRemove", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolBurnedIterator struct {
+ Event *USDCTokenPoolBurned
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolBurnedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolBurned)
+ 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(USDCTokenPoolBurned)
+ 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 *USDCTokenPoolBurnedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolBurnedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolBurned struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*USDCTokenPoolBurnedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolBurnedIterator{contract: _USDCTokenPool.contract, event: "Burned", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchBurned(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolBurned, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "Burned", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolBurned)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Burned", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseBurned(log types.Log) (*USDCTokenPoolBurned, error) {
+ event := new(USDCTokenPoolBurned)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Burned", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolChainAddedIterator struct {
+ Event *USDCTokenPoolChainAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolChainAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolChainAdded)
+ 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(USDCTokenPoolChainAdded)
+ 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 *USDCTokenPoolChainAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolChainAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolChainAdded struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterChainAdded(opts *bind.FilterOpts) (*USDCTokenPoolChainAddedIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolChainAddedIterator{contract: _USDCTokenPool.contract, event: "ChainAdded", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchChainAdded(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainAdded) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ChainAdded")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolChainAdded)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainAdded", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseChainAdded(log types.Log) (*USDCTokenPoolChainAdded, error) {
+ event := new(USDCTokenPoolChainAdded)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolChainConfiguredIterator struct {
+ Event *USDCTokenPoolChainConfigured
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolChainConfiguredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolChainConfigured)
+ 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(USDCTokenPoolChainConfigured)
+ 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 *USDCTokenPoolChainConfiguredIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolChainConfiguredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolChainConfigured struct {
+ RemoteChainSelector uint64
+ OutboundRateLimiterConfig RateLimiterConfig
+ InboundRateLimiterConfig RateLimiterConfig
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterChainConfigured(opts *bind.FilterOpts) (*USDCTokenPoolChainConfiguredIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolChainConfiguredIterator{contract: _USDCTokenPool.contract, event: "ChainConfigured", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainConfigured) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ChainConfigured")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolChainConfigured)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainConfigured", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseChainConfigured(log types.Log) (*USDCTokenPoolChainConfigured, error) {
+ event := new(USDCTokenPoolChainConfigured)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainConfigured", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolChainRemovedIterator struct {
+ Event *USDCTokenPoolChainRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolChainRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolChainRemoved)
+ 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(USDCTokenPoolChainRemoved)
+ 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 *USDCTokenPoolChainRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolChainRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolChainRemoved struct {
+ RemoteChainSelector uint64
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterChainRemoved(opts *bind.FilterOpts) (*USDCTokenPoolChainRemovedIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolChainRemovedIterator{contract: _USDCTokenPool.contract, event: "ChainRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ChainRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolChainRemoved)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainRemoved", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseChainRemoved(log types.Log) (*USDCTokenPoolChainRemoved, error) {
+ event := new(USDCTokenPoolChainRemoved)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ChainRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolConfigSetIterator struct {
+ Event *USDCTokenPoolConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolConfigSet)
+ 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(USDCTokenPoolConfigSet)
+ 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 *USDCTokenPoolConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolConfigSet struct {
+ TokenMessenger common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterConfigSet(opts *bind.FilterOpts) (*USDCTokenPoolConfigSetIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolConfigSetIterator{contract: _USDCTokenPool.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolConfigSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ConfigSet", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseConfigSet(log types.Log) (*USDCTokenPoolConfigSet, error) {
+ event := new(USDCTokenPoolConfigSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolDomainsSetIterator struct {
+ Event *USDCTokenPoolDomainsSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolDomainsSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolDomainsSet)
+ 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(USDCTokenPoolDomainsSet)
+ 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 *USDCTokenPoolDomainsSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolDomainsSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolDomainsSet struct {
+ Arg0 []USDCTokenPoolDomainUpdate
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterDomainsSet(opts *bind.FilterOpts) (*USDCTokenPoolDomainsSetIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "DomainsSet")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolDomainsSetIterator{contract: _USDCTokenPool.contract, event: "DomainsSet", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchDomainsSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolDomainsSet) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "DomainsSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolDomainsSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "DomainsSet", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseDomainsSet(log types.Log) (*USDCTokenPoolDomainsSet, error) {
+ event := new(USDCTokenPoolDomainsSet)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "DomainsSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolLockedIterator struct {
+ Event *USDCTokenPoolLocked
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolLockedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolLocked)
+ 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(USDCTokenPoolLocked)
+ 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 *USDCTokenPoolLockedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolLockedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolLocked struct {
+ Sender common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*USDCTokenPoolLockedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolLockedIterator{contract: _USDCTokenPool.contract, event: "Locked", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchLocked(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolLocked, sender []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "Locked", senderRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolLocked)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Locked", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseLocked(log types.Log) (*USDCTokenPoolLocked, error) {
+ event := new(USDCTokenPoolLocked)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Locked", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolMintedIterator struct {
+ Event *USDCTokenPoolMinted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolMintedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolMinted)
+ 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(USDCTokenPoolMinted)
+ 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 *USDCTokenPoolMintedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolMintedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolMinted struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*USDCTokenPoolMintedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolMintedIterator{contract: _USDCTokenPool.contract, event: "Minted", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchMinted(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "Minted", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolMinted)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Minted", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseMinted(log types.Log) (*USDCTokenPoolMinted, error) {
+ event := new(USDCTokenPoolMinted)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Minted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolOwnershipTransferRequestedIterator struct {
+ Event *USDCTokenPoolOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolOwnershipTransferRequested)
+ 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(USDCTokenPoolOwnershipTransferRequested)
+ 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 *USDCTokenPoolOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*USDCTokenPoolOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolOwnershipTransferRequestedIterator{contract: _USDCTokenPool.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolOwnershipTransferRequested)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseOwnershipTransferRequested(log types.Log) (*USDCTokenPoolOwnershipTransferRequested, error) {
+ event := new(USDCTokenPoolOwnershipTransferRequested)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolOwnershipTransferredIterator struct {
+ Event *USDCTokenPoolOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolOwnershipTransferred)
+ 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(USDCTokenPoolOwnershipTransferred)
+ 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 *USDCTokenPoolOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*USDCTokenPoolOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolOwnershipTransferredIterator{contract: _USDCTokenPool.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolOwnershipTransferred)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "OwnershipTransferred", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseOwnershipTransferred(log types.Log) (*USDCTokenPoolOwnershipTransferred, error) {
+ event := new(USDCTokenPoolOwnershipTransferred)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolReleasedIterator struct {
+ Event *USDCTokenPoolReleased
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolReleasedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolReleased)
+ 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(USDCTokenPoolReleased)
+ 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 *USDCTokenPoolReleasedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolReleasedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolReleased struct {
+ Sender common.Address
+ Recipient common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*USDCTokenPoolReleasedIterator, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolReleasedIterator{contract: _USDCTokenPool.contract, event: "Released", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchReleased(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error) {
+
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "Released", senderRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolReleased)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Released", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseReleased(log types.Log) (*USDCTokenPoolReleased, error) {
+ event := new(USDCTokenPoolReleased)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "Released", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type USDCTokenPoolRouterUpdatedIterator struct {
+ Event *USDCTokenPoolRouterUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *USDCTokenPoolRouterUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(USDCTokenPoolRouterUpdated)
+ 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(USDCTokenPoolRouterUpdated)
+ 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 *USDCTokenPoolRouterUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *USDCTokenPoolRouterUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type USDCTokenPoolRouterUpdated struct {
+ OldRouter common.Address
+ NewRouter common.Address
+ Raw types.Log
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) FilterRouterUpdated(opts *bind.FilterOpts) (*USDCTokenPoolRouterUpdatedIterator, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.FilterLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &USDCTokenPoolRouterUpdatedIterator{contract: _USDCTokenPool.contract, event: "RouterUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_USDCTokenPool *USDCTokenPoolFilterer) WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolRouterUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _USDCTokenPool.contract.WatchLogs(opts, "RouterUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(USDCTokenPoolRouterUpdated)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "RouterUpdated", 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 (_USDCTokenPool *USDCTokenPoolFilterer) ParseRouterUpdated(log types.Log) (*USDCTokenPoolRouterUpdated, error) {
+ event := new(USDCTokenPoolRouterUpdated)
+ if err := _USDCTokenPool.contract.UnpackLog(event, "RouterUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_USDCTokenPool *USDCTokenPool) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _USDCTokenPool.abi.Events["AllowListAdd"].ID:
+ return _USDCTokenPool.ParseAllowListAdd(log)
+ case _USDCTokenPool.abi.Events["AllowListRemove"].ID:
+ return _USDCTokenPool.ParseAllowListRemove(log)
+ case _USDCTokenPool.abi.Events["Burned"].ID:
+ return _USDCTokenPool.ParseBurned(log)
+ case _USDCTokenPool.abi.Events["ChainAdded"].ID:
+ return _USDCTokenPool.ParseChainAdded(log)
+ case _USDCTokenPool.abi.Events["ChainConfigured"].ID:
+ return _USDCTokenPool.ParseChainConfigured(log)
+ case _USDCTokenPool.abi.Events["ChainRemoved"].ID:
+ return _USDCTokenPool.ParseChainRemoved(log)
+ case _USDCTokenPool.abi.Events["ConfigSet"].ID:
+ return _USDCTokenPool.ParseConfigSet(log)
+ case _USDCTokenPool.abi.Events["DomainsSet"].ID:
+ return _USDCTokenPool.ParseDomainsSet(log)
+ case _USDCTokenPool.abi.Events["Locked"].ID:
+ return _USDCTokenPool.ParseLocked(log)
+ case _USDCTokenPool.abi.Events["Minted"].ID:
+ return _USDCTokenPool.ParseMinted(log)
+ case _USDCTokenPool.abi.Events["OwnershipTransferRequested"].ID:
+ return _USDCTokenPool.ParseOwnershipTransferRequested(log)
+ case _USDCTokenPool.abi.Events["OwnershipTransferred"].ID:
+ return _USDCTokenPool.ParseOwnershipTransferred(log)
+ case _USDCTokenPool.abi.Events["Released"].ID:
+ return _USDCTokenPool.ParseReleased(log)
+ case _USDCTokenPool.abi.Events["RouterUpdated"].ID:
+ return _USDCTokenPool.ParseRouterUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (USDCTokenPoolAllowListAdd) Topic() common.Hash {
+ return common.HexToHash("0x2640d4d76caf8bf478aabfa982fa4e1c4eb71a37f93cd15e80dbc657911546d8")
+}
+
+func (USDCTokenPoolAllowListRemove) Topic() common.Hash {
+ return common.HexToHash("0x800671136ab6cfee9fbe5ed1fb7ca417811aca3cf864800d127b927adedf7566")
+}
+
+func (USDCTokenPoolBurned) Topic() common.Hash {
+ return common.HexToHash("0x696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df7")
+}
+
+func (USDCTokenPoolChainAdded) Topic() common.Hash {
+ return common.HexToHash("0x0f135cbb9afa12a8bf3bbd071c117bcca4ddeca6160ef7f33d012a81b9c0c471")
+}
+
+func (USDCTokenPoolChainConfigured) Topic() common.Hash {
+ return common.HexToHash("0x0350d63aa5f270e01729d00d627eeb8f3429772b1818c016c66a588a864f912b")
+}
+
+func (USDCTokenPoolChainRemoved) Topic() common.Hash {
+ return common.HexToHash("0x5204aec90a3c794d8e90fded8b46ae9c7c552803e7e832e0c1d358396d859916")
+}
+
+func (USDCTokenPoolConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x2e902d38f15b233cbb63711add0fca4545334d3a169d60c0a616494d7eea9544")
+}
+
+func (USDCTokenPoolDomainsSet) Topic() common.Hash {
+ return common.HexToHash("0x1889010d2535a0ab1643678d1da87fbbe8b87b2f585b47ddb72ec622aef9ee56")
+}
+
+func (USDCTokenPoolLocked) Topic() common.Hash {
+ return common.HexToHash("0x9f1ec8c880f76798e7b793325d625e9b60e4082a553c98f42b6cda368dd60008")
+}
+
+func (USDCTokenPoolMinted) Topic() common.Hash {
+ return common.HexToHash("0x9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f0")
+}
+
+func (USDCTokenPoolOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (USDCTokenPoolOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (USDCTokenPoolReleased) Topic() common.Hash {
+ return common.HexToHash("0x2d87480f50083e2b2759522a8fdda59802650a8055e609a7772cf70c07748f52")
+}
+
+func (USDCTokenPoolRouterUpdated) Topic() common.Hash {
+ return common.HexToHash("0x02dc5c233404867c793b749c6d644beb2277536d18a7e7974d3f238e4c6f1684")
+}
+
+func (_USDCTokenPool *USDCTokenPool) Address() common.Address {
+ return _USDCTokenPool.address
+}
+
+type USDCTokenPoolInterface interface {
+ SUPPORTEDUSDCVERSION(opts *bind.CallOpts) (uint32, error)
+
+ GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
+
+ GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ GetArmProxy(opts *bind.CallOpts) (common.Address, error)
+
+ GetCurrentInboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, remoteChainSelector uint64) (RateLimiterTokenBucket, error)
+
+ GetDomain(opts *bind.CallOpts, chainSelector uint64) (USDCTokenPoolDomain, error)
+
+ GetRouter(opts *bind.CallOpts) (common.Address, error)
+
+ GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetToken(opts *bind.CallOpts) (common.Address, error)
+
+ GetUSDCInterfaceId(opts *bind.CallOpts) ([4]byte, error)
+
+ ILocalDomainIdentifier(opts *bind.CallOpts) (uint32, error)
+
+ IMessageTransmitter(opts *bind.CallOpts) (common.Address, error)
+
+ ITokenMessenger(opts *bind.CallOpts) (common.Address, error)
+
+ IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ ApplyAllowListUpdates(opts *bind.TransactOpts, removes []common.Address, adds []common.Address) (*types.Transaction, error)
+
+ ApplyChainUpdates(opts *bind.TransactOpts, chains []TokenPoolChainUpdate) (*types.Transaction, error)
+
+ LockOrBurn(opts *bind.TransactOpts, originalSender common.Address, destinationReceiver []byte, amount *big.Int, remoteChainSelector uint64, arg4 []byte) (*types.Transaction, error)
+
+ ReleaseOrMint(opts *bind.TransactOpts, arg0 []byte, receiver common.Address, amount *big.Int, remoteChainSelector uint64, extraData []byte) (*types.Transaction, error)
+
+ SetChainRateLimiterConfig(opts *bind.TransactOpts, remoteChainSelector uint64, outboundConfig RateLimiterConfig, inboundConfig RateLimiterConfig) (*types.Transaction, error)
+
+ SetDomains(opts *bind.TransactOpts, domains []USDCTokenPoolDomainUpdate) (*types.Transaction, error)
+
+ SetRouter(opts *bind.TransactOpts, newRouter common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterAllowListAdd(opts *bind.FilterOpts) (*USDCTokenPoolAllowListAddIterator, error)
+
+ WatchAllowListAdd(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolAllowListAdd) (event.Subscription, error)
+
+ ParseAllowListAdd(log types.Log) (*USDCTokenPoolAllowListAdd, error)
+
+ FilterAllowListRemove(opts *bind.FilterOpts) (*USDCTokenPoolAllowListRemoveIterator, error)
+
+ WatchAllowListRemove(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolAllowListRemove) (event.Subscription, error)
+
+ ParseAllowListRemove(log types.Log) (*USDCTokenPoolAllowListRemove, error)
+
+ FilterBurned(opts *bind.FilterOpts, sender []common.Address) (*USDCTokenPoolBurnedIterator, error)
+
+ WatchBurned(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolBurned, sender []common.Address) (event.Subscription, error)
+
+ ParseBurned(log types.Log) (*USDCTokenPoolBurned, error)
+
+ FilterChainAdded(opts *bind.FilterOpts) (*USDCTokenPoolChainAddedIterator, error)
+
+ WatchChainAdded(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainAdded) (event.Subscription, error)
+
+ ParseChainAdded(log types.Log) (*USDCTokenPoolChainAdded, error)
+
+ FilterChainConfigured(opts *bind.FilterOpts) (*USDCTokenPoolChainConfiguredIterator, error)
+
+ WatchChainConfigured(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainConfigured) (event.Subscription, error)
+
+ ParseChainConfigured(log types.Log) (*USDCTokenPoolChainConfigured, error)
+
+ FilterChainRemoved(opts *bind.FilterOpts) (*USDCTokenPoolChainRemovedIterator, error)
+
+ WatchChainRemoved(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolChainRemoved) (event.Subscription, error)
+
+ ParseChainRemoved(log types.Log) (*USDCTokenPoolChainRemoved, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*USDCTokenPoolConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*USDCTokenPoolConfigSet, error)
+
+ FilterDomainsSet(opts *bind.FilterOpts) (*USDCTokenPoolDomainsSetIterator, error)
+
+ WatchDomainsSet(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolDomainsSet) (event.Subscription, error)
+
+ ParseDomainsSet(log types.Log) (*USDCTokenPoolDomainsSet, error)
+
+ FilterLocked(opts *bind.FilterOpts, sender []common.Address) (*USDCTokenPoolLockedIterator, error)
+
+ WatchLocked(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolLocked, sender []common.Address) (event.Subscription, error)
+
+ ParseLocked(log types.Log) (*USDCTokenPoolLocked, error)
+
+ FilterMinted(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*USDCTokenPoolMintedIterator, error)
+
+ WatchMinted(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolMinted, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseMinted(log types.Log) (*USDCTokenPoolMinted, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*USDCTokenPoolOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*USDCTokenPoolOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*USDCTokenPoolOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*USDCTokenPoolOwnershipTransferred, error)
+
+ FilterReleased(opts *bind.FilterOpts, sender []common.Address, recipient []common.Address) (*USDCTokenPoolReleasedIterator, error)
+
+ WatchReleased(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolReleased, sender []common.Address, recipient []common.Address) (event.Subscription, error)
+
+ ParseReleased(log types.Log) (*USDCTokenPoolReleased, error)
+
+ FilterRouterUpdated(opts *bind.FilterOpts) (*USDCTokenPoolRouterUpdatedIterator, error)
+
+ WatchRouterUpdated(opts *bind.WatchOpts, sink chan<- *USDCTokenPoolRouterUpdated) (event.Subscription, error)
+
+ ParseRouterUpdated(log types.Log) (*USDCTokenPoolRouterUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generated/weth9/weth9.go b/core/gethwrappers/ccip/generated/weth9/weth9.go
new file mode 100644
index 00000000000..50d0aa23f73
--- /dev/null
+++ b/core/gethwrappers/ccip/generated/weth9/weth9.go
@@ -0,0 +1,996 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package weth9
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var WETH9MetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"guy\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"Withdrawal\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"guy\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deposit\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"src\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"dst\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wad\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
+ Bin: "0x60c0604052600d60809081526c2bb930b83832b21022ba3432b960991b60a05260009061002c9082610116565b506040805180820190915260048152630ae8aa8960e31b60208201526001906100559082610116565b506002805460ff1916601217905534801561006f57600080fd5b506101d5565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061009f57607f821691505b6020821081036100bf57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610111576000816000526020600020601f850160051c810160208610156100ee5750805b601f850160051c820191505b8181101561010d578281556001016100fa565b5050505b505050565b81516001600160401b0381111561012f5761012f610075565b6101438161013d845461008b565b846100c5565b602080601f83116001811461017857600084156101605750858301515b600019600386901b1c1916600185901b17855561010d565b600085815260208120601f198616915b828110156101a757888601518255948401946001909101908401610188565b50858210156101c55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6108ad806101e46000396000f3fe6080604052600436106100c05760003560e01c8063313ce56711610074578063a9059cbb1161004e578063a9059cbb146101fa578063d0e30db01461021a578063dd62ed3e1461022257600080fd5b8063313ce5671461018c57806370a08231146101b857806395d89b41146101e557600080fd5b806318160ddd116100a557806318160ddd1461012f57806323b872dd1461014c5780632e1a7d4d1461016c57600080fd5b806306fdde03146100d4578063095ea7b3146100ff57600080fd5b366100cf576100cd61025a565b005b600080fd5b3480156100e057600080fd5b506100e96102b5565b6040516100f69190610695565b60405180910390f35b34801561010b57600080fd5b5061011f61011a36600461072b565b610343565b60405190151581526020016100f6565b34801561013b57600080fd5b50475b6040519081526020016100f6565b34801561015857600080fd5b5061011f610167366004610755565b6103bd565b34801561017857600080fd5b506100cd610187366004610791565b6105c4565b34801561019857600080fd5b506002546101a69060ff1681565b60405160ff90911681526020016100f6565b3480156101c457600080fd5b5061013e6101d33660046107aa565b60036020526000908152604090205481565b3480156101f157600080fd5b506100e961066a565b34801561020657600080fd5b5061011f61021536600461072b565b610677565b6100cd61068b565b34801561022e57600080fd5b5061013e61023d3660046107c5565b600460209081526000928352604080842090915290825290205481565b3360009081526003602052604081208054349290610279908490610827565b909155505060405134815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c9060200160405180910390a2565b600080546102c29061083a565b80601f01602080910402602001604051908101604052809291908181526020018280546102ee9061083a565b801561033b5780601f106103105761010080835404028352916020019161033b565b820191906000526020600020905b81548152906001019060200180831161031e57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103ab9086815260200190565b60405180910390a35060015b92915050565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120548211156103ef57600080fd5b73ffffffffffffffffffffffffffffffffffffffff84163314801590610455575073ffffffffffffffffffffffffffffffffffffffff841660009081526004602090815260408083203384529091529020546fffffffffffffffffffffffffffffffff14155b156104dd5773ffffffffffffffffffffffffffffffffffffffff8416600090815260046020908152604080832033845290915290205482111561049757600080fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600460209081526040808320338452909152812080548492906104d790849061088d565b90915550505b73ffffffffffffffffffffffffffffffffffffffff84166000908152600360205260408120805484929061051290849061088d565b909155505073ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120805484929061054c908490610827565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516105b291815260200190565b60405180910390a35060019392505050565b336000908152600360205260409020548111156105e057600080fd5b33600090815260036020526040812080548392906105ff90849061088d565b9091555050604051339082156108fc029083906000818181858888f19350505050158015610631573d6000803e3d6000fd5b5060405181815233907f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b659060200160405180910390a250565b600180546102c29061083a565b60006106843384846103bd565b9392505050565b61069361025a565b565b60006020808352835180602085015260005b818110156106c3578581018301518582016040015282016106a7565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461072657600080fd5b919050565b6000806040838503121561073e57600080fd5b61074783610702565b946020939093013593505050565b60008060006060848603121561076a57600080fd5b61077384610702565b925061078160208501610702565b9150604084013590509250925092565b6000602082840312156107a357600080fd5b5035919050565b6000602082840312156107bc57600080fd5b61068482610702565b600080604083850312156107d857600080fd5b6107e183610702565b91506107ef60208401610702565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156103b7576103b76107f8565b600181811c9082168061084e57607f821691505b602082108103610887577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b818103818111156103b7576103b76107f856fea164736f6c6343000818000a",
+}
+
+var WETH9ABI = WETH9MetaData.ABI
+
+var WETH9Bin = WETH9MetaData.Bin
+
+func DeployWETH9(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *WETH9, error) {
+ parsed, err := WETH9MetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(WETH9Bin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &WETH9{address: address, abi: *parsed, WETH9Caller: WETH9Caller{contract: contract}, WETH9Transactor: WETH9Transactor{contract: contract}, WETH9Filterer: WETH9Filterer{contract: contract}}, nil
+}
+
+type WETH9 struct {
+ address common.Address
+ abi abi.ABI
+ WETH9Caller
+ WETH9Transactor
+ WETH9Filterer
+}
+
+type WETH9Caller struct {
+ contract *bind.BoundContract
+}
+
+type WETH9Transactor struct {
+ contract *bind.BoundContract
+}
+
+type WETH9Filterer struct {
+ contract *bind.BoundContract
+}
+
+type WETH9Session struct {
+ Contract *WETH9
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type WETH9CallerSession struct {
+ Contract *WETH9Caller
+ CallOpts bind.CallOpts
+}
+
+type WETH9TransactorSession struct {
+ Contract *WETH9Transactor
+ TransactOpts bind.TransactOpts
+}
+
+type WETH9Raw struct {
+ Contract *WETH9
+}
+
+type WETH9CallerRaw struct {
+ Contract *WETH9Caller
+}
+
+type WETH9TransactorRaw struct {
+ Contract *WETH9Transactor
+}
+
+func NewWETH9(address common.Address, backend bind.ContractBackend) (*WETH9, error) {
+ abi, err := abi.JSON(strings.NewReader(WETH9ABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindWETH9(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &WETH9{address: address, abi: abi, WETH9Caller: WETH9Caller{contract: contract}, WETH9Transactor: WETH9Transactor{contract: contract}, WETH9Filterer: WETH9Filterer{contract: contract}}, nil
+}
+
+func NewWETH9Caller(address common.Address, caller bind.ContractCaller) (*WETH9Caller, error) {
+ contract, err := bindWETH9(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &WETH9Caller{contract: contract}, nil
+}
+
+func NewWETH9Transactor(address common.Address, transactor bind.ContractTransactor) (*WETH9Transactor, error) {
+ contract, err := bindWETH9(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &WETH9Transactor{contract: contract}, nil
+}
+
+func NewWETH9Filterer(address common.Address, filterer bind.ContractFilterer) (*WETH9Filterer, error) {
+ contract, err := bindWETH9(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &WETH9Filterer{contract: contract}, nil
+}
+
+func bindWETH9(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := WETH9MetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_WETH9 *WETH9Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _WETH9.Contract.WETH9Caller.contract.Call(opts, result, method, params...)
+}
+
+func (_WETH9 *WETH9Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _WETH9.Contract.WETH9Transactor.contract.Transfer(opts)
+}
+
+func (_WETH9 *WETH9Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _WETH9.Contract.WETH9Transactor.contract.Transact(opts, method, params...)
+}
+
+func (_WETH9 *WETH9CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _WETH9.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_WETH9 *WETH9TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _WETH9.Contract.contract.Transfer(opts)
+}
+
+func (_WETH9 *WETH9TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _WETH9.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_WETH9 *WETH9Caller) Allowance(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _WETH9.contract.Call(opts, &out, "allowance", arg0, arg1)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_WETH9 *WETH9Session) Allowance(arg0 common.Address, arg1 common.Address) (*big.Int, error) {
+ return _WETH9.Contract.Allowance(&_WETH9.CallOpts, arg0, arg1)
+}
+
+func (_WETH9 *WETH9CallerSession) Allowance(arg0 common.Address, arg1 common.Address) (*big.Int, error) {
+ return _WETH9.Contract.Allowance(&_WETH9.CallOpts, arg0, arg1)
+}
+
+func (_WETH9 *WETH9Caller) BalanceOf(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _WETH9.contract.Call(opts, &out, "balanceOf", arg0)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_WETH9 *WETH9Session) BalanceOf(arg0 common.Address) (*big.Int, error) {
+ return _WETH9.Contract.BalanceOf(&_WETH9.CallOpts, arg0)
+}
+
+func (_WETH9 *WETH9CallerSession) BalanceOf(arg0 common.Address) (*big.Int, error) {
+ return _WETH9.Contract.BalanceOf(&_WETH9.CallOpts, arg0)
+}
+
+func (_WETH9 *WETH9Caller) Decimals(opts *bind.CallOpts) (uint8, error) {
+ var out []interface{}
+ err := _WETH9.contract.Call(opts, &out, "decimals")
+
+ if err != nil {
+ return *new(uint8), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
+
+ return out0, err
+
+}
+
+func (_WETH9 *WETH9Session) Decimals() (uint8, error) {
+ return _WETH9.Contract.Decimals(&_WETH9.CallOpts)
+}
+
+func (_WETH9 *WETH9CallerSession) Decimals() (uint8, error) {
+ return _WETH9.Contract.Decimals(&_WETH9.CallOpts)
+}
+
+func (_WETH9 *WETH9Caller) Name(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _WETH9.contract.Call(opts, &out, "name")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_WETH9 *WETH9Session) Name() (string, error) {
+ return _WETH9.Contract.Name(&_WETH9.CallOpts)
+}
+
+func (_WETH9 *WETH9CallerSession) Name() (string, error) {
+ return _WETH9.Contract.Name(&_WETH9.CallOpts)
+}
+
+func (_WETH9 *WETH9Caller) Symbol(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _WETH9.contract.Call(opts, &out, "symbol")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_WETH9 *WETH9Session) Symbol() (string, error) {
+ return _WETH9.Contract.Symbol(&_WETH9.CallOpts)
+}
+
+func (_WETH9 *WETH9CallerSession) Symbol() (string, error) {
+ return _WETH9.Contract.Symbol(&_WETH9.CallOpts)
+}
+
+func (_WETH9 *WETH9Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _WETH9.contract.Call(opts, &out, "totalSupply")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_WETH9 *WETH9Session) TotalSupply() (*big.Int, error) {
+ return _WETH9.Contract.TotalSupply(&_WETH9.CallOpts)
+}
+
+func (_WETH9 *WETH9CallerSession) TotalSupply() (*big.Int, error) {
+ return _WETH9.Contract.TotalSupply(&_WETH9.CallOpts)
+}
+
+func (_WETH9 *WETH9Transactor) Approve(opts *bind.TransactOpts, guy common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.contract.Transact(opts, "approve", guy, wad)
+}
+
+func (_WETH9 *WETH9Session) Approve(guy common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.Contract.Approve(&_WETH9.TransactOpts, guy, wad)
+}
+
+func (_WETH9 *WETH9TransactorSession) Approve(guy common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.Contract.Approve(&_WETH9.TransactOpts, guy, wad)
+}
+
+func (_WETH9 *WETH9Transactor) Deposit(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _WETH9.contract.Transact(opts, "deposit")
+}
+
+func (_WETH9 *WETH9Session) Deposit() (*types.Transaction, error) {
+ return _WETH9.Contract.Deposit(&_WETH9.TransactOpts)
+}
+
+func (_WETH9 *WETH9TransactorSession) Deposit() (*types.Transaction, error) {
+ return _WETH9.Contract.Deposit(&_WETH9.TransactOpts)
+}
+
+func (_WETH9 *WETH9Transactor) Transfer(opts *bind.TransactOpts, dst common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.contract.Transact(opts, "transfer", dst, wad)
+}
+
+func (_WETH9 *WETH9Session) Transfer(dst common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.Contract.Transfer(&_WETH9.TransactOpts, dst, wad)
+}
+
+func (_WETH9 *WETH9TransactorSession) Transfer(dst common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.Contract.Transfer(&_WETH9.TransactOpts, dst, wad)
+}
+
+func (_WETH9 *WETH9Transactor) TransferFrom(opts *bind.TransactOpts, src common.Address, dst common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.contract.Transact(opts, "transferFrom", src, dst, wad)
+}
+
+func (_WETH9 *WETH9Session) TransferFrom(src common.Address, dst common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.Contract.TransferFrom(&_WETH9.TransactOpts, src, dst, wad)
+}
+
+func (_WETH9 *WETH9TransactorSession) TransferFrom(src common.Address, dst common.Address, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.Contract.TransferFrom(&_WETH9.TransactOpts, src, dst, wad)
+}
+
+func (_WETH9 *WETH9Transactor) Withdraw(opts *bind.TransactOpts, wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.contract.Transact(opts, "withdraw", wad)
+}
+
+func (_WETH9 *WETH9Session) Withdraw(wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.Contract.Withdraw(&_WETH9.TransactOpts, wad)
+}
+
+func (_WETH9 *WETH9TransactorSession) Withdraw(wad *big.Int) (*types.Transaction, error) {
+ return _WETH9.Contract.Withdraw(&_WETH9.TransactOpts, wad)
+}
+
+func (_WETH9 *WETH9Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _WETH9.contract.RawTransact(opts, nil)
+}
+
+func (_WETH9 *WETH9Session) Receive() (*types.Transaction, error) {
+ return _WETH9.Contract.Receive(&_WETH9.TransactOpts)
+}
+
+func (_WETH9 *WETH9TransactorSession) Receive() (*types.Transaction, error) {
+ return _WETH9.Contract.Receive(&_WETH9.TransactOpts)
+}
+
+type WETH9ApprovalIterator struct {
+ Event *WETH9Approval
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *WETH9ApprovalIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(WETH9Approval)
+ 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(WETH9Approval)
+ 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 *WETH9ApprovalIterator) Error() error {
+ return it.fail
+}
+
+func (it *WETH9ApprovalIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type WETH9Approval struct {
+ Src common.Address
+ Guy common.Address
+ Wad *big.Int
+ Raw types.Log
+}
+
+func (_WETH9 *WETH9Filterer) FilterApproval(opts *bind.FilterOpts, src []common.Address, guy []common.Address) (*WETH9ApprovalIterator, error) {
+
+ var srcRule []interface{}
+ for _, srcItem := range src {
+ srcRule = append(srcRule, srcItem)
+ }
+ var guyRule []interface{}
+ for _, guyItem := range guy {
+ guyRule = append(guyRule, guyItem)
+ }
+
+ logs, sub, err := _WETH9.contract.FilterLogs(opts, "Approval", srcRule, guyRule)
+ if err != nil {
+ return nil, err
+ }
+ return &WETH9ApprovalIterator{contract: _WETH9.contract, event: "Approval", logs: logs, sub: sub}, nil
+}
+
+func (_WETH9 *WETH9Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *WETH9Approval, src []common.Address, guy []common.Address) (event.Subscription, error) {
+
+ var srcRule []interface{}
+ for _, srcItem := range src {
+ srcRule = append(srcRule, srcItem)
+ }
+ var guyRule []interface{}
+ for _, guyItem := range guy {
+ guyRule = append(guyRule, guyItem)
+ }
+
+ logs, sub, err := _WETH9.contract.WatchLogs(opts, "Approval", srcRule, guyRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(WETH9Approval)
+ if err := _WETH9.contract.UnpackLog(event, "Approval", 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 (_WETH9 *WETH9Filterer) ParseApproval(log types.Log) (*WETH9Approval, error) {
+ event := new(WETH9Approval)
+ if err := _WETH9.contract.UnpackLog(event, "Approval", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type WETH9DepositIterator struct {
+ Event *WETH9Deposit
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *WETH9DepositIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(WETH9Deposit)
+ 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(WETH9Deposit)
+ 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 *WETH9DepositIterator) Error() error {
+ return it.fail
+}
+
+func (it *WETH9DepositIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type WETH9Deposit struct {
+ Dst common.Address
+ Wad *big.Int
+ Raw types.Log
+}
+
+func (_WETH9 *WETH9Filterer) FilterDeposit(opts *bind.FilterOpts, dst []common.Address) (*WETH9DepositIterator, error) {
+
+ var dstRule []interface{}
+ for _, dstItem := range dst {
+ dstRule = append(dstRule, dstItem)
+ }
+
+ logs, sub, err := _WETH9.contract.FilterLogs(opts, "Deposit", dstRule)
+ if err != nil {
+ return nil, err
+ }
+ return &WETH9DepositIterator{contract: _WETH9.contract, event: "Deposit", logs: logs, sub: sub}, nil
+}
+
+func (_WETH9 *WETH9Filterer) WatchDeposit(opts *bind.WatchOpts, sink chan<- *WETH9Deposit, dst []common.Address) (event.Subscription, error) {
+
+ var dstRule []interface{}
+ for _, dstItem := range dst {
+ dstRule = append(dstRule, dstItem)
+ }
+
+ logs, sub, err := _WETH9.contract.WatchLogs(opts, "Deposit", dstRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(WETH9Deposit)
+ if err := _WETH9.contract.UnpackLog(event, "Deposit", 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 (_WETH9 *WETH9Filterer) ParseDeposit(log types.Log) (*WETH9Deposit, error) {
+ event := new(WETH9Deposit)
+ if err := _WETH9.contract.UnpackLog(event, "Deposit", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type WETH9TransferIterator struct {
+ Event *WETH9Transfer
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *WETH9TransferIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(WETH9Transfer)
+ 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(WETH9Transfer)
+ 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 *WETH9TransferIterator) Error() error {
+ return it.fail
+}
+
+func (it *WETH9TransferIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type WETH9Transfer struct {
+ Src common.Address
+ Dst common.Address
+ Wad *big.Int
+ Raw types.Log
+}
+
+func (_WETH9 *WETH9Filterer) FilterTransfer(opts *bind.FilterOpts, src []common.Address, dst []common.Address) (*WETH9TransferIterator, error) {
+
+ var srcRule []interface{}
+ for _, srcItem := range src {
+ srcRule = append(srcRule, srcItem)
+ }
+ var dstRule []interface{}
+ for _, dstItem := range dst {
+ dstRule = append(dstRule, dstItem)
+ }
+
+ logs, sub, err := _WETH9.contract.FilterLogs(opts, "Transfer", srcRule, dstRule)
+ if err != nil {
+ return nil, err
+ }
+ return &WETH9TransferIterator{contract: _WETH9.contract, event: "Transfer", logs: logs, sub: sub}, nil
+}
+
+func (_WETH9 *WETH9Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *WETH9Transfer, src []common.Address, dst []common.Address) (event.Subscription, error) {
+
+ var srcRule []interface{}
+ for _, srcItem := range src {
+ srcRule = append(srcRule, srcItem)
+ }
+ var dstRule []interface{}
+ for _, dstItem := range dst {
+ dstRule = append(dstRule, dstItem)
+ }
+
+ logs, sub, err := _WETH9.contract.WatchLogs(opts, "Transfer", srcRule, dstRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(WETH9Transfer)
+ if err := _WETH9.contract.UnpackLog(event, "Transfer", 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 (_WETH9 *WETH9Filterer) ParseTransfer(log types.Log) (*WETH9Transfer, error) {
+ event := new(WETH9Transfer)
+ if err := _WETH9.contract.UnpackLog(event, "Transfer", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type WETH9WithdrawalIterator struct {
+ Event *WETH9Withdrawal
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *WETH9WithdrawalIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(WETH9Withdrawal)
+ 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(WETH9Withdrawal)
+ 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 *WETH9WithdrawalIterator) Error() error {
+ return it.fail
+}
+
+func (it *WETH9WithdrawalIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type WETH9Withdrawal struct {
+ Src common.Address
+ Wad *big.Int
+ Raw types.Log
+}
+
+func (_WETH9 *WETH9Filterer) FilterWithdrawal(opts *bind.FilterOpts, src []common.Address) (*WETH9WithdrawalIterator, error) {
+
+ var srcRule []interface{}
+ for _, srcItem := range src {
+ srcRule = append(srcRule, srcItem)
+ }
+
+ logs, sub, err := _WETH9.contract.FilterLogs(opts, "Withdrawal", srcRule)
+ if err != nil {
+ return nil, err
+ }
+ return &WETH9WithdrawalIterator{contract: _WETH9.contract, event: "Withdrawal", logs: logs, sub: sub}, nil
+}
+
+func (_WETH9 *WETH9Filterer) WatchWithdrawal(opts *bind.WatchOpts, sink chan<- *WETH9Withdrawal, src []common.Address) (event.Subscription, error) {
+
+ var srcRule []interface{}
+ for _, srcItem := range src {
+ srcRule = append(srcRule, srcItem)
+ }
+
+ logs, sub, err := _WETH9.contract.WatchLogs(opts, "Withdrawal", srcRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(WETH9Withdrawal)
+ if err := _WETH9.contract.UnpackLog(event, "Withdrawal", 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 (_WETH9 *WETH9Filterer) ParseWithdrawal(log types.Log) (*WETH9Withdrawal, error) {
+ event := new(WETH9Withdrawal)
+ if err := _WETH9.contract.UnpackLog(event, "Withdrawal", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_WETH9 *WETH9) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _WETH9.abi.Events["Approval"].ID:
+ return _WETH9.ParseApproval(log)
+ case _WETH9.abi.Events["Deposit"].ID:
+ return _WETH9.ParseDeposit(log)
+ case _WETH9.abi.Events["Transfer"].ID:
+ return _WETH9.ParseTransfer(log)
+ case _WETH9.abi.Events["Withdrawal"].ID:
+ return _WETH9.ParseWithdrawal(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (WETH9Approval) Topic() common.Hash {
+ return common.HexToHash("0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925")
+}
+
+func (WETH9Deposit) Topic() common.Hash {
+ return common.HexToHash("0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c")
+}
+
+func (WETH9Transfer) Topic() common.Hash {
+ return common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
+}
+
+func (WETH9Withdrawal) Topic() common.Hash {
+ return common.HexToHash("0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65")
+}
+
+func (_WETH9 *WETH9) Address() common.Address {
+ return _WETH9.address
+}
+
+type WETH9Interface interface {
+ Allowance(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address) (*big.Int, error)
+
+ BalanceOf(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error)
+
+ Decimals(opts *bind.CallOpts) (uint8, error)
+
+ Name(opts *bind.CallOpts) (string, error)
+
+ Symbol(opts *bind.CallOpts) (string, error)
+
+ TotalSupply(opts *bind.CallOpts) (*big.Int, error)
+
+ Approve(opts *bind.TransactOpts, guy common.Address, wad *big.Int) (*types.Transaction, error)
+
+ Deposit(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Transfer(opts *bind.TransactOpts, dst common.Address, wad *big.Int) (*types.Transaction, error)
+
+ TransferFrom(opts *bind.TransactOpts, src common.Address, dst common.Address, wad *big.Int) (*types.Transaction, error)
+
+ Withdraw(opts *bind.TransactOpts, wad *big.Int) (*types.Transaction, error)
+
+ Receive(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterApproval(opts *bind.FilterOpts, src []common.Address, guy []common.Address) (*WETH9ApprovalIterator, error)
+
+ WatchApproval(opts *bind.WatchOpts, sink chan<- *WETH9Approval, src []common.Address, guy []common.Address) (event.Subscription, error)
+
+ ParseApproval(log types.Log) (*WETH9Approval, error)
+
+ FilterDeposit(opts *bind.FilterOpts, dst []common.Address) (*WETH9DepositIterator, error)
+
+ WatchDeposit(opts *bind.WatchOpts, sink chan<- *WETH9Deposit, dst []common.Address) (event.Subscription, error)
+
+ ParseDeposit(log types.Log) (*WETH9Deposit, error)
+
+ FilterTransfer(opts *bind.FilterOpts, src []common.Address, dst []common.Address) (*WETH9TransferIterator, error)
+
+ WatchTransfer(opts *bind.WatchOpts, sink chan<- *WETH9Transfer, src []common.Address, dst []common.Address) (event.Subscription, error)
+
+ ParseTransfer(log types.Log) (*WETH9Transfer, error)
+
+ FilterWithdrawal(opts *bind.FilterOpts, src []common.Address) (*WETH9WithdrawalIterator, error)
+
+ WatchWithdrawal(opts *bind.WatchOpts, sink chan<- *WETH9Withdrawal, src []common.Address) (event.Subscription, error)
+
+ ParseWithdrawal(log types.Log) (*WETH9Withdrawal, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt
new file mode 100644
index 00000000000..663eacb5ddb
--- /dev/null
+++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt
@@ -0,0 +1,37 @@
+GETH_VERSION: 1.13.8
+arm_contract: ../../../contracts/solc/v0.8.24/RMN/RMN.abi ../../../contracts/solc/v0.8.24/RMN/RMN.bin 1a0abacf84def916519013f713b667f106434a091af8b9f441e12cc90aa2cdf8
+arm_proxy_contract: ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.abi ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.bin b048d8e752e3c41113ebb305c1efa06737ad36b4907b93e627fb0a3113023454
+burn_from_mint_token_pool: ../../../contracts/solc/v0.8.24/BurnFromMintTokenPool/BurnFromMintTokenPool.abi ../../../contracts/solc/v0.8.24/BurnFromMintTokenPool/BurnFromMintTokenPool.bin d0708a0ae657eb7df01a5177ff4d5850c5823c821f5f6bbd0a468b3982330b13
+burn_mint_token_pool: ../../../contracts/solc/v0.8.24/BurnMintTokenPool/BurnMintTokenPool.abi ../../../contracts/solc/v0.8.24/BurnMintTokenPool/BurnMintTokenPool.bin fcb85edfc871504a5146db2e3951193c2de089fe491dd7a2fbc755fd92725cac
+burn_mint_token_pool_and_proxy: ../../../contracts/solc/v0.8.24/BurnMintTokenPoolAndProxy/BurnMintTokenPoolAndProxy.abi ../../../contracts/solc/v0.8.24/BurnMintTokenPoolAndProxy/BurnMintTokenPoolAndProxy.bin 17bcd03828f43f50028bc4d66fdfb0cf576aaf28895d8f86c6ff598159a0cd64
+burn_with_from_mint_token_pool: ../../../contracts/solc/v0.8.24/BurnWithFromMintTokenPool/BurnWithFromMintTokenPool.abi ../../../contracts/solc/v0.8.24/BurnWithFromMintTokenPool/BurnWithFromMintTokenPool.bin 6f40135e1488097eafa843839a719fe9a3c21354565b64eb377a24a0a55782ef
+ccip_config: ../../../contracts/solc/v0.8.24/CCIPConfig/CCIPConfig.abi ../../../contracts/solc/v0.8.24/CCIPConfig/CCIPConfig.bin c06c1cf1d004a803585a2c9d7a71ee5997b5fca86c2e111335cb8b930d9e3b5a
+commit_store: ../../../contracts/solc/v0.8.24/CommitStore/CommitStore.abi ../../../contracts/solc/v0.8.24/CommitStore/CommitStore.bin ddc26c10c2a52b59624faae9005827b09b98db4566887a736005e8cc37cf8a51
+commit_store_helper: ../../../contracts/solc/v0.8.24/CommitStoreHelper/CommitStoreHelper.abi ../../../contracts/solc/v0.8.24/CommitStoreHelper/CommitStoreHelper.bin ebd8aac686fa28a71d4212bcd25a28f8f640d50dce5e50498b2f6b8534890b69
+ether_sender_receiver: ../../../contracts/solc/v0.8.24/EtherSenderReceiver/EtherSenderReceiver.abi ../../../contracts/solc/v0.8.24/EtherSenderReceiver/EtherSenderReceiver.bin 09510a3f773f108a3c231e8d202835c845ded862d071ec54c4f89c12d868b8de
+evm_2_evm_multi_offramp: ../../../contracts/solc/v0.8.24/EVM2EVMMultiOffRamp/EVM2EVMMultiOffRamp.abi ../../../contracts/solc/v0.8.24/EVM2EVMMultiOffRamp/EVM2EVMMultiOffRamp.bin 25a7bf3aa46252844c7afabc15db1051e7b6a717e296fc4c6e2f2f93d16033c5
+evm_2_evm_multi_onramp: ../../../contracts/solc/v0.8.24/EVM2EVMMultiOnRamp/EVM2EVMMultiOnRamp.abi ../../../contracts/solc/v0.8.24/EVM2EVMMultiOnRamp/EVM2EVMMultiOnRamp.bin 9478aedc9f0072fbdafb54a6f82248de1efbcd7bdff18a90d8556b9aaff67455
+evm_2_evm_offramp: ../../../contracts/solc/v0.8.24/EVM2EVMOffRamp/EVM2EVMOffRamp.abi ../../../contracts/solc/v0.8.24/EVM2EVMOffRamp/EVM2EVMOffRamp.bin a8c23c9280a713544eae0a0b8841a9caf97e616338d31ebc62501d8b4ab0eed6
+evm_2_evm_onramp: ../../../contracts/solc/v0.8.24/EVM2EVMOnRamp/EVM2EVMOnRamp.abi ../../../contracts/solc/v0.8.24/EVM2EVMOnRamp/EVM2EVMOnRamp.bin 116d5cb8447a1af61664a8d1db2d76086c042a3228337bc5cd49b9abd3e815f7
+lock_release_token_pool: ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.bin 95a93517b01f51c35d82711a0015995f4804820ed67f6b46b785c4c94815df93
+lock_release_token_pool_and_proxy: ../../../contracts/solc/v0.8.24/LockReleaseTokenPoolAndProxy/LockReleaseTokenPoolAndProxy.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPoolAndProxy/LockReleaseTokenPoolAndProxy.bin 05e308151b5adc9ba8d33385b8f82d55aad638652fe50e3ea8b09b1d0bbfd367
+maybe_revert_message_receiver: ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.abi ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.bin d73956c26232ebcc4a5444429fa99cbefed960e323be9b5a24925885c2e477d5
+message_hasher: ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.abi ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.bin 1d5146d43e1b99cd2d6f9f06475be19087e4349f7cee0fdbbf134ba65e967c93
+mock_arm_contract: ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.abi ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.bin e7a3a6c3eda5fb882e16bcc2b4340f78523acb67907bcdcaf3c8ffc51488688e
+mock_usdc_token_messenger: ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.bin e0cf17a38b438239fc6294ddca88f86b6c39e4542aefd9815b2d92987191b8bd
+mock_usdc_token_transmitter: ../../../contracts/solc/v0.8.24/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.bin 33bdad70822e889de7c720ed20085cf9cd3f8eba8b68f26bd6535197749595fe
+mock_v3_aggregator_contract: ../../../contracts/solc/v0.8.24/MockV3Aggregator/MockV3Aggregator.abi ../../../contracts/solc/v0.8.24/MockV3Aggregator/MockV3Aggregator.bin 518e19efa2ff52b0fefd8e597b05765317ee7638189bfe34ca43de2f6599faf4
+multi_aggregate_rate_limiter: ../../../contracts/solc/v0.8.24/MultiAggregateRateLimiter/MultiAggregateRateLimiter.abi ../../../contracts/solc/v0.8.24/MultiAggregateRateLimiter/MultiAggregateRateLimiter.bin abb0ecb1ed8621f26e43b39f5fa25f3d0b6d6c184fa37c404c4389605ecb74e7
+multi_ocr3_helper: ../../../contracts/solc/v0.8.24/MultiOCR3Helper/MultiOCR3Helper.abi ../../../contracts/solc/v0.8.24/MultiOCR3Helper/MultiOCR3Helper.bin aa299e0c2659d53aad4eace4d66be0e734b1366008593669cf30361ff529da6a
+nonce_manager: ../../../contracts/solc/v0.8.24/NonceManager/NonceManager.abi ../../../contracts/solc/v0.8.24/NonceManager/NonceManager.bin 78b58f4f192db7496e2b6de805d6a2c918b98d4fa62f3c7ed145ef3b5657a40d
+ocr3_config_encoder: ../../../contracts/solc/v0.8.24/IOCR3ConfigEncoder/IOCR3ConfigEncoder.abi ../../../contracts/solc/v0.8.24/IOCR3ConfigEncoder/IOCR3ConfigEncoder.bin e21180898e1ad54a045ee20add85a2793c681425ea06f66d1a9e5cab128b6487
+ping_pong_demo: ../../../contracts/solc/v0.8.24/PingPongDemo/PingPongDemo.abi ../../../contracts/solc/v0.8.24/PingPongDemo/PingPongDemo.bin 1588313bb5e781d181a825247d30828f59007700f36b4b9b00391592b06ff4b4
+price_registry: ../../../contracts/solc/v0.8.24/PriceRegistry/PriceRegistry.abi ../../../contracts/solc/v0.8.24/PriceRegistry/PriceRegistry.bin 09cdd37920d6f605c8a264f805bdba183813517169b2b5df4547e995d9ce73f7
+registry_module_owner_custom: ../../../contracts/solc/v0.8.24/RegistryModuleOwnerCustom/RegistryModuleOwnerCustom.abi ../../../contracts/solc/v0.8.24/RegistryModuleOwnerCustom/RegistryModuleOwnerCustom.bin 7b2a47349d3fdb8d8b4e206d68577219deca7fabd1e893686fa8f118ad980d2d
+report_codec: ../../../contracts/solc/v0.8.24/ReportCodec/ReportCodec.abi ../../../contracts/solc/v0.8.24/ReportCodec/ReportCodec.bin c07af8433bf8dbc7981725b18922a9c4e2dea068dd204bc62adc0e926cb499c3
+router: ../../../contracts/solc/v0.8.24/Router/Router.abi ../../../contracts/solc/v0.8.24/Router/Router.bin 42576577e81beea9a069bd9229caaa9a71227fbaef3871a1a2e69fd218216290
+self_funded_ping_pong: ../../../contracts/solc/v0.8.24/SelfFundedPingPong/SelfFundedPingPong.abi ../../../contracts/solc/v0.8.24/SelfFundedPingPong/SelfFundedPingPong.bin 86e169636e5633854ed0b709c804066b615040bceba25aa5137450fbe6f76fa3
+token_admin_registry: ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.abi ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.bin fb06d2cf5f7476e512c6fb7aab8eab43545efd7f0f6ca133c64ff4e3963902c4
+token_pool: ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.abi ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.bin 47a83e91b28ad1381a2a5882e2adfe168809a63a8f533ab1631f174550c64bed
+usdc_token_pool: ../../../contracts/solc/v0.8.24/USDCTokenPool/USDCTokenPool.abi ../../../contracts/solc/v0.8.24/USDCTokenPool/USDCTokenPool.bin a54136ed9bffc74fff830c5066dbfcee6db1f31d636795317267d6baf1e0427a
+weth9: ../../../contracts/solc/v0.8.24/WETH9/WETH9.abi ../../../contracts/solc/v0.8.24/WETH9/WETH9.bin 2970d79a0ca6dd6279cde130de45e56c8790ed695eae477fb5ba4c1bb75b720d
diff --git a/core/gethwrappers/ccip/go_generate.go b/core/gethwrappers/ccip/go_generate.go
new file mode 100644
index 00000000000..870ac2dd579
--- /dev/null
+++ b/core/gethwrappers/ccip/go_generate.go
@@ -0,0 +1,80 @@
+// Package gethwrappers_ccip provides tools for wrapping solidity contracts with
+// golang packages, using abigen.
+package ccip
+
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/CommitStore/CommitStore.abi ../../../contracts/solc/v0.8.24/CommitStore/CommitStore.bin CommitStore commit_store
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/CommitStoreHelper/CommitStoreHelper.abi ../../../contracts/solc/v0.8.24/CommitStoreHelper/CommitStoreHelper.bin CommitStoreHelper commit_store_helper
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/BurnMintTokenPool/BurnMintTokenPool.abi ../../../contracts/solc/v0.8.24/BurnMintTokenPool/BurnMintTokenPool.bin BurnMintTokenPool burn_mint_token_pool
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/BurnFromMintTokenPool/BurnFromMintTokenPool.abi ../../../contracts/solc/v0.8.24/BurnFromMintTokenPool/BurnFromMintTokenPool.bin BurnFromMintTokenPool burn_from_mint_token_pool
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/BurnWithFromMintTokenPool/BurnWithFromMintTokenPool.abi ../../../contracts/solc/v0.8.24/BurnWithFromMintTokenPool/BurnWithFromMintTokenPool.bin BurnWithFromMintTokenPool burn_with_from_mint_token_pool
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.bin LockReleaseTokenPool lock_release_token_pool
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/BurnMintTokenPoolAndProxy/BurnMintTokenPoolAndProxy.abi ../../../contracts/solc/v0.8.24/BurnMintTokenPoolAndProxy/BurnMintTokenPoolAndProxy.bin BurnMintTokenPoolAndProxy burn_mint_token_pool_and_proxy
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/LockReleaseTokenPoolAndProxy/LockReleaseTokenPoolAndProxy.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPoolAndProxy/LockReleaseTokenPoolAndProxy.bin LockReleaseTokenPoolAndProxy lock_release_token_pool_and_proxy
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.abi ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.bin TokenPool token_pool
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/RMN/RMN.abi ../../../contracts/solc/v0.8.24/RMN/RMN.bin ARMContract arm_contract
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.abi ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.bin ARMProxyContract arm_proxy_contract
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.abi ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.bin MockARMContract mock_arm_contract
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.abi ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.bin TokenAdminRegistry token_admin_registry
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/RegistryModuleOwnerCustom/RegistryModuleOwnerCustom.abi ../../../contracts/solc/v0.8.24/RegistryModuleOwnerCustom/RegistryModuleOwnerCustom.bin RegistryModuleOwnerCustom registry_module_owner_custom
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.bin MockE2EUSDCTokenMessenger mock_usdc_token_messenger
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.bin MockE2EUSDCTransmitter mock_usdc_token_transmitter
+
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockV3Aggregator/MockV3Aggregator.abi ../../../contracts/solc/v0.8.24/MockV3Aggregator/MockV3Aggregator.bin MockV3Aggregator mock_v3_aggregator_contract
+
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/EVM2EVMOnRamp/EVM2EVMOnRamp.abi ../../../contracts/solc/v0.8.24/EVM2EVMOnRamp/EVM2EVMOnRamp.bin EVM2EVMOnRamp evm_2_evm_onramp
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/EVM2EVMMultiOnRamp/EVM2EVMMultiOnRamp.abi ../../../contracts/solc/v0.8.24/EVM2EVMMultiOnRamp/EVM2EVMMultiOnRamp.bin EVM2EVMMultiOnRamp evm_2_evm_multi_onramp
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/EVM2EVMOffRamp/EVM2EVMOffRamp.abi ../../../contracts/solc/v0.8.24/EVM2EVMOffRamp/EVM2EVMOffRamp.bin EVM2EVMOffRamp evm_2_evm_offramp
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/EVM2EVMMultiOffRamp/EVM2EVMMultiOffRamp.abi ../../../contracts/solc/v0.8.24/EVM2EVMMultiOffRamp/EVM2EVMMultiOffRamp.bin EVM2EVMMultiOffRamp evm_2_evm_multi_offramp
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MultiAggregateRateLimiter/MultiAggregateRateLimiter.abi ../../../contracts/solc/v0.8.24/MultiAggregateRateLimiter/MultiAggregateRateLimiter.bin MultiAggregateRateLimiter multi_aggregate_rate_limiter
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/Router/Router.abi ../../../contracts/solc/v0.8.24/Router/Router.bin Router router
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/PriceRegistry/PriceRegistry.abi ../../../contracts/solc/v0.8.24/PriceRegistry/PriceRegistry.bin PriceRegistry price_registry
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/CCIPConfig/CCIPConfig.abi ../../../contracts/solc/v0.8.24/CCIPConfig/CCIPConfig.bin CCIPConfig ccip_config
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOCR3ConfigEncoder/IOCR3ConfigEncoder.abi ../../../contracts/solc/v0.8.24/IOCR3ConfigEncoder/IOCR3ConfigEncoder.bin IOCR3ConfigEncoder ocr3_config_encoder
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/NonceManager/NonceManager.abi ../../../contracts/solc/v0.8.24/NonceManager/NonceManager.bin NonceManager nonce_manager
+
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.abi ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.bin MaybeRevertMessageReceiver maybe_revert_message_receiver
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/PingPongDemo/PingPongDemo.abi ../../../contracts/solc/v0.8.24/PingPongDemo/PingPongDemo.bin PingPongDemo ping_pong_demo
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/SelfFundedPingPong/SelfFundedPingPong.abi ../../../contracts/solc/v0.8.24/SelfFundedPingPong/SelfFundedPingPong.bin SelfFundedPingPong self_funded_ping_pong
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.abi ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.bin MessageHasher message_hasher
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MultiOCR3Helper/MultiOCR3Helper.abi ../../../contracts/solc/v0.8.24/MultiOCR3Helper/MultiOCR3Helper.bin MultiOCR3Helper multi_ocr3_helper
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/ReportCodec/ReportCodec.abi ../../../contracts/solc/v0.8.24/ReportCodec/ReportCodec.bin ReportCodec report_codec
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/EtherSenderReceiver/EtherSenderReceiver.abi ../../../contracts/solc/v0.8.24/EtherSenderReceiver/EtherSenderReceiver.bin EtherSenderReceiver ether_sender_receiver
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/WETH9/WETH9.abi ../../../contracts/solc/v0.8.24/WETH9/WETH9.bin WETH9 weth9
+
+// Customer contracts
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/USDCTokenPool/USDCTokenPool.abi ../../../contracts/solc/v0.8.24/USDCTokenPool/USDCTokenPool.bin USDCTokenPool usdc_token_pool
+
+// To run these commands, you must either install docker, or the correct version
+// of abigen. The latter can be installed with these commands, at least on linux:
+//
+// git clone https://github.com/ethereum/go-ethereum
+// cd go-ethereum/cmd/abigen
+// git checkout v
+// go install
+//
+// Here, is the version of go-ethereum specified in chainlink's
+// go.mod. This will install abigen in "$GOPATH/bin", which you should add to
+// your $PATH.
+//
+// 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
+// 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
+//
+// where VRFAll.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.
+//
+// If you're on linux, you can copy the correct version of solc out of the
+// appropriate docker container. At least, the following works on ubuntu:
+//
+// $ docker run --name solc ethereum/solc:0.6.2
+// $ sudo docker cp solc:/usr/bin/solc /usr/bin
+// $ docker rm solc
+//
+// If you need to point abigen at your solc executable, you can specify the path
+// with the abigen --solc option.
diff --git a/core/gethwrappers/ccip/mocks/commit_store_interface.go b/core/gethwrappers/ccip/mocks/commit_store_interface.go
new file mode 100644
index 00000000000..124c2acaa41
--- /dev/null
+++ b/core/gethwrappers/ccip/mocks/commit_store_interface.go
@@ -0,0 +1,3418 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_contracts
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+ commit_store "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// CommitStoreInterface is an autogenerated mock type for the CommitStoreInterface type
+type CommitStoreInterface struct {
+ mock.Mock
+}
+
+type CommitStoreInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *CommitStoreInterface) EXPECT() *CommitStoreInterface_Expecter {
+ return &CommitStoreInterface_Expecter{mock: &_m.Mock}
+}
+
+// AcceptOwnership provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AcceptOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_AcceptOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptOwnership'
+type CommitStoreInterface_AcceptOwnership_Call struct {
+ *mock.Call
+}
+
+// AcceptOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *CommitStoreInterface_Expecter) AcceptOwnership(opts interface{}) *CommitStoreInterface_AcceptOwnership_Call {
+ return &CommitStoreInterface_AcceptOwnership_Call{Call: _e.mock.On("AcceptOwnership", opts)}
+}
+
+func (_c *CommitStoreInterface_AcceptOwnership_Call) Run(run func(opts *bind.TransactOpts)) *CommitStoreInterface_AcceptOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_AcceptOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_AcceptOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_AcceptOwnership_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *CommitStoreInterface_AcceptOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Address provides a mock function with given fields:
+func (_m *CommitStoreInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// CommitStoreInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type CommitStoreInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *CommitStoreInterface_Expecter) Address() *CommitStoreInterface_Address_Call {
+ return &CommitStoreInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *CommitStoreInterface_Address_Call) Run(run func()) *CommitStoreInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_Address_Call) Return(_a0 common.Address) *CommitStoreInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *CommitStoreInterface_Address_Call) RunAndReturn(run func() common.Address) *CommitStoreInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterConfigSet(opts *bind.FilterOpts) (*commit_store.CommitStoreConfigSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet")
+ }
+
+ var r0 *commit_store.CommitStoreConfigSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreConfigSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStoreConfigSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreConfigSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet'
+type CommitStoreInterface_FilterConfigSet_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterConfigSet(opts interface{}) *CommitStoreInterface_FilterConfigSet_Call {
+ return &CommitStoreInterface_FilterConfigSet_Call{Call: _e.mock.On("FilterConfigSet", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterConfigSet_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterConfigSet_Call) Return(_a0 *commit_store.CommitStoreConfigSetIterator, _a1 error) *CommitStoreInterface_FilterConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterConfigSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStoreConfigSetIterator, error)) *CommitStoreInterface_FilterConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet0 provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterConfigSet0(opts *bind.FilterOpts) (*commit_store.CommitStoreConfigSet0Iterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet0")
+ }
+
+ var r0 *commit_store.CommitStoreConfigSet0Iterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreConfigSet0Iterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStoreConfigSet0Iterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreConfigSet0Iterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet0'
+type CommitStoreInterface_FilterConfigSet0_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet0 is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterConfigSet0(opts interface{}) *CommitStoreInterface_FilterConfigSet0_Call {
+ return &CommitStoreInterface_FilterConfigSet0_Call{Call: _e.mock.On("FilterConfigSet0", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterConfigSet0_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterConfigSet0_Call) Return(_a0 *commit_store.CommitStoreConfigSet0Iterator, _a1 error) *CommitStoreInterface_FilterConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterConfigSet0_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStoreConfigSet0Iterator, error)) *CommitStoreInterface_FilterConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterLatestPriceEpochAndRoundSet provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterLatestPriceEpochAndRoundSet(opts *bind.FilterOpts) (*commit_store.CommitStoreLatestPriceEpochAndRoundSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterLatestPriceEpochAndRoundSet")
+ }
+
+ var r0 *commit_store.CommitStoreLatestPriceEpochAndRoundSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreLatestPriceEpochAndRoundSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStoreLatestPriceEpochAndRoundSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreLatestPriceEpochAndRoundSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterLatestPriceEpochAndRoundSet'
+type CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call struct {
+ *mock.Call
+}
+
+// FilterLatestPriceEpochAndRoundSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterLatestPriceEpochAndRoundSet(opts interface{}) *CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call {
+ return &CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call{Call: _e.mock.On("FilterLatestPriceEpochAndRoundSet", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call) Return(_a0 *commit_store.CommitStoreLatestPriceEpochAndRoundSetIterator, _a1 error) *CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStoreLatestPriceEpochAndRoundSetIterator, error)) *CommitStoreInterface_FilterLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to
+func (_m *CommitStoreInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*commit_store.CommitStoreOwnershipTransferRequestedIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferRequested")
+ }
+
+ var r0 *commit_store.CommitStoreOwnershipTransferRequestedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*commit_store.CommitStoreOwnershipTransferRequestedIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *commit_store.CommitStoreOwnershipTransferRequestedIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreOwnershipTransferRequestedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferRequested'
+type CommitStoreInterface_FilterOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *CommitStoreInterface_Expecter) FilterOwnershipTransferRequested(opts interface{}, from interface{}, to interface{}) *CommitStoreInterface_FilterOwnershipTransferRequested_Call {
+ return &CommitStoreInterface_FilterOwnershipTransferRequested_Call{Call: _e.mock.On("FilterOwnershipTransferRequested", opts, from, to)}
+}
+
+func (_c *CommitStoreInterface_FilterOwnershipTransferRequested_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *CommitStoreInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterOwnershipTransferRequested_Call) Return(_a0 *commit_store.CommitStoreOwnershipTransferRequestedIterator, _a1 error) *CommitStoreInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*commit_store.CommitStoreOwnershipTransferRequestedIterator, error)) *CommitStoreInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to
+func (_m *CommitStoreInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*commit_store.CommitStoreOwnershipTransferredIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferred")
+ }
+
+ var r0 *commit_store.CommitStoreOwnershipTransferredIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*commit_store.CommitStoreOwnershipTransferredIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *commit_store.CommitStoreOwnershipTransferredIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreOwnershipTransferredIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferred'
+type CommitStoreInterface_FilterOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *CommitStoreInterface_Expecter) FilterOwnershipTransferred(opts interface{}, from interface{}, to interface{}) *CommitStoreInterface_FilterOwnershipTransferred_Call {
+ return &CommitStoreInterface_FilterOwnershipTransferred_Call{Call: _e.mock.On("FilterOwnershipTransferred", opts, from, to)}
+}
+
+func (_c *CommitStoreInterface_FilterOwnershipTransferred_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *CommitStoreInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterOwnershipTransferred_Call) Return(_a0 *commit_store.CommitStoreOwnershipTransferredIterator, _a1 error) *CommitStoreInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterOwnershipTransferred_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*commit_store.CommitStoreOwnershipTransferredIterator, error)) *CommitStoreInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPaused provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterPaused(opts *bind.FilterOpts) (*commit_store.CommitStorePausedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPaused")
+ }
+
+ var r0 *commit_store.CommitStorePausedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStorePausedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStorePausedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStorePausedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterPaused_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPaused'
+type CommitStoreInterface_FilterPaused_Call struct {
+ *mock.Call
+}
+
+// FilterPaused is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterPaused(opts interface{}) *CommitStoreInterface_FilterPaused_Call {
+ return &CommitStoreInterface_FilterPaused_Call{Call: _e.mock.On("FilterPaused", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterPaused_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterPaused_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterPaused_Call) Return(_a0 *commit_store.CommitStorePausedIterator, _a1 error) *CommitStoreInterface_FilterPaused_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterPaused_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStorePausedIterator, error)) *CommitStoreInterface_FilterPaused_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterReportAccepted provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterReportAccepted(opts *bind.FilterOpts) (*commit_store.CommitStoreReportAcceptedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterReportAccepted")
+ }
+
+ var r0 *commit_store.CommitStoreReportAcceptedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreReportAcceptedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStoreReportAcceptedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreReportAcceptedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterReportAccepted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterReportAccepted'
+type CommitStoreInterface_FilterReportAccepted_Call struct {
+ *mock.Call
+}
+
+// FilterReportAccepted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterReportAccepted(opts interface{}) *CommitStoreInterface_FilterReportAccepted_Call {
+ return &CommitStoreInterface_FilterReportAccepted_Call{Call: _e.mock.On("FilterReportAccepted", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterReportAccepted_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterReportAccepted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterReportAccepted_Call) Return(_a0 *commit_store.CommitStoreReportAcceptedIterator, _a1 error) *CommitStoreInterface_FilterReportAccepted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterReportAccepted_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStoreReportAcceptedIterator, error)) *CommitStoreInterface_FilterReportAccepted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterRootRemoved provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterRootRemoved(opts *bind.FilterOpts) (*commit_store.CommitStoreRootRemovedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterRootRemoved")
+ }
+
+ var r0 *commit_store.CommitStoreRootRemovedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreRootRemovedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStoreRootRemovedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreRootRemovedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterRootRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterRootRemoved'
+type CommitStoreInterface_FilterRootRemoved_Call struct {
+ *mock.Call
+}
+
+// FilterRootRemoved is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterRootRemoved(opts interface{}) *CommitStoreInterface_FilterRootRemoved_Call {
+ return &CommitStoreInterface_FilterRootRemoved_Call{Call: _e.mock.On("FilterRootRemoved", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterRootRemoved_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterRootRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterRootRemoved_Call) Return(_a0 *commit_store.CommitStoreRootRemovedIterator, _a1 error) *CommitStoreInterface_FilterRootRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterRootRemoved_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStoreRootRemovedIterator, error)) *CommitStoreInterface_FilterRootRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSequenceNumberSet provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterSequenceNumberSet(opts *bind.FilterOpts) (*commit_store.CommitStoreSequenceNumberSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSequenceNumberSet")
+ }
+
+ var r0 *commit_store.CommitStoreSequenceNumberSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreSequenceNumberSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStoreSequenceNumberSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreSequenceNumberSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterSequenceNumberSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSequenceNumberSet'
+type CommitStoreInterface_FilterSequenceNumberSet_Call struct {
+ *mock.Call
+}
+
+// FilterSequenceNumberSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterSequenceNumberSet(opts interface{}) *CommitStoreInterface_FilterSequenceNumberSet_Call {
+ return &CommitStoreInterface_FilterSequenceNumberSet_Call{Call: _e.mock.On("FilterSequenceNumberSet", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterSequenceNumberSet_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterSequenceNumberSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterSequenceNumberSet_Call) Return(_a0 *commit_store.CommitStoreSequenceNumberSetIterator, _a1 error) *CommitStoreInterface_FilterSequenceNumberSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterSequenceNumberSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStoreSequenceNumberSetIterator, error)) *CommitStoreInterface_FilterSequenceNumberSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTransmitted provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterTransmitted(opts *bind.FilterOpts) (*commit_store.CommitStoreTransmittedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTransmitted")
+ }
+
+ var r0 *commit_store.CommitStoreTransmittedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreTransmittedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStoreTransmittedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreTransmittedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTransmitted'
+type CommitStoreInterface_FilterTransmitted_Call struct {
+ *mock.Call
+}
+
+// FilterTransmitted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterTransmitted(opts interface{}) *CommitStoreInterface_FilterTransmitted_Call {
+ return &CommitStoreInterface_FilterTransmitted_Call{Call: _e.mock.On("FilterTransmitted", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterTransmitted_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterTransmitted_Call) Return(_a0 *commit_store.CommitStoreTransmittedIterator, _a1 error) *CommitStoreInterface_FilterTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterTransmitted_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStoreTransmittedIterator, error)) *CommitStoreInterface_FilterTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterUnpaused provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) FilterUnpaused(opts *bind.FilterOpts) (*commit_store.CommitStoreUnpausedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterUnpaused")
+ }
+
+ var r0 *commit_store.CommitStoreUnpausedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*commit_store.CommitStoreUnpausedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *commit_store.CommitStoreUnpausedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreUnpausedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_FilterUnpaused_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterUnpaused'
+type CommitStoreInterface_FilterUnpaused_Call struct {
+ *mock.Call
+}
+
+// FilterUnpaused is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *CommitStoreInterface_Expecter) FilterUnpaused(opts interface{}) *CommitStoreInterface_FilterUnpaused_Call {
+ return &CommitStoreInterface_FilterUnpaused_Call{Call: _e.mock.On("FilterUnpaused", opts)}
+}
+
+func (_c *CommitStoreInterface_FilterUnpaused_Call) Run(run func(opts *bind.FilterOpts)) *CommitStoreInterface_FilterUnpaused_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterUnpaused_Call) Return(_a0 *commit_store.CommitStoreUnpausedIterator, _a1 error) *CommitStoreInterface_FilterUnpaused_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_FilterUnpaused_Call) RunAndReturn(run func(*bind.FilterOpts) (*commit_store.CommitStoreUnpausedIterator, error)) *CommitStoreInterface_FilterUnpaused_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDynamicConfig provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) GetDynamicConfig(opts *bind.CallOpts) (commit_store.CommitStoreDynamicConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDynamicConfig")
+ }
+
+ var r0 commit_store.CommitStoreDynamicConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (commit_store.CommitStoreDynamicConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) commit_store.CommitStoreDynamicConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(commit_store.CommitStoreDynamicConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_GetDynamicConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDynamicConfig'
+type CommitStoreInterface_GetDynamicConfig_Call struct {
+ *mock.Call
+}
+
+// GetDynamicConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) GetDynamicConfig(opts interface{}) *CommitStoreInterface_GetDynamicConfig_Call {
+ return &CommitStoreInterface_GetDynamicConfig_Call{Call: _e.mock.On("GetDynamicConfig", opts)}
+}
+
+func (_c *CommitStoreInterface_GetDynamicConfig_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_GetDynamicConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetDynamicConfig_Call) Return(_a0 commit_store.CommitStoreDynamicConfig, _a1 error) *CommitStoreInterface_GetDynamicConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetDynamicConfig_Call) RunAndReturn(run func(*bind.CallOpts) (commit_store.CommitStoreDynamicConfig, error)) *CommitStoreInterface_GetDynamicConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetExpectedNextSequenceNumber provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetExpectedNextSequenceNumber")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_GetExpectedNextSequenceNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExpectedNextSequenceNumber'
+type CommitStoreInterface_GetExpectedNextSequenceNumber_Call struct {
+ *mock.Call
+}
+
+// GetExpectedNextSequenceNumber is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) GetExpectedNextSequenceNumber(opts interface{}) *CommitStoreInterface_GetExpectedNextSequenceNumber_Call {
+ return &CommitStoreInterface_GetExpectedNextSequenceNumber_Call{Call: _e.mock.On("GetExpectedNextSequenceNumber", opts)}
+}
+
+func (_c *CommitStoreInterface_GetExpectedNextSequenceNumber_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetExpectedNextSequenceNumber_Call) Return(_a0 uint64, _a1 error) *CommitStoreInterface_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetExpectedNextSequenceNumber_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *CommitStoreInterface_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetLatestPriceEpochAndRound provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) GetLatestPriceEpochAndRound(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetLatestPriceEpochAndRound")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_GetLatestPriceEpochAndRound_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestPriceEpochAndRound'
+type CommitStoreInterface_GetLatestPriceEpochAndRound_Call struct {
+ *mock.Call
+}
+
+// GetLatestPriceEpochAndRound is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) GetLatestPriceEpochAndRound(opts interface{}) *CommitStoreInterface_GetLatestPriceEpochAndRound_Call {
+ return &CommitStoreInterface_GetLatestPriceEpochAndRound_Call{Call: _e.mock.On("GetLatestPriceEpochAndRound", opts)}
+}
+
+func (_c *CommitStoreInterface_GetLatestPriceEpochAndRound_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_GetLatestPriceEpochAndRound_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetLatestPriceEpochAndRound_Call) Return(_a0 uint64, _a1 error) *CommitStoreInterface_GetLatestPriceEpochAndRound_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetLatestPriceEpochAndRound_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *CommitStoreInterface_GetLatestPriceEpochAndRound_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetMerkleRoot provides a mock function with given fields: opts, root
+func (_m *CommitStoreInterface) GetMerkleRoot(opts *bind.CallOpts, root [32]byte) (*big.Int, error) {
+ ret := _m.Called(opts, root)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetMerkleRoot")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) (*big.Int, error)); ok {
+ return rf(opts, root)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) *big.Int); ok {
+ r0 = rf(opts, root)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, [32]byte) error); ok {
+ r1 = rf(opts, root)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_GetMerkleRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetMerkleRoot'
+type CommitStoreInterface_GetMerkleRoot_Call struct {
+ *mock.Call
+}
+
+// GetMerkleRoot is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - root [32]byte
+func (_e *CommitStoreInterface_Expecter) GetMerkleRoot(opts interface{}, root interface{}) *CommitStoreInterface_GetMerkleRoot_Call {
+ return &CommitStoreInterface_GetMerkleRoot_Call{Call: _e.mock.On("GetMerkleRoot", opts, root)}
+}
+
+func (_c *CommitStoreInterface_GetMerkleRoot_Call) Run(run func(opts *bind.CallOpts, root [32]byte)) *CommitStoreInterface_GetMerkleRoot_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].([32]byte))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetMerkleRoot_Call) Return(_a0 *big.Int, _a1 error) *CommitStoreInterface_GetMerkleRoot_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetMerkleRoot_Call) RunAndReturn(run func(*bind.CallOpts, [32]byte) (*big.Int, error)) *CommitStoreInterface_GetMerkleRoot_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStaticConfig provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) GetStaticConfig(opts *bind.CallOpts) (commit_store.CommitStoreStaticConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStaticConfig")
+ }
+
+ var r0 commit_store.CommitStoreStaticConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (commit_store.CommitStoreStaticConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) commit_store.CommitStoreStaticConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(commit_store.CommitStoreStaticConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_GetStaticConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStaticConfig'
+type CommitStoreInterface_GetStaticConfig_Call struct {
+ *mock.Call
+}
+
+// GetStaticConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) GetStaticConfig(opts interface{}) *CommitStoreInterface_GetStaticConfig_Call {
+ return &CommitStoreInterface_GetStaticConfig_Call{Call: _e.mock.On("GetStaticConfig", opts)}
+}
+
+func (_c *CommitStoreInterface_GetStaticConfig_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_GetStaticConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetStaticConfig_Call) Return(_a0 commit_store.CommitStoreStaticConfig, _a1 error) *CommitStoreInterface_GetStaticConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetStaticConfig_Call) RunAndReturn(run func(*bind.CallOpts) (commit_store.CommitStoreStaticConfig, error)) *CommitStoreInterface_GetStaticConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTransmitters provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTransmitters")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_GetTransmitters_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTransmitters'
+type CommitStoreInterface_GetTransmitters_Call struct {
+ *mock.Call
+}
+
+// GetTransmitters is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) GetTransmitters(opts interface{}) *CommitStoreInterface_GetTransmitters_Call {
+ return &CommitStoreInterface_GetTransmitters_Call{Call: _e.mock.On("GetTransmitters", opts)}
+}
+
+func (_c *CommitStoreInterface_GetTransmitters_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_GetTransmitters_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetTransmitters_Call) Return(_a0 []common.Address, _a1 error) *CommitStoreInterface_GetTransmitters_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_GetTransmitters_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *CommitStoreInterface_GetTransmitters_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsBlessed provides a mock function with given fields: opts, root
+func (_m *CommitStoreInterface) IsBlessed(opts *bind.CallOpts, root [32]byte) (bool, error) {
+ ret := _m.Called(opts, root)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsBlessed")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) (bool, error)); ok {
+ return rf(opts, root)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) bool); ok {
+ r0 = rf(opts, root)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, [32]byte) error); ok {
+ r1 = rf(opts, root)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_IsBlessed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsBlessed'
+type CommitStoreInterface_IsBlessed_Call struct {
+ *mock.Call
+}
+
+// IsBlessed is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - root [32]byte
+func (_e *CommitStoreInterface_Expecter) IsBlessed(opts interface{}, root interface{}) *CommitStoreInterface_IsBlessed_Call {
+ return &CommitStoreInterface_IsBlessed_Call{Call: _e.mock.On("IsBlessed", opts, root)}
+}
+
+func (_c *CommitStoreInterface_IsBlessed_Call) Run(run func(opts *bind.CallOpts, root [32]byte)) *CommitStoreInterface_IsBlessed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].([32]byte))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_IsBlessed_Call) Return(_a0 bool, _a1 error) *CommitStoreInterface_IsBlessed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_IsBlessed_Call) RunAndReturn(run func(*bind.CallOpts, [32]byte) (bool, error)) *CommitStoreInterface_IsBlessed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsUnpausedAndNotCursed provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) IsUnpausedAndNotCursed(opts *bind.CallOpts) (bool, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsUnpausedAndNotCursed")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) bool); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_IsUnpausedAndNotCursed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsUnpausedAndNotCursed'
+type CommitStoreInterface_IsUnpausedAndNotCursed_Call struct {
+ *mock.Call
+}
+
+// IsUnpausedAndNotCursed is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) IsUnpausedAndNotCursed(opts interface{}) *CommitStoreInterface_IsUnpausedAndNotCursed_Call {
+ return &CommitStoreInterface_IsUnpausedAndNotCursed_Call{Call: _e.mock.On("IsUnpausedAndNotCursed", opts)}
+}
+
+func (_c *CommitStoreInterface_IsUnpausedAndNotCursed_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_IsUnpausedAndNotCursed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_IsUnpausedAndNotCursed_Call) Return(_a0 bool, _a1 error) *CommitStoreInterface_IsUnpausedAndNotCursed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_IsUnpausedAndNotCursed_Call) RunAndReturn(run func(*bind.CallOpts) (bool, error)) *CommitStoreInterface_IsUnpausedAndNotCursed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfigDetails provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) LatestConfigDetails(opts *bind.CallOpts) (commit_store.LatestConfigDetails, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfigDetails")
+ }
+
+ var r0 commit_store.LatestConfigDetails
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (commit_store.LatestConfigDetails, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) commit_store.LatestConfigDetails); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(commit_store.LatestConfigDetails)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_LatestConfigDetails_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfigDetails'
+type CommitStoreInterface_LatestConfigDetails_Call struct {
+ *mock.Call
+}
+
+// LatestConfigDetails is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) LatestConfigDetails(opts interface{}) *CommitStoreInterface_LatestConfigDetails_Call {
+ return &CommitStoreInterface_LatestConfigDetails_Call{Call: _e.mock.On("LatestConfigDetails", opts)}
+}
+
+func (_c *CommitStoreInterface_LatestConfigDetails_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_LatestConfigDetails_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_LatestConfigDetails_Call) Return(_a0 commit_store.LatestConfigDetails, _a1 error) *CommitStoreInterface_LatestConfigDetails_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_LatestConfigDetails_Call) RunAndReturn(run func(*bind.CallOpts) (commit_store.LatestConfigDetails, error)) *CommitStoreInterface_LatestConfigDetails_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfigDigestAndEpoch provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (commit_store.LatestConfigDigestAndEpoch, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfigDigestAndEpoch")
+ }
+
+ var r0 commit_store.LatestConfigDigestAndEpoch
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (commit_store.LatestConfigDigestAndEpoch, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) commit_store.LatestConfigDigestAndEpoch); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(commit_store.LatestConfigDigestAndEpoch)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_LatestConfigDigestAndEpoch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfigDigestAndEpoch'
+type CommitStoreInterface_LatestConfigDigestAndEpoch_Call struct {
+ *mock.Call
+}
+
+// LatestConfigDigestAndEpoch is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) LatestConfigDigestAndEpoch(opts interface{}) *CommitStoreInterface_LatestConfigDigestAndEpoch_Call {
+ return &CommitStoreInterface_LatestConfigDigestAndEpoch_Call{Call: _e.mock.On("LatestConfigDigestAndEpoch", opts)}
+}
+
+func (_c *CommitStoreInterface_LatestConfigDigestAndEpoch_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_LatestConfigDigestAndEpoch_Call) Return(_a0 commit_store.LatestConfigDigestAndEpoch, _a1 error) *CommitStoreInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_LatestConfigDigestAndEpoch_Call) RunAndReturn(run func(*bind.CallOpts) (commit_store.LatestConfigDigestAndEpoch, error)) *CommitStoreInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Owner provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) Owner(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Owner")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_Owner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Owner'
+type CommitStoreInterface_Owner_Call struct {
+ *mock.Call
+}
+
+// Owner is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) Owner(opts interface{}) *CommitStoreInterface_Owner_Call {
+ return &CommitStoreInterface_Owner_Call{Call: _e.mock.On("Owner", opts)}
+}
+
+func (_c *CommitStoreInterface_Owner_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_Owner_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_Owner_Call) Return(_a0 common.Address, _a1 error) *CommitStoreInterface_Owner_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_Owner_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *CommitStoreInterface_Owner_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseConfigSet(log types.Log) (*commit_store.CommitStoreConfigSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet")
+ }
+
+ var r0 *commit_store.CommitStoreConfigSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreConfigSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreConfigSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreConfigSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet'
+type CommitStoreInterface_ParseConfigSet_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseConfigSet(log interface{}) *CommitStoreInterface_ParseConfigSet_Call {
+ return &CommitStoreInterface_ParseConfigSet_Call{Call: _e.mock.On("ParseConfigSet", log)}
+}
+
+func (_c *CommitStoreInterface_ParseConfigSet_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseConfigSet_Call) Return(_a0 *commit_store.CommitStoreConfigSet, _a1 error) *CommitStoreInterface_ParseConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseConfigSet_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreConfigSet, error)) *CommitStoreInterface_ParseConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet0 provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseConfigSet0(log types.Log) (*commit_store.CommitStoreConfigSet0, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet0")
+ }
+
+ var r0 *commit_store.CommitStoreConfigSet0
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreConfigSet0, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreConfigSet0); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreConfigSet0)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet0'
+type CommitStoreInterface_ParseConfigSet0_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet0 is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseConfigSet0(log interface{}) *CommitStoreInterface_ParseConfigSet0_Call {
+ return &CommitStoreInterface_ParseConfigSet0_Call{Call: _e.mock.On("ParseConfigSet0", log)}
+}
+
+func (_c *CommitStoreInterface_ParseConfigSet0_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseConfigSet0_Call) Return(_a0 *commit_store.CommitStoreConfigSet0, _a1 error) *CommitStoreInterface_ParseConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseConfigSet0_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreConfigSet0, error)) *CommitStoreInterface_ParseConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLatestPriceEpochAndRoundSet provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseLatestPriceEpochAndRoundSet(log types.Log) (*commit_store.CommitStoreLatestPriceEpochAndRoundSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLatestPriceEpochAndRoundSet")
+ }
+
+ var r0 *commit_store.CommitStoreLatestPriceEpochAndRoundSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreLatestPriceEpochAndRoundSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreLatestPriceEpochAndRoundSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreLatestPriceEpochAndRoundSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLatestPriceEpochAndRoundSet'
+type CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call struct {
+ *mock.Call
+}
+
+// ParseLatestPriceEpochAndRoundSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseLatestPriceEpochAndRoundSet(log interface{}) *CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call {
+ return &CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call{Call: _e.mock.On("ParseLatestPriceEpochAndRoundSet", log)}
+}
+
+func (_c *CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call) Return(_a0 *commit_store.CommitStoreLatestPriceEpochAndRoundSet, _a1 error) *CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreLatestPriceEpochAndRoundSet, error)) *CommitStoreInterface_ParseLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type CommitStoreInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseLog(log interface{}) *CommitStoreInterface_ParseLog_Call {
+ return &CommitStoreInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *CommitStoreInterface_ParseLog_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *CommitStoreInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *CommitStoreInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferRequested provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseOwnershipTransferRequested(log types.Log) (*commit_store.CommitStoreOwnershipTransferRequested, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferRequested")
+ }
+
+ var r0 *commit_store.CommitStoreOwnershipTransferRequested
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreOwnershipTransferRequested, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreOwnershipTransferRequested); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreOwnershipTransferRequested)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferRequested'
+type CommitStoreInterface_ParseOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferRequested is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseOwnershipTransferRequested(log interface{}) *CommitStoreInterface_ParseOwnershipTransferRequested_Call {
+ return &CommitStoreInterface_ParseOwnershipTransferRequested_Call{Call: _e.mock.On("ParseOwnershipTransferRequested", log)}
+}
+
+func (_c *CommitStoreInterface_ParseOwnershipTransferRequested_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseOwnershipTransferRequested_Call) Return(_a0 *commit_store.CommitStoreOwnershipTransferRequested, _a1 error) *CommitStoreInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseOwnershipTransferRequested_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreOwnershipTransferRequested, error)) *CommitStoreInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferred provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseOwnershipTransferred(log types.Log) (*commit_store.CommitStoreOwnershipTransferred, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferred")
+ }
+
+ var r0 *commit_store.CommitStoreOwnershipTransferred
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreOwnershipTransferred, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreOwnershipTransferred); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreOwnershipTransferred)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferred'
+type CommitStoreInterface_ParseOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferred is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseOwnershipTransferred(log interface{}) *CommitStoreInterface_ParseOwnershipTransferred_Call {
+ return &CommitStoreInterface_ParseOwnershipTransferred_Call{Call: _e.mock.On("ParseOwnershipTransferred", log)}
+}
+
+func (_c *CommitStoreInterface_ParseOwnershipTransferred_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseOwnershipTransferred_Call) Return(_a0 *commit_store.CommitStoreOwnershipTransferred, _a1 error) *CommitStoreInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseOwnershipTransferred_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreOwnershipTransferred, error)) *CommitStoreInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePaused provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParsePaused(log types.Log) (*commit_store.CommitStorePaused, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePaused")
+ }
+
+ var r0 *commit_store.CommitStorePaused
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStorePaused, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStorePaused); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStorePaused)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParsePaused_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePaused'
+type CommitStoreInterface_ParsePaused_Call struct {
+ *mock.Call
+}
+
+// ParsePaused is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParsePaused(log interface{}) *CommitStoreInterface_ParsePaused_Call {
+ return &CommitStoreInterface_ParsePaused_Call{Call: _e.mock.On("ParsePaused", log)}
+}
+
+func (_c *CommitStoreInterface_ParsePaused_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParsePaused_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParsePaused_Call) Return(_a0 *commit_store.CommitStorePaused, _a1 error) *CommitStoreInterface_ParsePaused_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParsePaused_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStorePaused, error)) *CommitStoreInterface_ParsePaused_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseReportAccepted provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseReportAccepted(log types.Log) (*commit_store.CommitStoreReportAccepted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseReportAccepted")
+ }
+
+ var r0 *commit_store.CommitStoreReportAccepted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreReportAccepted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreReportAccepted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreReportAccepted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseReportAccepted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseReportAccepted'
+type CommitStoreInterface_ParseReportAccepted_Call struct {
+ *mock.Call
+}
+
+// ParseReportAccepted is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseReportAccepted(log interface{}) *CommitStoreInterface_ParseReportAccepted_Call {
+ return &CommitStoreInterface_ParseReportAccepted_Call{Call: _e.mock.On("ParseReportAccepted", log)}
+}
+
+func (_c *CommitStoreInterface_ParseReportAccepted_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseReportAccepted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseReportAccepted_Call) Return(_a0 *commit_store.CommitStoreReportAccepted, _a1 error) *CommitStoreInterface_ParseReportAccepted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseReportAccepted_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreReportAccepted, error)) *CommitStoreInterface_ParseReportAccepted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseRootRemoved provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseRootRemoved(log types.Log) (*commit_store.CommitStoreRootRemoved, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseRootRemoved")
+ }
+
+ var r0 *commit_store.CommitStoreRootRemoved
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreRootRemoved, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreRootRemoved); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreRootRemoved)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseRootRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseRootRemoved'
+type CommitStoreInterface_ParseRootRemoved_Call struct {
+ *mock.Call
+}
+
+// ParseRootRemoved is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseRootRemoved(log interface{}) *CommitStoreInterface_ParseRootRemoved_Call {
+ return &CommitStoreInterface_ParseRootRemoved_Call{Call: _e.mock.On("ParseRootRemoved", log)}
+}
+
+func (_c *CommitStoreInterface_ParseRootRemoved_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseRootRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseRootRemoved_Call) Return(_a0 *commit_store.CommitStoreRootRemoved, _a1 error) *CommitStoreInterface_ParseRootRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseRootRemoved_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreRootRemoved, error)) *CommitStoreInterface_ParseRootRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSequenceNumberSet provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseSequenceNumberSet(log types.Log) (*commit_store.CommitStoreSequenceNumberSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSequenceNumberSet")
+ }
+
+ var r0 *commit_store.CommitStoreSequenceNumberSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreSequenceNumberSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreSequenceNumberSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreSequenceNumberSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseSequenceNumberSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSequenceNumberSet'
+type CommitStoreInterface_ParseSequenceNumberSet_Call struct {
+ *mock.Call
+}
+
+// ParseSequenceNumberSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseSequenceNumberSet(log interface{}) *CommitStoreInterface_ParseSequenceNumberSet_Call {
+ return &CommitStoreInterface_ParseSequenceNumberSet_Call{Call: _e.mock.On("ParseSequenceNumberSet", log)}
+}
+
+func (_c *CommitStoreInterface_ParseSequenceNumberSet_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseSequenceNumberSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseSequenceNumberSet_Call) Return(_a0 *commit_store.CommitStoreSequenceNumberSet, _a1 error) *CommitStoreInterface_ParseSequenceNumberSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseSequenceNumberSet_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreSequenceNumberSet, error)) *CommitStoreInterface_ParseSequenceNumberSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTransmitted provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseTransmitted(log types.Log) (*commit_store.CommitStoreTransmitted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTransmitted")
+ }
+
+ var r0 *commit_store.CommitStoreTransmitted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreTransmitted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreTransmitted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreTransmitted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTransmitted'
+type CommitStoreInterface_ParseTransmitted_Call struct {
+ *mock.Call
+}
+
+// ParseTransmitted is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseTransmitted(log interface{}) *CommitStoreInterface_ParseTransmitted_Call {
+ return &CommitStoreInterface_ParseTransmitted_Call{Call: _e.mock.On("ParseTransmitted", log)}
+}
+
+func (_c *CommitStoreInterface_ParseTransmitted_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseTransmitted_Call) Return(_a0 *commit_store.CommitStoreTransmitted, _a1 error) *CommitStoreInterface_ParseTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseTransmitted_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreTransmitted, error)) *CommitStoreInterface_ParseTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseUnpaused provides a mock function with given fields: log
+func (_m *CommitStoreInterface) ParseUnpaused(log types.Log) (*commit_store.CommitStoreUnpaused, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseUnpaused")
+ }
+
+ var r0 *commit_store.CommitStoreUnpaused
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*commit_store.CommitStoreUnpaused, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *commit_store.CommitStoreUnpaused); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*commit_store.CommitStoreUnpaused)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ParseUnpaused_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseUnpaused'
+type CommitStoreInterface_ParseUnpaused_Call struct {
+ *mock.Call
+}
+
+// ParseUnpaused is a helper method to define mock.On call
+// - log types.Log
+func (_e *CommitStoreInterface_Expecter) ParseUnpaused(log interface{}) *CommitStoreInterface_ParseUnpaused_Call {
+ return &CommitStoreInterface_ParseUnpaused_Call{Call: _e.mock.On("ParseUnpaused", log)}
+}
+
+func (_c *CommitStoreInterface_ParseUnpaused_Call) Run(run func(log types.Log)) *CommitStoreInterface_ParseUnpaused_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseUnpaused_Call) Return(_a0 *commit_store.CommitStoreUnpaused, _a1 error) *CommitStoreInterface_ParseUnpaused_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ParseUnpaused_Call) RunAndReturn(run func(types.Log) (*commit_store.CommitStoreUnpaused, error)) *CommitStoreInterface_ParseUnpaused_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Pause provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Pause")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_Pause_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pause'
+type CommitStoreInterface_Pause_Call struct {
+ *mock.Call
+}
+
+// Pause is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *CommitStoreInterface_Expecter) Pause(opts interface{}) *CommitStoreInterface_Pause_Call {
+ return &CommitStoreInterface_Pause_Call{Call: _e.mock.On("Pause", opts)}
+}
+
+func (_c *CommitStoreInterface_Pause_Call) Run(run func(opts *bind.TransactOpts)) *CommitStoreInterface_Pause_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_Pause_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_Pause_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_Pause_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *CommitStoreInterface_Pause_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Paused provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) Paused(opts *bind.CallOpts) (bool, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Paused")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) bool); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_Paused_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Paused'
+type CommitStoreInterface_Paused_Call struct {
+ *mock.Call
+}
+
+// Paused is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) Paused(opts interface{}) *CommitStoreInterface_Paused_Call {
+ return &CommitStoreInterface_Paused_Call{Call: _e.mock.On("Paused", opts)}
+}
+
+func (_c *CommitStoreInterface_Paused_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_Paused_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_Paused_Call) Return(_a0 bool, _a1 error) *CommitStoreInterface_Paused_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_Paused_Call) RunAndReturn(run func(*bind.CallOpts) (bool, error)) *CommitStoreInterface_Paused_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ResetUnblessedRoots provides a mock function with given fields: opts, rootToReset
+func (_m *CommitStoreInterface) ResetUnblessedRoots(opts *bind.TransactOpts, rootToReset [][32]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, rootToReset)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ResetUnblessedRoots")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [][32]byte) (*types.Transaction, error)); ok {
+ return rf(opts, rootToReset)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [][32]byte) *types.Transaction); ok {
+ r0 = rf(opts, rootToReset)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [][32]byte) error); ok {
+ r1 = rf(opts, rootToReset)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_ResetUnblessedRoots_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResetUnblessedRoots'
+type CommitStoreInterface_ResetUnblessedRoots_Call struct {
+ *mock.Call
+}
+
+// ResetUnblessedRoots is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - rootToReset [][32]byte
+func (_e *CommitStoreInterface_Expecter) ResetUnblessedRoots(opts interface{}, rootToReset interface{}) *CommitStoreInterface_ResetUnblessedRoots_Call {
+ return &CommitStoreInterface_ResetUnblessedRoots_Call{Call: _e.mock.On("ResetUnblessedRoots", opts, rootToReset)}
+}
+
+func (_c *CommitStoreInterface_ResetUnblessedRoots_Call) Run(run func(opts *bind.TransactOpts, rootToReset [][32]byte)) *CommitStoreInterface_ResetUnblessedRoots_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_ResetUnblessedRoots_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_ResetUnblessedRoots_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_ResetUnblessedRoots_Call) RunAndReturn(run func(*bind.TransactOpts, [][32]byte) (*types.Transaction, error)) *CommitStoreInterface_ResetUnblessedRoots_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetLatestPriceEpochAndRound provides a mock function with given fields: opts, latestPriceEpochAndRound
+func (_m *CommitStoreInterface) SetLatestPriceEpochAndRound(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, latestPriceEpochAndRound)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetLatestPriceEpochAndRound")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, latestPriceEpochAndRound)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int) *types.Transaction); ok {
+ r0 = rf(opts, latestPriceEpochAndRound)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int) error); ok {
+ r1 = rf(opts, latestPriceEpochAndRound)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_SetLatestPriceEpochAndRound_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetLatestPriceEpochAndRound'
+type CommitStoreInterface_SetLatestPriceEpochAndRound_Call struct {
+ *mock.Call
+}
+
+// SetLatestPriceEpochAndRound is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - latestPriceEpochAndRound *big.Int
+func (_e *CommitStoreInterface_Expecter) SetLatestPriceEpochAndRound(opts interface{}, latestPriceEpochAndRound interface{}) *CommitStoreInterface_SetLatestPriceEpochAndRound_Call {
+ return &CommitStoreInterface_SetLatestPriceEpochAndRound_Call{Call: _e.mock.On("SetLatestPriceEpochAndRound", opts, latestPriceEpochAndRound)}
+}
+
+func (_c *CommitStoreInterface_SetLatestPriceEpochAndRound_Call) Run(run func(opts *bind.TransactOpts, latestPriceEpochAndRound *big.Int)) *CommitStoreInterface_SetLatestPriceEpochAndRound_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_SetLatestPriceEpochAndRound_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_SetLatestPriceEpochAndRound_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_SetLatestPriceEpochAndRound_Call) RunAndReturn(run func(*bind.TransactOpts, *big.Int) (*types.Transaction, error)) *CommitStoreInterface_SetLatestPriceEpochAndRound_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetMinSeqNr provides a mock function with given fields: opts, minSeqNr
+func (_m *CommitStoreInterface) SetMinSeqNr(opts *bind.TransactOpts, minSeqNr uint64) (*types.Transaction, error) {
+ ret := _m.Called(opts, minSeqNr)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetMinSeqNr")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64) (*types.Transaction, error)); ok {
+ return rf(opts, minSeqNr)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64) *types.Transaction); ok {
+ r0 = rf(opts, minSeqNr)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, uint64) error); ok {
+ r1 = rf(opts, minSeqNr)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_SetMinSeqNr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetMinSeqNr'
+type CommitStoreInterface_SetMinSeqNr_Call struct {
+ *mock.Call
+}
+
+// SetMinSeqNr is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - minSeqNr uint64
+func (_e *CommitStoreInterface_Expecter) SetMinSeqNr(opts interface{}, minSeqNr interface{}) *CommitStoreInterface_SetMinSeqNr_Call {
+ return &CommitStoreInterface_SetMinSeqNr_Call{Call: _e.mock.On("SetMinSeqNr", opts, minSeqNr)}
+}
+
+func (_c *CommitStoreInterface_SetMinSeqNr_Call) Run(run func(opts *bind.TransactOpts, minSeqNr uint64)) *CommitStoreInterface_SetMinSeqNr_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_SetMinSeqNr_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_SetMinSeqNr_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_SetMinSeqNr_Call) RunAndReturn(run func(*bind.TransactOpts, uint64) (*types.Transaction, error)) *CommitStoreInterface_SetMinSeqNr_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetOCR2Config provides a mock function with given fields: opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig
+func (_m *CommitStoreInterface) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetOCR2Config")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) *types.Transaction); ok {
+ r0 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) error); ok {
+ r1 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_SetOCR2Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetOCR2Config'
+type CommitStoreInterface_SetOCR2Config_Call struct {
+ *mock.Call
+}
+
+// SetOCR2Config is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - signers []common.Address
+// - transmitters []common.Address
+// - f uint8
+// - onchainConfig []byte
+// - offchainConfigVersion uint64
+// - offchainConfig []byte
+func (_e *CommitStoreInterface_Expecter) SetOCR2Config(opts interface{}, signers interface{}, transmitters interface{}, f interface{}, onchainConfig interface{}, offchainConfigVersion interface{}, offchainConfig interface{}) *CommitStoreInterface_SetOCR2Config_Call {
+ return &CommitStoreInterface_SetOCR2Config_Call{Call: _e.mock.On("SetOCR2Config", opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)}
+}
+
+func (_c *CommitStoreInterface_SetOCR2Config_Call) Run(run func(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte)) *CommitStoreInterface_SetOCR2Config_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].(uint8), args[4].([]byte), args[5].(uint64), args[6].([]byte))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_SetOCR2Config_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_SetOCR2Config_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_SetOCR2Config_Call) RunAndReturn(run func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)) *CommitStoreInterface_SetOCR2Config_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TransferOwnership provides a mock function with given fields: opts, to
+func (_m *CommitStoreInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TransferOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_TransferOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferOwnership'
+type CommitStoreInterface_TransferOwnership_Call struct {
+ *mock.Call
+}
+
+// TransferOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - to common.Address
+func (_e *CommitStoreInterface_Expecter) TransferOwnership(opts interface{}, to interface{}) *CommitStoreInterface_TransferOwnership_Call {
+ return &CommitStoreInterface_TransferOwnership_Call{Call: _e.mock.On("TransferOwnership", opts, to)}
+}
+
+func (_c *CommitStoreInterface_TransferOwnership_Call) Run(run func(opts *bind.TransactOpts, to common.Address)) *CommitStoreInterface_TransferOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_TransferOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_TransferOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_TransferOwnership_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *CommitStoreInterface_TransferOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Transmit provides a mock function with given fields: opts, reportContext, report, rs, ss, rawVs
+func (_m *CommitStoreInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, reportContext, report, rs, ss, rawVs)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Transmit")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok {
+ return rf(opts, reportContext, report, rs, ss, rawVs)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) *types.Transaction); ok {
+ r0 = rf(opts, reportContext, report, rs, ss, rawVs)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) error); ok {
+ r1 = rf(opts, reportContext, report, rs, ss, rawVs)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_Transmit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Transmit'
+type CommitStoreInterface_Transmit_Call struct {
+ *mock.Call
+}
+
+// Transmit is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - reportContext [3][32]byte
+// - report []byte
+// - rs [][32]byte
+// - ss [][32]byte
+// - rawVs [32]byte
+func (_e *CommitStoreInterface_Expecter) Transmit(opts interface{}, reportContext interface{}, report interface{}, rs interface{}, ss interface{}, rawVs interface{}) *CommitStoreInterface_Transmit_Call {
+ return &CommitStoreInterface_Transmit_Call{Call: _e.mock.On("Transmit", opts, reportContext, report, rs, ss, rawVs)}
+}
+
+func (_c *CommitStoreInterface_Transmit_Call) Run(run func(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte)) *CommitStoreInterface_Transmit_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([3][32]byte), args[2].([]byte), args[3].([][32]byte), args[4].([][32]byte), args[5].([32]byte))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_Transmit_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_Transmit_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_Transmit_Call) RunAndReturn(run func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)) *CommitStoreInterface_Transmit_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TypeAndVersion provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TypeAndVersion")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_TypeAndVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TypeAndVersion'
+type CommitStoreInterface_TypeAndVersion_Call struct {
+ *mock.Call
+}
+
+// TypeAndVersion is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *CommitStoreInterface_Expecter) TypeAndVersion(opts interface{}) *CommitStoreInterface_TypeAndVersion_Call {
+ return &CommitStoreInterface_TypeAndVersion_Call{Call: _e.mock.On("TypeAndVersion", opts)}
+}
+
+func (_c *CommitStoreInterface_TypeAndVersion_Call) Run(run func(opts *bind.CallOpts)) *CommitStoreInterface_TypeAndVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_TypeAndVersion_Call) Return(_a0 string, _a1 error) *CommitStoreInterface_TypeAndVersion_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_TypeAndVersion_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *CommitStoreInterface_TypeAndVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Unpause provides a mock function with given fields: opts
+func (_m *CommitStoreInterface) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Unpause")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_Unpause_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unpause'
+type CommitStoreInterface_Unpause_Call struct {
+ *mock.Call
+}
+
+// Unpause is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *CommitStoreInterface_Expecter) Unpause(opts interface{}) *CommitStoreInterface_Unpause_Call {
+ return &CommitStoreInterface_Unpause_Call{Call: _e.mock.On("Unpause", opts)}
+}
+
+func (_c *CommitStoreInterface_Unpause_Call) Run(run func(opts *bind.TransactOpts)) *CommitStoreInterface_Unpause_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_Unpause_Call) Return(_a0 *types.Transaction, _a1 error) *CommitStoreInterface_Unpause_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_Unpause_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *CommitStoreInterface_Unpause_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Verify provides a mock function with given fields: opts, hashedLeaves, proofs, proofFlagBits
+func (_m *CommitStoreInterface) Verify(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int) (*big.Int, error) {
+ ret := _m.Called(opts, hashedLeaves, proofs, proofFlagBits)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Verify")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, [][32]byte, [][32]byte, *big.Int) (*big.Int, error)); ok {
+ return rf(opts, hashedLeaves, proofs, proofFlagBits)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, [][32]byte, [][32]byte, *big.Int) *big.Int); ok {
+ r0 = rf(opts, hashedLeaves, proofs, proofFlagBits)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, [][32]byte, [][32]byte, *big.Int) error); ok {
+ r1 = rf(opts, hashedLeaves, proofs, proofFlagBits)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_Verify_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Verify'
+type CommitStoreInterface_Verify_Call struct {
+ *mock.Call
+}
+
+// Verify is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - hashedLeaves [][32]byte
+// - proofs [][32]byte
+// - proofFlagBits *big.Int
+func (_e *CommitStoreInterface_Expecter) Verify(opts interface{}, hashedLeaves interface{}, proofs interface{}, proofFlagBits interface{}) *CommitStoreInterface_Verify_Call {
+ return &CommitStoreInterface_Verify_Call{Call: _e.mock.On("Verify", opts, hashedLeaves, proofs, proofFlagBits)}
+}
+
+func (_c *CommitStoreInterface_Verify_Call) Run(run func(opts *bind.CallOpts, hashedLeaves [][32]byte, proofs [][32]byte, proofFlagBits *big.Int)) *CommitStoreInterface_Verify_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].([][32]byte), args[2].([][32]byte), args[3].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_Verify_Call) Return(_a0 *big.Int, _a1 error) *CommitStoreInterface_Verify_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_Verify_Call) RunAndReturn(run func(*bind.CallOpts, [][32]byte, [][32]byte, *big.Int) (*big.Int, error)) *CommitStoreInterface_Verify_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreConfigSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet'
+type CommitStoreInterface_WatchConfigSet_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreConfigSet
+func (_e *CommitStoreInterface_Expecter) WatchConfigSet(opts interface{}, sink interface{}) *CommitStoreInterface_WatchConfigSet_Call {
+ return &CommitStoreInterface_WatchConfigSet_Call{Call: _e.mock.On("WatchConfigSet", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchConfigSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreConfigSet)) *CommitStoreInterface_WatchConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreConfigSet))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchConfigSet_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchConfigSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet) (event.Subscription, error)) *CommitStoreInterface_WatchConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet0 provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreConfigSet0) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet0")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet0) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet0) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet0) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet0'
+type CommitStoreInterface_WatchConfigSet0_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet0 is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreConfigSet0
+func (_e *CommitStoreInterface_Expecter) WatchConfigSet0(opts interface{}, sink interface{}) *CommitStoreInterface_WatchConfigSet0_Call {
+ return &CommitStoreInterface_WatchConfigSet0_Call{Call: _e.mock.On("WatchConfigSet0", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchConfigSet0_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreConfigSet0)) *CommitStoreInterface_WatchConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreConfigSet0))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchConfigSet0_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchConfigSet0_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreConfigSet0) (event.Subscription, error)) *CommitStoreInterface_WatchConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchLatestPriceEpochAndRoundSet provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchLatestPriceEpochAndRoundSet(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreLatestPriceEpochAndRoundSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchLatestPriceEpochAndRoundSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreLatestPriceEpochAndRoundSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreLatestPriceEpochAndRoundSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreLatestPriceEpochAndRoundSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchLatestPriceEpochAndRoundSet'
+type CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call struct {
+ *mock.Call
+}
+
+// WatchLatestPriceEpochAndRoundSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreLatestPriceEpochAndRoundSet
+func (_e *CommitStoreInterface_Expecter) WatchLatestPriceEpochAndRoundSet(opts interface{}, sink interface{}) *CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call {
+ return &CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call{Call: _e.mock.On("WatchLatestPriceEpochAndRoundSet", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreLatestPriceEpochAndRoundSet)) *CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreLatestPriceEpochAndRoundSet))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreLatestPriceEpochAndRoundSet) (event.Subscription, error)) *CommitStoreInterface_WatchLatestPriceEpochAndRoundSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to
+func (_m *CommitStoreInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferRequested")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferRequested, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferRequested'
+type CommitStoreInterface_WatchOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreOwnershipTransferRequested
+// - from []common.Address
+// - to []common.Address
+func (_e *CommitStoreInterface_Expecter) WatchOwnershipTransferRequested(opts interface{}, sink interface{}, from interface{}, to interface{}) *CommitStoreInterface_WatchOwnershipTransferRequested_Call {
+ return &CommitStoreInterface_WatchOwnershipTransferRequested_Call{Call: _e.mock.On("WatchOwnershipTransferRequested", opts, sink, from, to)}
+}
+
+func (_c *CommitStoreInterface_WatchOwnershipTransferRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreOwnershipTransferRequested, from []common.Address, to []common.Address)) *CommitStoreInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreOwnershipTransferRequested), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchOwnershipTransferRequested_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)) *CommitStoreInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to
+func (_m *CommitStoreInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferred")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferred, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferred'
+type CommitStoreInterface_WatchOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreOwnershipTransferred
+// - from []common.Address
+// - to []common.Address
+func (_e *CommitStoreInterface_Expecter) WatchOwnershipTransferred(opts interface{}, sink interface{}, from interface{}, to interface{}) *CommitStoreInterface_WatchOwnershipTransferred_Call {
+ return &CommitStoreInterface_WatchOwnershipTransferred_Call{Call: _e.mock.On("WatchOwnershipTransferred", opts, sink, from, to)}
+}
+
+func (_c *CommitStoreInterface_WatchOwnershipTransferred_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreOwnershipTransferred, from []common.Address, to []common.Address)) *CommitStoreInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreOwnershipTransferred), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchOwnershipTransferred_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchOwnershipTransferred_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)) *CommitStoreInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPaused provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchPaused(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStorePaused) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPaused")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStorePaused) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStorePaused) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStorePaused) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchPaused_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPaused'
+type CommitStoreInterface_WatchPaused_Call struct {
+ *mock.Call
+}
+
+// WatchPaused is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStorePaused
+func (_e *CommitStoreInterface_Expecter) WatchPaused(opts interface{}, sink interface{}) *CommitStoreInterface_WatchPaused_Call {
+ return &CommitStoreInterface_WatchPaused_Call{Call: _e.mock.On("WatchPaused", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchPaused_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStorePaused)) *CommitStoreInterface_WatchPaused_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStorePaused))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchPaused_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchPaused_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchPaused_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStorePaused) (event.Subscription, error)) *CommitStoreInterface_WatchPaused_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchReportAccepted provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchReportAccepted(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreReportAccepted) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchReportAccepted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreReportAccepted) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreReportAccepted) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreReportAccepted) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchReportAccepted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchReportAccepted'
+type CommitStoreInterface_WatchReportAccepted_Call struct {
+ *mock.Call
+}
+
+// WatchReportAccepted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreReportAccepted
+func (_e *CommitStoreInterface_Expecter) WatchReportAccepted(opts interface{}, sink interface{}) *CommitStoreInterface_WatchReportAccepted_Call {
+ return &CommitStoreInterface_WatchReportAccepted_Call{Call: _e.mock.On("WatchReportAccepted", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchReportAccepted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreReportAccepted)) *CommitStoreInterface_WatchReportAccepted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreReportAccepted))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchReportAccepted_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchReportAccepted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchReportAccepted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreReportAccepted) (event.Subscription, error)) *CommitStoreInterface_WatchReportAccepted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchRootRemoved provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchRootRemoved(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreRootRemoved) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchRootRemoved")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreRootRemoved) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreRootRemoved) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreRootRemoved) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchRootRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchRootRemoved'
+type CommitStoreInterface_WatchRootRemoved_Call struct {
+ *mock.Call
+}
+
+// WatchRootRemoved is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreRootRemoved
+func (_e *CommitStoreInterface_Expecter) WatchRootRemoved(opts interface{}, sink interface{}) *CommitStoreInterface_WatchRootRemoved_Call {
+ return &CommitStoreInterface_WatchRootRemoved_Call{Call: _e.mock.On("WatchRootRemoved", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchRootRemoved_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreRootRemoved)) *CommitStoreInterface_WatchRootRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreRootRemoved))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchRootRemoved_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchRootRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchRootRemoved_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreRootRemoved) (event.Subscription, error)) *CommitStoreInterface_WatchRootRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSequenceNumberSet provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchSequenceNumberSet(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreSequenceNumberSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSequenceNumberSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreSequenceNumberSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreSequenceNumberSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreSequenceNumberSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchSequenceNumberSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSequenceNumberSet'
+type CommitStoreInterface_WatchSequenceNumberSet_Call struct {
+ *mock.Call
+}
+
+// WatchSequenceNumberSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreSequenceNumberSet
+func (_e *CommitStoreInterface_Expecter) WatchSequenceNumberSet(opts interface{}, sink interface{}) *CommitStoreInterface_WatchSequenceNumberSet_Call {
+ return &CommitStoreInterface_WatchSequenceNumberSet_Call{Call: _e.mock.On("WatchSequenceNumberSet", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchSequenceNumberSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreSequenceNumberSet)) *CommitStoreInterface_WatchSequenceNumberSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreSequenceNumberSet))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchSequenceNumberSet_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchSequenceNumberSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchSequenceNumberSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreSequenceNumberSet) (event.Subscription, error)) *CommitStoreInterface_WatchSequenceNumberSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTransmitted provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreTransmitted) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTransmitted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreTransmitted) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreTransmitted) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreTransmitted) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTransmitted'
+type CommitStoreInterface_WatchTransmitted_Call struct {
+ *mock.Call
+}
+
+// WatchTransmitted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreTransmitted
+func (_e *CommitStoreInterface_Expecter) WatchTransmitted(opts interface{}, sink interface{}) *CommitStoreInterface_WatchTransmitted_Call {
+ return &CommitStoreInterface_WatchTransmitted_Call{Call: _e.mock.On("WatchTransmitted", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchTransmitted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreTransmitted)) *CommitStoreInterface_WatchTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreTransmitted))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchTransmitted_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchTransmitted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreTransmitted) (event.Subscription, error)) *CommitStoreInterface_WatchTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchUnpaused provides a mock function with given fields: opts, sink
+func (_m *CommitStoreInterface) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreUnpaused) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchUnpaused")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreUnpaused) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreUnpaused) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *commit_store.CommitStoreUnpaused) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreInterface_WatchUnpaused_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchUnpaused'
+type CommitStoreInterface_WatchUnpaused_Call struct {
+ *mock.Call
+}
+
+// WatchUnpaused is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *commit_store.CommitStoreUnpaused
+func (_e *CommitStoreInterface_Expecter) WatchUnpaused(opts interface{}, sink interface{}) *CommitStoreInterface_WatchUnpaused_Call {
+ return &CommitStoreInterface_WatchUnpaused_Call{Call: _e.mock.On("WatchUnpaused", opts, sink)}
+}
+
+func (_c *CommitStoreInterface_WatchUnpaused_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *commit_store.CommitStoreUnpaused)) *CommitStoreInterface_WatchUnpaused_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *commit_store.CommitStoreUnpaused))
+ })
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchUnpaused_Call) Return(_a0 event.Subscription, _a1 error) *CommitStoreInterface_WatchUnpaused_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreInterface_WatchUnpaused_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *commit_store.CommitStoreUnpaused) (event.Subscription, error)) *CommitStoreInterface_WatchUnpaused_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewCommitStoreInterface creates a new instance of CommitStoreInterface. 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 NewCommitStoreInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *CommitStoreInterface {
+ mock := &CommitStoreInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/ccip/mocks/evm2_evm_off_ramp_interface.go b/core/gethwrappers/ccip/mocks/evm2_evm_off_ramp_interface.go
new file mode 100644
index 00000000000..6da66583e6e
--- /dev/null
+++ b/core/gethwrappers/ccip/mocks/evm2_evm_off_ramp_interface.go
@@ -0,0 +1,3893 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_contracts
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ evm_2_evm_offramp "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// EVM2EVMOffRampInterface is an autogenerated mock type for the EVM2EVMOffRampInterface type
+type EVM2EVMOffRampInterface struct {
+ mock.Mock
+}
+
+type EVM2EVMOffRampInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *EVM2EVMOffRampInterface) EXPECT() *EVM2EVMOffRampInterface_Expecter {
+ return &EVM2EVMOffRampInterface_Expecter{mock: &_m.Mock}
+}
+
+// AcceptOwnership provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AcceptOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_AcceptOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptOwnership'
+type EVM2EVMOffRampInterface_AcceptOwnership_Call struct {
+ *mock.Call
+}
+
+// AcceptOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) AcceptOwnership(opts interface{}) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ return &EVM2EVMOffRampInterface_AcceptOwnership_Call{Call: _e.mock.On("AcceptOwnership", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) Run(run func(opts *bind.TransactOpts)) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Address provides a mock function with given fields:
+func (_m *EVM2EVMOffRampInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// EVM2EVMOffRampInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type EVM2EVMOffRampInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *EVM2EVMOffRampInterface_Expecter) Address() *EVM2EVMOffRampInterface_Address_Call {
+ return &EVM2EVMOffRampInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) Run(run func()) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) Return(_a0 common.Address) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) RunAndReturn(run func() common.Address) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CcipReceive provides a mock function with given fields: opts, arg0
+func (_m *EVM2EVMOffRampInterface) CcipReceive(opts *bind.CallOpts, arg0 evm_2_evm_offramp.ClientAny2EVMMessage) error {
+ ret := _m.Called(opts, arg0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CcipReceive")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, evm_2_evm_offramp.ClientAny2EVMMessage) error); ok {
+ r0 = rf(opts, arg0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// EVM2EVMOffRampInterface_CcipReceive_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CcipReceive'
+type EVM2EVMOffRampInterface_CcipReceive_Call struct {
+ *mock.Call
+}
+
+// CcipReceive is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - arg0 evm_2_evm_offramp.ClientAny2EVMMessage
+func (_e *EVM2EVMOffRampInterface_Expecter) CcipReceive(opts interface{}, arg0 interface{}) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ return &EVM2EVMOffRampInterface_CcipReceive_Call{Call: _e.mock.On("CcipReceive", opts, arg0)}
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) Run(run func(opts *bind.CallOpts, arg0 evm_2_evm_offramp.ClientAny2EVMMessage)) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(evm_2_evm_offramp.ClientAny2EVMMessage))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) Return(_a0 error) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) RunAndReturn(run func(*bind.CallOpts, evm_2_evm_offramp.ClientAny2EVMMessage) error) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CurrentRateLimiterState provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) CurrentRateLimiterState(opts *bind.CallOpts) (evm_2_evm_offramp.RateLimiterTokenBucket, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CurrentRateLimiterState")
+ }
+
+ var r0 evm_2_evm_offramp.RateLimiterTokenBucket
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.RateLimiterTokenBucket, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp.RateLimiterTokenBucket); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp.RateLimiterTokenBucket)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_CurrentRateLimiterState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CurrentRateLimiterState'
+type EVM2EVMOffRampInterface_CurrentRateLimiterState_Call struct {
+ *mock.Call
+}
+
+// CurrentRateLimiterState is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) CurrentRateLimiterState(opts interface{}) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ return &EVM2EVMOffRampInterface_CurrentRateLimiterState_Call{Call: _e.mock.On("CurrentRateLimiterState", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) Return(_a0 evm_2_evm_offramp.RateLimiterTokenBucket, _a1 error) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp.RateLimiterTokenBucket, error)) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ExecuteSingleMessage provides a mock function with given fields: opts, message, offchainTokenData
+func (_m *EVM2EVMOffRampInterface) ExecuteSingleMessage(opts *bind.TransactOpts, message evm_2_evm_offramp.InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, message, offchainTokenData)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExecuteSingleMessage")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.InternalEVM2EVMMessage, [][]byte) (*types.Transaction, error)); ok {
+ return rf(opts, message, offchainTokenData)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.InternalEVM2EVMMessage, [][]byte) *types.Transaction); ok {
+ r0 = rf(opts, message, offchainTokenData)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp.InternalEVM2EVMMessage, [][]byte) error); ok {
+ r1 = rf(opts, message, offchainTokenData)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ExecuteSingleMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExecuteSingleMessage'
+type EVM2EVMOffRampInterface_ExecuteSingleMessage_Call struct {
+ *mock.Call
+}
+
+// ExecuteSingleMessage is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - message evm_2_evm_offramp.InternalEVM2EVMMessage
+// - offchainTokenData [][]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) ExecuteSingleMessage(opts interface{}, message interface{}, offchainTokenData interface{}) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ return &EVM2EVMOffRampInterface_ExecuteSingleMessage_Call{Call: _e.mock.On("ExecuteSingleMessage", opts, message, offchainTokenData)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) Run(run func(opts *bind.TransactOpts, message evm_2_evm_offramp.InternalEVM2EVMMessage, offchainTokenData [][]byte)) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp.InternalEVM2EVMMessage), args[2].([][]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp.InternalEVM2EVMMessage, [][]byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterAdminSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterAdminSet(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterAdminSet")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterAdminSet'
+type EVM2EVMOffRampInterface_FilterAdminSet_Call struct {
+ *mock.Call
+}
+
+// FilterAdminSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterAdminSet(opts interface{}) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ return &EVM2EVMOffRampInterface_FilterAdminSet_Call{Call: _e.mock.On("FilterAdminSet", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator, _a1 error) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSetIterator, error)) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigChanged provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterConfigChanged(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigChangedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigChanged")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigChangedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigChangedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp.EVM2EVMOffRampConfigChangedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampConfigChangedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterConfigChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigChanged'
+type EVM2EVMOffRampInterface_FilterConfigChanged_Call struct {
+ *mock.Call
+}
+
+// FilterConfigChanged is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterConfigChanged(opts interface{}) *EVM2EVMOffRampInterface_FilterConfigChanged_Call {
+ return &EVM2EVMOffRampInterface_FilterConfigChanged_Call{Call: _e.mock.On("FilterConfigChanged", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigChanged_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterConfigChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigChanged_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampConfigChangedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterConfigChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigChanged_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigChangedIterator, error)) *EVM2EVMOffRampInterface_FilterConfigChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterConfigSet(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet'
+type EVM2EVMOffRampInterface_FilterConfigSet_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterConfigSet(opts interface{}) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ return &EVM2EVMOffRampInterface_FilterConfigSet_Call{Call: _e.mock.On("FilterConfigSet", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator, _a1 error) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSetIterator, error)) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet0 provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterConfigSet0(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet0")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet0'
+type EVM2EVMOffRampInterface_FilterConfigSet0_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet0 is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterConfigSet0(opts interface{}) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_FilterConfigSet0_Call{Call: _e.mock.On("FilterConfigSet0", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator, _a1 error) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0Iterator, error)) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterExecutionStateChanged provides a mock function with given fields: opts, sequenceNumber, messageId
+func (_m *EVM2EVMOffRampInterface) FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator, error) {
+ ret := _m.Called(opts, sequenceNumber, messageId)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterExecutionStateChanged")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator, error)); ok {
+ return rf(opts, sequenceNumber, messageId)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte) *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator); ok {
+ r0 = rf(opts, sequenceNumber, messageId)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, [][32]byte) error); ok {
+ r1 = rf(opts, sequenceNumber, messageId)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterExecutionStateChanged'
+type EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// FilterExecutionStateChanged is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - sequenceNumber []uint64
+// - messageId [][32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterExecutionStateChanged(opts interface{}, sequenceNumber interface{}, messageId interface{}) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call{Call: _e.mock.On("FilterExecutionStateChanged", opts, sequenceNumber, messageId)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) Run(run func(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte)) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, [][32]byte) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChangedIterator, error)) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to
+func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferRequested")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterOwnershipTransferRequested(opts interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call{Call: _e.mock.On("FilterOwnershipTransferRequested", opts, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequestedIterator, error)) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to
+func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferred")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferred'
+type EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterOwnershipTransferred(opts interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call{Call: _e.mock.On("FilterOwnershipTransferred", opts, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator, _a1 error) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferredIterator, error)) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSkippedAlreadyExecutedMessage provides a mock function with given fields: opts, sequenceNumber
+func (_m *EVM2EVMOffRampInterface) FilterSkippedAlreadyExecutedMessage(opts *bind.FilterOpts, sequenceNumber []uint64) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator, error) {
+ ret := _m.Called(opts, sequenceNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSkippedAlreadyExecutedMessage")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator, error)); ok {
+ return rf(opts, sequenceNumber)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator); ok {
+ r0 = rf(opts, sequenceNumber)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64) error); ok {
+ r1 = rf(opts, sequenceNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSkippedAlreadyExecutedMessage'
+type EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call struct {
+ *mock.Call
+}
+
+// FilterSkippedAlreadyExecutedMessage is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - sequenceNumber []uint64
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterSkippedAlreadyExecutedMessage(opts interface{}, sequenceNumber interface{}) *EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call {
+ return &EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call{Call: _e.mock.On("FilterSkippedAlreadyExecutedMessage", opts, sequenceNumber)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call) Run(run func(opts *bind.FilterOpts, sequenceNumber []uint64)) *EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator, _a1 error) *EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessageIterator, error)) *EVM2EVMOffRampInterface_FilterSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSkippedIncorrectNonce provides a mock function with given fields: opts, nonce, sender
+func (_m *EVM2EVMOffRampInterface) FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator, error) {
+ ret := _m.Called(opts, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSkippedIncorrectNonce")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator, error)); ok {
+ return rf(opts, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator); ok {
+ r0 = rf(opts, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// FilterSkippedIncorrectNonce is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterSkippedIncorrectNonce(opts interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call{Call: _e.mock.On("FilterSkippedIncorrectNonce", opts, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) Run(run func(opts *bind.FilterOpts, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator, _a1 error) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonceIterator, error)) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: opts, nonce, sender
+func (_m *EVM2EVMOffRampInterface) FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error) {
+ ret := _m.Called(opts, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)); ok {
+ return rf(opts, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator); ok {
+ r0 = rf(opts, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// FilterSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterSkippedSenderWithPreviousRampMessageInflight(opts interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("FilterSkippedSenderWithPreviousRampMessageInflight", opts, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(opts *bind.FilterOpts, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, _a1 error) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTokenAggregateRateLimitAdded provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterTokenAggregateRateLimitAdded(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAddedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTokenAggregateRateLimitAdded")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAddedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAddedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAddedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAddedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTokenAggregateRateLimitAdded'
+type EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call struct {
+ *mock.Call
+}
+
+// FilterTokenAggregateRateLimitAdded is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterTokenAggregateRateLimitAdded(opts interface{}) *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call {
+ return &EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call{Call: _e.mock.On("FilterTokenAggregateRateLimitAdded", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAddedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAddedIterator, error)) *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTokenAggregateRateLimitRemoved provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterTokenAggregateRateLimitRemoved(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTokenAggregateRateLimitRemoved")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTokenAggregateRateLimitRemoved'
+type EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call struct {
+ *mock.Call
+}
+
+// FilterTokenAggregateRateLimitRemoved is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterTokenAggregateRateLimitRemoved(opts interface{}) *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call {
+ return &EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call{Call: _e.mock.On("FilterTokenAggregateRateLimitRemoved", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemovedIterator, error)) *EVM2EVMOffRampInterface_FilterTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTokensConsumed provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterTokensConsumed(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokensConsumedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTokensConsumed")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokensConsumedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampTokensConsumedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterTokensConsumed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTokensConsumed'
+type EVM2EVMOffRampInterface_FilterTokensConsumed_Call struct {
+ *mock.Call
+}
+
+// FilterTokensConsumed is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterTokensConsumed(opts interface{}) *EVM2EVMOffRampInterface_FilterTokensConsumed_Call {
+ return &EVM2EVMOffRampInterface_FilterTokensConsumed_Call{Call: _e.mock.On("FilterTokensConsumed", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokensConsumed_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterTokensConsumed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokensConsumed_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterTokensConsumed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTokensConsumed_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTokensConsumedIterator, error)) *EVM2EVMOffRampInterface_FilterTokensConsumed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTransmitted provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterTransmitted(opts *bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTransmitted")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTransmitted'
+type EVM2EVMOffRampInterface_FilterTransmitted_Call struct {
+ *mock.Call
+}
+
+// FilterTransmitted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterTransmitted(opts interface{}) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ return &EVM2EVMOffRampInterface_FilterTransmitted_Call{Call: _e.mock.On("FilterTransmitted", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp.EVM2EVMOffRampTransmittedIterator, error)) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetAllRateLimitTokens provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetAllRateLimitTokens(opts *bind.CallOpts) (evm_2_evm_offramp.GetAllRateLimitTokens, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetAllRateLimitTokens")
+ }
+
+ var r0 evm_2_evm_offramp.GetAllRateLimitTokens
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.GetAllRateLimitTokens, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp.GetAllRateLimitTokens); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp.GetAllRateLimitTokens)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllRateLimitTokens'
+type EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call struct {
+ *mock.Call
+}
+
+// GetAllRateLimitTokens is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetAllRateLimitTokens(opts interface{}) *EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call {
+ return &EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call{Call: _e.mock.On("GetAllRateLimitTokens", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call) Return(_a0 evm_2_evm_offramp.GetAllRateLimitTokens, _a1 error) *EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp.GetAllRateLimitTokens, error)) *EVM2EVMOffRampInterface_GetAllRateLimitTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDynamicConfig provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetDynamicConfig(opts *bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDynamicConfig")
+ }
+
+ var r0 evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetDynamicConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDynamicConfig'
+type EVM2EVMOffRampInterface_GetDynamicConfig_Call struct {
+ *mock.Call
+}
+
+// GetDynamicConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetDynamicConfig(opts interface{}) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ return &EVM2EVMOffRampInterface_GetDynamicConfig_Call{Call: _e.mock.On("GetDynamicConfig", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) Return(_a0 evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig, _a1 error) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig, error)) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetExecutionState provides a mock function with given fields: opts, sequenceNumber
+func (_m *EVM2EVMOffRampInterface) GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error) {
+ ret := _m.Called(opts, sequenceNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetExecutionState")
+ }
+
+ var r0 uint8
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (uint8, error)); ok {
+ return rf(opts, sequenceNumber)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) uint8); ok {
+ r0 = rf(opts, sequenceNumber)
+ } else {
+ r0 = ret.Get(0).(uint8)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, sequenceNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetExecutionState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExecutionState'
+type EVM2EVMOffRampInterface_GetExecutionState_Call struct {
+ *mock.Call
+}
+
+// GetExecutionState is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sequenceNumber uint64
+func (_e *EVM2EVMOffRampInterface_Expecter) GetExecutionState(opts interface{}, sequenceNumber interface{}) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ return &EVM2EVMOffRampInterface_GetExecutionState_Call{Call: _e.mock.On("GetExecutionState", opts, sequenceNumber)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) Run(run func(opts *bind.CallOpts, sequenceNumber uint64)) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) Return(_a0 uint8, _a1 error) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (uint8, error)) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSenderNonce provides a mock function with given fields: opts, sender
+func (_m *EVM2EVMOffRampInterface) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ ret := _m.Called(opts, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSenderNonce")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok {
+ return rf(opts, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) uint64); ok {
+ r0 = rf(opts, sender)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetSenderNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSenderNonce'
+type EVM2EVMOffRampInterface_GetSenderNonce_Call struct {
+ *mock.Call
+}
+
+// GetSenderNonce is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sender common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetSenderNonce(opts interface{}, sender interface{}) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ return &EVM2EVMOffRampInterface_GetSenderNonce_Call{Call: _e.mock.On("GetSenderNonce", opts, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) Run(run func(opts *bind.CallOpts, sender common.Address)) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) Return(_a0 uint64, _a1 error) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (uint64, error)) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStaticConfig provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetStaticConfig(opts *bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampStaticConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStaticConfig")
+ }
+
+ var r0 evm_2_evm_offramp.EVM2EVMOffRampStaticConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampStaticConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp.EVM2EVMOffRampStaticConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp.EVM2EVMOffRampStaticConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetStaticConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStaticConfig'
+type EVM2EVMOffRampInterface_GetStaticConfig_Call struct {
+ *mock.Call
+}
+
+// GetStaticConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetStaticConfig(opts interface{}) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ return &EVM2EVMOffRampInterface_GetStaticConfig_Call{Call: _e.mock.On("GetStaticConfig", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) Return(_a0 evm_2_evm_offramp.EVM2EVMOffRampStaticConfig, _a1 error) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampStaticConfig, error)) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenLimitAdmin provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenLimitAdmin")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenLimitAdmin'
+type EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call struct {
+ *mock.Call
+}
+
+// GetTokenLimitAdmin is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetTokenLimitAdmin(opts interface{}) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ return &EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call{Call: _e.mock.On("GetTokenLimitAdmin", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTransmitters provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTransmitters")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetTransmitters_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTransmitters'
+type EVM2EVMOffRampInterface_GetTransmitters_Call struct {
+ *mock.Call
+}
+
+// GetTransmitters is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetTransmitters(opts interface{}) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ return &EVM2EVMOffRampInterface_GetTransmitters_Call{Call: _e.mock.On("GetTransmitters", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) Return(_a0 []common.Address, _a1 error) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfigDetails provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) LatestConfigDetails(opts *bind.CallOpts) (evm_2_evm_offramp.LatestConfigDetails, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfigDetails")
+ }
+
+ var r0 evm_2_evm_offramp.LatestConfigDetails
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.LatestConfigDetails, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp.LatestConfigDetails); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp.LatestConfigDetails)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_LatestConfigDetails_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfigDetails'
+type EVM2EVMOffRampInterface_LatestConfigDetails_Call struct {
+ *mock.Call
+}
+
+// LatestConfigDetails is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) LatestConfigDetails(opts interface{}) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ return &EVM2EVMOffRampInterface_LatestConfigDetails_Call{Call: _e.mock.On("LatestConfigDetails", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) Return(_a0 evm_2_evm_offramp.LatestConfigDetails, _a1 error) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp.LatestConfigDetails, error)) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfigDigestAndEpoch provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (evm_2_evm_offramp.LatestConfigDigestAndEpoch, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfigDigestAndEpoch")
+ }
+
+ var r0 evm_2_evm_offramp.LatestConfigDigestAndEpoch
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp.LatestConfigDigestAndEpoch, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp.LatestConfigDigestAndEpoch); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp.LatestConfigDigestAndEpoch)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfigDigestAndEpoch'
+type EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call struct {
+ *mock.Call
+}
+
+// LatestConfigDigestAndEpoch is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) LatestConfigDigestAndEpoch(opts interface{}) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ return &EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call{Call: _e.mock.On("LatestConfigDigestAndEpoch", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) Return(_a0 evm_2_evm_offramp.LatestConfigDigestAndEpoch, _a1 error) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp.LatestConfigDigestAndEpoch, error)) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ManuallyExecute provides a mock function with given fields: opts, report, gasLimitOverrides
+func (_m *EVM2EVMOffRampInterface) ManuallyExecute(opts *bind.TransactOpts, report evm_2_evm_offramp.InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, report, gasLimitOverrides)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ManuallyExecute")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.InternalExecutionReport, []*big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, report, gasLimitOverrides)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.InternalExecutionReport, []*big.Int) *types.Transaction); ok {
+ r0 = rf(opts, report, gasLimitOverrides)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp.InternalExecutionReport, []*big.Int) error); ok {
+ r1 = rf(opts, report, gasLimitOverrides)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ManuallyExecute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ManuallyExecute'
+type EVM2EVMOffRampInterface_ManuallyExecute_Call struct {
+ *mock.Call
+}
+
+// ManuallyExecute is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - report evm_2_evm_offramp.InternalExecutionReport
+// - gasLimitOverrides []*big.Int
+func (_e *EVM2EVMOffRampInterface_Expecter) ManuallyExecute(opts interface{}, report interface{}, gasLimitOverrides interface{}) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ return &EVM2EVMOffRampInterface_ManuallyExecute_Call{Call: _e.mock.On("ManuallyExecute", opts, report, gasLimitOverrides)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) Run(run func(opts *bind.TransactOpts, report evm_2_evm_offramp.InternalExecutionReport, gasLimitOverrides []*big.Int)) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp.InternalExecutionReport), args[2].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp.InternalExecutionReport, []*big.Int) (*types.Transaction, error)) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Owner provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) Owner(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Owner")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_Owner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Owner'
+type EVM2EVMOffRampInterface_Owner_Call struct {
+ *mock.Call
+}
+
+// Owner is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) Owner(opts interface{}) *EVM2EVMOffRampInterface_Owner_Call {
+ return &EVM2EVMOffRampInterface_Owner_Call{Call: _e.mock.On("Owner", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseAdminSet provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseAdminSet(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseAdminSet")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampAdminSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampAdminSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampAdminSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseAdminSet'
+type EVM2EVMOffRampInterface_ParseAdminSet_Call struct {
+ *mock.Call
+}
+
+// ParseAdminSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseAdminSet(log interface{}) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ return &EVM2EVMOffRampInterface_ParseAdminSet_Call{Call: _e.mock.On("ParseAdminSet", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampAdminSet, _a1 error) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampAdminSet, error)) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigChanged provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseConfigChanged(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigChanged, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigChanged")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigChanged, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampConfigChanged)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseConfigChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigChanged'
+type EVM2EVMOffRampInterface_ParseConfigChanged_Call struct {
+ *mock.Call
+}
+
+// ParseConfigChanged is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseConfigChanged(log interface{}) *EVM2EVMOffRampInterface_ParseConfigChanged_Call {
+ return &EVM2EVMOffRampInterface_ParseConfigChanged_Call{Call: _e.mock.On("ParseConfigChanged", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigChanged_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseConfigChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigChanged_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged, _a1 error) *EVM2EVMOffRampInterface_ParseConfigChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigChanged_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigChanged, error)) *EVM2EVMOffRampInterface_ParseConfigChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseConfigSet(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampConfigSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampConfigSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet'
+type EVM2EVMOffRampInterface_ParseConfigSet_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseConfigSet(log interface{}) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ return &EVM2EVMOffRampInterface_ParseConfigSet_Call{Call: _e.mock.On("ParseConfigSet", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet, _a1 error) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet, error)) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet0 provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseConfigSet0(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet0")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet0'
+type EVM2EVMOffRampInterface_ParseConfigSet0_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet0 is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseConfigSet0(log interface{}) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_ParseConfigSet0_Call{Call: _e.mock.On("ParseConfigSet0", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0, _a1 error) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampConfigSet0, error)) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseExecutionStateChanged provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseExecutionStateChanged(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseExecutionStateChanged")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseExecutionStateChanged'
+type EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// ParseExecutionStateChanged is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseExecutionStateChanged(log interface{}) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call{Call: _e.mock.On("ParseExecutionStateChanged", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, _a1 error) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, error)) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type EVM2EVMOffRampInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseLog(log interface{}) *EVM2EVMOffRampInterface_ParseLog_Call {
+ return &EVM2EVMOffRampInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferRequested provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferRequested(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferRequested")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferRequested is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseOwnershipTransferRequested(log interface{}) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call{Call: _e.mock.On("ParseOwnershipTransferRequested", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, _a1 error) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, error)) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferred provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferred(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferred")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferred'
+type EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferred is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseOwnershipTransferred(log interface{}) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call{Call: _e.mock.On("ParseOwnershipTransferred", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, _a1 error) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, error)) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSkippedAlreadyExecutedMessage provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseSkippedAlreadyExecutedMessage(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSkippedAlreadyExecutedMessage")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSkippedAlreadyExecutedMessage'
+type EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call struct {
+ *mock.Call
+}
+
+// ParseSkippedAlreadyExecutedMessage is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseSkippedAlreadyExecutedMessage(log interface{}) *EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call {
+ return &EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call{Call: _e.mock.On("ParseSkippedAlreadyExecutedMessage", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, _a1 error) *EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, error)) *EVM2EVMOffRampInterface_ParseSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSkippedIncorrectNonce provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseSkippedIncorrectNonce(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSkippedIncorrectNonce")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// ParseSkippedIncorrectNonce is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseSkippedIncorrectNonce(log interface{}) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call{Call: _e.mock.On("ParseSkippedIncorrectNonce", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, _a1 error) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, error)) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// ParseSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseSkippedSenderWithPreviousRampMessageInflight(log interface{}) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("ParseSkippedSenderWithPreviousRampMessageInflight", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, _a1 error) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTokenAggregateRateLimitAdded provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseTokenAggregateRateLimitAdded(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTokenAggregateRateLimitAdded")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTokenAggregateRateLimitAdded'
+type EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call struct {
+ *mock.Call
+}
+
+// ParseTokenAggregateRateLimitAdded is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseTokenAggregateRateLimitAdded(log interface{}) *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call {
+ return &EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call{Call: _e.mock.On("ParseTokenAggregateRateLimitAdded", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded, _a1 error) *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded, error)) *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTokenAggregateRateLimitRemoved provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseTokenAggregateRateLimitRemoved(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTokenAggregateRateLimitRemoved")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTokenAggregateRateLimitRemoved'
+type EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call struct {
+ *mock.Call
+}
+
+// ParseTokenAggregateRateLimitRemoved is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseTokenAggregateRateLimitRemoved(log interface{}) *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call {
+ return &EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call{Call: _e.mock.On("ParseTokenAggregateRateLimitRemoved", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved, _a1 error) *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved, error)) *EVM2EVMOffRampInterface_ParseTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTokensConsumed provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseTokensConsumed(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTokensConsumed")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseTokensConsumed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTokensConsumed'
+type EVM2EVMOffRampInterface_ParseTokensConsumed_Call struct {
+ *mock.Call
+}
+
+// ParseTokensConsumed is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseTokensConsumed(log interface{}) *EVM2EVMOffRampInterface_ParseTokensConsumed_Call {
+ return &EVM2EVMOffRampInterface_ParseTokensConsumed_Call{Call: _e.mock.On("ParseTokensConsumed", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokensConsumed_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseTokensConsumed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokensConsumed_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed, _a1 error) *EVM2EVMOffRampInterface_ParseTokensConsumed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTokensConsumed_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed, error)) *EVM2EVMOffRampInterface_ParseTokensConsumed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTransmitted provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseTransmitted(log types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTransmitted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTransmitted")
+ }
+
+ var r0 *evm_2_evm_offramp.EVM2EVMOffRampTransmitted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTransmitted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp.EVM2EVMOffRampTransmitted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp.EVM2EVMOffRampTransmitted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTransmitted'
+type EVM2EVMOffRampInterface_ParseTransmitted_Call struct {
+ *mock.Call
+}
+
+// ParseTransmitted is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseTransmitted(log interface{}) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ return &EVM2EVMOffRampInterface_ParseTransmitted_Call{Call: _e.mock.On("ParseTransmitted", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) Return(_a0 *evm_2_evm_offramp.EVM2EVMOffRampTransmitted, _a1 error) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp.EVM2EVMOffRampTransmitted, error)) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetAdmin provides a mock function with given fields: opts, newAdmin
+func (_m *EVM2EVMOffRampInterface) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, newAdmin)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetAdmin")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, newAdmin)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, newAdmin)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, newAdmin)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAdmin'
+type EVM2EVMOffRampInterface_SetAdmin_Call struct {
+ *mock.Call
+}
+
+// SetAdmin is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - newAdmin common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) SetAdmin(opts interface{}, newAdmin interface{}) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ return &EVM2EVMOffRampInterface_SetAdmin_Call{Call: _e.mock.On("SetAdmin", opts, newAdmin)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) Run(run func(opts *bind.TransactOpts, newAdmin common.Address)) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetOCR2Config provides a mock function with given fields: opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig
+func (_m *EVM2EVMOffRampInterface) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetOCR2Config")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) *types.Transaction); ok {
+ r0 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) error); ok {
+ r1 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetOCR2Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetOCR2Config'
+type EVM2EVMOffRampInterface_SetOCR2Config_Call struct {
+ *mock.Call
+}
+
+// SetOCR2Config is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - signers []common.Address
+// - transmitters []common.Address
+// - f uint8
+// - onchainConfig []byte
+// - offchainConfigVersion uint64
+// - offchainConfig []byte
+func (_e *EVM2EVMOffRampInterface_Expecter) SetOCR2Config(opts interface{}, signers interface{}, transmitters interface{}, f interface{}, onchainConfig interface{}, offchainConfigVersion interface{}, offchainConfig interface{}) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ return &EVM2EVMOffRampInterface_SetOCR2Config_Call{Call: _e.mock.On("SetOCR2Config", opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) Run(run func(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte)) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].(uint8), args[4].([]byte), args[5].(uint64), args[6].([]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) RunAndReturn(run func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetRateLimiterConfig provides a mock function with given fields: opts, config
+func (_m *EVM2EVMOffRampInterface) SetRateLimiterConfig(opts *bind.TransactOpts, config evm_2_evm_offramp.RateLimiterConfig) (*types.Transaction, error) {
+ ret := _m.Called(opts, config)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetRateLimiterConfig")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.RateLimiterConfig) (*types.Transaction, error)); ok {
+ return rf(opts, config)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp.RateLimiterConfig) *types.Transaction); ok {
+ r0 = rf(opts, config)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp.RateLimiterConfig) error); ok {
+ r1 = rf(opts, config)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetRateLimiterConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetRateLimiterConfig'
+type EVM2EVMOffRampInterface_SetRateLimiterConfig_Call struct {
+ *mock.Call
+}
+
+// SetRateLimiterConfig is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - config evm_2_evm_offramp.RateLimiterConfig
+func (_e *EVM2EVMOffRampInterface_Expecter) SetRateLimiterConfig(opts interface{}, config interface{}) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ return &EVM2EVMOffRampInterface_SetRateLimiterConfig_Call{Call: _e.mock.On("SetRateLimiterConfig", opts, config)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) Run(run func(opts *bind.TransactOpts, config evm_2_evm_offramp.RateLimiterConfig)) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp.RateLimiterConfig))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp.RateLimiterConfig) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TransferOwnership provides a mock function with given fields: opts, to
+func (_m *EVM2EVMOffRampInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TransferOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_TransferOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferOwnership'
+type EVM2EVMOffRampInterface_TransferOwnership_Call struct {
+ *mock.Call
+}
+
+// TransferOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - to common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) TransferOwnership(opts interface{}, to interface{}) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ return &EVM2EVMOffRampInterface_TransferOwnership_Call{Call: _e.mock.On("TransferOwnership", opts, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) Run(run func(opts *bind.TransactOpts, to common.Address)) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Transmit provides a mock function with given fields: opts, reportContext, report, rs, ss, arg4
+func (_m *EVM2EVMOffRampInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, reportContext, report, rs, ss, arg4)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Transmit")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok {
+ return rf(opts, reportContext, report, rs, ss, arg4)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) *types.Transaction); ok {
+ r0 = rf(opts, reportContext, report, rs, ss, arg4)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) error); ok {
+ r1 = rf(opts, reportContext, report, rs, ss, arg4)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_Transmit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Transmit'
+type EVM2EVMOffRampInterface_Transmit_Call struct {
+ *mock.Call
+}
+
+// Transmit is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - reportContext [3][32]byte
+// - report []byte
+// - rs [][32]byte
+// - ss [][32]byte
+// - arg4 [32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) Transmit(opts interface{}, reportContext interface{}, report interface{}, rs interface{}, ss interface{}, arg4 interface{}) *EVM2EVMOffRampInterface_Transmit_Call {
+ return &EVM2EVMOffRampInterface_Transmit_Call{Call: _e.mock.On("Transmit", opts, reportContext, report, rs, ss, arg4)}
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) Run(run func(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte)) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([3][32]byte), args[2].([]byte), args[3].([][32]byte), args[4].([][32]byte), args[5].([32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) RunAndReturn(run func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TypeAndVersion provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TypeAndVersion")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_TypeAndVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TypeAndVersion'
+type EVM2EVMOffRampInterface_TypeAndVersion_Call struct {
+ *mock.Call
+}
+
+// TypeAndVersion is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) TypeAndVersion(opts interface{}) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ return &EVM2EVMOffRampInterface_TypeAndVersion_Call{Call: _e.mock.On("TypeAndVersion", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) Return(_a0 string, _a1 error) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// UpdateRateLimitTokens provides a mock function with given fields: opts, removes, adds
+func (_m *EVM2EVMOffRampInterface) UpdateRateLimitTokens(opts *bind.TransactOpts, removes []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, adds []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken) (*types.Transaction, error) {
+ ret := _m.Called(opts, removes, adds)
+
+ if len(ret) == 0 {
+ panic("no return value specified for UpdateRateLimitTokens")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken) (*types.Transaction, error)); ok {
+ return rf(opts, removes, adds)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken) *types.Transaction); ok {
+ r0 = rf(opts, removes, adds)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken) error); ok {
+ r1 = rf(opts, removes, adds)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateRateLimitTokens'
+type EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call struct {
+ *mock.Call
+}
+
+// UpdateRateLimitTokens is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - removes []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken
+// - adds []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken
+func (_e *EVM2EVMOffRampInterface_Expecter) UpdateRateLimitTokens(opts interface{}, removes interface{}, adds interface{}) *EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call {
+ return &EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call{Call: _e.mock.On("UpdateRateLimitTokens", opts, removes, adds)}
+}
+
+func (_c *EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call) Run(run func(opts *bind.TransactOpts, removes []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, adds []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken)) *EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken), args[2].([]evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call) RunAndReturn(run func(*bind.TransactOpts, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken) (*types.Transaction, error)) *EVM2EVMOffRampInterface_UpdateRateLimitTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchAdminSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchAdminSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAdminSet'
+type EVM2EVMOffRampInterface_WatchAdminSet_Call struct {
+ *mock.Call
+}
+
+// WatchAdminSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchAdminSet(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ return &EVM2EVMOffRampInterface_WatchAdminSet_Call{Call: _e.mock.On("WatchAdminSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet)) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampAdminSet) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigChanged provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigChanged")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchConfigChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigChanged'
+type EVM2EVMOffRampInterface_WatchConfigChanged_Call struct {
+ *mock.Call
+}
+
+// WatchConfigChanged is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchConfigChanged(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchConfigChanged_Call {
+ return &EVM2EVMOffRampInterface_WatchConfigChanged_Call{Call: _e.mock.On("WatchConfigChanged", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigChanged_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged)) *EVM2EVMOffRampInterface_WatchConfigChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigChanged_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchConfigChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigChanged_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigChanged) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchConfigChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet'
+type EVM2EVMOffRampInterface_WatchConfigSet_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchConfigSet(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ return &EVM2EVMOffRampInterface_WatchConfigSet_Call{Call: _e.mock.On("WatchConfigSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet)) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet0 provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet0")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet0'
+type EVM2EVMOffRampInterface_WatchConfigSet0_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet0 is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchConfigSet0(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_WatchConfigSet0_Call{Call: _e.mock.On("WatchConfigSet0", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0)) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampConfigSet0) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchExecutionStateChanged provides a mock function with given fields: opts, sink, sequenceNumber, messageId
+func (_m *EVM2EVMOffRampInterface) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, sequenceNumber, messageId)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchExecutionStateChanged")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) (event.Subscription, error)); ok {
+ return rf(opts, sink, sequenceNumber, messageId)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) event.Subscription); ok {
+ r0 = rf(opts, sink, sequenceNumber, messageId)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) error); ok {
+ r1 = rf(opts, sink, sequenceNumber, messageId)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchExecutionStateChanged'
+type EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// WatchExecutionStateChanged is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged
+// - sequenceNumber []uint64
+// - messageId [][32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchExecutionStateChanged(opts interface{}, sink interface{}, sequenceNumber interface{}, messageId interface{}) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call{Call: _e.mock.On("WatchExecutionStateChanged", opts, sink, sequenceNumber, messageId)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte)) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged), args[2].([]uint64), args[3].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to
+func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferRequested")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchOwnershipTransferRequested(opts interface{}, sink interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call{Call: _e.mock.On("WatchOwnershipTransferRequested", opts, sink, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to
+func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferred")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferred'
+type EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchOwnershipTransferred(opts interface{}, sink interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call{Call: _e.mock.On("WatchOwnershipTransferred", opts, sink, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSkippedAlreadyExecutedMessage provides a mock function with given fields: opts, sink, sequenceNumber
+func (_m *EVM2EVMOffRampInterface) WatchSkippedAlreadyExecutedMessage(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, sequenceNumber []uint64) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, sequenceNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSkippedAlreadyExecutedMessage")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, []uint64) (event.Subscription, error)); ok {
+ return rf(opts, sink, sequenceNumber)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, []uint64) event.Subscription); ok {
+ r0 = rf(opts, sink, sequenceNumber)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, []uint64) error); ok {
+ r1 = rf(opts, sink, sequenceNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSkippedAlreadyExecutedMessage'
+type EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call struct {
+ *mock.Call
+}
+
+// WatchSkippedAlreadyExecutedMessage is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage
+// - sequenceNumber []uint64
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchSkippedAlreadyExecutedMessage(opts interface{}, sink interface{}, sequenceNumber interface{}) *EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call {
+ return &EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call{Call: _e.mock.On("WatchSkippedAlreadyExecutedMessage", opts, sink, sequenceNumber)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, sequenceNumber []uint64)) *EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage), args[2].([]uint64))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedAlreadyExecutedMessage, []uint64) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchSkippedAlreadyExecutedMessage_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSkippedIncorrectNonce provides a mock function with given fields: opts, sink, nonce, sender
+func (_m *EVM2EVMOffRampInterface) WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSkippedIncorrectNonce")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, sink, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// WatchSkippedIncorrectNonce is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchSkippedIncorrectNonce(opts interface{}, sink interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call{Call: _e.mock.On("WatchSkippedIncorrectNonce", opts, sink, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce), args[2].([]uint64), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: opts, sink, nonce, sender
+func (_m *EVM2EVMOffRampInterface) WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, sink, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// WatchSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchSkippedSenderWithPreviousRampMessageInflight(opts interface{}, sink interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("WatchSkippedSenderWithPreviousRampMessageInflight", opts, sink, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight), args[2].([]uint64), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTokenAggregateRateLimitAdded provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchTokenAggregateRateLimitAdded(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTokenAggregateRateLimitAdded")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTokenAggregateRateLimitAdded'
+type EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call struct {
+ *mock.Call
+}
+
+// WatchTokenAggregateRateLimitAdded is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchTokenAggregateRateLimitAdded(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call {
+ return &EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call{Call: _e.mock.On("WatchTokenAggregateRateLimitAdded", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded)) *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitAdded) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTokenAggregateRateLimitRemoved provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchTokenAggregateRateLimitRemoved(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTokenAggregateRateLimitRemoved")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTokenAggregateRateLimitRemoved'
+type EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call struct {
+ *mock.Call
+}
+
+// WatchTokenAggregateRateLimitRemoved is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchTokenAggregateRateLimitRemoved(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call {
+ return &EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call{Call: _e.mock.On("WatchTokenAggregateRateLimitRemoved", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved)) *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokenAggregateRateLimitRemoved) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchTokenAggregateRateLimitRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTokensConsumed provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTokensConsumed")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchTokensConsumed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTokensConsumed'
+type EVM2EVMOffRampInterface_WatchTokensConsumed_Call struct {
+ *mock.Call
+}
+
+// WatchTokensConsumed is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchTokensConsumed(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchTokensConsumed_Call {
+ return &EVM2EVMOffRampInterface_WatchTokensConsumed_Call{Call: _e.mock.On("WatchTokensConsumed", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokensConsumed_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed)) *EVM2EVMOffRampInterface_WatchTokensConsumed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokensConsumed_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchTokensConsumed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTokensConsumed_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTokensConsumed) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchTokensConsumed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTransmitted provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTransmitted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTransmitted'
+type EVM2EVMOffRampInterface_WatchTransmitted_Call struct {
+ *mock.Call
+}
+
+// WatchTransmitted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchTransmitted(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ return &EVM2EVMOffRampInterface_WatchTransmitted_Call{Call: _e.mock.On("WatchTransmitted", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted)) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp.EVM2EVMOffRampTransmitted) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewEVM2EVMOffRampInterface creates a new instance of EVM2EVMOffRampInterface. 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 NewEVM2EVMOffRampInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *EVM2EVMOffRampInterface {
+ mock := &EVM2EVMOffRampInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/ccip/mocks/evm2_evm_on_ramp_interface.go b/core/gethwrappers/ccip/mocks/evm2_evm_on_ramp_interface.go
new file mode 100644
index 00000000000..57580777493
--- /dev/null
+++ b/core/gethwrappers/ccip/mocks/evm2_evm_on_ramp_interface.go
@@ -0,0 +1,3832 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_contracts
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ evm_2_evm_onramp "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// EVM2EVMOnRampInterface is an autogenerated mock type for the EVM2EVMOnRampInterface type
+type EVM2EVMOnRampInterface struct {
+ mock.Mock
+}
+
+type EVM2EVMOnRampInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *EVM2EVMOnRampInterface) EXPECT() *EVM2EVMOnRampInterface_Expecter {
+ return &EVM2EVMOnRampInterface_Expecter{mock: &_m.Mock}
+}
+
+// AcceptOwnership provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AcceptOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_AcceptOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptOwnership'
+type EVM2EVMOnRampInterface_AcceptOwnership_Call struct {
+ *mock.Call
+}
+
+// AcceptOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) AcceptOwnership(opts interface{}) *EVM2EVMOnRampInterface_AcceptOwnership_Call {
+ return &EVM2EVMOnRampInterface_AcceptOwnership_Call{Call: _e.mock.On("AcceptOwnership", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_AcceptOwnership_Call) Run(run func(opts *bind.TransactOpts)) *EVM2EVMOnRampInterface_AcceptOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_AcceptOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_AcceptOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_AcceptOwnership_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *EVM2EVMOnRampInterface_AcceptOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Address provides a mock function with given fields:
+func (_m *EVM2EVMOnRampInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// EVM2EVMOnRampInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type EVM2EVMOnRampInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *EVM2EVMOnRampInterface_Expecter) Address() *EVM2EVMOnRampInterface_Address_Call {
+ return &EVM2EVMOnRampInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *EVM2EVMOnRampInterface_Address_Call) Run(run func()) *EVM2EVMOnRampInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_Address_Call) Return(_a0 common.Address) *EVM2EVMOnRampInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_Address_Call) RunAndReturn(run func() common.Address) *EVM2EVMOnRampInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CurrentRateLimiterState provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) CurrentRateLimiterState(opts *bind.CallOpts) (evm_2_evm_onramp.RateLimiterTokenBucket, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CurrentRateLimiterState")
+ }
+
+ var r0 evm_2_evm_onramp.RateLimiterTokenBucket
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_onramp.RateLimiterTokenBucket, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_onramp.RateLimiterTokenBucket); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_onramp.RateLimiterTokenBucket)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_CurrentRateLimiterState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CurrentRateLimiterState'
+type EVM2EVMOnRampInterface_CurrentRateLimiterState_Call struct {
+ *mock.Call
+}
+
+// CurrentRateLimiterState is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) CurrentRateLimiterState(opts interface{}) *EVM2EVMOnRampInterface_CurrentRateLimiterState_Call {
+ return &EVM2EVMOnRampInterface_CurrentRateLimiterState_Call{Call: _e.mock.On("CurrentRateLimiterState", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_CurrentRateLimiterState_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_CurrentRateLimiterState_Call) Return(_a0 evm_2_evm_onramp.RateLimiterTokenBucket, _a1 error) *EVM2EVMOnRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_CurrentRateLimiterState_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_onramp.RateLimiterTokenBucket, error)) *EVM2EVMOnRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterAdminSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterAdminSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterAdminSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterAdminSet'
+type EVM2EVMOnRampInterface_FilterAdminSet_Call struct {
+ *mock.Call
+}
+
+// FilterAdminSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterAdminSet(opts interface{}) *EVM2EVMOnRampInterface_FilterAdminSet_Call {
+ return &EVM2EVMOnRampInterface_FilterAdminSet_Call{Call: _e.mock.On("FilterAdminSet", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterAdminSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterAdminSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator, _a1 error) *EVM2EVMOnRampInterface_FilterAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterAdminSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSetIterator, error)) *EVM2EVMOnRampInterface_FilterAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterCCIPSendRequested provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterCCIPSendRequested(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterCCIPSendRequested")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterCCIPSendRequested'
+type EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call struct {
+ *mock.Call
+}
+
+// FilterCCIPSendRequested is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterCCIPSendRequested(opts interface{}) *EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call {
+ return &EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call{Call: _e.mock.On("FilterCCIPSendRequested", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator, _a1 error) *EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequestedIterator, error)) *EVM2EVMOnRampInterface_FilterCCIPSendRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigChanged provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterConfigChanged(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampConfigChangedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigChanged")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampConfigChangedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampConfigChangedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampConfigChangedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampConfigChangedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterConfigChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigChanged'
+type EVM2EVMOnRampInterface_FilterConfigChanged_Call struct {
+ *mock.Call
+}
+
+// FilterConfigChanged is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterConfigChanged(opts interface{}) *EVM2EVMOnRampInterface_FilterConfigChanged_Call {
+ return &EVM2EVMOnRampInterface_FilterConfigChanged_Call{Call: _e.mock.On("FilterConfigChanged", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterConfigChanged_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterConfigChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterConfigChanged_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampConfigChangedIterator, _a1 error) *EVM2EVMOnRampInterface_FilterConfigChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterConfigChanged_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampConfigChangedIterator, error)) *EVM2EVMOnRampInterface_FilterConfigChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterConfigSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet'
+type EVM2EVMOnRampInterface_FilterConfigSet_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterConfigSet(opts interface{}) *EVM2EVMOnRampInterface_FilterConfigSet_Call {
+ return &EVM2EVMOnRampInterface_FilterConfigSet_Call{Call: _e.mock.On("FilterConfigSet", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterConfigSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterConfigSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator, _a1 error) *EVM2EVMOnRampInterface_FilterConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterConfigSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSetIterator, error)) *EVM2EVMOnRampInterface_FilterConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterFeeConfigSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterFeeConfigSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterFeeConfigSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterFeeConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterFeeConfigSet'
+type EVM2EVMOnRampInterface_FilterFeeConfigSet_Call struct {
+ *mock.Call
+}
+
+// FilterFeeConfigSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterFeeConfigSet(opts interface{}) *EVM2EVMOnRampInterface_FilterFeeConfigSet_Call {
+ return &EVM2EVMOnRampInterface_FilterFeeConfigSet_Call{Call: _e.mock.On("FilterFeeConfigSet", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterFeeConfigSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterFeeConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterFeeConfigSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator, _a1 error) *EVM2EVMOnRampInterface_FilterFeeConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterFeeConfigSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSetIterator, error)) *EVM2EVMOnRampInterface_FilterFeeConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterNopPaid provides a mock function with given fields: opts, nop
+func (_m *EVM2EVMOnRampInterface) FilterNopPaid(opts *bind.FilterOpts, nop []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator, error) {
+ ret := _m.Called(opts, nop)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterNopPaid")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator, error)); ok {
+ return rf(opts, nop)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator); ok {
+ r0 = rf(opts, nop)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, nop)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterNopPaid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterNopPaid'
+type EVM2EVMOnRampInterface_FilterNopPaid_Call struct {
+ *mock.Call
+}
+
+// FilterNopPaid is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nop []common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterNopPaid(opts interface{}, nop interface{}) *EVM2EVMOnRampInterface_FilterNopPaid_Call {
+ return &EVM2EVMOnRampInterface_FilterNopPaid_Call{Call: _e.mock.On("FilterNopPaid", opts, nop)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterNopPaid_Call) Run(run func(opts *bind.FilterOpts, nop []common.Address)) *EVM2EVMOnRampInterface_FilterNopPaid_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterNopPaid_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator, _a1 error) *EVM2EVMOnRampInterface_FilterNopPaid_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterNopPaid_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaidIterator, error)) *EVM2EVMOnRampInterface_FilterNopPaid_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterNopsSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterNopsSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterNopsSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterNopsSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterNopsSet'
+type EVM2EVMOnRampInterface_FilterNopsSet_Call struct {
+ *mock.Call
+}
+
+// FilterNopsSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterNopsSet(opts interface{}) *EVM2EVMOnRampInterface_FilterNopsSet_Call {
+ return &EVM2EVMOnRampInterface_FilterNopsSet_Call{Call: _e.mock.On("FilterNopsSet", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterNopsSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterNopsSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterNopsSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator, _a1 error) *EVM2EVMOnRampInterface_FilterNopsSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterNopsSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSetIterator, error)) *EVM2EVMOnRampInterface_FilterNopsSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to
+func (_m *EVM2EVMOnRampInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferRequested")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferRequested'
+type EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterOwnershipTransferRequested(opts interface{}, from interface{}, to interface{}) *EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call {
+ return &EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call{Call: _e.mock.On("FilterOwnershipTransferRequested", opts, from, to)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator, _a1 error) *EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequestedIterator, error)) *EVM2EVMOnRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to
+func (_m *EVM2EVMOnRampInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferred")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferred'
+type EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterOwnershipTransferred(opts interface{}, from interface{}, to interface{}) *EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call {
+ return &EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call{Call: _e.mock.On("FilterOwnershipTransferred", opts, from, to)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator, _a1 error) *EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferredIterator, error)) *EVM2EVMOnRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTokenTransferFeeConfigDeleted provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterTokenTransferFeeConfigDeleted(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTokenTransferFeeConfigDeleted")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTokenTransferFeeConfigDeleted'
+type EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call struct {
+ *mock.Call
+}
+
+// FilterTokenTransferFeeConfigDeleted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterTokenTransferFeeConfigDeleted(opts interface{}) *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call {
+ return &EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call{Call: _e.mock.On("FilterTokenTransferFeeConfigDeleted", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator, _a1 error) *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeletedIterator, error)) *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTokenTransferFeeConfigSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterTokenTransferFeeConfigSet(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTokenTransferFeeConfigSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTokenTransferFeeConfigSet'
+type EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call struct {
+ *mock.Call
+}
+
+// FilterTokenTransferFeeConfigSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterTokenTransferFeeConfigSet(opts interface{}) *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call {
+ return &EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call{Call: _e.mock.On("FilterTokenTransferFeeConfigSet", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator, _a1 error) *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSetIterator, error)) *EVM2EVMOnRampInterface_FilterTokenTransferFeeConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTokensConsumed provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) FilterTokensConsumed(opts *bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokensConsumedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTokensConsumed")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokensConsumedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampTokensConsumedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_FilterTokensConsumed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTokensConsumed'
+type EVM2EVMOnRampInterface_FilterTokensConsumed_Call struct {
+ *mock.Call
+}
+
+// FilterTokensConsumed is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) FilterTokensConsumed(opts interface{}) *EVM2EVMOnRampInterface_FilterTokensConsumed_Call {
+ return &EVM2EVMOnRampInterface_FilterTokensConsumed_Call{Call: _e.mock.On("FilterTokensConsumed", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokensConsumed_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOnRampInterface_FilterTokensConsumed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokensConsumed_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumedIterator, _a1 error) *EVM2EVMOnRampInterface_FilterTokensConsumed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_FilterTokensConsumed_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_onramp.EVM2EVMOnRampTokensConsumedIterator, error)) *EVM2EVMOnRampInterface_FilterTokensConsumed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ForwardFromRouter provides a mock function with given fields: opts, destChainSelector, message, feeTokenAmount, originalSender
+func (_m *EVM2EVMOnRampInterface) ForwardFromRouter(opts *bind.TransactOpts, destChainSelector uint64, message evm_2_evm_onramp.ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, destChainSelector, message, feeTokenAmount, originalSender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ForwardFromRouter")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage, *big.Int, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, destChainSelector, message, feeTokenAmount, originalSender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage, *big.Int, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, destChainSelector, message, feeTokenAmount, originalSender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage, *big.Int, common.Address) error); ok {
+ r1 = rf(opts, destChainSelector, message, feeTokenAmount, originalSender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ForwardFromRouter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ForwardFromRouter'
+type EVM2EVMOnRampInterface_ForwardFromRouter_Call struct {
+ *mock.Call
+}
+
+// ForwardFromRouter is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - destChainSelector uint64
+// - message evm_2_evm_onramp.ClientEVM2AnyMessage
+// - feeTokenAmount *big.Int
+// - originalSender common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) ForwardFromRouter(opts interface{}, destChainSelector interface{}, message interface{}, feeTokenAmount interface{}, originalSender interface{}) *EVM2EVMOnRampInterface_ForwardFromRouter_Call {
+ return &EVM2EVMOnRampInterface_ForwardFromRouter_Call{Call: _e.mock.On("ForwardFromRouter", opts, destChainSelector, message, feeTokenAmount, originalSender)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ForwardFromRouter_Call) Run(run func(opts *bind.TransactOpts, destChainSelector uint64, message evm_2_evm_onramp.ClientEVM2AnyMessage, feeTokenAmount *big.Int, originalSender common.Address)) *EVM2EVMOnRampInterface_ForwardFromRouter_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(uint64), args[2].(evm_2_evm_onramp.ClientEVM2AnyMessage), args[3].(*big.Int), args[4].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ForwardFromRouter_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_ForwardFromRouter_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ForwardFromRouter_Call) RunAndReturn(run func(*bind.TransactOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage, *big.Int, common.Address) (*types.Transaction, error)) *EVM2EVMOnRampInterface_ForwardFromRouter_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDynamicConfig provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) GetDynamicConfig(opts *bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDynamicConfig")
+ }
+
+ var r0 evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetDynamicConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDynamicConfig'
+type EVM2EVMOnRampInterface_GetDynamicConfig_Call struct {
+ *mock.Call
+}
+
+// GetDynamicConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) GetDynamicConfig(opts interface{}) *EVM2EVMOnRampInterface_GetDynamicConfig_Call {
+ return &EVM2EVMOnRampInterface_GetDynamicConfig_Call{Call: _e.mock.On("GetDynamicConfig", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetDynamicConfig_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_GetDynamicConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetDynamicConfig_Call) Return(_a0 evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig, _a1 error) *EVM2EVMOnRampInterface_GetDynamicConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetDynamicConfig_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig, error)) *EVM2EVMOnRampInterface_GetDynamicConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetExpectedNextSequenceNumber provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetExpectedNextSequenceNumber")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExpectedNextSequenceNumber'
+type EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call struct {
+ *mock.Call
+}
+
+// GetExpectedNextSequenceNumber is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) GetExpectedNextSequenceNumber(opts interface{}) *EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call {
+ return &EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call{Call: _e.mock.On("GetExpectedNextSequenceNumber", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call) Return(_a0 uint64, _a1 error) *EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *EVM2EVMOnRampInterface_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetFee provides a mock function with given fields: opts, destChainSelector, message
+func (_m *EVM2EVMOnRampInterface) GetFee(opts *bind.CallOpts, destChainSelector uint64, message evm_2_evm_onramp.ClientEVM2AnyMessage) (*big.Int, error) {
+ ret := _m.Called(opts, destChainSelector, message)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetFee")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage) (*big.Int, error)); ok {
+ return rf(opts, destChainSelector, message)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage) *big.Int); ok {
+ r0 = rf(opts, destChainSelector, message)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage) error); ok {
+ r1 = rf(opts, destChainSelector, message)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetFee_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFee'
+type EVM2EVMOnRampInterface_GetFee_Call struct {
+ *mock.Call
+}
+
+// GetFee is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destChainSelector uint64
+// - message evm_2_evm_onramp.ClientEVM2AnyMessage
+func (_e *EVM2EVMOnRampInterface_Expecter) GetFee(opts interface{}, destChainSelector interface{}, message interface{}) *EVM2EVMOnRampInterface_GetFee_Call {
+ return &EVM2EVMOnRampInterface_GetFee_Call{Call: _e.mock.On("GetFee", opts, destChainSelector, message)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetFee_Call) Run(run func(opts *bind.CallOpts, destChainSelector uint64, message evm_2_evm_onramp.ClientEVM2AnyMessage)) *EVM2EVMOnRampInterface_GetFee_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64), args[2].(evm_2_evm_onramp.ClientEVM2AnyMessage))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetFee_Call) Return(_a0 *big.Int, _a1 error) *EVM2EVMOnRampInterface_GetFee_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetFee_Call) RunAndReturn(run func(*bind.CallOpts, uint64, evm_2_evm_onramp.ClientEVM2AnyMessage) (*big.Int, error)) *EVM2EVMOnRampInterface_GetFee_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetFeeTokenConfig provides a mock function with given fields: opts, token
+func (_m *EVM2EVMOnRampInterface) GetFeeTokenConfig(opts *bind.CallOpts, token common.Address) (evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetFeeTokenConfig")
+ }
+
+ var r0 evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig); ok {
+ r0 = rf(opts, token)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetFeeTokenConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeeTokenConfig'
+type EVM2EVMOnRampInterface_GetFeeTokenConfig_Call struct {
+ *mock.Call
+}
+
+// GetFeeTokenConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - token common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) GetFeeTokenConfig(opts interface{}, token interface{}) *EVM2EVMOnRampInterface_GetFeeTokenConfig_Call {
+ return &EVM2EVMOnRampInterface_GetFeeTokenConfig_Call{Call: _e.mock.On("GetFeeTokenConfig", opts, token)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetFeeTokenConfig_Call) Run(run func(opts *bind.CallOpts, token common.Address)) *EVM2EVMOnRampInterface_GetFeeTokenConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetFeeTokenConfig_Call) Return(_a0 evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig, _a1 error) *EVM2EVMOnRampInterface_GetFeeTokenConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetFeeTokenConfig_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfig, error)) *EVM2EVMOnRampInterface_GetFeeTokenConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetNopFeesJuels provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) GetNopFeesJuels(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetNopFeesJuels")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetNopFeesJuels_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNopFeesJuels'
+type EVM2EVMOnRampInterface_GetNopFeesJuels_Call struct {
+ *mock.Call
+}
+
+// GetNopFeesJuels is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) GetNopFeesJuels(opts interface{}) *EVM2EVMOnRampInterface_GetNopFeesJuels_Call {
+ return &EVM2EVMOnRampInterface_GetNopFeesJuels_Call{Call: _e.mock.On("GetNopFeesJuels", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetNopFeesJuels_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_GetNopFeesJuels_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetNopFeesJuels_Call) Return(_a0 *big.Int, _a1 error) *EVM2EVMOnRampInterface_GetNopFeesJuels_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetNopFeesJuels_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *EVM2EVMOnRampInterface_GetNopFeesJuels_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetNops provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) GetNops(opts *bind.CallOpts) (evm_2_evm_onramp.GetNops, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetNops")
+ }
+
+ var r0 evm_2_evm_onramp.GetNops
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_onramp.GetNops, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_onramp.GetNops); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_onramp.GetNops)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetNops_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNops'
+type EVM2EVMOnRampInterface_GetNops_Call struct {
+ *mock.Call
+}
+
+// GetNops is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) GetNops(opts interface{}) *EVM2EVMOnRampInterface_GetNops_Call {
+ return &EVM2EVMOnRampInterface_GetNops_Call{Call: _e.mock.On("GetNops", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetNops_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_GetNops_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetNops_Call) Return(_a0 evm_2_evm_onramp.GetNops, _a1 error) *EVM2EVMOnRampInterface_GetNops_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetNops_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_onramp.GetNops, error)) *EVM2EVMOnRampInterface_GetNops_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetPoolBySourceToken provides a mock function with given fields: opts, arg0, sourceToken
+func (_m *EVM2EVMOnRampInterface) GetPoolBySourceToken(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address) (common.Address, error) {
+ ret := _m.Called(opts, arg0, sourceToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetPoolBySourceToken")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address) (common.Address, error)); ok {
+ return rf(opts, arg0, sourceToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address) common.Address); ok {
+ r0 = rf(opts, arg0, sourceToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64, common.Address) error); ok {
+ r1 = rf(opts, arg0, sourceToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetPoolBySourceToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPoolBySourceToken'
+type EVM2EVMOnRampInterface_GetPoolBySourceToken_Call struct {
+ *mock.Call
+}
+
+// GetPoolBySourceToken is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - arg0 uint64
+// - sourceToken common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) GetPoolBySourceToken(opts interface{}, arg0 interface{}, sourceToken interface{}) *EVM2EVMOnRampInterface_GetPoolBySourceToken_Call {
+ return &EVM2EVMOnRampInterface_GetPoolBySourceToken_Call{Call: _e.mock.On("GetPoolBySourceToken", opts, arg0, sourceToken)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetPoolBySourceToken_Call) Run(run func(opts *bind.CallOpts, arg0 uint64, sourceToken common.Address)) *EVM2EVMOnRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64), args[2].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetPoolBySourceToken_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOnRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetPoolBySourceToken_Call) RunAndReturn(run func(*bind.CallOpts, uint64, common.Address) (common.Address, error)) *EVM2EVMOnRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSenderNonce provides a mock function with given fields: opts, sender
+func (_m *EVM2EVMOnRampInterface) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ ret := _m.Called(opts, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSenderNonce")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok {
+ return rf(opts, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) uint64); ok {
+ r0 = rf(opts, sender)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetSenderNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSenderNonce'
+type EVM2EVMOnRampInterface_GetSenderNonce_Call struct {
+ *mock.Call
+}
+
+// GetSenderNonce is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sender common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) GetSenderNonce(opts interface{}, sender interface{}) *EVM2EVMOnRampInterface_GetSenderNonce_Call {
+ return &EVM2EVMOnRampInterface_GetSenderNonce_Call{Call: _e.mock.On("GetSenderNonce", opts, sender)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetSenderNonce_Call) Run(run func(opts *bind.CallOpts, sender common.Address)) *EVM2EVMOnRampInterface_GetSenderNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetSenderNonce_Call) Return(_a0 uint64, _a1 error) *EVM2EVMOnRampInterface_GetSenderNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetSenderNonce_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (uint64, error)) *EVM2EVMOnRampInterface_GetSenderNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStaticConfig provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) GetStaticConfig(opts *bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampStaticConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStaticConfig")
+ }
+
+ var r0 evm_2_evm_onramp.EVM2EVMOnRampStaticConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampStaticConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_onramp.EVM2EVMOnRampStaticConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_onramp.EVM2EVMOnRampStaticConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetStaticConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStaticConfig'
+type EVM2EVMOnRampInterface_GetStaticConfig_Call struct {
+ *mock.Call
+}
+
+// GetStaticConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) GetStaticConfig(opts interface{}) *EVM2EVMOnRampInterface_GetStaticConfig_Call {
+ return &EVM2EVMOnRampInterface_GetStaticConfig_Call{Call: _e.mock.On("GetStaticConfig", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetStaticConfig_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_GetStaticConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetStaticConfig_Call) Return(_a0 evm_2_evm_onramp.EVM2EVMOnRampStaticConfig, _a1 error) *EVM2EVMOnRampInterface_GetStaticConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetStaticConfig_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_onramp.EVM2EVMOnRampStaticConfig, error)) *EVM2EVMOnRampInterface_GetStaticConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSupportedTokens provides a mock function with given fields: opts, arg0
+func (_m *EVM2EVMOnRampInterface) GetSupportedTokens(opts *bind.CallOpts, arg0 uint64) ([]common.Address, error) {
+ ret := _m.Called(opts, arg0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSupportedTokens")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) ([]common.Address, error)); ok {
+ return rf(opts, arg0)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) []common.Address); ok {
+ r0 = rf(opts, arg0)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, arg0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetSupportedTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSupportedTokens'
+type EVM2EVMOnRampInterface_GetSupportedTokens_Call struct {
+ *mock.Call
+}
+
+// GetSupportedTokens is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - arg0 uint64
+func (_e *EVM2EVMOnRampInterface_Expecter) GetSupportedTokens(opts interface{}, arg0 interface{}) *EVM2EVMOnRampInterface_GetSupportedTokens_Call {
+ return &EVM2EVMOnRampInterface_GetSupportedTokens_Call{Call: _e.mock.On("GetSupportedTokens", opts, arg0)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetSupportedTokens_Call) Run(run func(opts *bind.CallOpts, arg0 uint64)) *EVM2EVMOnRampInterface_GetSupportedTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetSupportedTokens_Call) Return(_a0 []common.Address, _a1 error) *EVM2EVMOnRampInterface_GetSupportedTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetSupportedTokens_Call) RunAndReturn(run func(*bind.CallOpts, uint64) ([]common.Address, error)) *EVM2EVMOnRampInterface_GetSupportedTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenLimitAdmin provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenLimitAdmin")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenLimitAdmin'
+type EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call struct {
+ *mock.Call
+}
+
+// GetTokenLimitAdmin is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) GetTokenLimitAdmin(opts interface{}) *EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call {
+ return &EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call{Call: _e.mock.On("GetTokenLimitAdmin", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *EVM2EVMOnRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenTransferFeeConfig provides a mock function with given fields: opts, token
+func (_m *EVM2EVMOnRampInterface) GetTokenTransferFeeConfig(opts *bind.CallOpts, token common.Address) (evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenTransferFeeConfig")
+ }
+
+ var r0 evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig); ok {
+ r0 = rf(opts, token)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenTransferFeeConfig'
+type EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call struct {
+ *mock.Call
+}
+
+// GetTokenTransferFeeConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - token common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) GetTokenTransferFeeConfig(opts interface{}, token interface{}) *EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call {
+ return &EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call{Call: _e.mock.On("GetTokenTransferFeeConfig", opts, token)}
+}
+
+func (_c *EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call) Run(run func(opts *bind.CallOpts, token common.Address)) *EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call) Return(_a0 evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig, _a1 error) *EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfig, error)) *EVM2EVMOnRampInterface_GetTokenTransferFeeConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LinkAvailableForPayment provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LinkAvailableForPayment")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_LinkAvailableForPayment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LinkAvailableForPayment'
+type EVM2EVMOnRampInterface_LinkAvailableForPayment_Call struct {
+ *mock.Call
+}
+
+// LinkAvailableForPayment is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) LinkAvailableForPayment(opts interface{}) *EVM2EVMOnRampInterface_LinkAvailableForPayment_Call {
+ return &EVM2EVMOnRampInterface_LinkAvailableForPayment_Call{Call: _e.mock.On("LinkAvailableForPayment", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_LinkAvailableForPayment_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_LinkAvailableForPayment_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_LinkAvailableForPayment_Call) Return(_a0 *big.Int, _a1 error) *EVM2EVMOnRampInterface_LinkAvailableForPayment_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_LinkAvailableForPayment_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *EVM2EVMOnRampInterface_LinkAvailableForPayment_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Owner provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) Owner(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Owner")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_Owner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Owner'
+type EVM2EVMOnRampInterface_Owner_Call struct {
+ *mock.Call
+}
+
+// Owner is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) Owner(opts interface{}) *EVM2EVMOnRampInterface_Owner_Call {
+ return &EVM2EVMOnRampInterface_Owner_Call{Call: _e.mock.On("Owner", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_Owner_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_Owner_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_Owner_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOnRampInterface_Owner_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_Owner_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *EVM2EVMOnRampInterface_Owner_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseAdminSet provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseAdminSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseAdminSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampAdminSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampAdminSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampAdminSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseAdminSet'
+type EVM2EVMOnRampInterface_ParseAdminSet_Call struct {
+ *mock.Call
+}
+
+// ParseAdminSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseAdminSet(log interface{}) *EVM2EVMOnRampInterface_ParseAdminSet_Call {
+ return &EVM2EVMOnRampInterface_ParseAdminSet_Call{Call: _e.mock.On("ParseAdminSet", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseAdminSet_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseAdminSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampAdminSet, _a1 error) *EVM2EVMOnRampInterface_ParseAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseAdminSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampAdminSet, error)) *EVM2EVMOnRampInterface_ParseAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseCCIPSendRequested provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseCCIPSendRequested(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseCCIPSendRequested")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseCCIPSendRequested'
+type EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call struct {
+ *mock.Call
+}
+
+// ParseCCIPSendRequested is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseCCIPSendRequested(log interface{}) *EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call {
+ return &EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call{Call: _e.mock.On("ParseCCIPSendRequested", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested, _a1 error) *EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested, error)) *EVM2EVMOnRampInterface_ParseCCIPSendRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigChanged provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseConfigChanged(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampConfigChanged, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigChanged")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampConfigChanged, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampConfigChanged)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseConfigChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigChanged'
+type EVM2EVMOnRampInterface_ParseConfigChanged_Call struct {
+ *mock.Call
+}
+
+// ParseConfigChanged is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseConfigChanged(log interface{}) *EVM2EVMOnRampInterface_ParseConfigChanged_Call {
+ return &EVM2EVMOnRampInterface_ParseConfigChanged_Call{Call: _e.mock.On("ParseConfigChanged", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseConfigChanged_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseConfigChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseConfigChanged_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged, _a1 error) *EVM2EVMOnRampInterface_ParseConfigChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseConfigChanged_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampConfigChanged, error)) *EVM2EVMOnRampInterface_ParseConfigChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseConfigSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampConfigSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampConfigSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampConfigSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet'
+type EVM2EVMOnRampInterface_ParseConfigSet_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseConfigSet(log interface{}) *EVM2EVMOnRampInterface_ParseConfigSet_Call {
+ return &EVM2EVMOnRampInterface_ParseConfigSet_Call{Call: _e.mock.On("ParseConfigSet", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseConfigSet_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseConfigSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampConfigSet, _a1 error) *EVM2EVMOnRampInterface_ParseConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseConfigSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampConfigSet, error)) *EVM2EVMOnRampInterface_ParseConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseFeeConfigSet provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseFeeConfigSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseFeeConfigSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseFeeConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseFeeConfigSet'
+type EVM2EVMOnRampInterface_ParseFeeConfigSet_Call struct {
+ *mock.Call
+}
+
+// ParseFeeConfigSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseFeeConfigSet(log interface{}) *EVM2EVMOnRampInterface_ParseFeeConfigSet_Call {
+ return &EVM2EVMOnRampInterface_ParseFeeConfigSet_Call{Call: _e.mock.On("ParseFeeConfigSet", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseFeeConfigSet_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseFeeConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseFeeConfigSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet, _a1 error) *EVM2EVMOnRampInterface_ParseFeeConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseFeeConfigSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet, error)) *EVM2EVMOnRampInterface_ParseFeeConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type EVM2EVMOnRampInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseLog(log interface{}) *EVM2EVMOnRampInterface_ParseLog_Call {
+ return &EVM2EVMOnRampInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseLog_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *EVM2EVMOnRampInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *EVM2EVMOnRampInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseNopPaid provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseNopPaid(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaid, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseNopPaid")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampNopPaid
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaid, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampNopPaid); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampNopPaid)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseNopPaid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseNopPaid'
+type EVM2EVMOnRampInterface_ParseNopPaid_Call struct {
+ *mock.Call
+}
+
+// ParseNopPaid is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseNopPaid(log interface{}) *EVM2EVMOnRampInterface_ParseNopPaid_Call {
+ return &EVM2EVMOnRampInterface_ParseNopPaid_Call{Call: _e.mock.On("ParseNopPaid", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseNopPaid_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseNopPaid_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseNopPaid_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, _a1 error) *EVM2EVMOnRampInterface_ParseNopPaid_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseNopPaid_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopPaid, error)) *EVM2EVMOnRampInterface_ParseNopPaid_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseNopsSet provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseNopsSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseNopsSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampNopsSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampNopsSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampNopsSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseNopsSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseNopsSet'
+type EVM2EVMOnRampInterface_ParseNopsSet_Call struct {
+ *mock.Call
+}
+
+// ParseNopsSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseNopsSet(log interface{}) *EVM2EVMOnRampInterface_ParseNopsSet_Call {
+ return &EVM2EVMOnRampInterface_ParseNopsSet_Call{Call: _e.mock.On("ParseNopsSet", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseNopsSet_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseNopsSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseNopsSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampNopsSet, _a1 error) *EVM2EVMOnRampInterface_ParseNopsSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseNopsSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampNopsSet, error)) *EVM2EVMOnRampInterface_ParseNopsSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferRequested provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseOwnershipTransferRequested(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferRequested")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferRequested'
+type EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferRequested is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseOwnershipTransferRequested(log interface{}) *EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call {
+ return &EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call{Call: _e.mock.On("ParseOwnershipTransferRequested", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, _a1 error) *EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, error)) *EVM2EVMOnRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferred provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseOwnershipTransferred(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferred")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferred'
+type EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferred is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseOwnershipTransferred(log interface{}) *EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call {
+ return &EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call{Call: _e.mock.On("ParseOwnershipTransferred", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, _a1 error) *EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, error)) *EVM2EVMOnRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTokenTransferFeeConfigDeleted provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseTokenTransferFeeConfigDeleted(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTokenTransferFeeConfigDeleted")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTokenTransferFeeConfigDeleted'
+type EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call struct {
+ *mock.Call
+}
+
+// ParseTokenTransferFeeConfigDeleted is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseTokenTransferFeeConfigDeleted(log interface{}) *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call {
+ return &EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call{Call: _e.mock.On("ParseTokenTransferFeeConfigDeleted", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted, _a1 error) *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted, error)) *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTokenTransferFeeConfigSet provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseTokenTransferFeeConfigSet(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTokenTransferFeeConfigSet")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTokenTransferFeeConfigSet'
+type EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call struct {
+ *mock.Call
+}
+
+// ParseTokenTransferFeeConfigSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseTokenTransferFeeConfigSet(log interface{}) *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call {
+ return &EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call{Call: _e.mock.On("ParseTokenTransferFeeConfigSet", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet, _a1 error) *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet, error)) *EVM2EVMOnRampInterface_ParseTokenTransferFeeConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTokensConsumed provides a mock function with given fields: log
+func (_m *EVM2EVMOnRampInterface) ParseTokensConsumed(log types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTokensConsumed")
+ }
+
+ var r0 *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_ParseTokensConsumed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTokensConsumed'
+type EVM2EVMOnRampInterface_ParseTokensConsumed_Call struct {
+ *mock.Call
+}
+
+// ParseTokensConsumed is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOnRampInterface_Expecter) ParseTokensConsumed(log interface{}) *EVM2EVMOnRampInterface_ParseTokensConsumed_Call {
+ return &EVM2EVMOnRampInterface_ParseTokensConsumed_Call{Call: _e.mock.On("ParseTokensConsumed", log)}
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokensConsumed_Call) Run(run func(log types.Log)) *EVM2EVMOnRampInterface_ParseTokensConsumed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokensConsumed_Call) Return(_a0 *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed, _a1 error) *EVM2EVMOnRampInterface_ParseTokensConsumed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_ParseTokensConsumed_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed, error)) *EVM2EVMOnRampInterface_ParseTokensConsumed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// PayNops provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) PayNops(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for PayNops")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_PayNops_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PayNops'
+type EVM2EVMOnRampInterface_PayNops_Call struct {
+ *mock.Call
+}
+
+// PayNops is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) PayNops(opts interface{}) *EVM2EVMOnRampInterface_PayNops_Call {
+ return &EVM2EVMOnRampInterface_PayNops_Call{Call: _e.mock.On("PayNops", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_PayNops_Call) Run(run func(opts *bind.TransactOpts)) *EVM2EVMOnRampInterface_PayNops_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_PayNops_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_PayNops_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_PayNops_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *EVM2EVMOnRampInterface_PayNops_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetAdmin provides a mock function with given fields: opts, newAdmin
+func (_m *EVM2EVMOnRampInterface) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, newAdmin)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetAdmin")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, newAdmin)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, newAdmin)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, newAdmin)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_SetAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAdmin'
+type EVM2EVMOnRampInterface_SetAdmin_Call struct {
+ *mock.Call
+}
+
+// SetAdmin is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - newAdmin common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) SetAdmin(opts interface{}, newAdmin interface{}) *EVM2EVMOnRampInterface_SetAdmin_Call {
+ return &EVM2EVMOnRampInterface_SetAdmin_Call{Call: _e.mock.On("SetAdmin", opts, newAdmin)}
+}
+
+func (_c *EVM2EVMOnRampInterface_SetAdmin_Call) Run(run func(opts *bind.TransactOpts, newAdmin common.Address)) *EVM2EVMOnRampInterface_SetAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetAdmin_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_SetAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetAdmin_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *EVM2EVMOnRampInterface_SetAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetDynamicConfig provides a mock function with given fields: opts, dynamicConfig
+func (_m *EVM2EVMOnRampInterface) SetDynamicConfig(opts *bind.TransactOpts, dynamicConfig evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig) (*types.Transaction, error) {
+ ret := _m.Called(opts, dynamicConfig)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetDynamicConfig")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig) (*types.Transaction, error)); ok {
+ return rf(opts, dynamicConfig)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig) *types.Transaction); ok {
+ r0 = rf(opts, dynamicConfig)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig) error); ok {
+ r1 = rf(opts, dynamicConfig)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_SetDynamicConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetDynamicConfig'
+type EVM2EVMOnRampInterface_SetDynamicConfig_Call struct {
+ *mock.Call
+}
+
+// SetDynamicConfig is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - dynamicConfig evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig
+func (_e *EVM2EVMOnRampInterface_Expecter) SetDynamicConfig(opts interface{}, dynamicConfig interface{}) *EVM2EVMOnRampInterface_SetDynamicConfig_Call {
+ return &EVM2EVMOnRampInterface_SetDynamicConfig_Call{Call: _e.mock.On("SetDynamicConfig", opts, dynamicConfig)}
+}
+
+func (_c *EVM2EVMOnRampInterface_SetDynamicConfig_Call) Run(run func(opts *bind.TransactOpts, dynamicConfig evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig)) *EVM2EVMOnRampInterface_SetDynamicConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetDynamicConfig_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_SetDynamicConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetDynamicConfig_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig) (*types.Transaction, error)) *EVM2EVMOnRampInterface_SetDynamicConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetFeeTokenConfig provides a mock function with given fields: opts, feeTokenConfigArgs
+func (_m *EVM2EVMOnRampInterface) SetFeeTokenConfig(opts *bind.TransactOpts, feeTokenConfigArgs []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error) {
+ ret := _m.Called(opts, feeTokenConfigArgs)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetFeeTokenConfig")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error)); ok {
+ return rf(opts, feeTokenConfigArgs)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs) *types.Transaction); ok {
+ r0 = rf(opts, feeTokenConfigArgs)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs) error); ok {
+ r1 = rf(opts, feeTokenConfigArgs)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_SetFeeTokenConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetFeeTokenConfig'
+type EVM2EVMOnRampInterface_SetFeeTokenConfig_Call struct {
+ *mock.Call
+}
+
+// SetFeeTokenConfig is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - feeTokenConfigArgs []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs
+func (_e *EVM2EVMOnRampInterface_Expecter) SetFeeTokenConfig(opts interface{}, feeTokenConfigArgs interface{}) *EVM2EVMOnRampInterface_SetFeeTokenConfig_Call {
+ return &EVM2EVMOnRampInterface_SetFeeTokenConfig_Call{Call: _e.mock.On("SetFeeTokenConfig", opts, feeTokenConfigArgs)}
+}
+
+func (_c *EVM2EVMOnRampInterface_SetFeeTokenConfig_Call) Run(run func(opts *bind.TransactOpts, feeTokenConfigArgs []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs)) *EVM2EVMOnRampInterface_SetFeeTokenConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetFeeTokenConfig_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_SetFeeTokenConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetFeeTokenConfig_Call) RunAndReturn(run func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs) (*types.Transaction, error)) *EVM2EVMOnRampInterface_SetFeeTokenConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetNops provides a mock function with given fields: opts, nopsAndWeights
+func (_m *EVM2EVMOnRampInterface) SetNops(opts *bind.TransactOpts, nopsAndWeights []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) (*types.Transaction, error) {
+ ret := _m.Called(opts, nopsAndWeights)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetNops")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) (*types.Transaction, error)); ok {
+ return rf(opts, nopsAndWeights)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) *types.Transaction); ok {
+ r0 = rf(opts, nopsAndWeights)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) error); ok {
+ r1 = rf(opts, nopsAndWeights)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_SetNops_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetNops'
+type EVM2EVMOnRampInterface_SetNops_Call struct {
+ *mock.Call
+}
+
+// SetNops is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - nopsAndWeights []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight
+func (_e *EVM2EVMOnRampInterface_Expecter) SetNops(opts interface{}, nopsAndWeights interface{}) *EVM2EVMOnRampInterface_SetNops_Call {
+ return &EVM2EVMOnRampInterface_SetNops_Call{Call: _e.mock.On("SetNops", opts, nopsAndWeights)}
+}
+
+func (_c *EVM2EVMOnRampInterface_SetNops_Call) Run(run func(opts *bind.TransactOpts, nopsAndWeights []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight)) *EVM2EVMOnRampInterface_SetNops_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetNops_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_SetNops_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetNops_Call) RunAndReturn(run func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) (*types.Transaction, error)) *EVM2EVMOnRampInterface_SetNops_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetRateLimiterConfig provides a mock function with given fields: opts, config
+func (_m *EVM2EVMOnRampInterface) SetRateLimiterConfig(opts *bind.TransactOpts, config evm_2_evm_onramp.RateLimiterConfig) (*types.Transaction, error) {
+ ret := _m.Called(opts, config)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetRateLimiterConfig")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_onramp.RateLimiterConfig) (*types.Transaction, error)); ok {
+ return rf(opts, config)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_onramp.RateLimiterConfig) *types.Transaction); ok {
+ r0 = rf(opts, config)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_onramp.RateLimiterConfig) error); ok {
+ r1 = rf(opts, config)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_SetRateLimiterConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetRateLimiterConfig'
+type EVM2EVMOnRampInterface_SetRateLimiterConfig_Call struct {
+ *mock.Call
+}
+
+// SetRateLimiterConfig is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - config evm_2_evm_onramp.RateLimiterConfig
+func (_e *EVM2EVMOnRampInterface_Expecter) SetRateLimiterConfig(opts interface{}, config interface{}) *EVM2EVMOnRampInterface_SetRateLimiterConfig_Call {
+ return &EVM2EVMOnRampInterface_SetRateLimiterConfig_Call{Call: _e.mock.On("SetRateLimiterConfig", opts, config)}
+}
+
+func (_c *EVM2EVMOnRampInterface_SetRateLimiterConfig_Call) Run(run func(opts *bind.TransactOpts, config evm_2_evm_onramp.RateLimiterConfig)) *EVM2EVMOnRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_onramp.RateLimiterConfig))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetRateLimiterConfig_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetRateLimiterConfig_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_onramp.RateLimiterConfig) (*types.Transaction, error)) *EVM2EVMOnRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetTokenTransferFeeConfig provides a mock function with given fields: opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs
+func (_m *EVM2EVMOnRampInterface) SetTokenTransferFeeConfig(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetTokenTransferFeeConfig")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs, []common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs, []common.Address) *types.Transaction); ok {
+ r0 = rf(opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs, []common.Address) error); ok {
+ r1 = rf(opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetTokenTransferFeeConfig'
+type EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call struct {
+ *mock.Call
+}
+
+// SetTokenTransferFeeConfig is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - tokenTransferFeeConfigArgs []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs
+// - tokensToUseDefaultFeeConfigs []common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) SetTokenTransferFeeConfig(opts interface{}, tokenTransferFeeConfigArgs interface{}, tokensToUseDefaultFeeConfigs interface{}) *EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call {
+ return &EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call{Call: _e.mock.On("SetTokenTransferFeeConfig", opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)}
+}
+
+func (_c *EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call) Run(run func(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []common.Address)) *EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call) RunAndReturn(run func(*bind.TransactOpts, []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs, []common.Address) (*types.Transaction, error)) *EVM2EVMOnRampInterface_SetTokenTransferFeeConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TransferOwnership provides a mock function with given fields: opts, to
+func (_m *EVM2EVMOnRampInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TransferOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_TransferOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferOwnership'
+type EVM2EVMOnRampInterface_TransferOwnership_Call struct {
+ *mock.Call
+}
+
+// TransferOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - to common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) TransferOwnership(opts interface{}, to interface{}) *EVM2EVMOnRampInterface_TransferOwnership_Call {
+ return &EVM2EVMOnRampInterface_TransferOwnership_Call{Call: _e.mock.On("TransferOwnership", opts, to)}
+}
+
+func (_c *EVM2EVMOnRampInterface_TransferOwnership_Call) Run(run func(opts *bind.TransactOpts, to common.Address)) *EVM2EVMOnRampInterface_TransferOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_TransferOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_TransferOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_TransferOwnership_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *EVM2EVMOnRampInterface_TransferOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TypeAndVersion provides a mock function with given fields: opts
+func (_m *EVM2EVMOnRampInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TypeAndVersion")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_TypeAndVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TypeAndVersion'
+type EVM2EVMOnRampInterface_TypeAndVersion_Call struct {
+ *mock.Call
+}
+
+// TypeAndVersion is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOnRampInterface_Expecter) TypeAndVersion(opts interface{}) *EVM2EVMOnRampInterface_TypeAndVersion_Call {
+ return &EVM2EVMOnRampInterface_TypeAndVersion_Call{Call: _e.mock.On("TypeAndVersion", opts)}
+}
+
+func (_c *EVM2EVMOnRampInterface_TypeAndVersion_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOnRampInterface_TypeAndVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_TypeAndVersion_Call) Return(_a0 string, _a1 error) *EVM2EVMOnRampInterface_TypeAndVersion_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_TypeAndVersion_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *EVM2EVMOnRampInterface_TypeAndVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchAdminSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchAdminSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAdminSet'
+type EVM2EVMOnRampInterface_WatchAdminSet_Call struct {
+ *mock.Call
+}
+
+// WatchAdminSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchAdminSet(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchAdminSet_Call {
+ return &EVM2EVMOnRampInterface_WatchAdminSet_Call{Call: _e.mock.On("WatchAdminSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchAdminSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet)) *EVM2EVMOnRampInterface_WatchAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchAdminSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchAdminSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampAdminSet) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchCCIPSendRequested provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchCCIPSendRequested(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchCCIPSendRequested")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchCCIPSendRequested'
+type EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call struct {
+ *mock.Call
+}
+
+// WatchCCIPSendRequested is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchCCIPSendRequested(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call {
+ return &EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call{Call: _e.mock.On("WatchCCIPSendRequested", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested)) *EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchCCIPSendRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigChanged provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigChanged")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchConfigChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigChanged'
+type EVM2EVMOnRampInterface_WatchConfigChanged_Call struct {
+ *mock.Call
+}
+
+// WatchConfigChanged is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchConfigChanged(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchConfigChanged_Call {
+ return &EVM2EVMOnRampInterface_WatchConfigChanged_Call{Call: _e.mock.On("WatchConfigChanged", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchConfigChanged_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged)) *EVM2EVMOnRampInterface_WatchConfigChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchConfigChanged_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchConfigChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchConfigChanged_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigChanged) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchConfigChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet'
+type EVM2EVMOnRampInterface_WatchConfigSet_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchConfigSet(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchConfigSet_Call {
+ return &EVM2EVMOnRampInterface_WatchConfigSet_Call{Call: _e.mock.On("WatchConfigSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchConfigSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet)) *EVM2EVMOnRampInterface_WatchConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchConfigSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchConfigSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampConfigSet) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchFeeConfigSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchFeeConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchFeeConfigSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchFeeConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchFeeConfigSet'
+type EVM2EVMOnRampInterface_WatchFeeConfigSet_Call struct {
+ *mock.Call
+}
+
+// WatchFeeConfigSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchFeeConfigSet(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchFeeConfigSet_Call {
+ return &EVM2EVMOnRampInterface_WatchFeeConfigSet_Call{Call: _e.mock.On("WatchFeeConfigSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchFeeConfigSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet)) *EVM2EVMOnRampInterface_WatchFeeConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchFeeConfigSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchFeeConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchFeeConfigSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampFeeConfigSet) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchFeeConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchNopPaid provides a mock function with given fields: opts, sink, nop
+func (_m *EVM2EVMOnRampInterface) WatchNopPaid(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, nop []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nop)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchNopPaid")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, nop)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, nop)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, []common.Address) error); ok {
+ r1 = rf(opts, sink, nop)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchNopPaid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchNopPaid'
+type EVM2EVMOnRampInterface_WatchNopPaid_Call struct {
+ *mock.Call
+}
+
+// WatchNopPaid is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid
+// - nop []common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchNopPaid(opts interface{}, sink interface{}, nop interface{}) *EVM2EVMOnRampInterface_WatchNopPaid_Call {
+ return &EVM2EVMOnRampInterface_WatchNopPaid_Call{Call: _e.mock.On("WatchNopPaid", opts, sink, nop)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchNopPaid_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, nop []common.Address)) *EVM2EVMOnRampInterface_WatchNopPaid_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchNopPaid_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchNopPaid_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchNopPaid_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopPaid, []common.Address) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchNopPaid_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchNopsSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchNopsSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchNopsSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchNopsSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchNopsSet'
+type EVM2EVMOnRampInterface_WatchNopsSet_Call struct {
+ *mock.Call
+}
+
+// WatchNopsSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchNopsSet(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchNopsSet_Call {
+ return &EVM2EVMOnRampInterface_WatchNopsSet_Call{Call: _e.mock.On("WatchNopsSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchNopsSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet)) *EVM2EVMOnRampInterface_WatchNopsSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchNopsSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchNopsSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchNopsSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampNopsSet) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchNopsSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to
+func (_m *EVM2EVMOnRampInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferRequested")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferRequested'
+type EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchOwnershipTransferRequested(opts interface{}, sink interface{}, from interface{}, to interface{}) *EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call {
+ return &EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call{Call: _e.mock.On("WatchOwnershipTransferRequested", opts, sink, from, to)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, from []common.Address, to []common.Address)) *EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to
+func (_m *EVM2EVMOnRampInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferred")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferred'
+type EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchOwnershipTransferred(opts interface{}, sink interface{}, from interface{}, to interface{}) *EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call {
+ return &EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call{Call: _e.mock.On("WatchOwnershipTransferred", opts, sink, from, to)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, from []common.Address, to []common.Address)) *EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTokenTransferFeeConfigDeleted provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchTokenTransferFeeConfigDeleted(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTokenTransferFeeConfigDeleted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTokenTransferFeeConfigDeleted'
+type EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call struct {
+ *mock.Call
+}
+
+// WatchTokenTransferFeeConfigDeleted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchTokenTransferFeeConfigDeleted(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call {
+ return &EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call{Call: _e.mock.On("WatchTokenTransferFeeConfigDeleted", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted)) *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigDeleted) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTokenTransferFeeConfigSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchTokenTransferFeeConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTokenTransferFeeConfigSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTokenTransferFeeConfigSet'
+type EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call struct {
+ *mock.Call
+}
+
+// WatchTokenTransferFeeConfigSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchTokenTransferFeeConfigSet(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call {
+ return &EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call{Call: _e.mock.On("WatchTokenTransferFeeConfigSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet)) *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigSet) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchTokenTransferFeeConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTokensConsumed provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOnRampInterface) WatchTokensConsumed(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTokensConsumed")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WatchTokensConsumed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTokensConsumed'
+type EVM2EVMOnRampInterface_WatchTokensConsumed_Call struct {
+ *mock.Call
+}
+
+// WatchTokensConsumed is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed
+func (_e *EVM2EVMOnRampInterface_Expecter) WatchTokensConsumed(opts interface{}, sink interface{}) *EVM2EVMOnRampInterface_WatchTokensConsumed_Call {
+ return &EVM2EVMOnRampInterface_WatchTokensConsumed_Call{Call: _e.mock.On("WatchTokensConsumed", opts, sink)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokensConsumed_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed)) *EVM2EVMOnRampInterface_WatchTokensConsumed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokensConsumed_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOnRampInterface_WatchTokensConsumed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WatchTokensConsumed_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_onramp.EVM2EVMOnRampTokensConsumed) (event.Subscription, error)) *EVM2EVMOnRampInterface_WatchTokensConsumed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WithdrawNonLinkFees provides a mock function with given fields: opts, feeToken, to
+func (_m *EVM2EVMOnRampInterface) WithdrawNonLinkFees(opts *bind.TransactOpts, feeToken common.Address, to common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, feeToken, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WithdrawNonLinkFees")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, feeToken, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, feeToken, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address) error); ok {
+ r1 = rf(opts, feeToken, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithdrawNonLinkFees'
+type EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call struct {
+ *mock.Call
+}
+
+// WithdrawNonLinkFees is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - feeToken common.Address
+// - to common.Address
+func (_e *EVM2EVMOnRampInterface_Expecter) WithdrawNonLinkFees(opts interface{}, feeToken interface{}, to interface{}) *EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call {
+ return &EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call{Call: _e.mock.On("WithdrawNonLinkFees", opts, feeToken, to)}
+}
+
+func (_c *EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call) Run(run func(opts *bind.TransactOpts, feeToken common.Address, to common.Address)) *EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)) *EVM2EVMOnRampInterface_WithdrawNonLinkFees_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewEVM2EVMOnRampInterface creates a new instance of EVM2EVMOnRampInterface. 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 NewEVM2EVMOnRampInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *EVM2EVMOnRampInterface {
+ mock := &EVM2EVMOnRampInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/ccip/mocks/link_token_interface.go b/core/gethwrappers/ccip/mocks/link_token_interface.go
new file mode 100644
index 00000000000..efb4507f58e
--- /dev/null
+++ b/core/gethwrappers/ccip/mocks/link_token_interface.go
@@ -0,0 +1,1217 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_contracts
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ link_token_interface "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// LinkTokenInterface is an autogenerated mock type for the LinkTokenInterface type
+type LinkTokenInterface struct {
+ mock.Mock
+}
+
+type LinkTokenInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *LinkTokenInterface) EXPECT() *LinkTokenInterface_Expecter {
+ return &LinkTokenInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *LinkTokenInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// LinkTokenInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type LinkTokenInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *LinkTokenInterface_Expecter) Address() *LinkTokenInterface_Address_Call {
+ return &LinkTokenInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *LinkTokenInterface_Address_Call) Run(run func()) *LinkTokenInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_Address_Call) Return(_a0 common.Address) *LinkTokenInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *LinkTokenInterface_Address_Call) RunAndReturn(run func() common.Address) *LinkTokenInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Allowance provides a mock function with given fields: opts, _owner, _spender
+func (_m *LinkTokenInterface) Allowance(opts *bind.CallOpts, _owner common.Address, _spender common.Address) (*big.Int, error) {
+ ret := _m.Called(opts, _owner, _spender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Allowance")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address) (*big.Int, error)); ok {
+ return rf(opts, _owner, _spender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address) *big.Int); ok {
+ r0 = rf(opts, _owner, _spender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address, common.Address) error); ok {
+ r1 = rf(opts, _owner, _spender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_Allowance_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Allowance'
+type LinkTokenInterface_Allowance_Call struct {
+ *mock.Call
+}
+
+// Allowance is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - _owner common.Address
+// - _spender common.Address
+func (_e *LinkTokenInterface_Expecter) Allowance(opts interface{}, _owner interface{}, _spender interface{}) *LinkTokenInterface_Allowance_Call {
+ return &LinkTokenInterface_Allowance_Call{Call: _e.mock.On("Allowance", opts, _owner, _spender)}
+}
+
+func (_c *LinkTokenInterface_Allowance_Call) Run(run func(opts *bind.CallOpts, _owner common.Address, _spender common.Address)) *LinkTokenInterface_Allowance_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address), args[2].(common.Address))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_Allowance_Call) Return(_a0 *big.Int, _a1 error) *LinkTokenInterface_Allowance_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_Allowance_Call) RunAndReturn(run func(*bind.CallOpts, common.Address, common.Address) (*big.Int, error)) *LinkTokenInterface_Allowance_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Approve provides a mock function with given fields: opts, _spender, _value
+func (_m *LinkTokenInterface) Approve(opts *bind.TransactOpts, _spender common.Address, _value *big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, _spender, _value)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Approve")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, _spender, _value)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) *types.Transaction); ok {
+ r0 = rf(opts, _spender, _value)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int) error); ok {
+ r1 = rf(opts, _spender, _value)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_Approve_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Approve'
+type LinkTokenInterface_Approve_Call struct {
+ *mock.Call
+}
+
+// Approve is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _spender common.Address
+// - _value *big.Int
+func (_e *LinkTokenInterface_Expecter) Approve(opts interface{}, _spender interface{}, _value interface{}) *LinkTokenInterface_Approve_Call {
+ return &LinkTokenInterface_Approve_Call{Call: _e.mock.On("Approve", opts, _spender, _value)}
+}
+
+func (_c *LinkTokenInterface_Approve_Call) Run(run func(opts *bind.TransactOpts, _spender common.Address, _value *big.Int)) *LinkTokenInterface_Approve_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_Approve_Call) Return(_a0 *types.Transaction, _a1 error) *LinkTokenInterface_Approve_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_Approve_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)) *LinkTokenInterface_Approve_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// BalanceOf provides a mock function with given fields: opts, _owner
+func (_m *LinkTokenInterface) BalanceOf(opts *bind.CallOpts, _owner common.Address) (*big.Int, error) {
+ ret := _m.Called(opts, _owner)
+
+ if len(ret) == 0 {
+ panic("no return value specified for BalanceOf")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok {
+ return rf(opts, _owner)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) *big.Int); ok {
+ r0 = rf(opts, _owner)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, _owner)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_BalanceOf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BalanceOf'
+type LinkTokenInterface_BalanceOf_Call struct {
+ *mock.Call
+}
+
+// BalanceOf is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - _owner common.Address
+func (_e *LinkTokenInterface_Expecter) BalanceOf(opts interface{}, _owner interface{}) *LinkTokenInterface_BalanceOf_Call {
+ return &LinkTokenInterface_BalanceOf_Call{Call: _e.mock.On("BalanceOf", opts, _owner)}
+}
+
+func (_c *LinkTokenInterface_BalanceOf_Call) Run(run func(opts *bind.CallOpts, _owner common.Address)) *LinkTokenInterface_BalanceOf_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_BalanceOf_Call) Return(_a0 *big.Int, _a1 error) *LinkTokenInterface_BalanceOf_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_BalanceOf_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (*big.Int, error)) *LinkTokenInterface_BalanceOf_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Decimals provides a mock function with given fields: opts
+func (_m *LinkTokenInterface) Decimals(opts *bind.CallOpts) (uint8, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Decimals")
+ }
+
+ var r0 uint8
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint8); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint8)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_Decimals_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Decimals'
+type LinkTokenInterface_Decimals_Call struct {
+ *mock.Call
+}
+
+// Decimals is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *LinkTokenInterface_Expecter) Decimals(opts interface{}) *LinkTokenInterface_Decimals_Call {
+ return &LinkTokenInterface_Decimals_Call{Call: _e.mock.On("Decimals", opts)}
+}
+
+func (_c *LinkTokenInterface_Decimals_Call) Run(run func(opts *bind.CallOpts)) *LinkTokenInterface_Decimals_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_Decimals_Call) Return(_a0 uint8, _a1 error) *LinkTokenInterface_Decimals_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_Decimals_Call) RunAndReturn(run func(*bind.CallOpts) (uint8, error)) *LinkTokenInterface_Decimals_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// DecreaseApproval provides a mock function with given fields: opts, _spender, _subtractedValue
+func (_m *LinkTokenInterface) DecreaseApproval(opts *bind.TransactOpts, _spender common.Address, _subtractedValue *big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, _spender, _subtractedValue)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DecreaseApproval")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, _spender, _subtractedValue)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) *types.Transaction); ok {
+ r0 = rf(opts, _spender, _subtractedValue)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int) error); ok {
+ r1 = rf(opts, _spender, _subtractedValue)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_DecreaseApproval_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DecreaseApproval'
+type LinkTokenInterface_DecreaseApproval_Call struct {
+ *mock.Call
+}
+
+// DecreaseApproval is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _spender common.Address
+// - _subtractedValue *big.Int
+func (_e *LinkTokenInterface_Expecter) DecreaseApproval(opts interface{}, _spender interface{}, _subtractedValue interface{}) *LinkTokenInterface_DecreaseApproval_Call {
+ return &LinkTokenInterface_DecreaseApproval_Call{Call: _e.mock.On("DecreaseApproval", opts, _spender, _subtractedValue)}
+}
+
+func (_c *LinkTokenInterface_DecreaseApproval_Call) Run(run func(opts *bind.TransactOpts, _spender common.Address, _subtractedValue *big.Int)) *LinkTokenInterface_DecreaseApproval_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_DecreaseApproval_Call) Return(_a0 *types.Transaction, _a1 error) *LinkTokenInterface_DecreaseApproval_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_DecreaseApproval_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)) *LinkTokenInterface_DecreaseApproval_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterApproval provides a mock function with given fields: opts, owner, spender
+func (_m *LinkTokenInterface) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*link_token_interface.LinkTokenApprovalIterator, error) {
+ ret := _m.Called(opts, owner, spender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterApproval")
+ }
+
+ var r0 *link_token_interface.LinkTokenApprovalIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*link_token_interface.LinkTokenApprovalIterator, error)); ok {
+ return rf(opts, owner, spender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *link_token_interface.LinkTokenApprovalIterator); ok {
+ r0 = rf(opts, owner, spender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*link_token_interface.LinkTokenApprovalIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, owner, spender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_FilterApproval_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterApproval'
+type LinkTokenInterface_FilterApproval_Call struct {
+ *mock.Call
+}
+
+// FilterApproval is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - owner []common.Address
+// - spender []common.Address
+func (_e *LinkTokenInterface_Expecter) FilterApproval(opts interface{}, owner interface{}, spender interface{}) *LinkTokenInterface_FilterApproval_Call {
+ return &LinkTokenInterface_FilterApproval_Call{Call: _e.mock.On("FilterApproval", opts, owner, spender)}
+}
+
+func (_c *LinkTokenInterface_FilterApproval_Call) Run(run func(opts *bind.FilterOpts, owner []common.Address, spender []common.Address)) *LinkTokenInterface_FilterApproval_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_FilterApproval_Call) Return(_a0 *link_token_interface.LinkTokenApprovalIterator, _a1 error) *LinkTokenInterface_FilterApproval_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_FilterApproval_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*link_token_interface.LinkTokenApprovalIterator, error)) *LinkTokenInterface_FilterApproval_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTransfer provides a mock function with given fields: opts, from, to
+func (_m *LinkTokenInterface) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*link_token_interface.LinkTokenTransferIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTransfer")
+ }
+
+ var r0 *link_token_interface.LinkTokenTransferIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*link_token_interface.LinkTokenTransferIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *link_token_interface.LinkTokenTransferIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*link_token_interface.LinkTokenTransferIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_FilterTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTransfer'
+type LinkTokenInterface_FilterTransfer_Call struct {
+ *mock.Call
+}
+
+// FilterTransfer is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *LinkTokenInterface_Expecter) FilterTransfer(opts interface{}, from interface{}, to interface{}) *LinkTokenInterface_FilterTransfer_Call {
+ return &LinkTokenInterface_FilterTransfer_Call{Call: _e.mock.On("FilterTransfer", opts, from, to)}
+}
+
+func (_c *LinkTokenInterface_FilterTransfer_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *LinkTokenInterface_FilterTransfer_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_FilterTransfer_Call) Return(_a0 *link_token_interface.LinkTokenTransferIterator, _a1 error) *LinkTokenInterface_FilterTransfer_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_FilterTransfer_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*link_token_interface.LinkTokenTransferIterator, error)) *LinkTokenInterface_FilterTransfer_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IncreaseApproval provides a mock function with given fields: opts, _spender, _addedValue
+func (_m *LinkTokenInterface) IncreaseApproval(opts *bind.TransactOpts, _spender common.Address, _addedValue *big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, _spender, _addedValue)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IncreaseApproval")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, _spender, _addedValue)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) *types.Transaction); ok {
+ r0 = rf(opts, _spender, _addedValue)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int) error); ok {
+ r1 = rf(opts, _spender, _addedValue)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_IncreaseApproval_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IncreaseApproval'
+type LinkTokenInterface_IncreaseApproval_Call struct {
+ *mock.Call
+}
+
+// IncreaseApproval is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _spender common.Address
+// - _addedValue *big.Int
+func (_e *LinkTokenInterface_Expecter) IncreaseApproval(opts interface{}, _spender interface{}, _addedValue interface{}) *LinkTokenInterface_IncreaseApproval_Call {
+ return &LinkTokenInterface_IncreaseApproval_Call{Call: _e.mock.On("IncreaseApproval", opts, _spender, _addedValue)}
+}
+
+func (_c *LinkTokenInterface_IncreaseApproval_Call) Run(run func(opts *bind.TransactOpts, _spender common.Address, _addedValue *big.Int)) *LinkTokenInterface_IncreaseApproval_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_IncreaseApproval_Call) Return(_a0 *types.Transaction, _a1 error) *LinkTokenInterface_IncreaseApproval_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_IncreaseApproval_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)) *LinkTokenInterface_IncreaseApproval_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Name provides a mock function with given fields: opts
+func (_m *LinkTokenInterface) Name(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Name")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name'
+type LinkTokenInterface_Name_Call struct {
+ *mock.Call
+}
+
+// Name is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *LinkTokenInterface_Expecter) Name(opts interface{}) *LinkTokenInterface_Name_Call {
+ return &LinkTokenInterface_Name_Call{Call: _e.mock.On("Name", opts)}
+}
+
+func (_c *LinkTokenInterface_Name_Call) Run(run func(opts *bind.CallOpts)) *LinkTokenInterface_Name_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_Name_Call) Return(_a0 string, _a1 error) *LinkTokenInterface_Name_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_Name_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *LinkTokenInterface_Name_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseApproval provides a mock function with given fields: log
+func (_m *LinkTokenInterface) ParseApproval(log types.Log) (*link_token_interface.LinkTokenApproval, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseApproval")
+ }
+
+ var r0 *link_token_interface.LinkTokenApproval
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*link_token_interface.LinkTokenApproval, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *link_token_interface.LinkTokenApproval); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*link_token_interface.LinkTokenApproval)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_ParseApproval_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseApproval'
+type LinkTokenInterface_ParseApproval_Call struct {
+ *mock.Call
+}
+
+// ParseApproval is a helper method to define mock.On call
+// - log types.Log
+func (_e *LinkTokenInterface_Expecter) ParseApproval(log interface{}) *LinkTokenInterface_ParseApproval_Call {
+ return &LinkTokenInterface_ParseApproval_Call{Call: _e.mock.On("ParseApproval", log)}
+}
+
+func (_c *LinkTokenInterface_ParseApproval_Call) Run(run func(log types.Log)) *LinkTokenInterface_ParseApproval_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_ParseApproval_Call) Return(_a0 *link_token_interface.LinkTokenApproval, _a1 error) *LinkTokenInterface_ParseApproval_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_ParseApproval_Call) RunAndReturn(run func(types.Log) (*link_token_interface.LinkTokenApproval, error)) *LinkTokenInterface_ParseApproval_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *LinkTokenInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type LinkTokenInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *LinkTokenInterface_Expecter) ParseLog(log interface{}) *LinkTokenInterface_ParseLog_Call {
+ return &LinkTokenInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *LinkTokenInterface_ParseLog_Call) Run(run func(log types.Log)) *LinkTokenInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *LinkTokenInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *LinkTokenInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTransfer provides a mock function with given fields: log
+func (_m *LinkTokenInterface) ParseTransfer(log types.Log) (*link_token_interface.LinkTokenTransfer, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTransfer")
+ }
+
+ var r0 *link_token_interface.LinkTokenTransfer
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*link_token_interface.LinkTokenTransfer, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *link_token_interface.LinkTokenTransfer); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*link_token_interface.LinkTokenTransfer)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_ParseTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTransfer'
+type LinkTokenInterface_ParseTransfer_Call struct {
+ *mock.Call
+}
+
+// ParseTransfer is a helper method to define mock.On call
+// - log types.Log
+func (_e *LinkTokenInterface_Expecter) ParseTransfer(log interface{}) *LinkTokenInterface_ParseTransfer_Call {
+ return &LinkTokenInterface_ParseTransfer_Call{Call: _e.mock.On("ParseTransfer", log)}
+}
+
+func (_c *LinkTokenInterface_ParseTransfer_Call) Run(run func(log types.Log)) *LinkTokenInterface_ParseTransfer_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_ParseTransfer_Call) Return(_a0 *link_token_interface.LinkTokenTransfer, _a1 error) *LinkTokenInterface_ParseTransfer_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_ParseTransfer_Call) RunAndReturn(run func(types.Log) (*link_token_interface.LinkTokenTransfer, error)) *LinkTokenInterface_ParseTransfer_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Symbol provides a mock function with given fields: opts
+func (_m *LinkTokenInterface) Symbol(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Symbol")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_Symbol_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Symbol'
+type LinkTokenInterface_Symbol_Call struct {
+ *mock.Call
+}
+
+// Symbol is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *LinkTokenInterface_Expecter) Symbol(opts interface{}) *LinkTokenInterface_Symbol_Call {
+ return &LinkTokenInterface_Symbol_Call{Call: _e.mock.On("Symbol", opts)}
+}
+
+func (_c *LinkTokenInterface_Symbol_Call) Run(run func(opts *bind.CallOpts)) *LinkTokenInterface_Symbol_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_Symbol_Call) Return(_a0 string, _a1 error) *LinkTokenInterface_Symbol_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_Symbol_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *LinkTokenInterface_Symbol_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TotalSupply provides a mock function with given fields: opts
+func (_m *LinkTokenInterface) TotalSupply(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TotalSupply")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_TotalSupply_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TotalSupply'
+type LinkTokenInterface_TotalSupply_Call struct {
+ *mock.Call
+}
+
+// TotalSupply is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *LinkTokenInterface_Expecter) TotalSupply(opts interface{}) *LinkTokenInterface_TotalSupply_Call {
+ return &LinkTokenInterface_TotalSupply_Call{Call: _e.mock.On("TotalSupply", opts)}
+}
+
+func (_c *LinkTokenInterface_TotalSupply_Call) Run(run func(opts *bind.CallOpts)) *LinkTokenInterface_TotalSupply_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_TotalSupply_Call) Return(_a0 *big.Int, _a1 error) *LinkTokenInterface_TotalSupply_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_TotalSupply_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *LinkTokenInterface_TotalSupply_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Transfer provides a mock function with given fields: opts, _to, _value
+func (_m *LinkTokenInterface) Transfer(opts *bind.TransactOpts, _to common.Address, _value *big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, _to, _value)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Transfer")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, _to, _value)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) *types.Transaction); ok {
+ r0 = rf(opts, _to, _value)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int) error); ok {
+ r1 = rf(opts, _to, _value)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_Transfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Transfer'
+type LinkTokenInterface_Transfer_Call struct {
+ *mock.Call
+}
+
+// Transfer is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _to common.Address
+// - _value *big.Int
+func (_e *LinkTokenInterface_Expecter) Transfer(opts interface{}, _to interface{}, _value interface{}) *LinkTokenInterface_Transfer_Call {
+ return &LinkTokenInterface_Transfer_Call{Call: _e.mock.On("Transfer", opts, _to, _value)}
+}
+
+func (_c *LinkTokenInterface_Transfer_Call) Run(run func(opts *bind.TransactOpts, _to common.Address, _value *big.Int)) *LinkTokenInterface_Transfer_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_Transfer_Call) Return(_a0 *types.Transaction, _a1 error) *LinkTokenInterface_Transfer_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_Transfer_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)) *LinkTokenInterface_Transfer_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TransferAndCall provides a mock function with given fields: opts, _to, _value, _data
+func (_m *LinkTokenInterface) TransferAndCall(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, _to, _value, _data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TransferAndCall")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, _to, _value, _data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, _to, _value, _data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, _to, _value, _data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_TransferAndCall_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferAndCall'
+type LinkTokenInterface_TransferAndCall_Call struct {
+ *mock.Call
+}
+
+// TransferAndCall is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _to common.Address
+// - _value *big.Int
+// - _data []byte
+func (_e *LinkTokenInterface_Expecter) TransferAndCall(opts interface{}, _to interface{}, _value interface{}, _data interface{}) *LinkTokenInterface_TransferAndCall_Call {
+ return &LinkTokenInterface_TransferAndCall_Call{Call: _e.mock.On("TransferAndCall", opts, _to, _value, _data)}
+}
+
+func (_c *LinkTokenInterface_TransferAndCall_Call) Run(run func(opts *bind.TransactOpts, _to common.Address, _value *big.Int, _data []byte)) *LinkTokenInterface_TransferAndCall_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(*big.Int), args[3].([]byte))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_TransferAndCall_Call) Return(_a0 *types.Transaction, _a1 error) *LinkTokenInterface_TransferAndCall_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_TransferAndCall_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)) *LinkTokenInterface_TransferAndCall_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TransferFrom provides a mock function with given fields: opts, _from, _to, _value
+func (_m *LinkTokenInterface) TransferFrom(opts *bind.TransactOpts, _from common.Address, _to common.Address, _value *big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, _from, _to, _value)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TransferFrom")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, _from, _to, _value)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) *types.Transaction); ok {
+ r0 = rf(opts, _from, _to, _value)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) error); ok {
+ r1 = rf(opts, _from, _to, _value)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_TransferFrom_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferFrom'
+type LinkTokenInterface_TransferFrom_Call struct {
+ *mock.Call
+}
+
+// TransferFrom is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _from common.Address
+// - _to common.Address
+// - _value *big.Int
+func (_e *LinkTokenInterface_Expecter) TransferFrom(opts interface{}, _from interface{}, _to interface{}, _value interface{}) *LinkTokenInterface_TransferFrom_Call {
+ return &LinkTokenInterface_TransferFrom_Call{Call: _e.mock.On("TransferFrom", opts, _from, _to, _value)}
+}
+
+func (_c *LinkTokenInterface_TransferFrom_Call) Run(run func(opts *bind.TransactOpts, _from common.Address, _to common.Address, _value *big.Int)) *LinkTokenInterface_TransferFrom_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_TransferFrom_Call) Return(_a0 *types.Transaction, _a1 error) *LinkTokenInterface_TransferFrom_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_TransferFrom_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, *big.Int) (*types.Transaction, error)) *LinkTokenInterface_TransferFrom_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchApproval provides a mock function with given fields: opts, sink, owner, spender
+func (_m *LinkTokenInterface) WatchApproval(opts *bind.WatchOpts, sink chan<- *link_token_interface.LinkTokenApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, owner, spender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchApproval")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenApproval, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, owner, spender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenApproval, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, owner, spender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenApproval, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, owner, spender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_WatchApproval_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchApproval'
+type LinkTokenInterface_WatchApproval_Call struct {
+ *mock.Call
+}
+
+// WatchApproval is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *link_token_interface.LinkTokenApproval
+// - owner []common.Address
+// - spender []common.Address
+func (_e *LinkTokenInterface_Expecter) WatchApproval(opts interface{}, sink interface{}, owner interface{}, spender interface{}) *LinkTokenInterface_WatchApproval_Call {
+ return &LinkTokenInterface_WatchApproval_Call{Call: _e.mock.On("WatchApproval", opts, sink, owner, spender)}
+}
+
+func (_c *LinkTokenInterface_WatchApproval_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *link_token_interface.LinkTokenApproval, owner []common.Address, spender []common.Address)) *LinkTokenInterface_WatchApproval_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *link_token_interface.LinkTokenApproval), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_WatchApproval_Call) Return(_a0 event.Subscription, _a1 error) *LinkTokenInterface_WatchApproval_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_WatchApproval_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenApproval, []common.Address, []common.Address) (event.Subscription, error)) *LinkTokenInterface_WatchApproval_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTransfer provides a mock function with given fields: opts, sink, from, to
+func (_m *LinkTokenInterface) WatchTransfer(opts *bind.WatchOpts, sink chan<- *link_token_interface.LinkTokenTransfer, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTransfer")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenTransfer, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenTransfer, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenTransfer, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// LinkTokenInterface_WatchTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTransfer'
+type LinkTokenInterface_WatchTransfer_Call struct {
+ *mock.Call
+}
+
+// WatchTransfer is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *link_token_interface.LinkTokenTransfer
+// - from []common.Address
+// - to []common.Address
+func (_e *LinkTokenInterface_Expecter) WatchTransfer(opts interface{}, sink interface{}, from interface{}, to interface{}) *LinkTokenInterface_WatchTransfer_Call {
+ return &LinkTokenInterface_WatchTransfer_Call{Call: _e.mock.On("WatchTransfer", opts, sink, from, to)}
+}
+
+func (_c *LinkTokenInterface_WatchTransfer_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *link_token_interface.LinkTokenTransfer, from []common.Address, to []common.Address)) *LinkTokenInterface_WatchTransfer_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *link_token_interface.LinkTokenTransfer), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *LinkTokenInterface_WatchTransfer_Call) Return(_a0 event.Subscription, _a1 error) *LinkTokenInterface_WatchTransfer_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *LinkTokenInterface_WatchTransfer_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *link_token_interface.LinkTokenTransfer, []common.Address, []common.Address) (event.Subscription, error)) *LinkTokenInterface_WatchTransfer_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewLinkTokenInterface creates a new instance of LinkTokenInterface. 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 NewLinkTokenInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *LinkTokenInterface {
+ mock := &LinkTokenInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/ccip/mocks/price_registry_interface.go b/core/gethwrappers/ccip/mocks/price_registry_interface.go
new file mode 100644
index 00000000000..8c2834acce3
--- /dev/null
+++ b/core/gethwrappers/ccip/mocks/price_registry_interface.go
@@ -0,0 +1,4555 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_contracts
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ price_registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// PriceRegistryInterface is an autogenerated mock type for the PriceRegistryInterface type
+type PriceRegistryInterface struct {
+ mock.Mock
+}
+
+type PriceRegistryInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *PriceRegistryInterface) EXPECT() *PriceRegistryInterface_Expecter {
+ return &PriceRegistryInterface_Expecter{mock: &_m.Mock}
+}
+
+// AcceptOwnership provides a mock function with given fields: opts
+func (_m *PriceRegistryInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AcceptOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_AcceptOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptOwnership'
+type PriceRegistryInterface_AcceptOwnership_Call struct {
+ *mock.Call
+}
+
+// AcceptOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *PriceRegistryInterface_Expecter) AcceptOwnership(opts interface{}) *PriceRegistryInterface_AcceptOwnership_Call {
+ return &PriceRegistryInterface_AcceptOwnership_Call{Call: _e.mock.On("AcceptOwnership", opts)}
+}
+
+func (_c *PriceRegistryInterface_AcceptOwnership_Call) Run(run func(opts *bind.TransactOpts)) *PriceRegistryInterface_AcceptOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_AcceptOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_AcceptOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_AcceptOwnership_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *PriceRegistryInterface_AcceptOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Address provides a mock function with given fields:
+func (_m *PriceRegistryInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// PriceRegistryInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type PriceRegistryInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *PriceRegistryInterface_Expecter) Address() *PriceRegistryInterface_Address_Call {
+ return &PriceRegistryInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *PriceRegistryInterface_Address_Call) Run(run func()) *PriceRegistryInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_Address_Call) Return(_a0 common.Address) *PriceRegistryInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_Address_Call) RunAndReturn(run func() common.Address) *PriceRegistryInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ApplyAuthorizedCallerUpdates provides a mock function with given fields: opts, authorizedCallerArgs
+func (_m *PriceRegistryInterface) ApplyAuthorizedCallerUpdates(opts *bind.TransactOpts, authorizedCallerArgs price_registry.AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error) {
+ ret := _m.Called(opts, authorizedCallerArgs)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ApplyAuthorizedCallerUpdates")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, price_registry.AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error)); ok {
+ return rf(opts, authorizedCallerArgs)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, price_registry.AuthorizedCallersAuthorizedCallerArgs) *types.Transaction); ok {
+ r0 = rf(opts, authorizedCallerArgs)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, price_registry.AuthorizedCallersAuthorizedCallerArgs) error); ok {
+ r1 = rf(opts, authorizedCallerArgs)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyAuthorizedCallerUpdates'
+type PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call struct {
+ *mock.Call
+}
+
+// ApplyAuthorizedCallerUpdates is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - authorizedCallerArgs price_registry.AuthorizedCallersAuthorizedCallerArgs
+func (_e *PriceRegistryInterface_Expecter) ApplyAuthorizedCallerUpdates(opts interface{}, authorizedCallerArgs interface{}) *PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call {
+ return &PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call{Call: _e.mock.On("ApplyAuthorizedCallerUpdates", opts, authorizedCallerArgs)}
+}
+
+func (_c *PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call) Run(run func(opts *bind.TransactOpts, authorizedCallerArgs price_registry.AuthorizedCallersAuthorizedCallerArgs)) *PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(price_registry.AuthorizedCallersAuthorizedCallerArgs))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call) RunAndReturn(run func(*bind.TransactOpts, price_registry.AuthorizedCallersAuthorizedCallerArgs) (*types.Transaction, error)) *PriceRegistryInterface_ApplyAuthorizedCallerUpdates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ApplyDestChainConfigUpdates provides a mock function with given fields: opts, destChainConfigArgs
+func (_m *PriceRegistryInterface) ApplyDestChainConfigUpdates(opts *bind.TransactOpts, destChainConfigArgs []price_registry.PriceRegistryDestChainConfigArgs) (*types.Transaction, error) {
+ ret := _m.Called(opts, destChainConfigArgs)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ApplyDestChainConfigUpdates")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []price_registry.PriceRegistryDestChainConfigArgs) (*types.Transaction, error)); ok {
+ return rf(opts, destChainConfigArgs)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []price_registry.PriceRegistryDestChainConfigArgs) *types.Transaction); ok {
+ r0 = rf(opts, destChainConfigArgs)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []price_registry.PriceRegistryDestChainConfigArgs) error); ok {
+ r1 = rf(opts, destChainConfigArgs)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ApplyDestChainConfigUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyDestChainConfigUpdates'
+type PriceRegistryInterface_ApplyDestChainConfigUpdates_Call struct {
+ *mock.Call
+}
+
+// ApplyDestChainConfigUpdates is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - destChainConfigArgs []price_registry.PriceRegistryDestChainConfigArgs
+func (_e *PriceRegistryInterface_Expecter) ApplyDestChainConfigUpdates(opts interface{}, destChainConfigArgs interface{}) *PriceRegistryInterface_ApplyDestChainConfigUpdates_Call {
+ return &PriceRegistryInterface_ApplyDestChainConfigUpdates_Call{Call: _e.mock.On("ApplyDestChainConfigUpdates", opts, destChainConfigArgs)}
+}
+
+func (_c *PriceRegistryInterface_ApplyDestChainConfigUpdates_Call) Run(run func(opts *bind.TransactOpts, destChainConfigArgs []price_registry.PriceRegistryDestChainConfigArgs)) *PriceRegistryInterface_ApplyDestChainConfigUpdates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]price_registry.PriceRegistryDestChainConfigArgs))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyDestChainConfigUpdates_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_ApplyDestChainConfigUpdates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyDestChainConfigUpdates_Call) RunAndReturn(run func(*bind.TransactOpts, []price_registry.PriceRegistryDestChainConfigArgs) (*types.Transaction, error)) *PriceRegistryInterface_ApplyDestChainConfigUpdates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ApplyFeeTokensUpdates provides a mock function with given fields: opts, feeTokensToAdd, feeTokensToRemove
+func (_m *PriceRegistryInterface) ApplyFeeTokensUpdates(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, feeTokensToAdd, feeTokensToRemove)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ApplyFeeTokensUpdates")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, feeTokensToAdd, feeTokensToRemove)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address) *types.Transaction); ok {
+ r0 = rf(opts, feeTokensToAdd, feeTokensToRemove)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, feeTokensToAdd, feeTokensToRemove)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ApplyFeeTokensUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyFeeTokensUpdates'
+type PriceRegistryInterface_ApplyFeeTokensUpdates_Call struct {
+ *mock.Call
+}
+
+// ApplyFeeTokensUpdates is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - feeTokensToAdd []common.Address
+// - feeTokensToRemove []common.Address
+func (_e *PriceRegistryInterface_Expecter) ApplyFeeTokensUpdates(opts interface{}, feeTokensToAdd interface{}, feeTokensToRemove interface{}) *PriceRegistryInterface_ApplyFeeTokensUpdates_Call {
+ return &PriceRegistryInterface_ApplyFeeTokensUpdates_Call{Call: _e.mock.On("ApplyFeeTokensUpdates", opts, feeTokensToAdd, feeTokensToRemove)}
+}
+
+func (_c *PriceRegistryInterface_ApplyFeeTokensUpdates_Call) Run(run func(opts *bind.TransactOpts, feeTokensToAdd []common.Address, feeTokensToRemove []common.Address)) *PriceRegistryInterface_ApplyFeeTokensUpdates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyFeeTokensUpdates_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_ApplyFeeTokensUpdates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyFeeTokensUpdates_Call) RunAndReturn(run func(*bind.TransactOpts, []common.Address, []common.Address) (*types.Transaction, error)) *PriceRegistryInterface_ApplyFeeTokensUpdates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ApplyPremiumMultiplierWeiPerEthUpdates provides a mock function with given fields: opts, premiumMultiplierWeiPerEthArgs
+func (_m *PriceRegistryInterface) ApplyPremiumMultiplierWeiPerEthUpdates(opts *bind.TransactOpts, premiumMultiplierWeiPerEthArgs []price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs) (*types.Transaction, error) {
+ ret := _m.Called(opts, premiumMultiplierWeiPerEthArgs)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ApplyPremiumMultiplierWeiPerEthUpdates")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs) (*types.Transaction, error)); ok {
+ return rf(opts, premiumMultiplierWeiPerEthArgs)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs) *types.Transaction); ok {
+ r0 = rf(opts, premiumMultiplierWeiPerEthArgs)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs) error); ok {
+ r1 = rf(opts, premiumMultiplierWeiPerEthArgs)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyPremiumMultiplierWeiPerEthUpdates'
+type PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call struct {
+ *mock.Call
+}
+
+// ApplyPremiumMultiplierWeiPerEthUpdates is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - premiumMultiplierWeiPerEthArgs []price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs
+func (_e *PriceRegistryInterface_Expecter) ApplyPremiumMultiplierWeiPerEthUpdates(opts interface{}, premiumMultiplierWeiPerEthArgs interface{}) *PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call {
+ return &PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call{Call: _e.mock.On("ApplyPremiumMultiplierWeiPerEthUpdates", opts, premiumMultiplierWeiPerEthArgs)}
+}
+
+func (_c *PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call) Run(run func(opts *bind.TransactOpts, premiumMultiplierWeiPerEthArgs []price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs)) *PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call) RunAndReturn(run func(*bind.TransactOpts, []price_registry.PriceRegistryPremiumMultiplierWeiPerEthArgs) (*types.Transaction, error)) *PriceRegistryInterface_ApplyPremiumMultiplierWeiPerEthUpdates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ApplyTokenTransferFeeConfigUpdates provides a mock function with given fields: opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs
+func (_m *PriceRegistryInterface) ApplyTokenTransferFeeConfigUpdates(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []price_registry.PriceRegistryTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []price_registry.PriceRegistryTokenTransferFeeConfigRemoveArgs) (*types.Transaction, error) {
+ ret := _m.Called(opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ApplyTokenTransferFeeConfigUpdates")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []price_registry.PriceRegistryTokenTransferFeeConfigArgs, []price_registry.PriceRegistryTokenTransferFeeConfigRemoveArgs) (*types.Transaction, error)); ok {
+ return rf(opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []price_registry.PriceRegistryTokenTransferFeeConfigArgs, []price_registry.PriceRegistryTokenTransferFeeConfigRemoveArgs) *types.Transaction); ok {
+ r0 = rf(opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []price_registry.PriceRegistryTokenTransferFeeConfigArgs, []price_registry.PriceRegistryTokenTransferFeeConfigRemoveArgs) error); ok {
+ r1 = rf(opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyTokenTransferFeeConfigUpdates'
+type PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call struct {
+ *mock.Call
+}
+
+// ApplyTokenTransferFeeConfigUpdates is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - tokenTransferFeeConfigArgs []price_registry.PriceRegistryTokenTransferFeeConfigArgs
+// - tokensToUseDefaultFeeConfigs []price_registry.PriceRegistryTokenTransferFeeConfigRemoveArgs
+func (_e *PriceRegistryInterface_Expecter) ApplyTokenTransferFeeConfigUpdates(opts interface{}, tokenTransferFeeConfigArgs interface{}, tokensToUseDefaultFeeConfigs interface{}) *PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call {
+ return &PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call{Call: _e.mock.On("ApplyTokenTransferFeeConfigUpdates", opts, tokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs)}
+}
+
+func (_c *PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call) Run(run func(opts *bind.TransactOpts, tokenTransferFeeConfigArgs []price_registry.PriceRegistryTokenTransferFeeConfigArgs, tokensToUseDefaultFeeConfigs []price_registry.PriceRegistryTokenTransferFeeConfigRemoveArgs)) *PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]price_registry.PriceRegistryTokenTransferFeeConfigArgs), args[2].([]price_registry.PriceRegistryTokenTransferFeeConfigRemoveArgs))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call) RunAndReturn(run func(*bind.TransactOpts, []price_registry.PriceRegistryTokenTransferFeeConfigArgs, []price_registry.PriceRegistryTokenTransferFeeConfigRemoveArgs) (*types.Transaction, error)) *PriceRegistryInterface_ApplyTokenTransferFeeConfigUpdates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ConvertTokenAmount provides a mock function with given fields: opts, fromToken, fromTokenAmount, toToken
+func (_m *PriceRegistryInterface) ConvertTokenAmount(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address) (*big.Int, error) {
+ ret := _m.Called(opts, fromToken, fromTokenAmount, toToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ConvertTokenAmount")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, *big.Int, common.Address) (*big.Int, error)); ok {
+ return rf(opts, fromToken, fromTokenAmount, toToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, *big.Int, common.Address) *big.Int); ok {
+ r0 = rf(opts, fromToken, fromTokenAmount, toToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address, *big.Int, common.Address) error); ok {
+ r1 = rf(opts, fromToken, fromTokenAmount, toToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ConvertTokenAmount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConvertTokenAmount'
+type PriceRegistryInterface_ConvertTokenAmount_Call struct {
+ *mock.Call
+}
+
+// ConvertTokenAmount is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - fromToken common.Address
+// - fromTokenAmount *big.Int
+// - toToken common.Address
+func (_e *PriceRegistryInterface_Expecter) ConvertTokenAmount(opts interface{}, fromToken interface{}, fromTokenAmount interface{}, toToken interface{}) *PriceRegistryInterface_ConvertTokenAmount_Call {
+ return &PriceRegistryInterface_ConvertTokenAmount_Call{Call: _e.mock.On("ConvertTokenAmount", opts, fromToken, fromTokenAmount, toToken)}
+}
+
+func (_c *PriceRegistryInterface_ConvertTokenAmount_Call) Run(run func(opts *bind.CallOpts, fromToken common.Address, fromTokenAmount *big.Int, toToken common.Address)) *PriceRegistryInterface_ConvertTokenAmount_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address), args[2].(*big.Int), args[3].(common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ConvertTokenAmount_Call) Return(_a0 *big.Int, _a1 error) *PriceRegistryInterface_ConvertTokenAmount_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ConvertTokenAmount_Call) RunAndReturn(run func(*bind.CallOpts, common.Address, *big.Int, common.Address) (*big.Int, error)) *PriceRegistryInterface_ConvertTokenAmount_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterAuthorizedCallerAdded provides a mock function with given fields: opts
+func (_m *PriceRegistryInterface) FilterAuthorizedCallerAdded(opts *bind.FilterOpts) (*price_registry.PriceRegistryAuthorizedCallerAddedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterAuthorizedCallerAdded")
+ }
+
+ var r0 *price_registry.PriceRegistryAuthorizedCallerAddedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*price_registry.PriceRegistryAuthorizedCallerAddedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *price_registry.PriceRegistryAuthorizedCallerAddedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryAuthorizedCallerAddedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterAuthorizedCallerAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterAuthorizedCallerAdded'
+type PriceRegistryInterface_FilterAuthorizedCallerAdded_Call struct {
+ *mock.Call
+}
+
+// FilterAuthorizedCallerAdded is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *PriceRegistryInterface_Expecter) FilterAuthorizedCallerAdded(opts interface{}) *PriceRegistryInterface_FilterAuthorizedCallerAdded_Call {
+ return &PriceRegistryInterface_FilterAuthorizedCallerAdded_Call{Call: _e.mock.On("FilterAuthorizedCallerAdded", opts)}
+}
+
+func (_c *PriceRegistryInterface_FilterAuthorizedCallerAdded_Call) Run(run func(opts *bind.FilterOpts)) *PriceRegistryInterface_FilterAuthorizedCallerAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterAuthorizedCallerAdded_Call) Return(_a0 *price_registry.PriceRegistryAuthorizedCallerAddedIterator, _a1 error) *PriceRegistryInterface_FilterAuthorizedCallerAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterAuthorizedCallerAdded_Call) RunAndReturn(run func(*bind.FilterOpts) (*price_registry.PriceRegistryAuthorizedCallerAddedIterator, error)) *PriceRegistryInterface_FilterAuthorizedCallerAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterAuthorizedCallerRemoved provides a mock function with given fields: opts
+func (_m *PriceRegistryInterface) FilterAuthorizedCallerRemoved(opts *bind.FilterOpts) (*price_registry.PriceRegistryAuthorizedCallerRemovedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterAuthorizedCallerRemoved")
+ }
+
+ var r0 *price_registry.PriceRegistryAuthorizedCallerRemovedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*price_registry.PriceRegistryAuthorizedCallerRemovedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *price_registry.PriceRegistryAuthorizedCallerRemovedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryAuthorizedCallerRemovedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterAuthorizedCallerRemoved'
+type PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call struct {
+ *mock.Call
+}
+
+// FilterAuthorizedCallerRemoved is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *PriceRegistryInterface_Expecter) FilterAuthorizedCallerRemoved(opts interface{}) *PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call {
+ return &PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call{Call: _e.mock.On("FilterAuthorizedCallerRemoved", opts)}
+}
+
+func (_c *PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call) Run(run func(opts *bind.FilterOpts)) *PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call) Return(_a0 *price_registry.PriceRegistryAuthorizedCallerRemovedIterator, _a1 error) *PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call) RunAndReturn(run func(*bind.FilterOpts) (*price_registry.PriceRegistryAuthorizedCallerRemovedIterator, error)) *PriceRegistryInterface_FilterAuthorizedCallerRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterDestChainAdded provides a mock function with given fields: opts, destChainSelector
+func (_m *PriceRegistryInterface) FilterDestChainAdded(opts *bind.FilterOpts, destChainSelector []uint64) (*price_registry.PriceRegistryDestChainAddedIterator, error) {
+ ret := _m.Called(opts, destChainSelector)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterDestChainAdded")
+ }
+
+ var r0 *price_registry.PriceRegistryDestChainAddedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*price_registry.PriceRegistryDestChainAddedIterator, error)); ok {
+ return rf(opts, destChainSelector)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) *price_registry.PriceRegistryDestChainAddedIterator); ok {
+ r0 = rf(opts, destChainSelector)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryDestChainAddedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64) error); ok {
+ r1 = rf(opts, destChainSelector)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterDestChainAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterDestChainAdded'
+type PriceRegistryInterface_FilterDestChainAdded_Call struct {
+ *mock.Call
+}
+
+// FilterDestChainAdded is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - destChainSelector []uint64
+func (_e *PriceRegistryInterface_Expecter) FilterDestChainAdded(opts interface{}, destChainSelector interface{}) *PriceRegistryInterface_FilterDestChainAdded_Call {
+ return &PriceRegistryInterface_FilterDestChainAdded_Call{Call: _e.mock.On("FilterDestChainAdded", opts, destChainSelector)}
+}
+
+func (_c *PriceRegistryInterface_FilterDestChainAdded_Call) Run(run func(opts *bind.FilterOpts, destChainSelector []uint64)) *PriceRegistryInterface_FilterDestChainAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterDestChainAdded_Call) Return(_a0 *price_registry.PriceRegistryDestChainAddedIterator, _a1 error) *PriceRegistryInterface_FilterDestChainAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterDestChainAdded_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64) (*price_registry.PriceRegistryDestChainAddedIterator, error)) *PriceRegistryInterface_FilterDestChainAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterDestChainConfigUpdated provides a mock function with given fields: opts, destChainSelector
+func (_m *PriceRegistryInterface) FilterDestChainConfigUpdated(opts *bind.FilterOpts, destChainSelector []uint64) (*price_registry.PriceRegistryDestChainConfigUpdatedIterator, error) {
+ ret := _m.Called(opts, destChainSelector)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterDestChainConfigUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryDestChainConfigUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*price_registry.PriceRegistryDestChainConfigUpdatedIterator, error)); ok {
+ return rf(opts, destChainSelector)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) *price_registry.PriceRegistryDestChainConfigUpdatedIterator); ok {
+ r0 = rf(opts, destChainSelector)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryDestChainConfigUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64) error); ok {
+ r1 = rf(opts, destChainSelector)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterDestChainConfigUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterDestChainConfigUpdated'
+type PriceRegistryInterface_FilterDestChainConfigUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterDestChainConfigUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - destChainSelector []uint64
+func (_e *PriceRegistryInterface_Expecter) FilterDestChainConfigUpdated(opts interface{}, destChainSelector interface{}) *PriceRegistryInterface_FilterDestChainConfigUpdated_Call {
+ return &PriceRegistryInterface_FilterDestChainConfigUpdated_Call{Call: _e.mock.On("FilterDestChainConfigUpdated", opts, destChainSelector)}
+}
+
+func (_c *PriceRegistryInterface_FilterDestChainConfigUpdated_Call) Run(run func(opts *bind.FilterOpts, destChainSelector []uint64)) *PriceRegistryInterface_FilterDestChainConfigUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterDestChainConfigUpdated_Call) Return(_a0 *price_registry.PriceRegistryDestChainConfigUpdatedIterator, _a1 error) *PriceRegistryInterface_FilterDestChainConfigUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterDestChainConfigUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64) (*price_registry.PriceRegistryDestChainConfigUpdatedIterator, error)) *PriceRegistryInterface_FilterDestChainConfigUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterFeeTokenAdded provides a mock function with given fields: opts, feeToken
+func (_m *PriceRegistryInterface) FilterFeeTokenAdded(opts *bind.FilterOpts, feeToken []common.Address) (*price_registry.PriceRegistryFeeTokenAddedIterator, error) {
+ ret := _m.Called(opts, feeToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterFeeTokenAdded")
+ }
+
+ var r0 *price_registry.PriceRegistryFeeTokenAddedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryFeeTokenAddedIterator, error)); ok {
+ return rf(opts, feeToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *price_registry.PriceRegistryFeeTokenAddedIterator); ok {
+ r0 = rf(opts, feeToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryFeeTokenAddedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, feeToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterFeeTokenAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterFeeTokenAdded'
+type PriceRegistryInterface_FilterFeeTokenAdded_Call struct {
+ *mock.Call
+}
+
+// FilterFeeTokenAdded is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - feeToken []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterFeeTokenAdded(opts interface{}, feeToken interface{}) *PriceRegistryInterface_FilterFeeTokenAdded_Call {
+ return &PriceRegistryInterface_FilterFeeTokenAdded_Call{Call: _e.mock.On("FilterFeeTokenAdded", opts, feeToken)}
+}
+
+func (_c *PriceRegistryInterface_FilterFeeTokenAdded_Call) Run(run func(opts *bind.FilterOpts, feeToken []common.Address)) *PriceRegistryInterface_FilterFeeTokenAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterFeeTokenAdded_Call) Return(_a0 *price_registry.PriceRegistryFeeTokenAddedIterator, _a1 error) *PriceRegistryInterface_FilterFeeTokenAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterFeeTokenAdded_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryFeeTokenAddedIterator, error)) *PriceRegistryInterface_FilterFeeTokenAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterFeeTokenRemoved provides a mock function with given fields: opts, feeToken
+func (_m *PriceRegistryInterface) FilterFeeTokenRemoved(opts *bind.FilterOpts, feeToken []common.Address) (*price_registry.PriceRegistryFeeTokenRemovedIterator, error) {
+ ret := _m.Called(opts, feeToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterFeeTokenRemoved")
+ }
+
+ var r0 *price_registry.PriceRegistryFeeTokenRemovedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryFeeTokenRemovedIterator, error)); ok {
+ return rf(opts, feeToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *price_registry.PriceRegistryFeeTokenRemovedIterator); ok {
+ r0 = rf(opts, feeToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryFeeTokenRemovedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, feeToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterFeeTokenRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterFeeTokenRemoved'
+type PriceRegistryInterface_FilterFeeTokenRemoved_Call struct {
+ *mock.Call
+}
+
+// FilterFeeTokenRemoved is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - feeToken []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterFeeTokenRemoved(opts interface{}, feeToken interface{}) *PriceRegistryInterface_FilterFeeTokenRemoved_Call {
+ return &PriceRegistryInterface_FilterFeeTokenRemoved_Call{Call: _e.mock.On("FilterFeeTokenRemoved", opts, feeToken)}
+}
+
+func (_c *PriceRegistryInterface_FilterFeeTokenRemoved_Call) Run(run func(opts *bind.FilterOpts, feeToken []common.Address)) *PriceRegistryInterface_FilterFeeTokenRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterFeeTokenRemoved_Call) Return(_a0 *price_registry.PriceRegistryFeeTokenRemovedIterator, _a1 error) *PriceRegistryInterface_FilterFeeTokenRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterFeeTokenRemoved_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryFeeTokenRemovedIterator, error)) *PriceRegistryInterface_FilterFeeTokenRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to
+func (_m *PriceRegistryInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*price_registry.PriceRegistryOwnershipTransferRequestedIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferRequested")
+ }
+
+ var r0 *price_registry.PriceRegistryOwnershipTransferRequestedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*price_registry.PriceRegistryOwnershipTransferRequestedIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *price_registry.PriceRegistryOwnershipTransferRequestedIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryOwnershipTransferRequestedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferRequested'
+type PriceRegistryInterface_FilterOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterOwnershipTransferRequested(opts interface{}, from interface{}, to interface{}) *PriceRegistryInterface_FilterOwnershipTransferRequested_Call {
+ return &PriceRegistryInterface_FilterOwnershipTransferRequested_Call{Call: _e.mock.On("FilterOwnershipTransferRequested", opts, from, to)}
+}
+
+func (_c *PriceRegistryInterface_FilterOwnershipTransferRequested_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *PriceRegistryInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterOwnershipTransferRequested_Call) Return(_a0 *price_registry.PriceRegistryOwnershipTransferRequestedIterator, _a1 error) *PriceRegistryInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*price_registry.PriceRegistryOwnershipTransferRequestedIterator, error)) *PriceRegistryInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to
+func (_m *PriceRegistryInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*price_registry.PriceRegistryOwnershipTransferredIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferred")
+ }
+
+ var r0 *price_registry.PriceRegistryOwnershipTransferredIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*price_registry.PriceRegistryOwnershipTransferredIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *price_registry.PriceRegistryOwnershipTransferredIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryOwnershipTransferredIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferred'
+type PriceRegistryInterface_FilterOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterOwnershipTransferred(opts interface{}, from interface{}, to interface{}) *PriceRegistryInterface_FilterOwnershipTransferred_Call {
+ return &PriceRegistryInterface_FilterOwnershipTransferred_Call{Call: _e.mock.On("FilterOwnershipTransferred", opts, from, to)}
+}
+
+func (_c *PriceRegistryInterface_FilterOwnershipTransferred_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *PriceRegistryInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterOwnershipTransferred_Call) Return(_a0 *price_registry.PriceRegistryOwnershipTransferredIterator, _a1 error) *PriceRegistryInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterOwnershipTransferred_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*price_registry.PriceRegistryOwnershipTransferredIterator, error)) *PriceRegistryInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPremiumMultiplierWeiPerEthUpdated provides a mock function with given fields: opts, token
+func (_m *PriceRegistryInterface) FilterPremiumMultiplierWeiPerEthUpdated(opts *bind.FilterOpts, token []common.Address) (*price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPremiumMultiplierWeiPerEthUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator); ok {
+ r0 = rf(opts, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPremiumMultiplierWeiPerEthUpdated'
+type PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterPremiumMultiplierWeiPerEthUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterPremiumMultiplierWeiPerEthUpdated(opts interface{}, token interface{}) *PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call {
+ return &PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call{Call: _e.mock.On("FilterPremiumMultiplierWeiPerEthUpdated", opts, token)}
+}
+
+func (_c *PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call) Run(run func(opts *bind.FilterOpts, token []common.Address)) *PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call) Return(_a0 *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator, _a1 error) *PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdatedIterator, error)) *PriceRegistryInterface_FilterPremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPriceFeedPerTokenUpdated provides a mock function with given fields: opts, token
+func (_m *PriceRegistryInterface) FilterPriceFeedPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*price_registry.PriceRegistryPriceFeedPerTokenUpdatedIterator, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPriceFeedPerTokenUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryPriceFeedPerTokenUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPriceFeedPerTokenUpdatedIterator, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *price_registry.PriceRegistryPriceFeedPerTokenUpdatedIterator); ok {
+ r0 = rf(opts, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryPriceFeedPerTokenUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPriceFeedPerTokenUpdated'
+type PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterPriceFeedPerTokenUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterPriceFeedPerTokenUpdated(opts interface{}, token interface{}) *PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call {
+ return &PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call{Call: _e.mock.On("FilterPriceFeedPerTokenUpdated", opts, token)}
+}
+
+func (_c *PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call) Run(run func(opts *bind.FilterOpts, token []common.Address)) *PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call) Return(_a0 *price_registry.PriceRegistryPriceFeedPerTokenUpdatedIterator, _a1 error) *PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPriceFeedPerTokenUpdatedIterator, error)) *PriceRegistryInterface_FilterPriceFeedPerTokenUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPriceUpdaterRemoved provides a mock function with given fields: opts, priceUpdater
+func (_m *PriceRegistryInterface) FilterPriceUpdaterRemoved(opts *bind.FilterOpts, priceUpdater []common.Address) (*price_registry.PriceRegistryPriceUpdaterRemovedIterator, error) {
+ ret := _m.Called(opts, priceUpdater)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPriceUpdaterRemoved")
+ }
+
+ var r0 *price_registry.PriceRegistryPriceUpdaterRemovedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPriceUpdaterRemovedIterator, error)); ok {
+ return rf(opts, priceUpdater)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *price_registry.PriceRegistryPriceUpdaterRemovedIterator); ok {
+ r0 = rf(opts, priceUpdater)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryPriceUpdaterRemovedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, priceUpdater)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterPriceUpdaterRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPriceUpdaterRemoved'
+type PriceRegistryInterface_FilterPriceUpdaterRemoved_Call struct {
+ *mock.Call
+}
+
+// FilterPriceUpdaterRemoved is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - priceUpdater []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterPriceUpdaterRemoved(opts interface{}, priceUpdater interface{}) *PriceRegistryInterface_FilterPriceUpdaterRemoved_Call {
+ return &PriceRegistryInterface_FilterPriceUpdaterRemoved_Call{Call: _e.mock.On("FilterPriceUpdaterRemoved", opts, priceUpdater)}
+}
+
+func (_c *PriceRegistryInterface_FilterPriceUpdaterRemoved_Call) Run(run func(opts *bind.FilterOpts, priceUpdater []common.Address)) *PriceRegistryInterface_FilterPriceUpdaterRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterPriceUpdaterRemoved_Call) Return(_a0 *price_registry.PriceRegistryPriceUpdaterRemovedIterator, _a1 error) *PriceRegistryInterface_FilterPriceUpdaterRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterPriceUpdaterRemoved_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPriceUpdaterRemovedIterator, error)) *PriceRegistryInterface_FilterPriceUpdaterRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPriceUpdaterSet provides a mock function with given fields: opts, priceUpdater
+func (_m *PriceRegistryInterface) FilterPriceUpdaterSet(opts *bind.FilterOpts, priceUpdater []common.Address) (*price_registry.PriceRegistryPriceUpdaterSetIterator, error) {
+ ret := _m.Called(opts, priceUpdater)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPriceUpdaterSet")
+ }
+
+ var r0 *price_registry.PriceRegistryPriceUpdaterSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPriceUpdaterSetIterator, error)); ok {
+ return rf(opts, priceUpdater)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *price_registry.PriceRegistryPriceUpdaterSetIterator); ok {
+ r0 = rf(opts, priceUpdater)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryPriceUpdaterSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, priceUpdater)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterPriceUpdaterSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPriceUpdaterSet'
+type PriceRegistryInterface_FilterPriceUpdaterSet_Call struct {
+ *mock.Call
+}
+
+// FilterPriceUpdaterSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - priceUpdater []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterPriceUpdaterSet(opts interface{}, priceUpdater interface{}) *PriceRegistryInterface_FilterPriceUpdaterSet_Call {
+ return &PriceRegistryInterface_FilterPriceUpdaterSet_Call{Call: _e.mock.On("FilterPriceUpdaterSet", opts, priceUpdater)}
+}
+
+func (_c *PriceRegistryInterface_FilterPriceUpdaterSet_Call) Run(run func(opts *bind.FilterOpts, priceUpdater []common.Address)) *PriceRegistryInterface_FilterPriceUpdaterSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterPriceUpdaterSet_Call) Return(_a0 *price_registry.PriceRegistryPriceUpdaterSetIterator, _a1 error) *PriceRegistryInterface_FilterPriceUpdaterSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterPriceUpdaterSet_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryPriceUpdaterSetIterator, error)) *PriceRegistryInterface_FilterPriceUpdaterSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTokenTransferFeeConfigDeleted provides a mock function with given fields: opts, destChainSelector, token
+func (_m *PriceRegistryInterface) FilterTokenTransferFeeConfigDeleted(opts *bind.FilterOpts, destChainSelector []uint64, token []common.Address) (*price_registry.PriceRegistryTokenTransferFeeConfigDeletedIterator, error) {
+ ret := _m.Called(opts, destChainSelector, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTokenTransferFeeConfigDeleted")
+ }
+
+ var r0 *price_registry.PriceRegistryTokenTransferFeeConfigDeletedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*price_registry.PriceRegistryTokenTransferFeeConfigDeletedIterator, error)); ok {
+ return rf(opts, destChainSelector, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) *price_registry.PriceRegistryTokenTransferFeeConfigDeletedIterator); ok {
+ r0 = rf(opts, destChainSelector, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryTokenTransferFeeConfigDeletedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, destChainSelector, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTokenTransferFeeConfigDeleted'
+type PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call struct {
+ *mock.Call
+}
+
+// FilterTokenTransferFeeConfigDeleted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - destChainSelector []uint64
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterTokenTransferFeeConfigDeleted(opts interface{}, destChainSelector interface{}, token interface{}) *PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call {
+ return &PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call{Call: _e.mock.On("FilterTokenTransferFeeConfigDeleted", opts, destChainSelector, token)}
+}
+
+func (_c *PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call) Run(run func(opts *bind.FilterOpts, destChainSelector []uint64, token []common.Address)) *PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call) Return(_a0 *price_registry.PriceRegistryTokenTransferFeeConfigDeletedIterator, _a1 error) *PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, []common.Address) (*price_registry.PriceRegistryTokenTransferFeeConfigDeletedIterator, error)) *PriceRegistryInterface_FilterTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTokenTransferFeeConfigUpdated provides a mock function with given fields: opts, destChainSelector, token
+func (_m *PriceRegistryInterface) FilterTokenTransferFeeConfigUpdated(opts *bind.FilterOpts, destChainSelector []uint64, token []common.Address) (*price_registry.PriceRegistryTokenTransferFeeConfigUpdatedIterator, error) {
+ ret := _m.Called(opts, destChainSelector, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTokenTransferFeeConfigUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryTokenTransferFeeConfigUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*price_registry.PriceRegistryTokenTransferFeeConfigUpdatedIterator, error)); ok {
+ return rf(opts, destChainSelector, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) *price_registry.PriceRegistryTokenTransferFeeConfigUpdatedIterator); ok {
+ r0 = rf(opts, destChainSelector, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryTokenTransferFeeConfigUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, destChainSelector, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTokenTransferFeeConfigUpdated'
+type PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterTokenTransferFeeConfigUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - destChainSelector []uint64
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterTokenTransferFeeConfigUpdated(opts interface{}, destChainSelector interface{}, token interface{}) *PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call {
+ return &PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call{Call: _e.mock.On("FilterTokenTransferFeeConfigUpdated", opts, destChainSelector, token)}
+}
+
+func (_c *PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call) Run(run func(opts *bind.FilterOpts, destChainSelector []uint64, token []common.Address)) *PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call) Return(_a0 *price_registry.PriceRegistryTokenTransferFeeConfigUpdatedIterator, _a1 error) *PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, []common.Address) (*price_registry.PriceRegistryTokenTransferFeeConfigUpdatedIterator, error)) *PriceRegistryInterface_FilterTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterUsdPerTokenUpdated provides a mock function with given fields: opts, token
+func (_m *PriceRegistryInterface) FilterUsdPerTokenUpdated(opts *bind.FilterOpts, token []common.Address) (*price_registry.PriceRegistryUsdPerTokenUpdatedIterator, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterUsdPerTokenUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryUsdPerTokenUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryUsdPerTokenUpdatedIterator, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *price_registry.PriceRegistryUsdPerTokenUpdatedIterator); ok {
+ r0 = rf(opts, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryUsdPerTokenUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterUsdPerTokenUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterUsdPerTokenUpdated'
+type PriceRegistryInterface_FilterUsdPerTokenUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterUsdPerTokenUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) FilterUsdPerTokenUpdated(opts interface{}, token interface{}) *PriceRegistryInterface_FilterUsdPerTokenUpdated_Call {
+ return &PriceRegistryInterface_FilterUsdPerTokenUpdated_Call{Call: _e.mock.On("FilterUsdPerTokenUpdated", opts, token)}
+}
+
+func (_c *PriceRegistryInterface_FilterUsdPerTokenUpdated_Call) Run(run func(opts *bind.FilterOpts, token []common.Address)) *PriceRegistryInterface_FilterUsdPerTokenUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterUsdPerTokenUpdated_Call) Return(_a0 *price_registry.PriceRegistryUsdPerTokenUpdatedIterator, _a1 error) *PriceRegistryInterface_FilterUsdPerTokenUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterUsdPerTokenUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*price_registry.PriceRegistryUsdPerTokenUpdatedIterator, error)) *PriceRegistryInterface_FilterUsdPerTokenUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterUsdPerUnitGasUpdated provides a mock function with given fields: opts, destChain
+func (_m *PriceRegistryInterface) FilterUsdPerUnitGasUpdated(opts *bind.FilterOpts, destChain []uint64) (*price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator, error) {
+ ret := _m.Called(opts, destChain)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterUsdPerUnitGasUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator, error)); ok {
+ return rf(opts, destChain)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) *price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator); ok {
+ r0 = rf(opts, destChain)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64) error); ok {
+ r1 = rf(opts, destChain)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterUsdPerUnitGasUpdated'
+type PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterUsdPerUnitGasUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - destChain []uint64
+func (_e *PriceRegistryInterface_Expecter) FilterUsdPerUnitGasUpdated(opts interface{}, destChain interface{}) *PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call {
+ return &PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call{Call: _e.mock.On("FilterUsdPerUnitGasUpdated", opts, destChain)}
+}
+
+func (_c *PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call) Run(run func(opts *bind.FilterOpts, destChain []uint64)) *PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call) Return(_a0 *price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator, _a1 error) *PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64) (*price_registry.PriceRegistryUsdPerUnitGasUpdatedIterator, error)) *PriceRegistryInterface_FilterUsdPerUnitGasUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetAllAuthorizedCallers provides a mock function with given fields: opts
+func (_m *PriceRegistryInterface) GetAllAuthorizedCallers(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetAllAuthorizedCallers")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetAllAuthorizedCallers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllAuthorizedCallers'
+type PriceRegistryInterface_GetAllAuthorizedCallers_Call struct {
+ *mock.Call
+}
+
+// GetAllAuthorizedCallers is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *PriceRegistryInterface_Expecter) GetAllAuthorizedCallers(opts interface{}) *PriceRegistryInterface_GetAllAuthorizedCallers_Call {
+ return &PriceRegistryInterface_GetAllAuthorizedCallers_Call{Call: _e.mock.On("GetAllAuthorizedCallers", opts)}
+}
+
+func (_c *PriceRegistryInterface_GetAllAuthorizedCallers_Call) Run(run func(opts *bind.CallOpts)) *PriceRegistryInterface_GetAllAuthorizedCallers_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetAllAuthorizedCallers_Call) Return(_a0 []common.Address, _a1 error) *PriceRegistryInterface_GetAllAuthorizedCallers_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetAllAuthorizedCallers_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *PriceRegistryInterface_GetAllAuthorizedCallers_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDestChainConfig provides a mock function with given fields: opts, destChainSelector
+func (_m *PriceRegistryInterface) GetDestChainConfig(opts *bind.CallOpts, destChainSelector uint64) (price_registry.PriceRegistryDestChainConfig, error) {
+ ret := _m.Called(opts, destChainSelector)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDestChainConfig")
+ }
+
+ var r0 price_registry.PriceRegistryDestChainConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (price_registry.PriceRegistryDestChainConfig, error)); ok {
+ return rf(opts, destChainSelector)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) price_registry.PriceRegistryDestChainConfig); ok {
+ r0 = rf(opts, destChainSelector)
+ } else {
+ r0 = ret.Get(0).(price_registry.PriceRegistryDestChainConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, destChainSelector)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetDestChainConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDestChainConfig'
+type PriceRegistryInterface_GetDestChainConfig_Call struct {
+ *mock.Call
+}
+
+// GetDestChainConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destChainSelector uint64
+func (_e *PriceRegistryInterface_Expecter) GetDestChainConfig(opts interface{}, destChainSelector interface{}) *PriceRegistryInterface_GetDestChainConfig_Call {
+ return &PriceRegistryInterface_GetDestChainConfig_Call{Call: _e.mock.On("GetDestChainConfig", opts, destChainSelector)}
+}
+
+func (_c *PriceRegistryInterface_GetDestChainConfig_Call) Run(run func(opts *bind.CallOpts, destChainSelector uint64)) *PriceRegistryInterface_GetDestChainConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetDestChainConfig_Call) Return(_a0 price_registry.PriceRegistryDestChainConfig, _a1 error) *PriceRegistryInterface_GetDestChainConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetDestChainConfig_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (price_registry.PriceRegistryDestChainConfig, error)) *PriceRegistryInterface_GetDestChainConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDestinationChainGasPrice provides a mock function with given fields: opts, destChainSelector
+func (_m *PriceRegistryInterface) GetDestinationChainGasPrice(opts *bind.CallOpts, destChainSelector uint64) (price_registry.InternalTimestampedPackedUint224, error) {
+ ret := _m.Called(opts, destChainSelector)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDestinationChainGasPrice")
+ }
+
+ var r0 price_registry.InternalTimestampedPackedUint224
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (price_registry.InternalTimestampedPackedUint224, error)); ok {
+ return rf(opts, destChainSelector)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) price_registry.InternalTimestampedPackedUint224); ok {
+ r0 = rf(opts, destChainSelector)
+ } else {
+ r0 = ret.Get(0).(price_registry.InternalTimestampedPackedUint224)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, destChainSelector)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetDestinationChainGasPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDestinationChainGasPrice'
+type PriceRegistryInterface_GetDestinationChainGasPrice_Call struct {
+ *mock.Call
+}
+
+// GetDestinationChainGasPrice is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destChainSelector uint64
+func (_e *PriceRegistryInterface_Expecter) GetDestinationChainGasPrice(opts interface{}, destChainSelector interface{}) *PriceRegistryInterface_GetDestinationChainGasPrice_Call {
+ return &PriceRegistryInterface_GetDestinationChainGasPrice_Call{Call: _e.mock.On("GetDestinationChainGasPrice", opts, destChainSelector)}
+}
+
+func (_c *PriceRegistryInterface_GetDestinationChainGasPrice_Call) Run(run func(opts *bind.CallOpts, destChainSelector uint64)) *PriceRegistryInterface_GetDestinationChainGasPrice_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetDestinationChainGasPrice_Call) Return(_a0 price_registry.InternalTimestampedPackedUint224, _a1 error) *PriceRegistryInterface_GetDestinationChainGasPrice_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetDestinationChainGasPrice_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (price_registry.InternalTimestampedPackedUint224, error)) *PriceRegistryInterface_GetDestinationChainGasPrice_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetFeeTokens provides a mock function with given fields: opts
+func (_m *PriceRegistryInterface) GetFeeTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetFeeTokens")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetFeeTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeeTokens'
+type PriceRegistryInterface_GetFeeTokens_Call struct {
+ *mock.Call
+}
+
+// GetFeeTokens is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *PriceRegistryInterface_Expecter) GetFeeTokens(opts interface{}) *PriceRegistryInterface_GetFeeTokens_Call {
+ return &PriceRegistryInterface_GetFeeTokens_Call{Call: _e.mock.On("GetFeeTokens", opts)}
+}
+
+func (_c *PriceRegistryInterface_GetFeeTokens_Call) Run(run func(opts *bind.CallOpts)) *PriceRegistryInterface_GetFeeTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetFeeTokens_Call) Return(_a0 []common.Address, _a1 error) *PriceRegistryInterface_GetFeeTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetFeeTokens_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *PriceRegistryInterface_GetFeeTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetPremiumMultiplierWeiPerEth provides a mock function with given fields: opts, token
+func (_m *PriceRegistryInterface) GetPremiumMultiplierWeiPerEth(opts *bind.CallOpts, token common.Address) (uint64, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetPremiumMultiplierWeiPerEth")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) uint64); ok {
+ r0 = rf(opts, token)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPremiumMultiplierWeiPerEth'
+type PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call struct {
+ *mock.Call
+}
+
+// GetPremiumMultiplierWeiPerEth is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - token common.Address
+func (_e *PriceRegistryInterface_Expecter) GetPremiumMultiplierWeiPerEth(opts interface{}, token interface{}) *PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call {
+ return &PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call{Call: _e.mock.On("GetPremiumMultiplierWeiPerEth", opts, token)}
+}
+
+func (_c *PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call) Run(run func(opts *bind.CallOpts, token common.Address)) *PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call) Return(_a0 uint64, _a1 error) *PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (uint64, error)) *PriceRegistryInterface_GetPremiumMultiplierWeiPerEth_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStaticConfig provides a mock function with given fields: opts
+func (_m *PriceRegistryInterface) GetStaticConfig(opts *bind.CallOpts) (price_registry.PriceRegistryStaticConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStaticConfig")
+ }
+
+ var r0 price_registry.PriceRegistryStaticConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (price_registry.PriceRegistryStaticConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) price_registry.PriceRegistryStaticConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(price_registry.PriceRegistryStaticConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetStaticConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStaticConfig'
+type PriceRegistryInterface_GetStaticConfig_Call struct {
+ *mock.Call
+}
+
+// GetStaticConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *PriceRegistryInterface_Expecter) GetStaticConfig(opts interface{}) *PriceRegistryInterface_GetStaticConfig_Call {
+ return &PriceRegistryInterface_GetStaticConfig_Call{Call: _e.mock.On("GetStaticConfig", opts)}
+}
+
+func (_c *PriceRegistryInterface_GetStaticConfig_Call) Run(run func(opts *bind.CallOpts)) *PriceRegistryInterface_GetStaticConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetStaticConfig_Call) Return(_a0 price_registry.PriceRegistryStaticConfig, _a1 error) *PriceRegistryInterface_GetStaticConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetStaticConfig_Call) RunAndReturn(run func(*bind.CallOpts) (price_registry.PriceRegistryStaticConfig, error)) *PriceRegistryInterface_GetStaticConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenAndGasPrices provides a mock function with given fields: opts, token, destChainSelector
+func (_m *PriceRegistryInterface) GetTokenAndGasPrices(opts *bind.CallOpts, token common.Address, destChainSelector uint64) (price_registry.GetTokenAndGasPrices, error) {
+ ret := _m.Called(opts, token, destChainSelector)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenAndGasPrices")
+ }
+
+ var r0 price_registry.GetTokenAndGasPrices
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, uint64) (price_registry.GetTokenAndGasPrices, error)); ok {
+ return rf(opts, token, destChainSelector)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, uint64) price_registry.GetTokenAndGasPrices); ok {
+ r0 = rf(opts, token, destChainSelector)
+ } else {
+ r0 = ret.Get(0).(price_registry.GetTokenAndGasPrices)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address, uint64) error); ok {
+ r1 = rf(opts, token, destChainSelector)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetTokenAndGasPrices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenAndGasPrices'
+type PriceRegistryInterface_GetTokenAndGasPrices_Call struct {
+ *mock.Call
+}
+
+// GetTokenAndGasPrices is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - token common.Address
+// - destChainSelector uint64
+func (_e *PriceRegistryInterface_Expecter) GetTokenAndGasPrices(opts interface{}, token interface{}, destChainSelector interface{}) *PriceRegistryInterface_GetTokenAndGasPrices_Call {
+ return &PriceRegistryInterface_GetTokenAndGasPrices_Call{Call: _e.mock.On("GetTokenAndGasPrices", opts, token, destChainSelector)}
+}
+
+func (_c *PriceRegistryInterface_GetTokenAndGasPrices_Call) Run(run func(opts *bind.CallOpts, token common.Address, destChainSelector uint64)) *PriceRegistryInterface_GetTokenAndGasPrices_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address), args[2].(uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenAndGasPrices_Call) Return(_a0 price_registry.GetTokenAndGasPrices, _a1 error) *PriceRegistryInterface_GetTokenAndGasPrices_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenAndGasPrices_Call) RunAndReturn(run func(*bind.CallOpts, common.Address, uint64) (price_registry.GetTokenAndGasPrices, error)) *PriceRegistryInterface_GetTokenAndGasPrices_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenPrice provides a mock function with given fields: opts, token
+func (_m *PriceRegistryInterface) GetTokenPrice(opts *bind.CallOpts, token common.Address) (price_registry.InternalTimestampedPackedUint224, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenPrice")
+ }
+
+ var r0 price_registry.InternalTimestampedPackedUint224
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (price_registry.InternalTimestampedPackedUint224, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) price_registry.InternalTimestampedPackedUint224); ok {
+ r0 = rf(opts, token)
+ } else {
+ r0 = ret.Get(0).(price_registry.InternalTimestampedPackedUint224)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetTokenPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenPrice'
+type PriceRegistryInterface_GetTokenPrice_Call struct {
+ *mock.Call
+}
+
+// GetTokenPrice is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - token common.Address
+func (_e *PriceRegistryInterface_Expecter) GetTokenPrice(opts interface{}, token interface{}) *PriceRegistryInterface_GetTokenPrice_Call {
+ return &PriceRegistryInterface_GetTokenPrice_Call{Call: _e.mock.On("GetTokenPrice", opts, token)}
+}
+
+func (_c *PriceRegistryInterface_GetTokenPrice_Call) Run(run func(opts *bind.CallOpts, token common.Address)) *PriceRegistryInterface_GetTokenPrice_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenPrice_Call) Return(_a0 price_registry.InternalTimestampedPackedUint224, _a1 error) *PriceRegistryInterface_GetTokenPrice_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenPrice_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (price_registry.InternalTimestampedPackedUint224, error)) *PriceRegistryInterface_GetTokenPrice_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenPriceFeedConfig provides a mock function with given fields: opts, token
+func (_m *PriceRegistryInterface) GetTokenPriceFeedConfig(opts *bind.CallOpts, token common.Address) (price_registry.IPriceRegistryTokenPriceFeedConfig, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenPriceFeedConfig")
+ }
+
+ var r0 price_registry.IPriceRegistryTokenPriceFeedConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (price_registry.IPriceRegistryTokenPriceFeedConfig, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) price_registry.IPriceRegistryTokenPriceFeedConfig); ok {
+ r0 = rf(opts, token)
+ } else {
+ r0 = ret.Get(0).(price_registry.IPriceRegistryTokenPriceFeedConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetTokenPriceFeedConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenPriceFeedConfig'
+type PriceRegistryInterface_GetTokenPriceFeedConfig_Call struct {
+ *mock.Call
+}
+
+// GetTokenPriceFeedConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - token common.Address
+func (_e *PriceRegistryInterface_Expecter) GetTokenPriceFeedConfig(opts interface{}, token interface{}) *PriceRegistryInterface_GetTokenPriceFeedConfig_Call {
+ return &PriceRegistryInterface_GetTokenPriceFeedConfig_Call{Call: _e.mock.On("GetTokenPriceFeedConfig", opts, token)}
+}
+
+func (_c *PriceRegistryInterface_GetTokenPriceFeedConfig_Call) Run(run func(opts *bind.CallOpts, token common.Address)) *PriceRegistryInterface_GetTokenPriceFeedConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenPriceFeedConfig_Call) Return(_a0 price_registry.IPriceRegistryTokenPriceFeedConfig, _a1 error) *PriceRegistryInterface_GetTokenPriceFeedConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenPriceFeedConfig_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (price_registry.IPriceRegistryTokenPriceFeedConfig, error)) *PriceRegistryInterface_GetTokenPriceFeedConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenPrices provides a mock function with given fields: opts, tokens
+func (_m *PriceRegistryInterface) GetTokenPrices(opts *bind.CallOpts, tokens []common.Address) ([]price_registry.InternalTimestampedPackedUint224, error) {
+ ret := _m.Called(opts, tokens)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenPrices")
+ }
+
+ var r0 []price_registry.InternalTimestampedPackedUint224
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, []common.Address) ([]price_registry.InternalTimestampedPackedUint224, error)); ok {
+ return rf(opts, tokens)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, []common.Address) []price_registry.InternalTimestampedPackedUint224); ok {
+ r0 = rf(opts, tokens)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]price_registry.InternalTimestampedPackedUint224)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, []common.Address) error); ok {
+ r1 = rf(opts, tokens)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetTokenPrices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenPrices'
+type PriceRegistryInterface_GetTokenPrices_Call struct {
+ *mock.Call
+}
+
+// GetTokenPrices is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - tokens []common.Address
+func (_e *PriceRegistryInterface_Expecter) GetTokenPrices(opts interface{}, tokens interface{}) *PriceRegistryInterface_GetTokenPrices_Call {
+ return &PriceRegistryInterface_GetTokenPrices_Call{Call: _e.mock.On("GetTokenPrices", opts, tokens)}
+}
+
+func (_c *PriceRegistryInterface_GetTokenPrices_Call) Run(run func(opts *bind.CallOpts, tokens []common.Address)) *PriceRegistryInterface_GetTokenPrices_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenPrices_Call) Return(_a0 []price_registry.InternalTimestampedPackedUint224, _a1 error) *PriceRegistryInterface_GetTokenPrices_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenPrices_Call) RunAndReturn(run func(*bind.CallOpts, []common.Address) ([]price_registry.InternalTimestampedPackedUint224, error)) *PriceRegistryInterface_GetTokenPrices_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenTransferFeeConfig provides a mock function with given fields: opts, destChainSelector, token
+func (_m *PriceRegistryInterface) GetTokenTransferFeeConfig(opts *bind.CallOpts, destChainSelector uint64, token common.Address) (price_registry.PriceRegistryTokenTransferFeeConfig, error) {
+ ret := _m.Called(opts, destChainSelector, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenTransferFeeConfig")
+ }
+
+ var r0 price_registry.PriceRegistryTokenTransferFeeConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address) (price_registry.PriceRegistryTokenTransferFeeConfig, error)); ok {
+ return rf(opts, destChainSelector, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address) price_registry.PriceRegistryTokenTransferFeeConfig); ok {
+ r0 = rf(opts, destChainSelector, token)
+ } else {
+ r0 = ret.Get(0).(price_registry.PriceRegistryTokenTransferFeeConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64, common.Address) error); ok {
+ r1 = rf(opts, destChainSelector, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetTokenTransferFeeConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenTransferFeeConfig'
+type PriceRegistryInterface_GetTokenTransferFeeConfig_Call struct {
+ *mock.Call
+}
+
+// GetTokenTransferFeeConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destChainSelector uint64
+// - token common.Address
+func (_e *PriceRegistryInterface_Expecter) GetTokenTransferFeeConfig(opts interface{}, destChainSelector interface{}, token interface{}) *PriceRegistryInterface_GetTokenTransferFeeConfig_Call {
+ return &PriceRegistryInterface_GetTokenTransferFeeConfig_Call{Call: _e.mock.On("GetTokenTransferFeeConfig", opts, destChainSelector, token)}
+}
+
+func (_c *PriceRegistryInterface_GetTokenTransferFeeConfig_Call) Run(run func(opts *bind.CallOpts, destChainSelector uint64, token common.Address)) *PriceRegistryInterface_GetTokenTransferFeeConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64), args[2].(common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenTransferFeeConfig_Call) Return(_a0 price_registry.PriceRegistryTokenTransferFeeConfig, _a1 error) *PriceRegistryInterface_GetTokenTransferFeeConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetTokenTransferFeeConfig_Call) RunAndReturn(run func(*bind.CallOpts, uint64, common.Address) (price_registry.PriceRegistryTokenTransferFeeConfig, error)) *PriceRegistryInterface_GetTokenTransferFeeConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetValidatedFee provides a mock function with given fields: opts, destChainSelector, message
+func (_m *PriceRegistryInterface) GetValidatedFee(opts *bind.CallOpts, destChainSelector uint64, message price_registry.ClientEVM2AnyMessage) (*big.Int, error) {
+ ret := _m.Called(opts, destChainSelector, message)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetValidatedFee")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, price_registry.ClientEVM2AnyMessage) (*big.Int, error)); ok {
+ return rf(opts, destChainSelector, message)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, price_registry.ClientEVM2AnyMessage) *big.Int); ok {
+ r0 = rf(opts, destChainSelector, message)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64, price_registry.ClientEVM2AnyMessage) error); ok {
+ r1 = rf(opts, destChainSelector, message)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetValidatedFee_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetValidatedFee'
+type PriceRegistryInterface_GetValidatedFee_Call struct {
+ *mock.Call
+}
+
+// GetValidatedFee is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destChainSelector uint64
+// - message price_registry.ClientEVM2AnyMessage
+func (_e *PriceRegistryInterface_Expecter) GetValidatedFee(opts interface{}, destChainSelector interface{}, message interface{}) *PriceRegistryInterface_GetValidatedFee_Call {
+ return &PriceRegistryInterface_GetValidatedFee_Call{Call: _e.mock.On("GetValidatedFee", opts, destChainSelector, message)}
+}
+
+func (_c *PriceRegistryInterface_GetValidatedFee_Call) Run(run func(opts *bind.CallOpts, destChainSelector uint64, message price_registry.ClientEVM2AnyMessage)) *PriceRegistryInterface_GetValidatedFee_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64), args[2].(price_registry.ClientEVM2AnyMessage))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetValidatedFee_Call) Return(_a0 *big.Int, _a1 error) *PriceRegistryInterface_GetValidatedFee_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetValidatedFee_Call) RunAndReturn(run func(*bind.CallOpts, uint64, price_registry.ClientEVM2AnyMessage) (*big.Int, error)) *PriceRegistryInterface_GetValidatedFee_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetValidatedTokenPrice provides a mock function with given fields: opts, token
+func (_m *PriceRegistryInterface) GetValidatedTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error) {
+ ret := _m.Called(opts, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetValidatedTokenPrice")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok {
+ return rf(opts, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) *big.Int); ok {
+ r0 = rf(opts, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_GetValidatedTokenPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetValidatedTokenPrice'
+type PriceRegistryInterface_GetValidatedTokenPrice_Call struct {
+ *mock.Call
+}
+
+// GetValidatedTokenPrice is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - token common.Address
+func (_e *PriceRegistryInterface_Expecter) GetValidatedTokenPrice(opts interface{}, token interface{}) *PriceRegistryInterface_GetValidatedTokenPrice_Call {
+ return &PriceRegistryInterface_GetValidatedTokenPrice_Call{Call: _e.mock.On("GetValidatedTokenPrice", opts, token)}
+}
+
+func (_c *PriceRegistryInterface_GetValidatedTokenPrice_Call) Run(run func(opts *bind.CallOpts, token common.Address)) *PriceRegistryInterface_GetValidatedTokenPrice_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetValidatedTokenPrice_Call) Return(_a0 *big.Int, _a1 error) *PriceRegistryInterface_GetValidatedTokenPrice_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_GetValidatedTokenPrice_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (*big.Int, error)) *PriceRegistryInterface_GetValidatedTokenPrice_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Owner provides a mock function with given fields: opts
+func (_m *PriceRegistryInterface) Owner(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Owner")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_Owner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Owner'
+type PriceRegistryInterface_Owner_Call struct {
+ *mock.Call
+}
+
+// Owner is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *PriceRegistryInterface_Expecter) Owner(opts interface{}) *PriceRegistryInterface_Owner_Call {
+ return &PriceRegistryInterface_Owner_Call{Call: _e.mock.On("Owner", opts)}
+}
+
+func (_c *PriceRegistryInterface_Owner_Call) Run(run func(opts *bind.CallOpts)) *PriceRegistryInterface_Owner_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_Owner_Call) Return(_a0 common.Address, _a1 error) *PriceRegistryInterface_Owner_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_Owner_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *PriceRegistryInterface_Owner_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseAuthorizedCallerAdded provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseAuthorizedCallerAdded(log types.Log) (*price_registry.PriceRegistryAuthorizedCallerAdded, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseAuthorizedCallerAdded")
+ }
+
+ var r0 *price_registry.PriceRegistryAuthorizedCallerAdded
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryAuthorizedCallerAdded, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryAuthorizedCallerAdded); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryAuthorizedCallerAdded)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseAuthorizedCallerAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseAuthorizedCallerAdded'
+type PriceRegistryInterface_ParseAuthorizedCallerAdded_Call struct {
+ *mock.Call
+}
+
+// ParseAuthorizedCallerAdded is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseAuthorizedCallerAdded(log interface{}) *PriceRegistryInterface_ParseAuthorizedCallerAdded_Call {
+ return &PriceRegistryInterface_ParseAuthorizedCallerAdded_Call{Call: _e.mock.On("ParseAuthorizedCallerAdded", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseAuthorizedCallerAdded_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseAuthorizedCallerAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseAuthorizedCallerAdded_Call) Return(_a0 *price_registry.PriceRegistryAuthorizedCallerAdded, _a1 error) *PriceRegistryInterface_ParseAuthorizedCallerAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseAuthorizedCallerAdded_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryAuthorizedCallerAdded, error)) *PriceRegistryInterface_ParseAuthorizedCallerAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseAuthorizedCallerRemoved provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseAuthorizedCallerRemoved(log types.Log) (*price_registry.PriceRegistryAuthorizedCallerRemoved, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseAuthorizedCallerRemoved")
+ }
+
+ var r0 *price_registry.PriceRegistryAuthorizedCallerRemoved
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryAuthorizedCallerRemoved, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryAuthorizedCallerRemoved); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryAuthorizedCallerRemoved)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseAuthorizedCallerRemoved'
+type PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call struct {
+ *mock.Call
+}
+
+// ParseAuthorizedCallerRemoved is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseAuthorizedCallerRemoved(log interface{}) *PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call {
+ return &PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call{Call: _e.mock.On("ParseAuthorizedCallerRemoved", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call) Return(_a0 *price_registry.PriceRegistryAuthorizedCallerRemoved, _a1 error) *PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryAuthorizedCallerRemoved, error)) *PriceRegistryInterface_ParseAuthorizedCallerRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseDestChainAdded provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseDestChainAdded(log types.Log) (*price_registry.PriceRegistryDestChainAdded, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseDestChainAdded")
+ }
+
+ var r0 *price_registry.PriceRegistryDestChainAdded
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryDestChainAdded, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryDestChainAdded); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryDestChainAdded)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseDestChainAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseDestChainAdded'
+type PriceRegistryInterface_ParseDestChainAdded_Call struct {
+ *mock.Call
+}
+
+// ParseDestChainAdded is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseDestChainAdded(log interface{}) *PriceRegistryInterface_ParseDestChainAdded_Call {
+ return &PriceRegistryInterface_ParseDestChainAdded_Call{Call: _e.mock.On("ParseDestChainAdded", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseDestChainAdded_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseDestChainAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseDestChainAdded_Call) Return(_a0 *price_registry.PriceRegistryDestChainAdded, _a1 error) *PriceRegistryInterface_ParseDestChainAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseDestChainAdded_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryDestChainAdded, error)) *PriceRegistryInterface_ParseDestChainAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseDestChainConfigUpdated provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseDestChainConfigUpdated(log types.Log) (*price_registry.PriceRegistryDestChainConfigUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseDestChainConfigUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryDestChainConfigUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryDestChainConfigUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryDestChainConfigUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryDestChainConfigUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseDestChainConfigUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseDestChainConfigUpdated'
+type PriceRegistryInterface_ParseDestChainConfigUpdated_Call struct {
+ *mock.Call
+}
+
+// ParseDestChainConfigUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseDestChainConfigUpdated(log interface{}) *PriceRegistryInterface_ParseDestChainConfigUpdated_Call {
+ return &PriceRegistryInterface_ParseDestChainConfigUpdated_Call{Call: _e.mock.On("ParseDestChainConfigUpdated", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseDestChainConfigUpdated_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseDestChainConfigUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseDestChainConfigUpdated_Call) Return(_a0 *price_registry.PriceRegistryDestChainConfigUpdated, _a1 error) *PriceRegistryInterface_ParseDestChainConfigUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseDestChainConfigUpdated_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryDestChainConfigUpdated, error)) *PriceRegistryInterface_ParseDestChainConfigUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseFeeTokenAdded provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseFeeTokenAdded(log types.Log) (*price_registry.PriceRegistryFeeTokenAdded, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseFeeTokenAdded")
+ }
+
+ var r0 *price_registry.PriceRegistryFeeTokenAdded
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryFeeTokenAdded, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryFeeTokenAdded); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryFeeTokenAdded)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseFeeTokenAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseFeeTokenAdded'
+type PriceRegistryInterface_ParseFeeTokenAdded_Call struct {
+ *mock.Call
+}
+
+// ParseFeeTokenAdded is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseFeeTokenAdded(log interface{}) *PriceRegistryInterface_ParseFeeTokenAdded_Call {
+ return &PriceRegistryInterface_ParseFeeTokenAdded_Call{Call: _e.mock.On("ParseFeeTokenAdded", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseFeeTokenAdded_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseFeeTokenAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseFeeTokenAdded_Call) Return(_a0 *price_registry.PriceRegistryFeeTokenAdded, _a1 error) *PriceRegistryInterface_ParseFeeTokenAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseFeeTokenAdded_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryFeeTokenAdded, error)) *PriceRegistryInterface_ParseFeeTokenAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseFeeTokenRemoved provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseFeeTokenRemoved(log types.Log) (*price_registry.PriceRegistryFeeTokenRemoved, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseFeeTokenRemoved")
+ }
+
+ var r0 *price_registry.PriceRegistryFeeTokenRemoved
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryFeeTokenRemoved, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryFeeTokenRemoved); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryFeeTokenRemoved)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseFeeTokenRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseFeeTokenRemoved'
+type PriceRegistryInterface_ParseFeeTokenRemoved_Call struct {
+ *mock.Call
+}
+
+// ParseFeeTokenRemoved is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseFeeTokenRemoved(log interface{}) *PriceRegistryInterface_ParseFeeTokenRemoved_Call {
+ return &PriceRegistryInterface_ParseFeeTokenRemoved_Call{Call: _e.mock.On("ParseFeeTokenRemoved", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseFeeTokenRemoved_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseFeeTokenRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseFeeTokenRemoved_Call) Return(_a0 *price_registry.PriceRegistryFeeTokenRemoved, _a1 error) *PriceRegistryInterface_ParseFeeTokenRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseFeeTokenRemoved_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryFeeTokenRemoved, error)) *PriceRegistryInterface_ParseFeeTokenRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type PriceRegistryInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseLog(log interface{}) *PriceRegistryInterface_ParseLog_Call {
+ return &PriceRegistryInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseLog_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *PriceRegistryInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *PriceRegistryInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferRequested provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseOwnershipTransferRequested(log types.Log) (*price_registry.PriceRegistryOwnershipTransferRequested, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferRequested")
+ }
+
+ var r0 *price_registry.PriceRegistryOwnershipTransferRequested
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryOwnershipTransferRequested, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryOwnershipTransferRequested); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryOwnershipTransferRequested)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferRequested'
+type PriceRegistryInterface_ParseOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferRequested is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseOwnershipTransferRequested(log interface{}) *PriceRegistryInterface_ParseOwnershipTransferRequested_Call {
+ return &PriceRegistryInterface_ParseOwnershipTransferRequested_Call{Call: _e.mock.On("ParseOwnershipTransferRequested", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseOwnershipTransferRequested_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseOwnershipTransferRequested_Call) Return(_a0 *price_registry.PriceRegistryOwnershipTransferRequested, _a1 error) *PriceRegistryInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseOwnershipTransferRequested_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryOwnershipTransferRequested, error)) *PriceRegistryInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferred provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseOwnershipTransferred(log types.Log) (*price_registry.PriceRegistryOwnershipTransferred, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferred")
+ }
+
+ var r0 *price_registry.PriceRegistryOwnershipTransferred
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryOwnershipTransferred, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryOwnershipTransferred); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryOwnershipTransferred)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferred'
+type PriceRegistryInterface_ParseOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferred is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseOwnershipTransferred(log interface{}) *PriceRegistryInterface_ParseOwnershipTransferred_Call {
+ return &PriceRegistryInterface_ParseOwnershipTransferred_Call{Call: _e.mock.On("ParseOwnershipTransferred", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseOwnershipTransferred_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseOwnershipTransferred_Call) Return(_a0 *price_registry.PriceRegistryOwnershipTransferred, _a1 error) *PriceRegistryInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseOwnershipTransferred_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryOwnershipTransferred, error)) *PriceRegistryInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePremiumMultiplierWeiPerEthUpdated provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParsePremiumMultiplierWeiPerEthUpdated(log types.Log) (*price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePremiumMultiplierWeiPerEthUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePremiumMultiplierWeiPerEthUpdated'
+type PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call struct {
+ *mock.Call
+}
+
+// ParsePremiumMultiplierWeiPerEthUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParsePremiumMultiplierWeiPerEthUpdated(log interface{}) *PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call {
+ return &PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call{Call: _e.mock.On("ParsePremiumMultiplierWeiPerEthUpdated", log)}
+}
+
+func (_c *PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call) Return(_a0 *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, _a1 error) *PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, error)) *PriceRegistryInterface_ParsePremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePriceFeedPerTokenUpdated provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParsePriceFeedPerTokenUpdated(log types.Log) (*price_registry.PriceRegistryPriceFeedPerTokenUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePriceFeedPerTokenUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryPriceFeedPerTokenUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryPriceFeedPerTokenUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryPriceFeedPerTokenUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryPriceFeedPerTokenUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePriceFeedPerTokenUpdated'
+type PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call struct {
+ *mock.Call
+}
+
+// ParsePriceFeedPerTokenUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParsePriceFeedPerTokenUpdated(log interface{}) *PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call {
+ return &PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call{Call: _e.mock.On("ParsePriceFeedPerTokenUpdated", log)}
+}
+
+func (_c *PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call) Return(_a0 *price_registry.PriceRegistryPriceFeedPerTokenUpdated, _a1 error) *PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryPriceFeedPerTokenUpdated, error)) *PriceRegistryInterface_ParsePriceFeedPerTokenUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePriceUpdaterRemoved provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParsePriceUpdaterRemoved(log types.Log) (*price_registry.PriceRegistryPriceUpdaterRemoved, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePriceUpdaterRemoved")
+ }
+
+ var r0 *price_registry.PriceRegistryPriceUpdaterRemoved
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryPriceUpdaterRemoved, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryPriceUpdaterRemoved); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryPriceUpdaterRemoved)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParsePriceUpdaterRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePriceUpdaterRemoved'
+type PriceRegistryInterface_ParsePriceUpdaterRemoved_Call struct {
+ *mock.Call
+}
+
+// ParsePriceUpdaterRemoved is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParsePriceUpdaterRemoved(log interface{}) *PriceRegistryInterface_ParsePriceUpdaterRemoved_Call {
+ return &PriceRegistryInterface_ParsePriceUpdaterRemoved_Call{Call: _e.mock.On("ParsePriceUpdaterRemoved", log)}
+}
+
+func (_c *PriceRegistryInterface_ParsePriceUpdaterRemoved_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParsePriceUpdaterRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParsePriceUpdaterRemoved_Call) Return(_a0 *price_registry.PriceRegistryPriceUpdaterRemoved, _a1 error) *PriceRegistryInterface_ParsePriceUpdaterRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParsePriceUpdaterRemoved_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryPriceUpdaterRemoved, error)) *PriceRegistryInterface_ParsePriceUpdaterRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePriceUpdaterSet provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParsePriceUpdaterSet(log types.Log) (*price_registry.PriceRegistryPriceUpdaterSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePriceUpdaterSet")
+ }
+
+ var r0 *price_registry.PriceRegistryPriceUpdaterSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryPriceUpdaterSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryPriceUpdaterSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryPriceUpdaterSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParsePriceUpdaterSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePriceUpdaterSet'
+type PriceRegistryInterface_ParsePriceUpdaterSet_Call struct {
+ *mock.Call
+}
+
+// ParsePriceUpdaterSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParsePriceUpdaterSet(log interface{}) *PriceRegistryInterface_ParsePriceUpdaterSet_Call {
+ return &PriceRegistryInterface_ParsePriceUpdaterSet_Call{Call: _e.mock.On("ParsePriceUpdaterSet", log)}
+}
+
+func (_c *PriceRegistryInterface_ParsePriceUpdaterSet_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParsePriceUpdaterSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParsePriceUpdaterSet_Call) Return(_a0 *price_registry.PriceRegistryPriceUpdaterSet, _a1 error) *PriceRegistryInterface_ParsePriceUpdaterSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParsePriceUpdaterSet_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryPriceUpdaterSet, error)) *PriceRegistryInterface_ParsePriceUpdaterSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTokenTransferFeeConfigDeleted provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseTokenTransferFeeConfigDeleted(log types.Log) (*price_registry.PriceRegistryTokenTransferFeeConfigDeleted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTokenTransferFeeConfigDeleted")
+ }
+
+ var r0 *price_registry.PriceRegistryTokenTransferFeeConfigDeleted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryTokenTransferFeeConfigDeleted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryTokenTransferFeeConfigDeleted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryTokenTransferFeeConfigDeleted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTokenTransferFeeConfigDeleted'
+type PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call struct {
+ *mock.Call
+}
+
+// ParseTokenTransferFeeConfigDeleted is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseTokenTransferFeeConfigDeleted(log interface{}) *PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call {
+ return &PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call{Call: _e.mock.On("ParseTokenTransferFeeConfigDeleted", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call) Return(_a0 *price_registry.PriceRegistryTokenTransferFeeConfigDeleted, _a1 error) *PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryTokenTransferFeeConfigDeleted, error)) *PriceRegistryInterface_ParseTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTokenTransferFeeConfigUpdated provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseTokenTransferFeeConfigUpdated(log types.Log) (*price_registry.PriceRegistryTokenTransferFeeConfigUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTokenTransferFeeConfigUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryTokenTransferFeeConfigUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryTokenTransferFeeConfigUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryTokenTransferFeeConfigUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryTokenTransferFeeConfigUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTokenTransferFeeConfigUpdated'
+type PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call struct {
+ *mock.Call
+}
+
+// ParseTokenTransferFeeConfigUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseTokenTransferFeeConfigUpdated(log interface{}) *PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call {
+ return &PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call{Call: _e.mock.On("ParseTokenTransferFeeConfigUpdated", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call) Return(_a0 *price_registry.PriceRegistryTokenTransferFeeConfigUpdated, _a1 error) *PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryTokenTransferFeeConfigUpdated, error)) *PriceRegistryInterface_ParseTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseUsdPerTokenUpdated provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseUsdPerTokenUpdated(log types.Log) (*price_registry.PriceRegistryUsdPerTokenUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseUsdPerTokenUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryUsdPerTokenUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryUsdPerTokenUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryUsdPerTokenUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryUsdPerTokenUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseUsdPerTokenUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseUsdPerTokenUpdated'
+type PriceRegistryInterface_ParseUsdPerTokenUpdated_Call struct {
+ *mock.Call
+}
+
+// ParseUsdPerTokenUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseUsdPerTokenUpdated(log interface{}) *PriceRegistryInterface_ParseUsdPerTokenUpdated_Call {
+ return &PriceRegistryInterface_ParseUsdPerTokenUpdated_Call{Call: _e.mock.On("ParseUsdPerTokenUpdated", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseUsdPerTokenUpdated_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseUsdPerTokenUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseUsdPerTokenUpdated_Call) Return(_a0 *price_registry.PriceRegistryUsdPerTokenUpdated, _a1 error) *PriceRegistryInterface_ParseUsdPerTokenUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseUsdPerTokenUpdated_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryUsdPerTokenUpdated, error)) *PriceRegistryInterface_ParseUsdPerTokenUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseUsdPerUnitGasUpdated provides a mock function with given fields: log
+func (_m *PriceRegistryInterface) ParseUsdPerUnitGasUpdated(log types.Log) (*price_registry.PriceRegistryUsdPerUnitGasUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseUsdPerUnitGasUpdated")
+ }
+
+ var r0 *price_registry.PriceRegistryUsdPerUnitGasUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*price_registry.PriceRegistryUsdPerUnitGasUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *price_registry.PriceRegistryUsdPerUnitGasUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*price_registry.PriceRegistryUsdPerUnitGasUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseUsdPerUnitGasUpdated'
+type PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call struct {
+ *mock.Call
+}
+
+// ParseUsdPerUnitGasUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *PriceRegistryInterface_Expecter) ParseUsdPerUnitGasUpdated(log interface{}) *PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call {
+ return &PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call{Call: _e.mock.On("ParseUsdPerUnitGasUpdated", log)}
+}
+
+func (_c *PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call) Run(run func(log types.Log)) *PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call) Return(_a0 *price_registry.PriceRegistryUsdPerUnitGasUpdated, _a1 error) *PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call) RunAndReturn(run func(types.Log) (*price_registry.PriceRegistryUsdPerUnitGasUpdated, error)) *PriceRegistryInterface_ParseUsdPerUnitGasUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ProcessMessageArgs provides a mock function with given fields: opts, destChainSelector, feeToken, feeTokenAmount, extraArgs
+func (_m *PriceRegistryInterface) ProcessMessageArgs(opts *bind.CallOpts, destChainSelector uint64, feeToken common.Address, feeTokenAmount *big.Int, extraArgs []byte) (price_registry.ProcessMessageArgs, error) {
+ ret := _m.Called(opts, destChainSelector, feeToken, feeTokenAmount, extraArgs)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ProcessMessageArgs")
+ }
+
+ var r0 price_registry.ProcessMessageArgs
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address, *big.Int, []byte) (price_registry.ProcessMessageArgs, error)); ok {
+ return rf(opts, destChainSelector, feeToken, feeTokenAmount, extraArgs)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address, *big.Int, []byte) price_registry.ProcessMessageArgs); ok {
+ r0 = rf(opts, destChainSelector, feeToken, feeTokenAmount, extraArgs)
+ } else {
+ r0 = ret.Get(0).(price_registry.ProcessMessageArgs)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, destChainSelector, feeToken, feeTokenAmount, extraArgs)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_ProcessMessageArgs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProcessMessageArgs'
+type PriceRegistryInterface_ProcessMessageArgs_Call struct {
+ *mock.Call
+}
+
+// ProcessMessageArgs is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destChainSelector uint64
+// - feeToken common.Address
+// - feeTokenAmount *big.Int
+// - extraArgs []byte
+func (_e *PriceRegistryInterface_Expecter) ProcessMessageArgs(opts interface{}, destChainSelector interface{}, feeToken interface{}, feeTokenAmount interface{}, extraArgs interface{}) *PriceRegistryInterface_ProcessMessageArgs_Call {
+ return &PriceRegistryInterface_ProcessMessageArgs_Call{Call: _e.mock.On("ProcessMessageArgs", opts, destChainSelector, feeToken, feeTokenAmount, extraArgs)}
+}
+
+func (_c *PriceRegistryInterface_ProcessMessageArgs_Call) Run(run func(opts *bind.CallOpts, destChainSelector uint64, feeToken common.Address, feeTokenAmount *big.Int, extraArgs []byte)) *PriceRegistryInterface_ProcessMessageArgs_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64), args[2].(common.Address), args[3].(*big.Int), args[4].([]byte))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ProcessMessageArgs_Call) Return(_a0 price_registry.ProcessMessageArgs, _a1 error) *PriceRegistryInterface_ProcessMessageArgs_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ProcessMessageArgs_Call) RunAndReturn(run func(*bind.CallOpts, uint64, common.Address, *big.Int, []byte) (price_registry.ProcessMessageArgs, error)) *PriceRegistryInterface_ProcessMessageArgs_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TransferOwnership provides a mock function with given fields: opts, to
+func (_m *PriceRegistryInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TransferOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_TransferOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferOwnership'
+type PriceRegistryInterface_TransferOwnership_Call struct {
+ *mock.Call
+}
+
+// TransferOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - to common.Address
+func (_e *PriceRegistryInterface_Expecter) TransferOwnership(opts interface{}, to interface{}) *PriceRegistryInterface_TransferOwnership_Call {
+ return &PriceRegistryInterface_TransferOwnership_Call{Call: _e.mock.On("TransferOwnership", opts, to)}
+}
+
+func (_c *PriceRegistryInterface_TransferOwnership_Call) Run(run func(opts *bind.TransactOpts, to common.Address)) *PriceRegistryInterface_TransferOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_TransferOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_TransferOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_TransferOwnership_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *PriceRegistryInterface_TransferOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TypeAndVersion provides a mock function with given fields: opts
+func (_m *PriceRegistryInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TypeAndVersion")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_TypeAndVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TypeAndVersion'
+type PriceRegistryInterface_TypeAndVersion_Call struct {
+ *mock.Call
+}
+
+// TypeAndVersion is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *PriceRegistryInterface_Expecter) TypeAndVersion(opts interface{}) *PriceRegistryInterface_TypeAndVersion_Call {
+ return &PriceRegistryInterface_TypeAndVersion_Call{Call: _e.mock.On("TypeAndVersion", opts)}
+}
+
+func (_c *PriceRegistryInterface_TypeAndVersion_Call) Run(run func(opts *bind.CallOpts)) *PriceRegistryInterface_TypeAndVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_TypeAndVersion_Call) Return(_a0 string, _a1 error) *PriceRegistryInterface_TypeAndVersion_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_TypeAndVersion_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *PriceRegistryInterface_TypeAndVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// UpdatePrices provides a mock function with given fields: opts, priceUpdates
+func (_m *PriceRegistryInterface) UpdatePrices(opts *bind.TransactOpts, priceUpdates price_registry.InternalPriceUpdates) (*types.Transaction, error) {
+ ret := _m.Called(opts, priceUpdates)
+
+ if len(ret) == 0 {
+ panic("no return value specified for UpdatePrices")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, price_registry.InternalPriceUpdates) (*types.Transaction, error)); ok {
+ return rf(opts, priceUpdates)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, price_registry.InternalPriceUpdates) *types.Transaction); ok {
+ r0 = rf(opts, priceUpdates)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, price_registry.InternalPriceUpdates) error); ok {
+ r1 = rf(opts, priceUpdates)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_UpdatePrices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdatePrices'
+type PriceRegistryInterface_UpdatePrices_Call struct {
+ *mock.Call
+}
+
+// UpdatePrices is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - priceUpdates price_registry.InternalPriceUpdates
+func (_e *PriceRegistryInterface_Expecter) UpdatePrices(opts interface{}, priceUpdates interface{}) *PriceRegistryInterface_UpdatePrices_Call {
+ return &PriceRegistryInterface_UpdatePrices_Call{Call: _e.mock.On("UpdatePrices", opts, priceUpdates)}
+}
+
+func (_c *PriceRegistryInterface_UpdatePrices_Call) Run(run func(opts *bind.TransactOpts, priceUpdates price_registry.InternalPriceUpdates)) *PriceRegistryInterface_UpdatePrices_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(price_registry.InternalPriceUpdates))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_UpdatePrices_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_UpdatePrices_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_UpdatePrices_Call) RunAndReturn(run func(*bind.TransactOpts, price_registry.InternalPriceUpdates) (*types.Transaction, error)) *PriceRegistryInterface_UpdatePrices_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// UpdateTokenPriceFeeds provides a mock function with given fields: opts, tokenPriceFeedUpdates
+func (_m *PriceRegistryInterface) UpdateTokenPriceFeeds(opts *bind.TransactOpts, tokenPriceFeedUpdates []price_registry.PriceRegistryTokenPriceFeedUpdate) (*types.Transaction, error) {
+ ret := _m.Called(opts, tokenPriceFeedUpdates)
+
+ if len(ret) == 0 {
+ panic("no return value specified for UpdateTokenPriceFeeds")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []price_registry.PriceRegistryTokenPriceFeedUpdate) (*types.Transaction, error)); ok {
+ return rf(opts, tokenPriceFeedUpdates)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []price_registry.PriceRegistryTokenPriceFeedUpdate) *types.Transaction); ok {
+ r0 = rf(opts, tokenPriceFeedUpdates)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []price_registry.PriceRegistryTokenPriceFeedUpdate) error); ok {
+ r1 = rf(opts, tokenPriceFeedUpdates)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_UpdateTokenPriceFeeds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateTokenPriceFeeds'
+type PriceRegistryInterface_UpdateTokenPriceFeeds_Call struct {
+ *mock.Call
+}
+
+// UpdateTokenPriceFeeds is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - tokenPriceFeedUpdates []price_registry.PriceRegistryTokenPriceFeedUpdate
+func (_e *PriceRegistryInterface_Expecter) UpdateTokenPriceFeeds(opts interface{}, tokenPriceFeedUpdates interface{}) *PriceRegistryInterface_UpdateTokenPriceFeeds_Call {
+ return &PriceRegistryInterface_UpdateTokenPriceFeeds_Call{Call: _e.mock.On("UpdateTokenPriceFeeds", opts, tokenPriceFeedUpdates)}
+}
+
+func (_c *PriceRegistryInterface_UpdateTokenPriceFeeds_Call) Run(run func(opts *bind.TransactOpts, tokenPriceFeedUpdates []price_registry.PriceRegistryTokenPriceFeedUpdate)) *PriceRegistryInterface_UpdateTokenPriceFeeds_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]price_registry.PriceRegistryTokenPriceFeedUpdate))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_UpdateTokenPriceFeeds_Call) Return(_a0 *types.Transaction, _a1 error) *PriceRegistryInterface_UpdateTokenPriceFeeds_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_UpdateTokenPriceFeeds_Call) RunAndReturn(run func(*bind.TransactOpts, []price_registry.PriceRegistryTokenPriceFeedUpdate) (*types.Transaction, error)) *PriceRegistryInterface_UpdateTokenPriceFeeds_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ValidatePoolReturnData provides a mock function with given fields: opts, destChainSelector, rampTokenAmounts, sourceTokenAmounts
+func (_m *PriceRegistryInterface) ValidatePoolReturnData(opts *bind.CallOpts, destChainSelector uint64, rampTokenAmounts []price_registry.InternalRampTokenAmount, sourceTokenAmounts []price_registry.ClientEVMTokenAmount) error {
+ ret := _m.Called(opts, destChainSelector, rampTokenAmounts, sourceTokenAmounts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ValidatePoolReturnData")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, []price_registry.InternalRampTokenAmount, []price_registry.ClientEVMTokenAmount) error); ok {
+ r0 = rf(opts, destChainSelector, rampTokenAmounts, sourceTokenAmounts)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// PriceRegistryInterface_ValidatePoolReturnData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ValidatePoolReturnData'
+type PriceRegistryInterface_ValidatePoolReturnData_Call struct {
+ *mock.Call
+}
+
+// ValidatePoolReturnData is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destChainSelector uint64
+// - rampTokenAmounts []price_registry.InternalRampTokenAmount
+// - sourceTokenAmounts []price_registry.ClientEVMTokenAmount
+func (_e *PriceRegistryInterface_Expecter) ValidatePoolReturnData(opts interface{}, destChainSelector interface{}, rampTokenAmounts interface{}, sourceTokenAmounts interface{}) *PriceRegistryInterface_ValidatePoolReturnData_Call {
+ return &PriceRegistryInterface_ValidatePoolReturnData_Call{Call: _e.mock.On("ValidatePoolReturnData", opts, destChainSelector, rampTokenAmounts, sourceTokenAmounts)}
+}
+
+func (_c *PriceRegistryInterface_ValidatePoolReturnData_Call) Run(run func(opts *bind.CallOpts, destChainSelector uint64, rampTokenAmounts []price_registry.InternalRampTokenAmount, sourceTokenAmounts []price_registry.ClientEVMTokenAmount)) *PriceRegistryInterface_ValidatePoolReturnData_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64), args[2].([]price_registry.InternalRampTokenAmount), args[3].([]price_registry.ClientEVMTokenAmount))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ValidatePoolReturnData_Call) Return(_a0 error) *PriceRegistryInterface_ValidatePoolReturnData_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_ValidatePoolReturnData_Call) RunAndReturn(run func(*bind.CallOpts, uint64, []price_registry.InternalRampTokenAmount, []price_registry.ClientEVMTokenAmount) error) *PriceRegistryInterface_ValidatePoolReturnData_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchAuthorizedCallerAdded provides a mock function with given fields: opts, sink
+func (_m *PriceRegistryInterface) WatchAuthorizedCallerAdded(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryAuthorizedCallerAdded) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchAuthorizedCallerAdded")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryAuthorizedCallerAdded) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryAuthorizedCallerAdded) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryAuthorizedCallerAdded) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchAuthorizedCallerAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAuthorizedCallerAdded'
+type PriceRegistryInterface_WatchAuthorizedCallerAdded_Call struct {
+ *mock.Call
+}
+
+// WatchAuthorizedCallerAdded is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryAuthorizedCallerAdded
+func (_e *PriceRegistryInterface_Expecter) WatchAuthorizedCallerAdded(opts interface{}, sink interface{}) *PriceRegistryInterface_WatchAuthorizedCallerAdded_Call {
+ return &PriceRegistryInterface_WatchAuthorizedCallerAdded_Call{Call: _e.mock.On("WatchAuthorizedCallerAdded", opts, sink)}
+}
+
+func (_c *PriceRegistryInterface_WatchAuthorizedCallerAdded_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryAuthorizedCallerAdded)) *PriceRegistryInterface_WatchAuthorizedCallerAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryAuthorizedCallerAdded))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchAuthorizedCallerAdded_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchAuthorizedCallerAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchAuthorizedCallerAdded_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryAuthorizedCallerAdded) (event.Subscription, error)) *PriceRegistryInterface_WatchAuthorizedCallerAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchAuthorizedCallerRemoved provides a mock function with given fields: opts, sink
+func (_m *PriceRegistryInterface) WatchAuthorizedCallerRemoved(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryAuthorizedCallerRemoved) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchAuthorizedCallerRemoved")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryAuthorizedCallerRemoved) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryAuthorizedCallerRemoved) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryAuthorizedCallerRemoved) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAuthorizedCallerRemoved'
+type PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call struct {
+ *mock.Call
+}
+
+// WatchAuthorizedCallerRemoved is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryAuthorizedCallerRemoved
+func (_e *PriceRegistryInterface_Expecter) WatchAuthorizedCallerRemoved(opts interface{}, sink interface{}) *PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call {
+ return &PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call{Call: _e.mock.On("WatchAuthorizedCallerRemoved", opts, sink)}
+}
+
+func (_c *PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryAuthorizedCallerRemoved)) *PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryAuthorizedCallerRemoved))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryAuthorizedCallerRemoved) (event.Subscription, error)) *PriceRegistryInterface_WatchAuthorizedCallerRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchDestChainAdded provides a mock function with given fields: opts, sink, destChainSelector
+func (_m *PriceRegistryInterface) WatchDestChainAdded(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryDestChainAdded, destChainSelector []uint64) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, destChainSelector)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchDestChainAdded")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryDestChainAdded, []uint64) (event.Subscription, error)); ok {
+ return rf(opts, sink, destChainSelector)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryDestChainAdded, []uint64) event.Subscription); ok {
+ r0 = rf(opts, sink, destChainSelector)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryDestChainAdded, []uint64) error); ok {
+ r1 = rf(opts, sink, destChainSelector)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchDestChainAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchDestChainAdded'
+type PriceRegistryInterface_WatchDestChainAdded_Call struct {
+ *mock.Call
+}
+
+// WatchDestChainAdded is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryDestChainAdded
+// - destChainSelector []uint64
+func (_e *PriceRegistryInterface_Expecter) WatchDestChainAdded(opts interface{}, sink interface{}, destChainSelector interface{}) *PriceRegistryInterface_WatchDestChainAdded_Call {
+ return &PriceRegistryInterface_WatchDestChainAdded_Call{Call: _e.mock.On("WatchDestChainAdded", opts, sink, destChainSelector)}
+}
+
+func (_c *PriceRegistryInterface_WatchDestChainAdded_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryDestChainAdded, destChainSelector []uint64)) *PriceRegistryInterface_WatchDestChainAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryDestChainAdded), args[2].([]uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchDestChainAdded_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchDestChainAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchDestChainAdded_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryDestChainAdded, []uint64) (event.Subscription, error)) *PriceRegistryInterface_WatchDestChainAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchDestChainConfigUpdated provides a mock function with given fields: opts, sink, destChainSelector
+func (_m *PriceRegistryInterface) WatchDestChainConfigUpdated(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryDestChainConfigUpdated, destChainSelector []uint64) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, destChainSelector)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchDestChainConfigUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryDestChainConfigUpdated, []uint64) (event.Subscription, error)); ok {
+ return rf(opts, sink, destChainSelector)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryDestChainConfigUpdated, []uint64) event.Subscription); ok {
+ r0 = rf(opts, sink, destChainSelector)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryDestChainConfigUpdated, []uint64) error); ok {
+ r1 = rf(opts, sink, destChainSelector)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchDestChainConfigUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchDestChainConfigUpdated'
+type PriceRegistryInterface_WatchDestChainConfigUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchDestChainConfigUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryDestChainConfigUpdated
+// - destChainSelector []uint64
+func (_e *PriceRegistryInterface_Expecter) WatchDestChainConfigUpdated(opts interface{}, sink interface{}, destChainSelector interface{}) *PriceRegistryInterface_WatchDestChainConfigUpdated_Call {
+ return &PriceRegistryInterface_WatchDestChainConfigUpdated_Call{Call: _e.mock.On("WatchDestChainConfigUpdated", opts, sink, destChainSelector)}
+}
+
+func (_c *PriceRegistryInterface_WatchDestChainConfigUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryDestChainConfigUpdated, destChainSelector []uint64)) *PriceRegistryInterface_WatchDestChainConfigUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryDestChainConfigUpdated), args[2].([]uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchDestChainConfigUpdated_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchDestChainConfigUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchDestChainConfigUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryDestChainConfigUpdated, []uint64) (event.Subscription, error)) *PriceRegistryInterface_WatchDestChainConfigUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchFeeTokenAdded provides a mock function with given fields: opts, sink, feeToken
+func (_m *PriceRegistryInterface) WatchFeeTokenAdded(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryFeeTokenAdded, feeToken []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, feeToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchFeeTokenAdded")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenAdded, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, feeToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenAdded, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, feeToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenAdded, []common.Address) error); ok {
+ r1 = rf(opts, sink, feeToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchFeeTokenAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchFeeTokenAdded'
+type PriceRegistryInterface_WatchFeeTokenAdded_Call struct {
+ *mock.Call
+}
+
+// WatchFeeTokenAdded is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryFeeTokenAdded
+// - feeToken []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchFeeTokenAdded(opts interface{}, sink interface{}, feeToken interface{}) *PriceRegistryInterface_WatchFeeTokenAdded_Call {
+ return &PriceRegistryInterface_WatchFeeTokenAdded_Call{Call: _e.mock.On("WatchFeeTokenAdded", opts, sink, feeToken)}
+}
+
+func (_c *PriceRegistryInterface_WatchFeeTokenAdded_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryFeeTokenAdded, feeToken []common.Address)) *PriceRegistryInterface_WatchFeeTokenAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryFeeTokenAdded), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchFeeTokenAdded_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchFeeTokenAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchFeeTokenAdded_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenAdded, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchFeeTokenAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchFeeTokenRemoved provides a mock function with given fields: opts, sink, feeToken
+func (_m *PriceRegistryInterface) WatchFeeTokenRemoved(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryFeeTokenRemoved, feeToken []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, feeToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchFeeTokenRemoved")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenRemoved, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, feeToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenRemoved, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, feeToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenRemoved, []common.Address) error); ok {
+ r1 = rf(opts, sink, feeToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchFeeTokenRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchFeeTokenRemoved'
+type PriceRegistryInterface_WatchFeeTokenRemoved_Call struct {
+ *mock.Call
+}
+
+// WatchFeeTokenRemoved is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryFeeTokenRemoved
+// - feeToken []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchFeeTokenRemoved(opts interface{}, sink interface{}, feeToken interface{}) *PriceRegistryInterface_WatchFeeTokenRemoved_Call {
+ return &PriceRegistryInterface_WatchFeeTokenRemoved_Call{Call: _e.mock.On("WatchFeeTokenRemoved", opts, sink, feeToken)}
+}
+
+func (_c *PriceRegistryInterface_WatchFeeTokenRemoved_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryFeeTokenRemoved, feeToken []common.Address)) *PriceRegistryInterface_WatchFeeTokenRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryFeeTokenRemoved), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchFeeTokenRemoved_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchFeeTokenRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchFeeTokenRemoved_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryFeeTokenRemoved, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchFeeTokenRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to
+func (_m *PriceRegistryInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferRequested")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferRequested, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferRequested'
+type PriceRegistryInterface_WatchOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryOwnershipTransferRequested
+// - from []common.Address
+// - to []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchOwnershipTransferRequested(opts interface{}, sink interface{}, from interface{}, to interface{}) *PriceRegistryInterface_WatchOwnershipTransferRequested_Call {
+ return &PriceRegistryInterface_WatchOwnershipTransferRequested_Call{Call: _e.mock.On("WatchOwnershipTransferRequested", opts, sink, from, to)}
+}
+
+func (_c *PriceRegistryInterface_WatchOwnershipTransferRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryOwnershipTransferRequested, from []common.Address, to []common.Address)) *PriceRegistryInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryOwnershipTransferRequested), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchOwnershipTransferRequested_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to
+func (_m *PriceRegistryInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferred")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferred, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferred'
+type PriceRegistryInterface_WatchOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryOwnershipTransferred
+// - from []common.Address
+// - to []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchOwnershipTransferred(opts interface{}, sink interface{}, from interface{}, to interface{}) *PriceRegistryInterface_WatchOwnershipTransferred_Call {
+ return &PriceRegistryInterface_WatchOwnershipTransferred_Call{Call: _e.mock.On("WatchOwnershipTransferred", opts, sink, from, to)}
+}
+
+func (_c *PriceRegistryInterface_WatchOwnershipTransferred_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryOwnershipTransferred, from []common.Address, to []common.Address)) *PriceRegistryInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryOwnershipTransferred), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchOwnershipTransferred_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchOwnershipTransferred_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPremiumMultiplierWeiPerEthUpdated provides a mock function with given fields: opts, sink, token
+func (_m *PriceRegistryInterface) WatchPremiumMultiplierWeiPerEthUpdated(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, token []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPremiumMultiplierWeiPerEthUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, []common.Address) error); ok {
+ r1 = rf(opts, sink, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPremiumMultiplierWeiPerEthUpdated'
+type PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchPremiumMultiplierWeiPerEthUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchPremiumMultiplierWeiPerEthUpdated(opts interface{}, sink interface{}, token interface{}) *PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call {
+ return &PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call{Call: _e.mock.On("WatchPremiumMultiplierWeiPerEthUpdated", opts, sink, token)}
+}
+
+func (_c *PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, token []common.Address)) *PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPremiumMultiplierWeiPerEthUpdated, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchPremiumMultiplierWeiPerEthUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPriceFeedPerTokenUpdated provides a mock function with given fields: opts, sink, token
+func (_m *PriceRegistryInterface) WatchPriceFeedPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPriceFeedPerTokenUpdated, token []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPriceFeedPerTokenUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceFeedPerTokenUpdated, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceFeedPerTokenUpdated, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceFeedPerTokenUpdated, []common.Address) error); ok {
+ r1 = rf(opts, sink, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPriceFeedPerTokenUpdated'
+type PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchPriceFeedPerTokenUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryPriceFeedPerTokenUpdated
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchPriceFeedPerTokenUpdated(opts interface{}, sink interface{}, token interface{}) *PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call {
+ return &PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call{Call: _e.mock.On("WatchPriceFeedPerTokenUpdated", opts, sink, token)}
+}
+
+func (_c *PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPriceFeedPerTokenUpdated, token []common.Address)) *PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryPriceFeedPerTokenUpdated), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceFeedPerTokenUpdated, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchPriceFeedPerTokenUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPriceUpdaterRemoved provides a mock function with given fields: opts, sink, priceUpdater
+func (_m *PriceRegistryInterface) WatchPriceUpdaterRemoved(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, priceUpdater)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPriceUpdaterRemoved")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterRemoved, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, priceUpdater)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterRemoved, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, priceUpdater)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterRemoved, []common.Address) error); ok {
+ r1 = rf(opts, sink, priceUpdater)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchPriceUpdaterRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPriceUpdaterRemoved'
+type PriceRegistryInterface_WatchPriceUpdaterRemoved_Call struct {
+ *mock.Call
+}
+
+// WatchPriceUpdaterRemoved is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryPriceUpdaterRemoved
+// - priceUpdater []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchPriceUpdaterRemoved(opts interface{}, sink interface{}, priceUpdater interface{}) *PriceRegistryInterface_WatchPriceUpdaterRemoved_Call {
+ return &PriceRegistryInterface_WatchPriceUpdaterRemoved_Call{Call: _e.mock.On("WatchPriceUpdaterRemoved", opts, sink, priceUpdater)}
+}
+
+func (_c *PriceRegistryInterface_WatchPriceUpdaterRemoved_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPriceUpdaterRemoved, priceUpdater []common.Address)) *PriceRegistryInterface_WatchPriceUpdaterRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryPriceUpdaterRemoved), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchPriceUpdaterRemoved_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchPriceUpdaterRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchPriceUpdaterRemoved_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterRemoved, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchPriceUpdaterRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPriceUpdaterSet provides a mock function with given fields: opts, sink, priceUpdater
+func (_m *PriceRegistryInterface) WatchPriceUpdaterSet(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPriceUpdaterSet, priceUpdater []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, priceUpdater)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPriceUpdaterSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterSet, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, priceUpdater)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterSet, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, priceUpdater)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterSet, []common.Address) error); ok {
+ r1 = rf(opts, sink, priceUpdater)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchPriceUpdaterSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPriceUpdaterSet'
+type PriceRegistryInterface_WatchPriceUpdaterSet_Call struct {
+ *mock.Call
+}
+
+// WatchPriceUpdaterSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryPriceUpdaterSet
+// - priceUpdater []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchPriceUpdaterSet(opts interface{}, sink interface{}, priceUpdater interface{}) *PriceRegistryInterface_WatchPriceUpdaterSet_Call {
+ return &PriceRegistryInterface_WatchPriceUpdaterSet_Call{Call: _e.mock.On("WatchPriceUpdaterSet", opts, sink, priceUpdater)}
+}
+
+func (_c *PriceRegistryInterface_WatchPriceUpdaterSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryPriceUpdaterSet, priceUpdater []common.Address)) *PriceRegistryInterface_WatchPriceUpdaterSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryPriceUpdaterSet), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchPriceUpdaterSet_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchPriceUpdaterSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchPriceUpdaterSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryPriceUpdaterSet, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchPriceUpdaterSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTokenTransferFeeConfigDeleted provides a mock function with given fields: opts, sink, destChainSelector, token
+func (_m *PriceRegistryInterface) WatchTokenTransferFeeConfigDeleted(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryTokenTransferFeeConfigDeleted, destChainSelector []uint64, token []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, destChainSelector, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTokenTransferFeeConfigDeleted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryTokenTransferFeeConfigDeleted, []uint64, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, destChainSelector, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryTokenTransferFeeConfigDeleted, []uint64, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, destChainSelector, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryTokenTransferFeeConfigDeleted, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, sink, destChainSelector, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTokenTransferFeeConfigDeleted'
+type PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call struct {
+ *mock.Call
+}
+
+// WatchTokenTransferFeeConfigDeleted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryTokenTransferFeeConfigDeleted
+// - destChainSelector []uint64
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchTokenTransferFeeConfigDeleted(opts interface{}, sink interface{}, destChainSelector interface{}, token interface{}) *PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call {
+ return &PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call{Call: _e.mock.On("WatchTokenTransferFeeConfigDeleted", opts, sink, destChainSelector, token)}
+}
+
+func (_c *PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryTokenTransferFeeConfigDeleted, destChainSelector []uint64, token []common.Address)) *PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryTokenTransferFeeConfigDeleted), args[2].([]uint64), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryTokenTransferFeeConfigDeleted, []uint64, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchTokenTransferFeeConfigDeleted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTokenTransferFeeConfigUpdated provides a mock function with given fields: opts, sink, destChainSelector, token
+func (_m *PriceRegistryInterface) WatchTokenTransferFeeConfigUpdated(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryTokenTransferFeeConfigUpdated, destChainSelector []uint64, token []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, destChainSelector, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTokenTransferFeeConfigUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryTokenTransferFeeConfigUpdated, []uint64, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, destChainSelector, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryTokenTransferFeeConfigUpdated, []uint64, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, destChainSelector, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryTokenTransferFeeConfigUpdated, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, sink, destChainSelector, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTokenTransferFeeConfigUpdated'
+type PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchTokenTransferFeeConfigUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryTokenTransferFeeConfigUpdated
+// - destChainSelector []uint64
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchTokenTransferFeeConfigUpdated(opts interface{}, sink interface{}, destChainSelector interface{}, token interface{}) *PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call {
+ return &PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call{Call: _e.mock.On("WatchTokenTransferFeeConfigUpdated", opts, sink, destChainSelector, token)}
+}
+
+func (_c *PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryTokenTransferFeeConfigUpdated, destChainSelector []uint64, token []common.Address)) *PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryTokenTransferFeeConfigUpdated), args[2].([]uint64), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryTokenTransferFeeConfigUpdated, []uint64, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchTokenTransferFeeConfigUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchUsdPerTokenUpdated provides a mock function with given fields: opts, sink, token
+func (_m *PriceRegistryInterface) WatchUsdPerTokenUpdated(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryUsdPerTokenUpdated, token []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchUsdPerTokenUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerTokenUpdated, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerTokenUpdated, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerTokenUpdated, []common.Address) error); ok {
+ r1 = rf(opts, sink, token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchUsdPerTokenUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchUsdPerTokenUpdated'
+type PriceRegistryInterface_WatchUsdPerTokenUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchUsdPerTokenUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryUsdPerTokenUpdated
+// - token []common.Address
+func (_e *PriceRegistryInterface_Expecter) WatchUsdPerTokenUpdated(opts interface{}, sink interface{}, token interface{}) *PriceRegistryInterface_WatchUsdPerTokenUpdated_Call {
+ return &PriceRegistryInterface_WatchUsdPerTokenUpdated_Call{Call: _e.mock.On("WatchUsdPerTokenUpdated", opts, sink, token)}
+}
+
+func (_c *PriceRegistryInterface_WatchUsdPerTokenUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryUsdPerTokenUpdated, token []common.Address)) *PriceRegistryInterface_WatchUsdPerTokenUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryUsdPerTokenUpdated), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchUsdPerTokenUpdated_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchUsdPerTokenUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchUsdPerTokenUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerTokenUpdated, []common.Address) (event.Subscription, error)) *PriceRegistryInterface_WatchUsdPerTokenUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchUsdPerUnitGasUpdated provides a mock function with given fields: opts, sink, destChain
+func (_m *PriceRegistryInterface) WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, destChain)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchUsdPerUnitGasUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated, []uint64) (event.Subscription, error)); ok {
+ return rf(opts, sink, destChain)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated, []uint64) event.Subscription); ok {
+ r0 = rf(opts, sink, destChain)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated, []uint64) error); ok {
+ r1 = rf(opts, sink, destChain)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchUsdPerUnitGasUpdated'
+type PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchUsdPerUnitGasUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated
+// - destChain []uint64
+func (_e *PriceRegistryInterface_Expecter) WatchUsdPerUnitGasUpdated(opts interface{}, sink interface{}, destChain interface{}) *PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call {
+ return &PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call{Call: _e.mock.On("WatchUsdPerUnitGasUpdated", opts, sink, destChain)}
+}
+
+func (_c *PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated, destChain []uint64)) *PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated), args[2].([]uint64))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call) Return(_a0 event.Subscription, _a1 error) *PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *price_registry.PriceRegistryUsdPerUnitGasUpdated, []uint64) (event.Subscription, error)) *PriceRegistryInterface_WatchUsdPerUnitGasUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewPriceRegistryInterface creates a new instance of PriceRegistryInterface. 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 NewPriceRegistryInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *PriceRegistryInterface {
+ mock := &PriceRegistryInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/ccip/mocks/v1_0_0/evm2_evm_off_ramp_interface.go b/core/gethwrappers/ccip/mocks/v1_0_0/evm2_evm_off_ramp_interface.go
new file mode 100644
index 00000000000..cefb2c26841
--- /dev/null
+++ b/core/gethwrappers/ccip/mocks/v1_0_0/evm2_evm_off_ramp_interface.go
@@ -0,0 +1,3603 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_contracts
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ evm_2_evm_offramp_1_0_0 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// EVM2EVMOffRampInterface is an autogenerated mock type for the EVM2EVMOffRampInterface type
+type EVM2EVMOffRampInterface struct {
+ mock.Mock
+}
+
+type EVM2EVMOffRampInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *EVM2EVMOffRampInterface) EXPECT() *EVM2EVMOffRampInterface_Expecter {
+ return &EVM2EVMOffRampInterface_Expecter{mock: &_m.Mock}
+}
+
+// AcceptOwnership provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AcceptOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_AcceptOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptOwnership'
+type EVM2EVMOffRampInterface_AcceptOwnership_Call struct {
+ *mock.Call
+}
+
+// AcceptOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) AcceptOwnership(opts interface{}) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ return &EVM2EVMOffRampInterface_AcceptOwnership_Call{Call: _e.mock.On("AcceptOwnership", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) Run(run func(opts *bind.TransactOpts)) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Address provides a mock function with given fields:
+func (_m *EVM2EVMOffRampInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// EVM2EVMOffRampInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type EVM2EVMOffRampInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *EVM2EVMOffRampInterface_Expecter) Address() *EVM2EVMOffRampInterface_Address_Call {
+ return &EVM2EVMOffRampInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) Run(run func()) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) Return(_a0 common.Address) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) RunAndReturn(run func() common.Address) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ApplyPoolUpdates provides a mock function with given fields: opts, removes, adds
+func (_m *EVM2EVMOffRampInterface) ApplyPoolUpdates(opts *bind.TransactOpts, removes []evm_2_evm_offramp_1_0_0.InternalPoolUpdate, adds []evm_2_evm_offramp_1_0_0.InternalPoolUpdate) (*types.Transaction, error) {
+ ret := _m.Called(opts, removes, adds)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ApplyPoolUpdates")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_offramp_1_0_0.InternalPoolUpdate, []evm_2_evm_offramp_1_0_0.InternalPoolUpdate) (*types.Transaction, error)); ok {
+ return rf(opts, removes, adds)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_offramp_1_0_0.InternalPoolUpdate, []evm_2_evm_offramp_1_0_0.InternalPoolUpdate) *types.Transaction); ok {
+ r0 = rf(opts, removes, adds)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []evm_2_evm_offramp_1_0_0.InternalPoolUpdate, []evm_2_evm_offramp_1_0_0.InternalPoolUpdate) error); ok {
+ r1 = rf(opts, removes, adds)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ApplyPoolUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyPoolUpdates'
+type EVM2EVMOffRampInterface_ApplyPoolUpdates_Call struct {
+ *mock.Call
+}
+
+// ApplyPoolUpdates is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - removes []evm_2_evm_offramp_1_0_0.InternalPoolUpdate
+// - adds []evm_2_evm_offramp_1_0_0.InternalPoolUpdate
+func (_e *EVM2EVMOffRampInterface_Expecter) ApplyPoolUpdates(opts interface{}, removes interface{}, adds interface{}) *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call {
+ return &EVM2EVMOffRampInterface_ApplyPoolUpdates_Call{Call: _e.mock.On("ApplyPoolUpdates", opts, removes, adds)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call) Run(run func(opts *bind.TransactOpts, removes []evm_2_evm_offramp_1_0_0.InternalPoolUpdate, adds []evm_2_evm_offramp_1_0_0.InternalPoolUpdate)) *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]evm_2_evm_offramp_1_0_0.InternalPoolUpdate), args[2].([]evm_2_evm_offramp_1_0_0.InternalPoolUpdate))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call) RunAndReturn(run func(*bind.TransactOpts, []evm_2_evm_offramp_1_0_0.InternalPoolUpdate, []evm_2_evm_offramp_1_0_0.InternalPoolUpdate) (*types.Transaction, error)) *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CcipReceive provides a mock function with given fields: opts, arg0
+func (_m *EVM2EVMOffRampInterface) CcipReceive(opts *bind.CallOpts, arg0 evm_2_evm_offramp_1_0_0.ClientAny2EVMMessage) error {
+ ret := _m.Called(opts, arg0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CcipReceive")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, evm_2_evm_offramp_1_0_0.ClientAny2EVMMessage) error); ok {
+ r0 = rf(opts, arg0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// EVM2EVMOffRampInterface_CcipReceive_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CcipReceive'
+type EVM2EVMOffRampInterface_CcipReceive_Call struct {
+ *mock.Call
+}
+
+// CcipReceive is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - arg0 evm_2_evm_offramp_1_0_0.ClientAny2EVMMessage
+func (_e *EVM2EVMOffRampInterface_Expecter) CcipReceive(opts interface{}, arg0 interface{}) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ return &EVM2EVMOffRampInterface_CcipReceive_Call{Call: _e.mock.On("CcipReceive", opts, arg0)}
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) Run(run func(opts *bind.CallOpts, arg0 evm_2_evm_offramp_1_0_0.ClientAny2EVMMessage)) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(evm_2_evm_offramp_1_0_0.ClientAny2EVMMessage))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) Return(_a0 error) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) RunAndReturn(run func(*bind.CallOpts, evm_2_evm_offramp_1_0_0.ClientAny2EVMMessage) error) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CurrentRateLimiterState provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) CurrentRateLimiterState(opts *bind.CallOpts) (evm_2_evm_offramp_1_0_0.RateLimiterTokenBucket, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CurrentRateLimiterState")
+ }
+
+ var r0 evm_2_evm_offramp_1_0_0.RateLimiterTokenBucket
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.RateLimiterTokenBucket, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_0_0.RateLimiterTokenBucket); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_0_0.RateLimiterTokenBucket)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_CurrentRateLimiterState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CurrentRateLimiterState'
+type EVM2EVMOffRampInterface_CurrentRateLimiterState_Call struct {
+ *mock.Call
+}
+
+// CurrentRateLimiterState is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) CurrentRateLimiterState(opts interface{}) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ return &EVM2EVMOffRampInterface_CurrentRateLimiterState_Call{Call: _e.mock.On("CurrentRateLimiterState", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) Return(_a0 evm_2_evm_offramp_1_0_0.RateLimiterTokenBucket, _a1 error) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.RateLimiterTokenBucket, error)) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ExecuteSingleMessage provides a mock function with given fields: opts, message, offchainTokenData
+func (_m *EVM2EVMOffRampInterface) ExecuteSingleMessage(opts *bind.TransactOpts, message evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, message, offchainTokenData)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExecuteSingleMessage")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage, [][]byte) (*types.Transaction, error)); ok {
+ return rf(opts, message, offchainTokenData)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage, [][]byte) *types.Transaction); ok {
+ r0 = rf(opts, message, offchainTokenData)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage, [][]byte) error); ok {
+ r1 = rf(opts, message, offchainTokenData)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ExecuteSingleMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExecuteSingleMessage'
+type EVM2EVMOffRampInterface_ExecuteSingleMessage_Call struct {
+ *mock.Call
+}
+
+// ExecuteSingleMessage is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - message evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage
+// - offchainTokenData [][]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) ExecuteSingleMessage(opts interface{}, message interface{}, offchainTokenData interface{}) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ return &EVM2EVMOffRampInterface_ExecuteSingleMessage_Call{Call: _e.mock.On("ExecuteSingleMessage", opts, message, offchainTokenData)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) Run(run func(opts *bind.TransactOpts, message evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage, offchainTokenData [][]byte)) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage), args[2].([][]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage, [][]byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterAdminSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterAdminSet(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterAdminSet")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterAdminSet'
+type EVM2EVMOffRampInterface_FilterAdminSet_Call struct {
+ *mock.Call
+}
+
+// FilterAdminSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterAdminSet(opts interface{}) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ return &EVM2EVMOffRampInterface_FilterAdminSet_Call{Call: _e.mock.On("FilterAdminSet", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSetIterator, _a1 error) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSetIterator, error)) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterConfigSet(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet'
+type EVM2EVMOffRampInterface_FilterConfigSet_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterConfigSet(opts interface{}) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ return &EVM2EVMOffRampInterface_FilterConfigSet_Call{Call: _e.mock.On("FilterConfigSet", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSetIterator, _a1 error) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSetIterator, error)) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet0 provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterConfigSet0(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0Iterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet0")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0Iterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0Iterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0Iterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0Iterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet0'
+type EVM2EVMOffRampInterface_FilterConfigSet0_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet0 is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterConfigSet0(opts interface{}) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_FilterConfigSet0_Call{Call: _e.mock.On("FilterConfigSet0", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0Iterator, _a1 error) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0Iterator, error)) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterExecutionStateChanged provides a mock function with given fields: opts, sequenceNumber, messageId
+func (_m *EVM2EVMOffRampInterface) FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChangedIterator, error) {
+ ret := _m.Called(opts, sequenceNumber, messageId)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterExecutionStateChanged")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChangedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChangedIterator, error)); ok {
+ return rf(opts, sequenceNumber, messageId)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChangedIterator); ok {
+ r0 = rf(opts, sequenceNumber, messageId)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChangedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, [][32]byte) error); ok {
+ r1 = rf(opts, sequenceNumber, messageId)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterExecutionStateChanged'
+type EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// FilterExecutionStateChanged is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - sequenceNumber []uint64
+// - messageId [][32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterExecutionStateChanged(opts interface{}, sequenceNumber interface{}, messageId interface{}) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call{Call: _e.mock.On("FilterExecutionStateChanged", opts, sequenceNumber, messageId)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) Run(run func(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte)) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChangedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, [][32]byte) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChangedIterator, error)) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to
+func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequestedIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferRequested")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequestedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequestedIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequestedIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequestedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterOwnershipTransferRequested(opts interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call{Call: _e.mock.On("FilterOwnershipTransferRequested", opts, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequestedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequestedIterator, error)) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to
+func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferredIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferred")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferredIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferredIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferredIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferredIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferred'
+type EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterOwnershipTransferred(opts interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call{Call: _e.mock.On("FilterOwnershipTransferred", opts, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferredIterator, _a1 error) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferredIterator, error)) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPoolAdded provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterPoolAdded(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAddedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPoolAdded")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAddedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAddedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAddedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAddedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterPoolAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPoolAdded'
+type EVM2EVMOffRampInterface_FilterPoolAdded_Call struct {
+ *mock.Call
+}
+
+// FilterPoolAdded is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterPoolAdded(opts interface{}) *EVM2EVMOffRampInterface_FilterPoolAdded_Call {
+ return &EVM2EVMOffRampInterface_FilterPoolAdded_Call{Call: _e.mock.On("FilterPoolAdded", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolAdded_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterPoolAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolAdded_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAddedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterPoolAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolAdded_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAddedIterator, error)) *EVM2EVMOffRampInterface_FilterPoolAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPoolRemoved provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterPoolRemoved(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemovedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPoolRemoved")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemovedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemovedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemovedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemovedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterPoolRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPoolRemoved'
+type EVM2EVMOffRampInterface_FilterPoolRemoved_Call struct {
+ *mock.Call
+}
+
+// FilterPoolRemoved is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterPoolRemoved(opts interface{}) *EVM2EVMOffRampInterface_FilterPoolRemoved_Call {
+ return &EVM2EVMOffRampInterface_FilterPoolRemoved_Call{Call: _e.mock.On("FilterPoolRemoved", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolRemoved_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterPoolRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolRemoved_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemovedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterPoolRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolRemoved_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemovedIterator, error)) *EVM2EVMOffRampInterface_FilterPoolRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSkippedIncorrectNonce provides a mock function with given fields: opts, nonce, sender
+func (_m *EVM2EVMOffRampInterface) FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonceIterator, error) {
+ ret := _m.Called(opts, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSkippedIncorrectNonce")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonceIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonceIterator, error)); ok {
+ return rf(opts, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonceIterator); ok {
+ r0 = rf(opts, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonceIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// FilterSkippedIncorrectNonce is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterSkippedIncorrectNonce(opts interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call{Call: _e.mock.On("FilterSkippedIncorrectNonce", opts, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) Run(run func(opts *bind.FilterOpts, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonceIterator, _a1 error) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonceIterator, error)) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: opts, nonce, sender
+func (_m *EVM2EVMOffRampInterface) FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error) {
+ ret := _m.Called(opts, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)); ok {
+ return rf(opts, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator); ok {
+ r0 = rf(opts, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// FilterSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterSkippedSenderWithPreviousRampMessageInflight(opts interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("FilterSkippedSenderWithPreviousRampMessageInflight", opts, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(opts *bind.FilterOpts, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, _a1 error) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTransmitted provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterTransmitted(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmittedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTransmitted")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmittedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmittedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmittedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmittedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTransmitted'
+type EVM2EVMOffRampInterface_FilterTransmitted_Call struct {
+ *mock.Call
+}
+
+// FilterTransmitted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterTransmitted(opts interface{}) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ return &EVM2EVMOffRampInterface_FilterTransmitted_Call{Call: _e.mock.On("FilterTransmitted", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmittedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmittedIterator, error)) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDestinationToken provides a mock function with given fields: opts, sourceToken
+func (_m *EVM2EVMOffRampInterface) GetDestinationToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ ret := _m.Called(opts, sourceToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDestinationToken")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, sourceToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, sourceToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, sourceToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetDestinationToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDestinationToken'
+type EVM2EVMOffRampInterface_GetDestinationToken_Call struct {
+ *mock.Call
+}
+
+// GetDestinationToken is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sourceToken common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetDestinationToken(opts interface{}, sourceToken interface{}) *EVM2EVMOffRampInterface_GetDestinationToken_Call {
+ return &EVM2EVMOffRampInterface_GetDestinationToken_Call{Call: _e.mock.On("GetDestinationToken", opts, sourceToken)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationToken_Call) Run(run func(opts *bind.CallOpts, sourceToken common.Address)) *EVM2EVMOffRampInterface_GetDestinationToken_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationToken_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetDestinationToken_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationToken_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *EVM2EVMOffRampInterface_GetDestinationToken_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDestinationTokens provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetDestinationTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDestinationTokens")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetDestinationTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDestinationTokens'
+type EVM2EVMOffRampInterface_GetDestinationTokens_Call struct {
+ *mock.Call
+}
+
+// GetDestinationTokens is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetDestinationTokens(opts interface{}) *EVM2EVMOffRampInterface_GetDestinationTokens_Call {
+ return &EVM2EVMOffRampInterface_GetDestinationTokens_Call{Call: _e.mock.On("GetDestinationTokens", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationTokens_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetDestinationTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationTokens_Call) Return(_a0 []common.Address, _a1 error) *EVM2EVMOffRampInterface_GetDestinationTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationTokens_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *EVM2EVMOffRampInterface_GetDestinationTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDynamicConfig provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetDynamicConfig(opts *bind.CallOpts) (evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDynamicConfig")
+ }
+
+ var r0 evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetDynamicConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDynamicConfig'
+type EVM2EVMOffRampInterface_GetDynamicConfig_Call struct {
+ *mock.Call
+}
+
+// GetDynamicConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetDynamicConfig(opts interface{}) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ return &EVM2EVMOffRampInterface_GetDynamicConfig_Call{Call: _e.mock.On("GetDynamicConfig", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) Return(_a0 evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig, _a1 error) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig, error)) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetExecutionState provides a mock function with given fields: opts, sequenceNumber
+func (_m *EVM2EVMOffRampInterface) GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error) {
+ ret := _m.Called(opts, sequenceNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetExecutionState")
+ }
+
+ var r0 uint8
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (uint8, error)); ok {
+ return rf(opts, sequenceNumber)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) uint8); ok {
+ r0 = rf(opts, sequenceNumber)
+ } else {
+ r0 = ret.Get(0).(uint8)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, sequenceNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetExecutionState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExecutionState'
+type EVM2EVMOffRampInterface_GetExecutionState_Call struct {
+ *mock.Call
+}
+
+// GetExecutionState is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sequenceNumber uint64
+func (_e *EVM2EVMOffRampInterface_Expecter) GetExecutionState(opts interface{}, sequenceNumber interface{}) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ return &EVM2EVMOffRampInterface_GetExecutionState_Call{Call: _e.mock.On("GetExecutionState", opts, sequenceNumber)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) Run(run func(opts *bind.CallOpts, sequenceNumber uint64)) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) Return(_a0 uint8, _a1 error) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (uint8, error)) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetPoolByDestToken provides a mock function with given fields: opts, destToken
+func (_m *EVM2EVMOffRampInterface) GetPoolByDestToken(opts *bind.CallOpts, destToken common.Address) (common.Address, error) {
+ ret := _m.Called(opts, destToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetPoolByDestToken")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, destToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, destToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, destToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetPoolByDestToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPoolByDestToken'
+type EVM2EVMOffRampInterface_GetPoolByDestToken_Call struct {
+ *mock.Call
+}
+
+// GetPoolByDestToken is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destToken common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetPoolByDestToken(opts interface{}, destToken interface{}) *EVM2EVMOffRampInterface_GetPoolByDestToken_Call {
+ return &EVM2EVMOffRampInterface_GetPoolByDestToken_Call{Call: _e.mock.On("GetPoolByDestToken", opts, destToken)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolByDestToken_Call) Run(run func(opts *bind.CallOpts, destToken common.Address)) *EVM2EVMOffRampInterface_GetPoolByDestToken_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolByDestToken_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetPoolByDestToken_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolByDestToken_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *EVM2EVMOffRampInterface_GetPoolByDestToken_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetPoolBySourceToken provides a mock function with given fields: opts, sourceToken
+func (_m *EVM2EVMOffRampInterface) GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ ret := _m.Called(opts, sourceToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetPoolBySourceToken")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, sourceToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, sourceToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, sourceToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetPoolBySourceToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPoolBySourceToken'
+type EVM2EVMOffRampInterface_GetPoolBySourceToken_Call struct {
+ *mock.Call
+}
+
+// GetPoolBySourceToken is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sourceToken common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetPoolBySourceToken(opts interface{}, sourceToken interface{}) *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call {
+ return &EVM2EVMOffRampInterface_GetPoolBySourceToken_Call{Call: _e.mock.On("GetPoolBySourceToken", opts, sourceToken)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call) Run(run func(opts *bind.CallOpts, sourceToken common.Address)) *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSenderNonce provides a mock function with given fields: opts, sender
+func (_m *EVM2EVMOffRampInterface) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ ret := _m.Called(opts, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSenderNonce")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok {
+ return rf(opts, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) uint64); ok {
+ r0 = rf(opts, sender)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetSenderNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSenderNonce'
+type EVM2EVMOffRampInterface_GetSenderNonce_Call struct {
+ *mock.Call
+}
+
+// GetSenderNonce is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sender common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetSenderNonce(opts interface{}, sender interface{}) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ return &EVM2EVMOffRampInterface_GetSenderNonce_Call{Call: _e.mock.On("GetSenderNonce", opts, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) Run(run func(opts *bind.CallOpts, sender common.Address)) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) Return(_a0 uint64, _a1 error) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (uint64, error)) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStaticConfig provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetStaticConfig(opts *bind.CallOpts) (evm_2_evm_offramp_1_0_0.EVM2EVMOffRampStaticConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStaticConfig")
+ }
+
+ var r0 evm_2_evm_offramp_1_0_0.EVM2EVMOffRampStaticConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.EVM2EVMOffRampStaticConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_0_0.EVM2EVMOffRampStaticConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_0_0.EVM2EVMOffRampStaticConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetStaticConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStaticConfig'
+type EVM2EVMOffRampInterface_GetStaticConfig_Call struct {
+ *mock.Call
+}
+
+// GetStaticConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetStaticConfig(opts interface{}) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ return &EVM2EVMOffRampInterface_GetStaticConfig_Call{Call: _e.mock.On("GetStaticConfig", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) Return(_a0 evm_2_evm_offramp_1_0_0.EVM2EVMOffRampStaticConfig, _a1 error) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.EVM2EVMOffRampStaticConfig, error)) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSupportedTokens provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSupportedTokens")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetSupportedTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSupportedTokens'
+type EVM2EVMOffRampInterface_GetSupportedTokens_Call struct {
+ *mock.Call
+}
+
+// GetSupportedTokens is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetSupportedTokens(opts interface{}) *EVM2EVMOffRampInterface_GetSupportedTokens_Call {
+ return &EVM2EVMOffRampInterface_GetSupportedTokens_Call{Call: _e.mock.On("GetSupportedTokens", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSupportedTokens_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetSupportedTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSupportedTokens_Call) Return(_a0 []common.Address, _a1 error) *EVM2EVMOffRampInterface_GetSupportedTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSupportedTokens_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *EVM2EVMOffRampInterface_GetSupportedTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenLimitAdmin provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenLimitAdmin")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenLimitAdmin'
+type EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call struct {
+ *mock.Call
+}
+
+// GetTokenLimitAdmin is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetTokenLimitAdmin(opts interface{}) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ return &EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call{Call: _e.mock.On("GetTokenLimitAdmin", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTransmitters provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTransmitters")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetTransmitters_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTransmitters'
+type EVM2EVMOffRampInterface_GetTransmitters_Call struct {
+ *mock.Call
+}
+
+// GetTransmitters is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetTransmitters(opts interface{}) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ return &EVM2EVMOffRampInterface_GetTransmitters_Call{Call: _e.mock.On("GetTransmitters", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) Return(_a0 []common.Address, _a1 error) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfigDetails provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) LatestConfigDetails(opts *bind.CallOpts) (evm_2_evm_offramp_1_0_0.LatestConfigDetails, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfigDetails")
+ }
+
+ var r0 evm_2_evm_offramp_1_0_0.LatestConfigDetails
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.LatestConfigDetails, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_0_0.LatestConfigDetails); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_0_0.LatestConfigDetails)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_LatestConfigDetails_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfigDetails'
+type EVM2EVMOffRampInterface_LatestConfigDetails_Call struct {
+ *mock.Call
+}
+
+// LatestConfigDetails is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) LatestConfigDetails(opts interface{}) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ return &EVM2EVMOffRampInterface_LatestConfigDetails_Call{Call: _e.mock.On("LatestConfigDetails", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) Return(_a0 evm_2_evm_offramp_1_0_0.LatestConfigDetails, _a1 error) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.LatestConfigDetails, error)) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfigDigestAndEpoch provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (evm_2_evm_offramp_1_0_0.LatestConfigDigestAndEpoch, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfigDigestAndEpoch")
+ }
+
+ var r0 evm_2_evm_offramp_1_0_0.LatestConfigDigestAndEpoch
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.LatestConfigDigestAndEpoch, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_0_0.LatestConfigDigestAndEpoch); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_0_0.LatestConfigDigestAndEpoch)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfigDigestAndEpoch'
+type EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call struct {
+ *mock.Call
+}
+
+// LatestConfigDigestAndEpoch is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) LatestConfigDigestAndEpoch(opts interface{}) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ return &EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call{Call: _e.mock.On("LatestConfigDigestAndEpoch", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) Return(_a0 evm_2_evm_offramp_1_0_0.LatestConfigDigestAndEpoch, _a1 error) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_0_0.LatestConfigDigestAndEpoch, error)) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ManuallyExecute provides a mock function with given fields: opts, report, gasLimitOverrides
+func (_m *EVM2EVMOffRampInterface) ManuallyExecute(opts *bind.TransactOpts, report evm_2_evm_offramp_1_0_0.InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, report, gasLimitOverrides)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ManuallyExecute")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.InternalExecutionReport, []*big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, report, gasLimitOverrides)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.InternalExecutionReport, []*big.Int) *types.Transaction); ok {
+ r0 = rf(opts, report, gasLimitOverrides)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.InternalExecutionReport, []*big.Int) error); ok {
+ r1 = rf(opts, report, gasLimitOverrides)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ManuallyExecute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ManuallyExecute'
+type EVM2EVMOffRampInterface_ManuallyExecute_Call struct {
+ *mock.Call
+}
+
+// ManuallyExecute is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - report evm_2_evm_offramp_1_0_0.InternalExecutionReport
+// - gasLimitOverrides []*big.Int
+func (_e *EVM2EVMOffRampInterface_Expecter) ManuallyExecute(opts interface{}, report interface{}, gasLimitOverrides interface{}) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ return &EVM2EVMOffRampInterface_ManuallyExecute_Call{Call: _e.mock.On("ManuallyExecute", opts, report, gasLimitOverrides)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) Run(run func(opts *bind.TransactOpts, report evm_2_evm_offramp_1_0_0.InternalExecutionReport, gasLimitOverrides []*big.Int)) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp_1_0_0.InternalExecutionReport), args[2].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.InternalExecutionReport, []*big.Int) (*types.Transaction, error)) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Owner provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) Owner(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Owner")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_Owner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Owner'
+type EVM2EVMOffRampInterface_Owner_Call struct {
+ *mock.Call
+}
+
+// Owner is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) Owner(opts interface{}) *EVM2EVMOffRampInterface_Owner_Call {
+ return &EVM2EVMOffRampInterface_Owner_Call{Call: _e.mock.On("Owner", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseAdminSet provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseAdminSet(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseAdminSet")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseAdminSet'
+type EVM2EVMOffRampInterface_ParseAdminSet_Call struct {
+ *mock.Call
+}
+
+// ParseAdminSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseAdminSet(log interface{}) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ return &EVM2EVMOffRampInterface_ParseAdminSet_Call{Call: _e.mock.On("ParseAdminSet", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet, _a1 error) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet, error)) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseConfigSet(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet'
+type EVM2EVMOffRampInterface_ParseConfigSet_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseConfigSet(log interface{}) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ return &EVM2EVMOffRampInterface_ParseConfigSet_Call{Call: _e.mock.On("ParseConfigSet", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet, _a1 error) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet, error)) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet0 provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseConfigSet0(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet0")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet0'
+type EVM2EVMOffRampInterface_ParseConfigSet0_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet0 is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseConfigSet0(log interface{}) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_ParseConfigSet0_Call{Call: _e.mock.On("ParseConfigSet0", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0, _a1 error) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0, error)) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseExecutionStateChanged provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseExecutionStateChanged(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseExecutionStateChanged")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseExecutionStateChanged'
+type EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// ParseExecutionStateChanged is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseExecutionStateChanged(log interface{}) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call{Call: _e.mock.On("ParseExecutionStateChanged", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, _a1 error) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, error)) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type EVM2EVMOffRampInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseLog(log interface{}) *EVM2EVMOffRampInterface_ParseLog_Call {
+ return &EVM2EVMOffRampInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferRequested provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferRequested(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferRequested")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferRequested is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseOwnershipTransferRequested(log interface{}) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call{Call: _e.mock.On("ParseOwnershipTransferRequested", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, _a1 error) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, error)) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferred provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferred(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferred")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferred'
+type EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferred is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseOwnershipTransferred(log interface{}) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call{Call: _e.mock.On("ParseOwnershipTransferred", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, _a1 error) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, error)) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePoolAdded provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParsePoolAdded(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePoolAdded")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParsePoolAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePoolAdded'
+type EVM2EVMOffRampInterface_ParsePoolAdded_Call struct {
+ *mock.Call
+}
+
+// ParsePoolAdded is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParsePoolAdded(log interface{}) *EVM2EVMOffRampInterface_ParsePoolAdded_Call {
+ return &EVM2EVMOffRampInterface_ParsePoolAdded_Call{Call: _e.mock.On("ParsePoolAdded", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolAdded_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParsePoolAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolAdded_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded, _a1 error) *EVM2EVMOffRampInterface_ParsePoolAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolAdded_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded, error)) *EVM2EVMOffRampInterface_ParsePoolAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePoolRemoved provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParsePoolRemoved(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePoolRemoved")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParsePoolRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePoolRemoved'
+type EVM2EVMOffRampInterface_ParsePoolRemoved_Call struct {
+ *mock.Call
+}
+
+// ParsePoolRemoved is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParsePoolRemoved(log interface{}) *EVM2EVMOffRampInterface_ParsePoolRemoved_Call {
+ return &EVM2EVMOffRampInterface_ParsePoolRemoved_Call{Call: _e.mock.On("ParsePoolRemoved", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolRemoved_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParsePoolRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolRemoved_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved, _a1 error) *EVM2EVMOffRampInterface_ParsePoolRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolRemoved_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved, error)) *EVM2EVMOffRampInterface_ParsePoolRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSkippedIncorrectNonce provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseSkippedIncorrectNonce(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSkippedIncorrectNonce")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// ParseSkippedIncorrectNonce is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseSkippedIncorrectNonce(log interface{}) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call{Call: _e.mock.On("ParseSkippedIncorrectNonce", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, _a1 error) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, error)) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// ParseSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseSkippedSenderWithPreviousRampMessageInflight(log interface{}) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("ParseSkippedSenderWithPreviousRampMessageInflight", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, _a1 error) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTransmitted provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseTransmitted(log types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTransmitted")
+ }
+
+ var r0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTransmitted'
+type EVM2EVMOffRampInterface_ParseTransmitted_Call struct {
+ *mock.Call
+}
+
+// ParseTransmitted is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseTransmitted(log interface{}) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ return &EVM2EVMOffRampInterface_ParseTransmitted_Call{Call: _e.mock.On("ParseTransmitted", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) Return(_a0 *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted, _a1 error) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted, error)) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetAdmin provides a mock function with given fields: opts, newAdmin
+func (_m *EVM2EVMOffRampInterface) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, newAdmin)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetAdmin")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, newAdmin)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, newAdmin)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, newAdmin)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAdmin'
+type EVM2EVMOffRampInterface_SetAdmin_Call struct {
+ *mock.Call
+}
+
+// SetAdmin is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - newAdmin common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) SetAdmin(opts interface{}, newAdmin interface{}) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ return &EVM2EVMOffRampInterface_SetAdmin_Call{Call: _e.mock.On("SetAdmin", opts, newAdmin)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) Run(run func(opts *bind.TransactOpts, newAdmin common.Address)) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetOCR2Config provides a mock function with given fields: opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig
+func (_m *EVM2EVMOffRampInterface) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetOCR2Config")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) *types.Transaction); ok {
+ r0 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) error); ok {
+ r1 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetOCR2Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetOCR2Config'
+type EVM2EVMOffRampInterface_SetOCR2Config_Call struct {
+ *mock.Call
+}
+
+// SetOCR2Config is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - signers []common.Address
+// - transmitters []common.Address
+// - f uint8
+// - onchainConfig []byte
+// - offchainConfigVersion uint64
+// - offchainConfig []byte
+func (_e *EVM2EVMOffRampInterface_Expecter) SetOCR2Config(opts interface{}, signers interface{}, transmitters interface{}, f interface{}, onchainConfig interface{}, offchainConfigVersion interface{}, offchainConfig interface{}) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ return &EVM2EVMOffRampInterface_SetOCR2Config_Call{Call: _e.mock.On("SetOCR2Config", opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) Run(run func(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte)) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].(uint8), args[4].([]byte), args[5].(uint64), args[6].([]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) RunAndReturn(run func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetRateLimiterConfig provides a mock function with given fields: opts, config
+func (_m *EVM2EVMOffRampInterface) SetRateLimiterConfig(opts *bind.TransactOpts, config evm_2_evm_offramp_1_0_0.RateLimiterConfig) (*types.Transaction, error) {
+ ret := _m.Called(opts, config)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetRateLimiterConfig")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.RateLimiterConfig) (*types.Transaction, error)); ok {
+ return rf(opts, config)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.RateLimiterConfig) *types.Transaction); ok {
+ r0 = rf(opts, config)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.RateLimiterConfig) error); ok {
+ r1 = rf(opts, config)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetRateLimiterConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetRateLimiterConfig'
+type EVM2EVMOffRampInterface_SetRateLimiterConfig_Call struct {
+ *mock.Call
+}
+
+// SetRateLimiterConfig is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - config evm_2_evm_offramp_1_0_0.RateLimiterConfig
+func (_e *EVM2EVMOffRampInterface_Expecter) SetRateLimiterConfig(opts interface{}, config interface{}) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ return &EVM2EVMOffRampInterface_SetRateLimiterConfig_Call{Call: _e.mock.On("SetRateLimiterConfig", opts, config)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) Run(run func(opts *bind.TransactOpts, config evm_2_evm_offramp_1_0_0.RateLimiterConfig)) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp_1_0_0.RateLimiterConfig))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp_1_0_0.RateLimiterConfig) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TransferOwnership provides a mock function with given fields: opts, to
+func (_m *EVM2EVMOffRampInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TransferOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_TransferOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferOwnership'
+type EVM2EVMOffRampInterface_TransferOwnership_Call struct {
+ *mock.Call
+}
+
+// TransferOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - to common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) TransferOwnership(opts interface{}, to interface{}) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ return &EVM2EVMOffRampInterface_TransferOwnership_Call{Call: _e.mock.On("TransferOwnership", opts, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) Run(run func(opts *bind.TransactOpts, to common.Address)) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Transmit provides a mock function with given fields: opts, reportContext, report, rs, ss, arg4
+func (_m *EVM2EVMOffRampInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, reportContext, report, rs, ss, arg4)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Transmit")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok {
+ return rf(opts, reportContext, report, rs, ss, arg4)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) *types.Transaction); ok {
+ r0 = rf(opts, reportContext, report, rs, ss, arg4)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) error); ok {
+ r1 = rf(opts, reportContext, report, rs, ss, arg4)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_Transmit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Transmit'
+type EVM2EVMOffRampInterface_Transmit_Call struct {
+ *mock.Call
+}
+
+// Transmit is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - reportContext [3][32]byte
+// - report []byte
+// - rs [][32]byte
+// - ss [][32]byte
+// - arg4 [32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) Transmit(opts interface{}, reportContext interface{}, report interface{}, rs interface{}, ss interface{}, arg4 interface{}) *EVM2EVMOffRampInterface_Transmit_Call {
+ return &EVM2EVMOffRampInterface_Transmit_Call{Call: _e.mock.On("Transmit", opts, reportContext, report, rs, ss, arg4)}
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) Run(run func(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte)) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([3][32]byte), args[2].([]byte), args[3].([][32]byte), args[4].([][32]byte), args[5].([32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) RunAndReturn(run func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TypeAndVersion provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TypeAndVersion")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_TypeAndVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TypeAndVersion'
+type EVM2EVMOffRampInterface_TypeAndVersion_Call struct {
+ *mock.Call
+}
+
+// TypeAndVersion is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) TypeAndVersion(opts interface{}) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ return &EVM2EVMOffRampInterface_TypeAndVersion_Call{Call: _e.mock.On("TypeAndVersion", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) Return(_a0 string, _a1 error) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchAdminSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchAdminSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAdminSet'
+type EVM2EVMOffRampInterface_WatchAdminSet_Call struct {
+ *mock.Call
+}
+
+// WatchAdminSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchAdminSet(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ return &EVM2EVMOffRampInterface_WatchAdminSet_Call{Call: _e.mock.On("WatchAdminSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet)) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampAdminSet) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet'
+type EVM2EVMOffRampInterface_WatchConfigSet_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchConfigSet(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ return &EVM2EVMOffRampInterface_WatchConfigSet_Call{Call: _e.mock.On("WatchConfigSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet)) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet0 provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet0")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet0'
+type EVM2EVMOffRampInterface_WatchConfigSet0_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet0 is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchConfigSet0(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_WatchConfigSet0_Call{Call: _e.mock.On("WatchConfigSet0", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0)) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampConfigSet0) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchExecutionStateChanged provides a mock function with given fields: opts, sink, sequenceNumber, messageId
+func (_m *EVM2EVMOffRampInterface) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, sequenceNumber, messageId)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchExecutionStateChanged")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) (event.Subscription, error)); ok {
+ return rf(opts, sink, sequenceNumber, messageId)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) event.Subscription); ok {
+ r0 = rf(opts, sink, sequenceNumber, messageId)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) error); ok {
+ r1 = rf(opts, sink, sequenceNumber, messageId)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchExecutionStateChanged'
+type EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// WatchExecutionStateChanged is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged
+// - sequenceNumber []uint64
+// - messageId [][32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchExecutionStateChanged(opts interface{}, sink interface{}, sequenceNumber interface{}, messageId interface{}) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call{Call: _e.mock.On("WatchExecutionStateChanged", opts, sink, sequenceNumber, messageId)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte)) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged), args[2].([]uint64), args[3].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to
+func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferRequested")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchOwnershipTransferRequested(opts interface{}, sink interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call{Call: _e.mock.On("WatchOwnershipTransferRequested", opts, sink, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to
+func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferred")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferred'
+type EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchOwnershipTransferred(opts interface{}, sink interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call{Call: _e.mock.On("WatchOwnershipTransferred", opts, sink, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPoolAdded provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPoolAdded")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchPoolAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPoolAdded'
+type EVM2EVMOffRampInterface_WatchPoolAdded_Call struct {
+ *mock.Call
+}
+
+// WatchPoolAdded is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchPoolAdded(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchPoolAdded_Call {
+ return &EVM2EVMOffRampInterface_WatchPoolAdded_Call{Call: _e.mock.On("WatchPoolAdded", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolAdded_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded)) *EVM2EVMOffRampInterface_WatchPoolAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolAdded_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchPoolAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolAdded_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolAdded) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchPoolAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPoolRemoved provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPoolRemoved")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchPoolRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPoolRemoved'
+type EVM2EVMOffRampInterface_WatchPoolRemoved_Call struct {
+ *mock.Call
+}
+
+// WatchPoolRemoved is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchPoolRemoved(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchPoolRemoved_Call {
+ return &EVM2EVMOffRampInterface_WatchPoolRemoved_Call{Call: _e.mock.On("WatchPoolRemoved", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolRemoved_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved)) *EVM2EVMOffRampInterface_WatchPoolRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolRemoved_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchPoolRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolRemoved_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampPoolRemoved) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchPoolRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSkippedIncorrectNonce provides a mock function with given fields: opts, sink, nonce, sender
+func (_m *EVM2EVMOffRampInterface) WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSkippedIncorrectNonce")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, sink, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// WatchSkippedIncorrectNonce is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchSkippedIncorrectNonce(opts interface{}, sink interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call{Call: _e.mock.On("WatchSkippedIncorrectNonce", opts, sink, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce), args[2].([]uint64), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: opts, sink, nonce, sender
+func (_m *EVM2EVMOffRampInterface) WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, sink, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// WatchSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchSkippedSenderWithPreviousRampMessageInflight(opts interface{}, sink interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("WatchSkippedSenderWithPreviousRampMessageInflight", opts, sink, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight), args[2].([]uint64), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTransmitted provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTransmitted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTransmitted'
+type EVM2EVMOffRampInterface_WatchTransmitted_Call struct {
+ *mock.Call
+}
+
+// WatchTransmitted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchTransmitted(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ return &EVM2EVMOffRampInterface_WatchTransmitted_Call{Call: _e.mock.On("WatchTransmitted", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted)) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_0_0.EVM2EVMOffRampTransmitted) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewEVM2EVMOffRampInterface creates a new instance of EVM2EVMOffRampInterface. 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 NewEVM2EVMOffRampInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *EVM2EVMOffRampInterface {
+ mock := &EVM2EVMOffRampInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/ccip/mocks/v1_2_0/evm2_evm_off_ramp_interface.go b/core/gethwrappers/ccip/mocks/v1_2_0/evm2_evm_off_ramp_interface.go
new file mode 100644
index 00000000000..840c6e6c5ed
--- /dev/null
+++ b/core/gethwrappers/ccip/mocks/v1_2_0/evm2_evm_off_ramp_interface.go
@@ -0,0 +1,3603 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_contracts
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ evm_2_evm_offramp_1_2_0 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// EVM2EVMOffRampInterface is an autogenerated mock type for the EVM2EVMOffRampInterface type
+type EVM2EVMOffRampInterface struct {
+ mock.Mock
+}
+
+type EVM2EVMOffRampInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *EVM2EVMOffRampInterface) EXPECT() *EVM2EVMOffRampInterface_Expecter {
+ return &EVM2EVMOffRampInterface_Expecter{mock: &_m.Mock}
+}
+
+// AcceptOwnership provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AcceptOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_AcceptOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AcceptOwnership'
+type EVM2EVMOffRampInterface_AcceptOwnership_Call struct {
+ *mock.Call
+}
+
+// AcceptOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) AcceptOwnership(opts interface{}) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ return &EVM2EVMOffRampInterface_AcceptOwnership_Call{Call: _e.mock.On("AcceptOwnership", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) Run(run func(opts *bind.TransactOpts)) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_AcceptOwnership_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *EVM2EVMOffRampInterface_AcceptOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Address provides a mock function with given fields:
+func (_m *EVM2EVMOffRampInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// EVM2EVMOffRampInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type EVM2EVMOffRampInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *EVM2EVMOffRampInterface_Expecter) Address() *EVM2EVMOffRampInterface_Address_Call {
+ return &EVM2EVMOffRampInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) Run(run func()) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) Return(_a0 common.Address) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Address_Call) RunAndReturn(run func() common.Address) *EVM2EVMOffRampInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ApplyPoolUpdates provides a mock function with given fields: opts, removes, adds
+func (_m *EVM2EVMOffRampInterface) ApplyPoolUpdates(opts *bind.TransactOpts, removes []evm_2_evm_offramp_1_2_0.InternalPoolUpdate, adds []evm_2_evm_offramp_1_2_0.InternalPoolUpdate) (*types.Transaction, error) {
+ ret := _m.Called(opts, removes, adds)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ApplyPoolUpdates")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate) (*types.Transaction, error)); ok {
+ return rf(opts, removes, adds)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate) *types.Transaction); ok {
+ r0 = rf(opts, removes, adds)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate) error); ok {
+ r1 = rf(opts, removes, adds)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ApplyPoolUpdates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ApplyPoolUpdates'
+type EVM2EVMOffRampInterface_ApplyPoolUpdates_Call struct {
+ *mock.Call
+}
+
+// ApplyPoolUpdates is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - removes []evm_2_evm_offramp_1_2_0.InternalPoolUpdate
+// - adds []evm_2_evm_offramp_1_2_0.InternalPoolUpdate
+func (_e *EVM2EVMOffRampInterface_Expecter) ApplyPoolUpdates(opts interface{}, removes interface{}, adds interface{}) *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call {
+ return &EVM2EVMOffRampInterface_ApplyPoolUpdates_Call{Call: _e.mock.On("ApplyPoolUpdates", opts, removes, adds)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call) Run(run func(opts *bind.TransactOpts, removes []evm_2_evm_offramp_1_2_0.InternalPoolUpdate, adds []evm_2_evm_offramp_1_2_0.InternalPoolUpdate)) *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]evm_2_evm_offramp_1_2_0.InternalPoolUpdate), args[2].([]evm_2_evm_offramp_1_2_0.InternalPoolUpdate))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call) RunAndReturn(run func(*bind.TransactOpts, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate) (*types.Transaction, error)) *EVM2EVMOffRampInterface_ApplyPoolUpdates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CcipReceive provides a mock function with given fields: opts, arg0
+func (_m *EVM2EVMOffRampInterface) CcipReceive(opts *bind.CallOpts, arg0 evm_2_evm_offramp_1_2_0.ClientAny2EVMMessage) error {
+ ret := _m.Called(opts, arg0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CcipReceive")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, evm_2_evm_offramp_1_2_0.ClientAny2EVMMessage) error); ok {
+ r0 = rf(opts, arg0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// EVM2EVMOffRampInterface_CcipReceive_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CcipReceive'
+type EVM2EVMOffRampInterface_CcipReceive_Call struct {
+ *mock.Call
+}
+
+// CcipReceive is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - arg0 evm_2_evm_offramp_1_2_0.ClientAny2EVMMessage
+func (_e *EVM2EVMOffRampInterface_Expecter) CcipReceive(opts interface{}, arg0 interface{}) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ return &EVM2EVMOffRampInterface_CcipReceive_Call{Call: _e.mock.On("CcipReceive", opts, arg0)}
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) Run(run func(opts *bind.CallOpts, arg0 evm_2_evm_offramp_1_2_0.ClientAny2EVMMessage)) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(evm_2_evm_offramp_1_2_0.ClientAny2EVMMessage))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) Return(_a0 error) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CcipReceive_Call) RunAndReturn(run func(*bind.CallOpts, evm_2_evm_offramp_1_2_0.ClientAny2EVMMessage) error) *EVM2EVMOffRampInterface_CcipReceive_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CurrentRateLimiterState provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) CurrentRateLimiterState(opts *bind.CallOpts) (evm_2_evm_offramp_1_2_0.RateLimiterTokenBucket, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CurrentRateLimiterState")
+ }
+
+ var r0 evm_2_evm_offramp_1_2_0.RateLimiterTokenBucket
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.RateLimiterTokenBucket, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_2_0.RateLimiterTokenBucket); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_2_0.RateLimiterTokenBucket)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_CurrentRateLimiterState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CurrentRateLimiterState'
+type EVM2EVMOffRampInterface_CurrentRateLimiterState_Call struct {
+ *mock.Call
+}
+
+// CurrentRateLimiterState is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) CurrentRateLimiterState(opts interface{}) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ return &EVM2EVMOffRampInterface_CurrentRateLimiterState_Call{Call: _e.mock.On("CurrentRateLimiterState", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) Return(_a0 evm_2_evm_offramp_1_2_0.RateLimiterTokenBucket, _a1 error) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.RateLimiterTokenBucket, error)) *EVM2EVMOffRampInterface_CurrentRateLimiterState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ExecuteSingleMessage provides a mock function with given fields: opts, message, offchainTokenData
+func (_m *EVM2EVMOffRampInterface) ExecuteSingleMessage(opts *bind.TransactOpts, message evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage, offchainTokenData [][]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, message, offchainTokenData)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExecuteSingleMessage")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage, [][]byte) (*types.Transaction, error)); ok {
+ return rf(opts, message, offchainTokenData)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage, [][]byte) *types.Transaction); ok {
+ r0 = rf(opts, message, offchainTokenData)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage, [][]byte) error); ok {
+ r1 = rf(opts, message, offchainTokenData)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ExecuteSingleMessage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExecuteSingleMessage'
+type EVM2EVMOffRampInterface_ExecuteSingleMessage_Call struct {
+ *mock.Call
+}
+
+// ExecuteSingleMessage is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - message evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage
+// - offchainTokenData [][]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) ExecuteSingleMessage(opts interface{}, message interface{}, offchainTokenData interface{}) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ return &EVM2EVMOffRampInterface_ExecuteSingleMessage_Call{Call: _e.mock.On("ExecuteSingleMessage", opts, message, offchainTokenData)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) Run(run func(opts *bind.TransactOpts, message evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage, offchainTokenData [][]byte)) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage), args[2].([][]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage, [][]byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_ExecuteSingleMessage_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterAdminSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterAdminSet(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterAdminSet")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterAdminSet'
+type EVM2EVMOffRampInterface_FilterAdminSet_Call struct {
+ *mock.Call
+}
+
+// FilterAdminSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterAdminSet(opts interface{}) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ return &EVM2EVMOffRampInterface_FilterAdminSet_Call{Call: _e.mock.On("FilterAdminSet", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSetIterator, _a1 error) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterAdminSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSetIterator, error)) *EVM2EVMOffRampInterface_FilterAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterConfigSet(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSetIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSetIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSetIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet'
+type EVM2EVMOffRampInterface_FilterConfigSet_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterConfigSet(opts interface{}) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ return &EVM2EVMOffRampInterface_FilterConfigSet_Call{Call: _e.mock.On("FilterConfigSet", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSetIterator, _a1 error) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSetIterator, error)) *EVM2EVMOffRampInterface_FilterConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfigSet0 provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterConfigSet0(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0Iterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfigSet0")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0Iterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0Iterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0Iterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0Iterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfigSet0'
+type EVM2EVMOffRampInterface_FilterConfigSet0_Call struct {
+ *mock.Call
+}
+
+// FilterConfigSet0 is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterConfigSet0(opts interface{}) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_FilterConfigSet0_Call{Call: _e.mock.On("FilterConfigSet0", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0Iterator, _a1 error) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterConfigSet0_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0Iterator, error)) *EVM2EVMOffRampInterface_FilterConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterExecutionStateChanged provides a mock function with given fields: opts, sequenceNumber, messageId
+func (_m *EVM2EVMOffRampInterface) FilterExecutionStateChanged(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChangedIterator, error) {
+ ret := _m.Called(opts, sequenceNumber, messageId)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterExecutionStateChanged")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChangedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChangedIterator, error)); ok {
+ return rf(opts, sequenceNumber, messageId)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChangedIterator); ok {
+ r0 = rf(opts, sequenceNumber, messageId)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChangedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, [][32]byte) error); ok {
+ r1 = rf(opts, sequenceNumber, messageId)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterExecutionStateChanged'
+type EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// FilterExecutionStateChanged is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - sequenceNumber []uint64
+// - messageId [][32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterExecutionStateChanged(opts interface{}, sequenceNumber interface{}, messageId interface{}) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call{Call: _e.mock.On("FilterExecutionStateChanged", opts, sequenceNumber, messageId)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) Run(run func(opts *bind.FilterOpts, sequenceNumber []uint64, messageId [][32]byte)) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChangedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, [][32]byte) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChangedIterator, error)) *EVM2EVMOffRampInterface_FilterExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferRequested provides a mock function with given fields: opts, from, to
+func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequestedIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferRequested")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequestedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequestedIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequestedIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequestedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterOwnershipTransferRequested(opts interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call{Call: _e.mock.On("FilterOwnershipTransferRequested", opts, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequestedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequestedIterator, error)) *EVM2EVMOffRampInterface_FilterOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterOwnershipTransferred provides a mock function with given fields: opts, from, to
+func (_m *EVM2EVMOffRampInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferredIterator, error) {
+ ret := _m.Called(opts, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterOwnershipTransferred")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferredIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferredIterator, error)); ok {
+ return rf(opts, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferredIterator); ok {
+ r0 = rf(opts, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferredIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterOwnershipTransferred'
+type EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// FilterOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterOwnershipTransferred(opts interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call{Call: _e.mock.On("FilterOwnershipTransferred", opts, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) Run(run func(opts *bind.FilterOpts, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferredIterator, _a1 error) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferredIterator, error)) *EVM2EVMOffRampInterface_FilterOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPoolAdded provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterPoolAdded(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAddedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPoolAdded")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAddedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAddedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAddedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAddedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterPoolAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPoolAdded'
+type EVM2EVMOffRampInterface_FilterPoolAdded_Call struct {
+ *mock.Call
+}
+
+// FilterPoolAdded is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterPoolAdded(opts interface{}) *EVM2EVMOffRampInterface_FilterPoolAdded_Call {
+ return &EVM2EVMOffRampInterface_FilterPoolAdded_Call{Call: _e.mock.On("FilterPoolAdded", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolAdded_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterPoolAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolAdded_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAddedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterPoolAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolAdded_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAddedIterator, error)) *EVM2EVMOffRampInterface_FilterPoolAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterPoolRemoved provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterPoolRemoved(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemovedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterPoolRemoved")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemovedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemovedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemovedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemovedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterPoolRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterPoolRemoved'
+type EVM2EVMOffRampInterface_FilterPoolRemoved_Call struct {
+ *mock.Call
+}
+
+// FilterPoolRemoved is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterPoolRemoved(opts interface{}) *EVM2EVMOffRampInterface_FilterPoolRemoved_Call {
+ return &EVM2EVMOffRampInterface_FilterPoolRemoved_Call{Call: _e.mock.On("FilterPoolRemoved", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolRemoved_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterPoolRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolRemoved_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemovedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterPoolRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterPoolRemoved_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemovedIterator, error)) *EVM2EVMOffRampInterface_FilterPoolRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSkippedIncorrectNonce provides a mock function with given fields: opts, nonce, sender
+func (_m *EVM2EVMOffRampInterface) FilterSkippedIncorrectNonce(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonceIterator, error) {
+ ret := _m.Called(opts, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSkippedIncorrectNonce")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonceIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonceIterator, error)); ok {
+ return rf(opts, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonceIterator); ok {
+ r0 = rf(opts, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonceIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// FilterSkippedIncorrectNonce is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterSkippedIncorrectNonce(opts interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call{Call: _e.mock.On("FilterSkippedIncorrectNonce", opts, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) Run(run func(opts *bind.FilterOpts, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonceIterator, _a1 error) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonceIterator, error)) *EVM2EVMOffRampInterface_FilterSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: opts, nonce, sender
+func (_m *EVM2EVMOffRampInterface) FilterSkippedSenderWithPreviousRampMessageInflight(opts *bind.FilterOpts, nonce []uint64, sender []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error) {
+ ret := _m.Called(opts, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)); ok {
+ return rf(opts, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, []common.Address) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator); ok {
+ r0 = rf(opts, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// FilterSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterSkippedSenderWithPreviousRampMessageInflight(opts interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("FilterSkippedSenderWithPreviousRampMessageInflight", opts, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(opts *bind.FilterOpts, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, _a1 error) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, []common.Address) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflightIterator, error)) *EVM2EVMOffRampInterface_FilterSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTransmitted provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) FilterTransmitted(opts *bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmittedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTransmitted")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmittedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmittedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmittedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmittedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_FilterTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTransmitted'
+type EVM2EVMOffRampInterface_FilterTransmitted_Call struct {
+ *mock.Call
+}
+
+// FilterTransmitted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) FilterTransmitted(opts interface{}) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ return &EVM2EVMOffRampInterface_FilterTransmitted_Call{Call: _e.mock.On("FilterTransmitted", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) Run(run func(opts *bind.FilterOpts)) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmittedIterator, _a1 error) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_FilterTransmitted_Call) RunAndReturn(run func(*bind.FilterOpts) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmittedIterator, error)) *EVM2EVMOffRampInterface_FilterTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDestinationToken provides a mock function with given fields: opts, sourceToken
+func (_m *EVM2EVMOffRampInterface) GetDestinationToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ ret := _m.Called(opts, sourceToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDestinationToken")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, sourceToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, sourceToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, sourceToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetDestinationToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDestinationToken'
+type EVM2EVMOffRampInterface_GetDestinationToken_Call struct {
+ *mock.Call
+}
+
+// GetDestinationToken is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sourceToken common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetDestinationToken(opts interface{}, sourceToken interface{}) *EVM2EVMOffRampInterface_GetDestinationToken_Call {
+ return &EVM2EVMOffRampInterface_GetDestinationToken_Call{Call: _e.mock.On("GetDestinationToken", opts, sourceToken)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationToken_Call) Run(run func(opts *bind.CallOpts, sourceToken common.Address)) *EVM2EVMOffRampInterface_GetDestinationToken_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationToken_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetDestinationToken_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationToken_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *EVM2EVMOffRampInterface_GetDestinationToken_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDestinationTokens provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetDestinationTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDestinationTokens")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetDestinationTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDestinationTokens'
+type EVM2EVMOffRampInterface_GetDestinationTokens_Call struct {
+ *mock.Call
+}
+
+// GetDestinationTokens is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetDestinationTokens(opts interface{}) *EVM2EVMOffRampInterface_GetDestinationTokens_Call {
+ return &EVM2EVMOffRampInterface_GetDestinationTokens_Call{Call: _e.mock.On("GetDestinationTokens", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationTokens_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetDestinationTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationTokens_Call) Return(_a0 []common.Address, _a1 error) *EVM2EVMOffRampInterface_GetDestinationTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDestinationTokens_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *EVM2EVMOffRampInterface_GetDestinationTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDynamicConfig provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetDynamicConfig(opts *bind.CallOpts) (evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDynamicConfig")
+ }
+
+ var r0 evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetDynamicConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDynamicConfig'
+type EVM2EVMOffRampInterface_GetDynamicConfig_Call struct {
+ *mock.Call
+}
+
+// GetDynamicConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetDynamicConfig(opts interface{}) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ return &EVM2EVMOffRampInterface_GetDynamicConfig_Call{Call: _e.mock.On("GetDynamicConfig", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) Return(_a0 evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig, _a1 error) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetDynamicConfig_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig, error)) *EVM2EVMOffRampInterface_GetDynamicConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetExecutionState provides a mock function with given fields: opts, sequenceNumber
+func (_m *EVM2EVMOffRampInterface) GetExecutionState(opts *bind.CallOpts, sequenceNumber uint64) (uint8, error) {
+ ret := _m.Called(opts, sequenceNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetExecutionState")
+ }
+
+ var r0 uint8
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (uint8, error)); ok {
+ return rf(opts, sequenceNumber)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) uint8); ok {
+ r0 = rf(opts, sequenceNumber)
+ } else {
+ r0 = ret.Get(0).(uint8)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, sequenceNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetExecutionState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExecutionState'
+type EVM2EVMOffRampInterface_GetExecutionState_Call struct {
+ *mock.Call
+}
+
+// GetExecutionState is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sequenceNumber uint64
+func (_e *EVM2EVMOffRampInterface_Expecter) GetExecutionState(opts interface{}, sequenceNumber interface{}) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ return &EVM2EVMOffRampInterface_GetExecutionState_Call{Call: _e.mock.On("GetExecutionState", opts, sequenceNumber)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) Run(run func(opts *bind.CallOpts, sequenceNumber uint64)) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) Return(_a0 uint8, _a1 error) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetExecutionState_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (uint8, error)) *EVM2EVMOffRampInterface_GetExecutionState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetPoolByDestToken provides a mock function with given fields: opts, destToken
+func (_m *EVM2EVMOffRampInterface) GetPoolByDestToken(opts *bind.CallOpts, destToken common.Address) (common.Address, error) {
+ ret := _m.Called(opts, destToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetPoolByDestToken")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, destToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, destToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, destToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetPoolByDestToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPoolByDestToken'
+type EVM2EVMOffRampInterface_GetPoolByDestToken_Call struct {
+ *mock.Call
+}
+
+// GetPoolByDestToken is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - destToken common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetPoolByDestToken(opts interface{}, destToken interface{}) *EVM2EVMOffRampInterface_GetPoolByDestToken_Call {
+ return &EVM2EVMOffRampInterface_GetPoolByDestToken_Call{Call: _e.mock.On("GetPoolByDestToken", opts, destToken)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolByDestToken_Call) Run(run func(opts *bind.CallOpts, destToken common.Address)) *EVM2EVMOffRampInterface_GetPoolByDestToken_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolByDestToken_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetPoolByDestToken_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolByDestToken_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *EVM2EVMOffRampInterface_GetPoolByDestToken_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetPoolBySourceToken provides a mock function with given fields: opts, sourceToken
+func (_m *EVM2EVMOffRampInterface) GetPoolBySourceToken(opts *bind.CallOpts, sourceToken common.Address) (common.Address, error) {
+ ret := _m.Called(opts, sourceToken)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetPoolBySourceToken")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, sourceToken)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, sourceToken)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, sourceToken)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetPoolBySourceToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPoolBySourceToken'
+type EVM2EVMOffRampInterface_GetPoolBySourceToken_Call struct {
+ *mock.Call
+}
+
+// GetPoolBySourceToken is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sourceToken common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetPoolBySourceToken(opts interface{}, sourceToken interface{}) *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call {
+ return &EVM2EVMOffRampInterface_GetPoolBySourceToken_Call{Call: _e.mock.On("GetPoolBySourceToken", opts, sourceToken)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call) Run(run func(opts *bind.CallOpts, sourceToken common.Address)) *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *EVM2EVMOffRampInterface_GetPoolBySourceToken_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSenderNonce provides a mock function with given fields: opts, sender
+func (_m *EVM2EVMOffRampInterface) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ ret := _m.Called(opts, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSenderNonce")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok {
+ return rf(opts, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) uint64); ok {
+ r0 = rf(opts, sender)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetSenderNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSenderNonce'
+type EVM2EVMOffRampInterface_GetSenderNonce_Call struct {
+ *mock.Call
+}
+
+// GetSenderNonce is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sender common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) GetSenderNonce(opts interface{}, sender interface{}) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ return &EVM2EVMOffRampInterface_GetSenderNonce_Call{Call: _e.mock.On("GetSenderNonce", opts, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) Run(run func(opts *bind.CallOpts, sender common.Address)) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) Return(_a0 uint64, _a1 error) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSenderNonce_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (uint64, error)) *EVM2EVMOffRampInterface_GetSenderNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStaticConfig provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetStaticConfig(opts *bind.CallOpts) (evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStaticConfig")
+ }
+
+ var r0 evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetStaticConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStaticConfig'
+type EVM2EVMOffRampInterface_GetStaticConfig_Call struct {
+ *mock.Call
+}
+
+// GetStaticConfig is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetStaticConfig(opts interface{}) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ return &EVM2EVMOffRampInterface_GetStaticConfig_Call{Call: _e.mock.On("GetStaticConfig", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) Return(_a0 evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig, _a1 error) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetStaticConfig_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig, error)) *EVM2EVMOffRampInterface_GetStaticConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSupportedTokens provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSupportedTokens")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetSupportedTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSupportedTokens'
+type EVM2EVMOffRampInterface_GetSupportedTokens_Call struct {
+ *mock.Call
+}
+
+// GetSupportedTokens is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetSupportedTokens(opts interface{}) *EVM2EVMOffRampInterface_GetSupportedTokens_Call {
+ return &EVM2EVMOffRampInterface_GetSupportedTokens_Call{Call: _e.mock.On("GetSupportedTokens", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSupportedTokens_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetSupportedTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSupportedTokens_Call) Return(_a0 []common.Address, _a1 error) *EVM2EVMOffRampInterface_GetSupportedTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetSupportedTokens_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *EVM2EVMOffRampInterface_GetSupportedTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenLimitAdmin provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetTokenLimitAdmin(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenLimitAdmin")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenLimitAdmin'
+type EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call struct {
+ *mock.Call
+}
+
+// GetTokenLimitAdmin is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetTokenLimitAdmin(opts interface{}) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ return &EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call{Call: _e.mock.On("GetTokenLimitAdmin", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *EVM2EVMOffRampInterface_GetTokenLimitAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTransmitters provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTransmitters")
+ }
+
+ var r0 []common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) []common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_GetTransmitters_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTransmitters'
+type EVM2EVMOffRampInterface_GetTransmitters_Call struct {
+ *mock.Call
+}
+
+// GetTransmitters is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) GetTransmitters(opts interface{}) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ return &EVM2EVMOffRampInterface_GetTransmitters_Call{Call: _e.mock.On("GetTransmitters", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) Return(_a0 []common.Address, _a1 error) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_GetTransmitters_Call) RunAndReturn(run func(*bind.CallOpts) ([]common.Address, error)) *EVM2EVMOffRampInterface_GetTransmitters_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfigDetails provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) LatestConfigDetails(opts *bind.CallOpts) (evm_2_evm_offramp_1_2_0.LatestConfigDetails, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfigDetails")
+ }
+
+ var r0 evm_2_evm_offramp_1_2_0.LatestConfigDetails
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.LatestConfigDetails, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_2_0.LatestConfigDetails); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_2_0.LatestConfigDetails)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_LatestConfigDetails_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfigDetails'
+type EVM2EVMOffRampInterface_LatestConfigDetails_Call struct {
+ *mock.Call
+}
+
+// LatestConfigDetails is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) LatestConfigDetails(opts interface{}) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ return &EVM2EVMOffRampInterface_LatestConfigDetails_Call{Call: _e.mock.On("LatestConfigDetails", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) Return(_a0 evm_2_evm_offramp_1_2_0.LatestConfigDetails, _a1 error) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDetails_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.LatestConfigDetails, error)) *EVM2EVMOffRampInterface_LatestConfigDetails_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfigDigestAndEpoch provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (evm_2_evm_offramp_1_2_0.LatestConfigDigestAndEpoch, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfigDigestAndEpoch")
+ }
+
+ var r0 evm_2_evm_offramp_1_2_0.LatestConfigDigestAndEpoch
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.LatestConfigDigestAndEpoch, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) evm_2_evm_offramp_1_2_0.LatestConfigDigestAndEpoch); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(evm_2_evm_offramp_1_2_0.LatestConfigDigestAndEpoch)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfigDigestAndEpoch'
+type EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call struct {
+ *mock.Call
+}
+
+// LatestConfigDigestAndEpoch is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) LatestConfigDigestAndEpoch(opts interface{}) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ return &EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call{Call: _e.mock.On("LatestConfigDigestAndEpoch", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) Return(_a0 evm_2_evm_offramp_1_2_0.LatestConfigDigestAndEpoch, _a1 error) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call) RunAndReturn(run func(*bind.CallOpts) (evm_2_evm_offramp_1_2_0.LatestConfigDigestAndEpoch, error)) *EVM2EVMOffRampInterface_LatestConfigDigestAndEpoch_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ManuallyExecute provides a mock function with given fields: opts, report, gasLimitOverrides
+func (_m *EVM2EVMOffRampInterface) ManuallyExecute(opts *bind.TransactOpts, report evm_2_evm_offramp_1_2_0.InternalExecutionReport, gasLimitOverrides []*big.Int) (*types.Transaction, error) {
+ ret := _m.Called(opts, report, gasLimitOverrides)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ManuallyExecute")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.InternalExecutionReport, []*big.Int) (*types.Transaction, error)); ok {
+ return rf(opts, report, gasLimitOverrides)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.InternalExecutionReport, []*big.Int) *types.Transaction); ok {
+ r0 = rf(opts, report, gasLimitOverrides)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.InternalExecutionReport, []*big.Int) error); ok {
+ r1 = rf(opts, report, gasLimitOverrides)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ManuallyExecute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ManuallyExecute'
+type EVM2EVMOffRampInterface_ManuallyExecute_Call struct {
+ *mock.Call
+}
+
+// ManuallyExecute is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - report evm_2_evm_offramp_1_2_0.InternalExecutionReport
+// - gasLimitOverrides []*big.Int
+func (_e *EVM2EVMOffRampInterface_Expecter) ManuallyExecute(opts interface{}, report interface{}, gasLimitOverrides interface{}) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ return &EVM2EVMOffRampInterface_ManuallyExecute_Call{Call: _e.mock.On("ManuallyExecute", opts, report, gasLimitOverrides)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) Run(run func(opts *bind.TransactOpts, report evm_2_evm_offramp_1_2_0.InternalExecutionReport, gasLimitOverrides []*big.Int)) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp_1_2_0.InternalExecutionReport), args[2].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ManuallyExecute_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.InternalExecutionReport, []*big.Int) (*types.Transaction, error)) *EVM2EVMOffRampInterface_ManuallyExecute_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Owner provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) Owner(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Owner")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_Owner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Owner'
+type EVM2EVMOffRampInterface_Owner_Call struct {
+ *mock.Call
+}
+
+// Owner is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) Owner(opts interface{}) *EVM2EVMOffRampInterface_Owner_Call {
+ return &EVM2EVMOffRampInterface_Owner_Call{Call: _e.mock.On("Owner", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) Return(_a0 common.Address, _a1 error) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Owner_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *EVM2EVMOffRampInterface_Owner_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseAdminSet provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseAdminSet(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseAdminSet")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseAdminSet'
+type EVM2EVMOffRampInterface_ParseAdminSet_Call struct {
+ *mock.Call
+}
+
+// ParseAdminSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseAdminSet(log interface{}) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ return &EVM2EVMOffRampInterface_ParseAdminSet_Call{Call: _e.mock.On("ParseAdminSet", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet, _a1 error) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseAdminSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet, error)) *EVM2EVMOffRampInterface_ParseAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseConfigSet(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet'
+type EVM2EVMOffRampInterface_ParseConfigSet_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseConfigSet(log interface{}) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ return &EVM2EVMOffRampInterface_ParseConfigSet_Call{Call: _e.mock.On("ParseConfigSet", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet, _a1 error) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet, error)) *EVM2EVMOffRampInterface_ParseConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseConfigSet0 provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseConfigSet0(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseConfigSet0")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseConfigSet0'
+type EVM2EVMOffRampInterface_ParseConfigSet0_Call struct {
+ *mock.Call
+}
+
+// ParseConfigSet0 is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseConfigSet0(log interface{}) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_ParseConfigSet0_Call{Call: _e.mock.On("ParseConfigSet0", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0, _a1 error) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseConfigSet0_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0, error)) *EVM2EVMOffRampInterface_ParseConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseExecutionStateChanged provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseExecutionStateChanged(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseExecutionStateChanged")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseExecutionStateChanged'
+type EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// ParseExecutionStateChanged is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseExecutionStateChanged(log interface{}) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call{Call: _e.mock.On("ParseExecutionStateChanged", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, _a1 error) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, error)) *EVM2EVMOffRampInterface_ParseExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type EVM2EVMOffRampInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseLog(log interface{}) *EVM2EVMOffRampInterface_ParseLog_Call {
+ return &EVM2EVMOffRampInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *EVM2EVMOffRampInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferRequested provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferRequested(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferRequested")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferRequested is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseOwnershipTransferRequested(log interface{}) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call{Call: _e.mock.On("ParseOwnershipTransferRequested", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, _a1 error) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, error)) *EVM2EVMOffRampInterface_ParseOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseOwnershipTransferred provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseOwnershipTransferred(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseOwnershipTransferred")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseOwnershipTransferred'
+type EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// ParseOwnershipTransferred is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseOwnershipTransferred(log interface{}) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call{Call: _e.mock.On("ParseOwnershipTransferred", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, _a1 error) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, error)) *EVM2EVMOffRampInterface_ParseOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePoolAdded provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParsePoolAdded(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePoolAdded")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParsePoolAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePoolAdded'
+type EVM2EVMOffRampInterface_ParsePoolAdded_Call struct {
+ *mock.Call
+}
+
+// ParsePoolAdded is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParsePoolAdded(log interface{}) *EVM2EVMOffRampInterface_ParsePoolAdded_Call {
+ return &EVM2EVMOffRampInterface_ParsePoolAdded_Call{Call: _e.mock.On("ParsePoolAdded", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolAdded_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParsePoolAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolAdded_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded, _a1 error) *EVM2EVMOffRampInterface_ParsePoolAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolAdded_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded, error)) *EVM2EVMOffRampInterface_ParsePoolAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParsePoolRemoved provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParsePoolRemoved(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParsePoolRemoved")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParsePoolRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParsePoolRemoved'
+type EVM2EVMOffRampInterface_ParsePoolRemoved_Call struct {
+ *mock.Call
+}
+
+// ParsePoolRemoved is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParsePoolRemoved(log interface{}) *EVM2EVMOffRampInterface_ParsePoolRemoved_Call {
+ return &EVM2EVMOffRampInterface_ParsePoolRemoved_Call{Call: _e.mock.On("ParsePoolRemoved", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolRemoved_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParsePoolRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolRemoved_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved, _a1 error) *EVM2EVMOffRampInterface_ParsePoolRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParsePoolRemoved_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved, error)) *EVM2EVMOffRampInterface_ParsePoolRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSkippedIncorrectNonce provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseSkippedIncorrectNonce(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSkippedIncorrectNonce")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// ParseSkippedIncorrectNonce is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseSkippedIncorrectNonce(log interface{}) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call{Call: _e.mock.On("ParseSkippedIncorrectNonce", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, _a1 error) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, error)) *EVM2EVMOffRampInterface_ParseSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseSkippedSenderWithPreviousRampMessageInflight(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// ParseSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseSkippedSenderWithPreviousRampMessageInflight(log interface{}) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("ParseSkippedSenderWithPreviousRampMessageInflight", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, _a1 error) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, error)) *EVM2EVMOffRampInterface_ParseSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTransmitted provides a mock function with given fields: log
+func (_m *EVM2EVMOffRampInterface) ParseTransmitted(log types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTransmitted")
+ }
+
+ var r0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_ParseTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTransmitted'
+type EVM2EVMOffRampInterface_ParseTransmitted_Call struct {
+ *mock.Call
+}
+
+// ParseTransmitted is a helper method to define mock.On call
+// - log types.Log
+func (_e *EVM2EVMOffRampInterface_Expecter) ParseTransmitted(log interface{}) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ return &EVM2EVMOffRampInterface_ParseTransmitted_Call{Call: _e.mock.On("ParseTransmitted", log)}
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) Run(run func(log types.Log)) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) Return(_a0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted, _a1 error) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_ParseTransmitted_Call) RunAndReturn(run func(types.Log) (*evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted, error)) *EVM2EVMOffRampInterface_ParseTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetAdmin provides a mock function with given fields: opts, newAdmin
+func (_m *EVM2EVMOffRampInterface) SetAdmin(opts *bind.TransactOpts, newAdmin common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, newAdmin)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetAdmin")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, newAdmin)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, newAdmin)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, newAdmin)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAdmin'
+type EVM2EVMOffRampInterface_SetAdmin_Call struct {
+ *mock.Call
+}
+
+// SetAdmin is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - newAdmin common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) SetAdmin(opts interface{}, newAdmin interface{}) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ return &EVM2EVMOffRampInterface_SetAdmin_Call{Call: _e.mock.On("SetAdmin", opts, newAdmin)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) Run(run func(opts *bind.TransactOpts, newAdmin common.Address)) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetAdmin_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetOCR2Config provides a mock function with given fields: opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig
+func (_m *EVM2EVMOffRampInterface) SetOCR2Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetOCR2Config")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) *types.Transaction); ok {
+ r0 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) error); ok {
+ r1 = rf(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetOCR2Config_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetOCR2Config'
+type EVM2EVMOffRampInterface_SetOCR2Config_Call struct {
+ *mock.Call
+}
+
+// SetOCR2Config is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - signers []common.Address
+// - transmitters []common.Address
+// - f uint8
+// - onchainConfig []byte
+// - offchainConfigVersion uint64
+// - offchainConfig []byte
+func (_e *EVM2EVMOffRampInterface_Expecter) SetOCR2Config(opts interface{}, signers interface{}, transmitters interface{}, f interface{}, onchainConfig interface{}, offchainConfigVersion interface{}, offchainConfig interface{}) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ return &EVM2EVMOffRampInterface_SetOCR2Config_Call{Call: _e.mock.On("SetOCR2Config", opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) Run(run func(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte)) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].(uint8), args[4].([]byte), args[5].(uint64), args[6].([]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetOCR2Config_Call) RunAndReturn(run func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetOCR2Config_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetRateLimiterConfig provides a mock function with given fields: opts, config
+func (_m *EVM2EVMOffRampInterface) SetRateLimiterConfig(opts *bind.TransactOpts, config evm_2_evm_offramp_1_2_0.RateLimiterConfig) (*types.Transaction, error) {
+ ret := _m.Called(opts, config)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetRateLimiterConfig")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.RateLimiterConfig) (*types.Transaction, error)); ok {
+ return rf(opts, config)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.RateLimiterConfig) *types.Transaction); ok {
+ r0 = rf(opts, config)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.RateLimiterConfig) error); ok {
+ r1 = rf(opts, config)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_SetRateLimiterConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetRateLimiterConfig'
+type EVM2EVMOffRampInterface_SetRateLimiterConfig_Call struct {
+ *mock.Call
+}
+
+// SetRateLimiterConfig is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - config evm_2_evm_offramp_1_2_0.RateLimiterConfig
+func (_e *EVM2EVMOffRampInterface_Expecter) SetRateLimiterConfig(opts interface{}, config interface{}) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ return &EVM2EVMOffRampInterface_SetRateLimiterConfig_Call{Call: _e.mock.On("SetRateLimiterConfig", opts, config)}
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) Run(run func(opts *bind.TransactOpts, config evm_2_evm_offramp_1_2_0.RateLimiterConfig)) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(evm_2_evm_offramp_1_2_0.RateLimiterConfig))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call) RunAndReturn(run func(*bind.TransactOpts, evm_2_evm_offramp_1_2_0.RateLimiterConfig) (*types.Transaction, error)) *EVM2EVMOffRampInterface_SetRateLimiterConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TransferOwnership provides a mock function with given fields: opts, to
+func (_m *EVM2EVMOffRampInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TransferOwnership")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_TransferOwnership_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TransferOwnership'
+type EVM2EVMOffRampInterface_TransferOwnership_Call struct {
+ *mock.Call
+}
+
+// TransferOwnership is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - to common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) TransferOwnership(opts interface{}, to interface{}) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ return &EVM2EVMOffRampInterface_TransferOwnership_Call{Call: _e.mock.On("TransferOwnership", opts, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) Run(run func(opts *bind.TransactOpts, to common.Address)) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TransferOwnership_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *EVM2EVMOffRampInterface_TransferOwnership_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Transmit provides a mock function with given fields: opts, reportContext, report, rs, ss, arg4
+func (_m *EVM2EVMOffRampInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, reportContext, report, rs, ss, arg4)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Transmit")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok {
+ return rf(opts, reportContext, report, rs, ss, arg4)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) *types.Transaction); ok {
+ r0 = rf(opts, reportContext, report, rs, ss, arg4)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) error); ok {
+ r1 = rf(opts, reportContext, report, rs, ss, arg4)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_Transmit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Transmit'
+type EVM2EVMOffRampInterface_Transmit_Call struct {
+ *mock.Call
+}
+
+// Transmit is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - reportContext [3][32]byte
+// - report []byte
+// - rs [][32]byte
+// - ss [][32]byte
+// - arg4 [32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) Transmit(opts interface{}, reportContext interface{}, report interface{}, rs interface{}, ss interface{}, arg4 interface{}) *EVM2EVMOffRampInterface_Transmit_Call {
+ return &EVM2EVMOffRampInterface_Transmit_Call{Call: _e.mock.On("Transmit", opts, reportContext, report, rs, ss, arg4)}
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) Run(run func(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, arg4 [32]byte)) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([3][32]byte), args[2].([]byte), args[3].([][32]byte), args[4].([][32]byte), args[5].([32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) Return(_a0 *types.Transaction, _a1 error) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_Transmit_Call) RunAndReturn(run func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)) *EVM2EVMOffRampInterface_Transmit_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TypeAndVersion provides a mock function with given fields: opts
+func (_m *EVM2EVMOffRampInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TypeAndVersion")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_TypeAndVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TypeAndVersion'
+type EVM2EVMOffRampInterface_TypeAndVersion_Call struct {
+ *mock.Call
+}
+
+// TypeAndVersion is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *EVM2EVMOffRampInterface_Expecter) TypeAndVersion(opts interface{}) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ return &EVM2EVMOffRampInterface_TypeAndVersion_Call{Call: _e.mock.On("TypeAndVersion", opts)}
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) Run(run func(opts *bind.CallOpts)) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) Return(_a0 string, _a1 error) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_TypeAndVersion_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *EVM2EVMOffRampInterface_TypeAndVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchAdminSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchAdminSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchAdminSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchAdminSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchAdminSet'
+type EVM2EVMOffRampInterface_WatchAdminSet_Call struct {
+ *mock.Call
+}
+
+// WatchAdminSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchAdminSet(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ return &EVM2EVMOffRampInterface_WatchAdminSet_Call{Call: _e.mock.On("WatchAdminSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet)) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchAdminSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampAdminSet) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchAdminSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchConfigSet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet'
+type EVM2EVMOffRampInterface_WatchConfigSet_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchConfigSet(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ return &EVM2EVMOffRampInterface_WatchConfigSet_Call{Call: _e.mock.On("WatchConfigSet", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet)) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchConfigSet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchConfigSet0 provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchConfigSet0(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchConfigSet0")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchConfigSet0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchConfigSet0'
+type EVM2EVMOffRampInterface_WatchConfigSet0_Call struct {
+ *mock.Call
+}
+
+// WatchConfigSet0 is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchConfigSet0(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ return &EVM2EVMOffRampInterface_WatchConfigSet0_Call{Call: _e.mock.On("WatchConfigSet0", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0)) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchConfigSet0_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampConfigSet0) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchConfigSet0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchExecutionStateChanged provides a mock function with given fields: opts, sink, sequenceNumber, messageId
+func (_m *EVM2EVMOffRampInterface) WatchExecutionStateChanged(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, sequenceNumber, messageId)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchExecutionStateChanged")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) (event.Subscription, error)); ok {
+ return rf(opts, sink, sequenceNumber, messageId)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) event.Subscription); ok {
+ r0 = rf(opts, sink, sequenceNumber, messageId)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) error); ok {
+ r1 = rf(opts, sink, sequenceNumber, messageId)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchExecutionStateChanged'
+type EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call struct {
+ *mock.Call
+}
+
+// WatchExecutionStateChanged is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged
+// - sequenceNumber []uint64
+// - messageId [][32]byte
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchExecutionStateChanged(opts interface{}, sink interface{}, sequenceNumber interface{}, messageId interface{}) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ return &EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call{Call: _e.mock.On("WatchExecutionStateChanged", opts, sink, sequenceNumber, messageId)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, sequenceNumber []uint64, messageId [][32]byte)) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged), args[2].([]uint64), args[3].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampExecutionStateChanged, []uint64, [][32]byte) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchExecutionStateChanged_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferRequested provides a mock function with given fields: opts, sink, from, to
+func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferRequested")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferRequested'
+type EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferRequested is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchOwnershipTransferRequested(opts interface{}, sink interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ return &EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call{Call: _e.mock.On("WatchOwnershipTransferRequested", opts, sink, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchOwnershipTransferRequested_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchOwnershipTransferred provides a mock function with given fields: opts, sink, from, to
+func (_m *EVM2EVMOffRampInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, from, to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchOwnershipTransferred")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, from, to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, from, to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, from, to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchOwnershipTransferred'
+type EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call struct {
+ *mock.Call
+}
+
+// WatchOwnershipTransferred is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred
+// - from []common.Address
+// - to []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchOwnershipTransferred(opts interface{}, sink interface{}, from interface{}, to interface{}) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ return &EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call{Call: _e.mock.On("WatchOwnershipTransferred", opts, sink, from, to)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, from []common.Address, to []common.Address)) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchOwnershipTransferred_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPoolAdded provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchPoolAdded(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPoolAdded")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchPoolAdded_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPoolAdded'
+type EVM2EVMOffRampInterface_WatchPoolAdded_Call struct {
+ *mock.Call
+}
+
+// WatchPoolAdded is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchPoolAdded(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchPoolAdded_Call {
+ return &EVM2EVMOffRampInterface_WatchPoolAdded_Call{Call: _e.mock.On("WatchPoolAdded", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolAdded_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded)) *EVM2EVMOffRampInterface_WatchPoolAdded_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolAdded_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchPoolAdded_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolAdded_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolAdded) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchPoolAdded_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchPoolRemoved provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchPoolRemoved(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchPoolRemoved")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchPoolRemoved_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchPoolRemoved'
+type EVM2EVMOffRampInterface_WatchPoolRemoved_Call struct {
+ *mock.Call
+}
+
+// WatchPoolRemoved is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchPoolRemoved(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchPoolRemoved_Call {
+ return &EVM2EVMOffRampInterface_WatchPoolRemoved_Call{Call: _e.mock.On("WatchPoolRemoved", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolRemoved_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved)) *EVM2EVMOffRampInterface_WatchPoolRemoved_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolRemoved_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchPoolRemoved_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchPoolRemoved_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampPoolRemoved) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchPoolRemoved_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSkippedIncorrectNonce provides a mock function with given fields: opts, sink, nonce, sender
+func (_m *EVM2EVMOffRampInterface) WatchSkippedIncorrectNonce(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSkippedIncorrectNonce")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, sink, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSkippedIncorrectNonce'
+type EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call struct {
+ *mock.Call
+}
+
+// WatchSkippedIncorrectNonce is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchSkippedIncorrectNonce(opts interface{}, sink interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ return &EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call{Call: _e.mock.On("WatchSkippedIncorrectNonce", opts, sink, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce), args[2].([]uint64), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedIncorrectNonce, []uint64, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchSkippedIncorrectNonce_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSkippedSenderWithPreviousRampMessageInflight provides a mock function with given fields: opts, sink, nonce, sender
+func (_m *EVM2EVMOffRampInterface) WatchSkippedSenderWithPreviousRampMessageInflight(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nonce, sender)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSkippedSenderWithPreviousRampMessageInflight")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, nonce, sender)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, nonce, sender)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) error); ok {
+ r1 = rf(opts, sink, nonce, sender)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSkippedSenderWithPreviousRampMessageInflight'
+type EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call struct {
+ *mock.Call
+}
+
+// WatchSkippedSenderWithPreviousRampMessageInflight is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight
+// - nonce []uint64
+// - sender []common.Address
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchSkippedSenderWithPreviousRampMessageInflight(opts interface{}, sink interface{}, nonce interface{}, sender interface{}) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ return &EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call{Call: _e.mock.On("WatchSkippedSenderWithPreviousRampMessageInflight", opts, sink, nonce, sender)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, nonce []uint64, sender []common.Address)) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight), args[2].([]uint64), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampSkippedSenderWithPreviousRampMessageInflight, []uint64, []common.Address) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchSkippedSenderWithPreviousRampMessageInflight_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTransmitted provides a mock function with given fields: opts, sink
+func (_m *EVM2EVMOffRampInterface) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTransmitted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EVM2EVMOffRampInterface_WatchTransmitted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTransmitted'
+type EVM2EVMOffRampInterface_WatchTransmitted_Call struct {
+ *mock.Call
+}
+
+// WatchTransmitted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted
+func (_e *EVM2EVMOffRampInterface_Expecter) WatchTransmitted(opts interface{}, sink interface{}) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ return &EVM2EVMOffRampInterface_WatchTransmitted_Call{Call: _e.mock.On("WatchTransmitted", opts, sink)}
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted)) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted))
+ })
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) Return(_a0 event.Subscription, _a1 error) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EVM2EVMOffRampInterface_WatchTransmitted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *evm_2_evm_offramp_1_2_0.EVM2EVMOffRampTransmitted) (event.Subscription, error)) *EVM2EVMOffRampInterface_WatchTransmitted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewEVM2EVMOffRampInterface creates a new instance of EVM2EVMOffRampInterface. 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 NewEVM2EVMOffRampInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *EVM2EVMOffRampInterface {
+ mock := &EVM2EVMOffRampInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/generated/arbitrum_module/arbitrum_module.go b/core/gethwrappers/generated/arbitrum_module/arbitrum_module.go
index 537fbe21544..ca9b77d563f 100644
--- a/core/gethwrappers/generated/arbitrum_module/arbitrum_module.go
+++ b/core/gethwrappers/generated/arbitrum_module/arbitrum_module.go
@@ -29,8 +29,8 @@ var (
)
var ArbitrumModuleMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
- Bin: "0x608060405234801561001057600080fd5b5061041b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a2578063de9ee35e146100b557600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a366004610333565b6100cb565b6040519081526020015b60405180910390f35b61007f610158565b61007f6101cf565b61007f6100b0366004610333565b61021d565b6040805161138881526000602082015201610089565b600080606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa15801561011a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061013e919061034c565b50505050915050828161015191906103c5565b9392505050565b6000606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101ca91906103e2565b905090565b6000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101a6573d6000803e3d6000fd5b600080606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561026c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029091906103e2565b905080831015806102ab57506101006102a984836103fb565b115b156102b95750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa15801561030f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061015191906103e2565b60006020828403121561034557600080fd5b5035919050565b60008060008060008060c0878903121561036557600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176103dc576103dc610396565b92915050565b6000602082840312156103f457600080fd5b5051919050565b818103818111156103dc576103dc61039656fea164736f6c6343000813000a",
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b5061044a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637810d12a116100505780637810d12a1461009a57806385df51fd146100ad578063de9ee35e146100c057600080fd5b8063125441401461006c57806357e871e714610092575b600080fd5b61007f61007a366004610368565b6100d6565b6040519081526020015b60405180910390f35b61007f610163565b61007f6100a8366004610368565b6101da565b61007f6100bb366004610368565b610252565b6040805161138881526000602082015201610089565b600080606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa158015610125573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101499190610381565b50505050915050828161015c91906103fa565b9392505050565b6000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101d59190610411565b905090565b6000606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610228573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061024c9190610411565b92915050565b600080606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c59190610411565b905080831015806102e057506101006102de848361042a565b115b156102ee5750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa158015610344573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061015c9190610411565b60006020828403121561037a57600080fd5b5035919050565b60008060008060008060c0878903121561039a57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761024c5761024c6103cb565b60006020828403121561042357600080fd5b5051919050565b8181038181111561024c5761024c6103cb56fea164736f6c6343000813000a",
}
var ArbitrumModuleABI = ArbitrumModuleMetaData.ABI
@@ -213,9 +213,9 @@ func (_ArbitrumModule *ArbitrumModuleCallerSession) BlockNumber() (*big.Int, err
return _ArbitrumModule.Contract.BlockNumber(&_ArbitrumModule.CallOpts)
}
-func (_ArbitrumModule *ArbitrumModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error) {
+func (_ArbitrumModule *ArbitrumModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) {
var out []interface{}
- err := _ArbitrumModule.contract.Call(opts, &out, "getCurrentL1Fee")
+ err := _ArbitrumModule.contract.Call(opts, &out, "getCurrentL1Fee", arg0)
if err != nil {
return *new(*big.Int), err
@@ -227,12 +227,12 @@ func (_ArbitrumModule *ArbitrumModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts
}
-func (_ArbitrumModule *ArbitrumModuleSession) GetCurrentL1Fee() (*big.Int, error) {
- return _ArbitrumModule.Contract.GetCurrentL1Fee(&_ArbitrumModule.CallOpts)
+func (_ArbitrumModule *ArbitrumModuleSession) GetCurrentL1Fee(arg0 *big.Int) (*big.Int, error) {
+ return _ArbitrumModule.Contract.GetCurrentL1Fee(&_ArbitrumModule.CallOpts, arg0)
}
-func (_ArbitrumModule *ArbitrumModuleCallerSession) GetCurrentL1Fee() (*big.Int, error) {
- return _ArbitrumModule.Contract.GetCurrentL1Fee(&_ArbitrumModule.CallOpts)
+func (_ArbitrumModule *ArbitrumModuleCallerSession) GetCurrentL1Fee(arg0 *big.Int) (*big.Int, error) {
+ return _ArbitrumModule.Contract.GetCurrentL1Fee(&_ArbitrumModule.CallOpts, arg0)
}
func (_ArbitrumModule *ArbitrumModuleCaller) GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
@@ -301,7 +301,7 @@ type ArbitrumModuleInterface interface {
BlockNumber(opts *bind.CallOpts) (*big.Int, error)
- GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error)
+ GetCurrentL1Fee(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error)
GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
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 acbf11155db..c2a808d5545 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
@@ -57,7 +57,7 @@ type AutomationRegistryBase23PaymentReceipt struct {
var AutomationRegistryLogicBMetaData = &bind.MetaData{
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\":\"contractIERC20Metadata\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"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\"},{\"components\":[{\"internalType\":\"uint96\",\"name\":\"gasChargeInBillingToken\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"premiumInBillingToken\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"gasReimbursementInJuels\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"premiumInJuels\",\"type\":\"uint96\"},{\"internalType\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"linkUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"billingUSD\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.PaymentReceipt\",\"name\":\"receipt\",\"type\":\"tuple\"}],\"name\":\"UpkeepCharged\",\"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\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"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\":\"contractIERC20Metadata\",\"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: "0x6101806040523480156200001257600080fd5b5060405162005d2238038062005d2283398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e051610100516101205161014051610160516155e86200073a60003960008181610182015261022f0152600081816120e7015261228d01526000612bb30152600050506000612ee901526000613c5d01526000612fc3015260008181610c4701528181610d0801528181610dd30152612c7401526155e86000f3fe6080604052600436106101805760003560e01c80638765ecbe116100d6578063aed2e9291161007f578063ce7dc5b411610059578063ce7dc5b4146104b1578063f2fde38b146104d1578063f7d334ba146104f157610180565b8063aed2e9291461043a578063b148ab6b14610471578063cd7f71b51461049157610180565b8063948108f7116100b0578063948108f7146103e7578063a72aa27e146103fa578063a86e17811461041a57610180565b80638765ecbe1461037c5780638da5cb5b1461039c5780638dcf0fe7146103c757610180565b806354b7faae1161013857806371fae17f1161011257806371fae17f14610327578063744bfe611461034757806379ba50971461036757610180565b806354b7faae146102b457806368d369d8146102d457806371791aa0146102f457610180565b8063349e8cca11610169578063349e8cca146102205780634ee88d35146102745780635165f2f51461029457610180565b80631a2af011146101c757806329c5efad146101e7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156101c0573d6000f35b3d6000fd5b005b3480156101d357600080fd5b506101c56101e2366004614490565b610511565b3480156101f357600080fd5b50610207610202366004614604565b610617565b6040516102179493929190614723565b60405180910390f35b34801561022c57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610217565b34801561028057600080fd5b506101c561028f3660046147a5565b6108f5565b3480156102a057600080fd5b506101c56102af3660046147f1565b610957565b3480156102c057600080fd5b506101c56102cf36600461480a565b610b09565b3480156102e057600080fd5b506101c56102ef366004614836565b610d7c565b34801561030057600080fd5b5061031461030f366004614604565b61102a565b6040516102179796959493929190614877565b34801561033357600080fd5b506101c56103423660046147f1565b61178e565b34801561035357600080fd5b506101c5610362366004614490565b611824565b34801561037357600080fd5b506101c5611c9c565b34801561038857600080fd5b506101c56103973660046147f1565b611d99565b3480156103a857600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661024f565b3480156103d357600080fd5b506101c56103e23660046147a5565b611f4e565b6101c56103f53660046148c5565b611fa3565b34801561040657600080fd5b506101c561041536600461490d565b612365565b34801561042657600080fd5b506101c5610435366004614932565b612464565b34801561044657600080fd5b5061045a6104553660046147a5565b612545565b604080519215158352602083019190915201610217565b34801561047d57600080fd5b506101c561048c3660046147f1565b6126f0565b34801561049d57600080fd5b506101c56104ac3660046147a5565b61291d565b3480156104bd57600080fd5b506102076104cc3660046149ac565b6129d4565b3480156104dd57600080fd5b506101c56104ec366004614a8e565b612a96565b3480156104fd57600080fd5b5061031461050c3660046147f1565b612aaa565b61051a82612ae6565b3373ffffffffffffffffffffffffffffffffffffffff821603610569576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116146106135760008281526006602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b5050565b60006060600080610626612b9b565b600086815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff620100008204811695830195909552660100000000000081048516606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490941660e0820152600290910154909216908201525a9150600080826080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561077c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a09190614abb565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16896040516107e09190614ad8565b60006040518083038160008787f1925050503d806000811461081e576040519150601f19603f3d011682016040523d82523d6000602084013e610823565b606091505b50915091505a6108339085614b23565b93508161085c5760006040518060200160405280600081525060079650965096505050506108ec565b808060200190518101906108709190614b8b565b90975095508661089c5760006040518060200160405280600081525060049650965096505050506108ec565b60185486517401000000000000000000000000000000000000000090910463ffffffff1610156108e85760006040518060200160405280600081525060059650965096505050506108ec565b5050505b92959194509250565b6108fe83612ae6565b6000838152601d60205260409020610917828483614c70565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664838360405161094a929190614dd4565b60405180910390a2505050565b61096081612ae6565b600081815260046020908152604091829020825161012081018452815460ff808216151580845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152610a9a576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055610ad9600283612c0c565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b610b11612c21565b73ffffffffffffffffffffffffffffffffffffffff8216610b5e576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610b68612c72565b90506000811215610bb4576040517fcf47918100000000000000000000000000000000000000000000000000000000815260006004820152602481018390526044015b60405180910390fd5b80821115610bf8576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610bab565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000917f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610c92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb69190614de8565b905080610cef576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa885604051610d6e91815260200190565b60405180910390a350505050565b610d84612c21565b73ffffffffffffffffffffffffffffffffffffffff8216610dd1576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e56576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e60612c72565b128015610e835750600060255460ff166001811115610e8157610e816146b9565b145b15610eba576040517f981bb6a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190614e03565b610f649190614b23565b905080821115610faa576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610bab565b610fcb73ffffffffffffffffffffffffffffffffffffffff85168484612d41565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa884604051610d6e91815260200190565b60006060600080600080600061103e612b9b565b60006110498a612e1a565b905060006014604051806101200160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160139054906101000a900461ffff1661ffff1661ffff1681526020016000820160159054906101000a900460ff1660ff1660ff1681526020016000820160169054906101000a900460ff161515151581526020016000820160179054906101000a900460ff161515151581526020016000820160189054906101000a900460ff161515151581526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000600460008d8152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000808360a001511561140c5750506040805160208101825260008082529290910151919a5098506009975089965063ffffffff169450859350839250611782915050565b606083015163ffffffff908116146114565750506040805160208101825260008082529290910151919a5098506001975089965063ffffffff169450859350839250611782915050565b8251156114955750506040805160208101825260008082529290910151919a5098506002975089965063ffffffff169450859350839250611782915050565b61149e84612ec5565b8094508198508299505050506114c38e858786604001518b8b888a61010001516130b7565b9050806bffffffffffffffffffffffff168360c001516bffffffffffffffffffffffff1610156115255750506040805160208101825260008082529290910151919a5098506006975089965063ffffffff169450859350839250611782915050565b505060006115348d858e613427565b90505a9750600080836080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561158b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115af9190614abb565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16846040516115ef9190614ad8565b60006040518083038160008787f1925050503d806000811461162d576040519150601f19603f3d011682016040523d82523d6000602084013e611632565b606091505b50915091505a611642908b614b23565b9950816116c8576018548151780100000000000000000000000000000000000000000000000090910463ffffffff1610156116a75750506040805160208101825260008082529390910151929b509950600898505063ffffffff169450611782915050565b604090930151929a50600399505063ffffffff909116955061178292505050565b808060200190518101906116dc9190614b8b565b909d509b508c6117165750506040805160208101825260008082529390910151929b509950600498505063ffffffff169450611782915050565b6018548c517401000000000000000000000000000000000000000090910463ffffffff1610156117705750506040805160208101825260008082529390910151929b509950600598505063ffffffff169450611782915050565b5050506040015163ffffffff16945050505b92959891949750929550565b611796613607565b600081815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055602390915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690555182917f97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a91a250565b60145477010000000000000000000000000000000000000000000000900460ff161561187c576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000017905573ffffffffffffffffffffffffffffffffffffffff811661190b576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615158387015263ffffffff620100008304811684870152660100000000000083048116606085015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009093048316608085015260018501546fffffffffffffffffffffffffffffffff811660a08601526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08601527c010000000000000000000000000000000000000000000000000000000090041660e084015260029093015481169282019290925286855260059093529220549091163314611a4b576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601554604080517f57e871e7000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216916357e871e7916004808201926020929091908290030181865afa158015611abb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adf9190614e03565b816060015163ffffffff161115611b22576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526004602090815260408083206001015461010085015173ffffffffffffffffffffffffffffffffffffffff1684526021909252909120547001000000000000000000000000000000009091046bffffffffffffffffffffffff1690611b8d908290614b23565b6101008301805173ffffffffffffffffffffffffffffffffffffffff908116600090815260216020908152604080832095909555888252600490529290922060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff16905551611c109116846bffffffffffffffffffffffff8416612d41565b604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8516602082015285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a25050601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff1690555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610bab565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611da281612ae6565b600081815260046020908152604091829020825161012081018452815460ff808216158015845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152611edc576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611f1e600283613658565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b611f5783612ae6565b6000838152601e60205260409020611f70828483614c70565b50827f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850838360405161094a929190614dd4565b600082815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e084015260029093015416928101929092529091146120df576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b341561217b577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681610100015173ffffffffffffffffffffffffffffffffffffffff161461216f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61217834613664565b91505b818160c0015161218b9190614e1c565b600084815260046020908152604080832060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000006bffffffffffffffffffffffff9687160217905561010085015173ffffffffffffffffffffffffffffffffffffffff168352602190915290205461221b91841690614e41565b61010082015173ffffffffffffffffffffffffffffffffffffffff1660009081526021602052604081209190915534900361228b576101008101516122869073ffffffffffffffffffffffffffffffffffffffff1633306bffffffffffffffffffffffff8616613706565b61231b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836bffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016000604051808303818588803b15801561230157600080fd5b505af1158015612315573d6000803e3d6000fd5b50505050505b6040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6108fc8163ffffffff1610806123a2575060165463ffffffff78010000000000000000000000000000000000000000000000009091048116908216115b156123d9576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6123e282612ae6565b60008281526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff166201000063ffffffff861690810291909117909155915191825283917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c91015b60405180910390a25050565b61246c613607565b6000828152600460205260409020546601000000000000900463ffffffff908116146124c4576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556023909152902081906125128282614e65565b905050817fd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b340826040516124589190614eec565b600080612550612b9b565b601454760100000000000000000000000000000000000000000000900460ff16156125a7576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615158386015262010000820463ffffffff90811684880181905266010000000000008404821660608601526a010000000000000000000090930473ffffffffffffffffffffffffffffffffffffffff9081166080860181905260018701546fffffffffffffffffffffffffffffffff811660a088015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08801527c0100000000000000000000000000000000000000000000000000000000900490921660e0860152600290950154909416908301528451601f890185900485028101850190955287855290936126e393899089908190840183828082843760009201919091525061376a92505050565b9097909650945050505050565b600081815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e0840152600290930154169281019290925290911461282c576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612889576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602090815260408083208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821790935560069094528285208054909216909155905173ffffffffffffffffffffffffffffffffffffffff90911692839186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b61292683612ae6565b6017547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16811115612988576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602052604090206129a1828483614c70565b50827fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d838360405161094a929190614dd4565b600060606000806000634b56a42e60e01b8888886040516024016129fa93929190614f23565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050612a838982610617565b929c919b50995090975095505050505050565b612a9e613985565b612aa781613a06565b50565b600060606000806000806000612acf886040518060200160405280600081525061102a565b959e949d50929b5090995097509550909350915050565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612b43576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020546601000000000000900463ffffffff90811614612aa7576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612c0a576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6000612c188383613afb565b90505b92915050565b60185473ffffffffffffffffffffffffffffffffffffffff163314612c0a576040517fb6dfb7a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015612d0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d329190614e03565b612d3c9190614fb9565b905090565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052612e159084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613b4a565b505050565b6000818160045b600f811015612ea7577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612e5f57612e5f614fd9565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612e9557506000949350505050565b80612e9f81615008565b915050612e21565b5081600f1a6001811115612ebd57612ebd6146b9565b949350505050565b600080600080846040015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612f52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f76919061505a565b5094509092505050600081131580612f8d57508142105b80612fae5750828015612fae5750612fa58242614b23565b8463ffffffff16105b15612fbd576019549650612fc1565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561302c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613050919061505a565b509450909250505060008113158061306757508142105b806130885750828015613088575061307f8242614b23565b8463ffffffff16105b1561309757601a54955061309b565b8095505b86866130a68a613c56565b965096509650505050509193909250565b60008080808960018111156130ce576130ce6146b9565b036130dd575062017f98613132565b60018960018111156130f1576130f16146b9565b0361310057506201de84613132565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008a60800151600161314591906150aa565b6131539060ff1660406150c3565b601854613181906103a49074010000000000000000000000000000000000000000900463ffffffff16614e41565b61318b9190614e41565b601554604080517fde9ee35e0000000000000000000000000000000000000000000000000000000081528151939450600093849373ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa1580156131fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322091906150da565b90925090508183613232836018614e41565b61323c91906150c3565b60808f015161324c9060016150aa565b61325b9060ff166115e06150c3565b6132659190614e41565b61326f9190614e41565b6132799085614e41565b6101008e01516040517f125441400000000000000000000000000000000000000000000000000000000081526004810186905291955073ffffffffffffffffffffffffffffffffffffffff1690631254414090602401602060405180830381865afa1580156132ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133109190614e03565b8d6060015161ffff1661332391906150c3565b945050505060006133348b86613d47565b60008d815260046020526040902054909150610100900460ff16156133995760008c81526023602090815260409182902082518084018452905463ffffffff811680835264010000000090910462ffffff908116928401928352928501525116908201525b60006134038c6040518061012001604052808d63ffffffff1681526020018681526020018781526020018c81526020018b81526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff16815260200185815260200160001515815250613ec3565b6020810151815191925061341691614e1c565b9d9c50505050505050505050505050565b6060600083600181111561343d5761343d6146b9565b03613506576000848152600760205260409081902090517f6e04ff0d000000000000000000000000000000000000000000000000000000009161348291602401615199565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050613600565b600183600181111561351a5761351a6146b9565b03613100576000828060200190518101906135359190615212565b6000868152600760205260409081902090519192507f40691db4000000000000000000000000000000000000000000000000000000009161357a918491602401615322565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915291506136009050565b9392505050565b60175473ffffffffffffffffffffffffffffffffffffffff163314612c0a576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612c18838361420a565b60006bffffffffffffffffffffffff821115613702576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610bab565b5090565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526137649085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612d93565b50505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156137c7576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061383c9085906024016153ed565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d169061390f9087908790600401615400565b60408051808303816000875af115801561392d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139519190615419565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612c0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610bab565b3373ffffffffffffffffffffffffffffffffffffffff821603613a85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610bab565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818152600183016020526040812054613b4257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612c1b565b506000612c1b565b6000613bac826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166142fd9092919063ffffffff16565b805190915015612e155780806020019051810190613bca9190614de8565b612e15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610bab565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cea919061505a565b50935050925050600082131580613d0057508042105b80613d3057506000846040015162ffffff16118015613d305750613d248142614b23565b846040015162ffffff16105b15613d40575050601b5492915050565b5092915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa158015613e34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e58919061505a565b50935050925050600082131580613e6e57508042105b80613e9e57506000866040015162ffffff16118015613e9e5750613e928142614b23565b866040015162ffffff16105b15613eb25760018301546060850152613eba565b606084018290525b50505092915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff168460600151613f2e91906150c3565b90508361010001518015613f415750803a105b15613f4957503a5b600060128311613f5a576001613f70565b613f65601284614b23565b613f7090600a615565565b9050600060128410613f83576001613f99565b613f8e846012614b23565b613f9990600a615565565b905060008660a00151876040015188602001518960000151613fbb9190614e41565b613fc590876150c3565b613fcf9190614e41565b613fd991906150c3565b9050614035828860e0015160600151613ff291906150c3565b6001848a60e001516060015161400891906150c3565b6140129190614b23565b61401c86856150c3565b6140269190614e41565b6140309190615571565b613664565b6bffffffffffffffffffffffff1686526080870151614058906140309083615571565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906140919062ffffff16683635c9adc5dea000006150c3565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b6140c491906150c3565b6140ce9190614e41565b6140d891906150c3565b6140e291906150c3565b6140ec9190615571565b6140f69190614e41565b9050614139848a60e001516060015161410f91906150c3565b6001868c60e001516060015161412591906150c3565b61412f9190614b23565b61401c88856150c3565b6bffffffffffffffffffffffff166020890152608089015161415f906140309083615571565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a01919091528901516141a290613664565b6bffffffffffffffffffffffff1660a0808a01919091528901516141c590613664565b6bffffffffffffffffffffffff1660c089015260e0890151606001516141ea90613664565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b600081815260018301602052604081205480156142f357600061422e600183614b23565b855490915060009061424290600190614b23565b90508181146142a757600086600001828154811061426257614262614fd9565b906000526020600020015490508087600001848154811061428557614285614fd9565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806142b8576142b86155ac565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612c1b565b6000915050612c1b565b6060612ebd8484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516143319190614ad8565b60006040518083038185875af1925050503d806000811461436e576040519150601f19603f3d011682016040523d82523d6000602084013e614373565b606091505b50915091506143848783838761438f565b979650505050505050565b6060831561442557825160000361441e5773ffffffffffffffffffffffffffffffffffffffff85163b61441e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610bab565b5081612ebd565b612ebd838381511561443a5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bab91906153ed565b73ffffffffffffffffffffffffffffffffffffffff81168114612aa757600080fd5b600080604083850312156144a357600080fd5b8235915060208301356144b58161446e565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715614513576145136144c0565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614560576145606144c0565b604052919050565b600067ffffffffffffffff821115614582576145826144c0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126145bf57600080fd5b81356145d26145cd82614568565b614519565b8181528460208386010111156145e757600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561461757600080fd5b82359150602083013567ffffffffffffffff81111561463557600080fd5b614641858286016145ae565b9150509250929050565b60005b8381101561466657818101518382015260200161464e565b50506000910152565b6000815180845261468781602086016020860161464b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a811061471f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b841515815260806020820152600061473e608083018661466f565b905061474d60408301856146e8565b82606083015295945050505050565b60008083601f84011261476e57600080fd5b50813567ffffffffffffffff81111561478657600080fd5b60208301915083602082850101111561479e57600080fd5b9250929050565b6000806000604084860312156147ba57600080fd5b83359250602084013567ffffffffffffffff8111156147d857600080fd5b6147e48682870161475c565b9497909650939450505050565b60006020828403121561480357600080fd5b5035919050565b6000806040838503121561481d57600080fd5b82356148288161446e565b946020939093013593505050565b60008060006060848603121561484b57600080fd5b83356148568161446e565b925060208401356148668161446e565b929592945050506040919091013590565b871515815260e06020820152600061489260e083018961466f565b90506148a160408301886146e8565b8560608301528460808301528360a08301528260c083015298975050505050505050565b600080604083850312156148d857600080fd5b8235915060208301356bffffffffffffffffffffffff811681146144b557600080fd5b63ffffffff81168114612aa757600080fd5b6000806040838503121561492057600080fd5b8235915060208301356144b5816148fb565b600080828403606081121561494657600080fd5b8335925060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201121561497a57600080fd5b506020830190509250929050565b600067ffffffffffffffff8211156149a2576149a26144c0565b5060051b60200190565b600080600080606085870312156149c257600080fd5b8435935060208086013567ffffffffffffffff808211156149e257600080fd5b818801915088601f8301126149f657600080fd5b8135614a046145cd82614988565b81815260059190911b8301840190848101908b831115614a2357600080fd5b8585015b83811015614a5b57803585811115614a3f5760008081fd5b614a4d8e89838a01016145ae565b845250918601918601614a27565b50975050506040880135925080831115614a7457600080fd5b5050614a828782880161475c565b95989497509550505050565b600060208284031215614aa057600080fd5b81356136008161446e565b8051614ab68161446e565b919050565b600060208284031215614acd57600080fd5b81516136008161446e565b60008251614aea81846020870161464b565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115612c1b57612c1b614af4565b80518015158114614ab657600080fd5b600082601f830112614b5757600080fd5b8151614b656145cd82614568565b818152846020838601011115614b7a57600080fd5b612ebd82602083016020870161464b565b60008060408385031215614b9e57600080fd5b614ba783614b36565b9150602083015167ffffffffffffffff811115614bc357600080fd5b61464185828601614b46565b600181811c90821680614be357607f821691505b602082108103614c1c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115612e1557600081815260208120601f850160051c81016020861015614c495750805b601f850160051c820191505b81811015614c6857828155600101614c55565b505050505050565b67ffffffffffffffff831115614c8857614c886144c0565b614c9c83614c968354614bcf565b83614c22565b6000601f841160018114614cee5760008515614cb85750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614d84565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614d3d5786850135825560209485019460019092019101614d1d565b5086821015614d78577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612ebd602083018486614d8b565b600060208284031215614dfa57600080fd5b612c1882614b36565b600060208284031215614e1557600080fd5b5051919050565b6bffffffffffffffffffffffff818116838216019080821115613d4057613d40614af4565b80820180821115612c1b57612c1b614af4565b62ffffff81168114612aa757600080fd5b8135614e70816148fb565b63ffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082161783556020840135614eb081614e54565b66ffffff000000008160201b16837fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008416171784555050505050565b604081018235614efb816148fb565b63ffffffff1682526020830135614f1181614e54565b62ffffff811660208401525092915050565b6000604082016040835280865180835260608501915060608160051b8601019250602080890160005b83811015614f98577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552614f8686835161466f565b95509382019390820190600101614f4c565b505085840381870152505050614faf818587614d8b565b9695505050505050565b8181036000831280158383131683831282161715613d4057613d40614af4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361503957615039614af4565b5060010190565b805169ffffffffffffffffffff81168114614ab657600080fd5b600080600080600060a0868803121561507257600080fd5b61507b86615040565b945060208601519350604086015192506060860151915061509e60808701615040565b90509295509295909350565b60ff8181168382160190811115612c1b57612c1b614af4565b8082028115828204841417612c1b57612c1b614af4565b600080604083850312156150ed57600080fd5b505080516020909101519092909150565b6000815461510b81614bcf565b80855260206001838116801561512857600181146151605761518e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061518e565b866000528260002060005b858110156151865781548a820186015290830190840161516b565b890184019650505b505050505092915050565b602081526000612c1860208301846150fe565b600082601f8301126151bd57600080fd5b815160206151cd6145cd83614988565b82815260059290921b840181019181810190868411156151ec57600080fd5b8286015b8481101561520757805183529183019183016151f0565b509695505050505050565b60006020828403121561522457600080fd5b815167ffffffffffffffff8082111561523c57600080fd5b90830190610100828603121561525157600080fd5b6152596144ef565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015261529160a08401614aab565b60a082015260c0830151828111156152a857600080fd5b6152b4878286016151ac565b60c08301525060e0830151828111156152cc57600080fd5b6152d887828601614b46565b60e08301525095945050505050565b600081518084526020808501945080840160005b83811015615317578151875295820195908201906001016152fb565b509495945050505050565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c08401516101008081850152506153936101408401826152e7565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101208501526153cf828261466f565b91505082810360208401526153e481856150fe565b95945050505050565b602081526000612c18602083018461466f565b828152604060208201526000612ebd604083018461466f565b6000806040838503121561542c57600080fd5b61543583614b36565b9150602083015190509250929050565b600181815b8085111561549e57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561548457615484614af4565b8085161561549157918102915b93841c939080029061544a565b509250929050565b6000826154b557506001612c1b565b816154c257506000612c1b565b81600181146154d857600281146154e2576154fe565b6001915050612c1b565b60ff8411156154f3576154f3614af4565b50506001821b612c1b565b5060208310610133831016604e8410600b8410161715615521575081810a612c1b565b61552b8383615445565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561555d5761555d614af4565b029392505050565b6000612c1883836154a6565b6000826155a7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a",
+ Bin: "0x6101806040523480156200001257600080fd5b5060405162005d2238038062005d2283398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e051610100516101205161014051610160516155e86200073a60003960008181610182015261022f0152600081816120e7015261228d01526000612bb30152600050506000612ee901526000613c5d01526000612fc3015260008181610c4701528181610d0801528181610dd30152612c7401526155e86000f3fe6080604052600436106101805760003560e01c80638765ecbe116100d6578063aed2e9291161007f578063ce7dc5b411610059578063ce7dc5b4146104b1578063f2fde38b146104d1578063f7d334ba146104f157610180565b8063aed2e9291461043a578063b148ab6b14610471578063cd7f71b51461049157610180565b8063948108f7116100b0578063948108f7146103e7578063a72aa27e146103fa578063a86e17811461041a57610180565b80638765ecbe1461037c5780638da5cb5b1461039c5780638dcf0fe7146103c757610180565b806354b7faae1161013857806371fae17f1161011257806371fae17f14610327578063744bfe611461034757806379ba50971461036757610180565b806354b7faae146102b457806368d369d8146102d457806371791aa0146102f457610180565b8063349e8cca11610169578063349e8cca146102205780634ee88d35146102745780635165f2f51461029457610180565b80631a2af011146101c757806329c5efad146101e7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156101c0573d6000f35b3d6000fd5b005b3480156101d357600080fd5b506101c56101e2366004614490565b610511565b3480156101f357600080fd5b50610207610202366004614604565b610617565b6040516102179493929190614723565b60405180910390f35b34801561022c57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610217565b34801561028057600080fd5b506101c561028f3660046147a5565b6108f5565b3480156102a057600080fd5b506101c56102af3660046147f1565b610957565b3480156102c057600080fd5b506101c56102cf36600461480a565b610b09565b3480156102e057600080fd5b506101c56102ef366004614836565b610d7c565b34801561030057600080fd5b5061031461030f366004614604565b61102a565b6040516102179796959493929190614877565b34801561033357600080fd5b506101c56103423660046147f1565b61178e565b34801561035357600080fd5b506101c5610362366004614490565b611824565b34801561037357600080fd5b506101c5611c9c565b34801561038857600080fd5b506101c56103973660046147f1565b611d99565b3480156103a857600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661024f565b3480156103d357600080fd5b506101c56103e23660046147a5565b611f4e565b6101c56103f53660046148c5565b611fa3565b34801561040657600080fd5b506101c561041536600461490d565b612365565b34801561042657600080fd5b506101c5610435366004614932565b612464565b34801561044657600080fd5b5061045a6104553660046147a5565b612545565b604080519215158352602083019190915201610217565b34801561047d57600080fd5b506101c561048c3660046147f1565b6126f0565b34801561049d57600080fd5b506101c56104ac3660046147a5565b61291d565b3480156104bd57600080fd5b506102076104cc3660046149ac565b6129d4565b3480156104dd57600080fd5b506101c56104ec366004614a8e565b612a96565b3480156104fd57600080fd5b5061031461050c3660046147f1565b612aaa565b61051a82612ae6565b3373ffffffffffffffffffffffffffffffffffffffff821603610569576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116146106135760008281526006602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b5050565b60006060600080610626612b9b565b600086815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff620100008204811695830195909552660100000000000081048516606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490941660e0820152600290910154909216908201525a9150600080826080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561077c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a09190614abb565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16896040516107e09190614ad8565b60006040518083038160008787f1925050503d806000811461081e576040519150601f19603f3d011682016040523d82523d6000602084013e610823565b606091505b50915091505a6108339085614b23565b93508161085c5760006040518060200160405280600081525060079650965096505050506108ec565b808060200190518101906108709190614b8b565b90975095508661089c5760006040518060200160405280600081525060049650965096505050506108ec565b60185486517401000000000000000000000000000000000000000090910463ffffffff1610156108e85760006040518060200160405280600081525060059650965096505050506108ec565b5050505b92959194509250565b6108fe83612ae6565b6000838152601d60205260409020610917828483614c70565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664838360405161094a929190614dd4565b60405180910390a2505050565b61096081612ae6565b600081815260046020908152604091829020825161012081018452815460ff808216151580845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152610a9a576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055610ad9600283612c0c565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b610b11612c21565b73ffffffffffffffffffffffffffffffffffffffff8216610b5e576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610b68612c72565b90506000811215610bb4576040517fcf47918100000000000000000000000000000000000000000000000000000000815260006004820152602481018390526044015b60405180910390fd5b80821115610bf8576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610bab565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490526000917f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610c92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb69190614de8565b905080610cef576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa885604051610d6e91815260200190565b60405180910390a350505050565b610d84612c21565b73ffffffffffffffffffffffffffffffffffffffff8216610dd1576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e56576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e60612c72565b128015610e835750600060255460ff166001811115610e8157610e816146b9565b145b15610eba576040517f981bb6a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015610f36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5a9190614e03565b610f649190614b23565b905080821115610faa576040517fcf4791810000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610bab565b610fcb73ffffffffffffffffffffffffffffffffffffffff85168484612d41565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f5e110f8bc8a20b65dcc87f224bdf1cc039346e267118bae2739847f07321ffa884604051610d6e91815260200190565b60006060600080600080600061103e612b9b565b60006110498a612e1a565b905060006014604051806101200160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900462ffffff1662ffffff1662ffffff1681526020016000820160139054906101000a900461ffff1661ffff1661ffff1681526020016000820160159054906101000a900460ff1660ff1660ff1681526020016000820160169054906101000a900460ff161515151581526020016000820160179054906101000a900460ff161515151581526020016000820160189054906101000a900460ff161515151581526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000600460008d8152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff1681526020016001820160109054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201601c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505090506000808360a001511561140c5750506040805160208101825260008082529290910151919a5098506009975089965063ffffffff169450859350839250611782915050565b606083015163ffffffff908116146114565750506040805160208101825260008082529290910151919a5098506001975089965063ffffffff169450859350839250611782915050565b8251156114955750506040805160208101825260008082529290910151919a5098506002975089965063ffffffff169450859350839250611782915050565b61149e84612ec5565b8094508198508299505050506114c38e858786604001518b8b888a61010001516130b7565b9050806bffffffffffffffffffffffff168360c001516bffffffffffffffffffffffff1610156115255750506040805160208101825260008082529290910151919a5098506006975089965063ffffffff169450859350839250611782915050565b505060006115348d858e613427565b90505a9750600080836080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561158b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115af9190614abb565b73ffffffffffffffffffffffffffffffffffffffff16601660000160149054906101000a900463ffffffff1663ffffffff16846040516115ef9190614ad8565b60006040518083038160008787f1925050503d806000811461162d576040519150601f19603f3d011682016040523d82523d6000602084013e611632565b606091505b50915091505a611642908b614b23565b9950816116c8576018548151780100000000000000000000000000000000000000000000000090910463ffffffff1610156116a75750506040805160208101825260008082529390910151929b509950600898505063ffffffff169450611782915050565b604090930151929a50600399505063ffffffff909116955061178292505050565b808060200190518101906116dc9190614b8b565b909d509b508c6117165750506040805160208101825260008082529390910151929b509950600498505063ffffffff169450611782915050565b6018548c517401000000000000000000000000000000000000000090910463ffffffff1610156117705750506040805160208101825260008082529390910151929b509950600598505063ffffffff169450611782915050565b5050506040015163ffffffff16945050505b92959891949750929550565b611796613607565b600081815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055602390915280822080547fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000001690555182917f97d0ef3f46a56168af653f547bdb6f77ec2b1d7d9bc6ba0193c2b340ec68064a91a250565b60145477010000000000000000000000000000000000000000000000900460ff161561187c576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000017905573ffffffffffffffffffffffffffffffffffffffff811661190b576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615158387015263ffffffff620100008304811684870152660100000000000083048116606085015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009093048316608085015260018501546fffffffffffffffffffffffffffffffff811660a08601526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08601527c010000000000000000000000000000000000000000000000000000000090041660e084015260029093015481169282019290925286855260059093529220549091163314611a4b576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601554604080517f57e871e7000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff909216916357e871e7916004808201926020929091908290030181865afa158015611abb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adf9190614e03565b816060015163ffffffff161115611b22576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526004602090815260408083206001015461010085015173ffffffffffffffffffffffffffffffffffffffff1684526021909252909120547001000000000000000000000000000000009091046bffffffffffffffffffffffff1690611b8d908290614b23565b6101008301805173ffffffffffffffffffffffffffffffffffffffff908116600090815260216020908152604080832095909555888252600490529290922060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff16905551611c109116846bffffffffffffffffffffffff8416612d41565b604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8516602082015285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a25050601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff1690555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610bab565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611da281612ae6565b600081815260046020908152604091829020825161012081018452815460ff808216158015845261010080840490921615159584019590955262010000820463ffffffff9081169684019690965266010000000000008204861660608401526a010000000000000000000090910473ffffffffffffffffffffffffffffffffffffffff908116608084015260018401546fffffffffffffffffffffffffffffffff811660a085015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08501527c0100000000000000000000000000000000000000000000000000000000900490951660e083015260029092015490931690830152611edc576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611f1e600283613658565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b611f5783612ae6565b6000838152601e60205260409020611f70828483614c70565b50827f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850838360405161094a929190614dd4565b600082815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e084015260029093015416928101929092529091146120df576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b341561217b577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681610100015173ffffffffffffffffffffffffffffffffffffffff161461216f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61217834613664565b91505b818160c0015161218b9190614e1c565b600084815260046020908152604080832060010180547fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff167001000000000000000000000000000000006bffffffffffffffffffffffff9687160217905561010085015173ffffffffffffffffffffffffffffffffffffffff168352602190915290205461221b91841690614e41565b61010082015173ffffffffffffffffffffffffffffffffffffffff1660009081526021602052604081209190915534900361228b576101008101516122869073ffffffffffffffffffffffffffffffffffffffff1633306bffffffffffffffffffffffff8616613706565b61231b565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836bffffffffffffffffffffffff166040518263ffffffff1660e01b81526004016000604051808303818588803b15801561230157600080fd5b505af1158015612315573d6000803e3d6000fd5b50505050505b6040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6108fc8163ffffffff1610806123a2575060165463ffffffff78010000000000000000000000000000000000000000000000009091048116908216115b156123d9576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6123e282612ae6565b60008281526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffff166201000063ffffffff861690810291909117909155915191825283917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c91015b60405180910390a25050565b61246c613607565b6000828152600460205260409020546601000000000000900463ffffffff908116146124c4576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556023909152902081906125128282614e65565b905050817fd8a6d79d170a55968079d3a89b960d86b4442aef6aac1d01e644c32b9e38b340826040516124589190614eec565b600080612550612b9b565b601454760100000000000000000000000000000000000000000000900460ff16156125a7576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615158386015262010000820463ffffffff90811684880181905266010000000000008404821660608601526a010000000000000000000090930473ffffffffffffffffffffffffffffffffffffffff9081166080860181905260018701546fffffffffffffffffffffffffffffffff811660a088015270010000000000000000000000000000000081046bffffffffffffffffffffffff1660c08801527c0100000000000000000000000000000000000000000000000000000000900490921660e0860152600290950154909416908301528451601f890185900485028101850190955287855290936126e393899089908190840183828082843760009201919091525061376a92505050565b9097909650945050505050565b600081815260046020908152604091829020825161012081018452815460ff8082161515835261010080830490911615159483019490945263ffffffff6201000082048116958301959095526601000000000000810485166060830181905273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009092048216608084015260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c01000000000000000000000000000000000000000000000000000000009004861660e0840152600290930154169281019290925290911461282c576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612889576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602090815260408083208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821790935560069094528285208054909216909155905173ffffffffffffffffffffffffffffffffffffffff90911692839186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b61292683612ae6565b6017547c0100000000000000000000000000000000000000000000000000000000900463ffffffff16811115612988576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526007602052604090206129a1828483614c70565b50827fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d838360405161094a929190614dd4565b600060606000806000634b56a42e60e01b8888886040516024016129fa93929190614f23565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050612a838982610617565b929c919b50995090975095505050505050565b612a9e613985565b612aa781613a06565b50565b600060606000806000806000612acf886040518060200160405280600081525061102a565b959e949d50929b5090995097509550909350915050565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314612b43576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020546601000000000000900463ffffffff90811614612aa7576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612c0a576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6000612c188383613afb565b90505b92915050565b60185473ffffffffffffffffffffffffffffffffffffffff163314612c0a576040517fb6dfb7a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015612d0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d329190614e03565b612d3c9190614fb9565b905090565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052612e159084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613b4a565b505050565b6000818160045b600f811015612ea7577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612e5f57612e5f614fd9565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612e9557506000949350505050565b80612e9f81615008565b915050612e21565b5081600f1a6001811115612ebd57612ebd6146b9565b949350505050565b600080600080846040015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612f52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f76919061505a565b5094509092505050600081131580612f8d57508142105b80612fae5750828015612fae5750612fa58242614b23565b8463ffffffff16105b15612fbd576019549650612fc1565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561302c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613050919061505a565b509450909250505060008113158061306757508142105b806130885750828015613088575061307f8242614b23565b8463ffffffff16105b1561309757601a54955061309b565b8095505b86866130a68a613c56565b965096509650505050509193909250565b60008080808960018111156130ce576130ce6146b9565b036130dd575062017f98613132565b60018960018111156130f1576130f16146b9565b0361310057506201e26c613132565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008a60800151600161314591906150aa565b6131539060ff1660406150c3565b601854613181906103a49074010000000000000000000000000000000000000000900463ffffffff16614e41565b61318b9190614e41565b601554604080517fde9ee35e0000000000000000000000000000000000000000000000000000000081528151939450600093849373ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa1580156131fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322091906150da565b90925090508183613232836018614e41565b61323c91906150c3565b60808f015161324c9060016150aa565b61325b9060ff166115e06150c3565b6132659190614e41565b61326f9190614e41565b6132799085614e41565b6101008e01516040517f125441400000000000000000000000000000000000000000000000000000000081526004810186905291955073ffffffffffffffffffffffffffffffffffffffff1690631254414090602401602060405180830381865afa1580156132ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133109190614e03565b8d6060015161ffff1661332391906150c3565b945050505060006133348b86613d47565b60008d815260046020526040902054909150610100900460ff16156133995760008c81526023602090815260409182902082518084018452905463ffffffff811680835264010000000090910462ffffff908116928401928352928501525116908201525b60006134038c6040518061012001604052808d63ffffffff1681526020018681526020018781526020018c81526020018b81526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff16815260200185815260200160001515815250613ec3565b6020810151815191925061341691614e1c565b9d9c50505050505050505050505050565b6060600083600181111561343d5761343d6146b9565b03613506576000848152600760205260409081902090517f6e04ff0d000000000000000000000000000000000000000000000000000000009161348291602401615199565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050613600565b600183600181111561351a5761351a6146b9565b03613100576000828060200190518101906135359190615212565b6000868152600760205260409081902090519192507f40691db4000000000000000000000000000000000000000000000000000000009161357a918491602401615322565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915291506136009050565b9392505050565b60175473ffffffffffffffffffffffffffffffffffffffff163314612c0a576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612c18838361420a565b60006bffffffffffffffffffffffff821115613702576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610bab565b5090565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526137649085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612d93565b50505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156137c7576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b000000000000000000000000000000000000000000000000000000009061383c9085906024016153ed565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d169061390f9087908790600401615400565b60408051808303816000875af115801561392d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139519190615419565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612c0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610bab565b3373ffffffffffffffffffffffffffffffffffffffff821603613a85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610bab565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818152600183016020526040812054613b4257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612c1b565b506000612c1b565b6000613bac826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166142fd9092919063ffffffff16565b805190915015612e155780806020019051810190613bca9190614de8565b612e15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610bab565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613cc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cea919061505a565b50935050925050600082131580613d0057508042105b80613d3057506000846040015162ffffff16118015613d305750613d248142614b23565b846040015162ffffff16105b15613d40575050601b5492915050565b5092915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa158015613e34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e58919061505a565b50935050925050600082131580613e6e57508042105b80613e9e57506000866040015162ffffff16118015613e9e5750613e928142614b23565b866040015162ffffff16105b15613eb25760018301546060850152613eba565b606084018290525b50505092915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff168460600151613f2e91906150c3565b90508361010001518015613f415750803a105b15613f4957503a5b600060128311613f5a576001613f70565b613f65601284614b23565b613f7090600a615565565b9050600060128410613f83576001613f99565b613f8e846012614b23565b613f9990600a615565565b905060008660a00151876040015188602001518960000151613fbb9190614e41565b613fc590876150c3565b613fcf9190614e41565b613fd991906150c3565b9050614035828860e0015160600151613ff291906150c3565b6001848a60e001516060015161400891906150c3565b6140129190614b23565b61401c86856150c3565b6140269190614e41565b6140309190615571565b613664565b6bffffffffffffffffffffffff1686526080870151614058906140309083615571565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906140919062ffffff16683635c9adc5dea000006150c3565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b6140c491906150c3565b6140ce9190614e41565b6140d891906150c3565b6140e291906150c3565b6140ec9190615571565b6140f69190614e41565b9050614139848a60e001516060015161410f91906150c3565b6001868c60e001516060015161412591906150c3565b61412f9190614b23565b61401c88856150c3565b6bffffffffffffffffffffffff166020890152608089015161415f906140309083615571565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a01919091528901516141a290613664565b6bffffffffffffffffffffffff1660a0808a01919091528901516141c590613664565b6bffffffffffffffffffffffff1660c089015260e0890151606001516141ea90613664565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b600081815260018301602052604081205480156142f357600061422e600183614b23565b855490915060009061424290600190614b23565b90508181146142a757600086600001828154811061426257614262614fd9565b906000526020600020015490508087600001848154811061428557614285614fd9565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806142b8576142b86155ac565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612c1b565b6000915050612c1b565b6060612ebd8484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516143319190614ad8565b60006040518083038185875af1925050503d806000811461436e576040519150601f19603f3d011682016040523d82523d6000602084013e614373565b606091505b50915091506143848783838761438f565b979650505050505050565b6060831561442557825160000361441e5773ffffffffffffffffffffffffffffffffffffffff85163b61441e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610bab565b5081612ebd565b612ebd838381511561443a5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bab91906153ed565b73ffffffffffffffffffffffffffffffffffffffff81168114612aa757600080fd5b600080604083850312156144a357600080fd5b8235915060208301356144b58161446e565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715614513576145136144c0565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614560576145606144c0565b604052919050565b600067ffffffffffffffff821115614582576145826144c0565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f8301126145bf57600080fd5b81356145d26145cd82614568565b614519565b8181528460208386010111156145e757600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561461757600080fd5b82359150602083013567ffffffffffffffff81111561463557600080fd5b614641858286016145ae565b9150509250929050565b60005b8381101561466657818101518382015260200161464e565b50506000910152565b6000815180845261468781602086016020860161464b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a811061471f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b841515815260806020820152600061473e608083018661466f565b905061474d60408301856146e8565b82606083015295945050505050565b60008083601f84011261476e57600080fd5b50813567ffffffffffffffff81111561478657600080fd5b60208301915083602082850101111561479e57600080fd5b9250929050565b6000806000604084860312156147ba57600080fd5b83359250602084013567ffffffffffffffff8111156147d857600080fd5b6147e48682870161475c565b9497909650939450505050565b60006020828403121561480357600080fd5b5035919050565b6000806040838503121561481d57600080fd5b82356148288161446e565b946020939093013593505050565b60008060006060848603121561484b57600080fd5b83356148568161446e565b925060208401356148668161446e565b929592945050506040919091013590565b871515815260e06020820152600061489260e083018961466f565b90506148a160408301886146e8565b8560608301528460808301528360a08301528260c083015298975050505050505050565b600080604083850312156148d857600080fd5b8235915060208301356bffffffffffffffffffffffff811681146144b557600080fd5b63ffffffff81168114612aa757600080fd5b6000806040838503121561492057600080fd5b8235915060208301356144b5816148fb565b600080828403606081121561494657600080fd5b8335925060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201121561497a57600080fd5b506020830190509250929050565b600067ffffffffffffffff8211156149a2576149a26144c0565b5060051b60200190565b600080600080606085870312156149c257600080fd5b8435935060208086013567ffffffffffffffff808211156149e257600080fd5b818801915088601f8301126149f657600080fd5b8135614a046145cd82614988565b81815260059190911b8301840190848101908b831115614a2357600080fd5b8585015b83811015614a5b57803585811115614a3f5760008081fd5b614a4d8e89838a01016145ae565b845250918601918601614a27565b50975050506040880135925080831115614a7457600080fd5b5050614a828782880161475c565b95989497509550505050565b600060208284031215614aa057600080fd5b81356136008161446e565b8051614ab68161446e565b919050565b600060208284031215614acd57600080fd5b81516136008161446e565b60008251614aea81846020870161464b565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115612c1b57612c1b614af4565b80518015158114614ab657600080fd5b600082601f830112614b5757600080fd5b8151614b656145cd82614568565b818152846020838601011115614b7a57600080fd5b612ebd82602083016020870161464b565b60008060408385031215614b9e57600080fd5b614ba783614b36565b9150602083015167ffffffffffffffff811115614bc357600080fd5b61464185828601614b46565b600181811c90821680614be357607f821691505b602082108103614c1c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115612e1557600081815260208120601f850160051c81016020861015614c495750805b601f850160051c820191505b81811015614c6857828155600101614c55565b505050505050565b67ffffffffffffffff831115614c8857614c886144c0565b614c9c83614c968354614bcf565b83614c22565b6000601f841160018114614cee5760008515614cb85750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614d84565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614d3d5786850135825560209485019460019092019101614d1d565b5086821015614d78577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000612ebd602083018486614d8b565b600060208284031215614dfa57600080fd5b612c1882614b36565b600060208284031215614e1557600080fd5b5051919050565b6bffffffffffffffffffffffff818116838216019080821115613d4057613d40614af4565b80820180821115612c1b57612c1b614af4565b62ffffff81168114612aa757600080fd5b8135614e70816148fb565b63ffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000082161783556020840135614eb081614e54565b66ffffff000000008160201b16837fffffffffffffffffffffffffffffffffffffffffffffffffff000000000000008416171784555050505050565b604081018235614efb816148fb565b63ffffffff1682526020830135614f1181614e54565b62ffffff811660208401525092915050565b6000604082016040835280865180835260608501915060608160051b8601019250602080890160005b83811015614f98577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018552614f8686835161466f565b95509382019390820190600101614f4c565b505085840381870152505050614faf818587614d8b565b9695505050505050565b8181036000831280158383131683831282161715613d4057613d40614af4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361503957615039614af4565b5060010190565b805169ffffffffffffffffffff81168114614ab657600080fd5b600080600080600060a0868803121561507257600080fd5b61507b86615040565b945060208601519350604086015192506060860151915061509e60808701615040565b90509295509295909350565b60ff8181168382160190811115612c1b57612c1b614af4565b8082028115828204841417612c1b57612c1b614af4565b600080604083850312156150ed57600080fd5b505080516020909101519092909150565b6000815461510b81614bcf565b80855260206001838116801561512857600181146151605761518e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955061518e565b866000528260002060005b858110156151865781548a820186015290830190840161516b565b890184019650505b505050505092915050565b602081526000612c1860208301846150fe565b600082601f8301126151bd57600080fd5b815160206151cd6145cd83614988565b82815260059290921b840181019181810190868411156151ec57600080fd5b8286015b8481101561520757805183529183019183016151f0565b509695505050505050565b60006020828403121561522457600080fd5b815167ffffffffffffffff8082111561523c57600080fd5b90830190610100828603121561525157600080fd5b6152596144ef565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015261529160a08401614aab565b60a082015260c0830151828111156152a857600080fd5b6152b4878286016151ac565b60c08301525060e0830151828111156152cc57600080fd5b6152d887828601614b46565b60e08301525095945050505050565b600081518084526020808501945080840160005b83811015615317578151875295820195908201906001016152fb565b509495945050505050565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c08401516101008081850152506153936101408401826152e7565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101208501526153cf828261466f565b91505082810360208401526153e481856150fe565b95945050505050565b602081526000612c18602083018461466f565b828152604060208201526000612ebd604083018461466f565b6000806040838503121561542c57600080fd5b61543583614b36565b9150602083015190509250929050565b600181815b8085111561549e57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561548457615484614af4565b8085161561549157918102915b93841c939080029061544a565b509250929050565b6000826154b557506001612c1b565b816154c257506000612c1b565b81600181146154d857600281146154e2576154fe565b6001915050612c1b565b60ff8411156154f3576154f3614af4565b50506001821b612c1b565b5060208310610133831016604e8410600b8410161715615521575081810a612c1b565b61552b8383615445565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561555d5761555d614af4565b029392505050565b6000612c1883836154a6565b6000826155a7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a",
}
var AutomationRegistryLogicBABI = AutomationRegistryLogicBMetaData.ABI
diff --git a/core/gethwrappers/generated/automation_registry_logic_c_wrapper_2_3/automation_registry_logic_c_wrapper_2_3.go b/core/gethwrappers/generated/automation_registry_logic_c_wrapper_2_3/automation_registry_logic_c_wrapper_2_3.go
index e32d6890ddd..d5e6d9d64ff 100644
--- a/core/gethwrappers/generated/automation_registry_logic_c_wrapper_2_3/automation_registry_logic_c_wrapper_2_3.go
+++ b/core/gethwrappers/generated/automation_registry_logic_c_wrapper_2_3/automation_registry_logic_c_wrapper_2_3.go
@@ -151,7 +151,7 @@ type IAutomationV21PlusCommonUpkeepInfoLegacy struct {
var AutomationRegistryLogicCMetaData = &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\"},{\"internalType\":\"enumAutomationRegistryBase2_3.PayoutMode\",\"name\":\"payoutMode\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"wrappedNativeTokenAddress\",\"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\":\"contractIERC20Metadata\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"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\"},{\"components\":[{\"internalType\":\"uint96\",\"name\":\"gasChargeInBillingToken\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"premiumInBillingToken\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"gasReimbursementInJuels\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"premiumInJuels\",\"type\":\"uint96\"},{\"internalType\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"linkUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"billingUSD\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.PaymentReceipt\",\"name\":\"receipt\",\"type\":\"tuple\"}],\"name\":\"UpkeepCharged\",\"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\":[],\"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\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getAvailableERC20ForPayment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"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\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"}],\"name\":\"getBillingConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"fallbackPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"minSpend\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getBillingOverrides\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"}],\"internalType\":\"structAutomationRegistryBase2_3.BillingOverrides\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getBillingOverridesEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"upkeepID\",\"type\":\"uint256\"}],\"name\":\"getBillingToken\",\"outputs\":[{\"internalType\":\"contractIERC20Metadata\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20Metadata\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getBillingTokenConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"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\":\"contractIERC20Metadata[]\",\"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\":\"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\":\"contractIChainModule\",\"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\":\"contractIAutomationForwarder\",\"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\":\"contractIChainModule\",\"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\":\"enumAutomationRegistryBase2_3.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"contractIERC20Metadata\",\"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\":\"enumAutomationRegistryBase2_3.PayoutMode\",\"name\":\"\",\"type\":\"uint8\"}],\"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\":\"contractIERC20Metadata\",\"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\":[],\"name\":\"getTransmittersWithPayees\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"transmitterAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"payeeAddress\",\"type\":\"address\"}],\"internalType\":\"structAutomationRegistryBase2_3.TransmitterPayeeInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"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\":\"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\":\"linkAvailableForPayment\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"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\":\"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\":\"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\":\"contractIERC20Metadata\",\"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\":[],\"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\"}]",
- Bin: "0x6101606040523480156200001257600080fd5b5060405162005c8738038062005c87833981016040819052620000359162000309565b87878787878787873380600081620000945760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c757620000c78162000241565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff191660018381811115620001185762000118620003b6565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000179573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200019f9190620003cc565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002099190620003cc565b60ff16146200022b576040516301f86e1760e41b815260040160405180910390fd5b50505050505050505050505050505050620003f8565b336001600160a01b038216036200029b5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008b565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200030457600080fd5b919050565b600080600080600080600080610100898b0312156200032757600080fd5b6200033289620002ec565b97506200034260208a01620002ec565b96506200035260408a01620002ec565b95506200036260608a01620002ec565b94506200037260808a01620002ec565b93506200038260a08a01620002ec565b925060c0890151600281106200039757600080fd5b9150620003a760e08a01620002ec565b90509295985092959890939650565b634e487b7160e01b600052602160045260246000fd5b600060208284031215620003df57600080fd5b815160ff81168114620003f157600080fd5b9392505050565b60805160a05160c05160e051610100516101205161014051615803620004846000396000610b7001526000610ad2015260006107be0152600081816109a001526135b60152600081816109540152613e3201526000818161051d0152613690015260008181610c1801528181611df00152818161256b015281816125c80152613af601526158036000f3fe608060405234801561001057600080fd5b50600436106103d05760003560e01c80638ed02bab116101ff578063c3f909d41161011a578063eb5dcd6c116100ad578063f5a418461161007c578063f5a4184614610eb4578063f777ff0614610f35578063faa3e99614610f3c578063ffd242bd14610f8257600080fd5b8063eb5dcd6c14610de5578063ec4de4ba14610df8578063ed56b3e114610e2e578063f2fde38b14610ea157600080fd5b8063d09dc339116100e9578063d09dc33914610c3c578063d763264814610c44578063d85aa07c14610c57578063e80a3d4414610c5f57600080fd5b8063c3f909d414610bd6578063c5b964e014610beb578063c7c3a19a14610bf6578063ca30e60314610c1657600080fd5b8063aab9edd611610192578063b3596c2311610161578063b3596c23146107e2578063b6511a2a14610ba7578063b657bc9c14610bae578063ba87666814610bc157600080fd5b8063aab9edd614610b57578063abc76ae014610b66578063ac4dc59a14610b6e578063b121e14714610b9457600080fd5b8063a08714c0116101ce578063a08714c014610ad0578063a538b2eb14610af6578063a710b22114610b3c578063a87f45fe14610b4f57600080fd5b80638ed02bab14610a5c5780639089daa414610a7a57806393f6ebcf14610a8f5780639e0a99ed14610ac857600080fd5b806343cc055c116102ef5780636209e1e91161028257806379ba50971161025157806379ba5097146109ea57806379ea9943146109f25780638456cb5914610a365780638da5cb5b14610a3e57600080fd5b80636209e1e91461098b5780636709d0e51461099e578063671d36ed146109c45780636eec02a2146109d757600080fd5b80635425d8ac116102be5780635425d8ac146107bc57806357359584146107e2578063614486af146109525780636181d82d1461097857600080fd5b806343cc055c1461074957806344cb70b8146107705780634ca16c52146107935780635147cd591461079c57600080fd5b8063207b6516116103675780633b9cce59116103365780633b9cce59146106c05780633f4ba83a146106d3578063421d183b146106db57806343b46e5f1461074157600080fd5b8063207b651614610508578063226cf83c1461051b578063232c1cc5146105625780633408f73a1461056957600080fd5b8063187256e8116103a3578063187256e81461043b57806319d97a941461044e5780631e0104391461046e5780631efcf646146104d057600080fd5b8063050ee65d146103d557806306e3b632146103ed5780630b7d33e61461040d5780631865c57d14610422575b600080fd5b6201de845b6040519081526020015b60405180910390f35b6104006103fb36600461447a565b610f8a565b6040516103e491906144d7565b61042061041b366004614533565b6110a7565b005b61042a611108565b6040516103e495949392919061472b565b61042061044936600461486c565b611508565b61046161045c3660046148a9565b611579565b6040516103e49190614926565b6104b361047c3660046148a9565b60009081526004602052604090206001015470010000000000000000000000000000000090046bffffffffffffffffffffffff1690565b6040516bffffffffffffffffffffffff90911681526020016103e4565b6104f86104de3660046148a9565b600090815260046020526040902054610100900460ff1690565b60405190151581526020016103e4565b6104616105163660046148a9565b61161b565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103e4565b60186103da565b6106b36040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915250604080516101608101825260165473ffffffffffffffffffffffffffffffffffffffff808216835263ffffffff740100000000000000000000000000000000000000008084048216602086015278010000000000000000000000000000000000000000000000008085048316968601969096527c010000000000000000000000000000000000000000000000000000000093849004821660608601526017548084166080870152818104831660a0870152868104831660c087015293909304811660e085015260185491821661010085015291810482166101208401529290920490911661014082015290565b6040516103e49190614939565b6104206106ce366004614a63565b611638565b61042061188e565b6106ee6106e9366004614ad8565b6118f4565b60408051951515865260ff90941660208601526bffffffffffffffffffffffff9283169385019390935216606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a0016103e4565b610420611a13565b6014547801000000000000000000000000000000000000000000000000900460ff166104f8565b6104f861077e3660046148a9565b60009081526008602052604090205460ff1690565b62017f986103da565b6107af6107aa3660046148a9565b611eaa565b6040516103e49190614b34565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6108d46107f0366004614ad8565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091525073ffffffffffffffffffffffffffffffffffffffff908116600090815260226020908152604091829020825160c081018452815463ffffffff81168252640100000000810462ffffff16938201939093526701000000000000008304909416928401929092527b01000000000000000000000000000000000000000000000000000000900460ff16606083015260018101546080830152600201546bffffffffffffffffffffffff1660a082015290565b6040516103e49190600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6104b3610986366004614b47565b611eb5565b610461610999366004614ad8565b612010565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6104206109d2366004614ba7565b612043565b6103da6109e5366004614ad8565b6120c3565b61042061216d565b61053d610a003660046148a9565b6000908152600460205260409020546a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690565b61042061226f565b60005473ffffffffffffffffffffffffffffffffffffffff1661053d565b60155473ffffffffffffffffffffffffffffffffffffffff1661053d565b610a826122e8565b6040516103e49190614be3565b61053d610a9d3660046148a9565b60009081526004602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1690565b6103a46103da565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6104f8610b04366004614ad8565b73ffffffffffffffffffffffffffffffffffffffff908116600090815260226020526040902054670100000000000000900416151590565b610420610b4a366004614c4c565b6123fa565b610420612728565b604051600481526020016103e4565b6115e06103da565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b610420610ba2366004614ad8565b61275a565b60326103da565b6104b3610bbc3660046148a9565b612852565b610bc9612979565b6040516103e49190614c7a565b610bde6129e8565b6040516103e49190614cd4565b60255460ff166107af565b610c09610c043660046148a9565b612bd0565b6040516103e49190614e5b565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6103da612fe0565b6104b3610c523660046148a9565b612fef565b601b546103da565b610dd86040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091525060408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff750100000000000000000000000000000000000000000083048116608083015276010000000000000000000000000000000000000000000083048116151560a08301527701000000000000000000000000000000000000000000000083048116151560c08301527801000000000000000000000000000000000000000000000000909204909116151560e082015260155473ffffffffffffffffffffffffffffffffffffffff1661010082015290565b6040516103e49190614f92565b610420610df3366004614c4c565b612ffa565b6103da610e06366004614ad8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526021602052604090205490565b610e88610e3c366004614ad8565b73ffffffffffffffffffffffffffffffffffffffff166000908152600c602090815260409182902082518084019093525460ff8082161515808552610100909204169290910182905291565b60408051921515835260ff9091166020830152016103e4565b610420610eaf366004614ad8565b613159565b610f0f610ec23660046148a9565b60408051808201909152600080825260208201525060009081526023602090815260409182902082518084019093525463ffffffff81168352640100000000900462ffffff169082015290565b60408051825163ffffffff16815260209283015162ffffff1692810192909252016103e4565b60406103da565b610f75610f4a366004614ad8565b73ffffffffffffffffffffffffffffffffffffffff166000908152601c602052604090205460ff1690565b6040516103e49190615062565b6103da61316d565b60606000610f986002613175565b9050808410610fd3576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610fdf84866150a5565b905081811180610fed575083155b610ff75780610ff9565b815b9050600061100786836150b8565b67ffffffffffffffff81111561101f5761101f6150cb565b604051908082528060200260200182016040528015611048578160200160208202803683370190505b50905060005b815181101561109b5761106c61106488836150a5565b60029061317f565b82828151811061107e5761107e6150fa565b60209081029190910101528061109381615129565b91505061104e565b50925050505b92915050565b6110af61318b565b6000838152601f602052604090206110c8828483615203565b50827f2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae776983836040516110fb92919061531e565b60405180910390a2505050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152604080516101e08101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a08201526101c081019190915260408051610140810182526016547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1681526000602082018190529181018290526014546bffffffffffffffffffffffff16606080830191909152918291608081016112416002613175565b81526017547401000000000000000000000000000000000000000080820463ffffffff908116602080860191909152780100000000000000000000000000000000000000000000000080850483166040808801919091526013546060808901919091526014546c01000000000000000000000000810486166080808b0191909152760100000000000000000000000000000000000000000000820460ff16151560a09a8b015283516101e0810185526000808252968101879052601654898104891695820195909552700100000000000000000000000000000000830462ffffff169381019390935273010000000000000000000000000000000000000090910461ffff169082015296870192909252808204831660c08701527c0100000000000000000000000000000000000000000000000000000000909404821660e086015260185492830482166101008601529290910416610120830152601954610140830152601a5461016083015273ffffffffffffffffffffffffffffffffffffffff166101808201529095506101a081016113dc60096131de565b815260175473ffffffffffffffffffffffffffffffffffffffff16602091820152601454600d80546040805182860281018601909152818152949850899489949293600e93750100000000000000000000000000000000000000000090910460ff1692859183018282801561148757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161145c575b50505050509250818054806020026020016040519081016040528092919081815260200182805480156114f057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116114c5575b50505050509150945094509450945094509091929394565b6115106131eb565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601c6020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600381111561157057611570614af5565b02179055505050565b6000818152601f6020526040902080546060919061159690615161565b80601f01602080910402602001604051908101604052809291908181526020018280546115c290615161565b801561160f5780601f106115e45761010080835404028352916020019161160f565b820191906000526020600020905b8154815290600101906020018083116115f257829003601f168201915b50505050509050919050565b6000818152601d6020526040902080546060919061159690615161565b6116406131eb565b600e54811461167b576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b600e5481101561184d576000600e828154811061169d5761169d6150fa565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168084526011909252604083205491935016908585858181106116e7576116e76150fa565b90506020020160208101906116fc9190614ad8565b905073ffffffffffffffffffffffffffffffffffffffff8116158061178f575073ffffffffffffffffffffffffffffffffffffffff82161580159061176d57508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561178f575073ffffffffffffffffffffffffffffffffffffffff81811614155b156117c6576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff818116146118375773ffffffffffffffffffffffffffffffffffffffff838116600090815260116020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b505050808061184590615129565b91505061167e565b507fa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725600e83836040516118829392919061536b565b60405180910390a15050565b6118966131eb565b601480547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015282918291829182919082906119ba5760608201516014546000916119a6916bffffffffffffffffffffffff1661541d565b600e549091506119b69082615471565b9150505b8151602083015160408401516119d190849061549c565b6060949094015173ffffffffffffffffffffffffffffffffffffffff9a8b16600090815260116020526040902054929b919a9499509750921694509092505050565b611a1b61326c565b600060255460ff166001811115611a3457611a34614af5565b03611a6b576040517fe0262d7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601454600e546bffffffffffffffffffffffff909116906000611a8e600f613175565b90506000611a9c82846150a5565b905060008167ffffffffffffffff811115611ab957611ab96150cb565b604051908082528060200260200182016040528015611ae2578160200160208202803683370190505b50905060008267ffffffffffffffff811115611b0057611b006150cb565b604051908082528060200260200182016040528015611b29578160200160208202803683370190505b50905060005b85811015611c5b576000600e8281548110611b4c57611b4c6150fa565b600091825260208220015473ffffffffffffffffffffffffffffffffffffffff169150611b7a828a8a6132bd565b9050806bffffffffffffffffffffffff16858481518110611b9d57611b9d6150fa565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff808416600090815260119092526040909120548551911690859085908110611beb57611beb6150fa565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920181019190915292166000908152600b909252506040902080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff16905580611c5381615129565b915050611b2f565b5060005b84811015611dd8576000611c74600f8361317f565b73ffffffffffffffffffffffffffffffffffffffff8082166000818152600b602090815260408083208151608081018352905460ff80821615158352610100820416828501526bffffffffffffffffffffffff6201000082048116838501526e0100000000000000000000000000009091041660608201529383526011909152902054929350911684611d078a866150a5565b81518110611d1757611d176150fa565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260408101516bffffffffffffffffffffffff1685611d5a8a866150a5565b81518110611d6a57611d6a6150fa565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff9092166000908152600b909252506040902080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff16905580611dd081615129565b915050611c5f565b5073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166000908152602160205260408120819055611e2b600f613175565b90505b8015611e6857611e55611e4d611e456001846150b8565b600f9061317f565b600f906134c5565b5080611e60816154c1565b915050611e2e565b507f5af23b715253628d12b660b27a4f3fc626562ea8a55040aa99ab3dc178989fad8183604051611e9a9291906154f6565b60405180910390a1505050505050565b60006110a1826134e7565b60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff750100000000000000000000000000000000000000000083048116608083015276010000000000000000000000000000000000000000000083048116151560a08301527701000000000000000000000000000000000000000000000083048116151560c08301527801000000000000000000000000000000000000000000000000909204909116151560e082015260155473ffffffffffffffffffffffffffffffffffffffff16610100820152600090818080611fed84613592565b92509250925061200389858a8a8787878d613784565b9998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040902080546060919061159690615161565b61204b61318b565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602080526040902061207a828483615203565b508273ffffffffffffffffffffffffffffffffffffffff167f7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d283836040516110fb92919061531e565b73ffffffffffffffffffffffffffffffffffffffff81166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa15801561213f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121639190615524565b6110a191906150b8565b60015473ffffffffffffffffffffffffffffffffffffffff1633146121f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6122776131eb565b601480547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff167601000000000000000000000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016118ea565b600e5460609060008167ffffffffffffffff811115612309576123096150cb565b60405190808252806020026020018201604052801561234e57816020015b60408051808201909152600080825260208201528152602001906001900390816123275790505b50905060005b828110156123f3576000600e8281548110612371576123716150fa565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168084526011835260409384902054845180860190955281855290911691830182905285519093509091908590859081106123d3576123d36150fa565b6020026020010181905250505080806123eb90615129565b915050612354565b5092915050565b73ffffffffffffffffffffffffffffffffffffffff8116612447576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160255460ff16600181111561246057612460614af5565b03612497576040517f4a3578fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152601160205260409020541633146124f7576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601454600e5460009161251a9185916bffffffffffffffffffffffff16906132bd565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff1690557f000000000000000000000000000000000000000000000000000000000000000090931682526021905220549091506125b1906bffffffffffffffffffffffff8316906150b8565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166000818152602160205260408082209490945592517fa9059cbb00000000000000000000000000000000000000000000000000000000815291851660048301526bffffffffffffffffffffffff841660248301529063a9059cbb906044016020604051808303816000875af1158015612666573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061268a919061553d565b9050806126c3576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405133815273ffffffffffffffffffffffffffffffffffffffff808516916bffffffffffffffffffffffff8516918716907f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f406989060200160405180910390a450505050565b6127306131eb565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b73ffffffffffffffffffffffffffffffffffffffff8181166000908152601260205260409020541633146127ba576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81811660008181526011602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556012909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b6000818152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915261297283612962816134e7565b8360400151846101000151611eb5565b9392505050565b606060248054806020026020016040519081016040528092919081815260200182805480156129de57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116129b3575b5050505050905090565b604080516102008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a082018390526101c08201526101e0810191909152604080516102008101825260165463ffffffff74010000000000000000000000000000000000000000808304821684527801000000000000000000000000000000000000000000000000808404831660208601526017547c0100000000000000000000000000000000000000000000000000000000810484169686019690965273ffffffffffffffffffffffffffffffffffffffff938416606086015260145460ff828204161515608087015262ffffff70010000000000000000000000000000000082041660a0870152601854928304841660c087015290820490921660e085015293821661010084015261ffff7301000000000000000000000000000000000000009091041661012083015291909116610140820152601954610160820152601a54610180820152601b546101a08201526101c08101612baa60096131de565b815260155473ffffffffffffffffffffffffffffffffffffffff16602090910152919050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526000828152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a010000000000000000000090910481166080830181905260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c0100000000000000000000000000000000000000000000000000000000900490941660e08301526002909201549091169281019290925290919015612da557816080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da0919061555f565b612da8565b60005b90506040518061014001604052808273ffffffffffffffffffffffffffffffffffffffff168152602001836040015163ffffffff168152602001600760008781526020019081526020016000208054612e0090615161565b80601f0160208091040260200160405190810160405280929190818152602001828054612e2c90615161565b8015612e795780601f10612e4e57610100808354040283529160200191612e79565b820191906000526020600020905b815481529060010190602001808311612e5c57829003601f168201915b505050505081526020018360c001516bffffffffffffffffffffffff1681526020016005600087815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001836060015163ffffffff1667ffffffffffffffff1681526020018360e0015163ffffffff1681526020018360a001516bffffffffffffffffffffffff168152602001836000015115158152602001601e60008781526020019081526020016000208054612f5690615161565b80601f0160208091040260200160405190810160405280929190818152602001828054612f8290615161565b8015612fcf5780601f10612fa457610100808354040283529160200191612fcf565b820191906000526020600020905b815481529060010190602001808311612fb257829003601f168201915b505050505081525092505050919050565b6000612fea613af4565b905090565b60006110a182612852565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526011602052604090205416331461305a576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff8216036130a9576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152601260205260409020548116908216146131555773ffffffffffffffffffffffffffffffffffffffff82811660008181526012602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45b5050565b6131616131eb565b61316a81613bbe565b50565b6000612fea60025b60006110a1825490565b60006129728383613cb3565b60175473ffffffffffffffffffffffffffffffffffffffff1633146131dc576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6060600061297283613cdd565b60005473ffffffffffffffffffffffffffffffffffffffff1633146131dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016121ea565b60185473ffffffffffffffffffffffffffffffffffffffff1633146131dc576040517fb6dfb7a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152906134b9576000816060015185613355919061541d565b905060006133638583615471565b90508083604001818151613377919061549c565b6bffffffffffffffffffffffff16905250613392858261557c565b836060018181516133a3919061549c565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b60006129728373ffffffffffffffffffffffffffffffffffffffff8416613d38565b6000818160045b600f811015613574577fff00000000000000000000000000000000000000000000000000000000000000821683826020811061352c5761352c6150fa565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461356257506000949350505050565b8061356c81615129565b9150506134ee565b5081600f1a600181111561358a5761358a614af5565b949350505050565b600080600080846040015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561361f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061364391906155c3565b509450909250505060008113158061365a57508142105b8061367b575082801561367b575061367282426150b8565b8463ffffffff16105b1561368a57601954965061368e565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156136f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061371d91906155c3565b509450909250505060008113158061373457508142105b806137555750828015613755575061374c82426150b8565b8463ffffffff16105b1561376457601a549550613768565b8095505b86866137738a613e2b565b965096509650505050509193909250565b600080808089600181111561379b5761379b614af5565b036137aa575062017f986137ff565b60018960018111156137be576137be614af5565b036137cd57506201de846137ff565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008a6080015160016138129190615613565b6138209060ff16604061562c565b60185461384e906103a49074010000000000000000000000000000000000000000900463ffffffff166150a5565b61385891906150a5565b601554604080517fde9ee35e0000000000000000000000000000000000000000000000000000000081528151939450600093849373ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa1580156138c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ed9190615643565b909250905081836138ff8360186150a5565b613909919061562c565b60808f0151613919906001615613565b6139289060ff166115e061562c565b61393291906150a5565b61393c91906150a5565b61394690856150a5565b6101008e01516040517f125441400000000000000000000000000000000000000000000000000000000081526004810186905291955073ffffffffffffffffffffffffffffffffffffffff1690631254414090602401602060405180830381865afa1580156139b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139dd9190615524565b8d6060015161ffff166139f0919061562c565b94505050506000613a018b86613f15565b60008d815260046020526040902054909150610100900460ff1615613a665760008c81526023602090815260409182902082518084018452905463ffffffff811680835264010000000090910462ffffff908116928401928352928501525116908201525b6000613ad08c6040518061012001604052808d63ffffffff1681526020018681526020018781526020018c81526020018b81526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff16815260200185815260200160001515815250614091565b60208101518151919250613ae39161549c565b9d9c50505050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015613b90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb49190615524565b612fea9190615667565b3373ffffffffffffffffffffffffffffffffffffffff821603613c3d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016121ea565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110613cca57613cca6150fa565b9060005260206000200154905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561160f57602002820191906000526020600020905b815481526020019060010190808311613d195750505050509050919050565b60008181526001830160205260408120548015613e21576000613d5c6001836150b8565b8554909150600090613d70906001906150b8565b9050818114613dd5576000866000018281548110613d9057613d906150fa565b9060005260206000200154905080876000018481548110613db357613db36150fa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613de657613de6615687565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506110a1565b60009150506110a1565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ebf91906155c3565b50935050925050600082131580613ed557508042105b80613f0557506000846040015162ffffff16118015613f055750613ef981426150b8565b846040015162ffffff16105b156123f3575050601b5492915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa158015614002573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402691906155c3565b5093505092505060008213158061403c57508042105b8061406c57506000866040015162ffffff1611801561406c575061406081426150b8565b866040015162ffffff16105b156140805760018301546060850152614088565b606084018290525b50505092915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff1684606001516140fc919061562c565b9050836101000151801561410f5750803a105b1561411757503a5b60006012831161412857600161413e565b6141336012846150b8565b61413e90600a6157d6565b9050600060128410614151576001614167565b61415c8460126150b8565b61416790600a6157d6565b905060008660a0015187604001518860200151896000015161418991906150a5565b614193908761562c565b61419d91906150a5565b6141a7919061562c565b9050614203828860e00151606001516141c0919061562c565b6001848a60e00151606001516141d6919061562c565b6141e091906150b8565b6141ea868561562c565b6141f491906150a5565b6141fe91906157e2565b6143d8565b6bffffffffffffffffffffffff1686526080870151614226906141fe90836157e2565b6bffffffffffffffffffffffff1660408088019190915260e0880151015160009061425f9062ffffff16683635c9adc5dea0000061562c565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b614292919061562c565b61429c91906150a5565b6142a6919061562c565b6142b0919061562c565b6142ba91906157e2565b6142c491906150a5565b9050614307848a60e00151606001516142dd919061562c565b6001868c60e00151606001516142f3919061562c565b6142fd91906150b8565b6141ea888561562c565b6bffffffffffffffffffffffff166020890152608089015161432d906141fe90836157e2565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a0191909152890151614370906143d8565b6bffffffffffffffffffffffff1660a0808a0191909152890151614393906143d8565b6bffffffffffffffffffffffff1660c089015260e0890151606001516143b8906143d8565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b60006bffffffffffffffffffffffff821115614476576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016121ea565b5090565b6000806040838503121561448d57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b838110156144cc578151875295820195908201906001016144b0565b509495945050505050565b602081526000612972602083018461449c565b60008083601f8401126144fc57600080fd5b50813567ffffffffffffffff81111561451457600080fd5b60208301915083602082850101111561452c57600080fd5b9250929050565b60008060006040848603121561454857600080fd5b83359250602084013567ffffffffffffffff81111561456657600080fd5b614572868287016144ea565b9497909650939450505050565b600081518084526020808501945080840160005b838110156144cc57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614593565b805163ffffffff16825260006101e060208301516145eb602086018263ffffffff169052565b506040830151614603604086018263ffffffff169052565b50606083015161461a606086018262ffffff169052565b506080830151614630608086018261ffff169052565b5060a083015161465060a08601826bffffffffffffffffffffffff169052565b5060c083015161466860c086018263ffffffff169052565b5060e083015161468060e086018263ffffffff169052565b506101008381015163ffffffff908116918601919091526101208085015190911690850152610140808401519085015261016080840151908501526101808084015173ffffffffffffffffffffffffffffffffffffffff16908501526101a0808401518186018390526146f58387018261457f565b925050506101c0808401516147218287018273ffffffffffffffffffffffffffffffffffffffff169052565b5090949350505050565b855163ffffffff16815260006101c0602088015161475960208501826bffffffffffffffffffffffff169052565b5060408801516040840152606088015161478360608501826bffffffffffffffffffffffff169052565b506080880151608084015260a08801516147a560a085018263ffffffff169052565b5060c08801516147bd60c085018263ffffffff169052565b5060e088015160e0840152610100808901516147e08286018263ffffffff169052565b5050610120888101511515908401526101408301819052614803818401886145c5565b9050828103610160840152614818818761457f565b905082810361018084015261482d818661457f565b9150506148406101a083018460ff169052565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461316a57600080fd5b6000806040838503121561487f57600080fd5b823561488a8161484a565b915060208301356004811061489e57600080fd5b809150509250929050565b6000602082840312156148bb57600080fd5b5035919050565b6000815180845260005b818110156148e8576020818501810151868301820152016148cc565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061297260208301846148c2565b815173ffffffffffffffffffffffffffffffffffffffff1681526101608101602083015161496f602084018263ffffffff169052565b506040830151614987604084018263ffffffff169052565b50606083015161499f606084018263ffffffff169052565b5060808301516149c7608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a08301516149df60a084018263ffffffff169052565b5060c08301516149f760c084018263ffffffff169052565b5060e0830151614a0f60e084018263ffffffff169052565b506101008381015173ffffffffffffffffffffffffffffffffffffffff81168483015250506101208381015163ffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b60008060208385031215614a7657600080fd5b823567ffffffffffffffff80821115614a8e57600080fd5b818501915085601f830112614aa257600080fd5b813581811115614ab157600080fd5b8660208260051b8501011115614ac657600080fd5b60209290920196919550909350505050565b600060208284031215614aea57600080fd5b81356129728161484a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6002811061316a5761316a614af5565b60208101614b4183614b24565b91905290565b60008060008060808587031215614b5d57600080fd5b84359350602085013560028110614b7357600080fd5b9250604085013563ffffffff81168114614b8c57600080fd5b91506060850135614b9c8161484a565b939692955090935050565b600080600060408486031215614bbc57600080fd5b8335614bc78161484a565b9250602084013567ffffffffffffffff81111561456657600080fd5b602080825282518282018190526000919060409081850190868401855b82811015614c3f578151805173ffffffffffffffffffffffffffffffffffffffff90811686529087015116868501529284019290850190600101614c00565b5091979650505050505050565b60008060408385031215614c5f57600080fd5b8235614c6a8161484a565b9150602083013561489e8161484a565b6020808252825182820181905260009190848201906040850190845b81811015614cc857835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614c96565b50909695505050505050565b60208152614ceb60208201835163ffffffff169052565b60006020830151614d04604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e0830151610100614d838185018363ffffffff169052565b8401519050610120614dac8482018373ffffffffffffffffffffffffffffffffffffffff169052565b8401519050610140614dc38482018361ffff169052565b8401519050610160614dec8482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e080860182905291925090614e3461022086018461457f565b9086015173ffffffffffffffffffffffffffffffffffffffff811683870152909250614721565b60208152614e8260208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614e9b604084018263ffffffff169052565b506040830151610140806060850152614eb86101608501836148c2565b91506060850151614ed960808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614f45818701836bffffffffffffffffffffffff169052565b8601519050610120614f5a8682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00183870152905061484083826148c2565b6000610120820190506bffffffffffffffffffffffff835116825263ffffffff60208401511660208301526040830151614fd3604084018262ffffff169052565b506060830151614fe9606084018261ffff169052565b506080830151614ffe608084018260ff169052565b5060a083015161501260a084018215159052565b5060c083015161502660c084018215159052565b5060e083015161503a60e084018215159052565b506101008381015173ffffffffffffffffffffffffffffffffffffffff811684830152614a5b565b6020810160048310614b4157614b41614af5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156110a1576110a1615076565b818103818111156110a1576110a1615076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361515a5761515a615076565b5060010190565b600181811c9082168061517557607f821691505b6020821081036151ae577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156151fe57600081815260208120601f850160051c810160208610156151db5750805b601f850160051c820191505b818110156151fa578281556001016151e7565b5050505b505050565b67ffffffffffffffff83111561521b5761521b6150cb565b61522f836152298354615161565b836151b4565b6000601f841160018114615281576000851561524b5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355615317565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156152d057868501358255602094850194600190920191016152b0565b508682101561530b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156153c257815473ffffffffffffffffffffffffffffffffffffffff1684529284019260019182019101615390565b505050838103828501528481528590820160005b868110156154115782356153e98161484a565b73ffffffffffffffffffffffffffffffffffffffff16825291830191908301906001016153d6565b50979650505050505050565b6bffffffffffffffffffffffff8281168282160390808211156123f3576123f3615076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006bffffffffffffffffffffffff8084168061549057615490615442565b92169190910492915050565b6bffffffffffffffffffffffff8181168382160190808211156123f3576123f3615076565b6000816154d0576154d0615076565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b604081526000615509604083018561457f565b828103602084015261551b818561449c565b95945050505050565b60006020828403121561553657600080fd5b5051919050565b60006020828403121561554f57600080fd5b8151801515811461297257600080fd5b60006020828403121561557157600080fd5b81516129728161484a565b6bffffffffffffffffffffffff818116838216028082169190828114614a5b57614a5b615076565b805169ffffffffffffffffffff811681146155be57600080fd5b919050565b600080600080600060a086880312156155db57600080fd5b6155e4866155a4565b9450602086015193506040860151925060608601519150615607608087016155a4565b90509295509295909350565b60ff81811683821601908111156110a1576110a1615076565b80820281158282048414176110a1576110a1615076565b6000806040838503121561565657600080fd5b505080516020909101519092909150565b81810360008312801583831316838312821617156123f3576123f3615076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600181815b8085111561570f57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156156f5576156f5615076565b8085161561570257918102915b93841c93908002906156bb565b509250929050565b600082615726575060016110a1565b81615733575060006110a1565b816001811461574957600281146157535761576f565b60019150506110a1565b60ff84111561576457615764615076565b50506001821b6110a1565b5060208310610133831016604e8410600b8410161715615792575081810a6110a1565b61579c83836156b6565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156157ce576157ce615076565b029392505050565b60006129728383615717565b6000826157f1576157f1615442565b50049056fea164736f6c6343000813000a",
+ Bin: "0x6101606040523480156200001257600080fd5b5060405162005c8738038062005c87833981016040819052620000359162000309565b87878787878787873380600081620000945760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c757620000c78162000241565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff191660018381811115620001185762000118620003b6565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000179573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200019f9190620003cc565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002099190620003cc565b60ff16146200022b576040516301f86e1760e41b815260040160405180910390fd5b50505050505050505050505050505050620003f8565b336001600160a01b038216036200029b5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200008b565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200030457600080fd5b919050565b600080600080600080600080610100898b0312156200032757600080fd5b6200033289620002ec565b97506200034260208a01620002ec565b96506200035260408a01620002ec565b95506200036260608a01620002ec565b94506200037260808a01620002ec565b93506200038260a08a01620002ec565b925060c0890151600281106200039757600080fd5b9150620003a760e08a01620002ec565b90509295985092959890939650565b634e487b7160e01b600052602160045260246000fd5b600060208284031215620003df57600080fd5b815160ff81168114620003f157600080fd5b9392505050565b60805160a05160c05160e051610100516101205161014051615803620004846000396000610b7001526000610ad2015260006107be0152600081816109a001526135b60152600081816109540152613e3201526000818161051d0152613690015260008181610c1801528181611df00152818161256b015281816125c80152613af601526158036000f3fe608060405234801561001057600080fd5b50600436106103d05760003560e01c80638ed02bab116101ff578063c3f909d41161011a578063eb5dcd6c116100ad578063f5a418461161007c578063f5a4184614610eb4578063f777ff0614610f35578063faa3e99614610f3c578063ffd242bd14610f8257600080fd5b8063eb5dcd6c14610de5578063ec4de4ba14610df8578063ed56b3e114610e2e578063f2fde38b14610ea157600080fd5b8063d09dc339116100e9578063d09dc33914610c3c578063d763264814610c44578063d85aa07c14610c57578063e80a3d4414610c5f57600080fd5b8063c3f909d414610bd6578063c5b964e014610beb578063c7c3a19a14610bf6578063ca30e60314610c1657600080fd5b8063aab9edd611610192578063b3596c2311610161578063b3596c23146107e2578063b6511a2a14610ba7578063b657bc9c14610bae578063ba87666814610bc157600080fd5b8063aab9edd614610b57578063abc76ae014610b66578063ac4dc59a14610b6e578063b121e14714610b9457600080fd5b8063a08714c0116101ce578063a08714c014610ad0578063a538b2eb14610af6578063a710b22114610b3c578063a87f45fe14610b4f57600080fd5b80638ed02bab14610a5c5780639089daa414610a7a57806393f6ebcf14610a8f5780639e0a99ed14610ac857600080fd5b806343cc055c116102ef5780636209e1e91161028257806379ba50971161025157806379ba5097146109ea57806379ea9943146109f25780638456cb5914610a365780638da5cb5b14610a3e57600080fd5b80636209e1e91461098b5780636709d0e51461099e578063671d36ed146109c45780636eec02a2146109d757600080fd5b80635425d8ac116102be5780635425d8ac146107bc57806357359584146107e2578063614486af146109525780636181d82d1461097857600080fd5b806343cc055c1461074957806344cb70b8146107705780634ca16c52146107935780635147cd591461079c57600080fd5b8063207b6516116103675780633b9cce59116103365780633b9cce59146106c05780633f4ba83a146106d3578063421d183b146106db57806343b46e5f1461074157600080fd5b8063207b651614610508578063226cf83c1461051b578063232c1cc5146105625780633408f73a1461056957600080fd5b8063187256e8116103a3578063187256e81461043b57806319d97a941461044e5780631e0104391461046e5780631efcf646146104d057600080fd5b8063050ee65d146103d557806306e3b632146103ed5780630b7d33e61461040d5780631865c57d14610422575b600080fd5b6201e26c5b6040519081526020015b60405180910390f35b6104006103fb36600461447a565b610f8a565b6040516103e491906144d7565b61042061041b366004614533565b6110a7565b005b61042a611108565b6040516103e495949392919061472b565b61042061044936600461486c565b611508565b61046161045c3660046148a9565b611579565b6040516103e49190614926565b6104b361047c3660046148a9565b60009081526004602052604090206001015470010000000000000000000000000000000090046bffffffffffffffffffffffff1690565b6040516bffffffffffffffffffffffff90911681526020016103e4565b6104f86104de3660046148a9565b600090815260046020526040902054610100900460ff1690565b60405190151581526020016103e4565b6104616105163660046148a9565b61161b565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016103e4565b60186103da565b6106b36040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915250604080516101608101825260165473ffffffffffffffffffffffffffffffffffffffff808216835263ffffffff740100000000000000000000000000000000000000008084048216602086015278010000000000000000000000000000000000000000000000008085048316968601969096527c010000000000000000000000000000000000000000000000000000000093849004821660608601526017548084166080870152818104831660a0870152868104831660c087015293909304811660e085015260185491821661010085015291810482166101208401529290920490911661014082015290565b6040516103e49190614939565b6104206106ce366004614a63565b611638565b61042061188e565b6106ee6106e9366004614ad8565b6118f4565b60408051951515865260ff90941660208601526bffffffffffffffffffffffff9283169385019390935216606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a0016103e4565b610420611a13565b6014547801000000000000000000000000000000000000000000000000900460ff166104f8565b6104f861077e3660046148a9565b60009081526008602052604090205460ff1690565b62017f986103da565b6107af6107aa3660046148a9565b611eaa565b6040516103e49190614b34565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6108d46107f0366004614ad8565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091525073ffffffffffffffffffffffffffffffffffffffff908116600090815260226020908152604091829020825160c081018452815463ffffffff81168252640100000000810462ffffff16938201939093526701000000000000008304909416928401929092527b01000000000000000000000000000000000000000000000000000000900460ff16606083015260018101546080830152600201546bffffffffffffffffffffffff1660a082015290565b6040516103e49190600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6104b3610986366004614b47565b611eb5565b610461610999366004614ad8565b612010565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6104206109d2366004614ba7565b612043565b6103da6109e5366004614ad8565b6120c3565b61042061216d565b61053d610a003660046148a9565b6000908152600460205260409020546a0100000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690565b61042061226f565b60005473ffffffffffffffffffffffffffffffffffffffff1661053d565b60155473ffffffffffffffffffffffffffffffffffffffff1661053d565b610a826122e8565b6040516103e49190614be3565b61053d610a9d3660046148a9565b60009081526004602052604090206002015473ffffffffffffffffffffffffffffffffffffffff1690565b6103a46103da565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6104f8610b04366004614ad8565b73ffffffffffffffffffffffffffffffffffffffff908116600090815260226020526040902054670100000000000000900416151590565b610420610b4a366004614c4c565b6123fa565b610420612728565b604051600481526020016103e4565b6115e06103da565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b610420610ba2366004614ad8565b61275a565b60326103da565b6104b3610bbc3660046148a9565b612852565b610bc9612979565b6040516103e49190614c7a565b610bde6129e8565b6040516103e49190614cd4565b60255460ff166107af565b610c09610c043660046148a9565b612bd0565b6040516103e49190614e5b565b7f000000000000000000000000000000000000000000000000000000000000000061053d565b6103da612fe0565b6104b3610c523660046148a9565b612fef565b601b546103da565b610dd86040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091525060408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff750100000000000000000000000000000000000000000083048116608083015276010000000000000000000000000000000000000000000083048116151560a08301527701000000000000000000000000000000000000000000000083048116151560c08301527801000000000000000000000000000000000000000000000000909204909116151560e082015260155473ffffffffffffffffffffffffffffffffffffffff1661010082015290565b6040516103e49190614f92565b610420610df3366004614c4c565b612ffa565b6103da610e06366004614ad8565b73ffffffffffffffffffffffffffffffffffffffff1660009081526021602052604090205490565b610e88610e3c366004614ad8565b73ffffffffffffffffffffffffffffffffffffffff166000908152600c602090815260409182902082518084019093525460ff8082161515808552610100909204169290910182905291565b60408051921515835260ff9091166020830152016103e4565b610420610eaf366004614ad8565b613159565b610f0f610ec23660046148a9565b60408051808201909152600080825260208201525060009081526023602090815260409182902082518084019093525463ffffffff81168352640100000000900462ffffff169082015290565b60408051825163ffffffff16815260209283015162ffffff1692810192909252016103e4565b60406103da565b610f75610f4a366004614ad8565b73ffffffffffffffffffffffffffffffffffffffff166000908152601c602052604090205460ff1690565b6040516103e49190615062565b6103da61316d565b60606000610f986002613175565b9050808410610fd3576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610fdf84866150a5565b905081811180610fed575083155b610ff75780610ff9565b815b9050600061100786836150b8565b67ffffffffffffffff81111561101f5761101f6150cb565b604051908082528060200260200182016040528015611048578160200160208202803683370190505b50905060005b815181101561109b5761106c61106488836150a5565b60029061317f565b82828151811061107e5761107e6150fa565b60209081029190910101528061109381615129565b91505061104e565b50925050505b92915050565b6110af61318b565b6000838152601f602052604090206110c8828483615203565b50827f2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae776983836040516110fb92919061531e565b60405180910390a2505050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152604080516101e08101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a08201526101c081019190915260408051610140810182526016547c0100000000000000000000000000000000000000000000000000000000900463ffffffff1681526000602082018190529181018290526014546bffffffffffffffffffffffff16606080830191909152918291608081016112416002613175565b81526017547401000000000000000000000000000000000000000080820463ffffffff908116602080860191909152780100000000000000000000000000000000000000000000000080850483166040808801919091526013546060808901919091526014546c01000000000000000000000000810486166080808b0191909152760100000000000000000000000000000000000000000000820460ff16151560a09a8b015283516101e0810185526000808252968101879052601654898104891695820195909552700100000000000000000000000000000000830462ffffff169381019390935273010000000000000000000000000000000000000090910461ffff169082015296870192909252808204831660c08701527c0100000000000000000000000000000000000000000000000000000000909404821660e086015260185492830482166101008601529290910416610120830152601954610140830152601a5461016083015273ffffffffffffffffffffffffffffffffffffffff166101808201529095506101a081016113dc60096131de565b815260175473ffffffffffffffffffffffffffffffffffffffff16602091820152601454600d80546040805182860281018601909152818152949850899489949293600e93750100000000000000000000000000000000000000000090910460ff1692859183018282801561148757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff16815260019091019060200180831161145c575b50505050509250818054806020026020016040519081016040528092919081815260200182805480156114f057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116114c5575b50505050509150945094509450945094509091929394565b6115106131eb565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601c6020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600381111561157057611570614af5565b02179055505050565b6000818152601f6020526040902080546060919061159690615161565b80601f01602080910402602001604051908101604052809291908181526020018280546115c290615161565b801561160f5780601f106115e45761010080835404028352916020019161160f565b820191906000526020600020905b8154815290600101906020018083116115f257829003601f168201915b50505050509050919050565b6000818152601d6020526040902080546060919061159690615161565b6116406131eb565b600e54811461167b576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b600e5481101561184d576000600e828154811061169d5761169d6150fa565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168084526011909252604083205491935016908585858181106116e7576116e76150fa565b90506020020160208101906116fc9190614ad8565b905073ffffffffffffffffffffffffffffffffffffffff8116158061178f575073ffffffffffffffffffffffffffffffffffffffff82161580159061176d57508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561178f575073ffffffffffffffffffffffffffffffffffffffff81811614155b156117c6576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff818116146118375773ffffffffffffffffffffffffffffffffffffffff838116600090815260116020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b505050808061184590615129565b91505061167e565b507fa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725600e83836040516118829392919061536b565b60405180910390a15050565b6118966131eb565b601480547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015282918291829182919082906119ba5760608201516014546000916119a6916bffffffffffffffffffffffff1661541d565b600e549091506119b69082615471565b9150505b8151602083015160408401516119d190849061549c565b6060949094015173ffffffffffffffffffffffffffffffffffffffff9a8b16600090815260116020526040902054929b919a9499509750921694509092505050565b611a1b61326c565b600060255460ff166001811115611a3457611a34614af5565b03611a6b576040517fe0262d7400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601454600e546bffffffffffffffffffffffff909116906000611a8e600f613175565b90506000611a9c82846150a5565b905060008167ffffffffffffffff811115611ab957611ab96150cb565b604051908082528060200260200182016040528015611ae2578160200160208202803683370190505b50905060008267ffffffffffffffff811115611b0057611b006150cb565b604051908082528060200260200182016040528015611b29578160200160208202803683370190505b50905060005b85811015611c5b576000600e8281548110611b4c57611b4c6150fa565b600091825260208220015473ffffffffffffffffffffffffffffffffffffffff169150611b7a828a8a6132bd565b9050806bffffffffffffffffffffffff16858481518110611b9d57611b9d6150fa565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff808416600090815260119092526040909120548551911690859085908110611beb57611beb6150fa565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920181019190915292166000908152600b909252506040902080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff16905580611c5381615129565b915050611b2f565b5060005b84811015611dd8576000611c74600f8361317f565b73ffffffffffffffffffffffffffffffffffffffff8082166000818152600b602090815260408083208151608081018352905460ff80821615158352610100820416828501526bffffffffffffffffffffffff6201000082048116838501526e0100000000000000000000000000009091041660608201529383526011909152902054929350911684611d078a866150a5565b81518110611d1757611d176150fa565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260408101516bffffffffffffffffffffffff1685611d5a8a866150a5565b81518110611d6a57611d6a6150fa565b60209081029190910181019190915273ffffffffffffffffffffffffffffffffffffffff9092166000908152600b909252506040902080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff16905580611dd081615129565b915050611c5f565b5073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166000908152602160205260408120819055611e2b600f613175565b90505b8015611e6857611e55611e4d611e456001846150b8565b600f9061317f565b600f906134c5565b5080611e60816154c1565b915050611e2e565b507f5af23b715253628d12b660b27a4f3fc626562ea8a55040aa99ab3dc178989fad8183604051611e9a9291906154f6565b60405180910390a1505050505050565b60006110a1826134e7565b60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff750100000000000000000000000000000000000000000083048116608083015276010000000000000000000000000000000000000000000083048116151560a08301527701000000000000000000000000000000000000000000000083048116151560c08301527801000000000000000000000000000000000000000000000000909204909116151560e082015260155473ffffffffffffffffffffffffffffffffffffffff16610100820152600090818080611fed84613592565b92509250925061200389858a8a8787878d613784565b9998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602080526040902080546060919061159690615161565b61204b61318b565b73ffffffffffffffffffffffffffffffffffffffff83166000908152602080526040902061207a828483615203565b508273ffffffffffffffffffffffffffffffffffffffff167f7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d283836040516110fb92919061531e565b73ffffffffffffffffffffffffffffffffffffffff81166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa15801561213f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121639190615524565b6110a191906150b8565b60015473ffffffffffffffffffffffffffffffffffffffff1633146121f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6122776131eb565b601480547fffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff167601000000000000000000000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016118ea565b600e5460609060008167ffffffffffffffff811115612309576123096150cb565b60405190808252806020026020018201604052801561234e57816020015b60408051808201909152600080825260208201528152602001906001900390816123275790505b50905060005b828110156123f3576000600e8281548110612371576123716150fa565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168084526011835260409384902054845180860190955281855290911691830182905285519093509091908590859081106123d3576123d36150fa565b6020026020010181905250505080806123eb90615129565b915050612354565b5092915050565b73ffffffffffffffffffffffffffffffffffffffff8116612447576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160255460ff16600181111561246057612460614af5565b03612497576040517f4a3578fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152601160205260409020541633146124f7576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601454600e5460009161251a9185916bffffffffffffffffffffffff16906132bd565b73ffffffffffffffffffffffffffffffffffffffff8085166000908152600b6020908152604080832080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff1690557f000000000000000000000000000000000000000000000000000000000000000090931682526021905220549091506125b1906bffffffffffffffffffffffff8316906150b8565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166000818152602160205260408082209490945592517fa9059cbb00000000000000000000000000000000000000000000000000000000815291851660048301526bffffffffffffffffffffffff841660248301529063a9059cbb906044016020604051808303816000875af1158015612666573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061268a919061553d565b9050806126c3576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405133815273ffffffffffffffffffffffffffffffffffffffff808516916bffffffffffffffffffffffff8516918716907f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f406989060200160405180910390a450505050565b6127306131eb565b602580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b73ffffffffffffffffffffffffffffffffffffffff8181166000908152601260205260409020541633146127ba576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81811660008181526011602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556012909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b6000818152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915261297283612962816134e7565b8360400151846101000151611eb5565b9392505050565b606060248054806020026020016040519081016040528092919081815260200182805480156129de57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116129b3575b5050505050905090565b604080516102008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a082018390526101c08201526101e0810191909152604080516102008101825260165463ffffffff74010000000000000000000000000000000000000000808304821684527801000000000000000000000000000000000000000000000000808404831660208601526017547c0100000000000000000000000000000000000000000000000000000000810484169686019690965273ffffffffffffffffffffffffffffffffffffffff938416606086015260145460ff828204161515608087015262ffffff70010000000000000000000000000000000082041660a0870152601854928304841660c087015290820490921660e085015293821661010084015261ffff7301000000000000000000000000000000000000009091041661012083015291909116610140820152601954610160820152601a54610180820152601b546101a08201526101c08101612baa60096131de565b815260155473ffffffffffffffffffffffffffffffffffffffff16602090910152919050565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526000828152600460209081526040808320815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a010000000000000000000090910481166080830181905260018401546fffffffffffffffffffffffffffffffff811660a08501526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08501527c0100000000000000000000000000000000000000000000000000000000900490941660e08301526002909201549091169281019290925290919015612da557816080015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612da0919061555f565b612da8565b60005b90506040518061014001604052808273ffffffffffffffffffffffffffffffffffffffff168152602001836040015163ffffffff168152602001600760008781526020019081526020016000208054612e0090615161565b80601f0160208091040260200160405190810160405280929190818152602001828054612e2c90615161565b8015612e795780601f10612e4e57610100808354040283529160200191612e79565b820191906000526020600020905b815481529060010190602001808311612e5c57829003601f168201915b505050505081526020018360c001516bffffffffffffffffffffffff1681526020016005600087815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001836060015163ffffffff1667ffffffffffffffff1681526020018360e0015163ffffffff1681526020018360a001516bffffffffffffffffffffffff168152602001836000015115158152602001601e60008781526020019081526020016000208054612f5690615161565b80601f0160208091040260200160405190810160405280929190818152602001828054612f8290615161565b8015612fcf5780601f10612fa457610100808354040283529160200191612fcf565b820191906000526020600020905b815481529060010190602001808311612fb257829003601f168201915b505050505081525092505050919050565b6000612fea613af4565b905090565b60006110a182612852565b73ffffffffffffffffffffffffffffffffffffffff82811660009081526011602052604090205416331461305a576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff8216036130a9576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152601260205260409020548116908216146131555773ffffffffffffffffffffffffffffffffffffffff82811660008181526012602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45b5050565b6131616131eb565b61316a81613bbe565b50565b6000612fea60025b60006110a1825490565b60006129728383613cb3565b60175473ffffffffffffffffffffffffffffffffffffffff1633146131dc576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6060600061297283613cdd565b60005473ffffffffffffffffffffffffffffffffffffffff1633146131dc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016121ea565b60185473ffffffffffffffffffffffffffffffffffffffff1633146131dc576040517fb6dfb7a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152906134b9576000816060015185613355919061541d565b905060006133638583615471565b90508083604001818151613377919061549c565b6bffffffffffffffffffffffff16905250613392858261557c565b836060018181516133a3919061549c565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b60006129728373ffffffffffffffffffffffffffffffffffffffff8416613d38565b6000818160045b600f811015613574577fff00000000000000000000000000000000000000000000000000000000000000821683826020811061352c5761352c6150fa565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461356257506000949350505050565b8061356c81615129565b9150506134ee565b5081600f1a600181111561358a5761358a614af5565b949350505050565b600080600080846040015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561361f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061364391906155c3565b509450909250505060008113158061365a57508142105b8061367b575082801561367b575061367282426150b8565b8463ffffffff16105b1561368a57601954965061368e565b8096505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156136f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061371d91906155c3565b509450909250505060008113158061373457508142105b806137555750828015613755575061374c82426150b8565b8463ffffffff16105b1561376457601a549550613768565b8095505b86866137738a613e2b565b965096509650505050509193909250565b600080808089600181111561379b5761379b614af5565b036137aa575062017f986137ff565b60018960018111156137be576137be614af5565b036137cd57506201e26c6137ff565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008a6080015160016138129190615613565b6138209060ff16604061562c565b60185461384e906103a49074010000000000000000000000000000000000000000900463ffffffff166150a5565b61385891906150a5565b601554604080517fde9ee35e0000000000000000000000000000000000000000000000000000000081528151939450600093849373ffffffffffffffffffffffffffffffffffffffff169263de9ee35e92600480820193918290030181865afa1580156138c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138ed9190615643565b909250905081836138ff8360186150a5565b613909919061562c565b60808f0151613919906001615613565b6139289060ff166115e061562c565b61393291906150a5565b61393c91906150a5565b61394690856150a5565b6101008e01516040517f125441400000000000000000000000000000000000000000000000000000000081526004810186905291955073ffffffffffffffffffffffffffffffffffffffff1690631254414090602401602060405180830381865afa1580156139b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139dd9190615524565b8d6060015161ffff166139f0919061562c565b94505050506000613a018b86613f15565b60008d815260046020526040902054909150610100900460ff1615613a665760008c81526023602090815260409182902082518084018452905463ffffffff811680835264010000000090910462ffffff908116928401928352928501525116908201525b6000613ad08c6040518061012001604052808d63ffffffff1681526020018681526020018781526020018c81526020018b81526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff16815260200185815260200160001515815250614091565b60208101518151919250613ae39161549c565b9d9c50505050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000818152602160205260408082205490517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152919290916370a0823190602401602060405180830381865afa158015613b90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb49190615524565b612fea9190615667565b3373ffffffffffffffffffffffffffffffffffffffff821603613c3d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016121ea565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110613cca57613cca6150fa565b9060005260206000200154905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561160f57602002820191906000526020600020905b815481526020019060010190808311613d195750505050509050919050565b60008181526001830160205260408120548015613e21576000613d5c6001836150b8565b8554909150600090613d70906001906150b8565b9050818114613dd5576000866000018281548110613d9057613d906150fa565b9060005260206000200154905080876000018481548110613db357613db36150fa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613de657613de6615687565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506110a1565b60009150506110a1565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ebf91906155c3565b50935050925050600082131580613ed557508042105b80613f0557506000846040015162ffffff16118015613f055750613ef981426150b8565b846040015162ffffff16105b156123f3575050601b5492915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa158015614002573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061402691906155c3565b5093505092505060008213158061403c57508042105b8061406c57506000866040015162ffffff1611801561406c575061406081426150b8565b866040015162ffffff16105b156140805760018301546060850152614088565b606084018290525b50505092915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff1684606001516140fc919061562c565b9050836101000151801561410f5750803a105b1561411757503a5b60006012831161412857600161413e565b6141336012846150b8565b61413e90600a6157d6565b9050600060128410614151576001614167565b61415c8460126150b8565b61416790600a6157d6565b905060008660a0015187604001518860200151896000015161418991906150a5565b614193908761562c565b61419d91906150a5565b6141a7919061562c565b9050614203828860e00151606001516141c0919061562c565b6001848a60e00151606001516141d6919061562c565b6141e091906150b8565b6141ea868561562c565b6141f491906150a5565b6141fe91906157e2565b6143d8565b6bffffffffffffffffffffffff1686526080870151614226906141fe90836157e2565b6bffffffffffffffffffffffff1660408088019190915260e0880151015160009061425f9062ffffff16683635c9adc5dea0000061562c565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b614292919061562c565b61429c91906150a5565b6142a6919061562c565b6142b0919061562c565b6142ba91906157e2565b6142c491906150a5565b9050614307848a60e00151606001516142dd919061562c565b6001868c60e00151606001516142f3919061562c565b6142fd91906150b8565b6141ea888561562c565b6bffffffffffffffffffffffff166020890152608089015161432d906141fe90836157e2565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a0191909152890151614370906143d8565b6bffffffffffffffffffffffff1660a0808a0191909152890151614393906143d8565b6bffffffffffffffffffffffff1660c089015260e0890151606001516143b8906143d8565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b60006bffffffffffffffffffffffff821115614476576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016121ea565b5090565b6000806040838503121561448d57600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b838110156144cc578151875295820195908201906001016144b0565b509495945050505050565b602081526000612972602083018461449c565b60008083601f8401126144fc57600080fd5b50813567ffffffffffffffff81111561451457600080fd5b60208301915083602082850101111561452c57600080fd5b9250929050565b60008060006040848603121561454857600080fd5b83359250602084013567ffffffffffffffff81111561456657600080fd5b614572868287016144ea565b9497909650939450505050565b600081518084526020808501945080840160005b838110156144cc57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614593565b805163ffffffff16825260006101e060208301516145eb602086018263ffffffff169052565b506040830151614603604086018263ffffffff169052565b50606083015161461a606086018262ffffff169052565b506080830151614630608086018261ffff169052565b5060a083015161465060a08601826bffffffffffffffffffffffff169052565b5060c083015161466860c086018263ffffffff169052565b5060e083015161468060e086018263ffffffff169052565b506101008381015163ffffffff908116918601919091526101208085015190911690850152610140808401519085015261016080840151908501526101808084015173ffffffffffffffffffffffffffffffffffffffff16908501526101a0808401518186018390526146f58387018261457f565b925050506101c0808401516147218287018273ffffffffffffffffffffffffffffffffffffffff169052565b5090949350505050565b855163ffffffff16815260006101c0602088015161475960208501826bffffffffffffffffffffffff169052565b5060408801516040840152606088015161478360608501826bffffffffffffffffffffffff169052565b506080880151608084015260a08801516147a560a085018263ffffffff169052565b5060c08801516147bd60c085018263ffffffff169052565b5060e088015160e0840152610100808901516147e08286018263ffffffff169052565b5050610120888101511515908401526101408301819052614803818401886145c5565b9050828103610160840152614818818761457f565b905082810361018084015261482d818661457f565b9150506148406101a083018460ff169052565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461316a57600080fd5b6000806040838503121561487f57600080fd5b823561488a8161484a565b915060208301356004811061489e57600080fd5b809150509250929050565b6000602082840312156148bb57600080fd5b5035919050565b6000815180845260005b818110156148e8576020818501810151868301820152016148cc565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061297260208301846148c2565b815173ffffffffffffffffffffffffffffffffffffffff1681526101608101602083015161496f602084018263ffffffff169052565b506040830151614987604084018263ffffffff169052565b50606083015161499f606084018263ffffffff169052565b5060808301516149c7608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a08301516149df60a084018263ffffffff169052565b5060c08301516149f760c084018263ffffffff169052565b5060e0830151614a0f60e084018263ffffffff169052565b506101008381015173ffffffffffffffffffffffffffffffffffffffff81168483015250506101208381015163ffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b60008060208385031215614a7657600080fd5b823567ffffffffffffffff80821115614a8e57600080fd5b818501915085601f830112614aa257600080fd5b813581811115614ab157600080fd5b8660208260051b8501011115614ac657600080fd5b60209290920196919550909350505050565b600060208284031215614aea57600080fd5b81356129728161484a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6002811061316a5761316a614af5565b60208101614b4183614b24565b91905290565b60008060008060808587031215614b5d57600080fd5b84359350602085013560028110614b7357600080fd5b9250604085013563ffffffff81168114614b8c57600080fd5b91506060850135614b9c8161484a565b939692955090935050565b600080600060408486031215614bbc57600080fd5b8335614bc78161484a565b9250602084013567ffffffffffffffff81111561456657600080fd5b602080825282518282018190526000919060409081850190868401855b82811015614c3f578151805173ffffffffffffffffffffffffffffffffffffffff90811686529087015116868501529284019290850190600101614c00565b5091979650505050505050565b60008060408385031215614c5f57600080fd5b8235614c6a8161484a565b9150602083013561489e8161484a565b6020808252825182820181905260009190848201906040850190845b81811015614cc857835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614c96565b50909695505050505050565b60208152614ceb60208201835163ffffffff169052565b60006020830151614d04604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e0830151610100614d838185018363ffffffff169052565b8401519050610120614dac8482018373ffffffffffffffffffffffffffffffffffffffff169052565b8401519050610140614dc38482018361ffff169052565b8401519050610160614dec8482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e080860182905291925090614e3461022086018461457f565b9086015173ffffffffffffffffffffffffffffffffffffffff811683870152909250614721565b60208152614e8260208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60006020830151614e9b604084018263ffffffff169052565b506040830151610140806060850152614eb86101608501836148c2565b91506060850151614ed960808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e0850151610100614f45818701836bffffffffffffffffffffffff169052565b8601519050610120614f5a8682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00183870152905061484083826148c2565b6000610120820190506bffffffffffffffffffffffff835116825263ffffffff60208401511660208301526040830151614fd3604084018262ffffff169052565b506060830151614fe9606084018261ffff169052565b506080830151614ffe608084018260ff169052565b5060a083015161501260a084018215159052565b5060c083015161502660c084018215159052565b5060e083015161503a60e084018215159052565b506101008381015173ffffffffffffffffffffffffffffffffffffffff811684830152614a5b565b6020810160048310614b4157614b41614af5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156110a1576110a1615076565b818103818111156110a1576110a1615076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361515a5761515a615076565b5060010190565b600181811c9082168061517557607f821691505b6020821081036151ae577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156151fe57600081815260208120601f850160051c810160208610156151db5750805b601f850160051c820191505b818110156151fa578281556001016151e7565b5050505b505050565b67ffffffffffffffff83111561521b5761521b6150cb565b61522f836152298354615161565b836151b4565b6000601f841160018114615281576000851561524b5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355615317565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156152d057868501358255602094850194600190920191016152b0565b508682101561530b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000604082016040835280865480835260608501915087600052602092508260002060005b828110156153c257815473ffffffffffffffffffffffffffffffffffffffff1684529284019260019182019101615390565b505050838103828501528481528590820160005b868110156154115782356153e98161484a565b73ffffffffffffffffffffffffffffffffffffffff16825291830191908301906001016153d6565b50979650505050505050565b6bffffffffffffffffffffffff8281168282160390808211156123f3576123f3615076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006bffffffffffffffffffffffff8084168061549057615490615442565b92169190910492915050565b6bffffffffffffffffffffffff8181168382160190808211156123f3576123f3615076565b6000816154d0576154d0615076565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b604081526000615509604083018561457f565b828103602084015261551b818561449c565b95945050505050565b60006020828403121561553657600080fd5b5051919050565b60006020828403121561554f57600080fd5b8151801515811461297257600080fd5b60006020828403121561557157600080fd5b81516129728161484a565b6bffffffffffffffffffffffff818116838216028082169190828114614a5b57614a5b615076565b805169ffffffffffffffffffff811681146155be57600080fd5b919050565b600080600080600060a086880312156155db57600080fd5b6155e4866155a4565b9450602086015193506040860151925060608601519150615607608087016155a4565b90509295509295909350565b60ff81811683821601908111156110a1576110a1615076565b80820281158282048414176110a1576110a1615076565b6000806040838503121561565657600080fd5b505080516020909101519092909150565b81810360008312801583831316838312821617156123f3576123f3615076565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600181815b8085111561570f57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156156f5576156f5615076565b8085161561570257918102915b93841c93908002906156bb565b509250929050565b600082615726575060016110a1565b81615733575060006110a1565b816001811461574957600281146157535761576f565b60019150506110a1565b60ff84111561576457615764615076565b50506001821b6110a1565b5060208310610133831016604e8410600b8410161715615792575081810a6110a1565b61579c83836156b6565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156157ce576157ce615076565b029392505050565b60006129728383615717565b6000826157f1576157f1615442565b50049056fea164736f6c6343000813000a",
}
var AutomationRegistryLogicCABI = AutomationRegistryLogicCMetaData.ABI
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 eb385cf7b03..a7fcf430b3f 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
@@ -52,7 +52,7 @@ 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\":\"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",
+ Bin: "0x6101406040523480156200001257600080fd5b506040516200526d3803806200526d8339810160408190526200003591620003b1565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b9190620003b1565b826001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003b1565b836001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003b1565b846001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003b1565b856001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003b1565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b981620002ed565b5050506001600160a01b0394851660805292841660a05290831660c052821660e052811661010052166101205250620003d8565b336001600160a01b03821603620003475760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003ae57600080fd5b50565b600060208284031215620003c457600080fd5b8151620003d18162000398565b9392505050565b60805160a05160c05160e0516101005161012051614e48620004256000396000818160c9015261017c01526000611bb8015260005050600050506000505060006104c20152614e486000f3fe6080604052600436106100c75760003560e01c8063aed2e92911610074578063e3d0e7121161004e578063e3d0e71214610348578063f2fde38b14610368578063f75f6b1114610388576100c7565b8063aed2e929146102a3578063afcb95d7146102da578063b1dc65a414610328576100c7565b806381ff7048116100a557806381ff7048146101d65780638da5cb5b14610258578063a4c0ed3614610283576100c7565b8063181f5a771461010e578063349e8cca1461016d57806379ba5097146101c1575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610107573d6000f35b3d6000fd5b005b34801561011a57600080fd5b506101576040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e322e30000000000000000081525081565b6040516101649190613b44565b60405180910390f35b34801561017957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b3480156101cd57600080fd5b5061010c6103a8565b3480156101e257600080fd5b5061023560155460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b34801561026457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661019c565b34801561028f57600080fd5b5061010c61029e366004613bd2565b6104aa565b3480156102af57600080fd5b506102c36102be366004613c2e565b6106c6565b604080519215158352602083019190915201610164565b3480156102e657600080fd5b50601154601254604080516000815260208101939093527401000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b34801561033457600080fd5b5061010c610343366004613cbf565b61083c565b34801561035457600080fd5b5061010c610363366004613f90565b610b77565b34801561037457600080fd5b5061010c61038336600461405d565b610ba0565b34801561039457600080fd5b5061010c6103a3366004614261565b610bb4565b60015473ffffffffffffffffffffffffffffffffffffffff16331461042e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610519576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114610553576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610561828401846142f0565b60008181526004602052604090205490915065010000000000900463ffffffff908116146105bb576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600460205260409020600101546105f69085906c0100000000000000000000000090046bffffffffffffffffffffffff16614338565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff90921691909117905560195461066190859061435d565b6019556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b6000806106d1611ba0565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff1615610730576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f8901859004850281018501909552878552909361082f938990899081908401838280828437600092019190915250611c1192505050565b9097909650945050505050565b60005a60408051610160810182526012546bffffffffffffffffffffffff8116825263ffffffff6c010000000000000000000000008204811660208401527001000000000000000000000000000000008204811693830193909352740100000000000000000000000000000000000000008104909216606082015262ffffff7801000000000000000000000000000000000000000000000000830416608082015261ffff7b0100000000000000000000000000000000000000000000000000000083041660a082015260ff7d0100000000000000000000000000000000000000000000000000000000008304811660c08301527e010000000000000000000000000000000000000000000000000000000000008304811615801560e08401527f01000000000000000000000000000000000000000000000000000000000000009093048116151561010080840191909152601354918216151561012084015273ffffffffffffffffffffffffffffffffffffffff9104166101408201529192506109f2576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16610a3b576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a3514610a77576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c0810151610a8790600161439f565b60ff1686141580610a985750858414155b15610acf576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610adf8a8a8a8a8a8a8a8a611e3a565b6000610aeb8a8a6120a3565b905060208b0135600881901c63ffffffff16610b0884848761215e565b836060015163ffffffff168163ffffffff161115610b6857601280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416021790555b50505050505050505050505050565b610b9886868686806020019051810190610b91919061445e565b8686610bb4565b505050505050565b610ba8612b00565b610bb181612b81565b50565b610bbc612b00565b601f86511115610bf8576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff16600003610c35576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84518651141580610c545750610c4c8460036145e0565b60ff16865111155b15610c8b576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e546bffffffffffffffffffffffff9091169060005b816bffffffffffffffffffffffff16811015610d0d57610cfa600e8281548110610cd157610cd1614370565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168484612c76565b5080610d05816145fc565b915050610ca5565b5060008060005b836bffffffffffffffffffffffff16811015610e1657600d8181548110610d3d57610d3d614370565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff90921694509082908110610d7857610d78614370565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055915080610e0e816145fc565b915050610d14565b50610e23600d6000613a23565b610e2f600e6000613a23565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c5181101561129857600c60008e8381518110610e7457610e74614370565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615610edf576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d8281518110610f0957610f09614370565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603610f5e576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f8481518110610f8f57610f8f614370565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c908290811061103757611037614370565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110a7576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909350611162576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009095169490941717919091169290921791909117905580611290816145fc565b915050610e55565b50508a516112ae9150600d9060208d0190613a41565b5088516112c290600e9060208c0190613a41565b50604051806101600160405280856bffffffffffffffffffffffff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001600063ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020018960ff1681526020016012600001601e9054906101000a900460ff16151581526020016012600001601f9054906101000a900460ff161515815260200188610200015115158152602001886101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601260008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160186101000a81548162ffffff021916908362ffffff16021790555060a082015181600001601b6101000a81548161ffff021916908361ffff16021790555060c082015181600001601d6101000a81548160ff021916908360ff16021790555060e082015181600001601e6101000a81548160ff02191690831515021790555061010082015181600001601f6101000a81548160ff0219169083151502179055506101208201518160010160006101000a81548160ff0219169083151502179055506101408201518160010160016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601460010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601460010160149054906101000a900463ffffffff1663ffffffff168152602001601460010160189054906101000a900463ffffffff1663ffffffff1681526020016014600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160178190555086610160015160188190555060006014600101601c9054906101000a900463ffffffff169050876101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611963573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119879190614634565b601580547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff9384160217808255600192601891611a02918591780100000000000000000000000000000000000000000000000090041661464d565b92506101000a81548163ffffffff021916908363ffffffff160217905550600088604051602001611a3391906146bb565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601554909150611a9c90469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f612e7e565b60115560005b611aac6009612f28565b811015611adc57611ac9611ac1600983612f32565b600990612f45565b5080611ad4816145fc565b915050611aa2565b5060005b896101a0015151811015611b3357611b208a6101a001518281518110611b0857611b08614370565b60200260200101516009612f6790919063ffffffff16565b5080611b2b816145fc565b915050611ae0565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601460010160189054906101000a900463ffffffff168f8f8f878f8f604051611b8a9998979695949392919061485f565b60405180910390a1505050505050505050505050565b3273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c0f576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60125460009081907f0100000000000000000000000000000000000000000000000000000000000000900460ff1615611c76576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090611cf2908590602401613b44565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d1690611dc590879087906004016148f5565b60408051808303816000875af1158015611de3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e07919061490e565b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60008787604051611e4c92919061493c565b604051908190038120611e63918b9060200161494c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561203a57600185878360208110611ecf57611ecf614370565b611edc91901a601b61439f565b8c8c85818110611eee57611eee614370565b905060200201358b8b86818110611f0757611f07614370565b9050602002013560405160008152602001604052604051611f44949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611f66573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612014576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b840193508080612032906145fc565b915050611eb2565b50827e01010101010101010101010101010101010101010101010101010101010101841614612095576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6120dc6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006120ea83850185614a3d565b604081015151606082015151919250908114158061210d57508082608001515114155b8061211d5750808260a001515114155b15612154576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090505b92915050565b600082604001515167ffffffffffffffff81111561217e5761217e613d76565b60405190808252806020026020018201604052801561223a57816020015b604080516101c081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161219c5790505b50905060006040518060800160405280600061ffff1681526020016000815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152509050600085610140015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122fc9190614634565b6101408701516040517f7810d12a00000000000000000000000000000000000000000000000000000000815236600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690637810d12a90602401602060405180830381865afa158015612373573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123979190614634565b905060005b8660400151518110156127e65760046000886040015183815181106123c3576123c3614370565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c082015285518690839081106124a8576124a8614370565b6020026020010151600001819052506124dd876040015182815181106124d0576124d0614370565b6020026020010151612f89565b8582815181106124ef576124ef614370565b602002602001015160600190600181111561250c5761250c614b2a565b9081600181111561251f5761251f614b2a565b815250506125838760400151828151811061253c5761253c614370565b6020026020010151848960800151848151811061255b5761255b614370565b602002602001015188858151811061257557612575614370565b60200260200101518c613034565b86838151811061259557612595614370565b60200260200101516020018784815181106125b2576125b2614370565b602002602001015160c00182815250821515151581525050508481815181106125dd576125dd614370565b6020026020010151602001511561260d576001846000018181516126019190614b59565b61ffff16905250612612565b6127d4565b61267885828151811061262757612627614370565b602002602001015160000151606001518860600151838151811061264d5761264d614370565b60200260200101518960a00151848151811061266b5761266b614370565b6020026020010151611c11565b86838151811061268a5761268a614370565b60200260200101516040018784815181106126a7576126a7614370565b602090810291909101015160800191909152901515905260c08801516126ce90600161439f565b6126dc9060ff166040614b74565b6103a48860a0015183815181106126f5576126f5614370565b602002602001015151612708919061435d565b612712919061435d565b85828151811061272457612724614370565b602002602001015160a001818152505084818151811061274657612746614370565b602002602001015160a0015184602001818151612763919061435d565b905250845185908290811061277a5761277a614370565b602002602001015160800151866127919190614b8b565b95506127d4876040015182815181106127ac576127ac614370565b6020026020010151848784815181106127c7576127c7614370565b6020026020010151613153565b806127de816145fc565b91505061239c565b50825161ffff166000036127fd5750505050505050565b6155f061280b366010614b74565b5a6128169088614b8b565b612820919061435d565b61282a919061435d565b8351909550611b58906128419061ffff1687614bcd565b61284b919061435d565b945060008060005b886040015151811015612a2f5786818151811061287257612872614370565b60200260200101516020015115612a1d5761290b8a8a60400151838151811061289d5761289d614370565b60200260200101518984815181106128b7576128b7614370565b6020026020010151608001518c600001518d602001518d8c602001518e89815181106128e5576128e5614370565b602002602001015160a001518c6128fc9190614b74565b6129069190614bcd565b613258565b6060880180519295509093508391612924908390614338565b6bffffffffffffffffffffffff16905250604086018051849190612949908390614338565b6bffffffffffffffffffffffff16905250865187908290811061296e5761296e614370565b60200260200101516040015115158960400151828151811061299257612992614370565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b84866129c79190614338565b8a85815181106129d9576129d9614370565b6020026020010151608001518c8e6080015187815181106129fc576129fc614370565b6020026020010151604051612a149493929190614be1565b60405180910390a35b80612a27816145fc565b915050612853565b505050604083810151336000908152600b602052919091208054600290612a6b9084906201000090046bffffffffffffffffffffffff16614338565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260600151601260000160008282829054906101000a90046bffffffffffffffffffffffff16612ac99190614338565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611c0f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610425565b3373ffffffffffffffffffffffffffffffffffffffff821603612c00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610425565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015290612e72576000816060015185612d0e9190614c1e565b90506000612d1c8583614c43565b90508083604001818151612d309190614338565b6bffffffffffffffffffffffff16905250612d4b8582614c6e565b83606001818151612d5c9190614338565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b6000808a8a8a8a8a8a8a8a8a604051602001612ea299989796959493929190614c9e565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000612158825490565b6000612f3e83836133db565b9392505050565b6000612f3e8373ffffffffffffffffffffffffffffffffffffffff8416613405565b6000612f3e8373ffffffffffffffffffffffffffffffffffffffff84166134ff565b6000818160045b600f811015613016577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612fce57612fce614370565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461300457506000949350505050565b8061300e816145fc565b915050612f90565b5081600f1a600181111561302c5761302c614b2a565b949350505050565b60008080808560600151600181111561304f5761304f614b2a565b0361307557613061888888888861354e565b61307057600092509050613149565b6130ed565b60018560600151600181111561308d5761308d614b2a565b036130bb5760006130a0898989886136d9565b92509050806130b55750600092509050613149565b506130ed565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516040015163ffffffff16871061314257877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd56368760405161312f9190613b44565b60405180910390a2600092509050613149565b6001925090505b9550959350505050565b60008160600151600181111561316b5761316b614b2a565b036131cf57600083815260046020526040902060010180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff16780100000000000000000000000000000000000000000000000063ffffffff851602179055505050565b6001816060015160018111156131e7576131e7614b2a565b036132535760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008061326b898886868a8a60016138e7565b60008a8152600460205260408120600101549294509092506c010000000000000000000000009091046bffffffffffffffffffffffff16906132ad8385614338565b9050836bffffffffffffffffffffffff16826bffffffffffffffffffffffff1610156132e157509150600090508180613314565b806bffffffffffffffffffffffff16826bffffffffffffffffffffffff1610156133145750806133118482614c1e565b92505b60008a81526004602052604090206001018054829190600c906133569084906c0100000000000000000000000090046bffffffffffffffffffffffff16614c1e565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008c81526004602052604081206001018054859450909261339f91859116614338565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505097509795505050505050565b60008260000182815481106133f2576133f2614370565b9060005260206000200154905092915050565b600081815260018301602052604081205480156134ee576000613429600183614b8b565b855490915060009061343d90600190614b8b565b90508181146134a257600086600001828154811061345d5761345d614370565b906000526020600020015490508087600001848154811061348057613480614370565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134b3576134b3614d33565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612158565b6000915050612158565b5092915050565b600081815260018301602052604081205461354657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612158565b506000612158565b600080848060200190518101906135659190614d62565b845160c00151815191925063ffffffff908116911610156135c257867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8866040516135b09190613b44565b60405180910390a260009150506136d0565b826101200151801561368357506020810151158015906136835750602081015161014084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa15801561365c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136809190614634565b14155b806136955750805163ffffffff168611155b156136ca57867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301866040516135b09190613b44565b60019150505b95945050505050565b6000806000848060200190518101906136f29190614dba565b905060008782600001518360200151846040015160405160200161375494939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b604051602081830303815290604052805190602001209050846101200151801561383057506080820151158015906138305750608082015161014086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061382d9190614634565b14155b80613845575086826060015163ffffffff1610155b1561388f57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc3018760405161387a9190613b44565b60405180910390a26000935091506138de9050565b60008181526008602052604090205460ff16156138d657877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e88760405161387a9190613b44565b600193509150505b94509492505050565b60008060008960a0015161ffff16866139009190614b74565b905083801561390e5750803a105b1561391657503a5b600085886139248b8d61435d565b61392e9085614b74565b613938919061435d565b61394a90670de0b6b3a7640000614b74565b6139549190614bcd565b905060008b6040015163ffffffff1664e8d4a510006139739190614b74565b60208d0151889063ffffffff168b61398b8f88614b74565b613995919061435d565b6139a390633b9aca00614b74565b6139ad9190614b74565b6139b79190614bcd565b6139c1919061435d565b90506b033b2e3c9fd0803ce80000006139da828461435d565b1115613a12576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909b909a5098505050505050505050565b5080546000825590600052602060002090810190610bb19190613acb565b828054828255906000526020600020908101928215613abb579160200282015b82811115613abb57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613a61565b50613ac7929150613acb565b5090565b5b80821115613ac75760008155600101613acc565b6000815180845260005b81811015613b0657602081850181015186830182015201613aea565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000612f3e6020830184613ae0565b73ffffffffffffffffffffffffffffffffffffffff81168114610bb157600080fd5b8035613b8481613b57565b919050565b60008083601f840112613b9b57600080fd5b50813567ffffffffffffffff811115613bb357600080fd5b602083019150836020828501011115613bcb57600080fd5b9250929050565b60008060008060608587031215613be857600080fd5b8435613bf381613b57565b935060208501359250604085013567ffffffffffffffff811115613c1657600080fd5b613c2287828801613b89565b95989497509550505050565b600080600060408486031215613c4357600080fd5b83359250602084013567ffffffffffffffff811115613c6157600080fd5b613c6d86828701613b89565b9497909650939450505050565b60008083601f840112613c8c57600080fd5b50813567ffffffffffffffff811115613ca457600080fd5b6020830191508360208260051b8501011115613bcb57600080fd5b60008060008060008060008060e0898b031215613cdb57600080fd5b606089018a811115613cec57600080fd5b8998503567ffffffffffffffff80821115613d0657600080fd5b613d128c838d01613b89565b909950975060808b0135915080821115613d2b57600080fd5b613d378c838d01613c7a565b909750955060a08b0135915080821115613d5057600080fd5b50613d5d8b828c01613c7a565b999c989b50969995989497949560c00135949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610220810167ffffffffffffffff81118282101715613dc957613dc9613d76565b60405290565b60405160c0810167ffffffffffffffff81118282101715613dc957613dc9613d76565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613e3957613e39613d76565b604052919050565b600067ffffffffffffffff821115613e5b57613e5b613d76565b5060051b60200190565b600082601f830112613e7657600080fd5b81356020613e8b613e8683613e41565b613df2565b82815260059290921b84018101918181019086841115613eaa57600080fd5b8286015b84811015613ece578035613ec181613b57565b8352918301918301613eae565b509695505050505050565b803560ff81168114613b8457600080fd5b600082601f830112613efb57600080fd5b813567ffffffffffffffff811115613f1557613f15613d76565b613f4660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613df2565b818152846020838601011115613f5b57600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff81168114613b8457600080fd5b60008060008060008060c08789031215613fa957600080fd5b863567ffffffffffffffff80821115613fc157600080fd5b613fcd8a838b01613e65565b97506020890135915080821115613fe357600080fd5b613fef8a838b01613e65565b9650613ffd60408a01613ed9565b9550606089013591508082111561401357600080fd5b61401f8a838b01613eea565b945061402d60808a01613f78565b935060a089013591508082111561404357600080fd5b5061405089828a01613eea565b9150509295509295509295565b60006020828403121561406f57600080fd5b8135612f3e81613b57565b63ffffffff81168114610bb157600080fd5b8035613b848161407a565b62ffffff81168114610bb157600080fd5b8035613b8481614097565b61ffff81168114610bb157600080fd5b8035613b84816140b3565b6bffffffffffffffffffffffff81168114610bb157600080fd5b8035613b84816140ce565b8015158114610bb157600080fd5b8035613b84816140f3565b6000610220828403121561411f57600080fd5b614127613da5565b90506141328261408c565b81526141406020830161408c565b60208201526141516040830161408c565b6040820152614162606083016140a8565b6060820152614173608083016140c3565b608082015261418460a083016140e8565b60a082015261419560c0830161408c565b60c08201526141a660e0830161408c565b60e08201526101006141b981840161408c565b908201526101206141cb83820161408c565b90820152610140828101359082015261016080830135908201526101806141f3818401613b79565b908201526101a08281013567ffffffffffffffff81111561421357600080fd5b61421f85828601613e65565b8284015250506101c0614233818401613b79565b908201526101e0614245838201613b79565b90820152610200614257838201614101565b9082015292915050565b60008060008060008060c0878903121561427a57600080fd5b863567ffffffffffffffff8082111561429257600080fd5b61429e8a838b01613e65565b975060208901359150808211156142b457600080fd5b6142c08a838b01613e65565b96506142ce60408a01613ed9565b955060608901359150808211156142e457600080fd5b61401f8a838b0161410c565b60006020828403121561430257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff8181168382160190808211156134f8576134f8614309565b8082018082111561215857612158614309565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60ff818116838216019081111561215857612158614309565b8051613b848161407a565b8051613b8481614097565b8051613b84816140b3565b8051613b84816140ce565b8051613b8481613b57565b600082601f83011261440057600080fd5b81516020614410613e8683613e41565b82815260059290921b8401810191818101908684111561442f57600080fd5b8286015b84811015613ece57805161444681613b57565b8352918301918301614433565b8051613b84816140f3565b60006020828403121561447057600080fd5b815167ffffffffffffffff8082111561448857600080fd5b90830190610220828603121561449d57600080fd5b6144a5613da5565b6144ae836143b8565b81526144bc602084016143b8565b60208201526144cd604084016143b8565b60408201526144de606084016143c3565b60608201526144ef608084016143ce565b608082015261450060a084016143d9565b60a082015261451160c084016143b8565b60c082015261452260e084016143b8565b60e08201526101006145358185016143b8565b908201526101206145478482016143b8565b908201526101408381015190820152610160808401519082015261018061456f8185016143e4565b908201526101a0838101518381111561458757600080fd5b614593888287016143ef565b8284015250506101c091506145a98284016143e4565b828201526101e091506145bd8284016143e4565b8282015261020091506145d1828401614453565b91810191909152949350505050565b60ff81811683821602908116908181146134f8576134f8614309565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361462d5761462d614309565b5060010190565b60006020828403121561464657600080fd5b5051919050565b63ffffffff8181168382160190808211156134f8576134f8614309565b600081518084526020808501945080840160005b838110156146b057815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161467e565b509495945050505050565b602081526146d260208201835163ffffffff169052565b600060208301516146eb604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006147648185018363ffffffff169052565b840151905061012061477d8482018363ffffffff169052565b84015190506101406147968482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06147d98185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506102206101c081818601526147f961024086018461466a565b908601519092506101e06148248682018373ffffffffffffffffffffffffffffffffffffffff169052565b860151905061020061484d8682018373ffffffffffffffffffffffffffffffffffffffff169052565b90950151151593019290925250919050565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261488f8184018a61466a565b905082810360808401526148a3818961466a565b905060ff871660a084015282810360c08401526148c08187613ae0565b905067ffffffffffffffff851660e08401528281036101008401526148e58185613ae0565b9c9b505050505050505050505050565b82815260406020820152600061302c6040830184613ae0565b6000806040838503121561492157600080fd5b825161492c816140f3565b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261497357600080fd5b81356020614983613e8683613e41565b82815260059290921b840181019181810190868411156149a257600080fd5b8286015b84811015613ece57803583529183019183016149a6565b600082601f8301126149ce57600080fd5b813560206149de613e8683613e41565b82815260059290921b840181019181810190868411156149fd57600080fd5b8286015b84811015613ece57803567ffffffffffffffff811115614a215760008081fd5b614a2f8986838b0101613eea565b845250918301918301614a01565b600060208284031215614a4f57600080fd5b813567ffffffffffffffff80821115614a6757600080fd5b9083019060c08286031215614a7b57600080fd5b614a83613dcf565b8235815260208301356020820152604083013582811115614aa357600080fd5b614aaf87828601614962565b604083015250606083013582811115614ac757600080fd5b614ad387828601614962565b606083015250608083013582811115614aeb57600080fd5b614af7878286016149bd565b60808301525060a083013582811115614b0f57600080fd5b614b1b878286016149bd565b60a08301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff8181168382160190808211156134f8576134f8614309565b808202811582820484141761215857612158614309565b8181038181111561215857612158614309565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082614bdc57614bdc614b9e565b500490565b6bffffffffffffffffffffffff85168152836020820152826040820152608060608201526000614c146080830184613ae0565b9695505050505050565b6bffffffffffffffffffffffff8281168282160390808211156134f8576134f8614309565b60006bffffffffffffffffffffffff80841680614c6257614c62614b9e565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114614c9657614c96614309565b505092915050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614ce58285018b61466a565b91508382036080850152614cf9828a61466a565b915060ff881660a085015283820360c0850152614d168288613ae0565b90861660e085015283810361010085015290506148e58185613ae0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600060408284031215614d7457600080fd5b6040516040810181811067ffffffffffffffff82111715614d9757614d97613d76565b6040528251614da58161407a565b81526020928301519281019290925250919050565b600060a08284031215614dcc57600080fd5b60405160a0810181811067ffffffffffffffff82111715614def57614def613d76565b806040525082518152602083015160208201526040830151614e108161407a565b60408201526060830151614e238161407a565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a",
}
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 1d460036fa0..97f0cfb113a 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
@@ -76,7 +76,7 @@ type AutomationRegistryBase23PaymentReceipt struct {
var AutomationRegistryMetaData = &bind.MetaData{
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\":\"contractIERC20Metadata\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"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\"},{\"components\":[{\"internalType\":\"uint96\",\"name\":\"gasChargeInBillingToken\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"premiumInBillingToken\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"gasReimbursementInJuels\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"premiumInJuels\",\"type\":\"uint96\"},{\"internalType\":\"contractIERC20Metadata\",\"name\":\"billingToken\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"linkUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"nativeUSD\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"billingUSD\",\"type\":\"uint96\"}],\"indexed\":false,\"internalType\":\"structAutomationRegistryBase2_3.PaymentReceipt\",\"name\":\"receipt\",\"type\":\"tuple\"}],\"name\":\"UpkeepCharged\",\"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\":[],\"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\":\"contractIERC20Metadata[]\",\"name\":\"billingTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"gasFeePPB\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"flatFeeMilliCents\",\"type\":\"uint24\"},{\"internalType\":\"contractAggregatorV3Interface\",\"name\":\"priceFeed\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"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: "0x6101806040523480156200001257600080fd5b506040516200651f3803806200651f83398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051615e07620007186000396000818160b30152610186015260005050600050506000505060005050600061379a015260005050600081816113710152612dc30152615e076000f3fe6080604052600436106100b15760003560e01c80638da5cb5b11610069578063b1dc65a41161004e578063b1dc65a4146102cb578063e3d0e712146102eb578063f2fde38b1461030b576100b1565b80638da5cb5b1461025a578063afcb95d714610285576100b1565b8063349e8cca1161009a578063349e8cca1461017757806379ba5097146101cb57806381ff7048146101e0576100b1565b80630870d3a1146100f8578063181f5a7714610118575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156100f1573d6000f35b3d6000fd5b005b34801561010457600080fd5b506100f6610113366004614b7b565b61032b565b34801561012457600080fd5b506101616040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b60405161016e9190614cf7565b60405180910390f35b34801561018357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016e565b3480156101d757600080fd5b506100f6610c0f565b3480156101ec57600080fd5b5061023760175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff94851681529390921660208401529082015260600161016e565b34801561026657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101a6565b34801561029157600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff169082015260600161016e565b3480156102d757600080fd5b506100f66102e6366004614d56565b610d11565b3480156102f757600080fd5b506100f6610306366004614e3b565b611051565b34801561031757600080fd5b506100f6610326366004614f08565b61108b565b61033361109f565b601f8851111561036f576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036103ac576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806103cb57506103c3866003614f54565b60ff16885111155b15610402576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182511461043d576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104478282611122565b610451888861175a565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506000601660010160189054906101000a900463ffffffff1690506000866101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107259190614f70565b6017549091506000906107579074010000000000000000000000000000000000000000900463ffffffff166001614f89565b9050604051806101600160405280896060015173ffffffffffffffffffffffffffffffffffffffff168152602001896000015163ffffffff168152602001896020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200189610100015173ffffffffffffffffffffffffffffffffffffffff1681526020018263ffffffff1681526020018363ffffffff168152602001896040015163ffffffff16815260200189610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018960c0015163ffffffff1681526020018960e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050876101600151601981905550876101800151601a81905550876101a00151601b81905550600088604051602001610a9a9190614ff7565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610aff904690309074010000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f611e19565b6013556000610b0e6009611ec3565b90505b8015610b4b57610b38610b30610b2860018461517d565b600990611ed3565b600990611ee6565b5080610b4381615190565b915050610b11565b5060005b896101c0015151811015610ba257610b8f8a6101c001518281518110610b7757610b776151c5565b60200260200101516009611f0890919063ffffffff16565b5080610b9a816151f4565b915050610b4f565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0584601354601660010160149054906101000a900463ffffffff168f8f8f878f8f604051610bf99998979695949392919061522c565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005a90506000610d238660406152c2565b610d2f896101446152d9565b610d3991906152d9565b9050368114610d74576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff1661010082015290610ed3576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16610f1c576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548b3514610f58576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6080810151610f689060016152ec565b60ff1687141580610f795750868514155b15610fb0576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc08b8b8b8b8b8b8b8b611f2a565b6000610fcc8b8b612193565b905060208c0135600881901c63ffffffff16610fe984848861224c565b836020015163ffffffff168163ffffffff16111561104157601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b5050505050505050505050505050565b60008060008580602001905181019061106a9190615472565b925092509250611080898989868989888861032b565b505050505050505050565b61109361109f565b61109c81612e39565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611120576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c8c565b565b60005b6024548110156111e0576022600060248381548110611146576111466151c5565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055806111d8816151f4565b915050611125565b506111ed602460006145cf565b60255460ff1660005b8351811015611754576000848281518110611213576112136151c5565b602002602001015190506000848381518110611231576112316151c5565b602002602001015190508173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa919061561d565b60ff16816060015160ff161415806113385750806040015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611330919061561d565b60ff16600814155b1561136f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156113db575060018460018111156113d9576113d961563a565b145b15611412576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216158061144d5750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611484576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260226020526040902054670100000000000000900416156114ee576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018181019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec401805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216821790925560008181526022602090815260409182902086518154928801518489015160608a015160ff167b01000000000000000000000000000000000000000000000000000000027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff9190981667010000000000000002167fffffffff000000000000000000000000000000000000000000ffffffffffffff62ffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000090951663ffffffff9093169290921793909317929092169190911793909317835560808501519383019390935560a0840151600290920180546bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009093169290921790915590517fca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba390611737908490600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b60405180910390a25050808061174c906151f4565b9150506111f6565b50505050565b600e546014546bffffffffffffffffffffffff1660005b600e548110156117cd576117ba600e8281548110611791576117916151c5565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168385612f2e565b50806117c5816151f4565b915050611771565b5060255460009060ff16815b600e5481101561193e57600e81815481106117f6576117f66151c5565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c929184908110611833576118336151c5565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905560018260018111156118d5576118d561563a565b14801561191a575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b1561192c5761192a600f84611f08565b505b80611936816151f4565b9150506117d9565b5061194b600d60006145cf565b611957600e60006145cf565b6040805160808101825260008082526020820181905291810182905260608101829052905b8751811015611de757600c600089838151811061199b5761199b6151c5565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611a06576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16888281518110611a3057611a306151c5565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611a85576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008a8481518110611ab657611ab66151c5565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558651879082908110611b5e57611b5e6151c5565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611bce576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250611c89576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055836001811115611dc357611dc361563a565b03611dd557611dd3600f85611ee6565b505b80611ddf816151f4565b91505061197c565b508651611dfb90600d9060208a01906145ed565b508551611e0f90600e9060208901906145ed565b5050505050505050565b6000808a8a8a8a8a8a8a8a8a604051602001611e3d99989796959493929190615669565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000611ecd825490565b92915050565b6000611edf8383613136565b9392505050565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff8416613160565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff841661325a565b60008787604051611f3c9291906156fe565b604051908190038120611f53918b9060200161570e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561212a57600185878360208110611fbf57611fbf6151c5565b611fcc91901a601b6152ec565b8c8c85818110611fde57611fde6151c5565b905060200201358b8b86818110611ff757611ff76151c5565b9050602002013560405160008152602001604052604051612034949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612056573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612104576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b840193508080612122906151f4565b915050611fa2565b50827e01010101010101010101010101010101010101010101010101010101010101841614612185576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6121cc6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006121da838501856157ff565b60408101515160608201515191925090811415806121fd57508082608001515114155b8061220d5750808260a001515114155b15612244576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff81111561226c5761226c614684565b60405190808252806020026020018201604052801561233857816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161228a5790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123fa9190614f70565b9050600086610100015173ffffffffffffffffffffffffffffffffffffffff166318b8f6136040518163ffffffff1660e01b8152600401602060405180830381865afa15801561244e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124729190614f70565b905060005b86604001515181101561290257600460008860400151838151811061249e5761249e6151c5565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915285518690839081106125c1576125c16151c5565b6020026020010151600001819052506125f6876040015182815181106125e9576125e96151c5565b60200260200101516132a9565b858281518110612608576126086151c5565b60200260200101516060019060018111156126255761262561563a565b908160018111156126385761263861563a565b8152505061269c87604001518281518110612655576126556151c5565b60200260200101518489608001518481518110612674576126746151c5565b602002602001015188858151811061268e5761268e6151c5565b60200260200101518c613354565b8683815181106126ae576126ae6151c5565b60200260200101516020018784815181106126cb576126cb6151c5565b602002602001015160c00182815250821515151581525050508481815181106126f6576126f66151c5565b602002602001015160200151156127265760018460000181815161271a91906158ec565b61ffff1690525061272b565b6128f0565b612791858281518110612740576127406151c5565b6020026020010151600001516080015188606001518381518110612766576127666151c5565b60200260200101518960a001518481518110612784576127846151c5565b6020026020010151613473565b8683815181106127a3576127a36151c5565b60200260200101516040018784815181106127c0576127c06151c5565b60200260200101516080018281525082151515158152505050876080015160016127ea91906152ec565b6127f89060ff1660406152c2565b6103a48860a001518381518110612811576128116151c5565b60200260200101515161282491906152d9565b61282e91906152d9565b858281518110612840576128406151c5565b602002602001015160a0018181525050848181518110612862576128626151c5565b602002602001015160a001518460600181815161287f91906152d9565b9052508451859082908110612896576128966151c5565b602002602001015160800151866128ad919061517d565b95506128f0876040015182815181106128c8576128c86151c5565b6020026020010151848784815181106128e3576128e36151c5565b602002602001015161368e565b806128fa816151f4565b915050612477565b50825161ffff166000036129195750505050505050565b61c8006129273660106152c2565b5a612932908861517d565b61293c91906152d9565b61294691906152d9565b83519095506137789061295d9061ffff1687615936565b61296791906152d9565b604080516080810182526000808252602082018190529181018290526060810182905291965061299689613793565b905060005b886040015151811015612cd2578681815181106129ba576129ba6151c5565b60200260200101516020015115612cc057801580612a525750866129df60018361517d565b815181106129ef576129ef6151c5565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff16878281518110612a2857612a286151c5565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1614155b15612a8657612a838a888381518110612a6d57612a6d6151c5565b602002602001015160000151610100015161387d565b92505b6000612ba48b6040518061012001604052808b8681518110612aaa57612aaa6151c5565b60200260200101516080015181526020018c81526020018a606001518c8781518110612ad857612ad86151c5565b602002602001015160a001518a612aef91906152c2565b612af99190615936565b81526020018d6000015181526020018d6020015181526020018681526020018b8681518110612b2a57612b2a6151c5565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c604001518581518110612b7957612b796151c5565b60200260200101518b8681518110612b9357612b936151c5565b6020026020010151600001516139f9565b9050806060015187604001818151612bbc919061594a565b6bffffffffffffffffffffffff169052506040810151602088018051612be390839061594a565b6bffffffffffffffffffffffff169052508751889083908110612c0857612c086151c5565b60200260200101516040015115158a604001518381518110612c2c57612c2c6151c5565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b83602001518460000151612c69919061594a565b8b8681518110612c7b57612c7b6151c5565b6020026020010151608001518d8f608001518881518110612c9e57612c9e6151c5565b6020026020010151604051612cb6949392919061596f565b60405180910390a3505b80612cca816151f4565b91505061299b565b505050602083810151336000908152600b90925260409091208054600290612d0f9084906201000090046bffffffffffffffffffffffff1661594a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff16612d6d919061594a565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082604001518360200151612daf919061594a565b6bffffffffffffffffffffffff16602160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612e2b91906152d9565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612eb8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c8c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e010000000000000000000000000000900490911660608201529061312a576000816060015185612fc691906159ac565b90506000612fd485836159d1565b90508083604001818151612fe8919061594a565b6bffffffffffffffffffffffff1690525061300385826159fc565b83606001818151613014919061594a565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b600082600001828154811061314d5761314d6151c5565b9060005260206000200154905092915050565b6000818152600183016020526040812054801561324957600061318460018361517d565b85549091506000906131989060019061517d565b90508181146131fd5760008660000182815481106131b8576131b86151c5565b90600052602060002001549050808760000184815481106131db576131db6151c5565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061320e5761320e615a2c565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ecd565b6000915050611ecd565b5092915050565b60008181526001830160205260408120546132a157508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ecd565b506000611ecd565b6000818160045b600f811015613336577fff0000000000000000000000000000000000000000000000000000000000000082168382602081106132ee576132ee6151c5565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461332457506000949350505050565b8061332e816151f4565b9150506132b0565b5081600f1a600181111561334c5761334c61563a565b949350505050565b60008080808560600151600181111561336f5761336f61563a565b03613395576133818888888888613e68565b61339057600092509050613469565b61340d565b6001856060015160018111156133ad576133ad61563a565b036133db5760006133c089898988613ff2565b92509050806133d55750600092509050613469565b5061340d565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff16871061346257877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd56368760405161344f9190614cf7565b60405180910390a2600092509050613469565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156134d0576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090613545908590602401614cf7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906136189087908790600401615a5b565b60408051808303816000875af1158015613636573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061365a9190615a74565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b6000816060015160018111156136a6576136a661563a565b0361370a57600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b6001816060015160018111156137225761372261563a565b0361378e5760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613803573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138279190615abc565b5093505092505060008213158061383d57508042105b8061386d57506000846040015162ffffff1611801561386d5750613861814261517d565b846040015162ffffff16105b15613253575050601b5492915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa15801561396a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061398e9190615abc565b509350509250506000821315806139a457508042105b806139d457506000866040015162ffffff161180156139d457506139c8814261517d565b866040015162ffffff16105b156139e857600183015460608501526139f0565b606084018290525b50505092915050565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201529082015115613a8f5760008381526023602090815260409182902082518084018452905463ffffffff811680835262ffffff640100000000909204821692840192835260e089018051909401529051915191169101525b6000613a9b86866141ff565b60c0840151602082015182519293509091600091613ab89161594a565b60e08801515190915060ff16600060128210613ad5576001613aeb565b613ae082601261517d565b613aeb90600a615c2c565b9050600060128311613afe576001613b14565b613b0960128461517d565b613b1490600a615c2c565b905085600001516bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613bbc57849350613b90818b60800151613b5491906152c2565b838c60e0015160600151886bffffffffffffffffffffffff16613b7791906152c2565b613b8191906152c2565b613b8b9190615936565b61452d565b6bffffffffffffffffffffffff9081166040880152600060608801819052602088015285168652613ce2565b836bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613ce257849350613c4a86604001516bffffffffffffffffffffffff16828c60800151613c0991906152c2565b848d60e0015160600151896bffffffffffffffffffffffff16613c2c91906152c2565b613c3691906152c2565b613c409190615936565b613b8b919061517d565b6bffffffffffffffffffffffff1660608088019190915260e08b01510151613cce90613c779084906152c2565b6001848d60e0015160600151613c8d91906152c2565b613c97919061517d565b838d608001518a606001516bffffffffffffffffffffffff16613cba91906152c2565b613cc491906152c2565b613b8191906152d9565b6bffffffffffffffffffffffff1660208701525b60008981526004602052604090206001018054859190601090613d2890849070010000000000000000000000000000000090046bffffffffffffffffffffffff166159ac565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b81526004602052604081206001018054928816935091613d839084906fffffffffffffffffffffffffffffffff16615c38565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550836bffffffffffffffffffffffff16602160008c60c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613e1a919061517d565b92505081905550887f801ba6ed51146ffe3e99d1dbd9dd0f4de6292e78a9a34c39c0183de17b3f40fc87604051613e519190615c61565b60405180910390a250939998505050505050505050565b60008084806020019051810190613e7f9190615d21565b845160e00151815191925063ffffffff90811691161015613edc57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e886604051613eca9190614cf7565b60405180910390a26000915050613fe9565b8260e001518015613f9c5750602081015115801590613f9c5750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613f75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f999190614f70565b14155b80613fae5750805163ffffffff168611155b15613fe357867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30186604051613eca9190614cf7565b60019150505b95945050505050565b60008060008480602001905181019061400b9190615d79565b905060008782600001518360200151846040015160405160200161406d94939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e00151801561414857506080820151158015906141485750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015614121573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141459190614f70565b14155b8061415d575086826060015163ffffffff1610155b156141a757877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516141929190614cf7565b60405180910390a26000935091506141f69050565b60008181526008602052604090205460ff16156141ee57877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516141929190614cf7565b600193509150505b94509492505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff16846060015161426a91906152c2565b9050836101000151801561427d5750803a105b1561428557503a5b6000601283116142965760016142ac565b6142a160128461517d565b6142ac90600a615c2c565b90506000601284106142bf5760016142d5565b6142ca84601261517d565b6142d590600a615c2c565b905060008660a001518760400151886020015189600001516142f791906152d9565b61430190876152c2565b61430b91906152d9565b61431591906152c2565b9050614358828860e001516060015161432e91906152c2565b6001848a60e001516060015161434491906152c2565b61434e919061517d565b613cc486856152c2565b6bffffffffffffffffffffffff168652608087015161437b90613b8b9083615936565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906143b49062ffffff16683635c9adc5dea000006152c2565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b6143e791906152c2565b6143f191906152d9565b6143fb91906152c2565b61440591906152c2565b61440f9190615936565b61441991906152d9565b905061445c848a60e001516060015161443291906152c2565b6001868c60e001516060015161444891906152c2565b614452919061517d565b613cc488856152c2565b6bffffffffffffffffffffffff166020890152608089015161448290613b8b9083615936565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a01919091528901516144c59061452d565b6bffffffffffffffffffffffff1660a0808a01919091528901516144e89061452d565b6bffffffffffffffffffffffff1660c089015260e08901516060015161450d9061452d565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b60006bffffffffffffffffffffffff8211156145cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610c8c565b5090565b508054600082559060005260206000209081019061109c919061466f565b828054828255906000526020600020908101928215614667579160200282015b8281111561466757825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90911617825560209092019160019091019061460d565b506145cb9291505b5b808211156145cb5760008155600101614670565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff811182821017156146d7576146d7614684565b60405290565b60405160c0810167ffffffffffffffff811182821017156146d7576146d7614684565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561474757614747614684565b604052919050565b600067ffffffffffffffff82111561476957614769614684565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461109c57600080fd5b80356147a081614773565b919050565b600082601f8301126147b657600080fd5b813560206147cb6147c68361474f565b614700565b82815260059290921b840181019181810190868411156147ea57600080fd5b8286015b8481101561480e57803561480181614773565b83529183019183016147ee565b509695505050505050565b60ff8116811461109c57600080fd5b80356147a081614819565b63ffffffff8116811461109c57600080fd5b80356147a081614833565b801515811461109c57600080fd5b80356147a081614850565b62ffffff8116811461109c57600080fd5b80356147a081614869565b61ffff8116811461109c57600080fd5b80356147a081614885565b600061020082840312156148b357600080fd5b6148bb6146b3565b90506148c682614845565b81526148d460208301614845565b60208201526148e560408301614845565b60408201526148f660608301614795565b60608201526149076080830161485e565b608082015261491860a0830161487a565b60a082015261492960c08301614845565b60c082015261493a60e08301614845565b60e082015261010061494d818401614795565b9082015261012061495f838201614895565b90820152610140614971838201614795565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff8111156149b257600080fd5b6149be858286016147a5565b8284015250506101e06149d2818401614795565b9082015292915050565b803567ffffffffffffffff811681146147a057600080fd5b600082601f830112614a0557600080fd5b813567ffffffffffffffff811115614a1f57614a1f614684565b614a5060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614700565b818152846020838601011115614a6557600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461109c57600080fd5b600082601f830112614aad57600080fd5b81356020614abd6147c68361474f565b82815260c09283028501820192828201919087851115614adc57600080fd5b8387015b85811015614b6e5781818a031215614af85760008081fd5b614b006146dd565b8135614b0b81614833565b815281860135614b1a81614869565b81870152604082810135614b2d81614773565b90820152606082810135614b4081614819565b908201526080828101359082015260a080830135614b5d81614a82565b908201528452928401928101614ae0565b5090979650505050505050565b600080600080600080600080610100898b031215614b9857600080fd5b883567ffffffffffffffff80821115614bb057600080fd5b614bbc8c838d016147a5565b995060208b0135915080821115614bd257600080fd5b614bde8c838d016147a5565b9850614bec60408c01614828565b975060608b0135915080821115614c0257600080fd5b614c0e8c838d016148a0565b9650614c1c60808c016149dc565b955060a08b0135915080821115614c3257600080fd5b614c3e8c838d016149f4565b945060c08b0135915080821115614c5457600080fd5b614c608c838d016147a5565b935060e08b0135915080821115614c7657600080fd5b50614c838b828c01614a9c565b9150509295985092959890939650565b6000815180845260005b81811015614cb957602081850181015186830182015201614c9d565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611edf6020830184614c93565b60008083601f840112614d1c57600080fd5b50813567ffffffffffffffff811115614d3457600080fd5b6020830191508360208260051b8501011115614d4f57600080fd5b9250929050565b60008060008060008060008060e0898b031215614d7257600080fd5b606089018a811115614d8357600080fd5b8998503567ffffffffffffffff80821115614d9d57600080fd5b818b0191508b601f830112614db157600080fd5b813581811115614dc057600080fd5b8c6020828501011115614dd257600080fd5b6020830199508098505060808b0135915080821115614df057600080fd5b614dfc8c838d01614d0a565b909750955060a08b0135915080821115614e1557600080fd5b50614e228b828c01614d0a565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c08789031215614e5457600080fd5b863567ffffffffffffffff80821115614e6c57600080fd5b614e788a838b016147a5565b97506020890135915080821115614e8e57600080fd5b614e9a8a838b016147a5565b9650614ea860408a01614828565b95506060890135915080821115614ebe57600080fd5b614eca8a838b016149f4565b9450614ed860808a016149dc565b935060a0890135915080821115614eee57600080fd5b50614efb89828a016149f4565b9150509295509295509295565b600060208284031215614f1a57600080fd5b8135611edf81614773565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff818116838216029081169081811461325357613253614f25565b600060208284031215614f8257600080fd5b5051919050565b63ffffffff81811683821601908082111561325357613253614f25565b600081518084526020808501945080840160005b83811015614fec57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614fba565b509495945050505050565b6020815261500e60208201835163ffffffff169052565b60006020830151615027604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006150a68185018363ffffffff169052565b84015190506101206150cf8482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101406150e68482018361ffff169052565b840151905061016061510f8482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e080860182905291925090615157610220860184614fa6565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b81810381811115611ecd57611ecd614f25565b60008161519f5761519f614f25565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361522557615225614f25565b5060010190565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261525c8184018a614fa6565b905082810360808401526152708189614fa6565b905060ff871660a084015282810360c084015261528d8187614c93565b905067ffffffffffffffff851660e08401528281036101008401526152b28185614c93565b9c9b505050505050505050505050565b8082028115828204841417611ecd57611ecd614f25565b80820180821115611ecd57611ecd614f25565b60ff8181168382160190811115611ecd57611ecd614f25565b80516147a081614833565b80516147a081614773565b80516147a081614850565b80516147a081614869565b80516147a081614885565b600082601f83011261534d57600080fd5b8151602061535d6147c68361474f565b82815260059290921b8401810191818101908684111561537c57600080fd5b8286015b8481101561480e57805161539381614773565b8352918301918301615380565b600082601f8301126153b157600080fd5b815160206153c16147c68361474f565b82815260c092830285018201928282019190878511156153e057600080fd5b8387015b85811015614b6e5781818a0312156153fc5760008081fd5b6154046146dd565b815161540f81614833565b81528186015161541e81614869565b8187015260408281015161543181614773565b9082015260608281015161544481614819565b908201526080828101519082015260a08083015161546181614a82565b9082015284529284019281016153e4565b60008060006060848603121561548757600080fd5b835167ffffffffffffffff8082111561549f57600080fd5b9085019061020082880312156154b457600080fd5b6154bc6146b3565b6154c583615305565b81526154d360208401615305565b60208201526154e460408401615305565b60408201526154f560608401615310565b60608201526155066080840161531b565b608082015261551760a08401615326565b60a082015261552860c08401615305565b60c082015261553960e08401615305565b60e082015261010061554c818501615310565b9082015261012061555e848201615331565b90820152610140615570848201615310565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c080840151838111156155a957600080fd5b6155b58a82870161533c565b8284015250506101e06155c9818501615310565b9082015260208701519095509150808211156155e457600080fd5b6155f08783880161533c565b9350604086015191508082111561560657600080fd5b50615613868287016153a0565b9150509250925092565b60006020828403121561562f57600080fd5b8151611edf81614819565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526156b08285018b614fa6565b915083820360808501526156c4828a614fa6565b915060ff881660a085015283820360c08501526156e18288614c93565b90861660e085015283810361010085015290506152b28185614c93565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261573557600080fd5b813560206157456147c68361474f565b82815260059290921b8401810191818101908684111561576457600080fd5b8286015b8481101561480e5780358352918301918301615768565b600082601f83011261579057600080fd5b813560206157a06147c68361474f565b82815260059290921b840181019181810190868411156157bf57600080fd5b8286015b8481101561480e57803567ffffffffffffffff8111156157e35760008081fd5b6157f18986838b01016149f4565b8452509183019183016157c3565b60006020828403121561581157600080fd5b813567ffffffffffffffff8082111561582957600080fd5b9083019060c0828603121561583d57600080fd5b6158456146dd565b823581526020830135602082015260408301358281111561586557600080fd5b61587187828601615724565b60408301525060608301358281111561588957600080fd5b61589587828601615724565b6060830152506080830135828111156158ad57600080fd5b6158b98782860161577f565b60808301525060a0830135828111156158d157600080fd5b6158dd8782860161577f565b60a08301525095945050505050565b61ffff81811683821601908082111561325357613253614f25565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261594557615945615907565b500490565b6bffffffffffffffffffffffff81811683821601908082111561325357613253614f25565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006159a26080830184614c93565b9695505050505050565b6bffffffffffffffffffffffff82811682821603908082111561325357613253614f25565b60006bffffffffffffffffffffffff808416806159f0576159f0615907565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114615a2457615a24614f25565b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b82815260406020820152600061334c6040830184614c93565b60008060408385031215615a8757600080fd5b8251615a9281614850565b6020939093015192949293505050565b805169ffffffffffffffffffff811681146147a057600080fd5b600080600080600060a08688031215615ad457600080fd5b615add86615aa2565b9450602086015193506040860151925060608601519150615b0060808701615aa2565b90509295509295909350565b600181815b80851115615b6557817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615b4b57615b4b614f25565b80851615615b5857918102915b93841c9390800290615b11565b509250929050565b600082615b7c57506001611ecd565b81615b8957506000611ecd565b8160018114615b9f5760028114615ba957615bc5565b6001915050611ecd565b60ff841115615bba57615bba614f25565b50506001821b611ecd565b5060208310610133831016604e8410600b8410161715615be8575081810a611ecd565b615bf28383615b0c565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615c2457615c24614f25565b029392505050565b6000611edf8383615b6d565b6fffffffffffffffffffffffffffffffff81811683821601908082111561325357613253614f25565b6000610100820190506bffffffffffffffffffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401525073ffffffffffffffffffffffffffffffffffffffff608084015116608083015260a0830151615ce160a08401826bffffffffffffffffffffffff169052565b5060c0830151615d0160c08401826bffffffffffffffffffffffff169052565b5060e083015161325360e08401826bffffffffffffffffffffffff169052565b600060408284031215615d3357600080fd5b6040516040810181811067ffffffffffffffff82111715615d5657615d56614684565b6040528251615d6481614833565b81526020928301519281019290925250919050565b600060a08284031215615d8b57600080fd5b60405160a0810181811067ffffffffffffffff82111715615dae57615dae614684565b806040525082518152602083015160208201526040830151615dcf81614833565b60408201526060830151615de281614833565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a",
+ Bin: "0x6101806040523480156200001257600080fd5b50604051620065423803806200654283398101604081905262000035916200062f565b80816001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b91906200062f565b826001600160a01b031663226cf83c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010091906200062f565b836001600160a01b031663614486af6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016591906200062f565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca91906200062f565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f91906200062f565b866001600160a01b031663a08714c06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200026e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029491906200062f565b876001600160a01b031663c5b964e06040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f9919062000656565b886001600160a01b031663ac4dc59a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000338573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035e91906200062f565b3380600081620003b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620003e857620003e8816200056b565b5050506001600160a01b0380891660805287811660a05286811660c05285811660e052848116610100528316610120526025805483919060ff19166001838181111562000439576200043962000679565b0217905550806001600160a01b0316610140816001600160a01b03168152505060c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200049a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004c091906200068f565b60ff1660a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000504573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200052a91906200068f565b60ff16146200054c576040516301f86e1760e41b815260040160405180910390fd5b5050506001600160a01b039095166101605250620006b4945050505050565b336001600160a01b03821603620005c55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620003ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200062c57600080fd5b50565b6000602082840312156200064257600080fd5b81516200064f8162000616565b9392505050565b6000602082840312156200066957600080fd5b8151600281106200064f57600080fd5b634e487b7160e01b600052602160045260246000fd5b600060208284031215620006a257600080fd5b815160ff811681146200064f57600080fd5b60805160a05160c05160e05161010051610120516101405161016051615e2a620007186000396000818160b3015261018601526000505060005050600050506000505060006137bd015260005050600081816113710152612de60152615e2a6000f3fe6080604052600436106100b15760003560e01c80638da5cb5b11610069578063b1dc65a41161004e578063b1dc65a4146102cb578063e3d0e712146102eb578063f2fde38b1461030b576100b1565b80638da5cb5b1461025a578063afcb95d714610285576100b1565b8063349e8cca1161009a578063349e8cca1461017757806379ba5097146101cb57806381ff7048146101e0576100b1565b80630870d3a1146100f8578063181f5a7714610118575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156100f1573d6000f35b3d6000fd5b005b34801561010457600080fd5b506100f6610113366004614b9e565b61032b565b34801561012457600080fd5b506101616040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e332e30000000000000000081525081565b60405161016e9190614d1a565b60405180910390f35b34801561018357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016e565b3480156101d757600080fd5b506100f6610c0f565b3480156101ec57600080fd5b5061023760175460135463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff94851681529390921660208401529082015260600161016e565b34801561026657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101a6565b34801561029157600080fd5b50601354601454604080516000815260208101939093526c0100000000000000000000000090910463ffffffff169082015260600161016e565b3480156102d757600080fd5b506100f66102e6366004614d79565b610d11565b3480156102f757600080fd5b506100f6610306366004614e5e565b611051565b34801561031757600080fd5b506100f6610326366004614f2b565b61108b565b61033361109f565b601f8851111561036f576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560ff166000036103ac576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b865188511415806103cb57506103c3866003614f77565b60ff16885111155b15610402576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182511461043d576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104478282611122565b610451888861175a565b604051806101200160405280601460000160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001600063ffffffff1681526020018660a0015162ffffff16815260200186610120015161ffff1681526020018760ff168152602001601460000160169054906101000a900460ff1615158152602001601460000160179054906101000a900460ff1615158152602001866080015115158152602001866101e0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548162ffffff021916908362ffffff16021790555060608201518160000160136101000a81548161ffff021916908361ffff16021790555060808201518160000160156101000a81548160ff021916908360ff16021790555060a08201518160000160166101000a81548160ff02191690831515021790555060c08201518160000160176101000a81548160ff02191690831515021790555060e08201518160000160186101000a81548160ff0219169083151502179055506101008201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509050506000601660010160189054906101000a900463ffffffff1690506000866101e0015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610701573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107259190614f93565b6017549091506000906107579074010000000000000000000000000000000000000000900463ffffffff166001614fac565b9050604051806101600160405280896060015173ffffffffffffffffffffffffffffffffffffffff168152602001896000015163ffffffff168152602001896020015163ffffffff1681526020016016600001601c9054906101000a900463ffffffff1663ffffffff16815260200189610100015173ffffffffffffffffffffffffffffffffffffffff1681526020018263ffffffff1681526020018363ffffffff168152602001896040015163ffffffff16815260200189610140015173ffffffffffffffffffffffffffffffffffffffff1681526020018960c0015163ffffffff1681526020018960e0015163ffffffff16815250601660008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506101208201518160020160146101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160186101000a81548163ffffffff021916908363ffffffff160217905550905050876101600151601981905550876101800151601a81905550876101a00151601b81905550600088604051602001610a9a919061501a565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152919052601754909150610aff904690309074010000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f611e19565b6013556000610b0e6009611ec3565b90505b8015610b4b57610b38610b30610b286001846151a0565b600990611ed3565b600990611ee6565b5080610b43816151b3565b915050610b11565b5060005b896101c0015151811015610ba257610b8f8a6101c001518281518110610b7757610b776151e8565b60200260200101516009611f0890919063ffffffff16565b5080610b9a81615217565b915050610b4f565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0584601354601660010160149054906101000a900463ffffffff168f8f8f878f8f604051610bf99998979695949392919061524f565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60005a90506000610d238660406152e5565b610d2f896101446152fc565b610d3991906152fc565b9050368114610d74576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051610120810182526014546bffffffffffffffffffffffff8116825263ffffffff6c01000000000000000000000000820416602083015262ffffff7001000000000000000000000000000000008204169282019290925261ffff730100000000000000000000000000000000000000830416606082015260ff75010000000000000000000000000000000000000000008304811660808301527601000000000000000000000000000000000000000000008304811615801560a08401527701000000000000000000000000000000000000000000000084048216151560c0840152780100000000000000000000000000000000000000000000000090930416151560e082015260155473ffffffffffffffffffffffffffffffffffffffff1661010082015290610ed3576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff16610f1c576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6013548b3514610f58576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6080810151610f6890600161530f565b60ff1687141580610f795750868514155b15610fb0576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc08b8b8b8b8b8b8b8b611f2a565b6000610fcc8b8b612193565b905060208c0135600881901c63ffffffff16610fe984848861224c565b836020015163ffffffff168163ffffffff16111561104157601480547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff8416021790555b5050505050505050505050505050565b60008060008580602001905181019061106a9190615495565b925092509250611080898989868989888861032b565b505050505050505050565b61109361109f565b61109c81612e5c565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611120576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c8c565b565b60005b6024548110156111e0576022600060248381548110611146576111466151e8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffff00000000000000000000000000000000000000000000000000000000168155600181019190915560020180547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169055806111d881615217565b915050611125565b506111ed602460006145f2565b60255460ff1660005b8351811015611754576000848281518110611213576112136151e8565b602002602001015190506000848381518110611231576112316151e8565b602002602001015190508173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190615640565b60ff16816060015160ff161415806113385750806040015173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113309190615640565b60ff16600814155b1561136f576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480156113db575060018460018111156113d9576113d961565d565b145b15611412576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216158061144d5750604081015173ffffffffffffffffffffffffffffffffffffffff16155b15611484576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff828116600090815260226020526040902054670100000000000000900416156114ee576040517f357d0cc400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6024805460018181019092557f7cd332d19b93bcabe3cce7ca0c18a052f57e5fd03b4758a09f30f5ddc4b22ec401805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000909216821790925560008181526022602090815260409182902086518154928801518489015160608a015160ff167b01000000000000000000000000000000000000000000000000000000027fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff9190981667010000000000000002167fffffffff000000000000000000000000000000000000000000ffffffffffffff62ffffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000090951663ffffffff9093169290921793909317929092169190911793909317835560808501519383019390935560a0840151600290920180546bffffffffffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009093169290921790915590517fca93cbe727c73163ec538f71be6c0a64877d7f1f6dd35d5ca7cbaef3a3e34ba390611737908490600060c08201905063ffffffff835116825262ffffff602084015116602083015273ffffffffffffffffffffffffffffffffffffffff604084015116604083015260ff6060840151166060830152608083015160808301526bffffffffffffffffffffffff60a08401511660a083015292915050565b60405180910390a25050808061174c90615217565b9150506111f6565b50505050565b600e546014546bffffffffffffffffffffffff1660005b600e548110156117cd576117ba600e8281548110611791576117916151e8565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff168385612f51565b50806117c581615217565b915050611771565b5060255460009060ff16815b600e5481101561193e57600e81815481106117f6576117f66151e8565b6000918252602082200154600d805473ffffffffffffffffffffffffffffffffffffffff9092169550600c929184908110611833576118336151e8565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff9081168452838201949094526040928301822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559286168152600b909252902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905560018260018111156118d5576118d561565d565b14801561191a575073ffffffffffffffffffffffffffffffffffffffff83166000908152600b60205260409020546201000090046bffffffffffffffffffffffff1615155b1561192c5761192a600f84611f08565b505b8061193681615217565b9150506117d9565b5061194b600d60006145f2565b611957600e60006145f2565b6040805160808101825260008082526020820181905291810182905260608101829052905b8751811015611de757600c600089838151811061199b5761199b6151e8565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615611a06576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16888281518110611a3057611a306151e8565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611a85576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008a8481518110611ab657611ab66151e8565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558651879082908110611b5e57611b5e6151e8565b60200260200101519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611bce576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e01000000000000000000000000000090049092166060830152909250611c89576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180835260ff80831660208086019182526014546bffffffffffffffffffffffff9081166060880190815273ffffffffffffffffffffffffffffffffffffffff8a166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055836001811115611dc357611dc361565d565b03611dd557611dd3600f85611ee6565b505b80611ddf81615217565b91505061197c565b508651611dfb90600d9060208a0190614610565b508551611e0f90600e906020890190614610565b5050505050505050565b6000808a8a8a8a8a8a8a8a8a604051602001611e3d9998979695949392919061568c565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b6000611ecd825490565b92915050565b6000611edf8383613159565b9392505050565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff8416613183565b6000611edf8373ffffffffffffffffffffffffffffffffffffffff841661327d565b60008787604051611f3c929190615721565b604051908190038120611f53918b90602001615731565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b8881101561212a57600185878360208110611fbf57611fbf6151e8565b611fcc91901a601b61530f565b8c8c85818110611fde57611fde6151e8565b905060200201358b8b86818110611ff757611ff76151e8565b9050602002013560405160008152602001604052604051612034949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612056573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612104576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b84019350808061212290615217565b915050611fa2565b50827e01010101010101010101010101010101010101010101010101010101010101841614612185576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b6121cc6040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b60006121da83850185615822565b60408101515160608201515191925090811415806121fd57508082608001515114155b8061220d5750808260a001515114155b15612244576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b600082604001515167ffffffffffffffff81111561226c5761226c6146a7565b60405190808252806020026020018201604052801561233857816020015b6040805161020081018252600060e08201818152610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161228a5790505b50905060006040518060800160405280600061ffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160008152509050600085610100015173ffffffffffffffffffffffffffffffffffffffff166357e871e76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123fa9190614f93565b6101008701516040517f7810d12a00000000000000000000000000000000000000000000000000000000815236600482015291925060009173ffffffffffffffffffffffffffffffffffffffff90911690637810d12a90602401602060405180830381865afa158015612471573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124959190614f93565b905060005b8660400151518110156129255760046000886040015183815181106124c1576124c16151e8565b6020908102919091018101518252818101929092526040908101600020815161012081018352815460ff8082161515835261010080830490911615159583019590955263ffffffff620100008204811694830194909452660100000000000081048416606083015273ffffffffffffffffffffffffffffffffffffffff6a01000000000000000000009091048116608083015260018301546fffffffffffffffffffffffffffffffff811660a08401526bffffffffffffffffffffffff70010000000000000000000000000000000082041660c08401527c0100000000000000000000000000000000000000000000000000000000900490931660e08201526002909101549091169181019190915285518690839081106125e4576125e46151e8565b6020026020010151600001819052506126198760400151828151811061260c5761260c6151e8565b60200260200101516132cc565b85828151811061262b5761262b6151e8565b60200260200101516060019060018111156126485761264861565d565b9081600181111561265b5761265b61565d565b815250506126bf87604001518281518110612678576126786151e8565b60200260200101518489608001518481518110612697576126976151e8565b60200260200101518885815181106126b1576126b16151e8565b60200260200101518c613377565b8683815181106126d1576126d16151e8565b60200260200101516020018784815181106126ee576126ee6151e8565b602002602001015160c0018281525082151515158152505050848181518110612719576127196151e8565b602002602001015160200151156127495760018460000181815161273d919061590f565b61ffff1690525061274e565b612913565b6127b4858281518110612763576127636151e8565b6020026020010151600001516080015188606001518381518110612789576127896151e8565b60200260200101518960a0015184815181106127a7576127a76151e8565b6020026020010151613496565b8683815181106127c6576127c66151e8565b60200260200101516040018784815181106127e3576127e36151e8565b602002602001015160800182815250821515151581525050508760800151600161280d919061530f565b61281b9060ff1660406152e5565b6103a48860a001518381518110612834576128346151e8565b60200260200101515161284791906152fc565b61285191906152fc565b858281518110612863576128636151e8565b602002602001015160a0018181525050848181518110612885576128856151e8565b602002602001015160a00151846060018181516128a291906152fc565b90525084518590829081106128b9576128b96151e8565b602002602001015160800151866128d091906151a0565b9550612913876040015182815181106128eb576128eb6151e8565b602002602001015184878481518110612906576129066151e8565b60200260200101516136b1565b8061291d81615217565b91505061249a565b50825161ffff1660000361293c5750505050505050565b61c80061294a3660106152e5565b5a61295590886151a0565b61295f91906152fc565b61296991906152fc565b8351909550613778906129809061ffff1687615959565b61298a91906152fc565b60408051608081018252600080825260208201819052918101829052606081018290529196506129b9896137b6565b905060005b886040015151811015612cf5578681815181106129dd576129dd6151e8565b60200260200101516020015115612ce357801580612a75575086612a026001836151a0565b81518110612a1257612a126151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff16878281518110612a4b57612a4b6151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff1614155b15612aa957612aa68a888381518110612a9057612a906151e8565b60200260200101516000015161010001516138a0565b92505b6000612bc78b6040518061012001604052808b8681518110612acd57612acd6151e8565b60200260200101516080015181526020018c81526020018a606001518c8781518110612afb57612afb6151e8565b602002602001015160a001518a612b1291906152e5565b612b1c9190615959565b81526020018d6000015181526020018d6020015181526020018681526020018b8681518110612b4d57612b4d6151e8565b602002602001015160000151610100015173ffffffffffffffffffffffffffffffffffffffff168152602001878152602001600115158152508c604001518581518110612b9c57612b9c6151e8565b60200260200101518b8681518110612bb657612bb66151e8565b602002602001015160000151613a1c565b9050806060015187604001818151612bdf919061596d565b6bffffffffffffffffffffffff169052506040810151602088018051612c0690839061596d565b6bffffffffffffffffffffffff169052508751889083908110612c2b57612c2b6151e8565b60200260200101516040015115158a604001518381518110612c4f57612c4f6151e8565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b83602001518460000151612c8c919061596d565b8b8681518110612c9e57612c9e6151e8565b6020026020010151608001518d8f608001518881518110612cc157612cc16151e8565b6020026020010151604051612cd99493929190615992565b60405180910390a3505b80612ced81615217565b9150506129be565b505050602083810151336000908152600b90925260409091208054600290612d329084906201000090046bffffffffffffffffffffffff1661596d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508260400151601460000160008282829054906101000a90046bffffffffffffffffffffffff16612d90919061596d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555082604001518360200151612dd2919061596d565b6bffffffffffffffffffffffff16602160007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254612e4e91906152fc565b909155505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612edb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c8c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e010000000000000000000000000000900490911660608201529061314d576000816060015185612fe991906159cf565b90506000612ff785836159f4565b9050808360400181815161300b919061596d565b6bffffffffffffffffffffffff169052506130268582615a1f565b83606001818151613037919061596d565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b6000826000018281548110613170576131706151e8565b9060005260206000200154905092915050565b6000818152600183016020526040812054801561326c5760006131a76001836151a0565b85549091506000906131bb906001906151a0565b90508181146132205760008660000182815481106131db576131db6151e8565b90600052602060002001549050808760000184815481106131fe576131fe6151e8565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061323157613231615a4f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ecd565b6000915050611ecd565b5092915050565b60008181526001830160205260408120546132c457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ecd565b506000611ecd565b6000818160045b600f811015613359577fff000000000000000000000000000000000000000000000000000000000000008216838260208110613311576133116151e8565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461334757506000949350505050565b8061335181615217565b9150506132d3565b5081600f1a600181111561336f5761336f61565d565b949350505050565b6000808080856060015160018111156133925761339261565d565b036133b8576133a48888888888613e8b565b6133b35760009250905061348c565b613430565b6001856060015160018111156133d0576133d061565d565b036133fe5760006133e389898988614015565b92509050806133f8575060009250905061348c565b50613430565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84516060015163ffffffff16871061348557877fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636876040516134729190614d1a565b60405180910390a260009250905061348c565b6001925090505b9550959350505050565b601454600090819077010000000000000000000000000000000000000000000000900460ff16156134f3576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16770100000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090613568908590602401614d1a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d169061363b9087908790600401615a7e565b60408051808303816000875af1158015613659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367d9190615a97565b601480547fffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b6000816060015160018111156136c9576136c961565d565b0361372d57600083815260046020526040902060010180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff851602179055505050565b6001816060015160018111156137455761374561565d565b036137b15760c08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613826573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061384a9190615adf565b5093505092505060008213158061386057508042105b8061389057506000846040015162ffffff16118015613890575061388481426151a0565b846040015162ffffff16105b15613276575050601b5492915050565b60408051608081018252600080825260208083018281528385018381526060850184905273ffffffffffffffffffffffffffffffffffffffff878116855260229093528584208054640100000000810462ffffff1690925263ffffffff82169092527b01000000000000000000000000000000000000000000000000000000810460ff16855285517ffeaf968c00000000000000000000000000000000000000000000000000000000815295519495919484936701000000000000009092049091169163feaf968c9160048083019260a09291908290030181865afa15801561398d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b19190615adf565b509350509250506000821315806139c757508042105b806139f757506000866040015162ffffff161180156139f757506139eb81426151a0565b866040015162ffffff16105b15613a0b5760018301546060850152613a13565b606084018290525b50505092915050565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201529082015115613ab25760008381526023602090815260409182902082518084018452905463ffffffff811680835262ffffff640100000000909204821692840192835260e089018051909401529051915191169101525b6000613abe8686614222565b60c0840151602082015182519293509091600091613adb9161596d565b60e08801515190915060ff16600060128210613af8576001613b0e565b613b038260126151a0565b613b0e90600a615c4f565b9050600060128311613b21576001613b37565b613b2c6012846151a0565b613b3790600a615c4f565b905085600001516bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613bdf57849350613bb3818b60800151613b7791906152e5565b838c60e0015160600151886bffffffffffffffffffffffff16613b9a91906152e5565b613ba491906152e5565b613bae9190615959565b614550565b6bffffffffffffffffffffffff9081166040880152600060608801819052602088015285168652613d05565b836bffffffffffffffffffffffff16856bffffffffffffffffffffffff161015613d0557849350613c6d86604001516bffffffffffffffffffffffff16828c60800151613c2c91906152e5565b848d60e0015160600151896bffffffffffffffffffffffff16613c4f91906152e5565b613c5991906152e5565b613c639190615959565b613bae91906151a0565b6bffffffffffffffffffffffff1660608088019190915260e08b01510151613cf190613c9a9084906152e5565b6001848d60e0015160600151613cb091906152e5565b613cba91906151a0565b838d608001518a606001516bffffffffffffffffffffffff16613cdd91906152e5565b613ce791906152e5565b613ba491906152fc565b6bffffffffffffffffffffffff1660208701525b60008981526004602052604090206001018054859190601090613d4b90849070010000000000000000000000000000000090046bffffffffffffffffffffffff166159cf565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b81526004602052604081206001018054928816935091613da69084906fffffffffffffffffffffffffffffffff16615c5b565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff160217905550836bffffffffffffffffffffffff16602160008c60c0015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254613e3d91906151a0565b92505081905550887f801ba6ed51146ffe3e99d1dbd9dd0f4de6292e78a9a34c39c0183de17b3f40fc87604051613e749190615c84565b60405180910390a250939998505050505050505050565b60008084806020019051810190613ea29190615d44565b845160e00151815191925063ffffffff90811691161015613eff57867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e886604051613eed9190614d1a565b60405180910390a2600091505061400c565b8260e001518015613fbf5750602081015115801590613fbf5750602081015161010084015182516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015613f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fbc9190614f93565b14155b80613fd15750805163ffffffff168611155b1561400657867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30186604051613eed9190614d1a565b60019150505b95945050505050565b60008060008480602001905181019061402e9190615d9c565b905060008782600001518360200151846040015160405160200161409094939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508460e00151801561416b575060808201511580159061416b5750608082015161010086015160608401516040517f85df51fd00000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff909116906385df51fd90602401602060405180830381865afa158015614144573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141689190614f93565b14155b80614180575086826060015163ffffffff1610155b156141ca57877f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301876040516141b59190614d1a565b60405180910390a26000935091506142199050565b60008181526008602052604090205460ff161561421157877f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8876040516141b59190614d1a565b600193509150505b94509492505050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260008260e001516000015160ff1690506000846060015161ffff16846060015161428d91906152e5565b905083610100015180156142a05750803a105b156142a857503a5b6000601283116142b95760016142cf565b6142c46012846151a0565b6142cf90600a615c4f565b90506000601284106142e25760016142f8565b6142ed8460126151a0565b6142f890600a615c4f565b905060008660a0015187604001518860200151896000015161431a91906152fc565b61432490876152e5565b61432e91906152fc565b61433891906152e5565b905061437b828860e001516060015161435191906152e5565b6001848a60e001516060015161436791906152e5565b61437191906151a0565b613ce786856152e5565b6bffffffffffffffffffffffff168652608087015161439e90613bae9083615959565b6bffffffffffffffffffffffff1660408088019190915260e088015101516000906143d79062ffffff16683635c9adc5dea000006152e5565b9050600081633b9aca008a60a001518b60e001516020015163ffffffff168c604001518d600001518b61440a91906152e5565b61441491906152fc565b61441e91906152e5565b61442891906152e5565b6144329190615959565b61443c91906152fc565b905061447f848a60e001516060015161445591906152e5565b6001868c60e001516060015161446b91906152e5565b61447591906151a0565b613ce788856152e5565b6bffffffffffffffffffffffff16602089015260808901516144a590613bae9083615959565b6bffffffffffffffffffffffff16606089015260c089015173ffffffffffffffffffffffffffffffffffffffff166080808a01919091528901516144e890614550565b6bffffffffffffffffffffffff1660a0808a019190915289015161450b90614550565b6bffffffffffffffffffffffff1660c089015260e08901516060015161453090614550565b6bffffffffffffffffffffffff1660e08901525050505050505092915050565b60006bffffffffffffffffffffffff8211156145ee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610c8c565b5090565b508054600082559060005260206000209081019061109c9190614692565b82805482825590600052602060002090810192821561468a579160200282015b8281111561468a57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614630565b506145ee9291505b5b808211156145ee5760008155600101614693565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff811182821017156146fa576146fa6146a7565b60405290565b60405160c0810167ffffffffffffffff811182821017156146fa576146fa6146a7565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561476a5761476a6146a7565b604052919050565b600067ffffffffffffffff82111561478c5761478c6146a7565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff8116811461109c57600080fd5b80356147c381614796565b919050565b600082601f8301126147d957600080fd5b813560206147ee6147e983614772565b614723565b82815260059290921b8401810191818101908684111561480d57600080fd5b8286015b8481101561483157803561482481614796565b8352918301918301614811565b509695505050505050565b60ff8116811461109c57600080fd5b80356147c38161483c565b63ffffffff8116811461109c57600080fd5b80356147c381614856565b801515811461109c57600080fd5b80356147c381614873565b62ffffff8116811461109c57600080fd5b80356147c38161488c565b61ffff8116811461109c57600080fd5b80356147c3816148a8565b600061020082840312156148d657600080fd5b6148de6146d6565b90506148e982614868565b81526148f760208301614868565b602082015261490860408301614868565b6040820152614919606083016147b8565b606082015261492a60808301614881565b608082015261493b60a0830161489d565b60a082015261494c60c08301614868565b60c082015261495d60e08301614868565b60e08201526101006149708184016147b8565b908201526101206149828382016148b8565b908201526101406149948382016147b8565b90820152610160828101359082015261018080830135908201526101a080830135908201526101c08083013567ffffffffffffffff8111156149d557600080fd5b6149e1858286016147c8565b8284015250506101e06149f58184016147b8565b9082015292915050565b803567ffffffffffffffff811681146147c357600080fd5b600082601f830112614a2857600080fd5b813567ffffffffffffffff811115614a4257614a426146a7565b614a7360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614723565b818152846020838601011115614a8857600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461109c57600080fd5b600082601f830112614ad057600080fd5b81356020614ae06147e983614772565b82815260c09283028501820192828201919087851115614aff57600080fd5b8387015b85811015614b915781818a031215614b1b5760008081fd5b614b23614700565b8135614b2e81614856565b815281860135614b3d8161488c565b81870152604082810135614b5081614796565b90820152606082810135614b638161483c565b908201526080828101359082015260a080830135614b8081614aa5565b908201528452928401928101614b03565b5090979650505050505050565b600080600080600080600080610100898b031215614bbb57600080fd5b883567ffffffffffffffff80821115614bd357600080fd5b614bdf8c838d016147c8565b995060208b0135915080821115614bf557600080fd5b614c018c838d016147c8565b9850614c0f60408c0161484b565b975060608b0135915080821115614c2557600080fd5b614c318c838d016148c3565b9650614c3f60808c016149ff565b955060a08b0135915080821115614c5557600080fd5b614c618c838d01614a17565b945060c08b0135915080821115614c7757600080fd5b614c838c838d016147c8565b935060e08b0135915080821115614c9957600080fd5b50614ca68b828c01614abf565b9150509295985092959890939650565b6000815180845260005b81811015614cdc57602081850181015186830182015201614cc0565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611edf6020830184614cb6565b60008083601f840112614d3f57600080fd5b50813567ffffffffffffffff811115614d5757600080fd5b6020830191508360208260051b8501011115614d7257600080fd5b9250929050565b60008060008060008060008060e0898b031215614d9557600080fd5b606089018a811115614da657600080fd5b8998503567ffffffffffffffff80821115614dc057600080fd5b818b0191508b601f830112614dd457600080fd5b813581811115614de357600080fd5b8c6020828501011115614df557600080fd5b6020830199508098505060808b0135915080821115614e1357600080fd5b614e1f8c838d01614d2d565b909750955060a08b0135915080821115614e3857600080fd5b50614e458b828c01614d2d565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c08789031215614e7757600080fd5b863567ffffffffffffffff80821115614e8f57600080fd5b614e9b8a838b016147c8565b97506020890135915080821115614eb157600080fd5b614ebd8a838b016147c8565b9650614ecb60408a0161484b565b95506060890135915080821115614ee157600080fd5b614eed8a838b01614a17565b9450614efb60808a016149ff565b935060a0890135915080821115614f1157600080fd5b50614f1e89828a01614a17565b9150509295509295509295565b600060208284031215614f3d57600080fd5b8135611edf81614796565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff818116838216029081169081811461327657613276614f48565b600060208284031215614fa557600080fd5b5051919050565b63ffffffff81811683821601908082111561327657613276614f48565b600081518084526020808501945080840160005b8381101561500f57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101614fdd565b509495945050505050565b6020815261503160208201835163ffffffff169052565b6000602083015161504a604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015180151560a08401525060a083015162ffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006150c98185018363ffffffff169052565b84015190506101206150f28482018373ffffffffffffffffffffffffffffffffffffffff169052565b84015190506101406151098482018361ffff169052565b84015190506101606151328482018373ffffffffffffffffffffffffffffffffffffffff169052565b840151610180848101919091528401516101a0808501919091528401516101c0808501919091528401516102006101e08086018290529192509061517a610220860184614fc9565b95015173ffffffffffffffffffffffffffffffffffffffff169301929092525090919050565b81810381811115611ecd57611ecd614f48565b6000816151c2576151c2614f48565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361524857615248614f48565b5060010190565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261527f8184018a614fc9565b905082810360808401526152938189614fc9565b905060ff871660a084015282810360c08401526152b08187614cb6565b905067ffffffffffffffff851660e08401528281036101008401526152d58185614cb6565b9c9b505050505050505050505050565b8082028115828204841417611ecd57611ecd614f48565b80820180821115611ecd57611ecd614f48565b60ff8181168382160190811115611ecd57611ecd614f48565b80516147c381614856565b80516147c381614796565b80516147c381614873565b80516147c38161488c565b80516147c3816148a8565b600082601f83011261537057600080fd5b815160206153806147e983614772565b82815260059290921b8401810191818101908684111561539f57600080fd5b8286015b848110156148315780516153b681614796565b83529183019183016153a3565b600082601f8301126153d457600080fd5b815160206153e46147e983614772565b82815260c0928302850182019282820191908785111561540357600080fd5b8387015b85811015614b915781818a03121561541f5760008081fd5b615427614700565b815161543281614856565b8152818601516154418161488c565b8187015260408281015161545481614796565b908201526060828101516154678161483c565b908201526080828101519082015260a08083015161548481614aa5565b908201528452928401928101615407565b6000806000606084860312156154aa57600080fd5b835167ffffffffffffffff808211156154c257600080fd5b9085019061020082880312156154d757600080fd5b6154df6146d6565b6154e883615328565b81526154f660208401615328565b602082015261550760408401615328565b604082015261551860608401615333565b60608201526155296080840161533e565b608082015261553a60a08401615349565b60a082015261554b60c08401615328565b60c082015261555c60e08401615328565b60e082015261010061556f818501615333565b90820152610120615581848201615354565b90820152610140615593848201615333565b90820152610160838101519082015261018080840151908201526101a080840151908201526101c080840151838111156155cc57600080fd5b6155d88a82870161535f565b8284015250506101e06155ec818501615333565b90820152602087015190955091508082111561560757600080fd5b6156138783880161535f565b9350604086015191508082111561562957600080fd5b50615636868287016153c3565b9150509250925092565b60006020828403121561565257600080fd5b8151611edf8161483c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526156d38285018b614fc9565b915083820360808501526156e7828a614fc9565b915060ff881660a085015283820360c08501526157048288614cb6565b90861660e085015283810361010085015290506152d58185614cb6565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f83011261575857600080fd5b813560206157686147e983614772565b82815260059290921b8401810191818101908684111561578757600080fd5b8286015b84811015614831578035835291830191830161578b565b600082601f8301126157b357600080fd5b813560206157c36147e983614772565b82815260059290921b840181019181810190868411156157e257600080fd5b8286015b8481101561483157803567ffffffffffffffff8111156158065760008081fd5b6158148986838b0101614a17565b8452509183019183016157e6565b60006020828403121561583457600080fd5b813567ffffffffffffffff8082111561584c57600080fd5b9083019060c0828603121561586057600080fd5b615868614700565b823581526020830135602082015260408301358281111561588857600080fd5b61589487828601615747565b6040830152506060830135828111156158ac57600080fd5b6158b887828601615747565b6060830152506080830135828111156158d057600080fd5b6158dc878286016157a2565b60808301525060a0830135828111156158f457600080fd5b615900878286016157a2565b60a08301525095945050505050565b61ffff81811683821601908082111561327657613276614f48565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826159685761596861592a565b500490565b6bffffffffffffffffffffffff81811683821601908082111561327657613276614f48565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006159c56080830184614cb6565b9695505050505050565b6bffffffffffffffffffffffff82811682821603908082111561327657613276614f48565b60006bffffffffffffffffffffffff80841680615a1357615a1361592a565b92169190910492915050565b6bffffffffffffffffffffffff818116838216028082169190828114615a4757615a47614f48565b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b82815260406020820152600061336f6040830184614cb6565b60008060408385031215615aaa57600080fd5b8251615ab581614873565b6020939093015192949293505050565b805169ffffffffffffffffffff811681146147c357600080fd5b600080600080600060a08688031215615af757600080fd5b615b0086615ac5565b9450602086015193506040860151925060608601519150615b2360808701615ac5565b90509295509295909350565b600181815b80851115615b8857817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615b6e57615b6e614f48565b80851615615b7b57918102915b93841c9390800290615b34565b509250929050565b600082615b9f57506001611ecd565b81615bac57506000611ecd565b8160018114615bc25760028114615bcc57615be8565b6001915050611ecd565b60ff841115615bdd57615bdd614f48565b50506001821b611ecd565b5060208310610133831016604e8410600b8410161715615c0b575081810a611ecd565b615c158383615b2f565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615c4757615c47614f48565b029392505050565b6000611edf8383615b90565b6fffffffffffffffffffffffffffffffff81811683821601908082111561327657613276614f48565b6000610100820190506bffffffffffffffffffffffff8084511683528060208501511660208401528060408501511660408401528060608501511660608401525073ffffffffffffffffffffffffffffffffffffffff608084015116608083015260a0830151615d0460a08401826bffffffffffffffffffffffff169052565b5060c0830151615d2460c08401826bffffffffffffffffffffffff169052565b5060e083015161327660e08401826bffffffffffffffffffffffff169052565b600060408284031215615d5657600080fd5b6040516040810181811067ffffffffffffffff82111715615d7957615d796146a7565b6040528251615d8781614856565b81526020928301519281019290925250919050565b600060a08284031215615dae57600080fd5b60405160a0810181811067ffffffffffffffff82111715615dd157615dd16146a7565b806040525082518152602083015160208201526040830151615df281614856565b60408201526060830151615e0581614856565b6060820152608092830151928101929092525091905056fea164736f6c6343000813000a",
}
var AutomationRegistryABI = AutomationRegistryMetaData.ABI
diff --git a/core/gethwrappers/generated/chain_module_base/chain_module_base.go b/core/gethwrappers/generated/chain_module_base/chain_module_base.go
index bf98608aab7..19bc49298f5 100644
--- a/core/gethwrappers/generated/chain_module_base/chain_module_base.go
+++ b/core/gethwrappers/generated/chain_module_base/chain_module_base.go
@@ -29,8 +29,8 @@ var (
)
var ChainModuleBaseMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
- Bin: "0x608060405234801561001057600080fd5b5061015c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610093575b600080fd5b61008061007a3660046100f6565b50600090565b6040519081526020015b60405180910390f35b6000610080565b43610080565b6100806100ae3660046100f6565b6100c9565b6040805161012c8152600060208201520161008a565b600043821015806100e457506101006100e2834361010f565b115b156100f157506000919050565b504090565b60006020828403121561010857600080fd5b5035919050565b81810381811115610149577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000a",
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"l1Fee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maxL1Fee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b50610155806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637810d12a116100505780637810d12a1461006c57806385df51fd14610099578063de9ee35e146100ac57600080fd5b8063125441401461006c57806357e871e714610093575b600080fd5b61008061007a3660046100ef565b50600090565b6040519081526020015b60405180910390f35b43610080565b6100806100a73660046100ef565b6100c2565b6040805161012c8152600060208201520161008a565b600043821015806100dd57506101006100db8343610108565b115b156100ea57506000919050565b504090565b60006020828403121561010157600080fd5b5035919050565b81810381811115610142577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000813000a",
}
var ChainModuleBaseABI = ChainModuleBaseMetaData.ABI
@@ -213,9 +213,9 @@ func (_ChainModuleBase *ChainModuleBaseCallerSession) BlockNumber() (*big.Int, e
return _ChainModuleBase.Contract.BlockNumber(&_ChainModuleBase.CallOpts)
}
-func (_ChainModuleBase *ChainModuleBaseCaller) GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error) {
+func (_ChainModuleBase *ChainModuleBaseCaller) GetCurrentL1Fee(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) {
var out []interface{}
- err := _ChainModuleBase.contract.Call(opts, &out, "getCurrentL1Fee")
+ err := _ChainModuleBase.contract.Call(opts, &out, "getCurrentL1Fee", arg0)
if err != nil {
return *new(*big.Int), err
@@ -227,12 +227,12 @@ func (_ChainModuleBase *ChainModuleBaseCaller) GetCurrentL1Fee(opts *bind.CallOp
}
-func (_ChainModuleBase *ChainModuleBaseSession) GetCurrentL1Fee() (*big.Int, error) {
- return _ChainModuleBase.Contract.GetCurrentL1Fee(&_ChainModuleBase.CallOpts)
+func (_ChainModuleBase *ChainModuleBaseSession) GetCurrentL1Fee(arg0 *big.Int) (*big.Int, error) {
+ return _ChainModuleBase.Contract.GetCurrentL1Fee(&_ChainModuleBase.CallOpts, arg0)
}
-func (_ChainModuleBase *ChainModuleBaseCallerSession) GetCurrentL1Fee() (*big.Int, error) {
- return _ChainModuleBase.Contract.GetCurrentL1Fee(&_ChainModuleBase.CallOpts)
+func (_ChainModuleBase *ChainModuleBaseCallerSession) GetCurrentL1Fee(arg0 *big.Int) (*big.Int, error) {
+ return _ChainModuleBase.Contract.GetCurrentL1Fee(&_ChainModuleBase.CallOpts, arg0)
}
func (_ChainModuleBase *ChainModuleBaseCaller) GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
@@ -301,7 +301,7 @@ type ChainModuleBaseInterface interface {
BlockNumber(opts *bind.CallOpts) (*big.Int, error)
- GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error)
+ GetCurrentL1Fee(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error)
GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
diff --git a/core/gethwrappers/generated/chain_reader_tester/chain_reader_tester.go b/core/gethwrappers/generated/chain_reader_tester/chain_reader_tester.go
index 751df822696..c59a6f0f0d1 100644
--- a/core/gethwrappers/generated/chain_reader_tester/chain_reader_tester.go
+++ b/core/gethwrappers/generated/chain_reader_tester/chain_reader_tester.go
@@ -52,8 +52,8 @@ type TestStruct struct {
}
var ChainReaderTesterMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"Triggered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"fieldHash\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"TriggeredEventWithDynamicTopic\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"TriggeredWithFourTopics\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"addTestStruct\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAlterablePrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDifferentPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"getElementAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"NestedStruct\",\"type\":\"tuple\"}],\"internalType\":\"structTestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSliceValue\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"returnSeen\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"NestedStruct\",\"type\":\"tuple\"}],\"internalType\":\"structTestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"name\":\"setAlterablePrimitiveValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"triggerEvent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"triggerEventWithDynamicTopic\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"triggerWithFourTopics\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
- Bin: "0x608060405234801561001057600080fd5b50600180548082018255600082905260048082047fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6908101805460086003958616810261010090810a8088026001600160401b0391820219909416939093179093558654808801909755848704909301805496909516909202900a91820291021990921691909117905561181e806100a96000396000f3fe608060405234801561001057600080fd5b50600436106100c95760003560e01c80637f002d6711610081578063ef4e1ced1161005b578063ef4e1ced146101c0578063f6f871c8146101c7578063fbe9fbf6146101da57600080fd5b80637f002d671461017d578063ab5e0b3814610190578063dbfd7332146101ad57600080fd5b806349eac2ac116100b257806349eac2ac1461010c578063679004a41461011f5780636c9a43b61461013457600080fd5b80632c45576f146100ce5780633272b66c146100f7575b600080fd5b6100e16100dc366004610c2b565b6101ec565b6040516100ee9190610d8a565b60405180910390f35b61010a610105366004610ec9565b6104c7565b005b61010a61011a366004610fde565b61051c565b61012761081f565b6040516100ee91906110d0565b61010a61014236600461111e565b600280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055565b61010a61018b366004610fde565b6108ab565b6107c65b60405167ffffffffffffffff90911681526020016100ee565b61010a6101bb36600461114f565b610902565b6003610194565b6100e16101d5366004610fde565b61093f565b60025467ffffffffffffffff16610194565b6101f4610a48565b6000610201600184611192565b81548110610211576102116111cc565b6000918252602091829020604080516101008101909152600a90920201805460030b8252600181018054929391929184019161024c906111fb565b80601f0160208091040260200160405190810160405280929190818152602001828054610278906111fb565b80156102c55780601f1061029a576101008083540402835291602001916102c5565b820191906000526020600020905b8154815290600101906020018083116102a857829003601f168201915b5050509183525050600282015460ff166020808301919091526040805161040081018083529190930192916003850191826000855b825461010083900a900460ff168152602060019283018181049485019490930390920291018084116102fa57505050928452505050600482015473ffffffffffffffffffffffffffffffffffffffff1660208083019190915260058301805460408051828502810185018252828152940193928301828280156103b357602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610388575b5050509183525050600682015460170b6020808301919091526040805180820182526007808601805460f01b7fffff0000000000000000000000000000000000000000000000000000000000001683528351808501855260088801805490930b81526009880180549590970196939591948683019491939284019190610438906111fb565b80601f0160208091040260200160405190810160405280929190818152602001828054610464906111fb565b80156104b15780601f10610486576101008083540402835291602001916104b1565b820191906000526020600020905b81548152906001019060200180831161049457829003601f168201915b5050509190925250505090525090525092915050565b81816040516104d7929190611248565b60405180910390207f3d969732b1bbbb9f1d7eb9f3f14e4cb50a74d950b3ef916a397b85dfbab93c6783836040516105109291906112a1565b60405180910390a25050565b60006040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b602082015260400161060e8461139e565b905281546001808201845560009384526020938490208351600a9093020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff90931692909217825592820151919290919082019061067490826114f8565b5060408201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff90921691909117905560608201516106c29060038301906020610a97565b5060808201516004820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905560a08201518051610729916005840191602090910190610b2a565b5060c08201516006820180547fffffffffffffffff0000000000000000000000000000000000000000000000001677ffffffffffffffffffffffffffffffffffffffffffffffff90921691909117905560e082015180516007830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660f09290921c91909117815560208083015180516008860180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff90921691909117815591810151909190600986019061080c90826114f8565b5050505050505050505050505050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156108a157602002820191906000526020600020906000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff168152602001906008019060208260070104928301926001038202915080841161085c5790505b5050505050905090565b8960030b7f7188419dcd8b51877b71766f075f3626586c0ff190e7d056aa65ce9acb649a3d8a8a8a8a8a8a8a8a8a6040516108ee99989796959493929190611757565b60405180910390a250505050505050505050565b8060030b8260030b8460030b7f91c80dc390f3d041b3a04b0099b19634499541ea26972250986ee4b24a12fac560405160405180910390a4505050565b610947610a48565b6040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b6020820152604001610a378461139e565b90529b9a5050505050505050505050565b6040805161010081018252600080825260606020830181905292820152908101610a70610ba4565b8152600060208201819052606060408301819052820152608001610a92610bc3565b905290565b600183019183908215610b1a5791602002820160005b83821115610aeb57835183826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302610aad565b8015610b185782816101000a81549060ff0219169055600101602081600001049283019260010302610aeb565b505b50610b26929150610c16565b5090565b828054828255906000526020600020908101928215610b1a579160200282015b82811115610b1a57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610b4a565b6040518061040001604052806020906020820280368337509192915050565b604051806040016040528060007dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001610a926040518060400160405280600060070b8152602001606081525090565b5b80821115610b265760008155600101610c17565b600060208284031215610c3d57600080fd5b5035919050565b6000815180845260005b81811015610c6a57602081850181015186830182015201610c4e565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b8060005b6020808210610cbb5750610cd2565b825160ff1685529384019390910190600101610cac565b50505050565b600081518084526020808501945080840160005b83811015610d1e57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101610cec565b509495945050505050565b7fffff00000000000000000000000000000000000000000000000000000000000081511682526000602082015160406020850152805160070b60408501526020810151905060406060850152610d826080850182610c44565b949350505050565b60208152610d9e60208201835160030b9052565b600060208301516104e0806040850152610dbc610500850183610c44565b91506040850151610dd2606086018260ff169052565b506060850151610de56080860182610ca8565b50608085015173ffffffffffffffffffffffffffffffffffffffff1661048085015260a08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085840381016104a0870152610e428483610cd8565b935060c08701519150610e5b6104c087018360170b9052565b60e0870151915080868503018387015250610e768382610d29565b9695505050505050565b60008083601f840112610e9257600080fd5b50813567ffffffffffffffff811115610eaa57600080fd5b602083019150836020828501011115610ec257600080fd5b9250929050565b60008060208385031215610edc57600080fd5b823567ffffffffffffffff811115610ef357600080fd5b610eff85828601610e80565b90969095509350505050565b8035600381900b8114610f1d57600080fd5b919050565b803560ff81168114610f1d57600080fd5b806104008101831015610f4557600080fd5b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610f1d57600080fd5b60008083601f840112610f8157600080fd5b50813567ffffffffffffffff811115610f9957600080fd5b6020830191508360208260051b8501011115610ec257600080fd5b8035601781900b8114610f1d57600080fd5b600060408284031215610fd857600080fd5b50919050565b6000806000806000806000806000806104e08b8d031215610ffe57600080fd5b6110078b610f0b565b995060208b013567ffffffffffffffff8082111561102457600080fd5b6110308e838f01610e80565b909b50995089915061104460408e01610f22565b98506110538e60608f01610f33565b97506110626104608e01610f4b565b96506104808d013591508082111561107957600080fd5b6110858e838f01610f6f565b909650945084915061109a6104a08e01610fb4565b93506104c08d01359150808211156110b157600080fd5b506110be8d828e01610fc6565b9150509295989b9194979a5092959850565b6020808252825182820181905260009190848201906040850190845b8181101561111257835167ffffffffffffffff16835292840192918401916001016110ec565b50909695505050505050565b60006020828403121561113057600080fd5b813567ffffffffffffffff8116811461114857600080fd5b9392505050565b60008060006060848603121561116457600080fd5b61116d84610f0b565b925061117b60208501610f0b565b915061118960408501610f0b565b90509250925092565b81810381811115610f45577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c9082168061120f57607f821691505b602082108103610fd8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000610d82602083018486611258565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611307576113076112b5565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611354576113546112b5565b604052919050565b80357fffff00000000000000000000000000000000000000000000000000000000000081168114610f1d57600080fd5b8035600781900b8114610f1d57600080fd5b6000604082360312156113b057600080fd5b6113b86112e4565b6113c18361135c565b815260208084013567ffffffffffffffff808211156113df57600080fd5b8186019150604082360312156113f457600080fd5b6113fc6112e4565b6114058361138c565b8152838301358281111561141857600080fd5b929092019136601f84011261142c57600080fd5b82358281111561143e5761143e6112b5565b61146e857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161130d565b9250808352368582860101111561148457600080fd5b8085850186850137600090830185015280840191909152918301919091525092915050565b601f8211156114f357600081815260208120601f850160051c810160208610156114d05750805b601f850160051c820191505b818110156114ef578281556001016114dc565b5050505b505050565b815167ffffffffffffffff811115611512576115126112b5565b6115268161152084546111fb565b846114a9565b602080601f83116001811461157957600084156115435750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556114ef565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156115c6578886015182559484019460019091019084016115a7565b508582101561160257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8183526000602080850194508260005b85811015610d1e5773ffffffffffffffffffffffffffffffffffffffff61164883610f4b565b1687529582019590820190600101611622565b7fffff0000000000000000000000000000000000000000000000000000000000006116858261135c565b168252600060208201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126116bf57600080fd5b6040602085015282016116d18161138c565b60070b604085015260208101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811261170e57600080fd5b0160208101903567ffffffffffffffff81111561172a57600080fd5b80360382131561173957600080fd5b6040606086015261174e608086018284611258565b95945050505050565b60006104c080835261176c8184018c8e611258565b9050602060ff808c1682860152604085018b60005b848110156117a6578361179383610f22565b1683529184019190840190600101611781565b505050505073ffffffffffffffffffffffffffffffffffffffff88166104408401528281036104608401526117dc818789611612565b90506117ee61048084018660170b9052565b8281036104a0840152611801818561165b565b9c9b50505050505050505050505056fea164736f6c6343000813000a",
+ ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"Triggered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"fieldHash\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"TriggeredEventWithDynamicTopic\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"TriggeredWithFourTopics\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"field1\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint8[32]\",\"name\":\"field2\",\"type\":\"uint8[32]\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"field3\",\"type\":\"bytes32\"}],\"name\":\"TriggeredWithFourTopicsWithHashed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"addTestStruct\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAlterablePrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDifferentPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"getElementAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"NestedStruct\",\"type\":\"tuple\"}],\"internalType\":\"structTestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSliceValue\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"returnSeen\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"NestedStruct\",\"type\":\"tuple\"}],\"internalType\":\"structTestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"name\":\"setAlterablePrimitiveValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"triggerEvent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"triggerEventWithDynamicTopic\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"triggerWithFourTopics\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field1\",\"type\":\"string\"},{\"internalType\":\"uint8[32]\",\"name\":\"field2\",\"type\":\"uint8[32]\"},{\"internalType\":\"bytes32\",\"name\":\"field3\",\"type\":\"bytes32\"}],\"name\":\"triggerWithFourTopicsWithHashed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b50600180548082018255600082905260048082047fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6908101805460086003958616810261010090810a8088026001600160401b0391820219909416939093179093558654808801909755848704909301805496909516909202900a91820291021990921691909117905561199c806100a96000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063a90e199811610081578063ef4e1ced1161005b578063ef4e1ced146101de578063f6f871c8146101e5578063fbe9fbf6146101f857600080fd5b8063a90e19981461019b578063ab5e0b38146101ae578063dbfd7332146101cb57600080fd5b8063679004a4116100b2578063679004a41461012a5780636c9a43b61461013f5780637f002d671461018857600080fd5b80632c45576f146100d95780633272b66c1461010257806349eac2ac14610117575b600080fd5b6100ec6100e7366004610ca3565b61020a565b6040516100f99190610e0c565b60405180910390f35b610115610110366004610f4b565b6104e5565b005b610115610125366004611060565b61053a565b61013261083d565b6040516100f99190611152565b61011561014d3660046111a0565b600280547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92909216919091179055565b610115610196366004611060565b6108c9565b6101156101a93660046112d4565b610920565b6107c65b60405167ffffffffffffffff90911681526020016100f9565b6101156101d9366004611389565b61097a565b60036101b2565b6100ec6101f3366004611060565b6109b7565b60025467ffffffffffffffff166101b2565b610212610ac0565b600061021f6001846113cc565b8154811061022f5761022f611406565b6000918252602091829020604080516101008101909152600a90920201805460030b8252600181018054929391929184019161026a90611435565b80601f016020809104026020016040519081016040528092919081815260200182805461029690611435565b80156102e35780601f106102b8576101008083540402835291602001916102e3565b820191906000526020600020905b8154815290600101906020018083116102c657829003601f168201915b5050509183525050600282015460ff166020808301919091526040805161040081018083529190930192916003850191826000855b825461010083900a900460ff1681526020600192830181810494850194909303909202910180841161031857505050928452505050600482015473ffffffffffffffffffffffffffffffffffffffff1660208083019190915260058301805460408051828502810185018252828152940193928301828280156103d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116103a6575b5050509183525050600682015460170b6020808301919091526040805180820182526007808601805460f01b7fffff0000000000000000000000000000000000000000000000000000000000001683528351808501855260088801805490930b8152600988018054959097019693959194868301949193928401919061045690611435565b80601f016020809104026020016040519081016040528092919081815260200182805461048290611435565b80156104cf5780601f106104a4576101008083540402835291602001916104cf565b820191906000526020600020905b8154815290600101906020018083116104b257829003601f168201915b5050509190925250505090525090525092915050565b81816040516104f5929190611482565b60405180910390207f3d969732b1bbbb9f1d7eb9f3f14e4cb50a74d950b3ef916a397b85dfbab93c67838360405161052e9291906114db565b60405180910390a25050565b60006040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b602082015260400161062c84611531565b905281546001808201845560009384526020938490208351600a9093020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff909316929092178255928201519192909190820190610692908261161e565b5060408201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff90921691909117905560608201516106e09060038301906020610b0f565b5060808201516004820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905560a08201518051610747916005840191602090910190610ba2565b5060c08201516006820180547fffffffffffffffff0000000000000000000000000000000000000000000000001677ffffffffffffffffffffffffffffffffffffffffffffffff90921691909117905560e082015180516007830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660f09290921c91909117815560208083015180516008860180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff90921691909117815591810151909190600986019061082a908261161e565b5050505050505050505050505050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156108bf57602002820191906000526020600020906000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff168152602001906008019060208260070104928301926001038202915080841161087a5790505b5050505050905090565b8960030b7f7188419dcd8b51877b71766f075f3626586c0ff190e7d056aa65ce9acb649a3d8a8a8a8a8a8a8a8a8a60405161090c9998979695949392919061187d565b60405180910390a250505050505050505050565b808260405161092f9190611937565b6040518091039020846040516109459190611973565b604051908190038120907f7220e4dbe4e9d0ed5f71acd022bc89c26748ac6784f2c548bc17bb8e52af34b090600090a4505050565b8060030b8260030b8460030b7f91c80dc390f3d041b3a04b0099b19634499541ea26972250986ee4b24a12fac560405160405180910390a4505050565b6109bf610ac0565b6040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b6020820152604001610aaf84611531565b90529b9a5050505050505050505050565b6040805161010081018252600080825260606020830181905292820152908101610ae8610c1c565b8152600060208201819052606060408301819052820152608001610b0a610c3b565b905290565b600183019183908215610b925791602002820160005b83821115610b6357835183826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302610b25565b8015610b905782816101000a81549060ff0219169055600101602081600001049283019260010302610b63565b505b50610b9e929150610c8e565b5090565b828054828255906000526020600020908101928215610b92579160200282015b82811115610b9257825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610bc2565b6040518061040001604052806020906020820280368337509192915050565b604051806040016040528060007dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001610b0a6040518060400160405280600060070b8152602001606081525090565b5b80821115610b9e5760008155600101610c8f565b600060208284031215610cb557600080fd5b5035919050565b60005b83811015610cd7578181015183820152602001610cbf565b50506000910152565b60008151808452610cf8816020860160208601610cbc565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8060005b6020808210610d3d5750610d54565b825160ff1685529384019390910190600101610d2e565b50505050565b600081518084526020808501945080840160005b83811015610da057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101610d6e565b509495945050505050565b7fffff00000000000000000000000000000000000000000000000000000000000081511682526000602082015160406020850152805160070b60408501526020810151905060406060850152610e046080850182610ce0565b949350505050565b60208152610e2060208201835160030b9052565b600060208301516104e0806040850152610e3e610500850183610ce0565b91506040850151610e54606086018260ff169052565b506060850151610e676080860182610d2a565b50608085015173ffffffffffffffffffffffffffffffffffffffff1661048085015260a08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085840381016104a0870152610ec48483610d5a565b935060c08701519150610edd6104c087018360170b9052565b60e0870151915080868503018387015250610ef88382610dab565b9695505050505050565b60008083601f840112610f1457600080fd5b50813567ffffffffffffffff811115610f2c57600080fd5b602083019150836020828501011115610f4457600080fd5b9250929050565b60008060208385031215610f5e57600080fd5b823567ffffffffffffffff811115610f7557600080fd5b610f8185828601610f02565b90969095509350505050565b8035600381900b8114610f9f57600080fd5b919050565b803560ff81168114610f9f57600080fd5b806104008101831015610fc757600080fd5b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610f9f57600080fd5b60008083601f84011261100357600080fd5b50813567ffffffffffffffff81111561101b57600080fd5b6020830191508360208260051b8501011115610f4457600080fd5b8035601781900b8114610f9f57600080fd5b60006040828403121561105a57600080fd5b50919050565b6000806000806000806000806000806104e08b8d03121561108057600080fd5b6110898b610f8d565b995060208b013567ffffffffffffffff808211156110a657600080fd5b6110b28e838f01610f02565b909b5099508991506110c660408e01610fa4565b98506110d58e60608f01610fb5565b97506110e46104608e01610fcd565b96506104808d01359150808211156110fb57600080fd5b6111078e838f01610ff1565b909650945084915061111c6104a08e01611036565b93506104c08d013591508082111561113357600080fd5b506111408d828e01611048565b9150509295989b9194979a5092959850565b6020808252825182820181905260009190848201906040850190845b8181101561119457835167ffffffffffffffff168352928401929184019160010161116e565b50909695505050505050565b6000602082840312156111b257600080fd5b813567ffffffffffffffff811681146111ca57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715611223576112236111d1565b60405290565b600082601f83011261123a57600080fd5b813567ffffffffffffffff80821115611255576112556111d1565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561129b5761129b6111d1565b816040528381528660208588010111156112b457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600061044084860312156112ea57600080fd5b833567ffffffffffffffff8082111561130257600080fd5b61130e87838801611229565b94506020915086603f87011261132357600080fd5b6040516104008101818110838211171561133f5761133f6111d1565b60405290508061042087018881111561135757600080fd5b8388015b818110156113795761136c81610fa4565b845292840192840161135b565b5095989097509435955050505050565b60008060006060848603121561139e57600080fd5b6113a784610f8d565b92506113b560208501610f8d565b91506113c360408501610f8d565b90509250925092565b81810381811115610fc7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c9082168061144957607f821691505b60208210810361105a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000610e04602083018486611492565b80357fffff00000000000000000000000000000000000000000000000000000000000081168114610f9f57600080fd5b8035600781900b8114610f9f57600080fd5b60006040823603121561154357600080fd5b61154b611200565b611554836114ef565b8152602083013567ffffffffffffffff8082111561157157600080fd5b81850191506040823603121561158657600080fd5b61158e611200565b6115978361151f565b81526020830135828111156115ab57600080fd5b6115b736828601611229565b60208301525080602085015250505080915050919050565b601f82111561161957600081815260208120601f850160051c810160208610156115f65750805b601f850160051c820191505b8181101561161557828155600101611602565b5050505b505050565b815167ffffffffffffffff811115611638576116386111d1565b61164c816116468454611435565b846115cf565b602080601f83116001811461169f57600084156116695750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611615565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156116ec578886015182559484019460019091019084016116cd565b508582101561172857878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8183526000602080850194508260005b85811015610da05773ffffffffffffffffffffffffffffffffffffffff61176e83610fcd565b1687529582019590820190600101611748565b7fffff0000000000000000000000000000000000000000000000000000000000006117ab826114ef565b168252600060208201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18336030181126117e557600080fd5b6040602085015282016117f78161151f565b60070b604085015260208101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811261183457600080fd5b0160208101903567ffffffffffffffff81111561185057600080fd5b80360382131561185f57600080fd5b60406060860152611874608086018284611492565b95945050505050565b60006104c08083526118928184018c8e611492565b9050602060ff808c1682860152604085018b60005b848110156118cc57836118b983610fa4565b16835291840191908401906001016118a7565b505050505073ffffffffffffffffffffffffffffffffffffffff8816610440840152828103610460840152611902818789611738565b905061191461048084018660170b9052565b8281036104a08401526119278185611781565b9c9b505050505050505050505050565b60008183825b602080821061194c5750611963565b825160ff168452928301929091019060010161193d565b5050506104008201905092915050565b60008251611985818460208701610cbc565b919091019291505056fea164736f6c6343000813000a",
}
var ChainReaderTesterABI = ChainReaderTesterMetaData.ABI
@@ -384,6 +384,18 @@ func (_ChainReaderTester *ChainReaderTesterTransactorSession) TriggerWithFourTop
return _ChainReaderTester.Contract.TriggerWithFourTopics(&_ChainReaderTester.TransactOpts, field1, field2, field3)
}
+func (_ChainReaderTester *ChainReaderTesterTransactor) TriggerWithFourTopicsWithHashed(opts *bind.TransactOpts, field1 string, field2 [32]uint8, field3 [32]byte) (*types.Transaction, error) {
+ return _ChainReaderTester.contract.Transact(opts, "triggerWithFourTopicsWithHashed", field1, field2, field3)
+}
+
+func (_ChainReaderTester *ChainReaderTesterSession) TriggerWithFourTopicsWithHashed(field1 string, field2 [32]uint8, field3 [32]byte) (*types.Transaction, error) {
+ return _ChainReaderTester.Contract.TriggerWithFourTopicsWithHashed(&_ChainReaderTester.TransactOpts, field1, field2, field3)
+}
+
+func (_ChainReaderTester *ChainReaderTesterTransactorSession) TriggerWithFourTopicsWithHashed(field1 string, field2 [32]uint8, field3 [32]byte) (*types.Transaction, error) {
+ return _ChainReaderTester.Contract.TriggerWithFourTopicsWithHashed(&_ChainReaderTester.TransactOpts, field1, field2, field3)
+}
+
type ChainReaderTesterTriggeredIterator struct {
Event *ChainReaderTesterTriggered
@@ -791,6 +803,151 @@ func (_ChainReaderTester *ChainReaderTesterFilterer) ParseTriggeredWithFourTopic
return event, nil
}
+type ChainReaderTesterTriggeredWithFourTopicsWithHashedIterator struct {
+ Event *ChainReaderTesterTriggeredWithFourTopicsWithHashed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ChainReaderTesterTriggeredWithFourTopicsWithHashedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ChainReaderTesterTriggeredWithFourTopicsWithHashed)
+ 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(ChainReaderTesterTriggeredWithFourTopicsWithHashed)
+ 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 *ChainReaderTesterTriggeredWithFourTopicsWithHashedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ChainReaderTesterTriggeredWithFourTopicsWithHashedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ChainReaderTesterTriggeredWithFourTopicsWithHashed struct {
+ Field1 common.Hash
+ Field2 [32]uint8
+ Field3 [32]byte
+ Raw types.Log
+}
+
+func (_ChainReaderTester *ChainReaderTesterFilterer) FilterTriggeredWithFourTopicsWithHashed(opts *bind.FilterOpts, field1 []string, field2 [][32]uint8, field3 [][32]byte) (*ChainReaderTesterTriggeredWithFourTopicsWithHashedIterator, error) {
+
+ var field1Rule []interface{}
+ for _, field1Item := range field1 {
+ field1Rule = append(field1Rule, field1Item)
+ }
+ var field2Rule []interface{}
+ for _, field2Item := range field2 {
+ field2Rule = append(field2Rule, field2Item)
+ }
+ var field3Rule []interface{}
+ for _, field3Item := range field3 {
+ field3Rule = append(field3Rule, field3Item)
+ }
+
+ logs, sub, err := _ChainReaderTester.contract.FilterLogs(opts, "TriggeredWithFourTopicsWithHashed", field1Rule, field2Rule, field3Rule)
+ if err != nil {
+ return nil, err
+ }
+ return &ChainReaderTesterTriggeredWithFourTopicsWithHashedIterator{contract: _ChainReaderTester.contract, event: "TriggeredWithFourTopicsWithHashed", logs: logs, sub: sub}, nil
+}
+
+func (_ChainReaderTester *ChainReaderTesterFilterer) WatchTriggeredWithFourTopicsWithHashed(opts *bind.WatchOpts, sink chan<- *ChainReaderTesterTriggeredWithFourTopicsWithHashed, field1 []string, field2 [][32]uint8, field3 [][32]byte) (event.Subscription, error) {
+
+ var field1Rule []interface{}
+ for _, field1Item := range field1 {
+ field1Rule = append(field1Rule, field1Item)
+ }
+ var field2Rule []interface{}
+ for _, field2Item := range field2 {
+ field2Rule = append(field2Rule, field2Item)
+ }
+ var field3Rule []interface{}
+ for _, field3Item := range field3 {
+ field3Rule = append(field3Rule, field3Item)
+ }
+
+ logs, sub, err := _ChainReaderTester.contract.WatchLogs(opts, "TriggeredWithFourTopicsWithHashed", field1Rule, field2Rule, field3Rule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ChainReaderTesterTriggeredWithFourTopicsWithHashed)
+ if err := _ChainReaderTester.contract.UnpackLog(event, "TriggeredWithFourTopicsWithHashed", 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 (_ChainReaderTester *ChainReaderTesterFilterer) ParseTriggeredWithFourTopicsWithHashed(log types.Log) (*ChainReaderTesterTriggeredWithFourTopicsWithHashed, error) {
+ event := new(ChainReaderTesterTriggeredWithFourTopicsWithHashed)
+ if err := _ChainReaderTester.contract.UnpackLog(event, "TriggeredWithFourTopicsWithHashed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
func (_ChainReaderTester *ChainReaderTester) ParseLog(log types.Log) (generated.AbigenLog, error) {
switch log.Topics[0] {
case _ChainReaderTester.abi.Events["Triggered"].ID:
@@ -799,6 +956,8 @@ func (_ChainReaderTester *ChainReaderTester) ParseLog(log types.Log) (generated.
return _ChainReaderTester.ParseTriggeredEventWithDynamicTopic(log)
case _ChainReaderTester.abi.Events["TriggeredWithFourTopics"].ID:
return _ChainReaderTester.ParseTriggeredWithFourTopics(log)
+ case _ChainReaderTester.abi.Events["TriggeredWithFourTopicsWithHashed"].ID:
+ return _ChainReaderTester.ParseTriggeredWithFourTopicsWithHashed(log)
default:
return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
@@ -817,6 +976,10 @@ func (ChainReaderTesterTriggeredWithFourTopics) Topic() common.Hash {
return common.HexToHash("0x91c80dc390f3d041b3a04b0099b19634499541ea26972250986ee4b24a12fac5")
}
+func (ChainReaderTesterTriggeredWithFourTopicsWithHashed) Topic() common.Hash {
+ return common.HexToHash("0x7220e4dbe4e9d0ed5f71acd022bc89c26748ac6784f2c548bc17bb8e52af34b0")
+}
+
func (_ChainReaderTester *ChainReaderTester) Address() common.Address {
return _ChainReaderTester.address
}
@@ -844,6 +1007,8 @@ type ChainReaderTesterInterface interface {
TriggerWithFourTopics(opts *bind.TransactOpts, field1 int32, field2 int32, field3 int32) (*types.Transaction, error)
+ TriggerWithFourTopicsWithHashed(opts *bind.TransactOpts, field1 string, field2 [32]uint8, field3 [32]byte) (*types.Transaction, error)
+
FilterTriggered(opts *bind.FilterOpts, field []int32) (*ChainReaderTesterTriggeredIterator, error)
WatchTriggered(opts *bind.WatchOpts, sink chan<- *ChainReaderTesterTriggered, field []int32) (event.Subscription, error)
@@ -862,6 +1027,12 @@ type ChainReaderTesterInterface interface {
ParseTriggeredWithFourTopics(log types.Log) (*ChainReaderTesterTriggeredWithFourTopics, error)
+ FilterTriggeredWithFourTopicsWithHashed(opts *bind.FilterOpts, field1 []string, field2 [][32]uint8, field3 [][32]byte) (*ChainReaderTesterTriggeredWithFourTopicsWithHashedIterator, error)
+
+ WatchTriggeredWithFourTopicsWithHashed(opts *bind.WatchOpts, sink chan<- *ChainReaderTesterTriggeredWithFourTopicsWithHashed, field1 []string, field2 [][32]uint8, field3 [][32]byte) (event.Subscription, error)
+
+ ParseTriggeredWithFourTopicsWithHashed(log types.Log) (*ChainReaderTesterTriggeredWithFourTopicsWithHashed, error)
+
ParseLog(log types.Log) (generated.AbigenLog, error)
Address() common.Address
diff --git a/core/gethwrappers/generated/i_chain_module/i_chain_module.go b/core/gethwrappers/generated/i_chain_module/i_chain_module.go
index 23cec8fb9c8..e432d912cc5 100644
--- a/core/gethwrappers/generated/i_chain_module/i_chain_module.go
+++ b/core/gethwrappers/generated/i_chain_module/i_chain_module.go
@@ -29,7 +29,7 @@ var (
)
var IChainModuleMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"l1Fee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"maxL1Fee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
}
var IChainModuleABI = IChainModuleMetaData.ABI
@@ -150,9 +150,9 @@ func (_IChainModule *IChainModuleTransactorRaw) Transact(opts *bind.TransactOpts
return _IChainModule.Contract.contract.Transact(opts, method, params...)
}
-func (_IChainModule *IChainModuleCaller) BlockHash(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) {
+func (_IChainModule *IChainModuleCaller) BlockHash(opts *bind.CallOpts, blockNumber *big.Int) ([32]byte, error) {
var out []interface{}
- err := _IChainModule.contract.Call(opts, &out, "blockHash", arg0)
+ err := _IChainModule.contract.Call(opts, &out, "blockHash", blockNumber)
if err != nil {
return *new([32]byte), err
@@ -164,12 +164,12 @@ func (_IChainModule *IChainModuleCaller) BlockHash(opts *bind.CallOpts, arg0 *bi
}
-func (_IChainModule *IChainModuleSession) BlockHash(arg0 *big.Int) ([32]byte, error) {
- return _IChainModule.Contract.BlockHash(&_IChainModule.CallOpts, arg0)
+func (_IChainModule *IChainModuleSession) BlockHash(blockNumber *big.Int) ([32]byte, error) {
+ return _IChainModule.Contract.BlockHash(&_IChainModule.CallOpts, blockNumber)
}
-func (_IChainModule *IChainModuleCallerSession) BlockHash(arg0 *big.Int) ([32]byte, error) {
- return _IChainModule.Contract.BlockHash(&_IChainModule.CallOpts, arg0)
+func (_IChainModule *IChainModuleCallerSession) BlockHash(blockNumber *big.Int) ([32]byte, error) {
+ return _IChainModule.Contract.BlockHash(&_IChainModule.CallOpts, blockNumber)
}
func (_IChainModule *IChainModuleCaller) BlockNumber(opts *bind.CallOpts) (*big.Int, error) {
@@ -194,9 +194,9 @@ func (_IChainModule *IChainModuleCallerSession) BlockNumber() (*big.Int, error)
return _IChainModule.Contract.BlockNumber(&_IChainModule.CallOpts)
}
-func (_IChainModule *IChainModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error) {
+func (_IChainModule *IChainModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error) {
var out []interface{}
- err := _IChainModule.contract.Call(opts, &out, "getCurrentL1Fee")
+ err := _IChainModule.contract.Call(opts, &out, "getCurrentL1Fee", dataSize)
if err != nil {
return *new(*big.Int), err
@@ -208,12 +208,12 @@ func (_IChainModule *IChainModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts) (*
}
-func (_IChainModule *IChainModuleSession) GetCurrentL1Fee() (*big.Int, error) {
- return _IChainModule.Contract.GetCurrentL1Fee(&_IChainModule.CallOpts)
+func (_IChainModule *IChainModuleSession) GetCurrentL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _IChainModule.Contract.GetCurrentL1Fee(&_IChainModule.CallOpts, dataSize)
}
-func (_IChainModule *IChainModuleCallerSession) GetCurrentL1Fee() (*big.Int, error) {
- return _IChainModule.Contract.GetCurrentL1Fee(&_IChainModule.CallOpts)
+func (_IChainModule *IChainModuleCallerSession) GetCurrentL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _IChainModule.Contract.GetCurrentL1Fee(&_IChainModule.CallOpts, dataSize)
}
func (_IChainModule *IChainModuleCaller) GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
@@ -278,11 +278,11 @@ func (_IChainModule *IChainModule) Address() common.Address {
}
type IChainModuleInterface interface {
- BlockHash(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error)
+ BlockHash(opts *bind.CallOpts, blockNumber *big.Int) ([32]byte, error)
BlockNumber(opts *bind.CallOpts) (*big.Int, error)
- GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error)
+ GetCurrentL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error)
GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
diff --git a/core/gethwrappers/generated/optimism_module/optimism_module.go b/core/gethwrappers/generated/optimism_module/optimism_module.go
index 009ab6d8cff..89b6a758fcf 100644
--- a/core/gethwrappers/generated/optimism_module/optimism_module.go
+++ b/core/gethwrappers/generated/optimism_module/optimism_module.go
@@ -29,8 +29,8 @@ var (
)
var OptimismModuleMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
- Bin: "0x608060405234801561001057600080fd5b506104d1806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a3660046102e9565b6100ca565b6040519081526020015b60405180910390f35b61007f6101eb565b4361007f565b61007f6100ae3660046102e9565b6102bc565b6040805161ea60815261010e602082015201610089565b6000806100d8836004610331565b67ffffffffffffffff8111156100f0576100f061034e565b6040519080825280601f01601f19166020018201604052801561011a576020820181803683370190505b50905073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e82604051806080016040528060508152602001610475605091396040516020016101789291906103a1565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016101a391906103d0565b602060405180830381865afa1580156101c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e49190610421565b9392505050565b600073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e6000366040518060800160405280605081526020016104756050913960405160200161024b9392919061043a565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161027691906103d0565b602060405180830381865afa158015610293573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b79190610421565b905090565b600043821015806102d757506101006102d58343610461565b115b156102e457506000919050565b504090565b6000602082840312156102fb57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761034857610348610302565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b83811015610398578181015183820152602001610380565b50506000910152565b600083516103b381846020880161037d565b8351908301906103c781836020880161037d565b01949350505050565b60208152600082518060208401526103ef81604085016020870161037d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561043357600080fd5b5051919050565b82848237600083820160008152835161045781836020880161037d565b0195945050505050565b818103818111156103485761034861030256feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa164736f6c6343000813000a",
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b506103dc806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c80637810d12a116100505780637810d12a1461006c57806385df51fd14610098578063de9ee35e146100ab57600080fd5b8063125441401461006c57806357e871e714610092575b600080fd5b61007f61007a366004610221565b6100c2565b6040519081526020015b60405180910390f35b4361007f565b61007f6100a6366004610221565b6100d3565b6040805161ea60815261010e602082015201610089565b60006100cd82610100565b92915050565b600043821015806100ee57506101006100ec8343610269565b115b156100fb57506000919050565b504090565b60008061010e83600461027c565b67ffffffffffffffff81111561012657610126610293565b6040519080825280601f01601f191660200182016040528015610150576020820181803683370190505b50905073420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e82604051806080016040528060508152602001610380605091396040516020016101ae9291906102e6565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016101d99190610315565b602060405180830381865afa1580156101f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061021a9190610366565b9392505050565b60006020828403121561023357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156100cd576100cd61023a565b80820281158282048414176100cd576100cd61023a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156102dd5781810151838201526020016102c5565b50506000910152565b600083516102f88184602088016102c2565b83519083019061030c8183602088016102c2565b01949350505050565b60208152600082518060208401526103348160408501602087016102c2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561037857600080fd5b505191905056feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa164736f6c6343000813000a",
}
var OptimismModuleABI = OptimismModuleMetaData.ABI
@@ -213,9 +213,9 @@ func (_OptimismModule *OptimismModuleCallerSession) BlockNumber() (*big.Int, err
return _OptimismModule.Contract.BlockNumber(&_OptimismModule.CallOpts)
}
-func (_OptimismModule *OptimismModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error) {
+func (_OptimismModule *OptimismModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error) {
var out []interface{}
- err := _OptimismModule.contract.Call(opts, &out, "getCurrentL1Fee")
+ err := _OptimismModule.contract.Call(opts, &out, "getCurrentL1Fee", dataSize)
if err != nil {
return *new(*big.Int), err
@@ -227,12 +227,12 @@ func (_OptimismModule *OptimismModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts
}
-func (_OptimismModule *OptimismModuleSession) GetCurrentL1Fee() (*big.Int, error) {
- return _OptimismModule.Contract.GetCurrentL1Fee(&_OptimismModule.CallOpts)
+func (_OptimismModule *OptimismModuleSession) GetCurrentL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _OptimismModule.Contract.GetCurrentL1Fee(&_OptimismModule.CallOpts, dataSize)
}
-func (_OptimismModule *OptimismModuleCallerSession) GetCurrentL1Fee() (*big.Int, error) {
- return _OptimismModule.Contract.GetCurrentL1Fee(&_OptimismModule.CallOpts)
+func (_OptimismModule *OptimismModuleCallerSession) GetCurrentL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _OptimismModule.Contract.GetCurrentL1Fee(&_OptimismModule.CallOpts, dataSize)
}
func (_OptimismModule *OptimismModuleCaller) GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
@@ -301,7 +301,7 @@ type OptimismModuleInterface interface {
BlockNumber(opts *bind.CallOpts) (*big.Int, error)
- GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error)
+ GetCurrentL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error)
GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
diff --git a/core/gethwrappers/generated/optimism_module_v2/optimism_module_v2.go b/core/gethwrappers/generated/optimism_module_v2/optimism_module_v2.go
new file mode 100644
index 00000000000..abad079caa3
--- /dev/null
+++ b/core/gethwrappers/generated/optimism_module_v2/optimism_module_v2.go
@@ -0,0 +1,840 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_module_v2
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var OptimismModuleV2MetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"coefficient\",\"type\":\"uint8\"}],\"name\":\"InvalidL1FeeCoefficient\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"coefficient\",\"type\":\"uint8\"}],\"name\":\"L1FeeCoefficientSet\",\"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\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1FeeCoefficient\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"coefficient\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"coefficient\",\"type\":\"uint8\"}],\"name\":\"setL1FeeCalculation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60806040526001805460ff60a01b1916601960a21b17905534801561002357600080fd5b50338060008161007a5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100aa576100aa816100b2565b50505061015b565b336001600160a01b0382160361010a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610071565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b61073f8061016a6000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80638da5cb5b11610076578063de9ee35e1161005b578063de9ee35e1461016a578063f22559a014610180578063f2fde38b1461019357600080fd5b80638da5cb5b1461011f578063d10a944e1461014757600080fd5b80637810d12a116100a75780637810d12a146100ef57806379ba50971461010257806385df51fd1461010c57600080fd5b806312544140146100c357806357e871e7146100e9575b600080fd5b6100d66100d136600461060c565b6101a6565b6040519081526020015b60405180910390f35b436100d6565b6100d66100fd36600461060c565b6101b7565b61010a6101f6565b005b6100d661011a36600461060c565b6102f8565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e0565b60015474010000000000000000000000000000000000000000900460ff166100d6565b60408051616d60815260006020820152016100e0565b61010a61018e366004610625565b610325565b61010a6101a136600461064f565b6103f0565b60006101b182610404565b92915050565b600060646101c483610404565b6001546101ec919074010000000000000000000000000000000000000000900460ff166106b4565b6101b191906106cb565b60015473ffffffffffffffffffffffffffffffffffffffff16331461027c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000438210158061031357506101006103118343610706565b115b1561032057506000919050565b504090565b61032d610494565b60648160ff161115610370576040517f1a8a06a000000000000000000000000000000000000000000000000000000000815260ff82166004820152602401610273565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000060ff8416908102919091179091556040519081527f29ec9e31de0d3fe0208a7ccb792bbc26a854f123146110daa3a77219cb74a5549060200160405180910390a150565b6103f8610494565b61040181610517565b50565b6040517ff1c7a58b0000000000000000000000000000000000000000000000000000000081526004810182905260009073420000000000000000000000000000000000000f9063f1c7a58b90602401602060405180830381865afa158015610470573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101b19190610719565b60005473ffffffffffffffffffffffffffffffffffffffff163314610515576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610273565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610596576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610273565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006020828403121561061e57600080fd5b5035919050565b60006020828403121561063757600080fd5b813560ff8116811461064857600080fd5b9392505050565b60006020828403121561066157600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461064857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176101b1576101b1610685565b600082610701577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156101b1576101b1610685565b60006020828403121561072b57600080fd5b505191905056fea164736f6c6343000813000a",
+}
+
+var OptimismModuleV2ABI = OptimismModuleV2MetaData.ABI
+
+var OptimismModuleV2Bin = OptimismModuleV2MetaData.Bin
+
+func DeployOptimismModuleV2(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *OptimismModuleV2, error) {
+ parsed, err := OptimismModuleV2MetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(OptimismModuleV2Bin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &OptimismModuleV2{address: address, abi: *parsed, OptimismModuleV2Caller: OptimismModuleV2Caller{contract: contract}, OptimismModuleV2Transactor: OptimismModuleV2Transactor{contract: contract}, OptimismModuleV2Filterer: OptimismModuleV2Filterer{contract: contract}}, nil
+}
+
+type OptimismModuleV2 struct {
+ address common.Address
+ abi abi.ABI
+ OptimismModuleV2Caller
+ OptimismModuleV2Transactor
+ OptimismModuleV2Filterer
+}
+
+type OptimismModuleV2Caller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismModuleV2Transactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismModuleV2Filterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismModuleV2Session struct {
+ Contract *OptimismModuleV2
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismModuleV2CallerSession struct {
+ Contract *OptimismModuleV2Caller
+ CallOpts bind.CallOpts
+}
+
+type OptimismModuleV2TransactorSession struct {
+ Contract *OptimismModuleV2Transactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismModuleV2Raw struct {
+ Contract *OptimismModuleV2
+}
+
+type OptimismModuleV2CallerRaw struct {
+ Contract *OptimismModuleV2Caller
+}
+
+type OptimismModuleV2TransactorRaw struct {
+ Contract *OptimismModuleV2Transactor
+}
+
+func NewOptimismModuleV2(address common.Address, backend bind.ContractBackend) (*OptimismModuleV2, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismModuleV2ABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismModuleV2(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismModuleV2{address: address, abi: abi, OptimismModuleV2Caller: OptimismModuleV2Caller{contract: contract}, OptimismModuleV2Transactor: OptimismModuleV2Transactor{contract: contract}, OptimismModuleV2Filterer: OptimismModuleV2Filterer{contract: contract}}, nil
+}
+
+func NewOptimismModuleV2Caller(address common.Address, caller bind.ContractCaller) (*OptimismModuleV2Caller, error) {
+ contract, err := bindOptimismModuleV2(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismModuleV2Caller{contract: contract}, nil
+}
+
+func NewOptimismModuleV2Transactor(address common.Address, transactor bind.ContractTransactor) (*OptimismModuleV2Transactor, error) {
+ contract, err := bindOptimismModuleV2(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismModuleV2Transactor{contract: contract}, nil
+}
+
+func NewOptimismModuleV2Filterer(address common.Address, filterer bind.ContractFilterer) (*OptimismModuleV2Filterer, error) {
+ contract, err := bindOptimismModuleV2(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismModuleV2Filterer{contract: contract}, nil
+}
+
+func bindOptimismModuleV2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismModuleV2MetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismModuleV2.Contract.OptimismModuleV2Caller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.OptimismModuleV2Transactor.contract.Transfer(opts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.OptimismModuleV2Transactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismModuleV2.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Caller) BlockHash(opts *bind.CallOpts, n *big.Int) ([32]byte, error) {
+ var out []interface{}
+ err := _OptimismModuleV2.contract.Call(opts, &out, "blockHash", n)
+
+ if err != nil {
+ return *new([32]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
+
+ return out0, err
+
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) BlockHash(n *big.Int) ([32]byte, error) {
+ return _OptimismModuleV2.Contract.BlockHash(&_OptimismModuleV2.CallOpts, n)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2CallerSession) BlockHash(n *big.Int) ([32]byte, error) {
+ return _OptimismModuleV2.Contract.BlockHash(&_OptimismModuleV2.CallOpts, n)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Caller) BlockNumber(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _OptimismModuleV2.contract.Call(opts, &out, "blockNumber")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) BlockNumber() (*big.Int, error) {
+ return _OptimismModuleV2.Contract.BlockNumber(&_OptimismModuleV2.CallOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2CallerSession) BlockNumber() (*big.Int, error) {
+ return _OptimismModuleV2.Contract.BlockNumber(&_OptimismModuleV2.CallOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Caller) GetCurrentL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _OptimismModuleV2.contract.Call(opts, &out, "getCurrentL1Fee", dataSize)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) GetCurrentL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _OptimismModuleV2.Contract.GetCurrentL1Fee(&_OptimismModuleV2.CallOpts, dataSize)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2CallerSession) GetCurrentL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _OptimismModuleV2.Contract.GetCurrentL1Fee(&_OptimismModuleV2.CallOpts, dataSize)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Caller) GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
+
+ error) {
+ var out []interface{}
+ err := _OptimismModuleV2.contract.Call(opts, &out, "getGasOverhead")
+
+ outstruct := new(GetGasOverhead)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ChainModuleFixedOverhead = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+ outstruct.ChainModulePerByteOverhead = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+
+ return *outstruct, err
+
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) GetGasOverhead() (GetGasOverhead,
+
+ error) {
+ return _OptimismModuleV2.Contract.GetGasOverhead(&_OptimismModuleV2.CallOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2CallerSession) GetGasOverhead() (GetGasOverhead,
+
+ error) {
+ return _OptimismModuleV2.Contract.GetGasOverhead(&_OptimismModuleV2.CallOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Caller) GetL1FeeCoefficient(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _OptimismModuleV2.contract.Call(opts, &out, "getL1FeeCoefficient")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) GetL1FeeCoefficient() (*big.Int, error) {
+ return _OptimismModuleV2.Contract.GetL1FeeCoefficient(&_OptimismModuleV2.CallOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2CallerSession) GetL1FeeCoefficient() (*big.Int, error) {
+ return _OptimismModuleV2.Contract.GetL1FeeCoefficient(&_OptimismModuleV2.CallOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Caller) GetMaxL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _OptimismModuleV2.contract.Call(opts, &out, "getMaxL1Fee", dataSize)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) GetMaxL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _OptimismModuleV2.Contract.GetMaxL1Fee(&_OptimismModuleV2.CallOpts, dataSize)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2CallerSession) GetMaxL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _OptimismModuleV2.Contract.GetMaxL1Fee(&_OptimismModuleV2.CallOpts, dataSize)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Caller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _OptimismModuleV2.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) Owner() (common.Address, error) {
+ return _OptimismModuleV2.Contract.Owner(&_OptimismModuleV2.CallOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2CallerSession) Owner() (common.Address, error) {
+ return _OptimismModuleV2.Contract.Owner(&_OptimismModuleV2.CallOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Transactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismModuleV2.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) AcceptOwnership() (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.AcceptOwnership(&_OptimismModuleV2.TransactOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2TransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.AcceptOwnership(&_OptimismModuleV2.TransactOpts)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Transactor) SetL1FeeCalculation(opts *bind.TransactOpts, coefficient uint8) (*types.Transaction, error) {
+ return _OptimismModuleV2.contract.Transact(opts, "setL1FeeCalculation", coefficient)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) SetL1FeeCalculation(coefficient uint8) (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.SetL1FeeCalculation(&_OptimismModuleV2.TransactOpts, coefficient)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2TransactorSession) SetL1FeeCalculation(coefficient uint8) (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.SetL1FeeCalculation(&_OptimismModuleV2.TransactOpts, coefficient)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Transactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _OptimismModuleV2.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Session) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.TransferOwnership(&_OptimismModuleV2.TransactOpts, to)
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2TransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _OptimismModuleV2.Contract.TransferOwnership(&_OptimismModuleV2.TransactOpts, to)
+}
+
+type OptimismModuleV2L1FeeCoefficientSetIterator struct {
+ Event *OptimismModuleV2L1FeeCoefficientSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *OptimismModuleV2L1FeeCoefficientSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(OptimismModuleV2L1FeeCoefficientSet)
+ 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(OptimismModuleV2L1FeeCoefficientSet)
+ 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 *OptimismModuleV2L1FeeCoefficientSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *OptimismModuleV2L1FeeCoefficientSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type OptimismModuleV2L1FeeCoefficientSet struct {
+ Coefficient uint8
+ Raw types.Log
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Filterer) FilterL1FeeCoefficientSet(opts *bind.FilterOpts) (*OptimismModuleV2L1FeeCoefficientSetIterator, error) {
+
+ logs, sub, err := _OptimismModuleV2.contract.FilterLogs(opts, "L1FeeCoefficientSet")
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismModuleV2L1FeeCoefficientSetIterator{contract: _OptimismModuleV2.contract, event: "L1FeeCoefficientSet", logs: logs, sub: sub}, nil
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Filterer) WatchL1FeeCoefficientSet(opts *bind.WatchOpts, sink chan<- *OptimismModuleV2L1FeeCoefficientSet) (event.Subscription, error) {
+
+ logs, sub, err := _OptimismModuleV2.contract.WatchLogs(opts, "L1FeeCoefficientSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(OptimismModuleV2L1FeeCoefficientSet)
+ if err := _OptimismModuleV2.contract.UnpackLog(event, "L1FeeCoefficientSet", 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 (_OptimismModuleV2 *OptimismModuleV2Filterer) ParseL1FeeCoefficientSet(log types.Log) (*OptimismModuleV2L1FeeCoefficientSet, error) {
+ event := new(OptimismModuleV2L1FeeCoefficientSet)
+ if err := _OptimismModuleV2.contract.UnpackLog(event, "L1FeeCoefficientSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type OptimismModuleV2OwnershipTransferRequestedIterator struct {
+ Event *OptimismModuleV2OwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *OptimismModuleV2OwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(OptimismModuleV2OwnershipTransferRequested)
+ 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(OptimismModuleV2OwnershipTransferRequested)
+ 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 *OptimismModuleV2OwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *OptimismModuleV2OwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type OptimismModuleV2OwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Filterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*OptimismModuleV2OwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _OptimismModuleV2.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismModuleV2OwnershipTransferRequestedIterator{contract: _OptimismModuleV2.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Filterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *OptimismModuleV2OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _OptimismModuleV2.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(OptimismModuleV2OwnershipTransferRequested)
+ if err := _OptimismModuleV2.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_OptimismModuleV2 *OptimismModuleV2Filterer) ParseOwnershipTransferRequested(log types.Log) (*OptimismModuleV2OwnershipTransferRequested, error) {
+ event := new(OptimismModuleV2OwnershipTransferRequested)
+ if err := _OptimismModuleV2.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type OptimismModuleV2OwnershipTransferredIterator struct {
+ Event *OptimismModuleV2OwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *OptimismModuleV2OwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(OptimismModuleV2OwnershipTransferred)
+ 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(OptimismModuleV2OwnershipTransferred)
+ 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 *OptimismModuleV2OwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *OptimismModuleV2OwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type OptimismModuleV2OwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Filterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*OptimismModuleV2OwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _OptimismModuleV2.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismModuleV2OwnershipTransferredIterator{contract: _OptimismModuleV2.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2Filterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *OptimismModuleV2OwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _OptimismModuleV2.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(OptimismModuleV2OwnershipTransferred)
+ if err := _OptimismModuleV2.contract.UnpackLog(event, "OwnershipTransferred", 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 (_OptimismModuleV2 *OptimismModuleV2Filterer) ParseOwnershipTransferred(log types.Log) (*OptimismModuleV2OwnershipTransferred, error) {
+ event := new(OptimismModuleV2OwnershipTransferred)
+ if err := _OptimismModuleV2.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type GetGasOverhead struct {
+ ChainModuleFixedOverhead *big.Int
+ ChainModulePerByteOverhead *big.Int
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _OptimismModuleV2.abi.Events["L1FeeCoefficientSet"].ID:
+ return _OptimismModuleV2.ParseL1FeeCoefficientSet(log)
+ case _OptimismModuleV2.abi.Events["OwnershipTransferRequested"].ID:
+ return _OptimismModuleV2.ParseOwnershipTransferRequested(log)
+ case _OptimismModuleV2.abi.Events["OwnershipTransferred"].ID:
+ return _OptimismModuleV2.ParseOwnershipTransferred(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (OptimismModuleV2L1FeeCoefficientSet) Topic() common.Hash {
+ return common.HexToHash("0x29ec9e31de0d3fe0208a7ccb792bbc26a854f123146110daa3a77219cb74a554")
+}
+
+func (OptimismModuleV2OwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (OptimismModuleV2OwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (_OptimismModuleV2 *OptimismModuleV2) Address() common.Address {
+ return _OptimismModuleV2.address
+}
+
+type OptimismModuleV2Interface interface {
+ BlockHash(opts *bind.CallOpts, n *big.Int) ([32]byte, error)
+
+ BlockNumber(opts *bind.CallOpts) (*big.Int, error)
+
+ GetCurrentL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error)
+
+ GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
+
+ error)
+
+ GetL1FeeCoefficient(opts *bind.CallOpts) (*big.Int, error)
+
+ GetMaxL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetL1FeeCalculation(opts *bind.TransactOpts, coefficient uint8) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterL1FeeCoefficientSet(opts *bind.FilterOpts) (*OptimismModuleV2L1FeeCoefficientSetIterator, error)
+
+ WatchL1FeeCoefficientSet(opts *bind.WatchOpts, sink chan<- *OptimismModuleV2L1FeeCoefficientSet) (event.Subscription, error)
+
+ ParseL1FeeCoefficientSet(log types.Log) (*OptimismModuleV2L1FeeCoefficientSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*OptimismModuleV2OwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *OptimismModuleV2OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*OptimismModuleV2OwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*OptimismModuleV2OwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *OptimismModuleV2OwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*OptimismModuleV2OwnershipTransferred, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/generated/scroll_module/scroll_module.go b/core/gethwrappers/generated/scroll_module/scroll_module.go
index 702cc39a7ae..e8f48da0d04 100644
--- a/core/gethwrappers/generated/scroll_module/scroll_module.go
+++ b/core/gethwrappers/generated/scroll_module/scroll_module.go
@@ -5,6 +5,7 @@ package scroll_module
import (
"errors"
+ "fmt"
"math/big"
"strings"
@@ -14,6 +15,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
)
var (
@@ -29,8 +31,8 @@ var (
)
var ScrollModuleMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
- Bin: "0x608060405234801561001057600080fd5b5061050c806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806357e871e71161005057806357e871e71461009a57806385df51fd146100a0578063de9ee35e146100b357600080fd5b8063125441401461006c57806318b8f61314610092575b600080fd5b61007f61007a3660046102e8565b6100c9565b6040519081526020015b60405180910390f35b61007f6101ea565b4361007f565b61007f6100ae3660046102e8565b6102bb565b6040805161afc8815260aa602082015201610089565b6000806100d7836004610330565b67ffffffffffffffff8111156100ef576100ef61034d565b6040519080825280601f01601f191660200182016040528015610119576020820181803683370190505b50905073530000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff166349948e0e826040518060c00160405280608c8152602001610474608c91396040516020016101779291906103a0565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016101a291906103cf565b602060405180830381865afa1580156101bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e39190610420565b9392505050565b600073530000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff166349948e0e6000366040518060c00160405280608c8152602001610474608c913960405160200161024a93929190610439565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161027591906103cf565b602060405180830381865afa158015610292573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102b69190610420565b905090565b600043821015806102d657506101006102d48343610460565b115b156102e357506000919050565b504090565b6000602082840312156102fa57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761034757610347610301565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b8381101561039757818101518382015260200161037f565b50506000910152565b600083516103b281846020880161037c565b8351908301906103c681836020880161037c565b01949350505050565b60208152600082518060208401526103ee81604085016020870161037c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561043257600080fd5b5051919050565b82848237600083820160008152835161045681836020880161037c565b0195945050505050565b818103818111156103475761034761030156feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa164736f6c6343000813000a",
+ ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"coefficient\",\"type\":\"uint8\"}],\"name\":\"InvalidL1FeeCoefficient\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"coefficient\",\"type\":\"uint8\"}],\"name\":\"L1FeeCoefficientSet\",\"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\":\"n\",\"type\":\"uint256\"}],\"name\":\"blockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"blockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getCurrentL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainModuleFixedOverhead\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainModulePerByteOverhead\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1FeeCoefficient\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"coefficient\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataSize\",\"type\":\"uint256\"}],\"name\":\"getMaxL1Fee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"coefficient\",\"type\":\"uint8\"}],\"name\":\"setL1FeeCalculation\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60806040526001805460ff60a01b1916601960a21b17905534801561002357600080fd5b50338060008161007a5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100aa576100aa816100b2565b50505061015b565b336001600160a01b0382160361010a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610071565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6109288061016a6000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80638da5cb5b11610076578063de9ee35e1161005b578063de9ee35e1461016a578063f22559a014610180578063f2fde38b1461019357600080fd5b80638da5cb5b1461011f578063d10a944e1461014757600080fd5b80637810d12a116100a75780637810d12a146100ef57806379ba50971461010257806385df51fd1461010c57600080fd5b806312544140146100c357806357e871e7146100e9575b600080fd5b6100d66100d136600461069d565b6101a6565b6040519081526020015b60405180910390f35b436100d6565b6100d66100fd36600461069d565b6101b7565b61010a6101f6565b005b6100d661011a36600461069d565b6102f8565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e0565b60015474010000000000000000000000000000000000000000900460ff166100d6565b6040805161afc8815260aa6020820152016100e0565b61010a61018e3660046106b6565b610325565b61010a6101a13660046106d9565b6103f0565b60006101b182610404565b92915050565b600060646101c483610404565b6001546101ec919074010000000000000000000000000000000000000000900460ff1661073e565b6101b19190610755565b60015473ffffffffffffffffffffffffffffffffffffffff16331461027c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000438210158061031357506101006103118343610790565b115b1561032057506000919050565b504090565b61032d610525565b60648160ff161115610370576040517f1a8a06a000000000000000000000000000000000000000000000000000000000815260ff82166004820152602401610273565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000060ff8416908102919091179091556040519081527f29ec9e31de0d3fe0208a7ccb792bbc26a854f123146110daa3a77219cb74a5549060200160405180910390a150565b6103f8610525565b610401816105a8565b50565b60008061041283600461073e565b67ffffffffffffffff81111561042a5761042a6107a3565b6040519080825280601f01601f191660200182016040528015610454576020820181803683370190505b50905073530000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff166349948e0e826040518060c00160405280608c8152602001610890608c91396040516020016104b29291906107f6565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016104dd9190610825565b602060405180830381865afa1580156104fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051e9190610876565b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610273565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610627576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610273565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156106af57600080fd5b5035919050565b6000602082840312156106c857600080fd5b813560ff8116811461051e57600080fd5b6000602082840312156106eb57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461051e57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176101b1576101b161070f565b60008261078b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156101b1576101b161070f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60005b838110156107ed5781810151838201526020016107d5565b50506000910152565b600083516108088184602088016107d2565b83519083019061081c8183602088016107d2565b01949350505050565b60208152600082518060208401526108448160408501602087016107d2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561088857600080fd5b505191905056feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa164736f6c6343000813000a",
}
var ScrollModuleABI = ScrollModuleMetaData.ABI
@@ -213,9 +215,9 @@ func (_ScrollModule *ScrollModuleCallerSession) BlockNumber() (*big.Int, error)
return _ScrollModule.Contract.BlockNumber(&_ScrollModule.CallOpts)
}
-func (_ScrollModule *ScrollModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error) {
+func (_ScrollModule *ScrollModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error) {
var out []interface{}
- err := _ScrollModule.contract.Call(opts, &out, "getCurrentL1Fee")
+ err := _ScrollModule.contract.Call(opts, &out, "getCurrentL1Fee", dataSize)
if err != nil {
return *new(*big.Int), err
@@ -227,12 +229,12 @@ func (_ScrollModule *ScrollModuleCaller) GetCurrentL1Fee(opts *bind.CallOpts) (*
}
-func (_ScrollModule *ScrollModuleSession) GetCurrentL1Fee() (*big.Int, error) {
- return _ScrollModule.Contract.GetCurrentL1Fee(&_ScrollModule.CallOpts)
+func (_ScrollModule *ScrollModuleSession) GetCurrentL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _ScrollModule.Contract.GetCurrentL1Fee(&_ScrollModule.CallOpts, dataSize)
}
-func (_ScrollModule *ScrollModuleCallerSession) GetCurrentL1Fee() (*big.Int, error) {
- return _ScrollModule.Contract.GetCurrentL1Fee(&_ScrollModule.CallOpts)
+func (_ScrollModule *ScrollModuleCallerSession) GetCurrentL1Fee(dataSize *big.Int) (*big.Int, error) {
+ return _ScrollModule.Contract.GetCurrentL1Fee(&_ScrollModule.CallOpts, dataSize)
}
func (_ScrollModule *ScrollModuleCaller) GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
@@ -265,6 +267,28 @@ func (_ScrollModule *ScrollModuleCallerSession) GetGasOverhead() (GetGasOverhead
return _ScrollModule.Contract.GetGasOverhead(&_ScrollModule.CallOpts)
}
+func (_ScrollModule *ScrollModuleCaller) GetL1FeeCoefficient(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ScrollModule.contract.Call(opts, &out, "getL1FeeCoefficient")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ScrollModule *ScrollModuleSession) GetL1FeeCoefficient() (*big.Int, error) {
+ return _ScrollModule.Contract.GetL1FeeCoefficient(&_ScrollModule.CallOpts)
+}
+
+func (_ScrollModule *ScrollModuleCallerSession) GetL1FeeCoefficient() (*big.Int, error) {
+ return _ScrollModule.Contract.GetL1FeeCoefficient(&_ScrollModule.CallOpts)
+}
+
func (_ScrollModule *ScrollModuleCaller) GetMaxL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error) {
var out []interface{}
err := _ScrollModule.contract.Call(opts, &out, "getMaxL1Fee", dataSize)
@@ -287,11 +311,484 @@ func (_ScrollModule *ScrollModuleCallerSession) GetMaxL1Fee(dataSize *big.Int) (
return _ScrollModule.Contract.GetMaxL1Fee(&_ScrollModule.CallOpts, dataSize)
}
+func (_ScrollModule *ScrollModuleCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ScrollModule.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ScrollModule *ScrollModuleSession) Owner() (common.Address, error) {
+ return _ScrollModule.Contract.Owner(&_ScrollModule.CallOpts)
+}
+
+func (_ScrollModule *ScrollModuleCallerSession) Owner() (common.Address, error) {
+ return _ScrollModule.Contract.Owner(&_ScrollModule.CallOpts)
+}
+
+func (_ScrollModule *ScrollModuleTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ScrollModule.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_ScrollModule *ScrollModuleSession) AcceptOwnership() (*types.Transaction, error) {
+ return _ScrollModule.Contract.AcceptOwnership(&_ScrollModule.TransactOpts)
+}
+
+func (_ScrollModule *ScrollModuleTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _ScrollModule.Contract.AcceptOwnership(&_ScrollModule.TransactOpts)
+}
+
+func (_ScrollModule *ScrollModuleTransactor) SetL1FeeCalculation(opts *bind.TransactOpts, coefficient uint8) (*types.Transaction, error) {
+ return _ScrollModule.contract.Transact(opts, "setL1FeeCalculation", coefficient)
+}
+
+func (_ScrollModule *ScrollModuleSession) SetL1FeeCalculation(coefficient uint8) (*types.Transaction, error) {
+ return _ScrollModule.Contract.SetL1FeeCalculation(&_ScrollModule.TransactOpts, coefficient)
+}
+
+func (_ScrollModule *ScrollModuleTransactorSession) SetL1FeeCalculation(coefficient uint8) (*types.Transaction, error) {
+ return _ScrollModule.Contract.SetL1FeeCalculation(&_ScrollModule.TransactOpts, coefficient)
+}
+
+func (_ScrollModule *ScrollModuleTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _ScrollModule.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_ScrollModule *ScrollModuleSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _ScrollModule.Contract.TransferOwnership(&_ScrollModule.TransactOpts, to)
+}
+
+func (_ScrollModule *ScrollModuleTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _ScrollModule.Contract.TransferOwnership(&_ScrollModule.TransactOpts, to)
+}
+
+type ScrollModuleL1FeeCoefficientSetIterator struct {
+ Event *ScrollModuleL1FeeCoefficientSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ScrollModuleL1FeeCoefficientSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ScrollModuleL1FeeCoefficientSet)
+ 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(ScrollModuleL1FeeCoefficientSet)
+ 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 *ScrollModuleL1FeeCoefficientSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *ScrollModuleL1FeeCoefficientSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ScrollModuleL1FeeCoefficientSet struct {
+ Coefficient uint8
+ Raw types.Log
+}
+
+func (_ScrollModule *ScrollModuleFilterer) FilterL1FeeCoefficientSet(opts *bind.FilterOpts) (*ScrollModuleL1FeeCoefficientSetIterator, error) {
+
+ logs, sub, err := _ScrollModule.contract.FilterLogs(opts, "L1FeeCoefficientSet")
+ if err != nil {
+ return nil, err
+ }
+ return &ScrollModuleL1FeeCoefficientSetIterator{contract: _ScrollModule.contract, event: "L1FeeCoefficientSet", logs: logs, sub: sub}, nil
+}
+
+func (_ScrollModule *ScrollModuleFilterer) WatchL1FeeCoefficientSet(opts *bind.WatchOpts, sink chan<- *ScrollModuleL1FeeCoefficientSet) (event.Subscription, error) {
+
+ logs, sub, err := _ScrollModule.contract.WatchLogs(opts, "L1FeeCoefficientSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ScrollModuleL1FeeCoefficientSet)
+ if err := _ScrollModule.contract.UnpackLog(event, "L1FeeCoefficientSet", 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 (_ScrollModule *ScrollModuleFilterer) ParseL1FeeCoefficientSet(log types.Log) (*ScrollModuleL1FeeCoefficientSet, error) {
+ event := new(ScrollModuleL1FeeCoefficientSet)
+ if err := _ScrollModule.contract.UnpackLog(event, "L1FeeCoefficientSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ScrollModuleOwnershipTransferRequestedIterator struct {
+ Event *ScrollModuleOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ScrollModuleOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ScrollModuleOwnershipTransferRequested)
+ 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(ScrollModuleOwnershipTransferRequested)
+ 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 *ScrollModuleOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ScrollModuleOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ScrollModuleOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_ScrollModule *ScrollModuleFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ScrollModuleOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ScrollModule.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ScrollModuleOwnershipTransferRequestedIterator{contract: _ScrollModule.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_ScrollModule *ScrollModuleFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *ScrollModuleOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ScrollModule.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ScrollModuleOwnershipTransferRequested)
+ if err := _ScrollModule.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_ScrollModule *ScrollModuleFilterer) ParseOwnershipTransferRequested(log types.Log) (*ScrollModuleOwnershipTransferRequested, error) {
+ event := new(ScrollModuleOwnershipTransferRequested)
+ if err := _ScrollModule.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ScrollModuleOwnershipTransferredIterator struct {
+ Event *ScrollModuleOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ScrollModuleOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ScrollModuleOwnershipTransferred)
+ 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(ScrollModuleOwnershipTransferred)
+ 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 *ScrollModuleOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *ScrollModuleOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ScrollModuleOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_ScrollModule *ScrollModuleFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ScrollModuleOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ScrollModule.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ScrollModuleOwnershipTransferredIterator{contract: _ScrollModule.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_ScrollModule *ScrollModuleFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *ScrollModuleOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _ScrollModule.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ScrollModuleOwnershipTransferred)
+ if err := _ScrollModule.contract.UnpackLog(event, "OwnershipTransferred", 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 (_ScrollModule *ScrollModuleFilterer) ParseOwnershipTransferred(log types.Log) (*ScrollModuleOwnershipTransferred, error) {
+ event := new(ScrollModuleOwnershipTransferred)
+ if err := _ScrollModule.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
type GetGasOverhead struct {
ChainModuleFixedOverhead *big.Int
ChainModulePerByteOverhead *big.Int
}
+func (_ScrollModule *ScrollModule) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _ScrollModule.abi.Events["L1FeeCoefficientSet"].ID:
+ return _ScrollModule.ParseL1FeeCoefficientSet(log)
+ case _ScrollModule.abi.Events["OwnershipTransferRequested"].ID:
+ return _ScrollModule.ParseOwnershipTransferRequested(log)
+ case _ScrollModule.abi.Events["OwnershipTransferred"].ID:
+ return _ScrollModule.ParseOwnershipTransferred(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (ScrollModuleL1FeeCoefficientSet) Topic() common.Hash {
+ return common.HexToHash("0x29ec9e31de0d3fe0208a7ccb792bbc26a854f123146110daa3a77219cb74a554")
+}
+
+func (ScrollModuleOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (ScrollModuleOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
func (_ScrollModule *ScrollModule) Address() common.Address {
return _ScrollModule.address
}
@@ -301,13 +798,43 @@ type ScrollModuleInterface interface {
BlockNumber(opts *bind.CallOpts) (*big.Int, error)
- GetCurrentL1Fee(opts *bind.CallOpts) (*big.Int, error)
+ GetCurrentL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error)
GetGasOverhead(opts *bind.CallOpts) (GetGasOverhead,
error)
+ GetL1FeeCoefficient(opts *bind.CallOpts) (*big.Int, error)
+
GetMaxL1Fee(opts *bind.CallOpts, dataSize *big.Int) (*big.Int, error)
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetL1FeeCalculation(opts *bind.TransactOpts, coefficient uint8) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ FilterL1FeeCoefficientSet(opts *bind.FilterOpts) (*ScrollModuleL1FeeCoefficientSetIterator, error)
+
+ WatchL1FeeCoefficientSet(opts *bind.WatchOpts, sink chan<- *ScrollModuleL1FeeCoefficientSet) (event.Subscription, error)
+
+ ParseL1FeeCoefficientSet(log types.Log) (*ScrollModuleL1FeeCoefficientSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ScrollModuleOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *ScrollModuleOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*ScrollModuleOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*ScrollModuleOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *ScrollModuleOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*ScrollModuleOwnershipTransferred, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
Address() common.Address
}
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 41c270d61c0..8862fef8c8c 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
@@ -1,7 +1,7 @@
GETH_VERSION: 1.13.8
aggregator_v2v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.bin 95e8814b408bb05bf21742ef580d98698b7db6a9bac6a35c3de12b23aec4ee28
aggregator_v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.bin 351b55d3b0f04af67db6dfb5c92f1c64479400ca1fec77afc20bc0ce65cb49ab
-arbitrum_module: ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.abi ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.bin b76cf77e3e8200c5f292e93af3f620f68f207f83634aacaaee43d682701dfea3
+arbitrum_module: ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.abi ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.bin 12a7bad1f887d832d101a73ae279a91a90c93fd72befea9983e85eff493f62f4
authorized_forwarder: ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.bin 8ea76c883d460f8353a45a493f2aebeb5a2d9a7b4619d1bc4fff5fb590bb3e10
authorized_receiver: ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedReceiver.abi ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedReceiver.bin 18e8969ba3234b027e1b16c11a783aca58d0ea5c2361010ec597f134b7bf1c4f
automation_compatible_utils: ../../contracts/solc/v0.8.19/AutomationCompatibleUtils/AutomationCompatibleUtils.abi ../../contracts/solc/v0.8.19/AutomationCompatibleUtils/AutomationCompatibleUtils.bin dfe88f4f40d124b8cb5f36a7e9f9328008ca57f7ec5d07a28d949d569d5f2834
@@ -12,10 +12,10 @@ automation_registrar_wrapper2_3: ../../contracts/solc/v0.8.19/AutomationRegistra
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 73b5cc3ece642abbf6f2a4c9188335b71404f4dd0ad10b761390b6397af6f1c8
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 fbf6f6cf4e6858855ff5da847c3baa4859dd997cfae51f2fa0651e4fa15b92c9
-automation_registry_logic_c_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicC2_3/AutomationRegistryLogicC2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicC2_3/AutomationRegistryLogicC2_3.bin 6bfe0f54fa7a587a83b6981ffdef28b3cb5e24cae1c95becdf59eed21147d289
-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 f8f920a225fdb1e36948dd95bae3aa46ecc2b01fd113480e111960b5e5f95624
+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 e628b4ba1ca8bf45c2b08c6b80f0b14efbd2dff13b85e5a9ebf643df32335ed2
+automation_registry_logic_c_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicC2_3/AutomationRegistryLogicC2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicC2_3/AutomationRegistryLogicC2_3.bin 19d59318e42f28777756eff60d5c5e52563a2fffb8e3f0f0b07b6d36d82b2c55
+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 7072ba90159d84572f427ec816e78aa032cf907b39bf228185e0c446842f7c11
+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 b6163402434b84e3b66bc078f6efac121c1e1240dca0e8ea89c43db46b4e308b
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 11e2b481dc9a4d936e3443345d45d2cc571164459d214917b42a8054b295393b
@@ -23,8 +23,8 @@ batch_blockhash_store: ../../contracts/solc/v0.8.19/BatchBlockhashStore/BatchBlo
batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.bin 4512f4313bc5c078215c9241a69045a2a3cfecd6adfcef2f13037183a2d71483
batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.19/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin f13715b38b5b9084b08bffa571fb1c8ef686001535902e1255052f074b31ad4e
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_tester: ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.abi ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.bin b3718dad488f54de97d124221d96b867c81e11210084a1fad379cb8385d37ffe
+chain_module_base: ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.abi ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.bin 7a82cc28014761090185c2650239ad01a0901181f1b2b899b42ca293bcda3741
+chain_reader_tester: ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.abi ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.bin b207f9e6bf71e445a2664a602677011b87b80bf95c6352fd7869f1a9ddb08a5b
chain_specific_util_helper: ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin 66eb30b0717fefe05672df5ec863c0b9a5a654623c4757307a2726d8f31e26b1
counter: ../../contracts/solc/v0.8.6/Counter/Counter.abi ../../contracts/solc/v0.8.6/Counter/Counter.bin 6ca06e000e8423573ffa0bdfda749d88236ab3da2a4cbb4a868c706da90488c9
cron_upkeep_factory_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeepFactory.abi - dacb0f8cdf54ae9d2781c5e720fc314b32ed5e58eddccff512c75d6067292cd7
@@ -35,7 +35,7 @@ gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageW
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 06cc87c122452f63fbe84f65329978f30281613be0caa261e53503d94763e921
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_chain_module: ../../contracts/solc/v0.8.19/IChainModule/IChainModule.abi ../../contracts/solc/v0.8.19/IChainModule/IChainModule.bin 8ccb8fcfd1ae331a46b4469e1567c380e2a6d2bf21a9976d6c4c655a716aaa42
i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin ee0f150b3afbab2df3d24ff3f4c87851efa635da30db04cd1f70cb4e185a1781
i_log_automation: ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin 296beccb6af655d6fc3a6e676b244831cce2da6688d3afc4f21f8738ae59e03e
keeper_consumer_performance_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90
@@ -60,9 +60,9 @@ mock_ethusd_aggregator_wrapper: ../../contracts/solc/v0.8.19/MockETHUSDAggregato
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 88e6baa5d9b255eea02616fbcb2cbe21a25ab46adeb6395f6289d169dec949ae
operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin 23c3888eaa7259e6adf2153d09abae8f4b1987dc44200363faab1e65483f32d5
-optimism_module: ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.abi ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.bin a1f8ee97e12b1b2311db03b94dc52b91f3c2e9a2f8d554031a9c7b41e4432280
+optimism_module_v2: ../../contracts/solc/v0.8.19/OptimismModuleV2/OptimismModuleV2.abi ../../contracts/solc/v0.8.19/OptimismModuleV2/OptimismModuleV2.bin 6bc8f93d3a49b3fdecc169214565e6fe5690427860ca4f674818c611dd719502
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
+scroll_module: ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.abi ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.bin 0b99b89ff0c8d95a2ab273c93355e572b9e052ce2a9507498a06e0915b541a86
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_request_id_v08: ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.abi ../../contracts/solc/v0.8.6/VRFRequestIDBaseTestHelper/VRFRequestIDBaseTestHelper.bin f2559015d6f3e5d285c57b011be9b2300632e93dd6c4524e58202d6200f09edc
diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go
index c916380cb43..d877c7a8dbb 100644
--- a/core/gethwrappers/go_generate.go
+++ b/core/gethwrappers/go_generate.go
@@ -53,7 +53,7 @@ package gethwrappers
//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.abi ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.bin AutomationUtils automation_utils_2_3
//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.abi ../../contracts/solc/v0.8.19/ArbitrumModule/ArbitrumModule.bin ArbitrumModule arbitrum_module
//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.abi ../../contracts/solc/v0.8.19/ChainModuleBase/ChainModuleBase.bin ChainModuleBase chain_module_base
-//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.abi ../../contracts/solc/v0.8.19/OptimismModule/OptimismModule.bin OptimismModule optimism_module
+//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/OptimismModuleV2/OptimismModuleV2.abi ../../contracts/solc/v0.8.19/OptimismModuleV2/OptimismModuleV2.bin OptimismModuleV2 optimism_module_v2
//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.abi ../../contracts/solc/v0.8.19/ScrollModule/ScrollModule.bin ScrollModule scroll_module
//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/IChainModule/IChainModule.abi ../../contracts/solc/v0.8.19/IChainModule/IChainModule.bin IChainModule i_chain_module
//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.abi ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.bin IAutomationV21PlusCommon i_automation_v21_plus_common
@@ -154,20 +154,14 @@ package gethwrappers
// ChainReader test contract
//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.abi ../../contracts/solc/v0.8.19/ChainReaderTester/ChainReaderTester.bin ChainReaderTester chain_reader_tester
-// Chainlink Functions
//go:generate go generate ./functions
-
-// Chainlink Keystone
//go:generate go generate ./keystone
-
-// Mercury
//go:generate go generate ./llo-feeds
-
-// Operator Forwarder
//go:generate go generate ./operatorforwarder
-
-// Shared
//go:generate go generate ./shared
+//go:generate go generate ./transmission
+//go:generate go generate ./ccip
+//go:generate go generate ./liquiditymanager
// Mocks that contain only events and functions to emit them
// These contracts are used in testing Atlas flows. The contracts contain no logic, only events, structures, and functions to emit them.
@@ -177,6 +171,3 @@ package gethwrappers
// 3. Compile events mock contracts. ./generation/compile_event_mock_contract.sh calls contracts/scripts/native_solc_compile_all_events_mock to compile events mock contracts.
// 4. Generate wrappers for events mock contracts.
//go:generate ./generation/compile_event_mock_contract.sh
-
-// Transmission
-//go:generate go generate ./transmission
diff --git a/core/gethwrappers/keystone/generated/capabilities_registry/capabilities_registry.go b/core/gethwrappers/keystone/generated/capabilities_registry/capabilities_registry.go
index c345a86569f..9245f2c7386 100644
--- a/core/gethwrappers/keystone/generated/capabilities_registry/capabilities_registry.go
+++ b/core/gethwrappers/keystone/generated/capabilities_registry/capabilities_registry.go
@@ -86,8 +86,8 @@ type CapabilitiesRegistryNodeParams struct {
}
var CapabilitiesRegistryMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AccessForbidden\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityIsDeprecated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"}],\"name\":\"CapabilityRequiredByDON\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"}],\"name\":\"DONDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateDONCapability\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateDONNode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedConfigurationContract\",\"type\":\"address\"}],\"name\":\"InvalidCapabilityConfigurationContractInterface\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"nodeCount\",\"type\":\"uint256\"}],\"name\":\"InvalidFaultTolerance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"}],\"name\":\"InvalidNodeCapabilities\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidNodeOperatorAdmin\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"}],\"name\":\"InvalidNodeP2PId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidNodeSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"lengthOne\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lengthTwo\",\"type\":\"uint256\"}],\"name\":\"LengthMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"NodeAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"NodeDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"}],\"name\":\"NodeDoesNotSupportCapability\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"}],\"name\":\"NodeOperatorDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"NodePartOfCapabilitiesDON\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"NodePartOfWorkflowDON\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityDeprecated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"}],\"name\":\"NodeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NodeOperatorAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"}],\"name\":\"NodeOperatorRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NodeOperatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"}],\"name\":\"NodeRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"}],\"name\":\"NodeUpdated\",\"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\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"labelledName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityType\",\"name\":\"capabilityType\",\"type\":\"uint8\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityResponseType\",\"name\":\"responseType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"configurationContract\",\"type\":\"address\"}],\"internalType\":\"structCapabilitiesRegistry.Capability[]\",\"name\":\"capabilities\",\"type\":\"tuple[]\"}],\"name\":\"addCapabilities\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"nodes\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityConfiguration[]\",\"name\":\"capabilityConfigurations\",\"type\":\"tuple[]\"},{\"internalType\":\"bool\",\"name\":\"isPublic\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"acceptsWorkflows\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"name\":\"addDON\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structCapabilitiesRegistry.NodeOperator[]\",\"name\":\"nodeOperators\",\"type\":\"tuple[]\"}],\"name\":\"addNodeOperators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"}],\"internalType\":\"structCapabilitiesRegistry.NodeParams[]\",\"name\":\"nodes\",\"type\":\"tuple[]\"}],\"name\":\"addNodes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"}],\"name\":\"deprecateCapabilities\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCapabilities\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"hashedId\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"labelledName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityType\",\"name\":\"capabilityType\",\"type\":\"uint8\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityResponseType\",\"name\":\"responseType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"configurationContract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isDeprecated\",\"type\":\"bool\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedId\",\"type\":\"bytes32\"}],\"name\":\"getCapability\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"hashedId\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"labelledName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityType\",\"name\":\"capabilityType\",\"type\":\"uint8\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityResponseType\",\"name\":\"responseType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"configurationContract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isDeprecated\",\"type\":\"bool\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"}],\"name\":\"getCapabilityConfigs\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"}],\"name\":\"getDON\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"id\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isPublic\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"acceptsWorkflows\",\"type\":\"bool\"},{\"internalType\":\"bytes32[]\",\"name\":\"nodeP2PIds\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityConfiguration[]\",\"name\":\"capabilityConfigurations\",\"type\":\"tuple[]\"}],\"internalType\":\"structCapabilitiesRegistry.DONInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONs\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"id\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isPublic\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"acceptsWorkflows\",\"type\":\"bool\"},{\"internalType\":\"bytes32[]\",\"name\":\"nodeP2PIds\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityConfiguration[]\",\"name\":\"capabilityConfigurations\",\"type\":\"tuple[]\"}],\"internalType\":\"structCapabilitiesRegistry.DONInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"labelledName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"}],\"name\":\"getHashedCapabilityId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"}],\"name\":\"getNode\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"workflowDONId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256[]\",\"name\":\"capabilitiesDONIds\",\"type\":\"uint256[]\"}],\"internalType\":\"structCapabilitiesRegistry.NodeInfo\",\"name\":\"nodeInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"}],\"name\":\"getNodeOperator\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structCapabilitiesRegistry.NodeOperator\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNodeOperators\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structCapabilitiesRegistry.NodeOperator[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNodes\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"workflowDONId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256[]\",\"name\":\"capabilitiesDONIds\",\"type\":\"uint256[]\"}],\"internalType\":\"structCapabilitiesRegistry.NodeInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"isCapabilityDeprecated\",\"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\":\"uint32[]\",\"name\":\"donIds\",\"type\":\"uint32[]\"}],\"name\":\"removeDONs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"nodeOperatorIds\",\"type\":\"uint32[]\"}],\"name\":\"removeNodeOperators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"removedNodeP2PIds\",\"type\":\"bytes32[]\"}],\"name\":\"removeNodes\",\"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\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"nodes\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityConfiguration[]\",\"name\":\"capabilityConfigurations\",\"type\":\"tuple[]\"},{\"internalType\":\"bool\",\"name\":\"isPublic\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"acceptsWorkflows\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"name\":\"updateDON\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"nodeOperatorIds\",\"type\":\"uint32[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structCapabilitiesRegistry.NodeOperator[]\",\"name\":\"nodeOperators\",\"type\":\"tuple[]\"}],\"name\":\"updateNodeOperators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"}],\"internalType\":\"structCapabilitiesRegistry.NodeParams[]\",\"name\":\"nodes\",\"type\":\"tuple[]\"}],\"name\":\"updateNodes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
- Bin: "0x6080604052600e80546001600160401b0319166401000000011790553480156200002857600080fd5b503380600081620000805760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000b357620000b381620000bc565b50505062000167565b336001600160a01b03821603620001165760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000077565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6150f680620001776000396000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80635e65e309116100ee5780638da5cb5b11610097578063d8bc7b6811610071578063d8bc7b68146103f6578063ddbe4f8214610409578063e29581aa1461041e578063f2fde38b1461043357600080fd5b80638da5cb5b1461039b5780639cb7c5f4146103c3578063d59a79f6146103e357600080fd5b806373ac22b4116100c857806373ac22b41461036d57806379ba50971461038057806386fa42461461038857600080fd5b80635e65e3091461033257806366acaa3314610345578063715f52951461035a57600080fd5b8063235374051161015b578063398f377311610135578063398f3773146102cb5780633f2a13c9146102de57806350c946fe146102ff5780635d83d9671461031f57600080fd5b80632353740514610285578063275459f2146102a55780632c01a1e8146102b857600080fd5b80631d05394c1161018c5780631d05394c1461023b578063214502431461025057806322bdbcbc1461026557600080fd5b80630fe5800a146101b357806312570011146101d9578063181f5a77146101fc575b600080fd5b6101c66101c1366004613e8b565b610446565b6040519081526020015b60405180910390f35b6101ec6101e7366004613eef565b61047a565b60405190151581526020016101d0565b604080518082018252601a81527f4361706162696c6974696573526567697374727920312e302e30000000000000602082015290516101d09190613f76565b61024e610249366004613fce565b610487565b005b61025861069c565b6040516101d09190614150565b6102786102733660046141eb565b6107f9565b6040516101d09190614243565b6102986102933660046141eb565b6108e6565b6040516101d09190614256565b61024e6102b3366004613fce565b61092a565b61024e6102c6366004613fce565b610a01565b61024e6102d9366004613fce565b610c9d565b6102f16102ec366004614269565b610e5c565b6040516101d0929190614293565b61031261030d366004613eef565b611048565b6040516101d09190614358565b61024e61032d366004613fce565b611122565b61024e610340366004613fce565b611217565b61034d61193f565b6040516101d0919061436b565b61024e610368366004613fce565b611b22565b61024e61037b366004613fce565b611bd4565b61024e6120a2565b61024e6103963660046143e0565b61219f565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d0565b6103d66103d1366004613eef565b6124df565b6040516101d0919061452f565b61024e6103f1366004614561565b61271a565b61024e610404366004614616565b6127e3565b6104116128ad565b6040516101d091906146bb565b6104266129a1565b6040516101d09190614730565b61024e6104413660046147c9565b612aaa565b6000828260405160200161045b929190614293565b6040516020818303038152906040528051906020012090505b92915050565b6000610474600583612abe565b61048f612ad9565b60005b818110156106975760008383838181106104ae576104ae6147e4565b90506020020160208101906104c391906141eb565b63ffffffff8181166000908152600d60209081526040808320805464010000000081049095168085526001820190935290832094955093909290916a010000000000000000000090910460ff16905b61051b83612b5c565b8110156105bb57811561057157600c60006105368584612b66565b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1690556105b3565b6105b18663ffffffff16600c60006105928588612b6690919063ffffffff16565b8152602001908152602001600020600401612b7290919063ffffffff16565b505b600101610512565b508354640100000000900463ffffffff16600003610612576040517f2b62be9b00000000000000000000000000000000000000000000000000000000815263ffffffff861660048201526024015b60405180910390fd5b63ffffffff85166000818152600d6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffff00000000000000000000001690558051938452908301919091527ff264aae70bf6a9d90e68e0f9b393f4e7fbea67b063b0f336e0b36c1581703651910160405180910390a15050505050806001019050610492565b505050565b600e54606090640100000000900463ffffffff1660006106bd600183614842565b63ffffffff1667ffffffffffffffff8111156106db576106db613d25565b60405190808252806020026020018201604052801561076257816020015b6040805160e081018252600080825260208083018290529282018190526060808301829052608083019190915260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816106f95790505b509050600060015b8363ffffffff168163ffffffff1610156107d65763ffffffff8082166000908152600d602052604090205416156107ce576107a481612b7e565b8383815181106107b6576107b66147e4565b6020026020010181905250816107cb9061485f565b91505b60010161076a565b506107e2600184614842565b63ffffffff1681146107f2578082525b5092915050565b60408051808201909152600081526060602082015263ffffffff82166000908152600b60209081526040918290208251808401909352805473ffffffffffffffffffffffffffffffffffffffff168352600181018054919284019161085d90614897565b80601f016020809104026020016040519081016040528092919081815260200182805461088990614897565b80156108d65780601f106108ab576101008083540402835291602001916108d6565b820191906000526020600020905b8154815290600101906020018083116108b957829003601f168201915b5050505050815250509050919050565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082019290925260a0810182905260c081019190915261047482612b7e565b610932612ad9565b60005b63ffffffff811682111561069757600083838363ffffffff1681811061095d5761095d6147e4565b905060200201602081019061097291906141eb565b63ffffffff81166000908152600b6020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001681559192506109bd6001830182613cb8565b505060405163ffffffff8216907fa59268ca81d40429e65ccea5385b59cf2d3fc6519371dee92f8eb1dae5107a7a90600090a2506109fa816148ea565b9050610935565b6000805473ffffffffffffffffffffffffffffffffffffffff163314905b82811015610c97576000848483818110610a3b57610a3b6147e4565b602090810292909201356000818152600c90935260409092206001810154929350919050610a98576040517fd82f6adb00000000000000000000000000000000000000000000000000000000815260048101839052602401610609565b6000610aa682600401612b5c565b1115610afb57610ab96004820184612b66565b6040517f60a6d89800000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015260248101839052604401610609565b805468010000000000000000900463ffffffff1615610b635780546040517f60b9df730000000000000000000000000000000000000000000000000000000081526801000000000000000090910463ffffffff16600482015260248101839052604401610609565b83158015610b9d5750805463ffffffff166000908152600b602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b15610bd6576040517f9473075d000000000000000000000000000000000000000000000000000000008152336004820152602401610609565b6001810154610be790600790612b72565b506002810154610bf990600990612b72565b506000828152600c6020526040812080547fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815560018101829055600281018290559060048201818181610c4e8282613cf2565b5050505050507f5254e609a97bab37b7cc79fe128f85c097bd6015c6e1624ae0ba392eb975320582604051610c8591815260200190565b60405180910390a15050600101610a1f565b50505050565b610ca5612ad9565b60005b81811015610697576000838383818110610cc457610cc46147e4565b9050602002810190610cd6919061490d565b610cdf9061494b565b805190915073ffffffffffffffffffffffffffffffffffffffff16610d30576040517feeacd93900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e54604080518082018252835173ffffffffffffffffffffffffffffffffffffffff908116825260208086015181840190815263ffffffff9095166000818152600b909252939020825181547fffffffffffffffffffffffff00000000000000000000000000000000000000001692169190911781559251919290916001820190610dbc9082614a05565b5050600e8054909150600090610dd79063ffffffff166148ea565b91906101000a81548163ffffffff021916908363ffffffff160217905550816000015173ffffffffffffffffffffffffffffffffffffffff168163ffffffff167f78e94ca80be2c30abc061b99e7eb8583b1254781734b1e3ce339abb57da2fe8e8460200151604051610e4a9190613f76565b60405180910390a35050600101610ca8565b63ffffffff8083166000908152600d60209081526040808320805464010000000090049094168084526001909401825280832085845260030190915281208054606093849390929091610eae90614897565b80601f0160208091040260200160405190810160405280929190818152602001828054610eda90614897565b8015610f275780601f10610efc57610100808354040283529160200191610f27565b820191906000526020600020905b815481529060010190602001808311610f0a57829003601f168201915b5050506000888152600260208190526040909120015492935060609262010000900473ffffffffffffffffffffffffffffffffffffffff1615915061103a905057600086815260026020819052604091829020015490517f8318ed5d00000000000000000000000000000000000000000000000000000000815263ffffffff891660048201526201000090910473ffffffffffffffffffffffffffffffffffffffff1690638318ed5d90602401600060405180830381865afa158015610ff1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526110379190810190614b1f565b90505b9093509150505b9250929050565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082019290925260a0810182905260c08101919091526040805160e0810182526000848152600c6020908152838220805463ffffffff8082168652640100000000820481168487018190526801000000000000000090920416858701526001820154606086015260028201546080860152835260030190529190912060a08201906110f790612e49565b815260200161111a600c6000868152602001908152602001600020600401612e49565b905292915050565b61112a612ad9565b60005b81811015610697576000838383818110611149576111496147e4565b905060200201359050611166816003612abe90919063ffffffff16565b61119f576040517fe181733f00000000000000000000000000000000000000000000000000000000815260048101829052602401610609565b6111aa600582612e56565b6111e3576040517ff7d7a29400000000000000000000000000000000000000000000000000000000815260048101829052602401610609565b60405181907fdcea1b78b6ddc31592a94607d537543fcaafda6cc52d6d5cc7bbfca1422baf2190600090a25060010161112d565b6000805473ffffffffffffffffffffffffffffffffffffffff163314905b82811015610c97576000848483818110611251576112516147e4565b90506020028101906112639190614b8d565b61126c90614bc1565b6040808201516000908152600c6020908152828220805463ffffffff168352600b82528383208451808601909552805473ffffffffffffffffffffffffffffffffffffffff16855260018101805496975091959394939092840191906112d190614897565b80601f01602080910402602001604051908101604052809291908181526020018280546112fd90614897565b801561134a5780601f1061131f5761010080835404028352916020019161134a565b820191906000526020600020905b81548152906001019060200180831161132d57829003601f168201915b50505091909252505050600183015490915061139a5782604001516040517fd82f6adb00000000000000000000000000000000000000000000000000000000815260040161060991815260200190565b841580156113bf5750805173ffffffffffffffffffffffffffffffffffffffff163314155b156113f8576040517f9473075d000000000000000000000000000000000000000000000000000000008152336004820152602401610609565b6020830151611433576040517f8377314600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001820154602084015181146114b457602084015161145490600790612abe565b1561148b576040517f8377314600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602084015160018401556114a0600782612b72565b5060208401516114b290600790612e56565b505b606084015180516000036114f657806040517f3748d4c60000000000000000000000000000000000000000000000000000000081526004016106099190614c94565b8354600090859060049061151790640100000000900463ffffffff166148ea565b91906101000a81548163ffffffff021916908363ffffffff1602179055905060005b82518110156115fc5761156f838281518110611557576115576147e4565b60200260200101516003612abe90919063ffffffff16565b6115a757826040517f3748d4c60000000000000000000000000000000000000000000000000000000081526004016106099190614c94565b6115f38382815181106115bc576115bc6147e4565b60200260200101518760030160008563ffffffff1663ffffffff168152602001908152602001600020612e5690919063ffffffff16565b50600101611539565b50845468010000000000000000900463ffffffff16801561175d5763ffffffff8082166000908152600d60209081526040808320805464010000000090049094168352600190930181528282206002018054845181840281018401909552808552929392909183018282801561169157602002820191906000526020600020905b81548152602001906001019080831161167d575b5050505050905060005b815181101561175a576116f08282815181106116b9576116b96147e4565b60200260200101518960030160008763ffffffff1663ffffffff168152602001908152602001600020612abe90919063ffffffff16565b61175257818181518110611706576117066147e4565b6020026020010151836040517f03dcd86200000000000000000000000000000000000000000000000000000000815260040161060992919091825263ffffffff16602082015260400190565b60010161169b565b50505b600061176b87600401612e49565b905060005b81518163ffffffff1610156118b1576000828263ffffffff1681518110611799576117996147e4565b60209081029190910181015163ffffffff8082166000908152600d8452604080822080546401000000009004909316825260019092018452818120600201805483518187028101870190945280845293955090939192909183018282801561182057602002820191906000526020600020905b81548152602001906001019080831161180c575b5050505050905060005b815181101561189d5761187f828281518110611848576118486147e4565b60200260200101518c60030160008a63ffffffff1663ffffffff168152602001908152602001600020612abe90919063ffffffff16565b61189557818181518110611706576117066147e4565b60010161182a565b505050806118aa906148ea565b9050611770565b50875187547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff90911690811788556040808a015160028a018190556020808c01518351928352908201527f4b5b465e22eea0c3d40c30e936643245b80d19b2dcf75788c0699fe8d8db645b910160405180910390a25050505050505050806001019050611235565b600e5460609063ffffffff166000611958600183614842565b63ffffffff1667ffffffffffffffff81111561197657611976613d25565b6040519080825280602002602001820160405280156119bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816119945790505b509050600060015b8363ffffffff168163ffffffff161015611b0c5763ffffffff81166000908152600b602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611b045763ffffffff81166000908152600b60209081526040918290208251808401909352805473ffffffffffffffffffffffffffffffffffffffff1683526001810180549192840191611a5890614897565b80601f0160208091040260200160405190810160405280929190818152602001828054611a8490614897565b8015611ad15780601f10611aa657610100808354040283529160200191611ad1565b820191906000526020600020905b815481529060010190602001808311611ab457829003601f168201915b505050505081525050838381518110611aec57611aec6147e4565b602002602001018190525081611b019061485f565b91505b6001016119c4565b50600e546107e29060019063ffffffff16614842565b611b2a612ad9565b60005b81811015610697576000838383818110611b4957611b496147e4565b9050602002810190611b5b9190614cd8565b611b6490614d1b565b90506000611b7a82600001518360200151610446565b9050611b87600382612e56565b611bc0576040517febf5255100000000000000000000000000000000000000000000000000000000815260048101829052602401610609565b611bca8183612e62565b5050600101611b2d565b6000805473ffffffffffffffffffffffffffffffffffffffff163314905b82811015610c97576000848483818110611c0e57611c0e6147e4565b9050602002810190611c209190614b8d565b611c2990614bc1565b805163ffffffff166000908152600b602090815260408083208151808301909252805473ffffffffffffffffffffffffffffffffffffffff168252600181018054959650939491939092840191611c7f90614897565b80601f0160208091040260200160405190810160405280929190818152602001828054611cab90614897565b8015611cf85780601f10611ccd57610100808354040283529160200191611cf8565b820191906000526020600020905b815481529060010190602001808311611cdb57829003601f168201915b50505091909252505081519192505073ffffffffffffffffffffffffffffffffffffffff16611d5e5781516040517fadd9ae1e00000000000000000000000000000000000000000000000000000000815263ffffffff9091166004820152602401610609565b83158015611d835750805173ffffffffffffffffffffffffffffffffffffffff163314155b15611dbc576040517f9473075d000000000000000000000000000000000000000000000000000000008152336004820152602401610609565b6040808301516000908152600c60205220600181015415611e115782604001516040517f5461848300000000000000000000000000000000000000000000000000000000815260040161060991815260200190565b6040830151611e545782604001516040517f64e2ee9200000000000000000000000000000000000000000000000000000000815260040161060991815260200190565b60208301511580611e7157506020830151611e7190600790612abe565b15611ea8576040517f8377314600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301518051600003611eea57806040517f3748d4c60000000000000000000000000000000000000000000000000000000081526004016106099190614c94565b81548290600490611f0890640100000000900463ffffffff166148ea565b82546101009290920a63ffffffff818102199093169183160217909155825464010000000090041660005b8251811015611fde57611f51838281518110611557576115576147e4565b611f8957826040517f3748d4c60000000000000000000000000000000000000000000000000000000081526004016106099190614c94565b611fd5838281518110611f9e57611f9e6147e4565b60200260200101518560030160008563ffffffff1663ffffffff168152602001908152602001600020612e5690919063ffffffff16565b50600101611f33565b50845183547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff918216178455604086015160028501556020860151600185018190556120349160079190612e5616565b50604085015161204690600990612e56565b50845160408087015160208089015183519283529082015263ffffffff909216917f74becb12a5e8fd0e98077d02dfba8f647c9670c9df177e42c2418cf17a636f05910160405180910390a25050505050806001019050611bf2565b60015473ffffffffffffffffffffffffffffffffffffffff163314612123576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610609565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b8281146121e2576040517fab8b67c60000000000000000000000000000000000000000000000000000000081526004810184905260248101829052604401610609565b6000805473ffffffffffffffffffffffffffffffffffffffff16905b848110156124d757600086868381811061221a5761221a6147e4565b905060200201602081019061222f91906141eb565b63ffffffff81166000908152600b6020526040902080549192509073ffffffffffffffffffffffffffffffffffffffff1661229e576040517fadd9ae1e00000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152602401610609565b60008686858181106122b2576122b26147e4565b90506020028101906122c4919061490d565b6122cd9061494b565b805190915073ffffffffffffffffffffffffffffffffffffffff1661231e576040517feeacd93900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815473ffffffffffffffffffffffffffffffffffffffff16331480159061235b57503373ffffffffffffffffffffffffffffffffffffffff861614155b15612394576040517f9473075d000000000000000000000000000000000000000000000000000000008152336004820152602401610609565b8051825473ffffffffffffffffffffffffffffffffffffffff908116911614158061241057506020808201516040516123cd9201613f76565b60405160208183030381529060405280519060200120826001016040516020016123f79190614dc1565b6040516020818303038152906040528051906020012014155b156124c957805182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020810151600183019061246a9082614a05565b50806000015173ffffffffffffffffffffffffffffffffffffffff168363ffffffff167f86f41145bde5dd7f523305452e4aad3685508c181432ec733d5f345009358a2883602001516040516124c09190613f76565b60405180910390a35b5050508060010190506121fe565b505050505050565b6125206040805160e0810182526000808252606060208301819052928201839052909182019081526020016000815260006020820181905260409091015290565b6040805160e0810182528381526000848152600260209081529290208054919283019161254c90614897565b80601f016020809104026020016040519081016040528092919081815260200182805461257890614897565b80156125c55780601f1061259a576101008083540402835291602001916125c5565b820191906000526020600020905b8154815290600101906020018083116125a857829003601f168201915b505050505081526020016002600085815260200190815260200160002060010180546125f090614897565b80601f016020809104026020016040519081016040528092919081815260200182805461261c90614897565b80156126695780601f1061263e57610100808354040283529160200191612669565b820191906000526020600020905b81548152906001019060200180831161264c57829003601f168201915b50505091835250506000848152600260208181526040909220015491019060ff16600381111561269b5761269b61444c565b815260008481526002602081815260409092200154910190610100900460ff1660018111156126cc576126cc61444c565b81526000848152600260208181526040928390209091015462010000900473ffffffffffffffffffffffffffffffffffffffff169083015201612710600585612abe565b1515905292915050565b612722612ad9565b63ffffffff8089166000908152600d6020526040812054640100000000900490911690819003612786576040517f2b62be9b00000000000000000000000000000000000000000000000000000000815263ffffffff8a166004820152602401610609565b6127d8888888886040518060a001604052808f63ffffffff168152602001876127ae906148ea565b97508763ffffffff1681526020018a1515815260200189151581526020018860ff168152506130f6565b505050505050505050565b6127eb612ad9565b600e805460009164010000000090910463ffffffff1690600461280d836148ea565b82546101009290920a63ffffffff81810219909316918316021790915581166000818152600d602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001684179055815160a08101835292835260019083015286151590820152841515606082015260ff841660808201529091506128a39089908990899089906130f6565b5050505050505050565b606060006128bb6003612e49565b90506000815167ffffffffffffffff8111156128d9576128d9613d25565b60405190808252806020026020018201604052801561294b57816020015b6129386040805160e0810182526000808252606060208301819052928201839052909182019081526020016000815260006020820181905260409091015290565b8152602001906001900390816128f75790505b50905060005b82518110156107f25761297c83828151811061296f5761296f6147e4565b60200260200101516124df565b82828151811061298e5761298e6147e4565b6020908102919091010152600101612951565b606060006129af6009612e49565b90506000815167ffffffffffffffff8111156129cd576129cd613d25565b604051908082528060200260200182016040528015612a5457816020015b6040805160e081018252600080825260208083018290529282018190526060808301829052608083019190915260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816129eb5790505b50905060005b82518110156107f257612a85838281518110612a7857612a786147e4565b6020026020010151611048565b828281518110612a9757612a976147e4565b6020908102919091010152600101612a5a565b612ab2612ad9565b612abb8161391a565b50565b600081815260018301602052604081205415155b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612b5a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610609565b565b6000610474825490565b6000612ad28383613a0f565b6000612ad28383613a39565b6040805160e0810182526000808252602080830182905282840182905260608084018390526080840183905260a0840181905260c084015263ffffffff8581168352600d8252848320805464010000000090049091168084526001909101825284832060028101805487518186028101860190985280885295969295919493909190830182828015612c2f57602002820191906000526020600020905b815481526020019060010190808311612c1b575b505050505090506000815167ffffffffffffffff811115612c5257612c52613d25565b604051908082528060200260200182016040528015612c9857816020015b604080518082019091526000815260606020820152815260200190600190039081612c705790505b50905060005b8151811015612db0576040518060400160405280848381518110612cc457612cc46147e4565b60200260200101518152602001856003016000868581518110612ce957612ce96147e4565b602002602001015181526020019081526020016000208054612d0a90614897565b80601f0160208091040260200160405190810160405280929190818152602001828054612d3690614897565b8015612d835780601f10612d5857610100808354040283529160200191612d83565b820191906000526020600020905b815481529060010190602001808311612d6657829003601f168201915b5050505050815250828281518110612d9d57612d9d6147e4565b6020908102919091010152600101612c9e565b506040805160e08101825263ffffffff8089166000818152600d6020818152868320548086168752948b168187015260ff680100000000000000008604811697870197909752690100000000000000000085048716151560608701529290915290526a010000000000000000000090049091161515608082015260a08101612e3785612e49565b81526020019190915295945050505050565b60606000612ad283613b2c565b6000612ad28383613b88565b608081015173ffffffffffffffffffffffffffffffffffffffff1615612fb057608081015173ffffffffffffffffffffffffffffffffffffffff163b1580612f5b575060808101516040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f78bea72100000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff909116906301ffc9a790602401602060405180830381865afa158015612f35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f599190614e6f565b155b15612fb05760808101516040517fabb5e3fd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610609565b600082815260026020526040902081518291908190612fcf9082614a05565b5060208201516001820190612fe49082614a05565b5060408201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360038111156130265761302661444c565b021790555060608201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010083600181111561306d5761306d61444c565b0217905550608091909101516002909101805473ffffffffffffffffffffffffffffffffffffffff90921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff90921691909117905560405182907f04f0a9bcf3f3a3b42a4d7ca081119755f82ebe43e0d30c8f7292c4fe0dc4a2ae90600090a25050565b805163ffffffff9081166000908152600d602090815260408083208286015190941683526001909301905220608082015160ff161580613148575060808201518590613143906001614e8c565b60ff16115b156131915760808201516040517f25b4d61800000000000000000000000000000000000000000000000000000000815260ff909116600482015260248101869052604401610609565b6001826020015163ffffffff16111561327957815163ffffffff166000908152600d6020908152604082209084015160019182019183916131d29190614842565b63ffffffff1663ffffffff168152602001908152602001600020905060005b6131fa82612b5c565b81101561327657613229846000015163ffffffff16600c60006105928587600001612b6690919063ffffffff16565b50600c60006132388484612b66565b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1690556001016131f1565b50505b60005b858110156134b3576132a9878783818110613299576132996147e4565b8592602090910201359050612e56565b61330a5782518787838181106132c1576132c16147e4565b6040517f636e405700000000000000000000000000000000000000000000000000000000815263ffffffff90941660048501526020029190910135602483015250604401610609565b82606001511561346157825163ffffffff16600c6000898985818110613332576133326147e4565b602090810292909201358352508101919091526040016000205468010000000000000000900463ffffffff16148015906133ac5750600c600088888481811061337d5761337d6147e4565b602090810292909201358352508101919091526040016000205468010000000000000000900463ffffffff1615155b1561340e5782518787838181106133c5576133c56147e4565b6040517f60b9df7300000000000000000000000000000000000000000000000000000000815263ffffffff90941660048501526020029190910135602483015250604401610609565b8251600c6000898985818110613426576134266147e4565b90506020020135815260200190815260200160002060000160086101000a81548163ffffffff021916908363ffffffff1602179055506134ab565b82516134a99063ffffffff16600c60008a8a86818110613483576134836147e4565b905060200201358152602001908152602001600020600401612e5690919063ffffffff16565b505b60010161327c565b5060005b8381101561378f57368585838181106134d2576134d26147e4565b90506020028101906134e4919061490d565b90506134f260038235612abe565b61352b576040517fe181733f00000000000000000000000000000000000000000000000000000000815281356004820152602401610609565b61353760058235612abe565b15613571576040517ff7d7a29400000000000000000000000000000000000000000000000000000000815281356004820152602401610609565b803560009081526003840160205260408120805461358e90614897565b905011156135da5783516040517f3927d08000000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015281356024820152604401610609565b60005b878110156136e4576136818235600c60008c8c86818110613600576136006147e4565b9050602002013581526020019081526020016000206003016000600c60008e8e88818110613630576136306147e4565b90506020020135815260200190815260200160002060000160049054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001908152602001600020612abe90919063ffffffff16565b6136dc57888882818110613697576136976147e4565b6040517fa7e792500000000000000000000000000000000000000000000000000000000081526020909102929092013560048301525082356024820152604401610609565b6001016135dd565b506002830180546001810182556000918252602091829020833591015561370d90820182614ea5565b8235600090815260038601602052604090209161372b919083614f0a565b50835160208086015161378692918435908c908c9061374c90880188614ea5565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613bd792505050565b506001016134b7565b50604080830151835163ffffffff9081166000908152600d602090815284822080549415156901000000000000000000027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff90951694909417909355606086015186518316825284822080549115156a0100000000000000000000027fffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff9092169190911790556080860151865183168252848220805460ff9290921668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff909216919091179055918501805186518316845292849020805493909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff9093169290921790558351905191517ff264aae70bf6a9d90e68e0f9b393f4e7fbea67b063b0f336e0b36c15817036519261390a929163ffffffff92831681529116602082015260400190565b60405180910390a1505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613999576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610609565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110613a2657613a266147e4565b9060005260206000200154905092915050565b60008181526001830160205260408120548015613b22576000613a5d600183615025565b8554909150600090613a7190600190615025565b9050818114613ad6576000866000018281548110613a9157613a916147e4565b9060005260206000200154905080876000018481548110613ab457613ab46147e4565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613ae757613ae7615038565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610474565b6000915050610474565b606081600001805480602002602001604051908101604052809291908181526020018280548015613b7c57602002820191906000526020600020905b815481526020019060010190808311613b68575b50505050509050919050565b6000818152600183016020526040812054613bcf57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610474565b506000610474565b6000848152600260208190526040909120015462010000900473ffffffffffffffffffffffffffffffffffffffff16156124d757600084815260026020819052604091829020015490517ffba64a7c0000000000000000000000000000000000000000000000000000000081526201000090910473ffffffffffffffffffffffffffffffffffffffff169063fba64a7c90613c7e908690869086908b908d90600401615067565b600060405180830381600087803b158015613c9857600080fd5b505af1158015613cac573d6000803e3d6000fd5b50505050505050505050565b508054613cc490614897565b6000825580601f10613cd4575050565b601f016020900490600052602060002090810190612abb9190613d0c565b5080546000825590600052602060002090810190612abb91905b5b80821115613d215760008155600101613d0d565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613d7757613d77613d25565b60405290565b60405160a0810167ffffffffffffffff81118282101715613d7757613d77613d25565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613de757613de7613d25565b604052919050565b600067ffffffffffffffff821115613e0957613e09613d25565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613e4657600080fd5b8135613e59613e5482613def565b613da0565b818152846020838601011115613e6e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215613e9e57600080fd5b823567ffffffffffffffff80821115613eb657600080fd5b613ec286838701613e35565b93506020850135915080821115613ed857600080fd5b50613ee585828601613e35565b9150509250929050565b600060208284031215613f0157600080fd5b5035919050565b60005b83811015613f23578181015183820152602001613f0b565b50506000910152565b60008151808452613f44816020860160208601613f08565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612ad26020830184613f2c565b60008083601f840112613f9b57600080fd5b50813567ffffffffffffffff811115613fb357600080fd5b6020830191508360208260051b850101111561104157600080fd5b60008060208385031215613fe157600080fd5b823567ffffffffffffffff811115613ff857600080fd5b61400485828601613f89565b90969095509350505050565b60008151808452602080850194506020840160005b8381101561404157815187529582019590820190600101614025565b509495945050505050565b600082825180855260208086019550808260051b84010181860160005b848110156140c9578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051845284015160408585018190526140b581860183613f2c565b9a86019a9450505090830190600101614069565b5090979650505050505050565b600063ffffffff8083511684528060208401511660208501525060ff604083015116604084015260608201511515606084015260808201511515608084015260a082015160e060a085015261412e60e0850182614010565b905060c083015184820360c0860152614147828261404c565b95945050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156141c5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526141b38583516140d6565b94509285019290850190600101614179565b5092979650505050505050565b803563ffffffff811681146141e657600080fd5b919050565b6000602082840312156141fd57600080fd5b612ad2826141d2565b73ffffffffffffffffffffffffffffffffffffffff8151168252600060208201516040602085015261423b6040850182613f2c565b949350505050565b602081526000612ad26020830184614206565b602081526000612ad260208301846140d6565b6000806040838503121561427c57600080fd5b614285836141d2565b946020939093013593505050565b6040815260006142a66040830185613f2c565b82810360208401526141478185613f2c565b600063ffffffff808351168452602081818501511681860152816040850151166040860152606084015160608601526080840151608086015260a0840151915060e060a086015261430c60e0860183614010565b60c08581015187830391880191909152805180835290830193506000918301905b8083101561434d578451825293830193600192909201919083019061432d565b509695505050505050565b602081526000612ad260208301846142b8565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156141c5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526143ce858351614206565b94509285019290850190600101614394565b600080600080604085870312156143f657600080fd5b843567ffffffffffffffff8082111561440e57600080fd5b61441a88838901613f89565b9096509450602087013591508082111561443357600080fd5b5061444087828801613f89565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b805182526000602082015160e0602085015261449a60e0850182613f2c565b9050604083015184820360408601526144b38282613f2c565b9150506060830151600481106144cb576144cb61444c565b60608501526080830151600281106144e5576144e561444c565b8060808601525060a083015161451360a086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015161452760c086018215159052565b509392505050565b602081526000612ad2602083018461447b565b8015158114612abb57600080fd5b803560ff811681146141e657600080fd5b60008060008060008060008060c0898b03121561457d57600080fd5b614586896141d2565b9750602089013567ffffffffffffffff808211156145a357600080fd5b6145af8c838d01613f89565b909950975060408b01359150808211156145c857600080fd5b506145d58b828c01613f89565b90965094505060608901356145e981614542565b925060808901356145f981614542565b915061460760a08a01614550565b90509295985092959890939650565b600080600080600080600060a0888a03121561463157600080fd5b873567ffffffffffffffff8082111561464957600080fd5b6146558b838c01613f89565b909950975060208a013591508082111561466e57600080fd5b5061467b8a828b01613f89565b909650945050604088013561468f81614542565b9250606088013561469f81614542565b91506146ad60808901614550565b905092959891949750929550565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156141c5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261471e85835161447b565b945092850192908501906001016146e4565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156141c5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526147938583516142b8565b94509285019290850190600101614759565b803573ffffffffffffffffffffffffffffffffffffffff811681146141e657600080fd5b6000602082840312156147db57600080fd5b612ad2826147a5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff8281168282160390808211156107f2576107f2614813565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361489057614890614813565b5060010190565b600181811c908216806148ab57607f821691505b6020821081036148e4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600063ffffffff80831681810361490357614903614813565b6001019392505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261494157600080fd5b9190910192915050565b60006040823603121561495d57600080fd5b6040516040810167ffffffffffffffff828210818311171561498157614981613d25565b8160405261498e856147a5565b835260208501359150808211156149a457600080fd5b506149b136828601613e35565b60208301525092915050565b601f821115610697576000816000526020600020601f850160051c810160208610156149e65750805b601f850160051c820191505b818110156124d7578281556001016149f2565b815167ffffffffffffffff811115614a1f57614a1f613d25565b614a3381614a2d8454614897565b846149bd565b602080601f831160018114614a865760008415614a505750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556124d7565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614ad357888601518255948401946001909101908401614ab4565b5085821015614b0f57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215614b3157600080fd5b815167ffffffffffffffff811115614b4857600080fd5b8201601f81018413614b5957600080fd5b8051614b67613e5482613def565b818152856020838501011115614b7c57600080fd5b614147826020830160208601613f08565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261494157600080fd5b600060808236031215614bd357600080fd5b614bdb613d54565b614be4836141d2565b81526020808401358183015260408401356040830152606084013567ffffffffffffffff80821115614c1557600080fd5b9085019036601f830112614c2857600080fd5b813581811115614c3a57614c3a613d25565b8060051b9150614c4b848301613da0565b8181529183018401918481019036841115614c6557600080fd5b938501935b83851015614c8357843582529385019390850190614c6a565b606087015250939695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015614ccc57835183529284019291840191600101614cb0565b50909695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6183360301811261494157600080fd5b8035600281106141e657600080fd5b600060a08236031215614d2d57600080fd5b614d35613d7d565b823567ffffffffffffffff80821115614d4d57600080fd5b614d5936838701613e35565b83526020850135915080821115614d6f57600080fd5b50614d7c36828601613e35565b602083015250604083013560048110614d9457600080fd5b6040820152614da560608401614d0c565b6060820152614db6608084016147a5565b608082015292915050565b6000602080835260008454614dd581614897565b8060208701526040600180841660008114614df75760018114614e3157614e61565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00851660408a0152604084151560051b8a01019550614e61565b89600052602060002060005b85811015614e585781548b8201860152908301908801614e3d565b8a016040019650505b509398975050505050505050565b600060208284031215614e8157600080fd5b8151612ad281614542565b60ff818116838216019081111561047457610474614813565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614eda57600080fd5b83018035915067ffffffffffffffff821115614ef557600080fd5b60200191503681900382131561104157600080fd5b67ffffffffffffffff831115614f2257614f22613d25565b614f3683614f308354614897565b836149bd565b6000601f841160018114614f885760008515614f525750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835561501e565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614fd75786850135825560209485019460019092019101614fb7565b5086821015615012577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b8181038181111561047457610474614813565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6080815284608082015260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8611156150a057600080fd5b8560051b808860a0850137820182810360a090810160208501526150c690820187613f2c565b91505063ffffffff8085166040840152808416606084015250969550505050505056fea164736f6c6343000818000a",
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AccessForbidden\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityIsDeprecated\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"}],\"name\":\"CapabilityRequiredByDON\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"}],\"name\":\"DONDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateDONCapability\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateDONNode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedConfigurationContract\",\"type\":\"address\"}],\"name\":\"InvalidCapabilityConfigurationContractInterface\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"nodeCount\",\"type\":\"uint256\"}],\"name\":\"InvalidFaultTolerance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"}],\"name\":\"InvalidNodeCapabilities\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidNodeOperatorAdmin\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"}],\"name\":\"InvalidNodeP2PId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidNodeSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"lengthOne\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lengthTwo\",\"type\":\"uint256\"}],\"name\":\"LengthMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"NodeAlreadyExists\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"NodeDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"}],\"name\":\"NodeDoesNotSupportCapability\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"}],\"name\":\"NodeOperatorDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"NodePartOfCapabilitiesDON\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nodeP2PId\",\"type\":\"bytes32\"}],\"name\":\"NodePartOfWorkflowDON\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityConfigured\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"CapabilityDeprecated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"}],\"name\":\"NodeAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NodeOperatorAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"}],\"name\":\"NodeOperatorRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"name\":\"NodeOperatorUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"}],\"name\":\"NodeRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"}],\"name\":\"NodeUpdated\",\"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\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"labelledName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityType\",\"name\":\"capabilityType\",\"type\":\"uint8\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityResponseType\",\"name\":\"responseType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"configurationContract\",\"type\":\"address\"}],\"internalType\":\"structCapabilitiesRegistry.Capability[]\",\"name\":\"capabilities\",\"type\":\"tuple[]\"}],\"name\":\"addCapabilities\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"nodes\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityConfiguration[]\",\"name\":\"capabilityConfigurations\",\"type\":\"tuple[]\"},{\"internalType\":\"bool\",\"name\":\"isPublic\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"acceptsWorkflows\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"name\":\"addDON\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structCapabilitiesRegistry.NodeOperator[]\",\"name\":\"nodeOperators\",\"type\":\"tuple[]\"}],\"name\":\"addNodeOperators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"}],\"internalType\":\"structCapabilitiesRegistry.NodeParams[]\",\"name\":\"nodes\",\"type\":\"tuple[]\"}],\"name\":\"addNodes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"}],\"name\":\"deprecateCapabilities\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCapabilities\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"hashedId\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"labelledName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityType\",\"name\":\"capabilityType\",\"type\":\"uint8\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityResponseType\",\"name\":\"responseType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"configurationContract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isDeprecated\",\"type\":\"bool\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedId\",\"type\":\"bytes32\"}],\"name\":\"getCapability\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"hashedId\",\"type\":\"bytes32\"},{\"internalType\":\"string\",\"name\":\"labelledName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityType\",\"name\":\"capabilityType\",\"type\":\"uint8\"},{\"internalType\":\"enumCapabilitiesRegistry.CapabilityResponseType\",\"name\":\"responseType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"configurationContract\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isDeprecated\",\"type\":\"bool\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"}],\"name\":\"getCapabilityConfigs\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"}],\"name\":\"getDON\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"id\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isPublic\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"acceptsWorkflows\",\"type\":\"bool\"},{\"internalType\":\"bytes32[]\",\"name\":\"nodeP2PIds\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityConfiguration[]\",\"name\":\"capabilityConfigurations\",\"type\":\"tuple[]\"}],\"internalType\":\"structCapabilitiesRegistry.DONInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONs\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"id\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isPublic\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"acceptsWorkflows\",\"type\":\"bool\"},{\"internalType\":\"bytes32[]\",\"name\":\"nodeP2PIds\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityConfiguration[]\",\"name\":\"capabilityConfigurations\",\"type\":\"tuple[]\"}],\"internalType\":\"structCapabilitiesRegistry.DONInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"labelledName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"}],\"name\":\"getHashedCapabilityId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"}],\"name\":\"getNode\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"workflowDONId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256[]\",\"name\":\"capabilitiesDONIds\",\"type\":\"uint256[]\"}],\"internalType\":\"structCapabilitiesRegistry.NodeInfo\",\"name\":\"nodeInfo\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"}],\"name\":\"getNodeOperator\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structCapabilitiesRegistry.NodeOperator\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNodeOperators\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structCapabilitiesRegistry.NodeOperator[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getNodes\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"workflowDONId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256[]\",\"name\":\"capabilitiesDONIds\",\"type\":\"uint256[]\"}],\"internalType\":\"structCapabilitiesRegistry.NodeInfo[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"hashedCapabilityId\",\"type\":\"bytes32\"}],\"name\":\"isCapabilityDeprecated\",\"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\":\"uint32[]\",\"name\":\"donIds\",\"type\":\"uint32[]\"}],\"name\":\"removeDONs\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"nodeOperatorIds\",\"type\":\"uint32[]\"}],\"name\":\"removeNodeOperators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"removedNodeP2PIds\",\"type\":\"bytes32[]\"}],\"name\":\"removeNodes\",\"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\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32[]\",\"name\":\"nodes\",\"type\":\"bytes32[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"capabilityId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"config\",\"type\":\"bytes\"}],\"internalType\":\"structCapabilitiesRegistry.CapabilityConfiguration[]\",\"name\":\"capabilityConfigurations\",\"type\":\"tuple[]\"},{\"internalType\":\"bool\",\"name\":\"isPublic\",\"type\":\"bool\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"}],\"name\":\"updateDON\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"nodeOperatorIds\",\"type\":\"uint32[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"}],\"internalType\":\"structCapabilitiesRegistry.NodeOperator[]\",\"name\":\"nodeOperators\",\"type\":\"tuple[]\"}],\"name\":\"updateNodeOperators\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"nodeOperatorId\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"signer\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"p2pId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"hashedCapabilityIds\",\"type\":\"bytes32[]\"}],\"internalType\":\"structCapabilitiesRegistry.NodeParams[]\",\"name\":\"nodes\",\"type\":\"tuple[]\"}],\"name\":\"updateNodes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x6080604052600e80546001600160401b0319166401000000011790553480156200002857600080fd5b503380600081620000805760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000b357620000b381620000bc565b50505062000167565b336001600160a01b03821603620001165760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000077565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6150e080620001776000396000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80635d83d967116100ee57806386fa424611610097578063d8bc7b6811610071578063d8bc7b68146103f6578063ddbe4f8214610409578063e29581aa1461041e578063f2fde38b1461043357600080fd5b806386fa42461461039b5780638da5cb5b146103ae5780639cb7c5f4146103d657600080fd5b8063715f5295116100c8578063715f52951461036d57806373ac22b41461038057806379ba50971461039357600080fd5b80635d83d967146103325780635e65e3091461034557806366acaa331461035857600080fd5b8063235374051161015b5780632c01a1e8116101355780632c01a1e8146102cb578063398f3773146102de5780633f2a13c9146102f157806350c946fe1461031257600080fd5b80632353740514610285578063275459f2146102a55780632a852933146102b857600080fd5b80631d05394c1161018c5780631d05394c1461023b578063214502431461025057806322bdbcbc1461026557600080fd5b80630fe5800a146101b357806312570011146101d9578063181f5a77146101fc575b600080fd5b6101c66101c1366004613ea3565b610446565b6040519081526020015b60405180910390f35b6101ec6101e7366004613f07565b61047a565b60405190151581526020016101d0565b604080518082018252601a81527f4361706162696c6974696573526567697374727920312e302e30000000000000602082015290516101d09190613f8e565b61024e610249366004613fe6565b610487565b005b61025861069c565b6040516101d09190614168565b610278610273366004614203565b6107f9565b6040516101d0919061425b565b610298610293366004614203565b6108e6565b6040516101d0919061426e565b61024e6102b3366004613fe6565b61092a565b61024e6102c63660046142a0565b610a01565b61024e6102d9366004613fe6565b610ae1565b61024e6102ec366004613fe6565b610d7d565b6103046102ff366004614343565b610f3c565b6040516101d092919061436d565b610325610320366004613f07565b611128565b6040516101d09190614432565b61024e610340366004613fe6565b611202565b61024e610353366004613fe6565b6112f7565b610360611a1f565b6040516101d09190614445565b61024e61037b366004613fe6565b611c02565b61024e61038e366004613fe6565b611cb4565b61024e612182565b61024e6103a93660046144ba565b61227f565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d0565b6103e96103e4366004613f07565b6125bf565b6040516101d09190614609565b61024e61040436600461461c565b6127fa565b6104116128c4565b6040516101d091906146a5565b6104266129b8565b6040516101d0919061471a565b61024e6104413660046147b3565b612ac1565b6000828260405160200161045b92919061436d565b6040516020818303038152906040528051906020012090505b92915050565b6000610474600583612ad5565b61048f612af0565b60005b818110156106975760008383838181106104ae576104ae6147ce565b90506020020160208101906104c39190614203565b63ffffffff8181166000908152600d60209081526040808320805464010000000081049095168085526001820190935290832094955093909290916a010000000000000000000090910460ff16905b61051b83612b73565b8110156105bb57811561057157600c60006105368584612b7d565b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1690556105b3565b6105b18663ffffffff16600c60006105928588612b7d90919063ffffffff16565b8152602001908152602001600020600401612b8990919063ffffffff16565b505b600101610512565b508354640100000000900463ffffffff16600003610612576040517f2b62be9b00000000000000000000000000000000000000000000000000000000815263ffffffff861660048201526024015b60405180910390fd5b63ffffffff85166000818152600d6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffff00000000000000000000001690558051938452908301919091527ff264aae70bf6a9d90e68e0f9b393f4e7fbea67b063b0f336e0b36c1581703651910160405180910390a15050505050806001019050610492565b505050565b600e54606090640100000000900463ffffffff1660006106bd60018361482c565b63ffffffff1667ffffffffffffffff8111156106db576106db613d3d565b60405190808252806020026020018201604052801561076257816020015b6040805160e081018252600080825260208083018290529282018190526060808301829052608083019190915260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816106f95790505b509050600060015b8363ffffffff168163ffffffff1610156107d65763ffffffff8082166000908152600d602052604090205416156107ce576107a481612b95565b8383815181106107b6576107b66147ce565b6020026020010181905250816107cb90614849565b91505b60010161076a565b506107e260018461482c565b63ffffffff1681146107f2578082525b5092915050565b60408051808201909152600081526060602082015263ffffffff82166000908152600b60209081526040918290208251808401909352805473ffffffffffffffffffffffffffffffffffffffff168352600181018054919284019161085d90614881565b80601f016020809104026020016040519081016040528092919081815260200182805461088990614881565b80156108d65780601f106108ab576101008083540402835291602001916108d6565b820191906000526020600020905b8154815290600101906020018083116108b957829003601f168201915b5050505050815250509050919050565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082019290925260a0810182905260c081019190915261047482612b95565b610932612af0565b60005b63ffffffff811682111561069757600083838363ffffffff1681811061095d5761095d6147ce565b90506020020160208101906109729190614203565b63ffffffff81166000908152600b6020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001681559192506109bd6001830182613cd0565b505060405163ffffffff8216907fa59268ca81d40429e65ccea5385b59cf2d3fc6519371dee92f8eb1dae5107a7a90600090a2506109fa816148d4565b9050610935565b610a09612af0565b63ffffffff8088166000908152600d60205260408120805490926401000000009091041690819003610a6f576040517f2b62be9b00000000000000000000000000000000000000000000000000000000815263ffffffff8a166004820152602401610609565b610ad6888888886040518060a001604052808f63ffffffff16815260200187610a97906148d4565b63ffffffff811682528b15156020830152895460ff6a01000000000000000000009091048116151560408401528b166060909201919091529650612e60565b505050505050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff163314905b82811015610d77576000848483818110610b1b57610b1b6147ce565b602090810292909201356000818152600c90935260409092206001810154929350919050610b78576040517fd82f6adb00000000000000000000000000000000000000000000000000000000815260048101839052602401610609565b6000610b8682600401612b73565b1115610bdb57610b996004820184612b7d565b6040517f60a6d89800000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015260248101839052604401610609565b805468010000000000000000900463ffffffff1615610c435780546040517f60b9df730000000000000000000000000000000000000000000000000000000081526801000000000000000090910463ffffffff16600482015260248101839052604401610609565b83158015610c7d5750805463ffffffff166000908152600b602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b15610cb6576040517f9473075d000000000000000000000000000000000000000000000000000000008152336004820152602401610609565b6001810154610cc790600790612b89565b506002810154610cd990600990612b89565b506000828152600c6020526040812080547fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016815560018101829055600281018290559060048201818181610d2e8282613d0a565b5050505050507f5254e609a97bab37b7cc79fe128f85c097bd6015c6e1624ae0ba392eb975320582604051610d6591815260200190565b60405180910390a15050600101610aff565b50505050565b610d85612af0565b60005b81811015610697576000838383818110610da457610da46147ce565b9050602002810190610db691906148f7565b610dbf90614935565b805190915073ffffffffffffffffffffffffffffffffffffffff16610e10576040517feeacd93900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e54604080518082018252835173ffffffffffffffffffffffffffffffffffffffff908116825260208086015181840190815263ffffffff9095166000818152600b909252939020825181547fffffffffffffffffffffffff00000000000000000000000000000000000000001692169190911781559251919290916001820190610e9c90826149ef565b5050600e8054909150600090610eb79063ffffffff166148d4565b91906101000a81548163ffffffff021916908363ffffffff160217905550816000015173ffffffffffffffffffffffffffffffffffffffff168163ffffffff167f78e94ca80be2c30abc061b99e7eb8583b1254781734b1e3ce339abb57da2fe8e8460200151604051610f2a9190613f8e565b60405180910390a35050600101610d88565b63ffffffff8083166000908152600d60209081526040808320805464010000000090049094168084526001909401825280832085845260030190915281208054606093849390929091610f8e90614881565b80601f0160208091040260200160405190810160405280929190818152602001828054610fba90614881565b80156110075780601f10610fdc57610100808354040283529160200191611007565b820191906000526020600020905b815481529060010190602001808311610fea57829003601f168201915b5050506000888152600260208190526040909120015492935060609262010000900473ffffffffffffffffffffffffffffffffffffffff1615915061111a905057600086815260026020819052604091829020015490517f8318ed5d00000000000000000000000000000000000000000000000000000000815263ffffffff891660048201526201000090910473ffffffffffffffffffffffffffffffffffffffff1690638318ed5d90602401600060405180830381865afa1580156110d1573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526111179190810190614b09565b90505b9093509150505b9250929050565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082019290925260a0810182905260c08101919091526040805160e0810182526000848152600c6020908152838220805463ffffffff8082168652640100000000820481168487018190526801000000000000000090920416858701526001820154606086015260028201546080860152835260030190529190912060a08201906111d790613685565b81526020016111fa600c6000868152602001908152602001600020600401613685565b905292915050565b61120a612af0565b60005b81811015610697576000838383818110611229576112296147ce565b905060200201359050611246816003612ad590919063ffffffff16565b61127f576040517fe181733f00000000000000000000000000000000000000000000000000000000815260048101829052602401610609565b61128a600582613692565b6112c3576040517ff7d7a29400000000000000000000000000000000000000000000000000000000815260048101829052602401610609565b60405181907fdcea1b78b6ddc31592a94607d537543fcaafda6cc52d6d5cc7bbfca1422baf2190600090a25060010161120d565b6000805473ffffffffffffffffffffffffffffffffffffffff163314905b82811015610d77576000848483818110611331576113316147ce565b90506020028101906113439190614b77565b61134c90614bab565b6040808201516000908152600c6020908152828220805463ffffffff168352600b82528383208451808601909552805473ffffffffffffffffffffffffffffffffffffffff16855260018101805496975091959394939092840191906113b190614881565b80601f01602080910402602001604051908101604052809291908181526020018280546113dd90614881565b801561142a5780601f106113ff5761010080835404028352916020019161142a565b820191906000526020600020905b81548152906001019060200180831161140d57829003601f168201915b50505091909252505050600183015490915061147a5782604001516040517fd82f6adb00000000000000000000000000000000000000000000000000000000815260040161060991815260200190565b8415801561149f5750805173ffffffffffffffffffffffffffffffffffffffff163314155b156114d8576040517f9473075d000000000000000000000000000000000000000000000000000000008152336004820152602401610609565b6020830151611513576040517f8377314600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018201546020840151811461159457602084015161153490600790612ad5565b1561156b576040517f8377314600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208401516001840155611580600782612b89565b50602084015161159290600790613692565b505b606084015180516000036115d657806040517f3748d4c60000000000000000000000000000000000000000000000000000000081526004016106099190614c7e565b835460009085906004906115f790640100000000900463ffffffff166148d4565b91906101000a81548163ffffffff021916908363ffffffff1602179055905060005b82518110156116dc5761164f838281518110611637576116376147ce565b60200260200101516003612ad590919063ffffffff16565b61168757826040517f3748d4c60000000000000000000000000000000000000000000000000000000081526004016106099190614c7e565b6116d383828151811061169c5761169c6147ce565b60200260200101518760030160008563ffffffff1663ffffffff16815260200190815260200160002061369290919063ffffffff16565b50600101611619565b50845468010000000000000000900463ffffffff16801561183d5763ffffffff8082166000908152600d60209081526040808320805464010000000090049094168352600190930181528282206002018054845181840281018401909552808552929392909183018282801561177157602002820191906000526020600020905b81548152602001906001019080831161175d575b5050505050905060005b815181101561183a576117d0828281518110611799576117996147ce565b60200260200101518960030160008763ffffffff1663ffffffff168152602001908152602001600020612ad590919063ffffffff16565b611832578181815181106117e6576117e66147ce565b6020026020010151836040517f03dcd86200000000000000000000000000000000000000000000000000000000815260040161060992919091825263ffffffff16602082015260400190565b60010161177b565b50505b600061184b87600401613685565b905060005b81518163ffffffff161015611991576000828263ffffffff1681518110611879576118796147ce565b60209081029190910181015163ffffffff8082166000908152600d8452604080822080546401000000009004909316825260019092018452818120600201805483518187028101870190945280845293955090939192909183018282801561190057602002820191906000526020600020905b8154815260200190600101908083116118ec575b5050505050905060005b815181101561197d5761195f828281518110611928576119286147ce565b60200260200101518c60030160008a63ffffffff1663ffffffff168152602001908152602001600020612ad590919063ffffffff16565b611975578181815181106117e6576117e66147ce565b60010161190a565b5050508061198a906148d4565b9050611850565b50875187547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff90911690811788556040808a015160028a018190556020808c01518351928352908201527f4b5b465e22eea0c3d40c30e936643245b80d19b2dcf75788c0699fe8d8db645b910160405180910390a25050505050505050806001019050611315565b600e5460609063ffffffff166000611a3860018361482c565b63ffffffff1667ffffffffffffffff811115611a5657611a56613d3d565b604051908082528060200260200182016040528015611a9c57816020015b604080518082019091526000815260606020820152815260200190600190039081611a745790505b509050600060015b8363ffffffff168163ffffffff161015611bec5763ffffffff81166000908152600b602052604090205473ffffffffffffffffffffffffffffffffffffffff1615611be45763ffffffff81166000908152600b60209081526040918290208251808401909352805473ffffffffffffffffffffffffffffffffffffffff1683526001810180549192840191611b3890614881565b80601f0160208091040260200160405190810160405280929190818152602001828054611b6490614881565b8015611bb15780601f10611b8657610100808354040283529160200191611bb1565b820191906000526020600020905b815481529060010190602001808311611b9457829003601f168201915b505050505081525050838381518110611bcc57611bcc6147ce565b602002602001018190525081611be190614849565b91505b600101611aa4565b50600e546107e29060019063ffffffff1661482c565b611c0a612af0565b60005b81811015610697576000838383818110611c2957611c296147ce565b9050602002810190611c3b9190614cc2565b611c4490614d05565b90506000611c5a82600001518360200151610446565b9050611c67600382613692565b611ca0576040517febf5255100000000000000000000000000000000000000000000000000000000815260048101829052602401610609565b611caa818361369e565b5050600101611c0d565b6000805473ffffffffffffffffffffffffffffffffffffffff163314905b82811015610d77576000848483818110611cee57611cee6147ce565b9050602002810190611d009190614b77565b611d0990614bab565b805163ffffffff166000908152600b602090815260408083208151808301909252805473ffffffffffffffffffffffffffffffffffffffff168252600181018054959650939491939092840191611d5f90614881565b80601f0160208091040260200160405190810160405280929190818152602001828054611d8b90614881565b8015611dd85780601f10611dad57610100808354040283529160200191611dd8565b820191906000526020600020905b815481529060010190602001808311611dbb57829003601f168201915b50505091909252505081519192505073ffffffffffffffffffffffffffffffffffffffff16611e3e5781516040517fadd9ae1e00000000000000000000000000000000000000000000000000000000815263ffffffff9091166004820152602401610609565b83158015611e635750805173ffffffffffffffffffffffffffffffffffffffff163314155b15611e9c576040517f9473075d000000000000000000000000000000000000000000000000000000008152336004820152602401610609565b6040808301516000908152600c60205220600181015415611ef15782604001516040517f5461848300000000000000000000000000000000000000000000000000000000815260040161060991815260200190565b6040830151611f345782604001516040517f64e2ee9200000000000000000000000000000000000000000000000000000000815260040161060991815260200190565b60208301511580611f5157506020830151611f5190600790612ad5565b15611f88576040517f8377314600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301518051600003611fca57806040517f3748d4c60000000000000000000000000000000000000000000000000000000081526004016106099190614c7e565b81548290600490611fe890640100000000900463ffffffff166148d4565b82546101009290920a63ffffffff818102199093169183160217909155825464010000000090041660005b82518110156120be57612031838281518110611637576116376147ce565b61206957826040517f3748d4c60000000000000000000000000000000000000000000000000000000081526004016106099190614c7e565b6120b583828151811061207e5761207e6147ce565b60200260200101518560030160008563ffffffff1663ffffffff16815260200190815260200160002061369290919063ffffffff16565b50600101612013565b50845183547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff91821617845560408601516002850155602086015160018501819055612114916007919061369216565b50604085015161212690600990613692565b50845160408087015160208089015183519283529082015263ffffffff909216917f74becb12a5e8fd0e98077d02dfba8f647c9670c9df177e42c2418cf17a636f05910160405180910390a25050505050806001019050611cd2565b60015473ffffffffffffffffffffffffffffffffffffffff163314612203576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610609565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b8281146122c2576040517fab8b67c60000000000000000000000000000000000000000000000000000000081526004810184905260248101829052604401610609565b6000805473ffffffffffffffffffffffffffffffffffffffff16905b848110156125b75760008686838181106122fa576122fa6147ce565b905060200201602081019061230f9190614203565b63ffffffff81166000908152600b6020526040902080549192509073ffffffffffffffffffffffffffffffffffffffff1661237e576040517fadd9ae1e00000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152602401610609565b6000868685818110612392576123926147ce565b90506020028101906123a491906148f7565b6123ad90614935565b805190915073ffffffffffffffffffffffffffffffffffffffff166123fe576040517feeacd93900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815473ffffffffffffffffffffffffffffffffffffffff16331480159061243b57503373ffffffffffffffffffffffffffffffffffffffff861614155b15612474576040517f9473075d000000000000000000000000000000000000000000000000000000008152336004820152602401610609565b8051825473ffffffffffffffffffffffffffffffffffffffff90811691161415806124f057506020808201516040516124ad9201613f8e565b60405160208183030381529060405280519060200120826001016040516020016124d79190614dab565b6040516020818303038152906040528051906020012014155b156125a957805182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020810151600183019061254a90826149ef565b50806000015173ffffffffffffffffffffffffffffffffffffffff168363ffffffff167f86f41145bde5dd7f523305452e4aad3685508c181432ec733d5f345009358a2883602001516040516125a09190613f8e565b60405180910390a35b5050508060010190506122de565b505050505050565b6126006040805160e0810182526000808252606060208301819052928201839052909182019081526020016000815260006020820181905260409091015290565b6040805160e0810182528381526000848152600260209081529290208054919283019161262c90614881565b80601f016020809104026020016040519081016040528092919081815260200182805461265890614881565b80156126a55780601f1061267a576101008083540402835291602001916126a5565b820191906000526020600020905b81548152906001019060200180831161268857829003601f168201915b505050505081526020016002600085815260200190815260200160002060010180546126d090614881565b80601f01602080910402602001604051908101604052809291908181526020018280546126fc90614881565b80156127495780601f1061271e57610100808354040283529160200191612749565b820191906000526020600020905b81548152906001019060200180831161272c57829003601f168201915b50505091835250506000848152600260208181526040909220015491019060ff16600381111561277b5761277b614526565b815260008481526002602081815260409092200154910190610100900460ff1660018111156127ac576127ac614526565b81526000848152600260208181526040928390209091015462010000900473ffffffffffffffffffffffffffffffffffffffff1690830152016127f0600585612ad5565b1515905292915050565b612802612af0565b600e805460009164010000000090910463ffffffff16906004612824836148d4565b82546101009290920a63ffffffff81810219909316918316021790915581166000818152600d602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001684179055815160a08101835292835260019083015286151590820152841515606082015260ff841660808201529091506128ba908990899089908990612e60565b5050505050505050565b606060006128d26003613685565b90506000815167ffffffffffffffff8111156128f0576128f0613d3d565b60405190808252806020026020018201604052801561296257816020015b61294f6040805160e0810182526000808252606060208301819052928201839052909182019081526020016000815260006020820181905260409091015290565b81526020019060019003908161290e5790505b50905060005b82518110156107f257612993838281518110612986576129866147ce565b60200260200101516125bf565b8282815181106129a5576129a56147ce565b6020908102919091010152600101612968565b606060006129c66009613685565b90506000815167ffffffffffffffff8111156129e4576129e4613d3d565b604051908082528060200260200182016040528015612a6b57816020015b6040805160e081018252600080825260208083018290529282018190526060808301829052608083019190915260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612a025790505b50905060005b82518110156107f257612a9c838281518110612a8f57612a8f6147ce565b6020026020010151611128565b828281518110612aae57612aae6147ce565b6020908102919091010152600101612a71565b612ac9612af0565b612ad281613932565b50565b600081815260018301602052604081205415155b9392505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612b71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610609565b565b6000610474825490565b6000612ae98383613a27565b6000612ae98383613a51565b6040805160e0810182526000808252602080830182905282840182905260608084018390526080840183905260a0840181905260c084015263ffffffff8581168352600d8252848320805464010000000090049091168084526001909101825284832060028101805487518186028101860190985280885295969295919493909190830182828015612c4657602002820191906000526020600020905b815481526020019060010190808311612c32575b505050505090506000815167ffffffffffffffff811115612c6957612c69613d3d565b604051908082528060200260200182016040528015612caf57816020015b604080518082019091526000815260606020820152815260200190600190039081612c875790505b50905060005b8151811015612dc7576040518060400160405280848381518110612cdb57612cdb6147ce565b60200260200101518152602001856003016000868581518110612d0057612d006147ce565b602002602001015181526020019081526020016000208054612d2190614881565b80601f0160208091040260200160405190810160405280929190818152602001828054612d4d90614881565b8015612d9a5780601f10612d6f57610100808354040283529160200191612d9a565b820191906000526020600020905b815481529060010190602001808311612d7d57829003601f168201915b5050505050815250828281518110612db457612db46147ce565b6020908102919091010152600101612cb5565b506040805160e08101825263ffffffff8089166000818152600d6020818152868320548086168752948b168187015260ff680100000000000000008604811697870197909752690100000000000000000085048716151560608701529290915290526a010000000000000000000090049091161515608082015260a08101612e4e85613685565b81526020019190915295945050505050565b805163ffffffff9081166000908152600d602090815260408083208286015190941683526001909301905220608082015160ff161580612eb2575060808201518590612ead906001614e59565b60ff16115b15612efb5760808201516040517f25b4d61800000000000000000000000000000000000000000000000000000000815260ff909116600482015260248101869052604401610609565b6001826020015163ffffffff161115612fe357815163ffffffff166000908152600d602090815260408220908401516001918201918391612f3c919061482c565b63ffffffff1663ffffffff168152602001908152602001600020905060005b612f6482612b73565b811015612fe057612f93846000015163ffffffff16600c60006105928587600001612b7d90919063ffffffff16565b50600c6000612fa28484612b7d565b8152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff169055600101612f5b565b50505b60005b8581101561321d57613013878783818110613003576130036147ce565b8592602090910201359050613692565b61307457825187878381811061302b5761302b6147ce565b6040517f636e405700000000000000000000000000000000000000000000000000000000815263ffffffff90941660048501526020029190910135602483015250604401610609565b8260600151156131cb57825163ffffffff16600c600089898581811061309c5761309c6147ce565b602090810292909201358352508101919091526040016000205468010000000000000000900463ffffffff16148015906131165750600c60008888848181106130e7576130e76147ce565b602090810292909201358352508101919091526040016000205468010000000000000000900463ffffffff1615155b1561317857825187878381811061312f5761312f6147ce565b6040517f60b9df7300000000000000000000000000000000000000000000000000000000815263ffffffff90941660048501526020029190910135602483015250604401610609565b8251600c6000898985818110613190576131906147ce565b90506020020135815260200190815260200160002060000160086101000a81548163ffffffff021916908363ffffffff160217905550613215565b82516132139063ffffffff16600c60008a8a868181106131ed576131ed6147ce565b90506020020135815260200190815260200160002060040161369290919063ffffffff16565b505b600101612fe6565b5060005b8381101561362b573685858381811061323c5761323c6147ce565b905060200281019061324e91906148f7565b905061325c60038235612ad5565b613295576040517fe181733f00000000000000000000000000000000000000000000000000000000815281356004820152602401610609565b6132a160058235612ad5565b156132db576040517ff7d7a29400000000000000000000000000000000000000000000000000000000815281356004820152602401610609565b80356000908152600384016020526040812080546132f890614881565b905011156133445783516040517f3927d08000000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015281356024820152604401610609565b60005b8781101561344e576133eb8235600c60008c8c8681811061336a5761336a6147ce565b9050602002013581526020019081526020016000206003016000600c60008e8e8881811061339a5761339a6147ce565b90506020020135815260200190815260200160002060000160049054906101000a900463ffffffff1663ffffffff1663ffffffff168152602001908152602001600020612ad590919063ffffffff16565b61344657888882818110613401576134016147ce565b6040517fa7e792500000000000000000000000000000000000000000000000000000000081526020909102929092013560048301525082356024820152604401610609565b600101613347565b506002830180546001810182556000918252602091829020833591015561347790820182614e72565b82356000908152600386016020526040902091613495919083614ed7565b50604080850151855163ffffffff9081166000908152600d602090815284822080549415156901000000000000000000027fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff90951694909417909355606088015188518316825284822080549115156a0100000000000000000000027fffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff9092169190911790556080880151885183168252848220805460ff9290921668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff909216919091179055828801805189518416835294909120805494909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff9094169390931790558551915161362292918435908c908c906135e890880188614e72565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613b4492505050565b50600101613221565b50815160208301516040517ff264aae70bf6a9d90e68e0f9b393f4e7fbea67b063b0f336e0b36c15817036519261367592909163ffffffff92831681529116602082015260400190565b60405180910390a1505050505050565b60606000612ae983613c25565b6000612ae98383613c81565b608081015173ffffffffffffffffffffffffffffffffffffffff16156137ec57608081015173ffffffffffffffffffffffffffffffffffffffff163b1580613797575060808101516040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f78bea72100000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff909116906301ffc9a790602401602060405180830381865afa158015613771573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137959190614ff2565b155b156137ec5760808101516040517fabb5e3fd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610609565b60008281526002602052604090208151829190819061380b90826149ef565b506020820151600182019061382090826149ef565b5060408201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600381111561386257613862614526565b021790555060608201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101008360018111156138a9576138a9614526565b0217905550608091909101516002909101805473ffffffffffffffffffffffffffffffffffffffff90921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff90921691909117905560405182907f04f0a9bcf3f3a3b42a4d7ca081119755f82ebe43e0d30c8f7292c4fe0dc4a2ae90600090a25050565b3373ffffffffffffffffffffffffffffffffffffffff8216036139b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610609565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110613a3e57613a3e6147ce565b9060005260206000200154905092915050565b60008181526001830160205260408120548015613b3a576000613a7560018361500f565b8554909150600090613a899060019061500f565b9050818114613aee576000866000018281548110613aa957613aa96147ce565b9060005260206000200154905080876000018481548110613acc57613acc6147ce565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613aff57613aff615022565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610474565b6000915050610474565b6000848152600260208190526040909120015462010000900473ffffffffffffffffffffffffffffffffffffffff16156125b757600084815260026020819052604091829020015490517ffba64a7c0000000000000000000000000000000000000000000000000000000081526201000090910473ffffffffffffffffffffffffffffffffffffffff169063fba64a7c90613beb908690869086908b908d90600401615051565b600060405180830381600087803b158015613c0557600080fd5b505af1158015613c19573d6000803e3d6000fd5b50505050505050505050565b606081600001805480602002602001604051908101604052809291908181526020018280548015613c7557602002820191906000526020600020905b815481526020019060010190808311613c61575b50505050509050919050565b6000818152600183016020526040812054613cc857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610474565b506000610474565b508054613cdc90614881565b6000825580601f10613cec575050565b601f016020900490600052602060002090810190612ad29190613d24565b5080546000825590600052602060002090810190612ad291905b5b80821115613d395760008155600101613d25565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613d8f57613d8f613d3d565b60405290565b60405160a0810167ffffffffffffffff81118282101715613d8f57613d8f613d3d565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613dff57613dff613d3d565b604052919050565b600067ffffffffffffffff821115613e2157613e21613d3d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613e5e57600080fd5b8135613e71613e6c82613e07565b613db8565b818152846020838601011115613e8657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060408385031215613eb657600080fd5b823567ffffffffffffffff80821115613ece57600080fd5b613eda86838701613e4d565b93506020850135915080821115613ef057600080fd5b50613efd85828601613e4d565b9150509250929050565b600060208284031215613f1957600080fd5b5035919050565b60005b83811015613f3b578181015183820152602001613f23565b50506000910152565b60008151808452613f5c816020860160208601613f20565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612ae96020830184613f44565b60008083601f840112613fb357600080fd5b50813567ffffffffffffffff811115613fcb57600080fd5b6020830191508360208260051b850101111561112157600080fd5b60008060208385031215613ff957600080fd5b823567ffffffffffffffff81111561401057600080fd5b61401c85828601613fa1565b90969095509350505050565b60008151808452602080850194506020840160005b838110156140595781518752958201959082019060010161403d565b509495945050505050565b600082825180855260208086019550808260051b84010181860160005b848110156140e1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051845284015160408585018190526140cd81860183613f44565b9a86019a9450505090830190600101614081565b5090979650505050505050565b600063ffffffff8083511684528060208401511660208501525060ff604083015116604084015260608201511515606084015260808201511515608084015260a082015160e060a085015261414660e0850182614028565b905060c083015184820360c086015261415f8282614064565b95945050505050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156141dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526141cb8583516140ee565b94509285019290850190600101614191565b5092979650505050505050565b803563ffffffff811681146141fe57600080fd5b919050565b60006020828403121561421557600080fd5b612ae9826141ea565b73ffffffffffffffffffffffffffffffffffffffff815116825260006020820151604060208501526142536040850182613f44565b949350505050565b602081526000612ae9602083018461421e565b602081526000612ae960208301846140ee565b8015158114612ad257600080fd5b803560ff811681146141fe57600080fd5b600080600080600080600060a0888a0312156142bb57600080fd5b6142c4886141ea565b9650602088013567ffffffffffffffff808211156142e157600080fd5b6142ed8b838c01613fa1565b909850965060408a013591508082111561430657600080fd5b506143138a828b01613fa1565b909550935050606088013561432781614281565b91506143356080890161428f565b905092959891949750929550565b6000806040838503121561435657600080fd5b61435f836141ea565b946020939093013593505050565b6040815260006143806040830185613f44565b828103602084015261415f8185613f44565b600063ffffffff808351168452602081818501511681860152816040850151166040860152606084015160608601526080840151608086015260a0840151915060e060a08601526143e660e0860183614028565b60c08581015187830391880191909152805180835290830193506000918301905b808310156144275784518252938301936001929092019190830190614407565b509695505050505050565b602081526000612ae96020830184614392565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156141dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08886030184526144a885835161421e565b9450928501929085019060010161446e565b600080600080604085870312156144d057600080fd5b843567ffffffffffffffff808211156144e857600080fd5b6144f488838901613fa1565b9096509450602087013591508082111561450d57600080fd5b5061451a87828801613fa1565b95989497509550505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b805182526000602082015160e0602085015261457460e0850182613f44565b90506040830151848203604086015261458d8282613f44565b9150506060830151600481106145a5576145a5614526565b60608501526080830151600281106145bf576145bf614526565b8060808601525060a08301516145ed60a086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015161460160c086018215159052565b509392505050565b602081526000612ae96020830184614555565b600080600080600080600060a0888a03121561463757600080fd5b873567ffffffffffffffff8082111561464f57600080fd5b61465b8b838c01613fa1565b909950975060208a013591508082111561467457600080fd5b506146818a828b01613fa1565b909650945050604088013561469581614281565b9250606088013561432781614281565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156141dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614708858351614555565b945092850192908501906001016146ce565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b828110156141dd577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261477d858351614392565b94509285019290850190600101614743565b803573ffffffffffffffffffffffffffffffffffffffff811681146141fe57600080fd5b6000602082840312156147c557600080fd5b612ae98261478f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff8281168282160390808211156107f2576107f26147fd565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361487a5761487a6147fd565b5060010190565b600181811c9082168061489557607f821691505b6020821081036148ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600063ffffffff8083168181036148ed576148ed6147fd565b6001019392505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261492b57600080fd5b9190910192915050565b60006040823603121561494757600080fd5b6040516040810167ffffffffffffffff828210818311171561496b5761496b613d3d565b816040526149788561478f565b8352602085013591508082111561498e57600080fd5b5061499b36828601613e4d565b60208301525092915050565b601f821115610697576000816000526020600020601f850160051c810160208610156149d05750805b601f850160051c820191505b818110156125b7578281556001016149dc565b815167ffffffffffffffff811115614a0957614a09613d3d565b614a1d81614a178454614881565b846149a7565b602080601f831160018114614a705760008415614a3a5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556125b7565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614abd57888601518255948401946001909101908401614a9e565b5085821015614af957878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215614b1b57600080fd5b815167ffffffffffffffff811115614b3257600080fd5b8201601f81018413614b4357600080fd5b8051614b51613e6c82613e07565b818152856020838501011115614b6657600080fd5b61415f826020830160208601613f20565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8183360301811261492b57600080fd5b600060808236031215614bbd57600080fd5b614bc5613d6c565b614bce836141ea565b81526020808401358183015260408401356040830152606084013567ffffffffffffffff80821115614bff57600080fd5b9085019036601f830112614c1257600080fd5b813581811115614c2457614c24613d3d565b8060051b9150614c35848301613db8565b8181529183018401918481019036841115614c4f57600080fd5b938501935b83851015614c6d57843582529385019390850190614c54565b606087015250939695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015614cb657835183529284019291840191600101614c9a565b50909695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6183360301811261492b57600080fd5b8035600281106141fe57600080fd5b600060a08236031215614d1757600080fd5b614d1f613d95565b823567ffffffffffffffff80821115614d3757600080fd5b614d4336838701613e4d565b83526020850135915080821115614d5957600080fd5b50614d6636828601613e4d565b602083015250604083013560048110614d7e57600080fd5b6040820152614d8f60608401614cf6565b6060820152614da06080840161478f565b608082015292915050565b6000602080835260008454614dbf81614881565b8060208701526040600180841660008114614de15760018114614e1b57614e4b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00851660408a0152604084151560051b8a01019550614e4b565b89600052602060002060005b85811015614e425781548b8201860152908301908801614e27565b8a016040019650505b509398975050505050505050565b60ff8181168382160190811115610474576104746147fd565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614ea757600080fd5b83018035915067ffffffffffffffff821115614ec257600080fd5b60200191503681900382131561112157600080fd5b67ffffffffffffffff831115614eef57614eef613d3d565b614f0383614efd8354614881565b836149a7565b6000601f841160018114614f555760008515614f1f5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614feb565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015614fa45786850135825560209485019460019092019101614f84565b5086821015614fdf577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60006020828403121561500457600080fd5b8151612ae981614281565b81810381811115610474576104746147fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6080815284608082015260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86111561508a57600080fd5b8560051b808860a0850137820182810360a090810160208501526150b090820187613f44565b91505063ffffffff8085166040840152808416606084015250969550505050505056fea164736f6c6343000818000a",
}
var CapabilitiesRegistryABI = CapabilitiesRegistryMetaData.ABI
@@ -633,16 +633,16 @@ func (_CapabilitiesRegistry *CapabilitiesRegistryTransactorSession) TransferOwne
return _CapabilitiesRegistry.Contract.TransferOwnership(&_CapabilitiesRegistry.TransactOpts, to)
}
-func (_CapabilitiesRegistry *CapabilitiesRegistryTransactor) UpdateDON(opts *bind.TransactOpts, donId uint32, nodes [][32]byte, capabilityConfigurations []CapabilitiesRegistryCapabilityConfiguration, isPublic bool, acceptsWorkflows bool, f uint8) (*types.Transaction, error) {
- return _CapabilitiesRegistry.contract.Transact(opts, "updateDON", donId, nodes, capabilityConfigurations, isPublic, acceptsWorkflows, f)
+func (_CapabilitiesRegistry *CapabilitiesRegistryTransactor) UpdateDON(opts *bind.TransactOpts, donId uint32, nodes [][32]byte, capabilityConfigurations []CapabilitiesRegistryCapabilityConfiguration, isPublic bool, f uint8) (*types.Transaction, error) {
+ return _CapabilitiesRegistry.contract.Transact(opts, "updateDON", donId, nodes, capabilityConfigurations, isPublic, f)
}
-func (_CapabilitiesRegistry *CapabilitiesRegistrySession) UpdateDON(donId uint32, nodes [][32]byte, capabilityConfigurations []CapabilitiesRegistryCapabilityConfiguration, isPublic bool, acceptsWorkflows bool, f uint8) (*types.Transaction, error) {
- return _CapabilitiesRegistry.Contract.UpdateDON(&_CapabilitiesRegistry.TransactOpts, donId, nodes, capabilityConfigurations, isPublic, acceptsWorkflows, f)
+func (_CapabilitiesRegistry *CapabilitiesRegistrySession) UpdateDON(donId uint32, nodes [][32]byte, capabilityConfigurations []CapabilitiesRegistryCapabilityConfiguration, isPublic bool, f uint8) (*types.Transaction, error) {
+ return _CapabilitiesRegistry.Contract.UpdateDON(&_CapabilitiesRegistry.TransactOpts, donId, nodes, capabilityConfigurations, isPublic, f)
}
-func (_CapabilitiesRegistry *CapabilitiesRegistryTransactorSession) UpdateDON(donId uint32, nodes [][32]byte, capabilityConfigurations []CapabilitiesRegistryCapabilityConfiguration, isPublic bool, acceptsWorkflows bool, f uint8) (*types.Transaction, error) {
- return _CapabilitiesRegistry.Contract.UpdateDON(&_CapabilitiesRegistry.TransactOpts, donId, nodes, capabilityConfigurations, isPublic, acceptsWorkflows, f)
+func (_CapabilitiesRegistry *CapabilitiesRegistryTransactorSession) UpdateDON(donId uint32, nodes [][32]byte, capabilityConfigurations []CapabilitiesRegistryCapabilityConfiguration, isPublic bool, f uint8) (*types.Transaction, error) {
+ return _CapabilitiesRegistry.Contract.UpdateDON(&_CapabilitiesRegistry.TransactOpts, donId, nodes, capabilityConfigurations, isPublic, f)
}
func (_CapabilitiesRegistry *CapabilitiesRegistryTransactor) UpdateNodeOperators(opts *bind.TransactOpts, nodeOperatorIds []uint32, nodeOperators []CapabilitiesRegistryNodeOperator) (*types.Transaction, error) {
@@ -2214,7 +2214,7 @@ type CapabilitiesRegistryInterface interface {
TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
- UpdateDON(opts *bind.TransactOpts, donId uint32, nodes [][32]byte, capabilityConfigurations []CapabilitiesRegistryCapabilityConfiguration, isPublic bool, acceptsWorkflows bool, f uint8) (*types.Transaction, error)
+ UpdateDON(opts *bind.TransactOpts, donId uint32, nodes [][32]byte, capabilityConfigurations []CapabilitiesRegistryCapabilityConfiguration, isPublic bool, f uint8) (*types.Transaction, error)
UpdateNodeOperators(opts *bind.TransactOpts, nodeOperatorIds []uint32, nodeOperators []CapabilitiesRegistryNodeOperator) (*types.Transaction, error)
diff --git a/core/gethwrappers/keystone/generated/feeds_consumer/feeds_consumer.go b/core/gethwrappers/keystone/generated/feeds_consumer/feeds_consumer.go
index f4d52eedb9d..2951835c8d6 100644
--- a/core/gethwrappers/keystone/generated/feeds_consumer/feeds_consumer.go
+++ b/core/gethwrappers/keystone/generated/feeds_consumer/feeds_consumer.go
@@ -31,8 +31,8 @@ var (
)
var KeystoneFeedsConsumerMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes10\",\"name\":\"workflowName\",\"type\":\"bytes10\"}],\"name\":\"UnauthorizedWorkflowName\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"workflowOwner\",\"type\":\"address\"}],\"name\":\"UnauthorizedWorkflowOwner\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint224\",\"name\":\"price\",\"type\":\"uint224\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"name\":\"FeedReceived\",\"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\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"}],\"name\":\"getPrice\",\"outputs\":[{\"internalType\":\"uint224\",\"name\":\"\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"}],\"name\":\"onReport\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_allowedSendersList\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_allowedWorkflowOwnersList\",\"type\":\"address[]\"},{\"internalType\":\"bytes10[]\",\"name\":\"_allowedWorkflowNamesList\",\"type\":\"bytes10[]\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
- Bin: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615610097576100978161009f565b505050610148565b336001600160a01b038216036100f75760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6111cf806101576000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c80638da5cb5b116100505780638da5cb5b1461014e578063e340171114610176578063f2fde38b1461018957600080fd5b806331d98b3f1461007757806379ba509714610131578063805f21321461013b575b600080fd5b6100f3610085366004610d64565b6000908152600260209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168084527c010000000000000000000000000000000000000000000000000000000090910463ffffffff169290910182905291565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff909316835263ffffffff9091166020830152015b60405180910390f35b61013961019c565b005b610139610149366004610dc6565b61029e565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610128565b610139610184366004610e77565b61061d565b610139610197366004610f11565b610a5d565b60015473ffffffffffffffffffffffffffffffffffffffff163314610222576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3360009081526004602052604090205460ff166102e9576040517f3fcc3f17000000000000000000000000000000000000000000000000000000008152336004820152602401610219565b60008061032b86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610a7192505050565b7fffffffffffffffffffff000000000000000000000000000000000000000000008216600090815260086020526040902054919350915060ff166103bf576040517f4b942f800000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff0000000000000000000000000000000000000000000083166004820152602401610219565b73ffffffffffffffffffffffffffffffffffffffff811660009081526006602052604090205460ff16610436576040517fbf24162300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610219565b600061044484860186610ff5565b905060005b815181101561061357604051806040016040528083838151811061046f5761046f611107565b6020026020010151602001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1681526020018383815181106104b0576104b0611107565b60200260200101516040015163ffffffff16815250600260008484815181106104db576104db611107565b602090810291909101810151518252818101929092526040016000208251929091015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff909216919091179055815182908290811061055d5761055d611107565b6020026020010151600001517f2c30f5cb3caf4239d0f994ce539d7ef24817fa550169c388e3a110f02e40197d83838151811061059c5761059c611107565b6020026020010151602001518484815181106105ba576105ba611107565b6020026020010151604001516040516106039291907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216825263ffffffff16602082015260400190565b60405180910390a2600101610449565b5050505050505050565b610625610a87565b60005b60035463ffffffff821610156106c65760006004600060038463ffffffff168154811061065757610657611107565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556106bf81611136565b9050610628565b5060005b63ffffffff811686111561076e5760016004600089898563ffffffff168181106106f6576106f6611107565b905060200201602081019061070b9190610f11565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561076781611136565b90506106ca565b5061077b60038787610bff565b5060005b60055463ffffffff8216101561081d5760006006600060058463ffffffff16815481106107ae576107ae611107565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561081681611136565b905061077f565b5060005b63ffffffff81168411156108c55760016006600087878563ffffffff1681811061084d5761084d611107565b90506020020160208101906108629190610f11565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556108be81611136565b9050610821565b506108d260058585610bff565b5060005b60075463ffffffff821610156109935760006008600060078463ffffffff168154811061090557610905611107565b600091825260208083206003808404909101549206600a026101000a90910460b01b7fffffffffffffffffffff00000000000000000000000000000000000000000000168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561098c81611136565b90506108d6565b5060005b63ffffffff8116821115610a475760016008600085858563ffffffff168181106109c3576109c3611107565b90506020020160208101906109d89190611180565b7fffffffffffffffffffff00000000000000000000000000000000000000000000168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610a4081611136565b9050610997565b50610a5460078383610c87565b50505050505050565b610a65610a87565b610a6e81610b0a565b50565b6040810151604a90910151909160609190911c90565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b08576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610219565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610b89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610219565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610c77579160200282015b82811115610c775781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610c1f565b50610c83929150610d4f565b5090565b82805482825590600052602060002090600201600390048101928215610c775791602002820160005b83821115610d1057833575ffffffffffffffffffffffffffffffffffffffffffff191683826101000a81548169ffffffffffffffffffff021916908360b01c02179055509260200192600a01602081600901049283019260010302610cb0565b8015610d465782816101000a81549069ffffffffffffffffffff0219169055600a01602081600901049283019260010302610d10565b5050610c839291505b5b80821115610c835760008155600101610d50565b600060208284031215610d7657600080fd5b5035919050565b60008083601f840112610d8f57600080fd5b50813567ffffffffffffffff811115610da757600080fd5b602083019150836020828501011115610dbf57600080fd5b9250929050565b60008060008060408587031215610ddc57600080fd5b843567ffffffffffffffff80821115610df457600080fd5b610e0088838901610d7d565b90965094506020870135915080821115610e1957600080fd5b50610e2687828801610d7d565b95989497509550505050565b60008083601f840112610e4457600080fd5b50813567ffffffffffffffff811115610e5c57600080fd5b6020830191508360208260051b8501011115610dbf57600080fd5b60008060008060008060608789031215610e9057600080fd5b863567ffffffffffffffff80821115610ea857600080fd5b610eb48a838b01610e32565b90985096506020890135915080821115610ecd57600080fd5b610ed98a838b01610e32565b90965094506040890135915080821115610ef257600080fd5b50610eff89828a01610e32565b979a9699509497509295939492505050565b600060208284031215610f2357600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610f4757600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610fa057610fa0610f4e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610fed57610fed610f4e565b604052919050565b6000602080838503121561100857600080fd5b823567ffffffffffffffff8082111561102057600080fd5b818501915085601f83011261103457600080fd5b81358181111561104657611046610f4e565b611054848260051b01610fa6565b8181528481019250606091820284018501918883111561107357600080fd5b938501935b828510156110fb5780858a0312156110905760008081fd5b611098610f7d565b85358152868601357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681146110cb5760008081fd5b8188015260408681013563ffffffff811681146110e85760008081fd5b9082015284529384019392850192611078565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff808316818103611176577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6001019392505050565b60006020828403121561119257600080fd5b81357fffffffffffffffffffff0000000000000000000000000000000000000000000081168114610f4757600080fdfea164736f6c6343000818000a",
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes10\",\"name\":\"workflowName\",\"type\":\"bytes10\"}],\"name\":\"UnauthorizedWorkflowName\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"workflowOwner\",\"type\":\"address\"}],\"name\":\"UnauthorizedWorkflowOwner\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint224\",\"name\":\"price\",\"type\":\"uint224\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"name\":\"FeedReceived\",\"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\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"}],\"name\":\"getPrice\",\"outputs\":[{\"internalType\":\"uint224\",\"name\":\"\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"}],\"name\":\"onReport\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_allowedSendersList\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_allowedWorkflowOwnersList\",\"type\":\"address[]\"},{\"internalType\":\"bytes10[]\",\"name\":\"_allowedWorkflowNamesList\",\"type\":\"bytes10[]\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615610097576100978161009f565b505050610148565b336001600160a01b038216036100f75760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b611281806101576000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063805f21321161005b578063805f2132146101ab5780638da5cb5b146101be578063e3401711146101e6578063f2fde38b146101f957600080fd5b806301ffc9a71461008257806331d98b3f146100ec57806379ba5097146101a1575b600080fd5b6100d7610090366004610dd4565b7fffffffff00000000000000000000000000000000000000000000000000000000167f805f2132000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b6101686100fa366004610e1d565b6000908152600260209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168084527c010000000000000000000000000000000000000000000000000000000090910463ffffffff169290910182905291565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff909316835263ffffffff9091166020830152016100e3565b6101a961020c565b005b6101a96101b9366004610e7f565b61030e565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e3565b6101a96101f4366004610f30565b61068d565b6101a9610207366004610fca565b610acd565b60015473ffffffffffffffffffffffffffffffffffffffff163314610292576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3360009081526004602052604090205460ff16610359576040517f3fcc3f17000000000000000000000000000000000000000000000000000000008152336004820152602401610289565b60008061039b86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ae192505050565b7fffffffffffffffffffff000000000000000000000000000000000000000000008216600090815260086020526040902054919350915060ff1661042f576040517f4b942f800000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffff0000000000000000000000000000000000000000000083166004820152602401610289565b73ffffffffffffffffffffffffffffffffffffffff811660009081526006602052604090205460ff166104a6576040517fbf24162300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610289565b60006104b4848601866110a7565b905060005b81518110156106835760405180604001604052808383815181106104df576104df6111b9565b6020026020010151602001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152602001838381518110610520576105206111b9565b60200260200101516040015163ffffffff168152506002600084848151811061054b5761054b6111b9565b602090810291909101810151518252818101929092526040016000208251929091015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117905581518290829081106105cd576105cd6111b9565b6020026020010151600001517f2c30f5cb3caf4239d0f994ce539d7ef24817fa550169c388e3a110f02e40197d83838151811061060c5761060c6111b9565b60200260200101516020015184848151811061062a5761062a6111b9565b6020026020010151604001516040516106739291907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216825263ffffffff16602082015260400190565b60405180910390a26001016104b9565b5050505050505050565b610695610af7565b60005b60035463ffffffff821610156107365760006004600060038463ffffffff16815481106106c7576106c76111b9565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561072f816111e8565b9050610698565b5060005b63ffffffff81168611156107de5760016004600089898563ffffffff16818110610766576107666111b9565b905060200201602081019061077b9190610fca565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556107d7816111e8565b905061073a565b506107eb60038787610c6f565b5060005b60055463ffffffff8216101561088d5760006006600060058463ffffffff168154811061081e5761081e6111b9565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610886816111e8565b90506107ef565b5060005b63ffffffff81168411156109355760016006600087878563ffffffff168181106108bd576108bd6111b9565b90506020020160208101906108d29190610fca565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561092e816111e8565b9050610891565b5061094260058585610c6f565b5060005b60075463ffffffff82161015610a035760006008600060078463ffffffff1681548110610975576109756111b9565b600091825260208083206003808404909101549206600a026101000a90910460b01b7fffffffffffffffffffff00000000000000000000000000000000000000000000168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556109fc816111e8565b9050610946565b5060005b63ffffffff8116821115610ab75760016008600085858563ffffffff16818110610a3357610a336111b9565b9050602002016020810190610a489190611232565b7fffffffffffffffffffff00000000000000000000000000000000000000000000168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610ab0816111e8565b9050610a07565b50610ac460078383610cf7565b50505050505050565b610ad5610af7565b610ade81610b7a565b50565b6040810151604a90910151909160609190911c90565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b78576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610289565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610bf9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610289565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610ce7579160200282015b82811115610ce75781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610c8f565b50610cf3929150610dbf565b5090565b82805482825590600052602060002090600201600390048101928215610ce75791602002820160005b83821115610d8057833575ffffffffffffffffffffffffffffffffffffffffffff191683826101000a81548169ffffffffffffffffffff021916908360b01c02179055509260200192600a01602081600901049283019260010302610d20565b8015610db65782816101000a81549069ffffffffffffffffffff0219169055600a01602081600901049283019260010302610d80565b5050610cf39291505b5b80821115610cf35760008155600101610dc0565b600060208284031215610de657600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610e1657600080fd5b9392505050565b600060208284031215610e2f57600080fd5b5035919050565b60008083601f840112610e4857600080fd5b50813567ffffffffffffffff811115610e6057600080fd5b602083019150836020828501011115610e7857600080fd5b9250929050565b60008060008060408587031215610e9557600080fd5b843567ffffffffffffffff80821115610ead57600080fd5b610eb988838901610e36565b90965094506020870135915080821115610ed257600080fd5b50610edf87828801610e36565b95989497509550505050565b60008083601f840112610efd57600080fd5b50813567ffffffffffffffff811115610f1557600080fd5b6020830191508360208260051b8501011115610e7857600080fd5b60008060008060008060608789031215610f4957600080fd5b863567ffffffffffffffff80821115610f6157600080fd5b610f6d8a838b01610eeb565b90985096506020890135915080821115610f8657600080fd5b610f928a838b01610eeb565b90965094506040890135915080821115610fab57600080fd5b50610fb889828a01610eeb565b979a9699509497509295939492505050565b600060208284031215610fdc57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610e1657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561105257611052611000565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561109f5761109f611000565b604052919050565b600060208083850312156110ba57600080fd5b823567ffffffffffffffff808211156110d257600080fd5b818501915085601f8301126110e657600080fd5b8135818111156110f8576110f8611000565b611106848260051b01611058565b8181528481019250606091820284018501918883111561112557600080fd5b938501935b828510156111ad5780858a0312156111425760008081fd5b61114a61102f565b85358152868601357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117d5760008081fd5b8188015260408681013563ffffffff8116811461119a5760008081fd5b908201528452938401939285019261112a565b50979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff808316818103611228577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6001019392505050565b60006020828403121561124457600080fd5b81357fffffffffffffffffffff0000000000000000000000000000000000000000000081168114610e1657600080fdfea164736f6c6343000818000a",
}
var KeystoneFeedsConsumerABI = KeystoneFeedsConsumerMetaData.ABI
@@ -216,6 +216,28 @@ func (_KeystoneFeedsConsumer *KeystoneFeedsConsumerCallerSession) Owner() (commo
return _KeystoneFeedsConsumer.Contract.Owner(&_KeystoneFeedsConsumer.CallOpts)
}
+func (_KeystoneFeedsConsumer *KeystoneFeedsConsumerCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _KeystoneFeedsConsumer.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_KeystoneFeedsConsumer *KeystoneFeedsConsumerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _KeystoneFeedsConsumer.Contract.SupportsInterface(&_KeystoneFeedsConsumer.CallOpts, interfaceId)
+}
+
+func (_KeystoneFeedsConsumer *KeystoneFeedsConsumerCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _KeystoneFeedsConsumer.Contract.SupportsInterface(&_KeystoneFeedsConsumer.CallOpts, interfaceId)
+}
+
func (_KeystoneFeedsConsumer *KeystoneFeedsConsumerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
return _KeystoneFeedsConsumer.contract.Transact(opts, "acceptOwnership")
}
@@ -700,6 +722,8 @@ type KeystoneFeedsConsumerInterface interface {
Owner(opts *bind.CallOpts) (common.Address, error)
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
OnReport(opts *bind.TransactOpts, metadata []byte, rawReport []byte) (*types.Transaction, error)
diff --git a/core/gethwrappers/keystone/generated/forwarder/forwarder.go b/core/gethwrappers/keystone/generated/forwarder/forwarder.go
index 0412241cf77..a7a78ab67f9 100644
--- a/core/gethwrappers/keystone/generated/forwarder/forwarder.go
+++ b/core/gethwrappers/keystone/generated/forwarder/forwarder.go
@@ -30,9 +30,18 @@ var (
_ = abi.ConvertType
)
+type IRouterTransmissionInfo struct {
+ TransmissionId [32]byte
+ State uint8
+ Transmitter common.Address
+ InvalidReceiver bool
+ Success bool
+ GasLimit *big.Int
+}
+
var KeystoneForwarderMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transmissionId\",\"type\":\"bytes32\"}],\"name\":\"AlreadyAttempted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"DuplicateSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxSigners\",\"type\":\"uint256\"}],\"name\":\"ExcessSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FaultToleranceMustBePositive\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minSigners\",\"type\":\"uint256\"}],\"name\":\"InsufficientSigners\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"configId\",\"type\":\"uint64\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"received\",\"type\":\"uint256\"}],\"name\":\"InvalidSignatureCount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedForwarder\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"ForwarderAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"ForwarderRemoved\",\"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\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes2\",\"name\":\"reportId\",\"type\":\"bytes2\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"result\",\"type\":\"bool\"}],\"name\":\"ReportProcessed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"addForwarder\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"}],\"name\":\"clearConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes2\",\"name\":\"reportId\",\"type\":\"bytes2\"}],\"name\":\"getTransmissionId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes2\",\"name\":\"reportId\",\"type\":\"bytes2\"}],\"name\":\"getTransmissionState\",\"outputs\":[{\"internalType\":\"enumIRouter.TransmissionState\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes2\",\"name\":\"reportId\",\"type\":\"bytes2\"}],\"name\":\"getTransmitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"isForwarder\",\"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\":\"forwarder\",\"type\":\"address\"}],\"name\":\"removeForwarder\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"reportContext\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"signatures\",\"type\":\"bytes[]\"}],\"name\":\"report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transmissionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"validatedReport\",\"type\":\"bytes\"}],\"name\":\"route\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"}],\"name\":\"setConfig\",\"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: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b038481169190911790915581161561009757610097816100b9565b5050306000908152600360205260409020805460ff1916600117905550610162565b336001600160a01b038216036101115760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b611b2d80620001726000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806379ba50971161008c578063abcef55411610066578063abcef5541461023e578063ee59d26c14610277578063ef6e17a01461028a578063f2fde38b1461029d57600080fd5b806379ba5097146101e05780638864b864146101e85780638da5cb5b1461022057600080fd5b8063354bdd66116100c8578063354bdd661461017957806343c164671461019a5780634d93172d146101ba5780635c41d2fe146101cd57600080fd5b806311289565146100ef578063181f5a7714610104578063233fd52d14610156575b600080fd5b6101026100fd366004611474565b6102b0565b005b6101406040518060400160405280601a81526020017f466f7277617264657220616e6420526f7574657220312e302e3000000000000081525081565b60405161014d919061151f565b60405180910390f35b61016961016436600461158c565b61080d565b604051901515815260200161014d565b61018c610187366004611614565b610a00565b60405190815260200161014d565b6101ad6101a8366004611614565b610a84565b60405161014d9190611679565b6101026101c83660046116ba565b610b09565b6101026101db3660046116ba565b610b85565b610102610c04565b6101fb6101f6366004611614565b610d01565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014d565b60005473ffffffffffffffffffffffffffffffffffffffff166101fb565b61016961024c3660046116ba565b73ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205460ff1690565b6101026102853660046116e9565b610d41565b610102610298366004611767565b6110ba565b6101026102ab3660046116ba565b61115a565b606d8510156102eb576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080600061032f89898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061116e92505050565b67ffffffffffffffff8216600090815260026020526040812080549497509195509193509160ff16908190036103a2576040517fdf3b81ea00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b856103ae8260016117c9565b60ff1614610400576103c18160016117c9565b6040517fd6022e8e00000000000000000000000000000000000000000000000000000000815260ff909116600482015260248101879052604401610399565b60008b8b6040516104129291906117e8565b60405190819003812061042b918c908c906020016117f8565b60405160208183030381529060405280519060200120905061044b611301565b60005b888110156106cd573660008b8b8481811061046b5761046b611812565b905060200281019061047d9190611841565b9092509050604181146104c05781816040517f2adfdc300000000000000000000000000000000000000000000000000000000081526004016103999291906118ef565b6000600186848460408181106104d8576104d8611812565b6104ea92013560f81c9050601b6117c9565b6104f860206000878961190b565b61050191611935565b61050f60406020888a61190b565b61051891611935565b6040805160008152602081018083529590955260ff909316928401929092526060830152608082015260a0016020604051602081039080840390855afa158015610566573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff8116600090815260028c0160205291822054909350915081900361060c576040517fbf18af4300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610399565b600086826020811061062057610620611812565b602002015173ffffffffffffffffffffffffffffffffffffffff161461068a576040517fe021c4f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401610399565b8186826020811061069d5761069d611812565b73ffffffffffffffffffffffffffffffffffffffff909216602092909202015250506001909201915061044e9050565b50505050505060003073ffffffffffffffffffffffffffffffffffffffff1663233fd52d6106fc8c8686610a00565b338d8d8d602d90606d926107129392919061190b565b8f8f606d9080926107259392919061190b565b6040518863ffffffff1660e01b81526004016107479796959493929190611971565b6020604051808303816000875af1158015610766573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078a91906119d2565b9050817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916838b73ffffffffffffffffffffffffffffffffffffffff167f3617b009e9785c42daebadb6d3fb553243a4bf586d07ea72d65d80013ce116b5846040516107f9911515815260200190565b60405180910390a450505050505050505050565b3360009081526003602052604081205460ff16610856576040517fd79e123d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008881526004602052604090205473ffffffffffffffffffffffffffffffffffffffff16156108b5576040517fa53dc8ca00000000000000000000000000000000000000000000000000000000815260048101899052602401610399565b600088815260046020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a81169190911790915587163b9003610917575060006109f5565b6040517f805f213200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87169063805f21329061096f9088908890889088906004016119f4565b600060405180830381600087803b15801561098957600080fd5b505af192505050801561099a575060015b6109a6575060006109f5565b50600087815260046020526040902080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560015b979650505050505050565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085901b166020820152603481018390527fffff000000000000000000000000000000000000000000000000000000000000821660548201526000906056016040516020818303038152906040528051906020012090505b9392505050565b600080610a92858585610a00565b60008181526004602052604090205490915073ffffffffffffffffffffffffffffffffffffffff16610ac8576000915050610a7d565b60008181526004602052604090205474010000000000000000000000000000000000000000900460ff16610afd576002610b00565b60015b95945050505050565b610b11611189565b73ffffffffffffffffffffffffffffffffffffffff811660008181526003602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517fb96d15bf9258c7b8df062753a6a262864611fc7b060a5ee2e57e79b85f898d389190a250565b610b8d611189565b73ffffffffffffffffffffffffffffffffffffffff811660008181526003602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f0ea0ce2c048ff45a4a95f2947879de3fb94abec2f152190400cab2d1272a68e79190a250565b60015473ffffffffffffffffffffffffffffffffffffffff163314610c85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610399565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600060046000610d12868686610a00565b815260208101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff16949350505050565b610d49611189565b8260ff16600003610d86576040517f0743bae600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f811115610dcb576040517f61750f4000000000000000000000000000000000000000000000000000000000815260048101829052601f6024820152604401610399565b610dd6836003611a1b565b60ff168111610e345780610deb846003611a1b565b610df69060016117c9565b6040517f9dd9e6d8000000000000000000000000000000000000000000000000000000008152600481019290925260ff166024820152604401610399565b67ffffffff00000000602086901b1663ffffffff85161760005b67ffffffffffffffff8216600090815260026020526040902060010154811015610ee45767ffffffffffffffff8216600090815260026020819052604082206001810180549190920192919084908110610eaa57610eaa611812565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812055600101610e4e565b5060005b82811015610ffc576000848483818110610f0457610f04611812565b9050602002016020810190610f1991906116ba565b67ffffffffffffffff8416600090815260026020818152604080842073ffffffffffffffffffffffffffffffffffffffff86168552909201905290205490915015610fa8576040517fe021c4f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610399565b610fb3826001611a3e565b67ffffffffffffffff8416600090815260026020818152604080842073ffffffffffffffffffffffffffffffffffffffff90961684529490910190529190912055600101610ee8565b5067ffffffffffffffff81166000908152600260205260409020611024906001018484611320565b5067ffffffffffffffff81166000908152600260205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff87161790555163ffffffff86811691908816907f4120bd3b23957dd423555817d55654d4481b438aa15485c21b4180c784f1a455906110aa90889088908890611a51565b60405180910390a3505050505050565b6110c2611189565b63ffffffff818116602084811b67ffffffff00000000168217600090815260028252604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690558051828152928301905291928516917f4120bd3b23957dd423555817d55654d4481b438aa15485c21b4180c784f1a4559160405161114e929190611ab7565b60405180910390a35050565b611162611189565b61116b8161120c565b50565b60218101516045820151608b90920151909260c09290921c91565b60005473ffffffffffffffffffffffffffffffffffffffff16331461120a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610399565b565b3373ffffffffffffffffffffffffffffffffffffffff82160361128b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610399565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6040518061040001604052806020906020820280368337509192915050565b828054828255906000526020600020908101928215611398579160200282015b828111156113985781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190611340565b506113a49291506113a8565b5090565b5b808211156113a457600081556001016113a9565b803573ffffffffffffffffffffffffffffffffffffffff811681146113e157600080fd5b919050565b60008083601f8401126113f857600080fd5b50813567ffffffffffffffff81111561141057600080fd5b60208301915083602082850101111561142857600080fd5b9250929050565b60008083601f84011261144157600080fd5b50813567ffffffffffffffff81111561145957600080fd5b6020830191508360208260051b850101111561142857600080fd5b60008060008060008060006080888a03121561148f57600080fd5b611498886113bd565b9650602088013567ffffffffffffffff808211156114b557600080fd5b6114c18b838c016113e6565b909850965060408a01359150808211156114da57600080fd5b6114e68b838c016113e6565b909650945060608a01359150808211156114ff57600080fd5b5061150c8a828b0161142f565b989b979a50959850939692959293505050565b60006020808352835180602085015260005b8181101561154d57858101830151858201604001528201611531565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600080600080600080600060a0888a0312156115a757600080fd5b873596506115b7602089016113bd565b95506115c5604089016113bd565b9450606088013567ffffffffffffffff808211156115e257600080fd5b6115ee8b838c016113e6565b909650945060808a013591508082111561160757600080fd5b5061150c8a828b016113e6565b60008060006060848603121561162957600080fd5b611632846113bd565b92506020840135915060408401357fffff0000000000000000000000000000000000000000000000000000000000008116811461166e57600080fd5b809150509250925092565b60208101600383106116b4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6000602082840312156116cc57600080fd5b610a7d826113bd565b803563ffffffff811681146113e157600080fd5b60008060008060006080868803121561170157600080fd5b61170a866116d5565b9450611718602087016116d5565b9350604086013560ff8116811461172e57600080fd5b9250606086013567ffffffffffffffff81111561174a57600080fd5b6117568882890161142f565b969995985093965092949392505050565b6000806040838503121561177a57600080fd5b611783836116d5565b9150611791602084016116d5565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff81811683821601908111156117e2576117e261179a565b92915050565b8183823760009101908152919050565b838152818360208301376000910160200190815292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261187657600080fd5b83018035915067ffffffffffffffff82111561189157600080fd5b60200191503681900382131561142857600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6020815260006119036020830184866118a6565b949350505050565b6000808585111561191b57600080fd5b8386111561192857600080fd5b5050820193919092039150565b803560208310156117e2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b878152600073ffffffffffffffffffffffffffffffffffffffff808916602084015280881660408401525060a060608301526119b160a0830186886118a6565b82810360808401526119c48185876118a6565b9a9950505050505050505050565b6000602082840312156119e457600080fd5b81518015158114610a7d57600080fd5b604081526000611a086040830186886118a6565b82810360208401526109f58185876118a6565b60ff8181168382160290811690818114611a3757611a3761179a565b5092915050565b808201808211156117e2576117e261179a565b60ff8416815260406020808301829052908201839052600090849060608401835b86811015611aab5773ffffffffffffffffffffffffffffffffffffffff611a98856113bd565b1682529282019290820190600101611a72565b50979650505050505050565b60006040820160ff8516835260206040602085015281855180845260608601915060208701935060005b81811015611b1357845173ffffffffffffffffffffffffffffffffffffffff1683529383019391830191600101611ae1565b509097965050505050505056fea164736f6c6343000818000a",
+ ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transmissionId\",\"type\":\"bytes32\"}],\"name\":\"AlreadyAttempted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"DuplicateSigner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxSigners\",\"type\":\"uint256\"}],\"name\":\"ExcessSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FaultToleranceMustBePositive\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transmissionId\",\"type\":\"bytes32\"}],\"name\":\"InsufficientGasForRouting\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minSigners\",\"type\":\"uint256\"}],\"name\":\"InsufficientSigners\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"configId\",\"type\":\"uint64\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"received\",\"type\":\"uint256\"}],\"name\":\"InvalidSignatureCount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"signer\",\"type\":\"address\"}],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedForwarder\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"ForwarderAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"ForwarderRemoved\",\"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\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes2\",\"name\":\"reportId\",\"type\":\"bytes2\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"result\",\"type\":\"bool\"}],\"name\":\"ReportProcessed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"addForwarder\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"}],\"name\":\"clearConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes2\",\"name\":\"reportId\",\"type\":\"bytes2\"}],\"name\":\"getTransmissionId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes2\",\"name\":\"reportId\",\"type\":\"bytes2\"}],\"name\":\"getTransmissionInfo\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"transmissionId\",\"type\":\"bytes32\"},{\"internalType\":\"enumIRouter.TransmissionState\",\"name\":\"state\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"invalidReceiver\",\"type\":\"bool\"},{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"uint80\",\"name\":\"gasLimit\",\"type\":\"uint80\"}],\"internalType\":\"structIRouter.TransmissionInfo\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"workflowExecutionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes2\",\"name\":\"reportId\",\"type\":\"bytes2\"}],\"name\":\"getTransmitter\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"}],\"name\":\"isForwarder\",\"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\":\"forwarder\",\"type\":\"address\"}],\"name\":\"removeForwarder\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"rawReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"reportContext\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"signatures\",\"type\":\"bytes[]\"}],\"name\":\"report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transmissionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"validatedReport\",\"type\":\"bytes\"}],\"name\":\"route\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"donId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"configVersion\",\"type\":\"uint32\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"}],\"name\":\"setConfig\",\"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: "0x60806040523480156200001157600080fd5b503380600081620000695760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156200009c576200009c81620000bf565b5050306000908152600360205260409020805460ff19166001179055506200016a565b336001600160a01b03821603620001195760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000060565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b612141806200017a6000396000f3fe608060405234801561001057600080fd5b50600436106100ea5760003560e01c806379ba50971161008c578063abcef55411610066578063abcef5541461035d578063ee59d26c14610396578063ef6e17a0146103a9578063f2fde38b146103bc57600080fd5b806379ba50971461025e5780638864b864146102665780638da5cb5b1461033f57600080fd5b8063272cbd93116100c8578063272cbd9314610179578063354bdd66146101995780634d93172d146102385780635c41d2fe1461024b57600080fd5b806311289565146100ef578063181f5a7714610104578063233fd52d14610156575b600080fd5b6101026100fd3660046119df565b6103cf565b005b6101406040518060400160405280601a81526020017f466f7277617264657220616e6420526f7574657220312e302e3000000000000081525081565b60405161014d9190611a8a565b60405180910390f35b610169610164366004611af7565b610989565b604051901515815260200161014d565b61018c610187366004611b7f565b610e4a565b60405161014d9190611c13565b61022a6101a7366004611b7f565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085901b166020820152603481018390527fffff000000000000000000000000000000000000000000000000000000000000821660548201526000906056016040516020818303038152906040528051906020012090509392505050565b60405190815260200161014d565b610102610246366004611cbb565b611050565b610102610259366004611cbb565b6110cc565b61010261114b565b61031a610274366004611b7f565b6040805160609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208086019190915260348501939093527fffff000000000000000000000000000000000000000000000000000000000000919091166054840152805160368185030181526056909301815282519282019290922060009081526004909152205473ffffffffffffffffffffffffffffffffffffffff1690565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014d565b60005473ffffffffffffffffffffffffffffffffffffffff1661031a565b61016961036b366004611cbb565b73ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205460ff1690565b6101026103a4366004611cf1565b611248565b6101026103b7366004611d6f565b611625565b6101026103ca366004611cbb565b6116c5565b606d85101561040a576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080600061044e89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506116d992505050565b67ffffffffffffffff8216600090815260026020526040812080549497509195509193509160ff16908190036104c1576040517fdf3b81ea00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201526024015b60405180910390fd5b856104cd826001611dd1565b60ff161461051f576104e0816001611dd1565b6040517fd6022e8e00000000000000000000000000000000000000000000000000000000815260ff9091166004820152602481018790526044016104b8565b60008b8b604051610531929190611df0565b60405190819003812061054a918c908c90602001611e00565b60405160208183030381529060405280519060200120905061056a61186c565b60005b888110156107ec573660008b8b8481811061058a5761058a611e1a565b905060200281019061059c9190611e49565b9092509050604181146105df5781816040517f2adfdc300000000000000000000000000000000000000000000000000000000081526004016104b8929190611ef7565b6000600186848460408181106105f7576105f7611e1a565b61060992013560f81c9050601b611dd1565b610617602060008789611f13565b61062091611f3d565b61062e60406020888a611f13565b61063791611f3d565b6040805160008152602081018083529590955260ff909316928401929092526060830152608082015260a0016020604051602081039080840390855afa158015610685573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff8116600090815260028c0160205291822054909350915081900361072b576040517fbf18af4300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016104b8565b600086826020811061073f5761073f611e1a565b602002015173ffffffffffffffffffffffffffffffffffffffff16146107a9576040517fe021c4f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016104b8565b818682602081106107bc576107bc611e1a565b73ffffffffffffffffffffffffffffffffffffffff909216602092909202015250506001909201915061056d9050565b50506040805160608f901b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602080830191909152603482018990527fffff0000000000000000000000000000000000000000000000000000000000008816605483015282516036818403018152605690920190925280519101206000945030935063233fd52d92509050338d8d8d602d90606d9261088e93929190611f13565b8f8f606d9080926108a193929190611f13565b6040518863ffffffff1660e01b81526004016108c39796959493929190611f79565b6020604051808303816000875af11580156108e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109069190611fda565b9050817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916838b73ffffffffffffffffffffffffffffffffffffffff167f3617b009e9785c42daebadb6d3fb553243a4bf586d07ea72d65d80013ce116b584604051610975911515815260200190565b60405180910390a450505050505050505050565b3360009081526003602052604081205460ff166109d2576040517fd79e123d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a9050619c40811015610a16576040517f0bfecd63000000000000000000000000000000000000000000000000000000008152600481018a90526024016104b8565b6000898152600460209081526040918290208251608081018452905473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000810460ff90811615159383019390935275010000000000000000000000000000000000000000008104909216151592810183905276010000000000000000000000000000000000000000000090910469ffffffffffffffffffff1660608201529080610ace575080602001515b15610b08576040517fa53dc8ca000000000000000000000000000000000000000000000000000000008152600481018b90526024016104b8565b6000610b16619c4084611ffc565b905089600460008d815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460008d815260200190815260200160002060000160166101000a81548169ffffffffffffffffffff021916908369ffffffffffffffffffff1602179055508873ffffffffffffffffffffffffffffffffffffffff163b600003610c2257505050600088815260046020526040812080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790559050610e3f565b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f805f213200000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8a16906301ffc9a790602401602060405180830381865afa925050508015610ce6575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610ce391810190611fda565b60015b610d3f57505050600088815260046020526040812080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790559050610e3f565b5060008089898989604051602401610d5a949392919061200f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f805f21320000000000000000000000000000000000000000000000000000000017815281519192506000918291828f88f191508115610e335760008d815260046020526040902080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790555b509350610e3f92505050565b979650505050505050565b6040805160c0810182526000808252602080830182905282840182905260608084018390526080840183905260a0840183905284519088901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001681830152603481018790527fffff000000000000000000000000000000000000000000000000000000000000861660548201528451603681830301815260568201808752815191840191909120808552600490935285842060d68301909652945473ffffffffffffffffffffffffffffffffffffffff811680875274010000000000000000000000000000000000000000820460ff9081161515607685015275010000000000000000000000000000000000000000008304161515609684015276010000000000000000000000000000000000000000000090910469ffffffffffffffffffff1660b69092019190915292939092909190610fa857506000610fd0565b816020015115610fba57506002610fd0565b8160400151610fca576003610fcd565b60015b90505b6040518060c00160405280848152602001826003811115610ff357610ff3611be4565b8152602001836000015173ffffffffffffffffffffffffffffffffffffffff168152602001836020015115158152602001836040015115158152602001836060015169ffffffffffffffffffff1681525093505050509392505050565b6110586116f4565b73ffffffffffffffffffffffffffffffffffffffff811660008181526003602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517fb96d15bf9258c7b8df062753a6a262864611fc7b060a5ee2e57e79b85f898d389190a250565b6110d46116f4565b73ffffffffffffffffffffffffffffffffffffffff811660008181526003602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f0ea0ce2c048ff45a4a95f2947879de3fb94abec2f152190400cab2d1272a68e79190a250565b60015473ffffffffffffffffffffffffffffffffffffffff1633146111cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016104b8565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6112506116f4565b8260ff1660000361128d576040517f0743bae600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f8111156112d2576040517f61750f4000000000000000000000000000000000000000000000000000000000815260048101829052601f60248201526044016104b8565b6112dd836003612036565b60ff16811161133b57806112f2846003612036565b6112fd906001611dd1565b6040517f9dd9e6d8000000000000000000000000000000000000000000000000000000008152600481019290925260ff1660248201526044016104b8565b67ffffffff00000000602086901b1663ffffffff85161760005b67ffffffffffffffff82166000908152600260205260409020600101548110156113eb5767ffffffffffffffff82166000908152600260208190526040822060018101805491909201929190849081106113b1576113b1611e1a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812055600101611355565b5060005b8281101561156757600084848381811061140b5761140b611e1a565b90506020020160208101906114209190611cbb565b905073ffffffffffffffffffffffffffffffffffffffff8116611487576040517fbf18af4300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016104b8565b67ffffffffffffffff8316600090815260026020818152604080842073ffffffffffffffffffffffffffffffffffffffff86168552909201905290205415611513576040517fe021c4f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016104b8565b61151e826001612052565b67ffffffffffffffff8416600090815260026020818152604080842073ffffffffffffffffffffffffffffffffffffffff909616845294909101905291909120556001016113ef565b5067ffffffffffffffff8116600090815260026020526040902061158f90600101848461188b565b5067ffffffffffffffff81166000908152600260205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff87161790555163ffffffff86811691908816907f4120bd3b23957dd423555817d55654d4481b438aa15485c21b4180c784f1a4559061161590889088908890612065565b60405180910390a3505050505050565b61162d6116f4565b63ffffffff818116602084811b67ffffffff00000000168217600090815260028252604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690558051828152928301905291928516917f4120bd3b23957dd423555817d55654d4481b438aa15485c21b4180c784f1a455916040516116b99291906120cb565b60405180910390a35050565b6116cd6116f4565b6116d681611777565b50565b60218101516045820151608b90920151909260c09290921c91565b60005473ffffffffffffffffffffffffffffffffffffffff163314611775576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016104b8565b565b3373ffffffffffffffffffffffffffffffffffffffff8216036117f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016104b8565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6040518061040001604052806020906020820280368337509192915050565b828054828255906000526020600020908101928215611903579160200282015b828111156119035781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8435161782556020909201916001909101906118ab565b5061190f929150611913565b5090565b5b8082111561190f5760008155600101611914565b803573ffffffffffffffffffffffffffffffffffffffff8116811461194c57600080fd5b919050565b60008083601f84011261196357600080fd5b50813567ffffffffffffffff81111561197b57600080fd5b60208301915083602082850101111561199357600080fd5b9250929050565b60008083601f8401126119ac57600080fd5b50813567ffffffffffffffff8111156119c457600080fd5b6020830191508360208260051b850101111561199357600080fd5b60008060008060008060006080888a0312156119fa57600080fd5b611a0388611928565b9650602088013567ffffffffffffffff80821115611a2057600080fd5b611a2c8b838c01611951565b909850965060408a0135915080821115611a4557600080fd5b611a518b838c01611951565b909650945060608a0135915080821115611a6a57600080fd5b50611a778a828b0161199a565b989b979a50959850939692959293505050565b60006020808352835180602085015260005b81811015611ab857858101830151858201604001528201611a9c565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600080600080600080600060a0888a031215611b1257600080fd5b87359650611b2260208901611928565b9550611b3060408901611928565b9450606088013567ffffffffffffffff80821115611b4d57600080fd5b611b598b838c01611951565b909650945060808a0135915080821115611b7257600080fd5b50611a778a828b01611951565b600080600060608486031215611b9457600080fd5b611b9d84611928565b92506020840135915060408401357fffff00000000000000000000000000000000000000000000000000000000000081168114611bd957600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b81518152602082015160c082019060048110611c58577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8060208401525073ffffffffffffffffffffffffffffffffffffffff604084015116604083015260608301511515606083015260808301511515608083015260a0830151611cb460a084018269ffffffffffffffffffff169052565b5092915050565b600060208284031215611ccd57600080fd5b611cd682611928565b9392505050565b803563ffffffff8116811461194c57600080fd5b600080600080600060808688031215611d0957600080fd5b611d1286611cdd565b9450611d2060208701611cdd565b9350604086013560ff81168114611d3657600080fd5b9250606086013567ffffffffffffffff811115611d5257600080fd5b611d5e8882890161199a565b969995985093965092949392505050565b60008060408385031215611d8257600080fd5b611d8b83611cdd565b9150611d9960208401611cdd565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff8181168382160190811115611dea57611dea611da2565b92915050565b8183823760009101908152919050565b838152818360208301376000910160200190815292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611e7e57600080fd5b83018035915067ffffffffffffffff821115611e9957600080fd5b60200191503681900382131561199357600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000611f0b602083018486611eae565b949350505050565b60008085851115611f2357600080fd5b83861115611f3057600080fd5b5050820193919092039150565b80356020831015611dea577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b878152600073ffffffffffffffffffffffffffffffffffffffff808916602084015280881660408401525060a06060830152611fb960a083018688611eae565b8281036080840152611fcc818587611eae565b9a9950505050505050505050565b600060208284031215611fec57600080fd5b81518015158114611cd657600080fd5b81810381811115611dea57611dea611da2565b604081526000612023604083018688611eae565b8281036020840152610e3f818587611eae565b60ff8181168382160290811690818114611cb457611cb4611da2565b80820180821115611dea57611dea611da2565b60ff8416815260406020808301829052908201839052600090849060608401835b868110156120bf5773ffffffffffffffffffffffffffffffffffffffff6120ac85611928565b1682529282019290820190600101612086565b50979650505050505050565b60006040820160ff8516835260206040602085015281855180845260608601915060208701935060005b8181101561212757845173ffffffffffffffffffffffffffffffffffffffff16835293830193918301916001016120f5565b509097965050505050505056fea164736f6c6343000818000a",
}
var KeystoneForwarderABI = KeystoneForwarderMetaData.ABI
@@ -193,26 +202,26 @@ func (_KeystoneForwarder *KeystoneForwarderCallerSession) GetTransmissionId(rece
return _KeystoneForwarder.Contract.GetTransmissionId(&_KeystoneForwarder.CallOpts, receiver, workflowExecutionId, reportId)
}
-func (_KeystoneForwarder *KeystoneForwarderCaller) GetTransmissionState(opts *bind.CallOpts, receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (uint8, error) {
+func (_KeystoneForwarder *KeystoneForwarderCaller) GetTransmissionInfo(opts *bind.CallOpts, receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (IRouterTransmissionInfo, error) {
var out []interface{}
- err := _KeystoneForwarder.contract.Call(opts, &out, "getTransmissionState", receiver, workflowExecutionId, reportId)
+ err := _KeystoneForwarder.contract.Call(opts, &out, "getTransmissionInfo", receiver, workflowExecutionId, reportId)
if err != nil {
- return *new(uint8), err
+ return *new(IRouterTransmissionInfo), err
}
- out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8)
+ out0 := *abi.ConvertType(out[0], new(IRouterTransmissionInfo)).(*IRouterTransmissionInfo)
return out0, err
}
-func (_KeystoneForwarder *KeystoneForwarderSession) GetTransmissionState(receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (uint8, error) {
- return _KeystoneForwarder.Contract.GetTransmissionState(&_KeystoneForwarder.CallOpts, receiver, workflowExecutionId, reportId)
+func (_KeystoneForwarder *KeystoneForwarderSession) GetTransmissionInfo(receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (IRouterTransmissionInfo, error) {
+ return _KeystoneForwarder.Contract.GetTransmissionInfo(&_KeystoneForwarder.CallOpts, receiver, workflowExecutionId, reportId)
}
-func (_KeystoneForwarder *KeystoneForwarderCallerSession) GetTransmissionState(receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (uint8, error) {
- return _KeystoneForwarder.Contract.GetTransmissionState(&_KeystoneForwarder.CallOpts, receiver, workflowExecutionId, reportId)
+func (_KeystoneForwarder *KeystoneForwarderCallerSession) GetTransmissionInfo(receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (IRouterTransmissionInfo, error) {
+ return _KeystoneForwarder.Contract.GetTransmissionInfo(&_KeystoneForwarder.CallOpts, receiver, workflowExecutionId, reportId)
}
func (_KeystoneForwarder *KeystoneForwarderCaller) GetTransmitter(opts *bind.CallOpts, receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (common.Address, error) {
@@ -1260,7 +1269,7 @@ func (_KeystoneForwarder *KeystoneForwarder) Address() common.Address {
type KeystoneForwarderInterface interface {
GetTransmissionId(opts *bind.CallOpts, receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) ([32]byte, error)
- GetTransmissionState(opts *bind.CallOpts, receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (uint8, error)
+ GetTransmissionInfo(opts *bind.CallOpts, receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (IRouterTransmissionInfo, error)
GetTransmitter(opts *bind.CallOpts, receiver common.Address, workflowExecutionId [32]byte, reportId [2]byte) (common.Address, error)
diff --git a/core/gethwrappers/keystone/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/keystone/generation/generated-wrapper-dependency-versions-do-not-edit.txt
index 7d25f651dda..30396c12e70 100644
--- a/core/gethwrappers/keystone/generation/generated-wrapper-dependency-versions-do-not-edit.txt
+++ b/core/gethwrappers/keystone/generation/generated-wrapper-dependency-versions-do-not-edit.txt
@@ -1,5 +1,5 @@
GETH_VERSION: 1.13.8
-capabilities_registry: ../../../contracts/solc/v0.8.24/CapabilitiesRegistry/CapabilitiesRegistry.abi ../../../contracts/solc/v0.8.24/CapabilitiesRegistry/CapabilitiesRegistry.bin 6d2e3aa3a6f3aed2cf24b613743bb9ae4b9558f48a6864dc03b8b0ebb37235e3
-feeds_consumer: ../../../contracts/solc/v0.8.24/KeystoneFeedsConsumer/KeystoneFeedsConsumer.abi ../../../contracts/solc/v0.8.24/KeystoneFeedsConsumer/KeystoneFeedsConsumer.bin f098e25df6afc100425fcad7f5107aec0844cc98315117e49da139a179d0eead
-forwarder: ../../../contracts/solc/v0.8.24/KeystoneForwarder/KeystoneForwarder.abi ../../../contracts/solc/v0.8.24/KeystoneForwarder/KeystoneForwarder.bin dc98a86a3775ead987b79d5b6079ee0e26f31c0626032bdd6508f986e2423227
+capabilities_registry: ../../../contracts/solc/v0.8.24/CapabilitiesRegistry/CapabilitiesRegistry.abi ../../../contracts/solc/v0.8.24/CapabilitiesRegistry/CapabilitiesRegistry.bin 7e95d72f24940f08ada0ee3b85d894d6bfccfd6c8a3e0ceeff65bae52c899d54
+feeds_consumer: ../../../contracts/solc/v0.8.24/KeystoneFeedsConsumer/KeystoneFeedsConsumer.abi ../../../contracts/solc/v0.8.24/KeystoneFeedsConsumer/KeystoneFeedsConsumer.bin 8c3a2b18a80be41e7c40d2bc3a4c8d1b5e18d55c1fd20ad5af68cebb66109fc5
+forwarder: ../../../contracts/solc/v0.8.24/KeystoneForwarder/KeystoneForwarder.abi ../../../contracts/solc/v0.8.24/KeystoneForwarder/KeystoneForwarder.bin 45d9b866c64b41c1349a90b6764aee42a6d078b454d38f369b5fe02b23b9d16e
ocr3_capability: ../../../contracts/solc/v0.8.24/OCR3Capability/OCR3Capability.abi ../../../contracts/solc/v0.8.24/OCR3Capability/OCR3Capability.bin 8bf0f53f222efce7143dea6134552eb26ea1eef845407b4475a0d79b7d7ba9f8
diff --git a/core/gethwrappers/liquiditymanager/generated/abstract_arbitrum_token_gateway/abstract_arbitrum_token_gateway.go b/core/gethwrappers/liquiditymanager/generated/abstract_arbitrum_token_gateway/abstract_arbitrum_token_gateway.go
new file mode 100644
index 00000000000..d9dd3f435de
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/abstract_arbitrum_token_gateway/abstract_arbitrum_token_gateway.go
@@ -0,0 +1,283 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package abstract_arbitrum_token_gateway
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var AbstractArbitrumTokenGatewayMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1ERC20\",\"type\":\"address\"}],\"name\":\"calculateL2TokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counterpartGateway\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeInboundTransfer\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getOutboundCalldata\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasPriceBid\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"outboundTransfer\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var AbstractArbitrumTokenGatewayABI = AbstractArbitrumTokenGatewayMetaData.ABI
+
+type AbstractArbitrumTokenGateway struct {
+ address common.Address
+ abi abi.ABI
+ AbstractArbitrumTokenGatewayCaller
+ AbstractArbitrumTokenGatewayTransactor
+ AbstractArbitrumTokenGatewayFilterer
+}
+
+type AbstractArbitrumTokenGatewayCaller struct {
+ contract *bind.BoundContract
+}
+
+type AbstractArbitrumTokenGatewayTransactor struct {
+ contract *bind.BoundContract
+}
+
+type AbstractArbitrumTokenGatewayFilterer struct {
+ contract *bind.BoundContract
+}
+
+type AbstractArbitrumTokenGatewaySession struct {
+ Contract *AbstractArbitrumTokenGateway
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type AbstractArbitrumTokenGatewayCallerSession struct {
+ Contract *AbstractArbitrumTokenGatewayCaller
+ CallOpts bind.CallOpts
+}
+
+type AbstractArbitrumTokenGatewayTransactorSession struct {
+ Contract *AbstractArbitrumTokenGatewayTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type AbstractArbitrumTokenGatewayRaw struct {
+ Contract *AbstractArbitrumTokenGateway
+}
+
+type AbstractArbitrumTokenGatewayCallerRaw struct {
+ Contract *AbstractArbitrumTokenGatewayCaller
+}
+
+type AbstractArbitrumTokenGatewayTransactorRaw struct {
+ Contract *AbstractArbitrumTokenGatewayTransactor
+}
+
+func NewAbstractArbitrumTokenGateway(address common.Address, backend bind.ContractBackend) (*AbstractArbitrumTokenGateway, error) {
+ abi, err := abi.JSON(strings.NewReader(AbstractArbitrumTokenGatewayABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindAbstractArbitrumTokenGateway(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &AbstractArbitrumTokenGateway{address: address, abi: abi, AbstractArbitrumTokenGatewayCaller: AbstractArbitrumTokenGatewayCaller{contract: contract}, AbstractArbitrumTokenGatewayTransactor: AbstractArbitrumTokenGatewayTransactor{contract: contract}, AbstractArbitrumTokenGatewayFilterer: AbstractArbitrumTokenGatewayFilterer{contract: contract}}, nil
+}
+
+func NewAbstractArbitrumTokenGatewayCaller(address common.Address, caller bind.ContractCaller) (*AbstractArbitrumTokenGatewayCaller, error) {
+ contract, err := bindAbstractArbitrumTokenGateway(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &AbstractArbitrumTokenGatewayCaller{contract: contract}, nil
+}
+
+func NewAbstractArbitrumTokenGatewayTransactor(address common.Address, transactor bind.ContractTransactor) (*AbstractArbitrumTokenGatewayTransactor, error) {
+ contract, err := bindAbstractArbitrumTokenGateway(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &AbstractArbitrumTokenGatewayTransactor{contract: contract}, nil
+}
+
+func NewAbstractArbitrumTokenGatewayFilterer(address common.Address, filterer bind.ContractFilterer) (*AbstractArbitrumTokenGatewayFilterer, error) {
+ contract, err := bindAbstractArbitrumTokenGateway(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &AbstractArbitrumTokenGatewayFilterer{contract: contract}, nil
+}
+
+func bindAbstractArbitrumTokenGateway(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := AbstractArbitrumTokenGatewayMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _AbstractArbitrumTokenGateway.Contract.AbstractArbitrumTokenGatewayCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.Contract.AbstractArbitrumTokenGatewayTransactor.contract.Transfer(opts)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.Contract.AbstractArbitrumTokenGatewayTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _AbstractArbitrumTokenGateway.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.Contract.contract.Transfer(opts)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCaller) CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _AbstractArbitrumTokenGateway.contract.Call(opts, &out, "calculateL2TokenAddress", l1ERC20)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewaySession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _AbstractArbitrumTokenGateway.Contract.CalculateL2TokenAddress(&_AbstractArbitrumTokenGateway.CallOpts, l1ERC20)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCallerSession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _AbstractArbitrumTokenGateway.Contract.CalculateL2TokenAddress(&_AbstractArbitrumTokenGateway.CallOpts, l1ERC20)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCaller) CounterpartGateway(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _AbstractArbitrumTokenGateway.contract.Call(opts, &out, "counterpartGateway")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewaySession) CounterpartGateway() (common.Address, error) {
+ return _AbstractArbitrumTokenGateway.Contract.CounterpartGateway(&_AbstractArbitrumTokenGateway.CallOpts)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCallerSession) CounterpartGateway() (common.Address, error) {
+ return _AbstractArbitrumTokenGateway.Contract.CounterpartGateway(&_AbstractArbitrumTokenGateway.CallOpts)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCaller) GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ var out []interface{}
+ err := _AbstractArbitrumTokenGateway.contract.Call(opts, &out, "getOutboundCalldata", _token, _from, _to, _amount, _data)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewaySession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _AbstractArbitrumTokenGateway.Contract.GetOutboundCalldata(&_AbstractArbitrumTokenGateway.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCallerSession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _AbstractArbitrumTokenGateway.Contract.GetOutboundCalldata(&_AbstractArbitrumTokenGateway.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCaller) Router(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _AbstractArbitrumTokenGateway.contract.Call(opts, &out, "router")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewaySession) Router() (common.Address, error) {
+ return _AbstractArbitrumTokenGateway.Contract.Router(&_AbstractArbitrumTokenGateway.CallOpts)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayCallerSession) Router() (common.Address, error) {
+ return _AbstractArbitrumTokenGateway.Contract.Router(&_AbstractArbitrumTokenGateway.CallOpts)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayTransactor) FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.contract.Transact(opts, "finalizeInboundTransfer", _token, _from, _to, _amount, _data)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewaySession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.Contract.FinalizeInboundTransfer(&_AbstractArbitrumTokenGateway.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayTransactorSession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.Contract.FinalizeInboundTransfer(&_AbstractArbitrumTokenGateway.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayTransactor) OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.contract.Transact(opts, "outboundTransfer", _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewaySession) OutboundTransfer(_token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.Contract.OutboundTransfer(&_AbstractArbitrumTokenGateway.TransactOpts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGatewayTransactorSession) OutboundTransfer(_token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _AbstractArbitrumTokenGateway.Contract.OutboundTransfer(&_AbstractArbitrumTokenGateway.TransactOpts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_AbstractArbitrumTokenGateway *AbstractArbitrumTokenGateway) Address() common.Address {
+ return _AbstractArbitrumTokenGateway.address
+}
+
+type AbstractArbitrumTokenGatewayInterface interface {
+ CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error)
+
+ CounterpartGateway(opts *bind.CallOpts) (common.Address, error)
+
+ GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error)
+
+ Router(opts *bind.CallOpts) (common.Address, error)
+
+ FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error)
+
+ OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arb_node_interface/arb_node_interface.go b/core/gethwrappers/liquiditymanager/generated/arb_node_interface/arb_node_interface.go
new file mode 100644
index 00000000000..966c9f73168
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arb_node_interface/arb_node_interface.go
@@ -0,0 +1,428 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arb_node_interface
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var NodeInterfaceMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"l2BlockNum\",\"type\":\"uint64\"}],\"name\":\"blockL1Num\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"l1BlockNum\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"size\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"leaf\",\"type\":\"uint64\"}],\"name\":\"constructOutboxProof\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"send\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"deposit\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"l2CallValue\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"excessFeeRefundAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"callValueRefundAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"estimateRetryableTicket\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"}],\"name\":\"findBatchContainingBlock\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"batch\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"contractCreation\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"gasEstimateComponents\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"gasEstimate\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"gasEstimateForL1\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"baseFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"l1BaseFeeEstimate\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"contractCreation\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"gasEstimateL1Component\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"gasEstimateForL1\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"baseFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"l1BaseFeeEstimate\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"name\":\"getL1Confirmations\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"confirmations\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"blockNum\",\"type\":\"uint64\"}],\"name\":\"l2BlockRangeForL1\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"firstBlock\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"lastBlock\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"batchNum\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"}],\"name\":\"legacyLookupMessageBatchProof\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"path\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"l2Sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"l1Dest\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"l2Block\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"l1Block\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"calldataForL1\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nitroGenesisBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"number\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
+}
+
+var NodeInterfaceABI = NodeInterfaceMetaData.ABI
+
+type NodeInterface struct {
+ address common.Address
+ abi abi.ABI
+ NodeInterfaceCaller
+ NodeInterfaceTransactor
+ NodeInterfaceFilterer
+}
+
+type NodeInterfaceCaller struct {
+ contract *bind.BoundContract
+}
+
+type NodeInterfaceTransactor struct {
+ contract *bind.BoundContract
+}
+
+type NodeInterfaceFilterer struct {
+ contract *bind.BoundContract
+}
+
+type NodeInterfaceSession struct {
+ Contract *NodeInterface
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type NodeInterfaceCallerSession struct {
+ Contract *NodeInterfaceCaller
+ CallOpts bind.CallOpts
+}
+
+type NodeInterfaceTransactorSession struct {
+ Contract *NodeInterfaceTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type NodeInterfaceRaw struct {
+ Contract *NodeInterface
+}
+
+type NodeInterfaceCallerRaw struct {
+ Contract *NodeInterfaceCaller
+}
+
+type NodeInterfaceTransactorRaw struct {
+ Contract *NodeInterfaceTransactor
+}
+
+func NewNodeInterface(address common.Address, backend bind.ContractBackend) (*NodeInterface, error) {
+ abi, err := abi.JSON(strings.NewReader(NodeInterfaceABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindNodeInterface(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &NodeInterface{address: address, abi: abi, NodeInterfaceCaller: NodeInterfaceCaller{contract: contract}, NodeInterfaceTransactor: NodeInterfaceTransactor{contract: contract}, NodeInterfaceFilterer: NodeInterfaceFilterer{contract: contract}}, nil
+}
+
+func NewNodeInterfaceCaller(address common.Address, caller bind.ContractCaller) (*NodeInterfaceCaller, error) {
+ contract, err := bindNodeInterface(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &NodeInterfaceCaller{contract: contract}, nil
+}
+
+func NewNodeInterfaceTransactor(address common.Address, transactor bind.ContractTransactor) (*NodeInterfaceTransactor, error) {
+ contract, err := bindNodeInterface(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &NodeInterfaceTransactor{contract: contract}, nil
+}
+
+func NewNodeInterfaceFilterer(address common.Address, filterer bind.ContractFilterer) (*NodeInterfaceFilterer, error) {
+ contract, err := bindNodeInterface(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &NodeInterfaceFilterer{contract: contract}, nil
+}
+
+func bindNodeInterface(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := NodeInterfaceMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_NodeInterface *NodeInterfaceRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _NodeInterface.Contract.NodeInterfaceCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_NodeInterface *NodeInterfaceRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _NodeInterface.Contract.NodeInterfaceTransactor.contract.Transfer(opts)
+}
+
+func (_NodeInterface *NodeInterfaceRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _NodeInterface.Contract.NodeInterfaceTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_NodeInterface *NodeInterfaceCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _NodeInterface.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_NodeInterface *NodeInterfaceTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _NodeInterface.Contract.contract.Transfer(opts)
+}
+
+func (_NodeInterface *NodeInterfaceTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _NodeInterface.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_NodeInterface *NodeInterfaceCaller) BlockL1Num(opts *bind.CallOpts, l2BlockNum uint64) (uint64, error) {
+ var out []interface{}
+ err := _NodeInterface.contract.Call(opts, &out, "blockL1Num", l2BlockNum)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_NodeInterface *NodeInterfaceSession) BlockL1Num(l2BlockNum uint64) (uint64, error) {
+ return _NodeInterface.Contract.BlockL1Num(&_NodeInterface.CallOpts, l2BlockNum)
+}
+
+func (_NodeInterface *NodeInterfaceCallerSession) BlockL1Num(l2BlockNum uint64) (uint64, error) {
+ return _NodeInterface.Contract.BlockL1Num(&_NodeInterface.CallOpts, l2BlockNum)
+}
+
+func (_NodeInterface *NodeInterfaceCaller) ConstructOutboxProof(opts *bind.CallOpts, size uint64, leaf uint64) (ConstructOutboxProof,
+
+ error) {
+ var out []interface{}
+ err := _NodeInterface.contract.Call(opts, &out, "constructOutboxProof", size, leaf)
+
+ outstruct := new(ConstructOutboxProof)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.Send = *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
+ outstruct.Root = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Proof = *abi.ConvertType(out[2], new([][32]byte)).(*[][32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_NodeInterface *NodeInterfaceSession) ConstructOutboxProof(size uint64, leaf uint64) (ConstructOutboxProof,
+
+ error) {
+ return _NodeInterface.Contract.ConstructOutboxProof(&_NodeInterface.CallOpts, size, leaf)
+}
+
+func (_NodeInterface *NodeInterfaceCallerSession) ConstructOutboxProof(size uint64, leaf uint64) (ConstructOutboxProof,
+
+ error) {
+ return _NodeInterface.Contract.ConstructOutboxProof(&_NodeInterface.CallOpts, size, leaf)
+}
+
+func (_NodeInterface *NodeInterfaceCaller) FindBatchContainingBlock(opts *bind.CallOpts, blockNum uint64) (uint64, error) {
+ var out []interface{}
+ err := _NodeInterface.contract.Call(opts, &out, "findBatchContainingBlock", blockNum)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_NodeInterface *NodeInterfaceSession) FindBatchContainingBlock(blockNum uint64) (uint64, error) {
+ return _NodeInterface.Contract.FindBatchContainingBlock(&_NodeInterface.CallOpts, blockNum)
+}
+
+func (_NodeInterface *NodeInterfaceCallerSession) FindBatchContainingBlock(blockNum uint64) (uint64, error) {
+ return _NodeInterface.Contract.FindBatchContainingBlock(&_NodeInterface.CallOpts, blockNum)
+}
+
+func (_NodeInterface *NodeInterfaceCaller) GetL1Confirmations(opts *bind.CallOpts, blockHash [32]byte) (uint64, error) {
+ var out []interface{}
+ err := _NodeInterface.contract.Call(opts, &out, "getL1Confirmations", blockHash)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_NodeInterface *NodeInterfaceSession) GetL1Confirmations(blockHash [32]byte) (uint64, error) {
+ return _NodeInterface.Contract.GetL1Confirmations(&_NodeInterface.CallOpts, blockHash)
+}
+
+func (_NodeInterface *NodeInterfaceCallerSession) GetL1Confirmations(blockHash [32]byte) (uint64, error) {
+ return _NodeInterface.Contract.GetL1Confirmations(&_NodeInterface.CallOpts, blockHash)
+}
+
+func (_NodeInterface *NodeInterfaceCaller) L2BlockRangeForL1(opts *bind.CallOpts, blockNum uint64) (L2BlockRangeForL1,
+
+ error) {
+ var out []interface{}
+ err := _NodeInterface.contract.Call(opts, &out, "l2BlockRangeForL1", blockNum)
+
+ outstruct := new(L2BlockRangeForL1)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.FirstBlock = *abi.ConvertType(out[0], new(uint64)).(*uint64)
+ outstruct.LastBlock = *abi.ConvertType(out[1], new(uint64)).(*uint64)
+
+ return *outstruct, err
+
+}
+
+func (_NodeInterface *NodeInterfaceSession) L2BlockRangeForL1(blockNum uint64) (L2BlockRangeForL1,
+
+ error) {
+ return _NodeInterface.Contract.L2BlockRangeForL1(&_NodeInterface.CallOpts, blockNum)
+}
+
+func (_NodeInterface *NodeInterfaceCallerSession) L2BlockRangeForL1(blockNum uint64) (L2BlockRangeForL1,
+
+ error) {
+ return _NodeInterface.Contract.L2BlockRangeForL1(&_NodeInterface.CallOpts, blockNum)
+}
+
+func (_NodeInterface *NodeInterfaceCaller) LegacyLookupMessageBatchProof(opts *bind.CallOpts, batchNum *big.Int, index uint64) (LegacyLookupMessageBatchProof,
+
+ error) {
+ var out []interface{}
+ err := _NodeInterface.contract.Call(opts, &out, "legacyLookupMessageBatchProof", batchNum, index)
+
+ outstruct := new(LegacyLookupMessageBatchProof)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.Proof = *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte)
+ outstruct.Path = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int)
+ outstruct.L2Sender = *abi.ConvertType(out[2], new(common.Address)).(*common.Address)
+ outstruct.L1Dest = *abi.ConvertType(out[3], new(common.Address)).(*common.Address)
+ outstruct.L2Block = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int)
+ outstruct.L1Block = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int)
+ outstruct.Timestamp = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int)
+ outstruct.Amount = *abi.ConvertType(out[7], new(*big.Int)).(**big.Int)
+ outstruct.CalldataForL1 = *abi.ConvertType(out[8], new([]byte)).(*[]byte)
+
+ return *outstruct, err
+
+}
+
+func (_NodeInterface *NodeInterfaceSession) LegacyLookupMessageBatchProof(batchNum *big.Int, index uint64) (LegacyLookupMessageBatchProof,
+
+ error) {
+ return _NodeInterface.Contract.LegacyLookupMessageBatchProof(&_NodeInterface.CallOpts, batchNum, index)
+}
+
+func (_NodeInterface *NodeInterfaceCallerSession) LegacyLookupMessageBatchProof(batchNum *big.Int, index uint64) (LegacyLookupMessageBatchProof,
+
+ error) {
+ return _NodeInterface.Contract.LegacyLookupMessageBatchProof(&_NodeInterface.CallOpts, batchNum, index)
+}
+
+func (_NodeInterface *NodeInterfaceCaller) NitroGenesisBlock(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _NodeInterface.contract.Call(opts, &out, "nitroGenesisBlock")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_NodeInterface *NodeInterfaceSession) NitroGenesisBlock() (*big.Int, error) {
+ return _NodeInterface.Contract.NitroGenesisBlock(&_NodeInterface.CallOpts)
+}
+
+func (_NodeInterface *NodeInterfaceCallerSession) NitroGenesisBlock() (*big.Int, error) {
+ return _NodeInterface.Contract.NitroGenesisBlock(&_NodeInterface.CallOpts)
+}
+
+func (_NodeInterface *NodeInterfaceTransactor) EstimateRetryableTicket(opts *bind.TransactOpts, sender common.Address, deposit *big.Int, to common.Address, l2CallValue *big.Int, excessFeeRefundAddress common.Address, callValueRefundAddress common.Address, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.contract.Transact(opts, "estimateRetryableTicket", sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data)
+}
+
+func (_NodeInterface *NodeInterfaceSession) EstimateRetryableTicket(sender common.Address, deposit *big.Int, to common.Address, l2CallValue *big.Int, excessFeeRefundAddress common.Address, callValueRefundAddress common.Address, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.Contract.EstimateRetryableTicket(&_NodeInterface.TransactOpts, sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data)
+}
+
+func (_NodeInterface *NodeInterfaceTransactorSession) EstimateRetryableTicket(sender common.Address, deposit *big.Int, to common.Address, l2CallValue *big.Int, excessFeeRefundAddress common.Address, callValueRefundAddress common.Address, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.Contract.EstimateRetryableTicket(&_NodeInterface.TransactOpts, sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data)
+}
+
+func (_NodeInterface *NodeInterfaceTransactor) GasEstimateComponents(opts *bind.TransactOpts, to common.Address, contractCreation bool, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.contract.Transact(opts, "gasEstimateComponents", to, contractCreation, data)
+}
+
+func (_NodeInterface *NodeInterfaceSession) GasEstimateComponents(to common.Address, contractCreation bool, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.Contract.GasEstimateComponents(&_NodeInterface.TransactOpts, to, contractCreation, data)
+}
+
+func (_NodeInterface *NodeInterfaceTransactorSession) GasEstimateComponents(to common.Address, contractCreation bool, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.Contract.GasEstimateComponents(&_NodeInterface.TransactOpts, to, contractCreation, data)
+}
+
+func (_NodeInterface *NodeInterfaceTransactor) GasEstimateL1Component(opts *bind.TransactOpts, to common.Address, contractCreation bool, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.contract.Transact(opts, "gasEstimateL1Component", to, contractCreation, data)
+}
+
+func (_NodeInterface *NodeInterfaceSession) GasEstimateL1Component(to common.Address, contractCreation bool, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.Contract.GasEstimateL1Component(&_NodeInterface.TransactOpts, to, contractCreation, data)
+}
+
+func (_NodeInterface *NodeInterfaceTransactorSession) GasEstimateL1Component(to common.Address, contractCreation bool, data []byte) (*types.Transaction, error) {
+ return _NodeInterface.Contract.GasEstimateL1Component(&_NodeInterface.TransactOpts, to, contractCreation, data)
+}
+
+type ConstructOutboxProof struct {
+ Send [32]byte
+ Root [32]byte
+ Proof [][32]byte
+}
+type L2BlockRangeForL1 struct {
+ FirstBlock uint64
+ LastBlock uint64
+}
+type LegacyLookupMessageBatchProof struct {
+ Proof [][32]byte
+ Path *big.Int
+ L2Sender common.Address
+ L1Dest common.Address
+ L2Block *big.Int
+ L1Block *big.Int
+ Timestamp *big.Int
+ Amount *big.Int
+ CalldataForL1 []byte
+}
+
+func (_NodeInterface *NodeInterface) Address() common.Address {
+ return _NodeInterface.address
+}
+
+type NodeInterfaceInterface interface {
+ BlockL1Num(opts *bind.CallOpts, l2BlockNum uint64) (uint64, error)
+
+ ConstructOutboxProof(opts *bind.CallOpts, size uint64, leaf uint64) (ConstructOutboxProof,
+
+ error)
+
+ FindBatchContainingBlock(opts *bind.CallOpts, blockNum uint64) (uint64, error)
+
+ GetL1Confirmations(opts *bind.CallOpts, blockHash [32]byte) (uint64, error)
+
+ L2BlockRangeForL1(opts *bind.CallOpts, blockNum uint64) (L2BlockRangeForL1,
+
+ error)
+
+ LegacyLookupMessageBatchProof(opts *bind.CallOpts, batchNum *big.Int, index uint64) (LegacyLookupMessageBatchProof,
+
+ error)
+
+ NitroGenesisBlock(opts *bind.CallOpts) (*big.Int, error)
+
+ EstimateRetryableTicket(opts *bind.TransactOpts, sender common.Address, deposit *big.Int, to common.Address, l2CallValue *big.Int, excessFeeRefundAddress common.Address, callValueRefundAddress common.Address, data []byte) (*types.Transaction, error)
+
+ GasEstimateComponents(opts *bind.TransactOpts, to common.Address, contractCreation bool, data []byte) (*types.Transaction, error)
+
+ GasEstimateL1Component(opts *bind.TransactOpts, to common.Address, contractCreation bool, data []byte) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arbitrum_gateway_router/arbitrum_gateway_router.go b/core/gethwrappers/liquiditymanager/generated/arbitrum_gateway_router/arbitrum_gateway_router.go
new file mode 100644
index 00000000000..2e16cbb7b48
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arbitrum_gateway_router/arbitrum_gateway_router.go
@@ -0,0 +1,730 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arbitrum_gateway_router
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var ArbitrumGatewayRouterMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newDefaultGateway\",\"type\":\"address\"}],\"name\":\"DefaultGatewayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"gateway\",\"type\":\"address\"}],\"name\":\"GatewaySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_userFrom\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_userTo\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"gateway\",\"type\":\"address\"}],\"name\":\"TransferRouted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1ERC20\",\"type\":\"address\"}],\"name\":\"calculateL2TokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultGateway\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"gateway\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeInboundTransfer\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"}],\"name\":\"getGateway\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"gateway\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getOutboundCalldata\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasPriceBid\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"outboundTransfer\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+}
+
+var ArbitrumGatewayRouterABI = ArbitrumGatewayRouterMetaData.ABI
+
+type ArbitrumGatewayRouter struct {
+ address common.Address
+ abi abi.ABI
+ ArbitrumGatewayRouterCaller
+ ArbitrumGatewayRouterTransactor
+ ArbitrumGatewayRouterFilterer
+}
+
+type ArbitrumGatewayRouterCaller struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumGatewayRouterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumGatewayRouterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumGatewayRouterSession struct {
+ Contract *ArbitrumGatewayRouter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumGatewayRouterCallerSession struct {
+ Contract *ArbitrumGatewayRouterCaller
+ CallOpts bind.CallOpts
+}
+
+type ArbitrumGatewayRouterTransactorSession struct {
+ Contract *ArbitrumGatewayRouterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumGatewayRouterRaw struct {
+ Contract *ArbitrumGatewayRouter
+}
+
+type ArbitrumGatewayRouterCallerRaw struct {
+ Contract *ArbitrumGatewayRouterCaller
+}
+
+type ArbitrumGatewayRouterTransactorRaw struct {
+ Contract *ArbitrumGatewayRouterTransactor
+}
+
+func NewArbitrumGatewayRouter(address common.Address, backend bind.ContractBackend) (*ArbitrumGatewayRouter, error) {
+ abi, err := abi.JSON(strings.NewReader(ArbitrumGatewayRouterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindArbitrumGatewayRouter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumGatewayRouter{address: address, abi: abi, ArbitrumGatewayRouterCaller: ArbitrumGatewayRouterCaller{contract: contract}, ArbitrumGatewayRouterTransactor: ArbitrumGatewayRouterTransactor{contract: contract}, ArbitrumGatewayRouterFilterer: ArbitrumGatewayRouterFilterer{contract: contract}}, nil
+}
+
+func NewArbitrumGatewayRouterCaller(address common.Address, caller bind.ContractCaller) (*ArbitrumGatewayRouterCaller, error) {
+ contract, err := bindArbitrumGatewayRouter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumGatewayRouterCaller{contract: contract}, nil
+}
+
+func NewArbitrumGatewayRouterTransactor(address common.Address, transactor bind.ContractTransactor) (*ArbitrumGatewayRouterTransactor, error) {
+ contract, err := bindArbitrumGatewayRouter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumGatewayRouterTransactor{contract: contract}, nil
+}
+
+func NewArbitrumGatewayRouterFilterer(address common.Address, filterer bind.ContractFilterer) (*ArbitrumGatewayRouterFilterer, error) {
+ contract, err := bindArbitrumGatewayRouter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumGatewayRouterFilterer{contract: contract}, nil
+}
+
+func bindArbitrumGatewayRouter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ArbitrumGatewayRouterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumGatewayRouter.Contract.ArbitrumGatewayRouterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.Contract.ArbitrumGatewayRouterTransactor.contract.Transfer(opts)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.Contract.ArbitrumGatewayRouterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumGatewayRouter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.Contract.contract.Transfer(opts)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCaller) CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumGatewayRouter.contract.Call(opts, &out, "calculateL2TokenAddress", l1ERC20)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterSession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _ArbitrumGatewayRouter.Contract.CalculateL2TokenAddress(&_ArbitrumGatewayRouter.CallOpts, l1ERC20)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCallerSession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _ArbitrumGatewayRouter.Contract.CalculateL2TokenAddress(&_ArbitrumGatewayRouter.CallOpts, l1ERC20)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCaller) DefaultGateway(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumGatewayRouter.contract.Call(opts, &out, "defaultGateway")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterSession) DefaultGateway() (common.Address, error) {
+ return _ArbitrumGatewayRouter.Contract.DefaultGateway(&_ArbitrumGatewayRouter.CallOpts)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCallerSession) DefaultGateway() (common.Address, error) {
+ return _ArbitrumGatewayRouter.Contract.DefaultGateway(&_ArbitrumGatewayRouter.CallOpts)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCaller) GetGateway(opts *bind.CallOpts, _token common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumGatewayRouter.contract.Call(opts, &out, "getGateway", _token)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterSession) GetGateway(_token common.Address) (common.Address, error) {
+ return _ArbitrumGatewayRouter.Contract.GetGateway(&_ArbitrumGatewayRouter.CallOpts, _token)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCallerSession) GetGateway(_token common.Address) (common.Address, error) {
+ return _ArbitrumGatewayRouter.Contract.GetGateway(&_ArbitrumGatewayRouter.CallOpts, _token)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCaller) GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ var out []interface{}
+ err := _ArbitrumGatewayRouter.contract.Call(opts, &out, "getOutboundCalldata", _token, _from, _to, _amount, _data)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterSession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _ArbitrumGatewayRouter.Contract.GetOutboundCalldata(&_ArbitrumGatewayRouter.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterCallerSession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _ArbitrumGatewayRouter.Contract.GetOutboundCalldata(&_ArbitrumGatewayRouter.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterTransactor) FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.contract.Transact(opts, "finalizeInboundTransfer", _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterSession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.Contract.FinalizeInboundTransfer(&_ArbitrumGatewayRouter.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterTransactorSession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.Contract.FinalizeInboundTransfer(&_ArbitrumGatewayRouter.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterTransactor) OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.contract.Transact(opts, "outboundTransfer", _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterSession) OutboundTransfer(_token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.Contract.OutboundTransfer(&_ArbitrumGatewayRouter.TransactOpts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterTransactorSession) OutboundTransfer(_token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumGatewayRouter.Contract.OutboundTransfer(&_ArbitrumGatewayRouter.TransactOpts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+type ArbitrumGatewayRouterDefaultGatewayUpdatedIterator struct {
+ Event *ArbitrumGatewayRouterDefaultGatewayUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbitrumGatewayRouterDefaultGatewayUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbitrumGatewayRouterDefaultGatewayUpdated)
+ 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(ArbitrumGatewayRouterDefaultGatewayUpdated)
+ 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 *ArbitrumGatewayRouterDefaultGatewayUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbitrumGatewayRouterDefaultGatewayUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbitrumGatewayRouterDefaultGatewayUpdated struct {
+ NewDefaultGateway common.Address
+ Raw types.Log
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) FilterDefaultGatewayUpdated(opts *bind.FilterOpts) (*ArbitrumGatewayRouterDefaultGatewayUpdatedIterator, error) {
+
+ logs, sub, err := _ArbitrumGatewayRouter.contract.FilterLogs(opts, "DefaultGatewayUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumGatewayRouterDefaultGatewayUpdatedIterator{contract: _ArbitrumGatewayRouter.contract, event: "DefaultGatewayUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) WatchDefaultGatewayUpdated(opts *bind.WatchOpts, sink chan<- *ArbitrumGatewayRouterDefaultGatewayUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _ArbitrumGatewayRouter.contract.WatchLogs(opts, "DefaultGatewayUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbitrumGatewayRouterDefaultGatewayUpdated)
+ if err := _ArbitrumGatewayRouter.contract.UnpackLog(event, "DefaultGatewayUpdated", 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 (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) ParseDefaultGatewayUpdated(log types.Log) (*ArbitrumGatewayRouterDefaultGatewayUpdated, error) {
+ event := new(ArbitrumGatewayRouterDefaultGatewayUpdated)
+ if err := _ArbitrumGatewayRouter.contract.UnpackLog(event, "DefaultGatewayUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbitrumGatewayRouterGatewaySetIterator struct {
+ Event *ArbitrumGatewayRouterGatewaySet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbitrumGatewayRouterGatewaySetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbitrumGatewayRouterGatewaySet)
+ 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(ArbitrumGatewayRouterGatewaySet)
+ 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 *ArbitrumGatewayRouterGatewaySetIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbitrumGatewayRouterGatewaySetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbitrumGatewayRouterGatewaySet struct {
+ L1Token common.Address
+ Gateway common.Address
+ Raw types.Log
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) FilterGatewaySet(opts *bind.FilterOpts, l1Token []common.Address, gateway []common.Address) (*ArbitrumGatewayRouterGatewaySetIterator, error) {
+
+ var l1TokenRule []interface{}
+ for _, l1TokenItem := range l1Token {
+ l1TokenRule = append(l1TokenRule, l1TokenItem)
+ }
+ var gatewayRule []interface{}
+ for _, gatewayItem := range gateway {
+ gatewayRule = append(gatewayRule, gatewayItem)
+ }
+
+ logs, sub, err := _ArbitrumGatewayRouter.contract.FilterLogs(opts, "GatewaySet", l1TokenRule, gatewayRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumGatewayRouterGatewaySetIterator{contract: _ArbitrumGatewayRouter.contract, event: "GatewaySet", logs: logs, sub: sub}, nil
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) WatchGatewaySet(opts *bind.WatchOpts, sink chan<- *ArbitrumGatewayRouterGatewaySet, l1Token []common.Address, gateway []common.Address) (event.Subscription, error) {
+
+ var l1TokenRule []interface{}
+ for _, l1TokenItem := range l1Token {
+ l1TokenRule = append(l1TokenRule, l1TokenItem)
+ }
+ var gatewayRule []interface{}
+ for _, gatewayItem := range gateway {
+ gatewayRule = append(gatewayRule, gatewayItem)
+ }
+
+ logs, sub, err := _ArbitrumGatewayRouter.contract.WatchLogs(opts, "GatewaySet", l1TokenRule, gatewayRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbitrumGatewayRouterGatewaySet)
+ if err := _ArbitrumGatewayRouter.contract.UnpackLog(event, "GatewaySet", 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 (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) ParseGatewaySet(log types.Log) (*ArbitrumGatewayRouterGatewaySet, error) {
+ event := new(ArbitrumGatewayRouterGatewaySet)
+ if err := _ArbitrumGatewayRouter.contract.UnpackLog(event, "GatewaySet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbitrumGatewayRouterTransferRoutedIterator struct {
+ Event *ArbitrumGatewayRouterTransferRouted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbitrumGatewayRouterTransferRoutedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbitrumGatewayRouterTransferRouted)
+ 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(ArbitrumGatewayRouterTransferRouted)
+ 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 *ArbitrumGatewayRouterTransferRoutedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbitrumGatewayRouterTransferRoutedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbitrumGatewayRouterTransferRouted struct {
+ Token common.Address
+ UserFrom common.Address
+ UserTo common.Address
+ Gateway common.Address
+ Raw types.Log
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) FilterTransferRouted(opts *bind.FilterOpts, token []common.Address, _userFrom []common.Address, _userTo []common.Address) (*ArbitrumGatewayRouterTransferRoutedIterator, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var _userFromRule []interface{}
+ for _, _userFromItem := range _userFrom {
+ _userFromRule = append(_userFromRule, _userFromItem)
+ }
+ var _userToRule []interface{}
+ for _, _userToItem := range _userTo {
+ _userToRule = append(_userToRule, _userToItem)
+ }
+
+ logs, sub, err := _ArbitrumGatewayRouter.contract.FilterLogs(opts, "TransferRouted", tokenRule, _userFromRule, _userToRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumGatewayRouterTransferRoutedIterator{contract: _ArbitrumGatewayRouter.contract, event: "TransferRouted", logs: logs, sub: sub}, nil
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) WatchTransferRouted(opts *bind.WatchOpts, sink chan<- *ArbitrumGatewayRouterTransferRouted, token []common.Address, _userFrom []common.Address, _userTo []common.Address) (event.Subscription, error) {
+
+ var tokenRule []interface{}
+ for _, tokenItem := range token {
+ tokenRule = append(tokenRule, tokenItem)
+ }
+ var _userFromRule []interface{}
+ for _, _userFromItem := range _userFrom {
+ _userFromRule = append(_userFromRule, _userFromItem)
+ }
+ var _userToRule []interface{}
+ for _, _userToItem := range _userTo {
+ _userToRule = append(_userToRule, _userToItem)
+ }
+
+ logs, sub, err := _ArbitrumGatewayRouter.contract.WatchLogs(opts, "TransferRouted", tokenRule, _userFromRule, _userToRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbitrumGatewayRouterTransferRouted)
+ if err := _ArbitrumGatewayRouter.contract.UnpackLog(event, "TransferRouted", 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 (_ArbitrumGatewayRouter *ArbitrumGatewayRouterFilterer) ParseTransferRouted(log types.Log) (*ArbitrumGatewayRouterTransferRouted, error) {
+ event := new(ArbitrumGatewayRouterTransferRouted)
+ if err := _ArbitrumGatewayRouter.contract.UnpackLog(event, "TransferRouted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouter) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _ArbitrumGatewayRouter.abi.Events["DefaultGatewayUpdated"].ID:
+ return _ArbitrumGatewayRouter.ParseDefaultGatewayUpdated(log)
+ case _ArbitrumGatewayRouter.abi.Events["GatewaySet"].ID:
+ return _ArbitrumGatewayRouter.ParseGatewaySet(log)
+ case _ArbitrumGatewayRouter.abi.Events["TransferRouted"].ID:
+ return _ArbitrumGatewayRouter.ParseTransferRouted(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (ArbitrumGatewayRouterDefaultGatewayUpdated) Topic() common.Hash {
+ return common.HexToHash("0x3a8f8eb961383a94d41d193e16a3af73eaddfd5764a4c640257323a1603ac331")
+}
+
+func (ArbitrumGatewayRouterGatewaySet) Topic() common.Hash {
+ return common.HexToHash("0x812ca95fe4492a9e2d1f2723c2c40c03a60a27b059581ae20ac4e4d73bfba354")
+}
+
+func (ArbitrumGatewayRouterTransferRouted) Topic() common.Hash {
+ return common.HexToHash("0x85291dff2161a93c2f12c819d31889c96c63042116f5bc5a205aa701c2c429f5")
+}
+
+func (_ArbitrumGatewayRouter *ArbitrumGatewayRouter) Address() common.Address {
+ return _ArbitrumGatewayRouter.address
+}
+
+type ArbitrumGatewayRouterInterface interface {
+ CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error)
+
+ DefaultGateway(opts *bind.CallOpts) (common.Address, error)
+
+ GetGateway(opts *bind.CallOpts, _token common.Address) (common.Address, error)
+
+ GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error)
+
+ FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error)
+
+ OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error)
+
+ FilterDefaultGatewayUpdated(opts *bind.FilterOpts) (*ArbitrumGatewayRouterDefaultGatewayUpdatedIterator, error)
+
+ WatchDefaultGatewayUpdated(opts *bind.WatchOpts, sink chan<- *ArbitrumGatewayRouterDefaultGatewayUpdated) (event.Subscription, error)
+
+ ParseDefaultGatewayUpdated(log types.Log) (*ArbitrumGatewayRouterDefaultGatewayUpdated, error)
+
+ FilterGatewaySet(opts *bind.FilterOpts, l1Token []common.Address, gateway []common.Address) (*ArbitrumGatewayRouterGatewaySetIterator, error)
+
+ WatchGatewaySet(opts *bind.WatchOpts, sink chan<- *ArbitrumGatewayRouterGatewaySet, l1Token []common.Address, gateway []common.Address) (event.Subscription, error)
+
+ ParseGatewaySet(log types.Log) (*ArbitrumGatewayRouterGatewaySet, error)
+
+ FilterTransferRouted(opts *bind.FilterOpts, token []common.Address, _userFrom []common.Address, _userTo []common.Address) (*ArbitrumGatewayRouterTransferRoutedIterator, error)
+
+ WatchTransferRouted(opts *bind.WatchOpts, sink chan<- *ArbitrumGatewayRouterTransferRouted, token []common.Address, _userFrom []common.Address, _userTo []common.Address) (event.Subscription, error)
+
+ ParseTransferRouted(log types.Log) (*ArbitrumGatewayRouterTransferRouted, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arbitrum_inbox/arbitrum_inbox.go b/core/gethwrappers/liquiditymanager/generated/arbitrum_inbox/arbitrum_inbox.go
new file mode 100644
index 00000000000..4632ae6ba72
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arbitrum_inbox/arbitrum_inbox.go
@@ -0,0 +1,744 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arbitrum_inbox
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var ArbitrumInboxMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"InboxMessageDelivered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"messageNum\",\"type\":\"uint256\"}],\"name\":\"InboxMessageDeliveredFromOrigin\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"allowListEnabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"bridge\",\"outputs\":[{\"internalType\":\"contractIBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"dataLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"baseFee\",\"type\":\"uint256\"}],\"name\":\"calculateRetryableSubmissionFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProxyAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIBridge\",\"name\":\"_bridge\",\"type\":\"address\"},{\"internalType\":\"contractISequencerInbox\",\"name\":\"_sequencerInbox\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"isAllowed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxDataSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"sendContractTransaction\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"messageData\",\"type\":\"bytes\"}],\"name\":\"sendL2Message\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"messageData\",\"type\":\"bytes\"}],\"name\":\"sendL2MessageFromOrigin\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"sendUnsignedTransaction\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sequencerInbox\",\"outputs\":[{\"internalType\":\"contractISequencerInbox\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"user\",\"type\":\"address[]\"},{\"internalType\":\"bool[]\",\"name\":\"val\",\"type\":\"bool[]\"}],\"name\":\"setAllowList\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"_allowListEnabled\",\"type\":\"bool\"}],\"name\":\"setAllowListEnabled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+}
+
+var ArbitrumInboxABI = ArbitrumInboxMetaData.ABI
+
+type ArbitrumInbox struct {
+ address common.Address
+ abi abi.ABI
+ ArbitrumInboxCaller
+ ArbitrumInboxTransactor
+ ArbitrumInboxFilterer
+}
+
+type ArbitrumInboxCaller struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumInboxTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumInboxFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumInboxSession struct {
+ Contract *ArbitrumInbox
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumInboxCallerSession struct {
+ Contract *ArbitrumInboxCaller
+ CallOpts bind.CallOpts
+}
+
+type ArbitrumInboxTransactorSession struct {
+ Contract *ArbitrumInboxTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumInboxRaw struct {
+ Contract *ArbitrumInbox
+}
+
+type ArbitrumInboxCallerRaw struct {
+ Contract *ArbitrumInboxCaller
+}
+
+type ArbitrumInboxTransactorRaw struct {
+ Contract *ArbitrumInboxTransactor
+}
+
+func NewArbitrumInbox(address common.Address, backend bind.ContractBackend) (*ArbitrumInbox, error) {
+ abi, err := abi.JSON(strings.NewReader(ArbitrumInboxABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindArbitrumInbox(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumInbox{address: address, abi: abi, ArbitrumInboxCaller: ArbitrumInboxCaller{contract: contract}, ArbitrumInboxTransactor: ArbitrumInboxTransactor{contract: contract}, ArbitrumInboxFilterer: ArbitrumInboxFilterer{contract: contract}}, nil
+}
+
+func NewArbitrumInboxCaller(address common.Address, caller bind.ContractCaller) (*ArbitrumInboxCaller, error) {
+ contract, err := bindArbitrumInbox(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumInboxCaller{contract: contract}, nil
+}
+
+func NewArbitrumInboxTransactor(address common.Address, transactor bind.ContractTransactor) (*ArbitrumInboxTransactor, error) {
+ contract, err := bindArbitrumInbox(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumInboxTransactor{contract: contract}, nil
+}
+
+func NewArbitrumInboxFilterer(address common.Address, filterer bind.ContractFilterer) (*ArbitrumInboxFilterer, error) {
+ contract, err := bindArbitrumInbox(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumInboxFilterer{contract: contract}, nil
+}
+
+func bindArbitrumInbox(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ArbitrumInboxMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ArbitrumInbox *ArbitrumInboxRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumInbox.Contract.ArbitrumInboxCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.ArbitrumInboxTransactor.contract.Transfer(opts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.ArbitrumInboxTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumInbox.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.contract.Transfer(opts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCaller) AllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _ArbitrumInbox.contract.Call(opts, &out, "allowListEnabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) AllowListEnabled() (bool, error) {
+ return _ArbitrumInbox.Contract.AllowListEnabled(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCallerSession) AllowListEnabled() (bool, error) {
+ return _ArbitrumInbox.Contract.AllowListEnabled(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCaller) Bridge(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumInbox.contract.Call(opts, &out, "bridge")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) Bridge() (common.Address, error) {
+ return _ArbitrumInbox.Contract.Bridge(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCallerSession) Bridge() (common.Address, error) {
+ return _ArbitrumInbox.Contract.Bridge(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCaller) CalculateRetryableSubmissionFee(opts *bind.CallOpts, dataLength *big.Int, baseFee *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbitrumInbox.contract.Call(opts, &out, "calculateRetryableSubmissionFee", dataLength, baseFee)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) CalculateRetryableSubmissionFee(dataLength *big.Int, baseFee *big.Int) (*big.Int, error) {
+ return _ArbitrumInbox.Contract.CalculateRetryableSubmissionFee(&_ArbitrumInbox.CallOpts, dataLength, baseFee)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCallerSession) CalculateRetryableSubmissionFee(dataLength *big.Int, baseFee *big.Int) (*big.Int, error) {
+ return _ArbitrumInbox.Contract.CalculateRetryableSubmissionFee(&_ArbitrumInbox.CallOpts, dataLength, baseFee)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCaller) GetProxyAdmin(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumInbox.contract.Call(opts, &out, "getProxyAdmin")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) GetProxyAdmin() (common.Address, error) {
+ return _ArbitrumInbox.Contract.GetProxyAdmin(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCallerSession) GetProxyAdmin() (common.Address, error) {
+ return _ArbitrumInbox.Contract.GetProxyAdmin(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCaller) IsAllowed(opts *bind.CallOpts, user common.Address) (bool, error) {
+ var out []interface{}
+ err := _ArbitrumInbox.contract.Call(opts, &out, "isAllowed", user)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) IsAllowed(user common.Address) (bool, error) {
+ return _ArbitrumInbox.Contract.IsAllowed(&_ArbitrumInbox.CallOpts, user)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCallerSession) IsAllowed(user common.Address) (bool, error) {
+ return _ArbitrumInbox.Contract.IsAllowed(&_ArbitrumInbox.CallOpts, user)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCaller) MaxDataSize(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbitrumInbox.contract.Call(opts, &out, "maxDataSize")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) MaxDataSize() (*big.Int, error) {
+ return _ArbitrumInbox.Contract.MaxDataSize(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCallerSession) MaxDataSize() (*big.Int, error) {
+ return _ArbitrumInbox.Contract.MaxDataSize(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCaller) SequencerInbox(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumInbox.contract.Call(opts, &out, "sequencerInbox")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) SequencerInbox() (common.Address, error) {
+ return _ArbitrumInbox.Contract.SequencerInbox(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxCallerSession) SequencerInbox() (common.Address, error) {
+ return _ArbitrumInbox.Contract.SequencerInbox(&_ArbitrumInbox.CallOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) Initialize(opts *bind.TransactOpts, _bridge common.Address, _sequencerInbox common.Address) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "initialize", _bridge, _sequencerInbox)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) Initialize(_bridge common.Address, _sequencerInbox common.Address) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.Initialize(&_ArbitrumInbox.TransactOpts, _bridge, _sequencerInbox)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) Initialize(_bridge common.Address, _sequencerInbox common.Address) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.Initialize(&_ArbitrumInbox.TransactOpts, _bridge, _sequencerInbox)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "pause")
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) Pause() (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.Pause(&_ArbitrumInbox.TransactOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) Pause() (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.Pause(&_ArbitrumInbox.TransactOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) SendContractTransaction(opts *bind.TransactOpts, gasLimit *big.Int, maxFeePerGas *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "sendContractTransaction", gasLimit, maxFeePerGas, to, value, data)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) SendContractTransaction(gasLimit *big.Int, maxFeePerGas *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SendContractTransaction(&_ArbitrumInbox.TransactOpts, gasLimit, maxFeePerGas, to, value, data)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) SendContractTransaction(gasLimit *big.Int, maxFeePerGas *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SendContractTransaction(&_ArbitrumInbox.TransactOpts, gasLimit, maxFeePerGas, to, value, data)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) SendL2Message(opts *bind.TransactOpts, messageData []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "sendL2Message", messageData)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) SendL2Message(messageData []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SendL2Message(&_ArbitrumInbox.TransactOpts, messageData)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) SendL2Message(messageData []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SendL2Message(&_ArbitrumInbox.TransactOpts, messageData)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) SendL2MessageFromOrigin(opts *bind.TransactOpts, messageData []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "sendL2MessageFromOrigin", messageData)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) SendL2MessageFromOrigin(messageData []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SendL2MessageFromOrigin(&_ArbitrumInbox.TransactOpts, messageData)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) SendL2MessageFromOrigin(messageData []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SendL2MessageFromOrigin(&_ArbitrumInbox.TransactOpts, messageData)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) SendUnsignedTransaction(opts *bind.TransactOpts, gasLimit *big.Int, maxFeePerGas *big.Int, nonce *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "sendUnsignedTransaction", gasLimit, maxFeePerGas, nonce, to, value, data)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) SendUnsignedTransaction(gasLimit *big.Int, maxFeePerGas *big.Int, nonce *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SendUnsignedTransaction(&_ArbitrumInbox.TransactOpts, gasLimit, maxFeePerGas, nonce, to, value, data)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) SendUnsignedTransaction(gasLimit *big.Int, maxFeePerGas *big.Int, nonce *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SendUnsignedTransaction(&_ArbitrumInbox.TransactOpts, gasLimit, maxFeePerGas, nonce, to, value, data)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) SetAllowList(opts *bind.TransactOpts, user []common.Address, val []bool) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "setAllowList", user, val)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) SetAllowList(user []common.Address, val []bool) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SetAllowList(&_ArbitrumInbox.TransactOpts, user, val)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) SetAllowList(user []common.Address, val []bool) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SetAllowList(&_ArbitrumInbox.TransactOpts, user, val)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) SetAllowListEnabled(opts *bind.TransactOpts, _allowListEnabled bool) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "setAllowListEnabled", _allowListEnabled)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) SetAllowListEnabled(_allowListEnabled bool) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SetAllowListEnabled(&_ArbitrumInbox.TransactOpts, _allowListEnabled)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) SetAllowListEnabled(_allowListEnabled bool) (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.SetAllowListEnabled(&_ArbitrumInbox.TransactOpts, _allowListEnabled)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumInbox.contract.Transact(opts, "unpause")
+}
+
+func (_ArbitrumInbox *ArbitrumInboxSession) Unpause() (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.Unpause(&_ArbitrumInbox.TransactOpts)
+}
+
+func (_ArbitrumInbox *ArbitrumInboxTransactorSession) Unpause() (*types.Transaction, error) {
+ return _ArbitrumInbox.Contract.Unpause(&_ArbitrumInbox.TransactOpts)
+}
+
+type ArbitrumInboxInboxMessageDeliveredIterator struct {
+ Event *ArbitrumInboxInboxMessageDelivered
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbitrumInboxInboxMessageDeliveredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbitrumInboxInboxMessageDelivered)
+ 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(ArbitrumInboxInboxMessageDelivered)
+ 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 *ArbitrumInboxInboxMessageDeliveredIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbitrumInboxInboxMessageDeliveredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbitrumInboxInboxMessageDelivered struct {
+ MessageNum *big.Int
+ Data []byte
+ Raw types.Log
+}
+
+func (_ArbitrumInbox *ArbitrumInboxFilterer) FilterInboxMessageDelivered(opts *bind.FilterOpts, messageNum []*big.Int) (*ArbitrumInboxInboxMessageDeliveredIterator, error) {
+
+ var messageNumRule []interface{}
+ for _, messageNumItem := range messageNum {
+ messageNumRule = append(messageNumRule, messageNumItem)
+ }
+
+ logs, sub, err := _ArbitrumInbox.contract.FilterLogs(opts, "InboxMessageDelivered", messageNumRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumInboxInboxMessageDeliveredIterator{contract: _ArbitrumInbox.contract, event: "InboxMessageDelivered", logs: logs, sub: sub}, nil
+}
+
+func (_ArbitrumInbox *ArbitrumInboxFilterer) WatchInboxMessageDelivered(opts *bind.WatchOpts, sink chan<- *ArbitrumInboxInboxMessageDelivered, messageNum []*big.Int) (event.Subscription, error) {
+
+ var messageNumRule []interface{}
+ for _, messageNumItem := range messageNum {
+ messageNumRule = append(messageNumRule, messageNumItem)
+ }
+
+ logs, sub, err := _ArbitrumInbox.contract.WatchLogs(opts, "InboxMessageDelivered", messageNumRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbitrumInboxInboxMessageDelivered)
+ if err := _ArbitrumInbox.contract.UnpackLog(event, "InboxMessageDelivered", 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 (_ArbitrumInbox *ArbitrumInboxFilterer) ParseInboxMessageDelivered(log types.Log) (*ArbitrumInboxInboxMessageDelivered, error) {
+ event := new(ArbitrumInboxInboxMessageDelivered)
+ if err := _ArbitrumInbox.contract.UnpackLog(event, "InboxMessageDelivered", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbitrumInboxInboxMessageDeliveredFromOriginIterator struct {
+ Event *ArbitrumInboxInboxMessageDeliveredFromOrigin
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbitrumInboxInboxMessageDeliveredFromOriginIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbitrumInboxInboxMessageDeliveredFromOrigin)
+ 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(ArbitrumInboxInboxMessageDeliveredFromOrigin)
+ 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 *ArbitrumInboxInboxMessageDeliveredFromOriginIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbitrumInboxInboxMessageDeliveredFromOriginIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbitrumInboxInboxMessageDeliveredFromOrigin struct {
+ MessageNum *big.Int
+ Raw types.Log
+}
+
+func (_ArbitrumInbox *ArbitrumInboxFilterer) FilterInboxMessageDeliveredFromOrigin(opts *bind.FilterOpts, messageNum []*big.Int) (*ArbitrumInboxInboxMessageDeliveredFromOriginIterator, error) {
+
+ var messageNumRule []interface{}
+ for _, messageNumItem := range messageNum {
+ messageNumRule = append(messageNumRule, messageNumItem)
+ }
+
+ logs, sub, err := _ArbitrumInbox.contract.FilterLogs(opts, "InboxMessageDeliveredFromOrigin", messageNumRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumInboxInboxMessageDeliveredFromOriginIterator{contract: _ArbitrumInbox.contract, event: "InboxMessageDeliveredFromOrigin", logs: logs, sub: sub}, nil
+}
+
+func (_ArbitrumInbox *ArbitrumInboxFilterer) WatchInboxMessageDeliveredFromOrigin(opts *bind.WatchOpts, sink chan<- *ArbitrumInboxInboxMessageDeliveredFromOrigin, messageNum []*big.Int) (event.Subscription, error) {
+
+ var messageNumRule []interface{}
+ for _, messageNumItem := range messageNum {
+ messageNumRule = append(messageNumRule, messageNumItem)
+ }
+
+ logs, sub, err := _ArbitrumInbox.contract.WatchLogs(opts, "InboxMessageDeliveredFromOrigin", messageNumRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbitrumInboxInboxMessageDeliveredFromOrigin)
+ if err := _ArbitrumInbox.contract.UnpackLog(event, "InboxMessageDeliveredFromOrigin", 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 (_ArbitrumInbox *ArbitrumInboxFilterer) ParseInboxMessageDeliveredFromOrigin(log types.Log) (*ArbitrumInboxInboxMessageDeliveredFromOrigin, error) {
+ event := new(ArbitrumInboxInboxMessageDeliveredFromOrigin)
+ if err := _ArbitrumInbox.contract.UnpackLog(event, "InboxMessageDeliveredFromOrigin", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_ArbitrumInbox *ArbitrumInbox) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _ArbitrumInbox.abi.Events["InboxMessageDelivered"].ID:
+ return _ArbitrumInbox.ParseInboxMessageDelivered(log)
+ case _ArbitrumInbox.abi.Events["InboxMessageDeliveredFromOrigin"].ID:
+ return _ArbitrumInbox.ParseInboxMessageDeliveredFromOrigin(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (ArbitrumInboxInboxMessageDelivered) Topic() common.Hash {
+ return common.HexToHash("0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b")
+}
+
+func (ArbitrumInboxInboxMessageDeliveredFromOrigin) Topic() common.Hash {
+ return common.HexToHash("0xab532385be8f1005a4b6ba8fa20a2245facb346134ac739fe9a5198dc1580b9c")
+}
+
+func (_ArbitrumInbox *ArbitrumInbox) Address() common.Address {
+ return _ArbitrumInbox.address
+}
+
+type ArbitrumInboxInterface interface {
+ AllowListEnabled(opts *bind.CallOpts) (bool, error)
+
+ Bridge(opts *bind.CallOpts) (common.Address, error)
+
+ CalculateRetryableSubmissionFee(opts *bind.CallOpts, dataLength *big.Int, baseFee *big.Int) (*big.Int, error)
+
+ GetProxyAdmin(opts *bind.CallOpts) (common.Address, error)
+
+ IsAllowed(opts *bind.CallOpts, user common.Address) (bool, error)
+
+ MaxDataSize(opts *bind.CallOpts) (*big.Int, error)
+
+ SequencerInbox(opts *bind.CallOpts) (common.Address, error)
+
+ Initialize(opts *bind.TransactOpts, _bridge common.Address, _sequencerInbox common.Address) (*types.Transaction, error)
+
+ Pause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SendContractTransaction(opts *bind.TransactOpts, gasLimit *big.Int, maxFeePerGas *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error)
+
+ SendL2Message(opts *bind.TransactOpts, messageData []byte) (*types.Transaction, error)
+
+ SendL2MessageFromOrigin(opts *bind.TransactOpts, messageData []byte) (*types.Transaction, error)
+
+ SendUnsignedTransaction(opts *bind.TransactOpts, gasLimit *big.Int, maxFeePerGas *big.Int, nonce *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error)
+
+ SetAllowList(opts *bind.TransactOpts, user []common.Address, val []bool) (*types.Transaction, error)
+
+ SetAllowListEnabled(opts *bind.TransactOpts, _allowListEnabled bool) (*types.Transaction, error)
+
+ Unpause(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterInboxMessageDelivered(opts *bind.FilterOpts, messageNum []*big.Int) (*ArbitrumInboxInboxMessageDeliveredIterator, error)
+
+ WatchInboxMessageDelivered(opts *bind.WatchOpts, sink chan<- *ArbitrumInboxInboxMessageDelivered, messageNum []*big.Int) (event.Subscription, error)
+
+ ParseInboxMessageDelivered(log types.Log) (*ArbitrumInboxInboxMessageDelivered, error)
+
+ FilterInboxMessageDeliveredFromOrigin(opts *bind.FilterOpts, messageNum []*big.Int) (*ArbitrumInboxInboxMessageDeliveredFromOriginIterator, error)
+
+ WatchInboxMessageDeliveredFromOrigin(opts *bind.WatchOpts, sink chan<- *ArbitrumInboxInboxMessageDeliveredFromOrigin, messageNum []*big.Int) (event.Subscription, error)
+
+ ParseInboxMessageDeliveredFromOrigin(log types.Log) (*ArbitrumInboxInboxMessageDeliveredFromOrigin, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arbitrum_l1_bridge_adapter/arbitrum_l1_bridge_adapter.go b/core/gethwrappers/liquiditymanager/generated/arbitrum_l1_bridge_adapter/arbitrum_l1_bridge_adapter.go
new file mode 100644
index 00000000000..d0ddb797f18
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arbitrum_l1_bridge_adapter/arbitrum_l1_bridge_adapter.go
@@ -0,0 +1,316 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arbitrum_l1_bridge_adapter
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ArbitrumL1BridgeAdapterArbitrumFinalizationPayload struct {
+ Proof [][32]byte
+ Index *big.Int
+ L2Sender common.Address
+ To common.Address
+ L2Block *big.Int
+ L1Block *big.Int
+ L2Timestamp *big.Int
+ Value *big.Int
+ Data []byte
+}
+
+type ArbitrumL1BridgeAdapterSendERC20Params struct {
+ GasLimit *big.Int
+ MaxSubmissionCost *big.Int
+ MaxFeePerGas *big.Int
+}
+
+var ArbitrumL1BridgeAdapterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIL1GatewayRouter\",\"name\":\"l1GatewayRouter\",\"type\":\"address\"},{\"internalType\":\"contractIOutbox\",\"name\":\"l1Outbox\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BridgeAddressCannotBeZero\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wanted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"}],\"name\":\"InsufficientEthValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"MsgShouldNotContainValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"msgValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"MsgValueDoesNotMatchAmount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"NoGatewayForToken\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unimplemented\",\"type\":\"error\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"l2Sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"l2Block\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"l1Block\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"l2Timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structArbitrumL1BridgeAdapter.ArbitrumFinalizationPayload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"name\":\"exposeArbitrumFinalizationPayload\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxSubmissionCost\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeePerGas\",\"type\":\"uint256\"}],\"internalType\":\"structArbitrumL1BridgeAdapter.SendERC20Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"exposeSendERC20Params\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"arbitrumFinalizationPayload\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBridgeFeeInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"}],\"name\":\"getL2Token\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"bridgeSpecificPayload\",\"type\":\"bytes\"}],\"name\":\"sendERC20\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+ Bin: "0x60c060405234801561001057600080fd5b50604051620013c0380380620013c08339810160408190526100319161009b565b6001600160a01b038216158061004e57506001600160a01b038116155b1561006c57604051635e9c404d60e11b815260040160405180910390fd5b6001600160a01b039182166080521660a0526100d5565b6001600160a01b038116811461009857600080fd5b50565b600080604083850312156100ae57600080fd5b82516100b981610083565b60208401519092506100ca81610083565b809150509250929050565b60805160a0516112b76200010960003960006102100152600081816102f90152818161047101526105cd01526112b76000f3fe6080604052600436106100655760003560e01c8063b5399c9e11610043578063b5399c9e146100e2578063c7665dd214610102578063c985069c1461011d57600080fd5b80632e4b1fc91461006a57806338314bb214610092578063a71d98b7146100c2575b600080fd5b34801561007657600080fd5b5061007f610162565b6040519081526020015b60405180910390f35b34801561009e57600080fd5b506100b26100ad366004610ba1565b610196565b6040519015158152602001610089565b6100d56100d0366004610c06565b61028d565b6040516100899190610cf9565b3480156100ee57600080fd5b506101006100fd366004610dbb565b50565b005b34801561010e57600080fd5b506101006100fd366004610f28565b34801561012957600080fd5b5061013d610138366004611012565b610585565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610089565b60006040517f6e12839900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806101a583850185610f28565b805160208201516040808401516060850151608086015160a087015160c088015160e08901516101008a015196517f08635a95000000000000000000000000000000000000000000000000000000008152999a5073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016996308635a959961024d999098909796959493929160040161102f565b600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b5050505060019150505b949350505050565b60606102b173ffffffffffffffffffffffffffffffffffffffff8816333087610640565b6040517fbda009fe00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063bda009fe90602401602060405180830381865afa158015610342573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061036691906110ed565b905073ffffffffffffffffffffffffffffffffffffffff81166103d2576040517f6c1460f400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff891660048201526024015b60405180910390fd5b6103f373ffffffffffffffffffffffffffffffffffffffff89168287610722565b600061040184860186610dbb565b9050600081602001518260400151836000015161041e9190611139565b6104289190611150565b90508034101561046d576040517f03da4d23000000000000000000000000000000000000000000000000000000008152346004820152602481018290526044016103c9565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634fb1a07b348d8c8d8d89600001518a604001518b60200151604051806020016040528060008152506040516020016104e0929190611163565b6040516020818303038152906040526040518963ffffffff1660e01b8152600401610511979695949392919061117c565b60006040518083038185885af115801561052f573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261057691908101906111dc565b9b9a5050505050505050505050565b6040517fa7e28d4800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063a7e28d4890602401602060405180830381865afa158015610616573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061063a91906110ed565b92915050565b60405173ffffffffffffffffffffffffffffffffffffffff8085166024830152831660448201526064810182905261071c9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526108a9565b50505050565b8015806107c257506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561079c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c09190611253565b155b61084e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084016103c9565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526108a49084907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161069a565b505050565b600061090b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166109b59092919063ffffffff16565b8051909150156108a45780806020019051810190610929919061126c565b6108a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016103c9565b60606102858484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516109e9919061128e565b60006040518083038185875af1925050503d8060008114610a26576040519150601f19603f3d011682016040523d82523d6000602084013e610a2b565b606091505b5091509150610a3c87838387610a47565b979650505050505050565b60608315610add578251600003610ad65773ffffffffffffffffffffffffffffffffffffffff85163b610ad6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103c9565b5081610285565b6102858383815115610af25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103c99190610cf9565b73ffffffffffffffffffffffffffffffffffffffff811681146100fd57600080fd5b8035610b5381610b26565b919050565b60008083601f840112610b6a57600080fd5b50813567ffffffffffffffff811115610b8257600080fd5b602083019150836020828501011115610b9a57600080fd5b9250929050565b60008060008060608587031215610bb757600080fd5b8435610bc281610b26565b93506020850135610bd281610b26565b9250604085013567ffffffffffffffff811115610bee57600080fd5b610bfa87828801610b58565b95989497509550505050565b60008060008060008060a08789031215610c1f57600080fd5b8635610c2a81610b26565b95506020870135610c3a81610b26565b94506040870135610c4a81610b26565b935060608701359250608087013567ffffffffffffffff811115610c6d57600080fd5b610c7989828a01610b58565b979a9699509497509295939492505050565b60005b83811015610ca6578181015183820152602001610c8e565b50506000910152565b60008151808452610cc7816020860160208601610c8b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610d0c6020830184610caf565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715610d6657610d66610d13565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610db357610db3610d13565b604052919050565b600060608284031215610dcd57600080fd5b6040516060810181811067ffffffffffffffff82111715610df057610df0610d13565b80604052508235815260208301356020820152604083013560408201528091505092915050565b600082601f830112610e2857600080fd5b8135602067ffffffffffffffff821115610e4457610e44610d13565b8160051b610e53828201610d6c565b9283528481018201928281019087851115610e6d57600080fd5b83870192505b84831015610a3c57823582529183019190830190610e73565b600067ffffffffffffffff821115610ea657610ea6610d13565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112610ee357600080fd5b8135610ef6610ef182610e8c565b610d6c565b818152846020838601011115610f0b57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215610f3a57600080fd5b813567ffffffffffffffff80821115610f5257600080fd5b908301906101208286031215610f6757600080fd5b610f6f610d42565b823582811115610f7e57600080fd5b610f8a87828601610e17565b82525060208301356020820152610fa360408401610b48565b6040820152610fb460608401610b48565b60608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013583811115610ff557600080fd5b61100188828701610ed2565b918301919091525095945050505050565b60006020828403121561102457600080fd5b8135610d0c81610b26565b6101208082528a51908201819052600090610140830190602090818e01845b8281101561106a5781518552938301939083019060010161104e565b505050508a6020840152611096604084018b73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff891660608401528760808401528660a08401528560c08401528460e08401528281036101008401526110dd8185610caf565b9c9b505050505050505050505050565b6000602082840312156110ff57600080fd5b8151610d0c81610b26565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761063a5761063a61110a565b8082018082111561063a5761063a61110a565b8281526040602082015260006102856040830184610caf565b600073ffffffffffffffffffffffffffffffffffffffff808a16835280891660208401528088166040840152508560608301528460808301528360a083015260e060c08301526111cf60e0830184610caf565b9998505050505050505050565b6000602082840312156111ee57600080fd5b815167ffffffffffffffff81111561120557600080fd5b8201601f8101841361121657600080fd5b8051611224610ef182610e8c565b81815285602083850101111561123957600080fd5b61124a826020830160208601610c8b565b95945050505050565b60006020828403121561126557600080fd5b5051919050565b60006020828403121561127e57600080fd5b81518015158114610d0c57600080fd5b600082516112a0818460208701610c8b565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var ArbitrumL1BridgeAdapterABI = ArbitrumL1BridgeAdapterMetaData.ABI
+
+var ArbitrumL1BridgeAdapterBin = ArbitrumL1BridgeAdapterMetaData.Bin
+
+func DeployArbitrumL1BridgeAdapter(auth *bind.TransactOpts, backend bind.ContractBackend, l1GatewayRouter common.Address, l1Outbox common.Address) (common.Address, *types.Transaction, *ArbitrumL1BridgeAdapter, error) {
+ parsed, err := ArbitrumL1BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ArbitrumL1BridgeAdapterBin), backend, l1GatewayRouter, l1Outbox)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &ArbitrumL1BridgeAdapter{address: address, abi: *parsed, ArbitrumL1BridgeAdapterCaller: ArbitrumL1BridgeAdapterCaller{contract: contract}, ArbitrumL1BridgeAdapterTransactor: ArbitrumL1BridgeAdapterTransactor{contract: contract}, ArbitrumL1BridgeAdapterFilterer: ArbitrumL1BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+type ArbitrumL1BridgeAdapter struct {
+ address common.Address
+ abi abi.ABI
+ ArbitrumL1BridgeAdapterCaller
+ ArbitrumL1BridgeAdapterTransactor
+ ArbitrumL1BridgeAdapterFilterer
+}
+
+type ArbitrumL1BridgeAdapterCaller struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL1BridgeAdapterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL1BridgeAdapterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL1BridgeAdapterSession struct {
+ Contract *ArbitrumL1BridgeAdapter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumL1BridgeAdapterCallerSession struct {
+ Contract *ArbitrumL1BridgeAdapterCaller
+ CallOpts bind.CallOpts
+}
+
+type ArbitrumL1BridgeAdapterTransactorSession struct {
+ Contract *ArbitrumL1BridgeAdapterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumL1BridgeAdapterRaw struct {
+ Contract *ArbitrumL1BridgeAdapter
+}
+
+type ArbitrumL1BridgeAdapterCallerRaw struct {
+ Contract *ArbitrumL1BridgeAdapterCaller
+}
+
+type ArbitrumL1BridgeAdapterTransactorRaw struct {
+ Contract *ArbitrumL1BridgeAdapterTransactor
+}
+
+func NewArbitrumL1BridgeAdapter(address common.Address, backend bind.ContractBackend) (*ArbitrumL1BridgeAdapter, error) {
+ abi, err := abi.JSON(strings.NewReader(ArbitrumL1BridgeAdapterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindArbitrumL1BridgeAdapter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL1BridgeAdapter{address: address, abi: abi, ArbitrumL1BridgeAdapterCaller: ArbitrumL1BridgeAdapterCaller{contract: contract}, ArbitrumL1BridgeAdapterTransactor: ArbitrumL1BridgeAdapterTransactor{contract: contract}, ArbitrumL1BridgeAdapterFilterer: ArbitrumL1BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+func NewArbitrumL1BridgeAdapterCaller(address common.Address, caller bind.ContractCaller) (*ArbitrumL1BridgeAdapterCaller, error) {
+ contract, err := bindArbitrumL1BridgeAdapter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL1BridgeAdapterCaller{contract: contract}, nil
+}
+
+func NewArbitrumL1BridgeAdapterTransactor(address common.Address, transactor bind.ContractTransactor) (*ArbitrumL1BridgeAdapterTransactor, error) {
+ contract, err := bindArbitrumL1BridgeAdapter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL1BridgeAdapterTransactor{contract: contract}, nil
+}
+
+func NewArbitrumL1BridgeAdapterFilterer(address common.Address, filterer bind.ContractFilterer) (*ArbitrumL1BridgeAdapterFilterer, error) {
+ contract, err := bindArbitrumL1BridgeAdapter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL1BridgeAdapterFilterer{contract: contract}, nil
+}
+
+func bindArbitrumL1BridgeAdapter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ArbitrumL1BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumL1BridgeAdapter.Contract.ArbitrumL1BridgeAdapterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.ArbitrumL1BridgeAdapterTransactor.contract.Transfer(opts)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.ArbitrumL1BridgeAdapterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumL1BridgeAdapter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.contract.Transfer(opts)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCaller) ExposeArbitrumFinalizationPayload(opts *bind.CallOpts, payload ArbitrumL1BridgeAdapterArbitrumFinalizationPayload) error {
+ var out []interface{}
+ err := _ArbitrumL1BridgeAdapter.contract.Call(opts, &out, "exposeArbitrumFinalizationPayload", payload)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterSession) ExposeArbitrumFinalizationPayload(payload ArbitrumL1BridgeAdapterArbitrumFinalizationPayload) error {
+ return _ArbitrumL1BridgeAdapter.Contract.ExposeArbitrumFinalizationPayload(&_ArbitrumL1BridgeAdapter.CallOpts, payload)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCallerSession) ExposeArbitrumFinalizationPayload(payload ArbitrumL1BridgeAdapterArbitrumFinalizationPayload) error {
+ return _ArbitrumL1BridgeAdapter.Contract.ExposeArbitrumFinalizationPayload(&_ArbitrumL1BridgeAdapter.CallOpts, payload)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCaller) ExposeSendERC20Params(opts *bind.CallOpts, params ArbitrumL1BridgeAdapterSendERC20Params) error {
+ var out []interface{}
+ err := _ArbitrumL1BridgeAdapter.contract.Call(opts, &out, "exposeSendERC20Params", params)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterSession) ExposeSendERC20Params(params ArbitrumL1BridgeAdapterSendERC20Params) error {
+ return _ArbitrumL1BridgeAdapter.Contract.ExposeSendERC20Params(&_ArbitrumL1BridgeAdapter.CallOpts, params)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCallerSession) ExposeSendERC20Params(params ArbitrumL1BridgeAdapterSendERC20Params) error {
+ return _ArbitrumL1BridgeAdapter.Contract.ExposeSendERC20Params(&_ArbitrumL1BridgeAdapter.CallOpts, params)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCaller) GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbitrumL1BridgeAdapter.contract.Call(opts, &out, "getBridgeFeeInNative")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.GetBridgeFeeInNative(&_ArbitrumL1BridgeAdapter.CallOpts)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCallerSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.GetBridgeFeeInNative(&_ArbitrumL1BridgeAdapter.CallOpts)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCaller) GetL2Token(opts *bind.CallOpts, l1Token common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumL1BridgeAdapter.contract.Call(opts, &out, "getL2Token", l1Token)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterSession) GetL2Token(l1Token common.Address) (common.Address, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.GetL2Token(&_ArbitrumL1BridgeAdapter.CallOpts, l1Token)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterCallerSession) GetL2Token(l1Token common.Address) (common.Address, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.GetL2Token(&_ArbitrumL1BridgeAdapter.CallOpts, l1Token)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterTransactor) FinalizeWithdrawERC20(opts *bind.TransactOpts, arg0 common.Address, arg1 common.Address, arbitrumFinalizationPayload []byte) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.contract.Transact(opts, "finalizeWithdrawERC20", arg0, arg1, arbitrumFinalizationPayload)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, arbitrumFinalizationPayload []byte) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.FinalizeWithdrawERC20(&_ArbitrumL1BridgeAdapter.TransactOpts, arg0, arg1, arbitrumFinalizationPayload)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterTransactorSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, arbitrumFinalizationPayload []byte) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.FinalizeWithdrawERC20(&_ArbitrumL1BridgeAdapter.TransactOpts, arg0, arg1, arbitrumFinalizationPayload)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterTransactor) SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.contract.Transact(opts, "sendERC20", localToken, arg1, recipient, amount, bridgeSpecificPayload)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterSession) SendERC20(localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.SendERC20(&_ArbitrumL1BridgeAdapter.TransactOpts, localToken, arg1, recipient, amount, bridgeSpecificPayload)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapterTransactorSession) SendERC20(localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _ArbitrumL1BridgeAdapter.Contract.SendERC20(&_ArbitrumL1BridgeAdapter.TransactOpts, localToken, arg1, recipient, amount, bridgeSpecificPayload)
+}
+
+func (_ArbitrumL1BridgeAdapter *ArbitrumL1BridgeAdapter) Address() common.Address {
+ return _ArbitrumL1BridgeAdapter.address
+}
+
+type ArbitrumL1BridgeAdapterInterface interface {
+ ExposeArbitrumFinalizationPayload(opts *bind.CallOpts, payload ArbitrumL1BridgeAdapterArbitrumFinalizationPayload) error
+
+ ExposeSendERC20Params(opts *bind.CallOpts, params ArbitrumL1BridgeAdapterSendERC20Params) error
+
+ GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error)
+
+ GetL2Token(opts *bind.CallOpts, l1Token common.Address) (common.Address, error)
+
+ FinalizeWithdrawERC20(opts *bind.TransactOpts, arg0 common.Address, arg1 common.Address, arbitrumFinalizationPayload []byte) (*types.Transaction, error)
+
+ SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arbitrum_l1_gateway_router/arbitrum_l1_gateway_router.go b/core/gethwrappers/liquiditymanager/generated/arbitrum_l1_gateway_router/arbitrum_l1_gateway_router.go
new file mode 100644
index 00000000000..e2e76e5f5bb
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arbitrum_l1_gateway_router/arbitrum_l1_gateway_router.go
@@ -0,0 +1,349 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arbitrum_l1_gateway_router
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var ArbitrumL1GatewayRouterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1ERC20\",\"type\":\"address\"}],\"name\":\"calculateL2TokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeInboundTransfer\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getOutboundCalldata\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"inbox\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasPriceBid\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"outboundTransfer\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_refundTo\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasPriceBid\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"outboundTransferCustomRefund\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_gateway\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_maxGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasPriceBid\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxSubmissionCost\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_creditBackAddress\",\"type\":\"address\"}],\"name\":\"setGateway\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_gateway\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_maxGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasPriceBid\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxSubmissionCost\",\"type\":\"uint256\"}],\"name\":\"setGateway\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var ArbitrumL1GatewayRouterABI = ArbitrumL1GatewayRouterMetaData.ABI
+
+type ArbitrumL1GatewayRouter struct {
+ address common.Address
+ abi abi.ABI
+ ArbitrumL1GatewayRouterCaller
+ ArbitrumL1GatewayRouterTransactor
+ ArbitrumL1GatewayRouterFilterer
+}
+
+type ArbitrumL1GatewayRouterCaller struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL1GatewayRouterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL1GatewayRouterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL1GatewayRouterSession struct {
+ Contract *ArbitrumL1GatewayRouter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumL1GatewayRouterCallerSession struct {
+ Contract *ArbitrumL1GatewayRouterCaller
+ CallOpts bind.CallOpts
+}
+
+type ArbitrumL1GatewayRouterTransactorSession struct {
+ Contract *ArbitrumL1GatewayRouterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumL1GatewayRouterRaw struct {
+ Contract *ArbitrumL1GatewayRouter
+}
+
+type ArbitrumL1GatewayRouterCallerRaw struct {
+ Contract *ArbitrumL1GatewayRouterCaller
+}
+
+type ArbitrumL1GatewayRouterTransactorRaw struct {
+ Contract *ArbitrumL1GatewayRouterTransactor
+}
+
+func NewArbitrumL1GatewayRouter(address common.Address, backend bind.ContractBackend) (*ArbitrumL1GatewayRouter, error) {
+ abi, err := abi.JSON(strings.NewReader(ArbitrumL1GatewayRouterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindArbitrumL1GatewayRouter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL1GatewayRouter{address: address, abi: abi, ArbitrumL1GatewayRouterCaller: ArbitrumL1GatewayRouterCaller{contract: contract}, ArbitrumL1GatewayRouterTransactor: ArbitrumL1GatewayRouterTransactor{contract: contract}, ArbitrumL1GatewayRouterFilterer: ArbitrumL1GatewayRouterFilterer{contract: contract}}, nil
+}
+
+func NewArbitrumL1GatewayRouterCaller(address common.Address, caller bind.ContractCaller) (*ArbitrumL1GatewayRouterCaller, error) {
+ contract, err := bindArbitrumL1GatewayRouter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL1GatewayRouterCaller{contract: contract}, nil
+}
+
+func NewArbitrumL1GatewayRouterTransactor(address common.Address, transactor bind.ContractTransactor) (*ArbitrumL1GatewayRouterTransactor, error) {
+ contract, err := bindArbitrumL1GatewayRouter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL1GatewayRouterTransactor{contract: contract}, nil
+}
+
+func NewArbitrumL1GatewayRouterFilterer(address common.Address, filterer bind.ContractFilterer) (*ArbitrumL1GatewayRouterFilterer, error) {
+ contract, err := bindArbitrumL1GatewayRouter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL1GatewayRouterFilterer{contract: contract}, nil
+}
+
+func bindArbitrumL1GatewayRouter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ArbitrumL1GatewayRouterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumL1GatewayRouter.Contract.ArbitrumL1GatewayRouterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.ArbitrumL1GatewayRouterTransactor.contract.Transfer(opts)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.ArbitrumL1GatewayRouterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumL1GatewayRouter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.contract.Transfer(opts)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCaller) CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumL1GatewayRouter.contract.Call(opts, &out, "calculateL2TokenAddress", l1ERC20)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _ArbitrumL1GatewayRouter.Contract.CalculateL2TokenAddress(&_ArbitrumL1GatewayRouter.CallOpts, l1ERC20)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCallerSession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _ArbitrumL1GatewayRouter.Contract.CalculateL2TokenAddress(&_ArbitrumL1GatewayRouter.CallOpts, l1ERC20)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCaller) GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ var out []interface{}
+ err := _ArbitrumL1GatewayRouter.contract.Call(opts, &out, "getOutboundCalldata", _token, _from, _to, _amount, _data)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _ArbitrumL1GatewayRouter.Contract.GetOutboundCalldata(&_ArbitrumL1GatewayRouter.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCallerSession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _ArbitrumL1GatewayRouter.Contract.GetOutboundCalldata(&_ArbitrumL1GatewayRouter.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCaller) Inbox(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumL1GatewayRouter.contract.Call(opts, &out, "inbox")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) Inbox() (common.Address, error) {
+ return _ArbitrumL1GatewayRouter.Contract.Inbox(&_ArbitrumL1GatewayRouter.CallOpts)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCallerSession) Inbox() (common.Address, error) {
+ return _ArbitrumL1GatewayRouter.Contract.Inbox(&_ArbitrumL1GatewayRouter.CallOpts)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumL1GatewayRouter.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) Owner() (common.Address, error) {
+ return _ArbitrumL1GatewayRouter.Contract.Owner(&_ArbitrumL1GatewayRouter.CallOpts)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCallerSession) Owner() (common.Address, error) {
+ return _ArbitrumL1GatewayRouter.Contract.Owner(&_ArbitrumL1GatewayRouter.CallOpts)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _ArbitrumL1GatewayRouter.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _ArbitrumL1GatewayRouter.Contract.SupportsInterface(&_ArbitrumL1GatewayRouter.CallOpts, interfaceId)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _ArbitrumL1GatewayRouter.Contract.SupportsInterface(&_ArbitrumL1GatewayRouter.CallOpts, interfaceId)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactor) FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.contract.Transact(opts, "finalizeInboundTransfer", _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.FinalizeInboundTransfer(&_ArbitrumL1GatewayRouter.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactorSession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.FinalizeInboundTransfer(&_ArbitrumL1GatewayRouter.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactor) OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.contract.Transact(opts, "outboundTransfer", _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) OutboundTransfer(_token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.OutboundTransfer(&_ArbitrumL1GatewayRouter.TransactOpts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactorSession) OutboundTransfer(_token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.OutboundTransfer(&_ArbitrumL1GatewayRouter.TransactOpts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactor) OutboundTransferCustomRefund(opts *bind.TransactOpts, _token common.Address, _refundTo common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.contract.Transact(opts, "outboundTransferCustomRefund", _token, _refundTo, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) OutboundTransferCustomRefund(_token common.Address, _refundTo common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.OutboundTransferCustomRefund(&_ArbitrumL1GatewayRouter.TransactOpts, _token, _refundTo, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactorSession) OutboundTransferCustomRefund(_token common.Address, _refundTo common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.OutboundTransferCustomRefund(&_ArbitrumL1GatewayRouter.TransactOpts, _token, _refundTo, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactor) SetGateway(opts *bind.TransactOpts, _gateway common.Address, _maxGas *big.Int, _gasPriceBid *big.Int, _maxSubmissionCost *big.Int, _creditBackAddress common.Address) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.contract.Transact(opts, "setGateway", _gateway, _maxGas, _gasPriceBid, _maxSubmissionCost, _creditBackAddress)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) SetGateway(_gateway common.Address, _maxGas *big.Int, _gasPriceBid *big.Int, _maxSubmissionCost *big.Int, _creditBackAddress common.Address) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.SetGateway(&_ArbitrumL1GatewayRouter.TransactOpts, _gateway, _maxGas, _gasPriceBid, _maxSubmissionCost, _creditBackAddress)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactorSession) SetGateway(_gateway common.Address, _maxGas *big.Int, _gasPriceBid *big.Int, _maxSubmissionCost *big.Int, _creditBackAddress common.Address) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.SetGateway(&_ArbitrumL1GatewayRouter.TransactOpts, _gateway, _maxGas, _gasPriceBid, _maxSubmissionCost, _creditBackAddress)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactor) SetGateway0(opts *bind.TransactOpts, _gateway common.Address, _maxGas *big.Int, _gasPriceBid *big.Int, _maxSubmissionCost *big.Int) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.contract.Transact(opts, "setGateway0", _gateway, _maxGas, _gasPriceBid, _maxSubmissionCost)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterSession) SetGateway0(_gateway common.Address, _maxGas *big.Int, _gasPriceBid *big.Int, _maxSubmissionCost *big.Int) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.SetGateway0(&_ArbitrumL1GatewayRouter.TransactOpts, _gateway, _maxGas, _gasPriceBid, _maxSubmissionCost)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouterTransactorSession) SetGateway0(_gateway common.Address, _maxGas *big.Int, _gasPriceBid *big.Int, _maxSubmissionCost *big.Int) (*types.Transaction, error) {
+ return _ArbitrumL1GatewayRouter.Contract.SetGateway0(&_ArbitrumL1GatewayRouter.TransactOpts, _gateway, _maxGas, _gasPriceBid, _maxSubmissionCost)
+}
+
+func (_ArbitrumL1GatewayRouter *ArbitrumL1GatewayRouter) Address() common.Address {
+ return _ArbitrumL1GatewayRouter.address
+}
+
+type ArbitrumL1GatewayRouterInterface interface {
+ CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error)
+
+ GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error)
+
+ Inbox(opts *bind.CallOpts) (common.Address, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error)
+
+ OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error)
+
+ OutboundTransferCustomRefund(opts *bind.TransactOpts, _token common.Address, _refundTo common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error)
+
+ SetGateway(opts *bind.TransactOpts, _gateway common.Address, _maxGas *big.Int, _gasPriceBid *big.Int, _maxSubmissionCost *big.Int, _creditBackAddress common.Address) (*types.Transaction, error)
+
+ SetGateway0(opts *bind.TransactOpts, _gateway common.Address, _maxGas *big.Int, _gasPriceBid *big.Int, _maxSubmissionCost *big.Int) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arbitrum_l2_bridge_adapter/arbitrum_l2_bridge_adapter.go b/core/gethwrappers/liquiditymanager/generated/arbitrum_l2_bridge_adapter/arbitrum_l2_bridge_adapter.go
new file mode 100644
index 00000000000..245daddaa4c
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arbitrum_l2_bridge_adapter/arbitrum_l2_bridge_adapter.go
@@ -0,0 +1,254 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arbitrum_l2_bridge_adapter
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var ArbitrumL2BridgeAdapterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIL2GatewayRouter\",\"name\":\"l2GatewayRouter\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BridgeAddressCannotBeZero\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wanted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"}],\"name\":\"InsufficientEthValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"MsgShouldNotContainValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"msgValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"MsgValueDoesNotMatchAmount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"depositNativeToL1\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBridgeFeeInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"sendERC20\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+ Bin: "0x60a060405234801561001057600080fd5b50604051610a24380380610a2483398101604081905261002f91610067565b6001600160a01b03811661005657604051635e9c404d60e11b815260040160405180910390fd5b6001600160a01b0316608052610097565b60006020828403121561007957600080fd5b81516001600160a01b038116811461009057600080fd5b9392505050565b6080516109726100b2600039600061021a01526109726000f3fe60806040526004361061003f5760003560e01c80630ff98e31146100445780632e4b1fc91461005957806338314bb21461007a578063a71d98b7146100aa575b600080fd5b61005761005236600461060a565b6100ca565b005b34801561006557600080fd5b50604051600081526020015b60405180910390f35b34801561008657600080fd5b5061009a610095366004610675565b610161565b6040519015158152602001610071565b6100bd6100b83660046106d6565b61016c565b60405161007191906107c3565b6040517f25e1606300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526064906325e1606390349060240160206040518083038185885af1158015610138573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061015d91906107d6565b5050565b60015b949350505050565b606034156101ad576040517f2543d86e0000000000000000000000000000000000000000000000000000000081523460048201526024015b60405180910390fd5b6101cf73ffffffffffffffffffffffffffffffffffffffff88163330876102c4565b60408051602081018252600080825291517f7b3a3c8b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691637b3a3c8b91610253918b918b918b916004016107ef565b6000604051808303816000875af1158015610272573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526102b89190810190610867565b98975050505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261035990859061035f565b50505050565b60006103c1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166104709092919063ffffffff16565b80519091501561046b57808060200190518101906103df9190610927565b61046b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016101a4565b505050565b60606101648484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516104a49190610949565b60006040518083038185875af1925050503d80600081146104e1576040519150601f19603f3d011682016040523d82523d6000602084013e6104e6565b606091505b50915091506104f787838387610502565b979650505050505050565b606083156105985782516000036105915773ffffffffffffffffffffffffffffffffffffffff85163b610591576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101a4565b5081610164565b61016483838151156105ad5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101a491906107c3565b803573ffffffffffffffffffffffffffffffffffffffff8116811461060557600080fd5b919050565b60006020828403121561061c57600080fd5b610625826105e1565b9392505050565b60008083601f84011261063e57600080fd5b50813567ffffffffffffffff81111561065657600080fd5b60208301915083602082850101111561066e57600080fd5b9250929050565b6000806000806060858703121561068b57600080fd5b610694856105e1565b93506106a2602086016105e1565b9250604085013567ffffffffffffffff8111156106be57600080fd5b6106ca8782880161062c565b95989497509550505050565b60008060008060008060a087890312156106ef57600080fd5b6106f8876105e1565b9550610706602088016105e1565b9450610714604088016105e1565b935060608701359250608087013567ffffffffffffffff81111561073757600080fd5b61074389828a0161062c565b979a9699509497509295939492505050565b60005b83811015610770578181015183820152602001610758565b50506000910152565b60008151808452610791816020860160208601610755565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006106256020830184610779565b6000602082840312156107e857600080fd5b5051919050565b600073ffffffffffffffffffffffffffffffffffffffff80871683528086166020840152508360408301526080606083015261082e6080830184610779565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561087957600080fd5b815167ffffffffffffffff8082111561089157600080fd5b818401915084601f8301126108a557600080fd5b8151818111156108b7576108b7610838565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156108fd576108fd610838565b8160405282815287602084870101111561091657600080fd5b6104f7836020830160208801610755565b60006020828403121561093957600080fd5b8151801515811461062557600080fd5b6000825161095b818460208701610755565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var ArbitrumL2BridgeAdapterABI = ArbitrumL2BridgeAdapterMetaData.ABI
+
+var ArbitrumL2BridgeAdapterBin = ArbitrumL2BridgeAdapterMetaData.Bin
+
+func DeployArbitrumL2BridgeAdapter(auth *bind.TransactOpts, backend bind.ContractBackend, l2GatewayRouter common.Address) (common.Address, *types.Transaction, *ArbitrumL2BridgeAdapter, error) {
+ parsed, err := ArbitrumL2BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ArbitrumL2BridgeAdapterBin), backend, l2GatewayRouter)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &ArbitrumL2BridgeAdapter{address: address, abi: *parsed, ArbitrumL2BridgeAdapterCaller: ArbitrumL2BridgeAdapterCaller{contract: contract}, ArbitrumL2BridgeAdapterTransactor: ArbitrumL2BridgeAdapterTransactor{contract: contract}, ArbitrumL2BridgeAdapterFilterer: ArbitrumL2BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+type ArbitrumL2BridgeAdapter struct {
+ address common.Address
+ abi abi.ABI
+ ArbitrumL2BridgeAdapterCaller
+ ArbitrumL2BridgeAdapterTransactor
+ ArbitrumL2BridgeAdapterFilterer
+}
+
+type ArbitrumL2BridgeAdapterCaller struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL2BridgeAdapterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL2BridgeAdapterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumL2BridgeAdapterSession struct {
+ Contract *ArbitrumL2BridgeAdapter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumL2BridgeAdapterCallerSession struct {
+ Contract *ArbitrumL2BridgeAdapterCaller
+ CallOpts bind.CallOpts
+}
+
+type ArbitrumL2BridgeAdapterTransactorSession struct {
+ Contract *ArbitrumL2BridgeAdapterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumL2BridgeAdapterRaw struct {
+ Contract *ArbitrumL2BridgeAdapter
+}
+
+type ArbitrumL2BridgeAdapterCallerRaw struct {
+ Contract *ArbitrumL2BridgeAdapterCaller
+}
+
+type ArbitrumL2BridgeAdapterTransactorRaw struct {
+ Contract *ArbitrumL2BridgeAdapterTransactor
+}
+
+func NewArbitrumL2BridgeAdapter(address common.Address, backend bind.ContractBackend) (*ArbitrumL2BridgeAdapter, error) {
+ abi, err := abi.JSON(strings.NewReader(ArbitrumL2BridgeAdapterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindArbitrumL2BridgeAdapter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL2BridgeAdapter{address: address, abi: abi, ArbitrumL2BridgeAdapterCaller: ArbitrumL2BridgeAdapterCaller{contract: contract}, ArbitrumL2BridgeAdapterTransactor: ArbitrumL2BridgeAdapterTransactor{contract: contract}, ArbitrumL2BridgeAdapterFilterer: ArbitrumL2BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+func NewArbitrumL2BridgeAdapterCaller(address common.Address, caller bind.ContractCaller) (*ArbitrumL2BridgeAdapterCaller, error) {
+ contract, err := bindArbitrumL2BridgeAdapter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL2BridgeAdapterCaller{contract: contract}, nil
+}
+
+func NewArbitrumL2BridgeAdapterTransactor(address common.Address, transactor bind.ContractTransactor) (*ArbitrumL2BridgeAdapterTransactor, error) {
+ contract, err := bindArbitrumL2BridgeAdapter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL2BridgeAdapterTransactor{contract: contract}, nil
+}
+
+func NewArbitrumL2BridgeAdapterFilterer(address common.Address, filterer bind.ContractFilterer) (*ArbitrumL2BridgeAdapterFilterer, error) {
+ contract, err := bindArbitrumL2BridgeAdapter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumL2BridgeAdapterFilterer{contract: contract}, nil
+}
+
+func bindArbitrumL2BridgeAdapter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ArbitrumL2BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumL2BridgeAdapter.Contract.ArbitrumL2BridgeAdapterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.ArbitrumL2BridgeAdapterTransactor.contract.Transfer(opts)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.ArbitrumL2BridgeAdapterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumL2BridgeAdapter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.contract.Transfer(opts)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterCaller) FinalizeWithdrawERC20(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ var out []interface{}
+ err := _ArbitrumL2BridgeAdapter.contract.Call(opts, &out, "finalizeWithdrawERC20", arg0, arg1, arg2)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.FinalizeWithdrawERC20(&_ArbitrumL2BridgeAdapter.CallOpts, arg0, arg1, arg2)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterCallerSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.FinalizeWithdrawERC20(&_ArbitrumL2BridgeAdapter.CallOpts, arg0, arg1, arg2)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterCaller) GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbitrumL2BridgeAdapter.contract.Call(opts, &out, "getBridgeFeeInNative")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.GetBridgeFeeInNative(&_ArbitrumL2BridgeAdapter.CallOpts)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterCallerSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.GetBridgeFeeInNative(&_ArbitrumL2BridgeAdapter.CallOpts)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterTransactor) DepositNativeToL1(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.contract.Transact(opts, "depositNativeToL1", recipient)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterSession) DepositNativeToL1(recipient common.Address) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.DepositNativeToL1(&_ArbitrumL2BridgeAdapter.TransactOpts, recipient)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterTransactorSession) DepositNativeToL1(recipient common.Address) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.DepositNativeToL1(&_ArbitrumL2BridgeAdapter.TransactOpts, recipient)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterTransactor) SendERC20(opts *bind.TransactOpts, localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.contract.Transact(opts, "sendERC20", localToken, remoteToken, recipient, amount, arg4)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterSession) SendERC20(localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.SendERC20(&_ArbitrumL2BridgeAdapter.TransactOpts, localToken, remoteToken, recipient, amount, arg4)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapterTransactorSession) SendERC20(localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _ArbitrumL2BridgeAdapter.Contract.SendERC20(&_ArbitrumL2BridgeAdapter.TransactOpts, localToken, remoteToken, recipient, amount, arg4)
+}
+
+func (_ArbitrumL2BridgeAdapter *ArbitrumL2BridgeAdapter) Address() common.Address {
+ return _ArbitrumL2BridgeAdapter.address
+}
+
+type ArbitrumL2BridgeAdapterInterface interface {
+ FinalizeWithdrawERC20(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error)
+
+ GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error)
+
+ DepositNativeToL1(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error)
+
+ SendERC20(opts *bind.TransactOpts, localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arbitrum_rollup_core/arbitrum_rollup_core.go b/core/gethwrappers/liquiditymanager/generated/arbitrum_rollup_core/arbitrum_rollup_core.go
new file mode 100644
index 00000000000..f90cc869d5d
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arbitrum_rollup_core/arbitrum_rollup_core.go
@@ -0,0 +1,2022 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arbitrum_rollup_core
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type Assertion struct {
+ BeforeState ExecutionState
+ AfterState ExecutionState
+ NumBlocks uint64
+}
+
+type ExecutionState struct {
+ GlobalState GlobalState
+ MachineStatus uint8
+}
+
+type GlobalState struct {
+ Bytes32Vals [2][32]byte
+ U64Vals [2]uint64
+}
+
+type IRollupCoreStaker struct {
+ AmountStaked *big.Int
+ Index uint64
+ LatestStakedNode uint64
+ CurrentChallenge uint64
+ IsStaked bool
+}
+
+type Node struct {
+ StateHash [32]byte
+ ChallengeHash [32]byte
+ ConfirmData [32]byte
+ PrevNum uint64
+ DeadlineBlock uint64
+ NoChildConfirmedBeforeBlock uint64
+ StakerCount uint64
+ ChildStakerCount uint64
+ FirstChildBlock uint64
+ LatestChildNumber uint64
+ CreatedAtBlock uint64
+ NodeHash [32]byte
+}
+
+var ArbRollupCoreMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nodeNum\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"sendRoot\",\"type\":\"bytes32\"}],\"name\":\"NodeConfirmed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nodeNum\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"parentNodeHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"nodeHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"executionHash\",\"type\":\"bytes32\"},{\"components\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32[2]\",\"name\":\"bytes32Vals\",\"type\":\"bytes32[2]\"},{\"internalType\":\"uint64[2]\",\"name\":\"u64Vals\",\"type\":\"uint64[2]\"}],\"internalType\":\"structGlobalState\",\"name\":\"globalState\",\"type\":\"tuple\"},{\"internalType\":\"enumMachineStatus\",\"name\":\"machineStatus\",\"type\":\"uint8\"}],\"internalType\":\"structExecutionState\",\"name\":\"beforeState\",\"type\":\"tuple\"},{\"components\":[{\"components\":[{\"internalType\":\"bytes32[2]\",\"name\":\"bytes32Vals\",\"type\":\"bytes32[2]\"},{\"internalType\":\"uint64[2]\",\"name\":\"u64Vals\",\"type\":\"uint64[2]\"}],\"internalType\":\"structGlobalState\",\"name\":\"globalState\",\"type\":\"tuple\"},{\"internalType\":\"enumMachineStatus\",\"name\":\"machineStatus\",\"type\":\"uint8\"}],\"internalType\":\"structExecutionState\",\"name\":\"afterState\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"numBlocks\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structAssertion\",\"name\":\"assertion\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"afterInboxBatchAcc\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"wasmModuleRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"inboxMaxCount\",\"type\":\"uint256\"}],\"name\":\"NodeCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"nodeNum\",\"type\":\"uint64\"}],\"name\":\"NodeRejected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"challengeIndex\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"asserter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"challenger\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"challengedNode\",\"type\":\"uint64\"}],\"name\":\"RollupChallengeStarted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"machineHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"}],\"name\":\"RollupInitialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"finalBalance\",\"type\":\"uint256\"}],\"name\":\"UserStakeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"finalBalance\",\"type\":\"uint256\"}],\"name\":\"UserWithdrawableFundsUpdated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"amountStaked\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"bridge\",\"outputs\":[{\"internalType\":\"contractIBridge\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"challengeManager\",\"outputs\":[{\"internalType\":\"contractIChallengeManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"confirmPeriodBlocks\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"currentChallenge\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"extraChallengeTimeBlocks\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"firstUnresolvedNode\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"nodeNum\",\"type\":\"uint64\"}],\"name\":\"getNode\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"stateHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"challengeHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"confirmData\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"prevNum\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"deadlineBlock\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"noChildConfirmedBeforeBlock\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"stakerCount\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"childStakerCount\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"firstChildBlock\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"latestChildNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"createdAtBlock\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"nodeHash\",\"type\":\"bytes32\"}],\"internalType\":\"structNode\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"nodeNum\",\"type\":\"uint64\"}],\"name\":\"getNodeCreationBlockForLogLookup\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"getStaker\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amountStaked\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"index\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"latestStakedNode\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"currentChallenge\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"isStaked\",\"type\":\"bool\"}],\"internalType\":\"structIRollupCore.Staker\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"stakerNum\",\"type\":\"uint64\"}],\"name\":\"getStakerAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"isStaked\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isValidator\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"isZombie\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastStakeBlock\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfirmed\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestNodeCreated\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"latestStakedNode\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"loserStakeEscrow\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"minimumAssertionPeriod\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"nodeNum\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"staker\",\"type\":\"address\"}],\"name\":\"nodeHasStaker\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outbox\",\"outputs\":[{\"internalType\":\"contractIOutbox\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rollupEventInbox\",\"outputs\":[{\"internalType\":\"contractIRollupEventInbox\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sequencerInbox\",\"outputs\":[{\"internalType\":\"contractISequencerInbox\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakeToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stakerCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"validatorWhitelistDisabled\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wasmModuleRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"withdrawableFunds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"zombieNum\",\"type\":\"uint256\"}],\"name\":\"zombieAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zombieCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"zombieNum\",\"type\":\"uint256\"}],\"name\":\"zombieLatestStakedNode\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var ArbRollupCoreABI = ArbRollupCoreMetaData.ABI
+
+type ArbRollupCore struct {
+ address common.Address
+ abi abi.ABI
+ ArbRollupCoreCaller
+ ArbRollupCoreTransactor
+ ArbRollupCoreFilterer
+}
+
+type ArbRollupCoreCaller struct {
+ contract *bind.BoundContract
+}
+
+type ArbRollupCoreTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ArbRollupCoreFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ArbRollupCoreSession struct {
+ Contract *ArbRollupCore
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ArbRollupCoreCallerSession struct {
+ Contract *ArbRollupCoreCaller
+ CallOpts bind.CallOpts
+}
+
+type ArbRollupCoreTransactorSession struct {
+ Contract *ArbRollupCoreTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ArbRollupCoreRaw struct {
+ Contract *ArbRollupCore
+}
+
+type ArbRollupCoreCallerRaw struct {
+ Contract *ArbRollupCoreCaller
+}
+
+type ArbRollupCoreTransactorRaw struct {
+ Contract *ArbRollupCoreTransactor
+}
+
+func NewArbRollupCore(address common.Address, backend bind.ContractBackend) (*ArbRollupCore, error) {
+ abi, err := abi.JSON(strings.NewReader(ArbRollupCoreABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindArbRollupCore(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCore{address: address, abi: abi, ArbRollupCoreCaller: ArbRollupCoreCaller{contract: contract}, ArbRollupCoreTransactor: ArbRollupCoreTransactor{contract: contract}, ArbRollupCoreFilterer: ArbRollupCoreFilterer{contract: contract}}, nil
+}
+
+func NewArbRollupCoreCaller(address common.Address, caller bind.ContractCaller) (*ArbRollupCoreCaller, error) {
+ contract, err := bindArbRollupCore(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreCaller{contract: contract}, nil
+}
+
+func NewArbRollupCoreTransactor(address common.Address, transactor bind.ContractTransactor) (*ArbRollupCoreTransactor, error) {
+ contract, err := bindArbRollupCore(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreTransactor{contract: contract}, nil
+}
+
+func NewArbRollupCoreFilterer(address common.Address, filterer bind.ContractFilterer) (*ArbRollupCoreFilterer, error) {
+ contract, err := bindArbRollupCore(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreFilterer{contract: contract}, nil
+}
+
+func bindArbRollupCore(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ArbRollupCoreMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ArbRollupCore *ArbRollupCoreRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbRollupCore.Contract.ArbRollupCoreCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbRollupCore *ArbRollupCoreRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbRollupCore.Contract.ArbRollupCoreTransactor.contract.Transfer(opts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbRollupCore.Contract.ArbRollupCoreTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbRollupCore.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbRollupCore *ArbRollupCoreTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbRollupCore.Contract.contract.Transfer(opts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbRollupCore.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) AmountStaked(opts *bind.CallOpts, staker common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "amountStaked", staker)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) AmountStaked(staker common.Address) (*big.Int, error) {
+ return _ArbRollupCore.Contract.AmountStaked(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) AmountStaked(staker common.Address) (*big.Int, error) {
+ return _ArbRollupCore.Contract.AmountStaked(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) BaseStake(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "baseStake")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) BaseStake() (*big.Int, error) {
+ return _ArbRollupCore.Contract.BaseStake(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) BaseStake() (*big.Int, error) {
+ return _ArbRollupCore.Contract.BaseStake(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) Bridge(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "bridge")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) Bridge() (common.Address, error) {
+ return _ArbRollupCore.Contract.Bridge(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) Bridge() (common.Address, error) {
+ return _ArbRollupCore.Contract.Bridge(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) ChainId(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "chainId")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) ChainId() (*big.Int, error) {
+ return _ArbRollupCore.Contract.ChainId(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) ChainId() (*big.Int, error) {
+ return _ArbRollupCore.Contract.ChainId(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) ChallengeManager(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "challengeManager")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) ChallengeManager() (common.Address, error) {
+ return _ArbRollupCore.Contract.ChallengeManager(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) ChallengeManager() (common.Address, error) {
+ return _ArbRollupCore.Contract.ChallengeManager(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) ConfirmPeriodBlocks(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "confirmPeriodBlocks")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) ConfirmPeriodBlocks() (uint64, error) {
+ return _ArbRollupCore.Contract.ConfirmPeriodBlocks(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) ConfirmPeriodBlocks() (uint64, error) {
+ return _ArbRollupCore.Contract.ConfirmPeriodBlocks(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) CurrentChallenge(opts *bind.CallOpts, staker common.Address) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "currentChallenge", staker)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) CurrentChallenge(staker common.Address) (uint64, error) {
+ return _ArbRollupCore.Contract.CurrentChallenge(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) CurrentChallenge(staker common.Address) (uint64, error) {
+ return _ArbRollupCore.Contract.CurrentChallenge(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) ExtraChallengeTimeBlocks(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "extraChallengeTimeBlocks")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) ExtraChallengeTimeBlocks() (uint64, error) {
+ return _ArbRollupCore.Contract.ExtraChallengeTimeBlocks(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) ExtraChallengeTimeBlocks() (uint64, error) {
+ return _ArbRollupCore.Contract.ExtraChallengeTimeBlocks(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) FirstUnresolvedNode(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "firstUnresolvedNode")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) FirstUnresolvedNode() (uint64, error) {
+ return _ArbRollupCore.Contract.FirstUnresolvedNode(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) FirstUnresolvedNode() (uint64, error) {
+ return _ArbRollupCore.Contract.FirstUnresolvedNode(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) GetNode(opts *bind.CallOpts, nodeNum uint64) (Node, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "getNode", nodeNum)
+
+ if err != nil {
+ return *new(Node), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(Node)).(*Node)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) GetNode(nodeNum uint64) (Node, error) {
+ return _ArbRollupCore.Contract.GetNode(&_ArbRollupCore.CallOpts, nodeNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) GetNode(nodeNum uint64) (Node, error) {
+ return _ArbRollupCore.Contract.GetNode(&_ArbRollupCore.CallOpts, nodeNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) GetNodeCreationBlockForLogLookup(opts *bind.CallOpts, nodeNum uint64) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "getNodeCreationBlockForLogLookup", nodeNum)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) GetNodeCreationBlockForLogLookup(nodeNum uint64) (*big.Int, error) {
+ return _ArbRollupCore.Contract.GetNodeCreationBlockForLogLookup(&_ArbRollupCore.CallOpts, nodeNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) GetNodeCreationBlockForLogLookup(nodeNum uint64) (*big.Int, error) {
+ return _ArbRollupCore.Contract.GetNodeCreationBlockForLogLookup(&_ArbRollupCore.CallOpts, nodeNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) GetStaker(opts *bind.CallOpts, staker common.Address) (IRollupCoreStaker, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "getStaker", staker)
+
+ if err != nil {
+ return *new(IRollupCoreStaker), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(IRollupCoreStaker)).(*IRollupCoreStaker)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) GetStaker(staker common.Address) (IRollupCoreStaker, error) {
+ return _ArbRollupCore.Contract.GetStaker(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) GetStaker(staker common.Address) (IRollupCoreStaker, error) {
+ return _ArbRollupCore.Contract.GetStaker(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) GetStakerAddress(opts *bind.CallOpts, stakerNum uint64) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "getStakerAddress", stakerNum)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) GetStakerAddress(stakerNum uint64) (common.Address, error) {
+ return _ArbRollupCore.Contract.GetStakerAddress(&_ArbRollupCore.CallOpts, stakerNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) GetStakerAddress(stakerNum uint64) (common.Address, error) {
+ return _ArbRollupCore.Contract.GetStakerAddress(&_ArbRollupCore.CallOpts, stakerNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) IsStaked(opts *bind.CallOpts, staker common.Address) (bool, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "isStaked", staker)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) IsStaked(staker common.Address) (bool, error) {
+ return _ArbRollupCore.Contract.IsStaked(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) IsStaked(staker common.Address) (bool, error) {
+ return _ArbRollupCore.Contract.IsStaked(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) IsValidator(opts *bind.CallOpts, arg0 common.Address) (bool, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "isValidator", arg0)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) IsValidator(arg0 common.Address) (bool, error) {
+ return _ArbRollupCore.Contract.IsValidator(&_ArbRollupCore.CallOpts, arg0)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) IsValidator(arg0 common.Address) (bool, error) {
+ return _ArbRollupCore.Contract.IsValidator(&_ArbRollupCore.CallOpts, arg0)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) IsZombie(opts *bind.CallOpts, staker common.Address) (bool, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "isZombie", staker)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) IsZombie(staker common.Address) (bool, error) {
+ return _ArbRollupCore.Contract.IsZombie(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) IsZombie(staker common.Address) (bool, error) {
+ return _ArbRollupCore.Contract.IsZombie(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) LastStakeBlock(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "lastStakeBlock")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) LastStakeBlock() (uint64, error) {
+ return _ArbRollupCore.Contract.LastStakeBlock(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) LastStakeBlock() (uint64, error) {
+ return _ArbRollupCore.Contract.LastStakeBlock(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) LatestConfirmed(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "latestConfirmed")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) LatestConfirmed() (uint64, error) {
+ return _ArbRollupCore.Contract.LatestConfirmed(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) LatestConfirmed() (uint64, error) {
+ return _ArbRollupCore.Contract.LatestConfirmed(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) LatestNodeCreated(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "latestNodeCreated")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) LatestNodeCreated() (uint64, error) {
+ return _ArbRollupCore.Contract.LatestNodeCreated(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) LatestNodeCreated() (uint64, error) {
+ return _ArbRollupCore.Contract.LatestNodeCreated(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) LatestStakedNode(opts *bind.CallOpts, staker common.Address) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "latestStakedNode", staker)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) LatestStakedNode(staker common.Address) (uint64, error) {
+ return _ArbRollupCore.Contract.LatestStakedNode(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) LatestStakedNode(staker common.Address) (uint64, error) {
+ return _ArbRollupCore.Contract.LatestStakedNode(&_ArbRollupCore.CallOpts, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) LoserStakeEscrow(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "loserStakeEscrow")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) LoserStakeEscrow() (common.Address, error) {
+ return _ArbRollupCore.Contract.LoserStakeEscrow(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) LoserStakeEscrow() (common.Address, error) {
+ return _ArbRollupCore.Contract.LoserStakeEscrow(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) MinimumAssertionPeriod(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "minimumAssertionPeriod")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) MinimumAssertionPeriod() (*big.Int, error) {
+ return _ArbRollupCore.Contract.MinimumAssertionPeriod(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) MinimumAssertionPeriod() (*big.Int, error) {
+ return _ArbRollupCore.Contract.MinimumAssertionPeriod(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) NodeHasStaker(opts *bind.CallOpts, nodeNum uint64, staker common.Address) (bool, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "nodeHasStaker", nodeNum, staker)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) NodeHasStaker(nodeNum uint64, staker common.Address) (bool, error) {
+ return _ArbRollupCore.Contract.NodeHasStaker(&_ArbRollupCore.CallOpts, nodeNum, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) NodeHasStaker(nodeNum uint64, staker common.Address) (bool, error) {
+ return _ArbRollupCore.Contract.NodeHasStaker(&_ArbRollupCore.CallOpts, nodeNum, staker)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) Outbox(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "outbox")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) Outbox() (common.Address, error) {
+ return _ArbRollupCore.Contract.Outbox(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) Outbox() (common.Address, error) {
+ return _ArbRollupCore.Contract.Outbox(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) RollupEventInbox(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "rollupEventInbox")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) RollupEventInbox() (common.Address, error) {
+ return _ArbRollupCore.Contract.RollupEventInbox(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) RollupEventInbox() (common.Address, error) {
+ return _ArbRollupCore.Contract.RollupEventInbox(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) SequencerInbox(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "sequencerInbox")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) SequencerInbox() (common.Address, error) {
+ return _ArbRollupCore.Contract.SequencerInbox(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) SequencerInbox() (common.Address, error) {
+ return _ArbRollupCore.Contract.SequencerInbox(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) StakeToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "stakeToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) StakeToken() (common.Address, error) {
+ return _ArbRollupCore.Contract.StakeToken(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) StakeToken() (common.Address, error) {
+ return _ArbRollupCore.Contract.StakeToken(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) StakerCount(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "stakerCount")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) StakerCount() (uint64, error) {
+ return _ArbRollupCore.Contract.StakerCount(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) StakerCount() (uint64, error) {
+ return _ArbRollupCore.Contract.StakerCount(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) ValidatorWhitelistDisabled(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "validatorWhitelistDisabled")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) ValidatorWhitelistDisabled() (bool, error) {
+ return _ArbRollupCore.Contract.ValidatorWhitelistDisabled(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) ValidatorWhitelistDisabled() (bool, error) {
+ return _ArbRollupCore.Contract.ValidatorWhitelistDisabled(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) WasmModuleRoot(opts *bind.CallOpts) ([32]byte, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "wasmModuleRoot")
+
+ if err != nil {
+ return *new([32]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) WasmModuleRoot() ([32]byte, error) {
+ return _ArbRollupCore.Contract.WasmModuleRoot(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) WasmModuleRoot() ([32]byte, error) {
+ return _ArbRollupCore.Contract.WasmModuleRoot(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) WithdrawableFunds(opts *bind.CallOpts, owner common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "withdrawableFunds", owner)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) WithdrawableFunds(owner common.Address) (*big.Int, error) {
+ return _ArbRollupCore.Contract.WithdrawableFunds(&_ArbRollupCore.CallOpts, owner)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) WithdrawableFunds(owner common.Address) (*big.Int, error) {
+ return _ArbRollupCore.Contract.WithdrawableFunds(&_ArbRollupCore.CallOpts, owner)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) ZombieAddress(opts *bind.CallOpts, zombieNum *big.Int) (common.Address, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "zombieAddress", zombieNum)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) ZombieAddress(zombieNum *big.Int) (common.Address, error) {
+ return _ArbRollupCore.Contract.ZombieAddress(&_ArbRollupCore.CallOpts, zombieNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) ZombieAddress(zombieNum *big.Int) (common.Address, error) {
+ return _ArbRollupCore.Contract.ZombieAddress(&_ArbRollupCore.CallOpts, zombieNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) ZombieCount(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "zombieCount")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) ZombieCount() (*big.Int, error) {
+ return _ArbRollupCore.Contract.ZombieCount(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) ZombieCount() (*big.Int, error) {
+ return _ArbRollupCore.Contract.ZombieCount(&_ArbRollupCore.CallOpts)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCaller) ZombieLatestStakedNode(opts *bind.CallOpts, zombieNum *big.Int) (uint64, error) {
+ var out []interface{}
+ err := _ArbRollupCore.contract.Call(opts, &out, "zombieLatestStakedNode", zombieNum)
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_ArbRollupCore *ArbRollupCoreSession) ZombieLatestStakedNode(zombieNum *big.Int) (uint64, error) {
+ return _ArbRollupCore.Contract.ZombieLatestStakedNode(&_ArbRollupCore.CallOpts, zombieNum)
+}
+
+func (_ArbRollupCore *ArbRollupCoreCallerSession) ZombieLatestStakedNode(zombieNum *big.Int) (uint64, error) {
+ return _ArbRollupCore.Contract.ZombieLatestStakedNode(&_ArbRollupCore.CallOpts, zombieNum)
+}
+
+type ArbRollupCoreNodeConfirmedIterator struct {
+ Event *ArbRollupCoreNodeConfirmed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbRollupCoreNodeConfirmedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbRollupCoreNodeConfirmed)
+ 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(ArbRollupCoreNodeConfirmed)
+ 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 *ArbRollupCoreNodeConfirmedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbRollupCoreNodeConfirmedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbRollupCoreNodeConfirmed struct {
+ NodeNum uint64
+ BlockHash [32]byte
+ SendRoot [32]byte
+ Raw types.Log
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) FilterNodeConfirmed(opts *bind.FilterOpts, nodeNum []uint64) (*ArbRollupCoreNodeConfirmedIterator, error) {
+
+ var nodeNumRule []interface{}
+ for _, nodeNumItem := range nodeNum {
+ nodeNumRule = append(nodeNumRule, nodeNumItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.FilterLogs(opts, "NodeConfirmed", nodeNumRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreNodeConfirmedIterator{contract: _ArbRollupCore.contract, event: "NodeConfirmed", logs: logs, sub: sub}, nil
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) WatchNodeConfirmed(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreNodeConfirmed, nodeNum []uint64) (event.Subscription, error) {
+
+ var nodeNumRule []interface{}
+ for _, nodeNumItem := range nodeNum {
+ nodeNumRule = append(nodeNumRule, nodeNumItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.WatchLogs(opts, "NodeConfirmed", nodeNumRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbRollupCoreNodeConfirmed)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "NodeConfirmed", 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 (_ArbRollupCore *ArbRollupCoreFilterer) ParseNodeConfirmed(log types.Log) (*ArbRollupCoreNodeConfirmed, error) {
+ event := new(ArbRollupCoreNodeConfirmed)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "NodeConfirmed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbRollupCoreNodeCreatedIterator struct {
+ Event *ArbRollupCoreNodeCreated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbRollupCoreNodeCreatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbRollupCoreNodeCreated)
+ 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(ArbRollupCoreNodeCreated)
+ 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 *ArbRollupCoreNodeCreatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbRollupCoreNodeCreatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbRollupCoreNodeCreated struct {
+ NodeNum uint64
+ ParentNodeHash [32]byte
+ NodeHash [32]byte
+ ExecutionHash [32]byte
+ Assertion Assertion
+ AfterInboxBatchAcc [32]byte
+ WasmModuleRoot [32]byte
+ InboxMaxCount *big.Int
+ Raw types.Log
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) FilterNodeCreated(opts *bind.FilterOpts, nodeNum []uint64, parentNodeHash [][32]byte, nodeHash [][32]byte) (*ArbRollupCoreNodeCreatedIterator, error) {
+
+ var nodeNumRule []interface{}
+ for _, nodeNumItem := range nodeNum {
+ nodeNumRule = append(nodeNumRule, nodeNumItem)
+ }
+ var parentNodeHashRule []interface{}
+ for _, parentNodeHashItem := range parentNodeHash {
+ parentNodeHashRule = append(parentNodeHashRule, parentNodeHashItem)
+ }
+ var nodeHashRule []interface{}
+ for _, nodeHashItem := range nodeHash {
+ nodeHashRule = append(nodeHashRule, nodeHashItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.FilterLogs(opts, "NodeCreated", nodeNumRule, parentNodeHashRule, nodeHashRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreNodeCreatedIterator{contract: _ArbRollupCore.contract, event: "NodeCreated", logs: logs, sub: sub}, nil
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) WatchNodeCreated(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreNodeCreated, nodeNum []uint64, parentNodeHash [][32]byte, nodeHash [][32]byte) (event.Subscription, error) {
+
+ var nodeNumRule []interface{}
+ for _, nodeNumItem := range nodeNum {
+ nodeNumRule = append(nodeNumRule, nodeNumItem)
+ }
+ var parentNodeHashRule []interface{}
+ for _, parentNodeHashItem := range parentNodeHash {
+ parentNodeHashRule = append(parentNodeHashRule, parentNodeHashItem)
+ }
+ var nodeHashRule []interface{}
+ for _, nodeHashItem := range nodeHash {
+ nodeHashRule = append(nodeHashRule, nodeHashItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.WatchLogs(opts, "NodeCreated", nodeNumRule, parentNodeHashRule, nodeHashRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbRollupCoreNodeCreated)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "NodeCreated", 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 (_ArbRollupCore *ArbRollupCoreFilterer) ParseNodeCreated(log types.Log) (*ArbRollupCoreNodeCreated, error) {
+ event := new(ArbRollupCoreNodeCreated)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "NodeCreated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbRollupCoreNodeRejectedIterator struct {
+ Event *ArbRollupCoreNodeRejected
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbRollupCoreNodeRejectedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbRollupCoreNodeRejected)
+ 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(ArbRollupCoreNodeRejected)
+ 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 *ArbRollupCoreNodeRejectedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbRollupCoreNodeRejectedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbRollupCoreNodeRejected struct {
+ NodeNum uint64
+ Raw types.Log
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) FilterNodeRejected(opts *bind.FilterOpts, nodeNum []uint64) (*ArbRollupCoreNodeRejectedIterator, error) {
+
+ var nodeNumRule []interface{}
+ for _, nodeNumItem := range nodeNum {
+ nodeNumRule = append(nodeNumRule, nodeNumItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.FilterLogs(opts, "NodeRejected", nodeNumRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreNodeRejectedIterator{contract: _ArbRollupCore.contract, event: "NodeRejected", logs: logs, sub: sub}, nil
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) WatchNodeRejected(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreNodeRejected, nodeNum []uint64) (event.Subscription, error) {
+
+ var nodeNumRule []interface{}
+ for _, nodeNumItem := range nodeNum {
+ nodeNumRule = append(nodeNumRule, nodeNumItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.WatchLogs(opts, "NodeRejected", nodeNumRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbRollupCoreNodeRejected)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "NodeRejected", 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 (_ArbRollupCore *ArbRollupCoreFilterer) ParseNodeRejected(log types.Log) (*ArbRollupCoreNodeRejected, error) {
+ event := new(ArbRollupCoreNodeRejected)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "NodeRejected", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbRollupCoreRollupChallengeStartedIterator struct {
+ Event *ArbRollupCoreRollupChallengeStarted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbRollupCoreRollupChallengeStartedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbRollupCoreRollupChallengeStarted)
+ 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(ArbRollupCoreRollupChallengeStarted)
+ 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 *ArbRollupCoreRollupChallengeStartedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbRollupCoreRollupChallengeStartedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbRollupCoreRollupChallengeStarted struct {
+ ChallengeIndex uint64
+ Asserter common.Address
+ Challenger common.Address
+ ChallengedNode uint64
+ Raw types.Log
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) FilterRollupChallengeStarted(opts *bind.FilterOpts, challengeIndex []uint64) (*ArbRollupCoreRollupChallengeStartedIterator, error) {
+
+ var challengeIndexRule []interface{}
+ for _, challengeIndexItem := range challengeIndex {
+ challengeIndexRule = append(challengeIndexRule, challengeIndexItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.FilterLogs(opts, "RollupChallengeStarted", challengeIndexRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreRollupChallengeStartedIterator{contract: _ArbRollupCore.contract, event: "RollupChallengeStarted", logs: logs, sub: sub}, nil
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) WatchRollupChallengeStarted(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreRollupChallengeStarted, challengeIndex []uint64) (event.Subscription, error) {
+
+ var challengeIndexRule []interface{}
+ for _, challengeIndexItem := range challengeIndex {
+ challengeIndexRule = append(challengeIndexRule, challengeIndexItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.WatchLogs(opts, "RollupChallengeStarted", challengeIndexRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbRollupCoreRollupChallengeStarted)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "RollupChallengeStarted", 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 (_ArbRollupCore *ArbRollupCoreFilterer) ParseRollupChallengeStarted(log types.Log) (*ArbRollupCoreRollupChallengeStarted, error) {
+ event := new(ArbRollupCoreRollupChallengeStarted)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "RollupChallengeStarted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbRollupCoreRollupInitializedIterator struct {
+ Event *ArbRollupCoreRollupInitialized
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbRollupCoreRollupInitializedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbRollupCoreRollupInitialized)
+ 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(ArbRollupCoreRollupInitialized)
+ 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 *ArbRollupCoreRollupInitializedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbRollupCoreRollupInitializedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbRollupCoreRollupInitialized struct {
+ MachineHash [32]byte
+ ChainId *big.Int
+ Raw types.Log
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) FilterRollupInitialized(opts *bind.FilterOpts) (*ArbRollupCoreRollupInitializedIterator, error) {
+
+ logs, sub, err := _ArbRollupCore.contract.FilterLogs(opts, "RollupInitialized")
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreRollupInitializedIterator{contract: _ArbRollupCore.contract, event: "RollupInitialized", logs: logs, sub: sub}, nil
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) WatchRollupInitialized(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreRollupInitialized) (event.Subscription, error) {
+
+ logs, sub, err := _ArbRollupCore.contract.WatchLogs(opts, "RollupInitialized")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbRollupCoreRollupInitialized)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "RollupInitialized", 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 (_ArbRollupCore *ArbRollupCoreFilterer) ParseRollupInitialized(log types.Log) (*ArbRollupCoreRollupInitialized, error) {
+ event := new(ArbRollupCoreRollupInitialized)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "RollupInitialized", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbRollupCoreUserStakeUpdatedIterator struct {
+ Event *ArbRollupCoreUserStakeUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbRollupCoreUserStakeUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbRollupCoreUserStakeUpdated)
+ 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(ArbRollupCoreUserStakeUpdated)
+ 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 *ArbRollupCoreUserStakeUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbRollupCoreUserStakeUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbRollupCoreUserStakeUpdated struct {
+ User common.Address
+ InitialBalance *big.Int
+ FinalBalance *big.Int
+ Raw types.Log
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) FilterUserStakeUpdated(opts *bind.FilterOpts, user []common.Address) (*ArbRollupCoreUserStakeUpdatedIterator, error) {
+
+ var userRule []interface{}
+ for _, userItem := range user {
+ userRule = append(userRule, userItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.FilterLogs(opts, "UserStakeUpdated", userRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreUserStakeUpdatedIterator{contract: _ArbRollupCore.contract, event: "UserStakeUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) WatchUserStakeUpdated(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreUserStakeUpdated, user []common.Address) (event.Subscription, error) {
+
+ var userRule []interface{}
+ for _, userItem := range user {
+ userRule = append(userRule, userItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.WatchLogs(opts, "UserStakeUpdated", userRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbRollupCoreUserStakeUpdated)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "UserStakeUpdated", 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 (_ArbRollupCore *ArbRollupCoreFilterer) ParseUserStakeUpdated(log types.Log) (*ArbRollupCoreUserStakeUpdated, error) {
+ event := new(ArbRollupCoreUserStakeUpdated)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "UserStakeUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbRollupCoreUserWithdrawableFundsUpdatedIterator struct {
+ Event *ArbRollupCoreUserWithdrawableFundsUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbRollupCoreUserWithdrawableFundsUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbRollupCoreUserWithdrawableFundsUpdated)
+ 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(ArbRollupCoreUserWithdrawableFundsUpdated)
+ 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 *ArbRollupCoreUserWithdrawableFundsUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbRollupCoreUserWithdrawableFundsUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbRollupCoreUserWithdrawableFundsUpdated struct {
+ User common.Address
+ InitialBalance *big.Int
+ FinalBalance *big.Int
+ Raw types.Log
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) FilterUserWithdrawableFundsUpdated(opts *bind.FilterOpts, user []common.Address) (*ArbRollupCoreUserWithdrawableFundsUpdatedIterator, error) {
+
+ var userRule []interface{}
+ for _, userItem := range user {
+ userRule = append(userRule, userItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.FilterLogs(opts, "UserWithdrawableFundsUpdated", userRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbRollupCoreUserWithdrawableFundsUpdatedIterator{contract: _ArbRollupCore.contract, event: "UserWithdrawableFundsUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_ArbRollupCore *ArbRollupCoreFilterer) WatchUserWithdrawableFundsUpdated(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreUserWithdrawableFundsUpdated, user []common.Address) (event.Subscription, error) {
+
+ var userRule []interface{}
+ for _, userItem := range user {
+ userRule = append(userRule, userItem)
+ }
+
+ logs, sub, err := _ArbRollupCore.contract.WatchLogs(opts, "UserWithdrawableFundsUpdated", userRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbRollupCoreUserWithdrawableFundsUpdated)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "UserWithdrawableFundsUpdated", 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 (_ArbRollupCore *ArbRollupCoreFilterer) ParseUserWithdrawableFundsUpdated(log types.Log) (*ArbRollupCoreUserWithdrawableFundsUpdated, error) {
+ event := new(ArbRollupCoreUserWithdrawableFundsUpdated)
+ if err := _ArbRollupCore.contract.UnpackLog(event, "UserWithdrawableFundsUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_ArbRollupCore *ArbRollupCore) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _ArbRollupCore.abi.Events["NodeConfirmed"].ID:
+ return _ArbRollupCore.ParseNodeConfirmed(log)
+ case _ArbRollupCore.abi.Events["NodeCreated"].ID:
+ return _ArbRollupCore.ParseNodeCreated(log)
+ case _ArbRollupCore.abi.Events["NodeRejected"].ID:
+ return _ArbRollupCore.ParseNodeRejected(log)
+ case _ArbRollupCore.abi.Events["RollupChallengeStarted"].ID:
+ return _ArbRollupCore.ParseRollupChallengeStarted(log)
+ case _ArbRollupCore.abi.Events["RollupInitialized"].ID:
+ return _ArbRollupCore.ParseRollupInitialized(log)
+ case _ArbRollupCore.abi.Events["UserStakeUpdated"].ID:
+ return _ArbRollupCore.ParseUserStakeUpdated(log)
+ case _ArbRollupCore.abi.Events["UserWithdrawableFundsUpdated"].ID:
+ return _ArbRollupCore.ParseUserWithdrawableFundsUpdated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (ArbRollupCoreNodeConfirmed) Topic() common.Hash {
+ return common.HexToHash("0x22ef0479a7ff660660d1c2fe35f1b632cf31675c2d9378db8cec95b00d8ffa3c")
+}
+
+func (ArbRollupCoreNodeCreated) Topic() common.Hash {
+ return common.HexToHash("0x4f4caa9e67fb994e349dd35d1ad0ce23053d4323f83ce11dc817b5435031d096")
+}
+
+func (ArbRollupCoreNodeRejected) Topic() common.Hash {
+ return common.HexToHash("0xeaffa3d968707ec919a2fc9f31d5ab2b86c905881ff561725d5a82fc95ad4640")
+}
+
+func (ArbRollupCoreRollupChallengeStarted) Topic() common.Hash {
+ return common.HexToHash("0x6db7dc2f507647d135035469b27aa79cea90582779d084a7821d6cd092cbd873")
+}
+
+func (ArbRollupCoreRollupInitialized) Topic() common.Hash {
+ return common.HexToHash("0xfc1b83c11d99d08a938e0b82a0bd45f822f71ff5abf23f999c93c4533d752464")
+}
+
+func (ArbRollupCoreUserStakeUpdated) Topic() common.Hash {
+ return common.HexToHash("0xebd093d389ab57f3566918d2c379a2b4d9539e8eb95efad9d5e465457833fde6")
+}
+
+func (ArbRollupCoreUserWithdrawableFundsUpdated) Topic() common.Hash {
+ return common.HexToHash("0xa740af14c56e4e04a617b1de1eb20de73270decbaaead14f142aabf3038e5ae2")
+}
+
+func (_ArbRollupCore *ArbRollupCore) Address() common.Address {
+ return _ArbRollupCore.address
+}
+
+type ArbRollupCoreInterface interface {
+ AmountStaked(opts *bind.CallOpts, staker common.Address) (*big.Int, error)
+
+ BaseStake(opts *bind.CallOpts) (*big.Int, error)
+
+ Bridge(opts *bind.CallOpts) (common.Address, error)
+
+ ChainId(opts *bind.CallOpts) (*big.Int, error)
+
+ ChallengeManager(opts *bind.CallOpts) (common.Address, error)
+
+ ConfirmPeriodBlocks(opts *bind.CallOpts) (uint64, error)
+
+ CurrentChallenge(opts *bind.CallOpts, staker common.Address) (uint64, error)
+
+ ExtraChallengeTimeBlocks(opts *bind.CallOpts) (uint64, error)
+
+ FirstUnresolvedNode(opts *bind.CallOpts) (uint64, error)
+
+ GetNode(opts *bind.CallOpts, nodeNum uint64) (Node, error)
+
+ GetNodeCreationBlockForLogLookup(opts *bind.CallOpts, nodeNum uint64) (*big.Int, error)
+
+ GetStaker(opts *bind.CallOpts, staker common.Address) (IRollupCoreStaker, error)
+
+ GetStakerAddress(opts *bind.CallOpts, stakerNum uint64) (common.Address, error)
+
+ IsStaked(opts *bind.CallOpts, staker common.Address) (bool, error)
+
+ IsValidator(opts *bind.CallOpts, arg0 common.Address) (bool, error)
+
+ IsZombie(opts *bind.CallOpts, staker common.Address) (bool, error)
+
+ LastStakeBlock(opts *bind.CallOpts) (uint64, error)
+
+ LatestConfirmed(opts *bind.CallOpts) (uint64, error)
+
+ LatestNodeCreated(opts *bind.CallOpts) (uint64, error)
+
+ LatestStakedNode(opts *bind.CallOpts, staker common.Address) (uint64, error)
+
+ LoserStakeEscrow(opts *bind.CallOpts) (common.Address, error)
+
+ MinimumAssertionPeriod(opts *bind.CallOpts) (*big.Int, error)
+
+ NodeHasStaker(opts *bind.CallOpts, nodeNum uint64, staker common.Address) (bool, error)
+
+ Outbox(opts *bind.CallOpts) (common.Address, error)
+
+ RollupEventInbox(opts *bind.CallOpts) (common.Address, error)
+
+ SequencerInbox(opts *bind.CallOpts) (common.Address, error)
+
+ StakeToken(opts *bind.CallOpts) (common.Address, error)
+
+ StakerCount(opts *bind.CallOpts) (uint64, error)
+
+ ValidatorWhitelistDisabled(opts *bind.CallOpts) (bool, error)
+
+ WasmModuleRoot(opts *bind.CallOpts) ([32]byte, error)
+
+ WithdrawableFunds(opts *bind.CallOpts, owner common.Address) (*big.Int, error)
+
+ ZombieAddress(opts *bind.CallOpts, zombieNum *big.Int) (common.Address, error)
+
+ ZombieCount(opts *bind.CallOpts) (*big.Int, error)
+
+ ZombieLatestStakedNode(opts *bind.CallOpts, zombieNum *big.Int) (uint64, error)
+
+ FilterNodeConfirmed(opts *bind.FilterOpts, nodeNum []uint64) (*ArbRollupCoreNodeConfirmedIterator, error)
+
+ WatchNodeConfirmed(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreNodeConfirmed, nodeNum []uint64) (event.Subscription, error)
+
+ ParseNodeConfirmed(log types.Log) (*ArbRollupCoreNodeConfirmed, error)
+
+ FilterNodeCreated(opts *bind.FilterOpts, nodeNum []uint64, parentNodeHash [][32]byte, nodeHash [][32]byte) (*ArbRollupCoreNodeCreatedIterator, error)
+
+ WatchNodeCreated(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreNodeCreated, nodeNum []uint64, parentNodeHash [][32]byte, nodeHash [][32]byte) (event.Subscription, error)
+
+ ParseNodeCreated(log types.Log) (*ArbRollupCoreNodeCreated, error)
+
+ FilterNodeRejected(opts *bind.FilterOpts, nodeNum []uint64) (*ArbRollupCoreNodeRejectedIterator, error)
+
+ WatchNodeRejected(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreNodeRejected, nodeNum []uint64) (event.Subscription, error)
+
+ ParseNodeRejected(log types.Log) (*ArbRollupCoreNodeRejected, error)
+
+ FilterRollupChallengeStarted(opts *bind.FilterOpts, challengeIndex []uint64) (*ArbRollupCoreRollupChallengeStartedIterator, error)
+
+ WatchRollupChallengeStarted(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreRollupChallengeStarted, challengeIndex []uint64) (event.Subscription, error)
+
+ ParseRollupChallengeStarted(log types.Log) (*ArbRollupCoreRollupChallengeStarted, error)
+
+ FilterRollupInitialized(opts *bind.FilterOpts) (*ArbRollupCoreRollupInitializedIterator, error)
+
+ WatchRollupInitialized(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreRollupInitialized) (event.Subscription, error)
+
+ ParseRollupInitialized(log types.Log) (*ArbRollupCoreRollupInitialized, error)
+
+ FilterUserStakeUpdated(opts *bind.FilterOpts, user []common.Address) (*ArbRollupCoreUserStakeUpdatedIterator, error)
+
+ WatchUserStakeUpdated(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreUserStakeUpdated, user []common.Address) (event.Subscription, error)
+
+ ParseUserStakeUpdated(log types.Log) (*ArbRollupCoreUserStakeUpdated, error)
+
+ FilterUserWithdrawableFundsUpdated(opts *bind.FilterOpts, user []common.Address) (*ArbRollupCoreUserWithdrawableFundsUpdatedIterator, error)
+
+ WatchUserWithdrawableFundsUpdated(opts *bind.WatchOpts, sink chan<- *ArbRollupCoreUserWithdrawableFundsUpdated, user []common.Address) (event.Subscription, error)
+
+ ParseUserWithdrawableFundsUpdated(log types.Log) (*ArbRollupCoreUserWithdrawableFundsUpdated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arbitrum_token_gateway/arbitrum_token_gateway.go b/core/gethwrappers/liquiditymanager/generated/arbitrum_token_gateway/arbitrum_token_gateway.go
new file mode 100644
index 00000000000..db303b881f2
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arbitrum_token_gateway/arbitrum_token_gateway.go
@@ -0,0 +1,235 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arbitrum_token_gateway
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var ArbitrumTokenGatewayMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1ERC20\",\"type\":\"address\"}],\"name\":\"calculateL2TokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeInboundTransfer\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getOutboundCalldata\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxGas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_gasPriceBid\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"outboundTransfer\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+}
+
+var ArbitrumTokenGatewayABI = ArbitrumTokenGatewayMetaData.ABI
+
+type ArbitrumTokenGateway struct {
+ address common.Address
+ abi abi.ABI
+ ArbitrumTokenGatewayCaller
+ ArbitrumTokenGatewayTransactor
+ ArbitrumTokenGatewayFilterer
+}
+
+type ArbitrumTokenGatewayCaller struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumTokenGatewayTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumTokenGatewayFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ArbitrumTokenGatewaySession struct {
+ Contract *ArbitrumTokenGateway
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumTokenGatewayCallerSession struct {
+ Contract *ArbitrumTokenGatewayCaller
+ CallOpts bind.CallOpts
+}
+
+type ArbitrumTokenGatewayTransactorSession struct {
+ Contract *ArbitrumTokenGatewayTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ArbitrumTokenGatewayRaw struct {
+ Contract *ArbitrumTokenGateway
+}
+
+type ArbitrumTokenGatewayCallerRaw struct {
+ Contract *ArbitrumTokenGatewayCaller
+}
+
+type ArbitrumTokenGatewayTransactorRaw struct {
+ Contract *ArbitrumTokenGatewayTransactor
+}
+
+func NewArbitrumTokenGateway(address common.Address, backend bind.ContractBackend) (*ArbitrumTokenGateway, error) {
+ abi, err := abi.JSON(strings.NewReader(ArbitrumTokenGatewayABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindArbitrumTokenGateway(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumTokenGateway{address: address, abi: abi, ArbitrumTokenGatewayCaller: ArbitrumTokenGatewayCaller{contract: contract}, ArbitrumTokenGatewayTransactor: ArbitrumTokenGatewayTransactor{contract: contract}, ArbitrumTokenGatewayFilterer: ArbitrumTokenGatewayFilterer{contract: contract}}, nil
+}
+
+func NewArbitrumTokenGatewayCaller(address common.Address, caller bind.ContractCaller) (*ArbitrumTokenGatewayCaller, error) {
+ contract, err := bindArbitrumTokenGateway(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumTokenGatewayCaller{contract: contract}, nil
+}
+
+func NewArbitrumTokenGatewayTransactor(address common.Address, transactor bind.ContractTransactor) (*ArbitrumTokenGatewayTransactor, error) {
+ contract, err := bindArbitrumTokenGateway(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumTokenGatewayTransactor{contract: contract}, nil
+}
+
+func NewArbitrumTokenGatewayFilterer(address common.Address, filterer bind.ContractFilterer) (*ArbitrumTokenGatewayFilterer, error) {
+ contract, err := bindArbitrumTokenGateway(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbitrumTokenGatewayFilterer{contract: contract}, nil
+}
+
+func bindArbitrumTokenGateway(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ArbitrumTokenGatewayMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumTokenGateway.Contract.ArbitrumTokenGatewayCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.Contract.ArbitrumTokenGatewayTransactor.contract.Transfer(opts)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.Contract.ArbitrumTokenGatewayTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbitrumTokenGateway.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.Contract.contract.Transfer(opts)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayCaller) CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _ArbitrumTokenGateway.contract.Call(opts, &out, "calculateL2TokenAddress", l1ERC20)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewaySession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _ArbitrumTokenGateway.Contract.CalculateL2TokenAddress(&_ArbitrumTokenGateway.CallOpts, l1ERC20)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayCallerSession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _ArbitrumTokenGateway.Contract.CalculateL2TokenAddress(&_ArbitrumTokenGateway.CallOpts, l1ERC20)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayCaller) GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ var out []interface{}
+ err := _ArbitrumTokenGateway.contract.Call(opts, &out, "getOutboundCalldata", _token, _from, _to, _amount, _data)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewaySession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _ArbitrumTokenGateway.Contract.GetOutboundCalldata(&_ArbitrumTokenGateway.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayCallerSession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _ArbitrumTokenGateway.Contract.GetOutboundCalldata(&_ArbitrumTokenGateway.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayTransactor) FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.contract.Transact(opts, "finalizeInboundTransfer", _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewaySession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.Contract.FinalizeInboundTransfer(&_ArbitrumTokenGateway.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayTransactorSession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.Contract.FinalizeInboundTransfer(&_ArbitrumTokenGateway.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayTransactor) OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.contract.Transact(opts, "outboundTransfer", _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewaySession) OutboundTransfer(_token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.Contract.OutboundTransfer(&_ArbitrumTokenGateway.TransactOpts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGatewayTransactorSession) OutboundTransfer(_token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ return _ArbitrumTokenGateway.Contract.OutboundTransfer(&_ArbitrumTokenGateway.TransactOpts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+}
+
+func (_ArbitrumTokenGateway *ArbitrumTokenGateway) Address() common.Address {
+ return _ArbitrumTokenGateway.address
+}
+
+type ArbitrumTokenGatewayInterface interface {
+ CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error)
+
+ GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error)
+
+ FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error)
+
+ OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/arbsys/arbsys.go b/core/gethwrappers/liquiditymanager/generated/arbsys/arbsys.go
new file mode 100644
index 00000000000..fe9eb5e75bc
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/arbsys/arbsys.go
@@ -0,0 +1,940 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package arbsys
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var ArbSysMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"uniqueId\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"batchNumber\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"indexInBatch\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"arbBlockNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ethBlockNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callvalue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"L2ToL1Transaction\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"hash\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"position\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"arbBlockNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ethBlockNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"callvalue\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"L2ToL1Tx\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"reserved\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"hash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"position\",\"type\":\"uint256\"}],\"name\":\"SendMerkleUpdate\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"arbBlockNum\",\"type\":\"uint256\"}],\"name\":\"arbBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"arbBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"arbChainID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"arbOSVersion\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStorageGasAvailable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isTopLevelCall\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"unused\",\"type\":\"address\"}],\"name\":\"mapL1SenderContractAddressToL2Alias\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"myCallersAddressWithoutAliasing\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sendMerkleTreeState\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"partials\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"sendTxToL1\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wasMyCallersAddressAliased\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"withdrawEth\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+}
+
+var ArbSysABI = ArbSysMetaData.ABI
+
+type ArbSys struct {
+ address common.Address
+ abi abi.ABI
+ ArbSysCaller
+ ArbSysTransactor
+ ArbSysFilterer
+}
+
+type ArbSysCaller struct {
+ contract *bind.BoundContract
+}
+
+type ArbSysTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ArbSysFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ArbSysSession struct {
+ Contract *ArbSys
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ArbSysCallerSession struct {
+ Contract *ArbSysCaller
+ CallOpts bind.CallOpts
+}
+
+type ArbSysTransactorSession struct {
+ Contract *ArbSysTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ArbSysRaw struct {
+ Contract *ArbSys
+}
+
+type ArbSysCallerRaw struct {
+ Contract *ArbSysCaller
+}
+
+type ArbSysTransactorRaw struct {
+ Contract *ArbSysTransactor
+}
+
+func NewArbSys(address common.Address, backend bind.ContractBackend) (*ArbSys, error) {
+ abi, err := abi.JSON(strings.NewReader(ArbSysABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindArbSys(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbSys{address: address, abi: abi, ArbSysCaller: ArbSysCaller{contract: contract}, ArbSysTransactor: ArbSysTransactor{contract: contract}, ArbSysFilterer: ArbSysFilterer{contract: contract}}, nil
+}
+
+func NewArbSysCaller(address common.Address, caller bind.ContractCaller) (*ArbSysCaller, error) {
+ contract, err := bindArbSys(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbSysCaller{contract: contract}, nil
+}
+
+func NewArbSysTransactor(address common.Address, transactor bind.ContractTransactor) (*ArbSysTransactor, error) {
+ contract, err := bindArbSys(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbSysTransactor{contract: contract}, nil
+}
+
+func NewArbSysFilterer(address common.Address, filterer bind.ContractFilterer) (*ArbSysFilterer, error) {
+ contract, err := bindArbSys(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbSysFilterer{contract: contract}, nil
+}
+
+func bindArbSys(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ArbSysMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ArbSys *ArbSysRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbSys.Contract.ArbSysCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbSys *ArbSysRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbSys.Contract.ArbSysTransactor.contract.Transfer(opts)
+}
+
+func (_ArbSys *ArbSysRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbSys.Contract.ArbSysTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ArbSys *ArbSysCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ArbSys.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ArbSys *ArbSysTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ArbSys.Contract.contract.Transfer(opts)
+}
+
+func (_ArbSys *ArbSysTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ArbSys.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ArbSys *ArbSysCaller) ArbBlockHash(opts *bind.CallOpts, arbBlockNum *big.Int) ([32]byte, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "arbBlockHash", arbBlockNum)
+
+ if err != nil {
+ return *new([32]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) ArbBlockHash(arbBlockNum *big.Int) ([32]byte, error) {
+ return _ArbSys.Contract.ArbBlockHash(&_ArbSys.CallOpts, arbBlockNum)
+}
+
+func (_ArbSys *ArbSysCallerSession) ArbBlockHash(arbBlockNum *big.Int) ([32]byte, error) {
+ return _ArbSys.Contract.ArbBlockHash(&_ArbSys.CallOpts, arbBlockNum)
+}
+
+func (_ArbSys *ArbSysCaller) ArbBlockNumber(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "arbBlockNumber")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) ArbBlockNumber() (*big.Int, error) {
+ return _ArbSys.Contract.ArbBlockNumber(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCallerSession) ArbBlockNumber() (*big.Int, error) {
+ return _ArbSys.Contract.ArbBlockNumber(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCaller) ArbChainID(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "arbChainID")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) ArbChainID() (*big.Int, error) {
+ return _ArbSys.Contract.ArbChainID(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCallerSession) ArbChainID() (*big.Int, error) {
+ return _ArbSys.Contract.ArbChainID(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCaller) ArbOSVersion(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "arbOSVersion")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) ArbOSVersion() (*big.Int, error) {
+ return _ArbSys.Contract.ArbOSVersion(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCallerSession) ArbOSVersion() (*big.Int, error) {
+ return _ArbSys.Contract.ArbOSVersion(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCaller) GetStorageGasAvailable(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "getStorageGasAvailable")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) GetStorageGasAvailable() (*big.Int, error) {
+ return _ArbSys.Contract.GetStorageGasAvailable(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCallerSession) GetStorageGasAvailable() (*big.Int, error) {
+ return _ArbSys.Contract.GetStorageGasAvailable(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCaller) IsTopLevelCall(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "isTopLevelCall")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) IsTopLevelCall() (bool, error) {
+ return _ArbSys.Contract.IsTopLevelCall(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCallerSession) IsTopLevelCall() (bool, error) {
+ return _ArbSys.Contract.IsTopLevelCall(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCaller) MapL1SenderContractAddressToL2Alias(opts *bind.CallOpts, sender common.Address, unused common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "mapL1SenderContractAddressToL2Alias", sender, unused)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) MapL1SenderContractAddressToL2Alias(sender common.Address, unused common.Address) (common.Address, error) {
+ return _ArbSys.Contract.MapL1SenderContractAddressToL2Alias(&_ArbSys.CallOpts, sender, unused)
+}
+
+func (_ArbSys *ArbSysCallerSession) MapL1SenderContractAddressToL2Alias(sender common.Address, unused common.Address) (common.Address, error) {
+ return _ArbSys.Contract.MapL1SenderContractAddressToL2Alias(&_ArbSys.CallOpts, sender, unused)
+}
+
+func (_ArbSys *ArbSysCaller) MyCallersAddressWithoutAliasing(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "myCallersAddressWithoutAliasing")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) MyCallersAddressWithoutAliasing() (common.Address, error) {
+ return _ArbSys.Contract.MyCallersAddressWithoutAliasing(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCallerSession) MyCallersAddressWithoutAliasing() (common.Address, error) {
+ return _ArbSys.Contract.MyCallersAddressWithoutAliasing(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCaller) SendMerkleTreeState(opts *bind.CallOpts) (SendMerkleTreeState,
+
+ error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "sendMerkleTreeState")
+
+ outstruct := new(SendMerkleTreeState)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.Size = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+ outstruct.Root = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte)
+ outstruct.Partials = *abi.ConvertType(out[2], new([][32]byte)).(*[][32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_ArbSys *ArbSysSession) SendMerkleTreeState() (SendMerkleTreeState,
+
+ error) {
+ return _ArbSys.Contract.SendMerkleTreeState(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCallerSession) SendMerkleTreeState() (SendMerkleTreeState,
+
+ error) {
+ return _ArbSys.Contract.SendMerkleTreeState(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCaller) WasMyCallersAddressAliased(opts *bind.CallOpts) (bool, error) {
+ var out []interface{}
+ err := _ArbSys.contract.Call(opts, &out, "wasMyCallersAddressAliased")
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_ArbSys *ArbSysSession) WasMyCallersAddressAliased() (bool, error) {
+ return _ArbSys.Contract.WasMyCallersAddressAliased(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysCallerSession) WasMyCallersAddressAliased() (bool, error) {
+ return _ArbSys.Contract.WasMyCallersAddressAliased(&_ArbSys.CallOpts)
+}
+
+func (_ArbSys *ArbSysTransactor) SendTxToL1(opts *bind.TransactOpts, destination common.Address, data []byte) (*types.Transaction, error) {
+ return _ArbSys.contract.Transact(opts, "sendTxToL1", destination, data)
+}
+
+func (_ArbSys *ArbSysSession) SendTxToL1(destination common.Address, data []byte) (*types.Transaction, error) {
+ return _ArbSys.Contract.SendTxToL1(&_ArbSys.TransactOpts, destination, data)
+}
+
+func (_ArbSys *ArbSysTransactorSession) SendTxToL1(destination common.Address, data []byte) (*types.Transaction, error) {
+ return _ArbSys.Contract.SendTxToL1(&_ArbSys.TransactOpts, destination, data)
+}
+
+func (_ArbSys *ArbSysTransactor) WithdrawEth(opts *bind.TransactOpts, destination common.Address) (*types.Transaction, error) {
+ return _ArbSys.contract.Transact(opts, "withdrawEth", destination)
+}
+
+func (_ArbSys *ArbSysSession) WithdrawEth(destination common.Address) (*types.Transaction, error) {
+ return _ArbSys.Contract.WithdrawEth(&_ArbSys.TransactOpts, destination)
+}
+
+func (_ArbSys *ArbSysTransactorSession) WithdrawEth(destination common.Address) (*types.Transaction, error) {
+ return _ArbSys.Contract.WithdrawEth(&_ArbSys.TransactOpts, destination)
+}
+
+type ArbSysL2ToL1TransactionIterator struct {
+ Event *ArbSysL2ToL1Transaction
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbSysL2ToL1TransactionIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbSysL2ToL1Transaction)
+ 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(ArbSysL2ToL1Transaction)
+ 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 *ArbSysL2ToL1TransactionIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbSysL2ToL1TransactionIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbSysL2ToL1Transaction struct {
+ Caller common.Address
+ Destination common.Address
+ UniqueId *big.Int
+ BatchNumber *big.Int
+ IndexInBatch *big.Int
+ ArbBlockNum *big.Int
+ EthBlockNum *big.Int
+ Timestamp *big.Int
+ Callvalue *big.Int
+ Data []byte
+ Raw types.Log
+}
+
+func (_ArbSys *ArbSysFilterer) FilterL2ToL1Transaction(opts *bind.FilterOpts, destination []common.Address, uniqueId []*big.Int, batchNumber []*big.Int) (*ArbSysL2ToL1TransactionIterator, error) {
+
+ var destinationRule []interface{}
+ for _, destinationItem := range destination {
+ destinationRule = append(destinationRule, destinationItem)
+ }
+ var uniqueIdRule []interface{}
+ for _, uniqueIdItem := range uniqueId {
+ uniqueIdRule = append(uniqueIdRule, uniqueIdItem)
+ }
+ var batchNumberRule []interface{}
+ for _, batchNumberItem := range batchNumber {
+ batchNumberRule = append(batchNumberRule, batchNumberItem)
+ }
+
+ logs, sub, err := _ArbSys.contract.FilterLogs(opts, "L2ToL1Transaction", destinationRule, uniqueIdRule, batchNumberRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbSysL2ToL1TransactionIterator{contract: _ArbSys.contract, event: "L2ToL1Transaction", logs: logs, sub: sub}, nil
+}
+
+func (_ArbSys *ArbSysFilterer) WatchL2ToL1Transaction(opts *bind.WatchOpts, sink chan<- *ArbSysL2ToL1Transaction, destination []common.Address, uniqueId []*big.Int, batchNumber []*big.Int) (event.Subscription, error) {
+
+ var destinationRule []interface{}
+ for _, destinationItem := range destination {
+ destinationRule = append(destinationRule, destinationItem)
+ }
+ var uniqueIdRule []interface{}
+ for _, uniqueIdItem := range uniqueId {
+ uniqueIdRule = append(uniqueIdRule, uniqueIdItem)
+ }
+ var batchNumberRule []interface{}
+ for _, batchNumberItem := range batchNumber {
+ batchNumberRule = append(batchNumberRule, batchNumberItem)
+ }
+
+ logs, sub, err := _ArbSys.contract.WatchLogs(opts, "L2ToL1Transaction", destinationRule, uniqueIdRule, batchNumberRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbSysL2ToL1Transaction)
+ if err := _ArbSys.contract.UnpackLog(event, "L2ToL1Transaction", 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 (_ArbSys *ArbSysFilterer) ParseL2ToL1Transaction(log types.Log) (*ArbSysL2ToL1Transaction, error) {
+ event := new(ArbSysL2ToL1Transaction)
+ if err := _ArbSys.contract.UnpackLog(event, "L2ToL1Transaction", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbSysL2ToL1TxIterator struct {
+ Event *ArbSysL2ToL1Tx
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbSysL2ToL1TxIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbSysL2ToL1Tx)
+ 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(ArbSysL2ToL1Tx)
+ 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 *ArbSysL2ToL1TxIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbSysL2ToL1TxIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbSysL2ToL1Tx struct {
+ Caller common.Address
+ Destination common.Address
+ Hash *big.Int
+ Position *big.Int
+ ArbBlockNum *big.Int
+ EthBlockNum *big.Int
+ Timestamp *big.Int
+ Callvalue *big.Int
+ Data []byte
+ Raw types.Log
+}
+
+func (_ArbSys *ArbSysFilterer) FilterL2ToL1Tx(opts *bind.FilterOpts, destination []common.Address, hash []*big.Int, position []*big.Int) (*ArbSysL2ToL1TxIterator, error) {
+
+ var destinationRule []interface{}
+ for _, destinationItem := range destination {
+ destinationRule = append(destinationRule, destinationItem)
+ }
+ var hashRule []interface{}
+ for _, hashItem := range hash {
+ hashRule = append(hashRule, hashItem)
+ }
+ var positionRule []interface{}
+ for _, positionItem := range position {
+ positionRule = append(positionRule, positionItem)
+ }
+
+ logs, sub, err := _ArbSys.contract.FilterLogs(opts, "L2ToL1Tx", destinationRule, hashRule, positionRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbSysL2ToL1TxIterator{contract: _ArbSys.contract, event: "L2ToL1Tx", logs: logs, sub: sub}, nil
+}
+
+func (_ArbSys *ArbSysFilterer) WatchL2ToL1Tx(opts *bind.WatchOpts, sink chan<- *ArbSysL2ToL1Tx, destination []common.Address, hash []*big.Int, position []*big.Int) (event.Subscription, error) {
+
+ var destinationRule []interface{}
+ for _, destinationItem := range destination {
+ destinationRule = append(destinationRule, destinationItem)
+ }
+ var hashRule []interface{}
+ for _, hashItem := range hash {
+ hashRule = append(hashRule, hashItem)
+ }
+ var positionRule []interface{}
+ for _, positionItem := range position {
+ positionRule = append(positionRule, positionItem)
+ }
+
+ logs, sub, err := _ArbSys.contract.WatchLogs(opts, "L2ToL1Tx", destinationRule, hashRule, positionRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbSysL2ToL1Tx)
+ if err := _ArbSys.contract.UnpackLog(event, "L2ToL1Tx", 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 (_ArbSys *ArbSysFilterer) ParseL2ToL1Tx(log types.Log) (*ArbSysL2ToL1Tx, error) {
+ event := new(ArbSysL2ToL1Tx)
+ if err := _ArbSys.contract.UnpackLog(event, "L2ToL1Tx", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type ArbSysSendMerkleUpdateIterator struct {
+ Event *ArbSysSendMerkleUpdate
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *ArbSysSendMerkleUpdateIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(ArbSysSendMerkleUpdate)
+ 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(ArbSysSendMerkleUpdate)
+ 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 *ArbSysSendMerkleUpdateIterator) Error() error {
+ return it.fail
+}
+
+func (it *ArbSysSendMerkleUpdateIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type ArbSysSendMerkleUpdate struct {
+ Reserved *big.Int
+ Hash [32]byte
+ Position *big.Int
+ Raw types.Log
+}
+
+func (_ArbSys *ArbSysFilterer) FilterSendMerkleUpdate(opts *bind.FilterOpts, reserved []*big.Int, hash [][32]byte, position []*big.Int) (*ArbSysSendMerkleUpdateIterator, error) {
+
+ var reservedRule []interface{}
+ for _, reservedItem := range reserved {
+ reservedRule = append(reservedRule, reservedItem)
+ }
+ var hashRule []interface{}
+ for _, hashItem := range hash {
+ hashRule = append(hashRule, hashItem)
+ }
+ var positionRule []interface{}
+ for _, positionItem := range position {
+ positionRule = append(positionRule, positionItem)
+ }
+
+ logs, sub, err := _ArbSys.contract.FilterLogs(opts, "SendMerkleUpdate", reservedRule, hashRule, positionRule)
+ if err != nil {
+ return nil, err
+ }
+ return &ArbSysSendMerkleUpdateIterator{contract: _ArbSys.contract, event: "SendMerkleUpdate", logs: logs, sub: sub}, nil
+}
+
+func (_ArbSys *ArbSysFilterer) WatchSendMerkleUpdate(opts *bind.WatchOpts, sink chan<- *ArbSysSendMerkleUpdate, reserved []*big.Int, hash [][32]byte, position []*big.Int) (event.Subscription, error) {
+
+ var reservedRule []interface{}
+ for _, reservedItem := range reserved {
+ reservedRule = append(reservedRule, reservedItem)
+ }
+ var hashRule []interface{}
+ for _, hashItem := range hash {
+ hashRule = append(hashRule, hashItem)
+ }
+ var positionRule []interface{}
+ for _, positionItem := range position {
+ positionRule = append(positionRule, positionItem)
+ }
+
+ logs, sub, err := _ArbSys.contract.WatchLogs(opts, "SendMerkleUpdate", reservedRule, hashRule, positionRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(ArbSysSendMerkleUpdate)
+ if err := _ArbSys.contract.UnpackLog(event, "SendMerkleUpdate", 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 (_ArbSys *ArbSysFilterer) ParseSendMerkleUpdate(log types.Log) (*ArbSysSendMerkleUpdate, error) {
+ event := new(ArbSysSendMerkleUpdate)
+ if err := _ArbSys.contract.UnpackLog(event, "SendMerkleUpdate", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type SendMerkleTreeState struct {
+ Size *big.Int
+ Root [32]byte
+ Partials [][32]byte
+}
+
+func (_ArbSys *ArbSys) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _ArbSys.abi.Events["L2ToL1Transaction"].ID:
+ return _ArbSys.ParseL2ToL1Transaction(log)
+ case _ArbSys.abi.Events["L2ToL1Tx"].ID:
+ return _ArbSys.ParseL2ToL1Tx(log)
+ case _ArbSys.abi.Events["SendMerkleUpdate"].ID:
+ return _ArbSys.ParseSendMerkleUpdate(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (ArbSysL2ToL1Transaction) Topic() common.Hash {
+ return common.HexToHash("0x5baaa87db386365b5c161be377bc3d8e317e8d98d71a3ca7ed7d555340c8f767")
+}
+
+func (ArbSysL2ToL1Tx) Topic() common.Hash {
+ return common.HexToHash("0x3e7aafa77dbf186b7fd488006beff893744caa3c4f6f299e8a709fa2087374fc")
+}
+
+func (ArbSysSendMerkleUpdate) Topic() common.Hash {
+ return common.HexToHash("0xe9e13da364699fb5b0496ff5a0fc70760ad5836e93ba96568a4e42b9914a8b95")
+}
+
+func (_ArbSys *ArbSys) Address() common.Address {
+ return _ArbSys.address
+}
+
+type ArbSysInterface interface {
+ ArbBlockHash(opts *bind.CallOpts, arbBlockNum *big.Int) ([32]byte, error)
+
+ ArbBlockNumber(opts *bind.CallOpts) (*big.Int, error)
+
+ ArbChainID(opts *bind.CallOpts) (*big.Int, error)
+
+ ArbOSVersion(opts *bind.CallOpts) (*big.Int, error)
+
+ GetStorageGasAvailable(opts *bind.CallOpts) (*big.Int, error)
+
+ IsTopLevelCall(opts *bind.CallOpts) (bool, error)
+
+ MapL1SenderContractAddressToL2Alias(opts *bind.CallOpts, sender common.Address, unused common.Address) (common.Address, error)
+
+ MyCallersAddressWithoutAliasing(opts *bind.CallOpts) (common.Address, error)
+
+ SendMerkleTreeState(opts *bind.CallOpts) (SendMerkleTreeState,
+
+ error)
+
+ WasMyCallersAddressAliased(opts *bind.CallOpts) (bool, error)
+
+ SendTxToL1(opts *bind.TransactOpts, destination common.Address, data []byte) (*types.Transaction, error)
+
+ WithdrawEth(opts *bind.TransactOpts, destination common.Address) (*types.Transaction, error)
+
+ FilterL2ToL1Transaction(opts *bind.FilterOpts, destination []common.Address, uniqueId []*big.Int, batchNumber []*big.Int) (*ArbSysL2ToL1TransactionIterator, error)
+
+ WatchL2ToL1Transaction(opts *bind.WatchOpts, sink chan<- *ArbSysL2ToL1Transaction, destination []common.Address, uniqueId []*big.Int, batchNumber []*big.Int) (event.Subscription, error)
+
+ ParseL2ToL1Transaction(log types.Log) (*ArbSysL2ToL1Transaction, error)
+
+ FilterL2ToL1Tx(opts *bind.FilterOpts, destination []common.Address, hash []*big.Int, position []*big.Int) (*ArbSysL2ToL1TxIterator, error)
+
+ WatchL2ToL1Tx(opts *bind.WatchOpts, sink chan<- *ArbSysL2ToL1Tx, destination []common.Address, hash []*big.Int, position []*big.Int) (event.Subscription, error)
+
+ ParseL2ToL1Tx(log types.Log) (*ArbSysL2ToL1Tx, error)
+
+ FilterSendMerkleUpdate(opts *bind.FilterOpts, reserved []*big.Int, hash [][32]byte, position []*big.Int) (*ArbSysSendMerkleUpdateIterator, error)
+
+ WatchSendMerkleUpdate(opts *bind.WatchOpts, sink chan<- *ArbSysSendMerkleUpdate, reserved []*big.Int, hash [][32]byte, position []*big.Int) (event.Subscription, error)
+
+ ParseSendMerkleUpdate(log types.Log) (*ArbSysSendMerkleUpdate, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_gateway/l2_arbitrum_gateway.go b/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_gateway/l2_arbitrum_gateway.go
new file mode 100644
index 00000000000..4e5ab36f5db
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_gateway/l2_arbitrum_gateway.go
@@ -0,0 +1,823 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package l2_arbitrum_gateway
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var L2ArbitrumGatewayMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"DepositFinalized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"TxToL1\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"l1Token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_l2ToL1Id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_exitNum\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"WithdrawalInitiated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"l1ERC20\",\"type\":\"address\"}],\"name\":\"calculateL2TokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counterpartGateway\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"exitNum\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"finalizeInboundTransfer\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"getOutboundCalldata\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"outboundCalldata\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"outboundTransfer\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_l1Token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"outboundTransfer\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"res\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"postUpgradeInit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"router\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var L2ArbitrumGatewayABI = L2ArbitrumGatewayMetaData.ABI
+
+type L2ArbitrumGateway struct {
+ address common.Address
+ abi abi.ABI
+ L2ArbitrumGatewayCaller
+ L2ArbitrumGatewayTransactor
+ L2ArbitrumGatewayFilterer
+}
+
+type L2ArbitrumGatewayCaller struct {
+ contract *bind.BoundContract
+}
+
+type L2ArbitrumGatewayTransactor struct {
+ contract *bind.BoundContract
+}
+
+type L2ArbitrumGatewayFilterer struct {
+ contract *bind.BoundContract
+}
+
+type L2ArbitrumGatewaySession struct {
+ Contract *L2ArbitrumGateway
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type L2ArbitrumGatewayCallerSession struct {
+ Contract *L2ArbitrumGatewayCaller
+ CallOpts bind.CallOpts
+}
+
+type L2ArbitrumGatewayTransactorSession struct {
+ Contract *L2ArbitrumGatewayTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type L2ArbitrumGatewayRaw struct {
+ Contract *L2ArbitrumGateway
+}
+
+type L2ArbitrumGatewayCallerRaw struct {
+ Contract *L2ArbitrumGatewayCaller
+}
+
+type L2ArbitrumGatewayTransactorRaw struct {
+ Contract *L2ArbitrumGatewayTransactor
+}
+
+func NewL2ArbitrumGateway(address common.Address, backend bind.ContractBackend) (*L2ArbitrumGateway, error) {
+ abi, err := abi.JSON(strings.NewReader(L2ArbitrumGatewayABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindL2ArbitrumGateway(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumGateway{address: address, abi: abi, L2ArbitrumGatewayCaller: L2ArbitrumGatewayCaller{contract: contract}, L2ArbitrumGatewayTransactor: L2ArbitrumGatewayTransactor{contract: contract}, L2ArbitrumGatewayFilterer: L2ArbitrumGatewayFilterer{contract: contract}}, nil
+}
+
+func NewL2ArbitrumGatewayCaller(address common.Address, caller bind.ContractCaller) (*L2ArbitrumGatewayCaller, error) {
+ contract, err := bindL2ArbitrumGateway(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumGatewayCaller{contract: contract}, nil
+}
+
+func NewL2ArbitrumGatewayTransactor(address common.Address, transactor bind.ContractTransactor) (*L2ArbitrumGatewayTransactor, error) {
+ contract, err := bindL2ArbitrumGateway(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumGatewayTransactor{contract: contract}, nil
+}
+
+func NewL2ArbitrumGatewayFilterer(address common.Address, filterer bind.ContractFilterer) (*L2ArbitrumGatewayFilterer, error) {
+ contract, err := bindL2ArbitrumGateway(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumGatewayFilterer{contract: contract}, nil
+}
+
+func bindL2ArbitrumGateway(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := L2ArbitrumGatewayMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _L2ArbitrumGateway.Contract.L2ArbitrumGatewayCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.L2ArbitrumGatewayTransactor.contract.Transfer(opts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.L2ArbitrumGatewayTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _L2ArbitrumGateway.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.contract.Transfer(opts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCaller) CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _L2ArbitrumGateway.contract.Call(opts, &out, "calculateL2TokenAddress", l1ERC20)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _L2ArbitrumGateway.Contract.CalculateL2TokenAddress(&_L2ArbitrumGateway.CallOpts, l1ERC20)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCallerSession) CalculateL2TokenAddress(l1ERC20 common.Address) (common.Address, error) {
+ return _L2ArbitrumGateway.Contract.CalculateL2TokenAddress(&_L2ArbitrumGateway.CallOpts, l1ERC20)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCaller) CounterpartGateway(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _L2ArbitrumGateway.contract.Call(opts, &out, "counterpartGateway")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) CounterpartGateway() (common.Address, error) {
+ return _L2ArbitrumGateway.Contract.CounterpartGateway(&_L2ArbitrumGateway.CallOpts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCallerSession) CounterpartGateway() (common.Address, error) {
+ return _L2ArbitrumGateway.Contract.CounterpartGateway(&_L2ArbitrumGateway.CallOpts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCaller) ExitNum(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _L2ArbitrumGateway.contract.Call(opts, &out, "exitNum")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) ExitNum() (*big.Int, error) {
+ return _L2ArbitrumGateway.Contract.ExitNum(&_L2ArbitrumGateway.CallOpts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCallerSession) ExitNum() (*big.Int, error) {
+ return _L2ArbitrumGateway.Contract.ExitNum(&_L2ArbitrumGateway.CallOpts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCaller) GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ var out []interface{}
+ err := _L2ArbitrumGateway.contract.Call(opts, &out, "getOutboundCalldata", _token, _from, _to, _amount, _data)
+
+ if err != nil {
+ return *new([]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte)
+
+ return out0, err
+
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _L2ArbitrumGateway.Contract.GetOutboundCalldata(&_L2ArbitrumGateway.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCallerSession) GetOutboundCalldata(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ return _L2ArbitrumGateway.Contract.GetOutboundCalldata(&_L2ArbitrumGateway.CallOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCaller) Router(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _L2ArbitrumGateway.contract.Call(opts, &out, "router")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) Router() (common.Address, error) {
+ return _L2ArbitrumGateway.Contract.Router(&_L2ArbitrumGateway.CallOpts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayCallerSession) Router() (common.Address, error) {
+ return _L2ArbitrumGateway.Contract.Router(&_L2ArbitrumGateway.CallOpts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactor) FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.contract.Transact(opts, "finalizeInboundTransfer", _token, _from, _to, _amount, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.FinalizeInboundTransfer(&_L2ArbitrumGateway.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactorSession) FinalizeInboundTransfer(_token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.FinalizeInboundTransfer(&_L2ArbitrumGateway.TransactOpts, _token, _from, _to, _amount, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactor) OutboundTransfer(opts *bind.TransactOpts, _l1Token common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.contract.Transact(opts, "outboundTransfer", _l1Token, _to, _amount, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) OutboundTransfer(_l1Token common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.OutboundTransfer(&_L2ArbitrumGateway.TransactOpts, _l1Token, _to, _amount, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactorSession) OutboundTransfer(_l1Token common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.OutboundTransfer(&_L2ArbitrumGateway.TransactOpts, _l1Token, _to, _amount, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactor) OutboundTransfer0(opts *bind.TransactOpts, _l1Token common.Address, _to common.Address, _amount *big.Int, arg3 *big.Int, arg4 *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.contract.Transact(opts, "outboundTransfer0", _l1Token, _to, _amount, arg3, arg4, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) OutboundTransfer0(_l1Token common.Address, _to common.Address, _amount *big.Int, arg3 *big.Int, arg4 *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.OutboundTransfer0(&_L2ArbitrumGateway.TransactOpts, _l1Token, _to, _amount, arg3, arg4, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactorSession) OutboundTransfer0(_l1Token common.Address, _to common.Address, _amount *big.Int, arg3 *big.Int, arg4 *big.Int, _data []byte) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.OutboundTransfer0(&_L2ArbitrumGateway.TransactOpts, _l1Token, _to, _amount, arg3, arg4, _data)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactor) PostUpgradeInit(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _L2ArbitrumGateway.contract.Transact(opts, "postUpgradeInit")
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewaySession) PostUpgradeInit() (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.PostUpgradeInit(&_L2ArbitrumGateway.TransactOpts)
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayTransactorSession) PostUpgradeInit() (*types.Transaction, error) {
+ return _L2ArbitrumGateway.Contract.PostUpgradeInit(&_L2ArbitrumGateway.TransactOpts)
+}
+
+type L2ArbitrumGatewayDepositFinalizedIterator struct {
+ Event *L2ArbitrumGatewayDepositFinalized
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *L2ArbitrumGatewayDepositFinalizedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(L2ArbitrumGatewayDepositFinalized)
+ 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(L2ArbitrumGatewayDepositFinalized)
+ 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 *L2ArbitrumGatewayDepositFinalizedIterator) Error() error {
+ return it.fail
+}
+
+func (it *L2ArbitrumGatewayDepositFinalizedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type L2ArbitrumGatewayDepositFinalized struct {
+ L1Token common.Address
+ From common.Address
+ To common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) FilterDepositFinalized(opts *bind.FilterOpts, l1Token []common.Address, _from []common.Address, _to []common.Address) (*L2ArbitrumGatewayDepositFinalizedIterator, error) {
+
+ var l1TokenRule []interface{}
+ for _, l1TokenItem := range l1Token {
+ l1TokenRule = append(l1TokenRule, l1TokenItem)
+ }
+ var _fromRule []interface{}
+ for _, _fromItem := range _from {
+ _fromRule = append(_fromRule, _fromItem)
+ }
+ var _toRule []interface{}
+ for _, _toItem := range _to {
+ _toRule = append(_toRule, _toItem)
+ }
+
+ logs, sub, err := _L2ArbitrumGateway.contract.FilterLogs(opts, "DepositFinalized", l1TokenRule, _fromRule, _toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumGatewayDepositFinalizedIterator{contract: _L2ArbitrumGateway.contract, event: "DepositFinalized", logs: logs, sub: sub}, nil
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) WatchDepositFinalized(opts *bind.WatchOpts, sink chan<- *L2ArbitrumGatewayDepositFinalized, l1Token []common.Address, _from []common.Address, _to []common.Address) (event.Subscription, error) {
+
+ var l1TokenRule []interface{}
+ for _, l1TokenItem := range l1Token {
+ l1TokenRule = append(l1TokenRule, l1TokenItem)
+ }
+ var _fromRule []interface{}
+ for _, _fromItem := range _from {
+ _fromRule = append(_fromRule, _fromItem)
+ }
+ var _toRule []interface{}
+ for _, _toItem := range _to {
+ _toRule = append(_toRule, _toItem)
+ }
+
+ logs, sub, err := _L2ArbitrumGateway.contract.WatchLogs(opts, "DepositFinalized", l1TokenRule, _fromRule, _toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(L2ArbitrumGatewayDepositFinalized)
+ if err := _L2ArbitrumGateway.contract.UnpackLog(event, "DepositFinalized", 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 (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) ParseDepositFinalized(log types.Log) (*L2ArbitrumGatewayDepositFinalized, error) {
+ event := new(L2ArbitrumGatewayDepositFinalized)
+ if err := _L2ArbitrumGateway.contract.UnpackLog(event, "DepositFinalized", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type L2ArbitrumGatewayTxToL1Iterator struct {
+ Event *L2ArbitrumGatewayTxToL1
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *L2ArbitrumGatewayTxToL1Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(L2ArbitrumGatewayTxToL1)
+ 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(L2ArbitrumGatewayTxToL1)
+ 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 *L2ArbitrumGatewayTxToL1Iterator) Error() error {
+ return it.fail
+}
+
+func (it *L2ArbitrumGatewayTxToL1Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type L2ArbitrumGatewayTxToL1 struct {
+ From common.Address
+ To common.Address
+ Id *big.Int
+ Data []byte
+ Raw types.Log
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) FilterTxToL1(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _id []*big.Int) (*L2ArbitrumGatewayTxToL1Iterator, error) {
+
+ var _fromRule []interface{}
+ for _, _fromItem := range _from {
+ _fromRule = append(_fromRule, _fromItem)
+ }
+ var _toRule []interface{}
+ for _, _toItem := range _to {
+ _toRule = append(_toRule, _toItem)
+ }
+ var _idRule []interface{}
+ for _, _idItem := range _id {
+ _idRule = append(_idRule, _idItem)
+ }
+
+ logs, sub, err := _L2ArbitrumGateway.contract.FilterLogs(opts, "TxToL1", _fromRule, _toRule, _idRule)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumGatewayTxToL1Iterator{contract: _L2ArbitrumGateway.contract, event: "TxToL1", logs: logs, sub: sub}, nil
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) WatchTxToL1(opts *bind.WatchOpts, sink chan<- *L2ArbitrumGatewayTxToL1, _from []common.Address, _to []common.Address, _id []*big.Int) (event.Subscription, error) {
+
+ var _fromRule []interface{}
+ for _, _fromItem := range _from {
+ _fromRule = append(_fromRule, _fromItem)
+ }
+ var _toRule []interface{}
+ for _, _toItem := range _to {
+ _toRule = append(_toRule, _toItem)
+ }
+ var _idRule []interface{}
+ for _, _idItem := range _id {
+ _idRule = append(_idRule, _idItem)
+ }
+
+ logs, sub, err := _L2ArbitrumGateway.contract.WatchLogs(opts, "TxToL1", _fromRule, _toRule, _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(L2ArbitrumGatewayTxToL1)
+ if err := _L2ArbitrumGateway.contract.UnpackLog(event, "TxToL1", 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 (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) ParseTxToL1(log types.Log) (*L2ArbitrumGatewayTxToL1, error) {
+ event := new(L2ArbitrumGatewayTxToL1)
+ if err := _L2ArbitrumGateway.contract.UnpackLog(event, "TxToL1", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type L2ArbitrumGatewayWithdrawalInitiatedIterator struct {
+ Event *L2ArbitrumGatewayWithdrawalInitiated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *L2ArbitrumGatewayWithdrawalInitiatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(L2ArbitrumGatewayWithdrawalInitiated)
+ 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(L2ArbitrumGatewayWithdrawalInitiated)
+ 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 *L2ArbitrumGatewayWithdrawalInitiatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *L2ArbitrumGatewayWithdrawalInitiatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type L2ArbitrumGatewayWithdrawalInitiated struct {
+ L1Token common.Address
+ From common.Address
+ To common.Address
+ L2ToL1Id *big.Int
+ ExitNum *big.Int
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) FilterWithdrawalInitiated(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _l2ToL1Id []*big.Int) (*L2ArbitrumGatewayWithdrawalInitiatedIterator, error) {
+
+ var _fromRule []interface{}
+ for _, _fromItem := range _from {
+ _fromRule = append(_fromRule, _fromItem)
+ }
+ var _toRule []interface{}
+ for _, _toItem := range _to {
+ _toRule = append(_toRule, _toItem)
+ }
+ var _l2ToL1IdRule []interface{}
+ for _, _l2ToL1IdItem := range _l2ToL1Id {
+ _l2ToL1IdRule = append(_l2ToL1IdRule, _l2ToL1IdItem)
+ }
+
+ logs, sub, err := _L2ArbitrumGateway.contract.FilterLogs(opts, "WithdrawalInitiated", _fromRule, _toRule, _l2ToL1IdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumGatewayWithdrawalInitiatedIterator{contract: _L2ArbitrumGateway.contract, event: "WithdrawalInitiated", logs: logs, sub: sub}, nil
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) WatchWithdrawalInitiated(opts *bind.WatchOpts, sink chan<- *L2ArbitrumGatewayWithdrawalInitiated, _from []common.Address, _to []common.Address, _l2ToL1Id []*big.Int) (event.Subscription, error) {
+
+ var _fromRule []interface{}
+ for _, _fromItem := range _from {
+ _fromRule = append(_fromRule, _fromItem)
+ }
+ var _toRule []interface{}
+ for _, _toItem := range _to {
+ _toRule = append(_toRule, _toItem)
+ }
+ var _l2ToL1IdRule []interface{}
+ for _, _l2ToL1IdItem := range _l2ToL1Id {
+ _l2ToL1IdRule = append(_l2ToL1IdRule, _l2ToL1IdItem)
+ }
+
+ logs, sub, err := _L2ArbitrumGateway.contract.WatchLogs(opts, "WithdrawalInitiated", _fromRule, _toRule, _l2ToL1IdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(L2ArbitrumGatewayWithdrawalInitiated)
+ if err := _L2ArbitrumGateway.contract.UnpackLog(event, "WithdrawalInitiated", 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 (_L2ArbitrumGateway *L2ArbitrumGatewayFilterer) ParseWithdrawalInitiated(log types.Log) (*L2ArbitrumGatewayWithdrawalInitiated, error) {
+ event := new(L2ArbitrumGatewayWithdrawalInitiated)
+ if err := _L2ArbitrumGateway.contract.UnpackLog(event, "WithdrawalInitiated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGateway) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _L2ArbitrumGateway.abi.Events["DepositFinalized"].ID:
+ return _L2ArbitrumGateway.ParseDepositFinalized(log)
+ case _L2ArbitrumGateway.abi.Events["TxToL1"].ID:
+ return _L2ArbitrumGateway.ParseTxToL1(log)
+ case _L2ArbitrumGateway.abi.Events["WithdrawalInitiated"].ID:
+ return _L2ArbitrumGateway.ParseWithdrawalInitiated(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (L2ArbitrumGatewayDepositFinalized) Topic() common.Hash {
+ return common.HexToHash("0xc7f2e9c55c40a50fbc217dfc70cd39a222940dfa62145aa0ca49eb9535d4fcb2")
+}
+
+func (L2ArbitrumGatewayTxToL1) Topic() common.Hash {
+ return common.HexToHash("0x2b986d32a0536b7e19baa48ab949fec7b903b7fad7730820b20632d100cc3a68")
+}
+
+func (L2ArbitrumGatewayWithdrawalInitiated) Topic() common.Hash {
+ return common.HexToHash("0x3073a74ecb728d10be779fe19a74a1428e20468f5b4d167bf9c73d9067847d73")
+}
+
+func (_L2ArbitrumGateway *L2ArbitrumGateway) Address() common.Address {
+ return _L2ArbitrumGateway.address
+}
+
+type L2ArbitrumGatewayInterface interface {
+ CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error)
+
+ CounterpartGateway(opts *bind.CallOpts) (common.Address, error)
+
+ ExitNum(opts *bind.CallOpts) (*big.Int, error)
+
+ GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error)
+
+ Router(opts *bind.CallOpts) (common.Address, error)
+
+ FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error)
+
+ OutboundTransfer(opts *bind.TransactOpts, _l1Token common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error)
+
+ OutboundTransfer0(opts *bind.TransactOpts, _l1Token common.Address, _to common.Address, _amount *big.Int, arg3 *big.Int, arg4 *big.Int, _data []byte) (*types.Transaction, error)
+
+ PostUpgradeInit(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterDepositFinalized(opts *bind.FilterOpts, l1Token []common.Address, _from []common.Address, _to []common.Address) (*L2ArbitrumGatewayDepositFinalizedIterator, error)
+
+ WatchDepositFinalized(opts *bind.WatchOpts, sink chan<- *L2ArbitrumGatewayDepositFinalized, l1Token []common.Address, _from []common.Address, _to []common.Address) (event.Subscription, error)
+
+ ParseDepositFinalized(log types.Log) (*L2ArbitrumGatewayDepositFinalized, error)
+
+ FilterTxToL1(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _id []*big.Int) (*L2ArbitrumGatewayTxToL1Iterator, error)
+
+ WatchTxToL1(opts *bind.WatchOpts, sink chan<- *L2ArbitrumGatewayTxToL1, _from []common.Address, _to []common.Address, _id []*big.Int) (event.Subscription, error)
+
+ ParseTxToL1(log types.Log) (*L2ArbitrumGatewayTxToL1, error)
+
+ FilterWithdrawalInitiated(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _l2ToL1Id []*big.Int) (*L2ArbitrumGatewayWithdrawalInitiatedIterator, error)
+
+ WatchWithdrawalInitiated(opts *bind.WatchOpts, sink chan<- *L2ArbitrumGatewayWithdrawalInitiated, _from []common.Address, _to []common.Address, _l2ToL1Id []*big.Int) (event.Subscription, error)
+
+ ParseWithdrawalInitiated(log types.Log) (*L2ArbitrumGatewayWithdrawalInitiated, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_messenger/l2_arbitrum_messenger.go b/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_messenger/l2_arbitrum_messenger.go
new file mode 100644
index 00000000000..4aa2952efcf
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_messenger/l2_arbitrum_messenger.go
@@ -0,0 +1,329 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package l2_arbitrum_messenger
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var L2ArbitrumMessengerMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"TxToL1\",\"type\":\"event\"}]",
+}
+
+var L2ArbitrumMessengerABI = L2ArbitrumMessengerMetaData.ABI
+
+type L2ArbitrumMessenger struct {
+ address common.Address
+ abi abi.ABI
+ L2ArbitrumMessengerCaller
+ L2ArbitrumMessengerTransactor
+ L2ArbitrumMessengerFilterer
+}
+
+type L2ArbitrumMessengerCaller struct {
+ contract *bind.BoundContract
+}
+
+type L2ArbitrumMessengerTransactor struct {
+ contract *bind.BoundContract
+}
+
+type L2ArbitrumMessengerFilterer struct {
+ contract *bind.BoundContract
+}
+
+type L2ArbitrumMessengerSession struct {
+ Contract *L2ArbitrumMessenger
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type L2ArbitrumMessengerCallerSession struct {
+ Contract *L2ArbitrumMessengerCaller
+ CallOpts bind.CallOpts
+}
+
+type L2ArbitrumMessengerTransactorSession struct {
+ Contract *L2ArbitrumMessengerTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type L2ArbitrumMessengerRaw struct {
+ Contract *L2ArbitrumMessenger
+}
+
+type L2ArbitrumMessengerCallerRaw struct {
+ Contract *L2ArbitrumMessengerCaller
+}
+
+type L2ArbitrumMessengerTransactorRaw struct {
+ Contract *L2ArbitrumMessengerTransactor
+}
+
+func NewL2ArbitrumMessenger(address common.Address, backend bind.ContractBackend) (*L2ArbitrumMessenger, error) {
+ abi, err := abi.JSON(strings.NewReader(L2ArbitrumMessengerABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindL2ArbitrumMessenger(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumMessenger{address: address, abi: abi, L2ArbitrumMessengerCaller: L2ArbitrumMessengerCaller{contract: contract}, L2ArbitrumMessengerTransactor: L2ArbitrumMessengerTransactor{contract: contract}, L2ArbitrumMessengerFilterer: L2ArbitrumMessengerFilterer{contract: contract}}, nil
+}
+
+func NewL2ArbitrumMessengerCaller(address common.Address, caller bind.ContractCaller) (*L2ArbitrumMessengerCaller, error) {
+ contract, err := bindL2ArbitrumMessenger(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumMessengerCaller{contract: contract}, nil
+}
+
+func NewL2ArbitrumMessengerTransactor(address common.Address, transactor bind.ContractTransactor) (*L2ArbitrumMessengerTransactor, error) {
+ contract, err := bindL2ArbitrumMessenger(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumMessengerTransactor{contract: contract}, nil
+}
+
+func NewL2ArbitrumMessengerFilterer(address common.Address, filterer bind.ContractFilterer) (*L2ArbitrumMessengerFilterer, error) {
+ contract, err := bindL2ArbitrumMessenger(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumMessengerFilterer{contract: contract}, nil
+}
+
+func bindL2ArbitrumMessenger(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := L2ArbitrumMessengerMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessengerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _L2ArbitrumMessenger.Contract.L2ArbitrumMessengerCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessengerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _L2ArbitrumMessenger.Contract.L2ArbitrumMessengerTransactor.contract.Transfer(opts)
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessengerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _L2ArbitrumMessenger.Contract.L2ArbitrumMessengerTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessengerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _L2ArbitrumMessenger.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessengerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _L2ArbitrumMessenger.Contract.contract.Transfer(opts)
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessengerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _L2ArbitrumMessenger.Contract.contract.Transact(opts, method, params...)
+}
+
+type L2ArbitrumMessengerTxToL1Iterator struct {
+ Event *L2ArbitrumMessengerTxToL1
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *L2ArbitrumMessengerTxToL1Iterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(L2ArbitrumMessengerTxToL1)
+ 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(L2ArbitrumMessengerTxToL1)
+ 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 *L2ArbitrumMessengerTxToL1Iterator) Error() error {
+ return it.fail
+}
+
+func (it *L2ArbitrumMessengerTxToL1Iterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type L2ArbitrumMessengerTxToL1 struct {
+ From common.Address
+ To common.Address
+ Id *big.Int
+ Data []byte
+ Raw types.Log
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessengerFilterer) FilterTxToL1(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _id []*big.Int) (*L2ArbitrumMessengerTxToL1Iterator, error) {
+
+ var _fromRule []interface{}
+ for _, _fromItem := range _from {
+ _fromRule = append(_fromRule, _fromItem)
+ }
+ var _toRule []interface{}
+ for _, _toItem := range _to {
+ _toRule = append(_toRule, _toItem)
+ }
+ var _idRule []interface{}
+ for _, _idItem := range _id {
+ _idRule = append(_idRule, _idItem)
+ }
+
+ logs, sub, err := _L2ArbitrumMessenger.contract.FilterLogs(opts, "TxToL1", _fromRule, _toRule, _idRule)
+ if err != nil {
+ return nil, err
+ }
+ return &L2ArbitrumMessengerTxToL1Iterator{contract: _L2ArbitrumMessenger.contract, event: "TxToL1", logs: logs, sub: sub}, nil
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessengerFilterer) WatchTxToL1(opts *bind.WatchOpts, sink chan<- *L2ArbitrumMessengerTxToL1, _from []common.Address, _to []common.Address, _id []*big.Int) (event.Subscription, error) {
+
+ var _fromRule []interface{}
+ for _, _fromItem := range _from {
+ _fromRule = append(_fromRule, _fromItem)
+ }
+ var _toRule []interface{}
+ for _, _toItem := range _to {
+ _toRule = append(_toRule, _toItem)
+ }
+ var _idRule []interface{}
+ for _, _idItem := range _id {
+ _idRule = append(_idRule, _idItem)
+ }
+
+ logs, sub, err := _L2ArbitrumMessenger.contract.WatchLogs(opts, "TxToL1", _fromRule, _toRule, _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(L2ArbitrumMessengerTxToL1)
+ if err := _L2ArbitrumMessenger.contract.UnpackLog(event, "TxToL1", 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 (_L2ArbitrumMessenger *L2ArbitrumMessengerFilterer) ParseTxToL1(log types.Log) (*L2ArbitrumMessengerTxToL1, error) {
+ event := new(L2ArbitrumMessengerTxToL1)
+ if err := _L2ArbitrumMessenger.contract.UnpackLog(event, "TxToL1", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessenger) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _L2ArbitrumMessenger.abi.Events["TxToL1"].ID:
+ return _L2ArbitrumMessenger.ParseTxToL1(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (L2ArbitrumMessengerTxToL1) Topic() common.Hash {
+ return common.HexToHash("0x2b986d32a0536b7e19baa48ab949fec7b903b7fad7730820b20632d100cc3a68")
+}
+
+func (_L2ArbitrumMessenger *L2ArbitrumMessenger) Address() common.Address {
+ return _L2ArbitrumMessenger.address
+}
+
+type L2ArbitrumMessengerInterface interface {
+ FilterTxToL1(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _id []*big.Int) (*L2ArbitrumMessengerTxToL1Iterator, error)
+
+ WatchTxToL1(opts *bind.WatchOpts, sink chan<- *L2ArbitrumMessengerTxToL1, _from []common.Address, _to []common.Address, _id []*big.Int) (event.Subscription, error)
+
+ ParseTxToL1(log types.Log) (*L2ArbitrumMessengerTxToL1, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/liquiditymanager/liquiditymanager.go b/core/gethwrappers/liquiditymanager/generated/liquiditymanager/liquiditymanager.go
new file mode 100644
index 00000000000..6c0cfd3f6f9
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/liquiditymanager/liquiditymanager.go
@@ -0,0 +1,2878 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package liquiditymanager
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ILiquidityManagerCrossChainRebalancerArgs struct {
+ RemoteRebalancer common.Address
+ LocalBridge common.Address
+ RemoteToken common.Address
+ RemoteChainSelector uint64
+ Enabled bool
+}
+
+type LiquidityManagerCrossChainRebalancer struct {
+ RemoteRebalancer common.Address
+ LocalBridge common.Address
+ RemoteToken common.Address
+ Enabled bool
+}
+
+var LiquidityManagerMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"localChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"contractILiquidityContainer\",\"name\":\"localLiquidityContainer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minimumLiquidity\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"finance\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyReport\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requested\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"available\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"reserve\",\"type\":\"uint256\"}],\"name\":\"InsufficientLiquidity\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidRemoteChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"latestSequenceNumber\",\"type\":\"uint64\"}],\"name\":\"NonIncreasingSequenceNumber\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyFinanceRole\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroChainSelector\",\"type\":\"error\"},{\"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\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"contractIBridgeAdapter\",\"name\":\"localBridge\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"remoteRebalancer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"name\":\"CrossChainRebalancerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"ocrSeqNum\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"bridgeSpecificData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"reason\",\"type\":\"bytes\"}],\"name\":\"FinalizationFailed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"ocrSeqNum\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"bridgeSpecificData\",\"type\":\"bytes\"}],\"name\":\"FinalizationStepCompleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"financeRole\",\"type\":\"address\"}],\"name\":\"FinanceRoleSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityAddedToContainer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newLiquidityContainer\",\"type\":\"address\"}],\"name\":\"LiquidityContainerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"remover\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityRemovedFromContainer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"ocrSeqNum\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"fromChainSelector\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"toChainSelector\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"bridgeSpecificData\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"bridgeReturnData\",\"type\":\"bytes\"}],\"name\":\"LiquidityTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldBalance\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newBalance\",\"type\":\"uint256\"}],\"name\":\"MinimumLiquiditySet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"depositor\",\"type\":\"address\"}],\"name\":\"NativeDeposited\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"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\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"addLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllCrossChainRebalancers\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"remoteRebalancer\",\"type\":\"address\"},{\"internalType\":\"contractIBridgeAdapter\",\"name\":\"localBridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structILiquidityManager.CrossChainRebalancerArgs[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"}],\"name\":\"getCrossChainRebalancer\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"remoteRebalancer\",\"type\":\"address\"},{\"internalType\":\"contractIBridgeAdapter\",\"name\":\"localBridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structLiquidityManager.CrossChainRebalancer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFinanceRole\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLiquidity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"currentLiquidity\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLocalLiquidityContainer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMinimumLiquidity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSupportedDestChains\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_localToken\",\"outputs\":[{\"internalType\":\"contractIERC20\",\"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\":\"latestSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"chainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nativeBridgeFee\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"bridgeSpecificPayload\",\"type\":\"bytes\"}],\"name\":\"rebalanceLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"shouldWrapNative\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"bridgeSpecificPayload\",\"type\":\"bytes\"}],\"name\":\"receiveLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"removeLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"remoteRebalancer\",\"type\":\"address\"},{\"internalType\":\"contractIBridgeAdapter\",\"name\":\"localBridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structILiquidityManager.CrossChainRebalancerArgs\",\"name\":\"crossChainLiqManager\",\"type\":\"tuple\"}],\"name\":\"setCrossChainRebalancer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"remoteRebalancer\",\"type\":\"address\"},{\"internalType\":\"contractIBridgeAdapter\",\"name\":\"localBridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structILiquidityManager.CrossChainRebalancerArgs[]\",\"name\":\"crossChainRebalancers\",\"type\":\"tuple[]\"}],\"name\":\"setCrossChainRebalancers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"finance\",\"type\":\"address\"}],\"name\":\"setFinanceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractILiquidityContainer\",\"name\":\"localLiquidityContainer\",\"type\":\"address\"}],\"name\":\"setLocalLiquidityContainer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minimumLiquidity\",\"type\":\"uint256\"}],\"name\":\"setMinimumLiquidity\",\"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\":\"onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setOCR3Config\",\"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\":\"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\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"addresspayable\",\"name\":\"destination\",\"type\":\"address\"}],\"name\":\"withdrawNative\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
+ Bin: "0x60e06040523480156200001157600080fd5b5060405162004b8538038062004b85833981016040819052620000349162000239565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be8162000175565b505046608052506001600160401b038416600003620000f05760405163f89d762960e01b815260040160405180910390fd5b6001600160a01b03851615806200010e57506001600160a01b038316155b156200012d5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0394851660a0526001600160401b0390931660c052600b80549285166001600160a01b0319938416179055600855600c8054929093169116179055620002b8565b336001600160a01b03821603620001cf5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b03811681146200023657600080fd5b50565b600080600080600060a086880312156200025257600080fd5b85516200025f8162000220565b60208701519095506001600160401b03811681146200027d57600080fd5b6040870151909450620002908162000220565b606087015160808801519194509250620002aa8162000220565b809150509295509295909350565b60805160a05160c0516148576200032e6000396000818161321a01526133ef0152600081816104850152818161078201528181610a1f01528181610a6501528181611762015281816130f801528181613179015281816132a201526133400152600081816118ff015261194b01526148576000f3fe6080604052600436106101bb5760003560e01c8063791781f5116100ec578063b7e7fa051161008a578063f1c0461611610064578063f1c0461614610696578063f2fde38b146106d5578063f8c2d8fa146106f5578063fe65d5af1461071557600080fd5b8063b7e7fa051461062b578063b8ca8dd81461064b578063da9c0f961461066b57600080fd5b806383d34afe116100c657806383d34afe146105ab5780638da5cb5b146105c05780639c8f9f23146105eb578063b1dc65a41461060b57600080fd5b8063791781f51461052e57806379ba50971461055957806381ff70481461056e57600080fd5b806351c6590a116101595780636511d919116101335780636511d91914610473578063666cab8d146104cc5780636a11ee90146104ee578063706bf6451461050e57600080fd5b806351c6590a14610321578063568446e7146103415780635fc3ea0b1461045357600080fd5b80633275636e116101955780633275636e1461029f578063348759c1146102bf5780634f814d04146102e157806350a197d71461030157600080fd5b80630910a510146101ff578063181f5a7714610227578063282567b41461027d57600080fd5b366101fa57604080513481523360208201527f3c597f6ac9fe7f0ed6da50b07618f5850a642e459ad587f7fab491a71f8b0ab8910160405180910390a1005b600080fd5b34801561020b57600080fd5b50610214610737565b6040519081526020015b60405180910390f35b34801561023357600080fd5b506102706040518060400160405280601a81526020017f4c69717569646974794d616e6167657220312e302e302d64657600000000000081525081565b60405161021e91906139c6565b34801561028957600080fd5b5061029d6102983660046139e0565b6107f2565b005b3480156102ab57600080fd5b5061029d6102ba3660046139f9565b61083f565b3480156102cb57600080fd5b506102d4610853565b60405161021e9190613a11565b3480156102ed57600080fd5b5061029d6102fc366004613a81565b6108df565b34801561030d57600080fd5b5061029d61031c366004613b12565b610960565b34801561032d57600080fd5b5061029d61033c3660046139e0565b610a05565b34801561034d57600080fd5b5061040461035c366004613b83565b6040805160808101825260008082526020820181905291810182905260608101919091525067ffffffffffffffff166000908152600960209081526040918290208251608081018452815473ffffffffffffffffffffffffffffffffffffffff908116825260018301548116938201939093526002909101549182169281019290925274010000000000000000000000000000000000000000900460ff161515606082015290565b60408051825173ffffffffffffffffffffffffffffffffffffffff908116825260208085015182169083015283830151169181019190915260609182015115159181019190915260800161021e565b34801561045f57600080fd5b5061029d61046e366004613b9e565b610b42565b34801561047f57600080fd5b506104a77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161021e565b3480156104d857600080fd5b506104e1610bb9565b60405161021e9190613c32565b3480156104fa57600080fd5b5061029d610509366004613e53565b610c27565b34801561051a57600080fd5b5061029d610529366004613a81565b61145b565b34801561053a57600080fd5b50600b5473ffffffffffffffffffffffffffffffffffffffff166104a7565b34801561056557600080fd5b5061029d61151f565b34801561057a57600080fd5b506004546002546040805163ffffffff8085168252640100000000909404909316602084015282015260600161021e565b3480156105b757600080fd5b50600854610214565b3480156105cc57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166104a7565b3480156105f757600080fd5b5061029d6106063660046139e0565b61161c565b34801561061757600080fd5b5061029d610626366004613f65565b6117bc565b34801561063757600080fd5b5061029d61064636600461401c565b611e2d565b34801561065757600080fd5b5061029d610666366004614091565b611e68565b34801561067757600080fd5b50600c5473ffffffffffffffffffffffffffffffffffffffff166104a7565b3480156106a257600080fd5b5060045468010000000000000000900467ffffffffffffffff1660405167ffffffffffffffff909116815260200161021e565b3480156106e157600080fd5b5061029d6106f0366004613a81565b611fa6565b34801561070157600080fd5b5061029d6107103660046140c1565b611fb7565b34801561072157600080fd5b5061072a612053565b60405161021e919061410c565b600b546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed91906141a1565b905090565b6107fa612214565b600880549082905560408051828152602081018490527ff97e758c8b3d81df7b0e1b7327a6a7fcf09a41536b2d274b9103015d715f11eb910160405180910390a15050565b610847612214565b61085081612297565b50565b6060600a8054806020026020016040519081016040528092919081815260200182805480156108d557602002820191906000526020600020906000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff16815260200190600801906020826007010492830192600103820291508084116108905790505b5050505050905090565b6108e7612214565b600c80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f58024d20c07d3ebb87b192861d337d3a60995665acc5b8ce29596458b1f251709060200160405180910390a150565b600c5473ffffffffffffffffffffffffffffffffffffffff1633146109b1576040517fb2a59b2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109fe858584848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525089925067ffffffffffffffff91506126939050565b5050505050565b610a4773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084612918565b600b54610a8e9073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081169116836129fa565b600b546040517feb521a4c0000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff9091169063eb521a4c90602401600060405180830381600087803b158015610afa57600080fd5b505af1158015610b0e573d6000803e3d6000fd5b50506040518392503391507f5414b81d05ac3542606f164e16a9a107d05d21e906539cc5ceb61d7b6b707eb590600090a350565b600c5473ffffffffffffffffffffffffffffffffffffffff163314610b93576040517fb2a59b2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bb473ffffffffffffffffffffffffffffffffffffffff84168284612b7c565b505050565b606060078054806020026020016040519081016040528092919081815260200182805480156108d557602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610bf3575050505050905090565b855185518560ff16601f831115610c9f576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064015b60405180910390fd5b80600003610d09576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610c96565b818314610d97576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610c96565b610da28160036141e9565b8311610e0a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610c96565b610e12612214565b60065460005b81811015610f06576005600060068381548110610e3757610e37614206565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560078054600592919084908110610ea757610ea7614206565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055600101610e18565b50895160005b818110156112d95760008c8281518110610f2857610f28614206565b6020026020010151905060006002811115610f4557610f45614235565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff166002811115610f8457610f84614235565b14610feb576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610c96565b73ffffffffffffffffffffffffffffffffffffffff8116611038576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016001905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156110e8576110e8614235565b021790555090505060008c838151811061110457611104614206565b602002602001015190506000600281111561112157611121614235565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff16600281111561116057611160614235565b146111c7576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610c96565b73ffffffffffffffffffffffffffffffffffffffff8116611214576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff84168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156112c4576112c4614235565b02179055509050505050806001019050610f0c565b508a516112ed9060069060208e019061389a565b5089516113019060079060208d019061389a565b506003805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908c1617179055600480546113879146913091906000906113599063ffffffff16614264565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168e8e8e8e8e8e612bd2565b600260000181905550600060048054906101000a900463ffffffff169050436004806101000a81548163ffffffff021916908363ffffffff1602179055506000600460086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600260000154600460009054906101000a900463ffffffff168f8f8f8f8f8f60405161144599989796959493929190614287565b60405180910390a1505050505050505050505050565b611463612214565b73ffffffffffffffffffffffffffffffffffffffff81166114b0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f07dc474694ac40123aadcd2445f1b38d2eb353edd9319dcea043548ab34990ec90600090a250565b60015473ffffffffffffffffffffffffffffffffffffffff1633146115a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610c96565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600c5473ffffffffffffffffffffffffffffffffffffffff16331461166d576040517fb2a59b2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611677610737565b9050818110156116c4576040517fd54d0fc4000000000000000000000000000000000000000000000000000000008152600481018390526024810182905260006044820152606401610c96565b600b546040517f0a861f2a0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff90911690630a861f2a90602401600060405180830381600087803b15801561173057600080fd5b505af1158015611744573d6000803e3d6000fd5b5061178b92505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690503384612b7c565b604051829033907f2bda316674f8d73d289689d7a3acdf8e353b7a142fb5a68ac2aa475104039c1890600090a35050565b60045460208901359067ffffffffffffffff6801000000000000000090910481169082161161183f57600480546040517f6e376b6600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff80851693820193909352680100000000000000009091049091166024820152604401610c96565b61184a888883612c7d565b600480547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff8416021790556040805160608101825260025480825260035460ff808216602085015261010090910416928201929092528a359182146118fc5780516040517f93df584c000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401610c96565b467f00000000000000000000000000000000000000000000000000000000000000001461197d576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f00000000000000000000000000000000000000000000000000000000000000006004820152466024820152604401610c96565b6040805183815267ffffffffffffffff851660208201527fe893c2681d327421d89e1cb54fbe64645b4dcea668d6826130b62cf4c6eefea2910160405180910390a160208101516119cf90600161431d565b60ff168714611a0a576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b868514611a43576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602090815260408083208151808301909252805460ff80821684529293919291840191610100909104166002811115611a8657611a86614235565b6002811115611a9757611a97614235565b9052509050600281602001516002811115611ab457611ab4614235565b148015611afb57506007816000015160ff1681548110611ad657611ad6614206565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b611b31576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000611b3f8660206141e9565b611b4a8960206141e9565b611b568c610144614336565b611b609190614336565b611b6a9190614336565b9050368114611bae576040517f8e1192e100000000000000000000000000000000000000000000000000000000815260048101829052366024820152604401610c96565b5060008a8a604051611bc1929190614349565b604051908190038120611bd8918e90602001614359565b604051602081830303815290604052805190602001209050611bf8613924565b8860005b81811015611e1c5760006001858a8460208110611c1b57611c1b614206565b611c2891901a601b61431d565b8f8f86818110611c3a57611c3a614206565b905060200201358e8e87818110611c5357611c53614206565b9050602002013560405160008152602001604052604051611c90949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611cb2573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152848220848601909552845460ff8082168652939750919550929392840191610100909104166002811115611d3557611d35614235565b6002811115611d4657611d46614235565b9052509050600181602001516002811115611d6357611d63614235565b14611d9a576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f8110611db157611db1614206565b602002015115611ded576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f8110611e0857611e08614206565b911515602090920201525050600101611bfc565b505050505050505050505050505050565b611e35612214565b60005b81811015610bb457611e60838383818110611e5557611e55614206565b905060a00201612297565b600101611e38565b600c5473ffffffffffffffffffffffffffffffffffffffff163314611eb9576040517fb2a59b2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114611f13576040519150601f19603f3d011682016040523d82523d6000602084013e611f18565b606091505b5050905080611f53576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805184815273ffffffffffffffffffffffffffffffffffffffff841660208201527f6b84d241b711af111ecfa0e518239e6ca212da442a76548fe8a1f4e77518256a910160405180910390a1505050565b611fae612214565b61085081612e2c565b600c5473ffffffffffffffffffffffffffffffffffffffff163314612008576040517fb2a59b2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109fe85858567ffffffffffffffff86868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612f2192505050565b600a5460609060008167ffffffffffffffff81111561207457612074613c45565b6040519080825280602002602001820160405280156120eb57816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816120925790505b50905060005b8281101561220d576000600a828154811061210e5761210e614206565b6000918252602080832060048304015460039092166008026101000a90910467ffffffffffffffff1680835260098252604092839020835160808082018652825473ffffffffffffffffffffffffffffffffffffffff9081168352600184015481168387019081526002909401548082168489019081527401000000000000000000000000000000000000000090910460ff1615156060808601918252895160a081018b528651851681529651841698870198909852905190911696840196909652938201839052935115159281019290925285519093508590859081106121f8576121f8614206565b602090810291909101015250506001016120f1565b5092915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314612295576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610c96565b565b6122a76080820160608301613b83565b67ffffffffffffffff166000036122ea576040517ff89d762900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006122f96020830183613a81565b73ffffffffffffffffffffffffffffffffffffffff161480612340575060006123286040830160208401613a81565b73ffffffffffffffffffffffffffffffffffffffff16145b80612370575060006123586060830160408401613a81565b73ffffffffffffffffffffffffffffffffffffffff16145b156123a7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006009816123bc6080850160608601613b83565b67ffffffffffffffff16815260208101919091526040016000206002015473ffffffffffffffffffffffffffffffffffffffff160361244857600a6124076080830160608401613b83565b8154600181018355600092835260209092206004830401805460039093166008026101000a67ffffffffffffffff8181021990941692909316929092021790555b6040805160808101909152806124616020840184613a81565b73ffffffffffffffffffffffffffffffffffffffff16815260200182602001602081019061248f9190613a81565b73ffffffffffffffffffffffffffffffffffffffff1681526020016124ba6060840160408501613a81565b73ffffffffffffffffffffffffffffffffffffffff1681526020016124e560a084016080850161436d565b15159052600960006124fd6080850160608601613b83565b67ffffffffffffffff16815260208082019290925260409081016000208351815473ffffffffffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161783559385015160018301805491831691909516179093559083015160029091018054606094850151151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00000000000000000000000000000000000000000090911692909316919091179190911790556125de9060808301908301613b83565b67ffffffffffffffff167fab9bd0e4888101232b8f09dae2952ff59a6eea4a19fbddf2a8ca7b23f0e4cb406126196040840160208501613a81565b6126296060850160408601613a81565b6126366020860186613a81565b61264660a087016080880161436d565b604051612688949392919073ffffffffffffffffffffffffffffffffffffffff9485168152928416602084015292166040820152901515606082015260800190565b60405180910390a250565b67ffffffffffffffff85166000908152600960209081526040918290208251608081018452815473ffffffffffffffffffffffffffffffffffffffff908116825260018301548116938201939093526002909101549182169281019290925274010000000000000000000000000000000000000000900460ff16151560608201819052612758576040517fc9ff038f00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff87166004820152602401610c96565b602081015181516040517f38314bb200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909216916338314bb2916127b4913090899060040161438a565b6020604051808303816000875af192505050801561280d575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261280a918101906143cc565b60015b612896573d80801561283b576040519150601f19603f3d011682016040523d82523d6000602084013e612840565b606091505b508667ffffffffffffffff168367ffffffffffffffff167fa481d91c3f9574c23ee84fef85246354b760a0527a535d6382354e4684703ce387846040516128889291906143e9565b60405180910390a350612903565b80156128ae576128a9868489888861329a565b6128fc565b8667ffffffffffffffff168367ffffffffffffffff167f8d3121fe961b40270f336aa75feb1213f1c979a33993311c60da4dd0f24526cf876040516128f391906139c6565b60405180910390a35b50506109fe565b612910858388878761329a565b505050505050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526129f49085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613481565b50505050565b801580612a9a57506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612a74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9891906141a1565b155b612b26576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610c96565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610bb49084907f095ea7b30000000000000000000000000000000000000000000000000000000090606401612972565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610bb49084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401612972565b6000808a8a8a8a8a8a8a8a8a604051602001612bf69998979695949392919061440e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b6000612c8b838501856145ab565b8051516020820151519192509081158015612ca4575080155b15612cda576040517ebf199700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82811015612d7e57612d7684600001518281518110612cfe57612cfe614206565b60200260200101516040015185600001518381518110612d2057612d20614206565b60200260200101516000015186600001518481518110612d4257612d42614206565b6020026020010151602001518888600001518681518110612d6557612d65614206565b602002602001015160600151612f21565b600101612cdd565b5060005b81811015612e2357612e1b84602001518281518110612da357612da3614206565b60200260200101516020015185602001518381518110612dc557612dc5614206565b60200260200101516000015186602001518481518110612de757612de7614206565b60200260200101516060015187602001518581518110612e0957612e09614206565b60200260200101516040015189612693565b600101612d82565b50505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603612eab576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610c96565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000612f2b610737565b60085490915080821080612f47575085612f45828461471f565b105b15612f8f576040517fd54d0fc4000000000000000000000000000000000000000000000000000000008152600481018790526024810183905260448101829052606401610c96565b67ffffffffffffffff87166000908152600960209081526040918290208251608081018452815473ffffffffffffffffffffffffffffffffffffffff908116825260018301548116938201939093526002909101549182169281019290925274010000000000000000000000000000000000000000900460ff16151560608201819052613054576040517fc9ff038f00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff89166004820152602401610c96565b600b546040517f0a861f2a0000000000000000000000000000000000000000000000000000000081526004810189905273ffffffffffffffffffffffffffffffffffffffff90911690630a861f2a90602401600060405180830381600087803b1580156130c057600080fd5b505af11580156130d4573d6000803e3d6000fd5b505050602082015161311f915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690896129fa565b6020810151604080830151835191517fa71d98b700000000000000000000000000000000000000000000000000000000815260009373ffffffffffffffffffffffffffffffffffffffff169263a71d98b7928b926131a6927f000000000000000000000000000000000000000000000000000000000000000092918f908d90600401614732565b60006040518083038185885af11580156131c4573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261320b9190810190614779565b90508867ffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168767ffffffffffffffff167f2a0b69eaf1b415ca57005b4f87582ddefc6d960325ff30dc62a9b3e1e1e5b8a885600001518c8a8760405161328794939291906147e7565b60405180910390a4505050505050505050565b8015613322577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0866040518263ffffffff1660e01b81526004016000604051808303818588803b15801561330857600080fd5b505af115801561331c573d6000803e3d6000fd5b50505050505b600b546133699073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691168761358d565b600b546040517feb521a4c0000000000000000000000000000000000000000000000000000000081526004810187905273ffffffffffffffffffffffffffffffffffffffff9091169063eb521a4c90602401600060405180830381600087803b1580156133d557600080fd5b505af11580156133e9573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff168367ffffffffffffffff168567ffffffffffffffff167f2a0b69eaf1b415ca57005b4f87582ddefc6d960325ff30dc62a9b3e1e1e5b8a83089876040518060200160405280600081525060405161347294939291906147e7565b60405180910390a45050505050565b60006134e3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661368b9092919063ffffffff16565b805190915015610bb4578080602001905181019061350191906143cc565b610bb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610c96565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015613604573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061362891906141a1565b6136329190614336565b60405173ffffffffffffffffffffffffffffffffffffffff85166024820152604481018290529091506129f49085907f095ea7b30000000000000000000000000000000000000000000000000000000090606401612972565b606061369a84846000856136a2565b949350505050565b606082471015613734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610c96565b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161375d919061482e565b60006040518083038185875af1925050503d806000811461379a576040519150601f19603f3d011682016040523d82523d6000602084013e61379f565b606091505b50915091506137b0878383876137bb565b979650505050505050565b6060831561385157825160000361384a5773ffffffffffffffffffffffffffffffffffffffff85163b61384a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c96565b508161369a565b61369a83838151156138665781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c9691906139c6565b828054828255906000526020600020908101928215613914579160200282015b8281111561391457825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906138ba565b50613920929150613943565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b808211156139205760008155600101613944565b60005b8381101561397357818101518382015260200161395b565b50506000910152565b60008151808452613994816020860160208601613958565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006139d9602083018461397c565b9392505050565b6000602082840312156139f257600080fd5b5035919050565b600060a08284031215613a0b57600080fd5b50919050565b6020808252825182820181905260009190848201906040850190845b81811015613a5357835167ffffffffffffffff1683529284019291840191600101613a2d565b50909695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461085057600080fd5b600060208284031215613a9357600080fd5b81356139d981613a5f565b803567ffffffffffffffff81168114613ab657600080fd5b919050565b801515811461085057600080fd5b60008083601f840112613adb57600080fd5b50813567ffffffffffffffff811115613af357600080fd5b602083019150836020828501011115613b0b57600080fd5b9250929050565b600080600080600060808688031215613b2a57600080fd5b613b3386613a9e565b9450602086013593506040860135613b4a81613abb565b9250606086013567ffffffffffffffff811115613b6657600080fd5b613b7288828901613ac9565b969995985093965092949392505050565b600060208284031215613b9557600080fd5b6139d982613a9e565b600080600060608486031215613bb357600080fd5b8335613bbe81613a5f565b9250602084013591506040840135613bd581613a5f565b809150509250925092565b60008151808452602080850194506020840160005b83811015613c2757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613bf5565b509495945050505050565b6020815260006139d96020830184613be0565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613c9757613c97613c45565b60405290565b6040805190810167ffffffffffffffff81118282101715613c9757613c97613c45565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613d0757613d07613c45565b604052919050565b600067ffffffffffffffff821115613d2957613d29613c45565b5060051b60200190565b600082601f830112613d4457600080fd5b81356020613d59613d5483613d0f565b613cc0565b8083825260208201915060208460051b870101935086841115613d7b57600080fd5b602086015b84811015613da0578035613d9381613a5f565b8352918301918301613d80565b509695505050505050565b803560ff81168114613ab657600080fd5b600067ffffffffffffffff821115613dd657613dd6613c45565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112613e1357600080fd5b8135613e21613d5482613dbc565b818152846020838601011115613e3657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c08789031215613e6c57600080fd5b863567ffffffffffffffff80821115613e8457600080fd5b613e908a838b01613d33565b97506020890135915080821115613ea657600080fd5b613eb28a838b01613d33565b9650613ec060408a01613dab565b95506060890135915080821115613ed657600080fd5b613ee28a838b01613e02565b9450613ef060808a01613a9e565b935060a0890135915080821115613f0657600080fd5b50613f1389828a01613e02565b9150509295509295509295565b60008083601f840112613f3257600080fd5b50813567ffffffffffffffff811115613f4a57600080fd5b6020830191508360208260051b8501011115613b0b57600080fd5b60008060008060008060008060e0898b031215613f8157600080fd5b606089018a811115613f9257600080fd5b8998503567ffffffffffffffff80821115613fac57600080fd5b613fb88c838d01613ac9565b909950975060808b0135915080821115613fd157600080fd5b613fdd8c838d01613f20565b909750955060a08b0135915080821115613ff657600080fd5b506140038b828c01613f20565b999c989b50969995989497949560c00135949350505050565b6000806020838503121561402f57600080fd5b823567ffffffffffffffff8082111561404757600080fd5b818501915085601f83011261405b57600080fd5b81358181111561406a57600080fd5b86602060a08302850101111561407f57600080fd5b60209290920196919550909350505050565b600080604083850312156140a457600080fd5b8235915060208301356140b681613a5f565b809150509250929050565b6000806000806000608086880312156140d957600080fd5b6140e286613a9e565b94506020860135935060408601359250606086013567ffffffffffffffff811115613b6657600080fd5b602080825282518282018190526000919060409081850190868401855b82811015614194578151805173ffffffffffffffffffffffffffffffffffffffff90811686528782015181168887015286820151168686015260608082015167ffffffffffffffff169086015260809081015115159085015260a09093019290850190600101614129565b5091979650505050505050565b6000602082840312156141b357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417614200576142006141ba565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600063ffffffff80831681810361427d5761427d6141ba565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526142b78184018a613be0565b905082810360808401526142cb8189613be0565b905060ff871660a084015282810360c08401526142e8818761397c565b905067ffffffffffffffff851660e084015282810361010084015261430d818561397c565b9c9b505050505050505050505050565b60ff8181168382160190811115614200576142006141ba565b80820180821115614200576142006141ba565b8183823760009101908152919050565b828152606082602083013760800192915050565b60006020828403121561437f57600080fd5b81356139d981613abb565b600073ffffffffffffffffffffffffffffffffffffffff8086168352808516602084015250606060408301526143c3606083018461397c565b95945050505050565b6000602082840312156143de57600080fd5b81516139d981613abb565b6040815260006143fc604083018561397c565b82810360208401526143c3818561397c565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526144558285018b613be0565b91508382036080850152614469828a613be0565b915060ff881660a085015283820360c0850152614486828861397c565b90861660e0850152838103610100850152905061430d818561397c565b600082601f8301126144b457600080fd5b813560206144c4613d5483613d0f565b82815260059290921b840181019181810190868411156144e357600080fd5b8286015b84811015613da057803567ffffffffffffffff808211156145085760008081fd5b81890191506080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848d030112156145415760008081fd5b614549613c74565b878401358152604061455c818601613a9e565b8983015260608086013561456f81613abb565b8383015292850135928484111561458857600091508182fd5b6145968e8b86890101613e02565b908301525086525050509183019183016144e7565b600060208083850312156145be57600080fd5b823567ffffffffffffffff808211156145d657600080fd5b90840190604082870312156145ea57600080fd5b6145f2613c9d565b82358281111561460157600080fd5b8301601f8101881361461257600080fd5b8035614620613d5482613d0f565b81815260059190911b8201860190868101908a83111561463f57600080fd5b8784015b838110156146eb5780358781111561465a57600080fd5b85016080818e037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001121561468e57600080fd5b614696613c74565b8a820135815260408201358b8201526146b160608301613a9e565b60408201526080820135898111156146c95760008081fd5b6146d78f8d83860101613e02565b606083015250845250918801918801614643565b508452505050828401358281111561470257600080fd5b61470e888286016144a3565b948201949094529695505050505050565b81810381811115614200576142006141ba565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525083606083015260a060808301526137b060a083018461397c565b60006020828403121561478b57600080fd5b815167ffffffffffffffff8111156147a257600080fd5b8201601f810184136147b357600080fd5b80516147c1613d5482613dbc565b8181528560208385010111156147d657600080fd5b6143c3826020830160208601613958565b73ffffffffffffffffffffffffffffffffffffffff8516815283602082015260806040820152600061481c608083018561397c565b82810360608401526137b0818561397c565b60008251614840818460208701613958565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var LiquidityManagerABI = LiquidityManagerMetaData.ABI
+
+var LiquidityManagerBin = LiquidityManagerMetaData.Bin
+
+func DeployLiquidityManager(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, localChainSelector uint64, localLiquidityContainer common.Address, minimumLiquidity *big.Int, finance common.Address) (common.Address, *types.Transaction, *LiquidityManager, error) {
+ parsed, err := LiquidityManagerMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(LiquidityManagerBin), backend, token, localChainSelector, localLiquidityContainer, minimumLiquidity, finance)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &LiquidityManager{address: address, abi: *parsed, LiquidityManagerCaller: LiquidityManagerCaller{contract: contract}, LiquidityManagerTransactor: LiquidityManagerTransactor{contract: contract}, LiquidityManagerFilterer: LiquidityManagerFilterer{contract: contract}}, nil
+}
+
+type LiquidityManager struct {
+ address common.Address
+ abi abi.ABI
+ LiquidityManagerCaller
+ LiquidityManagerTransactor
+ LiquidityManagerFilterer
+}
+
+type LiquidityManagerCaller struct {
+ contract *bind.BoundContract
+}
+
+type LiquidityManagerTransactor struct {
+ contract *bind.BoundContract
+}
+
+type LiquidityManagerFilterer struct {
+ contract *bind.BoundContract
+}
+
+type LiquidityManagerSession struct {
+ Contract *LiquidityManager
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type LiquidityManagerCallerSession struct {
+ Contract *LiquidityManagerCaller
+ CallOpts bind.CallOpts
+}
+
+type LiquidityManagerTransactorSession struct {
+ Contract *LiquidityManagerTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type LiquidityManagerRaw struct {
+ Contract *LiquidityManager
+}
+
+type LiquidityManagerCallerRaw struct {
+ Contract *LiquidityManagerCaller
+}
+
+type LiquidityManagerTransactorRaw struct {
+ Contract *LiquidityManagerTransactor
+}
+
+func NewLiquidityManager(address common.Address, backend bind.ContractBackend) (*LiquidityManager, error) {
+ abi, err := abi.JSON(strings.NewReader(LiquidityManagerABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindLiquidityManager(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManager{address: address, abi: abi, LiquidityManagerCaller: LiquidityManagerCaller{contract: contract}, LiquidityManagerTransactor: LiquidityManagerTransactor{contract: contract}, LiquidityManagerFilterer: LiquidityManagerFilterer{contract: contract}}, nil
+}
+
+func NewLiquidityManagerCaller(address common.Address, caller bind.ContractCaller) (*LiquidityManagerCaller, error) {
+ contract, err := bindLiquidityManager(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerCaller{contract: contract}, nil
+}
+
+func NewLiquidityManagerTransactor(address common.Address, transactor bind.ContractTransactor) (*LiquidityManagerTransactor, error) {
+ contract, err := bindLiquidityManager(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerTransactor{contract: contract}, nil
+}
+
+func NewLiquidityManagerFilterer(address common.Address, filterer bind.ContractFilterer) (*LiquidityManagerFilterer, error) {
+ contract, err := bindLiquidityManager(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerFilterer{contract: contract}, nil
+}
+
+func bindLiquidityManager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := LiquidityManagerMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_LiquidityManager *LiquidityManagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LiquidityManager.Contract.LiquidityManagerCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_LiquidityManager *LiquidityManagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.LiquidityManagerTransactor.contract.Transfer(opts)
+}
+
+func (_LiquidityManager *LiquidityManagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.LiquidityManagerTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _LiquidityManager.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.contract.Transfer(opts)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) GetAllCrossChainRebalancers(opts *bind.CallOpts) ([]ILiquidityManagerCrossChainRebalancerArgs, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "getAllCrossChainRebalancers")
+
+ if err != nil {
+ return *new([]ILiquidityManagerCrossChainRebalancerArgs), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]ILiquidityManagerCrossChainRebalancerArgs)).(*[]ILiquidityManagerCrossChainRebalancerArgs)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) GetAllCrossChainRebalancers() ([]ILiquidityManagerCrossChainRebalancerArgs, error) {
+ return _LiquidityManager.Contract.GetAllCrossChainRebalancers(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) GetAllCrossChainRebalancers() ([]ILiquidityManagerCrossChainRebalancerArgs, error) {
+ return _LiquidityManager.Contract.GetAllCrossChainRebalancers(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) GetCrossChainRebalancer(opts *bind.CallOpts, chainSelector uint64) (LiquidityManagerCrossChainRebalancer, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "getCrossChainRebalancer", chainSelector)
+
+ if err != nil {
+ return *new(LiquidityManagerCrossChainRebalancer), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(LiquidityManagerCrossChainRebalancer)).(*LiquidityManagerCrossChainRebalancer)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) GetCrossChainRebalancer(chainSelector uint64) (LiquidityManagerCrossChainRebalancer, error) {
+ return _LiquidityManager.Contract.GetCrossChainRebalancer(&_LiquidityManager.CallOpts, chainSelector)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) GetCrossChainRebalancer(chainSelector uint64) (LiquidityManagerCrossChainRebalancer, error) {
+ return _LiquidityManager.Contract.GetCrossChainRebalancer(&_LiquidityManager.CallOpts, chainSelector)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) GetFinanceRole(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "getFinanceRole")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) GetFinanceRole() (common.Address, error) {
+ return _LiquidityManager.Contract.GetFinanceRole(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) GetFinanceRole() (common.Address, error) {
+ return _LiquidityManager.Contract.GetFinanceRole(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) GetLiquidity(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "getLiquidity")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) GetLiquidity() (*big.Int, error) {
+ return _LiquidityManager.Contract.GetLiquidity(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) GetLiquidity() (*big.Int, error) {
+ return _LiquidityManager.Contract.GetLiquidity(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) GetLocalLiquidityContainer(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "getLocalLiquidityContainer")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) GetLocalLiquidityContainer() (common.Address, error) {
+ return _LiquidityManager.Contract.GetLocalLiquidityContainer(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) GetLocalLiquidityContainer() (common.Address, error) {
+ return _LiquidityManager.Contract.GetLocalLiquidityContainer(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) GetMinimumLiquidity(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "getMinimumLiquidity")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) GetMinimumLiquidity() (*big.Int, error) {
+ return _LiquidityManager.Contract.GetMinimumLiquidity(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) GetMinimumLiquidity() (*big.Int, error) {
+ return _LiquidityManager.Contract.GetMinimumLiquidity(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) GetSupportedDestChains(opts *bind.CallOpts) ([]uint64, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "getSupportedDestChains")
+
+ if err != nil {
+ return *new([]uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) GetSupportedDestChains() ([]uint64, error) {
+ return _LiquidityManager.Contract.GetSupportedDestChains(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) GetSupportedDestChains() ([]uint64, error) {
+ return _LiquidityManager.Contract.GetSupportedDestChains(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) GetTransmitters() ([]common.Address, error) {
+ return _LiquidityManager.Contract.GetTransmitters(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) GetTransmitters() ([]common.Address, error) {
+ return _LiquidityManager.Contract.GetTransmitters(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) ILocalToken(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "i_localToken")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) ILocalToken() (common.Address, error) {
+ return _LiquidityManager.Contract.ILocalToken(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) ILocalToken() (common.Address, error) {
+ return _LiquidityManager.Contract.ILocalToken(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _LiquidityManager.Contract.LatestConfigDetails(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _LiquidityManager.Contract.LatestConfigDetails(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) LatestSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "latestSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) LatestSequenceNumber() (uint64, error) {
+ return _LiquidityManager.Contract.LatestSequenceNumber(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) LatestSequenceNumber() (uint64, error) {
+ return _LiquidityManager.Contract.LatestSequenceNumber(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) Owner() (common.Address, error) {
+ return _LiquidityManager.Contract.Owner(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) Owner() (common.Address, error) {
+ return _LiquidityManager.Contract.Owner(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _LiquidityManager.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_LiquidityManager *LiquidityManagerSession) TypeAndVersion() (string, error) {
+ return _LiquidityManager.Contract.TypeAndVersion(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerCallerSession) TypeAndVersion() (string, error) {
+ return _LiquidityManager.Contract.TypeAndVersion(&_LiquidityManager.CallOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_LiquidityManager *LiquidityManagerSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LiquidityManager.Contract.AcceptOwnership(&_LiquidityManager.TransactOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _LiquidityManager.Contract.AcceptOwnership(&_LiquidityManager.TransactOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) AddLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "addLiquidity", amount)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) AddLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.AddLiquidity(&_LiquidityManager.TransactOpts, amount)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) AddLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.AddLiquidity(&_LiquidityManager.TransactOpts, amount)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) RebalanceLiquidity(opts *bind.TransactOpts, chainSelector uint64, amount *big.Int, nativeBridgeFee *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "rebalanceLiquidity", chainSelector, amount, nativeBridgeFee, bridgeSpecificPayload)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) RebalanceLiquidity(chainSelector uint64, amount *big.Int, nativeBridgeFee *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.RebalanceLiquidity(&_LiquidityManager.TransactOpts, chainSelector, amount, nativeBridgeFee, bridgeSpecificPayload)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) RebalanceLiquidity(chainSelector uint64, amount *big.Int, nativeBridgeFee *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.RebalanceLiquidity(&_LiquidityManager.TransactOpts, chainSelector, amount, nativeBridgeFee, bridgeSpecificPayload)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) ReceiveLiquidity(opts *bind.TransactOpts, remoteChainSelector uint64, amount *big.Int, shouldWrapNative bool, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "receiveLiquidity", remoteChainSelector, amount, shouldWrapNative, bridgeSpecificPayload)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) ReceiveLiquidity(remoteChainSelector uint64, amount *big.Int, shouldWrapNative bool, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.ReceiveLiquidity(&_LiquidityManager.TransactOpts, remoteChainSelector, amount, shouldWrapNative, bridgeSpecificPayload)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) ReceiveLiquidity(remoteChainSelector uint64, amount *big.Int, shouldWrapNative bool, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.ReceiveLiquidity(&_LiquidityManager.TransactOpts, remoteChainSelector, amount, shouldWrapNative, bridgeSpecificPayload)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) RemoveLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "removeLiquidity", amount)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) RemoveLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.RemoveLiquidity(&_LiquidityManager.TransactOpts, amount)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) RemoveLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.RemoveLiquidity(&_LiquidityManager.TransactOpts, amount)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) SetCrossChainRebalancer(opts *bind.TransactOpts, crossChainLiqManager ILiquidityManagerCrossChainRebalancerArgs) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "setCrossChainRebalancer", crossChainLiqManager)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) SetCrossChainRebalancer(crossChainLiqManager ILiquidityManagerCrossChainRebalancerArgs) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetCrossChainRebalancer(&_LiquidityManager.TransactOpts, crossChainLiqManager)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) SetCrossChainRebalancer(crossChainLiqManager ILiquidityManagerCrossChainRebalancerArgs) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetCrossChainRebalancer(&_LiquidityManager.TransactOpts, crossChainLiqManager)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) SetCrossChainRebalancers(opts *bind.TransactOpts, crossChainRebalancers []ILiquidityManagerCrossChainRebalancerArgs) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "setCrossChainRebalancers", crossChainRebalancers)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) SetCrossChainRebalancers(crossChainRebalancers []ILiquidityManagerCrossChainRebalancerArgs) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetCrossChainRebalancers(&_LiquidityManager.TransactOpts, crossChainRebalancers)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) SetCrossChainRebalancers(crossChainRebalancers []ILiquidityManagerCrossChainRebalancerArgs) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetCrossChainRebalancers(&_LiquidityManager.TransactOpts, crossChainRebalancers)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) SetFinanceRole(opts *bind.TransactOpts, finance common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "setFinanceRole", finance)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) SetFinanceRole(finance common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetFinanceRole(&_LiquidityManager.TransactOpts, finance)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) SetFinanceRole(finance common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetFinanceRole(&_LiquidityManager.TransactOpts, finance)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) SetLocalLiquidityContainer(opts *bind.TransactOpts, localLiquidityContainer common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "setLocalLiquidityContainer", localLiquidityContainer)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) SetLocalLiquidityContainer(localLiquidityContainer common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetLocalLiquidityContainer(&_LiquidityManager.TransactOpts, localLiquidityContainer)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) SetLocalLiquidityContainer(localLiquidityContainer common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetLocalLiquidityContainer(&_LiquidityManager.TransactOpts, localLiquidityContainer)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) SetMinimumLiquidity(opts *bind.TransactOpts, minimumLiquidity *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "setMinimumLiquidity", minimumLiquidity)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) SetMinimumLiquidity(minimumLiquidity *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetMinimumLiquidity(&_LiquidityManager.TransactOpts, minimumLiquidity)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) SetMinimumLiquidity(minimumLiquidity *big.Int) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetMinimumLiquidity(&_LiquidityManager.TransactOpts, minimumLiquidity)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) SetOCR3Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "setOCR3Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) SetOCR3Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetOCR3Config(&_LiquidityManager.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) SetOCR3Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.SetOCR3Config(&_LiquidityManager.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.TransferOwnership(&_LiquidityManager.TransactOpts, to)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.TransferOwnership(&_LiquidityManager.TransactOpts, to)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.Transmit(&_LiquidityManager.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.Transmit(&_LiquidityManager.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) WithdrawERC20(opts *bind.TransactOpts, token common.Address, amount *big.Int, destination common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "withdrawERC20", token, amount, destination)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) WithdrawERC20(token common.Address, amount *big.Int, destination common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.WithdrawERC20(&_LiquidityManager.TransactOpts, token, amount, destination)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) WithdrawERC20(token common.Address, amount *big.Int, destination common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.WithdrawERC20(&_LiquidityManager.TransactOpts, token, amount, destination)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) WithdrawNative(opts *bind.TransactOpts, amount *big.Int, destination common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.contract.Transact(opts, "withdrawNative", amount, destination)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) WithdrawNative(amount *big.Int, destination common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.WithdrawNative(&_LiquidityManager.TransactOpts, amount, destination)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) WithdrawNative(amount *big.Int, destination common.Address) (*types.Transaction, error) {
+ return _LiquidityManager.Contract.WithdrawNative(&_LiquidityManager.TransactOpts, amount, destination)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _LiquidityManager.contract.RawTransact(opts, nil)
+}
+
+func (_LiquidityManager *LiquidityManagerSession) Receive() (*types.Transaction, error) {
+ return _LiquidityManager.Contract.Receive(&_LiquidityManager.TransactOpts)
+}
+
+func (_LiquidityManager *LiquidityManagerTransactorSession) Receive() (*types.Transaction, error) {
+ return _LiquidityManager.Contract.Receive(&_LiquidityManager.TransactOpts)
+}
+
+type LiquidityManagerConfigSetIterator struct {
+ Event *LiquidityManagerConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerConfigSet)
+ 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(LiquidityManagerConfigSet)
+ 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 *LiquidityManagerConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerConfigSet struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterConfigSet(opts *bind.FilterOpts) (*LiquidityManagerConfigSetIterator, error) {
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerConfigSetIterator{contract: _LiquidityManager.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerConfigSet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "ConfigSet", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseConfigSet(log types.Log) (*LiquidityManagerConfigSet, error) {
+ event := new(LiquidityManagerConfigSet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerCrossChainRebalancerSetIterator struct {
+ Event *LiquidityManagerCrossChainRebalancerSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerCrossChainRebalancerSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerCrossChainRebalancerSet)
+ 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(LiquidityManagerCrossChainRebalancerSet)
+ 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 *LiquidityManagerCrossChainRebalancerSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerCrossChainRebalancerSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerCrossChainRebalancerSet struct {
+ RemoteChainSelector uint64
+ LocalBridge common.Address
+ RemoteToken common.Address
+ RemoteRebalancer common.Address
+ Enabled bool
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterCrossChainRebalancerSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*LiquidityManagerCrossChainRebalancerSetIterator, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "CrossChainRebalancerSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerCrossChainRebalancerSetIterator{contract: _LiquidityManager.contract, event: "CrossChainRebalancerSet", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchCrossChainRebalancerSet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerCrossChainRebalancerSet, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "CrossChainRebalancerSet", remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerCrossChainRebalancerSet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "CrossChainRebalancerSet", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseCrossChainRebalancerSet(log types.Log) (*LiquidityManagerCrossChainRebalancerSet, error) {
+ event := new(LiquidityManagerCrossChainRebalancerSet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "CrossChainRebalancerSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerFinalizationFailedIterator struct {
+ Event *LiquidityManagerFinalizationFailed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerFinalizationFailedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerFinalizationFailed)
+ 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(LiquidityManagerFinalizationFailed)
+ 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 *LiquidityManagerFinalizationFailedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerFinalizationFailedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerFinalizationFailed struct {
+ OcrSeqNum uint64
+ RemoteChainSelector uint64
+ BridgeSpecificData []byte
+ Reason []byte
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterFinalizationFailed(opts *bind.FilterOpts, ocrSeqNum []uint64, remoteChainSelector []uint64) (*LiquidityManagerFinalizationFailedIterator, error) {
+
+ var ocrSeqNumRule []interface{}
+ for _, ocrSeqNumItem := range ocrSeqNum {
+ ocrSeqNumRule = append(ocrSeqNumRule, ocrSeqNumItem)
+ }
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "FinalizationFailed", ocrSeqNumRule, remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerFinalizationFailedIterator{contract: _LiquidityManager.contract, event: "FinalizationFailed", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchFinalizationFailed(opts *bind.WatchOpts, sink chan<- *LiquidityManagerFinalizationFailed, ocrSeqNum []uint64, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var ocrSeqNumRule []interface{}
+ for _, ocrSeqNumItem := range ocrSeqNum {
+ ocrSeqNumRule = append(ocrSeqNumRule, ocrSeqNumItem)
+ }
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "FinalizationFailed", ocrSeqNumRule, remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerFinalizationFailed)
+ if err := _LiquidityManager.contract.UnpackLog(event, "FinalizationFailed", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseFinalizationFailed(log types.Log) (*LiquidityManagerFinalizationFailed, error) {
+ event := new(LiquidityManagerFinalizationFailed)
+ if err := _LiquidityManager.contract.UnpackLog(event, "FinalizationFailed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerFinalizationStepCompletedIterator struct {
+ Event *LiquidityManagerFinalizationStepCompleted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerFinalizationStepCompletedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerFinalizationStepCompleted)
+ 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(LiquidityManagerFinalizationStepCompleted)
+ 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 *LiquidityManagerFinalizationStepCompletedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerFinalizationStepCompletedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerFinalizationStepCompleted struct {
+ OcrSeqNum uint64
+ RemoteChainSelector uint64
+ BridgeSpecificData []byte
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterFinalizationStepCompleted(opts *bind.FilterOpts, ocrSeqNum []uint64, remoteChainSelector []uint64) (*LiquidityManagerFinalizationStepCompletedIterator, error) {
+
+ var ocrSeqNumRule []interface{}
+ for _, ocrSeqNumItem := range ocrSeqNum {
+ ocrSeqNumRule = append(ocrSeqNumRule, ocrSeqNumItem)
+ }
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "FinalizationStepCompleted", ocrSeqNumRule, remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerFinalizationStepCompletedIterator{contract: _LiquidityManager.contract, event: "FinalizationStepCompleted", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchFinalizationStepCompleted(opts *bind.WatchOpts, sink chan<- *LiquidityManagerFinalizationStepCompleted, ocrSeqNum []uint64, remoteChainSelector []uint64) (event.Subscription, error) {
+
+ var ocrSeqNumRule []interface{}
+ for _, ocrSeqNumItem := range ocrSeqNum {
+ ocrSeqNumRule = append(ocrSeqNumRule, ocrSeqNumItem)
+ }
+ var remoteChainSelectorRule []interface{}
+ for _, remoteChainSelectorItem := range remoteChainSelector {
+ remoteChainSelectorRule = append(remoteChainSelectorRule, remoteChainSelectorItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "FinalizationStepCompleted", ocrSeqNumRule, remoteChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerFinalizationStepCompleted)
+ if err := _LiquidityManager.contract.UnpackLog(event, "FinalizationStepCompleted", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseFinalizationStepCompleted(log types.Log) (*LiquidityManagerFinalizationStepCompleted, error) {
+ event := new(LiquidityManagerFinalizationStepCompleted)
+ if err := _LiquidityManager.contract.UnpackLog(event, "FinalizationStepCompleted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerFinanceRoleSetIterator struct {
+ Event *LiquidityManagerFinanceRoleSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerFinanceRoleSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerFinanceRoleSet)
+ 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(LiquidityManagerFinanceRoleSet)
+ 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 *LiquidityManagerFinanceRoleSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerFinanceRoleSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerFinanceRoleSet struct {
+ FinanceRole common.Address
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterFinanceRoleSet(opts *bind.FilterOpts) (*LiquidityManagerFinanceRoleSetIterator, error) {
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "FinanceRoleSet")
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerFinanceRoleSetIterator{contract: _LiquidityManager.contract, event: "FinanceRoleSet", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchFinanceRoleSet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerFinanceRoleSet) (event.Subscription, error) {
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "FinanceRoleSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerFinanceRoleSet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "FinanceRoleSet", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseFinanceRoleSet(log types.Log) (*LiquidityManagerFinanceRoleSet, error) {
+ event := new(LiquidityManagerFinanceRoleSet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "FinanceRoleSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerLiquidityAddedToContainerIterator struct {
+ Event *LiquidityManagerLiquidityAddedToContainer
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerLiquidityAddedToContainerIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerLiquidityAddedToContainer)
+ 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(LiquidityManagerLiquidityAddedToContainer)
+ 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 *LiquidityManagerLiquidityAddedToContainerIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerLiquidityAddedToContainerIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerLiquidityAddedToContainer struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterLiquidityAddedToContainer(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LiquidityManagerLiquidityAddedToContainerIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "LiquidityAddedToContainer", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerLiquidityAddedToContainerIterator{contract: _LiquidityManager.contract, event: "LiquidityAddedToContainer", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchLiquidityAddedToContainer(opts *bind.WatchOpts, sink chan<- *LiquidityManagerLiquidityAddedToContainer, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "LiquidityAddedToContainer", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerLiquidityAddedToContainer)
+ if err := _LiquidityManager.contract.UnpackLog(event, "LiquidityAddedToContainer", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseLiquidityAddedToContainer(log types.Log) (*LiquidityManagerLiquidityAddedToContainer, error) {
+ event := new(LiquidityManagerLiquidityAddedToContainer)
+ if err := _LiquidityManager.contract.UnpackLog(event, "LiquidityAddedToContainer", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerLiquidityContainerSetIterator struct {
+ Event *LiquidityManagerLiquidityContainerSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerLiquidityContainerSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerLiquidityContainerSet)
+ 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(LiquidityManagerLiquidityContainerSet)
+ 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 *LiquidityManagerLiquidityContainerSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerLiquidityContainerSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerLiquidityContainerSet struct {
+ NewLiquidityContainer common.Address
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterLiquidityContainerSet(opts *bind.FilterOpts, newLiquidityContainer []common.Address) (*LiquidityManagerLiquidityContainerSetIterator, error) {
+
+ var newLiquidityContainerRule []interface{}
+ for _, newLiquidityContainerItem := range newLiquidityContainer {
+ newLiquidityContainerRule = append(newLiquidityContainerRule, newLiquidityContainerItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "LiquidityContainerSet", newLiquidityContainerRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerLiquidityContainerSetIterator{contract: _LiquidityManager.contract, event: "LiquidityContainerSet", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchLiquidityContainerSet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerLiquidityContainerSet, newLiquidityContainer []common.Address) (event.Subscription, error) {
+
+ var newLiquidityContainerRule []interface{}
+ for _, newLiquidityContainerItem := range newLiquidityContainer {
+ newLiquidityContainerRule = append(newLiquidityContainerRule, newLiquidityContainerItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "LiquidityContainerSet", newLiquidityContainerRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerLiquidityContainerSet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "LiquidityContainerSet", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseLiquidityContainerSet(log types.Log) (*LiquidityManagerLiquidityContainerSet, error) {
+ event := new(LiquidityManagerLiquidityContainerSet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "LiquidityContainerSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerLiquidityRemovedFromContainerIterator struct {
+ Event *LiquidityManagerLiquidityRemovedFromContainer
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerLiquidityRemovedFromContainerIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerLiquidityRemovedFromContainer)
+ 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(LiquidityManagerLiquidityRemovedFromContainer)
+ 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 *LiquidityManagerLiquidityRemovedFromContainerIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerLiquidityRemovedFromContainerIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerLiquidityRemovedFromContainer struct {
+ Remover common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterLiquidityRemovedFromContainer(opts *bind.FilterOpts, remover []common.Address, amount []*big.Int) (*LiquidityManagerLiquidityRemovedFromContainerIterator, error) {
+
+ var removerRule []interface{}
+ for _, removerItem := range remover {
+ removerRule = append(removerRule, removerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "LiquidityRemovedFromContainer", removerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerLiquidityRemovedFromContainerIterator{contract: _LiquidityManager.contract, event: "LiquidityRemovedFromContainer", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchLiquidityRemovedFromContainer(opts *bind.WatchOpts, sink chan<- *LiquidityManagerLiquidityRemovedFromContainer, remover []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var removerRule []interface{}
+ for _, removerItem := range remover {
+ removerRule = append(removerRule, removerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "LiquidityRemovedFromContainer", removerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerLiquidityRemovedFromContainer)
+ if err := _LiquidityManager.contract.UnpackLog(event, "LiquidityRemovedFromContainer", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseLiquidityRemovedFromContainer(log types.Log) (*LiquidityManagerLiquidityRemovedFromContainer, error) {
+ event := new(LiquidityManagerLiquidityRemovedFromContainer)
+ if err := _LiquidityManager.contract.UnpackLog(event, "LiquidityRemovedFromContainer", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerLiquidityTransferredIterator struct {
+ Event *LiquidityManagerLiquidityTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerLiquidityTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerLiquidityTransferred)
+ 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(LiquidityManagerLiquidityTransferred)
+ 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 *LiquidityManagerLiquidityTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerLiquidityTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerLiquidityTransferred struct {
+ OcrSeqNum uint64
+ FromChainSelector uint64
+ ToChainSelector uint64
+ To common.Address
+ Amount *big.Int
+ BridgeSpecificData []byte
+ BridgeReturnData []byte
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterLiquidityTransferred(opts *bind.FilterOpts, ocrSeqNum []uint64, fromChainSelector []uint64, toChainSelector []uint64) (*LiquidityManagerLiquidityTransferredIterator, error) {
+
+ var ocrSeqNumRule []interface{}
+ for _, ocrSeqNumItem := range ocrSeqNum {
+ ocrSeqNumRule = append(ocrSeqNumRule, ocrSeqNumItem)
+ }
+ var fromChainSelectorRule []interface{}
+ for _, fromChainSelectorItem := range fromChainSelector {
+ fromChainSelectorRule = append(fromChainSelectorRule, fromChainSelectorItem)
+ }
+ var toChainSelectorRule []interface{}
+ for _, toChainSelectorItem := range toChainSelector {
+ toChainSelectorRule = append(toChainSelectorRule, toChainSelectorItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "LiquidityTransferred", ocrSeqNumRule, fromChainSelectorRule, toChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerLiquidityTransferredIterator{contract: _LiquidityManager.contract, event: "LiquidityTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchLiquidityTransferred(opts *bind.WatchOpts, sink chan<- *LiquidityManagerLiquidityTransferred, ocrSeqNum []uint64, fromChainSelector []uint64, toChainSelector []uint64) (event.Subscription, error) {
+
+ var ocrSeqNumRule []interface{}
+ for _, ocrSeqNumItem := range ocrSeqNum {
+ ocrSeqNumRule = append(ocrSeqNumRule, ocrSeqNumItem)
+ }
+ var fromChainSelectorRule []interface{}
+ for _, fromChainSelectorItem := range fromChainSelector {
+ fromChainSelectorRule = append(fromChainSelectorRule, fromChainSelectorItem)
+ }
+ var toChainSelectorRule []interface{}
+ for _, toChainSelectorItem := range toChainSelector {
+ toChainSelectorRule = append(toChainSelectorRule, toChainSelectorItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "LiquidityTransferred", ocrSeqNumRule, fromChainSelectorRule, toChainSelectorRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerLiquidityTransferred)
+ if err := _LiquidityManager.contract.UnpackLog(event, "LiquidityTransferred", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseLiquidityTransferred(log types.Log) (*LiquidityManagerLiquidityTransferred, error) {
+ event := new(LiquidityManagerLiquidityTransferred)
+ if err := _LiquidityManager.contract.UnpackLog(event, "LiquidityTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerMinimumLiquiditySetIterator struct {
+ Event *LiquidityManagerMinimumLiquiditySet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerMinimumLiquiditySetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerMinimumLiquiditySet)
+ 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(LiquidityManagerMinimumLiquiditySet)
+ 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 *LiquidityManagerMinimumLiquiditySetIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerMinimumLiquiditySetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerMinimumLiquiditySet struct {
+ OldBalance *big.Int
+ NewBalance *big.Int
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterMinimumLiquiditySet(opts *bind.FilterOpts) (*LiquidityManagerMinimumLiquiditySetIterator, error) {
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "MinimumLiquiditySet")
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerMinimumLiquiditySetIterator{contract: _LiquidityManager.contract, event: "MinimumLiquiditySet", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchMinimumLiquiditySet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerMinimumLiquiditySet) (event.Subscription, error) {
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "MinimumLiquiditySet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerMinimumLiquiditySet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "MinimumLiquiditySet", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseMinimumLiquiditySet(log types.Log) (*LiquidityManagerMinimumLiquiditySet, error) {
+ event := new(LiquidityManagerMinimumLiquiditySet)
+ if err := _LiquidityManager.contract.UnpackLog(event, "MinimumLiquiditySet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerNativeDepositedIterator struct {
+ Event *LiquidityManagerNativeDeposited
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerNativeDepositedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerNativeDeposited)
+ 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(LiquidityManagerNativeDeposited)
+ 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 *LiquidityManagerNativeDepositedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerNativeDepositedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerNativeDeposited struct {
+ Amount *big.Int
+ Depositor common.Address
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterNativeDeposited(opts *bind.FilterOpts) (*LiquidityManagerNativeDepositedIterator, error) {
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "NativeDeposited")
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerNativeDepositedIterator{contract: _LiquidityManager.contract, event: "NativeDeposited", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchNativeDeposited(opts *bind.WatchOpts, sink chan<- *LiquidityManagerNativeDeposited) (event.Subscription, error) {
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "NativeDeposited")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerNativeDeposited)
+ if err := _LiquidityManager.contract.UnpackLog(event, "NativeDeposited", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseNativeDeposited(log types.Log) (*LiquidityManagerNativeDeposited, error) {
+ event := new(LiquidityManagerNativeDeposited)
+ if err := _LiquidityManager.contract.UnpackLog(event, "NativeDeposited", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerNativeWithdrawnIterator struct {
+ Event *LiquidityManagerNativeWithdrawn
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerNativeWithdrawnIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerNativeWithdrawn)
+ 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(LiquidityManagerNativeWithdrawn)
+ 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 *LiquidityManagerNativeWithdrawnIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerNativeWithdrawnIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerNativeWithdrawn struct {
+ Amount *big.Int
+ Destination common.Address
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterNativeWithdrawn(opts *bind.FilterOpts) (*LiquidityManagerNativeWithdrawnIterator, error) {
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "NativeWithdrawn")
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerNativeWithdrawnIterator{contract: _LiquidityManager.contract, event: "NativeWithdrawn", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchNativeWithdrawn(opts *bind.WatchOpts, sink chan<- *LiquidityManagerNativeWithdrawn) (event.Subscription, error) {
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "NativeWithdrawn")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerNativeWithdrawn)
+ if err := _LiquidityManager.contract.UnpackLog(event, "NativeWithdrawn", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseNativeWithdrawn(log types.Log) (*LiquidityManagerNativeWithdrawn, error) {
+ event := new(LiquidityManagerNativeWithdrawn)
+ if err := _LiquidityManager.contract.UnpackLog(event, "NativeWithdrawn", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerOwnershipTransferRequestedIterator struct {
+ Event *LiquidityManagerOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerOwnershipTransferRequested)
+ 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(LiquidityManagerOwnershipTransferRequested)
+ 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 *LiquidityManagerOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LiquidityManagerOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerOwnershipTransferRequestedIterator{contract: _LiquidityManager.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LiquidityManagerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerOwnershipTransferRequested)
+ if err := _LiquidityManager.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseOwnershipTransferRequested(log types.Log) (*LiquidityManagerOwnershipTransferRequested, error) {
+ event := new(LiquidityManagerOwnershipTransferRequested)
+ if err := _LiquidityManager.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerOwnershipTransferredIterator struct {
+ Event *LiquidityManagerOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerOwnershipTransferred)
+ 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(LiquidityManagerOwnershipTransferred)
+ 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 *LiquidityManagerOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LiquidityManagerOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerOwnershipTransferredIterator{contract: _LiquidityManager.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LiquidityManagerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerOwnershipTransferred)
+ if err := _LiquidityManager.contract.UnpackLog(event, "OwnershipTransferred", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseOwnershipTransferred(log types.Log) (*LiquidityManagerOwnershipTransferred, error) {
+ event := new(LiquidityManagerOwnershipTransferred)
+ if err := _LiquidityManager.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LiquidityManagerTransmittedIterator struct {
+ Event *LiquidityManagerTransmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *LiquidityManagerTransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(LiquidityManagerTransmitted)
+ 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(LiquidityManagerTransmitted)
+ 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 *LiquidityManagerTransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *LiquidityManagerTransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type LiquidityManagerTransmitted struct {
+ ConfigDigest [32]byte
+ SequenceNumber uint64
+ Raw types.Log
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) FilterTransmitted(opts *bind.FilterOpts) (*LiquidityManagerTransmittedIterator, error) {
+
+ logs, sub, err := _LiquidityManager.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &LiquidityManagerTransmittedIterator{contract: _LiquidityManager.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_LiquidityManager *LiquidityManagerFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *LiquidityManagerTransmitted) (event.Subscription, error) {
+
+ logs, sub, err := _LiquidityManager.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(LiquidityManagerTransmitted)
+ if err := _LiquidityManager.contract.UnpackLog(event, "Transmitted", 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 (_LiquidityManager *LiquidityManagerFilterer) ParseTransmitted(log types.Log) (*LiquidityManagerTransmitted, error) {
+ event := new(LiquidityManagerTransmitted)
+ if err := _LiquidityManager.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+
+func (_LiquidityManager *LiquidityManager) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _LiquidityManager.abi.Events["ConfigSet"].ID:
+ return _LiquidityManager.ParseConfigSet(log)
+ case _LiquidityManager.abi.Events["CrossChainRebalancerSet"].ID:
+ return _LiquidityManager.ParseCrossChainRebalancerSet(log)
+ case _LiquidityManager.abi.Events["FinalizationFailed"].ID:
+ return _LiquidityManager.ParseFinalizationFailed(log)
+ case _LiquidityManager.abi.Events["FinalizationStepCompleted"].ID:
+ return _LiquidityManager.ParseFinalizationStepCompleted(log)
+ case _LiquidityManager.abi.Events["FinanceRoleSet"].ID:
+ return _LiquidityManager.ParseFinanceRoleSet(log)
+ case _LiquidityManager.abi.Events["LiquidityAddedToContainer"].ID:
+ return _LiquidityManager.ParseLiquidityAddedToContainer(log)
+ case _LiquidityManager.abi.Events["LiquidityContainerSet"].ID:
+ return _LiquidityManager.ParseLiquidityContainerSet(log)
+ case _LiquidityManager.abi.Events["LiquidityRemovedFromContainer"].ID:
+ return _LiquidityManager.ParseLiquidityRemovedFromContainer(log)
+ case _LiquidityManager.abi.Events["LiquidityTransferred"].ID:
+ return _LiquidityManager.ParseLiquidityTransferred(log)
+ case _LiquidityManager.abi.Events["MinimumLiquiditySet"].ID:
+ return _LiquidityManager.ParseMinimumLiquiditySet(log)
+ case _LiquidityManager.abi.Events["NativeDeposited"].ID:
+ return _LiquidityManager.ParseNativeDeposited(log)
+ case _LiquidityManager.abi.Events["NativeWithdrawn"].ID:
+ return _LiquidityManager.ParseNativeWithdrawn(log)
+ case _LiquidityManager.abi.Events["OwnershipTransferRequested"].ID:
+ return _LiquidityManager.ParseOwnershipTransferRequested(log)
+ case _LiquidityManager.abi.Events["OwnershipTransferred"].ID:
+ return _LiquidityManager.ParseOwnershipTransferred(log)
+ case _LiquidityManager.abi.Events["Transmitted"].ID:
+ return _LiquidityManager.ParseTransmitted(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (LiquidityManagerConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (LiquidityManagerCrossChainRebalancerSet) Topic() common.Hash {
+ return common.HexToHash("0xab9bd0e4888101232b8f09dae2952ff59a6eea4a19fbddf2a8ca7b23f0e4cb40")
+}
+
+func (LiquidityManagerFinalizationFailed) Topic() common.Hash {
+ return common.HexToHash("0xa481d91c3f9574c23ee84fef85246354b760a0527a535d6382354e4684703ce3")
+}
+
+func (LiquidityManagerFinalizationStepCompleted) Topic() common.Hash {
+ return common.HexToHash("0x8d3121fe961b40270f336aa75feb1213f1c979a33993311c60da4dd0f24526cf")
+}
+
+func (LiquidityManagerFinanceRoleSet) Topic() common.Hash {
+ return common.HexToHash("0x58024d20c07d3ebb87b192861d337d3a60995665acc5b8ce29596458b1f25170")
+}
+
+func (LiquidityManagerLiquidityAddedToContainer) Topic() common.Hash {
+ return common.HexToHash("0x5414b81d05ac3542606f164e16a9a107d05d21e906539cc5ceb61d7b6b707eb5")
+}
+
+func (LiquidityManagerLiquidityContainerSet) Topic() common.Hash {
+ return common.HexToHash("0x07dc474694ac40123aadcd2445f1b38d2eb353edd9319dcea043548ab34990ec")
+}
+
+func (LiquidityManagerLiquidityRemovedFromContainer) Topic() common.Hash {
+ return common.HexToHash("0x2bda316674f8d73d289689d7a3acdf8e353b7a142fb5a68ac2aa475104039c18")
+}
+
+func (LiquidityManagerLiquidityTransferred) Topic() common.Hash {
+ return common.HexToHash("0x2a0b69eaf1b415ca57005b4f87582ddefc6d960325ff30dc62a9b3e1e1e5b8a8")
+}
+
+func (LiquidityManagerMinimumLiquiditySet) Topic() common.Hash {
+ return common.HexToHash("0xf97e758c8b3d81df7b0e1b7327a6a7fcf09a41536b2d274b9103015d715f11eb")
+}
+
+func (LiquidityManagerNativeDeposited) Topic() common.Hash {
+ return common.HexToHash("0x3c597f6ac9fe7f0ed6da50b07618f5850a642e459ad587f7fab491a71f8b0ab8")
+}
+
+func (LiquidityManagerNativeWithdrawn) Topic() common.Hash {
+ return common.HexToHash("0x6b84d241b711af111ecfa0e518239e6ca212da442a76548fe8a1f4e77518256a")
+}
+
+func (LiquidityManagerOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (LiquidityManagerOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (LiquidityManagerTransmitted) Topic() common.Hash {
+ return common.HexToHash("0xe893c2681d327421d89e1cb54fbe64645b4dcea668d6826130b62cf4c6eefea2")
+}
+
+func (_LiquidityManager *LiquidityManager) Address() common.Address {
+ return _LiquidityManager.address
+}
+
+type LiquidityManagerInterface interface {
+ GetAllCrossChainRebalancers(opts *bind.CallOpts) ([]ILiquidityManagerCrossChainRebalancerArgs, error)
+
+ GetCrossChainRebalancer(opts *bind.CallOpts, chainSelector uint64) (LiquidityManagerCrossChainRebalancer, error)
+
+ GetFinanceRole(opts *bind.CallOpts) (common.Address, error)
+
+ GetLiquidity(opts *bind.CallOpts) (*big.Int, error)
+
+ GetLocalLiquidityContainer(opts *bind.CallOpts) (common.Address, error)
+
+ GetMinimumLiquidity(opts *bind.CallOpts) (*big.Int, error)
+
+ GetSupportedDestChains(opts *bind.CallOpts) ([]uint64, error)
+
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ ILocalToken(opts *bind.CallOpts) (common.Address, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ AddLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ RebalanceLiquidity(opts *bind.TransactOpts, chainSelector uint64, amount *big.Int, nativeBridgeFee *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error)
+
+ ReceiveLiquidity(opts *bind.TransactOpts, remoteChainSelector uint64, amount *big.Int, shouldWrapNative bool, bridgeSpecificPayload []byte) (*types.Transaction, error)
+
+ RemoveLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ SetCrossChainRebalancer(opts *bind.TransactOpts, crossChainLiqManager ILiquidityManagerCrossChainRebalancerArgs) (*types.Transaction, error)
+
+ SetCrossChainRebalancers(opts *bind.TransactOpts, crossChainRebalancers []ILiquidityManagerCrossChainRebalancerArgs) (*types.Transaction, error)
+
+ SetFinanceRole(opts *bind.TransactOpts, finance common.Address) (*types.Transaction, error)
+
+ SetLocalLiquidityContainer(opts *bind.TransactOpts, localLiquidityContainer common.Address) (*types.Transaction, error)
+
+ SetMinimumLiquidity(opts *bind.TransactOpts, minimumLiquidity *big.Int) (*types.Transaction, error)
+
+ SetOCR3Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ WithdrawERC20(opts *bind.TransactOpts, token common.Address, amount *big.Int, destination common.Address) (*types.Transaction, error)
+
+ WithdrawNative(opts *bind.TransactOpts, amount *big.Int, destination common.Address) (*types.Transaction, error)
+
+ Receive(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*LiquidityManagerConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*LiquidityManagerConfigSet, error)
+
+ FilterCrossChainRebalancerSet(opts *bind.FilterOpts, remoteChainSelector []uint64) (*LiquidityManagerCrossChainRebalancerSetIterator, error)
+
+ WatchCrossChainRebalancerSet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerCrossChainRebalancerSet, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseCrossChainRebalancerSet(log types.Log) (*LiquidityManagerCrossChainRebalancerSet, error)
+
+ FilterFinalizationFailed(opts *bind.FilterOpts, ocrSeqNum []uint64, remoteChainSelector []uint64) (*LiquidityManagerFinalizationFailedIterator, error)
+
+ WatchFinalizationFailed(opts *bind.WatchOpts, sink chan<- *LiquidityManagerFinalizationFailed, ocrSeqNum []uint64, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseFinalizationFailed(log types.Log) (*LiquidityManagerFinalizationFailed, error)
+
+ FilterFinalizationStepCompleted(opts *bind.FilterOpts, ocrSeqNum []uint64, remoteChainSelector []uint64) (*LiquidityManagerFinalizationStepCompletedIterator, error)
+
+ WatchFinalizationStepCompleted(opts *bind.WatchOpts, sink chan<- *LiquidityManagerFinalizationStepCompleted, ocrSeqNum []uint64, remoteChainSelector []uint64) (event.Subscription, error)
+
+ ParseFinalizationStepCompleted(log types.Log) (*LiquidityManagerFinalizationStepCompleted, error)
+
+ FilterFinanceRoleSet(opts *bind.FilterOpts) (*LiquidityManagerFinanceRoleSetIterator, error)
+
+ WatchFinanceRoleSet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerFinanceRoleSet) (event.Subscription, error)
+
+ ParseFinanceRoleSet(log types.Log) (*LiquidityManagerFinanceRoleSet, error)
+
+ FilterLiquidityAddedToContainer(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*LiquidityManagerLiquidityAddedToContainerIterator, error)
+
+ WatchLiquidityAddedToContainer(opts *bind.WatchOpts, sink chan<- *LiquidityManagerLiquidityAddedToContainer, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityAddedToContainer(log types.Log) (*LiquidityManagerLiquidityAddedToContainer, error)
+
+ FilterLiquidityContainerSet(opts *bind.FilterOpts, newLiquidityContainer []common.Address) (*LiquidityManagerLiquidityContainerSetIterator, error)
+
+ WatchLiquidityContainerSet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerLiquidityContainerSet, newLiquidityContainer []common.Address) (event.Subscription, error)
+
+ ParseLiquidityContainerSet(log types.Log) (*LiquidityManagerLiquidityContainerSet, error)
+
+ FilterLiquidityRemovedFromContainer(opts *bind.FilterOpts, remover []common.Address, amount []*big.Int) (*LiquidityManagerLiquidityRemovedFromContainerIterator, error)
+
+ WatchLiquidityRemovedFromContainer(opts *bind.WatchOpts, sink chan<- *LiquidityManagerLiquidityRemovedFromContainer, remover []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityRemovedFromContainer(log types.Log) (*LiquidityManagerLiquidityRemovedFromContainer, error)
+
+ FilterLiquidityTransferred(opts *bind.FilterOpts, ocrSeqNum []uint64, fromChainSelector []uint64, toChainSelector []uint64) (*LiquidityManagerLiquidityTransferredIterator, error)
+
+ WatchLiquidityTransferred(opts *bind.WatchOpts, sink chan<- *LiquidityManagerLiquidityTransferred, ocrSeqNum []uint64, fromChainSelector []uint64, toChainSelector []uint64) (event.Subscription, error)
+
+ ParseLiquidityTransferred(log types.Log) (*LiquidityManagerLiquidityTransferred, error)
+
+ FilterMinimumLiquiditySet(opts *bind.FilterOpts) (*LiquidityManagerMinimumLiquiditySetIterator, error)
+
+ WatchMinimumLiquiditySet(opts *bind.WatchOpts, sink chan<- *LiquidityManagerMinimumLiquiditySet) (event.Subscription, error)
+
+ ParseMinimumLiquiditySet(log types.Log) (*LiquidityManagerMinimumLiquiditySet, error)
+
+ FilterNativeDeposited(opts *bind.FilterOpts) (*LiquidityManagerNativeDepositedIterator, error)
+
+ WatchNativeDeposited(opts *bind.WatchOpts, sink chan<- *LiquidityManagerNativeDeposited) (event.Subscription, error)
+
+ ParseNativeDeposited(log types.Log) (*LiquidityManagerNativeDeposited, error)
+
+ FilterNativeWithdrawn(opts *bind.FilterOpts) (*LiquidityManagerNativeWithdrawnIterator, error)
+
+ WatchNativeWithdrawn(opts *bind.WatchOpts, sink chan<- *LiquidityManagerNativeWithdrawn) (event.Subscription, error)
+
+ ParseNativeWithdrawn(log types.Log) (*LiquidityManagerNativeWithdrawn, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LiquidityManagerOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *LiquidityManagerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*LiquidityManagerOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*LiquidityManagerOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *LiquidityManagerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*LiquidityManagerOwnershipTransferred, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*LiquidityManagerTransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *LiquidityManagerTransmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*LiquidityManagerTransmitted, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/mock_l1_bridge_adapter/mock_l1_bridge_adapter.go b/core/gethwrappers/liquiditymanager/generated/mock_l1_bridge_adapter/mock_l1_bridge_adapter.go
new file mode 100644
index 00000000000..bbfbb1079d5
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/mock_l1_bridge_adapter/mock_l1_bridge_adapter.go
@@ -0,0 +1,660 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package mock_l1_bridge_adapter
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type MockL1BridgeAdapterFinalizePayload struct {
+ Nonce *big.Int
+ Amount *big.Int
+}
+
+type MockL1BridgeAdapterPayload struct {
+ Action uint8
+ Data []byte
+}
+
+type MockL1BridgeAdapterProvePayload struct {
+ Nonce *big.Int
+}
+
+var MockL1BridgeAdapterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"holdNative\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BridgeAddressCannotBeZero\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wanted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"}],\"name\":\"InsufficientEthValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientLiquidity\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFinalizationAction\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"MsgShouldNotContainValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"msgValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"MsgValueDoesNotMatchAmount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeSendFailed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"NonceAlreadyUsed\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"NonceNotProven\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"LiquidityRemoved\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structMockL1BridgeAdapter.FinalizePayload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"name\":\"encodeFinalizePayload\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"enumMockL1BridgeAdapter.FinalizationAction\",\"name\":\"action\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structMockL1BridgeAdapter.Payload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"name\":\"encodePayload\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structMockL1BridgeAdapter.ProvePayload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"name\":\"encodeProvePayload\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"localReceiver\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"bridgeSpecificPayload\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBridgeFeeInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"provideLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"sendERC20\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLiquidity\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
+ Bin: "0x60c0604052600160005534801561001557600080fd5b5060405161126f38038061126f8339810160408190526100349161004c565b6001600160a01b03909116608052151560a052610097565b6000806040838503121561005f57600080fd5b82516001600160a01b038116811461007657600080fd5b6020840151909250801515811461008c57600080fd5b809150509250929050565b60805160a0516111906100df6000396000818161042801526109cf0152600081816101c2015281816102940152818161047b015281816105660152610aa701526111906000f3fe60806040526004361061007f5760003560e01c8063a71d98b71161004e578063a71d98b71461011c578063aee0c3881461013c578063eb521a4c14610157578063f19e1eb61461017757600080fd5b80630a861f2a1461008b5780632e4b1fc9146100ad578063331e5ff0146100ce57806338314bb2146100ec57600080fd5b3661008657005b600080fd5b34801561009757600080fd5b506100ab6100a6366004610c43565b610192565b005b3480156100b957600080fd5b50604051600081526020015b60405180910390f35b3480156100da57600080fd5b506100ab6100e9366004610d26565b50565b3480156100f857600080fd5b5061010c610107366004610e8a565b6102eb565b60405190151581526020016100c5565b61012f61012a366004610eeb565b610385565b6040516100c59190610fd8565b34801561014857600080fd5b506100ab6100e9366004610ff2565b34801561016357600080fd5b506100ab610172366004610c43565b61054c565b34801561018357600080fd5b506100ab6100e9366004611024565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561021e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102429190611048565b101561027a576040517fbb55fd2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6102bb73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633836105be565b604051819033907fc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf984017171990600090a350565b6000806102fa83850185610d26565b905060008151600181111561031157610311611061565b036103275761031f81610697565b91505061037d565b60018151600181111561033c5761033c611061565b0361034b5761031f818661074b565b6040517fee2ef09800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810184905260609073ffffffffffffffffffffffffffffffffffffffff8816906323b872dd906064016020604051808303816000875af1158015610401573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104259190611090565b507f0000000000000000000000000000000000000000000000000000000000000000156104ed576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b1580156104d457600080fd5b505af11580156104e8573d6000803e3d6000fd5b505050505b6000805481806104fc836110b2565b9190505560405160200161051291815260200190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905298975050505050505050565b61058e73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633308461085d565b604051819033907fc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb31208890600090a350565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526106929084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526108c1565b505050565b60008082602001518060200190518101906106b29190611111565b805160009081526001602052604090205490915060ff161561070b5780516040517f91cab50400000000000000000000000000000000000000000000000000000000815260048101919091526024015b60405180910390fd5b516000908152600160208190526040822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909117905592915050565b60008083602001518060200190518101906107669190611135565b805160009081526001602052604090205490915060ff166107b95780516040517f974f61110000000000000000000000000000000000000000000000000000000081526004810191909152602401610702565b805160009081526002602052604090205460ff161561080a5780516040517f91cab5040000000000000000000000000000000000000000000000000000000081526004810191909152602401610702565b8051600090815260026020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905581015161085390846109cd565b5060019392505050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526108bb9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401610610565b50505050565b6000610923826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610ad29092919063ffffffff16565b80519091501561069257808060200190518101906109419190611090565b610692576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610702565b7f000000000000000000000000000000000000000000000000000000000000000015610a8d5760008173ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114610a4d576040519150601f19603f3d011682016040523d82523d6000602084013e610a52565b606091505b5050905080610692576040517fa0c968e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ace73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001682846105be565b5050565b606061037d8484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051610b069190611167565b60006040518083038185875af1925050503d8060008114610b43576040519150601f19603f3d011682016040523d82523d6000602084013e610b48565b606091505b5091509150610b5987838387610b64565b979650505050505050565b60608315610bfa578251600003610bf35773ffffffffffffffffffffffffffffffffffffffff85163b610bf3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610702565b508161037d565b61037d8383815115610c0f5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107029190610fd8565b600060208284031215610c5557600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cae57610cae610c5c565b60405290565b6040516020810167ffffffffffffffff81118282101715610cae57610cae610c5c565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610d1e57610d1e610c5c565b604052919050565b60006020808385031215610d3957600080fd5b823567ffffffffffffffff80821115610d5157600080fd5b9084019060408287031215610d6557600080fd5b610d6d610c8b565b823560028110610d7c57600080fd5b81528284013582811115610d8f57600080fd5b80840193505086601f840112610da457600080fd5b823582811115610db657610db6610c5c565b610de6857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610cd7565b92508083528785828601011115610dfc57600080fd5b8085850186850137600090830185015292830152509392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e3c57600080fd5b919050565b60008083601f840112610e5357600080fd5b50813567ffffffffffffffff811115610e6b57600080fd5b602083019150836020828501011115610e8357600080fd5b9250929050565b60008060008060608587031215610ea057600080fd5b610ea985610e18565b9350610eb760208601610e18565b9250604085013567ffffffffffffffff811115610ed357600080fd5b610edf87828801610e41565b95989497509550505050565b60008060008060008060a08789031215610f0457600080fd5b610f0d87610e18565b9550610f1b60208801610e18565b9450610f2960408801610e18565b935060608701359250608087013567ffffffffffffffff811115610f4c57600080fd5b610f5889828a01610e41565b979a9699509497509295939492505050565b60005b83811015610f85578181015183820152602001610f6d565b50506000910152565b60008151808452610fa6816020860160208601610f6a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610feb6020830184610f8e565b9392505050565b60006040828403121561100457600080fd5b61100c610c8b565b82358152602083013560208201528091505092915050565b60006020828403121561103657600080fd5b61103e610cb4565b9135825250919050565b60006020828403121561105a57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6000602082840312156110a257600080fd5b81518015158114610feb57600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361110a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60006020828403121561112357600080fd5b61112b610cb4565b9151825250919050565b60006040828403121561114757600080fd5b61114f610c8b565b82518152602083015160208201528091505092915050565b60008251611179818460208701610f6a565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var MockL1BridgeAdapterABI = MockL1BridgeAdapterMetaData.ABI
+
+var MockL1BridgeAdapterBin = MockL1BridgeAdapterMetaData.Bin
+
+func DeployMockL1BridgeAdapter(auth *bind.TransactOpts, backend bind.ContractBackend, token common.Address, holdNative bool) (common.Address, *types.Transaction, *MockL1BridgeAdapter, error) {
+ parsed, err := MockL1BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MockL1BridgeAdapterBin), backend, token, holdNative)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MockL1BridgeAdapter{address: address, abi: *parsed, MockL1BridgeAdapterCaller: MockL1BridgeAdapterCaller{contract: contract}, MockL1BridgeAdapterTransactor: MockL1BridgeAdapterTransactor{contract: contract}, MockL1BridgeAdapterFilterer: MockL1BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+type MockL1BridgeAdapter struct {
+ address common.Address
+ abi abi.ABI
+ MockL1BridgeAdapterCaller
+ MockL1BridgeAdapterTransactor
+ MockL1BridgeAdapterFilterer
+}
+
+type MockL1BridgeAdapterCaller struct {
+ contract *bind.BoundContract
+}
+
+type MockL1BridgeAdapterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MockL1BridgeAdapterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MockL1BridgeAdapterSession struct {
+ Contract *MockL1BridgeAdapter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MockL1BridgeAdapterCallerSession struct {
+ Contract *MockL1BridgeAdapterCaller
+ CallOpts bind.CallOpts
+}
+
+type MockL1BridgeAdapterTransactorSession struct {
+ Contract *MockL1BridgeAdapterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MockL1BridgeAdapterRaw struct {
+ Contract *MockL1BridgeAdapter
+}
+
+type MockL1BridgeAdapterCallerRaw struct {
+ Contract *MockL1BridgeAdapterCaller
+}
+
+type MockL1BridgeAdapterTransactorRaw struct {
+ Contract *MockL1BridgeAdapterTransactor
+}
+
+func NewMockL1BridgeAdapter(address common.Address, backend bind.ContractBackend) (*MockL1BridgeAdapter, error) {
+ abi, err := abi.JSON(strings.NewReader(MockL1BridgeAdapterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMockL1BridgeAdapter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL1BridgeAdapter{address: address, abi: abi, MockL1BridgeAdapterCaller: MockL1BridgeAdapterCaller{contract: contract}, MockL1BridgeAdapterTransactor: MockL1BridgeAdapterTransactor{contract: contract}, MockL1BridgeAdapterFilterer: MockL1BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+func NewMockL1BridgeAdapterCaller(address common.Address, caller bind.ContractCaller) (*MockL1BridgeAdapterCaller, error) {
+ contract, err := bindMockL1BridgeAdapter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL1BridgeAdapterCaller{contract: contract}, nil
+}
+
+func NewMockL1BridgeAdapterTransactor(address common.Address, transactor bind.ContractTransactor) (*MockL1BridgeAdapterTransactor, error) {
+ contract, err := bindMockL1BridgeAdapter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL1BridgeAdapterTransactor{contract: contract}, nil
+}
+
+func NewMockL1BridgeAdapterFilterer(address common.Address, filterer bind.ContractFilterer) (*MockL1BridgeAdapterFilterer, error) {
+ contract, err := bindMockL1BridgeAdapter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL1BridgeAdapterFilterer{contract: contract}, nil
+}
+
+func bindMockL1BridgeAdapter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MockL1BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockL1BridgeAdapter.Contract.MockL1BridgeAdapterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.MockL1BridgeAdapterTransactor.contract.Transfer(opts)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.MockL1BridgeAdapterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockL1BridgeAdapter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.contract.Transfer(opts)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCaller) EncodeFinalizePayload(opts *bind.CallOpts, payload MockL1BridgeAdapterFinalizePayload) error {
+ var out []interface{}
+ err := _MockL1BridgeAdapter.contract.Call(opts, &out, "encodeFinalizePayload", payload)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) EncodeFinalizePayload(payload MockL1BridgeAdapterFinalizePayload) error {
+ return _MockL1BridgeAdapter.Contract.EncodeFinalizePayload(&_MockL1BridgeAdapter.CallOpts, payload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCallerSession) EncodeFinalizePayload(payload MockL1BridgeAdapterFinalizePayload) error {
+ return _MockL1BridgeAdapter.Contract.EncodeFinalizePayload(&_MockL1BridgeAdapter.CallOpts, payload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCaller) EncodePayload(opts *bind.CallOpts, payload MockL1BridgeAdapterPayload) error {
+ var out []interface{}
+ err := _MockL1BridgeAdapter.contract.Call(opts, &out, "encodePayload", payload)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) EncodePayload(payload MockL1BridgeAdapterPayload) error {
+ return _MockL1BridgeAdapter.Contract.EncodePayload(&_MockL1BridgeAdapter.CallOpts, payload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCallerSession) EncodePayload(payload MockL1BridgeAdapterPayload) error {
+ return _MockL1BridgeAdapter.Contract.EncodePayload(&_MockL1BridgeAdapter.CallOpts, payload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCaller) EncodeProvePayload(opts *bind.CallOpts, payload MockL1BridgeAdapterProvePayload) error {
+ var out []interface{}
+ err := _MockL1BridgeAdapter.contract.Call(opts, &out, "encodeProvePayload", payload)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) EncodeProvePayload(payload MockL1BridgeAdapterProvePayload) error {
+ return _MockL1BridgeAdapter.Contract.EncodeProvePayload(&_MockL1BridgeAdapter.CallOpts, payload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCallerSession) EncodeProvePayload(payload MockL1BridgeAdapterProvePayload) error {
+ return _MockL1BridgeAdapter.Contract.EncodeProvePayload(&_MockL1BridgeAdapter.CallOpts, payload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCaller) GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _MockL1BridgeAdapter.contract.Call(opts, &out, "getBridgeFeeInNative")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _MockL1BridgeAdapter.Contract.GetBridgeFeeInNative(&_MockL1BridgeAdapter.CallOpts)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterCallerSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _MockL1BridgeAdapter.Contract.GetBridgeFeeInNative(&_MockL1BridgeAdapter.CallOpts)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactor) FinalizeWithdrawERC20(opts *bind.TransactOpts, arg0 common.Address, localReceiver common.Address, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.contract.Transact(opts, "finalizeWithdrawERC20", arg0, localReceiver, bridgeSpecificPayload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) FinalizeWithdrawERC20(arg0 common.Address, localReceiver common.Address, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.FinalizeWithdrawERC20(&_MockL1BridgeAdapter.TransactOpts, arg0, localReceiver, bridgeSpecificPayload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactorSession) FinalizeWithdrawERC20(arg0 common.Address, localReceiver common.Address, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.FinalizeWithdrawERC20(&_MockL1BridgeAdapter.TransactOpts, arg0, localReceiver, bridgeSpecificPayload)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactor) ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.contract.Transact(opts, "provideLiquidity", amount)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.ProvideLiquidity(&_MockL1BridgeAdapter.TransactOpts, amount)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactorSession) ProvideLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.ProvideLiquidity(&_MockL1BridgeAdapter.TransactOpts, amount)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactor) SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, arg2 common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.contract.Transact(opts, "sendERC20", localToken, arg1, arg2, amount, arg4)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) SendERC20(localToken common.Address, arg1 common.Address, arg2 common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.SendERC20(&_MockL1BridgeAdapter.TransactOpts, localToken, arg1, arg2, amount, arg4)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactorSession) SendERC20(localToken common.Address, arg1 common.Address, arg2 common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.SendERC20(&_MockL1BridgeAdapter.TransactOpts, localToken, arg1, arg2, amount, arg4)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactor) WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.contract.Transact(opts, "withdrawLiquidity", amount)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.WithdrawLiquidity(&_MockL1BridgeAdapter.TransactOpts, amount)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactorSession) WithdrawLiquidity(amount *big.Int) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.WithdrawLiquidity(&_MockL1BridgeAdapter.TransactOpts, amount)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.contract.RawTransact(opts, nil)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterSession) Receive() (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.Receive(&_MockL1BridgeAdapter.TransactOpts)
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterTransactorSession) Receive() (*types.Transaction, error) {
+ return _MockL1BridgeAdapter.Contract.Receive(&_MockL1BridgeAdapter.TransactOpts)
+}
+
+type MockL1BridgeAdapterLiquidityAddedIterator struct {
+ Event *MockL1BridgeAdapterLiquidityAdded
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MockL1BridgeAdapterLiquidityAddedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MockL1BridgeAdapterLiquidityAdded)
+ 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(MockL1BridgeAdapterLiquidityAdded)
+ 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 *MockL1BridgeAdapterLiquidityAddedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MockL1BridgeAdapterLiquidityAddedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MockL1BridgeAdapterLiquidityAdded struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterFilterer) FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*MockL1BridgeAdapterLiquidityAddedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _MockL1BridgeAdapter.contract.FilterLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL1BridgeAdapterLiquidityAddedIterator{contract: _MockL1BridgeAdapter.contract, event: "LiquidityAdded", logs: logs, sub: sub}, nil
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterFilterer) WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *MockL1BridgeAdapterLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _MockL1BridgeAdapter.contract.WatchLogs(opts, "LiquidityAdded", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MockL1BridgeAdapterLiquidityAdded)
+ if err := _MockL1BridgeAdapter.contract.UnpackLog(event, "LiquidityAdded", 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 (_MockL1BridgeAdapter *MockL1BridgeAdapterFilterer) ParseLiquidityAdded(log types.Log) (*MockL1BridgeAdapterLiquidityAdded, error) {
+ event := new(MockL1BridgeAdapterLiquidityAdded)
+ if err := _MockL1BridgeAdapter.contract.UnpackLog(event, "LiquidityAdded", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type MockL1BridgeAdapterLiquidityRemovedIterator struct {
+ Event *MockL1BridgeAdapterLiquidityRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *MockL1BridgeAdapterLiquidityRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(MockL1BridgeAdapterLiquidityRemoved)
+ 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(MockL1BridgeAdapterLiquidityRemoved)
+ 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 *MockL1BridgeAdapterLiquidityRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *MockL1BridgeAdapterLiquidityRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type MockL1BridgeAdapterLiquidityRemoved struct {
+ Provider common.Address
+ Amount *big.Int
+ Raw types.Log
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterFilterer) FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*MockL1BridgeAdapterLiquidityRemovedIterator, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _MockL1BridgeAdapter.contract.FilterLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL1BridgeAdapterLiquidityRemovedIterator{contract: _MockL1BridgeAdapter.contract, event: "LiquidityRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapterFilterer) WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *MockL1BridgeAdapterLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error) {
+
+ var providerRule []interface{}
+ for _, providerItem := range provider {
+ providerRule = append(providerRule, providerItem)
+ }
+ var amountRule []interface{}
+ for _, amountItem := range amount {
+ amountRule = append(amountRule, amountItem)
+ }
+
+ logs, sub, err := _MockL1BridgeAdapter.contract.WatchLogs(opts, "LiquidityRemoved", providerRule, amountRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(MockL1BridgeAdapterLiquidityRemoved)
+ if err := _MockL1BridgeAdapter.contract.UnpackLog(event, "LiquidityRemoved", 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 (_MockL1BridgeAdapter *MockL1BridgeAdapterFilterer) ParseLiquidityRemoved(log types.Log) (*MockL1BridgeAdapterLiquidityRemoved, error) {
+ event := new(MockL1BridgeAdapterLiquidityRemoved)
+ if err := _MockL1BridgeAdapter.contract.UnpackLog(event, "LiquidityRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapter) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _MockL1BridgeAdapter.abi.Events["LiquidityAdded"].ID:
+ return _MockL1BridgeAdapter.ParseLiquidityAdded(log)
+ case _MockL1BridgeAdapter.abi.Events["LiquidityRemoved"].ID:
+ return _MockL1BridgeAdapter.ParseLiquidityRemoved(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (MockL1BridgeAdapterLiquidityAdded) Topic() common.Hash {
+ return common.HexToHash("0xc17cea59c2955cb181b03393209566960365771dbba9dc3d510180e7cb312088")
+}
+
+func (MockL1BridgeAdapterLiquidityRemoved) Topic() common.Hash {
+ return common.HexToHash("0xc2c3f06e49b9f15e7b4af9055e183b0d73362e033ad82a07dec9bf9840171719")
+}
+
+func (_MockL1BridgeAdapter *MockL1BridgeAdapter) Address() common.Address {
+ return _MockL1BridgeAdapter.address
+}
+
+type MockL1BridgeAdapterInterface interface {
+ EncodeFinalizePayload(opts *bind.CallOpts, payload MockL1BridgeAdapterFinalizePayload) error
+
+ EncodePayload(opts *bind.CallOpts, payload MockL1BridgeAdapterPayload) error
+
+ EncodeProvePayload(opts *bind.CallOpts, payload MockL1BridgeAdapterProvePayload) error
+
+ GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error)
+
+ FinalizeWithdrawERC20(opts *bind.TransactOpts, arg0 common.Address, localReceiver common.Address, bridgeSpecificPayload []byte) (*types.Transaction, error)
+
+ ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, arg2 common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error)
+
+ WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error)
+
+ Receive(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ FilterLiquidityAdded(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*MockL1BridgeAdapterLiquidityAddedIterator, error)
+
+ WatchLiquidityAdded(opts *bind.WatchOpts, sink chan<- *MockL1BridgeAdapterLiquidityAdded, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityAdded(log types.Log) (*MockL1BridgeAdapterLiquidityAdded, error)
+
+ FilterLiquidityRemoved(opts *bind.FilterOpts, provider []common.Address, amount []*big.Int) (*MockL1BridgeAdapterLiquidityRemovedIterator, error)
+
+ WatchLiquidityRemoved(opts *bind.WatchOpts, sink chan<- *MockL1BridgeAdapterLiquidityRemoved, provider []common.Address, amount []*big.Int) (event.Subscription, error)
+
+ ParseLiquidityRemoved(log types.Log) (*MockL1BridgeAdapterLiquidityRemoved, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/mock_l2_bridge_adapter/mock_l2_bridge_adapter.go b/core/gethwrappers/liquiditymanager/generated/mock_l2_bridge_adapter/mock_l2_bridge_adapter.go
new file mode 100644
index 00000000000..463214247fd
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/mock_l2_bridge_adapter/mock_l2_bridge_adapter.go
@@ -0,0 +1,240 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package mock_l2_bridge_adapter
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var MockL2BridgeAdapterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[],\"name\":\"BridgeAddressCannotBeZero\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wanted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"}],\"name\":\"InsufficientEthValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"MsgShouldNotContainValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"msgValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"MsgValueDoesNotMatchAmount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBridgeFeeInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"sendERC20\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b5061035f806100206000396000f3fe6080604052600436106100345760003560e01c80632e4b1fc91461003957806338314bb21461005a578063a71d98b71461008f575b600080fd5b34801561004557600080fd5b50604051600081526020015b60405180910390f35b34801561006657600080fd5b5061007f6100753660046101dc565b6001949350505050565b6040519015158152602001610051565b6100a261009d36600461023d565b6100af565b60405161005191906102bc565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810184905260609073ffffffffffffffffffffffffffffffffffffffff8816906323b872dd906064016020604051808303816000875af115801561012b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061014f9190610329565b50506040805160208101909152600081529695505050505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461018e57600080fd5b919050565b60008083601f8401126101a557600080fd5b50813567ffffffffffffffff8111156101bd57600080fd5b6020830191508360208285010111156101d557600080fd5b9250929050565b600080600080606085870312156101f257600080fd5b6101fb8561016a565b93506102096020860161016a565b9250604085013567ffffffffffffffff81111561022557600080fd5b61023187828801610193565b95989497509550505050565b60008060008060008060a0878903121561025657600080fd5b61025f8761016a565b955061026d6020880161016a565b945061027b6040880161016a565b935060608701359250608087013567ffffffffffffffff81111561029e57600080fd5b6102aa89828a01610193565b979a9699509497509295939492505050565b60006020808352835180602085015260005b818110156102ea578581018301518582016040015282016102ce565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60006020828403121561033b57600080fd5b8151801515811461034b57600080fd5b939250505056fea164736f6c6343000818000a",
+}
+
+var MockL2BridgeAdapterABI = MockL2BridgeAdapterMetaData.ABI
+
+var MockL2BridgeAdapterBin = MockL2BridgeAdapterMetaData.Bin
+
+func DeployMockL2BridgeAdapter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *MockL2BridgeAdapter, error) {
+ parsed, err := MockL2BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(MockL2BridgeAdapterBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &MockL2BridgeAdapter{address: address, abi: *parsed, MockL2BridgeAdapterCaller: MockL2BridgeAdapterCaller{contract: contract}, MockL2BridgeAdapterTransactor: MockL2BridgeAdapterTransactor{contract: contract}, MockL2BridgeAdapterFilterer: MockL2BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+type MockL2BridgeAdapter struct {
+ address common.Address
+ abi abi.ABI
+ MockL2BridgeAdapterCaller
+ MockL2BridgeAdapterTransactor
+ MockL2BridgeAdapterFilterer
+}
+
+type MockL2BridgeAdapterCaller struct {
+ contract *bind.BoundContract
+}
+
+type MockL2BridgeAdapterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type MockL2BridgeAdapterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type MockL2BridgeAdapterSession struct {
+ Contract *MockL2BridgeAdapter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type MockL2BridgeAdapterCallerSession struct {
+ Contract *MockL2BridgeAdapterCaller
+ CallOpts bind.CallOpts
+}
+
+type MockL2BridgeAdapterTransactorSession struct {
+ Contract *MockL2BridgeAdapterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type MockL2BridgeAdapterRaw struct {
+ Contract *MockL2BridgeAdapter
+}
+
+type MockL2BridgeAdapterCallerRaw struct {
+ Contract *MockL2BridgeAdapterCaller
+}
+
+type MockL2BridgeAdapterTransactorRaw struct {
+ Contract *MockL2BridgeAdapterTransactor
+}
+
+func NewMockL2BridgeAdapter(address common.Address, backend bind.ContractBackend) (*MockL2BridgeAdapter, error) {
+ abi, err := abi.JSON(strings.NewReader(MockL2BridgeAdapterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindMockL2BridgeAdapter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL2BridgeAdapter{address: address, abi: abi, MockL2BridgeAdapterCaller: MockL2BridgeAdapterCaller{contract: contract}, MockL2BridgeAdapterTransactor: MockL2BridgeAdapterTransactor{contract: contract}, MockL2BridgeAdapterFilterer: MockL2BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+func NewMockL2BridgeAdapterCaller(address common.Address, caller bind.ContractCaller) (*MockL2BridgeAdapterCaller, error) {
+ contract, err := bindMockL2BridgeAdapter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL2BridgeAdapterCaller{contract: contract}, nil
+}
+
+func NewMockL2BridgeAdapterTransactor(address common.Address, transactor bind.ContractTransactor) (*MockL2BridgeAdapterTransactor, error) {
+ contract, err := bindMockL2BridgeAdapter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL2BridgeAdapterTransactor{contract: contract}, nil
+}
+
+func NewMockL2BridgeAdapterFilterer(address common.Address, filterer bind.ContractFilterer) (*MockL2BridgeAdapterFilterer, error) {
+ contract, err := bindMockL2BridgeAdapter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &MockL2BridgeAdapterFilterer{contract: contract}, nil
+}
+
+func bindMockL2BridgeAdapter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := MockL2BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockL2BridgeAdapter.Contract.MockL2BridgeAdapterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockL2BridgeAdapter.Contract.MockL2BridgeAdapterTransactor.contract.Transfer(opts)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockL2BridgeAdapter.Contract.MockL2BridgeAdapterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _MockL2BridgeAdapter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _MockL2BridgeAdapter.Contract.contract.Transfer(opts)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _MockL2BridgeAdapter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterCaller) FinalizeWithdrawERC20(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ var out []interface{}
+ err := _MockL2BridgeAdapter.contract.Call(opts, &out, "finalizeWithdrawERC20", arg0, arg1, arg2)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ return _MockL2BridgeAdapter.Contract.FinalizeWithdrawERC20(&_MockL2BridgeAdapter.CallOpts, arg0, arg1, arg2)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterCallerSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ return _MockL2BridgeAdapter.Contract.FinalizeWithdrawERC20(&_MockL2BridgeAdapter.CallOpts, arg0, arg1, arg2)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterCaller) GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _MockL2BridgeAdapter.contract.Call(opts, &out, "getBridgeFeeInNative")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _MockL2BridgeAdapter.Contract.GetBridgeFeeInNative(&_MockL2BridgeAdapter.CallOpts)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterCallerSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _MockL2BridgeAdapter.Contract.GetBridgeFeeInNative(&_MockL2BridgeAdapter.CallOpts)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterTransactor) SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, arg2 common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _MockL2BridgeAdapter.contract.Transact(opts, "sendERC20", localToken, arg1, arg2, amount, arg4)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterSession) SendERC20(localToken common.Address, arg1 common.Address, arg2 common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _MockL2BridgeAdapter.Contract.SendERC20(&_MockL2BridgeAdapter.TransactOpts, localToken, arg1, arg2, amount, arg4)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapterTransactorSession) SendERC20(localToken common.Address, arg1 common.Address, arg2 common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _MockL2BridgeAdapter.Contract.SendERC20(&_MockL2BridgeAdapter.TransactOpts, localToken, arg1, arg2, amount, arg4)
+}
+
+func (_MockL2BridgeAdapter *MockL2BridgeAdapter) Address() common.Address {
+ return _MockL2BridgeAdapter.address
+}
+
+type MockL2BridgeAdapterInterface interface {
+ FinalizeWithdrawERC20(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error)
+
+ GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error)
+
+ SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, arg2 common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/no_op_ocr3/no_op_ocr3.go b/core/gethwrappers/liquiditymanager/generated/no_op_ocr3/no_op_ocr3.go
new file mode 100644
index 00000000000..c9dca8b5f4f
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/no_op_ocr3/no_op_ocr3.go
@@ -0,0 +1,946 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package no_op_ocr3
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var NoOpOCR3MetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"expected\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"actual\",\"type\":\"bytes32\"}],\"name\":\"ConfigDigestMismatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"ForkedChain\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"latestSequenceNumber\",\"type\":\"uint64\"}],\"name\":\"NonIncreasingSequenceNumber\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OracleCannotBeZeroAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SignaturesOutOfRegistration\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedTransmitter\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actual\",\"type\":\"uint256\"}],\"name\":\"WrongMessageLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WrongNumberOfSignatures\",\"type\":\"error\"},{\"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\":\"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\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTransmitters\",\"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\":\"latestSequenceNumber\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"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\":\"setOCR3Config\",\"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\":\"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\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+ Bin: "0x60a060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b038481169190911790915581161561009757610097816100a3565b5050466080525061014c565b336001600160a01b038216036100fb5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b608051611c0d6200016f60003960008181610cb40152610d000152611c0d6000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c806381ff704811610076578063b1dc65a41161005b578063b1dc65a414610184578063f1c0461614610197578063f2fde38b146101c957600080fd5b806381ff70481461012c5780638da5cb5b1461015c57600080fd5b8063181f5a77146100a8578063666cab8d146100fa5780636a11ee901461010f57806379ba509714610124575b600080fd5b6100e46040518060400160405280600e81526020017f4e6f4f704f43523320312e302e3000000000000000000000000000000000000081525081565b6040516100f1919061153b565b60405180910390f35b6101026101dc565b6040516100f191906115a7565b61012261011d36600461179f565b61024b565b005b610122610a7f565b6004546002546040805163ffffffff808516825264010000000090940490931660208401528201526060016100f1565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f1565b6101226101923660046118b8565b610b7c565b60045468010000000000000000900467ffffffffffffffff1660405167ffffffffffffffff90911681526020016100f1565b6101226101d736600461199d565b6111e2565b6060600780548060200260200160405190810160405280929190818152602001828054801561024157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610216575b5050505050905090565b855185518560ff16601f8311156102c3576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e6572730000000000000000000000000000000060448201526064015b60405180910390fd5b8060000361032d576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f736974697665000000000000000000000000000060448201526064016102ba565b8183146103bb576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e0000000000000000000000000000000000000000000000000000000060648201526084016102ba565b6103c68160036119e7565b831161042e576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f2068696768000000000000000060448201526064016102ba565b6104366111f6565b60065460005b8181101561052a57600560006006838154811061045b5761045b611a04565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000169055600780546005929190849081106104cb576104cb611a04565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016905560010161043c565b50895160005b818110156108fd5760008c828151811061054c5761054c611a04565b602002602001015190506000600281111561056957610569611a33565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff1660028111156105a8576105a8611a33565b1461060f576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e6572206164647265737300000000000000000060448201526064016102ba565b73ffffffffffffffffffffffffffffffffffffffff811661065c576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff83168152602081016001905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561070c5761070c611a33565b021790555090505060008c838151811061072857610728611a04565b602002602001015190506000600281111561074557610745611a33565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260056020526040902054610100900460ff16600281111561078457610784611a33565b146107eb576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d697474657220616464726573730000000060448201526064016102ba565b73ffffffffffffffffffffffffffffffffffffffff8116610838576040517fd6c62c9b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805180820190915260ff84168152602081016002905273ffffffffffffffffffffffffffffffffffffffff821660009081526005602090815260409091208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156108e8576108e8611a33565b02179055509050505050806001019050610530565b508a516109119060069060208e0190611419565b5089516109259060079060208d0190611419565b506003805460ff838116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909216908c1617179055600480546109ab91469130919060009061097d9063ffffffff16611a62565b91906101000a81548163ffffffff021916908363ffffffff160217905563ffffffff168e8e8e8e8e8e611279565b600260000181905550600060048054906101000a900463ffffffff169050436004806101000a81548163ffffffff021916908363ffffffff1602179055506000600460086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0581600260000154600460009054906101000a900463ffffffff168f8f8f8f8f8f604051610a6999989796959493929190611a85565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016102ba565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60045460208901359067ffffffffffffffff68010000000000000000909104811690821611610bff57600480546040517f6e376b6600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff808516938201939093526801000000000000000090910490911660248201526044016102ba565b600480547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff8416021790556040805160608101825260025480825260035460ff808216602085015261010090910416928201929092528a35918214610cb15780516040517f93df584c0000000000000000000000000000000000000000000000000000000081526004810191909152602481018390526044016102ba565b467f000000000000000000000000000000000000000000000000000000000000000014610d32576040517f0f01ce850000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000060048201524660248201526044016102ba565b6040805183815267ffffffffffffffff851660208201527fe893c2681d327421d89e1cb54fbe64645b4dcea668d6826130b62cf4c6eefea2910160405180910390a16020810151610d84906001611b1b565b60ff168714610dbf576040517f71253a2500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b868514610df8576040517fa75d88af00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526005602090815260408083208151808301909252805460ff80821684529293919291840191610100909104166002811115610e3b57610e3b611a33565b6002811115610e4c57610e4c611a33565b9052509050600281602001516002811115610e6957610e69611a33565b148015610eb057506007816000015160ff1681548110610e8b57610e8b611a04565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b610ee6576040517fda0f08e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000610ef48660206119e7565b610eff8960206119e7565b610f0b8c610144611b34565b610f159190611b34565b610f1f9190611b34565b9050368114610f63576040517f8e1192e1000000000000000000000000000000000000000000000000000000008152600481018290523660248201526044016102ba565b5060008a8a604051610f76929190611b47565b604051908190038120610f8d918e90602001611b57565b604051602081830303815290604052805190602001209050610fad6114a3565b8860005b818110156111d15760006001858a8460208110610fd057610fd0611a04565b610fdd91901a601b611b1b565b8f8f86818110610fef57610fef611a04565b905060200201358e8e8781811061100857611008611a04565b9050602002013560405160008152602001604052604051611045949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611067573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152848220848601909552845460ff80821686529397509195509293928401916101009091041660028111156110ea576110ea611a33565b60028111156110fb576110fb611a33565b905250905060018160200151600281111561111857611118611a33565b1461114f576040517fca31867a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051859060ff16601f811061116657611166611a04565b6020020151156111a2576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600185826000015160ff16601f81106111bd576111bd611a04565b911515602090920201525050600101610fb1565b505050505050505050505050505050565b6111ea6111f6565b6111f381611324565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314611277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016102ba565b565b6000808a8a8a8a8a8a8a8a8a60405160200161129d99989796959493929190611b6b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036113a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016102ba565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215611493579160200282015b8281111561149357825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190611439565b5061149f9291506114c2565b5090565b604051806103e00160405280601f906020820280368337509192915050565b5b8082111561149f57600081556001016114c3565b6000815180845260005b818110156114fd576020818501810151868301820152016114e1565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061154e60208301846114d7565b9392505050565b60008151808452602080850194506020840160005b8381101561159c57815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161156a565b509495945050505050565b60208152600061154e6020830184611555565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611630576116306115ba565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461165c57600080fd5b919050565b600082601f83011261167257600080fd5b8135602067ffffffffffffffff82111561168e5761168e6115ba565b8160051b61169d8282016115e9565b92835284810182019282810190878511156116b757600080fd5b83870192505b848310156116dd576116ce83611638565b825291830191908301906116bd565b979650505050505050565b803560ff8116811461165c57600080fd5b600082601f83011261170a57600080fd5b813567ffffffffffffffff811115611724576117246115ba565b61175560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016115e9565b81815284602083860101111561176a57600080fd5b816020850160208301376000918101602001919091529392505050565b803567ffffffffffffffff8116811461165c57600080fd5b60008060008060008060c087890312156117b857600080fd5b863567ffffffffffffffff808211156117d057600080fd5b6117dc8a838b01611661565b975060208901359150808211156117f257600080fd5b6117fe8a838b01611661565b965061180c60408a016116e8565b9550606089013591508082111561182257600080fd5b61182e8a838b016116f9565b945061183c60808a01611787565b935060a089013591508082111561185257600080fd5b5061185f89828a016116f9565b9150509295509295509295565b60008083601f84011261187e57600080fd5b50813567ffffffffffffffff81111561189657600080fd5b6020830191508360208260051b85010111156118b157600080fd5b9250929050565b60008060008060008060008060e0898b0312156118d457600080fd5b606089018a8111156118e557600080fd5b8998503567ffffffffffffffff808211156118ff57600080fd5b818b0191508b601f83011261191357600080fd5b81358181111561192257600080fd5b8c602082850101111561193457600080fd5b6020830199508098505060808b013591508082111561195257600080fd5b61195e8c838d0161186c565b909750955060a08b013591508082111561197757600080fd5b506119848b828c0161186c565b999c989b50969995989497949560c00135949350505050565b6000602082840312156119af57600080fd5b61154e82611638565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176119fe576119fe6119b8565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600063ffffffff808316818103611a7b57611a7b6119b8565b6001019392505050565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152611ab58184018a611555565b90508281036080840152611ac98189611555565b905060ff871660a084015282810360c0840152611ae681876114d7565b905067ffffffffffffffff851660e0840152828103610100840152611b0b81856114d7565b9c9b505050505050505050505050565b60ff81811683821601908111156119fe576119fe6119b8565b808201808211156119fe576119fe6119b8565b8183823760009101908152919050565b828152606082602083013760800192915050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152611bb28285018b611555565b91508382036080850152611bc6828a611555565b915060ff881660a085015283820360c0850152611be382886114d7565b90861660e08501528381036101008501529050611b0b81856114d756fea164736f6c6343000818000a",
+}
+
+var NoOpOCR3ABI = NoOpOCR3MetaData.ABI
+
+var NoOpOCR3Bin = NoOpOCR3MetaData.Bin
+
+func DeployNoOpOCR3(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *NoOpOCR3, error) {
+ parsed, err := NoOpOCR3MetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(NoOpOCR3Bin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &NoOpOCR3{address: address, abi: *parsed, NoOpOCR3Caller: NoOpOCR3Caller{contract: contract}, NoOpOCR3Transactor: NoOpOCR3Transactor{contract: contract}, NoOpOCR3Filterer: NoOpOCR3Filterer{contract: contract}}, nil
+}
+
+type NoOpOCR3 struct {
+ address common.Address
+ abi abi.ABI
+ NoOpOCR3Caller
+ NoOpOCR3Transactor
+ NoOpOCR3Filterer
+}
+
+type NoOpOCR3Caller struct {
+ contract *bind.BoundContract
+}
+
+type NoOpOCR3Transactor struct {
+ contract *bind.BoundContract
+}
+
+type NoOpOCR3Filterer struct {
+ contract *bind.BoundContract
+}
+
+type NoOpOCR3Session struct {
+ Contract *NoOpOCR3
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type NoOpOCR3CallerSession struct {
+ Contract *NoOpOCR3Caller
+ CallOpts bind.CallOpts
+}
+
+type NoOpOCR3TransactorSession struct {
+ Contract *NoOpOCR3Transactor
+ TransactOpts bind.TransactOpts
+}
+
+type NoOpOCR3Raw struct {
+ Contract *NoOpOCR3
+}
+
+type NoOpOCR3CallerRaw struct {
+ Contract *NoOpOCR3Caller
+}
+
+type NoOpOCR3TransactorRaw struct {
+ Contract *NoOpOCR3Transactor
+}
+
+func NewNoOpOCR3(address common.Address, backend bind.ContractBackend) (*NoOpOCR3, error) {
+ abi, err := abi.JSON(strings.NewReader(NoOpOCR3ABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindNoOpOCR3(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &NoOpOCR3{address: address, abi: abi, NoOpOCR3Caller: NoOpOCR3Caller{contract: contract}, NoOpOCR3Transactor: NoOpOCR3Transactor{contract: contract}, NoOpOCR3Filterer: NoOpOCR3Filterer{contract: contract}}, nil
+}
+
+func NewNoOpOCR3Caller(address common.Address, caller bind.ContractCaller) (*NoOpOCR3Caller, error) {
+ contract, err := bindNoOpOCR3(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &NoOpOCR3Caller{contract: contract}, nil
+}
+
+func NewNoOpOCR3Transactor(address common.Address, transactor bind.ContractTransactor) (*NoOpOCR3Transactor, error) {
+ contract, err := bindNoOpOCR3(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &NoOpOCR3Transactor{contract: contract}, nil
+}
+
+func NewNoOpOCR3Filterer(address common.Address, filterer bind.ContractFilterer) (*NoOpOCR3Filterer, error) {
+ contract, err := bindNoOpOCR3(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &NoOpOCR3Filterer{contract: contract}, nil
+}
+
+func bindNoOpOCR3(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := NoOpOCR3MetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_NoOpOCR3 *NoOpOCR3Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _NoOpOCR3.Contract.NoOpOCR3Caller.contract.Call(opts, result, method, params...)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.NoOpOCR3Transactor.contract.Transfer(opts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.NoOpOCR3Transactor.contract.Transact(opts, method, params...)
+}
+
+func (_NoOpOCR3 *NoOpOCR3CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _NoOpOCR3.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_NoOpOCR3 *NoOpOCR3TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.contract.Transfer(opts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Caller) GetTransmitters(opts *bind.CallOpts) ([]common.Address, error) {
+ var out []interface{}
+ err := _NoOpOCR3.contract.Call(opts, &out, "getTransmitters")
+
+ if err != nil {
+ return *new([]common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address)
+
+ return out0, err
+
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) GetTransmitters() ([]common.Address, error) {
+ return _NoOpOCR3.Contract.GetTransmitters(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3CallerSession) GetTransmitters() ([]common.Address, error) {
+ return _NoOpOCR3.Contract.GetTransmitters(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Caller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error) {
+ var out []interface{}
+ err := _NoOpOCR3.contract.Call(opts, &out, "latestConfigDetails")
+
+ outstruct := new(LatestConfigDetails)
+ if err != nil {
+ return *outstruct, err
+ }
+
+ outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32)
+ outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32)
+ outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte)
+
+ return *outstruct, err
+
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _NoOpOCR3.Contract.LatestConfigDetails(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3CallerSession) LatestConfigDetails() (LatestConfigDetails,
+
+ error) {
+ return _NoOpOCR3.Contract.LatestConfigDetails(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Caller) LatestSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ var out []interface{}
+ err := _NoOpOCR3.contract.Call(opts, &out, "latestSequenceNumber")
+
+ if err != nil {
+ return *new(uint64), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64)
+
+ return out0, err
+
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) LatestSequenceNumber() (uint64, error) {
+ return _NoOpOCR3.Contract.LatestSequenceNumber(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3CallerSession) LatestSequenceNumber() (uint64, error) {
+ return _NoOpOCR3.Contract.LatestSequenceNumber(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Caller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _NoOpOCR3.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) Owner() (common.Address, error) {
+ return _NoOpOCR3.Contract.Owner(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3CallerSession) Owner() (common.Address, error) {
+ return _NoOpOCR3.Contract.Owner(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Caller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _NoOpOCR3.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) TypeAndVersion() (string, error) {
+ return _NoOpOCR3.Contract.TypeAndVersion(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3CallerSession) TypeAndVersion() (string, error) {
+ return _NoOpOCR3.Contract.TypeAndVersion(&_NoOpOCR3.CallOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Transactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _NoOpOCR3.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) AcceptOwnership() (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.AcceptOwnership(&_NoOpOCR3.TransactOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3TransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.AcceptOwnership(&_NoOpOCR3.TransactOpts)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Transactor) SetOCR3Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _NoOpOCR3.contract.Transact(opts, "setOCR3Config", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) SetOCR3Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.SetOCR3Config(&_NoOpOCR3.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_NoOpOCR3 *NoOpOCR3TransactorSession) SetOCR3Config(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.SetOCR3Config(&_NoOpOCR3.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Transactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _NoOpOCR3.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.TransferOwnership(&_NoOpOCR3.TransactOpts, to)
+}
+
+func (_NoOpOCR3 *NoOpOCR3TransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.TransferOwnership(&_NoOpOCR3.TransactOpts, to)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Transactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _NoOpOCR3.contract.Transact(opts, "transmit", reportContext, report, rs, ss, rawVs)
+}
+
+func (_NoOpOCR3 *NoOpOCR3Session) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.Transmit(&_NoOpOCR3.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+func (_NoOpOCR3 *NoOpOCR3TransactorSession) Transmit(reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) {
+ return _NoOpOCR3.Contract.Transmit(&_NoOpOCR3.TransactOpts, reportContext, report, rs, ss, rawVs)
+}
+
+type NoOpOCR3ConfigSetIterator struct {
+ Event *NoOpOCR3ConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NoOpOCR3ConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NoOpOCR3ConfigSet)
+ 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(NoOpOCR3ConfigSet)
+ 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 *NoOpOCR3ConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *NoOpOCR3ConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NoOpOCR3ConfigSet struct {
+ PreviousConfigBlockNumber uint32
+ ConfigDigest [32]byte
+ ConfigCount uint64
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+ Raw types.Log
+}
+
+func (_NoOpOCR3 *NoOpOCR3Filterer) FilterConfigSet(opts *bind.FilterOpts) (*NoOpOCR3ConfigSetIterator, error) {
+
+ logs, sub, err := _NoOpOCR3.contract.FilterLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return &NoOpOCR3ConfigSetIterator{contract: _NoOpOCR3.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_NoOpOCR3 *NoOpOCR3Filterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *NoOpOCR3ConfigSet) (event.Subscription, error) {
+
+ logs, sub, err := _NoOpOCR3.contract.WatchLogs(opts, "ConfigSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NoOpOCR3ConfigSet)
+ if err := _NoOpOCR3.contract.UnpackLog(event, "ConfigSet", 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 (_NoOpOCR3 *NoOpOCR3Filterer) ParseConfigSet(log types.Log) (*NoOpOCR3ConfigSet, error) {
+ event := new(NoOpOCR3ConfigSet)
+ if err := _NoOpOCR3.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type NoOpOCR3OwnershipTransferRequestedIterator struct {
+ Event *NoOpOCR3OwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NoOpOCR3OwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NoOpOCR3OwnershipTransferRequested)
+ 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(NoOpOCR3OwnershipTransferRequested)
+ 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 *NoOpOCR3OwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *NoOpOCR3OwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NoOpOCR3OwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_NoOpOCR3 *NoOpOCR3Filterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NoOpOCR3OwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _NoOpOCR3.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &NoOpOCR3OwnershipTransferRequestedIterator{contract: _NoOpOCR3.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_NoOpOCR3 *NoOpOCR3Filterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *NoOpOCR3OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _NoOpOCR3.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NoOpOCR3OwnershipTransferRequested)
+ if err := _NoOpOCR3.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_NoOpOCR3 *NoOpOCR3Filterer) ParseOwnershipTransferRequested(log types.Log) (*NoOpOCR3OwnershipTransferRequested, error) {
+ event := new(NoOpOCR3OwnershipTransferRequested)
+ if err := _NoOpOCR3.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type NoOpOCR3OwnershipTransferredIterator struct {
+ Event *NoOpOCR3OwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NoOpOCR3OwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NoOpOCR3OwnershipTransferred)
+ 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(NoOpOCR3OwnershipTransferred)
+ 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 *NoOpOCR3OwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *NoOpOCR3OwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NoOpOCR3OwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_NoOpOCR3 *NoOpOCR3Filterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NoOpOCR3OwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _NoOpOCR3.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &NoOpOCR3OwnershipTransferredIterator{contract: _NoOpOCR3.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_NoOpOCR3 *NoOpOCR3Filterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *NoOpOCR3OwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _NoOpOCR3.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NoOpOCR3OwnershipTransferred)
+ if err := _NoOpOCR3.contract.UnpackLog(event, "OwnershipTransferred", 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 (_NoOpOCR3 *NoOpOCR3Filterer) ParseOwnershipTransferred(log types.Log) (*NoOpOCR3OwnershipTransferred, error) {
+ event := new(NoOpOCR3OwnershipTransferred)
+ if err := _NoOpOCR3.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type NoOpOCR3TransmittedIterator struct {
+ Event *NoOpOCR3Transmitted
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *NoOpOCR3TransmittedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(NoOpOCR3Transmitted)
+ 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(NoOpOCR3Transmitted)
+ 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 *NoOpOCR3TransmittedIterator) Error() error {
+ return it.fail
+}
+
+func (it *NoOpOCR3TransmittedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type NoOpOCR3Transmitted struct {
+ ConfigDigest [32]byte
+ SequenceNumber uint64
+ Raw types.Log
+}
+
+func (_NoOpOCR3 *NoOpOCR3Filterer) FilterTransmitted(opts *bind.FilterOpts) (*NoOpOCR3TransmittedIterator, error) {
+
+ logs, sub, err := _NoOpOCR3.contract.FilterLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return &NoOpOCR3TransmittedIterator{contract: _NoOpOCR3.contract, event: "Transmitted", logs: logs, sub: sub}, nil
+}
+
+func (_NoOpOCR3 *NoOpOCR3Filterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *NoOpOCR3Transmitted) (event.Subscription, error) {
+
+ logs, sub, err := _NoOpOCR3.contract.WatchLogs(opts, "Transmitted")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(NoOpOCR3Transmitted)
+ if err := _NoOpOCR3.contract.UnpackLog(event, "Transmitted", 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 (_NoOpOCR3 *NoOpOCR3Filterer) ParseTransmitted(log types.Log) (*NoOpOCR3Transmitted, error) {
+ event := new(NoOpOCR3Transmitted)
+ if err := _NoOpOCR3.contract.UnpackLog(event, "Transmitted", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type LatestConfigDetails struct {
+ ConfigCount uint32
+ BlockNumber uint32
+ ConfigDigest [32]byte
+}
+
+func (_NoOpOCR3 *NoOpOCR3) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _NoOpOCR3.abi.Events["ConfigSet"].ID:
+ return _NoOpOCR3.ParseConfigSet(log)
+ case _NoOpOCR3.abi.Events["OwnershipTransferRequested"].ID:
+ return _NoOpOCR3.ParseOwnershipTransferRequested(log)
+ case _NoOpOCR3.abi.Events["OwnershipTransferred"].ID:
+ return _NoOpOCR3.ParseOwnershipTransferred(log)
+ case _NoOpOCR3.abi.Events["Transmitted"].ID:
+ return _NoOpOCR3.ParseTransmitted(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (NoOpOCR3ConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+}
+
+func (NoOpOCR3OwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (NoOpOCR3OwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (NoOpOCR3Transmitted) Topic() common.Hash {
+ return common.HexToHash("0xe893c2681d327421d89e1cb54fbe64645b4dcea668d6826130b62cf4c6eefea2")
+}
+
+func (_NoOpOCR3 *NoOpOCR3) Address() common.Address {
+ return _NoOpOCR3.address
+}
+
+type NoOpOCR3Interface interface {
+ GetTransmitters(opts *bind.CallOpts) ([]common.Address, error)
+
+ LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails,
+
+ error)
+
+ LatestSequenceNumber(opts *bind.CallOpts) (uint64, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetOCR3Config(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error)
+
+ FilterConfigSet(opts *bind.FilterOpts) (*NoOpOCR3ConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *NoOpOCR3ConfigSet) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*NoOpOCR3ConfigSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NoOpOCR3OwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *NoOpOCR3OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*NoOpOCR3OwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NoOpOCR3OwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *NoOpOCR3OwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*NoOpOCR3OwnershipTransferred, error)
+
+ FilterTransmitted(opts *bind.FilterOpts) (*NoOpOCR3TransmittedIterator, error)
+
+ WatchTransmitted(opts *bind.WatchOpts, sink chan<- *NoOpOCR3Transmitted) (event.Subscription, error)
+
+ ParseTransmitted(log types.Log) (*NoOpOCR3Transmitted, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_cross_domain_messenger/optimism_cross_domain_messenger.go b/core/gethwrappers/liquiditymanager/generated/optimism_cross_domain_messenger/optimism_cross_domain_messenger.go
new file mode 100644
index 00000000000..599d2e3739f
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_cross_domain_messenger/optimism_cross_domain_messenger.go
@@ -0,0 +1,328 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_cross_domain_messenger
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var OptimismCrossDomainMessengerMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"messageNonce\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"SentMessage\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_minGasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_message\",\"type\":\"bytes\"}],\"name\":\"relayMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+}
+
+var OptimismCrossDomainMessengerABI = OptimismCrossDomainMessengerMetaData.ABI
+
+type OptimismCrossDomainMessenger struct {
+ address common.Address
+ abi abi.ABI
+ OptimismCrossDomainMessengerCaller
+ OptimismCrossDomainMessengerTransactor
+ OptimismCrossDomainMessengerFilterer
+}
+
+type OptimismCrossDomainMessengerCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismCrossDomainMessengerTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismCrossDomainMessengerFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismCrossDomainMessengerSession struct {
+ Contract *OptimismCrossDomainMessenger
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismCrossDomainMessengerCallerSession struct {
+ Contract *OptimismCrossDomainMessengerCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismCrossDomainMessengerTransactorSession struct {
+ Contract *OptimismCrossDomainMessengerTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismCrossDomainMessengerRaw struct {
+ Contract *OptimismCrossDomainMessenger
+}
+
+type OptimismCrossDomainMessengerCallerRaw struct {
+ Contract *OptimismCrossDomainMessengerCaller
+}
+
+type OptimismCrossDomainMessengerTransactorRaw struct {
+ Contract *OptimismCrossDomainMessengerTransactor
+}
+
+func NewOptimismCrossDomainMessenger(address common.Address, backend bind.ContractBackend) (*OptimismCrossDomainMessenger, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismCrossDomainMessengerABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismCrossDomainMessenger(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismCrossDomainMessenger{address: address, abi: abi, OptimismCrossDomainMessengerCaller: OptimismCrossDomainMessengerCaller{contract: contract}, OptimismCrossDomainMessengerTransactor: OptimismCrossDomainMessengerTransactor{contract: contract}, OptimismCrossDomainMessengerFilterer: OptimismCrossDomainMessengerFilterer{contract: contract}}, nil
+}
+
+func NewOptimismCrossDomainMessengerCaller(address common.Address, caller bind.ContractCaller) (*OptimismCrossDomainMessengerCaller, error) {
+ contract, err := bindOptimismCrossDomainMessenger(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismCrossDomainMessengerCaller{contract: contract}, nil
+}
+
+func NewOptimismCrossDomainMessengerTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismCrossDomainMessengerTransactor, error) {
+ contract, err := bindOptimismCrossDomainMessenger(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismCrossDomainMessengerTransactor{contract: contract}, nil
+}
+
+func NewOptimismCrossDomainMessengerFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismCrossDomainMessengerFilterer, error) {
+ contract, err := bindOptimismCrossDomainMessenger(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismCrossDomainMessengerFilterer{contract: contract}, nil
+}
+
+func bindOptimismCrossDomainMessenger(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismCrossDomainMessengerMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismCrossDomainMessenger.Contract.OptimismCrossDomainMessengerCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismCrossDomainMessenger.Contract.OptimismCrossDomainMessengerTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismCrossDomainMessenger.Contract.OptimismCrossDomainMessengerTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismCrossDomainMessenger.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismCrossDomainMessenger.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismCrossDomainMessenger.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerTransactor) RelayMessage(opts *bind.TransactOpts, _nonce *big.Int, _sender common.Address, _target common.Address, _value *big.Int, _minGasLimit *big.Int, _message []byte) (*types.Transaction, error) {
+ return _OptimismCrossDomainMessenger.contract.Transact(opts, "relayMessage", _nonce, _sender, _target, _value, _minGasLimit, _message)
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerSession) RelayMessage(_nonce *big.Int, _sender common.Address, _target common.Address, _value *big.Int, _minGasLimit *big.Int, _message []byte) (*types.Transaction, error) {
+ return _OptimismCrossDomainMessenger.Contract.RelayMessage(&_OptimismCrossDomainMessenger.TransactOpts, _nonce, _sender, _target, _value, _minGasLimit, _message)
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerTransactorSession) RelayMessage(_nonce *big.Int, _sender common.Address, _target common.Address, _value *big.Int, _minGasLimit *big.Int, _message []byte) (*types.Transaction, error) {
+ return _OptimismCrossDomainMessenger.Contract.RelayMessage(&_OptimismCrossDomainMessenger.TransactOpts, _nonce, _sender, _target, _value, _minGasLimit, _message)
+}
+
+type OptimismCrossDomainMessengerSentMessageIterator struct {
+ Event *OptimismCrossDomainMessengerSentMessage
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *OptimismCrossDomainMessengerSentMessageIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(OptimismCrossDomainMessengerSentMessage)
+ 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(OptimismCrossDomainMessengerSentMessage)
+ 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 *OptimismCrossDomainMessengerSentMessageIterator) Error() error {
+ return it.fail
+}
+
+func (it *OptimismCrossDomainMessengerSentMessageIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type OptimismCrossDomainMessengerSentMessage struct {
+ Target common.Address
+ Sender common.Address
+ Message []byte
+ MessageNonce *big.Int
+ GasLimit *big.Int
+ Raw types.Log
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerFilterer) FilterSentMessage(opts *bind.FilterOpts, target []common.Address) (*OptimismCrossDomainMessengerSentMessageIterator, error) {
+
+ var targetRule []interface{}
+ for _, targetItem := range target {
+ targetRule = append(targetRule, targetItem)
+ }
+
+ logs, sub, err := _OptimismCrossDomainMessenger.contract.FilterLogs(opts, "SentMessage", targetRule)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismCrossDomainMessengerSentMessageIterator{contract: _OptimismCrossDomainMessenger.contract, event: "SentMessage", logs: logs, sub: sub}, nil
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerFilterer) WatchSentMessage(opts *bind.WatchOpts, sink chan<- *OptimismCrossDomainMessengerSentMessage, target []common.Address) (event.Subscription, error) {
+
+ var targetRule []interface{}
+ for _, targetItem := range target {
+ targetRule = append(targetRule, targetItem)
+ }
+
+ logs, sub, err := _OptimismCrossDomainMessenger.contract.WatchLogs(opts, "SentMessage", targetRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(OptimismCrossDomainMessengerSentMessage)
+ if err := _OptimismCrossDomainMessenger.contract.UnpackLog(event, "SentMessage", 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 (_OptimismCrossDomainMessenger *OptimismCrossDomainMessengerFilterer) ParseSentMessage(log types.Log) (*OptimismCrossDomainMessengerSentMessage, error) {
+ event := new(OptimismCrossDomainMessengerSentMessage)
+ if err := _OptimismCrossDomainMessenger.contract.UnpackLog(event, "SentMessage", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessenger) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _OptimismCrossDomainMessenger.abi.Events["SentMessage"].ID:
+ return _OptimismCrossDomainMessenger.ParseSentMessage(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (OptimismCrossDomainMessengerSentMessage) Topic() common.Hash {
+ return common.HexToHash("0xcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a")
+}
+
+func (_OptimismCrossDomainMessenger *OptimismCrossDomainMessenger) Address() common.Address {
+ return _OptimismCrossDomainMessenger.address
+}
+
+type OptimismCrossDomainMessengerInterface interface {
+ RelayMessage(opts *bind.TransactOpts, _nonce *big.Int, _sender common.Address, _target common.Address, _value *big.Int, _minGasLimit *big.Int, _message []byte) (*types.Transaction, error)
+
+ FilterSentMessage(opts *bind.FilterOpts, target []common.Address) (*OptimismCrossDomainMessengerSentMessageIterator, error)
+
+ WatchSentMessage(opts *bind.WatchOpts, sink chan<- *OptimismCrossDomainMessengerSentMessage, target []common.Address) (event.Subscription, error)
+
+ ParseSentMessage(log types.Log) (*OptimismCrossDomainMessengerSentMessage, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_dispute_game_factory/optimism_dispute_game_factory.go b/core/gethwrappers/liquiditymanager/generated/optimism_dispute_game_factory/optimism_dispute_game_factory.go
new file mode 100644
index 00000000000..909324ad1fb
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_dispute_game_factory/optimism_dispute_game_factory.go
@@ -0,0 +1,215 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_dispute_game_factory
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type IOptimismDisputeGameFactoryGameSearchResult struct {
+ Index *big.Int
+ Metadata [32]byte
+ Timestamp uint64
+ RootClaim [32]byte
+ ExtraData []byte
+}
+
+var OptimismDisputeGameFactoryMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"GameType\",\"name\":\"_gameType\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"_start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_n\",\"type\":\"uint256\"}],\"name\":\"findLatestGames\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"GameId\",\"name\":\"metadata\",\"type\":\"bytes32\"},{\"internalType\":\"Timestamp\",\"name\":\"timestamp\",\"type\":\"uint64\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"internalType\":\"structIOptimismDisputeGameFactory.GameSearchResult[]\",\"name\":\"games_\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gameCount_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var OptimismDisputeGameFactoryABI = OptimismDisputeGameFactoryMetaData.ABI
+
+type OptimismDisputeGameFactory struct {
+ address common.Address
+ abi abi.ABI
+ OptimismDisputeGameFactoryCaller
+ OptimismDisputeGameFactoryTransactor
+ OptimismDisputeGameFactoryFilterer
+}
+
+type OptimismDisputeGameFactoryCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismDisputeGameFactoryTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismDisputeGameFactoryFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismDisputeGameFactorySession struct {
+ Contract *OptimismDisputeGameFactory
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismDisputeGameFactoryCallerSession struct {
+ Contract *OptimismDisputeGameFactoryCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismDisputeGameFactoryTransactorSession struct {
+ Contract *OptimismDisputeGameFactoryTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismDisputeGameFactoryRaw struct {
+ Contract *OptimismDisputeGameFactory
+}
+
+type OptimismDisputeGameFactoryCallerRaw struct {
+ Contract *OptimismDisputeGameFactoryCaller
+}
+
+type OptimismDisputeGameFactoryTransactorRaw struct {
+ Contract *OptimismDisputeGameFactoryTransactor
+}
+
+func NewOptimismDisputeGameFactory(address common.Address, backend bind.ContractBackend) (*OptimismDisputeGameFactory, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismDisputeGameFactoryABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismDisputeGameFactory(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismDisputeGameFactory{address: address, abi: abi, OptimismDisputeGameFactoryCaller: OptimismDisputeGameFactoryCaller{contract: contract}, OptimismDisputeGameFactoryTransactor: OptimismDisputeGameFactoryTransactor{contract: contract}, OptimismDisputeGameFactoryFilterer: OptimismDisputeGameFactoryFilterer{contract: contract}}, nil
+}
+
+func NewOptimismDisputeGameFactoryCaller(address common.Address, caller bind.ContractCaller) (*OptimismDisputeGameFactoryCaller, error) {
+ contract, err := bindOptimismDisputeGameFactory(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismDisputeGameFactoryCaller{contract: contract}, nil
+}
+
+func NewOptimismDisputeGameFactoryTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismDisputeGameFactoryTransactor, error) {
+ contract, err := bindOptimismDisputeGameFactory(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismDisputeGameFactoryTransactor{contract: contract}, nil
+}
+
+func NewOptimismDisputeGameFactoryFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismDisputeGameFactoryFilterer, error) {
+ contract, err := bindOptimismDisputeGameFactory(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismDisputeGameFactoryFilterer{contract: contract}, nil
+}
+
+func bindOptimismDisputeGameFactory(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismDisputeGameFactoryMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismDisputeGameFactory.Contract.OptimismDisputeGameFactoryCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismDisputeGameFactory.Contract.OptimismDisputeGameFactoryTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismDisputeGameFactory.Contract.OptimismDisputeGameFactoryTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismDisputeGameFactory.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismDisputeGameFactory.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismDisputeGameFactory.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryCaller) FindLatestGames(opts *bind.CallOpts, _gameType uint32, _start *big.Int, _n *big.Int) ([]IOptimismDisputeGameFactoryGameSearchResult, error) {
+ var out []interface{}
+ err := _OptimismDisputeGameFactory.contract.Call(opts, &out, "findLatestGames", _gameType, _start, _n)
+
+ if err != nil {
+ return *new([]IOptimismDisputeGameFactoryGameSearchResult), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]IOptimismDisputeGameFactoryGameSearchResult)).(*[]IOptimismDisputeGameFactoryGameSearchResult)
+
+ return out0, err
+
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactorySession) FindLatestGames(_gameType uint32, _start *big.Int, _n *big.Int) ([]IOptimismDisputeGameFactoryGameSearchResult, error) {
+ return _OptimismDisputeGameFactory.Contract.FindLatestGames(&_OptimismDisputeGameFactory.CallOpts, _gameType, _start, _n)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryCallerSession) FindLatestGames(_gameType uint32, _start *big.Int, _n *big.Int) ([]IOptimismDisputeGameFactoryGameSearchResult, error) {
+ return _OptimismDisputeGameFactory.Contract.FindLatestGames(&_OptimismDisputeGameFactory.CallOpts, _gameType, _start, _n)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryCaller) GameCount(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _OptimismDisputeGameFactory.contract.Call(opts, &out, "gameCount")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactorySession) GameCount() (*big.Int, error) {
+ return _OptimismDisputeGameFactory.Contract.GameCount(&_OptimismDisputeGameFactory.CallOpts)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactoryCallerSession) GameCount() (*big.Int, error) {
+ return _OptimismDisputeGameFactory.Contract.GameCount(&_OptimismDisputeGameFactory.CallOpts)
+}
+
+func (_OptimismDisputeGameFactory *OptimismDisputeGameFactory) Address() common.Address {
+ return _OptimismDisputeGameFactory.address
+}
+
+type OptimismDisputeGameFactoryInterface interface {
+ FindLatestGames(opts *bind.CallOpts, _gameType uint32, _start *big.Int, _n *big.Int) ([]IOptimismDisputeGameFactoryGameSearchResult, error)
+
+ GameCount(opts *bind.CallOpts) (*big.Int, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_l1_bridge_adapter/optimism_l1_bridge_adapter.go b/core/gethwrappers/liquiditymanager/generated/optimism_l1_bridge_adapter/optimism_l1_bridge_adapter.go
new file mode 100644
index 00000000000..189d13dd43d
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_l1_bridge_adapter/optimism_l1_bridge_adapter.go
@@ -0,0 +1,316 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_l1_bridge_adapter
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var OptimismL1BridgeAdapterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIL1StandardBridge\",\"name\":\"l1Bridge\",\"type\":\"address\"},{\"internalType\":\"contractIWrappedNative\",\"name\":\"wrappedNative\",\"type\":\"address\"},{\"internalType\":\"contractIOptimismPortal\",\"name\":\"optimismPortal\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BridgeAddressCannotBeZero\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wanted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"}],\"name\":\"InsufficientEthValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidFinalizationAction\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"MsgShouldNotContainValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"msgValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"MsgValueDoesNotMatchAmount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBridgeFeeInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL1Bridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOptimismPortal\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWrappedNative\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"sendERC20\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
+ Bin: "0x60e0604052600080546001600160401b03191690553480156200002157600080fd5b50604051620016e7380380620016e78339810160408190526200004491620000cb565b6001600160a01b03831615806200006257506001600160a01b038216155b806200007557506001600160a01b038116155b156200009457604051635e9c404d60e11b815260040160405180910390fd5b6001600160a01b0392831660805290821660a0521660c0526200011f565b6001600160a01b0381168114620000c857600080fd5b50565b600080600060608486031215620000e157600080fd5b8351620000ee81620000b2565b60208501519093506200010181620000b2565b60408501519092506200011481620000b2565b809150509250925092565b60805160a05160c0516115686200017f6000396000818160d5015281816105f901526106da01526000818161017c0152818161035401526103d40152600081816101490152818161048001528181610515015261057701526115686000f3fe6080604052600436106100695760003560e01c8063a71d98b711610043578063a71d98b71461011a578063c86d5bdd1461013a578063e861e9071461016d57600080fd5b80632e4b1fc91461007557806338314bb21461009657806354fd969f146100c657600080fd5b3661007057005b600080fd5b34801561008157600080fd5b50604051600081526020015b60405180910390f35b3480156100a257600080fd5b506100b66100b1366004610c62565b6101a0565b604051901515815260200161008d565b3480156100d257600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161008d565b61012d610128366004610cc7565b61027f565b60405161008d9190610dba565b34801561014657600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006100f5565b34801561017957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006100f5565b6000806101af83850185610ee4565b90506000815160018111156101c6576101c6610faa565b036101fb57600081602001518060200190518101906101e5919061116c565b90506101f0816105f7565b600092505050610277565b60018151600181111561021057610210610faa565b03610245576000816020015180602001905181019061022f919061126a565b905061023a8161069b565b600192505050610277565b6040517fee2ef09800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b949350505050565b60606102a373ffffffffffffffffffffffffffffffffffffffff881633308761070e565b34156102e2576040517f2543d86e0000000000000000000000000000000000000000000000000000000081523460048201526024015b60405180910390fd5b6000805467ffffffffffffffff1681806102fb836112ed565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550604051602001610341919067ffffffffffffffff91909116815260200190565b60405160208183030381529060405290507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036104f9576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561042d57600080fd5b505af1158015610441573d6000803e3d6000fd5b50506040517f9a2ac6d500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169250639a2ac6d5915087906104be908a90600090879060040161133b565b6000604051808303818588803b1580156104d757600080fd5b505af11580156104eb573d6000803e3d6000fd5b5050505050809150506105ed565b61053a73ffffffffffffffffffffffffffffffffffffffff89167f0000000000000000000000000000000000000000000000000000000000000000876107f0565b6040517f838b252000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063838b2520906105b7908b908b908b908b90600090899060040161137f565b600060405180830381600087803b1580156105d157600080fd5b505af11580156105e5573d6000803e3d6000fd5b509293505050505b9695505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634870496f82600001518360200151846040015185606001516040518563ffffffff1660e01b81526004016106669493929190611435565b600060405180830381600087803b15801561068057600080fd5b505af1158015610694573d6000803e3d6000fd5b5050505050565b80516040517f8c3152e900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691638c3152e99161066691906004016114f1565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526107ea9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152610977565b50505050565b80158061089057506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015284169063dd62ed3e90604401602060405180830381865afa15801561086a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088e9190611504565b155b61091c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084016102d9565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526109729084907f095ea7b30000000000000000000000000000000000000000000000000000000090606401610768565b505050565b60006109d9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16610a839092919063ffffffff16565b80519091501561097257808060200190518101906109f7919061151d565b610972576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016102d9565b60606102778484600085856000808673ffffffffffffffffffffffffffffffffffffffff168587604051610ab7919061153f565b60006040518083038185875af1925050503d8060008114610af4576040519150601f19603f3d011682016040523d82523d6000602084013e610af9565b606091505b5091509150610b0a87838387610b15565b979650505050505050565b60608315610bab578251600003610ba45773ffffffffffffffffffffffffffffffffffffffff85163b610ba4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016102d9565b5081610277565b6102778383815115610bc05781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d99190610dba565b73ffffffffffffffffffffffffffffffffffffffff81168114610c1657600080fd5b50565b60008083601f840112610c2b57600080fd5b50813567ffffffffffffffff811115610c4357600080fd5b602083019150836020828501011115610c5b57600080fd5b9250929050565b60008060008060608587031215610c7857600080fd5b8435610c8381610bf4565b93506020850135610c9381610bf4565b9250604085013567ffffffffffffffff811115610caf57600080fd5b610cbb87828801610c19565b95989497509550505050565b60008060008060008060a08789031215610ce057600080fd5b8635610ceb81610bf4565b95506020870135610cfb81610bf4565b94506040870135610d0b81610bf4565b935060608701359250608087013567ffffffffffffffff811115610d2e57600080fd5b610d3a89828a01610c19565b979a9699509497509295939492505050565b60005b83811015610d67578181015183820152602001610d4f565b50506000910152565b60008151808452610d88816020860160208601610d4c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610dcd6020830184610d70565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610e2657610e26610dd4565b60405290565b6040516080810167ffffffffffffffff81118282101715610e2657610e26610dd4565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610e9657610e96610dd4565b604052919050565b600067ffffffffffffffff821115610eb857610eb8610dd4565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006020808385031215610ef757600080fd5b823567ffffffffffffffff80821115610f0f57600080fd5b9084019060408287031215610f2357600080fd5b610f2b610e03565b823560028110610f3a57600080fd5b81528284013582811115610f4d57600080fd5b80840193505086601f840112610f6257600080fd5b82359150610f77610f7283610e9e565b610e4f565b8281528785848601011115610f8b57600080fd5b8285850186830137600092810185019290925292830152509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600082601f830112610fea57600080fd5b8151610ff8610f7282610e9e565b81815284602083860101111561100d57600080fd5b610277826020830160208701610d4c565b600060c0828403121561103057600080fd5b60405160c0810167ffffffffffffffff828210818311171561105457611054610dd4565b81604052829350845183526020850151915061106f82610bf4565b8160208401526040850151915061108582610bf4565b816040840152606085015160608401526080850151608084015260a08501519150808211156110b357600080fd5b506110c085828601610fd9565b60a0830152505092915050565b600082601f8301126110de57600080fd5b8151602067ffffffffffffffff808311156110fb576110fb610dd4565b8260051b61110a838201610e4f565b938452858101830193838101908886111561112457600080fd5b84880192505b85831015611160578251848111156111425760008081fd5b6111508a87838c0101610fd9565b835250918401919084019061112a565b98975050505050505050565b60006020828403121561117e57600080fd5b815167ffffffffffffffff8082111561119657600080fd5b9083019081850360e08112156111ab57600080fd5b6111b3610e2c565b8351838111156111c257600080fd5b6111ce8882870161101e565b8252506020840151602082015260807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08301121561120b57600080fd5b611213610e2c565b6040858101518252606080870151602084015260808701518284015260a08701519083015282015260c084015191508282111561124f57600080fd5b61125b878386016110cd565b60608201529695505050505050565b60006020828403121561127c57600080fd5b815167ffffffffffffffff8082111561129457600080fd5b90830190602082860312156112a857600080fd5b6040516020810181811083821117156112c3576112c3610dd4565b6040528251828111156112d557600080fd5b6112e18782860161101e565b82525095945050505050565b600067ffffffffffffffff808316818103611331577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6001019392505050565b73ffffffffffffffffffffffffffffffffffffffff8416815263ffffffff831660208201526060604082015260006113766060830184610d70565b95945050505050565b600073ffffffffffffffffffffffffffffffffffffffff8089168352808816602084015280871660408401525084606083015263ffffffff8416608083015260c060a083015261116060c0830184610d70565b805182526000602082015173ffffffffffffffffffffffffffffffffffffffff80821660208601528060408501511660408601525050606082015160608401526080820151608084015260a082015160c060a085015261027760c0850182610d70565b60e08152600061144860e08301876113d2565b602086818501528551604085015280860151606085015260408601516080850152606086015160a085015283820360c08501528185518084528284019150828160051b85010183880160005b838110156114e0577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08784030185526114ce838351610d70565b94860194925090850190600101611494565b50909b9a5050505050505050505050565b602081526000610dcd60208301846113d2565b60006020828403121561151657600080fd5b5051919050565b60006020828403121561152f57600080fd5b81518015158114610dcd57600080fd5b60008251611551818460208701610d4c565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var OptimismL1BridgeAdapterABI = OptimismL1BridgeAdapterMetaData.ABI
+
+var OptimismL1BridgeAdapterBin = OptimismL1BridgeAdapterMetaData.Bin
+
+func DeployOptimismL1BridgeAdapter(auth *bind.TransactOpts, backend bind.ContractBackend, l1Bridge common.Address, wrappedNative common.Address, optimismPortal common.Address) (common.Address, *types.Transaction, *OptimismL1BridgeAdapter, error) {
+ parsed, err := OptimismL1BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(OptimismL1BridgeAdapterBin), backend, l1Bridge, wrappedNative, optimismPortal)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &OptimismL1BridgeAdapter{address: address, abi: *parsed, OptimismL1BridgeAdapterCaller: OptimismL1BridgeAdapterCaller{contract: contract}, OptimismL1BridgeAdapterTransactor: OptimismL1BridgeAdapterTransactor{contract: contract}, OptimismL1BridgeAdapterFilterer: OptimismL1BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+type OptimismL1BridgeAdapter struct {
+ address common.Address
+ abi abi.ABI
+ OptimismL1BridgeAdapterCaller
+ OptimismL1BridgeAdapterTransactor
+ OptimismL1BridgeAdapterFilterer
+}
+
+type OptimismL1BridgeAdapterCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1BridgeAdapterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1BridgeAdapterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1BridgeAdapterSession struct {
+ Contract *OptimismL1BridgeAdapter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL1BridgeAdapterCallerSession struct {
+ Contract *OptimismL1BridgeAdapterCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismL1BridgeAdapterTransactorSession struct {
+ Contract *OptimismL1BridgeAdapterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL1BridgeAdapterRaw struct {
+ Contract *OptimismL1BridgeAdapter
+}
+
+type OptimismL1BridgeAdapterCallerRaw struct {
+ Contract *OptimismL1BridgeAdapterCaller
+}
+
+type OptimismL1BridgeAdapterTransactorRaw struct {
+ Contract *OptimismL1BridgeAdapterTransactor
+}
+
+func NewOptimismL1BridgeAdapter(address common.Address, backend bind.ContractBackend) (*OptimismL1BridgeAdapter, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismL1BridgeAdapterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismL1BridgeAdapter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1BridgeAdapter{address: address, abi: abi, OptimismL1BridgeAdapterCaller: OptimismL1BridgeAdapterCaller{contract: contract}, OptimismL1BridgeAdapterTransactor: OptimismL1BridgeAdapterTransactor{contract: contract}, OptimismL1BridgeAdapterFilterer: OptimismL1BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+func NewOptimismL1BridgeAdapterCaller(address common.Address, caller bind.ContractCaller) (*OptimismL1BridgeAdapterCaller, error) {
+ contract, err := bindOptimismL1BridgeAdapter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1BridgeAdapterCaller{contract: contract}, nil
+}
+
+func NewOptimismL1BridgeAdapterTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismL1BridgeAdapterTransactor, error) {
+ contract, err := bindOptimismL1BridgeAdapter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1BridgeAdapterTransactor{contract: contract}, nil
+}
+
+func NewOptimismL1BridgeAdapterFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismL1BridgeAdapterFilterer, error) {
+ contract, err := bindOptimismL1BridgeAdapter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1BridgeAdapterFilterer{contract: contract}, nil
+}
+
+func bindOptimismL1BridgeAdapter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismL1BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL1BridgeAdapter.Contract.OptimismL1BridgeAdapterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.OptimismL1BridgeAdapterTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.OptimismL1BridgeAdapterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL1BridgeAdapter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCaller) GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _OptimismL1BridgeAdapter.contract.Call(opts, &out, "getBridgeFeeInNative")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _OptimismL1BridgeAdapter.Contract.GetBridgeFeeInNative(&_OptimismL1BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCallerSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _OptimismL1BridgeAdapter.Contract.GetBridgeFeeInNative(&_OptimismL1BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCaller) GetL1Bridge(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _OptimismL1BridgeAdapter.contract.Call(opts, &out, "getL1Bridge")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterSession) GetL1Bridge() (common.Address, error) {
+ return _OptimismL1BridgeAdapter.Contract.GetL1Bridge(&_OptimismL1BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCallerSession) GetL1Bridge() (common.Address, error) {
+ return _OptimismL1BridgeAdapter.Contract.GetL1Bridge(&_OptimismL1BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCaller) GetOptimismPortal(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _OptimismL1BridgeAdapter.contract.Call(opts, &out, "getOptimismPortal")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterSession) GetOptimismPortal() (common.Address, error) {
+ return _OptimismL1BridgeAdapter.Contract.GetOptimismPortal(&_OptimismL1BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCallerSession) GetOptimismPortal() (common.Address, error) {
+ return _OptimismL1BridgeAdapter.Contract.GetOptimismPortal(&_OptimismL1BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCaller) GetWrappedNative(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _OptimismL1BridgeAdapter.contract.Call(opts, &out, "getWrappedNative")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterSession) GetWrappedNative() (common.Address, error) {
+ return _OptimismL1BridgeAdapter.Contract.GetWrappedNative(&_OptimismL1BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterCallerSession) GetWrappedNative() (common.Address, error) {
+ return _OptimismL1BridgeAdapter.Contract.GetWrappedNative(&_OptimismL1BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterTransactor) FinalizeWithdrawERC20(opts *bind.TransactOpts, arg0 common.Address, arg1 common.Address, data []byte) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.contract.Transact(opts, "finalizeWithdrawERC20", arg0, arg1, data)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, data []byte) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.FinalizeWithdrawERC20(&_OptimismL1BridgeAdapter.TransactOpts, arg0, arg1, data)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterTransactorSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, data []byte) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.FinalizeWithdrawERC20(&_OptimismL1BridgeAdapter.TransactOpts, arg0, arg1, data)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterTransactor) SendERC20(opts *bind.TransactOpts, localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.contract.Transact(opts, "sendERC20", localToken, remoteToken, recipient, amount, arg4)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterSession) SendERC20(localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.SendERC20(&_OptimismL1BridgeAdapter.TransactOpts, localToken, remoteToken, recipient, amount, arg4)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterTransactorSession) SendERC20(localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.SendERC20(&_OptimismL1BridgeAdapter.TransactOpts, localToken, remoteToken, recipient, amount, arg4)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.contract.RawTransact(opts, nil)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterSession) Receive() (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.Receive(&_OptimismL1BridgeAdapter.TransactOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapterTransactorSession) Receive() (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapter.Contract.Receive(&_OptimismL1BridgeAdapter.TransactOpts)
+}
+
+func (_OptimismL1BridgeAdapter *OptimismL1BridgeAdapter) Address() common.Address {
+ return _OptimismL1BridgeAdapter.address
+}
+
+type OptimismL1BridgeAdapterInterface interface {
+ GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error)
+
+ GetL1Bridge(opts *bind.CallOpts) (common.Address, error)
+
+ GetOptimismPortal(opts *bind.CallOpts) (common.Address, error)
+
+ GetWrappedNative(opts *bind.CallOpts) (common.Address, error)
+
+ FinalizeWithdrawERC20(opts *bind.TransactOpts, arg0 common.Address, arg1 common.Address, data []byte) (*types.Transaction, error)
+
+ SendERC20(opts *bind.TransactOpts, localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error)
+
+ Receive(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_l1_bridge_adapter_encoder/optimism_l1_bridge_adapter_encoder.go b/core/gethwrappers/liquiditymanager/generated/optimism_l1_bridge_adapter_encoder/optimism_l1_bridge_adapter_encoder.go
new file mode 100644
index 00000000000..14aa651399b
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_l1_bridge_adapter_encoder/optimism_l1_bridge_adapter_encoder.go
@@ -0,0 +1,257 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_l1_bridge_adapter_encoder
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type OptimismL1BridgeAdapterFinalizeWithdrawERC20Payload struct {
+ Action uint8
+ Data []byte
+}
+
+type OptimismL1BridgeAdapterOptimismFinalizationPayload struct {
+ WithdrawalTransaction TypesWithdrawalTransaction
+}
+
+type OptimismL1BridgeAdapterOptimismProveWithdrawalPayload struct {
+ WithdrawalTransaction TypesWithdrawalTransaction
+ L2OutputIndex *big.Int
+ OutputRootProof TypesOutputRootProof
+ WithdrawalProof [][]byte
+}
+
+type TypesOutputRootProof struct {
+ Version [32]byte
+ StateRoot [32]byte
+ MessagePasserStorageRoot [32]byte
+ LatestBlockhash [32]byte
+}
+
+type TypesWithdrawalTransaction struct {
+ Nonce *big.Int
+ Sender common.Address
+ Target common.Address
+ Value *big.Int
+ GasLimit *big.Int
+ Data []byte
+}
+
+var OptimismL1BridgeAdapterEncoderMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"enumOptimismL1BridgeAdapter.FinalizationAction\",\"name\":\"action\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structOptimismL1BridgeAdapter.FinalizeWithdrawERC20Payload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"name\":\"encodeFinalizeWithdrawalERC20Payload\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structTypes.WithdrawalTransaction\",\"name\":\"withdrawalTransaction\",\"type\":\"tuple\"}],\"internalType\":\"structOptimismL1BridgeAdapter.OptimismFinalizationPayload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"name\":\"encodeOptimismFinalizationPayload\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structTypes.WithdrawalTransaction\",\"name\":\"withdrawalTransaction\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"l2OutputIndex\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"version\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"messagePasserStorageRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"latestBlockhash\",\"type\":\"bytes32\"}],\"internalType\":\"structTypes.OutputRootProof\",\"name\":\"outputRootProof\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"withdrawalProof\",\"type\":\"bytes[]\"}],\"internalType\":\"structOptimismL1BridgeAdapter.OptimismProveWithdrawalPayload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"name\":\"encodeOptimismProveWithdrawalPayload\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
+}
+
+var OptimismL1BridgeAdapterEncoderABI = OptimismL1BridgeAdapterEncoderMetaData.ABI
+
+type OptimismL1BridgeAdapterEncoder struct {
+ address common.Address
+ abi abi.ABI
+ OptimismL1BridgeAdapterEncoderCaller
+ OptimismL1BridgeAdapterEncoderTransactor
+ OptimismL1BridgeAdapterEncoderFilterer
+}
+
+type OptimismL1BridgeAdapterEncoderCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1BridgeAdapterEncoderTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1BridgeAdapterEncoderFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1BridgeAdapterEncoderSession struct {
+ Contract *OptimismL1BridgeAdapterEncoder
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL1BridgeAdapterEncoderCallerSession struct {
+ Contract *OptimismL1BridgeAdapterEncoderCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismL1BridgeAdapterEncoderTransactorSession struct {
+ Contract *OptimismL1BridgeAdapterEncoderTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL1BridgeAdapterEncoderRaw struct {
+ Contract *OptimismL1BridgeAdapterEncoder
+}
+
+type OptimismL1BridgeAdapterEncoderCallerRaw struct {
+ Contract *OptimismL1BridgeAdapterEncoderCaller
+}
+
+type OptimismL1BridgeAdapterEncoderTransactorRaw struct {
+ Contract *OptimismL1BridgeAdapterEncoderTransactor
+}
+
+func NewOptimismL1BridgeAdapterEncoder(address common.Address, backend bind.ContractBackend) (*OptimismL1BridgeAdapterEncoder, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismL1BridgeAdapterEncoderABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismL1BridgeAdapterEncoder(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1BridgeAdapterEncoder{address: address, abi: abi, OptimismL1BridgeAdapterEncoderCaller: OptimismL1BridgeAdapterEncoderCaller{contract: contract}, OptimismL1BridgeAdapterEncoderTransactor: OptimismL1BridgeAdapterEncoderTransactor{contract: contract}, OptimismL1BridgeAdapterEncoderFilterer: OptimismL1BridgeAdapterEncoderFilterer{contract: contract}}, nil
+}
+
+func NewOptimismL1BridgeAdapterEncoderCaller(address common.Address, caller bind.ContractCaller) (*OptimismL1BridgeAdapterEncoderCaller, error) {
+ contract, err := bindOptimismL1BridgeAdapterEncoder(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1BridgeAdapterEncoderCaller{contract: contract}, nil
+}
+
+func NewOptimismL1BridgeAdapterEncoderTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismL1BridgeAdapterEncoderTransactor, error) {
+ contract, err := bindOptimismL1BridgeAdapterEncoder(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1BridgeAdapterEncoderTransactor{contract: contract}, nil
+}
+
+func NewOptimismL1BridgeAdapterEncoderFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismL1BridgeAdapterEncoderFilterer, error) {
+ contract, err := bindOptimismL1BridgeAdapterEncoder(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1BridgeAdapterEncoderFilterer{contract: contract}, nil
+}
+
+func bindOptimismL1BridgeAdapterEncoder(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismL1BridgeAdapterEncoderMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL1BridgeAdapterEncoder.Contract.OptimismL1BridgeAdapterEncoderCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapterEncoder.Contract.OptimismL1BridgeAdapterEncoderTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapterEncoder.Contract.OptimismL1BridgeAdapterEncoderTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL1BridgeAdapterEncoder.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapterEncoder.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL1BridgeAdapterEncoder.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderCaller) EncodeFinalizeWithdrawalERC20Payload(opts *bind.CallOpts, payload OptimismL1BridgeAdapterFinalizeWithdrawERC20Payload) error {
+ var out []interface{}
+ err := _OptimismL1BridgeAdapterEncoder.contract.Call(opts, &out, "encodeFinalizeWithdrawalERC20Payload", payload)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderSession) EncodeFinalizeWithdrawalERC20Payload(payload OptimismL1BridgeAdapterFinalizeWithdrawERC20Payload) error {
+ return _OptimismL1BridgeAdapterEncoder.Contract.EncodeFinalizeWithdrawalERC20Payload(&_OptimismL1BridgeAdapterEncoder.CallOpts, payload)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderCallerSession) EncodeFinalizeWithdrawalERC20Payload(payload OptimismL1BridgeAdapterFinalizeWithdrawERC20Payload) error {
+ return _OptimismL1BridgeAdapterEncoder.Contract.EncodeFinalizeWithdrawalERC20Payload(&_OptimismL1BridgeAdapterEncoder.CallOpts, payload)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderCaller) EncodeOptimismFinalizationPayload(opts *bind.CallOpts, payload OptimismL1BridgeAdapterOptimismFinalizationPayload) error {
+ var out []interface{}
+ err := _OptimismL1BridgeAdapterEncoder.contract.Call(opts, &out, "encodeOptimismFinalizationPayload", payload)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderSession) EncodeOptimismFinalizationPayload(payload OptimismL1BridgeAdapterOptimismFinalizationPayload) error {
+ return _OptimismL1BridgeAdapterEncoder.Contract.EncodeOptimismFinalizationPayload(&_OptimismL1BridgeAdapterEncoder.CallOpts, payload)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderCallerSession) EncodeOptimismFinalizationPayload(payload OptimismL1BridgeAdapterOptimismFinalizationPayload) error {
+ return _OptimismL1BridgeAdapterEncoder.Contract.EncodeOptimismFinalizationPayload(&_OptimismL1BridgeAdapterEncoder.CallOpts, payload)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderCaller) EncodeOptimismProveWithdrawalPayload(opts *bind.CallOpts, payload OptimismL1BridgeAdapterOptimismProveWithdrawalPayload) error {
+ var out []interface{}
+ err := _OptimismL1BridgeAdapterEncoder.contract.Call(opts, &out, "encodeOptimismProveWithdrawalPayload", payload)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderSession) EncodeOptimismProveWithdrawalPayload(payload OptimismL1BridgeAdapterOptimismProveWithdrawalPayload) error {
+ return _OptimismL1BridgeAdapterEncoder.Contract.EncodeOptimismProveWithdrawalPayload(&_OptimismL1BridgeAdapterEncoder.CallOpts, payload)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoderCallerSession) EncodeOptimismProveWithdrawalPayload(payload OptimismL1BridgeAdapterOptimismProveWithdrawalPayload) error {
+ return _OptimismL1BridgeAdapterEncoder.Contract.EncodeOptimismProveWithdrawalPayload(&_OptimismL1BridgeAdapterEncoder.CallOpts, payload)
+}
+
+func (_OptimismL1BridgeAdapterEncoder *OptimismL1BridgeAdapterEncoder) Address() common.Address {
+ return _OptimismL1BridgeAdapterEncoder.address
+}
+
+type OptimismL1BridgeAdapterEncoderInterface interface {
+ EncodeFinalizeWithdrawalERC20Payload(opts *bind.CallOpts, payload OptimismL1BridgeAdapterFinalizeWithdrawERC20Payload) error
+
+ EncodeOptimismFinalizationPayload(opts *bind.CallOpts, payload OptimismL1BridgeAdapterOptimismFinalizationPayload) error
+
+ EncodeOptimismProveWithdrawalPayload(opts *bind.CallOpts, payload OptimismL1BridgeAdapterOptimismProveWithdrawalPayload) error
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_l1_standard_bridge/optimism_l1_standard_bridge.go b/core/gethwrappers/liquiditymanager/generated/optimism_l1_standard_bridge/optimism_l1_standard_bridge.go
new file mode 100644
index 00000000000..b376a334355
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_l1_standard_bridge/optimism_l1_standard_bridge.go
@@ -0,0 +1,173 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_l1_standard_bridge
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var OptimismL1StandardBridgeMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"_minGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"depositETHTo\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+}
+
+var OptimismL1StandardBridgeABI = OptimismL1StandardBridgeMetaData.ABI
+
+type OptimismL1StandardBridge struct {
+ address common.Address
+ abi abi.ABI
+ OptimismL1StandardBridgeCaller
+ OptimismL1StandardBridgeTransactor
+ OptimismL1StandardBridgeFilterer
+}
+
+type OptimismL1StandardBridgeCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1StandardBridgeTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1StandardBridgeFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL1StandardBridgeSession struct {
+ Contract *OptimismL1StandardBridge
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL1StandardBridgeCallerSession struct {
+ Contract *OptimismL1StandardBridgeCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismL1StandardBridgeTransactorSession struct {
+ Contract *OptimismL1StandardBridgeTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL1StandardBridgeRaw struct {
+ Contract *OptimismL1StandardBridge
+}
+
+type OptimismL1StandardBridgeCallerRaw struct {
+ Contract *OptimismL1StandardBridgeCaller
+}
+
+type OptimismL1StandardBridgeTransactorRaw struct {
+ Contract *OptimismL1StandardBridgeTransactor
+}
+
+func NewOptimismL1StandardBridge(address common.Address, backend bind.ContractBackend) (*OptimismL1StandardBridge, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismL1StandardBridgeABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismL1StandardBridge(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1StandardBridge{address: address, abi: abi, OptimismL1StandardBridgeCaller: OptimismL1StandardBridgeCaller{contract: contract}, OptimismL1StandardBridgeTransactor: OptimismL1StandardBridgeTransactor{contract: contract}, OptimismL1StandardBridgeFilterer: OptimismL1StandardBridgeFilterer{contract: contract}}, nil
+}
+
+func NewOptimismL1StandardBridgeCaller(address common.Address, caller bind.ContractCaller) (*OptimismL1StandardBridgeCaller, error) {
+ contract, err := bindOptimismL1StandardBridge(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1StandardBridgeCaller{contract: contract}, nil
+}
+
+func NewOptimismL1StandardBridgeTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismL1StandardBridgeTransactor, error) {
+ contract, err := bindOptimismL1StandardBridge(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1StandardBridgeTransactor{contract: contract}, nil
+}
+
+func NewOptimismL1StandardBridgeFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismL1StandardBridgeFilterer, error) {
+ contract, err := bindOptimismL1StandardBridge(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL1StandardBridgeFilterer{contract: contract}, nil
+}
+
+func bindOptimismL1StandardBridge(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismL1StandardBridgeMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL1StandardBridge.Contract.OptimismL1StandardBridgeCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL1StandardBridge.Contract.OptimismL1StandardBridgeTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL1StandardBridge.Contract.OptimismL1StandardBridgeTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL1StandardBridge.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL1StandardBridge.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL1StandardBridge.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeTransactor) DepositETHTo(opts *bind.TransactOpts, _to common.Address, _minGasLimit uint32, _extraData []byte) (*types.Transaction, error) {
+ return _OptimismL1StandardBridge.contract.Transact(opts, "depositETHTo", _to, _minGasLimit, _extraData)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeSession) DepositETHTo(_to common.Address, _minGasLimit uint32, _extraData []byte) (*types.Transaction, error) {
+ return _OptimismL1StandardBridge.Contract.DepositETHTo(&_OptimismL1StandardBridge.TransactOpts, _to, _minGasLimit, _extraData)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridgeTransactorSession) DepositETHTo(_to common.Address, _minGasLimit uint32, _extraData []byte) (*types.Transaction, error) {
+ return _OptimismL1StandardBridge.Contract.DepositETHTo(&_OptimismL1StandardBridge.TransactOpts, _to, _minGasLimit, _extraData)
+}
+
+func (_OptimismL1StandardBridge *OptimismL1StandardBridge) Address() common.Address {
+ return _OptimismL1StandardBridge.address
+}
+
+type OptimismL1StandardBridgeInterface interface {
+ DepositETHTo(opts *bind.TransactOpts, _to common.Address, _minGasLimit uint32, _extraData []byte) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_l2_bridge_adapter/optimism_l2_bridge_adapter.go b/core/gethwrappers/liquiditymanager/generated/optimism_l2_bridge_adapter/optimism_l2_bridge_adapter.go
new file mode 100644
index 00000000000..589db5ceb4b
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_l2_bridge_adapter/optimism_l2_bridge_adapter.go
@@ -0,0 +1,302 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_l2_bridge_adapter
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var OptimismL2BridgeAdapterMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"contractIWrappedNative\",\"name\":\"wrappedNative\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"BridgeAddressCannotBeZero\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"wanted\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"got\",\"type\":\"uint256\"}],\"name\":\"InsufficientEthValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"MsgShouldNotContainValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"msgValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"MsgValueDoesNotMatchAmount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"finalizeWithdrawERC20\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBridgeFeeInNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getL2Bridge\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWrappedNative\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"sendERC20\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]",
+ Bin: "0x60c0604052734200000000000000000000000000000000000010608052600080546001600160401b031916905534801561003857600080fd5b50604051610c2e380380610c2e83398101604081905261005791610068565b6001600160a01b031660a052610098565b60006020828403121561007a57600080fd5b81516001600160a01b038116811461009157600080fd5b9392505050565b60805160a051610b4f6100df6000396000818161013e0152818161024201526102c2015260008181609a0152818161036e0152818161043c01526104f60152610b4f6000f3fe60806040526004361061005e5760003560e01c806338314bb21161004357806338314bb2146100df578063a71d98b71461010f578063e861e9071461012f57600080fd5b80632e4b1fc91461006a5780633429072c1461008b57600080fd5b3661006557005b600080fd5b34801561007657600080fd5b50604051600081526020015b60405180910390f35b34801561009757600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610082565b3480156100eb57600080fd5b506100ff6100fa366004610903565b610162565b6040519015158152602001610082565b61012261011d366004610964565b61016d565b6040516100829190610a51565b34801561013b57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006100ba565b60015b949350505050565b606034156101ae576040517f2543d86e0000000000000000000000000000000000000000000000000000000081523460048201526024015b60405180910390fd5b6101d073ffffffffffffffffffffffffffffffffffffffff8816333087610574565b6000805467ffffffffffffffff1681806101e983610a6b565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405160200161022f919067ffffffffffffffff91909116815260200190565b60405160208183030381529060405290507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16036103ff576040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b15801561031b57600080fd5b505af115801561032f573d6000803e3d6000fd5b50506040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016925063a3a79548915087906103c49073deaddeaddeaddeaddeaddeaddeaddeaddead0000908b9084906000908990600401610ab9565b6000604051808303818588803b1580156103dd57600080fd5b505af11580156103f1573d6000803e3d6000fd5b50505050508091505061056a565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905289169063095ea7b3906044016020604051808303816000875af1158015610494573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b89190610b04565b506040517fa3a7954800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a3a7954890610534908b908a908a906000908890600401610ab9565b600060405180830381600087803b15801561054e57600080fd5b505af1158015610562573d6000803e3d6000fd5b509293505050505b9695505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd0000000000000000000000000000000000000000000000000000000017905261060990859061060f565b50505050565b6000610671826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166107209092919063ffffffff16565b80519091501561071b578080602001905181019061068f9190610b04565b61071b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016101a5565b505050565b60606101658484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516107549190610b26565b60006040518083038185875af1925050503d8060008114610791576040519150601f19603f3d011682016040523d82523d6000602084013e610796565b606091505b50915091506107a7878383876107b2565b979650505050505050565b606083156108485782516000036108415773ffffffffffffffffffffffffffffffffffffffff85163b610841576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101a5565b5081610165565b610165838381511561085d5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101a59190610a51565b803573ffffffffffffffffffffffffffffffffffffffff811681146108b557600080fd5b919050565b60008083601f8401126108cc57600080fd5b50813567ffffffffffffffff8111156108e457600080fd5b6020830191508360208285010111156108fc57600080fd5b9250929050565b6000806000806060858703121561091957600080fd5b61092285610891565b935061093060208601610891565b9250604085013567ffffffffffffffff81111561094c57600080fd5b610958878288016108ba565b95989497509550505050565b60008060008060008060a0878903121561097d57600080fd5b61098687610891565b955061099460208801610891565b94506109a260408801610891565b935060608701359250608087013567ffffffffffffffff8111156109c557600080fd5b6109d189828a016108ba565b979a9699509497509295939492505050565b60005b838110156109fe5781810151838201526020016109e6565b50506000910152565b60008151808452610a1f8160208601602086016109e3565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610a646020830184610a07565b9392505050565b600067ffffffffffffffff808316818103610aaf577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6001019392505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015263ffffffff8416606083015260a060808301526107a760a0830184610a07565b600060208284031215610b1657600080fd5b81518015158114610a6457600080fd5b60008251610b388184602087016109e3565b919091019291505056fea164736f6c6343000818000a",
+}
+
+var OptimismL2BridgeAdapterABI = OptimismL2BridgeAdapterMetaData.ABI
+
+var OptimismL2BridgeAdapterBin = OptimismL2BridgeAdapterMetaData.Bin
+
+func DeployOptimismL2BridgeAdapter(auth *bind.TransactOpts, backend bind.ContractBackend, wrappedNative common.Address) (common.Address, *types.Transaction, *OptimismL2BridgeAdapter, error) {
+ parsed, err := OptimismL2BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(OptimismL2BridgeAdapterBin), backend, wrappedNative)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &OptimismL2BridgeAdapter{address: address, abi: *parsed, OptimismL2BridgeAdapterCaller: OptimismL2BridgeAdapterCaller{contract: contract}, OptimismL2BridgeAdapterTransactor: OptimismL2BridgeAdapterTransactor{contract: contract}, OptimismL2BridgeAdapterFilterer: OptimismL2BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+type OptimismL2BridgeAdapter struct {
+ address common.Address
+ abi abi.ABI
+ OptimismL2BridgeAdapterCaller
+ OptimismL2BridgeAdapterTransactor
+ OptimismL2BridgeAdapterFilterer
+}
+
+type OptimismL2BridgeAdapterCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2BridgeAdapterTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2BridgeAdapterFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2BridgeAdapterSession struct {
+ Contract *OptimismL2BridgeAdapter
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL2BridgeAdapterCallerSession struct {
+ Contract *OptimismL2BridgeAdapterCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismL2BridgeAdapterTransactorSession struct {
+ Contract *OptimismL2BridgeAdapterTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL2BridgeAdapterRaw struct {
+ Contract *OptimismL2BridgeAdapter
+}
+
+type OptimismL2BridgeAdapterCallerRaw struct {
+ Contract *OptimismL2BridgeAdapterCaller
+}
+
+type OptimismL2BridgeAdapterTransactorRaw struct {
+ Contract *OptimismL2BridgeAdapterTransactor
+}
+
+func NewOptimismL2BridgeAdapter(address common.Address, backend bind.ContractBackend) (*OptimismL2BridgeAdapter, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismL2BridgeAdapterABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismL2BridgeAdapter(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2BridgeAdapter{address: address, abi: abi, OptimismL2BridgeAdapterCaller: OptimismL2BridgeAdapterCaller{contract: contract}, OptimismL2BridgeAdapterTransactor: OptimismL2BridgeAdapterTransactor{contract: contract}, OptimismL2BridgeAdapterFilterer: OptimismL2BridgeAdapterFilterer{contract: contract}}, nil
+}
+
+func NewOptimismL2BridgeAdapterCaller(address common.Address, caller bind.ContractCaller) (*OptimismL2BridgeAdapterCaller, error) {
+ contract, err := bindOptimismL2BridgeAdapter(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2BridgeAdapterCaller{contract: contract}, nil
+}
+
+func NewOptimismL2BridgeAdapterTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismL2BridgeAdapterTransactor, error) {
+ contract, err := bindOptimismL2BridgeAdapter(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2BridgeAdapterTransactor{contract: contract}, nil
+}
+
+func NewOptimismL2BridgeAdapterFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismL2BridgeAdapterFilterer, error) {
+ contract, err := bindOptimismL2BridgeAdapter(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2BridgeAdapterFilterer{contract: contract}, nil
+}
+
+func bindOptimismL2BridgeAdapter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismL2BridgeAdapterMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL2BridgeAdapter.Contract.OptimismL2BridgeAdapterCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.Contract.OptimismL2BridgeAdapterTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.Contract.OptimismL2BridgeAdapterTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL2BridgeAdapter.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCaller) FinalizeWithdrawERC20(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ var out []interface{}
+ err := _OptimismL2BridgeAdapter.contract.Call(opts, &out, "finalizeWithdrawERC20", arg0, arg1, arg2)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ return _OptimismL2BridgeAdapter.Contract.FinalizeWithdrawERC20(&_OptimismL2BridgeAdapter.CallOpts, arg0, arg1, arg2)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCallerSession) FinalizeWithdrawERC20(arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ return _OptimismL2BridgeAdapter.Contract.FinalizeWithdrawERC20(&_OptimismL2BridgeAdapter.CallOpts, arg0, arg1, arg2)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCaller) GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _OptimismL2BridgeAdapter.contract.Call(opts, &out, "getBridgeFeeInNative")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _OptimismL2BridgeAdapter.Contract.GetBridgeFeeInNative(&_OptimismL2BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCallerSession) GetBridgeFeeInNative() (*big.Int, error) {
+ return _OptimismL2BridgeAdapter.Contract.GetBridgeFeeInNative(&_OptimismL2BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCaller) GetL2Bridge(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _OptimismL2BridgeAdapter.contract.Call(opts, &out, "getL2Bridge")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterSession) GetL2Bridge() (common.Address, error) {
+ return _OptimismL2BridgeAdapter.Contract.GetL2Bridge(&_OptimismL2BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCallerSession) GetL2Bridge() (common.Address, error) {
+ return _OptimismL2BridgeAdapter.Contract.GetL2Bridge(&_OptimismL2BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCaller) GetWrappedNative(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _OptimismL2BridgeAdapter.contract.Call(opts, &out, "getWrappedNative")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterSession) GetWrappedNative() (common.Address, error) {
+ return _OptimismL2BridgeAdapter.Contract.GetWrappedNative(&_OptimismL2BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterCallerSession) GetWrappedNative() (common.Address, error) {
+ return _OptimismL2BridgeAdapter.Contract.GetWrappedNative(&_OptimismL2BridgeAdapter.CallOpts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterTransactor) SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.contract.Transact(opts, "sendERC20", localToken, arg1, recipient, amount, arg4)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterSession) SendERC20(localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.Contract.SendERC20(&_OptimismL2BridgeAdapter.TransactOpts, localToken, arg1, recipient, amount, arg4)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterTransactorSession) SendERC20(localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.Contract.SendERC20(&_OptimismL2BridgeAdapter.TransactOpts, localToken, arg1, recipient, amount, arg4)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.contract.RawTransact(opts, nil)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterSession) Receive() (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.Contract.Receive(&_OptimismL2BridgeAdapter.TransactOpts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapterTransactorSession) Receive() (*types.Transaction, error) {
+ return _OptimismL2BridgeAdapter.Contract.Receive(&_OptimismL2BridgeAdapter.TransactOpts)
+}
+
+func (_OptimismL2BridgeAdapter *OptimismL2BridgeAdapter) Address() common.Address {
+ return _OptimismL2BridgeAdapter.address
+}
+
+type OptimismL2BridgeAdapterInterface interface {
+ FinalizeWithdrawERC20(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error)
+
+ GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error)
+
+ GetL2Bridge(opts *bind.CallOpts) (common.Address, error)
+
+ GetWrappedNative(opts *bind.CallOpts) (common.Address, error)
+
+ SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error)
+
+ Receive(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_l2_output_oracle/optimism_l2_output_oracle.go b/core/gethwrappers/liquiditymanager/generated/optimism_l2_output_oracle/optimism_l2_output_oracle.go
new file mode 100644
index 00000000000..ddcd6e47ca9
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_l2_output_oracle/optimism_l2_output_oracle.go
@@ -0,0 +1,213 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_l2_output_oracle
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type TypesOutputProposal struct {
+ OutputRoot [32]byte
+ Timestamp *big.Int
+ L2BlockNumber *big.Int
+}
+
+var OptimismL2OutputOracleMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l2OutputIndex\",\"type\":\"uint256\"}],\"name\":\"getL2Output\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"outputRoot\",\"type\":\"bytes32\"},{\"internalType\":\"uint128\",\"name\":\"timestamp\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"l2BlockNumber\",\"type\":\"uint128\"}],\"internalType\":\"structTypes.OutputProposal\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_l2BlockNumber\",\"type\":\"uint256\"}],\"name\":\"getL2OutputIndexAfter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var OptimismL2OutputOracleABI = OptimismL2OutputOracleMetaData.ABI
+
+type OptimismL2OutputOracle struct {
+ address common.Address
+ abi abi.ABI
+ OptimismL2OutputOracleCaller
+ OptimismL2OutputOracleTransactor
+ OptimismL2OutputOracleFilterer
+}
+
+type OptimismL2OutputOracleCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2OutputOracleTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2OutputOracleFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2OutputOracleSession struct {
+ Contract *OptimismL2OutputOracle
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL2OutputOracleCallerSession struct {
+ Contract *OptimismL2OutputOracleCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismL2OutputOracleTransactorSession struct {
+ Contract *OptimismL2OutputOracleTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL2OutputOracleRaw struct {
+ Contract *OptimismL2OutputOracle
+}
+
+type OptimismL2OutputOracleCallerRaw struct {
+ Contract *OptimismL2OutputOracleCaller
+}
+
+type OptimismL2OutputOracleTransactorRaw struct {
+ Contract *OptimismL2OutputOracleTransactor
+}
+
+func NewOptimismL2OutputOracle(address common.Address, backend bind.ContractBackend) (*OptimismL2OutputOracle, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismL2OutputOracleABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismL2OutputOracle(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2OutputOracle{address: address, abi: abi, OptimismL2OutputOracleCaller: OptimismL2OutputOracleCaller{contract: contract}, OptimismL2OutputOracleTransactor: OptimismL2OutputOracleTransactor{contract: contract}, OptimismL2OutputOracleFilterer: OptimismL2OutputOracleFilterer{contract: contract}}, nil
+}
+
+func NewOptimismL2OutputOracleCaller(address common.Address, caller bind.ContractCaller) (*OptimismL2OutputOracleCaller, error) {
+ contract, err := bindOptimismL2OutputOracle(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2OutputOracleCaller{contract: contract}, nil
+}
+
+func NewOptimismL2OutputOracleTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismL2OutputOracleTransactor, error) {
+ contract, err := bindOptimismL2OutputOracle(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2OutputOracleTransactor{contract: contract}, nil
+}
+
+func NewOptimismL2OutputOracleFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismL2OutputOracleFilterer, error) {
+ contract, err := bindOptimismL2OutputOracle(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2OutputOracleFilterer{contract: contract}, nil
+}
+
+func bindOptimismL2OutputOracle(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismL2OutputOracleMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL2OutputOracle.Contract.OptimismL2OutputOracleCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL2OutputOracle.Contract.OptimismL2OutputOracleTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL2OutputOracle.Contract.OptimismL2OutputOracleTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL2OutputOracle.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL2OutputOracle.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL2OutputOracle.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleCaller) GetL2Output(opts *bind.CallOpts, _l2OutputIndex *big.Int) (TypesOutputProposal, error) {
+ var out []interface{}
+ err := _OptimismL2OutputOracle.contract.Call(opts, &out, "getL2Output", _l2OutputIndex)
+
+ if err != nil {
+ return *new(TypesOutputProposal), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(TypesOutputProposal)).(*TypesOutputProposal)
+
+ return out0, err
+
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleSession) GetL2Output(_l2OutputIndex *big.Int) (TypesOutputProposal, error) {
+ return _OptimismL2OutputOracle.Contract.GetL2Output(&_OptimismL2OutputOracle.CallOpts, _l2OutputIndex)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleCallerSession) GetL2Output(_l2OutputIndex *big.Int) (TypesOutputProposal, error) {
+ return _OptimismL2OutputOracle.Contract.GetL2Output(&_OptimismL2OutputOracle.CallOpts, _l2OutputIndex)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleCaller) GetL2OutputIndexAfter(opts *bind.CallOpts, _l2BlockNumber *big.Int) (*big.Int, error) {
+ var out []interface{}
+ err := _OptimismL2OutputOracle.contract.Call(opts, &out, "getL2OutputIndexAfter", _l2BlockNumber)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleSession) GetL2OutputIndexAfter(_l2BlockNumber *big.Int) (*big.Int, error) {
+ return _OptimismL2OutputOracle.Contract.GetL2OutputIndexAfter(&_OptimismL2OutputOracle.CallOpts, _l2BlockNumber)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracleCallerSession) GetL2OutputIndexAfter(_l2BlockNumber *big.Int) (*big.Int, error) {
+ return _OptimismL2OutputOracle.Contract.GetL2OutputIndexAfter(&_OptimismL2OutputOracle.CallOpts, _l2BlockNumber)
+}
+
+func (_OptimismL2OutputOracle *OptimismL2OutputOracle) Address() common.Address {
+ return _OptimismL2OutputOracle.address
+}
+
+type OptimismL2OutputOracleInterface interface {
+ GetL2Output(opts *bind.CallOpts, _l2OutputIndex *big.Int) (TypesOutputProposal, error)
+
+ GetL2OutputIndexAfter(opts *bind.CallOpts, _l2BlockNumber *big.Int) (*big.Int, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_l2_to_l1_message_passer/optimism_l2_to_l1_message_passer.go b/core/gethwrappers/liquiditymanager/generated/optimism_l2_to_l1_message_passer/optimism_l2_to_l1_message_passer.go
new file mode 100644
index 00000000000..69ee5a2ba27
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_l2_to_l1_message_passer/optimism_l2_to_l1_message_passer.go
@@ -0,0 +1,332 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_l2_to_l1_message_passer
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var OptimismL2ToL1MessagePasserMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"withdrawalHash\",\"type\":\"bytes32\"}],\"name\":\"MessagePassed\",\"type\":\"event\"}]",
+}
+
+var OptimismL2ToL1MessagePasserABI = OptimismL2ToL1MessagePasserMetaData.ABI
+
+type OptimismL2ToL1MessagePasser struct {
+ address common.Address
+ abi abi.ABI
+ OptimismL2ToL1MessagePasserCaller
+ OptimismL2ToL1MessagePasserTransactor
+ OptimismL2ToL1MessagePasserFilterer
+}
+
+type OptimismL2ToL1MessagePasserCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2ToL1MessagePasserTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2ToL1MessagePasserFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismL2ToL1MessagePasserSession struct {
+ Contract *OptimismL2ToL1MessagePasser
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL2ToL1MessagePasserCallerSession struct {
+ Contract *OptimismL2ToL1MessagePasserCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismL2ToL1MessagePasserTransactorSession struct {
+ Contract *OptimismL2ToL1MessagePasserTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismL2ToL1MessagePasserRaw struct {
+ Contract *OptimismL2ToL1MessagePasser
+}
+
+type OptimismL2ToL1MessagePasserCallerRaw struct {
+ Contract *OptimismL2ToL1MessagePasserCaller
+}
+
+type OptimismL2ToL1MessagePasserTransactorRaw struct {
+ Contract *OptimismL2ToL1MessagePasserTransactor
+}
+
+func NewOptimismL2ToL1MessagePasser(address common.Address, backend bind.ContractBackend) (*OptimismL2ToL1MessagePasser, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismL2ToL1MessagePasserABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismL2ToL1MessagePasser(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2ToL1MessagePasser{address: address, abi: abi, OptimismL2ToL1MessagePasserCaller: OptimismL2ToL1MessagePasserCaller{contract: contract}, OptimismL2ToL1MessagePasserTransactor: OptimismL2ToL1MessagePasserTransactor{contract: contract}, OptimismL2ToL1MessagePasserFilterer: OptimismL2ToL1MessagePasserFilterer{contract: contract}}, nil
+}
+
+func NewOptimismL2ToL1MessagePasserCaller(address common.Address, caller bind.ContractCaller) (*OptimismL2ToL1MessagePasserCaller, error) {
+ contract, err := bindOptimismL2ToL1MessagePasser(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2ToL1MessagePasserCaller{contract: contract}, nil
+}
+
+func NewOptimismL2ToL1MessagePasserTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismL2ToL1MessagePasserTransactor, error) {
+ contract, err := bindOptimismL2ToL1MessagePasser(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2ToL1MessagePasserTransactor{contract: contract}, nil
+}
+
+func NewOptimismL2ToL1MessagePasserFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismL2ToL1MessagePasserFilterer, error) {
+ contract, err := bindOptimismL2ToL1MessagePasser(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2ToL1MessagePasserFilterer{contract: contract}, nil
+}
+
+func bindOptimismL2ToL1MessagePasser(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismL2ToL1MessagePasserMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL2ToL1MessagePasser.Contract.OptimismL2ToL1MessagePasserCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL2ToL1MessagePasser.Contract.OptimismL2ToL1MessagePasserTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL2ToL1MessagePasser.Contract.OptimismL2ToL1MessagePasserTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismL2ToL1MessagePasser.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismL2ToL1MessagePasser.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismL2ToL1MessagePasser.Contract.contract.Transact(opts, method, params...)
+}
+
+type OptimismL2ToL1MessagePasserMessagePassedIterator struct {
+ Event *OptimismL2ToL1MessagePasserMessagePassed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *OptimismL2ToL1MessagePasserMessagePassedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(OptimismL2ToL1MessagePasserMessagePassed)
+ 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(OptimismL2ToL1MessagePasserMessagePassed)
+ 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 *OptimismL2ToL1MessagePasserMessagePassedIterator) Error() error {
+ return it.fail
+}
+
+func (it *OptimismL2ToL1MessagePasserMessagePassedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type OptimismL2ToL1MessagePasserMessagePassed struct {
+ Nonce *big.Int
+ Sender common.Address
+ Target common.Address
+ Value *big.Int
+ GasLimit *big.Int
+ Data []byte
+ WithdrawalHash [32]byte
+ Raw types.Log
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserFilterer) FilterMessagePassed(opts *bind.FilterOpts, nonce []*big.Int, sender []common.Address, target []common.Address) (*OptimismL2ToL1MessagePasserMessagePassedIterator, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var targetRule []interface{}
+ for _, targetItem := range target {
+ targetRule = append(targetRule, targetItem)
+ }
+
+ logs, sub, err := _OptimismL2ToL1MessagePasser.contract.FilterLogs(opts, "MessagePassed", nonceRule, senderRule, targetRule)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismL2ToL1MessagePasserMessagePassedIterator{contract: _OptimismL2ToL1MessagePasser.contract, event: "MessagePassed", logs: logs, sub: sub}, nil
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserFilterer) WatchMessagePassed(opts *bind.WatchOpts, sink chan<- *OptimismL2ToL1MessagePasserMessagePassed, nonce []*big.Int, sender []common.Address, target []common.Address) (event.Subscription, error) {
+
+ var nonceRule []interface{}
+ for _, nonceItem := range nonce {
+ nonceRule = append(nonceRule, nonceItem)
+ }
+ var senderRule []interface{}
+ for _, senderItem := range sender {
+ senderRule = append(senderRule, senderItem)
+ }
+ var targetRule []interface{}
+ for _, targetItem := range target {
+ targetRule = append(targetRule, targetItem)
+ }
+
+ logs, sub, err := _OptimismL2ToL1MessagePasser.contract.WatchLogs(opts, "MessagePassed", nonceRule, senderRule, targetRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(OptimismL2ToL1MessagePasserMessagePassed)
+ if err := _OptimismL2ToL1MessagePasser.contract.UnpackLog(event, "MessagePassed", 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 (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasserFilterer) ParseMessagePassed(log types.Log) (*OptimismL2ToL1MessagePasserMessagePassed, error) {
+ event := new(OptimismL2ToL1MessagePasserMessagePassed)
+ if err := _OptimismL2ToL1MessagePasser.contract.UnpackLog(event, "MessagePassed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasser) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _OptimismL2ToL1MessagePasser.abi.Events["MessagePassed"].ID:
+ return _OptimismL2ToL1MessagePasser.ParseMessagePassed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (OptimismL2ToL1MessagePasserMessagePassed) Topic() common.Hash {
+ return common.HexToHash("0x02a52367d10742d8032712c1bb8e0144ff1ec5ffda1ed7d70bb05a2744955054")
+}
+
+func (_OptimismL2ToL1MessagePasser *OptimismL2ToL1MessagePasser) Address() common.Address {
+ return _OptimismL2ToL1MessagePasser.address
+}
+
+type OptimismL2ToL1MessagePasserInterface interface {
+ FilterMessagePassed(opts *bind.FilterOpts, nonce []*big.Int, sender []common.Address, target []common.Address) (*OptimismL2ToL1MessagePasserMessagePassedIterator, error)
+
+ WatchMessagePassed(opts *bind.WatchOpts, sink chan<- *OptimismL2ToL1MessagePasserMessagePassed, nonce []*big.Int, sender []common.Address, target []common.Address) (event.Subscription, error)
+
+ ParseMessagePassed(log types.Log) (*OptimismL2ToL1MessagePasserMessagePassed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_portal/optimism_portal.go b/core/gethwrappers/liquiditymanager/generated/optimism_portal/optimism_portal.go
new file mode 100644
index 00000000000..e142d700fc1
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_portal/optimism_portal.go
@@ -0,0 +1,227 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_portal
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type TypesOutputRootProof struct {
+ Version [32]byte
+ StateRoot [32]byte
+ MessagePasserStorageRoot [32]byte
+ LatestBlockhash [32]byte
+}
+
+type TypesWithdrawalTransaction struct {
+ Nonce *big.Int
+ Sender common.Address
+ Target common.Address
+ Value *big.Int
+ GasLimit *big.Int
+ Data []byte
+}
+
+var OptimismPortalMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structTypes.WithdrawalTransaction\",\"name\":\"_tx\",\"type\":\"tuple\"}],\"name\":\"finalizeWithdrawalTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structTypes.WithdrawalTransaction\",\"name\":\"_tx\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"_l2OutputIndex\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"version\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"stateRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"messagePasserStorageRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"latestBlockhash\",\"type\":\"bytes32\"}],\"internalType\":\"structTypes.OutputRootProof\",\"name\":\"_outputRootProof\",\"type\":\"tuple\"},{\"internalType\":\"bytes[]\",\"name\":\"_withdrawalProof\",\"type\":\"bytes[]\"}],\"name\":\"proveWithdrawalTransaction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var OptimismPortalABI = OptimismPortalMetaData.ABI
+
+type OptimismPortal struct {
+ address common.Address
+ abi abi.ABI
+ OptimismPortalCaller
+ OptimismPortalTransactor
+ OptimismPortalFilterer
+}
+
+type OptimismPortalCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismPortalTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismPortalFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismPortalSession struct {
+ Contract *OptimismPortal
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismPortalCallerSession struct {
+ Contract *OptimismPortalCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismPortalTransactorSession struct {
+ Contract *OptimismPortalTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismPortalRaw struct {
+ Contract *OptimismPortal
+}
+
+type OptimismPortalCallerRaw struct {
+ Contract *OptimismPortalCaller
+}
+
+type OptimismPortalTransactorRaw struct {
+ Contract *OptimismPortalTransactor
+}
+
+func NewOptimismPortal(address common.Address, backend bind.ContractBackend) (*OptimismPortal, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismPortalABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismPortal(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismPortal{address: address, abi: abi, OptimismPortalCaller: OptimismPortalCaller{contract: contract}, OptimismPortalTransactor: OptimismPortalTransactor{contract: contract}, OptimismPortalFilterer: OptimismPortalFilterer{contract: contract}}, nil
+}
+
+func NewOptimismPortalCaller(address common.Address, caller bind.ContractCaller) (*OptimismPortalCaller, error) {
+ contract, err := bindOptimismPortal(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismPortalCaller{contract: contract}, nil
+}
+
+func NewOptimismPortalTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismPortalTransactor, error) {
+ contract, err := bindOptimismPortal(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismPortalTransactor{contract: contract}, nil
+}
+
+func NewOptimismPortalFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismPortalFilterer, error) {
+ contract, err := bindOptimismPortal(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismPortalFilterer{contract: contract}, nil
+}
+
+func bindOptimismPortal(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismPortalMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismPortal *OptimismPortalRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismPortal.Contract.OptimismPortalCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismPortal *OptimismPortalRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismPortal.Contract.OptimismPortalTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismPortal *OptimismPortalRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismPortal.Contract.OptimismPortalTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismPortal *OptimismPortalCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismPortal.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismPortal *OptimismPortalTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismPortal.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismPortal *OptimismPortalTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismPortal.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismPortal *OptimismPortalCaller) Version(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _OptimismPortal.contract.Call(opts, &out, "version")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_OptimismPortal *OptimismPortalSession) Version() (string, error) {
+ return _OptimismPortal.Contract.Version(&_OptimismPortal.CallOpts)
+}
+
+func (_OptimismPortal *OptimismPortalCallerSession) Version() (string, error) {
+ return _OptimismPortal.Contract.Version(&_OptimismPortal.CallOpts)
+}
+
+func (_OptimismPortal *OptimismPortalTransactor) FinalizeWithdrawalTransaction(opts *bind.TransactOpts, _tx TypesWithdrawalTransaction) (*types.Transaction, error) {
+ return _OptimismPortal.contract.Transact(opts, "finalizeWithdrawalTransaction", _tx)
+}
+
+func (_OptimismPortal *OptimismPortalSession) FinalizeWithdrawalTransaction(_tx TypesWithdrawalTransaction) (*types.Transaction, error) {
+ return _OptimismPortal.Contract.FinalizeWithdrawalTransaction(&_OptimismPortal.TransactOpts, _tx)
+}
+
+func (_OptimismPortal *OptimismPortalTransactorSession) FinalizeWithdrawalTransaction(_tx TypesWithdrawalTransaction) (*types.Transaction, error) {
+ return _OptimismPortal.Contract.FinalizeWithdrawalTransaction(&_OptimismPortal.TransactOpts, _tx)
+}
+
+func (_OptimismPortal *OptimismPortalTransactor) ProveWithdrawalTransaction(opts *bind.TransactOpts, _tx TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof TypesOutputRootProof, _withdrawalProof [][]byte) (*types.Transaction, error) {
+ return _OptimismPortal.contract.Transact(opts, "proveWithdrawalTransaction", _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof)
+}
+
+func (_OptimismPortal *OptimismPortalSession) ProveWithdrawalTransaction(_tx TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof TypesOutputRootProof, _withdrawalProof [][]byte) (*types.Transaction, error) {
+ return _OptimismPortal.Contract.ProveWithdrawalTransaction(&_OptimismPortal.TransactOpts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof)
+}
+
+func (_OptimismPortal *OptimismPortalTransactorSession) ProveWithdrawalTransaction(_tx TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof TypesOutputRootProof, _withdrawalProof [][]byte) (*types.Transaction, error) {
+ return _OptimismPortal.Contract.ProveWithdrawalTransaction(&_OptimismPortal.TransactOpts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof)
+}
+
+func (_OptimismPortal *OptimismPortal) Address() common.Address {
+ return _OptimismPortal.address
+}
+
+type OptimismPortalInterface interface {
+ Version(opts *bind.CallOpts) (string, error)
+
+ FinalizeWithdrawalTransaction(opts *bind.TransactOpts, _tx TypesWithdrawalTransaction) (*types.Transaction, error)
+
+ ProveWithdrawalTransaction(opts *bind.TransactOpts, _tx TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof TypesOutputRootProof, _withdrawalProof [][]byte) (*types.Transaction, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_portal_2/optimism_portal_2.go b/core/gethwrappers/liquiditymanager/generated/optimism_portal_2/optimism_portal_2.go
new file mode 100644
index 00000000000..1759ca12514
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_portal_2/optimism_portal_2.go
@@ -0,0 +1,207 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_portal_2
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var OptimismPortal2MetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[],\"name\":\"disputeGameFactory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"respectedGameType\",\"outputs\":[{\"internalType\":\"GameType\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var OptimismPortal2ABI = OptimismPortal2MetaData.ABI
+
+type OptimismPortal2 struct {
+ address common.Address
+ abi abi.ABI
+ OptimismPortal2Caller
+ OptimismPortal2Transactor
+ OptimismPortal2Filterer
+}
+
+type OptimismPortal2Caller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismPortal2Transactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismPortal2Filterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismPortal2Session struct {
+ Contract *OptimismPortal2
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismPortal2CallerSession struct {
+ Contract *OptimismPortal2Caller
+ CallOpts bind.CallOpts
+}
+
+type OptimismPortal2TransactorSession struct {
+ Contract *OptimismPortal2Transactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismPortal2Raw struct {
+ Contract *OptimismPortal2
+}
+
+type OptimismPortal2CallerRaw struct {
+ Contract *OptimismPortal2Caller
+}
+
+type OptimismPortal2TransactorRaw struct {
+ Contract *OptimismPortal2Transactor
+}
+
+func NewOptimismPortal2(address common.Address, backend bind.ContractBackend) (*OptimismPortal2, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismPortal2ABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismPortal2(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismPortal2{address: address, abi: abi, OptimismPortal2Caller: OptimismPortal2Caller{contract: contract}, OptimismPortal2Transactor: OptimismPortal2Transactor{contract: contract}, OptimismPortal2Filterer: OptimismPortal2Filterer{contract: contract}}, nil
+}
+
+func NewOptimismPortal2Caller(address common.Address, caller bind.ContractCaller) (*OptimismPortal2Caller, error) {
+ contract, err := bindOptimismPortal2(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismPortal2Caller{contract: contract}, nil
+}
+
+func NewOptimismPortal2Transactor(address common.Address, transactor bind.ContractTransactor) (*OptimismPortal2Transactor, error) {
+ contract, err := bindOptimismPortal2(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismPortal2Transactor{contract: contract}, nil
+}
+
+func NewOptimismPortal2Filterer(address common.Address, filterer bind.ContractFilterer) (*OptimismPortal2Filterer, error) {
+ contract, err := bindOptimismPortal2(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismPortal2Filterer{contract: contract}, nil
+}
+
+func bindOptimismPortal2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismPortal2MetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismPortal2 *OptimismPortal2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismPortal2.Contract.OptimismPortal2Caller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismPortal2 *OptimismPortal2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismPortal2.Contract.OptimismPortal2Transactor.contract.Transfer(opts)
+}
+
+func (_OptimismPortal2 *OptimismPortal2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismPortal2.Contract.OptimismPortal2Transactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismPortal2 *OptimismPortal2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismPortal2.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismPortal2 *OptimismPortal2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismPortal2.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismPortal2 *OptimismPortal2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismPortal2.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismPortal2 *OptimismPortal2Caller) DisputeGameFactory(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _OptimismPortal2.contract.Call(opts, &out, "disputeGameFactory")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_OptimismPortal2 *OptimismPortal2Session) DisputeGameFactory() (common.Address, error) {
+ return _OptimismPortal2.Contract.DisputeGameFactory(&_OptimismPortal2.CallOpts)
+}
+
+func (_OptimismPortal2 *OptimismPortal2CallerSession) DisputeGameFactory() (common.Address, error) {
+ return _OptimismPortal2.Contract.DisputeGameFactory(&_OptimismPortal2.CallOpts)
+}
+
+func (_OptimismPortal2 *OptimismPortal2Caller) RespectedGameType(opts *bind.CallOpts) (uint32, error) {
+ var out []interface{}
+ err := _OptimismPortal2.contract.Call(opts, &out, "respectedGameType")
+
+ if err != nil {
+ return *new(uint32), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32)
+
+ return out0, err
+
+}
+
+func (_OptimismPortal2 *OptimismPortal2Session) RespectedGameType() (uint32, error) {
+ return _OptimismPortal2.Contract.RespectedGameType(&_OptimismPortal2.CallOpts)
+}
+
+func (_OptimismPortal2 *OptimismPortal2CallerSession) RespectedGameType() (uint32, error) {
+ return _OptimismPortal2.Contract.RespectedGameType(&_OptimismPortal2.CallOpts)
+}
+
+func (_OptimismPortal2 *OptimismPortal2) Address() common.Address {
+ return _OptimismPortal2.address
+}
+
+type OptimismPortal2Interface interface {
+ DisputeGameFactory(opts *bind.CallOpts) (common.Address, error)
+
+ RespectedGameType(opts *bind.CallOpts) (uint32, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/optimism_standard_bridge/optimism_standard_bridge.go b/core/gethwrappers/liquiditymanager/generated/optimism_standard_bridge/optimism_standard_bridge.go
new file mode 100644
index 00000000000..b6a7d451439
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/optimism_standard_bridge/optimism_standard_bridge.go
@@ -0,0 +1,345 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package optimism_standard_bridge
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var OptimismStandardBridgeMetaData = &bind.MetaData{
+ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"localToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"}],\"name\":\"ERC20BridgeFinalized\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_localToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_remoteToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_extraData\",\"type\":\"bytes\"}],\"name\":\"finalizeBridgeERC20\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+}
+
+var OptimismStandardBridgeABI = OptimismStandardBridgeMetaData.ABI
+
+type OptimismStandardBridge struct {
+ address common.Address
+ abi abi.ABI
+ OptimismStandardBridgeCaller
+ OptimismStandardBridgeTransactor
+ OptimismStandardBridgeFilterer
+}
+
+type OptimismStandardBridgeCaller struct {
+ contract *bind.BoundContract
+}
+
+type OptimismStandardBridgeTransactor struct {
+ contract *bind.BoundContract
+}
+
+type OptimismStandardBridgeFilterer struct {
+ contract *bind.BoundContract
+}
+
+type OptimismStandardBridgeSession struct {
+ Contract *OptimismStandardBridge
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismStandardBridgeCallerSession struct {
+ Contract *OptimismStandardBridgeCaller
+ CallOpts bind.CallOpts
+}
+
+type OptimismStandardBridgeTransactorSession struct {
+ Contract *OptimismStandardBridgeTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type OptimismStandardBridgeRaw struct {
+ Contract *OptimismStandardBridge
+}
+
+type OptimismStandardBridgeCallerRaw struct {
+ Contract *OptimismStandardBridgeCaller
+}
+
+type OptimismStandardBridgeTransactorRaw struct {
+ Contract *OptimismStandardBridgeTransactor
+}
+
+func NewOptimismStandardBridge(address common.Address, backend bind.ContractBackend) (*OptimismStandardBridge, error) {
+ abi, err := abi.JSON(strings.NewReader(OptimismStandardBridgeABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindOptimismStandardBridge(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismStandardBridge{address: address, abi: abi, OptimismStandardBridgeCaller: OptimismStandardBridgeCaller{contract: contract}, OptimismStandardBridgeTransactor: OptimismStandardBridgeTransactor{contract: contract}, OptimismStandardBridgeFilterer: OptimismStandardBridgeFilterer{contract: contract}}, nil
+}
+
+func NewOptimismStandardBridgeCaller(address common.Address, caller bind.ContractCaller) (*OptimismStandardBridgeCaller, error) {
+ contract, err := bindOptimismStandardBridge(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismStandardBridgeCaller{contract: contract}, nil
+}
+
+func NewOptimismStandardBridgeTransactor(address common.Address, transactor bind.ContractTransactor) (*OptimismStandardBridgeTransactor, error) {
+ contract, err := bindOptimismStandardBridge(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismStandardBridgeTransactor{contract: contract}, nil
+}
+
+func NewOptimismStandardBridgeFilterer(address common.Address, filterer bind.ContractFilterer) (*OptimismStandardBridgeFilterer, error) {
+ contract, err := bindOptimismStandardBridge(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismStandardBridgeFilterer{contract: contract}, nil
+}
+
+func bindOptimismStandardBridge(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := OptimismStandardBridgeMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismStandardBridge.Contract.OptimismStandardBridgeCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismStandardBridge.Contract.OptimismStandardBridgeTransactor.contract.Transfer(opts)
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismStandardBridge.Contract.OptimismStandardBridgeTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _OptimismStandardBridge.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _OptimismStandardBridge.Contract.contract.Transfer(opts)
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _OptimismStandardBridge.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeTransactor) FinalizeBridgeERC20(opts *bind.TransactOpts, _localToken common.Address, _remoteToken common.Address, _from common.Address, _to common.Address, _amount *big.Int, _extraData []byte) (*types.Transaction, error) {
+ return _OptimismStandardBridge.contract.Transact(opts, "finalizeBridgeERC20", _localToken, _remoteToken, _from, _to, _amount, _extraData)
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeSession) FinalizeBridgeERC20(_localToken common.Address, _remoteToken common.Address, _from common.Address, _to common.Address, _amount *big.Int, _extraData []byte) (*types.Transaction, error) {
+ return _OptimismStandardBridge.Contract.FinalizeBridgeERC20(&_OptimismStandardBridge.TransactOpts, _localToken, _remoteToken, _from, _to, _amount, _extraData)
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeTransactorSession) FinalizeBridgeERC20(_localToken common.Address, _remoteToken common.Address, _from common.Address, _to common.Address, _amount *big.Int, _extraData []byte) (*types.Transaction, error) {
+ return _OptimismStandardBridge.Contract.FinalizeBridgeERC20(&_OptimismStandardBridge.TransactOpts, _localToken, _remoteToken, _from, _to, _amount, _extraData)
+}
+
+type OptimismStandardBridgeERC20BridgeFinalizedIterator struct {
+ Event *OptimismStandardBridgeERC20BridgeFinalized
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *OptimismStandardBridgeERC20BridgeFinalizedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(OptimismStandardBridgeERC20BridgeFinalized)
+ 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(OptimismStandardBridgeERC20BridgeFinalized)
+ 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 *OptimismStandardBridgeERC20BridgeFinalizedIterator) Error() error {
+ return it.fail
+}
+
+func (it *OptimismStandardBridgeERC20BridgeFinalizedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type OptimismStandardBridgeERC20BridgeFinalized struct {
+ LocalToken common.Address
+ RemoteToken common.Address
+ From common.Address
+ To common.Address
+ Amount *big.Int
+ ExtraData []byte
+ Raw types.Log
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeFilterer) FilterERC20BridgeFinalized(opts *bind.FilterOpts, localToken []common.Address, remoteToken []common.Address, from []common.Address) (*OptimismStandardBridgeERC20BridgeFinalizedIterator, error) {
+
+ var localTokenRule []interface{}
+ for _, localTokenItem := range localToken {
+ localTokenRule = append(localTokenRule, localTokenItem)
+ }
+ var remoteTokenRule []interface{}
+ for _, remoteTokenItem := range remoteToken {
+ remoteTokenRule = append(remoteTokenRule, remoteTokenItem)
+ }
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+
+ logs, sub, err := _OptimismStandardBridge.contract.FilterLogs(opts, "ERC20BridgeFinalized", localTokenRule, remoteTokenRule, fromRule)
+ if err != nil {
+ return nil, err
+ }
+ return &OptimismStandardBridgeERC20BridgeFinalizedIterator{contract: _OptimismStandardBridge.contract, event: "ERC20BridgeFinalized", logs: logs, sub: sub}, nil
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridgeFilterer) WatchERC20BridgeFinalized(opts *bind.WatchOpts, sink chan<- *OptimismStandardBridgeERC20BridgeFinalized, localToken []common.Address, remoteToken []common.Address, from []common.Address) (event.Subscription, error) {
+
+ var localTokenRule []interface{}
+ for _, localTokenItem := range localToken {
+ localTokenRule = append(localTokenRule, localTokenItem)
+ }
+ var remoteTokenRule []interface{}
+ for _, remoteTokenItem := range remoteToken {
+ remoteTokenRule = append(remoteTokenRule, remoteTokenItem)
+ }
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+
+ logs, sub, err := _OptimismStandardBridge.contract.WatchLogs(opts, "ERC20BridgeFinalized", localTokenRule, remoteTokenRule, fromRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(OptimismStandardBridgeERC20BridgeFinalized)
+ if err := _OptimismStandardBridge.contract.UnpackLog(event, "ERC20BridgeFinalized", 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 (_OptimismStandardBridge *OptimismStandardBridgeFilterer) ParseERC20BridgeFinalized(log types.Log) (*OptimismStandardBridgeERC20BridgeFinalized, error) {
+ event := new(OptimismStandardBridgeERC20BridgeFinalized)
+ if err := _OptimismStandardBridge.contract.UnpackLog(event, "ERC20BridgeFinalized", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridge) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _OptimismStandardBridge.abi.Events["ERC20BridgeFinalized"].ID:
+ return _OptimismStandardBridge.ParseERC20BridgeFinalized(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (OptimismStandardBridgeERC20BridgeFinalized) Topic() common.Hash {
+ return common.HexToHash("0xd59c65b35445225835c83f50b6ede06a7be047d22e357073e250d9af537518cd")
+}
+
+func (_OptimismStandardBridge *OptimismStandardBridge) Address() common.Address {
+ return _OptimismStandardBridge.address
+}
+
+type OptimismStandardBridgeInterface interface {
+ FinalizeBridgeERC20(opts *bind.TransactOpts, _localToken common.Address, _remoteToken common.Address, _from common.Address, _to common.Address, _amount *big.Int, _extraData []byte) (*types.Transaction, error)
+
+ FilterERC20BridgeFinalized(opts *bind.FilterOpts, localToken []common.Address, remoteToken []common.Address, from []common.Address) (*OptimismStandardBridgeERC20BridgeFinalizedIterator, error)
+
+ WatchERC20BridgeFinalized(opts *bind.WatchOpts, sink chan<- *OptimismStandardBridgeERC20BridgeFinalized, localToken []common.Address, remoteToken []common.Address, from []common.Address) (event.Subscription, error)
+
+ ParseERC20BridgeFinalized(log types.Log) (*OptimismStandardBridgeERC20BridgeFinalized, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generated/report_encoder/report_encoder.go b/core/gethwrappers/liquiditymanager/generated/report_encoder/report_encoder.go
new file mode 100644
index 00000000000..1e14ea185e3
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generated/report_encoder/report_encoder.go
@@ -0,0 +1,256 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package report_encoder
+
+import (
+ "errors"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type ILiquidityManagerCrossChainRebalancerArgs struct {
+ RemoteRebalancer common.Address
+ LocalBridge common.Address
+ RemoteToken common.Address
+ RemoteChainSelector uint64
+ Enabled bool
+}
+
+type ILiquidityManagerLiquidityInstructions struct {
+ SendLiquidityParams []ILiquidityManagerSendLiquidityParams
+ ReceiveLiquidityParams []ILiquidityManagerReceiveLiquidityParams
+}
+
+type ILiquidityManagerReceiveLiquidityParams struct {
+ Amount *big.Int
+ RemoteChainSelector uint64
+ ShouldWrapNative bool
+ BridgeData []byte
+}
+
+type ILiquidityManagerSendLiquidityParams struct {
+ Amount *big.Int
+ NativeBridgeFee *big.Int
+ RemoteChainSelector uint64
+ BridgeData []byte
+}
+
+var ReportEncoderMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nativeBridgeFee\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"bridgeData\",\"type\":\"bytes\"}],\"internalType\":\"structILiquidityManager.SendLiquidityParams[]\",\"name\":\"sendLiquidityParams\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"shouldWrapNative\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"bridgeData\",\"type\":\"bytes\"}],\"internalType\":\"structILiquidityManager.ReceiveLiquidityParams[]\",\"name\":\"receiveLiquidityParams\",\"type\":\"tuple[]\"}],\"internalType\":\"structILiquidityManager.LiquidityInstructions\",\"name\":\"instructions\",\"type\":\"tuple\"}],\"name\":\"exposeForEncoding\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllCrossChainRebalancers\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"remoteRebalancer\",\"type\":\"address\"},{\"internalType\":\"contractIBridgeAdapter\",\"name\":\"localBridge\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"remoteToken\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"remoteChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"}],\"internalType\":\"structILiquidityManager.CrossChainRebalancerArgs[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLiquidity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"currentLiquidity\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
+}
+
+var ReportEncoderABI = ReportEncoderMetaData.ABI
+
+type ReportEncoder struct {
+ address common.Address
+ abi abi.ABI
+ ReportEncoderCaller
+ ReportEncoderTransactor
+ ReportEncoderFilterer
+}
+
+type ReportEncoderCaller struct {
+ contract *bind.BoundContract
+}
+
+type ReportEncoderTransactor struct {
+ contract *bind.BoundContract
+}
+
+type ReportEncoderFilterer struct {
+ contract *bind.BoundContract
+}
+
+type ReportEncoderSession struct {
+ Contract *ReportEncoder
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type ReportEncoderCallerSession struct {
+ Contract *ReportEncoderCaller
+ CallOpts bind.CallOpts
+}
+
+type ReportEncoderTransactorSession struct {
+ Contract *ReportEncoderTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type ReportEncoderRaw struct {
+ Contract *ReportEncoder
+}
+
+type ReportEncoderCallerRaw struct {
+ Contract *ReportEncoderCaller
+}
+
+type ReportEncoderTransactorRaw struct {
+ Contract *ReportEncoderTransactor
+}
+
+func NewReportEncoder(address common.Address, backend bind.ContractBackend) (*ReportEncoder, error) {
+ abi, err := abi.JSON(strings.NewReader(ReportEncoderABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindReportEncoder(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &ReportEncoder{address: address, abi: abi, ReportEncoderCaller: ReportEncoderCaller{contract: contract}, ReportEncoderTransactor: ReportEncoderTransactor{contract: contract}, ReportEncoderFilterer: ReportEncoderFilterer{contract: contract}}, nil
+}
+
+func NewReportEncoderCaller(address common.Address, caller bind.ContractCaller) (*ReportEncoderCaller, error) {
+ contract, err := bindReportEncoder(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ReportEncoderCaller{contract: contract}, nil
+}
+
+func NewReportEncoderTransactor(address common.Address, transactor bind.ContractTransactor) (*ReportEncoderTransactor, error) {
+ contract, err := bindReportEncoder(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &ReportEncoderTransactor{contract: contract}, nil
+}
+
+func NewReportEncoderFilterer(address common.Address, filterer bind.ContractFilterer) (*ReportEncoderFilterer, error) {
+ contract, err := bindReportEncoder(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &ReportEncoderFilterer{contract: contract}, nil
+}
+
+func bindReportEncoder(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := ReportEncoderMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_ReportEncoder *ReportEncoderRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ReportEncoder.Contract.ReportEncoderCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_ReportEncoder *ReportEncoderRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ReportEncoder.Contract.ReportEncoderTransactor.contract.Transfer(opts)
+}
+
+func (_ReportEncoder *ReportEncoderRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ReportEncoder.Contract.ReportEncoderTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_ReportEncoder *ReportEncoderCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _ReportEncoder.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_ReportEncoder *ReportEncoderTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _ReportEncoder.Contract.contract.Transfer(opts)
+}
+
+func (_ReportEncoder *ReportEncoderTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _ReportEncoder.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_ReportEncoder *ReportEncoderCaller) ExposeForEncoding(opts *bind.CallOpts, instructions ILiquidityManagerLiquidityInstructions) error {
+ var out []interface{}
+ err := _ReportEncoder.contract.Call(opts, &out, "exposeForEncoding", instructions)
+
+ if err != nil {
+ return err
+ }
+
+ return err
+
+}
+
+func (_ReportEncoder *ReportEncoderSession) ExposeForEncoding(instructions ILiquidityManagerLiquidityInstructions) error {
+ return _ReportEncoder.Contract.ExposeForEncoding(&_ReportEncoder.CallOpts, instructions)
+}
+
+func (_ReportEncoder *ReportEncoderCallerSession) ExposeForEncoding(instructions ILiquidityManagerLiquidityInstructions) error {
+ return _ReportEncoder.Contract.ExposeForEncoding(&_ReportEncoder.CallOpts, instructions)
+}
+
+func (_ReportEncoder *ReportEncoderCaller) GetAllCrossChainRebalancers(opts *bind.CallOpts) ([]ILiquidityManagerCrossChainRebalancerArgs, error) {
+ var out []interface{}
+ err := _ReportEncoder.contract.Call(opts, &out, "getAllCrossChainRebalancers")
+
+ if err != nil {
+ return *new([]ILiquidityManagerCrossChainRebalancerArgs), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([]ILiquidityManagerCrossChainRebalancerArgs)).(*[]ILiquidityManagerCrossChainRebalancerArgs)
+
+ return out0, err
+
+}
+
+func (_ReportEncoder *ReportEncoderSession) GetAllCrossChainRebalancers() ([]ILiquidityManagerCrossChainRebalancerArgs, error) {
+ return _ReportEncoder.Contract.GetAllCrossChainRebalancers(&_ReportEncoder.CallOpts)
+}
+
+func (_ReportEncoder *ReportEncoderCallerSession) GetAllCrossChainRebalancers() ([]ILiquidityManagerCrossChainRebalancerArgs, error) {
+ return _ReportEncoder.Contract.GetAllCrossChainRebalancers(&_ReportEncoder.CallOpts)
+}
+
+func (_ReportEncoder *ReportEncoderCaller) GetLiquidity(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _ReportEncoder.contract.Call(opts, &out, "getLiquidity")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_ReportEncoder *ReportEncoderSession) GetLiquidity() (*big.Int, error) {
+ return _ReportEncoder.Contract.GetLiquidity(&_ReportEncoder.CallOpts)
+}
+
+func (_ReportEncoder *ReportEncoderCallerSession) GetLiquidity() (*big.Int, error) {
+ return _ReportEncoder.Contract.GetLiquidity(&_ReportEncoder.CallOpts)
+}
+
+func (_ReportEncoder *ReportEncoder) Address() common.Address {
+ return _ReportEncoder.address
+}
+
+type ReportEncoderInterface interface {
+ ExposeForEncoding(opts *bind.CallOpts, instructions ILiquidityManagerLiquidityInstructions) error
+
+ GetAllCrossChainRebalancers(opts *bind.CallOpts) ([]ILiquidityManagerCrossChainRebalancerArgs, error)
+
+ GetLiquidity(opts *bind.CallOpts) (*big.Int, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/liquiditymanager/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/liquiditymanager/generation/generated-wrapper-dependency-versions-do-not-edit.txt
new file mode 100644
index 00000000000..a4fe8720abf
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/generation/generated-wrapper-dependency-versions-do-not-edit.txt
@@ -0,0 +1,29 @@
+GETH_VERSION: 1.13.8
+abstract_arbitrum_token_gateway: ../../../contracts/solc/v0.8.24/IAbstractArbitrumTokenGateway/IAbstractArbitrumTokenGateway.abi ../../../contracts/solc/v0.8.24/IAbstractArbitrumTokenGateway/IAbstractArbitrumTokenGateway.bin 779e05d8fb797d4fcfa565174c071ad9f0161d103d6a322f6d0e1e42be568fa0
+arb_node_interface: ../../../contracts/solc/v0.8.24/INodeInterface/INodeInterface.abi ../../../contracts/solc/v0.8.24/INodeInterface/INodeInterface.bin c72f9e9d1e9b9c371c42817590a490a327e743775f423d9417982914d6136ff7
+arbitrum_gateway_router: ../../../contracts/solc/v0.8.24/IArbitrumGatewayRouter/IArbitrumGatewayRouter.abi ../../../contracts/solc/v0.8.24/IArbitrumGatewayRouter/IArbitrumGatewayRouter.bin d02c8ed0b4bfe50630e0fce452f9aef23d394bd28110314356954185a6544cb8
+arbitrum_inbox: ../../../contracts/solc/v0.8.24/IArbitrumInbox/IArbitrumInbox.abi ../../../contracts/solc/v0.8.24/IArbitrumInbox/IArbitrumInbox.bin 815c2ba12fadd3a6961330d746645dd1920a06253ce9555b46b4c8526065dbaf
+arbitrum_l1_bridge_adapter: ../../../contracts/solc/v0.8.24/ArbitrumL1BridgeAdapter/ArbitrumL1BridgeAdapter.abi ../../../contracts/solc/v0.8.24/ArbitrumL1BridgeAdapter/ArbitrumL1BridgeAdapter.bin 1a3719911f8af8652fbf7653ca514a21e7e1acbac4c8bed56f353b8ce69c98d6
+arbitrum_l1_gateway_router: ../../../contracts/solc/v0.8.24/IArbitrumL1GatewayRouter/IArbitrumL1GatewayRouter.abi ../../../contracts/solc/v0.8.24/IArbitrumL1GatewayRouter/IArbitrumL1GatewayRouter.bin 48b098f0667521be7c4a31f2c361a2898536c5ab5406c18c2cedf8c8238909ad
+arbitrum_l2_bridge_adapter: ../../../contracts/solc/v0.8.24/ArbitrumL2BridgeAdapter/ArbitrumL2BridgeAdapter.abi ../../../contracts/solc/v0.8.24/ArbitrumL2BridgeAdapter/ArbitrumL2BridgeAdapter.bin c22f2cf6a940dbedf96329a2041d8e396094c172665ace33727bcc0b4aaf9535
+arbitrum_rollup_core: ../../../contracts/solc/v0.8.24/IArbRollupCore/IArbRollupCore.abi ../../../contracts/solc/v0.8.24/IArbRollupCore/IArbRollupCore.bin 18ebdef208265cde0cde8671214840afdffaf57b5d82627d18604727b6210fa6
+arbitrum_token_gateway: ../../../contracts/solc/v0.8.24/IArbitrumTokenGateway/IArbitrumTokenGateway.abi ../../../contracts/solc/v0.8.24/IArbitrumTokenGateway/IArbitrumTokenGateway.bin c3d42c4f174317fe06f96435952ebe7ca8b042c787a61bf3f69060c00c396eae
+arbsys: ../../../contracts/solc/v0.8.24/IArbSys/IArbSys.abi ../../../contracts/solc/v0.8.24/IArbSys/IArbSys.bin 70adb49f157d8e077485d1a5c87ddf64b214822aef736bb68e122a77bab78a16
+l2_arbitrum_gateway: ../../../contracts/solc/v0.8.24/IL2ArbitrumGateway/IL2ArbitrumGateway.abi ../../../contracts/solc/v0.8.24/IL2ArbitrumGateway/IL2ArbitrumGateway.bin 4d1af2bdb0aeb0b15e3cbc4ed2158f9bcba4925f68ed3669e0ecfde14115c893
+l2_arbitrum_messenger: ../../../contracts/solc/v0.8.24/IL2ArbitrumMessenger/IL2ArbitrumMessenger.abi ../../../contracts/solc/v0.8.24/IL2ArbitrumMessenger/IL2ArbitrumMessenger.bin 84d4bfedf16e92e3fb15880832fa54a3a21808dffea8a7c0946cde3b5e17a0c3
+liquiditymanager: ../../../contracts/solc/v0.8.24/LiquidityManager/LiquidityManager.abi ../../../contracts/solc/v0.8.24/LiquidityManager/LiquidityManager.bin 6e9aecb13ccf2e92e799e4a2a75c98d58949e34a04e30878f29765f3653993e4
+mock_l1_bridge_adapter: ../../../contracts/solc/v0.8.24/MockBridgeAdapter/MockL1BridgeAdapter.abi ../../../contracts/solc/v0.8.24/MockBridgeAdapter/MockL1BridgeAdapter.bin 538d2e3855031bcb4ef28ab8f0c54c8249e90936a588cde81b965d1dd2d08ad4
+mock_l2_bridge_adapter: ../../../contracts/solc/v0.8.24/MockBridgeAdapter/MockL2BridgeAdapter.abi ../../../contracts/solc/v0.8.24/MockBridgeAdapter/MockL2BridgeAdapter.bin 8ff182e2ac6aac98e1fe85c37d6d92a0b0570de695ed1292127ae25babe96bda
+no_op_ocr3: ../../../contracts/solc/v0.8.24/NoOpOCR3/NoOpOCR3.abi ../../../contracts/solc/v0.8.24/NoOpOCR3/NoOpOCR3.bin 8797017885f77efaa7784d3adab29924c95231562baac947949269592c88a441
+optimism_cross_domain_messenger: ../../../contracts/solc/v0.8.24/IOptimismCrossDomainMessenger/IOptimismCrossDomainMessenger.abi ../../../contracts/solc/v0.8.24/IOptimismCrossDomainMessenger/IOptimismCrossDomainMessenger.bin e6d54a344ca1cf29e3b2d320bad4ab4b5aa6c197705d7a65586d4d215d751fca
+optimism_dispute_game_factory: ../../../contracts/solc/v0.8.24/IOptimismDisputeGameFactory/IOptimismDisputeGameFactory.abi ../../../contracts/solc/v0.8.24/IOptimismDisputeGameFactory/IOptimismDisputeGameFactory.bin d4bcd96a87fdc6316b3788bd33eb8d96140002f7716b123a03ba4196a5aeeb72
+optimism_l1_bridge_adapter: ../../../contracts/solc/v0.8.24/OptimismL1BridgeAdapter/OptimismL1BridgeAdapter.abi ../../../contracts/solc/v0.8.24/OptimismL1BridgeAdapter/OptimismL1BridgeAdapter.bin f05678747b99fa7bc4255e7c11a44e5e49f51f749a97f5b41ac9badae0592ac1
+optimism_l1_bridge_adapter_encoder: ../../../contracts/solc/v0.8.24/OptimismL1BridgeAdapterEncoder/OptimismL1BridgeAdapterEncoder.abi ../../../contracts/solc/v0.8.24/OptimismL1BridgeAdapterEncoder/OptimismL1BridgeAdapterEncoder.bin 449f12408130b7d0a17aa1da14b5bbae7f22d90307422992ebf26c7fe93b85f2
+optimism_l1_standard_bridge: ../../../contracts/solc/v0.8.24/IOptimismL1StandardBridge/IOptimismL1StandardBridge.abi ../../../contracts/solc/v0.8.24/IOptimismL1StandardBridge/IOptimismL1StandardBridge.bin ba8676c979f072983617d55b51ea3bc482abe06356830da57816c28f5397eb2e
+optimism_l2_bridge_adapter: ../../../contracts/solc/v0.8.24/OptimismL2BridgeAdapter/OptimismL2BridgeAdapter.abi ../../../contracts/solc/v0.8.24/OptimismL2BridgeAdapter/OptimismL2BridgeAdapter.bin ac707b967a62f8a70c8d1b1d02d28d1d8474f0511c279f709b68bbb3e08067bd
+optimism_l2_output_oracle: ../../../contracts/solc/v0.8.24/IOptimismL2OutputOracle/IOptimismL2OutputOracle.abi ../../../contracts/solc/v0.8.24/IOptimismL2OutputOracle/IOptimismL2OutputOracle.bin c89386866c41c4b31fed4b8b945ba27aa8258ad472968da98a81448a8a95e43c
+optimism_l2_to_l1_message_passer: ../../../contracts/solc/v0.8.24/IOptimismL2ToL1MessagePasser/IOptimismL2ToL1MessagePasser.abi ../../../contracts/solc/v0.8.24/IOptimismL2ToL1MessagePasser/IOptimismL2ToL1MessagePasser.bin 51f4568aa734c564a9aa82169f06e974e30650aeccbd07b20b0c8c60d48459fd
+optimism_portal: ../../../contracts/solc/v0.8.24/IOptimismPortal/IOptimismPortal.abi ../../../contracts/solc/v0.8.24/IOptimismPortal/IOptimismPortal.bin a644f108c9267f16bcea1648c8935e0e3741484b9b9ba7e87e0c2cb02bd0839f
+optimism_portal_2: ../../../contracts/solc/v0.8.24/IOptimismPortal2/IOptimismPortal2.abi ../../../contracts/solc/v0.8.24/IOptimismPortal2/IOptimismPortal2.bin a205fe314abb9056a23ee1ed609e182d012e3809d886c68c96c7b13da9513ab4
+optimism_standard_bridge: ../../../contracts/solc/v0.8.24/IOptimismStandardBridge/IOptimismStandardBridge.abi ../../../contracts/solc/v0.8.24/IOptimismStandardBridge/IOptimismStandardBridge.bin aaa354f8d9a45484aacb896eb148d315ac58587fad0e607adcd468723e653a94
+report_encoder: ../../../contracts/solc/v0.8.24/ReportEncoder/ReportEncoder.abi ../../../contracts/solc/v0.8.24/ReportEncoder/ReportEncoder.bin 43c10d4541b687ce08e754e07ccaa8ac6e5a4f2973d359ece4a56a02b68149d1
diff --git a/core/gethwrappers/liquiditymanager/go_generate.go b/core/gethwrappers/liquiditymanager/go_generate.go
new file mode 100644
index 00000000000..93507793bbd
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/go_generate.go
@@ -0,0 +1,37 @@
+// Package gethwrappers_ccip provides tools for wrapping solidity contracts with
+// golang packages, using abigen.
+package liquiditymanager
+
+// LiquidityManager contracts
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/LiquidityManager/LiquidityManager.abi ../../../contracts/solc/v0.8.24/LiquidityManager/LiquidityManager.bin LiquidityManager liquiditymanager
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/ArbitrumL1BridgeAdapter/ArbitrumL1BridgeAdapter.abi ../../../contracts/solc/v0.8.24/ArbitrumL1BridgeAdapter/ArbitrumL1BridgeAdapter.bin ArbitrumL1BridgeAdapter arbitrum_l1_bridge_adapter
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/ArbitrumL2BridgeAdapter/ArbitrumL2BridgeAdapter.abi ../../../contracts/solc/v0.8.24/ArbitrumL2BridgeAdapter/ArbitrumL2BridgeAdapter.bin ArbitrumL2BridgeAdapter arbitrum_l2_bridge_adapter
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/OptimismL1BridgeAdapter/OptimismL1BridgeAdapter.abi ../../../contracts/solc/v0.8.24/OptimismL1BridgeAdapter/OptimismL1BridgeAdapter.bin OptimismL1BridgeAdapter optimism_l1_bridge_adapter
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/OptimismL2BridgeAdapter/OptimismL2BridgeAdapter.abi ../../../contracts/solc/v0.8.24/OptimismL2BridgeAdapter/OptimismL2BridgeAdapter.bin OptimismL2BridgeAdapter optimism_l2_bridge_adapter
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/NoOpOCR3/NoOpOCR3.abi ../../../contracts/solc/v0.8.24/NoOpOCR3/NoOpOCR3.bin NoOpOCR3 no_op_ocr3
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockBridgeAdapter/MockL2BridgeAdapter.abi ../../../contracts/solc/v0.8.24/MockBridgeAdapter/MockL2BridgeAdapter.bin MockL2BridgeAdapter mock_l2_bridge_adapter
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/MockBridgeAdapter/MockL1BridgeAdapter.abi ../../../contracts/solc/v0.8.24/MockBridgeAdapter/MockL1BridgeAdapter.bin MockL1BridgeAdapter mock_l1_bridge_adapter
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/ReportEncoder/ReportEncoder.abi ../../../contracts/solc/v0.8.24/ReportEncoder/ReportEncoder.bin ReportEncoder report_encoder
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/OptimismL1BridgeAdapterEncoder/OptimismL1BridgeAdapterEncoder.abi ../../../contracts/solc/v0.8.24/OptimismL1BridgeAdapterEncoder/OptimismL1BridgeAdapterEncoder.bin OptimismL1BridgeAdapterEncoder optimism_l1_bridge_adapter_encoder
+
+// Arbitrum helpers
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IArbSys/IArbSys.abi ../../../contracts/solc/v0.8.24/IArbSys/IArbSys.bin ArbSys arbsys
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/INodeInterface/INodeInterface.abi ../../../contracts/solc/v0.8.24/INodeInterface/INodeInterface.bin NodeInterface arb_node_interface
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IL2ArbitrumGateway/IL2ArbitrumGateway.abi ../../../contracts/solc/v0.8.24/IL2ArbitrumGateway/IL2ArbitrumGateway.bin L2ArbitrumGateway l2_arbitrum_gateway
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IL2ArbitrumMessenger/IL2ArbitrumMessenger.abi ../../../contracts/solc/v0.8.24/IL2ArbitrumMessenger/IL2ArbitrumMessenger.bin L2ArbitrumMessenger l2_arbitrum_messenger
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IArbRollupCore/IArbRollupCore.abi ../../../contracts/solc/v0.8.24/IArbRollupCore/IArbRollupCore.bin ArbRollupCore arbitrum_rollup_core
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IArbitrumL1GatewayRouter/IArbitrumL1GatewayRouter.abi ../../../contracts/solc/v0.8.24/IArbitrumL1GatewayRouter/IArbitrumL1GatewayRouter.bin ArbitrumL1GatewayRouter arbitrum_l1_gateway_router
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IArbitrumInbox/IArbitrumInbox.abi ../../../contracts/solc/v0.8.24/IArbitrumInbox/IArbitrumInbox.bin ArbitrumInbox arbitrum_inbox
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IArbitrumGatewayRouter/IArbitrumGatewayRouter.abi ../../../contracts/solc/v0.8.24/IArbitrumGatewayRouter/IArbitrumGatewayRouter.bin ArbitrumGatewayRouter arbitrum_gateway_router
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IArbitrumTokenGateway/IArbitrumTokenGateway.abi ../../../contracts/solc/v0.8.24/IArbitrumTokenGateway/IArbitrumTokenGateway.bin ArbitrumTokenGateway arbitrum_token_gateway
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IAbstractArbitrumTokenGateway/IAbstractArbitrumTokenGateway.abi ../../../contracts/solc/v0.8.24/IAbstractArbitrumTokenGateway/IAbstractArbitrumTokenGateway.bin AbstractArbitrumTokenGateway abstract_arbitrum_token_gateway
+
+// Optimism helpers
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOptimismPortal/IOptimismPortal.abi ../../../contracts/solc/v0.8.24/IOptimismPortal/IOptimismPortal.bin OptimismPortal optimism_portal
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOptimismL2OutputOracle/IOptimismL2OutputOracle.abi ../../../contracts/solc/v0.8.24/IOptimismL2OutputOracle/IOptimismL2OutputOracle.bin OptimismL2OutputOracle optimism_l2_output_oracle
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOptimismL2ToL1MessagePasser/IOptimismL2ToL1MessagePasser.abi ../../../contracts/solc/v0.8.24/IOptimismL2ToL1MessagePasser/IOptimismL2ToL1MessagePasser.bin OptimismL2ToL1MessagePasser optimism_l2_to_l1_message_passer
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOptimismCrossDomainMessenger/IOptimismCrossDomainMessenger.abi ../../../contracts/solc/v0.8.24/IOptimismCrossDomainMessenger/IOptimismCrossDomainMessenger.bin OptimismCrossDomainMessenger optimism_cross_domain_messenger
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOptimismPortal2/IOptimismPortal2.abi ../../../contracts/solc/v0.8.24/IOptimismPortal2/IOptimismPortal2.bin OptimismPortal2 optimism_portal_2
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOptimismDisputeGameFactory/IOptimismDisputeGameFactory.abi ../../../contracts/solc/v0.8.24/IOptimismDisputeGameFactory/IOptimismDisputeGameFactory.bin OptimismDisputeGameFactory optimism_dispute_game_factory
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOptimismStandardBridge/IOptimismStandardBridge.abi ../../../contracts/solc/v0.8.24/IOptimismStandardBridge/IOptimismStandardBridge.bin OptimismStandardBridge optimism_standard_bridge
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.24/IOptimismL1StandardBridge/IOptimismL1StandardBridge.abi ../../../contracts/solc/v0.8.24/IOptimismL1StandardBridge/IOptimismL1StandardBridge.bin OptimismL1StandardBridge optimism_l1_standard_bridge
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_gateway_router/arbitrum_gateway_router_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_gateway_router/arbitrum_gateway_router_interface.go
new file mode 100644
index 00000000000..7503e5357e3
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_gateway_router/arbitrum_gateway_router_interface.go
@@ -0,0 +1,1054 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_arbitrum_gateway_router
+
+import (
+ big "math/big"
+
+ arbitrum_gateway_router "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_gateway_router"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ArbitrumGatewayRouterInterface is an autogenerated mock type for the ArbitrumGatewayRouterInterface type
+type ArbitrumGatewayRouterInterface struct {
+ mock.Mock
+}
+
+type ArbitrumGatewayRouterInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ArbitrumGatewayRouterInterface) EXPECT() *ArbitrumGatewayRouterInterface_Expecter {
+ return &ArbitrumGatewayRouterInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *ArbitrumGatewayRouterInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// ArbitrumGatewayRouterInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type ArbitrumGatewayRouterInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *ArbitrumGatewayRouterInterface_Expecter) Address() *ArbitrumGatewayRouterInterface_Address_Call {
+ return &ArbitrumGatewayRouterInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_Address_Call) Run(run func()) *ArbitrumGatewayRouterInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_Address_Call) Return(_a0 common.Address) *ArbitrumGatewayRouterInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_Address_Call) RunAndReturn(run func() common.Address) *ArbitrumGatewayRouterInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CalculateL2TokenAddress provides a mock function with given fields: opts, l1ERC20
+func (_m *ArbitrumGatewayRouterInterface) CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error) {
+ ret := _m.Called(opts, l1ERC20)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CalculateL2TokenAddress")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, l1ERC20)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, l1ERC20)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, l1ERC20)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CalculateL2TokenAddress'
+type ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call struct {
+ *mock.Call
+}
+
+// CalculateL2TokenAddress is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - l1ERC20 common.Address
+func (_e *ArbitrumGatewayRouterInterface_Expecter) CalculateL2TokenAddress(opts interface{}, l1ERC20 interface{}) *ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call {
+ return &ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call{Call: _e.mock.On("CalculateL2TokenAddress", opts, l1ERC20)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call) Run(run func(opts *bind.CallOpts, l1ERC20 common.Address)) *ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call) Return(_a0 common.Address, _a1 error) *ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *ArbitrumGatewayRouterInterface_CalculateL2TokenAddress_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// DefaultGateway provides a mock function with given fields: opts
+func (_m *ArbitrumGatewayRouterInterface) DefaultGateway(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DefaultGateway")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_DefaultGateway_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DefaultGateway'
+type ArbitrumGatewayRouterInterface_DefaultGateway_Call struct {
+ *mock.Call
+}
+
+// DefaultGateway is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbitrumGatewayRouterInterface_Expecter) DefaultGateway(opts interface{}) *ArbitrumGatewayRouterInterface_DefaultGateway_Call {
+ return &ArbitrumGatewayRouterInterface_DefaultGateway_Call{Call: _e.mock.On("DefaultGateway", opts)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_DefaultGateway_Call) Run(run func(opts *bind.CallOpts)) *ArbitrumGatewayRouterInterface_DefaultGateway_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_DefaultGateway_Call) Return(_a0 common.Address, _a1 error) *ArbitrumGatewayRouterInterface_DefaultGateway_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_DefaultGateway_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbitrumGatewayRouterInterface_DefaultGateway_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterDefaultGatewayUpdated provides a mock function with given fields: opts
+func (_m *ArbitrumGatewayRouterInterface) FilterDefaultGatewayUpdated(opts *bind.FilterOpts) (*arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdatedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterDefaultGatewayUpdated")
+ }
+
+ var r0 *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdatedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdatedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterDefaultGatewayUpdated'
+type ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterDefaultGatewayUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *ArbitrumGatewayRouterInterface_Expecter) FilterDefaultGatewayUpdated(opts interface{}) *ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call {
+ return &ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call{Call: _e.mock.On("FilterDefaultGatewayUpdated", opts)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call) Run(run func(opts *bind.FilterOpts)) *ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call) Return(_a0 *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdatedIterator, _a1 error) *ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call) RunAndReturn(run func(*bind.FilterOpts) (*arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdatedIterator, error)) *ArbitrumGatewayRouterInterface_FilterDefaultGatewayUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterGatewaySet provides a mock function with given fields: opts, l1Token, gateway
+func (_m *ArbitrumGatewayRouterInterface) FilterGatewaySet(opts *bind.FilterOpts, l1Token []common.Address, gateway []common.Address) (*arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySetIterator, error) {
+ ret := _m.Called(opts, l1Token, gateway)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterGatewaySet")
+ }
+
+ var r0 *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySetIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySetIterator, error)); ok {
+ return rf(opts, l1Token, gateway)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySetIterator); ok {
+ r0 = rf(opts, l1Token, gateway)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySetIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, l1Token, gateway)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_FilterGatewaySet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterGatewaySet'
+type ArbitrumGatewayRouterInterface_FilterGatewaySet_Call struct {
+ *mock.Call
+}
+
+// FilterGatewaySet is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - l1Token []common.Address
+// - gateway []common.Address
+func (_e *ArbitrumGatewayRouterInterface_Expecter) FilterGatewaySet(opts interface{}, l1Token interface{}, gateway interface{}) *ArbitrumGatewayRouterInterface_FilterGatewaySet_Call {
+ return &ArbitrumGatewayRouterInterface_FilterGatewaySet_Call{Call: _e.mock.On("FilterGatewaySet", opts, l1Token, gateway)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterGatewaySet_Call) Run(run func(opts *bind.FilterOpts, l1Token []common.Address, gateway []common.Address)) *ArbitrumGatewayRouterInterface_FilterGatewaySet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterGatewaySet_Call) Return(_a0 *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySetIterator, _a1 error) *ArbitrumGatewayRouterInterface_FilterGatewaySet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterGatewaySet_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address) (*arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySetIterator, error)) *ArbitrumGatewayRouterInterface_FilterGatewaySet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTransferRouted provides a mock function with given fields: opts, token, _userFrom, _userTo
+func (_m *ArbitrumGatewayRouterInterface) FilterTransferRouted(opts *bind.FilterOpts, token []common.Address, _userFrom []common.Address, _userTo []common.Address) (*arbitrum_gateway_router.ArbitrumGatewayRouterTransferRoutedIterator, error) {
+ ret := _m.Called(opts, token, _userFrom, _userTo)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTransferRouted")
+ }
+
+ var r0 *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRoutedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*arbitrum_gateway_router.ArbitrumGatewayRouterTransferRoutedIterator, error)); ok {
+ return rf(opts, token, _userFrom, _userTo)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRoutedIterator); ok {
+ r0 = rf(opts, token, _userFrom, _userTo)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_gateway_router.ArbitrumGatewayRouterTransferRoutedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, token, _userFrom, _userTo)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_FilterTransferRouted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTransferRouted'
+type ArbitrumGatewayRouterInterface_FilterTransferRouted_Call struct {
+ *mock.Call
+}
+
+// FilterTransferRouted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - token []common.Address
+// - _userFrom []common.Address
+// - _userTo []common.Address
+func (_e *ArbitrumGatewayRouterInterface_Expecter) FilterTransferRouted(opts interface{}, token interface{}, _userFrom interface{}, _userTo interface{}) *ArbitrumGatewayRouterInterface_FilterTransferRouted_Call {
+ return &ArbitrumGatewayRouterInterface_FilterTransferRouted_Call{Call: _e.mock.On("FilterTransferRouted", opts, token, _userFrom, _userTo)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterTransferRouted_Call) Run(run func(opts *bind.FilterOpts, token []common.Address, _userFrom []common.Address, _userTo []common.Address)) *ArbitrumGatewayRouterInterface_FilterTransferRouted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterTransferRouted_Call) Return(_a0 *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRoutedIterator, _a1 error) *ArbitrumGatewayRouterInterface_FilterTransferRouted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FilterTransferRouted_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*arbitrum_gateway_router.ArbitrumGatewayRouterTransferRoutedIterator, error)) *ArbitrumGatewayRouterInterface_FilterTransferRouted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FinalizeInboundTransfer provides a mock function with given fields: opts, _token, _from, _to, _amount, _data
+func (_m *ArbitrumGatewayRouterInterface) FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, _token, _from, _to, _amount, _data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FinalizeInboundTransfer")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, _token, _from, _to, _amount, _data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, _token, _from, _to, _amount, _data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, _token, _from, _to, _amount, _data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FinalizeInboundTransfer'
+type ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call struct {
+ *mock.Call
+}
+
+// FinalizeInboundTransfer is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _token common.Address
+// - _from common.Address
+// - _to common.Address
+// - _amount *big.Int
+// - _data []byte
+func (_e *ArbitrumGatewayRouterInterface_Expecter) FinalizeInboundTransfer(opts interface{}, _token interface{}, _from interface{}, _to interface{}, _amount interface{}, _data interface{}) *ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call {
+ return &ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call{Call: _e.mock.On("FinalizeInboundTransfer", opts, _token, _from, _to, _amount, _data)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call) Run(run func(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte)) *ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(common.Address), args[4].(*big.Int), args[5].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)) *ArbitrumGatewayRouterInterface_FinalizeInboundTransfer_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetGateway provides a mock function with given fields: opts, _token
+func (_m *ArbitrumGatewayRouterInterface) GetGateway(opts *bind.CallOpts, _token common.Address) (common.Address, error) {
+ ret := _m.Called(opts, _token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGateway")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, _token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, _token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, _token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_GetGateway_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGateway'
+type ArbitrumGatewayRouterInterface_GetGateway_Call struct {
+ *mock.Call
+}
+
+// GetGateway is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - _token common.Address
+func (_e *ArbitrumGatewayRouterInterface_Expecter) GetGateway(opts interface{}, _token interface{}) *ArbitrumGatewayRouterInterface_GetGateway_Call {
+ return &ArbitrumGatewayRouterInterface_GetGateway_Call{Call: _e.mock.On("GetGateway", opts, _token)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_GetGateway_Call) Run(run func(opts *bind.CallOpts, _token common.Address)) *ArbitrumGatewayRouterInterface_GetGateway_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_GetGateway_Call) Return(_a0 common.Address, _a1 error) *ArbitrumGatewayRouterInterface_GetGateway_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_GetGateway_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *ArbitrumGatewayRouterInterface_GetGateway_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetOutboundCalldata provides a mock function with given fields: opts, _token, _from, _to, _amount, _data
+func (_m *ArbitrumGatewayRouterInterface) GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ ret := _m.Called(opts, _token, _from, _to, _amount, _data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetOutboundCalldata")
+ }
+
+ var r0 []byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address, common.Address, *big.Int, []byte) ([]byte, error)); ok {
+ return rf(opts, _token, _from, _to, _amount, _data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address, common.Address, *big.Int, []byte) []byte); ok {
+ r0 = rf(opts, _token, _from, _to, _amount, _data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address, common.Address, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, _token, _from, _to, _amount, _data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOutboundCalldata'
+type ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call struct {
+ *mock.Call
+}
+
+// GetOutboundCalldata is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - _token common.Address
+// - _from common.Address
+// - _to common.Address
+// - _amount *big.Int
+// - _data []byte
+func (_e *ArbitrumGatewayRouterInterface_Expecter) GetOutboundCalldata(opts interface{}, _token interface{}, _from interface{}, _to interface{}, _amount interface{}, _data interface{}) *ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call {
+ return &ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call{Call: _e.mock.On("GetOutboundCalldata", opts, _token, _from, _to, _amount, _data)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call) Run(run func(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte)) *ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address), args[2].(common.Address), args[3].(common.Address), args[4].(*big.Int), args[5].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call) Return(_a0 []byte, _a1 error) *ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call) RunAndReturn(run func(*bind.CallOpts, common.Address, common.Address, common.Address, *big.Int, []byte) ([]byte, error)) *ArbitrumGatewayRouterInterface_GetOutboundCalldata_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// OutboundTransfer provides a mock function with given fields: opts, _token, _to, _amount, _maxGas, _gasPriceBid, _data
+func (_m *ArbitrumGatewayRouterInterface) OutboundTransfer(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OutboundTransfer")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, *big.Int, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, *big.Int, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, *big.Int, *big.Int, []byte) error); ok {
+ r1 = rf(opts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_OutboundTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OutboundTransfer'
+type ArbitrumGatewayRouterInterface_OutboundTransfer_Call struct {
+ *mock.Call
+}
+
+// OutboundTransfer is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _token common.Address
+// - _to common.Address
+// - _amount *big.Int
+// - _maxGas *big.Int
+// - _gasPriceBid *big.Int
+// - _data []byte
+func (_e *ArbitrumGatewayRouterInterface_Expecter) OutboundTransfer(opts interface{}, _token interface{}, _to interface{}, _amount interface{}, _maxGas interface{}, _gasPriceBid interface{}, _data interface{}) *ArbitrumGatewayRouterInterface_OutboundTransfer_Call {
+ return &ArbitrumGatewayRouterInterface_OutboundTransfer_Call{Call: _e.mock.On("OutboundTransfer", opts, _token, _to, _amount, _maxGas, _gasPriceBid, _data)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_OutboundTransfer_Call) Run(run func(opts *bind.TransactOpts, _token common.Address, _to common.Address, _amount *big.Int, _maxGas *big.Int, _gasPriceBid *big.Int, _data []byte)) *ArbitrumGatewayRouterInterface_OutboundTransfer_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(*big.Int), args[4].(*big.Int), args[5].(*big.Int), args[6].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_OutboundTransfer_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumGatewayRouterInterface_OutboundTransfer_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_OutboundTransfer_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, *big.Int, *big.Int, *big.Int, []byte) (*types.Transaction, error)) *ArbitrumGatewayRouterInterface_OutboundTransfer_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseDefaultGatewayUpdated provides a mock function with given fields: log
+func (_m *ArbitrumGatewayRouterInterface) ParseDefaultGatewayUpdated(log types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseDefaultGatewayUpdated")
+ }
+
+ var r0 *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseDefaultGatewayUpdated'
+type ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call struct {
+ *mock.Call
+}
+
+// ParseDefaultGatewayUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbitrumGatewayRouterInterface_Expecter) ParseDefaultGatewayUpdated(log interface{}) *ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call {
+ return &ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call{Call: _e.mock.On("ParseDefaultGatewayUpdated", log)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call) Run(run func(log types.Log)) *ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call) Return(_a0 *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated, _a1 error) *ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call) RunAndReturn(run func(types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated, error)) *ArbitrumGatewayRouterInterface_ParseDefaultGatewayUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseGatewaySet provides a mock function with given fields: log
+func (_m *ArbitrumGatewayRouterInterface) ParseGatewaySet(log types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseGatewaySet")
+ }
+
+ var r0 *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_ParseGatewaySet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseGatewaySet'
+type ArbitrumGatewayRouterInterface_ParseGatewaySet_Call struct {
+ *mock.Call
+}
+
+// ParseGatewaySet is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbitrumGatewayRouterInterface_Expecter) ParseGatewaySet(log interface{}) *ArbitrumGatewayRouterInterface_ParseGatewaySet_Call {
+ return &ArbitrumGatewayRouterInterface_ParseGatewaySet_Call{Call: _e.mock.On("ParseGatewaySet", log)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseGatewaySet_Call) Run(run func(log types.Log)) *ArbitrumGatewayRouterInterface_ParseGatewaySet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseGatewaySet_Call) Return(_a0 *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, _a1 error) *ArbitrumGatewayRouterInterface_ParseGatewaySet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseGatewaySet_Call) RunAndReturn(run func(types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, error)) *ArbitrumGatewayRouterInterface_ParseGatewaySet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *ArbitrumGatewayRouterInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type ArbitrumGatewayRouterInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbitrumGatewayRouterInterface_Expecter) ParseLog(log interface{}) *ArbitrumGatewayRouterInterface_ParseLog_Call {
+ return &ArbitrumGatewayRouterInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseLog_Call) Run(run func(log types.Log)) *ArbitrumGatewayRouterInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *ArbitrumGatewayRouterInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *ArbitrumGatewayRouterInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTransferRouted provides a mock function with given fields: log
+func (_m *ArbitrumGatewayRouterInterface) ParseTransferRouted(log types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTransferRouted")
+ }
+
+ var r0 *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_ParseTransferRouted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTransferRouted'
+type ArbitrumGatewayRouterInterface_ParseTransferRouted_Call struct {
+ *mock.Call
+}
+
+// ParseTransferRouted is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbitrumGatewayRouterInterface_Expecter) ParseTransferRouted(log interface{}) *ArbitrumGatewayRouterInterface_ParseTransferRouted_Call {
+ return &ArbitrumGatewayRouterInterface_ParseTransferRouted_Call{Call: _e.mock.On("ParseTransferRouted", log)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseTransferRouted_Call) Run(run func(log types.Log)) *ArbitrumGatewayRouterInterface_ParseTransferRouted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseTransferRouted_Call) Return(_a0 *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, _a1 error) *ArbitrumGatewayRouterInterface_ParseTransferRouted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_ParseTransferRouted_Call) RunAndReturn(run func(types.Log) (*arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, error)) *ArbitrumGatewayRouterInterface_ParseTransferRouted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchDefaultGatewayUpdated provides a mock function with given fields: opts, sink
+func (_m *ArbitrumGatewayRouterInterface) WatchDefaultGatewayUpdated(opts *bind.WatchOpts, sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchDefaultGatewayUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchDefaultGatewayUpdated'
+type ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchDefaultGatewayUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated
+func (_e *ArbitrumGatewayRouterInterface_Expecter) WatchDefaultGatewayUpdated(opts interface{}, sink interface{}) *ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call {
+ return &ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call{Call: _e.mock.On("WatchDefaultGatewayUpdated", opts, sink)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated)) *ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call) Return(_a0 event.Subscription, _a1 error) *ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterDefaultGatewayUpdated) (event.Subscription, error)) *ArbitrumGatewayRouterInterface_WatchDefaultGatewayUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchGatewaySet provides a mock function with given fields: opts, sink, l1Token, gateway
+func (_m *ArbitrumGatewayRouterInterface) WatchGatewaySet(opts *bind.WatchOpts, sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, l1Token []common.Address, gateway []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, l1Token, gateway)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchGatewaySet")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, l1Token, gateway)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, l1Token, gateway)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, l1Token, gateway)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_WatchGatewaySet_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchGatewaySet'
+type ArbitrumGatewayRouterInterface_WatchGatewaySet_Call struct {
+ *mock.Call
+}
+
+// WatchGatewaySet is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet
+// - l1Token []common.Address
+// - gateway []common.Address
+func (_e *ArbitrumGatewayRouterInterface_Expecter) WatchGatewaySet(opts interface{}, sink interface{}, l1Token interface{}, gateway interface{}) *ArbitrumGatewayRouterInterface_WatchGatewaySet_Call {
+ return &ArbitrumGatewayRouterInterface_WatchGatewaySet_Call{Call: _e.mock.On("WatchGatewaySet", opts, sink, l1Token, gateway)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchGatewaySet_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, l1Token []common.Address, gateway []common.Address)) *ArbitrumGatewayRouterInterface_WatchGatewaySet_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchGatewaySet_Call) Return(_a0 event.Subscription, _a1 error) *ArbitrumGatewayRouterInterface_WatchGatewaySet_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchGatewaySet_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterGatewaySet, []common.Address, []common.Address) (event.Subscription, error)) *ArbitrumGatewayRouterInterface_WatchGatewaySet_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTransferRouted provides a mock function with given fields: opts, sink, token, _userFrom, _userTo
+func (_m *ArbitrumGatewayRouterInterface) WatchTransferRouted(opts *bind.WatchOpts, sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, token []common.Address, _userFrom []common.Address, _userTo []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, token, _userFrom, _userTo)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTransferRouted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, token, _userFrom, _userTo)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, []common.Address, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, token, _userFrom, _userTo)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, []common.Address, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, token, _userFrom, _userTo)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumGatewayRouterInterface_WatchTransferRouted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTransferRouted'
+type ArbitrumGatewayRouterInterface_WatchTransferRouted_Call struct {
+ *mock.Call
+}
+
+// WatchTransferRouted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted
+// - token []common.Address
+// - _userFrom []common.Address
+// - _userTo []common.Address
+func (_e *ArbitrumGatewayRouterInterface_Expecter) WatchTransferRouted(opts interface{}, sink interface{}, token interface{}, _userFrom interface{}, _userTo interface{}) *ArbitrumGatewayRouterInterface_WatchTransferRouted_Call {
+ return &ArbitrumGatewayRouterInterface_WatchTransferRouted_Call{Call: _e.mock.On("WatchTransferRouted", opts, sink, token, _userFrom, _userTo)}
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchTransferRouted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, token []common.Address, _userFrom []common.Address, _userTo []common.Address)) *ArbitrumGatewayRouterInterface_WatchTransferRouted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted), args[2].([]common.Address), args[3].([]common.Address), args[4].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchTransferRouted_Call) Return(_a0 event.Subscription, _a1 error) *ArbitrumGatewayRouterInterface_WatchTransferRouted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumGatewayRouterInterface_WatchTransferRouted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_gateway_router.ArbitrumGatewayRouterTransferRouted, []common.Address, []common.Address, []common.Address) (event.Subscription, error)) *ArbitrumGatewayRouterInterface_WatchTransferRouted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewArbitrumGatewayRouterInterface creates a new instance of ArbitrumGatewayRouterInterface. 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 NewArbitrumGatewayRouterInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ArbitrumGatewayRouterInterface {
+ mock := &ArbitrumGatewayRouterInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_inbox/arbitrum_inbox_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_inbox/arbitrum_inbox_interface.go
new file mode 100644
index 00000000000..ca259c06211
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_inbox/arbitrum_inbox_interface.go
@@ -0,0 +1,1452 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_arbitrum_inbox
+
+import (
+ big "math/big"
+
+ arbitrum_inbox "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_inbox"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ArbitrumInboxInterface is an autogenerated mock type for the ArbitrumInboxInterface type
+type ArbitrumInboxInterface struct {
+ mock.Mock
+}
+
+type ArbitrumInboxInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ArbitrumInboxInterface) EXPECT() *ArbitrumInboxInterface_Expecter {
+ return &ArbitrumInboxInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *ArbitrumInboxInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// ArbitrumInboxInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type ArbitrumInboxInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *ArbitrumInboxInterface_Expecter) Address() *ArbitrumInboxInterface_Address_Call {
+ return &ArbitrumInboxInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *ArbitrumInboxInterface_Address_Call) Run(run func()) *ArbitrumInboxInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Address_Call) Return(_a0 common.Address) *ArbitrumInboxInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Address_Call) RunAndReturn(run func() common.Address) *ArbitrumInboxInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// AllowListEnabled provides a mock function with given fields: opts
+func (_m *ArbitrumInboxInterface) AllowListEnabled(opts *bind.CallOpts) (bool, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AllowListEnabled")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) bool); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_AllowListEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AllowListEnabled'
+type ArbitrumInboxInterface_AllowListEnabled_Call struct {
+ *mock.Call
+}
+
+// AllowListEnabled is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbitrumInboxInterface_Expecter) AllowListEnabled(opts interface{}) *ArbitrumInboxInterface_AllowListEnabled_Call {
+ return &ArbitrumInboxInterface_AllowListEnabled_Call{Call: _e.mock.On("AllowListEnabled", opts)}
+}
+
+func (_c *ArbitrumInboxInterface_AllowListEnabled_Call) Run(run func(opts *bind.CallOpts)) *ArbitrumInboxInterface_AllowListEnabled_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_AllowListEnabled_Call) Return(_a0 bool, _a1 error) *ArbitrumInboxInterface_AllowListEnabled_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_AllowListEnabled_Call) RunAndReturn(run func(*bind.CallOpts) (bool, error)) *ArbitrumInboxInterface_AllowListEnabled_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Bridge provides a mock function with given fields: opts
+func (_m *ArbitrumInboxInterface) Bridge(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Bridge")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_Bridge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bridge'
+type ArbitrumInboxInterface_Bridge_Call struct {
+ *mock.Call
+}
+
+// Bridge is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbitrumInboxInterface_Expecter) Bridge(opts interface{}) *ArbitrumInboxInterface_Bridge_Call {
+ return &ArbitrumInboxInterface_Bridge_Call{Call: _e.mock.On("Bridge", opts)}
+}
+
+func (_c *ArbitrumInboxInterface_Bridge_Call) Run(run func(opts *bind.CallOpts)) *ArbitrumInboxInterface_Bridge_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Bridge_Call) Return(_a0 common.Address, _a1 error) *ArbitrumInboxInterface_Bridge_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Bridge_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbitrumInboxInterface_Bridge_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CalculateRetryableSubmissionFee provides a mock function with given fields: opts, dataLength, baseFee
+func (_m *ArbitrumInboxInterface) CalculateRetryableSubmissionFee(opts *bind.CallOpts, dataLength *big.Int, baseFee *big.Int) (*big.Int, error) {
+ ret := _m.Called(opts, dataLength, baseFee)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CalculateRetryableSubmissionFee")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, *big.Int) (*big.Int, error)); ok {
+ return rf(opts, dataLength, baseFee)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, *big.Int) *big.Int); ok {
+ r0 = rf(opts, dataLength, baseFee)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int, *big.Int) error); ok {
+ r1 = rf(opts, dataLength, baseFee)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CalculateRetryableSubmissionFee'
+type ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call struct {
+ *mock.Call
+}
+
+// CalculateRetryableSubmissionFee is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - dataLength *big.Int
+// - baseFee *big.Int
+func (_e *ArbitrumInboxInterface_Expecter) CalculateRetryableSubmissionFee(opts interface{}, dataLength interface{}, baseFee interface{}) *ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call {
+ return &ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call{Call: _e.mock.On("CalculateRetryableSubmissionFee", opts, dataLength, baseFee)}
+}
+
+func (_c *ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call) Run(run func(opts *bind.CallOpts, dataLength *big.Int, baseFee *big.Int)) *ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(*big.Int), args[2].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call) Return(_a0 *big.Int, _a1 error) *ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int, *big.Int) (*big.Int, error)) *ArbitrumInboxInterface_CalculateRetryableSubmissionFee_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterInboxMessageDelivered provides a mock function with given fields: opts, messageNum
+func (_m *ArbitrumInboxInterface) FilterInboxMessageDelivered(opts *bind.FilterOpts, messageNum []*big.Int) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredIterator, error) {
+ ret := _m.Called(opts, messageNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterInboxMessageDelivered")
+ }
+
+ var r0 *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredIterator, error)); ok {
+ return rf(opts, messageNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredIterator); ok {
+ r0 = rf(opts, messageNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok {
+ r1 = rf(opts, messageNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_FilterInboxMessageDelivered_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterInboxMessageDelivered'
+type ArbitrumInboxInterface_FilterInboxMessageDelivered_Call struct {
+ *mock.Call
+}
+
+// FilterInboxMessageDelivered is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - messageNum []*big.Int
+func (_e *ArbitrumInboxInterface_Expecter) FilterInboxMessageDelivered(opts interface{}, messageNum interface{}) *ArbitrumInboxInterface_FilterInboxMessageDelivered_Call {
+ return &ArbitrumInboxInterface_FilterInboxMessageDelivered_Call{Call: _e.mock.On("FilterInboxMessageDelivered", opts, messageNum)}
+}
+
+func (_c *ArbitrumInboxInterface_FilterInboxMessageDelivered_Call) Run(run func(opts *bind.FilterOpts, messageNum []*big.Int)) *ArbitrumInboxInterface_FilterInboxMessageDelivered_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_FilterInboxMessageDelivered_Call) Return(_a0 *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredIterator, _a1 error) *ArbitrumInboxInterface_FilterInboxMessageDelivered_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_FilterInboxMessageDelivered_Call) RunAndReturn(run func(*bind.FilterOpts, []*big.Int) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredIterator, error)) *ArbitrumInboxInterface_FilterInboxMessageDelivered_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterInboxMessageDeliveredFromOrigin provides a mock function with given fields: opts, messageNum
+func (_m *ArbitrumInboxInterface) FilterInboxMessageDeliveredFromOrigin(opts *bind.FilterOpts, messageNum []*big.Int) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOriginIterator, error) {
+ ret := _m.Called(opts, messageNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterInboxMessageDeliveredFromOrigin")
+ }
+
+ var r0 *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOriginIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOriginIterator, error)); ok {
+ return rf(opts, messageNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOriginIterator); ok {
+ r0 = rf(opts, messageNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOriginIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int) error); ok {
+ r1 = rf(opts, messageNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterInboxMessageDeliveredFromOrigin'
+type ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call struct {
+ *mock.Call
+}
+
+// FilterInboxMessageDeliveredFromOrigin is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - messageNum []*big.Int
+func (_e *ArbitrumInboxInterface_Expecter) FilterInboxMessageDeliveredFromOrigin(opts interface{}, messageNum interface{}) *ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call {
+ return &ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call{Call: _e.mock.On("FilterInboxMessageDeliveredFromOrigin", opts, messageNum)}
+}
+
+func (_c *ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call) Run(run func(opts *bind.FilterOpts, messageNum []*big.Int)) *ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call) Return(_a0 *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOriginIterator, _a1 error) *ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call) RunAndReturn(run func(*bind.FilterOpts, []*big.Int) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOriginIterator, error)) *ArbitrumInboxInterface_FilterInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetProxyAdmin provides a mock function with given fields: opts
+func (_m *ArbitrumInboxInterface) GetProxyAdmin(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetProxyAdmin")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_GetProxyAdmin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProxyAdmin'
+type ArbitrumInboxInterface_GetProxyAdmin_Call struct {
+ *mock.Call
+}
+
+// GetProxyAdmin is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbitrumInboxInterface_Expecter) GetProxyAdmin(opts interface{}) *ArbitrumInboxInterface_GetProxyAdmin_Call {
+ return &ArbitrumInboxInterface_GetProxyAdmin_Call{Call: _e.mock.On("GetProxyAdmin", opts)}
+}
+
+func (_c *ArbitrumInboxInterface_GetProxyAdmin_Call) Run(run func(opts *bind.CallOpts)) *ArbitrumInboxInterface_GetProxyAdmin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_GetProxyAdmin_Call) Return(_a0 common.Address, _a1 error) *ArbitrumInboxInterface_GetProxyAdmin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_GetProxyAdmin_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbitrumInboxInterface_GetProxyAdmin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Initialize provides a mock function with given fields: opts, _bridge, _sequencerInbox
+func (_m *ArbitrumInboxInterface) Initialize(opts *bind.TransactOpts, _bridge common.Address, _sequencerInbox common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, _bridge, _sequencerInbox)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Initialize")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, _bridge, _sequencerInbox)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, _bridge, _sequencerInbox)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address) error); ok {
+ r1 = rf(opts, _bridge, _sequencerInbox)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_Initialize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Initialize'
+type ArbitrumInboxInterface_Initialize_Call struct {
+ *mock.Call
+}
+
+// Initialize is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _bridge common.Address
+// - _sequencerInbox common.Address
+func (_e *ArbitrumInboxInterface_Expecter) Initialize(opts interface{}, _bridge interface{}, _sequencerInbox interface{}) *ArbitrumInboxInterface_Initialize_Call {
+ return &ArbitrumInboxInterface_Initialize_Call{Call: _e.mock.On("Initialize", opts, _bridge, _sequencerInbox)}
+}
+
+func (_c *ArbitrumInboxInterface_Initialize_Call) Run(run func(opts *bind.TransactOpts, _bridge common.Address, _sequencerInbox common.Address)) *ArbitrumInboxInterface_Initialize_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Initialize_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_Initialize_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Initialize_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)) *ArbitrumInboxInterface_Initialize_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsAllowed provides a mock function with given fields: opts, user
+func (_m *ArbitrumInboxInterface) IsAllowed(opts *bind.CallOpts, user common.Address) (bool, error) {
+ ret := _m.Called(opts, user)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsAllowed")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (bool, error)); ok {
+ return rf(opts, user)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) bool); ok {
+ r0 = rf(opts, user)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, user)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_IsAllowed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsAllowed'
+type ArbitrumInboxInterface_IsAllowed_Call struct {
+ *mock.Call
+}
+
+// IsAllowed is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - user common.Address
+func (_e *ArbitrumInboxInterface_Expecter) IsAllowed(opts interface{}, user interface{}) *ArbitrumInboxInterface_IsAllowed_Call {
+ return &ArbitrumInboxInterface_IsAllowed_Call{Call: _e.mock.On("IsAllowed", opts, user)}
+}
+
+func (_c *ArbitrumInboxInterface_IsAllowed_Call) Run(run func(opts *bind.CallOpts, user common.Address)) *ArbitrumInboxInterface_IsAllowed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_IsAllowed_Call) Return(_a0 bool, _a1 error) *ArbitrumInboxInterface_IsAllowed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_IsAllowed_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (bool, error)) *ArbitrumInboxInterface_IsAllowed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// MaxDataSize provides a mock function with given fields: opts
+func (_m *ArbitrumInboxInterface) MaxDataSize(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for MaxDataSize")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_MaxDataSize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MaxDataSize'
+type ArbitrumInboxInterface_MaxDataSize_Call struct {
+ *mock.Call
+}
+
+// MaxDataSize is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbitrumInboxInterface_Expecter) MaxDataSize(opts interface{}) *ArbitrumInboxInterface_MaxDataSize_Call {
+ return &ArbitrumInboxInterface_MaxDataSize_Call{Call: _e.mock.On("MaxDataSize", opts)}
+}
+
+func (_c *ArbitrumInboxInterface_MaxDataSize_Call) Run(run func(opts *bind.CallOpts)) *ArbitrumInboxInterface_MaxDataSize_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_MaxDataSize_Call) Return(_a0 *big.Int, _a1 error) *ArbitrumInboxInterface_MaxDataSize_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_MaxDataSize_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbitrumInboxInterface_MaxDataSize_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseInboxMessageDelivered provides a mock function with given fields: log
+func (_m *ArbitrumInboxInterface) ParseInboxMessageDelivered(log types.Log) (*arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseInboxMessageDelivered")
+ }
+
+ var r0 *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_inbox.ArbitrumInboxInboxMessageDelivered)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_ParseInboxMessageDelivered_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseInboxMessageDelivered'
+type ArbitrumInboxInterface_ParseInboxMessageDelivered_Call struct {
+ *mock.Call
+}
+
+// ParseInboxMessageDelivered is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbitrumInboxInterface_Expecter) ParseInboxMessageDelivered(log interface{}) *ArbitrumInboxInterface_ParseInboxMessageDelivered_Call {
+ return &ArbitrumInboxInterface_ParseInboxMessageDelivered_Call{Call: _e.mock.On("ParseInboxMessageDelivered", log)}
+}
+
+func (_c *ArbitrumInboxInterface_ParseInboxMessageDelivered_Call) Run(run func(log types.Log)) *ArbitrumInboxInterface_ParseInboxMessageDelivered_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_ParseInboxMessageDelivered_Call) Return(_a0 *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, _a1 error) *ArbitrumInboxInterface_ParseInboxMessageDelivered_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_ParseInboxMessageDelivered_Call) RunAndReturn(run func(types.Log) (*arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, error)) *ArbitrumInboxInterface_ParseInboxMessageDelivered_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseInboxMessageDeliveredFromOrigin provides a mock function with given fields: log
+func (_m *ArbitrumInboxInterface) ParseInboxMessageDeliveredFromOrigin(log types.Log) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseInboxMessageDeliveredFromOrigin")
+ }
+
+ var r0 *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseInboxMessageDeliveredFromOrigin'
+type ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call struct {
+ *mock.Call
+}
+
+// ParseInboxMessageDeliveredFromOrigin is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbitrumInboxInterface_Expecter) ParseInboxMessageDeliveredFromOrigin(log interface{}) *ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call {
+ return &ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call{Call: _e.mock.On("ParseInboxMessageDeliveredFromOrigin", log)}
+}
+
+func (_c *ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call) Run(run func(log types.Log)) *ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call) Return(_a0 *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, _a1 error) *ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call) RunAndReturn(run func(types.Log) (*arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, error)) *ArbitrumInboxInterface_ParseInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *ArbitrumInboxInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type ArbitrumInboxInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbitrumInboxInterface_Expecter) ParseLog(log interface{}) *ArbitrumInboxInterface_ParseLog_Call {
+ return &ArbitrumInboxInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *ArbitrumInboxInterface_ParseLog_Call) Run(run func(log types.Log)) *ArbitrumInboxInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *ArbitrumInboxInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *ArbitrumInboxInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Pause provides a mock function with given fields: opts
+func (_m *ArbitrumInboxInterface) Pause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Pause")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_Pause_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Pause'
+type ArbitrumInboxInterface_Pause_Call struct {
+ *mock.Call
+}
+
+// Pause is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *ArbitrumInboxInterface_Expecter) Pause(opts interface{}) *ArbitrumInboxInterface_Pause_Call {
+ return &ArbitrumInboxInterface_Pause_Call{Call: _e.mock.On("Pause", opts)}
+}
+
+func (_c *ArbitrumInboxInterface_Pause_Call) Run(run func(opts *bind.TransactOpts)) *ArbitrumInboxInterface_Pause_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Pause_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_Pause_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Pause_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *ArbitrumInboxInterface_Pause_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SendContractTransaction provides a mock function with given fields: opts, gasLimit, maxFeePerGas, to, value, data
+func (_m *ArbitrumInboxInterface) SendContractTransaction(opts *bind.TransactOpts, gasLimit *big.Int, maxFeePerGas *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, gasLimit, maxFeePerGas, to, value, data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SendContractTransaction")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, gasLimit, maxFeePerGas, to, value, data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int, common.Address, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, gasLimit, maxFeePerGas, to, value, data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, *big.Int, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, gasLimit, maxFeePerGas, to, value, data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_SendContractTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendContractTransaction'
+type ArbitrumInboxInterface_SendContractTransaction_Call struct {
+ *mock.Call
+}
+
+// SendContractTransaction is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - gasLimit *big.Int
+// - maxFeePerGas *big.Int
+// - to common.Address
+// - value *big.Int
+// - data []byte
+func (_e *ArbitrumInboxInterface_Expecter) SendContractTransaction(opts interface{}, gasLimit interface{}, maxFeePerGas interface{}, to interface{}, value interface{}, data interface{}) *ArbitrumInboxInterface_SendContractTransaction_Call {
+ return &ArbitrumInboxInterface_SendContractTransaction_Call{Call: _e.mock.On("SendContractTransaction", opts, gasLimit, maxFeePerGas, to, value, data)}
+}
+
+func (_c *ArbitrumInboxInterface_SendContractTransaction_Call) Run(run func(opts *bind.TransactOpts, gasLimit *big.Int, maxFeePerGas *big.Int, to common.Address, value *big.Int, data []byte)) *ArbitrumInboxInterface_SendContractTransaction_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(*big.Int), args[2].(*big.Int), args[3].(common.Address), args[4].(*big.Int), args[5].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SendContractTransaction_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_SendContractTransaction_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SendContractTransaction_Call) RunAndReturn(run func(*bind.TransactOpts, *big.Int, *big.Int, common.Address, *big.Int, []byte) (*types.Transaction, error)) *ArbitrumInboxInterface_SendContractTransaction_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SendL2Message provides a mock function with given fields: opts, messageData
+func (_m *ArbitrumInboxInterface) SendL2Message(opts *bind.TransactOpts, messageData []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, messageData)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SendL2Message")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, messageData)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []byte) *types.Transaction); ok {
+ r0 = rf(opts, messageData)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []byte) error); ok {
+ r1 = rf(opts, messageData)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_SendL2Message_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendL2Message'
+type ArbitrumInboxInterface_SendL2Message_Call struct {
+ *mock.Call
+}
+
+// SendL2Message is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - messageData []byte
+func (_e *ArbitrumInboxInterface_Expecter) SendL2Message(opts interface{}, messageData interface{}) *ArbitrumInboxInterface_SendL2Message_Call {
+ return &ArbitrumInboxInterface_SendL2Message_Call{Call: _e.mock.On("SendL2Message", opts, messageData)}
+}
+
+func (_c *ArbitrumInboxInterface_SendL2Message_Call) Run(run func(opts *bind.TransactOpts, messageData []byte)) *ArbitrumInboxInterface_SendL2Message_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SendL2Message_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_SendL2Message_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SendL2Message_Call) RunAndReturn(run func(*bind.TransactOpts, []byte) (*types.Transaction, error)) *ArbitrumInboxInterface_SendL2Message_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SendL2MessageFromOrigin provides a mock function with given fields: opts, messageData
+func (_m *ArbitrumInboxInterface) SendL2MessageFromOrigin(opts *bind.TransactOpts, messageData []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, messageData)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SendL2MessageFromOrigin")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, messageData)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []byte) *types.Transaction); ok {
+ r0 = rf(opts, messageData)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []byte) error); ok {
+ r1 = rf(opts, messageData)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_SendL2MessageFromOrigin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendL2MessageFromOrigin'
+type ArbitrumInboxInterface_SendL2MessageFromOrigin_Call struct {
+ *mock.Call
+}
+
+// SendL2MessageFromOrigin is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - messageData []byte
+func (_e *ArbitrumInboxInterface_Expecter) SendL2MessageFromOrigin(opts interface{}, messageData interface{}) *ArbitrumInboxInterface_SendL2MessageFromOrigin_Call {
+ return &ArbitrumInboxInterface_SendL2MessageFromOrigin_Call{Call: _e.mock.On("SendL2MessageFromOrigin", opts, messageData)}
+}
+
+func (_c *ArbitrumInboxInterface_SendL2MessageFromOrigin_Call) Run(run func(opts *bind.TransactOpts, messageData []byte)) *ArbitrumInboxInterface_SendL2MessageFromOrigin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SendL2MessageFromOrigin_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_SendL2MessageFromOrigin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SendL2MessageFromOrigin_Call) RunAndReturn(run func(*bind.TransactOpts, []byte) (*types.Transaction, error)) *ArbitrumInboxInterface_SendL2MessageFromOrigin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SendUnsignedTransaction provides a mock function with given fields: opts, gasLimit, maxFeePerGas, nonce, to, value, data
+func (_m *ArbitrumInboxInterface) SendUnsignedTransaction(opts *bind.TransactOpts, gasLimit *big.Int, maxFeePerGas *big.Int, nonce *big.Int, to common.Address, value *big.Int, data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, gasLimit, maxFeePerGas, nonce, to, value, data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SendUnsignedTransaction")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int, *big.Int, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, gasLimit, maxFeePerGas, nonce, to, value, data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int, *big.Int, common.Address, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, gasLimit, maxFeePerGas, nonce, to, value, data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, *big.Int, *big.Int, *big.Int, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, gasLimit, maxFeePerGas, nonce, to, value, data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_SendUnsignedTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendUnsignedTransaction'
+type ArbitrumInboxInterface_SendUnsignedTransaction_Call struct {
+ *mock.Call
+}
+
+// SendUnsignedTransaction is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - gasLimit *big.Int
+// - maxFeePerGas *big.Int
+// - nonce *big.Int
+// - to common.Address
+// - value *big.Int
+// - data []byte
+func (_e *ArbitrumInboxInterface_Expecter) SendUnsignedTransaction(opts interface{}, gasLimit interface{}, maxFeePerGas interface{}, nonce interface{}, to interface{}, value interface{}, data interface{}) *ArbitrumInboxInterface_SendUnsignedTransaction_Call {
+ return &ArbitrumInboxInterface_SendUnsignedTransaction_Call{Call: _e.mock.On("SendUnsignedTransaction", opts, gasLimit, maxFeePerGas, nonce, to, value, data)}
+}
+
+func (_c *ArbitrumInboxInterface_SendUnsignedTransaction_Call) Run(run func(opts *bind.TransactOpts, gasLimit *big.Int, maxFeePerGas *big.Int, nonce *big.Int, to common.Address, value *big.Int, data []byte)) *ArbitrumInboxInterface_SendUnsignedTransaction_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(*big.Int), args[2].(*big.Int), args[3].(*big.Int), args[4].(common.Address), args[5].(*big.Int), args[6].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SendUnsignedTransaction_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_SendUnsignedTransaction_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SendUnsignedTransaction_Call) RunAndReturn(run func(*bind.TransactOpts, *big.Int, *big.Int, *big.Int, common.Address, *big.Int, []byte) (*types.Transaction, error)) *ArbitrumInboxInterface_SendUnsignedTransaction_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SequencerInbox provides a mock function with given fields: opts
+func (_m *ArbitrumInboxInterface) SequencerInbox(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SequencerInbox")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_SequencerInbox_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SequencerInbox'
+type ArbitrumInboxInterface_SequencerInbox_Call struct {
+ *mock.Call
+}
+
+// SequencerInbox is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbitrumInboxInterface_Expecter) SequencerInbox(opts interface{}) *ArbitrumInboxInterface_SequencerInbox_Call {
+ return &ArbitrumInboxInterface_SequencerInbox_Call{Call: _e.mock.On("SequencerInbox", opts)}
+}
+
+func (_c *ArbitrumInboxInterface_SequencerInbox_Call) Run(run func(opts *bind.CallOpts)) *ArbitrumInboxInterface_SequencerInbox_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SequencerInbox_Call) Return(_a0 common.Address, _a1 error) *ArbitrumInboxInterface_SequencerInbox_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SequencerInbox_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbitrumInboxInterface_SequencerInbox_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetAllowList provides a mock function with given fields: opts, user, val
+func (_m *ArbitrumInboxInterface) SetAllowList(opts *bind.TransactOpts, user []common.Address, val []bool) (*types.Transaction, error) {
+ ret := _m.Called(opts, user, val)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetAllowList")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []bool) (*types.Transaction, error)); ok {
+ return rf(opts, user, val)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []bool) *types.Transaction); ok {
+ r0 = rf(opts, user, val)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, []common.Address, []bool) error); ok {
+ r1 = rf(opts, user, val)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_SetAllowList_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAllowList'
+type ArbitrumInboxInterface_SetAllowList_Call struct {
+ *mock.Call
+}
+
+// SetAllowList is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - user []common.Address
+// - val []bool
+func (_e *ArbitrumInboxInterface_Expecter) SetAllowList(opts interface{}, user interface{}, val interface{}) *ArbitrumInboxInterface_SetAllowList_Call {
+ return &ArbitrumInboxInterface_SetAllowList_Call{Call: _e.mock.On("SetAllowList", opts, user, val)}
+}
+
+func (_c *ArbitrumInboxInterface_SetAllowList_Call) Run(run func(opts *bind.TransactOpts, user []common.Address, val []bool)) *ArbitrumInboxInterface_SetAllowList_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].([]common.Address), args[2].([]bool))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SetAllowList_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_SetAllowList_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SetAllowList_Call) RunAndReturn(run func(*bind.TransactOpts, []common.Address, []bool) (*types.Transaction, error)) *ArbitrumInboxInterface_SetAllowList_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetAllowListEnabled provides a mock function with given fields: opts, _allowListEnabled
+func (_m *ArbitrumInboxInterface) SetAllowListEnabled(opts *bind.TransactOpts, _allowListEnabled bool) (*types.Transaction, error) {
+ ret := _m.Called(opts, _allowListEnabled)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetAllowListEnabled")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, bool) (*types.Transaction, error)); ok {
+ return rf(opts, _allowListEnabled)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, bool) *types.Transaction); ok {
+ r0 = rf(opts, _allowListEnabled)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, bool) error); ok {
+ r1 = rf(opts, _allowListEnabled)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_SetAllowListEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetAllowListEnabled'
+type ArbitrumInboxInterface_SetAllowListEnabled_Call struct {
+ *mock.Call
+}
+
+// SetAllowListEnabled is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _allowListEnabled bool
+func (_e *ArbitrumInboxInterface_Expecter) SetAllowListEnabled(opts interface{}, _allowListEnabled interface{}) *ArbitrumInboxInterface_SetAllowListEnabled_Call {
+ return &ArbitrumInboxInterface_SetAllowListEnabled_Call{Call: _e.mock.On("SetAllowListEnabled", opts, _allowListEnabled)}
+}
+
+func (_c *ArbitrumInboxInterface_SetAllowListEnabled_Call) Run(run func(opts *bind.TransactOpts, _allowListEnabled bool)) *ArbitrumInboxInterface_SetAllowListEnabled_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(bool))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SetAllowListEnabled_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_SetAllowListEnabled_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_SetAllowListEnabled_Call) RunAndReturn(run func(*bind.TransactOpts, bool) (*types.Transaction, error)) *ArbitrumInboxInterface_SetAllowListEnabled_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Unpause provides a mock function with given fields: opts
+func (_m *ArbitrumInboxInterface) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Unpause")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_Unpause_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unpause'
+type ArbitrumInboxInterface_Unpause_Call struct {
+ *mock.Call
+}
+
+// Unpause is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *ArbitrumInboxInterface_Expecter) Unpause(opts interface{}) *ArbitrumInboxInterface_Unpause_Call {
+ return &ArbitrumInboxInterface_Unpause_Call{Call: _e.mock.On("Unpause", opts)}
+}
+
+func (_c *ArbitrumInboxInterface_Unpause_Call) Run(run func(opts *bind.TransactOpts)) *ArbitrumInboxInterface_Unpause_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Unpause_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumInboxInterface_Unpause_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_Unpause_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *ArbitrumInboxInterface_Unpause_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchInboxMessageDelivered provides a mock function with given fields: opts, sink, messageNum
+func (_m *ArbitrumInboxInterface) WatchInboxMessageDelivered(opts *bind.WatchOpts, sink chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, messageNum []*big.Int) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, messageNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchInboxMessageDelivered")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, []*big.Int) (event.Subscription, error)); ok {
+ return rf(opts, sink, messageNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, []*big.Int) event.Subscription); ok {
+ r0 = rf(opts, sink, messageNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, []*big.Int) error); ok {
+ r1 = rf(opts, sink, messageNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_WatchInboxMessageDelivered_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchInboxMessageDelivered'
+type ArbitrumInboxInterface_WatchInboxMessageDelivered_Call struct {
+ *mock.Call
+}
+
+// WatchInboxMessageDelivered is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered
+// - messageNum []*big.Int
+func (_e *ArbitrumInboxInterface_Expecter) WatchInboxMessageDelivered(opts interface{}, sink interface{}, messageNum interface{}) *ArbitrumInboxInterface_WatchInboxMessageDelivered_Call {
+ return &ArbitrumInboxInterface_WatchInboxMessageDelivered_Call{Call: _e.mock.On("WatchInboxMessageDelivered", opts, sink, messageNum)}
+}
+
+func (_c *ArbitrumInboxInterface_WatchInboxMessageDelivered_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, messageNum []*big.Int)) *ArbitrumInboxInterface_WatchInboxMessageDelivered_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered), args[2].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_WatchInboxMessageDelivered_Call) Return(_a0 event.Subscription, _a1 error) *ArbitrumInboxInterface_WatchInboxMessageDelivered_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_WatchInboxMessageDelivered_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDelivered, []*big.Int) (event.Subscription, error)) *ArbitrumInboxInterface_WatchInboxMessageDelivered_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchInboxMessageDeliveredFromOrigin provides a mock function with given fields: opts, sink, messageNum
+func (_m *ArbitrumInboxInterface) WatchInboxMessageDeliveredFromOrigin(opts *bind.WatchOpts, sink chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, messageNum []*big.Int) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, messageNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchInboxMessageDeliveredFromOrigin")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, []*big.Int) (event.Subscription, error)); ok {
+ return rf(opts, sink, messageNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, []*big.Int) event.Subscription); ok {
+ r0 = rf(opts, sink, messageNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, []*big.Int) error); ok {
+ r1 = rf(opts, sink, messageNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchInboxMessageDeliveredFromOrigin'
+type ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call struct {
+ *mock.Call
+}
+
+// WatchInboxMessageDeliveredFromOrigin is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin
+// - messageNum []*big.Int
+func (_e *ArbitrumInboxInterface_Expecter) WatchInboxMessageDeliveredFromOrigin(opts interface{}, sink interface{}, messageNum interface{}) *ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call {
+ return &ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call{Call: _e.mock.On("WatchInboxMessageDeliveredFromOrigin", opts, sink, messageNum)}
+}
+
+func (_c *ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, messageNum []*big.Int)) *ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin), args[2].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call) Return(_a0 event.Subscription, _a1 error) *ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_inbox.ArbitrumInboxInboxMessageDeliveredFromOrigin, []*big.Int) (event.Subscription, error)) *ArbitrumInboxInterface_WatchInboxMessageDeliveredFromOrigin_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewArbitrumInboxInterface creates a new instance of ArbitrumInboxInterface. 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 NewArbitrumInboxInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ArbitrumInboxInterface {
+ mock := &ArbitrumInboxInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_l1_bridge_adapter/arbitrum_l1_bridge_adapter_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_l1_bridge_adapter/arbitrum_l1_bridge_adapter_interface.go
new file mode 100644
index 00000000000..94c24efa200
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_l1_bridge_adapter/arbitrum_l1_bridge_adapter_interface.go
@@ -0,0 +1,426 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_arbitrum_l1_bridge_adapter
+
+import (
+ big "math/big"
+
+ arbitrum_l1_bridge_adapter "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_l1_bridge_adapter"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+
+ common "github.com/ethereum/go-ethereum/common"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ArbitrumL1BridgeAdapterInterface is an autogenerated mock type for the ArbitrumL1BridgeAdapterInterface type
+type ArbitrumL1BridgeAdapterInterface struct {
+ mock.Mock
+}
+
+type ArbitrumL1BridgeAdapterInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ArbitrumL1BridgeAdapterInterface) EXPECT() *ArbitrumL1BridgeAdapterInterface_Expecter {
+ return &ArbitrumL1BridgeAdapterInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *ArbitrumL1BridgeAdapterInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// ArbitrumL1BridgeAdapterInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type ArbitrumL1BridgeAdapterInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *ArbitrumL1BridgeAdapterInterface_Expecter) Address() *ArbitrumL1BridgeAdapterInterface_Address_Call {
+ return &ArbitrumL1BridgeAdapterInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_Address_Call) Run(run func()) *ArbitrumL1BridgeAdapterInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_Address_Call) Return(_a0 common.Address) *ArbitrumL1BridgeAdapterInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_Address_Call) RunAndReturn(run func() common.Address) *ArbitrumL1BridgeAdapterInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ExposeArbitrumFinalizationPayload provides a mock function with given fields: opts, payload
+func (_m *ArbitrumL1BridgeAdapterInterface) ExposeArbitrumFinalizationPayload(opts *bind.CallOpts, payload arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterArbitrumFinalizationPayload) error {
+ ret := _m.Called(opts, payload)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExposeArbitrumFinalizationPayload")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterArbitrumFinalizationPayload) error); ok {
+ r0 = rf(opts, payload)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExposeArbitrumFinalizationPayload'
+type ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call struct {
+ *mock.Call
+}
+
+// ExposeArbitrumFinalizationPayload is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - payload arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterArbitrumFinalizationPayload
+func (_e *ArbitrumL1BridgeAdapterInterface_Expecter) ExposeArbitrumFinalizationPayload(opts interface{}, payload interface{}) *ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call {
+ return &ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call{Call: _e.mock.On("ExposeArbitrumFinalizationPayload", opts, payload)}
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call) Run(run func(opts *bind.CallOpts, payload arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterArbitrumFinalizationPayload)) *ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterArbitrumFinalizationPayload))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call) Return(_a0 error) *ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call) RunAndReturn(run func(*bind.CallOpts, arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterArbitrumFinalizationPayload) error) *ArbitrumL1BridgeAdapterInterface_ExposeArbitrumFinalizationPayload_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ExposeSendERC20Params provides a mock function with given fields: opts, params
+func (_m *ArbitrumL1BridgeAdapterInterface) ExposeSendERC20Params(opts *bind.CallOpts, params arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterSendERC20Params) error {
+ ret := _m.Called(opts, params)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExposeSendERC20Params")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterSendERC20Params) error); ok {
+ r0 = rf(opts, params)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExposeSendERC20Params'
+type ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call struct {
+ *mock.Call
+}
+
+// ExposeSendERC20Params is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - params arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterSendERC20Params
+func (_e *ArbitrumL1BridgeAdapterInterface_Expecter) ExposeSendERC20Params(opts interface{}, params interface{}) *ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call {
+ return &ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call{Call: _e.mock.On("ExposeSendERC20Params", opts, params)}
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call) Run(run func(opts *bind.CallOpts, params arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterSendERC20Params)) *ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterSendERC20Params))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call) Return(_a0 error) *ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call) RunAndReturn(run func(*bind.CallOpts, arbitrum_l1_bridge_adapter.ArbitrumL1BridgeAdapterSendERC20Params) error) *ArbitrumL1BridgeAdapterInterface_ExposeSendERC20Params_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FinalizeWithdrawERC20 provides a mock function with given fields: opts, arg0, arg1, arbitrumFinalizationPayload
+func (_m *ArbitrumL1BridgeAdapterInterface) FinalizeWithdrawERC20(opts *bind.TransactOpts, arg0 common.Address, arg1 common.Address, arbitrumFinalizationPayload []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, arg0, arg1, arbitrumFinalizationPayload)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FinalizeWithdrawERC20")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, arg0, arg1, arbitrumFinalizationPayload)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, []byte) *types.Transaction); ok {
+ r0 = rf(opts, arg0, arg1, arbitrumFinalizationPayload)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, []byte) error); ok {
+ r1 = rf(opts, arg0, arg1, arbitrumFinalizationPayload)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FinalizeWithdrawERC20'
+type ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call struct {
+ *mock.Call
+}
+
+// FinalizeWithdrawERC20 is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - arg0 common.Address
+// - arg1 common.Address
+// - arbitrumFinalizationPayload []byte
+func (_e *ArbitrumL1BridgeAdapterInterface_Expecter) FinalizeWithdrawERC20(opts interface{}, arg0 interface{}, arg1 interface{}, arbitrumFinalizationPayload interface{}) *ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call {
+ return &ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call{Call: _e.mock.On("FinalizeWithdrawERC20", opts, arg0, arg1, arbitrumFinalizationPayload)}
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call) Run(run func(opts *bind.TransactOpts, arg0 common.Address, arg1 common.Address, arbitrumFinalizationPayload []byte)) *ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, []byte) (*types.Transaction, error)) *ArbitrumL1BridgeAdapterInterface_FinalizeWithdrawERC20_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetBridgeFeeInNative provides a mock function with given fields: opts
+func (_m *ArbitrumL1BridgeAdapterInterface) GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetBridgeFeeInNative")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBridgeFeeInNative'
+type ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call struct {
+ *mock.Call
+}
+
+// GetBridgeFeeInNative is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbitrumL1BridgeAdapterInterface_Expecter) GetBridgeFeeInNative(opts interface{}) *ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call {
+ return &ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call{Call: _e.mock.On("GetBridgeFeeInNative", opts)}
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call) Run(run func(opts *bind.CallOpts)) *ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call) Return(_a0 *big.Int, _a1 error) *ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbitrumL1BridgeAdapterInterface_GetBridgeFeeInNative_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetL2Token provides a mock function with given fields: opts, l1Token
+func (_m *ArbitrumL1BridgeAdapterInterface) GetL2Token(opts *bind.CallOpts, l1Token common.Address) (common.Address, error) {
+ ret := _m.Called(opts, l1Token)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetL2Token")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, l1Token)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, l1Token)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, l1Token)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumL1BridgeAdapterInterface_GetL2Token_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL2Token'
+type ArbitrumL1BridgeAdapterInterface_GetL2Token_Call struct {
+ *mock.Call
+}
+
+// GetL2Token is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - l1Token common.Address
+func (_e *ArbitrumL1BridgeAdapterInterface_Expecter) GetL2Token(opts interface{}, l1Token interface{}) *ArbitrumL1BridgeAdapterInterface_GetL2Token_Call {
+ return &ArbitrumL1BridgeAdapterInterface_GetL2Token_Call{Call: _e.mock.On("GetL2Token", opts, l1Token)}
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_GetL2Token_Call) Run(run func(opts *bind.CallOpts, l1Token common.Address)) *ArbitrumL1BridgeAdapterInterface_GetL2Token_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_GetL2Token_Call) Return(_a0 common.Address, _a1 error) *ArbitrumL1BridgeAdapterInterface_GetL2Token_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_GetL2Token_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *ArbitrumL1BridgeAdapterInterface_GetL2Token_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SendERC20 provides a mock function with given fields: opts, localToken, arg1, recipient, amount, bridgeSpecificPayload
+func (_m *ArbitrumL1BridgeAdapterInterface) SendERC20(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, bridgeSpecificPayload []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, localToken, arg1, recipient, amount, bridgeSpecificPayload)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SendERC20")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, localToken, arg1, recipient, amount, bridgeSpecificPayload)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, localToken, arg1, recipient, amount, bridgeSpecificPayload)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, localToken, arg1, recipient, amount, bridgeSpecificPayload)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumL1BridgeAdapterInterface_SendERC20_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendERC20'
+type ArbitrumL1BridgeAdapterInterface_SendERC20_Call struct {
+ *mock.Call
+}
+
+// SendERC20 is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - localToken common.Address
+// - arg1 common.Address
+// - recipient common.Address
+// - amount *big.Int
+// - bridgeSpecificPayload []byte
+func (_e *ArbitrumL1BridgeAdapterInterface_Expecter) SendERC20(opts interface{}, localToken interface{}, arg1 interface{}, recipient interface{}, amount interface{}, bridgeSpecificPayload interface{}) *ArbitrumL1BridgeAdapterInterface_SendERC20_Call {
+ return &ArbitrumL1BridgeAdapterInterface_SendERC20_Call{Call: _e.mock.On("SendERC20", opts, localToken, arg1, recipient, amount, bridgeSpecificPayload)}
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_SendERC20_Call) Run(run func(opts *bind.TransactOpts, localToken common.Address, arg1 common.Address, recipient common.Address, amount *big.Int, bridgeSpecificPayload []byte)) *ArbitrumL1BridgeAdapterInterface_SendERC20_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(common.Address), args[4].(*big.Int), args[5].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_SendERC20_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumL1BridgeAdapterInterface_SendERC20_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumL1BridgeAdapterInterface_SendERC20_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)) *ArbitrumL1BridgeAdapterInterface_SendERC20_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewArbitrumL1BridgeAdapterInterface creates a new instance of ArbitrumL1BridgeAdapterInterface. 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 NewArbitrumL1BridgeAdapterInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ArbitrumL1BridgeAdapterInterface {
+ mock := &ArbitrumL1BridgeAdapterInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_l2_bridge_adapter/arbitrum_l2_bridge_adapter_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_l2_bridge_adapter/arbitrum_l2_bridge_adapter_interface.go
new file mode 100644
index 00000000000..01d025790a6
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_l2_bridge_adapter/arbitrum_l2_bridge_adapter_interface.go
@@ -0,0 +1,327 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_arbitrum_l2_bridge_adapter
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ArbitrumL2BridgeAdapterInterface is an autogenerated mock type for the ArbitrumL2BridgeAdapterInterface type
+type ArbitrumL2BridgeAdapterInterface struct {
+ mock.Mock
+}
+
+type ArbitrumL2BridgeAdapterInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ArbitrumL2BridgeAdapterInterface) EXPECT() *ArbitrumL2BridgeAdapterInterface_Expecter {
+ return &ArbitrumL2BridgeAdapterInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *ArbitrumL2BridgeAdapterInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// ArbitrumL2BridgeAdapterInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type ArbitrumL2BridgeAdapterInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *ArbitrumL2BridgeAdapterInterface_Expecter) Address() *ArbitrumL2BridgeAdapterInterface_Address_Call {
+ return &ArbitrumL2BridgeAdapterInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_Address_Call) Run(run func()) *ArbitrumL2BridgeAdapterInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_Address_Call) Return(_a0 common.Address) *ArbitrumL2BridgeAdapterInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_Address_Call) RunAndReturn(run func() common.Address) *ArbitrumL2BridgeAdapterInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// DepositNativeToL1 provides a mock function with given fields: opts, recipient
+func (_m *ArbitrumL2BridgeAdapterInterface) DepositNativeToL1(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, recipient)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DepositNativeToL1")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, recipient)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, recipient)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, recipient)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DepositNativeToL1'
+type ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call struct {
+ *mock.Call
+}
+
+// DepositNativeToL1 is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - recipient common.Address
+func (_e *ArbitrumL2BridgeAdapterInterface_Expecter) DepositNativeToL1(opts interface{}, recipient interface{}) *ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call {
+ return &ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call{Call: _e.mock.On("DepositNativeToL1", opts, recipient)}
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call) Run(run func(opts *bind.TransactOpts, recipient common.Address)) *ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *ArbitrumL2BridgeAdapterInterface_DepositNativeToL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FinalizeWithdrawERC20 provides a mock function with given fields: opts, arg0, arg1, arg2
+func (_m *ArbitrumL2BridgeAdapterInterface) FinalizeWithdrawERC20(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 []byte) (bool, error) {
+ ret := _m.Called(opts, arg0, arg1, arg2)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FinalizeWithdrawERC20")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address, []byte) (bool, error)); ok {
+ return rf(opts, arg0, arg1, arg2)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address, []byte) bool); ok {
+ r0 = rf(opts, arg0, arg1, arg2)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address, common.Address, []byte) error); ok {
+ r1 = rf(opts, arg0, arg1, arg2)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FinalizeWithdrawERC20'
+type ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call struct {
+ *mock.Call
+}
+
+// FinalizeWithdrawERC20 is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - arg0 common.Address
+// - arg1 common.Address
+// - arg2 []byte
+func (_e *ArbitrumL2BridgeAdapterInterface_Expecter) FinalizeWithdrawERC20(opts interface{}, arg0 interface{}, arg1 interface{}, arg2 interface{}) *ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call {
+ return &ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call{Call: _e.mock.On("FinalizeWithdrawERC20", opts, arg0, arg1, arg2)}
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call) Run(run func(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address, arg2 []byte)) *ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address), args[2].(common.Address), args[3].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call) Return(_a0 bool, _a1 error) *ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call) RunAndReturn(run func(*bind.CallOpts, common.Address, common.Address, []byte) (bool, error)) *ArbitrumL2BridgeAdapterInterface_FinalizeWithdrawERC20_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetBridgeFeeInNative provides a mock function with given fields: opts
+func (_m *ArbitrumL2BridgeAdapterInterface) GetBridgeFeeInNative(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetBridgeFeeInNative")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBridgeFeeInNative'
+type ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call struct {
+ *mock.Call
+}
+
+// GetBridgeFeeInNative is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbitrumL2BridgeAdapterInterface_Expecter) GetBridgeFeeInNative(opts interface{}) *ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call {
+ return &ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call{Call: _e.mock.On("GetBridgeFeeInNative", opts)}
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call) Run(run func(opts *bind.CallOpts)) *ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call) Return(_a0 *big.Int, _a1 error) *ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbitrumL2BridgeAdapterInterface_GetBridgeFeeInNative_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SendERC20 provides a mock function with given fields: opts, localToken, remoteToken, recipient, amount, arg4
+func (_m *ArbitrumL2BridgeAdapterInterface) SendERC20(opts *bind.TransactOpts, localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, localToken, remoteToken, recipient, amount, arg4)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SendERC20")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, localToken, remoteToken, recipient, amount, arg4)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, localToken, remoteToken, recipient, amount, arg4)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, localToken, remoteToken, recipient, amount, arg4)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbitrumL2BridgeAdapterInterface_SendERC20_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendERC20'
+type ArbitrumL2BridgeAdapterInterface_SendERC20_Call struct {
+ *mock.Call
+}
+
+// SendERC20 is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - localToken common.Address
+// - remoteToken common.Address
+// - recipient common.Address
+// - amount *big.Int
+// - arg4 []byte
+func (_e *ArbitrumL2BridgeAdapterInterface_Expecter) SendERC20(opts interface{}, localToken interface{}, remoteToken interface{}, recipient interface{}, amount interface{}, arg4 interface{}) *ArbitrumL2BridgeAdapterInterface_SendERC20_Call {
+ return &ArbitrumL2BridgeAdapterInterface_SendERC20_Call{Call: _e.mock.On("SendERC20", opts, localToken, remoteToken, recipient, amount, arg4)}
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_SendERC20_Call) Run(run func(opts *bind.TransactOpts, localToken common.Address, remoteToken common.Address, recipient common.Address, amount *big.Int, arg4 []byte)) *ArbitrumL2BridgeAdapterInterface_SendERC20_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(common.Address), args[4].(*big.Int), args[5].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_SendERC20_Call) Return(_a0 *types.Transaction, _a1 error) *ArbitrumL2BridgeAdapterInterface_SendERC20_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbitrumL2BridgeAdapterInterface_SendERC20_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)) *ArbitrumL2BridgeAdapterInterface_SendERC20_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewArbitrumL2BridgeAdapterInterface creates a new instance of ArbitrumL2BridgeAdapterInterface. 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 NewArbitrumL2BridgeAdapterInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ArbitrumL2BridgeAdapterInterface {
+ mock := &ArbitrumL2BridgeAdapterInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_rollup_core/arb_rollup_core_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_rollup_core/arb_rollup_core_interface.go
new file mode 100644
index 00000000000..bc18ea95f14
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_arbitrum_rollup_core/arb_rollup_core_interface.go
@@ -0,0 +1,3347 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_arbitrum_rollup_core
+
+import (
+ big "math/big"
+
+ arbitrum_rollup_core "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbitrum_rollup_core"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ArbRollupCoreInterface is an autogenerated mock type for the ArbRollupCoreInterface type
+type ArbRollupCoreInterface struct {
+ mock.Mock
+}
+
+type ArbRollupCoreInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ArbRollupCoreInterface) EXPECT() *ArbRollupCoreInterface_Expecter {
+ return &ArbRollupCoreInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *ArbRollupCoreInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// ArbRollupCoreInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type ArbRollupCoreInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *ArbRollupCoreInterface_Expecter) Address() *ArbRollupCoreInterface_Address_Call {
+ return &ArbRollupCoreInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *ArbRollupCoreInterface_Address_Call) Run(run func()) *ArbRollupCoreInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_Address_Call) Return(_a0 common.Address) *ArbRollupCoreInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_Address_Call) RunAndReturn(run func() common.Address) *ArbRollupCoreInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// AmountStaked provides a mock function with given fields: opts, staker
+func (_m *ArbRollupCoreInterface) AmountStaked(opts *bind.CallOpts, staker common.Address) (*big.Int, error) {
+ ret := _m.Called(opts, staker)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AmountStaked")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok {
+ return rf(opts, staker)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) *big.Int); ok {
+ r0 = rf(opts, staker)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, staker)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_AmountStaked_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AmountStaked'
+type ArbRollupCoreInterface_AmountStaked_Call struct {
+ *mock.Call
+}
+
+// AmountStaked is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - staker common.Address
+func (_e *ArbRollupCoreInterface_Expecter) AmountStaked(opts interface{}, staker interface{}) *ArbRollupCoreInterface_AmountStaked_Call {
+ return &ArbRollupCoreInterface_AmountStaked_Call{Call: _e.mock.On("AmountStaked", opts, staker)}
+}
+
+func (_c *ArbRollupCoreInterface_AmountStaked_Call) Run(run func(opts *bind.CallOpts, staker common.Address)) *ArbRollupCoreInterface_AmountStaked_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_AmountStaked_Call) Return(_a0 *big.Int, _a1 error) *ArbRollupCoreInterface_AmountStaked_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_AmountStaked_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (*big.Int, error)) *ArbRollupCoreInterface_AmountStaked_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// BaseStake provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) BaseStake(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for BaseStake")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_BaseStake_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BaseStake'
+type ArbRollupCoreInterface_BaseStake_Call struct {
+ *mock.Call
+}
+
+// BaseStake is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) BaseStake(opts interface{}) *ArbRollupCoreInterface_BaseStake_Call {
+ return &ArbRollupCoreInterface_BaseStake_Call{Call: _e.mock.On("BaseStake", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_BaseStake_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_BaseStake_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_BaseStake_Call) Return(_a0 *big.Int, _a1 error) *ArbRollupCoreInterface_BaseStake_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_BaseStake_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbRollupCoreInterface_BaseStake_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Bridge provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) Bridge(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Bridge")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_Bridge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bridge'
+type ArbRollupCoreInterface_Bridge_Call struct {
+ *mock.Call
+}
+
+// Bridge is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) Bridge(opts interface{}) *ArbRollupCoreInterface_Bridge_Call {
+ return &ArbRollupCoreInterface_Bridge_Call{Call: _e.mock.On("Bridge", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_Bridge_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_Bridge_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_Bridge_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_Bridge_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_Bridge_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbRollupCoreInterface_Bridge_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ChainId provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) ChainId(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ChainId")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ChainId_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ChainId'
+type ArbRollupCoreInterface_ChainId_Call struct {
+ *mock.Call
+}
+
+// ChainId is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) ChainId(opts interface{}) *ArbRollupCoreInterface_ChainId_Call {
+ return &ArbRollupCoreInterface_ChainId_Call{Call: _e.mock.On("ChainId", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_ChainId_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_ChainId_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ChainId_Call) Return(_a0 *big.Int, _a1 error) *ArbRollupCoreInterface_ChainId_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ChainId_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbRollupCoreInterface_ChainId_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ChallengeManager provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) ChallengeManager(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ChallengeManager")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ChallengeManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ChallengeManager'
+type ArbRollupCoreInterface_ChallengeManager_Call struct {
+ *mock.Call
+}
+
+// ChallengeManager is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) ChallengeManager(opts interface{}) *ArbRollupCoreInterface_ChallengeManager_Call {
+ return &ArbRollupCoreInterface_ChallengeManager_Call{Call: _e.mock.On("ChallengeManager", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_ChallengeManager_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_ChallengeManager_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ChallengeManager_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_ChallengeManager_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ChallengeManager_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbRollupCoreInterface_ChallengeManager_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ConfirmPeriodBlocks provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) ConfirmPeriodBlocks(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ConfirmPeriodBlocks")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ConfirmPeriodBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConfirmPeriodBlocks'
+type ArbRollupCoreInterface_ConfirmPeriodBlocks_Call struct {
+ *mock.Call
+}
+
+// ConfirmPeriodBlocks is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) ConfirmPeriodBlocks(opts interface{}) *ArbRollupCoreInterface_ConfirmPeriodBlocks_Call {
+ return &ArbRollupCoreInterface_ConfirmPeriodBlocks_Call{Call: _e.mock.On("ConfirmPeriodBlocks", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_ConfirmPeriodBlocks_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_ConfirmPeriodBlocks_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ConfirmPeriodBlocks_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_ConfirmPeriodBlocks_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ConfirmPeriodBlocks_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *ArbRollupCoreInterface_ConfirmPeriodBlocks_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CurrentChallenge provides a mock function with given fields: opts, staker
+func (_m *ArbRollupCoreInterface) CurrentChallenge(opts *bind.CallOpts, staker common.Address) (uint64, error) {
+ ret := _m.Called(opts, staker)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CurrentChallenge")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok {
+ return rf(opts, staker)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) uint64); ok {
+ r0 = rf(opts, staker)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, staker)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_CurrentChallenge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CurrentChallenge'
+type ArbRollupCoreInterface_CurrentChallenge_Call struct {
+ *mock.Call
+}
+
+// CurrentChallenge is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - staker common.Address
+func (_e *ArbRollupCoreInterface_Expecter) CurrentChallenge(opts interface{}, staker interface{}) *ArbRollupCoreInterface_CurrentChallenge_Call {
+ return &ArbRollupCoreInterface_CurrentChallenge_Call{Call: _e.mock.On("CurrentChallenge", opts, staker)}
+}
+
+func (_c *ArbRollupCoreInterface_CurrentChallenge_Call) Run(run func(opts *bind.CallOpts, staker common.Address)) *ArbRollupCoreInterface_CurrentChallenge_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_CurrentChallenge_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_CurrentChallenge_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_CurrentChallenge_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (uint64, error)) *ArbRollupCoreInterface_CurrentChallenge_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ExtraChallengeTimeBlocks provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) ExtraChallengeTimeBlocks(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExtraChallengeTimeBlocks")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExtraChallengeTimeBlocks'
+type ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call struct {
+ *mock.Call
+}
+
+// ExtraChallengeTimeBlocks is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) ExtraChallengeTimeBlocks(opts interface{}) *ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call {
+ return &ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call{Call: _e.mock.On("ExtraChallengeTimeBlocks", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *ArbRollupCoreInterface_ExtraChallengeTimeBlocks_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterNodeConfirmed provides a mock function with given fields: opts, nodeNum
+func (_m *ArbRollupCoreInterface) FilterNodeConfirmed(opts *bind.FilterOpts, nodeNum []uint64) (*arbitrum_rollup_core.ArbRollupCoreNodeConfirmedIterator, error) {
+ ret := _m.Called(opts, nodeNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterNodeConfirmed")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreNodeConfirmedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*arbitrum_rollup_core.ArbRollupCoreNodeConfirmedIterator, error)); ok {
+ return rf(opts, nodeNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) *arbitrum_rollup_core.ArbRollupCoreNodeConfirmedIterator); ok {
+ r0 = rf(opts, nodeNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreNodeConfirmedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64) error); ok {
+ r1 = rf(opts, nodeNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_FilterNodeConfirmed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterNodeConfirmed'
+type ArbRollupCoreInterface_FilterNodeConfirmed_Call struct {
+ *mock.Call
+}
+
+// FilterNodeConfirmed is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nodeNum []uint64
+func (_e *ArbRollupCoreInterface_Expecter) FilterNodeConfirmed(opts interface{}, nodeNum interface{}) *ArbRollupCoreInterface_FilterNodeConfirmed_Call {
+ return &ArbRollupCoreInterface_FilterNodeConfirmed_Call{Call: _e.mock.On("FilterNodeConfirmed", opts, nodeNum)}
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeConfirmed_Call) Run(run func(opts *bind.FilterOpts, nodeNum []uint64)) *ArbRollupCoreInterface_FilterNodeConfirmed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeConfirmed_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreNodeConfirmedIterator, _a1 error) *ArbRollupCoreInterface_FilterNodeConfirmed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeConfirmed_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64) (*arbitrum_rollup_core.ArbRollupCoreNodeConfirmedIterator, error)) *ArbRollupCoreInterface_FilterNodeConfirmed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterNodeCreated provides a mock function with given fields: opts, nodeNum, parentNodeHash, nodeHash
+func (_m *ArbRollupCoreInterface) FilterNodeCreated(opts *bind.FilterOpts, nodeNum []uint64, parentNodeHash [][32]byte, nodeHash [][32]byte) (*arbitrum_rollup_core.ArbRollupCoreNodeCreatedIterator, error) {
+ ret := _m.Called(opts, nodeNum, parentNodeHash, nodeHash)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterNodeCreated")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreNodeCreatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte, [][32]byte) (*arbitrum_rollup_core.ArbRollupCoreNodeCreatedIterator, error)); ok {
+ return rf(opts, nodeNum, parentNodeHash, nodeHash)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64, [][32]byte, [][32]byte) *arbitrum_rollup_core.ArbRollupCoreNodeCreatedIterator); ok {
+ r0 = rf(opts, nodeNum, parentNodeHash, nodeHash)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreNodeCreatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64, [][32]byte, [][32]byte) error); ok {
+ r1 = rf(opts, nodeNum, parentNodeHash, nodeHash)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_FilterNodeCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterNodeCreated'
+type ArbRollupCoreInterface_FilterNodeCreated_Call struct {
+ *mock.Call
+}
+
+// FilterNodeCreated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nodeNum []uint64
+// - parentNodeHash [][32]byte
+// - nodeHash [][32]byte
+func (_e *ArbRollupCoreInterface_Expecter) FilterNodeCreated(opts interface{}, nodeNum interface{}, parentNodeHash interface{}, nodeHash interface{}) *ArbRollupCoreInterface_FilterNodeCreated_Call {
+ return &ArbRollupCoreInterface_FilterNodeCreated_Call{Call: _e.mock.On("FilterNodeCreated", opts, nodeNum, parentNodeHash, nodeHash)}
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeCreated_Call) Run(run func(opts *bind.FilterOpts, nodeNum []uint64, parentNodeHash [][32]byte, nodeHash [][32]byte)) *ArbRollupCoreInterface_FilterNodeCreated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64), args[2].([][32]byte), args[3].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeCreated_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreNodeCreatedIterator, _a1 error) *ArbRollupCoreInterface_FilterNodeCreated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeCreated_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64, [][32]byte, [][32]byte) (*arbitrum_rollup_core.ArbRollupCoreNodeCreatedIterator, error)) *ArbRollupCoreInterface_FilterNodeCreated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterNodeRejected provides a mock function with given fields: opts, nodeNum
+func (_m *ArbRollupCoreInterface) FilterNodeRejected(opts *bind.FilterOpts, nodeNum []uint64) (*arbitrum_rollup_core.ArbRollupCoreNodeRejectedIterator, error) {
+ ret := _m.Called(opts, nodeNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterNodeRejected")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreNodeRejectedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*arbitrum_rollup_core.ArbRollupCoreNodeRejectedIterator, error)); ok {
+ return rf(opts, nodeNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) *arbitrum_rollup_core.ArbRollupCoreNodeRejectedIterator); ok {
+ r0 = rf(opts, nodeNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreNodeRejectedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64) error); ok {
+ r1 = rf(opts, nodeNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_FilterNodeRejected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterNodeRejected'
+type ArbRollupCoreInterface_FilterNodeRejected_Call struct {
+ *mock.Call
+}
+
+// FilterNodeRejected is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - nodeNum []uint64
+func (_e *ArbRollupCoreInterface_Expecter) FilterNodeRejected(opts interface{}, nodeNum interface{}) *ArbRollupCoreInterface_FilterNodeRejected_Call {
+ return &ArbRollupCoreInterface_FilterNodeRejected_Call{Call: _e.mock.On("FilterNodeRejected", opts, nodeNum)}
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeRejected_Call) Run(run func(opts *bind.FilterOpts, nodeNum []uint64)) *ArbRollupCoreInterface_FilterNodeRejected_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeRejected_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreNodeRejectedIterator, _a1 error) *ArbRollupCoreInterface_FilterNodeRejected_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterNodeRejected_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64) (*arbitrum_rollup_core.ArbRollupCoreNodeRejectedIterator, error)) *ArbRollupCoreInterface_FilterNodeRejected_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterRollupChallengeStarted provides a mock function with given fields: opts, challengeIndex
+func (_m *ArbRollupCoreInterface) FilterRollupChallengeStarted(opts *bind.FilterOpts, challengeIndex []uint64) (*arbitrum_rollup_core.ArbRollupCoreRollupChallengeStartedIterator, error) {
+ ret := _m.Called(opts, challengeIndex)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterRollupChallengeStarted")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStartedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*arbitrum_rollup_core.ArbRollupCoreRollupChallengeStartedIterator, error)); ok {
+ return rf(opts, challengeIndex)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStartedIterator); ok {
+ r0 = rf(opts, challengeIndex)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreRollupChallengeStartedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []uint64) error); ok {
+ r1 = rf(opts, challengeIndex)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_FilterRollupChallengeStarted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterRollupChallengeStarted'
+type ArbRollupCoreInterface_FilterRollupChallengeStarted_Call struct {
+ *mock.Call
+}
+
+// FilterRollupChallengeStarted is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - challengeIndex []uint64
+func (_e *ArbRollupCoreInterface_Expecter) FilterRollupChallengeStarted(opts interface{}, challengeIndex interface{}) *ArbRollupCoreInterface_FilterRollupChallengeStarted_Call {
+ return &ArbRollupCoreInterface_FilterRollupChallengeStarted_Call{Call: _e.mock.On("FilterRollupChallengeStarted", opts, challengeIndex)}
+}
+
+func (_c *ArbRollupCoreInterface_FilterRollupChallengeStarted_Call) Run(run func(opts *bind.FilterOpts, challengeIndex []uint64)) *ArbRollupCoreInterface_FilterRollupChallengeStarted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterRollupChallengeStarted_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStartedIterator, _a1 error) *ArbRollupCoreInterface_FilterRollupChallengeStarted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterRollupChallengeStarted_Call) RunAndReturn(run func(*bind.FilterOpts, []uint64) (*arbitrum_rollup_core.ArbRollupCoreRollupChallengeStartedIterator, error)) *ArbRollupCoreInterface_FilterRollupChallengeStarted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterRollupInitialized provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) FilterRollupInitialized(opts *bind.FilterOpts) (*arbitrum_rollup_core.ArbRollupCoreRollupInitializedIterator, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterRollupInitialized")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreRollupInitializedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*arbitrum_rollup_core.ArbRollupCoreRollupInitializedIterator, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts) *arbitrum_rollup_core.ArbRollupCoreRollupInitializedIterator); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreRollupInitializedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_FilterRollupInitialized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterRollupInitialized'
+type ArbRollupCoreInterface_FilterRollupInitialized_Call struct {
+ *mock.Call
+}
+
+// FilterRollupInitialized is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+func (_e *ArbRollupCoreInterface_Expecter) FilterRollupInitialized(opts interface{}) *ArbRollupCoreInterface_FilterRollupInitialized_Call {
+ return &ArbRollupCoreInterface_FilterRollupInitialized_Call{Call: _e.mock.On("FilterRollupInitialized", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_FilterRollupInitialized_Call) Run(run func(opts *bind.FilterOpts)) *ArbRollupCoreInterface_FilterRollupInitialized_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterRollupInitialized_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreRollupInitializedIterator, _a1 error) *ArbRollupCoreInterface_FilterRollupInitialized_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterRollupInitialized_Call) RunAndReturn(run func(*bind.FilterOpts) (*arbitrum_rollup_core.ArbRollupCoreRollupInitializedIterator, error)) *ArbRollupCoreInterface_FilterRollupInitialized_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterUserStakeUpdated provides a mock function with given fields: opts, user
+func (_m *ArbRollupCoreInterface) FilterUserStakeUpdated(opts *bind.FilterOpts, user []common.Address) (*arbitrum_rollup_core.ArbRollupCoreUserStakeUpdatedIterator, error) {
+ ret := _m.Called(opts, user)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterUserStakeUpdated")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*arbitrum_rollup_core.ArbRollupCoreUserStakeUpdatedIterator, error)); ok {
+ return rf(opts, user)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdatedIterator); ok {
+ r0 = rf(opts, user)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreUserStakeUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, user)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_FilterUserStakeUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterUserStakeUpdated'
+type ArbRollupCoreInterface_FilterUserStakeUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterUserStakeUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - user []common.Address
+func (_e *ArbRollupCoreInterface_Expecter) FilterUserStakeUpdated(opts interface{}, user interface{}) *ArbRollupCoreInterface_FilterUserStakeUpdated_Call {
+ return &ArbRollupCoreInterface_FilterUserStakeUpdated_Call{Call: _e.mock.On("FilterUserStakeUpdated", opts, user)}
+}
+
+func (_c *ArbRollupCoreInterface_FilterUserStakeUpdated_Call) Run(run func(opts *bind.FilterOpts, user []common.Address)) *ArbRollupCoreInterface_FilterUserStakeUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterUserStakeUpdated_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdatedIterator, _a1 error) *ArbRollupCoreInterface_FilterUserStakeUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterUserStakeUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*arbitrum_rollup_core.ArbRollupCoreUserStakeUpdatedIterator, error)) *ArbRollupCoreInterface_FilterUserStakeUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterUserWithdrawableFundsUpdated provides a mock function with given fields: opts, user
+func (_m *ArbRollupCoreInterface) FilterUserWithdrawableFundsUpdated(opts *bind.FilterOpts, user []common.Address) (*arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdatedIterator, error) {
+ ret := _m.Called(opts, user)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterUserWithdrawableFundsUpdated")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdatedIterator, error)); ok {
+ return rf(opts, user)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdatedIterator); ok {
+ r0 = rf(opts, user)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address) error); ok {
+ r1 = rf(opts, user)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterUserWithdrawableFundsUpdated'
+type ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call struct {
+ *mock.Call
+}
+
+// FilterUserWithdrawableFundsUpdated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - user []common.Address
+func (_e *ArbRollupCoreInterface_Expecter) FilterUserWithdrawableFundsUpdated(opts interface{}, user interface{}) *ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call {
+ return &ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call{Call: _e.mock.On("FilterUserWithdrawableFundsUpdated", opts, user)}
+}
+
+func (_c *ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call) Run(run func(opts *bind.FilterOpts, user []common.Address)) *ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdatedIterator, _a1 error) *ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address) (*arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdatedIterator, error)) *ArbRollupCoreInterface_FilterUserWithdrawableFundsUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FirstUnresolvedNode provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) FirstUnresolvedNode(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FirstUnresolvedNode")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_FirstUnresolvedNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FirstUnresolvedNode'
+type ArbRollupCoreInterface_FirstUnresolvedNode_Call struct {
+ *mock.Call
+}
+
+// FirstUnresolvedNode is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) FirstUnresolvedNode(opts interface{}) *ArbRollupCoreInterface_FirstUnresolvedNode_Call {
+ return &ArbRollupCoreInterface_FirstUnresolvedNode_Call{Call: _e.mock.On("FirstUnresolvedNode", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_FirstUnresolvedNode_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_FirstUnresolvedNode_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FirstUnresolvedNode_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_FirstUnresolvedNode_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_FirstUnresolvedNode_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *ArbRollupCoreInterface_FirstUnresolvedNode_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetNode provides a mock function with given fields: opts, nodeNum
+func (_m *ArbRollupCoreInterface) GetNode(opts *bind.CallOpts, nodeNum uint64) (arbitrum_rollup_core.Node, error) {
+ ret := _m.Called(opts, nodeNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetNode")
+ }
+
+ var r0 arbitrum_rollup_core.Node
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (arbitrum_rollup_core.Node, error)); ok {
+ return rf(opts, nodeNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) arbitrum_rollup_core.Node); ok {
+ r0 = rf(opts, nodeNum)
+ } else {
+ r0 = ret.Get(0).(arbitrum_rollup_core.Node)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, nodeNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_GetNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNode'
+type ArbRollupCoreInterface_GetNode_Call struct {
+ *mock.Call
+}
+
+// GetNode is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - nodeNum uint64
+func (_e *ArbRollupCoreInterface_Expecter) GetNode(opts interface{}, nodeNum interface{}) *ArbRollupCoreInterface_GetNode_Call {
+ return &ArbRollupCoreInterface_GetNode_Call{Call: _e.mock.On("GetNode", opts, nodeNum)}
+}
+
+func (_c *ArbRollupCoreInterface_GetNode_Call) Run(run func(opts *bind.CallOpts, nodeNum uint64)) *ArbRollupCoreInterface_GetNode_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_GetNode_Call) Return(_a0 arbitrum_rollup_core.Node, _a1 error) *ArbRollupCoreInterface_GetNode_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_GetNode_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (arbitrum_rollup_core.Node, error)) *ArbRollupCoreInterface_GetNode_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetNodeCreationBlockForLogLookup provides a mock function with given fields: opts, nodeNum
+func (_m *ArbRollupCoreInterface) GetNodeCreationBlockForLogLookup(opts *bind.CallOpts, nodeNum uint64) (*big.Int, error) {
+ ret := _m.Called(opts, nodeNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetNodeCreationBlockForLogLookup")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (*big.Int, error)); ok {
+ return rf(opts, nodeNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) *big.Int); ok {
+ r0 = rf(opts, nodeNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, nodeNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNodeCreationBlockForLogLookup'
+type ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call struct {
+ *mock.Call
+}
+
+// GetNodeCreationBlockForLogLookup is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - nodeNum uint64
+func (_e *ArbRollupCoreInterface_Expecter) GetNodeCreationBlockForLogLookup(opts interface{}, nodeNum interface{}) *ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call {
+ return &ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call{Call: _e.mock.On("GetNodeCreationBlockForLogLookup", opts, nodeNum)}
+}
+
+func (_c *ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call) Run(run func(opts *bind.CallOpts, nodeNum uint64)) *ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call) Return(_a0 *big.Int, _a1 error) *ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (*big.Int, error)) *ArbRollupCoreInterface_GetNodeCreationBlockForLogLookup_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStaker provides a mock function with given fields: opts, staker
+func (_m *ArbRollupCoreInterface) GetStaker(opts *bind.CallOpts, staker common.Address) (arbitrum_rollup_core.IRollupCoreStaker, error) {
+ ret := _m.Called(opts, staker)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStaker")
+ }
+
+ var r0 arbitrum_rollup_core.IRollupCoreStaker
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (arbitrum_rollup_core.IRollupCoreStaker, error)); ok {
+ return rf(opts, staker)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) arbitrum_rollup_core.IRollupCoreStaker); ok {
+ r0 = rf(opts, staker)
+ } else {
+ r0 = ret.Get(0).(arbitrum_rollup_core.IRollupCoreStaker)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, staker)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_GetStaker_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStaker'
+type ArbRollupCoreInterface_GetStaker_Call struct {
+ *mock.Call
+}
+
+// GetStaker is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - staker common.Address
+func (_e *ArbRollupCoreInterface_Expecter) GetStaker(opts interface{}, staker interface{}) *ArbRollupCoreInterface_GetStaker_Call {
+ return &ArbRollupCoreInterface_GetStaker_Call{Call: _e.mock.On("GetStaker", opts, staker)}
+}
+
+func (_c *ArbRollupCoreInterface_GetStaker_Call) Run(run func(opts *bind.CallOpts, staker common.Address)) *ArbRollupCoreInterface_GetStaker_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_GetStaker_Call) Return(_a0 arbitrum_rollup_core.IRollupCoreStaker, _a1 error) *ArbRollupCoreInterface_GetStaker_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_GetStaker_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (arbitrum_rollup_core.IRollupCoreStaker, error)) *ArbRollupCoreInterface_GetStaker_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStakerAddress provides a mock function with given fields: opts, stakerNum
+func (_m *ArbRollupCoreInterface) GetStakerAddress(opts *bind.CallOpts, stakerNum uint64) (common.Address, error) {
+ ret := _m.Called(opts, stakerNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStakerAddress")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (common.Address, error)); ok {
+ return rf(opts, stakerNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) common.Address); ok {
+ r0 = rf(opts, stakerNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, stakerNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_GetStakerAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStakerAddress'
+type ArbRollupCoreInterface_GetStakerAddress_Call struct {
+ *mock.Call
+}
+
+// GetStakerAddress is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - stakerNum uint64
+func (_e *ArbRollupCoreInterface_Expecter) GetStakerAddress(opts interface{}, stakerNum interface{}) *ArbRollupCoreInterface_GetStakerAddress_Call {
+ return &ArbRollupCoreInterface_GetStakerAddress_Call{Call: _e.mock.On("GetStakerAddress", opts, stakerNum)}
+}
+
+func (_c *ArbRollupCoreInterface_GetStakerAddress_Call) Run(run func(opts *bind.CallOpts, stakerNum uint64)) *ArbRollupCoreInterface_GetStakerAddress_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_GetStakerAddress_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_GetStakerAddress_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_GetStakerAddress_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (common.Address, error)) *ArbRollupCoreInterface_GetStakerAddress_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsStaked provides a mock function with given fields: opts, staker
+func (_m *ArbRollupCoreInterface) IsStaked(opts *bind.CallOpts, staker common.Address) (bool, error) {
+ ret := _m.Called(opts, staker)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsStaked")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (bool, error)); ok {
+ return rf(opts, staker)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) bool); ok {
+ r0 = rf(opts, staker)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, staker)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_IsStaked_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsStaked'
+type ArbRollupCoreInterface_IsStaked_Call struct {
+ *mock.Call
+}
+
+// IsStaked is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - staker common.Address
+func (_e *ArbRollupCoreInterface_Expecter) IsStaked(opts interface{}, staker interface{}) *ArbRollupCoreInterface_IsStaked_Call {
+ return &ArbRollupCoreInterface_IsStaked_Call{Call: _e.mock.On("IsStaked", opts, staker)}
+}
+
+func (_c *ArbRollupCoreInterface_IsStaked_Call) Run(run func(opts *bind.CallOpts, staker common.Address)) *ArbRollupCoreInterface_IsStaked_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_IsStaked_Call) Return(_a0 bool, _a1 error) *ArbRollupCoreInterface_IsStaked_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_IsStaked_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (bool, error)) *ArbRollupCoreInterface_IsStaked_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsValidator provides a mock function with given fields: opts, arg0
+func (_m *ArbRollupCoreInterface) IsValidator(opts *bind.CallOpts, arg0 common.Address) (bool, error) {
+ ret := _m.Called(opts, arg0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsValidator")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (bool, error)); ok {
+ return rf(opts, arg0)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) bool); ok {
+ r0 = rf(opts, arg0)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, arg0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_IsValidator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsValidator'
+type ArbRollupCoreInterface_IsValidator_Call struct {
+ *mock.Call
+}
+
+// IsValidator is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - arg0 common.Address
+func (_e *ArbRollupCoreInterface_Expecter) IsValidator(opts interface{}, arg0 interface{}) *ArbRollupCoreInterface_IsValidator_Call {
+ return &ArbRollupCoreInterface_IsValidator_Call{Call: _e.mock.On("IsValidator", opts, arg0)}
+}
+
+func (_c *ArbRollupCoreInterface_IsValidator_Call) Run(run func(opts *bind.CallOpts, arg0 common.Address)) *ArbRollupCoreInterface_IsValidator_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_IsValidator_Call) Return(_a0 bool, _a1 error) *ArbRollupCoreInterface_IsValidator_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_IsValidator_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (bool, error)) *ArbRollupCoreInterface_IsValidator_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsZombie provides a mock function with given fields: opts, staker
+func (_m *ArbRollupCoreInterface) IsZombie(opts *bind.CallOpts, staker common.Address) (bool, error) {
+ ret := _m.Called(opts, staker)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsZombie")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (bool, error)); ok {
+ return rf(opts, staker)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) bool); ok {
+ r0 = rf(opts, staker)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, staker)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_IsZombie_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsZombie'
+type ArbRollupCoreInterface_IsZombie_Call struct {
+ *mock.Call
+}
+
+// IsZombie is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - staker common.Address
+func (_e *ArbRollupCoreInterface_Expecter) IsZombie(opts interface{}, staker interface{}) *ArbRollupCoreInterface_IsZombie_Call {
+ return &ArbRollupCoreInterface_IsZombie_Call{Call: _e.mock.On("IsZombie", opts, staker)}
+}
+
+func (_c *ArbRollupCoreInterface_IsZombie_Call) Run(run func(opts *bind.CallOpts, staker common.Address)) *ArbRollupCoreInterface_IsZombie_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_IsZombie_Call) Return(_a0 bool, _a1 error) *ArbRollupCoreInterface_IsZombie_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_IsZombie_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (bool, error)) *ArbRollupCoreInterface_IsZombie_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LastStakeBlock provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) LastStakeBlock(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LastStakeBlock")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_LastStakeBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LastStakeBlock'
+type ArbRollupCoreInterface_LastStakeBlock_Call struct {
+ *mock.Call
+}
+
+// LastStakeBlock is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) LastStakeBlock(opts interface{}) *ArbRollupCoreInterface_LastStakeBlock_Call {
+ return &ArbRollupCoreInterface_LastStakeBlock_Call{Call: _e.mock.On("LastStakeBlock", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_LastStakeBlock_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_LastStakeBlock_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LastStakeBlock_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_LastStakeBlock_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LastStakeBlock_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *ArbRollupCoreInterface_LastStakeBlock_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestConfirmed provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) LatestConfirmed(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestConfirmed")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_LatestConfirmed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestConfirmed'
+type ArbRollupCoreInterface_LatestConfirmed_Call struct {
+ *mock.Call
+}
+
+// LatestConfirmed is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) LatestConfirmed(opts interface{}) *ArbRollupCoreInterface_LatestConfirmed_Call {
+ return &ArbRollupCoreInterface_LatestConfirmed_Call{Call: _e.mock.On("LatestConfirmed", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_LatestConfirmed_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_LatestConfirmed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LatestConfirmed_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_LatestConfirmed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LatestConfirmed_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *ArbRollupCoreInterface_LatestConfirmed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestNodeCreated provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) LatestNodeCreated(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestNodeCreated")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_LatestNodeCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestNodeCreated'
+type ArbRollupCoreInterface_LatestNodeCreated_Call struct {
+ *mock.Call
+}
+
+// LatestNodeCreated is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) LatestNodeCreated(opts interface{}) *ArbRollupCoreInterface_LatestNodeCreated_Call {
+ return &ArbRollupCoreInterface_LatestNodeCreated_Call{Call: _e.mock.On("LatestNodeCreated", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_LatestNodeCreated_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_LatestNodeCreated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LatestNodeCreated_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_LatestNodeCreated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LatestNodeCreated_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *ArbRollupCoreInterface_LatestNodeCreated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestStakedNode provides a mock function with given fields: opts, staker
+func (_m *ArbRollupCoreInterface) LatestStakedNode(opts *bind.CallOpts, staker common.Address) (uint64, error) {
+ ret := _m.Called(opts, staker)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestStakedNode")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (uint64, error)); ok {
+ return rf(opts, staker)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) uint64); ok {
+ r0 = rf(opts, staker)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, staker)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_LatestStakedNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestStakedNode'
+type ArbRollupCoreInterface_LatestStakedNode_Call struct {
+ *mock.Call
+}
+
+// LatestStakedNode is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - staker common.Address
+func (_e *ArbRollupCoreInterface_Expecter) LatestStakedNode(opts interface{}, staker interface{}) *ArbRollupCoreInterface_LatestStakedNode_Call {
+ return &ArbRollupCoreInterface_LatestStakedNode_Call{Call: _e.mock.On("LatestStakedNode", opts, staker)}
+}
+
+func (_c *ArbRollupCoreInterface_LatestStakedNode_Call) Run(run func(opts *bind.CallOpts, staker common.Address)) *ArbRollupCoreInterface_LatestStakedNode_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LatestStakedNode_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_LatestStakedNode_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LatestStakedNode_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (uint64, error)) *ArbRollupCoreInterface_LatestStakedNode_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LoserStakeEscrow provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) LoserStakeEscrow(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LoserStakeEscrow")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_LoserStakeEscrow_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoserStakeEscrow'
+type ArbRollupCoreInterface_LoserStakeEscrow_Call struct {
+ *mock.Call
+}
+
+// LoserStakeEscrow is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) LoserStakeEscrow(opts interface{}) *ArbRollupCoreInterface_LoserStakeEscrow_Call {
+ return &ArbRollupCoreInterface_LoserStakeEscrow_Call{Call: _e.mock.On("LoserStakeEscrow", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_LoserStakeEscrow_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_LoserStakeEscrow_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LoserStakeEscrow_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_LoserStakeEscrow_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_LoserStakeEscrow_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbRollupCoreInterface_LoserStakeEscrow_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// MinimumAssertionPeriod provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) MinimumAssertionPeriod(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for MinimumAssertionPeriod")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_MinimumAssertionPeriod_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MinimumAssertionPeriod'
+type ArbRollupCoreInterface_MinimumAssertionPeriod_Call struct {
+ *mock.Call
+}
+
+// MinimumAssertionPeriod is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) MinimumAssertionPeriod(opts interface{}) *ArbRollupCoreInterface_MinimumAssertionPeriod_Call {
+ return &ArbRollupCoreInterface_MinimumAssertionPeriod_Call{Call: _e.mock.On("MinimumAssertionPeriod", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_MinimumAssertionPeriod_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_MinimumAssertionPeriod_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_MinimumAssertionPeriod_Call) Return(_a0 *big.Int, _a1 error) *ArbRollupCoreInterface_MinimumAssertionPeriod_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_MinimumAssertionPeriod_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbRollupCoreInterface_MinimumAssertionPeriod_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NodeHasStaker provides a mock function with given fields: opts, nodeNum, staker
+func (_m *ArbRollupCoreInterface) NodeHasStaker(opts *bind.CallOpts, nodeNum uint64, staker common.Address) (bool, error) {
+ ret := _m.Called(opts, nodeNum, staker)
+
+ if len(ret) == 0 {
+ panic("no return value specified for NodeHasStaker")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address) (bool, error)); ok {
+ return rf(opts, nodeNum, staker)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, common.Address) bool); ok {
+ r0 = rf(opts, nodeNum, staker)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64, common.Address) error); ok {
+ r1 = rf(opts, nodeNum, staker)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_NodeHasStaker_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NodeHasStaker'
+type ArbRollupCoreInterface_NodeHasStaker_Call struct {
+ *mock.Call
+}
+
+// NodeHasStaker is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - nodeNum uint64
+// - staker common.Address
+func (_e *ArbRollupCoreInterface_Expecter) NodeHasStaker(opts interface{}, nodeNum interface{}, staker interface{}) *ArbRollupCoreInterface_NodeHasStaker_Call {
+ return &ArbRollupCoreInterface_NodeHasStaker_Call{Call: _e.mock.On("NodeHasStaker", opts, nodeNum, staker)}
+}
+
+func (_c *ArbRollupCoreInterface_NodeHasStaker_Call) Run(run func(opts *bind.CallOpts, nodeNum uint64, staker common.Address)) *ArbRollupCoreInterface_NodeHasStaker_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64), args[2].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_NodeHasStaker_Call) Return(_a0 bool, _a1 error) *ArbRollupCoreInterface_NodeHasStaker_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_NodeHasStaker_Call) RunAndReturn(run func(*bind.CallOpts, uint64, common.Address) (bool, error)) *ArbRollupCoreInterface_NodeHasStaker_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Outbox provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) Outbox(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Outbox")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_Outbox_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Outbox'
+type ArbRollupCoreInterface_Outbox_Call struct {
+ *mock.Call
+}
+
+// Outbox is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) Outbox(opts interface{}) *ArbRollupCoreInterface_Outbox_Call {
+ return &ArbRollupCoreInterface_Outbox_Call{Call: _e.mock.On("Outbox", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_Outbox_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_Outbox_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_Outbox_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_Outbox_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_Outbox_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbRollupCoreInterface_Outbox_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *ArbRollupCoreInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type ArbRollupCoreInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbRollupCoreInterface_Expecter) ParseLog(log interface{}) *ArbRollupCoreInterface_ParseLog_Call {
+ return &ArbRollupCoreInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *ArbRollupCoreInterface_ParseLog_Call) Run(run func(log types.Log)) *ArbRollupCoreInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *ArbRollupCoreInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *ArbRollupCoreInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseNodeConfirmed provides a mock function with given fields: log
+func (_m *ArbRollupCoreInterface) ParseNodeConfirmed(log types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseNodeConfirmed")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreNodeConfirmed)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ParseNodeConfirmed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseNodeConfirmed'
+type ArbRollupCoreInterface_ParseNodeConfirmed_Call struct {
+ *mock.Call
+}
+
+// ParseNodeConfirmed is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbRollupCoreInterface_Expecter) ParseNodeConfirmed(log interface{}) *ArbRollupCoreInterface_ParseNodeConfirmed_Call {
+ return &ArbRollupCoreInterface_ParseNodeConfirmed_Call{Call: _e.mock.On("ParseNodeConfirmed", log)}
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeConfirmed_Call) Run(run func(log types.Log)) *ArbRollupCoreInterface_ParseNodeConfirmed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeConfirmed_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, _a1 error) *ArbRollupCoreInterface_ParseNodeConfirmed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeConfirmed_Call) RunAndReturn(run func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, error)) *ArbRollupCoreInterface_ParseNodeConfirmed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseNodeCreated provides a mock function with given fields: log
+func (_m *ArbRollupCoreInterface) ParseNodeCreated(log types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeCreated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseNodeCreated")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreNodeCreated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeCreated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_rollup_core.ArbRollupCoreNodeCreated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreNodeCreated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ParseNodeCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseNodeCreated'
+type ArbRollupCoreInterface_ParseNodeCreated_Call struct {
+ *mock.Call
+}
+
+// ParseNodeCreated is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbRollupCoreInterface_Expecter) ParseNodeCreated(log interface{}) *ArbRollupCoreInterface_ParseNodeCreated_Call {
+ return &ArbRollupCoreInterface_ParseNodeCreated_Call{Call: _e.mock.On("ParseNodeCreated", log)}
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeCreated_Call) Run(run func(log types.Log)) *ArbRollupCoreInterface_ParseNodeCreated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeCreated_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreNodeCreated, _a1 error) *ArbRollupCoreInterface_ParseNodeCreated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeCreated_Call) RunAndReturn(run func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeCreated, error)) *ArbRollupCoreInterface_ParseNodeCreated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseNodeRejected provides a mock function with given fields: log
+func (_m *ArbRollupCoreInterface) ParseNodeRejected(log types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeRejected, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseNodeRejected")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreNodeRejected
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeRejected, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_rollup_core.ArbRollupCoreNodeRejected); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreNodeRejected)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ParseNodeRejected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseNodeRejected'
+type ArbRollupCoreInterface_ParseNodeRejected_Call struct {
+ *mock.Call
+}
+
+// ParseNodeRejected is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbRollupCoreInterface_Expecter) ParseNodeRejected(log interface{}) *ArbRollupCoreInterface_ParseNodeRejected_Call {
+ return &ArbRollupCoreInterface_ParseNodeRejected_Call{Call: _e.mock.On("ParseNodeRejected", log)}
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeRejected_Call) Run(run func(log types.Log)) *ArbRollupCoreInterface_ParseNodeRejected_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeRejected_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreNodeRejected, _a1 error) *ArbRollupCoreInterface_ParseNodeRejected_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseNodeRejected_Call) RunAndReturn(run func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreNodeRejected, error)) *ArbRollupCoreInterface_ParseNodeRejected_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseRollupChallengeStarted provides a mock function with given fields: log
+func (_m *ArbRollupCoreInterface) ParseRollupChallengeStarted(log types.Log) (*arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseRollupChallengeStarted")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ParseRollupChallengeStarted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseRollupChallengeStarted'
+type ArbRollupCoreInterface_ParseRollupChallengeStarted_Call struct {
+ *mock.Call
+}
+
+// ParseRollupChallengeStarted is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbRollupCoreInterface_Expecter) ParseRollupChallengeStarted(log interface{}) *ArbRollupCoreInterface_ParseRollupChallengeStarted_Call {
+ return &ArbRollupCoreInterface_ParseRollupChallengeStarted_Call{Call: _e.mock.On("ParseRollupChallengeStarted", log)}
+}
+
+func (_c *ArbRollupCoreInterface_ParseRollupChallengeStarted_Call) Run(run func(log types.Log)) *ArbRollupCoreInterface_ParseRollupChallengeStarted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseRollupChallengeStarted_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, _a1 error) *ArbRollupCoreInterface_ParseRollupChallengeStarted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseRollupChallengeStarted_Call) RunAndReturn(run func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, error)) *ArbRollupCoreInterface_ParseRollupChallengeStarted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseRollupInitialized provides a mock function with given fields: log
+func (_m *ArbRollupCoreInterface) ParseRollupInitialized(log types.Log) (*arbitrum_rollup_core.ArbRollupCoreRollupInitialized, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseRollupInitialized")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreRollupInitialized
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreRollupInitialized, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_rollup_core.ArbRollupCoreRollupInitialized); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreRollupInitialized)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ParseRollupInitialized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseRollupInitialized'
+type ArbRollupCoreInterface_ParseRollupInitialized_Call struct {
+ *mock.Call
+}
+
+// ParseRollupInitialized is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbRollupCoreInterface_Expecter) ParseRollupInitialized(log interface{}) *ArbRollupCoreInterface_ParseRollupInitialized_Call {
+ return &ArbRollupCoreInterface_ParseRollupInitialized_Call{Call: _e.mock.On("ParseRollupInitialized", log)}
+}
+
+func (_c *ArbRollupCoreInterface_ParseRollupInitialized_Call) Run(run func(log types.Log)) *ArbRollupCoreInterface_ParseRollupInitialized_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseRollupInitialized_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreRollupInitialized, _a1 error) *ArbRollupCoreInterface_ParseRollupInitialized_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseRollupInitialized_Call) RunAndReturn(run func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreRollupInitialized, error)) *ArbRollupCoreInterface_ParseRollupInitialized_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseUserStakeUpdated provides a mock function with given fields: log
+func (_m *ArbRollupCoreInterface) ParseUserStakeUpdated(log types.Log) (*arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseUserStakeUpdated")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ParseUserStakeUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseUserStakeUpdated'
+type ArbRollupCoreInterface_ParseUserStakeUpdated_Call struct {
+ *mock.Call
+}
+
+// ParseUserStakeUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbRollupCoreInterface_Expecter) ParseUserStakeUpdated(log interface{}) *ArbRollupCoreInterface_ParseUserStakeUpdated_Call {
+ return &ArbRollupCoreInterface_ParseUserStakeUpdated_Call{Call: _e.mock.On("ParseUserStakeUpdated", log)}
+}
+
+func (_c *ArbRollupCoreInterface_ParseUserStakeUpdated_Call) Run(run func(log types.Log)) *ArbRollupCoreInterface_ParseUserStakeUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseUserStakeUpdated_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, _a1 error) *ArbRollupCoreInterface_ParseUserStakeUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseUserStakeUpdated_Call) RunAndReturn(run func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, error)) *ArbRollupCoreInterface_ParseUserStakeUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseUserWithdrawableFundsUpdated provides a mock function with given fields: log
+func (_m *ArbRollupCoreInterface) ParseUserWithdrawableFundsUpdated(log types.Log) (*arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseUserWithdrawableFundsUpdated")
+ }
+
+ var r0 *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseUserWithdrawableFundsUpdated'
+type ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call struct {
+ *mock.Call
+}
+
+// ParseUserWithdrawableFundsUpdated is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbRollupCoreInterface_Expecter) ParseUserWithdrawableFundsUpdated(log interface{}) *ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call {
+ return &ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call{Call: _e.mock.On("ParseUserWithdrawableFundsUpdated", log)}
+}
+
+func (_c *ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call) Run(run func(log types.Log)) *ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call) Return(_a0 *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, _a1 error) *ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call) RunAndReturn(run func(types.Log) (*arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, error)) *ArbRollupCoreInterface_ParseUserWithdrawableFundsUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// RollupEventInbox provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) RollupEventInbox(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RollupEventInbox")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_RollupEventInbox_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RollupEventInbox'
+type ArbRollupCoreInterface_RollupEventInbox_Call struct {
+ *mock.Call
+}
+
+// RollupEventInbox is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) RollupEventInbox(opts interface{}) *ArbRollupCoreInterface_RollupEventInbox_Call {
+ return &ArbRollupCoreInterface_RollupEventInbox_Call{Call: _e.mock.On("RollupEventInbox", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_RollupEventInbox_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_RollupEventInbox_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_RollupEventInbox_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_RollupEventInbox_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_RollupEventInbox_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbRollupCoreInterface_RollupEventInbox_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SequencerInbox provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) SequencerInbox(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SequencerInbox")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_SequencerInbox_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SequencerInbox'
+type ArbRollupCoreInterface_SequencerInbox_Call struct {
+ *mock.Call
+}
+
+// SequencerInbox is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) SequencerInbox(opts interface{}) *ArbRollupCoreInterface_SequencerInbox_Call {
+ return &ArbRollupCoreInterface_SequencerInbox_Call{Call: _e.mock.On("SequencerInbox", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_SequencerInbox_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_SequencerInbox_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_SequencerInbox_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_SequencerInbox_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_SequencerInbox_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbRollupCoreInterface_SequencerInbox_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// StakeToken provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) StakeToken(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for StakeToken")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_StakeToken_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StakeToken'
+type ArbRollupCoreInterface_StakeToken_Call struct {
+ *mock.Call
+}
+
+// StakeToken is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) StakeToken(opts interface{}) *ArbRollupCoreInterface_StakeToken_Call {
+ return &ArbRollupCoreInterface_StakeToken_Call{Call: _e.mock.On("StakeToken", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_StakeToken_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_StakeToken_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_StakeToken_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_StakeToken_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_StakeToken_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbRollupCoreInterface_StakeToken_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// StakerCount provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) StakerCount(opts *bind.CallOpts) (uint64, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for StakerCount")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint64); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_StakerCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StakerCount'
+type ArbRollupCoreInterface_StakerCount_Call struct {
+ *mock.Call
+}
+
+// StakerCount is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) StakerCount(opts interface{}) *ArbRollupCoreInterface_StakerCount_Call {
+ return &ArbRollupCoreInterface_StakerCount_Call{Call: _e.mock.On("StakerCount", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_StakerCount_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_StakerCount_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_StakerCount_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_StakerCount_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_StakerCount_Call) RunAndReturn(run func(*bind.CallOpts) (uint64, error)) *ArbRollupCoreInterface_StakerCount_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ValidatorWhitelistDisabled provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) ValidatorWhitelistDisabled(opts *bind.CallOpts) (bool, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ValidatorWhitelistDisabled")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) bool); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ValidatorWhitelistDisabled'
+type ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call struct {
+ *mock.Call
+}
+
+// ValidatorWhitelistDisabled is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) ValidatorWhitelistDisabled(opts interface{}) *ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call {
+ return &ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call{Call: _e.mock.On("ValidatorWhitelistDisabled", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call) Return(_a0 bool, _a1 error) *ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call) RunAndReturn(run func(*bind.CallOpts) (bool, error)) *ArbRollupCoreInterface_ValidatorWhitelistDisabled_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WasmModuleRoot provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) WasmModuleRoot(opts *bind.CallOpts) ([32]byte, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WasmModuleRoot")
+ }
+
+ var r0 [32]byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) [32]byte); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([32]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WasmModuleRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WasmModuleRoot'
+type ArbRollupCoreInterface_WasmModuleRoot_Call struct {
+ *mock.Call
+}
+
+// WasmModuleRoot is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) WasmModuleRoot(opts interface{}) *ArbRollupCoreInterface_WasmModuleRoot_Call {
+ return &ArbRollupCoreInterface_WasmModuleRoot_Call{Call: _e.mock.On("WasmModuleRoot", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_WasmModuleRoot_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_WasmModuleRoot_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WasmModuleRoot_Call) Return(_a0 [32]byte, _a1 error) *ArbRollupCoreInterface_WasmModuleRoot_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WasmModuleRoot_Call) RunAndReturn(run func(*bind.CallOpts) ([32]byte, error)) *ArbRollupCoreInterface_WasmModuleRoot_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchNodeConfirmed provides a mock function with given fields: opts, sink, nodeNum
+func (_m *ArbRollupCoreInterface) WatchNodeConfirmed(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, nodeNum []uint64) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nodeNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchNodeConfirmed")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, []uint64) (event.Subscription, error)); ok {
+ return rf(opts, sink, nodeNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, []uint64) event.Subscription); ok {
+ r0 = rf(opts, sink, nodeNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, []uint64) error); ok {
+ r1 = rf(opts, sink, nodeNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WatchNodeConfirmed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchNodeConfirmed'
+type ArbRollupCoreInterface_WatchNodeConfirmed_Call struct {
+ *mock.Call
+}
+
+// WatchNodeConfirmed is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed
+// - nodeNum []uint64
+func (_e *ArbRollupCoreInterface_Expecter) WatchNodeConfirmed(opts interface{}, sink interface{}, nodeNum interface{}) *ArbRollupCoreInterface_WatchNodeConfirmed_Call {
+ return &ArbRollupCoreInterface_WatchNodeConfirmed_Call{Call: _e.mock.On("WatchNodeConfirmed", opts, sink, nodeNum)}
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeConfirmed_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, nodeNum []uint64)) *ArbRollupCoreInterface_WatchNodeConfirmed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed), args[2].([]uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeConfirmed_Call) Return(_a0 event.Subscription, _a1 error) *ArbRollupCoreInterface_WatchNodeConfirmed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeConfirmed_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeConfirmed, []uint64) (event.Subscription, error)) *ArbRollupCoreInterface_WatchNodeConfirmed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchNodeCreated provides a mock function with given fields: opts, sink, nodeNum, parentNodeHash, nodeHash
+func (_m *ArbRollupCoreInterface) WatchNodeCreated(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeCreated, nodeNum []uint64, parentNodeHash [][32]byte, nodeHash [][32]byte) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nodeNum, parentNodeHash, nodeHash)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchNodeCreated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeCreated, []uint64, [][32]byte, [][32]byte) (event.Subscription, error)); ok {
+ return rf(opts, sink, nodeNum, parentNodeHash, nodeHash)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeCreated, []uint64, [][32]byte, [][32]byte) event.Subscription); ok {
+ r0 = rf(opts, sink, nodeNum, parentNodeHash, nodeHash)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeCreated, []uint64, [][32]byte, [][32]byte) error); ok {
+ r1 = rf(opts, sink, nodeNum, parentNodeHash, nodeHash)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WatchNodeCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchNodeCreated'
+type ArbRollupCoreInterface_WatchNodeCreated_Call struct {
+ *mock.Call
+}
+
+// WatchNodeCreated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeCreated
+// - nodeNum []uint64
+// - parentNodeHash [][32]byte
+// - nodeHash [][32]byte
+func (_e *ArbRollupCoreInterface_Expecter) WatchNodeCreated(opts interface{}, sink interface{}, nodeNum interface{}, parentNodeHash interface{}, nodeHash interface{}) *ArbRollupCoreInterface_WatchNodeCreated_Call {
+ return &ArbRollupCoreInterface_WatchNodeCreated_Call{Call: _e.mock.On("WatchNodeCreated", opts, sink, nodeNum, parentNodeHash, nodeHash)}
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeCreated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeCreated, nodeNum []uint64, parentNodeHash [][32]byte, nodeHash [][32]byte)) *ArbRollupCoreInterface_WatchNodeCreated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_rollup_core.ArbRollupCoreNodeCreated), args[2].([]uint64), args[3].([][32]byte), args[4].([][32]byte))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeCreated_Call) Return(_a0 event.Subscription, _a1 error) *ArbRollupCoreInterface_WatchNodeCreated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeCreated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeCreated, []uint64, [][32]byte, [][32]byte) (event.Subscription, error)) *ArbRollupCoreInterface_WatchNodeCreated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchNodeRejected provides a mock function with given fields: opts, sink, nodeNum
+func (_m *ArbRollupCoreInterface) WatchNodeRejected(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeRejected, nodeNum []uint64) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, nodeNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchNodeRejected")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeRejected, []uint64) (event.Subscription, error)); ok {
+ return rf(opts, sink, nodeNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeRejected, []uint64) event.Subscription); ok {
+ r0 = rf(opts, sink, nodeNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeRejected, []uint64) error); ok {
+ r1 = rf(opts, sink, nodeNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WatchNodeRejected_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchNodeRejected'
+type ArbRollupCoreInterface_WatchNodeRejected_Call struct {
+ *mock.Call
+}
+
+// WatchNodeRejected is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeRejected
+// - nodeNum []uint64
+func (_e *ArbRollupCoreInterface_Expecter) WatchNodeRejected(opts interface{}, sink interface{}, nodeNum interface{}) *ArbRollupCoreInterface_WatchNodeRejected_Call {
+ return &ArbRollupCoreInterface_WatchNodeRejected_Call{Call: _e.mock.On("WatchNodeRejected", opts, sink, nodeNum)}
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeRejected_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreNodeRejected, nodeNum []uint64)) *ArbRollupCoreInterface_WatchNodeRejected_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_rollup_core.ArbRollupCoreNodeRejected), args[2].([]uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeRejected_Call) Return(_a0 event.Subscription, _a1 error) *ArbRollupCoreInterface_WatchNodeRejected_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchNodeRejected_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreNodeRejected, []uint64) (event.Subscription, error)) *ArbRollupCoreInterface_WatchNodeRejected_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchRollupChallengeStarted provides a mock function with given fields: opts, sink, challengeIndex
+func (_m *ArbRollupCoreInterface) WatchRollupChallengeStarted(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, challengeIndex []uint64) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, challengeIndex)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchRollupChallengeStarted")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, []uint64) (event.Subscription, error)); ok {
+ return rf(opts, sink, challengeIndex)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, []uint64) event.Subscription); ok {
+ r0 = rf(opts, sink, challengeIndex)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, []uint64) error); ok {
+ r1 = rf(opts, sink, challengeIndex)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WatchRollupChallengeStarted_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchRollupChallengeStarted'
+type ArbRollupCoreInterface_WatchRollupChallengeStarted_Call struct {
+ *mock.Call
+}
+
+// WatchRollupChallengeStarted is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted
+// - challengeIndex []uint64
+func (_e *ArbRollupCoreInterface_Expecter) WatchRollupChallengeStarted(opts interface{}, sink interface{}, challengeIndex interface{}) *ArbRollupCoreInterface_WatchRollupChallengeStarted_Call {
+ return &ArbRollupCoreInterface_WatchRollupChallengeStarted_Call{Call: _e.mock.On("WatchRollupChallengeStarted", opts, sink, challengeIndex)}
+}
+
+func (_c *ArbRollupCoreInterface_WatchRollupChallengeStarted_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, challengeIndex []uint64)) *ArbRollupCoreInterface_WatchRollupChallengeStarted_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted), args[2].([]uint64))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchRollupChallengeStarted_Call) Return(_a0 event.Subscription, _a1 error) *ArbRollupCoreInterface_WatchRollupChallengeStarted_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchRollupChallengeStarted_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreRollupChallengeStarted, []uint64) (event.Subscription, error)) *ArbRollupCoreInterface_WatchRollupChallengeStarted_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchRollupInitialized provides a mock function with given fields: opts, sink
+func (_m *ArbRollupCoreInterface) WatchRollupInitialized(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreRollupInitialized) (event.Subscription, error) {
+ ret := _m.Called(opts, sink)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchRollupInitialized")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreRollupInitialized) (event.Subscription, error)); ok {
+ return rf(opts, sink)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreRollupInitialized) event.Subscription); ok {
+ r0 = rf(opts, sink)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreRollupInitialized) error); ok {
+ r1 = rf(opts, sink)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WatchRollupInitialized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchRollupInitialized'
+type ArbRollupCoreInterface_WatchRollupInitialized_Call struct {
+ *mock.Call
+}
+
+// WatchRollupInitialized is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_rollup_core.ArbRollupCoreRollupInitialized
+func (_e *ArbRollupCoreInterface_Expecter) WatchRollupInitialized(opts interface{}, sink interface{}) *ArbRollupCoreInterface_WatchRollupInitialized_Call {
+ return &ArbRollupCoreInterface_WatchRollupInitialized_Call{Call: _e.mock.On("WatchRollupInitialized", opts, sink)}
+}
+
+func (_c *ArbRollupCoreInterface_WatchRollupInitialized_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreRollupInitialized)) *ArbRollupCoreInterface_WatchRollupInitialized_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_rollup_core.ArbRollupCoreRollupInitialized))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchRollupInitialized_Call) Return(_a0 event.Subscription, _a1 error) *ArbRollupCoreInterface_WatchRollupInitialized_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchRollupInitialized_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreRollupInitialized) (event.Subscription, error)) *ArbRollupCoreInterface_WatchRollupInitialized_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchUserStakeUpdated provides a mock function with given fields: opts, sink, user
+func (_m *ArbRollupCoreInterface) WatchUserStakeUpdated(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, user []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, user)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchUserStakeUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, user)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, user)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, []common.Address) error); ok {
+ r1 = rf(opts, sink, user)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WatchUserStakeUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchUserStakeUpdated'
+type ArbRollupCoreInterface_WatchUserStakeUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchUserStakeUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated
+// - user []common.Address
+func (_e *ArbRollupCoreInterface_Expecter) WatchUserStakeUpdated(opts interface{}, sink interface{}, user interface{}) *ArbRollupCoreInterface_WatchUserStakeUpdated_Call {
+ return &ArbRollupCoreInterface_WatchUserStakeUpdated_Call{Call: _e.mock.On("WatchUserStakeUpdated", opts, sink, user)}
+}
+
+func (_c *ArbRollupCoreInterface_WatchUserStakeUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, user []common.Address)) *ArbRollupCoreInterface_WatchUserStakeUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchUserStakeUpdated_Call) Return(_a0 event.Subscription, _a1 error) *ArbRollupCoreInterface_WatchUserStakeUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchUserStakeUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreUserStakeUpdated, []common.Address) (event.Subscription, error)) *ArbRollupCoreInterface_WatchUserStakeUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchUserWithdrawableFundsUpdated provides a mock function with given fields: opts, sink, user
+func (_m *ArbRollupCoreInterface) WatchUserWithdrawableFundsUpdated(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, user []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, user)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchUserWithdrawableFundsUpdated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, user)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, user)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, []common.Address) error); ok {
+ r1 = rf(opts, sink, user)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchUserWithdrawableFundsUpdated'
+type ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call struct {
+ *mock.Call
+}
+
+// WatchUserWithdrawableFundsUpdated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated
+// - user []common.Address
+func (_e *ArbRollupCoreInterface_Expecter) WatchUserWithdrawableFundsUpdated(opts interface{}, sink interface{}, user interface{}) *ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call {
+ return &ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call{Call: _e.mock.On("WatchUserWithdrawableFundsUpdated", opts, sink, user)}
+}
+
+func (_c *ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, user []common.Address)) *ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated), args[2].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call) Return(_a0 event.Subscription, _a1 error) *ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbitrum_rollup_core.ArbRollupCoreUserWithdrawableFundsUpdated, []common.Address) (event.Subscription, error)) *ArbRollupCoreInterface_WatchUserWithdrawableFundsUpdated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WithdrawableFunds provides a mock function with given fields: opts, owner
+func (_m *ArbRollupCoreInterface) WithdrawableFunds(opts *bind.CallOpts, owner common.Address) (*big.Int, error) {
+ ret := _m.Called(opts, owner)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WithdrawableFunds")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok {
+ return rf(opts, owner)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) *big.Int); ok {
+ r0 = rf(opts, owner)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, owner)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_WithdrawableFunds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithdrawableFunds'
+type ArbRollupCoreInterface_WithdrawableFunds_Call struct {
+ *mock.Call
+}
+
+// WithdrawableFunds is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - owner common.Address
+func (_e *ArbRollupCoreInterface_Expecter) WithdrawableFunds(opts interface{}, owner interface{}) *ArbRollupCoreInterface_WithdrawableFunds_Call {
+ return &ArbRollupCoreInterface_WithdrawableFunds_Call{Call: _e.mock.On("WithdrawableFunds", opts, owner)}
+}
+
+func (_c *ArbRollupCoreInterface_WithdrawableFunds_Call) Run(run func(opts *bind.CallOpts, owner common.Address)) *ArbRollupCoreInterface_WithdrawableFunds_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WithdrawableFunds_Call) Return(_a0 *big.Int, _a1 error) *ArbRollupCoreInterface_WithdrawableFunds_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_WithdrawableFunds_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (*big.Int, error)) *ArbRollupCoreInterface_WithdrawableFunds_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ZombieAddress provides a mock function with given fields: opts, zombieNum
+func (_m *ArbRollupCoreInterface) ZombieAddress(opts *bind.CallOpts, zombieNum *big.Int) (common.Address, error) {
+ ret := _m.Called(opts, zombieNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ZombieAddress")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (common.Address, error)); ok {
+ return rf(opts, zombieNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) common.Address); ok {
+ r0 = rf(opts, zombieNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok {
+ r1 = rf(opts, zombieNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ZombieAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ZombieAddress'
+type ArbRollupCoreInterface_ZombieAddress_Call struct {
+ *mock.Call
+}
+
+// ZombieAddress is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - zombieNum *big.Int
+func (_e *ArbRollupCoreInterface_Expecter) ZombieAddress(opts interface{}, zombieNum interface{}) *ArbRollupCoreInterface_ZombieAddress_Call {
+ return &ArbRollupCoreInterface_ZombieAddress_Call{Call: _e.mock.On("ZombieAddress", opts, zombieNum)}
+}
+
+func (_c *ArbRollupCoreInterface_ZombieAddress_Call) Run(run func(opts *bind.CallOpts, zombieNum *big.Int)) *ArbRollupCoreInterface_ZombieAddress_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ZombieAddress_Call) Return(_a0 common.Address, _a1 error) *ArbRollupCoreInterface_ZombieAddress_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ZombieAddress_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int) (common.Address, error)) *ArbRollupCoreInterface_ZombieAddress_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ZombieCount provides a mock function with given fields: opts
+func (_m *ArbRollupCoreInterface) ZombieCount(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ZombieCount")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ZombieCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ZombieCount'
+type ArbRollupCoreInterface_ZombieCount_Call struct {
+ *mock.Call
+}
+
+// ZombieCount is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbRollupCoreInterface_Expecter) ZombieCount(opts interface{}) *ArbRollupCoreInterface_ZombieCount_Call {
+ return &ArbRollupCoreInterface_ZombieCount_Call{Call: _e.mock.On("ZombieCount", opts)}
+}
+
+func (_c *ArbRollupCoreInterface_ZombieCount_Call) Run(run func(opts *bind.CallOpts)) *ArbRollupCoreInterface_ZombieCount_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ZombieCount_Call) Return(_a0 *big.Int, _a1 error) *ArbRollupCoreInterface_ZombieCount_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ZombieCount_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbRollupCoreInterface_ZombieCount_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ZombieLatestStakedNode provides a mock function with given fields: opts, zombieNum
+func (_m *ArbRollupCoreInterface) ZombieLatestStakedNode(opts *bind.CallOpts, zombieNum *big.Int) (uint64, error) {
+ ret := _m.Called(opts, zombieNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ZombieLatestStakedNode")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (uint64, error)); ok {
+ return rf(opts, zombieNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) uint64); ok {
+ r0 = rf(opts, zombieNum)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok {
+ r1 = rf(opts, zombieNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbRollupCoreInterface_ZombieLatestStakedNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ZombieLatestStakedNode'
+type ArbRollupCoreInterface_ZombieLatestStakedNode_Call struct {
+ *mock.Call
+}
+
+// ZombieLatestStakedNode is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - zombieNum *big.Int
+func (_e *ArbRollupCoreInterface_Expecter) ZombieLatestStakedNode(opts interface{}, zombieNum interface{}) *ArbRollupCoreInterface_ZombieLatestStakedNode_Call {
+ return &ArbRollupCoreInterface_ZombieLatestStakedNode_Call{Call: _e.mock.On("ZombieLatestStakedNode", opts, zombieNum)}
+}
+
+func (_c *ArbRollupCoreInterface_ZombieLatestStakedNode_Call) Run(run func(opts *bind.CallOpts, zombieNum *big.Int)) *ArbRollupCoreInterface_ZombieLatestStakedNode_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ZombieLatestStakedNode_Call) Return(_a0 uint64, _a1 error) *ArbRollupCoreInterface_ZombieLatestStakedNode_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbRollupCoreInterface_ZombieLatestStakedNode_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int) (uint64, error)) *ArbRollupCoreInterface_ZombieLatestStakedNode_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewArbRollupCoreInterface creates a new instance of ArbRollupCoreInterface. 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 NewArbRollupCoreInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ArbRollupCoreInterface {
+ mock := &ArbRollupCoreInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_arbsys/arb_sys_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_arbsys/arb_sys_interface.go
new file mode 100644
index 00000000000..609cff0ceda
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_arbsys/arb_sys_interface.go
@@ -0,0 +1,1392 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_arbsys
+
+import (
+ big "math/big"
+
+ arbsys "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arbsys"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// ArbSysInterface is an autogenerated mock type for the ArbSysInterface type
+type ArbSysInterface struct {
+ mock.Mock
+}
+
+type ArbSysInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ArbSysInterface) EXPECT() *ArbSysInterface_Expecter {
+ return &ArbSysInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *ArbSysInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// ArbSysInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type ArbSysInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *ArbSysInterface_Expecter) Address() *ArbSysInterface_Address_Call {
+ return &ArbSysInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *ArbSysInterface_Address_Call) Run(run func()) *ArbSysInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_Address_Call) Return(_a0 common.Address) *ArbSysInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ArbSysInterface_Address_Call) RunAndReturn(run func() common.Address) *ArbSysInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ArbBlockHash provides a mock function with given fields: opts, arbBlockNum
+func (_m *ArbSysInterface) ArbBlockHash(opts *bind.CallOpts, arbBlockNum *big.Int) ([32]byte, error) {
+ ret := _m.Called(opts, arbBlockNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ArbBlockHash")
+ }
+
+ var r0 [32]byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([32]byte, error)); ok {
+ return rf(opts, arbBlockNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) [32]byte); ok {
+ r0 = rf(opts, arbBlockNum)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([32]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok {
+ r1 = rf(opts, arbBlockNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_ArbBlockHash_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ArbBlockHash'
+type ArbSysInterface_ArbBlockHash_Call struct {
+ *mock.Call
+}
+
+// ArbBlockHash is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - arbBlockNum *big.Int
+func (_e *ArbSysInterface_Expecter) ArbBlockHash(opts interface{}, arbBlockNum interface{}) *ArbSysInterface_ArbBlockHash_Call {
+ return &ArbSysInterface_ArbBlockHash_Call{Call: _e.mock.On("ArbBlockHash", opts, arbBlockNum)}
+}
+
+func (_c *ArbSysInterface_ArbBlockHash_Call) Run(run func(opts *bind.CallOpts, arbBlockNum *big.Int)) *ArbSysInterface_ArbBlockHash_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_ArbBlockHash_Call) Return(_a0 [32]byte, _a1 error) *ArbSysInterface_ArbBlockHash_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_ArbBlockHash_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int) ([32]byte, error)) *ArbSysInterface_ArbBlockHash_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ArbBlockNumber provides a mock function with given fields: opts
+func (_m *ArbSysInterface) ArbBlockNumber(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ArbBlockNumber")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_ArbBlockNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ArbBlockNumber'
+type ArbSysInterface_ArbBlockNumber_Call struct {
+ *mock.Call
+}
+
+// ArbBlockNumber is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbSysInterface_Expecter) ArbBlockNumber(opts interface{}) *ArbSysInterface_ArbBlockNumber_Call {
+ return &ArbSysInterface_ArbBlockNumber_Call{Call: _e.mock.On("ArbBlockNumber", opts)}
+}
+
+func (_c *ArbSysInterface_ArbBlockNumber_Call) Run(run func(opts *bind.CallOpts)) *ArbSysInterface_ArbBlockNumber_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_ArbBlockNumber_Call) Return(_a0 *big.Int, _a1 error) *ArbSysInterface_ArbBlockNumber_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_ArbBlockNumber_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbSysInterface_ArbBlockNumber_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ArbChainID provides a mock function with given fields: opts
+func (_m *ArbSysInterface) ArbChainID(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ArbChainID")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_ArbChainID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ArbChainID'
+type ArbSysInterface_ArbChainID_Call struct {
+ *mock.Call
+}
+
+// ArbChainID is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbSysInterface_Expecter) ArbChainID(opts interface{}) *ArbSysInterface_ArbChainID_Call {
+ return &ArbSysInterface_ArbChainID_Call{Call: _e.mock.On("ArbChainID", opts)}
+}
+
+func (_c *ArbSysInterface_ArbChainID_Call) Run(run func(opts *bind.CallOpts)) *ArbSysInterface_ArbChainID_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_ArbChainID_Call) Return(_a0 *big.Int, _a1 error) *ArbSysInterface_ArbChainID_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_ArbChainID_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbSysInterface_ArbChainID_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ArbOSVersion provides a mock function with given fields: opts
+func (_m *ArbSysInterface) ArbOSVersion(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ArbOSVersion")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_ArbOSVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ArbOSVersion'
+type ArbSysInterface_ArbOSVersion_Call struct {
+ *mock.Call
+}
+
+// ArbOSVersion is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbSysInterface_Expecter) ArbOSVersion(opts interface{}) *ArbSysInterface_ArbOSVersion_Call {
+ return &ArbSysInterface_ArbOSVersion_Call{Call: _e.mock.On("ArbOSVersion", opts)}
+}
+
+func (_c *ArbSysInterface_ArbOSVersion_Call) Run(run func(opts *bind.CallOpts)) *ArbSysInterface_ArbOSVersion_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_ArbOSVersion_Call) Return(_a0 *big.Int, _a1 error) *ArbSysInterface_ArbOSVersion_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_ArbOSVersion_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbSysInterface_ArbOSVersion_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterL2ToL1Transaction provides a mock function with given fields: opts, destination, uniqueId, batchNumber
+func (_m *ArbSysInterface) FilterL2ToL1Transaction(opts *bind.FilterOpts, destination []common.Address, uniqueId []*big.Int, batchNumber []*big.Int) (*arbsys.ArbSysL2ToL1TransactionIterator, error) {
+ ret := _m.Called(opts, destination, uniqueId, batchNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterL2ToL1Transaction")
+ }
+
+ var r0 *arbsys.ArbSysL2ToL1TransactionIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []*big.Int, []*big.Int) (*arbsys.ArbSysL2ToL1TransactionIterator, error)); ok {
+ return rf(opts, destination, uniqueId, batchNumber)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []*big.Int, []*big.Int) *arbsys.ArbSysL2ToL1TransactionIterator); ok {
+ r0 = rf(opts, destination, uniqueId, batchNumber)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbsys.ArbSysL2ToL1TransactionIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []*big.Int, []*big.Int) error); ok {
+ r1 = rf(opts, destination, uniqueId, batchNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_FilterL2ToL1Transaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterL2ToL1Transaction'
+type ArbSysInterface_FilterL2ToL1Transaction_Call struct {
+ *mock.Call
+}
+
+// FilterL2ToL1Transaction is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - destination []common.Address
+// - uniqueId []*big.Int
+// - batchNumber []*big.Int
+func (_e *ArbSysInterface_Expecter) FilterL2ToL1Transaction(opts interface{}, destination interface{}, uniqueId interface{}, batchNumber interface{}) *ArbSysInterface_FilterL2ToL1Transaction_Call {
+ return &ArbSysInterface_FilterL2ToL1Transaction_Call{Call: _e.mock.On("FilterL2ToL1Transaction", opts, destination, uniqueId, batchNumber)}
+}
+
+func (_c *ArbSysInterface_FilterL2ToL1Transaction_Call) Run(run func(opts *bind.FilterOpts, destination []common.Address, uniqueId []*big.Int, batchNumber []*big.Int)) *ArbSysInterface_FilterL2ToL1Transaction_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]*big.Int), args[3].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_FilterL2ToL1Transaction_Call) Return(_a0 *arbsys.ArbSysL2ToL1TransactionIterator, _a1 error) *ArbSysInterface_FilterL2ToL1Transaction_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_FilterL2ToL1Transaction_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []*big.Int, []*big.Int) (*arbsys.ArbSysL2ToL1TransactionIterator, error)) *ArbSysInterface_FilterL2ToL1Transaction_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterL2ToL1Tx provides a mock function with given fields: opts, destination, hash, position
+func (_m *ArbSysInterface) FilterL2ToL1Tx(opts *bind.FilterOpts, destination []common.Address, hash []*big.Int, position []*big.Int) (*arbsys.ArbSysL2ToL1TxIterator, error) {
+ ret := _m.Called(opts, destination, hash, position)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterL2ToL1Tx")
+ }
+
+ var r0 *arbsys.ArbSysL2ToL1TxIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []*big.Int, []*big.Int) (*arbsys.ArbSysL2ToL1TxIterator, error)); ok {
+ return rf(opts, destination, hash, position)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []*big.Int, []*big.Int) *arbsys.ArbSysL2ToL1TxIterator); ok {
+ r0 = rf(opts, destination, hash, position)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbsys.ArbSysL2ToL1TxIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []*big.Int, []*big.Int) error); ok {
+ r1 = rf(opts, destination, hash, position)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_FilterL2ToL1Tx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterL2ToL1Tx'
+type ArbSysInterface_FilterL2ToL1Tx_Call struct {
+ *mock.Call
+}
+
+// FilterL2ToL1Tx is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - destination []common.Address
+// - hash []*big.Int
+// - position []*big.Int
+func (_e *ArbSysInterface_Expecter) FilterL2ToL1Tx(opts interface{}, destination interface{}, hash interface{}, position interface{}) *ArbSysInterface_FilterL2ToL1Tx_Call {
+ return &ArbSysInterface_FilterL2ToL1Tx_Call{Call: _e.mock.On("FilterL2ToL1Tx", opts, destination, hash, position)}
+}
+
+func (_c *ArbSysInterface_FilterL2ToL1Tx_Call) Run(run func(opts *bind.FilterOpts, destination []common.Address, hash []*big.Int, position []*big.Int)) *ArbSysInterface_FilterL2ToL1Tx_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]*big.Int), args[3].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_FilterL2ToL1Tx_Call) Return(_a0 *arbsys.ArbSysL2ToL1TxIterator, _a1 error) *ArbSysInterface_FilterL2ToL1Tx_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_FilterL2ToL1Tx_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []*big.Int, []*big.Int) (*arbsys.ArbSysL2ToL1TxIterator, error)) *ArbSysInterface_FilterL2ToL1Tx_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterSendMerkleUpdate provides a mock function with given fields: opts, reserved, hash, position
+func (_m *ArbSysInterface) FilterSendMerkleUpdate(opts *bind.FilterOpts, reserved []*big.Int, hash [][32]byte, position []*big.Int) (*arbsys.ArbSysSendMerkleUpdateIterator, error) {
+ ret := _m.Called(opts, reserved, hash, position)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterSendMerkleUpdate")
+ }
+
+ var r0 *arbsys.ArbSysSendMerkleUpdateIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, [][32]byte, []*big.Int) (*arbsys.ArbSysSendMerkleUpdateIterator, error)); ok {
+ return rf(opts, reserved, hash, position)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, [][32]byte, []*big.Int) *arbsys.ArbSysSendMerkleUpdateIterator); ok {
+ r0 = rf(opts, reserved, hash, position)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbsys.ArbSysSendMerkleUpdateIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []*big.Int, [][32]byte, []*big.Int) error); ok {
+ r1 = rf(opts, reserved, hash, position)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_FilterSendMerkleUpdate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterSendMerkleUpdate'
+type ArbSysInterface_FilterSendMerkleUpdate_Call struct {
+ *mock.Call
+}
+
+// FilterSendMerkleUpdate is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - reserved []*big.Int
+// - hash [][32]byte
+// - position []*big.Int
+func (_e *ArbSysInterface_Expecter) FilterSendMerkleUpdate(opts interface{}, reserved interface{}, hash interface{}, position interface{}) *ArbSysInterface_FilterSendMerkleUpdate_Call {
+ return &ArbSysInterface_FilterSendMerkleUpdate_Call{Call: _e.mock.On("FilterSendMerkleUpdate", opts, reserved, hash, position)}
+}
+
+func (_c *ArbSysInterface_FilterSendMerkleUpdate_Call) Run(run func(opts *bind.FilterOpts, reserved []*big.Int, hash [][32]byte, position []*big.Int)) *ArbSysInterface_FilterSendMerkleUpdate_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]*big.Int), args[2].([][32]byte), args[3].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_FilterSendMerkleUpdate_Call) Return(_a0 *arbsys.ArbSysSendMerkleUpdateIterator, _a1 error) *ArbSysInterface_FilterSendMerkleUpdate_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_FilterSendMerkleUpdate_Call) RunAndReturn(run func(*bind.FilterOpts, []*big.Int, [][32]byte, []*big.Int) (*arbsys.ArbSysSendMerkleUpdateIterator, error)) *ArbSysInterface_FilterSendMerkleUpdate_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStorageGasAvailable provides a mock function with given fields: opts
+func (_m *ArbSysInterface) GetStorageGasAvailable(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStorageGasAvailable")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_GetStorageGasAvailable_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStorageGasAvailable'
+type ArbSysInterface_GetStorageGasAvailable_Call struct {
+ *mock.Call
+}
+
+// GetStorageGasAvailable is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbSysInterface_Expecter) GetStorageGasAvailable(opts interface{}) *ArbSysInterface_GetStorageGasAvailable_Call {
+ return &ArbSysInterface_GetStorageGasAvailable_Call{Call: _e.mock.On("GetStorageGasAvailable", opts)}
+}
+
+func (_c *ArbSysInterface_GetStorageGasAvailable_Call) Run(run func(opts *bind.CallOpts)) *ArbSysInterface_GetStorageGasAvailable_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_GetStorageGasAvailable_Call) Return(_a0 *big.Int, _a1 error) *ArbSysInterface_GetStorageGasAvailable_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_GetStorageGasAvailable_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *ArbSysInterface_GetStorageGasAvailable_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsTopLevelCall provides a mock function with given fields: opts
+func (_m *ArbSysInterface) IsTopLevelCall(opts *bind.CallOpts) (bool, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsTopLevelCall")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) bool); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_IsTopLevelCall_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsTopLevelCall'
+type ArbSysInterface_IsTopLevelCall_Call struct {
+ *mock.Call
+}
+
+// IsTopLevelCall is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbSysInterface_Expecter) IsTopLevelCall(opts interface{}) *ArbSysInterface_IsTopLevelCall_Call {
+ return &ArbSysInterface_IsTopLevelCall_Call{Call: _e.mock.On("IsTopLevelCall", opts)}
+}
+
+func (_c *ArbSysInterface_IsTopLevelCall_Call) Run(run func(opts *bind.CallOpts)) *ArbSysInterface_IsTopLevelCall_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_IsTopLevelCall_Call) Return(_a0 bool, _a1 error) *ArbSysInterface_IsTopLevelCall_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_IsTopLevelCall_Call) RunAndReturn(run func(*bind.CallOpts) (bool, error)) *ArbSysInterface_IsTopLevelCall_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// MapL1SenderContractAddressToL2Alias provides a mock function with given fields: opts, sender, unused
+func (_m *ArbSysInterface) MapL1SenderContractAddressToL2Alias(opts *bind.CallOpts, sender common.Address, unused common.Address) (common.Address, error) {
+ ret := _m.Called(opts, sender, unused)
+
+ if len(ret) == 0 {
+ panic("no return value specified for MapL1SenderContractAddressToL2Alias")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address) (common.Address, error)); ok {
+ return rf(opts, sender, unused)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address) common.Address); ok {
+ r0 = rf(opts, sender, unused)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address, common.Address) error); ok {
+ r1 = rf(opts, sender, unused)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MapL1SenderContractAddressToL2Alias'
+type ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call struct {
+ *mock.Call
+}
+
+// MapL1SenderContractAddressToL2Alias is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - sender common.Address
+// - unused common.Address
+func (_e *ArbSysInterface_Expecter) MapL1SenderContractAddressToL2Alias(opts interface{}, sender interface{}, unused interface{}) *ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call {
+ return &ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call{Call: _e.mock.On("MapL1SenderContractAddressToL2Alias", opts, sender, unused)}
+}
+
+func (_c *ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call) Run(run func(opts *bind.CallOpts, sender common.Address, unused common.Address)) *ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address), args[2].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call) Return(_a0 common.Address, _a1 error) *ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call) RunAndReturn(run func(*bind.CallOpts, common.Address, common.Address) (common.Address, error)) *ArbSysInterface_MapL1SenderContractAddressToL2Alias_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// MyCallersAddressWithoutAliasing provides a mock function with given fields: opts
+func (_m *ArbSysInterface) MyCallersAddressWithoutAliasing(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for MyCallersAddressWithoutAliasing")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_MyCallersAddressWithoutAliasing_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MyCallersAddressWithoutAliasing'
+type ArbSysInterface_MyCallersAddressWithoutAliasing_Call struct {
+ *mock.Call
+}
+
+// MyCallersAddressWithoutAliasing is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbSysInterface_Expecter) MyCallersAddressWithoutAliasing(opts interface{}) *ArbSysInterface_MyCallersAddressWithoutAliasing_Call {
+ return &ArbSysInterface_MyCallersAddressWithoutAliasing_Call{Call: _e.mock.On("MyCallersAddressWithoutAliasing", opts)}
+}
+
+func (_c *ArbSysInterface_MyCallersAddressWithoutAliasing_Call) Run(run func(opts *bind.CallOpts)) *ArbSysInterface_MyCallersAddressWithoutAliasing_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_MyCallersAddressWithoutAliasing_Call) Return(_a0 common.Address, _a1 error) *ArbSysInterface_MyCallersAddressWithoutAliasing_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_MyCallersAddressWithoutAliasing_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *ArbSysInterface_MyCallersAddressWithoutAliasing_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseL2ToL1Transaction provides a mock function with given fields: log
+func (_m *ArbSysInterface) ParseL2ToL1Transaction(log types.Log) (*arbsys.ArbSysL2ToL1Transaction, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseL2ToL1Transaction")
+ }
+
+ var r0 *arbsys.ArbSysL2ToL1Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbsys.ArbSysL2ToL1Transaction, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbsys.ArbSysL2ToL1Transaction); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbsys.ArbSysL2ToL1Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_ParseL2ToL1Transaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseL2ToL1Transaction'
+type ArbSysInterface_ParseL2ToL1Transaction_Call struct {
+ *mock.Call
+}
+
+// ParseL2ToL1Transaction is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbSysInterface_Expecter) ParseL2ToL1Transaction(log interface{}) *ArbSysInterface_ParseL2ToL1Transaction_Call {
+ return &ArbSysInterface_ParseL2ToL1Transaction_Call{Call: _e.mock.On("ParseL2ToL1Transaction", log)}
+}
+
+func (_c *ArbSysInterface_ParseL2ToL1Transaction_Call) Run(run func(log types.Log)) *ArbSysInterface_ParseL2ToL1Transaction_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_ParseL2ToL1Transaction_Call) Return(_a0 *arbsys.ArbSysL2ToL1Transaction, _a1 error) *ArbSysInterface_ParseL2ToL1Transaction_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_ParseL2ToL1Transaction_Call) RunAndReturn(run func(types.Log) (*arbsys.ArbSysL2ToL1Transaction, error)) *ArbSysInterface_ParseL2ToL1Transaction_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseL2ToL1Tx provides a mock function with given fields: log
+func (_m *ArbSysInterface) ParseL2ToL1Tx(log types.Log) (*arbsys.ArbSysL2ToL1Tx, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseL2ToL1Tx")
+ }
+
+ var r0 *arbsys.ArbSysL2ToL1Tx
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbsys.ArbSysL2ToL1Tx, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbsys.ArbSysL2ToL1Tx); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbsys.ArbSysL2ToL1Tx)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_ParseL2ToL1Tx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseL2ToL1Tx'
+type ArbSysInterface_ParseL2ToL1Tx_Call struct {
+ *mock.Call
+}
+
+// ParseL2ToL1Tx is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbSysInterface_Expecter) ParseL2ToL1Tx(log interface{}) *ArbSysInterface_ParseL2ToL1Tx_Call {
+ return &ArbSysInterface_ParseL2ToL1Tx_Call{Call: _e.mock.On("ParseL2ToL1Tx", log)}
+}
+
+func (_c *ArbSysInterface_ParseL2ToL1Tx_Call) Run(run func(log types.Log)) *ArbSysInterface_ParseL2ToL1Tx_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_ParseL2ToL1Tx_Call) Return(_a0 *arbsys.ArbSysL2ToL1Tx, _a1 error) *ArbSysInterface_ParseL2ToL1Tx_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_ParseL2ToL1Tx_Call) RunAndReturn(run func(types.Log) (*arbsys.ArbSysL2ToL1Tx, error)) *ArbSysInterface_ParseL2ToL1Tx_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *ArbSysInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type ArbSysInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbSysInterface_Expecter) ParseLog(log interface{}) *ArbSysInterface_ParseLog_Call {
+ return &ArbSysInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *ArbSysInterface_ParseLog_Call) Run(run func(log types.Log)) *ArbSysInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *ArbSysInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *ArbSysInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseSendMerkleUpdate provides a mock function with given fields: log
+func (_m *ArbSysInterface) ParseSendMerkleUpdate(log types.Log) (*arbsys.ArbSysSendMerkleUpdate, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseSendMerkleUpdate")
+ }
+
+ var r0 *arbsys.ArbSysSendMerkleUpdate
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*arbsys.ArbSysSendMerkleUpdate, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *arbsys.ArbSysSendMerkleUpdate); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*arbsys.ArbSysSendMerkleUpdate)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_ParseSendMerkleUpdate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseSendMerkleUpdate'
+type ArbSysInterface_ParseSendMerkleUpdate_Call struct {
+ *mock.Call
+}
+
+// ParseSendMerkleUpdate is a helper method to define mock.On call
+// - log types.Log
+func (_e *ArbSysInterface_Expecter) ParseSendMerkleUpdate(log interface{}) *ArbSysInterface_ParseSendMerkleUpdate_Call {
+ return &ArbSysInterface_ParseSendMerkleUpdate_Call{Call: _e.mock.On("ParseSendMerkleUpdate", log)}
+}
+
+func (_c *ArbSysInterface_ParseSendMerkleUpdate_Call) Run(run func(log types.Log)) *ArbSysInterface_ParseSendMerkleUpdate_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_ParseSendMerkleUpdate_Call) Return(_a0 *arbsys.ArbSysSendMerkleUpdate, _a1 error) *ArbSysInterface_ParseSendMerkleUpdate_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_ParseSendMerkleUpdate_Call) RunAndReturn(run func(types.Log) (*arbsys.ArbSysSendMerkleUpdate, error)) *ArbSysInterface_ParseSendMerkleUpdate_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SendMerkleTreeState provides a mock function with given fields: opts
+func (_m *ArbSysInterface) SendMerkleTreeState(opts *bind.CallOpts) (arbsys.SendMerkleTreeState, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SendMerkleTreeState")
+ }
+
+ var r0 arbsys.SendMerkleTreeState
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (arbsys.SendMerkleTreeState, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) arbsys.SendMerkleTreeState); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(arbsys.SendMerkleTreeState)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_SendMerkleTreeState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendMerkleTreeState'
+type ArbSysInterface_SendMerkleTreeState_Call struct {
+ *mock.Call
+}
+
+// SendMerkleTreeState is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbSysInterface_Expecter) SendMerkleTreeState(opts interface{}) *ArbSysInterface_SendMerkleTreeState_Call {
+ return &ArbSysInterface_SendMerkleTreeState_Call{Call: _e.mock.On("SendMerkleTreeState", opts)}
+}
+
+func (_c *ArbSysInterface_SendMerkleTreeState_Call) Run(run func(opts *bind.CallOpts)) *ArbSysInterface_SendMerkleTreeState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_SendMerkleTreeState_Call) Return(_a0 arbsys.SendMerkleTreeState, _a1 error) *ArbSysInterface_SendMerkleTreeState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_SendMerkleTreeState_Call) RunAndReturn(run func(*bind.CallOpts) (arbsys.SendMerkleTreeState, error)) *ArbSysInterface_SendMerkleTreeState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SendTxToL1 provides a mock function with given fields: opts, destination, data
+func (_m *ArbSysInterface) SendTxToL1(opts *bind.TransactOpts, destination common.Address, data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, destination, data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SendTxToL1")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, destination, data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, []byte) *types.Transaction); ok {
+ r0 = rf(opts, destination, data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, []byte) error); ok {
+ r1 = rf(opts, destination, data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_SendTxToL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendTxToL1'
+type ArbSysInterface_SendTxToL1_Call struct {
+ *mock.Call
+}
+
+// SendTxToL1 is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - destination common.Address
+// - data []byte
+func (_e *ArbSysInterface_Expecter) SendTxToL1(opts interface{}, destination interface{}, data interface{}) *ArbSysInterface_SendTxToL1_Call {
+ return &ArbSysInterface_SendTxToL1_Call{Call: _e.mock.On("SendTxToL1", opts, destination, data)}
+}
+
+func (_c *ArbSysInterface_SendTxToL1_Call) Run(run func(opts *bind.TransactOpts, destination common.Address, data []byte)) *ArbSysInterface_SendTxToL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].([]byte))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_SendTxToL1_Call) Return(_a0 *types.Transaction, _a1 error) *ArbSysInterface_SendTxToL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_SendTxToL1_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, []byte) (*types.Transaction, error)) *ArbSysInterface_SendTxToL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WasMyCallersAddressAliased provides a mock function with given fields: opts
+func (_m *ArbSysInterface) WasMyCallersAddressAliased(opts *bind.CallOpts) (bool, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WasMyCallersAddressAliased")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) bool); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_WasMyCallersAddressAliased_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WasMyCallersAddressAliased'
+type ArbSysInterface_WasMyCallersAddressAliased_Call struct {
+ *mock.Call
+}
+
+// WasMyCallersAddressAliased is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *ArbSysInterface_Expecter) WasMyCallersAddressAliased(opts interface{}) *ArbSysInterface_WasMyCallersAddressAliased_Call {
+ return &ArbSysInterface_WasMyCallersAddressAliased_Call{Call: _e.mock.On("WasMyCallersAddressAliased", opts)}
+}
+
+func (_c *ArbSysInterface_WasMyCallersAddressAliased_Call) Run(run func(opts *bind.CallOpts)) *ArbSysInterface_WasMyCallersAddressAliased_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_WasMyCallersAddressAliased_Call) Return(_a0 bool, _a1 error) *ArbSysInterface_WasMyCallersAddressAliased_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_WasMyCallersAddressAliased_Call) RunAndReturn(run func(*bind.CallOpts) (bool, error)) *ArbSysInterface_WasMyCallersAddressAliased_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchL2ToL1Transaction provides a mock function with given fields: opts, sink, destination, uniqueId, batchNumber
+func (_m *ArbSysInterface) WatchL2ToL1Transaction(opts *bind.WatchOpts, sink chan<- *arbsys.ArbSysL2ToL1Transaction, destination []common.Address, uniqueId []*big.Int, batchNumber []*big.Int) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, destination, uniqueId, batchNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchL2ToL1Transaction")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysL2ToL1Transaction, []common.Address, []*big.Int, []*big.Int) (event.Subscription, error)); ok {
+ return rf(opts, sink, destination, uniqueId, batchNumber)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysL2ToL1Transaction, []common.Address, []*big.Int, []*big.Int) event.Subscription); ok {
+ r0 = rf(opts, sink, destination, uniqueId, batchNumber)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysL2ToL1Transaction, []common.Address, []*big.Int, []*big.Int) error); ok {
+ r1 = rf(opts, sink, destination, uniqueId, batchNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_WatchL2ToL1Transaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchL2ToL1Transaction'
+type ArbSysInterface_WatchL2ToL1Transaction_Call struct {
+ *mock.Call
+}
+
+// WatchL2ToL1Transaction is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbsys.ArbSysL2ToL1Transaction
+// - destination []common.Address
+// - uniqueId []*big.Int
+// - batchNumber []*big.Int
+func (_e *ArbSysInterface_Expecter) WatchL2ToL1Transaction(opts interface{}, sink interface{}, destination interface{}, uniqueId interface{}, batchNumber interface{}) *ArbSysInterface_WatchL2ToL1Transaction_Call {
+ return &ArbSysInterface_WatchL2ToL1Transaction_Call{Call: _e.mock.On("WatchL2ToL1Transaction", opts, sink, destination, uniqueId, batchNumber)}
+}
+
+func (_c *ArbSysInterface_WatchL2ToL1Transaction_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbsys.ArbSysL2ToL1Transaction, destination []common.Address, uniqueId []*big.Int, batchNumber []*big.Int)) *ArbSysInterface_WatchL2ToL1Transaction_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbsys.ArbSysL2ToL1Transaction), args[2].([]common.Address), args[3].([]*big.Int), args[4].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_WatchL2ToL1Transaction_Call) Return(_a0 event.Subscription, _a1 error) *ArbSysInterface_WatchL2ToL1Transaction_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_WatchL2ToL1Transaction_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbsys.ArbSysL2ToL1Transaction, []common.Address, []*big.Int, []*big.Int) (event.Subscription, error)) *ArbSysInterface_WatchL2ToL1Transaction_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchL2ToL1Tx provides a mock function with given fields: opts, sink, destination, hash, position
+func (_m *ArbSysInterface) WatchL2ToL1Tx(opts *bind.WatchOpts, sink chan<- *arbsys.ArbSysL2ToL1Tx, destination []common.Address, hash []*big.Int, position []*big.Int) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, destination, hash, position)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchL2ToL1Tx")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysL2ToL1Tx, []common.Address, []*big.Int, []*big.Int) (event.Subscription, error)); ok {
+ return rf(opts, sink, destination, hash, position)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysL2ToL1Tx, []common.Address, []*big.Int, []*big.Int) event.Subscription); ok {
+ r0 = rf(opts, sink, destination, hash, position)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysL2ToL1Tx, []common.Address, []*big.Int, []*big.Int) error); ok {
+ r1 = rf(opts, sink, destination, hash, position)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_WatchL2ToL1Tx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchL2ToL1Tx'
+type ArbSysInterface_WatchL2ToL1Tx_Call struct {
+ *mock.Call
+}
+
+// WatchL2ToL1Tx is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbsys.ArbSysL2ToL1Tx
+// - destination []common.Address
+// - hash []*big.Int
+// - position []*big.Int
+func (_e *ArbSysInterface_Expecter) WatchL2ToL1Tx(opts interface{}, sink interface{}, destination interface{}, hash interface{}, position interface{}) *ArbSysInterface_WatchL2ToL1Tx_Call {
+ return &ArbSysInterface_WatchL2ToL1Tx_Call{Call: _e.mock.On("WatchL2ToL1Tx", opts, sink, destination, hash, position)}
+}
+
+func (_c *ArbSysInterface_WatchL2ToL1Tx_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbsys.ArbSysL2ToL1Tx, destination []common.Address, hash []*big.Int, position []*big.Int)) *ArbSysInterface_WatchL2ToL1Tx_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbsys.ArbSysL2ToL1Tx), args[2].([]common.Address), args[3].([]*big.Int), args[4].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_WatchL2ToL1Tx_Call) Return(_a0 event.Subscription, _a1 error) *ArbSysInterface_WatchL2ToL1Tx_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_WatchL2ToL1Tx_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbsys.ArbSysL2ToL1Tx, []common.Address, []*big.Int, []*big.Int) (event.Subscription, error)) *ArbSysInterface_WatchL2ToL1Tx_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchSendMerkleUpdate provides a mock function with given fields: opts, sink, reserved, hash, position
+func (_m *ArbSysInterface) WatchSendMerkleUpdate(opts *bind.WatchOpts, sink chan<- *arbsys.ArbSysSendMerkleUpdate, reserved []*big.Int, hash [][32]byte, position []*big.Int) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, reserved, hash, position)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchSendMerkleUpdate")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysSendMerkleUpdate, []*big.Int, [][32]byte, []*big.Int) (event.Subscription, error)); ok {
+ return rf(opts, sink, reserved, hash, position)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysSendMerkleUpdate, []*big.Int, [][32]byte, []*big.Int) event.Subscription); ok {
+ r0 = rf(opts, sink, reserved, hash, position)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *arbsys.ArbSysSendMerkleUpdate, []*big.Int, [][32]byte, []*big.Int) error); ok {
+ r1 = rf(opts, sink, reserved, hash, position)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_WatchSendMerkleUpdate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchSendMerkleUpdate'
+type ArbSysInterface_WatchSendMerkleUpdate_Call struct {
+ *mock.Call
+}
+
+// WatchSendMerkleUpdate is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *arbsys.ArbSysSendMerkleUpdate
+// - reserved []*big.Int
+// - hash [][32]byte
+// - position []*big.Int
+func (_e *ArbSysInterface_Expecter) WatchSendMerkleUpdate(opts interface{}, sink interface{}, reserved interface{}, hash interface{}, position interface{}) *ArbSysInterface_WatchSendMerkleUpdate_Call {
+ return &ArbSysInterface_WatchSendMerkleUpdate_Call{Call: _e.mock.On("WatchSendMerkleUpdate", opts, sink, reserved, hash, position)}
+}
+
+func (_c *ArbSysInterface_WatchSendMerkleUpdate_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *arbsys.ArbSysSendMerkleUpdate, reserved []*big.Int, hash [][32]byte, position []*big.Int)) *ArbSysInterface_WatchSendMerkleUpdate_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *arbsys.ArbSysSendMerkleUpdate), args[2].([]*big.Int), args[3].([][32]byte), args[4].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_WatchSendMerkleUpdate_Call) Return(_a0 event.Subscription, _a1 error) *ArbSysInterface_WatchSendMerkleUpdate_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_WatchSendMerkleUpdate_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *arbsys.ArbSysSendMerkleUpdate, []*big.Int, [][32]byte, []*big.Int) (event.Subscription, error)) *ArbSysInterface_WatchSendMerkleUpdate_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WithdrawEth provides a mock function with given fields: opts, destination
+func (_m *ArbSysInterface) WithdrawEth(opts *bind.TransactOpts, destination common.Address) (*types.Transaction, error) {
+ ret := _m.Called(opts, destination)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WithdrawEth")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok {
+ return rf(opts, destination)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) *types.Transaction); ok {
+ r0 = rf(opts, destination)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address) error); ok {
+ r1 = rf(opts, destination)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ArbSysInterface_WithdrawEth_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithdrawEth'
+type ArbSysInterface_WithdrawEth_Call struct {
+ *mock.Call
+}
+
+// WithdrawEth is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - destination common.Address
+func (_e *ArbSysInterface_Expecter) WithdrawEth(opts interface{}, destination interface{}) *ArbSysInterface_WithdrawEth_Call {
+ return &ArbSysInterface_WithdrawEth_Call{Call: _e.mock.On("WithdrawEth", opts, destination)}
+}
+
+func (_c *ArbSysInterface_WithdrawEth_Call) Run(run func(opts *bind.TransactOpts, destination common.Address)) *ArbSysInterface_WithdrawEth_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *ArbSysInterface_WithdrawEth_Call) Return(_a0 *types.Transaction, _a1 error) *ArbSysInterface_WithdrawEth_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ArbSysInterface_WithdrawEth_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address) (*types.Transaction, error)) *ArbSysInterface_WithdrawEth_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewArbSysInterface creates a new instance of ArbSysInterface. 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 NewArbSysInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ArbSysInterface {
+ mock := &ArbSysInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_l2_arbitrum_gateway/l2_arbitrum_gateway_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_l2_arbitrum_gateway/l2_arbitrum_gateway_interface.go
new file mode 100644
index 00000000000..6ed290e9125
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_l2_arbitrum_gateway/l2_arbitrum_gateway_interface.go
@@ -0,0 +1,1238 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_l2_arbitrum_gateway
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ l2_arbitrum_gateway "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_gateway"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// L2ArbitrumGatewayInterface is an autogenerated mock type for the L2ArbitrumGatewayInterface type
+type L2ArbitrumGatewayInterface struct {
+ mock.Mock
+}
+
+type L2ArbitrumGatewayInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *L2ArbitrumGatewayInterface) EXPECT() *L2ArbitrumGatewayInterface_Expecter {
+ return &L2ArbitrumGatewayInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *L2ArbitrumGatewayInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// L2ArbitrumGatewayInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type L2ArbitrumGatewayInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *L2ArbitrumGatewayInterface_Expecter) Address() *L2ArbitrumGatewayInterface_Address_Call {
+ return &L2ArbitrumGatewayInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *L2ArbitrumGatewayInterface_Address_Call) Run(run func()) *L2ArbitrumGatewayInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_Address_Call) Return(_a0 common.Address) *L2ArbitrumGatewayInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_Address_Call) RunAndReturn(run func() common.Address) *L2ArbitrumGatewayInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CalculateL2TokenAddress provides a mock function with given fields: opts, l1ERC20
+func (_m *L2ArbitrumGatewayInterface) CalculateL2TokenAddress(opts *bind.CallOpts, l1ERC20 common.Address) (common.Address, error) {
+ ret := _m.Called(opts, l1ERC20)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CalculateL2TokenAddress")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok {
+ return rf(opts, l1ERC20)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) common.Address); ok {
+ r0 = rf(opts, l1ERC20)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address) error); ok {
+ r1 = rf(opts, l1ERC20)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CalculateL2TokenAddress'
+type L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call struct {
+ *mock.Call
+}
+
+// CalculateL2TokenAddress is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - l1ERC20 common.Address
+func (_e *L2ArbitrumGatewayInterface_Expecter) CalculateL2TokenAddress(opts interface{}, l1ERC20 interface{}) *L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call {
+ return &L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call{Call: _e.mock.On("CalculateL2TokenAddress", opts, l1ERC20)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call) Run(run func(opts *bind.CallOpts, l1ERC20 common.Address)) *L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call) Return(_a0 common.Address, _a1 error) *L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call) RunAndReturn(run func(*bind.CallOpts, common.Address) (common.Address, error)) *L2ArbitrumGatewayInterface_CalculateL2TokenAddress_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CounterpartGateway provides a mock function with given fields: opts
+func (_m *L2ArbitrumGatewayInterface) CounterpartGateway(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CounterpartGateway")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_CounterpartGateway_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CounterpartGateway'
+type L2ArbitrumGatewayInterface_CounterpartGateway_Call struct {
+ *mock.Call
+}
+
+// CounterpartGateway is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *L2ArbitrumGatewayInterface_Expecter) CounterpartGateway(opts interface{}) *L2ArbitrumGatewayInterface_CounterpartGateway_Call {
+ return &L2ArbitrumGatewayInterface_CounterpartGateway_Call{Call: _e.mock.On("CounterpartGateway", opts)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_CounterpartGateway_Call) Run(run func(opts *bind.CallOpts)) *L2ArbitrumGatewayInterface_CounterpartGateway_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_CounterpartGateway_Call) Return(_a0 common.Address, _a1 error) *L2ArbitrumGatewayInterface_CounterpartGateway_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_CounterpartGateway_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *L2ArbitrumGatewayInterface_CounterpartGateway_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ExitNum provides a mock function with given fields: opts
+func (_m *L2ArbitrumGatewayInterface) ExitNum(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExitNum")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_ExitNum_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExitNum'
+type L2ArbitrumGatewayInterface_ExitNum_Call struct {
+ *mock.Call
+}
+
+// ExitNum is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *L2ArbitrumGatewayInterface_Expecter) ExitNum(opts interface{}) *L2ArbitrumGatewayInterface_ExitNum_Call {
+ return &L2ArbitrumGatewayInterface_ExitNum_Call{Call: _e.mock.On("ExitNum", opts)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_ExitNum_Call) Run(run func(opts *bind.CallOpts)) *L2ArbitrumGatewayInterface_ExitNum_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ExitNum_Call) Return(_a0 *big.Int, _a1 error) *L2ArbitrumGatewayInterface_ExitNum_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ExitNum_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *L2ArbitrumGatewayInterface_ExitNum_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterDepositFinalized provides a mock function with given fields: opts, l1Token, _from, _to
+func (_m *L2ArbitrumGatewayInterface) FilterDepositFinalized(opts *bind.FilterOpts, l1Token []common.Address, _from []common.Address, _to []common.Address) (*l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalizedIterator, error) {
+ ret := _m.Called(opts, l1Token, _from, _to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterDepositFinalized")
+ }
+
+ var r0 *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalizedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalizedIterator, error)); ok {
+ return rf(opts, l1Token, _from, _to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalizedIterator); ok {
+ r0 = rf(opts, l1Token, _from, _to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalizedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, l1Token, _from, _to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_FilterDepositFinalized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterDepositFinalized'
+type L2ArbitrumGatewayInterface_FilterDepositFinalized_Call struct {
+ *mock.Call
+}
+
+// FilterDepositFinalized is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - l1Token []common.Address
+// - _from []common.Address
+// - _to []common.Address
+func (_e *L2ArbitrumGatewayInterface_Expecter) FilterDepositFinalized(opts interface{}, l1Token interface{}, _from interface{}, _to interface{}) *L2ArbitrumGatewayInterface_FilterDepositFinalized_Call {
+ return &L2ArbitrumGatewayInterface_FilterDepositFinalized_Call{Call: _e.mock.On("FilterDepositFinalized", opts, l1Token, _from, _to)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterDepositFinalized_Call) Run(run func(opts *bind.FilterOpts, l1Token []common.Address, _from []common.Address, _to []common.Address)) *L2ArbitrumGatewayInterface_FilterDepositFinalized_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterDepositFinalized_Call) Return(_a0 *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalizedIterator, _a1 error) *L2ArbitrumGatewayInterface_FilterDepositFinalized_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterDepositFinalized_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalizedIterator, error)) *L2ArbitrumGatewayInterface_FilterDepositFinalized_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTxToL1 provides a mock function with given fields: opts, _from, _to, _id
+func (_m *L2ArbitrumGatewayInterface) FilterTxToL1(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _id []*big.Int) (*l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1Iterator, error) {
+ ret := _m.Called(opts, _from, _to, _id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTxToL1")
+ }
+
+ var r0 *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1Iterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) (*l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1Iterator, error)); ok {
+ return rf(opts, _from, _to, _id)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1Iterator); ok {
+ r0 = rf(opts, _from, _to, _id)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1Iterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) error); ok {
+ r1 = rf(opts, _from, _to, _id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_FilterTxToL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTxToL1'
+type L2ArbitrumGatewayInterface_FilterTxToL1_Call struct {
+ *mock.Call
+}
+
+// FilterTxToL1 is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - _from []common.Address
+// - _to []common.Address
+// - _id []*big.Int
+func (_e *L2ArbitrumGatewayInterface_Expecter) FilterTxToL1(opts interface{}, _from interface{}, _to interface{}, _id interface{}) *L2ArbitrumGatewayInterface_FilterTxToL1_Call {
+ return &L2ArbitrumGatewayInterface_FilterTxToL1_Call{Call: _e.mock.On("FilterTxToL1", opts, _from, _to, _id)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterTxToL1_Call) Run(run func(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _id []*big.Int)) *L2ArbitrumGatewayInterface_FilterTxToL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterTxToL1_Call) Return(_a0 *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1Iterator, _a1 error) *L2ArbitrumGatewayInterface_FilterTxToL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterTxToL1_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) (*l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1Iterator, error)) *L2ArbitrumGatewayInterface_FilterTxToL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterWithdrawalInitiated provides a mock function with given fields: opts, _from, _to, _l2ToL1Id
+func (_m *L2ArbitrumGatewayInterface) FilterWithdrawalInitiated(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _l2ToL1Id []*big.Int) (*l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiatedIterator, error) {
+ ret := _m.Called(opts, _from, _to, _l2ToL1Id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterWithdrawalInitiated")
+ }
+
+ var r0 *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiatedIterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) (*l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiatedIterator, error)); ok {
+ return rf(opts, _from, _to, _l2ToL1Id)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiatedIterator); ok {
+ r0 = rf(opts, _from, _to, _l2ToL1Id)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiatedIterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) error); ok {
+ r1 = rf(opts, _from, _to, _l2ToL1Id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterWithdrawalInitiated'
+type L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call struct {
+ *mock.Call
+}
+
+// FilterWithdrawalInitiated is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - _from []common.Address
+// - _to []common.Address
+// - _l2ToL1Id []*big.Int
+func (_e *L2ArbitrumGatewayInterface_Expecter) FilterWithdrawalInitiated(opts interface{}, _from interface{}, _to interface{}, _l2ToL1Id interface{}) *L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call {
+ return &L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call{Call: _e.mock.On("FilterWithdrawalInitiated", opts, _from, _to, _l2ToL1Id)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call) Run(run func(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _l2ToL1Id []*big.Int)) *L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call) Return(_a0 *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiatedIterator, _a1 error) *L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) (*l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiatedIterator, error)) *L2ArbitrumGatewayInterface_FilterWithdrawalInitiated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FinalizeInboundTransfer provides a mock function with given fields: opts, _token, _from, _to, _amount, _data
+func (_m *L2ArbitrumGatewayInterface) FinalizeInboundTransfer(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, _token, _from, _to, _amount, _data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FinalizeInboundTransfer")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, _token, _from, _to, _amount, _data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, _token, _from, _to, _amount, _data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, _token, _from, _to, _amount, _data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FinalizeInboundTransfer'
+type L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call struct {
+ *mock.Call
+}
+
+// FinalizeInboundTransfer is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _token common.Address
+// - _from common.Address
+// - _to common.Address
+// - _amount *big.Int
+// - _data []byte
+func (_e *L2ArbitrumGatewayInterface_Expecter) FinalizeInboundTransfer(opts interface{}, _token interface{}, _from interface{}, _to interface{}, _amount interface{}, _data interface{}) *L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call {
+ return &L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call{Call: _e.mock.On("FinalizeInboundTransfer", opts, _token, _from, _to, _amount, _data)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call) Run(run func(opts *bind.TransactOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte)) *L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(common.Address), args[4].(*big.Int), args[5].([]byte))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call) Return(_a0 *types.Transaction, _a1 error) *L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)) *L2ArbitrumGatewayInterface_FinalizeInboundTransfer_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetOutboundCalldata provides a mock function with given fields: opts, _token, _from, _to, _amount, _data
+func (_m *L2ArbitrumGatewayInterface) GetOutboundCalldata(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte) ([]byte, error) {
+ ret := _m.Called(opts, _token, _from, _to, _amount, _data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetOutboundCalldata")
+ }
+
+ var r0 []byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address, common.Address, *big.Int, []byte) ([]byte, error)); ok {
+ return rf(opts, _token, _from, _to, _amount, _data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, common.Address, common.Address, *big.Int, []byte) []byte); ok {
+ r0 = rf(opts, _token, _from, _to, _amount, _data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, common.Address, common.Address, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, _token, _from, _to, _amount, _data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_GetOutboundCalldata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOutboundCalldata'
+type L2ArbitrumGatewayInterface_GetOutboundCalldata_Call struct {
+ *mock.Call
+}
+
+// GetOutboundCalldata is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - _token common.Address
+// - _from common.Address
+// - _to common.Address
+// - _amount *big.Int
+// - _data []byte
+func (_e *L2ArbitrumGatewayInterface_Expecter) GetOutboundCalldata(opts interface{}, _token interface{}, _from interface{}, _to interface{}, _amount interface{}, _data interface{}) *L2ArbitrumGatewayInterface_GetOutboundCalldata_Call {
+ return &L2ArbitrumGatewayInterface_GetOutboundCalldata_Call{Call: _e.mock.On("GetOutboundCalldata", opts, _token, _from, _to, _amount, _data)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_GetOutboundCalldata_Call) Run(run func(opts *bind.CallOpts, _token common.Address, _from common.Address, _to common.Address, _amount *big.Int, _data []byte)) *L2ArbitrumGatewayInterface_GetOutboundCalldata_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(common.Address), args[2].(common.Address), args[3].(common.Address), args[4].(*big.Int), args[5].([]byte))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_GetOutboundCalldata_Call) Return(_a0 []byte, _a1 error) *L2ArbitrumGatewayInterface_GetOutboundCalldata_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_GetOutboundCalldata_Call) RunAndReturn(run func(*bind.CallOpts, common.Address, common.Address, common.Address, *big.Int, []byte) ([]byte, error)) *L2ArbitrumGatewayInterface_GetOutboundCalldata_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// OutboundTransfer provides a mock function with given fields: opts, _l1Token, _to, _amount, _data
+func (_m *L2ArbitrumGatewayInterface) OutboundTransfer(opts *bind.TransactOpts, _l1Token common.Address, _to common.Address, _amount *big.Int, _data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, _l1Token, _to, _amount, _data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OutboundTransfer")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, _l1Token, _to, _amount, _data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, _l1Token, _to, _amount, _data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, []byte) error); ok {
+ r1 = rf(opts, _l1Token, _to, _amount, _data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_OutboundTransfer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OutboundTransfer'
+type L2ArbitrumGatewayInterface_OutboundTransfer_Call struct {
+ *mock.Call
+}
+
+// OutboundTransfer is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _l1Token common.Address
+// - _to common.Address
+// - _amount *big.Int
+// - _data []byte
+func (_e *L2ArbitrumGatewayInterface_Expecter) OutboundTransfer(opts interface{}, _l1Token interface{}, _to interface{}, _amount interface{}, _data interface{}) *L2ArbitrumGatewayInterface_OutboundTransfer_Call {
+ return &L2ArbitrumGatewayInterface_OutboundTransfer_Call{Call: _e.mock.On("OutboundTransfer", opts, _l1Token, _to, _amount, _data)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_OutboundTransfer_Call) Run(run func(opts *bind.TransactOpts, _l1Token common.Address, _to common.Address, _amount *big.Int, _data []byte)) *L2ArbitrumGatewayInterface_OutboundTransfer_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(*big.Int), args[4].([]byte))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_OutboundTransfer_Call) Return(_a0 *types.Transaction, _a1 error) *L2ArbitrumGatewayInterface_OutboundTransfer_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_OutboundTransfer_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, *big.Int, []byte) (*types.Transaction, error)) *L2ArbitrumGatewayInterface_OutboundTransfer_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// OutboundTransfer0 provides a mock function with given fields: opts, _l1Token, _to, _amount, arg3, arg4, _data
+func (_m *L2ArbitrumGatewayInterface) OutboundTransfer0(opts *bind.TransactOpts, _l1Token common.Address, _to common.Address, _amount *big.Int, arg3 *big.Int, arg4 *big.Int, _data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, _l1Token, _to, _amount, arg3, arg4, _data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OutboundTransfer0")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, *big.Int, *big.Int, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, _l1Token, _to, _amount, arg3, arg4, _data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, *big.Int, *big.Int, []byte) *types.Transaction); ok {
+ r0 = rf(opts, _l1Token, _to, _amount, arg3, arg4, _data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int, *big.Int, *big.Int, []byte) error); ok {
+ r1 = rf(opts, _l1Token, _to, _amount, arg3, arg4, _data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_OutboundTransfer0_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OutboundTransfer0'
+type L2ArbitrumGatewayInterface_OutboundTransfer0_Call struct {
+ *mock.Call
+}
+
+// OutboundTransfer0 is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _l1Token common.Address
+// - _to common.Address
+// - _amount *big.Int
+// - arg3 *big.Int
+// - arg4 *big.Int
+// - _data []byte
+func (_e *L2ArbitrumGatewayInterface_Expecter) OutboundTransfer0(opts interface{}, _l1Token interface{}, _to interface{}, _amount interface{}, arg3 interface{}, arg4 interface{}, _data interface{}) *L2ArbitrumGatewayInterface_OutboundTransfer0_Call {
+ return &L2ArbitrumGatewayInterface_OutboundTransfer0_Call{Call: _e.mock.On("OutboundTransfer0", opts, _l1Token, _to, _amount, arg3, arg4, _data)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_OutboundTransfer0_Call) Run(run func(opts *bind.TransactOpts, _l1Token common.Address, _to common.Address, _amount *big.Int, arg3 *big.Int, arg4 *big.Int, _data []byte)) *L2ArbitrumGatewayInterface_OutboundTransfer0_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(common.Address), args[3].(*big.Int), args[4].(*big.Int), args[5].(*big.Int), args[6].([]byte))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_OutboundTransfer0_Call) Return(_a0 *types.Transaction, _a1 error) *L2ArbitrumGatewayInterface_OutboundTransfer0_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_OutboundTransfer0_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, common.Address, *big.Int, *big.Int, *big.Int, []byte) (*types.Transaction, error)) *L2ArbitrumGatewayInterface_OutboundTransfer0_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseDepositFinalized provides a mock function with given fields: log
+func (_m *L2ArbitrumGatewayInterface) ParseDepositFinalized(log types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseDepositFinalized")
+ }
+
+ var r0 *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_ParseDepositFinalized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseDepositFinalized'
+type L2ArbitrumGatewayInterface_ParseDepositFinalized_Call struct {
+ *mock.Call
+}
+
+// ParseDepositFinalized is a helper method to define mock.On call
+// - log types.Log
+func (_e *L2ArbitrumGatewayInterface_Expecter) ParseDepositFinalized(log interface{}) *L2ArbitrumGatewayInterface_ParseDepositFinalized_Call {
+ return &L2ArbitrumGatewayInterface_ParseDepositFinalized_Call{Call: _e.mock.On("ParseDepositFinalized", log)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseDepositFinalized_Call) Run(run func(log types.Log)) *L2ArbitrumGatewayInterface_ParseDepositFinalized_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseDepositFinalized_Call) Return(_a0 *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, _a1 error) *L2ArbitrumGatewayInterface_ParseDepositFinalized_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseDepositFinalized_Call) RunAndReturn(run func(types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, error)) *L2ArbitrumGatewayInterface_ParseDepositFinalized_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *L2ArbitrumGatewayInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type L2ArbitrumGatewayInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *L2ArbitrumGatewayInterface_Expecter) ParseLog(log interface{}) *L2ArbitrumGatewayInterface_ParseLog_Call {
+ return &L2ArbitrumGatewayInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseLog_Call) Run(run func(log types.Log)) *L2ArbitrumGatewayInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *L2ArbitrumGatewayInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *L2ArbitrumGatewayInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTxToL1 provides a mock function with given fields: log
+func (_m *L2ArbitrumGatewayInterface) ParseTxToL1(log types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTxToL1")
+ }
+
+ var r0 *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_ParseTxToL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTxToL1'
+type L2ArbitrumGatewayInterface_ParseTxToL1_Call struct {
+ *mock.Call
+}
+
+// ParseTxToL1 is a helper method to define mock.On call
+// - log types.Log
+func (_e *L2ArbitrumGatewayInterface_Expecter) ParseTxToL1(log interface{}) *L2ArbitrumGatewayInterface_ParseTxToL1_Call {
+ return &L2ArbitrumGatewayInterface_ParseTxToL1_Call{Call: _e.mock.On("ParseTxToL1", log)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseTxToL1_Call) Run(run func(log types.Log)) *L2ArbitrumGatewayInterface_ParseTxToL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseTxToL1_Call) Return(_a0 *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, _a1 error) *L2ArbitrumGatewayInterface_ParseTxToL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseTxToL1_Call) RunAndReturn(run func(types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, error)) *L2ArbitrumGatewayInterface_ParseTxToL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseWithdrawalInitiated provides a mock function with given fields: log
+func (_m *L2ArbitrumGatewayInterface) ParseWithdrawalInitiated(log types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseWithdrawalInitiated")
+ }
+
+ var r0 *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseWithdrawalInitiated'
+type L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call struct {
+ *mock.Call
+}
+
+// ParseWithdrawalInitiated is a helper method to define mock.On call
+// - log types.Log
+func (_e *L2ArbitrumGatewayInterface_Expecter) ParseWithdrawalInitiated(log interface{}) *L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call {
+ return &L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call{Call: _e.mock.On("ParseWithdrawalInitiated", log)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call) Run(run func(log types.Log)) *L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call) Return(_a0 *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, _a1 error) *L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call) RunAndReturn(run func(types.Log) (*l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, error)) *L2ArbitrumGatewayInterface_ParseWithdrawalInitiated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// PostUpgradeInit provides a mock function with given fields: opts
+func (_m *L2ArbitrumGatewayInterface) PostUpgradeInit(opts *bind.TransactOpts) (*types.Transaction, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for PostUpgradeInit")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts) *types.Transaction); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_PostUpgradeInit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PostUpgradeInit'
+type L2ArbitrumGatewayInterface_PostUpgradeInit_Call struct {
+ *mock.Call
+}
+
+// PostUpgradeInit is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+func (_e *L2ArbitrumGatewayInterface_Expecter) PostUpgradeInit(opts interface{}) *L2ArbitrumGatewayInterface_PostUpgradeInit_Call {
+ return &L2ArbitrumGatewayInterface_PostUpgradeInit_Call{Call: _e.mock.On("PostUpgradeInit", opts)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_PostUpgradeInit_Call) Run(run func(opts *bind.TransactOpts)) *L2ArbitrumGatewayInterface_PostUpgradeInit_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_PostUpgradeInit_Call) Return(_a0 *types.Transaction, _a1 error) *L2ArbitrumGatewayInterface_PostUpgradeInit_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_PostUpgradeInit_Call) RunAndReturn(run func(*bind.TransactOpts) (*types.Transaction, error)) *L2ArbitrumGatewayInterface_PostUpgradeInit_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Router provides a mock function with given fields: opts
+func (_m *L2ArbitrumGatewayInterface) Router(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Router")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_Router_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Router'
+type L2ArbitrumGatewayInterface_Router_Call struct {
+ *mock.Call
+}
+
+// Router is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *L2ArbitrumGatewayInterface_Expecter) Router(opts interface{}) *L2ArbitrumGatewayInterface_Router_Call {
+ return &L2ArbitrumGatewayInterface_Router_Call{Call: _e.mock.On("Router", opts)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_Router_Call) Run(run func(opts *bind.CallOpts)) *L2ArbitrumGatewayInterface_Router_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_Router_Call) Return(_a0 common.Address, _a1 error) *L2ArbitrumGatewayInterface_Router_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_Router_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *L2ArbitrumGatewayInterface_Router_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchDepositFinalized provides a mock function with given fields: opts, sink, l1Token, _from, _to
+func (_m *L2ArbitrumGatewayInterface) WatchDepositFinalized(opts *bind.WatchOpts, sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, l1Token []common.Address, _from []common.Address, _to []common.Address) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, l1Token, _from, _to)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchDepositFinalized")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok {
+ return rf(opts, sink, l1Token, _from, _to)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, []common.Address, []common.Address, []common.Address) event.Subscription); ok {
+ r0 = rf(opts, sink, l1Token, _from, _to)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, []common.Address, []common.Address, []common.Address) error); ok {
+ r1 = rf(opts, sink, l1Token, _from, _to)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_WatchDepositFinalized_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchDepositFinalized'
+type L2ArbitrumGatewayInterface_WatchDepositFinalized_Call struct {
+ *mock.Call
+}
+
+// WatchDepositFinalized is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized
+// - l1Token []common.Address
+// - _from []common.Address
+// - _to []common.Address
+func (_e *L2ArbitrumGatewayInterface_Expecter) WatchDepositFinalized(opts interface{}, sink interface{}, l1Token interface{}, _from interface{}, _to interface{}) *L2ArbitrumGatewayInterface_WatchDepositFinalized_Call {
+ return &L2ArbitrumGatewayInterface_WatchDepositFinalized_Call{Call: _e.mock.On("WatchDepositFinalized", opts, sink, l1Token, _from, _to)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchDepositFinalized_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, l1Token []common.Address, _from []common.Address, _to []common.Address)) *L2ArbitrumGatewayInterface_WatchDepositFinalized_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized), args[2].([]common.Address), args[3].([]common.Address), args[4].([]common.Address))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchDepositFinalized_Call) Return(_a0 event.Subscription, _a1 error) *L2ArbitrumGatewayInterface_WatchDepositFinalized_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchDepositFinalized_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayDepositFinalized, []common.Address, []common.Address, []common.Address) (event.Subscription, error)) *L2ArbitrumGatewayInterface_WatchDepositFinalized_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTxToL1 provides a mock function with given fields: opts, sink, _from, _to, _id
+func (_m *L2ArbitrumGatewayInterface) WatchTxToL1(opts *bind.WatchOpts, sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, _from []common.Address, _to []common.Address, _id []*big.Int) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, _from, _to, _id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTxToL1")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, []common.Address, []common.Address, []*big.Int) (event.Subscription, error)); ok {
+ return rf(opts, sink, _from, _to, _id)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, []common.Address, []common.Address, []*big.Int) event.Subscription); ok {
+ r0 = rf(opts, sink, _from, _to, _id)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, []common.Address, []common.Address, []*big.Int) error); ok {
+ r1 = rf(opts, sink, _from, _to, _id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_WatchTxToL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTxToL1'
+type L2ArbitrumGatewayInterface_WatchTxToL1_Call struct {
+ *mock.Call
+}
+
+// WatchTxToL1 is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1
+// - _from []common.Address
+// - _to []common.Address
+// - _id []*big.Int
+func (_e *L2ArbitrumGatewayInterface_Expecter) WatchTxToL1(opts interface{}, sink interface{}, _from interface{}, _to interface{}, _id interface{}) *L2ArbitrumGatewayInterface_WatchTxToL1_Call {
+ return &L2ArbitrumGatewayInterface_WatchTxToL1_Call{Call: _e.mock.On("WatchTxToL1", opts, sink, _from, _to, _id)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchTxToL1_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, _from []common.Address, _to []common.Address, _id []*big.Int)) *L2ArbitrumGatewayInterface_WatchTxToL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1), args[2].([]common.Address), args[3].([]common.Address), args[4].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchTxToL1_Call) Return(_a0 event.Subscription, _a1 error) *L2ArbitrumGatewayInterface_WatchTxToL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchTxToL1_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayTxToL1, []common.Address, []common.Address, []*big.Int) (event.Subscription, error)) *L2ArbitrumGatewayInterface_WatchTxToL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchWithdrawalInitiated provides a mock function with given fields: opts, sink, _from, _to, _l2ToL1Id
+func (_m *L2ArbitrumGatewayInterface) WatchWithdrawalInitiated(opts *bind.WatchOpts, sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, _from []common.Address, _to []common.Address, _l2ToL1Id []*big.Int) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, _from, _to, _l2ToL1Id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchWithdrawalInitiated")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, []common.Address, []common.Address, []*big.Int) (event.Subscription, error)); ok {
+ return rf(opts, sink, _from, _to, _l2ToL1Id)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, []common.Address, []common.Address, []*big.Int) event.Subscription); ok {
+ r0 = rf(opts, sink, _from, _to, _l2ToL1Id)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, []common.Address, []common.Address, []*big.Int) error); ok {
+ r1 = rf(opts, sink, _from, _to, _l2ToL1Id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchWithdrawalInitiated'
+type L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call struct {
+ *mock.Call
+}
+
+// WatchWithdrawalInitiated is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated
+// - _from []common.Address
+// - _to []common.Address
+// - _l2ToL1Id []*big.Int
+func (_e *L2ArbitrumGatewayInterface_Expecter) WatchWithdrawalInitiated(opts interface{}, sink interface{}, _from interface{}, _to interface{}, _l2ToL1Id interface{}) *L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call {
+ return &L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call{Call: _e.mock.On("WatchWithdrawalInitiated", opts, sink, _from, _to, _l2ToL1Id)}
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, _from []common.Address, _to []common.Address, _l2ToL1Id []*big.Int)) *L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated), args[2].([]common.Address), args[3].([]common.Address), args[4].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call) Return(_a0 event.Subscription, _a1 error) *L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *l2_arbitrum_gateway.L2ArbitrumGatewayWithdrawalInitiated, []common.Address, []common.Address, []*big.Int) (event.Subscription, error)) *L2ArbitrumGatewayInterface_WatchWithdrawalInitiated_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewL2ArbitrumGatewayInterface creates a new instance of L2ArbitrumGatewayInterface. 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 NewL2ArbitrumGatewayInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *L2ArbitrumGatewayInterface {
+ mock := &L2ArbitrumGatewayInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_l2_arbitrum_messenger/l2_arbitrum_messenger_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_l2_arbitrum_messenger/l2_arbitrum_messenger_interface.go
new file mode 100644
index 00000000000..126f870685b
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_l2_arbitrum_messenger/l2_arbitrum_messenger_interface.go
@@ -0,0 +1,333 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_l2_arbitrum_messenger
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ event "github.com/ethereum/go-ethereum/event"
+
+ generated "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+
+ l2_arbitrum_messenger "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/l2_arbitrum_messenger"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// L2ArbitrumMessengerInterface is an autogenerated mock type for the L2ArbitrumMessengerInterface type
+type L2ArbitrumMessengerInterface struct {
+ mock.Mock
+}
+
+type L2ArbitrumMessengerInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *L2ArbitrumMessengerInterface) EXPECT() *L2ArbitrumMessengerInterface_Expecter {
+ return &L2ArbitrumMessengerInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *L2ArbitrumMessengerInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// L2ArbitrumMessengerInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type L2ArbitrumMessengerInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *L2ArbitrumMessengerInterface_Expecter) Address() *L2ArbitrumMessengerInterface_Address_Call {
+ return &L2ArbitrumMessengerInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *L2ArbitrumMessengerInterface_Address_Call) Run(run func()) *L2ArbitrumMessengerInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_Address_Call) Return(_a0 common.Address) *L2ArbitrumMessengerInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_Address_Call) RunAndReturn(run func() common.Address) *L2ArbitrumMessengerInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterTxToL1 provides a mock function with given fields: opts, _from, _to, _id
+func (_m *L2ArbitrumMessengerInterface) FilterTxToL1(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _id []*big.Int) (*l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1Iterator, error) {
+ ret := _m.Called(opts, _from, _to, _id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterTxToL1")
+ }
+
+ var r0 *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1Iterator
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) (*l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1Iterator, error)); ok {
+ return rf(opts, _from, _to, _id)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1Iterator); ok {
+ r0 = rf(opts, _from, _to, _id)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1Iterator)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) error); ok {
+ r1 = rf(opts, _from, _to, _id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumMessengerInterface_FilterTxToL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterTxToL1'
+type L2ArbitrumMessengerInterface_FilterTxToL1_Call struct {
+ *mock.Call
+}
+
+// FilterTxToL1 is a helper method to define mock.On call
+// - opts *bind.FilterOpts
+// - _from []common.Address
+// - _to []common.Address
+// - _id []*big.Int
+func (_e *L2ArbitrumMessengerInterface_Expecter) FilterTxToL1(opts interface{}, _from interface{}, _to interface{}, _id interface{}) *L2ArbitrumMessengerInterface_FilterTxToL1_Call {
+ return &L2ArbitrumMessengerInterface_FilterTxToL1_Call{Call: _e.mock.On("FilterTxToL1", opts, _from, _to, _id)}
+}
+
+func (_c *L2ArbitrumMessengerInterface_FilterTxToL1_Call) Run(run func(opts *bind.FilterOpts, _from []common.Address, _to []common.Address, _id []*big.Int)) *L2ArbitrumMessengerInterface_FilterTxToL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.FilterOpts), args[1].([]common.Address), args[2].([]common.Address), args[3].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_FilterTxToL1_Call) Return(_a0 *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1Iterator, _a1 error) *L2ArbitrumMessengerInterface_FilterTxToL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_FilterTxToL1_Call) RunAndReturn(run func(*bind.FilterOpts, []common.Address, []common.Address, []*big.Int) (*l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1Iterator, error)) *L2ArbitrumMessengerInterface_FilterTxToL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseLog provides a mock function with given fields: log
+func (_m *L2ArbitrumMessengerInterface) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseLog")
+ }
+
+ var r0 generated.AbigenLog
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) generated.AbigenLog); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(generated.AbigenLog)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumMessengerInterface_ParseLog_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseLog'
+type L2ArbitrumMessengerInterface_ParseLog_Call struct {
+ *mock.Call
+}
+
+// ParseLog is a helper method to define mock.On call
+// - log types.Log
+func (_e *L2ArbitrumMessengerInterface_Expecter) ParseLog(log interface{}) *L2ArbitrumMessengerInterface_ParseLog_Call {
+ return &L2ArbitrumMessengerInterface_ParseLog_Call{Call: _e.mock.On("ParseLog", log)}
+}
+
+func (_c *L2ArbitrumMessengerInterface_ParseLog_Call) Run(run func(log types.Log)) *L2ArbitrumMessengerInterface_ParseLog_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_ParseLog_Call) Return(_a0 generated.AbigenLog, _a1 error) *L2ArbitrumMessengerInterface_ParseLog_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_ParseLog_Call) RunAndReturn(run func(types.Log) (generated.AbigenLog, error)) *L2ArbitrumMessengerInterface_ParseLog_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ParseTxToL1 provides a mock function with given fields: log
+func (_m *L2ArbitrumMessengerInterface) ParseTxToL1(log types.Log) (*l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, error) {
+ ret := _m.Called(log)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ParseTxToL1")
+ }
+
+ var r0 *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1
+ var r1 error
+ if rf, ok := ret.Get(0).(func(types.Log) (*l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, error)); ok {
+ return rf(log)
+ }
+ if rf, ok := ret.Get(0).(func(types.Log) *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1); ok {
+ r0 = rf(log)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(types.Log) error); ok {
+ r1 = rf(log)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumMessengerInterface_ParseTxToL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ParseTxToL1'
+type L2ArbitrumMessengerInterface_ParseTxToL1_Call struct {
+ *mock.Call
+}
+
+// ParseTxToL1 is a helper method to define mock.On call
+// - log types.Log
+func (_e *L2ArbitrumMessengerInterface_Expecter) ParseTxToL1(log interface{}) *L2ArbitrumMessengerInterface_ParseTxToL1_Call {
+ return &L2ArbitrumMessengerInterface_ParseTxToL1_Call{Call: _e.mock.On("ParseTxToL1", log)}
+}
+
+func (_c *L2ArbitrumMessengerInterface_ParseTxToL1_Call) Run(run func(log types.Log)) *L2ArbitrumMessengerInterface_ParseTxToL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(types.Log))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_ParseTxToL1_Call) Return(_a0 *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, _a1 error) *L2ArbitrumMessengerInterface_ParseTxToL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_ParseTxToL1_Call) RunAndReturn(run func(types.Log) (*l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, error)) *L2ArbitrumMessengerInterface_ParseTxToL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// WatchTxToL1 provides a mock function with given fields: opts, sink, _from, _to, _id
+func (_m *L2ArbitrumMessengerInterface) WatchTxToL1(opts *bind.WatchOpts, sink chan<- *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, _from []common.Address, _to []common.Address, _id []*big.Int) (event.Subscription, error) {
+ ret := _m.Called(opts, sink, _from, _to, _id)
+
+ if len(ret) == 0 {
+ panic("no return value specified for WatchTxToL1")
+ }
+
+ var r0 event.Subscription
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, []common.Address, []common.Address, []*big.Int) (event.Subscription, error)); ok {
+ return rf(opts, sink, _from, _to, _id)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, []common.Address, []common.Address, []*big.Int) event.Subscription); ok {
+ r0 = rf(opts, sink, _from, _to, _id)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(event.Subscription)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.WatchOpts, chan<- *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, []common.Address, []common.Address, []*big.Int) error); ok {
+ r1 = rf(opts, sink, _from, _to, _id)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// L2ArbitrumMessengerInterface_WatchTxToL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WatchTxToL1'
+type L2ArbitrumMessengerInterface_WatchTxToL1_Call struct {
+ *mock.Call
+}
+
+// WatchTxToL1 is a helper method to define mock.On call
+// - opts *bind.WatchOpts
+// - sink chan<- *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1
+// - _from []common.Address
+// - _to []common.Address
+// - _id []*big.Int
+func (_e *L2ArbitrumMessengerInterface_Expecter) WatchTxToL1(opts interface{}, sink interface{}, _from interface{}, _to interface{}, _id interface{}) *L2ArbitrumMessengerInterface_WatchTxToL1_Call {
+ return &L2ArbitrumMessengerInterface_WatchTxToL1_Call{Call: _e.mock.On("WatchTxToL1", opts, sink, _from, _to, _id)}
+}
+
+func (_c *L2ArbitrumMessengerInterface_WatchTxToL1_Call) Run(run func(opts *bind.WatchOpts, sink chan<- *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, _from []common.Address, _to []common.Address, _id []*big.Int)) *L2ArbitrumMessengerInterface_WatchTxToL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.WatchOpts), args[1].(chan<- *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1), args[2].([]common.Address), args[3].([]common.Address), args[4].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_WatchTxToL1_Call) Return(_a0 event.Subscription, _a1 error) *L2ArbitrumMessengerInterface_WatchTxToL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *L2ArbitrumMessengerInterface_WatchTxToL1_Call) RunAndReturn(run func(*bind.WatchOpts, chan<- *l2_arbitrum_messenger.L2ArbitrumMessengerTxToL1, []common.Address, []common.Address, []*big.Int) (event.Subscription, error)) *L2ArbitrumMessengerInterface_WatchTxToL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewL2ArbitrumMessengerInterface creates a new instance of L2ArbitrumMessengerInterface. 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 NewL2ArbitrumMessengerInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *L2ArbitrumMessengerInterface {
+ mock := &L2ArbitrumMessengerInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_node_interface/node_interface_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_node_interface/node_interface_interface.go
new file mode 100644
index 00000000000..8210f1050e7
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_node_interface/node_interface_interface.go
@@ -0,0 +1,680 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_node_interface
+
+import (
+ big "math/big"
+
+ arb_node_interface "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/arb_node_interface"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+
+ common "github.com/ethereum/go-ethereum/common"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// NodeInterfaceInterface is an autogenerated mock type for the NodeInterfaceInterface type
+type NodeInterfaceInterface struct {
+ mock.Mock
+}
+
+type NodeInterfaceInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *NodeInterfaceInterface) EXPECT() *NodeInterfaceInterface_Expecter {
+ return &NodeInterfaceInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *NodeInterfaceInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// NodeInterfaceInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type NodeInterfaceInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *NodeInterfaceInterface_Expecter) Address() *NodeInterfaceInterface_Address_Call {
+ return &NodeInterfaceInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *NodeInterfaceInterface_Address_Call) Run(run func()) *NodeInterfaceInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_Address_Call) Return(_a0 common.Address) *NodeInterfaceInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_Address_Call) RunAndReturn(run func() common.Address) *NodeInterfaceInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// BlockL1Num provides a mock function with given fields: opts, l2BlockNum
+func (_m *NodeInterfaceInterface) BlockL1Num(opts *bind.CallOpts, l2BlockNum uint64) (uint64, error) {
+ ret := _m.Called(opts, l2BlockNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for BlockL1Num")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (uint64, error)); ok {
+ return rf(opts, l2BlockNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) uint64); ok {
+ r0 = rf(opts, l2BlockNum)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, l2BlockNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_BlockL1Num_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockL1Num'
+type NodeInterfaceInterface_BlockL1Num_Call struct {
+ *mock.Call
+}
+
+// BlockL1Num is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - l2BlockNum uint64
+func (_e *NodeInterfaceInterface_Expecter) BlockL1Num(opts interface{}, l2BlockNum interface{}) *NodeInterfaceInterface_BlockL1Num_Call {
+ return &NodeInterfaceInterface_BlockL1Num_Call{Call: _e.mock.On("BlockL1Num", opts, l2BlockNum)}
+}
+
+func (_c *NodeInterfaceInterface_BlockL1Num_Call) Run(run func(opts *bind.CallOpts, l2BlockNum uint64)) *NodeInterfaceInterface_BlockL1Num_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_BlockL1Num_Call) Return(_a0 uint64, _a1 error) *NodeInterfaceInterface_BlockL1Num_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_BlockL1Num_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (uint64, error)) *NodeInterfaceInterface_BlockL1Num_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ConstructOutboxProof provides a mock function with given fields: opts, size, leaf
+func (_m *NodeInterfaceInterface) ConstructOutboxProof(opts *bind.CallOpts, size uint64, leaf uint64) (arb_node_interface.ConstructOutboxProof, error) {
+ ret := _m.Called(opts, size, leaf)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ConstructOutboxProof")
+ }
+
+ var r0 arb_node_interface.ConstructOutboxProof
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, uint64) (arb_node_interface.ConstructOutboxProof, error)); ok {
+ return rf(opts, size, leaf)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64, uint64) arb_node_interface.ConstructOutboxProof); ok {
+ r0 = rf(opts, size, leaf)
+ } else {
+ r0 = ret.Get(0).(arb_node_interface.ConstructOutboxProof)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64, uint64) error); ok {
+ r1 = rf(opts, size, leaf)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_ConstructOutboxProof_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ConstructOutboxProof'
+type NodeInterfaceInterface_ConstructOutboxProof_Call struct {
+ *mock.Call
+}
+
+// ConstructOutboxProof is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - size uint64
+// - leaf uint64
+func (_e *NodeInterfaceInterface_Expecter) ConstructOutboxProof(opts interface{}, size interface{}, leaf interface{}) *NodeInterfaceInterface_ConstructOutboxProof_Call {
+ return &NodeInterfaceInterface_ConstructOutboxProof_Call{Call: _e.mock.On("ConstructOutboxProof", opts, size, leaf)}
+}
+
+func (_c *NodeInterfaceInterface_ConstructOutboxProof_Call) Run(run func(opts *bind.CallOpts, size uint64, leaf uint64)) *NodeInterfaceInterface_ConstructOutboxProof_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64), args[2].(uint64))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_ConstructOutboxProof_Call) Return(_a0 arb_node_interface.ConstructOutboxProof, _a1 error) *NodeInterfaceInterface_ConstructOutboxProof_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_ConstructOutboxProof_Call) RunAndReturn(run func(*bind.CallOpts, uint64, uint64) (arb_node_interface.ConstructOutboxProof, error)) *NodeInterfaceInterface_ConstructOutboxProof_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// EstimateRetryableTicket provides a mock function with given fields: opts, sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data
+func (_m *NodeInterfaceInterface) EstimateRetryableTicket(opts *bind.TransactOpts, sender common.Address, deposit *big.Int, to common.Address, l2CallValue *big.Int, excessFeeRefundAddress common.Address, callValueRefundAddress common.Address, data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for EstimateRetryableTicket")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, common.Address, *big.Int, common.Address, common.Address, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, common.Address, *big.Int, common.Address, common.Address, []byte) *types.Transaction); ok {
+ r0 = rf(opts, sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, *big.Int, common.Address, *big.Int, common.Address, common.Address, []byte) error); ok {
+ r1 = rf(opts, sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_EstimateRetryableTicket_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EstimateRetryableTicket'
+type NodeInterfaceInterface_EstimateRetryableTicket_Call struct {
+ *mock.Call
+}
+
+// EstimateRetryableTicket is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - sender common.Address
+// - deposit *big.Int
+// - to common.Address
+// - l2CallValue *big.Int
+// - excessFeeRefundAddress common.Address
+// - callValueRefundAddress common.Address
+// - data []byte
+func (_e *NodeInterfaceInterface_Expecter) EstimateRetryableTicket(opts interface{}, sender interface{}, deposit interface{}, to interface{}, l2CallValue interface{}, excessFeeRefundAddress interface{}, callValueRefundAddress interface{}, data interface{}) *NodeInterfaceInterface_EstimateRetryableTicket_Call {
+ return &NodeInterfaceInterface_EstimateRetryableTicket_Call{Call: _e.mock.On("EstimateRetryableTicket", opts, sender, deposit, to, l2CallValue, excessFeeRefundAddress, callValueRefundAddress, data)}
+}
+
+func (_c *NodeInterfaceInterface_EstimateRetryableTicket_Call) Run(run func(opts *bind.TransactOpts, sender common.Address, deposit *big.Int, to common.Address, l2CallValue *big.Int, excessFeeRefundAddress common.Address, callValueRefundAddress common.Address, data []byte)) *NodeInterfaceInterface_EstimateRetryableTicket_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(*big.Int), args[3].(common.Address), args[4].(*big.Int), args[5].(common.Address), args[6].(common.Address), args[7].([]byte))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_EstimateRetryableTicket_Call) Return(_a0 *types.Transaction, _a1 error) *NodeInterfaceInterface_EstimateRetryableTicket_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_EstimateRetryableTicket_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, *big.Int, common.Address, *big.Int, common.Address, common.Address, []byte) (*types.Transaction, error)) *NodeInterfaceInterface_EstimateRetryableTicket_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FindBatchContainingBlock provides a mock function with given fields: opts, blockNum
+func (_m *NodeInterfaceInterface) FindBatchContainingBlock(opts *bind.CallOpts, blockNum uint64) (uint64, error) {
+ ret := _m.Called(opts, blockNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FindBatchContainingBlock")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (uint64, error)); ok {
+ return rf(opts, blockNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) uint64); ok {
+ r0 = rf(opts, blockNum)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, blockNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_FindBatchContainingBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindBatchContainingBlock'
+type NodeInterfaceInterface_FindBatchContainingBlock_Call struct {
+ *mock.Call
+}
+
+// FindBatchContainingBlock is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - blockNum uint64
+func (_e *NodeInterfaceInterface_Expecter) FindBatchContainingBlock(opts interface{}, blockNum interface{}) *NodeInterfaceInterface_FindBatchContainingBlock_Call {
+ return &NodeInterfaceInterface_FindBatchContainingBlock_Call{Call: _e.mock.On("FindBatchContainingBlock", opts, blockNum)}
+}
+
+func (_c *NodeInterfaceInterface_FindBatchContainingBlock_Call) Run(run func(opts *bind.CallOpts, blockNum uint64)) *NodeInterfaceInterface_FindBatchContainingBlock_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_FindBatchContainingBlock_Call) Return(_a0 uint64, _a1 error) *NodeInterfaceInterface_FindBatchContainingBlock_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_FindBatchContainingBlock_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (uint64, error)) *NodeInterfaceInterface_FindBatchContainingBlock_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GasEstimateComponents provides a mock function with given fields: opts, to, contractCreation, data
+func (_m *NodeInterfaceInterface) GasEstimateComponents(opts *bind.TransactOpts, to common.Address, contractCreation bool, data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, to, contractCreation, data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GasEstimateComponents")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, bool, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, to, contractCreation, data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, bool, []byte) *types.Transaction); ok {
+ r0 = rf(opts, to, contractCreation, data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, bool, []byte) error); ok {
+ r1 = rf(opts, to, contractCreation, data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_GasEstimateComponents_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GasEstimateComponents'
+type NodeInterfaceInterface_GasEstimateComponents_Call struct {
+ *mock.Call
+}
+
+// GasEstimateComponents is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - to common.Address
+// - contractCreation bool
+// - data []byte
+func (_e *NodeInterfaceInterface_Expecter) GasEstimateComponents(opts interface{}, to interface{}, contractCreation interface{}, data interface{}) *NodeInterfaceInterface_GasEstimateComponents_Call {
+ return &NodeInterfaceInterface_GasEstimateComponents_Call{Call: _e.mock.On("GasEstimateComponents", opts, to, contractCreation, data)}
+}
+
+func (_c *NodeInterfaceInterface_GasEstimateComponents_Call) Run(run func(opts *bind.TransactOpts, to common.Address, contractCreation bool, data []byte)) *NodeInterfaceInterface_GasEstimateComponents_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(bool), args[3].([]byte))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_GasEstimateComponents_Call) Return(_a0 *types.Transaction, _a1 error) *NodeInterfaceInterface_GasEstimateComponents_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_GasEstimateComponents_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, bool, []byte) (*types.Transaction, error)) *NodeInterfaceInterface_GasEstimateComponents_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GasEstimateL1Component provides a mock function with given fields: opts, to, contractCreation, data
+func (_m *NodeInterfaceInterface) GasEstimateL1Component(opts *bind.TransactOpts, to common.Address, contractCreation bool, data []byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, to, contractCreation, data)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GasEstimateL1Component")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, bool, []byte) (*types.Transaction, error)); ok {
+ return rf(opts, to, contractCreation, data)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, bool, []byte) *types.Transaction); ok {
+ r0 = rf(opts, to, contractCreation, data)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, common.Address, bool, []byte) error); ok {
+ r1 = rf(opts, to, contractCreation, data)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_GasEstimateL1Component_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GasEstimateL1Component'
+type NodeInterfaceInterface_GasEstimateL1Component_Call struct {
+ *mock.Call
+}
+
+// GasEstimateL1Component is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - to common.Address
+// - contractCreation bool
+// - data []byte
+func (_e *NodeInterfaceInterface_Expecter) GasEstimateL1Component(opts interface{}, to interface{}, contractCreation interface{}, data interface{}) *NodeInterfaceInterface_GasEstimateL1Component_Call {
+ return &NodeInterfaceInterface_GasEstimateL1Component_Call{Call: _e.mock.On("GasEstimateL1Component", opts, to, contractCreation, data)}
+}
+
+func (_c *NodeInterfaceInterface_GasEstimateL1Component_Call) Run(run func(opts *bind.TransactOpts, to common.Address, contractCreation bool, data []byte)) *NodeInterfaceInterface_GasEstimateL1Component_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(common.Address), args[2].(bool), args[3].([]byte))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_GasEstimateL1Component_Call) Return(_a0 *types.Transaction, _a1 error) *NodeInterfaceInterface_GasEstimateL1Component_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_GasEstimateL1Component_Call) RunAndReturn(run func(*bind.TransactOpts, common.Address, bool, []byte) (*types.Transaction, error)) *NodeInterfaceInterface_GasEstimateL1Component_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetL1Confirmations provides a mock function with given fields: opts, blockHash
+func (_m *NodeInterfaceInterface) GetL1Confirmations(opts *bind.CallOpts, blockHash [32]byte) (uint64, error) {
+ ret := _m.Called(opts, blockHash)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetL1Confirmations")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) (uint64, error)); ok {
+ return rf(opts, blockHash)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, [32]byte) uint64); ok {
+ r0 = rf(opts, blockHash)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, [32]byte) error); ok {
+ r1 = rf(opts, blockHash)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_GetL1Confirmations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL1Confirmations'
+type NodeInterfaceInterface_GetL1Confirmations_Call struct {
+ *mock.Call
+}
+
+// GetL1Confirmations is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - blockHash [32]byte
+func (_e *NodeInterfaceInterface_Expecter) GetL1Confirmations(opts interface{}, blockHash interface{}) *NodeInterfaceInterface_GetL1Confirmations_Call {
+ return &NodeInterfaceInterface_GetL1Confirmations_Call{Call: _e.mock.On("GetL1Confirmations", opts, blockHash)}
+}
+
+func (_c *NodeInterfaceInterface_GetL1Confirmations_Call) Run(run func(opts *bind.CallOpts, blockHash [32]byte)) *NodeInterfaceInterface_GetL1Confirmations_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].([32]byte))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_GetL1Confirmations_Call) Return(_a0 uint64, _a1 error) *NodeInterfaceInterface_GetL1Confirmations_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_GetL1Confirmations_Call) RunAndReturn(run func(*bind.CallOpts, [32]byte) (uint64, error)) *NodeInterfaceInterface_GetL1Confirmations_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// L2BlockRangeForL1 provides a mock function with given fields: opts, blockNum
+func (_m *NodeInterfaceInterface) L2BlockRangeForL1(opts *bind.CallOpts, blockNum uint64) (arb_node_interface.L2BlockRangeForL1, error) {
+ ret := _m.Called(opts, blockNum)
+
+ if len(ret) == 0 {
+ panic("no return value specified for L2BlockRangeForL1")
+ }
+
+ var r0 arb_node_interface.L2BlockRangeForL1
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (arb_node_interface.L2BlockRangeForL1, error)); ok {
+ return rf(opts, blockNum)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) arb_node_interface.L2BlockRangeForL1); ok {
+ r0 = rf(opts, blockNum)
+ } else {
+ r0 = ret.Get(0).(arb_node_interface.L2BlockRangeForL1)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint64) error); ok {
+ r1 = rf(opts, blockNum)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_L2BlockRangeForL1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'L2BlockRangeForL1'
+type NodeInterfaceInterface_L2BlockRangeForL1_Call struct {
+ *mock.Call
+}
+
+// L2BlockRangeForL1 is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - blockNum uint64
+func (_e *NodeInterfaceInterface_Expecter) L2BlockRangeForL1(opts interface{}, blockNum interface{}) *NodeInterfaceInterface_L2BlockRangeForL1_Call {
+ return &NodeInterfaceInterface_L2BlockRangeForL1_Call{Call: _e.mock.On("L2BlockRangeForL1", opts, blockNum)}
+}
+
+func (_c *NodeInterfaceInterface_L2BlockRangeForL1_Call) Run(run func(opts *bind.CallOpts, blockNum uint64)) *NodeInterfaceInterface_L2BlockRangeForL1_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_L2BlockRangeForL1_Call) Return(_a0 arb_node_interface.L2BlockRangeForL1, _a1 error) *NodeInterfaceInterface_L2BlockRangeForL1_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_L2BlockRangeForL1_Call) RunAndReturn(run func(*bind.CallOpts, uint64) (arb_node_interface.L2BlockRangeForL1, error)) *NodeInterfaceInterface_L2BlockRangeForL1_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LegacyLookupMessageBatchProof provides a mock function with given fields: opts, batchNum, index
+func (_m *NodeInterfaceInterface) LegacyLookupMessageBatchProof(opts *bind.CallOpts, batchNum *big.Int, index uint64) (arb_node_interface.LegacyLookupMessageBatchProof, error) {
+ ret := _m.Called(opts, batchNum, index)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LegacyLookupMessageBatchProof")
+ }
+
+ var r0 arb_node_interface.LegacyLookupMessageBatchProof
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, uint64) (arb_node_interface.LegacyLookupMessageBatchProof, error)); ok {
+ return rf(opts, batchNum, index)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, uint64) arb_node_interface.LegacyLookupMessageBatchProof); ok {
+ r0 = rf(opts, batchNum, index)
+ } else {
+ r0 = ret.Get(0).(arb_node_interface.LegacyLookupMessageBatchProof)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int, uint64) error); ok {
+ r1 = rf(opts, batchNum, index)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LegacyLookupMessageBatchProof'
+type NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call struct {
+ *mock.Call
+}
+
+// LegacyLookupMessageBatchProof is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - batchNum *big.Int
+// - index uint64
+func (_e *NodeInterfaceInterface_Expecter) LegacyLookupMessageBatchProof(opts interface{}, batchNum interface{}, index interface{}) *NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call {
+ return &NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call{Call: _e.mock.On("LegacyLookupMessageBatchProof", opts, batchNum, index)}
+}
+
+func (_c *NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call) Run(run func(opts *bind.CallOpts, batchNum *big.Int, index uint64)) *NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(*big.Int), args[2].(uint64))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call) Return(_a0 arb_node_interface.LegacyLookupMessageBatchProof, _a1 error) *NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int, uint64) (arb_node_interface.LegacyLookupMessageBatchProof, error)) *NodeInterfaceInterface_LegacyLookupMessageBatchProof_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NitroGenesisBlock provides a mock function with given fields: opts
+func (_m *NodeInterfaceInterface) NitroGenesisBlock(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for NitroGenesisBlock")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// NodeInterfaceInterface_NitroGenesisBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NitroGenesisBlock'
+type NodeInterfaceInterface_NitroGenesisBlock_Call struct {
+ *mock.Call
+}
+
+// NitroGenesisBlock is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *NodeInterfaceInterface_Expecter) NitroGenesisBlock(opts interface{}) *NodeInterfaceInterface_NitroGenesisBlock_Call {
+ return &NodeInterfaceInterface_NitroGenesisBlock_Call{Call: _e.mock.On("NitroGenesisBlock", opts)}
+}
+
+func (_c *NodeInterfaceInterface_NitroGenesisBlock_Call) Run(run func(opts *bind.CallOpts)) *NodeInterfaceInterface_NitroGenesisBlock_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_NitroGenesisBlock_Call) Return(_a0 *big.Int, _a1 error) *NodeInterfaceInterface_NitroGenesisBlock_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *NodeInterfaceInterface_NitroGenesisBlock_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *NodeInterfaceInterface_NitroGenesisBlock_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewNodeInterfaceInterface creates a new instance of NodeInterfaceInterface. 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 NewNodeInterfaceInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *NodeInterfaceInterface {
+ mock := &NodeInterfaceInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_optimism_dispute_game_factory/optimism_dispute_game_factory_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_optimism_dispute_game_factory/optimism_dispute_game_factory_interface.go
new file mode 100644
index 00000000000..3f0b69f1a08
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_optimism_dispute_game_factory/optimism_dispute_game_factory_interface.go
@@ -0,0 +1,207 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_optimism_dispute_game_factory
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ mock "github.com/stretchr/testify/mock"
+
+ optimism_dispute_game_factory "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/optimism_dispute_game_factory"
+)
+
+// OptimismDisputeGameFactoryInterface is an autogenerated mock type for the OptimismDisputeGameFactoryInterface type
+type OptimismDisputeGameFactoryInterface struct {
+ mock.Mock
+}
+
+type OptimismDisputeGameFactoryInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *OptimismDisputeGameFactoryInterface) EXPECT() *OptimismDisputeGameFactoryInterface_Expecter {
+ return &OptimismDisputeGameFactoryInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *OptimismDisputeGameFactoryInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// OptimismDisputeGameFactoryInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type OptimismDisputeGameFactoryInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *OptimismDisputeGameFactoryInterface_Expecter) Address() *OptimismDisputeGameFactoryInterface_Address_Call {
+ return &OptimismDisputeGameFactoryInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_Address_Call) Run(run func()) *OptimismDisputeGameFactoryInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_Address_Call) Return(_a0 common.Address) *OptimismDisputeGameFactoryInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_Address_Call) RunAndReturn(run func() common.Address) *OptimismDisputeGameFactoryInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FindLatestGames provides a mock function with given fields: opts, _gameType, _start, _n
+func (_m *OptimismDisputeGameFactoryInterface) FindLatestGames(opts *bind.CallOpts, _gameType uint32, _start *big.Int, _n *big.Int) ([]optimism_dispute_game_factory.IOptimismDisputeGameFactoryGameSearchResult, error) {
+ ret := _m.Called(opts, _gameType, _start, _n)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FindLatestGames")
+ }
+
+ var r0 []optimism_dispute_game_factory.IOptimismDisputeGameFactoryGameSearchResult
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint32, *big.Int, *big.Int) ([]optimism_dispute_game_factory.IOptimismDisputeGameFactoryGameSearchResult, error)); ok {
+ return rf(opts, _gameType, _start, _n)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint32, *big.Int, *big.Int) []optimism_dispute_game_factory.IOptimismDisputeGameFactoryGameSearchResult); ok {
+ r0 = rf(opts, _gameType, _start, _n)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]optimism_dispute_game_factory.IOptimismDisputeGameFactoryGameSearchResult)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, uint32, *big.Int, *big.Int) error); ok {
+ r1 = rf(opts, _gameType, _start, _n)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismDisputeGameFactoryInterface_FindLatestGames_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FindLatestGames'
+type OptimismDisputeGameFactoryInterface_FindLatestGames_Call struct {
+ *mock.Call
+}
+
+// FindLatestGames is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - _gameType uint32
+// - _start *big.Int
+// - _n *big.Int
+func (_e *OptimismDisputeGameFactoryInterface_Expecter) FindLatestGames(opts interface{}, _gameType interface{}, _start interface{}, _n interface{}) *OptimismDisputeGameFactoryInterface_FindLatestGames_Call {
+ return &OptimismDisputeGameFactoryInterface_FindLatestGames_Call{Call: _e.mock.On("FindLatestGames", opts, _gameType, _start, _n)}
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_FindLatestGames_Call) Run(run func(opts *bind.CallOpts, _gameType uint32, _start *big.Int, _n *big.Int)) *OptimismDisputeGameFactoryInterface_FindLatestGames_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(uint32), args[2].(*big.Int), args[3].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_FindLatestGames_Call) Return(_a0 []optimism_dispute_game_factory.IOptimismDisputeGameFactoryGameSearchResult, _a1 error) *OptimismDisputeGameFactoryInterface_FindLatestGames_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_FindLatestGames_Call) RunAndReturn(run func(*bind.CallOpts, uint32, *big.Int, *big.Int) ([]optimism_dispute_game_factory.IOptimismDisputeGameFactoryGameSearchResult, error)) *OptimismDisputeGameFactoryInterface_FindLatestGames_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GameCount provides a mock function with given fields: opts
+func (_m *OptimismDisputeGameFactoryInterface) GameCount(opts *bind.CallOpts) (*big.Int, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GameCount")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) *big.Int); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismDisputeGameFactoryInterface_GameCount_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GameCount'
+type OptimismDisputeGameFactoryInterface_GameCount_Call struct {
+ *mock.Call
+}
+
+// GameCount is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *OptimismDisputeGameFactoryInterface_Expecter) GameCount(opts interface{}) *OptimismDisputeGameFactoryInterface_GameCount_Call {
+ return &OptimismDisputeGameFactoryInterface_GameCount_Call{Call: _e.mock.On("GameCount", opts)}
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_GameCount_Call) Run(run func(opts *bind.CallOpts)) *OptimismDisputeGameFactoryInterface_GameCount_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_GameCount_Call) Return(_a0 *big.Int, _a1 error) *OptimismDisputeGameFactoryInterface_GameCount_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismDisputeGameFactoryInterface_GameCount_Call) RunAndReturn(run func(*bind.CallOpts) (*big.Int, error)) *OptimismDisputeGameFactoryInterface_GameCount_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewOptimismDisputeGameFactoryInterface creates a new instance of OptimismDisputeGameFactoryInterface. 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 NewOptimismDisputeGameFactoryInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *OptimismDisputeGameFactoryInterface {
+ mock := &OptimismDisputeGameFactoryInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_optimism_l2_output_oracle/optimism_l2_output_oracle_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_optimism_l2_output_oracle/optimism_l2_output_oracle_interface.go
new file mode 100644
index 00000000000..f93bee3bf59
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_optimism_l2_output_oracle/optimism_l2_output_oracle_interface.go
@@ -0,0 +1,204 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_optimism_l2_output_oracle
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ mock "github.com/stretchr/testify/mock"
+
+ optimism_l2_output_oracle "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/optimism_l2_output_oracle"
+)
+
+// OptimismL2OutputOracleInterface is an autogenerated mock type for the OptimismL2OutputOracleInterface type
+type OptimismL2OutputOracleInterface struct {
+ mock.Mock
+}
+
+type OptimismL2OutputOracleInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *OptimismL2OutputOracleInterface) EXPECT() *OptimismL2OutputOracleInterface_Expecter {
+ return &OptimismL2OutputOracleInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *OptimismL2OutputOracleInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// OptimismL2OutputOracleInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type OptimismL2OutputOracleInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *OptimismL2OutputOracleInterface_Expecter) Address() *OptimismL2OutputOracleInterface_Address_Call {
+ return &OptimismL2OutputOracleInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *OptimismL2OutputOracleInterface_Address_Call) Run(run func()) *OptimismL2OutputOracleInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *OptimismL2OutputOracleInterface_Address_Call) Return(_a0 common.Address) *OptimismL2OutputOracleInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *OptimismL2OutputOracleInterface_Address_Call) RunAndReturn(run func() common.Address) *OptimismL2OutputOracleInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetL2Output provides a mock function with given fields: opts, _l2OutputIndex
+func (_m *OptimismL2OutputOracleInterface) GetL2Output(opts *bind.CallOpts, _l2OutputIndex *big.Int) (optimism_l2_output_oracle.TypesOutputProposal, error) {
+ ret := _m.Called(opts, _l2OutputIndex)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetL2Output")
+ }
+
+ var r0 optimism_l2_output_oracle.TypesOutputProposal
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (optimism_l2_output_oracle.TypesOutputProposal, error)); ok {
+ return rf(opts, _l2OutputIndex)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) optimism_l2_output_oracle.TypesOutputProposal); ok {
+ r0 = rf(opts, _l2OutputIndex)
+ } else {
+ r0 = ret.Get(0).(optimism_l2_output_oracle.TypesOutputProposal)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok {
+ r1 = rf(opts, _l2OutputIndex)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismL2OutputOracleInterface_GetL2Output_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL2Output'
+type OptimismL2OutputOracleInterface_GetL2Output_Call struct {
+ *mock.Call
+}
+
+// GetL2Output is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - _l2OutputIndex *big.Int
+func (_e *OptimismL2OutputOracleInterface_Expecter) GetL2Output(opts interface{}, _l2OutputIndex interface{}) *OptimismL2OutputOracleInterface_GetL2Output_Call {
+ return &OptimismL2OutputOracleInterface_GetL2Output_Call{Call: _e.mock.On("GetL2Output", opts, _l2OutputIndex)}
+}
+
+func (_c *OptimismL2OutputOracleInterface_GetL2Output_Call) Run(run func(opts *bind.CallOpts, _l2OutputIndex *big.Int)) *OptimismL2OutputOracleInterface_GetL2Output_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *OptimismL2OutputOracleInterface_GetL2Output_Call) Return(_a0 optimism_l2_output_oracle.TypesOutputProposal, _a1 error) *OptimismL2OutputOracleInterface_GetL2Output_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismL2OutputOracleInterface_GetL2Output_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int) (optimism_l2_output_oracle.TypesOutputProposal, error)) *OptimismL2OutputOracleInterface_GetL2Output_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetL2OutputIndexAfter provides a mock function with given fields: opts, _l2BlockNumber
+func (_m *OptimismL2OutputOracleInterface) GetL2OutputIndexAfter(opts *bind.CallOpts, _l2BlockNumber *big.Int) (*big.Int, error) {
+ ret := _m.Called(opts, _l2BlockNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetL2OutputIndexAfter")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (*big.Int, error)); ok {
+ return rf(opts, _l2BlockNumber)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) *big.Int); ok {
+ r0 = rf(opts, _l2BlockNumber)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts, *big.Int) error); ok {
+ r1 = rf(opts, _l2BlockNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetL2OutputIndexAfter'
+type OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call struct {
+ *mock.Call
+}
+
+// GetL2OutputIndexAfter is a helper method to define mock.On call
+// - opts *bind.CallOpts
+// - _l2BlockNumber *big.Int
+func (_e *OptimismL2OutputOracleInterface_Expecter) GetL2OutputIndexAfter(opts interface{}, _l2BlockNumber interface{}) *OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call {
+ return &OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call{Call: _e.mock.On("GetL2OutputIndexAfter", opts, _l2BlockNumber)}
+}
+
+func (_c *OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call) Run(run func(opts *bind.CallOpts, _l2BlockNumber *big.Int)) *OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call) Return(_a0 *big.Int, _a1 error) *OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call) RunAndReturn(run func(*bind.CallOpts, *big.Int) (*big.Int, error)) *OptimismL2OutputOracleInterface_GetL2OutputIndexAfter_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewOptimismL2OutputOracleInterface creates a new instance of OptimismL2OutputOracleInterface. 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 NewOptimismL2OutputOracleInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *OptimismL2OutputOracleInterface {
+ mock := &OptimismL2OutputOracleInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_optimism_portal/optimism_portal_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_optimism_portal/optimism_portal_interface.go
new file mode 100644
index 00000000000..eede00e7d9a
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_optimism_portal/optimism_portal_interface.go
@@ -0,0 +1,267 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_optimism_portal
+
+import (
+ big "math/big"
+
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ mock "github.com/stretchr/testify/mock"
+
+ optimism_portal "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/liquiditymanager/generated/optimism_portal"
+
+ types "github.com/ethereum/go-ethereum/core/types"
+)
+
+// OptimismPortalInterface is an autogenerated mock type for the OptimismPortalInterface type
+type OptimismPortalInterface struct {
+ mock.Mock
+}
+
+type OptimismPortalInterface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *OptimismPortalInterface) EXPECT() *OptimismPortalInterface_Expecter {
+ return &OptimismPortalInterface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *OptimismPortalInterface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// OptimismPortalInterface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type OptimismPortalInterface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *OptimismPortalInterface_Expecter) Address() *OptimismPortalInterface_Address_Call {
+ return &OptimismPortalInterface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *OptimismPortalInterface_Address_Call) Run(run func()) *OptimismPortalInterface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *OptimismPortalInterface_Address_Call) Return(_a0 common.Address) *OptimismPortalInterface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *OptimismPortalInterface_Address_Call) RunAndReturn(run func() common.Address) *OptimismPortalInterface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FinalizeWithdrawalTransaction provides a mock function with given fields: opts, _tx
+func (_m *OptimismPortalInterface) FinalizeWithdrawalTransaction(opts *bind.TransactOpts, _tx optimism_portal.TypesWithdrawalTransaction) (*types.Transaction, error) {
+ ret := _m.Called(opts, _tx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FinalizeWithdrawalTransaction")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, optimism_portal.TypesWithdrawalTransaction) (*types.Transaction, error)); ok {
+ return rf(opts, _tx)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, optimism_portal.TypesWithdrawalTransaction) *types.Transaction); ok {
+ r0 = rf(opts, _tx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, optimism_portal.TypesWithdrawalTransaction) error); ok {
+ r1 = rf(opts, _tx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismPortalInterface_FinalizeWithdrawalTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FinalizeWithdrawalTransaction'
+type OptimismPortalInterface_FinalizeWithdrawalTransaction_Call struct {
+ *mock.Call
+}
+
+// FinalizeWithdrawalTransaction is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _tx optimism_portal.TypesWithdrawalTransaction
+func (_e *OptimismPortalInterface_Expecter) FinalizeWithdrawalTransaction(opts interface{}, _tx interface{}) *OptimismPortalInterface_FinalizeWithdrawalTransaction_Call {
+ return &OptimismPortalInterface_FinalizeWithdrawalTransaction_Call{Call: _e.mock.On("FinalizeWithdrawalTransaction", opts, _tx)}
+}
+
+func (_c *OptimismPortalInterface_FinalizeWithdrawalTransaction_Call) Run(run func(opts *bind.TransactOpts, _tx optimism_portal.TypesWithdrawalTransaction)) *OptimismPortalInterface_FinalizeWithdrawalTransaction_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(optimism_portal.TypesWithdrawalTransaction))
+ })
+ return _c
+}
+
+func (_c *OptimismPortalInterface_FinalizeWithdrawalTransaction_Call) Return(_a0 *types.Transaction, _a1 error) *OptimismPortalInterface_FinalizeWithdrawalTransaction_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismPortalInterface_FinalizeWithdrawalTransaction_Call) RunAndReturn(run func(*bind.TransactOpts, optimism_portal.TypesWithdrawalTransaction) (*types.Transaction, error)) *OptimismPortalInterface_FinalizeWithdrawalTransaction_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ProveWithdrawalTransaction provides a mock function with given fields: opts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof
+func (_m *OptimismPortalInterface) ProveWithdrawalTransaction(opts *bind.TransactOpts, _tx optimism_portal.TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof optimism_portal.TypesOutputRootProof, _withdrawalProof [][]byte) (*types.Transaction, error) {
+ ret := _m.Called(opts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ProveWithdrawalTransaction")
+ }
+
+ var r0 *types.Transaction
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, optimism_portal.TypesWithdrawalTransaction, *big.Int, optimism_portal.TypesOutputRootProof, [][]byte) (*types.Transaction, error)); ok {
+ return rf(opts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.TransactOpts, optimism_portal.TypesWithdrawalTransaction, *big.Int, optimism_portal.TypesOutputRootProof, [][]byte) *types.Transaction); ok {
+ r0 = rf(opts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*types.Transaction)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.TransactOpts, optimism_portal.TypesWithdrawalTransaction, *big.Int, optimism_portal.TypesOutputRootProof, [][]byte) error); ok {
+ r1 = rf(opts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismPortalInterface_ProveWithdrawalTransaction_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProveWithdrawalTransaction'
+type OptimismPortalInterface_ProveWithdrawalTransaction_Call struct {
+ *mock.Call
+}
+
+// ProveWithdrawalTransaction is a helper method to define mock.On call
+// - opts *bind.TransactOpts
+// - _tx optimism_portal.TypesWithdrawalTransaction
+// - _l2OutputIndex *big.Int
+// - _outputRootProof optimism_portal.TypesOutputRootProof
+// - _withdrawalProof [][]byte
+func (_e *OptimismPortalInterface_Expecter) ProveWithdrawalTransaction(opts interface{}, _tx interface{}, _l2OutputIndex interface{}, _outputRootProof interface{}, _withdrawalProof interface{}) *OptimismPortalInterface_ProveWithdrawalTransaction_Call {
+ return &OptimismPortalInterface_ProveWithdrawalTransaction_Call{Call: _e.mock.On("ProveWithdrawalTransaction", opts, _tx, _l2OutputIndex, _outputRootProof, _withdrawalProof)}
+}
+
+func (_c *OptimismPortalInterface_ProveWithdrawalTransaction_Call) Run(run func(opts *bind.TransactOpts, _tx optimism_portal.TypesWithdrawalTransaction, _l2OutputIndex *big.Int, _outputRootProof optimism_portal.TypesOutputRootProof, _withdrawalProof [][]byte)) *OptimismPortalInterface_ProveWithdrawalTransaction_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.TransactOpts), args[1].(optimism_portal.TypesWithdrawalTransaction), args[2].(*big.Int), args[3].(optimism_portal.TypesOutputRootProof), args[4].([][]byte))
+ })
+ return _c
+}
+
+func (_c *OptimismPortalInterface_ProveWithdrawalTransaction_Call) Return(_a0 *types.Transaction, _a1 error) *OptimismPortalInterface_ProveWithdrawalTransaction_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismPortalInterface_ProveWithdrawalTransaction_Call) RunAndReturn(run func(*bind.TransactOpts, optimism_portal.TypesWithdrawalTransaction, *big.Int, optimism_portal.TypesOutputRootProof, [][]byte) (*types.Transaction, error)) *OptimismPortalInterface_ProveWithdrawalTransaction_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Version provides a mock function with given fields: opts
+func (_m *OptimismPortalInterface) Version(opts *bind.CallOpts) (string, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Version")
+ }
+
+ var r0 string
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) string); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismPortalInterface_Version_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Version'
+type OptimismPortalInterface_Version_Call struct {
+ *mock.Call
+}
+
+// Version is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *OptimismPortalInterface_Expecter) Version(opts interface{}) *OptimismPortalInterface_Version_Call {
+ return &OptimismPortalInterface_Version_Call{Call: _e.mock.On("Version", opts)}
+}
+
+func (_c *OptimismPortalInterface_Version_Call) Run(run func(opts *bind.CallOpts)) *OptimismPortalInterface_Version_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *OptimismPortalInterface_Version_Call) Return(_a0 string, _a1 error) *OptimismPortalInterface_Version_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismPortalInterface_Version_Call) RunAndReturn(run func(*bind.CallOpts) (string, error)) *OptimismPortalInterface_Version_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewOptimismPortalInterface creates a new instance of OptimismPortalInterface. 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 NewOptimismPortalInterface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *OptimismPortalInterface {
+ mock := &OptimismPortalInterface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/liquiditymanager/mocks/mock_optimism_portal_2/optimism_portal2_interface.go b/core/gethwrappers/liquiditymanager/mocks/mock_optimism_portal_2/optimism_portal2_interface.go
new file mode 100644
index 00000000000..e3d1312120f
--- /dev/null
+++ b/core/gethwrappers/liquiditymanager/mocks/mock_optimism_portal_2/optimism_portal2_interface.go
@@ -0,0 +1,198 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mock_optimism_portal_2
+
+import (
+ bind "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ common "github.com/ethereum/go-ethereum/common"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// OptimismPortal2Interface is an autogenerated mock type for the OptimismPortal2Interface type
+type OptimismPortal2Interface struct {
+ mock.Mock
+}
+
+type OptimismPortal2Interface_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *OptimismPortal2Interface) EXPECT() *OptimismPortal2Interface_Expecter {
+ return &OptimismPortal2Interface_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *OptimismPortal2Interface) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// OptimismPortal2Interface_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type OptimismPortal2Interface_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *OptimismPortal2Interface_Expecter) Address() *OptimismPortal2Interface_Address_Call {
+ return &OptimismPortal2Interface_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *OptimismPortal2Interface_Address_Call) Run(run func()) *OptimismPortal2Interface_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *OptimismPortal2Interface_Address_Call) Return(_a0 common.Address) *OptimismPortal2Interface_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *OptimismPortal2Interface_Address_Call) RunAndReturn(run func() common.Address) *OptimismPortal2Interface_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// DisputeGameFactory provides a mock function with given fields: opts
+func (_m *OptimismPortal2Interface) DisputeGameFactory(opts *bind.CallOpts) (common.Address, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DisputeGameFactory")
+ }
+
+ var r0 common.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) common.Address); ok {
+ r0 = rf(opts)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismPortal2Interface_DisputeGameFactory_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisputeGameFactory'
+type OptimismPortal2Interface_DisputeGameFactory_Call struct {
+ *mock.Call
+}
+
+// DisputeGameFactory is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *OptimismPortal2Interface_Expecter) DisputeGameFactory(opts interface{}) *OptimismPortal2Interface_DisputeGameFactory_Call {
+ return &OptimismPortal2Interface_DisputeGameFactory_Call{Call: _e.mock.On("DisputeGameFactory", opts)}
+}
+
+func (_c *OptimismPortal2Interface_DisputeGameFactory_Call) Run(run func(opts *bind.CallOpts)) *OptimismPortal2Interface_DisputeGameFactory_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *OptimismPortal2Interface_DisputeGameFactory_Call) Return(_a0 common.Address, _a1 error) *OptimismPortal2Interface_DisputeGameFactory_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismPortal2Interface_DisputeGameFactory_Call) RunAndReturn(run func(*bind.CallOpts) (common.Address, error)) *OptimismPortal2Interface_DisputeGameFactory_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// RespectedGameType provides a mock function with given fields: opts
+func (_m *OptimismPortal2Interface) RespectedGameType(opts *bind.CallOpts) (uint32, error) {
+ ret := _m.Called(opts)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RespectedGameType")
+ }
+
+ var r0 uint32
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok {
+ return rf(opts)
+ }
+ if rf, ok := ret.Get(0).(func(*bind.CallOpts) uint32); ok {
+ r0 = rf(opts)
+ } else {
+ r0 = ret.Get(0).(uint32)
+ }
+
+ if rf, ok := ret.Get(1).(func(*bind.CallOpts) error); ok {
+ r1 = rf(opts)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OptimismPortal2Interface_RespectedGameType_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RespectedGameType'
+type OptimismPortal2Interface_RespectedGameType_Call struct {
+ *mock.Call
+}
+
+// RespectedGameType is a helper method to define mock.On call
+// - opts *bind.CallOpts
+func (_e *OptimismPortal2Interface_Expecter) RespectedGameType(opts interface{}) *OptimismPortal2Interface_RespectedGameType_Call {
+ return &OptimismPortal2Interface_RespectedGameType_Call{Call: _e.mock.On("RespectedGameType", opts)}
+}
+
+func (_c *OptimismPortal2Interface_RespectedGameType_Call) Run(run func(opts *bind.CallOpts)) *OptimismPortal2Interface_RespectedGameType_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*bind.CallOpts))
+ })
+ return _c
+}
+
+func (_c *OptimismPortal2Interface_RespectedGameType_Call) Return(_a0 uint32, _a1 error) *OptimismPortal2Interface_RespectedGameType_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OptimismPortal2Interface_RespectedGameType_Call) RunAndReturn(run func(*bind.CallOpts) (uint32, error)) *OptimismPortal2Interface_RespectedGameType_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewOptimismPortal2Interface creates a new instance of OptimismPortal2Interface. 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 NewOptimismPortal2Interface(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *OptimismPortal2Interface {
+ mock := &OptimismPortal2Interface{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/gethwrappers/llo-feeds/generated/destination_fee_manager/destination_fee_manager.go b/core/gethwrappers/llo-feeds/generated/destination_fee_manager/destination_fee_manager.go
new file mode 100644
index 00000000000..b87cf068ac5
--- /dev/null
+++ b/core/gethwrappers/llo-feeds/generated/destination_fee_manager/destination_fee_manager.go
@@ -0,0 +1,1790 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package destination_fee_manager
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommonAddressAndWeight struct {
+ Addr common.Address
+ Weight uint64
+}
+
+type CommonAsset struct {
+ AssetAddress common.Address
+ Amount *big.Int
+}
+
+type IDestinationRewardManagerFeePayment struct {
+ PoolId [32]byte
+ Amount *big.Int
+}
+
+var DestinationFeeManagerMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_linkAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_nativeAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_verifierAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_rewardManagerAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"ExpiredReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDeposit\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDiscount\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidQuote\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReceivingAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSurcharge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PoolIdMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroDeficit\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"fee\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"structCommon.Asset\",\"name\":\"reward\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"appliedDiscount\",\"type\":\"uint256\"}],\"name\":\"DiscountApplied\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIDestinationRewardManager.FeePayment[]\",\"name\":\"rewards\",\"type\":\"tuple[]\"}],\"name\":\"InsufficientLink\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"linkQuantity\",\"type\":\"uint256\"}],\"name\":\"LinkDeficitCleared\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"newSurcharge\",\"type\":\"uint64\"}],\"name\":\"NativeSurchargeUpdated\",\"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\":\"subscriber\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"SubscriberDiscountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"addVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"quoteAddress\",\"type\":\"address\"}],\"name\":\"getFeeAndReward\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structCommon.Asset\",\"name\":\"\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_linkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_nativeAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_rewardManager\",\"outputs\":[{\"internalType\":\"contractIDestinationRewardManager\",\"name\":\"\",\"type\":\"address\"}],\"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\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"name\":\"payLinkDeficit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"recipient\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"parameterPayload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFee\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"poolIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"parameterPayload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"subscriber\",\"type\":\"address\"}],\"name\":\"processFeeBulk\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"removeVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_linkDeficit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_nativeSurcharge\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_subscriberDiscounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_verifierAddressList\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setFeeRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"surcharge\",\"type\":\"uint64\"}],\"name\":\"setNativeSurcharge\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"rewardManagerAddress\",\"type\":\"address\"}],\"name\":\"setRewardManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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\":\"subscriber\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"feedId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"discount\",\"type\":\"uint64\"}],\"name\":\"updateSubscriberDiscount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"assetAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60c06040523480156200001157600080fd5b5060405162003c3238038062003c328339810160408190526200003491620002af565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620001e7565b5050506001600160a01b0384161580620000df57506001600160a01b038316155b80620000f257506001600160a01b038216155b806200010557506001600160a01b038116155b15620001245760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b03848116608081905284821660a05283821660008181526004602081905260409182902080546001600160a01b03199081169094179055600580549093169486169485179092555163095ea7b360e01b81529081019290925260001960248301529063095ea7b3906044016020604051808303816000875af1158015620001b6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001dc91906200030c565b505050505062000337565b336001600160a01b03821603620002415760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620002aa57600080fd5b919050565b60008060008060808587031215620002c657600080fd5b620002d18562000292565b9350620002e16020860162000292565b9250620002f16040860162000292565b9150620003016060860162000292565b905092959194509250565b6000602082840312156200031f57600080fd5b815180151581146200033057600080fd5b9392505050565b60805160a051613850620003e26000396000818161033b0152818161151c0152818161177a015281816117d101528181611a7e0152818161248e01526125370152600081816105430152818161098e01528181610a9801528181610e9b015281816111f4015281816114c50152818161165c0152818161179f015281816118280152818161196d015281816119da01528181611a1a01528181612109015261262b01526138506000f3fe60806040526004361061018b5760003560e01c806386968cfd116100d6578063d09dc3391161007f578063ea4b861b11610059578063ea4b861b14610531578063f2fde38b14610565578063f65df9621461058557600080fd5b8063d09dc33914610491578063e03dab1a146104a6578063e389d9a41461051157600080fd5b80639000b3d6116100b05780639000b3d614610431578063ca2dfd0a14610451578063ce7817d11461047157600080fd5b806386968cfd146103b557806387d6d843146103c85780638da5cb5b1461040657600080fd5b80633690750911610138578063638786681161011257806363878668146103295780637700feeb1461035d57806379ba5097146103a057600080fd5b806336907509146102a45780633aa5ac07146102b7578063505380941461030957600080fd5b8063181f5a7711610169578063181f5a77146102225780631d4d84a21461026e57806332f5f7461461028e57600080fd5b8063013f542b1461019057806301ffc9a7146101d0578063153ee55414610200575b600080fd5b34801561019c57600080fd5b506101bd6101ab366004612d9a565b60036020526000908152604090205481565b6040519081526020015b60405180910390f35b3480156101dc57600080fd5b506101f06101eb366004612db3565b6105a5565b60405190151581526020016101c7565b34801561020c57600080fd5b5061022061021b366004612e27565b6108ea565b005b34801561022e57600080fd5b50604080518082018252601b81527f44657374696e6174696f6e4665654d616e6167657220312e302e300000000000602082015290516101c79190612e68565b34801561027a57600080fd5b50610220610289366004612edf565b610b0b565b34801561029a57600080fd5b506101bd60065481565b6102206102b2366004613036565b610c9f565b3480156102c357600080fd5b506005546102e49073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c7565b34801561031557600080fd5b50610220610324366004613156565b610f50565b34801561033557600080fd5b506102e47f000000000000000000000000000000000000000000000000000000000000000081565b34801561036957600080fd5b506102e4610378366004612e27565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b3480156103ac57600080fd5b50610220610fea565b6102206103c3366004613171565b6110ec565b3480156103d457600080fd5b506101bd6103e33660046131fd565b600260209081526000938452604080852082529284528284209052825290205481565b34801561041257600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166102e4565b34801561043d57600080fd5b5061022061044c366004612e27565b61126d565b34801561045d57600080fd5b5061022061046c366004612e27565b611370565b34801561047d57600080fd5b5061022061048c366004613234565b61146f565b34801561049d57600080fd5b506101bd61162b565b3480156104b257600080fd5b506104c66104c1366004613313565b6116e1565b60408051845173ffffffffffffffffffffffffffffffffffffffff9081168252602095860151868301528451169181019190915292909101516060830152608082015260a0016101c7565b34801561051d57600080fd5b5061022061052c366004612d9a565b611ae0565b34801561053d57600080fd5b506102e47f000000000000000000000000000000000000000000000000000000000000000081565b34801561057157600080fd5b50610220610580366004612e27565b611c95565b34801561059157600080fd5b506102206105a036600461336c565b611ca9565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fe03dab1a00000000000000000000000000000000000000000000000000000000148061063857507fffffffff0000000000000000000000000000000000000000000000000000000082167f5053809400000000000000000000000000000000000000000000000000000000145b8061068457507fffffffff0000000000000000000000000000000000000000000000000000000082167fce7817d100000000000000000000000000000000000000000000000000000000145b806106d057507fffffffff0000000000000000000000000000000000000000000000000000000082167f1d4d84a200000000000000000000000000000000000000000000000000000000145b8061071c57507fffffffff0000000000000000000000000000000000000000000000000000000082167fd09dc33900000000000000000000000000000000000000000000000000000000145b8061076857507fffffffff0000000000000000000000000000000000000000000000000000000082167fe389d9a400000000000000000000000000000000000000000000000000000000145b806107b457507fffffffff0000000000000000000000000000000000000000000000000000000082167f9000b3d600000000000000000000000000000000000000000000000000000000145b8061080057507fffffffff0000000000000000000000000000000000000000000000000000000082167fca2dfd0a00000000000000000000000000000000000000000000000000000000145b8061084c57507fffffffff0000000000000000000000000000000000000000000000000000000082167f86968cfd00000000000000000000000000000000000000000000000000000000145b8061089857507fffffffff0000000000000000000000000000000000000000000000000000000082167f3690750900000000000000000000000000000000000000000000000000000000145b806108e457507fffffffff0000000000000000000000000000000000000000000000000000000082167ff65df96200000000000000000000000000000000000000000000000000000000145b92915050565b6108f2611dbd565b73ffffffffffffffffffffffffffffffffffffffff811661093f576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152600060248201527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303816000875af11580156109d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109fd91906133eb565b50600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182179092556040517f095ea7b300000000000000000000000000000000000000000000000000000000815260048101919091527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248201527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303816000875af1158015610ae3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0791906133eb565b5050565b610b13611dbd565b73ffffffffffffffffffffffffffffffffffffffff8316610be85760008273ffffffffffffffffffffffffffffffffffffffff168277ffffffffffffffffffffffffffffffffffffffffffffffff1660405160006040518083038185875af1925050503d8060008114610ba2576040519150601f19603f3d011682016040523d82523d6000602084013e610ba7565b606091505b5050905080610be2576040517fef2af20100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b610c2373ffffffffffffffffffffffffffffffffffffffff84168377ffffffffffffffffffffffffffffffffffffffffffffffff8416611e40565b6040805133815273ffffffffffffffffffffffffffffffffffffffff848116602083015285168183015277ffffffffffffffffffffffffffffffffffffffffffffffff8316606082015290517f7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f299181900360800190a15b505050565b3360008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1614610cfc576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85518414610d35576040517e154a0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008467ffffffffffffffff811115610d5057610d50612f2a565b604051908082528060200260200182016040528015610d8957816020015b610d76612d0d565b815260200190600190039081610d6e5790505b5090506000806000805b88811015610f16576000801b8b8281518110610db157610db161340d565b602002602001015103610df0576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000610e248d8d86818110610e0a57610e0a61340d565b9050602002810190610e1c919061343c565b8d8d8d611f14565b9250925092508260200151600014610f025760405180608001604052808f8681518110610e5357610e5361340d565b6020026020010151815260200184815260200183815260200182815250888680610e7c906134d0565b975081518110610e8e57610e8e61340d565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff1603610efb57866001019650610f02565b8560010195505b50505080610f0f906134d0565b9050610d93565b5082151580610f2457508115155b15610f3a57610f3585858585612024565b610f44565b610f44853461281e565b50505050505050505050565b610f58611dbd565b670de0b6b3a764000067ffffffffffffffff82161115610fa4576040517f05e8ac2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660068190556040519081527f08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d6399060200160405180910390a150565b60015473ffffffffffffffffffffffffffffffffffffffff163314611070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3360008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1614611149576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080600061115b8888888888611f14565b925092509250826020015160000361117f57611177843461281e565b505050611265565b604080516001808252818301909252600091816020015b61119e612d0d565b81526020019060019003908161119657905050905060405180608001604052808b815260200185815260200184815260200183815250816000815181106111e7576111e761340d565b60200260200101819052507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff160361125757610f35858260016000612024565b610f44858260006001612024565b505050505050565b611275611dbd565b73ffffffffffffffffffffffffffffffffffffffff81166112c2576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8181166000908152600460205260409020541615611321576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600081815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169091179055565b611378611dbd565b73ffffffffffffffffffffffffffffffffffffffff81166113c5576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81811660009081526004602052604090205416611423576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b611477611dbd565b670de0b6b3a764000067ffffffffffffffff821611156114c3576040517f997ea36000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415801561156b57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b156115a2576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff848116600081815260026020908152604080832088845282528083209487168084529482529182902067ffffffffffffffff86169081905582519485529084015285927f5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139910160405180910390a350505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa1580156116b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116dc9190613508565b905090565b604080518082018252600080825260208083018290528351808501855282815280820183905284518086018652838152808301849052855180870190965283865291850183905292938261173488613521565b90507fffff0000000000000000000000000000000000000000000000000000000000008082169081016117cf57505073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811683527f0000000000000000000000000000000000000000000000000000000000000000168152909350915060009050611ad7565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff161415801561187757507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614155b156118ae576040517ff861803000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060008b8060200190518101906118c7919061357a565b77ffffffffffffffffffffffffffffffffffffffffffffffff91821698509116955063ffffffff169350505042821015905061192f576040517fb6c405f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808e16600090815260026020908152604080832089845282528083208f851684529091529020547f000000000000000000000000000000000000000000000000000000000000000090911687526119be6119a682670de0b6b3a76400006135e0565b6119b090866135f3565b670de0b6b3a7640000612867565b602088015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116908d1603611a4b5773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016885260208088015190890152611ac8565b600654600090611a67906119a690670de0b6b3a764000061360a565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168a529050611ac1611ab783670de0b6b3a76400006135e0565b6119b090836135f3565b60208a0152505b96995094975094955050505050505b93509350939050565b611ae8611dbd565b60008181526003602052604081205490819003611b31576040517f03aad31200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600360205260408082208290558051600180825281830190925290816020015b6040805180820190915260008082526020820152815260200190600190039081611b5657905050905060405180604001604052808481526020018377ffffffffffffffffffffffffffffffffffffffffffffffff1681525081600081518110611bc157611bc161340d565b60209081029190910101526005546040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063b0d9fa1990611c24908490309060040161367d565b600060405180830381600087803b158015611c3e57600080fd5b505af1158015611c52573d6000803e3d6000fd5b50505050827f843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd989583604051611c8891815260200190565b60405180910390a2505050565b611c9d611dbd565b611ca68161289f565b50565b3360008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1614801590611cf5575060005473ffffffffffffffffffffffffffffffffffffffff163314155b15611d2c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005546040517f14060f2300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906314060f2390611d86908690869086906004016136b5565b600060405180830381600087803b158015611da057600080fd5b505af1158015611db4573d6000803e3d6000fd5b50505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611e3e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401611067565b565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610c9a9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612994565b6040805180820190915260008082526020820152604080518082019091526000808252602082015260003073ffffffffffffffffffffffffffffffffffffffff851603611f8d576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611f9b888a018a613735565b915050600081611faa90613521565b905060007e010000000000000000000000000000000000000000000000000000000000007fffff00000000000000000000000000000000000000000000000000000000000083161461200557612002888a018a612e27565b90505b6120108784836116e1565b955095509550505050955095509592505050565b60008267ffffffffffffffff81111561203f5761203f612f2a565b60405190808252806020026020018201604052801561208457816020015b604080518082019091526000808252602082015281526020019060019003908161205d5790505b50905060008267ffffffffffffffff8111156120a2576120a2612f2a565b6040519080825280602002602001820160405280156120e757816020015b60408051808201909152600080825260208201528152602001906001900390816120c05790505b5090506000808080806120fa888a61360a565b905060005b81811015612449577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168b82815181106121505761215061340d565b6020026020010151602001516000015173ffffffffffffffffffffffffffffffffffffffff16036122165760405180604001604052808c83815181106121985761219861340d565b60200260200101516000015181526020018c83815181106121bb576121bb61340d565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff168152508885806121f4906134d0565b9650815181106122065761220661340d565b602002602001018190525061230b565b60405180604001604052808c83815181106122335761223361340d565b60200260200101516000015181526020018c83815181106122565761225661340d565b6020026020010151604001516020015177ffffffffffffffffffffffffffffffffffffffffffffffff1681525087848061228f906134d0565b9550815181106122a1576122a161340d565b60200260200101819052508a81815181106122be576122be61340d565b60200260200101516020015160200151866122d9919061360a565b95508a81815181106122ed576122ed61340d565b6020026020010151604001516020015185612308919061360a565b94505b8a818151811061231d5761231d61340d565b602002602001015160600151600014612439578b73ffffffffffffffffffffffffffffffffffffffff168b82815181106123595761235961340d565b6020026020010151600001517f88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e71258d84815181106123985761239861340d565b6020026020010151602001518e85815181106123b6576123b661340d565b6020026020010151604001518f86815181106123d4576123d461340d565b60200260200101516060015160405161243093929190835173ffffffffffffffffffffffffffffffffffffffff908116825260209485015185830152835116604082015291909201516060820152608081019190915260a00190565b60405180910390a35b612442816134d0565b90506120ff565b5060003415612517573486111561248c576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0876040518263ffffffff1660e01b81526004016000604051808303818588803b1580156124f457600080fd5b505af1158015612508573d6000803e3d6000fd5b5050505050853403905061255f565b851561255f5761255f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168d3089612aa0565b8751156125f657600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b0d9fa19898e6040518363ffffffff1660e01b81526004016125c392919061367d565b600060405180830381600087803b1580156125dd57600080fd5b505af11580156125f1573d6000803e3d6000fd5b505050505b865115612806576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612687573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ab9190613508565b85111561277b5760005b875181101561273e578781815181106126d0576126d061340d565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff16600360008a848151811061270c5761270c61340d565b60209081029190910181015151825281019190915260400160002080549091019055612737816134d0565b90506126b5565b507ff52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b678760405161276e91906137d9565b60405180910390a1612806565b6005546040517fb0d9fa1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063b0d9fa19906127d3908a90309060040161367d565b600060405180830381600087803b1580156127ed57600080fd5b505af1158015612801573d6000803e3d6000fd5b505050505b6128108c8261281e565b505050505050505050505050565b8015610b075760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610c9a573d6000803e3d6000fd5b60008215612895578161287b6001856135e0565b61288591906137ec565b61289090600161360a565b612898565b60005b9392505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361291e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401611067565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60006129f6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16612afe9092919063ffffffff16565b805190915015610c9a5780806020019051810190612a1491906133eb565b610c9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611067565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610be29085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611e92565b6060612b0d8484600085612b15565b949350505050565b606082471015612ba7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401611067565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051612bd09190613827565b60006040518083038185875af1925050503d8060008114612c0d576040519150601f19603f3d011682016040523d82523d6000602084013e612c12565b606091505b5091509150612c2387838387612c2e565b979650505050505050565b60608315612cc4578251600003612cbd5773ffffffffffffffffffffffffffffffffffffffff85163b612cbd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611067565b5081612b0d565b612b0d8383815115612cd95781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110679190612e68565b604051806080016040528060008019168152602001612d556040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b8152602001612d8d6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b8152602001600081525090565b600060208284031215612dac57600080fd5b5035919050565b600060208284031215612dc557600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461289857600080fd5b73ffffffffffffffffffffffffffffffffffffffff81168114611ca657600080fd5b8035612e2281612df5565b919050565b600060208284031215612e3957600080fd5b813561289881612df5565b60005b83811015612e5f578181015183820152602001612e47565b50506000910152565b6020815260008251806020840152612e87816040850160208701612e44565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b77ffffffffffffffffffffffffffffffffffffffffffffffff81168114611ca657600080fd5b600080600060608486031215612ef457600080fd5b8335612eff81612df5565b92506020840135612f0f81612df5565b91506040840135612f1f81612eb9565b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612fa057612fa0612f2a565b604052919050565b60008083601f840112612fba57600080fd5b50813567ffffffffffffffff811115612fd257600080fd5b6020830191508360208260051b8501011115612fed57600080fd5b9250929050565b60008083601f84011261300657600080fd5b50813567ffffffffffffffff81111561301e57600080fd5b602083019150836020828501011115612fed57600080fd5b6000806000806000806080878903121561304f57600080fd5b863567ffffffffffffffff8082111561306757600080fd5b818901915089601f83011261307b57600080fd5b813560208282111561308f5761308f612f2a565b8160051b61309e828201612f59565b928352848101820192828101908e8511156130b857600080fd5b958301955b848710156130d6578635825295830195908301906130bd565b9b5050508a0135925050808211156130ed57600080fd5b6130f98a838b01612fa8565b9097509550604089013591508082111561311257600080fd5b5061311f89828a01612ff4565b9094509250613132905060608801612e17565b90509295509295509295565b803567ffffffffffffffff81168114612e2257600080fd5b60006020828403121561316857600080fd5b6128988261313e565b6000806000806000806080878903121561318a57600080fd5b86359550602087013567ffffffffffffffff808211156131a957600080fd5b6131b58a838b01612ff4565b909750955060408901359150808211156131ce57600080fd5b506131db89828a01612ff4565b90945092505060608701356131ef81612df5565b809150509295509295509295565b60008060006060848603121561321257600080fd5b833561321d81612df5565b9250602084013591506040840135612f1f81612df5565b6000806000806080858703121561324a57600080fd5b843561325581612df5565b935060208501359250604085013561326c81612df5565b915061327a6060860161313e565b905092959194509250565b600082601f83011261329657600080fd5b813567ffffffffffffffff8111156132b0576132b0612f2a565b6132e160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612f59565b8181528460208386010111156132f657600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561332857600080fd5b833561333381612df5565b9250602084013567ffffffffffffffff81111561334f57600080fd5b61335b86828701613285565b9250506040840135612f1f81612df5565b60008060006040848603121561338157600080fd5b83359250602084013567ffffffffffffffff808211156133a057600080fd5b818601915086601f8301126133b457600080fd5b8135818111156133c357600080fd5b8760208260061b85010111156133d857600080fd5b6020830194508093505050509250925092565b6000602082840312156133fd57600080fd5b8151801515811461289857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261347157600080fd5b83018035915067ffffffffffffffff82111561348c57600080fd5b602001915036819003821315612fed57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613501576135016134a1565b5060010190565b60006020828403121561351a57600080fd5b5051919050565b80516020808301519190811015613560577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b805163ffffffff81168114612e2257600080fd5b60008060008060008060c0878903121561359357600080fd5b865195506135a360208801613566565b94506135b160408801613566565b935060608701516135c181612eb9565b60808801519093506135d281612eb9565b915061313260a08801613566565b818103818111156108e4576108e46134a1565b80820281158282048414176108e4576108e46134a1565b808201808211156108e4576108e46134a1565b600081518084526020808501945080840160005b838110156136725781518051885283015177ffffffffffffffffffffffffffffffffffffffffffffffff168388015260409096019590820190600101613631565b509495945050505050565b604081526000613690604083018561361d565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b8381526040602080830182905282820184905260009190859060608501845b878110156137285783356136e781612df5565b73ffffffffffffffffffffffffffffffffffffffff16825267ffffffffffffffff61371385850161313e565b168284015292840192908401906001016136d4565b5098975050505050505050565b6000806080838503121561374857600080fd5b83601f84011261375757600080fd5b6040516060810167ffffffffffffffff828210818311171561377b5761377b612f2a565b81604052829150606086018781111561379357600080fd5b865b818110156137ad578035845260209384019301613795565b50929450913591808311156137c157600080fd5b50506137cf85828601613285565b9150509250929050565b602081526000612898602083018461361d565b600082613822577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008251613839818460208701612e44565b919091019291505056fea164736f6c6343000813000a",
+}
+
+var DestinationFeeManagerABI = DestinationFeeManagerMetaData.ABI
+
+var DestinationFeeManagerBin = DestinationFeeManagerMetaData.Bin
+
+func DeployDestinationFeeManager(auth *bind.TransactOpts, backend bind.ContractBackend, _linkAddress common.Address, _nativeAddress common.Address, _verifierAddress common.Address, _rewardManagerAddress common.Address) (common.Address, *types.Transaction, *DestinationFeeManager, error) {
+ parsed, err := DestinationFeeManagerMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DestinationFeeManagerBin), backend, _linkAddress, _nativeAddress, _verifierAddress, _rewardManagerAddress)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &DestinationFeeManager{address: address, abi: *parsed, DestinationFeeManagerCaller: DestinationFeeManagerCaller{contract: contract}, DestinationFeeManagerTransactor: DestinationFeeManagerTransactor{contract: contract}, DestinationFeeManagerFilterer: DestinationFeeManagerFilterer{contract: contract}}, nil
+}
+
+type DestinationFeeManager struct {
+ address common.Address
+ abi abi.ABI
+ DestinationFeeManagerCaller
+ DestinationFeeManagerTransactor
+ DestinationFeeManagerFilterer
+}
+
+type DestinationFeeManagerCaller struct {
+ contract *bind.BoundContract
+}
+
+type DestinationFeeManagerTransactor struct {
+ contract *bind.BoundContract
+}
+
+type DestinationFeeManagerFilterer struct {
+ contract *bind.BoundContract
+}
+
+type DestinationFeeManagerSession struct {
+ Contract *DestinationFeeManager
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type DestinationFeeManagerCallerSession struct {
+ Contract *DestinationFeeManagerCaller
+ CallOpts bind.CallOpts
+}
+
+type DestinationFeeManagerTransactorSession struct {
+ Contract *DestinationFeeManagerTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type DestinationFeeManagerRaw struct {
+ Contract *DestinationFeeManager
+}
+
+type DestinationFeeManagerCallerRaw struct {
+ Contract *DestinationFeeManagerCaller
+}
+
+type DestinationFeeManagerTransactorRaw struct {
+ Contract *DestinationFeeManagerTransactor
+}
+
+func NewDestinationFeeManager(address common.Address, backend bind.ContractBackend) (*DestinationFeeManager, error) {
+ abi, err := abi.JSON(strings.NewReader(DestinationFeeManagerABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindDestinationFeeManager(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManager{address: address, abi: abi, DestinationFeeManagerCaller: DestinationFeeManagerCaller{contract: contract}, DestinationFeeManagerTransactor: DestinationFeeManagerTransactor{contract: contract}, DestinationFeeManagerFilterer: DestinationFeeManagerFilterer{contract: contract}}, nil
+}
+
+func NewDestinationFeeManagerCaller(address common.Address, caller bind.ContractCaller) (*DestinationFeeManagerCaller, error) {
+ contract, err := bindDestinationFeeManager(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerCaller{contract: contract}, nil
+}
+
+func NewDestinationFeeManagerTransactor(address common.Address, transactor bind.ContractTransactor) (*DestinationFeeManagerTransactor, error) {
+ contract, err := bindDestinationFeeManager(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerTransactor{contract: contract}, nil
+}
+
+func NewDestinationFeeManagerFilterer(address common.Address, filterer bind.ContractFilterer) (*DestinationFeeManagerFilterer, error) {
+ contract, err := bindDestinationFeeManager(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerFilterer{contract: contract}, nil
+}
+
+func bindDestinationFeeManager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := DestinationFeeManagerMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _DestinationFeeManager.Contract.DestinationFeeManagerCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.DestinationFeeManagerTransactor.contract.Transfer(opts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.DestinationFeeManagerTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _DestinationFeeManager.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.contract.Transfer(opts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quoteAddress common.Address) (CommonAsset, CommonAsset, *big.Int, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "getFeeAndReward", subscriber, report, quoteAddress)
+
+ if err != nil {
+ return *new(CommonAsset), *new(CommonAsset), *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(CommonAsset)).(*CommonAsset)
+ out1 := *abi.ConvertType(out[1], new(CommonAsset)).(*CommonAsset)
+ out2 := *abi.ConvertType(out[2], new(*big.Int)).(**big.Int)
+
+ return out0, out1, out2, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) GetFeeAndReward(subscriber common.Address, report []byte, quoteAddress common.Address) (CommonAsset, CommonAsset, *big.Int, error) {
+ return _DestinationFeeManager.Contract.GetFeeAndReward(&_DestinationFeeManager.CallOpts, subscriber, report, quoteAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) GetFeeAndReward(subscriber common.Address, report []byte, quoteAddress common.Address) (CommonAsset, CommonAsset, *big.Int, error) {
+ return _DestinationFeeManager.Contract.GetFeeAndReward(&_DestinationFeeManager.CallOpts, subscriber, report, quoteAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) ILinkAddress(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "i_linkAddress")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) ILinkAddress() (common.Address, error) {
+ return _DestinationFeeManager.Contract.ILinkAddress(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) ILinkAddress() (common.Address, error) {
+ return _DestinationFeeManager.Contract.ILinkAddress(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) INativeAddress(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "i_nativeAddress")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) INativeAddress() (common.Address, error) {
+ return _DestinationFeeManager.Contract.INativeAddress(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) INativeAddress() (common.Address, error) {
+ return _DestinationFeeManager.Contract.INativeAddress(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) IRewardManager(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "i_rewardManager")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) IRewardManager() (common.Address, error) {
+ return _DestinationFeeManager.Contract.IRewardManager(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) IRewardManager() (common.Address, error) {
+ return _DestinationFeeManager.Contract.IRewardManager(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.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
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _DestinationFeeManager.Contract.LinkAvailableForPayment(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) LinkAvailableForPayment() (*big.Int, error) {
+ return _DestinationFeeManager.Contract.LinkAvailableForPayment(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) Owner() (common.Address, error) {
+ return _DestinationFeeManager.Contract.Owner(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) Owner() (common.Address, error) {
+ return _DestinationFeeManager.Contract.Owner(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) SLinkDeficit(opts *bind.CallOpts, arg0 [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "s_linkDeficit", arg0)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) SLinkDeficit(arg0 [32]byte) (*big.Int, error) {
+ return _DestinationFeeManager.Contract.SLinkDeficit(&_DestinationFeeManager.CallOpts, arg0)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) SLinkDeficit(arg0 [32]byte) (*big.Int, error) {
+ return _DestinationFeeManager.Contract.SLinkDeficit(&_DestinationFeeManager.CallOpts, arg0)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) SNativeSurcharge(opts *bind.CallOpts) (*big.Int, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "s_nativeSurcharge")
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) SNativeSurcharge() (*big.Int, error) {
+ return _DestinationFeeManager.Contract.SNativeSurcharge(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) SNativeSurcharge() (*big.Int, error) {
+ return _DestinationFeeManager.Contract.SNativeSurcharge(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) SSubscriberDiscounts(opts *bind.CallOpts, arg0 common.Address, arg1 [32]byte, arg2 common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "s_subscriberDiscounts", arg0, arg1, arg2)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) SSubscriberDiscounts(arg0 common.Address, arg1 [32]byte, arg2 common.Address) (*big.Int, error) {
+ return _DestinationFeeManager.Contract.SSubscriberDiscounts(&_DestinationFeeManager.CallOpts, arg0, arg1, arg2)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) SSubscriberDiscounts(arg0 common.Address, arg1 [32]byte, arg2 common.Address) (*big.Int, error) {
+ return _DestinationFeeManager.Contract.SSubscriberDiscounts(&_DestinationFeeManager.CallOpts, arg0, arg1, arg2)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) SVerifierAddressList(opts *bind.CallOpts, arg0 common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "s_verifierAddressList", arg0)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) SVerifierAddressList(arg0 common.Address) (common.Address, error) {
+ return _DestinationFeeManager.Contract.SVerifierAddressList(&_DestinationFeeManager.CallOpts, arg0)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) SVerifierAddressList(arg0 common.Address) (common.Address, error) {
+ return _DestinationFeeManager.Contract.SVerifierAddressList(&_DestinationFeeManager.CallOpts, arg0)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _DestinationFeeManager.Contract.SupportsInterface(&_DestinationFeeManager.CallOpts, interfaceId)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _DestinationFeeManager.Contract.SupportsInterface(&_DestinationFeeManager.CallOpts, interfaceId)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _DestinationFeeManager.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) TypeAndVersion() (string, error) {
+ return _DestinationFeeManager.Contract.TypeAndVersion(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerCallerSession) TypeAndVersion() (string, error) {
+ return _DestinationFeeManager.Contract.TypeAndVersion(&_DestinationFeeManager.CallOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) AcceptOwnership() (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.AcceptOwnership(&_DestinationFeeManager.TransactOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.AcceptOwnership(&_DestinationFeeManager.TransactOpts)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) AddVerifier(opts *bind.TransactOpts, verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "addVerifier", verifierAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) AddVerifier(verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.AddVerifier(&_DestinationFeeManager.TransactOpts, verifierAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) AddVerifier(verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.AddVerifier(&_DestinationFeeManager.TransactOpts, verifierAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) PayLinkDeficit(opts *bind.TransactOpts, configDigest [32]byte) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "payLinkDeficit", configDigest)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) PayLinkDeficit(configDigest [32]byte) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.PayLinkDeficit(&_DestinationFeeManager.TransactOpts, configDigest)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) PayLinkDeficit(configDigest [32]byte) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.PayLinkDeficit(&_DestinationFeeManager.TransactOpts, configDigest)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) ProcessFee(opts *bind.TransactOpts, recipient [32]byte, payload []byte, parameterPayload []byte, subscriber common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "processFee", recipient, payload, parameterPayload, subscriber)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) ProcessFee(recipient [32]byte, payload []byte, parameterPayload []byte, subscriber common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.ProcessFee(&_DestinationFeeManager.TransactOpts, recipient, payload, parameterPayload, subscriber)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) ProcessFee(recipient [32]byte, payload []byte, parameterPayload []byte, subscriber common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.ProcessFee(&_DestinationFeeManager.TransactOpts, recipient, payload, parameterPayload, subscriber)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) ProcessFeeBulk(opts *bind.TransactOpts, poolIds [][32]byte, payloads [][]byte, parameterPayload []byte, subscriber common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "processFeeBulk", poolIds, payloads, parameterPayload, subscriber)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) ProcessFeeBulk(poolIds [][32]byte, payloads [][]byte, parameterPayload []byte, subscriber common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.ProcessFeeBulk(&_DestinationFeeManager.TransactOpts, poolIds, payloads, parameterPayload, subscriber)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) ProcessFeeBulk(poolIds [][32]byte, payloads [][]byte, parameterPayload []byte, subscriber common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.ProcessFeeBulk(&_DestinationFeeManager.TransactOpts, poolIds, payloads, parameterPayload, subscriber)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) RemoveVerifier(opts *bind.TransactOpts, verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "removeVerifier", verifierAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) RemoveVerifier(verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.RemoveVerifier(&_DestinationFeeManager.TransactOpts, verifierAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) RemoveVerifier(verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.RemoveVerifier(&_DestinationFeeManager.TransactOpts, verifierAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) SetFeeRecipients(opts *bind.TransactOpts, configDigest [32]byte, rewardRecipientAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "setFeeRecipients", configDigest, rewardRecipientAndWeights)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) SetFeeRecipients(configDigest [32]byte, rewardRecipientAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.SetFeeRecipients(&_DestinationFeeManager.TransactOpts, configDigest, rewardRecipientAndWeights)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) SetFeeRecipients(configDigest [32]byte, rewardRecipientAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.SetFeeRecipients(&_DestinationFeeManager.TransactOpts, configDigest, rewardRecipientAndWeights)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) SetNativeSurcharge(opts *bind.TransactOpts, surcharge uint64) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "setNativeSurcharge", surcharge)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) SetNativeSurcharge(surcharge uint64) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.SetNativeSurcharge(&_DestinationFeeManager.TransactOpts, surcharge)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) SetNativeSurcharge(surcharge uint64) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.SetNativeSurcharge(&_DestinationFeeManager.TransactOpts, surcharge)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) SetRewardManager(opts *bind.TransactOpts, rewardManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "setRewardManager", rewardManagerAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) SetRewardManager(rewardManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.SetRewardManager(&_DestinationFeeManager.TransactOpts, rewardManagerAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) SetRewardManager(rewardManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.SetRewardManager(&_DestinationFeeManager.TransactOpts, rewardManagerAddress)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.TransferOwnership(&_DestinationFeeManager.TransactOpts, to)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.TransferOwnership(&_DestinationFeeManager.TransactOpts, to)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) UpdateSubscriberDiscount(opts *bind.TransactOpts, subscriber common.Address, feedId [32]byte, token common.Address, discount uint64) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "updateSubscriberDiscount", subscriber, feedId, token, discount)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) UpdateSubscriberDiscount(subscriber common.Address, feedId [32]byte, token common.Address, discount uint64) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.UpdateSubscriberDiscount(&_DestinationFeeManager.TransactOpts, subscriber, feedId, token, discount)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) UpdateSubscriberDiscount(subscriber common.Address, feedId [32]byte, token common.Address, discount uint64) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.UpdateSubscriberDiscount(&_DestinationFeeManager.TransactOpts, subscriber, feedId, token, discount)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactor) Withdraw(opts *bind.TransactOpts, assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) {
+ return _DestinationFeeManager.contract.Transact(opts, "withdraw", assetAddress, recipient, quantity)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerSession) Withdraw(assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.Withdraw(&_DestinationFeeManager.TransactOpts, assetAddress, recipient, quantity)
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerTransactorSession) Withdraw(assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error) {
+ return _DestinationFeeManager.Contract.Withdraw(&_DestinationFeeManager.TransactOpts, assetAddress, recipient, quantity)
+}
+
+type DestinationFeeManagerDiscountAppliedIterator struct {
+ Event *DestinationFeeManagerDiscountApplied
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationFeeManagerDiscountAppliedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationFeeManagerDiscountApplied)
+ 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(DestinationFeeManagerDiscountApplied)
+ 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 *DestinationFeeManagerDiscountAppliedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationFeeManagerDiscountAppliedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationFeeManagerDiscountApplied struct {
+ ConfigDigest [32]byte
+ Subscriber common.Address
+ Fee CommonAsset
+ Reward CommonAsset
+ AppliedDiscount *big.Int
+ Raw types.Log
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) FilterDiscountApplied(opts *bind.FilterOpts, configDigest [][32]byte, subscriber []common.Address) (*DestinationFeeManagerDiscountAppliedIterator, error) {
+
+ var configDigestRule []interface{}
+ for _, configDigestItem := range configDigest {
+ configDigestRule = append(configDigestRule, configDigestItem)
+ }
+ var subscriberRule []interface{}
+ for _, subscriberItem := range subscriber {
+ subscriberRule = append(subscriberRule, subscriberItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.FilterLogs(opts, "DiscountApplied", configDigestRule, subscriberRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerDiscountAppliedIterator{contract: _DestinationFeeManager.contract, event: "DiscountApplied", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) WatchDiscountApplied(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerDiscountApplied, configDigest [][32]byte, subscriber []common.Address) (event.Subscription, error) {
+
+ var configDigestRule []interface{}
+ for _, configDigestItem := range configDigest {
+ configDigestRule = append(configDigestRule, configDigestItem)
+ }
+ var subscriberRule []interface{}
+ for _, subscriberItem := range subscriber {
+ subscriberRule = append(subscriberRule, subscriberItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.WatchLogs(opts, "DiscountApplied", configDigestRule, subscriberRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationFeeManagerDiscountApplied)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "DiscountApplied", 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 (_DestinationFeeManager *DestinationFeeManagerFilterer) ParseDiscountApplied(log types.Log) (*DestinationFeeManagerDiscountApplied, error) {
+ event := new(DestinationFeeManagerDiscountApplied)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "DiscountApplied", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationFeeManagerInsufficientLinkIterator struct {
+ Event *DestinationFeeManagerInsufficientLink
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationFeeManagerInsufficientLinkIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationFeeManagerInsufficientLink)
+ 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(DestinationFeeManagerInsufficientLink)
+ 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 *DestinationFeeManagerInsufficientLinkIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationFeeManagerInsufficientLinkIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationFeeManagerInsufficientLink struct {
+ Rewards []IDestinationRewardManagerFeePayment
+ Raw types.Log
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) FilterInsufficientLink(opts *bind.FilterOpts) (*DestinationFeeManagerInsufficientLinkIterator, error) {
+
+ logs, sub, err := _DestinationFeeManager.contract.FilterLogs(opts, "InsufficientLink")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerInsufficientLinkIterator{contract: _DestinationFeeManager.contract, event: "InsufficientLink", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) WatchInsufficientLink(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerInsufficientLink) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationFeeManager.contract.WatchLogs(opts, "InsufficientLink")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationFeeManagerInsufficientLink)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "InsufficientLink", 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 (_DestinationFeeManager *DestinationFeeManagerFilterer) ParseInsufficientLink(log types.Log) (*DestinationFeeManagerInsufficientLink, error) {
+ event := new(DestinationFeeManagerInsufficientLink)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "InsufficientLink", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationFeeManagerLinkDeficitClearedIterator struct {
+ Event *DestinationFeeManagerLinkDeficitCleared
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationFeeManagerLinkDeficitClearedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationFeeManagerLinkDeficitCleared)
+ 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(DestinationFeeManagerLinkDeficitCleared)
+ 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 *DestinationFeeManagerLinkDeficitClearedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationFeeManagerLinkDeficitClearedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationFeeManagerLinkDeficitCleared struct {
+ ConfigDigest [32]byte
+ LinkQuantity *big.Int
+ Raw types.Log
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) FilterLinkDeficitCleared(opts *bind.FilterOpts, configDigest [][32]byte) (*DestinationFeeManagerLinkDeficitClearedIterator, error) {
+
+ var configDigestRule []interface{}
+ for _, configDigestItem := range configDigest {
+ configDigestRule = append(configDigestRule, configDigestItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.FilterLogs(opts, "LinkDeficitCleared", configDigestRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerLinkDeficitClearedIterator{contract: _DestinationFeeManager.contract, event: "LinkDeficitCleared", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) WatchLinkDeficitCleared(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerLinkDeficitCleared, configDigest [][32]byte) (event.Subscription, error) {
+
+ var configDigestRule []interface{}
+ for _, configDigestItem := range configDigest {
+ configDigestRule = append(configDigestRule, configDigestItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.WatchLogs(opts, "LinkDeficitCleared", configDigestRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationFeeManagerLinkDeficitCleared)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "LinkDeficitCleared", 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 (_DestinationFeeManager *DestinationFeeManagerFilterer) ParseLinkDeficitCleared(log types.Log) (*DestinationFeeManagerLinkDeficitCleared, error) {
+ event := new(DestinationFeeManagerLinkDeficitCleared)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "LinkDeficitCleared", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationFeeManagerNativeSurchargeUpdatedIterator struct {
+ Event *DestinationFeeManagerNativeSurchargeUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationFeeManagerNativeSurchargeUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationFeeManagerNativeSurchargeUpdated)
+ 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(DestinationFeeManagerNativeSurchargeUpdated)
+ 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 *DestinationFeeManagerNativeSurchargeUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationFeeManagerNativeSurchargeUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationFeeManagerNativeSurchargeUpdated struct {
+ NewSurcharge uint64
+ Raw types.Log
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) FilterNativeSurchargeUpdated(opts *bind.FilterOpts) (*DestinationFeeManagerNativeSurchargeUpdatedIterator, error) {
+
+ logs, sub, err := _DestinationFeeManager.contract.FilterLogs(opts, "NativeSurchargeUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerNativeSurchargeUpdatedIterator{contract: _DestinationFeeManager.contract, event: "NativeSurchargeUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) WatchNativeSurchargeUpdated(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerNativeSurchargeUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationFeeManager.contract.WatchLogs(opts, "NativeSurchargeUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationFeeManagerNativeSurchargeUpdated)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "NativeSurchargeUpdated", 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 (_DestinationFeeManager *DestinationFeeManagerFilterer) ParseNativeSurchargeUpdated(log types.Log) (*DestinationFeeManagerNativeSurchargeUpdated, error) {
+ event := new(DestinationFeeManagerNativeSurchargeUpdated)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "NativeSurchargeUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationFeeManagerOwnershipTransferRequestedIterator struct {
+ Event *DestinationFeeManagerOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationFeeManagerOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationFeeManagerOwnershipTransferRequested)
+ 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(DestinationFeeManagerOwnershipTransferRequested)
+ 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 *DestinationFeeManagerOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationFeeManagerOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationFeeManagerOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationFeeManagerOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerOwnershipTransferRequestedIterator{contract: _DestinationFeeManager.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationFeeManagerOwnershipTransferRequested)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_DestinationFeeManager *DestinationFeeManagerFilterer) ParseOwnershipTransferRequested(log types.Log) (*DestinationFeeManagerOwnershipTransferRequested, error) {
+ event := new(DestinationFeeManagerOwnershipTransferRequested)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationFeeManagerOwnershipTransferredIterator struct {
+ Event *DestinationFeeManagerOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationFeeManagerOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationFeeManagerOwnershipTransferred)
+ 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(DestinationFeeManagerOwnershipTransferred)
+ 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 *DestinationFeeManagerOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationFeeManagerOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationFeeManagerOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationFeeManagerOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerOwnershipTransferredIterator{contract: _DestinationFeeManager.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationFeeManagerOwnershipTransferred)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "OwnershipTransferred", 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 (_DestinationFeeManager *DestinationFeeManagerFilterer) ParseOwnershipTransferred(log types.Log) (*DestinationFeeManagerOwnershipTransferred, error) {
+ event := new(DestinationFeeManagerOwnershipTransferred)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationFeeManagerSubscriberDiscountUpdatedIterator struct {
+ Event *DestinationFeeManagerSubscriberDiscountUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationFeeManagerSubscriberDiscountUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationFeeManagerSubscriberDiscountUpdated)
+ 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(DestinationFeeManagerSubscriberDiscountUpdated)
+ 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 *DestinationFeeManagerSubscriberDiscountUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationFeeManagerSubscriberDiscountUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationFeeManagerSubscriberDiscountUpdated struct {
+ Subscriber common.Address
+ FeedId [32]byte
+ Token common.Address
+ Discount uint64
+ Raw types.Log
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) FilterSubscriberDiscountUpdated(opts *bind.FilterOpts, subscriber []common.Address, feedId [][32]byte) (*DestinationFeeManagerSubscriberDiscountUpdatedIterator, error) {
+
+ var subscriberRule []interface{}
+ for _, subscriberItem := range subscriber {
+ subscriberRule = append(subscriberRule, subscriberItem)
+ }
+ var feedIdRule []interface{}
+ for _, feedIdItem := range feedId {
+ feedIdRule = append(feedIdRule, feedIdItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.FilterLogs(opts, "SubscriberDiscountUpdated", subscriberRule, feedIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerSubscriberDiscountUpdatedIterator{contract: _DestinationFeeManager.contract, event: "SubscriberDiscountUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) WatchSubscriberDiscountUpdated(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerSubscriberDiscountUpdated, subscriber []common.Address, feedId [][32]byte) (event.Subscription, error) {
+
+ var subscriberRule []interface{}
+ for _, subscriberItem := range subscriber {
+ subscriberRule = append(subscriberRule, subscriberItem)
+ }
+ var feedIdRule []interface{}
+ for _, feedIdItem := range feedId {
+ feedIdRule = append(feedIdRule, feedIdItem)
+ }
+
+ logs, sub, err := _DestinationFeeManager.contract.WatchLogs(opts, "SubscriberDiscountUpdated", subscriberRule, feedIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationFeeManagerSubscriberDiscountUpdated)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "SubscriberDiscountUpdated", 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 (_DestinationFeeManager *DestinationFeeManagerFilterer) ParseSubscriberDiscountUpdated(log types.Log) (*DestinationFeeManagerSubscriberDiscountUpdated, error) {
+ event := new(DestinationFeeManagerSubscriberDiscountUpdated)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "SubscriberDiscountUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationFeeManagerWithdrawIterator struct {
+ Event *DestinationFeeManagerWithdraw
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationFeeManagerWithdrawIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationFeeManagerWithdraw)
+ 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(DestinationFeeManagerWithdraw)
+ 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 *DestinationFeeManagerWithdrawIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationFeeManagerWithdrawIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationFeeManagerWithdraw struct {
+ AdminAddress common.Address
+ Recipient common.Address
+ AssetAddress common.Address
+ Quantity *big.Int
+ Raw types.Log
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) FilterWithdraw(opts *bind.FilterOpts) (*DestinationFeeManagerWithdrawIterator, error) {
+
+ logs, sub, err := _DestinationFeeManager.contract.FilterLogs(opts, "Withdraw")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationFeeManagerWithdrawIterator{contract: _DestinationFeeManager.contract, event: "Withdraw", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManagerFilterer) WatchWithdraw(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerWithdraw) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationFeeManager.contract.WatchLogs(opts, "Withdraw")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationFeeManagerWithdraw)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "Withdraw", 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 (_DestinationFeeManager *DestinationFeeManagerFilterer) ParseWithdraw(log types.Log) (*DestinationFeeManagerWithdraw, error) {
+ event := new(DestinationFeeManagerWithdraw)
+ if err := _DestinationFeeManager.contract.UnpackLog(event, "Withdraw", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_DestinationFeeManager *DestinationFeeManager) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _DestinationFeeManager.abi.Events["DiscountApplied"].ID:
+ return _DestinationFeeManager.ParseDiscountApplied(log)
+ case _DestinationFeeManager.abi.Events["InsufficientLink"].ID:
+ return _DestinationFeeManager.ParseInsufficientLink(log)
+ case _DestinationFeeManager.abi.Events["LinkDeficitCleared"].ID:
+ return _DestinationFeeManager.ParseLinkDeficitCleared(log)
+ case _DestinationFeeManager.abi.Events["NativeSurchargeUpdated"].ID:
+ return _DestinationFeeManager.ParseNativeSurchargeUpdated(log)
+ case _DestinationFeeManager.abi.Events["OwnershipTransferRequested"].ID:
+ return _DestinationFeeManager.ParseOwnershipTransferRequested(log)
+ case _DestinationFeeManager.abi.Events["OwnershipTransferred"].ID:
+ return _DestinationFeeManager.ParseOwnershipTransferred(log)
+ case _DestinationFeeManager.abi.Events["SubscriberDiscountUpdated"].ID:
+ return _DestinationFeeManager.ParseSubscriberDiscountUpdated(log)
+ case _DestinationFeeManager.abi.Events["Withdraw"].ID:
+ return _DestinationFeeManager.ParseWithdraw(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (DestinationFeeManagerDiscountApplied) Topic() common.Hash {
+ return common.HexToHash("0x88b15eb682210089cddf967648e2cb2a4535aeadc8f8f36050922e33c04e7125")
+}
+
+func (DestinationFeeManagerInsufficientLink) Topic() common.Hash {
+ return common.HexToHash("0xf52e5907b69d97c33392936c12d78b494463b78c5b72df50b4c497eee5720b67")
+}
+
+func (DestinationFeeManagerLinkDeficitCleared) Topic() common.Hash {
+ return common.HexToHash("0x843f0b103e50b42b08f9d30f12f961845a6d02623730872e24644899c0dd9895")
+}
+
+func (DestinationFeeManagerNativeSurchargeUpdated) Topic() common.Hash {
+ return common.HexToHash("0x08f7c0d17932ddb8523bc06754d42ff19ebc77d76a8b9bfde02c28ab1ed3d639")
+}
+
+func (DestinationFeeManagerOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (DestinationFeeManagerOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (DestinationFeeManagerSubscriberDiscountUpdated) Topic() common.Hash {
+ return common.HexToHash("0x5eba5a8afa39780f0f99b6cbeb95f3da6a7040ca00abd46bdc91a0a060134139")
+}
+
+func (DestinationFeeManagerWithdraw) Topic() common.Hash {
+ return common.HexToHash("0x7ff78a71698bdb18dcca96f52ab25e0a1b146fb6a49adf8e6845299e49021f29")
+}
+
+func (_DestinationFeeManager *DestinationFeeManager) Address() common.Address {
+ return _DestinationFeeManager.address
+}
+
+type DestinationFeeManagerInterface interface {
+ GetFeeAndReward(opts *bind.CallOpts, subscriber common.Address, report []byte, quoteAddress common.Address) (CommonAsset, CommonAsset, *big.Int, error)
+
+ ILinkAddress(opts *bind.CallOpts) (common.Address, error)
+
+ INativeAddress(opts *bind.CallOpts) (common.Address, error)
+
+ IRewardManager(opts *bind.CallOpts) (common.Address, error)
+
+ LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SLinkDeficit(opts *bind.CallOpts, arg0 [32]byte) (*big.Int, error)
+
+ SNativeSurcharge(opts *bind.CallOpts) (*big.Int, error)
+
+ SSubscriberDiscounts(opts *bind.CallOpts, arg0 common.Address, arg1 [32]byte, arg2 common.Address) (*big.Int, error)
+
+ SVerifierAddressList(opts *bind.CallOpts, arg0 common.Address) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ AddVerifier(opts *bind.TransactOpts, verifierAddress common.Address) (*types.Transaction, error)
+
+ PayLinkDeficit(opts *bind.TransactOpts, configDigest [32]byte) (*types.Transaction, error)
+
+ ProcessFee(opts *bind.TransactOpts, recipient [32]byte, payload []byte, parameterPayload []byte, subscriber common.Address) (*types.Transaction, error)
+
+ ProcessFeeBulk(opts *bind.TransactOpts, poolIds [][32]byte, payloads [][]byte, parameterPayload []byte, subscriber common.Address) (*types.Transaction, error)
+
+ RemoveVerifier(opts *bind.TransactOpts, verifierAddress common.Address) (*types.Transaction, error)
+
+ SetFeeRecipients(opts *bind.TransactOpts, configDigest [32]byte, rewardRecipientAndWeights []CommonAddressAndWeight) (*types.Transaction, error)
+
+ SetNativeSurcharge(opts *bind.TransactOpts, surcharge uint64) (*types.Transaction, error)
+
+ SetRewardManager(opts *bind.TransactOpts, rewardManagerAddress common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ UpdateSubscriberDiscount(opts *bind.TransactOpts, subscriber common.Address, feedId [32]byte, token common.Address, discount uint64) (*types.Transaction, error)
+
+ Withdraw(opts *bind.TransactOpts, assetAddress common.Address, recipient common.Address, quantity *big.Int) (*types.Transaction, error)
+
+ FilterDiscountApplied(opts *bind.FilterOpts, configDigest [][32]byte, subscriber []common.Address) (*DestinationFeeManagerDiscountAppliedIterator, error)
+
+ WatchDiscountApplied(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerDiscountApplied, configDigest [][32]byte, subscriber []common.Address) (event.Subscription, error)
+
+ ParseDiscountApplied(log types.Log) (*DestinationFeeManagerDiscountApplied, error)
+
+ FilterInsufficientLink(opts *bind.FilterOpts) (*DestinationFeeManagerInsufficientLinkIterator, error)
+
+ WatchInsufficientLink(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerInsufficientLink) (event.Subscription, error)
+
+ ParseInsufficientLink(log types.Log) (*DestinationFeeManagerInsufficientLink, error)
+
+ FilterLinkDeficitCleared(opts *bind.FilterOpts, configDigest [][32]byte) (*DestinationFeeManagerLinkDeficitClearedIterator, error)
+
+ WatchLinkDeficitCleared(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerLinkDeficitCleared, configDigest [][32]byte) (event.Subscription, error)
+
+ ParseLinkDeficitCleared(log types.Log) (*DestinationFeeManagerLinkDeficitCleared, error)
+
+ FilterNativeSurchargeUpdated(opts *bind.FilterOpts) (*DestinationFeeManagerNativeSurchargeUpdatedIterator, error)
+
+ WatchNativeSurchargeUpdated(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerNativeSurchargeUpdated) (event.Subscription, error)
+
+ ParseNativeSurchargeUpdated(log types.Log) (*DestinationFeeManagerNativeSurchargeUpdated, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationFeeManagerOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*DestinationFeeManagerOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationFeeManagerOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*DestinationFeeManagerOwnershipTransferred, error)
+
+ FilterSubscriberDiscountUpdated(opts *bind.FilterOpts, subscriber []common.Address, feedId [][32]byte) (*DestinationFeeManagerSubscriberDiscountUpdatedIterator, error)
+
+ WatchSubscriberDiscountUpdated(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerSubscriberDiscountUpdated, subscriber []common.Address, feedId [][32]byte) (event.Subscription, error)
+
+ ParseSubscriberDiscountUpdated(log types.Log) (*DestinationFeeManagerSubscriberDiscountUpdated, error)
+
+ FilterWithdraw(opts *bind.FilterOpts) (*DestinationFeeManagerWithdrawIterator, error)
+
+ WatchWithdraw(opts *bind.WatchOpts, sink chan<- *DestinationFeeManagerWithdraw) (event.Subscription, error)
+
+ ParseWithdraw(log types.Log) (*DestinationFeeManagerWithdraw, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/llo-feeds/generated/destination_reward_manager/destination_reward_manager.go b/core/gethwrappers/llo-feeds/generated/destination_reward_manager/destination_reward_manager.go
new file mode 100644
index 00000000000..989482fc0ec
--- /dev/null
+++ b/core/gethwrappers/llo-feeds/generated/destination_reward_manager/destination_reward_manager.go
@@ -0,0 +1,1434 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package destination_reward_manager
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommonAddressAndWeight struct {
+ Addr common.Address
+ Weight uint64
+}
+
+type IDestinationRewardManagerFeePayment struct {
+ PoolId [32]byte
+ Amount *big.Int
+}
+
+var DestinationRewardManagerMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPoolLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidWeights\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unauthorized\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"FeeManagerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"indexed\":false,\"internalType\":\"structIDestinationRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"FeePaid\",\"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\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"RewardRecipientsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint192\",\"name\":\"quantity\",\"type\":\"uint192\"}],\"name\":\"RewardsClaimed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newFeeManagerAddress\",\"type\":\"address\"}],\"name\":\"addFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"poolIds\",\"type\":\"bytes32[]\"}],\"name\":\"claimRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"startIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endIndex\",\"type\":\"uint256\"}],\"name\":\"getAvailableRewardPoolIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_linkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"uint192\",\"name\":\"amount\",\"type\":\"uint192\"}],\"internalType\":\"structIDestinationRewardManager.FeePayment[]\",\"name\":\"payments\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"}],\"name\":\"onFeePaid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"recipients\",\"type\":\"address[]\"}],\"name\":\"payRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"feeManagerAddress\",\"type\":\"address\"}],\"name\":\"removeFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_feeManagerAddressList\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_registeredPoolIds\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_rewardRecipientWeights\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_rewardRecipientWeightsSet\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"s_totalRewardRecipientFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"s_totalRewardRecipientFeesLastClaimedAmounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"rewardRecipientAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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\":\"bytes32\",\"name\":\"poolId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"newRewardRecipients\",\"type\":\"tuple[]\"}],\"name\":\"updateRewardRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
+ Bin: "0x60a06040523480156200001157600080fd5b506040516200244c3803806200244c8339810160408190526200003491620001a6565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000fb565b5050506001600160a01b038116620000e95760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b0316608052620001d8565b336001600160a01b03821603620001555760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001b957600080fd5b81516001600160a01b0381168114620001d157600080fd5b9392505050565b60805161224a62000202600039600081816103bb0152818161107601526112b1015261224a6000f3fe608060405234801561001057600080fd5b506004361061016c5760003560e01c806360122608116100cd5780639604d05f11610081578063cd5f729211610066578063cd5f7292146103a3578063ea4b861b146103b6578063f2fde38b146103dd57600080fd5b80639604d05f1461035a578063b0d9fa191461039057600080fd5b80638115c9cc116100b25780638115c9cc146102dd5780638ac85a5c146102f05780638da5cb5b1461031b57600080fd5b806360122608146102aa57806379ba5097146102d557600080fd5b806339ee81e1116101245780634944832f116101095780634944832f146102615780634d32208414610274578063592562011461028757600080fd5b806339ee81e114610213578063472264751461024157600080fd5b806314060f231161015557806314060f23146101ae578063181f5a77146101c15780631f2d32c31461020057600080fd5b806301ffc9a7146101715780630f3c34d114610199575b600080fd5b61018461017f366004611b3d565b6103f0565b60405190151581526020015b60405180910390f35b6101ac6101a7366004611bfd565b610651565b005b6101ac6101bc366004611cef565b61065f565b604080518082018252601381527f5265776172644d616e6167657220312e302e3000000000000000000000000000602082015290516101909190611d5f565b6101ac61020e366004611dd9565b610821565b610233610221366004611df4565b60026020526000908152604090205481565b604051908152602001610190565b61025461024f366004611e0d565b610959565b6040516101909190611e40565b6101ac61026f366004611cef565b610ae3565b6101ac610282366004611e84565b610c2c565b610184610295366004611df4565b60056020526000908152604090205460ff1681565b6102336102b8366004611f03565b600360209081526000928352604080842090915290825290205481565b6101ac610d6b565b6101ac6102eb366004611dd9565b610e6d565b6102336102fe366004611f03565b600460209081526000928352604080842090915290825290205481565b60005473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610190565b610335610368366004611dd9565b60076020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b6101ac61039e366004611f2f565b610f1f565b6102336103b1366004611df4565b6110df565b6103357f000000000000000000000000000000000000000000000000000000000000000081565b6101ac6103eb366004611dd9565b611100565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f0f3c34d100000000000000000000000000000000000000000000000000000000148061048357507fffffffff0000000000000000000000000000000000000000000000000000000082167f14060f2300000000000000000000000000000000000000000000000000000000145b806104cf57507fffffffff0000000000000000000000000000000000000000000000000000000082167f4944832f00000000000000000000000000000000000000000000000000000000145b8061051b57507fffffffff0000000000000000000000000000000000000000000000000000000082167f4d32208400000000000000000000000000000000000000000000000000000000145b8061056757507fffffffff0000000000000000000000000000000000000000000000000000000082167f1f2d32c300000000000000000000000000000000000000000000000000000000145b806105b357507fffffffff0000000000000000000000000000000000000000000000000000000082167f8115c9cc00000000000000000000000000000000000000000000000000000000145b806105ff57507fffffffff0000000000000000000000000000000000000000000000000000000082167f4722647500000000000000000000000000000000000000000000000000000000145b8061064b57507fffffffff0000000000000000000000000000000000000000000000000000000082167fb0d9fa1900000000000000000000000000000000000000000000000000000000145b92915050565b61065b3382611114565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff1633148015906106ab57503360008181526007602052604090205473ffffffffffffffffffffffffffffffffffffffff1614155b156106e2576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081900361071d576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526005602052604090205460ff1615610766576040517f0afa7ee800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006805460018181019092557ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01849055600084815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790556107e2838383670de0b6b3a76400006112df565b827f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe68383604051610814929190611f9b565b60405180910390a2505050565b6108296114b6565b73ffffffffffffffffffffffffffffffffffffffff8116610876576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81811660009081526007602052604090205416156108d5576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660008181526007602090815260409182902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905590519182527fe45f5e140399b0a7e12971ab020724b828fbed8ac408c420884dc7d1bbe506b4910160405180910390a150565b600654606090600081841161096e5783610970565b815b9050808511156109ac576040517fa22caccc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006109b88683612032565b67ffffffffffffffff8111156109d0576109d0611b7f565b6040519080825280602002602001820160405280156109f9578160200160208202803683370190505b5090506000865b83811015610ad657600060068281548110610a1d57610a1d612045565b600091825260208083209091015480835260048252604080842073ffffffffffffffffffffffffffffffffffffffff8f16855290925291205490915015610ac5576000818152600260209081526040808320546003835281842073ffffffffffffffffffffffffffffffffffffffff8f168552909252909120548114610ac35781858580600101965081518110610ab657610ab6612045565b6020026020010181815250505b505b50610acf81612074565b9050610a00565b5090979650505050505050565b610aeb6114b6565b604080516001808252818301909252600091602080830190803683370190505090508381600081518110610b2157610b21612045565b6020026020010181815250506000805b83811015610bde576000858583818110610b4d57610b4d612045565b610b639260206040909202019081019150611dd9565b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902054909150610bc7878785818110610bab57610bab612045565b610bc19260206040909202019081019150611dd9565b86611114565b50929092019150610bd781612074565b9050610b31565b50610beb858585846112df565b847f8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe68585604051610c1d929190611f9b565b60405180910390a25050505050565b82610c4c60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614158015610c9e57506000818152600460209081526040808320338452909152902054155b15610cd5576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001808252818301909252600091602080830190803683370190505090508481600081518110610d0b57610d0b612045565b60200260200101818152505060005b83811015610d6357610d52858583818110610d3757610d37612045565b9050602002016020810190610d4c9190611dd9565b83611114565b50610d5c81612074565b9050610d1a565b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610df1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610e756114b6565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526007602052604090205416610ed3576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260076020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b3360008181526007602052604090205473ffffffffffffffffffffffffffffffffffffffff1614610f7c576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b8381101561105b57848482818110610f9a57610f9a612045565b9050604002016020016020810190610fb291906120d4565b77ffffffffffffffffffffffffffffffffffffffffffffffff1660026000878785818110610fe257610fe2612045565b604090810292909201358352506020820192909252016000208054909101905584848281811061101457611014612045565b905060400201602001602081019061102c91906120d4565b77ffffffffffffffffffffffffffffffffffffffffffffffff16820191508061105490612074565b9050610f80565b5061109e73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016833084611539565b7fa1cc025ea76bacce5d740ee4bc331899375dc2c5f2ab33933aaacbd9ba001b668484846040516110d1939291906120ef565b60405180910390a150505050565b600681815481106110ef57600080fd5b600091825260209091200154905081565b6111086114b6565b6111118161161b565b50565b60008060005b835181101561129057600084828151811061113757611137612045565b6020026020010151905060006002600083815260200190815260200160002054905080600003611168575050611280565b600082815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8b16808552908352818420548685526004845282852091855292528220549083039190670de0b6b3a7640000908302049050806000036111d15750505050611280565b600084815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8d16808552925290912084905588519682019689908790811061121c5761121c612045565b60200260200101517f989969655bc1d593922527fe85d71347bb8e12fa423cc71f362dd8ef7cb10ef283604051611273919077ffffffffffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a3505050505b61128981612074565b905061111a565b5080156112d8576112d873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168583611710565b9392505050565b61133a8383808060200260200160405190810160405280939291908181526020016000905b828210156113305761132160408302860136819003810190612176565b81526020019060010190611304565b505050505061176b565b15611371576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b8381101561147557600085858381811061139157611391612045565b90506040020160200160208101906113a991906121d1565b67ffffffffffffffff16905060008686848181106113c9576113c9612045565b6113df9260206040909202019081019150611dd9565b905073ffffffffffffffffffffffffffffffffffffffff811661142e576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff909416835292905220819055919091019061146e81612074565b9050611375565b508181146114af576040517f84677ce800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611537576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610de8565b565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526116159085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611822565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361169a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610de8565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526117669084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611593565b505050565b6000805b82518110156118195760006117858260016121ec565b90505b8351811015611810578381815181106117a3576117a3612045565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff168483815181106117d7576117d7612045565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1603611808575060019392505050565b600101611788565b5060010161176f565b50600092915050565b6000611884826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff1661192e9092919063ffffffff16565b80519091501561176657808060200190518101906118a291906121ff565b611766576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610de8565b606061193d8484600085611945565b949350505050565b6060824710156119d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610de8565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611a009190612221565b60006040518083038185875af1925050503d8060008114611a3d576040519150601f19603f3d011682016040523d82523d6000602084013e611a42565b606091505b5091509150611a5387838387611a5e565b979650505050505050565b60608315611af4578251600003611aed5773ffffffffffffffffffffffffffffffffffffffff85163b611aed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610de8565b508161193d565b61193d8383815115611b095781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610de89190611d5f565b600060208284031215611b4f57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146112d857600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611bf557611bf5611b7f565b604052919050565b60006020808385031215611c1057600080fd5b823567ffffffffffffffff80821115611c2857600080fd5b818501915085601f830112611c3c57600080fd5b813581811115611c4e57611c4e611b7f565b8060051b9150611c5f848301611bae565b8181529183018401918481019088841115611c7957600080fd5b938501935b83851015611c9757843582529385019390850190611c7e565b98975050505050505050565b60008083601f840112611cb557600080fd5b50813567ffffffffffffffff811115611ccd57600080fd5b6020830191508360208260061b8501011115611ce857600080fd5b9250929050565b600080600060408486031215611d0457600080fd5b83359250602084013567ffffffffffffffff811115611d2257600080fd5b611d2e86828701611ca3565b9497909650939450505050565b60005b83811015611d56578181015183820152602001611d3e565b50506000910152565b6020815260008251806020840152611d7e816040850160208701611d3b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611dd457600080fd5b919050565b600060208284031215611deb57600080fd5b6112d882611db0565b600060208284031215611e0657600080fd5b5035919050565b600080600060608486031215611e2257600080fd5b611e2b84611db0565b95602085013595506040909401359392505050565b6020808252825182820181905260009190848201906040850190845b81811015611e7857835183529284019291840191600101611e5c565b50909695505050505050565b600080600060408486031215611e9957600080fd5b83359250602084013567ffffffffffffffff80821115611eb857600080fd5b818601915086601f830112611ecc57600080fd5b813581811115611edb57600080fd5b8760208260051b8501011115611ef057600080fd5b6020830194508093505050509250925092565b60008060408385031215611f1657600080fd5b82359150611f2660208401611db0565b90509250929050565b600080600060408486031215611f4457600080fd5b833567ffffffffffffffff811115611f5b57600080fd5b611f6786828701611ca3565b9094509250611f7a905060208501611db0565b90509250925092565b803567ffffffffffffffff81168114611dd457600080fd5b6020808252818101839052600090604080840186845b87811015610ad65773ffffffffffffffffffffffffffffffffffffffff611fd783611db0565b16835267ffffffffffffffff611fee868401611f83565b16838601529183019190830190600101611fb1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561064b5761064b612003565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036120a5576120a5612003565b5060010190565b803577ffffffffffffffffffffffffffffffffffffffffffffffff81168114611dd457600080fd5b6000602082840312156120e657600080fd5b6112d8826120ac565b60408082528181018490526000908560608401835b8781101561214b5782358252602077ffffffffffffffffffffffffffffffffffffffffffffffff6121368286016120ac565b16908301529183019190830190600101612104565b5080935050505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b60006040828403121561218857600080fd5b6040516040810181811067ffffffffffffffff821117156121ab576121ab611b7f565b6040526121b783611db0565b81526121c560208401611f83565b60208201529392505050565b6000602082840312156121e357600080fd5b6112d882611f83565b8082018082111561064b5761064b612003565b60006020828403121561221157600080fd5b815180151581146112d857600080fd5b60008251612233818460208701611d3b565b919091019291505056fea164736f6c6343000813000a",
+}
+
+var DestinationRewardManagerABI = DestinationRewardManagerMetaData.ABI
+
+var DestinationRewardManagerBin = DestinationRewardManagerMetaData.Bin
+
+func DeployDestinationRewardManager(auth *bind.TransactOpts, backend bind.ContractBackend, linkAddress common.Address) (common.Address, *types.Transaction, *DestinationRewardManager, error) {
+ parsed, err := DestinationRewardManagerMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DestinationRewardManagerBin), backend, linkAddress)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &DestinationRewardManager{address: address, abi: *parsed, DestinationRewardManagerCaller: DestinationRewardManagerCaller{contract: contract}, DestinationRewardManagerTransactor: DestinationRewardManagerTransactor{contract: contract}, DestinationRewardManagerFilterer: DestinationRewardManagerFilterer{contract: contract}}, nil
+}
+
+type DestinationRewardManager struct {
+ address common.Address
+ abi abi.ABI
+ DestinationRewardManagerCaller
+ DestinationRewardManagerTransactor
+ DestinationRewardManagerFilterer
+}
+
+type DestinationRewardManagerCaller struct {
+ contract *bind.BoundContract
+}
+
+type DestinationRewardManagerTransactor struct {
+ contract *bind.BoundContract
+}
+
+type DestinationRewardManagerFilterer struct {
+ contract *bind.BoundContract
+}
+
+type DestinationRewardManagerSession struct {
+ Contract *DestinationRewardManager
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type DestinationRewardManagerCallerSession struct {
+ Contract *DestinationRewardManagerCaller
+ CallOpts bind.CallOpts
+}
+
+type DestinationRewardManagerTransactorSession struct {
+ Contract *DestinationRewardManagerTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type DestinationRewardManagerRaw struct {
+ Contract *DestinationRewardManager
+}
+
+type DestinationRewardManagerCallerRaw struct {
+ Contract *DestinationRewardManagerCaller
+}
+
+type DestinationRewardManagerTransactorRaw struct {
+ Contract *DestinationRewardManagerTransactor
+}
+
+func NewDestinationRewardManager(address common.Address, backend bind.ContractBackend) (*DestinationRewardManager, error) {
+ abi, err := abi.JSON(strings.NewReader(DestinationRewardManagerABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindDestinationRewardManager(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManager{address: address, abi: abi, DestinationRewardManagerCaller: DestinationRewardManagerCaller{contract: contract}, DestinationRewardManagerTransactor: DestinationRewardManagerTransactor{contract: contract}, DestinationRewardManagerFilterer: DestinationRewardManagerFilterer{contract: contract}}, nil
+}
+
+func NewDestinationRewardManagerCaller(address common.Address, caller bind.ContractCaller) (*DestinationRewardManagerCaller, error) {
+ contract, err := bindDestinationRewardManager(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerCaller{contract: contract}, nil
+}
+
+func NewDestinationRewardManagerTransactor(address common.Address, transactor bind.ContractTransactor) (*DestinationRewardManagerTransactor, error) {
+ contract, err := bindDestinationRewardManager(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerTransactor{contract: contract}, nil
+}
+
+func NewDestinationRewardManagerFilterer(address common.Address, filterer bind.ContractFilterer) (*DestinationRewardManagerFilterer, error) {
+ contract, err := bindDestinationRewardManager(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerFilterer{contract: contract}, nil
+}
+
+func bindDestinationRewardManager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := DestinationRewardManagerMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _DestinationRewardManager.Contract.DestinationRewardManagerCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.DestinationRewardManagerTransactor.contract.Transfer(opts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.DestinationRewardManagerTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _DestinationRewardManager.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.contract.Transfer(opts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "getAvailableRewardPoolIds", recipient, startIndex, endIndex)
+
+ if err != nil {
+ return *new([][32]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([][32]byte)).(*[][32]byte)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) GetAvailableRewardPoolIds(recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) {
+ return _DestinationRewardManager.Contract.GetAvailableRewardPoolIds(&_DestinationRewardManager.CallOpts, recipient, startIndex, endIndex)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) GetAvailableRewardPoolIds(recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error) {
+ return _DestinationRewardManager.Contract.GetAvailableRewardPoolIds(&_DestinationRewardManager.CallOpts, recipient, startIndex, endIndex)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) ILinkAddress(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "i_linkAddress")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) ILinkAddress() (common.Address, error) {
+ return _DestinationRewardManager.Contract.ILinkAddress(&_DestinationRewardManager.CallOpts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) ILinkAddress() (common.Address, error) {
+ return _DestinationRewardManager.Contract.ILinkAddress(&_DestinationRewardManager.CallOpts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) Owner() (common.Address, error) {
+ return _DestinationRewardManager.Contract.Owner(&_DestinationRewardManager.CallOpts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) Owner() (common.Address, error) {
+ return _DestinationRewardManager.Contract.Owner(&_DestinationRewardManager.CallOpts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) SFeeManagerAddressList(opts *bind.CallOpts, arg0 common.Address) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "s_feeManagerAddressList", arg0)
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) SFeeManagerAddressList(arg0 common.Address) (common.Address, error) {
+ return _DestinationRewardManager.Contract.SFeeManagerAddressList(&_DestinationRewardManager.CallOpts, arg0)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) SFeeManagerAddressList(arg0 common.Address) (common.Address, error) {
+ return _DestinationRewardManager.Contract.SFeeManagerAddressList(&_DestinationRewardManager.CallOpts, arg0)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) SRegisteredPoolIds(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "s_registeredPoolIds", arg0)
+
+ if err != nil {
+ return *new([32]byte), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) SRegisteredPoolIds(arg0 *big.Int) ([32]byte, error) {
+ return _DestinationRewardManager.Contract.SRegisteredPoolIds(&_DestinationRewardManager.CallOpts, arg0)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) SRegisteredPoolIds(arg0 *big.Int) ([32]byte, error) {
+ return _DestinationRewardManager.Contract.SRegisteredPoolIds(&_DestinationRewardManager.CallOpts, arg0)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) SRewardRecipientWeights(opts *bind.CallOpts, arg0 [32]byte, arg1 common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "s_rewardRecipientWeights", arg0, arg1)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) SRewardRecipientWeights(arg0 [32]byte, arg1 common.Address) (*big.Int, error) {
+ return _DestinationRewardManager.Contract.SRewardRecipientWeights(&_DestinationRewardManager.CallOpts, arg0, arg1)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) SRewardRecipientWeights(arg0 [32]byte, arg1 common.Address) (*big.Int, error) {
+ return _DestinationRewardManager.Contract.SRewardRecipientWeights(&_DestinationRewardManager.CallOpts, arg0, arg1)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) SRewardRecipientWeightsSet(opts *bind.CallOpts, arg0 [32]byte) (bool, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "s_rewardRecipientWeightsSet", arg0)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) SRewardRecipientWeightsSet(arg0 [32]byte) (bool, error) {
+ return _DestinationRewardManager.Contract.SRewardRecipientWeightsSet(&_DestinationRewardManager.CallOpts, arg0)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) SRewardRecipientWeightsSet(arg0 [32]byte) (bool, error) {
+ return _DestinationRewardManager.Contract.SRewardRecipientWeightsSet(&_DestinationRewardManager.CallOpts, arg0)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) STotalRewardRecipientFees(opts *bind.CallOpts, arg0 [32]byte) (*big.Int, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "s_totalRewardRecipientFees", arg0)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) STotalRewardRecipientFees(arg0 [32]byte) (*big.Int, error) {
+ return _DestinationRewardManager.Contract.STotalRewardRecipientFees(&_DestinationRewardManager.CallOpts, arg0)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) STotalRewardRecipientFees(arg0 [32]byte) (*big.Int, error) {
+ return _DestinationRewardManager.Contract.STotalRewardRecipientFees(&_DestinationRewardManager.CallOpts, arg0)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) STotalRewardRecipientFeesLastClaimedAmounts(opts *bind.CallOpts, arg0 [32]byte, arg1 common.Address) (*big.Int, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "s_totalRewardRecipientFeesLastClaimedAmounts", arg0, arg1)
+
+ if err != nil {
+ return *new(*big.Int), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) STotalRewardRecipientFeesLastClaimedAmounts(arg0 [32]byte, arg1 common.Address) (*big.Int, error) {
+ return _DestinationRewardManager.Contract.STotalRewardRecipientFeesLastClaimedAmounts(&_DestinationRewardManager.CallOpts, arg0, arg1)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) STotalRewardRecipientFeesLastClaimedAmounts(arg0 [32]byte, arg1 common.Address) (*big.Int, error) {
+ return _DestinationRewardManager.Contract.STotalRewardRecipientFeesLastClaimedAmounts(&_DestinationRewardManager.CallOpts, arg0, arg1)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _DestinationRewardManager.Contract.SupportsInterface(&_DestinationRewardManager.CallOpts, interfaceId)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _DestinationRewardManager.Contract.SupportsInterface(&_DestinationRewardManager.CallOpts, interfaceId)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _DestinationRewardManager.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) TypeAndVersion() (string, error) {
+ return _DestinationRewardManager.Contract.TypeAndVersion(&_DestinationRewardManager.CallOpts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerCallerSession) TypeAndVersion() (string, error) {
+ return _DestinationRewardManager.Contract.TypeAndVersion(&_DestinationRewardManager.CallOpts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) AcceptOwnership() (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.AcceptOwnership(&_DestinationRewardManager.TransactOpts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.AcceptOwnership(&_DestinationRewardManager.TransactOpts)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) AddFeeManager(opts *bind.TransactOpts, newFeeManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "addFeeManager", newFeeManagerAddress)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) AddFeeManager(newFeeManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.AddFeeManager(&_DestinationRewardManager.TransactOpts, newFeeManagerAddress)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) AddFeeManager(newFeeManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.AddFeeManager(&_DestinationRewardManager.TransactOpts, newFeeManagerAddress)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) ClaimRewards(opts *bind.TransactOpts, poolIds [][32]byte) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "claimRewards", poolIds)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) ClaimRewards(poolIds [][32]byte) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.ClaimRewards(&_DestinationRewardManager.TransactOpts, poolIds)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) ClaimRewards(poolIds [][32]byte) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.ClaimRewards(&_DestinationRewardManager.TransactOpts, poolIds)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) OnFeePaid(opts *bind.TransactOpts, payments []IDestinationRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "onFeePaid", payments, payer)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) OnFeePaid(payments []IDestinationRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.OnFeePaid(&_DestinationRewardManager.TransactOpts, payments, payer)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) OnFeePaid(payments []IDestinationRewardManagerFeePayment, payer common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.OnFeePaid(&_DestinationRewardManager.TransactOpts, payments, payer)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) PayRecipients(opts *bind.TransactOpts, poolId [32]byte, recipients []common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "payRecipients", poolId, recipients)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) PayRecipients(poolId [32]byte, recipients []common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.PayRecipients(&_DestinationRewardManager.TransactOpts, poolId, recipients)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) PayRecipients(poolId [32]byte, recipients []common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.PayRecipients(&_DestinationRewardManager.TransactOpts, poolId, recipients)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) RemoveFeeManager(opts *bind.TransactOpts, feeManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "removeFeeManager", feeManagerAddress)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) RemoveFeeManager(feeManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.RemoveFeeManager(&_DestinationRewardManager.TransactOpts, feeManagerAddress)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) RemoveFeeManager(feeManagerAddress common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.RemoveFeeManager(&_DestinationRewardManager.TransactOpts, feeManagerAddress)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) SetRewardRecipients(opts *bind.TransactOpts, poolId [32]byte, rewardRecipientAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "setRewardRecipients", poolId, rewardRecipientAndWeights)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) SetRewardRecipients(poolId [32]byte, rewardRecipientAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.SetRewardRecipients(&_DestinationRewardManager.TransactOpts, poolId, rewardRecipientAndWeights)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) SetRewardRecipients(poolId [32]byte, rewardRecipientAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.SetRewardRecipients(&_DestinationRewardManager.TransactOpts, poolId, rewardRecipientAndWeights)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.TransferOwnership(&_DestinationRewardManager.TransactOpts, to)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.TransferOwnership(&_DestinationRewardManager.TransactOpts, to)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactor) UpdateRewardRecipients(opts *bind.TransactOpts, poolId [32]byte, newRewardRecipients []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationRewardManager.contract.Transact(opts, "updateRewardRecipients", poolId, newRewardRecipients)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerSession) UpdateRewardRecipients(poolId [32]byte, newRewardRecipients []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.UpdateRewardRecipients(&_DestinationRewardManager.TransactOpts, poolId, newRewardRecipients)
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerTransactorSession) UpdateRewardRecipients(poolId [32]byte, newRewardRecipients []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationRewardManager.Contract.UpdateRewardRecipients(&_DestinationRewardManager.TransactOpts, poolId, newRewardRecipients)
+}
+
+type DestinationRewardManagerFeeManagerUpdatedIterator struct {
+ Event *DestinationRewardManagerFeeManagerUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationRewardManagerFeeManagerUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationRewardManagerFeeManagerUpdated)
+ 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(DestinationRewardManagerFeeManagerUpdated)
+ 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 *DestinationRewardManagerFeeManagerUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationRewardManagerFeeManagerUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationRewardManagerFeeManagerUpdated struct {
+ NewFeeManagerAddress common.Address
+ Raw types.Log
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) FilterFeeManagerUpdated(opts *bind.FilterOpts) (*DestinationRewardManagerFeeManagerUpdatedIterator, error) {
+
+ logs, sub, err := _DestinationRewardManager.contract.FilterLogs(opts, "FeeManagerUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerFeeManagerUpdatedIterator{contract: _DestinationRewardManager.contract, event: "FeeManagerUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) WatchFeeManagerUpdated(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerFeeManagerUpdated) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationRewardManager.contract.WatchLogs(opts, "FeeManagerUpdated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationRewardManagerFeeManagerUpdated)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "FeeManagerUpdated", 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 (_DestinationRewardManager *DestinationRewardManagerFilterer) ParseFeeManagerUpdated(log types.Log) (*DestinationRewardManagerFeeManagerUpdated, error) {
+ event := new(DestinationRewardManagerFeeManagerUpdated)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "FeeManagerUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationRewardManagerFeePaidIterator struct {
+ Event *DestinationRewardManagerFeePaid
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationRewardManagerFeePaidIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationRewardManagerFeePaid)
+ 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(DestinationRewardManagerFeePaid)
+ 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 *DestinationRewardManagerFeePaidIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationRewardManagerFeePaidIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationRewardManagerFeePaid struct {
+ Payments []IDestinationRewardManagerFeePayment
+ Payer common.Address
+ Raw types.Log
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) FilterFeePaid(opts *bind.FilterOpts) (*DestinationRewardManagerFeePaidIterator, error) {
+
+ logs, sub, err := _DestinationRewardManager.contract.FilterLogs(opts, "FeePaid")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerFeePaidIterator{contract: _DestinationRewardManager.contract, event: "FeePaid", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) WatchFeePaid(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerFeePaid) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationRewardManager.contract.WatchLogs(opts, "FeePaid")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationRewardManagerFeePaid)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "FeePaid", 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 (_DestinationRewardManager *DestinationRewardManagerFilterer) ParseFeePaid(log types.Log) (*DestinationRewardManagerFeePaid, error) {
+ event := new(DestinationRewardManagerFeePaid)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "FeePaid", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationRewardManagerOwnershipTransferRequestedIterator struct {
+ Event *DestinationRewardManagerOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationRewardManagerOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationRewardManagerOwnershipTransferRequested)
+ 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(DestinationRewardManagerOwnershipTransferRequested)
+ 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 *DestinationRewardManagerOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationRewardManagerOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationRewardManagerOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationRewardManagerOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationRewardManager.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerOwnershipTransferRequestedIterator{contract: _DestinationRewardManager.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationRewardManager.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationRewardManagerOwnershipTransferRequested)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_DestinationRewardManager *DestinationRewardManagerFilterer) ParseOwnershipTransferRequested(log types.Log) (*DestinationRewardManagerOwnershipTransferRequested, error) {
+ event := new(DestinationRewardManagerOwnershipTransferRequested)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationRewardManagerOwnershipTransferredIterator struct {
+ Event *DestinationRewardManagerOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationRewardManagerOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationRewardManagerOwnershipTransferred)
+ 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(DestinationRewardManagerOwnershipTransferred)
+ 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 *DestinationRewardManagerOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationRewardManagerOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationRewardManagerOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationRewardManagerOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationRewardManager.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerOwnershipTransferredIterator{contract: _DestinationRewardManager.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationRewardManager.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationRewardManagerOwnershipTransferred)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "OwnershipTransferred", 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 (_DestinationRewardManager *DestinationRewardManagerFilterer) ParseOwnershipTransferred(log types.Log) (*DestinationRewardManagerOwnershipTransferred, error) {
+ event := new(DestinationRewardManagerOwnershipTransferred)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationRewardManagerRewardRecipientsUpdatedIterator struct {
+ Event *DestinationRewardManagerRewardRecipientsUpdated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationRewardManagerRewardRecipientsUpdatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationRewardManagerRewardRecipientsUpdated)
+ 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(DestinationRewardManagerRewardRecipientsUpdated)
+ 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 *DestinationRewardManagerRewardRecipientsUpdatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationRewardManagerRewardRecipientsUpdatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationRewardManagerRewardRecipientsUpdated struct {
+ PoolId [32]byte
+ NewRewardRecipients []CommonAddressAndWeight
+ Raw types.Log
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) FilterRewardRecipientsUpdated(opts *bind.FilterOpts, poolId [][32]byte) (*DestinationRewardManagerRewardRecipientsUpdatedIterator, error) {
+
+ var poolIdRule []interface{}
+ for _, poolIdItem := range poolId {
+ poolIdRule = append(poolIdRule, poolIdItem)
+ }
+
+ logs, sub, err := _DestinationRewardManager.contract.FilterLogs(opts, "RewardRecipientsUpdated", poolIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerRewardRecipientsUpdatedIterator{contract: _DestinationRewardManager.contract, event: "RewardRecipientsUpdated", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) WatchRewardRecipientsUpdated(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerRewardRecipientsUpdated, poolId [][32]byte) (event.Subscription, error) {
+
+ var poolIdRule []interface{}
+ for _, poolIdItem := range poolId {
+ poolIdRule = append(poolIdRule, poolIdItem)
+ }
+
+ logs, sub, err := _DestinationRewardManager.contract.WatchLogs(opts, "RewardRecipientsUpdated", poolIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationRewardManagerRewardRecipientsUpdated)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "RewardRecipientsUpdated", 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 (_DestinationRewardManager *DestinationRewardManagerFilterer) ParseRewardRecipientsUpdated(log types.Log) (*DestinationRewardManagerRewardRecipientsUpdated, error) {
+ event := new(DestinationRewardManagerRewardRecipientsUpdated)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "RewardRecipientsUpdated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationRewardManagerRewardsClaimedIterator struct {
+ Event *DestinationRewardManagerRewardsClaimed
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationRewardManagerRewardsClaimedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationRewardManagerRewardsClaimed)
+ 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(DestinationRewardManagerRewardsClaimed)
+ 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 *DestinationRewardManagerRewardsClaimedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationRewardManagerRewardsClaimedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationRewardManagerRewardsClaimed struct {
+ PoolId [32]byte
+ Recipient common.Address
+ Quantity *big.Int
+ Raw types.Log
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) FilterRewardsClaimed(opts *bind.FilterOpts, poolId [][32]byte, recipient []common.Address) (*DestinationRewardManagerRewardsClaimedIterator, error) {
+
+ var poolIdRule []interface{}
+ for _, poolIdItem := range poolId {
+ poolIdRule = append(poolIdRule, poolIdItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _DestinationRewardManager.contract.FilterLogs(opts, "RewardsClaimed", poolIdRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationRewardManagerRewardsClaimedIterator{contract: _DestinationRewardManager.contract, event: "RewardsClaimed", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationRewardManager *DestinationRewardManagerFilterer) WatchRewardsClaimed(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerRewardsClaimed, poolId [][32]byte, recipient []common.Address) (event.Subscription, error) {
+
+ var poolIdRule []interface{}
+ for _, poolIdItem := range poolId {
+ poolIdRule = append(poolIdRule, poolIdItem)
+ }
+ var recipientRule []interface{}
+ for _, recipientItem := range recipient {
+ recipientRule = append(recipientRule, recipientItem)
+ }
+
+ logs, sub, err := _DestinationRewardManager.contract.WatchLogs(opts, "RewardsClaimed", poolIdRule, recipientRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationRewardManagerRewardsClaimed)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "RewardsClaimed", 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 (_DestinationRewardManager *DestinationRewardManagerFilterer) ParseRewardsClaimed(log types.Log) (*DestinationRewardManagerRewardsClaimed, error) {
+ event := new(DestinationRewardManagerRewardsClaimed)
+ if err := _DestinationRewardManager.contract.UnpackLog(event, "RewardsClaimed", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_DestinationRewardManager *DestinationRewardManager) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _DestinationRewardManager.abi.Events["FeeManagerUpdated"].ID:
+ return _DestinationRewardManager.ParseFeeManagerUpdated(log)
+ case _DestinationRewardManager.abi.Events["FeePaid"].ID:
+ return _DestinationRewardManager.ParseFeePaid(log)
+ case _DestinationRewardManager.abi.Events["OwnershipTransferRequested"].ID:
+ return _DestinationRewardManager.ParseOwnershipTransferRequested(log)
+ case _DestinationRewardManager.abi.Events["OwnershipTransferred"].ID:
+ return _DestinationRewardManager.ParseOwnershipTransferred(log)
+ case _DestinationRewardManager.abi.Events["RewardRecipientsUpdated"].ID:
+ return _DestinationRewardManager.ParseRewardRecipientsUpdated(log)
+ case _DestinationRewardManager.abi.Events["RewardsClaimed"].ID:
+ return _DestinationRewardManager.ParseRewardsClaimed(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (DestinationRewardManagerFeeManagerUpdated) Topic() common.Hash {
+ return common.HexToHash("0xe45f5e140399b0a7e12971ab020724b828fbed8ac408c420884dc7d1bbe506b4")
+}
+
+func (DestinationRewardManagerFeePaid) Topic() common.Hash {
+ return common.HexToHash("0xa1cc025ea76bacce5d740ee4bc331899375dc2c5f2ab33933aaacbd9ba001b66")
+}
+
+func (DestinationRewardManagerOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (DestinationRewardManagerOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (DestinationRewardManagerRewardRecipientsUpdated) Topic() common.Hash {
+ return common.HexToHash("0x8f668d6090683f98b3373a8b83d214da45737f7486cb7de554cc07b54e61cfe6")
+}
+
+func (DestinationRewardManagerRewardsClaimed) Topic() common.Hash {
+ return common.HexToHash("0x989969655bc1d593922527fe85d71347bb8e12fa423cc71f362dd8ef7cb10ef2")
+}
+
+func (_DestinationRewardManager *DestinationRewardManager) Address() common.Address {
+ return _DestinationRewardManager.address
+}
+
+type DestinationRewardManagerInterface interface {
+ GetAvailableRewardPoolIds(opts *bind.CallOpts, recipient common.Address, startIndex *big.Int, endIndex *big.Int) ([][32]byte, error)
+
+ ILinkAddress(opts *bind.CallOpts) (common.Address, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SFeeManagerAddressList(opts *bind.CallOpts, arg0 common.Address) (common.Address, error)
+
+ SRegisteredPoolIds(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error)
+
+ SRewardRecipientWeights(opts *bind.CallOpts, arg0 [32]byte, arg1 common.Address) (*big.Int, error)
+
+ SRewardRecipientWeightsSet(opts *bind.CallOpts, arg0 [32]byte) (bool, error)
+
+ STotalRewardRecipientFees(opts *bind.CallOpts, arg0 [32]byte) (*big.Int, error)
+
+ STotalRewardRecipientFeesLastClaimedAmounts(opts *bind.CallOpts, arg0 [32]byte, arg1 common.Address) (*big.Int, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ AddFeeManager(opts *bind.TransactOpts, newFeeManagerAddress common.Address) (*types.Transaction, error)
+
+ ClaimRewards(opts *bind.TransactOpts, poolIds [][32]byte) (*types.Transaction, error)
+
+ OnFeePaid(opts *bind.TransactOpts, payments []IDestinationRewardManagerFeePayment, payer common.Address) (*types.Transaction, error)
+
+ PayRecipients(opts *bind.TransactOpts, poolId [32]byte, recipients []common.Address) (*types.Transaction, error)
+
+ RemoveFeeManager(opts *bind.TransactOpts, feeManagerAddress common.Address) (*types.Transaction, error)
+
+ SetRewardRecipients(opts *bind.TransactOpts, poolId [32]byte, rewardRecipientAndWeights []CommonAddressAndWeight) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ UpdateRewardRecipients(opts *bind.TransactOpts, poolId [32]byte, newRewardRecipients []CommonAddressAndWeight) (*types.Transaction, error)
+
+ FilterFeeManagerUpdated(opts *bind.FilterOpts) (*DestinationRewardManagerFeeManagerUpdatedIterator, error)
+
+ WatchFeeManagerUpdated(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerFeeManagerUpdated) (event.Subscription, error)
+
+ ParseFeeManagerUpdated(log types.Log) (*DestinationRewardManagerFeeManagerUpdated, error)
+
+ FilterFeePaid(opts *bind.FilterOpts) (*DestinationRewardManagerFeePaidIterator, error)
+
+ WatchFeePaid(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerFeePaid) (event.Subscription, error)
+
+ ParseFeePaid(log types.Log) (*DestinationRewardManagerFeePaid, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationRewardManagerOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*DestinationRewardManagerOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationRewardManagerOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*DestinationRewardManagerOwnershipTransferred, error)
+
+ FilterRewardRecipientsUpdated(opts *bind.FilterOpts, poolId [][32]byte) (*DestinationRewardManagerRewardRecipientsUpdatedIterator, error)
+
+ WatchRewardRecipientsUpdated(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerRewardRecipientsUpdated, poolId [][32]byte) (event.Subscription, error)
+
+ ParseRewardRecipientsUpdated(log types.Log) (*DestinationRewardManagerRewardRecipientsUpdated, error)
+
+ FilterRewardsClaimed(opts *bind.FilterOpts, poolId [][32]byte, recipient []common.Address) (*DestinationRewardManagerRewardsClaimedIterator, error)
+
+ WatchRewardsClaimed(opts *bind.WatchOpts, sink chan<- *DestinationRewardManagerRewardsClaimed, poolId [][32]byte, recipient []common.Address) (event.Subscription, error)
+
+ ParseRewardsClaimed(log types.Log) (*DestinationRewardManagerRewardsClaimed, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/llo-feeds/generated/destination_verifier/destination_verifier.go b/core/gethwrappers/llo-feeds/generated/destination_verifier/destination_verifier.go
new file mode 100644
index 00000000000..2fa48b7249c
--- /dev/null
+++ b/core/gethwrappers/llo-feeds/generated/destination_verifier/destination_verifier.go
@@ -0,0 +1,1576 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package destination_verifier
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+type CommonAddressAndWeight struct {
+ Addr common.Address
+ Weight uint64
+}
+
+var DestinationVerifierMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierProxy\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessForbidden\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadActivationTime\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BadVerification\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes24\",\"name\":\"donConfigId\",\"type\":\"bytes24\"}],\"name\":\"DonConfigAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DonConfigDoesNotExist\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxSigners\",\"type\":\"uint256\"}],\"name\":\"ExcessSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FaultToleranceMustBePositive\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeManagerInvalid\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numSigners\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minSigners\",\"type\":\"uint256\"}],\"name\":\"InsufficientSigners\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"rsLength\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"ssLength\",\"type\":\"uint256\"}],\"name\":\"MismatchedSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NonUniqueSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"VerifierProxyInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldAccessController\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAccessController\",\"type\":\"address\"}],\"name\":\"AccessControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes24\",\"name\":\"donConfigId\",\"type\":\"bytes24\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isActive\",\"type\":\"bool\"}],\"name\":\"ConfigActivated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes24\",\"name\":\"donConfigId\",\"type\":\"bytes24\"}],\"name\":\"ConfigRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes24\",\"name\":\"donConfigId\",\"type\":\"bytes24\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"recipientAddressesAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"oldFeeManager\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newFeeManager\",\"type\":\"address\"}],\"name\":\"FeeManagerSet\",\"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\":\"feedId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"}],\"name\":\"ReportVerified\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_verifierProxy\",\"outputs\":[{\"internalType\":\"contractIDestinationVerifierProxy\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"removeLatestConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_accessController\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManager\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"accessController\",\"type\":\"address\"}],\"name\":\"setAccessController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"recipientAddressesAndWeights\",\"type\":\"tuple[]\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"donConfigIndex\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isActive\",\"type\":\"bool\"}],\"name\":\"setConfigActive\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"recipientAddressesAndWeights\",\"type\":\"tuple[]\"},{\"internalType\":\"uint32\",\"name\":\"activationTime\",\"type\":\"uint32\"}],\"name\":\"setConfigWithActivationTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"feeManager\",\"type\":\"address\"}],\"name\":\"setFeeManager\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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\":\"bytes\",\"name\":\"signedReport\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"parameterPayload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"signedReports\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"parameterPayload\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"verifyBulk\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+ Bin: "0x60a06040523480156200001157600080fd5b506040516200379d3803806200379d8339810160408190526200003491620001a6565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000fb565b5050506001600160a01b038116620000e95760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0316608052620001d8565b336001600160a01b03821603620001555760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620001b957600080fd5b81516001600160a01b0381168114620001d157600080fd5b9392505050565b60805161359b62000202600039600081816102d70152818161062a0152611064015261359b6000f3fe6080604052600436106100f35760003560e01c80638da5cb5b1161008a578063d7c72e4e11610059578063d7c72e4e146102f9578063f08391d814610319578063f2fde38b14610339578063f9c7bf771461035957600080fd5b80638da5cb5b1461025857806394ba284614610283578063af4fed24146102b0578063b97455c7146102c557600080fd5b8063453ec61b116100c6578063453ec61b146101e1578063472d35b9146102035780635ad72fae1461022357806379ba50971461024357600080fd5b806301ffc9a7146100f8578063181f5a771461012d578063294d2bb11461017c57806338416b5b1461018f575b600080fd5b34801561010457600080fd5b50610118610113366004612622565b610379565b60405190151581526020015b60405180910390f35b34801561013957600080fd5b5060408051808201909152601981527f44657374696e6174696f6e566572696669657220312e302e300000000000000060208201525b60405161012491906126cf565b61016f61018a366004612754565b610626565b34801561019b57600080fd5b506004546101bc9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610124565b3480156101ed57600080fd5b506102016101fc3660046129e3565b610873565b005b34801561020f57600080fd5b5061020161021e366004612a57565b61097b565b34801561022f57600080fd5b5061020161023e366004612a80565b610c5c565b34801561024f57600080fd5b50610201610d72565b34801561026457600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101bc565b34801561028f57600080fd5b506005546101bc9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102bc57600080fd5b50610201610e6f565b3480156102d157600080fd5b506101bc7f000000000000000000000000000000000000000000000000000000000000000081565b61030c610307366004612ab0565b611060565b6040516101249190612b33565b34801561032557600080fd5b50610201610334366004612a57565b611352565b34801561034557600080fd5b50610201610354366004612a57565b6113d9565b34801561036557600080fd5b50610201610374366004612bc5565b6113ed565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f294d2bb100000000000000000000000000000000000000000000000000000000148061040c57507fffffffff0000000000000000000000000000000000000000000000000000000082167fd7c72e4e00000000000000000000000000000000000000000000000000000000145b8061045857507fffffffff0000000000000000000000000000000000000000000000000000000082167f94ba284600000000000000000000000000000000000000000000000000000000145b806104a457507fffffffff0000000000000000000000000000000000000000000000000000000082167f38416b5b00000000000000000000000000000000000000000000000000000000145b806104f057507fffffffff0000000000000000000000000000000000000000000000000000000082167f453ec61b00000000000000000000000000000000000000000000000000000000145b8061053c57507fffffffff0000000000000000000000000000000000000000000000000000000082167ff9c7bf7700000000000000000000000000000000000000000000000000000000145b8061058857507fffffffff0000000000000000000000000000000000000000000000000000000082167f472d35b900000000000000000000000000000000000000000000000000000000145b806105d457507fffffffff0000000000000000000000000000000000000000000000000000000082167ff08391d800000000000000000000000000000000000000000000000000000000145b8061062057507fffffffff0000000000000000000000000000000000000000000000000000000082167f5ad72fae00000000000000000000000000000000000000000000000000000000145b92915050565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610697576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554829073ffffffffffffffffffffffffffffffffffffffff16801580159061075657506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf8906107139085906000903690600401612c95565b602060405180830381865afa158015610730573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107549190612cce565b155b1561078d576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008061079b8a8a886114ab565b600454919350915073ffffffffffffffffffffffffffffffffffffffff168015610864578073ffffffffffffffffffffffffffffffffffffffff166386968cfd34848e8e8e8e8e6040518863ffffffff1660e01b815260040161080396959493929190612ceb565b6000604051808303818588803b15801561081c57600080fd5b505af19350505050801561082e575060015b610864576040517f4df18f0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50909998505050505050505050565b82518260ff16806000036108b3576040517f0743bae600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f8211156108fd576040517f61750f4000000000000000000000000000000000000000000000000000000000815260048101839052601f60248201526044015b60405180910390fd5b610908816003612d71565b8211610960578161091a826003612d71565b610925906001612d88565b6040517f9dd9e6d8000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044016108f4565b6109686119b0565b61097485858542611a33565b5050505050565b6109836119b0565b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f86968cfd00000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610a0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a319190612cce565b1580610ae857506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f3690750900000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610ac2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae69190612cce565b155b80610b9e57506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527ff65df96200000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9c9190612cce565b155b15610bd5576040517f8238941900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f04628abcaa6b1674651352125cb94b65b289145bc2bc4d67720bb7d966372f0391015b60405180910390a15050565b610c646119b0565b6003548210610c9f576040517f5a0d6fe200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060038381548110610cb457610cb4612d9b565b600091825260209182902001805484151579010000000000000000000000000000000000000000000000000081027fffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffff909216919091178083556040805191811b7fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000168252938101919091529092507f90186a1e77b498ec417ea88bd026cae00d7043c357cc45221777623bda582dd4910160405180910390a1505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610df3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108f4565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610e776119b0565b600354600003610eb3576040517f5a0d6fe200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003805460009190610ec790600190612dca565b81548110610ed757610ed7612d9b565b600091825260209182902060408051608081018252929091015480821b7fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001683527801000000000000000000000000000000000000000000000000810460ff9081169484019490945279010000000000000000000000000000000000000000000000000081049093161515908201527a01000000000000000000000000000000000000000000000000000090910463ffffffff166060820152600380549192509080610fa557610fa5612ddd565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffff00000000000000000000000000000000000000000000000000000000000016905501905580516040517f970fd8f3ebdd9a271080aacf9807a5c709be0b448e4047a6fc212b8cc165368d91611055917fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000091909116815260200190565b60405180910390a150565b60607f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1633146110d1576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554829073ffffffffffffffffffffffffffffffffffffffff16801580159061119057506040517f6b14daf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061114d9085906000903690600401612c95565b602060405180830381865afa15801561116a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118e9190612cce565b155b156111c7576040517fef67f5d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008767ffffffffffffffff8111156111e2576111e26127d5565b60405190808252806020026020018201604052801561121557816020015b60608152602001906001900390816112005790505b50905060008867ffffffffffffffff811115611233576112336127d5565b60405190808252806020026020018201604052801561125c578160200160208202803683370190505b50905060005b898110156112ee5760008061129a8d8d8581811061128257611282612d9b565b90506020028101906112949190612e0c565b8b6114ab565b91509150818584815181106112b1576112b1612d9b565b6020026020010181905250808484815181106112cf576112cf612d9b565b6020026020010181815250505050806112e790612e71565b9050611262565b5060045473ffffffffffffffffffffffffffffffffffffffff168015610864578073ffffffffffffffffffffffffffffffffffffffff16633690750934848e8e8e8e8e6040518863ffffffff1660e01b815260040161080396959493929190612ea9565b61135a6119b0565b6005805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f953e92b1a6442e9c3242531154a3f6f6eb00b4e9c719ba8118fa6235e4ce89b69101610c50565b6113e16119b0565b6113ea816120eb565b50565b83518360ff168060000361142d576040517f0743bae600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f821115611472576040517f61750f4000000000000000000000000000000000000000000000000000000000815260048101839052601f60248201526044016108f4565b61147d816003612d71565b821161148f578161091a826003612d71565b6114976119b0565b6114a386868686611a33565b505050505050565b6060600080808080806114c0898b018b6130db565b94509450945094509450815183511461151257825182516040517ff0d31408000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044016108f4565b825160000361154d576040517fc7af40f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008480519060200120866040516020016115699291906131b6565b6040516020818303038152906040528051906020012090506000845167ffffffffffffffff81111561159d5761159d6127d5565b6040519080825280602002602001820160405280156115c6578160200160208202803683370190505b50905060005b85518110156116d4576001838583602081106115ea576115ea612d9b565b6115f791901a601b6131f2565b88848151811061160957611609612d9b565b602002602001015188858151811061162357611623612d9b565b602002602001015160405160008152602001604052604051611661949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611683573d6000803e3d6000fd5b5050506020604051035182828151811061169f5761169f612d9b565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526116cd81612e71565b90506115cc565b506116de816121e0565b15611715576040517f4df18f0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006117208761228f565b9050600061172d826122b5565b80519091507fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001661178a576040517f4df18f0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80604001516117c5576040517f4df18f0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806020015160ff16835111611806576040517f4df18f0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b84518110156119245784818151811061182557611825612d9b565b6020026020010151836000015160405160200161189592919060609290921b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001682527fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166014820152602c0190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301206000818152600290935291205490925060ff16611914576040517f4df18f0700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61191d81612e71565b905061180a565b5061192e8961320b565b60405173ffffffffffffffffffffffffffffffffffffffff8f1681527f58ca9502e98a536e06e72d680fcc251e5d10b72291a281665a2c2dc0ac30fcc59060200160405180910390a25051969d7fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009097169c50959a5050505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611a31576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108f4565b565b83518360ff1680600003611a73576040517f0743bae600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601f821115611ab8576040517f61750f4000000000000000000000000000000000000000000000000000000000815260048101839052601f60248201526044016108f4565b611ac3816003612d71565b8211611ad5578161091a826003612d71565b611add6119b0565b611ae6866121e0565b15611b1d576040517ff67bc7c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b428363ffffffff161115611b5d576040517f0114c7e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b7686600060018951611b719190612dca565b61243a565b60008686604051602001611b8b929190613250565b60405160208183030381529060405280519060200120905060005b8751811015611d3257600073ffffffffffffffffffffffffffffffffffffffff16888281518110611bd957611bd9612d9b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611c2e576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600260008a8481518110611c4657611c46612d9b565b602002602001015185604051602001611cb292919060609290921b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001682527fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166014820152602c0190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301208352908201929092520160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055611d2b81612e71565b9050611ba6565b506003548015801590611d96575063ffffffff85166003611d54600184612dca565b81548110611d6457611d64612d9b565b6000918252602090912001547a010000000000000000000000000000000000000000000000000000900463ffffffff16115b15611dcd576040517f0114c7e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081118015611e4b57507fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000082166003611e08600184612dca565b81548110611e1857611e18612d9b565b60009182526020909120015460401b7fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016145b15611ea6576040517fc0178c860000000000000000000000000000000000000000000000000000000081527fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000831660048201526024016108f4565b855115611f3757600480546040517ff65df96200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169163f65df96291611f049186918b910161332e565b600060405180830381600087803b158015611f1e57600080fd5b505af1158015611f32573d6000803e3d6000fd5b505050505b604080516080810182527fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000841680825260ff808b1660208401908152600184860181815263ffffffff808d166060880190815260038054948501815560005296517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90930180549451925197519091167a010000000000000000000000000000000000000000000000000000027fffff00000000ffffffffffffffffffffffffffffffffffffffffffffffffffff97151579010000000000000000000000000000000000000000000000000002979097167fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff929095167801000000000000000000000000000000000000000000000000027fffffffffffffff0000000000000000000000000000000000000000000000000090941692881c929092179290921791909116919091179290921790915590517f2d763a674a99583454a287d792819ffb9ff7e791c23e7745a082701136ce336c906120d9908b908b908b90613371565b60405180910390a25050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361216a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108f4565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000805b82518110156122865760006121fa826001612d88565b90505b835181101561227d5783818151811061221857612218612d9b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1684838151811061224857612248612d9b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603612275575060019392505050565b6001016121fd565b506001016121e4565b50600092915050565b600080828060200190518101906122a691906133dd565b63ffffffff1695945050505050565b6040805160808101825260008082526020820181905291810182905260608101919091526040805160808101825260008082526020820181905291810182905260608101919091526003545b80156124335761231081613420565b9050836003828154811061232657612326612d9b565b6000918252602090912001547a010000000000000000000000000000000000000000000000000000900463ffffffff161161242e576003818154811061236e5761236e612d9b565b600091825260209182902060408051608081018252929091015480821b7fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001683527801000000000000000000000000000000000000000000000000810460ff9081169484019490945279010000000000000000000000000000000000000000000000000081049093161515908201527a01000000000000000000000000000000000000000000000000000090910463ffffffff1660608201529150612433565b612301565b5092915050565b818180820361244a575050505050565b60008560026124598787613455565b6124639190613475565b61246d9087613504565b8151811061247d5761247d612d9b565b602002602001015190505b8183136125fc575b8073ffffffffffffffffffffffffffffffffffffffff168684815181106124b9576124b9612d9b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1610156124ef57826124e78161352c565b935050612490565b85828151811061250157612501612d9b565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16101561254e57816125468161355d565b9250506124ef565b8183136125f75785828151811061256757612567612d9b565b602002602001015186848151811061258157612581612d9b565b602002602001015187858151811061259b5761259b612d9b565b602002602001018885815181106125b4576125b4612d9b565b73ffffffffffffffffffffffffffffffffffffffff938416602091820292909201015291169052826125e58161352c565b93505081806125f39061355d565b9250505b612488565b8185121561260f5761260f86868461243a565b838312156114a3576114a386848661243a565b60006020828403121561263457600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461266457600080fd5b9392505050565b6000815180845260005b8181101561269157602081850181015186830182015201612675565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000612664602083018461266b565b60008083601f8401126126f457600080fd5b50813567ffffffffffffffff81111561270c57600080fd5b60208301915083602082850101111561272457600080fd5b9250929050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461274f57600080fd5b919050565b60008060008060006060868803121561276c57600080fd5b853567ffffffffffffffff8082111561278457600080fd5b61279089838a016126e2565b909750955060208801359150808211156127a957600080fd5b506127b6888289016126e2565b90945092506127c990506040870161272b565b90509295509295909350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715612827576128276127d5565b60405290565b6040516060810167ffffffffffffffff81118282101715612827576128276127d5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715612897576128976127d5565b604052919050565b600067ffffffffffffffff8211156128b9576128b96127d5565b5060051b60200190565b600082601f8301126128d457600080fd5b813560206128e96128e48361289f565b612850565b82815260059290921b8401810191818101908684111561290857600080fd5b8286015b8481101561292a5761291d8161272b565b835291830191830161290c565b509695505050505050565b803560ff8116811461274f57600080fd5b600082601f83011261295757600080fd5b813560206129676128e48361289f565b82815260069290921b8401810191818101908684111561298657600080fd5b8286015b8481101561292a57604081890312156129a35760008081fd5b6129ab612804565b6129b48261272b565b81528482013567ffffffffffffffff811681146129d15760008081fd5b8186015283529183019160400161298a565b6000806000606084860312156129f857600080fd5b833567ffffffffffffffff80821115612a1057600080fd5b612a1c878388016128c3565b9450612a2a60208701612935565b93506040860135915080821115612a4057600080fd5b50612a4d86828701612946565b9150509250925092565b600060208284031215612a6957600080fd5b6126648261272b565b80151581146113ea57600080fd5b60008060408385031215612a9357600080fd5b823591506020830135612aa581612a72565b809150509250929050565b600080600080600060608688031215612ac857600080fd5b853567ffffffffffffffff80821115612ae057600080fd5b818801915088601f830112612af457600080fd5b813581811115612b0357600080fd5b8960208260051b8501011115612b1857600080fd5b6020928301975095509087013590808211156127a957600080fd5b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015612ba6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452612b9485835161266b565b94509285019290850190600101612b5a565b5092979650505050505050565b63ffffffff811681146113ea57600080fd5b60008060008060808587031215612bdb57600080fd5b843567ffffffffffffffff80821115612bf357600080fd5b612bff888389016128c3565b9550612c0d60208801612935565b94506040870135915080821115612c2357600080fd5b50612c3087828801612946565b9250506060850135612c4181612bb3565b939692955090935050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000612cc5604083018486612c4c565b95945050505050565b600060208284031215612ce057600080fd5b815161266481612a72565b868152608060208201526000612d05608083018789612c4c565b8281036040840152612d18818688612c4c565b91505073ffffffffffffffffffffffffffffffffffffffff83166060830152979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761062057610620612d42565b8082018082111561062057610620612d42565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8181038181111561062057610620612d42565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612e4157600080fd5b83018035915067ffffffffffffffff821115612e5c57600080fd5b60200191503681900382131561272457600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612ea257612ea2612d42565b5060010190565b6080808252875190820181905260009060209060a0840190828b01845b82811015612ee257815184529284019290840190600101612ec6565b50505083810382850152878152818101600589901b820183018a60005b8b811015612faa577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085840301845281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18e3603018112612f6057600080fd5b8d01868101903567ffffffffffffffff811115612f7c57600080fd5b803603821315612f8b57600080fd5b612f96858284612c4c565b958801959450505090850190600101612eff565b50508581036040870152612fbf81898b612c4c565b945050505050612fe7606083018473ffffffffffffffffffffffffffffffffffffffff169052565b979650505050505050565b600082601f83011261300357600080fd5b813567ffffffffffffffff81111561301d5761301d6127d5565b61304e60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612850565b81815284602083860101111561306357600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261309157600080fd5b813560206130a16128e48361289f565b82815260059290921b840181019181810190868411156130c057600080fd5b8286015b8481101561292a57803583529183019183016130c4565b600080600080600060e086880312156130f357600080fd5b86601f87011261310257600080fd5b61310a61282d565b80606088018981111561311c57600080fd5b885b8181101561313657803584526020938401930161311e565b5090965035905067ffffffffffffffff8082111561315357600080fd5b61315f89838a01612ff2565b9550608088013591508082111561317557600080fd5b61318189838a01613080565b945060a088013591508082111561319757600080fd5b506131a488828901613080565b9598949750929560c001359392505050565b828152600060208083018460005b60038110156131e1578151835291830191908301906001016131c4565b505050506080820190509392505050565b60ff818116838216019081111561062057610620612d42565b8051602080830151919081101561324a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b825160009082906020808701845b8381101561329057815173ffffffffffffffffffffffffffffffffffffffff168552938201939082019060010161325e565b5050505060f89390931b7fff000000000000000000000000000000000000000000000000000000000000001683525050600101919050565b600081518084526020808501945080840160005b83811015613323578151805173ffffffffffffffffffffffffffffffffffffffff16885283015167ffffffffffffffff1683880152604090960195908201906001016132dc565b509495945050505050565b7fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008316815260406020820152600061336960408301846132c8565b949350505050565b606080825284519082018190526000906020906080840190828801845b828110156133c057815173ffffffffffffffffffffffffffffffffffffffff168452928401929084019060010161338e565b50505060ff8616828501528381036040850152612fe781866132c8565b6000806000606084860312156133f257600080fd5b83519250602084015161340481612bb3565b604085015190925061341581612bb3565b809150509250925092565b60008161342f5761342f612d42565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b818103600083128015838313168383128216171561243357612433612d42565b6000826134ab577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f8000000000000000000000000000000000000000000000000000000000000000831416156134ff576134ff612d42565b500590565b808201828112600083128015821682158216171561352457613524612d42565b505092915050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612ea257612ea2612d42565b60007f8000000000000000000000000000000000000000000000000000000000000000820361342f5761342f612d4256fea164736f6c6343000813000a",
+}
+
+var DestinationVerifierABI = DestinationVerifierMetaData.ABI
+
+var DestinationVerifierBin = DestinationVerifierMetaData.Bin
+
+func DeployDestinationVerifier(auth *bind.TransactOpts, backend bind.ContractBackend, verifierProxy common.Address) (common.Address, *types.Transaction, *DestinationVerifier, error) {
+ parsed, err := DestinationVerifierMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DestinationVerifierBin), backend, verifierProxy)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &DestinationVerifier{address: address, abi: *parsed, DestinationVerifierCaller: DestinationVerifierCaller{contract: contract}, DestinationVerifierTransactor: DestinationVerifierTransactor{contract: contract}, DestinationVerifierFilterer: DestinationVerifierFilterer{contract: contract}}, nil
+}
+
+type DestinationVerifier struct {
+ address common.Address
+ abi abi.ABI
+ DestinationVerifierCaller
+ DestinationVerifierTransactor
+ DestinationVerifierFilterer
+}
+
+type DestinationVerifierCaller struct {
+ contract *bind.BoundContract
+}
+
+type DestinationVerifierTransactor struct {
+ contract *bind.BoundContract
+}
+
+type DestinationVerifierFilterer struct {
+ contract *bind.BoundContract
+}
+
+type DestinationVerifierSession struct {
+ Contract *DestinationVerifier
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type DestinationVerifierCallerSession struct {
+ Contract *DestinationVerifierCaller
+ CallOpts bind.CallOpts
+}
+
+type DestinationVerifierTransactorSession struct {
+ Contract *DestinationVerifierTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type DestinationVerifierRaw struct {
+ Contract *DestinationVerifier
+}
+
+type DestinationVerifierCallerRaw struct {
+ Contract *DestinationVerifierCaller
+}
+
+type DestinationVerifierTransactorRaw struct {
+ Contract *DestinationVerifierTransactor
+}
+
+func NewDestinationVerifier(address common.Address, backend bind.ContractBackend) (*DestinationVerifier, error) {
+ abi, err := abi.JSON(strings.NewReader(DestinationVerifierABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindDestinationVerifier(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifier{address: address, abi: abi, DestinationVerifierCaller: DestinationVerifierCaller{contract: contract}, DestinationVerifierTransactor: DestinationVerifierTransactor{contract: contract}, DestinationVerifierFilterer: DestinationVerifierFilterer{contract: contract}}, nil
+}
+
+func NewDestinationVerifierCaller(address common.Address, caller bind.ContractCaller) (*DestinationVerifierCaller, error) {
+ contract, err := bindDestinationVerifier(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierCaller{contract: contract}, nil
+}
+
+func NewDestinationVerifierTransactor(address common.Address, transactor bind.ContractTransactor) (*DestinationVerifierTransactor, error) {
+ contract, err := bindDestinationVerifier(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierTransactor{contract: contract}, nil
+}
+
+func NewDestinationVerifierFilterer(address common.Address, filterer bind.ContractFilterer) (*DestinationVerifierFilterer, error) {
+ contract, err := bindDestinationVerifier(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierFilterer{contract: contract}, nil
+}
+
+func bindDestinationVerifier(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := DestinationVerifierMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_DestinationVerifier *DestinationVerifierRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _DestinationVerifier.Contract.DestinationVerifierCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_DestinationVerifier *DestinationVerifierRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.DestinationVerifierTransactor.contract.Transfer(opts)
+}
+
+func (_DestinationVerifier *DestinationVerifierRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.DestinationVerifierTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_DestinationVerifier *DestinationVerifierCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _DestinationVerifier.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.contract.Transfer(opts)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_DestinationVerifier *DestinationVerifierCaller) IVerifierProxy(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationVerifier.contract.Call(opts, &out, "i_verifierProxy")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) IVerifierProxy() (common.Address, error) {
+ return _DestinationVerifier.Contract.IVerifierProxy(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCallerSession) IVerifierProxy() (common.Address, error) {
+ return _DestinationVerifier.Contract.IVerifierProxy(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationVerifier.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) Owner() (common.Address, error) {
+ return _DestinationVerifier.Contract.Owner(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCallerSession) Owner() (common.Address, error) {
+ return _DestinationVerifier.Contract.Owner(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCaller) SAccessController(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationVerifier.contract.Call(opts, &out, "s_accessController")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) SAccessController() (common.Address, error) {
+ return _DestinationVerifier.Contract.SAccessController(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCallerSession) SAccessController() (common.Address, error) {
+ return _DestinationVerifier.Contract.SAccessController(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCaller) SFeeManager(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationVerifier.contract.Call(opts, &out, "s_feeManager")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) SFeeManager() (common.Address, error) {
+ return _DestinationVerifier.Contract.SFeeManager(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCallerSession) SFeeManager() (common.Address, error) {
+ return _DestinationVerifier.Contract.SFeeManager(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _DestinationVerifier.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _DestinationVerifier.Contract.SupportsInterface(&_DestinationVerifier.CallOpts, interfaceId)
+}
+
+func (_DestinationVerifier *DestinationVerifierCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _DestinationVerifier.Contract.SupportsInterface(&_DestinationVerifier.CallOpts, interfaceId)
+}
+
+func (_DestinationVerifier *DestinationVerifierCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _DestinationVerifier.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) TypeAndVersion() (string, error) {
+ return _DestinationVerifier.Contract.TypeAndVersion(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierCallerSession) TypeAndVersion() (string, error) {
+ return _DestinationVerifier.Contract.TypeAndVersion(&_DestinationVerifier.CallOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) AcceptOwnership() (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.AcceptOwnership(&_DestinationVerifier.TransactOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.AcceptOwnership(&_DestinationVerifier.TransactOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) RemoveLatestConfig(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "removeLatestConfig")
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) RemoveLatestConfig() (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.RemoveLatestConfig(&_DestinationVerifier.TransactOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) RemoveLatestConfig() (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.RemoveLatestConfig(&_DestinationVerifier.TransactOpts)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) SetAccessController(opts *bind.TransactOpts, accessController common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "setAccessController", accessController)
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) SetAccessController(accessController common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetAccessController(&_DestinationVerifier.TransactOpts, accessController)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) SetAccessController(accessController common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetAccessController(&_DestinationVerifier.TransactOpts, accessController)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) SetConfig(opts *bind.TransactOpts, signers []common.Address, f uint8, recipientAddressesAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "setConfig", signers, f, recipientAddressesAndWeights)
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) SetConfig(signers []common.Address, f uint8, recipientAddressesAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetConfig(&_DestinationVerifier.TransactOpts, signers, f, recipientAddressesAndWeights)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) SetConfig(signers []common.Address, f uint8, recipientAddressesAndWeights []CommonAddressAndWeight) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetConfig(&_DestinationVerifier.TransactOpts, signers, f, recipientAddressesAndWeights)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) SetConfigActive(opts *bind.TransactOpts, donConfigIndex *big.Int, isActive bool) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "setConfigActive", donConfigIndex, isActive)
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) SetConfigActive(donConfigIndex *big.Int, isActive bool) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetConfigActive(&_DestinationVerifier.TransactOpts, donConfigIndex, isActive)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) SetConfigActive(donConfigIndex *big.Int, isActive bool) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetConfigActive(&_DestinationVerifier.TransactOpts, donConfigIndex, isActive)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) SetConfigWithActivationTime(opts *bind.TransactOpts, signers []common.Address, f uint8, recipientAddressesAndWeights []CommonAddressAndWeight, activationTime uint32) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "setConfigWithActivationTime", signers, f, recipientAddressesAndWeights, activationTime)
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) SetConfigWithActivationTime(signers []common.Address, f uint8, recipientAddressesAndWeights []CommonAddressAndWeight, activationTime uint32) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetConfigWithActivationTime(&_DestinationVerifier.TransactOpts, signers, f, recipientAddressesAndWeights, activationTime)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) SetConfigWithActivationTime(signers []common.Address, f uint8, recipientAddressesAndWeights []CommonAddressAndWeight, activationTime uint32) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetConfigWithActivationTime(&_DestinationVerifier.TransactOpts, signers, f, recipientAddressesAndWeights, activationTime)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) SetFeeManager(opts *bind.TransactOpts, feeManager common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "setFeeManager", feeManager)
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) SetFeeManager(feeManager common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetFeeManager(&_DestinationVerifier.TransactOpts, feeManager)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) SetFeeManager(feeManager common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.SetFeeManager(&_DestinationVerifier.TransactOpts, feeManager)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.TransferOwnership(&_DestinationVerifier.TransactOpts, to)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.TransferOwnership(&_DestinationVerifier.TransactOpts, to)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) Verify(opts *bind.TransactOpts, signedReport []byte, parameterPayload []byte, sender common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "verify", signedReport, parameterPayload, sender)
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) Verify(signedReport []byte, parameterPayload []byte, sender common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.Verify(&_DestinationVerifier.TransactOpts, signedReport, parameterPayload, sender)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) Verify(signedReport []byte, parameterPayload []byte, sender common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.Verify(&_DestinationVerifier.TransactOpts, signedReport, parameterPayload, sender)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactor) VerifyBulk(opts *bind.TransactOpts, signedReports [][]byte, parameterPayload []byte, sender common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.contract.Transact(opts, "verifyBulk", signedReports, parameterPayload, sender)
+}
+
+func (_DestinationVerifier *DestinationVerifierSession) VerifyBulk(signedReports [][]byte, parameterPayload []byte, sender common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.VerifyBulk(&_DestinationVerifier.TransactOpts, signedReports, parameterPayload, sender)
+}
+
+func (_DestinationVerifier *DestinationVerifierTransactorSession) VerifyBulk(signedReports [][]byte, parameterPayload []byte, sender common.Address) (*types.Transaction, error) {
+ return _DestinationVerifier.Contract.VerifyBulk(&_DestinationVerifier.TransactOpts, signedReports, parameterPayload, sender)
+}
+
+type DestinationVerifierAccessControllerSetIterator struct {
+ Event *DestinationVerifierAccessControllerSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierAccessControllerSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierAccessControllerSet)
+ 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(DestinationVerifierAccessControllerSet)
+ 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 *DestinationVerifierAccessControllerSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierAccessControllerSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierAccessControllerSet struct {
+ OldAccessController common.Address
+ NewAccessController common.Address
+ Raw types.Log
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) FilterAccessControllerSet(opts *bind.FilterOpts) (*DestinationVerifierAccessControllerSetIterator, error) {
+
+ logs, sub, err := _DestinationVerifier.contract.FilterLogs(opts, "AccessControllerSet")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierAccessControllerSetIterator{contract: _DestinationVerifier.contract, event: "AccessControllerSet", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) WatchAccessControllerSet(opts *bind.WatchOpts, sink chan<- *DestinationVerifierAccessControllerSet) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationVerifier.contract.WatchLogs(opts, "AccessControllerSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierAccessControllerSet)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "AccessControllerSet", 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 (_DestinationVerifier *DestinationVerifierFilterer) ParseAccessControllerSet(log types.Log) (*DestinationVerifierAccessControllerSet, error) {
+ event := new(DestinationVerifierAccessControllerSet)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "AccessControllerSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationVerifierConfigActivatedIterator struct {
+ Event *DestinationVerifierConfigActivated
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierConfigActivatedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierConfigActivated)
+ 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(DestinationVerifierConfigActivated)
+ 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 *DestinationVerifierConfigActivatedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierConfigActivatedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierConfigActivated struct {
+ DonConfigId [24]byte
+ IsActive bool
+ Raw types.Log
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) FilterConfigActivated(opts *bind.FilterOpts) (*DestinationVerifierConfigActivatedIterator, error) {
+
+ logs, sub, err := _DestinationVerifier.contract.FilterLogs(opts, "ConfigActivated")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierConfigActivatedIterator{contract: _DestinationVerifier.contract, event: "ConfigActivated", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) WatchConfigActivated(opts *bind.WatchOpts, sink chan<- *DestinationVerifierConfigActivated) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationVerifier.contract.WatchLogs(opts, "ConfigActivated")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierConfigActivated)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "ConfigActivated", 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 (_DestinationVerifier *DestinationVerifierFilterer) ParseConfigActivated(log types.Log) (*DestinationVerifierConfigActivated, error) {
+ event := new(DestinationVerifierConfigActivated)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "ConfigActivated", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationVerifierConfigRemovedIterator struct {
+ Event *DestinationVerifierConfigRemoved
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierConfigRemovedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierConfigRemoved)
+ 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(DestinationVerifierConfigRemoved)
+ 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 *DestinationVerifierConfigRemovedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierConfigRemovedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierConfigRemoved struct {
+ DonConfigId [24]byte
+ Raw types.Log
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) FilterConfigRemoved(opts *bind.FilterOpts) (*DestinationVerifierConfigRemovedIterator, error) {
+
+ logs, sub, err := _DestinationVerifier.contract.FilterLogs(opts, "ConfigRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierConfigRemovedIterator{contract: _DestinationVerifier.contract, event: "ConfigRemoved", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) WatchConfigRemoved(opts *bind.WatchOpts, sink chan<- *DestinationVerifierConfigRemoved) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationVerifier.contract.WatchLogs(opts, "ConfigRemoved")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierConfigRemoved)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "ConfigRemoved", 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 (_DestinationVerifier *DestinationVerifierFilterer) ParseConfigRemoved(log types.Log) (*DestinationVerifierConfigRemoved, error) {
+ event := new(DestinationVerifierConfigRemoved)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "ConfigRemoved", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationVerifierConfigSetIterator struct {
+ Event *DestinationVerifierConfigSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierConfigSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierConfigSet)
+ 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(DestinationVerifierConfigSet)
+ 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 *DestinationVerifierConfigSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierConfigSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierConfigSet struct {
+ DonConfigId [24]byte
+ Signers []common.Address
+ F uint8
+ RecipientAddressesAndWeights []CommonAddressAndWeight
+ Raw types.Log
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) FilterConfigSet(opts *bind.FilterOpts, donConfigId [][24]byte) (*DestinationVerifierConfigSetIterator, error) {
+
+ var donConfigIdRule []interface{}
+ for _, donConfigIdItem := range donConfigId {
+ donConfigIdRule = append(donConfigIdRule, donConfigIdItem)
+ }
+
+ logs, sub, err := _DestinationVerifier.contract.FilterLogs(opts, "ConfigSet", donConfigIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierConfigSetIterator{contract: _DestinationVerifier.contract, event: "ConfigSet", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *DestinationVerifierConfigSet, donConfigId [][24]byte) (event.Subscription, error) {
+
+ var donConfigIdRule []interface{}
+ for _, donConfigIdItem := range donConfigId {
+ donConfigIdRule = append(donConfigIdRule, donConfigIdItem)
+ }
+
+ logs, sub, err := _DestinationVerifier.contract.WatchLogs(opts, "ConfigSet", donConfigIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierConfigSet)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "ConfigSet", 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 (_DestinationVerifier *DestinationVerifierFilterer) ParseConfigSet(log types.Log) (*DestinationVerifierConfigSet, error) {
+ event := new(DestinationVerifierConfigSet)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "ConfigSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationVerifierFeeManagerSetIterator struct {
+ Event *DestinationVerifierFeeManagerSet
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierFeeManagerSetIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierFeeManagerSet)
+ 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(DestinationVerifierFeeManagerSet)
+ 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 *DestinationVerifierFeeManagerSetIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierFeeManagerSetIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierFeeManagerSet struct {
+ OldFeeManager common.Address
+ NewFeeManager common.Address
+ Raw types.Log
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) FilterFeeManagerSet(opts *bind.FilterOpts) (*DestinationVerifierFeeManagerSetIterator, error) {
+
+ logs, sub, err := _DestinationVerifier.contract.FilterLogs(opts, "FeeManagerSet")
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierFeeManagerSetIterator{contract: _DestinationVerifier.contract, event: "FeeManagerSet", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) WatchFeeManagerSet(opts *bind.WatchOpts, sink chan<- *DestinationVerifierFeeManagerSet) (event.Subscription, error) {
+
+ logs, sub, err := _DestinationVerifier.contract.WatchLogs(opts, "FeeManagerSet")
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierFeeManagerSet)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "FeeManagerSet", 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 (_DestinationVerifier *DestinationVerifierFilterer) ParseFeeManagerSet(log types.Log) (*DestinationVerifierFeeManagerSet, error) {
+ event := new(DestinationVerifierFeeManagerSet)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "FeeManagerSet", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationVerifierOwnershipTransferRequestedIterator struct {
+ Event *DestinationVerifierOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierOwnershipTransferRequested)
+ 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(DestinationVerifierOwnershipTransferRequested)
+ 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 *DestinationVerifierOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationVerifierOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationVerifier.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierOwnershipTransferRequestedIterator{contract: _DestinationVerifier.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DestinationVerifierOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationVerifier.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierOwnershipTransferRequested)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_DestinationVerifier *DestinationVerifierFilterer) ParseOwnershipTransferRequested(log types.Log) (*DestinationVerifierOwnershipTransferRequested, error) {
+ event := new(DestinationVerifierOwnershipTransferRequested)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationVerifierOwnershipTransferredIterator struct {
+ Event *DestinationVerifierOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierOwnershipTransferred)
+ 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(DestinationVerifierOwnershipTransferred)
+ 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 *DestinationVerifierOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationVerifierOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationVerifier.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierOwnershipTransferredIterator{contract: _DestinationVerifier.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DestinationVerifierOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationVerifier.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierOwnershipTransferred)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "OwnershipTransferred", 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 (_DestinationVerifier *DestinationVerifierFilterer) ParseOwnershipTransferred(log types.Log) (*DestinationVerifierOwnershipTransferred, error) {
+ event := new(DestinationVerifierOwnershipTransferred)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationVerifierReportVerifiedIterator struct {
+ Event *DestinationVerifierReportVerified
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierReportVerifiedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierReportVerified)
+ 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(DestinationVerifierReportVerified)
+ 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 *DestinationVerifierReportVerifiedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierReportVerifiedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierReportVerified struct {
+ FeedId [32]byte
+ Requester common.Address
+ Raw types.Log
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) FilterReportVerified(opts *bind.FilterOpts, feedId [][32]byte) (*DestinationVerifierReportVerifiedIterator, error) {
+
+ var feedIdRule []interface{}
+ for _, feedIdItem := range feedId {
+ feedIdRule = append(feedIdRule, feedIdItem)
+ }
+
+ logs, sub, err := _DestinationVerifier.contract.FilterLogs(opts, "ReportVerified", feedIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierReportVerifiedIterator{contract: _DestinationVerifier.contract, event: "ReportVerified", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifier *DestinationVerifierFilterer) WatchReportVerified(opts *bind.WatchOpts, sink chan<- *DestinationVerifierReportVerified, feedId [][32]byte) (event.Subscription, error) {
+
+ var feedIdRule []interface{}
+ for _, feedIdItem := range feedId {
+ feedIdRule = append(feedIdRule, feedIdItem)
+ }
+
+ logs, sub, err := _DestinationVerifier.contract.WatchLogs(opts, "ReportVerified", feedIdRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierReportVerified)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "ReportVerified", 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 (_DestinationVerifier *DestinationVerifierFilterer) ParseReportVerified(log types.Log) (*DestinationVerifierReportVerified, error) {
+ event := new(DestinationVerifierReportVerified)
+ if err := _DestinationVerifier.contract.UnpackLog(event, "ReportVerified", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_DestinationVerifier *DestinationVerifier) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _DestinationVerifier.abi.Events["AccessControllerSet"].ID:
+ return _DestinationVerifier.ParseAccessControllerSet(log)
+ case _DestinationVerifier.abi.Events["ConfigActivated"].ID:
+ return _DestinationVerifier.ParseConfigActivated(log)
+ case _DestinationVerifier.abi.Events["ConfigRemoved"].ID:
+ return _DestinationVerifier.ParseConfigRemoved(log)
+ case _DestinationVerifier.abi.Events["ConfigSet"].ID:
+ return _DestinationVerifier.ParseConfigSet(log)
+ case _DestinationVerifier.abi.Events["FeeManagerSet"].ID:
+ return _DestinationVerifier.ParseFeeManagerSet(log)
+ case _DestinationVerifier.abi.Events["OwnershipTransferRequested"].ID:
+ return _DestinationVerifier.ParseOwnershipTransferRequested(log)
+ case _DestinationVerifier.abi.Events["OwnershipTransferred"].ID:
+ return _DestinationVerifier.ParseOwnershipTransferred(log)
+ case _DestinationVerifier.abi.Events["ReportVerified"].ID:
+ return _DestinationVerifier.ParseReportVerified(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (DestinationVerifierAccessControllerSet) Topic() common.Hash {
+ return common.HexToHash("0x953e92b1a6442e9c3242531154a3f6f6eb00b4e9c719ba8118fa6235e4ce89b6")
+}
+
+func (DestinationVerifierConfigActivated) Topic() common.Hash {
+ return common.HexToHash("0x90186a1e77b498ec417ea88bd026cae00d7043c357cc45221777623bda582dd4")
+}
+
+func (DestinationVerifierConfigRemoved) Topic() common.Hash {
+ return common.HexToHash("0x970fd8f3ebdd9a271080aacf9807a5c709be0b448e4047a6fc212b8cc165368d")
+}
+
+func (DestinationVerifierConfigSet) Topic() common.Hash {
+ return common.HexToHash("0x2d763a674a99583454a287d792819ffb9ff7e791c23e7745a082701136ce336c")
+}
+
+func (DestinationVerifierFeeManagerSet) Topic() common.Hash {
+ return common.HexToHash("0x04628abcaa6b1674651352125cb94b65b289145bc2bc4d67720bb7d966372f03")
+}
+
+func (DestinationVerifierOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (DestinationVerifierOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (DestinationVerifierReportVerified) Topic() common.Hash {
+ return common.HexToHash("0x58ca9502e98a536e06e72d680fcc251e5d10b72291a281665a2c2dc0ac30fcc5")
+}
+
+func (_DestinationVerifier *DestinationVerifier) Address() common.Address {
+ return _DestinationVerifier.address
+}
+
+type DestinationVerifierInterface interface {
+ IVerifierProxy(opts *bind.CallOpts) (common.Address, error)
+
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SAccessController(opts *bind.CallOpts) (common.Address, error)
+
+ SFeeManager(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ RemoveLatestConfig(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetAccessController(opts *bind.TransactOpts, accessController common.Address) (*types.Transaction, error)
+
+ SetConfig(opts *bind.TransactOpts, signers []common.Address, f uint8, recipientAddressesAndWeights []CommonAddressAndWeight) (*types.Transaction, error)
+
+ SetConfigActive(opts *bind.TransactOpts, donConfigIndex *big.Int, isActive bool) (*types.Transaction, error)
+
+ SetConfigWithActivationTime(opts *bind.TransactOpts, signers []common.Address, f uint8, recipientAddressesAndWeights []CommonAddressAndWeight, activationTime uint32) (*types.Transaction, error)
+
+ SetFeeManager(opts *bind.TransactOpts, feeManager common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Verify(opts *bind.TransactOpts, signedReport []byte, parameterPayload []byte, sender common.Address) (*types.Transaction, error)
+
+ VerifyBulk(opts *bind.TransactOpts, signedReports [][]byte, parameterPayload []byte, sender common.Address) (*types.Transaction, error)
+
+ FilterAccessControllerSet(opts *bind.FilterOpts) (*DestinationVerifierAccessControllerSetIterator, error)
+
+ WatchAccessControllerSet(opts *bind.WatchOpts, sink chan<- *DestinationVerifierAccessControllerSet) (event.Subscription, error)
+
+ ParseAccessControllerSet(log types.Log) (*DestinationVerifierAccessControllerSet, error)
+
+ FilterConfigActivated(opts *bind.FilterOpts) (*DestinationVerifierConfigActivatedIterator, error)
+
+ WatchConfigActivated(opts *bind.WatchOpts, sink chan<- *DestinationVerifierConfigActivated) (event.Subscription, error)
+
+ ParseConfigActivated(log types.Log) (*DestinationVerifierConfigActivated, error)
+
+ FilterConfigRemoved(opts *bind.FilterOpts) (*DestinationVerifierConfigRemovedIterator, error)
+
+ WatchConfigRemoved(opts *bind.WatchOpts, sink chan<- *DestinationVerifierConfigRemoved) (event.Subscription, error)
+
+ ParseConfigRemoved(log types.Log) (*DestinationVerifierConfigRemoved, error)
+
+ FilterConfigSet(opts *bind.FilterOpts, donConfigId [][24]byte) (*DestinationVerifierConfigSetIterator, error)
+
+ WatchConfigSet(opts *bind.WatchOpts, sink chan<- *DestinationVerifierConfigSet, donConfigId [][24]byte) (event.Subscription, error)
+
+ ParseConfigSet(log types.Log) (*DestinationVerifierConfigSet, error)
+
+ FilterFeeManagerSet(opts *bind.FilterOpts) (*DestinationVerifierFeeManagerSetIterator, error)
+
+ WatchFeeManagerSet(opts *bind.WatchOpts, sink chan<- *DestinationVerifierFeeManagerSet) (event.Subscription, error)
+
+ ParseFeeManagerSet(log types.Log) (*DestinationVerifierFeeManagerSet, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationVerifierOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DestinationVerifierOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*DestinationVerifierOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationVerifierOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DestinationVerifierOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*DestinationVerifierOwnershipTransferred, error)
+
+ FilterReportVerified(opts *bind.FilterOpts, feedId [][32]byte) (*DestinationVerifierReportVerifiedIterator, error)
+
+ WatchReportVerified(opts *bind.WatchOpts, sink chan<- *DestinationVerifierReportVerified, feedId [][32]byte) (event.Subscription, error)
+
+ ParseReportVerified(log types.Log) (*DestinationVerifierReportVerified, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/llo-feeds/generated/destination_verifier_proxy/destination_verifier_proxy.go b/core/gethwrappers/llo-feeds/generated/destination_verifier_proxy/destination_verifier_proxy.go
new file mode 100644
index 00000000000..a2ae546d9bb
--- /dev/null
+++ b/core/gethwrappers/llo-feeds/generated/destination_verifier_proxy/destination_verifier_proxy.go
@@ -0,0 +1,676 @@
+// Code generated - DO NOT EDIT.
+// This file is a generated binding and any manual changes will be lost.
+
+package destination_verifier_proxy
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+ "strings"
+
+ ethereum "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
+)
+
+var (
+ _ = errors.New
+ _ = big.NewInt
+ _ = strings.NewReader
+ _ = ethereum.NotFound
+ _ = bind.Bind
+ _ = common.Big1
+ _ = types.BloomLookup
+ _ = event.NewSubscription
+ _ = abi.ConvertType
+)
+
+var DestinationVerifierProxyMetaData = &bind.MetaData{
+ ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"VerifierInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"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\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_accessController\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_feeManager\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"verifierAddress\",\"type\":\"address\"}],\"name\":\"setVerifier\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"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\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"parameterPayload\",\"type\":\"bytes\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"payloads\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"parameterPayload\",\"type\":\"bytes\"}],\"name\":\"verifyBulk\",\"outputs\":[{\"internalType\":\"bytes[]\",\"name\":\"verifiedReports\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b5033806000816100675760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615610097576100978161009f565b505050610148565b336001600160a01b038216036100f75760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161005e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b61130b806101576000396000f3fe6080604052600436106100b15760003560e01c80638da5cb5b11610069578063f2fde38b1161004e578063f2fde38b146101eb578063f7e83aee1461020b578063f873a61c1461021e57600080fd5b80638da5cb5b146101ab57806394ba2846146101d657600080fd5b806338416b5b1161009a57806338416b5b1461013a5780635437988d1461017457806379ba50971461019657600080fd5b806301ffc9a7146100b6578063181f5a77146100eb575b600080fd5b3480156100c257600080fd5b506100d66100d1366004610c56565b61023e565b60405190151581526020015b60405180910390f35b3480156100f757600080fd5b5060408051808201909152601e81527f44657374696e6174696f6e566572696669657250726f787920312e302e30000060208201525b6040516100e29190610d0d565b34801561014657600080fd5b5061014f6103bb565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100e2565b34801561018057600080fd5b5061019461018f366004610d42565b610454565b005b3480156101a257600080fd5b506101946107c8565b3480156101b757600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661014f565b3480156101e257600080fd5b5061014f6108c5565b3480156101f757600080fd5b50610194610206366004610d42565b610935565b61012d610219366004610da8565b610949565b61023161022c366004610e14565b610a18565b6040516100e29190610e95565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5437988d0000000000000000000000000000000000000000000000000000000014806102d157507fffffffff0000000000000000000000000000000000000000000000000000000082167ff7e83aee00000000000000000000000000000000000000000000000000000000145b8061031d57507fffffffff0000000000000000000000000000000000000000000000000000000082167ff873a61c00000000000000000000000000000000000000000000000000000000145b8061036957507fffffffff0000000000000000000000000000000000000000000000000000000082167f38416b5b00000000000000000000000000000000000000000000000000000000145b806103b557507fffffffff0000000000000000000000000000000000000000000000000000000082167f94ba284600000000000000000000000000000000000000000000000000000000145b92915050565b600254604080517f38416b5b000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff16916338416b5b9160048083019260209291908290030181865afa15801561042b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044f9190610f15565b905090565b61045c610ade565b6040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f94ba284600000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa1580156104e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061050a9190610f32565b15806105c157506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f38416b5b00000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa15801561059b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bf9190610f32565b155b8061067757506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f294d2bb100000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610651573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106759190610f32565b155b8061072d57506040517f01ffc9a70000000000000000000000000000000000000000000000000000000081527fd7c72e4e00000000000000000000000000000000000000000000000000000000600482015273ffffffffffffffffffffffffffffffffffffffff8216906301ffc9a790602401602060405180830381865afa158015610707573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061072b9190610f32565b155b15610781576040517f96ac86f300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610849576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610778565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600254604080517f94ba2846000000000000000000000000000000000000000000000000000000008152905160009273ffffffffffffffffffffffffffffffffffffffff16916394ba28469160048083019260209291908290030181865afa15801561042b573d6000803e3d6000fd5b61093d610ade565b61094681610b61565b50565b6002546040517f294d2bb100000000000000000000000000000000000000000000000000000000815260609173ffffffffffffffffffffffffffffffffffffffff169063294d2bb19034906109aa9089908990899089903390600401610f9d565b60006040518083038185885af11580156109c8573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a0f91908101906110f5565b95945050505050565b6002546040517fd7c72e4e00000000000000000000000000000000000000000000000000000000815260609173ffffffffffffffffffffffffffffffffffffffff169063d7c72e4e903490610a79908990899089908990339060040161112a565b60006040518083038185885af1158015610a97573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a0f919081019061123b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610778565b565b3373ffffffffffffffffffffffffffffffffffffffff821603610be0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610778565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215610c6857600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610c9857600080fd5b9392505050565b60005b83811015610cba578181015183820152602001610ca2565b50506000910152565b60008151808452610cdb816020860160208601610c9f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610c986020830184610cc3565b73ffffffffffffffffffffffffffffffffffffffff8116811461094657600080fd5b600060208284031215610d5457600080fd5b8135610c9881610d20565b60008083601f840112610d7157600080fd5b50813567ffffffffffffffff811115610d8957600080fd5b602083019150836020828501011115610da157600080fd5b9250929050565b60008060008060408587031215610dbe57600080fd5b843567ffffffffffffffff80821115610dd657600080fd5b610de288838901610d5f565b90965094506020870135915080821115610dfb57600080fd5b50610e0887828801610d5f565b95989497509550505050565b60008060008060408587031215610e2a57600080fd5b843567ffffffffffffffff80821115610e4257600080fd5b818701915087601f830112610e5657600080fd5b813581811115610e6557600080fd5b8860208260051b8501011115610e7a57600080fd5b602092830196509450908601359080821115610dfb57600080fd5b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015610f08577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452610ef6858351610cc3565b94509285019290850190600101610ebc565b5092979650505050505050565b600060208284031215610f2757600080fd5b8151610c9881610d20565b600060208284031215610f4457600080fd5b81518015158114610c9857600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b606081526000610fb1606083018789610f54565b8281036020840152610fc4818688610f54565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561106357611063610fed565b604052919050565b600082601f83011261107c57600080fd5b815167ffffffffffffffff81111561109657611096610fed565b6110c760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161101c565b8181528460208386010111156110dc57600080fd5b6110ed826020830160208701610c9f565b949350505050565b60006020828403121561110757600080fd5b815167ffffffffffffffff81111561111e57600080fd5b6110ed8482850161106b565b6060808252810185905260006080600587901b8301810190830188835b898110156111f6577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086850301835281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18c36030181126111a857600080fd5b8b01602081810191359067ffffffffffffffff8211156111c757600080fd5b8136038313156111d657600080fd5b6111e1878385610f54565b96509485019493909301925050600101611147565b505050828103602084015261120c818688610f54565b915050611231604083018473ffffffffffffffffffffffffffffffffffffffff169052565b9695505050505050565b6000602080838503121561124e57600080fd5b825167ffffffffffffffff8082111561126657600080fd5b818501915085601f83011261127a57600080fd5b81518181111561128c5761128c610fed565b8060051b61129b85820161101c565b91825283810185019185810190898411156112b557600080fd5b86860192505b838310156112f1578251858111156112d35760008081fd5b6112e18b89838a010161106b565b83525091860191908601906112bb565b999850505050505050505056fea164736f6c6343000813000a",
+}
+
+var DestinationVerifierProxyABI = DestinationVerifierProxyMetaData.ABI
+
+var DestinationVerifierProxyBin = DestinationVerifierProxyMetaData.Bin
+
+func DeployDestinationVerifierProxy(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *DestinationVerifierProxy, error) {
+ parsed, err := DestinationVerifierProxyMetaData.GetAbi()
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ if parsed == nil {
+ return common.Address{}, nil, nil, errors.New("GetABI returned nil")
+ }
+
+ address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DestinationVerifierProxyBin), backend)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, &DestinationVerifierProxy{address: address, abi: *parsed, DestinationVerifierProxyCaller: DestinationVerifierProxyCaller{contract: contract}, DestinationVerifierProxyTransactor: DestinationVerifierProxyTransactor{contract: contract}, DestinationVerifierProxyFilterer: DestinationVerifierProxyFilterer{contract: contract}}, nil
+}
+
+type DestinationVerifierProxy struct {
+ address common.Address
+ abi abi.ABI
+ DestinationVerifierProxyCaller
+ DestinationVerifierProxyTransactor
+ DestinationVerifierProxyFilterer
+}
+
+type DestinationVerifierProxyCaller struct {
+ contract *bind.BoundContract
+}
+
+type DestinationVerifierProxyTransactor struct {
+ contract *bind.BoundContract
+}
+
+type DestinationVerifierProxyFilterer struct {
+ contract *bind.BoundContract
+}
+
+type DestinationVerifierProxySession struct {
+ Contract *DestinationVerifierProxy
+ CallOpts bind.CallOpts
+ TransactOpts bind.TransactOpts
+}
+
+type DestinationVerifierProxyCallerSession struct {
+ Contract *DestinationVerifierProxyCaller
+ CallOpts bind.CallOpts
+}
+
+type DestinationVerifierProxyTransactorSession struct {
+ Contract *DestinationVerifierProxyTransactor
+ TransactOpts bind.TransactOpts
+}
+
+type DestinationVerifierProxyRaw struct {
+ Contract *DestinationVerifierProxy
+}
+
+type DestinationVerifierProxyCallerRaw struct {
+ Contract *DestinationVerifierProxyCaller
+}
+
+type DestinationVerifierProxyTransactorRaw struct {
+ Contract *DestinationVerifierProxyTransactor
+}
+
+func NewDestinationVerifierProxy(address common.Address, backend bind.ContractBackend) (*DestinationVerifierProxy, error) {
+ abi, err := abi.JSON(strings.NewReader(DestinationVerifierProxyABI))
+ if err != nil {
+ return nil, err
+ }
+ contract, err := bindDestinationVerifierProxy(address, backend, backend, backend)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierProxy{address: address, abi: abi, DestinationVerifierProxyCaller: DestinationVerifierProxyCaller{contract: contract}, DestinationVerifierProxyTransactor: DestinationVerifierProxyTransactor{contract: contract}, DestinationVerifierProxyFilterer: DestinationVerifierProxyFilterer{contract: contract}}, nil
+}
+
+func NewDestinationVerifierProxyCaller(address common.Address, caller bind.ContractCaller) (*DestinationVerifierProxyCaller, error) {
+ contract, err := bindDestinationVerifierProxy(address, caller, nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierProxyCaller{contract: contract}, nil
+}
+
+func NewDestinationVerifierProxyTransactor(address common.Address, transactor bind.ContractTransactor) (*DestinationVerifierProxyTransactor, error) {
+ contract, err := bindDestinationVerifierProxy(address, nil, transactor, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierProxyTransactor{contract: contract}, nil
+}
+
+func NewDestinationVerifierProxyFilterer(address common.Address, filterer bind.ContractFilterer) (*DestinationVerifierProxyFilterer, error) {
+ contract, err := bindDestinationVerifierProxy(address, nil, nil, filterer)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierProxyFilterer{contract: contract}, nil
+}
+
+func bindDestinationVerifierProxy(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
+ parsed, err := DestinationVerifierProxyMetaData.GetAbi()
+ if err != nil {
+ return nil, err
+ }
+ return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _DestinationVerifierProxy.Contract.DestinationVerifierProxyCaller.contract.Call(opts, result, method, params...)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.DestinationVerifierProxyTransactor.contract.Transfer(opts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.DestinationVerifierProxyTransactor.contract.Transact(opts, method, params...)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
+ return _DestinationVerifierProxy.Contract.contract.Call(opts, result, method, params...)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.contract.Transfer(opts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.contract.Transact(opts, method, params...)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCaller) Owner(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationVerifierProxy.contract.Call(opts, &out, "owner")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) Owner() (common.Address, error) {
+ return _DestinationVerifierProxy.Contract.Owner(&_DestinationVerifierProxy.CallOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCallerSession) Owner() (common.Address, error) {
+ return _DestinationVerifierProxy.Contract.Owner(&_DestinationVerifierProxy.CallOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCaller) SAccessController(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationVerifierProxy.contract.Call(opts, &out, "s_accessController")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) SAccessController() (common.Address, error) {
+ return _DestinationVerifierProxy.Contract.SAccessController(&_DestinationVerifierProxy.CallOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCallerSession) SAccessController() (common.Address, error) {
+ return _DestinationVerifierProxy.Contract.SAccessController(&_DestinationVerifierProxy.CallOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCaller) SFeeManager(opts *bind.CallOpts) (common.Address, error) {
+ var out []interface{}
+ err := _DestinationVerifierProxy.contract.Call(opts, &out, "s_feeManager")
+
+ if err != nil {
+ return *new(common.Address), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) SFeeManager() (common.Address, error) {
+ return _DestinationVerifierProxy.Contract.SFeeManager(&_DestinationVerifierProxy.CallOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCallerSession) SFeeManager() (common.Address, error) {
+ return _DestinationVerifierProxy.Contract.SFeeManager(&_DestinationVerifierProxy.CallOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) {
+ var out []interface{}
+ err := _DestinationVerifierProxy.contract.Call(opts, &out, "supportsInterface", interfaceId)
+
+ if err != nil {
+ return *new(bool), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(bool)).(*bool)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _DestinationVerifierProxy.Contract.SupportsInterface(&_DestinationVerifierProxy.CallOpts, interfaceId)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) {
+ return _DestinationVerifierProxy.Contract.SupportsInterface(&_DestinationVerifierProxy.CallOpts, interfaceId)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) {
+ var out []interface{}
+ err := _DestinationVerifierProxy.contract.Call(opts, &out, "typeAndVersion")
+
+ if err != nil {
+ return *new(string), err
+ }
+
+ out0 := *abi.ConvertType(out[0], new(string)).(*string)
+
+ return out0, err
+
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) TypeAndVersion() (string, error) {
+ return _DestinationVerifierProxy.Contract.TypeAndVersion(&_DestinationVerifierProxy.CallOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyCallerSession) TypeAndVersion() (string, error) {
+ return _DestinationVerifierProxy.Contract.TypeAndVersion(&_DestinationVerifierProxy.CallOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.contract.Transact(opts, "acceptOwnership")
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) AcceptOwnership() (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.AcceptOwnership(&_DestinationVerifierProxy.TransactOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactorSession) AcceptOwnership() (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.AcceptOwnership(&_DestinationVerifierProxy.TransactOpts)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactor) SetVerifier(opts *bind.TransactOpts, verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.contract.Transact(opts, "setVerifier", verifierAddress)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) SetVerifier(verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.SetVerifier(&_DestinationVerifierProxy.TransactOpts, verifierAddress)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactorSession) SetVerifier(verifierAddress common.Address) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.SetVerifier(&_DestinationVerifierProxy.TransactOpts, verifierAddress)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.contract.Transact(opts, "transferOwnership", to)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.TransferOwnership(&_DestinationVerifierProxy.TransactOpts, to)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.TransferOwnership(&_DestinationVerifierProxy.TransactOpts, to)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactor) Verify(opts *bind.TransactOpts, payload []byte, parameterPayload []byte) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.contract.Transact(opts, "verify", payload, parameterPayload)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) Verify(payload []byte, parameterPayload []byte) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.Verify(&_DestinationVerifierProxy.TransactOpts, payload, parameterPayload)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactorSession) Verify(payload []byte, parameterPayload []byte) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.Verify(&_DestinationVerifierProxy.TransactOpts, payload, parameterPayload)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactor) VerifyBulk(opts *bind.TransactOpts, payloads [][]byte, parameterPayload []byte) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.contract.Transact(opts, "verifyBulk", payloads, parameterPayload)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxySession) VerifyBulk(payloads [][]byte, parameterPayload []byte) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.VerifyBulk(&_DestinationVerifierProxy.TransactOpts, payloads, parameterPayload)
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyTransactorSession) VerifyBulk(payloads [][]byte, parameterPayload []byte) (*types.Transaction, error) {
+ return _DestinationVerifierProxy.Contract.VerifyBulk(&_DestinationVerifierProxy.TransactOpts, payloads, parameterPayload)
+}
+
+type DestinationVerifierProxyOwnershipTransferRequestedIterator struct {
+ Event *DestinationVerifierProxyOwnershipTransferRequested
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierProxyOwnershipTransferRequestedIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierProxyOwnershipTransferRequested)
+ 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(DestinationVerifierProxyOwnershipTransferRequested)
+ 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 *DestinationVerifierProxyOwnershipTransferRequestedIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierProxyOwnershipTransferRequestedIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierProxyOwnershipTransferRequested struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationVerifierProxyOwnershipTransferRequestedIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationVerifierProxy.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierProxyOwnershipTransferRequestedIterator{contract: _DestinationVerifierProxy.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DestinationVerifierProxyOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationVerifierProxy.contract.WatchLogs(opts, "OwnershipTransferRequested", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierProxyOwnershipTransferRequested)
+ if err := _DestinationVerifierProxy.contract.UnpackLog(event, "OwnershipTransferRequested", 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 (_DestinationVerifierProxy *DestinationVerifierProxyFilterer) ParseOwnershipTransferRequested(log types.Log) (*DestinationVerifierProxyOwnershipTransferRequested, error) {
+ event := new(DestinationVerifierProxyOwnershipTransferRequested)
+ if err := _DestinationVerifierProxy.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+type DestinationVerifierProxyOwnershipTransferredIterator struct {
+ Event *DestinationVerifierProxyOwnershipTransferred
+
+ contract *bind.BoundContract
+ event string
+
+ logs chan types.Log
+ sub ethereum.Subscription
+ done bool
+ fail error
+}
+
+func (it *DestinationVerifierProxyOwnershipTransferredIterator) Next() bool {
+
+ if it.fail != nil {
+ return false
+ }
+
+ if it.done {
+ select {
+ case log := <-it.logs:
+ it.Event = new(DestinationVerifierProxyOwnershipTransferred)
+ 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(DestinationVerifierProxyOwnershipTransferred)
+ 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 *DestinationVerifierProxyOwnershipTransferredIterator) Error() error {
+ return it.fail
+}
+
+func (it *DestinationVerifierProxyOwnershipTransferredIterator) Close() error {
+ it.sub.Unsubscribe()
+ return nil
+}
+
+type DestinationVerifierProxyOwnershipTransferred struct {
+ From common.Address
+ To common.Address
+ Raw types.Log
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationVerifierProxyOwnershipTransferredIterator, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationVerifierProxy.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return &DestinationVerifierProxyOwnershipTransferredIterator{contract: _DestinationVerifierProxy.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxyFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DestinationVerifierProxyOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) {
+
+ var fromRule []interface{}
+ for _, fromItem := range from {
+ fromRule = append(fromRule, fromItem)
+ }
+ var toRule []interface{}
+ for _, toItem := range to {
+ toRule = append(toRule, toItem)
+ }
+
+ logs, sub, err := _DestinationVerifierProxy.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule)
+ if err != nil {
+ return nil, err
+ }
+ return event.NewSubscription(func(quit <-chan struct{}) error {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case log := <-logs:
+
+ event := new(DestinationVerifierProxyOwnershipTransferred)
+ if err := _DestinationVerifierProxy.contract.UnpackLog(event, "OwnershipTransferred", 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 (_DestinationVerifierProxy *DestinationVerifierProxyFilterer) ParseOwnershipTransferred(log types.Log) (*DestinationVerifierProxyOwnershipTransferred, error) {
+ event := new(DestinationVerifierProxyOwnershipTransferred)
+ if err := _DestinationVerifierProxy.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil {
+ return nil, err
+ }
+ event.Raw = log
+ return event, nil
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxy) ParseLog(log types.Log) (generated.AbigenLog, error) {
+ switch log.Topics[0] {
+ case _DestinationVerifierProxy.abi.Events["OwnershipTransferRequested"].ID:
+ return _DestinationVerifierProxy.ParseOwnershipTransferRequested(log)
+ case _DestinationVerifierProxy.abi.Events["OwnershipTransferred"].ID:
+ return _DestinationVerifierProxy.ParseOwnershipTransferred(log)
+
+ default:
+ return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0])
+ }
+}
+
+func (DestinationVerifierProxyOwnershipTransferRequested) Topic() common.Hash {
+ return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278")
+}
+
+func (DestinationVerifierProxyOwnershipTransferred) Topic() common.Hash {
+ return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0")
+}
+
+func (_DestinationVerifierProxy *DestinationVerifierProxy) Address() common.Address {
+ return _DestinationVerifierProxy.address
+}
+
+type DestinationVerifierProxyInterface interface {
+ Owner(opts *bind.CallOpts) (common.Address, error)
+
+ SAccessController(opts *bind.CallOpts) (common.Address, error)
+
+ SFeeManager(opts *bind.CallOpts) (common.Address, error)
+
+ SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error)
+
+ TypeAndVersion(opts *bind.CallOpts) (string, error)
+
+ AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error)
+
+ SetVerifier(opts *bind.TransactOpts, verifierAddress common.Address) (*types.Transaction, error)
+
+ TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error)
+
+ Verify(opts *bind.TransactOpts, payload []byte, parameterPayload []byte) (*types.Transaction, error)
+
+ VerifyBulk(opts *bind.TransactOpts, payloads [][]byte, parameterPayload []byte) (*types.Transaction, error)
+
+ FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationVerifierProxyOwnershipTransferRequestedIterator, error)
+
+ WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *DestinationVerifierProxyOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferRequested(log types.Log) (*DestinationVerifierProxyOwnershipTransferRequested, error)
+
+ FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*DestinationVerifierProxyOwnershipTransferredIterator, error)
+
+ WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *DestinationVerifierProxyOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error)
+
+ ParseOwnershipTransferred(log types.Log) (*DestinationVerifierProxyOwnershipTransferred, error)
+
+ ParseLog(log types.Log) (generated.AbigenLog, error)
+
+ Address() common.Address
+}
diff --git a/core/gethwrappers/llo-feeds/generated/errored_verifier/errored_verifier.go b/core/gethwrappers/llo-feeds/generated/errored_verifier/errored_verifier.go
index 4d140ea064a..f834686dfef 100644
--- a/core/gethwrappers/llo-feeds/generated/errored_verifier/errored_verifier.go
+++ b/core/gethwrappers/llo-feeds/generated/errored_verifier/errored_verifier.go
@@ -34,8 +34,8 @@ type CommonAddressAndWeight struct {
}
var ErroredVerifierMetaData = &bind.MetaData{
- ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"activateConfig\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"activateFeed\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"deactivateConfig\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"deactivateFeed\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"setConfigFromSource\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
- Bin: "0x608060405234801561001057600080fd5b50610c2e806100206000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c8063b70d929d11610076578063e7db9c2a1161005b578063e7db9c2a146101d1578063e84f128e146101e4578063f01072211461021a57600080fd5b8063b70d929d14610188578063ded6307c146101be57600080fd5b80633dd86430116100a75780633dd864301461014d578063564a0a7a1461016257806394d959801461017557600080fd5b806301ffc9a7146100c35780633d3ac1b51461012d575b600080fd5b6101186100d136600461059a565b7fffffffff00000000000000000000000000000000000000000000000000000000167f3d3ac1b5000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b61014061013b366004610741565b610228565b604051610124919061078f565b61016061015b3660046107fb565b610292565b005b6101606101703660046107fb565b6102f4565b610160610183366004610814565b610356565b61019b6101963660046107fb565b6103b8565b604080519315158452602084019290925263ffffffff1690820152606001610124565b6101606101cc366004610814565b610447565b6101606101df3660046109f1565b6104a9565b6101f76101f23660046107fb565b61050b565b6040805163ffffffff948516815293909216602084015290820152606001610124565b6101606101df366004610b24565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f4661696c656420746f207665726966790000000000000000000000000000000060448201526060906064015b60405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4661696c656420746f20616374697661746520666565640000000000000000006044820152606401610289565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4661696c656420746f20646561637469766174652066656564000000000000006044820152606401610289565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4661696c656420746f206465616374697661746520636f6e66696700000000006044820152606401610289565b60008060006040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610289906020808252602c908201527f4661696c656420746f20676574206c617465737420636f6e666967206469676560408201527f737420616e642065706f63680000000000000000000000000000000000000000606082015260800190565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4661696c656420746f20616374697661746520636f6e666967000000000000006044820152606401610289565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4661696c656420746f2073657420636f6e6669670000000000000000000000006044820152606401610289565b60008060006040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102899060208082526023908201527f4661696c656420746f20676574206c617465737420636f6e666967206465746160408201527f696c730000000000000000000000000000000000000000000000000000000000606082015260800190565b6000602082840312156105ac57600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105dc57600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610635576106356105e3565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610682576106826105e3565b604052919050565b600082601f83011261069b57600080fd5b813567ffffffffffffffff8111156106b5576106b56105e3565b6106e660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161063b565b8181528460208386010111156106fb57600080fd5b816020850160208301376000918101602001919091529392505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461073c57600080fd5b919050565b6000806040838503121561075457600080fd5b823567ffffffffffffffff81111561076b57600080fd5b6107778582860161068a565b92505061078660208401610718565b90509250929050565b600060208083528351808285015260005b818110156107bc578581018301518582016040015282016107a0565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60006020828403121561080d57600080fd5b5035919050565b6000806040838503121561082757600080fd5b50508035926020909101359150565b803563ffffffff8116811461073c57600080fd5b600067ffffffffffffffff821115610864576108646105e3565b5060051b60200190565b600082601f83011261087f57600080fd5b8135602061089461088f8361084a565b61063b565b82815260059290921b840181019181810190868411156108b357600080fd5b8286015b848110156108d5576108c881610718565b83529183019183016108b7565b509695505050505050565b600082601f8301126108f157600080fd5b8135602061090161088f8361084a565b82815260059290921b8401810191818101908684111561092057600080fd5b8286015b848110156108d55780358352918301918301610924565b803560ff8116811461073c57600080fd5b803567ffffffffffffffff8116811461073c57600080fd5b600082601f83011261097557600080fd5b8135602061098561088f8361084a565b82815260069290921b840181019181810190868411156109a457600080fd5b8286015b848110156108d557604081890312156109c15760008081fd5b6109c9610612565b6109d282610718565b81526109df85830161094c565b818601528352918301916040016109a8565b60008060008060008060008060008060006101608c8e031215610a1357600080fd5b8b359a5060208c01359950610a2a60408d01610718565b9850610a3860608d01610836565b975067ffffffffffffffff8060808e01351115610a5457600080fd5b610a648e60808f01358f0161086e565b97508060a08e01351115610a7757600080fd5b610a878e60a08f01358f016108e0565b9650610a9560c08e0161093b565b95508060e08e01351115610aa857600080fd5b610ab88e60e08f01358f0161068a565b9450610ac76101008e0161094c565b9350806101208e01351115610adb57600080fd5b610aec8e6101208f01358f0161068a565b9250806101408e01351115610b0057600080fd5b50610b128d6101408e01358e01610964565b90509295989b509295989b9093969950565b600080600080600080600080610100898b031215610b4157600080fd5b88359750602089013567ffffffffffffffff80821115610b6057600080fd5b610b6c8c838d0161086e565b985060408b0135915080821115610b8257600080fd5b610b8e8c838d016108e0565b9750610b9c60608c0161093b565b965060808b0135915080821115610bb257600080fd5b610bbe8c838d0161068a565b9550610bcc60a08c0161094c565b945060c08b0135915080821115610be257600080fd5b610bee8c838d0161068a565b935060e08b0135915080821115610c0457600080fd5b50610c118b828c01610964565b915050929598509295989093965056fea164736f6c6343000813000a",
+ ABI: "[{\"inputs\":[],\"name\":\"FailedToActivateConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToActivateFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToDeactivateConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToDeactivateFeed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToGetLatestConfigDetails\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToGetLatestConfigDigestAndEpoch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToSetConfig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedToVerify\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"activateConfig\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"activateFeed\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"deactivateConfig\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"deactivateFeed\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"weight\",\"type\":\"uint64\"}],\"internalType\":\"structCommon.AddressAndWeight[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"name\":\"setConfigFromSource\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"verify\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]",
+ Bin: "0x608060405234801561001057600080fd5b50610a58806100206000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c8063b70d929d11610076578063e7db9c2a1161005b578063e7db9c2a146101d1578063e84f128e146101e4578063f01072211461021a57600080fd5b8063b70d929d14610188578063ded6307c146101be57600080fd5b80633dd86430116100a75780633dd864301461014d578063564a0a7a1461016257806394d959801461017557600080fd5b806301ffc9a7146100c35780633d3ac1b51461012d575b600080fd5b6101186100d13660046103c4565b7fffffffff00000000000000000000000000000000000000000000000000000000167f3d3ac1b5000000000000000000000000000000000000000000000000000000001490565b60405190151581526020015b60405180910390f35b61014061013b36600461056b565b610228565b60405161012491906105b9565b61016061015b366004610625565b61025c565b005b610160610170366004610625565b61028e565b61016061018336600461063e565b6102c0565b61019b610196366004610625565b6102f2565b604080519315158452602084019290925263ffffffff1690820152606001610124565b6101606101cc36600461063e565b610329565b6101606101df36600461081b565b61035b565b6101f76101f2366004610625565b61038d565b6040805163ffffffff948516815293909216602084015290820152606001610124565b6101606101df36600461094e565b60606040517fcf2e344600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9601b68300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa03564b300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f8a406e4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060006040517fbbc0083000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f7adb7c9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f35e91bf100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060006040517fa06d64a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000602082840312156103d657600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461040657600080fd5b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561045f5761045f61040d565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156104ac576104ac61040d565b604052919050565b600082601f8301126104c557600080fd5b813567ffffffffffffffff8111156104df576104df61040d565b61051060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610465565b81815284602083860101111561052557600080fd5b816020850160208301376000918101602001919091529392505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461056657600080fd5b919050565b6000806040838503121561057e57600080fd5b823567ffffffffffffffff81111561059557600080fd5b6105a1858286016104b4565b9250506105b060208401610542565b90509250929050565b600060208083528351808285015260005b818110156105e6578581018301518582016040015282016105ca565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60006020828403121561063757600080fd5b5035919050565b6000806040838503121561065157600080fd5b50508035926020909101359150565b803563ffffffff8116811461056657600080fd5b600067ffffffffffffffff82111561068e5761068e61040d565b5060051b60200190565b600082601f8301126106a957600080fd5b813560206106be6106b983610674565b610465565b82815260059290921b840181019181810190868411156106dd57600080fd5b8286015b848110156106ff576106f281610542565b83529183019183016106e1565b509695505050505050565b600082601f83011261071b57600080fd5b8135602061072b6106b983610674565b82815260059290921b8401810191818101908684111561074a57600080fd5b8286015b848110156106ff578035835291830191830161074e565b803560ff8116811461056657600080fd5b803567ffffffffffffffff8116811461056657600080fd5b600082601f83011261079f57600080fd5b813560206107af6106b983610674565b82815260069290921b840181019181810190868411156107ce57600080fd5b8286015b848110156106ff57604081890312156107eb5760008081fd5b6107f361043c565b6107fc82610542565b8152610809858301610776565b818601528352918301916040016107d2565b60008060008060008060008060008060006101608c8e03121561083d57600080fd5b8b359a5060208c0135995061085460408d01610542565b985061086260608d01610660565b975067ffffffffffffffff8060808e0135111561087e57600080fd5b61088e8e60808f01358f01610698565b97508060a08e013511156108a157600080fd5b6108b18e60a08f01358f0161070a565b96506108bf60c08e01610765565b95508060e08e013511156108d257600080fd5b6108e28e60e08f01358f016104b4565b94506108f16101008e01610776565b9350806101208e0135111561090557600080fd5b6109168e6101208f01358f016104b4565b9250806101408e0135111561092a57600080fd5b5061093c8d6101408e01358e0161078e565b90509295989b509295989b9093969950565b600080600080600080600080610100898b03121561096b57600080fd5b88359750602089013567ffffffffffffffff8082111561098a57600080fd5b6109968c838d01610698565b985060408b01359150808211156109ac57600080fd5b6109b88c838d0161070a565b97506109c660608c01610765565b965060808b01359150808211156109dc57600080fd5b6109e88c838d016104b4565b95506109f660a08c01610776565b945060c08b0135915080821115610a0c57600080fd5b610a188c838d016104b4565b935060e08b0135915080821115610a2e57600080fd5b50610a3b8b828c0161078e565b915050929598509295989093965056fea164736f6c6343000813000a",
}
var ErroredVerifierABI = ErroredVerifierMetaData.ABI
diff --git a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt
index 729d3a295cd..0eec657b4c7 100644
--- a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt
+++ b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt
@@ -2,7 +2,11 @@ GETH_VERSION: 1.13.8
channel_config_store: ../../../contracts/solc/v0.8.19/ChannelConfigStore/ChannelConfigStore.abi ../../../contracts/solc/v0.8.19/ChannelConfigStore/ChannelConfigStore.bin c90e29d9f1a885098982b6175e0447416431b28c605273c807694ac7141e9167
channel_config_verifier_proxy: ../../../contracts/solc/v0.8.19/ChannelVerifierProxy/ChannelVerifierProxy.abi ../../../contracts/solc/v0.8.19/ChannelVerifierProxy/ChannelVerifierProxy.bin 655658e5f61dfadfe3268de04f948b7e690ad03ca45676e645d6cd6018154661
channel_verifier: ../../../contracts/solc/v0.8.19/ChannelVerifier/ChannelVerifier.abi ../../../contracts/solc/v0.8.19/ChannelVerifier/ChannelVerifier.bin e6020553bd8e3e6b250fcaffe7efd22aea955c8c1a0eb05d282fdeb0ab6550b7
-errored_verifier: ../../../contracts/solc/v0.8.19/ErroredVerifier/ErroredVerifier.abi ../../../contracts/solc/v0.8.19/ErroredVerifier/ErroredVerifier.bin a3e5a77262e13ee30fe8d35551b32a3452d71929e43fd780bbfefeaf4aa62e43
+destination_fee_manager: ../../../contracts/solc/v0.8.19/DestinationFeeManager/DestinationFeeManager.abi ../../../contracts/solc/v0.8.19/DestinationFeeManager/DestinationFeeManager.bin c581af84832b8fd886685f59518bcdb11bd1c9b508d88b07c04d6226e6a2789e
+destination_reward_manager: ../../../contracts/solc/v0.8.19/DestinationRewardManager/DestinationRewardManager.abi ../../../contracts/solc/v0.8.19/DestinationRewardManager/DestinationRewardManager.bin 6aed4313578f74ede71bcb60674391103d265d96d56d4736a79ef4128f0590f4
+destination_verifier: ../../../contracts/solc/v0.8.19/DestinationVerifier/DestinationVerifier.abi ../../../contracts/solc/v0.8.19/DestinationVerifier/DestinationVerifier.bin 2dc118aecd5c30d34a69354a9fb603beb98d46215a18d31c59f0f7902fd8f4c2
+destination_verifier_proxy: ../../../contracts/solc/v0.8.19/DestinationVerifierProxy/DestinationVerifierProxy.abi ../../../contracts/solc/v0.8.19/DestinationVerifierProxy/DestinationVerifierProxy.bin a4bf230bbba8a7b8e32a85a6161ca1343f7472b257c358a73ac37996809ce1c0
+errored_verifier: ../../../contracts/solc/v0.8.19/ErroredVerifier/ErroredVerifier.abi ../../../contracts/solc/v0.8.19/ErroredVerifier/ErroredVerifier.bin ad8ac8d6b99890081725e2304d79d1ba7dd5212b89d130aa9689f4269eed4691
exposed_channel_verifier: ../../../contracts/solc/v0.8.19/ExposedChannelVerifier/ExposedChannelVerifier.abi ../../../contracts/solc/v0.8.19/ExposedChannelVerifier/ExposedChannelVerifier.bin c21cde078900241c06de69e2bc5d906c5ef558b52db66caa68bed065940a2253
exposed_verifier: ../../../contracts/solc/v0.8.19/ExposedVerifier/ExposedVerifier.abi ../../../contracts/solc/v0.8.19/ExposedVerifier/ExposedVerifier.bin 00816ab345f768e522c79abadeadf9155c2c688067e18f8f73e5d6ab71037663
fee_manager: ../../../contracts/solc/v0.8.19/FeeManager/FeeManager.abi ../../../contracts/solc/v0.8.19/FeeManager/FeeManager.bin edc85f34294ae7c90d45c4c71eb5c105c60a4842dfbbf700c692870ffcc403a1
diff --git a/core/gethwrappers/llo-feeds/go_generate.go b/core/gethwrappers/llo-feeds/go_generate.go
index 5e5b841b72d..688b503cc1e 100644
--- a/core/gethwrappers/llo-feeds/go_generate.go
+++ b/core/gethwrappers/llo-feeds/go_generate.go
@@ -12,3 +12,8 @@ package gethwrappers
//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/ChannelConfigStore/ChannelConfigStore.abi ../../../contracts/solc/v0.8.19/ChannelConfigStore/ChannelConfigStore.bin ChannelConfigStore channel_config_store
//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/ChannelVerifier/ChannelVerifier.abi ../../../contracts/solc/v0.8.19/ChannelVerifier/ChannelVerifier.bin ChannelVerifier channel_verifier
//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/ExposedChannelVerifier/ExposedChannelVerifier.abi ../../../contracts/solc/v0.8.19/ExposedChannelVerifier/ExposedChannelVerifier.bin ExposedChannelVerifier exposed_channel_verifier
+
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/DestinationVerifier/DestinationVerifier.abi ../../../contracts/solc/v0.8.19/DestinationVerifier/DestinationVerifier.bin DestinationVerifier destination_verifier
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/DestinationVerifierProxy/DestinationVerifierProxy.abi ../../../contracts/solc/v0.8.19/DestinationVerifierProxy/DestinationVerifierProxy.bin DestinationVerifierProxy destination_verifier_proxy
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/DestinationFeeManager/DestinationFeeManager.abi ../../../contracts/solc/v0.8.19/DestinationFeeManager/DestinationFeeManager.bin DestinationFeeManager destination_fee_manager
+//go:generate go run ../generation/generate/wrap.go ../../../contracts/solc/v0.8.19/DestinationRewardManager/DestinationRewardManager.abi ../../../contracts/solc/v0.8.19/DestinationRewardManager/DestinationRewardManager.bin DestinationRewardManager destination_reward_manager
diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go
index 12491300bf7..7447d1385f6 100644
--- a/core/internal/cltest/cltest.go
+++ b/core/internal/cltest/cltest.go
@@ -439,6 +439,13 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn
}
initOps = append(initOps, chainlink.InitStarknet(testCtx, relayerFactory, starkCfg))
}
+ if cfg.AptosEnabled() {
+ aptosCfg := chainlink.AptosFactoryConfig{
+ Keystore: keyStore.Aptos(),
+ TOMLConfigs: cfg.AptosConfigs(),
+ }
+ initOps = append(initOps, chainlink.InitAptos(testCtx, relayerFactory, aptosCfg))
+ }
relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...)
if err != nil {
diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go
index 9e0ee2f3f20..fd01f72c131 100644
--- a/core/internal/cltest/mocks.go
+++ b/core/internal/cltest/mocks.go
@@ -392,6 +392,7 @@ func NewLegacyChainsWithMockChain(t testing.TB, ethClient evmclient.Client, cfg
scopedCfg := evmtest.NewChainScopedConfig(t, cfg)
ch.On("ID").Return(scopedCfg.EVM().ChainID())
ch.On("Config").Return(scopedCfg)
+ ch.On("HeadTracker").Return(nil)
return NewLegacyChainsWithChain(ch, cfg)
}
diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go
index 046f21b7f7d..86e43f44eb4 100644
--- a/core/internal/features/features_test.go
+++ b/core/internal/features/features_test.go
@@ -1339,7 +1339,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) {
chain := evmtest.MustGetDefaultChain(t, legacyChains)
estimator := chain.GasEstimator()
- gasPrice, gasLimit, err := estimator.GetFee(testutils.Context(t), nil, 500_000, maxGasPrice)
+ gasPrice, gasLimit, err := estimator.GetFee(testutils.Context(t), nil, 500_000, maxGasPrice, nil)
require.NoError(t, err)
assert.Equal(t, uint64(500000), gasLimit)
assert.Equal(t, "41.5 gwei", gasPrice.Legacy.String())
@@ -1360,7 +1360,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) {
newHeads.TrySend(h43)
gomega.NewWithT(t).Eventually(func() string {
- gasPrice, _, err := estimator.GetFee(testutils.Context(t), nil, 500000, maxGasPrice)
+ gasPrice, _, err := estimator.GetFee(testutils.Context(t), nil, 500000, maxGasPrice, nil)
require.NoError(t, err)
return gasPrice.Legacy.String()
}, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal("45 gwei"))
diff --git a/core/internal/mocks/prometheus_backend.go b/core/internal/mocks/prometheus_backend.go
deleted file mode 100644
index d02f7062cbf..00000000000
--- a/core/internal/mocks/prometheus_backend.go
+++ /dev/null
@@ -1,204 +0,0 @@
-// Code generated by mockery v2.43.2. DO NOT EDIT.
-
-package mocks
-
-import (
- big "math/big"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// PrometheusBackend is an autogenerated mock type for the PrometheusBackend type
-type PrometheusBackend struct {
- mock.Mock
-}
-
-type PrometheusBackend_Expecter struct {
- mock *mock.Mock
-}
-
-func (_m *PrometheusBackend) EXPECT() *PrometheusBackend_Expecter {
- return &PrometheusBackend_Expecter{mock: &_m.Mock}
-}
-
-// SetMaxUnconfirmedAge provides a mock function with given fields: _a0, _a1
-func (_m *PrometheusBackend) SetMaxUnconfirmedAge(_a0 *big.Int, _a1 float64) {
- _m.Called(_a0, _a1)
-}
-
-// PrometheusBackend_SetMaxUnconfirmedAge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetMaxUnconfirmedAge'
-type PrometheusBackend_SetMaxUnconfirmedAge_Call struct {
- *mock.Call
-}
-
-// SetMaxUnconfirmedAge is a helper method to define mock.On call
-// - _a0 *big.Int
-// - _a1 float64
-func (_e *PrometheusBackend_Expecter) SetMaxUnconfirmedAge(_a0 interface{}, _a1 interface{}) *PrometheusBackend_SetMaxUnconfirmedAge_Call {
- return &PrometheusBackend_SetMaxUnconfirmedAge_Call{Call: _e.mock.On("SetMaxUnconfirmedAge", _a0, _a1)}
-}
-
-func (_c *PrometheusBackend_SetMaxUnconfirmedAge_Call) Run(run func(_a0 *big.Int, _a1 float64)) *PrometheusBackend_SetMaxUnconfirmedAge_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(*big.Int), args[1].(float64))
- })
- return _c
-}
-
-func (_c *PrometheusBackend_SetMaxUnconfirmedAge_Call) Return() *PrometheusBackend_SetMaxUnconfirmedAge_Call {
- _c.Call.Return()
- return _c
-}
-
-func (_c *PrometheusBackend_SetMaxUnconfirmedAge_Call) RunAndReturn(run func(*big.Int, float64)) *PrometheusBackend_SetMaxUnconfirmedAge_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetMaxUnconfirmedBlocks provides a mock function with given fields: _a0, _a1
-func (_m *PrometheusBackend) SetMaxUnconfirmedBlocks(_a0 *big.Int, _a1 int64) {
- _m.Called(_a0, _a1)
-}
-
-// PrometheusBackend_SetMaxUnconfirmedBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetMaxUnconfirmedBlocks'
-type PrometheusBackend_SetMaxUnconfirmedBlocks_Call struct {
- *mock.Call
-}
-
-// SetMaxUnconfirmedBlocks is a helper method to define mock.On call
-// - _a0 *big.Int
-// - _a1 int64
-func (_e *PrometheusBackend_Expecter) SetMaxUnconfirmedBlocks(_a0 interface{}, _a1 interface{}) *PrometheusBackend_SetMaxUnconfirmedBlocks_Call {
- return &PrometheusBackend_SetMaxUnconfirmedBlocks_Call{Call: _e.mock.On("SetMaxUnconfirmedBlocks", _a0, _a1)}
-}
-
-func (_c *PrometheusBackend_SetMaxUnconfirmedBlocks_Call) Run(run func(_a0 *big.Int, _a1 int64)) *PrometheusBackend_SetMaxUnconfirmedBlocks_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(*big.Int), args[1].(int64))
- })
- return _c
-}
-
-func (_c *PrometheusBackend_SetMaxUnconfirmedBlocks_Call) Return() *PrometheusBackend_SetMaxUnconfirmedBlocks_Call {
- _c.Call.Return()
- return _c
-}
-
-func (_c *PrometheusBackend_SetMaxUnconfirmedBlocks_Call) RunAndReturn(run func(*big.Int, int64)) *PrometheusBackend_SetMaxUnconfirmedBlocks_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetPipelineRunsQueued provides a mock function with given fields: n
-func (_m *PrometheusBackend) SetPipelineRunsQueued(n int) {
- _m.Called(n)
-}
-
-// PrometheusBackend_SetPipelineRunsQueued_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPipelineRunsQueued'
-type PrometheusBackend_SetPipelineRunsQueued_Call struct {
- *mock.Call
-}
-
-// SetPipelineRunsQueued is a helper method to define mock.On call
-// - n int
-func (_e *PrometheusBackend_Expecter) SetPipelineRunsQueued(n interface{}) *PrometheusBackend_SetPipelineRunsQueued_Call {
- return &PrometheusBackend_SetPipelineRunsQueued_Call{Call: _e.mock.On("SetPipelineRunsQueued", n)}
-}
-
-func (_c *PrometheusBackend_SetPipelineRunsQueued_Call) Run(run func(n int)) *PrometheusBackend_SetPipelineRunsQueued_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(int))
- })
- return _c
-}
-
-func (_c *PrometheusBackend_SetPipelineRunsQueued_Call) Return() *PrometheusBackend_SetPipelineRunsQueued_Call {
- _c.Call.Return()
- return _c
-}
-
-func (_c *PrometheusBackend_SetPipelineRunsQueued_Call) RunAndReturn(run func(int)) *PrometheusBackend_SetPipelineRunsQueued_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetPipelineTaskRunsQueued provides a mock function with given fields: n
-func (_m *PrometheusBackend) SetPipelineTaskRunsQueued(n int) {
- _m.Called(n)
-}
-
-// PrometheusBackend_SetPipelineTaskRunsQueued_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPipelineTaskRunsQueued'
-type PrometheusBackend_SetPipelineTaskRunsQueued_Call struct {
- *mock.Call
-}
-
-// SetPipelineTaskRunsQueued is a helper method to define mock.On call
-// - n int
-func (_e *PrometheusBackend_Expecter) SetPipelineTaskRunsQueued(n interface{}) *PrometheusBackend_SetPipelineTaskRunsQueued_Call {
- return &PrometheusBackend_SetPipelineTaskRunsQueued_Call{Call: _e.mock.On("SetPipelineTaskRunsQueued", n)}
-}
-
-func (_c *PrometheusBackend_SetPipelineTaskRunsQueued_Call) Run(run func(n int)) *PrometheusBackend_SetPipelineTaskRunsQueued_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(int))
- })
- return _c
-}
-
-func (_c *PrometheusBackend_SetPipelineTaskRunsQueued_Call) Return() *PrometheusBackend_SetPipelineTaskRunsQueued_Call {
- _c.Call.Return()
- return _c
-}
-
-func (_c *PrometheusBackend_SetPipelineTaskRunsQueued_Call) RunAndReturn(run func(int)) *PrometheusBackend_SetPipelineTaskRunsQueued_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// SetUnconfirmedTransactions provides a mock function with given fields: _a0, _a1
-func (_m *PrometheusBackend) SetUnconfirmedTransactions(_a0 *big.Int, _a1 int64) {
- _m.Called(_a0, _a1)
-}
-
-// PrometheusBackend_SetUnconfirmedTransactions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetUnconfirmedTransactions'
-type PrometheusBackend_SetUnconfirmedTransactions_Call struct {
- *mock.Call
-}
-
-// SetUnconfirmedTransactions is a helper method to define mock.On call
-// - _a0 *big.Int
-// - _a1 int64
-func (_e *PrometheusBackend_Expecter) SetUnconfirmedTransactions(_a0 interface{}, _a1 interface{}) *PrometheusBackend_SetUnconfirmedTransactions_Call {
- return &PrometheusBackend_SetUnconfirmedTransactions_Call{Call: _e.mock.On("SetUnconfirmedTransactions", _a0, _a1)}
-}
-
-func (_c *PrometheusBackend_SetUnconfirmedTransactions_Call) Run(run func(_a0 *big.Int, _a1 int64)) *PrometheusBackend_SetUnconfirmedTransactions_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(*big.Int), args[1].(int64))
- })
- return _c
-}
-
-func (_c *PrometheusBackend_SetUnconfirmedTransactions_Call) Return() *PrometheusBackend_SetUnconfirmedTransactions_Call {
- _c.Call.Return()
- return _c
-}
-
-func (_c *PrometheusBackend_SetUnconfirmedTransactions_Call) RunAndReturn(run func(*big.Int, int64)) *PrometheusBackend_SetUnconfirmedTransactions_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// NewPrometheusBackend creates a new instance of PrometheusBackend. 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 NewPrometheusBackend(t interface {
- mock.TestingT
- Cleanup(func())
-}) *PrometheusBackend {
- mock := &PrometheusBackend{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/core/recovery/recover.go b/core/recovery/recover.go
index 8e485abc556..61315defa9a 100644
--- a/core/recovery/recover.go
+++ b/core/recovery/recover.go
@@ -3,38 +3,38 @@ package recovery
import (
"github.com/getsentry/sentry-go"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
+ corelogger "github.com/smartcontractkit/chainlink/v2/core/logger"
)
func ReportPanics(fn func()) {
- defer func() {
- if err := recover(); err != nil {
- sentry.CurrentHub().Recover(err)
- sentry.Flush(logger.SentryFlushDeadline)
+ HandleFn(fn, func(err any) {
+ sentry.CurrentHub().Recover(err)
+ sentry.Flush(corelogger.SentryFlushDeadline)
- panic(err)
- }
- }()
- fn()
+ panic(err)
+ })
}
func WrapRecover(lggr logger.Logger, fn func()) {
- defer func() {
- if err := recover(); err != nil {
- lggr.Recover(err)
+ WrapRecoverHandle(lggr, fn, nil)
+}
+
+func WrapRecoverHandle(lggr logger.Logger, fn func(), onPanic func(recovered any)) {
+ HandleFn(fn, func(recovered any) {
+ logger.Sugared(lggr).Criticalw("Recovered goroutine panic", "panic", recovered)
+
+ if onPanic != nil {
+ onPanic(recovered)
}
- }()
- fn()
+ })
}
-func WrapRecoverHandle(lggr logger.Logger, fn func(), onPanic func(interface{})) {
+func HandleFn(fn func(), onPanic func(recovered any)) {
defer func() {
- if err := recover(); err != nil {
- lggr.Recover(err)
-
- if onPanic != nil {
- onPanic(err)
- }
+ if recovered := recover(); recovered != nil {
+ onPanic(recovered)
}
}()
fn()
diff --git a/core/scripts/go.mod b/core/scripts/go.mod
index 3753cf92bc0..27073b9ab19 100644
--- a/core/scripts/go.mod
+++ b/core/scripts/go.mod
@@ -22,7 +22,7 @@ require (
github.com/prometheus/client_golang v1.17.0
github.com/shopspring/decimal v1.4.0
github.com/smartcontractkit/chainlink-automation v1.0.4
- github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1
+ github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5
github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7
github.com/spf13/cobra v1.8.0
@@ -60,7 +60,7 @@ require (
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/avast/retry-go/v4 v4.6.0 // 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
@@ -102,7 +102,7 @@ require (
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/deckarep/golang-set/v2 v2.3.0 // indirect
+ github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
@@ -171,7 +171,7 @@ require (
github.com/gorilla/sessions v1.2.2 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grafana/pyroscope-go v1.1.1 // indirect
- github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // indirect
+ github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/graph-gophers/dataloader v5.0.0+incompatible // indirect
github.com/graph-gophers/graphql-go v1.3.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
@@ -213,7 +213,7 @@ require (
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/klauspost/compress v1.17.3 // indirect
+ github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
@@ -269,11 +269,12 @@ require (
github.com/sethvargo/go-retry v0.2.4 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/shirou/gopsutil/v3 v3.24.3 // indirect
- github.com/smartcontractkit/chain-selectors v1.0.10 // indirect
+ github.com/smartcontractkit/chain-selectors v1.0.21 // indirect
+ github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 // indirect
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 // indirect
- github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa // indirect
+ github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2 // indirect
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 // indirect
- github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e // indirect
+ github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f // indirect
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799 // 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
@@ -329,17 +330,17 @@ require (
go.uber.org/ratelimit v0.3.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/arch v0.8.0 // indirect
- golang.org/x/crypto v0.25.0 // indirect
- golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 // indirect
- golang.org/x/mod v0.19.0 // indirect
- golang.org/x/net v0.27.0 // indirect
+ golang.org/x/crypto v0.26.0 // indirect
+ golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
+ golang.org/x/mod v0.20.0 // indirect
+ golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
- golang.org/x/sync v0.7.0 // indirect
- golang.org/x/sys v0.22.0 // indirect
- golang.org/x/term v0.22.0 // indirect
- golang.org/x/text v0.16.0 // indirect
+ golang.org/x/sync v0.8.0 // indirect
+ golang.org/x/sys v0.23.0 // indirect
+ golang.org/x/term v0.23.0 // indirect
+ golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.23.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
diff --git a/core/scripts/go.sum b/core/scripts/go.sum
index f3276d5a623..217c2c19e28 100644
--- a/core/scripts/go.sum
+++ b/core/scripts/go.sum
@@ -147,8 +147,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
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/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o=
-github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc=
+github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
+github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4=
@@ -330,8 +330,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g=
-github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
+github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
@@ -667,8 +667,8 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ=
github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88=
-github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo=
-github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug=
github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4=
github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0=
@@ -872,8 +872,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
-github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
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=
@@ -1180,20 +1180,22 @@ 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/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/chain-selectors v1.0.21 h1:KCR9SA7PhOexaBzFieHoLv1WonwhVOPtOStpqTmLC4E=
+github.com/smartcontractkit/chain-selectors v1.0.21/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8=
github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM=
-github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1 h1:pdEpjgbZ5w/Sd5lzg/XiuC5gVyrmSovOo+3nUD46SP8=
-github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1/go.mod h1:Jg1sCTsbxg76YByI8ifpFby3FvVqISStHT8ypy9ocmY=
+github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 h1:LAgJTg9Yr/uCo2g7Krp88Dco2U45Y6sbJVl8uKoLkys=
+github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95/go.mod h1:/ZWraCBaDDgaIN1prixYcbVvIk/6HeED9+8zbWQ+TMo=
+github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5 h1:+XvRzgHlcaZYLMJ5HR3HzOjvXNmpVKQFZbuHZiRno68=
+github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5/go.mod h1:5rmU5YKBkIOwWkuNZi26sMXlBUBm6weBFXh+8BEEp2s=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 h1:NBQLtqk8zsyY4qTJs+NElI3aDFTcAo83JHvqD04EvB0=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45/go.mod h1:LV0h7QBQUpoC2UUi6TcUvcIFm1xjP/DtEcqV8+qeLUs=
-github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa h1:g75H8oh2ws52s8BekwvGQ9XvBVu3E7WM1rfiA0PN0zk=
-github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa/go.mod h1:wZvLHX/Sd9hskN51016cTFcT3G62KXVa6xbVDS7tRjc=
+github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2 h1:KH6tpCw5hu8u6UTtgll7a8mE4sIbHCbmtzHJdKuRwBw=
+github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2/go.mod h1:V/86loaFSH0dqqUEHqyXVbyNqDRSjvcf9BRomWFTljU=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 h1:BCHu4pNP6arrcHLEWx61XjLaonOd2coQNyL0NTUcaMc=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827/go.mod h1:OPX+wC2TWQsyLNpR7daMt2vMpmsNcoBxbZyGTHr6tiA=
-github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e h1:PzwzlHNv1YbJ6ZIdl/pIFRoOuOS4V4WLvjZvFUnZFL4=
-github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e/go.mod h1:hsFhop+SlQHKD+DEFjZrMJmbauT1A/wvtZIeeo4PxFU=
+github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f h1:b0Ifwk7eK3fwJ0R69Ovhv5XvZ1/TUAfHkU5Jp7wbNZ0=
+github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f/go.mod h1:Ml88TJTwZCj6yHDkAEN/EhxVutzSlk+kDZgfibRIqF0=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799 h1:HyLTySm7BR+oNfZqDTkVJ25wnmcTtxBBD31UkFL+kEM=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799/go.mod h1:UVFRacRkP7O7TQAzFmR52v5mUlxf+G1ovMlCQAB/cHU=
github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo=
@@ -1472,8 +1474,8 @@ golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0
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.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
-golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
-golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
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=
@@ -1484,8 +1486,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
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-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA=
-golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
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=
@@ -1513,8 +1515,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/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.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
-golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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=
@@ -1571,8 +1573,8 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
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.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
-golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
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=
@@ -1597,8 +1599,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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=
@@ -1684,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.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
-golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.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=
@@ -1693,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.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
-golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
+golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
+golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
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=
@@ -1707,8 +1709,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
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=
@@ -1780,8 +1782,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
-golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/core/scripts/keystone/.gitignore b/core/scripts/keystone/.gitignore
index 4af4a42a015..92bf9aabc58 100644
--- a/core/scripts/keystone/.gitignore
+++ b/core/scripts/keystone/.gitignore
@@ -3,3 +3,4 @@
!*-sample.sh
keystone
.cache/
+artefacts/
diff --git a/core/scripts/keystone/main.go b/core/scripts/keystone/main.go
index 571623578ac..3486830ca32 100644
--- a/core/scripts/keystone/main.go
+++ b/core/scripts/keystone/main.go
@@ -20,6 +20,8 @@ func main() {
src.NewGenerateCribClusterOverridesCommand(),
src.NewDeleteJobsCommand(),
src.NewDeployAndInitializeCapabilitiesRegistryCommand(),
+ src.NewDeployWorkflowsCommand(),
+ src.NewDeleteWorkflowsCommand(),
}
commandsList := func(commands []command) string {
diff --git a/core/scripts/keystone/src/01_deploy_contracts_cmd.go b/core/scripts/keystone/src/01_deploy_contracts_cmd.go
index 2ca60bdfaf2..b3049737956 100644
--- a/core/scripts/keystone/src/01_deploy_contracts_cmd.go
+++ b/core/scripts/keystone/src/01_deploy_contracts_cmd.go
@@ -52,8 +52,12 @@ func (g *deployContracts) Run(args []string) {
skipFunding := fs.Bool("skipfunding", false, "skip funding the transmitters")
onlySetConfig := fs.Bool("onlysetconfig", false, "set the config on the OCR3 contract without deploying the contracts or funding transmitters")
dryRun := fs.Bool("dryrun", false, "dry run, don't actually deploy the contracts and do not fund transmitters")
+ publicKeys := fs.String("publickeys", "", "Custom public keys json location")
+ nodeList := fs.String("nodes", "", "Custom node list location")
+ artefactsDir := fs.String("artefacts", "", "Custom artefacts directory location")
err := fs.Parse(args)
+
if err != nil ||
*ocrConfigFile == "" || ocrConfigFile == nil ||
*ethUrl == "" || ethUrl == nil ||
@@ -63,11 +67,21 @@ func (g *deployContracts) Run(args []string) {
os.Exit(1)
}
+ if *artefactsDir == "" {
+ *artefactsDir = defaultArtefactsDir
+ }
+ if *publicKeys == "" {
+ *publicKeys = defaultPublicKeys
+ }
+ if *nodeList == "" {
+ *nodeList = defaultNodeList
+ }
+
os.Setenv("ETH_URL", *ethUrl)
os.Setenv("ETH_CHAIN_ID", fmt.Sprintf("%d", *chainID))
os.Setenv("ACCOUNT_KEY", *accountKey)
- deploy(*ocrConfigFile, *skipFunding, *dryRun, *onlySetConfig)
+ deploy(*nodeList, *publicKeys, *ocrConfigFile, *skipFunding, *dryRun, *onlySetConfig, *artefactsDir)
}
// deploy does the following:
@@ -77,16 +91,20 @@ func (g *deployContracts) Run(args []string) {
// 4. Writes the deployed contract addresses to a file
// 5. Funds the transmitters
func deploy(
+ nodeList string,
+ publicKeys string,
configFile string,
skipFunding bool,
dryRun bool,
onlySetConfig bool,
+ artefacts string,
) {
env := helpers.SetupEnv(false)
ocrConfig := generateOCR3Config(
+ nodeList,
configFile,
env.ChainID,
- ".cache/PublicKeys.json",
+ publicKeys,
)
if dryRun {
@@ -96,11 +114,11 @@ func deploy(
if onlySetConfig {
fmt.Println("Skipping deployment of contracts and skipping funding transmitters, only setting config")
- setOCR3Config(env, ocrConfig)
+ setOCR3Config(env, ocrConfig, artefacts)
return
}
- if ContractsAlreadyDeployed() {
+ if ContractsAlreadyDeployed(artefacts) {
fmt.Println("Contracts already deployed")
return
}
@@ -118,10 +136,10 @@ func deploy(
jsonBytes, err := json.Marshal(contracts)
PanicErr(err)
- err = os.WriteFile(DeployedContractsFilePath(), jsonBytes, 0600)
+ err = os.WriteFile(DeployedContractsFilePath(artefacts), jsonBytes, 0600)
PanicErr(err)
- setOCR3Config(env, ocrConfig)
+ setOCR3Config(env, ocrConfig, artefacts)
if skipFunding {
fmt.Println("Skipping funding transmitters")
@@ -139,8 +157,9 @@ func deploy(
func setOCR3Config(
env helpers.Environment,
ocrConfig orc2drOracleConfig,
+ artefacts string,
) {
- loadedContracts, err := LoadDeployedContracts()
+ loadedContracts, err := LoadDeployedContracts(artefacts)
PanicErr(err)
ocrContract, err := ocr3_capability.NewOCR3Capability(loadedContracts.OCRContract, env.Ec)
@@ -161,16 +180,16 @@ func setOCR3Config(
loadedContracts.SetConfigTxBlock = receipt.BlockNumber.Uint64()
jsonBytes, err := json.Marshal(loadedContracts)
PanicErr(err)
- err = os.WriteFile(DeployedContractsFilePath(), jsonBytes, 0600)
+ err = os.WriteFile(DeployedContractsFilePath(artefacts), jsonBytes, 0600)
PanicErr(err)
}
-func LoadDeployedContracts() (deployedContracts, error) {
- if !ContractsAlreadyDeployed() {
+func LoadDeployedContracts(artefacts string) (deployedContracts, error) {
+ if !ContractsAlreadyDeployed(artefacts) {
return deployedContracts{}, fmt.Errorf("no deployed contracts found, run deploy first")
}
- jsonBytes, err := os.ReadFile(DeployedContractsFilePath())
+ jsonBytes, err := os.ReadFile(DeployedContractsFilePath(artefacts))
if err != nil {
return deployedContracts{}, err
}
@@ -180,13 +199,13 @@ func LoadDeployedContracts() (deployedContracts, error) {
return contracts, err
}
-func ContractsAlreadyDeployed() bool {
- _, err := os.Stat(DeployedContractsFilePath())
+func ContractsAlreadyDeployed(artefacts string) bool {
+ _, err := os.Stat(DeployedContractsFilePath(artefacts))
return err == nil
}
-func DeployedContractsFilePath() string {
- return filepath.Join(artefactsDir, deployedContractsJSON)
+func DeployedContractsFilePath(artefacts string) string {
+ return filepath.Join(artefacts, deployedContractsJSON)
}
func DeployForwarder(e helpers.Environment) *forwarder.KeystoneForwarder {
diff --git a/core/scripts/keystone/src/02_deploy_jobspecs_cmd.go b/core/scripts/keystone/src/02_deploy_jobspecs_cmd.go
index 5918650cf88..275943d6388 100644
--- a/core/scripts/keystone/src/02_deploy_jobspecs_cmd.go
+++ b/core/scripts/keystone/src/02_deploy_jobspecs_cmd.go
@@ -16,8 +16,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/cmd"
)
-type deployJobSpecs struct {
-}
+type deployJobSpecs struct{}
func NewDeployJobSpecsCommand() *deployJobSpecs {
return &deployJobSpecs{}
@@ -32,6 +31,11 @@ func (g *deployJobSpecs) Run(args []string) {
chainID := fs.Int64("chainid", 11155111, "chain id")
p2pPort := fs.Int64("p2pport", 6690, "p2p port")
onlyReplay := fs.Bool("onlyreplay", false, "only replay the block from the OCR3 contract setConfig transaction")
+ templatesLocation := fs.String("templates", "", "Custom templates location")
+ nodeList := fs.String("nodes", "", "Custom node list location")
+ publicKeys := fs.String("publickeys", "", "Custom public keys json location")
+ artefactsDir := fs.String("artefacts", "", "Custom artefacts directory location")
+
err := fs.Parse(args)
if err != nil || chainID == nil || *chainID == 0 || p2pPort == nil || *p2pPort == 0 || onlyReplay == nil {
fs.Usage()
@@ -43,12 +47,27 @@ func (g *deployJobSpecs) Run(args []string) {
fmt.Println("Deploying OCR3 job specs")
}
- nodes := downloadNodeAPICredentialsDefault()
- deployedContracts, err := LoadDeployedContracts()
+ if *artefactsDir == "" {
+ *artefactsDir = defaultArtefactsDir
+ }
+ if *publicKeys == "" {
+ *publicKeys = defaultPublicKeys
+ }
+ if *nodeList == "" {
+ *nodeList = defaultNodeList
+ }
+ if *templatesLocation == "" {
+ *templatesLocation = "templates"
+ }
+
+ nodes := downloadNodeAPICredentials(*nodeList)
+ deployedContracts, err := LoadDeployedContracts(*artefactsDir)
PanicErr(err)
jobspecs := genSpecs(
- ".cache/PublicKeys.json", ".cache/NodeList.txt", "templates",
+ *publicKeys,
+ *nodeList,
+ *templatesLocation,
*chainID, *p2pPort, deployedContracts.OCRContract.Hex(),
)
flattenedSpecs := []hostSpec{jobspecs.bootstrap}
diff --git a/core/scripts/keystone/src/03_gen_crib_cluster_overrides_cmd.go b/core/scripts/keystone/src/03_gen_crib_cluster_overrides_cmd.go
index cb3acf903b3..6b98951459e 100644
--- a/core/scripts/keystone/src/03_gen_crib_cluster_overrides_cmd.go
+++ b/core/scripts/keystone/src/03_gen_crib_cluster_overrides_cmd.go
@@ -9,8 +9,7 @@ import (
helpers "github.com/smartcontractkit/chainlink/core/scripts/common"
)
-type generateCribClusterOverrides struct {
-}
+type generateCribClusterOverrides struct{}
func NewGenerateCribClusterOverridesCommand() *generateCribClusterOverrides {
return &generateCribClusterOverrides{}
@@ -24,25 +23,39 @@ func (g *generateCribClusterOverrides) Run(args []string) {
fs := flag.NewFlagSet(g.Name(), flag.ContinueOnError)
chainID := fs.Int64("chainid", 11155111, "chain id")
outputPath := fs.String("outpath", "../crib", "the path to output the generated overrides")
+ publicKeys := fs.String("publickeys", "", "Custom public keys json location")
+ nodeList := fs.String("nodes", "", "Custom node list location")
+ artefactsDir := fs.String("artefacts", "", "Custom artefacts directory location")
- deployedContracts, err := LoadDeployedContracts()
- helpers.PanicErr(err)
templatesDir := "templates"
- err = fs.Parse(args)
+ err := fs.Parse(args)
if err != nil || outputPath == nil || *outputPath == "" || chainID == nil || *chainID == 0 {
fs.Usage()
os.Exit(1)
}
- lines := generateCribConfig(".cache/PublicKeys.json", chainID, templatesDir, deployedContracts.ForwarderContract.Hex())
+ if *artefactsDir == "" {
+ *artefactsDir = defaultArtefactsDir
+ }
+ if *publicKeys == "" {
+ *publicKeys = defaultPublicKeys
+ }
+ if *nodeList == "" {
+ *nodeList = defaultNodeList
+ }
+
+ deployedContracts, err := LoadDeployedContracts(*artefactsDir)
+ helpers.PanicErr(err)
+
+ lines := generateCribConfig(*nodeList, *publicKeys, chainID, templatesDir, deployedContracts.ForwarderContract.Hex())
cribOverridesStr := strings.Join(lines, "\n")
err = os.WriteFile(filepath.Join(*outputPath, "crib-cluster-overrides.yaml"), []byte(cribOverridesStr), 0600)
helpers.PanicErr(err)
}
-func generateCribConfig(pubKeysPath string, chainID *int64, templatesDir string, forwarderAddress string) []string {
- nca := downloadNodePubKeys(*chainID, pubKeysPath)
+func generateCribConfig(nodeList string, pubKeysPath string, chainID *int64, templatesDir string, forwarderAddress string) []string {
+ nca := downloadNodePubKeys(nodeList, *chainID, pubKeysPath)
nodeAddresses := []string{}
for _, node := range nca[1:] {
diff --git a/core/scripts/keystone/src/03_gen_crib_cluster_overrides_cmd_test.go b/core/scripts/keystone/src/03_gen_crib_cluster_overrides_cmd_test.go
index 722b01e91c3..53d43c2342f 100644
--- a/core/scripts/keystone/src/03_gen_crib_cluster_overrides_cmd_test.go
+++ b/core/scripts/keystone/src/03_gen_crib_cluster_overrides_cmd_test.go
@@ -13,7 +13,7 @@ func TestGenerateCribConfig(t *testing.T) {
forwarderAddress := "0x1234567890abcdef"
publicKeysPath := "./testdata/PublicKeys.json"
- lines := generateCribConfig(publicKeysPath, &chainID, templatesDir, forwarderAddress)
+ lines := generateCribConfig(defaultNodeList, publicKeysPath, &chainID, templatesDir, forwarderAddress)
snaps.MatchSnapshot(t, strings.Join(lines, "\n"))
}
diff --git a/core/scripts/keystone/src/04_delete_ocr3_jobs_cmd.go b/core/scripts/keystone/src/04_delete_ocr3_jobs_cmd.go
index 2ebed000ed4..136691962dd 100644
--- a/core/scripts/keystone/src/04_delete_ocr3_jobs_cmd.go
+++ b/core/scripts/keystone/src/04_delete_ocr3_jobs_cmd.go
@@ -5,14 +5,14 @@ import (
"encoding/json"
"flag"
"fmt"
+ "os"
"github.com/urfave/cli"
helpers "github.com/smartcontractkit/chainlink/core/scripts/common"
)
-type deleteJobs struct {
-}
+type deleteJobs struct{}
type OCRSpec struct {
ContractID string
@@ -22,11 +22,16 @@ type BootSpec struct {
ContractID string
}
+type WorkflowSpec struct {
+ WorkflowID string
+}
+
type JobSpec struct {
Id string
Name string
BootstrapSpec BootSpec
OffChainReporting2OracleSpec OCRSpec
+ WorkflowSpec WorkflowSpec
}
func NewDeleteJobsCommand() *deleteJobs {
@@ -38,9 +43,26 @@ func (g *deleteJobs) Name() string {
}
func (g *deleteJobs) Run(args []string) {
- deployedContracts, err := LoadDeployedContracts()
+ fs := flag.NewFlagSet(g.Name(), flag.ContinueOnError)
+ nodeList := fs.String("nodes", "", "Custom node list location")
+ artefactsDir := fs.String("artefacts", "", "Custom artefacts directory location")
+
+ err := fs.Parse(args)
+ if err != nil {
+ fs.Usage()
+ os.Exit(1)
+ }
+
+ if *artefactsDir == "" {
+ *artefactsDir = defaultArtefactsDir
+ }
+ if *nodeList == "" {
+ *nodeList = defaultNodeList
+ }
+
+ deployedContracts, err := LoadDeployedContracts(*artefactsDir)
helpers.PanicErr(err)
- nodes := downloadNodeAPICredentialsDefault()
+ nodes := downloadNodeAPICredentials(*nodeList)
for _, node := range nodes {
output := &bytes.Buffer{}
diff --git a/core/scripts/keystone/src/05_deploy_initialize_capabilities_registry.go b/core/scripts/keystone/src/05_deploy_initialize_capabilities_registry.go
index 87622415430..3352267d149 100644
--- a/core/scripts/keystone/src/05_deploy_initialize_capabilities_registry.go
+++ b/core/scripts/keystone/src/05_deploy_initialize_capabilities_registry.go
@@ -11,10 +11,11 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
- ragetypes "github.com/smartcontractkit/libocr/ragep2p/types"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
+ ragetypes "github.com/smartcontractkit/libocr/ragep2p/types"
+
capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink-common/pkg/values"
@@ -373,8 +374,14 @@ func (c *deployAndInitializeCapabilitiesRegistryCommand) Run(args []string) {
panic(err)
}
- cc = newCapabilityConfig()
- ccb, err = proto.Marshal(cc)
+ targetCapabilityConfig := newCapabilityConfig()
+ targetCapabilityConfig.RemoteConfig = &capabilitiespb.CapabilityConfig_RemoteTargetConfig{
+ RemoteTargetConfig: &capabilitiespb.RemoteTargetConfig{
+ RequestHashExcludedAttributes: []string{"signed_report.Signatures"},
+ },
+ }
+
+ remoteTargetConfigBytes, err := proto.Marshal(targetCapabilityConfig)
if err != nil {
panic(err)
}
@@ -382,7 +389,7 @@ func (c *deployAndInitializeCapabilitiesRegistryCommand) Run(args []string) {
cfgs = []kcr.CapabilitiesRegistryCapabilityConfiguration{
{
CapabilityId: wid,
- Config: ccb,
+ Config: remoteTargetConfigBytes,
},
}
_, err = reg.AddDON(env.Owner, ps, cfgs, true, false, 1)
diff --git a/core/scripts/keystone/src/06_deploy_workflows_cmd.go b/core/scripts/keystone/src/06_deploy_workflows_cmd.go
new file mode 100644
index 00000000000..0ca8e5d4a7b
--- /dev/null
+++ b/core/scripts/keystone/src/06_deploy_workflows_cmd.go
@@ -0,0 +1,71 @@
+package src
+
+import (
+ "bytes"
+ "errors"
+ "flag"
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+
+ helpers "github.com/smartcontractkit/chainlink/core/scripts/common"
+)
+
+type deployWorkflows struct{}
+
+func NewDeployWorkflowsCommand() *deployWorkflows {
+ return &deployWorkflows{}
+}
+
+func (g *deployWorkflows) Name() string {
+ return "deploy-workflows"
+}
+
+func (g *deployWorkflows) Run(args []string) {
+ fs := flag.NewFlagSet(g.Name(), flag.ContinueOnError)
+ workflowFile := fs.String("workflow", "workflow.yml", "path to workflow file")
+ nodeList := fs.String("nodes", "", "Custom node list location")
+ err := fs.Parse(args)
+ if err != nil || workflowFile == nil || *workflowFile == "" {
+ fs.Usage()
+ os.Exit(1)
+ }
+ if *nodeList == "" {
+ *nodeList = defaultNodeList
+ }
+ fmt.Println("Deploying workflows")
+
+ // use a separate list
+ nodes := downloadNodeAPICredentials(*nodeList)
+
+ if _, err = os.Stat(*workflowFile); err != nil {
+ PanicErr(errors.New("toml file does not exist"))
+ }
+
+ for i, n := range nodes {
+ if i == 0 {
+ continue // skip bootstrap node
+ }
+ output := &bytes.Buffer{}
+ client, app := newApp(n, output)
+ fmt.Println("Logging in:", n.url)
+ loginFs := flag.NewFlagSet("test", flag.ContinueOnError)
+ loginFs.Bool("bypass-version-check", true, "")
+ loginCtx := cli.NewContext(app, loginFs, nil)
+ err := client.RemoteLogin(loginCtx)
+ helpers.PanicErr(err)
+ output.Reset()
+
+ fmt.Printf("Deploying workflow\n... \n")
+ fs := flag.NewFlagSet("test", flag.ExitOnError)
+ err = fs.Parse([]string{*workflowFile})
+
+ helpers.PanicErr(err)
+ err = client.CreateJob(cli.NewContext(app, fs, nil))
+ if err != nil {
+ fmt.Println("Failed to deploy workflow:", "Error:", err)
+ }
+ output.Reset()
+ }
+}
diff --git a/core/scripts/keystone/src/07_delete_workflows_cmd.go b/core/scripts/keystone/src/07_delete_workflows_cmd.go
new file mode 100644
index 00000000000..cccedaf9e70
--- /dev/null
+++ b/core/scripts/keystone/src/07_delete_workflows_cmd.go
@@ -0,0 +1,74 @@
+package src
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "os"
+
+ "github.com/urfave/cli"
+
+ helpers "github.com/smartcontractkit/chainlink/core/scripts/common"
+)
+
+type deleteWorkflows struct{}
+
+func NewDeleteWorkflowsCommand() *deleteWorkflows {
+ return &deleteWorkflows{}
+}
+
+func (g *deleteWorkflows) Name() string {
+ return "delete-workflows"
+}
+
+func (g *deleteWorkflows) Run(args []string) {
+ fs := flag.NewFlagSet(g.Name(), flag.ExitOnError)
+ nodeList := fs.String("nodes", "", "Custom node list location")
+
+ err := fs.Parse(args)
+ if err != nil {
+ fs.Usage()
+ os.Exit(1)
+ }
+
+ if *nodeList == "" {
+ *nodeList = defaultNodeList
+ }
+
+ nodes := downloadNodeAPICredentials(*nodeList)
+
+ for _, node := range nodes {
+ output := &bytes.Buffer{}
+ client, app := newApp(node, output)
+
+ fmt.Println("Logging in:", node.url)
+ loginFs := flag.NewFlagSet("test", flag.ContinueOnError)
+ loginFs.Bool("bypass-version-check", true, "")
+ loginCtx := cli.NewContext(app, loginFs, nil)
+ err := client.RemoteLogin(loginCtx)
+ helpers.PanicErr(err)
+ output.Reset()
+
+ fileFs := flag.NewFlagSet("test", flag.ExitOnError)
+ err = client.ListJobs(cli.NewContext(app, fileFs, nil))
+ helpers.PanicErr(err)
+
+ var parsed []JobSpec
+ err = json.Unmarshal(output.Bytes(), &parsed)
+ helpers.PanicErr(err)
+
+ for _, jobSpec := range parsed {
+ if jobSpec.WorkflowSpec.WorkflowID != "" {
+ fmt.Println("Deleting workflow job ID:", jobSpec.Id, "name:", jobSpec.Name)
+ set := flag.NewFlagSet("test", flag.ExitOnError)
+ err = set.Parse([]string{jobSpec.Id})
+ helpers.PanicErr(err)
+ err = client.DeleteJob(cli.NewContext(app, set, nil))
+ helpers.PanicErr(err)
+ }
+ }
+
+ output.Reset()
+ }
+}
diff --git a/core/scripts/keystone/src/88_gen_jobspecs.go b/core/scripts/keystone/src/88_gen_jobspecs.go
index 6a9c911a5f5..5f0b9097d2f 100644
--- a/core/scripts/keystone/src/88_gen_jobspecs.go
+++ b/core/scripts/keystone/src/88_gen_jobspecs.go
@@ -34,12 +34,12 @@ func genSpecs(
ocrConfigContractAddress string,
) donHostSpec {
nodes := downloadNodeAPICredentials(nodeListPath)
- nca := downloadNodePubKeys(chainID, pubkeysPath)
+ nca := downloadNodePubKeys(nodeListPath, chainID, pubkeysPath)
bootstrapNode := nca[0]
bootstrapSpecLines, err := readLines(filepath.Join(templatesDir, bootstrapSpecTemplate))
helpers.PanicErr(err)
- bootHost := nodes[0].url.Host
+ bootHost := nodes[0].url.Hostname()
bootstrapSpecLines = replacePlaceholders(
bootstrapSpecLines,
chainID, p2pPort,
diff --git a/core/scripts/keystone/src/88_gen_ocr3_config.go b/core/scripts/keystone/src/88_gen_ocr3_config.go
index fe9241a2bde..1107df57ca1 100644
--- a/core/scripts/keystone/src/88_gen_ocr3_config.go
+++ b/core/scripts/keystone/src/88_gen_ocr3_config.go
@@ -96,10 +96,10 @@ func mustReadConfig(fileName string) (output TopLevelConfigSource) {
return mustParseJSON[TopLevelConfigSource](fileName)
}
-func generateOCR3Config(configFile string, chainID int64, pubKeysPath string) orc2drOracleConfig {
+func generateOCR3Config(nodeList string, configFile string, chainID int64, pubKeysPath string) orc2drOracleConfig {
topLevelCfg := mustReadConfig(configFile)
cfg := topLevelCfg.OracleConfig
- nca := downloadNodePubKeys(chainID, pubKeysPath)
+ nca := downloadNodePubKeys(nodeList, chainID, pubKeysPath)
onchainPubKeys := []common.Address{}
for _, n := range nca {
diff --git a/core/scripts/keystone/src/88_gen_ocr3_config_test.go b/core/scripts/keystone/src/88_gen_ocr3_config_test.go
index 185354ec2fe..10cdc07b204 100644
--- a/core/scripts/keystone/src/88_gen_ocr3_config_test.go
+++ b/core/scripts/keystone/src/88_gen_ocr3_config_test.go
@@ -10,7 +10,7 @@ import (
func TestGenerateOCR3Config(t *testing.T) {
// Generate OCR3 config
- config := generateOCR3Config("./testdata/SampleConfig.json", 11155111, "./testdata/PublicKeys.json")
+ config := generateOCR3Config(".cache/NodeList.txt", "./testdata/SampleConfig.json", 11155111, "./testdata/PublicKeys.json")
matchOffchainConfig := match.Custom("OffchainConfig", func(s any) (any, error) {
// coerce the value to a string
diff --git a/core/scripts/keystone/src/99_fetch_keys.go b/core/scripts/keystone/src/99_fetch_keys.go
index 4fcb6f138a7..b115a7bb94d 100644
--- a/core/scripts/keystone/src/99_fetch_keys.go
+++ b/core/scripts/keystone/src/99_fetch_keys.go
@@ -17,14 +17,14 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/web/presenters"
)
-func downloadNodePubKeys(chainID int64, pubKeysPath string) []NodeKeys {
+func downloadNodePubKeys(nodeList string, chainID int64, pubKeysPath string) []NodeKeys {
// Check if file exists already, and if so, return the keys
if _, err := os.Stat(pubKeysPath); err == nil {
fmt.Println("Loading existing public keys at:", pubKeysPath)
return mustParseJSON[[]NodeKeys](pubKeysPath)
}
- nodes := downloadNodeAPICredentialsDefault()
+ nodes := downloadNodeAPICredentials(nodeList)
nodesKeys := mustFetchNodesKeys(chainID, nodes)
marshalledNodeKeys, err := json.MarshalIndent(nodesKeys, "", " ")
@@ -40,13 +40,6 @@ func downloadNodePubKeys(chainID int64, pubKeysPath string) []NodeKeys {
return nodesKeys
}
-// downloadNodeAPICredentialsDefault downloads the node API credentials, or loads them from disk if they already exist
-//
-// The nodes are sorted by URL. In the case of crib, the bootstrap node is the first node in the list.
-func downloadNodeAPICredentialsDefault() []*node {
- return downloadNodeAPICredentials(".cache/NodeList.txt")
-}
-
// downloadNodeAPICredentials downloads the node API credentials, or loads them from disk if they already exist
//
// The nodes are sorted by URL. In the case of crib, the bootstrap node is the first node in the list.
diff --git a/core/scripts/keystone/src/99_files.go b/core/scripts/keystone/src/99_files.go
index d334b0fd56c..08ba12e4194 100644
--- a/core/scripts/keystone/src/99_files.go
+++ b/core/scripts/keystone/src/99_files.go
@@ -11,7 +11,9 @@ import (
)
const (
- artefactsDir = "artefacts"
+ defaultArtefactsDir = "artefacts"
+ defaultPublicKeys = ".cache/PublicKeys.json"
+ defaultNodeList = ".cache/NodeList.txt"
deployedContractsJSON = "deployed_contracts.json"
bootstrapSpecTemplate = "bootstrap.toml"
cribOverrideTemplate = "crib-overrides.yaml"
diff --git a/core/scripts/keystone/src/__snapshots__/88_gen_jobspecs_test.snap b/core/scripts/keystone/src/__snapshots__/88_gen_jobspecs_test.snap
index 1ee7f678945..a4b4e6e3021 100755
--- a/core/scripts/keystone/src/__snapshots__/88_gen_jobspecs_test.snap
+++ b/core/scripts/keystone/src/__snapshots__/88_gen_jobspecs_test.snap
@@ -33,13 +33,12 @@ chainID = "11155111"
command = "chainlink-ocr3-capability"
ocrVersion = 3
pluginName = "ocr-capability"
-providerType = "plugin"
+providerType = "ocr3-capability"
telemetryType = "plugin"
[onchainSigningStrategy]
strategyName = 'single-chain'
[onchainSigningStrategy.config]
-publicKey = '8fa807463ad73f9ee855cfd60ba406dcf98a2855b3dd8af613107b0f6890a707'
--------------------------------
Oracle 1:
@@ -63,13 +62,12 @@ chainID = "11155111"
command = "chainlink-ocr3-capability"
ocrVersion = 3
pluginName = "ocr-capability"
-providerType = "plugin"
+providerType = "ocr3-capability"
telemetryType = "plugin"
[onchainSigningStrategy]
strategyName = 'single-chain'
[onchainSigningStrategy.config]
-publicKey = '8fa807463ad73f9ee855cfd60ba406dcf98a2855b3dd8af613107b0f6890a707'
--------------------------------
Oracle 2:
@@ -93,13 +91,12 @@ chainID = "11155111"
command = "chainlink-ocr3-capability"
ocrVersion = 3
pluginName = "ocr-capability"
-providerType = "plugin"
+providerType = "ocr3-capability"
telemetryType = "plugin"
[onchainSigningStrategy]
strategyName = 'single-chain'
[onchainSigningStrategy.config]
-publicKey = '8fa807463ad73f9ee855cfd60ba406dcf98a2855b3dd8af613107b0f6890a707'
--------------------------------
Oracle 3:
@@ -123,13 +120,12 @@ chainID = "11155111"
command = "chainlink-ocr3-capability"
ocrVersion = 3
pluginName = "ocr-capability"
-providerType = "plugin"
+providerType = "ocr3-capability"
telemetryType = "plugin"
[onchainSigningStrategy]
strategyName = 'single-chain'
[onchainSigningStrategy.config]
-publicKey = '8fa807463ad73f9ee855cfd60ba406dcf98a2855b3dd8af613107b0f6890a707'
---
diff --git a/core/scripts/keystone/templates/oracle.toml b/core/scripts/keystone/templates/oracle.toml
index f2ff87de923..6049ad925d4 100644
--- a/core/scripts/keystone/templates/oracle.toml
+++ b/core/scripts/keystone/templates/oracle.toml
@@ -17,10 +17,9 @@ chainID = "{{ chain_id }}"
command = "chainlink-ocr3-capability"
ocrVersion = 3
pluginName = "ocr-capability"
-providerType = "plugin"
+providerType = "ocr3-capability"
telemetryType = "plugin"
[onchainSigningStrategy]
strategyName = 'single-chain'
[onchainSigningStrategy.config]
-publicKey = '8fa807463ad73f9ee855cfd60ba406dcf98a2855b3dd8af613107b0f6890a707'
diff --git a/core/services/ccip/mocks/orm.go b/core/services/ccip/mocks/orm.go
index 8a987c21602..0c9086def7e 100644
--- a/core/services/ccip/mocks/orm.go
+++ b/core/services/ccip/mocks/orm.go
@@ -8,6 +8,8 @@ import (
ccip "github.com/smartcontractkit/chainlink/v2/core/services/ccip"
mock "github.com/stretchr/testify/mock"
+
+ time "time"
)
// ORM is an autogenerated mock type for the ORM type
@@ -23,102 +25,6 @@ func (_m *ORM) EXPECT() *ORM_Expecter {
return &ORM_Expecter{mock: &_m.Mock}
}
-// ClearGasPricesByDestChain provides a mock function with given fields: ctx, destChainSelector, expireSec
-func (_m *ORM) ClearGasPricesByDestChain(ctx context.Context, destChainSelector uint64, expireSec int) error {
- ret := _m.Called(ctx, destChainSelector, expireSec)
-
- if len(ret) == 0 {
- panic("no return value specified for ClearGasPricesByDestChain")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, uint64, int) error); ok {
- r0 = rf(ctx, destChainSelector, expireSec)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// ORM_ClearGasPricesByDestChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearGasPricesByDestChain'
-type ORM_ClearGasPricesByDestChain_Call struct {
- *mock.Call
-}
-
-// ClearGasPricesByDestChain is a helper method to define mock.On call
-// - ctx context.Context
-// - destChainSelector uint64
-// - expireSec int
-func (_e *ORM_Expecter) ClearGasPricesByDestChain(ctx interface{}, destChainSelector interface{}, expireSec interface{}) *ORM_ClearGasPricesByDestChain_Call {
- return &ORM_ClearGasPricesByDestChain_Call{Call: _e.mock.On("ClearGasPricesByDestChain", ctx, destChainSelector, expireSec)}
-}
-
-func (_c *ORM_ClearGasPricesByDestChain_Call) Run(run func(ctx context.Context, destChainSelector uint64, expireSec int)) *ORM_ClearGasPricesByDestChain_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(uint64), args[2].(int))
- })
- return _c
-}
-
-func (_c *ORM_ClearGasPricesByDestChain_Call) Return(_a0 error) *ORM_ClearGasPricesByDestChain_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *ORM_ClearGasPricesByDestChain_Call) RunAndReturn(run func(context.Context, uint64, int) error) *ORM_ClearGasPricesByDestChain_Call {
- _c.Call.Return(run)
- return _c
-}
-
-// ClearTokenPricesByDestChain provides a mock function with given fields: ctx, destChainSelector, expireSec
-func (_m *ORM) ClearTokenPricesByDestChain(ctx context.Context, destChainSelector uint64, expireSec int) error {
- ret := _m.Called(ctx, destChainSelector, expireSec)
-
- if len(ret) == 0 {
- panic("no return value specified for ClearTokenPricesByDestChain")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, uint64, int) error); ok {
- r0 = rf(ctx, destChainSelector, expireSec)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// ORM_ClearTokenPricesByDestChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearTokenPricesByDestChain'
-type ORM_ClearTokenPricesByDestChain_Call struct {
- *mock.Call
-}
-
-// ClearTokenPricesByDestChain is a helper method to define mock.On call
-// - ctx context.Context
-// - destChainSelector uint64
-// - expireSec int
-func (_e *ORM_Expecter) ClearTokenPricesByDestChain(ctx interface{}, destChainSelector interface{}, expireSec interface{}) *ORM_ClearTokenPricesByDestChain_Call {
- return &ORM_ClearTokenPricesByDestChain_Call{Call: _e.mock.On("ClearTokenPricesByDestChain", ctx, destChainSelector, expireSec)}
-}
-
-func (_c *ORM_ClearTokenPricesByDestChain_Call) Run(run func(ctx context.Context, destChainSelector uint64, expireSec int)) *ORM_ClearTokenPricesByDestChain_Call {
- _c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(uint64), args[2].(int))
- })
- return _c
-}
-
-func (_c *ORM_ClearTokenPricesByDestChain_Call) Return(_a0 error) *ORM_ClearTokenPricesByDestChain_Call {
- _c.Call.Return(_a0)
- return _c
-}
-
-func (_c *ORM_ClearTokenPricesByDestChain_Call) RunAndReturn(run func(context.Context, uint64, int) error) *ORM_ClearTokenPricesByDestChain_Call {
- _c.Call.Return(run)
- return _c
-}
-
// GetGasPricesByDestChain provides a mock function with given fields: ctx, destChainSelector
func (_m *ORM) GetGasPricesByDestChain(ctx context.Context, destChainSelector uint64) ([]ccip.GasPrice, error) {
ret := _m.Called(ctx, destChainSelector)
@@ -237,100 +143,119 @@ func (_c *ORM_GetTokenPricesByDestChain_Call) RunAndReturn(run func(context.Cont
return _c
}
-// InsertGasPricesForDestChain provides a mock function with given fields: ctx, destChainSelector, jobId, gasPrices
-func (_m *ORM) InsertGasPricesForDestChain(ctx context.Context, destChainSelector uint64, jobId int32, gasPrices []ccip.GasPriceUpdate) error {
- ret := _m.Called(ctx, destChainSelector, jobId, gasPrices)
+// UpsertGasPricesForDestChain provides a mock function with given fields: ctx, destChainSelector, gasPrices
+func (_m *ORM) UpsertGasPricesForDestChain(ctx context.Context, destChainSelector uint64, gasPrices []ccip.GasPrice) (int64, error) {
+ ret := _m.Called(ctx, destChainSelector, gasPrices)
if len(ret) == 0 {
- panic("no return value specified for InsertGasPricesForDestChain")
+ panic("no return value specified for UpsertGasPricesForDestChain")
}
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, uint64, int32, []ccip.GasPriceUpdate) error); ok {
- r0 = rf(ctx, destChainSelector, jobId, gasPrices)
+ var r0 int64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, []ccip.GasPrice) (int64, error)); ok {
+ return rf(ctx, destChainSelector, gasPrices)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, []ccip.GasPrice) int64); ok {
+ r0 = rf(ctx, destChainSelector, gasPrices)
} else {
- r0 = ret.Error(0)
+ r0 = ret.Get(0).(int64)
}
- return r0
+ if rf, ok := ret.Get(1).(func(context.Context, uint64, []ccip.GasPrice) error); ok {
+ r1 = rf(ctx, destChainSelector, gasPrices)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
}
-// ORM_InsertGasPricesForDestChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InsertGasPricesForDestChain'
-type ORM_InsertGasPricesForDestChain_Call struct {
+// ORM_UpsertGasPricesForDestChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpsertGasPricesForDestChain'
+type ORM_UpsertGasPricesForDestChain_Call struct {
*mock.Call
}
-// InsertGasPricesForDestChain is a helper method to define mock.On call
+// UpsertGasPricesForDestChain is a helper method to define mock.On call
// - ctx context.Context
// - destChainSelector uint64
-// - jobId int32
-// - gasPrices []ccip.GasPriceUpdate
-func (_e *ORM_Expecter) InsertGasPricesForDestChain(ctx interface{}, destChainSelector interface{}, jobId interface{}, gasPrices interface{}) *ORM_InsertGasPricesForDestChain_Call {
- return &ORM_InsertGasPricesForDestChain_Call{Call: _e.mock.On("InsertGasPricesForDestChain", ctx, destChainSelector, jobId, gasPrices)}
+// - gasPrices []ccip.GasPrice
+func (_e *ORM_Expecter) UpsertGasPricesForDestChain(ctx interface{}, destChainSelector interface{}, gasPrices interface{}) *ORM_UpsertGasPricesForDestChain_Call {
+ return &ORM_UpsertGasPricesForDestChain_Call{Call: _e.mock.On("UpsertGasPricesForDestChain", ctx, destChainSelector, gasPrices)}
}
-func (_c *ORM_InsertGasPricesForDestChain_Call) Run(run func(ctx context.Context, destChainSelector uint64, jobId int32, gasPrices []ccip.GasPriceUpdate)) *ORM_InsertGasPricesForDestChain_Call {
+func (_c *ORM_UpsertGasPricesForDestChain_Call) Run(run func(ctx context.Context, destChainSelector uint64, gasPrices []ccip.GasPrice)) *ORM_UpsertGasPricesForDestChain_Call {
_c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(uint64), args[2].(int32), args[3].([]ccip.GasPriceUpdate))
+ run(args[0].(context.Context), args[1].(uint64), args[2].([]ccip.GasPrice))
})
return _c
}
-func (_c *ORM_InsertGasPricesForDestChain_Call) Return(_a0 error) *ORM_InsertGasPricesForDestChain_Call {
- _c.Call.Return(_a0)
+func (_c *ORM_UpsertGasPricesForDestChain_Call) Return(_a0 int64, _a1 error) *ORM_UpsertGasPricesForDestChain_Call {
+ _c.Call.Return(_a0, _a1)
return _c
}
-func (_c *ORM_InsertGasPricesForDestChain_Call) RunAndReturn(run func(context.Context, uint64, int32, []ccip.GasPriceUpdate) error) *ORM_InsertGasPricesForDestChain_Call {
+func (_c *ORM_UpsertGasPricesForDestChain_Call) RunAndReturn(run func(context.Context, uint64, []ccip.GasPrice) (int64, error)) *ORM_UpsertGasPricesForDestChain_Call {
_c.Call.Return(run)
return _c
}
-// InsertTokenPricesForDestChain provides a mock function with given fields: ctx, destChainSelector, jobId, tokenPrices
-func (_m *ORM) InsertTokenPricesForDestChain(ctx context.Context, destChainSelector uint64, jobId int32, tokenPrices []ccip.TokenPriceUpdate) error {
- ret := _m.Called(ctx, destChainSelector, jobId, tokenPrices)
+// UpsertTokenPricesForDestChain provides a mock function with given fields: ctx, destChainSelector, tokenPrices, interval
+func (_m *ORM) UpsertTokenPricesForDestChain(ctx context.Context, destChainSelector uint64, tokenPrices []ccip.TokenPrice, interval time.Duration) (int64, error) {
+ ret := _m.Called(ctx, destChainSelector, tokenPrices, interval)
if len(ret) == 0 {
- panic("no return value specified for InsertTokenPricesForDestChain")
+ panic("no return value specified for UpsertTokenPricesForDestChain")
}
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, uint64, int32, []ccip.TokenPriceUpdate) error); ok {
- r0 = rf(ctx, destChainSelector, jobId, tokenPrices)
+ var r0 int64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, []ccip.TokenPrice, time.Duration) (int64, error)); ok {
+ return rf(ctx, destChainSelector, tokenPrices, interval)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, []ccip.TokenPrice, time.Duration) int64); ok {
+ r0 = rf(ctx, destChainSelector, tokenPrices, interval)
} else {
- r0 = ret.Error(0)
+ r0 = ret.Get(0).(int64)
}
- return r0
+ if rf, ok := ret.Get(1).(func(context.Context, uint64, []ccip.TokenPrice, time.Duration) error); ok {
+ r1 = rf(ctx, destChainSelector, tokenPrices, interval)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
}
-// ORM_InsertTokenPricesForDestChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InsertTokenPricesForDestChain'
-type ORM_InsertTokenPricesForDestChain_Call struct {
+// ORM_UpsertTokenPricesForDestChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpsertTokenPricesForDestChain'
+type ORM_UpsertTokenPricesForDestChain_Call struct {
*mock.Call
}
-// InsertTokenPricesForDestChain is a helper method to define mock.On call
+// UpsertTokenPricesForDestChain is a helper method to define mock.On call
// - ctx context.Context
// - destChainSelector uint64
-// - jobId int32
-// - tokenPrices []ccip.TokenPriceUpdate
-func (_e *ORM_Expecter) InsertTokenPricesForDestChain(ctx interface{}, destChainSelector interface{}, jobId interface{}, tokenPrices interface{}) *ORM_InsertTokenPricesForDestChain_Call {
- return &ORM_InsertTokenPricesForDestChain_Call{Call: _e.mock.On("InsertTokenPricesForDestChain", ctx, destChainSelector, jobId, tokenPrices)}
+// - tokenPrices []ccip.TokenPrice
+// - interval time.Duration
+func (_e *ORM_Expecter) UpsertTokenPricesForDestChain(ctx interface{}, destChainSelector interface{}, tokenPrices interface{}, interval interface{}) *ORM_UpsertTokenPricesForDestChain_Call {
+ return &ORM_UpsertTokenPricesForDestChain_Call{Call: _e.mock.On("UpsertTokenPricesForDestChain", ctx, destChainSelector, tokenPrices, interval)}
}
-func (_c *ORM_InsertTokenPricesForDestChain_Call) Run(run func(ctx context.Context, destChainSelector uint64, jobId int32, tokenPrices []ccip.TokenPriceUpdate)) *ORM_InsertTokenPricesForDestChain_Call {
+func (_c *ORM_UpsertTokenPricesForDestChain_Call) Run(run func(ctx context.Context, destChainSelector uint64, tokenPrices []ccip.TokenPrice, interval time.Duration)) *ORM_UpsertTokenPricesForDestChain_Call {
_c.Call.Run(func(args mock.Arguments) {
- run(args[0].(context.Context), args[1].(uint64), args[2].(int32), args[3].([]ccip.TokenPriceUpdate))
+ run(args[0].(context.Context), args[1].(uint64), args[2].([]ccip.TokenPrice), args[3].(time.Duration))
})
return _c
}
-func (_c *ORM_InsertTokenPricesForDestChain_Call) Return(_a0 error) *ORM_InsertTokenPricesForDestChain_Call {
- _c.Call.Return(_a0)
+func (_c *ORM_UpsertTokenPricesForDestChain_Call) Return(_a0 int64, _a1 error) *ORM_UpsertTokenPricesForDestChain_Call {
+ _c.Call.Return(_a0, _a1)
return _c
}
-func (_c *ORM_InsertTokenPricesForDestChain_Call) RunAndReturn(run func(context.Context, uint64, int32, []ccip.TokenPriceUpdate) error) *ORM_InsertTokenPricesForDestChain_Call {
+func (_c *ORM_UpsertTokenPricesForDestChain_Call) RunAndReturn(run func(context.Context, uint64, []ccip.TokenPrice, time.Duration) (int64, error)) *ORM_UpsertTokenPricesForDestChain_Call {
_c.Call.Return(run)
return _c
}
diff --git a/core/services/ccip/observability.go b/core/services/ccip/observability.go
new file mode 100644
index 00000000000..8a061893ce6
--- /dev/null
+++ b/core/services/ccip/observability.go
@@ -0,0 +1,115 @@
+package ccip
+
+import (
+ "context"
+ "strconv"
+ "time"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+var (
+ sqlLatencyBuckets = []float64{
+ float64(10 * time.Millisecond),
+ float64(20 * time.Millisecond),
+ float64(30 * time.Millisecond),
+ float64(40 * time.Millisecond),
+ float64(50 * time.Millisecond),
+ float64(70 * time.Millisecond),
+ float64(90 * time.Millisecond),
+ float64(100 * time.Millisecond),
+ float64(200 * time.Millisecond),
+ float64(300 * time.Millisecond),
+ float64(400 * time.Millisecond),
+ float64(500 * time.Millisecond),
+ float64(750 * time.Millisecond),
+ float64(1 * time.Second),
+ }
+ ccipQueryDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Name: "ccip_orm_query_duration",
+ Buckets: sqlLatencyBuckets,
+ }, []string{"query", "destChainSelector"})
+ ccipQueryDatasets = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "ccip_orm_dataset_size",
+ }, []string{"query", "destChainSelector"})
+)
+
+type observedORM struct {
+ ORM
+ queryDuration *prometheus.HistogramVec
+ datasetSize *prometheus.GaugeVec
+}
+
+var _ ORM = (*observedORM)(nil)
+
+func NewObservedORM(ds sqlutil.DataSource, lggr logger.Logger) (*observedORM, error) {
+ delegate, err := NewORM(ds, lggr)
+ if err != nil {
+ return nil, err
+ }
+
+ return &observedORM{
+ ORM: delegate,
+ queryDuration: ccipQueryDuration,
+ datasetSize: ccipQueryDatasets,
+ }, nil
+}
+
+func (o *observedORM) GetGasPricesByDestChain(ctx context.Context, destChainSelector uint64) ([]GasPrice, error) {
+ return withObservedQueryAndResults(o, "GetGasPricesByDestChain", destChainSelector, func() ([]GasPrice, error) {
+ return o.ORM.GetGasPricesByDestChain(ctx, destChainSelector)
+ })
+}
+
+func (o *observedORM) GetTokenPricesByDestChain(ctx context.Context, destChainSelector uint64) ([]TokenPrice, error) {
+ return withObservedQueryAndResults(o, "GetTokenPricesByDestChain", destChainSelector, func() ([]TokenPrice, error) {
+ return o.ORM.GetTokenPricesByDestChain(ctx, destChainSelector)
+ })
+}
+
+func (o *observedORM) UpsertGasPricesForDestChain(ctx context.Context, destChainSelector uint64, gasPrices []GasPrice) (int64, error) {
+ return withObservedQueryAndRowsAffected(o, "UpsertGasPricesForDestChain", destChainSelector, func() (int64, error) {
+ return o.ORM.UpsertGasPricesForDestChain(ctx, destChainSelector, gasPrices)
+ })
+}
+
+func (o *observedORM) UpsertTokenPricesForDestChain(ctx context.Context, destChainSelector uint64, tokenPrices []TokenPrice, interval time.Duration) (int64, error) {
+ return withObservedQueryAndRowsAffected(o, "UpsertTokenPricesForDestChain", destChainSelector, func() (int64, error) {
+ return o.ORM.UpsertTokenPricesForDestChain(ctx, destChainSelector, tokenPrices, interval)
+ })
+}
+
+func withObservedQueryAndRowsAffected(o *observedORM, queryName string, chainSelector uint64, query func() (int64, error)) (int64, error) {
+ rowsAffected, err := withObservedQuery(o, queryName, chainSelector, query)
+ if err == nil {
+ o.datasetSize.
+ WithLabelValues(queryName, strconv.FormatUint(chainSelector, 10)).
+ Set(float64(rowsAffected))
+ }
+ return rowsAffected, err
+}
+
+func withObservedQueryAndResults[T any](o *observedORM, queryName string, chainSelector uint64, query func() ([]T, error)) ([]T, error) {
+ results, err := withObservedQuery(o, queryName, chainSelector, query)
+ if err == nil {
+ o.datasetSize.
+ WithLabelValues(queryName, strconv.FormatUint(chainSelector, 10)).
+ Set(float64(len(results)))
+ }
+ return results, err
+}
+
+func withObservedQuery[T any](o *observedORM, queryName string, chainSelector uint64, query func() (T, error)) (T, error) {
+ queryStarted := time.Now()
+ defer func() {
+ o.queryDuration.
+ WithLabelValues(queryName, strconv.FormatUint(chainSelector, 10)).
+ Observe(float64(time.Since(queryStarted)))
+ }()
+ return query()
+}
diff --git a/core/services/ccip/observability_test.go b/core/services/ccip/observability_test.go
new file mode 100644
index 00000000000..24bfb4a9ec1
--- /dev/null
+++ b/core/services/ccip/observability_test.go
@@ -0,0 +1,94 @@
+package ccip
+
+import (
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/testutil"
+ io_prometheus_client "github.com/prometheus/client_model/go"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+func Test_MetricsAreTrackedForAllMethods(t *testing.T) {
+ ctx := testutils.Context(t)
+ db := pgtest.NewSqlxDB(t)
+ ccipORM, err := NewObservedORM(db, logger.TestLogger(t))
+ require.NoError(t, err)
+
+ tokenPrices := []TokenPrice{
+ {
+ TokenAddr: "0xA",
+ TokenPrice: assets.NewWei(big.NewInt(1e18)),
+ },
+ {
+ TokenAddr: "0xB",
+ TokenPrice: assets.NewWei(big.NewInt(1e18)),
+ },
+ }
+ tokensUpserted, err := ccipORM.UpsertTokenPricesForDestChain(ctx, 100, tokenPrices, time.Second)
+ require.NoError(t, err)
+ assert.Equal(t, len(tokenPrices), int(tokensUpserted))
+ assert.Equal(t, len(tokenPrices), counterFromGaugeByLabels(ccipORM.datasetSize, "UpsertTokenPricesForDestChain", "100"))
+ assert.Equal(t, 0, counterFromGaugeByLabels(ccipORM.datasetSize, "UpsertTokenPricesForDestChain", "200"))
+
+ tokens, err := ccipORM.GetTokenPricesByDestChain(ctx, 100)
+ require.NoError(t, err)
+ assert.Equal(t, len(tokenPrices), len(tokens))
+ assert.Equal(t, len(tokenPrices), counterFromGaugeByLabels(ccipORM.datasetSize, "GetTokenPricesByDestChain", "100"))
+ assert.Equal(t, 1, counterFromHistogramByLabels(t, ccipORM.queryDuration, "GetTokenPricesByDestChain", "100"))
+
+ gasPrices := []GasPrice{
+ {
+ SourceChainSelector: 200,
+ GasPrice: assets.NewWei(big.NewInt(1e18)),
+ },
+ {
+ SourceChainSelector: 201,
+ GasPrice: assets.NewWei(big.NewInt(1e18)),
+ },
+ {
+ SourceChainSelector: 202,
+ GasPrice: assets.NewWei(big.NewInt(1e18)),
+ },
+ }
+ gasUpserted, err := ccipORM.UpsertGasPricesForDestChain(ctx, 100, gasPrices)
+ require.NoError(t, err)
+ assert.Equal(t, len(gasPrices), int(gasUpserted))
+ assert.Equal(t, len(gasPrices), counterFromGaugeByLabels(ccipORM.datasetSize, "UpsertGasPricesForDestChain", "100"))
+ assert.Equal(t, 0, counterFromGaugeByLabels(ccipORM.datasetSize, "UpsertGasPricesForDestChain", "200"))
+
+ gas, err := ccipORM.GetGasPricesByDestChain(ctx, 100)
+ require.NoError(t, err)
+ assert.Equal(t, len(gasPrices), len(gas))
+ assert.Equal(t, len(gasPrices), counterFromGaugeByLabels(ccipORM.datasetSize, "GetGasPricesByDestChain", "100"))
+ assert.Equal(t, 1, counterFromHistogramByLabels(t, ccipORM.queryDuration, "GetGasPricesByDestChain", "100"))
+}
+
+func counterFromHistogramByLabels(t *testing.T, histogramVec *prometheus.HistogramVec, labels ...string) int {
+ observer, err := histogramVec.GetMetricWithLabelValues(labels...)
+ require.NoError(t, err)
+
+ metricCh := make(chan prometheus.Metric, 1)
+ observer.(prometheus.Histogram).Collect(metricCh)
+ close(metricCh)
+
+ metric := <-metricCh
+ pb := &io_prometheus_client.Metric{}
+ err = metric.Write(pb)
+ require.NoError(t, err)
+
+ return int(pb.GetHistogram().GetSampleCount())
+}
+
+func counterFromGaugeByLabels(gaugeVec *prometheus.GaugeVec, labels ...string) int {
+ value := testutil.ToFloat64(gaugeVec.WithLabelValues(labels...))
+ return int(value)
+}
diff --git a/core/services/ccip/orm.go b/core/services/ccip/orm.go
index d074ea7473e..1942c68fef9 100644
--- a/core/services/ccip/orm.go
+++ b/core/services/ccip/orm.go
@@ -8,65 +8,51 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
)
type GasPrice struct {
SourceChainSelector uint64
GasPrice *assets.Wei
- CreatedAt time.Time
-}
-
-type GasPriceUpdate struct {
- SourceChainSelector uint64
- GasPrice *assets.Wei
}
type TokenPrice struct {
TokenAddr string
TokenPrice *assets.Wei
- CreatedAt time.Time
-}
-
-type TokenPriceUpdate struct {
- TokenAddr string
- TokenPrice *assets.Wei
}
type ORM interface {
GetGasPricesByDestChain(ctx context.Context, destChainSelector uint64) ([]GasPrice, error)
GetTokenPricesByDestChain(ctx context.Context, destChainSelector uint64) ([]TokenPrice, error)
- InsertGasPricesForDestChain(ctx context.Context, destChainSelector uint64, jobId int32, gasPrices []GasPriceUpdate) error
- InsertTokenPricesForDestChain(ctx context.Context, destChainSelector uint64, jobId int32, tokenPrices []TokenPriceUpdate) error
-
- ClearGasPricesByDestChain(ctx context.Context, destChainSelector uint64, expireSec int) error
- ClearTokenPricesByDestChain(ctx context.Context, destChainSelector uint64, expireSec int) error
+ UpsertGasPricesForDestChain(ctx context.Context, destChainSelector uint64, gasPrices []GasPrice) (int64, error)
+ UpsertTokenPricesForDestChain(ctx context.Context, destChainSelector uint64, tokenPrices []TokenPrice, interval time.Duration) (int64, error)
}
type orm struct {
- ds sqlutil.DataSource
+ ds sqlutil.DataSource
+ lggr logger.Logger
}
var _ ORM = (*orm)(nil)
-func NewORM(ds sqlutil.DataSource) (ORM, error) {
+func NewORM(ds sqlutil.DataSource, lggr logger.Logger) (ORM, error) {
if ds == nil {
return nil, fmt.Errorf("datasource to CCIP NewORM cannot be nil")
}
return &orm{
- ds: ds,
+ ds: ds,
+ lggr: lggr,
}, nil
}
func (o *orm) GetGasPricesByDestChain(ctx context.Context, destChainSelector uint64) ([]GasPrice, error) {
var gasPrices []GasPrice
stmt := `
- SELECT DISTINCT ON (source_chain_selector)
- source_chain_selector, gas_price, created_at
+ SELECT source_chain_selector, gas_price
FROM ccip.observed_gas_prices
- WHERE chain_selector = $1
- ORDER BY source_chain_selector, created_at DESC;
+ WHERE chain_selector = $1;
`
err := o.ds.SelectContext(ctx, &gasPrices, stmt, destChainSelector)
if err != nil {
@@ -79,82 +65,147 @@ func (o *orm) GetGasPricesByDestChain(ctx context.Context, destChainSelector uin
func (o *orm) GetTokenPricesByDestChain(ctx context.Context, destChainSelector uint64) ([]TokenPrice, error) {
var tokenPrices []TokenPrice
stmt := `
- SELECT DISTINCT ON (token_addr)
- token_addr, token_price, created_at
+ SELECT token_addr, token_price
FROM ccip.observed_token_prices
- WHERE chain_selector = $1
- ORDER BY token_addr, created_at DESC;
+ WHERE chain_selector = $1;
`
err := o.ds.SelectContext(ctx, &tokenPrices, stmt, destChainSelector)
if err != nil {
return nil, err
}
-
return tokenPrices, nil
}
-func (o *orm) InsertGasPricesForDestChain(ctx context.Context, destChainSelector uint64, jobId int32, gasPrices []GasPriceUpdate) error {
+func (o *orm) UpsertGasPricesForDestChain(ctx context.Context, destChainSelector uint64, gasPrices []GasPrice) (int64, error) {
if len(gasPrices) == 0 {
- return nil
+ return 0, nil
+ }
+
+ uniqueGasUpdates := make(map[string]GasPrice)
+ for _, gasPrice := range gasPrices {
+ key := fmt.Sprintf("%d-%d", gasPrice.SourceChainSelector, destChainSelector)
+ uniqueGasUpdates[key] = gasPrice
}
- insertData := make([]map[string]interface{}, 0, len(gasPrices))
- for _, price := range gasPrices {
+ insertData := make([]map[string]interface{}, 0, len(uniqueGasUpdates))
+ for _, price := range uniqueGasUpdates {
insertData = append(insertData, map[string]interface{}{
"chain_selector": destChainSelector,
- "job_id": jobId,
"source_chain_selector": price.SourceChainSelector,
"gas_price": price.GasPrice,
})
}
- // using statement_timestamp() to make testing easier
- stmt := `INSERT INTO ccip.observed_gas_prices (chain_selector, job_id, source_chain_selector, gas_price, created_at)
- VALUES (:chain_selector, :job_id, :source_chain_selector, :gas_price, statement_timestamp());`
- _, err := o.ds.NamedExecContext(ctx, stmt, insertData)
+ stmt := `INSERT INTO ccip.observed_gas_prices (chain_selector, source_chain_selector, gas_price, updated_at)
+ VALUES (:chain_selector, :source_chain_selector, :gas_price, statement_timestamp())
+ ON CONFLICT (source_chain_selector, chain_selector)
+ DO UPDATE SET gas_price = EXCLUDED.gas_price, updated_at = EXCLUDED.updated_at;`
+
+ result, err := o.ds.NamedExecContext(ctx, stmt, insertData)
if err != nil {
- err = fmt.Errorf("error inserting gas prices for job %d: %w", jobId, err)
+ return 0, fmt.Errorf("error inserting gas prices %w", err)
}
-
- return err
+ return result.RowsAffected()
}
-func (o *orm) InsertTokenPricesForDestChain(ctx context.Context, destChainSelector uint64, jobId int32, tokenPrices []TokenPriceUpdate) error {
+// UpsertTokenPricesForDestChain inserts or updates only relevant token prices.
+// In order to reduce locking an unnecessary writes to the table, we start with fetching current prices.
+// If price for a token doesn't change or was updated recently we don't include that token to the upsert query.
+// We don't run in TX intentionally, because we don't want to lock the table and conflicts are resolved on the insert level
+func (o *orm) UpsertTokenPricesForDestChain(ctx context.Context, destChainSelector uint64, tokenPrices []TokenPrice, interval time.Duration) (int64, error) {
if len(tokenPrices) == 0 {
- return nil
+ return 0, nil
}
- insertData := make([]map[string]interface{}, 0, len(tokenPrices))
- for _, price := range tokenPrices {
+ tokensToUpdate, err := o.pickOnlyRelevantTokensForUpdate(ctx, destChainSelector, tokenPrices, interval)
+ if err != nil || len(tokensToUpdate) == 0 {
+ return 0, err
+ }
+
+ insertData := make([]map[string]interface{}, 0, len(tokensToUpdate))
+ for _, price := range tokensToUpdate {
insertData = append(insertData, map[string]interface{}{
"chain_selector": destChainSelector,
- "job_id": jobId,
"token_addr": price.TokenAddr,
"token_price": price.TokenPrice,
})
}
- // using statement_timestamp() to make testing easier
- stmt := `INSERT INTO ccip.observed_token_prices (chain_selector, job_id, token_addr, token_price, created_at)
- VALUES (:chain_selector, :job_id, :token_addr, :token_price, statement_timestamp());`
- _, err := o.ds.NamedExecContext(ctx, stmt, insertData)
+ stmt := `INSERT INTO ccip.observed_token_prices (chain_selector, token_addr, token_price, updated_at)
+ VALUES (:chain_selector, :token_addr, :token_price, statement_timestamp())
+ ON CONFLICT (token_addr, chain_selector)
+ DO UPDATE SET token_price = EXCLUDED.token_price, updated_at = EXCLUDED.updated_at;`
+ result, err := o.ds.NamedExecContext(ctx, stmt, insertData)
if err != nil {
- err = fmt.Errorf("error inserting token prices for job %d: %w", jobId, err)
+ return 0, fmt.Errorf("error inserting token prices %w", err)
}
-
- return err
+ return result.RowsAffected()
}
-func (o *orm) ClearGasPricesByDestChain(ctx context.Context, destChainSelector uint64, expireSec int) error {
- stmt := `DELETE FROM ccip.observed_gas_prices WHERE chain_selector = $1 AND created_at < (statement_timestamp() - $2 * interval '1 second')`
+// pickOnlyRelevantTokensForUpdate returns only tokens that need to be updated. Multiple jobs can be updating the same tokens,
+// in order to reduce table locking and redundant upserts we start with reading the table and checking which tokens are eligible for update.
+// A token is eligible for update when time since last update is greater than the interval.
+func (o *orm) pickOnlyRelevantTokensForUpdate(
+ ctx context.Context,
+ destChainSelector uint64,
+ tokenPrices []TokenPrice,
+ interval time.Duration,
+) ([]TokenPrice, error) {
+ tokenPricesByAddress := toTokensByAddress(tokenPrices)
+
+ // Picks only tokens which were recently updated and can be ignored,
+ // we will filter out these tokens from the upsert query.
+ stmt := `
+ SELECT
+ token_addr
+ FROM ccip.observed_token_prices
+ WHERE
+ chain_selector = $1
+ and token_addr = any($2)
+ and updated_at >= statement_timestamp() - $3::interval
+ `
+
+ pgInterval := fmt.Sprintf("%d milliseconds", interval.Milliseconds())
+ args := []interface{}{destChainSelector, tokenAddrsToBytes(tokenPricesByAddress), pgInterval}
+ var dbTokensToIgnore []string
+ if err := o.ds.SelectContext(ctx, &dbTokensToIgnore, stmt, args...); err != nil {
+ return nil, err
+ }
+
+ tokensToIgnore := make(map[string]struct{}, len(dbTokensToIgnore))
+ for _, tk := range dbTokensToIgnore {
+ tokensToIgnore[tk] = struct{}{}
+ }
- _, err := o.ds.ExecContext(ctx, stmt, destChainSelector, expireSec)
- return err
+ tokenPricesToUpdate := make([]TokenPrice, 0, len(tokenPrices))
+ for tokenAddr, tokenPrice := range tokenPricesByAddress {
+ eligibleForUpdate := false
+ if _, ok := tokensToIgnore[tokenAddr]; !ok {
+ eligibleForUpdate = true
+ tokenPricesToUpdate = append(tokenPricesToUpdate, TokenPrice{TokenAddr: tokenAddr, TokenPrice: tokenPrice})
+ }
+ o.lggr.Debugw(
+ "Token price eligibility for database update",
+ "eligibleForUpdate", eligibleForUpdate,
+ "token", tokenAddr,
+ "price", tokenPrice,
+ )
+ }
+ return tokenPricesToUpdate, nil
}
-func (o *orm) ClearTokenPricesByDestChain(ctx context.Context, destChainSelector uint64, expireSec int) error {
- stmt := `DELETE FROM ccip.observed_token_prices WHERE chain_selector = $1 AND created_at < (statement_timestamp() - $2 * interval '1 second')`
+func toTokensByAddress(tokens []TokenPrice) map[string]*assets.Wei {
+ tokensByAddr := make(map[string]*assets.Wei, len(tokens))
+ for _, tk := range tokens {
+ tokensByAddr[tk.TokenAddr] = tk.TokenPrice
+ }
+ return tokensByAddr
+}
- _, err := o.ds.ExecContext(ctx, stmt, destChainSelector, expireSec)
- return err
+func tokenAddrsToBytes(tokens map[string]*assets.Wei) [][]byte {
+ addrs := make([][]byte, 0, len(tokens))
+ for tkAddr := range tokens {
+ addrs = append(addrs, []byte(tkAddr))
+ }
+ return addrs
}
diff --git a/core/services/ccip/orm_test.go b/core/services/ccip/orm_test.go
index 7b7b8d82710..e778ddf6ce3 100644
--- a/core/services/ccip/orm_test.go
+++ b/core/services/ccip/orm_test.go
@@ -15,13 +15,18 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+var (
+ r = rand.New(rand.NewSource(time.Now().UnixNano()))
)
func setupORM(t *testing.T) (ORM, sqlutil.DataSource) {
t.Helper()
db := pgtest.NewSqlxDB(t)
- orm, err := NewORM(db)
+ orm, err := NewORM(db, logger.TestLogger(t))
require.NoError(t, err)
@@ -37,12 +42,12 @@ func generateChainSelectors(n int) []uint64 {
return selectors
}
-func generateGasPriceUpdates(chainSelector uint64, n int) []GasPriceUpdate {
- updates := make([]GasPriceUpdate, n)
+func generateGasPrices(chainSelector uint64, n int) []GasPrice {
+ updates := make([]GasPrice, n)
for i := 0; i < n; i++ {
// gas prices can take up whole range of uint256
uint256Max := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1))
- row := GasPriceUpdate{
+ row := GasPrice{
SourceChainSelector: chainSelector,
GasPrice: assets.NewWei(new(big.Int).Sub(uint256Max, big.NewInt(int64(i)))),
}
@@ -61,10 +66,21 @@ func generateTokenAddresses(n int) []string {
return addrs
}
-func generateTokenPriceUpdates(tokenAddr string, n int) []TokenPriceUpdate {
- updates := make([]TokenPriceUpdate, n)
+func generateRandomTokenPrices(tokenAddrs []string) []TokenPrice {
+ updates := make([]TokenPrice, 0, len(tokenAddrs))
+ for _, addr := range tokenAddrs {
+ updates = append(updates, TokenPrice{
+ TokenAddr: addr,
+ TokenPrice: assets.NewWei(new(big.Int).Rand(r, big.NewInt(1e18))),
+ })
+ }
+ return updates
+}
+
+func generateTokenPrices(tokenAddr string, n int) []TokenPrice {
+ updates := make([]TokenPrice, n)
for i := 0; i < n; i++ {
- row := TokenPriceUpdate{
+ row := TokenPrice{
TokenAddr: tokenAddr,
TokenPrice: assets.NewWei(new(big.Int).Mul(big.NewInt(1e18), big.NewInt(int64(i)))),
}
@@ -134,20 +150,20 @@ func TestORM_InsertAndGetGasPrices(t *testing.T) {
sourceSelectors := generateChainSelectors(numSourceChainSelectors)
- updates := make(map[uint64][]GasPriceUpdate)
+ updates := make(map[uint64][]GasPrice)
for _, selector := range sourceSelectors {
- updates[selector] = generateGasPriceUpdates(selector, numUpdatesPerSourceSelector)
+ updates[selector] = generateGasPrices(selector, numUpdatesPerSourceSelector)
}
// 5 jobs, each inserting prices for 10 chains, with 20 updates per chain.
- expectedPrices := make(map[uint64]GasPriceUpdate)
+ expectedPrices := make(map[uint64]GasPrice)
for i := 0; i < numJobs; i++ {
for selector, updatesPerSelector := range updates {
lastIndex := len(updatesPerSelector) - 1
- err := orm.InsertGasPricesForDestChain(ctx, destSelector, int32(i), updatesPerSelector[:lastIndex])
+ _, err := orm.UpsertGasPricesForDestChain(ctx, destSelector, updatesPerSelector[:lastIndex])
assert.NoError(t, err)
- err = orm.InsertGasPricesForDestChain(ctx, destSelector, int32(i), updatesPerSelector[lastIndex:])
+ _, err = orm.UpsertGasPricesForDestChain(ctx, destSelector, updatesPerSelector[lastIndex:])
assert.NoError(t, err)
expectedPrices[selector] = updatesPerSelector[lastIndex]
@@ -156,7 +172,7 @@ func TestORM_InsertAndGetGasPrices(t *testing.T) {
// verify number of rows inserted
numRows := getGasTableRowCount(t, db)
- assert.Equal(t, numJobs*numSourceChainSelectors*numUpdatesPerSourceSelector, numRows)
+ assert.Equal(t, numSourceChainSelectors, numRows)
prices, err := orm.GetGasPricesByDestChain(ctx, destSelector)
assert.NoError(t, err)
@@ -170,15 +186,15 @@ func TestORM_InsertAndGetGasPrices(t *testing.T) {
}
// after the initial inserts, insert new round of prices, 1 price per selector this time
- var combinedUpdates []GasPriceUpdate
+ var combinedUpdates []GasPrice
for selector, updatesPerSelector := range updates {
combinedUpdates = append(combinedUpdates, updatesPerSelector[0])
expectedPrices[selector] = updatesPerSelector[0]
}
- err = orm.InsertGasPricesForDestChain(ctx, destSelector, 1, combinedUpdates)
+ _, err = orm.UpsertGasPricesForDestChain(ctx, destSelector, combinedUpdates)
assert.NoError(t, err)
- assert.Equal(t, numJobs*numSourceChainSelectors*numUpdatesPerSourceSelector+numSourceChainSelectors, getGasTableRowCount(t, db))
+ assert.Equal(t, numSourceChainSelectors, getGasTableRowCount(t, db))
prices, err = orm.GetGasPricesByDestChain(ctx, destSelector)
assert.NoError(t, err)
@@ -190,7 +206,7 @@ func TestORM_InsertAndGetGasPrices(t *testing.T) {
}
}
-func TestORM_InsertAndDeleteGasPrices(t *testing.T) {
+func TestORM_UpsertGasPrices(t *testing.T) {
t.Parallel()
ctx := testutils.Context(t)
@@ -202,13 +218,13 @@ func TestORM_InsertAndDeleteGasPrices(t *testing.T) {
sourceSelectors := generateChainSelectors(numSourceChainSelectors)
- updates := make(map[uint64][]GasPriceUpdate)
+ updates := make(map[uint64][]GasPrice)
for _, selector := range sourceSelectors {
- updates[selector] = generateGasPriceUpdates(selector, numUpdatesPerSourceSelector)
+ updates[selector] = generateGasPrices(selector, numUpdatesPerSourceSelector)
}
for _, updatesPerSelector := range updates {
- err := orm.InsertGasPricesForDestChain(ctx, destSelector, 1, updatesPerSelector)
+ _, err := orm.UpsertGasPricesForDestChain(ctx, destSelector, updatesPerSelector)
assert.NoError(t, err)
}
@@ -217,21 +233,11 @@ func TestORM_InsertAndDeleteGasPrices(t *testing.T) {
// insert for the 2nd time after interimTimeStamp
for _, updatesPerSelector := range updates {
- err := orm.InsertGasPricesForDestChain(ctx, destSelector, 1, updatesPerSelector)
+ _, err := orm.UpsertGasPricesForDestChain(ctx, destSelector, updatesPerSelector)
assert.NoError(t, err)
}
- assert.Equal(t, 2*numSourceChainSelectors*numUpdatesPerSourceSelector, getGasTableRowCount(t, db))
-
- // clear by sleepSec should delete rows inserted before it
- err := orm.ClearGasPricesByDestChain(ctx, destSelector, sleepSec)
- assert.NoError(t, err)
- assert.Equal(t, numSourceChainSelectors*numUpdatesPerSourceSelector, getGasTableRowCount(t, db))
-
- // clear by 0 expiration seconds should delete all rows
- err = orm.ClearGasPricesByDestChain(ctx, destSelector, 0)
- assert.NoError(t, err)
- assert.Equal(t, 0, getGasTableRowCount(t, db))
+ assert.Equal(t, numSourceChainSelectors, getGasTableRowCount(t, db))
}
func TestORM_InsertAndGetTokenPrices(t *testing.T) {
@@ -247,20 +253,20 @@ func TestORM_InsertAndGetTokenPrices(t *testing.T) {
addrs := generateTokenAddresses(numAddresses)
- updates := make(map[string][]TokenPriceUpdate)
+ updates := make(map[string][]TokenPrice)
for _, addr := range addrs {
- updates[addr] = generateTokenPriceUpdates(addr, numUpdatesPerAddress)
+ updates[addr] = generateTokenPrices(addr, numUpdatesPerAddress)
}
// 5 jobs, each inserting prices for 10 chains, with 20 updates per chain.
- expectedPrices := make(map[string]TokenPriceUpdate)
+ expectedPrices := make(map[string]TokenPrice)
for i := 0; i < numJobs; i++ {
for addr, updatesPerAddr := range updates {
lastIndex := len(updatesPerAddr) - 1
- err := orm.InsertTokenPricesForDestChain(ctx, destSelector, int32(i), updatesPerAddr[:lastIndex])
+ _, err := orm.UpsertTokenPricesForDestChain(ctx, destSelector, updatesPerAddr[:lastIndex], 0)
assert.NoError(t, err)
- err = orm.InsertTokenPricesForDestChain(ctx, destSelector, int32(i), updatesPerAddr[lastIndex:])
+ _, err = orm.UpsertTokenPricesForDestChain(ctx, destSelector, updatesPerAddr[lastIndex:], 0)
assert.NoError(t, err)
expectedPrices[addr] = updatesPerAddr[lastIndex]
@@ -269,7 +275,7 @@ func TestORM_InsertAndGetTokenPrices(t *testing.T) {
// verify number of rows inserted
numRows := getTokenTableRowCount(t, db)
- assert.Equal(t, numJobs*numAddresses*numUpdatesPerAddress, numRows)
+ assert.Equal(t, numAddresses, numRows)
prices, err := orm.GetTokenPricesByDestChain(ctx, destSelector)
assert.NoError(t, err)
@@ -283,15 +289,15 @@ func TestORM_InsertAndGetTokenPrices(t *testing.T) {
}
// after the initial inserts, insert new round of prices, 1 price per selector this time
- var combinedUpdates []TokenPriceUpdate
+ var combinedUpdates []TokenPrice
for addr, updatesPerAddr := range updates {
combinedUpdates = append(combinedUpdates, updatesPerAddr[0])
expectedPrices[addr] = updatesPerAddr[0]
}
- err = orm.InsertTokenPricesForDestChain(ctx, destSelector, 1, combinedUpdates)
+ _, err = orm.UpsertTokenPricesForDestChain(ctx, destSelector, combinedUpdates, 0)
assert.NoError(t, err)
- assert.Equal(t, numJobs*numAddresses*numUpdatesPerAddress+numAddresses, getTokenTableRowCount(t, db))
+ assert.Equal(t, numAddresses, getTokenTableRowCount(t, db))
prices, err = orm.GetTokenPricesByDestChain(ctx, destSelector)
assert.NoError(t, err)
@@ -303,46 +309,68 @@ func TestORM_InsertAndGetTokenPrices(t *testing.T) {
}
}
-func TestORM_InsertAndDeleteTokenPrices(t *testing.T) {
+func TestORM_InsertTokenPricesWhenExpired(t *testing.T) {
t.Parallel()
ctx := testutils.Context(t)
-
- orm, db := setupORM(t)
+ orm, _ := setupORM(t)
numAddresses := 10
- numUpdatesPerAddress := 20
- destSelector := uint64(1)
-
+ destSelector := rand.Uint64()
addrs := generateTokenAddresses(numAddresses)
+ initTokenUpdates := generateRandomTokenPrices(addrs)
- updates := make(map[string][]TokenPriceUpdate)
- for _, addr := range addrs {
- updates[addr] = generateTokenPriceUpdates(addr, numUpdatesPerAddress)
- }
+ // Insert the first time, table is initialized
+ rowsUpdated, err := orm.UpsertTokenPricesForDestChain(ctx, destSelector, initTokenUpdates, time.Minute)
+ require.NoError(t, err)
+ assert.Equal(t, int64(numAddresses), rowsUpdated)
- for _, updatesPerAddr := range updates {
- err := orm.InsertTokenPricesForDestChain(ctx, destSelector, 1, updatesPerAddr)
- assert.NoError(t, err)
- }
+ //time.Sleep(100 * time.Millisecond)
- sleepSec := 2
- time.Sleep(time.Duration(sleepSec) * time.Second)
+ // Insert the second time, no updates, because prices haven't changed
+ rowsUpdated, err = orm.UpsertTokenPricesForDestChain(ctx, destSelector, initTokenUpdates, time.Minute)
+ require.NoError(t, err)
+ assert.Equal(t, int64(0), rowsUpdated)
- // insert for the 2nd time after interimTimeStamp
- for _, updatesPerAddr := range updates {
- err := orm.InsertTokenPricesForDestChain(ctx, destSelector, 1, updatesPerAddr)
- assert.NoError(t, err)
+ // There are new prices, but we still haven't reached interval
+ newPrices := generateRandomTokenPrices(addrs)
+ rowsUpdated, err = orm.UpsertTokenPricesForDestChain(ctx, destSelector, newPrices, time.Minute)
+ require.NoError(t, err)
+ assert.Equal(t, int64(0), rowsUpdated)
+
+ time.Sleep(100 * time.Millisecond)
+
+ // Again with the same new prices, but this time interval is reached
+ rowsUpdated, err = orm.UpsertTokenPricesForDestChain(ctx, destSelector, newPrices, time.Millisecond)
+ require.NoError(t, err)
+ assert.Equal(t, int64(numAddresses), rowsUpdated)
+
+ dbTokenPrices, err := orm.GetTokenPricesByDestChain(ctx, destSelector)
+ require.NoError(t, err)
+ assert.Len(t, dbTokenPrices, numAddresses)
+
+ dbTokenPricesByAddr := toTokensByAddress(dbTokenPrices)
+ for _, tkPrice := range newPrices {
+ dbToken, ok := dbTokenPricesByAddr[tkPrice.TokenAddr]
+ assert.True(t, ok)
+ assert.Equal(t, dbToken, tkPrice.TokenPrice)
}
+}
- assert.Equal(t, 2*numAddresses*numUpdatesPerAddress, getTokenTableRowCount(t, db))
+func Benchmark_UpsertsTheSameTokenPrices(b *testing.B) {
+ db := pgtest.NewSqlxDB(b)
+ orm, err := NewORM(db, logger.NullLogger)
+ require.NoError(b, err)
- // clear by sleepSec should delete rows inserted before it
- err := orm.ClearTokenPricesByDestChain(ctx, destSelector, sleepSec)
- assert.NoError(t, err)
- assert.Equal(t, numAddresses*numUpdatesPerAddress, getTokenTableRowCount(t, db))
+ ctx := testutils.Context(b)
+ numAddresses := 50
+ destSelector := rand.Uint64()
+ addrs := generateTokenAddresses(numAddresses)
+ tokenUpdates := generateRandomTokenPrices(addrs)
- // clear by 0 expiration seconds should delete all rows
- err = orm.ClearTokenPricesByDestChain(ctx, destSelector, 0)
- assert.NoError(t, err)
- assert.Equal(t, 0, getTokenTableRowCount(t, db))
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ _, err1 := orm.UpsertTokenPricesForDestChain(ctx, destSelector, tokenUpdates, time.Second)
+ require.NoError(b, err1)
+ }
}
diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go
index cabaacbb274..3efc92c2270 100644
--- a/core/services/chainlink/application.go
+++ b/core/services/chainlink/application.go
@@ -23,15 +23,14 @@ import (
"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/chains/evm/logpoller"
- "github.com/smartcontractkit/chainlink/v2/core/services/standardcapabilities"
- "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"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip"
"github.com/smartcontractkit/chainlink/v2/core/capabilities/remote"
remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types"
+ "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"
evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
@@ -46,6 +45,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/feeds"
"github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2"
"github.com/smartcontractkit/chainlink/v2/core/services/gateway"
+ "github.com/smartcontractkit/chainlink/v2/core/services/headreporter"
"github.com/smartcontractkit/chainlink/v2/core/services/job"
"github.com/smartcontractkit/chainlink/v2/core/services/keeper"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
@@ -57,10 +57,10 @@ import (
externalp2p "github.com/smartcontractkit/chainlink/v2/core/services/p2p/wrapper"
"github.com/smartcontractkit/chainlink/v2/core/services/periodicbackup"
"github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
- "github.com/smartcontractkit/chainlink/v2/core/services/promreporter"
"github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/standardcapabilities"
"github.com/smartcontractkit/chainlink/v2/core/services/streams"
"github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
"github.com/smartcontractkit/chainlink/v2/core/services/vrf"
@@ -70,6 +70,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/sessions"
"github.com/smartcontractkit/chainlink/v2/core/sessions/ldapauth"
"github.com/smartcontractkit/chainlink/v2/core/sessions/localauth"
+ "github.com/smartcontractkit/chainlink/v2/core/static"
"github.com/smartcontractkit/chainlink/v2/plugins"
)
@@ -148,7 +149,6 @@ type ChainlinkApplication struct {
shutdownOnce sync.Once
srvcs []services.ServiceCtx
HealthChecker services.Checker
- Nurse *services.Nurse
logger logger.SugaredLogger
AuditLogger audit.AuditLogger
closeLogger func() error
@@ -214,42 +214,52 @@ func NewApplication(opts ApplicationOpts) (Application, error) {
signer := externalPeer
externalPeerWrapper = externalPeer
remoteDispatcher := remote.NewDispatcher(externalPeerWrapper, signer, opts.CapabilitiesRegistry, globalLogger)
- srvcs = append(srvcs, remoteDispatcher)
-
dispatcher = remoteDispatcher
} else {
dispatcher = opts.CapabilitiesDispatcher
externalPeerWrapper = opts.CapabilitiesPeerWrapper
}
- srvcs = append(srvcs, externalPeerWrapper)
+ srvcs = append(srvcs, externalPeerWrapper, dispatcher)
- rid := cfg.Capabilities().ExternalRegistry().RelayID()
- registryAddress := cfg.Capabilities().ExternalRegistry().Address()
- relayer, err := relayerChainInterops.Get(rid)
- if err != nil {
- return nil, fmt.Errorf("could not fetch relayer %s configured for capabilities registry: %w", rid, err)
- }
+ if cfg.Capabilities().ExternalRegistry().Address() != "" {
+ rid := cfg.Capabilities().ExternalRegistry().RelayID()
+ registryAddress := cfg.Capabilities().ExternalRegistry().Address()
+ relayer, err := relayerChainInterops.Get(rid)
+ if err != nil {
+ return nil, fmt.Errorf("could not fetch relayer %s configured for capabilities registry: %w", rid, err)
+ }
+ registrySyncer, err := registrysyncer.New(
+ globalLogger,
+ func() (p2ptypes.PeerID, error) {
+ p := externalPeerWrapper.GetPeer()
+ if p == nil {
+ return p2ptypes.PeerID{}, errors.New("could not get peer")
+ }
- registrySyncer, err := registrysyncer.New(
- globalLogger,
- externalPeerWrapper,
- relayer,
- registryAddress,
- )
- if err != nil {
- return nil, fmt.Errorf("could not configure syncer: %w", err)
- }
+ return p.ID(), nil
+ },
+ relayer,
+ registryAddress,
+ registrysyncer.NewORM(opts.DS, globalLogger),
+ )
+ if err != nil {
+ return nil, fmt.Errorf("could not configure syncer: %w", err)
+ }
- wfLauncher := capabilities.NewLauncher(
- globalLogger,
- externalPeerWrapper,
- dispatcher,
- opts.CapabilitiesRegistry,
- )
- registrySyncer.AddLauncher(wfLauncher)
+ wfLauncher := capabilities.NewLauncher(
+ globalLogger,
+ externalPeerWrapper,
+ dispatcher,
+ opts.CapabilitiesRegistry,
+ )
+ registrySyncer.AddLauncher(wfLauncher)
- srvcs = append(srvcs, dispatcher, wfLauncher, registrySyncer)
+ srvcs = append(srvcs, wfLauncher, registrySyncer)
+ }
+ } else {
+ globalLogger.Debug("External registry not configured, skipping registry syncer and starting with an empty registry")
+ opts.CapabilitiesRegistry.SetLocalRegistry(&capabilities.TestMetadataRegistry{})
}
// LOOPs can be created as options, in the case of LOOP relayers, or
@@ -279,14 +289,9 @@ func NewApplication(opts ApplicationOpts) (Application, error) {
}
ap := cfg.AutoPprof()
- var nurse *services.Nurse
if ap.Enabled() {
globalLogger.Info("Nurse service (automatic pprof profiling) is enabled")
- nurse = services.NewNurse(ap, globalLogger)
- err := nurse.Start()
- if err != nil {
- return nil, err
- }
+ srvcs = append(srvcs, services.NewNurse(ap, globalLogger))
} else {
globalLogger.Info("Nurse service (automatic pprof profiling) is disabled")
}
@@ -322,8 +327,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) {
srvcs = append(srvcs, mailMon)
srvcs = append(srvcs, relayerChainInterops.Services()...)
- promReporter := promreporter.NewPromReporter(opts.DS, legacyEVMChains, globalLogger)
- srvcs = append(srvcs, promReporter)
// Initialize Local Users ORM and Authentication Provider specified in config
// BasicAdminUsersORM is initialized and required regardless of separate Authentication Provider
@@ -363,8 +366,16 @@ func NewApplication(opts ApplicationOpts) (Application, error) {
workflowORM = workflowstore.NewDBStore(opts.DS, globalLogger, clockwork.NewRealClock())
)
+ promReporter := headreporter.NewPrometheusReporter(opts.DS, legacyEVMChains)
+ chainIDs := make([]*big.Int, legacyEVMChains.Len())
+ for i, chain := range legacyEVMChains.Slice() {
+ chainIDs[i] = chain.ID()
+ }
+ telemReporter := headreporter.NewTelemetryReporter(telemetryManager, globalLogger, chainIDs...)
+ headReporter := headreporter.NewHeadReporterService(opts.DS, globalLogger, promReporter, telemReporter)
+ srvcs = append(srvcs, headReporter)
for _, chain := range legacyEVMChains.Slice() {
- chain.HeadBroadcaster().Subscribe(promReporter)
+ chain.HeadBroadcaster().Subscribe(headReporter)
chain.TxManager().RegisterResumeCallback(pipelineRunner.ResumeRun)
}
@@ -520,6 +531,18 @@ func NewApplication(opts ApplicationOpts) (Application, error) {
cfg.Insecure(),
opts.RelayerChainInteroperators,
)
+ delegates[job.CCIP] = ccip.NewDelegate(
+ globalLogger,
+ loopRegistrarConfig,
+ pipelineRunner,
+ opts.RelayerChainInteroperators.LegacyEVMChains(),
+ relayerChainInterops,
+ opts.KeyStore,
+ opts.DS,
+ peerWrapper,
+ telemetryManager,
+ cfg.Capabilities(),
+ )
} else {
globalLogger.Debug("Off-chain reporting v2 disabled")
}
@@ -590,7 +613,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) {
SessionReaper: sessionReaper,
ExternalInitiatorManager: externalInitiatorManager,
HealthChecker: healthChecker,
- Nurse: nurse,
logger: globalLogger,
AuditLogger: auditLogger,
closeLogger: opts.CloseLogger,
@@ -710,10 +732,6 @@ func (app *ChainlinkApplication) stop() (err error) {
err = multierr.Append(err, app.FeedsService.Close())
}
- if app.Nurse != nil {
- err = multierr.Append(err, app.Nurse.Close())
- }
-
if app.profiler != nil {
err = multierr.Append(err, app.profiler.Stop())
}
diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go
index dc301c0967f..476e758ccbb 100644
--- a/core/services/chainlink/config.go
+++ b/core/services/chainlink/config.go
@@ -55,8 +55,13 @@ type RawConfig map[string]any
// ValidateConfig returns an error if the Config is not valid for use, as-is.
func (c *RawConfig) ValidateConfig() (err error) {
if v, ok := (*c)["Enabled"]; ok {
- if _, ok := v.(*bool); !ok {
- err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Enabled", Value: v, Msg: "expected *bool"})
+ if _, ok := v.(bool); !ok {
+ err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Enabled", Value: v, Msg: "expected bool"})
+ }
+ }
+ if v, ok := (*c)["ChainID"]; ok {
+ if _, ok := v.(string); !ok {
+ err = multierr.Append(err, commonconfig.ErrInvalid{Name: "ChainID", Value: v, Msg: "expected string"})
}
}
return err
@@ -67,7 +72,17 @@ func (c *RawConfig) IsEnabled() bool {
return false
}
- return (*c)["Enabled"] == nil || *(*c)["Enabled"].(*bool)
+ enabled, ok := (*c)["Enabled"].(bool)
+ return ok && enabled
+}
+
+func (c *RawConfig) ChainID() string {
+ if c == nil {
+ return ""
+ }
+
+ chainID, _ := (*c)["ChainID"].(string)
+ return chainID
}
// TOMLString returns a TOML encoded string.
@@ -170,6 +185,9 @@ func (c *Config) SetFrom(f *Config) (err error) {
err = multierr.Append(err, commonconfig.NamedMultiErrorList(err4, "Starknet"))
}
+ // the plugin should handle it's own defaults and merging
+ c.Aptos = f.Aptos
+
_, err = commonconfig.MultiErrorList(err)
return err
diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go
index 5b6b839fb5e..79c92f82145 100644
--- a/core/services/chainlink/config_general.go
+++ b/core/services/chainlink/config_general.go
@@ -209,6 +209,10 @@ func (g *generalConfig) StarknetConfigs() starknet.TOMLConfigs {
return g.c.Starknet
}
+func (g *generalConfig) AptosConfigs() RawConfigs {
+ return g.c.Aptos
+}
+
func (g *generalConfig) Validate() error {
return g.validate(g.secrets.Validate)
}
diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go
index c8cd5ec4790..253e4aa067f 100644
--- a/core/services/chainlink/config_test.go
+++ b/core/services/chainlink/config_test.go
@@ -261,6 +261,7 @@ func TestConfig_Marshal(t *testing.T) {
FeedsManager: ptr(true),
LogPoller: ptr(true),
UICSAKeys: ptr(true),
+ CCIP: ptr(true),
}
full.Database = toml.Database{
DefaultIdleInTxSessionTimeout: commoncfg.MustNewDuration(time.Minute),
@@ -519,6 +520,7 @@ func TestConfig_Marshal(t *testing.T) {
LimitMax: ptr[uint64](17),
LimitMultiplier: mustDecimal("1.234"),
LimitTransfer: ptr[uint64](100),
+ EstimateGasLimit: ptr(false),
TipCapDefault: assets.NewWeiI(2),
TipCapMin: assets.NewWeiI(1),
PriceDefault: assets.NewWeiI(math.MaxInt64),
@@ -553,19 +555,20 @@ func TestConfig_Marshal(t *testing.T) {
},
},
- LinkContractAddress: mustAddress("0x538aAaB4ea120b2bC2fe5D296852D948F07D849e"),
- LogBackfillBatchSize: ptr[uint32](17),
- LogPollInterval: &minute,
- LogKeepBlocksDepth: ptr[uint32](100000),
- LogPrunePageSize: ptr[uint32](0),
- BackupLogPollerBlockDelay: ptr[uint64](532),
- MinContractPayment: commonassets.NewLinkFromJuels(math.MaxInt64),
- MinIncomingConfirmations: ptr[uint32](13),
- NonceAutoSync: ptr(true),
- NoNewHeadsThreshold: &minute,
- OperatorFactoryAddress: mustAddress("0xa5B85635Be42F21f94F28034B7DA440EeFF0F418"),
- RPCDefaultBatchSize: ptr[uint32](17),
- RPCBlockQueryDelay: ptr[uint16](10),
+ LinkContractAddress: mustAddress("0x538aAaB4ea120b2bC2fe5D296852D948F07D849e"),
+ LogBackfillBatchSize: ptr[uint32](17),
+ LogPollInterval: &minute,
+ LogKeepBlocksDepth: ptr[uint32](100000),
+ LogPrunePageSize: ptr[uint32](0),
+ BackupLogPollerBlockDelay: ptr[uint64](532),
+ MinContractPayment: commonassets.NewLinkFromJuels(math.MaxInt64),
+ MinIncomingConfirmations: ptr[uint32](13),
+ NonceAutoSync: ptr(true),
+ NoNewHeadsThreshold: &minute,
+ OperatorFactoryAddress: mustAddress("0xa5B85635Be42F21f94F28034B7DA440EeFF0F418"),
+ RPCDefaultBatchSize: ptr[uint32](17),
+ RPCBlockQueryDelay: ptr[uint16](10),
+ NoNewFinalizedHeadsThreshold: &hour,
Transactions: evmcfg.Transactions{
MaxInFlight: ptr[uint32](19),
@@ -770,6 +773,7 @@ Headers = ['Authorization: token', 'X-SomeOther-Header: value with spaces | and
FeedsManager = true
LogPoller = true
UICSAKeys = true
+CCIP = true
`},
{"Database", Config{Core: toml.Core{Database: full.Database}}, `[Database]
DefaultIdleInTxSessionTimeout = '1m0s'
@@ -996,6 +1000,7 @@ OperatorFactoryAddress = '0xa5B85635Be42F21f94F28034B7DA440EeFF0F418'
RPCDefaultBatchSize = 17
RPCBlockQueryDelay = 10
FinalizedBlockOffset = 16
+NoNewFinalizedHeadsThreshold = '1h0m0s'
[EVM.Transactions]
ForwardersEnabled = true
@@ -1020,6 +1025,7 @@ LimitDefault = 12
LimitMax = 17
LimitMultiplier = '1.234'
LimitTransfer = 100
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 10
BumpThreshold = 6
@@ -1300,7 +1306,7 @@ func TestConfig_Validate(t *testing.T) {
- 1: 10 errors:
- ChainType: invalid value (Foo): must not be set with this chain id
- Nodes: missing: must have at least one node
- - ChainType: invalid value (Foo): must be one of arbitrum, celo, gnosis, kroma, metis, optimismBedrock, scroll, wemix, xlayer, zkevm, zksync or omitted
+ - ChainType: invalid value (Foo): must be one of arbitrum, astar, celo, gnosis, hedera, kroma, mantle, metis, optimismBedrock, scroll, wemix, xlayer, zkevm, zksync or omitted
- HeadTracker.HistoryDepth: invalid value (30): must be greater than or equal to FinalizedBlockOffset
- GasEstimator.BumpThreshold: invalid value (0): cannot be 0 if auto-purge feature is enabled for Foo
- Transactions.AutoPurge.Threshold: missing: needs to be set if auto-purge feature is enabled for Foo
@@ -1313,7 +1319,7 @@ func TestConfig_Validate(t *testing.T) {
- 2: 5 errors:
- ChainType: invalid value (Arbitrum): only "optimismBedrock" can be used with this chain id
- Nodes: missing: must have at least one node
- - ChainType: invalid value (Arbitrum): must be one of arbitrum, celo, gnosis, kroma, metis, optimismBedrock, scroll, wemix, xlayer, zkevm, zksync or omitted
+ - ChainType: invalid value (Arbitrum): must be one of arbitrum, astar, celo, gnosis, hedera, kroma, mantle, metis, optimismBedrock, scroll, wemix, xlayer, zkevm, zksync or omitted
- FinalityDepth: invalid value (0): must be greater than or equal to 1
- MinIncomingConfirmations: invalid value (0): must be greater than or equal to 1
- 3.Nodes: 5 errors:
@@ -1361,7 +1367,7 @@ func TestConfig_Validate(t *testing.T) {
- 1: 2 errors:
- ChainID: missing: required for all chains
- Nodes: missing: must have at least one node
- - Aptos.0.Enabled: invalid value (1): expected *bool`},
+ - Aptos.0.Enabled: invalid value (1): expected bool`},
} {
t.Run(tt.name, func(t *testing.T) {
var c Config
diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go
index c42ed5c7014..f4594a43225 100644
--- a/core/services/chainlink/mocks/general_config.go
+++ b/core/services/chainlink/mocks/general_config.go
@@ -4,6 +4,8 @@ package mocks
import (
chainlinkconfig "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config"
+ chainlink "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
+
config "github.com/smartcontractkit/chainlink/v2/core/config"
cosmosconfig "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config"
@@ -81,6 +83,53 @@ func (_c *GeneralConfig_AppID_Call) RunAndReturn(run func() uuid.UUID) *GeneralC
return _c
}
+// AptosConfigs provides a mock function with given fields:
+func (_m *GeneralConfig) AptosConfigs() chainlink.RawConfigs {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for AptosConfigs")
+ }
+
+ var r0 chainlink.RawConfigs
+ if rf, ok := ret.Get(0).(func() chainlink.RawConfigs); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(chainlink.RawConfigs)
+ }
+ }
+
+ return r0
+}
+
+// GeneralConfig_AptosConfigs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AptosConfigs'
+type GeneralConfig_AptosConfigs_Call struct {
+ *mock.Call
+}
+
+// AptosConfigs is a helper method to define mock.On call
+func (_e *GeneralConfig_Expecter) AptosConfigs() *GeneralConfig_AptosConfigs_Call {
+ return &GeneralConfig_AptosConfigs_Call{Call: _e.mock.On("AptosConfigs")}
+}
+
+func (_c *GeneralConfig_AptosConfigs_Call) Run(run func()) *GeneralConfig_AptosConfigs_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *GeneralConfig_AptosConfigs_Call) Return(_a0 chainlink.RawConfigs) *GeneralConfig_AptosConfigs_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *GeneralConfig_AptosConfigs_Call) RunAndReturn(run func() chainlink.RawConfigs) *GeneralConfig_AptosConfigs_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// AptosEnabled provides a mock function with given fields:
func (_m *GeneralConfig) AptosEnabled() bool {
ret := _m.Called()
diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go
index 60381c0d479..ffcfc67b87d 100644
--- a/core/services/chainlink/relayer_chain_interoperators.go
+++ b/core/services/chainlink/relayer_chain_interoperators.go
@@ -186,6 +186,23 @@ func InitStarknet(ctx context.Context, factory RelayerFactory, config StarkNetFa
}
}
+// InitAptos is a option for instantiating Aptos relayers
+func InitAptos(ctx context.Context, factory RelayerFactory, config AptosFactoryConfig) CoreRelayerChainInitFunc {
+ return func(op *CoreRelayerChainInteroperators) (err error) {
+ relayers, err := factory.NewAptos(config.Keystore, config.TOMLConfigs)
+ if err != nil {
+ return fmt.Errorf("failed to setup aptos relayer: %w", err)
+ }
+
+ for id, relayer := range relayers {
+ op.srvs = append(op.srvs, relayer)
+ op.loopRelayers[id] = relayer
+ }
+
+ return nil
+ }
+}
+
// Get a [loop.Relayer] by id
func (rs *CoreRelayerChainInteroperators) Get(id types.RelayID) (loop.Relayer, error) {
rs.mu.Lock()
diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go
index 849964f9bec..3ddfe270477 100644
--- a/core/services/chainlink/relayer_factory.go
+++ b/core/services/chainlink/relayer_factory.go
@@ -18,7 +18,7 @@ import (
solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config"
pkgstarknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink"
starkchain "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/chain"
- "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config"
+ starkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
coreconfig "github.com/smartcontractkit/chainlink/v2/core/config"
"github.com/smartcontractkit/chainlink/v2/core/config/env"
@@ -171,12 +171,12 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solcfg.TOMLConf
type StarkNetFactoryConfig struct {
Keystore keystore.StarkNet
- config.TOMLConfigs
+ starkcfg.TOMLConfigs
}
// TODO BCF-2606 consider consolidating the driving logic with that of NewSolana above via generics
// perhaps when we implement a Cosmos LOOP
-func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOMLConfigs) (map[types.RelayID]loop.Relayer, error) {
+func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs starkcfg.TOMLConfigs) (map[types.RelayID]loop.Relayer, error) {
starknetRelayers := make(map[types.RelayID]loop.Relayer)
var (
@@ -205,7 +205,7 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML
if cmdName := env.StarknetPlugin.Cmd.Get(); cmdName != "" {
// setup the starknet relayer to be a LOOP
cfgTOML, err := toml.Marshal(struct {
- Starknet config.TOMLConfig
+ Starknet starkcfg.TOMLConfig
}{Starknet: *chainCfg})
if err != nil {
return nil, fmt.Errorf("failed to marshal StarkNet configs: %w", err)
@@ -301,3 +301,65 @@ func (r *RelayerFactory) NewCosmos(config CosmosFactoryConfig) (map[types.RelayI
}
return relayers, nil
}
+
+type AptosFactoryConfig struct {
+ Keystore keystore.Aptos
+ TOMLConfigs RawConfigs
+}
+
+func (r *RelayerFactory) NewAptos(ks keystore.Aptos, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) {
+ plugin := env.NewPlugin("aptos")
+ loopKs := &keystore.AptosLooppSigner{Aptos: ks}
+ return r.NewLOOPRelayer("Aptos", corerelay.NetworkAptos, plugin, loopKs, chainCfgs)
+}
+
+func (r *RelayerFactory) NewLOOPRelayer(name string, network string, plugin env.Plugin, ks coretypes.Keystore, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) {
+ relayers := make(map[types.RelayID]loop.Relayer)
+ lggr := r.Logger.Named(name)
+
+ unique := make(map[string]struct{})
+ // create one relayer per chain id
+ for _, chainCfg := range chainCfgs {
+ relayID := types.RelayID{Network: network, ChainID: chainCfg.ChainID()}
+ if _, alreadyExists := unique[relayID.Name()]; alreadyExists {
+ return nil, fmt.Errorf("duplicate chain definitions for %s", relayID.Name())
+ }
+ unique[relayID.Name()] = struct{}{}
+
+ // skip disabled chains from further processing
+ if !chainCfg.IsEnabled() {
+ lggr.Warnw("Skipping disabled chain", "id", relayID.ChainID)
+ continue
+ }
+
+ lggr2 := lggr.Named(relayID.ChainID)
+
+ cmdName := plugin.Cmd.Get()
+ if cmdName == "" {
+ return nil, fmt.Errorf("plugin not defined: %s", "")
+ }
+
+ // setup the relayer as a LOOP
+ cfgTOML, err := toml.Marshal(chainCfg)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal configs: %w", err)
+ }
+
+ envVars, err := plugins.ParseEnvFile(plugin.Env.Get())
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse env file: %w", err)
+ }
+ cmdFn, err := plugins.NewCmdFactory(r.Register, plugins.CmdConfig{
+ ID: relayID.Name(),
+ Cmd: cmdName,
+ Env: envVars,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to create LOOP command: %w", err)
+ }
+ // the relayer service has a delicate keystore dependency. the value that is passed to NewRelayerService must
+ // be compatible with instantiating a starknet transaction manager KeystoreAdapter within the LOOPp executable.
+ relayers[relayID] = loop.NewRelayerService(lggr2, r.GRPCOpts, cmdFn, string(cfgTOML), ks, r.CapabilitiesRegistry)
+ }
+ return relayers, nil
+}
diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml
index 1bad3fd91c6..f1325d824ea 100644
--- a/core/services/chainlink/testdata/config-empty-effective.toml
+++ b/core/services/chainlink/testdata/config-empty-effective.toml
@@ -6,6 +6,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml
index 78f52805dfe..a7fc9dcb94c 100644
--- a/core/services/chainlink/testdata/config-full.toml
+++ b/core/services/chainlink/testdata/config-full.toml
@@ -6,6 +6,7 @@ ShutdownGracePeriod = '10s'
FeedsManager = true
LogPoller = true
UICSAKeys = true
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1m0s'
@@ -290,6 +291,7 @@ OperatorFactoryAddress = '0xa5B85635Be42F21f94F28034B7DA440EeFF0F418'
RPCDefaultBatchSize = 17
RPCBlockQueryDelay = 10
FinalizedBlockOffset = 16
+NoNewFinalizedHeadsThreshold = '1h0m0s'
[EVM.Transactions]
ForwardersEnabled = true
@@ -314,6 +316,7 @@ LimitDefault = 12
LimitMax = 17
LimitMultiplier = '1.234'
LimitTransfer = 100
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 10
BumpThreshold = 6
diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml
index 61c5e3fa266..8bfc93c7be0 100644
--- a/core/services/chainlink/testdata/config-multi-chain-effective.toml
+++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml
@@ -6,6 +6,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
@@ -277,6 +278,7 @@ OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 12
+NoNewFinalizedHeadsThreshold = '9m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -301,6 +303,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -376,6 +379,7 @@ OperatorFactoryAddress = '0x8007e24251b1D2Fc518Eb843A701d9cD21fe0aA3'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -400,6 +404,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -469,6 +474,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 10
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '6m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -493,6 +499,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '20 gwei'
BumpPercent = 20
BumpThreshold = 5
diff --git a/core/services/chainlink/types.go b/core/services/chainlink/types.go
index 4aa37825493..74ffc5dc66d 100644
--- a/core/services/chainlink/types.go
+++ b/core/services/chainlink/types.go
@@ -15,6 +15,7 @@ type GeneralConfig interface {
CosmosConfigs() coscfg.TOMLConfigs
SolanaConfigs() solcfg.TOMLConfigs
StarknetConfigs() stkcfg.TOMLConfigs
+ AptosConfigs() RawConfigs
// ConfigTOML returns both the user provided and effective configuration as TOML.
ConfigTOML() (user, effective string)
}
diff --git a/core/services/feeds/mocks/service.go b/core/services/feeds/mocks/service.go
index a660420759e..d37c327850d 100644
--- a/core/services/feeds/mocks/service.go
+++ b/core/services/feeds/mocks/service.go
@@ -1403,6 +1403,39 @@ func (_c *Service_SyncNodeInfo_Call) RunAndReturn(run func(context.Context, int6
return _c
}
+// Unsafe_SetConnectionsManager provides a mock function with given fields: _a0
+func (_m *Service) Unsafe_SetConnectionsManager(_a0 feeds.ConnectionsManager) {
+ _m.Called(_a0)
+}
+
+// Service_Unsafe_SetConnectionsManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unsafe_SetConnectionsManager'
+type Service_Unsafe_SetConnectionsManager_Call struct {
+ *mock.Call
+}
+
+// Unsafe_SetConnectionsManager is a helper method to define mock.On call
+// - _a0 feeds.ConnectionsManager
+func (_e *Service_Expecter) Unsafe_SetConnectionsManager(_a0 interface{}) *Service_Unsafe_SetConnectionsManager_Call {
+ return &Service_Unsafe_SetConnectionsManager_Call{Call: _e.mock.On("Unsafe_SetConnectionsManager", _a0)}
+}
+
+func (_c *Service_Unsafe_SetConnectionsManager_Call) Run(run func(_a0 feeds.ConnectionsManager)) *Service_Unsafe_SetConnectionsManager_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(feeds.ConnectionsManager))
+ })
+ return _c
+}
+
+func (_c *Service_Unsafe_SetConnectionsManager_Call) Return() *Service_Unsafe_SetConnectionsManager_Call {
+ _c.Call.Return()
+ return _c
+}
+
+func (_c *Service_Unsafe_SetConnectionsManager_Call) RunAndReturn(run func(feeds.ConnectionsManager)) *Service_Unsafe_SetConnectionsManager_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
// UpdateChainConfig provides a mock function with given fields: ctx, cfg
func (_m *Service) UpdateChainConfig(ctx context.Context, cfg feeds.ChainConfig) (int64, error) {
ret := _m.Called(ctx, cfg)
diff --git a/core/services/feeds/proto/feeds_manager.pb.go b/core/services/feeds/proto/feeds_manager.pb.go
index 89f351a4270..ee5bcef3938 100644
--- a/core/services/feeds/proto/feeds_manager.pb.go
+++ b/core/services/feeds/proto/feeds_manager.pb.go
@@ -79,8 +79,7 @@ const (
ChainType_CHAIN_TYPE_UNSPECIFIED ChainType = 0
ChainType_CHAIN_TYPE_EVM ChainType = 1
ChainType_CHAIN_TYPE_SOLANA ChainType = 2
- ChainType_CHAIN_TYPE_ZKSYNC ChainType = 3
- ChainType_CHAIN_TYPE_STARKNET ChainType = 4
+ ChainType_CHAIN_TYPE_STARKNET ChainType = 3
)
// Enum value maps for ChainType.
@@ -89,15 +88,13 @@ var (
0: "CHAIN_TYPE_UNSPECIFIED",
1: "CHAIN_TYPE_EVM",
2: "CHAIN_TYPE_SOLANA",
- 3: "CHAIN_TYPE_ZKSYNC",
- 4: "CHAIN_TYPE_STARKNET",
+ 3: "CHAIN_TYPE_STARKNET",
}
ChainType_value = map[string]int32{
"CHAIN_TYPE_UNSPECIFIED": 0,
"CHAIN_TYPE_EVM": 1,
"CHAIN_TYPE_SOLANA": 2,
- "CHAIN_TYPE_ZKSYNC": 3,
- "CHAIN_TYPE_STARKNET": 4,
+ "CHAIN_TYPE_STARKNET": 3,
}
)
@@ -476,13 +473,17 @@ type ChainConfig struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
- Chain *Chain `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"`
- AccountAddress string `protobuf:"bytes,2,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty"`
- AdminAddress string `protobuf:"bytes,3,opt,name=admin_address,json=adminAddress,proto3" json:"admin_address,omitempty"`
- FluxMonitorConfig *FluxMonitorConfig `protobuf:"bytes,4,opt,name=flux_monitor_config,json=fluxMonitorConfig,proto3" json:"flux_monitor_config,omitempty"`
- Ocr1Config *OCR1Config `protobuf:"bytes,5,opt,name=ocr1_config,json=ocr1Config,proto3" json:"ocr1_config,omitempty"`
- Ocr2Config *OCR2Config `protobuf:"bytes,6,opt,name=ocr2_config,json=ocr2Config,proto3" json:"ocr2_config,omitempty"`
- AccountAddressPublicKey *string `protobuf:"bytes,7,opt,name=account_address_public_key,json=accountAddressPublicKey,proto3,oneof" json:"account_address_public_key,omitempty"`
+ Chain *Chain `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"`
+ AccountAddress string `protobuf:"bytes,2,opt,name=account_address,json=accountAddress,proto3" json:"account_address,omitempty"`
+ AdminAddress string `protobuf:"bytes,3,opt,name=admin_address,json=adminAddress,proto3" json:"admin_address,omitempty"`
+ FluxMonitorConfig *FluxMonitorConfig `protobuf:"bytes,4,opt,name=flux_monitor_config,json=fluxMonitorConfig,proto3" json:"flux_monitor_config,omitempty"`
+ Ocr1Config *OCR1Config `protobuf:"bytes,5,opt,name=ocr1_config,json=ocr1Config,proto3" json:"ocr1_config,omitempty"`
+ Ocr2Config *OCR2Config `protobuf:"bytes,6,opt,name=ocr2_config,json=ocr2Config,proto3" json:"ocr2_config,omitempty"`
+ // For EVM chains, we do not need this value and it is kept in the node's
+ // keystore. For starknet, because the wallet address needs to be deployed
+ // using this value and this pub key needs to be passed into the starknet
+ // relayer, we request the node to send this directly to CLO.
+ AccountAddressPublicKey *string `protobuf:"bytes,7,opt,name=account_address_public_key,json=accountAddressPublicKey,proto3,oneof" json:"account_address_public_key,omitempty"`
}
func (x *ChainConfig) Reset() {
@@ -1912,53 +1913,52 @@ var file_pkg_noderpc_proto_feeds_manager_proto_rawDesc = []byte{
0x5f, 0x4d, 0x4f, 0x4e, 0x49, 0x54, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x4a, 0x4f,
0x42, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x43, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d,
0x4a, 0x4f, 0x42, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x43, 0x52, 0x32, 0x10, 0x03, 0x2a,
- 0x82, 0x01, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a,
- 0x16, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50,
- 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x48, 0x41,
- 0x49, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x56, 0x4d, 0x10, 0x01, 0x12, 0x15, 0x0a,
- 0x11, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4f, 0x4c, 0x41,
- 0x4e, 0x41, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x59,
- 0x50, 0x45, 0x5f, 0x5a, 0x4b, 0x53, 0x59, 0x4e, 0x43, 0x10, 0x03, 0x12, 0x17, 0x0a, 0x13, 0x43,
- 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x4b, 0x4e,
- 0x45, 0x54, 0x10, 0x04, 0x32, 0xd8, 0x02, 0x0a, 0x0c, 0x46, 0x65, 0x65, 0x64, 0x73, 0x4d, 0x61,
- 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x40, 0x0a, 0x0b, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65,
- 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f,
- 0x76, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e,
- 0x63, 0x66, 0x6d, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52,
- 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74,
- 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x17, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x48, 0x65, 0x61,
- 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
- 0x18, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63,
- 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x55, 0x70, 0x64,
- 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x55, 0x70,
- 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
- 0x17, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65,
- 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x0b, 0x52, 0x65, 0x6a, 0x65,
- 0x63, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x52, 0x65,
- 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
- 0x1a, 0x18, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4a,
- 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0c, 0x43, 0x61,
- 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x63, 0x66, 0x6d,
- 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71,
- 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65,
- 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32,
- 0xc4, 0x01, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
- 0x3d, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x16, 0x2e,
+ 0x6b, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16,
+ 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
+ 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x48, 0x41, 0x49,
+ 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x56, 0x4d, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11,
+ 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4f, 0x4c, 0x41, 0x4e,
+ 0x41, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x48, 0x41, 0x49, 0x4e, 0x5f, 0x54, 0x59, 0x50,
+ 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x4b, 0x4e, 0x45, 0x54, 0x10, 0x03, 0x32, 0xd8, 0x02, 0x0a,
+ 0x0c, 0x46, 0x65, 0x65, 0x64, 0x73, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x40, 0x0a,
+ 0x0b, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x63,
+ 0x66, 0x6d, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x41, 0x70, 0x70, 0x72,
+ 0x6f, 0x76, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
+ 0x40, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x17,
+ 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x48, 0x65,
+ 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12,
+ 0x16, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x55, 0x70,
+ 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+ 0x12, 0x40, 0x0a, 0x0b, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12,
+ 0x17, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4a, 0x6f,
+ 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x52,
+ 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0c, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x4a,
+ 0x6f, 0x62, 0x12, 0x18, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c,
+ 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63,
+ 0x66, 0x6d, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc4, 0x01, 0x0a, 0x0b, 0x4e, 0x6f, 0x64, 0x65,
+ 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3d, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x70, 0x6f,
+ 0x73, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x16, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x50, 0x72, 0x6f, 0x70,
+ 0x6f, 0x73, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e,
0x63, 0x66, 0x6d, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65,
- 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x50, 0x72, 0x6f, 0x70,
- 0x6f, 0x73, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a,
- 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x2e, 0x63, 0x66,
- 0x6d, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65,
- 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a,
- 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x52, 0x65,
- 0x76, 0x6f, 0x6b, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x52, 0x65,
- 0x76, 0x6f, 0x6b, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
- 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65,
- 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
- 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61,
- 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x66, 0x65, 0x65, 0x64, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61,
- 0x67, 0x65, 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x72, 0x70, 0x63, 0x2f,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
+ 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
+ 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x63, 0x66, 0x6d,
+ 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
+ 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4a, 0x6f, 0x62, 0x12,
+ 0x15, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x4a, 0x6f, 0x62, 0x52,
+ 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x63, 0x66, 0x6d, 0x2e, 0x52, 0x65, 0x76,
+ 0x6f, 0x6b, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3d,
+ 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61,
+ 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x66, 0x65,
+ 0x65, 0x64, 0x73, 0x2d, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f,
+ 0x6e, 0x6f, 0x64, 0x65, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
diff --git a/core/services/feeds/proto/feeds_manager_wsrpc.pb.go b/core/services/feeds/proto/feeds_manager_wsrpc.pb.go
index a002257e5cb..17fe100b4fc 100644
--- a/core/services/feeds/proto/feeds_manager_wsrpc.pb.go
+++ b/core/services/feeds/proto/feeds_manager_wsrpc.pb.go
@@ -1,13 +1,12 @@
// Code generated by protoc-gen-go-wsrpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-wsrpc v0.0.1
-// - protoc v3.21.7
+// - protoc v4.25.3
package proto
import (
context "context"
-
wsrpc "github.com/smartcontractkit/wsrpc"
)
diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go
index b11b2b0167a..5e8e743109a 100644
--- a/core/services/feeds/service.go
+++ b/core/services/feeds/service.go
@@ -107,6 +107,9 @@ type Service interface {
ListSpecsByJobProposalIDs(ctx context.Context, ids []int64) ([]JobProposalSpec, error)
RejectSpec(ctx context.Context, id int64) error
UpdateSpecDefinition(ctx context.Context, id int64, spec string) error
+
+ // Unsafe_SetConnectionsManager Only for testing
+ Unsafe_SetConnectionsManager(ConnectionsManager)
}
type service struct {
@@ -206,7 +209,7 @@ func (s *service) RegisterManager(ctx context.Context, params RegisterManagerPar
var txerr error
id, txerr = tx.CreateManager(ctx, &mgr)
- if err != nil {
+ if txerr != nil {
return txerr
}
@@ -216,6 +219,9 @@ func (s *service) RegisterManager(ctx context.Context, params RegisterManagerPar
return nil
})
+ if err != nil {
+ return 0, err
+ }
privkey, err := s.getCSAPrivateKey()
if err != nil {
@@ -1105,6 +1111,16 @@ func (s *service) observeJobProposalCounts(ctx context.Context) error {
return nil
}
+// Unsafe_SetConnectionsManager sets the ConnectionsManager on the service.
+//
+// We need to be able to inject a mock for the client to facilitate integration
+// tests.
+//
+// ONLY TO BE USED FOR TESTING.
+func (s *service) Unsafe_SetConnectionsManager(connMgr ConnectionsManager) {
+ s.connMgr = connMgr
+}
+
// findExistingJobForOCR2 looks for existing job for OCR2
func findExistingJobForOCR2(ctx context.Context, j *job.Job, tx job.ORM) (int32, error) {
var contractID string
@@ -1501,5 +1517,6 @@ func (ns NullService) IsJobManaged(ctx context.Context, jobID int64) (bool, erro
func (ns NullService) UpdateSpecDefinition(ctx context.Context, id int64, spec string) error {
return ErrFeedsManagerDisabled
}
+func (ns NullService) Unsafe_SetConnectionsManager(_ ConnectionsManager) {}
//revive:enable
diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go
index 3ee7adc0d70..e98ae984fb7 100644
--- a/core/services/feeds/service_test.go
+++ b/core/services/feeds/service_test.go
@@ -265,6 +265,52 @@ func Test_Service_RegisterManager(t *testing.T) {
assert.Equal(t, actual, id)
}
+func Test_Service_RegisterManager_InvalidCreateManager(t *testing.T) {
+ t.Parallel()
+
+ var (
+ id = int64(1)
+ pubKeyHex = "0f17c3bf72de8beef6e2d17a14c0a972f5d7e0e66e70722373f12b88382d40f9"
+ )
+
+ var pubKey crypto.PublicKey
+ _, err := hex.Decode([]byte(pubKeyHex), pubKey)
+ require.NoError(t, err)
+
+ var (
+ mgr = feeds.FeedsManager{
+ Name: "FMS",
+ URI: "localhost:8080",
+ PublicKey: pubKey,
+ }
+ params = feeds.RegisterManagerParams{
+ Name: "FMS",
+ URI: "localhost:8080",
+ PublicKey: pubKey,
+ }
+ )
+
+ svc := setupTestService(t)
+
+ svc.orm.On("CountManagers", mock.Anything).Return(int64(0), nil)
+ svc.orm.On("CreateManager", mock.Anything, &mgr, mock.Anything).
+ Return(id, errors.New("orm error"))
+ // ListManagers runs in a goroutine so it might be called.
+ svc.orm.On("ListManagers", testutils.Context(t)).Return([]feeds.FeedsManager{mgr}, nil).Maybe()
+
+ transactCall := svc.orm.On("Transact", mock.Anything, mock.Anything)
+ transactCall.Run(func(args mock.Arguments) {
+ fn := args[1].(func(orm feeds.ORM) error)
+ transactCall.ReturnArguments = mock.Arguments{fn(svc.orm)}
+ })
+ _, err = svc.RegisterManager(testutils.Context(t), params)
+ // We need to stop the service because the manager will attempt to make a
+ // connection
+ svc.Close()
+ require.Error(t, err)
+ assert.Equal(t, "orm error", err.Error())
+}
+
func Test_Service_ListManagers(t *testing.T) {
t.Parallel()
ctx := testutils.Context(t)
diff --git a/core/services/fluxmonitorv2/deviation_checker.go b/core/services/fluxmonitorv2/deviation_checker.go
index 51e85de371e..9dc399b09f9 100644
--- a/core/services/fluxmonitorv2/deviation_checker.go
+++ b/core/services/fluxmonitorv2/deviation_checker.go
@@ -3,7 +3,7 @@ package fluxmonitorv2
import (
"github.com/shopspring/decimal"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
)
// DeviationThresholds carries parameters used by the threshold-trigger logic
@@ -26,7 +26,7 @@ func NewDeviationChecker(rel, abs float64, lggr logger.Logger) *DeviationChecker
Rel: rel,
Abs: abs,
},
- lggr: lggr.Named("DeviationChecker").With("threshold", rel, "absoluteThreshold", abs),
+ lggr: logger.Sugared(lggr).Named("DeviationChecker").With("threshold", rel, "absoluteThreshold", abs),
}
}
diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go
index 9175feb1a68..b8154ab6797 100644
--- a/core/services/fluxmonitorv2/flux_monitor.go
+++ b/core/services/fluxmonitorv2/flux_monitor.go
@@ -13,6 +13,7 @@ import (
"github.com/pkg/errors"
"github.com/shopspring/decimal"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
@@ -22,7 +23,6 @@ import (
evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/recovery"
"github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2/promfm"
"github.com/smartcontractkit/chainlink/v2/core/services/job"
@@ -56,7 +56,10 @@ const DefaultHibernationPollPeriod = 24 * time.Hour
// FluxMonitor polls external price adapters via HTTP to check for price swings.
type FluxMonitor struct {
- services.StateMachine
+ services.Service
+ eng *services.Engine
+ logger logger.SugaredLogger
+
contractAddress common.Address
oracleAddress common.Address
jobSpec job.Job
@@ -77,13 +80,8 @@ type FluxMonitor struct {
logBroadcaster log.Broadcaster
chainID *big.Int
- logger logger.SugaredLogger
-
backlog *utils.BoundedPriorityQueue[log.Broadcast]
chProcessLogs chan struct{}
-
- chStop services.StopChan
- waitOnStop chan struct{}
}
// NewFluxMonitor returns a new instance of PollingDeviationChecker.
@@ -105,7 +103,7 @@ func NewFluxMonitor(
flags Flags,
fluxAggregator flux_aggregator_wrapper.FluxAggregatorInterface,
logBroadcaster log.Broadcaster,
- fmLogger logger.Logger,
+ lggr logger.Logger,
chainID *big.Int,
) (*FluxMonitor, error) {
fm := &FluxMonitor{
@@ -126,7 +124,6 @@ func NewFluxMonitor(
flags: flags,
logBroadcaster: logBroadcaster,
fluxAggregator: fluxAggregator,
- logger: logger.Sugared(fmLogger),
chainID: chainID,
backlog: utils.NewBoundedPriorityQueue[log.Broadcast](map[uint]int{
// We want reconnecting nodes to be able to submit to a round
@@ -136,9 +133,13 @@ func NewFluxMonitor(
PriorityFlagChangedLog: 2,
}),
chProcessLogs: make(chan struct{}, 1),
- chStop: make(services.StopChan),
- waitOnStop: make(chan struct{}),
}
+ fm.Service, fm.eng = services.Config{
+ Name: "FluxMonitor",
+ Start: fm.start,
+ Close: fm.close,
+ }.NewServiceEngine(lggr)
+ fm.logger = logger.Sugared(fm.eng)
return fm, nil
}
@@ -220,7 +221,7 @@ func NewFromJobSpec(
return nil, err
}
- fmLogger := lggr.With(
+ fmLogger := logger.With(lggr,
"jobID", jobSpec.ID,
"contract", fmSpec.ContractAddress.Hex(),
)
@@ -279,14 +280,9 @@ const (
// Start implements the job.Service interface. It begins the CSP consumer in a
// single goroutine to poll the price adapters and listen to NewRound events.
-func (fm *FluxMonitor) Start(context.Context) error {
- return fm.StartOnce("FluxMonitor", func() error {
- fm.logger.Debug("Starting Flux Monitor for job")
-
- go fm.consume()
-
- return nil
- })
+func (fm *FluxMonitor) start(context.Context) error {
+ fm.eng.Go(fm.consume)
+ return nil
}
func (fm *FluxMonitor) IsHibernating() bool {
@@ -304,16 +300,12 @@ func (fm *FluxMonitor) IsHibernating() bool {
return !isFlagLowered
}
-// Close implements the job.Service interface. It stops this instance from
+// close stops this instance from
// polling, cleaning up resources.
-func (fm *FluxMonitor) Close() error {
- return fm.StopOnce("FluxMonitor", func() error {
- fm.pollManager.Stop()
- close(fm.chStop)
- <-fm.waitOnStop
+func (fm *FluxMonitor) close() error {
+ fm.pollManager.Stop()
- return nil
- })
+ return nil
}
// JobID implements the listener.Listener interface.
@@ -354,10 +346,8 @@ func (fm *FluxMonitor) HandleLog(ctx context.Context, broadcast log.Broadcast) {
}
}
-func (fm *FluxMonitor) consume() {
- defer close(fm.waitOnStop)
-
- if err := fm.SetOracleAddress(); err != nil {
+func (fm *FluxMonitor) consume(ctx context.Context) {
+ if err := fm.SetOracleAddress(ctx); err != nil {
fm.logger.Warnw(
"unable to set oracle address, this flux monitor job may not work correctly",
"err", err,
@@ -398,46 +388,46 @@ func (fm *FluxMonitor) consume() {
for {
select {
- case <-fm.chStop:
+ case <-ctx.Done():
return
case <-fm.chProcessLogs:
- recovery.WrapRecover(fm.logger, fm.processLogs)
+ recovery.WrapRecover(fm.logger, func() { fm.processLogs(ctx) })
case at := <-fm.pollManager.PollTickerTicks():
tickLogger.Debugf("Poll ticker fired on %v", formatTime(at))
recovery.WrapRecover(fm.logger, func() {
- fm.pollIfEligible(PollRequestTypePoll, fm.deviationChecker, nil)
+ fm.pollIfEligible(ctx, PollRequestTypePoll, fm.deviationChecker, nil)
})
case at := <-fm.pollManager.IdleTimerTicks():
tickLogger.Debugf("Idle timer fired on %v", formatTime(at))
recovery.WrapRecover(fm.logger, func() {
- fm.pollIfEligible(PollRequestTypeIdle, NewZeroDeviationChecker(fm.logger), nil)
+ fm.pollIfEligible(ctx, PollRequestTypeIdle, NewZeroDeviationChecker(fm.logger), nil)
})
case at := <-fm.pollManager.RoundTimerTicks():
tickLogger.Debugf("Round timer fired on %v", formatTime(at))
recovery.WrapRecover(fm.logger, func() {
- fm.pollIfEligible(PollRequestTypeRound, fm.deviationChecker, nil)
+ fm.pollIfEligible(ctx, PollRequestTypeRound, fm.deviationChecker, nil)
})
case at := <-fm.pollManager.HibernationTimerTicks():
tickLogger.Debugf("Hibernation timer fired on %v", formatTime(at))
recovery.WrapRecover(fm.logger, func() {
- fm.pollIfEligible(PollRequestTypeHibernation, NewZeroDeviationChecker(fm.logger), nil)
+ fm.pollIfEligible(ctx, PollRequestTypeHibernation, NewZeroDeviationChecker(fm.logger), nil)
})
case at := <-fm.pollManager.RetryTickerTicks():
tickLogger.Debugf("Retry ticker fired on %v", formatTime(at))
recovery.WrapRecover(fm.logger, func() {
- fm.pollIfEligible(PollRequestTypeRetry, NewZeroDeviationChecker(fm.logger), nil)
+ fm.pollIfEligible(ctx, PollRequestTypeRetry, NewZeroDeviationChecker(fm.logger), nil)
})
case at := <-fm.pollManager.DrumbeatTicks():
tickLogger.Debugf("Drumbeat ticker fired on %v", formatTime(at))
recovery.WrapRecover(fm.logger, func() {
- fm.pollIfEligible(PollRequestTypeDrumbeat, NewZeroDeviationChecker(fm.logger), nil)
+ fm.pollIfEligible(ctx, PollRequestTypeDrumbeat, NewZeroDeviationChecker(fm.logger), nil)
})
case request := <-fm.pollManager.Poll():
@@ -446,7 +436,7 @@ func (fm *FluxMonitor) consume() {
break
default:
recovery.WrapRecover(fm.logger, func() {
- fm.pollIfEligible(request.Type, fm.deviationChecker, nil)
+ fm.pollIfEligible(ctx, request.Type, fm.deviationChecker, nil)
})
}
}
@@ -460,11 +450,7 @@ func formatTime(at time.Time) string {
// SetOracleAddress sets the oracle address which matches the node's keys.
// If none match, it uses the first available key
-func (fm *FluxMonitor) SetOracleAddress() error {
- // fm on deprecation path, using dangling context
- ctx, cancel := fm.chStop.NewCtx()
- defer cancel()
-
+func (fm *FluxMonitor) SetOracleAddress(ctx context.Context) error {
oracleAddrs, err := fm.fluxAggregator.GetOracles(nil)
if err != nil {
fm.logger.Error("failed to get list of oracles from FluxAggregator contract")
@@ -502,10 +488,7 @@ func (fm *FluxMonitor) SetOracleAddress() error {
return errors.New("No keys found")
}
-func (fm *FluxMonitor) processLogs() {
- ctx, cancel := fm.chStop.NewCtx()
- defer cancel()
-
+func (fm *FluxMonitor) processLogs(ctx context.Context) {
for ctx.Err() == nil && !fm.backlog.Empty() {
broadcast := fm.backlog.Take()
fm.processBroadcast(ctx, broadcast)
@@ -529,7 +512,7 @@ func (fm *FluxMonitor) processBroadcast(ctx context.Context, broadcast log.Broad
decodedLog := broadcast.DecodedLog()
switch log := decodedLog.(type) {
case *flux_aggregator_wrapper.FluxAggregatorNewRound:
- fm.respondToNewRoundLog(*log, broadcast)
+ fm.respondToNewRoundLog(ctx, *log, broadcast)
case *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated:
fm.respondToAnswerUpdatedLog(*log)
fm.markLogAsConsumed(ctx, broadcast, decodedLog, started)
@@ -540,7 +523,7 @@ func (fm *FluxMonitor) processBroadcast(ctx context.Context, broadcast log.Broad
// Only reactivate if it is hibernating
if fm.pollManager.isHibernating.Load() {
fm.pollManager.Awaken(fm.initialRoundState())
- fm.pollIfEligible(PollRequestTypeAwaken, NewZeroDeviationChecker(fm.logger), broadcast)
+ fm.pollIfEligible(ctx, PollRequestTypeAwaken, NewZeroDeviationChecker(fm.logger), broadcast)
}
default:
fm.logger.Errorf("unknown log %v of type %T", log, log)
@@ -589,10 +572,8 @@ func (fm *FluxMonitor) respondToAnswerUpdatedLog(log flux_aggregator_wrapper.Flu
// The NewRound log tells us that an oracle has initiated a new round. This tells us that we
// need to poll and submit an answer to the contract regardless of the deviation.
-func (fm *FluxMonitor) respondToNewRoundLog(log flux_aggregator_wrapper.FluxAggregatorNewRound, lb log.Broadcast) {
+func (fm *FluxMonitor) respondToNewRoundLog(ctx context.Context, log flux_aggregator_wrapper.FluxAggregatorNewRound, lb log.Broadcast) {
started := time.Now()
- ctx, cancel := fm.chStop.NewCtx()
- defer cancel()
newRoundLogger := fm.logger.With(
"round", log.RoundId,
@@ -819,10 +800,8 @@ func (fm *FluxMonitor) checkEligibilityAndAggregatorFunding(roundState flux_aggr
return nil
}
-func (fm *FluxMonitor) pollIfEligible(pollReq PollRequestType, deviationChecker *DeviationChecker, broadcast log.Broadcast) {
+func (fm *FluxMonitor) pollIfEligible(ctx context.Context, pollReq PollRequestType, deviationChecker *DeviationChecker, broadcast log.Broadcast) {
started := time.Now()
- ctx, cancel := fm.chStop.NewCtx()
- defer cancel()
l := fm.logger.With(
"threshold", deviationChecker.Thresholds.Rel,
diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go
index b3a5bcee6b9..1d1ed676e48 100644
--- a/core/services/fluxmonitorv2/flux_monitor_test.go
+++ b/core/services/fluxmonitorv2/flux_monitor_test.go
@@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/google/uuid"
+ "github.com/jmoiron/sqlx"
"github.com/onsi/gomega"
"github.com/pkg/errors"
"github.com/shopspring/decimal"
@@ -18,11 +19,10 @@ import (
"github.com/stretchr/testify/require"
"gopkg.in/guregu/null.v4"
- "github.com/jmoiron/sqlx"
-
"github.com/smartcontractkit/chainlink-common/pkg/assets"
"github.com/smartcontractkit/chainlink-common/pkg/services/servicetest"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/log"
logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks"
@@ -491,7 +491,7 @@ func TestFluxMonitor_PollIfEligible(t *testing.T) {
oracles := []common.Address{nodeAddr, testutils.NewAddress()}
tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil)
- require.NoError(t, fm.SetOracleAddress())
+ require.NoError(t, fm.SetOracleAddress(tests.Context(t)))
fm.ExportedPollIfEligible(thresholds.rel, thresholds.abs)
})
}
@@ -526,7 +526,7 @@ func TestFluxMonitor_PollIfEligible_Creates_JobErr(t *testing.T) {
Once()
tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil)
- require.NoError(t, fm.SetOracleAddress())
+ require.NoError(t, fm.SetOracleAddress(tests.Context(t)))
fm.ExportedPollIfEligible(1, 1)
}
@@ -1171,7 +1171,7 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutAtZero(t *testing.T) {
tm.fluxAggregator.On("Address").Return(common.Address{})
tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil)
- require.NoError(t, fm.SetOracleAddress())
+ require.NoError(t, fm.SetOracleAddress(tests.Context(t)))
fm.ExportedRoundState(t)
servicetest.Run(t, fm)
@@ -1506,7 +1506,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) {
Return(nil)
tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil)
- require.NoError(t, fm.SetOracleAddress())
+ require.NoError(t, fm.SetOracleAddress(tests.Context(t)))
tm.fluxAggregator.On("LatestRoundData", nilOpts).Return(flux_aggregator_wrapper.LatestRoundData{
Answer: big.NewInt(10),
@@ -1635,7 +1635,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) {
Once()
tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil)
- require.NoError(t, fm.SetOracleAddress())
+ require.NoError(t, fm.SetOracleAddress(tests.Context(t)))
fm.ExportedPollIfEligible(0, 0)
// Now fire off the NewRound log and ensure it does not respond this time
@@ -1732,7 +1732,7 @@ func TestFluxMonitor_DoesNotDoubleSubmit(t *testing.T) {
Once()
tm.fluxAggregator.On("GetOracles", nilOpts).Return(oracles, nil)
- require.NoError(t, fm.SetOracleAddress())
+ require.NoError(t, fm.SetOracleAddress(tests.Context(t)))
fm.ExportedPollIfEligible(0, 0)
// Now fire off the NewRound log and ensure it does not respond this time
diff --git a/core/services/fluxmonitorv2/helpers_test.go b/core/services/fluxmonitorv2/helpers_test.go
index d321ddc35c3..80db82351c7 100644
--- a/core/services/fluxmonitorv2/helpers_test.go
+++ b/core/services/fluxmonitorv2/helpers_test.go
@@ -19,11 +19,15 @@ func (fm *FluxMonitor) Format(f fmt.State, verb rune) {
}
func (fm *FluxMonitor) ExportedPollIfEligible(threshold, absoluteThreshold float64) {
- fm.pollIfEligible(PollRequestTypePoll, NewDeviationChecker(threshold, absoluteThreshold, fm.logger), nil)
+ ctx, cancel := fm.eng.NewCtx()
+ defer cancel()
+ fm.pollIfEligible(ctx, PollRequestTypePoll, NewDeviationChecker(threshold, absoluteThreshold, fm.logger), nil)
}
func (fm *FluxMonitor) ExportedProcessLogs() {
- fm.processLogs()
+ ctx, cancel := fm.eng.NewCtx()
+ defer cancel()
+ fm.processLogs(ctx)
}
func (fm *FluxMonitor) ExportedBacklog() *utils.BoundedPriorityQueue[log.Broadcast] {
@@ -36,7 +40,9 @@ func (fm *FluxMonitor) ExportedRoundState(t *testing.T) {
}
func (fm *FluxMonitor) ExportedRespondToNewRoundLog(log *flux_aggregator_wrapper.FluxAggregatorNewRound, broadcast log.Broadcast) {
- fm.respondToNewRoundLog(*log, broadcast)
+ ctx, cancel := fm.eng.NewCtx()
+ defer cancel()
+ fm.respondToNewRoundLog(ctx, *log, broadcast)
}
func (fm *FluxMonitor) ExportedRespondToFlagsRaisedLog() {
diff --git a/core/services/fluxmonitorv2/poll_manager.go b/core/services/fluxmonitorv2/poll_manager.go
index 78b99aec4d5..aca6c75a311 100644
--- a/core/services/fluxmonitorv2/poll_manager.go
+++ b/core/services/fluxmonitorv2/poll_manager.go
@@ -5,8 +5,8 @@ import (
"sync/atomic"
"time"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/utils"
)
@@ -64,7 +64,7 @@ type PollManager struct {
}
// NewPollManager initializes a new PollManager
-func NewPollManager(cfg PollManagerConfig, logger logger.Logger) (*PollManager, error) {
+func NewPollManager(cfg PollManagerConfig, lggr logger.Logger) (*PollManager, error) {
minBackoffDuration := cfg.MinRetryBackoffDuration
if cfg.IdleTimerPeriod < minBackoffDuration {
minBackoffDuration = cfg.IdleTimerPeriod
@@ -82,7 +82,7 @@ func NewPollManager(cfg PollManagerConfig, logger logger.Logger) (*PollManager,
p := &PollManager{
cfg: cfg,
- logger: logger.Named("PollManager"),
+ logger: logger.Named(lggr, "PollManager"),
hibernationTimer: utils.NewResettableTimer(),
pollTicker: utils.NewPausableTicker(cfg.PollTickerInterval),
@@ -277,7 +277,7 @@ func (pm *PollManager) startIdleTimer(roundStartedAtUTC uint64) {
deadline := startedAt.Add(pm.cfg.IdleTimerPeriod)
deadlineDuration := time.Until(deadline)
- log := pm.logger.With(
+ log := logger.With(pm.logger,
"pollFrequency", pm.cfg.PollTickerInterval,
"idleDuration", pm.cfg.IdleTimerPeriod,
"startedAt", roundStartedAtUTC,
@@ -300,7 +300,7 @@ func (pm *PollManager) startIdleTimer(roundStartedAtUTC uint64) {
// startRoundTimer starts the round timer
func (pm *PollManager) startRoundTimer(roundTimesOutAt uint64) {
- log := pm.logger.With(
+ log := logger.With(pm.logger,
"pollFrequency", pm.cfg.PollTickerInterval,
"idleDuration", pm.cfg.IdleTimerPeriod,
"timesOutAt", roundTimesOutAt,
diff --git a/core/services/headreporter/head_reporter.go b/core/services/headreporter/head_reporter.go
new file mode 100644
index 00000000000..94de8ae2be9
--- /dev/null
+++ b/core/services/headreporter/head_reporter.go
@@ -0,0 +1,111 @@
+package headreporter
+
+import (
+ "context"
+ "sync"
+ "time"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
+ "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types"
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+type (
+ HeadReporter interface {
+ ReportNewHead(ctx context.Context, head *evmtypes.Head) error
+ ReportPeriodic(ctx context.Context) error
+ }
+
+ HeadReporterService struct {
+ services.StateMachine
+ ds sqlutil.DataSource
+ lggr logger.Logger
+ newHeads *mailbox.Mailbox[*evmtypes.Head]
+ chStop services.StopChan
+ wgDone sync.WaitGroup
+ reportPeriod time.Duration
+ reporters []HeadReporter
+ unsubscribeFns []func()
+ }
+)
+
+func NewHeadReporterService(ds sqlutil.DataSource, lggr logger.Logger, reporters ...HeadReporter) *HeadReporterService {
+ return &HeadReporterService{
+ ds: ds,
+ lggr: lggr.Named("HeadReporter"),
+ newHeads: mailbox.NewSingle[*evmtypes.Head](),
+ chStop: make(chan struct{}),
+ reporters: reporters,
+ reportPeriod: 15 * time.Second,
+ }
+}
+
+func (hrd *HeadReporterService) Subscribe(subFn func(types.HeadTrackable) (evmtypes.Head, func())) {
+ _, unsubscribe := subFn(hrd)
+ hrd.unsubscribeFns = append(hrd.unsubscribeFns, unsubscribe)
+}
+
+func (hrd *HeadReporterService) Start(context.Context) error {
+ return hrd.StartOnce(hrd.Name(), func() error {
+ hrd.wgDone.Add(1)
+ go hrd.eventLoop()
+ return nil
+ })
+}
+
+func (hrd *HeadReporterService) Close() error {
+ return hrd.StopOnce(hrd.Name(), func() error {
+ close(hrd.chStop)
+ hrd.wgDone.Wait()
+ return nil
+ })
+}
+
+func (hrd *HeadReporterService) Name() string {
+ return hrd.lggr.Name()
+}
+
+func (hrd *HeadReporterService) HealthReport() map[string]error {
+ return map[string]error{hrd.Name(): hrd.Healthy()}
+}
+
+func (hrd *HeadReporterService) OnNewLongestChain(ctx context.Context, head *evmtypes.Head) {
+ hrd.newHeads.Deliver(head)
+}
+
+func (hrd *HeadReporterService) eventLoop() {
+ hrd.lggr.Debug("Starting event loop")
+ defer hrd.wgDone.Done()
+ ctx, cancel := hrd.chStop.NewCtx()
+ defer cancel()
+ after := time.After(hrd.reportPeriod)
+ for {
+ select {
+ case <-hrd.newHeads.Notify():
+ head, exists := hrd.newHeads.Retrieve()
+ if !exists {
+ continue
+ }
+ for _, reporter := range hrd.reporters {
+ err := reporter.ReportNewHead(ctx, head)
+ if err != nil && ctx.Err() == nil {
+ hrd.lggr.Errorw("Error reporting new head", "err", err)
+ }
+ }
+ case <-after:
+ for _, reporter := range hrd.reporters {
+ err := reporter.ReportPeriodic(ctx)
+ if err != nil && ctx.Err() == nil {
+ hrd.lggr.Errorw("Error in periodic report", "err", err)
+ }
+ }
+ after = time.After(hrd.reportPeriod)
+ case <-hrd.chStop:
+ return
+ }
+ }
+}
diff --git a/core/services/headreporter/head_reporter_mock.go b/core/services/headreporter/head_reporter_mock.go
new file mode 100644
index 00000000000..21978abb86a
--- /dev/null
+++ b/core/services/headreporter/head_reporter_mock.go
@@ -0,0 +1,130 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package headreporter
+
+import (
+ context "context"
+
+ types "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// MockHeadReporter is an autogenerated mock type for the HeadReporter type
+type MockHeadReporter struct {
+ mock.Mock
+}
+
+type MockHeadReporter_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockHeadReporter) EXPECT() *MockHeadReporter_Expecter {
+ return &MockHeadReporter_Expecter{mock: &_m.Mock}
+}
+
+// ReportNewHead provides a mock function with given fields: ctx, head
+func (_m *MockHeadReporter) ReportNewHead(ctx context.Context, head *types.Head) error {
+ ret := _m.Called(ctx, head)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ReportNewHead")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, *types.Head) error); ok {
+ r0 = rf(ctx, head)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// MockHeadReporter_ReportNewHead_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReportNewHead'
+type MockHeadReporter_ReportNewHead_Call struct {
+ *mock.Call
+}
+
+// ReportNewHead is a helper method to define mock.On call
+// - ctx context.Context
+// - head *types.Head
+func (_e *MockHeadReporter_Expecter) ReportNewHead(ctx interface{}, head interface{}) *MockHeadReporter_ReportNewHead_Call {
+ return &MockHeadReporter_ReportNewHead_Call{Call: _e.mock.On("ReportNewHead", ctx, head)}
+}
+
+func (_c *MockHeadReporter_ReportNewHead_Call) Run(run func(ctx context.Context, head *types.Head)) *MockHeadReporter_ReportNewHead_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(*types.Head))
+ })
+ return _c
+}
+
+func (_c *MockHeadReporter_ReportNewHead_Call) Return(_a0 error) *MockHeadReporter_ReportNewHead_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *MockHeadReporter_ReportNewHead_Call) RunAndReturn(run func(context.Context, *types.Head) error) *MockHeadReporter_ReportNewHead_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ReportPeriodic provides a mock function with given fields: ctx
+func (_m *MockHeadReporter) ReportPeriodic(ctx context.Context) error {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ReportPeriodic")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// MockHeadReporter_ReportPeriodic_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReportPeriodic'
+type MockHeadReporter_ReportPeriodic_Call struct {
+ *mock.Call
+}
+
+// ReportPeriodic is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *MockHeadReporter_Expecter) ReportPeriodic(ctx interface{}) *MockHeadReporter_ReportPeriodic_Call {
+ return &MockHeadReporter_ReportPeriodic_Call{Call: _e.mock.On("ReportPeriodic", ctx)}
+}
+
+func (_c *MockHeadReporter_ReportPeriodic_Call) Run(run func(ctx context.Context)) *MockHeadReporter_ReportPeriodic_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *MockHeadReporter_ReportPeriodic_Call) Return(_a0 error) *MockHeadReporter_ReportPeriodic_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *MockHeadReporter_ReportPeriodic_Call) RunAndReturn(run func(context.Context) error) *MockHeadReporter_ReportPeriodic_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockHeadReporter creates a new instance of MockHeadReporter. 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 NewMockHeadReporter(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockHeadReporter {
+ mock := &MockHeadReporter{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/headreporter/head_reporter_test.go b/core/services/headreporter/head_reporter_test.go
new file mode 100644
index 00000000000..304dd59a478
--- /dev/null
+++ b/core/services/headreporter/head_reporter_test.go
@@ -0,0 +1,51 @@
+package headreporter
+
+import (
+ "sync/atomic"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ 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/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+func NewHead() evmtypes.Head {
+ return evmtypes.Head{Number: 42, EVMChainID: ubig.NewI(0)}
+}
+
+func Test_HeadReporterService(t *testing.T) {
+ t.Run("report everything", func(t *testing.T) {
+ db := pgtest.NewSqlxDB(t)
+
+ headReporter := NewMockHeadReporter(t)
+ service := NewHeadReporterService(db, logger.TestLogger(t), headReporter)
+ service.reportPeriod = time.Second
+ err := service.Start(testutils.Context(t))
+ require.NoError(t, err)
+
+ var reportCalls atomic.Int32
+ head := NewHead()
+ headReporter.On("ReportNewHead", mock.Anything, &head).Run(func(args mock.Arguments) {
+ reportCalls.Add(1)
+ }).Return(nil)
+ headReporter.On("ReportPeriodic", mock.Anything).Run(func(args mock.Arguments) {
+ reportCalls.Add(1)
+ }).Return(nil)
+ service.OnNewLongestChain(testutils.Context(t), &head)
+
+ require.Eventually(t, func() bool { return reportCalls.Load() == 2 }, 5*time.Second, 100*time.Millisecond)
+ })
+
+ t.Run("has default report period", func(t *testing.T) {
+ service := NewHeadReporterService(pgtest.NewSqlxDB(t), logger.TestLogger(t), NewMockHeadReporter(t))
+ assert.Equal(t, service.reportPeriod, 15*time.Second)
+ })
+}
diff --git a/core/services/headreporter/helper_test.go b/core/services/headreporter/helper_test.go
new file mode 100644
index 00000000000..fa05182a851
--- /dev/null
+++ b/core/services/headreporter/helper_test.go
@@ -0,0 +1,5 @@
+package headreporter
+
+func (p *prometheusReporter) SetBackend(b PrometheusBackend) {
+ p.backend = b
+}
diff --git a/core/services/headreporter/prometheus_backend_mock.go b/core/services/headreporter/prometheus_backend_mock.go
new file mode 100644
index 00000000000..ca83f6c4fbb
--- /dev/null
+++ b/core/services/headreporter/prometheus_backend_mock.go
@@ -0,0 +1,204 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package headreporter
+
+import (
+ big "math/big"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// MockPrometheusBackend is an autogenerated mock type for the PrometheusBackend type
+type MockPrometheusBackend struct {
+ mock.Mock
+}
+
+type MockPrometheusBackend_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockPrometheusBackend) EXPECT() *MockPrometheusBackend_Expecter {
+ return &MockPrometheusBackend_Expecter{mock: &_m.Mock}
+}
+
+// SetMaxUnconfirmedAge provides a mock function with given fields: _a0, _a1
+func (_m *MockPrometheusBackend) SetMaxUnconfirmedAge(_a0 *big.Int, _a1 float64) {
+ _m.Called(_a0, _a1)
+}
+
+// MockPrometheusBackend_SetMaxUnconfirmedAge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetMaxUnconfirmedAge'
+type MockPrometheusBackend_SetMaxUnconfirmedAge_Call struct {
+ *mock.Call
+}
+
+// SetMaxUnconfirmedAge is a helper method to define mock.On call
+// - _a0 *big.Int
+// - _a1 float64
+func (_e *MockPrometheusBackend_Expecter) SetMaxUnconfirmedAge(_a0 interface{}, _a1 interface{}) *MockPrometheusBackend_SetMaxUnconfirmedAge_Call {
+ return &MockPrometheusBackend_SetMaxUnconfirmedAge_Call{Call: _e.mock.On("SetMaxUnconfirmedAge", _a0, _a1)}
+}
+
+func (_c *MockPrometheusBackend_SetMaxUnconfirmedAge_Call) Run(run func(_a0 *big.Int, _a1 float64)) *MockPrometheusBackend_SetMaxUnconfirmedAge_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(float64))
+ })
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetMaxUnconfirmedAge_Call) Return() *MockPrometheusBackend_SetMaxUnconfirmedAge_Call {
+ _c.Call.Return()
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetMaxUnconfirmedAge_Call) RunAndReturn(run func(*big.Int, float64)) *MockPrometheusBackend_SetMaxUnconfirmedAge_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetMaxUnconfirmedBlocks provides a mock function with given fields: _a0, _a1
+func (_m *MockPrometheusBackend) SetMaxUnconfirmedBlocks(_a0 *big.Int, _a1 int64) {
+ _m.Called(_a0, _a1)
+}
+
+// MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetMaxUnconfirmedBlocks'
+type MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call struct {
+ *mock.Call
+}
+
+// SetMaxUnconfirmedBlocks is a helper method to define mock.On call
+// - _a0 *big.Int
+// - _a1 int64
+func (_e *MockPrometheusBackend_Expecter) SetMaxUnconfirmedBlocks(_a0 interface{}, _a1 interface{}) *MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call {
+ return &MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call{Call: _e.mock.On("SetMaxUnconfirmedBlocks", _a0, _a1)}
+}
+
+func (_c *MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call) Run(run func(_a0 *big.Int, _a1 int64)) *MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(int64))
+ })
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call) Return() *MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call {
+ _c.Call.Return()
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call) RunAndReturn(run func(*big.Int, int64)) *MockPrometheusBackend_SetMaxUnconfirmedBlocks_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetPipelineRunsQueued provides a mock function with given fields: n
+func (_m *MockPrometheusBackend) SetPipelineRunsQueued(n int) {
+ _m.Called(n)
+}
+
+// MockPrometheusBackend_SetPipelineRunsQueued_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPipelineRunsQueued'
+type MockPrometheusBackend_SetPipelineRunsQueued_Call struct {
+ *mock.Call
+}
+
+// SetPipelineRunsQueued is a helper method to define mock.On call
+// - n int
+func (_e *MockPrometheusBackend_Expecter) SetPipelineRunsQueued(n interface{}) *MockPrometheusBackend_SetPipelineRunsQueued_Call {
+ return &MockPrometheusBackend_SetPipelineRunsQueued_Call{Call: _e.mock.On("SetPipelineRunsQueued", n)}
+}
+
+func (_c *MockPrometheusBackend_SetPipelineRunsQueued_Call) Run(run func(n int)) *MockPrometheusBackend_SetPipelineRunsQueued_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(int))
+ })
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetPipelineRunsQueued_Call) Return() *MockPrometheusBackend_SetPipelineRunsQueued_Call {
+ _c.Call.Return()
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetPipelineRunsQueued_Call) RunAndReturn(run func(int)) *MockPrometheusBackend_SetPipelineRunsQueued_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetPipelineTaskRunsQueued provides a mock function with given fields: n
+func (_m *MockPrometheusBackend) SetPipelineTaskRunsQueued(n int) {
+ _m.Called(n)
+}
+
+// MockPrometheusBackend_SetPipelineTaskRunsQueued_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetPipelineTaskRunsQueued'
+type MockPrometheusBackend_SetPipelineTaskRunsQueued_Call struct {
+ *mock.Call
+}
+
+// SetPipelineTaskRunsQueued is a helper method to define mock.On call
+// - n int
+func (_e *MockPrometheusBackend_Expecter) SetPipelineTaskRunsQueued(n interface{}) *MockPrometheusBackend_SetPipelineTaskRunsQueued_Call {
+ return &MockPrometheusBackend_SetPipelineTaskRunsQueued_Call{Call: _e.mock.On("SetPipelineTaskRunsQueued", n)}
+}
+
+func (_c *MockPrometheusBackend_SetPipelineTaskRunsQueued_Call) Run(run func(n int)) *MockPrometheusBackend_SetPipelineTaskRunsQueued_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(int))
+ })
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetPipelineTaskRunsQueued_Call) Return() *MockPrometheusBackend_SetPipelineTaskRunsQueued_Call {
+ _c.Call.Return()
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetPipelineTaskRunsQueued_Call) RunAndReturn(run func(int)) *MockPrometheusBackend_SetPipelineTaskRunsQueued_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetUnconfirmedTransactions provides a mock function with given fields: _a0, _a1
+func (_m *MockPrometheusBackend) SetUnconfirmedTransactions(_a0 *big.Int, _a1 int64) {
+ _m.Called(_a0, _a1)
+}
+
+// MockPrometheusBackend_SetUnconfirmedTransactions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetUnconfirmedTransactions'
+type MockPrometheusBackend_SetUnconfirmedTransactions_Call struct {
+ *mock.Call
+}
+
+// SetUnconfirmedTransactions is a helper method to define mock.On call
+// - _a0 *big.Int
+// - _a1 int64
+func (_e *MockPrometheusBackend_Expecter) SetUnconfirmedTransactions(_a0 interface{}, _a1 interface{}) *MockPrometheusBackend_SetUnconfirmedTransactions_Call {
+ return &MockPrometheusBackend_SetUnconfirmedTransactions_Call{Call: _e.mock.On("SetUnconfirmedTransactions", _a0, _a1)}
+}
+
+func (_c *MockPrometheusBackend_SetUnconfirmedTransactions_Call) Run(run func(_a0 *big.Int, _a1 int64)) *MockPrometheusBackend_SetUnconfirmedTransactions_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(int64))
+ })
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetUnconfirmedTransactions_Call) Return() *MockPrometheusBackend_SetUnconfirmedTransactions_Call {
+ _c.Call.Return()
+ return _c
+}
+
+func (_c *MockPrometheusBackend_SetUnconfirmedTransactions_Call) RunAndReturn(run func(*big.Int, int64)) *MockPrometheusBackend_SetUnconfirmedTransactions_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockPrometheusBackend creates a new instance of MockPrometheusBackend. 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 NewMockPrometheusBackend(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockPrometheusBackend {
+ mock := &MockPrometheusBackend{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/promreporter/prom_reporter.go b/core/services/headreporter/prometheus_reporter.go
similarity index 63%
rename from core/services/promreporter/prom_reporter.go
rename to core/services/headreporter/prometheus_reporter.go
index 31d5f1129ef..3e39c7aca45 100644
--- a/core/services/promreporter/prom_reporter.go
+++ b/core/services/headreporter/prometheus_reporter.go
@@ -1,40 +1,28 @@
-package promreporter
+package headreporter
import (
"context"
"fmt"
"math/big"
- "sync"
"time"
- "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
- txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr"
- "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
-
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"go.uber.org/multierr"
- "github.com/smartcontractkit/chainlink-common/pkg/services"
- "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
-
+ "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+ txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr"
+ "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"
)
type (
- promReporter struct {
- services.StateMachine
- ds sqlutil.DataSource
- chains legacyevm.LegacyChainContainer
- lggr logger.Logger
- backend PrometheusBackend
- newHeads *mailbox.Mailbox[*evmtypes.Head]
- chStop services.StopChan
- wgDone sync.WaitGroup
- reportPeriod time.Duration
+ prometheusReporter struct {
+ ds sqlutil.DataSource
+ chains legacyevm.LegacyChainContainer
+ backend PrometheusBackend
}
PrometheusBackend interface {
@@ -71,103 +59,15 @@ var (
})
)
-func (defaultBackend) SetUnconfirmedTransactions(evmChainID *big.Int, n int64) {
- promUnconfirmedTransactions.WithLabelValues(evmChainID.String()).Set(float64(n))
-}
-
-func (defaultBackend) SetMaxUnconfirmedAge(evmChainID *big.Int, s float64) {
- promMaxUnconfirmedAge.WithLabelValues(evmChainID.String()).Set(s)
-}
-
-func (defaultBackend) SetMaxUnconfirmedBlocks(evmChainID *big.Int, n int64) {
- promMaxUnconfirmedBlocks.WithLabelValues(evmChainID.String()).Set(float64(n))
-}
-
-func (defaultBackend) SetPipelineRunsQueued(n int) {
- promPipelineTaskRunsQueued.Set(float64(n))
-}
-
-func (defaultBackend) SetPipelineTaskRunsQueued(n int) {
- promPipelineRunsQueued.Set(float64(n))
-}
-
-func NewPromReporter(ds sqlutil.DataSource, chainContainer legacyevm.LegacyChainContainer, lggr logger.Logger, opts ...interface{}) *promReporter {
- var backend PrometheusBackend = defaultBackend{}
- period := 15 * time.Second
- for _, opt := range opts {
- switch v := opt.(type) {
- case time.Duration:
- period = v
- case PrometheusBackend:
- backend = v
- }
- }
-
- chStop := make(chan struct{})
- return &promReporter{
- ds: ds,
- chains: chainContainer,
- lggr: lggr.Named("PromReporter"),
- backend: backend,
- newHeads: mailbox.NewSingle[*evmtypes.Head](),
- chStop: chStop,
- reportPeriod: period,
+func NewPrometheusReporter(ds sqlutil.DataSource, chainContainer legacyevm.LegacyChainContainer) *prometheusReporter {
+ return &prometheusReporter{
+ ds: ds,
+ chains: chainContainer,
+ backend: defaultBackend{},
}
}
-// Start starts PromReporter.
-func (pr *promReporter) Start(context.Context) error {
- return pr.StartOnce("PromReporter", func() error {
- pr.wgDone.Add(1)
- go pr.eventLoop()
- return nil
- })
-}
-
-func (pr *promReporter) Close() error {
- return pr.StopOnce("PromReporter", func() error {
- close(pr.chStop)
- pr.wgDone.Wait()
- return nil
- })
-}
-func (pr *promReporter) Name() string {
- return pr.lggr.Name()
-}
-
-func (pr *promReporter) HealthReport() map[string]error {
- return map[string]error{pr.Name(): pr.Healthy()}
-}
-
-func (pr *promReporter) OnNewLongestChain(ctx context.Context, head *evmtypes.Head) {
- pr.newHeads.Deliver(head)
-}
-
-func (pr *promReporter) eventLoop() {
- pr.lggr.Debug("Starting event loop")
- defer pr.wgDone.Done()
- ctx, cancel := pr.chStop.NewCtx()
- defer cancel()
- for {
- select {
- case <-pr.newHeads.Notify():
- head, exists := pr.newHeads.Retrieve()
- if !exists {
- continue
- }
- pr.reportHeadMetrics(ctx, head)
- case <-time.After(pr.reportPeriod):
- if err := errors.Wrap(pr.reportPipelineRunStats(ctx), "reportPipelineRunStats failed"); err != nil {
- pr.lggr.Errorw("Error reporting prometheus metrics", "err", err)
- }
-
- case <-pr.chStop:
- return
- }
- }
-}
-
-func (pr *promReporter) getTxm(evmChainID *big.Int) (txmgr.TxManager, error) {
+func (pr *prometheusReporter) getTxm(evmChainID *big.Int) (txmgr.TxManager, error) {
chain, err := pr.chains.Get(evmChainID.String())
if err != nil {
return nil, fmt.Errorf("failed to get chain: %w", err)
@@ -175,20 +75,16 @@ func (pr *promReporter) getTxm(evmChainID *big.Int) (txmgr.TxManager, error) {
return chain.TxManager(), nil
}
-func (pr *promReporter) reportHeadMetrics(ctx context.Context, head *evmtypes.Head) {
+func (pr *prometheusReporter) ReportNewHead(ctx context.Context, head *evmtypes.Head) error {
evmChainID := head.EVMChainID.ToInt()
- err := multierr.Combine(
+ return multierr.Combine(
errors.Wrap(pr.reportPendingEthTxes(ctx, evmChainID), "reportPendingEthTxes failed"),
errors.Wrap(pr.reportMaxUnconfirmedAge(ctx, evmChainID), "reportMaxUnconfirmedAge failed"),
errors.Wrap(pr.reportMaxUnconfirmedBlocks(ctx, head), "reportMaxUnconfirmedBlocks failed"),
)
-
- if err != nil && ctx.Err() == nil {
- pr.lggr.Errorw("Error reporting prometheus metrics", "err", err)
- }
}
-func (pr *promReporter) reportPendingEthTxes(ctx context.Context, evmChainID *big.Int) (err error) {
+func (pr *prometheusReporter) reportPendingEthTxes(ctx context.Context, evmChainID *big.Int) (err error) {
txm, err := pr.getTxm(evmChainID)
if err != nil {
return fmt.Errorf("failed to get txm: %w", err)
@@ -202,7 +98,7 @@ func (pr *promReporter) reportPendingEthTxes(ctx context.Context, evmChainID *bi
return nil
}
-func (pr *promReporter) reportMaxUnconfirmedAge(ctx context.Context, evmChainID *big.Int) (err error) {
+func (pr *prometheusReporter) reportMaxUnconfirmedAge(ctx context.Context, evmChainID *big.Int) (err error) {
txm, err := pr.getTxm(evmChainID)
if err != nil {
return fmt.Errorf("failed to get txm: %w", err)
@@ -221,7 +117,7 @@ func (pr *promReporter) reportMaxUnconfirmedAge(ctx context.Context, evmChainID
return nil
}
-func (pr *promReporter) reportMaxUnconfirmedBlocks(ctx context.Context, head *evmtypes.Head) (err error) {
+func (pr *prometheusReporter) reportMaxUnconfirmedBlocks(ctx context.Context, head *evmtypes.Head) (err error) {
txm, err := pr.getTxm(head.EVMChainID.ToInt())
if err != nil {
return fmt.Errorf("failed to get txm: %w", err)
@@ -240,7 +136,11 @@ func (pr *promReporter) reportMaxUnconfirmedBlocks(ctx context.Context, head *ev
return nil
}
-func (pr *promReporter) reportPipelineRunStats(ctx context.Context) (err error) {
+func (pr *prometheusReporter) ReportPeriodic(ctx context.Context) error {
+ return errors.Wrap(pr.reportPipelineRunStats(ctx), "reportPipelineRunStats failed")
+}
+
+func (pr *prometheusReporter) reportPipelineRunStats(ctx context.Context) (err error) {
rows, err := pr.ds.QueryContext(ctx, `
SELECT pipeline_run_id FROM pipeline_task_runs WHERE finished_at IS NULL
`)
@@ -271,3 +171,23 @@ SELECT pipeline_run_id FROM pipeline_task_runs WHERE finished_at IS NULL
return nil
}
+
+func (defaultBackend) SetUnconfirmedTransactions(evmChainID *big.Int, n int64) {
+ promUnconfirmedTransactions.WithLabelValues(evmChainID.String()).Set(float64(n))
+}
+
+func (defaultBackend) SetMaxUnconfirmedAge(evmChainID *big.Int, s float64) {
+ promMaxUnconfirmedAge.WithLabelValues(evmChainID.String()).Set(s)
+}
+
+func (defaultBackend) SetMaxUnconfirmedBlocks(evmChainID *big.Int, n int64) {
+ promMaxUnconfirmedBlocks.WithLabelValues(evmChainID.String()).Set(float64(n))
+}
+
+func (defaultBackend) SetPipelineRunsQueued(n int) {
+ promPipelineTaskRunsQueued.Set(float64(n))
+}
+
+func (defaultBackend) SetPipelineTaskRunsQueued(n int) {
+ promPipelineRunsQueued.Set(float64(n))
+}
diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/headreporter/prometheus_reporter_test.go
similarity index 64%
rename from core/services/promreporter/prom_reporter_test.go
rename to core/services/headreporter/prometheus_reporter_test.go
index b61fa25bdc4..d96e617fd79 100644
--- a/core/services/promreporter/prom_reporter_test.go
+++ b/core/services/headreporter/prometheus_reporter_test.go
@@ -1,8 +1,7 @@
-package promreporter_test
+package headreporter_test
import (
"math/big"
- "sync/atomic"
"testing"
"time"
@@ -10,90 +9,40 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
- "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest"
-
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
"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"
- ubig "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"
- "github.com/smartcontractkit/chainlink/v2/core/internal/mocks"
"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/promreporter"
+ "github.com/smartcontractkit/chainlink/v2/core/services/headreporter"
)
-func newHead() evmtypes.Head {
- return evmtypes.Head{Number: 42, EVMChainID: ubig.NewI(0)}
-}
-
-func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainContainer {
- config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t)
- keyStore := cltest.NewKeyStore(t, db).Eth()
- ethClient := evmtest.NewEthClientMockWithDefaultChain(t)
- estimator, err := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator())
- require.NoError(t, err)
- lggr := logger.TestLogger(t)
- lpOpts := logpoller.Opts{
- PollPeriod: 100 * time.Millisecond,
- FinalityDepth: 2,
- BackfillBatchSize: 3,
- RpcBatchSize: 2,
- KeepFinalizedBlocksDepth: 1000,
- }
- ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
- lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), ethClient, lggr, ht, lpOpts)
-
- txm, err := txmgr.NewTxm(
- db,
- evmConfig,
- evmConfig.GasEstimator(),
- evmConfig.Transactions(),
- nil,
- dbConfig,
- dbConfig.Listener(),
- ethClient,
- lggr,
- lp,
- keyStore,
- estimator)
- require.NoError(t, err)
-
- cfg := configtest.NewGeneralConfig(t, nil)
- return cltest.NewLegacyChainsWithMockChainAndTxManager(t, ethClient, cfg, txm)
-}
-
-func Test_PromReporter_OnNewLongestChain(t *testing.T) {
+func Test_PrometheusReporter(t *testing.T) {
t.Run("with nothing in the database", func(t *testing.T) {
db := pgtest.NewSqlxDB(t)
- backend := mocks.NewPrometheusBackend(t)
- reporter := promreporter.NewPromReporter(db, newLegacyChainContainer(t, db), logger.TestLogger(t), backend, 10*time.Millisecond)
-
- var subscribeCalls atomic.Int32
-
+ backend := headreporter.NewMockPrometheusBackend(t)
backend.On("SetUnconfirmedTransactions", big.NewInt(0), int64(0)).Return()
backend.On("SetMaxUnconfirmedAge", big.NewInt(0), float64(0)).Return()
backend.On("SetMaxUnconfirmedBlocks", big.NewInt(0), int64(0)).Return()
- backend.On("SetPipelineTaskRunsQueued", 0).Return()
- backend.On("SetPipelineRunsQueued", 0).
- Run(func(args mock.Arguments) {
- subscribeCalls.Add(1)
- }).
- Return()
- servicetest.Run(t, reporter)
+ reporter := headreporter.NewPrometheusReporter(db, newLegacyChainContainer(t, db))
+ reporter.SetBackend(backend)
- head := newHead()
- reporter.OnNewLongestChain(testutils.Context(t), &head)
+ head := headreporter.NewHead()
+ err := reporter.ReportNewHead(testutils.Context(t), &head)
+ require.NoError(t, err)
- require.Eventually(t, func() bool { return subscribeCalls.Load() >= 1 }, 12*time.Second, 100*time.Millisecond)
+ backend.On("SetPipelineTaskRunsQueued", 0).Return()
+ backend.On("SetPipelineRunsQueued", 0).Return()
+ err = reporter.ReportPeriodic(testutils.Context(t))
+ require.NoError(t, err)
})
t.Run("with unconfirmed evm.txes", func(t *testing.T) {
@@ -102,61 +51,93 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) {
ethKeyStore := cltest.NewKeyStore(t, db).Eth()
_, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore)
- var subscribeCalls atomic.Int32
+ etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress)
+ cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress)
+ cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress)
+ require.NoError(t, txStore.UpdateTxAttemptBroadcastBeforeBlockNum(testutils.Context(t), etx.ID, 7))
- backend := mocks.NewPrometheusBackend(t)
+ backend := headreporter.NewMockPrometheusBackend(t)
backend.On("SetUnconfirmedTransactions", big.NewInt(0), int64(3)).Return()
backend.On("SetMaxUnconfirmedAge", big.NewInt(0), mock.MatchedBy(func(s float64) bool {
return s > 0
})).Return()
backend.On("SetMaxUnconfirmedBlocks", big.NewInt(0), int64(35)).Return()
- backend.On("SetPipelineTaskRunsQueued", 0).Return()
- backend.On("SetPipelineRunsQueued", 0).
- Run(func(args mock.Arguments) {
- subscribeCalls.Add(1)
- }).
- Return()
- reporter := promreporter.NewPromReporter(db, newLegacyChainContainer(t, db), logger.TestLogger(t), backend, 10*time.Millisecond)
- servicetest.Run(t, reporter)
- etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress)
- cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress)
- cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress)
- require.NoError(t, txStore.UpdateTxAttemptBroadcastBeforeBlockNum(testutils.Context(t), etx.ID, 7))
+ reporter := headreporter.NewPrometheusReporter(db, newLegacyChainContainer(t, db))
+ reporter.SetBackend(backend)
+
+ head := headreporter.NewHead()
+ err := reporter.ReportNewHead(testutils.Context(t), &head)
+ require.NoError(t, err)
- head := newHead()
- reporter.OnNewLongestChain(testutils.Context(t), &head)
+ backend.On("SetPipelineTaskRunsQueued", 0).Return()
+ backend.On("SetPipelineRunsQueued", 0).Return()
- require.Eventually(t, func() bool { return subscribeCalls.Load() >= 1 }, 12*time.Second, 100*time.Millisecond)
+ err = reporter.ReportPeriodic(testutils.Context(t))
+ require.NoError(t, err)
})
t.Run("with unfinished pipeline task runs", func(t *testing.T) {
db := pgtest.NewSqlxDB(t)
pgtest.MustExec(t, db, `SET CONSTRAINTS pipeline_task_runs_pipeline_run_id_fkey DEFERRED`)
- backend := mocks.NewPrometheusBackend(t)
- reporter := promreporter.NewPromReporter(db, newLegacyChainContainer(t, db), logger.TestLogger(t), backend, 10*time.Millisecond)
-
cltest.MustInsertUnfinishedPipelineTaskRun(t, db, 1)
cltest.MustInsertUnfinishedPipelineTaskRun(t, db, 1)
cltest.MustInsertUnfinishedPipelineTaskRun(t, db, 2)
- var subscribeCalls atomic.Int32
-
+ backend := headreporter.NewMockPrometheusBackend(t)
backend.On("SetUnconfirmedTransactions", big.NewInt(0), int64(0)).Return()
backend.On("SetMaxUnconfirmedAge", big.NewInt(0), float64(0)).Return()
backend.On("SetMaxUnconfirmedBlocks", big.NewInt(0), int64(0)).Return()
- backend.On("SetPipelineTaskRunsQueued", 3).Return()
- backend.On("SetPipelineRunsQueued", 2).
- Run(func(args mock.Arguments) {
- subscribeCalls.Add(1)
- }).
- Return()
- servicetest.Run(t, reporter)
- head := newHead()
- reporter.OnNewLongestChain(testutils.Context(t), &head)
+ reporter := headreporter.NewPrometheusReporter(db, newLegacyChainContainer(t, db))
+ reporter.SetBackend(backend)
+
+ head := headreporter.NewHead()
+ err := reporter.ReportNewHead(testutils.Context(t), &head)
+ require.NoError(t, err)
+
+ backend.On("SetPipelineTaskRunsQueued", 3).Return()
+ backend.On("SetPipelineRunsQueued", 2).Return()
- require.Eventually(t, func() bool { return subscribeCalls.Load() >= 1 }, 12*time.Second, 100*time.Millisecond)
+ err = reporter.ReportPeriodic(testutils.Context(t))
+ require.NoError(t, err)
})
}
+
+func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainContainer {
+ config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t)
+ keyStore := cltest.NewKeyStore(t, db).Eth()
+ ethClient := evmtest.NewEthClientMockWithDefaultChain(t)
+ estimator, err := gas.NewEstimator(logger.TestLogger(t), ethClient, config, evmConfig.GasEstimator())
+ require.NoError(t, err)
+ lggr := logger.TestLogger(t)
+ lpOpts := logpoller.Opts{
+ PollPeriod: 100 * time.Millisecond,
+ FinalityDepth: 2,
+ BackfillBatchSize: 3,
+ RpcBatchSize: 2,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+ ht := headtracker.NewSimulatedHeadTracker(ethClient, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.FixtureChainID, db, lggr), ethClient, lggr, ht, lpOpts)
+
+ txm, err := txmgr.NewTxm(
+ db,
+ evmConfig,
+ evmConfig.GasEstimator(),
+ evmConfig.Transactions(),
+ nil,
+ dbConfig,
+ dbConfig.Listener(),
+ ethClient,
+ lggr,
+ lp,
+ keyStore,
+ estimator,
+ ht)
+ require.NoError(t, err)
+
+ cfg := configtest.NewGeneralConfig(t, nil)
+ return cltest.NewLegacyChainsWithMockChainAndTxManager(t, ethClient, cfg, txm)
+}
diff --git a/core/services/headreporter/telemetry_reporter.go b/core/services/headreporter/telemetry_reporter.go
new file mode 100644
index 00000000000..93852f44c0d
--- /dev/null
+++ b/core/services/headreporter/telemetry_reporter.go
@@ -0,0 +1,68 @@
+package headreporter
+
+import (
+ "context"
+ "math/big"
+
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/libocr/commontypes"
+ "google.golang.org/protobuf/proto"
+
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
+ "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem"
+ "github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
+)
+
+type telemetryReporter struct {
+ lggr logger.Logger
+ endpoints map[uint64]commontypes.MonitoringEndpoint
+}
+
+func NewTelemetryReporter(monitoringEndpointGen telemetry.MonitoringEndpointGenerator, lggr logger.Logger, chainIDs ...*big.Int) HeadReporter {
+ endpoints := make(map[uint64]commontypes.MonitoringEndpoint)
+ for _, chainID := range chainIDs {
+ endpoints[chainID.Uint64()] = monitoringEndpointGen.GenMonitoringEndpoint("EVM", chainID.String(), "", synchronization.HeadReport)
+ }
+ return &telemetryReporter{lggr: lggr.Named("TelemetryReporter"), endpoints: endpoints}
+}
+
+func (t *telemetryReporter) ReportNewHead(ctx context.Context, head *evmtypes.Head) error {
+ monitoringEndpoint := t.endpoints[head.EVMChainID.ToInt().Uint64()]
+ if monitoringEndpoint == nil {
+ return errors.Errorf("No monitoring endpoint provided chain_id=%d", head.EVMChainID.Int64())
+ }
+ var finalized *telem.Block
+ latestFinalizedHead := head.LatestFinalizedHead()
+ if latestFinalizedHead != nil {
+ finalized = &telem.Block{
+ Timestamp: uint64(latestFinalizedHead.GetTimestamp().UTC().Unix()),
+ Number: uint64(latestFinalizedHead.BlockNumber()),
+ Hash: latestFinalizedHead.BlockHash().Hex(),
+ }
+ }
+ request := &telem.HeadReportRequest{
+ Latest: &telem.Block{
+ Timestamp: uint64(head.Timestamp.UTC().Unix()),
+ Number: uint64(head.Number),
+ Hash: head.Hash.Hex(),
+ },
+ Finalized: finalized,
+ }
+ bytes, err := proto.Marshal(request)
+ if err != nil {
+ return errors.WithMessage(err, "telem.HeadReportRequest marshal error")
+ }
+ monitoringEndpoint.SendLog(bytes)
+ if finalized == nil {
+ t.lggr.Infow("No finalized block was found", "chainID", head.EVMChainID.Int64(),
+ "head.number", head.Number, "chainLength", head.ChainLength())
+ }
+ return nil
+}
+
+func (t *telemetryReporter) ReportPeriodic(ctx context.Context) error {
+ return nil
+}
diff --git a/core/services/headreporter/telemetry_reporter_test.go b/core/services/headreporter/telemetry_reporter_test.go
new file mode 100644
index 00000000000..58c09354905
--- /dev/null
+++ b/core/services/headreporter/telemetry_reporter_test.go
@@ -0,0 +1,106 @@
+package headreporter_test
+
+import (
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "google.golang.org/protobuf/proto"
+
+ mocks2 "github.com/smartcontractkit/chainlink/v2/common/types/mocks"
+ 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/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/headreporter"
+ "github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
+ "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem"
+ "github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
+)
+
+func Test_TelemetryReporter_NewHead(t *testing.T) {
+ head := evmtypes.Head{
+ Number: 42,
+ EVMChainID: ubig.NewI(100),
+ Hash: common.HexToHash("0x1010"),
+ Timestamp: time.UnixMilli(1000),
+ IsFinalized: false,
+ Parent: &evmtypes.Head{
+ Number: 41,
+ Hash: common.HexToHash("0x1009"),
+ Timestamp: time.UnixMilli(999),
+ IsFinalized: true,
+ },
+ }
+ requestBytes, err := proto.Marshal(&telem.HeadReportRequest{
+ Latest: &telem.Block{
+ Timestamp: uint64(head.Timestamp.UTC().Unix()),
+ Number: 42,
+ Hash: head.Hash.Hex(),
+ },
+ Finalized: &telem.Block{
+ Timestamp: uint64(head.Parent.Timestamp.UTC().Unix()),
+ Number: 41,
+ Hash: head.Parent.Hash.Hex(),
+ },
+ })
+ assert.NoError(t, err)
+
+ monitoringEndpoint := mocks2.NewMonitoringEndpoint(t)
+ monitoringEndpoint.On("SendLog", requestBytes).Return()
+
+ monitoringEndpointGen := telemetry.NewMockMonitoringEndpointGenerator(t)
+ monitoringEndpointGen.
+ On("GenMonitoringEndpoint", "EVM", "100", "", synchronization.HeadReport).
+ Return(monitoringEndpoint)
+ reporter := headreporter.NewTelemetryReporter(monitoringEndpointGen, logger.TestLogger(t), big.NewInt(100))
+
+ err = reporter.ReportNewHead(testutils.Context(t), &head)
+ assert.NoError(t, err)
+}
+
+func Test_TelemetryReporter_NewHeadMissingFinalized(t *testing.T) {
+ head := evmtypes.Head{
+ Number: 42,
+ EVMChainID: ubig.NewI(100),
+ Hash: common.HexToHash("0x1010"),
+ Timestamp: time.UnixMilli(1000),
+ IsFinalized: false,
+ }
+ requestBytes, err := proto.Marshal(&telem.HeadReportRequest{
+ Latest: &telem.Block{
+ Timestamp: uint64(head.Timestamp.UTC().Unix()),
+ Number: 42,
+ Hash: head.Hash.Hex(),
+ },
+ })
+ assert.NoError(t, err)
+
+ monitoringEndpoint := mocks2.NewMonitoringEndpoint(t)
+ monitoringEndpoint.On("SendLog", requestBytes).Return()
+
+ monitoringEndpointGen := telemetry.NewMockMonitoringEndpointGenerator(t)
+ monitoringEndpointGen.
+ On("GenMonitoringEndpoint", "EVM", "100", "", synchronization.HeadReport).
+ Return(monitoringEndpoint)
+ reporter := headreporter.NewTelemetryReporter(monitoringEndpointGen, logger.TestLogger(t), big.NewInt(100))
+
+ err = reporter.ReportNewHead(testutils.Context(t), &head)
+ assert.NoError(t, err)
+}
+
+func Test_TelemetryReporter_NewHead_MissingEndpoint(t *testing.T) {
+ monitoringEndpointGen := telemetry.NewMockMonitoringEndpointGenerator(t)
+ monitoringEndpointGen.
+ On("GenMonitoringEndpoint", "EVM", "100", "", synchronization.HeadReport).
+ Return(nil)
+
+ reporter := headreporter.NewTelemetryReporter(monitoringEndpointGen, logger.TestLogger(t), big.NewInt(100))
+
+ head := evmtypes.Head{Number: 42, EVMChainID: ubig.NewI(100)}
+
+ err := reporter.ReportNewHead(testutils.Context(t), &head)
+ assert.Errorf(t, err, "No monitoring endpoint provided chain_id=100")
+}
diff --git a/core/services/job/models.go b/core/services/job/models.go
index 2f864efe300..1c46d08c59c 100644
--- a/core/services/job/models.go
+++ b/core/services/job/models.go
@@ -38,6 +38,7 @@ const (
BlockhashStore Type = (Type)(pipeline.BlockhashStoreJobType)
Bootstrap Type = (Type)(pipeline.BootstrapJobType)
Cron Type = (Type)(pipeline.CronJobType)
+ CCIP Type = (Type)(pipeline.CCIPJobType)
DirectRequest Type = (Type)(pipeline.DirectRequestJobType)
FluxMonitor Type = (Type)(pipeline.FluxMonitorJobType)
Gateway Type = (Type)(pipeline.GatewayJobType)
@@ -78,6 +79,7 @@ var (
BlockhashStore: false,
Bootstrap: false,
Cron: true,
+ CCIP: false,
DirectRequest: true,
FluxMonitor: true,
Gateway: false,
@@ -97,6 +99,7 @@ var (
BlockhashStore: false,
Bootstrap: false,
Cron: true,
+ CCIP: false,
DirectRequest: true,
FluxMonitor: false,
Gateway: false,
@@ -116,6 +119,7 @@ var (
BlockhashStore: 1,
Bootstrap: 1,
Cron: 1,
+ CCIP: 1,
DirectRequest: 1,
FluxMonitor: 1,
Gateway: 1,
@@ -176,6 +180,7 @@ type Job struct {
StandardCapabilitiesSpecID *int32
StandardCapabilitiesSpec *StandardCapabilitiesSpec
CCIPSpecID *int32
+ CCIPSpec *CCIPSpec
CCIPBootstrapSpecID *int32
JobSpecErrors []SpecError
Type Type `toml:"type"`
@@ -910,3 +915,48 @@ func (w *StandardCapabilitiesSpec) SetID(value string) error {
w.ID = int32(ID)
return nil
}
+
+type CCIPSpec struct {
+ ID int32
+ CreatedAt time.Time `toml:"-"`
+ UpdatedAt time.Time `toml:"-"`
+
+ // P2PV2Bootstrappers is a list of "peer_id@ip_address:port" strings that are used to
+ // identify the bootstrap nodes of the P2P network.
+ // These bootstrappers will be used to bootstrap all CCIP DONs.
+ P2PV2Bootstrappers pq.StringArray `toml:"p2pV2Bootstrappers" db:"p2pv2_bootstrappers"`
+
+ // CapabilityVersion is the semantic version of the CCIP capability.
+ // This capability version must exist in the onchain capability registry.
+ CapabilityVersion string `toml:"capabilityVersion" db:"capability_version"`
+
+ // CapabilityLabelledName is the labelled name of the CCIP capability.
+ // Corresponds to the labelled name of the capability in the onchain capability registry.
+ CapabilityLabelledName string `toml:"capabilityLabelledName" db:"capability_labelled_name"`
+
+ // OCRKeyBundleIDs is a mapping from chain type to OCR key bundle ID.
+ // These are explicitly specified here so that we don't run into strange errors auto-detecting
+ // the valid bundle, since nops can create as many bundles as they want.
+ // This will most likely never change for a particular CCIP capability version,
+ // since new chain families will likely require a new capability version.
+ // {"evm": "evm_key_bundle_id", "solana": "solana_key_bundle_id", ... }
+ OCRKeyBundleIDs JSONConfig `toml:"ocrKeyBundleIDs" db:"ocr_key_bundle_ids"`
+
+ // RelayConfigs consists of relay specific configuration.
+ // Chain reader configurations are stored here, and are defined on a chain family basis, e.g
+ // we will have one chain reader config for EVM, one for solana, starknet, etc.
+ // Chain writer configurations are also stored here, and are also defined on a chain family basis,
+ // e.g we will have one chain writer config for EVM, one for solana, starknet, etc.
+ // See tests for examples of relay configs in TOML.
+ // { "evm": {"chainReader": {...}, "chainWriter": {...}}, "solana": {...}, ... }
+ // see core/services/relay/evm/types/types.go for EVM configs.
+ RelayConfigs JSONConfig `toml:"relayConfigs" db:"relay_configs"`
+
+ // P2PKeyID is the ID of the P2P key of the node.
+ // This must be present in the capability registry otherwise the job will not start correctly.
+ P2PKeyID string `toml:"p2pKeyID" db:"p2p_key_id"`
+
+ // PluginConfig contains plugin-specific config, like token price pipelines
+ // and RMN network info for offchain blessing.
+ PluginConfig JSONConfig `toml:"pluginConfig"`
+}
diff --git a/core/services/job/orm.go b/core/services/job/orm.go
index d13decc7208..ac3bb655306 100644
--- a/core/services/job/orm.go
+++ b/core/services/job/orm.go
@@ -425,7 +425,34 @@ func (o *orm) CreateJob(ctx context.Context, jb *Job) error {
return errors.Wrap(err, "failed to create StandardCapabilities for jobSpec")
}
jb.StandardCapabilitiesSpecID = &specID
-
+ case CCIP:
+ sql := `INSERT INTO ccip_specs (
+ capability_version,
+ capability_labelled_name,
+ ocr_key_bundle_ids,
+ p2p_key_id,
+ p2pv2_bootstrappers,
+ relay_configs,
+ plugin_config,
+ created_at,
+ updated_at
+ ) VALUES (
+ :capability_version,
+ :capability_labelled_name,
+ :ocr_key_bundle_ids,
+ :p2p_key_id,
+ :p2pv2_bootstrappers,
+ :relay_configs,
+ :plugin_config,
+ NOW(),
+ NOW()
+ )
+ RETURNING id;`
+ specID, err := tx.prepareQuerySpecID(ctx, sql, jb.CCIPSpec)
+ if err != nil {
+ return errors.Wrap(err, "failed to create CCIPSpec for jobSpec")
+ }
+ jb.CCIPSpecID = &specID
default:
o.lggr.Panicf("Unsupported jb.Type: %v", jb.Type)
}
@@ -643,19 +670,19 @@ func (o *orm) InsertJob(ctx context.Context, job *Job) error {
// if job has id, emplace otherwise insert with a new id.
if job.ID == 0 {
query = `INSERT INTO jobs (name, stream_id, schema_version, type, max_task_duration, ocr_oracle_spec_id, ocr2_oracle_spec_id, direct_request_spec_id, flux_monitor_spec_id,
- keeper_spec_id, cron_spec_id, vrf_spec_id, webhook_spec_id, blockhash_store_spec_id, bootstrap_spec_id, block_header_feeder_spec_id, gateway_spec_id,
- legacy_gas_station_server_spec_id, legacy_gas_station_sidecar_spec_id, workflow_spec_id, standard_capabilities_spec_id, external_job_id, gas_limit, forwarding_allowed, created_at)
+ keeper_spec_id, cron_spec_id, vrf_spec_id, webhook_spec_id, blockhash_store_spec_id, bootstrap_spec_id, block_header_feeder_spec_id, gateway_spec_id,
+ legacy_gas_station_server_spec_id, legacy_gas_station_sidecar_spec_id, workflow_spec_id, standard_capabilities_spec_id, ccip_spec_id, external_job_id, gas_limit, forwarding_allowed, created_at)
VALUES (:name, :stream_id, :schema_version, :type, :max_task_duration, :ocr_oracle_spec_id, :ocr2_oracle_spec_id, :direct_request_spec_id, :flux_monitor_spec_id,
- :keeper_spec_id, :cron_spec_id, :vrf_spec_id, :webhook_spec_id, :blockhash_store_spec_id, :bootstrap_spec_id, :block_header_feeder_spec_id, :gateway_spec_id,
- :legacy_gas_station_server_spec_id, :legacy_gas_station_sidecar_spec_id, :workflow_spec_id, :standard_capabilities_spec_id, :external_job_id, :gas_limit, :forwarding_allowed, NOW())
+ :keeper_spec_id, :cron_spec_id, :vrf_spec_id, :webhook_spec_id, :blockhash_store_spec_id, :bootstrap_spec_id, :block_header_feeder_spec_id, :gateway_spec_id,
+ :legacy_gas_station_server_spec_id, :legacy_gas_station_sidecar_spec_id, :workflow_spec_id, :standard_capabilities_spec_id, :ccip_spec_id, :external_job_id, :gas_limit, :forwarding_allowed, NOW())
RETURNING *;`
} else {
query = `INSERT INTO jobs (id, name, stream_id, schema_version, type, max_task_duration, ocr_oracle_spec_id, ocr2_oracle_spec_id, direct_request_spec_id, flux_monitor_spec_id,
- keeper_spec_id, cron_spec_id, vrf_spec_id, webhook_spec_id, blockhash_store_spec_id, bootstrap_spec_id, block_header_feeder_spec_id, gateway_spec_id,
- legacy_gas_station_server_spec_id, legacy_gas_station_sidecar_spec_id, workflow_spec_id, standard_capabilities_spec_id, external_job_id, gas_limit, forwarding_allowed, created_at)
+ keeper_spec_id, cron_spec_id, vrf_spec_id, webhook_spec_id, blockhash_store_spec_id, bootstrap_spec_id, block_header_feeder_spec_id, gateway_spec_id,
+ legacy_gas_station_server_spec_id, legacy_gas_station_sidecar_spec_id, workflow_spec_id, standard_capabilities_spec_id, ccip_spec_id, external_job_id, gas_limit, forwarding_allowed, created_at)
VALUES (:id, :name, :stream_id, :schema_version, :type, :max_task_duration, :ocr_oracle_spec_id, :ocr2_oracle_spec_id, :direct_request_spec_id, :flux_monitor_spec_id,
- :keeper_spec_id, :cron_spec_id, :vrf_spec_id, :webhook_spec_id, :blockhash_store_spec_id, :bootstrap_spec_id, :block_header_feeder_spec_id, :gateway_spec_id,
- :legacy_gas_station_server_spec_id, :legacy_gas_station_sidecar_spec_id, :workflow_spec_id, :standard_capabilities_spec_id, :external_job_id, :gas_limit, :forwarding_allowed, NOW())
+ :keeper_spec_id, :cron_spec_id, :vrf_spec_id, :webhook_spec_id, :blockhash_store_spec_id, :bootstrap_spec_id, :block_header_feeder_spec_id, :gateway_spec_id,
+ :legacy_gas_station_server_spec_id, :legacy_gas_station_sidecar_spec_id, :workflow_spec_id, :standard_capabilities_spec_id, :ccip_spec_id, :external_job_id, :gas_limit, :forwarding_allowed, NOW())
RETURNING *;`
}
query, args, err := tx.ds.BindNamed(query, job)
@@ -699,7 +726,8 @@ func (o *orm) DeleteJob(ctx context.Context, id int32) error {
block_header_feeder_spec_id,
gateway_spec_id,
workflow_spec_id,
- standard_capabilities_spec_id
+ standard_capabilities_spec_id,
+ ccip_spec_id
),
deleted_oracle_specs AS (
DELETE FROM ocr_oracle_specs WHERE id IN (SELECT ocr_oracle_spec_id FROM deleted_jobs)
@@ -742,7 +770,10 @@ func (o *orm) DeleteJob(ctx context.Context, id int32) error {
),
deleted_standardcapabilities_specs AS (
DELETE FROM standardcapabilities_specs WHERE id in (SELECT standard_capabilities_spec_id FROM deleted_jobs)
- ),
+ ),
+ deleted_ccip_specs AS (
+ DELETE FROM ccip_specs WHERE id in (SELECT ccip_spec_id FROM deleted_jobs)
+ ),
deleted_job_pipeline_specs AS (
DELETE FROM job_pipeline_specs WHERE job_id IN (SELECT id FROM deleted_jobs) RETURNING pipeline_spec_id
)
@@ -816,7 +847,7 @@ func (o *orm) FindJobs(ctx context.Context, offset, limit int) (jobs []Job, coun
return fmt.Errorf("failed to query jobs count: %w", err)
}
- sql = `SELECT jobs.*, job_pipeline_specs.pipeline_spec_id as pipeline_spec_id
+ sql = `SELECT jobs.*, job_pipeline_specs.pipeline_spec_id as pipeline_spec_id
FROM jobs
JOIN job_pipeline_specs ON (jobs.id = job_pipeline_specs.job_id)
ORDER BY jobs.created_at DESC, jobs.id DESC OFFSET $1 LIMIT $2;`
@@ -1030,8 +1061,8 @@ func (o *orm) findJob(ctx context.Context, jb *Job, col string, arg interface{})
}
func (o *orm) FindJobIDsWithBridge(ctx context.Context, name string) (jids []int32, err error) {
- query := `SELECT
- jobs.id, pipeline_specs.dot_dag_source
+ query := `SELECT
+ jobs.id, pipeline_specs.dot_dag_source
FROM jobs
JOIN job_pipeline_specs ON job_pipeline_specs.job_id = jobs.id
JOIN pipeline_specs ON pipeline_specs.id = job_pipeline_specs.pipeline_spec_id
@@ -1078,7 +1109,7 @@ func (o *orm) FindJobIDsWithBridge(ctx context.Context, name string) (jids []int
func (o *orm) FindJobIDByWorkflow(ctx context.Context, spec WorkflowSpec) (jobID int32, err error) {
stmt := `
SELECT jobs.id FROM jobs
-INNER JOIN workflow_specs ws on jobs.workflow_spec_id = ws.id AND ws.workflow_owner = $1 AND ws.workflow_name = $2
+INNER JOIN workflow_specs ws on jobs.workflow_spec_id = ws.id AND ws.workflow_owner = $1 AND ws.workflow_name = $2
`
err = o.ds.GetContext(ctx, &jobID, stmt, spec.WorkflowOwner, spec.WorkflowName)
if err != nil {
@@ -1391,6 +1422,7 @@ func (o *orm) loadAllJobTypes(ctx context.Context, job *Job) error {
o.loadJobType(ctx, job, "GatewaySpec", "gateway_specs", job.GatewaySpecID),
o.loadJobType(ctx, job, "WorkflowSpec", "workflow_specs", job.WorkflowSpecID),
o.loadJobType(ctx, job, "StandardCapabilitiesSpec", "standardcapabilities_specs", job.StandardCapabilitiesSpecID),
+ o.loadJobType(ctx, job, "CCIPSpec", "ccip_specs", job.CCIPSpecID),
)
}
@@ -1428,7 +1460,7 @@ func (o *orm) loadJobPipelineSpec(ctx context.Context, job *Job, id *int32) erro
ctx,
pipelineSpecRow,
`SELECT pipeline_specs.*, job_pipeline_specs.job_id as job_id
- FROM pipeline_specs
+ FROM pipeline_specs
JOIN job_pipeline_specs ON(pipeline_specs.id = job_pipeline_specs.pipeline_spec_id)
WHERE job_pipeline_specs.job_id = $1 AND job_pipeline_specs.pipeline_spec_id = $2`,
job.ID, *id,
diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go
index c70a92c725c..0f685439040 100644
--- a/core/services/keeper/upkeep_executer_test.go
+++ b/core/services/keeper/upkeep_executer_test.go
@@ -48,7 +48,7 @@ func mockEstimator(t *testing.T) gas.EvmFeeEstimator {
// note: estimator will only return 1 of legacy or dynamic fees (not both)
// assumed to call legacy estimator only
estimator := gasmocks.NewEvmFeeEstimator(t)
- estimator.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Maybe().Return(gas.EvmFee{
+ estimator.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Maybe().Return(gas.EvmFee{
Legacy: assets.GWei(60),
}, uint32(60), nil)
return estimator
diff --git a/core/services/keystore/keys/aptoskey/account.go b/core/services/keystore/keys/aptoskey/account.go
deleted file mode 100644
index 89f62d33011..00000000000
--- a/core/services/keystore/keys/aptoskey/account.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package aptoskey
-
-import (
- "encoding/hex"
- "errors"
- "fmt"
- "strings"
-)
-
-// AccountAddress is a 32 byte address on the Aptos blockchain
-// It can represent an Object, an Account, and much more.
-//
-// AccountAddress is copied from the aptos sdk because:
-// 1. There are still breaking changes in sdk and we don't want the dependency.
-// 2. AccountAddress is just a wrapper and can be easily extracted out.
-//
-// https://github.com/aptos-labs/aptos-go-sdk/blob/main/internal/types/account.go
-type AccountAddress [32]byte
-
-// IsSpecial Returns whether the address is a "special" address. Addresses are considered
-// special if the first 63 characters of the hex string are zero. In other words,
-// an address is special if the first 31 bytes are zero and the last byte is
-// smaller than `0b10000` (16). In other words, special is defined as an address
-// that matches the following regex: `^0x0{63}[0-9a-f]$`. In short form this means
-// the addresses in the range from `0x0` to `0xf` (inclusive) are special.
-// For more details see the v1 address standard defined as part of AIP-40:
-// https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md
-func (aa *AccountAddress) IsSpecial() bool {
- for _, b := range aa[:31] {
- if b != 0 {
- return false
- }
- }
- return aa[31] < 0x10
-}
-
-// String Returns the canonical string representation of the AccountAddress
-func (aa *AccountAddress) String() string {
- if aa.IsSpecial() {
- return fmt.Sprintf("0x%x", aa[31])
- }
- return BytesToHex(aa[:])
-}
-
-// ParseStringRelaxed parses a string into an AccountAddress
-func (aa *AccountAddress) ParseStringRelaxed(x string) error {
- x = strings.TrimPrefix(x, "0x")
- if len(x) < 1 {
- return ErrAddressTooShort
- }
- if len(x) > 64 {
- return ErrAddressTooLong
- }
- if len(x)%2 != 0 {
- x = "0" + x
- }
- bytes, err := hex.DecodeString(x)
- if err != nil {
- return err
- }
- // zero-prefix/right-align what bytes we got
- copy((*aa)[32-len(bytes):], bytes)
-
- return nil
-}
-
-var ErrAddressTooShort = errors.New("AccountAddress too short")
-var ErrAddressTooLong = errors.New("AccountAddress too long")
-
-func BytesToHex(bytes []byte) string {
- return "0x" + hex.EncodeToString(bytes)
-}
diff --git a/core/services/keystore/keys/aptoskey/account_test.go b/core/services/keystore/keys/aptoskey/account_test.go
deleted file mode 100644
index b9ed4ea04a5..00000000000
--- a/core/services/keystore/keys/aptoskey/account_test.go
+++ /dev/null
@@ -1,141 +0,0 @@
-package aptoskey
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-// Tests extracted from
-// https://github.com/aptos-labs/aptos-go-sdk/blob/5ee5ac308e5881b508c0a5124f5e0b8df27a4d40/internal/types/account_test.go
-
-func TestStringOutput(t *testing.T) {
- inputs := [][]byte{
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F},
- {0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
- {0x02, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
- {0x00, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
- {0x00, 0x04, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
- {0x00, 0x00, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x12, 0x34, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
- }
- expected := []string{
- "0x0",
- "0x1",
- "0xf",
- "0x1234123412341234123412341234123412341234123412340123456789abcdef",
- "0x0234123412341234123412341234123412341234123412340123456789abcdef",
- "0x0034123412341234123412341234123412341234123412340123456789abcdef",
- "0x0004123412341234123412341234123412341234123412340123456789abcdef",
- "0x0000123412341234123412341234123412341234123412340123456789abcdef",
- }
-
- for i := 0; i < len(inputs); i++ {
- addr := AccountAddress(inputs[i])
- assert.Equal(t, expected[i], addr.String())
- }
-}
-
-func TestAccountAddress_ParseStringRelaxed_Error(t *testing.T) {
- var owner AccountAddress
- err := owner.ParseStringRelaxed("0x")
- assert.Error(t, err)
- err = owner.ParseStringRelaxed("0xF1234567812345678123456781234567812345678123456781234567812345678")
- assert.Error(t, err)
- err = owner.ParseStringRelaxed("NotHex")
- assert.Error(t, err)
-}
-
-func TestAccountAddress_String(t *testing.T) {
- testCases := []struct {
- name string
- address AccountAddress
- expected string
- }{
- {
- name: "Special address",
- address: AccountAddress{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
- expected: "0x1",
- },
- {
- name: "Non-special address",
- address: AccountAddress{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
- expected: "0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0",
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- assert.Equal(t, tc.expected, tc.address.String())
- })
- }
-}
-
-func TestAccountAddress_IsSpecial(t *testing.T) {
- testCases := []struct {
- name string
- address AccountAddress
- expected bool
- }{
- {
- name: "Special address",
- address: AccountAddress{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
- expected: true,
- },
- {
- name: "Non-special address",
- address: AccountAddress{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
- expected: false,
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- assert.Equal(t, tc.expected, tc.address.IsSpecial())
- })
- }
-}
-
-func TestBytesToHex(t *testing.T) {
- testCases := []struct {
- name string
- bytes []byte
- expected string
- }{
- {
- name: "Empty bytes",
- bytes: []byte{},
- expected: "0x",
- },
- {
- name: "Non-empty bytes",
- bytes: []byte{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0},
- expected: "0x123456789abcdef0",
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- assert.Equal(t, tc.expected, BytesToHex(tc.bytes))
- })
- }
-}
-
-func TestAccountSpecialString(t *testing.T) {
- var aa AccountAddress
- aa[31] = 3
- aas := aa.String()
- if aas != "0x3" {
- t.Errorf("wanted 0x3 got %s", aas)
- }
-
- var aa2 AccountAddress
- err := aa2.ParseStringRelaxed("0x3")
- if err != nil {
- t.Errorf("unexpected err %s", err)
- }
- if aa2 != aa {
- t.Errorf("aa2 != aa")
- }
-}
diff --git a/core/services/keystore/keys/aptoskey/key.go b/core/services/keystore/keys/aptoskey/key.go
index ec9b27a3596..fa8925454e4 100644
--- a/core/services/keystore/keys/aptoskey/key.go
+++ b/core/services/keystore/keys/aptoskey/key.go
@@ -7,7 +7,7 @@ import (
"fmt"
"io"
- "github.com/mr-tron/base58"
+ "golang.org/x/crypto/sha3"
)
// Raw represents the Aptos private key
@@ -37,6 +37,7 @@ var _ fmt.GoStringer = &Key{}
// Key represents Aptos key
type Key struct {
+ // TODO: store initial Account() derivation to support key rotation
privkey ed25519.PrivateKey
pubKey ed25519.PublicKey
}
@@ -72,14 +73,20 @@ func (key Key) ID() string {
return key.PublicKeyStr()
}
+// https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-40.md#long
+func (key Key) Account() string {
+ authKey := sha3.Sum256(append([]byte(key.pubKey), 0x00))
+ return fmt.Sprintf("%064x", authKey)
+}
+
// GetPublic get Key's public key
func (key Key) GetPublic() ed25519.PublicKey {
return key.pubKey
}
-// PublicKeyStr return base58 encoded public key
+// PublicKeyStr returns hex encoded public key
func (key Key) PublicKeyStr() string {
- return base58.Encode(key.pubKey)
+ return fmt.Sprintf("%064x", key.pubKey)
}
// Raw returns the seed from private key
diff --git a/core/services/keystore/keys/aptoskey/key_test.go b/core/services/keystore/keys/aptoskey/key_test.go
new file mode 100644
index 00000000000..277a30eb9f3
--- /dev/null
+++ b/core/services/keystore/keys/aptoskey/key_test.go
@@ -0,0 +1,17 @@
+package aptoskey
+
+import (
+ "encoding/hex"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestAptosKey(t *testing.T) {
+ bytes, err := hex.DecodeString("f0d07ab448018b2754475f9a3b580218b0675a1456aad96ad607c7bbd7d9237b")
+ require.NoError(t, err)
+ k := Raw(bytes).Key()
+ assert.Equal(t, k.PublicKeyStr(), "2acd605efc181e2af8a0b8c0686a5e12578efa1253d15a235fa5e5ad970c4b29")
+ assert.Equal(t, k.Account(), "69d8b07f5945185873c622ea66873b0e1fb921de7b94d904d3ef9be80770682e")
+}
diff --git a/core/services/keystore/keys/cosmoskey/key.go b/core/services/keystore/keys/cosmoskey/key.go
index 3e516a21ab5..b5ea255f23f 100644
--- a/core/services/keystore/keys/cosmoskey/key.go
+++ b/core/services/keystore/keys/cosmoskey/key.go
@@ -59,9 +59,6 @@ func newFrom(reader io.Reader) Key {
panic(err)
}
privKey := secpSigningAlgo.Generate()(rawKey.D.Bytes())
- if err != nil {
- panic(err)
- }
return Key{
d: rawKey.D,
diff --git a/core/services/keystore/keys/ocr2key/aptos_keyring.go b/core/services/keystore/keys/ocr2key/aptos_keyring.go
index 51e6c3a9c8f..cdc5afa792f 100644
--- a/core/services/keystore/keys/ocr2key/aptos_keyring.go
+++ b/core/services/keystore/keys/ocr2key/aptos_keyring.go
@@ -2,12 +2,11 @@ package ocr2key
import (
"crypto/ed25519"
- "encoding/binary"
"io"
"github.com/hdevalence/ed25519consensus"
"github.com/pkg/errors"
- "golang.org/x/crypto/blake2s"
+ "golang.org/x/crypto/blake2b"
"github.com/smartcontractkit/chainlink/v2/core/utils"
@@ -37,17 +36,15 @@ func (akr *aptosKeyring) PublicKey() ocrtypes.OnchainPublicKey {
func (akr *aptosKeyring) reportToSigData(reportCtx ocrtypes.ReportContext, report ocrtypes.Report) ([]byte, error) {
rawReportContext := evmutil.RawReportContext(reportCtx)
- h, err := blake2s.New256(nil)
+ h, err := blake2b.New256(nil)
if err != nil {
return nil, err
}
- reportLen := make([]byte, 4)
- binary.BigEndian.PutUint32(reportLen[0:], uint32(len(report)))
- h.Write(reportLen[:])
- h.Write(report)
+ // blake2b_256(report_context | report)
h.Write(rawReportContext[0][:])
h.Write(rawReportContext[1][:])
h.Write(rawReportContext[2][:])
+ h.Write(report)
return h.Sum(nil), nil
}
diff --git a/core/services/llo/bm/dummy_transmitter.go b/core/services/llo/bm/dummy_transmitter.go
index c349c9e0ee8..aa29938545f 100644
--- a/core/services/llo/bm/dummy_transmitter.go
+++ b/core/services/llo/bm/dummy_transmitter.go
@@ -12,10 +12,9 @@ import (
"github.com/smartcontractkit/chainlink-data-streams/llo"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo"
-
- "github.com/smartcontractkit/chainlink/v2/core/logger"
)
// A dummy transmitter useful for benchmarking and testing
@@ -39,7 +38,7 @@ type transmitter struct {
func NewTransmitter(lggr logger.Logger, fromAccount string) Transmitter {
return &transmitter{
- lggr.Named("DummyTransmitter"),
+ logger.Named(lggr, "DummyTransmitter"),
fromAccount,
}
}
@@ -66,7 +65,7 @@ func (t *transmitter) Transmit(
if err != nil {
lggr.Debugw("Failed to decode JSON report", "err", err)
}
- lggr = lggr.With(
+ lggr = logger.With(lggr,
"report.Report.ConfigDigest", r.ConfigDigest,
"report.Report.SeqNr", r.SeqNr,
"report.Report.ChannelID", r.ChannelID,
diff --git a/core/services/llo/channel_definition_cache_factory.go b/core/services/llo/channel_definition_cache_factory.go
index 51906e0ff1b..4aa358d64af 100644
--- a/core/services/llo/channel_definition_cache_factory.go
+++ b/core/services/llo/channel_definition_cache_factory.go
@@ -6,10 +6,10 @@ import (
"github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config"
)
diff --git a/core/services/llo/onchain_channel_definition_cache.go b/core/services/llo/onchain_channel_definition_cache.go
index 4d3fb0e8255..3362aa9b9d6 100644
--- a/core/services/llo/onchain_channel_definition_cache.go
+++ b/core/services/llo/onchain_channel_definition_cache.go
@@ -13,12 +13,12 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/channel_config_store"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
)
type ChannelDefinitionCacheORM interface {
@@ -75,7 +75,7 @@ func NewChannelDefinitionCache(lggr logger.Logger, orm ChannelDefinitionCacheORM
lp,
0,
addr,
- lggr.Named("ChannelDefinitionCache").With("addr", addr, "fromBlock", fromBlock),
+ logger.Sugared(lggr).Named("ChannelDefinitionCache").With("addr", addr, "fromBlock", fromBlock),
sync.RWMutex{},
nil,
fromBlock,
diff --git a/core/services/llo/static_channel_definitions_cache.go b/core/services/llo/static_channel_definitions_cache.go
index 98ef3642cb7..980625bd599 100644
--- a/core/services/llo/static_channel_definitions_cache.go
+++ b/core/services/llo/static_channel_definitions_cache.go
@@ -7,7 +7,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/services"
llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
)
// A CDC that loads a static JSON of channel definitions; useful for
@@ -27,7 +27,7 @@ func NewStaticChannelDefinitionCache(lggr logger.Logger, dfnstr string) (llotype
if err := json.Unmarshal([]byte(dfnstr), &definitions); err != nil {
return nil, err
}
- return &staticCDC{services.StateMachine{}, lggr.Named("StaticChannelDefinitionCache"), definitions}, nil
+ return &staticCDC{services.StateMachine{}, logger.Named(lggr, "StaticChannelDefinitionCache"), definitions}, nil
}
func (s *staticCDC) Start(context.Context) error {
diff --git a/core/services/llo/transmitter.go b/core/services/llo/transmitter.go
index b8cfb86de3b..f8761284810 100644
--- a/core/services/llo/transmitter.go
+++ b/core/services/llo/transmitter.go
@@ -11,10 +11,10 @@ import (
"github.com/smartcontractkit/libocr/offchainreporting2plus/types"
ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc"
)
diff --git a/core/services/nurse.go b/core/services/nurse.go
index a9069b5181d..7f3cad13e71 100644
--- a/core/services/nurse.go
+++ b/core/services/nurse.go
@@ -3,6 +3,7 @@ package services
import (
"bytes"
"compress/gzip"
+ "context"
"fmt"
"io/fs"
"os"
@@ -19,22 +20,21 @@ import (
commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
"github.com/smartcontractkit/chainlink-common/pkg/services"
+ "github.com/smartcontractkit/chainlink-common/pkg/timeutil"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/utils"
)
type Nurse struct {
- services.StateMachine
+ services.Service
+ eng *services.Engine
cfg Config
- log logger.Logger
checks map[string]CheckFunc
checksMu sync.RWMutex
chGather chan gatherRequest
- chStop chan struct{}
- wgDone sync.WaitGroup
}
type Config interface {
@@ -66,85 +66,63 @@ const (
)
func NewNurse(cfg Config, log logger.Logger) *Nurse {
- return &Nurse{
+ n := &Nurse{
cfg: cfg,
- log: log.Named("Nurse"),
checks: make(map[string]CheckFunc),
chGather: make(chan gatherRequest, 1),
- chStop: make(chan struct{}),
}
+ n.Service, n.eng = services.Config{
+ Name: "Nurse",
+ Start: n.start,
+ }.NewServiceEngine(log)
+
+ return n
}
-func (n *Nurse) Start() error {
- return n.StartOnce("Nurse", func() error {
- // This must be set *once*, and it must occur as early as possible
- if n.cfg.MemProfileRate() != runtime.MemProfileRate {
- runtime.MemProfileRate = n.cfg.BlockProfileRate()
- }
+func (n *Nurse) start(_ context.Context) error {
+ // This must be set *once*, and it must occur as early as possible
+ if n.cfg.MemProfileRate() != runtime.MemProfileRate {
+ runtime.MemProfileRate = n.cfg.BlockProfileRate()
+ }
- n.log.Debugf("Starting nurse with config %+v", n.cfg)
- runtime.SetCPUProfileRate(n.cfg.CPUProfileRate())
- runtime.SetBlockProfileRate(n.cfg.BlockProfileRate())
- runtime.SetMutexProfileFraction(n.cfg.MutexProfileFraction())
+ n.eng.Debugf("Starting nurse with config %+v", n.cfg)
+ runtime.SetCPUProfileRate(n.cfg.CPUProfileRate())
+ runtime.SetBlockProfileRate(n.cfg.BlockProfileRate())
+ runtime.SetMutexProfileFraction(n.cfg.MutexProfileFraction())
- err := utils.EnsureDirAndMaxPerms(n.cfg.ProfileRoot(), 0744)
- if err != nil {
- return err
- }
+ err := utils.EnsureDirAndMaxPerms(n.cfg.ProfileRoot(), 0744)
+ if err != nil {
+ return err
+ }
- n.AddCheck("mem", n.checkMem)
- n.AddCheck("goroutines", n.checkGoroutines)
-
- n.wgDone.Add(1)
- // Checker
- go func() {
- defer n.wgDone.Done()
- for {
- select {
- case <-n.chStop:
- return
- case <-time.After(n.cfg.PollInterval().Duration()):
- }
-
- func() {
- n.checksMu.RLock()
- defer n.checksMu.RUnlock()
- for reason, checkFunc := range n.checks {
- if unwell, meta := checkFunc(); unwell {
- n.GatherVitals(reason, meta)
- break
- }
- }
- }()
- }
- }()
-
- n.wgDone.Add(1)
- // Responder
- go func() {
- defer n.wgDone.Done()
- for {
- select {
- case <-n.chStop:
- return
- case req := <-n.chGather:
- n.gatherVitals(req.reason, req.meta)
- }
- }
- }()
+ n.AddCheck("mem", n.checkMem)
+ n.AddCheck("goroutines", n.checkGoroutines)
- return nil
+ // Checker
+ n.eng.GoTick(timeutil.NewTicker(n.cfg.PollInterval().Duration), func(ctx context.Context) {
+ n.checksMu.RLock()
+ defer n.checksMu.RUnlock()
+ for reason, checkFunc := range n.checks {
+ if unwell, meta := checkFunc(); unwell {
+ n.GatherVitals(ctx, reason, meta)
+ break
+ }
+ }
})
-}
-func (n *Nurse) Close() error {
- return n.StopOnce("Nurse", func() error {
- n.log.Debug("Nurse closing...")
- defer n.log.Debug("Nurse closed")
- close(n.chStop)
- n.wgDone.Wait()
- return nil
+ // Responder
+ n.eng.Go(func(ctx context.Context) {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case req := <-n.chGather:
+ n.gatherVitals(req.reason, req.meta)
+ }
+ }
})
+
+ return nil
}
func (n *Nurse) AddCheck(reason string, checkFunc CheckFunc) {
@@ -153,9 +131,9 @@ func (n *Nurse) AddCheck(reason string, checkFunc CheckFunc) {
n.checks[reason] = checkFunc
}
-func (n *Nurse) GatherVitals(reason string, meta Meta) {
+func (n *Nurse) GatherVitals(ctx context.Context, reason string, meta Meta) {
select {
- case <-n.chStop:
+ case <-ctx.Done():
case n.chGather <- gatherRequest{reason, meta}:
default:
}
@@ -189,14 +167,14 @@ func (n *Nurse) checkGoroutines() (bool, Meta) {
func (n *Nurse) gatherVitals(reason string, meta Meta) {
loggerFields := (logger.Fields{"reason": reason}).Merge(logger.Fields(meta))
- n.log.Debugw("Nurse is gathering vitals", loggerFields.Slice()...)
+ n.eng.Debugw("Nurse is gathering vitals", loggerFields.Slice()...)
size, err := n.totalProfileBytes()
if err != nil {
- n.log.Errorw("could not fetch total profile bytes", loggerFields.With("err", err).Slice()...)
+ n.eng.Errorw("could not fetch total profile bytes", loggerFields.With("err", err).Slice()...)
return
} else if size >= uint64(n.cfg.MaxProfileSize()) {
- n.log.Warnw("cannot write pprof profile, total profile size exceeds configured PPROF_MAX_PROFILE_SIZE",
+ n.eng.Warnw("cannot write pprof profile, total profile size exceeds configured PPROF_MAX_PROFILE_SIZE",
loggerFields.With("total", size, "max", n.cfg.MaxProfileSize()).Slice()...,
)
return
@@ -206,7 +184,7 @@ func (n *Nurse) gatherVitals(reason string, meta Meta) {
err = n.appendLog(now, reason, meta)
if err != nil {
- n.log.Warnw("cannot write pprof profile", loggerFields.With("err", err).Slice()...)
+ n.eng.Warnw("cannot write pprof profile", loggerFields.With("err", err).Slice()...)
return
}
var wg sync.WaitGroup
@@ -227,7 +205,7 @@ func (n *Nurse) gatherVitals(reason string, meta Meta) {
wg.Add(1)
go n.gather("heap", now, &wg)
} else {
- n.log.Info("skipping heap collection because runtime.MemProfileRate = 0")
+ n.eng.Info("skipping heap collection because runtime.MemProfileRate = 0")
}
wg.Add(1)
@@ -236,15 +214,13 @@ func (n *Nurse) gatherVitals(reason string, meta Meta) {
go n.gather("threadcreate", now, &wg)
ch := make(chan struct{})
- n.wgDone.Add(1)
- go func() {
- defer n.wgDone.Done()
+ n.eng.Go(func(ctx context.Context) {
defer close(ch)
wg.Wait()
- }()
+ })
select {
- case <-n.chStop:
+ case <-n.eng.StopChan:
case <-ch:
}
}
@@ -252,7 +228,7 @@ func (n *Nurse) gatherVitals(reason string, meta Meta) {
func (n *Nurse) appendLog(now time.Time, reason string, meta Meta) error {
filename := filepath.Join(n.cfg.ProfileRoot(), "nurse.log")
- n.log.Debugf("creating nurse log %s", filename)
+ n.eng.Debugf("creating nurse log %s", filename)
file, err := os.Create(filename)
if err != nil {
@@ -288,34 +264,34 @@ func (n *Nurse) appendLog(now time.Time, reason string, meta Meta) error {
func (n *Nurse) gatherCPU(now time.Time, wg *sync.WaitGroup) {
defer wg.Done()
- n.log.Debugf("gather cpu %d ...", now.UnixMicro())
- defer n.log.Debugf("gather cpu %d done", now.UnixMicro())
+ n.eng.Debugf("gather cpu %d ...", now.UnixMicro())
+ defer n.eng.Debugf("gather cpu %d done", now.UnixMicro())
wc, err := n.createFile(now, cpuProfName, false)
if err != nil {
- n.log.Errorw("could not write cpu profile", "err", err)
+ n.eng.Errorw("could not write cpu profile", "err", err)
return
}
defer wc.Close()
err = pprof.StartCPUProfile(wc)
if err != nil {
- n.log.Errorw("could not start cpu profile", "err", err)
+ n.eng.Errorw("could not start cpu profile", "err", err)
return
}
select {
- case <-n.chStop:
- n.log.Debug("gather cpu received stop")
+ case <-n.eng.StopChan:
+ n.eng.Debug("gather cpu received stop")
case <-time.After(n.cfg.GatherDuration().Duration()):
- n.log.Debugf("gather cpu duration elapsed %s. stoping profiling.", n.cfg.GatherDuration().Duration().String())
+ n.eng.Debugf("gather cpu duration elapsed %s. stoping profiling.", n.cfg.GatherDuration().Duration().String())
}
pprof.StopCPUProfile()
err = wc.Close()
if err != nil {
- n.log.Errorw("could not close cpu profile", "err", err)
+ n.eng.Errorw("could not close cpu profile", "err", err)
return
}
}
@@ -323,23 +299,23 @@ func (n *Nurse) gatherCPU(now time.Time, wg *sync.WaitGroup) {
func (n *Nurse) gatherTrace(now time.Time, wg *sync.WaitGroup) {
defer wg.Done()
- n.log.Debugf("gather trace %d ...", now.UnixMicro())
- defer n.log.Debugf("gather trace %d done", now.UnixMicro())
+ n.eng.Debugf("gather trace %d ...", now.UnixMicro())
+ defer n.eng.Debugf("gather trace %d done", now.UnixMicro())
wc, err := n.createFile(now, traceProfName, true)
if err != nil {
- n.log.Errorw("could not write trace profile", "err", err)
+ n.eng.Errorw("could not write trace profile", "err", err)
return
}
defer wc.Close()
err = trace.Start(wc)
if err != nil {
- n.log.Errorw("could not start trace profile", "err", err)
+ n.eng.Errorw("could not start trace profile", "err", err)
return
}
select {
- case <-n.chStop:
+ case <-n.eng.StopChan:
case <-time.After(n.cfg.GatherTraceDuration().Duration()):
}
@@ -347,7 +323,7 @@ func (n *Nurse) gatherTrace(now time.Time, wg *sync.WaitGroup) {
err = wc.Close()
if err != nil {
- n.log.Errorw("could not close trace profile", "err", err)
+ n.eng.Errorw("could not close trace profile", "err", err)
return
}
}
@@ -355,18 +331,18 @@ func (n *Nurse) gatherTrace(now time.Time, wg *sync.WaitGroup) {
func (n *Nurse) gather(typ string, now time.Time, wg *sync.WaitGroup) {
defer wg.Done()
- n.log.Debugf("gather %s %d ...", typ, now.UnixMicro())
- n.log.Debugf("gather %s %d done", typ, now.UnixMicro())
+ n.eng.Debugf("gather %s %d ...", typ, now.UnixMicro())
+ n.eng.Debugf("gather %s %d done", typ, now.UnixMicro())
p := pprof.Lookup(typ)
if p == nil {
- n.log.Errorf("Invariant violation: pprof type '%v' does not exist", typ)
+ n.eng.Errorf("Invariant violation: pprof type '%v' does not exist", typ)
return
}
p0, err := collectProfile(p)
if err != nil {
- n.log.Errorw(fmt.Sprintf("could not collect %v profile", typ), "err", err)
+ n.eng.Errorw(fmt.Sprintf("could not collect %v profile", typ), "err", err)
return
}
@@ -374,14 +350,14 @@ func (n *Nurse) gather(typ string, now time.Time, wg *sync.WaitGroup) {
defer t.Stop()
select {
- case <-n.chStop:
+ case <-n.eng.StopChan:
return
case <-t.C:
}
p1, err := collectProfile(p)
if err != nil {
- n.log.Errorw(fmt.Sprintf("could not collect %v profile", typ), "err", err)
+ n.eng.Errorw(fmt.Sprintf("could not collect %v profile", typ), "err", err)
return
}
ts := p1.TimeNanos
@@ -391,7 +367,7 @@ func (n *Nurse) gather(typ string, now time.Time, wg *sync.WaitGroup) {
p1, err = profile.Merge([]*profile.Profile{p0, p1})
if err != nil {
- n.log.Errorw(fmt.Sprintf("could not compute delta for %v profile", typ), "err", err)
+ n.eng.Errorw(fmt.Sprintf("could not compute delta for %v profile", typ), "err", err)
return
}
@@ -400,19 +376,19 @@ func (n *Nurse) gather(typ string, now time.Time, wg *sync.WaitGroup) {
wc, err := n.createFile(now, typ, false)
if err != nil {
- n.log.Errorw(fmt.Sprintf("could not write %v profile", typ), "err", err)
+ n.eng.Errorw(fmt.Sprintf("could not write %v profile", typ), "err", err)
return
}
defer wc.Close()
err = p1.Write(wc)
if err != nil {
- n.log.Errorw(fmt.Sprintf("could not write %v profile", typ), "err", err)
+ n.eng.Errorw(fmt.Sprintf("could not write %v profile", typ), "err", err)
return
}
err = wc.Close()
if err != nil {
- n.log.Errorw(fmt.Sprintf("could not close file for %v profile", typ), "err", err)
+ n.eng.Errorw(fmt.Sprintf("could not close file for %v profile", typ), "err", err)
return
}
}
@@ -437,7 +413,7 @@ func (n *Nurse) createFile(now time.Time, typ string, shouldGzip bool) (*utils.D
filename += ".gz"
}
fullpath := filepath.Join(n.cfg.ProfileRoot(), filename)
- n.log.Debugf("creating file %s", fullpath)
+ n.eng.Debugf("creating file %s", fullpath)
file, err := os.Create(fullpath)
if err != nil {
diff --git a/core/services/nurse_test.go b/core/services/nurse_test.go
index 4597eeb456b..ed6f6872dc9 100644
--- a/core/services/nurse_test.go
+++ b/core/services/nurse_test.go
@@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/require"
commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/utils"
@@ -102,7 +103,7 @@ func TestNurse(t *testing.T) {
nrse := NewNurse(newMockConfig(t), l)
nrse.AddCheck("test", func() (bool, Meta) { return true, Meta{} })
- require.NoError(t, nrse.Start())
+ require.NoError(t, nrse.Start(tests.Context(t)))
defer func() { require.NoError(t, nrse.Close()) }()
require.NoError(t, nrse.appendLog(time.Now(), "test", Meta{}))
diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go
index 11dfacd1d1a..d7199874a9f 100644
--- a/core/services/ocr/contract_tracker.go
+++ b/core/services/ocr/contract_tracker.go
@@ -399,7 +399,7 @@ func (t *OCRContractTracker) LatestBlockHeight(ctx context.Context) (blockheight
// care about the block height; we have no way of getting the L1 block
// height anyway
return 0, nil
- case "", chaintype.ChainArbitrum, chaintype.ChainCelo, chaintype.ChainGnosis, chaintype.ChainKroma, chaintype.ChainOptimismBedrock, chaintype.ChainScroll, chaintype.ChainWeMix, chaintype.ChainXLayer, chaintype.ChainZkEvm, chaintype.ChainZkSync:
+ case "", chaintype.ChainArbitrum, chaintype.ChainAstar, chaintype.ChainCelo, chaintype.ChainGnosis, chaintype.ChainHedera, chaintype.ChainKroma, chaintype.ChainOptimismBedrock, chaintype.ChainScroll, chaintype.ChainWeMix, chaintype.ChainXLayer, chaintype.ChainZkEvm, chaintype.ChainZkSync:
// continue
}
latestBlockHeight := t.getLatestBlockHeight()
diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go
index db0f4e9725e..f53ceaefa14 100644
--- a/core/services/ocr2/delegate.go
+++ b/core/services/ocr2/delegate.go
@@ -6,18 +6,25 @@ import (
"encoding/json"
"fmt"
"log"
+ "strconv"
"time"
+ "gopkg.in/guregu/null.v4"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/core"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
- "google.golang.org/grpc"
- "gopkg.in/guregu/null.v4"
-
+ chainselectors "github.com/smartcontractkit/chain-selectors"
"github.com/smartcontractkit/libocr/commontypes"
libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "google.golang.org/grpc"
ocr2keepers20 "github.com/smartcontractkit/chainlink-automation/pkg/v2"
ocr2keepers20config "github.com/smartcontractkit/chainlink-automation/pkg/v2/config"
@@ -26,13 +33,11 @@ import (
ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner"
ocr2keepers21config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config"
ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin"
-
"github.com/smartcontractkit/chainlink-common/pkg/loop"
"github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins"
"github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins/ocr3"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
"github.com/smartcontractkit/chainlink-common/pkg/types"
- "github.com/smartcontractkit/chainlink-common/pkg/types/core"
llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo"
"github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
datastreamsllo "github.com/smartcontractkit/chainlink-data-streams/llo"
@@ -47,12 +52,15 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key"
"github.com/smartcontractkit/chainlink/v2/core/services/llo"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/ccipcommit"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/ccipexec"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/generic"
lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper"
+
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21"
ocr2keeper21core "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate"
@@ -68,6 +76,8 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
"github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
"github.com/smartcontractkit/chainlink/v2/plugins"
+
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
)
type ErrJobSpecNoRelayer struct {
@@ -284,6 +294,7 @@ func (d *Delegate) cleanupEVM(ctx context.Context, jb job.Job, relayID types.Rel
// an inconsistent state. This assumes UnregisterFilter will return nil if the filter wasn't found
// at all (no rows deleted).
spec := jb.OCR2OracleSpec
+ transmitterID := spec.TransmitterID.String
chain, err := d.legacyChains.Get(relayID.ChainID)
if err != nil {
d.lggr.Errorw("cleanupEVM: failed to get chain id", "chainId", relayID.ChainID, "err", err)
@@ -305,6 +316,51 @@ func (d *Delegate) cleanupEVM(ctx context.Context, jb job.Job, relayID types.Rel
d.lggr.Errorw("failed to derive ocr2keeper filter names from spec", "err", err, "spec", spec)
}
filters = append(filters, filters21...)
+ case types.CCIPCommit:
+ // Write PluginConfig bytes to send source/dest relayer provider + info outside of top level rargs/pargs over the wire
+ var pluginJobSpecConfig ccipconfig.CommitPluginJobSpecConfig
+ err = json.Unmarshal(spec.PluginConfig.Bytes(), &pluginJobSpecConfig)
+ if err != nil {
+ return err
+ }
+
+ dstProvider, err2 := d.ccipCommitGetDstProvider(ctx, jb, pluginJobSpecConfig, transmitterID)
+ if err2 != nil {
+ return err
+ }
+
+ srcProvider, _, err2 := d.ccipCommitGetSrcProvider(ctx, jb, pluginJobSpecConfig, transmitterID, dstProvider)
+ if err2 != nil {
+ return err
+ }
+ err2 = ccipcommit.UnregisterCommitPluginLpFilters(srcProvider, dstProvider)
+ if err2 != nil {
+ d.lggr.Errorw("failed to unregister ccip commit plugin filters", "err", err2, "spec", spec)
+ }
+ return nil
+ case types.CCIPExecution:
+ // PROVIDER BASED ARG CONSTRUCTION
+ // Write PluginConfig bytes to send source/dest relayer provider + info outside of top level rargs/pargs over the wire
+ var pluginJobSpecConfig ccipconfig.ExecPluginJobSpecConfig
+ err = json.Unmarshal(spec.PluginConfig.Bytes(), &pluginJobSpecConfig)
+ if err != nil {
+ return err
+ }
+
+ dstProvider, err2 := d.ccipExecGetDstProvider(ctx, jb, pluginJobSpecConfig, transmitterID)
+ if err2 != nil {
+ return err
+ }
+
+ srcProvider, _, err2 := d.ccipExecGetSrcProvider(ctx, jb, pluginJobSpecConfig, transmitterID, dstProvider)
+ if err2 != nil {
+ return err
+ }
+ err2 = ccipexec.UnregisterExecPluginLpFilters(srcProvider, dstProvider)
+ if err2 != nil {
+ d.lggr.Errorw("failed to unregister ccip exec plugin filters", "err", err2, "spec", spec)
+ }
+ return nil
default:
return nil
}
@@ -448,6 +504,10 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi
return d.newServicesGenericPlugin(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, d.capabilitiesRegistry,
kvStore)
+ case types.CCIPCommit:
+ return d.newServicesCCIPCommit(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, transmitterID)
+ case types.CCIPExecution:
+ return d.newServicesCCIPExecution(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, transmitterID)
default:
return nil, errors.Errorf("plugin type %s not supported", spec.PluginType)
}
@@ -712,7 +772,7 @@ func (d *Delegate) newServicesGenericPlugin(
}
keyBundles[name] = os
}
- onchainKeyringAdapter, err = ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(keyBundles, lggr)
+ onchainKeyringAdapter, err = ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(keyBundles, kb.PublicKey(), lggr)
if err != nil {
return nil, err
}
@@ -1498,6 +1558,337 @@ func (d *Delegate) newServicesOCR2Functions(
return append([]job.ServiceCtx{functionsProvider, thresholdProvider, s4Provider, ocrLogger}, functionsServices...), nil
}
+func (d *Delegate) newServicesCCIPCommit(ctx context.Context, lggr logger.SugaredLogger, jb job.Job, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, ocrDB *db, lc ocrtypes.LocalConfig, transmitterID string) ([]job.ServiceCtx, error) {
+ spec := jb.OCR2OracleSpec
+ if spec.Relay != relay.NetworkEVM {
+ return nil, fmt.Errorf("non evm chains are not supported for CCIP commit")
+ }
+ dstRid, err := spec.RelayID()
+ if err != nil {
+ return nil, ErrJobSpecNoRelayer{Err: err, PluginName: string(spec.PluginType)}
+ }
+
+ logError := func(msg string) {
+ lggr.ErrorIf(d.jobORM.RecordError(context.Background(), jb.ID, msg), "unable to record error")
+ }
+
+ // Write PluginConfig bytes to send source/dest relayer provider + info outside of top level rargs/pargs over the wire
+ var pluginJobSpecConfig ccipconfig.CommitPluginJobSpecConfig
+ err = json.Unmarshal(spec.PluginConfig.Bytes(), &pluginJobSpecConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ dstChainID, err := strconv.ParseInt(dstRid.ChainID, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ dstProvider, err := d.ccipCommitGetDstProvider(ctx, jb, pluginJobSpecConfig, transmitterID)
+ if err != nil {
+ return nil, err
+ }
+
+ srcProvider, srcChainID, err := d.ccipCommitGetSrcProvider(ctx, jb, pluginJobSpecConfig, transmitterID, dstProvider)
+ if err != nil {
+ return nil, err
+ }
+
+ oracleArgsNoPlugin := libocr2.OCR2OracleArgs{
+ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2,
+ V2Bootstrappers: bootstrapPeers,
+ ContractTransmitter: dstProvider.ContractTransmitter(),
+ ContractConfigTracker: dstProvider.ContractConfigTracker(),
+ Database: ocrDB,
+ LocalConfig: lc,
+ MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(
+ dstRid.Network,
+ dstRid.ChainID,
+ spec.ContractID,
+ synchronization.OCR2CCIPCommit,
+ ),
+ OffchainConfigDigester: dstProvider.OffchainConfigDigester(),
+ OffchainKeyring: kb,
+ OnchainKeyring: kb,
+ MetricsRegisterer: prometheus.WrapRegistererWith(map[string]string{"job_name": jb.Name.ValueOrZero()}, prometheus.DefaultRegisterer),
+ }
+
+ return ccipcommit.NewCommitServices(ctx, d.ds, srcProvider, dstProvider, d.legacyChains, jb, lggr, d.pipelineRunner, oracleArgsNoPlugin, d.isNewlyCreatedJob, int64(srcChainID), dstChainID, logError)
+}
+
+func newCCIPCommitPluginBytes(isSourceProvider bool, sourceStartBlock uint64, destStartBlock uint64) config.CommitPluginConfig {
+ return config.CommitPluginConfig{
+ IsSourceProvider: isSourceProvider,
+ SourceStartBlock: sourceStartBlock,
+ DestStartBlock: destStartBlock,
+ }
+}
+
+func (d *Delegate) ccipCommitGetDstProvider(ctx context.Context, jb job.Job, pluginJobSpecConfig ccipconfig.CommitPluginJobSpecConfig, transmitterID string) (types.CCIPCommitProvider, error) {
+ spec := jb.OCR2OracleSpec
+ if spec.Relay != relay.NetworkEVM {
+ return nil, fmt.Errorf("non evm chains are not supported for CCIP commit")
+ }
+
+ dstRid, err := spec.RelayID()
+ if err != nil {
+ return nil, ErrJobSpecNoRelayer{Err: err, PluginName: string(spec.PluginType)}
+ }
+
+ // Write PluginConfig bytes to send source/dest relayer provider + info outside of top level rargs/pargs over the wire
+ dstConfigBytes, err := newCCIPCommitPluginBytes(false, pluginJobSpecConfig.SourceStartBlock, pluginJobSpecConfig.DestStartBlock).Encode()
+ if err != nil {
+ return nil, err
+ }
+
+ // Get provider from dest chain
+ dstRelayer, err := d.RelayGetter.Get(dstRid)
+ if err != nil {
+ return nil, err
+ }
+
+ provider, err := dstRelayer.NewPluginProvider(ctx,
+ types.RelayArgs{
+ ContractID: spec.ContractID,
+ RelayConfig: spec.RelayConfig.Bytes(),
+ ProviderType: string(types.CCIPCommit),
+ },
+ types.PluginArgs{
+ TransmitterID: transmitterID,
+ PluginConfig: dstConfigBytes,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("unable to create ccip commit provider: %w", err)
+ }
+ dstProvider, ok := provider.(types.CCIPCommitProvider)
+ if !ok {
+ return nil, fmt.Errorf("could not coerce PluginProvider to CCIPCommitProvider")
+ }
+
+ return dstProvider, nil
+}
+
+func (d *Delegate) ccipCommitGetSrcProvider(ctx context.Context, jb job.Job, pluginJobSpecConfig ccipconfig.CommitPluginJobSpecConfig, transmitterID string, dstProvider types.CCIPCommitProvider) (srcProvider types.CCIPCommitProvider, srcChainID uint64, err error) {
+ spec := jb.OCR2OracleSpec
+ srcConfigBytes, err := newCCIPCommitPluginBytes(true, pluginJobSpecConfig.SourceStartBlock, pluginJobSpecConfig.DestStartBlock).Encode()
+ if err != nil {
+ return nil, 0, err
+ }
+ // Use OffRampReader to get src chain ID and fetch the src relayer
+
+ var pluginConfig ccipconfig.CommitPluginJobSpecConfig
+ err = json.Unmarshal(spec.PluginConfig.Bytes(), &pluginConfig)
+ if err != nil {
+ return nil, 0, err
+ }
+ offRampAddress := pluginConfig.OffRamp
+ offRampReader, err := dstProvider.NewOffRampReader(ctx, offRampAddress)
+ if err != nil {
+ return nil, 0, fmt.Errorf("create offRampReader: %w", err)
+ }
+
+ offRampConfig, err := offRampReader.GetStaticConfig(ctx)
+ if err != nil {
+ return nil, 0, fmt.Errorf("get offRamp static config: %w", err)
+ }
+
+ srcChainID, err = chainselectors.ChainIdFromSelector(offRampConfig.SourceChainSelector)
+ if err != nil {
+ return nil, 0, err
+ }
+ srcChainIDstr := strconv.FormatUint(srcChainID, 10)
+
+ // Get provider from source chain
+ srcRelayer, err := d.RelayGetter.Get(types.RelayID{Network: spec.Relay, ChainID: srcChainIDstr})
+ if err != nil {
+ return nil, 0, err
+ }
+ provider, err := srcRelayer.NewPluginProvider(ctx,
+ types.RelayArgs{
+ ContractID: "", // Contract address only valid for dst chain
+ RelayConfig: spec.RelayConfig.Bytes(),
+ ProviderType: string(types.CCIPCommit),
+ },
+ types.PluginArgs{
+ TransmitterID: transmitterID,
+ PluginConfig: srcConfigBytes,
+ })
+ if err != nil {
+ return nil, 0, fmt.Errorf("srcRelayer.NewPluginProvider: %w", err)
+ }
+ srcProvider, ok := provider.(types.CCIPCommitProvider)
+ if !ok {
+ return nil, 0, fmt.Errorf("could not coerce PluginProvider to CCIPCommitProvider")
+ }
+
+ return
+}
+
+func (d *Delegate) newServicesCCIPExecution(ctx context.Context, lggr logger.SugaredLogger, jb job.Job, bootstrapPeers []commontypes.BootstrapperLocator, kb ocr2key.KeyBundle, ocrDB *db, lc ocrtypes.LocalConfig, transmitterID string) ([]job.ServiceCtx, error) {
+ spec := jb.OCR2OracleSpec
+ if spec.Relay != relay.NetworkEVM {
+ return nil, fmt.Errorf("non evm chains are not supported for CCIP execution")
+ }
+ dstRid, err := spec.RelayID()
+
+ if err != nil {
+ return nil, ErrJobSpecNoRelayer{Err: err, PluginName: string(spec.PluginType)}
+ }
+
+ logError := func(msg string) {
+ lggr.ErrorIf(d.jobORM.RecordError(context.Background(), jb.ID, msg), "unable to record error")
+ }
+
+ // PROVIDER BASED ARG CONSTRUCTION
+ // Write PluginConfig bytes to send source/dest relayer provider + info outside of top level rargs/pargs over the wire
+ var pluginJobSpecConfig ccipconfig.ExecPluginJobSpecConfig
+ err = json.Unmarshal(spec.PluginConfig.Bytes(), &pluginJobSpecConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ dstChainID, err := strconv.ParseInt(dstRid.ChainID, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ dstProvider, err := d.ccipExecGetDstProvider(ctx, jb, pluginJobSpecConfig, transmitterID)
+ if err != nil {
+ return nil, err
+ }
+
+ srcProvider, srcChainID, err := d.ccipExecGetSrcProvider(ctx, jb, pluginJobSpecConfig, transmitterID, dstProvider)
+ if err != nil {
+ return nil, err
+ }
+
+ oracleArgsNoPlugin2 := libocr2.OCR2OracleArgs{
+ BinaryNetworkEndpointFactory: d.peerWrapper.Peer2,
+ V2Bootstrappers: bootstrapPeers,
+ ContractTransmitter: dstProvider.ContractTransmitter(),
+ ContractConfigTracker: dstProvider.ContractConfigTracker(),
+ Database: ocrDB,
+ LocalConfig: lc,
+ MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(
+ dstRid.Network,
+ dstRid.ChainID,
+ spec.ContractID,
+ synchronization.OCR2CCIPExec,
+ ),
+ OffchainConfigDigester: dstProvider.OffchainConfigDigester(),
+ OffchainKeyring: kb,
+ OnchainKeyring: kb,
+ MetricsRegisterer: prometheus.WrapRegistererWith(map[string]string{"job_name": jb.Name.ValueOrZero()}, prometheus.DefaultRegisterer),
+ }
+
+ return ccipexec.NewExecServices(ctx, lggr, jb, srcProvider, dstProvider, int64(srcChainID), dstChainID, d.isNewlyCreatedJob, oracleArgsNoPlugin2, logError)
+}
+
+func (d *Delegate) ccipExecGetDstProvider(ctx context.Context, jb job.Job, pluginJobSpecConfig ccipconfig.ExecPluginJobSpecConfig, transmitterID string) (types.CCIPExecProvider, error) {
+ spec := jb.OCR2OracleSpec
+ if spec.Relay != relay.NetworkEVM {
+ return nil, fmt.Errorf("non evm chains are not supported for CCIP execution")
+ }
+ dstRid, err := spec.RelayID()
+
+ if err != nil {
+ return nil, ErrJobSpecNoRelayer{Err: err, PluginName: string(spec.PluginType)}
+ }
+
+ // PROVIDER BASED ARG CONSTRUCTION
+ // Write PluginConfig bytes to send source/dest relayer provider + info outside of top level rargs/pargs over the wire
+ dstConfigBytes, err := newExecPluginConfig(false, pluginJobSpecConfig.SourceStartBlock, pluginJobSpecConfig.DestStartBlock, pluginJobSpecConfig.USDCConfig, string(jb.ID)).Encode()
+ if err != nil {
+ return nil, err
+ }
+
+ // Get provider from dest chain
+ dstRelayer, err := d.RelayGetter.Get(dstRid)
+ if err != nil {
+ return nil, err
+ }
+ provider, err := dstRelayer.NewPluginProvider(ctx,
+ types.RelayArgs{
+ ContractID: spec.ContractID,
+ RelayConfig: spec.RelayConfig.Bytes(),
+ ProviderType: string(types.CCIPExecution),
+ },
+ types.PluginArgs{
+ TransmitterID: transmitterID,
+ PluginConfig: dstConfigBytes,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("NewPluginProvider failed on dstRelayer: %w", err)
+ }
+ dstProvider, ok := provider.(types.CCIPExecProvider)
+ if !ok {
+ return nil, fmt.Errorf("could not coerce PluginProvider to CCIPExecProvider")
+ }
+
+ return dstProvider, nil
+}
+
+func (d *Delegate) ccipExecGetSrcProvider(ctx context.Context, jb job.Job, pluginJobSpecConfig ccipconfig.ExecPluginJobSpecConfig, transmitterID string, dstProvider types.CCIPExecProvider) (srcProvider types.CCIPExecProvider, srcChainID uint64, err error) {
+ spec := jb.OCR2OracleSpec
+ srcConfigBytes, err := newExecPluginConfig(true, pluginJobSpecConfig.SourceStartBlock, pluginJobSpecConfig.DestStartBlock, pluginJobSpecConfig.USDCConfig, string(jb.ID)).Encode()
+ if err != nil {
+ return nil, 0, err
+ }
+
+ // Use OffRampReader to get src chain ID and fetch the src relayer
+ offRampAddress := cciptypes.Address(common.HexToAddress(spec.ContractID).String())
+ offRampReader, err := dstProvider.NewOffRampReader(ctx, offRampAddress)
+ if err != nil {
+ return nil, 0, fmt.Errorf("create offRampReader: %w", err)
+ }
+
+ offRampConfig, err := offRampReader.GetStaticConfig(ctx)
+ if err != nil {
+ return nil, 0, fmt.Errorf("get offRamp static config: %w", err)
+ }
+
+ srcChainID, err = chainselectors.ChainIdFromSelector(offRampConfig.SourceChainSelector)
+ if err != nil {
+ return nil, 0, err
+ }
+ srcChainIDstr := strconv.FormatUint(srcChainID, 10)
+
+ // Get provider from source chain
+ srcRelayer, err := d.RelayGetter.Get(types.RelayID{Network: spec.Relay, ChainID: srcChainIDstr})
+ if err != nil {
+ return nil, 0, fmt.Errorf("failed to get relayer: %w", err)
+ }
+ provider, err := srcRelayer.NewPluginProvider(ctx,
+ types.RelayArgs{
+ ContractID: "",
+ RelayConfig: spec.RelayConfig.Bytes(),
+ ProviderType: string(types.CCIPExecution),
+ },
+ types.PluginArgs{
+ TransmitterID: transmitterID,
+ PluginConfig: srcConfigBytes,
+ })
+ if err != nil {
+ return nil, 0, err
+ }
+ srcProvider, ok := provider.(types.CCIPExecProvider)
+ if !ok {
+ return nil, 0, fmt.Errorf("could not coerce PluginProvider to CCIPExecProvider: %w", err)
+ }
+
+ return
+}
+
+func newExecPluginConfig(isSourceProvider bool, srcStartBlock uint64, dstStartBlock uint64, usdcConfig ccipconfig.USDCConfig, jobID string) config.ExecPluginConfig {
+ return config.ExecPluginConfig{
+ IsSourceProvider: isSourceProvider,
+ SourceStartBlock: srcStartBlock,
+ DestStartBlock: dstStartBlock,
+ USDCConfig: usdcConfig,
+ JobID: jobID,
+ }
+}
+
// errorLog implements [loop.ErrorLog]
type errorLog struct {
jobID int32
diff --git a/core/services/ocr2/plugins/ccip/LICENSE.md b/core/services/ocr2/plugins/ccip/LICENSE.md
new file mode 100644
index 00000000000..b127e1a823a
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/LICENSE.md
@@ -0,0 +1,55 @@
+Business Source License 1.1
+
+License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
+"Business Source License" is a trademark of MariaDB Corporation Ab.
+
+-----------------------------------------------------------------------------
+
+Parameters
+
+Licensor: SmartContract Chainlink Limited SEZC
+
+Licensed Work: Cross-Chain Interoperability Protocol v1.4
+The Licensed Work is (c) 2023 SmartContract Chainlink Limited SEZC
+
+Additional Use Grant: Any uses listed and defined at [v1.4-CCIP-License-grants](../../../../../contracts/src/v0.8/ccip/v1.4-CCIP-License-grants)
+
+Change Date: May 23, 2027
+
+Change License: MIT
+
+-----------------------------------------------------------------------------
+
+Terms
+
+The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use.
+
+Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate.
+
+If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work.
+
+All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor.
+
+You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work.
+
+Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work.
+
+This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License).
+
+TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
+
+MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below.
+
+-----------------------------------------------------------------------------
+
+Covenants of Licensor
+
+In consideration of the right to use this License’s text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor:
+
+1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation.
+
+2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None".
+
+3. To specify a Change Date.
+
+4. Not to modify this License in any other way.
\ No newline at end of file
diff --git a/core/services/ocr2/plugins/ccip/abihelpers/abi_helpers.go b/core/services/ocr2/plugins/ccip/abihelpers/abi_helpers.go
new file mode 100644
index 00000000000..d0ad5642d94
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/abihelpers/abi_helpers.go
@@ -0,0 +1,187 @@
+package abihelpers
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math/big"
+ "strings"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+ "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
+)
+
+func MustGetEventID(name string, abi2 abi.ABI) common.Hash {
+ event, ok := abi2.Events[name]
+ if !ok {
+ panic(fmt.Sprintf("missing event %s", name))
+ }
+ return event.ID
+}
+
+func MustGetEventInputs(name string, abi2 abi.ABI) abi.Arguments {
+ m, ok := abi2.Events[name]
+ if !ok {
+ panic(fmt.Sprintf("missing event %s", name))
+ }
+ return m.Inputs
+}
+
+func MustGetMethodInputs(name string, abi2 abi.ABI) abi.Arguments {
+ m, ok := abi2.Methods[name]
+ if !ok {
+ panic(fmt.Sprintf("missing method %s", name))
+ }
+ return m.Inputs
+}
+
+func MustParseABI(abiStr string) abi.ABI {
+ abiParsed, err := abi.JSON(strings.NewReader(abiStr))
+ if err != nil {
+ panic(err)
+ }
+ return abiParsed
+}
+
+// ProofFlagsToBits transforms a list of boolean proof flags to a *big.Int
+// encoded number.
+func ProofFlagsToBits(proofFlags []bool) *big.Int {
+ encodedFlags := big.NewInt(0)
+ for i := 0; i < len(proofFlags); i++ {
+ if proofFlags[i] {
+ encodedFlags.SetBit(encodedFlags, i, 1)
+ }
+ }
+ return encodedFlags
+}
+
+type AbiDefined interface {
+ AbiString() string
+}
+
+type AbiDefinedValid interface {
+ AbiDefined
+ Validate() error
+}
+
+func ABIEncode(abiStr string, values ...interface{}) ([]byte, error) {
+ inAbi, err := getABI(abiStr, ENCODE)
+ if err != nil {
+ return nil, err
+ }
+ res, err := inAbi.Pack("method", values...)
+ if err != nil {
+ return nil, err
+ }
+ return res[4:], nil
+}
+
+func ABIDecode(abiStr string, data []byte) ([]interface{}, error) {
+ inAbi, err := getABI(abiStr, DECODE)
+ if err != nil {
+ return nil, err
+ }
+ return inAbi.Unpack("method", data)
+}
+
+func EncodeAbiStruct[T AbiDefined](decoded T) ([]byte, error) {
+ return ABIEncode(decoded.AbiString(), decoded)
+}
+
+func EncodeAddress(address common.Address) ([]byte, error) {
+ return ABIEncode(`[{"type":"address"}]`, address)
+}
+
+func DecodeAbiStruct[T AbiDefinedValid](encoded []byte) (T, error) {
+ var empty T
+
+ decoded, err := ABIDecode(empty.AbiString(), encoded)
+ if err != nil {
+ return empty, err
+ }
+
+ converted := abi.ConvertType(decoded[0], &empty)
+ if casted, ok := converted.(*T); ok {
+ return *casted, (*casted).Validate()
+ }
+ return empty, fmt.Errorf("can't cast from %T to %T", converted, empty)
+}
+
+func EvmWord(i uint64) common.Hash {
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint64(b, i)
+ return common.BigToHash(big.NewInt(0).SetBytes(b))
+}
+
+func DecodeOCR2Config(encoded []byte) (*ocr2aggregator.OCR2AggregatorConfigSet, error) {
+ unpacked := new(ocr2aggregator.OCR2AggregatorConfigSet)
+ abiPointer, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi()
+ if err != nil {
+ return unpacked, err
+ }
+ defaultABI := *abiPointer
+ err = defaultABI.UnpackIntoInterface(unpacked, "ConfigSet", encoded)
+ if err != nil {
+ return unpacked, errors.Wrap(err, "failed to unpack log data")
+ }
+ return unpacked, nil
+}
+
+// create const encode and decode
+const (
+ ENCODE = iota
+ DECODE
+)
+
+type abiCache struct {
+ cache map[string]*abi.ABI
+ mu *sync.RWMutex
+}
+
+func newAbiCache() *abiCache {
+ return &abiCache{
+ cache: make(map[string]*abi.ABI),
+ mu: &sync.RWMutex{},
+ }
+}
+
+// Global cache for ABIs to avoid parsing the same ABI multiple times
+// As the module is already a helper module and not a service, we can keep the cache global
+// It's private to the package and can't be accessed from outside
+var myAbiCache = newAbiCache()
+
+// This Function is used to get the ABI from the cache or create a new one and cache it for later use
+// operationType is used to differentiate between encoding and decoding
+// encoding uses a definition with `inputs` and decoding uses a definition with `outputs` (check inDef)
+func getABI(abiStr string, operationType uint8) (*abi.ABI, error) {
+ var operationStr string
+ switch operationType {
+ case ENCODE:
+ operationStr = "inputs"
+ case DECODE:
+ operationStr = "outputs"
+ default:
+ return nil, fmt.Errorf("invalid operation type")
+ }
+
+ inDef := fmt.Sprintf(`[{ "name" : "method", "type": "function", "%s": %s}]`, operationStr, abiStr)
+
+ myAbiCache.mu.RLock()
+ if cachedAbi, found := myAbiCache.cache[inDef]; found {
+ myAbiCache.mu.RUnlock() // unlocking before returning
+ return cachedAbi, nil
+ }
+ myAbiCache.mu.RUnlock()
+
+ res, err := abi.JSON(strings.NewReader(inDef))
+ if err != nil {
+ return nil, err
+ }
+
+ myAbiCache.mu.Lock()
+ defer myAbiCache.mu.Unlock()
+ myAbiCache.cache[inDef] = &res
+ return &res, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/abihelpers/abi_helpers_test.go b/core/services/ocr2/plugins/ccip/abihelpers/abi_helpers_test.go
new file mode 100644
index 00000000000..4890aeb1188
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/abihelpers/abi_helpers_test.go
@@ -0,0 +1,147 @@
+package abihelpers
+
+import (
+ "bytes"
+ "fmt"
+ "math"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+)
+
+func TestProofFlagToBits(t *testing.T) {
+ genFlags := func(indexesSet []int, size int) []bool {
+ bools := make([]bool, size)
+ for _, indexSet := range indexesSet {
+ bools[indexSet] = true
+ }
+ return bools
+ }
+ tt := []struct {
+ flags []bool
+ expected *big.Int
+ }{
+ {
+ []bool{true, false, true},
+ big.NewInt(5),
+ },
+ {
+ []bool{true, true, false}, // Note the bits are reversed, slightly easier to implement.
+ big.NewInt(3),
+ },
+ {
+ []bool{false, true, true},
+ big.NewInt(6),
+ },
+ {
+ []bool{false, false, false},
+ big.NewInt(0),
+ },
+ {
+ []bool{true, true, true},
+ big.NewInt(7),
+ },
+ {
+ genFlags([]int{266}, 300),
+ big.NewInt(0).SetBit(big.NewInt(0), 266, 1),
+ },
+ }
+ for _, tc := range tt {
+ tc := tc
+ a := ProofFlagsToBits(tc.flags)
+ assert.Equal(t, tc.expected.String(), a.String())
+ }
+}
+
+func TestEvmWord(t *testing.T) {
+ testCases := []struct {
+ inp uint64
+ exp common.Hash
+ }{
+ {inp: 1, exp: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001")},
+ {inp: math.MaxUint64, exp: common.HexToHash("0x000000000000000000000000000000000000000000000000ffffffffffffffff")},
+ }
+
+ for _, tc := range testCases {
+ t.Run(fmt.Sprintf("test %d", tc.inp), func(t *testing.T) {
+ h := EvmWord(tc.inp)
+ assert.Equal(t, tc.exp, h)
+ })
+ }
+}
+
+func TestABIEncodeDecode(t *testing.T) {
+ abiStr := `[{"components": [{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}], "type":"tuple"}]`
+ values := []interface{}{struct {
+ Int1 *big.Int `json:"int1"`
+ Int2 *big.Int `json:"int2"`
+ }{big.NewInt(10), big.NewInt(12)}}
+
+ // First encoding, should call the underlying utils.ABIEncode
+ encoded, err := ABIEncode(abiStr, values...)
+ assert.NoError(t, err)
+ assert.NotNil(t, encoded)
+
+ // Second encoding, should retrieve from cache
+ // we're just testing here that it returns same result
+ encodedAgain, err := ABIEncode(abiStr, values...)
+
+ assert.NoError(t, err)
+ assert.True(t, bytes.Equal(encoded, encodedAgain))
+
+ // Should be able to decode it back to the original values
+ decoded, err := ABIDecode(abiStr, encoded)
+ assert.NoError(t, err)
+ assert.Equal(t, decoded, values)
+}
+
+func BenchmarkComparisonEncode(b *testing.B) {
+ abiStr := `[{"components": [{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}], "type":"tuple"}]`
+ values := []interface{}{struct {
+ Int1 *big.Int `json:"int1"`
+ Int2 *big.Int `json:"int2"`
+ }{big.NewInt(10), big.NewInt(12)}}
+
+ b.Run("WithoutCache", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, _ = utils.ABIEncode(abiStr, values...)
+ }
+ })
+
+ // Warm up the cache
+ _, _ = ABIEncode(abiStr, values...)
+
+ b.Run("WithCache", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, _ = ABIEncode(abiStr, values...)
+ }
+ })
+}
+
+func BenchmarkComparisonDecode(b *testing.B) {
+ abiStr := `[{"components": [{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}], "type":"tuple"}]`
+ values := []interface{}{struct {
+ Int1 *big.Int `json:"int1"`
+ Int2 *big.Int `json:"int2"`
+ }{big.NewInt(10), big.NewInt(12)}}
+ data, _ := utils.ABIEncode(abiStr, values...)
+
+ b.Run("WithoutCache", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, _ = utils.ABIDecode(abiStr, data)
+ }
+ })
+
+ // Warm up the cache
+ _, _ = ABIDecode(abiStr, data)
+
+ b.Run("WithCache", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, _ = ABIDecode(abiStr, data)
+ }
+ })
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipcommit/factory.go b/core/services/ocr2/plugins/ccip/ccipcommit/factory.go
new file mode 100644
index 00000000000..648f62a23a2
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipcommit/factory.go
@@ -0,0 +1,150 @@
+package ccipcommit
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+type CommitReportingPluginFactory struct {
+ // Configuration derived from the job spec which does not change
+ // between plugin instances (ie between SetConfigs onchain)
+ config CommitPluginStaticConfig
+
+ // Dynamic readers
+ readersMu *sync.Mutex
+ destPriceRegReader ccipdata.PriceRegistryReader
+ destPriceRegAddr common.Address
+}
+
+// NewCommitReportingPluginFactory return a new CommitReportingPluginFactory.
+func NewCommitReportingPluginFactory(config CommitPluginStaticConfig) *CommitReportingPluginFactory {
+ return &CommitReportingPluginFactory{
+ config: config,
+ readersMu: &sync.Mutex{},
+
+ // the fields below are initially empty and populated on demand
+ destPriceRegReader: nil,
+ destPriceRegAddr: common.Address{},
+ }
+}
+
+func (rf *CommitReportingPluginFactory) UpdateDynamicReaders(ctx context.Context, newPriceRegAddr common.Address) error {
+ rf.readersMu.Lock()
+ defer rf.readersMu.Unlock()
+ // TODO: Investigate use of Close() to cleanup.
+ // TODO: a true price registry upgrade on an existing lane may want some kind of start block in its config? Right now we
+ // essentially assume that plugins don't care about historical price reg logs.
+ if rf.destPriceRegAddr == newPriceRegAddr {
+ // No-op
+ return nil
+ }
+ // Close old reader if present and open new reader if address changed
+ if rf.destPriceRegReader != nil {
+ if err := rf.destPriceRegReader.Close(); err != nil {
+ return err
+ }
+ }
+
+ destPriceRegistryReader, err := rf.config.priceRegistryProvider.NewPriceRegistryReader(context.Background(), cciptypes.Address(newPriceRegAddr.String()))
+ if err != nil {
+ return fmt.Errorf("init dynamic price registry: %w", err)
+ }
+ rf.destPriceRegReader = destPriceRegistryReader
+ rf.destPriceRegAddr = newPriceRegAddr
+ return nil
+}
+
+type reportingPluginAndInfo struct {
+ plugin types.ReportingPlugin
+ pluginInfo types.ReportingPluginInfo
+}
+
+// NewReportingPlugin registers a new ReportingPlugin
+func (rf *CommitReportingPluginFactory) NewReportingPlugin(config types.ReportingPluginConfig) (types.ReportingPlugin, types.ReportingPluginInfo, error) {
+ initialRetryDelay := rf.config.newReportingPluginRetryConfig.InitialDelay
+ maxDelay := rf.config.newReportingPluginRetryConfig.MaxDelay
+
+ pluginAndInfo, err := ccipcommon.RetryUntilSuccess(rf.NewReportingPluginFn(config), initialRetryDelay, maxDelay)
+ if err != nil {
+ return nil, types.ReportingPluginInfo{}, err
+ }
+ return pluginAndInfo.plugin, pluginAndInfo.pluginInfo, err
+}
+
+// NewReportingPluginFn implements the NewReportingPlugin logic. It is defined as a function so that it can easily be
+// retried via RetryUntilSuccess. NewReportingPlugin must return successfully in order for the Commit plugin to
+// function, hence why we can only keep retrying it until it succeeds.
+func (rf *CommitReportingPluginFactory) NewReportingPluginFn(config types.ReportingPluginConfig) func() (reportingPluginAndInfo, error) {
+ return func() (reportingPluginAndInfo, error) {
+ ctx := context.Background() // todo: consider adding some timeout
+
+ destPriceReg, err := rf.config.commitStore.ChangeConfig(ctx, config.OnchainConfig, config.OffchainConfig)
+ if err != nil {
+ return reportingPluginAndInfo{}, err
+ }
+
+ priceRegEvmAddr, err := ccipcalc.GenericAddrToEvm(destPriceReg)
+ if err != nil {
+ return reportingPluginAndInfo{}, err
+ }
+ if err = rf.UpdateDynamicReaders(ctx, priceRegEvmAddr); err != nil {
+ return reportingPluginAndInfo{}, err
+ }
+
+ pluginOffChainConfig, err := rf.config.commitStore.OffchainConfig(ctx)
+ if err != nil {
+ return reportingPluginAndInfo{}, err
+ }
+
+ gasPriceEstimator, err := rf.config.commitStore.GasPriceEstimator(ctx)
+ if err != nil {
+ return reportingPluginAndInfo{}, err
+ }
+
+ err = rf.config.priceService.UpdateDynamicConfig(ctx, gasPriceEstimator, rf.destPriceRegReader)
+ if err != nil {
+ return reportingPluginAndInfo{}, err
+ }
+
+ lggr := rf.config.lggr.Named("CommitReportingPlugin")
+ plugin := &CommitReportingPlugin{
+ sourceChainSelector: rf.config.sourceChainSelector,
+ sourceNative: rf.config.sourceNative,
+ onRampReader: rf.config.onRampReader,
+ destChainSelector: rf.config.destChainSelector,
+ commitStoreReader: rf.config.commitStore,
+ F: config.F,
+ lggr: lggr,
+ destPriceRegistryReader: rf.destPriceRegReader,
+ offRampReader: rf.config.offRamp,
+ gasPriceEstimator: gasPriceEstimator,
+ offchainConfig: pluginOffChainConfig,
+ metricsCollector: rf.config.metricsCollector,
+ chainHealthcheck: rf.config.chainHealthcheck,
+ priceService: rf.config.priceService,
+ }
+
+ pluginInfo := types.ReportingPluginInfo{
+ Name: "CCIPCommit",
+ UniqueReports: false, // See comment in CommitStore constructor.
+ Limits: types.ReportingPluginLimits{
+ MaxQueryLength: ccip.MaxQueryLength,
+ MaxObservationLength: ccip.MaxObservationLength,
+ MaxReportLength: MaxCommitReportLength,
+ },
+ }
+
+ return reportingPluginAndInfo{plugin, pluginInfo}, nil
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipcommit/factory_test.go b/core/services/ocr2/plugins/ccip/ccipcommit/factory_test.go
new file mode 100644
index 00000000000..825026bd17e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipcommit/factory_test.go
@@ -0,0 +1,100 @@
+package ccipcommit
+
+import (
+ "errors"
+ "testing"
+ "time"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ ccipdataprovidermocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+ dbMocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdb/mocks"
+)
+
+// Assert that NewReportingPlugin keeps retrying until it succeeds.
+//
+// NewReportingPlugin makes several calls (e.g. CommitStoreReader.ChangeConfig) that can fail. We use mocks to cause the
+// first call to each of these functions to fail, then all subsequent calls succeed. We assert that NewReportingPlugin
+// retries a sufficient number of times to get through the transient errors and eventually succeed.
+func TestNewReportingPluginRetriesUntilSuccess(t *testing.T) {
+ commitConfig := CommitPluginStaticConfig{}
+
+ // For this unit test, ensure that there is no delay between retries
+ commitConfig.newReportingPluginRetryConfig = ccipdata.RetryConfig{
+ InitialDelay: 0 * time.Nanosecond,
+ MaxDelay: 0 * time.Nanosecond,
+ }
+
+ // Set up the OffRampReader mock
+ mockCommitStore := new(mocks.CommitStoreReader)
+
+ // The first call is set to return an error, the following calls return a nil error
+ mockCommitStore.
+ On("ChangeConfig", mock.Anything, mock.Anything, mock.Anything).
+ Return(ccip.Address(""), errors.New("")).
+ Once()
+ mockCommitStore.
+ On("ChangeConfig", mock.Anything, mock.Anything, mock.Anything).
+ Return(ccip.Address("0x7c6e4F0BDe29f83BC394B75a7f313B7E5DbD2d77"), nil).
+ Times(5)
+
+ mockCommitStore.
+ On("OffchainConfig", mock.Anything).
+ Return(ccip.CommitOffchainConfig{}, errors.New("")).
+ Once()
+ mockCommitStore.
+ On("OffchainConfig", mock.Anything).
+ Return(ccip.CommitOffchainConfig{}, nil).
+ Times(3)
+
+ mockCommitStore.
+ On("GasPriceEstimator", mock.Anything).
+ Return(nil, errors.New("")).
+ Once()
+ mockCommitStore.
+ On("GasPriceEstimator", mock.Anything).
+ Return(nil, nil).
+ Times(2)
+
+ commitConfig.commitStore = mockCommitStore
+
+ mockPriceService := new(dbMocks.PriceService)
+
+ mockPriceService.
+ On("UpdateDynamicConfig", mock.Anything, mock.Anything, mock.Anything).
+ Return(errors.New("")).
+ Once()
+ mockPriceService.
+ On("UpdateDynamicConfig", mock.Anything, mock.Anything, mock.Anything).
+ Return(nil)
+
+ commitConfig.priceService = mockPriceService
+
+ priceRegistryProvider := new(ccipdataprovidermocks.PriceRegistry)
+ priceRegistryProvider.
+ On("NewPriceRegistryReader", mock.Anything, mock.Anything).
+ Return(nil, errors.New("")).
+ Once()
+ priceRegistryProvider.
+ On("NewPriceRegistryReader", mock.Anything, mock.Anything).
+ Return(nil, nil).
+ Once()
+ commitConfig.priceRegistryProvider = priceRegistryProvider
+
+ commitConfig.lggr, _ = logger.NewLogger()
+
+ factory := NewCommitReportingPluginFactory(commitConfig)
+ reportingConfig := types.ReportingPluginConfig{}
+ reportingConfig.OnchainConfig = []byte{1, 2, 3}
+ reportingConfig.OffchainConfig = []byte{1, 2, 3}
+
+ // Assert that NewReportingPlugin succeeds despite many transient internal failures (mocked out above)
+ _, _, err := factory.NewReportingPlugin(reportingConfig)
+ assert.Equal(t, nil, err)
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipcommit/initializers.go b/core/services/ocr2/plugins/ccip/ccipcommit/initializers.go
new file mode 100644
index 00000000000..771fdd322f3
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipcommit/initializers.go
@@ -0,0 +1,241 @@
+package ccipcommit
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "strings"
+ "time"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+
+ "github.com/Masterminds/semver/v3"
+ "github.com/ethereum/go-ethereum/common"
+ libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus"
+ "go.uber.org/multierr"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+
+ commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
+
+ cciporm "github.com/smartcontractkit/chainlink/v2/core/services/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ db "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdb"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
+ "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/ocr2/plugins/ccip"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/observability"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/oraclelib"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/promwrapper"
+ "github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
+)
+
+var defaultNewReportingPluginRetryConfig = ccipdata.RetryConfig{InitialDelay: time.Second, MaxDelay: 5 * time.Minute}
+
+func NewCommitServices(ctx context.Context, ds sqlutil.DataSource, srcProvider commontypes.CCIPCommitProvider, dstProvider commontypes.CCIPCommitProvider, chainSet legacyevm.LegacyChainContainer, jb job.Job, lggr logger.Logger, pr pipeline.Runner, argsNoPlugin libocr2.OCR2OracleArgs, new bool, sourceChainID int64, destChainID int64, logError func(string)) ([]job.ServiceCtx, error) {
+ spec := jb.OCR2OracleSpec
+
+ var pluginConfig ccipconfig.CommitPluginJobSpecConfig
+ err := json.Unmarshal(spec.PluginConfig.Bytes(), &pluginConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ commitStoreAddress := common.HexToAddress(spec.ContractID)
+
+ // commit store contract doesn't exist on the source chain, but we have an implementation of it
+ // to get access to a gas estimator on the source chain
+ srcCommitStore, err := srcProvider.NewCommitStoreReader(ctx, ccipcalc.EvmAddrToGeneric(commitStoreAddress))
+ if err != nil {
+ return nil, err
+ }
+
+ dstCommitStore, err := dstProvider.NewCommitStoreReader(ctx, ccipcalc.EvmAddrToGeneric(commitStoreAddress))
+ if err != nil {
+ return nil, err
+ }
+
+ var commitStoreReader ccipdata.CommitStoreReader
+ commitStoreReader = ccip.NewProviderProxyCommitStoreReader(srcCommitStore, dstCommitStore)
+ commitLggr := lggr.Named("CCIPCommit").With("sourceChain", sourceChainID, "destChain", destChainID)
+
+ var priceGetter pricegetter.AllTokensPriceGetter
+ withPipeline := strings.Trim(pluginConfig.TokenPricesUSDPipeline, "\n\t ") != ""
+ if withPipeline {
+ priceGetter, err = pricegetter.NewPipelineGetter(pluginConfig.TokenPricesUSDPipeline, pr, jb.ID, jb.ExternalJobID, jb.Name.ValueOrZero(), lggr)
+ if err != nil {
+ return nil, fmt.Errorf("creating pipeline price getter: %w", err)
+ }
+ } else {
+ // Use dynamic price getter.
+ if pluginConfig.PriceGetterConfig == nil {
+ return nil, fmt.Errorf("priceGetterConfig is nil")
+ }
+
+ // Build price getter clients for all chains specified in the aggregator configurations.
+ // Some lanes (e.g. Wemix/Kroma) requires other clients than source and destination, since they use feeds from other chains.
+ priceGetterClients := map[uint64]pricegetter.DynamicPriceGetterClient{}
+ for _, aggCfg := range pluginConfig.PriceGetterConfig.AggregatorPrices {
+ chainID := aggCfg.ChainID
+ // Retrieve the chain.
+ chain, _, err2 := ccipconfig.GetChainByChainID(chainSet, chainID)
+ if err2 != nil {
+ return nil, fmt.Errorf("retrieving chain for chainID %d: %w", chainID, err2)
+ }
+ caller := rpclib.NewDynamicLimitedBatchCaller(
+ lggr,
+ chain.Client(),
+ rpclib.DefaultRpcBatchSizeLimit,
+ rpclib.DefaultRpcBatchBackOffMultiplier,
+ rpclib.DefaultMaxParallelRpcCalls,
+ )
+ priceGetterClients[chainID] = pricegetter.NewDynamicPriceGetterClient(caller)
+ }
+
+ priceGetter, err = pricegetter.NewDynamicPriceGetter(*pluginConfig.PriceGetterConfig, priceGetterClients)
+ if err != nil {
+ return nil, fmt.Errorf("creating dynamic price getter: %w", err)
+ }
+ }
+
+ offRampReader, err := dstProvider.NewOffRampReader(ctx, pluginConfig.OffRamp)
+ if err != nil {
+ return nil, err
+ }
+
+ staticConfig, err := commitStoreReader.GetCommitStoreStaticConfig(ctx)
+ if err != nil {
+ return nil, err
+ }
+ onRampAddress := staticConfig.OnRamp
+
+ onRampReader, err := srcProvider.NewOnRampReader(ctx, onRampAddress, staticConfig.SourceChainSelector, staticConfig.ChainSelector)
+ if err != nil {
+ return nil, err
+ }
+
+ onRampRouterAddr, err := onRampReader.RouterAddress(ctx)
+ if err != nil {
+ return nil, err
+ }
+ sourceNative, err := srcProvider.SourceNativeToken(ctx, onRampRouterAddr)
+ if err != nil {
+ return nil, err
+ }
+ // Prom wrappers
+ onRampReader = observability.NewObservedOnRampReader(onRampReader, sourceChainID, ccip.CommitPluginLabel)
+ commitStoreReader = observability.NewObservedCommitStoreReader(commitStoreReader, destChainID, ccip.CommitPluginLabel)
+ offRampReader = observability.NewObservedOffRampReader(offRampReader, destChainID, ccip.CommitPluginLabel)
+ metricsCollector := ccip.NewPluginMetricsCollector(ccip.CommitPluginLabel, sourceChainID, destChainID)
+
+ chainHealthCheck := cache.NewObservedChainHealthCheck(
+ cache.NewChainHealthcheck(
+ // Adding more details to Logger to make healthcheck logs more informative
+ // It's safe because healthcheck logs only in case of unhealthy state
+ lggr.With(
+ "onramp", onRampAddress,
+ "commitStore", commitStoreAddress,
+ "offramp", pluginConfig.OffRamp,
+ ),
+ onRampReader,
+ commitStoreReader,
+ ),
+ ccip.CommitPluginLabel,
+ sourceChainID, // assuming this is the chain id?
+ destChainID,
+ onRampAddress,
+ )
+
+ orm, err := cciporm.NewObservedORM(ds, lggr)
+ if err != nil {
+ return nil, err
+ }
+
+ priceService := db.NewPriceService(
+ lggr,
+ orm,
+ jb.ID,
+ staticConfig.ChainSelector,
+ staticConfig.SourceChainSelector,
+ sourceNative,
+ priceGetter,
+ offRampReader,
+ )
+
+ wrappedPluginFactory := NewCommitReportingPluginFactory(CommitPluginStaticConfig{
+ lggr: lggr,
+ newReportingPluginRetryConfig: defaultNewReportingPluginRetryConfig,
+ onRampReader: onRampReader,
+ sourceChainSelector: staticConfig.SourceChainSelector,
+ sourceNative: sourceNative,
+ offRamp: offRampReader,
+ commitStore: commitStoreReader,
+ destChainSelector: staticConfig.ChainSelector,
+ priceRegistryProvider: ccip.NewChainAgnosticPriceRegistry(dstProvider),
+ metricsCollector: metricsCollector,
+ chainHealthcheck: chainHealthCheck,
+ priceService: priceService,
+ })
+ argsNoPlugin.ReportingPluginFactory = promwrapper.NewPromFactory(wrappedPluginFactory, "CCIPCommit", jb.OCR2OracleSpec.Relay, big.NewInt(0).SetInt64(destChainID))
+ argsNoPlugin.Logger = commonlogger.NewOCRWrapper(commitLggr, true, logError)
+ oracle, err := libocr2.NewOracle(argsNoPlugin)
+ if err != nil {
+ return nil, err
+ }
+ // If this is a brand-new job, then we make use of the start blocks. If not then we're rebooting and log poller will pick up where we left off.
+ if new {
+ return []job.ServiceCtx{
+ oraclelib.NewChainAgnosticBackFilledOracle(
+ lggr,
+ srcProvider,
+ dstProvider,
+ job.NewServiceAdapter(oracle),
+ ),
+ chainHealthCheck,
+ priceService,
+ }, nil
+ }
+ return []job.ServiceCtx{
+ job.NewServiceAdapter(oracle),
+ chainHealthCheck,
+ priceService,
+ }, nil
+}
+
+func CommitReportToEthTxMeta(typ ccipconfig.ContractType, ver semver.Version) (func(report []byte) (*txmgr.TxMeta, error), error) {
+ return factory.CommitReportToEthTxMeta(typ, ver)
+}
+
+// UnregisterCommitPluginLpFilters unregisters all the registered filters for both source and dest chains.
+// NOTE: The transaction MUST be used here for CLO's monster tx to function as expected
+// https://github.com/smartcontractkit/ccip/blob/68e2197472fb017dd4e5630d21e7878d58bc2a44/core/services/feeds/service.go#L716
+// TODO once that transaction is broken up, we should be able to simply rely on oracle.Close() to cleanup the filters.
+// Until then we have to deterministically reload the readers from the spec (and thus their filters) and close them.
+func UnregisterCommitPluginLpFilters(srcProvider commontypes.CCIPCommitProvider, dstProvider commontypes.CCIPCommitProvider) error {
+ unregisterFuncs := []func() error{
+ func() error {
+ return srcProvider.Close()
+ },
+ func() error {
+ return dstProvider.Close()
+ },
+ }
+
+ var multiErr error
+ for _, fn := range unregisterFuncs {
+ if err := fn(); err != nil {
+ multiErr = multierr.Append(multiErr, err)
+ }
+ }
+ return multiErr
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go b/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go
new file mode 100644
index 00000000000..2f0fc4e7956
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipcommit/ocr2.go
@@ -0,0 +1,753 @@
+package ccipcommit
+
+import (
+ "context"
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "sort"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/merklemulti"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider"
+ db "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdb"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+const (
+ // only dynamic field in CommitReport is tokens PriceUpdates, and we don't expect to need to update thousands of tokens in a single tx
+ MaxCommitReportLength = 10_000
+ // Maximum inflight seq number range before we consider reports to be failing to get included entirely
+ // and restart from the chain's minSeqNum. Want to set it high to allow for large throughput,
+ // but low enough to minimize wasted revert cost.
+ MaxInflightSeqNumGap = 500
+ // OnRampMessagesScanLimit is used to limit number of onramp messages scanned in each Observation.
+ // Single CommitRoot can contain up to merklemulti.MaxNumberTreeLeaves, so we scan twice that to be safe and still don't hurt DB performance.
+ OnRampMessagesScanLimit = merklemulti.MaxNumberTreeLeaves * 2
+)
+
+var (
+ _ types.ReportingPluginFactory = &CommitReportingPluginFactory{}
+ _ types.ReportingPlugin = &CommitReportingPlugin{}
+)
+
+type update struct {
+ timestamp time.Time
+ value *big.Int
+}
+
+type CommitPluginStaticConfig struct {
+ lggr logger.Logger
+ newReportingPluginRetryConfig ccipdata.RetryConfig
+ // Source
+ onRampReader ccipdata.OnRampReader
+ sourceChainSelector uint64
+ sourceNative cciptypes.Address
+ // Dest
+ offRamp ccipdata.OffRampReader
+ commitStore ccipdata.CommitStoreReader
+ destChainSelector uint64
+ priceRegistryProvider ccipdataprovider.PriceRegistry
+ // Offchain
+ metricsCollector ccip.PluginMetricsCollector
+ chainHealthcheck cache.ChainHealthcheck
+ priceService db.PriceService
+}
+
+type CommitReportingPlugin struct {
+ lggr logger.Logger
+ // Source
+ onRampReader ccipdata.OnRampReader
+ sourceChainSelector uint64
+ sourceNative cciptypes.Address
+ gasPriceEstimator prices.GasPriceEstimatorCommit
+ // Dest
+ destChainSelector uint64
+ commitStoreReader ccipdata.CommitStoreReader
+ destPriceRegistryReader ccipdata.PriceRegistryReader
+ offchainConfig cciptypes.CommitOffchainConfig
+ offRampReader ccipdata.OffRampReader
+ F int
+ // Offchain
+ metricsCollector ccip.PluginMetricsCollector
+ // State
+ chainHealthcheck cache.ChainHealthcheck
+ // DB
+ priceService db.PriceService
+}
+
+// Query is not used by the CCIP Commit plugin.
+func (r *CommitReportingPlugin) Query(context.Context, types.ReportTimestamp) (types.Query, error) {
+ return types.Query{}, nil
+}
+
+// Observation calculates the sequence number interval ready to be committed and
+// the token and gas price updates required. A valid report could contain a merkle
+// root and price updates. Price updates should never contain nil values, otherwise
+// the observation will be considered invalid and rejected.
+func (r *CommitReportingPlugin) Observation(ctx context.Context, epochAndRound types.ReportTimestamp, _ types.Query) (types.Observation, error) {
+ lggr := r.lggr.Named("CommitObservation")
+ if healthy, err := r.chainHealthcheck.IsHealthy(ctx); err != nil {
+ return nil, err
+ } else if !healthy {
+ return nil, ccip.ErrChainIsNotHealthy
+ }
+
+ // Will return 0,0 if no messages are found. This is a valid case as the report could
+ // still contain fee updates.
+ minSeqNr, maxSeqNr, messageIDs, err := r.calculateMinMaxSequenceNumbers(ctx, lggr)
+ if err != nil {
+ return nil, err
+ }
+
+ // Fetches multi-lane gasPricesUSD and tokenPricesUSD for the same dest chain
+ gasPricesUSD, sourceGasPriceUSD, tokenPricesUSD, err := r.observePriceUpdates(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ lggr.Infow("Observation",
+ "minSeqNr", minSeqNr,
+ "maxSeqNr", maxSeqNr,
+ "gasPricesUSD", gasPricesUSD,
+ "tokenPricesUSD", tokenPricesUSD,
+ "epochAndRound", epochAndRound,
+ "messageIDs", messageIDs,
+ )
+ r.metricsCollector.NumberOfMessagesBasedOnInterval(ccip.Observation, minSeqNr, maxSeqNr)
+
+ // Even if all values are empty we still want to communicate our observation
+ // with the other nodes, therefore, we always return the observed values.
+ return ccip.CommitObservation{
+ Interval: cciptypes.CommitStoreInterval{
+ Min: minSeqNr,
+ Max: maxSeqNr,
+ },
+ TokenPricesUSD: tokenPricesUSD,
+ SourceGasPriceUSD: sourceGasPriceUSD,
+ SourceGasPriceUSDPerChain: gasPricesUSD,
+ }.Marshal()
+}
+
+// observePriceUpdates fetches latest gas and token prices from DB as long as price reporting is not disabled.
+// The prices are aggregated for all lanes for the same destination chain.
+func (r *CommitReportingPlugin) observePriceUpdates(
+ ctx context.Context,
+) (gasPricesUSD map[uint64]*big.Int, sourceGasPriceUSD *big.Int, tokenPricesUSD map[cciptypes.Address]*big.Int, err error) {
+ // Do not observe prices if price reporting is disabled. Price reporting will be disabled for lanes that are not leader lanes.
+ if r.offchainConfig.PriceReportingDisabled {
+ r.lggr.Infow("Price reporting disabled, skipping gas and token price reads")
+ return map[uint64]*big.Int{}, nil, map[cciptypes.Address]*big.Int{}, nil
+ }
+
+ // Fetches multi-lane gas prices and token prices, for the given dest chain
+ gasPricesUSD, tokenPricesUSD, err = r.priceService.GetGasAndTokenPrices(ctx, r.destChainSelector)
+ if err != nil {
+ return nil, nil, nil, fmt.Errorf("failed to get prices from PriceService: %w", err)
+ }
+
+ // Set prices to empty maps if nil to be friendlier to JSON encoding
+ if gasPricesUSD == nil {
+ gasPricesUSD = map[uint64]*big.Int{}
+ }
+ if tokenPricesUSD == nil {
+ tokenPricesUSD = map[cciptypes.Address]*big.Int{}
+ }
+
+ // For backwards compatibility with the older release during phased rollout, set the default gas price on this lane
+ sourceGasPriceUSD = gasPricesUSD[r.sourceChainSelector]
+
+ return gasPricesUSD, sourceGasPriceUSD, tokenPricesUSD, nil
+}
+
+func (r *CommitReportingPlugin) calculateMinMaxSequenceNumbers(ctx context.Context, lggr logger.Logger) (uint64, uint64, []cciptypes.Hash, error) {
+ nextSeqNum, err := r.commitStoreReader.GetExpectedNextSequenceNumber(ctx)
+ if err != nil {
+ return 0, 0, []cciptypes.Hash{}, err
+ }
+
+ msgRequests, err := r.onRampReader.GetSendRequestsBetweenSeqNums(ctx, nextSeqNum, nextSeqNum+OnRampMessagesScanLimit, true)
+ if err != nil {
+ return 0, 0, []cciptypes.Hash{}, err
+ }
+ if len(msgRequests) == 0 {
+ lggr.Infow("No new requests", "nextSeqNum", nextSeqNum)
+ return 0, 0, []cciptypes.Hash{}, nil
+ }
+
+ messageIDs := make([]cciptypes.Hash, 0, len(msgRequests))
+ seqNrs := make([]uint64, 0, len(msgRequests))
+ for _, msgReq := range msgRequests {
+ seqNrs = append(seqNrs, msgReq.SequenceNumber)
+ messageIDs = append(messageIDs, msgReq.MessageID)
+ }
+
+ minSeqNr := seqNrs[0]
+ maxSeqNr := seqNrs[len(seqNrs)-1]
+ if minSeqNr != nextSeqNum {
+ // Still report the observation as even partial reports have value e.g. all nodes are
+ // missing a single, different log each, they would still be able to produce a valid report.
+ lggr.Warnf("Missing sequence number range [%d-%d]", nextSeqNum, minSeqNr)
+ }
+ if !ccipcalc.ContiguousReqs(lggr, minSeqNr, maxSeqNr, seqNrs) {
+ return 0, 0, []cciptypes.Hash{}, errors.New("unexpected gap in seq nums")
+ }
+ return minSeqNr, maxSeqNr, messageIDs, nil
+}
+
+// Gets the latest token price updates based on logs within the heartbeat
+// The updates returned by this function are guaranteed to not contain nil values.
+func (r *CommitReportingPlugin) getLatestTokenPriceUpdates(ctx context.Context, now time.Time) (map[cciptypes.Address]update, error) {
+ tokenPriceUpdates, err := r.destPriceRegistryReader.GetTokenPriceUpdatesCreatedAfter(
+ ctx,
+ now.Add(-r.offchainConfig.TokenPriceHeartBeat),
+ 0,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ latestUpdates := make(map[cciptypes.Address]update)
+ for _, tokenUpdate := range tokenPriceUpdates {
+ priceUpdate := tokenUpdate.TokenPriceUpdate
+ // Ordered by ascending timestamps
+ timestamp := time.Unix(priceUpdate.TimestampUnixSec.Int64(), 0)
+ if priceUpdate.Value != nil && !timestamp.Before(latestUpdates[priceUpdate.Token].timestamp) {
+ latestUpdates[priceUpdate.Token] = update{
+ timestamp: timestamp,
+ value: priceUpdate.Value,
+ }
+ }
+ }
+
+ return latestUpdates, nil
+}
+
+// getLatestGasPriceUpdate returns the latest gas price updates based on logs within the heartbeat.
+// If an update is found, it is not expected to contain a nil value.
+func (r *CommitReportingPlugin) getLatestGasPriceUpdate(ctx context.Context, now time.Time) (map[uint64]update, error) {
+ gasPriceUpdates, err := r.destPriceRegistryReader.GetAllGasPriceUpdatesCreatedAfter(
+ ctx,
+ now.Add(-r.offchainConfig.GasPriceHeartBeat),
+ 0,
+ )
+
+ if err != nil {
+ return nil, err
+ }
+
+ latestUpdates := make(map[uint64]update)
+ for _, gasUpdate := range gasPriceUpdates {
+ priceUpdate := gasUpdate.GasPriceUpdate
+ // Ordered by ascending timestamps
+ timestamp := time.Unix(priceUpdate.TimestampUnixSec.Int64(), 0)
+ if priceUpdate.Value != nil && !timestamp.Before(latestUpdates[priceUpdate.DestChainSelector].timestamp) {
+ latestUpdates[priceUpdate.DestChainSelector] = update{
+ timestamp: timestamp,
+ value: priceUpdate.Value,
+ }
+ }
+ }
+
+ r.lggr.Infow("Latest gas price from log poller", "latestUpdates", latestUpdates)
+ return latestUpdates, nil
+}
+
+func (r *CommitReportingPlugin) Report(ctx context.Context, epochAndRound types.ReportTimestamp, _ types.Query, observations []types.AttributedObservation) (bool, types.Report, error) {
+ now := time.Now()
+ lggr := r.lggr.Named("CommitReport")
+ if healthy, err := r.chainHealthcheck.IsHealthy(ctx); err != nil {
+ return false, nil, err
+ } else if !healthy {
+ return false, nil, ccip.ErrChainIsNotHealthy
+ }
+
+ parsableObservations := ccip.GetParsableObservations[ccip.CommitObservation](lggr, observations)
+
+ intervals, gasPriceObs, tokenPriceObs, err := extractObservationData(lggr, r.F, r.sourceChainSelector, parsableObservations)
+ if err != nil {
+ return false, nil, err
+ }
+
+ agreedInterval, err := calculateIntervalConsensus(intervals, r.F, merklemulti.MaxNumberTreeLeaves)
+ if err != nil {
+ return false, nil, err
+ }
+
+ gasPrices, tokenPrices, err := r.selectPriceUpdates(ctx, now, gasPriceObs, tokenPriceObs)
+ if err != nil {
+ return false, nil, err
+ }
+ // If there are no fee updates and the interval is zero there is no report to produce.
+ if agreedInterval.Max == 0 && len(gasPrices) == 0 && len(tokenPrices) == 0 {
+ lggr.Infow("Empty report, skipping")
+ return false, nil, nil
+ }
+
+ report, err := r.buildReport(ctx, lggr, agreedInterval, gasPrices, tokenPrices)
+ if err != nil {
+ return false, nil, err
+ }
+ encodedReport, err := r.commitStoreReader.EncodeCommitReport(ctx, report)
+ if err != nil {
+ return false, nil, err
+ }
+ r.metricsCollector.SequenceNumber(ccip.Report, report.Interval.Max)
+ r.metricsCollector.NumberOfMessagesBasedOnInterval(ccip.Report, report.Interval.Min, report.Interval.Max)
+ lggr.Infow("Report",
+ "merkleRoot", hex.EncodeToString(report.MerkleRoot[:]),
+ "minSeqNr", report.Interval.Min,
+ "maxSeqNr", report.Interval.Max,
+ "gasPriceUpdates", report.GasPrices,
+ "tokenPriceUpdates", report.TokenPrices,
+ "epochAndRound", epochAndRound,
+ )
+ return true, encodedReport, nil
+}
+
+// calculateIntervalConsensus compresses a set of intervals into one interval
+// taking into account f which is the maximum number of faults across the whole DON.
+// OCR itself won't call Report unless there are 2*f+1 observations
+// https://github.com/smartcontractkit/libocr/blob/master/offchainreporting2/internal/protocol/report_generation_follower.go#L415
+// and f of those observations may be either unparseable or adversarially set values. That means
+// we'll either have f+1 parsed honest values here, 2f+1 parsed values with f adversarial values or somewhere
+// in between.
+// rangeLimit is the maximum range of the interval. If the interval is larger than this, it will be truncated. Zero means no limit.
+func calculateIntervalConsensus(intervals []cciptypes.CommitStoreInterval, f int, rangeLimit uint64) (cciptypes.CommitStoreInterval, error) {
+ // To understand min/max selection here, we need to consider an adversary that controls f values
+ // and is intentionally trying to stall the protocol or influence the value returned. For simplicity
+ // consider f=1 and n=4 nodes. In that case adversary may try to bias the min or max high/low.
+ // We could end up (2f+1=3) with sorted_mins=[1,1,1e9] or [-1e9,1,1] as examples. Selecting
+ // sorted_mins[f] ensures:
+ // - At least one honest node has seen this value, so adversary cannot bias the value lower which
+ // would cause reverts
+ // - If an honest oracle reports sorted_min[f] which happens to be stale i.e. that oracle
+ // has a delayed view of the chain, then the report will revert onchain but still succeed upon retry
+ // - We minimize the risk of naturally hitting the error condition minSeqNum > maxSeqNum due to oracles
+ // delayed views of the chain (would be an issue with taking sorted_mins[-f])
+ sort.Slice(intervals, func(i, j int) bool {
+ return intervals[i].Min < intervals[j].Min
+ })
+ minSeqNum := intervals[f].Min
+
+ // The only way a report could have a minSeqNum of 0 is when there are no messages to report
+ // and the report is potentially still valid for gas fee updates.
+ if minSeqNum == 0 {
+ return cciptypes.CommitStoreInterval{Min: 0, Max: 0}, nil
+ }
+ // Consider a similar example to the sorted_mins one above except where they are maxes.
+ // We choose the more "conservative" sorted_maxes[f] so:
+ // - We are ensured that at least one honest oracle has seen the max, so adversary cannot set it lower and
+ // cause the maxSeqNum < minSeqNum errors
+ // - If an honest oracle reports sorted_max[f] which happens to be stale i.e. that oracle
+ // has a delayed view of the source chain, then we simply lose a little bit of throughput.
+ // - If we were to pick sorted_max[-f] i.e. the maximum honest node view (a more "aggressive" setting in terms of throughput),
+ // then an adversary can continually send high values e.g. imagine we have observations from all 4 nodes
+ // [honest 1, honest 1, honest 2, malicious 2], in this case we pick 2, but it's not enough to be able
+ // to build a report since the first 2 honest nodes are unaware of message 2.
+ sort.Slice(intervals, func(i, j int) bool {
+ return intervals[i].Max < intervals[j].Max
+ })
+ maxSeqNum := intervals[f].Max
+ if maxSeqNum < minSeqNum {
+ // If the consensus report is invalid for onchain acceptance, we do not vote for it as
+ // an early termination step.
+ return cciptypes.CommitStoreInterval{}, errors.New("max seq num smaller than min")
+ }
+
+ // If the range is too large, truncate it.
+ if rangeLimit > 0 && maxSeqNum-minSeqNum+1 > rangeLimit {
+ maxSeqNum = minSeqNum + rangeLimit - 1
+ }
+
+ return cciptypes.CommitStoreInterval{
+ Min: minSeqNum,
+ Max: maxSeqNum,
+ }, nil
+}
+
+// extractObservationData extracts observation fields into their own slices
+// and filters out observation data that are invalid
+func extractObservationData(lggr logger.Logger, f int, sourceChainSelector uint64, observations []ccip.CommitObservation) (intervals []cciptypes.CommitStoreInterval, gasPrices map[uint64][]*big.Int, tokenPrices map[cciptypes.Address][]*big.Int, err error) {
+ // We require at least f+1 observations to reach consensus. Checking to ensure there are at least f+1 parsed observations.
+ if len(observations) <= f {
+ return nil, nil, nil, fmt.Errorf("not enough observations to form consensus: #obs=%d, f=%d", len(observations), f)
+ }
+
+ gasPriceObservations := make(map[uint64][]*big.Int)
+ tokenPriceObservations := make(map[cciptypes.Address][]*big.Int)
+ for _, obs := range observations {
+ intervals = append(intervals, obs.Interval)
+
+ for selector, price := range obs.SourceGasPriceUSDPerChain {
+ if price != nil {
+ gasPriceObservations[selector] = append(gasPriceObservations[selector], price)
+ }
+ }
+ // During phased rollout, NOPs running old release only report SourceGasPriceUSD.
+ // An empty `SourceGasPriceUSDPerChain` with a non-nil `SourceGasPriceUSD` can only happen with old release.
+ if len(obs.SourceGasPriceUSDPerChain) == 0 && obs.SourceGasPriceUSD != nil {
+ gasPriceObservations[sourceChainSelector] = append(gasPriceObservations[sourceChainSelector], obs.SourceGasPriceUSD)
+ }
+
+ for token, price := range obs.TokenPricesUSD {
+ if price != nil {
+ tokenPriceObservations[token] = append(tokenPriceObservations[token], price)
+ }
+ }
+ }
+
+ // Price is dropped if there are not enough valid observations. With a threshold of 2*(f-1) + 1, we achieve a balance between safety and liveness.
+ // During phased-rollout where some honest nodes may not have started observing the token yet, it requires 5 malicious node with 1 being the leader to successfully alter price.
+ // During regular operation, it requires 3 malicious nodes with 1 being the leader to temporarily delay price update for the token.
+ priceReportingThreshold := 2*(f-1) + 1
+
+ gasPrices = make(map[uint64][]*big.Int)
+ for selector, perChainPriceObservations := range gasPriceObservations {
+ if len(perChainPriceObservations) < priceReportingThreshold {
+ lggr.Warnf("Skipping chain with selector %d due to not enough valid observations: #obs=%d, f=%d, threshold=%d", selector, len(perChainPriceObservations), f, priceReportingThreshold)
+ continue
+ }
+ gasPrices[selector] = perChainPriceObservations
+ }
+
+ tokenPrices = make(map[cciptypes.Address][]*big.Int)
+ for token, perTokenPriceObservations := range tokenPriceObservations {
+ if len(perTokenPriceObservations) < priceReportingThreshold {
+ lggr.Warnf("Skipping token %s due to not enough valid observations: #obs=%d, f=%d, threshold=%d", string(token), len(perTokenPriceObservations), f, priceReportingThreshold)
+ continue
+ }
+ tokenPrices[token] = perTokenPriceObservations
+ }
+
+ return intervals, gasPrices, tokenPrices, nil
+}
+
+// selectPriceUpdates filters out gas and token price updates that are already inflight
+func (r *CommitReportingPlugin) selectPriceUpdates(ctx context.Context, now time.Time, gasPriceObs map[uint64][]*big.Int, tokenPriceObs map[cciptypes.Address][]*big.Int) ([]cciptypes.GasPrice, []cciptypes.TokenPrice, error) {
+ // If price reporting is disabled, there is no need to select price updates.
+ if r.offchainConfig.PriceReportingDisabled {
+ return nil, nil, nil
+ }
+
+ latestGasPrice, err := r.getLatestGasPriceUpdate(ctx, now)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ latestTokenPrices, err := r.getLatestTokenPriceUpdates(ctx, now)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return r.calculatePriceUpdates(gasPriceObs, tokenPriceObs, latestGasPrice, latestTokenPrices)
+}
+
+// Note priceUpdates must be deterministic.
+// The provided gasPriceObs and tokenPriceObs should not contain nil values.
+// The returned latestGasPrice and latestTokenPrices should not contain nil values.
+func (r *CommitReportingPlugin) calculatePriceUpdates(gasPriceObs map[uint64][]*big.Int, tokenPriceObs map[cciptypes.Address][]*big.Int, latestGasPrice map[uint64]update, latestTokenPrices map[cciptypes.Address]update) ([]cciptypes.GasPrice, []cciptypes.TokenPrice, error) {
+ var tokenPriceUpdates []cciptypes.TokenPrice
+ for token, tokenPriceObservations := range tokenPriceObs {
+ medianPrice := ccipcalc.BigIntSortedMiddle(tokenPriceObservations)
+
+ latestTokenPrice, exists := latestTokenPrices[token]
+ if exists {
+ tokenPriceUpdatedRecently := time.Since(latestTokenPrice.timestamp) < r.offchainConfig.TokenPriceHeartBeat
+ tokenPriceNotChanged := !ccipcalc.Deviates(medianPrice, latestTokenPrice.value, int64(r.offchainConfig.TokenPriceDeviationPPB))
+ if tokenPriceUpdatedRecently && tokenPriceNotChanged {
+ r.lggr.Debugw("token price was updated recently, skipping the update",
+ "token", token, "newPrice", medianPrice, "existingPrice", latestTokenPrice.value)
+ continue // skip the update if we recently had a price update close to the new value
+ }
+ }
+
+ tokenPriceUpdates = append(tokenPriceUpdates, cciptypes.TokenPrice{
+ Token: token,
+ Value: medianPrice,
+ })
+ }
+
+ // Determinism required.
+ sort.Slice(tokenPriceUpdates, func(i, j int) bool {
+ return tokenPriceUpdates[i].Token < tokenPriceUpdates[j].Token
+ })
+
+ var gasPriceUpdate []cciptypes.GasPrice
+ for chainSelector, gasPriceObservations := range gasPriceObs {
+ newGasPrice, err := r.gasPriceEstimator.Median(gasPriceObservations) // Compute the median price
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to calculate median gas price for chain selector %d: %w", chainSelector, err)
+ }
+
+ // Default to updating so that we update if there are no prior updates.
+ latestGasPrice, exists := latestGasPrice[chainSelector]
+ if exists && latestGasPrice.value != nil {
+ gasPriceUpdatedRecently := time.Since(latestGasPrice.timestamp) < r.offchainConfig.GasPriceHeartBeat
+ gasPriceDeviated, err := r.gasPriceEstimator.Deviates(newGasPrice, latestGasPrice.value)
+ if err != nil {
+ return nil, nil, err
+ }
+ if gasPriceUpdatedRecently && !gasPriceDeviated {
+ r.lggr.Debugw("gas price was updated recently and not deviated sufficiently, skipping the update",
+ "chainSelector", chainSelector, "newPrice", newGasPrice, "existingPrice", latestGasPrice.value)
+ continue
+ }
+ }
+
+ gasPriceUpdate = append(gasPriceUpdate, cciptypes.GasPrice{
+ DestChainSelector: chainSelector,
+ Value: newGasPrice,
+ })
+ }
+
+ sort.Slice(gasPriceUpdate, func(i, j int) bool {
+ return gasPriceUpdate[i].DestChainSelector < gasPriceUpdate[j].DestChainSelector
+ })
+
+ return gasPriceUpdate, tokenPriceUpdates, nil
+}
+
+// buildReport assumes there is at least one message in reqs.
+func (r *CommitReportingPlugin) buildReport(ctx context.Context, lggr logger.Logger, interval cciptypes.CommitStoreInterval, gasPrices []cciptypes.GasPrice, tokenPrices []cciptypes.TokenPrice) (cciptypes.CommitStoreReport, error) {
+ // If no messages are needed only include fee updates
+ if interval.Min == 0 {
+ return cciptypes.CommitStoreReport{
+ TokenPrices: tokenPrices,
+ GasPrices: gasPrices,
+ MerkleRoot: [32]byte{},
+ Interval: interval,
+ }, nil
+ }
+
+ // Logs are guaranteed to be in order of seq num, since these are finalized logs only
+ // and the contract's seq num is auto-incrementing.
+ sendRequests, err := r.onRampReader.GetSendRequestsBetweenSeqNums(ctx, interval.Min, interval.Max, true)
+ if err != nil {
+ return cciptypes.CommitStoreReport{}, err
+ }
+ if len(sendRequests) == 0 {
+ lggr.Warn("No messages found in interval",
+ "minSeqNr", interval.Min,
+ "maxSeqNr", interval.Max)
+ return cciptypes.CommitStoreReport{}, fmt.Errorf("tried building a tree without leaves")
+ }
+
+ leaves := make([][32]byte, 0, len(sendRequests))
+ var seqNrs []uint64
+ for _, req := range sendRequests {
+ leaves = append(leaves, req.Hash)
+ seqNrs = append(seqNrs, req.SequenceNumber)
+ }
+ if !ccipcalc.ContiguousReqs(lggr, interval.Min, interval.Max, seqNrs) {
+ return cciptypes.CommitStoreReport{}, errors.Errorf("do not have full range [%v, %v] have %v", interval.Min, interval.Max, seqNrs)
+ }
+ tree, err := merklemulti.NewTree(hashutil.NewKeccak(), leaves)
+ if err != nil {
+ return cciptypes.CommitStoreReport{}, err
+ }
+
+ return cciptypes.CommitStoreReport{
+ GasPrices: gasPrices,
+ TokenPrices: tokenPrices,
+ MerkleRoot: tree.Root(),
+ Interval: interval,
+ }, nil
+}
+
+func (r *CommitReportingPlugin) ShouldAcceptFinalizedReport(ctx context.Context, reportTimestamp types.ReportTimestamp, report types.Report) (bool, error) {
+ parsedReport, err := r.commitStoreReader.DecodeCommitReport(ctx, report)
+ if err != nil {
+ return false, err
+ }
+ lggr := r.lggr.Named("CommitShouldAcceptFinalizedReport").With(
+ "merkleRoot", parsedReport.MerkleRoot,
+ "minSeqNum", parsedReport.Interval.Min,
+ "maxSeqNum", parsedReport.Interval.Max,
+ "gasPriceUpdates", parsedReport.GasPrices,
+ "tokenPriceUpdates", parsedReport.TokenPrices,
+ "reportTimestamp", reportTimestamp,
+ )
+ // Empty report, should not be put on chain
+ if parsedReport.MerkleRoot == [32]byte{} && len(parsedReport.GasPrices) == 0 && len(parsedReport.TokenPrices) == 0 {
+ lggr.Warn("Empty report, should not be put on chain")
+ return false, nil
+ }
+
+ if healthy, err1 := r.chainHealthcheck.IsHealthy(ctx); err1 != nil {
+ return false, err1
+ } else if !healthy {
+ return false, ccip.ErrChainIsNotHealthy
+ }
+
+ if r.isStaleReport(ctx, lggr, parsedReport, reportTimestamp) {
+ lggr.Infow("Rejecting stale report")
+ return false, nil
+ }
+
+ r.metricsCollector.SequenceNumber(ccip.ShouldAccept, parsedReport.Interval.Max)
+ lggr.Infow("Accepting finalized report", "merkleRoot", hexutil.Encode(parsedReport.MerkleRoot[:]))
+ return true, nil
+}
+
+// ShouldTransmitAcceptedReport checks if the report is stale, if it is it should not be transmitted.
+func (r *CommitReportingPlugin) ShouldTransmitAcceptedReport(ctx context.Context, reportTimestamp types.ReportTimestamp, report types.Report) (bool, error) {
+ lggr := r.lggr.Named("CommitShouldTransmitAcceptedReport")
+ parsedReport, err := r.commitStoreReader.DecodeCommitReport(ctx, report)
+ if err != nil {
+ return false, err
+ }
+ if healthy, err1 := r.chainHealthcheck.IsHealthy(ctx); err1 != nil {
+ return false, err1
+ } else if !healthy {
+ return false, ccip.ErrChainIsNotHealthy
+ }
+ // If report is not stale we transmit.
+ // When the commitTransmitter enqueues the tx for tx manager,
+ // we mark it as fulfilled, effectively removing it from the set of inflight messages.
+ shouldTransmit := !r.isStaleReport(ctx, lggr, parsedReport, reportTimestamp)
+
+ lggr.Infow("ShouldTransmitAcceptedReport",
+ "shouldTransmit", shouldTransmit,
+ "reportTimestamp", reportTimestamp)
+ return shouldTransmit, nil
+}
+
+// isStaleReport checks a report to see if the contents have become stale.
+// It does so in four ways:
+// 1. if there is a merkle root, check if the sequence numbers match up with onchain data
+// 2. if there is no merkle root, check if current price's epoch and round is after onchain epoch and round
+// 3. if there is a gas price update check to see if the value is different from the last
+// reported value
+// 4. if there are token prices check to see if the values are different from the last
+// reported values.
+//
+// If there is a merkle root present, staleness is only measured based on the merkle root
+// If there is no merkle root but there is a gas update, only this gas update is used for staleness checks.
+// If only price updates are included, the price updates are used to check for staleness
+// If nothing is included the report is always considered stale.
+func (r *CommitReportingPlugin) isStaleReport(ctx context.Context, lggr logger.Logger, report cciptypes.CommitStoreReport, reportTimestamp types.ReportTimestamp) bool {
+ // If there is a merkle root, ignore all other staleness checks and only check for sequence number staleness
+ if report.MerkleRoot != [32]byte{} {
+ return r.isStaleMerkleRoot(ctx, lggr, report.Interval)
+ }
+
+ hasGasPriceUpdate := len(report.GasPrices) > 0
+ hasTokenPriceUpdates := len(report.TokenPrices) > 0
+
+ // If there is no merkle root, no gas price update and no token price update
+ // we don't want to write anything on-chain, so we consider this report stale.
+ if !hasGasPriceUpdate && !hasTokenPriceUpdates {
+ return true
+ }
+
+ // We consider a price update as stale when, there isn't an update or there is an update that is stale.
+ gasPriceStale := !hasGasPriceUpdate || r.isStaleGasPrice(ctx, lggr, report.GasPrices)
+ tokenPricesStale := !hasTokenPriceUpdates || r.isStaleTokenPrices(ctx, lggr, report.TokenPrices)
+
+ if gasPriceStale && tokenPricesStale {
+ return true
+ }
+
+ // If report only has price update, check if its epoch and round lags behind the latest onchain
+ lastPriceEpochAndRound, err := r.commitStoreReader.GetLatestPriceEpochAndRound(ctx)
+ if err != nil {
+ // Assume it's a transient issue getting the last report and try again on the next round
+ return true
+ }
+
+ thisEpochAndRound := ccipcalc.MergeEpochAndRound(reportTimestamp.Epoch, reportTimestamp.Round)
+ return lastPriceEpochAndRound >= thisEpochAndRound
+}
+
+func (r *CommitReportingPlugin) isStaleMerkleRoot(ctx context.Context, lggr logger.Logger, reportInterval cciptypes.CommitStoreInterval) bool {
+ nextSeqNum, err := r.commitStoreReader.GetExpectedNextSequenceNumber(ctx)
+ if err != nil {
+ // Assume it's a transient issue getting the last report and try again on the next round
+ return true
+ }
+
+ // The report is not stale and correct only if nextSeqNum == reportInterval.Min.
+ // Mark it stale if the condition isn't met.
+ if nextSeqNum != reportInterval.Min {
+ lggr.Infow("The report is stale because of sequence number mismatch with the commit store interval min value",
+ "nextSeqNum", nextSeqNum, "reportIntervalMin", reportInterval.Min)
+ return true
+ }
+
+ lggr.Infow("Report root is not stale", "nextSeqNum", nextSeqNum, "reportIntervalMin", reportInterval.Min)
+
+ // If a report has root and valid sequence number, the report should be submitted, regardless of price staleness
+ return false
+}
+
+func (r *CommitReportingPlugin) isStaleGasPrice(ctx context.Context, lggr logger.Logger, gasPriceUpdates []cciptypes.GasPrice) bool {
+ latestGasPrice, err := r.getLatestGasPriceUpdate(ctx, time.Now())
+ if err != nil {
+ lggr.Errorw("Gas price is stale because getLatestGasPriceUpdate failed", "err", err)
+ return true
+ }
+
+ for _, gasPriceUpdate := range gasPriceUpdates {
+ latestUpdate, exists := latestGasPrice[gasPriceUpdate.DestChainSelector]
+ if !exists || latestUpdate.value == nil {
+ lggr.Infow("Found non-stale gas price", "chainSelector", gasPriceUpdate.DestChainSelector, "gasPriceUSd", gasPriceUpdate.Value)
+ return false
+ }
+
+ gasPriceDeviated, err := r.gasPriceEstimator.Deviates(gasPriceUpdate.Value, latestUpdate.value)
+ if err != nil {
+ lggr.Errorw("Gas price is stale because deviation check failed", "err", err)
+ return true
+ }
+
+ if gasPriceDeviated {
+ lggr.Infow("Found non-stale gas price", "chainSelector", gasPriceUpdate.DestChainSelector, "gasPriceUSd", gasPriceUpdate.Value, "latestUpdate", latestUpdate.value)
+ return false
+ }
+ lggr.Infow("Gas price is stale", "chainSelector", gasPriceUpdate.DestChainSelector, "gasPriceUSd", gasPriceUpdate.Value, "latestGasPrice", latestUpdate.value)
+ }
+
+ lggr.Infow("All gas prices are stale")
+ return true
+}
+
+func (r *CommitReportingPlugin) isStaleTokenPrices(ctx context.Context, lggr logger.Logger, priceUpdates []cciptypes.TokenPrice) bool {
+ // getting the last price updates without including inflight is like querying
+ // current prices onchain, but uses logpoller's data to save on the RPC requests
+ latestTokenPriceUpdates, err := r.getLatestTokenPriceUpdates(ctx, time.Now())
+ if err != nil {
+ return true
+ }
+
+ for _, tokenUpdate := range priceUpdates {
+ latestUpdate, ok := latestTokenPriceUpdates[tokenUpdate.Token]
+ priceEqual := ok && !ccipcalc.Deviates(tokenUpdate.Value, latestUpdate.value, int64(r.offchainConfig.TokenPriceDeviationPPB))
+
+ if !priceEqual {
+ lggr.Infow("Found non-stale token price", "token", tokenUpdate.Token, "usdPerToken", tokenUpdate.Value, "latestUpdate", latestUpdate.value)
+ return false
+ }
+ lggr.Infow("Token price is stale", "latestTokenPrice", latestUpdate.value, "usdPerToken", tokenUpdate.Value, "token", tokenUpdate.Token)
+ }
+
+ lggr.Infow("All token prices are stale")
+ return true
+}
+
+func (r *CommitReportingPlugin) Close() error {
+ return nil
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipcommit/ocr2_test.go b/core/services/ocr2/plugins/ccip/ccipcommit/ocr2_test.go
new file mode 100644
index 00000000000..6cf7e4bec72
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipcommit/ocr2_test.go
@@ -0,0 +1,1861 @@
+package ccipcommit
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "math/rand"
+ "slices"
+ "sort"
+ "testing"
+ "time"
+
+ "github.com/Masterminds/semver/v3"
+ "github.com/leanovate/gopter"
+ "github.com/leanovate/gopter/gen"
+ "github.com/leanovate/gopter/prop"
+ "github.com/pkg/errors"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/merklemulti"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks"
+ mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ ccipcachemocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+ ccipdatamocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+
+ ccipdbmocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdb/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+func TestCommitReportingPlugin_Observation(t *testing.T) {
+ sourceNativeTokenAddr := ccipcalc.HexToAddress("1000")
+ destChainSelector := uint64(1)
+ sourceChainSelector := uint64(2)
+
+ bridgedTokens := []cciptypes.Address{
+ ccipcalc.HexToAddress("2000"),
+ ccipcalc.HexToAddress("3000"),
+ }
+
+ // Token price of 1e18 token amount in 1e18 USD precision
+ expectedTokenPrice := map[cciptypes.Address]*big.Int{
+ bridgedTokens[0]: big.NewInt(1e10),
+ bridgedTokens[1]: big.NewInt(2e18),
+ }
+
+ testCases := []struct {
+ name string
+ epochAndRound types.ReportTimestamp
+ commitStorePaused bool
+ sourceChainCursed bool
+ commitStoreSeqNum uint64
+ gasPrices map[uint64]*big.Int
+ tokenPrices map[cciptypes.Address]*big.Int
+ sendReqs []cciptypes.EVM2EVMMessageWithTxMeta
+ priceReportingDisabled bool
+
+ expErr bool
+ expObs ccip.CommitObservation
+ }{
+ {
+ name: "base report",
+ commitStoreSeqNum: 54,
+ gasPrices: map[uint64]*big.Int{
+ sourceChainSelector: big.NewInt(2e18),
+ },
+ tokenPrices: expectedTokenPrice,
+ sendReqs: []cciptypes.EVM2EVMMessageWithTxMeta{
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 54}},
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 55}},
+ },
+ expObs: ccip.CommitObservation{
+ TokenPricesUSD: expectedTokenPrice,
+ SourceGasPriceUSD: big.NewInt(2e18),
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector: big.NewInt(2e18),
+ },
+ Interval: cciptypes.CommitStoreInterval{
+ Min: 54,
+ Max: 55,
+ },
+ },
+ },
+ {
+ name: "base report with multi-chain gas prices",
+ commitStoreSeqNum: 54,
+ gasPrices: map[uint64]*big.Int{
+ sourceChainSelector + 1: big.NewInt(2e18),
+ sourceChainSelector + 2: big.NewInt(3e18),
+ },
+ tokenPrices: expectedTokenPrice,
+ sendReqs: []cciptypes.EVM2EVMMessageWithTxMeta{
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 54}},
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 55}},
+ },
+ expObs: ccip.CommitObservation{
+ TokenPricesUSD: expectedTokenPrice,
+ SourceGasPriceUSD: nil,
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector + 1: big.NewInt(2e18),
+ sourceChainSelector + 2: big.NewInt(3e18),
+ },
+ Interval: cciptypes.CommitStoreInterval{
+ Min: 54,
+ Max: 55,
+ },
+ },
+ },
+ {
+ name: "base report with price reporting disabled",
+ commitStoreSeqNum: 54,
+ gasPrices: map[uint64]*big.Int{
+ sourceChainSelector: big.NewInt(2e18),
+ },
+ tokenPrices: expectedTokenPrice,
+ sendReqs: []cciptypes.EVM2EVMMessageWithTxMeta{
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 54}},
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 55}},
+ },
+ priceReportingDisabled: true,
+ expObs: ccip.CommitObservation{
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{},
+ SourceGasPriceUSD: nil,
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{},
+ Interval: cciptypes.CommitStoreInterval{
+ Min: 54,
+ Max: 55,
+ },
+ },
+ },
+ {
+ name: "commit store is down",
+ commitStorePaused: true,
+ sourceChainCursed: false,
+ expErr: true,
+ },
+ {
+ name: "source chain is cursed",
+ commitStorePaused: false,
+ sourceChainCursed: true,
+ expErr: true,
+ },
+ }
+
+ ctx := testutils.Context(t)
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ commitStoreReader.On("IsDown", ctx).Return(tc.commitStorePaused, nil)
+ commitStoreReader.On("IsDestChainHealthy", ctx).Return(true, nil)
+ if !tc.commitStorePaused && !tc.sourceChainCursed {
+ commitStoreReader.On("GetExpectedNextSequenceNumber", ctx).Return(tc.commitStoreSeqNum, nil)
+ }
+
+ onRampReader := ccipdatamocks.NewOnRampReader(t)
+ onRampReader.On("IsSourceChainHealthy", ctx).Return(true, nil)
+ onRampReader.On("IsSourceCursed", ctx).Return(tc.sourceChainCursed, nil)
+ if len(tc.sendReqs) > 0 {
+ onRampReader.On("GetSendRequestsBetweenSeqNums", ctx, tc.commitStoreSeqNum, tc.commitStoreSeqNum+OnRampMessagesScanLimit, true).
+ Return(tc.sendReqs, nil)
+ }
+
+ mockPriceService := ccipdbmocks.NewPriceService(t)
+ mockPriceService.On("GetGasAndTokenPrices", ctx, destChainSelector).Return(
+ tc.gasPrices,
+ tc.tokenPrices,
+ nil,
+ ).Maybe()
+
+ p := &CommitReportingPlugin{}
+ p.lggr = logger.TestLogger(t)
+ p.commitStoreReader = commitStoreReader
+ p.onRampReader = onRampReader
+ p.sourceNative = sourceNativeTokenAddr
+ p.metricsCollector = ccip.NoopMetricsCollector
+ p.chainHealthcheck = cache.NewChainHealthcheck(p.lggr, onRampReader, commitStoreReader)
+ p.priceService = mockPriceService
+ p.destChainSelector = destChainSelector
+ p.sourceChainSelector = sourceChainSelector
+ p.offchainConfig = cciptypes.CommitOffchainConfig{
+ PriceReportingDisabled: tc.priceReportingDisabled,
+ }
+
+ obs, err := p.Observation(ctx, tc.epochAndRound, types.Query{})
+
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+
+ if tc.expObs.TokenPricesUSD != nil {
+ // field ordering in mapping is not guaranteed, if TokenPricesUSD exists, unmarshal to compare mapping
+ var obsStuct ccip.CommitObservation
+ err = json.Unmarshal(obs, &obsStuct)
+ assert.NoError(t, err)
+
+ assert.Equal(t, tc.expObs, obsStuct)
+ } else {
+ // if TokenPricesUSD is nil, compare the bytes directly, marshal then unmarshal turns nil map to empty
+ expObsBytes, err := tc.expObs.Marshal()
+ assert.NoError(t, err)
+ assert.Equal(t, expObsBytes, []byte(obs))
+ }
+ })
+ }
+}
+
+func TestCommitReportingPlugin_Report(t *testing.T) {
+ ctx := testutils.Context(t)
+ sourceChainSelector := uint64(rand.Int())
+ var gasPrice = big.NewInt(1)
+ var gasPrice2 = big.NewInt(2)
+ gasPriceHeartBeat := *config.MustNewDuration(time.Hour)
+
+ t.Run("not enough observations", func(t *testing.T) {
+ p := &CommitReportingPlugin{}
+ p.lggr = logger.TestLogger(t)
+ p.F = 1
+
+ chainHealthcheck := ccipcachemocks.NewChainHealthcheck(t)
+ chainHealthcheck.On("IsHealthy", ctx).Return(true, nil).Maybe()
+ p.chainHealthcheck = chainHealthcheck
+
+ o := ccip.CommitObservation{Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1}, SourceGasPriceUSD: big.NewInt(0)}
+ obs, err := o.Marshal()
+ assert.NoError(t, err)
+
+ aos := []types.AttributedObservation{{Observation: obs}}
+
+ gotSomeReport, gotReport, err := p.Report(ctx, types.ReportTimestamp{}, types.Query{}, aos)
+ assert.False(t, gotSomeReport)
+ assert.Nil(t, gotReport)
+ assert.Error(t, err)
+ })
+
+ testCases := []struct {
+ name string
+ observations []ccip.CommitObservation
+ f int
+ gasPriceUpdates []cciptypes.GasPriceUpdateWithTxMeta
+ tokenDecimals map[cciptypes.Address]uint8
+ tokenPriceUpdates []cciptypes.TokenPriceUpdateWithTxMeta
+ sendRequests []cciptypes.EVM2EVMMessageWithTxMeta
+ expCommitReport *cciptypes.CommitStoreReport
+ expSeqNumRange cciptypes.CommitStoreInterval
+ expErr bool
+ }{
+ {
+ name: "base",
+ observations: []ccip.CommitObservation{
+ {Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1}, SourceGasPriceUSDPerChain: map[uint64]*big.Int{sourceChainSelector: gasPrice}},
+ {Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1}, SourceGasPriceUSDPerChain: map[uint64]*big.Int{sourceChainSelector: gasPrice}},
+ },
+ f: 1,
+ sendRequests: []cciptypes.EVM2EVMMessageWithTxMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 1,
+ },
+ },
+ },
+ gasPriceUpdates: []cciptypes.GasPriceUpdateWithTxMeta{
+ {
+ GasPriceUpdate: cciptypes.GasPriceUpdate{
+ GasPrice: cciptypes.GasPrice{
+ DestChainSelector: sourceChainSelector,
+ Value: big.NewInt(1),
+ },
+ TimestampUnixSec: big.NewInt(time.Now().Add(-2 * gasPriceHeartBeat.Duration()).Unix()),
+ },
+ },
+ },
+ expSeqNumRange: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ expCommitReport: &cciptypes.CommitStoreReport{
+ MerkleRoot: [32]byte{},
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ TokenPrices: nil,
+ GasPrices: []cciptypes.GasPrice{{DestChainSelector: sourceChainSelector, Value: gasPrice}},
+ },
+ expErr: false,
+ },
+ {
+ name: "observations with mix gas price formats",
+ observations: []ccip.CommitObservation{
+ {
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector: gasPrice,
+ sourceChainSelector + 1: gasPrice2,
+ sourceChainSelector + 2: gasPrice2,
+ },
+ },
+ {
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector: gasPrice,
+ sourceChainSelector + 1: gasPrice2,
+ sourceChainSelector + 2: gasPrice2,
+ },
+ },
+ {
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector: gasPrice,
+ sourceChainSelector + 1: gasPrice2,
+ },
+ },
+ {
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ SourceGasPriceUSD: gasPrice,
+ },
+ },
+ f: 2,
+ sendRequests: []cciptypes.EVM2EVMMessageWithTxMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 1,
+ },
+ },
+ },
+ gasPriceUpdates: []cciptypes.GasPriceUpdateWithTxMeta{
+ {
+ GasPriceUpdate: cciptypes.GasPriceUpdate{
+ GasPrice: cciptypes.GasPrice{
+ DestChainSelector: sourceChainSelector,
+ Value: big.NewInt(1),
+ },
+ TimestampUnixSec: big.NewInt(time.Now().Add(-2 * gasPriceHeartBeat.Duration()).Unix()),
+ },
+ },
+ },
+ expSeqNumRange: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ expCommitReport: &cciptypes.CommitStoreReport{
+ MerkleRoot: [32]byte{},
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ TokenPrices: nil,
+ GasPrices: []cciptypes.GasPrice{
+ {DestChainSelector: sourceChainSelector, Value: gasPrice},
+ {DestChainSelector: sourceChainSelector + 1, Value: gasPrice2},
+ },
+ },
+ expErr: false,
+ },
+ {
+ name: "empty",
+ observations: []ccip.CommitObservation{
+ {Interval: cciptypes.CommitStoreInterval{Min: 0, Max: 0}, SourceGasPriceUSD: big.NewInt(0)},
+ {Interval: cciptypes.CommitStoreInterval{Min: 0, Max: 0}, SourceGasPriceUSD: big.NewInt(0)},
+ },
+ gasPriceUpdates: []cciptypes.GasPriceUpdateWithTxMeta{
+ {
+ GasPriceUpdate: cciptypes.GasPriceUpdate{
+ GasPrice: cciptypes.GasPrice{
+ DestChainSelector: sourceChainSelector,
+ Value: big.NewInt(0),
+ },
+ TimestampUnixSec: big.NewInt(time.Now().Add(-gasPriceHeartBeat.Duration() / 2).Unix()),
+ },
+ },
+ },
+ f: 1,
+ expErr: false,
+ },
+ {
+ name: "no leaves",
+ observations: []ccip.CommitObservation{
+ {Interval: cciptypes.CommitStoreInterval{Min: 2, Max: 2}, SourceGasPriceUSD: big.NewInt(0)},
+ {Interval: cciptypes.CommitStoreInterval{Min: 2, Max: 2}, SourceGasPriceUSD: big.NewInt(0)},
+ },
+ f: 1,
+ sendRequests: []cciptypes.EVM2EVMMessageWithTxMeta{{}},
+ expSeqNumRange: cciptypes.CommitStoreInterval{Min: 2, Max: 2},
+ expErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ destPriceRegistryReader := ccipdatamocks.NewPriceRegistryReader(t)
+ destPriceRegistryReader.On("GetAllGasPriceUpdatesCreatedAfter", ctx, mock.Anything, 0).Return(tc.gasPriceUpdates, nil)
+ destPriceRegistryReader.On("GetTokenPriceUpdatesCreatedAfter", ctx, mock.Anything, 0).Return(tc.tokenPriceUpdates, nil)
+
+ onRampReader := ccipdatamocks.NewOnRampReader(t)
+ if len(tc.sendRequests) > 0 {
+ onRampReader.On("GetSendRequestsBetweenSeqNums", ctx, tc.expSeqNumRange.Min, tc.expSeqNumRange.Max, true).Return(tc.sendRequests, nil)
+ }
+
+ evmEstimator := mocks.NewEvmFeeEstimator(t)
+ evmEstimator.On("L1Oracle").Return(nil)
+ gasPriceEstimator := prices.NewDAGasPriceEstimator(evmEstimator, nil, 2e9, 2e9) // 200% deviation
+
+ var destTokens []cciptypes.Address
+ for tk := range tc.tokenDecimals {
+ destTokens = append(destTokens, tk)
+ }
+ sort.Slice(destTokens, func(i, j int) bool {
+ return destTokens[i] < destTokens[j]
+ })
+ var destDecimals []uint8
+ for _, token := range destTokens {
+ destDecimals = append(destDecimals, tc.tokenDecimals[token])
+ }
+
+ destPriceRegistryReader.On("GetTokensDecimals", ctx, mock.MatchedBy(func(tokens []cciptypes.Address) bool {
+ for _, token := range tokens {
+ if !slices.Contains(destTokens, token) {
+ return false
+ }
+ }
+ return true
+ })).Return(destDecimals, nil).Maybe()
+
+ lp := mocks2.NewLogPoller(t)
+ commitStoreReader, err := v1_2_0.NewCommitStore(logger.TestLogger(t), utils.RandomAddress(), nil, lp)
+ assert.NoError(t, err)
+
+ healthCheck := ccipcachemocks.NewChainHealthcheck(t)
+ healthCheck.On("IsHealthy", ctx).Return(true, nil)
+
+ p := &CommitReportingPlugin{}
+ p.lggr = logger.TestLogger(t)
+ p.destPriceRegistryReader = destPriceRegistryReader
+ p.onRampReader = onRampReader
+ p.sourceChainSelector = sourceChainSelector
+ p.gasPriceEstimator = gasPriceEstimator
+ p.offchainConfig.GasPriceHeartBeat = gasPriceHeartBeat.Duration()
+ p.commitStoreReader = commitStoreReader
+ p.F = tc.f
+ p.metricsCollector = ccip.NoopMetricsCollector
+ p.chainHealthcheck = healthCheck
+
+ aos := make([]types.AttributedObservation, 0, len(tc.observations))
+ for _, o := range tc.observations {
+ obs, err2 := o.Marshal()
+ assert.NoError(t, err2)
+ aos = append(aos, types.AttributedObservation{Observation: obs})
+ }
+
+ gotSomeReport, gotReport, err := p.Report(ctx, types.ReportTimestamp{}, types.Query{}, aos)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+
+ assert.NoError(t, err)
+
+ if tc.expCommitReport != nil {
+ assert.True(t, gotSomeReport)
+ encodedExpectedReport, err := encodeCommitReport(*tc.expCommitReport)
+ assert.NoError(t, err)
+ assert.Equal(t, types.Report(encodedExpectedReport), gotReport)
+ }
+ })
+ }
+}
+
+func TestCommitReportingPlugin_ShouldAcceptFinalizedReport(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ newPlugin := func() *CommitReportingPlugin {
+ p := &CommitReportingPlugin{}
+ p.lggr = logger.TestLogger(t)
+ p.metricsCollector = ccip.NoopMetricsCollector
+ return p
+ }
+
+ t.Run("report cannot be decoded leads to error", func(t *testing.T) {
+ p := newPlugin()
+
+ encodedReport := []byte("whatever")
+
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ p.commitStoreReader = commitStoreReader
+ commitStoreReader.On("DecodeCommitReport", mock.Anything, encodedReport).
+ Return(cciptypes.CommitStoreReport{}, errors.New("unable to decode report"))
+
+ _, err := p.ShouldAcceptFinalizedReport(ctx, types.ReportTimestamp{}, encodedReport)
+ assert.Error(t, err)
+ })
+
+ t.Run("empty report should not be accepted", func(t *testing.T) {
+ p := newPlugin()
+
+ report := cciptypes.CommitStoreReport{}
+
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ p.commitStoreReader = commitStoreReader
+ commitStoreReader.On("DecodeCommitReport", mock.Anything, mock.Anything).Return(report, nil)
+
+ chainHealthCheck := ccipcachemocks.NewChainHealthcheck(t)
+ chainHealthCheck.On("IsHealthy", ctx).Return(true, nil).Maybe()
+ p.chainHealthcheck = chainHealthCheck
+
+ encodedReport, err := encodeCommitReport(report)
+ assert.NoError(t, err)
+ shouldAccept, err := p.ShouldAcceptFinalizedReport(ctx, types.ReportTimestamp{}, encodedReport)
+ assert.NoError(t, err)
+ assert.False(t, shouldAccept)
+ })
+
+ t.Run("stale report should not be accepted", func(t *testing.T) {
+ onChainSeqNum := uint64(100)
+
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ p := newPlugin()
+
+ p.commitStoreReader = commitStoreReader
+
+ report := cciptypes.CommitStoreReport{
+ GasPrices: []cciptypes.GasPrice{{Value: big.NewInt(int64(rand.Int()))}},
+ MerkleRoot: [32]byte{123}, // this report is considered non-empty since it has a merkle root
+ }
+
+ commitStoreReader.On("DecodeCommitReport", mock.Anything, mock.Anything).Return(report, nil)
+ commitStoreReader.On("GetExpectedNextSequenceNumber", mock.Anything).Return(onChainSeqNum, nil)
+
+ chainHealthCheck := ccipcachemocks.NewChainHealthcheck(t)
+ chainHealthCheck.On("IsHealthy", ctx).Return(true, nil)
+ p.chainHealthcheck = chainHealthCheck
+
+ // stale since report interval is behind on chain seq num
+ report.Interval = cciptypes.CommitStoreInterval{Min: onChainSeqNum - 2, Max: onChainSeqNum + 10}
+ encodedReport, err := encodeCommitReport(report)
+ assert.NoError(t, err)
+
+ shouldAccept, err := p.ShouldAcceptFinalizedReport(ctx, types.ReportTimestamp{}, encodedReport)
+ assert.NoError(t, err)
+ assert.False(t, shouldAccept)
+ })
+
+ t.Run("non-stale report should be accepted", func(t *testing.T) {
+ onChainSeqNum := uint64(100)
+
+ p := newPlugin()
+
+ priceRegistryReader := ccipdatamocks.NewPriceRegistryReader(t)
+ p.destPriceRegistryReader = priceRegistryReader
+
+ p.lggr = logger.TestLogger(t)
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ p.commitStoreReader = commitStoreReader
+
+ report := cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{
+ Min: onChainSeqNum,
+ Max: onChainSeqNum + 10,
+ },
+ TokenPrices: []cciptypes.TokenPrice{
+ {
+ Token: cciptypes.Address(utils.RandomAddress().String()),
+ Value: big.NewInt(int64(rand.Int())),
+ },
+ },
+ GasPrices: []cciptypes.GasPrice{
+ {
+ DestChainSelector: rand.Uint64(),
+ Value: big.NewInt(int64(rand.Int())),
+ },
+ },
+ MerkleRoot: [32]byte{123},
+ }
+ commitStoreReader.On("DecodeCommitReport", mock.Anything, mock.Anything).Return(report, nil)
+ commitStoreReader.On("GetExpectedNextSequenceNumber", mock.Anything).Return(onChainSeqNum, nil)
+
+ // non-stale since report interval is not behind on-chain seq num
+ report.Interval = cciptypes.CommitStoreInterval{Min: onChainSeqNum, Max: onChainSeqNum + 10}
+ encodedReport, err := encodeCommitReport(report)
+ assert.NoError(t, err)
+
+ chainHealthCheck := ccipcachemocks.NewChainHealthcheck(t)
+ chainHealthCheck.On("IsHealthy", ctx).Return(true, nil)
+ p.chainHealthcheck = chainHealthCheck
+
+ shouldAccept, err := p.ShouldAcceptFinalizedReport(ctx, types.ReportTimestamp{}, encodedReport)
+ assert.NoError(t, err)
+ assert.True(t, shouldAccept)
+ })
+}
+
+func TestCommitReportingPlugin_ShouldTransmitAcceptedReport(t *testing.T) {
+ report := cciptypes.CommitStoreReport{
+ TokenPrices: []cciptypes.TokenPrice{
+ {Token: cciptypes.Address(utils.RandomAddress().String()), Value: big.NewInt(9e18)},
+ },
+ GasPrices: []cciptypes.GasPrice{
+ {
+
+ DestChainSelector: rand.Uint64(),
+ Value: big.NewInt(2000e9),
+ },
+ },
+ MerkleRoot: [32]byte{123},
+ }
+
+ ctx := testutils.Context(t)
+ p := &CommitReportingPlugin{}
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ onChainSeqNum := uint64(100)
+ commitStoreReader.On("GetExpectedNextSequenceNumber", mock.Anything).Return(onChainSeqNum, nil)
+ p.commitStoreReader = commitStoreReader
+ p.lggr = logger.TestLogger(t)
+
+ chainHealthCheck := ccipcachemocks.NewChainHealthcheck(t)
+ chainHealthCheck.On("IsHealthy", ctx).Return(true, nil).Maybe()
+ p.chainHealthcheck = chainHealthCheck
+
+ t.Run("should transmit when report is not stale", func(t *testing.T) {
+ // not-stale since report interval is not behind on chain seq num
+ report.Interval = cciptypes.CommitStoreInterval{Min: onChainSeqNum, Max: onChainSeqNum + 10}
+ encodedReport, err := encodeCommitReport(report)
+ assert.NoError(t, err)
+ commitStoreReader.On("DecodeCommitReport", mock.Anything, encodedReport).Return(report, nil).Once()
+ shouldTransmit, err := p.ShouldTransmitAcceptedReport(ctx, types.ReportTimestamp{}, encodedReport)
+ assert.NoError(t, err)
+ assert.True(t, shouldTransmit)
+ })
+
+ t.Run("should not transmit when report is stale", func(t *testing.T) {
+ // stale since report interval is behind on chain seq num
+ report.Interval = cciptypes.CommitStoreInterval{Min: onChainSeqNum - 2, Max: onChainSeqNum + 10}
+ encodedReport, err := encodeCommitReport(report)
+ assert.NoError(t, err)
+ commitStoreReader.On("DecodeCommitReport", mock.Anything, encodedReport).Return(report, nil).Once()
+ shouldTransmit, err := p.ShouldTransmitAcceptedReport(ctx, types.ReportTimestamp{}, encodedReport)
+ assert.NoError(t, err)
+ assert.False(t, shouldTransmit)
+ })
+
+ t.Run("error when report cannot be decoded", func(t *testing.T) {
+ reportBytes := []byte("whatever")
+ commitStoreReader.On("DecodeCommitReport", mock.Anything, reportBytes).
+ Return(cciptypes.CommitStoreReport{}, errors.New("decode error")).Once()
+ _, err := p.ShouldTransmitAcceptedReport(ctx, types.ReportTimestamp{}, reportBytes)
+ assert.Error(t, err)
+ })
+}
+
+func TestCommitReportingPlugin_observePriceUpdates(t *testing.T) {
+ destChainSelector := uint64(12345)
+ sourceChainSelector := uint64(67890)
+
+ token1 := ccipcalc.HexToAddress("0x123")
+ token2 := ccipcalc.HexToAddress("0x234")
+
+ gasPrices := map[uint64]*big.Int{
+ sourceChainSelector: big.NewInt(1e18),
+ }
+ tokenPrices := map[cciptypes.Address]*big.Int{
+ token1: big.NewInt(2e18),
+ token2: big.NewInt(3e18),
+ }
+
+ testCases := []struct {
+ name string
+ psGasPricesResult map[uint64]*big.Int
+ psTokenPricesResult map[cciptypes.Address]*big.Int
+ PriceReportingDisabled bool
+
+ expectedGasPrice map[uint64]*big.Int
+ expectedTokenPrices map[cciptypes.Address]*big.Int
+
+ psError bool
+ expectedErr bool
+ }{
+ {
+ name: "ORM called successfully",
+ psGasPricesResult: gasPrices,
+ psTokenPricesResult: tokenPrices,
+ expectedGasPrice: gasPrices,
+ expectedTokenPrices: tokenPrices,
+ },
+ {
+ name: "price reporting disabled",
+ psGasPricesResult: gasPrices,
+ psTokenPricesResult: tokenPrices,
+ PriceReportingDisabled: true,
+ expectedGasPrice: map[uint64]*big.Int{},
+ expectedTokenPrices: map[cciptypes.Address]*big.Int{},
+ psError: false,
+ expectedErr: false,
+ },
+ {
+ name: "price service error",
+ psGasPricesResult: map[uint64]*big.Int{},
+ psTokenPricesResult: map[cciptypes.Address]*big.Int{},
+ expectedGasPrice: nil,
+ expectedTokenPrices: nil,
+ psError: true,
+ expectedErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := tests.Context(t)
+
+ mockPriceService := ccipdbmocks.NewPriceService(t)
+ var psError error
+ if tc.psError {
+ psError = fmt.Errorf("price service error")
+ }
+ mockPriceService.On("GetGasAndTokenPrices", ctx, destChainSelector).Return(
+ tc.psGasPricesResult,
+ tc.psTokenPricesResult,
+ psError,
+ ).Maybe()
+
+ p := &CommitReportingPlugin{
+ lggr: logger.TestLogger(t),
+ destChainSelector: destChainSelector,
+ sourceChainSelector: sourceChainSelector,
+ priceService: mockPriceService,
+ offchainConfig: cciptypes.CommitOffchainConfig{
+ PriceReportingDisabled: tc.PriceReportingDisabled,
+ },
+ }
+ gasPricesUSD, sourceGasPriceUSD, tokenPricesUSD, err := p.observePriceUpdates(ctx)
+ if tc.expectedErr {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expectedGasPrice, gasPricesUSD)
+ assert.Equal(t, tc.expectedTokenPrices, tokenPricesUSD)
+ if tc.expectedGasPrice != nil {
+ assert.Equal(t, tc.expectedGasPrice[sourceChainSelector], sourceGasPriceUSD)
+ }
+ }
+ })
+ }
+}
+
+type CommitObservationLegacy struct {
+ Interval cciptypes.CommitStoreInterval `json:"interval"`
+ TokenPricesUSD map[cciptypes.Address]*big.Int `json:"tokensPerFeeCoin"`
+ SourceGasPriceUSD *big.Int `json:"sourceGasPrice"`
+}
+
+func TestCommitReportingPlugin_extractObservationData(t *testing.T) {
+ token1 := ccipcalc.HexToAddress("0xa")
+ token2 := ccipcalc.HexToAddress("0xb")
+ token1Price := big.NewInt(1)
+ token2Price := big.NewInt(2)
+ unsupportedToken := ccipcalc.HexToAddress("0xc")
+ gasPrice1 := big.NewInt(100)
+ gasPrice2 := big.NewInt(100)
+ var sourceChainSelector1 uint64 = 10
+ var sourceChainSelector2 uint64 = 20
+
+ tokenDecimals := make(map[cciptypes.Address]uint8)
+ tokenDecimals[token1] = 18
+ tokenDecimals[token2] = 18
+
+ validInterval := cciptypes.CommitStoreInterval{Min: 1, Max: 2}
+ zeroInterval := cciptypes.CommitStoreInterval{Min: 0, Max: 0}
+
+ // mix legacy commit observations with new commit observations to ensure they can work together
+ legacyObsRaw := CommitObservationLegacy{
+ Interval: validInterval,
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{
+ token1: token1Price,
+ token2: token2Price,
+ },
+ SourceGasPriceUSD: gasPrice1,
+ }
+ legacyObsBytes, err := json.Marshal(&legacyObsRaw)
+ assert.NoError(t, err)
+
+ newObsRaw := ccip.CommitObservation{
+ Interval: validInterval,
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{
+ token1: token1Price,
+ token2: token2Price,
+ },
+ SourceGasPriceUSD: gasPrice1,
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector1: gasPrice1,
+ sourceChainSelector2: gasPrice2,
+ },
+ }
+ newObsBytes, err := newObsRaw.Marshal()
+ assert.NoError(t, err)
+
+ lggr := logger.TestLogger(t)
+ observations := ccip.GetParsableObservations[ccip.CommitObservation](lggr, []types.AttributedObservation{
+ {Observation: legacyObsBytes},
+ {Observation: newObsBytes},
+ })
+ assert.Len(t, observations, 2)
+ legacyObs := observations[0]
+ newObs := observations[1]
+
+ obWithNilGasPrice := ccip.CommitObservation{
+ Interval: zeroInterval,
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{
+ token1: token1Price,
+ token2: token2Price,
+ },
+ SourceGasPriceUSD: nil,
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{},
+ }
+ obWithNilTokenPrice := ccip.CommitObservation{
+ Interval: zeroInterval,
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{
+ token1: token1Price,
+ token2: nil,
+ },
+ SourceGasPriceUSD: gasPrice1,
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector1: gasPrice1,
+ sourceChainSelector2: gasPrice2,
+ },
+ }
+ obMissingTokenPrices := ccip.CommitObservation{
+ Interval: zeroInterval,
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{},
+ SourceGasPriceUSD: gasPrice1,
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector1: gasPrice1,
+ sourceChainSelector2: gasPrice2,
+ },
+ }
+ obWithUnsupportedToken := ccip.CommitObservation{
+ Interval: zeroInterval,
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{
+ token1: token1Price,
+ token2: token2Price,
+ unsupportedToken: token2Price,
+ },
+ SourceGasPriceUSD: gasPrice1,
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ sourceChainSelector1: gasPrice1,
+ sourceChainSelector2: gasPrice2,
+ },
+ }
+ obEmpty := ccip.CommitObservation{
+ Interval: zeroInterval,
+ TokenPricesUSD: nil,
+ SourceGasPriceUSD: nil,
+ SourceGasPriceUSDPerChain: nil,
+ }
+
+ testCases := []struct {
+ name string
+ commitObservations []ccip.CommitObservation
+ f int
+ expIntervals []cciptypes.CommitStoreInterval
+ expGasPriceObs map[uint64][]*big.Int
+ expTokenPriceObs map[cciptypes.Address][]*big.Int
+ expError bool
+ }{
+ {
+ name: "base",
+ commitObservations: []ccip.CommitObservation{newObs, newObs, newObs},
+ f: 2,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, validInterval, validInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1},
+ sourceChainSelector2: {gasPrice2, gasPrice2, gasPrice2},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{
+ token1: {token1Price, token1Price, token1Price},
+ token2: {token2Price, token2Price, token2Price},
+ },
+ expError: false,
+ },
+ {
+ name: "pass with f=2 and mixed observations",
+ commitObservations: []ccip.CommitObservation{legacyObs, newObs, legacyObs, newObs, newObs, obWithNilGasPrice},
+ f: 2,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, validInterval, validInterval, validInterval, validInterval, zeroInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1, gasPrice1, gasPrice1},
+ sourceChainSelector2: {gasPrice2, gasPrice2, gasPrice2},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{
+ token1: {token1Price, token1Price, token1Price, token1Price, token1Price, token1Price},
+ token2: {token2Price, token2Price, token2Price, token2Price, token2Price, token2Price},
+ },
+ expError: false,
+ },
+ {
+ name: "pass with f=2 and mixed observations with mostly legacy observations",
+ commitObservations: []ccip.CommitObservation{legacyObs, legacyObs, legacyObs, legacyObs, newObs},
+ f: 2,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, validInterval, validInterval, validInterval, validInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1, gasPrice1, gasPrice1},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{
+ token1: {token1Price, token1Price, token1Price, token1Price, token1Price},
+ token2: {token2Price, token2Price, token2Price, token2Price, token2Price},
+ },
+ expError: false,
+ },
+ {
+ name: "tolerate 1 faulty obs with f=2",
+ commitObservations: []ccip.CommitObservation{legacyObs, newObs, legacyObs, obWithNilGasPrice},
+ f: 2,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, validInterval, validInterval, zeroInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{
+ token1: {token1Price, token1Price, token1Price, token1Price},
+ token2: {token2Price, token2Price, token2Price, token2Price},
+ },
+ expError: false,
+ },
+ {
+ name: "tolerate 1 nil token price with f=1",
+ commitObservations: []ccip.CommitObservation{legacyObs, newObs, obWithNilTokenPrice},
+ f: 1,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, validInterval, zeroInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1},
+ sourceChainSelector2: {gasPrice2, gasPrice2},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{
+ token1: {token1Price, token1Price, token1Price},
+ token2: {token2Price, token2Price},
+ },
+ expError: false,
+ },
+ {
+ name: "tolerate 1 missing token prices with f=1",
+ commitObservations: []ccip.CommitObservation{legacyObs, newObs, obMissingTokenPrices},
+ f: 1,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, validInterval, zeroInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1},
+ sourceChainSelector2: {gasPrice2, gasPrice2},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{
+ token1: {token1Price, token1Price},
+ token2: {token2Price, token2Price},
+ },
+ expError: false,
+ },
+ {
+ name: "tolerate 1 unsupported token with f=2",
+ commitObservations: []ccip.CommitObservation{legacyObs, newObs, obWithUnsupportedToken},
+ f: 2,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, validInterval, zeroInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{
+ token1: {token1Price, token1Price, token1Price},
+ token2: {token2Price, token2Price, token2Price},
+ },
+ expError: false,
+ },
+ {
+ name: "tolerate mis-matched token observations with f=2",
+ commitObservations: []ccip.CommitObservation{legacyObs, newObs, obWithNilTokenPrice, obMissingTokenPrices},
+ f: 2,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, validInterval, zeroInterval, zeroInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1, gasPrice1},
+ sourceChainSelector2: {gasPrice2, gasPrice2, gasPrice2},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{
+ token1: {token1Price, token1Price, token1Price},
+ },
+ expError: false,
+ },
+ {
+ name: "tolerate all tokens filtered out with f=2",
+ commitObservations: []ccip.CommitObservation{newObs, obMissingTokenPrices, obMissingTokenPrices},
+ f: 2,
+ expIntervals: []cciptypes.CommitStoreInterval{validInterval, zeroInterval, zeroInterval},
+ expGasPriceObs: map[uint64][]*big.Int{
+ sourceChainSelector1: {gasPrice1, gasPrice1, gasPrice1},
+ sourceChainSelector2: {gasPrice2, gasPrice2, gasPrice2},
+ },
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{},
+ expError: false,
+ },
+ {
+ name: "not enough observations",
+ commitObservations: []ccip.CommitObservation{legacyObs, newObs},
+ f: 2,
+ expError: true,
+ },
+ {
+ name: "too many empty observations",
+ commitObservations: []ccip.CommitObservation{obWithNilGasPrice, obWithNilTokenPrice, obEmpty, obEmpty, obEmpty},
+ f: 2,
+ expIntervals: []cciptypes.CommitStoreInterval{zeroInterval, zeroInterval, zeroInterval, zeroInterval, zeroInterval},
+ expGasPriceObs: map[uint64][]*big.Int{},
+ expTokenPriceObs: map[cciptypes.Address][]*big.Int{},
+ expError: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ intervals, gasPriceOps, tokenPriceOps, err := extractObservationData(logger.TestLogger(t), tc.f, sourceChainSelector1, tc.commitObservations)
+
+ if tc.expError {
+ assert.Error(t, err)
+ return
+ }
+ assert.Equal(t, tc.expIntervals, intervals)
+ assert.Equal(t, tc.expGasPriceObs, gasPriceOps)
+ assert.Equal(t, tc.expTokenPriceObs, tokenPriceOps)
+ assert.NoError(t, err)
+ })
+ }
+}
+
+func TestCommitReportingPlugin_calculatePriceUpdates(t *testing.T) {
+ const defaultSourceChainSelector = 10 // we reuse this value across all test cases
+ feeToken1 := ccipcalc.HexToAddress("0xa")
+ feeToken2 := ccipcalc.HexToAddress("0xb")
+
+ val1e18 := func(val int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(val)) }
+
+ testCases := []struct {
+ name string
+ commitObservations []ccip.CommitObservation
+ f int
+ latestGasPrice map[uint64]update
+ latestTokenPrices map[cciptypes.Address]update
+ gasPriceHeartBeat config.Duration
+ daGasPriceDeviationPPB int64
+ execGasPriceDeviationPPB int64
+ tokenPriceHeartBeat config.Duration
+ tokenPriceDeviationPPB uint32
+ expTokenUpdates []cciptypes.TokenPrice
+ expGasUpdates []cciptypes.GasPrice
+ }{
+ {
+ name: "median",
+ commitObservations: []ccip.CommitObservation{
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: big.NewInt(1)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: big.NewInt(2)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: big.NewInt(3)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: big.NewInt(4)}},
+ },
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-30 * time.Minute), // recent
+ value: val1e18(9), // median deviates
+ },
+ },
+ f: 2,
+ expGasUpdates: []cciptypes.GasPrice{{DestChainSelector: defaultSourceChainSelector, Value: big.NewInt(3)}},
+ },
+ {
+ name: "gas price update skipped because the latest is similar and was updated recently",
+ commitObservations: []ccip.CommitObservation{
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(11)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(12)}},
+ },
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 20e7,
+ execGasPriceDeviationPPB: 20e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ tokenPriceDeviationPPB: 20e7,
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-30 * time.Minute), // recent
+ value: val1e18(10), // median deviates
+ },
+ },
+ f: 1,
+ expGasUpdates: nil,
+ },
+ {
+ name: "gas price update included, the latest is similar but was not updated recently",
+ commitObservations: []ccip.CommitObservation{
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(10)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(11)}},
+ },
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 20e7,
+ execGasPriceDeviationPPB: 20e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ tokenPriceDeviationPPB: 20e7,
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-90 * time.Minute), // stale
+ value: val1e18(9), // median deviates
+ },
+ },
+ f: 1,
+ expGasUpdates: []cciptypes.GasPrice{{DestChainSelector: defaultSourceChainSelector, Value: val1e18(11)}},
+ },
+ {
+ name: "gas price update deviates from latest",
+ commitObservations: []ccip.CommitObservation{
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(10)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(20)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(20)}},
+ },
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 20e7,
+ execGasPriceDeviationPPB: 20e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ tokenPriceDeviationPPB: 20e7,
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-30 * time.Minute), // recent
+ value: val1e18(11), // latest value close to the update
+ },
+ },
+ f: 2,
+ expGasUpdates: []cciptypes.GasPrice{{DestChainSelector: defaultSourceChainSelector, Value: val1e18(20)}},
+ },
+ {
+ name: "multichain gas prices",
+ commitObservations: []ccip.CommitObservation{
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(1)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector + 1: val1e18(11)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector + 2: val1e18(111)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(2)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector + 1: val1e18(22)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector + 2: val1e18(222)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(3)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector + 1: val1e18(33)}},
+ {SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector + 2: val1e18(333)}},
+ },
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 20e7,
+ execGasPriceDeviationPPB: 20e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ tokenPriceDeviationPPB: 20e7,
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-90 * time.Minute), // stale
+ value: val1e18(9), // median deviates
+ },
+ defaultSourceChainSelector + 1: {
+ timestamp: time.Now().Add(-30 * time.Minute), // recent
+ value: val1e18(20), // median does not deviate
+ },
+ },
+ f: 1,
+ expGasUpdates: []cciptypes.GasPrice{
+ {DestChainSelector: defaultSourceChainSelector, Value: val1e18(2)},
+ {DestChainSelector: defaultSourceChainSelector + 2, Value: val1e18(222)},
+ },
+ },
+ {
+ name: "median one token",
+ commitObservations: []ccip.CommitObservation{
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: big.NewInt(10)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(0)},
+ },
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: big.NewInt(12)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(0)},
+ },
+ },
+ f: 1,
+ expTokenUpdates: []cciptypes.TokenPrice{
+ {Token: feeToken1, Value: big.NewInt(12)},
+ },
+ // We expect a gas update because no latest
+ expGasUpdates: []cciptypes.GasPrice{{DestChainSelector: defaultSourceChainSelector, Value: big.NewInt(0)}},
+ },
+ {
+ name: "median two tokens",
+ commitObservations: []ccip.CommitObservation{
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: big.NewInt(10), feeToken2: big.NewInt(13)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(0)},
+ },
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: big.NewInt(12), feeToken2: big.NewInt(7)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(0)},
+ },
+ },
+ f: 1,
+ expTokenUpdates: []cciptypes.TokenPrice{
+ {Token: feeToken1, Value: big.NewInt(12)},
+ {Token: feeToken2, Value: big.NewInt(13)},
+ },
+ // We expect a gas update because no latest
+ expGasUpdates: []cciptypes.GasPrice{{DestChainSelector: defaultSourceChainSelector, Value: big.NewInt(0)}},
+ },
+ {
+ name: "token price update skipped because it is close to the latest",
+ commitObservations: []ccip.CommitObservation{
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(11)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(0)},
+ },
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(12)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(0)},
+ },
+ },
+ f: 1,
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 20e7,
+ execGasPriceDeviationPPB: 20e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ tokenPriceDeviationPPB: 20e7,
+ latestTokenPrices: map[cciptypes.Address]update{
+ feeToken1: {
+ timestamp: time.Now().Add(-30 * time.Minute),
+ value: val1e18(10),
+ },
+ },
+ // We expect a gas update because no latest
+ expGasUpdates: []cciptypes.GasPrice{{DestChainSelector: defaultSourceChainSelector, Value: big.NewInt(0)}},
+ },
+ {
+ name: "gas price and token price both included because they are not close to the latest",
+ commitObservations: []ccip.CommitObservation{
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(20)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ defaultSourceChainSelector: val1e18(10),
+ defaultSourceChainSelector + 1: val1e18(20),
+ },
+ },
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(21)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ defaultSourceChainSelector: val1e18(11),
+ defaultSourceChainSelector + 1: val1e18(21),
+ },
+ },
+ },
+ f: 1,
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 10e7,
+ execGasPriceDeviationPPB: 10e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ tokenPriceDeviationPPB: 20e7,
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-30 * time.Minute),
+ value: val1e18(9),
+ },
+ defaultSourceChainSelector + 1: {
+ timestamp: time.Now().Add(-30 * time.Minute),
+ value: val1e18(9),
+ },
+ },
+ latestTokenPrices: map[cciptypes.Address]update{
+ feeToken1: {
+ timestamp: time.Now().Add(-30 * time.Minute),
+ value: val1e18(9),
+ },
+ },
+ expTokenUpdates: []cciptypes.TokenPrice{
+ {Token: feeToken1, Value: val1e18(21)},
+ },
+ expGasUpdates: []cciptypes.GasPrice{
+ {DestChainSelector: defaultSourceChainSelector, Value: val1e18(11)},
+ {DestChainSelector: defaultSourceChainSelector + 1, Value: val1e18(21)},
+ },
+ },
+ {
+ name: "gas price and token price both included because they not been updated recently",
+ commitObservations: []ccip.CommitObservation{
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(20)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ defaultSourceChainSelector: val1e18(10),
+ defaultSourceChainSelector + 1: val1e18(20),
+ },
+ },
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(21)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ defaultSourceChainSelector: val1e18(11),
+ defaultSourceChainSelector + 1: val1e18(21),
+ },
+ },
+ },
+ f: 1,
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 10e7,
+ execGasPriceDeviationPPB: 10e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(2 * time.Hour),
+ tokenPriceDeviationPPB: 20e7,
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-90 * time.Minute),
+ value: val1e18(11),
+ },
+ defaultSourceChainSelector + 1: {
+ timestamp: time.Now().Add(-90 * time.Minute),
+ value: val1e18(21),
+ },
+ },
+ latestTokenPrices: map[cciptypes.Address]update{
+ feeToken1: {
+ timestamp: time.Now().Add(-4 * time.Hour),
+ value: val1e18(21),
+ },
+ },
+ expTokenUpdates: []cciptypes.TokenPrice{
+ {Token: feeToken1, Value: val1e18(21)},
+ },
+ expGasUpdates: []cciptypes.GasPrice{
+ {DestChainSelector: defaultSourceChainSelector, Value: val1e18(11)},
+ {DestChainSelector: defaultSourceChainSelector + 1, Value: val1e18(21)},
+ },
+ },
+ {
+ name: "gas price included because it deviates from latest and token price skipped because it does not deviate",
+ commitObservations: []ccip.CommitObservation{
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(20)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(10)},
+ },
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(21)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(11)},
+ },
+ },
+ f: 1,
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 10e7,
+ execGasPriceDeviationPPB: 10e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(2 * time.Hour),
+ tokenPriceDeviationPPB: 200e7,
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-90 * time.Minute),
+ value: val1e18(9),
+ },
+ },
+ latestTokenPrices: map[cciptypes.Address]update{
+ feeToken1: {
+ timestamp: time.Now().Add(-30 * time.Minute),
+ value: val1e18(9),
+ },
+ },
+ expGasUpdates: []cciptypes.GasPrice{{DestChainSelector: defaultSourceChainSelector, Value: val1e18(11)}},
+ },
+ {
+ name: "gas price skipped because it does not deviate and token price included because it has not been updated recently",
+ commitObservations: []ccip.CommitObservation{
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(20)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(10)},
+ },
+ {
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{feeToken1: val1e18(21)},
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{defaultSourceChainSelector: val1e18(11)},
+ },
+ },
+ f: 1,
+ gasPriceHeartBeat: *config.MustNewDuration(time.Hour),
+ daGasPriceDeviationPPB: 10e7,
+ execGasPriceDeviationPPB: 10e7,
+ tokenPriceHeartBeat: *config.MustNewDuration(2 * time.Hour),
+ tokenPriceDeviationPPB: 20e7,
+ latestGasPrice: map[uint64]update{
+ defaultSourceChainSelector: {
+ timestamp: time.Now().Add(-30 * time.Minute),
+ value: val1e18(11),
+ },
+ },
+ latestTokenPrices: map[cciptypes.Address]update{
+ feeToken1: {
+ timestamp: time.Now().Add(-4 * time.Hour),
+ value: val1e18(21),
+ },
+ },
+ expTokenUpdates: []cciptypes.TokenPrice{
+ {Token: feeToken1, Value: val1e18(21)},
+ },
+ expGasUpdates: nil,
+ },
+ }
+
+ evmEstimator := mocks.NewEvmFeeEstimator(t)
+ evmEstimator.On("L1Oracle").Return(nil)
+ estimatorCSVer, _ := semver.NewVersion("1.2.0")
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ estimator, _ := prices.NewGasPriceEstimatorForCommitPlugin(
+ *estimatorCSVer,
+ evmEstimator,
+ nil,
+ tc.daGasPriceDeviationPPB,
+ tc.execGasPriceDeviationPPB,
+ )
+
+ r := &CommitReportingPlugin{
+ lggr: logger.TestLogger(t),
+ sourceChainSelector: defaultSourceChainSelector,
+ offchainConfig: cciptypes.CommitOffchainConfig{
+ GasPriceHeartBeat: tc.gasPriceHeartBeat.Duration(),
+ TokenPriceHeartBeat: tc.tokenPriceHeartBeat.Duration(),
+ TokenPriceDeviationPPB: tc.tokenPriceDeviationPPB,
+ },
+ gasPriceEstimator: estimator,
+ F: tc.f,
+ }
+
+ gasPriceObs := make(map[uint64][]*big.Int)
+ tokenPriceObs := make(map[cciptypes.Address][]*big.Int)
+ for _, obs := range tc.commitObservations {
+ for selector, price := range obs.SourceGasPriceUSDPerChain {
+ gasPriceObs[selector] = append(gasPriceObs[selector], price)
+ }
+ for token, price := range obs.TokenPricesUSD {
+ tokenPriceObs[token] = append(tokenPriceObs[token], price)
+ }
+ }
+
+ gotGas, gotTokens, err := r.calculatePriceUpdates(gasPriceObs, tokenPriceObs, tc.latestGasPrice, tc.latestTokenPrices)
+
+ assert.Equal(t, tc.expGasUpdates, gotGas)
+ assert.Equal(t, tc.expTokenUpdates, gotTokens)
+ assert.NoError(t, err)
+ })
+ }
+}
+
+func TestCommitReportingPlugin_isStaleReport(t *testing.T) {
+ ctx := context.Background()
+ lggr := logger.TestLogger(t)
+ merkleRoot1 := utils.Keccak256Fixed([]byte("some merkle root 1"))
+
+ t.Run("empty report", func(t *testing.T) {
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ r := &CommitReportingPlugin{commitStoreReader: commitStoreReader}
+ isStale := r.isStaleReport(ctx, lggr, cciptypes.CommitStoreReport{}, types.ReportTimestamp{})
+ assert.True(t, isStale)
+ })
+
+ t.Run("merkle root", func(t *testing.T) {
+ const expNextSeqNum = uint64(9)
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ commitStoreReader.On("GetExpectedNextSequenceNumber", mock.Anything).Return(expNextSeqNum, nil)
+
+ r := &CommitReportingPlugin{
+ commitStoreReader: commitStoreReader,
+ }
+
+ testCases := map[string]struct {
+ interval cciptypes.CommitStoreInterval
+ result bool
+ }{
+ "The nextSeqNumber is equal to the commit store interval Min value": {
+ interval: cciptypes.CommitStoreInterval{Min: expNextSeqNum, Max: expNextSeqNum + 10},
+ result: false,
+ },
+ "The nextSeqNumber is less than the commit store interval Min value": {
+ interval: cciptypes.CommitStoreInterval{Min: expNextSeqNum + 1, Max: expNextSeqNum + 10},
+ result: true,
+ },
+ "The nextSeqNumber is greater than the commit store interval Min value": {
+ interval: cciptypes.CommitStoreInterval{Min: expNextSeqNum - 1, Max: expNextSeqNum + 10},
+ result: true,
+ },
+ "Empty interval": {
+ interval: cciptypes.CommitStoreInterval{},
+ result: true,
+ },
+ }
+
+ for tcName, tc := range testCases {
+ t.Run(tcName, func(t *testing.T) {
+ assert.Equal(t, tc.result, r.isStaleReport(ctx, lggr, cciptypes.CommitStoreReport{
+ MerkleRoot: merkleRoot1,
+ Interval: tc.interval,
+ }, types.ReportTimestamp{}))
+ })
+ }
+ })
+}
+
+func TestCommitReportingPlugin_calculateMinMaxSequenceNumbers(t *testing.T) {
+ testCases := []struct {
+ name string
+ commitStoreSeqNum uint64
+ msgSeqNums []uint64
+
+ expQueryMin uint64 // starting seq num that is used in the query to get messages
+ expMin uint64
+ expMax uint64
+ expErr bool
+ }{
+ {
+ name: "happy flow",
+ commitStoreSeqNum: 9,
+ msgSeqNums: []uint64{11, 12, 13, 14},
+ expQueryMin: 9,
+ expMin: 11,
+ expMax: 14,
+ expErr: false,
+ },
+ {
+ name: "happy flow 2",
+ commitStoreSeqNum: 9,
+ msgSeqNums: []uint64{11, 12, 13, 14},
+ expQueryMin: 9, // from commit store
+ expMin: 11,
+ expMax: 14,
+ expErr: false,
+ },
+ {
+ name: "gap in msg seq nums",
+ commitStoreSeqNum: 10,
+ expQueryMin: 10,
+ msgSeqNums: []uint64{11, 12, 14},
+ expErr: true,
+ },
+ {
+ name: "no new messages",
+ commitStoreSeqNum: 9,
+ msgSeqNums: []uint64{},
+ expQueryMin: 9,
+ expMin: 0,
+ expMax: 0,
+ expErr: false,
+ },
+ {
+ name: "unordered seq nums",
+ commitStoreSeqNum: 9,
+ msgSeqNums: []uint64{11, 13, 14, 10},
+ expQueryMin: 9,
+ expErr: true,
+ },
+ }
+
+ ctx := testutils.Context(t)
+ lggr := logger.TestLogger(t)
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ p := &CommitReportingPlugin{}
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ commitStoreReader.On("GetExpectedNextSequenceNumber", mock.Anything).Return(tc.commitStoreSeqNum, nil)
+ p.commitStoreReader = commitStoreReader
+
+ onRampReader := ccipdatamocks.NewOnRampReader(t)
+ var sendReqs []cciptypes.EVM2EVMMessageWithTxMeta
+ for _, seqNum := range tc.msgSeqNums {
+ sendReqs = append(sendReqs, cciptypes.EVM2EVMMessageWithTxMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: seqNum,
+ },
+ })
+ }
+ onRampReader.On("GetSendRequestsBetweenSeqNums", ctx, tc.expQueryMin, tc.expQueryMin+OnRampMessagesScanLimit, true).Return(sendReqs, nil)
+ p.onRampReader = onRampReader
+
+ minSeqNum, maxSeqNum, _, err := p.calculateMinMaxSequenceNumbers(ctx, lggr)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+
+ assert.Equal(t, tc.expMin, minSeqNum)
+ assert.Equal(t, tc.expMax, maxSeqNum)
+ })
+ }
+}
+
+func TestCommitReportingPlugin_getLatestGasPriceUpdate(t *testing.T) {
+ now := time.Now()
+ chainSelector1 := uint64(1234)
+ chainSelector2 := uint64(5678)
+
+ chain1Value := big.NewInt(1000)
+ chain2Value := big.NewInt(2000)
+
+ testCases := []struct {
+ name string
+ priceRegistryUpdates []cciptypes.GasPriceUpdate
+ expUpdates map[uint64]update
+ expErr bool
+ }{
+ {
+ name: "happy path",
+ priceRegistryUpdates: []cciptypes.GasPriceUpdate{
+ {
+ GasPrice: cciptypes.GasPrice{DestChainSelector: chainSelector1, Value: chain1Value},
+ TimestampUnixSec: big.NewInt(now.Unix()),
+ },
+ },
+ expUpdates: map[uint64]update{chainSelector1: {timestamp: now, value: chain1Value}},
+ expErr: false,
+ },
+ {
+ name: "happy path multiple updates",
+ priceRegistryUpdates: []cciptypes.GasPriceUpdate{
+ {
+ GasPrice: cciptypes.GasPrice{DestChainSelector: chainSelector1, Value: big.NewInt(1)},
+ TimestampUnixSec: big.NewInt(now.Unix()),
+ },
+ {
+ GasPrice: cciptypes.GasPrice{DestChainSelector: chainSelector2, Value: big.NewInt(1)},
+ TimestampUnixSec: big.NewInt(now.Add(1 * time.Minute).Unix()),
+ },
+ {
+ GasPrice: cciptypes.GasPrice{DestChainSelector: chainSelector2, Value: chain2Value},
+ TimestampUnixSec: big.NewInt(now.Add(2 * time.Minute).Unix()),
+ },
+ {
+ GasPrice: cciptypes.GasPrice{DestChainSelector: chainSelector1, Value: chain1Value},
+ TimestampUnixSec: big.NewInt(now.Add(3 * time.Minute).Unix()),
+ },
+ },
+ expUpdates: map[uint64]update{
+ chainSelector1: {timestamp: now.Add(3 * time.Minute), value: chain1Value},
+ chainSelector2: {timestamp: now.Add(2 * time.Minute), value: chain2Value},
+ },
+ expErr: false,
+ },
+ }
+
+ ctx := testutils.Context(t)
+ lggr := logger.TestLogger(t)
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ p := &CommitReportingPlugin{}
+ p.lggr = lggr
+ priceReg := ccipdatamocks.NewPriceRegistryReader(t)
+ p.destPriceRegistryReader = priceReg
+
+ var events []cciptypes.GasPriceUpdateWithTxMeta
+ for _, update := range tc.priceRegistryUpdates {
+ events = append(events, cciptypes.GasPriceUpdateWithTxMeta{
+ GasPriceUpdate: update,
+ })
+ }
+
+ priceReg.On("GetAllGasPriceUpdatesCreatedAfter", ctx, mock.Anything, 0).Return(events, nil)
+
+ gotUpdates, err := p.getLatestGasPriceUpdate(ctx, now)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equal(t, len(tc.expUpdates), len(gotUpdates))
+ for selector, gotUpdate := range gotUpdates {
+ assert.Equal(t, tc.expUpdates[selector].timestamp.Truncate(time.Second), gotUpdate.timestamp.Truncate(time.Second))
+ assert.Equal(t, tc.expUpdates[selector].value.Uint64(), gotUpdate.value.Uint64())
+ }
+ })
+ }
+}
+
+func TestCommitReportingPlugin_getLatestTokenPriceUpdates(t *testing.T) {
+ now := time.Now()
+ tk1 := cciptypes.Address(utils.RandomAddress().String())
+ tk2 := cciptypes.Address(utils.RandomAddress().String())
+
+ testCases := []struct {
+ name string
+ priceRegistryUpdates []cciptypes.TokenPriceUpdate
+ expUpdates map[cciptypes.Address]update
+ expErr bool
+ }{
+ {
+ name: "happy path",
+ priceRegistryUpdates: []cciptypes.TokenPriceUpdate{
+ {
+ TokenPrice: cciptypes.TokenPrice{
+ Token: tk1,
+ Value: big.NewInt(1000),
+ },
+ TimestampUnixSec: big.NewInt(now.Add(1 * time.Minute).Unix()),
+ },
+ {
+ TokenPrice: cciptypes.TokenPrice{
+ Token: tk2,
+ Value: big.NewInt(2000),
+ },
+ TimestampUnixSec: big.NewInt(now.Add(2 * time.Minute).Unix()),
+ },
+ },
+ expUpdates: map[cciptypes.Address]update{
+ tk1: {timestamp: now.Add(1 * time.Minute), value: big.NewInt(1000)},
+ tk2: {timestamp: now.Add(2 * time.Minute), value: big.NewInt(2000)},
+ },
+ expErr: false,
+ },
+ }
+
+ ctx := testutils.Context(t)
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ p := &CommitReportingPlugin{}
+
+ priceReg := ccipdatamocks.NewPriceRegistryReader(t)
+ p.destPriceRegistryReader = priceReg
+
+ var events []cciptypes.TokenPriceUpdateWithTxMeta
+ for _, up := range tc.priceRegistryUpdates {
+ events = append(events, cciptypes.TokenPriceUpdateWithTxMeta{
+ TokenPriceUpdate: up,
+ })
+ }
+
+ priceReg.On("GetTokenPriceUpdatesCreatedAfter", ctx, mock.Anything, 0).Return(events, nil)
+
+ updates, err := p.getLatestTokenPriceUpdates(ctx, now)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equal(t, len(tc.expUpdates), len(updates))
+ for k, v := range updates {
+ assert.Equal(t, tc.expUpdates[k].timestamp.Truncate(time.Second), v.timestamp.Truncate(time.Second))
+ assert.Equal(t, tc.expUpdates[k].value.Uint64(), v.value.Uint64())
+ }
+ })
+ }
+}
+
+func Test_commitReportSize(t *testing.T) {
+ testParams := gopter.DefaultTestParameters()
+ testParams.MinSuccessfulTests = 100
+ p := gopter.NewProperties(testParams)
+ p.Property("bounded commit report size", prop.ForAll(func(root []byte, min, max uint64) bool {
+ var root32 [32]byte
+ copy(root32[:], root)
+ rep, err := encodeCommitReport(cciptypes.CommitStoreReport{
+ MerkleRoot: root32,
+ Interval: cciptypes.CommitStoreInterval{Min: min, Max: max},
+ TokenPrices: []cciptypes.TokenPrice{},
+ GasPrices: []cciptypes.GasPrice{
+ {
+ DestChainSelector: 1337,
+ Value: big.NewInt(2000e9), // $2000 per eth * 1gwei = 2000e9
+ },
+ },
+ })
+ require.NoError(t, err)
+ return len(rep) <= MaxCommitReportLength
+ }, gen.SliceOfN(32, gen.UInt8()), gen.UInt64(), gen.UInt64()))
+ p.TestingRun(t)
+}
+
+func Test_calculateIntervalConsensus(t *testing.T) {
+ tests := []struct {
+ name string
+ intervals []cciptypes.CommitStoreInterval
+ rangeLimit uint64
+ f int
+ wantMin uint64
+ wantMax uint64
+ wantErr bool
+ }{
+ {"no obs", []cciptypes.CommitStoreInterval{{Min: 0, Max: 0}}, 0, 0, 0, 0, false},
+ {"basic", []cciptypes.CommitStoreInterval{
+ {Min: 9, Max: 14},
+ {Min: 10, Max: 12},
+ {Min: 10, Max: 14},
+ }, 0, 1, 10, 14, false},
+ {"min > max", []cciptypes.CommitStoreInterval{
+ {Min: 9, Max: 4},
+ {Min: 10, Max: 4},
+ {Min: 10, Max: 6},
+ }, 0, 1, 0, 0, true},
+ {
+ "range limit", []cciptypes.CommitStoreInterval{
+ {Min: 10, Max: 100},
+ {Min: 1, Max: 1000},
+ }, 256, 1, 10, 265, false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := calculateIntervalConsensus(tt.intervals, tt.f, tt.rangeLimit)
+ if tt.wantErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ assert.Equal(t, tt.wantMin, got.Min)
+ assert.Equal(t, tt.wantMax, got.Max)
+ })
+ }
+}
+
+func TestCommitReportToEthTxMeta(t *testing.T) {
+ mctx := hashutil.NewKeccak()
+ tree, err := merklemulti.NewTree(mctx, [][32]byte{mctx.Hash([]byte{0xaa})})
+ require.NoError(t, err)
+
+ tests := []struct {
+ name string
+ min, max uint64
+ expectedRange []uint64
+ }{
+ {
+ "happy flow",
+ 1, 10,
+ []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
+ },
+ {
+ "same sequence",
+ 1, 1,
+ []uint64{1},
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ report := cciptypes.CommitStoreReport{
+ TokenPrices: []cciptypes.TokenPrice{},
+ GasPrices: []cciptypes.GasPrice{
+ {
+ DestChainSelector: uint64(1337),
+ Value: big.NewInt(2000e9), // $2000 per eth * 1gwei = 2000e9
+ },
+ },
+ MerkleRoot: tree.Root(),
+ Interval: cciptypes.CommitStoreInterval{Min: tc.min, Max: tc.max},
+ }
+ out, err := encodeCommitReport(report)
+ require.NoError(t, err)
+
+ fn, err := factory.CommitReportToEthTxMeta(ccipconfig.CommitStore, *semver.MustParse("1.0.0"))
+ require.NoError(t, err)
+ txMeta, err := fn(out)
+ require.NoError(t, err)
+ require.NotNil(t, txMeta)
+ require.EqualValues(t, tc.expectedRange, txMeta.SeqNumbers)
+ })
+ }
+}
+
+// TODO should be removed, tests need to be updated to use the Reader interface.
+// encodeCommitReport is only used in tests
+func encodeCommitReport(report cciptypes.CommitStoreReport) ([]byte, error) {
+ commitStoreABI := abihelpers.MustParseABI(commit_store.CommitStoreABI)
+ return v1_2_0.EncodeCommitReport(abihelpers.MustGetEventInputs(v1_0_0.ReportAccepted, commitStoreABI), report)
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/batching.go b/core/services/ocr2/plugins/ccip/ccipexec/batching.go
new file mode 100644
index 00000000000..b457dd986d4
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/batching.go
@@ -0,0 +1,540 @@
+package ccipexec
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "time"
+
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/merklemulti"
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/statuschecker"
+)
+
+type BatchContext struct {
+ report commitReportWithSendRequests
+ inflight []InflightInternalExecutionReport
+ inflightAggregateValue *big.Int
+ lggr logger.Logger
+ availableDataLen int
+ availableGas uint64
+ expectedNonces map[cciptypes.Address]uint64
+ sendersNonce map[cciptypes.Address]uint64
+ sourceTokenPricesUSD map[cciptypes.Address]*big.Int
+ destTokenPricesUSD map[cciptypes.Address]*big.Int
+ gasPrice *big.Int
+ sourceToDestToken map[cciptypes.Address]cciptypes.Address
+ aggregateTokenLimit *big.Int
+ tokenDataRemainingDuration time.Duration
+ tokenDataWorker tokendata.Worker
+ gasPriceEstimator prices.GasPriceEstimatorExec
+ destWrappedNative cciptypes.Address
+ offchainConfig cciptypes.ExecOffchainConfig
+}
+
+type BatchingStrategy interface {
+ BuildBatch(ctx context.Context, batchCtx *BatchContext) ([]ccip.ObservedMessage, []messageExecStatus)
+}
+
+type BestEffortBatchingStrategy struct{}
+
+type ZKOverflowBatchingStrategy struct {
+ statuschecker statuschecker.CCIPTransactionStatusChecker
+}
+
+func NewBatchingStrategy(batchingStrategyID uint32, statusChecker statuschecker.CCIPTransactionStatusChecker) (BatchingStrategy, error) {
+ var batchingStrategy BatchingStrategy
+ switch batchingStrategyID {
+ case 0:
+ batchingStrategy = &BestEffortBatchingStrategy{}
+ case 1:
+ batchingStrategy = &ZKOverflowBatchingStrategy{
+ statuschecker: statusChecker,
+ }
+ default:
+ return nil, errors.Errorf("unknown batching strategy ID %d", batchingStrategyID)
+ }
+ return batchingStrategy, nil
+}
+
+// BestEffortBatchingStrategy is a batching strategy that tries to batch as many messages as possible (up to certain limits).
+func (s *BestEffortBatchingStrategy) BuildBatch(
+ ctx context.Context,
+ batchCtx *BatchContext,
+) ([]ccip.ObservedMessage, []messageExecStatus) {
+ batchBuilder := newBatchBuildContainer(len(batchCtx.report.sendRequestsWithMeta))
+ for _, msg := range batchCtx.report.sendRequestsWithMeta {
+ msgLggr := batchCtx.lggr.With("messageID", hexutil.Encode(msg.MessageID[:]), "seqNr", msg.SequenceNumber)
+ status, messageMaxGas, tokenData, msgValue, err := performCommonChecks(ctx, batchCtx, msg, msgLggr)
+
+ if err != nil {
+ return []ccip.ObservedMessage{}, []messageExecStatus{}
+ }
+
+ if status.shouldBeSkipped() {
+ batchBuilder.skip(msg, status)
+ continue
+ }
+
+ updateBatchContext(batchCtx, msg, messageMaxGas, msgValue, msgLggr)
+ batchBuilder.addToBatch(msg, tokenData)
+ }
+ return batchBuilder.batch, batchBuilder.statuses
+}
+
+// ZKOverflowBatchingStrategy is a batching strategy for ZK chains overflowing under certain conditions.
+// It is a simple batching strategy that only allows one message to be added to the batch.
+// TXM is used to perform the ZK check: if the message failed the check, it will be skipped.
+func (bs ZKOverflowBatchingStrategy) BuildBatch(
+ ctx context.Context,
+ batchCtx *BatchContext,
+) ([]ccip.ObservedMessage, []messageExecStatus) {
+ batchBuilder := newBatchBuildContainer(len(batchCtx.report.sendRequestsWithMeta))
+ inflightSeqNums := getInflightSeqNums(batchCtx.inflight)
+
+ for _, msg := range batchCtx.report.sendRequestsWithMeta {
+ msgId := hexutil.Encode(msg.MessageID[:])
+ msgLggr := batchCtx.lggr.With("messageID", msgId, "seqNr", msg.SequenceNumber)
+
+ // Check if msg is inflight
+ if exists := inflightSeqNums.Contains(msg.SequenceNumber); exists {
+ // Message is inflight, skip it
+ msgLggr.Infow("Skipping message - already inflight", "message", msgId)
+ batchBuilder.skip(msg, SkippedInflight)
+ continue
+ }
+ // Message is not inflight, continue with checks
+ // Check if the messsage is overflown using TXM
+ statuses, count, err := bs.statuschecker.CheckMessageStatus(ctx, msgId)
+ if err != nil {
+ batchBuilder.skip(msg, TXMCheckError)
+ continue
+ }
+
+ msgLggr.Infow("TXM check result", "statuses", statuses, "count", count)
+
+ if len(statuses) == 0 {
+ // No status found for message = first time we see it
+ msgLggr.Infow("No status found for message - proceeding with checks", "message", msgId)
+ } else {
+ // Status(es) found for message = check if any of them is final to decide if we should add it to the batch
+ hasFatalStatus := false
+ for _, s := range statuses {
+ if s == types.Fatal {
+ msgLggr.Infow("Skipping message - found a fatal TXM status", "message", msgId)
+ batchBuilder.skip(msg, TXMFatalStatus)
+ hasFatalStatus = true
+ break
+ }
+ }
+ if hasFatalStatus {
+ continue
+ }
+ msgLggr.Infow("No fatal status found for message - proceeding with checks", "message", msgId)
+ }
+
+ status, messageMaxGas, tokenData, msgValue, err := performCommonChecks(ctx, batchCtx, msg, msgLggr)
+
+ if err != nil {
+ return []ccip.ObservedMessage{}, []messageExecStatus{}
+ }
+
+ if status.shouldBeSkipped() {
+ batchBuilder.skip(msg, status)
+ continue
+ }
+
+ updateBatchContext(batchCtx, msg, messageMaxGas, msgValue, msgLggr)
+ msgLggr.Infow("Adding message to batch", "message", msgId)
+ batchBuilder.addToBatch(msg, tokenData)
+
+ // Batch size is limited to 1 for ZK Overflow chains
+ break
+ }
+ return batchBuilder.batch, batchBuilder.statuses
+}
+
+func performCommonChecks(
+ ctx context.Context,
+ batchCtx *BatchContext,
+ msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta,
+ msgLggr logger.Logger,
+) (messageStatus, uint64, [][]byte, *big.Int, error) {
+ if msg.Executed {
+ msgLggr.Infow("Skipping message - already executed")
+ return AlreadyExecuted, 0, nil, nil, nil
+ }
+
+ if len(msg.Data) > batchCtx.availableDataLen {
+ msgLggr.Infow("Skipping message - insufficient remaining batch data length", "msgDataLen", len(msg.Data), "availableBatchDataLen", batchCtx.availableDataLen)
+ return InsufficientRemainingBatchDataLength, 0, nil, nil, nil
+ }
+
+ messageMaxGas, err1 := calculateMessageMaxGas(
+ msg.GasLimit,
+ len(batchCtx.report.sendRequestsWithMeta),
+ len(msg.Data),
+ len(msg.TokenAmounts),
+ )
+ if err1 != nil {
+ msgLggr.Errorw("Skipping message - message max gas calculation error", "err", err1)
+ return MessageMaxGasCalcError, 0, nil, nil, nil
+ }
+
+ // Check sufficient gas in batch
+ if batchCtx.availableGas < messageMaxGas {
+ msgLggr.Infow("Skipping message - insufficient remaining batch gas limit", "availableGas", batchCtx.availableGas, "messageMaxGas", messageMaxGas)
+ return InsufficientRemainingBatchGas, 0, nil, nil, nil
+ }
+
+ if _, ok := batchCtx.expectedNonces[msg.Sender]; !ok {
+ nonce, ok1 := batchCtx.sendersNonce[msg.Sender]
+ if !ok1 {
+ msgLggr.Errorw("Skipping message - missing nonce", "sender", msg.Sender)
+ return MissingNonce, 0, nil, nil, nil
+ }
+ batchCtx.expectedNonces[msg.Sender] = nonce + 1
+ }
+
+ // Check expected nonce is valid for sequenced messages.
+ // Sequenced messages have non-zero nonces.
+ if msg.Nonce > 0 && msg.Nonce != batchCtx.expectedNonces[msg.Sender] {
+ msgLggr.Warnw("Skipping message - invalid nonce", "have", msg.Nonce, "want", batchCtx.expectedNonces[msg.Sender])
+ return InvalidNonce, 0, nil, nil, nil
+ }
+
+ msgValue, err1 := aggregateTokenValue(batchCtx.lggr, batchCtx.destTokenPricesUSD, batchCtx.sourceToDestToken, msg.TokenAmounts)
+ if err1 != nil {
+ msgLggr.Errorw("Skipping message - aggregate token value compute error", "err", err1)
+ return AggregateTokenValueComputeError, 0, nil, nil, nil
+ }
+
+ // if token limit is smaller than message value skip message
+ if tokensLeft, hasCapacity := hasEnoughTokens(batchCtx.aggregateTokenLimit, msgValue, batchCtx.inflightAggregateValue); !hasCapacity {
+ msgLggr.Warnw("Skipping message - aggregate token limit exceeded", "aggregateTokenLimit", tokensLeft.String(), "msgValue", msgValue.String())
+ return AggregateTokenLimitExceeded, 0, nil, nil, nil
+ }
+
+ tokenData, elapsed, err1 := getTokenDataWithTimeout(ctx, msg, batchCtx.tokenDataRemainingDuration, batchCtx.tokenDataWorker)
+ batchCtx.tokenDataRemainingDuration -= elapsed
+ if err1 != nil {
+ if errors.Is(err1, tokendata.ErrNotReady) {
+ msgLggr.Warnw("Skipping message - token data not ready", "err", err1)
+ return TokenDataNotReady, 0, nil, nil, nil
+ }
+ msgLggr.Errorw("Skipping message - token data fetch error", "err", err1)
+ return TokenDataFetchError, 0, nil, nil, nil
+ }
+
+ dstWrappedNativePrice, exists := batchCtx.destTokenPricesUSD[batchCtx.destWrappedNative]
+ if !exists {
+ msgLggr.Errorw("Skipping message - token not in destination token prices", "token", batchCtx.destWrappedNative)
+ return TokenNotInDestTokenPrices, 0, nil, nil, nil
+ }
+
+ // calculating the source chain fee, dividing by 1e18 for denomination.
+ // For example:
+ // FeeToken=link; FeeTokenAmount=1e17 i.e. 0.1 link, price is 6e18 USD/link (1 USD = 1e18),
+ // availableFee is 1e17*6e18/1e18 = 6e17 = 0.6 USD
+ sourceFeeTokenPrice, exists := batchCtx.sourceTokenPricesUSD[msg.FeeToken]
+ if !exists {
+ msgLggr.Errorw("Skipping message - token not in source token prices", "token", msg.FeeToken)
+ return TokenNotInSrcTokenPrices, 0, nil, nil, nil
+ }
+
+ // Fee boosting
+ execCostUsd, err1 := batchCtx.gasPriceEstimator.EstimateMsgCostUSD(batchCtx.gasPrice, dstWrappedNativePrice, msg)
+ if err1 != nil {
+ msgLggr.Errorw("Failed to estimate message cost USD", "err", err1)
+ return "", 0, nil, nil, errors.New("failed to estimate message cost USD")
+ }
+
+ availableFee := big.NewInt(0).Mul(msg.FeeTokenAmount, sourceFeeTokenPrice)
+ availableFee = availableFee.Div(availableFee, big.NewInt(1e18))
+ availableFeeUsd := waitBoostedFee(time.Since(msg.BlockTimestamp), availableFee, batchCtx.offchainConfig.RelativeBoostPerWaitHour)
+ if availableFeeUsd.Cmp(execCostUsd) < 0 {
+ msgLggr.Infow(
+ "Skipping message - insufficient remaining fee",
+ "availableFeeUsd", availableFeeUsd,
+ "execCostUsd", execCostUsd,
+ "sourceBlockTimestamp", msg.BlockTimestamp,
+ "waitTime", time.Since(msg.BlockTimestamp),
+ "boost", batchCtx.offchainConfig.RelativeBoostPerWaitHour,
+ )
+ return InsufficientRemainingFee, 0, nil, nil, nil
+ }
+
+ return SuccesfullyValidated, messageMaxGas, tokenData, msgValue, nil
+}
+
+// getTokenDataWithCappedLatency gets the token data for the provided message.
+// Stops and returns an error if more than allowedWaitingTime is passed.
+func getTokenDataWithTimeout(
+ ctx context.Context,
+ msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta,
+ timeout time.Duration,
+ tokenDataWorker tokendata.Worker,
+) ([][]byte, time.Duration, error) {
+ if len(msg.TokenAmounts) == 0 {
+ return nil, 0, nil
+ }
+
+ ctxTimeout, cf := context.WithTimeout(ctx, timeout)
+ defer cf()
+ tStart := time.Now()
+ tokenData, err := tokenDataWorker.GetMsgTokenData(ctxTimeout, msg)
+ tDur := time.Since(tStart)
+ return tokenData, tDur, err
+}
+
+func getProofData(
+ ctx context.Context,
+ sourceReader ccipdata.OnRampReader,
+ interval cciptypes.CommitStoreInterval,
+) (sendReqsInRoot []cciptypes.EVM2EVMMessageWithTxMeta, leaves [][32]byte, tree *merklemulti.Tree[[32]byte], err error) {
+ // We don't need to double-check if logs are finalized because we already checked that in the Commit phase.
+ sendReqs, err := sourceReader.GetSendRequestsBetweenSeqNums(ctx, interval.Min, interval.Max, false)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ if err1 := validateSendRequests(sendReqs, interval); err1 != nil {
+ return nil, nil, nil, err1
+ }
+
+ leaves = make([][32]byte, 0, len(sendReqs))
+ for _, req := range sendReqs {
+ leaves = append(leaves, req.Hash)
+ }
+ tree, err = merklemulti.NewTree(hashutil.NewKeccak(), leaves)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ return sendReqs, leaves, tree, nil
+}
+
+func validateSendRequests(sendReqs []cciptypes.EVM2EVMMessageWithTxMeta, interval cciptypes.CommitStoreInterval) error {
+ if len(sendReqs) == 0 {
+ return fmt.Errorf("could not find any requests in the provided interval %v", interval)
+ }
+
+ gotInterval := cciptypes.CommitStoreInterval{
+ Min: sendReqs[0].SequenceNumber,
+ Max: sendReqs[0].SequenceNumber,
+ }
+
+ for _, req := range sendReqs[1:] {
+ if req.SequenceNumber < gotInterval.Min {
+ gotInterval.Min = req.SequenceNumber
+ }
+ if req.SequenceNumber > gotInterval.Max {
+ gotInterval.Max = req.SequenceNumber
+ }
+ }
+
+ if (gotInterval.Min != interval.Min) || (gotInterval.Max != interval.Max) {
+ return fmt.Errorf("interval %v is not the expected %v", gotInterval, interval)
+ }
+ return nil
+}
+
+func getInflightSeqNums(inflight []InflightInternalExecutionReport) mapset.Set[uint64] {
+ seqNums := mapset.NewSet[uint64]()
+ for _, report := range inflight {
+ for _, msg := range report.messages {
+ seqNums.Add(msg.SequenceNumber)
+ }
+ }
+ return seqNums
+}
+
+func aggregateTokenValue(lggr logger.Logger, destTokenPricesUSD map[cciptypes.Address]*big.Int, sourceToDest map[cciptypes.Address]cciptypes.Address, tokensAndAmount []cciptypes.TokenAmount) (*big.Int, error) {
+ sum := big.NewInt(0)
+ for i := 0; i < len(tokensAndAmount); i++ {
+ price, ok := destTokenPricesUSD[sourceToDest[tokensAndAmount[i].Token]]
+ if !ok {
+ // If we don't have a price for the token, we will assume it's worth 0.
+ lggr.Infof("No price for token %s, assuming 0", tokensAndAmount[i].Token)
+ continue
+ }
+ sum.Add(sum, new(big.Int).Quo(new(big.Int).Mul(price, tokensAndAmount[i].Amount), big.NewInt(1e18)))
+ }
+ return sum, nil
+}
+
+func updateBatchContext(
+ batchCtx *BatchContext,
+ msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta,
+ messageMaxGas uint64,
+ msgValue *big.Int,
+ msgLggr logger.Logger) {
+ batchCtx.availableGas -= messageMaxGas
+ batchCtx.availableDataLen -= len(msg.Data)
+ batchCtx.aggregateTokenLimit.Sub(batchCtx.aggregateTokenLimit, msgValue)
+ if msg.Nonce > 0 {
+ batchCtx.expectedNonces[msg.Sender] = msg.Nonce + 1
+ }
+
+ msgLggr.Infow(
+ "Message successfully added to execution batch",
+ "nonce", msg.Nonce,
+ "sender", msg.Sender,
+ "value", msgValue,
+ "availableAggrTokenLimit", batchCtx.aggregateTokenLimit,
+ "availableGas", batchCtx.availableGas,
+ "availableDataLen", batchCtx.availableDataLen,
+ )
+}
+
+func hasEnoughTokens(tokenLimit *big.Int, msgValue *big.Int, inflightValue *big.Int) (*big.Int, bool) {
+ tokensLeft := big.NewInt(0).Sub(tokenLimit, inflightValue)
+ return tokensLeft, tokensLeft.Cmp(msgValue) >= 0
+}
+
+func buildExecutionReportForMessages(
+ msgsInRoot []cciptypes.EVM2EVMMessageWithTxMeta,
+ tree *merklemulti.Tree[[32]byte],
+ commitInterval cciptypes.CommitStoreInterval,
+ observedMessages []ccip.ObservedMessage,
+) (cciptypes.ExecReport, error) {
+ innerIdxs := make([]int, 0, len(observedMessages))
+ var messages []cciptypes.EVM2EVMMessage
+ var offchainTokenData [][][]byte
+ for _, observedMessage := range observedMessages {
+ if observedMessage.SeqNr < commitInterval.Min || observedMessage.SeqNr > commitInterval.Max {
+ // We only return messages from a single root (the root of the first message).
+ continue
+ }
+ innerIdx := int(observedMessage.SeqNr - commitInterval.Min)
+ if innerIdx >= len(msgsInRoot) || innerIdx < 0 {
+ return cciptypes.ExecReport{}, fmt.Errorf("invalid inneridx SeqNr=%d IntervalMin=%d msgsInRoot=%d",
+ observedMessage.SeqNr, commitInterval.Min, len(msgsInRoot))
+ }
+ messages = append(messages, msgsInRoot[innerIdx].EVM2EVMMessage)
+ offchainTokenData = append(offchainTokenData, observedMessage.TokenData)
+ innerIdxs = append(innerIdxs, innerIdx)
+ }
+
+ merkleProof, err := tree.Prove(innerIdxs)
+ if err != nil {
+ return cciptypes.ExecReport{}, err
+ }
+
+ // any capped proof will have length <= this one, so we reuse it to avoid proving inside loop, and update later if changed
+ return cciptypes.ExecReport{
+ Messages: messages,
+ Proofs: merkleProof.Hashes,
+ ProofFlagBits: abihelpers.ProofFlagsToBits(merkleProof.SourceFlags),
+ OffchainTokenData: offchainTokenData,
+ }, nil
+}
+
+// Validates the given message observations do not exceed the committed sequence numbers
+// in the commitStoreReader.
+func validateSeqNumbers(serviceCtx context.Context, commitStore ccipdata.CommitStoreReader, observedMessages []ccip.ObservedMessage) error {
+ nextMin, err := commitStore.GetExpectedNextSequenceNumber(serviceCtx)
+ if err != nil {
+ return err
+ }
+ // observedMessages are always sorted by SeqNr and never empty, so it's safe to take last element
+ maxSeqNumInBatch := observedMessages[len(observedMessages)-1].SeqNr
+
+ if maxSeqNumInBatch >= nextMin {
+ return errors.Errorf("Cannot execute uncommitted seq num. nextMin %v, seqNums %v", nextMin, observedMessages)
+ }
+ return nil
+}
+
+// Gets the commit report from the saved logs for a given sequence number.
+func getCommitReportForSeqNum(ctx context.Context, commitStoreReader ccipdata.CommitStoreReader, seqNum uint64) (cciptypes.CommitStoreReport, error) {
+ acceptedReports, err := commitStoreReader.GetCommitReportMatchingSeqNum(ctx, seqNum, 0)
+ if err != nil {
+ return cciptypes.CommitStoreReport{}, err
+ }
+
+ if len(acceptedReports) == 0 {
+ return cciptypes.CommitStoreReport{}, errors.Errorf("seq number not committed")
+ }
+
+ return acceptedReports[0].CommitStoreReport, nil
+}
+
+type messageStatus string
+
+const (
+ SuccesfullyValidated messageStatus = "successfully_validated"
+ AlreadyExecuted messageStatus = "already_executed"
+ SenderAlreadySkipped messageStatus = "sender_already_skipped"
+ MessageMaxGasCalcError messageStatus = "message_max_gas_calc_error"
+ InsufficientRemainingBatchDataLength messageStatus = "insufficient_remaining_batch_data_length"
+ InsufficientRemainingBatchGas messageStatus = "insufficient_remaining_batch_gas"
+ MissingNonce messageStatus = "missing_nonce"
+ InvalidNonce messageStatus = "invalid_nonce"
+ AggregateTokenValueComputeError messageStatus = "aggregate_token_value_compute_error"
+ AggregateTokenLimitExceeded messageStatus = "aggregate_token_limit_exceeded"
+ TokenDataNotReady messageStatus = "token_data_not_ready"
+ TokenDataFetchError messageStatus = "token_data_fetch_error"
+ TokenNotInDestTokenPrices messageStatus = "token_not_in_dest_token_prices"
+ TokenNotInSrcTokenPrices messageStatus = "token_not_in_src_token_prices"
+ InsufficientRemainingFee messageStatus = "insufficient_remaining_fee"
+ AddedToBatch messageStatus = "added_to_batch"
+ TXMCheckError messageStatus = "txm_check_error"
+ TXMFatalStatus messageStatus = "txm_fatal_status"
+ SkippedInflight messageStatus = "skipped_inflight"
+)
+
+func (m messageStatus) shouldBeSkipped() bool {
+ return m != SuccesfullyValidated
+}
+
+type messageExecStatus struct {
+ SeqNr uint64
+ MessageId string
+ Status messageStatus
+}
+
+func newMessageExecState(seqNr uint64, messageId cciptypes.Hash, status messageStatus) messageExecStatus {
+ return messageExecStatus{
+ SeqNr: seqNr,
+ MessageId: hexutil.Encode(messageId[:]),
+ Status: status,
+ }
+}
+
+type batchBuildContainer struct {
+ batch []ccip.ObservedMessage
+ statuses []messageExecStatus
+}
+
+func newBatchBuildContainer(capacity int) *batchBuildContainer {
+ return &batchBuildContainer{
+ batch: make([]ccip.ObservedMessage, 0, capacity),
+ statuses: make([]messageExecStatus, 0, capacity),
+ }
+}
+
+func (m *batchBuildContainer) skip(msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, status messageStatus) {
+ m.addState(msg, status)
+}
+
+func (m *batchBuildContainer) addToBatch(msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenData [][]byte) {
+ m.addState(msg, AddedToBatch)
+ m.batch = append(m.batch, ccip.NewObservedMessage(msg.SequenceNumber, tokenData))
+}
+
+func (m *batchBuildContainer) addState(msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, state messageStatus) {
+ m.statuses = append(m.statuses, newMessageExecState(msg.SequenceNumber, msg.MessageID, state))
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/batching_test.go b/core/services/ocr2/plugins/ccip/ccipexec/batching_test.go
new file mode 100644
index 00000000000..3647556a6d5
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/batching_test.go
@@ -0,0 +1,910 @@
+package ccipexec
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "math"
+ "math/big"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/pkg/errors"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+ mockstatuschecker "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/statuschecker/mocks"
+)
+
+type testCase struct {
+ name string
+ reqs []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta
+ inflight []InflightInternalExecutionReport
+ tokenLimit, destGasPrice, inflightAggregateValue *big.Int
+ srcPrices, dstPrices map[cciptypes.Address]*big.Int
+ offRampNoncesBySender map[cciptypes.Address]uint64
+ srcToDestTokens map[cciptypes.Address]cciptypes.Address
+ expectedSeqNrs []ccip.ObservedMessage
+ expectedStates []messageExecStatus
+ statuschecker func(m *mockstatuschecker.CCIPTransactionStatusChecker)
+ skipGasPriceEstimator bool
+}
+
+func Test_NewBatchingStrategy(t *testing.T) {
+ t.Parallel()
+
+ mockStatusChecker := mockstatuschecker.NewCCIPTransactionStatusChecker(t)
+
+ testCases := []int{0, 1, 2}
+
+ for _, batchingStrategyId := range testCases {
+ factory, err := NewBatchingStrategy(uint32(batchingStrategyId), mockStatusChecker)
+ if batchingStrategyId == 2 {
+ assert.Error(t, err)
+ } else {
+ assert.NotNil(t, factory)
+ assert.NoError(t, err)
+ }
+ }
+}
+
+func Test_validateSendRequests(t *testing.T) {
+ testCases := []struct {
+ name string
+ seqNums []uint64
+ providedInterval cciptypes.CommitStoreInterval
+ expErr bool
+ }{
+ {
+ name: "zero interval no seq nums",
+ seqNums: nil,
+ providedInterval: cciptypes.CommitStoreInterval{Min: 0, Max: 0},
+ expErr: true,
+ },
+ {
+ name: "exp 1 seq num got none",
+ seqNums: nil,
+ providedInterval: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ expErr: true,
+ },
+ {
+ name: "exp 10 seq num got none",
+ seqNums: nil,
+ providedInterval: cciptypes.CommitStoreInterval{Min: 1, Max: 10},
+ expErr: true,
+ },
+ {
+ name: "got 1 seq num as expected",
+ seqNums: []uint64{1},
+ providedInterval: cciptypes.CommitStoreInterval{Min: 1, Max: 1},
+ expErr: false,
+ },
+ {
+ name: "got 5 seq num as expected",
+ seqNums: []uint64{11, 12, 13, 14, 15},
+ providedInterval: cciptypes.CommitStoreInterval{Min: 11, Max: 15},
+ expErr: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ sendReqs := make([]cciptypes.EVM2EVMMessageWithTxMeta, 0, len(tc.seqNums))
+ for _, seqNum := range tc.seqNums {
+ sendReqs = append(sendReqs, cciptypes.EVM2EVMMessageWithTxMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: seqNum},
+ })
+ }
+ err := validateSendRequests(sendReqs, tc.providedInterval)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ })
+ }
+}
+
+type delayedTokenDataWorker struct {
+ delay time.Duration
+ tokendata.Worker
+}
+
+func (m delayedTokenDataWorker) GetMsgTokenData(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) ([][]byte, error) {
+ time.Sleep(m.delay)
+ return nil, ctx.Err()
+}
+
+func TestExecutionReportingPlugin_getTokenDataWithCappedLatency(t *testing.T) {
+ testCases := []struct {
+ name string
+ allowedWaitingTime time.Duration
+ workerLatency time.Duration
+ expErr bool
+ }{
+ {
+ name: "happy flow",
+ allowedWaitingTime: 10 * time.Millisecond,
+ workerLatency: time.Nanosecond,
+ expErr: false,
+ },
+ {
+ name: "worker takes long to reply",
+ allowedWaitingTime: 10 * time.Millisecond,
+ workerLatency: 20 * time.Millisecond,
+ expErr: true,
+ },
+ }
+
+ ctx := testutils.Context(t)
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ tokenDataWorker := delayedTokenDataWorker{delay: tc.workerLatency}
+
+ msg := cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{TokenAmounts: make([]cciptypes.TokenAmount, 1)},
+ }
+
+ _, _, err := getTokenDataWithTimeout(ctx, msg, tc.allowedWaitingTime, tokenDataWorker)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ })
+ }
+}
+
+func TestBatchingStrategies(t *testing.T) {
+ sender1 := ccipcalc.HexToAddress("0xa")
+ destNative := ccipcalc.HexToAddress("0xb")
+ srcNative := ccipcalc.HexToAddress("0xc")
+
+ msg1 := createTestMessage(1, sender1, 1, srcNative, big.NewInt(1e9), false, nil)
+
+ msg2 := msg1
+ msg2.Executed = true
+
+ msg3 := msg1
+ msg3.Executed = true
+ msg3.Finalized = true
+
+ msg4 := msg1
+ msg4.TokenAmounts = []cciptypes.TokenAmount{
+ {Token: srcNative, Amount: big.NewInt(100)},
+ }
+
+ msg5 := msg4
+ msg5.SequenceNumber = msg5.SequenceNumber + 1
+ msg5.Nonce = msg5.Nonce + 1
+
+ zkMsg1 := createTestMessage(1, sender1, 0, srcNative, big.NewInt(1e9), false, nil)
+ zkMsg2 := createTestMessage(2, sender1, 0, srcNative, big.NewInt(1e9), false, nil)
+ zkMsg3 := createTestMessage(3, sender1, 0, srcNative, big.NewInt(1e9), false, nil)
+ zkMsg4 := createTestMessage(4, sender1, 0, srcNative, big.NewInt(1e9), false, nil)
+
+ testCases := []testCase{
+ {
+ name: "single message no tokens",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: uint64(1)}},
+ expectedStates: []messageExecStatus{newMessageExecState(msg1.SequenceNumber, msg1.MessageID, AddedToBatch)},
+ },
+ {
+ name: "gasPriceEstimator returns error",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ },
+ {
+ name: "executed non finalized messages should be skipped",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg2},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{newMessageExecState(msg2.SequenceNumber, msg2.MessageID, AlreadyExecuted)},
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "finalized executed log",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg3},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{newMessageExecState(msg3.SequenceNumber, msg3.MessageID, AlreadyExecuted)},
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "dst token price does not exist",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{newMessageExecState(msg1.SequenceNumber, msg1.MessageID, TokenNotInDestTokenPrices)},
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "src token price does not exist",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{newMessageExecState(msg1.SequenceNumber, msg1.MessageID, TokenNotInSrcTokenPrices)},
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "message with tokens is not executed if limit is reached",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg4},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(99),
+ destGasPrice: big.NewInt(1),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1e18)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1e18)},
+ srcToDestTokens: map[cciptypes.Address]cciptypes.Address{
+ srcNative: destNative,
+ },
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{newMessageExecState(msg4.SequenceNumber, msg4.MessageID, AggregateTokenLimitExceeded)},
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "message with tokens is not executed if limit is reached when inflight is full",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg5},
+ inflight: []InflightInternalExecutionReport{{createdAt: time.Now(), messages: []cciptypes.EVM2EVMMessage{msg4.EVM2EVMMessage}}},
+ inflightAggregateValue: big.NewInt(100),
+ tokenLimit: big.NewInt(50),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1e18)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1e18)},
+ srcToDestTokens: map[cciptypes.Address]cciptypes.Address{
+ srcNative: destNative,
+ },
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 1},
+ expectedStates: []messageExecStatus{newMessageExecState(msg5.SequenceNumber, msg5.MessageID, AggregateTokenLimitExceeded)},
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "skip when nonce doesn't match chain value",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 123},
+ expectedStates: []messageExecStatus{newMessageExecState(msg1.SequenceNumber, msg1.MessageID, InvalidNonce)},
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "skip when nonce not found",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{msg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{},
+ expectedStates: []messageExecStatus{newMessageExecState(msg1.SequenceNumber, msg1.MessageID, MissingNonce)},
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "unordered messages",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 10,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 0,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ },
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: uint64(10)}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(10, [32]byte{}, AddedToBatch),
+ },
+ },
+ {
+ name: "unordered messages not blocked by nonce",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 9,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 5,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 10,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 0,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ },
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 3},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: uint64(10)}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(9, [32]byte{}, InvalidNonce),
+ newMessageExecState(10, [32]byte{}, AddedToBatch),
+ },
+ },
+ }
+
+ bestEffortTestCases := []testCase{
+ {
+ name: "skip when batch gas limit is reached",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 10,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 1,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 11,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 2,
+ GasLimit: big.NewInt(math.MaxInt64),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 12,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 3,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ },
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: uint64(10)}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(10, [32]byte{}, AddedToBatch),
+ newMessageExecState(11, [32]byte{}, InsufficientRemainingBatchGas),
+ newMessageExecState(12, [32]byte{}, InvalidNonce),
+ },
+ },
+ {
+ name: "some messages skipped after hitting max batch data len",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 10,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 1,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 11,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 2,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, MaxDataLenPerBatch-500), // skipped from batch
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 12,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 3,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ },
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: uint64(10)}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(10, [32]byte{}, AddedToBatch),
+ newMessageExecState(11, [32]byte{}, InsufficientRemainingBatchDataLength),
+ newMessageExecState(12, [32]byte{}, InvalidNonce),
+ },
+ },
+ {
+ name: "unordered messages then ordered messages",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 9,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 0,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: 10,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: sender1,
+ Nonce: 5,
+ GasLimit: big.NewInt(1),
+ Data: bytes.Repeat([]byte{'a'}, 1000),
+ FeeToken: srcNative,
+ MessageID: [32]byte{},
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ },
+ },
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 4},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: uint64(9)}, {SeqNr: uint64(10)}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(9, [32]byte{}, AddedToBatch),
+ newMessageExecState(10, [32]byte{}, AddedToBatch),
+ },
+ },
+ }
+
+ specificZkOverflowTestCases := []testCase{
+ {
+ name: "batch size is 1",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1, zkMsg2, zkMsg3},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: zkMsg1.SequenceNumber}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, AddedToBatch),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, mock.Anything).Return([]types.TransactionStatus{}, -1, nil)
+ },
+ },
+ {
+ name: "snooze fatal message and return empty batch",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, TXMFatalStatus),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg1.MessageID.String()).Return([]types.TransactionStatus{types.Fatal}, 0, nil)
+ },
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "snooze fatal message and add next message to batch",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1, zkMsg2},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: zkMsg2.SequenceNumber}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, TXMFatalStatus),
+ newMessageExecState(zkMsg2.SequenceNumber, zkMsg2.MessageID, AddedToBatch),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg1.MessageID.String()).Return([]types.TransactionStatus{types.Fatal}, 0, nil)
+ m.On("CheckMessageStatus", mock.Anything, zkMsg2.MessageID.String()).Return([]types.TransactionStatus{}, -1, nil)
+ },
+ },
+ {
+ name: "all messages are fatal and batch is empty",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1, zkMsg2},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, TXMFatalStatus),
+ newMessageExecState(zkMsg2.SequenceNumber, zkMsg2.MessageID, TXMFatalStatus),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg1.MessageID.String()).Return([]types.TransactionStatus{types.Fatal}, 0, nil)
+ m.On("CheckMessageStatus", mock.Anything, zkMsg2.MessageID.String()).Return([]types.TransactionStatus{types.Fatal}, 0, nil)
+ },
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "message batched when unconfirmed or failed",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1, zkMsg2},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: zkMsg1.SequenceNumber}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, AddedToBatch),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg1.MessageID.String()).Return([]types.TransactionStatus{types.Unconfirmed, types.Failed}, 1, nil)
+ },
+ },
+ {
+ name: "message snoozed when multiple statuses with fatal",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1, zkMsg2},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: zkMsg2.SequenceNumber}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, TXMFatalStatus),
+ newMessageExecState(zkMsg2.SequenceNumber, zkMsg2.MessageID, AddedToBatch),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg1.MessageID.String()).Return([]types.TransactionStatus{types.Unconfirmed, types.Failed, types.Fatal}, 2, nil)
+ m.On("CheckMessageStatus", mock.Anything, zkMsg2.MessageID.String()).Return([]types.TransactionStatus{}, -1, nil)
+ },
+ },
+ {
+ name: "txm return error for message",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1, zkMsg2},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: zkMsg2.SequenceNumber}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, TXMCheckError),
+ newMessageExecState(zkMsg2.SequenceNumber, zkMsg2.MessageID, AddedToBatch),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg1.MessageID.String()).Return([]types.TransactionStatus{}, -1, errors.New("dummy txm error"))
+ m.On("CheckMessageStatus", mock.Anything, zkMsg2.MessageID.String()).Return([]types.TransactionStatus{}, -1, nil)
+ },
+ },
+ {
+ name: "snooze message when inflight",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1},
+ inflight: createInflight(zkMsg1),
+ inflightAggregateValue: zkMsg1.FeeTokenAmount,
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, SkippedInflight),
+ },
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "snooze when not inflight but txm returns error",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, TXMCheckError),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg1.MessageID.String()).Return([]types.TransactionStatus{}, -1, errors.New("dummy txm error"))
+ },
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "snooze when not inflight but txm returns fatal status",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1},
+ inflight: []InflightInternalExecutionReport{},
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, TXMFatalStatus),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg1.MessageID.String()).Return([]types.TransactionStatus{types.Unconfirmed, types.Failed, types.Fatal}, 2, nil)
+ },
+ skipGasPriceEstimator: true,
+ },
+ {
+ name: "snooze messages when inflight but batch valid messages",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{zkMsg1, zkMsg2, zkMsg3, zkMsg4},
+ inflight: createInflight(zkMsg1, zkMsg2),
+ inflightAggregateValue: big.NewInt(0),
+ tokenLimit: big.NewInt(0),
+ destGasPrice: big.NewInt(10),
+ srcPrices: map[cciptypes.Address]*big.Int{srcNative: big.NewInt(1)},
+ dstPrices: map[cciptypes.Address]*big.Int{destNative: big.NewInt(1)},
+ offRampNoncesBySender: map[cciptypes.Address]uint64{sender1: 0},
+ expectedSeqNrs: []ccip.ObservedMessage{{SeqNr: zkMsg3.SequenceNumber}},
+ expectedStates: []messageExecStatus{
+ newMessageExecState(zkMsg1.SequenceNumber, zkMsg1.MessageID, SkippedInflight),
+ newMessageExecState(zkMsg2.SequenceNumber, zkMsg2.MessageID, SkippedInflight),
+ newMessageExecState(zkMsg3.SequenceNumber, zkMsg3.MessageID, AddedToBatch),
+ },
+ statuschecker: func(m *mockstatuschecker.CCIPTransactionStatusChecker) {
+ m.Mock = mock.Mock{} // reset mock
+ m.On("CheckMessageStatus", mock.Anything, zkMsg3.MessageID.String()).Return([]types.TransactionStatus{}, -1, nil)
+ },
+ skipGasPriceEstimator: false,
+ },
+ }
+
+ t.Run("BestEffortBatchingStrategy", func(t *testing.T) {
+ strategy := &BestEffortBatchingStrategy{}
+ runBatchingStrategyTests(t, strategy, 1_000_000, append(testCases, bestEffortTestCases...))
+ })
+
+ t.Run("ZKOverflowBatchingStrategy", func(t *testing.T) {
+ mockedStatusChecker := mockstatuschecker.NewCCIPTransactionStatusChecker(t)
+ strategy := &ZKOverflowBatchingStrategy{
+ statuschecker: mockedStatusChecker,
+ }
+ runBatchingStrategyTests(t, strategy, 1_000_000, append(testCases, specificZkOverflowTestCases...))
+ })
+}
+
+// Function to set up and run tests for a given batching strategy
+func runBatchingStrategyTests(t *testing.T, strategy BatchingStrategy, availableGas uint64, testCases []testCase) {
+ destNative := ccipcalc.HexToAddress("0xb")
+
+ for _, tc := range testCases {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ lggr := logger.TestLogger(t)
+
+ gasPriceEstimator := prices.NewMockGasPriceEstimatorExec(t)
+ if !tc.skipGasPriceEstimator {
+ if tc.expectedSeqNrs != nil {
+ gasPriceEstimator.On("EstimateMsgCostUSD", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(0), nil)
+ } else {
+ gasPriceEstimator.On("EstimateMsgCostUSD", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(0), errors.New("error"))
+ }
+ }
+
+ // default case for ZKOverflowBatchingStrategy
+ if strategyType := reflect.TypeOf(strategy); tc.statuschecker == nil && strategyType == reflect.TypeOf(&ZKOverflowBatchingStrategy{}) {
+ strategy.(*ZKOverflowBatchingStrategy).statuschecker.(*mockstatuschecker.CCIPTransactionStatusChecker).On("CheckMessageStatus", mock.Anything, mock.Anything).Return([]types.TransactionStatus{}, -1, nil)
+ }
+
+ // Mock calls to TXM
+ if tc.statuschecker != nil {
+ tc.statuschecker(strategy.(*ZKOverflowBatchingStrategy).statuschecker.(*mockstatuschecker.CCIPTransactionStatusChecker))
+ }
+
+ batchContext := &BatchContext{
+ report: commitReportWithSendRequests{sendRequestsWithMeta: tc.reqs},
+ inflight: tc.inflight,
+ inflightAggregateValue: tc.inflightAggregateValue,
+ lggr: lggr,
+ availableDataLen: MaxDataLenPerBatch,
+ availableGas: availableGas,
+ expectedNonces: make(map[cciptypes.Address]uint64),
+ sendersNonce: tc.offRampNoncesBySender,
+ sourceTokenPricesUSD: tc.srcPrices,
+ destTokenPricesUSD: tc.dstPrices,
+ gasPrice: tc.destGasPrice,
+ sourceToDestToken: tc.srcToDestTokens,
+ aggregateTokenLimit: tc.tokenLimit,
+ tokenDataRemainingDuration: 5 * time.Second,
+ tokenDataWorker: tokendata.NewBackgroundWorker(map[cciptypes.Address]tokendata.Reader{}, 10, 5*time.Second, time.Hour),
+ gasPriceEstimator: gasPriceEstimator,
+ destWrappedNative: destNative,
+ offchainConfig: cciptypes.ExecOffchainConfig{
+ DestOptimisticConfirmations: 1,
+ BatchGasLimit: 300_000,
+ RelativeBoostPerWaitHour: 1,
+ },
+ }
+
+ seqNrs, execStates := strategy.BuildBatch(context.Background(), batchContext)
+
+ runAssertions(t, tc, seqNrs, execStates)
+ })
+ }
+}
+
+// Utility function to run common assertions
+func runAssertions(t *testing.T, tc testCase, seqNrs []ccip.ObservedMessage, execStates []messageExecStatus) {
+ if tc.expectedSeqNrs == nil {
+ assert.Len(t, seqNrs, 0)
+ } else {
+ assert.Equal(t, tc.expectedSeqNrs, seqNrs)
+ }
+
+ if tc.expectedStates == nil {
+ assert.Len(t, execStates, 0)
+ } else {
+ assert.Equal(t, tc.expectedStates, execStates)
+ }
+}
+
+func createTestMessage(seqNr uint64, sender cciptypes.Address, nonce uint64, feeToken cciptypes.Address, feeAmount *big.Int, executed bool, data []byte) cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta {
+ return cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: seqNr,
+ FeeTokenAmount: feeAmount,
+ Sender: sender,
+ Nonce: nonce,
+ GasLimit: big.NewInt(1),
+ Strict: false,
+ Receiver: "",
+ Data: data,
+ TokenAmounts: nil,
+ FeeToken: feeToken,
+ MessageID: generateMessageIDFromInt(seqNr),
+ },
+ BlockTimestamp: time.Date(2010, 1, 1, 12, 12, 12, 0, time.UTC),
+ Executed: executed,
+ }
+}
+
+func generateMessageIDFromInt(input uint64) [32]byte {
+ var messageID [32]byte
+ binary.LittleEndian.PutUint32(messageID[:], uint32(input))
+ return messageID
+}
+
+func createInflight(msgs ...cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) []InflightInternalExecutionReport {
+ reports := make([]InflightInternalExecutionReport, len(msgs))
+
+ for i, msg := range msgs {
+ reports[i] = InflightInternalExecutionReport{
+ messages: []cciptypes.EVM2EVMMessage{msg.EVM2EVMMessage},
+ createdAt: msg.BlockTimestamp,
+ }
+ }
+
+ return reports
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/factory.go b/core/services/ocr2/plugins/ccip/ccipexec/factory.go
new file mode 100644
index 00000000000..97caf2e719c
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/factory.go
@@ -0,0 +1,164 @@
+package ccipexec
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+type ExecutionReportingPluginFactory struct {
+ // Config derived from job specs and does not change between instances.
+ config ExecutionPluginStaticConfig
+
+ destPriceRegReader ccipdata.PriceRegistryReader
+ destPriceRegAddr cciptypes.Address
+ readersMu *sync.Mutex
+}
+
+func NewExecutionReportingPluginFactory(config ExecutionPluginStaticConfig) *ExecutionReportingPluginFactory {
+ return &ExecutionReportingPluginFactory{
+ config: config,
+ readersMu: &sync.Mutex{},
+
+ // the fields below are initially empty and populated on demand
+ destPriceRegReader: nil,
+ destPriceRegAddr: "",
+ }
+}
+
+func (rf *ExecutionReportingPluginFactory) UpdateDynamicReaders(ctx context.Context, newPriceRegAddr cciptypes.Address) error {
+ rf.readersMu.Lock()
+ defer rf.readersMu.Unlock()
+ // TODO: Investigate use of Close() to cleanup.
+ // TODO: a true price registry upgrade on an existing lane may want some kind of start block in its config? Right now we
+ // essentially assume that plugins don't care about historical price reg logs.
+ if rf.destPriceRegAddr == newPriceRegAddr {
+ // No-op
+ return nil
+ }
+ // Close old reader (if present) and open new reader if address changed.
+ if rf.destPriceRegReader != nil {
+ if err := rf.destPriceRegReader.Close(); err != nil {
+ return err
+ }
+ }
+
+ destPriceRegistryReader, err := rf.config.priceRegistryProvider.NewPriceRegistryReader(context.Background(), newPriceRegAddr)
+ if err != nil {
+ return err
+ }
+ rf.destPriceRegReader = destPriceRegistryReader
+ rf.destPriceRegAddr = newPriceRegAddr
+ return nil
+}
+
+type reportingPluginAndInfo struct {
+ plugin types.ReportingPlugin
+ pluginInfo types.ReportingPluginInfo
+}
+
+// NewReportingPlugin registers a new ReportingPlugin
+func (rf *ExecutionReportingPluginFactory) NewReportingPlugin(config types.ReportingPluginConfig) (types.ReportingPlugin, types.ReportingPluginInfo, error) {
+ initialRetryDelay := rf.config.newReportingPluginRetryConfig.InitialDelay
+ maxDelay := rf.config.newReportingPluginRetryConfig.MaxDelay
+
+ pluginAndInfo, err := ccipcommon.RetryUntilSuccess(rf.NewReportingPluginFn(config), initialRetryDelay, maxDelay)
+ if err != nil {
+ return nil, types.ReportingPluginInfo{}, err
+ }
+ return pluginAndInfo.plugin, pluginAndInfo.pluginInfo, err
+}
+
+// NewReportingPluginFn implements the NewReportingPlugin logic. It is defined as a function so that it can easily be
+// retried via RetryUntilSuccess. NewReportingPlugin must return successfully in order for the Exec plugin to function,
+// hence why we can only keep retrying it until it succeeds.
+func (rf *ExecutionReportingPluginFactory) NewReportingPluginFn(config types.ReportingPluginConfig) func() (reportingPluginAndInfo, error) {
+ return func() (reportingPluginAndInfo, error) {
+ ctx := context.Background() // todo: consider setting a timeout
+
+ destPriceRegistry, destWrappedNative, err := rf.config.offRampReader.ChangeConfig(ctx, config.OnchainConfig, config.OffchainConfig)
+ if err != nil {
+ return reportingPluginAndInfo{}, err
+ }
+
+ // Open dynamic readers
+ err = rf.UpdateDynamicReaders(ctx, destPriceRegistry)
+ if err != nil {
+ return reportingPluginAndInfo{}, err
+ }
+
+ offchainConfig, err := rf.config.offRampReader.OffchainConfig(ctx)
+ if err != nil {
+ return reportingPluginAndInfo{}, fmt.Errorf("get offchain config from offramp: %w", err)
+ }
+
+ gasPriceEstimator, err := rf.config.offRampReader.GasPriceEstimator(ctx)
+ if err != nil {
+ return reportingPluginAndInfo{}, fmt.Errorf("get gas price estimator from offramp: %w", err)
+ }
+
+ onchainConfig, err := rf.config.offRampReader.OnchainConfig(ctx)
+ if err != nil {
+ return reportingPluginAndInfo{}, fmt.Errorf("get onchain config from offramp: %w", err)
+ }
+
+ batchingStrategy, err := NewBatchingStrategy(offchainConfig.BatchingStrategyID, rf.config.txmStatusChecker)
+ if err != nil {
+ return reportingPluginAndInfo{}, fmt.Errorf("get batching strategy: %w", err)
+ }
+
+ msgVisibilityInterval := offchainConfig.MessageVisibilityInterval.Duration()
+ if msgVisibilityInterval.Seconds() == 0 {
+ rf.config.lggr.Info("MessageVisibilityInterval not set, falling back to PermissionLessExecutionThreshold")
+ msgVisibilityInterval = onchainConfig.PermissionLessExecutionThresholdSeconds
+ }
+ rf.config.lggr.Infof("MessageVisibilityInterval set to: %s", msgVisibilityInterval)
+
+ lggr := rf.config.lggr.Named("ExecutionReportingPlugin")
+ plugin := &ExecutionReportingPlugin{
+ F: config.F,
+ lggr: lggr,
+ offchainConfig: offchainConfig,
+ tokenDataWorker: rf.config.tokenDataWorker,
+ gasPriceEstimator: gasPriceEstimator,
+ sourcePriceRegistryProvider: rf.config.sourcePriceRegistryProvider,
+ sourcePriceRegistryLock: sync.RWMutex{},
+ sourceWrappedNativeToken: rf.config.sourceWrappedNativeToken,
+ onRampReader: rf.config.onRampReader,
+ commitStoreReader: rf.config.commitStoreReader,
+ destPriceRegistry: rf.destPriceRegReader,
+ destWrappedNative: destWrappedNative,
+ onchainConfig: onchainConfig,
+ offRampReader: rf.config.offRampReader,
+ tokenPoolBatchedReader: rf.config.tokenPoolBatchedReader,
+ inflightReports: newInflightExecReportsContainer(offchainConfig.InflightCacheExpiry.Duration()),
+ commitRootsCache: cache.NewCommitRootsCache(lggr, rf.config.commitStoreReader, msgVisibilityInterval, offchainConfig.RootSnoozeTime.Duration()),
+ metricsCollector: rf.config.metricsCollector,
+ chainHealthcheck: rf.config.chainHealthcheck,
+ batchingStrategy: batchingStrategy,
+ }
+
+ pluginInfo := types.ReportingPluginInfo{
+ Name: "CCIPExecution",
+ // Setting this to false saves on calldata since OffRamp doesn't require agreement between NOPs
+ // (OffRamp is only able to execute committed messages).
+ UniqueReports: false,
+ Limits: types.ReportingPluginLimits{
+ MaxObservationLength: ccip.MaxObservationLength,
+ MaxReportLength: MaxExecutionReportLength,
+ },
+ }
+
+ return reportingPluginAndInfo{plugin, pluginInfo}, nil
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/factory_test.go b/core/services/ocr2/plugins/ccip/ccipexec/factory_test.go
new file mode 100644
index 00000000000..7bbb9be0c69
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/factory_test.go
@@ -0,0 +1,67 @@
+package ccipexec
+
+import (
+ "errors"
+ "testing"
+ "time"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ ccipdataprovidermocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+)
+
+// Assert that NewReportingPlugin keeps retrying until it succeeds.
+//
+// NewReportingPlugin makes several calls (e.g. OffRampReader.ChangeConfig()) that can fail. We use mocks to cause the
+// first call to each of these functions to fail, then all subsequent calls succeed. We assert that NewReportingPlugin
+// retries a sufficient number of times to get through the transient errors and eventually succeed.
+func TestNewReportingPluginRetriesUntilSuccess(t *testing.T) {
+ execConfig := ExecutionPluginStaticConfig{}
+
+ // For this unit test, ensure that there is no delay between retries
+ execConfig.newReportingPluginRetryConfig = ccipdata.RetryConfig{
+ InitialDelay: 0 * time.Nanosecond,
+ MaxDelay: 0 * time.Nanosecond,
+ }
+
+ // Set up the OffRampReader mock
+ mockOffRampReader := new(mocks.OffRampReader)
+
+ // The first call is set to return an error, the following calls return a nil error
+ mockOffRampReader.On("ChangeConfig", mock.Anything, mock.Anything, mock.Anything).Return(ccip.Address(""), ccip.Address(""), errors.New("")).Once()
+ mockOffRampReader.On("ChangeConfig", mock.Anything, mock.Anything, mock.Anything).Return(ccip.Address("addr1"), ccip.Address("addr2"), nil).Times(5)
+
+ mockOffRampReader.On("OffchainConfig", mock.Anything).Return(ccip.ExecOffchainConfig{}, errors.New("")).Once()
+ mockOffRampReader.On("OffchainConfig", mock.Anything).Return(ccip.ExecOffchainConfig{}, nil).Times(3)
+
+ mockOffRampReader.On("GasPriceEstimator", mock.Anything).Return(nil, errors.New("")).Once()
+ mockOffRampReader.On("GasPriceEstimator", mock.Anything).Return(nil, nil).Times(2)
+
+ mockOffRampReader.On("OnchainConfig", mock.Anything).Return(ccip.ExecOnchainConfig{}, errors.New("")).Once()
+ mockOffRampReader.On("OnchainConfig", mock.Anything).Return(ccip.ExecOnchainConfig{}, nil).Times(1)
+
+ execConfig.offRampReader = mockOffRampReader
+
+ // Set up the PriceRegistry mock
+ priceRegistryProvider := new(ccipdataprovidermocks.PriceRegistry)
+ priceRegistryProvider.On("NewPriceRegistryReader", mock.Anything, mock.Anything).Return(nil, errors.New("")).Once()
+ priceRegistryProvider.On("NewPriceRegistryReader", mock.Anything, mock.Anything).Return(nil, nil).Once()
+ execConfig.priceRegistryProvider = priceRegistryProvider
+
+ execConfig.lggr, _ = logger.NewLogger()
+
+ factory := NewExecutionReportingPluginFactory(execConfig)
+ reportingConfig := types.ReportingPluginConfig{}
+ reportingConfig.OnchainConfig = []byte{1, 2, 3}
+ reportingConfig.OffchainConfig = []byte{1, 2, 3}
+
+ // Assert that NewReportingPlugin succeeds despite many transient internal failures (mocked out above)
+ _, _, err := factory.NewReportingPlugin(reportingConfig)
+ assert.Equal(t, nil, err)
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/gashelpers.go b/core/services/ocr2/plugins/ccip/ccipexec/gashelpers.go
new file mode 100644
index 00000000000..7e208296c53
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/gashelpers.go
@@ -0,0 +1,83 @@
+package ccipexec
+
+import (
+ "math"
+ "math/big"
+ "time"
+)
+
+const (
+ EvmAddressLengthBytes = 20
+ EvmWordBytes = 32
+ CalldataGasPerByte = 16
+ TokenAdminRegistryWarmupCost = 2_500
+ TokenAdminRegistryPoolLookupGas = 100 + // WARM_ACCESS_COST TokenAdminRegistry
+ 700 + // CALL cost for TokenAdminRegistry
+ 2_100 // COLD_SLOAD_COST loading the pool address
+ SupportsInterfaceCheck = 2600 + // because the receiver will be untouched initially
+ 30_000*3 // supportsInterface of ERC165Checker library performs 3 static-calls of 30k gas each
+ PerTokenOverheadGas = TokenAdminRegistryPoolLookupGas +
+ SupportsInterfaceCheck +
+ 200_000 + // releaseOrMint using callWithExactGas
+ 50_000 // transfer using callWithExactGas
+ RateLimiterOverheadGas = 2_100 + // COLD_SLOAD_COST for accessing token bucket
+ 5_000 // SSTORE_RESET_GAS for updating & decreasing token bucket
+ ConstantMessagePartBytes = 10 * 32 // A message consists of 10 abi encoded fields 32B each (after encoding)
+ ExecutionStateProcessingOverheadGas = 2_100 + // COLD_SLOAD_COST for first reading the state
+ 20_000 + // SSTORE_SET_GAS for writing from 0 (untouched) to non-zero (in-progress)
+ 100 //# SLOAD_GAS = WARM_STORAGE_READ_COST for rewriting from non-zero (in-progress) to non-zero (success/failure)
+)
+
+// return the size of bytes for msg tokens
+func bytesForMsgTokens(numTokens int) int {
+ // token address (address) + token amount (uint256)
+ return (EvmAddressLengthBytes + EvmWordBytes) * numTokens
+}
+
+// Offchain: we compute the max overhead gas to determine msg executability.
+func overheadGas(dataLength, numTokens int) uint64 {
+ messageBytes := ConstantMessagePartBytes +
+ bytesForMsgTokens(numTokens) +
+ dataLength
+
+ messageCallDataGas := uint64(messageBytes * CalldataGasPerByte)
+
+ // Rate limiter only limits value in tokens. It's not called if there are no
+ // tokens in the message. The same goes for the admin registry, it's only loaded
+ // if there are tokens, and it's only loaded once.
+ rateLimiterOverhead := uint64(0)
+ adminRegistryOverhead := uint64(0)
+ if numTokens >= 1 {
+ rateLimiterOverhead = RateLimiterOverheadGas
+ adminRegistryOverhead = TokenAdminRegistryWarmupCost
+ }
+
+ return messageCallDataGas +
+ ExecutionStateProcessingOverheadGas +
+ SupportsInterfaceCheck +
+ adminRegistryOverhead +
+ rateLimiterOverhead +
+ PerTokenOverheadGas*uint64(numTokens)
+}
+
+func maxGasOverHeadGas(numMsgs, dataLength, numTokens int) uint64 {
+ merkleProofBytes := (math.Ceil(math.Log2(float64(numMsgs))))*32 + (1+2)*32 // only ever one outer root hash
+ merkleGasShare := uint64(merkleProofBytes * CalldataGasPerByte)
+
+ return overheadGas(dataLength, numTokens) + merkleGasShare
+}
+
+// waitBoostedFee boosts the given fee according to the time passed since the msg was sent.
+// RelativeBoostPerWaitHour is used to normalize the time diff,
+// it makes our loss taking "smooth" and gives us time to react without a hard deadline.
+// At the same time, messages that are slightly underpaid will start going through after waiting for a little bit.
+//
+// wait_boosted_fee(m) = (1 + (now - m.send_time).hours * RELATIVE_BOOST_PER_WAIT_HOUR) * fee(m)
+func waitBoostedFee(waitTime time.Duration, fee *big.Int, relativeBoostPerWaitHour float64) *big.Int {
+ k := 1.0 + waitTime.Hours()*relativeBoostPerWaitHour
+
+ boostedFee := big.NewFloat(0).Mul(big.NewFloat(k), new(big.Float).SetInt(fee))
+ res, _ := boostedFee.Int(nil)
+
+ return res
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/gashelpers_test.go b/core/services/ocr2/plugins/ccip/ccipexec/gashelpers_test.go
new file mode 100644
index 00000000000..15607cc310e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/gashelpers_test.go
@@ -0,0 +1,179 @@
+package ccipexec
+
+import (
+ "math/big"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestOverheadGas(t *testing.T) {
+ // Only Data and TokenAmounts are used from the messages
+ // And only the length is used so the contents doesn't matter.
+ tests := []struct {
+ dataLength int
+ numberOfTokens int
+ want uint64
+ }{
+ {
+ dataLength: 0,
+ numberOfTokens: 0,
+ want: 119920,
+ },
+ {
+ dataLength: len([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}),
+ numberOfTokens: 1,
+ want: 475948,
+ },
+ }
+
+ for _, tc := range tests {
+ got := overheadGas(tc.dataLength, tc.numberOfTokens)
+ if !reflect.DeepEqual(tc.want, got) {
+ t.Fatalf("expected: %v, got: %v", tc.want, got)
+ }
+ }
+}
+
+func TestMaxGasOverHeadGas(t *testing.T) {
+ // Only Data and TokenAmounts are used from the messages
+ // And only the length is used so the contents doesn't matter.
+ tests := []struct {
+ numMsgs int
+ dataLength int
+ numberOfTokens int
+ want uint64
+ }{
+ {
+ numMsgs: 6,
+ dataLength: 0,
+ numberOfTokens: 0,
+ want: 122992,
+ },
+ {
+ numMsgs: 3,
+ dataLength: len([]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0}),
+ numberOfTokens: 1,
+ want: 478508,
+ },
+ }
+
+ for _, tc := range tests {
+ got := maxGasOverHeadGas(tc.numMsgs, tc.dataLength, tc.numberOfTokens)
+ if !reflect.DeepEqual(tc.want, got) {
+ t.Fatalf("expected: %v, got: %v", tc.want, got)
+ }
+ }
+}
+
+func TestWaitBoostedFee(t *testing.T) {
+ tests := []struct {
+ name string
+ sendTimeDiff time.Duration
+ fee *big.Int
+ diff *big.Int
+ relativeBoostPerWaitHour float64
+ }{
+ {
+ "wait 10s",
+ time.Second * 10,
+ big.NewInt(6e18), // Fee: 6 LINK
+
+ big.NewInt(1166666666665984), // Boost: 0.01 LINK
+ 0.07,
+ },
+ {
+ "wait 5m",
+ time.Minute * 5,
+ big.NewInt(6e18), // Fee: 6 LINK
+ big.NewInt(35e15), // Boost: 0.35 LINK
+ 0.07,
+ },
+ {
+ "wait 7m",
+ time.Minute * 7,
+ big.NewInt(6e18), // Fee: 6 LINK
+ big.NewInt(49e15), // Boost: 0.49 LINK
+ 0.07,
+ },
+ {
+ "wait 12m",
+ time.Minute * 12,
+ big.NewInt(6e18), // Fee: 6 LINK
+ big.NewInt(84e15), // Boost: 0.84 LINK
+ 0.07,
+ },
+ {
+ "wait 25m",
+ time.Minute * 25,
+ big.NewInt(6e18), // Fee: 6 LINK
+ big.NewInt(174999999999998976), // Boost: 1.75 LINK
+ 0.07,
+ },
+ {
+ "wait 1h",
+ time.Hour * 1,
+ big.NewInt(6e18), // Fee: 6 LINK
+ big.NewInt(420e15), // Boost: 4.2 LINK
+ 0.07,
+ },
+ {
+ "wait 5h",
+ time.Hour * 5,
+ big.NewInt(6e18), // Fee: 6 LINK
+ big.NewInt(2100000000000001024), // Boost: 21LINK
+ 0.07,
+ },
+ {
+ "wait 24h",
+ time.Hour * 24,
+ big.NewInt(6e18), // Fee: 6 LINK
+ big.NewInt(0).Mul(big.NewInt(10), big.NewInt(1008e15)), // Boost: 100LINK
+ 0.07,
+ },
+ {
+ "high boost wait 10s",
+ time.Second * 10,
+ big.NewInt(5e18),
+ big.NewInt(9722222222222336), // 1e16
+ 0.7,
+ },
+ {
+ "high boost wait 5m",
+ time.Minute * 5,
+ big.NewInt(5e18),
+ big.NewInt(291666666666667008), // 1e18
+ 0.7,
+ },
+ {
+ "high boost wait 25m",
+ time.Minute * 25,
+ big.NewInt(5e18),
+ big.NewInt(1458333333333334016), // 1e19
+ 0.7,
+ },
+ {
+ "high boost wait 5h",
+ time.Hour * 5,
+ big.NewInt(5e18),
+ big.NewInt(0).Mul(big.NewInt(10), big.NewInt(175e16)), // 1e20
+ 0.7,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ boosted := waitBoostedFee(tc.sendTimeDiff, tc.fee, tc.relativeBoostPerWaitHour)
+ diff := big.NewInt(0).Sub(boosted, tc.fee)
+ assert.Equal(t, diff, tc.diff)
+ // we check that the actual diff is approximately equals to expected diff,
+ // as we might get slightly different results locally vs. CI therefore normal Equal() would be unstable
+ //diffUpperLimit := big.NewInt(0).Add(tc.diff, big.NewInt(1e9))
+ //diffLowerLimit := big.NewInt(0).Add(tc.diff, big.NewInt(-1e9))
+ //require.Equalf(t, -1, diff.Cmp(diffUpperLimit), "actual diff (%s) is larger than expected (%s)", diff.String(), diffUpperLimit.String())
+ //require.Equal(t, 1, diff.Cmp(diffLowerLimit), "actual diff (%s) is smaller than expected (%s)", diff.String(), diffLowerLimit.String())
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/helpers.go b/core/services/ocr2/plugins/ccip/ccipexec/helpers.go
new file mode 100644
index 00000000000..46df7d793ba
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/helpers.go
@@ -0,0 +1,53 @@
+package ccipexec
+
+import (
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+// helper struct to hold the commitReport and the related send requests
+type commitReportWithSendRequests struct {
+ commitReport cciptypes.CommitStoreReport
+ sendRequestsWithMeta []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta
+}
+
+func (r *commitReportWithSendRequests) validate() error {
+ // make sure that number of messages is the expected
+ if exp := int(r.commitReport.Interval.Max - r.commitReport.Interval.Min + 1); len(r.sendRequestsWithMeta) != exp {
+ return errors.Errorf(
+ "unexpected missing sendRequestsWithMeta in committed root %x have %d want %d", r.commitReport.MerkleRoot, len(r.sendRequestsWithMeta), exp)
+ }
+
+ return nil
+}
+
+// uniqueSenders returns slice of unique senders based on the send requests. Order is preserved based on the order of the send requests (by sequence number).
+func (r *commitReportWithSendRequests) uniqueSenders() []cciptypes.Address {
+ orderedUniqueSenders := make([]cciptypes.Address, 0, len(r.sendRequestsWithMeta))
+ visitedSenders := mapset.NewSet[cciptypes.Address]()
+
+ for _, req := range r.sendRequestsWithMeta {
+ if !visitedSenders.Contains(req.Sender) {
+ orderedUniqueSenders = append(orderedUniqueSenders, req.Sender)
+ visitedSenders.Add(req.Sender)
+ }
+ }
+ return orderedUniqueSenders
+}
+
+func (r *commitReportWithSendRequests) allRequestsAreExecutedAndFinalized() bool {
+ for _, req := range r.sendRequestsWithMeta {
+ if !req.Executed || !req.Finalized {
+ return false
+ }
+ }
+ return true
+}
+
+// checks if the send request fits the commit report interval
+func (r *commitReportWithSendRequests) sendReqFits(sendReq cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) bool {
+ return sendReq.SequenceNumber >= r.commitReport.Interval.Min &&
+ sendReq.SequenceNumber <= r.commitReport.Interval.Max
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/helpers_test.go b/core/services/ocr2/plugins/ccip/ccipexec/helpers_test.go
new file mode 100644
index 00000000000..daa54fd2428
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/helpers_test.go
@@ -0,0 +1,96 @@
+package ccipexec
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+)
+
+func Test_CommitReportWithSendRequests_uniqueSenders(t *testing.T) {
+ messageFn := func(address cciptypes.Address) cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta {
+ return cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{EVM2EVMMessage: cciptypes.EVM2EVMMessage{Sender: address}}
+ }
+
+ tests := []struct {
+ name string
+ sendRequests []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta
+ expUniqueSenders int
+ expSendersOrder []cciptypes.Address
+ }{
+ {
+ name: "all unique senders",
+ sendRequests: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ messageFn(cciptypes.Address(utils.RandomAddress().String())),
+ messageFn(cciptypes.Address(utils.RandomAddress().String())),
+ messageFn(cciptypes.Address(utils.RandomAddress().String())),
+ },
+ expUniqueSenders: 3,
+ },
+ {
+ name: "some senders are the same",
+ sendRequests: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ messageFn("0x1"),
+ messageFn("0x2"),
+ messageFn("0x1"),
+ messageFn("0x2"),
+ messageFn("0x3"),
+ },
+ expUniqueSenders: 3,
+ expSendersOrder: []cciptypes.Address{
+ cciptypes.Address("0x1"),
+ cciptypes.Address("0x2"),
+ cciptypes.Address("0x3"),
+ },
+ },
+ {
+ name: "all senders are the same",
+ sendRequests: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ messageFn("0x1"),
+ messageFn("0x1"),
+ messageFn("0x1"),
+ },
+ expUniqueSenders: 1,
+ expSendersOrder: []cciptypes.Address{
+ cciptypes.Address("0x1"),
+ },
+ },
+ {
+ name: "order is preserved",
+ sendRequests: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ messageFn("0x3"),
+ messageFn("0x1"),
+ messageFn("0x3"),
+ messageFn("0x2"),
+ messageFn("0x2"),
+ messageFn("0x1"),
+ },
+ expUniqueSenders: 3,
+ expSendersOrder: []cciptypes.Address{
+ cciptypes.Address("0x3"),
+ cciptypes.Address("0x1"),
+ cciptypes.Address("0x2"),
+ },
+ },
+ {
+ name: "no senders",
+ sendRequests: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{},
+ expUniqueSenders: 0,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ rep := commitReportWithSendRequests{sendRequestsWithMeta: tt.sendRequests}
+ uniqueSenders := rep.uniqueSenders()
+
+ assert.Len(t, uniqueSenders, tt.expUniqueSenders)
+ if tt.expSendersOrder != nil {
+ assert.Equal(t, tt.expSendersOrder, uniqueSenders)
+ }
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/inflight.go b/core/services/ocr2/plugins/ccip/ccipexec/inflight.go
new file mode 100644
index 00000000000..c76bfdf7780
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/inflight.go
@@ -0,0 +1,82 @@
+package ccipexec
+
+import (
+ "sync"
+ "time"
+
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+// InflightInternalExecutionReport serves the same purpose as InflightCommitReport
+// see the comment on that struct for context.
+type InflightInternalExecutionReport struct {
+ createdAt time.Time
+ messages []cciptypes.EVM2EVMMessage
+}
+
+// inflightExecReportsContainer holds existing inflight reports.
+// it provides a thread-safe access as it is called from multiple goroutines,
+// e.g. reporting and transmission protocols.
+type inflightExecReportsContainer struct {
+ locker sync.RWMutex
+ reports []InflightInternalExecutionReport
+
+ cacheExpiry time.Duration
+}
+
+func newInflightExecReportsContainer(inflightCacheExpiry time.Duration) *inflightExecReportsContainer {
+ return &inflightExecReportsContainer{
+ locker: sync.RWMutex{},
+ reports: make([]InflightInternalExecutionReport, 0),
+ cacheExpiry: inflightCacheExpiry,
+ }
+}
+
+func (container *inflightExecReportsContainer) getAll() []InflightInternalExecutionReport {
+ container.locker.RLock()
+ defer container.locker.RUnlock()
+
+ reports := make([]InflightInternalExecutionReport, len(container.reports))
+ copy(reports[:], container.reports[:])
+
+ return reports
+}
+
+func (container *inflightExecReportsContainer) expire(lggr logger.Logger) {
+ container.locker.Lock()
+ defer container.locker.Unlock()
+ // Reap old inflight txs and check if any messages in the report are inflight.
+ var stillInFlight []InflightInternalExecutionReport
+ for _, report := range container.reports {
+ if time.Since(report.createdAt) > container.cacheExpiry {
+ // Happy path: inflight report was successfully transmitted onchain, we remove it from inflight and onchain state reflects inflight.
+ // Sad path: inflight report reverts onchain, we remove it from inflight, onchain state does not reflect the change so we retry.
+ lggr.Infow("Inflight report expired", "messages", report.messages)
+ } else {
+ stillInFlight = append(stillInFlight, report)
+ }
+ }
+ container.reports = stillInFlight
+}
+
+func (container *inflightExecReportsContainer) add(lggr logger.Logger, messages []cciptypes.EVM2EVMMessage) error {
+ container.locker.Lock()
+ defer container.locker.Unlock()
+
+ for _, report := range container.reports {
+ if (len(report.messages) > 0) && (report.messages[0].SequenceNumber == messages[0].SequenceNumber) {
+ return errors.Errorf("report is already in flight")
+ }
+ }
+
+ // Otherwise not already in flight, add it.
+ lggr.Info("Inflight report added")
+ container.reports = append(container.reports, InflightInternalExecutionReport{
+ createdAt: time.Now(),
+ messages: messages,
+ })
+ return nil
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/inflight_test.go b/core/services/ocr2/plugins/ccip/ccipexec/inflight_test.go
new file mode 100644
index 00000000000..2a91457ef4f
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/inflight_test.go
@@ -0,0 +1,42 @@
+package ccipexec
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+func TestInflightReportsContainer_add(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ container := newInflightExecReportsContainer(time.Second)
+
+ err := container.add(lggr, []cciptypes.EVM2EVMMessage{
+ {SequenceNumber: 1}, {SequenceNumber: 2}, {SequenceNumber: 3},
+ })
+ require.NoError(t, err)
+ err = container.add(lggr, []cciptypes.EVM2EVMMessage{
+ {SequenceNumber: 1},
+ })
+ require.Error(t, err)
+ require.Equal(t, "report is already in flight", err.Error())
+ require.Equal(t, 1, len(container.getAll()))
+}
+
+func TestInflightReportsContainer_expire(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ container := newInflightExecReportsContainer(time.Second)
+
+ err := container.add(lggr, []cciptypes.EVM2EVMMessage{
+ {SequenceNumber: 1}, {SequenceNumber: 2}, {SequenceNumber: 3},
+ })
+ require.NoError(t, err)
+ container.reports[0].createdAt = time.Now().Add(-time.Second * 5)
+ require.Equal(t, 1, len(container.getAll()))
+
+ container.expire(lggr)
+ require.Equal(t, 0, len(container.getAll()))
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/initializers.go b/core/services/ocr2/plugins/ccip/ccipexec/initializers.go
new file mode 100644
index 00000000000..7826f6058fe
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/initializers.go
@@ -0,0 +1,228 @@
+package ccipexec
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "time"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+
+ "github.com/Masterminds/semver/v3"
+ "go.uber.org/multierr"
+
+ libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus"
+
+ commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/statuschecker"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/observability"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/oraclelib"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/promwrapper"
+)
+
+var (
+ // tokenDataWorkerTimeout defines 1) The timeout while waiting for a bg call to the token data 3P provider.
+ // 2) When a client requests token data and does not specify a timeout this value is used as a default.
+ // 5 seconds is a reasonable value for a timeout.
+ // At this moment, minimum OCR Delta Round is set to 30s and deltaGrace to 5s. Based on this configuration
+ // 5s for token data worker timeout is a reasonable default.
+ tokenDataWorkerTimeout = 5 * time.Second
+ // tokenDataWorkerNumWorkers is the number of workers that will be processing token data in parallel.
+ tokenDataWorkerNumWorkers = 5
+)
+
+var defaultNewReportingPluginRetryConfig = ccipdata.RetryConfig{InitialDelay: time.Second, MaxDelay: 5 * time.Minute}
+
+func NewExecServices(ctx context.Context, lggr logger.Logger, jb job.Job, srcProvider types.CCIPExecProvider, dstProvider types.CCIPExecProvider, srcChainID int64, dstChainID int64, new bool, argsNoPlugin libocr2.OCR2OracleArgs, logError func(string)) ([]job.ServiceCtx, error) {
+ if jb.OCR2OracleSpec == nil {
+ return nil, fmt.Errorf("spec is nil")
+ }
+ spec := jb.OCR2OracleSpec
+ var pluginConfig ccipconfig.ExecPluginJobSpecConfig
+ err := json.Unmarshal(spec.PluginConfig.Bytes(), &pluginConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ offRampAddress := ccipcalc.HexToAddress(spec.ContractID)
+ offRampReader, err := dstProvider.NewOffRampReader(ctx, offRampAddress)
+ if err != nil {
+ return nil, fmt.Errorf("create offRampReader: %w", err)
+ }
+
+ offRampConfig, err := offRampReader.GetStaticConfig(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("get offRamp static config: %w", err)
+ }
+
+ srcChainSelector := offRampConfig.SourceChainSelector
+ dstChainSelector := offRampConfig.ChainSelector
+ onRampReader, err := srcProvider.NewOnRampReader(ctx, offRampConfig.OnRamp, srcChainSelector, dstChainSelector)
+ if err != nil {
+ return nil, fmt.Errorf("create onRampReader: %w", err)
+ }
+
+ dynamicOnRampConfig, err := onRampReader.GetDynamicConfig(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("get onramp dynamic config: %w", err)
+ }
+
+ sourceWrappedNative, err := srcProvider.SourceNativeToken(ctx, dynamicOnRampConfig.Router)
+ if err != nil {
+ return nil, fmt.Errorf("get source wrapped native token: %w", err)
+ }
+
+ srcCommitStore, err := srcProvider.NewCommitStoreReader(ctx, offRampConfig.CommitStore)
+ if err != nil {
+ return nil, fmt.Errorf("could not create src commitStoreReader reader: %w", err)
+ }
+
+ dstCommitStore, err := dstProvider.NewCommitStoreReader(ctx, offRampConfig.CommitStore)
+ if err != nil {
+ return nil, fmt.Errorf("could not create dst commitStoreReader reader: %w", err)
+ }
+
+ var commitStoreReader ccipdata.CommitStoreReader
+ commitStoreReader = ccip.NewProviderProxyCommitStoreReader(srcCommitStore, dstCommitStore)
+
+ tokenDataProviders := make(map[cciptypes.Address]tokendata.Reader)
+ // init usdc token data provider
+ if pluginConfig.USDCConfig.AttestationAPI != "" {
+ lggr.Infof("USDC token data provider enabled")
+ err2 := pluginConfig.USDCConfig.ValidateUSDCConfig()
+ if err2 != nil {
+ return nil, err2
+ }
+
+ usdcReader, err2 := srcProvider.NewTokenDataReader(ctx, ccip.EvmAddrToGeneric(pluginConfig.USDCConfig.SourceTokenAddress))
+ if err2 != nil {
+ return nil, fmt.Errorf("new usdc reader: %w", err2)
+ }
+ tokenDataProviders[cciptypes.Address(pluginConfig.USDCConfig.SourceTokenAddress.String())] = usdcReader
+ }
+
+ // Prom wrappers
+ onRampReader = observability.NewObservedOnRampReader(onRampReader, srcChainID, ccip.ExecPluginLabel)
+ commitStoreReader = observability.NewObservedCommitStoreReader(commitStoreReader, dstChainID, ccip.ExecPluginLabel)
+ offRampReader = observability.NewObservedOffRampReader(offRampReader, dstChainID, ccip.ExecPluginLabel)
+ metricsCollector := ccip.NewPluginMetricsCollector(ccip.ExecPluginLabel, srcChainID, dstChainID)
+
+ tokenPoolBatchedReader, err := dstProvider.NewTokenPoolBatchedReader(ctx, offRampAddress, srcChainSelector)
+ if err != nil {
+ return nil, fmt.Errorf("new token pool batched reader: %w", err)
+ }
+
+ chainHealthcheck := cache.NewObservedChainHealthCheck(
+ cache.NewChainHealthcheck(
+ // Adding more details to Logger to make healthcheck logs more informative
+ // It's safe because healthcheck logs only in case of unhealthy state
+ lggr.With(
+ "onramp", offRampConfig.OnRamp,
+ "commitStore", offRampConfig.CommitStore,
+ "offramp", offRampAddress,
+ ),
+ onRampReader,
+ commitStoreReader,
+ ),
+ ccip.ExecPluginLabel,
+ srcChainID,
+ dstChainID,
+ offRampConfig.OnRamp,
+ )
+
+ tokenBackgroundWorker := tokendata.NewBackgroundWorker(
+ tokenDataProviders,
+ tokenDataWorkerNumWorkers,
+ tokenDataWorkerTimeout,
+ 2*tokenDataWorkerTimeout,
+ )
+
+ wrappedPluginFactory := NewExecutionReportingPluginFactory(ExecutionPluginStaticConfig{
+ lggr: lggr,
+ onRampReader: onRampReader,
+ commitStoreReader: commitStoreReader,
+ offRampReader: offRampReader,
+ sourcePriceRegistryProvider: ccip.NewChainAgnosticPriceRegistry(srcProvider),
+ sourceWrappedNativeToken: sourceWrappedNative,
+ destChainSelector: dstChainSelector,
+ priceRegistryProvider: ccip.NewChainAgnosticPriceRegistry(dstProvider),
+ tokenPoolBatchedReader: tokenPoolBatchedReader,
+ tokenDataWorker: tokenBackgroundWorker,
+ metricsCollector: metricsCollector,
+ chainHealthcheck: chainHealthcheck,
+ newReportingPluginRetryConfig: defaultNewReportingPluginRetryConfig,
+ txmStatusChecker: statuschecker.NewTxmStatusChecker(dstProvider.GetTransactionStatus),
+ })
+
+ argsNoPlugin.ReportingPluginFactory = promwrapper.NewPromFactory(wrappedPluginFactory, "CCIPExecution", jb.OCR2OracleSpec.Relay, big.NewInt(0).SetInt64(dstChainID))
+ argsNoPlugin.Logger = commonlogger.NewOCRWrapper(lggr, true, logError)
+ oracle, err := libocr2.NewOracle(argsNoPlugin)
+ if err != nil {
+ return nil, err
+ }
+ // If this is a brand-new job, then we make use of the start blocks. If not then we're rebooting and log poller will pick up where we left off.
+ if new {
+ return []job.ServiceCtx{
+ oraclelib.NewChainAgnosticBackFilledOracle(
+ lggr,
+ srcProvider,
+ dstProvider,
+ job.NewServiceAdapter(oracle),
+ ),
+ chainHealthcheck,
+ tokenBackgroundWorker,
+ }, nil
+ }
+ return []job.ServiceCtx{
+ job.NewServiceAdapter(oracle),
+ chainHealthcheck,
+ tokenBackgroundWorker,
+ }, nil
+}
+
+// UnregisterExecPluginLpFilters unregisters all the registered filters for both source and dest chains.
+// See comment in UnregisterCommitPluginLpFilters
+// It MUST mirror the filters registered in NewExecServices.
+// This currently works because the filters registered by the created custom providers when the job is first added
+// are stored in the db. Those same filters are unregistered (i.e. deleted from the db) by the newly created providers
+// that are passed in from cleanupEVM, as while the providers have no knowledge of each other, they are created
+// on the same source and dest relayer.
+func UnregisterExecPluginLpFilters(srcProvider types.CCIPExecProvider, dstProvider types.CCIPExecProvider) error {
+ unregisterFuncs := []func() error{
+ func() error {
+ return srcProvider.Close()
+ },
+ func() error {
+ return dstProvider.Close()
+ },
+ }
+
+ var multiErr error
+ for _, fn := range unregisterFuncs {
+ if err := fn(); err != nil {
+ multiErr = multierr.Append(multiErr, err)
+ }
+ }
+ return multiErr
+}
+
+// ExecReportToEthTxMeta generates a txmgr.EthTxMeta from the given report.
+// Only MessageIDs will be populated in the TxMeta.
+func ExecReportToEthTxMeta(ctx context.Context, typ ccipconfig.ContractType, ver semver.Version) (func(report []byte) (*txmgr.TxMeta, error), error) {
+ return factory.ExecReportToEthTxMeta(ctx, typ, ver)
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/ocr2.go b/core/services/ocr2/plugins/ccip/ccipexec/ocr2.go
new file mode 100644
index 00000000000..4a09cf37b45
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/ocr2.go
@@ -0,0 +1,845 @@
+package ccipexec
+
+import (
+ "context"
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "sort"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/pkg/errors"
+ "golang.org/x/sync/errgroup"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/statuschecker"
+)
+
+const (
+ // exec Report should make sure to cap returned payload to this limit
+ MaxExecutionReportLength = 250_000
+
+ // MaxDataLenPerBatch limits the total length of msg data that can be in a batch.
+ MaxDataLenPerBatch = 60_000
+
+ // MaximumAllowedTokenDataWaitTimePerBatch defines the maximum time that is allowed
+ // for the plugin to wait for token data to be fetched from external providers per batch.
+ MaximumAllowedTokenDataWaitTimePerBatch = 2 * time.Second
+
+ // MessagesIterationStep limits number of messages fetched to memory at once when iterating through unexpired CommitRoots
+ MessagesIterationStep = 1024
+)
+
+var (
+ _ types.ReportingPluginFactory = &ExecutionReportingPluginFactory{}
+ _ types.ReportingPlugin = &ExecutionReportingPlugin{}
+)
+
+type ExecutionPluginStaticConfig struct {
+ lggr logger.Logger
+ onRampReader ccipdata.OnRampReader
+ offRampReader ccipdata.OffRampReader
+ commitStoreReader ccipdata.CommitStoreReader
+ sourcePriceRegistryProvider ccipdataprovider.PriceRegistry
+ sourceWrappedNativeToken cciptypes.Address
+ tokenDataWorker tokendata.Worker
+ destChainSelector uint64
+ priceRegistryProvider ccipdataprovider.PriceRegistry // destination price registry provider.
+ tokenPoolBatchedReader batchreader.TokenPoolBatchedReader
+ metricsCollector ccip.PluginMetricsCollector
+ chainHealthcheck cache.ChainHealthcheck
+ newReportingPluginRetryConfig ccipdata.RetryConfig
+ txmStatusChecker statuschecker.CCIPTransactionStatusChecker
+}
+
+type ExecutionReportingPlugin struct {
+ // Misc
+ F int
+ lggr logger.Logger
+ offchainConfig cciptypes.ExecOffchainConfig
+ tokenDataWorker tokendata.Worker
+ metricsCollector ccip.PluginMetricsCollector
+ batchingStrategy BatchingStrategy
+
+ // Source
+ gasPriceEstimator prices.GasPriceEstimatorExec
+ sourcePriceRegistry ccipdata.PriceRegistryReader
+ sourcePriceRegistryProvider ccipdataprovider.PriceRegistry
+ sourcePriceRegistryLock sync.RWMutex
+ sourceWrappedNativeToken cciptypes.Address
+ onRampReader ccipdata.OnRampReader
+
+ // Dest
+ commitStoreReader ccipdata.CommitStoreReader
+ destPriceRegistry ccipdata.PriceRegistryReader
+ destWrappedNative cciptypes.Address
+ onchainConfig cciptypes.ExecOnchainConfig
+ offRampReader ccipdata.OffRampReader
+ tokenPoolBatchedReader batchreader.TokenPoolBatchedReader
+
+ // State
+ inflightReports *inflightExecReportsContainer
+ commitRootsCache cache.CommitsRootsCache
+ chainHealthcheck cache.ChainHealthcheck
+}
+
+func (r *ExecutionReportingPlugin) Query(context.Context, types.ReportTimestamp) (types.Query, error) {
+ return types.Query{}, nil
+}
+
+func (r *ExecutionReportingPlugin) Observation(ctx context.Context, timestamp types.ReportTimestamp, query types.Query) (types.Observation, error) {
+ lggr := r.lggr.Named("ExecutionObservation")
+ if healthy, err := r.chainHealthcheck.IsHealthy(ctx); err != nil {
+ return nil, err
+ } else if !healthy {
+ return nil, ccip.ErrChainIsNotHealthy
+ }
+
+ // Ensure that the source price registry is synchronized with the onRamp.
+ if err := r.ensurePriceRegistrySynchronization(ctx); err != nil {
+ return nil, fmt.Errorf("ensuring price registry synchronization: %w", err)
+ }
+
+ // Expire any inflight reports.
+ r.inflightReports.expire(lggr)
+ inFlight := r.inflightReports.getAll()
+
+ executableObservations, err := r.getExecutableObservations(ctx, lggr, inFlight)
+ if err != nil {
+ return nil, err
+ }
+ // cap observations which fits MaxObservationLength (after serialized)
+ capped := sort.Search(len(executableObservations), func(i int) bool {
+ var encoded []byte
+ encoded, err = ccip.NewExecutionObservation(executableObservations[:i+1]).Marshal()
+ if err != nil {
+ // false makes Search keep looking to the right, always including any "erroring" ObservedMessage and allowing us to detect in the bottom
+ return false
+ }
+ return len(encoded) > ccip.MaxObservationLength
+ })
+ if err != nil {
+ return nil, err
+ }
+ executableObservations = executableObservations[:capped]
+ r.metricsCollector.NumberOfMessagesProcessed(ccip.Observation, len(executableObservations))
+ lggr.Infow("Observation", "executableMessages", executableObservations)
+ // Note can be empty
+ return ccip.NewExecutionObservation(executableObservations).Marshal()
+}
+
+func (r *ExecutionReportingPlugin) getExecutableObservations(ctx context.Context, lggr logger.Logger, inflight []InflightInternalExecutionReport) ([]ccip.ObservedMessage, error) {
+ unexpiredReports, err := r.commitRootsCache.RootsEligibleForExecution(ctx)
+ if err != nil {
+ return nil, err
+ }
+ r.metricsCollector.UnexpiredCommitRoots(len(unexpiredReports))
+
+ if len(unexpiredReports) == 0 {
+ return []ccip.ObservedMessage{}, nil
+ }
+
+ getExecTokenData := cache.LazyFunction[execTokenData](func() (execTokenData, error) {
+ return r.prepareTokenExecData(ctx)
+ })
+
+ for j := 0; j < len(unexpiredReports); {
+ unexpiredReportsPart, step := selectReportsToFillBatch(unexpiredReports[j:], MessagesIterationStep)
+ j += step
+
+ unexpiredReportsWithSendReqs, err := r.getReportsWithSendRequests(ctx, unexpiredReportsPart)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, unexpiredReport := range unexpiredReportsWithSendReqs {
+ r.tokenDataWorker.AddJobsFromMsgs(ctx, unexpiredReport.sendRequestsWithMeta)
+ }
+
+ for _, rep := range unexpiredReportsWithSendReqs {
+ if ctx.Err() != nil {
+ lggr.Warn("Processing of roots killed by context")
+ break
+ }
+
+ merkleRoot := rep.commitReport.MerkleRoot
+
+ rootLggr := lggr.With("root", hexutil.Encode(merkleRoot[:]),
+ "minSeqNr", rep.commitReport.Interval.Min,
+ "maxSeqNr", rep.commitReport.Interval.Max,
+ )
+
+ if err := rep.validate(); err != nil {
+ rootLggr.Errorw("Skipping invalid report", "err", err)
+ continue
+ }
+
+ // If all messages are already executed and finalized, snooze the root for
+ // config.PermissionLessExecutionThresholdSeconds so it will never be considered again.
+ if allMsgsExecutedAndFinalized := rep.allRequestsAreExecutedAndFinalized(); allMsgsExecutedAndFinalized {
+ rootLggr.Infow("Snoozing root forever since there are no executable txs anymore", "root", hex.EncodeToString(merkleRoot[:]))
+ r.commitRootsCache.MarkAsExecuted(merkleRoot)
+ continue
+ }
+
+ blessed, err := r.commitStoreReader.IsBlessed(ctx, merkleRoot)
+ if err != nil {
+ return nil, err
+ }
+ if !blessed {
+ rootLggr.Infow("Report is accepted but not blessed")
+ continue
+ }
+
+ tokenExecData, err := getExecTokenData()
+ if err != nil {
+ return nil, err
+ }
+
+ batch, msgExecStates := r.buildBatch(
+ ctx,
+ inflight,
+ rootLggr,
+ rep,
+ tokenExecData.rateLimiterTokenBucket.Tokens,
+ tokenExecData.sourceTokenPrices,
+ tokenExecData.destTokenPrices,
+ tokenExecData.gasPrice,
+ tokenExecData.sourceToDestTokens)
+ if len(batch) != 0 {
+ lggr.Infow("Execution batch created", "batchSize", len(batch), "messageStates", msgExecStates)
+ return batch, nil
+ }
+ r.commitRootsCache.Snooze(merkleRoot)
+ }
+ }
+ return []ccip.ObservedMessage{}, nil
+}
+
+// Calculates a map that indicates whether a sequence number has already been executed.
+// It doesn't matter if the execution succeeded, since we don't retry previous
+// attempts even if they failed. Value in the map indicates whether the log is finalized or not.
+func (r *ExecutionReportingPlugin) getExecutedSeqNrsInRange(ctx context.Context, min, max uint64) (map[uint64]bool, error) {
+ stateChanges, err := r.offRampReader.GetExecutionStateChangesBetweenSeqNums(
+ ctx,
+ min,
+ max,
+ int(r.offchainConfig.DestOptimisticConfirmations),
+ )
+ if err != nil {
+ return nil, err
+ }
+ executedMp := make(map[uint64]bool, len(stateChanges))
+ for _, stateChange := range stateChanges {
+ executedMp[stateChange.SequenceNumber] = stateChange.TxMeta.IsFinalized()
+ }
+ return executedMp, nil
+}
+
+// Builds a batch of transactions that can be executed, takes into account
+// the available gas, rate limiting, execution state, nonce state, and
+// profitability of execution.
+func (r *ExecutionReportingPlugin) buildBatch(
+ ctx context.Context,
+ inflight []InflightInternalExecutionReport,
+ lggr logger.Logger,
+ report commitReportWithSendRequests,
+ aggregateTokenLimit *big.Int,
+ sourceTokenPricesUSD map[cciptypes.Address]*big.Int,
+ destTokenPricesUSD map[cciptypes.Address]*big.Int,
+ gasPrice *big.Int,
+ sourceToDestToken map[cciptypes.Address]cciptypes.Address,
+) ([]ccip.ObservedMessage, []messageExecStatus) {
+ // We assume that next observation will start after previous epoch transmission so nonces should be already updated onchain.
+ // Worst case scenario we will try to process the same message again, and it will be skipped but protocol would progress anyway.
+ // We don't use inflightCache here to avoid cases in which inflight cache keeps progressing but due to transmission failures
+ // previous reports are not included onchain. That can lead to issues with IncorrectNonce skips,
+ // because we enforce sequential processing per sender (per sender's nonce ordering is enforced by Offramp contract)
+ sendersNonce, err := r.offRampReader.ListSenderNonces(ctx, report.uniqueSenders())
+ if err != nil {
+ lggr.Errorw("Fetching senders nonce", "err", err)
+ return []ccip.ObservedMessage{}, []messageExecStatus{}
+ }
+
+ inflightAggregateValue, err := getInflightAggregateRateLimit(lggr, inflight, destTokenPricesUSD, sourceToDestToken)
+ if err != nil {
+ lggr.Errorw("Unexpected error computing inflight values", "err", err)
+ return []ccip.ObservedMessage{}, nil
+ }
+
+ batchCtx := &BatchContext{
+ report,
+ inflight,
+ inflightAggregateValue,
+ lggr,
+ MaxDataLenPerBatch,
+ uint64(r.offchainConfig.BatchGasLimit),
+ make(map[cciptypes.Address]uint64),
+ sendersNonce,
+ sourceTokenPricesUSD,
+ destTokenPricesUSD,
+ gasPrice,
+ sourceToDestToken,
+ aggregateTokenLimit,
+ MaximumAllowedTokenDataWaitTimePerBatch,
+ r.tokenDataWorker,
+ r.gasPriceEstimator,
+ r.destWrappedNative,
+ r.offchainConfig,
+ }
+
+ return r.batchingStrategy.BuildBatch(ctx, batchCtx)
+}
+
+func calculateMessageMaxGas(gasLimit *big.Int, numRequests, dataLen, numTokens int) (uint64, error) {
+ if !gasLimit.IsUint64() {
+ return 0, fmt.Errorf("gas limit %s cannot be casted to uint64", gasLimit)
+ }
+
+ gasLimitU64 := gasLimit.Uint64()
+ gasOverHeadGas := maxGasOverHeadGas(numRequests, dataLen, numTokens)
+ messageMaxGas := gasLimitU64 + gasOverHeadGas
+
+ if messageMaxGas < gasLimitU64 || messageMaxGas < gasOverHeadGas {
+ return 0, fmt.Errorf("message max gas overflow, gasLimit=%d gasOverHeadGas=%d", gasLimitU64, gasOverHeadGas)
+ }
+
+ return messageMaxGas, nil
+}
+
+// getReportsWithSendRequests returns the target reports with populated send requests.
+func (r *ExecutionReportingPlugin) getReportsWithSendRequests(
+ ctx context.Context,
+ reports []cciptypes.CommitStoreReport,
+) ([]commitReportWithSendRequests, error) {
+ if len(reports) == 0 {
+ return nil, nil
+ }
+
+ // find interval from all the reports
+ intervalMin := reports[0].Interval.Min
+ intervalMax := reports[0].Interval.Max
+ for _, report := range reports[1:] {
+ if report.Interval.Max > intervalMax {
+ intervalMax = report.Interval.Max
+ }
+ if report.Interval.Min < intervalMin {
+ intervalMin = report.Interval.Min
+ }
+ }
+
+ // use errgroup to fetch send request logs and executed sequence numbers in parallel
+ eg := &errgroup.Group{}
+
+ var sendRequests []cciptypes.EVM2EVMMessageWithTxMeta
+ eg.Go(func() error {
+ // We don't need to double-check if logs are finalized because we already checked that in the Commit phase.
+ sendReqs, err := r.onRampReader.GetSendRequestsBetweenSeqNums(ctx, intervalMin, intervalMax, false)
+ if err != nil {
+ return err
+ }
+ sendRequests = sendReqs
+ return nil
+ })
+
+ var executedSeqNums map[uint64]bool
+ eg.Go(func() error {
+ // get executed sequence numbers
+ executedMp, err := r.getExecutedSeqNrsInRange(ctx, intervalMin, intervalMax)
+ if err != nil {
+ return err
+ }
+ executedSeqNums = executedMp
+ return nil
+ })
+
+ if err := eg.Wait(); err != nil {
+ return nil, err
+ }
+
+ reportsWithSendReqs := make([]commitReportWithSendRequests, len(reports))
+ for i, report := range reports {
+ reportsWithSendReqs[i] = commitReportWithSendRequests{
+ commitReport: report,
+ sendRequestsWithMeta: make([]cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, 0, report.Interval.Max-report.Interval.Min+1),
+ }
+ }
+
+ for _, sendReq := range sendRequests {
+ // if value exists in the map then it's executed
+ // if value exists, and it's true then it's considered finalized
+ finalized, executed := executedSeqNums[sendReq.SequenceNumber]
+
+ reqWithMeta := cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: sendReq.EVM2EVMMessage,
+ BlockTimestamp: time.UnixMilli(sendReq.BlockTimestampUnixMilli),
+ Executed: executed,
+ Finalized: finalized,
+ LogIndex: uint(sendReq.LogIndex),
+ TxHash: sendReq.TxHash,
+ }
+
+ // attach the msg to the appropriate reports
+ for i := range reportsWithSendReqs {
+ if reportsWithSendReqs[i].sendReqFits(reqWithMeta) {
+ reportsWithSendReqs[i].sendRequestsWithMeta = append(reportsWithSendReqs[i].sendRequestsWithMeta, reqWithMeta)
+ }
+ }
+ }
+
+ return reportsWithSendReqs, nil
+}
+
+// Assumes non-empty report. Messages to execute can span more than one report, but are assumed to be in order of increasing
+// sequence number.
+func (r *ExecutionReportingPlugin) buildReport(ctx context.Context, lggr logger.Logger, observedMessages []ccip.ObservedMessage) ([]byte, error) {
+ if err := validateSeqNumbers(ctx, r.commitStoreReader, observedMessages); err != nil {
+ return nil, err
+ }
+ commitReport, err := getCommitReportForSeqNum(ctx, r.commitStoreReader, observedMessages[0].SeqNr)
+ if err != nil {
+ return nil, err
+ }
+ lggr.Infow("Building execution report", "observations", observedMessages, "merkleRoot", hexutil.Encode(commitReport.MerkleRoot[:]), "report", commitReport)
+
+ sendReqsInRoot, _, tree, err := getProofData(ctx, r.onRampReader, commitReport.Interval)
+ if err != nil {
+ return nil, err
+ }
+
+ // cap messages which fits MaxExecutionReportLength (after serialized)
+ capped := sort.Search(len(observedMessages), func(i int) bool {
+ report, err2 := buildExecutionReportForMessages(sendReqsInRoot, tree, commitReport.Interval, observedMessages[:i+1])
+ if err2 != nil {
+ r.lggr.Errorw("build execution report", "err", err2)
+ return false
+ }
+
+ encoded, err2 := r.offRampReader.EncodeExecutionReport(ctx, report)
+ if err2 != nil {
+ // false makes Search keep looking to the right, always including any "erroring" ObservedMessage and allowing us to detect in the bottom
+ return false
+ }
+ return len(encoded) > MaxExecutionReportLength
+ })
+
+ execReport, err := buildExecutionReportForMessages(sendReqsInRoot, tree, commitReport.Interval, observedMessages[:capped])
+ if err != nil {
+ return nil, err
+ }
+
+ encodedReport, err := r.offRampReader.EncodeExecutionReport(ctx, execReport)
+ if err != nil {
+ return nil, err
+ }
+
+ if capped < len(observedMessages) {
+ lggr.Warnf(
+ "Capping report to fit MaxExecutionReportLength: msgsCount %d -> %d, bytes %d, bytesLimit %d",
+ len(observedMessages), capped, len(encodedReport), MaxExecutionReportLength,
+ )
+ }
+ // Double check this verifies before sending.
+ valid, err := r.commitStoreReader.VerifyExecutionReport(ctx, execReport)
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to verify")
+ }
+ if !valid {
+ return nil, errors.New("root does not verify")
+ }
+ if len(execReport.Messages) > 0 {
+ r.metricsCollector.NumberOfMessagesProcessed(ccip.Report, len(execReport.Messages))
+ r.metricsCollector.SequenceNumber(ccip.Report, execReport.Messages[len(execReport.Messages)-1].SequenceNumber)
+ }
+ return encodedReport, nil
+}
+
+func (r *ExecutionReportingPlugin) Report(ctx context.Context, timestamp types.ReportTimestamp, query types.Query, observations []types.AttributedObservation) (bool, types.Report, error) {
+ lggr := r.lggr.Named("ExecutionReport")
+ if healthy, err := r.chainHealthcheck.IsHealthy(ctx); err != nil {
+ return false, nil, err
+ } else if !healthy {
+ return false, nil, ccip.ErrChainIsNotHealthy
+ }
+ parsableObservations := ccip.GetParsableObservations[ccip.ExecutionObservation](lggr, observations)
+ // Need at least F+1 observations
+ if len(parsableObservations) <= r.F {
+ lggr.Warn("Non-empty observations <= F, need at least F+1 to continue")
+ return false, nil, nil
+ }
+
+ observedMessages, err := calculateObservedMessagesConsensus(parsableObservations, r.F)
+ if err != nil {
+ return false, nil, err
+ }
+ if len(observedMessages) == 0 {
+ return false, nil, nil
+ }
+
+ report, err := r.buildReport(ctx, lggr, observedMessages)
+ if err != nil {
+ return false, nil, err
+ }
+ lggr.Infow("Report", "executableObservations", observedMessages)
+ return true, report, nil
+}
+
+type tallyKey struct {
+ seqNr uint64
+ tokenDataHash [32]byte
+}
+
+type tallyVal struct {
+ tally int
+ tokenData [][]byte
+}
+
+func calculateObservedMessagesConsensus(observations []ccip.ExecutionObservation, f int) ([]ccip.ObservedMessage, error) {
+ tally := make(map[tallyKey]tallyVal)
+ for _, obs := range observations {
+ for seqNr, msgData := range obs.Messages {
+ tokenDataHash, err := hashutil.BytesOfBytesKeccak(msgData.TokenData)
+ if err != nil {
+ return nil, fmt.Errorf("bytes of bytes keccak: %w", err)
+ }
+
+ key := tallyKey{seqNr: seqNr, tokenDataHash: tokenDataHash}
+ if val, ok := tally[key]; ok {
+ tally[key] = tallyVal{tally: val.tally + 1, tokenData: msgData.TokenData}
+ } else {
+ tally[key] = tallyVal{tally: 1, tokenData: msgData.TokenData}
+ }
+ }
+ }
+
+ // We might have different token data for the same sequence number.
+ // For that purpose we want to keep the token data with the most occurrences.
+ seqNumTally := make(map[uint64]tallyVal)
+
+ // order tally keys to make looping over the entries deterministic
+ tallyKeys := make([]tallyKey, 0, len(tally))
+ for key := range tally {
+ tallyKeys = append(tallyKeys, key)
+ }
+ sort.Slice(tallyKeys, func(i, j int) bool {
+ return hex.EncodeToString(tallyKeys[i].tokenDataHash[:]) < hex.EncodeToString(tallyKeys[j].tokenDataHash[:])
+ })
+
+ for _, key := range tallyKeys {
+ tallyInfo := tally[key]
+ existingTally, exists := seqNumTally[key.seqNr]
+ if tallyInfo.tally > f && (!exists || tallyInfo.tally > existingTally.tally) {
+ seqNumTally[key.seqNr] = tallyInfo
+ }
+ }
+
+ finalSequenceNumbers := make([]ccip.ObservedMessage, 0, len(seqNumTally))
+ for seqNr, tallyInfo := range seqNumTally {
+ finalSequenceNumbers = append(finalSequenceNumbers, ccip.NewObservedMessage(seqNr, tallyInfo.tokenData))
+ }
+ // buildReport expects sorted sequence numbers (tally map is non-deterministic).
+ sort.Slice(finalSequenceNumbers, func(i, j int) bool {
+ return finalSequenceNumbers[i].SeqNr < finalSequenceNumbers[j].SeqNr
+ })
+ return finalSequenceNumbers, nil
+}
+
+func (r *ExecutionReportingPlugin) ShouldAcceptFinalizedReport(ctx context.Context, timestamp types.ReportTimestamp, report types.Report) (bool, error) {
+ lggr := r.lggr.Named("ShouldAcceptFinalizedReport")
+ execReport, err := r.offRampReader.DecodeExecutionReport(ctx, report)
+ if err != nil {
+ lggr.Errorw("Unable to decode report", "err", err)
+ return false, err
+ }
+ lggr = lggr.With("messageIDs", ccipcommon.GetMessageIDsAsHexString(execReport.Messages))
+
+ if healthy, err1 := r.chainHealthcheck.IsHealthy(ctx); err1 != nil {
+ return false, err1
+ } else if !healthy {
+ return false, ccip.ErrChainIsNotHealthy
+ }
+ // If the first message is executed already, this execution report is stale, and we do not accept it.
+ stale, err := r.isStaleReport(ctx, execReport.Messages)
+ if err != nil {
+ return false, err
+ }
+ if stale {
+ lggr.Info("Execution report is stale")
+ return false, nil
+ }
+ // Else just assume in flight
+ if err = r.inflightReports.add(lggr, execReport.Messages); err != nil {
+ return false, err
+ }
+ if len(execReport.Messages) > 0 {
+ r.metricsCollector.SequenceNumber(ccip.ShouldAccept, execReport.Messages[len(execReport.Messages)-1].SequenceNumber)
+ }
+ lggr.Info("Accepting finalized report")
+ return true, nil
+}
+
+func (r *ExecutionReportingPlugin) ShouldTransmitAcceptedReport(ctx context.Context, timestamp types.ReportTimestamp, report types.Report) (bool, error) {
+ lggr := r.lggr.Named("ShouldTransmitAcceptedReport")
+ execReport, err := r.offRampReader.DecodeExecutionReport(ctx, report)
+ if err != nil {
+ lggr.Errorw("Unable to decode report", "err", err)
+ return false, nil
+ }
+ lggr = lggr.With("messageIDs", ccipcommon.GetMessageIDsAsHexString(execReport.Messages))
+
+ if healthy, err1 := r.chainHealthcheck.IsHealthy(ctx); err1 != nil {
+ return false, err1
+ } else if !healthy {
+ return false, ccip.ErrChainIsNotHealthy
+ }
+ // If report is not stale we transmit.
+ // When the executeTransmitter enqueues the tx for tx manager,
+ // we mark it as execution_sent, removing it from the set of inflight messages.
+ stale, err := r.isStaleReport(ctx, execReport.Messages)
+ if err != nil {
+ return false, err
+ }
+ if stale {
+ lggr.Info("Execution report is stale")
+ return false, nil
+ }
+
+ lggr.Info("Transmitting finalized report")
+ return true, err
+}
+
+func (r *ExecutionReportingPlugin) isStaleReport(ctx context.Context, messages []cciptypes.EVM2EVMMessage) (bool, error) {
+ if len(messages) == 0 {
+ return true, fmt.Errorf("messages are empty")
+ }
+
+ // If the first message is executed already, this execution report is stale.
+ // Note the default execution state, including for arbitrary seq number not yet committed
+ // is ExecutionStateUntouched.
+ msgState, err := r.offRampReader.GetExecutionState(ctx, messages[0].SequenceNumber)
+ if err != nil {
+ return true, err
+ }
+ if state := cciptypes.MessageExecutionState(msgState); state == cciptypes.ExecutionStateFailure || state == cciptypes.ExecutionStateSuccess {
+ return true, nil
+ }
+
+ return false, nil
+}
+
+func (r *ExecutionReportingPlugin) Close() error {
+ return nil
+}
+
+func getInflightAggregateRateLimit(
+ lggr logger.Logger,
+ inflight []InflightInternalExecutionReport,
+ destTokenPrices map[cciptypes.Address]*big.Int,
+ sourceToDest map[cciptypes.Address]cciptypes.Address,
+) (*big.Int, error) {
+ inflightAggregateValue := big.NewInt(0)
+
+ for _, rep := range inflight {
+ for _, message := range rep.messages {
+ msgValue, err := aggregateTokenValue(lggr, destTokenPrices, sourceToDest, message.TokenAmounts)
+ if err != nil {
+ return nil, err
+ }
+ inflightAggregateValue.Add(inflightAggregateValue, msgValue)
+ }
+ }
+ return inflightAggregateValue, nil
+}
+
+// getTokensPrices returns token prices of the given price registry,
+// price values are USD per 1e18 of smallest token denomination, in base units 1e18 (e.g. 5$ = 5e18 USD per 1e18 units).
+// this function is used for price registry of both source and destination chains.
+func getTokensPrices(ctx context.Context, priceRegistry ccipdata.PriceRegistryReader, tokens []cciptypes.Address) (map[cciptypes.Address]*big.Int, error) {
+ tokenPrices := make(map[cciptypes.Address]*big.Int)
+
+ fetchedPrices, err := priceRegistry.GetTokenPrices(ctx, tokens)
+ if err != nil {
+ return nil, errors.Wrapf(err, "could not get token prices of %v", tokens)
+ }
+
+ // price registry should always return a price per token ordered by input tokens
+ if len(fetchedPrices) != len(tokens) {
+ return nil, fmt.Errorf("token prices length exp=%d actual=%d", len(tokens), len(fetchedPrices))
+ }
+
+ for i, token := range tokens {
+ // price of a token can never be zero
+ if fetchedPrices[i].Value.BitLen() == 0 {
+ priceRegistryAddress, err := priceRegistry.Address(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("get price registry address: %w", err)
+ }
+ return nil, fmt.Errorf("price of token %s is zero (price registry=%s)", token, priceRegistryAddress)
+ }
+
+ // price registry should not report different price for the same token
+ price, exists := tokenPrices[token]
+ if exists && fetchedPrices[i].Value.Cmp(price) != 0 {
+ return nil, fmt.Errorf("price registry reported different prices (%s and %s) for the same token %s",
+ fetchedPrices[i].Value, price, token)
+ }
+
+ tokenPrices[token] = fetchedPrices[i].Value
+ }
+
+ return tokenPrices, nil
+}
+
+type execTokenData struct {
+ rateLimiterTokenBucket cciptypes.TokenBucketRateLimit
+ sourceTokenPrices map[cciptypes.Address]*big.Int
+ destTokenPrices map[cciptypes.Address]*big.Int
+ sourceToDestTokens map[cciptypes.Address]cciptypes.Address
+ gasPrice *big.Int
+}
+
+// prepareTokenExecData gather all the pre-execution data needed for token execution into a single lazy call.
+// This is done to avoid fetching the data multiple times for each message. Additionally, most of the RPC calls
+// within that function is cached, so it should be relatively fast and not require any RPC batching.
+func (r *ExecutionReportingPlugin) prepareTokenExecData(ctx context.Context) (execTokenData, error) {
+ // This could result in slightly different values on each call as
+ // the function returns the allowed amount at the time of the last block.
+ // Since this will only increase over time, the highest observed value will
+ // always be the lower bound of what would be available on chain
+ // since we already account for inflight txs.
+ rateLimiterTokenBucket, err := r.offRampReader.CurrentRateLimiterState(ctx)
+ if err != nil {
+ return execTokenData{}, err
+ }
+
+ sourceFeeTokens, err := r.sourcePriceRegistry.GetFeeTokens(ctx)
+ if err != nil {
+ return execTokenData{}, fmt.Errorf("get source fee tokens: %w", err)
+ }
+ sourceTokensPrices, err := getTokensPrices(
+ ctx,
+ r.sourcePriceRegistry,
+ ccipcommon.FlattenUniqueSlice(
+ sourceFeeTokens,
+ []cciptypes.Address{r.sourceWrappedNativeToken},
+ ),
+ )
+ if err != nil {
+ return execTokenData{}, err
+ }
+
+ destFeeTokens, destBridgedTokens, err := ccipcommon.GetDestinationTokens(ctx, r.offRampReader, r.destPriceRegistry)
+ if err != nil {
+ return execTokenData{}, fmt.Errorf("get destination tokens: %w", err)
+ }
+ destTokenPrices, err := getTokensPrices(
+ ctx,
+ r.destPriceRegistry,
+ ccipcommon.FlattenUniqueSlice(
+ destFeeTokens,
+ destBridgedTokens,
+ []cciptypes.Address{r.destWrappedNative},
+ ),
+ )
+ if err != nil {
+ return execTokenData{}, err
+ }
+
+ sourceToDestTokens, err := r.offRampReader.GetSourceToDestTokensMapping(ctx)
+ if err != nil {
+ return execTokenData{}, err
+ }
+
+ gasPrice, err := r.gasPriceEstimator.GetGasPrice(ctx)
+ if err != nil {
+ return execTokenData{}, err
+ }
+
+ return execTokenData{
+ rateLimiterTokenBucket: rateLimiterTokenBucket,
+ sourceTokenPrices: sourceTokensPrices,
+ sourceToDestTokens: sourceToDestTokens,
+ destTokenPrices: destTokenPrices,
+ gasPrice: gasPrice,
+ }, nil
+}
+
+// ensurePriceRegistrySynchronization ensures that the source price registry points to the same as the one configured on the onRamp.
+// This is required since the price registry address on the onRamp can change over time.
+func (r *ExecutionReportingPlugin) ensurePriceRegistrySynchronization(ctx context.Context) error {
+ needPriceRegistryUpdate := false
+ r.sourcePriceRegistryLock.RLock()
+ priceRegistryAddress, err := r.onRampReader.SourcePriceRegistryAddress(ctx)
+ if err != nil {
+ r.sourcePriceRegistryLock.RUnlock()
+ return fmt.Errorf("getting price registry from onramp: %w", err)
+ }
+
+ currentPriceRegistryAddress := cciptypes.Address("")
+ if r.sourcePriceRegistry != nil {
+ currentPriceRegistryAddress, err = r.sourcePriceRegistry.Address(ctx)
+ if err != nil {
+ return fmt.Errorf("get current priceregistry address: %w", err)
+ }
+ }
+
+ needPriceRegistryUpdate = r.sourcePriceRegistry == nil || priceRegistryAddress != currentPriceRegistryAddress
+ r.sourcePriceRegistryLock.RUnlock()
+ if !needPriceRegistryUpdate {
+ return nil
+ }
+
+ // Update the price registry if required.
+ r.sourcePriceRegistryLock.Lock()
+ defer r.sourcePriceRegistryLock.Unlock()
+
+ // Price registry address changed or not initialized yet, updating source price registry.
+ sourcePriceRegistry, err := r.sourcePriceRegistryProvider.NewPriceRegistryReader(ctx, priceRegistryAddress)
+ if err != nil {
+ return err
+ }
+ oldPriceRegistry := r.sourcePriceRegistry
+ r.sourcePriceRegistry = sourcePriceRegistry
+ // Close the old price registry
+ if oldPriceRegistry != nil {
+ if err1 := oldPriceRegistry.Close(); err1 != nil {
+ r.lggr.Warnw("failed to close old price registry", "err", err1)
+ }
+ }
+ return nil
+}
+
+// selectReportsToFillBatch returns the reports to fill the message limit. Single Commit Root contains exactly (Interval.Max - Interval.Min + 1) messages.
+// We keep adding reports until we reach the message limit. Please see the tests for more examples and edge cases.
+// unexpiredReports have to be sorted by Interval.Min. Otherwise, the batching logic will not be efficient,
+// because it picks messages and execution states based on the report[0].Interval.Min - report[len-1].Interval.Max range.
+// Having unexpiredReports not sorted properly will lead to fetching more messages and execution states to the memory than the messagesLimit provided.
+// However, logs from LogPoller are returned ordered by (block_number, log_index), so it should preserve the order of Interval.Min.
+// Single CommitRoot can have up to 256 messages, with current MessagesIterationStep of 1024, it means processing 4 CommitRoots at once.
+func selectReportsToFillBatch(unexpiredReports []cciptypes.CommitStoreReport, messagesLimit uint64) ([]cciptypes.CommitStoreReport, int) {
+ currentNumberOfMessages := uint64(0)
+ nbReports := 0
+ for _, report := range unexpiredReports {
+ reportMsgCount := report.Interval.Max - report.Interval.Min + 1
+ if currentNumberOfMessages+reportMsgCount > messagesLimit {
+ break
+ }
+ currentNumberOfMessages += reportMsgCount
+ nbReports++
+ }
+ return unexpiredReports[:nbReports], nbReports
+}
diff --git a/core/services/ocr2/plugins/ccip/ccipexec/ocr2_test.go b/core/services/ocr2/plugins/ccip/ccipexec/ocr2_test.go
new file mode 100644
index 00000000000..84cb73c6643
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/ccipexec/ocr2_test.go
@@ -0,0 +1,1421 @@
+package ccipexec
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "math"
+ "math/big"
+ "reflect"
+ "sort"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/cometbft/cometbft/libs/rand"
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+ "github.com/smartcontractkit/libocr/commontypes"
+ "github.com/smartcontractkit/libocr/offchainreporting2/types"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ lpMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ ccipcachemocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader"
+ ccipdataprovidermocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/mocks"
+ ccipdatamocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+)
+
+func TestExecutionReportingPlugin_Observation(t *testing.T) {
+ testCases := []struct {
+ name string
+ commitStorePaused bool
+ sourceChainCursed bool
+ inflightReports []InflightInternalExecutionReport
+ unexpiredReports []cciptypes.CommitStoreReportWithTxMeta
+ sendRequests []cciptypes.EVM2EVMMessageWithTxMeta
+ executedSeqNums []uint64
+ tokenPoolsMapping map[common.Address]common.Address
+ blessedRoots map[[32]byte]bool
+ senderNonce uint64
+ rateLimiterState cciptypes.TokenBucketRateLimit
+ expErr bool
+ sourceChainHealthy bool
+ destChainHealthy bool
+ }{
+ {
+ name: "commit store is down",
+ commitStorePaused: true,
+ sourceChainCursed: false,
+ sourceChainHealthy: true,
+ destChainHealthy: true,
+ expErr: true,
+ },
+ {
+ name: "source chain is cursed",
+ commitStorePaused: false,
+ sourceChainCursed: true,
+ sourceChainHealthy: true,
+ destChainHealthy: true,
+ expErr: true,
+ },
+ {
+ name: "source chain not healthy",
+ commitStorePaused: false,
+ sourceChainCursed: false,
+ sourceChainHealthy: false,
+ destChainHealthy: true,
+ expErr: true,
+ },
+ {
+ name: "dest chain not healthy",
+ commitStorePaused: false,
+ sourceChainCursed: false,
+ sourceChainHealthy: true,
+ destChainHealthy: false,
+ expErr: true,
+ },
+ {
+ name: "happy flow",
+ commitStorePaused: false,
+ sourceChainCursed: false,
+ sourceChainHealthy: true,
+ destChainHealthy: true,
+ inflightReports: []InflightInternalExecutionReport{},
+ unexpiredReports: []cciptypes.CommitStoreReportWithTxMeta{
+ {
+ CommitStoreReport: cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{Min: 10, Max: 12},
+ MerkleRoot: [32]byte{123},
+ },
+ },
+ },
+ blessedRoots: map[[32]byte]bool{
+ {123}: true,
+ },
+ rateLimiterState: cciptypes.TokenBucketRateLimit{
+ IsEnabled: false,
+ },
+ tokenPoolsMapping: map[common.Address]common.Address{},
+ senderNonce: 9,
+ sendRequests: []cciptypes.EVM2EVMMessageWithTxMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 10, GasLimit: big.NewInt(0)},
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 11, GasLimit: big.NewInt(0)},
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 12, GasLimit: big.NewInt(0)},
+ },
+ },
+ },
+ }
+
+ ctx := testutils.Context(t)
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ p := &ExecutionReportingPlugin{}
+ p.inflightReports = newInflightExecReportsContainer(time.Minute)
+ p.inflightReports.reports = tc.inflightReports
+ p.lggr = logger.TestLogger(t)
+ p.tokenDataWorker = tokendata.NewBackgroundWorker(
+ make(map[cciptypes.Address]tokendata.Reader), 10, 5*time.Second, time.Hour)
+ p.metricsCollector = ccip.NoopMetricsCollector
+
+ commitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ commitStoreReader.On("IsDown", mock.Anything).Return(tc.commitStorePaused, nil).Maybe()
+ commitStoreReader.On("IsDestChainHealthy", mock.Anything).Return(tc.destChainHealthy, nil).Maybe()
+ // Blessed roots return true
+ for root, blessed := range tc.blessedRoots {
+ commitStoreReader.On("IsBlessed", mock.Anything, root).Return(blessed, nil).Maybe()
+ }
+ commitStoreReader.On("GetAcceptedCommitReportsGteTimestamp", ctx, mock.Anything, 0).
+ Return(tc.unexpiredReports, nil).Maybe()
+ p.commitStoreReader = commitStoreReader
+
+ var executionEvents []cciptypes.ExecutionStateChangedWithTxMeta
+ for _, seqNum := range tc.executedSeqNums {
+ executionEvents = append(executionEvents, cciptypes.ExecutionStateChangedWithTxMeta{
+ ExecutionStateChanged: cciptypes.ExecutionStateChanged{SequenceNumber: seqNum},
+ })
+ }
+
+ offRamp, _ := testhelpers.NewFakeOffRamp(t)
+ offRamp.SetRateLimiterState(tc.rateLimiterState)
+
+ tokenPoolBatchedReader, err := batchreader.NewEVMTokenPoolBatchedReader(p.lggr, 0, ccipcalc.EvmAddrToGeneric(offRamp.Address()), nil)
+ assert.NoError(t, err)
+ p.tokenPoolBatchedReader = tokenPoolBatchedReader
+
+ mockOffRampReader := ccipdatamocks.NewOffRampReader(t)
+ mockOffRampReader.On("GetExecutionStateChangesBetweenSeqNums", ctx, mock.Anything, mock.Anything, 0).
+ Return(executionEvents, nil).Maybe()
+ mockOffRampReader.On("CurrentRateLimiterState", mock.Anything).Return(tc.rateLimiterState, nil).Maybe()
+ mockOffRampReader.On("Address", ctx).Return(cciptypes.Address(offRamp.Address().String()), nil).Maybe()
+ senderNonces := map[cciptypes.Address]uint64{
+ cciptypes.Address(utils.RandomAddress().String()): tc.senderNonce,
+ }
+ mockOffRampReader.On("ListSenderNonces", mock.Anything, mock.Anything).Return(senderNonces, nil).Maybe()
+ mockOffRampReader.On("GetTokenPoolsRateLimits", ctx, []ccipdata.TokenPoolReader{}).
+ Return([]cciptypes.TokenBucketRateLimit{}, nil).Maybe()
+
+ mockOffRampReader.On("GetSourceToDestTokensMapping", ctx).Return(nil, nil).Maybe()
+ mockOffRampReader.On("GetTokens", ctx).Return(cciptypes.OffRampTokens{
+ DestinationTokens: []cciptypes.Address{},
+ SourceTokens: []cciptypes.Address{},
+ }, nil).Maybe()
+ p.offRampReader = mockOffRampReader
+
+ mockOnRampReader := ccipdatamocks.NewOnRampReader(t)
+ mockOnRampReader.On("IsSourceCursed", ctx).Return(tc.sourceChainCursed, nil).Maybe()
+ mockOnRampReader.On("IsSourceChainHealthy", ctx).Return(tc.sourceChainHealthy, nil).Maybe()
+ mockOnRampReader.On("GetSendRequestsBetweenSeqNums", ctx, mock.Anything, mock.Anything, false).
+ Return(tc.sendRequests, nil).Maybe()
+ sourcePriceRegistryAddress := cciptypes.Address(utils.RandomAddress().String())
+ mockOnRampReader.On("SourcePriceRegistryAddress", ctx).Return(sourcePriceRegistryAddress, nil).Maybe()
+ p.onRampReader = mockOnRampReader
+
+ mockGasPriceEstimator := prices.NewMockGasPriceEstimatorExec(t)
+ mockGasPriceEstimator.On("GetGasPrice", ctx).Return(big.NewInt(1), nil).Maybe()
+ p.gasPriceEstimator = mockGasPriceEstimator
+
+ destPriceRegReader := ccipdatamocks.NewPriceRegistryReader(t)
+ destPriceRegReader.On("GetTokenPrices", ctx, mock.Anything).Return(
+ []cciptypes.TokenPriceUpdate{{TokenPrice: cciptypes.TokenPrice{Token: ccipcalc.HexToAddress("0x1"), Value: big.NewInt(123)}, TimestampUnixSec: big.NewInt(time.Now().Unix())}}, nil).Maybe()
+ destPriceRegReader.On("Address", ctx).Return(cciptypes.Address(utils.RandomAddress().String()), nil).Maybe()
+ destPriceRegReader.On("GetFeeTokens", ctx).Return([]cciptypes.Address{}, nil).Maybe()
+ sourcePriceRegReader := ccipdatamocks.NewPriceRegistryReader(t)
+ sourcePriceRegReader.On("Address", ctx).Return(sourcePriceRegistryAddress, nil).Maybe()
+ sourcePriceRegReader.On("GetFeeTokens", ctx).Return([]cciptypes.Address{}, nil).Maybe()
+ sourcePriceRegReader.On("GetTokenPrices", ctx, mock.Anything).Return(
+ []cciptypes.TokenPriceUpdate{{TokenPrice: cciptypes.TokenPrice{Token: ccipcalc.HexToAddress("0x1"), Value: big.NewInt(123)}, TimestampUnixSec: big.NewInt(time.Now().Unix())}}, nil).Maybe()
+ p.destPriceRegistry = destPriceRegReader
+
+ mockOnRampPriceRegistryProvider := ccipdataprovidermocks.NewPriceRegistry(t)
+ mockOnRampPriceRegistryProvider.On("NewPriceRegistryReader", ctx, sourcePriceRegistryAddress).Return(sourcePriceRegReader, nil).Maybe()
+ p.sourcePriceRegistryProvider = mockOnRampPriceRegistryProvider
+
+ p.commitRootsCache = cache.NewCommitRootsCache(logger.TestLogger(t), commitStoreReader, time.Minute, time.Minute)
+ p.chainHealthcheck = cache.NewChainHealthcheck(p.lggr, mockOnRampReader, commitStoreReader)
+
+ bs := &BestEffortBatchingStrategy{}
+ p.batchingStrategy = bs
+
+ _, err = p.Observation(ctx, types.ReportTimestamp{}, types.Query{})
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ })
+ }
+}
+
+func TestExecutionReportingPlugin_Report(t *testing.T) {
+ testCases := []struct {
+ name string
+ f int
+ committedSeqNum uint64
+ observations []ccip.ExecutionObservation
+
+ expectingSomeReport bool
+ expectedReport cciptypes.ExecReport
+ expectingSomeErr bool
+ }{
+ {
+ name: "not enough observations to form consensus",
+ f: 5,
+ committedSeqNum: 5,
+ observations: []ccip.ExecutionObservation{
+ {Messages: map[uint64]ccip.MsgData{3: {}, 4: {}}},
+ {Messages: map[uint64]ccip.MsgData{3: {}, 4: {}}},
+ },
+ expectingSomeErr: false,
+ expectingSomeReport: false,
+ },
+ {
+ name: "zero observations",
+ f: 0,
+ committedSeqNum: 5,
+ observations: []ccip.ExecutionObservation{},
+ expectingSomeErr: false,
+ expectingSomeReport: false,
+ },
+ }
+
+ ctx := testutils.Context(t)
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ p := ExecutionReportingPlugin{}
+ p.lggr = logger.TestLogger(t)
+ p.F = tc.f
+
+ p.commitStoreReader = ccipdatamocks.NewCommitStoreReader(t)
+ chainHealthcheck := ccipcachemocks.NewChainHealthcheck(t)
+ chainHealthcheck.On("IsHealthy", ctx).Return(true, nil)
+ p.chainHealthcheck = chainHealthcheck
+
+ observations := make([]types.AttributedObservation, len(tc.observations))
+ for i := range observations {
+ b, err := json.Marshal(tc.observations[i])
+ assert.NoError(t, err)
+ observations[i] = types.AttributedObservation{Observation: b, Observer: commontypes.OracleID(i + 1)}
+ }
+
+ _, _, err := p.Report(ctx, types.ReportTimestamp{}, types.Query{}, observations)
+ if tc.expectingSomeErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ })
+ }
+}
+
+func TestExecutionReportingPlugin_ShouldAcceptFinalizedReport(t *testing.T) {
+ msg := cciptypes.EVM2EVMMessage{
+ SequenceNumber: 12,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: cciptypes.Address(utils.RandomAddress().String()),
+ Nonce: 1,
+ GasLimit: big.NewInt(1),
+ Strict: false,
+ Receiver: cciptypes.Address(utils.RandomAddress().String()),
+ Data: nil,
+ TokenAmounts: nil,
+ FeeToken: cciptypes.Address(utils.RandomAddress().String()),
+ MessageID: [32]byte{},
+ }
+ report := cciptypes.ExecReport{
+ Messages: []cciptypes.EVM2EVMMessage{msg},
+ OffchainTokenData: [][][]byte{{}},
+ Proofs: [][32]byte{{}},
+ ProofFlagBits: big.NewInt(1),
+ }
+
+ encodedReport := encodeExecutionReport(t, report)
+ mockOffRampReader := ccipdatamocks.NewOffRampReader(t)
+ mockOffRampReader.On("DecodeExecutionReport", mock.Anything, encodedReport).Return(report, nil)
+
+ chainHealthcheck := ccipcachemocks.NewChainHealthcheck(t)
+ chainHealthcheck.On("IsHealthy", mock.Anything).Return(true, nil)
+
+ plugin := ExecutionReportingPlugin{
+ offRampReader: mockOffRampReader,
+ lggr: logger.TestLogger(t),
+ inflightReports: newInflightExecReportsContainer(1 * time.Hour),
+ chainHealthcheck: chainHealthcheck,
+ metricsCollector: ccip.NoopMetricsCollector,
+ }
+
+ mockedExecState := mockOffRampReader.On("GetExecutionState", mock.Anything, uint64(12)).Return(uint8(cciptypes.ExecutionStateUntouched), nil).Once()
+
+ should, err := plugin.ShouldAcceptFinalizedReport(testutils.Context(t), ocrtypes.ReportTimestamp{}, encodedReport)
+ require.NoError(t, err)
+ assert.Equal(t, true, should)
+
+ mockedExecState.Return(uint8(cciptypes.ExecutionStateSuccess), nil).Once()
+
+ should, err = plugin.ShouldAcceptFinalizedReport(testutils.Context(t), ocrtypes.ReportTimestamp{}, encodedReport)
+ require.NoError(t, err)
+ assert.Equal(t, false, should)
+}
+
+func TestExecutionReportingPlugin_ShouldTransmitAcceptedReport(t *testing.T) {
+ msg := cciptypes.EVM2EVMMessage{
+ SequenceNumber: 12,
+ FeeTokenAmount: big.NewInt(1e9),
+ Sender: cciptypes.Address(utils.RandomAddress().String()),
+ Nonce: 1,
+ GasLimit: big.NewInt(1),
+ Strict: false,
+ Receiver: cciptypes.Address(utils.RandomAddress().String()),
+ Data: nil,
+ TokenAmounts: nil,
+ FeeToken: cciptypes.Address(utils.RandomAddress().String()),
+ MessageID: [32]byte{},
+ }
+ report := cciptypes.ExecReport{
+ Messages: []cciptypes.EVM2EVMMessage{msg},
+ OffchainTokenData: [][][]byte{{}},
+ Proofs: [][32]byte{{}},
+ ProofFlagBits: big.NewInt(1),
+ }
+ encodedReport := encodeExecutionReport(t, report)
+
+ mockCommitStoreReader := ccipdatamocks.NewCommitStoreReader(t)
+ mockOffRampReader := ccipdatamocks.NewOffRampReader(t)
+ mockOffRampReader.On("DecodeExecutionReport", mock.Anything, encodedReport).Return(report, nil)
+ mockedExecState := mockOffRampReader.On("GetExecutionState", mock.Anything, uint64(12)).Return(uint8(cciptypes.ExecutionStateUntouched), nil).Once()
+
+ chainHealthcheck := ccipcachemocks.NewChainHealthcheck(t)
+ chainHealthcheck.On("IsHealthy", mock.Anything).Return(true, nil)
+
+ plugin := ExecutionReportingPlugin{
+ commitStoreReader: mockCommitStoreReader,
+ offRampReader: mockOffRampReader,
+ lggr: logger.TestLogger(t),
+ inflightReports: newInflightExecReportsContainer(1 * time.Hour),
+ chainHealthcheck: chainHealthcheck,
+ }
+
+ should, err := plugin.ShouldTransmitAcceptedReport(testutils.Context(t), ocrtypes.ReportTimestamp{}, encodedReport)
+ require.NoError(t, err)
+ assert.Equal(t, true, should)
+
+ mockedExecState.Return(uint8(cciptypes.ExecutionStateFailure), nil).Once()
+ should, err = plugin.ShouldTransmitAcceptedReport(testutils.Context(t), ocrtypes.ReportTimestamp{}, encodedReport)
+ require.NoError(t, err)
+ assert.Equal(t, false, should)
+}
+
+func TestExecutionReportingPlugin_buildReport(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ const numMessages = 100
+ const tokensPerMessage = 20
+ const bytesPerMessage = 1000
+
+ executionReport := generateExecutionReport(t, numMessages, tokensPerMessage, bytesPerMessage)
+ encodedReport := encodeExecutionReport(t, executionReport)
+ // ensure "naive" full report would be bigger than limit
+ assert.Greater(t, len(encodedReport), MaxExecutionReportLength, "full execution report length")
+
+ observations := make([]ccip.ObservedMessage, len(executionReport.Messages))
+ for i, msg := range executionReport.Messages {
+ observations[i] = ccip.NewObservedMessage(msg.SequenceNumber, executionReport.OffchainTokenData[i])
+ }
+
+ // ensure that buildReport should cap the built report to fit in MaxExecutionReportLength
+ p := &ExecutionReportingPlugin{}
+ p.lggr = logger.TestLogger(t)
+
+ commitStore := ccipdatamocks.NewCommitStoreReader(t)
+ commitStore.On("VerifyExecutionReport", mock.Anything, mock.Anything, mock.Anything).Return(true, nil)
+ commitStore.On("GetExpectedNextSequenceNumber", mock.Anything).
+ Return(executionReport.Messages[len(executionReport.Messages)-1].SequenceNumber+1, nil)
+ commitStore.On("GetCommitReportMatchingSeqNum", ctx, observations[0].SeqNr, 0).
+ Return([]cciptypes.CommitStoreReportWithTxMeta{
+ {
+ CommitStoreReport: cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{
+ Min: observations[0].SeqNr,
+ Max: observations[len(observations)-1].SeqNr,
+ },
+ },
+ },
+ }, nil)
+ p.metricsCollector = ccip.NoopMetricsCollector
+ p.commitStoreReader = commitStore
+
+ lp := lpMocks.NewLogPoller(t)
+ offRampReader, err := v1_0_0.NewOffRamp(logger.TestLogger(t), utils.RandomAddress(), nil, lp, nil, nil)
+ assert.NoError(t, err)
+ p.offRampReader = offRampReader
+
+ sendReqs := make([]cciptypes.EVM2EVMMessageWithTxMeta, len(observations))
+ sourceReader := ccipdatamocks.NewOnRampReader(t)
+ for i := range observations {
+ msg := cciptypes.EVM2EVMMessage{
+ SourceChainSelector: math.MaxUint64,
+ SequenceNumber: uint64(i + 1),
+ FeeTokenAmount: big.NewInt(math.MaxInt64),
+ Sender: cciptypes.Address(utils.RandomAddress().String()),
+ Nonce: math.MaxUint64,
+ GasLimit: big.NewInt(math.MaxInt64),
+ Strict: false,
+ Receiver: cciptypes.Address(utils.RandomAddress().String()),
+ Data: bytes.Repeat([]byte{0}, bytesPerMessage),
+ TokenAmounts: nil,
+ FeeToken: cciptypes.Address(utils.RandomAddress().String()),
+ MessageID: [32]byte{12},
+ }
+ sendReqs[i] = cciptypes.EVM2EVMMessageWithTxMeta{EVM2EVMMessage: msg}
+ }
+ sourceReader.On("GetSendRequestsBetweenSeqNums",
+ ctx, observations[0].SeqNr, observations[len(observations)-1].SeqNr, false).Return(sendReqs, nil)
+ p.onRampReader = sourceReader
+
+ execReport, err := p.buildReport(ctx, p.lggr, observations)
+ assert.NoError(t, err)
+ assert.LessOrEqual(t, len(execReport), MaxExecutionReportLength, "built execution report length")
+}
+
+func TestExecutionReportingPlugin_getReportsWithSendRequests(t *testing.T) {
+ testCases := []struct {
+ name string
+ reports []cciptypes.CommitStoreReport
+ expQueryMin uint64 // expected min/max used in the query to get ccipevents
+ expQueryMax uint64
+ onchainEvents []cciptypes.EVM2EVMMessageWithTxMeta
+ destExecutedSeqNums []uint64
+
+ expReports []commitReportWithSendRequests
+ expErr bool
+ }{
+ {
+ name: "no reports",
+ reports: nil,
+ expReports: nil,
+ expErr: false,
+ },
+ {
+ name: "two reports happy flow",
+ reports: []cciptypes.CommitStoreReport{
+ {
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 2},
+ MerkleRoot: [32]byte{100},
+ },
+ {
+ Interval: cciptypes.CommitStoreInterval{Min: 3, Max: 3},
+ MerkleRoot: [32]byte{200},
+ },
+ },
+ expQueryMin: 1,
+ expQueryMax: 3,
+ onchainEvents: []cciptypes.EVM2EVMMessageWithTxMeta{
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 1}},
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 2}},
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 3}},
+ },
+ destExecutedSeqNums: []uint64{1},
+ expReports: []commitReportWithSendRequests{
+ {
+ commitReport: cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 2},
+ MerkleRoot: [32]byte{100},
+ },
+ sendRequestsWithMeta: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 1},
+ Executed: true,
+ Finalized: true,
+ },
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 2},
+ Executed: false,
+ Finalized: false,
+ },
+ },
+ },
+ {
+ commitReport: cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{Min: 3, Max: 3},
+ MerkleRoot: [32]byte{200},
+ },
+ sendRequestsWithMeta: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 3},
+ Executed: false,
+ Finalized: false,
+ },
+ },
+ },
+ },
+ expErr: false,
+ },
+ }
+
+ ctx := testutils.Context(t)
+ lggr := logger.TestLogger(t)
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ p := &ExecutionReportingPlugin{}
+ p.lggr = lggr
+
+ offRampReader := ccipdatamocks.NewOffRampReader(t)
+ p.offRampReader = offRampReader
+
+ sourceReader := ccipdatamocks.NewOnRampReader(t)
+ sourceReader.On("GetSendRequestsBetweenSeqNums", ctx, tc.expQueryMin, tc.expQueryMax, false).
+ Return(tc.onchainEvents, nil).Maybe()
+ p.onRampReader = sourceReader
+
+ finalized := make(map[uint64]cciptypes.FinalizedStatus)
+ for _, r := range tc.expReports {
+ for _, s := range r.sendRequestsWithMeta {
+ finalized[s.SequenceNumber] = cciptypes.FinalizedStatusNotFinalized
+ if s.Finalized {
+ finalized[s.SequenceNumber] = cciptypes.FinalizedStatusFinalized
+ }
+ }
+ }
+
+ var executedEvents []cciptypes.ExecutionStateChangedWithTxMeta
+ for _, executedSeqNum := range tc.destExecutedSeqNums {
+ executedEvents = append(executedEvents, cciptypes.ExecutionStateChangedWithTxMeta{
+ ExecutionStateChanged: cciptypes.ExecutionStateChanged{
+ SequenceNumber: executedSeqNum,
+ },
+ TxMeta: cciptypes.TxMeta{
+ Finalized: finalized[executedSeqNum],
+ },
+ })
+ }
+ offRampReader.On("GetExecutionStateChangesBetweenSeqNums", ctx, tc.expQueryMin, tc.expQueryMax, 0).Return(executedEvents, nil).Maybe()
+
+ populatedReports, err := p.getReportsWithSendRequests(ctx, tc.reports)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equal(t, len(tc.expReports), len(populatedReports))
+ for i, expReport := range tc.expReports {
+ assert.Equal(t, len(expReport.sendRequestsWithMeta), len(populatedReports[i].sendRequestsWithMeta))
+ for j, expReq := range expReport.sendRequestsWithMeta {
+ assert.Equal(t, expReq.Executed, populatedReports[i].sendRequestsWithMeta[j].Executed)
+ assert.Equal(t, expReq.Finalized, populatedReports[i].sendRequestsWithMeta[j].Finalized)
+ assert.Equal(t, expReq.SequenceNumber, populatedReports[i].sendRequestsWithMeta[j].SequenceNumber)
+ }
+ }
+ })
+ }
+}
+
+func Test_calculateObservedMessagesConsensus(t *testing.T) {
+ type args struct {
+ observations []ccip.ExecutionObservation
+ f int
+ }
+ tests := []struct {
+ name string
+ args args
+ want []ccip.ObservedMessage
+ }{
+ {
+ name: "no observations",
+ args: args{
+ observations: nil,
+ f: 0,
+ },
+ want: []ccip.ObservedMessage{},
+ },
+ {
+ name: "common path",
+ args: args{
+ observations: []ccip.ExecutionObservation{
+ {
+ Messages: map[uint64]ccip.MsgData{
+ 1: {TokenData: [][]byte{{0x1}, {0x1}, {0x1}}},
+ 2: {TokenData: [][]byte{{0x2}, {0x2}, {0x2}}},
+ },
+ },
+ {
+ Messages: map[uint64]ccip.MsgData{
+ 1: {TokenData: [][]byte{{0x1}, {0x1}, {0xff}}}, // different token data - should not be picked
+ 2: {TokenData: [][]byte{{0x2}, {0x2}, {0x2}}},
+ 3: {TokenData: [][]byte{{0x3}, {0x3}, {0x3}}},
+ },
+ },
+ {
+ Messages: map[uint64]ccip.MsgData{
+ 1: {TokenData: [][]byte{{0x1}, {0x1}, {0x1}}},
+ 2: {TokenData: [][]byte{{0x2}, {0x2}, {0x2}}},
+ },
+ },
+ },
+ f: 1,
+ },
+ want: []ccip.ObservedMessage{
+ {SeqNr: 1, MsgData: ccip.MsgData{TokenData: [][]byte{{0x1}, {0x1}, {0x1}}}},
+ {SeqNr: 2, MsgData: ccip.MsgData{TokenData: [][]byte{{0x2}, {0x2}, {0x2}}}},
+ },
+ },
+ {
+ name: "similar token data",
+ args: args{
+ observations: []ccip.ExecutionObservation{
+ {
+ Messages: map[uint64]ccip.MsgData{
+ 1: {TokenData: [][]byte{{0x1}, {0x1}, {0x1}}},
+ },
+ },
+ {
+ Messages: map[uint64]ccip.MsgData{
+ 1: {TokenData: [][]byte{{0x1}, {0x1, 0x1}}},
+ },
+ },
+ {
+ Messages: map[uint64]ccip.MsgData{
+ 1: {TokenData: [][]byte{{0x1}, {0x1, 0x1}}},
+ },
+ },
+ },
+ f: 1,
+ },
+ want: []ccip.ObservedMessage{
+ {SeqNr: 1, MsgData: ccip.MsgData{TokenData: [][]byte{{0x1}, {0x1, 0x1}}}},
+ },
+ },
+ {
+ name: "results should be deterministic",
+ args: args{
+ observations: []ccip.ExecutionObservation{
+ {Messages: map[uint64]ccip.MsgData{1: {TokenData: [][]byte{{0x2}}}}},
+ {Messages: map[uint64]ccip.MsgData{1: {TokenData: [][]byte{{0x2}}}}},
+ {Messages: map[uint64]ccip.MsgData{1: {TokenData: [][]byte{{0x1}}}}},
+ {Messages: map[uint64]ccip.MsgData{1: {TokenData: [][]byte{{0x3}}}}},
+ {Messages: map[uint64]ccip.MsgData{1: {TokenData: [][]byte{{0x3}}}}},
+ {Messages: map[uint64]ccip.MsgData{1: {TokenData: [][]byte{{0x1}}}}},
+ },
+ f: 1,
+ },
+ want: []ccip.ObservedMessage{
+ {SeqNr: 1, MsgData: ccip.MsgData{TokenData: [][]byte{{0x3}}}},
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ res, err := calculateObservedMessagesConsensus(
+ tt.args.observations,
+ tt.args.f,
+ )
+ assert.NoError(t, err)
+ sort.Slice(res, func(i, j int) bool {
+ return res[i].SeqNr < res[j].SeqNr
+ })
+ assert.Equalf(t, tt.want, res, "calculateObservedMessagesConsensus(%v, %v)", tt.args.observations, tt.args.f)
+ })
+ }
+}
+
+func Test_getTokensPrices(t *testing.T) {
+ tk1 := ccipcalc.HexToAddress("1")
+ tk2 := ccipcalc.HexToAddress("2")
+ tk3 := ccipcalc.HexToAddress("3")
+
+ testCases := []struct {
+ name string
+ feeTokens []cciptypes.Address
+ tokens []cciptypes.Address
+ retPrices []cciptypes.TokenPriceUpdate
+ expPrices map[cciptypes.Address]*big.Int
+ expErr bool
+ }{
+ {
+ name: "base",
+ feeTokens: []cciptypes.Address{tk1, tk2},
+ tokens: []cciptypes.Address{tk3},
+ retPrices: []cciptypes.TokenPriceUpdate{
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(10)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(20)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(30)}},
+ },
+ expPrices: map[cciptypes.Address]*big.Int{
+ tk1: big.NewInt(10),
+ tk2: big.NewInt(20),
+ tk3: big.NewInt(30),
+ },
+ expErr: false,
+ },
+ {
+ name: "token is both fee token and normal token",
+ feeTokens: []cciptypes.Address{tk1, tk2},
+ tokens: []cciptypes.Address{tk3, tk1},
+ retPrices: []cciptypes.TokenPriceUpdate{
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(10)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(20)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(30)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(10)}},
+ },
+ expPrices: map[cciptypes.Address]*big.Int{
+ tk1: big.NewInt(10),
+ tk2: big.NewInt(20),
+ tk3: big.NewInt(30),
+ },
+ expErr: false,
+ },
+ {
+ name: "token is both fee token and normal token and price registry gave different price",
+ feeTokens: []cciptypes.Address{tk1, tk2},
+ tokens: []cciptypes.Address{tk3, tk1},
+ retPrices: []cciptypes.TokenPriceUpdate{
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(10)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(20)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(30)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(1000)}},
+ },
+ expErr: true,
+ },
+ {
+ name: "contract returns less prices than requested",
+ feeTokens: []cciptypes.Address{tk1, tk2},
+ tokens: []cciptypes.Address{tk3},
+ retPrices: []cciptypes.TokenPriceUpdate{
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(10)}},
+ {TokenPrice: cciptypes.TokenPrice{Value: big.NewInt(20)}},
+ },
+ expErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ priceReg := ccipdatamocks.NewPriceRegistryReader(t)
+ priceReg.On("GetTokenPrices", mock.Anything, mock.Anything).Return(tc.retPrices, nil)
+ priceReg.On("Address", mock.Anything).Return(cciptypes.Address(utils.RandomAddress().String()), nil).Maybe()
+
+ tokenPrices, err := getTokensPrices(context.Background(), priceReg, append(tc.feeTokens, tc.tokens...))
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+
+ assert.NoError(t, err)
+ for tk, price := range tc.expPrices {
+ assert.Equal(t, price, tokenPrices[tk])
+ }
+ })
+ }
+}
+
+func Test_calculateMessageMaxGas(t *testing.T) {
+ type args struct {
+ gasLimit *big.Int
+ numRequests int
+ dataLen int
+ numTokens int
+ }
+ tests := []struct {
+ name string
+ args args
+ want uint64
+ wantErr bool
+ }{
+ {
+ name: "base",
+ args: args{gasLimit: big.NewInt(1000), numRequests: 5, dataLen: 5, numTokens: 2},
+ want: 826_336,
+ wantErr: false,
+ },
+ {
+ name: "large",
+ args: args{gasLimit: big.NewInt(1000), numRequests: 1000, dataLen: 1000, numTokens: 1000},
+ want: 346_485_176,
+ wantErr: false,
+ },
+ {
+ name: "gas limit overflow",
+ args: args{gasLimit: big.NewInt(0).Mul(big.NewInt(math.MaxInt64), big.NewInt(math.MaxInt64))},
+ want: 36_391_540,
+ wantErr: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := calculateMessageMaxGas(tt.args.gasLimit, tt.args.numRequests, tt.args.dataLen, tt.args.numTokens)
+ if tt.wantErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equalf(t, tt.want, got, "calculateMessageMaxGas(%v, %v, %v, %v)", tt.args.gasLimit, tt.args.numRequests, tt.args.dataLen, tt.args.numTokens)
+ })
+ }
+}
+
+func Test_inflightAggregates(t *testing.T) {
+ const n = 10
+ addrs := make([]cciptypes.Address, n)
+ tokenAddrs := make([]cciptypes.Address, n)
+ for i := range addrs {
+ addrs[i] = cciptypes.Address(utils.RandomAddress().String())
+ tokenAddrs[i] = cciptypes.Address(utils.RandomAddress().String())
+ }
+ lggr := logger.TestLogger(t)
+
+ testCases := []struct {
+ name string
+ inflight []InflightInternalExecutionReport
+ destTokenPrices map[cciptypes.Address]*big.Int
+ sourceToDest map[cciptypes.Address]cciptypes.Address
+
+ expInflightSeqNrs mapset.Set[uint64]
+ expInflightAggrVal *big.Int
+ expMaxInflightSenderNonces map[cciptypes.Address]uint64
+ expInflightTokenAmounts map[cciptypes.Address]*big.Int
+ expErr bool
+ }{
+ {
+ name: "base",
+ inflight: []InflightInternalExecutionReport{
+ {
+ messages: []cciptypes.EVM2EVMMessage{
+ {
+ Sender: addrs[0],
+ SequenceNumber: 100,
+ Nonce: 2,
+ TokenAmounts: []cciptypes.TokenAmount{
+ {Token: tokenAddrs[0], Amount: big.NewInt(1e18)},
+ {Token: tokenAddrs[0], Amount: big.NewInt(2e18)},
+ },
+ },
+ {
+ Sender: addrs[0],
+ SequenceNumber: 106,
+ Nonce: 4,
+ TokenAmounts: []cciptypes.TokenAmount{
+ {Token: tokenAddrs[0], Amount: big.NewInt(1e18)},
+ {Token: tokenAddrs[0], Amount: big.NewInt(5e18)},
+ {Token: tokenAddrs[2], Amount: big.NewInt(5e18)},
+ },
+ },
+ },
+ },
+ },
+ destTokenPrices: map[cciptypes.Address]*big.Int{
+ tokenAddrs[1]: big.NewInt(1000),
+ tokenAddrs[3]: big.NewInt(500),
+ },
+ sourceToDest: map[cciptypes.Address]cciptypes.Address{
+ tokenAddrs[0]: tokenAddrs[1],
+ tokenAddrs[2]: tokenAddrs[3],
+ },
+ expInflightSeqNrs: mapset.NewSet[uint64](100, 106),
+ expInflightAggrVal: big.NewInt(9*1000 + 5*500),
+ expMaxInflightSenderNonces: map[cciptypes.Address]uint64{
+ addrs[0]: 4,
+ },
+ expInflightTokenAmounts: map[cciptypes.Address]*big.Int{
+ tokenAddrs[0]: big.NewInt(9e18),
+ tokenAddrs[2]: big.NewInt(5e18),
+ },
+ expErr: false,
+ },
+ {
+ name: "missing price should be 0",
+ inflight: []InflightInternalExecutionReport{
+ {
+ messages: []cciptypes.EVM2EVMMessage{
+ {
+ Sender: addrs[0],
+ SequenceNumber: 100,
+ Nonce: 2,
+ TokenAmounts: []cciptypes.TokenAmount{
+ {Token: tokenAddrs[0], Amount: big.NewInt(1e18)},
+ },
+ },
+ },
+ },
+ },
+ destTokenPrices: map[cciptypes.Address]*big.Int{
+ tokenAddrs[3]: big.NewInt(500),
+ },
+ sourceToDest: map[cciptypes.Address]cciptypes.Address{
+ tokenAddrs[2]: tokenAddrs[3],
+ },
+ expInflightAggrVal: big.NewInt(0),
+ expErr: false,
+ },
+ {
+ name: "nothing inflight",
+ inflight: []InflightInternalExecutionReport{},
+ expInflightSeqNrs: mapset.NewSet[uint64](),
+ expInflightAggrVal: big.NewInt(0),
+ expMaxInflightSenderNonces: map[cciptypes.Address]uint64{},
+ expInflightTokenAmounts: map[cciptypes.Address]*big.Int{},
+ expErr: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ inflightAggrVal, err := getInflightAggregateRateLimit(
+ lggr,
+ tc.inflight,
+ tc.destTokenPrices,
+ tc.sourceToDest,
+ )
+
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.True(t, reflect.DeepEqual(tc.expInflightAggrVal, inflightAggrVal))
+ })
+ }
+}
+
+func Test_commitReportWithSendRequests_validate(t *testing.T) {
+ testCases := []struct {
+ name string
+ reportInterval cciptypes.CommitStoreInterval
+ numReqs int
+ expValid bool
+ }{
+ {
+ name: "valid report",
+ reportInterval: cciptypes.CommitStoreInterval{Min: 10, Max: 20},
+ numReqs: 11,
+ expValid: true,
+ },
+ {
+ name: "report with one request",
+ reportInterval: cciptypes.CommitStoreInterval{Min: 1234, Max: 1234},
+ numReqs: 1,
+ expValid: true,
+ },
+ {
+ name: "request is missing",
+ reportInterval: cciptypes.CommitStoreInterval{Min: 1234, Max: 1234},
+ numReqs: 0,
+ expValid: false,
+ },
+ {
+ name: "requests are missing",
+ reportInterval: cciptypes.CommitStoreInterval{Min: 1, Max: 10},
+ numReqs: 5,
+ expValid: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ rep := commitReportWithSendRequests{
+ commitReport: cciptypes.CommitStoreReport{
+ Interval: tc.reportInterval,
+ },
+ sendRequestsWithMeta: make([]cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tc.numReqs),
+ }
+ err := rep.validate()
+ isValid := err == nil
+ assert.Equal(t, tc.expValid, isValid)
+ })
+ }
+}
+
+func Test_commitReportWithSendRequests_allRequestsAreExecutedAndFinalized(t *testing.T) {
+ testCases := []struct {
+ name string
+ reqs []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta
+ expRes bool
+ }{
+ {
+ name: "all requests executed and finalized",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {Executed: true, Finalized: true},
+ {Executed: true, Finalized: true},
+ {Executed: true, Finalized: true},
+ },
+ expRes: true,
+ },
+ {
+ name: "true when there are zero requests",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{},
+ expRes: true,
+ },
+ {
+ name: "some request not executed",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {Executed: true, Finalized: true},
+ {Executed: true, Finalized: true},
+ {Executed: false, Finalized: true},
+ },
+ expRes: false,
+ },
+ {
+ name: "some request not finalized",
+ reqs: []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {Executed: true, Finalized: true},
+ {Executed: true, Finalized: true},
+ {Executed: true, Finalized: false},
+ },
+ expRes: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ rep := commitReportWithSendRequests{sendRequestsWithMeta: tc.reqs}
+ res := rep.allRequestsAreExecutedAndFinalized()
+ assert.Equal(t, tc.expRes, res)
+ })
+ }
+}
+
+func Test_commitReportWithSendRequests_sendReqFits(t *testing.T) {
+ testCases := []struct {
+ name string
+ req cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta
+ report cciptypes.CommitStoreReport
+ expRes bool
+ }{
+ {
+ name: "all requests executed and finalized",
+ req: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 1},
+ },
+ report: cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 10},
+ },
+ expRes: true,
+ },
+ {
+ name: "all requests executed and finalized",
+ req: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 10},
+ },
+ report: cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 10},
+ },
+ expRes: true,
+ },
+ {
+ name: "all requests executed and finalized",
+ req: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 11},
+ },
+ report: cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 10},
+ },
+ expRes: false,
+ },
+ {
+ name: "all requests executed and finalized",
+ req: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 10},
+ },
+ report: cciptypes.CommitStoreReport{
+ Interval: cciptypes.CommitStoreInterval{Min: 10, Max: 10},
+ },
+ expRes: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ r := &commitReportWithSendRequests{commitReport: tc.report}
+ assert.Equal(t, tc.expRes, r.sendReqFits(tc.req))
+ })
+ }
+}
+
+// generateExecutionReport generates an execution report that can be used in tests
+func generateExecutionReport(t *testing.T, numMsgs, tokensPerMsg, bytesPerMsg int) cciptypes.ExecReport {
+ messages := make([]cciptypes.EVM2EVMMessage, numMsgs)
+
+ randAddr := func() cciptypes.Address {
+ return cciptypes.Address(utils.RandomAddress().String())
+ }
+
+ offChainTokenData := make([][][]byte, numMsgs)
+ for i := range messages {
+ tokenAmounts := make([]cciptypes.TokenAmount, tokensPerMsg)
+ for j := range tokenAmounts {
+ tokenAmounts[j] = cciptypes.TokenAmount{
+ Token: randAddr(),
+ Amount: big.NewInt(math.MaxInt64),
+ }
+ }
+
+ messages[i] = cciptypes.EVM2EVMMessage{
+ SourceChainSelector: rand.Uint64(),
+ SequenceNumber: uint64(i + 1),
+ FeeTokenAmount: big.NewInt(rand.Int64()),
+ Sender: randAddr(),
+ Nonce: rand.Uint64(),
+ GasLimit: big.NewInt(rand.Int64()),
+ Strict: false,
+ Receiver: randAddr(),
+ Data: bytes.Repeat([]byte{1}, bytesPerMsg),
+ TokenAmounts: tokenAmounts,
+ FeeToken: randAddr(),
+ MessageID: utils.RandomBytes32(),
+ }
+
+ data := []byte(`{"foo": "bar"}`)
+ offChainTokenData[i] = [][]byte{data, data, data}
+ }
+
+ return cciptypes.ExecReport{
+ Messages: messages,
+ OffchainTokenData: offChainTokenData,
+ Proofs: make([][32]byte, numMsgs),
+ ProofFlagBits: big.NewInt(rand.Int64()),
+ }
+}
+
+func Test_selectReportsToFillBatch(t *testing.T) {
+ tests := []struct {
+ name string
+ messagesLimit uint64 // maximum number of messages that can be included in a batch.
+ expectedBatches int // expected number of batches.
+ expectedReports int // expected number of selected reports.
+ }{
+ {
+ name: "pick all at once when messages limit is high",
+ messagesLimit: 5000,
+ expectedBatches: 1,
+ expectedReports: 10,
+ },
+ {
+ name: "pick none when messages limit is below commit report size",
+ messagesLimit: 199,
+ expectedBatches: 0,
+ expectedReports: 0,
+ },
+ {
+ name: "pick exactly the number in each report",
+ messagesLimit: 200,
+ expectedBatches: 10,
+ expectedReports: 10,
+ },
+ {
+ name: "messages limit larger than individual reports",
+ messagesLimit: 300,
+ expectedBatches: 10,
+ expectedReports: 10,
+ },
+ {
+ name: "messages limit larger than several reports",
+ messagesLimit: 650,
+ expectedBatches: 4,
+ expectedReports: 10,
+ },
+ {
+ name: "default limit",
+ messagesLimit: 1024,
+ expectedBatches: 2,
+ expectedReports: 10,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ nbCommitStoreReports := 10
+ nbMsgPerRoot := 200
+
+ var reports []cciptypes.CommitStoreReport
+ for i := 0; i < nbCommitStoreReports; i++ {
+ reports = append(reports, cciptypes.CommitStoreReport{Interval: cciptypes.CommitStoreInterval{Min: uint64(i * nbMsgPerRoot), Max: uint64((i+1)*nbMsgPerRoot - 1)}})
+ }
+
+ var unexpiredReportsBatches [][]cciptypes.CommitStoreReport
+ for i := 0; i < len(reports); {
+ unexpiredReports, step := selectReportsToFillBatch(reports[i:], tt.messagesLimit)
+ if step == 0 {
+ break
+ }
+ unexpiredReportsBatches = append(unexpiredReportsBatches, unexpiredReports)
+ i += step
+ }
+ assert.Len(t, unexpiredReportsBatches, tt.expectedBatches)
+
+ var flatten []cciptypes.CommitStoreReport
+ for _, r := range unexpiredReportsBatches {
+ flatten = append(flatten, r...)
+ }
+ assert.Equal(t, tt.expectedReports, len(flatten))
+ if tt.expectedBatches > 0 {
+ assert.Equal(t, reports, flatten)
+ } else {
+ assert.Empty(t, flatten)
+ }
+ })
+ }
+}
+
+func Test_prepareTokenExecData(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ weth := cciptypes.Address(utils.RandomAddress().String())
+ wavax := cciptypes.Address(utils.RandomAddress().String())
+ link := cciptypes.Address(utils.RandomAddress().String())
+ usdc := cciptypes.Address(utils.RandomAddress().String())
+
+ wethPriceUpdate := cciptypes.TokenPriceUpdate{TokenPrice: cciptypes.TokenPrice{Token: weth, Value: big.NewInt(2e18)}}
+ wavaxPriceUpdate := cciptypes.TokenPriceUpdate{TokenPrice: cciptypes.TokenPrice{Token: wavax, Value: big.NewInt(3e18)}}
+ linkPriceUpdate := cciptypes.TokenPriceUpdate{TokenPrice: cciptypes.TokenPrice{Token: link, Value: big.NewInt(4e18)}}
+ usdcPriceUpdate := cciptypes.TokenPriceUpdate{TokenPrice: cciptypes.TokenPrice{Token: usdc, Value: big.NewInt(5e18)}}
+
+ tokenPrices := map[cciptypes.Address]cciptypes.TokenPriceUpdate{weth: wethPriceUpdate, wavax: wavaxPriceUpdate, link: linkPriceUpdate, usdc: usdcPriceUpdate}
+
+ tests := []struct {
+ name string
+ sourceFeeTokens []cciptypes.Address
+ sourceFeeTokensErr error
+ destTokens []cciptypes.Address
+ destTokensErr error
+ destFeeTokens []cciptypes.Address
+ destFeeTokensErr error
+ sourcePrices []cciptypes.TokenPriceUpdate
+ destPrices []cciptypes.TokenPriceUpdate
+ }{
+ {
+ name: "only native token",
+ sourcePrices: []cciptypes.TokenPriceUpdate{wethPriceUpdate},
+ destPrices: []cciptypes.TokenPriceUpdate{wavaxPriceUpdate},
+ },
+ {
+ name: "additional dest fee token",
+ destFeeTokens: []cciptypes.Address{link},
+ sourcePrices: []cciptypes.TokenPriceUpdate{wethPriceUpdate},
+ destPrices: []cciptypes.TokenPriceUpdate{linkPriceUpdate, wavaxPriceUpdate},
+ },
+ {
+ name: "dest tokens",
+ destTokens: []cciptypes.Address{link, usdc},
+ sourcePrices: []cciptypes.TokenPriceUpdate{wethPriceUpdate},
+ destPrices: []cciptypes.TokenPriceUpdate{linkPriceUpdate, usdcPriceUpdate, wavaxPriceUpdate},
+ },
+ {
+ name: "source fee tokens",
+ sourceFeeTokens: []cciptypes.Address{usdc},
+ sourcePrices: []cciptypes.TokenPriceUpdate{usdcPriceUpdate, wethPriceUpdate},
+ destPrices: []cciptypes.TokenPriceUpdate{wavaxPriceUpdate},
+ },
+ {
+ name: "source, dest and fee tokens",
+ sourceFeeTokens: []cciptypes.Address{usdc},
+ destTokens: []cciptypes.Address{link},
+ destFeeTokens: []cciptypes.Address{usdc},
+ sourcePrices: []cciptypes.TokenPriceUpdate{usdcPriceUpdate, wethPriceUpdate},
+ destPrices: []cciptypes.TokenPriceUpdate{usdcPriceUpdate, linkPriceUpdate, wavaxPriceUpdate},
+ },
+ {
+ name: "source, dest and fee tokens with duplicates",
+ sourceFeeTokens: []cciptypes.Address{link, weth},
+ destTokens: []cciptypes.Address{link, wavax},
+ destFeeTokens: []cciptypes.Address{link, wavax},
+ sourcePrices: []cciptypes.TokenPriceUpdate{linkPriceUpdate, wethPriceUpdate},
+ destPrices: []cciptypes.TokenPriceUpdate{linkPriceUpdate, wavaxPriceUpdate},
+ },
+ {
+ name: "everything fails when source fails",
+ sourceFeeTokensErr: errors.New("source error"),
+ },
+ {
+ name: "everything fails when dest fee fails",
+ destFeeTokensErr: errors.New("dest fee error"),
+ },
+ {
+ name: "everything fails when dest fails",
+ destTokensErr: errors.New("dest error"),
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ onrampReader := ccipdatamocks.NewOnRampReader(t)
+ offrampReader := ccipdatamocks.NewOffRampReader(t)
+ sourcePriceRegistry := ccipdatamocks.NewPriceRegistryReader(t)
+ destPriceRegistry := ccipdatamocks.NewPriceRegistryReader(t)
+ gasPriceEstimator := prices.NewMockGasPriceEstimatorExec(t)
+ sourcePriceRegistryProvider := ccipdataprovidermocks.NewPriceRegistry(t)
+
+ sourcePriceRegistryAddress := cciptypes.Address(utils.RandomAddress().String())
+ onrampReader.On("SourcePriceRegistryAddress", ctx).Return(sourcePriceRegistryAddress, nil).Maybe()
+ offrampReader.On("CurrentRateLimiterState", ctx).Return(cciptypes.TokenBucketRateLimit{}, nil).Maybe()
+ offrampReader.On("GetSourceToDestTokensMapping", ctx).Return(map[cciptypes.Address]cciptypes.Address{}, nil).Maybe()
+ gasPriceEstimator.On("GetGasPrice", ctx).Return(big.NewInt(1e9), nil).Maybe()
+
+ offrampReader.On("GetTokens", ctx).Return(cciptypes.OffRampTokens{DestinationTokens: tt.destTokens}, tt.destTokensErr).Maybe()
+ sourcePriceRegistry.On("Address", mock.Anything).Return(sourcePriceRegistryAddress, nil).Maybe()
+ sourcePriceRegistry.On("GetFeeTokens", ctx).Return(tt.sourceFeeTokens, tt.sourceFeeTokensErr).Maybe()
+ sourcePriceRegistry.On("GetTokenPrices", ctx, mock.Anything).Return(tt.sourcePrices, nil).Maybe()
+ destPriceRegistry.On("GetFeeTokens", ctx).Return(tt.destFeeTokens, tt.destFeeTokensErr).Maybe()
+ destPriceRegistry.On("GetTokenPrices", ctx, mock.Anything).Return(tt.destPrices, nil).Maybe()
+
+ sourcePriceRegistryProvider.On("NewPriceRegistryReader", ctx, sourcePriceRegistryAddress).Return(sourcePriceRegistry, nil).Maybe()
+
+ reportingPlugin := ExecutionReportingPlugin{
+ onRampReader: onrampReader,
+ offRampReader: offrampReader,
+ sourcePriceRegistry: sourcePriceRegistry,
+ sourcePriceRegistryProvider: sourcePriceRegistryProvider,
+ destPriceRegistry: destPriceRegistry,
+ gasPriceEstimator: gasPriceEstimator,
+ sourceWrappedNativeToken: weth,
+ destWrappedNative: wavax,
+ }
+
+ tokenData, err := reportingPlugin.prepareTokenExecData(ctx)
+ if tt.destFeeTokensErr != nil || tt.sourceFeeTokensErr != nil || tt.destTokensErr != nil {
+ require.Error(t, err)
+ return
+ }
+
+ require.NoError(t, err)
+ assert.Len(t, tokenData.sourceTokenPrices, len(tt.sourcePrices))
+ assert.Len(t, tokenData.destTokenPrices, len(tt.destPrices))
+
+ for token, price := range tokenData.sourceTokenPrices {
+ assert.Equal(t, tokenPrices[token].Value, price)
+ }
+
+ for token, price := range tokenData.destTokenPrices {
+ assert.Equal(t, tokenPrices[token].Value, price)
+ }
+ })
+ }
+}
+
+func encodeExecutionReport(t *testing.T, report cciptypes.ExecReport) []byte {
+ reader, err := v1_2_0.NewOffRamp(logger.TestLogger(t), utils.RandomAddress(), nil, nil, nil, nil)
+ require.NoError(t, err)
+ ctx := testutils.Context(t)
+ encodedReport, err := reader.EncodeExecutionReport(ctx, report)
+ require.NoError(t, err)
+ return encodedReport
+}
+
+// Verify the price registry update mechanism in case of configuration change on the source onRamp.
+func TestExecutionReportingPlugin_ensurePriceRegistrySynchronization(t *testing.T) {
+ p := &ExecutionReportingPlugin{}
+ p.lggr = logger.TestLogger(t)
+ p.sourcePriceRegistryLock = sync.RWMutex{}
+
+ sourcePriceRegistryAddress1 := cciptypes.Address(utils.RandomAddress().String())
+ sourcePriceRegistryAddress2 := cciptypes.Address(utils.RandomAddress().String())
+
+ mockPriceRegistryReader1 := ccipdatamocks.NewPriceRegistryReader(t)
+ mockPriceRegistryReader2 := ccipdatamocks.NewPriceRegistryReader(t)
+ mockPriceRegistryReader1.On("Address", mock.Anything).Return(sourcePriceRegistryAddress1, nil)
+ mockPriceRegistryReader2.On("Address", mock.Anything).Return(sourcePriceRegistryAddress2, nil).Maybe()
+ mockPriceRegistryReader1.On("Close", mock.Anything).Return(nil)
+ mockPriceRegistryReader2.On("Close", mock.Anything).Return(nil).Maybe()
+
+ mockSourcePriceRegistryProvider := ccipdataprovidermocks.NewPriceRegistry(t)
+ mockSourcePriceRegistryProvider.On("NewPriceRegistryReader", mock.Anything, sourcePriceRegistryAddress1).Return(mockPriceRegistryReader1, nil)
+ mockSourcePriceRegistryProvider.On("NewPriceRegistryReader", mock.Anything, sourcePriceRegistryAddress2).Return(mockPriceRegistryReader2, nil)
+ p.sourcePriceRegistryProvider = mockSourcePriceRegistryProvider
+
+ mockOnRampReader := ccipdatamocks.NewOnRampReader(t)
+ p.onRampReader = mockOnRampReader
+
+ mockOnRampReader.On("SourcePriceRegistryAddress", mock.Anything).Return(sourcePriceRegistryAddress1, nil).Once()
+ require.Equal(t, nil, p.sourcePriceRegistry)
+ err := p.ensurePriceRegistrySynchronization(context.Background())
+ require.NoError(t, err)
+ require.Equal(t, mockPriceRegistryReader1, p.sourcePriceRegistry)
+
+ mockOnRampReader.On("SourcePriceRegistryAddress", mock.Anything).Return(sourcePriceRegistryAddress2, nil).Once()
+ err = p.ensurePriceRegistrySynchronization(context.Background())
+ require.NoError(t, err)
+ require.Equal(t, mockPriceRegistryReader2, p.sourcePriceRegistry)
+}
diff --git a/core/services/ocr2/plugins/ccip/clo_ccip_integration_test.go b/core/services/ocr2/plugins/ccip/clo_ccip_integration_test.go
new file mode 100644
index 00000000000..2fddd58ac8f
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/clo_ccip_integration_test.go
@@ -0,0 +1,137 @@
+package ccip_test
+
+import (
+ "context"
+ "encoding/json"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+ integrationtesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/integration"
+)
+
+func Test_CLOSpecApprovalFlow_pipeline(t *testing.T) {
+ ccipTH := integrationtesthelpers.SetupCCIPIntegrationTH(t, testhelpers.SourceChainID, testhelpers.SourceChainSelector, testhelpers.DestChainID, testhelpers.DestChainSelector)
+
+ tokenPricesUSDPipeline, linkUSD, ethUSD := ccipTH.CreatePricesPipeline(t)
+ defer linkUSD.Close()
+ defer ethUSD.Close()
+
+ test_CLOSpecApprovalFlow(t, ccipTH, tokenPricesUSDPipeline, "")
+}
+
+func Test_CLOSpecApprovalFlow_dynamicPriceGetter(t *testing.T) {
+ ccipTH := integrationtesthelpers.SetupCCIPIntegrationTH(t, testhelpers.SourceChainID, testhelpers.SourceChainSelector, testhelpers.DestChainID, testhelpers.DestChainSelector)
+
+ //Set up the aggregators here to avoid modifying ccipTH.
+ dstLinkAddr := ccipTH.Dest.LinkToken.Address()
+ srcNativeAddr, err := ccipTH.Source.Router.GetWrappedNative(nil)
+ require.NoError(t, err)
+ aggDstNativeAddr := ccipTH.Dest.WrappedNative.Address()
+
+ aggSrcNatAddr, _, aggSrcNat, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(ccipTH.Source.User, ccipTH.Source.Chain, 18, big.NewInt(2e18))
+ require.NoError(t, err)
+ _, err = aggSrcNat.UpdateRoundData(ccipTH.Source.User, big.NewInt(50), big.NewInt(17000000), big.NewInt(1000), big.NewInt(1000))
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ aggDstLnkAddr, _, aggDstLnk, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(ccipTH.Dest.User, ccipTH.Dest.Chain, 18, big.NewInt(3e18))
+ require.NoError(t, err)
+ ccipTH.Dest.Chain.Commit()
+ _, err = aggDstLnk.UpdateRoundData(ccipTH.Dest.User, big.NewInt(50), big.NewInt(8000000), big.NewInt(1000), big.NewInt(1000))
+ require.NoError(t, err)
+ ccipTH.Dest.Chain.Commit()
+
+ // Check content is ok on aggregator.
+ tmp, err := aggDstLnk.LatestRoundData(&bind.CallOpts{})
+ require.NoError(t, err)
+ require.Equal(t, big.NewInt(50), tmp.RoundId)
+ require.Equal(t, big.NewInt(8000000), tmp.Answer)
+
+ // deploy dest wrapped native aggregator
+ aggDstNativeAggrAddr, _, aggDstNativeAggr, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(ccipTH.Dest.User, ccipTH.Dest.Chain, 18, big.NewInt(3e18))
+ require.NoError(t, err)
+ ccipTH.Dest.Chain.Commit()
+ _, err = aggDstNativeAggr.UpdateRoundData(ccipTH.Dest.User, big.NewInt(50), big.NewInt(500000), big.NewInt(1000), big.NewInt(1000))
+ require.NoError(t, err)
+ ccipTH.Dest.Chain.Commit()
+
+ priceGetterConfig := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ srcNativeAddr: {
+ ChainID: ccipTH.Source.ChainID,
+ AggregatorContractAddress: aggSrcNatAddr,
+ },
+ dstLinkAddr: {
+ ChainID: ccipTH.Dest.ChainID,
+ AggregatorContractAddress: aggDstLnkAddr,
+ },
+ aggDstNativeAddr: {
+ ChainID: ccipTH.Dest.ChainID,
+ AggregatorContractAddress: aggDstNativeAggrAddr,
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{},
+ }
+ priceGetterConfigBytes, err := json.MarshalIndent(priceGetterConfig, "", " ")
+ require.NoError(t, err)
+ priceGetterConfigJson := string(priceGetterConfigBytes)
+
+ test_CLOSpecApprovalFlow(t, ccipTH, "", priceGetterConfigJson)
+}
+
+func test_CLOSpecApprovalFlow(t *testing.T, ccipTH integrationtesthelpers.CCIPIntegrationTestHarness, tokenPricesUSDPipeline string, priceGetterConfiguration string) {
+ jobParams := ccipTH.SetUpNodesAndJobs(t, tokenPricesUSDPipeline, priceGetterConfiguration, "http://blah.com")
+ ccipTH.SetupFeedsManager(t)
+
+ // Propose and approve new specs
+ ccipTH.ApproveJobSpecs(t, jobParams)
+
+ // Sanity check that CCIP works after CLO flow
+ currentSeqNum := 1
+
+ extraArgs, err := testhelpers.GetEVMExtraArgsV1(big.NewInt(200_003), false)
+ require.NoError(t, err)
+
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: testhelpers.MustEncodeAddress(t, ccipTH.Dest.Receivers[0].Receiver.Address()),
+ Data: utils.RandomAddress().Bytes(),
+ TokenAmounts: []router.ClientEVMTokenAmount{},
+ FeeToken: ccipTH.Source.LinkToken.Address(),
+ ExtraArgs: extraArgs,
+ }
+ fee, err := ccipTH.Source.Router.GetFee(nil, testhelpers.DestChainSelector, msg)
+ require.NoError(t, err)
+
+ _, err = ccipTH.Source.LinkToken.Approve(ccipTH.Source.User, ccipTH.Source.Router.Address(), new(big.Int).Set(fee))
+ require.NoError(t, err)
+ blockHash := ccipTH.Dest.Chain.Commit()
+ // get the block number
+ block, err := ccipTH.Dest.Chain.BlockByHash(context.Background(), blockHash)
+ require.NoError(t, err)
+ blockNumber := block.Number().Uint64() + 1 // +1 as a block will be mined for the request from EventuallyReportCommitted
+
+ ccipTH.SendRequest(t, msg)
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum)
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum)
+ ccipTH.EventuallyPriceRegistryUpdated(
+ t,
+ blockNumber,
+ ccipTH.Source.ChainSelector,
+ []common.Address{ccipTH.Dest.LinkToken.Address(), ccipTH.Dest.WrappedNative.Address()},
+ ccipTH.Source.WrappedNative.Address(),
+ )
+
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum)
+ assert.Len(t, executionLogs, 1)
+ ccipTH.AssertExecState(t, executionLogs[0], testhelpers.ExecutionStateSuccess)
+}
diff --git a/core/services/ocr2/plugins/ccip/config/chain_config.go b/core/services/ocr2/plugins/ccip/config/chain_config.go
new file mode 100644
index 00000000000..ff82def6066
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/config/chain_config.go
@@ -0,0 +1,48 @@
+package config
+
+import (
+ "strconv"
+
+ "github.com/pkg/errors"
+ chainselectors "github.com/smartcontractkit/chain-selectors"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+)
+
+func GetChainFromSpec(spec *job.OCR2OracleSpec, chainSet legacyevm.LegacyChainContainer) (legacyevm.Chain, int64, error) {
+ chainIDInterface, ok := spec.RelayConfig["chainID"]
+ if !ok {
+ return nil, 0, errors.New("chainID must be provided in relay config")
+ }
+ destChainID := uint64(chainIDInterface.(float64))
+ return GetChainByChainID(chainSet, destChainID)
+}
+
+func GetChainByChainSelector(chainSet legacyevm.LegacyChainContainer, chainSelector uint64) (legacyevm.Chain, int64, error) {
+ chainID, err := chainselectors.ChainIdFromSelector(chainSelector)
+ if err != nil {
+ return nil, 0, err
+ }
+ return GetChainByChainID(chainSet, chainID)
+}
+
+func GetChainByChainID(chainSet legacyevm.LegacyChainContainer, chainID uint64) (legacyevm.Chain, int64, error) {
+ chain, err := chainSet.Get(strconv.FormatUint(chainID, 10))
+ if err != nil {
+ return nil, 0, errors.Wrap(err, "chain not found in chainset")
+ }
+ return chain, chain.ID().Int64(), nil
+}
+
+func ResolveChainNames(sourceChainId int64, destChainId int64) (string, string, error) {
+ sourceChainName, err := chainselectors.NameFromChainId(uint64(sourceChainId))
+ if err != nil {
+ return "", "", err
+ }
+ destChainName, err := chainselectors.NameFromChainId(uint64(destChainId))
+ if err != nil {
+ return "", "", err
+ }
+ return sourceChainName, destChainName, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/config/chain_config_test.go b/core/services/ocr2/plugins/ccip/config/chain_config_test.go
new file mode 100644
index 00000000000..df2351a5ea4
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/config/chain_config_test.go
@@ -0,0 +1,135 @@
+package config
+
+import (
+ "math/big"
+ "strconv"
+ "testing"
+
+ "github.com/pkg/errors"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+)
+
+func TestGetChainFromSpec(t *testing.T) {
+ testChainID := int64(1337)
+
+ tests := []struct {
+ name string
+ spec *job.OCR2OracleSpec
+ expectedErr bool
+ expectedErrMsg string
+ }{
+ {
+ name: "success",
+ spec: &job.OCR2OracleSpec{
+ RelayConfig: job.JSONConfig{
+ "chainID": float64(testChainID),
+ },
+ },
+ expectedErr: false,
+ },
+ {
+ name: "missing_chain_ID",
+ spec: &job.OCR2OracleSpec{},
+ expectedErr: true,
+ expectedErrMsg: "chainID must be provided in relay config",
+ },
+ }
+
+ mockChain := mocks.NewChain(t)
+ mockChain.On("ID").Return(big.NewInt(testChainID)).Maybe()
+
+ mockChainSet := mocks.NewLegacyChainContainer(t)
+ mockChainSet.On("Get", strconv.FormatInt(testChainID, 10)).Return(mockChain, nil).Maybe()
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ chain, chainID, err := GetChainFromSpec(test.spec, mockChainSet)
+ if test.expectedErr {
+ require.Error(t, err)
+ require.Contains(t, err.Error(), test.expectedErrMsg)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, mockChain, chain)
+ require.Equal(t, testChainID, chainID)
+ }
+ })
+ }
+}
+
+func TestGetChainByChainSelector_success(t *testing.T) {
+ mockChain := mocks.NewChain(t)
+ mockChain.On("ID").Return(big.NewInt(11155111))
+
+ mockChainSet := mocks.NewLegacyChainContainer(t)
+ mockChainSet.On("Get", "11155111").Return(mockChain, nil)
+
+ // Ethereum Sepolia chain selector.
+ chain, chainID, err := GetChainByChainSelector(mockChainSet, uint64(16015286601757825753))
+ require.NoError(t, err)
+ require.Equal(t, mockChain, chain)
+ require.Equal(t, int64(11155111), chainID)
+}
+
+func TestGetChainByChainSelector_selectorNotFound(t *testing.T) {
+ mockChainSet := mocks.NewLegacyChainContainer(t)
+
+ _, _, err := GetChainByChainSelector(mockChainSet, uint64(444000444))
+ require.Error(t, err)
+}
+
+func TestGetChainById_notFound(t *testing.T) {
+ mockChainSet := mocks.NewLegacyChainContainer(t)
+ mockChainSet.On("Get", "444").Return(nil, errors.New("test")).Maybe()
+
+ _, _, err := GetChainByChainID(mockChainSet, uint64(444))
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "chain not found in chainset")
+}
+
+func TestResolveChainNames(t *testing.T) {
+ tests := []struct {
+ name string
+ sourceChainId int64
+ destChainId int64
+ expectedSourceChainName string
+ expectedDestChainName string
+ expectedErr bool
+ }{
+ {
+ name: "success",
+ sourceChainId: 1,
+ destChainId: 10,
+ expectedSourceChainName: "ethereum-mainnet",
+ expectedDestChainName: "ethereum-mainnet-optimism-1",
+ },
+ {
+ name: "source chain not found",
+ sourceChainId: 901278309182,
+ destChainId: 10,
+ expectedErr: true,
+ },
+ {
+ name: "dest chain not found",
+ sourceChainId: 1,
+ destChainId: 901278309182,
+ expectedErr: true,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ sourceChainName, destChainName, err := ResolveChainNames(test.sourceChainId, test.destChainId)
+ if test.expectedErr {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ assert.Equal(t, test.expectedSourceChainName, sourceChainName)
+ assert.Equal(t, test.expectedDestChainName, destChainName)
+ }
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/config/config.go b/core/services/ocr2/plugins/ccip/config/config.go
new file mode 100644
index 00000000000..a24a6edfd13
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/config/config.go
@@ -0,0 +1,152 @@
+package config
+
+import (
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+)
+
+// CommitPluginJobSpecConfig contains the plugin specific variables for the ccip.CCIPCommit plugin.
+type CommitPluginJobSpecConfig struct {
+ SourceStartBlock, DestStartBlock uint64 // Only for first time job add.
+ OffRamp cciptypes.Address `json:"offRamp"`
+ // TokenPricesUSDPipeline should contain a token price pipeline for the following tokens:
+ // The SOURCE chain wrapped native
+ // The DESTINATION supported tokens (including fee tokens) as defined in destination OffRamp and PriceRegistry.
+ TokenPricesUSDPipeline string `json:"tokenPricesUSDPipeline,omitempty"`
+ // PriceGetterConfig defines where to get the token prices from (i.e. static or aggregator source).
+ PriceGetterConfig *DynamicPriceGetterConfig `json:"priceGetterConfig,omitempty"`
+}
+
+type CommitPluginConfig struct {
+ IsSourceProvider bool
+ SourceStartBlock, DestStartBlock uint64
+}
+
+func (c CommitPluginConfig) Encode() ([]byte, error) {
+ bytes, err := json.Marshal(c)
+ if err != nil {
+ return nil, err
+ }
+ return bytes, nil
+}
+
+// DynamicPriceGetterConfig specifies which configuration to use for getting the price of tokens (map keys).
+type DynamicPriceGetterConfig struct {
+ AggregatorPrices map[common.Address]AggregatorPriceConfig `json:"aggregatorPrices"`
+ StaticPrices map[common.Address]StaticPriceConfig `json:"staticPrices"`
+}
+
+// AggregatorPriceConfig specifies a price retrieved from an aggregator contract.
+type AggregatorPriceConfig struct {
+ ChainID uint64 `json:"chainID,string"`
+ AggregatorContractAddress common.Address `json:"contractAddress"`
+}
+
+// StaticPriceConfig specifies a price defined statically.
+type StaticPriceConfig struct {
+ ChainID uint64 `json:"chainID,string"`
+ Price *big.Int `json:"price"`
+}
+
+// UnmarshalJSON provides a custom un-marshaller to handle JSON embedded in Toml content.
+func (c *DynamicPriceGetterConfig) UnmarshalJSON(data []byte) error {
+ type Alias DynamicPriceGetterConfig
+ if bytes.HasQuotes(data) {
+ trimmed := string(bytes.TrimQuotes(data))
+ trimmed = strings.ReplaceAll(trimmed, "\\n", "")
+ trimmed = strings.ReplaceAll(trimmed, "\\t", "")
+ trimmed = strings.ReplaceAll(trimmed, "\\", "")
+ return json.Unmarshal([]byte(trimmed), (*Alias)(c))
+ }
+ return json.Unmarshal(data, (*Alias)(c))
+}
+
+func (c *DynamicPriceGetterConfig) Validate() error {
+ for addr, v := range c.AggregatorPrices {
+ if addr == utils.ZeroAddress {
+ return fmt.Errorf("token address is zero")
+ }
+ if v.AggregatorContractAddress == utils.ZeroAddress {
+ return fmt.Errorf("aggregator contract address is zero")
+ }
+ if v.ChainID == 0 {
+ return fmt.Errorf("chain id is zero")
+ }
+ }
+
+ for addr, v := range c.StaticPrices {
+ if addr == utils.ZeroAddress {
+ return fmt.Errorf("token address is zero")
+ }
+ if v.ChainID == 0 {
+ return fmt.Errorf("chain id is zero")
+ }
+ }
+
+ // Ensure no duplication in token price resolution rules.
+ if c.AggregatorPrices != nil && c.StaticPrices != nil {
+ for tk := range c.AggregatorPrices {
+ if _, exists := c.StaticPrices[tk]; exists {
+ return fmt.Errorf("token %s defined in both aggregator and static price rules", tk)
+ }
+ }
+ }
+ return nil
+}
+
+// ExecPluginJobSpecConfig contains the plugin specific variables for the ccip.CCIPExecution plugin.
+type ExecPluginJobSpecConfig struct {
+ SourceStartBlock, DestStartBlock uint64 // Only for first time job add.
+ USDCConfig USDCConfig
+}
+
+type USDCConfig struct {
+ SourceTokenAddress common.Address
+ SourceMessageTransmitterAddress common.Address
+ AttestationAPI string
+ AttestationAPITimeoutSeconds uint
+ // AttestationAPIIntervalMilliseconds can be set to -1 to disable or 0 to use a default interval.
+ AttestationAPIIntervalMilliseconds int
+}
+
+type ExecPluginConfig struct {
+ SourceStartBlock, DestStartBlock uint64 // Only for first time job add.
+ IsSourceProvider bool
+ USDCConfig USDCConfig
+ JobID string
+}
+
+func (e ExecPluginConfig) Encode() ([]byte, error) {
+ bytes, err := json.Marshal(e)
+ if err != nil {
+ return nil, err
+ }
+ return bytes, nil
+}
+
+func (uc *USDCConfig) ValidateUSDCConfig() error {
+ if uc.AttestationAPI == "" {
+ return errors.New("AttestationAPI is required")
+ }
+ if uc.AttestationAPIIntervalMilliseconds < -1 {
+ return errors.New("AttestationAPIIntervalMilliseconds must be -1 to disable, 0 for default or greater to define the exact interval")
+ }
+ if uc.SourceTokenAddress == utils.ZeroAddress {
+ return errors.New("SourceTokenAddress is required")
+ }
+ if uc.SourceMessageTransmitterAddress == utils.ZeroAddress {
+ return errors.New("SourceMessageTransmitterAddress is required")
+ }
+
+ return nil
+}
diff --git a/core/services/ocr2/plugins/ccip/config/config_test.go b/core/services/ocr2/plugins/ccip/config/config_test.go
new file mode 100644
index 00000000000..e6207aa2231
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/config/config_test.go
@@ -0,0 +1,234 @@
+package config
+
+import (
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+func TestCommitConfig(t *testing.T) {
+ tests := []struct {
+ name string
+ cfg CommitPluginJobSpecConfig
+ expectedValidationError error
+ }{
+ {
+ name: "valid config",
+ cfg: CommitPluginJobSpecConfig{
+ SourceStartBlock: 222,
+ DestStartBlock: 333,
+ OffRamp: ccipcalc.HexToAddress("0x123"),
+ TokenPricesUSDPipeline: `merge [type=merge left="{}" right="{\"0xC79b96044906550A5652BCf20a6EA02f139B9Ae5\":\"1000000000000000000\"}"];`,
+ PriceGetterConfig: &DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]AggregatorPriceConfig{
+ common.HexToAddress("0x0820c05e1fba1244763a494a52272170c321cad3"): {
+ ChainID: 1000,
+ AggregatorContractAddress: common.HexToAddress("0xb8dabd288955d302d05ca6b011bb46dfa3ea7acf"),
+ },
+ common.HexToAddress("0x4a98bb4d65347016a7ab6f85bea24b129c9a1272"): {
+ ChainID: 1337,
+ AggregatorContractAddress: common.HexToAddress("0xb80244cc8b0bb18db071c150b36e9bcb8310b236"),
+ },
+ },
+ StaticPrices: map[common.Address]StaticPriceConfig{
+ common.HexToAddress("0xec8c353470ccaa4f43067fcde40558e084a12927"): {
+ ChainID: 1057,
+ Price: big.NewInt(1000000000000000000),
+ },
+ },
+ },
+ },
+ expectedValidationError: nil,
+ },
+ {
+ name: "missing dynamic aggregator contract address",
+ cfg: CommitPluginJobSpecConfig{
+ SourceStartBlock: 222,
+ DestStartBlock: 333,
+ OffRamp: ccipcalc.HexToAddress("0x123"),
+ TokenPricesUSDPipeline: `merge [type=merge left="{}" right="{\"0xC79b96044906550A5652BCf20a6EA02f139B9Ae5\":\"1000000000000000000\"}"];`,
+ PriceGetterConfig: &DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]AggregatorPriceConfig{
+ common.HexToAddress("0x0820c05e1fba1244763a494a52272170c321cad3"): {
+ ChainID: 1000,
+ AggregatorContractAddress: common.HexToAddress("0xb8dabd288955d302d05ca6b011bb46dfa3ea7acf"),
+ },
+ common.HexToAddress("0x4a98bb4d65347016a7ab6f85bea24b129c9a1272"): {
+ ChainID: 1337,
+ AggregatorContractAddress: common.HexToAddress(""),
+ },
+ },
+ StaticPrices: map[common.Address]StaticPriceConfig{
+ common.HexToAddress("0xec8c353470ccaa4f43067fcde40558e084a12927"): {
+ ChainID: 1057,
+ Price: big.NewInt(1000000000000000000),
+ },
+ },
+ },
+ },
+ expectedValidationError: fmt.Errorf("aggregator contract address is zero"),
+ },
+ {
+ name: "missing chain ID",
+ cfg: CommitPluginJobSpecConfig{
+ SourceStartBlock: 222,
+ DestStartBlock: 333,
+ OffRamp: ccipcalc.HexToAddress("0x123"),
+ TokenPricesUSDPipeline: `merge [type=merge left="{}" right="{\"0xC79b96044906550A5652BCf20a6EA02f139B9Ae5\":\"1000000000000000000\"}"];`,
+ PriceGetterConfig: &DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]AggregatorPriceConfig{
+ common.HexToAddress("0x0820c05e1fba1244763a494a52272170c321cad3"): {
+ ChainID: 1000,
+ AggregatorContractAddress: common.HexToAddress("0xb8dabd288955d302d05ca6b011bb46dfa3ea7acf"),
+ },
+ common.HexToAddress("0x4a98bb4d65347016a7ab6f85bea24b129c9a1272"): {
+ ChainID: 1337,
+ AggregatorContractAddress: common.HexToAddress("0xb80244cc8b0bb18db071c150b36e9bcb8310b236"),
+ },
+ },
+ StaticPrices: map[common.Address]StaticPriceConfig{
+ common.HexToAddress("0xec8c353470ccaa4f43067fcde40558e084a12927"): {
+ ChainID: 0,
+ Price: big.NewInt(1000000000000000000),
+ },
+ },
+ },
+ },
+ expectedValidationError: fmt.Errorf("chain id is zero"),
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ // Verify proper marshall/unmarshalling of the config.
+ bts, err := json.Marshal(test.cfg)
+ require.NoError(t, err)
+ parsedConfig := CommitPluginJobSpecConfig{}
+ require.NoError(t, json.Unmarshal(bts, &parsedConfig))
+ require.Equal(t, test.cfg, parsedConfig)
+
+ // Ensure correctness of price getter configuration.
+ pgc := test.cfg.PriceGetterConfig
+ err = pgc.Validate()
+ if test.expectedValidationError != nil {
+ require.ErrorContains(t, err, test.expectedValidationError.Error())
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, uint64(1000), pgc.AggregatorPrices[common.HexToAddress("0x0820c05e1fba1244763a494a52272170c321cad3")].ChainID)
+ require.Equal(t, uint64(1337), pgc.AggregatorPrices[common.HexToAddress("0x4a98bb4d65347016a7ab6f85bea24b129c9a1272")].ChainID)
+ require.Equal(t, uint64(1057), pgc.StaticPrices[common.HexToAddress("0xec8c353470ccaa4f43067fcde40558e084a12927")].ChainID)
+ }
+ })
+ }
+}
+
+func TestExecutionConfig(t *testing.T) {
+ exampleConfig := ExecPluginJobSpecConfig{
+ SourceStartBlock: 222,
+ DestStartBlock: 333,
+ }
+
+ bts, err := json.Marshal(exampleConfig)
+ require.NoError(t, err)
+
+ parsedConfig := ExecPluginJobSpecConfig{}
+ require.NoError(t, json.Unmarshal(bts, &parsedConfig))
+
+ require.Equal(t, exampleConfig, parsedConfig)
+}
+
+func TestUSDCValidate(t *testing.T) {
+ testcases := []struct {
+ config USDCConfig
+ err string
+ }{
+ {
+ config: USDCConfig{},
+ err: "AttestationAPI is required",
+ },
+ {
+ config: USDCConfig{
+ AttestationAPI: "api",
+ },
+ err: "SourceTokenAddress is required",
+ },
+ {
+ config: USDCConfig{
+ AttestationAPI: "api",
+ SourceTokenAddress: utils.ZeroAddress,
+ },
+ err: "SourceTokenAddress is required",
+ },
+ {
+ config: USDCConfig{
+ AttestationAPI: "api",
+ SourceTokenAddress: utils.RandomAddress(),
+ },
+ err: "SourceMessageTransmitterAddress is required",
+ },
+ {
+ config: USDCConfig{
+ AttestationAPI: "api",
+ SourceTokenAddress: utils.RandomAddress(),
+ SourceMessageTransmitterAddress: utils.ZeroAddress,
+ },
+ err: "SourceMessageTransmitterAddress is required",
+ },
+ {
+ config: USDCConfig{
+ AttestationAPI: "api",
+ SourceTokenAddress: utils.RandomAddress(),
+ SourceMessageTransmitterAddress: utils.RandomAddress(),
+ },
+ err: "",
+ },
+ }
+
+ for _, tc := range testcases {
+ tc := tc
+ t.Run(fmt.Sprintf("error = %s", tc.err), func(t *testing.T) {
+ t.Parallel()
+ err := tc.config.ValidateUSDCConfig()
+ if tc.err != "" {
+ require.ErrorContains(t, err, tc.err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
+
+func TestUnmarshallDynamicPriceConfig(t *testing.T) {
+ jsonCfg := `
+{
+ "aggregatorPrices": {
+ "0x0820c05e1fba1244763a494a52272170c321cad3": {
+ "chainID": "1000",
+ "contractAddress": "0xb8dabd288955d302d05ca6b011bb46dfa3ea7acf"
+ },
+ "0x4a98bb4d65347016a7ab6f85bea24b129c9a1272": {
+ "chainID": "1337",
+ "contractAddress": "0xb80244cc8b0bb18db071c150b36e9bcb8310b236"
+ }
+ },
+ "staticPrices": {
+ "0xec8c353470ccaa4f43067fcde40558e084a12927": {
+ "chainID": "1057",
+ "price": 1000000000000000000
+ }
+ }
+}
+`
+ var cfg DynamicPriceGetterConfig
+ err := json.Unmarshal([]byte(jsonCfg), &cfg)
+ require.NoError(t, err)
+ err = cfg.Validate()
+ require.NoError(t, err)
+}
diff --git a/core/services/ocr2/plugins/ccip/config/offchain_config.go b/core/services/ocr2/plugins/ccip/config/offchain_config.go
new file mode 100644
index 00000000000..f8fba3f1bcb
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/config/offchain_config.go
@@ -0,0 +1,26 @@
+package config
+
+import (
+ "encoding/json"
+)
+
+type OffchainConfig interface {
+ Validate() error
+}
+
+func DecodeOffchainConfig[T OffchainConfig](encodedConfig []byte) (T, error) {
+ var result T
+ err := json.Unmarshal(encodedConfig, &result)
+ if err != nil {
+ return result, err
+ }
+ err = result.Validate()
+ if err != nil {
+ return result, err
+ }
+ return result, nil
+}
+
+func EncodeOffchainConfig[T OffchainConfig](occ T) ([]byte, error) {
+ return json.Marshal(occ)
+}
diff --git a/core/services/ocr2/plugins/ccip/config/type_and_version.go b/core/services/ocr2/plugins/ccip/config/type_and_version.go
new file mode 100644
index 00000000000..fdfd892b087
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/config/type_and_version.go
@@ -0,0 +1,73 @@
+package config
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/Masterminds/semver/v3"
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+
+ type_and_version "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/type_and_version_interface_wrapper"
+)
+
+type ContractType string
+
+var (
+ EVM2EVMOnRamp ContractType = "EVM2EVMOnRamp"
+ EVM2EVMOffRamp ContractType = "EVM2EVMOffRamp"
+ CommitStore ContractType = "CommitStore"
+ PriceRegistry ContractType = "PriceRegistry"
+ ContractTypes = mapset.NewSet[ContractType](
+ EVM2EVMOffRamp,
+ EVM2EVMOnRamp,
+ CommitStore,
+ PriceRegistry,
+ )
+)
+
+func VerifyTypeAndVersion(addr common.Address, client bind.ContractBackend, expectedType ContractType) (semver.Version, error) {
+ contractType, version, err := TypeAndVersion(addr, client)
+ if err != nil {
+ return semver.Version{}, fmt.Errorf("failed getting type and version %w", err)
+ }
+ if contractType != expectedType {
+ return semver.Version{}, fmt.Errorf("wrong contract type %s", contractType)
+ }
+ return version, nil
+}
+
+func TypeAndVersion(addr common.Address, client bind.ContractBackend) (ContractType, semver.Version, error) {
+ tv, err := type_and_version.NewTypeAndVersionInterface(addr, client)
+ if err != nil {
+ return "", semver.Version{}, err
+ }
+ tvStr, err := tv.TypeAndVersion(nil)
+ if err != nil {
+ return "", semver.Version{}, fmt.Errorf("error calling typeAndVersion on addr: %s %w", addr.String(), err)
+ }
+
+ contractType, versionStr, err := ParseTypeAndVersion(tvStr)
+ if err != nil {
+ return "", semver.Version{}, err
+ }
+ v, err := semver.NewVersion(versionStr)
+ if err != nil {
+ return "", semver.Version{}, fmt.Errorf("failed parsing version %s: %w", versionStr, err)
+ }
+
+ if !ContractTypes.Contains(ContractType(contractType)) {
+ return "", semver.Version{}, fmt.Errorf("unrecognized contract type %v", contractType)
+ }
+ return ContractType(contractType), *v, nil
+}
+
+func ParseTypeAndVersion(tvStr string) (string, string, error) {
+ typeAndVersionValues := strings.Split(tvStr, " ")
+
+ if len(typeAndVersionValues) < 2 {
+ return "", "", fmt.Errorf("invalid type and version %s", tvStr)
+ }
+ return typeAndVersionValues[0], typeAndVersionValues[1], nil
+}
diff --git a/core/services/ocr2/plugins/ccip/exportinternal.go b/core/services/ocr2/plugins/ccip/exportinternal.go
new file mode 100644
index 00000000000..aecf1a0b163
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/exportinternal.go
@@ -0,0 +1,136 @@
+package ccip
+
+import (
+ "context"
+ "math/big"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+)
+
+func GenericAddrToEvm(addr ccip.Address) (common.Address, error) {
+ return ccipcalc.GenericAddrToEvm(addr)
+}
+
+func EvmAddrToGeneric(addr common.Address) ccip.Address {
+ return ccipcalc.EvmAddrToGeneric(addr)
+}
+
+func NewEvmPriceRegistry(lp logpoller.LogPoller, ec client.Client, lggr logger.Logger, pluginLabel string) *ccipdataprovider.EvmPriceRegistry {
+ return ccipdataprovider.NewEvmPriceRegistry(lp, ec, lggr, pluginLabel)
+}
+
+type VersionFinder = factory.VersionFinder
+
+func NewCommitStoreReader(lggr logger.Logger, versionFinder VersionFinder, address ccip.Address, ec client.Client, lp logpoller.LogPoller) (ccipdata.CommitStoreReader, error) {
+ return factory.NewCommitStoreReader(lggr, versionFinder, address, ec, lp)
+}
+
+func CloseCommitStoreReader(lggr logger.Logger, versionFinder VersionFinder, address ccip.Address, ec client.Client, lp logpoller.LogPoller) error {
+ return factory.CloseCommitStoreReader(lggr, versionFinder, address, ec, lp)
+}
+
+func NewOffRampReader(lggr logger.Logger, versionFinder VersionFinder, addr ccip.Address, destClient client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int, registerFilters bool) (ccipdata.OffRampReader, error) {
+ return factory.NewOffRampReader(lggr, versionFinder, addr, destClient, lp, estimator, destMaxGasPrice, registerFilters)
+}
+
+func CloseOffRampReader(lggr logger.Logger, versionFinder VersionFinder, addr ccip.Address, destClient client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int) error {
+ return factory.CloseOffRampReader(lggr, versionFinder, addr, destClient, lp, estimator, destMaxGasPrice)
+}
+
+func NewEvmVersionFinder() factory.EvmVersionFinder {
+ return factory.NewEvmVersionFinder()
+}
+
+func NewOnRampReader(lggr logger.Logger, versionFinder VersionFinder, sourceSelector, destSelector uint64, onRampAddress ccip.Address, sourceLP logpoller.LogPoller, source client.Client) (ccipdata.OnRampReader, error) {
+ return factory.NewOnRampReader(lggr, versionFinder, sourceSelector, destSelector, onRampAddress, sourceLP, source)
+}
+
+func CloseOnRampReader(lggr logger.Logger, versionFinder VersionFinder, sourceSelector, destSelector uint64, onRampAddress ccip.Address, sourceLP logpoller.LogPoller, source client.Client) error {
+ return factory.CloseOnRampReader(lggr, versionFinder, sourceSelector, destSelector, onRampAddress, sourceLP, source)
+}
+
+type OffRampReader = ccipdata.OffRampReader
+
+type DynamicPriceGetterClient = pricegetter.DynamicPriceGetterClient
+
+type DynamicPriceGetter = pricegetter.DynamicPriceGetter
+
+func NewDynamicPriceGetterClient(batchCaller rpclib.EvmBatchCaller) DynamicPriceGetterClient {
+ return pricegetter.NewDynamicPriceGetterClient(batchCaller)
+}
+
+func NewDynamicPriceGetter(cfg config.DynamicPriceGetterConfig, evmClients map[uint64]DynamicPriceGetterClient) (*DynamicPriceGetter, error) {
+ return pricegetter.NewDynamicPriceGetter(cfg, evmClients)
+}
+
+func NewDynamicLimitedBatchCaller(
+ lggr logger.Logger, batchSender rpclib.BatchSender, batchSizeLimit, backOffMultiplier, parallelRpcCallsLimit uint,
+) *rpclib.DynamicLimitedBatchCaller {
+ return rpclib.NewDynamicLimitedBatchCaller(lggr, batchSender, batchSizeLimit, backOffMultiplier, parallelRpcCallsLimit)
+}
+
+func NewUSDCReader(lggr logger.Logger, jobID string, transmitter common.Address, lp logpoller.LogPoller, registerFilters bool) (*ccipdata.USDCReaderImpl, error) {
+ return ccipdata.NewUSDCReader(lggr, jobID, transmitter, lp, registerFilters)
+}
+
+func CloseUSDCReader(lggr logger.Logger, jobID string, transmitter common.Address, lp logpoller.LogPoller) error {
+ return ccipdata.CloseUSDCReader(lggr, jobID, transmitter, lp)
+}
+
+type USDCReaderImpl = ccipdata.USDCReaderImpl
+
+var DefaultRpcBatchSizeLimit = rpclib.DefaultRpcBatchSizeLimit
+var DefaultRpcBatchBackOffMultiplier = rpclib.DefaultRpcBatchBackOffMultiplier
+var DefaultMaxParallelRpcCalls = rpclib.DefaultMaxParallelRpcCalls
+
+func NewEVMTokenPoolBatchedReader(lggr logger.Logger, remoteChainSelector uint64, offRampAddress ccip.Address, evmBatchCaller rpclib.EvmBatchCaller) (*batchreader.EVMTokenPoolBatchedReader, error) {
+ return batchreader.NewEVMTokenPoolBatchedReader(lggr, remoteChainSelector, offRampAddress, evmBatchCaller)
+}
+
+type ChainAgnosticPriceRegistry struct {
+ p ChainAgnosticPriceRegistryFactory
+}
+
+// [ChainAgnosticPriceRegistryFactory] is satisfied by [commontypes.CCIPCommitProvider] and [commontypes.CCIPExecProvider]
+type ChainAgnosticPriceRegistryFactory interface {
+ NewPriceRegistryReader(ctx context.Context, addr ccip.Address) (ccip.PriceRegistryReader, error)
+}
+
+func (c *ChainAgnosticPriceRegistry) NewPriceRegistryReader(ctx context.Context, addr ccip.Address) (ccip.PriceRegistryReader, error) {
+ return c.p.NewPriceRegistryReader(ctx, addr)
+}
+
+func NewChainAgnosticPriceRegistry(provider ChainAgnosticPriceRegistryFactory) *ChainAgnosticPriceRegistry {
+ return &ChainAgnosticPriceRegistry{provider}
+}
+
+type JSONCommitOffchainConfigV1_2_0 = v1_2_0.JSONCommitOffchainConfig
+type CommitOnchainConfig = ccipdata.CommitOnchainConfig
+
+func NewCommitOffchainConfig(
+ gasPriceDeviationPPB uint32,
+ gasPriceHeartBeat time.Duration,
+ tokenPriceDeviationPPB uint32,
+ tokenPriceHeartBeat time.Duration,
+ inflightCacheExpiry time.Duration,
+ priceReportingDisabled bool,
+) ccip.CommitOffchainConfig {
+ return ccipdata.NewCommitOffchainConfig(gasPriceDeviationPPB, gasPriceHeartBeat, tokenPriceDeviationPPB, tokenPriceHeartBeat, inflightCacheExpiry, priceReportingDisabled)
+}
diff --git a/core/services/ocr2/plugins/ccip/integration_legacy_test.go b/core/services/ocr2/plugins/ccip/integration_legacy_test.go
new file mode 100644
index 00000000000..d89c50b4070
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/integration_legacy_test.go
@@ -0,0 +1,588 @@
+package ccip_test
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ gethtypes "github.com/ethereum/go-ethereum/core/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ evm_2_evm_onramp "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ testhelpers_new "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+ testhelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0"
+)
+
+func TestIntegration_legacy_CCIP(t *testing.T) {
+ // Run the batches of tests for both pipeline and dynamic price getter setups.
+ // We will remove the pipeline batch once the feature is deleted from the code.
+ tests := []struct {
+ name string
+ withPipeline bool
+ }{
+ {
+ name: "with pipeline",
+ withPipeline: true,
+ },
+ {
+ name: "with dynamic price getter",
+ withPipeline: false,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ ccipTH := testhelpers.SetupCCIPIntegrationTH(t, testhelpers.SourceChainID, testhelpers.SourceChainSelector, testhelpers.DestChainID, testhelpers.DestChainSelector)
+
+ tokenPricesUSDPipeline := ""
+ priceGetterConfigJson := ""
+
+ if test.withPipeline {
+ // Set up a test pipeline.
+ testPricePipeline, linkUSD, ethUSD := ccipTH.CreatePricesPipeline(t)
+ defer linkUSD.Close()
+ defer ethUSD.Close()
+ tokenPricesUSDPipeline = testPricePipeline
+ } else {
+ // Set up a test price getter.
+ // Set up the aggregators here to avoid modifying ccipTH.
+ aggSrcNatAddr, _, aggSrcNat, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(ccipTH.Source.User, ccipTH.Source.Chain, 18, big.NewInt(2e18))
+ require.NoError(t, err)
+ _, err = aggSrcNat.UpdateRoundData(ccipTH.Source.User, big.NewInt(50), big.NewInt(17000000), big.NewInt(1000), big.NewInt(1000))
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ aggDstLnkAddr, _, aggDstLnk, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(ccipTH.Dest.User, ccipTH.Dest.Chain, 18, big.NewInt(3e18))
+ require.NoError(t, err)
+ ccipTH.Dest.Chain.Commit()
+ _, err = aggDstLnk.UpdateRoundData(ccipTH.Dest.User, big.NewInt(50), big.NewInt(8000000), big.NewInt(1000), big.NewInt(1000))
+ require.NoError(t, err)
+ ccipTH.Dest.Chain.Commit()
+
+ priceGetterConfig := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ ccipTH.Source.WrappedNative.Address(): {
+ ChainID: ccipTH.Source.ChainID,
+ AggregatorContractAddress: aggSrcNatAddr,
+ },
+ ccipTH.Dest.LinkToken.Address(): {
+ ChainID: ccipTH.Dest.ChainID,
+ AggregatorContractAddress: aggDstLnkAddr,
+ },
+ ccipTH.Dest.WrappedNative.Address(): {
+ ChainID: ccipTH.Dest.ChainID,
+ AggregatorContractAddress: aggDstLnkAddr,
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{},
+ }
+ priceGetterConfigBytes, err := json.MarshalIndent(priceGetterConfig, "", " ")
+ require.NoError(t, err)
+ priceGetterConfigJson = string(priceGetterConfigBytes)
+ }
+
+ jobParams := ccipTH.SetUpNodesAndJobs(t, tokenPricesUSDPipeline, priceGetterConfigJson, "")
+
+ currentSeqNum := 1
+
+ t.Run("single", func(t *testing.T) {
+ tokenAmount := big.NewInt(500000003) // prime number
+ gasLimit := big.NewInt(200_003) // prime number
+
+ extraArgs, err2 := testhelpers.GetEVMExtraArgsV1(gasLimit, false)
+ require.NoError(t, err2)
+
+ sourceBalances, err2 := testhelpers.GetBalances(t, []testhelpers.BalanceReq{
+ {Name: testhelpers.SourcePool, Addr: ccipTH.Source.LinkTokenPool.Address(), Getter: ccipTH.GetSourceLinkBalance},
+ {Name: testhelpers.OnRamp, Addr: ccipTH.Source.OnRamp.Address(), Getter: ccipTH.GetSourceLinkBalance},
+ {Name: testhelpers.SourceRouter, Addr: ccipTH.Source.Router.Address(), Getter: ccipTH.GetSourceLinkBalance},
+ {Name: testhelpers.SourcePriceRegistry, Addr: ccipTH.Source.PriceRegistry.Address(), Getter: ccipTH.GetSourceLinkBalance},
+ })
+ require.NoError(t, err2)
+ destBalances, err2 := testhelpers.GetBalances(t, []testhelpers.BalanceReq{
+ {Name: testhelpers.Receiver, Addr: ccipTH.Dest.Receivers[0].Receiver.Address(), Getter: ccipTH.GetDestLinkBalance},
+ {Name: testhelpers.DestPool, Addr: ccipTH.Dest.LinkTokenPool.Address(), Getter: ccipTH.GetDestLinkBalance},
+ {Name: testhelpers.OffRamp, Addr: ccipTH.Dest.OffRamp.Address(), Getter: ccipTH.GetDestLinkBalance},
+ })
+ require.NoError(t, err2)
+
+ ccipTH.Source.User.Value = tokenAmount
+ _, err2 = ccipTH.Source.WrappedNative.Deposit(ccipTH.Source.User)
+ require.NoError(t, err2)
+ ccipTH.Source.Chain.Commit()
+ ccipTH.Source.User.Value = nil
+
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: testhelpers.MustEncodeAddress(t, ccipTH.Dest.Receivers[0].Receiver.Address()),
+ Data: []byte("hello"),
+ TokenAmounts: []router.ClientEVMTokenAmount{
+ {
+ Token: ccipTH.Source.LinkToken.Address(),
+ Amount: tokenAmount,
+ },
+ {
+ Token: ccipTH.Source.WrappedNative.Address(),
+ Amount: tokenAmount,
+ },
+ },
+ FeeToken: ccipTH.Source.LinkToken.Address(),
+ ExtraArgs: extraArgs,
+ }
+ fee, err2 := ccipTH.Source.Router.GetFee(nil, testhelpers.DestChainSelector, msg)
+ require.NoError(t, err2)
+ // Currently no overhead and 10gwei dest gas price. So fee is simply (gasLimit * gasPrice)* link/native
+ // require.Equal(t, new(big.Int).Mul(gasLimit, gasPrice).String(), fee.String())
+ // Approve the fee amount + the token amount
+ _, err2 = ccipTH.Source.LinkToken.Approve(ccipTH.Source.User, ccipTH.Source.Router.Address(), new(big.Int).Add(fee, tokenAmount))
+ require.NoError(t, err2)
+ ccipTH.Source.Chain.Commit()
+ _, err2 = ccipTH.Source.WrappedNative.Approve(ccipTH.Source.User, ccipTH.Source.Router.Address(), tokenAmount)
+ require.NoError(t, err2)
+ ccipTH.Source.Chain.Commit()
+
+ ccipTH.SendRequest(t, msg)
+ // Should eventually see this executed.
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum)
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum)
+
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum)
+ assert.Len(t, executionLogs, 1)
+ ccipTH.AssertExecState(t, executionLogs[0], testhelpers.ExecutionStateSuccess)
+
+ // Asserts
+ // 1) The total pool input == total pool output
+ // 2) Pool flow equals tokens sent
+ // 3) Sent tokens arrive at the receiver
+ ccipTH.AssertBalances(t, []testhelpers.BalanceAssertion{
+ {
+ Name: testhelpers.SourcePool,
+ Address: ccipTH.Source.LinkTokenPool.Address(),
+ Expected: testhelpers.MustAddBigInt(sourceBalances[testhelpers.SourcePool], tokenAmount.String()).String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.SourcePriceRegistry,
+ Address: ccipTH.Source.PriceRegistry.Address(),
+ Expected: sourceBalances[testhelpers.SourcePriceRegistry].String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ // Fees end up in the onramp.
+ Name: testhelpers.OnRamp,
+ Address: ccipTH.Source.OnRamp.Address(),
+ Expected: testhelpers.MustAddBigInt(sourceBalances[testhelpers.SourcePriceRegistry], fee.String()).String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.SourceRouter,
+ Address: ccipTH.Source.Router.Address(),
+ Expected: sourceBalances[testhelpers.SourceRouter].String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.Receiver,
+ Address: ccipTH.Dest.Receivers[0].Receiver.Address(),
+ Expected: testhelpers.MustAddBigInt(destBalances[testhelpers.Receiver], tokenAmount.String()).String(),
+ Getter: ccipTH.GetDestLinkBalance,
+ },
+ {
+ Name: testhelpers.DestPool,
+ Address: ccipTH.Dest.LinkTokenPool.Address(),
+ Expected: testhelpers.MustSubBigInt(destBalances[testhelpers.DestPool], tokenAmount.String()).String(),
+ Getter: ccipTH.GetDestLinkBalance,
+ },
+ {
+ Name: testhelpers.OffRamp,
+ Address: ccipTH.Dest.OffRamp.Address(),
+ Expected: destBalances[testhelpers.OffRamp].String(),
+ Getter: ccipTH.GetDestLinkBalance,
+ },
+ })
+ currentSeqNum++
+ })
+
+ t.Run("multiple batches", func(t *testing.T) {
+ tokenAmount := big.NewInt(500000003)
+ gasLimit := big.NewInt(250_000)
+
+ var txs []*gethtypes.Transaction
+ // Enough to require batched executions as gasLimit per tx is 250k -> 500k -> 750k ....
+ // The actual gas usage of executing 15 messages is higher than the gas limit for
+ // a single tx. This means that when batching is turned off, and we simply include
+ // all txs without checking gas, this also fails.
+ n := 15
+ for i := 0; i < n; i++ {
+ txGasLimit := new(big.Int).Mul(gasLimit, big.NewInt(int64(i+1)))
+ extraArgs, err2 := testhelpers.GetEVMExtraArgsV1(txGasLimit, false)
+ require.NoError(t, err2)
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: testhelpers.MustEncodeAddress(t, ccipTH.Dest.Receivers[0].Receiver.Address()),
+ Data: []byte("hello"),
+ TokenAmounts: []router.ClientEVMTokenAmount{
+ {
+ Token: ccipTH.Source.LinkToken.Address(),
+ Amount: tokenAmount,
+ },
+ },
+ FeeToken: ccipTH.Source.LinkToken.Address(),
+ ExtraArgs: extraArgs,
+ }
+ fee, err2 := ccipTH.Source.Router.GetFee(nil, testhelpers.DestChainSelector, msg)
+ require.NoError(t, err2)
+ // Currently no overhead and 1gwei dest gas price. So fee is simply gasLimit * gasPrice.
+ // require.Equal(t, new(big.Int).Mul(txGasLimit, gasPrice).String(), fee.String())
+ // Approve the fee amount + the token amount
+ _, err2 = ccipTH.Source.LinkToken.Approve(ccipTH.Source.User, ccipTH.Source.Router.Address(), new(big.Int).Add(fee, tokenAmount))
+ require.NoError(t, err2)
+ tx, err2 := ccipTH.Source.Router.CcipSend(ccipTH.Source.User, ccipTH.Dest.ChainSelector, msg)
+ require.NoError(t, err2)
+ txs = append(txs, tx)
+ }
+
+ // Send a batch of requests in a single block
+ testhelpers_new.ConfirmTxs(t, txs, ccipTH.Source.Chain)
+ for i := 0; i < n; i++ {
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum+i)
+ }
+ // Should see a report with the full range
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum+n-1)
+ // Should all be executed
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum+n-1)
+ for _, execLog := range executionLogs {
+ ccipTH.AssertExecState(t, execLog, testhelpers.ExecutionStateSuccess)
+ }
+
+ currentSeqNum += n
+ })
+
+ // Deploy new on ramp,Commit store,off ramp
+ // Delete v1 jobs
+ // Send a number of requests
+ // Upgrade the router with new contracts
+ // create new jobs
+ // Verify all pending requests are sent after the contracts are upgraded
+ t.Run("upgrade contracts and verify requests can be sent with upgraded contract", func(t *testing.T) {
+ gasLimit := big.NewInt(200_003) // prime number
+ tokenAmount := big.NewInt(100)
+ commitStoreV1 := ccipTH.Dest.CommitStore
+ offRampV1 := ccipTH.Dest.OffRamp
+ onRampV1 := ccipTH.Source.OnRamp
+ // deploy v2 contracts
+ ccipTH.DeployNewOnRamp(t)
+ ccipTH.DeployNewCommitStore(t)
+ ccipTH.DeployNewOffRamp(t)
+
+ // send a request as the v2 contracts are not enabled in router it should route through the v1 contracts
+ t.Logf("sending request for seqnum %d", currentSeqNum)
+ ccipTH.SendMessage(t, gasLimit, tokenAmount, ccipTH.Dest.Receivers[0].Receiver.Address())
+ ccipTH.Source.Chain.Commit()
+ ccipTH.Dest.Chain.Commit()
+ t.Logf("verifying seqnum %d on previous onRamp %s", currentSeqNum, onRampV1.Address().Hex())
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum, onRampV1.Address())
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum, commitStoreV1.Address())
+ executionLog := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum, offRampV1.Address())
+ ccipTH.AssertExecState(t, executionLog[0], testhelpers.ExecutionStateSuccess, offRampV1.Address())
+
+ nonceAtOnRampV1, err := onRampV1.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err, "getting nonce from onRamp")
+ require.Equal(t, currentSeqNum, int(nonceAtOnRampV1))
+ nonceAtOffRampV1, err := offRampV1.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err, "getting nonce from offRamp")
+ require.Equal(t, currentSeqNum, int(nonceAtOffRampV1))
+
+ // enable the newly deployed contracts
+ newConfigBlock := ccipTH.Dest.Chain.Blockchain().CurrentBlock().Number.Int64()
+ ccipTH.EnableOnRamp(t)
+ ccipTH.EnableCommitStore(t)
+ ccipTH.EnableOffRamp(t)
+ srcStartBlock := ccipTH.Source.Chain.Blockchain().CurrentBlock().Number.Uint64()
+
+ // send a number of requests, the requests should not be delivered yet as the previous contracts are not configured
+ // with the router anymore
+ startSeq := 1
+ noOfRequests := 5
+ endSeqNum := startSeq + noOfRequests
+ for i := startSeq; i <= endSeqNum; i++ {
+ t.Logf("sending request for seqnum %d", i)
+ ccipTH.SendMessage(t, gasLimit, tokenAmount, ccipTH.Dest.Receivers[0].Receiver.Address())
+ ccipTH.Source.Chain.Commit()
+ ccipTH.Dest.Chain.Commit()
+ ccipTH.EventuallySendRequested(t, uint64(i))
+ }
+
+ // delete v1 jobs
+ for _, node := range ccipTH.Nodes {
+ id := node.FindJobIDForContract(t, commitStoreV1.Address())
+ require.Greater(t, id, int32(0))
+ t.Logf("deleting job %d", id)
+ err = node.App.DeleteJob(context.Background(), id)
+ require.NoError(t, err)
+ id = node.FindJobIDForContract(t, offRampV1.Address())
+ require.Greater(t, id, int32(0))
+ t.Logf("deleting job %d", id)
+ err = node.App.DeleteJob(context.Background(), id)
+ require.NoError(t, err)
+ }
+
+ // Commit on both chains to reach Finality
+ ccipTH.Source.Chain.Commit()
+ ccipTH.Dest.Chain.Commit()
+
+ // create new jobs
+ jobParams = ccipTH.NewCCIPJobSpecParams(tokenPricesUSDPipeline, priceGetterConfigJson, newConfigBlock, "")
+ jobParams.Version = "v2"
+ jobParams.SourceStartBlock = srcStartBlock
+ ccipTH.AddAllJobs(t, jobParams)
+ committedSeqNum := uint64(0)
+ // Now the requests should be delivered
+ for i := startSeq; i <= endSeqNum; i++ {
+ t.Logf("verifying seqnum %d", i)
+ ccipTH.AllNodesHaveReqSeqNum(t, i)
+ if committedSeqNum < uint64(i+1) {
+ committedSeqNum = ccipTH.EventuallyReportCommitted(t, i)
+ }
+ ccipTH.EventuallyExecutionStateChangedToSuccess(t, []uint64{uint64(i)}, uint64(newConfigBlock))
+ }
+
+ // nonces should be correctly synced from v1 contracts for the sender
+ nonceAtOnRampV2, err := ccipTH.Source.OnRamp.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err, "getting nonce from onRamp")
+ nonceAtOffRampV2, err := ccipTH.Dest.OffRamp.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err, "getting nonce from offRamp")
+ require.Equal(t, nonceAtOnRampV1+uint64(noOfRequests)+1, nonceAtOnRampV2, "nonce should be synced from v1 onRamps")
+ require.Equal(t, nonceAtOffRampV1+uint64(noOfRequests)+1, nonceAtOffRampV2, "nonce should be synced from v1 offRamps")
+ currentSeqNum = endSeqNum + 1
+ })
+
+ t.Run("pay nops", func(t *testing.T) {
+ linkToTransferToOnRamp := big.NewInt(1e18)
+
+ // transfer some link to onramp to pay the nops
+ _, err := ccipTH.Source.LinkToken.Transfer(ccipTH.Source.User, ccipTH.Source.OnRamp.Address(), linkToTransferToOnRamp)
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ srcBalReq := []testhelpers.BalanceReq{
+ {
+ Name: testhelpers.Sender,
+ Addr: ccipTH.Source.User.From,
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ {
+ Name: testhelpers.OnRampNative,
+ Addr: ccipTH.Source.OnRamp.Address(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ {
+ Name: testhelpers.OnRamp,
+ Addr: ccipTH.Source.OnRamp.Address(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.SourceRouter,
+ Addr: ccipTH.Source.Router.Address(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ }
+
+ var nopsAndWeights []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight
+ var totalWeight uint16
+ nodes := ccipTH.Nodes
+ for i := range nodes {
+ // For now set the transmitter addresses to be the same as the payee addresses
+ nodes[i].PaymentReceiver = nodes[i].Transmitter
+ nopsAndWeights = append(nopsAndWeights, evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{
+ Nop: nodes[i].PaymentReceiver,
+ Weight: 5,
+ })
+ totalWeight += 5
+ srcBalReq = append(srcBalReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("node %d", i),
+ Addr: nodes[i].PaymentReceiver,
+ Getter: ccipTH.GetSourceLinkBalance,
+ })
+ }
+ srcBalances, err := testhelpers.GetBalances(t, srcBalReq)
+ require.NoError(t, err)
+
+ // set nops on the onramp
+ ccipTH.SetNopsOnRamp(t, nopsAndWeights)
+
+ // send a message
+ extraArgs, err := testhelpers.GetEVMExtraArgsV1(big.NewInt(200_000), true)
+ require.NoError(t, err)
+
+ // FeeToken is empty, indicating it should use native token
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: testhelpers.MustEncodeAddress(t, ccipTH.Dest.Receivers[1].Receiver.Address()),
+ Data: []byte("hello"),
+ TokenAmounts: []router.ClientEVMTokenAmount{},
+ ExtraArgs: extraArgs,
+ FeeToken: common.Address{},
+ }
+ fee, err := ccipTH.Source.Router.GetFee(nil, testhelpers.DestChainSelector, msg)
+ require.NoError(t, err)
+
+ // verify message is sent
+ ccipTH.Source.User.Value = fee
+ ccipTH.SendRequest(t, msg)
+ ccipTH.Source.User.Value = nil
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum)
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum)
+
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum)
+ assert.Len(t, executionLogs, 1)
+ ccipTH.AssertExecState(t, executionLogs[0], testhelpers.ExecutionStateSuccess)
+ currentSeqNum++
+
+ // get the nop fee
+ nopFee, err := ccipTH.Source.OnRamp.GetNopFeesJuels(nil)
+ require.NoError(t, err)
+ t.Log("nopFee", nopFee)
+
+ // withdraw fees and verify there is still fund left for nop payment
+ _, err = ccipTH.Source.OnRamp.WithdrawNonLinkFees(
+ ccipTH.Source.User,
+ ccipTH.Source.WrappedNative.Address(),
+ ccipTH.Source.User.From,
+ )
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ // pay nops
+ _, err = ccipTH.Source.OnRamp.PayNops(ccipTH.Source.User)
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ srcBalanceAssertions := []testhelpers.BalanceAssertion{
+ {
+ // Onramp should not have any balance left in wrapped native
+ Name: testhelpers.OnRampNative,
+ Address: ccipTH.Source.OnRamp.Address(),
+ Expected: big.NewInt(0).String(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ {
+ // Onramp should have the remaining link after paying nops
+ Name: testhelpers.OnRamp,
+ Address: ccipTH.Source.OnRamp.Address(),
+ Expected: new(big.Int).Sub(srcBalances[testhelpers.OnRamp], nopFee).String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.SourceRouter,
+ Address: ccipTH.Source.Router.Address(),
+ Expected: srcBalances[testhelpers.SourceRouter].String(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ // onRamp's balance (of previously sent fee during message sending) should have been transferred to
+ // the owner as a result of WithdrawNonLinkFees
+ {
+ Name: testhelpers.Sender,
+ Address: ccipTH.Source.User.From,
+ Expected: fee.String(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ }
+
+ // the nodes should be paid according to the weights assigned
+ for i, node := range nodes {
+ paymentWeight := float64(nopsAndWeights[i].Weight) / float64(totalWeight)
+ paidInFloat := paymentWeight * float64(nopFee.Int64())
+ paid, _ := new(big.Float).SetFloat64(paidInFloat).Int64()
+ bal := new(big.Int).Add(
+ new(big.Int).SetInt64(paid),
+ srcBalances[fmt.Sprintf("node %d", i)]).String()
+ srcBalanceAssertions = append(srcBalanceAssertions, testhelpers.BalanceAssertion{
+ Name: fmt.Sprintf("node %d", i),
+ Address: node.PaymentReceiver,
+ Expected: bal,
+ Getter: ccipTH.GetSourceLinkBalance,
+ })
+ }
+ ccipTH.AssertBalances(t, srcBalanceAssertions)
+ })
+
+ // Keep on sending a bunch of messages
+ // In the meantime update onchainConfig with new price registry address
+ // Verify if the jobs can pick up updated config
+ // Verify if all the messages are sent
+ t.Run("config change or price registry update while requests are inflight", func(t *testing.T) {
+ gasLimit := big.NewInt(200_003) // prime number
+ tokenAmount := big.NewInt(100)
+ msgWg := &sync.WaitGroup{}
+ msgWg.Add(1)
+ ticker := time.NewTicker(100 * time.Millisecond)
+ defer ticker.Stop()
+ startSeq := currentSeqNum
+ endSeq := currentSeqNum + 20
+
+ // send message with the old configs
+ ccipTH.SendMessage(t, gasLimit, tokenAmount, ccipTH.Dest.Receivers[0].Receiver.Address())
+ ccipTH.Source.Chain.Commit()
+
+ go func(ccipContracts testhelpers.CCIPContracts, currentSeqNum int) {
+ seqNumber := currentSeqNum + 1
+ defer msgWg.Done()
+ for {
+ <-ticker.C // wait for ticker
+ t.Logf("sending request for seqnum %d", seqNumber)
+ ccipContracts.SendMessage(t, gasLimit, tokenAmount, ccipTH.Dest.Receivers[0].Receiver.Address())
+ ccipContracts.Source.Chain.Commit()
+ seqNumber++
+ if seqNumber == endSeq {
+ return
+ }
+ }
+ }(ccipTH.CCIPContracts, currentSeqNum)
+
+ ccipTH.DeployNewPriceRegistry(t)
+ commitOnchainConfig := ccipTH.CreateDefaultCommitOnchainConfig(t)
+ commitOffchainConfig := ccipTH.CreateDefaultCommitOffchainConfig(t)
+ execOnchainConfig := ccipTH.CreateDefaultExecOnchainConfig(t)
+ execOffchainConfig := ccipTH.CreateDefaultExecOffchainConfig(t)
+
+ ccipTH.SetupOnchainConfig(t, commitOnchainConfig, commitOffchainConfig, execOnchainConfig, execOffchainConfig)
+
+ // wait for all requests to be complete
+ msgWg.Wait()
+ for i := startSeq; i < endSeq; i++ {
+ ccipTH.AllNodesHaveReqSeqNum(t, i)
+ ccipTH.EventuallyReportCommitted(t, i)
+
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, i, i)
+ assert.Len(t, executionLogs, 1)
+ ccipTH.AssertExecState(t, executionLogs[0], testhelpers.ExecutionStateSuccess)
+ }
+
+ for i, node := range ccipTH.Nodes {
+ t.Logf("verifying node %d", i)
+ node.EventuallyNodeUsesNewCommitConfig(t, ccipTH, ccipdata.CommitOnchainConfig{
+ PriceRegistry: ccipTH.Dest.PriceRegistry.Address(),
+ })
+ node.EventuallyNodeUsesNewExecConfig(t, ccipTH, v1_2_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: testhelpers.PermissionLessExecutionThresholdSeconds,
+ Router: ccipTH.Dest.Router.Address(),
+ PriceRegistry: ccipTH.Dest.PriceRegistry.Address(),
+ MaxDataBytes: 1e5,
+ MaxNumberOfTokensPerMsg: 5,
+ MaxPoolReleaseOrMintGas: 200_000,
+ })
+ node.EventuallyNodeUsesUpdatedPriceRegistry(t, ccipTH)
+ }
+ currentSeqNum = endSeq
+ })
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/integration_test.go b/core/services/ocr2/plugins/ccip/integration_test.go
new file mode 100644
index 00000000000..bbf785efa8e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/integration_test.go
@@ -0,0 +1,633 @@
+package ccip_test
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ gethtypes "github.com/ethereum/go-ethereum/core/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+ integrationtesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/integration"
+)
+
+func TestIntegration_CCIP(t *testing.T) {
+ // Run the batches of tests for both pipeline and dynamic price getter setups.
+ // We will remove the pipeline batch once the feature is deleted from the code.
+ tests := []struct {
+ name string
+ withPipeline bool
+ allowOutOfOrderExecution bool
+ }{
+ {
+ name: "with pipeline allowOutOfOrderExecution true",
+ withPipeline: true,
+ allowOutOfOrderExecution: true,
+ },
+ {
+ name: "with dynamic price getter allowOutOfOrderExecution false",
+ withPipeline: false,
+ allowOutOfOrderExecution: false,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ ccipTH := integrationtesthelpers.SetupCCIPIntegrationTH(t, testhelpers.SourceChainID, testhelpers.SourceChainSelector, testhelpers.DestChainID, testhelpers.DestChainSelector)
+
+ tokenPricesUSDPipeline := ""
+ priceGetterConfigJson := ""
+
+ if test.withPipeline {
+ // Set up a test pipeline.
+ testPricePipeline, linkUSD, ethUSD := ccipTH.CreatePricesPipeline(t)
+ defer linkUSD.Close()
+ defer ethUSD.Close()
+ tokenPricesUSDPipeline = testPricePipeline
+ } else {
+ // Set up a test price getter.
+ // Set up the aggregators here to avoid modifying ccipTH.
+ aggSrcNatAddr, _, aggSrcNat, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(ccipTH.Source.User, ccipTH.Source.Chain, 18, big.NewInt(2e18))
+ require.NoError(t, err)
+ _, err = aggSrcNat.UpdateRoundData(ccipTH.Source.User, big.NewInt(50), big.NewInt(17000000), big.NewInt(1000), big.NewInt(1000))
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ aggDstLnkAddr, _, aggDstLnk, err := mock_v3_aggregator_contract.DeployMockV3AggregatorContract(ccipTH.Dest.User, ccipTH.Dest.Chain, 18, big.NewInt(3e18))
+ require.NoError(t, err)
+ ccipTH.Dest.Chain.Commit()
+ _, err = aggDstLnk.UpdateRoundData(ccipTH.Dest.User, big.NewInt(50), big.NewInt(8000000), big.NewInt(1000), big.NewInt(1000))
+ require.NoError(t, err)
+ ccipTH.Dest.Chain.Commit()
+
+ priceGetterConfig := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ ccipTH.Source.WrappedNative.Address(): {
+ ChainID: ccipTH.Source.ChainID,
+ AggregatorContractAddress: aggSrcNatAddr,
+ },
+ ccipTH.Dest.LinkToken.Address(): {
+ ChainID: ccipTH.Dest.ChainID,
+ AggregatorContractAddress: aggDstLnkAddr,
+ },
+ ccipTH.Dest.WrappedNative.Address(): {
+ ChainID: ccipTH.Dest.ChainID,
+ AggregatorContractAddress: aggDstLnkAddr,
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{},
+ }
+ priceGetterConfigBytes, err := json.MarshalIndent(priceGetterConfig, "", " ")
+ require.NoError(t, err)
+ priceGetterConfigJson = string(priceGetterConfigBytes)
+ }
+
+ jobParams := ccipTH.SetUpNodesAndJobs(t, tokenPricesUSDPipeline, priceGetterConfigJson, "")
+
+ // track sequence number and nonce separately since nonce doesn't bump for messages with allowOutOfOrderExecution == true,
+ // but sequence number always bumps.
+ // for this test, when test.outOfOrder == false, sequence number and nonce are equal.
+ // when test.outOfOrder == true, nonce is not bumped at all, so sequence number and nonce are NOT equal.
+ currentSeqNum := 1
+ currentNonce := uint64(1)
+
+ t.Run("single", func(t *testing.T) {
+ tokenAmount := big.NewInt(500000003) // prime number
+ gasLimit := big.NewInt(200_003) // prime number
+
+ extraArgs, err2 := testhelpers.GetEVMExtraArgsV2(gasLimit, test.allowOutOfOrderExecution)
+ require.NoError(t, err2)
+
+ sourceBalances, err2 := testhelpers.GetBalances(t, []testhelpers.BalanceReq{
+ {Name: testhelpers.SourcePool, Addr: ccipTH.Source.LinkTokenPool.Address(), Getter: ccipTH.GetSourceLinkBalance},
+ {Name: testhelpers.OnRamp, Addr: ccipTH.Source.OnRamp.Address(), Getter: ccipTH.GetSourceLinkBalance},
+ {Name: testhelpers.SourceRouter, Addr: ccipTH.Source.Router.Address(), Getter: ccipTH.GetSourceLinkBalance},
+ {Name: testhelpers.SourcePriceRegistry, Addr: ccipTH.Source.PriceRegistry.Address(), Getter: ccipTH.GetSourceLinkBalance},
+ })
+ require.NoError(t, err2)
+ destBalances, err2 := testhelpers.GetBalances(t, []testhelpers.BalanceReq{
+ {Name: testhelpers.Receiver, Addr: ccipTH.Dest.Receivers[0].Receiver.Address(), Getter: ccipTH.GetDestLinkBalance},
+ {Name: testhelpers.DestPool, Addr: ccipTH.Dest.LinkTokenPool.Address(), Getter: ccipTH.GetDestLinkBalance},
+ {Name: testhelpers.OffRamp, Addr: ccipTH.Dest.OffRamp.Address(), Getter: ccipTH.GetDestLinkBalance},
+ })
+ require.NoError(t, err2)
+
+ ccipTH.Source.User.Value = tokenAmount
+ _, err2 = ccipTH.Source.WrappedNative.Deposit(ccipTH.Source.User)
+ require.NoError(t, err2)
+ ccipTH.Source.Chain.Commit()
+ ccipTH.Source.User.Value = nil
+
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: testhelpers.MustEncodeAddress(t, ccipTH.Dest.Receivers[0].Receiver.Address()),
+ Data: []byte("hello"),
+ TokenAmounts: []router.ClientEVMTokenAmount{
+ {
+ Token: ccipTH.Source.LinkToken.Address(),
+ Amount: tokenAmount,
+ },
+ {
+ Token: ccipTH.Source.WrappedNative.Address(),
+ Amount: tokenAmount,
+ },
+ },
+ FeeToken: ccipTH.Source.LinkToken.Address(),
+ ExtraArgs: extraArgs,
+ }
+ fee, err2 := ccipTH.Source.Router.GetFee(nil, testhelpers.DestChainSelector, msg)
+ require.NoError(t, err2)
+ // Currently no overhead and 10gwei dest gas price. So fee is simply (gasLimit * gasPrice)* link/native
+ // require.Equal(t, new(big.Int).Mul(gasLimit, gasPrice).String(), fee.String())
+ // Approve the fee amount + the token amount
+ _, err2 = ccipTH.Source.LinkToken.Approve(ccipTH.Source.User, ccipTH.Source.Router.Address(), new(big.Int).Add(fee, tokenAmount))
+ require.NoError(t, err2)
+ ccipTH.Source.Chain.Commit()
+ _, err2 = ccipTH.Source.WrappedNative.Approve(ccipTH.Source.User, ccipTH.Source.Router.Address(), tokenAmount)
+ require.NoError(t, err2)
+ ccipTH.Source.Chain.Commit()
+
+ beforeNonce, err := ccipTH.Source.OnRamp.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err)
+ ccipTH.SendRequest(t, msg)
+ // TODO: can this be moved into SendRequest?
+ if test.allowOutOfOrderExecution {
+ // the nonce for that sender must not be bumped for allowOutOfOrderExecution == true messages.
+ nonce, err2 := ccipTH.Source.OnRamp.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err2)
+ require.Equal(t, beforeNonce, nonce, "nonce must not be bumped for allowOutOfOrderExecution == true requests")
+ } else {
+ // the nonce for that sender must be bumped for allowOutOfOrderExecution == false messages.
+ nonce, err2 := ccipTH.Source.OnRamp.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err2)
+ require.Equal(t, beforeNonce+1, nonce, "nonce must be bumped for allowOutOfOrderExecution == false requests")
+ }
+
+ // Should eventually see this executed.
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum)
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum)
+
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum)
+ assert.Len(t, executionLogs, 1)
+ ccipTH.AssertExecState(t, executionLogs[0], testhelpers.ExecutionStateSuccess)
+
+ // Asserts
+ // 1) The total pool input == total pool output
+ // 2) Pool flow equals tokens sent
+ // 3) Sent tokens arrive at the receiver
+ ccipTH.AssertBalances(t, []testhelpers.BalanceAssertion{
+ {
+ Name: testhelpers.SourcePool,
+ Address: ccipTH.Source.LinkTokenPool.Address(),
+ Expected: testhelpers.MustAddBigInt(sourceBalances[testhelpers.SourcePool], tokenAmount.String()).String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.SourcePriceRegistry,
+ Address: ccipTH.Source.PriceRegistry.Address(),
+ Expected: sourceBalances[testhelpers.SourcePriceRegistry].String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ // Fees end up in the onramp.
+ Name: testhelpers.OnRamp,
+ Address: ccipTH.Source.OnRamp.Address(),
+ Expected: testhelpers.MustAddBigInt(sourceBalances[testhelpers.SourcePriceRegistry], fee.String()).String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.SourceRouter,
+ Address: ccipTH.Source.Router.Address(),
+ Expected: sourceBalances[testhelpers.SourceRouter].String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.Receiver,
+ Address: ccipTH.Dest.Receivers[0].Receiver.Address(),
+ Expected: testhelpers.MustAddBigInt(destBalances[testhelpers.Receiver], tokenAmount.String()).String(),
+ Getter: ccipTH.GetDestLinkBalance,
+ },
+ {
+ Name: testhelpers.DestPool,
+ Address: ccipTH.Dest.LinkTokenPool.Address(),
+ Expected: testhelpers.MustSubBigInt(destBalances[testhelpers.DestPool], tokenAmount.String()).String(),
+ Getter: ccipTH.GetDestLinkBalance,
+ },
+ {
+ Name: testhelpers.OffRamp,
+ Address: ccipTH.Dest.OffRamp.Address(),
+ Expected: destBalances[testhelpers.OffRamp].String(),
+ Getter: ccipTH.GetDestLinkBalance,
+ },
+ })
+ currentSeqNum++
+ if !test.allowOutOfOrderExecution {
+ currentNonce = uint64(currentSeqNum)
+ }
+ })
+
+ t.Run("multiple batches", func(t *testing.T) {
+ tokenAmount := big.NewInt(500000003)
+ gasLimit := big.NewInt(250_000)
+
+ var txs []*gethtypes.Transaction
+ // Enough to require batched executions as gasLimit per tx is 250k -> 500k -> 750k ....
+ // The actual gas usage of executing 15 messages is higher than the gas limit for
+ // a single tx. This means that when batching is turned off, and we simply include
+ // all txs without checking gas, this also fails.
+ n := 15
+ for i := 0; i < n; i++ {
+ txGasLimit := new(big.Int).Mul(gasLimit, big.NewInt(int64(i+1)))
+
+ // interleave ordered and non-ordered messages.
+ allowOutOfOrderExecution := false
+ if i%2 == 0 {
+ allowOutOfOrderExecution = true
+ }
+ extraArgs, err2 := testhelpers.GetEVMExtraArgsV2(txGasLimit, allowOutOfOrderExecution)
+ require.NoError(t, err2)
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: testhelpers.MustEncodeAddress(t, ccipTH.Dest.Receivers[0].Receiver.Address()),
+ Data: []byte("hello"),
+ TokenAmounts: []router.ClientEVMTokenAmount{
+ {
+ Token: ccipTH.Source.LinkToken.Address(),
+ Amount: tokenAmount,
+ },
+ },
+ FeeToken: ccipTH.Source.LinkToken.Address(),
+ ExtraArgs: extraArgs,
+ }
+ fee, err2 := ccipTH.Source.Router.GetFee(nil, testhelpers.DestChainSelector, msg)
+ require.NoError(t, err2)
+ // Currently no overhead and 1gwei dest gas price. So fee is simply gasLimit * gasPrice.
+ // require.Equal(t, new(big.Int).Mul(txGasLimit, gasPrice).String(), fee.String())
+ // Approve the fee amount + the token amount
+ _, err2 = ccipTH.Source.LinkToken.Approve(ccipTH.Source.User, ccipTH.Source.Router.Address(), new(big.Int).Add(fee, tokenAmount))
+ require.NoError(t, err2)
+ tx, err2 := ccipTH.Source.Router.CcipSend(ccipTH.Source.User, ccipTH.Dest.ChainSelector, msg)
+ require.NoError(t, err2)
+ txs = append(txs, tx)
+ if !allowOutOfOrderExecution {
+ currentNonce++
+ }
+ }
+
+ // Send a batch of requests in a single block
+ testhelpers.ConfirmTxs(t, txs, ccipTH.Source.Chain)
+ for i := 0; i < n; i++ {
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum+i)
+ }
+ // Should see a report with the full range
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum+n-1)
+ // Should all be executed
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum+n-1)
+ for _, execLog := range executionLogs {
+ ccipTH.AssertExecState(t, execLog, testhelpers.ExecutionStateSuccess)
+ }
+
+ currentSeqNum += n
+ })
+
+ // Deploy new on ramp,Commit store,off ramp
+ // Delete v1 jobs
+ // Send a number of requests
+ // Upgrade the router with new contracts
+ // create new jobs
+ // Verify all pending requests are sent after the contracts are upgraded
+ t.Run("upgrade contracts and verify requests can be sent with upgraded contract", func(t *testing.T) {
+ gasLimit := big.NewInt(200_003) // prime number
+ tokenAmount := big.NewInt(100)
+ commitStoreV1 := ccipTH.Dest.CommitStore
+ offRampV1 := ccipTH.Dest.OffRamp
+ onRampV1 := ccipTH.Source.OnRamp
+ // deploy v2 contracts
+ ccipTH.DeployNewOnRamp(t)
+ ccipTH.DeployNewCommitStore(t)
+ ccipTH.DeployNewOffRamp(t)
+
+ // send a request as the v2 contracts are not enabled in router it should route through the v1 contracts
+ t.Logf("sending request for seqnum %d", currentSeqNum)
+ ccipTH.SendMessage(t, gasLimit, tokenAmount, ccipTH.Dest.Receivers[0].Receiver.Address())
+ ccipTH.Source.Chain.Commit()
+ ccipTH.Dest.Chain.Commit()
+ t.Logf("verifying seqnum %d on previous onRamp %s", currentSeqNum, onRampV1.Address().Hex())
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum, onRampV1.Address())
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum, commitStoreV1.Address())
+ executionLog := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum, offRampV1.Address())
+ ccipTH.AssertExecState(t, executionLog[0], testhelpers.ExecutionStateSuccess, offRampV1.Address())
+
+ nonceAtOnRampV1, err := onRampV1.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err, "getting nonce from onRamp")
+ require.Equal(t, currentNonce, nonceAtOnRampV1, "nonce should be synced from v1 onRamp")
+ nonceAtOffRampV1, err := offRampV1.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err, "getting nonce from offRamp")
+ require.Equal(t, currentNonce, nonceAtOffRampV1, "nonce should be synced from v1 offRamp")
+
+ // enable the newly deployed contracts
+ newConfigBlock := ccipTH.Dest.Chain.Blockchain().CurrentBlock().Number.Int64()
+ ccipTH.EnableOnRamp(t)
+ ccipTH.EnableCommitStore(t)
+ ccipTH.EnableOffRamp(t)
+ srcStartBlock := ccipTH.Source.Chain.Blockchain().CurrentBlock().Number.Uint64()
+
+ // send a number of requests, the requests should not be delivered yet as the previous contracts are not configured
+ // with the router anymore
+ startSeq := 1
+ noOfRequests := 5
+ endSeqNum := startSeq + noOfRequests
+ for i := startSeq; i <= endSeqNum; i++ {
+ t.Logf("sending request for seqnum %d", i)
+ ccipTH.SendMessage(t, gasLimit, tokenAmount, ccipTH.Dest.Receivers[0].Receiver.Address())
+ ccipTH.Source.Chain.Commit()
+ ccipTH.Dest.Chain.Commit()
+ ccipTH.EventuallySendRequested(t, uint64(i))
+ }
+
+ // delete v1 jobs
+ for _, node := range ccipTH.Nodes {
+ id := node.FindJobIDForContract(t, commitStoreV1.Address())
+ require.Greater(t, id, int32(0))
+ t.Logf("deleting job %d", id)
+ err = node.App.DeleteJob(context.Background(), id)
+ require.NoError(t, err)
+ id = node.FindJobIDForContract(t, offRampV1.Address())
+ require.Greater(t, id, int32(0))
+ t.Logf("deleting job %d", id)
+ err = node.App.DeleteJob(context.Background(), id)
+ require.NoError(t, err)
+ }
+
+ // Commit on both chains to reach Finality
+ ccipTH.Source.Chain.Commit()
+ ccipTH.Dest.Chain.Commit()
+
+ // create new jobs
+ jobParams = ccipTH.NewCCIPJobSpecParams(tokenPricesUSDPipeline, priceGetterConfigJson, newConfigBlock, "")
+ jobParams.Version = "v2"
+ jobParams.SourceStartBlock = srcStartBlock
+ ccipTH.AddAllJobs(t, jobParams)
+ committedSeqNum := uint64(0)
+ // Now the requests should be delivered
+ for i := startSeq; i <= endSeqNum; i++ {
+ t.Logf("verifying seqnum %d", i)
+ ccipTH.AllNodesHaveReqSeqNum(t, i)
+ if committedSeqNum < uint64(i+1) {
+ committedSeqNum = ccipTH.EventuallyReportCommitted(t, i)
+ }
+ ccipTH.EventuallyExecutionStateChangedToSuccess(t, []uint64{uint64(i)}, uint64(newConfigBlock))
+ }
+
+ // nonces should be correctly synced from v1 contracts for the sender
+ nonceAtOnRampV2, err := ccipTH.Source.OnRamp.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err, "getting nonce from onRamp")
+ nonceAtOffRampV2, err := ccipTH.Dest.OffRamp.GetSenderNonce(nil, ccipTH.Source.User.From)
+ require.NoError(t, err, "getting nonce from offRamp")
+ require.Equal(t, nonceAtOnRampV1+uint64(noOfRequests)+1, nonceAtOnRampV2, "nonce should be synced from v1 onRamps")
+ require.Equal(t, nonceAtOffRampV1+uint64(noOfRequests)+1, nonceAtOffRampV2, "nonce should be synced from v1 offRamps")
+ currentSeqNum = endSeqNum + 1
+ if !test.allowOutOfOrderExecution {
+ currentNonce = uint64(currentSeqNum)
+ }
+ })
+
+ t.Run("pay nops", func(t *testing.T) {
+ linkToTransferToOnRamp := big.NewInt(1e18)
+
+ // transfer some link to onramp to pay the nops
+ _, err := ccipTH.Source.LinkToken.Transfer(ccipTH.Source.User, ccipTH.Source.OnRamp.Address(), linkToTransferToOnRamp)
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ srcBalReq := []testhelpers.BalanceReq{
+ {
+ Name: testhelpers.Sender,
+ Addr: ccipTH.Source.User.From,
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ {
+ Name: testhelpers.OnRampNative,
+ Addr: ccipTH.Source.OnRamp.Address(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ {
+ Name: testhelpers.OnRamp,
+ Addr: ccipTH.Source.OnRamp.Address(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.SourceRouter,
+ Addr: ccipTH.Source.Router.Address(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ }
+
+ var nopsAndWeights []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight
+ var totalWeight uint16
+ nodes := ccipTH.Nodes
+ for i := range nodes {
+ // For now set the transmitter addresses to be the same as the payee addresses
+ nodes[i].PaymentReceiver = nodes[i].Transmitter
+ nopsAndWeights = append(nopsAndWeights, evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{
+ Nop: nodes[i].PaymentReceiver,
+ Weight: 5,
+ })
+ totalWeight += 5
+ srcBalReq = append(srcBalReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("node %d", i),
+ Addr: nodes[i].PaymentReceiver,
+ Getter: ccipTH.GetSourceLinkBalance,
+ })
+ }
+ srcBalances, err := testhelpers.GetBalances(t, srcBalReq)
+ require.NoError(t, err)
+
+ // set nops on the onramp
+ ccipTH.SetNopsOnRamp(t, nopsAndWeights)
+
+ // send a message
+ extraArgs, err := testhelpers.GetEVMExtraArgsV2(big.NewInt(200_000), test.allowOutOfOrderExecution)
+ require.NoError(t, err)
+
+ // FeeToken is empty, indicating it should use native token
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: testhelpers.MustEncodeAddress(t, ccipTH.Dest.Receivers[1].Receiver.Address()),
+ Data: []byte("hello"),
+ TokenAmounts: []router.ClientEVMTokenAmount{},
+ ExtraArgs: extraArgs,
+ FeeToken: common.Address{},
+ }
+ fee, err := ccipTH.Source.Router.GetFee(nil, testhelpers.DestChainSelector, msg)
+ require.NoError(t, err)
+
+ // verify message is sent
+ ccipTH.Source.User.Value = fee
+ ccipTH.SendRequest(t, msg)
+ ccipTH.Source.User.Value = nil
+ ccipTH.AllNodesHaveReqSeqNum(t, currentSeqNum)
+ ccipTH.EventuallyReportCommitted(t, currentSeqNum)
+
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, currentSeqNum, currentSeqNum)
+ assert.Len(t, executionLogs, 1)
+ ccipTH.AssertExecState(t, executionLogs[0], testhelpers.ExecutionStateSuccess)
+ currentSeqNum++
+ if test.allowOutOfOrderExecution {
+ currentNonce = uint64(currentSeqNum)
+ }
+
+ // get the nop fee
+ nopFee, err := ccipTH.Source.OnRamp.GetNopFeesJuels(nil)
+ require.NoError(t, err)
+ t.Log("nopFee", nopFee)
+
+ // withdraw fees and verify there is still fund left for nop payment
+ _, err = ccipTH.Source.OnRamp.WithdrawNonLinkFees(
+ ccipTH.Source.User,
+ ccipTH.Source.WrappedNative.Address(),
+ ccipTH.Source.User.From,
+ )
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ // pay nops
+ _, err = ccipTH.Source.OnRamp.PayNops(ccipTH.Source.User)
+ require.NoError(t, err)
+ ccipTH.Source.Chain.Commit()
+
+ srcBalanceAssertions := []testhelpers.BalanceAssertion{
+ {
+ // Onramp should not have any balance left in wrapped native
+ Name: testhelpers.OnRampNative,
+ Address: ccipTH.Source.OnRamp.Address(),
+ Expected: big.NewInt(0).String(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ {
+ // Onramp should have the remaining link after paying nops
+ Name: testhelpers.OnRamp,
+ Address: ccipTH.Source.OnRamp.Address(),
+ Expected: new(big.Int).Sub(srcBalances[testhelpers.OnRamp], nopFee).String(),
+ Getter: ccipTH.GetSourceLinkBalance,
+ },
+ {
+ Name: testhelpers.SourceRouter,
+ Address: ccipTH.Source.Router.Address(),
+ Expected: srcBalances[testhelpers.SourceRouter].String(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ // onRamp's balance (of previously sent fee during message sending) should have been transferred to
+ // the owner as a result of WithdrawNonLinkFees
+ {
+ Name: testhelpers.Sender,
+ Address: ccipTH.Source.User.From,
+ Expected: fee.String(),
+ Getter: ccipTH.GetSourceWrappedTokenBalance,
+ },
+ }
+
+ // the nodes should be paid according to the weights assigned
+ for i, node := range nodes {
+ paymentWeight := float64(nopsAndWeights[i].Weight) / float64(totalWeight)
+ paidInFloat := paymentWeight * float64(nopFee.Int64())
+ paid, _ := new(big.Float).SetFloat64(paidInFloat).Int64()
+ bal := new(big.Int).Add(
+ new(big.Int).SetInt64(paid),
+ srcBalances[fmt.Sprintf("node %d", i)]).String()
+ srcBalanceAssertions = append(srcBalanceAssertions, testhelpers.BalanceAssertion{
+ Name: fmt.Sprintf("node %d", i),
+ Address: node.PaymentReceiver,
+ Expected: bal,
+ Getter: ccipTH.GetSourceLinkBalance,
+ })
+ }
+ ccipTH.AssertBalances(t, srcBalanceAssertions)
+ })
+
+ // Keep on sending a bunch of messages
+ // In the meantime update onchainConfig with new price registry address
+ // Verify if the jobs can pick up updated config
+ // Verify if all the messages are sent
+ t.Run("config change or price registry update while requests are inflight", func(t *testing.T) {
+ gasLimit := big.NewInt(200_003) // prime number
+ tokenAmount := big.NewInt(100)
+ msgWg := &sync.WaitGroup{}
+ msgWg.Add(1)
+ ticker := time.NewTicker(100 * time.Millisecond)
+ defer ticker.Stop()
+ startSeq := currentSeqNum
+ endSeq := currentSeqNum + 20
+
+ // send message with the old configs
+ ccipTH.SendMessage(t, gasLimit, tokenAmount, ccipTH.Dest.Receivers[0].Receiver.Address())
+ ccipTH.Source.Chain.Commit()
+
+ go func(ccipContracts testhelpers.CCIPContracts, currentSeqNum int) {
+ seqNumber := currentSeqNum + 1
+ defer msgWg.Done()
+ for {
+ <-ticker.C // wait for ticker
+ t.Logf("sending request for seqnum %d", seqNumber)
+ ccipContracts.SendMessage(t, gasLimit, tokenAmount, ccipTH.Dest.Receivers[0].Receiver.Address())
+ ccipContracts.Source.Chain.Commit()
+ seqNumber++
+ if seqNumber == endSeq {
+ return
+ }
+ }
+ }(ccipTH.CCIPContracts, currentSeqNum)
+
+ ccipTH.DeployNewPriceRegistry(t)
+ commitOnchainConfig := ccipTH.CreateDefaultCommitOnchainConfig(t)
+ commitOffchainConfig := ccipTH.CreateDefaultCommitOffchainConfig(t)
+ execOnchainConfig := ccipTH.CreateDefaultExecOnchainConfig(t)
+ execOffchainConfig := ccipTH.CreateDefaultExecOffchainConfig(t)
+
+ ccipTH.SetupOnchainConfig(t, commitOnchainConfig, commitOffchainConfig, execOnchainConfig, execOffchainConfig)
+
+ // wait for all requests to be complete
+ msgWg.Wait()
+ for i := startSeq; i < endSeq; i++ {
+ ccipTH.AllNodesHaveReqSeqNum(t, i)
+ ccipTH.EventuallyReportCommitted(t, i)
+
+ executionLogs := ccipTH.AllNodesHaveExecutedSeqNums(t, i, i)
+ assert.Len(t, executionLogs, 1)
+ ccipTH.AssertExecState(t, executionLogs[0], testhelpers.ExecutionStateSuccess)
+ }
+
+ for i, node := range ccipTH.Nodes {
+ t.Logf("verifying node %d", i)
+ node.EventuallyNodeUsesNewCommitConfig(t, ccipTH, ccipdata.CommitOnchainConfig{
+ PriceRegistry: ccipTH.Dest.PriceRegistry.Address(),
+ })
+ node.EventuallyNodeUsesNewExecConfig(t, ccipTH, v1_5_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: testhelpers.PermissionLessExecutionThresholdSeconds,
+ Router: ccipTH.Dest.Router.Address(),
+ PriceRegistry: ccipTH.Dest.PriceRegistry.Address(),
+ MaxDataBytes: 1e5,
+ MaxNumberOfTokensPerMsg: 5,
+ MaxPoolReleaseOrMintGas: 200_000,
+ MaxTokenTransferGas: 100_000,
+ })
+ node.EventuallyNodeUsesUpdatedPriceRegistry(t, ccipTH)
+ }
+ currentSeqNum = endSeq
+ if test.allowOutOfOrderExecution {
+ currentNonce = uint64(currentSeqNum)
+ }
+ })
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/autosync.go b/core/services/ocr2/plugins/ccip/internal/cache/autosync.go
new file mode 100644
index 00000000000..690b4dd05b9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/autosync.go
@@ -0,0 +1,141 @@
+package cache
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+)
+
+type AutoSync[T any] interface {
+ Get(ctx context.Context, syncFunc func(ctx context.Context) (T, error)) (T, error)
+}
+
+// LogpollerEventsBased IMPORTANT: Cache refresh relies on the events that are finalized.
+// This introduces some delay between the event onchain occurrence and cache refreshing.
+// This is intentional, because we want to prevent handling reorgs within the cache.
+type LogpollerEventsBased[T any] struct {
+ logPoller logpoller.LogPoller
+ observedEvents []common.Hash
+ address common.Address
+
+ lock *sync.RWMutex
+ value T
+ lastChangeBlock int64
+}
+
+func NewLogpollerEventsBased[T any](
+ lp logpoller.LogPoller,
+ observedEvents []common.Hash,
+ contractAddress common.Address,
+) *LogpollerEventsBased[T] {
+ var emptyValue T
+ return &LogpollerEventsBased[T]{
+ logPoller: lp,
+ observedEvents: observedEvents,
+ address: contractAddress,
+
+ lock: &sync.RWMutex{},
+ value: emptyValue,
+ lastChangeBlock: 0,
+ }
+}
+
+func (c *LogpollerEventsBased[T]) Get(ctx context.Context, syncFunc func(ctx context.Context) (T, error)) (T, error) {
+ var empty T
+
+ hasExpired, newEventBlockNum, err := c.hasExpired(ctx)
+ if err != nil {
+ return empty, fmt.Errorf("check cache expiration: %w", err)
+ }
+
+ if hasExpired {
+ var latestValue T
+ latestValue, err = syncFunc(ctx)
+ if err != nil {
+ return empty, fmt.Errorf("sync func: %w", err)
+ }
+
+ c.set(latestValue, newEventBlockNum)
+ return latestValue, nil
+ }
+
+ cachedValue := c.get()
+ if err != nil {
+ return empty, fmt.Errorf("get cached value: %w", err)
+ }
+
+ c.lock.Lock()
+ if newEventBlockNum > c.lastChangeBlock {
+ // update the most recent block number
+ // that way the scanning window is shorter in the next run
+ c.lastChangeBlock = newEventBlockNum
+ }
+ c.lock.Unlock()
+
+ return cachedValue, nil
+}
+
+func (c *LogpollerEventsBased[T]) hasExpired(ctx context.Context) (expired bool, blockOfLatestEvent int64, err error) {
+ c.lock.RLock()
+ blockOfCurrentValue := c.lastChangeBlock
+ c.lock.RUnlock()
+
+ // NOTE: latest block should be fetched before LatestBlockByEventSigsAddrsWithConfs
+ // Otherwise there might be new events between LatestBlockByEventSigsAddrsWithConfs and
+ // latestBlock which will be missed.
+ latestBlock, err := c.logPoller.LatestBlock(ctx)
+ latestFinalizedBlock := int64(0)
+ if err != nil && !errors.Is(err, sql.ErrNoRows) {
+ return false, 0, fmt.Errorf("get latest log poller block: %w", err)
+ } else if err == nil {
+ // Since we know that we have all the events till latestBlock.FinalizedBlockNumber
+ // we want to return the block number instead of the block of the latest event
+ // for reducing the scan window on the next call.
+ latestFinalizedBlock = latestBlock.FinalizedBlockNumber
+ }
+
+ if blockOfCurrentValue == 0 {
+ return true, latestFinalizedBlock, nil
+ }
+
+ blockOfLatestEvent, err = c.logPoller.LatestBlockByEventSigsAddrsWithConfs(
+ ctx,
+ blockOfCurrentValue,
+ c.observedEvents,
+ []common.Address{c.address},
+ evmtypes.Finalized,
+ )
+ if err != nil {
+ return false, 0, fmt.Errorf("get latest events form lp: %w", err)
+ }
+
+ if blockOfLatestEvent > latestFinalizedBlock {
+ latestFinalizedBlock = blockOfLatestEvent
+ }
+ return blockOfLatestEvent > blockOfCurrentValue, latestFinalizedBlock, nil
+}
+
+func (c *LogpollerEventsBased[T]) set(value T, blockNum int64) {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if c.lastChangeBlock > blockNum {
+ return
+ }
+
+ c.value = value
+ c.lastChangeBlock = blockNum
+}
+
+func (c *LogpollerEventsBased[T]) get() T {
+ c.lock.RLock()
+ defer c.lock.RUnlock()
+ return c.value
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/autosync_test.go b/core/services/ocr2/plugins/ccip/internal/cache/autosync_test.go
new file mode 100644
index 00000000000..0babfeb421d
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/autosync_test.go
@@ -0,0 +1,128 @@
+package cache_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ 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/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+)
+
+func TestLogpollerEventsBased(t *testing.T) {
+ ctx := testutils.Context(t)
+ lp := lpmocks.NewLogPoller(t)
+ observedEvents := []common.Hash{
+ utils.Bytes32FromString("event a"),
+ utils.Bytes32FromString("event b"),
+ }
+ contractAddress := utils.RandomAddress()
+ c := cache.NewLogpollerEventsBased[[]int](lp, observedEvents, contractAddress)
+
+ testRounds := []struct {
+ logPollerLatestBlock int64 // latest block that logpoller parsed
+ latestEventBlock int64 // latest block that an event was seen
+ stateLatestBlock int64 // block of the current cached value (before run)
+ shouldSync bool // whether we expect sync to happen in this round
+ syncData []int // data returned after sync
+ expData []int // expected data that cache will return
+ }{
+ {
+ // this is the first 'Get' call to our cache, an event was seen at block 800
+ // and now log poller has reached block 1000.
+ logPollerLatestBlock: 1000,
+ latestEventBlock: 800,
+ stateLatestBlock: 0,
+ shouldSync: true,
+ syncData: []int{1, 2, 3},
+ expData: []int{1, 2, 3},
+ },
+ {
+ // log poller moved a few blocks and there weren't any new events
+ logPollerLatestBlock: 1010,
+ latestEventBlock: 800,
+ stateLatestBlock: 1000,
+ shouldSync: false,
+ expData: []int{1, 2, 3},
+ },
+ {
+ // log poller moved a few blocks and there was a new event
+ logPollerLatestBlock: 1020,
+ latestEventBlock: 1020,
+ stateLatestBlock: 1010,
+ shouldSync: true,
+ syncData: []int{111},
+ expData: []int{111},
+ },
+ {
+ // log poller moved a few more blocks and there was another new event
+ logPollerLatestBlock: 1050,
+ latestEventBlock: 1040,
+ stateLatestBlock: 1020,
+ shouldSync: true,
+ syncData: []int{222},
+ expData: []int{222},
+ },
+ {
+ // log poller moved a few more blocks and there wasn't any new event
+ logPollerLatestBlock: 1100,
+ latestEventBlock: 1040,
+ stateLatestBlock: 1050,
+ shouldSync: false,
+ expData: []int{222},
+ },
+ {
+ // log poller moved a few more blocks and there wasn't any new event
+ logPollerLatestBlock: 1300,
+ latestEventBlock: 1040,
+ stateLatestBlock: 1100,
+ shouldSync: false,
+ expData: []int{222},
+ },
+ {
+ // log poller moved a few more blocks and there was a new event
+ // more recent than latest block (for whatever internal reason)
+ logPollerLatestBlock: 1300,
+ latestEventBlock: 1305,
+ stateLatestBlock: 1300,
+ shouldSync: true,
+ syncData: []int{666},
+ expData: []int{666},
+ },
+ {
+ // log poller moved a few more blocks and there wasn't any new event
+ logPollerLatestBlock: 1300,
+ latestEventBlock: 1305,
+ stateLatestBlock: 1305, // <-- that's what we are testing in this round
+ shouldSync: false,
+ expData: []int{666},
+ },
+ }
+
+ for _, round := range testRounds {
+ lp.On("LatestBlock", mock.Anything).
+ Return(logpoller.LogPollerBlock{FinalizedBlockNumber: round.logPollerLatestBlock}, nil).Once()
+
+ if round.stateLatestBlock > 0 {
+ lp.On(
+ "LatestBlockByEventSigsAddrsWithConfs",
+ mock.Anything,
+ round.stateLatestBlock,
+ observedEvents,
+ []common.Address{contractAddress},
+ evmtypes.Finalized,
+ ).Return(round.latestEventBlock, nil).Once()
+ }
+
+ data, err := c.Get(ctx, func(ctx context.Context) ([]int, error) { return round.syncData, nil })
+ assert.NoError(t, err)
+ assert.Equal(t, round.expData, data)
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/chain_health.go b/core/services/ocr2/plugins/ccip/internal/cache/chain_health.go
new file mode 100644
index 00000000000..00f90615eb2
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/chain_health.go
@@ -0,0 +1,273 @@
+package cache
+
+import (
+ "context"
+ "sync"
+ "time"
+
+ "github.com/patrickmn/go-cache"
+ "github.com/pkg/errors"
+ "golang.org/x/sync/errgroup"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+// ChainHealthcheck checks the health of the both source and destination chain.
+// Based on the values returned, CCIP can make a decision to stop or continue processing messages.
+// There are four things verified here:
+// 1. Source chain is healthy (this is verified by checking if source LogPoller saw finality violation)
+// 2. Dest chain is healthy (this is verified by checking if destination LogPoller saw finality violation)
+// 3. CommitStore is down (this is verified by checking if CommitStore is down and destination RMN is not cursed)
+// 4. Source chain is cursed (this is verified by checking if source RMN is not cursed)
+//
+// Whenever any of the above checks fail, the chain is considered unhealthy and the CCIP should stop
+// processing messages. Additionally, when the chain is unhealthy, this information is considered "sticky"
+// and is cached for a certain period of time based on defaultGlobalStatusExpirationDuration.
+// This may lead to some false-positives, but in this case we want to be extra cautious and avoid executing any reorged messages.
+//
+// Additionally, to reduce the number of calls to the RPC, we refresh RMN state in the background based on defaultRMNStateRefreshInterval
+type ChainHealthcheck interface {
+ job.ServiceCtx
+ IsHealthy(ctx context.Context) (bool, error)
+}
+
+const (
+ // RMN curse state is refreshed every 10 seconds
+ defaultRMNStateRefreshInterval = 10 * time.Second
+ // Whenever we mark the chain as unhealthy, we cache this information for 30 minutes
+ defaultGlobalStatusExpirationDuration = 30 * time.Minute
+
+ globalStatusKey = "globalStatus"
+ rmnStatusKey = "rmnCurseCheck"
+)
+
+type chainHealthcheck struct {
+ cache *cache.Cache
+ globalStatusKey string
+ rmnStatusKey string
+ globalStatusExpiration time.Duration
+ rmnStatusRefreshInterval time.Duration
+
+ lggr logger.Logger
+ onRamp ccipdata.OnRampReader
+ commitStore ccipdata.CommitStoreReader
+
+ services.StateMachine
+ wg *sync.WaitGroup
+ backgroundCtx context.Context //nolint:containedctx
+ backgroundCancel context.CancelFunc
+}
+
+func NewChainHealthcheck(lggr logger.Logger, onRamp ccipdata.OnRampReader, commitStore ccipdata.CommitStoreReader) *chainHealthcheck {
+ ctx, cancel := context.WithCancel(context.Background())
+
+ ch := &chainHealthcheck{
+ // Different keys use different expiration times, so we don't need to worry about the default value
+ cache: cache.New(cache.NoExpiration, 0),
+ rmnStatusKey: rmnStatusKey,
+ globalStatusKey: globalStatusKey,
+ globalStatusExpiration: defaultGlobalStatusExpirationDuration,
+ rmnStatusRefreshInterval: defaultRMNStateRefreshInterval,
+
+ lggr: lggr,
+ onRamp: onRamp,
+ commitStore: commitStore,
+
+ wg: new(sync.WaitGroup),
+ backgroundCtx: ctx,
+ backgroundCancel: cancel,
+ }
+ return ch
+}
+
+// newChainHealthcheckWithCustomEviction is used for testing purposes only. It doesn't start background worker
+func newChainHealthcheckWithCustomEviction(lggr logger.Logger, onRamp ccipdata.OnRampReader, commitStore ccipdata.CommitStoreReader, globalStatusDuration time.Duration, rmnStatusRefreshInterval time.Duration) *chainHealthcheck {
+ ctx, cancel := context.WithCancel(context.Background())
+
+ return &chainHealthcheck{
+ cache: cache.New(rmnStatusRefreshInterval, 0),
+ rmnStatusKey: rmnStatusKey,
+ globalStatusKey: globalStatusKey,
+ globalStatusExpiration: globalStatusDuration,
+ rmnStatusRefreshInterval: rmnStatusRefreshInterval,
+
+ lggr: lggr,
+ onRamp: onRamp,
+ commitStore: commitStore,
+
+ wg: new(sync.WaitGroup),
+ backgroundCtx: ctx,
+ backgroundCancel: cancel,
+ }
+}
+
+type rmnResponse struct {
+ healthy bool
+ err error
+}
+
+func (c *chainHealthcheck) IsHealthy(ctx context.Context) (bool, error) {
+ // Verify if flag is raised to indicate that the chain is not healthy
+ // If set to false then immediately return false without checking the chain
+ if cachedValue, found := c.cache.Get(c.globalStatusKey); found {
+ healthy, ok := cachedValue.(bool)
+ // If cached value is properly casted to bool and not healthy it means the sticky flag is raised
+ // and should be returned immediately
+ if !ok {
+ c.lggr.Criticalw("Failed to cast cached value to sticky healthcheck", "value", cachedValue)
+ } else if ok && !healthy {
+ return false, nil
+ }
+ }
+
+ // These checks are cheap and don't require any communication with the database or RPC
+ if healthy, err := c.checkIfReadersAreHealthy(ctx); err != nil {
+ return false, err
+ } else if !healthy {
+ c.markStickyStatusUnhealthy()
+ return healthy, nil
+ }
+
+ // First call might initialize cache if it's not initialized yet. Otherwise, it will use the cached value
+ if healthy, err := c.checkIfRMNsAreHealthy(ctx); err != nil {
+ return false, err
+ } else if !healthy {
+ c.markStickyStatusUnhealthy()
+ return healthy, nil
+ }
+ return true, nil
+}
+
+func (c *chainHealthcheck) Start(context.Context) error {
+ return c.StateMachine.StartOnce("ChainHealthcheck", func() error {
+ c.lggr.Info("Starting ChainHealthcheck")
+ c.wg.Add(1)
+ c.run()
+ return nil
+ })
+}
+
+func (c *chainHealthcheck) Close() error {
+ return c.StateMachine.StopOnce("ChainHealthcheck", func() error {
+ c.lggr.Info("Closing ChainHealthcheck")
+ c.backgroundCancel()
+ c.wg.Wait()
+ return nil
+ })
+}
+
+func (c *chainHealthcheck) run() {
+ ticker := time.NewTicker(c.rmnStatusRefreshInterval)
+ go func() {
+ defer c.wg.Done()
+ // Refresh the RMN state immediately after starting the background refresher
+ _, _ = c.refresh(c.backgroundCtx)
+
+ for {
+ select {
+ case <-c.backgroundCtx.Done():
+ return
+ case <-ticker.C:
+ _, err := c.refresh(c.backgroundCtx)
+ if err != nil {
+ c.lggr.Errorw("Failed to refresh RMN state in the background", "err", err)
+ }
+ }
+ }
+ }()
+}
+
+func (c *chainHealthcheck) refresh(ctx context.Context) (bool, error) {
+ healthy, err := c.fetchRMNCurseState(ctx)
+ c.cache.Set(
+ c.rmnStatusKey,
+ rmnResponse{healthy, err},
+ // Cache the value for 3 refresh intervals, this is just a defensive approach
+ // that will enforce the RMN state to be refreshed in case of bg worker hiccup (it should never happen)
+ 3*c.rmnStatusRefreshInterval,
+ )
+ return healthy, err
+}
+
+// checkIfReadersAreHealthy checks if the source and destination chains are healthy by calling underlying LogPoller
+// These calls are cheap because they don't require any communication with the database or RPC, so we don't have
+// to cache the result of these calls.
+func (c *chainHealthcheck) checkIfReadersAreHealthy(ctx context.Context) (bool, error) {
+ sourceChainHealthy, err := c.onRamp.IsSourceChainHealthy(ctx)
+ if err != nil {
+ return false, errors.Wrap(err, "onRamp IsSourceChainHealthy errored")
+ }
+
+ destChainHealthy, err := c.commitStore.IsDestChainHealthy(ctx)
+ if err != nil {
+ return false, errors.Wrap(err, "commitStore IsDestChainHealthy errored")
+ }
+
+ if !sourceChainHealthy || !destChainHealthy {
+ c.lggr.Criticalw(
+ "Lane processing is stopped because source or destination chain is reported unhealthy",
+ "sourceChainHealthy", sourceChainHealthy,
+ "destChainHealthy", destChainHealthy,
+ )
+ }
+ return sourceChainHealthy && destChainHealthy, nil
+}
+
+func (c *chainHealthcheck) checkIfRMNsAreHealthy(ctx context.Context) (bool, error) {
+ if cachedValue, found := c.cache.Get(c.rmnStatusKey); found {
+ rmn := cachedValue.(rmnResponse)
+ return rmn.healthy, rmn.err
+ }
+
+ // If the value is not found in the cache, fetch the RMN curse state in a sync manner for the first time
+ c.lggr.Info("Refreshing RMN state from the plugin routine, this should happen only once per lane during boot")
+ return c.refresh(ctx)
+}
+
+func (c *chainHealthcheck) markStickyStatusUnhealthy() {
+ c.cache.Set(c.globalStatusKey, false, c.globalStatusExpiration)
+}
+
+func (c *chainHealthcheck) fetchRMNCurseState(ctx context.Context) (bool, error) {
+ var (
+ eg = new(errgroup.Group)
+ isCommitStoreDown bool
+ isSourceCursed bool
+ )
+
+ eg.Go(func() error {
+ var err error
+ isCommitStoreDown, err = c.commitStore.IsDown(ctx)
+ if err != nil {
+ return errors.Wrap(err, "commitStore isDown check errored")
+ }
+ return nil
+ })
+
+ eg.Go(func() error {
+ var err error
+ isSourceCursed, err = c.onRamp.IsSourceCursed(ctx)
+ if err != nil {
+ return errors.Wrap(err, "onRamp isSourceCursed errored")
+ }
+ return nil
+ })
+
+ if err := eg.Wait(); err != nil {
+ return false, err
+ }
+
+ if isCommitStoreDown || isSourceCursed {
+ c.lggr.Criticalw(
+ "Lane processing is stopped because source chain is cursed or CommitStore is down",
+ "isCommitStoreDown", isCommitStoreDown,
+ "isSourceCursed", isSourceCursed,
+ )
+ return false, nil
+ }
+ return true, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/chain_health_test.go b/core/services/ocr2/plugins/ccip/internal/cache/chain_health_test.go
new file mode 100644
index 00000000000..ccdc7c4b22f
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/chain_health_test.go
@@ -0,0 +1,303 @@
+package cache
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+)
+
+func Test_RMNStateCaching(t *testing.T) {
+ ctx := tests.Context(t)
+ lggr := logger.TestLogger(t)
+ mockCommitStore := mocks.NewCommitStoreReader(t)
+ mockOnRamp := mocks.NewOnRampReader(t)
+
+ chainState := newChainHealthcheckWithCustomEviction(lggr, mockOnRamp, mockCommitStore, 10*time.Hour, 10*time.Hour)
+
+ // Chain is not cursed and healthy
+ mockCommitStore.On("IsDown", ctx).Return(false, nil).Once()
+ mockCommitStore.On("IsDestChainHealthy", ctx).Return(true, nil).Maybe()
+ mockOnRamp.On("IsSourceCursed", ctx).Return(false, nil).Once()
+ mockOnRamp.On("IsSourceChainHealthy", ctx).Return(true, nil).Maybe()
+ healthy, err := chainState.IsHealthy(ctx)
+ assert.NoError(t, err)
+ assert.True(t, healthy)
+
+ // Chain is cursed, but cache is stale
+ mockCommitStore.On("IsDown", ctx).Return(true, nil).Once()
+ mockOnRamp.On("IsSourceCursed", ctx).Return(true, nil).Once()
+ healthy, err = chainState.IsHealthy(ctx)
+ assert.NoError(t, err)
+ assert.True(t, healthy)
+
+ // Enforce cache refresh
+ _, err = chainState.refresh(ctx)
+ assert.NoError(t, err)
+
+ healthy, err = chainState.IsHealthy(ctx)
+ assert.Nil(t, err)
+ assert.False(t, healthy)
+
+ // Chain is not cursed, but previous curse should be "sticky" even when force refreshing
+ mockCommitStore.On("IsDown", ctx).Return(false, nil).Maybe()
+ mockOnRamp.On("IsSourceCursed", ctx).Return(false, nil).Maybe()
+ // Enforce cache refresh
+ _, err = chainState.refresh(ctx)
+ assert.NoError(t, err)
+
+ healthy, err = chainState.IsHealthy(ctx)
+ assert.Nil(t, err)
+ assert.False(t, healthy)
+}
+
+func Test_ChainStateIsCached(t *testing.T) {
+ ctx := tests.Context(t)
+ lggr := logger.TestLogger(t)
+ mockCommitStore := mocks.NewCommitStoreReader(t)
+ mockOnRamp := mocks.NewOnRampReader(t)
+
+ chainState := newChainHealthcheckWithCustomEviction(lggr, mockOnRamp, mockCommitStore, 10*time.Hour, 10*time.Hour)
+
+ // Chain is not cursed and healthy
+ mockCommitStore.On("IsDown", ctx).Return(false, nil).Maybe()
+ mockCommitStore.On("IsDestChainHealthy", ctx).Return(true, nil).Once()
+ mockOnRamp.On("IsSourceCursed", ctx).Return(false, nil).Maybe()
+ mockOnRamp.On("IsSourceChainHealthy", ctx).Return(true, nil).Once()
+
+ _, err := chainState.refresh(ctx)
+ assert.NoError(t, err)
+
+ healthy, err := chainState.IsHealthy(ctx)
+ assert.NoError(t, err)
+ assert.True(t, healthy)
+
+ // Chain is not healthy
+ mockCommitStore.On("IsDestChainHealthy", ctx).Return(false, nil).Once()
+ mockOnRamp.On("IsSourceChainHealthy", ctx).Return(false, nil).Once()
+ _, err = chainState.refresh(ctx)
+ assert.NoError(t, err)
+
+ healthy, err = chainState.IsHealthy(ctx)
+ assert.NoError(t, err)
+ assert.False(t, healthy)
+
+ // Previous value is returned
+ mockCommitStore.On("IsDestChainHealthy", ctx).Return(true, nil).Maybe()
+ mockOnRamp.On("IsSourceChainHealthy", ctx).Return(true, nil).Maybe()
+
+ _, err = chainState.refresh(ctx)
+ assert.NoError(t, err)
+
+ healthy, err = chainState.IsHealthy(ctx)
+ assert.NoError(t, err)
+ assert.False(t, healthy)
+}
+
+func Test_ChainStateIsHealthy(t *testing.T) {
+ testCases := []struct {
+ name string
+ commitStoreDown bool
+ commitStoreErr error
+ onRampCursed bool
+ onRampErr error
+ sourceChainUnhealthy bool
+ sourceChainErr error
+ destChainUnhealthy bool
+ destChainErr error
+
+ expectedState bool
+ expectedErr bool
+ }{
+ {
+ name: "all components healthy",
+ expectedState: true,
+ },
+ {
+ name: "CommitStore is down",
+ commitStoreDown: true,
+ expectedState: false,
+ },
+ {
+ name: "CommitStore error",
+ commitStoreErr: errors.New("commit store error"),
+ expectedErr: true,
+ },
+ {
+ name: "OnRamp is cursed",
+ onRampCursed: true,
+ expectedState: false,
+ },
+ {
+ name: "OnRamp error",
+ onRampErr: errors.New("onramp error"),
+ expectedErr: true,
+ },
+ {
+ name: "Source chain is unhealthy",
+ sourceChainUnhealthy: true,
+ expectedState: false,
+ },
+ {
+ name: "Source chain error",
+ sourceChainErr: errors.New("source chain error"),
+ expectedErr: true,
+ },
+ {
+ name: "Destination chain is unhealthy",
+ destChainUnhealthy: true,
+ expectedState: false,
+ },
+ {
+ name: "Destination chain error",
+ destChainErr: errors.New("destination chain error"),
+ expectedErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := tests.Context(t)
+ mockCommitStore := mocks.NewCommitStoreReader(t)
+ mockOnRamp := mocks.NewOnRampReader(t)
+
+ mockCommitStore.On("IsDown", ctx).Return(tc.commitStoreDown, tc.commitStoreErr).Maybe()
+ mockCommitStore.On("IsDestChainHealthy", ctx).Return(!tc.destChainUnhealthy, tc.destChainErr).Maybe()
+ mockOnRamp.On("IsSourceCursed", ctx).Return(tc.onRampCursed, tc.onRampErr).Maybe()
+ mockOnRamp.On("IsSourceChainHealthy", ctx).Return(!tc.sourceChainUnhealthy, tc.sourceChainErr).Maybe()
+
+ chainState := newChainHealthcheckWithCustomEviction(logger.TestLogger(t), mockOnRamp, mockCommitStore, 10*time.Hour, 10*time.Hour)
+
+ healthy, err := chainState.IsHealthy(ctx)
+
+ if tc.expectedErr {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expectedState, healthy)
+ }
+ })
+ }
+}
+
+func Test_RefreshingInBackground(t *testing.T) {
+ mockCommitStore := newCommitStoreWrapper(t, true, nil)
+ mockCommitStore.CommitStoreReader.On("IsDestChainHealthy", mock.Anything).Return(true, nil).Maybe()
+
+ mockOnRamp := newOnRampWrapper(t, true, nil)
+ mockOnRamp.OnRampReader.On("IsSourceChainHealthy", mock.Anything).Return(true, nil).Maybe()
+
+ chainState := newChainHealthcheckWithCustomEviction(
+ logger.TestLogger(t),
+ mockOnRamp,
+ mockCommitStore,
+ 10*time.Microsecond,
+ 10*time.Microsecond,
+ )
+ require.NoError(t, chainState.Start(tests.Context(t)))
+
+ // All healthy
+ assertHealthy(t, chainState, true)
+
+ // Commit store not healthy
+ mockCommitStore.set(false, nil)
+ assertHealthy(t, chainState, false)
+
+ // Commit store error
+ mockCommitStore.set(false, fmt.Errorf("commit store error"))
+ assertError(t, chainState)
+
+ // Commit store is back
+ mockCommitStore.set(true, nil)
+ assertHealthy(t, chainState, true)
+
+ // OnRamp not healthy
+ mockOnRamp.set(false, nil)
+ assertHealthy(t, chainState, false)
+
+ // OnRamp error
+ mockOnRamp.set(false, fmt.Errorf("onramp error"))
+ assertError(t, chainState)
+
+ // All back in healthy state
+ mockOnRamp.set(true, nil)
+ assertHealthy(t, chainState, true)
+
+ require.NoError(t, chainState.Close())
+}
+
+func assertHealthy(t *testing.T, ch *chainHealthcheck, expected bool) {
+ assert.Eventually(t, func() bool {
+ healthy, err := ch.IsHealthy(testutils.Context(t))
+ return err == nil && healthy == expected
+ }, testutils.WaitTimeout(t), testutils.TestInterval)
+}
+
+func assertError(t *testing.T, ch *chainHealthcheck) {
+ assert.Eventually(t, func() bool {
+ _, err := ch.IsHealthy(testutils.Context(t))
+ return err != nil
+ }, testutils.WaitTimeout(t), testutils.TestInterval)
+}
+
+type fakeStatusWrapper struct {
+ *mocks.CommitStoreReader
+ *mocks.OnRampReader
+
+ healthy bool
+ err error
+ mu *sync.Mutex
+}
+
+func newCommitStoreWrapper(t *testing.T, healthy bool, err error) *fakeStatusWrapper {
+ return &fakeStatusWrapper{
+ CommitStoreReader: mocks.NewCommitStoreReader(t),
+ healthy: healthy,
+ err: err,
+ mu: new(sync.Mutex),
+ }
+}
+
+func newOnRampWrapper(t *testing.T, healthy bool, err error) *fakeStatusWrapper {
+ return &fakeStatusWrapper{
+ OnRampReader: mocks.NewOnRampReader(t),
+ healthy: healthy,
+ err: err,
+ mu: new(sync.Mutex),
+ }
+}
+
+func (f *fakeStatusWrapper) IsDown(context.Context) (bool, error) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ return !f.healthy, f.err
+}
+
+func (f *fakeStatusWrapper) IsSourceCursed(context.Context) (bool, error) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ return !f.healthy, f.err
+}
+
+func (f *fakeStatusWrapper) Close() error {
+ return nil
+}
+
+func (f *fakeStatusWrapper) set(healthy bool, err error) {
+ f.mu.Lock()
+ defer f.mu.Unlock()
+ f.healthy = healthy
+ f.err = err
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/commit_roots.go b/core/services/ocr2/plugins/ccip/internal/cache/commit_roots.go
new file mode 100644
index 00000000000..5f8bd5edc56
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/commit_roots.go
@@ -0,0 +1,243 @@
+package cache
+
+import (
+ "context"
+ "slices"
+ "sync"
+ "time"
+
+ "github.com/patrickmn/go-cache"
+ orderedmap "github.com/wk8/go-ordered-map/v2"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+const (
+ // EvictionGracePeriod defines how long after the messageVisibilityInterval a root is still kept in the cache
+ EvictionGracePeriod = 1 * time.Hour
+ // CleanupInterval defines how often roots cache is scanned to evict stale roots
+ CleanupInterval = 30 * time.Minute
+)
+
+type CommitsRootsCache interface {
+ RootsEligibleForExecution(ctx context.Context) ([]ccip.CommitStoreReport, error)
+ MarkAsExecuted(merkleRoot [32]byte)
+ Snooze(merkleRoot [32]byte)
+}
+
+func NewCommitRootsCache(
+ lggr logger.Logger,
+ reader ccip.CommitStoreReader,
+ messageVisibilityInterval time.Duration,
+ rootSnoozeTime time.Duration,
+) CommitsRootsCache {
+ return newCommitRootsCache(
+ lggr,
+ reader,
+ messageVisibilityInterval,
+ rootSnoozeTime,
+ CleanupInterval,
+ EvictionGracePeriod,
+ )
+}
+
+func newCommitRootsCache(
+ lggr logger.Logger,
+ reader ccip.CommitStoreReader,
+ messageVisibilityInterval time.Duration,
+ rootSnoozeTime time.Duration,
+ cleanupInterval time.Duration,
+ evictionGracePeriod time.Duration,
+) *commitRootsCache {
+ snoozedRoots := cache.New(rootSnoozeTime, cleanupInterval)
+ executedRoots := cache.New(messageVisibilityInterval+evictionGracePeriod, cleanupInterval)
+
+ return &commitRootsCache{
+ lggr: lggr,
+ reader: reader,
+ rootSnoozeTime: rootSnoozeTime,
+ finalizedRoots: orderedmap.New[string, ccip.CommitStoreReportWithTxMeta](),
+ executedRoots: executedRoots,
+ snoozedRoots: snoozedRoots,
+ messageVisibilityInterval: messageVisibilityInterval,
+ latestFinalizedCommitRootTs: time.Now().Add(-messageVisibilityInterval),
+ cacheMu: sync.RWMutex{},
+ }
+}
+
+type commitRootsCache struct {
+ lggr logger.Logger
+ reader ccip.CommitStoreReader
+ messageVisibilityInterval time.Duration
+ rootSnoozeTime time.Duration
+
+ // Mutable state. finalizedRoots is thread-safe by default, but updating latestFinalizedCommitRootTs and finalizedRoots requires locking.
+ cacheMu sync.RWMutex
+ // finalizedRoots is a map of merkleRoot -> CommitStoreReportWithTxMeta. It stores all the CommitReports that are
+ // marked as finalized by LogPoller, but not executed yet. Keeping only finalized reports doesn't require any state sync between LP and the cache.
+ // In order to keep this map size under control, we evict stale items every time we fetch new logs from the database.
+ // Also, ccip.CommitStoreReportWithTxMeta is a very tiny entity with almost fixed size, so it's not a big deal to keep it in memory.
+ // In case of high memory footprint caused by storing roots, we can make these even more lightweight by removing token/gas price updates.
+ // Whenever the root is executed (all messages executed and ExecutionStateChange events are finalized), we remove the root from the map.
+ finalizedRoots *orderedmap.OrderedMap[string, ccip.CommitStoreReportWithTxMeta]
+ // snoozedRoots used only for temporary snoozing roots. It's a cache with TTL (usually around 5 minutes, but this configuration is set up on chain using rootSnoozeTime)
+ snoozedRoots *cache.Cache
+ // executedRoots is a cache with TTL (usually around 8 hours, but this configuration is set up on chain using messageVisibilityInterval).
+ // We keep executed roots there to make sure we don't accidentally try to reprocess already executed CommitReport
+ executedRoots *cache.Cache
+ // latestFinalizedCommitRootTs is the timestamp of the latest finalized commit root (youngest in terms of timestamp).
+ // It's used get only the logs that were considered as unfinalized in a previous run.
+ // This way we limit database scans to the minimum and keep polling "unfinalized" part of the ReportAccepted events queue.
+ latestFinalizedCommitRootTs time.Time
+}
+
+func (r *commitRootsCache) RootsEligibleForExecution(ctx context.Context) ([]ccip.CommitStoreReport, error) {
+ // 1. Fetch all the logs from the database after the latest finalized commit root timestamp.
+ // If this is a first run, it will fetch all the logs based on the messageVisibilityInterval.
+ // Worst case scenario, it will fetch around 480 reports (OCR Commit 60 seconds (fast chains default) * messageVisibilityInterval set to 8 hours (mainnet default))
+ // Even with the larger messageVisibilityInterval window (e.g. 24 hours) it should be acceptable (around 1500 logs).
+ // Keep in mind that this potentially heavy operation happens only once during the plugin boot and it's no different from the previous implementation.
+ logs, err := r.fetchLogsFromCommitStore(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ // 2. Iterate over the logs and check if the root is finalized or not. Return finalized and unfinalized reports
+ // It promotes finalized roots to the finalizedRoots map and evicts stale roots.
+ finalizedReports, unfinalizedReports := r.updateFinalizedRoots(logs)
+
+ // 3. Join finalized commit reports with unfinalized reports and outfilter snoozed roots.
+ // Return only the reports that are not snoozed.
+ return r.pickReadyToExecute(finalizedReports, unfinalizedReports), nil
+}
+
+// MarkAsExecuted marks the root as executed. It means that all the messages from the root were executed and the ExecutionStateChange event was finalized.
+// Executed roots are removed from the cache.
+func (r *commitRootsCache) MarkAsExecuted(merkleRoot [32]byte) {
+ prettyMerkleRoot := merkleRootToString(merkleRoot)
+ r.lggr.Infow("Marking root as executed and removing entirely from cache", "merkleRoot", prettyMerkleRoot)
+
+ r.cacheMu.Lock()
+ defer r.cacheMu.Unlock()
+ r.finalizedRoots.Delete(prettyMerkleRoot)
+ r.executedRoots.SetDefault(prettyMerkleRoot, struct{}{})
+}
+
+// Snooze temporarily snoozes the root. It means that the root is not eligible for execution for a certain period of time.
+// Snoozed roots are skipped when calling RootsEligibleForExecution
+func (r *commitRootsCache) Snooze(merkleRoot [32]byte) {
+ prettyMerkleRoot := merkleRootToString(merkleRoot)
+ r.lggr.Infow("Snoozing root temporarily", "merkleRoot", prettyMerkleRoot, "rootSnoozeTime", r.rootSnoozeTime)
+ r.snoozedRoots.SetDefault(prettyMerkleRoot, struct{}{})
+}
+
+func (r *commitRootsCache) isSnoozed(merkleRoot [32]byte) bool {
+ _, snoozed := r.snoozedRoots.Get(merkleRootToString(merkleRoot))
+ return snoozed
+}
+
+func (r *commitRootsCache) isExecuted(merkleRoot [32]byte) bool {
+ _, executed := r.executedRoots.Get(merkleRootToString(merkleRoot))
+ return executed
+}
+
+func (r *commitRootsCache) fetchLogsFromCommitStore(ctx context.Context) ([]ccip.CommitStoreReportWithTxMeta, error) {
+ r.cacheMu.Lock()
+ messageVisibilityWindow := time.Now().Add(-r.messageVisibilityInterval)
+ if r.latestFinalizedCommitRootTs.Before(messageVisibilityWindow) {
+ r.latestFinalizedCommitRootTs = messageVisibilityWindow
+ }
+ commitRootsFilterTimestamp := r.latestFinalizedCommitRootTs
+ r.cacheMu.Unlock()
+
+ // IO operation, release lock before!
+ r.lggr.Infow("Fetching Commit Reports with timestamp greater than or equal to", "blockTimestamp", commitRootsFilterTimestamp)
+ return r.reader.GetAcceptedCommitReportsGteTimestamp(ctx, commitRootsFilterTimestamp, 0)
+}
+
+func (r *commitRootsCache) updateFinalizedRoots(logs []ccip.CommitStoreReportWithTxMeta) ([]ccip.CommitStoreReportWithTxMeta, []ccip.CommitStoreReportWithTxMeta) {
+ r.cacheMu.Lock()
+ defer r.cacheMu.Unlock()
+
+ // Assuming logs are properly ordered by block_timestamp, log_index
+ var unfinalizedReports []ccip.CommitStoreReportWithTxMeta
+ for _, log := range logs {
+ prettyMerkleRoot := merkleRootToString(log.MerkleRoot)
+ // Defensive check, if something is marked as executed, never allow it to come back to the cache
+ if r.isExecuted(log.MerkleRoot) {
+ r.lggr.Debugw("Ignoring root marked as executed", "merkleRoot", prettyMerkleRoot, "blockTimestamp", log.BlockTimestampUnixMilli)
+ continue
+ }
+
+ if log.IsFinalized() {
+ r.lggr.Debugw("Adding finalized root to cache", "merkleRoot", prettyMerkleRoot, "blockTimestamp", log.BlockTimestampUnixMilli)
+ r.finalizedRoots.Store(prettyMerkleRoot, log)
+ } else {
+ r.lggr.Debugw("Bypassing unfinalized root", "merkleRoot", prettyMerkleRoot, "blockTimestamp", log.BlockTimestampUnixMilli)
+ unfinalizedReports = append(unfinalizedReports, log)
+ }
+ }
+
+ if newest := r.finalizedRoots.Newest(); newest != nil {
+ r.latestFinalizedCommitRootTs = time.UnixMilli(newest.Value.BlockTimestampUnixMilli)
+ }
+
+ var finalizedRoots []ccip.CommitStoreReportWithTxMeta
+ var rootsToDelete []string
+
+ messageVisibilityWindow := time.Now().Add(-r.messageVisibilityInterval)
+ for pair := r.finalizedRoots.Oldest(); pair != nil; pair = pair.Next() {
+ // Mark items as stale if they are older than the messageVisibilityInterval
+ // SortedMap doesn't allow to iterate and delete, so we mark roots for deletion and remove them in a separate loop
+ if time.UnixMilli(pair.Value.BlockTimestampUnixMilli).Before(messageVisibilityWindow) {
+ rootsToDelete = append(rootsToDelete, pair.Key)
+ continue
+ }
+ finalizedRoots = append(finalizedRoots, pair.Value)
+ }
+
+ // Remove stale items
+ for _, root := range rootsToDelete {
+ r.finalizedRoots.Delete(root)
+ }
+
+ return finalizedRoots, unfinalizedReports
+}
+
+func (r *commitRootsCache) pickReadyToExecute(r1 []ccip.CommitStoreReportWithTxMeta, r2 []ccip.CommitStoreReportWithTxMeta) []ccip.CommitStoreReport {
+ allReports := append(r1, r2...)
+ eligibleReports := make([]ccip.CommitStoreReport, 0, len(allReports))
+ for _, report := range allReports {
+ if r.isSnoozed(report.MerkleRoot) {
+ r.lggr.Debugw("Skipping snoozed root",
+ "minSeqNr", report.Interval.Min,
+ "maxSeqNr", report.Interval.Max,
+ "merkleRoot", merkleRootToString(report.MerkleRoot))
+ continue
+ }
+ eligibleReports = append(eligibleReports, report.CommitStoreReport)
+ }
+ // safety check, probably not needed
+ slices.SortFunc(eligibleReports, func(i, j ccip.CommitStoreReport) int {
+ return int(i.Interval.Min - j.Interval.Min)
+ })
+ return eligibleReports
+}
+
+// internal use only for testing
+func (r *commitRootsCache) finalizedCachedLogs() []ccip.CommitStoreReport {
+ r.cacheMu.RLock()
+ defer r.cacheMu.RUnlock()
+
+ var finalizedRoots []ccip.CommitStoreReport
+ for pair := r.finalizedRoots.Oldest(); pair != nil; pair = pair.Next() {
+ finalizedRoots = append(finalizedRoots, pair.Value.CommitStoreReport)
+ }
+ return finalizedRoots
+}
+
+func merkleRootToString(merkleRoot ccip.Hash) string {
+ return merkleRoot.String()
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/commit_roots_test.go b/core/services/ocr2/plugins/ccip/internal/cache/commit_roots_test.go
new file mode 100644
index 00000000000..dc0a8443497
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/commit_roots_test.go
@@ -0,0 +1,297 @@
+package cache_test
+
+import (
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "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/ccip/generated/commit_store_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "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/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+)
+
+func Test_RootsEligibleForExecution(t *testing.T) {
+ ctx := testutils.Context(t)
+ chainID := testutils.NewRandomEVMChainID()
+ orm := logpoller.NewORM(chainID, pgtest.NewSqlxDB(t), logger.TestLogger(t))
+ lpOpts := logpoller.Opts{
+ PollPeriod: time.Hour,
+ FinalityDepth: 2,
+ BackfillBatchSize: 20,
+ RpcBatchSize: 10,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+ lp := logpoller.NewLogPoller(orm, nil, logger.TestLogger(t), nil, lpOpts)
+
+ commitStoreAddr := utils.RandomAddress()
+
+ block2 := time.Now().Add(-8 * time.Hour)
+ block3 := time.Now().Add(-5 * time.Hour)
+ block4 := time.Now().Add(-1 * time.Hour)
+ newBlock4 := time.Now().Add(-2 * time.Hour)
+ block5 := time.Now()
+
+ root1 := utils.RandomBytes32()
+ root2 := utils.RandomBytes32()
+ root3 := utils.RandomBytes32()
+ root4 := utils.RandomBytes32()
+ root5 := utils.RandomBytes32()
+
+ inputLogs := []logpoller.Log{
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 2, 1, root1, block2),
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 2, 2, root2, block2),
+ }
+ require.NoError(t, orm.InsertLogsWithBlock(ctx, inputLogs, logpoller.NewLogPollerBlock(utils.RandomBytes32(), 2, time.Now(), 1)))
+
+ commitStore, err := v1_2_0.NewCommitStore(logger.TestLogger(t), commitStoreAddr, nil, lp)
+ require.NoError(t, err)
+
+ rootsCache := cache.NewCommitRootsCache(logger.TestLogger(t), commitStore, 10*time.Hour, time.Second)
+
+ roots, err := rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root1, root2)
+
+ rootsCache.Snooze(root1)
+ rootsCache.Snooze(root2)
+
+ // Roots are snoozed
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots)
+
+ // Roots are unsnoozed
+ require.Eventually(t, func() bool {
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ return len(roots) == 2
+ }, 5*time.Second, 1*time.Second)
+
+ // Marking root as executed doesn't ignore other roots from the same block
+ rootsCache.MarkAsExecuted(root1)
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root2)
+
+ // Finality progress, mark all roots as finalized
+ require.NoError(t, orm.InsertBlock(ctx, utils.RandomBytes32(), 3, time.Now(), 3))
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root2)
+
+ inputLogs = []logpoller.Log{
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 3, 1, root3, block3),
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 4, 1, root4, block4),
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 5, 1, root5, block5),
+ }
+ require.NoError(t, orm.InsertLogsWithBlock(ctx, inputLogs, logpoller.NewLogPollerBlock(utils.RandomBytes32(), 5, time.Now(), 3)))
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root2, root3, root4, root5)
+
+ // Mark root in the middle as executed but keep the oldest one still waiting
+ rootsCache.MarkAsExecuted(root3)
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root2, root4, root5)
+
+ // Simulate reorg by removing all unfinalized blocks
+ require.NoError(t, orm.DeleteLogsAndBlocksAfter(ctx, 4))
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root2)
+
+ // Root4 comes back but with the different block_timestamp (before the reorged block)
+ inputLogs = []logpoller.Log{
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 4, 1, root4, newBlock4),
+ }
+ require.NoError(t, orm.InsertLogsWithBlock(ctx, inputLogs, logpoller.NewLogPollerBlock(utils.RandomBytes32(), 5, time.Now(), 3)))
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root2, root4)
+
+ // Mark everything as executed
+ rootsCache.MarkAsExecuted(root2)
+ rootsCache.MarkAsExecuted(root4)
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots)
+}
+
+func Test_RootsEligibleForExecutionWithReorgs(t *testing.T) {
+ ctx := testutils.Context(t)
+ chainID := testutils.NewRandomEVMChainID()
+ orm := logpoller.NewORM(chainID, pgtest.NewSqlxDB(t), logger.TestLogger(t))
+ lpOpts := logpoller.Opts{
+ PollPeriod: time.Hour,
+ FinalityDepth: 2,
+ BackfillBatchSize: 20,
+ RpcBatchSize: 10,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+ lp := logpoller.NewLogPoller(orm, nil, logger.TestLogger(t), nil, lpOpts)
+
+ commitStoreAddr := utils.RandomAddress()
+
+ block1 := time.Now().Add(-8 * time.Hour)
+ block2 := time.Now().Add(-5 * time.Hour)
+ block3 := time.Now().Add(-2 * time.Hour)
+ block4 := time.Now().Add(-1 * time.Hour)
+
+ root1 := utils.RandomBytes32()
+ root2 := utils.RandomBytes32()
+ root3 := utils.RandomBytes32()
+
+ // Genesis block
+ require.NoError(t, orm.InsertBlock(ctx, utils.RandomBytes32(), 1, block1, 1))
+ inputLogs := []logpoller.Log{
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 2, 1, root1, block2),
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 2, 2, root2, block2),
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 3, 1, root3, block3),
+ }
+ require.NoError(t, orm.InsertLogsWithBlock(ctx, inputLogs, logpoller.NewLogPollerBlock(utils.RandomBytes32(), 3, time.Now(), 1)))
+
+ commitStore, err := v1_2_0.NewCommitStore(logger.TestLogger(t), commitStoreAddr, nil, lp)
+ require.NoError(t, err)
+
+ rootsCache := cache.NewCommitRootsCache(logger.TestLogger(t), commitStore, 10*time.Hour, time.Second)
+
+ // Get all including finalized and unfinalized
+ roots, err := rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root1, root2, root3)
+
+ // Reorg everything away
+ require.NoError(t, orm.DeleteLogsAndBlocksAfter(ctx, 2))
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots)
+
+ // Reinsert the logs, mark first one as finalized
+ inputLogs = []logpoller.Log{
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 3, 1, root1, block3),
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 4, 1, root2, block4),
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 4, 2, root3, block4),
+ }
+ require.NoError(t, orm.InsertLogsWithBlock(ctx, inputLogs, logpoller.NewLogPollerBlock(utils.RandomBytes32(), 5, time.Now(), 3)))
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root1, root2, root3)
+
+ // Reorg away everything except the finalized one
+ require.NoError(t, orm.DeleteLogsAndBlocksAfter(ctx, 4))
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root1)
+}
+
+// Not very likely, but let's be more defensive here and verify if cache works properly and can deal with duplicates
+func Test_BlocksWithTheSameTimestamps(t *testing.T) {
+ ctx := testutils.Context(t)
+ chainID := testutils.NewRandomEVMChainID()
+ orm := logpoller.NewORM(chainID, pgtest.NewSqlxDB(t), logger.TestLogger(t))
+ lpOpts := logpoller.Opts{
+ PollPeriod: time.Hour,
+ FinalityDepth: 2,
+ BackfillBatchSize: 20,
+ RpcBatchSize: 10,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+ lp := logpoller.NewLogPoller(orm, nil, logger.TestLogger(t), nil, lpOpts)
+
+ commitStoreAddr := utils.RandomAddress()
+
+ block := time.Now().Add(-1 * time.Hour).Truncate(time.Second)
+ root1 := utils.RandomBytes32()
+ root2 := utils.RandomBytes32()
+
+ inputLogs := []logpoller.Log{
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 2, 1, root1, block),
+ }
+ require.NoError(t, orm.InsertLogsWithBlock(ctx, inputLogs, logpoller.NewLogPollerBlock(utils.RandomBytes32(), 2, time.Now(), 2)))
+
+ commitStore, err := v1_2_0.NewCommitStore(logger.TestLogger(t), commitStoreAddr, nil, lp)
+ require.NoError(t, err)
+
+ rootsCache := cache.NewCommitRootsCache(logger.TestLogger(t), commitStore, 10*time.Hour, time.Second)
+ roots, err := rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root1)
+
+ inputLogs = []logpoller.Log{
+ createReportAcceptedLog(t, chainID, commitStoreAddr, 3, 1, root2, block),
+ }
+ require.NoError(t, orm.InsertLogsWithBlock(ctx, inputLogs, logpoller.NewLogPollerBlock(utils.RandomBytes32(), 3, time.Now(), 3)))
+
+ roots, err = rootsCache.RootsEligibleForExecution(ctx)
+ require.NoError(t, err)
+ assertRoots(t, roots, root1, root2)
+}
+
+func assertRoots(t *testing.T, roots []cciptypes.CommitStoreReport, root ...[32]byte) {
+ require.Len(t, roots, len(root))
+ for i, r := range root {
+ require.Equal(t, r, roots[i].MerkleRoot)
+ }
+}
+
+func createReportAcceptedLog(t testing.TB, chainID *big.Int, address common.Address, blockNumber int64, logIndex int64, merkleRoot common.Hash, blockTimestamp time.Time) logpoller.Log {
+ tAbi, err := commit_store_1_2_0.CommitStoreMetaData.GetAbi()
+ require.NoError(t, err)
+ eseEvent, ok := tAbi.Events["ReportAccepted"]
+ require.True(t, ok)
+
+ gasPriceUpdates := make([]commit_store_1_2_0.InternalGasPriceUpdate, 100)
+ tokenPriceUpdates := make([]commit_store_1_2_0.InternalTokenPriceUpdate, 100)
+
+ for i := 0; i < 100; i++ {
+ gasPriceUpdates[i] = commit_store_1_2_0.InternalGasPriceUpdate{
+ DestChainSelector: uint64(i),
+ UsdPerUnitGas: big.NewInt(int64(i)),
+ }
+ tokenPriceUpdates[i] = commit_store_1_2_0.InternalTokenPriceUpdate{
+ SourceToken: utils.RandomAddress(),
+ UsdPerToken: big.NewInt(int64(i)),
+ }
+ }
+
+ message := commit_store_1_2_0.CommitStoreCommitReport{
+ PriceUpdates: commit_store_1_2_0.InternalPriceUpdates{
+ TokenPriceUpdates: tokenPriceUpdates,
+ GasPriceUpdates: gasPriceUpdates,
+ },
+ Interval: commit_store_1_2_0.CommitStoreInterval{Min: 1, Max: 10},
+ MerkleRoot: merkleRoot,
+ }
+
+ logData, err := eseEvent.Inputs.Pack(message)
+ require.NoError(t, err)
+
+ topic0 := commit_store_1_2_0.CommitStoreReportAccepted{}.Topic()
+
+ return logpoller.Log{
+ Topics: [][]byte{
+ topic0[:],
+ },
+ Data: logData,
+ LogIndex: logIndex,
+ BlockHash: utils.RandomBytes32(),
+ BlockNumber: blockNumber,
+ BlockTimestamp: blockTimestamp.Truncate(time.Millisecond),
+ EventSig: topic0,
+ Address: address,
+ TxHash: utils.RandomBytes32(),
+ EvmChainId: ubig.New(chainID),
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/commit_roots_unit_test.go b/core/services/ocr2/plugins/ccip/internal/cache/commit_roots_unit_test.go
new file mode 100644
index 00000000000..34a470ef907
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/commit_roots_unit_test.go
@@ -0,0 +1,212 @@
+package cache
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+)
+
+func Test_CacheIsInitializedWithFirstCall(t *testing.T) {
+ commitStoreReader := mocks.NewCommitStoreReader(t)
+ cache := newCommitRootsCache(logger.TestLogger(t), commitStoreReader, time.Hour, time.Hour, time.Hour, time.Hour)
+ commitStoreReader.On("GetAcceptedCommitReportsGteTimestamp", mock.Anything, mock.Anything, mock.Anything).Return([]ccip.CommitStoreReportWithTxMeta{}, nil)
+
+ roots, err := cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots)
+}
+
+func Test_CacheExpiration(t *testing.T) {
+ ts1 := time.Now().Add(-5 * time.Millisecond).Truncate(time.Millisecond)
+ ts2 := time.Now().Add(-3 * time.Millisecond).Truncate(time.Millisecond)
+ ts3 := time.Now().Add(-1 * time.Millisecond).Truncate(time.Millisecond)
+
+ root1 := utils.RandomBytes32()
+ root2 := utils.RandomBytes32()
+ root3 := utils.RandomBytes32()
+
+ commitStoreReader := mocks.NewCommitStoreReader(t)
+ cache := newCommitRootsCache(logger.TestLogger(t), commitStoreReader, time.Second, time.Hour, time.Hour, time.Hour)
+ mockCommitStoreReader(commitStoreReader, time.Time{}, []ccip.CommitStoreReportWithTxMeta{
+ createCommitStoreEntry(root1, ts1, true),
+ createCommitStoreEntry(root2, ts2, true),
+ createCommitStoreEntry(root3, ts3, false),
+ })
+ roots, err := cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots, root1, root2, root3)
+
+ require.Eventually(t, func() bool {
+ mockCommitStoreReader(commitStoreReader, time.Time{}, []ccip.CommitStoreReportWithTxMeta{
+ createCommitStoreEntry(root3, ts3, false),
+ })
+ roots, err = cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ return len(roots) == 1 && roots[0].MerkleRoot == root3
+ }, 5*time.Second, 1*time.Second)
+}
+
+func Test_CacheFullEviction(t *testing.T) {
+ commitStoreReader := mocks.NewCommitStoreReader(t)
+ cache := newCommitRootsCache(logger.TestLogger(t), commitStoreReader, 2*time.Second, 1*time.Second, time.Second, time.Second)
+
+ maxElements := 10000
+ commitRoots := make([]ccip.CommitStoreReportWithTxMeta, maxElements)
+ for i := 0; i < maxElements; i++ {
+ finalized := i >= maxElements/2
+ commitRoots[i] = createCommitStoreEntry(utils.RandomBytes32(), time.Now(), finalized)
+ }
+ mockCommitStoreReader(commitStoreReader, time.Time{}, commitRoots)
+
+ roots, err := cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ require.Len(t, roots, maxElements)
+
+ // Marks some of them as exeucted and some of them as snoozed
+ for i := 0; i < maxElements; i++ {
+ if i%3 == 0 {
+ cache.MarkAsExecuted(commitRoots[i].MerkleRoot)
+ }
+ if i%3 == 1 {
+ cache.Snooze(commitRoots[i].MerkleRoot)
+ }
+ }
+ // Eventually everything should be entirely removed from cache. We need that check to verify if cache doesn't grow indefinitely
+ require.Eventually(t, func() bool {
+ mockCommitStoreReader(commitStoreReader, time.Time{}, []ccip.CommitStoreReportWithTxMeta{})
+ roots1, err1 := cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err1)
+
+ return len(roots1) == 0 &&
+ cache.finalizedRoots.Len() == 0 &&
+ len(cache.snoozedRoots.Items()) == 0 &&
+ len(cache.executedRoots.Items()) == 0
+ }, 10*time.Second, time.Second)
+}
+
+func Test_CacheProgression_Internal(t *testing.T) {
+ ts1 := time.Now().Add(-5 * time.Hour).Truncate(time.Millisecond)
+ ts2 := time.Now().Add(-3 * time.Hour).Truncate(time.Millisecond)
+ ts3 := time.Now().Add(-1 * time.Hour).Truncate(time.Millisecond)
+
+ root1 := utils.RandomBytes32()
+ root2 := utils.RandomBytes32()
+ root3 := utils.RandomBytes32()
+
+ commitStoreReader := mocks.NewCommitStoreReader(t)
+
+ cache := newCommitRootsCache(logger.TestLogger(t), commitStoreReader, 10*time.Hour, time.Hour, time.Hour, time.Hour)
+
+ // Empty cache, no results from the reader
+ mockCommitStoreReader(commitStoreReader, time.Time{}, []ccip.CommitStoreReportWithTxMeta{})
+ roots, err := cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots)
+ assertRoots(t, cache.finalizedCachedLogs())
+
+ // Single unfinalized root returned
+ mockCommitStoreReader(commitStoreReader, time.Time{}, []ccip.CommitStoreReportWithTxMeta{createCommitStoreEntry(root1, ts1, false)})
+ roots, err = cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots, root1)
+ assertRoots(t, cache.finalizedCachedLogs())
+
+ // Finalized and unfinalized roots returned
+ mockCommitStoreReader(commitStoreReader, time.Time{}, []ccip.CommitStoreReportWithTxMeta{
+ createCommitStoreEntry(root1, ts1, true),
+ createCommitStoreEntry(root2, ts2, false),
+ })
+ roots, err = cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots, root1, root2)
+ assertRoots(t, cache.finalizedCachedLogs(), root1)
+
+ // Returning the same data should not impact cache state (no duplicates)
+ mockCommitStoreReader(commitStoreReader, ts1, []ccip.CommitStoreReportWithTxMeta{
+ createCommitStoreEntry(root1, ts1, true),
+ createCommitStoreEntry(root2, ts2, false),
+ })
+ roots, err = cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots, root1, root2)
+ assertRoots(t, cache.finalizedCachedLogs(), root1)
+
+ // Snoozing oldest root
+ cache.Snooze(root1)
+ mockCommitStoreReader(commitStoreReader, ts1, []ccip.CommitStoreReportWithTxMeta{
+ createCommitStoreEntry(root2, ts2, false),
+ createCommitStoreEntry(root3, ts3, false),
+ })
+ roots, err = cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots, root2, root3)
+ assertRoots(t, cache.finalizedCachedLogs(), root1)
+
+ // Snoozing everything
+ cache.Snooze(root2)
+ cache.Snooze(root3)
+ mockCommitStoreReader(commitStoreReader, ts1, []ccip.CommitStoreReportWithTxMeta{
+ createCommitStoreEntry(root2, ts2, true),
+ createCommitStoreEntry(root3, ts3, true),
+ })
+ roots, err = cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots)
+ assertRoots(t, cache.finalizedCachedLogs(), root1, root2, root3)
+
+ // Marking everything as executed removes it entirely, even if root is returned from the CommitStore
+ cache.MarkAsExecuted(root1)
+ cache.MarkAsExecuted(root2)
+ cache.MarkAsExecuted(root3)
+ mockCommitStoreReader(commitStoreReader, ts3, []ccip.CommitStoreReportWithTxMeta{
+ createCommitStoreEntry(root2, ts2, true),
+ createCommitStoreEntry(root3, ts3, true),
+ })
+ roots, err = cache.RootsEligibleForExecution(tests.Context(t))
+ require.NoError(t, err)
+ assertRoots(t, roots)
+ assertRoots(t, cache.finalizedCachedLogs())
+}
+
+func assertRoots(t *testing.T, reports []ccip.CommitStoreReport, expectedRoots ...[32]byte) {
+ require.Len(t, reports, len(expectedRoots))
+ for i, report := range reports {
+ assert.Equal(t, expectedRoots[i], report.MerkleRoot)
+ }
+}
+
+func mockCommitStoreReader(reader *mocks.CommitStoreReader, blockTimestamp time.Time, roots []ccip.CommitStoreReportWithTxMeta) {
+ if blockTimestamp.IsZero() {
+ reader.On("GetAcceptedCommitReportsGteTimestamp", mock.Anything, mock.Anything, mock.Anything).
+ Return(roots, nil).Once()
+ } else {
+ reader.On("GetAcceptedCommitReportsGteTimestamp", mock.Anything, blockTimestamp, mock.Anything).
+ Return(roots, nil).Once()
+ }
+}
+
+func createCommitStoreEntry(root [32]byte, ts time.Time, finalized bool) ccip.CommitStoreReportWithTxMeta {
+ status := ccip.FinalizedStatusNotFinalized
+ if finalized {
+ status = ccip.FinalizedStatusFinalized
+ }
+ return ccip.CommitStoreReportWithTxMeta{
+ CommitStoreReport: ccip.CommitStoreReport{
+ MerkleRoot: root,
+ },
+ TxMeta: ccip.TxMeta{
+ BlockTimestampUnixMilli: ts.UnixMilli(),
+ Finalized: status,
+ },
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/lazy.go b/core/services/ocr2/plugins/ccip/internal/cache/lazy.go
new file mode 100644
index 00000000000..7b15abe271b
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/lazy.go
@@ -0,0 +1,20 @@
+package cache
+
+import "sync"
+
+type LazyFunction[T any] func() (T, error)
+
+// LazyFetch caches the results during the first call and then returns the cached value
+// on each consecutive call.
+func LazyFetch[T any](fun LazyFunction[T]) LazyFunction[T] {
+ var result T
+ var err error
+ var once sync.Once
+
+ return func() (T, error) {
+ once.Do(func() {
+ result, err = fun()
+ })
+ return result, err
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/lazy_test.go b/core/services/ocr2/plugins/ccip/internal/cache/lazy_test.go
new file mode 100644
index 00000000000..2777a6c2e0b
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/lazy_test.go
@@ -0,0 +1,71 @@
+package cache
+
+import (
+ "fmt"
+ "sync"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestLazyFetchPass(t *testing.T) {
+ counterFunction := createPassingCounter()
+
+ counter, _ := counterFunction()
+ require.Equal(t, 1, counter)
+
+ lazyCounter := LazyFetch(counterFunction)
+ counter, _ = lazyCounter()
+ require.Equal(t, 2, counter)
+
+ counter, _ = lazyCounter()
+ require.Equal(t, 2, counter)
+}
+
+func TestLazyFetchFail(t *testing.T) {
+ counterFunction := createFailingCounter()
+
+ _, err := counterFunction()
+ require.Equal(t, "counter 1 failed", err.Error())
+
+ lazyCounter := LazyFetch(counterFunction)
+ _, err = lazyCounter()
+ require.Equal(t, "counter 2 failed", err.Error())
+
+ _, err = lazyCounter()
+ require.Equal(t, "counter 2 failed", err.Error())
+}
+
+func TestLazyFetchMultipleRoutines(t *testing.T) {
+ routines := 100
+ counterFunction := LazyFetch(createPassingCounter())
+
+ var wg sync.WaitGroup
+ wg.Add(routines)
+
+ for i := 0; i < routines; i++ {
+ go func() {
+ counter, _ := counterFunction()
+ require.Equal(t, 1, counter)
+ wg.Done()
+ }()
+ }
+
+ wg.Wait()
+}
+
+func createFailingCounter() func() (int, error) {
+ counter := 0
+ return func() (int, error) {
+ counter++
+ return 0, fmt.Errorf("counter %d failed", counter)
+ }
+}
+
+func createPassingCounter() func() (int, error) {
+ counter := 0
+ return func() (int, error) {
+ counter++
+ return counter, nil
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/mocks/chain_health_mock.go b/core/services/ocr2/plugins/ccip/internal/cache/mocks/chain_health_mock.go
new file mode 100644
index 00000000000..595b15774af
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/mocks/chain_health_mock.go
@@ -0,0 +1,183 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// ChainHealthcheck is an autogenerated mock type for the ChainHealthcheck type
+type ChainHealthcheck struct {
+ mock.Mock
+}
+
+type ChainHealthcheck_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ChainHealthcheck) EXPECT() *ChainHealthcheck_Expecter {
+ return &ChainHealthcheck_Expecter{mock: &_m.Mock}
+}
+
+// Close provides a mock function with given fields:
+func (_m *ChainHealthcheck) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// ChainHealthcheck_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type ChainHealthcheck_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *ChainHealthcheck_Expecter) Close() *ChainHealthcheck_Close_Call {
+ return &ChainHealthcheck_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *ChainHealthcheck_Close_Call) Run(run func()) *ChainHealthcheck_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *ChainHealthcheck_Close_Call) Return(_a0 error) *ChainHealthcheck_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ChainHealthcheck_Close_Call) RunAndReturn(run func() error) *ChainHealthcheck_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsHealthy provides a mock function with given fields: ctx
+func (_m *ChainHealthcheck) IsHealthy(ctx context.Context) (bool, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsHealthy")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) bool); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ChainHealthcheck_IsHealthy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsHealthy'
+type ChainHealthcheck_IsHealthy_Call struct {
+ *mock.Call
+}
+
+// IsHealthy is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *ChainHealthcheck_Expecter) IsHealthy(ctx interface{}) *ChainHealthcheck_IsHealthy_Call {
+ return &ChainHealthcheck_IsHealthy_Call{Call: _e.mock.On("IsHealthy", ctx)}
+}
+
+func (_c *ChainHealthcheck_IsHealthy_Call) Run(run func(ctx context.Context)) *ChainHealthcheck_IsHealthy_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *ChainHealthcheck_IsHealthy_Call) Return(_a0 bool, _a1 error) *ChainHealthcheck_IsHealthy_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ChainHealthcheck_IsHealthy_Call) RunAndReturn(run func(context.Context) (bool, error)) *ChainHealthcheck_IsHealthy_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Start provides a mock function with given fields: _a0
+func (_m *ChainHealthcheck) Start(_a0 context.Context) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Start")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// ChainHealthcheck_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
+type ChainHealthcheck_Start_Call struct {
+ *mock.Call
+}
+
+// Start is a helper method to define mock.On call
+// - _a0 context.Context
+func (_e *ChainHealthcheck_Expecter) Start(_a0 interface{}) *ChainHealthcheck_Start_Call {
+ return &ChainHealthcheck_Start_Call{Call: _e.mock.On("Start", _a0)}
+}
+
+func (_c *ChainHealthcheck_Start_Call) Run(run func(_a0 context.Context)) *ChainHealthcheck_Start_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *ChainHealthcheck_Start_Call) Return(_a0 error) *ChainHealthcheck_Start_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ChainHealthcheck_Start_Call) RunAndReturn(run func(context.Context) error) *ChainHealthcheck_Start_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewChainHealthcheck creates a new instance of ChainHealthcheck. 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 NewChainHealthcheck(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ChainHealthcheck {
+ mock := &ChainHealthcheck{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/observed_chain_health.go b/core/services/ocr2/plugins/ccip/internal/cache/observed_chain_health.go
new file mode 100644
index 00000000000..941162448af
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/observed_chain_health.go
@@ -0,0 +1,70 @@
+package cache
+
+import (
+ "context"
+ "strconv"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+var (
+ laneHealthStatus = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "ccip_lane_healthcheck_status",
+ Help: "Keep track of the chain healthcheck calls for each lane and plugin",
+ }, []string{"plugin", "source", "dest", "onramp"})
+)
+
+type ObservedChainHealthcheck struct {
+ ChainHealthcheck
+
+ sourceChain string
+ destChain string
+ plugin string
+ // onrampAddress is used to distinguish between 1.0/2.0 lanes or blue/green lanes during deployment
+ // This changes very rarely, so it's not a performance concern for Prometheus
+ onrampAddress string
+ laneHealthStatus *prometheus.GaugeVec
+}
+
+func NewObservedChainHealthCheck(
+ chainHealthcheck ChainHealthcheck,
+ plugin string,
+ sourceChain int64,
+ destChain int64,
+ onrampAddress cciptypes.Address,
+) *ObservedChainHealthcheck {
+ return &ObservedChainHealthcheck{
+ ChainHealthcheck: chainHealthcheck,
+ sourceChain: strconv.FormatInt(sourceChain, 10),
+ destChain: strconv.FormatInt(destChain, 10),
+ plugin: plugin,
+ laneHealthStatus: laneHealthStatus,
+ onrampAddress: string(onrampAddress),
+ }
+}
+
+func (o *ObservedChainHealthcheck) IsHealthy(ctx context.Context) (bool, error) {
+ healthy, err := o.ChainHealthcheck.IsHealthy(ctx)
+ o.trackState(healthy, err)
+ return healthy, err
+}
+
+func (o *ObservedChainHealthcheck) trackState(healthy bool, err error) {
+ if err != nil {
+ // Don't report errors as unhealthy, as they are not necessarily indicative of the chain's health
+ // Could be RPC issues, etc.
+ return
+ }
+
+ status := 0
+ if healthy {
+ status = 1
+ }
+
+ o.laneHealthStatus.
+ WithLabelValues(o.plugin, o.sourceChain, o.destChain, o.onrampAddress).
+ Set(float64(status))
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/observed_chain_health_test.go b/core/services/ocr2/plugins/ccip/internal/cache/observed_chain_health_test.go
new file mode 100644
index 00000000000..19583a37c70
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/observed_chain_health_test.go
@@ -0,0 +1,62 @@
+package cache
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/prometheus/client_golang/prometheus/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache/mocks"
+)
+
+var address = cciptypes.Address(common.HexToAddress("0x1234567890123456789012345678901234567890").String())
+
+func Test_ObservedChainStateSkipErrors(t *testing.T) {
+ mockedHealthcheck := mocks.NewChainHealthcheck(t)
+ mockedHealthcheck.On("IsHealthy", mock.Anything).Return(false, fmt.Errorf("error"))
+
+ observedChainState := NewObservedChainHealthCheck(
+ mockedHealthcheck,
+ "plugin",
+ 10,
+ 20,
+ address,
+ )
+
+ _, err := observedChainState.IsHealthy(tests.Context(t))
+ assert.Error(t, err)
+ assert.Equal(t, float64(0), testutil.ToFloat64(laneHealthStatus.WithLabelValues("plugin", "10", "20", "0x1234567890123456789012345678901234567890")))
+}
+
+func Test_ObservedChainStateReportsStatus(t *testing.T) {
+ mockedHealthcheck := mocks.NewChainHealthcheck(t)
+ mockedHealthcheck.On("IsHealthy", mock.Anything).Return(true, nil).Once()
+
+ observedChainState := NewObservedChainHealthCheck(
+ mockedHealthcheck,
+ "plugin",
+ 10,
+ 20,
+ address,
+ )
+
+ health, err := observedChainState.IsHealthy(tests.Context(t))
+ require.NoError(t, err)
+ assert.True(t, health)
+ assert.Equal(t, float64(1), testutil.ToFloat64(laneHealthStatus.WithLabelValues("plugin", "10", "20", "0x1234567890123456789012345678901234567890")))
+
+ // Mark as unhealthy
+ mockedHealthcheck.On("IsHealthy", mock.Anything).Return(false, nil).Once()
+
+ health, err = observedChainState.IsHealthy(tests.Context(t))
+ require.NoError(t, err)
+ assert.False(t, health)
+ assert.Equal(t, float64(0), testutil.ToFloat64(laneHealthStatus.WithLabelValues("plugin", "10", "20", "0x1234567890123456789012345678901234567890")))
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/once.go b/core/services/ocr2/plugins/ccip/internal/cache/once.go
new file mode 100644
index 00000000000..713501a03e1
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/once.go
@@ -0,0 +1,38 @@
+package cache
+
+import (
+ "context"
+ "sync"
+)
+
+type OnceCtxFunction[T any] func(ctx context.Context) (T, error)
+
+// CallOnceOnNoError returns a new function that wraps the given function f with caching capabilities.
+// If f returns an error, the result is not cached, allowing f to be retried on subsequent calls.
+// Use case for that is to avoid caching an error forever in case of transient errors (e.g. flaky RPC)
+func CallOnceOnNoError[T any](f OnceCtxFunction[T]) OnceCtxFunction[T] {
+ var (
+ mu sync.Mutex
+ value T
+ err error
+ called bool
+ )
+
+ return func(ctx context.Context) (T, error) {
+ mu.Lock()
+ defer mu.Unlock()
+
+ // If the function has been called successfully before, return the cached result.
+ if called && err == nil {
+ return value, nil
+ }
+
+ // Call the function and cache the result only if there is no error.
+ value, err = f(ctx)
+ if err == nil {
+ called = true
+ }
+
+ return value, err
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/cache/once_test.go b/core/services/ocr2/plugins/ccip/internal/cache/once_test.go
new file mode 100644
index 00000000000..6ba2fbddd53
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/cache/once_test.go
@@ -0,0 +1,83 @@
+package cache
+
+import (
+ "context"
+ "errors"
+ "sync"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+)
+
+// TestCallOnceOnNoErrorCachingSuccess tests caching behavior when the function succeeds.
+func TestCallOnceOnNoErrorCachingSuccess(t *testing.T) {
+ callCount := 0
+ testFunc := func(ctx context.Context) (string, error) {
+ callCount++
+ return "test result", nil
+ }
+
+ cachedFunc := CallOnceOnNoError(testFunc)
+
+ // Call the function twice.
+ _, err := cachedFunc(tests.Context(t))
+ assert.NoError(t, err, "Expected no error on the first call")
+
+ _, err = cachedFunc(tests.Context(t))
+ assert.NoError(t, err, "Expected no error on the second call")
+
+ assert.Equal(t, 1, callCount, "Function should be called exactly once")
+}
+
+// TestCallOnceOnNoErrorCachingError tests that the function is retried after an error.
+func TestCallOnceOnNoErrorCachingError(t *testing.T) {
+ callCount := 0
+ testFunc := func(ctx context.Context) (string, error) {
+ callCount++
+ if callCount == 1 {
+ return "", errors.New("test error")
+ }
+ return "test result", nil
+ }
+
+ cachedFunc := CallOnceOnNoError(testFunc)
+
+ // First call should fail.
+ _, err := cachedFunc(tests.Context(t))
+ require.Error(t, err, "Expected an error on the first call")
+
+ // Second call should succeed.
+ r, err := cachedFunc(tests.Context(t))
+ assert.NoError(t, err, "Expected no error on the second call")
+ assert.Equal(t, "test result", r)
+ assert.Equal(t, 2, callCount, "Function should be called exactly twice")
+}
+
+// TestCallOnceOnNoErrorCachingConcurrency tests that the function works correctly under concurrent access.
+func TestCallOnceOnNoErrorCachingConcurrency(t *testing.T) {
+ var wg sync.WaitGroup
+ callCount := 0
+ testFunc := func(ctx context.Context) (string, error) {
+ callCount++
+ return "test result", nil
+ }
+
+ cachedFunc := CallOnceOnNoError(testFunc)
+
+ // Simulate concurrent calls.
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ _, err := cachedFunc(tests.Context(t))
+ assert.NoError(t, err, "Expected no error in concurrent execution")
+ }()
+ }
+
+ wg.Wait()
+
+ assert.Equal(t, 1, callCount, "Function should be called exactly once despite concurrent calls")
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipcalc/addr.go b/core/services/ocr2/plugins/ccip/internal/ccipcalc/addr.go
new file mode 100644
index 00000000000..40cdab6df9d
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipcalc/addr.go
@@ -0,0 +1,44 @@
+package ccipcalc
+
+import (
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/common"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+func EvmAddrsToGeneric(evmAddrs ...common.Address) []cciptypes.Address {
+ res := make([]cciptypes.Address, 0, len(evmAddrs))
+ for _, addr := range evmAddrs {
+ res = append(res, cciptypes.Address(addr.String()))
+ }
+ return res
+}
+
+func EvmAddrToGeneric(evmAddr common.Address) cciptypes.Address {
+ return cciptypes.Address(evmAddr.String())
+}
+
+func GenericAddrsToEvm(genericAddrs ...cciptypes.Address) ([]common.Address, error) {
+ evmAddrs := make([]common.Address, 0, len(genericAddrs))
+ for _, addr := range genericAddrs {
+ if !common.IsHexAddress(string(addr)) {
+ return nil, fmt.Errorf("%s not an evm address", addr)
+ }
+ evmAddrs = append(evmAddrs, common.HexToAddress(string(addr)))
+ }
+ return evmAddrs, nil
+}
+
+func GenericAddrToEvm(genAddr cciptypes.Address) (common.Address, error) {
+ evmAddrs, err := GenericAddrsToEvm(genAddr)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return evmAddrs[0], nil
+}
+
+func HexToAddress(h string) cciptypes.Address {
+ return cciptypes.Address(common.HexToAddress(h).String())
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipcalc/calc.go b/core/services/ocr2/plugins/ccip/internal/ccipcalc/calc.go
new file mode 100644
index 00000000000..8ba57e77ed2
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipcalc/calc.go
@@ -0,0 +1,69 @@
+package ccipcalc
+
+import (
+ "math/big"
+ "sort"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+// ContiguousReqs checks if seqNrs contains all numbers from min to max.
+func ContiguousReqs(lggr logger.Logger, min, max uint64, seqNrs []uint64) bool {
+ if int(max-min+1) != len(seqNrs) {
+ return false
+ }
+
+ for i, j := min, 0; i <= max && j < len(seqNrs); i, j = i+1, j+1 {
+ if seqNrs[j] != i {
+ lggr.Errorw("unexpected gap in seq nums", "seqNr", i, "minSeqNr", min, "maxSeqNr", max)
+ return false
+ }
+ }
+ return true
+}
+
+// CalculateUsdPerUnitGas returns: (sourceGasPrice * usdPerFeeCoin) / 1e18
+func CalculateUsdPerUnitGas(sourceGasPrice *big.Int, usdPerFeeCoin *big.Int) *big.Int {
+ // (wei / gas) * (usd / eth) * (1 eth / 1e18 wei) = usd/gas
+ tmp := new(big.Int).Mul(sourceGasPrice, usdPerFeeCoin)
+ return tmp.Div(tmp, big.NewInt(1e18))
+}
+
+// BigIntSortedMiddle returns the middle number after sorting the provided numbers. nil is returned if the provided slice is empty.
+// If length of the provided slice is even, the right-hand-side value of the middle 2 numbers is returned.
+// The objective of this function is to always pick within the range of values reported by honest nodes when we have 2f+1 values.
+func BigIntSortedMiddle(vals []*big.Int) *big.Int {
+ if len(vals) == 0 {
+ return nil
+ }
+
+ valsCopy := make([]*big.Int, len(vals))
+ copy(valsCopy[:], vals[:])
+ sort.Slice(valsCopy, func(i, j int) bool {
+ return valsCopy[i].Cmp(valsCopy[j]) == -1
+ })
+ return valsCopy[len(valsCopy)/2]
+}
+
+// Deviates checks if x1 and x2 deviates based on the provided ppb (parts per billion)
+// ppb is calculated based on the smaller value of the two
+// e.g, if x1 > x2, deviation_parts_per_billion = ((x1 - x2) / x2) * 1e9
+func Deviates(x1, x2 *big.Int, ppb int64) bool {
+ // if x1 == 0 or x2 == 0, deviates if x2 != x1, to avoid the relative division by 0 error
+ if x1.BitLen() == 0 || x2.BitLen() == 0 {
+ return x1.Cmp(x2) != 0
+ }
+ diff := big.NewInt(0).Sub(x1, x2) // diff = x1-x2
+ diff.Mul(diff, big.NewInt(1e9)) // diff = diff * 1e9
+ // dividing by the smaller value gives consistent ppb regardless of input order, and supports >100% deviation.
+ if x1.Cmp(x2) > 0 {
+ diff.Div(diff, x2)
+ } else {
+ diff.Div(diff, x1)
+ }
+ return diff.CmpAbs(big.NewInt(ppb)) > 0 // abs(diff) > ppb
+}
+
+func MergeEpochAndRound(epoch uint32, round uint8) uint64 {
+ return uint64(epoch)<<8 + uint64(round)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipcalc/calc_test.go b/core/services/ocr2/plugins/ccip/internal/ccipcalc/calc_test.go
new file mode 100644
index 00000000000..83384eca481
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipcalc/calc_test.go
@@ -0,0 +1,220 @@
+package ccipcalc
+
+import (
+ "math"
+ "math/big"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+)
+
+func TestMergeEpochAndRound(t *testing.T) {
+ type args struct {
+ epoch uint32
+ round uint8
+ }
+ tests := []struct {
+ name string
+ args args
+ want uint64
+ }{
+ {
+ name: "zero round and epoch",
+ args: args{epoch: 0, round: 0},
+ want: 0,
+ },
+ {
+ name: "avg case",
+ args: args{
+ epoch: 243,
+ round: 15,
+ },
+ want: 62223,
+ },
+ {
+ name: "largest epoch and round",
+ args: args{
+ epoch: math.MaxUint32,
+ round: math.MaxUint8,
+ },
+ want: 1099511627775,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want,
+ MergeEpochAndRound(tt.args.epoch, tt.args.round),
+ "mergeEpochAndRound(%v, %v)", tt.args.epoch, tt.args.round)
+ })
+ }
+}
+
+func TestContiguousReqs(t *testing.T) {
+ testCases := []struct {
+ min uint64
+ max uint64
+ seqNrs []uint64
+ exp bool
+ }{
+ {min: 5, max: 10, seqNrs: []uint64{5, 6, 7, 8, 9, 10}, exp: true},
+ {min: 5, max: 10, seqNrs: []uint64{5, 7, 8, 9, 10}, exp: false},
+ {min: 5, max: 10, seqNrs: []uint64{5, 6, 7, 8, 9, 10, 11}, exp: false},
+ {min: 5, max: 10, seqNrs: []uint64{}, exp: false},
+ {min: 1, max: 1, seqNrs: []uint64{1}, exp: true},
+ {min: 6, max: 10, seqNrs: []uint64{5, 7, 8, 9, 10}, exp: false},
+ }
+
+ for _, tc := range testCases {
+ res := ContiguousReqs(logger.NullLogger, tc.min, tc.max, tc.seqNrs)
+ assert.Equal(t, tc.exp, res)
+ }
+}
+
+func TestCalculateUsdPerUnitGas(t *testing.T) {
+ testCases := []struct {
+ name string
+ sourceGasPrice *big.Int
+ usdPerFeeCoin *big.Int
+ exp *big.Int
+ }{
+ {
+ name: "base case",
+ sourceGasPrice: big.NewInt(2e18),
+ usdPerFeeCoin: big.NewInt(3e18),
+ exp: big.NewInt(6e18),
+ },
+ {
+ name: "small numbers",
+ sourceGasPrice: big.NewInt(1000),
+ usdPerFeeCoin: big.NewInt(2000),
+ exp: big.NewInt(0),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ res := CalculateUsdPerUnitGas(tc.sourceGasPrice, tc.usdPerFeeCoin)
+ assert.Zero(t, tc.exp.Cmp(res))
+ })
+ }
+}
+
+func TestBigIntSortedMiddle(t *testing.T) {
+ tests := []struct {
+ name string
+ vals []*big.Int
+ want *big.Int
+ }{
+ {
+ name: "base case",
+ vals: []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(4), big.NewInt(5)},
+ want: big.NewInt(4),
+ },
+ {
+ name: "not sorted",
+ vals: []*big.Int{big.NewInt(100), big.NewInt(50), big.NewInt(30), big.NewInt(110)},
+ want: big.NewInt(100),
+ },
+ {
+ name: "empty slice",
+ vals: []*big.Int{},
+ want: nil,
+ },
+ {
+ name: "one item",
+ vals: []*big.Int{big.NewInt(123)},
+ want: big.NewInt(123),
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, BigIntSortedMiddle(tt.vals), "BigIntSortedMiddle(%v)", tt.vals)
+ })
+ }
+}
+
+func TestDeviates(t *testing.T) {
+ type args struct {
+ x1 *big.Int
+ x2 *big.Int
+ ppb int64
+ }
+ tests := []struct {
+ name string
+ args args
+ want bool
+ }{
+ {
+ name: "base case",
+ args: args{x1: big.NewInt(1e9), x2: big.NewInt(2e9), ppb: 1},
+ want: true,
+ },
+ {
+ name: "x1 is zero and x1 neq x2",
+ args: args{x1: big.NewInt(0), x2: big.NewInt(1), ppb: 999},
+ want: true,
+ },
+ {
+ name: "x2 is zero and x1 neq x2",
+ args: args{x1: big.NewInt(1), x2: big.NewInt(0), ppb: 999},
+ want: true,
+ },
+ {
+ name: "x1 and x2 are both zero",
+ args: args{x1: big.NewInt(0), x2: big.NewInt(0), ppb: 999},
+ want: false,
+ },
+ {
+ name: "deviates when ppb is 0",
+ args: args{x1: big.NewInt(0), x2: big.NewInt(1), ppb: 0},
+ want: true,
+ },
+ {
+ name: "does not deviate when x1 eq x2",
+ args: args{x1: big.NewInt(5), x2: big.NewInt(5), ppb: 1},
+ want: false,
+ },
+ {
+ name: "does not deviate with high ppb when x2 is greater",
+ args: args{x1: big.NewInt(5), x2: big.NewInt(10), ppb: 2e9},
+ want: false,
+ },
+ {
+ name: "does not deviate with high ppb when x1 is greater",
+ args: args{x1: big.NewInt(10), x2: big.NewInt(5), ppb: 2e9},
+ want: false,
+ },
+ {
+ name: "deviates with low ppb when x2 is greater",
+ args: args{x1: big.NewInt(5), x2: big.NewInt(10), ppb: 9e8},
+ want: true,
+ },
+ {
+ name: "deviates with low ppb when x1 is greater",
+ args: args{x1: big.NewInt(10), x2: big.NewInt(5), ppb: 9e8},
+ want: true,
+ },
+ {
+ name: "near deviation limit but deviates",
+ args: args{x1: big.NewInt(10), x2: big.NewInt(5), ppb: 1e9 - 1},
+ want: true,
+ },
+ {
+ name: "at deviation limit but does not deviate",
+ args: args{x1: big.NewInt(10), x2: big.NewInt(5), ppb: 1e9},
+ want: false,
+ },
+ {
+ name: "near deviation limit but does not deviate",
+ args: args{x1: big.NewInt(10), x2: big.NewInt(5), ppb: 1e9 + 1},
+ want: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, Deviates(tt.args.x1, tt.args.x2, tt.args.ppb), "Deviates(%v, %v, %v)", tt.args.x1, tt.args.x2, tt.args.ppb)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts.go b/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts.go
new file mode 100644
index 00000000000..8372ae47486
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts.go
@@ -0,0 +1,123 @@
+package ccipcommon
+
+import (
+ "context"
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/avast/retry-go/v4"
+
+ "golang.org/x/sync/errgroup"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+func GetMessageIDsAsHexString(messages []cciptypes.EVM2EVMMessage) []string {
+ messageIDs := make([]string, 0, len(messages))
+ for _, m := range messages {
+ messageIDs = append(messageIDs, "0x"+hex.EncodeToString(m.MessageID[:]))
+ }
+ return messageIDs
+}
+
+type BackfillArgs struct {
+ SourceLP, DestLP logpoller.LogPoller
+ SourceStartBlock, DestStartBlock uint64
+}
+
+func FlattenedAndSortedTokens(slices ...[]cciptypes.Address) (tokens []cciptypes.Address) {
+ // fee token can overlap with bridgeable tokens, we need to dedup them to arrive at lane token set
+ tokens = FlattenUniqueSlice(slices...)
+
+ // return the tokens in deterministic order to aid with testing and debugging
+ sort.Slice(tokens, func(i, j int) bool {
+ return tokens[i] < tokens[j]
+ })
+
+ return tokens
+}
+
+// GetDestinationTokens returns the destination chain fee tokens from the provided price registry
+// and the bridgeable tokens from the offramp.
+func GetDestinationTokens(ctx context.Context, offRamp ccipdata.OffRampReader, priceRegistry cciptypes.PriceRegistryReader) (fee, bridged []cciptypes.Address, err error) {
+ eg := new(errgroup.Group)
+
+ var destFeeTokens []cciptypes.Address
+ var destBridgeableTokens []cciptypes.Address
+
+ eg.Go(func() error {
+ tokens, err := priceRegistry.GetFeeTokens(ctx)
+ if err != nil {
+ return fmt.Errorf("get dest fee tokens: %w", err)
+ }
+ destFeeTokens = tokens
+ return nil
+ })
+
+ eg.Go(func() error {
+ tokens, err := offRamp.GetTokens(ctx)
+ if err != nil {
+ return fmt.Errorf("get dest bridgeable tokens: %w", err)
+ }
+ destBridgeableTokens = tokens.DestinationTokens
+ return nil
+ })
+
+ if err := eg.Wait(); err != nil {
+ return nil, nil, err
+ }
+
+ return destFeeTokens, destBridgeableTokens, nil
+}
+
+// FlattenUniqueSlice returns a flattened slice that contains unique elements by preserving their order.
+func FlattenUniqueSlice[T comparable](slices ...[]T) []T {
+ seen := make(map[T]struct{})
+ flattened := make([]T, 0)
+
+ for _, sl := range slices {
+ for _, el := range sl {
+ if _, exists := seen[el]; !exists {
+ flattened = append(flattened, el)
+ seen[el] = struct{}{}
+ }
+ }
+ }
+ return flattened
+}
+
+func IsTxRevertError(err error) bool {
+ if err == nil {
+ return false
+ }
+
+ // Geth eth_call reverts with "execution reverted"
+ // Nethermind, Parity, OpenEthereum eth_call reverts with "VM execution error"
+ // See: https://github.com/ethereum/go-ethereum/issues/21886
+ return strings.Contains(err.Error(), "execution reverted") || strings.Contains(err.Error(), "VM execution error")
+}
+
+func SelectorToBytes(chainSelector uint64) [16]byte {
+ var b [16]byte
+ binary.BigEndian.PutUint64(b[:], chainSelector)
+ return b
+}
+
+// RetryUntilSuccess repeatedly calls fn until it returns a nil error. After each failed call there is an exponential
+// backoff applied, between initialDelay and maxDelay.
+func RetryUntilSuccess[T any](fn func() (T, error), initialDelay time.Duration, maxDelay time.Duration) (T, error) {
+ return retry.DoWithData(
+ fn,
+ retry.Delay(initialDelay),
+ retry.MaxDelay(maxDelay),
+ retry.DelayType(retry.BackOffDelay),
+ retry.UntilSucceeded(),
+ )
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts_test.go b/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts_test.go
new file mode 100644
index 00000000000..6f1cdb4a6af
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipcommon/shortcuts_test.go
@@ -0,0 +1,158 @@
+package ccipcommon
+
+import (
+ "fmt"
+ "math/rand"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+func TestGetMessageIDsAsHexString(t *testing.T) {
+ t.Run("base", func(t *testing.T) {
+ hashes := make([]cciptypes.Hash, 10)
+ for i := range hashes {
+ hashes[i] = cciptypes.Hash(common.HexToHash(strconv.Itoa(rand.Intn(100000))))
+ }
+
+ msgs := make([]cciptypes.EVM2EVMMessage, len(hashes))
+ for i := range msgs {
+ msgs[i] = cciptypes.EVM2EVMMessage{MessageID: hashes[i]}
+ }
+
+ messageIDs := GetMessageIDsAsHexString(msgs)
+ for i := range messageIDs {
+ assert.Equal(t, hashes[i].String(), messageIDs[i])
+ }
+ })
+
+ t.Run("empty", func(t *testing.T) {
+ messageIDs := GetMessageIDsAsHexString(nil)
+ assert.Empty(t, messageIDs)
+ })
+}
+
+func TestFlattenUniqueSlice(t *testing.T) {
+ testCases := []struct {
+ name string
+ inputSlices [][]int
+ expectedOutput []int
+ }{
+ {name: "empty", inputSlices: nil, expectedOutput: []int{}},
+ {name: "empty 2", inputSlices: [][]int{}, expectedOutput: []int{}},
+ {name: "single", inputSlices: [][]int{{1, 2, 3, 3, 3, 4}}, expectedOutput: []int{1, 2, 3, 4}},
+ {name: "simple", inputSlices: [][]int{{1, 2, 3}, {2, 3, 4}}, expectedOutput: []int{1, 2, 3, 4}},
+ {
+ name: "more complex case",
+ inputSlices: [][]int{{1, 3}, {2, 4, 3}, {5, 2, -1, 7, 10}},
+ expectedOutput: []int{1, 3, 2, 4, 5, -1, 7, 10},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ res := FlattenUniqueSlice(tc.inputSlices...)
+ assert.Equal(t, tc.expectedOutput, res)
+ })
+ }
+}
+
+func TestFlattenedAndSortedTokens(t *testing.T) {
+ testCases := []struct {
+ name string
+ inputSlices [][]cciptypes.Address
+ expectedOutput []cciptypes.Address
+ }{
+ {name: "empty", inputSlices: nil, expectedOutput: []cciptypes.Address{}},
+ {name: "empty 2", inputSlices: [][]cciptypes.Address{}, expectedOutput: []cciptypes.Address{}},
+ {
+ name: "single",
+ inputSlices: [][]cciptypes.Address{{"0x1", "0x2", "0x3"}},
+ expectedOutput: []cciptypes.Address{"0x1", "0x2", "0x3"},
+ },
+ {
+ name: "simple",
+ inputSlices: [][]cciptypes.Address{{"0x1", "0x2", "0x3"}, {"0x2", "0x3", "0x4"}},
+ expectedOutput: []cciptypes.Address{"0x1", "0x2", "0x3", "0x4"},
+ },
+ {
+ name: "more complex case",
+ inputSlices: [][]cciptypes.Address{
+ {"0x1", "0x3"},
+ {"0x2", "0x4", "0x3"},
+ {"0x5", "0x2", "0x7", "0xa"},
+ },
+ expectedOutput: []cciptypes.Address{
+ "0x1",
+ "0x2",
+ "0x3",
+ "0x4",
+ "0x5",
+ "0x7",
+ "0xa",
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ res := FlattenedAndSortedTokens(tc.inputSlices...)
+ assert.Equal(t, tc.expectedOutput, res)
+ })
+ }
+}
+
+func TestIsTxRevertError(t *testing.T) {
+ testCases := []struct {
+ name string
+ inputError error
+ expectedOutput bool
+ }{
+ {name: "empty", inputError: nil, expectedOutput: false},
+ {name: "non-revert error", inputError: fmt.Errorf("nothing"), expectedOutput: false},
+ {name: "geth error", inputError: fmt.Errorf("execution reverted"), expectedOutput: true},
+ {name: "nethermind error", inputError: fmt.Errorf("VM execution error"), expectedOutput: true},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ assert.Equal(t, tc.expectedOutput, IsTxRevertError(tc.inputError))
+ })
+ }
+}
+
+func TestRetryUntilSuccess(t *testing.T) {
+ // Set delays to 0 for tests
+ initialDelay := 0 * time.Nanosecond
+ maxDelay := 0 * time.Nanosecond
+
+ numAttempts := 5
+ numCalls := 0
+ // A function that returns success only after numAttempts calls. RetryUntilSuccess will repeatedly call this
+ // function until it succeeds.
+ fn := func() (int, error) {
+ numCalls++
+ numAttempts--
+ if numAttempts > 0 {
+ return numCalls, fmt.Errorf("")
+ }
+ return numCalls, nil
+ }
+
+ // Assert that RetryUntilSuccess returns the expected value when fn returns success on the 5th attempt
+ numCalls, err := RetryUntilSuccess(fn, initialDelay, maxDelay)
+ assert.Nil(t, err)
+ assert.Equal(t, 5, numCalls)
+
+ // Assert that RetryUntilSuccess returns the expected value when fn returns success on the 8th attempt
+ numAttempts = 8
+ numCalls = 0
+ numCalls, err = RetryUntilSuccess(fn, initialDelay, maxDelay)
+ assert.Nil(t, err)
+ assert.Equal(t, 8, numCalls)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/mocks/token_pool_batched_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/mocks/token_pool_batched_reader_mock.go
new file mode 100644
index 00000000000..551cd7c6a68
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/mocks/token_pool_batched_reader_mock.go
@@ -0,0 +1,142 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// TokenPoolBatchedReader is an autogenerated mock type for the TokenPoolBatchedReader type
+type TokenPoolBatchedReader struct {
+ mock.Mock
+}
+
+type TokenPoolBatchedReader_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *TokenPoolBatchedReader) EXPECT() *TokenPoolBatchedReader_Expecter {
+ return &TokenPoolBatchedReader_Expecter{mock: &_m.Mock}
+}
+
+// Close provides a mock function with given fields:
+func (_m *TokenPoolBatchedReader) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// TokenPoolBatchedReader_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type TokenPoolBatchedReader_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *TokenPoolBatchedReader_Expecter) Close() *TokenPoolBatchedReader_Close_Call {
+ return &TokenPoolBatchedReader_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *TokenPoolBatchedReader_Close_Call) Run(run func()) *TokenPoolBatchedReader_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *TokenPoolBatchedReader_Close_Call) Return(_a0 error) *TokenPoolBatchedReader_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *TokenPoolBatchedReader_Close_Call) RunAndReturn(run func() error) *TokenPoolBatchedReader_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetInboundTokenPoolRateLimits provides a mock function with given fields: ctx, tokenPoolReaders
+func (_m *TokenPoolBatchedReader) GetInboundTokenPoolRateLimits(ctx context.Context, tokenPoolReaders []ccip.Address) ([]ccip.TokenBucketRateLimit, error) {
+ ret := _m.Called(ctx, tokenPoolReaders)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetInboundTokenPoolRateLimits")
+ }
+
+ var r0 []ccip.TokenBucketRateLimit
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) ([]ccip.TokenBucketRateLimit, error)); ok {
+ return rf(ctx, tokenPoolReaders)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) []ccip.TokenBucketRateLimit); ok {
+ r0 = rf(ctx, tokenPoolReaders)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.TokenBucketRateLimit)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []ccip.Address) error); ok {
+ r1 = rf(ctx, tokenPoolReaders)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetInboundTokenPoolRateLimits'
+type TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call struct {
+ *mock.Call
+}
+
+// GetInboundTokenPoolRateLimits is a helper method to define mock.On call
+// - ctx context.Context
+// - tokenPoolReaders []ccip.Address
+func (_e *TokenPoolBatchedReader_Expecter) GetInboundTokenPoolRateLimits(ctx interface{}, tokenPoolReaders interface{}) *TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call {
+ return &TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call{Call: _e.mock.On("GetInboundTokenPoolRateLimits", ctx, tokenPoolReaders)}
+}
+
+func (_c *TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call) Run(run func(ctx context.Context, tokenPoolReaders []ccip.Address)) *TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]ccip.Address))
+ })
+ return _c
+}
+
+func (_c *TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call) Return(_a0 []ccip.TokenBucketRateLimit, _a1 error) *TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call) RunAndReturn(run func(context.Context, []ccip.Address) ([]ccip.TokenBucketRateLimit, error)) *TokenPoolBatchedReader_GetInboundTokenPoolRateLimits_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewTokenPoolBatchedReader creates a new instance of TokenPoolBatchedReader. 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 NewTokenPoolBatchedReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *TokenPoolBatchedReader {
+ mock := &TokenPoolBatchedReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/token_pool_batch_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/token_pool_batch_reader.go
new file mode 100644
index 00000000000..32ec1b24ac9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/token_pool_batch_reader.go
@@ -0,0 +1,192 @@
+package batchreader
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+
+ "github.com/ethereum/go-ethereum/common"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ type_and_version "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/type_and_version_interface_wrapper"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_4_0"
+)
+
+var (
+ typeAndVersionABI = abihelpers.MustParseABI(type_and_version.TypeAndVersionInterfaceABI)
+)
+
+type EVMTokenPoolBatchedReader struct {
+ lggr logger.Logger
+ remoteChainSelector uint64
+ offRampAddress common.Address
+ evmBatchCaller rpclib.EvmBatchCaller
+
+ tokenPoolReaders map[cciptypes.Address]ccipdata.TokenPoolReader
+ tokenPoolReaderMu sync.RWMutex
+}
+
+type TokenPoolBatchedReader interface {
+ cciptypes.TokenPoolBatchedReader
+}
+
+var _ TokenPoolBatchedReader = (*EVMTokenPoolBatchedReader)(nil)
+
+func NewEVMTokenPoolBatchedReader(lggr logger.Logger, remoteChainSelector uint64, offRampAddress cciptypes.Address, evmBatchCaller rpclib.EvmBatchCaller) (*EVMTokenPoolBatchedReader, error) {
+ offRampAddrEvm, err := ccipcalc.GenericAddrToEvm(offRampAddress)
+ if err != nil {
+ return nil, err
+ }
+
+ return &EVMTokenPoolBatchedReader{
+ lggr: lggr,
+ remoteChainSelector: remoteChainSelector,
+ offRampAddress: offRampAddrEvm,
+ evmBatchCaller: evmBatchCaller,
+ tokenPoolReaders: make(map[cciptypes.Address]ccipdata.TokenPoolReader),
+ }, nil
+}
+
+func (br *EVMTokenPoolBatchedReader) GetInboundTokenPoolRateLimits(ctx context.Context, tokenPools []cciptypes.Address) ([]cciptypes.TokenBucketRateLimit, error) {
+ if len(tokenPools) == 0 {
+ return []cciptypes.TokenBucketRateLimit{}, nil
+ }
+
+ err := br.loadTokenPoolReaders(ctx, tokenPools)
+ if err != nil {
+ return nil, err
+ }
+
+ tokenPoolReaders := make([]ccipdata.TokenPoolReader, 0, len(tokenPools))
+ for _, poolAddress := range tokenPools {
+ br.tokenPoolReaderMu.RLock()
+ tokenPoolReader, exists := br.tokenPoolReaders[poolAddress]
+ br.tokenPoolReaderMu.RUnlock()
+ if !exists {
+ return nil, fmt.Errorf("token pool %s not found", poolAddress)
+ }
+ tokenPoolReaders = append(tokenPoolReaders, tokenPoolReader)
+ }
+
+ evmCalls := make([]rpclib.EvmCall, 0, len(tokenPoolReaders))
+ for _, poolReader := range tokenPoolReaders {
+ switch v := poolReader.(type) {
+ case *v1_2_0.TokenPool:
+ evmCalls = append(evmCalls, v1_2_0.GetInboundTokenPoolRateLimitCall(v.Address(), v.OffRampAddress))
+ case *v1_4_0.TokenPool:
+ evmCalls = append(evmCalls, v1_4_0.GetInboundTokenPoolRateLimitCall(v.Address(), v.RemoteChainSelector))
+ default:
+ return nil, fmt.Errorf("unsupported token pool version %T", v)
+ }
+ }
+
+ results, err := br.evmBatchCaller.BatchCall(ctx, 0, evmCalls)
+ if err != nil {
+ return nil, fmt.Errorf("batch call limit: %w", err)
+ }
+
+ resultsParsed, err := rpclib.ParseOutputs[cciptypes.TokenBucketRateLimit](results, func(d rpclib.DataAndErr) (cciptypes.TokenBucketRateLimit, error) {
+ return rpclib.ParseOutput[cciptypes.TokenBucketRateLimit](d, 0)
+ })
+ if err != nil {
+ return nil, fmt.Errorf("parse outputs: %w", err)
+ }
+ return resultsParsed, nil
+}
+
+// loadTokenPoolReaders loads the token pools into the factory's cache
+func (br *EVMTokenPoolBatchedReader) loadTokenPoolReaders(ctx context.Context, tokenPoolAddresses []cciptypes.Address) error {
+ var missingTokens []common.Address
+
+ br.tokenPoolReaderMu.RLock()
+ for _, poolAddress := range tokenPoolAddresses {
+ if _, exists := br.tokenPoolReaders[poolAddress]; !exists {
+ evmPoolAddr, err := ccipcalc.GenericAddrToEvm(poolAddress)
+ if err != nil {
+ return err
+ }
+ missingTokens = append(missingTokens, evmPoolAddr)
+ }
+ }
+ br.tokenPoolReaderMu.RUnlock()
+
+ // Only continue if there are missing tokens
+ if len(missingTokens) == 0 {
+ return nil
+ }
+
+ typeAndVersions, err := getBatchedTypeAndVersion(ctx, br.evmBatchCaller, missingTokens)
+ if err != nil {
+ return err
+ }
+
+ br.tokenPoolReaderMu.Lock()
+ defer br.tokenPoolReaderMu.Unlock()
+ for i, tokenPoolAddress := range missingTokens {
+ typeAndVersion := typeAndVersions[i]
+ poolType, version, err := ccipconfig.ParseTypeAndVersion(typeAndVersion)
+ if err != nil {
+ return err
+ }
+ switch version {
+ case ccipdata.V1_0_0, ccipdata.V1_1_0, ccipdata.V1_2_0:
+ br.tokenPoolReaders[ccipcalc.EvmAddrToGeneric(tokenPoolAddress)] = v1_2_0.NewTokenPool(poolType, tokenPoolAddress, br.offRampAddress)
+ case ccipdata.V1_4_0:
+ br.tokenPoolReaders[ccipcalc.EvmAddrToGeneric(tokenPoolAddress)] = v1_4_0.NewTokenPool(poolType, tokenPoolAddress, br.remoteChainSelector)
+ default:
+ return fmt.Errorf("unsupported token pool version %v", version)
+ }
+ }
+ return nil
+}
+
+func getBatchedTypeAndVersion(ctx context.Context, evmBatchCaller rpclib.EvmBatchCaller, poolAddresses []common.Address) ([]string, error) {
+ var evmCalls []rpclib.EvmCall
+
+ for _, poolAddress := range poolAddresses {
+ // Add the typeAndVersion call to the batch
+ evmCalls = append(evmCalls, rpclib.NewEvmCall(
+ typeAndVersionABI,
+ "typeAndVersion",
+ poolAddress,
+ ))
+ }
+
+ results, err := evmBatchCaller.BatchCall(ctx, 0, evmCalls)
+ if err != nil {
+ return nil, fmt.Errorf("batch call limit: %w", err)
+ }
+
+ result, err := rpclib.ParseOutputs[string](results, func(d rpclib.DataAndErr) (string, error) {
+ tAndV, err1 := rpclib.ParseOutput[string](d, 0)
+ if err1 != nil {
+ // typeAndVersion method do not exist for 1.0 pools. We are going to get an ErrEmptyOutput in that case.
+ // Some chains, like the simulated chains, will simply revert with "execution reverted"
+ if errors.Is(err1, rpclib.ErrEmptyOutput) || ccipcommon.IsTxRevertError(err1) {
+ return "LegacyPool " + ccipdata.V1_0_0, nil
+ }
+ return "", err1
+ }
+
+ return tAndV, nil
+ })
+ if err != nil {
+ return nil, fmt.Errorf("parse outputs: %w", err)
+ }
+ return result, nil
+}
+
+func (br *EVMTokenPoolBatchedReader) Close() error {
+ return nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/token_pool_batch_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/token_pool_batch_reader_test.go
new file mode 100644
index 00000000000..ceafdf22721
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/batchreader/token_pool_batch_reader_test.go
@@ -0,0 +1,86 @@
+package batchreader
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "testing"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+func TestTokenPoolFactory(t *testing.T) {
+ lggr := logger.Test(t)
+ offRamp := utils.RandomAddress()
+ ctx := context.Background()
+ remoteChainSelector := uint64(2000)
+ batchCallerMock := rpclibmocks.NewEvmBatchCaller(t)
+
+ tokenPoolBatchReader, err := NewEVMTokenPoolBatchedReader(lggr, remoteChainSelector, ccipcalc.EvmAddrToGeneric(offRamp), batchCallerMock)
+ assert.NoError(t, err)
+
+ poolTypes := []string{"BurnMint", "LockRelease"}
+
+ rateLimits := cciptypes.TokenBucketRateLimit{
+ Tokens: big.NewInt(333333),
+ LastUpdated: 33,
+ IsEnabled: true,
+ Capacity: big.NewInt(666666),
+ Rate: big.NewInt(444444),
+ }
+
+ for _, versionStr := range []string{ccipdata.V1_0_0, ccipdata.V1_1_0, ccipdata.V1_2_0, ccipdata.V1_4_0} {
+ gotRateLimits, err := tokenPoolBatchReader.GetInboundTokenPoolRateLimits(ctx, []cciptypes.Address{})
+ require.NoError(t, err)
+ assert.Empty(t, gotRateLimits)
+
+ var batchCallResult []rpclib.DataAndErr
+ for _, poolType := range poolTypes {
+ if versionStr == ccipdata.V1_0_0 {
+ // simulating the behaviour for 1.0.0 pools where typeAndVersion method does not exist
+ batchCallResult = append(batchCallResult, rpclib.DataAndErr{
+ Err: fmt.Errorf("unpack result: %w", rpclib.ErrEmptyOutput),
+ })
+ } else {
+ batchCallResult = append(batchCallResult, rpclib.DataAndErr{
+ Outputs: []any{poolType + " " + versionStr},
+ Err: nil,
+ })
+ }
+ }
+
+ batchCallerMock.On("BatchCall", ctx, uint64(0), mock.Anything).Return(batchCallResult, nil).Once()
+ batchCallerMock.On("BatchCall", ctx, uint64(0), mock.Anything).Return([]rpclib.DataAndErr{{
+ Outputs: []any{rateLimits},
+ Err: nil,
+ }, {
+ Outputs: []any{rateLimits},
+ Err: nil,
+ }}, nil).Once()
+
+ var poolAddresses []cciptypes.Address
+
+ for i := 0; i < len(poolTypes); i++ {
+ poolAddresses = append(poolAddresses, ccipcalc.EvmAddrToGeneric(utils.RandomAddress()))
+ }
+
+ gotRateLimits, err = tokenPoolBatchReader.GetInboundTokenPoolRateLimits(ctx, poolAddresses)
+ require.NoError(t, err)
+ assert.Len(t, gotRateLimits, len(poolTypes))
+
+ for _, gotRateLimit := range gotRateLimits {
+ assert.Equal(t, rateLimits, gotRateLimit)
+ }
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/mocks/price_registry_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/mocks/price_registry_mock.go
new file mode 100644
index 00000000000..59588a25d17
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/mocks/price_registry_mock.go
@@ -0,0 +1,97 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// PriceRegistry is an autogenerated mock type for the PriceRegistry type
+type PriceRegistry struct {
+ mock.Mock
+}
+
+type PriceRegistry_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *PriceRegistry) EXPECT() *PriceRegistry_Expecter {
+ return &PriceRegistry_Expecter{mock: &_m.Mock}
+}
+
+// NewPriceRegistryReader provides a mock function with given fields: ctx, addr
+func (_m *PriceRegistry) NewPriceRegistryReader(ctx context.Context, addr ccip.Address) (ccip.PriceRegistryReader, error) {
+ ret := _m.Called(ctx, addr)
+
+ if len(ret) == 0 {
+ panic("no return value specified for NewPriceRegistryReader")
+ }
+
+ var r0 ccip.PriceRegistryReader
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.Address) (ccip.PriceRegistryReader, error)); ok {
+ return rf(ctx, addr)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.Address) ccip.PriceRegistryReader); ok {
+ r0 = rf(ctx, addr)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(ccip.PriceRegistryReader)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, ccip.Address) error); ok {
+ r1 = rf(ctx, addr)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistry_NewPriceRegistryReader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewPriceRegistryReader'
+type PriceRegistry_NewPriceRegistryReader_Call struct {
+ *mock.Call
+}
+
+// NewPriceRegistryReader is a helper method to define mock.On call
+// - ctx context.Context
+// - addr ccip.Address
+func (_e *PriceRegistry_Expecter) NewPriceRegistryReader(ctx interface{}, addr interface{}) *PriceRegistry_NewPriceRegistryReader_Call {
+ return &PriceRegistry_NewPriceRegistryReader_Call{Call: _e.mock.On("NewPriceRegistryReader", ctx, addr)}
+}
+
+func (_c *PriceRegistry_NewPriceRegistryReader_Call) Run(run func(ctx context.Context, addr ccip.Address)) *PriceRegistry_NewPriceRegistryReader_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(ccip.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistry_NewPriceRegistryReader_Call) Return(_a0 ccip.PriceRegistryReader, _a1 error) *PriceRegistry_NewPriceRegistryReader_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistry_NewPriceRegistryReader_Call) RunAndReturn(run func(context.Context, ccip.Address) (ccip.PriceRegistryReader, error)) *PriceRegistry_NewPriceRegistryReader_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewPriceRegistry creates a new instance of PriceRegistry. 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 NewPriceRegistry(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *PriceRegistry {
+ mock := &PriceRegistry{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/provider.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/provider.go
new file mode 100644
index 00000000000..971b507e828
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/ccipdataprovider/provider.go
@@ -0,0 +1,41 @@
+package ccipdataprovider
+
+import (
+ "context"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/observability"
+)
+
+type PriceRegistry interface {
+ NewPriceRegistryReader(ctx context.Context, addr cciptypes.Address) (cciptypes.PriceRegistryReader, error)
+}
+
+type EvmPriceRegistry struct {
+ lp logpoller.LogPoller
+ ec client.Client
+ lggr logger.Logger
+ pluginLabel string
+}
+
+func NewEvmPriceRegistry(lp logpoller.LogPoller, ec client.Client, lggr logger.Logger, pluginLabel string) *EvmPriceRegistry {
+ return &EvmPriceRegistry{
+ lp: lp,
+ ec: ec,
+ lggr: lggr,
+ pluginLabel: pluginLabel,
+ }
+}
+
+func (p *EvmPriceRegistry) NewPriceRegistryReader(ctx context.Context, addr cciptypes.Address) (cciptypes.PriceRegistryReader, error) {
+ destPriceRegistryReader, err := factory.NewPriceRegistryReader(ctx, p.lggr, factory.NewEvmVersionFinder(), addr, p.lp, p.ec)
+ if err != nil {
+ return nil, err
+ }
+ return observability.NewPriceRegistryReader(destPriceRegistryReader, p.ec.ConfiguredChainID().Int64(), p.pluginLabel), nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader.go
new file mode 100644
index 00000000000..2b144b765ed
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader.go
@@ -0,0 +1,81 @@
+package ccipdata
+
+import (
+ "context"
+ "math/big"
+ "time"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+)
+
+// Common to all versions
+type CommitOnchainConfig commit_store.CommitStoreDynamicConfig
+
+func (d CommitOnchainConfig) AbiString() string {
+ return `
+ [
+ {
+ "components": [
+ {"name": "priceRegistry", "type": "address"}
+ ],
+ "type": "tuple"
+ }
+ ]`
+}
+
+func (d CommitOnchainConfig) Validate() error {
+ if d.PriceRegistry == (common.Address{}) {
+ return errors.New("must set Price Registry address")
+ }
+ return nil
+}
+
+func NewCommitOffchainConfig(
+ gasPriceDeviationPPB uint32,
+ gasPriceHeartBeat time.Duration,
+ tokenPriceDeviationPPB uint32,
+ tokenPriceHeartBeat time.Duration,
+ inflightCacheExpiry time.Duration,
+ priceReportingDisabled bool,
+) cciptypes.CommitOffchainConfig {
+ return cciptypes.CommitOffchainConfig{
+ GasPriceDeviationPPB: gasPriceDeviationPPB,
+ GasPriceHeartBeat: gasPriceHeartBeat,
+ TokenPriceDeviationPPB: tokenPriceDeviationPPB,
+ TokenPriceHeartBeat: tokenPriceHeartBeat,
+ InflightCacheExpiry: inflightCacheExpiry,
+ PriceReportingDisabled: priceReportingDisabled,
+ }
+}
+
+type CommitStoreReader interface {
+ cciptypes.CommitStoreReader
+ SetGasEstimator(ctx context.Context, gpe gas.EvmFeeEstimator) error
+ SetSourceMaxGasPrice(ctx context.Context, sourceMaxGasPrice *big.Int) error
+}
+
+// FetchCommitStoreStaticConfig provides access to a commitStore's static config, which is required to access the source chain ID.
+func FetchCommitStoreStaticConfig(address common.Address, ec client.Client) (commit_store.CommitStoreStaticConfig, error) {
+ commitStore, err := loadCommitStore(address, ec)
+ if err != nil {
+ return commit_store.CommitStoreStaticConfig{}, err
+ }
+ return commitStore.GetStaticConfig(&bind.CallOpts{})
+}
+
+func loadCommitStore(commitStoreAddress common.Address, client client.Client) (commit_store.CommitStoreInterface, error) {
+ _, err := ccipconfig.VerifyTypeAndVersion(commitStoreAddress, client, ccipconfig.CommitStore)
+ if err != nil {
+ return nil, errors.Wrap(err, "Invalid commitStore contract")
+ }
+ return commit_store.NewCommitStore(commitStoreAddress, client)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader_test.go
new file mode 100644
index 00000000000..993829c1b68
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/commit_store_reader_test.go
@@ -0,0 +1,422 @@
+package ccipdata_test
+
+import (
+ "context"
+ "math/big"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks"
+ rollupMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_helper_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_helper_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+)
+
+func TestCommitOffchainConfig_Encoding(t *testing.T) {
+ tests := map[string]struct {
+ want v1_2_0.JSONCommitOffchainConfig
+ expectErr bool
+ }{
+ "encodes and decodes config with all fields set": {
+ want: v1_2_0.JSONCommitOffchainConfig{
+ SourceFinalityDepth: 3,
+ DestFinalityDepth: 3,
+ GasPriceHeartBeat: *config.MustNewDuration(1 * time.Hour),
+ DAGasPriceDeviationPPB: 5e7,
+ ExecGasPriceDeviationPPB: 5e7,
+ TokenPriceHeartBeat: *config.MustNewDuration(1 * time.Hour),
+ TokenPriceDeviationPPB: 5e7,
+ InflightCacheExpiry: *config.MustNewDuration(23456 * time.Second),
+ },
+ },
+ "fails decoding when all fields present but with 0 values": {
+ want: v1_2_0.JSONCommitOffchainConfig{
+ SourceFinalityDepth: 0,
+ DestFinalityDepth: 0,
+ GasPriceHeartBeat: *config.MustNewDuration(0),
+ DAGasPriceDeviationPPB: 0,
+ ExecGasPriceDeviationPPB: 0,
+ TokenPriceHeartBeat: *config.MustNewDuration(0),
+ TokenPriceDeviationPPB: 0,
+ InflightCacheExpiry: *config.MustNewDuration(0),
+ },
+ expectErr: true,
+ },
+ "fails decoding when all fields are missing": {
+ want: v1_2_0.JSONCommitOffchainConfig{},
+ expectErr: true,
+ },
+ "fails decoding when some fields are missing": {
+ want: v1_2_0.JSONCommitOffchainConfig{
+ SourceFinalityDepth: 3,
+ GasPriceHeartBeat: *config.MustNewDuration(1 * time.Hour),
+ DAGasPriceDeviationPPB: 5e7,
+ ExecGasPriceDeviationPPB: 5e7,
+ TokenPriceHeartBeat: *config.MustNewDuration(1 * time.Hour),
+ TokenPriceDeviationPPB: 5e7,
+ },
+ expectErr: true,
+ },
+ }
+ for name, tc := range tests {
+ t.Run(name, func(t *testing.T) {
+ encode, err := ccipconfig.EncodeOffchainConfig(tc.want)
+ require.NoError(t, err)
+ got, err := ccipconfig.DecodeOffchainConfig[v1_2_0.JSONCommitOffchainConfig](encode)
+
+ if tc.expectErr {
+ require.ErrorContains(t, err, "must set")
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tc.want, got)
+ }
+ })
+ }
+}
+
+func TestCommitOnchainConfig(t *testing.T) {
+ tests := []struct {
+ name string
+ want ccipdata.CommitOnchainConfig
+ expectErr bool
+ }{
+ {
+ name: "encodes and decodes config with all fields set",
+ want: ccipdata.CommitOnchainConfig{
+ PriceRegistry: utils.RandomAddress(),
+ },
+ expectErr: false,
+ },
+ {
+ name: "encodes and fails decoding config with missing fields",
+ want: ccipdata.CommitOnchainConfig{},
+ expectErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ encoded, err := abihelpers.EncodeAbiStruct(tt.want)
+ require.NoError(t, err)
+
+ decoded, err := abihelpers.DecodeAbiStruct[ccipdata.CommitOnchainConfig](encoded)
+ if tt.expectErr {
+ require.ErrorContains(t, err, "must set")
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.want, decoded)
+ }
+ })
+ }
+}
+
+func TestCommitStoreReaders(t *testing.T) {
+ user, ec := newSim(t)
+ ctx := testutils.Context(t)
+ lggr := logger.Test(t)
+ lpOpts := logpoller.Opts{
+ PollPeriod: 100 * time.Millisecond,
+ FinalityDepth: 2,
+ BackfillBatchSize: 3,
+ RpcBatchSize: 2,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+ headTracker := headtracker.NewSimulatedHeadTracker(ec, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ if lpOpts.PollPeriod == 0 {
+ lpOpts.PollPeriod = 1 * time.Hour
+ }
+ lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, pgtest.NewSqlxDB(t), lggr), ec, lggr, headTracker, lpOpts)
+
+ // Deploy 2 commit store versions
+ onramp1 := utils.RandomAddress()
+ onramp2 := utils.RandomAddress()
+ // Report
+ rep := cciptypes.CommitStoreReport{
+ TokenPrices: []cciptypes.TokenPrice{{Token: ccipcalc.EvmAddrToGeneric(utils.RandomAddress()), Value: big.NewInt(1)}},
+ GasPrices: []cciptypes.GasPrice{{DestChainSelector: 1, Value: big.NewInt(1)}},
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 10},
+ MerkleRoot: common.HexToHash("0x1"),
+ }
+ er := big.NewInt(1)
+ armAddr, _, arm, err := mock_arm_contract.DeployMockARMContract(user, ec)
+ require.NoError(t, err)
+ addr, _, ch, err := commit_store_helper_1_0_0.DeployCommitStoreHelper(user, ec, commit_store_helper_1_0_0.CommitStoreStaticConfig{
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ SourceChainSelector: testutils.SimulatedChainID.Uint64(),
+ OnRamp: onramp1,
+ ArmProxy: armAddr,
+ })
+ require.NoError(t, err)
+ addr2, _, ch2, err := commit_store_helper_1_2_0.DeployCommitStoreHelper(user, ec, commit_store_helper_1_2_0.CommitStoreStaticConfig{
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ SourceChainSelector: testutils.SimulatedChainID.Uint64(),
+ OnRamp: onramp2,
+ ArmProxy: armAddr,
+ })
+ require.NoError(t, err)
+ commitAndGetBlockTs(ec) // Deploy these
+ pr, _, _, err := price_registry_1_0_0.DeployPriceRegistry(user, ec, []common.Address{addr}, nil, 1e6)
+ require.NoError(t, err)
+ pr2, _, _, err := price_registry_1_2_0.DeployPriceRegistry(user, ec, []common.Address{addr2}, nil, 1e6)
+ require.NoError(t, err)
+ commitAndGetBlockTs(ec) // Deploy these
+ ge := new(gasmocks.EvmFeeEstimator)
+ lm := new(rollupMocks.L1Oracle)
+ ge.On("L1Oracle").Return(lm)
+
+ maxGasPrice := big.NewInt(1e8)
+ c10r, err := factory.NewCommitStoreReader(lggr, factory.NewEvmVersionFinder(), ccipcalc.EvmAddrToGeneric(addr), ec, lp) // ge, maxGasPrice
+ require.NoError(t, err)
+ err = c10r.SetGasEstimator(ctx, ge)
+ require.NoError(t, err)
+ err = c10r.SetSourceMaxGasPrice(ctx, maxGasPrice)
+ require.NoError(t, err)
+ assert.Equal(t, reflect.TypeOf(c10r).String(), reflect.TypeOf(&v1_0_0.CommitStore{}).String())
+ c12r, err := factory.NewCommitStoreReader(lggr, factory.NewEvmVersionFinder(), ccipcalc.EvmAddrToGeneric(addr2), ec, lp)
+ require.NoError(t, err)
+ err = c12r.SetGasEstimator(ctx, ge)
+ require.NoError(t, err)
+ err = c12r.SetSourceMaxGasPrice(ctx, maxGasPrice)
+ require.NoError(t, err)
+ assert.Equal(t, reflect.TypeOf(c12r).String(), reflect.TypeOf(&v1_2_0.CommitStore{}).String())
+
+ // Apply config
+ signers := []common.Address{utils.RandomAddress(), utils.RandomAddress(), utils.RandomAddress(), utils.RandomAddress()}
+ transmitters := []common.Address{utils.RandomAddress(), utils.RandomAddress(), utils.RandomAddress(), utils.RandomAddress()}
+ onchainConfig, err := abihelpers.EncodeAbiStruct[ccipdata.CommitOnchainConfig](ccipdata.CommitOnchainConfig{
+ PriceRegistry: pr,
+ })
+ require.NoError(t, err)
+
+ sourceFinalityDepth := uint32(1)
+ destFinalityDepth := uint32(2)
+ commonOffchain := cciptypes.CommitOffchainConfig{
+ GasPriceDeviationPPB: 1e6,
+ GasPriceHeartBeat: 1 * time.Hour,
+ TokenPriceDeviationPPB: 1e6,
+ TokenPriceHeartBeat: 1 * time.Hour,
+ InflightCacheExpiry: 3 * time.Hour,
+ PriceReportingDisabled: false,
+ }
+ offchainConfig, err := ccipconfig.EncodeOffchainConfig[v1_0_0.CommitOffchainConfig](v1_0_0.CommitOffchainConfig{
+ SourceFinalityDepth: sourceFinalityDepth,
+ DestFinalityDepth: destFinalityDepth,
+ FeeUpdateHeartBeat: *config.MustNewDuration(commonOffchain.GasPriceHeartBeat),
+ FeeUpdateDeviationPPB: commonOffchain.GasPriceDeviationPPB,
+ InflightCacheExpiry: *config.MustNewDuration(commonOffchain.InflightCacheExpiry),
+ })
+ require.NoError(t, err)
+ _, err = ch.SetOCR2Config(user, signers, transmitters, 1, onchainConfig, 1, []byte{})
+ require.NoError(t, err)
+ onchainConfig2, err := abihelpers.EncodeAbiStruct[ccipdata.CommitOnchainConfig](ccipdata.CommitOnchainConfig{
+ PriceRegistry: pr2,
+ })
+ require.NoError(t, err)
+ offchainConfig2, err := ccipconfig.EncodeOffchainConfig[v1_2_0.JSONCommitOffchainConfig](v1_2_0.JSONCommitOffchainConfig{
+ SourceFinalityDepth: sourceFinalityDepth,
+ DestFinalityDepth: destFinalityDepth,
+ GasPriceHeartBeat: *config.MustNewDuration(commonOffchain.GasPriceHeartBeat),
+ DAGasPriceDeviationPPB: 1e7,
+ ExecGasPriceDeviationPPB: commonOffchain.GasPriceDeviationPPB,
+ TokenPriceDeviationPPB: commonOffchain.TokenPriceDeviationPPB,
+ TokenPriceHeartBeat: *config.MustNewDuration(commonOffchain.TokenPriceHeartBeat),
+ InflightCacheExpiry: *config.MustNewDuration(commonOffchain.InflightCacheExpiry),
+ })
+ require.NoError(t, err)
+ _, err = ch2.SetOCR2Config(user, signers, transmitters, 1, onchainConfig2, 1, []byte{})
+ require.NoError(t, err)
+ commitAndGetBlockTs(ec)
+
+ // Apply report
+ b, err := c10r.EncodeCommitReport(ctx, rep)
+ require.NoError(t, err)
+ _, err = ch.Report(user, b, er)
+ require.NoError(t, err)
+ b, err = c12r.EncodeCommitReport(ctx, rep)
+ require.NoError(t, err)
+ _, err = ch2.Report(user, b, er)
+ require.NoError(t, err)
+ commitAndGetBlockTs(ec)
+
+ // Capture all logs.
+ lp.PollAndSaveLogs(context.Background(), 1)
+
+ configs := map[string][][]byte{
+ ccipdata.V1_0_0: {onchainConfig, offchainConfig},
+ ccipdata.V1_2_0: {onchainConfig2, offchainConfig2},
+ }
+ crs := map[string]ccipdata.CommitStoreReader{
+ ccipdata.V1_0_0: c10r,
+ ccipdata.V1_2_0: c12r,
+ }
+ prs := map[string]common.Address{
+ ccipdata.V1_0_0: pr,
+ ccipdata.V1_2_0: pr2,
+ }
+ gasPrice := big.NewInt(10)
+ daPrice := big.NewInt(20)
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, assets.NewWei(maxGasPrice), (*common.Address)(nil)).Return(gas.EvmFee{Legacy: assets.NewWei(gasPrice)}, uint64(0), nil)
+ lm.On("GasPrice", mock.Anything).Return(assets.NewWei(daPrice), nil)
+
+ for v, cr := range crs {
+ cr := cr
+ t.Run("CommitStoreReader "+v, func(t *testing.T) {
+ // Static config.
+ cfg, err := cr.GetCommitStoreStaticConfig(context.Background())
+ require.NoError(t, err)
+ require.NotNil(t, cfg)
+
+ // Assert encoding
+ b, err := cr.EncodeCommitReport(ctx, rep)
+ require.NoError(t, err)
+ d, err := cr.DecodeCommitReport(ctx, b)
+ require.NoError(t, err)
+ assert.Equal(t, d, rep)
+
+ // Assert reading
+ latest, err := cr.GetLatestPriceEpochAndRound(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, er.Uint64(), latest)
+
+ // Assert cursing
+ down, err := cr.IsDown(context.Background())
+ require.NoError(t, err)
+ assert.False(t, down)
+ _, err = arm.VoteToCurse(user, [32]byte{})
+ require.NoError(t, err)
+ ec.Commit()
+ down, err = cr.IsDown(context.Background())
+ require.NoError(t, err)
+ assert.True(t, down)
+ _, err = arm.OwnerUnvoteToCurse0(user, nil)
+ require.NoError(t, err)
+ ec.Commit()
+
+ seqNr, err := cr.GetExpectedNextSequenceNumber(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, rep.Interval.Max+1, seqNr)
+
+ reps, err := cr.GetCommitReportMatchingSeqNum(context.Background(), rep.Interval.Max+1, 0)
+ require.NoError(t, err)
+ assert.Len(t, reps, 0)
+
+ reps, err = cr.GetCommitReportMatchingSeqNum(context.Background(), rep.Interval.Max, 0)
+ require.NoError(t, err)
+ require.Len(t, reps, 1)
+ assert.Equal(t, reps[0].Interval, rep.Interval)
+ assert.Equal(t, reps[0].MerkleRoot, rep.MerkleRoot)
+ assert.Equal(t, reps[0].GasPrices, rep.GasPrices)
+ assert.Equal(t, reps[0].TokenPrices, rep.TokenPrices)
+
+ reps, err = cr.GetCommitReportMatchingSeqNum(context.Background(), rep.Interval.Min, 0)
+ require.NoError(t, err)
+ require.Len(t, reps, 1)
+ assert.Equal(t, reps[0].Interval, rep.Interval)
+ assert.Equal(t, reps[0].MerkleRoot, rep.MerkleRoot)
+ assert.Equal(t, reps[0].GasPrices, rep.GasPrices)
+ assert.Equal(t, reps[0].TokenPrices, rep.TokenPrices)
+
+ reps, err = cr.GetCommitReportMatchingSeqNum(context.Background(), rep.Interval.Min-1, 0)
+ require.NoError(t, err)
+ require.Len(t, reps, 0)
+
+ // Sanity
+ reps, err = cr.GetAcceptedCommitReportsGteTimestamp(context.Background(), time.Unix(0, 0), 0)
+ require.NoError(t, err)
+ require.Len(t, reps, 1)
+ assert.Equal(t, reps[0].Interval, rep.Interval)
+ assert.Equal(t, reps[0].MerkleRoot, rep.MerkleRoot)
+ assert.Equal(t, reps[0].GasPrices, rep.GasPrices)
+ assert.Equal(t, reps[0].TokenPrices, rep.TokenPrices)
+
+ // Until we detect the config, we'll have empty offchain config
+ c1, err := cr.OffchainConfig(ctx)
+ require.NoError(t, err)
+ assert.Equal(t, c1, cciptypes.CommitOffchainConfig{})
+ newPr, err := cr.ChangeConfig(ctx, configs[v][0], configs[v][1])
+ require.NoError(t, err)
+ assert.Equal(t, ccipcalc.EvmAddrToGeneric(prs[v]), newPr)
+
+ c2, err := cr.OffchainConfig(ctx)
+ require.NoError(t, err)
+ assert.Equal(t, commonOffchain, c2)
+ // We should be able to query for gas prices now.
+ gpe, err := cr.GasPriceEstimator(ctx)
+ require.NoError(t, err)
+ gp, err := gpe.GetGasPrice(context.Background())
+ require.NoError(t, err)
+ assert.True(t, gp.Cmp(big.NewInt(0)) > 0)
+ })
+ }
+}
+
+func TestNewCommitStoreReader(t *testing.T) {
+ var tt = []struct {
+ typeAndVersion string
+ expectedErr string
+ }{
+ {
+ typeAndVersion: "blah",
+ expectedErr: "unable to read type and version: invalid type and version blah",
+ },
+ {
+ typeAndVersion: "EVM2EVMOffRamp 1.0.0",
+ expectedErr: "expected CommitStore got EVM2EVMOffRamp",
+ },
+ {
+ typeAndVersion: "CommitStore 1.2.0",
+ expectedErr: "",
+ },
+ {
+ typeAndVersion: "CommitStore 2.0.0",
+ expectedErr: "unsupported commit store version 2.0.0",
+ },
+ }
+ for _, tc := range tt {
+ t.Run(tc.typeAndVersion, func(t *testing.T) {
+ b, err := utils.ABIEncode(`[{"type":"string"}]`, tc.typeAndVersion)
+ require.NoError(t, err)
+ c := evmclientmocks.NewClient(t)
+ c.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(b, nil)
+ addr := ccipcalc.EvmAddrToGeneric(utils.RandomAddress())
+ lp := lpmocks.NewLogPoller(t)
+ if tc.expectedErr == "" {
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil)
+ }
+ _, err = factory.NewCommitStoreReader(logger.Test(t), factory.NewEvmVersionFinder(), addr, c, lp)
+ if tc.expectedErr != "" {
+ require.EqualError(t, err, tc.expectedErr)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/commit_store.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/commit_store.go
new file mode 100644
index 00000000000..6ab9b52fc58
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/commit_store.go
@@ -0,0 +1,121 @@
+package factory
+
+import (
+ "github.com/Masterminds/semver/v3"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0"
+)
+
+func NewCommitStoreReader(lggr logger.Logger, versionFinder VersionFinder, address cciptypes.Address, ec client.Client, lp logpoller.LogPoller) (ccipdata.CommitStoreReader, error) {
+ return initOrCloseCommitStoreReader(lggr, versionFinder, address, ec, lp, false)
+}
+
+func CloseCommitStoreReader(lggr logger.Logger, versionFinder VersionFinder, address cciptypes.Address, ec client.Client, lp logpoller.LogPoller) error {
+ _, err := initOrCloseCommitStoreReader(lggr, versionFinder, address, ec, lp, true)
+ return err
+}
+
+func initOrCloseCommitStoreReader(lggr logger.Logger, versionFinder VersionFinder, address cciptypes.Address, ec client.Client, lp logpoller.LogPoller, closeReader bool) (ccipdata.CommitStoreReader, error) {
+ contractType, version, err := versionFinder.TypeAndVersion(address, ec)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to read type and version")
+ }
+ if contractType != ccipconfig.CommitStore {
+ return nil, errors.Errorf("expected %v got %v", ccipconfig.CommitStore, contractType)
+ }
+
+ evmAddr, err := ccipcalc.GenericAddrToEvm(address)
+ if err != nil {
+ return nil, err
+ }
+
+ lggr.Infow("Initializing CommitStore Reader", "version", version.String())
+
+ switch version.String() {
+ case ccipdata.V1_0_0, ccipdata.V1_1_0: // Versions are identical
+ cs, err := v1_0_0.NewCommitStore(lggr, evmAddr, ec, lp)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, cs.Close()
+ }
+ return cs, cs.RegisterFilters()
+ case ccipdata.V1_2_0:
+ cs, err := v1_2_0.NewCommitStore(lggr, evmAddr, ec, lp)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, cs.Close()
+ }
+ return cs, cs.RegisterFilters()
+ case ccipdata.V1_5_0:
+ cs, err := v1_5_0.NewCommitStore(lggr, evmAddr, ec, lp)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, cs.Close()
+ }
+ return cs, cs.RegisterFilters()
+ default:
+ return nil, errors.Errorf("unsupported commit store version %v", version.String())
+ }
+}
+
+func CommitReportToEthTxMeta(typ ccipconfig.ContractType, ver semver.Version) (func(report []byte) (*txmgr.TxMeta, error), error) {
+ if typ != ccipconfig.CommitStore {
+ return nil, errors.Errorf("expected %v got %v", ccipconfig.CommitStore, typ)
+ }
+ switch ver.String() {
+ case ccipdata.V1_0_0, ccipdata.V1_1_0:
+ commitStoreABI := abihelpers.MustParseABI(commit_store_1_0_0.CommitStoreABI)
+ return func(report []byte) (*txmgr.TxMeta, error) {
+ commitReport, err := v1_0_0.DecodeCommitReport(abihelpers.MustGetEventInputs(v1_0_0.ReportAccepted, commitStoreABI), report)
+ if err != nil {
+ return nil, err
+ }
+ return commitReportToEthTxMeta(commitReport)
+ }, nil
+ case ccipdata.V1_2_0, ccipdata.V1_5_0:
+ commitStoreABI := abihelpers.MustParseABI(commit_store.CommitStoreABI)
+ return func(report []byte) (*txmgr.TxMeta, error) {
+ commitReport, err := v1_2_0.DecodeCommitReport(abihelpers.MustGetEventInputs(v1_0_0.ReportAccepted, commitStoreABI), report)
+ if err != nil {
+ return nil, err
+ }
+ return commitReportToEthTxMeta(commitReport)
+ }, nil
+ default:
+ return nil, errors.Errorf("got unexpected version %v", ver.String())
+ }
+}
+
+// CommitReportToEthTxMeta generates a txmgr.EthTxMeta from the given commit report.
+// sequence numbers of the committed messages will be added to tx metadata
+func commitReportToEthTxMeta(commitReport cciptypes.CommitStoreReport) (*txmgr.TxMeta, error) {
+ n := (commitReport.Interval.Max - commitReport.Interval.Min) + 1
+ seqRange := make([]uint64, n)
+ for i := uint64(0); i < n; i++ {
+ seqRange[i] = i + commitReport.Interval.Min
+ }
+ return &txmgr.TxMeta{
+ SeqNumbers: seqRange,
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/commit_store_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/commit_store_test.go
new file mode 100644
index 00000000000..ae6b9977944
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/commit_store_test.go
@@ -0,0 +1,37 @@
+package factory
+
+import (
+ "testing"
+
+ "github.com/Masterminds/semver/v3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+)
+
+func TestCommitStore(t *testing.T) {
+ for _, versionStr := range []string{ccipdata.V1_0_0, ccipdata.V1_2_0} {
+ lggr := logger.Test(t)
+ addr := cciptypes.Address(utils.RandomAddress().String())
+ lp := mocks2.NewLogPoller(t)
+
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil)
+ versionFinder := newMockVersionFinder(ccipconfig.CommitStore, *semver.MustParse(versionStr), nil)
+ _, err := NewCommitStoreReader(lggr, versionFinder, addr, nil, lp)
+ assert.NoError(t, err)
+
+ expFilterName := logpoller.FilterName(v1_0_0.EXEC_REPORT_ACCEPTS, addr)
+ lp.On("UnregisterFilter", mock.Anything, expFilterName).Return(nil)
+ err = CloseCommitStoreReader(lggr, versionFinder, addr, nil, lp)
+ assert.NoError(t, err)
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp.go
new file mode 100644
index 00000000000..3c8d7182d42
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp.go
@@ -0,0 +1,125 @@
+package factory
+
+import (
+ "context"
+ "math/big"
+
+ "github.com/Masterminds/semver/v3"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0"
+)
+
+func NewOffRampReader(lggr logger.Logger, versionFinder VersionFinder, addr cciptypes.Address, destClient client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int, registerFilters bool) (ccipdata.OffRampReader, error) {
+ return initOrCloseOffRampReader(lggr, versionFinder, addr, destClient, lp, estimator, destMaxGasPrice, false, registerFilters)
+}
+
+func CloseOffRampReader(lggr logger.Logger, versionFinder VersionFinder, addr cciptypes.Address, destClient client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int) error {
+ _, err := initOrCloseOffRampReader(lggr, versionFinder, addr, destClient, lp, estimator, destMaxGasPrice, true, false)
+ return err
+}
+
+func initOrCloseOffRampReader(lggr logger.Logger, versionFinder VersionFinder, addr cciptypes.Address, destClient client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int, closeReader bool, registerFilters bool) (ccipdata.OffRampReader, error) {
+ contractType, version, err := versionFinder.TypeAndVersion(addr, destClient)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to read type and version")
+ }
+ if contractType != ccipconfig.EVM2EVMOffRamp {
+ return nil, errors.Errorf("expected %v got %v", ccipconfig.EVM2EVMOffRamp, contractType)
+ }
+
+ evmAddr, err := ccipcalc.GenericAddrToEvm(addr)
+ if err != nil {
+ return nil, err
+ }
+
+ lggr.Infow("Initializing OffRamp Reader", "version", version.String(), "destMaxGasPrice", destMaxGasPrice.String())
+
+ switch version.String() {
+ case ccipdata.V1_0_0, ccipdata.V1_1_0:
+ offRamp, err := v1_0_0.NewOffRamp(lggr, evmAddr, destClient, lp, estimator, destMaxGasPrice)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, offRamp.Close()
+ }
+ return offRamp, offRamp.RegisterFilters()
+ case ccipdata.V1_2_0:
+ offRamp, err := v1_2_0.NewOffRamp(lggr, evmAddr, destClient, lp, estimator, destMaxGasPrice)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, offRamp.Close()
+ }
+ return offRamp, offRamp.RegisterFilters()
+ case ccipdata.V1_5_0:
+ offRamp, err := v1_5_0.NewOffRamp(lggr, evmAddr, destClient, lp, estimator, destMaxGasPrice)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, offRamp.Close()
+ }
+ return offRamp, offRamp.RegisterFilters()
+ default:
+ return nil, errors.Errorf("unsupported offramp version %v", version.String())
+ }
+ // TODO can validate it pointing to the correct version
+}
+
+func ExecReportToEthTxMeta(ctx context.Context, typ ccipconfig.ContractType, ver semver.Version) (func(report []byte) (*txmgr.TxMeta, error), error) {
+ if typ != ccipconfig.EVM2EVMOffRamp {
+ return nil, errors.Errorf("expected %v got %v", ccipconfig.EVM2EVMOffRamp, typ)
+ }
+ switch ver.String() {
+ case ccipdata.V1_0_0, ccipdata.V1_1_0:
+ offRampABI := abihelpers.MustParseABI(evm_2_evm_offramp_1_0_0.EVM2EVMOffRampABI)
+ return func(report []byte) (*txmgr.TxMeta, error) {
+ execReport, err := v1_0_0.DecodeExecReport(ctx, abihelpers.MustGetMethodInputs(ccipdata.ManuallyExecute, offRampABI)[:1], report)
+ if err != nil {
+ return nil, err
+ }
+ return execReportToEthTxMeta(execReport)
+ }, nil
+ case ccipdata.V1_2_0, ccipdata.V1_5_0:
+ offRampABI := abihelpers.MustParseABI(evm_2_evm_offramp.EVM2EVMOffRampABI)
+ return func(report []byte) (*txmgr.TxMeta, error) {
+ execReport, err := v1_2_0.DecodeExecReport(ctx, abihelpers.MustGetMethodInputs(ccipdata.ManuallyExecute, offRampABI)[:1], report)
+ if err != nil {
+ return nil, err
+ }
+ return execReportToEthTxMeta(execReport)
+ }, nil
+ default:
+ return nil, errors.Errorf("got unexpected version %v", ver.String())
+ }
+}
+
+func execReportToEthTxMeta(execReport cciptypes.ExecReport) (*txmgr.TxMeta, error) {
+ msgIDs := make([]string, len(execReport.Messages))
+ for i, msg := range execReport.Messages {
+ msgIDs[i] = hexutil.Encode(msg.MessageID[:])
+ }
+
+ return &txmgr.TxMeta{
+ MessageIDs: msgIDs,
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp_test.go
new file mode 100644
index 00000000000..145d00bc134
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/offramp_test.go
@@ -0,0 +1,44 @@
+package factory
+
+import (
+ "testing"
+
+ "github.com/Masterminds/semver/v3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+)
+
+func TestOffRamp(t *testing.T) {
+ for _, versionStr := range []string{ccipdata.V1_0_0, ccipdata.V1_2_0} {
+ lggr := logger.Test(t)
+ addr := cciptypes.Address(utils.RandomAddress().String())
+ lp := mocks2.NewLogPoller(t)
+
+ expFilterNames := []string{
+ logpoller.FilterName(v1_0_0.EXEC_EXECUTION_STATE_CHANGES, addr),
+ logpoller.FilterName(v1_0_0.EXEC_TOKEN_POOL_ADDED, addr),
+ logpoller.FilterName(v1_0_0.EXEC_TOKEN_POOL_REMOVED, addr),
+ }
+ versionFinder := newMockVersionFinder(ccipconfig.EVM2EVMOffRamp, *semver.MustParse(versionStr), nil)
+
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil).Times(len(expFilterNames))
+ _, err := NewOffRampReader(lggr, versionFinder, addr, nil, lp, nil, nil, true)
+ assert.NoError(t, err)
+
+ for _, f := range expFilterNames {
+ lp.On("UnregisterFilter", mock.Anything, f).Return(nil)
+ }
+ err = CloseOffRampReader(lggr, versionFinder, addr, nil, lp, nil, nil)
+ assert.NoError(t, err)
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/onramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/onramp.go
new file mode 100644
index 00000000000..cb9e0015ca5
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/onramp.go
@@ -0,0 +1,88 @@
+package factory
+
+import (
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_1_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0"
+)
+
+// NewOnRampReader determines the appropriate version of the onramp and returns a reader for it
+func NewOnRampReader(lggr logger.Logger, versionFinder VersionFinder, sourceSelector, destSelector uint64, onRampAddress cciptypes.Address, sourceLP logpoller.LogPoller, source client.Client) (ccipdata.OnRampReader, error) {
+ return initOrCloseOnRampReader(lggr, versionFinder, sourceSelector, destSelector, onRampAddress, sourceLP, source, false)
+}
+
+func CloseOnRampReader(lggr logger.Logger, versionFinder VersionFinder, sourceSelector, destSelector uint64, onRampAddress cciptypes.Address, sourceLP logpoller.LogPoller, source client.Client) error {
+ _, err := initOrCloseOnRampReader(lggr, versionFinder, sourceSelector, destSelector, onRampAddress, sourceLP, source, true)
+ return err
+}
+
+func initOrCloseOnRampReader(lggr logger.Logger, versionFinder VersionFinder, sourceSelector, destSelector uint64, onRampAddress cciptypes.Address, sourceLP logpoller.LogPoller, source client.Client, closeReader bool) (ccipdata.OnRampReader, error) {
+ contractType, version, err := versionFinder.TypeAndVersion(onRampAddress, source)
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to read type and version")
+ }
+ if contractType != ccipconfig.EVM2EVMOnRamp {
+ return nil, errors.Errorf("expected %v got %v", ccipconfig.EVM2EVMOnRamp, contractType)
+ }
+
+ onRampAddrEvm, err := ccipcalc.GenericAddrToEvm(onRampAddress)
+ if err != nil {
+ return nil, err
+ }
+
+ lggr.Infof("Initializing onRamp for version %v", version.String())
+
+ switch version.String() {
+ case ccipdata.V1_0_0:
+ onRamp, err := v1_0_0.NewOnRamp(lggr, sourceSelector, destSelector, onRampAddrEvm, sourceLP, source)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, onRamp.Close()
+ }
+ return onRamp, onRamp.RegisterFilters()
+ case ccipdata.V1_1_0:
+ onRamp, err := v1_1_0.NewOnRamp(lggr, sourceSelector, destSelector, onRampAddrEvm, sourceLP, source)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, onRamp.Close()
+ }
+ return onRamp, onRamp.RegisterFilters()
+ case ccipdata.V1_2_0:
+ onRamp, err := v1_2_0.NewOnRamp(lggr, sourceSelector, destSelector, onRampAddrEvm, sourceLP, source)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, onRamp.Close()
+ }
+ return onRamp, onRamp.RegisterFilters()
+ case ccipdata.V1_5_0:
+ onRamp, err := v1_5_0.NewOnRamp(lggr, sourceSelector, destSelector, onRampAddrEvm, sourceLP, source)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, onRamp.Close()
+ }
+ return onRamp, onRamp.RegisterFilters()
+ // Adding a new version?
+ // Please update the public factory function in leafer.go if the new version updates the leaf hash function.
+ default:
+ return nil, errors.Errorf("unsupported onramp version %v", version.String())
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/onramp_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/onramp_test.go
new file mode 100644
index 00000000000..e3013e36298
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/onramp_test.go
@@ -0,0 +1,45 @@
+package factory
+
+import (
+ "testing"
+
+ "github.com/Masterminds/semver/v3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+func TestOnRamp(t *testing.T) {
+ for _, versionStr := range []string{ccipdata.V1_0_0, ccipdata.V1_1_0, ccipdata.V1_2_0, ccipdata.V1_5_0} {
+ lggr := logger.Test(t)
+ addr := cciptypes.Address(utils.RandomAddress().String())
+ lp := mocks2.NewLogPoller(t)
+
+ sourceSelector := uint64(1000)
+ destSelector := uint64(2000)
+
+ expFilterNames := []string{
+ logpoller.FilterName(ccipdata.COMMIT_CCIP_SENDS, addr),
+ logpoller.FilterName(ccipdata.CONFIG_CHANGED, addr),
+ }
+ versionFinder := newMockVersionFinder(ccipconfig.EVM2EVMOnRamp, *semver.MustParse(versionStr), nil)
+
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil).Times(len(expFilterNames))
+ _, err := NewOnRampReader(lggr, versionFinder, sourceSelector, destSelector, addr, lp, nil)
+ assert.NoError(t, err)
+
+ for _, f := range expFilterNames {
+ lp.On("UnregisterFilter", mock.Anything, f).Return(nil)
+ }
+ err = CloseOnRampReader(lggr, versionFinder, sourceSelector, destSelector, addr, lp, nil)
+ assert.NoError(t, err)
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/price_registry.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/price_registry.go
new file mode 100644
index 00000000000..7f08b04d486
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/price_registry.go
@@ -0,0 +1,82 @@
+package factory
+
+import (
+ "context"
+
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+)
+
+// NewPriceRegistryReader determines the appropriate version of the price registry and returns a reader for it.
+func NewPriceRegistryReader(ctx context.Context, lggr logger.Logger, versionFinder VersionFinder, priceRegistryAddress cciptypes.Address, lp logpoller.LogPoller, cl client.Client) (ccipdata.PriceRegistryReader, error) {
+ return initOrClosePriceRegistryReader(ctx, lggr, versionFinder, priceRegistryAddress, lp, cl, false)
+}
+
+func ClosePriceRegistryReader(ctx context.Context, lggr logger.Logger, versionFinder VersionFinder, priceRegistryAddress cciptypes.Address, lp logpoller.LogPoller, cl client.Client) error {
+ _, err := initOrClosePriceRegistryReader(ctx, lggr, versionFinder, priceRegistryAddress, lp, cl, true)
+ return err
+}
+
+func initOrClosePriceRegistryReader(ctx context.Context, lggr logger.Logger, versionFinder VersionFinder, priceRegistryAddress cciptypes.Address, lp logpoller.LogPoller, cl client.Client, closeReader bool) (ccipdata.PriceRegistryReader, error) {
+ registerFilters := !closeReader
+
+ priceRegistryEvmAddr, err := ccipcalc.GenericAddrToEvm(priceRegistryAddress)
+ if err != nil {
+ return nil, err
+ }
+
+ contractType, version, err := versionFinder.TypeAndVersion(priceRegistryAddress, cl)
+ isV1_0_0 := ccipcommon.IsTxRevertError(err) || (contractType == ccipconfig.PriceRegistry && version.String() == ccipdata.V1_0_0)
+ if isV1_0_0 {
+ lggr.Infof("Assuming %v is 1.0.0 price registry, got %v", priceRegistryEvmAddr, err)
+ // Unfortunately the v1 price registry doesn't have a method to get the version so assume if it reverts its v1.
+ pr, err2 := v1_0_0.NewPriceRegistry(lggr, priceRegistryEvmAddr, lp, cl, registerFilters)
+ if err2 != nil {
+ return nil, err2
+ }
+ if closeReader {
+ return nil, pr.Close()
+ }
+ return pr, nil
+ }
+ if err != nil {
+ return nil, errors.Wrapf(err, "unable to read type and version")
+ }
+
+ if contractType != ccipconfig.PriceRegistry {
+ return nil, errors.Errorf("expected %v got %v", ccipconfig.PriceRegistry, contractType)
+ }
+ switch version.String() {
+ case ccipdata.V1_2_0:
+ pr, err := v1_2_0.NewPriceRegistry(lggr, priceRegistryEvmAddr, lp, cl, registerFilters)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, pr.Close()
+ }
+ return pr, nil
+ case ccipdata.V1_6_0:
+ pr, err := v1_2_0.NewPriceRegistry(lggr, priceRegistryEvmAddr, lp, cl, registerFilters)
+ if err != nil {
+ return nil, err
+ }
+ if closeReader {
+ return nil, pr.Close()
+ }
+ return pr, nil
+ default:
+ return nil, errors.Errorf("unsupported price registry version %v", version.String())
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/price_registry_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/price_registry_test.go
new file mode 100644
index 00000000000..f388c5cb9a3
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/price_registry_test.go
@@ -0,0 +1,46 @@
+package factory
+
+import (
+ "testing"
+
+ "github.com/Masterminds/semver/v3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+func TestPriceRegistry(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ for _, versionStr := range []string{ccipdata.V1_0_0, ccipdata.V1_2_0} {
+ lggr := logger.Test(t)
+ addr := cciptypes.Address(utils.RandomAddress().String())
+ lp := mocks2.NewLogPoller(t)
+
+ expFilterNames := []string{
+ logpoller.FilterName(ccipdata.COMMIT_PRICE_UPDATES, addr),
+ logpoller.FilterName(ccipdata.FEE_TOKEN_ADDED, addr),
+ logpoller.FilterName(ccipdata.FEE_TOKEN_REMOVED, addr),
+ }
+ versionFinder := newMockVersionFinder(ccipconfig.PriceRegistry, *semver.MustParse(versionStr), nil)
+
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil).Times(len(expFilterNames))
+ _, err := NewPriceRegistryReader(ctx, lggr, versionFinder, addr, lp, nil)
+ assert.NoError(t, err)
+
+ for _, f := range expFilterNames {
+ lp.On("UnregisterFilter", mock.Anything, f).Return(nil)
+ }
+ err = ClosePriceRegistryReader(ctx, lggr, versionFinder, addr, lp, nil)
+ assert.NoError(t, err)
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/versionfinder.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/versionfinder.go
new file mode 100644
index 00000000000..ac16fc4df2f
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/factory/versionfinder.go
@@ -0,0 +1,44 @@
+package factory
+
+import (
+ "github.com/Masterminds/semver/v3"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+// VersionFinder accepts a contract address and a client and performs an on-chain call to
+// determine the contract type.
+type VersionFinder interface {
+ TypeAndVersion(addr cciptypes.Address, client bind.ContractBackend) (config.ContractType, semver.Version, error)
+}
+
+type EvmVersionFinder struct{}
+
+func NewEvmVersionFinder() EvmVersionFinder {
+ return EvmVersionFinder{}
+}
+
+func (e EvmVersionFinder) TypeAndVersion(addr cciptypes.Address, client bind.ContractBackend) (config.ContractType, semver.Version, error) {
+ evmAddr, err := ccipcalc.GenericAddrToEvm(addr)
+ if err != nil {
+ return "", semver.Version{}, err
+ }
+ return config.TypeAndVersion(evmAddr, client)
+}
+
+type mockVersionFinder struct {
+ typ config.ContractType
+ version semver.Version
+ err error
+}
+
+func newMockVersionFinder(typ config.ContractType, version semver.Version, err error) *mockVersionFinder {
+ return &mockVersionFinder{typ: typ, version: version, err: err}
+}
+
+func (m mockVersionFinder) TypeAndVersion(addr cciptypes.Address, client bind.ContractBackend) (config.ContractType, semver.Version, error) {
+ return m.typ, m.version, m.err
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/commit_store_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/commit_store_reader_mock.go
new file mode 100644
index 00000000000..f383a87a8a9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/commit_store_reader_mock.go
@@ -0,0 +1,985 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ big "math/big"
+
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ context "context"
+
+ gas "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+
+ mock "github.com/stretchr/testify/mock"
+
+ time "time"
+)
+
+// CommitStoreReader is an autogenerated mock type for the CommitStoreReader type
+type CommitStoreReader struct {
+ mock.Mock
+}
+
+type CommitStoreReader_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *CommitStoreReader) EXPECT() *CommitStoreReader_Expecter {
+ return &CommitStoreReader_Expecter{mock: &_m.Mock}
+}
+
+// ChangeConfig provides a mock function with given fields: ctx, onchainConfig, offchainConfig
+func (_m *CommitStoreReader) ChangeConfig(ctx context.Context, onchainConfig []byte, offchainConfig []byte) (ccip.Address, error) {
+ ret := _m.Called(ctx, onchainConfig, offchainConfig)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ChangeConfig")
+ }
+
+ var r0 ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []byte, []byte) (ccip.Address, error)); ok {
+ return rf(ctx, onchainConfig, offchainConfig)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []byte, []byte) ccip.Address); ok {
+ r0 = rf(ctx, onchainConfig, offchainConfig)
+ } else {
+ r0 = ret.Get(0).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []byte, []byte) error); ok {
+ r1 = rf(ctx, onchainConfig, offchainConfig)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_ChangeConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ChangeConfig'
+type CommitStoreReader_ChangeConfig_Call struct {
+ *mock.Call
+}
+
+// ChangeConfig is a helper method to define mock.On call
+// - ctx context.Context
+// - onchainConfig []byte
+// - offchainConfig []byte
+func (_e *CommitStoreReader_Expecter) ChangeConfig(ctx interface{}, onchainConfig interface{}, offchainConfig interface{}) *CommitStoreReader_ChangeConfig_Call {
+ return &CommitStoreReader_ChangeConfig_Call{Call: _e.mock.On("ChangeConfig", ctx, onchainConfig, offchainConfig)}
+}
+
+func (_c *CommitStoreReader_ChangeConfig_Call) Run(run func(ctx context.Context, onchainConfig []byte, offchainConfig []byte)) *CommitStoreReader_ChangeConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]byte), args[2].([]byte))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_ChangeConfig_Call) Return(_a0 ccip.Address, _a1 error) *CommitStoreReader_ChangeConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_ChangeConfig_Call) RunAndReturn(run func(context.Context, []byte, []byte) (ccip.Address, error)) *CommitStoreReader_ChangeConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Close provides a mock function with given fields:
+func (_m *CommitStoreReader) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CommitStoreReader_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type CommitStoreReader_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *CommitStoreReader_Expecter) Close() *CommitStoreReader_Close_Call {
+ return &CommitStoreReader_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *CommitStoreReader_Close_Call) Run(run func()) *CommitStoreReader_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_Close_Call) Return(_a0 error) *CommitStoreReader_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *CommitStoreReader_Close_Call) RunAndReturn(run func() error) *CommitStoreReader_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// DecodeCommitReport provides a mock function with given fields: ctx, report
+func (_m *CommitStoreReader) DecodeCommitReport(ctx context.Context, report []byte) (ccip.CommitStoreReport, error) {
+ ret := _m.Called(ctx, report)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DecodeCommitReport")
+ }
+
+ var r0 ccip.CommitStoreReport
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) (ccip.CommitStoreReport, error)); ok {
+ return rf(ctx, report)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) ccip.CommitStoreReport); ok {
+ r0 = rf(ctx, report)
+ } else {
+ r0 = ret.Get(0).(ccip.CommitStoreReport)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+ r1 = rf(ctx, report)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_DecodeCommitReport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DecodeCommitReport'
+type CommitStoreReader_DecodeCommitReport_Call struct {
+ *mock.Call
+}
+
+// DecodeCommitReport is a helper method to define mock.On call
+// - ctx context.Context
+// - report []byte
+func (_e *CommitStoreReader_Expecter) DecodeCommitReport(ctx interface{}, report interface{}) *CommitStoreReader_DecodeCommitReport_Call {
+ return &CommitStoreReader_DecodeCommitReport_Call{Call: _e.mock.On("DecodeCommitReport", ctx, report)}
+}
+
+func (_c *CommitStoreReader_DecodeCommitReport_Call) Run(run func(ctx context.Context, report []byte)) *CommitStoreReader_DecodeCommitReport_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]byte))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_DecodeCommitReport_Call) Return(_a0 ccip.CommitStoreReport, _a1 error) *CommitStoreReader_DecodeCommitReport_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_DecodeCommitReport_Call) RunAndReturn(run func(context.Context, []byte) (ccip.CommitStoreReport, error)) *CommitStoreReader_DecodeCommitReport_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// EncodeCommitReport provides a mock function with given fields: ctx, report
+func (_m *CommitStoreReader) EncodeCommitReport(ctx context.Context, report ccip.CommitStoreReport) ([]byte, error) {
+ ret := _m.Called(ctx, report)
+
+ if len(ret) == 0 {
+ panic("no return value specified for EncodeCommitReport")
+ }
+
+ var r0 []byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.CommitStoreReport) ([]byte, error)); ok {
+ return rf(ctx, report)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.CommitStoreReport) []byte); ok {
+ r0 = rf(ctx, report)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, ccip.CommitStoreReport) error); ok {
+ r1 = rf(ctx, report)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_EncodeCommitReport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EncodeCommitReport'
+type CommitStoreReader_EncodeCommitReport_Call struct {
+ *mock.Call
+}
+
+// EncodeCommitReport is a helper method to define mock.On call
+// - ctx context.Context
+// - report ccip.CommitStoreReport
+func (_e *CommitStoreReader_Expecter) EncodeCommitReport(ctx interface{}, report interface{}) *CommitStoreReader_EncodeCommitReport_Call {
+ return &CommitStoreReader_EncodeCommitReport_Call{Call: _e.mock.On("EncodeCommitReport", ctx, report)}
+}
+
+func (_c *CommitStoreReader_EncodeCommitReport_Call) Run(run func(ctx context.Context, report ccip.CommitStoreReport)) *CommitStoreReader_EncodeCommitReport_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(ccip.CommitStoreReport))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_EncodeCommitReport_Call) Return(_a0 []byte, _a1 error) *CommitStoreReader_EncodeCommitReport_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_EncodeCommitReport_Call) RunAndReturn(run func(context.Context, ccip.CommitStoreReport) ([]byte, error)) *CommitStoreReader_EncodeCommitReport_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GasPriceEstimator provides a mock function with given fields: ctx
+func (_m *CommitStoreReader) GasPriceEstimator(ctx context.Context) (ccip.GasPriceEstimatorCommit, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GasPriceEstimator")
+ }
+
+ var r0 ccip.GasPriceEstimatorCommit
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.GasPriceEstimatorCommit, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.GasPriceEstimatorCommit); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(ccip.GasPriceEstimatorCommit)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_GasPriceEstimator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GasPriceEstimator'
+type CommitStoreReader_GasPriceEstimator_Call struct {
+ *mock.Call
+}
+
+// GasPriceEstimator is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *CommitStoreReader_Expecter) GasPriceEstimator(ctx interface{}) *CommitStoreReader_GasPriceEstimator_Call {
+ return &CommitStoreReader_GasPriceEstimator_Call{Call: _e.mock.On("GasPriceEstimator", ctx)}
+}
+
+func (_c *CommitStoreReader_GasPriceEstimator_Call) Run(run func(ctx context.Context)) *CommitStoreReader_GasPriceEstimator_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_GasPriceEstimator_Call) Return(_a0 ccip.GasPriceEstimatorCommit, _a1 error) *CommitStoreReader_GasPriceEstimator_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_GasPriceEstimator_Call) RunAndReturn(run func(context.Context) (ccip.GasPriceEstimatorCommit, error)) *CommitStoreReader_GasPriceEstimator_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetAcceptedCommitReportsGteTimestamp provides a mock function with given fields: ctx, ts, confirmations
+func (_m *CommitStoreReader) GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confirmations int) ([]ccip.CommitStoreReportWithTxMeta, error) {
+ ret := _m.Called(ctx, ts, confirmations)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetAcceptedCommitReportsGteTimestamp")
+ }
+
+ var r0 []ccip.CommitStoreReportWithTxMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, time.Time, int) ([]ccip.CommitStoreReportWithTxMeta, error)); ok {
+ return rf(ctx, ts, confirmations)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, time.Time, int) []ccip.CommitStoreReportWithTxMeta); ok {
+ r0 = rf(ctx, ts, confirmations)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.CommitStoreReportWithTxMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, time.Time, int) error); ok {
+ r1 = rf(ctx, ts, confirmations)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAcceptedCommitReportsGteTimestamp'
+type CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call struct {
+ *mock.Call
+}
+
+// GetAcceptedCommitReportsGteTimestamp is a helper method to define mock.On call
+// - ctx context.Context
+// - ts time.Time
+// - confirmations int
+func (_e *CommitStoreReader_Expecter) GetAcceptedCommitReportsGteTimestamp(ctx interface{}, ts interface{}, confirmations interface{}) *CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call {
+ return &CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call{Call: _e.mock.On("GetAcceptedCommitReportsGteTimestamp", ctx, ts, confirmations)}
+}
+
+func (_c *CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call) Run(run func(ctx context.Context, ts time.Time, confirmations int)) *CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(time.Time), args[2].(int))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call) Return(_a0 []ccip.CommitStoreReportWithTxMeta, _a1 error) *CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call) RunAndReturn(run func(context.Context, time.Time, int) ([]ccip.CommitStoreReportWithTxMeta, error)) *CommitStoreReader_GetAcceptedCommitReportsGteTimestamp_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetCommitReportMatchingSeqNum provides a mock function with given fields: ctx, seqNum, confirmations
+func (_m *CommitStoreReader) GetCommitReportMatchingSeqNum(ctx context.Context, seqNum uint64, confirmations int) ([]ccip.CommitStoreReportWithTxMeta, error) {
+ ret := _m.Called(ctx, seqNum, confirmations)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetCommitReportMatchingSeqNum")
+ }
+
+ var r0 []ccip.CommitStoreReportWithTxMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, int) ([]ccip.CommitStoreReportWithTxMeta, error)); ok {
+ return rf(ctx, seqNum, confirmations)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, int) []ccip.CommitStoreReportWithTxMeta); ok {
+ r0 = rf(ctx, seqNum, confirmations)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.CommitStoreReportWithTxMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint64, int) error); ok {
+ r1 = rf(ctx, seqNum, confirmations)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_GetCommitReportMatchingSeqNum_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCommitReportMatchingSeqNum'
+type CommitStoreReader_GetCommitReportMatchingSeqNum_Call struct {
+ *mock.Call
+}
+
+// GetCommitReportMatchingSeqNum is a helper method to define mock.On call
+// - ctx context.Context
+// - seqNum uint64
+// - confirmations int
+func (_e *CommitStoreReader_Expecter) GetCommitReportMatchingSeqNum(ctx interface{}, seqNum interface{}, confirmations interface{}) *CommitStoreReader_GetCommitReportMatchingSeqNum_Call {
+ return &CommitStoreReader_GetCommitReportMatchingSeqNum_Call{Call: _e.mock.On("GetCommitReportMatchingSeqNum", ctx, seqNum, confirmations)}
+}
+
+func (_c *CommitStoreReader_GetCommitReportMatchingSeqNum_Call) Run(run func(ctx context.Context, seqNum uint64, confirmations int)) *CommitStoreReader_GetCommitReportMatchingSeqNum_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint64), args[2].(int))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_GetCommitReportMatchingSeqNum_Call) Return(_a0 []ccip.CommitStoreReportWithTxMeta, _a1 error) *CommitStoreReader_GetCommitReportMatchingSeqNum_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_GetCommitReportMatchingSeqNum_Call) RunAndReturn(run func(context.Context, uint64, int) ([]ccip.CommitStoreReportWithTxMeta, error)) *CommitStoreReader_GetCommitReportMatchingSeqNum_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetCommitStoreStaticConfig provides a mock function with given fields: ctx
+func (_m *CommitStoreReader) GetCommitStoreStaticConfig(ctx context.Context) (ccip.CommitStoreStaticConfig, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetCommitStoreStaticConfig")
+ }
+
+ var r0 ccip.CommitStoreStaticConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.CommitStoreStaticConfig, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.CommitStoreStaticConfig); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.CommitStoreStaticConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_GetCommitStoreStaticConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCommitStoreStaticConfig'
+type CommitStoreReader_GetCommitStoreStaticConfig_Call struct {
+ *mock.Call
+}
+
+// GetCommitStoreStaticConfig is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *CommitStoreReader_Expecter) GetCommitStoreStaticConfig(ctx interface{}) *CommitStoreReader_GetCommitStoreStaticConfig_Call {
+ return &CommitStoreReader_GetCommitStoreStaticConfig_Call{Call: _e.mock.On("GetCommitStoreStaticConfig", ctx)}
+}
+
+func (_c *CommitStoreReader_GetCommitStoreStaticConfig_Call) Run(run func(ctx context.Context)) *CommitStoreReader_GetCommitStoreStaticConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_GetCommitStoreStaticConfig_Call) Return(_a0 ccip.CommitStoreStaticConfig, _a1 error) *CommitStoreReader_GetCommitStoreStaticConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_GetCommitStoreStaticConfig_Call) RunAndReturn(run func(context.Context) (ccip.CommitStoreStaticConfig, error)) *CommitStoreReader_GetCommitStoreStaticConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetExpectedNextSequenceNumber provides a mock function with given fields: ctx
+func (_m *CommitStoreReader) GetExpectedNextSequenceNumber(ctx context.Context) (uint64, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetExpectedNextSequenceNumber")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) uint64); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_GetExpectedNextSequenceNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExpectedNextSequenceNumber'
+type CommitStoreReader_GetExpectedNextSequenceNumber_Call struct {
+ *mock.Call
+}
+
+// GetExpectedNextSequenceNumber is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *CommitStoreReader_Expecter) GetExpectedNextSequenceNumber(ctx interface{}) *CommitStoreReader_GetExpectedNextSequenceNumber_Call {
+ return &CommitStoreReader_GetExpectedNextSequenceNumber_Call{Call: _e.mock.On("GetExpectedNextSequenceNumber", ctx)}
+}
+
+func (_c *CommitStoreReader_GetExpectedNextSequenceNumber_Call) Run(run func(ctx context.Context)) *CommitStoreReader_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_GetExpectedNextSequenceNumber_Call) Return(_a0 uint64, _a1 error) *CommitStoreReader_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_GetExpectedNextSequenceNumber_Call) RunAndReturn(run func(context.Context) (uint64, error)) *CommitStoreReader_GetExpectedNextSequenceNumber_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetLatestPriceEpochAndRound provides a mock function with given fields: ctx
+func (_m *CommitStoreReader) GetLatestPriceEpochAndRound(ctx context.Context) (uint64, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetLatestPriceEpochAndRound")
+ }
+
+ var r0 uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) uint64); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(uint64)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_GetLatestPriceEpochAndRound_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestPriceEpochAndRound'
+type CommitStoreReader_GetLatestPriceEpochAndRound_Call struct {
+ *mock.Call
+}
+
+// GetLatestPriceEpochAndRound is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *CommitStoreReader_Expecter) GetLatestPriceEpochAndRound(ctx interface{}) *CommitStoreReader_GetLatestPriceEpochAndRound_Call {
+ return &CommitStoreReader_GetLatestPriceEpochAndRound_Call{Call: _e.mock.On("GetLatestPriceEpochAndRound", ctx)}
+}
+
+func (_c *CommitStoreReader_GetLatestPriceEpochAndRound_Call) Run(run func(ctx context.Context)) *CommitStoreReader_GetLatestPriceEpochAndRound_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_GetLatestPriceEpochAndRound_Call) Return(_a0 uint64, _a1 error) *CommitStoreReader_GetLatestPriceEpochAndRound_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_GetLatestPriceEpochAndRound_Call) RunAndReturn(run func(context.Context) (uint64, error)) *CommitStoreReader_GetLatestPriceEpochAndRound_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsBlessed provides a mock function with given fields: ctx, root
+func (_m *CommitStoreReader) IsBlessed(ctx context.Context, root [32]byte) (bool, error) {
+ ret := _m.Called(ctx, root)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsBlessed")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, [32]byte) (bool, error)); ok {
+ return rf(ctx, root)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, [32]byte) bool); ok {
+ r0 = rf(ctx, root)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, [32]byte) error); ok {
+ r1 = rf(ctx, root)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_IsBlessed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsBlessed'
+type CommitStoreReader_IsBlessed_Call struct {
+ *mock.Call
+}
+
+// IsBlessed is a helper method to define mock.On call
+// - ctx context.Context
+// - root [32]byte
+func (_e *CommitStoreReader_Expecter) IsBlessed(ctx interface{}, root interface{}) *CommitStoreReader_IsBlessed_Call {
+ return &CommitStoreReader_IsBlessed_Call{Call: _e.mock.On("IsBlessed", ctx, root)}
+}
+
+func (_c *CommitStoreReader_IsBlessed_Call) Run(run func(ctx context.Context, root [32]byte)) *CommitStoreReader_IsBlessed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([32]byte))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_IsBlessed_Call) Return(_a0 bool, _a1 error) *CommitStoreReader_IsBlessed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_IsBlessed_Call) RunAndReturn(run func(context.Context, [32]byte) (bool, error)) *CommitStoreReader_IsBlessed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsDestChainHealthy provides a mock function with given fields: ctx
+func (_m *CommitStoreReader) IsDestChainHealthy(ctx context.Context) (bool, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsDestChainHealthy")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) bool); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_IsDestChainHealthy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsDestChainHealthy'
+type CommitStoreReader_IsDestChainHealthy_Call struct {
+ *mock.Call
+}
+
+// IsDestChainHealthy is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *CommitStoreReader_Expecter) IsDestChainHealthy(ctx interface{}) *CommitStoreReader_IsDestChainHealthy_Call {
+ return &CommitStoreReader_IsDestChainHealthy_Call{Call: _e.mock.On("IsDestChainHealthy", ctx)}
+}
+
+func (_c *CommitStoreReader_IsDestChainHealthy_Call) Run(run func(ctx context.Context)) *CommitStoreReader_IsDestChainHealthy_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_IsDestChainHealthy_Call) Return(_a0 bool, _a1 error) *CommitStoreReader_IsDestChainHealthy_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_IsDestChainHealthy_Call) RunAndReturn(run func(context.Context) (bool, error)) *CommitStoreReader_IsDestChainHealthy_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsDown provides a mock function with given fields: ctx
+func (_m *CommitStoreReader) IsDown(ctx context.Context) (bool, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsDown")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) bool); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_IsDown_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsDown'
+type CommitStoreReader_IsDown_Call struct {
+ *mock.Call
+}
+
+// IsDown is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *CommitStoreReader_Expecter) IsDown(ctx interface{}) *CommitStoreReader_IsDown_Call {
+ return &CommitStoreReader_IsDown_Call{Call: _e.mock.On("IsDown", ctx)}
+}
+
+func (_c *CommitStoreReader_IsDown_Call) Run(run func(ctx context.Context)) *CommitStoreReader_IsDown_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_IsDown_Call) Return(_a0 bool, _a1 error) *CommitStoreReader_IsDown_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_IsDown_Call) RunAndReturn(run func(context.Context) (bool, error)) *CommitStoreReader_IsDown_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// OffchainConfig provides a mock function with given fields: ctx
+func (_m *CommitStoreReader) OffchainConfig(ctx context.Context) (ccip.CommitOffchainConfig, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OffchainConfig")
+ }
+
+ var r0 ccip.CommitOffchainConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.CommitOffchainConfig, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.CommitOffchainConfig); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.CommitOffchainConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_OffchainConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OffchainConfig'
+type CommitStoreReader_OffchainConfig_Call struct {
+ *mock.Call
+}
+
+// OffchainConfig is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *CommitStoreReader_Expecter) OffchainConfig(ctx interface{}) *CommitStoreReader_OffchainConfig_Call {
+ return &CommitStoreReader_OffchainConfig_Call{Call: _e.mock.On("OffchainConfig", ctx)}
+}
+
+func (_c *CommitStoreReader_OffchainConfig_Call) Run(run func(ctx context.Context)) *CommitStoreReader_OffchainConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_OffchainConfig_Call) Return(_a0 ccip.CommitOffchainConfig, _a1 error) *CommitStoreReader_OffchainConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_OffchainConfig_Call) RunAndReturn(run func(context.Context) (ccip.CommitOffchainConfig, error)) *CommitStoreReader_OffchainConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetGasEstimator provides a mock function with given fields: ctx, gpe
+func (_m *CommitStoreReader) SetGasEstimator(ctx context.Context, gpe gas.EvmFeeEstimator) error {
+ ret := _m.Called(ctx, gpe)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetGasEstimator")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, gas.EvmFeeEstimator) error); ok {
+ r0 = rf(ctx, gpe)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CommitStoreReader_SetGasEstimator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetGasEstimator'
+type CommitStoreReader_SetGasEstimator_Call struct {
+ *mock.Call
+}
+
+// SetGasEstimator is a helper method to define mock.On call
+// - ctx context.Context
+// - gpe gas.EvmFeeEstimator
+func (_e *CommitStoreReader_Expecter) SetGasEstimator(ctx interface{}, gpe interface{}) *CommitStoreReader_SetGasEstimator_Call {
+ return &CommitStoreReader_SetGasEstimator_Call{Call: _e.mock.On("SetGasEstimator", ctx, gpe)}
+}
+
+func (_c *CommitStoreReader_SetGasEstimator_Call) Run(run func(ctx context.Context, gpe gas.EvmFeeEstimator)) *CommitStoreReader_SetGasEstimator_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(gas.EvmFeeEstimator))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_SetGasEstimator_Call) Return(_a0 error) *CommitStoreReader_SetGasEstimator_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *CommitStoreReader_SetGasEstimator_Call) RunAndReturn(run func(context.Context, gas.EvmFeeEstimator) error) *CommitStoreReader_SetGasEstimator_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetSourceMaxGasPrice provides a mock function with given fields: ctx, sourceMaxGasPrice
+func (_m *CommitStoreReader) SetSourceMaxGasPrice(ctx context.Context, sourceMaxGasPrice *big.Int) error {
+ ret := _m.Called(ctx, sourceMaxGasPrice)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetSourceMaxGasPrice")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, *big.Int) error); ok {
+ r0 = rf(ctx, sourceMaxGasPrice)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// CommitStoreReader_SetSourceMaxGasPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetSourceMaxGasPrice'
+type CommitStoreReader_SetSourceMaxGasPrice_Call struct {
+ *mock.Call
+}
+
+// SetSourceMaxGasPrice is a helper method to define mock.On call
+// - ctx context.Context
+// - sourceMaxGasPrice *big.Int
+func (_e *CommitStoreReader_Expecter) SetSourceMaxGasPrice(ctx interface{}, sourceMaxGasPrice interface{}) *CommitStoreReader_SetSourceMaxGasPrice_Call {
+ return &CommitStoreReader_SetSourceMaxGasPrice_Call{Call: _e.mock.On("SetSourceMaxGasPrice", ctx, sourceMaxGasPrice)}
+}
+
+func (_c *CommitStoreReader_SetSourceMaxGasPrice_Call) Run(run func(ctx context.Context, sourceMaxGasPrice *big.Int)) *CommitStoreReader_SetSourceMaxGasPrice_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_SetSourceMaxGasPrice_Call) Return(_a0 error) *CommitStoreReader_SetSourceMaxGasPrice_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *CommitStoreReader_SetSourceMaxGasPrice_Call) RunAndReturn(run func(context.Context, *big.Int) error) *CommitStoreReader_SetSourceMaxGasPrice_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// VerifyExecutionReport provides a mock function with given fields: ctx, report
+func (_m *CommitStoreReader) VerifyExecutionReport(ctx context.Context, report ccip.ExecReport) (bool, error) {
+ ret := _m.Called(ctx, report)
+
+ if len(ret) == 0 {
+ panic("no return value specified for VerifyExecutionReport")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.ExecReport) (bool, error)); ok {
+ return rf(ctx, report)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.ExecReport) bool); ok {
+ r0 = rf(ctx, report)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, ccip.ExecReport) error); ok {
+ r1 = rf(ctx, report)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// CommitStoreReader_VerifyExecutionReport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifyExecutionReport'
+type CommitStoreReader_VerifyExecutionReport_Call struct {
+ *mock.Call
+}
+
+// VerifyExecutionReport is a helper method to define mock.On call
+// - ctx context.Context
+// - report ccip.ExecReport
+func (_e *CommitStoreReader_Expecter) VerifyExecutionReport(ctx interface{}, report interface{}) *CommitStoreReader_VerifyExecutionReport_Call {
+ return &CommitStoreReader_VerifyExecutionReport_Call{Call: _e.mock.On("VerifyExecutionReport", ctx, report)}
+}
+
+func (_c *CommitStoreReader_VerifyExecutionReport_Call) Run(run func(ctx context.Context, report ccip.ExecReport)) *CommitStoreReader_VerifyExecutionReport_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(ccip.ExecReport))
+ })
+ return _c
+}
+
+func (_c *CommitStoreReader_VerifyExecutionReport_Call) Return(_a0 bool, _a1 error) *CommitStoreReader_VerifyExecutionReport_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *CommitStoreReader_VerifyExecutionReport_Call) RunAndReturn(run func(context.Context, ccip.ExecReport) (bool, error)) *CommitStoreReader_VerifyExecutionReport_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewCommitStoreReader creates a new instance of CommitStoreReader. 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 NewCommitStoreReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *CommitStoreReader {
+ mock := &CommitStoreReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/offramp_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/offramp_reader_mock.go
new file mode 100644
index 00000000000..f383ccdc0ba
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/offramp_reader_mock.go
@@ -0,0 +1,949 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// OffRampReader is an autogenerated mock type for the OffRampReader type
+type OffRampReader struct {
+ mock.Mock
+}
+
+type OffRampReader_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *OffRampReader) EXPECT() *OffRampReader_Expecter {
+ return &OffRampReader_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields: ctx
+func (_m *OffRampReader) Address(ctx context.Context) (ccip.Address, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.Address, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.Address); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type OffRampReader_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) Address(ctx interface{}) *OffRampReader_Address_Call {
+ return &OffRampReader_Address_Call{Call: _e.mock.On("Address", ctx)}
+}
+
+func (_c *OffRampReader_Address_Call) Run(run func(ctx context.Context)) *OffRampReader_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_Address_Call) Return(_a0 ccip.Address, _a1 error) *OffRampReader_Address_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_Address_Call) RunAndReturn(run func(context.Context) (ccip.Address, error)) *OffRampReader_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ChangeConfig provides a mock function with given fields: ctx, onchainConfig, offchainConfig
+func (_m *OffRampReader) ChangeConfig(ctx context.Context, onchainConfig []byte, offchainConfig []byte) (ccip.Address, ccip.Address, error) {
+ ret := _m.Called(ctx, onchainConfig, offchainConfig)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ChangeConfig")
+ }
+
+ var r0 ccip.Address
+ var r1 ccip.Address
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context, []byte, []byte) (ccip.Address, ccip.Address, error)); ok {
+ return rf(ctx, onchainConfig, offchainConfig)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []byte, []byte) ccip.Address); ok {
+ r0 = rf(ctx, onchainConfig, offchainConfig)
+ } else {
+ r0 = ret.Get(0).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []byte, []byte) ccip.Address); ok {
+ r1 = rf(ctx, onchainConfig, offchainConfig)
+ } else {
+ r1 = ret.Get(1).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context, []byte, []byte) error); ok {
+ r2 = rf(ctx, onchainConfig, offchainConfig)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// OffRampReader_ChangeConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ChangeConfig'
+type OffRampReader_ChangeConfig_Call struct {
+ *mock.Call
+}
+
+// ChangeConfig is a helper method to define mock.On call
+// - ctx context.Context
+// - onchainConfig []byte
+// - offchainConfig []byte
+func (_e *OffRampReader_Expecter) ChangeConfig(ctx interface{}, onchainConfig interface{}, offchainConfig interface{}) *OffRampReader_ChangeConfig_Call {
+ return &OffRampReader_ChangeConfig_Call{Call: _e.mock.On("ChangeConfig", ctx, onchainConfig, offchainConfig)}
+}
+
+func (_c *OffRampReader_ChangeConfig_Call) Run(run func(ctx context.Context, onchainConfig []byte, offchainConfig []byte)) *OffRampReader_ChangeConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]byte), args[2].([]byte))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_ChangeConfig_Call) Return(_a0 ccip.Address, _a1 ccip.Address, _a2 error) *OffRampReader_ChangeConfig_Call {
+ _c.Call.Return(_a0, _a1, _a2)
+ return _c
+}
+
+func (_c *OffRampReader_ChangeConfig_Call) RunAndReturn(run func(context.Context, []byte, []byte) (ccip.Address, ccip.Address, error)) *OffRampReader_ChangeConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Close provides a mock function with given fields:
+func (_m *OffRampReader) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// OffRampReader_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type OffRampReader_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *OffRampReader_Expecter) Close() *OffRampReader_Close_Call {
+ return &OffRampReader_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *OffRampReader_Close_Call) Run(run func()) *OffRampReader_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *OffRampReader_Close_Call) Return(_a0 error) *OffRampReader_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *OffRampReader_Close_Call) RunAndReturn(run func() error) *OffRampReader_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// CurrentRateLimiterState provides a mock function with given fields: ctx
+func (_m *OffRampReader) CurrentRateLimiterState(ctx context.Context) (ccip.TokenBucketRateLimit, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CurrentRateLimiterState")
+ }
+
+ var r0 ccip.TokenBucketRateLimit
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.TokenBucketRateLimit, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.TokenBucketRateLimit); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.TokenBucketRateLimit)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_CurrentRateLimiterState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CurrentRateLimiterState'
+type OffRampReader_CurrentRateLimiterState_Call struct {
+ *mock.Call
+}
+
+// CurrentRateLimiterState is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) CurrentRateLimiterState(ctx interface{}) *OffRampReader_CurrentRateLimiterState_Call {
+ return &OffRampReader_CurrentRateLimiterState_Call{Call: _e.mock.On("CurrentRateLimiterState", ctx)}
+}
+
+func (_c *OffRampReader_CurrentRateLimiterState_Call) Run(run func(ctx context.Context)) *OffRampReader_CurrentRateLimiterState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_CurrentRateLimiterState_Call) Return(_a0 ccip.TokenBucketRateLimit, _a1 error) *OffRampReader_CurrentRateLimiterState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_CurrentRateLimiterState_Call) RunAndReturn(run func(context.Context) (ccip.TokenBucketRateLimit, error)) *OffRampReader_CurrentRateLimiterState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// DecodeExecutionReport provides a mock function with given fields: ctx, report
+func (_m *OffRampReader) DecodeExecutionReport(ctx context.Context, report []byte) (ccip.ExecReport, error) {
+ ret := _m.Called(ctx, report)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DecodeExecutionReport")
+ }
+
+ var r0 ccip.ExecReport
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) (ccip.ExecReport, error)); ok {
+ return rf(ctx, report)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []byte) ccip.ExecReport); ok {
+ r0 = rf(ctx, report)
+ } else {
+ r0 = ret.Get(0).(ccip.ExecReport)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []byte) error); ok {
+ r1 = rf(ctx, report)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_DecodeExecutionReport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DecodeExecutionReport'
+type OffRampReader_DecodeExecutionReport_Call struct {
+ *mock.Call
+}
+
+// DecodeExecutionReport is a helper method to define mock.On call
+// - ctx context.Context
+// - report []byte
+func (_e *OffRampReader_Expecter) DecodeExecutionReport(ctx interface{}, report interface{}) *OffRampReader_DecodeExecutionReport_Call {
+ return &OffRampReader_DecodeExecutionReport_Call{Call: _e.mock.On("DecodeExecutionReport", ctx, report)}
+}
+
+func (_c *OffRampReader_DecodeExecutionReport_Call) Run(run func(ctx context.Context, report []byte)) *OffRampReader_DecodeExecutionReport_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]byte))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_DecodeExecutionReport_Call) Return(_a0 ccip.ExecReport, _a1 error) *OffRampReader_DecodeExecutionReport_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_DecodeExecutionReport_Call) RunAndReturn(run func(context.Context, []byte) (ccip.ExecReport, error)) *OffRampReader_DecodeExecutionReport_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// EncodeExecutionReport provides a mock function with given fields: ctx, report
+func (_m *OffRampReader) EncodeExecutionReport(ctx context.Context, report ccip.ExecReport) ([]byte, error) {
+ ret := _m.Called(ctx, report)
+
+ if len(ret) == 0 {
+ panic("no return value specified for EncodeExecutionReport")
+ }
+
+ var r0 []byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.ExecReport) ([]byte, error)); ok {
+ return rf(ctx, report)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.ExecReport) []byte); ok {
+ r0 = rf(ctx, report)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, ccip.ExecReport) error); ok {
+ r1 = rf(ctx, report)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_EncodeExecutionReport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EncodeExecutionReport'
+type OffRampReader_EncodeExecutionReport_Call struct {
+ *mock.Call
+}
+
+// EncodeExecutionReport is a helper method to define mock.On call
+// - ctx context.Context
+// - report ccip.ExecReport
+func (_e *OffRampReader_Expecter) EncodeExecutionReport(ctx interface{}, report interface{}) *OffRampReader_EncodeExecutionReport_Call {
+ return &OffRampReader_EncodeExecutionReport_Call{Call: _e.mock.On("EncodeExecutionReport", ctx, report)}
+}
+
+func (_c *OffRampReader_EncodeExecutionReport_Call) Run(run func(ctx context.Context, report ccip.ExecReport)) *OffRampReader_EncodeExecutionReport_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(ccip.ExecReport))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_EncodeExecutionReport_Call) Return(_a0 []byte, _a1 error) *OffRampReader_EncodeExecutionReport_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_EncodeExecutionReport_Call) RunAndReturn(run func(context.Context, ccip.ExecReport) ([]byte, error)) *OffRampReader_EncodeExecutionReport_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GasPriceEstimator provides a mock function with given fields: ctx
+func (_m *OffRampReader) GasPriceEstimator(ctx context.Context) (ccip.GasPriceEstimatorExec, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GasPriceEstimator")
+ }
+
+ var r0 ccip.GasPriceEstimatorExec
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.GasPriceEstimatorExec, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.GasPriceEstimatorExec); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(ccip.GasPriceEstimatorExec)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_GasPriceEstimator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GasPriceEstimator'
+type OffRampReader_GasPriceEstimator_Call struct {
+ *mock.Call
+}
+
+// GasPriceEstimator is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) GasPriceEstimator(ctx interface{}) *OffRampReader_GasPriceEstimator_Call {
+ return &OffRampReader_GasPriceEstimator_Call{Call: _e.mock.On("GasPriceEstimator", ctx)}
+}
+
+func (_c *OffRampReader_GasPriceEstimator_Call) Run(run func(ctx context.Context)) *OffRampReader_GasPriceEstimator_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_GasPriceEstimator_Call) Return(_a0 ccip.GasPriceEstimatorExec, _a1 error) *OffRampReader_GasPriceEstimator_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_GasPriceEstimator_Call) RunAndReturn(run func(context.Context) (ccip.GasPriceEstimatorExec, error)) *OffRampReader_GasPriceEstimator_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetExecutionState provides a mock function with given fields: ctx, sequenceNumber
+func (_m *OffRampReader) GetExecutionState(ctx context.Context, sequenceNumber uint64) (uint8, error) {
+ ret := _m.Called(ctx, sequenceNumber)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetExecutionState")
+ }
+
+ var r0 uint8
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64) (uint8, error)); ok {
+ return rf(ctx, sequenceNumber)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64) uint8); ok {
+ r0 = rf(ctx, sequenceNumber)
+ } else {
+ r0 = ret.Get(0).(uint8)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok {
+ r1 = rf(ctx, sequenceNumber)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_GetExecutionState_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExecutionState'
+type OffRampReader_GetExecutionState_Call struct {
+ *mock.Call
+}
+
+// GetExecutionState is a helper method to define mock.On call
+// - ctx context.Context
+// - sequenceNumber uint64
+func (_e *OffRampReader_Expecter) GetExecutionState(ctx interface{}, sequenceNumber interface{}) *OffRampReader_GetExecutionState_Call {
+ return &OffRampReader_GetExecutionState_Call{Call: _e.mock.On("GetExecutionState", ctx, sequenceNumber)}
+}
+
+func (_c *OffRampReader_GetExecutionState_Call) Run(run func(ctx context.Context, sequenceNumber uint64)) *OffRampReader_GetExecutionState_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_GetExecutionState_Call) Return(_a0 uint8, _a1 error) *OffRampReader_GetExecutionState_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_GetExecutionState_Call) RunAndReturn(run func(context.Context, uint64) (uint8, error)) *OffRampReader_GetExecutionState_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetExecutionStateChangesBetweenSeqNums provides a mock function with given fields: ctx, seqNumMin, seqNumMax, confirmations
+func (_m *OffRampReader) GetExecutionStateChangesBetweenSeqNums(ctx context.Context, seqNumMin uint64, seqNumMax uint64, confirmations int) ([]ccip.ExecutionStateChangedWithTxMeta, error) {
+ ret := _m.Called(ctx, seqNumMin, seqNumMax, confirmations)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetExecutionStateChangesBetweenSeqNums")
+ }
+
+ var r0 []ccip.ExecutionStateChangedWithTxMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, int) ([]ccip.ExecutionStateChangedWithTxMeta, error)); ok {
+ return rf(ctx, seqNumMin, seqNumMax, confirmations)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, int) []ccip.ExecutionStateChangedWithTxMeta); ok {
+ r0 = rf(ctx, seqNumMin, seqNumMax, confirmations)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.ExecutionStateChangedWithTxMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64, int) error); ok {
+ r1 = rf(ctx, seqNumMin, seqNumMax, confirmations)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExecutionStateChangesBetweenSeqNums'
+type OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call struct {
+ *mock.Call
+}
+
+// GetExecutionStateChangesBetweenSeqNums is a helper method to define mock.On call
+// - ctx context.Context
+// - seqNumMin uint64
+// - seqNumMax uint64
+// - confirmations int
+func (_e *OffRampReader_Expecter) GetExecutionStateChangesBetweenSeqNums(ctx interface{}, seqNumMin interface{}, seqNumMax interface{}, confirmations interface{}) *OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call {
+ return &OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call{Call: _e.mock.On("GetExecutionStateChangesBetweenSeqNums", ctx, seqNumMin, seqNumMax, confirmations)}
+}
+
+func (_c *OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call) Run(run func(ctx context.Context, seqNumMin uint64, seqNumMax uint64, confirmations int)) *OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint64), args[2].(uint64), args[3].(int))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call) Return(_a0 []ccip.ExecutionStateChangedWithTxMeta, _a1 error) *OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call) RunAndReturn(run func(context.Context, uint64, uint64, int) ([]ccip.ExecutionStateChangedWithTxMeta, error)) *OffRampReader_GetExecutionStateChangesBetweenSeqNums_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetRouter provides a mock function with given fields: ctx
+func (_m *OffRampReader) GetRouter(ctx context.Context) (ccip.Address, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetRouter")
+ }
+
+ var r0 ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.Address, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.Address); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_GetRouter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRouter'
+type OffRampReader_GetRouter_Call struct {
+ *mock.Call
+}
+
+// GetRouter is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) GetRouter(ctx interface{}) *OffRampReader_GetRouter_Call {
+ return &OffRampReader_GetRouter_Call{Call: _e.mock.On("GetRouter", ctx)}
+}
+
+func (_c *OffRampReader_GetRouter_Call) Run(run func(ctx context.Context)) *OffRampReader_GetRouter_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_GetRouter_Call) Return(_a0 ccip.Address, _a1 error) *OffRampReader_GetRouter_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_GetRouter_Call) RunAndReturn(run func(context.Context) (ccip.Address, error)) *OffRampReader_GetRouter_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSourceToDestTokensMapping provides a mock function with given fields: ctx
+func (_m *OffRampReader) GetSourceToDestTokensMapping(ctx context.Context) (map[ccip.Address]ccip.Address, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSourceToDestTokensMapping")
+ }
+
+ var r0 map[ccip.Address]ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (map[ccip.Address]ccip.Address, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) map[ccip.Address]ccip.Address); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(map[ccip.Address]ccip.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_GetSourceToDestTokensMapping_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSourceToDestTokensMapping'
+type OffRampReader_GetSourceToDestTokensMapping_Call struct {
+ *mock.Call
+}
+
+// GetSourceToDestTokensMapping is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) GetSourceToDestTokensMapping(ctx interface{}) *OffRampReader_GetSourceToDestTokensMapping_Call {
+ return &OffRampReader_GetSourceToDestTokensMapping_Call{Call: _e.mock.On("GetSourceToDestTokensMapping", ctx)}
+}
+
+func (_c *OffRampReader_GetSourceToDestTokensMapping_Call) Run(run func(ctx context.Context)) *OffRampReader_GetSourceToDestTokensMapping_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_GetSourceToDestTokensMapping_Call) Return(_a0 map[ccip.Address]ccip.Address, _a1 error) *OffRampReader_GetSourceToDestTokensMapping_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_GetSourceToDestTokensMapping_Call) RunAndReturn(run func(context.Context) (map[ccip.Address]ccip.Address, error)) *OffRampReader_GetSourceToDestTokensMapping_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetStaticConfig provides a mock function with given fields: ctx
+func (_m *OffRampReader) GetStaticConfig(ctx context.Context) (ccip.OffRampStaticConfig, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetStaticConfig")
+ }
+
+ var r0 ccip.OffRampStaticConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.OffRampStaticConfig, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.OffRampStaticConfig); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.OffRampStaticConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_GetStaticConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStaticConfig'
+type OffRampReader_GetStaticConfig_Call struct {
+ *mock.Call
+}
+
+// GetStaticConfig is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) GetStaticConfig(ctx interface{}) *OffRampReader_GetStaticConfig_Call {
+ return &OffRampReader_GetStaticConfig_Call{Call: _e.mock.On("GetStaticConfig", ctx)}
+}
+
+func (_c *OffRampReader_GetStaticConfig_Call) Run(run func(ctx context.Context)) *OffRampReader_GetStaticConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_GetStaticConfig_Call) Return(_a0 ccip.OffRampStaticConfig, _a1 error) *OffRampReader_GetStaticConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_GetStaticConfig_Call) RunAndReturn(run func(context.Context) (ccip.OffRampStaticConfig, error)) *OffRampReader_GetStaticConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokens provides a mock function with given fields: ctx
+func (_m *OffRampReader) GetTokens(ctx context.Context) (ccip.OffRampTokens, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokens")
+ }
+
+ var r0 ccip.OffRampTokens
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.OffRampTokens, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.OffRampTokens); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.OffRampTokens)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_GetTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokens'
+type OffRampReader_GetTokens_Call struct {
+ *mock.Call
+}
+
+// GetTokens is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) GetTokens(ctx interface{}) *OffRampReader_GetTokens_Call {
+ return &OffRampReader_GetTokens_Call{Call: _e.mock.On("GetTokens", ctx)}
+}
+
+func (_c *OffRampReader_GetTokens_Call) Run(run func(ctx context.Context)) *OffRampReader_GetTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_GetTokens_Call) Return(_a0 ccip.OffRampTokens, _a1 error) *OffRampReader_GetTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_GetTokens_Call) RunAndReturn(run func(context.Context) (ccip.OffRampTokens, error)) *OffRampReader_GetTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ListSenderNonces provides a mock function with given fields: ctx, senders
+func (_m *OffRampReader) ListSenderNonces(ctx context.Context, senders []ccip.Address) (map[ccip.Address]uint64, error) {
+ ret := _m.Called(ctx, senders)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ListSenderNonces")
+ }
+
+ var r0 map[ccip.Address]uint64
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) (map[ccip.Address]uint64, error)); ok {
+ return rf(ctx, senders)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) map[ccip.Address]uint64); ok {
+ r0 = rf(ctx, senders)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(map[ccip.Address]uint64)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []ccip.Address) error); ok {
+ r1 = rf(ctx, senders)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_ListSenderNonces_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListSenderNonces'
+type OffRampReader_ListSenderNonces_Call struct {
+ *mock.Call
+}
+
+// ListSenderNonces is a helper method to define mock.On call
+// - ctx context.Context
+// - senders []ccip.Address
+func (_e *OffRampReader_Expecter) ListSenderNonces(ctx interface{}, senders interface{}) *OffRampReader_ListSenderNonces_Call {
+ return &OffRampReader_ListSenderNonces_Call{Call: _e.mock.On("ListSenderNonces", ctx, senders)}
+}
+
+func (_c *OffRampReader_ListSenderNonces_Call) Run(run func(ctx context.Context, senders []ccip.Address)) *OffRampReader_ListSenderNonces_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]ccip.Address))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_ListSenderNonces_Call) Return(_a0 map[ccip.Address]uint64, _a1 error) *OffRampReader_ListSenderNonces_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_ListSenderNonces_Call) RunAndReturn(run func(context.Context, []ccip.Address) (map[ccip.Address]uint64, error)) *OffRampReader_ListSenderNonces_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// OffchainConfig provides a mock function with given fields: ctx
+func (_m *OffRampReader) OffchainConfig(ctx context.Context) (ccip.ExecOffchainConfig, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OffchainConfig")
+ }
+
+ var r0 ccip.ExecOffchainConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.ExecOffchainConfig, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.ExecOffchainConfig); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.ExecOffchainConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_OffchainConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OffchainConfig'
+type OffRampReader_OffchainConfig_Call struct {
+ *mock.Call
+}
+
+// OffchainConfig is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) OffchainConfig(ctx interface{}) *OffRampReader_OffchainConfig_Call {
+ return &OffRampReader_OffchainConfig_Call{Call: _e.mock.On("OffchainConfig", ctx)}
+}
+
+func (_c *OffRampReader_OffchainConfig_Call) Run(run func(ctx context.Context)) *OffRampReader_OffchainConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_OffchainConfig_Call) Return(_a0 ccip.ExecOffchainConfig, _a1 error) *OffRampReader_OffchainConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_OffchainConfig_Call) RunAndReturn(run func(context.Context) (ccip.ExecOffchainConfig, error)) *OffRampReader_OffchainConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// OnchainConfig provides a mock function with given fields: ctx
+func (_m *OffRampReader) OnchainConfig(ctx context.Context) (ccip.ExecOnchainConfig, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for OnchainConfig")
+ }
+
+ var r0 ccip.ExecOnchainConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.ExecOnchainConfig, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.ExecOnchainConfig); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.ExecOnchainConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OffRampReader_OnchainConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OnchainConfig'
+type OffRampReader_OnchainConfig_Call struct {
+ *mock.Call
+}
+
+// OnchainConfig is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OffRampReader_Expecter) OnchainConfig(ctx interface{}) *OffRampReader_OnchainConfig_Call {
+ return &OffRampReader_OnchainConfig_Call{Call: _e.mock.On("OnchainConfig", ctx)}
+}
+
+func (_c *OffRampReader_OnchainConfig_Call) Run(run func(ctx context.Context)) *OffRampReader_OnchainConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OffRampReader_OnchainConfig_Call) Return(_a0 ccip.ExecOnchainConfig, _a1 error) *OffRampReader_OnchainConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OffRampReader_OnchainConfig_Call) RunAndReturn(run func(context.Context) (ccip.ExecOnchainConfig, error)) *OffRampReader_OnchainConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewOffRampReader creates a new instance of OffRampReader. 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 NewOffRampReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *OffRampReader {
+ mock := &OffRampReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/onramp_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/onramp_reader_mock.go
new file mode 100644
index 00000000000..ccf5bd78463
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/onramp_reader_mock.go
@@ -0,0 +1,480 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// OnRampReader is an autogenerated mock type for the OnRampReader type
+type OnRampReader struct {
+ mock.Mock
+}
+
+type OnRampReader_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *OnRampReader) EXPECT() *OnRampReader_Expecter {
+ return &OnRampReader_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields: ctx
+func (_m *OnRampReader) Address(ctx context.Context) (ccip.Address, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.Address, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.Address); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OnRampReader_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type OnRampReader_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OnRampReader_Expecter) Address(ctx interface{}) *OnRampReader_Address_Call {
+ return &OnRampReader_Address_Call{Call: _e.mock.On("Address", ctx)}
+}
+
+func (_c *OnRampReader_Address_Call) Run(run func(ctx context.Context)) *OnRampReader_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OnRampReader_Address_Call) Return(_a0 ccip.Address, _a1 error) *OnRampReader_Address_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OnRampReader_Address_Call) RunAndReturn(run func(context.Context) (ccip.Address, error)) *OnRampReader_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Close provides a mock function with given fields:
+func (_m *OnRampReader) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// OnRampReader_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type OnRampReader_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *OnRampReader_Expecter) Close() *OnRampReader_Close_Call {
+ return &OnRampReader_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *OnRampReader_Close_Call) Run(run func()) *OnRampReader_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *OnRampReader_Close_Call) Return(_a0 error) *OnRampReader_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *OnRampReader_Close_Call) RunAndReturn(run func() error) *OnRampReader_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetDynamicConfig provides a mock function with given fields: ctx
+func (_m *OnRampReader) GetDynamicConfig(ctx context.Context) (ccip.OnRampDynamicConfig, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetDynamicConfig")
+ }
+
+ var r0 ccip.OnRampDynamicConfig
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.OnRampDynamicConfig, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.OnRampDynamicConfig); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.OnRampDynamicConfig)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OnRampReader_GetDynamicConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDynamicConfig'
+type OnRampReader_GetDynamicConfig_Call struct {
+ *mock.Call
+}
+
+// GetDynamicConfig is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OnRampReader_Expecter) GetDynamicConfig(ctx interface{}) *OnRampReader_GetDynamicConfig_Call {
+ return &OnRampReader_GetDynamicConfig_Call{Call: _e.mock.On("GetDynamicConfig", ctx)}
+}
+
+func (_c *OnRampReader_GetDynamicConfig_Call) Run(run func(ctx context.Context)) *OnRampReader_GetDynamicConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OnRampReader_GetDynamicConfig_Call) Return(_a0 ccip.OnRampDynamicConfig, _a1 error) *OnRampReader_GetDynamicConfig_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OnRampReader_GetDynamicConfig_Call) RunAndReturn(run func(context.Context) (ccip.OnRampDynamicConfig, error)) *OnRampReader_GetDynamicConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetSendRequestsBetweenSeqNums provides a mock function with given fields: ctx, seqNumMin, seqNumMax, finalized
+func (_m *OnRampReader) GetSendRequestsBetweenSeqNums(ctx context.Context, seqNumMin uint64, seqNumMax uint64, finalized bool) ([]ccip.EVM2EVMMessageWithTxMeta, error) {
+ ret := _m.Called(ctx, seqNumMin, seqNumMax, finalized)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetSendRequestsBetweenSeqNums")
+ }
+
+ var r0 []ccip.EVM2EVMMessageWithTxMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, bool) ([]ccip.EVM2EVMMessageWithTxMeta, error)); ok {
+ return rf(ctx, seqNumMin, seqNumMax, finalized)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, bool) []ccip.EVM2EVMMessageWithTxMeta); ok {
+ r0 = rf(ctx, seqNumMin, seqNumMax, finalized)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.EVM2EVMMessageWithTxMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64, bool) error); ok {
+ r1 = rf(ctx, seqNumMin, seqNumMax, finalized)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OnRampReader_GetSendRequestsBetweenSeqNums_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSendRequestsBetweenSeqNums'
+type OnRampReader_GetSendRequestsBetweenSeqNums_Call struct {
+ *mock.Call
+}
+
+// GetSendRequestsBetweenSeqNums is a helper method to define mock.On call
+// - ctx context.Context
+// - seqNumMin uint64
+// - seqNumMax uint64
+// - finalized bool
+func (_e *OnRampReader_Expecter) GetSendRequestsBetweenSeqNums(ctx interface{}, seqNumMin interface{}, seqNumMax interface{}, finalized interface{}) *OnRampReader_GetSendRequestsBetweenSeqNums_Call {
+ return &OnRampReader_GetSendRequestsBetweenSeqNums_Call{Call: _e.mock.On("GetSendRequestsBetweenSeqNums", ctx, seqNumMin, seqNumMax, finalized)}
+}
+
+func (_c *OnRampReader_GetSendRequestsBetweenSeqNums_Call) Run(run func(ctx context.Context, seqNumMin uint64, seqNumMax uint64, finalized bool)) *OnRampReader_GetSendRequestsBetweenSeqNums_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint64), args[2].(uint64), args[3].(bool))
+ })
+ return _c
+}
+
+func (_c *OnRampReader_GetSendRequestsBetweenSeqNums_Call) Return(_a0 []ccip.EVM2EVMMessageWithTxMeta, _a1 error) *OnRampReader_GetSendRequestsBetweenSeqNums_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OnRampReader_GetSendRequestsBetweenSeqNums_Call) RunAndReturn(run func(context.Context, uint64, uint64, bool) ([]ccip.EVM2EVMMessageWithTxMeta, error)) *OnRampReader_GetSendRequestsBetweenSeqNums_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsSourceChainHealthy provides a mock function with given fields: ctx
+func (_m *OnRampReader) IsSourceChainHealthy(ctx context.Context) (bool, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsSourceChainHealthy")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) bool); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OnRampReader_IsSourceChainHealthy_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsSourceChainHealthy'
+type OnRampReader_IsSourceChainHealthy_Call struct {
+ *mock.Call
+}
+
+// IsSourceChainHealthy is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OnRampReader_Expecter) IsSourceChainHealthy(ctx interface{}) *OnRampReader_IsSourceChainHealthy_Call {
+ return &OnRampReader_IsSourceChainHealthy_Call{Call: _e.mock.On("IsSourceChainHealthy", ctx)}
+}
+
+func (_c *OnRampReader_IsSourceChainHealthy_Call) Run(run func(ctx context.Context)) *OnRampReader_IsSourceChainHealthy_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OnRampReader_IsSourceChainHealthy_Call) Return(_a0 bool, _a1 error) *OnRampReader_IsSourceChainHealthy_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OnRampReader_IsSourceChainHealthy_Call) RunAndReturn(run func(context.Context) (bool, error)) *OnRampReader_IsSourceChainHealthy_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// IsSourceCursed provides a mock function with given fields: ctx
+func (_m *OnRampReader) IsSourceCursed(ctx context.Context) (bool, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for IsSourceCursed")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) bool); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OnRampReader_IsSourceCursed_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsSourceCursed'
+type OnRampReader_IsSourceCursed_Call struct {
+ *mock.Call
+}
+
+// IsSourceCursed is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OnRampReader_Expecter) IsSourceCursed(ctx interface{}) *OnRampReader_IsSourceCursed_Call {
+ return &OnRampReader_IsSourceCursed_Call{Call: _e.mock.On("IsSourceCursed", ctx)}
+}
+
+func (_c *OnRampReader_IsSourceCursed_Call) Run(run func(ctx context.Context)) *OnRampReader_IsSourceCursed_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OnRampReader_IsSourceCursed_Call) Return(_a0 bool, _a1 error) *OnRampReader_IsSourceCursed_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OnRampReader_IsSourceCursed_Call) RunAndReturn(run func(context.Context) (bool, error)) *OnRampReader_IsSourceCursed_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// RouterAddress provides a mock function with given fields: _a0
+func (_m *OnRampReader) RouterAddress(_a0 context.Context) (ccip.Address, error) {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for RouterAddress")
+ }
+
+ var r0 ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.Address, error)); ok {
+ return rf(_a0)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.Address); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Get(0).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(_a0)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OnRampReader_RouterAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RouterAddress'
+type OnRampReader_RouterAddress_Call struct {
+ *mock.Call
+}
+
+// RouterAddress is a helper method to define mock.On call
+// - _a0 context.Context
+func (_e *OnRampReader_Expecter) RouterAddress(_a0 interface{}) *OnRampReader_RouterAddress_Call {
+ return &OnRampReader_RouterAddress_Call{Call: _e.mock.On("RouterAddress", _a0)}
+}
+
+func (_c *OnRampReader_RouterAddress_Call) Run(run func(_a0 context.Context)) *OnRampReader_RouterAddress_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OnRampReader_RouterAddress_Call) Return(_a0 ccip.Address, _a1 error) *OnRampReader_RouterAddress_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OnRampReader_RouterAddress_Call) RunAndReturn(run func(context.Context) (ccip.Address, error)) *OnRampReader_RouterAddress_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SourcePriceRegistryAddress provides a mock function with given fields: ctx
+func (_m *OnRampReader) SourcePriceRegistryAddress(ctx context.Context) (ccip.Address, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SourcePriceRegistryAddress")
+ }
+
+ var r0 ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.Address, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.Address); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// OnRampReader_SourcePriceRegistryAddress_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SourcePriceRegistryAddress'
+type OnRampReader_SourcePriceRegistryAddress_Call struct {
+ *mock.Call
+}
+
+// SourcePriceRegistryAddress is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *OnRampReader_Expecter) SourcePriceRegistryAddress(ctx interface{}) *OnRampReader_SourcePriceRegistryAddress_Call {
+ return &OnRampReader_SourcePriceRegistryAddress_Call{Call: _e.mock.On("SourcePriceRegistryAddress", ctx)}
+}
+
+func (_c *OnRampReader_SourcePriceRegistryAddress_Call) Run(run func(ctx context.Context)) *OnRampReader_SourcePriceRegistryAddress_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *OnRampReader_SourcePriceRegistryAddress_Call) Return(_a0 ccip.Address, _a1 error) *OnRampReader_SourcePriceRegistryAddress_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *OnRampReader_SourcePriceRegistryAddress_Call) RunAndReturn(run func(context.Context) (ccip.Address, error)) *OnRampReader_SourcePriceRegistryAddress_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewOnRampReader creates a new instance of OnRampReader. 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 NewOnRampReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *OnRampReader {
+ mock := &OnRampReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/price_registry_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/price_registry_reader_mock.go
new file mode 100644
index 00000000000..94e354acb25
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/price_registry_reader_mock.go
@@ -0,0 +1,498 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+
+ time "time"
+)
+
+// PriceRegistryReader is an autogenerated mock type for the PriceRegistryReader type
+type PriceRegistryReader struct {
+ mock.Mock
+}
+
+type PriceRegistryReader_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *PriceRegistryReader) EXPECT() *PriceRegistryReader_Expecter {
+ return &PriceRegistryReader_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields: ctx
+func (_m *PriceRegistryReader) Address(ctx context.Context) (ccip.Address, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (ccip.Address, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) ccip.Address); ok {
+ r0 = rf(ctx)
+ } else {
+ r0 = ret.Get(0).(ccip.Address)
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryReader_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type PriceRegistryReader_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *PriceRegistryReader_Expecter) Address(ctx interface{}) *PriceRegistryReader_Address_Call {
+ return &PriceRegistryReader_Address_Call{Call: _e.mock.On("Address", ctx)}
+}
+
+func (_c *PriceRegistryReader_Address_Call) Run(run func(ctx context.Context)) *PriceRegistryReader_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryReader_Address_Call) Return(_a0 ccip.Address, _a1 error) *PriceRegistryReader_Address_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryReader_Address_Call) RunAndReturn(run func(context.Context) (ccip.Address, error)) *PriceRegistryReader_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Close provides a mock function with given fields:
+func (_m *PriceRegistryReader) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// PriceRegistryReader_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type PriceRegistryReader_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *PriceRegistryReader_Expecter) Close() *PriceRegistryReader_Close_Call {
+ return &PriceRegistryReader_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *PriceRegistryReader_Close_Call) Run(run func()) *PriceRegistryReader_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *PriceRegistryReader_Close_Call) Return(_a0 error) *PriceRegistryReader_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *PriceRegistryReader_Close_Call) RunAndReturn(run func() error) *PriceRegistryReader_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetAllGasPriceUpdatesCreatedAfter provides a mock function with given fields: ctx, ts, confirmations
+func (_m *PriceRegistryReader) GetAllGasPriceUpdatesCreatedAfter(ctx context.Context, ts time.Time, confirmations int) ([]ccip.GasPriceUpdateWithTxMeta, error) {
+ ret := _m.Called(ctx, ts, confirmations)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetAllGasPriceUpdatesCreatedAfter")
+ }
+
+ var r0 []ccip.GasPriceUpdateWithTxMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, time.Time, int) ([]ccip.GasPriceUpdateWithTxMeta, error)); ok {
+ return rf(ctx, ts, confirmations)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, time.Time, int) []ccip.GasPriceUpdateWithTxMeta); ok {
+ r0 = rf(ctx, ts, confirmations)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.GasPriceUpdateWithTxMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, time.Time, int) error); ok {
+ r1 = rf(ctx, ts, confirmations)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllGasPriceUpdatesCreatedAfter'
+type PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call struct {
+ *mock.Call
+}
+
+// GetAllGasPriceUpdatesCreatedAfter is a helper method to define mock.On call
+// - ctx context.Context
+// - ts time.Time
+// - confirmations int
+func (_e *PriceRegistryReader_Expecter) GetAllGasPriceUpdatesCreatedAfter(ctx interface{}, ts interface{}, confirmations interface{}) *PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call {
+ return &PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call{Call: _e.mock.On("GetAllGasPriceUpdatesCreatedAfter", ctx, ts, confirmations)}
+}
+
+func (_c *PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call) Run(run func(ctx context.Context, ts time.Time, confirmations int)) *PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(time.Time), args[2].(int))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call) Return(_a0 []ccip.GasPriceUpdateWithTxMeta, _a1 error) *PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call) RunAndReturn(run func(context.Context, time.Time, int) ([]ccip.GasPriceUpdateWithTxMeta, error)) *PriceRegistryReader_GetAllGasPriceUpdatesCreatedAfter_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetFeeTokens provides a mock function with given fields: ctx
+func (_m *PriceRegistryReader) GetFeeTokens(ctx context.Context) ([]ccip.Address, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetFeeTokens")
+ }
+
+ var r0 []ccip.Address
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) ([]ccip.Address, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) []ccip.Address); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryReader_GetFeeTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFeeTokens'
+type PriceRegistryReader_GetFeeTokens_Call struct {
+ *mock.Call
+}
+
+// GetFeeTokens is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *PriceRegistryReader_Expecter) GetFeeTokens(ctx interface{}) *PriceRegistryReader_GetFeeTokens_Call {
+ return &PriceRegistryReader_GetFeeTokens_Call{Call: _e.mock.On("GetFeeTokens", ctx)}
+}
+
+func (_c *PriceRegistryReader_GetFeeTokens_Call) Run(run func(ctx context.Context)) *PriceRegistryReader_GetFeeTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetFeeTokens_Call) Return(_a0 []ccip.Address, _a1 error) *PriceRegistryReader_GetFeeTokens_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetFeeTokens_Call) RunAndReturn(run func(context.Context) ([]ccip.Address, error)) *PriceRegistryReader_GetFeeTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetGasPriceUpdatesCreatedAfter provides a mock function with given fields: ctx, chainSelector, ts, confirmations
+func (_m *PriceRegistryReader) GetGasPriceUpdatesCreatedAfter(ctx context.Context, chainSelector uint64, ts time.Time, confirmations int) ([]ccip.GasPriceUpdateWithTxMeta, error) {
+ ret := _m.Called(ctx, chainSelector, ts, confirmations)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGasPriceUpdatesCreatedAfter")
+ }
+
+ var r0 []ccip.GasPriceUpdateWithTxMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, time.Time, int) ([]ccip.GasPriceUpdateWithTxMeta, error)); ok {
+ return rf(ctx, chainSelector, ts, confirmations)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, time.Time, int) []ccip.GasPriceUpdateWithTxMeta); ok {
+ r0 = rf(ctx, chainSelector, ts, confirmations)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.GasPriceUpdateWithTxMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint64, time.Time, int) error); ok {
+ r1 = rf(ctx, chainSelector, ts, confirmations)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGasPriceUpdatesCreatedAfter'
+type PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call struct {
+ *mock.Call
+}
+
+// GetGasPriceUpdatesCreatedAfter is a helper method to define mock.On call
+// - ctx context.Context
+// - chainSelector uint64
+// - ts time.Time
+// - confirmations int
+func (_e *PriceRegistryReader_Expecter) GetGasPriceUpdatesCreatedAfter(ctx interface{}, chainSelector interface{}, ts interface{}, confirmations interface{}) *PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call {
+ return &PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call{Call: _e.mock.On("GetGasPriceUpdatesCreatedAfter", ctx, chainSelector, ts, confirmations)}
+}
+
+func (_c *PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call) Run(run func(ctx context.Context, chainSelector uint64, ts time.Time, confirmations int)) *PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint64), args[2].(time.Time), args[3].(int))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call) Return(_a0 []ccip.GasPriceUpdateWithTxMeta, _a1 error) *PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call) RunAndReturn(run func(context.Context, uint64, time.Time, int) ([]ccip.GasPriceUpdateWithTxMeta, error)) *PriceRegistryReader_GetGasPriceUpdatesCreatedAfter_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenPriceUpdatesCreatedAfter provides a mock function with given fields: ctx, ts, confirmations
+func (_m *PriceRegistryReader) GetTokenPriceUpdatesCreatedAfter(ctx context.Context, ts time.Time, confirmations int) ([]ccip.TokenPriceUpdateWithTxMeta, error) {
+ ret := _m.Called(ctx, ts, confirmations)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenPriceUpdatesCreatedAfter")
+ }
+
+ var r0 []ccip.TokenPriceUpdateWithTxMeta
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, time.Time, int) ([]ccip.TokenPriceUpdateWithTxMeta, error)); ok {
+ return rf(ctx, ts, confirmations)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, time.Time, int) []ccip.TokenPriceUpdateWithTxMeta); ok {
+ r0 = rf(ctx, ts, confirmations)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.TokenPriceUpdateWithTxMeta)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, time.Time, int) error); ok {
+ r1 = rf(ctx, ts, confirmations)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenPriceUpdatesCreatedAfter'
+type PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call struct {
+ *mock.Call
+}
+
+// GetTokenPriceUpdatesCreatedAfter is a helper method to define mock.On call
+// - ctx context.Context
+// - ts time.Time
+// - confirmations int
+func (_e *PriceRegistryReader_Expecter) GetTokenPriceUpdatesCreatedAfter(ctx interface{}, ts interface{}, confirmations interface{}) *PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call {
+ return &PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call{Call: _e.mock.On("GetTokenPriceUpdatesCreatedAfter", ctx, ts, confirmations)}
+}
+
+func (_c *PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call) Run(run func(ctx context.Context, ts time.Time, confirmations int)) *PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(time.Time), args[2].(int))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call) Return(_a0 []ccip.TokenPriceUpdateWithTxMeta, _a1 error) *PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call) RunAndReturn(run func(context.Context, time.Time, int) ([]ccip.TokenPriceUpdateWithTxMeta, error)) *PriceRegistryReader_GetTokenPriceUpdatesCreatedAfter_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokenPrices provides a mock function with given fields: ctx, wantedTokens
+func (_m *PriceRegistryReader) GetTokenPrices(ctx context.Context, wantedTokens []ccip.Address) ([]ccip.TokenPriceUpdate, error) {
+ ret := _m.Called(ctx, wantedTokens)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokenPrices")
+ }
+
+ var r0 []ccip.TokenPriceUpdate
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) ([]ccip.TokenPriceUpdate, error)); ok {
+ return rf(ctx, wantedTokens)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) []ccip.TokenPriceUpdate); ok {
+ r0 = rf(ctx, wantedTokens)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.TokenPriceUpdate)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []ccip.Address) error); ok {
+ r1 = rf(ctx, wantedTokens)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryReader_GetTokenPrices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokenPrices'
+type PriceRegistryReader_GetTokenPrices_Call struct {
+ *mock.Call
+}
+
+// GetTokenPrices is a helper method to define mock.On call
+// - ctx context.Context
+// - wantedTokens []ccip.Address
+func (_e *PriceRegistryReader_Expecter) GetTokenPrices(ctx interface{}, wantedTokens interface{}) *PriceRegistryReader_GetTokenPrices_Call {
+ return &PriceRegistryReader_GetTokenPrices_Call{Call: _e.mock.On("GetTokenPrices", ctx, wantedTokens)}
+}
+
+func (_c *PriceRegistryReader_GetTokenPrices_Call) Run(run func(ctx context.Context, wantedTokens []ccip.Address)) *PriceRegistryReader_GetTokenPrices_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]ccip.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetTokenPrices_Call) Return(_a0 []ccip.TokenPriceUpdate, _a1 error) *PriceRegistryReader_GetTokenPrices_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetTokenPrices_Call) RunAndReturn(run func(context.Context, []ccip.Address) ([]ccip.TokenPriceUpdate, error)) *PriceRegistryReader_GetTokenPrices_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetTokensDecimals provides a mock function with given fields: ctx, tokenAddresses
+func (_m *PriceRegistryReader) GetTokensDecimals(ctx context.Context, tokenAddresses []ccip.Address) ([]uint8, error) {
+ ret := _m.Called(ctx, tokenAddresses)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetTokensDecimals")
+ }
+
+ var r0 []uint8
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) ([]uint8, error)); ok {
+ return rf(ctx, tokenAddresses)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) []uint8); ok {
+ r0 = rf(ctx, tokenAddresses)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]uint8)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []ccip.Address) error); ok {
+ r1 = rf(ctx, tokenAddresses)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// PriceRegistryReader_GetTokensDecimals_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTokensDecimals'
+type PriceRegistryReader_GetTokensDecimals_Call struct {
+ *mock.Call
+}
+
+// GetTokensDecimals is a helper method to define mock.On call
+// - ctx context.Context
+// - tokenAddresses []ccip.Address
+func (_e *PriceRegistryReader_Expecter) GetTokensDecimals(ctx interface{}, tokenAddresses interface{}) *PriceRegistryReader_GetTokensDecimals_Call {
+ return &PriceRegistryReader_GetTokensDecimals_Call{Call: _e.mock.On("GetTokensDecimals", ctx, tokenAddresses)}
+}
+
+func (_c *PriceRegistryReader_GetTokensDecimals_Call) Run(run func(ctx context.Context, tokenAddresses []ccip.Address)) *PriceRegistryReader_GetTokensDecimals_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]ccip.Address))
+ })
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetTokensDecimals_Call) Return(_a0 []uint8, _a1 error) *PriceRegistryReader_GetTokensDecimals_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *PriceRegistryReader_GetTokensDecimals_Call) RunAndReturn(run func(context.Context, []ccip.Address) ([]uint8, error)) *PriceRegistryReader_GetTokensDecimals_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewPriceRegistryReader creates a new instance of PriceRegistryReader. 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 NewPriceRegistryReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *PriceRegistryReader {
+ mock := &PriceRegistryReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/token_pool_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/token_pool_reader_mock.go
new file mode 100644
index 00000000000..0bb23b9cc23
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/token_pool_reader_mock.go
@@ -0,0 +1,127 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ common "github.com/ethereum/go-ethereum/common"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// TokenPoolReader is an autogenerated mock type for the TokenPoolReader type
+type TokenPoolReader struct {
+ mock.Mock
+}
+
+type TokenPoolReader_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *TokenPoolReader) EXPECT() *TokenPoolReader_Expecter {
+ return &TokenPoolReader_Expecter{mock: &_m.Mock}
+}
+
+// Address provides a mock function with given fields:
+func (_m *TokenPoolReader) Address() common.Address {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Address")
+ }
+
+ var r0 common.Address
+ if rf, ok := ret.Get(0).(func() common.Address); ok {
+ r0 = rf()
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(common.Address)
+ }
+ }
+
+ return r0
+}
+
+// TokenPoolReader_Address_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Address'
+type TokenPoolReader_Address_Call struct {
+ *mock.Call
+}
+
+// Address is a helper method to define mock.On call
+func (_e *TokenPoolReader_Expecter) Address() *TokenPoolReader_Address_Call {
+ return &TokenPoolReader_Address_Call{Call: _e.mock.On("Address")}
+}
+
+func (_c *TokenPoolReader_Address_Call) Run(run func()) *TokenPoolReader_Address_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *TokenPoolReader_Address_Call) Return(_a0 common.Address) *TokenPoolReader_Address_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *TokenPoolReader_Address_Call) RunAndReturn(run func() common.Address) *TokenPoolReader_Address_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Type provides a mock function with given fields:
+func (_m *TokenPoolReader) Type() string {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Type")
+ }
+
+ var r0 string
+ if rf, ok := ret.Get(0).(func() string); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Get(0).(string)
+ }
+
+ return r0
+}
+
+// TokenPoolReader_Type_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Type'
+type TokenPoolReader_Type_Call struct {
+ *mock.Call
+}
+
+// Type is a helper method to define mock.On call
+func (_e *TokenPoolReader_Expecter) Type() *TokenPoolReader_Type_Call {
+ return &TokenPoolReader_Type_Call{Call: _e.mock.On("Type")}
+}
+
+func (_c *TokenPoolReader_Type_Call) Run(run func()) *TokenPoolReader_Type_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *TokenPoolReader_Type_Call) Return(_a0 string) *TokenPoolReader_Type_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *TokenPoolReader_Type_Call) RunAndReturn(run func() string) *TokenPoolReader_Type_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewTokenPoolReader creates a new instance of TokenPoolReader. 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 NewTokenPoolReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *TokenPoolReader {
+ mock := &TokenPoolReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/usdc_reader_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/usdc_reader_mock.go
new file mode 100644
index 00000000000..ac72d599923
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks/usdc_reader_mock.go
@@ -0,0 +1,97 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// USDCReader is an autogenerated mock type for the USDCReader type
+type USDCReader struct {
+ mock.Mock
+}
+
+type USDCReader_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *USDCReader) EXPECT() *USDCReader_Expecter {
+ return &USDCReader_Expecter{mock: &_m.Mock}
+}
+
+// GetUSDCMessagePriorToLogIndexInTx provides a mock function with given fields: ctx, logIndex, usdcTokenIndexOffset, txHash
+func (_m *USDCReader) GetUSDCMessagePriorToLogIndexInTx(ctx context.Context, logIndex int64, usdcTokenIndexOffset int, txHash string) ([]byte, error) {
+ ret := _m.Called(ctx, logIndex, usdcTokenIndexOffset, txHash)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetUSDCMessagePriorToLogIndexInTx")
+ }
+
+ var r0 []byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, int64, int, string) ([]byte, error)); ok {
+ return rf(ctx, logIndex, usdcTokenIndexOffset, txHash)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, int64, int, string) []byte); ok {
+ r0 = rf(ctx, logIndex, usdcTokenIndexOffset, txHash)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, int64, int, string) error); ok {
+ r1 = rf(ctx, logIndex, usdcTokenIndexOffset, txHash)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUSDCMessagePriorToLogIndexInTx'
+type USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call struct {
+ *mock.Call
+}
+
+// GetUSDCMessagePriorToLogIndexInTx is a helper method to define mock.On call
+// - ctx context.Context
+// - logIndex int64
+// - usdcTokenIndexOffset int
+// - txHash string
+func (_e *USDCReader_Expecter) GetUSDCMessagePriorToLogIndexInTx(ctx interface{}, logIndex interface{}, usdcTokenIndexOffset interface{}, txHash interface{}) *USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call {
+ return &USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call{Call: _e.mock.On("GetUSDCMessagePriorToLogIndexInTx", ctx, logIndex, usdcTokenIndexOffset, txHash)}
+}
+
+func (_c *USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call) Run(run func(ctx context.Context, logIndex int64, usdcTokenIndexOffset int, txHash string)) *USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(int64), args[2].(int), args[3].(string))
+ })
+ return _c
+}
+
+func (_c *USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call) Return(_a0 []byte, _a1 error) *USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call) RunAndReturn(run func(context.Context, int64, int, string) ([]byte, error)) *USDCReader_GetUSDCMessagePriorToLogIndexInTx_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewUSDCReader creates a new instance of USDCReader. 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 NewUSDCReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *USDCReader {
+ mock := &USDCReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader.go
new file mode 100644
index 00000000000..c3bad6235b3
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader.go
@@ -0,0 +1,13 @@
+package ccipdata
+
+import (
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+const (
+ ManuallyExecute = "manuallyExecute"
+)
+
+type OffRampReader interface {
+ cciptypes.OffRampReader
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go
new file mode 100644
index 00000000000..7a13e20cbab
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/offramp_reader_test.go
@@ -0,0 +1,416 @@
+package ccipdata_test
+
+import (
+ "math/big"
+ "math/rand"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_helper"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+)
+
+type offRampReaderTH struct {
+ user *bind.TransactOpts
+ reader ccipdata.OffRampReader
+}
+
+func TestExecOnchainConfig100(t *testing.T) {
+ tests := []struct {
+ name string
+ want v1_0_0.ExecOnchainConfig
+ expectErr bool
+ }{
+ {
+ name: "encodes and decodes config with all fields set",
+ want: v1_0_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: rand.Uint32(),
+ Router: utils.RandomAddress(),
+ PriceRegistry: utils.RandomAddress(),
+ MaxTokensLength: uint16(rand.Uint32()),
+ MaxDataSize: rand.Uint32(),
+ },
+ },
+ {
+ name: "encodes and fails decoding config with missing fields",
+ want: v1_0_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: rand.Uint32(),
+ MaxDataSize: rand.Uint32(),
+ },
+ expectErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ encoded, err := abihelpers.EncodeAbiStruct(tt.want)
+ require.NoError(t, err)
+
+ decoded, err := abihelpers.DecodeAbiStruct[v1_0_0.ExecOnchainConfig](encoded)
+ if tt.expectErr {
+ require.ErrorContains(t, err, "must set")
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.want, decoded)
+ }
+ })
+ }
+}
+
+func TestExecOnchainConfig120(t *testing.T) {
+ tests := []struct {
+ name string
+ want v1_2_0.ExecOnchainConfig
+ expectErr bool
+ }{
+ {
+ name: "encodes and decodes config with all fields set",
+ want: v1_2_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: rand.Uint32(),
+ Router: utils.RandomAddress(),
+ PriceRegistry: utils.RandomAddress(),
+ MaxNumberOfTokensPerMsg: uint16(rand.Uint32()),
+ MaxDataBytes: rand.Uint32(),
+ MaxPoolReleaseOrMintGas: rand.Uint32(),
+ },
+ },
+ {
+ name: "encodes and fails decoding config with missing fields",
+ want: v1_2_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: rand.Uint32(),
+ MaxDataBytes: rand.Uint32(),
+ },
+ expectErr: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ encoded, err := abihelpers.EncodeAbiStruct(tt.want)
+ require.NoError(t, err)
+
+ decoded, err := abihelpers.DecodeAbiStruct[v1_2_0.ExecOnchainConfig](encoded)
+ if tt.expectErr {
+ require.ErrorContains(t, err, "must set")
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tt.want, decoded)
+ }
+ })
+ }
+}
+
+func TestOffRampReaderInit(t *testing.T) {
+ tests := []struct {
+ name string
+ version string
+ }{
+ {
+ name: "OffRampReader_V1_0_0",
+ version: ccipdata.V1_0_0,
+ },
+ {
+ name: "OffRampReader_V1_1_0",
+ version: ccipdata.V1_1_0,
+ },
+ {
+ name: "OffRampReader_V1_2_0",
+ version: ccipdata.V1_2_0,
+ },
+ {
+ name: "OffRampReader_V1_5_0",
+ version: ccipdata.V1_5_0,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ th := setupOffRampReaderTH(t, test.version)
+ testOffRampReader(t, th)
+ })
+ }
+}
+
+func setupOffRampReaderTH(t *testing.T, version string) offRampReaderTH {
+ ctx := testutils.Context(t)
+ user, bc := ccipdata.NewSimulation(t)
+ log := logger.Test(t)
+ orm := logpoller.NewORM(testutils.SimulatedChainID, pgtest.NewSqlxDB(t), log)
+ lpOpts := logpoller.Opts{
+ PollPeriod: 100 * time.Millisecond,
+ FinalityDepth: 2,
+ BackfillBatchSize: 3,
+ RpcBatchSize: 2,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+ headTracker := headtracker.NewSimulatedHeadTracker(bc, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ if lpOpts.PollPeriod == 0 {
+ lpOpts.PollPeriod = 1 * time.Hour
+ }
+ lp := logpoller.NewLogPoller(
+ orm,
+ bc,
+ log,
+ headTracker,
+ lpOpts)
+ assert.NoError(t, orm.InsertBlock(ctx, common.Hash{}, 1, time.Now(), 1))
+ // Setup offRamp.
+ var offRampAddress common.Address
+ switch version {
+ case ccipdata.V1_0_0:
+ offRampAddress = setupOffRampV1_0_0(t, user, bc)
+ case ccipdata.V1_1_0:
+ // Version 1.1.0 uses the same contracts as 1.0.0.
+ offRampAddress = setupOffRampV1_0_0(t, user, bc)
+ case ccipdata.V1_2_0:
+ offRampAddress = setupOffRampV1_2_0(t, user, bc)
+ case ccipdata.V1_5_0:
+ offRampAddress = setupOffRampV1_5_0(t, user, bc)
+ default:
+ require.Fail(t, "Unknown version: ", version)
+ }
+
+ // Create the version-specific reader.
+ reader, err := factory.NewOffRampReader(log, factory.NewEvmVersionFinder(), ccipcalc.EvmAddrToGeneric(offRampAddress), bc, lp, nil, nil, true)
+ require.NoError(t, err)
+ addr, err := reader.Address(ctx)
+ require.NoError(t, err)
+ require.Equal(t, ccipcalc.EvmAddrToGeneric(offRampAddress), addr)
+
+ return offRampReaderTH{
+ user: user,
+ reader: reader,
+ }
+}
+
+func setupOffRampV1_0_0(t *testing.T, user *bind.TransactOpts, bc *client.SimulatedBackendClient) common.Address {
+ onRampAddr := utils.RandomAddress()
+ armAddr := deployMockArm(t, user, bc)
+ csAddr := deployCommitStore(t, user, bc, onRampAddr, armAddr)
+
+ // Deploy the OffRamp.
+ staticConfig := evm_2_evm_offramp_1_0_0.EVM2EVMOffRampStaticConfig{
+ CommitStore: csAddr,
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ SourceChainSelector: testutils.SimulatedChainID.Uint64(),
+ OnRamp: onRampAddr,
+ PrevOffRamp: common.Address{},
+ ArmProxy: armAddr,
+ }
+ sourceTokens := []common.Address{}
+ pools := []common.Address{}
+ rateLimiterConfig := evm_2_evm_offramp_1_0_0.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(0),
+ Rate: big.NewInt(0),
+ }
+
+ offRampAddr, tx, offRamp, err := evm_2_evm_offramp_1_0_0.DeployEVM2EVMOffRamp(user, bc, staticConfig, sourceTokens, pools, rateLimiterConfig)
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, tx, bc, user)
+
+ // Verify the deployed OffRamp.
+ tav, err := offRamp.TypeAndVersion(&bind.CallOpts{
+ Context: testutils.Context(t),
+ })
+ require.NoError(t, err)
+ require.Equal(t, "EVM2EVMOffRamp 1.0.0", tav)
+ return offRampAddr
+}
+
+func setupOffRampV1_2_0(t *testing.T, user *bind.TransactOpts, bc *client.SimulatedBackendClient) common.Address {
+ onRampAddr := utils.RandomAddress()
+ armAddr := deployMockArm(t, user, bc)
+ csAddr := deployCommitStore(t, user, bc, onRampAddr, armAddr)
+
+ // Deploy the OffRamp.
+ staticConfig := evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig{
+ CommitStore: csAddr,
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ SourceChainSelector: testutils.SimulatedChainID.Uint64(),
+ OnRamp: onRampAddr,
+ PrevOffRamp: common.Address{},
+ ArmProxy: armAddr,
+ }
+ sourceTokens := []common.Address{}
+ pools := []common.Address{}
+ rateLimiterConfig := evm_2_evm_offramp_1_2_0.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(0),
+ Rate: big.NewInt(0),
+ }
+
+ offRampAddr, tx, offRamp, err := evm_2_evm_offramp_1_2_0.DeployEVM2EVMOffRamp(user, bc, staticConfig, sourceTokens, pools, rateLimiterConfig)
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, tx, bc, user)
+
+ // Verify the deployed OffRamp.
+ tav, err := offRamp.TypeAndVersion(&bind.CallOpts{
+ Context: testutils.Context(t),
+ })
+ require.NoError(t, err)
+ require.Equal(t, "EVM2EVMOffRamp 1.2.0", tav)
+ return offRampAddr
+}
+
+func setupOffRampV1_5_0(t *testing.T, user *bind.TransactOpts, bc *client.SimulatedBackendClient) common.Address {
+ onRampAddr := utils.RandomAddress()
+ tokenAdminRegAddr := utils.RandomAddress()
+ rmnAddr := deployMockArm(t, user, bc)
+ csAddr := deployCommitStore(t, user, bc, onRampAddr, rmnAddr)
+
+ // Deploy the OffRamp.
+ staticConfig := evm_2_evm_offramp.EVM2EVMOffRampStaticConfig{
+ CommitStore: csAddr,
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ SourceChainSelector: testutils.SimulatedChainID.Uint64(),
+ OnRamp: onRampAddr,
+ PrevOffRamp: common.Address{},
+ RmnProxy: rmnAddr,
+ TokenAdminRegistry: tokenAdminRegAddr,
+ }
+ rateLimiterConfig := evm_2_evm_offramp.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(0),
+ Rate: big.NewInt(0),
+ }
+
+ offRampAddr, tx, offRamp, err := evm_2_evm_offramp.DeployEVM2EVMOffRamp(user, bc, staticConfig, rateLimiterConfig)
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, tx, bc, user)
+
+ // Verify the deployed OffRamp.
+ tav, err := offRamp.TypeAndVersion(&bind.CallOpts{
+ Context: testutils.Context(t),
+ })
+ require.NoError(t, err)
+ require.Equal(t, "EVM2EVMOffRamp 1.5.0-dev", tav)
+ return offRampAddr
+}
+
+func deployMockArm(
+ t *testing.T,
+ user *bind.TransactOpts,
+ bc *client.SimulatedBackendClient,
+) common.Address {
+ armAddr, tx, _, err := mock_arm_contract.DeployMockARMContract(user, bc)
+ require.NoError(t, err)
+ bc.Commit()
+ ccipdata.AssertNonRevert(t, tx, bc, user)
+ require.NotEqual(t, common.Address{}, armAddr)
+ return armAddr
+}
+
+// Deploy the CommitStore. We use the same CommitStore version for all versions of OffRamp tested.
+func deployCommitStore(
+ t *testing.T,
+ user *bind.TransactOpts,
+ bc *client.SimulatedBackendClient,
+ onRampAddress common.Address,
+ armAddress common.Address,
+) common.Address {
+ // Deploy the CommitStore using the helper.
+ csAddr, tx, cs, err := commit_store_helper.DeployCommitStoreHelper(user, bc, commit_store_helper.CommitStoreStaticConfig{
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ SourceChainSelector: testutils.SimulatedChainID.Uint64(),
+ OnRamp: onRampAddress,
+ RmnProxy: armAddress,
+ })
+ require.NoError(t, err)
+ bc.Commit()
+ ccipdata.AssertNonRevert(t, tx, bc, user)
+
+ // Test the deployed CommitStore.
+ callOpts := &bind.CallOpts{
+ Context: testutils.Context(t),
+ }
+ tav, err := cs.TypeAndVersion(callOpts)
+ require.NoError(t, err)
+ require.Equal(t, "CommitStore 1.5.0-dev", tav)
+ return csAddr
+}
+
+func testOffRampReader(t *testing.T, th offRampReaderTH) {
+ ctx := th.user.Context
+ tokens, err := th.reader.GetTokens(ctx)
+ require.NoError(t, err)
+ require.Equal(t, []cciptypes.Address{}, tokens.DestinationTokens)
+
+ events, err := th.reader.GetExecutionStateChangesBetweenSeqNums(ctx, 0, 10, 0)
+ require.NoError(t, err)
+ require.Equal(t, []cciptypes.ExecutionStateChangedWithTxMeta{}, events)
+
+ sourceToDestTokens, err := th.reader.GetSourceToDestTokensMapping(ctx)
+ require.NoError(t, err)
+ require.Empty(t, sourceToDestTokens)
+
+ require.NoError(t, err)
+}
+
+func TestNewOffRampReader(t *testing.T) {
+ var tt = []struct {
+ typeAndVersion string
+ expectedErr string
+ }{
+ {
+ typeAndVersion: "blah",
+ expectedErr: "unable to read type and version: invalid type and version blah",
+ },
+ {
+ typeAndVersion: "CommitStore 1.0.0",
+ expectedErr: "expected EVM2EVMOffRamp got CommitStore",
+ },
+ {
+ typeAndVersion: "EVM2EVMOffRamp 1.2.0",
+ expectedErr: "",
+ },
+ {
+ typeAndVersion: "EVM2EVMOffRamp 2.0.0",
+ expectedErr: "unsupported offramp version 2.0.0",
+ },
+ }
+ for _, tc := range tt {
+ t.Run(tc.typeAndVersion, func(t *testing.T) {
+ b, err := utils.ABIEncode(`[{"type":"string"}]`, tc.typeAndVersion)
+ require.NoError(t, err)
+ c := evmclientmocks.NewClient(t)
+ c.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(b, nil)
+ addr := ccipcalc.EvmAddrToGeneric(utils.RandomAddress())
+ lp := lpmocks.NewLogPoller(t)
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil).Maybe()
+ _, err = factory.NewOffRampReader(logger.Test(t), factory.NewEvmVersionFinder(), addr, c, lp, nil, nil, true)
+ if tc.expectedErr != "" {
+ assert.EqualError(t, err, tc.expectedErr)
+ } else {
+ assert.NoError(t, err)
+ }
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader.go
new file mode 100644
index 00000000000..e2571de57f6
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader.go
@@ -0,0 +1,21 @@
+package ccipdata
+
+import (
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+type LeafHasherInterface[H hashutil.Hash] interface {
+ HashLeaf(log types.Log) (H, error)
+}
+
+const (
+ COMMIT_CCIP_SENDS = "Commit ccip sends"
+ CONFIG_CHANGED = "Dynamic config changed"
+)
+
+type OnRampReader interface {
+ cciptypes.OnRampReader
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go
new file mode 100644
index 00000000000..2f0ccbc246c
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/onramp_reader_test.go
@@ -0,0 +1,479 @@
+package ccipdata_test
+
+import (
+ "fmt"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_1_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+)
+
+type onRampReaderTH struct {
+ user *bind.TransactOpts
+ reader ccipdata.OnRampReader
+}
+
+func TestNewOnRampReader_noContractAtAddress(t *testing.T) {
+ _, bc := ccipdata.NewSimulation(t)
+ addr := ccipcalc.EvmAddrToGeneric(utils.RandomAddress())
+ _, err := factory.NewOnRampReader(logger.Test(t), factory.NewEvmVersionFinder(), testutils.SimulatedChainID.Uint64(), testutils.SimulatedChainID.Uint64(), addr, lpmocks.NewLogPoller(t), bc)
+ assert.EqualError(t, err, fmt.Sprintf("unable to read type and version: error calling typeAndVersion on addr: %s no contract code at given address", addr))
+}
+
+func TestOnRampReaderInit(t *testing.T) {
+ tests := []struct {
+ name string
+ version string
+ }{
+ {
+ name: "OnRampReader_V1_0_0",
+ version: ccipdata.V1_0_0,
+ },
+ {
+ name: "OnRampReader_V1_1_0",
+ version: ccipdata.V1_1_0,
+ },
+ {
+ name: "OnRampReader_V1_2_0",
+ version: ccipdata.V1_2_0,
+ },
+ {
+ name: "OnRampReader_V1_5_0",
+ version: ccipdata.V1_5_0,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ th := setupOnRampReaderTH(t, test.version)
+ testVersionSpecificOnRampReader(t, th, test.version)
+ })
+ }
+}
+
+func setupOnRampReaderTH(t *testing.T, version string) onRampReaderTH {
+ user, bc := ccipdata.NewSimulation(t)
+ log := logger.Test(t)
+ orm := logpoller.NewORM(testutils.SimulatedChainID, pgtest.NewSqlxDB(t), log)
+ lpOpts := logpoller.Opts{
+ PollPeriod: 100 * time.Millisecond,
+ FinalityDepth: 2,
+ BackfillBatchSize: 3,
+ RpcBatchSize: 2,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+ headTracker := headtracker.NewSimulatedHeadTracker(bc, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ if lpOpts.PollPeriod == 0 {
+ lpOpts.PollPeriod = 1 * time.Hour
+ }
+ lp := logpoller.NewLogPoller(
+ orm,
+ bc,
+ log,
+ headTracker,
+ lpOpts)
+
+ // Setup onRamp.
+ var onRampAddress common.Address
+ switch version {
+ case ccipdata.V1_0_0:
+ onRampAddress = setupOnRampV1_0_0(t, user, bc)
+ case ccipdata.V1_1_0:
+ onRampAddress = setupOnRampV1_1_0(t, user, bc)
+ case ccipdata.V1_2_0:
+ onRampAddress = setupOnRampV1_2_0(t, user, bc)
+ case ccipdata.V1_5_0:
+ onRampAddress = setupOnRampV1_5_0(t, user, bc)
+ default:
+ require.Fail(t, "Unknown version: ", version)
+ }
+
+ // Create the version-specific reader.
+ reader, err := factory.NewOnRampReader(log, factory.NewEvmVersionFinder(), testutils.SimulatedChainID.Uint64(), testutils.SimulatedChainID.Uint64(), ccipcalc.EvmAddrToGeneric(onRampAddress), lp, bc)
+ require.NoError(t, err)
+
+ return onRampReaderTH{
+ user: user,
+ reader: reader,
+ }
+}
+
+func setupOnRampV1_0_0(t *testing.T, user *bind.TransactOpts, bc *client.SimulatedBackendClient) common.Address {
+ linkTokenAddress := common.HexToAddress("0x000011")
+ staticConfig := evm_2_evm_onramp_1_0_0.EVM2EVMOnRampStaticConfig{
+ LinkToken: linkTokenAddress,
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ DestChainSelector: testutils.SimulatedChainID.Uint64(),
+ DefaultTxGasLimit: 30000,
+ MaxNopFeesJuels: big.NewInt(1000000),
+ PrevOnRamp: common.Address{},
+ ArmProxy: utils.RandomAddress(),
+ }
+ dynamicConfig := evm_2_evm_onramp_1_0_0.EVM2EVMOnRampDynamicConfig{
+ Router: common.HexToAddress("0x000100"),
+ MaxTokensLength: 4,
+ PriceRegistry: utils.RandomAddress(),
+ MaxDataSize: 100000,
+ MaxGasLimit: 100000,
+ }
+ rateLimiterConfig := evm_2_evm_onramp_1_0_0.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(5),
+ Rate: big.NewInt(5),
+ }
+ allowList := []common.Address{user.From}
+ feeTokenConfigs := []evm_2_evm_onramp_1_0_0.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: linkTokenAddress,
+ GasMultiplier: 1,
+ NetworkFeeAmountUSD: big.NewInt(0),
+ DestGasOverhead: 50,
+ DestGasPerPayloadByte: 60,
+ Enabled: false,
+ },
+ }
+ tokenTransferConfigArgs := []evm_2_evm_onramp_1_0_0.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: utils.RandomAddress(),
+ MinFee: 10,
+ MaxFee: 1000,
+ Ratio: 1,
+ },
+ }
+ nopsAndWeights := []evm_2_evm_onramp_1_0_0.EVM2EVMOnRampNopAndWeight{
+ {
+ Nop: utils.RandomAddress(),
+ Weight: 1,
+ },
+ }
+ tokenAndPool := []evm_2_evm_onramp_1_0_0.InternalPoolUpdate{}
+ onRampAddress, transaction, _, err := evm_2_evm_onramp_1_0_0.DeployEVM2EVMOnRamp(
+ user,
+ bc,
+ staticConfig,
+ dynamicConfig,
+ tokenAndPool,
+ allowList,
+ rateLimiterConfig,
+ feeTokenConfigs,
+ tokenTransferConfigArgs,
+ nopsAndWeights,
+ )
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, transaction, bc, user)
+ return onRampAddress
+}
+
+func setupOnRampV1_1_0(t *testing.T, user *bind.TransactOpts, bc *client.SimulatedBackendClient) common.Address {
+ linkTokenAddress := common.HexToAddress("0x000011")
+ staticConfig := evm_2_evm_onramp_1_1_0.EVM2EVMOnRampStaticConfig{
+ LinkToken: linkTokenAddress,
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ DestChainSelector: testutils.SimulatedChainID.Uint64(),
+ DefaultTxGasLimit: 30000,
+ MaxNopFeesJuels: big.NewInt(1000000),
+ PrevOnRamp: common.Address{},
+ ArmProxy: utils.RandomAddress(),
+ }
+ dynamicConfig := evm_2_evm_onramp_1_1_0.EVM2EVMOnRampDynamicConfig{
+ Router: common.HexToAddress("0x000110"),
+ MaxTokensLength: 4,
+ PriceRegistry: common.HexToAddress("0x000066"),
+ MaxDataSize: 100000,
+ MaxGasLimit: 100000,
+ }
+ rateLimiterConfig := evm_2_evm_onramp_1_1_0.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(5),
+ Rate: big.NewInt(5),
+ }
+ allowList := []common.Address{user.From}
+ feeTokenConfigs := []evm_2_evm_onramp_1_1_0.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: linkTokenAddress,
+ NetworkFeeUSD: 0,
+ MinTokenTransferFeeUSD: 0,
+ MaxTokenTransferFeeUSD: 0,
+ GasMultiplier: 0,
+ PremiumMultiplier: 0,
+ Enabled: false,
+ },
+ }
+ tokenTransferConfigArgs := []evm_2_evm_onramp_1_1_0.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: linkTokenAddress,
+ Ratio: 0,
+ DestGasOverhead: 0,
+ },
+ }
+ nopsAndWeights := []evm_2_evm_onramp_1_1_0.EVM2EVMOnRampNopAndWeight{
+ {
+ Nop: common.HexToAddress("0x222222222"),
+ Weight: 1,
+ },
+ }
+ tokenAndPool := []evm_2_evm_onramp_1_1_0.InternalPoolUpdate{}
+ onRampAddress, transaction, _, err := evm_2_evm_onramp_1_1_0.DeployEVM2EVMOnRamp(
+ user,
+ bc,
+ staticConfig,
+ dynamicConfig,
+ tokenAndPool,
+ allowList,
+ rateLimiterConfig,
+ feeTokenConfigs,
+ tokenTransferConfigArgs,
+ nopsAndWeights,
+ )
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, transaction, bc, user)
+ return onRampAddress
+}
+
+func setupOnRampV1_2_0(t *testing.T, user *bind.TransactOpts, bc *client.SimulatedBackendClient) common.Address {
+ linkTokenAddress := common.HexToAddress("0x000011")
+ staticConfig := evm_2_evm_onramp_1_2_0.EVM2EVMOnRampStaticConfig{
+ LinkToken: linkTokenAddress,
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ DestChainSelector: testutils.SimulatedChainID.Uint64(),
+ DefaultTxGasLimit: 30000,
+ MaxNopFeesJuels: big.NewInt(1000000),
+ PrevOnRamp: common.Address{},
+ ArmProxy: utils.RandomAddress(),
+ }
+ dynamicConfig := evm_2_evm_onramp_1_2_0.EVM2EVMOnRampDynamicConfig{
+ Router: common.HexToAddress("0x0000000000000000000000000000000000000120"),
+ MaxNumberOfTokensPerMsg: 0,
+ DestGasOverhead: 0,
+ DestGasPerPayloadByte: 0,
+ DestDataAvailabilityOverheadGas: 0,
+ DestGasPerDataAvailabilityByte: 0,
+ DestDataAvailabilityMultiplierBps: 0,
+ PriceRegistry: utils.RandomAddress(),
+ MaxDataBytes: 0,
+ MaxPerMsgGasLimit: 0,
+ }
+ rateLimiterConfig := evm_2_evm_onramp_1_2_0.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(5),
+ Rate: big.NewInt(5),
+ }
+ feeTokenConfigs := []evm_2_evm_onramp_1_2_0.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: linkTokenAddress,
+ NetworkFeeUSDCents: 0,
+ GasMultiplierWeiPerEth: 0,
+ PremiumMultiplierWeiPerEth: 0,
+ Enabled: false,
+ },
+ }
+ tokenTransferConfigArgs := []evm_2_evm_onramp_1_2_0.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: linkTokenAddress,
+ MinFeeUSDCents: 0,
+ MaxFeeUSDCents: 0,
+ DeciBps: 0,
+ DestGasOverhead: 0,
+ DestBytesOverhead: 0,
+ },
+ }
+ nopsAndWeights := []evm_2_evm_onramp_1_2_0.EVM2EVMOnRampNopAndWeight{
+ {
+ Nop: utils.RandomAddress(),
+ Weight: 1,
+ },
+ }
+ tokenAndPool := []evm_2_evm_onramp_1_2_0.InternalPoolUpdate{}
+ onRampAddress, transaction, _, err := evm_2_evm_onramp_1_2_0.DeployEVM2EVMOnRamp(
+ user,
+ bc,
+ staticConfig,
+ dynamicConfig,
+ tokenAndPool,
+ rateLimiterConfig,
+ feeTokenConfigs,
+ tokenTransferConfigArgs,
+ nopsAndWeights,
+ )
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, transaction, bc, user)
+ return onRampAddress
+}
+
+func setupOnRampV1_5_0(t *testing.T, user *bind.TransactOpts, bc *client.SimulatedBackendClient) common.Address {
+ linkTokenAddress := common.HexToAddress("0x000011")
+ staticConfig := evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{
+ LinkToken: linkTokenAddress,
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ DestChainSelector: testutils.SimulatedChainID.Uint64(),
+ DefaultTxGasLimit: 30000,
+ MaxNopFeesJuels: big.NewInt(1000000),
+ PrevOnRamp: common.Address{},
+ RmnProxy: utils.RandomAddress(),
+ TokenAdminRegistry: utils.RandomAddress(),
+ }
+ dynamicConfig := evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig{
+ Router: common.HexToAddress("0x0000000000000000000000000000000000000150"),
+ MaxNumberOfTokensPerMsg: 0,
+ DestGasOverhead: 0,
+ DestGasPerPayloadByte: 0,
+ DestDataAvailabilityOverheadGas: 0,
+ DestGasPerDataAvailabilityByte: 0,
+ DestDataAvailabilityMultiplierBps: 0,
+ PriceRegistry: utils.RandomAddress(),
+ MaxDataBytes: 0,
+ MaxPerMsgGasLimit: 0,
+ DefaultTokenFeeUSDCents: 50,
+ DefaultTokenDestGasOverhead: 34_000,
+ DefaultTokenDestBytesOverhead: 500,
+ }
+ rateLimiterConfig := evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(5),
+ Rate: big.NewInt(5),
+ }
+ feeTokenConfigs := []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: linkTokenAddress,
+ NetworkFeeUSDCents: 0,
+ GasMultiplierWeiPerEth: 0,
+ PremiumMultiplierWeiPerEth: 0,
+ Enabled: false,
+ },
+ }
+ tokenTransferConfigArgs := []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: linkTokenAddress,
+ MinFeeUSDCents: 0,
+ MaxFeeUSDCents: 0,
+ DeciBps: 0,
+ DestGasOverhead: 0,
+ DestBytesOverhead: 64,
+ AggregateRateLimitEnabled: true,
+ },
+ }
+ nopsAndWeights := []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{
+ {
+ Nop: utils.RandomAddress(),
+ Weight: 1,
+ },
+ }
+ onRampAddress, transaction, _, err := evm_2_evm_onramp.DeployEVM2EVMOnRamp(
+ user,
+ bc,
+ staticConfig,
+ dynamicConfig,
+ rateLimiterConfig,
+ feeTokenConfigs,
+ tokenTransferConfigArgs,
+ nopsAndWeights,
+ )
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, transaction, bc, user)
+ return onRampAddress
+}
+
+func testVersionSpecificOnRampReader(t *testing.T, th onRampReaderTH, version string) {
+ switch version {
+ case ccipdata.V1_0_0:
+ testOnRampReader(t, th, common.HexToAddress("0x0000000000000000000000000000000000000100"))
+ case ccipdata.V1_1_0:
+ testOnRampReader(t, th, common.HexToAddress("0x0000000000000000000000000000000000000110"))
+ case ccipdata.V1_2_0:
+ testOnRampReader(t, th, common.HexToAddress("0x0000000000000000000000000000000000000120"))
+ case ccipdata.V1_5_0:
+ testOnRampReader(t, th, common.HexToAddress("0x0000000000000000000000000000000000000150"))
+ default:
+ require.Fail(t, "Unknown version: ", version)
+ }
+}
+
+func testOnRampReader(t *testing.T, th onRampReaderTH, expectedRouterAddress common.Address) {
+ ctx := th.user.Context
+ res, err := th.reader.RouterAddress(ctx)
+ require.NoError(t, err)
+ require.Equal(t, ccipcalc.EvmAddrToGeneric(expectedRouterAddress), res)
+
+ msg, err := th.reader.GetSendRequestsBetweenSeqNums(ctx, 0, 10, true)
+ require.NoError(t, err)
+ require.NotNil(t, msg)
+ require.Equal(t, []cciptypes.EVM2EVMMessageWithTxMeta{}, msg)
+
+ address, err := th.reader.Address(ctx)
+ require.NoError(t, err)
+ require.NotNil(t, address)
+
+ cfg, err := th.reader.GetDynamicConfig(ctx)
+ require.NoError(t, err)
+ require.NotNil(t, cfg)
+ require.Equal(t, ccipcalc.EvmAddrToGeneric(expectedRouterAddress), cfg.Router)
+}
+
+func TestNewOnRampReader(t *testing.T) {
+ var tt = []struct {
+ typeAndVersion string
+ expectedErr string
+ }{
+ {
+ typeAndVersion: "blah",
+ expectedErr: "unable to read type and version: invalid type and version blah",
+ },
+ {
+ typeAndVersion: "EVM2EVMOffRamp 1.0.0",
+ expectedErr: "expected EVM2EVMOnRamp got EVM2EVMOffRamp",
+ },
+ {
+ typeAndVersion: "EVM2EVMOnRamp 1.2.0",
+ expectedErr: "",
+ },
+ {
+ typeAndVersion: "EVM2EVMOnRamp 2.0.0",
+ expectedErr: "unsupported onramp version 2.0.0",
+ },
+ }
+ for _, tc := range tt {
+ t.Run(tc.typeAndVersion, func(t *testing.T) {
+ b, err := utils.ABIEncode(`[{"type":"string"}]`, tc.typeAndVersion)
+ require.NoError(t, err)
+ c := evmclientmocks.NewClient(t)
+ c.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(b, nil)
+ addr := ccipcalc.EvmAddrToGeneric(utils.RandomAddress())
+ lp := lpmocks.NewLogPoller(t)
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil).Maybe()
+ _, err = factory.NewOnRampReader(logger.Test(t), factory.NewEvmVersionFinder(), 1, 2, addr, lp, c)
+ if tc.expectedErr != "" {
+ require.EqualError(t, err, tc.expectedErr)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader.go
new file mode 100644
index 00000000000..02aef5e9efc
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader.go
@@ -0,0 +1,14 @@
+package ccipdata
+
+import cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+const (
+ COMMIT_PRICE_UPDATES = "Commit price updates"
+ FEE_TOKEN_ADDED = "Fee token added"
+ FEE_TOKEN_REMOVED = "Fee token removed"
+ ExecPluginLabel = "exec"
+)
+
+type PriceRegistryReader interface {
+ cciptypes.PriceRegistryReader
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go
new file mode 100644
index 00000000000..9ace6ea4819
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/price_registry_reader_test.go
@@ -0,0 +1,296 @@
+package ccipdata_test
+
+import (
+ "context"
+ "math/big"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ evmclientmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/factory"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+)
+
+type priceRegReaderTH struct {
+ lp logpoller.LogPollerTest
+ ec client.Client
+ lggr logger.Logger
+ user *bind.TransactOpts
+ readers map[string]ccipdata.PriceRegistryReader
+
+ // Expected state
+ blockTs []uint64
+ expectedFeeTokens []common.Address
+ expectedGasUpdates map[uint64][]cciptypes.GasPrice
+ expectedTokenUpdates map[uint64][]cciptypes.TokenPrice
+ destSelectors []uint64
+}
+
+func commitAndGetBlockTs(ec *client.SimulatedBackendClient) uint64 {
+ h := ec.Commit()
+ b, _ := ec.BlockByHash(context.Background(), h)
+ return b.Time()
+}
+
+func newSim(t *testing.T) (*bind.TransactOpts, *client.SimulatedBackendClient) {
+ user := testutils.MustNewSimTransactor(t)
+ sim := backends.NewSimulatedBackend(map[common.Address]core.GenesisAccount{
+ user.From: {
+ Balance: big.NewInt(0).Mul(big.NewInt(10), big.NewInt(1e18)),
+ },
+ }, 10e6)
+ ec := client.NewSimulatedBackendClient(t, sim, testutils.SimulatedChainID)
+ return user, ec
+}
+
+// setupPriceRegistryReaderTH instantiates all versions of the price registry reader
+// with a snapshot of data so reader tests can do multi-version assertions.
+func setupPriceRegistryReaderTH(t *testing.T) priceRegReaderTH {
+ user, ec := newSim(t)
+ lggr := logger.Test(t)
+ lpOpts := logpoller.Opts{
+ PollPeriod: 100 * time.Millisecond,
+ FinalityDepth: 2,
+ BackfillBatchSize: 3,
+ RpcBatchSize: 2,
+ KeepFinalizedBlocksDepth: 1000,
+ }
+ headTracker := headtracker.NewSimulatedHeadTracker(ec, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ if lpOpts.PollPeriod == 0 {
+ lpOpts.PollPeriod = 1 * time.Hour
+ }
+ // TODO: We should be able to use an in memory log poller ORM here to speed up the tests.
+ lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, pgtest.NewSqlxDB(t), lggr), ec, lggr, headTracker, lpOpts)
+
+ feeTokens := []common.Address{utils.RandomAddress(), utils.RandomAddress()}
+ dest1 := uint64(10)
+ dest2 := uint64(11)
+ gasPriceUpdatesBlock1 := []cciptypes.GasPrice{
+ {
+ DestChainSelector: dest1,
+ Value: big.NewInt(11),
+ },
+ }
+ gasPriceUpdatesBlock2 := []cciptypes.GasPrice{
+ {
+ DestChainSelector: dest1, // Reset same gas price
+ Value: big.NewInt(12), // Intentionally different from block1
+ },
+ {
+ DestChainSelector: dest2, // Set gas price for different chain
+ Value: big.NewInt(12),
+ },
+ }
+ token1 := ccipcalc.EvmAddrToGeneric(utils.RandomAddress())
+ token2 := ccipcalc.EvmAddrToGeneric(utils.RandomAddress())
+ tokenPriceUpdatesBlock1 := []cciptypes.TokenPrice{
+ {
+ Token: token1,
+ Value: big.NewInt(12),
+ },
+ }
+ tokenPriceUpdatesBlock2 := []cciptypes.TokenPrice{
+ {
+ Token: token1,
+ Value: big.NewInt(13), // Intentionally change token1 value
+ },
+ {
+ Token: token2,
+ Value: big.NewInt(12), // Intentionally set a same value different token
+ },
+ }
+ ctx := testutils.Context(t)
+ addr, _, _, err := price_registry_1_0_0.DeployPriceRegistry(user, ec, nil, feeTokens, 1000)
+ require.NoError(t, err)
+ addr2, _, _, err := price_registry_1_2_0.DeployPriceRegistry(user, ec, nil, feeTokens, 1000)
+ require.NoError(t, err)
+ commitAndGetBlockTs(ec) // Deploy these
+ pr10r, err := factory.NewPriceRegistryReader(ctx, lggr, factory.NewEvmVersionFinder(), ccipcalc.EvmAddrToGeneric(addr), lp, ec)
+ require.NoError(t, err)
+ assert.Equal(t, reflect.TypeOf(pr10r).String(), reflect.TypeOf(&v1_0_0.PriceRegistry{}).String())
+ pr12r, err := factory.NewPriceRegistryReader(ctx, lggr, factory.NewEvmVersionFinder(), ccipcalc.EvmAddrToGeneric(addr2), lp, ec)
+ require.NoError(t, err)
+ assert.Equal(t, reflect.TypeOf(pr12r).String(), reflect.TypeOf(&v1_2_0.PriceRegistry{}).String())
+ // Apply block1.
+ v1_0_0.ApplyPriceRegistryUpdate(t, user, addr, ec, gasPriceUpdatesBlock1, tokenPriceUpdatesBlock1)
+ v1_2_0.ApplyPriceRegistryUpdate(t, user, addr2, ec, gasPriceUpdatesBlock1, tokenPriceUpdatesBlock1)
+ b1 := commitAndGetBlockTs(ec)
+ // Apply block2
+ v1_0_0.ApplyPriceRegistryUpdate(t, user, addr, ec, gasPriceUpdatesBlock2, tokenPriceUpdatesBlock2)
+ v1_2_0.ApplyPriceRegistryUpdate(t, user, addr2, ec, gasPriceUpdatesBlock2, tokenPriceUpdatesBlock2)
+ b2 := commitAndGetBlockTs(ec)
+
+ // Capture all lp data.
+ lp.PollAndSaveLogs(context.Background(), 1)
+
+ return priceRegReaderTH{
+ lp: lp,
+ ec: ec,
+ lggr: lggr,
+ user: user,
+ readers: map[string]ccipdata.PriceRegistryReader{
+ ccipdata.V1_0_0: pr10r, ccipdata.V1_2_0: pr12r,
+ },
+ expectedFeeTokens: feeTokens,
+ expectedGasUpdates: map[uint64][]cciptypes.GasPrice{
+ b1: gasPriceUpdatesBlock1,
+ b2: gasPriceUpdatesBlock2,
+ },
+ expectedTokenUpdates: map[uint64][]cciptypes.TokenPrice{
+ b1: tokenPriceUpdatesBlock1,
+ b2: tokenPriceUpdatesBlock2,
+ },
+ blockTs: []uint64{b1, b2},
+ destSelectors: []uint64{dest1, dest2},
+ }
+}
+
+func testPriceRegistryReader(t *testing.T, th priceRegReaderTH, pr ccipdata.PriceRegistryReader) {
+ // Assert have expected fee tokens.
+ gotFeeTokens, err := pr.GetFeeTokens(context.Background())
+ require.NoError(t, err)
+ evmAddrs, err := ccipcalc.GenericAddrsToEvm(gotFeeTokens...)
+ require.NoError(t, err)
+ assert.Equal(t, th.expectedFeeTokens, evmAddrs)
+
+ // Note unsupported chain selector simply returns an empty set not an error
+ gasUpdates, err := pr.GetGasPriceUpdatesCreatedAfter(context.Background(), 1e6, time.Unix(0, 0), 0)
+ require.NoError(t, err)
+ assert.Len(t, gasUpdates, 0)
+
+ for i, ts := range th.blockTs {
+ // Should see all updates >= ts.
+ var expectedGas []cciptypes.GasPrice
+ var expectedDest0Gas []cciptypes.GasPrice
+ var expectedToken []cciptypes.TokenPrice
+ for j := i; j < len(th.blockTs); j++ {
+ expectedGas = append(expectedGas, th.expectedGasUpdates[th.blockTs[j]]...)
+ for _, g := range th.expectedGasUpdates[th.blockTs[j]] {
+ if g.DestChainSelector == th.destSelectors[0] {
+ expectedDest0Gas = append(expectedDest0Gas, g)
+ }
+ }
+ expectedToken = append(expectedToken, th.expectedTokenUpdates[th.blockTs[j]]...)
+ }
+ gasUpdates, err = pr.GetAllGasPriceUpdatesCreatedAfter(context.Background(), time.Unix(int64(ts-1), 0), 0)
+ require.NoError(t, err)
+ assert.Len(t, gasUpdates, len(expectedGas))
+
+ gasUpdates, err = pr.GetGasPriceUpdatesCreatedAfter(context.Background(), th.destSelectors[0], time.Unix(int64(ts-1), 0), 0)
+ require.NoError(t, err)
+ assert.Len(t, gasUpdates, len(expectedDest0Gas))
+
+ tokenUpdates, err2 := pr.GetTokenPriceUpdatesCreatedAfter(context.Background(), time.Unix(int64(ts-1), 0), 0)
+ require.NoError(t, err2)
+ assert.Len(t, tokenUpdates, len(expectedToken))
+ }
+
+ // Empty token set should return empty set no error.
+ gotEmpty, err := pr.GetTokenPrices(context.Background(), []cciptypes.Address{})
+ require.NoError(t, err)
+ assert.Len(t, gotEmpty, 0)
+
+ // We expect latest token prices to apply
+ allTokenUpdates, err := pr.GetTokenPriceUpdatesCreatedAfter(context.Background(), time.Unix(0, 0), 0)
+ require.NoError(t, err)
+ // Build latest map
+ latest := make(map[cciptypes.Address]*big.Int)
+ // Comes back in ascending order (oldest first)
+ var allTokens []cciptypes.Address
+ for i := len(allTokenUpdates) - 1; i >= 0; i-- {
+ assert.NoError(t, err)
+ _, have := latest[allTokenUpdates[i].Token]
+ if have {
+ continue
+ }
+ latest[allTokenUpdates[i].Token] = allTokenUpdates[i].Value
+ allTokens = append(allTokens, allTokenUpdates[i].Token)
+ }
+ tokenPrices, err := pr.GetTokenPrices(context.Background(), allTokens)
+ require.NoError(t, err)
+ require.Len(t, tokenPrices, len(allTokens))
+ for _, p := range tokenPrices {
+ assert.Equal(t, p.Value, latest[p.Token])
+ }
+}
+
+func TestPriceRegistryReader(t *testing.T) {
+ th := setupPriceRegistryReaderTH(t)
+ // Assert all readers produce the same expected results.
+ for version, pr := range th.readers {
+ pr := pr
+ t.Run("PriceRegistryReader"+version, func(t *testing.T) {
+ testPriceRegistryReader(t, th, pr)
+ })
+ }
+}
+
+func TestNewPriceRegistryReader(t *testing.T) {
+ var tt = []struct {
+ typeAndVersion string
+ expectedErr string
+ }{
+ {
+ typeAndVersion: "blah",
+ expectedErr: "unable to read type and version: invalid type and version blah",
+ },
+ {
+ typeAndVersion: "EVM2EVMOffRamp 1.0.0",
+ expectedErr: "expected PriceRegistry got EVM2EVMOffRamp",
+ },
+ {
+ typeAndVersion: "PriceRegistry 1.2.0",
+ expectedErr: "",
+ },
+ {
+ typeAndVersion: "PriceRegistry 1.6.0-dev",
+ expectedErr: "",
+ },
+ {
+ typeAndVersion: "PriceRegistry 2.0.0",
+ expectedErr: "unsupported price registry version 2.0.0",
+ },
+ }
+ ctx := testutils.Context(t)
+ for _, tc := range tt {
+ t.Run(tc.typeAndVersion, func(t *testing.T) {
+ b, err := utils.ABIEncode(`[{"type":"string"}]`, tc.typeAndVersion)
+ require.NoError(t, err)
+ c := evmclientmocks.NewClient(t)
+ c.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(b, nil)
+ addr := ccipcalc.EvmAddrToGeneric(utils.RandomAddress())
+ lp := lpmocks.NewLogPoller(t)
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil).Maybe()
+ _, err = factory.NewPriceRegistryReader(ctx, logger.Test(t), factory.NewEvmVersionFinder(), addr, lp, c)
+ if tc.expectedErr != "" {
+ require.EqualError(t, err, tc.expectedErr)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/reader.go
new file mode 100644
index 00000000000..25471d0d659
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/reader.go
@@ -0,0 +1,79 @@
+package ccipdata
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
+)
+
+const (
+ V1_0_0 = "1.0.0"
+ V1_1_0 = "1.1.0"
+ V1_2_0 = "1.2.0"
+ V1_4_0 = "1.4.0"
+ V1_5_0 = "1.5.0-dev"
+ V1_6_0 = "1.6.0-dev"
+)
+
+const (
+ // CommitExecLogsRetention defines the duration for which logs critical for Commit/Exec plugins processing are retained.
+ // Although Exec relies on permissionlessExecThreshold which is lower than 24hours for picking eligible CommitRoots,
+ // Commit still can reach to older logs because it filters them by sequence numbers. For instance, in case of RMN curse on chain,
+ // we might have logs waiting in OnRamp to be committed first. When outage takes days we still would
+ // be able to bring back processing without replaying any logs from chain. You can read that param as
+ // "how long CCIP can be down and still be able to process all the messages after getting back to life".
+ // Breaching this threshold would require replaying chain using LogPoller from the beginning of the outage.
+ CommitExecLogsRetention = 30 * 24 * time.Hour // 30 days
+ // CacheEvictionLogsRetention defines the duration for which logs used for caching on-chain data are kept.
+ // Restarting node clears the cache entirely and rebuilds it from scratch by fetching data from chain,
+ // so we don't need to keep these logs for very long. All events relying on cache.NewLogpollerEventsBased should use this retention.
+ CacheEvictionLogsRetention = 7 * 24 * time.Hour // 7 days
+ // PriceUpdatesLogsRetention defines the duration for which logs with price updates are kept.
+ // These logs are emitted whenever the token price or gas price is updated and Commit scans very small time windows (e.g. 2 hours)
+ PriceUpdatesLogsRetention = 1 * 24 * time.Hour // 1 day
+)
+
+type Event[T any] struct {
+ Data T
+ cciptypes.TxMeta
+}
+
+func LogsConfirmations(finalized bool) evmtypes.Confirmations {
+ if finalized {
+ return evmtypes.Finalized
+ }
+ return evmtypes.Unconfirmed
+}
+
+func ParseLogs[T any](logs []logpoller.Log, lggr logger.Logger, parseFunc func(log types.Log) (*T, error)) ([]Event[T], error) {
+ reqs := make([]Event[T], 0, len(logs))
+
+ for _, log := range logs {
+ data, err := parseFunc(log.ToGethLog())
+ if err != nil {
+ lggr.Errorw("Unable to parse log", "err", err)
+ continue
+ }
+ reqs = append(reqs, Event[T]{
+ Data: *data,
+ TxMeta: cciptypes.TxMeta{
+ BlockTimestampUnixMilli: log.BlockTimestamp.UnixMilli(),
+ BlockNumber: uint64(log.BlockNumber),
+ TxHash: log.TxHash.String(),
+ LogIndex: uint64(log.LogIndex),
+ },
+ })
+ }
+
+ if len(logs) != len(reqs) {
+ return nil, fmt.Errorf("%d logs were not parsed", len(logs)-len(reqs))
+ }
+ return reqs, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/reader_test.go
new file mode 100644
index 00000000000..0df76873915
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/reader_test.go
@@ -0,0 +1,73 @@
+package ccipdata
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap/zapcore"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+)
+
+func Test_parseLogs(t *testing.T) {
+ // generate 100 logs
+ logs := make([]logpoller.Log, 100)
+ for i := range logs {
+ logs[i].LogIndex = int64(i + 1)
+ logs[i].BlockNumber = int64(i) * 1000
+ logs[i].BlockTimestamp = time.Now()
+ }
+
+ parseFn := func(log types.Log) (*uint, error) {
+ return &log.Index, nil
+ }
+
+ parsedEvents, err := ParseLogs[uint](logs, logger.Test(t), parseFn)
+ require.NoError(t, err)
+ assert.Len(t, parsedEvents, 100)
+
+ // Make sure everything is parsed according to the parse func
+ for i, ev := range parsedEvents {
+ assert.Equal(t, i+1, int(ev.Data))
+ assert.Equal(t, i*1000, int(ev.BlockNumber))
+ assert.Greater(t, ev.BlockTimestampUnixMilli, time.Now().Add(-time.Minute).UnixMilli())
+ }
+}
+
+func Test_parseLogs_withErrors(t *testing.T) {
+ // generate 50 valid logs and 50 errors
+ actualErrorCount := 50
+ logs := make([]logpoller.Log, actualErrorCount*2)
+ for i := range logs {
+ logs[i].LogIndex = int64(i + 1)
+ }
+
+ // return an error for half of the logs.
+ parseFn := func(log types.Log) (*uint, error) {
+ if log.Index%2 == 0 {
+ return nil, fmt.Errorf("cannot parse %d", log.Index)
+ }
+ return &log.Index, nil
+ }
+
+ log, observed := logger.TestObserved(t, zapcore.DebugLevel)
+ parsedEvents, err := ParseLogs[uint](logs, log, parseFn)
+ assert.ErrorContains(t, err, fmt.Sprintf("%d logs were not parsed", len(logs)/2))
+ assert.Nil(t, parsedEvents, "No events are returned if there was an error.")
+
+ // logs are written for errors.
+ require.Equal(t, actualErrorCount, observed.Len(), "Expect 51 warnings: one for each error and a summary.")
+ for i, entry := range observed.All() {
+ assert.Equal(t, zapcore.ErrorLevel, entry.Level)
+ assert.Contains(t, entry.Message, "Unable to parse log")
+ contextMap := entry.ContextMap()
+ require.Contains(t, contextMap, "err")
+ assert.Contains(t, contextMap["err"], fmt.Sprintf("cannot parse %d", (i+1)*2), "each error should be logged as a warning")
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/retry_config.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/retry_config.go
new file mode 100644
index 00000000000..41161ee9388
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/retry_config.go
@@ -0,0 +1,9 @@
+package ccipdata
+
+import "time"
+
+// RetryConfig configures an initial delay between retries and a max delay between retries
+type RetryConfig struct {
+ InitialDelay time.Duration
+ MaxDelay time.Duration
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/test_utils.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/test_utils.go
new file mode 100644
index 00000000000..6dc51b888ed
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/test_utils.go
@@ -0,0 +1,36 @@
+package ccipdata
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+)
+
+// NewSimulation returns a client and a simulated backend.
+func NewSimulation(t testing.TB) (*bind.TransactOpts, *client.SimulatedBackendClient) {
+ user := testutils.MustNewSimTransactor(t)
+ simulatedBackend := backends.NewSimulatedBackend(map[common.Address]core.GenesisAccount{
+ user.From: {
+ Balance: big.NewInt(0).Mul(big.NewInt(3), big.NewInt(1e18)),
+ },
+ }, 10e6)
+ simulatedBackendClient := client.NewSimulatedBackendClient(t, simulatedBackend, testutils.SimulatedChainID)
+ return user, simulatedBackendClient
+}
+
+// AssertNonRevert Verify that a transaction was not reverted.
+func AssertNonRevert(t testing.TB, tx *types.Transaction, bc *client.SimulatedBackendClient, user *bind.TransactOpts) {
+ require.NotNil(t, tx, "Transaction should not be nil")
+ receipt, err := bc.TransactionReceipt(user.Context, tx.Hash())
+ require.NoError(t, err)
+ require.NotEqual(t, uint64(0), receipt.Status, "Transaction should not have reverted")
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/token_pool_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/token_pool_reader.go
new file mode 100644
index 00000000000..999061f4913
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/token_pool_reader.go
@@ -0,0 +1,10 @@
+package ccipdata
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+)
+
+type TokenPoolReader interface {
+ Address() common.Address
+ Type() string
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader.go
new file mode 100644
index 00000000000..cd8fd3150ae
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader.go
@@ -0,0 +1,170 @@
+package ccipdata
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/patrickmn/go-cache"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+var (
+ // shortLivedInMemLogsCacheExpiration is used for the short-lived in meme logs cache.
+ // Value should usually be set to just a few seconds, a larger duration will not increase performance and might
+ // cause performance issues on re-orged logs.
+ shortLivedInMemLogsCacheExpiration = 20 * time.Second
+)
+
+const (
+ MESSAGE_SENT_FILTER_NAME = "USDC message sent"
+)
+
+var _ USDCReader = &USDCReaderImpl{}
+
+type USDCReader interface {
+ // GetUSDCMessagePriorToLogIndexInTx returns the specified USDC message data.
+ // e.g. if msg contains 3 tokens: [usdc1, wETH, usdc2] ignoring non-usdc tokens
+ // if usdcTokenIndexOffset is 0 we select usdc2
+ // if usdcTokenIndexOffset is 1 we select usdc1
+ // The message logs are found using the provided transaction hash.
+ GetUSDCMessagePriorToLogIndexInTx(ctx context.Context, logIndex int64, usdcTokenIndexOffset int, txHash string) ([]byte, error)
+}
+
+type USDCReaderImpl struct {
+ usdcMessageSent common.Hash
+ lp logpoller.LogPoller
+ filter logpoller.Filter
+ lggr logger.Logger
+ transmitterAddress common.Address
+
+ // shortLivedInMemLogs is a short-lived cache (items expire every few seconds)
+ // used to prevent frequent log fetching from the log poller
+ shortLivedInMemLogs *cache.Cache
+}
+
+func (u *USDCReaderImpl) Close() error {
+ // FIXME Dim pgOpts removed from LogPoller
+ return u.lp.UnregisterFilter(context.Background(), u.filter.Name)
+}
+
+func (u *USDCReaderImpl) RegisterFilters() error {
+ // FIXME Dim pgOpts removed from LogPoller
+ return u.lp.RegisterFilter(context.Background(), u.filter)
+}
+
+// usdcPayload has to match the onchain event emitted by the USDC message transmitter
+type usdcPayload []byte
+
+func (d usdcPayload) AbiString() string {
+ return `[{"type": "bytes"}]`
+}
+
+func (d usdcPayload) Validate() error {
+ if len(d) == 0 {
+ return errors.New("must be non-empty")
+ }
+ return nil
+}
+
+func parseUSDCMessageSent(logData []byte) ([]byte, error) {
+ decodeAbiStruct, err := abihelpers.DecodeAbiStruct[usdcPayload](logData)
+ if err != nil {
+ return nil, err
+ }
+ return decodeAbiStruct, nil
+}
+
+func (u *USDCReaderImpl) GetUSDCMessagePriorToLogIndexInTx(ctx context.Context, logIndex int64, usdcTokenIndexOffset int, txHash string) ([]byte, error) {
+ var lpLogs []logpoller.Log
+
+ // fetch all the usdc logs for the provided tx hash
+ k := fmt.Sprintf("usdc-%s", txHash) // custom prefix to avoid key collision if someone re-uses the cache
+ if rawLogs, foundInMem := u.shortLivedInMemLogs.Get(k); foundInMem {
+ inMemLogs, ok := rawLogs.([]logpoller.Log)
+ if !ok {
+ return nil, errors.Errorf("unexpected in-mem logs type %T", rawLogs)
+ }
+ u.lggr.Debugw("found logs in memory", "k", k, "len", len(inMemLogs))
+ lpLogs = inMemLogs
+ }
+
+ if len(lpLogs) == 0 {
+ u.lggr.Debugw("fetching logs from lp", "k", k)
+ logs, err := u.lp.IndexedLogsByTxHash(
+ ctx,
+ u.usdcMessageSent,
+ u.transmitterAddress,
+ common.HexToHash(txHash),
+ )
+ if err != nil {
+ return nil, err
+ }
+ lpLogs = logs
+ u.shortLivedInMemLogs.Set(k, logs, cache.DefaultExpiration)
+ u.lggr.Debugw("fetched logs from lp", "logs", len(lpLogs))
+ }
+
+ // collect the logs with log index less than the provided log index
+ allUsdcTokensData := make([][]byte, 0)
+ for _, current := range lpLogs {
+ if current.LogIndex < logIndex {
+ u.lggr.Infow("Found USDC message", "logIndex", current.LogIndex, "txHash", current.TxHash.Hex(), "data", hexutil.Encode(current.Data))
+ allUsdcTokensData = append(allUsdcTokensData, current.Data)
+ }
+ }
+
+ usdcTokenIndex := (len(allUsdcTokensData) - 1) - usdcTokenIndexOffset
+
+ if usdcTokenIndex < 0 || usdcTokenIndex >= len(allUsdcTokensData) {
+ u.lggr.Errorw("usdc message not found",
+ "logIndex", logIndex,
+ "allUsdcTokenData", len(allUsdcTokensData),
+ "txHash", txHash,
+ "usdcTokenIndex", usdcTokenIndex,
+ )
+ return nil, errors.Errorf("usdc token index %d is not valid", usdcTokenIndex)
+ }
+ return parseUSDCMessageSent(allUsdcTokensData[usdcTokenIndex])
+}
+
+func NewUSDCReader(lggr logger.Logger, jobID string, transmitter common.Address, lp logpoller.LogPoller, registerFilters bool) (*USDCReaderImpl, error) {
+ eventSig := utils.Keccak256Fixed([]byte("MessageSent(bytes)"))
+
+ r := &USDCReaderImpl{
+ lggr: lggr,
+ lp: lp,
+ usdcMessageSent: eventSig,
+ filter: logpoller.Filter{
+ Name: logpoller.FilterName(MESSAGE_SENT_FILTER_NAME, jobID, transmitter.Hex()),
+ EventSigs: []common.Hash{eventSig},
+ Addresses: []common.Address{transmitter},
+ Retention: CommitExecLogsRetention,
+ },
+ transmitterAddress: transmitter,
+ shortLivedInMemLogs: cache.New(shortLivedInMemLogsCacheExpiration, 2*shortLivedInMemLogsCacheExpiration),
+ }
+
+ if registerFilters {
+ if err := r.RegisterFilters(); err != nil {
+ return nil, fmt.Errorf("register filters: %w", err)
+ }
+ }
+ return r, nil
+}
+
+func CloseUSDCReader(lggr logger.Logger, jobID string, transmitter common.Address, lp logpoller.LogPoller) error {
+ r, err := NewUSDCReader(lggr, jobID, transmitter, lp, false)
+ if err != nil {
+ return err
+ }
+ return r.Close()
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go
new file mode 100644
index 00000000000..953da52713b
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/usdc_reader_internal_test.go
@@ -0,0 +1,179 @@
+package ccipdata
+
+import (
+ "context"
+ "fmt"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core"
+ "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/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+)
+
+func TestLogPollerClient_GetUSDCMessagePriorToLogIndexInTx(t *testing.T) {
+ addr := utils.RandomAddress()
+ txHash := common.BytesToHash(addr[:])
+ ccipLogIndex := int64(100)
+
+ expectedData := "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f80000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc08610000000000000000"
+ expectedPostParse := "0x0000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc0861"
+ lggr := logger.Test(t)
+
+ t.Run("multiple found - selected last", func(t *testing.T) {
+ lp := lpmocks.NewLogPoller(t)
+ u, _ := NewUSDCReader(lggr, "job_123", utils.RandomAddress(), lp, false)
+
+ lp.On("IndexedLogsByTxHash",
+ mock.Anything,
+ u.usdcMessageSent,
+ u.transmitterAddress,
+ txHash,
+ ).Return([]logpoller.Log{
+ {LogIndex: ccipLogIndex - 2, Data: []byte("-2")},
+ {LogIndex: ccipLogIndex - 1, Data: hexutil.MustDecode(expectedData)},
+ {LogIndex: ccipLogIndex, Data: []byte("0")},
+ {LogIndex: ccipLogIndex + 1, Data: []byte("1")},
+ }, nil)
+ usdcMessageData, err := u.GetUSDCMessagePriorToLogIndexInTx(context.Background(), ccipLogIndex, 0, txHash.String())
+ assert.NoError(t, err)
+ assert.Equal(t, expectedPostParse, hexutil.Encode(usdcMessageData))
+ lp.AssertExpectations(t)
+ })
+
+ t.Run("multiple found - selected first", func(t *testing.T) {
+ lp := lpmocks.NewLogPoller(t)
+ u, _ := NewUSDCReader(lggr, "job_123", utils.RandomAddress(), lp, false)
+
+ lp.On("IndexedLogsByTxHash",
+ mock.Anything,
+ u.usdcMessageSent,
+ u.transmitterAddress,
+ txHash,
+ ).Return([]logpoller.Log{
+ {LogIndex: ccipLogIndex - 2, Data: hexutil.MustDecode(expectedData)},
+ {LogIndex: ccipLogIndex - 1, Data: []byte("-2")},
+ {LogIndex: ccipLogIndex, Data: []byte("0")},
+ {LogIndex: ccipLogIndex + 1, Data: []byte("1")},
+ }, nil)
+ usdcMessageData, err := u.GetUSDCMessagePriorToLogIndexInTx(context.Background(), ccipLogIndex, 1, txHash.String())
+ assert.NoError(t, err)
+ assert.Equal(t, expectedPostParse, hexutil.Encode(usdcMessageData))
+ lp.AssertExpectations(t)
+ })
+
+ t.Run("logs fetched from memory in subsequent calls", func(t *testing.T) {
+ lp := lpmocks.NewLogPoller(t)
+ u, _ := NewUSDCReader(lggr, "job_123", utils.RandomAddress(), lp, false)
+
+ lp.On("IndexedLogsByTxHash",
+ mock.Anything,
+ u.usdcMessageSent,
+ u.transmitterAddress,
+ txHash,
+ ).Return([]logpoller.Log{
+ {LogIndex: ccipLogIndex - 2, Data: hexutil.MustDecode(expectedData)},
+ {LogIndex: ccipLogIndex - 1, Data: []byte("-2")},
+ {LogIndex: ccipLogIndex, Data: []byte("0")},
+ {LogIndex: ccipLogIndex + 1, Data: []byte("1")},
+ }, nil).Once()
+
+ // first call logs must be fetched from lp
+ usdcMessageData, err := u.GetUSDCMessagePriorToLogIndexInTx(context.Background(), ccipLogIndex, 1, txHash.String())
+ assert.NoError(t, err)
+ assert.Equal(t, expectedPostParse, hexutil.Encode(usdcMessageData))
+
+ // subsequent call, logs must be fetched from memory
+ usdcMessageData, err = u.GetUSDCMessagePriorToLogIndexInTx(context.Background(), ccipLogIndex, 1, txHash.String())
+ assert.NoError(t, err)
+ assert.Equal(t, expectedPostParse, hexutil.Encode(usdcMessageData))
+
+ lp.AssertExpectations(t)
+ })
+
+ t.Run("none found", func(t *testing.T) {
+ lp := lpmocks.NewLogPoller(t)
+ u, _ := NewUSDCReader(lggr, "job_123", utils.RandomAddress(), lp, false)
+ lp.On("IndexedLogsByTxHash",
+ mock.Anything,
+ u.usdcMessageSent,
+ u.transmitterAddress,
+ txHash,
+ ).Return([]logpoller.Log{}, nil)
+
+ usdcMessageData, err := u.GetUSDCMessagePriorToLogIndexInTx(context.Background(), ccipLogIndex, 0, txHash.String())
+ assert.Errorf(t, err, fmt.Sprintf("no USDC message found prior to log index %d in tx %s", ccipLogIndex, txHash.Hex()))
+ assert.Nil(t, usdcMessageData)
+
+ lp.AssertExpectations(t)
+ })
+}
+
+func TestParse(t *testing.T) {
+ expectedBody, err := hexutil.Decode("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f80000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc08610000000000000000")
+ require.NoError(t, err)
+
+ parsedBody, err := parseUSDCMessageSent(expectedBody)
+ require.NoError(t, err)
+
+ expectedPostParse := "0x0000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc0861"
+
+ require.Equal(t, expectedPostParse, hexutil.Encode(parsedBody))
+}
+
+func TestFilters(t *testing.T) {
+ t.Run("filters of different jobs should be distinct", func(t *testing.T) {
+ lggr := logger.Test(t)
+ chainID := testutils.NewRandomEVMChainID()
+ db := pgtest.NewSqlxDB(t)
+ o := logpoller.NewORM(chainID, db, lggr)
+ ec := backends.NewSimulatedBackend(map[common.Address]core.GenesisAccount{}, 10e6)
+ esc := client.NewSimulatedBackendClient(t, ec, chainID)
+ lpOpts := logpoller.Opts{
+ PollPeriod: 1 * time.Hour,
+ FinalityDepth: 1,
+ BackfillBatchSize: 1,
+ RpcBatchSize: 1,
+ KeepFinalizedBlocksDepth: 100,
+ }
+ headTracker := headtracker.NewSimulatedHeadTracker(esc, lpOpts.UseFinalityTag, lpOpts.FinalityDepth)
+ if lpOpts.PollPeriod == 0 {
+ lpOpts.PollPeriod = 1 * time.Hour
+ }
+ lp := logpoller.NewLogPoller(o, esc, lggr, headTracker, lpOpts)
+
+ jobID1 := "job-1"
+ jobID2 := "job-2"
+ transmitter := utils.RandomAddress()
+
+ f1 := logpoller.FilterName("USDC message sent", jobID1, transmitter.Hex())
+ f2 := logpoller.FilterName("USDC message sent", jobID2, transmitter.Hex())
+
+ _, err := NewUSDCReader(lggr, jobID1, transmitter, lp, true)
+ assert.NoError(t, err)
+ assert.True(t, lp.HasFilter(f1))
+
+ _, err = NewUSDCReader(lggr, jobID2, transmitter, lp, true)
+ assert.NoError(t, err)
+ assert.True(t, lp.HasFilter(f2))
+
+ err = CloseUSDCReader(lggr, jobID2, transmitter, lp)
+ assert.NoError(t, err)
+ assert.True(t, lp.HasFilter(f1))
+ assert.False(t, lp.HasFilter(f2))
+ })
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/commit_store.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/commit_store.go
new file mode 100644
index 00000000000..d0559b800e0
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/commit_store.go
@@ -0,0 +1,456 @@
+package v1_0_0
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "sync"
+ "time"
+
+ "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"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/query"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "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/gethwrappers/ccip/generated/commit_store_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/logpollerutil"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+const (
+ EXEC_REPORT_ACCEPTS = "Exec report accepts"
+ ReportAccepted = "ReportAccepted"
+)
+
+var _ ccipdata.CommitStoreReader = &CommitStore{}
+
+type CommitStore struct {
+ // Static config
+ commitStore *commit_store_1_0_0.CommitStore
+ lggr logger.Logger
+ lp logpoller.LogPoller
+ address common.Address
+ estimator *gas.EvmFeeEstimator
+ sourceMaxGasPrice *big.Int
+ filters []logpoller.Filter
+ reportAcceptedSig common.Hash
+ reportAcceptedMaxSeqIndex int
+ commitReportArgs abi.Arguments
+
+ // Dynamic config
+ configMu sync.RWMutex
+ gasPriceEstimator prices.ExecGasPriceEstimator
+ offchainConfig cciptypes.CommitOffchainConfig
+}
+
+func (c *CommitStore) GetCommitStoreStaticConfig(ctx context.Context) (cciptypes.CommitStoreStaticConfig, error) {
+ legacyConfig, err := c.commitStore.GetStaticConfig(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return cciptypes.CommitStoreStaticConfig{}, errors.New("Could not get commitStore static config")
+ }
+ return cciptypes.CommitStoreStaticConfig{
+ ChainSelector: legacyConfig.ChainSelector,
+ SourceChainSelector: legacyConfig.SourceChainSelector,
+ OnRamp: ccipcalc.EvmAddrToGeneric(legacyConfig.OnRamp),
+ ArmProxy: ccipcalc.EvmAddrToGeneric(legacyConfig.ArmProxy),
+ }, nil
+}
+
+func (c *CommitStore) EncodeCommitReport(_ context.Context, report cciptypes.CommitStoreReport) ([]byte, error) {
+ return encodeCommitReport(c.commitReportArgs, report)
+}
+
+func encodeCommitReport(commitReportArgs abi.Arguments, report cciptypes.CommitStoreReport) ([]byte, error) {
+ var tokenPriceUpdates []commit_store_1_0_0.InternalTokenPriceUpdate
+ for _, tokenPriceUpdate := range report.TokenPrices {
+ sourceTokenEvmAddr, err := ccipcalc.GenericAddrToEvm(tokenPriceUpdate.Token)
+ if err != nil {
+ return nil, err
+ }
+ tokenPriceUpdates = append(tokenPriceUpdates, commit_store_1_0_0.InternalTokenPriceUpdate{
+ SourceToken: sourceTokenEvmAddr,
+ UsdPerToken: tokenPriceUpdate.Value,
+ })
+ }
+ var usdPerUnitGas = big.NewInt(0)
+ var destChainSelector = uint64(0)
+ if len(report.GasPrices) > 1 {
+ return []byte{}, errors.Errorf("CommitStore V1_0_0 can only accept 1 gas price, received: %d", len(report.GasPrices))
+ }
+ if len(report.GasPrices) > 0 {
+ usdPerUnitGas = report.GasPrices[0].Value
+ destChainSelector = report.GasPrices[0].DestChainSelector
+ }
+ rep := commit_store_1_0_0.CommitStoreCommitReport{
+ PriceUpdates: commit_store_1_0_0.InternalPriceUpdates{
+ TokenPriceUpdates: tokenPriceUpdates,
+ UsdPerUnitGas: usdPerUnitGas,
+ DestChainSelector: destChainSelector,
+ },
+ Interval: commit_store_1_0_0.CommitStoreInterval{Min: report.Interval.Min, Max: report.Interval.Max},
+ MerkleRoot: report.MerkleRoot,
+ }
+ return commitReportArgs.PackValues([]interface{}{rep})
+}
+
+func DecodeCommitReport(commitReportArgs abi.Arguments, report []byte) (cciptypes.CommitStoreReport, error) {
+ unpacked, err := commitReportArgs.Unpack(report)
+ if err != nil {
+ return cciptypes.CommitStoreReport{}, err
+ }
+ if len(unpacked) != 1 {
+ return cciptypes.CommitStoreReport{}, errors.New("expected single struct value")
+ }
+
+ commitReport, ok := unpacked[0].(struct {
+ PriceUpdates struct {
+ TokenPriceUpdates []struct {
+ SourceToken common.Address `json:"sourceToken"`
+ UsdPerToken *big.Int `json:"usdPerToken"`
+ } `json:"tokenPriceUpdates"`
+ DestChainSelector uint64 `json:"destChainSelector"`
+ UsdPerUnitGas *big.Int `json:"usdPerUnitGas"`
+ } `json:"priceUpdates"`
+ Interval struct {
+ Min uint64 `json:"min"`
+ Max uint64 `json:"max"`
+ } `json:"interval"`
+ MerkleRoot [32]byte `json:"merkleRoot"`
+ })
+ if !ok {
+ return cciptypes.CommitStoreReport{}, errors.Errorf("invalid commit report got %T", unpacked[0])
+ }
+
+ var tokenPriceUpdates []cciptypes.TokenPrice
+ for _, u := range commitReport.PriceUpdates.TokenPriceUpdates {
+ tokenPriceUpdates = append(tokenPriceUpdates, cciptypes.TokenPrice{
+ Token: cciptypes.Address(u.SourceToken.String()),
+ Value: u.UsdPerToken,
+ })
+ }
+
+ var gasPrices []cciptypes.GasPrice
+ if commitReport.PriceUpdates.DestChainSelector != 0 {
+ // No gas price update {
+ gasPrices = append(gasPrices, cciptypes.GasPrice{
+ DestChainSelector: commitReport.PriceUpdates.DestChainSelector,
+ Value: commitReport.PriceUpdates.UsdPerUnitGas,
+ })
+ }
+
+ return cciptypes.CommitStoreReport{
+ TokenPrices: tokenPriceUpdates,
+ GasPrices: gasPrices,
+ Interval: cciptypes.CommitStoreInterval{
+ Min: commitReport.Interval.Min,
+ Max: commitReport.Interval.Max,
+ },
+ MerkleRoot: commitReport.MerkleRoot,
+ }, nil
+}
+
+func (c *CommitStore) DecodeCommitReport(_ context.Context, report []byte) (cciptypes.CommitStoreReport, error) {
+ return DecodeCommitReport(c.commitReportArgs, report)
+}
+
+func (c *CommitStore) IsBlessed(ctx context.Context, root [32]byte) (bool, error) {
+ return c.commitStore.IsBlessed(&bind.CallOpts{Context: ctx}, root)
+}
+
+func (c *CommitStore) OffchainConfig(context.Context) (cciptypes.CommitOffchainConfig, error) {
+ c.configMu.RLock()
+ defer c.configMu.RUnlock()
+ return c.offchainConfig, nil
+}
+
+func (c *CommitStore) GasPriceEstimator(context.Context) (cciptypes.GasPriceEstimatorCommit, error) {
+ c.configMu.RLock()
+ defer c.configMu.RUnlock()
+ return c.gasPriceEstimator, nil
+}
+
+func (c *CommitStore) SetGasEstimator(ctx context.Context, gpe gas.EvmFeeEstimator) error {
+ c.configMu.RLock()
+ defer c.configMu.RUnlock()
+ c.estimator = &gpe
+ return nil
+}
+
+func (c *CommitStore) SetSourceMaxGasPrice(ctx context.Context, sourceMaxGasPrice *big.Int) error {
+ c.configMu.RLock()
+ defer c.configMu.RUnlock()
+ c.sourceMaxGasPrice = sourceMaxGasPrice
+ return nil
+}
+
+// CommitOffchainConfig is a legacy version of CommitOffchainConfig, used for CommitStore version 1.0.0 and 1.1.0
+type CommitOffchainConfig struct {
+ SourceFinalityDepth uint32
+ DestFinalityDepth uint32
+ FeeUpdateHeartBeat config.Duration
+ FeeUpdateDeviationPPB uint32
+ InflightCacheExpiry config.Duration
+ PriceReportingDisabled bool
+}
+
+func (c CommitOffchainConfig) Validate() error {
+ if c.SourceFinalityDepth == 0 {
+ return errors.New("must set SourceFinalityDepth")
+ }
+ if c.DestFinalityDepth == 0 {
+ return errors.New("must set DestFinalityDepth")
+ }
+ if c.FeeUpdateHeartBeat.Duration() == 0 {
+ return errors.New("must set FeeUpdateHeartBeat")
+ }
+ if c.FeeUpdateDeviationPPB == 0 {
+ return errors.New("must set FeeUpdateDeviationPPB")
+ }
+ if c.InflightCacheExpiry.Duration() == 0 {
+ return errors.New("must set InflightCacheExpiry")
+ }
+
+ return nil
+}
+
+func (c *CommitStore) ChangeConfig(_ context.Context, onchainConfig []byte, offchainConfig []byte) (cciptypes.Address, error) {
+ onchainConfigParsed, err := abihelpers.DecodeAbiStruct[ccipdata.CommitOnchainConfig](onchainConfig)
+ if err != nil {
+ return "", err
+ }
+
+ offchainConfigV1, err := ccipconfig.DecodeOffchainConfig[CommitOffchainConfig](offchainConfig)
+ if err != nil {
+ return "", err
+ }
+ c.configMu.Lock()
+ defer c.configMu.Unlock()
+
+ if c.estimator == nil {
+ return "", fmt.Errorf("this CommitStore estimator is nil. SetGasEstimator should be called before ChangeConfig")
+ }
+
+ if c.sourceMaxGasPrice == nil {
+ return "", fmt.Errorf("this CommitStore sourceMaxGasPrice is nil. SetSourceMaxGasPrice should be called before ChangeConfig")
+ }
+
+ c.gasPriceEstimator = prices.NewExecGasPriceEstimator(
+ *c.estimator,
+ c.sourceMaxGasPrice,
+ int64(offchainConfigV1.FeeUpdateDeviationPPB))
+ c.offchainConfig = ccipdata.NewCommitOffchainConfig(
+ offchainConfigV1.FeeUpdateDeviationPPB,
+ offchainConfigV1.FeeUpdateHeartBeat.Duration(),
+ offchainConfigV1.FeeUpdateDeviationPPB,
+ offchainConfigV1.FeeUpdateHeartBeat.Duration(),
+ offchainConfigV1.InflightCacheExpiry.Duration(),
+ offchainConfigV1.PriceReportingDisabled)
+ c.lggr.Infow("ChangeConfig",
+ "offchainConfig", offchainConfigV1,
+ "onchainConfig", onchainConfigParsed,
+ )
+ return cciptypes.Address(onchainConfigParsed.PriceRegistry.String()), nil
+}
+
+func (c *CommitStore) Close() error {
+ return logpollerutil.UnregisterLpFilters(c.lp, c.filters)
+}
+
+func (c *CommitStore) parseReport(log types.Log) (*cciptypes.CommitStoreReport, error) {
+ repAccepted, err := c.commitStore.ParseReportAccepted(log)
+ if err != nil {
+ return nil, err
+ }
+ // Translate to common struct.
+ var tokenPrices []cciptypes.TokenPrice
+ for _, tpu := range repAccepted.Report.PriceUpdates.TokenPriceUpdates {
+ tokenPrices = append(tokenPrices, cciptypes.TokenPrice{
+ Token: cciptypes.Address(tpu.SourceToken.String()),
+ Value: tpu.UsdPerToken,
+ })
+ }
+ return &cciptypes.CommitStoreReport{
+ TokenPrices: tokenPrices,
+ GasPrices: []cciptypes.GasPrice{{DestChainSelector: repAccepted.Report.PriceUpdates.DestChainSelector, Value: repAccepted.Report.PriceUpdates.UsdPerUnitGas}},
+ MerkleRoot: repAccepted.Report.MerkleRoot,
+ Interval: cciptypes.CommitStoreInterval{Min: repAccepted.Report.Interval.Min, Max: repAccepted.Report.Interval.Max},
+ }, nil
+}
+
+func (c *CommitStore) GetCommitReportMatchingSeqNum(ctx context.Context, seqNr uint64, confs int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ logs, err := c.lp.LogsDataWordBetween(
+ ctx,
+ c.reportAcceptedSig,
+ c.address,
+ c.reportAcceptedMaxSeqIndex-1,
+ c.reportAcceptedMaxSeqIndex,
+ logpoller.EvmWord(seqNr),
+ evmtypes.Confirmations(confs),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.CommitStoreReport](
+ logs,
+ c.lggr,
+ c.parseReport,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ res := make([]cciptypes.CommitStoreReportWithTxMeta, 0, len(parsedLogs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.CommitStoreReportWithTxMeta{
+ TxMeta: log.TxMeta,
+ CommitStoreReport: log.Data,
+ })
+ }
+
+ if len(res) > 1 {
+ c.lggr.Errorw("More than one report found for seqNr", "seqNr", seqNr, "commitReports", parsedLogs)
+ return res[:1], nil
+ }
+ return res, nil
+}
+
+func (c *CommitStore) GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confs int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ latestBlock, err := c.lp.LatestBlock(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ reportsQuery, err := query.Where(
+ c.address.String(),
+ logpoller.NewAddressFilter(c.address),
+ logpoller.NewEventSigFilter(c.reportAcceptedSig),
+ query.Timestamp(uint64(ts.Unix()), primitives.Gte),
+ logpoller.NewConfirmationsFilter(evmtypes.Confirmations(confs)),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ logs, err := c.lp.FilteredLogs(
+ ctx,
+ reportsQuery,
+ query.NewLimitAndSort(query.Limit{}, query.NewSortBySequence(query.Asc)),
+ "GetAcceptedCommitReportsGteTimestamp",
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.CommitStoreReport](logs, c.lggr, c.parseReport)
+ if err != nil {
+ return nil, fmt.Errorf("parse logs: %w", err)
+ }
+
+ parsedReports := make([]cciptypes.CommitStoreReportWithTxMeta, 0, len(parsedLogs))
+ for _, log := range parsedLogs {
+ parsedReports = append(parsedReports, cciptypes.CommitStoreReportWithTxMeta{
+ TxMeta: log.TxMeta.WithFinalityStatus(uint64(latestBlock.FinalizedBlockNumber)),
+ CommitStoreReport: log.Data,
+ })
+ }
+
+ return parsedReports, nil
+}
+
+func (c *CommitStore) GetExpectedNextSequenceNumber(ctx context.Context) (uint64, error) {
+ return c.commitStore.GetExpectedNextSequenceNumber(&bind.CallOpts{Context: ctx})
+}
+
+func (c *CommitStore) GetLatestPriceEpochAndRound(ctx context.Context) (uint64, error) {
+ return c.commitStore.GetLatestPriceEpochAndRound(&bind.CallOpts{Context: ctx})
+}
+
+func (c *CommitStore) IsDestChainHealthy(context.Context) (bool, error) {
+ if err := c.lp.Healthy(); err != nil {
+ return false, nil
+ }
+ return true, nil
+}
+
+func (c *CommitStore) IsDown(ctx context.Context) (bool, error) {
+ unPausedAndHealthy, err := c.commitStore.IsUnpausedAndARMHealthy(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return true, err
+ }
+ return !unPausedAndHealthy, nil
+}
+
+func (c *CommitStore) VerifyExecutionReport(ctx context.Context, report cciptypes.ExecReport) (bool, error) {
+ var hashes [][32]byte
+ for _, msg := range report.Messages {
+ hashes = append(hashes, msg.Hash)
+ }
+ res, err := c.commitStore.Verify(&bind.CallOpts{Context: ctx}, hashes, report.Proofs, report.ProofFlagBits)
+ if err != nil {
+ c.lggr.Errorw("Unable to call verify", "messages", report.Messages, "err", err)
+ return false, nil
+ }
+ // No timestamp, means failed to verify root.
+ if res.Cmp(big.NewInt(0)) == 0 {
+ c.lggr.Errorw("Root does not verify", "messages", report.Messages)
+ return false, nil
+ }
+ return true, nil
+}
+
+func (c *CommitStore) RegisterFilters() error {
+ return logpollerutil.RegisterLpFilters(c.lp, c.filters)
+}
+
+func NewCommitStore(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller) (*CommitStore, error) {
+ commitStore, err := commit_store_1_0_0.NewCommitStore(addr, ec)
+ if err != nil {
+ return nil, err
+ }
+ commitStoreABI := abihelpers.MustParseABI(commit_store_1_0_0.CommitStoreABI)
+ eventSig := abihelpers.MustGetEventID(ReportAccepted, commitStoreABI)
+ commitReportArgs := abihelpers.MustGetEventInputs(ReportAccepted, commitStoreABI)
+ filters := []logpoller.Filter{
+ {
+ Name: logpoller.FilterName(EXEC_REPORT_ACCEPTS, addr.String()),
+ EventSigs: []common.Hash{eventSig},
+ Addresses: []common.Address{addr},
+ Retention: ccipdata.CommitExecLogsRetention,
+ },
+ }
+ return &CommitStore{
+ commitStore: commitStore,
+ address: addr,
+ lggr: lggr,
+ lp: lp,
+
+ // Note that sourceMaxGasPrice and estimator now have explicit setters (CCIP-2493)
+
+ filters: filters,
+ commitReportArgs: commitReportArgs,
+ reportAcceptedSig: eventSig,
+ // offset || priceUpdatesOffset || minSeqNum || maxSeqNum || merkleRoot
+ reportAcceptedMaxSeqIndex: 3,
+ configMu: sync.RWMutex{},
+
+ // The fields below are initially empty and set on ChangeConfig method
+ offchainConfig: cciptypes.CommitOffchainConfig{},
+ gasPriceEstimator: prices.ExecGasPriceEstimator{},
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/commit_store_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/commit_store_test.go
new file mode 100644
index 00000000000..b10e3ec8893
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/commit_store_test.go
@@ -0,0 +1,49 @@
+package v1_0_0
+
+import (
+ "math/big"
+ "math/rand"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+)
+
+func TestCommitReportEncoding(t *testing.T) {
+ ctx := testutils.Context(t)
+ report := cciptypes.CommitStoreReport{
+ TokenPrices: []cciptypes.TokenPrice{
+ {
+ Token: cciptypes.Address(utils.RandomAddress().String()),
+ Value: big.NewInt(9e18),
+ },
+ },
+ GasPrices: []cciptypes.GasPrice{
+ {
+ DestChainSelector: rand.Uint64(),
+ Value: big.NewInt(2000e9),
+ },
+ },
+ MerkleRoot: [32]byte{123},
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 10},
+ }
+
+ c, err := NewCommitStore(logger.Test(t), utils.RandomAddress(), nil, mocks.NewLogPoller(t))
+ assert.NoError(t, err)
+
+ encodedReport, err := c.EncodeCommitReport(ctx, report)
+ require.NoError(t, err)
+ assert.Greater(t, len(encodedReport), 0)
+
+ decodedReport, err := c.DecodeCommitReport(ctx, encodedReport)
+ require.NoError(t, err)
+ require.Equal(t, report.TokenPrices, decodedReport.TokenPrices)
+ require.Equal(t, report, decodedReport)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/hasher.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/hasher.go
new file mode 100644
index 00000000000..0d1b7f736f6
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/hasher.go
@@ -0,0 +1,85 @@
+package v1_0_0
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+const (
+ MetaDataHashPrefix = "EVM2EVMMessageEvent"
+)
+
+var LeafDomainSeparator = [1]byte{0x00}
+
+type LeafHasher struct {
+ metaDataHash [32]byte
+ ctx hashutil.Hasher[[32]byte]
+ onRamp *evm_2_evm_onramp_1_0_0.EVM2EVMOnRamp
+}
+
+func GetMetaDataHash[H hashutil.Hash](ctx hashutil.Hasher[H], prefix [32]byte, sourceChainSelector uint64, onRampId common.Address, destChainSelector uint64) H {
+ paddedOnRamp := common.BytesToHash(onRampId[:])
+ return ctx.Hash(utils.ConcatBytes(prefix[:], math.U256Bytes(big.NewInt(0).SetUint64(sourceChainSelector)), math.U256Bytes(big.NewInt(0).SetUint64(destChainSelector)), paddedOnRamp[:]))
+}
+
+func NewLeafHasher(sourceChainSelector uint64, destChainSelector uint64, onRampId common.Address, ctx hashutil.Hasher[[32]byte], onRamp *evm_2_evm_onramp_1_0_0.EVM2EVMOnRamp) *LeafHasher {
+ return &LeafHasher{
+ metaDataHash: GetMetaDataHash(ctx, ctx.Hash([]byte(MetaDataHashPrefix)), sourceChainSelector, onRampId, destChainSelector),
+ ctx: ctx,
+ onRamp: onRamp,
+ }
+}
+
+func (t *LeafHasher) HashLeaf(log types.Log) ([32]byte, error) {
+ message, err := t.onRamp.ParseCCIPSendRequested(log)
+ if err != nil {
+ return [32]byte{}, err
+ }
+ encodedTokens, err := abihelpers.ABIEncode(
+ `[
+{"components": [{"name":"token","type":"address"},{"name":"amount","type":"uint256"}], "type":"tuple[]"}]`, message.Message.TokenAmounts)
+ if err != nil {
+ return [32]byte{}, err
+ }
+
+ packedValues, err := abihelpers.ABIEncode(
+ `[
+{"name": "leafDomainSeparator","type":"bytes1"},
+{"name": "metadataHash", "type":"bytes32"},
+{"name": "sequenceNumber", "type":"uint64"},
+{"name": "nonce", "type":"uint64"},
+{"name": "sender", "type":"address"},
+{"name": "receiver", "type":"address"},
+{"name": "dataHash", "type":"bytes32"},
+{"name": "tokenAmountsHash", "type":"bytes32"},
+{"name": "gasLimit", "type":"uint256"},
+{"name": "strict", "type":"bool"},
+{"name": "feeToken","type": "address"},
+{"name": "feeTokenAmount","type": "uint256"}
+]`,
+ LeafDomainSeparator,
+ t.metaDataHash,
+ message.Message.SequenceNumber,
+ message.Message.Nonce,
+ message.Message.Sender,
+ message.Message.Receiver,
+ t.ctx.Hash(message.Message.Data),
+ t.ctx.Hash(encodedTokens),
+ message.Message.GasLimit,
+ message.Message.Strict,
+ message.Message.FeeToken,
+ message.Message.FeeTokenAmount,
+ )
+ if err != nil {
+ return [32]byte{}, err
+ }
+ return t.ctx.Hash(packedValues), nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/hasher_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/hasher_test.go
new file mode 100644
index 00000000000..b1219a27dfa
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/hasher_test.go
@@ -0,0 +1,84 @@
+package v1_0_0
+
+import (
+ "encoding/hex"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+func TestHasherV1_0_0(t *testing.T) {
+ sourceChainSelector, destChainSelector := uint64(1), uint64(4)
+ onRampAddress := common.HexToAddress("0x5550000000000000000000000000000000000001")
+ onRampABI := abihelpers.MustParseABI(evm_2_evm_onramp_1_0_0.EVM2EVMOnRampABI)
+
+ ramp, err := evm_2_evm_onramp_1_0_0.NewEVM2EVMOnRamp(onRampAddress, nil)
+ require.NoError(t, err)
+ hashingCtx := hashutil.NewKeccak()
+ hasher := NewLeafHasher(sourceChainSelector, destChainSelector, onRampAddress, hashingCtx, ramp)
+
+ message := evm_2_evm_onramp_1_0_0.InternalEVM2EVMMessage{
+ SourceChainSelector: sourceChainSelector,
+ Sender: common.HexToAddress("0x1110000000000000000000000000000000000001"),
+ Receiver: common.HexToAddress("0x2220000000000000000000000000000000000001"),
+ SequenceNumber: 1337,
+ GasLimit: big.NewInt(100),
+ Strict: false,
+ Nonce: 1337,
+ FeeToken: common.Address{},
+ FeeTokenAmount: big.NewInt(1),
+ Data: []byte{},
+ TokenAmounts: []evm_2_evm_onramp_1_0_0.ClientEVMTokenAmount{{Token: common.HexToAddress("0x4440000000000000000000000000000000000001"), Amount: big.NewInt(12345678900)}},
+ MessageId: [32]byte{},
+ }
+
+ data, err := onRampABI.Events[CCIPSendRequestedEventName].Inputs.Pack(message)
+ require.NoError(t, err)
+ hash, err := hasher.HashLeaf(types.Log{Topics: []common.Hash{abihelpers.MustGetEventID("CCIPSendRequested", onRampABI)}, Data: data})
+ require.NoError(t, err)
+
+ // NOTE: Must match spec
+ require.Equal(t, "26f282c6ac8231933b1799648d01ff6cec792a33fb37408b4d135968f9168ace", hex.EncodeToString(hash[:]))
+
+ message = evm_2_evm_onramp_1_0_0.InternalEVM2EVMMessage{
+ SourceChainSelector: sourceChainSelector,
+ Sender: common.HexToAddress("0x1110000000000000000000000000000000000001"),
+ Receiver: common.HexToAddress("0x2220000000000000000000000000000000000001"),
+ SequenceNumber: 1337,
+ GasLimit: big.NewInt(100),
+ Strict: false,
+ Nonce: 1337,
+ FeeToken: common.Address{},
+ FeeTokenAmount: big.NewInt(1e12),
+ Data: []byte("foo bar baz"),
+ TokenAmounts: []evm_2_evm_onramp_1_0_0.ClientEVMTokenAmount{
+ {Token: common.HexToAddress("0x4440000000000000000000000000000000000001"), Amount: big.NewInt(12345678900)},
+ {Token: common.HexToAddress("0x6660000000000000000000000000000000000001"), Amount: big.NewInt(4204242)},
+ },
+ MessageId: [32]byte{},
+ }
+
+ data, err = onRampABI.Events[CCIPSendRequestedEventName].Inputs.Pack(message)
+ require.NoError(t, err)
+ hash, err = hasher.HashLeaf(types.Log{Topics: []common.Hash{abihelpers.MustGetEventID("CCIPSendRequested", onRampABI)}, Data: data})
+ require.NoError(t, err)
+
+ // NOTE: Must match spec
+ require.Equal(t, "05cee92e7cb86a37b6536554828a5b21ff20ac3d4ef821ec47056f1d963313de", hex.EncodeToString(hash[:]))
+}
+
+func TestMetaDataHash(t *testing.T) {
+ sourceChainSelector, destChainSelector := uint64(1), uint64(4)
+ onRampAddress := common.HexToAddress("0x5550000000000000000000000000000000000001")
+ ctx := hashutil.NewKeccak()
+ hash := GetMetaDataHash(ctx, ctx.Hash([]byte(MetaDataHashPrefix)), sourceChainSelector, onRampAddress, destChainSelector)
+ require.Equal(t, "1409948abde219f43870c3d6d1c16beabd8878eb5039a3fa765eb56e4b8ded9e", hex.EncodeToString(hash[:]))
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp.go
new file mode 100644
index 00000000000..c8b7c504ff2
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp.go
@@ -0,0 +1,686 @@
+package v1_0_0
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "sync"
+ "time"
+
+ mapset "github.com/deckarep/golang-set/v2"
+ "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"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "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/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/logpollerutil"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+const (
+ EXEC_EXECUTION_STATE_CHANGES = "Exec execution state changes"
+ EXEC_TOKEN_POOL_ADDED = "Token pool added"
+ EXEC_TOKEN_POOL_REMOVED = "Token pool removed"
+)
+
+var (
+ abiOffRamp = abihelpers.MustParseABI(evm_2_evm_offramp_1_0_0.EVM2EVMOffRampABI)
+ _ ccipdata.OffRampReader = &OffRamp{}
+ ExecutionStateChangedEvent = abihelpers.MustGetEventID("ExecutionStateChanged", abiOffRamp)
+ PoolAddedEvent = abihelpers.MustGetEventID("PoolAdded", abiOffRamp)
+ PoolRemovedEvent = abihelpers.MustGetEventID("PoolRemoved", abiOffRamp)
+ ExecutionStateChangedSeqNrIndex = 1
+)
+
+var offRamp_poolAddedPoolRemovedEvents = []common.Hash{PoolAddedEvent, PoolRemovedEvent}
+
+type ExecOnchainConfig evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig
+
+func (d ExecOnchainConfig) AbiString() string {
+ return `
+ [
+ {
+ "components": [
+ {"name": "permissionLessExecutionThresholdSeconds", "type": "uint32"},
+ {"name": "router", "type": "address"},
+ {"name": "priceRegistry", "type": "address"},
+ {"name": "maxTokensLength", "type": "uint16"},
+ {"name": "maxDataSize", "type": "uint32"}
+ ],
+ "type": "tuple"
+ }
+ ]`
+}
+
+func (d ExecOnchainConfig) Validate() error {
+ if d.PermissionLessExecutionThresholdSeconds == 0 {
+ return errors.New("must set PermissionLessExecutionThresholdSeconds")
+ }
+ if d.Router == (common.Address{}) {
+ return errors.New("must set Router address")
+ }
+ if d.PriceRegistry == (common.Address{}) {
+ return errors.New("must set PriceRegistry address")
+ }
+ if d.MaxTokensLength == 0 {
+ return errors.New("must set MaxTokensLength")
+ }
+ if d.MaxDataSize == 0 {
+ return errors.New("must set MaxDataSize")
+ }
+ return nil
+}
+
+// ExecOffchainConfig is the configuration for nodes executing committed CCIP messages (v1.0–v1.2).
+// It comes from the OffchainConfig field of the corresponding OCR2 plugin configuration.
+// NOTE: do not change the JSON format of this struct without consulting with the RDD people first.
+type ExecOffchainConfig struct {
+ // SourceFinalityDepth indicates how many confirmations a transaction should get on the source chain event before we consider it finalized.
+ SourceFinalityDepth uint32
+ // See [ccipdata.ExecOffchainConfig.DestOptimisticConfirmations]
+ DestOptimisticConfirmations uint32
+ // DestFinalityDepth indicates how many confirmations a transaction should get on the destination chain event before we consider it finalized.
+ DestFinalityDepth uint32
+ // See [ccipdata.ExecOffchainConfig.BatchGasLimit]
+ BatchGasLimit uint32
+ // See [ccipdata.ExecOffchainConfig.RelativeBoostPerWaitHour]
+ RelativeBoostPerWaitHour float64
+ // See [ccipdata.ExecOffchainConfig.InflightCacheExpiry]
+ InflightCacheExpiry config.Duration
+ // See [ccipdata.ExecOffchainConfig.RootSnoozeTime]
+ RootSnoozeTime config.Duration
+ // See [ccipdata.ExecOffchainConfig.BatchingStrategyID]
+ BatchingStrategyID uint32
+ // See [ccipdata.ExecOffchainConfig.MessageVisibilityInterval]
+ MessageVisibilityInterval config.Duration
+}
+
+func (c ExecOffchainConfig) Validate() error {
+ if c.SourceFinalityDepth == 0 {
+ return errors.New("must set SourceFinalityDepth")
+ }
+ if c.DestFinalityDepth == 0 {
+ return errors.New("must set DestFinalityDepth")
+ }
+ if c.DestOptimisticConfirmations == 0 {
+ return errors.New("must set DestOptimisticConfirmations")
+ }
+ if c.BatchGasLimit == 0 {
+ return errors.New("must set BatchGasLimit")
+ }
+ if c.RelativeBoostPerWaitHour == 0 {
+ return errors.New("must set RelativeBoostPerWaitHour")
+ }
+ if c.InflightCacheExpiry.Duration() == 0 {
+ return errors.New("must set InflightCacheExpiry")
+ }
+ if c.RootSnoozeTime.Duration() == 0 {
+ return errors.New("must set RootSnoozeTime")
+ }
+
+ return nil
+}
+
+type OffRamp struct {
+ offRampV100 evm_2_evm_offramp_1_0_0.EVM2EVMOffRampInterface
+ addr common.Address
+ lp logpoller.LogPoller
+ Logger logger.Logger
+ Client client.Client
+ evmBatchCaller rpclib.EvmBatchCaller
+ filters []logpoller.Filter
+ Estimator gas.EvmFeeEstimator
+ DestMaxGasPrice *big.Int
+ ExecutionReportArgs abi.Arguments
+ eventIndex int
+ eventSig common.Hash
+ cachedOffRampTokens cache.AutoSync[cciptypes.OffRampTokens]
+ sourceToDestTokensCache sync.Map
+
+ // Dynamic config
+ // configMu guards all the dynamic config fields.
+ configMu sync.RWMutex
+ gasPriceEstimator prices.GasPriceEstimatorExec
+ offchainConfig cciptypes.ExecOffchainConfig
+ onchainConfig cciptypes.ExecOnchainConfig
+}
+
+func (o *OffRamp) GetStaticConfig(ctx context.Context) (cciptypes.OffRampStaticConfig, error) {
+ if o.offRampV100 == nil {
+ return cciptypes.OffRampStaticConfig{}, fmt.Errorf("offramp not initialized")
+ }
+ c, err := o.offRampV100.GetStaticConfig(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return cciptypes.OffRampStaticConfig{}, fmt.Errorf("error while retrieving offramp config: %w", err)
+ }
+ return cciptypes.OffRampStaticConfig{
+ CommitStore: cciptypes.Address(c.CommitStore.String()),
+ ChainSelector: c.ChainSelector,
+ SourceChainSelector: c.SourceChainSelector,
+ OnRamp: cciptypes.Address(c.OnRamp.String()),
+ PrevOffRamp: cciptypes.Address(c.PrevOffRamp.String()),
+ ArmProxy: cciptypes.Address(c.ArmProxy.String()),
+ }, nil
+}
+
+func (o *OffRamp) GetExecutionState(ctx context.Context, sequenceNumber uint64) (uint8, error) {
+ return o.offRampV100.GetExecutionState(&bind.CallOpts{Context: ctx}, sequenceNumber)
+}
+
+func (o *OffRamp) GetSenderNonce(ctx context.Context, sender cciptypes.Address) (uint64, error) {
+ evmAddr, err := ccipcalc.GenericAddrToEvm(sender)
+ if err != nil {
+ return 0, err
+ }
+ return o.offRampV100.GetSenderNonce(&bind.CallOpts{Context: ctx}, evmAddr)
+}
+
+func (o *OffRamp) ListSenderNonces(ctx context.Context, senders []cciptypes.Address) (map[cciptypes.Address]uint64, error) {
+ if len(senders) == 0 {
+ return make(map[cciptypes.Address]uint64), nil
+ }
+
+ evmSenders, err := ccipcalc.GenericAddrsToEvm(senders...)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to convert generic addresses to evm addresses")
+ }
+
+ evmCalls := make([]rpclib.EvmCall, 0, len(evmSenders))
+ for _, evmAddr := range evmSenders {
+ evmCalls = append(evmCalls, rpclib.NewEvmCall(
+ abiOffRamp,
+ "getSenderNonce",
+ o.addr,
+ evmAddr,
+ ))
+ }
+
+ results, err := o.evmBatchCaller.BatchCall(ctx, 0, evmCalls)
+ if err != nil {
+ o.Logger.Errorw("error while batch fetching sender nonces", "err", err, "senders", evmSenders)
+ return nil, err
+ }
+
+ nonces, err := rpclib.ParseOutputs[uint64](results, func(d rpclib.DataAndErr) (uint64, error) {
+ return rpclib.ParseOutput[uint64](d, 0)
+ })
+ if err != nil {
+ o.Logger.Errorw("error while parsing sender nonces", "err", err, "senders", evmSenders)
+ return nil, err
+ }
+
+ if len(senders) != len(nonces) {
+ o.Logger.Errorw("unexpected number of nonces returned", "senders", evmSenders, "nonces", nonces)
+ return nil, errors.New("unexpected number of nonces returned")
+ }
+
+ senderNonce := make(map[cciptypes.Address]uint64, len(senders))
+ for i, sender := range senders {
+ senderNonce[sender] = nonces[i]
+ }
+ return senderNonce, nil
+}
+
+func (o *OffRamp) CurrentRateLimiterState(ctx context.Context) (cciptypes.TokenBucketRateLimit, error) {
+ state, err := o.offRampV100.CurrentRateLimiterState(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return cciptypes.TokenBucketRateLimit{}, err
+ }
+ return cciptypes.TokenBucketRateLimit{
+ Tokens: state.Tokens,
+ LastUpdated: state.LastUpdated,
+ IsEnabled: state.IsEnabled,
+ Capacity: state.Capacity,
+ Rate: state.Rate,
+ }, nil
+}
+
+func (o *OffRamp) getDestinationTokensFromSourceTokens(ctx context.Context, tokenAddresses []cciptypes.Address) ([]cciptypes.Address, error) {
+ destTokens := make([]cciptypes.Address, len(tokenAddresses))
+ found := make(map[cciptypes.Address]bool)
+
+ for i, tokenAddress := range tokenAddresses {
+ if v, exists := o.sourceToDestTokensCache.Load(tokenAddress); exists {
+ if destToken, isAddr := v.(cciptypes.Address); isAddr {
+ destTokens[i] = destToken
+ found[tokenAddress] = true
+ } else {
+ o.Logger.Errorf("source to dest cache contains invalid type %T", v)
+ }
+ }
+ }
+
+ if len(found) == len(tokenAddresses) {
+ return destTokens, nil
+ }
+
+ evmAddrs, err := ccipcalc.GenericAddrsToEvm(tokenAddresses...)
+ if err != nil {
+ return nil, err
+ }
+
+ evmCalls := make([]rpclib.EvmCall, 0, len(tokenAddresses))
+ for i, sourceTk := range tokenAddresses {
+ if !found[sourceTk] {
+ evmCalls = append(evmCalls, rpclib.NewEvmCall(abiOffRamp, "getDestinationToken", o.addr, evmAddrs[i]))
+ }
+ }
+
+ results, err := o.evmBatchCaller.BatchCall(ctx, 0, evmCalls)
+ if err != nil {
+ return nil, fmt.Errorf("batch call limit: %w", err)
+ }
+
+ destTokensFromRpc, err := rpclib.ParseOutputs[common.Address](results, func(d rpclib.DataAndErr) (common.Address, error) {
+ return rpclib.ParseOutput[common.Address](d, 0)
+ })
+ if err != nil {
+ return nil, fmt.Errorf("parse outputs: %w", err)
+ }
+
+ j := 0
+ for i, sourceToken := range tokenAddresses {
+ if !found[sourceToken] {
+ destTokens[i] = cciptypes.Address(destTokensFromRpc[j].String())
+ o.sourceToDestTokensCache.Store(sourceToken, destTokens[i])
+ j++
+ }
+ }
+
+ seenDestTokens := mapset.NewSet[cciptypes.Address]()
+ for _, destToken := range destTokens {
+ if seenDestTokens.Contains(destToken) {
+ return nil, fmt.Errorf("offRamp misconfig, destination token %s already exists", destToken)
+ }
+ seenDestTokens.Add(destToken)
+ }
+
+ return destTokens, nil
+}
+
+func (o *OffRamp) GetSourceToDestTokensMapping(ctx context.Context) (map[cciptypes.Address]cciptypes.Address, error) {
+ tokens, err := o.GetTokens(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ destTokens, err := o.getDestinationTokensFromSourceTokens(ctx, tokens.SourceTokens)
+ if err != nil {
+ return nil, fmt.Errorf("get destination tokens from source tokens: %w", err)
+ }
+
+ srcToDstTokenMapping := make(map[cciptypes.Address]cciptypes.Address, len(tokens.SourceTokens))
+ for i, sourceToken := range tokens.SourceTokens {
+ srcToDstTokenMapping[sourceToken] = destTokens[i]
+ }
+ return srcToDstTokenMapping, nil
+}
+
+func (o *OffRamp) GetTokens(ctx context.Context) (cciptypes.OffRampTokens, error) {
+ return o.cachedOffRampTokens.Get(ctx, func(ctx context.Context) (cciptypes.OffRampTokens, error) {
+ destTokens, err := o.offRampV100.GetDestinationTokens(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return cciptypes.OffRampTokens{}, fmt.Errorf("get destination tokens: %w", err)
+ }
+ sourceTokens, err := o.offRampV100.GetSupportedTokens(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return cciptypes.OffRampTokens{}, err
+ }
+
+ return cciptypes.OffRampTokens{
+ DestinationTokens: ccipcalc.EvmAddrsToGeneric(destTokens...),
+ SourceTokens: ccipcalc.EvmAddrsToGeneric(sourceTokens...),
+ }, nil
+ })
+}
+
+func (o *OffRamp) GetRouter(ctx context.Context) (cciptypes.Address, error) {
+ dynamicConfig, err := o.offRampV100.GetDynamicConfig(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return "", err
+ }
+ return ccipcalc.EvmAddrToGeneric(dynamicConfig.Router), nil
+}
+
+func (o *OffRamp) OffchainConfig(ctx context.Context) (cciptypes.ExecOffchainConfig, error) {
+ o.configMu.RLock()
+ defer o.configMu.RUnlock()
+ return o.offchainConfig, nil
+}
+
+func (o *OffRamp) OnchainConfig(ctx context.Context) (cciptypes.ExecOnchainConfig, error) {
+ o.configMu.RLock()
+ defer o.configMu.RUnlock()
+ return o.onchainConfig, nil
+}
+
+func (o *OffRamp) GasPriceEstimator(ctx context.Context) (cciptypes.GasPriceEstimatorExec, error) {
+ o.configMu.RLock()
+ defer o.configMu.RUnlock()
+ return o.gasPriceEstimator, nil
+}
+
+func (o *OffRamp) Address(ctx context.Context) (cciptypes.Address, error) {
+ return cciptypes.Address(o.addr.String()), nil
+}
+
+func (o *OffRamp) UpdateDynamicConfig(onchainConfig cciptypes.ExecOnchainConfig, offchainConfig cciptypes.ExecOffchainConfig, gasPriceEstimator prices.GasPriceEstimatorExec) {
+ o.configMu.Lock()
+ o.onchainConfig = onchainConfig
+ o.offchainConfig = offchainConfig
+ o.gasPriceEstimator = gasPriceEstimator
+ o.configMu.Unlock()
+}
+
+func (o *OffRamp) ChangeConfig(ctx context.Context, onchainConfigBytes []byte, offchainConfigBytes []byte) (cciptypes.Address, cciptypes.Address, error) {
+ onchainConfigParsed, err := abihelpers.DecodeAbiStruct[ExecOnchainConfig](onchainConfigBytes)
+ if err != nil {
+ return "", "", err
+ }
+
+ offchainConfigParsed, err := ccipconfig.DecodeOffchainConfig[ExecOffchainConfig](offchainConfigBytes)
+ if err != nil {
+ return "", "", err
+ }
+ destRouter, err := router.NewRouter(onchainConfigParsed.Router, o.Client)
+ if err != nil {
+ return "", "", err
+ }
+ destWrappedNative, err := destRouter.GetWrappedNative(nil)
+ if err != nil {
+ return "", "", err
+ }
+
+ offchainConfig := cciptypes.ExecOffchainConfig{
+ DestOptimisticConfirmations: offchainConfigParsed.DestOptimisticConfirmations,
+ BatchGasLimit: offchainConfigParsed.BatchGasLimit,
+ RelativeBoostPerWaitHour: offchainConfigParsed.RelativeBoostPerWaitHour,
+ InflightCacheExpiry: offchainConfigParsed.InflightCacheExpiry,
+ RootSnoozeTime: offchainConfigParsed.RootSnoozeTime,
+ MessageVisibilityInterval: offchainConfigParsed.MessageVisibilityInterval,
+ BatchingStrategyID: offchainConfigParsed.BatchingStrategyID,
+ }
+ onchainConfig := cciptypes.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: time.Second * time.Duration(onchainConfigParsed.PermissionLessExecutionThresholdSeconds),
+ Router: cciptypes.Address(onchainConfigParsed.Router.String()),
+ }
+ gasPriceEstimator := prices.NewExecGasPriceEstimator(o.Estimator, o.DestMaxGasPrice, 0)
+
+ o.UpdateDynamicConfig(onchainConfig, offchainConfig, gasPriceEstimator)
+
+ o.Logger.Infow("Starting exec plugin",
+ "offchainConfig", onchainConfigParsed,
+ "onchainConfig", offchainConfigParsed)
+ return cciptypes.Address(onchainConfigParsed.PriceRegistry.String()),
+ cciptypes.Address(destWrappedNative.String()), nil
+}
+
+func (o *OffRamp) Close() error {
+ return logpollerutil.UnregisterLpFilters(o.lp, o.filters)
+}
+
+func (o *OffRamp) GetExecutionStateChangesBetweenSeqNums(ctx context.Context, seqNumMin, seqNumMax uint64, confs int) ([]cciptypes.ExecutionStateChangedWithTxMeta, error) {
+ latestBlock, err := o.lp.LatestBlock(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("get lp latest block: %w", err)
+ }
+
+ logs, err := o.lp.IndexedLogsTopicRange(
+ ctx,
+ o.eventSig,
+ o.addr,
+ o.eventIndex,
+ logpoller.EvmWord(seqNumMin),
+ logpoller.EvmWord(seqNumMax),
+ evmtypes.Confirmations(confs),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.ExecutionStateChanged](
+ logs,
+ o.Logger,
+ func(log types.Log) (*cciptypes.ExecutionStateChanged, error) {
+ sc, err1 := o.offRampV100.ParseExecutionStateChanged(log)
+ if err1 != nil {
+ return nil, err1
+ }
+
+ return &cciptypes.ExecutionStateChanged{
+ SequenceNumber: sc.SequenceNumber,
+ }, nil
+ },
+ )
+ if err != nil {
+ return nil, fmt.Errorf("parse logs: %w", err)
+ }
+
+ res := make([]cciptypes.ExecutionStateChangedWithTxMeta, 0, len(parsedLogs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.ExecutionStateChangedWithTxMeta{
+ TxMeta: log.TxMeta.WithFinalityStatus(uint64(latestBlock.FinalizedBlockNumber)),
+ ExecutionStateChanged: log.Data,
+ })
+ }
+ return res, nil
+}
+
+func encodeExecutionReport(args abi.Arguments, report cciptypes.ExecReport) ([]byte, error) {
+ var msgs []evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage
+ for _, msg := range report.Messages {
+ var ta []evm_2_evm_offramp_1_0_0.ClientEVMTokenAmount
+ for _, tokenAndAmount := range msg.TokenAmounts {
+ evmTokenAddr, err := ccipcalc.GenericAddrToEvm(tokenAndAmount.Token)
+ if err != nil {
+ return nil, err
+ }
+
+ ta = append(ta, evm_2_evm_offramp_1_0_0.ClientEVMTokenAmount{
+ Token: evmTokenAddr,
+ Amount: tokenAndAmount.Amount,
+ })
+ }
+
+ senderEvmAddr, err := ccipcalc.GenericAddrToEvm(msg.Sender)
+ if err != nil {
+ return nil, fmt.Errorf("msg sender is not evm addr: %w", err)
+ }
+
+ receiverEvmAddr, err := ccipcalc.GenericAddrToEvm(msg.Receiver)
+ if err != nil {
+ return nil, fmt.Errorf("msg receiver is not evm addr: %w", err)
+ }
+
+ feeTokenEvmAddr, err := ccipcalc.GenericAddrToEvm(msg.FeeToken)
+ if err != nil {
+ return nil, fmt.Errorf("fee token is not evm addr: %w", err)
+ }
+
+ msgs = append(msgs, evm_2_evm_offramp_1_0_0.InternalEVM2EVMMessage{
+ SourceChainSelector: msg.SourceChainSelector,
+ Sender: senderEvmAddr,
+ Receiver: receiverEvmAddr,
+ SequenceNumber: msg.SequenceNumber,
+ GasLimit: msg.GasLimit,
+ Strict: msg.Strict,
+ Nonce: msg.Nonce,
+ FeeToken: feeTokenEvmAddr,
+ FeeTokenAmount: msg.FeeTokenAmount,
+ Data: msg.Data,
+ TokenAmounts: ta,
+ MessageId: msg.MessageID,
+ })
+ }
+
+ rep := evm_2_evm_offramp_1_0_0.InternalExecutionReport{
+ Messages: msgs,
+ OffchainTokenData: report.OffchainTokenData,
+ Proofs: report.Proofs,
+ ProofFlagBits: report.ProofFlagBits,
+ }
+ return args.PackValues([]interface{}{&rep})
+}
+
+func (o *OffRamp) EncodeExecutionReport(ctx context.Context, report cciptypes.ExecReport) ([]byte, error) {
+ return encodeExecutionReport(o.ExecutionReportArgs, report)
+}
+
+func DecodeExecReport(ctx context.Context, args abi.Arguments, report []byte) (cciptypes.ExecReport, error) {
+ unpacked, err := args.Unpack(report)
+ if err != nil {
+ return cciptypes.ExecReport{}, err
+ }
+ if len(unpacked) == 0 {
+ return cciptypes.ExecReport{}, errors.New("assumptionViolation: expected at least one element")
+ }
+
+ erStruct, ok := unpacked[0].(struct {
+ Messages []struct {
+ SourceChainSelector uint64 `json:"sourceChainSelector"`
+ SequenceNumber uint64 `json:"sequenceNumber"`
+ FeeTokenAmount *big.Int `json:"feeTokenAmount"`
+ Sender common.Address `json:"sender"`
+ Nonce uint64 `json:"nonce"`
+ GasLimit *big.Int `json:"gasLimit"`
+ Strict bool `json:"strict"`
+ Receiver common.Address `json:"receiver"`
+ Data []uint8 `json:"data"`
+ TokenAmounts []struct {
+ Token common.Address `json:"token"`
+ Amount *big.Int `json:"amount"`
+ } `json:"tokenAmounts"`
+ FeeToken common.Address `json:"feeToken"`
+ MessageId [32]uint8 `json:"messageId"`
+ } `json:"messages"`
+ OffchainTokenData [][][]uint8 `json:"offchainTokenData"`
+ Proofs [][32]uint8 `json:"proofs"`
+ ProofFlagBits *big.Int `json:"proofFlagBits"`
+ })
+
+ if !ok {
+ return cciptypes.ExecReport{}, fmt.Errorf("got %T", unpacked[0])
+ }
+ messages := make([]cciptypes.EVM2EVMMessage, 0, len(erStruct.Messages))
+ for _, msg := range erStruct.Messages {
+ var tokensAndAmounts []cciptypes.TokenAmount
+ for _, tokenAndAmount := range msg.TokenAmounts {
+ tokensAndAmounts = append(tokensAndAmounts, cciptypes.TokenAmount{
+ Token: cciptypes.Address(tokenAndAmount.Token.String()),
+ Amount: tokenAndAmount.Amount,
+ })
+ }
+ messages = append(messages, cciptypes.EVM2EVMMessage{
+ SequenceNumber: msg.SequenceNumber,
+ GasLimit: msg.GasLimit,
+ Nonce: msg.Nonce,
+ MessageID: msg.MessageId,
+ SourceChainSelector: msg.SourceChainSelector,
+ Sender: cciptypes.Address(msg.Sender.String()),
+ Receiver: cciptypes.Address(msg.Receiver.String()),
+ Strict: msg.Strict,
+ FeeToken: cciptypes.Address(msg.FeeToken.String()),
+ FeeTokenAmount: msg.FeeTokenAmount,
+ Data: msg.Data,
+ TokenAmounts: tokensAndAmounts,
+ // TODO: Not needed for plugins, but should be recomputed for consistency.
+ // Requires the offramp knowing about onramp version
+ Hash: [32]byte{},
+ })
+ }
+
+ // Unpack will populate with big.Int{false, } for 0 values,
+ // which is different from the expected big.NewInt(0). Rebuild to the expected value for this case.
+ return cciptypes.ExecReport{
+ Messages: messages,
+ OffchainTokenData: erStruct.OffchainTokenData,
+ Proofs: erStruct.Proofs,
+ ProofFlagBits: new(big.Int).SetBytes(erStruct.ProofFlagBits.Bytes()),
+ }, nil
+}
+
+func (o *OffRamp) DecodeExecutionReport(ctx context.Context, report []byte) (cciptypes.ExecReport, error) {
+ return DecodeExecReport(ctx, o.ExecutionReportArgs, report)
+}
+
+func (o *OffRamp) RegisterFilters() error {
+ return logpollerutil.RegisterLpFilters(o.lp, o.filters)
+}
+
+func NewOffRamp(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int) (*OffRamp, error) {
+ offRamp, err := evm_2_evm_offramp_1_0_0.NewEVM2EVMOffRamp(addr, ec)
+ if err != nil {
+ return nil, err
+ }
+
+ executionStateChangedSequenceNumberIndex := 1
+ executionReportArgs := abihelpers.MustGetMethodInputs("manuallyExecute", abiOffRamp)[:1]
+ filters := []logpoller.Filter{
+ {
+ Name: logpoller.FilterName(EXEC_EXECUTION_STATE_CHANGES, addr.String()),
+ EventSigs: []common.Hash{ExecutionStateChangedEvent},
+ Addresses: []common.Address{addr},
+ Retention: ccipdata.CommitExecLogsRetention,
+ },
+ {
+ Name: logpoller.FilterName(EXEC_TOKEN_POOL_ADDED, addr.String()),
+ EventSigs: []common.Hash{PoolAddedEvent},
+ Addresses: []common.Address{addr},
+ Retention: ccipdata.CacheEvictionLogsRetention,
+ },
+ {
+ Name: logpoller.FilterName(EXEC_TOKEN_POOL_REMOVED, addr.String()),
+ EventSigs: []common.Hash{PoolRemovedEvent},
+ Addresses: []common.Address{addr},
+ Retention: ccipdata.CacheEvictionLogsRetention,
+ },
+ }
+
+ return &OffRamp{
+ offRampV100: offRamp,
+ Client: ec,
+ addr: addr,
+ Logger: lggr,
+ lp: lp,
+ filters: filters,
+ Estimator: estimator,
+ DestMaxGasPrice: destMaxGasPrice,
+ ExecutionReportArgs: executionReportArgs,
+ eventSig: ExecutionStateChangedEvent,
+ eventIndex: executionStateChangedSequenceNumberIndex,
+ configMu: sync.RWMutex{},
+ evmBatchCaller: rpclib.NewDynamicLimitedBatchCaller(
+ lggr,
+ ec,
+ rpclib.DefaultRpcBatchSizeLimit,
+ rpclib.DefaultRpcBatchBackOffMultiplier,
+ rpclib.DefaultMaxParallelRpcCalls,
+ ),
+ cachedOffRampTokens: cache.NewLogpollerEventsBased[cciptypes.OffRampTokens](
+ lp,
+ offRamp_poolAddedPoolRemovedEvents,
+ offRamp.Address(),
+ ),
+ // values set on the fly after ChangeConfig is called
+ gasPriceEstimator: prices.ExecGasPriceEstimator{},
+ offchainConfig: cciptypes.ExecOffchainConfig{},
+ onchainConfig: cciptypes.ExecOnchainConfig{},
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_reader_test.go
new file mode 100644
index 00000000000..67d40df2bf4
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_reader_test.go
@@ -0,0 +1,39 @@
+package v1_0_0_test
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+)
+
+func TestExecutionReportEncodingV100(t *testing.T) {
+ // Note could consider some fancier testing here (fuzz/property)
+ // but I think that would essentially be testing geth's abi library
+ // as our encode/decode is a thin wrapper around that.
+ report := cciptypes.ExecReport{
+ Messages: []cciptypes.EVM2EVMMessage{},
+ OffchainTokenData: [][][]byte{{}},
+ Proofs: [][32]byte{testutils.Random32Byte()},
+ ProofFlagBits: big.NewInt(133),
+ }
+
+ offRamp, err := v1_0_0.NewOffRamp(logger.Test(t), utils.RandomAddress(), nil, lpmocks.NewLogPoller(t), nil, nil)
+ require.NoError(t, err)
+
+ ctx := testutils.Context(t)
+ encodeExecutionReport, err := offRamp.EncodeExecutionReport(ctx, report)
+ require.NoError(t, err)
+ decodeCommitReport, err := offRamp.DecodeExecutionReport(ctx, encodeExecutionReport)
+ require.NoError(t, err)
+ require.Equal(t, report.Proofs, decodeCommitReport.Proofs)
+ require.Equal(t, report, decodeCommitReport)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_reader_unit_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_reader_unit_test.go
new file mode 100644
index 00000000000..f1cd2a4f841
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_reader_unit_test.go
@@ -0,0 +1,230 @@
+package v1_0_0
+
+import (
+ "fmt"
+ "math/rand"
+ "slices"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ 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/gethwrappers/ccip/generated/evm_2_evm_offramp_1_0_0"
+ mock_contracts "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/mocks/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks"
+)
+
+func TestOffRampGetDestinationTokensFromSourceTokens(t *testing.T) {
+ ctx := testutils.Context(t)
+ const numSrcTokens = 20
+
+ testCases := []struct {
+ name string
+ outputChangeFn func(outputs []rpclib.DataAndErr) []rpclib.DataAndErr
+ expErr bool
+ }{
+ {
+ name: "happy path",
+ outputChangeFn: func(outputs []rpclib.DataAndErr) []rpclib.DataAndErr { return outputs },
+ expErr: false,
+ },
+ {
+ name: "rpc error",
+ outputChangeFn: func(outputs []rpclib.DataAndErr) []rpclib.DataAndErr {
+ outputs[2].Err = fmt.Errorf("some error")
+ return outputs
+ },
+ expErr: true,
+ },
+ {
+ name: "unexpected outputs length should be fine if the type is correct",
+ outputChangeFn: func(outputs []rpclib.DataAndErr) []rpclib.DataAndErr {
+ outputs[0].Outputs = append(outputs[0].Outputs, "unexpected", 123)
+ return outputs
+ },
+ expErr: false,
+ },
+ {
+ name: "different compatible type",
+ outputChangeFn: func(outputs []rpclib.DataAndErr) []rpclib.DataAndErr {
+ outputs[0].Outputs = []any{outputs[0].Outputs[0].(common.Address)}
+ return outputs
+ },
+ expErr: false,
+ },
+ {
+ name: "different incompatible type",
+ outputChangeFn: func(outputs []rpclib.DataAndErr) []rpclib.DataAndErr {
+ outputs[0].Outputs = []any{outputs[0].Outputs[0].(common.Address).Bytes()}
+ return outputs
+ },
+ expErr: true,
+ },
+ }
+
+ lp := mocks.NewLogPoller(t)
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ batchCaller := rpclibmocks.NewEvmBatchCaller(t)
+ o := &OffRamp{evmBatchCaller: batchCaller, lp: lp}
+ srcTks, dstTks, outputs := generateTokensAndOutputs(numSrcTokens)
+ outputs = tc.outputChangeFn(outputs)
+ batchCaller.On("BatchCall", mock.Anything, mock.Anything, mock.Anything).Return(outputs, nil)
+ genericAddrs := ccipcalc.EvmAddrsToGeneric(srcTks...)
+ actualDstTokens, err := o.getDestinationTokensFromSourceTokens(ctx, genericAddrs)
+
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+
+ assert.NoError(t, err)
+ assert.Equal(t, ccipcalc.EvmAddrsToGeneric(dstTks...), actualDstTokens)
+ })
+ }
+}
+
+func TestCachedOffRampTokens(t *testing.T) {
+ // Test data.
+ srcTks, dstTks, _ := generateTokensAndOutputs(3)
+
+ // Mock contract wrapper.
+ mockOffRamp := mock_contracts.NewEVM2EVMOffRampInterface(t)
+ mockOffRamp.On("GetDestinationTokens", mock.Anything).Return(dstTks, nil)
+ mockOffRamp.On("GetSupportedTokens", mock.Anything).Return(srcTks, nil)
+ mockOffRamp.On("Address").Return(utils.RandomAddress())
+
+ lp := mocks.NewLogPoller(t)
+ lp.On("LatestBlock", mock.Anything).Return(logpoller.LogPollerBlock{BlockNumber: rand.Int63()}, nil)
+
+ offRamp := OffRamp{
+ offRampV100: mockOffRamp,
+ lp: lp,
+ Logger: logger.Test(t),
+ Client: evmclimocks.NewClient(t),
+ evmBatchCaller: rpclibmocks.NewEvmBatchCaller(t),
+ cachedOffRampTokens: cache.NewLogpollerEventsBased[cciptypes.OffRampTokens](
+ lp,
+ offRamp_poolAddedPoolRemovedEvents,
+ mockOffRamp.Address(),
+ ),
+ }
+
+ ctx := testutils.Context(t)
+ tokens, err := offRamp.GetTokens(ctx)
+ require.NoError(t, err)
+
+ // Verify data is properly loaded in the cache.
+ expectedPools := make(map[cciptypes.Address]cciptypes.Address)
+ for i := range dstTks {
+ expectedPools[cciptypes.Address(dstTks[i].String())] = cciptypes.Address(dstTks[i].String())
+ }
+ require.Equal(t, cciptypes.OffRampTokens{
+ DestinationTokens: ccipcalc.EvmAddrsToGeneric(dstTks...),
+ SourceTokens: ccipcalc.EvmAddrsToGeneric(srcTks...),
+ }, tokens)
+}
+
+func generateTokensAndOutputs(nbTokens uint) ([]common.Address, []common.Address, []rpclib.DataAndErr) {
+ srcTks := make([]common.Address, nbTokens)
+ dstTks := make([]common.Address, nbTokens)
+ outputs := make([]rpclib.DataAndErr, nbTokens)
+ for i := range srcTks {
+ srcTks[i] = utils.RandomAddress()
+ dstTks[i] = utils.RandomAddress()
+ outputs[i] = rpclib.DataAndErr{
+ Outputs: []any{dstTks[i]}, Err: nil,
+ }
+ }
+ return srcTks, dstTks, outputs
+}
+
+func Test_LogsAreProperlyMarkedAsFinalized(t *testing.T) {
+ minSeqNr := uint64(10)
+ maxSeqNr := uint64(14)
+ inputLogs := []logpoller.Log{
+ CreateExecutionStateChangeEventLog(t, 10, 2, utils.RandomBytes32()),
+ CreateExecutionStateChangeEventLog(t, 11, 3, utils.RandomBytes32()),
+ CreateExecutionStateChangeEventLog(t, 12, 5, utils.RandomBytes32()),
+ CreateExecutionStateChangeEventLog(t, 14, 7, utils.RandomBytes32()),
+ }
+
+ tests := []struct {
+ name string
+ lastFinalizedBlock uint64
+ expectedFinalizedSequenceNr []uint64
+ }{
+ {
+ "all logs are finalized",
+ 10,
+ []uint64{10, 11, 12, 14},
+ },
+ {
+ "some logs are finalized",
+ 5,
+ []uint64{10, 11, 12},
+ },
+ {
+ "no logs are finalized",
+ 1,
+ []uint64{},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ offrampAddress := utils.RandomAddress()
+
+ lp := mocks.NewLogPoller(t)
+ lp.On("LatestBlock", mock.Anything).
+ Return(logpoller.LogPollerBlock{FinalizedBlockNumber: int64(tt.lastFinalizedBlock)}, nil)
+ lp.On("IndexedLogsTopicRange", mock.Anything, ExecutionStateChangedEvent, offrampAddress, 1, logpoller.EvmWord(minSeqNr), logpoller.EvmWord(maxSeqNr), evmtypes.Confirmations(0)).
+ Return(inputLogs, nil)
+
+ offRamp, err := NewOffRamp(logger.Test(t), offrampAddress, evmclimocks.NewClient(t), lp, nil, nil)
+ require.NoError(t, err)
+ logs, err := offRamp.GetExecutionStateChangesBetweenSeqNums(testutils.Context(t), minSeqNr, maxSeqNr, 0)
+ require.NoError(t, err)
+ assert.Len(t, logs, len(inputLogs))
+
+ for _, log := range logs {
+ assert.Equal(t, slices.Contains(tt.expectedFinalizedSequenceNr, log.SequenceNumber), log.IsFinalized())
+ }
+ })
+ }
+}
+
+func TestGetRouter(t *testing.T) {
+ routerAddr := utils.RandomAddress()
+
+ mockOffRamp := mock_contracts.NewEVM2EVMOffRampInterface(t)
+ mockOffRamp.On("GetDynamicConfig", mock.Anything).Return(evm_2_evm_offramp_1_0_0.EVM2EVMOffRampDynamicConfig{
+ Router: routerAddr,
+ }, nil)
+
+ offRamp := OffRamp{
+ offRampV100: mockOffRamp,
+ }
+
+ ctx := testutils.Context(t)
+ gotRouterAddr, err := offRamp.GetRouter(ctx)
+ require.NoError(t, err)
+
+ gotRouterEvmAddr, err := ccipcalc.GenericAddrToEvm(gotRouterAddr)
+ require.NoError(t, err)
+ assert.Equal(t, routerAddr, gotRouterEvmAddr)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_test.go
new file mode 100644
index 00000000000..234490a72c4
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/offramp_test.go
@@ -0,0 +1,231 @@
+package v1_0_0
+
+import (
+ "encoding/json"
+ "testing"
+ "time"
+
+ "github.com/pkg/errors"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks"
+)
+
+func TestExecOffchainConfig100_Encoding(t *testing.T) {
+ tests := []struct {
+ name string
+ want ExecOffchainConfig
+ expectErr bool
+ }{
+ {
+ name: "encodes and decodes config with all fields set",
+ want: ExecOffchainConfig{
+ SourceFinalityDepth: 3,
+ DestOptimisticConfirmations: 6,
+ DestFinalityDepth: 3,
+ BatchGasLimit: 5_000_000,
+ RelativeBoostPerWaitHour: 0.07,
+ InflightCacheExpiry: *config.MustNewDuration(64 * time.Second),
+ RootSnoozeTime: *config.MustNewDuration(128 * time.Minute),
+ MessageVisibilityInterval: *config.MustNewDuration(6 * time.Hour),
+ },
+ },
+ {
+ name: "fails decoding when all fields present but with 0 values",
+ want: ExecOffchainConfig{
+ SourceFinalityDepth: 0,
+ DestFinalityDepth: 0,
+ DestOptimisticConfirmations: 0,
+ BatchGasLimit: 0,
+ RelativeBoostPerWaitHour: 0,
+ InflightCacheExpiry: *config.MustNewDuration(0),
+ RootSnoozeTime: *config.MustNewDuration(0),
+ MessageVisibilityInterval: *config.MustNewDuration(0),
+ },
+ expectErr: true,
+ },
+ {
+ name: "fails decoding when all fields are missing",
+ want: ExecOffchainConfig{},
+ expectErr: true,
+ },
+ {
+ name: "fails decoding when some fields are missing",
+ want: ExecOffchainConfig{
+ SourceFinalityDepth: 99999999,
+ InflightCacheExpiry: *config.MustNewDuration(64 * time.Second),
+ },
+ expectErr: true,
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ exp := tc.want
+ encode, err := ccipconfig.EncodeOffchainConfig(&exp)
+ require.NoError(t, err)
+ got, err := ccipconfig.DecodeOffchainConfig[ExecOffchainConfig](encode)
+
+ if tc.expectErr {
+ require.ErrorContains(t, err, "must set")
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tc.want, got)
+ }
+ })
+ }
+}
+
+func TestExecOffchainConfig100_AllFieldsRequired(t *testing.T) {
+ cfg := ExecOffchainConfig{
+ SourceFinalityDepth: 3,
+ DestOptimisticConfirmations: 6,
+ DestFinalityDepth: 3,
+ BatchGasLimit: 5_000_000,
+ RelativeBoostPerWaitHour: 0.07,
+ InflightCacheExpiry: *config.MustNewDuration(64 * time.Second),
+ RootSnoozeTime: *config.MustNewDuration(128 * time.Minute),
+ BatchingStrategyID: 0,
+ }
+ encoded, err := ccipconfig.EncodeOffchainConfig(&cfg)
+ require.NoError(t, err)
+
+ var configAsMap map[string]any
+ err = json.Unmarshal(encoded, &configAsMap)
+ require.NoError(t, err)
+ for keyToDelete := range configAsMap {
+ if keyToDelete == "MessageVisibilityInterval" {
+ continue // this field is optional
+ }
+
+ partialConfig := make(map[string]any)
+ for k, v := range configAsMap {
+ if k != keyToDelete {
+ partialConfig[k] = v
+ }
+ }
+ encodedPartialConfig, err := json.Marshal(partialConfig)
+ require.NoError(t, err)
+ _, err = ccipconfig.DecodeOffchainConfig[ExecOffchainConfig](encodedPartialConfig)
+ if keyToDelete == "BatchingStrategyID" {
+ require.NoError(t, err)
+ } else {
+ require.ErrorContains(t, err, keyToDelete)
+ }
+ }
+}
+
+func Test_GetSendersNonce(t *testing.T) {
+ sender1 := cciptypes.Address(utils.RandomAddress().String())
+ sender2 := cciptypes.Address(utils.RandomAddress().String())
+
+ tests := []struct {
+ name string
+ addresses []cciptypes.Address
+ batchCaller *rpclibmocks.EvmBatchCaller
+ expectedResult map[cciptypes.Address]uint64
+ expectedError bool
+ }{
+ {
+ name: "return empty map when input is empty",
+ addresses: []cciptypes.Address{},
+ batchCaller: rpclibmocks.NewEvmBatchCaller(t),
+ expectedResult: map[cciptypes.Address]uint64{},
+ },
+ {
+ name: "return error when batch call fails",
+ addresses: []cciptypes.Address{sender1},
+ batchCaller: func() *rpclibmocks.EvmBatchCaller {
+ mockBatchCaller := rpclibmocks.NewEvmBatchCaller(t)
+ mockBatchCaller.On("BatchCall", mock.Anything, mock.Anything, mock.Anything).
+ Return(nil, errors.New("batch call error"))
+ return mockBatchCaller
+ }(),
+ expectedError: true,
+ },
+ {
+ name: "return error when nonces dont match senders",
+ addresses: []cciptypes.Address{sender1, sender2},
+ batchCaller: func() *rpclibmocks.EvmBatchCaller {
+ mockBatchCaller := rpclibmocks.NewEvmBatchCaller(t)
+ results := []rpclib.DataAndErr{
+ {
+ Outputs: []any{uint64(1)},
+ Err: nil,
+ },
+ }
+ mockBatchCaller.On("BatchCall", mock.Anything, mock.Anything, mock.Anything).
+ Return(results, nil)
+ return mockBatchCaller
+ }(),
+ expectedError: true,
+ },
+ {
+ name: "return error when single request from batch fails",
+ addresses: []cciptypes.Address{sender1, sender2},
+ batchCaller: func() *rpclibmocks.EvmBatchCaller {
+ mockBatchCaller := rpclibmocks.NewEvmBatchCaller(t)
+ results := []rpclib.DataAndErr{
+ {
+ Outputs: []any{uint64(1)},
+ Err: nil,
+ },
+ {
+ Outputs: []any{},
+ Err: errors.New("request failed"),
+ },
+ }
+ mockBatchCaller.On("BatchCall", mock.Anything, mock.Anything, mock.Anything).
+ Return(results, nil)
+ return mockBatchCaller
+ }(),
+ expectedError: true,
+ },
+ {
+ name: "return map of nonce per sender",
+ addresses: []cciptypes.Address{sender1, sender2},
+ batchCaller: func() *rpclibmocks.EvmBatchCaller {
+ mockBatchCaller := rpclibmocks.NewEvmBatchCaller(t)
+ results := []rpclib.DataAndErr{
+ {
+ Outputs: []any{uint64(1)},
+ Err: nil,
+ },
+ {
+ Outputs: []any{uint64(2)},
+ Err: nil,
+ },
+ }
+ mockBatchCaller.On("BatchCall", mock.Anything, mock.Anything, mock.Anything).
+ Return(results, nil)
+ return mockBatchCaller
+ }(),
+ expectedResult: map[cciptypes.Address]uint64{
+ sender1: uint64(1),
+ sender2: uint64(2),
+ },
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ offramp := OffRamp{evmBatchCaller: test.batchCaller, Logger: logger.Test(t)}
+ nonce, err := offramp.ListSenderNonces(testutils.Context(t), test.addresses)
+
+ if test.expectedError {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, test.expectedResult, nonce)
+ }
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/onramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/onramp.go
new file mode 100644
index 00000000000..969b1fa48f0
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/onramp.go
@@ -0,0 +1,241 @@
+package v1_0_0
+
+import (
+ "context"
+ "errors"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/logpollerutil"
+)
+
+const (
+ CCIPSendRequestedEventName = "CCIPSendRequested"
+ ConfigSetEventName = "ConfigSet"
+)
+
+var _ ccipdata.OnRampReader = &OnRamp{}
+
+type OnRamp struct {
+ address common.Address
+ onRamp *evm_2_evm_onramp_1_0_0.EVM2EVMOnRamp
+ lp logpoller.LogPoller
+ lggr logger.Logger
+ client client.Client
+ leafHasher ccipdata.LeafHasherInterface[[32]byte]
+ sendRequestedEventSig common.Hash
+ sendRequestedSeqNumberWord int
+ filters []logpoller.Filter
+ cachedSourcePriceRegistryAddress cache.AutoSync[cciptypes.Address]
+ // Static config can be cached, because it's never expected to change.
+ // The only way to change that is through the contract's constructor (redeployment)
+ cachedStaticConfig cache.OnceCtxFunction[evm_2_evm_onramp_1_0_0.EVM2EVMOnRampStaticConfig]
+ cachedRmnContract cache.OnceCtxFunction[*arm_contract.ARMContract]
+}
+
+func NewOnRamp(lggr logger.Logger, sourceSelector, destSelector uint64, onRampAddress common.Address, sourceLP logpoller.LogPoller, source client.Client) (*OnRamp, error) {
+ onRamp, err := evm_2_evm_onramp_1_0_0.NewEVM2EVMOnRamp(onRampAddress, source)
+ if err != nil {
+ return nil, err
+ }
+ onRampABI := abihelpers.MustParseABI(evm_2_evm_onramp_1_0_0.EVM2EVMOnRampABI)
+ eventSig := abihelpers.MustGetEventID(CCIPSendRequestedEventName, onRampABI)
+ configSetEventSig := abihelpers.MustGetEventID(ConfigSetEventName, onRampABI)
+ filters := []logpoller.Filter{
+ {
+ Name: logpoller.FilterName(ccipdata.COMMIT_CCIP_SENDS, onRampAddress),
+ EventSigs: []common.Hash{eventSig},
+ Addresses: []common.Address{onRampAddress},
+ Retention: ccipdata.CommitExecLogsRetention,
+ },
+ {
+ Name: logpoller.FilterName(ccipdata.CONFIG_CHANGED, onRampAddress),
+ EventSigs: []common.Hash{configSetEventSig},
+ Addresses: []common.Address{onRampAddress},
+ Retention: ccipdata.CacheEvictionLogsRetention,
+ },
+ }
+ cachedStaticConfig := cache.OnceCtxFunction[evm_2_evm_onramp_1_0_0.EVM2EVMOnRampStaticConfig](func(ctx context.Context) (evm_2_evm_onramp_1_0_0.EVM2EVMOnRampStaticConfig, error) {
+ return onRamp.GetStaticConfig(&bind.CallOpts{Context: ctx})
+ })
+ cachedRmnContract := cache.OnceCtxFunction[*arm_contract.ARMContract](func(ctx context.Context) (*arm_contract.ARMContract, error) {
+ staticConfig, err := cachedStaticConfig(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return arm_contract.NewARMContract(staticConfig.ArmProxy, source)
+ })
+ return &OnRamp{
+ lggr: lggr,
+ address: onRampAddress,
+ onRamp: onRamp,
+ client: source,
+ filters: filters,
+ lp: sourceLP,
+ leafHasher: NewLeafHasher(sourceSelector, destSelector, onRampAddress, hashutil.NewKeccak(), onRamp),
+ // offset || sourceChainID || seqNum || ...
+ sendRequestedSeqNumberWord: 2,
+ sendRequestedEventSig: eventSig,
+ cachedSourcePriceRegistryAddress: cache.NewLogpollerEventsBased[cciptypes.Address](
+ sourceLP,
+ []common.Hash{configSetEventSig},
+ onRampAddress,
+ ),
+ cachedStaticConfig: cache.CallOnceOnNoError(cachedStaticConfig),
+ cachedRmnContract: cache.CallOnceOnNoError(cachedRmnContract),
+ }, nil
+}
+
+func (o *OnRamp) Address(context.Context) (cciptypes.Address, error) {
+ return cciptypes.Address(o.onRamp.Address().String()), nil
+}
+
+func (o *OnRamp) GetDynamicConfig(context.Context) (cciptypes.OnRampDynamicConfig, error) {
+ if o.onRamp == nil {
+ return cciptypes.OnRampDynamicConfig{}, fmt.Errorf("onramp not initialized")
+ }
+ legacyDynamicConfig, err := o.onRamp.GetDynamicConfig(nil)
+ if err != nil {
+ return cciptypes.OnRampDynamicConfig{}, err
+ }
+ return cciptypes.OnRampDynamicConfig{
+ Router: cciptypes.Address(legacyDynamicConfig.Router.String()),
+ MaxNumberOfTokensPerMsg: legacyDynamicConfig.MaxTokensLength,
+ DestGasOverhead: 0,
+ DestGasPerPayloadByte: 0,
+ DestDataAvailabilityOverheadGas: 0,
+ DestGasPerDataAvailabilityByte: 0,
+ DestDataAvailabilityMultiplierBps: 0,
+ PriceRegistry: cciptypes.Address(legacyDynamicConfig.PriceRegistry.String()),
+ MaxDataBytes: legacyDynamicConfig.MaxDataSize,
+ MaxPerMsgGasLimit: uint32(legacyDynamicConfig.MaxGasLimit),
+ }, nil
+}
+
+func (o *OnRamp) SourcePriceRegistryAddress(ctx context.Context) (cciptypes.Address, error) {
+ return o.cachedSourcePriceRegistryAddress.Get(ctx, func(ctx context.Context) (cciptypes.Address, error) {
+ c, err := o.GetDynamicConfig(ctx)
+ if err != nil {
+ return "", err
+ }
+ return c.PriceRegistry, nil
+ })
+}
+
+func (o *OnRamp) GetSendRequestsBetweenSeqNums(ctx context.Context, seqNumMin, seqNumMax uint64, finalized bool) ([]cciptypes.EVM2EVMMessageWithTxMeta, error) {
+ logs, err := o.lp.LogsDataWordRange(
+ ctx,
+ o.sendRequestedEventSig,
+ o.address,
+ o.sendRequestedSeqNumberWord,
+ logpoller.EvmWord(seqNumMin),
+ logpoller.EvmWord(seqNumMax),
+ ccipdata.LogsConfirmations(finalized),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.EVM2EVMMessage](logs, o.lggr, o.logToMessage)
+ if err != nil {
+ return nil, err
+ }
+
+ res := make([]cciptypes.EVM2EVMMessageWithTxMeta, 0, len(parsedLogs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.EVM2EVMMessageWithTxMeta{
+ TxMeta: log.TxMeta,
+ EVM2EVMMessage: log.Data,
+ })
+ }
+ return res, nil
+}
+
+func (o *OnRamp) RouterAddress(context.Context) (cciptypes.Address, error) {
+ config, err := o.onRamp.GetDynamicConfig(nil)
+ if err != nil {
+ return "", err
+ }
+ return cciptypes.Address(config.Router.String()), nil
+}
+
+func (o *OnRamp) IsSourceChainHealthy(context.Context) (bool, error) {
+ if err := o.lp.Healthy(); err != nil {
+ return false, nil
+ }
+ return true, nil
+}
+
+func (o *OnRamp) IsSourceCursed(ctx context.Context) (bool, error) {
+ arm, err := o.cachedRmnContract(ctx)
+ if err != nil {
+ return false, fmt.Errorf("intializing Arm contract through the ArmProxy: %w", err)
+ }
+
+ cursed, err := arm.IsCursed0(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return false, fmt.Errorf("checking if source Arm is cursed: %w", err)
+ }
+ return cursed, nil
+}
+
+func (o *OnRamp) GetUSDCMessagePriorToLogIndexInTx(ctx context.Context, logIndex, offsetFromFinal int64, txHash common.Hash) ([]byte, error) {
+ return nil, errors.New("USDC not supported in < 1.2.0")
+}
+
+func (o *OnRamp) Close() error {
+ return logpollerutil.UnregisterLpFilters(o.lp, o.filters)
+}
+
+func (o *OnRamp) RegisterFilters() error {
+ return logpollerutil.RegisterLpFilters(o.lp, o.filters)
+}
+
+func (o *OnRamp) logToMessage(log types.Log) (*cciptypes.EVM2EVMMessage, error) {
+ msg, err := o.onRamp.ParseCCIPSendRequested(log)
+ if err != nil {
+ return nil, err
+ }
+ h, err := o.leafHasher.HashLeaf(log)
+ if err != nil {
+ return nil, err
+ }
+ tokensAndAmounts := make([]cciptypes.TokenAmount, len(msg.Message.TokenAmounts))
+ for i, tokenAndAmount := range msg.Message.TokenAmounts {
+ tokensAndAmounts[i] = cciptypes.TokenAmount{
+ Token: cciptypes.Address(tokenAndAmount.Token.String()),
+ Amount: tokenAndAmount.Amount,
+ }
+ }
+ return &cciptypes.EVM2EVMMessage{
+ SequenceNumber: msg.Message.SequenceNumber,
+ GasLimit: msg.Message.GasLimit,
+ Nonce: msg.Message.Nonce,
+ MessageID: msg.Message.MessageId,
+ SourceChainSelector: msg.Message.SourceChainSelector,
+ Sender: cciptypes.Address(msg.Message.Sender.String()),
+ Receiver: cciptypes.Address(msg.Message.Receiver.String()),
+ Strict: msg.Message.Strict,
+ FeeToken: cciptypes.Address(msg.Message.FeeToken.String()),
+ FeeTokenAmount: msg.Message.FeeTokenAmount,
+ Data: msg.Message.Data,
+ TokenAmounts: tokensAndAmounts,
+ SourceTokenData: make([][]byte, len(msg.Message.TokenAmounts)), // Always empty in 1.0
+ Hash: h,
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/price_registry.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/price_registry.go
new file mode 100644
index 00000000000..2ed9015a989
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/price_registry.go
@@ -0,0 +1,309 @@
+package v1_0_0
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "sync"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "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/gethwrappers/ccip/generated/price_registry_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/erc20"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/logpollerutil"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+)
+
+var (
+ abiERC20 = abihelpers.MustParseABI(erc20.ERC20ABI)
+ _ ccipdata.PriceRegistryReader = &PriceRegistry{}
+ // Exposed only for backwards compatibility with tests.
+ UsdPerUnitGasUpdated = abihelpers.MustGetEventID("UsdPerUnitGasUpdated", abihelpers.MustParseABI(price_registry_1_0_0.PriceRegistryABI))
+)
+
+type PriceRegistry struct {
+ priceRegistry price_registry_1_0_0.PriceRegistryInterface
+ address common.Address
+ lp logpoller.LogPoller
+ evmBatchCaller rpclib.EvmBatchCaller
+ lggr logger.Logger
+ filters []logpoller.Filter
+ tokenUpdated common.Hash
+ gasUpdated common.Hash
+ feeTokenAdded common.Hash
+ feeTokenRemoved common.Hash
+
+ feeTokensCache cache.AutoSync[[]common.Address]
+ tokenDecimalsCache sync.Map
+}
+
+func NewPriceRegistry(lggr logger.Logger, priceRegistryAddr common.Address, lp logpoller.LogPoller, ec client.Client, registerFilters bool) (*PriceRegistry, error) {
+ priceRegistry, err := price_registry_1_0_0.NewPriceRegistry(priceRegistryAddr, ec)
+ if err != nil {
+ return nil, err
+ }
+ priceRegABI := abihelpers.MustParseABI(price_registry_1_0_0.PriceRegistryABI)
+ usdPerTokenUpdated := abihelpers.MustGetEventID("UsdPerTokenUpdated", priceRegABI)
+ feeTokenRemoved := abihelpers.MustGetEventID("FeeTokenRemoved", priceRegABI)
+ feeTokenAdded := abihelpers.MustGetEventID("FeeTokenAdded", priceRegABI)
+ var filters = []logpoller.Filter{
+ {
+ Name: logpoller.FilterName(ccipdata.COMMIT_PRICE_UPDATES, priceRegistryAddr.String()),
+ EventSigs: []common.Hash{UsdPerUnitGasUpdated, usdPerTokenUpdated},
+ Addresses: []common.Address{priceRegistryAddr},
+ Retention: ccipdata.PriceUpdatesLogsRetention,
+ },
+ {
+ Name: logpoller.FilterName(ccipdata.FEE_TOKEN_ADDED, priceRegistryAddr.String()),
+ EventSigs: []common.Hash{feeTokenAdded},
+ Addresses: []common.Address{priceRegistryAddr},
+ Retention: ccipdata.CacheEvictionLogsRetention,
+ },
+ {
+ Name: logpoller.FilterName(ccipdata.FEE_TOKEN_REMOVED, priceRegistryAddr.String()),
+ EventSigs: []common.Hash{feeTokenRemoved},
+ Addresses: []common.Address{priceRegistryAddr},
+ Retention: ccipdata.CacheEvictionLogsRetention,
+ }}
+ if registerFilters {
+ err = logpollerutil.RegisterLpFilters(lp, filters)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return &PriceRegistry{
+ priceRegistry: priceRegistry,
+ address: priceRegistryAddr,
+ lp: lp,
+ evmBatchCaller: rpclib.NewDynamicLimitedBatchCaller(
+ lggr,
+ ec,
+ rpclib.DefaultRpcBatchSizeLimit,
+ rpclib.DefaultRpcBatchBackOffMultiplier,
+ rpclib.DefaultMaxParallelRpcCalls,
+ ),
+ lggr: lggr,
+ gasUpdated: UsdPerUnitGasUpdated,
+ tokenUpdated: usdPerTokenUpdated,
+ feeTokenRemoved: feeTokenRemoved,
+ feeTokenAdded: feeTokenAdded,
+ filters: filters,
+ feeTokensCache: cache.NewLogpollerEventsBased[[]common.Address](
+ lp,
+ []common.Hash{feeTokenAdded, feeTokenRemoved},
+ priceRegistryAddr,
+ ),
+ }, nil
+}
+
+func (p *PriceRegistry) GetTokenPrices(ctx context.Context, wantedTokens []cciptypes.Address) ([]cciptypes.TokenPriceUpdate, error) {
+ evmAddrs, err := ccipcalc.GenericAddrsToEvm(wantedTokens...)
+ if err != nil {
+ return nil, err
+ }
+
+ tps, err := p.priceRegistry.GetTokenPrices(&bind.CallOpts{Context: ctx}, evmAddrs)
+ if err != nil {
+ return nil, err
+ }
+ var tpu []cciptypes.TokenPriceUpdate
+ for i, tp := range tps {
+ tpu = append(tpu, cciptypes.TokenPriceUpdate{
+ TokenPrice: cciptypes.TokenPrice{
+ Token: cciptypes.Address(evmAddrs[i].String()),
+ Value: tp.Value,
+ },
+ TimestampUnixSec: big.NewInt(int64(tp.Timestamp)),
+ })
+ }
+ return tpu, nil
+}
+
+func (p *PriceRegistry) Address(ctx context.Context) (cciptypes.Address, error) {
+ return cciptypes.Address(p.address.String()), nil
+}
+
+func (p *PriceRegistry) GetFeeTokens(ctx context.Context) ([]cciptypes.Address, error) {
+ feeTokens, err := p.feeTokensCache.Get(ctx, func(ctx context.Context) ([]common.Address, error) {
+ return p.priceRegistry.GetFeeTokens(&bind.CallOpts{Context: ctx})
+ })
+ if err != nil {
+ return nil, fmt.Errorf("get fee tokens: %w", err)
+ }
+
+ return ccipcalc.EvmAddrsToGeneric(feeTokens...), nil
+}
+
+func (p *PriceRegistry) Close() error {
+ return logpollerutil.UnregisterLpFilters(p.lp, p.filters)
+}
+
+func (p *PriceRegistry) GetTokenPriceUpdatesCreatedAfter(ctx context.Context, ts time.Time, confs int) ([]cciptypes.TokenPriceUpdateWithTxMeta, error) {
+ logs, err := p.lp.LogsCreatedAfter(
+ ctx,
+ p.tokenUpdated,
+ p.address,
+ ts,
+ evmtypes.Confirmations(confs),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.TokenPriceUpdate](
+ logs,
+ p.lggr,
+ func(log types.Log) (*cciptypes.TokenPriceUpdate, error) {
+ tp, err1 := p.priceRegistry.ParseUsdPerTokenUpdated(log)
+ if err1 != nil {
+ return nil, err1
+ }
+ return &cciptypes.TokenPriceUpdate{
+ TokenPrice: cciptypes.TokenPrice{
+ Token: cciptypes.Address(tp.Token.String()),
+ Value: tp.Value,
+ },
+ TimestampUnixSec: tp.Timestamp,
+ }, nil
+ },
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ res := make([]cciptypes.TokenPriceUpdateWithTxMeta, 0, len(parsedLogs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.TokenPriceUpdateWithTxMeta{
+ TxMeta: log.TxMeta,
+ TokenPriceUpdate: log.Data,
+ })
+ }
+ return res, nil
+}
+
+func (p *PriceRegistry) GetGasPriceUpdatesCreatedAfter(ctx context.Context, chainSelector uint64, ts time.Time, confs int) ([]cciptypes.GasPriceUpdateWithTxMeta, error) {
+ logs, err := p.lp.IndexedLogsCreatedAfter(
+ ctx,
+ p.gasUpdated,
+ p.address,
+ 1,
+ []common.Hash{abihelpers.EvmWord(chainSelector)},
+ ts,
+ evmtypes.Confirmations(confs),
+ )
+ if err != nil {
+ return nil, err
+ }
+ return p.parseGasPriceUpdatesLogs(logs)
+}
+
+func (p *PriceRegistry) GetAllGasPriceUpdatesCreatedAfter(ctx context.Context, ts time.Time, confs int) ([]cciptypes.GasPriceUpdateWithTxMeta, error) {
+ logs, err := p.lp.LogsCreatedAfter(
+ ctx,
+ p.gasUpdated,
+ p.address,
+ ts,
+ evmtypes.Confirmations(confs),
+ )
+ if err != nil {
+ return nil, err
+ }
+ return p.parseGasPriceUpdatesLogs(logs)
+}
+
+func (p *PriceRegistry) parseGasPriceUpdatesLogs(logs []logpoller.Log) ([]cciptypes.GasPriceUpdateWithTxMeta, error) {
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.GasPriceUpdate](
+ logs,
+ p.lggr,
+ func(log types.Log) (*cciptypes.GasPriceUpdate, error) {
+ p, err1 := p.priceRegistry.ParseUsdPerUnitGasUpdated(log)
+ if err1 != nil {
+ return nil, err1
+ }
+ return &cciptypes.GasPriceUpdate{
+ GasPrice: cciptypes.GasPrice{
+ DestChainSelector: p.DestChain,
+ Value: p.Value,
+ },
+ TimestampUnixSec: p.Timestamp,
+ }, nil
+ },
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ res := make([]cciptypes.GasPriceUpdateWithTxMeta, 0, len(parsedLogs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.GasPriceUpdateWithTxMeta{
+ TxMeta: log.TxMeta,
+ GasPriceUpdate: log.Data,
+ })
+ }
+ return res, nil
+}
+
+func (p *PriceRegistry) GetTokensDecimals(ctx context.Context, tokenAddresses []cciptypes.Address) ([]uint8, error) {
+ evmAddrs, err := ccipcalc.GenericAddrsToEvm(tokenAddresses...)
+ if err != nil {
+ return nil, err
+ }
+
+ found := make(map[common.Address]bool)
+ tokenDecimals := make([]uint8, len(evmAddrs))
+ for i, tokenAddress := range evmAddrs {
+ if v, ok := p.tokenDecimalsCache.Load(tokenAddress); ok {
+ if decimals, isUint8 := v.(uint8); isUint8 {
+ tokenDecimals[i] = decimals
+ found[tokenAddress] = true
+ } else {
+ p.lggr.Errorf("token decimals cache contains invalid type %T", v)
+ }
+ }
+ }
+ if len(found) == len(evmAddrs) {
+ return tokenDecimals, nil
+ }
+
+ evmCalls := make([]rpclib.EvmCall, 0, len(evmAddrs))
+ for _, tokenAddress := range evmAddrs {
+ if !found[tokenAddress] {
+ evmCalls = append(evmCalls, rpclib.NewEvmCall(abiERC20, "decimals", tokenAddress))
+ }
+ }
+
+ results, err := p.evmBatchCaller.BatchCall(ctx, 0, evmCalls)
+ if err != nil {
+ return nil, fmt.Errorf("batch call limit: %w", err)
+ }
+
+ decimals, err := rpclib.ParseOutputs[uint8](results, func(d rpclib.DataAndErr) (uint8, error) {
+ return rpclib.ParseOutput[uint8](d, 0)
+ })
+ if err != nil {
+ return nil, fmt.Errorf("parse outputs: %w", err)
+ }
+
+ j := 0
+ for i, tokenAddress := range evmAddrs {
+ if !found[tokenAddress] {
+ tokenDecimals[i] = decimals[j]
+ p.tokenDecimalsCache.Store(tokenAddress, tokenDecimals[i])
+ j++
+ }
+ }
+ return tokenDecimals, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/test_helpers.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/test_helpers.go
new file mode 100644
index 00000000000..34f832e17fc
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0/test_helpers.go
@@ -0,0 +1,90 @@
+package v1_0_0
+
+import (
+ "encoding/binary"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+// ApplyPriceRegistryUpdate is a helper function used in tests only.
+func ApplyPriceRegistryUpdate(t *testing.T, user *bind.TransactOpts, addr common.Address, ec client.Client, gasPrice []cciptypes.GasPrice, tokenPrices []cciptypes.TokenPrice) {
+ require.True(t, len(gasPrice) <= 2)
+ pr, err := price_registry_1_0_0.NewPriceRegistry(addr, ec)
+ require.NoError(t, err)
+ var tps []price_registry_1_0_0.InternalTokenPriceUpdate
+ for _, tp := range tokenPrices {
+ evmAddrs, err1 := ccipcalc.GenericAddrsToEvm(tp.Token)
+ assert.NoError(t, err1)
+ tps = append(tps, price_registry_1_0_0.InternalTokenPriceUpdate{
+ SourceToken: evmAddrs[0],
+ UsdPerToken: tp.Value,
+ })
+ }
+ dest := uint64(0)
+ gas := big.NewInt(0)
+ if len(gasPrice) >= 1 {
+ dest = gasPrice[0].DestChainSelector
+ gas = gasPrice[0].Value
+ }
+ _, err = pr.UpdatePrices(user, price_registry_1_0_0.InternalPriceUpdates{
+ TokenPriceUpdates: tps,
+ DestChainSelector: dest,
+ UsdPerUnitGas: gas,
+ })
+ require.NoError(t, err)
+
+ for i := 1; i < len(gasPrice); i++ {
+ dest = gasPrice[i].DestChainSelector
+ gas = gasPrice[i].Value
+ _, err = pr.UpdatePrices(user, price_registry_1_0_0.InternalPriceUpdates{
+ TokenPriceUpdates: []price_registry_1_0_0.InternalTokenPriceUpdate{},
+ DestChainSelector: dest,
+ UsdPerUnitGas: gas,
+ })
+ require.NoError(t, err)
+ }
+}
+
+func CreateExecutionStateChangeEventLog(t *testing.T, seqNr uint64, blockNumber int64, messageID common.Hash) logpoller.Log {
+ tAbi, err := evm_2_evm_offramp.EVM2EVMOffRampMetaData.GetAbi()
+ require.NoError(t, err)
+ eseEvent, ok := tAbi.Events["ExecutionStateChanged"]
+ require.True(t, ok)
+
+ logData, err := eseEvent.Inputs.NonIndexed().Pack(uint8(1), []byte("some return data"))
+ require.NoError(t, err)
+ seqNrBytes := make([]byte, 8)
+ binary.BigEndian.PutUint64(seqNrBytes, seqNr)
+ seqNrTopic := common.BytesToHash(seqNrBytes)
+ topic0 := evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged{}.Topic()
+
+ return logpoller.Log{
+ Topics: [][]byte{
+ topic0[:],
+ seqNrTopic[:],
+ messageID[:],
+ },
+ Data: logData,
+ LogIndex: 1,
+ BlockHash: utils.RandomBytes32(),
+ BlockNumber: blockNumber,
+ EventSig: topic0,
+ Address: testutils.NewAddress(),
+ TxHash: utils.RandomBytes32(),
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_1_0/onramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_1_0/onramp.go
new file mode 100644
index 00000000000..52d7985f7e3
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_1_0/onramp.go
@@ -0,0 +1,70 @@
+package v1_1_0
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/common"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_1_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+)
+
+var _ ccipdata.OnRampReader = &OnRamp{}
+
+// OnRamp The only difference that the plugins care about in 1.1 is that the dynamic config struct has changed.
+type OnRamp struct {
+ *v1_0_0.OnRamp
+ onRamp *evm_2_evm_onramp_1_1_0.EVM2EVMOnRamp
+}
+
+func NewOnRamp(lggr logger.Logger, sourceSelector, destSelector uint64, onRampAddress common.Address, sourceLP logpoller.LogPoller, source client.Client) (*OnRamp, error) {
+ onRamp, err := evm_2_evm_onramp_1_1_0.NewEVM2EVMOnRamp(onRampAddress, source)
+ if err != nil {
+ return nil, err
+ }
+ onRamp100, err := v1_0_0.NewOnRamp(lggr, sourceSelector, destSelector, onRampAddress, sourceLP, source)
+ if err != nil {
+ return nil, err
+ }
+ return &OnRamp{
+ OnRamp: onRamp100,
+ onRamp: onRamp,
+ }, nil
+}
+
+func (o *OnRamp) RouterAddress(context.Context) (cciptypes.Address, error) {
+ config, err := o.onRamp.GetDynamicConfig(nil)
+ if err != nil {
+ return "", err
+ }
+ return cciptypes.Address(config.Router.String()), nil
+}
+
+func (o *OnRamp) GetDynamicConfig(context.Context) (cciptypes.OnRampDynamicConfig, error) {
+ if o.onRamp == nil {
+ return cciptypes.OnRampDynamicConfig{}, fmt.Errorf("onramp not initialized")
+ }
+ legacyDynamicConfig, err := o.onRamp.GetDynamicConfig(nil)
+ if err != nil {
+ return cciptypes.OnRampDynamicConfig{}, err
+ }
+ return cciptypes.OnRampDynamicConfig{
+ Router: cciptypes.Address(legacyDynamicConfig.Router.String()),
+ MaxNumberOfTokensPerMsg: legacyDynamicConfig.MaxTokensLength,
+ DestGasOverhead: legacyDynamicConfig.DestGasOverhead,
+ DestGasPerPayloadByte: legacyDynamicConfig.DestGasPerPayloadByte,
+ DestDataAvailabilityOverheadGas: 0,
+ DestGasPerDataAvailabilityByte: 0,
+ DestDataAvailabilityMultiplierBps: 0,
+ PriceRegistry: cciptypes.Address(legacyDynamicConfig.PriceRegistry.String()),
+ MaxDataBytes: legacyDynamicConfig.MaxDataSize,
+ MaxPerMsgGasLimit: uint32(legacyDynamicConfig.MaxGasLimit),
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store.go
new file mode 100644
index 00000000000..2b87a7913ac
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store.go
@@ -0,0 +1,469 @@
+package v1_2_0
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "sync"
+ "time"
+
+ "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"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/query"
+ "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "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/gethwrappers/ccip/generated/commit_store_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/logpollerutil"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+var _ ccipdata.CommitStoreReader = &CommitStore{}
+
+type CommitStore struct {
+ // Static config
+ commitStore *commit_store_1_2_0.CommitStore
+ lggr logger.Logger
+ lp logpoller.LogPoller
+ address common.Address
+ estimator *gas.EvmFeeEstimator
+ sourceMaxGasPrice *big.Int
+ filters []logpoller.Filter
+ reportAcceptedSig common.Hash
+ reportAcceptedMaxSeqIndex int
+ commitReportArgs abi.Arguments
+
+ // Dynamic config
+ configMu sync.RWMutex
+ gasPriceEstimator *prices.DAGasPriceEstimator
+ offchainConfig cciptypes.CommitOffchainConfig
+}
+
+func (c *CommitStore) GetCommitStoreStaticConfig(ctx context.Context) (cciptypes.CommitStoreStaticConfig, error) {
+ staticConfig, err := c.commitStore.GetStaticConfig(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return cciptypes.CommitStoreStaticConfig{}, err
+ }
+ return cciptypes.CommitStoreStaticConfig{
+ ChainSelector: staticConfig.ChainSelector,
+ SourceChainSelector: staticConfig.SourceChainSelector,
+ OnRamp: cciptypes.Address(staticConfig.OnRamp.String()),
+ ArmProxy: cciptypes.Address(staticConfig.ArmProxy.String()),
+ }, nil
+}
+
+func (c *CommitStore) EncodeCommitReport(_ context.Context, report cciptypes.CommitStoreReport) ([]byte, error) {
+ return EncodeCommitReport(c.commitReportArgs, report)
+}
+
+func EncodeCommitReport(commitReportArgs abi.Arguments, report cciptypes.CommitStoreReport) ([]byte, error) {
+ var tokenPriceUpdates []commit_store_1_2_0.InternalTokenPriceUpdate
+ for _, tokenPriceUpdate := range report.TokenPrices {
+ tokenAddressEvm, err := ccipcalc.GenericAddrToEvm(tokenPriceUpdate.Token)
+ if err != nil {
+ return nil, fmt.Errorf("token price update address to evm: %w", err)
+ }
+
+ tokenPriceUpdates = append(tokenPriceUpdates, commit_store_1_2_0.InternalTokenPriceUpdate{
+ SourceToken: tokenAddressEvm,
+ UsdPerToken: tokenPriceUpdate.Value,
+ })
+ }
+
+ var gasPriceUpdates []commit_store_1_2_0.InternalGasPriceUpdate
+ for _, gasPriceUpdate := range report.GasPrices {
+ gasPriceUpdates = append(gasPriceUpdates, commit_store_1_2_0.InternalGasPriceUpdate{
+ DestChainSelector: gasPriceUpdate.DestChainSelector,
+ UsdPerUnitGas: gasPriceUpdate.Value,
+ })
+ }
+
+ rep := commit_store_1_2_0.CommitStoreCommitReport{
+ PriceUpdates: commit_store_1_2_0.InternalPriceUpdates{
+ TokenPriceUpdates: tokenPriceUpdates,
+ GasPriceUpdates: gasPriceUpdates,
+ },
+ Interval: commit_store_1_2_0.CommitStoreInterval{Min: report.Interval.Min, Max: report.Interval.Max},
+ MerkleRoot: report.MerkleRoot,
+ }
+ return commitReportArgs.PackValues([]interface{}{rep})
+}
+
+func DecodeCommitReport(commitReportArgs abi.Arguments, report []byte) (cciptypes.CommitStoreReport, error) {
+ unpacked, err := commitReportArgs.Unpack(report)
+ if err != nil {
+ return cciptypes.CommitStoreReport{}, err
+ }
+ if len(unpacked) != 1 {
+ return cciptypes.CommitStoreReport{}, errors.New("expected single struct value")
+ }
+
+ commitReport, ok := unpacked[0].(struct {
+ PriceUpdates struct {
+ TokenPriceUpdates []struct {
+ SourceToken common.Address `json:"sourceToken"`
+ UsdPerToken *big.Int `json:"usdPerToken"`
+ } `json:"tokenPriceUpdates"`
+ GasPriceUpdates []struct {
+ DestChainSelector uint64 `json:"destChainSelector"`
+ UsdPerUnitGas *big.Int `json:"usdPerUnitGas"`
+ } `json:"gasPriceUpdates"`
+ } `json:"priceUpdates"`
+ Interval struct {
+ Min uint64 `json:"min"`
+ Max uint64 `json:"max"`
+ } `json:"interval"`
+ MerkleRoot [32]byte `json:"merkleRoot"`
+ })
+ if !ok {
+ return cciptypes.CommitStoreReport{}, errors.Errorf("invalid commit report got %T", unpacked[0])
+ }
+
+ var tokenPriceUpdates []cciptypes.TokenPrice
+ for _, u := range commitReport.PriceUpdates.TokenPriceUpdates {
+ tokenPriceUpdates = append(tokenPriceUpdates, cciptypes.TokenPrice{
+ Token: cciptypes.Address(u.SourceToken.String()),
+ Value: u.UsdPerToken,
+ })
+ }
+
+ var gasPrices []cciptypes.GasPrice
+ for _, u := range commitReport.PriceUpdates.GasPriceUpdates {
+ gasPrices = append(gasPrices, cciptypes.GasPrice{
+ DestChainSelector: u.DestChainSelector,
+ Value: u.UsdPerUnitGas,
+ })
+ }
+
+ return cciptypes.CommitStoreReport{
+ TokenPrices: tokenPriceUpdates,
+ GasPrices: gasPrices,
+ Interval: cciptypes.CommitStoreInterval{
+ Min: commitReport.Interval.Min,
+ Max: commitReport.Interval.Max,
+ },
+ MerkleRoot: commitReport.MerkleRoot,
+ }, nil
+}
+
+func (c *CommitStore) DecodeCommitReport(_ context.Context, report []byte) (cciptypes.CommitStoreReport, error) {
+ return DecodeCommitReport(c.commitReportArgs, report)
+}
+
+func (c *CommitStore) IsBlessed(ctx context.Context, root [32]byte) (bool, error) {
+ return c.commitStore.IsBlessed(&bind.CallOpts{Context: ctx}, root)
+}
+
+func (c *CommitStore) OffchainConfig(context.Context) (cciptypes.CommitOffchainConfig, error) {
+ c.configMu.RLock()
+ defer c.configMu.RUnlock()
+ return c.offchainConfig, nil
+}
+
+func (c *CommitStore) GasPriceEstimator(context.Context) (cciptypes.GasPriceEstimatorCommit, error) {
+ c.configMu.RLock()
+ defer c.configMu.RUnlock()
+ return c.gasPriceEstimator, nil
+}
+
+func (c *CommitStore) SetGasEstimator(ctx context.Context, gpe gas.EvmFeeEstimator) error {
+ c.configMu.RLock()
+ defer c.configMu.RUnlock()
+ c.estimator = &gpe
+ return nil
+}
+
+func (c *CommitStore) SetSourceMaxGasPrice(ctx context.Context, sourceMaxGasPrice *big.Int) error {
+ c.configMu.RLock()
+ defer c.configMu.RUnlock()
+ c.sourceMaxGasPrice = sourceMaxGasPrice
+ return nil
+}
+
+// Do not change the JSON format of this struct without consulting with the RDD people first.
+type JSONCommitOffchainConfig struct {
+ SourceFinalityDepth uint32
+ DestFinalityDepth uint32
+ GasPriceHeartBeat config.Duration
+ DAGasPriceDeviationPPB uint32
+ ExecGasPriceDeviationPPB uint32
+ TokenPriceHeartBeat config.Duration
+ TokenPriceDeviationPPB uint32
+ InflightCacheExpiry config.Duration
+ PriceReportingDisabled bool
+}
+
+func (c JSONCommitOffchainConfig) Validate() error {
+ if c.GasPriceHeartBeat.Duration() == 0 {
+ return errors.New("must set GasPriceHeartBeat")
+ }
+ if c.ExecGasPriceDeviationPPB == 0 {
+ return errors.New("must set ExecGasPriceDeviationPPB")
+ }
+ if c.TokenPriceHeartBeat.Duration() == 0 {
+ return errors.New("must set TokenPriceHeartBeat")
+ }
+ if c.TokenPriceDeviationPPB == 0 {
+ return errors.New("must set TokenPriceDeviationPPB")
+ }
+ if c.InflightCacheExpiry.Duration() == 0 {
+ return errors.New("must set InflightCacheExpiry")
+ }
+ // DAGasPriceDeviationPPB is not validated because it can be 0 on non-rollups
+
+ return nil
+}
+
+func (c *CommitStore) ChangeConfig(_ context.Context, onchainConfig []byte, offchainConfig []byte) (cciptypes.Address, error) {
+ onchainConfigParsed, err := abihelpers.DecodeAbiStruct[ccipdata.CommitOnchainConfig](onchainConfig)
+ if err != nil {
+ return "", err
+ }
+
+ offchainConfigParsed, err := ccipconfig.DecodeOffchainConfig[JSONCommitOffchainConfig](offchainConfig)
+ if err != nil {
+ return "", err
+ }
+ c.configMu.Lock()
+ defer c.configMu.Unlock()
+
+ if c.estimator == nil {
+ return "", fmt.Errorf("this CommitStore estimator is nil. SetGasEstimator should be called before ChangeConfig")
+ }
+
+ if c.sourceMaxGasPrice == nil {
+ return "", fmt.Errorf("this CommitStore sourceMaxGasPrice is nil. SetSourceMaxGasPrice should be called before ChangeConfig")
+ }
+
+ c.gasPriceEstimator = prices.NewDAGasPriceEstimator(
+ *c.estimator,
+ c.sourceMaxGasPrice,
+ int64(offchainConfigParsed.ExecGasPriceDeviationPPB),
+ int64(offchainConfigParsed.DAGasPriceDeviationPPB),
+ )
+ c.offchainConfig = ccipdata.NewCommitOffchainConfig(
+ offchainConfigParsed.ExecGasPriceDeviationPPB,
+ offchainConfigParsed.GasPriceHeartBeat.Duration(),
+ offchainConfigParsed.TokenPriceDeviationPPB,
+ offchainConfigParsed.TokenPriceHeartBeat.Duration(),
+ offchainConfigParsed.InflightCacheExpiry.Duration(),
+ offchainConfigParsed.PriceReportingDisabled,
+ )
+
+ c.lggr.Infow("ChangeConfig",
+ "offchainConfig", offchainConfigParsed,
+ "onchainConfig", onchainConfigParsed,
+ )
+ return cciptypes.Address(onchainConfigParsed.PriceRegistry.String()), nil
+}
+
+func (c *CommitStore) Close() error {
+ return logpollerutil.UnregisterLpFilters(c.lp, c.filters)
+}
+
+func (c *CommitStore) parseReport(log types.Log) (*cciptypes.CommitStoreReport, error) {
+ repAccepted, err := c.commitStore.ParseReportAccepted(log)
+ if err != nil {
+ return nil, err
+ }
+ // Translate to common struct.
+ var tokenPrices []cciptypes.TokenPrice
+ for _, tpu := range repAccepted.Report.PriceUpdates.TokenPriceUpdates {
+ tokenPrices = append(tokenPrices, cciptypes.TokenPrice{
+ Token: cciptypes.Address(tpu.SourceToken.String()),
+ Value: tpu.UsdPerToken,
+ })
+ }
+ var gasPrices []cciptypes.GasPrice
+ for _, tpu := range repAccepted.Report.PriceUpdates.GasPriceUpdates {
+ gasPrices = append(gasPrices, cciptypes.GasPrice{
+ DestChainSelector: tpu.DestChainSelector,
+ Value: tpu.UsdPerUnitGas,
+ })
+ }
+
+ return &cciptypes.CommitStoreReport{
+ TokenPrices: tokenPrices,
+ GasPrices: gasPrices,
+ MerkleRoot: repAccepted.Report.MerkleRoot,
+ Interval: cciptypes.CommitStoreInterval{Min: repAccepted.Report.Interval.Min, Max: repAccepted.Report.Interval.Max},
+ }, nil
+}
+
+func (c *CommitStore) GetCommitReportMatchingSeqNum(ctx context.Context, seqNr uint64, confs int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ logs, err := c.lp.LogsDataWordBetween(
+ ctx,
+ c.reportAcceptedSig,
+ c.address,
+ c.reportAcceptedMaxSeqIndex-1,
+ c.reportAcceptedMaxSeqIndex,
+ logpoller.EvmWord(seqNr),
+ evmtypes.Confirmations(confs),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.CommitStoreReport](
+ logs,
+ c.lggr,
+ c.parseReport,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ res := make([]cciptypes.CommitStoreReportWithTxMeta, 0, len(parsedLogs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.CommitStoreReportWithTxMeta{
+ TxMeta: log.TxMeta,
+ CommitStoreReport: log.Data,
+ })
+ }
+
+ if len(res) > 1 {
+ c.lggr.Errorw("More than one report found for seqNr", "seqNr", seqNr, "commitReports", parsedLogs)
+ return res[:1], nil
+ }
+ return res, nil
+}
+
+func (c *CommitStore) GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confs int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ latestBlock, err := c.lp.LatestBlock(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ reportsQuery, err := query.Where(
+ c.address.String(),
+ logpoller.NewAddressFilter(c.address),
+ logpoller.NewEventSigFilter(c.reportAcceptedSig),
+ query.Timestamp(uint64(ts.Unix()), primitives.Gte),
+ logpoller.NewConfirmationsFilter(evmtypes.Confirmations(confs)),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ logs, err := c.lp.FilteredLogs(
+ ctx,
+ reportsQuery,
+ query.NewLimitAndSort(query.Limit{}, query.NewSortBySequence(query.Asc)),
+ "GetAcceptedCommitReportsGteTimestamp",
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.CommitStoreReport](logs, c.lggr, c.parseReport)
+ if err != nil {
+ return nil, fmt.Errorf("parse logs: %w", err)
+ }
+
+ res := make([]cciptypes.CommitStoreReportWithTxMeta, 0, len(parsedLogs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.CommitStoreReportWithTxMeta{
+ TxMeta: log.TxMeta.WithFinalityStatus(uint64(latestBlock.FinalizedBlockNumber)),
+ CommitStoreReport: log.Data,
+ })
+ }
+ return res, nil
+}
+
+func (c *CommitStore) GetExpectedNextSequenceNumber(ctx context.Context) (uint64, error) {
+ return c.commitStore.GetExpectedNextSequenceNumber(&bind.CallOpts{Context: ctx})
+}
+
+func (c *CommitStore) GetLatestPriceEpochAndRound(ctx context.Context) (uint64, error) {
+ return c.commitStore.GetLatestPriceEpochAndRound(&bind.CallOpts{Context: ctx})
+}
+
+func (c *CommitStore) IsDestChainHealthy(context.Context) (bool, error) {
+ if err := c.lp.Healthy(); err != nil {
+ return false, nil
+ }
+ return true, nil
+}
+
+func (c *CommitStore) IsDown(ctx context.Context) (bool, error) {
+ unPausedAndHealthy, err := c.commitStore.IsUnpausedAndARMHealthy(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return true, err
+ }
+ return !unPausedAndHealthy, nil
+}
+
+func (c *CommitStore) VerifyExecutionReport(ctx context.Context, report cciptypes.ExecReport) (bool, error) {
+ var hashes [][32]byte
+ for _, msg := range report.Messages {
+ hashes = append(hashes, msg.Hash)
+ }
+ res, err := c.commitStore.Verify(&bind.CallOpts{Context: ctx}, hashes, report.Proofs, report.ProofFlagBits)
+ if err != nil {
+ c.lggr.Errorw("Unable to call verify", "messages", report.Messages, "err", err)
+ return false, nil
+ }
+ // No timestamp, means failed to verify root.
+ if res.Cmp(big.NewInt(0)) == 0 {
+ c.lggr.Errorw("Root does not verify", "messages", report.Messages)
+ return false, nil
+ }
+ return true, nil
+}
+
+func (c *CommitStore) RegisterFilters() error {
+ return logpollerutil.RegisterLpFilters(c.lp, c.filters)
+}
+
+func NewCommitStore(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller) (*CommitStore, error) {
+ commitStore, err := commit_store_1_2_0.NewCommitStore(addr, ec)
+ if err != nil {
+ return nil, err
+ }
+ commitStoreABI := abihelpers.MustParseABI(commit_store_1_2_0.CommitStoreABI)
+ eventSig := abihelpers.MustGetEventID(v1_0_0.ReportAccepted, commitStoreABI)
+ commitReportArgs := abihelpers.MustGetEventInputs(v1_0_0.ReportAccepted, commitStoreABI)
+ filters := []logpoller.Filter{
+ {
+ Name: logpoller.FilterName(v1_0_0.EXEC_REPORT_ACCEPTS, addr.String()),
+ EventSigs: []common.Hash{eventSig},
+ Addresses: []common.Address{addr},
+ Retention: ccipdata.CommitExecLogsRetention,
+ },
+ }
+
+ return &CommitStore{
+ commitStore: commitStore,
+ address: addr,
+ lggr: lggr,
+ lp: lp,
+
+ // Note that sourceMaxGasPrice and estimator now have explicit setters (CCIP-2493)
+
+ filters: filters,
+ commitReportArgs: commitReportArgs,
+ reportAcceptedSig: eventSig,
+ // offset || priceUpdatesOffset || minSeqNum || maxSeqNum || merkleRoot
+ reportAcceptedMaxSeqIndex: 3,
+ configMu: sync.RWMutex{},
+
+ // The fields below are initially empty and set on ChangeConfig method
+ offchainConfig: cciptypes.CommitOffchainConfig{},
+ gasPriceEstimator: nil,
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store_test.go
new file mode 100644
index 00000000000..e0771f33cb9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/commit_store_test.go
@@ -0,0 +1,223 @@
+package v1_2_0
+
+import (
+ "math/big"
+ "math/rand"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+)
+
+func TestCommitReportEncoding(t *testing.T) {
+ t.Parallel()
+ ctx := testutils.Context(t)
+ report := cciptypes.CommitStoreReport{
+ TokenPrices: []cciptypes.TokenPrice{
+ {
+ Token: cciptypes.Address(utils.RandomAddress().String()),
+ Value: big.NewInt(9e18),
+ },
+ {
+ Token: cciptypes.Address(utils.RandomAddress().String()),
+ Value: big.NewInt(1e18),
+ },
+ },
+ GasPrices: []cciptypes.GasPrice{
+ {
+ DestChainSelector: rand.Uint64(),
+ Value: big.NewInt(2000e9),
+ },
+ {
+ DestChainSelector: rand.Uint64(),
+ Value: big.NewInt(3000e9),
+ },
+ },
+ MerkleRoot: [32]byte{123},
+ Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 10},
+ }
+
+ c, err := NewCommitStore(logger.Test(t), utils.RandomAddress(), nil, mocks.NewLogPoller(t))
+ assert.NoError(t, err)
+
+ encodedReport, err := c.EncodeCommitReport(ctx, report)
+ require.NoError(t, err)
+ assert.Greater(t, len(encodedReport), 0)
+
+ decodedReport, err := c.DecodeCommitReport(ctx, encodedReport)
+ require.NoError(t, err)
+ require.Equal(t, report, decodedReport)
+}
+
+func TestCommitStoreV120ffchainConfigEncoding(t *testing.T) {
+ t.Parallel()
+ validConfig := JSONCommitOffchainConfig{
+ SourceFinalityDepth: 3,
+ DestFinalityDepth: 4,
+ GasPriceHeartBeat: *config.MustNewDuration(1 * time.Minute),
+ DAGasPriceDeviationPPB: 10,
+ ExecGasPriceDeviationPPB: 11,
+ TokenPriceHeartBeat: *config.MustNewDuration(2 * time.Minute),
+ TokenPriceDeviationPPB: 12,
+ InflightCacheExpiry: *config.MustNewDuration(3 * time.Minute),
+ }
+
+ require.NoError(t, validConfig.Validate())
+
+ tests := []struct {
+ name string
+ want JSONCommitOffchainConfig
+ errPattern string
+ }{
+ {
+ name: "legacy offchain config format parses",
+ want: validConfig,
+ },
+ {
+ name: "can omit finality depth",
+ want: modifyCopy(validConfig, func(c *JSONCommitOffchainConfig) {
+ c.SourceFinalityDepth = 0
+ c.DestFinalityDepth = 0
+ }),
+ },
+ {
+ name: "can set PriceReportingDisabled",
+ want: modifyCopy(validConfig, func(c *JSONCommitOffchainConfig) {
+ c.PriceReportingDisabled = true
+ }),
+ },
+ {
+ name: "must set GasPriceHeartBeat",
+ want: modifyCopy(validConfig, func(c *JSONCommitOffchainConfig) {
+ c.GasPriceHeartBeat = *config.MustNewDuration(0)
+ }),
+ errPattern: "GasPriceHeartBeat",
+ },
+ {
+ name: "must set ExecGasPriceDeviationPPB",
+ want: modifyCopy(validConfig, func(c *JSONCommitOffchainConfig) {
+ c.ExecGasPriceDeviationPPB = 0
+ }),
+ errPattern: "ExecGasPriceDeviationPPB",
+ },
+ {
+ name: "must set TokenPriceHeartBeat",
+ want: modifyCopy(validConfig, func(c *JSONCommitOffchainConfig) {
+ c.TokenPriceHeartBeat = *config.MustNewDuration(0)
+ }),
+ errPattern: "TokenPriceHeartBeat",
+ },
+ {
+ name: "must set TokenPriceDeviationPPB",
+ want: modifyCopy(validConfig, func(c *JSONCommitOffchainConfig) {
+ c.TokenPriceDeviationPPB = 0
+ }),
+ errPattern: "TokenPriceDeviationPPB",
+ },
+ {
+ name: "must set InflightCacheExpiry",
+ want: modifyCopy(validConfig, func(c *JSONCommitOffchainConfig) {
+ c.InflightCacheExpiry = *config.MustNewDuration(0)
+ }),
+ errPattern: "InflightCacheExpiry",
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ exp := tc.want
+ encode, err := ccipconfig.EncodeOffchainConfig(&exp)
+ require.NoError(t, err)
+ got, err := ccipconfig.DecodeOffchainConfig[JSONCommitOffchainConfig](encode)
+
+ if tc.errPattern != "" {
+ require.ErrorContains(t, err, tc.errPattern)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tc.want, got)
+ }
+ })
+ }
+}
+
+func TestCommitStoreV120ffchainConfigDecodingCompatibility(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ config []byte
+ priceReportingDisabled bool
+ }{
+ {
+ name: "with MaxGasPrice",
+ config: []byte(`{
+ "SourceFinalityDepth": 3,
+ "DestFinalityDepth": 4,
+ "GasPriceHeartBeat": "60s",
+ "DAGasPriceDeviationPPB": 10,
+ "ExecGasPriceDeviationPPB": 11,
+ "TokenPriceHeartBeat": "120s",
+ "TokenPriceDeviationPPB": 12,
+ "MaxGasPrice": 100000000,
+ "SourceMaxGasPrice": 100000000,
+ "InflightCacheExpiry": "180s"
+ }`),
+ priceReportingDisabled: false,
+ },
+ {
+ name: "without MaxGasPrice",
+ config: []byte(`{
+ "SourceFinalityDepth": 3,
+ "DestFinalityDepth": 4,
+ "GasPriceHeartBeat": "60s",
+ "DAGasPriceDeviationPPB": 10,
+ "ExecGasPriceDeviationPPB": 11,
+ "TokenPriceHeartBeat": "120s",
+ "TokenPriceDeviationPPB": 12,
+ "InflightCacheExpiry": "180s"
+ }`),
+ priceReportingDisabled: false,
+ },
+ {
+ name: "with PriceReportingDisabled",
+ config: []byte(`{
+ "SourceFinalityDepth": 3,
+ "DestFinalityDepth": 4,
+ "GasPriceHeartBeat": "60s",
+ "DAGasPriceDeviationPPB": 10,
+ "ExecGasPriceDeviationPPB": 11,
+ "TokenPriceHeartBeat": "120s",
+ "TokenPriceDeviationPPB": 12,
+ "InflightCacheExpiry": "180s",
+ "PriceReportingDisabled": true
+ }`),
+ priceReportingDisabled: true,
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ decoded, err := ccipconfig.DecodeOffchainConfig[JSONCommitOffchainConfig](tc.config)
+ require.NoError(t, err)
+ require.Equal(t, JSONCommitOffchainConfig{
+ SourceFinalityDepth: 3,
+ DestFinalityDepth: 4,
+ GasPriceHeartBeat: *config.MustNewDuration(1 * time.Minute),
+ DAGasPriceDeviationPPB: 10,
+ ExecGasPriceDeviationPPB: 11,
+ TokenPriceHeartBeat: *config.MustNewDuration(2 * time.Minute),
+ TokenPriceDeviationPPB: 12,
+ InflightCacheExpiry: *config.MustNewDuration(3 * time.Minute),
+ PriceReportingDisabled: tc.priceReportingDisabled,
+ }, decoded)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/hasher.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/hasher.go
new file mode 100644
index 00000000000..4739c946c36
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/hasher.go
@@ -0,0 +1,101 @@
+package v1_2_0
+
+import (
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+)
+
+const (
+ MetaDataHashPrefix = "EVM2EVMMessageHashV2"
+)
+
+type LeafHasher struct {
+ metaDataHash [32]byte
+ ctx hashutil.Hasher[[32]byte]
+ onRamp *evm_2_evm_onramp_1_2_0.EVM2EVMOnRamp
+}
+
+func NewLeafHasher(sourceChainSelector uint64, destChainSelector uint64, onRampId common.Address, ctx hashutil.Hasher[[32]byte], onRamp *evm_2_evm_onramp_1_2_0.EVM2EVMOnRamp) *LeafHasher {
+ return &LeafHasher{
+ metaDataHash: v1_0_0.GetMetaDataHash(ctx, ctx.Hash([]byte(MetaDataHashPrefix)), sourceChainSelector, onRampId, destChainSelector),
+ ctx: ctx,
+ onRamp: onRamp,
+ }
+}
+
+func (t *LeafHasher) HashLeaf(log types.Log) ([32]byte, error) {
+ msg, err := t.onRamp.ParseCCIPSendRequested(log)
+ if err != nil {
+ return [32]byte{}, err
+ }
+ message := msg.Message
+ encodedTokens, err := abihelpers.ABIEncode(
+ `[
+{"components": [{"name":"token","type":"address"},{"name":"amount","type":"uint256"}], "type":"tuple[]"}]`, message.TokenAmounts)
+ if err != nil {
+ return [32]byte{}, err
+ }
+
+ bytesArray, err := abi.NewType("bytes[]", "bytes[]", nil)
+ if err != nil {
+ return [32]byte{}, err
+ }
+
+ encodedSourceTokenData, err := abi.Arguments{abi.Argument{Type: bytesArray}}.PackValues([]interface{}{message.SourceTokenData})
+ if err != nil {
+ return [32]byte{}, err
+ }
+
+ packedFixedSizeValues, err := abihelpers.ABIEncode(
+ `[
+{"name": "sender", "type":"address"},
+{"name": "receiver", "type":"address"},
+{"name": "sequenceNumber", "type":"uint64"},
+{"name": "gasLimit", "type":"uint256"},
+{"name": "strict", "type":"bool"},
+{"name": "nonce", "type":"uint64"},
+{"name": "feeToken","type": "address"},
+{"name": "feeTokenAmount","type": "uint256"}
+]`,
+ message.Sender,
+ message.Receiver,
+ message.SequenceNumber,
+ message.GasLimit,
+ message.Strict,
+ message.Nonce,
+ message.FeeToken,
+ message.FeeTokenAmount,
+ )
+ if err != nil {
+ return [32]byte{}, err
+ }
+ fixedSizeValuesHash := t.ctx.Hash(packedFixedSizeValues)
+
+ packedValues, err := abihelpers.ABIEncode(
+ `[
+{"name": "leafDomainSeparator","type":"bytes1"},
+{"name": "metadataHash", "type":"bytes32"},
+{"name": "fixedSizeValuesHash", "type":"bytes32"},
+{"name": "dataHash", "type":"bytes32"},
+{"name": "tokenAmountsHash", "type":"bytes32"},
+{"name": "sourceTokenDataHash", "type":"bytes32"}
+]`,
+ v1_0_0.LeafDomainSeparator,
+ t.metaDataHash,
+ fixedSizeValuesHash,
+ t.ctx.Hash(message.Data),
+ t.ctx.Hash(encodedTokens),
+ t.ctx.Hash(encodedSourceTokenData),
+ )
+ if err != nil {
+ return [32]byte{}, err
+ }
+ return t.ctx.Hash(packedValues), nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/hasher_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/hasher_test.go
new file mode 100644
index 00000000000..4bfbf7295e6
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/hasher_test.go
@@ -0,0 +1,78 @@
+package v1_2_0
+
+import (
+ "encoding/hex"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+func TestHasherV1_2_0(t *testing.T) {
+ sourceChainSelector, destChainSelector := uint64(1), uint64(4)
+ onRampAddress := common.HexToAddress("0x5550000000000000000000000000000000000001")
+ onRampABI := abihelpers.MustParseABI(evm_2_evm_onramp_1_2_0.EVM2EVMOnRampABI)
+
+ hashingCtx := hashutil.NewKeccak()
+ ramp, err := evm_2_evm_onramp_1_2_0.NewEVM2EVMOnRamp(onRampAddress, nil)
+ require.NoError(t, err)
+ hasher := NewLeafHasher(sourceChainSelector, destChainSelector, onRampAddress, hashingCtx, ramp)
+
+ message := evm_2_evm_onramp_1_2_0.InternalEVM2EVMMessage{
+ SourceChainSelector: sourceChainSelector,
+ Sender: common.HexToAddress("0x1110000000000000000000000000000000000001"),
+ Receiver: common.HexToAddress("0x2220000000000000000000000000000000000001"),
+ SequenceNumber: 1337,
+ GasLimit: big.NewInt(100),
+ Strict: false,
+ Nonce: 1337,
+ FeeToken: common.Address{},
+ FeeTokenAmount: big.NewInt(1),
+ Data: []byte{},
+ TokenAmounts: []evm_2_evm_onramp_1_2_0.ClientEVMTokenAmount{{Token: common.HexToAddress("0x4440000000000000000000000000000000000001"), Amount: big.NewInt(12345678900)}},
+ SourceTokenData: [][]byte{},
+ MessageId: [32]byte{},
+ }
+
+ data, err := onRampABI.Events[CCIPSendRequestedEventName].Inputs.Pack(message)
+ require.NoError(t, err)
+ hash, err := hasher.HashLeaf(types.Log{Topics: []common.Hash{CCIPSendRequestEventSig}, Data: data})
+ require.NoError(t, err)
+
+ // NOTE: Must match spec
+ require.Equal(t, "46ad031bfb052db2e4a2514fed8dc480b98e5ce4acb55d5640d91407e0d8a3e9", hex.EncodeToString(hash[:]))
+
+ message = evm_2_evm_onramp_1_2_0.InternalEVM2EVMMessage{
+ SourceChainSelector: sourceChainSelector,
+ Sender: common.HexToAddress("0x1110000000000000000000000000000000000001"),
+ Receiver: common.HexToAddress("0x2220000000000000000000000000000000000001"),
+ SequenceNumber: 1337,
+ GasLimit: big.NewInt(100),
+ Strict: false,
+ Nonce: 1337,
+ FeeToken: common.Address{},
+ FeeTokenAmount: big.NewInt(1e12),
+ Data: []byte("foo bar baz"),
+ TokenAmounts: []evm_2_evm_onramp_1_2_0.ClientEVMTokenAmount{
+ {Token: common.HexToAddress("0x4440000000000000000000000000000000000001"), Amount: big.NewInt(12345678900)},
+ {Token: common.HexToAddress("0x6660000000000000000000000000000000000001"), Amount: big.NewInt(4204242)},
+ },
+ SourceTokenData: [][]byte{{0x2, 0x1}},
+ MessageId: [32]byte{},
+ }
+
+ data, err = onRampABI.Events[CCIPSendRequestedEventName].Inputs.Pack(message)
+ require.NoError(t, err)
+ hash, err = hasher.HashLeaf(types.Log{Topics: []common.Hash{CCIPSendRequestEventSig}, Data: data})
+ require.NoError(t, err)
+
+ // NOTE: Must match spec
+ require.Equal(t, "4362a13a42e52ff5ce4324e7184dc7aa41704c3146bc842d35d95b94b32a78b6", hex.EncodeToString(hash[:]))
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp.go
new file mode 100644
index 00000000000..1f404397430
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp.go
@@ -0,0 +1,339 @@
+package v1_2_0
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+var (
+ abiOffRamp = abihelpers.MustParseABI(evm_2_evm_offramp_1_2_0.EVM2EVMOffRampABI)
+ _ ccipdata.OffRampReader = &OffRamp{}
+)
+
+type ExecOnchainConfig evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig
+
+func (d ExecOnchainConfig) AbiString() string {
+ return `
+ [
+ {
+ "components": [
+ {"name": "permissionLessExecutionThresholdSeconds", "type": "uint32"},
+ {"name": "router", "type": "address"},
+ {"name": "priceRegistry", "type": "address"},
+ {"name": "maxNumberOfTokensPerMsg", "type": "uint16"},
+ {"name": "maxDataBytes", "type": "uint32"},
+ {"name": "maxPoolReleaseOrMintGas", "type": "uint32"}
+ ],
+ "type": "tuple"
+ }
+ ]`
+}
+
+func (d ExecOnchainConfig) Validate() error {
+ if d.PermissionLessExecutionThresholdSeconds == 0 {
+ return errors.New("must set PermissionLessExecutionThresholdSeconds")
+ }
+ if d.Router == (common.Address{}) {
+ return errors.New("must set Router address")
+ }
+ if d.PriceRegistry == (common.Address{}) {
+ return errors.New("must set PriceRegistry address")
+ }
+ if d.MaxNumberOfTokensPerMsg == 0 {
+ return errors.New("must set MaxNumberOfTokensPerMsg")
+ }
+ if d.MaxPoolReleaseOrMintGas == 0 {
+ return errors.New("must set MaxPoolReleaseOrMintGas")
+ }
+ return nil
+}
+
+// JSONExecOffchainConfig is the configuration for nodes executing committed CCIP messages (v1.2).
+// It comes from the OffchainConfig field of the corresponding OCR2 plugin configuration.
+// NOTE: do not change the JSON format of this struct without consulting with the RDD people first.
+type JSONExecOffchainConfig struct {
+ // SourceFinalityDepth indicates how many confirmations a transaction should get on the source chain event before we consider it finalized.
+ //
+ // Deprecated: we now use the source chain finality instead.
+ SourceFinalityDepth uint32
+ // See [ccipdata.ExecOffchainConfig.DestOptimisticConfirmations]
+ DestOptimisticConfirmations uint32
+ // DestFinalityDepth indicates how many confirmations a transaction should get on the destination chain event before we consider it finalized.
+ //
+ // Deprecated: we now use the destination chain finality instead.
+ DestFinalityDepth uint32
+ // See [ccipdata.ExecOffchainConfig.BatchGasLimit]
+ BatchGasLimit uint32
+ // See [ccipdata.ExecOffchainConfig.RelativeBoostPerWaitHour]
+ RelativeBoostPerWaitHour float64
+ // See [ccipdata.ExecOffchainConfig.InflightCacheExpiry]
+ InflightCacheExpiry config.Duration
+ // See [ccipdata.ExecOffchainConfig.RootSnoozeTime]
+ RootSnoozeTime config.Duration
+ // See [ccipdata.ExecOffchainConfig.BatchingStrategyID]
+ BatchingStrategyID uint32
+ // See [ccipdata.ExecOffchainConfig.MessageVisibilityInterval]
+ MessageVisibilityInterval config.Duration
+}
+
+func (c JSONExecOffchainConfig) Validate() error {
+ if c.DestOptimisticConfirmations == 0 {
+ return errors.New("must set DestOptimisticConfirmations")
+ }
+ if c.BatchGasLimit == 0 {
+ return errors.New("must set BatchGasLimit")
+ }
+ if c.RelativeBoostPerWaitHour == 0 {
+ return errors.New("must set RelativeBoostPerWaitHour")
+ }
+ if c.InflightCacheExpiry.Duration() == 0 {
+ return errors.New("must set InflightCacheExpiry")
+ }
+ if c.RootSnoozeTime.Duration() == 0 {
+ return errors.New("must set RootSnoozeTime")
+ }
+
+ return nil
+}
+
+// OffRamp In 1.2 we have a different estimator impl
+type OffRamp struct {
+ *v1_0_0.OffRamp
+ offRampV120 evm_2_evm_offramp_1_2_0.EVM2EVMOffRampInterface
+}
+
+func (o *OffRamp) CurrentRateLimiterState(ctx context.Context) (cciptypes.TokenBucketRateLimit, error) {
+ bucket, err := o.offRampV120.CurrentRateLimiterState(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return cciptypes.TokenBucketRateLimit{}, err
+ }
+ return cciptypes.TokenBucketRateLimit{
+ Tokens: bucket.Tokens,
+ LastUpdated: bucket.LastUpdated,
+ IsEnabled: bucket.IsEnabled,
+ Capacity: bucket.Capacity,
+ Rate: bucket.Rate,
+ }, nil
+}
+
+func (o *OffRamp) GetRouter(ctx context.Context) (cciptypes.Address, error) {
+ dynamicConfig, err := o.offRampV120.GetDynamicConfig(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return "", err
+ }
+ return ccipcalc.EvmAddrToGeneric(dynamicConfig.Router), nil
+}
+
+func (o *OffRamp) ChangeConfig(ctx context.Context, onchainConfigBytes []byte, offchainConfigBytes []byte) (cciptypes.Address, cciptypes.Address, error) {
+ // Same as the v1.0.0 method, except for the ExecOnchainConfig type.
+ onchainConfigParsed, err := abihelpers.DecodeAbiStruct[ExecOnchainConfig](onchainConfigBytes)
+ if err != nil {
+ return "", "", err
+ }
+
+ offchainConfigParsed, err := ccipconfig.DecodeOffchainConfig[JSONExecOffchainConfig](offchainConfigBytes)
+ if err != nil {
+ return "", "", err
+ }
+ destRouter, err := router.NewRouter(onchainConfigParsed.Router, o.Client)
+ if err != nil {
+ return "", "", err
+ }
+ destWrappedNative, err := destRouter.GetWrappedNative(nil)
+ if err != nil {
+ return "", "", err
+ }
+ offchainConfig := cciptypes.ExecOffchainConfig{
+ DestOptimisticConfirmations: offchainConfigParsed.DestOptimisticConfirmations,
+ BatchGasLimit: offchainConfigParsed.BatchGasLimit,
+ RelativeBoostPerWaitHour: offchainConfigParsed.RelativeBoostPerWaitHour,
+ InflightCacheExpiry: offchainConfigParsed.InflightCacheExpiry,
+ RootSnoozeTime: offchainConfigParsed.RootSnoozeTime,
+ MessageVisibilityInterval: offchainConfigParsed.MessageVisibilityInterval,
+ BatchingStrategyID: offchainConfigParsed.BatchingStrategyID,
+ }
+ onchainConfig := cciptypes.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: time.Second * time.Duration(onchainConfigParsed.PermissionLessExecutionThresholdSeconds),
+ Router: cciptypes.Address(onchainConfigParsed.Router.String()),
+ }
+ priceEstimator := prices.NewDAGasPriceEstimator(o.Estimator, o.DestMaxGasPrice, 0, 0)
+
+ o.UpdateDynamicConfig(onchainConfig, offchainConfig, priceEstimator)
+
+ o.Logger.Infow("Starting exec plugin",
+ "offchainConfig", onchainConfigParsed,
+ "onchainConfig", offchainConfigParsed)
+ return cciptypes.Address(onchainConfigParsed.PriceRegistry.String()),
+ cciptypes.Address(destWrappedNative.String()), nil
+}
+
+func EncodeExecutionReport(ctx context.Context, args abi.Arguments, report cciptypes.ExecReport) ([]byte, error) {
+ var msgs []evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage
+ for _, msg := range report.Messages {
+ var ta []evm_2_evm_offramp_1_2_0.ClientEVMTokenAmount
+ for _, tokenAndAmount := range msg.TokenAmounts {
+ evmAddrs, err := ccipcalc.GenericAddrsToEvm(tokenAndAmount.Token)
+ if err != nil {
+ return nil, err
+ }
+ ta = append(ta, evm_2_evm_offramp_1_2_0.ClientEVMTokenAmount{
+ Token: evmAddrs[0],
+ Amount: tokenAndAmount.Amount,
+ })
+ }
+
+ evmAddrs, err := ccipcalc.GenericAddrsToEvm(msg.Sender, msg.Receiver, msg.FeeToken)
+ if err != nil {
+ return nil, err
+ }
+
+ msgs = append(msgs, evm_2_evm_offramp_1_2_0.InternalEVM2EVMMessage{
+ SourceChainSelector: msg.SourceChainSelector,
+ Sender: evmAddrs[0],
+ Receiver: evmAddrs[1],
+ SequenceNumber: msg.SequenceNumber,
+ GasLimit: msg.GasLimit,
+ Strict: msg.Strict,
+ Nonce: msg.Nonce,
+ FeeToken: evmAddrs[2],
+ FeeTokenAmount: msg.FeeTokenAmount,
+ Data: msg.Data,
+ TokenAmounts: ta,
+ MessageId: msg.MessageID,
+ // NOTE: this field is new in v1.2.
+ SourceTokenData: msg.SourceTokenData,
+ })
+ }
+
+ rep := evm_2_evm_offramp_1_2_0.InternalExecutionReport{
+ Messages: msgs,
+ OffchainTokenData: report.OffchainTokenData,
+ Proofs: report.Proofs,
+ ProofFlagBits: report.ProofFlagBits,
+ }
+ return args.PackValues([]interface{}{&rep})
+}
+
+func (o *OffRamp) EncodeExecutionReport(ctx context.Context, report cciptypes.ExecReport) ([]byte, error) {
+ return EncodeExecutionReport(ctx, o.ExecutionReportArgs, report)
+}
+
+func DecodeExecReport(ctx context.Context, args abi.Arguments, report []byte) (cciptypes.ExecReport, error) {
+ unpacked, err := args.Unpack(report)
+ if err != nil {
+ return cciptypes.ExecReport{}, err
+ }
+ if len(unpacked) == 0 {
+ return cciptypes.ExecReport{}, errors.New("assumptionViolation: expected at least one element")
+ }
+ // Must be anonymous struct here
+ erStruct, ok := unpacked[0].(struct {
+ Messages []struct {
+ SourceChainSelector uint64 `json:"sourceChainSelector"`
+ Sender common.Address `json:"sender"`
+ Receiver common.Address `json:"receiver"`
+ SequenceNumber uint64 `json:"sequenceNumber"`
+ GasLimit *big.Int `json:"gasLimit"`
+ Strict bool `json:"strict"`
+ Nonce uint64 `json:"nonce"`
+ FeeToken common.Address `json:"feeToken"`
+ FeeTokenAmount *big.Int `json:"feeTokenAmount"`
+ Data []uint8 `json:"data"`
+ TokenAmounts []struct {
+ Token common.Address `json:"token"`
+ Amount *big.Int `json:"amount"`
+ } `json:"tokenAmounts"`
+ SourceTokenData [][]uint8 `json:"sourceTokenData"`
+ MessageId [32]uint8 `json:"messageId"`
+ } `json:"messages"`
+ OffchainTokenData [][][]uint8 `json:"offchainTokenData"`
+ Proofs [][32]uint8 `json:"proofs"`
+ ProofFlagBits *big.Int `json:"proofFlagBits"`
+ })
+ if !ok {
+ return cciptypes.ExecReport{}, fmt.Errorf("got %T", unpacked[0])
+ }
+ messages := make([]cciptypes.EVM2EVMMessage, 0, len(erStruct.Messages))
+ for _, msg := range erStruct.Messages {
+ var tokensAndAmounts []cciptypes.TokenAmount
+ for _, tokenAndAmount := range msg.TokenAmounts {
+ tokensAndAmounts = append(tokensAndAmounts, cciptypes.TokenAmount{
+ Token: cciptypes.Address(tokenAndAmount.Token.String()),
+ Amount: tokenAndAmount.Amount,
+ })
+ }
+ messages = append(messages, cciptypes.EVM2EVMMessage{
+ SequenceNumber: msg.SequenceNumber,
+ GasLimit: msg.GasLimit,
+ Nonce: msg.Nonce,
+ MessageID: msg.MessageId,
+ SourceChainSelector: msg.SourceChainSelector,
+ Sender: cciptypes.Address(msg.Sender.String()),
+ Receiver: cciptypes.Address(msg.Receiver.String()),
+ Strict: msg.Strict,
+ FeeToken: cciptypes.Address(msg.FeeToken.String()),
+ FeeTokenAmount: msg.FeeTokenAmount,
+ Data: msg.Data,
+ TokenAmounts: tokensAndAmounts,
+ SourceTokenData: msg.SourceTokenData,
+ // TODO: Not needed for plugins, but should be recomputed for consistency.
+ // Requires the offramp knowing about onramp version
+ Hash: [32]byte{},
+ })
+ }
+
+ // Unpack will populate with big.Int{false, } for 0 values,
+ // which is different from the expected big.NewInt(0). Rebuild to the expected value for this case.
+ return cciptypes.ExecReport{
+ Messages: messages,
+ OffchainTokenData: erStruct.OffchainTokenData,
+ Proofs: erStruct.Proofs,
+ ProofFlagBits: new(big.Int).SetBytes(erStruct.ProofFlagBits.Bytes()),
+ }, nil
+}
+
+func (o *OffRamp) DecodeExecutionReport(ctx context.Context, report []byte) (cciptypes.ExecReport, error) {
+ return DecodeExecReport(ctx, o.ExecutionReportArgs, report)
+}
+
+func NewOffRamp(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int) (*OffRamp, error) {
+ v100, err := v1_0_0.NewOffRamp(lggr, addr, ec, lp, estimator, destMaxGasPrice)
+ if err != nil {
+ return nil, err
+ }
+
+ offRamp, err := evm_2_evm_offramp_1_2_0.NewEVM2EVMOffRamp(addr, ec)
+ if err != nil {
+ return nil, err
+ }
+
+ v100.ExecutionReportArgs = abihelpers.MustGetMethodInputs("manuallyExecute", abiOffRamp)[:1]
+
+ return &OffRamp{
+ OffRamp: v100,
+ offRampV120: offRamp,
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_reader_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_reader_test.go
new file mode 100644
index 00000000000..630b92f67fc
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_reader_test.go
@@ -0,0 +1,39 @@
+package v1_2_0_test
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+)
+
+func TestExecutionReportEncodingV120(t *testing.T) {
+ // Note could consider some fancier testing here (fuzz/property)
+ // but I think that would essentially be testing geth's abi library
+ // as our encode/decode is a thin wrapper around that.
+ report := cciptypes.ExecReport{
+ Messages: []cciptypes.EVM2EVMMessage{},
+ OffchainTokenData: [][][]byte{{}},
+ Proofs: [][32]byte{testutils.Random32Byte()},
+ ProofFlagBits: big.NewInt(133),
+ }
+
+ offRamp, err := v1_2_0.NewOffRamp(logger.Test(t), utils.RandomAddress(), nil, lpmocks.NewLogPoller(t), nil, nil)
+ require.NoError(t, err)
+
+ ctx := testutils.Context(t)
+ encodeExecutionReport, err := offRamp.EncodeExecutionReport(ctx, report)
+ require.NoError(t, err)
+ decodeCommitReport, err := offRamp.DecodeExecutionReport(ctx, encodeExecutionReport)
+ require.NoError(t, err)
+ require.Equal(t, report.Proofs, decodeCommitReport.Proofs)
+ require.Equal(t, report, decodeCommitReport)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_reader_unit_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_reader_unit_test.go
new file mode 100644
index 00000000000..98454ce59b2
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_reader_unit_test.go
@@ -0,0 +1,36 @@
+package v1_2_0
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0"
+ mock_contracts "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/mocks/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+func TestGetRouter(t *testing.T) {
+ routerAddr := utils.RandomAddress()
+
+ mockOffRamp := mock_contracts.NewEVM2EVMOffRampInterface(t)
+ mockOffRamp.On("GetDynamicConfig", mock.Anything).Return(evm_2_evm_offramp_1_2_0.EVM2EVMOffRampDynamicConfig{
+ Router: routerAddr,
+ }, nil)
+
+ offRamp := OffRamp{
+ offRampV120: mockOffRamp,
+ }
+
+ ctx := testutils.Context(t)
+ gotRouterAddr, err := offRamp.GetRouter(ctx)
+ require.NoError(t, err)
+
+ gotRouterEvmAddr, err := ccipcalc.GenericAddrToEvm(gotRouterAddr)
+ require.NoError(t, err)
+ assert.Equal(t, routerAddr, gotRouterEvmAddr)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_test.go
new file mode 100644
index 00000000000..7d174d5db71
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/offramp_test.go
@@ -0,0 +1,173 @@
+package v1_2_0
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+)
+
+func modifyCopy[T any](c T, f func(c *T)) T {
+ f(&c)
+ return c
+}
+
+func TestExecOffchainConfig120_Encoding(t *testing.T) {
+ t.Parallel()
+ validConfig := JSONExecOffchainConfig{
+ SourceFinalityDepth: 3,
+ DestOptimisticConfirmations: 6,
+ DestFinalityDepth: 3,
+ BatchGasLimit: 5_000_000,
+ RelativeBoostPerWaitHour: 0.07,
+ InflightCacheExpiry: *config.MustNewDuration(64 * time.Second),
+ RootSnoozeTime: *config.MustNewDuration(128 * time.Minute),
+ BatchingStrategyID: 0,
+ }
+
+ tests := []struct {
+ name string
+ want JSONExecOffchainConfig
+ errPattern string
+ }{
+ {
+ name: "legacy offchain config format parses",
+ want: validConfig,
+ },
+ {
+ name: "can omit finality depth",
+ want: modifyCopy(validConfig, func(c *JSONExecOffchainConfig) {
+ c.SourceFinalityDepth = 0
+ c.DestFinalityDepth = 0
+ }),
+ },
+ {
+ name: "must set BatchGasLimit",
+ want: modifyCopy(validConfig, func(c *JSONExecOffchainConfig) {
+ c.BatchGasLimit = 0
+ }),
+ errPattern: "BatchGasLimit",
+ },
+ {
+ name: "must set DestOptimisticConfirmations",
+ want: modifyCopy(validConfig, func(c *JSONExecOffchainConfig) {
+ c.DestOptimisticConfirmations = 0
+ }),
+ errPattern: "DestOptimisticConfirmations",
+ },
+ {
+ name: "must set RelativeBoostPerWaitHour",
+ want: modifyCopy(validConfig, func(c *JSONExecOffchainConfig) {
+ c.RelativeBoostPerWaitHour = 0
+ }),
+ errPattern: "RelativeBoostPerWaitHour",
+ },
+ {
+ name: "must set InflightCacheExpiry",
+ want: modifyCopy(validConfig, func(c *JSONExecOffchainConfig) {
+ c.InflightCacheExpiry = *config.MustNewDuration(0)
+ }),
+ errPattern: "InflightCacheExpiry",
+ },
+ {
+ name: "must set RootSnoozeTime",
+ want: modifyCopy(validConfig, func(c *JSONExecOffchainConfig) {
+ c.RootSnoozeTime = *config.MustNewDuration(0)
+ }),
+ errPattern: "RootSnoozeTime",
+ },
+ {
+ name: "must set BatchingStrategyId",
+ want: modifyCopy(validConfig, func(c *JSONExecOffchainConfig) {
+ c.BatchingStrategyID = 1
+ }),
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ exp := tc.want
+ encode, err := ccipconfig.EncodeOffchainConfig(&exp)
+ require.NoError(t, err)
+ got, err := ccipconfig.DecodeOffchainConfig[JSONExecOffchainConfig](encode)
+
+ if tc.errPattern != "" {
+ require.ErrorContains(t, err, tc.errPattern)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, tc.want, got)
+ }
+ })
+ }
+}
+
+func TestExecOffchainConfig120_ParseRawJson(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ config []byte
+ }{
+ {
+ name: "with MaxGasPrice",
+ config: []byte(`{
+ "DestOptimisticConfirmations": 6,
+ "BatchGasLimit": 5000000,
+ "RelativeBoostPerWaitHour": 0.07,
+ "MaxGasPrice": 200000000000,
+ "InflightCacheExpiry": "64s",
+ "RootSnoozeTime": "128m"
+ }`),
+ },
+ {
+ name: "without MaxGasPrice",
+ config: []byte(`{
+ "DestOptimisticConfirmations": 6,
+ "BatchGasLimit": 5000000,
+ "RelativeBoostPerWaitHour": 0.07,
+ "InflightCacheExpiry": "64s",
+ "RootSnoozeTime": "128m"
+ }`),
+ },
+ {
+ name: "with BatchingStrategyId",
+ config: []byte(`{
+ "DestOptimisticConfirmations": 6,
+ "BatchGasLimit": 5000000,
+ "RelativeBoostPerWaitHour": 0.07,
+ "InflightCacheExpiry": "64s",
+ "RootSnoozeTime": "128m",
+ "BatchingStrategyId": 1
+ }`),
+ },
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ decoded, err := ccipconfig.DecodeOffchainConfig[JSONExecOffchainConfig](tc.config)
+ require.NoError(t, err)
+
+ if tc.name == "with BatchingStrategyId" {
+ require.Equal(t, JSONExecOffchainConfig{
+ DestOptimisticConfirmations: 6,
+ BatchGasLimit: 5_000_000,
+ RelativeBoostPerWaitHour: 0.07,
+ InflightCacheExpiry: *config.MustNewDuration(64 * time.Second),
+ RootSnoozeTime: *config.MustNewDuration(128 * time.Minute),
+ BatchingStrategyID: 1, // Actual value
+ }, decoded)
+ } else {
+ require.Equal(t, JSONExecOffchainConfig{
+ DestOptimisticConfirmations: 6,
+ BatchGasLimit: 5_000_000,
+ RelativeBoostPerWaitHour: 0.07,
+ InflightCacheExpiry: *config.MustNewDuration(64 * time.Second),
+ RootSnoozeTime: *config.MustNewDuration(128 * time.Minute),
+ BatchingStrategyID: 0, // Default
+ }, decoded)
+ }
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/onramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/onramp.go
new file mode 100644
index 00000000000..9579286470c
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/onramp.go
@@ -0,0 +1,256 @@
+package v1_2_0
+
+import (
+ "context"
+ "fmt"
+ "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"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/logpollerutil"
+)
+
+var (
+ // Backwards compat for integration tests
+ CCIPSendRequestEventSig common.Hash
+ ConfigSetEventSig common.Hash
+)
+
+const (
+ CCIPSendRequestSeqNumIndex = 4
+ CCIPSendRequestedEventName = "CCIPSendRequested"
+ ConfigSetEventName = "ConfigSet"
+)
+
+func init() {
+ onRampABI, err := abi.JSON(strings.NewReader(evm_2_evm_onramp_1_2_0.EVM2EVMOnRampABI))
+ if err != nil {
+ panic(err)
+ }
+ CCIPSendRequestEventSig = abihelpers.MustGetEventID(CCIPSendRequestedEventName, onRampABI)
+ ConfigSetEventSig = abihelpers.MustGetEventID(ConfigSetEventName, onRampABI)
+}
+
+var _ ccipdata.OnRampReader = &OnRamp{}
+
+// Significant change in 1.2:
+// - CCIPSendRequested event signature has changed
+type OnRamp struct {
+ onRamp *evm_2_evm_onramp_1_2_0.EVM2EVMOnRamp
+ address common.Address
+ lggr logger.Logger
+ lp logpoller.LogPoller
+ leafHasher ccipdata.LeafHasherInterface[[32]byte]
+ client client.Client
+ sendRequestedEventSig common.Hash
+ sendRequestedSeqNumberWord int
+ filters []logpoller.Filter
+ cachedSourcePriceRegistryAddress cache.AutoSync[cciptypes.Address]
+ // Static config can be cached, because it's never expected to change.
+ // The only way to change that is through the contract's constructor (redeployment)
+ cachedStaticConfig cache.OnceCtxFunction[evm_2_evm_onramp_1_2_0.EVM2EVMOnRampStaticConfig]
+ cachedRmnContract cache.OnceCtxFunction[*arm_contract.ARMContract]
+}
+
+func NewOnRamp(lggr logger.Logger, sourceSelector, destSelector uint64, onRampAddress common.Address, sourceLP logpoller.LogPoller, source client.Client) (*OnRamp, error) {
+ onRamp, err := evm_2_evm_onramp_1_2_0.NewEVM2EVMOnRamp(onRampAddress, source)
+ if err != nil {
+ return nil, err
+ }
+ // Subscribe to the relevant logs
+ // Note we can keep the same prefix across 1.0/1.1 and 1.2 because the onramp addresses will be different
+ filters := []logpoller.Filter{
+ {
+ Name: logpoller.FilterName(ccipdata.COMMIT_CCIP_SENDS, onRampAddress),
+ EventSigs: []common.Hash{CCIPSendRequestEventSig},
+ Addresses: []common.Address{onRampAddress},
+ Retention: ccipdata.CommitExecLogsRetention,
+ },
+ {
+ Name: logpoller.FilterName(ccipdata.CONFIG_CHANGED, onRampAddress),
+ EventSigs: []common.Hash{ConfigSetEventSig},
+ Addresses: []common.Address{onRampAddress},
+ Retention: ccipdata.CacheEvictionLogsRetention,
+ },
+ }
+ cachedStaticConfig := cache.OnceCtxFunction[evm_2_evm_onramp_1_2_0.EVM2EVMOnRampStaticConfig](func(ctx context.Context) (evm_2_evm_onramp_1_2_0.EVM2EVMOnRampStaticConfig, error) {
+ return onRamp.GetStaticConfig(&bind.CallOpts{Context: ctx})
+ })
+ cachedRmnContract := cache.OnceCtxFunction[*arm_contract.ARMContract](func(ctx context.Context) (*arm_contract.ARMContract, error) {
+ staticConfig, err := cachedStaticConfig(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return arm_contract.NewARMContract(staticConfig.ArmProxy, source)
+ })
+ return &OnRamp{
+ lggr: lggr,
+ client: source,
+ lp: sourceLP,
+ leafHasher: NewLeafHasher(sourceSelector, destSelector, onRampAddress, hashutil.NewKeccak(), onRamp),
+ onRamp: onRamp,
+ filters: filters,
+ address: onRampAddress,
+ sendRequestedSeqNumberWord: CCIPSendRequestSeqNumIndex,
+ sendRequestedEventSig: CCIPSendRequestEventSig,
+ cachedSourcePriceRegistryAddress: cache.NewLogpollerEventsBased[cciptypes.Address](
+ sourceLP,
+ []common.Hash{ConfigSetEventSig},
+ onRampAddress,
+ ),
+ cachedStaticConfig: cache.CallOnceOnNoError(cachedStaticConfig),
+ cachedRmnContract: cache.CallOnceOnNoError(cachedRmnContract),
+ }, nil
+}
+
+func (o *OnRamp) Address(context.Context) (cciptypes.Address, error) {
+ return cciptypes.Address(o.onRamp.Address().String()), nil
+}
+
+func (o *OnRamp) GetDynamicConfig(context.Context) (cciptypes.OnRampDynamicConfig, error) {
+ if o.onRamp == nil {
+ return cciptypes.OnRampDynamicConfig{}, fmt.Errorf("onramp not initialized")
+ }
+ config, err := o.onRamp.GetDynamicConfig(&bind.CallOpts{})
+ if err != nil {
+ return cciptypes.OnRampDynamicConfig{}, fmt.Errorf("get dynamic config v1.2: %w", err)
+ }
+ return cciptypes.OnRampDynamicConfig{
+ Router: cciptypes.Address(config.Router.String()),
+ MaxNumberOfTokensPerMsg: config.MaxNumberOfTokensPerMsg,
+ DestGasOverhead: config.DestGasOverhead,
+ DestGasPerPayloadByte: config.DestGasPerPayloadByte,
+ DestDataAvailabilityOverheadGas: config.DestDataAvailabilityOverheadGas,
+ DestGasPerDataAvailabilityByte: config.DestGasPerDataAvailabilityByte,
+ DestDataAvailabilityMultiplierBps: config.DestDataAvailabilityMultiplierBps,
+ PriceRegistry: cciptypes.Address(config.PriceRegistry.String()),
+ MaxDataBytes: config.MaxDataBytes,
+ MaxPerMsgGasLimit: config.MaxPerMsgGasLimit,
+ }, nil
+}
+
+func (o *OnRamp) SourcePriceRegistryAddress(ctx context.Context) (cciptypes.Address, error) {
+ return o.cachedSourcePriceRegistryAddress.Get(ctx, func(ctx context.Context) (cciptypes.Address, error) {
+ c, err := o.GetDynamicConfig(ctx)
+ if err != nil {
+ return "", err
+ }
+ return c.PriceRegistry, nil
+ })
+}
+
+func (o *OnRamp) GetSendRequestsBetweenSeqNums(ctx context.Context, seqNumMin, seqNumMax uint64, finalized bool) ([]cciptypes.EVM2EVMMessageWithTxMeta, error) {
+ logs, err := o.lp.LogsDataWordRange(
+ ctx,
+ o.sendRequestedEventSig,
+ o.address,
+ o.sendRequestedSeqNumberWord,
+ logpoller.EvmWord(seqNumMin),
+ logpoller.EvmWord(seqNumMax),
+ ccipdata.LogsConfirmations(finalized),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.EVM2EVMMessage](logs, o.lggr, o.logToMessage)
+ if err != nil {
+ return nil, err
+ }
+
+ res := make([]cciptypes.EVM2EVMMessageWithTxMeta, 0, len(logs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.EVM2EVMMessageWithTxMeta{
+ TxMeta: log.TxMeta,
+ EVM2EVMMessage: log.Data,
+ })
+ }
+
+ return res, nil
+}
+
+func (o *OnRamp) RouterAddress(context.Context) (cciptypes.Address, error) {
+ config, err := o.onRamp.GetDynamicConfig(nil)
+ if err != nil {
+ return "", err
+ }
+ return cciptypes.Address(config.Router.String()), nil
+}
+
+func (o *OnRamp) IsSourceChainHealthy(context.Context) (bool, error) {
+ if err := o.lp.Healthy(); err != nil {
+ return false, nil
+ }
+ return true, nil
+}
+
+func (o *OnRamp) IsSourceCursed(ctx context.Context) (bool, error) {
+ arm, err := o.cachedRmnContract(ctx)
+ if err != nil {
+ return false, fmt.Errorf("intializing Arm contract through the ArmProxy: %w", err)
+ }
+
+ cursed, err := arm.IsCursed0(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return false, fmt.Errorf("checking if source Arm is cursed: %w", err)
+ }
+ return cursed, nil
+}
+
+func (o *OnRamp) Close() error {
+ return logpollerutil.UnregisterLpFilters(o.lp, o.filters)
+}
+
+func (o *OnRamp) RegisterFilters() error {
+ return logpollerutil.RegisterLpFilters(o.lp, o.filters)
+}
+
+func (o *OnRamp) logToMessage(log types.Log) (*cciptypes.EVM2EVMMessage, error) {
+ msg, err := o.onRamp.ParseCCIPSendRequested(log)
+ if err != nil {
+ return nil, err
+ }
+ h, err := o.leafHasher.HashLeaf(log)
+ if err != nil {
+ return nil, err
+ }
+ tokensAndAmounts := make([]cciptypes.TokenAmount, len(msg.Message.TokenAmounts))
+ for i, tokenAndAmount := range msg.Message.TokenAmounts {
+ tokensAndAmounts[i] = cciptypes.TokenAmount{
+ Token: cciptypes.Address(tokenAndAmount.Token.String()),
+ Amount: tokenAndAmount.Amount,
+ }
+ }
+
+ return &cciptypes.EVM2EVMMessage{
+ SequenceNumber: msg.Message.SequenceNumber,
+ GasLimit: msg.Message.GasLimit,
+ Nonce: msg.Message.Nonce,
+ MessageID: msg.Message.MessageId,
+ SourceChainSelector: msg.Message.SourceChainSelector,
+ Sender: cciptypes.Address(msg.Message.Sender.String()),
+ Receiver: cciptypes.Address(msg.Message.Receiver.String()),
+ Strict: msg.Message.Strict,
+ FeeToken: cciptypes.Address(msg.Message.FeeToken.String()),
+ FeeTokenAmount: msg.Message.FeeTokenAmount,
+ Data: msg.Message.Data,
+ TokenAmounts: tokensAndAmounts,
+ SourceTokenData: msg.Message.SourceTokenData, // Breaking change 1.2
+ Hash: h,
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/onramp_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/onramp_test.go
new file mode 100644
index 00000000000..bbdf52e23a4
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/onramp_test.go
@@ -0,0 +1,58 @@
+package v1_2_0
+
+import (
+ "context"
+ "testing"
+
+ "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/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ 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/services/ocr2/plugins/ccip/abihelpers"
+)
+
+func TestLogPollerClient_GetSendRequestsBetweenSeqNumsV1_2_0(t *testing.T) {
+ onRampAddr := utils.RandomAddress()
+ seqNum := uint64(100)
+ limit := uint64(10)
+ lggr := logger.Test(t)
+
+ tests := []struct {
+ name string
+ finalized bool
+ confirmations evmtypes.Confirmations
+ }{
+ {"finalized", true, evmtypes.Finalized},
+ {"unfinalized", false, evmtypes.Confirmations(0)},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ lp := mocks.NewLogPoller(t)
+ onRampV2, err := NewOnRamp(lggr, 1, 1, onRampAddr, lp, nil)
+ require.NoError(t, err)
+
+ lp.On("LogsDataWordRange",
+ mock.Anything,
+ onRampV2.sendRequestedEventSig,
+ onRampAddr,
+ onRampV2.sendRequestedSeqNumberWord,
+ abihelpers.EvmWord(seqNum),
+ abihelpers.EvmWord(seqNum+limit),
+ tt.confirmations,
+ ).Once().Return([]logpoller.Log{}, nil)
+
+ events, err1 := onRampV2.GetSendRequestsBetweenSeqNums(context.Background(), seqNum, seqNum+limit, tt.finalized)
+ assert.NoError(t, err1)
+ assert.Empty(t, events)
+
+ lp.AssertExpectations(t)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/price_registry.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/price_registry.go
new file mode 100644
index 00000000000..df958233779
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/price_registry.go
@@ -0,0 +1,69 @@
+package v1_2_0
+
+import (
+ "context"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+)
+
+var (
+ _ ccipdata.PriceRegistryReader = &PriceRegistry{}
+)
+
+type PriceRegistry struct {
+ *v1_0_0.PriceRegistry
+ pr *price_registry_1_2_0.PriceRegistry
+}
+
+func NewPriceRegistry(lggr logger.Logger, priceRegistryAddr common.Address, lp logpoller.LogPoller, ec client.Client, registerFilters bool) (*PriceRegistry, error) {
+ v100, err := v1_0_0.NewPriceRegistry(lggr, priceRegistryAddr, lp, ec, registerFilters)
+ if err != nil {
+ return nil, err
+ }
+ priceRegistry, err := price_registry_1_2_0.NewPriceRegistry(priceRegistryAddr, ec)
+ if err != nil {
+ return nil, err
+ }
+ return &PriceRegistry{
+ PriceRegistry: v100,
+ pr: priceRegistry,
+ }, nil
+}
+
+// GetTokenPrices must be overridden to use the 1.2 ABI (return parameter changed from uint192 to uint224)
+// See https://github.com/smartcontractkit/ccip/blob/ccip-develop/contracts/src/v0.8/ccip/PriceRegistry.sol#L141
+func (p *PriceRegistry) GetTokenPrices(ctx context.Context, wantedTokens []cciptypes.Address) ([]cciptypes.TokenPriceUpdate, error) {
+ evmAddrs, err := ccipcalc.GenericAddrsToEvm(wantedTokens...)
+ if err != nil {
+ return nil, err
+ }
+
+ // Make call using 224 ABI.
+ tps, err := p.pr.GetTokenPrices(&bind.CallOpts{Context: ctx}, evmAddrs)
+ if err != nil {
+ return nil, err
+ }
+ var tpu []cciptypes.TokenPriceUpdate
+ for i, tp := range tps {
+ tpu = append(tpu, cciptypes.TokenPriceUpdate{
+ TokenPrice: cciptypes.TokenPrice{
+ Token: wantedTokens[i],
+ Value: tp.Value,
+ },
+ TimestampUnixSec: big.NewInt(int64(tp.Timestamp)),
+ })
+ }
+ return tpu, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/test_helpers.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/test_helpers.go
new file mode 100644
index 00000000000..e7972d5f5fe
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/test_helpers.go
@@ -0,0 +1,48 @@
+package v1_2_0
+
+import (
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+// ApplyPriceRegistryUpdate is a helper function used in tests only.
+func ApplyPriceRegistryUpdate(t *testing.T, user *bind.TransactOpts, addr common.Address, ec client.Client, gasPrices []cciptypes.GasPrice, tokenPrices []cciptypes.TokenPrice) common.Hash {
+ require.True(t, len(gasPrices) <= 2)
+ pr, err := price_registry.NewPriceRegistry(addr, ec)
+ require.NoError(t, err)
+ o, err := pr.Owner(nil)
+ require.NoError(t, err)
+ require.Equal(t, user.From, o)
+ var tps []price_registry.InternalTokenPriceUpdate
+ for _, tp := range tokenPrices {
+ evmAddrs, err1 := ccipcalc.GenericAddrsToEvm(tp.Token)
+ assert.NoError(t, err1)
+ tps = append(tps, price_registry.InternalTokenPriceUpdate{
+ SourceToken: evmAddrs[0],
+ UsdPerToken: tp.Value,
+ })
+ }
+ var gps []price_registry.InternalGasPriceUpdate
+ for _, gp := range gasPrices {
+ gps = append(gps, price_registry.InternalGasPriceUpdate{
+ DestChainSelector: gp.DestChainSelector,
+ UsdPerUnitGas: gp.Value,
+ })
+ }
+ tx, err := pr.UpdatePrices(user, price_registry.InternalPriceUpdates{
+ TokenPriceUpdates: tps,
+ GasPriceUpdates: gps,
+ })
+ require.NoError(t, err)
+ return tx.Hash()
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/token_pool.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/token_pool.go
new file mode 100644
index 00000000000..a0850ebb2e9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/token_pool.go
@@ -0,0 +1,48 @@
+package v1_2_0
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+var (
+ poolABI = abihelpers.MustParseABI(burn_mint_token_pool_1_2_0.BurnMintTokenPoolABI)
+)
+
+var _ ccipdata.TokenPoolReader = &TokenPool{}
+
+type TokenPool struct {
+ addr common.Address
+ OffRampAddress common.Address
+ poolType string
+}
+
+func NewTokenPool(poolType string, addr common.Address, offRampAddress common.Address) *TokenPool {
+ return &TokenPool{
+ addr: addr,
+ OffRampAddress: offRampAddress,
+ poolType: poolType,
+ }
+}
+
+func (p *TokenPool) Address() common.Address {
+ return p.addr
+}
+
+func (p *TokenPool) Type() string {
+ return p.poolType
+}
+
+func GetInboundTokenPoolRateLimitCall(tokenPoolAddress common.Address, offRampAddress common.Address) rpclib.EvmCall {
+ return rpclib.NewEvmCall(
+ poolABI,
+ "currentOffRampRateLimiterState",
+ tokenPoolAddress,
+ offRampAddress,
+ )
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/token_pool_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/token_pool_test.go
new file mode 100644
index 00000000000..3308ab05cec
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0/token_pool_test.go
@@ -0,0 +1,24 @@
+package v1_2_0
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+)
+
+func TestTokenPool(t *testing.T) {
+ addr := utils.RandomAddress()
+ offRamp := utils.RandomAddress()
+ poolType := "BurnMint"
+
+ tokenPool := NewTokenPool(poolType, addr, offRamp)
+
+ assert.Equal(t, addr, tokenPool.Address())
+ assert.Equal(t, poolType, tokenPool.Type())
+
+ inboundRateLimitCall := GetInboundTokenPoolRateLimitCall(addr, offRamp)
+
+ assert.Equal(t, "currentOffRampRateLimiterState", inboundRateLimitCall.MethodName())
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_4_0/token_pool.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_4_0/token_pool.go
new file mode 100644
index 00000000000..caf652b9e4e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_4_0/token_pool.go
@@ -0,0 +1,48 @@
+package v1_4_0
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+var (
+ poolABI = abihelpers.MustParseABI(burn_mint_token_pool_1_4_0.BurnMintTokenPoolABI)
+)
+
+var _ ccipdata.TokenPoolReader = &TokenPool{}
+
+type TokenPool struct {
+ addr common.Address
+ RemoteChainSelector uint64
+ poolType string
+}
+
+func NewTokenPool(poolType string, addr common.Address, remoteChainSelector uint64) *TokenPool {
+ return &TokenPool{
+ addr: addr,
+ RemoteChainSelector: remoteChainSelector,
+ poolType: poolType,
+ }
+}
+
+func (p *TokenPool) Address() common.Address {
+ return p.addr
+}
+
+func (p *TokenPool) Type() string {
+ return p.poolType
+}
+
+func GetInboundTokenPoolRateLimitCall(tokenPoolAddress common.Address, remoteChainSelector uint64) rpclib.EvmCall {
+ return rpclib.NewEvmCall(
+ poolABI,
+ "getCurrentInboundRateLimiterState",
+ tokenPoolAddress,
+ remoteChainSelector,
+ )
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_4_0/token_pool_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_4_0/token_pool_test.go
new file mode 100644
index 00000000000..8aaddc3312e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_4_0/token_pool_test.go
@@ -0,0 +1,24 @@
+package v1_4_0
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+)
+
+func TestTokenPool(t *testing.T) {
+ addr := utils.RandomAddress()
+ chainSelector := uint64(2000)
+ poolType := "BurnMint"
+
+ tokenPool := NewTokenPool(poolType, addr, chainSelector)
+
+ assert.Equal(t, addr, tokenPool.Address())
+ assert.Equal(t, poolType, tokenPool.Type())
+
+ inboundRateLimitCall := GetInboundTokenPoolRateLimitCall(addr, chainSelector)
+
+ assert.Equal(t, "getCurrentInboundRateLimiterState", inboundRateLimitCall.MethodName())
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/commit_store.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/commit_store.go
new file mode 100644
index 00000000000..fd768d4235c
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/commit_store.go
@@ -0,0 +1,59 @@
+package v1_5_0
+
+import (
+ "context"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+)
+
+type CommitStore struct {
+ *v1_2_0.CommitStore
+ commitStore *commit_store.CommitStore
+}
+
+func (c *CommitStore) GetCommitStoreStaticConfig(ctx context.Context) (cciptypes.CommitStoreStaticConfig, error) {
+ staticConfig, err := c.commitStore.GetStaticConfig(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return cciptypes.CommitStoreStaticConfig{}, err
+ }
+ return cciptypes.CommitStoreStaticConfig{
+ ChainSelector: staticConfig.ChainSelector,
+ SourceChainSelector: staticConfig.SourceChainSelector,
+ OnRamp: cciptypes.Address(staticConfig.OnRamp.String()),
+ ArmProxy: cciptypes.Address(staticConfig.RmnProxy.String()),
+ }, nil
+}
+
+func (c *CommitStore) IsDown(ctx context.Context) (bool, error) {
+ unPausedAndNotCursed, err := c.commitStore.IsUnpausedAndNotCursed(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return true, err
+ }
+ return !unPausedAndNotCursed, nil
+}
+
+func NewCommitStore(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller) (*CommitStore, error) {
+ v120, err := v1_2_0.NewCommitStore(lggr, addr, ec, lp)
+ if err != nil {
+ return nil, err
+ }
+
+ commitStore, err := commit_store.NewCommitStore(addr, ec)
+ if err != nil {
+ return nil, err
+ }
+
+ return &CommitStore{
+ commitStore: commitStore,
+ CommitStore: v120,
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/hasher.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/hasher.go
new file mode 100644
index 00000000000..a00ec376cdb
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/hasher.go
@@ -0,0 +1,101 @@
+package v1_5_0
+
+import (
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+)
+
+const (
+ MetaDataHashPrefix = "EVM2EVMMessageHashV2"
+)
+
+type LeafHasher struct {
+ metaDataHash [32]byte
+ ctx hashutil.Hasher[[32]byte]
+ onRamp *evm_2_evm_onramp.EVM2EVMOnRamp
+}
+
+func NewLeafHasher(sourceChainSelector uint64, destChainSelector uint64, onRampId common.Address, ctx hashutil.Hasher[[32]byte], onRamp *evm_2_evm_onramp.EVM2EVMOnRamp) *LeafHasher {
+ return &LeafHasher{
+ metaDataHash: v1_0_0.GetMetaDataHash(ctx, ctx.Hash([]byte(MetaDataHashPrefix)), sourceChainSelector, onRampId, destChainSelector),
+ ctx: ctx,
+ onRamp: onRamp,
+ }
+}
+
+func (t *LeafHasher) HashLeaf(log types.Log) ([32]byte, error) {
+ msg, err := t.onRamp.ParseCCIPSendRequested(log)
+ if err != nil {
+ return [32]byte{}, err
+ }
+ message := msg.Message
+ encodedTokens, err := abihelpers.ABIEncode(
+ `[
+{"components": [{"name":"token","type":"address"},{"name":"amount","type":"uint256"}], "type":"tuple[]"}]`, message.TokenAmounts)
+ if err != nil {
+ return [32]byte{}, err
+ }
+
+ bytesArray, err := abi.NewType("bytes[]", "bytes[]", nil)
+ if err != nil {
+ return [32]byte{}, err
+ }
+
+ encodedSourceTokenData, err := abi.Arguments{abi.Argument{Type: bytesArray}}.PackValues([]interface{}{message.SourceTokenData})
+ if err != nil {
+ return [32]byte{}, err
+ }
+
+ packedFixedSizeValues, err := abihelpers.ABIEncode(
+ `[
+{"name": "sender", "type":"address"},
+{"name": "receiver", "type":"address"},
+{"name": "sequenceNumber", "type":"uint64"},
+{"name": "gasLimit", "type":"uint256"},
+{"name": "strict", "type":"bool"},
+{"name": "nonce", "type":"uint64"},
+{"name": "feeToken","type": "address"},
+{"name": "feeTokenAmount","type": "uint256"}
+]`,
+ message.Sender,
+ message.Receiver,
+ message.SequenceNumber,
+ message.GasLimit,
+ message.Strict,
+ message.Nonce,
+ message.FeeToken,
+ message.FeeTokenAmount,
+ )
+ if err != nil {
+ return [32]byte{}, err
+ }
+ fixedSizeValuesHash := t.ctx.Hash(packedFixedSizeValues)
+
+ packedValues, err := abihelpers.ABIEncode(
+ `[
+{"name": "leafDomainSeparator","type":"bytes1"},
+{"name": "metadataHash", "type":"bytes32"},
+{"name": "fixedSizeValuesHash", "type":"bytes32"},
+{"name": "dataHash", "type":"bytes32"},
+{"name": "tokenAmountsHash", "type":"bytes32"},
+{"name": "sourceTokenDataHash", "type":"bytes32"}
+]`,
+ v1_0_0.LeafDomainSeparator,
+ t.metaDataHash,
+ fixedSizeValuesHash,
+ t.ctx.Hash(message.Data),
+ t.ctx.Hash(encodedTokens),
+ t.ctx.Hash(encodedSourceTokenData),
+ )
+ if err != nil {
+ return [32]byte{}, err
+ }
+ return t.ctx.Hash(packedValues), nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/hasher_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/hasher_test.go
new file mode 100644
index 00000000000..2a585f7bd1e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/hasher_test.go
@@ -0,0 +1,78 @@
+package v1_5_0
+
+import (
+ "encoding/hex"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+func TestHasherV1_4_0(t *testing.T) {
+ sourceChainSelector, destChainSelector := uint64(1), uint64(4)
+ onRampAddress := common.HexToAddress("0x5550000000000000000000000000000000000001")
+ onRampABI := abihelpers.MustParseABI(evm_2_evm_onramp.EVM2EVMOnRampABI)
+
+ hashingCtx := hashutil.NewKeccak()
+ ramp, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(onRampAddress, nil)
+ require.NoError(t, err)
+ hasher := NewLeafHasher(sourceChainSelector, destChainSelector, onRampAddress, hashingCtx, ramp)
+
+ message := evm_2_evm_onramp.InternalEVM2EVMMessage{
+ SourceChainSelector: sourceChainSelector,
+ Sender: common.HexToAddress("0x1110000000000000000000000000000000000001"),
+ Receiver: common.HexToAddress("0x2220000000000000000000000000000000000001"),
+ SequenceNumber: 1337,
+ GasLimit: big.NewInt(100),
+ Strict: false,
+ Nonce: 1337,
+ FeeToken: common.Address{},
+ FeeTokenAmount: big.NewInt(1),
+ Data: []byte{},
+ TokenAmounts: []evm_2_evm_onramp.ClientEVMTokenAmount{{Token: common.HexToAddress("0x4440000000000000000000000000000000000001"), Amount: big.NewInt(12345678900)}},
+ SourceTokenData: [][]byte{},
+ MessageId: [32]byte{},
+ }
+
+ data, err := onRampABI.Events[CCIPSendRequestedEventName].Inputs.Pack(message)
+ require.NoError(t, err)
+ hash, err := hasher.HashLeaf(types.Log{Topics: []common.Hash{CCIPSendRequestEventSig}, Data: data})
+ require.NoError(t, err)
+
+ // NOTE: Must match spec
+ require.Equal(t, "46ad031bfb052db2e4a2514fed8dc480b98e5ce4acb55d5640d91407e0d8a3e9", hex.EncodeToString(hash[:]))
+
+ message = evm_2_evm_onramp.InternalEVM2EVMMessage{
+ SourceChainSelector: sourceChainSelector,
+ Sender: common.HexToAddress("0x1110000000000000000000000000000000000001"),
+ Receiver: common.HexToAddress("0x2220000000000000000000000000000000000001"),
+ SequenceNumber: 1337,
+ GasLimit: big.NewInt(100),
+ Strict: false,
+ Nonce: 1337,
+ FeeToken: common.Address{},
+ FeeTokenAmount: big.NewInt(1e12),
+ Data: []byte("foo bar baz"),
+ TokenAmounts: []evm_2_evm_onramp.ClientEVMTokenAmount{
+ {Token: common.HexToAddress("0x4440000000000000000000000000000000000001"), Amount: big.NewInt(12345678900)},
+ {Token: common.HexToAddress("0x6660000000000000000000000000000000000001"), Amount: big.NewInt(4204242)},
+ },
+ SourceTokenData: [][]byte{{0x2, 0x1}},
+ MessageId: [32]byte{},
+ }
+
+ data, err = onRampABI.Events[CCIPSendRequestedEventName].Inputs.Pack(message)
+ require.NoError(t, err)
+ hash, err = hasher.HashLeaf(types.Log{Topics: []common.Hash{CCIPSendRequestEventSig}, Data: data})
+ require.NoError(t, err)
+
+ // NOTE: Must match spec
+ require.Equal(t, "4362a13a42e52ff5ce4324e7184dc7aa41704c3146bc842d35d95b94b32a78b6", hex.EncodeToString(hash[:]))
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp.go
new file mode 100644
index 00000000000..2db9498de9d
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp.go
@@ -0,0 +1,199 @@
+package v1_5_0
+
+import (
+ "context"
+ "math/big"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+var (
+ abiOffRamp = abihelpers.MustParseABI(evm_2_evm_offramp.EVM2EVMOffRampABI)
+ _ ccipdata.OffRampReader = &OffRamp{}
+ RateLimitTokenAddedEvent = abihelpers.MustGetEventID("TokenAggregateRateLimitAdded", abiOffRamp)
+ RateLimitTokenRemovedEvent = abihelpers.MustGetEventID("TokenAggregateRateLimitRemoved", abiOffRamp)
+)
+
+type ExecOnchainConfig evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig
+
+func (d ExecOnchainConfig) AbiString() string {
+ return `
+ [
+ {
+ "components": [
+ {"name": "permissionLessExecutionThresholdSeconds", "type": "uint32"},
+ {"name": "maxDataBytes", "type": "uint32"},
+ {"name": "maxNumberOfTokensPerMsg", "type": "uint16"},
+ {"name": "router", "type": "address"},
+ {"name": "priceRegistry", "type": "address"},
+ {"name": "maxPoolReleaseOrMintGas", "type": "uint32"},
+ {"name": "maxTokenTransferGas", "type": "uint32"}
+ ],
+ "type": "tuple"
+ }
+ ]`
+}
+
+func (d ExecOnchainConfig) Validate() error {
+ if d.PermissionLessExecutionThresholdSeconds == 0 {
+ return errors.New("must set PermissionLessExecutionThresholdSeconds")
+ }
+ if d.Router == (common.Address{}) {
+ return errors.New("must set Router address")
+ }
+ if d.PriceRegistry == (common.Address{}) {
+ return errors.New("must set PriceRegistry address")
+ }
+ if d.MaxNumberOfTokensPerMsg == 0 {
+ return errors.New("must set MaxNumberOfTokensPerMsg")
+ }
+ if d.MaxPoolReleaseOrMintGas == 0 {
+ return errors.New("must set MaxPoolReleaseOrMintGas")
+ }
+ if d.MaxTokenTransferGas == 0 {
+ return errors.New("must set MaxTokenTransferGas")
+ }
+ return nil
+}
+
+type OffRamp struct {
+ *v1_2_0.OffRamp
+ offRampV150 evm_2_evm_offramp.EVM2EVMOffRampInterface
+ cachedRateLimitTokens cache.AutoSync[cciptypes.OffRampTokens]
+}
+
+// GetTokens Returns no data as the offRamps no longer have this information.
+func (o *OffRamp) GetTokens(ctx context.Context) (cciptypes.OffRampTokens, error) {
+ sourceTokens, destTokens, err := o.GetSourceAndDestRateLimitTokens(ctx)
+ if err != nil {
+ return cciptypes.OffRampTokens{}, err
+ }
+ return cciptypes.OffRampTokens{
+ SourceTokens: sourceTokens,
+ DestinationTokens: destTokens,
+ }, nil
+}
+
+func (o *OffRamp) GetSourceAndDestRateLimitTokens(ctx context.Context) (sourceTokens []cciptypes.Address, destTokens []cciptypes.Address, err error) {
+ cachedTokens, err := o.cachedRateLimitTokens.Get(ctx, func(ctx context.Context) (cciptypes.OffRampTokens, error) {
+ tokens, err2 := o.offRampV150.GetAllRateLimitTokens(&bind.CallOpts{Context: ctx})
+ if err2 != nil {
+ return cciptypes.OffRampTokens{}, err2
+ }
+
+ if len(tokens.SourceTokens) != len(tokens.DestTokens) {
+ return cciptypes.OffRampTokens{}, errors.New("source and destination tokens are not the same length")
+ }
+
+ return cciptypes.OffRampTokens{
+ DestinationTokens: ccipcalc.EvmAddrsToGeneric(tokens.DestTokens...),
+ SourceTokens: ccipcalc.EvmAddrsToGeneric(tokens.SourceTokens...),
+ }, nil
+ })
+ if err != nil {
+ return nil, nil, errors.Wrap(err, "failed to get rate limit tokens, if token set is large (~400k) batching may be needed")
+ }
+ return cachedTokens.SourceTokens, cachedTokens.DestinationTokens, nil
+}
+
+func (o *OffRamp) GetSourceToDestTokensMapping(ctx context.Context) (map[cciptypes.Address]cciptypes.Address, error) {
+ sourceTokens, destTokens, err := o.GetSourceAndDestRateLimitTokens(ctx)
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to get rate limit tokens, if token set is large (~400k) batching may be needed")
+ }
+
+ if sourceTokens == nil || destTokens == nil {
+ return nil, errors.New("source or destination tokens are nil")
+ }
+
+ mapping := make(map[cciptypes.Address]cciptypes.Address)
+ for i, sourceToken := range sourceTokens {
+ mapping[sourceToken] = destTokens[i]
+ }
+ return mapping, nil
+}
+
+func (o *OffRamp) ChangeConfig(ctx context.Context, onchainConfigBytes []byte, offchainConfigBytes []byte) (cciptypes.Address, cciptypes.Address, error) {
+ // Same as the v1.2.0 method, except for the ExecOnchainConfig type.
+ onchainConfigParsed, err := abihelpers.DecodeAbiStruct[ExecOnchainConfig](onchainConfigBytes)
+ if err != nil {
+ return "", "", err
+ }
+
+ offchainConfigParsed, err := ccipconfig.DecodeOffchainConfig[v1_2_0.JSONExecOffchainConfig](offchainConfigBytes)
+ if err != nil {
+ return "", "", err
+ }
+ destRouter, err := router.NewRouter(onchainConfigParsed.Router, o.Client)
+ if err != nil {
+ return "", "", err
+ }
+ destWrappedNative, err := destRouter.GetWrappedNative(nil)
+ if err != nil {
+ return "", "", err
+ }
+ offchainConfig := cciptypes.ExecOffchainConfig{
+ DestOptimisticConfirmations: offchainConfigParsed.DestOptimisticConfirmations,
+ BatchGasLimit: offchainConfigParsed.BatchGasLimit,
+ RelativeBoostPerWaitHour: offchainConfigParsed.RelativeBoostPerWaitHour,
+ InflightCacheExpiry: offchainConfigParsed.InflightCacheExpiry,
+ RootSnoozeTime: offchainConfigParsed.RootSnoozeTime,
+ MessageVisibilityInterval: offchainConfigParsed.MessageVisibilityInterval,
+ BatchingStrategyID: offchainConfigParsed.BatchingStrategyID,
+ }
+ onchainConfig := cciptypes.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: time.Second * time.Duration(onchainConfigParsed.PermissionLessExecutionThresholdSeconds),
+ Router: cciptypes.Address(onchainConfigParsed.Router.String()),
+ }
+ priceEstimator := prices.NewDAGasPriceEstimator(o.Estimator, o.DestMaxGasPrice, 0, 0)
+
+ o.UpdateDynamicConfig(onchainConfig, offchainConfig, priceEstimator)
+
+ o.Logger.Infow("Starting exec plugin",
+ "offchainConfig", onchainConfigParsed,
+ "onchainConfig", offchainConfigParsed)
+ return cciptypes.Address(onchainConfigParsed.PriceRegistry.String()),
+ cciptypes.Address(destWrappedNative.String()), nil
+}
+
+func NewOffRamp(lggr logger.Logger, addr common.Address, ec client.Client, lp logpoller.LogPoller, estimator gas.EvmFeeEstimator, destMaxGasPrice *big.Int) (*OffRamp, error) {
+ v120, err := v1_2_0.NewOffRamp(lggr, addr, ec, lp, estimator, destMaxGasPrice)
+ if err != nil {
+ return nil, err
+ }
+
+ offRamp, err := evm_2_evm_offramp.NewEVM2EVMOffRamp(addr, ec)
+ if err != nil {
+ return nil, err
+ }
+
+ v120.ExecutionReportArgs = abihelpers.MustGetMethodInputs("manuallyExecute", abiOffRamp)[:1]
+
+ return &OffRamp{
+ OffRamp: v120,
+ offRampV150: offRamp,
+ cachedRateLimitTokens: cache.NewLogpollerEventsBased[cciptypes.OffRampTokens](
+ lp,
+ []common.Hash{RateLimitTokenAddedEvent, RateLimitTokenRemovedEvent},
+ offRamp.Address(),
+ ),
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp_test.go
new file mode 100644
index 00000000000..a95445ec028
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/offramp_test.go
@@ -0,0 +1 @@
+package v1_5_0
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/onramp.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/onramp.go
new file mode 100644
index 00000000000..d07fa7bb617
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/onramp.go
@@ -0,0 +1,259 @@
+package v1_5_0
+
+import (
+ "context"
+ "fmt"
+ "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"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/logpollerutil"
+)
+
+var (
+ // Backwards compat for integration tests
+ CCIPSendRequestEventSig common.Hash
+ ConfigSetEventSig common.Hash
+)
+
+const (
+ CCIPSendRequestSeqNumIndex = 4
+ CCIPSendRequestedEventName = "CCIPSendRequested"
+ ConfigSetEventName = "ConfigSet"
+)
+
+func init() {
+ onRampABI, err := abi.JSON(strings.NewReader(evm_2_evm_onramp.EVM2EVMOnRampABI))
+ if err != nil {
+ panic(err)
+ }
+ CCIPSendRequestEventSig = abihelpers.MustGetEventID(CCIPSendRequestedEventName, onRampABI)
+ ConfigSetEventSig = abihelpers.MustGetEventID(ConfigSetEventName, onRampABI)
+}
+
+var _ ccipdata.OnRampReader = &OnRamp{}
+
+type OnRamp struct {
+ onRamp *evm_2_evm_onramp.EVM2EVMOnRamp
+ address common.Address
+ destChainSelectorBytes [16]byte
+ lggr logger.Logger
+ lp logpoller.LogPoller
+ leafHasher ccipdata.LeafHasherInterface[[32]byte]
+ client client.Client
+ sendRequestedEventSig common.Hash
+ sendRequestedSeqNumberWord int
+ filters []logpoller.Filter
+ cachedSourcePriceRegistryAddress cache.AutoSync[cciptypes.Address]
+ // Static config can be cached, because it's never expected to change.
+ // The only way to change that is through the contract's constructor (redeployment)
+ cachedStaticConfig cache.OnceCtxFunction[evm_2_evm_onramp.EVM2EVMOnRampStaticConfig]
+ cachedRmnContract cache.OnceCtxFunction[*arm_contract.ARMContract]
+}
+
+func NewOnRamp(lggr logger.Logger, sourceSelector, destSelector uint64, onRampAddress common.Address, sourceLP logpoller.LogPoller, source client.Client) (*OnRamp, error) {
+ onRamp, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(onRampAddress, source)
+ if err != nil {
+ return nil, err
+ }
+
+ // Subscribe to the relevant logs
+ // Note we can keep the same prefix across 1.0/1.1 and 1.2 because the onramp addresses will be different
+ filters := []logpoller.Filter{
+ {
+ Name: logpoller.FilterName(ccipdata.COMMIT_CCIP_SENDS, onRampAddress),
+ EventSigs: []common.Hash{CCIPSendRequestEventSig},
+ Addresses: []common.Address{onRampAddress},
+ Retention: ccipdata.CommitExecLogsRetention,
+ },
+ {
+ Name: logpoller.FilterName(ccipdata.CONFIG_CHANGED, onRampAddress),
+ EventSigs: []common.Hash{ConfigSetEventSig},
+ Addresses: []common.Address{onRampAddress},
+ Retention: ccipdata.CacheEvictionLogsRetention,
+ },
+ }
+ cachedStaticConfig := cache.OnceCtxFunction[evm_2_evm_onramp.EVM2EVMOnRampStaticConfig](func(ctx context.Context) (evm_2_evm_onramp.EVM2EVMOnRampStaticConfig, error) {
+ return onRamp.GetStaticConfig(&bind.CallOpts{Context: ctx})
+ })
+ cachedRmnContract := cache.OnceCtxFunction[*arm_contract.ARMContract](func(ctx context.Context) (*arm_contract.ARMContract, error) {
+ staticConfig, err := cachedStaticConfig(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return arm_contract.NewARMContract(staticConfig.RmnProxy, source)
+ })
+
+ return &OnRamp{
+ lggr: lggr,
+ client: source,
+ destChainSelectorBytes: ccipcommon.SelectorToBytes(destSelector),
+ lp: sourceLP,
+ leafHasher: NewLeafHasher(sourceSelector, destSelector, onRampAddress, hashutil.NewKeccak(), onRamp),
+ onRamp: onRamp,
+ filters: filters,
+ address: onRampAddress,
+ sendRequestedSeqNumberWord: CCIPSendRequestSeqNumIndex,
+ sendRequestedEventSig: CCIPSendRequestEventSig,
+ cachedSourcePriceRegistryAddress: cache.NewLogpollerEventsBased[cciptypes.Address](
+ sourceLP,
+ []common.Hash{ConfigSetEventSig},
+ onRampAddress,
+ ),
+ cachedStaticConfig: cache.CallOnceOnNoError(cachedStaticConfig),
+ cachedRmnContract: cache.CallOnceOnNoError(cachedRmnContract),
+ }, nil
+}
+
+func (o *OnRamp) Address(context.Context) (cciptypes.Address, error) {
+ return ccipcalc.EvmAddrToGeneric(o.onRamp.Address()), nil
+}
+
+func (o *OnRamp) GetDynamicConfig(context.Context) (cciptypes.OnRampDynamicConfig, error) {
+ if o.onRamp == nil {
+ return cciptypes.OnRampDynamicConfig{}, fmt.Errorf("onramp not initialized")
+ }
+ config, err := o.onRamp.GetDynamicConfig(&bind.CallOpts{})
+ if err != nil {
+ return cciptypes.OnRampDynamicConfig{}, fmt.Errorf("get dynamic config v1.5: %w", err)
+ }
+ return cciptypes.OnRampDynamicConfig{
+ Router: ccipcalc.EvmAddrToGeneric(config.Router),
+ MaxNumberOfTokensPerMsg: config.MaxNumberOfTokensPerMsg,
+ DestGasOverhead: config.DestGasOverhead,
+ DestGasPerPayloadByte: config.DestGasPerPayloadByte,
+ DestDataAvailabilityOverheadGas: config.DestDataAvailabilityOverheadGas,
+ DestGasPerDataAvailabilityByte: config.DestGasPerDataAvailabilityByte,
+ DestDataAvailabilityMultiplierBps: config.DestDataAvailabilityMultiplierBps,
+ PriceRegistry: ccipcalc.EvmAddrToGeneric(config.PriceRegistry),
+ MaxDataBytes: config.MaxDataBytes,
+ MaxPerMsgGasLimit: config.MaxPerMsgGasLimit,
+ }, nil
+}
+
+func (o *OnRamp) SourcePriceRegistryAddress(ctx context.Context) (cciptypes.Address, error) {
+ return o.cachedSourcePriceRegistryAddress.Get(ctx, func(ctx context.Context) (cciptypes.Address, error) {
+ c, err := o.GetDynamicConfig(ctx)
+ if err != nil {
+ return "", err
+ }
+ return c.PriceRegistry, nil
+ })
+}
+
+func (o *OnRamp) GetSendRequestsBetweenSeqNums(ctx context.Context, seqNumMin, seqNumMax uint64, finalized bool) ([]cciptypes.EVM2EVMMessageWithTxMeta, error) {
+ logs, err := o.lp.LogsDataWordRange(
+ ctx,
+ o.sendRequestedEventSig,
+ o.address,
+ o.sendRequestedSeqNumberWord,
+ logpoller.EvmWord(seqNumMin),
+ logpoller.EvmWord(seqNumMax),
+ ccipdata.LogsConfirmations(finalized),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ parsedLogs, err := ccipdata.ParseLogs[cciptypes.EVM2EVMMessage](logs, o.lggr, o.logToMessage)
+ if err != nil {
+ return nil, err
+ }
+
+ res := make([]cciptypes.EVM2EVMMessageWithTxMeta, 0, len(logs))
+ for _, log := range parsedLogs {
+ res = append(res, cciptypes.EVM2EVMMessageWithTxMeta{
+ TxMeta: log.TxMeta,
+ EVM2EVMMessage: log.Data,
+ })
+ }
+ return res, nil
+}
+
+func (o *OnRamp) RouterAddress(context.Context) (cciptypes.Address, error) {
+ config, err := o.onRamp.GetDynamicConfig(nil)
+ if err != nil {
+ return "", err
+ }
+ return ccipcalc.EvmAddrToGeneric(config.Router), nil
+}
+
+func (o *OnRamp) IsSourceChainHealthy(context.Context) (bool, error) {
+ if err := o.lp.Healthy(); err != nil {
+ return false, nil
+ }
+ return true, nil
+}
+
+func (o *OnRamp) IsSourceCursed(ctx context.Context) (bool, error) {
+ arm, err := o.cachedRmnContract(ctx)
+ if err != nil {
+ return false, fmt.Errorf("initializing RMN contract through the RmnProxy: %w", err)
+ }
+
+ cursed, err := arm.IsCursed(&bind.CallOpts{Context: ctx}, o.destChainSelectorBytes)
+ if err != nil {
+ return false, fmt.Errorf("checking if source is cursed by RMN: %w", err)
+ }
+ return cursed, nil
+}
+
+func (o *OnRamp) Close() error {
+ return logpollerutil.UnregisterLpFilters(o.lp, o.filters)
+}
+
+func (o *OnRamp) RegisterFilters() error {
+ return logpollerutil.RegisterLpFilters(o.lp, o.filters)
+}
+
+func (o *OnRamp) logToMessage(log types.Log) (*cciptypes.EVM2EVMMessage, error) {
+ msg, err := o.onRamp.ParseCCIPSendRequested(log)
+ if err != nil {
+ return nil, err
+ }
+ h, err := o.leafHasher.HashLeaf(log)
+ if err != nil {
+ return nil, err
+ }
+ tokensAndAmounts := make([]cciptypes.TokenAmount, len(msg.Message.TokenAmounts))
+ for i, tokenAndAmount := range msg.Message.TokenAmounts {
+ tokensAndAmounts[i] = cciptypes.TokenAmount{
+ Token: ccipcalc.EvmAddrToGeneric(tokenAndAmount.Token),
+ Amount: tokenAndAmount.Amount,
+ }
+ }
+
+ return &cciptypes.EVM2EVMMessage{
+ SequenceNumber: msg.Message.SequenceNumber,
+ GasLimit: msg.Message.GasLimit,
+ Nonce: msg.Message.Nonce,
+ MessageID: msg.Message.MessageId,
+ SourceChainSelector: msg.Message.SourceChainSelector,
+ Sender: ccipcalc.EvmAddrToGeneric(msg.Message.Sender),
+ Receiver: ccipcalc.EvmAddrToGeneric(msg.Message.Receiver),
+ Strict: msg.Message.Strict,
+ FeeToken: ccipcalc.EvmAddrToGeneric(msg.Message.FeeToken),
+ FeeTokenAmount: msg.Message.FeeTokenAmount,
+ Data: msg.Message.Data,
+ TokenAmounts: tokensAndAmounts,
+ SourceTokenData: msg.Message.SourceTokenData, // Breaking change 1.2
+ Hash: h,
+ }, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/onramp_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/onramp_test.go
new file mode 100644
index 00000000000..f072fc2b384
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0/onramp_test.go
@@ -0,0 +1,210 @@
+package v1_5_0
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "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/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ 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/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+func TestLogPollerClient_GetSendRequestsBetweenSeqNums1_4_0(t *testing.T) {
+ onRampAddr := utils.RandomAddress()
+ seqNum := uint64(100)
+ limit := uint64(10)
+ lggr := logger.Test(t)
+
+ tests := []struct {
+ name string
+ finalized bool
+ confirmations evmtypes.Confirmations
+ }{
+ {"finalized", true, evmtypes.Finalized},
+ {"unfinalized", false, evmtypes.Confirmations(0)},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ lp := mocks.NewLogPoller(t)
+ onRampV2, err := NewOnRamp(lggr, 1, 1, onRampAddr, lp, nil)
+ require.NoError(t, err)
+
+ lp.On("LogsDataWordRange",
+ mock.Anything,
+ onRampV2.sendRequestedEventSig,
+ onRampAddr,
+ onRampV2.sendRequestedSeqNumberWord,
+ abihelpers.EvmWord(seqNum),
+ abihelpers.EvmWord(seqNum+limit),
+ tt.confirmations,
+ ).Once().Return([]logpoller.Log{}, nil)
+
+ events, err1 := onRampV2.GetSendRequestsBetweenSeqNums(context.Background(), seqNum, seqNum+limit, tt.finalized)
+ assert.NoError(t, err1)
+ assert.Empty(t, events)
+
+ lp.AssertExpectations(t)
+ })
+ }
+}
+
+func Test_ProperlyRecognizesPerLaneCurses(t *testing.T) {
+ user, bc := ccipdata.NewSimulation(t)
+ ctx := testutils.Context(t)
+ destChainSelector := uint64(100)
+ sourceChainSelector := uint64(200)
+ onRampAddress, mockRMN, mockRMNAddress := setupOnRampV1_5_0(t, user, bc)
+
+ onRamp, err := NewOnRamp(logger.Test(t), 1, destChainSelector, onRampAddress, mocks.NewLogPoller(t), bc)
+ require.NoError(t, err)
+
+ onRamp.cachedStaticConfig = func(ctx context.Context) (evm_2_evm_onramp.EVM2EVMOnRampStaticConfig, error) {
+ return evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{
+ RmnProxy: mockRMNAddress,
+ }, nil
+ }
+
+ // Lane is not cursed right after deployment
+ isCursed, err := onRamp.IsSourceCursed(ctx)
+ require.NoError(t, err)
+ assert.False(t, isCursed)
+
+ // Cursing different chain selector
+ _, err = mockRMN.VoteToCurse0(user, [32]byte{}, ccipcommon.SelectorToBytes(sourceChainSelector))
+ require.NoError(t, err)
+ bc.Commit()
+
+ isCursed, err = onRamp.IsSourceCursed(ctx)
+ require.NoError(t, err)
+ assert.False(t, isCursed)
+
+ // Cursing the correct chain selector
+ _, err = mockRMN.VoteToCurse0(user, [32]byte{}, ccipcommon.SelectorToBytes(destChainSelector))
+ require.NoError(t, err)
+ bc.Commit()
+
+ isCursed, err = onRamp.IsSourceCursed(ctx)
+ require.NoError(t, err)
+ assert.True(t, isCursed)
+
+ // Uncursing the chain selector
+ _, err = mockRMN.OwnerUnvoteToCurse(user, []mock_arm_contract.RMNUnvoteToCurseRecord{}, ccipcommon.SelectorToBytes(destChainSelector))
+ require.NoError(t, err)
+ bc.Commit()
+
+ isCursed, err = onRamp.IsSourceCursed(ctx)
+ require.NoError(t, err)
+ assert.False(t, isCursed)
+}
+
+// This is written to benchmark before and after the caching of StaticConfig and RMNContract
+func BenchmarkIsSourceCursedWithCache(b *testing.B) {
+ user, bc := ccipdata.NewSimulation(b)
+ ctx := testutils.Context(b)
+ destChainSelector := uint64(100)
+ onRampAddress, _, _ := setupOnRampV1_5_0(b, user, bc)
+
+ onRamp, err := NewOnRamp(logger.Test(b), 1, destChainSelector, onRampAddress, mocks.NewLogPoller(b), bc)
+ require.NoError(b, err)
+
+ for i := 0; i < b.N; i++ {
+ _, _ = onRamp.IsSourceCursed(ctx)
+ }
+}
+
+func setupOnRampV1_5_0(t testing.TB, user *bind.TransactOpts, bc *client.SimulatedBackendClient) (common.Address, *mock_arm_contract.MockARMContract, common.Address) {
+ rmnAddress, transaction, rmnContract, err := mock_arm_contract.DeployMockARMContract(user, bc)
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, transaction, bc, user)
+
+ linkTokenAddress := common.HexToAddress("0x000011")
+ staticConfig := evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{
+ LinkToken: linkTokenAddress,
+ ChainSelector: testutils.SimulatedChainID.Uint64(),
+ DestChainSelector: testutils.SimulatedChainID.Uint64(),
+ DefaultTxGasLimit: 30000,
+ MaxNopFeesJuels: big.NewInt(1000000),
+ PrevOnRamp: common.Address{},
+ RmnProxy: rmnAddress,
+ TokenAdminRegistry: utils.RandomAddress(),
+ }
+ dynamicConfig := evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig{
+ Router: common.HexToAddress("0x0000000000000000000000000000000000000150"),
+ MaxNumberOfTokensPerMsg: 0,
+ DestGasOverhead: 0,
+ DestGasPerPayloadByte: 0,
+ DestDataAvailabilityOverheadGas: 0,
+ DestGasPerDataAvailabilityByte: 0,
+ DestDataAvailabilityMultiplierBps: 0,
+ PriceRegistry: utils.RandomAddress(),
+ MaxDataBytes: 0,
+ MaxPerMsgGasLimit: 0,
+ DefaultTokenFeeUSDCents: 50,
+ DefaultTokenDestGasOverhead: 34_000,
+ DefaultTokenDestBytesOverhead: 500,
+ }
+ rateLimiterConfig := evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(5),
+ Rate: big.NewInt(5),
+ }
+ feeTokenConfigs := []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: linkTokenAddress,
+ NetworkFeeUSDCents: 0,
+ GasMultiplierWeiPerEth: 0,
+ PremiumMultiplierWeiPerEth: 0,
+ Enabled: false,
+ },
+ }
+ tokenTransferConfigArgs := []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: linkTokenAddress,
+ MinFeeUSDCents: 0,
+ MaxFeeUSDCents: 0,
+ DeciBps: 0,
+ DestGasOverhead: 0,
+ DestBytesOverhead: 32,
+ AggregateRateLimitEnabled: true,
+ },
+ }
+ nopsAndWeights := []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{
+ {
+ Nop: utils.RandomAddress(),
+ Weight: 1,
+ },
+ }
+ onRampAddress, transaction, _, err := evm_2_evm_onramp.DeployEVM2EVMOnRamp(
+ user,
+ bc,
+ staticConfig,
+ dynamicConfig,
+ rateLimiterConfig,
+ feeTokenConfigs,
+ tokenTransferConfigArgs,
+ nopsAndWeights,
+ )
+ bc.Commit()
+ require.NoError(t, err)
+ ccipdata.AssertNonRevert(t, transaction, bc, user)
+
+ return onRampAddress, rmnContract, rmnAddress
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdb/mocks/price_service_mock.go b/core/services/ocr2/plugins/ccip/internal/ccipdb/mocks/price_service_mock.go
new file mode 100644
index 00000000000..39ba632aff9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdb/mocks/price_service_mock.go
@@ -0,0 +1,250 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ big "math/big"
+
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ ccipdata "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+
+ prices "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+// PriceService is an autogenerated mock type for the PriceService type
+type PriceService struct {
+ mock.Mock
+}
+
+type PriceService_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *PriceService) EXPECT() *PriceService_Expecter {
+ return &PriceService_Expecter{mock: &_m.Mock}
+}
+
+// Close provides a mock function with given fields:
+func (_m *PriceService) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// PriceService_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type PriceService_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *PriceService_Expecter) Close() *PriceService_Close_Call {
+ return &PriceService_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *PriceService_Close_Call) Run(run func()) *PriceService_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *PriceService_Close_Call) Return(_a0 error) *PriceService_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *PriceService_Close_Call) RunAndReturn(run func() error) *PriceService_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetGasAndTokenPrices provides a mock function with given fields: ctx, destChainSelector
+func (_m *PriceService) GetGasAndTokenPrices(ctx context.Context, destChainSelector uint64) (map[uint64]*big.Int, map[ccip.Address]*big.Int, error) {
+ ret := _m.Called(ctx, destChainSelector)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGasAndTokenPrices")
+ }
+
+ var r0 map[uint64]*big.Int
+ var r1 map[ccip.Address]*big.Int
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64) (map[uint64]*big.Int, map[ccip.Address]*big.Int, error)); ok {
+ return rf(ctx, destChainSelector)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64) map[uint64]*big.Int); ok {
+ r0 = rf(ctx, destChainSelector)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(map[uint64]*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint64) map[ccip.Address]*big.Int); ok {
+ r1 = rf(ctx, destChainSelector)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).(map[ccip.Address]*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context, uint64) error); ok {
+ r2 = rf(ctx, destChainSelector)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// PriceService_GetGasAndTokenPrices_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGasAndTokenPrices'
+type PriceService_GetGasAndTokenPrices_Call struct {
+ *mock.Call
+}
+
+// GetGasAndTokenPrices is a helper method to define mock.On call
+// - ctx context.Context
+// - destChainSelector uint64
+func (_e *PriceService_Expecter) GetGasAndTokenPrices(ctx interface{}, destChainSelector interface{}) *PriceService_GetGasAndTokenPrices_Call {
+ return &PriceService_GetGasAndTokenPrices_Call{Call: _e.mock.On("GetGasAndTokenPrices", ctx, destChainSelector)}
+}
+
+func (_c *PriceService_GetGasAndTokenPrices_Call) Run(run func(ctx context.Context, destChainSelector uint64)) *PriceService_GetGasAndTokenPrices_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint64))
+ })
+ return _c
+}
+
+func (_c *PriceService_GetGasAndTokenPrices_Call) Return(_a0 map[uint64]*big.Int, _a1 map[ccip.Address]*big.Int, _a2 error) *PriceService_GetGasAndTokenPrices_Call {
+ _c.Call.Return(_a0, _a1, _a2)
+ return _c
+}
+
+func (_c *PriceService_GetGasAndTokenPrices_Call) RunAndReturn(run func(context.Context, uint64) (map[uint64]*big.Int, map[ccip.Address]*big.Int, error)) *PriceService_GetGasAndTokenPrices_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Start provides a mock function with given fields: _a0
+func (_m *PriceService) Start(_a0 context.Context) error {
+ ret := _m.Called(_a0)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Start")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context) error); ok {
+ r0 = rf(_a0)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// PriceService_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
+type PriceService_Start_Call struct {
+ *mock.Call
+}
+
+// Start is a helper method to define mock.On call
+// - _a0 context.Context
+func (_e *PriceService_Expecter) Start(_a0 interface{}) *PriceService_Start_Call {
+ return &PriceService_Start_Call{Call: _e.mock.On("Start", _a0)}
+}
+
+func (_c *PriceService_Start_Call) Run(run func(_a0 context.Context)) *PriceService_Start_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *PriceService_Start_Call) Return(_a0 error) *PriceService_Start_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *PriceService_Start_Call) RunAndReturn(run func(context.Context) error) *PriceService_Start_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// UpdateDynamicConfig provides a mock function with given fields: ctx, gasPriceEstimator, destPriceRegistryReader
+func (_m *PriceService) UpdateDynamicConfig(ctx context.Context, gasPriceEstimator prices.GasPriceEstimatorCommit, destPriceRegistryReader ccipdata.PriceRegistryReader) error {
+ ret := _m.Called(ctx, gasPriceEstimator, destPriceRegistryReader)
+
+ if len(ret) == 0 {
+ panic("no return value specified for UpdateDynamicConfig")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, prices.GasPriceEstimatorCommit, ccipdata.PriceRegistryReader) error); ok {
+ r0 = rf(ctx, gasPriceEstimator, destPriceRegistryReader)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// PriceService_UpdateDynamicConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateDynamicConfig'
+type PriceService_UpdateDynamicConfig_Call struct {
+ *mock.Call
+}
+
+// UpdateDynamicConfig is a helper method to define mock.On call
+// - ctx context.Context
+// - gasPriceEstimator prices.GasPriceEstimatorCommit
+// - destPriceRegistryReader ccipdata.PriceRegistryReader
+func (_e *PriceService_Expecter) UpdateDynamicConfig(ctx interface{}, gasPriceEstimator interface{}, destPriceRegistryReader interface{}) *PriceService_UpdateDynamicConfig_Call {
+ return &PriceService_UpdateDynamicConfig_Call{Call: _e.mock.On("UpdateDynamicConfig", ctx, gasPriceEstimator, destPriceRegistryReader)}
+}
+
+func (_c *PriceService_UpdateDynamicConfig_Call) Run(run func(ctx context.Context, gasPriceEstimator prices.GasPriceEstimatorCommit, destPriceRegistryReader ccipdata.PriceRegistryReader)) *PriceService_UpdateDynamicConfig_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(prices.GasPriceEstimatorCommit), args[2].(ccipdata.PriceRegistryReader))
+ })
+ return _c
+}
+
+func (_c *PriceService_UpdateDynamicConfig_Call) Return(_a0 error) *PriceService_UpdateDynamicConfig_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *PriceService_UpdateDynamicConfig_Call) RunAndReturn(run func(context.Context, prices.GasPriceEstimatorCommit, ccipdata.PriceRegistryReader) error) *PriceService_UpdateDynamicConfig_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewPriceService creates a new instance of PriceService. 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 NewPriceService(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *PriceService {
+ mock := &PriceService{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service.go b/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service.go
new file mode 100644
index 00000000000..2806c26e220
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service.go
@@ -0,0 +1,449 @@
+package db
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "slices"
+ "sort"
+ "sync"
+ "time"
+
+ "golang.org/x/sync/errgroup"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ cciporm "github.com/smartcontractkit/chainlink/v2/core/services/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+ "github.com/smartcontractkit/chainlink/v2/core/utils"
+)
+
+// PriceService manages DB access for gas and token price data.
+// In the background, PriceService periodically inserts latest gas and token prices into the DB.
+// During `Observation` phase, Commit plugin calls PriceService to fetch the latest prices from DB.
+// This enables all lanes connected to a chain to feed price data to the leader lane's Commit plugin for that chain.
+type PriceService interface {
+ job.ServiceCtx
+
+ // UpdateDynamicConfig updates gasPriceEstimator and destPriceRegistryReader during Commit plugin dynamic config change.
+ UpdateDynamicConfig(ctx context.Context, gasPriceEstimator prices.GasPriceEstimatorCommit, destPriceRegistryReader ccipdata.PriceRegistryReader) error
+
+ // GetGasAndTokenPrices fetches source chain gas prices and relevant token prices from all lanes that touch the given dest chain.
+ // The prices have been written into the DB by each lane's PriceService in the background. The prices are denoted in USD.
+ GetGasAndTokenPrices(ctx context.Context, destChainSelector uint64) (map[uint64]*big.Int, map[cciptypes.Address]*big.Int, error)
+}
+
+var _ PriceService = (*priceService)(nil)
+
+const (
+ // Gas prices are refreshed every 1 minute, they are sufficiently accurate, and consistent with Commit OCR round time.
+ gasPriceUpdateInterval = 1 * time.Minute
+ // Token prices are refreshed every 10 minutes, we only report prices for blue chip tokens, DS&A simulation show
+ // their prices are stable, 10-minute resolution is accurate enough.
+ tokenPriceUpdateInterval = 10 * time.Minute
+)
+
+type priceService struct {
+ gasUpdateInterval time.Duration
+ tokenUpdateInterval time.Duration
+
+ lggr logger.Logger
+ orm cciporm.ORM
+ jobId int32
+ destChainSelector uint64
+
+ sourceChainSelector uint64
+ sourceNative cciptypes.Address
+ priceGetter pricegetter.AllTokensPriceGetter
+ offRampReader ccipdata.OffRampReader
+ gasPriceEstimator prices.GasPriceEstimatorCommit
+ destPriceRegistryReader ccipdata.PriceRegistryReader
+
+ services.StateMachine
+ wg *sync.WaitGroup
+ backgroundCtx context.Context //nolint:containedctx
+ backgroundCancel context.CancelFunc
+ dynamicConfigMu *sync.RWMutex
+}
+
+func NewPriceService(
+ lggr logger.Logger,
+ orm cciporm.ORM,
+ jobId int32,
+ destChainSelector uint64,
+ sourceChainSelector uint64,
+
+ sourceNative cciptypes.Address,
+ priceGetter pricegetter.AllTokensPriceGetter,
+ offRampReader ccipdata.OffRampReader,
+) PriceService {
+ ctx, cancel := context.WithCancel(context.Background())
+
+ pw := &priceService{
+ gasUpdateInterval: gasPriceUpdateInterval,
+ tokenUpdateInterval: tokenPriceUpdateInterval,
+
+ lggr: lggr,
+ orm: orm,
+ jobId: jobId,
+ destChainSelector: destChainSelector,
+
+ sourceChainSelector: sourceChainSelector,
+ sourceNative: sourceNative,
+ priceGetter: priceGetter,
+ offRampReader: offRampReader,
+
+ wg: new(sync.WaitGroup),
+ backgroundCtx: ctx,
+ backgroundCancel: cancel,
+ dynamicConfigMu: &sync.RWMutex{},
+ }
+ return pw
+}
+
+func (p *priceService) Start(context.Context) error {
+ return p.StateMachine.StartOnce("PriceService", func() error {
+ p.lggr.Info("Starting PriceService")
+ p.wg.Add(1)
+ p.run()
+ return nil
+ })
+}
+
+func (p *priceService) Close() error {
+ return p.StateMachine.StopOnce("PriceService", func() error {
+ p.lggr.Info("Closing PriceService")
+ p.backgroundCancel()
+ p.wg.Wait()
+ return nil
+ })
+}
+
+func (p *priceService) run() {
+ gasUpdateTicker := time.NewTicker(utils.WithJitter(p.gasUpdateInterval))
+ tokenUpdateTicker := time.NewTicker(utils.WithJitter(p.tokenUpdateInterval))
+
+ go func() {
+ defer p.wg.Done()
+ defer gasUpdateTicker.Stop()
+ defer tokenUpdateTicker.Stop()
+
+ for {
+ select {
+ case <-p.backgroundCtx.Done():
+ return
+ case <-gasUpdateTicker.C:
+ err := p.runGasPriceUpdate(p.backgroundCtx)
+ if err != nil {
+ p.lggr.Errorw("Error when updating gas prices in the background", "err", err)
+ }
+ case <-tokenUpdateTicker.C:
+ err := p.runTokenPriceUpdate(p.backgroundCtx)
+ if err != nil {
+ p.lggr.Errorw("Error when updating token prices in the background", "err", err)
+ }
+ }
+ }
+ }()
+}
+
+func (p *priceService) UpdateDynamicConfig(ctx context.Context, gasPriceEstimator prices.GasPriceEstimatorCommit, destPriceRegistryReader ccipdata.PriceRegistryReader) error {
+ p.dynamicConfigMu.Lock()
+ p.gasPriceEstimator = gasPriceEstimator
+ p.destPriceRegistryReader = destPriceRegistryReader
+ p.dynamicConfigMu.Unlock()
+
+ // Config update may substantially change the prices, refresh the prices immediately, this also makes testing easier
+ // for not having to wait to the full update interval.
+ if err := p.runGasPriceUpdate(ctx); err != nil {
+ p.lggr.Errorw("Error when updating gas prices after dynamic config update", "err", err)
+ }
+ if err := p.runTokenPriceUpdate(ctx); err != nil {
+ p.lggr.Errorw("Error when updating token prices after dynamic config update", "err", err)
+ }
+
+ return nil
+}
+
+func (p *priceService) GetGasAndTokenPrices(ctx context.Context, destChainSelector uint64) (map[uint64]*big.Int, map[cciptypes.Address]*big.Int, error) {
+ eg := new(errgroup.Group)
+
+ var gasPricesInDB []cciporm.GasPrice
+ var tokenPricesInDB []cciporm.TokenPrice
+
+ eg.Go(func() error {
+ gasPrices, err := p.orm.GetGasPricesByDestChain(ctx, destChainSelector)
+ if err != nil {
+ return fmt.Errorf("failed to get gas prices from db: %w", err)
+ }
+ gasPricesInDB = gasPrices
+ return nil
+ })
+
+ eg.Go(func() error {
+ tokenPrices, err := p.orm.GetTokenPricesByDestChain(ctx, destChainSelector)
+ if err != nil {
+ return fmt.Errorf("failed to get token prices from db: %w", err)
+ }
+ tokenPricesInDB = tokenPrices
+ return nil
+ })
+
+ if err := eg.Wait(); err != nil {
+ return nil, nil, err
+ }
+
+ gasPrices := make(map[uint64]*big.Int, len(gasPricesInDB))
+ tokenPrices := make(map[cciptypes.Address]*big.Int, len(tokenPricesInDB))
+
+ for _, gasPrice := range gasPricesInDB {
+ if gasPrice.GasPrice != nil {
+ gasPrices[gasPrice.SourceChainSelector] = gasPrice.GasPrice.ToInt()
+ }
+ }
+
+ for _, tokenPrice := range tokenPricesInDB {
+ if tokenPrice.TokenPrice != nil {
+ tokenPrices[cciptypes.Address(tokenPrice.TokenAddr)] = tokenPrice.TokenPrice.ToInt()
+ }
+ }
+
+ return gasPrices, tokenPrices, nil
+}
+
+func (p *priceService) runGasPriceUpdate(ctx context.Context) error {
+ // Protect against concurrent updates of `gasPriceEstimator` and `destPriceRegistryReader`
+ // Price updates happen infrequently - once every `gasPriceUpdateInterval` seconds.
+ // It does not happen on any code path that is performance sensitive.
+ // We can afford to have non-performant unlocks here that is simple and safe.
+ p.dynamicConfigMu.RLock()
+ defer p.dynamicConfigMu.RUnlock()
+
+ // There may be a period of time between service is started and dynamic config is updated
+ if p.gasPriceEstimator == nil {
+ p.lggr.Info("Skipping gas price update due to gasPriceEstimator not ready")
+ return nil
+ }
+
+ sourceGasPriceUSD, err := p.observeGasPriceUpdates(ctx, p.lggr)
+ if err != nil {
+ return fmt.Errorf("failed to observe gas price updates: %w", err)
+ }
+
+ err = p.writeGasPricesToDB(ctx, sourceGasPriceUSD)
+ if err != nil {
+ return fmt.Errorf("failed to write gas prices to db: %w", err)
+ }
+
+ return nil
+}
+
+func (p *priceService) runTokenPriceUpdate(ctx context.Context) error {
+ // Protect against concurrent updates of `tokenPriceEstimator` and `destPriceRegistryReader`
+ // Price updates happen infrequently - once every `tokenPriceUpdateInterval` seconds.
+ p.dynamicConfigMu.RLock()
+ defer p.dynamicConfigMu.RUnlock()
+
+ // There may be a period of time between service is started and dynamic config is updated
+ if p.destPriceRegistryReader == nil {
+ p.lggr.Info("Skipping token price update due to destPriceRegistry not ready")
+ return nil
+ }
+
+ tokenPricesUSD, err := p.observeTokenPriceUpdates(ctx, p.lggr)
+ if err != nil {
+ return fmt.Errorf("failed to observe token price updates: %w", err)
+ }
+
+ err = p.writeTokenPricesToDB(ctx, tokenPricesUSD)
+ if err != nil {
+ return fmt.Errorf("failed to write token prices to db: %w", err)
+ }
+
+ return nil
+}
+
+func (p *priceService) observeGasPriceUpdates(
+ ctx context.Context,
+ lggr logger.Logger,
+) (sourceGasPriceUSD *big.Int, err error) {
+ if p.gasPriceEstimator == nil {
+ return nil, fmt.Errorf("gasPriceEstimator is not set yet")
+ }
+
+ // Include wrapped native to identify the source native USD price, notice USD is in 1e18 scale, i.e. $1 = 1e18
+ rawTokenPricesUSD, err := p.priceGetter.TokenPricesUSD(ctx, []cciptypes.Address{p.sourceNative})
+
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch source native price (%s): %w", p.sourceNative, err)
+ }
+
+ sourceNativePriceUSD, exists := rawTokenPricesUSD[p.sourceNative]
+ if !exists {
+ return nil, fmt.Errorf("missing source native (%s) price", p.sourceNative)
+ }
+
+ sourceGasPrice, err := p.gasPriceEstimator.GetGasPrice(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if sourceGasPrice == nil {
+ return nil, fmt.Errorf("missing gas price")
+ }
+ sourceGasPriceUSD, err = p.gasPriceEstimator.DenoteInUSD(sourceGasPrice, sourceNativePriceUSD)
+ if err != nil {
+ return nil, err
+ }
+
+ lggr.Infow("PriceService observed latest gas price",
+ "sourceChainSelector", p.sourceChainSelector,
+ "destChainSelector", p.destChainSelector,
+ "sourceNative", p.sourceNative,
+ "gasPriceWei", sourceGasPrice,
+ "sourceNativePriceUSD", sourceNativePriceUSD,
+ "sourceGasPriceUSD", sourceGasPriceUSD,
+ )
+ return sourceGasPriceUSD, nil
+}
+
+// All prices are USD ($1=1e18) denominated. All prices must be not nil.
+// Jobspec should have the destination tokens (Aggregate Rate Limit, Bps) and 1 source token (source native).
+// Not respecting this will error out as we need to fetch the token decimals for all tokens expect sourceNative.
+// destTokens is only used to check if sourceNative has the same address as one of the dest tokens.
+// Return token prices should contain the exact same tokens as in tokenDecimals.
+func (p *priceService) observeTokenPriceUpdates(
+ ctx context.Context,
+ lggr logger.Logger,
+) (tokenPricesUSD map[cciptypes.Address]*big.Int, err error) {
+ if p.destPriceRegistryReader == nil {
+ return nil, fmt.Errorf("destPriceRegistry is not set yet")
+ }
+ rawTokenPricesUSD, err := p.priceGetter.GetJobSpecTokenPricesUSD(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch token prices: %w", err)
+ }
+
+ // Verify no price returned by price getter is nil
+ for token, price := range rawTokenPricesUSD {
+ if price == nil {
+ return nil, fmt.Errorf("Token price is nil for token %s", token)
+ }
+ }
+
+ lggr.Infow("Raw token prices", "rawTokenPrices", rawTokenPricesUSD)
+
+ sourceNativeEvmAddr, err := ccipcalc.GenericAddrToEvm(p.sourceNative)
+ if err != nil {
+ return nil, fmt.Errorf("failed to convert source native to EVM address: %w", err)
+ }
+
+ // Filter out source native token only if source native not in dest tokens
+ var finalDestTokens []cciptypes.Address
+ for token := range rawTokenPricesUSD {
+ tokenEvmAddr, err2 := ccipcalc.GenericAddrToEvm(token)
+ if err2 != nil {
+ return nil, fmt.Errorf("failed to convert token to EVM address: %w", err)
+ }
+
+ if tokenEvmAddr != sourceNativeEvmAddr {
+ finalDestTokens = append(finalDestTokens, token)
+ }
+ }
+
+ fee, bridged, err := ccipcommon.GetDestinationTokens(ctx, p.offRampReader, p.destPriceRegistryReader)
+ if err != nil {
+ return nil, fmt.Errorf("get destination tokens: %w", err)
+ }
+ onchainDestTokens := ccipcommon.FlattenedAndSortedTokens(fee, bridged)
+ lggr.Debugw("Destination tokens", "destTokens", onchainDestTokens)
+
+ onchainTokensEvmAddr, err := ccipcalc.GenericAddrsToEvm(onchainDestTokens...)
+ if err != nil {
+ return nil, fmt.Errorf("failed to convert sorted lane tokens to EVM addresses: %w", err)
+ }
+ // Check for case where sourceNative has same address as one of the dest tokens (example: WETH in Base and Optimism)
+ hasSameDestAddress := slices.Contains(onchainTokensEvmAddr, sourceNativeEvmAddr)
+
+ if hasSameDestAddress {
+ finalDestTokens = append(finalDestTokens, p.sourceNative)
+ }
+
+ // Sort tokens to make the order deterministic, easier for testing and debugging
+ sort.Slice(finalDestTokens, func(i, j int) bool {
+ return finalDestTokens[i] < finalDestTokens[j]
+ })
+
+ destTokensDecimals, err := p.destPriceRegistryReader.GetTokensDecimals(ctx, finalDestTokens)
+ if err != nil {
+ return nil, fmt.Errorf("get tokens decimals: %w", err)
+ }
+
+ if len(destTokensDecimals) != len(finalDestTokens) {
+ return nil, fmt.Errorf("mismatched token decimals and tokens")
+ }
+
+ tokenPricesUSD = make(map[cciptypes.Address]*big.Int, len(rawTokenPricesUSD))
+ for i, token := range finalDestTokens {
+ tokenPricesUSD[token] = calculateUsdPer1e18TokenAmount(rawTokenPricesUSD[token], destTokensDecimals[i])
+ }
+
+ lggr.Infow("PriceService observed latest token prices",
+ "sourceChainSelector", p.sourceChainSelector,
+ "destChainSelector", p.destChainSelector,
+ "tokenPricesUSD", tokenPricesUSD,
+ )
+ return tokenPricesUSD, nil
+}
+
+func (p *priceService) writeGasPricesToDB(ctx context.Context, sourceGasPriceUSD *big.Int) error {
+ if sourceGasPriceUSD == nil {
+ return nil
+ }
+
+ _, err := p.orm.UpsertGasPricesForDestChain(ctx, p.destChainSelector, []cciporm.GasPrice{
+ {
+ SourceChainSelector: p.sourceChainSelector,
+ GasPrice: assets.NewWei(sourceGasPriceUSD),
+ },
+ })
+ return err
+}
+
+func (p *priceService) writeTokenPricesToDB(ctx context.Context, tokenPricesUSD map[cciptypes.Address]*big.Int) error {
+ if tokenPricesUSD == nil {
+ return nil
+ }
+
+ var tokenPrices []cciporm.TokenPrice
+
+ for token, price := range tokenPricesUSD {
+ tokenPrices = append(tokenPrices, cciporm.TokenPrice{
+ TokenAddr: string(token),
+ TokenPrice: assets.NewWei(price),
+ })
+ }
+
+ // Sort token by addr to make price updates ordering deterministic, easier for testing and debugging
+ sort.Slice(tokenPrices, func(i, j int) bool {
+ return tokenPrices[i].TokenAddr < tokenPrices[j].TokenAddr
+ })
+
+ _, err := p.orm.UpsertTokenPricesForDestChain(ctx, p.destChainSelector, tokenPrices, p.tokenUpdateInterval)
+ return err
+}
+
+// Input price is USD per full token, with 18 decimal precision
+// Result price is USD per 1e18 of smallest token denomination, with 18 decimal precision
+// Example: 1 USDC = 1.00 USD per full token, each full token is 6 decimals -> 1 * 1e18 * 1e18 / 1e6 = 1e30
+func calculateUsdPer1e18TokenAmount(price *big.Int, decimals uint8) *big.Int {
+ tmp := big.NewInt(0).Mul(price, big.NewInt(1e18))
+ return tmp.Div(tmp, big.NewInt(0).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service_test.go b/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service_test.go
new file mode 100644
index 00000000000..a25c5d3c47e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/ccipdb/price_service_test.go
@@ -0,0 +1,842 @@
+package db
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "reflect"
+ "slices"
+ "sort"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ cciporm "github.com/smartcontractkit/chainlink/v2/core/services/ccip"
+ ccipmocks "github.com/smartcontractkit/chainlink/v2/core/services/ccip/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ ccipdatamocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+func TestPriceService_writeGasPrices(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ jobId := int32(1)
+ destChainSelector := uint64(12345)
+ sourceChainSelector := uint64(67890)
+
+ gasPrice := big.NewInt(1e18)
+
+ expectedGasPriceUpdate := []cciporm.GasPrice{
+ {
+ SourceChainSelector: sourceChainSelector,
+ GasPrice: assets.NewWei(gasPrice),
+ },
+ }
+
+ testCases := []struct {
+ name string
+ gasPriceError bool
+ expectedErr bool
+ }{
+ {
+ name: "ORM called successfully",
+ gasPriceError: false,
+ expectedErr: false,
+ },
+ {
+ name: "gasPrice clear failed",
+ gasPriceError: true,
+ expectedErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := tests.Context(t)
+
+ var gasPricesError error
+ if tc.gasPriceError {
+ gasPricesError = fmt.Errorf("gas prices error")
+ }
+
+ mockOrm := ccipmocks.NewORM(t)
+ mockOrm.On("UpsertGasPricesForDestChain", ctx, destChainSelector, expectedGasPriceUpdate).Return(int64(0), gasPricesError).Once()
+
+ priceService := NewPriceService(
+ lggr,
+ mockOrm,
+ jobId,
+ destChainSelector,
+ sourceChainSelector,
+ "",
+ nil,
+ nil,
+ ).(*priceService)
+ err := priceService.writeGasPricesToDB(ctx, gasPrice)
+ if tc.expectedErr {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ }
+ })
+ }
+}
+
+func TestPriceService_writeTokenPrices(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ jobId := int32(1)
+ destChainSelector := uint64(12345)
+ sourceChainSelector := uint64(67890)
+
+ tokenPrices := map[cciptypes.Address]*big.Int{
+ "0x123": big.NewInt(2e18),
+ "0x234": big.NewInt(3e18),
+ }
+
+ expectedTokenPriceUpdate := []cciporm.TokenPrice{
+ {
+ TokenAddr: "0x123",
+ TokenPrice: assets.NewWei(big.NewInt(2e18)),
+ },
+ {
+ TokenAddr: "0x234",
+ TokenPrice: assets.NewWei(big.NewInt(3e18)),
+ },
+ }
+
+ testCases := []struct {
+ name string
+ tokenPriceError bool
+ expectedErr bool
+ }{
+ {
+ name: "ORM called successfully",
+ tokenPriceError: false,
+ expectedErr: false,
+ },
+ {
+ name: "tokenPrice clear failed",
+ tokenPriceError: true,
+ expectedErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := tests.Context(t)
+
+ var tokenPricesError error
+ if tc.tokenPriceError {
+ tokenPricesError = fmt.Errorf("token prices error")
+ }
+
+ mockOrm := ccipmocks.NewORM(t)
+ mockOrm.On("UpsertTokenPricesForDestChain", ctx, destChainSelector, expectedTokenPriceUpdate, tokenPriceUpdateInterval).
+ Return(int64(len(expectedTokenPriceUpdate)), tokenPricesError).Once()
+
+ priceService := NewPriceService(
+ lggr,
+ mockOrm,
+ jobId,
+ destChainSelector,
+ sourceChainSelector,
+ "",
+ nil,
+ nil,
+ ).(*priceService)
+ err := priceService.writeTokenPricesToDB(ctx, tokenPrices)
+ if tc.expectedErr {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ }
+ })
+ }
+}
+
+func TestPriceService_observeGasPriceUpdates(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ jobId := int32(1)
+ destChainSelector := uint64(12345)
+ sourceChainSelector := uint64(67890)
+ sourceNativeToken := cciptypes.Address(utils.RandomAddress().String())
+
+ testCases := []struct {
+ name string
+ sourceNativeToken cciptypes.Address
+ priceGetterRespData map[cciptypes.Address]*big.Int
+ priceGetterRespErr error
+ feeEstimatorRespFee *big.Int
+ feeEstimatorRespErr error
+ maxGasPrice uint64
+ expSourceGasPriceUSD *big.Int
+ expErr bool
+ }{
+ {
+ name: "base",
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ sourceNativeToken: val1e18(100),
+ },
+ priceGetterRespErr: nil,
+ feeEstimatorRespFee: big.NewInt(10),
+ feeEstimatorRespErr: nil,
+ maxGasPrice: 1e18,
+ expSourceGasPriceUSD: big.NewInt(1000),
+ expErr: false,
+ },
+ {
+ name: "price getter returned an error",
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: nil,
+ priceGetterRespErr: fmt.Errorf("some random network error"),
+ expErr: true,
+ },
+ {
+ name: "price getter did not return source native gas price",
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ "0x1": val1e18(100),
+ },
+ priceGetterRespErr: nil,
+ expErr: true,
+ },
+ {
+ name: "dynamic fee cap overrides legacy",
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ sourceNativeToken: val1e18(100),
+ },
+ priceGetterRespErr: nil,
+ feeEstimatorRespFee: big.NewInt(20),
+ feeEstimatorRespErr: nil,
+ maxGasPrice: 1e18,
+ expSourceGasPriceUSD: big.NewInt(2000),
+ expErr: false,
+ },
+ {
+ name: "nil gas price",
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ sourceNativeToken: val1e18(100),
+ },
+ feeEstimatorRespFee: nil,
+ maxGasPrice: 1e18,
+ expErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ priceGetter := pricegetter.NewMockAllTokensPriceGetter(t)
+ defer priceGetter.AssertExpectations(t)
+
+ gasPriceEstimator := prices.NewMockGasPriceEstimatorCommit(t)
+ defer gasPriceEstimator.AssertExpectations(t)
+
+ priceGetter.On("TokenPricesUSD", mock.Anything, []cciptypes.Address{tc.sourceNativeToken}).Return(tc.priceGetterRespData, tc.priceGetterRespErr)
+
+ if tc.maxGasPrice > 0 {
+ gasPriceEstimator.On("GetGasPrice", mock.Anything).Return(tc.feeEstimatorRespFee, tc.feeEstimatorRespErr)
+ if tc.feeEstimatorRespFee != nil {
+ pUSD := ccipcalc.CalculateUsdPerUnitGas(tc.feeEstimatorRespFee, tc.priceGetterRespData[tc.sourceNativeToken])
+ gasPriceEstimator.On("DenoteInUSD", mock.Anything, mock.Anything).Return(pUSD, nil)
+ }
+ }
+
+ priceService := NewPriceService(
+ lggr,
+ nil,
+ jobId,
+ destChainSelector,
+ sourceChainSelector,
+ tc.sourceNativeToken,
+ priceGetter,
+ nil,
+ ).(*priceService)
+ priceService.gasPriceEstimator = gasPriceEstimator
+
+ sourceGasPriceUSD, err := priceService.observeGasPriceUpdates(context.Background(), lggr)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.True(t, tc.expSourceGasPriceUSD.Cmp(sourceGasPriceUSD) == 0)
+ })
+ }
+}
+
+func TestPriceService_observeTokenPriceUpdates(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ jobId := int32(1)
+ destChainSelector := uint64(12345)
+ sourceChainSelector := uint64(67890)
+ sourceNativeToken := cciptypes.Address(utils.RandomAddress().String())
+
+ const nTokens = 10
+ tokens := make([]cciptypes.Address, nTokens)
+ for i := range tokens {
+ tokens[i] = cciptypes.Address(utils.RandomAddress().String())
+ }
+ sort.Slice(tokens, func(i, j int) bool { return tokens[i] < tokens[j] })
+
+ testCases := []struct {
+ name string
+ destTokens []cciptypes.Address
+ tokenDecimals map[cciptypes.Address]uint8
+ sourceNativeToken cciptypes.Address
+ filterOutTokens []cciptypes.Address
+ priceGetterRespData map[cciptypes.Address]*big.Int
+ priceGetterRespErr error
+ expTokenPricesUSD map[cciptypes.Address]*big.Int
+ expErr bool
+ expDecimalErr bool
+ }{
+ {
+ name: "base case with src native token not equals to dest token",
+ tokenDecimals: map[cciptypes.Address]uint8{ // only destination tokens
+ tokens[1]: 18,
+ tokens[2]: 12,
+ },
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: map[cciptypes.Address]*big.Int{ // should return all tokens (including source native token)
+ sourceNativeToken: val1e18(100),
+ tokens[1]: val1e18(200),
+ tokens[2]: val1e18(300),
+ },
+ priceGetterRespErr: nil,
+ expTokenPricesUSD: map[cciptypes.Address]*big.Int{ // should only return the tokens in destination chain
+ tokens[1]: val1e18(200),
+ tokens[2]: val1e18(300 * 1e6),
+ },
+ expErr: false,
+ },
+ {
+ name: "base case with src native token equals to dest token",
+ tokenDecimals: map[cciptypes.Address]uint8{
+ sourceNativeToken: 18,
+ tokens[1]: 12,
+ },
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ sourceNativeToken: val1e18(100),
+ tokens[1]: val1e18(200),
+ },
+ priceGetterRespErr: nil,
+ expTokenPricesUSD: map[cciptypes.Address]*big.Int{
+ sourceNativeToken: val1e18(100),
+ tokens[1]: val1e18(200 * 1e6),
+ },
+ expErr: false,
+ },
+ {
+ name: "price getter returned an error",
+ tokenDecimals: map[cciptypes.Address]uint8{
+ tokens[0]: 18,
+ tokens[1]: 18,
+ },
+ sourceNativeToken: tokens[0],
+ priceGetterRespData: nil,
+ priceGetterRespErr: fmt.Errorf("some random network error"),
+ expErr: true,
+ },
+ {
+ name: "price getter returns more prices than destTokens",
+ destTokens: []cciptypes.Address{tokens[1]},
+ tokenDecimals: map[cciptypes.Address]uint8{
+ tokens[1]: 18,
+ tokens[2]: 12,
+ tokens[3]: 18,
+ },
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ sourceNativeToken: val1e18(100),
+ tokens[1]: val1e18(200),
+ tokens[2]: val1e18(300),
+ tokens[3]: val1e18(400),
+ },
+ expTokenPricesUSD: map[cciptypes.Address]*big.Int{
+ tokens[1]: val1e18(200),
+ tokens[2]: val1e18(300 * 1e6),
+ tokens[3]: val1e18(400),
+ },
+ },
+ {
+ name: "price getter returns more prices with missing decimals",
+ tokenDecimals: map[cciptypes.Address]uint8{
+ tokens[1]: 18,
+ tokens[2]: 12,
+ },
+ sourceNativeToken: sourceNativeToken,
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ sourceNativeToken: val1e18(100),
+ tokens[1]: val1e18(200),
+ tokens[2]: val1e18(300),
+ tokens[3]: val1e18(400),
+ },
+ priceGetterRespErr: nil,
+ expErr: true,
+ expDecimalErr: true,
+ },
+ {
+ name: "price getter skipped a requested price",
+ tokenDecimals: map[cciptypes.Address]uint8{
+ tokens[0]: 18,
+ },
+ sourceNativeToken: tokens[0],
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ tokens[0]: val1e18(100),
+ },
+ priceGetterRespErr: nil,
+ expTokenPricesUSD: map[cciptypes.Address]*big.Int{
+ tokens[0]: val1e18(100),
+ },
+ expErr: false,
+ },
+ {
+ name: "nil token price",
+ tokenDecimals: map[cciptypes.Address]uint8{
+ tokens[0]: 18,
+ tokens[1]: 18,
+ tokens[2]: 18,
+ },
+ sourceNativeToken: tokens[0],
+ filterOutTokens: []cciptypes.Address{tokens[2]},
+ priceGetterRespData: map[cciptypes.Address]*big.Int{
+ tokens[0]: nil,
+ tokens[1]: val1e18(200),
+ tokens[2]: val1e18(300),
+ },
+ expErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ priceGetter := pricegetter.NewMockAllTokensPriceGetter(t)
+ defer priceGetter.AssertExpectations(t)
+
+ var destTokens []cciptypes.Address
+ if len(tc.destTokens) == 0 {
+ for tk := range tc.tokenDecimals {
+ destTokens = append(destTokens, tk)
+ }
+ } else {
+ destTokens = tc.destTokens
+ }
+
+ finalDestTokens := make([]cciptypes.Address, 0, len(destTokens))
+ for addr := range tc.priceGetterRespData {
+ if (tc.sourceNativeToken != addr) || (slices.Contains(destTokens, addr)) {
+ finalDestTokens = append(finalDestTokens, addr)
+ }
+ }
+ sort.Slice(finalDestTokens, func(i, j int) bool {
+ return finalDestTokens[i] < finalDestTokens[j]
+ })
+
+ var destDecimals []uint8
+ for _, token := range finalDestTokens {
+ destDecimals = append(destDecimals, tc.tokenDecimals[token])
+ }
+
+ priceGetter.On("GetJobSpecTokenPricesUSD", mock.Anything).Return(tc.priceGetterRespData, tc.priceGetterRespErr)
+
+ offRampReader := ccipdatamocks.NewOffRampReader(t)
+ offRampReader.On("GetTokens", mock.Anything).Return(cciptypes.OffRampTokens{
+ DestinationTokens: destTokens,
+ }, nil).Maybe()
+
+ destPriceReg := ccipdatamocks.NewPriceRegistryReader(t)
+ if tc.expDecimalErr {
+ destPriceReg.On("GetTokensDecimals", mock.Anything, finalDestTokens).Return([]uint8{}, fmt.Errorf("Token not found")).Maybe()
+ } else {
+ destPriceReg.On("GetTokensDecimals", mock.Anything, finalDestTokens).Return(destDecimals, nil).Maybe()
+ }
+ destPriceReg.On("GetFeeTokens", mock.Anything).Return([]cciptypes.Address{destTokens[0]}, nil).Maybe()
+
+ priceService := NewPriceService(
+ lggr,
+ nil,
+ jobId,
+ destChainSelector,
+ sourceChainSelector,
+ tc.sourceNativeToken,
+ priceGetter,
+ offRampReader,
+ ).(*priceService)
+ priceService.destPriceRegistryReader = destPriceReg
+
+ tokenPricesUSD, err := priceService.observeTokenPriceUpdates(context.Background(), lggr)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.True(t, reflect.DeepEqual(tc.expTokenPricesUSD, tokenPricesUSD))
+ })
+ }
+}
+
+func TestPriceService_calculateUsdPer1e18TokenAmount(t *testing.T) {
+ testCases := []struct {
+ name string
+ price *big.Int
+ decimal uint8
+ wantResult *big.Int
+ }{
+ {
+ name: "18-decimal token, $6.5 per token",
+ price: big.NewInt(65e17),
+ decimal: 18,
+ wantResult: big.NewInt(65e17),
+ },
+ {
+ name: "6-decimal token, $1 per token",
+ price: big.NewInt(1e18),
+ decimal: 6,
+ wantResult: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e12)), // 1e30
+ },
+ {
+ name: "0-decimal token, $1 per token",
+ price: big.NewInt(1e18),
+ decimal: 0,
+ wantResult: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e18)), // 1e36
+ },
+ {
+ name: "36-decimal token, $1 per token",
+ price: big.NewInt(1e18),
+ decimal: 36,
+ wantResult: big.NewInt(1),
+ },
+ }
+ for _, tt := range testCases {
+ t.Run(tt.name, func(t *testing.T) {
+ got := calculateUsdPer1e18TokenAmount(tt.price, tt.decimal)
+ assert.Equal(t, tt.wantResult, got)
+ })
+ }
+}
+
+func TestPriceService_GetGasAndTokenPrices(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ jobId := int32(1)
+ destChainSelector := uint64(12345)
+ sourceChainSelector := uint64(67890)
+
+ token1 := ccipcalc.HexToAddress("0x123")
+ token2 := ccipcalc.HexToAddress("0x234")
+
+ gasPrice := big.NewInt(1e18)
+ tokenPrices := map[cciptypes.Address]*big.Int{
+ token1: big.NewInt(2e18),
+ token2: big.NewInt(3e18),
+ }
+
+ testCases := []struct {
+ name string
+ ormGasPricesResult []cciporm.GasPrice
+ ormTokenPricesResult []cciporm.TokenPrice
+
+ expectedGasPrices map[uint64]*big.Int
+ expectedTokenPrices map[cciptypes.Address]*big.Int
+
+ gasPriceError bool
+ tokenPriceError bool
+ expectedErr bool
+ }{
+ {
+ name: "ORM called successfully",
+ ormGasPricesResult: []cciporm.GasPrice{
+ {
+ SourceChainSelector: sourceChainSelector,
+ GasPrice: assets.NewWei(gasPrice),
+ },
+ },
+ ormTokenPricesResult: []cciporm.TokenPrice{
+ {
+ TokenAddr: string(token1),
+ TokenPrice: assets.NewWei(tokenPrices[token1]),
+ },
+ {
+ TokenAddr: string(token2),
+ TokenPrice: assets.NewWei(tokenPrices[token2]),
+ },
+ },
+ expectedGasPrices: map[uint64]*big.Int{
+ sourceChainSelector: gasPrice,
+ },
+ expectedTokenPrices: tokenPrices,
+ gasPriceError: false,
+ tokenPriceError: false,
+ expectedErr: false,
+ },
+ {
+ name: "multiple gas prices with nil token price",
+ ormGasPricesResult: []cciporm.GasPrice{
+ {
+ SourceChainSelector: sourceChainSelector,
+ GasPrice: assets.NewWei(gasPrice),
+ },
+ {
+ SourceChainSelector: sourceChainSelector + 1,
+ GasPrice: assets.NewWei(big.NewInt(200)),
+ },
+ {
+ SourceChainSelector: sourceChainSelector + 2,
+ GasPrice: assets.NewWei(big.NewInt(300)),
+ },
+ },
+ ormTokenPricesResult: nil,
+ expectedGasPrices: map[uint64]*big.Int{
+ sourceChainSelector: gasPrice,
+ sourceChainSelector + 1: big.NewInt(200),
+ sourceChainSelector + 2: big.NewInt(300),
+ },
+ expectedTokenPrices: map[cciptypes.Address]*big.Int{},
+ gasPriceError: false,
+ tokenPriceError: false,
+ expectedErr: false,
+ },
+ {
+ name: "multiple token prices with nil gas price",
+ ormGasPricesResult: nil,
+ ormTokenPricesResult: []cciporm.TokenPrice{
+ {
+ TokenAddr: string(token1),
+ TokenPrice: assets.NewWei(tokenPrices[token1]),
+ },
+ {
+ TokenAddr: string(token2),
+ TokenPrice: assets.NewWei(tokenPrices[token2]),
+ },
+ },
+ expectedGasPrices: map[uint64]*big.Int{},
+ expectedTokenPrices: tokenPrices,
+ gasPriceError: false,
+ tokenPriceError: false,
+ expectedErr: false,
+ },
+ {
+ name: "nil prices filtered out",
+ ormGasPricesResult: []cciporm.GasPrice{
+ {
+ SourceChainSelector: sourceChainSelector,
+ GasPrice: nil,
+ },
+ {
+ SourceChainSelector: sourceChainSelector + 1,
+ GasPrice: assets.NewWei(gasPrice),
+ },
+ },
+ ormTokenPricesResult: []cciporm.TokenPrice{
+ {
+ TokenAddr: string(token1),
+ TokenPrice: assets.NewWei(tokenPrices[token1]),
+ },
+ {
+ TokenAddr: string(token2),
+ TokenPrice: nil,
+ },
+ },
+ expectedGasPrices: map[uint64]*big.Int{
+ sourceChainSelector + 1: gasPrice,
+ },
+ expectedTokenPrices: map[cciptypes.Address]*big.Int{
+ token1: tokenPrices[token1],
+ },
+ gasPriceError: false,
+ tokenPriceError: false,
+ expectedErr: false,
+ },
+ {
+ name: "gasPrice clear failed",
+ gasPriceError: true,
+ tokenPriceError: false,
+ expectedErr: true,
+ },
+ {
+ name: "tokenPrice clear failed",
+ gasPriceError: false,
+ tokenPriceError: true,
+ expectedErr: true,
+ },
+ {
+ name: "both ORM calls failed",
+ gasPriceError: true,
+ tokenPriceError: true,
+ expectedErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx := tests.Context(t)
+
+ mockOrm := ccipmocks.NewORM(t)
+ if tc.gasPriceError {
+ mockOrm.On("GetGasPricesByDestChain", ctx, destChainSelector).Return(nil, fmt.Errorf("gas prices error")).Once()
+ } else {
+ mockOrm.On("GetGasPricesByDestChain", ctx, destChainSelector).Return(tc.ormGasPricesResult, nil).Once()
+ }
+ if tc.tokenPriceError {
+ mockOrm.On("GetTokenPricesByDestChain", ctx, destChainSelector).Return(nil, fmt.Errorf("token prices error")).Once()
+ } else {
+ mockOrm.On("GetTokenPricesByDestChain", ctx, destChainSelector).Return(tc.ormTokenPricesResult, nil).Once()
+ }
+
+ priceService := NewPriceService(
+ lggr,
+ mockOrm,
+ jobId,
+ destChainSelector,
+ sourceChainSelector,
+ "",
+ nil,
+ nil,
+ ).(*priceService)
+ gasPricesResult, tokenPricesResult, err := priceService.GetGasAndTokenPrices(ctx, destChainSelector)
+ if tc.expectedErr {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expectedGasPrices, gasPricesResult)
+ assert.Equal(t, tc.expectedTokenPrices, tokenPricesResult)
+ }
+ })
+ }
+}
+
+func val1e18(val int64) *big.Int {
+ return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(val))
+}
+
+func setupORM(t *testing.T) cciporm.ORM {
+ t.Helper()
+
+ db := pgtest.NewSqlxDB(t)
+ orm, err := cciporm.NewORM(db, logger.TestLogger(t))
+
+ require.NoError(t, err)
+
+ return orm
+}
+
+func checkResultLen(t *testing.T, priceService PriceService, destChainSelector uint64, gasCount int, tokenCount int) error {
+ ctx := tests.Context(t)
+ dbGasResult, dbTokenResult, err := priceService.GetGasAndTokenPrices(ctx, destChainSelector)
+ if err != nil {
+ return nil
+ }
+ if len(dbGasResult) != gasCount {
+ return fmt.Errorf("expected %d gas prices, got %d", gasCount, len(dbGasResult))
+ }
+ if len(dbTokenResult) != tokenCount {
+ return fmt.Errorf("expected %d token prices, got %d", tokenCount, len(dbTokenResult))
+ }
+ return nil
+}
+
+func TestPriceService_priceWriteInBackground(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ jobId := int32(1)
+ destChainSelector := uint64(12345)
+ sourceChainSelector := uint64(67890)
+ ctx := tests.Context(t)
+
+ sourceNative := cciptypes.Address(utils.RandomAddress().String())
+ feeToken := cciptypes.Address(utils.RandomAddress().String())
+ destToken1 := cciptypes.Address(utils.RandomAddress().String())
+ destToken2 := cciptypes.Address(utils.RandomAddress().String())
+
+ feeTokens := []cciptypes.Address{feeToken}
+ rampTokens := []cciptypes.Address{destToken1, destToken2}
+
+ laneTokens := []cciptypes.Address{sourceNative, feeToken, destToken1, destToken2}
+ // sort laneTokens
+ sort.Slice(laneTokens, func(i, j int) bool {
+ return laneTokens[i] < laneTokens[j]
+ })
+ laneTokenDecimals := []uint8{18, 18, 18, 18}
+
+ tokens := []cciptypes.Address{sourceNative, feeToken, destToken1, destToken2}
+ tokenPrices := []int64{2, 3, 4, 5}
+ gasPrice := big.NewInt(10)
+
+ orm := setupORM(t)
+
+ priceGetter := pricegetter.NewMockAllTokensPriceGetter(t)
+ defer priceGetter.AssertExpectations(t)
+
+ gasPriceEstimator := prices.NewMockGasPriceEstimatorCommit(t)
+ defer gasPriceEstimator.AssertExpectations(t)
+
+ priceGetter.On("TokenPricesUSD", mock.Anything, []cciptypes.Address{sourceNative}).Return(map[cciptypes.Address]*big.Int{
+ tokens[0]: val1e18(tokenPrices[0]),
+ }, nil)
+
+ priceGetter.On("GetJobSpecTokenPricesUSD", mock.Anything).Return(map[cciptypes.Address]*big.Int{
+ tokens[0]: val1e18(tokenPrices[0]),
+ tokens[1]: val1e18(tokenPrices[1]),
+ tokens[2]: val1e18(tokenPrices[2]),
+ tokens[3]: val1e18(tokenPrices[3]),
+ }, nil)
+
+ destTokens := append(rampTokens, sourceNative)
+ offRampReader := ccipdatamocks.NewOffRampReader(t)
+ offRampReader.On("GetTokens", mock.Anything).Return(cciptypes.OffRampTokens{
+ DestinationTokens: destTokens,
+ }, nil).Maybe()
+
+ gasPriceEstimator.On("GetGasPrice", mock.Anything).Return(gasPrice, nil)
+ pUSD := ccipcalc.CalculateUsdPerUnitGas(gasPrice, val1e18(tokenPrices[0]))
+ gasPriceEstimator.On("DenoteInUSD", mock.Anything, mock.Anything).Return(pUSD, nil)
+
+ destPriceReg := ccipdatamocks.NewPriceRegistryReader(t)
+ destPriceReg.On("GetTokensDecimals", mock.Anything, laneTokens).Return(laneTokenDecimals, nil).Maybe()
+ destPriceReg.On("GetFeeTokens", mock.Anything).Return(feeTokens, nil).Maybe()
+
+ priceService := NewPriceService(
+ lggr,
+ orm,
+ jobId,
+ destChainSelector,
+ sourceChainSelector,
+ tokens[0],
+ priceGetter,
+ offRampReader,
+ ).(*priceService)
+
+ gasUpdateInterval := 2000 * time.Millisecond
+ tokenUpdateInterval := 5000 * time.Millisecond
+
+ // run gas price task every 2 second
+ priceService.gasUpdateInterval = gasUpdateInterval
+ // run token price task every 5 second
+ priceService.tokenUpdateInterval = tokenUpdateInterval
+
+ // initially, db is empty
+ assert.NoError(t, checkResultLen(t, priceService, destChainSelector, 0, 0))
+
+ // starts PriceService in the background
+ assert.NoError(t, priceService.Start(ctx))
+
+ // setting dynamicConfig triggers initial price update
+ err := priceService.UpdateDynamicConfig(ctx, gasPriceEstimator, destPriceReg)
+ assert.NoError(t, err)
+ assert.NoError(t, checkResultLen(t, priceService, destChainSelector, 1, len(laneTokens)))
+
+ assert.NoError(t, priceService.Close())
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/logpollerutil/filters.go b/core/services/ocr2/plugins/ccip/internal/logpollerutil/filters.go
new file mode 100644
index 00000000000..e42dd8c154d
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/logpollerutil/filters.go
@@ -0,0 +1,73 @@
+package logpollerutil
+
+import (
+ "context"
+
+ "github.com/ethereum/go-ethereum/common"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+)
+
+func RegisterLpFilters(lp logpoller.LogPoller, filters []logpoller.Filter) error {
+ for _, lpFilter := range filters {
+ if filterContainsZeroAddress(lpFilter.Addresses) {
+ continue
+ }
+ // FIXME Dim pgOpts removed from LogPoller
+ if err := lp.RegisterFilter(context.Background(), lpFilter); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func UnregisterLpFilters(lp logpoller.LogPoller, filters []logpoller.Filter) error {
+ for _, lpFilter := range filters {
+ if filterContainsZeroAddress(lpFilter.Addresses) {
+ continue
+ }
+ // FIXME Dim pgOpts removed from LogPoller
+ if err := lp.UnregisterFilter(context.Background(), lpFilter.Name); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func FiltersDiff(filtersBefore, filtersNow []logpoller.Filter) (created, deleted []logpoller.Filter) {
+ created = make([]logpoller.Filter, 0, len(filtersNow))
+ deleted = make([]logpoller.Filter, 0, len(filtersBefore))
+
+ for _, f := range filtersNow {
+ if !containsFilter(filtersBefore, f) {
+ created = append(created, f)
+ }
+ }
+
+ for _, f := range filtersBefore {
+ if !containsFilter(filtersNow, f) {
+ deleted = append(deleted, f)
+ }
+ }
+
+ return created, deleted
+}
+
+func containsFilter(filters []logpoller.Filter, f logpoller.Filter) bool {
+ for _, existing := range filters {
+ if existing.Name == f.Name {
+ return true
+ }
+ }
+ return false
+}
+
+func filterContainsZeroAddress(addrs []common.Address) bool {
+ for _, addr := range addrs {
+ if addr == utils.ZeroAddress {
+ return true
+ }
+ }
+ return false
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/logpollerutil/filters_test.go b/core/services/ocr2/plugins/ccip/internal/logpollerutil/filters_test.go
new file mode 100644
index 00000000000..9ea08ec1421
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/logpollerutil/filters_test.go
@@ -0,0 +1,156 @@
+package logpollerutil
+
+import (
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+)
+
+func Test_FiltersDiff(t *testing.T) {
+ type args struct {
+ filtersBefore []logpoller.Filter
+ filtersNow []logpoller.Filter
+ }
+ tests := []struct {
+ name string
+ args args
+ wantCreated []logpoller.Filter
+ wantDeleted []logpoller.Filter
+ }{
+ {
+ name: "no diff, both empty",
+ args: args{
+ filtersBefore: []logpoller.Filter{},
+ filtersNow: []logpoller.Filter{},
+ },
+ wantCreated: []logpoller.Filter{},
+ wantDeleted: []logpoller.Filter{},
+ },
+ {
+ name: "no diff, both non-empty",
+ args: args{
+ filtersBefore: []logpoller.Filter{{Name: "a"}},
+ filtersNow: []logpoller.Filter{{Name: "a"}},
+ },
+ wantCreated: []logpoller.Filter{},
+ wantDeleted: []logpoller.Filter{},
+ },
+ {
+ name: "no diff, only name matters",
+ args: args{
+ filtersBefore: []logpoller.Filter{{Name: "a", Retention: time.Minute}},
+ filtersNow: []logpoller.Filter{{Name: "a", Retention: time.Second}},
+ },
+ wantCreated: []logpoller.Filter{},
+ wantDeleted: []logpoller.Filter{},
+ },
+ {
+ name: "diff for both created and deleted",
+ args: args{
+ filtersBefore: []logpoller.Filter{{Name: "e"}, {Name: "a"}, {Name: "b"}},
+ filtersNow: []logpoller.Filter{{Name: "a"}, {Name: "c"}, {Name: "d"}},
+ },
+ wantCreated: []logpoller.Filter{{Name: "c"}, {Name: "d"}},
+ wantDeleted: []logpoller.Filter{{Name: "e"}, {Name: "b"}},
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ gotCreated, gotDeleted := FiltersDiff(tt.args.filtersBefore, tt.args.filtersNow)
+ assert.Equalf(t, tt.wantCreated, gotCreated, "filtersDiff(%v, %v)", tt.args.filtersBefore, tt.args.filtersNow)
+ assert.Equalf(t, tt.wantDeleted, gotDeleted, "filtersDiff(%v, %v)", tt.args.filtersBefore, tt.args.filtersNow)
+ })
+ }
+}
+
+func Test_filterContainsZeroAddress(t *testing.T) {
+ type args struct {
+ addrs []common.Address
+ }
+ tests := []struct {
+ name string
+ args args
+ want bool
+ }{
+ {
+ name: "non-zero addrs",
+ args: args{
+ addrs: []common.Address{
+ common.HexToAddress("1"),
+ common.HexToAddress("2"),
+ common.HexToAddress("3"),
+ },
+ },
+ want: false,
+ },
+ {
+ name: "empty",
+ args: args{addrs: []common.Address{}},
+ want: false,
+ },
+ {
+ name: "zero addr",
+ args: args{
+ addrs: []common.Address{
+ common.HexToAddress("1"),
+ common.HexToAddress("0"),
+ common.HexToAddress("2"),
+ common.HexToAddress("3"),
+ },
+ },
+ want: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, filterContainsZeroAddress(tt.args.addrs), "filterContainsZeroAddress(%v)", tt.args.addrs)
+ })
+ }
+}
+
+func Test_containsFilter(t *testing.T) {
+ type args struct {
+ filters []logpoller.Filter
+ f logpoller.Filter
+ }
+ tests := []struct {
+ name string
+ args args
+ want bool
+ }{
+ {
+ name: "empty",
+ args: args{
+ filters: []logpoller.Filter{},
+ f: logpoller.Filter{},
+ },
+ want: false,
+ },
+ {
+ name: "contains",
+ args: args{
+ filters: []logpoller.Filter{{Name: "a"}, {Name: "b"}},
+ f: logpoller.Filter{Name: "b"},
+ },
+ want: true,
+ },
+ {
+ name: "does not contain",
+ args: args{
+ filters: []logpoller.Filter{{Name: "a"}, {Name: "b"}},
+ f: logpoller.Filter{Name: "c"},
+ },
+ want: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want,
+ containsFilter(tt.args.filters, tt.args.f), "containsFilter(%v, %v)", tt.args.filters, tt.args.f)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/observability/commit_store.go b/core/services/ocr2/plugins/ccip/internal/observability/commit_store.go
new file mode 100644
index 00000000000..6a1fb48f498
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/observability/commit_store.go
@@ -0,0 +1,75 @@
+package observability
+
+import (
+ "context"
+ "time"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+type ObservedCommitStoreReader struct {
+ ccipdata.CommitStoreReader
+ metric metricDetails
+}
+
+func NewObservedCommitStoreReader(origin ccipdata.CommitStoreReader, chainID int64, pluginName string) *ObservedCommitStoreReader {
+ return &ObservedCommitStoreReader{
+ CommitStoreReader: origin,
+ metric: metricDetails{
+ interactionDuration: readerHistogram,
+ resultSetSize: readerDatasetSize,
+ pluginName: pluginName,
+ readerName: "CommitStoreReader",
+ chainId: chainID,
+ },
+ }
+}
+
+func (o *ObservedCommitStoreReader) GetExpectedNextSequenceNumber(context context.Context) (uint64, error) {
+ return withObservedInteraction(o.metric, "GetExpectedNextSequenceNumber", func() (uint64, error) {
+ return o.CommitStoreReader.GetExpectedNextSequenceNumber(context)
+ })
+}
+
+func (o *ObservedCommitStoreReader) GetLatestPriceEpochAndRound(context context.Context) (uint64, error) {
+ return withObservedInteraction(o.metric, "GetLatestPriceEpochAndRound", func() (uint64, error) {
+ return o.CommitStoreReader.GetLatestPriceEpochAndRound(context)
+ })
+}
+
+func (o *ObservedCommitStoreReader) GetCommitReportMatchingSeqNum(ctx context.Context, seqNum uint64, confs int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return withObservedInteractionAndResults(o.metric, "GetCommitReportMatchingSeqNum", func() ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return o.CommitStoreReader.GetCommitReportMatchingSeqNum(ctx, seqNum, confs)
+ })
+}
+
+func (o *ObservedCommitStoreReader) GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confs int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return withObservedInteractionAndResults(o.metric, "GetAcceptedCommitReportsGteTimestamp", func() ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return o.CommitStoreReader.GetAcceptedCommitReportsGteTimestamp(ctx, ts, confs)
+ })
+}
+
+func (o *ObservedCommitStoreReader) IsDown(ctx context.Context) (bool, error) {
+ return withObservedInteraction(o.metric, "IsDown", func() (bool, error) {
+ return o.CommitStoreReader.IsDown(ctx)
+ })
+}
+
+func (o *ObservedCommitStoreReader) IsBlessed(ctx context.Context, root [32]byte) (bool, error) {
+ return withObservedInteraction(o.metric, "IsBlessed", func() (bool, error) {
+ return o.CommitStoreReader.IsBlessed(ctx, root)
+ })
+}
+
+func (o *ObservedCommitStoreReader) VerifyExecutionReport(ctx context.Context, report cciptypes.ExecReport) (bool, error) {
+ return withObservedInteraction(o.metric, "VerifyExecutionReport", func() (bool, error) {
+ return o.CommitStoreReader.VerifyExecutionReport(ctx, report)
+ })
+}
+
+func (o *ObservedCommitStoreReader) GetCommitStoreStaticConfig(ctx context.Context) (cciptypes.CommitStoreStaticConfig, error) {
+ return withObservedInteraction(o.metric, "GetCommitStoreStaticConfig", func() (cciptypes.CommitStoreStaticConfig, error) {
+ return o.CommitStoreReader.GetCommitStoreStaticConfig(ctx)
+ })
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/observability/metrics.go b/core/services/ocr2/plugins/ccip/internal/observability/metrics.go
new file mode 100644
index 00000000000..9e161fdd9ae
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/observability/metrics.go
@@ -0,0 +1,75 @@
+package observability
+
+import (
+ "strconv"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+)
+
+var (
+ latencyBuckets = []float64{
+ float64(10 * time.Millisecond),
+ float64(25 * time.Millisecond),
+ float64(50 * time.Millisecond),
+ float64(75 * time.Millisecond),
+ float64(100 * time.Millisecond),
+ float64(200 * time.Millisecond),
+ float64(300 * time.Millisecond),
+ float64(400 * time.Millisecond),
+ float64(500 * time.Millisecond),
+ float64(750 * time.Millisecond),
+ float64(1 * time.Second),
+ float64(2 * time.Second),
+ float64(3 * time.Second),
+ float64(4 * time.Second),
+ }
+ labels = []string{"evmChainID", "plugin", "reader", "function", "success"}
+ readerHistogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Name: "ccip_reader_duration",
+ Help: "Duration of calls to Reader instance",
+ Buckets: latencyBuckets,
+ }, labels)
+ readerDatasetSize = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "ccip_reader_dataset_size",
+ Help: "Size of the dataset returned from the Reader instance",
+ }, labels)
+)
+
+type metricDetails struct {
+ interactionDuration *prometheus.HistogramVec
+ resultSetSize *prometheus.GaugeVec
+ pluginName string
+ readerName string
+ chainId int64
+}
+
+func withObservedInteraction[T any](metric metricDetails, function string, f func() (T, error)) (T, error) {
+ contractExecutionStarted := time.Now()
+ value, err := f()
+ metric.interactionDuration.
+ WithLabelValues(
+ strconv.FormatInt(metric.chainId, 10),
+ metric.pluginName,
+ metric.readerName,
+ function,
+ strconv.FormatBool(err == nil),
+ ).
+ Observe(float64(time.Since(contractExecutionStarted)))
+ return value, err
+}
+
+func withObservedInteractionAndResults[T any](metric metricDetails, function string, f func() ([]T, error)) ([]T, error) {
+ results, err := withObservedInteraction(metric, function, f)
+ if err == nil {
+ metric.resultSetSize.WithLabelValues(
+ strconv.FormatInt(metric.chainId, 10),
+ metric.pluginName,
+ metric.readerName,
+ function,
+ strconv.FormatBool(err == nil),
+ ).Set(float64(len(results)))
+ }
+ return results, err
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/observability/metrics_test.go b/core/services/ocr2/plugins/ccip/internal/observability/metrics_test.go
new file mode 100644
index 00000000000..3d84acf9616
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/observability/metrics_test.go
@@ -0,0 +1,87 @@
+package observability
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/prometheus/client_golang/prometheus"
+ io_prometheus_client "github.com/prometheus/client_model/go"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ ccipdatamocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+)
+
+func TestProperLabelsArePassed(t *testing.T) {
+ histogram := readerHistogram
+ successCounter := 10
+ failedCounter := 5
+
+ details := metricDetails{
+ interactionDuration: histogram,
+ pluginName: "plugin",
+ readerName: "reader",
+ chainId: 123,
+ }
+
+ for i := 0; i < successCounter; i++ {
+ _, err := withObservedInteraction[string](details, "successFun", successfulContract)
+ require.NoError(t, err)
+ }
+
+ for i := 0; i < failedCounter; i++ {
+ _, err := withObservedInteraction[string](details, "failedFun", failedContract)
+ require.Error(t, err)
+ }
+
+ assert.Equal(t, successCounter, counterFromHistogramByLabels(t, histogram, "123", "plugin", "reader", "successFun", "true"))
+ assert.Equal(t, failedCounter, counterFromHistogramByLabels(t, histogram, "123", "plugin", "reader", "failedFun", "false"))
+
+ assert.Equal(t, 0, counterFromHistogramByLabels(t, histogram, "123", "plugin", "reader", "failedFun", "true"))
+ assert.Equal(t, 0, counterFromHistogramByLabels(t, histogram, "123", "plugin", "reader", "successFun", "false"))
+}
+
+func TestMetricsSendFromContractDirectly(t *testing.T) {
+ expectedCounter := 4
+ ctx := testutils.Context(t)
+ chainId := int64(420)
+
+ mockedOfframp := ccipdatamocks.NewOffRampReader(t)
+ mockedOfframp.On("GetTokens", ctx).Return(cciptypes.OffRampTokens{}, fmt.Errorf("execution error"))
+
+ observedOfframp := NewObservedOffRampReader(mockedOfframp, chainId, "plugin")
+
+ for i := 0; i < expectedCounter; i++ {
+ _, _ = observedOfframp.GetTokens(ctx)
+ }
+
+ assert.Equal(t, expectedCounter, counterFromHistogramByLabels(t, observedOfframp.metric.interactionDuration, "420", "plugin", "OffRampReader", "GetTokens", "false"))
+ assert.Equal(t, 0, counterFromHistogramByLabels(t, observedOfframp.metric.interactionDuration, "420", "plugin", "OffRampReader", "GetPoolByDestToken", "false"))
+ assert.Equal(t, 0, counterFromHistogramByLabels(t, observedOfframp.metric.interactionDuration, "420", "plugin", "OffRampReader", "GetPoolByDestToken", "true"))
+}
+
+func counterFromHistogramByLabels(t *testing.T, histogramVec *prometheus.HistogramVec, labels ...string) int {
+ observer, err := histogramVec.GetMetricWithLabelValues(labels...)
+ require.NoError(t, err)
+
+ metricCh := make(chan prometheus.Metric, 1)
+ observer.(prometheus.Histogram).Collect(metricCh)
+ close(metricCh)
+
+ metric := <-metricCh
+ pb := &io_prometheus_client.Metric{}
+ err = metric.Write(pb)
+ require.NoError(t, err)
+
+ return int(pb.GetHistogram().GetSampleCount())
+}
+
+func successfulContract() (string, error) {
+ return "success", nil
+}
+
+func failedContract() (string, error) {
+ return "", fmt.Errorf("just error")
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/observability/offramp.go b/core/services/ocr2/plugins/ccip/internal/observability/offramp.go
new file mode 100644
index 00000000000..b426bc8c91d
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/observability/offramp.go
@@ -0,0 +1,69 @@
+package observability
+
+import (
+ "context"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+type ObservedOffRampReader struct {
+ ccipdata.OffRampReader
+ metric metricDetails
+}
+
+func NewObservedOffRampReader(origin ccipdata.OffRampReader, chainID int64, pluginName string) *ObservedOffRampReader {
+ return &ObservedOffRampReader{
+ OffRampReader: origin,
+ metric: metricDetails{
+ interactionDuration: readerHistogram,
+ resultSetSize: readerDatasetSize,
+ pluginName: pluginName,
+ readerName: "OffRampReader",
+ chainId: chainID,
+ },
+ }
+}
+
+func (o *ObservedOffRampReader) GetExecutionStateChangesBetweenSeqNums(ctx context.Context, seqNumMin, seqNumMax uint64, confs int) ([]cciptypes.ExecutionStateChangedWithTxMeta, error) {
+ return withObservedInteraction(o.metric, "GetExecutionStateChangesBetweenSeqNums", func() ([]cciptypes.ExecutionStateChangedWithTxMeta, error) {
+ return o.OffRampReader.GetExecutionStateChangesBetweenSeqNums(ctx, seqNumMin, seqNumMax, confs)
+ })
+}
+
+func (o *ObservedOffRampReader) CurrentRateLimiterState(ctx context.Context) (cciptypes.TokenBucketRateLimit, error) {
+ return withObservedInteraction(o.metric, "CurrentRateLimiterState", func() (cciptypes.TokenBucketRateLimit, error) {
+ return o.OffRampReader.CurrentRateLimiterState(ctx)
+ })
+}
+
+func (o *ObservedOffRampReader) GetExecutionState(ctx context.Context, sequenceNumber uint64) (uint8, error) {
+ return withObservedInteraction(o.metric, "GetExecutionState", func() (uint8, error) {
+ return o.OffRampReader.GetExecutionState(ctx, sequenceNumber)
+ })
+}
+
+func (o *ObservedOffRampReader) GetStaticConfig(ctx context.Context) (cciptypes.OffRampStaticConfig, error) {
+ return withObservedInteraction(o.metric, "GetStaticConfig", func() (cciptypes.OffRampStaticConfig, error) {
+ return o.OffRampReader.GetStaticConfig(ctx)
+ })
+}
+
+func (o *ObservedOffRampReader) GetSourceToDestTokensMapping(ctx context.Context) (map[cciptypes.Address]cciptypes.Address, error) {
+ return withObservedInteraction(o.metric, "GetSourceToDestTokensMapping", func() (map[cciptypes.Address]cciptypes.Address, error) {
+ return o.OffRampReader.GetSourceToDestTokensMapping(ctx)
+ })
+}
+
+func (o *ObservedOffRampReader) GetTokens(ctx context.Context) (cciptypes.OffRampTokens, error) {
+ return withObservedInteraction(o.metric, "GetTokens", func() (cciptypes.OffRampTokens, error) {
+ return o.OffRampReader.GetTokens(ctx)
+ })
+}
+
+func (o *ObservedOffRampReader) GetSendersNonce(ctx context.Context, senders []cciptypes.Address) (map[cciptypes.Address]uint64, error) {
+ return withObservedInteraction(o.metric, "ListSenderNonces", func() (map[cciptypes.Address]uint64, error) {
+ return o.OffRampReader.ListSenderNonces(ctx, senders)
+ })
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/observability/onramp.go b/core/services/ocr2/plugins/ccip/internal/observability/onramp.go
new file mode 100644
index 00000000000..b167bd57b06
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/observability/onramp.go
@@ -0,0 +1,63 @@
+package observability
+
+import (
+ "context"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+type ObservedOnRampReader struct {
+ ccipdata.OnRampReader
+ metric metricDetails
+}
+
+func NewObservedOnRampReader(origin ccipdata.OnRampReader, chainID int64, pluginName string) *ObservedOnRampReader {
+ return &ObservedOnRampReader{
+ OnRampReader: origin,
+ metric: metricDetails{
+ interactionDuration: readerHistogram,
+ resultSetSize: readerDatasetSize,
+ pluginName: pluginName,
+ readerName: "OnRampReader",
+ chainId: chainID,
+ },
+ }
+}
+
+func (o ObservedOnRampReader) GetSendRequestsBetweenSeqNums(ctx context.Context, seqNumMin, seqNumMax uint64, finalized bool) ([]cciptypes.EVM2EVMMessageWithTxMeta, error) {
+ return withObservedInteractionAndResults(o.metric, "GetSendRequestsBetweenSeqNums", func() ([]cciptypes.EVM2EVMMessageWithTxMeta, error) {
+ return o.OnRampReader.GetSendRequestsBetweenSeqNums(ctx, seqNumMin, seqNumMax, finalized)
+ })
+}
+
+func (o ObservedOnRampReader) RouterAddress(ctx context.Context) (cciptypes.Address, error) {
+ return withObservedInteraction(o.metric, "RouterAddress", func() (cciptypes.Address, error) {
+ return o.OnRampReader.RouterAddress(ctx)
+ })
+}
+
+func (o ObservedOnRampReader) GetDynamicConfig(ctx context.Context) (cciptypes.OnRampDynamicConfig, error) {
+ return withObservedInteraction(o.metric, "GetDynamicConfig", func() (cciptypes.OnRampDynamicConfig, error) {
+ return o.OnRampReader.GetDynamicConfig(ctx)
+ })
+}
+
+func (o ObservedOnRampReader) IsSourceCursed(ctx context.Context) (bool, error) {
+ return withObservedInteraction(o.metric, "IsSourceCursed", func() (bool, error) {
+ return o.OnRampReader.IsSourceCursed(ctx)
+ })
+}
+
+func (o ObservedOnRampReader) IsSourceChainHealthy(ctx context.Context) (bool, error) {
+ return withObservedInteraction(o.metric, "IsSourceChainHealthy", func() (bool, error) {
+ return o.OnRampReader.IsSourceChainHealthy(ctx)
+ })
+}
+
+func (o ObservedOnRampReader) SourcePriceRegistryAddress(ctx context.Context) (cciptypes.Address, error) {
+ return withObservedInteraction(o.metric, "SourcePriceRegistryAddress", func() (cciptypes.Address, error) {
+ return o.OnRampReader.SourcePriceRegistryAddress(ctx)
+ })
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/observability/onramp_observed_test.go b/core/services/ocr2/plugins/ccip/internal/observability/onramp_observed_test.go
new file mode 100644
index 00000000000..1918f632b94
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/observability/onramp_observed_test.go
@@ -0,0 +1,155 @@
+package observability
+
+import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+ "testing"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+)
+
+type MethodCall struct {
+ MethodName string
+ Arguments []interface{}
+ Returns []interface{}
+}
+
+// The class expected to override the observed methods.
+const expectedWrapper = "core/services/ocr2/plugins/ccip/internal/observability.ObservedOnRampReader"
+
+// TestOnRampObservedMethods tests that all methods of OnRampReader are observed by a wrapper.
+// It uses the runtime to detect if the call stack contains the wrapper class.
+func TestOnRampObservedMethods(t *testing.T) {
+ // Methods not expected to be observed.
+ // Add a method name here to exclude it from the test.
+ excludedMethods := []string{
+ "Address",
+ "Close",
+ }
+
+ // Defines the overridden method calls to test.
+ // Not defining a non-excluded method here will cause the test to fail with an explicit error.
+ methodCalls := make(map[string]MethodCall)
+ methodCalls["GetDynamicConfig"] = MethodCall{
+ MethodName: "GetDynamicConfig",
+ Arguments: []interface{}{testutils.Context(t)},
+ Returns: []interface{}{cciptypes.OnRampDynamicConfig{}, nil},
+ }
+ methodCalls["GetSendRequestsBetweenSeqNums"] = MethodCall{
+ MethodName: "GetSendRequestsBetweenSeqNums",
+ Arguments: []interface{}{testutils.Context(t), uint64(0), uint64(100), true},
+ Returns: []interface{}{nil, nil},
+ }
+ methodCalls["IsSourceChainHealthy"] = MethodCall{
+ MethodName: "IsSourceChainHealthy",
+ Arguments: []interface{}{testutils.Context(t)},
+ Returns: []interface{}{false, nil},
+ }
+ methodCalls["IsSourceCursed"] = MethodCall{
+ MethodName: "IsSourceCursed",
+ Arguments: []interface{}{testutils.Context(t)},
+ Returns: []interface{}{false, nil},
+ }
+ methodCalls["RouterAddress"] = MethodCall{
+ MethodName: "RouterAddress",
+ Arguments: []interface{}{testutils.Context(t)},
+ Returns: []interface{}{cciptypes.Address("0x0"), nil},
+ }
+ methodCalls["SourcePriceRegistryAddress"] = MethodCall{
+ MethodName: "SourcePriceRegistryAddress",
+ Arguments: []interface{}{testutils.Context(t)},
+ Returns: []interface{}{cciptypes.Address("0x0"), nil},
+ }
+
+ // Test each method defined in the embedded type.
+ observed, reader := buildReader(t)
+ observedType := reflect.TypeOf(observed)
+ for i := 0; i < observedType.NumMethod(); i++ {
+ method := observedType.Method(i)
+ testMethod(t, method, methodCalls, excludedMethods, reader, observed)
+ }
+}
+
+func testMethod(t *testing.T, method reflect.Method, methodCalls map[string]MethodCall, excludedMethods []string, reader *mocks.OnRampReader, observed ObservedOnRampReader) {
+ t.Run(fmt.Sprintf("observability_wrapper_%s", method.Name), func(t *testing.T) {
+ // Skip excluded methods.
+ for _, em := range excludedMethods {
+ if method.Name == em {
+ // Skipping ignore method (not an error).
+ return
+ }
+ }
+
+ // Retrieve method call from definition (fail if not present).
+ mc := methodCalls[method.Name]
+ if mc.MethodName == "" {
+ assert.Fail(t, fmt.Sprintf("method %s not defined in methodCalls, please define it or exclude it.", method.Name))
+ return
+ }
+
+ assertCallByWrapper(t, reader, mc)
+
+ // Perform call on observed object.
+ callParams := buildCallParams(mc)
+ methodc := reflect.ValueOf(&observed).MethodByName(mc.MethodName)
+ methodc.Call(callParams)
+ })
+}
+
+// Set the mock to fail if not called by the wrapper.
+func assertCallByWrapper(t *testing.T, reader *mocks.OnRampReader, mc MethodCall) {
+ reader.On(mc.MethodName, mc.Arguments...).Maybe().Return(mc.Returns...).Run(func(args mock.Arguments) {
+ var i = 0
+ var pc uintptr
+ var ok = true
+ for ok {
+ pc, _, _, ok = runtime.Caller(i)
+ f := runtime.FuncForPC(pc)
+ if strings.Contains(f.Name(), expectedWrapper) {
+ // Found the expected wrapper in the call stack.
+ return
+ }
+ i++
+ }
+ assert.Fail(t, fmt.Sprintf("method %s not observed by wrapper. Please implement the method or add it to the excluded list.", mc.MethodName))
+ })
+}
+
+func buildCallParams(mc MethodCall) []reflect.Value {
+ callParams := make([]reflect.Value, len(mc.Arguments))
+ for i, arg := range mc.Arguments {
+ callParams[i] = reflect.ValueOf(arg)
+ }
+ return callParams
+}
+
+// Build a mock reader and an observed wrapper to be used in the tests.
+func buildReader(t *testing.T) (ObservedOnRampReader, *mocks.OnRampReader) {
+ labels = []string{"evmChainID", "plugin", "reader", "function", "success"}
+ ph := promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Name: "test_histogram",
+ }, labels)
+ pg := promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "test_gauge",
+ }, labels)
+ metric := metricDetails{
+ interactionDuration: ph,
+ resultSetSize: pg,
+ pluginName: "test plugin",
+ readerName: "test reader",
+ chainId: 1337,
+ }
+ reader := mocks.NewOnRampReader(t)
+ observed := ObservedOnRampReader{reader, metric}
+ return observed, reader
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/observability/price_registry.go b/core/services/ocr2/plugins/ccip/internal/observability/price_registry.go
new file mode 100644
index 00000000000..f5b87686d35
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/observability/price_registry.go
@@ -0,0 +1,64 @@
+package observability
+
+import (
+ "context"
+ "time"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+)
+
+type ObservedPriceRegistryReader struct {
+ ccipdata.PriceRegistryReader
+ metric metricDetails
+}
+
+func NewPriceRegistryReader(origin ccipdata.PriceRegistryReader, chainID int64, pluginName string) *ObservedPriceRegistryReader {
+ return &ObservedPriceRegistryReader{
+ PriceRegistryReader: origin,
+ metric: metricDetails{
+ interactionDuration: readerHistogram,
+ resultSetSize: readerDatasetSize,
+ pluginName: pluginName,
+ readerName: "PriceRegistryReader",
+ chainId: chainID,
+ },
+ }
+}
+
+func (o *ObservedPriceRegistryReader) GetTokenPriceUpdatesCreatedAfter(ctx context.Context, ts time.Time, confs int) ([]cciptypes.TokenPriceUpdateWithTxMeta, error) {
+ return withObservedInteractionAndResults(o.metric, "GetTokenPriceUpdatesCreatedAfter", func() ([]cciptypes.TokenPriceUpdateWithTxMeta, error) {
+ return o.PriceRegistryReader.GetTokenPriceUpdatesCreatedAfter(ctx, ts, confs)
+ })
+}
+
+func (o *ObservedPriceRegistryReader) GetGasPriceUpdatesCreatedAfter(ctx context.Context, chainSelector uint64, ts time.Time, confs int) ([]cciptypes.GasPriceUpdateWithTxMeta, error) {
+ return withObservedInteractionAndResults(o.metric, "GetGasPriceUpdatesCreatedAfter", func() ([]cciptypes.GasPriceUpdateWithTxMeta, error) {
+ return o.PriceRegistryReader.GetGasPriceUpdatesCreatedAfter(ctx, chainSelector, ts, confs)
+ })
+}
+
+func (o *ObservedPriceRegistryReader) GetAllGasPriceUpdatesCreatedAfter(ctx context.Context, ts time.Time, confs int) ([]cciptypes.GasPriceUpdateWithTxMeta, error) {
+ return withObservedInteractionAndResults(o.metric, "GetAllGasPriceUpdatesCreatedAfter", func() ([]cciptypes.GasPriceUpdateWithTxMeta, error) {
+ return o.PriceRegistryReader.GetAllGasPriceUpdatesCreatedAfter(ctx, ts, confs)
+ })
+}
+
+func (o *ObservedPriceRegistryReader) GetFeeTokens(ctx context.Context) ([]cciptypes.Address, error) {
+ return withObservedInteraction(o.metric, "GetFeeTokens", func() ([]cciptypes.Address, error) {
+ return o.PriceRegistryReader.GetFeeTokens(ctx)
+ })
+}
+
+func (o *ObservedPriceRegistryReader) GetTokenPrices(ctx context.Context, wantedTokens []cciptypes.Address) ([]cciptypes.TokenPriceUpdate, error) {
+ return withObservedInteractionAndResults(o.metric, "GetTokenPrices", func() ([]cciptypes.TokenPriceUpdate, error) {
+ return o.PriceRegistryReader.GetTokenPrices(ctx, wantedTokens)
+ })
+}
+
+func (o *ObservedPriceRegistryReader) GetTokensDecimals(ctx context.Context, tokenAddresses []cciptypes.Address) ([]uint8, error) {
+ return withObservedInteractionAndResults(o.metric, "GetTokensDecimals", func() ([]uint8, error) {
+ return o.PriceRegistryReader.GetTokensDecimals(ctx, tokenAddresses)
+ })
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/oraclelib/backfilled_oracle.go b/core/services/ocr2/plugins/ccip/internal/oraclelib/backfilled_oracle.go
new file mode 100644
index 00000000000..d2851e3a079
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/oraclelib/backfilled_oracle.go
@@ -0,0 +1,218 @@
+package oraclelib
+
+import (
+ "context"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services"
+
+ "go.uber.org/multierr"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+)
+
+type BackfilledOracle struct {
+ srcStartBlock, dstStartBlock uint64
+ oracleStarted atomic.Bool
+ cancelFn context.CancelFunc
+ src, dst logpoller.LogPoller
+ oracle job.ServiceCtx
+ lggr logger.Logger
+}
+
+func NewBackfilledOracle(lggr logger.Logger, src, dst logpoller.LogPoller, srcStartBlock, dstStartBlock uint64, oracle job.ServiceCtx) *BackfilledOracle {
+ return &BackfilledOracle{
+ srcStartBlock: srcStartBlock,
+ dstStartBlock: dstStartBlock,
+ oracleStarted: atomic.Bool{},
+ cancelFn: nil,
+ src: src,
+ dst: dst,
+ oracle: oracle,
+ lggr: lggr,
+ }
+}
+
+func (r *BackfilledOracle) Start(_ context.Context) error {
+ go r.Run()
+ return nil
+}
+
+func (r *BackfilledOracle) IsRunning() bool {
+ return r.oracleStarted.Load()
+}
+
+func (r *BackfilledOracle) Run() {
+ ctx, cancelFn := context.WithCancel(context.Background())
+ r.cancelFn = cancelFn
+ var err error
+ var errMu sync.Mutex
+ var wg sync.WaitGroup
+ // Replay in parallel if both requested.
+ if r.srcStartBlock != 0 {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ s := time.Now()
+ r.lggr.Infow("start replaying src chain", "fromBlock", r.srcStartBlock)
+ srcReplayErr := r.src.Replay(ctx, int64(r.srcStartBlock))
+ errMu.Lock()
+ err = multierr.Combine(err, srcReplayErr)
+ errMu.Unlock()
+ r.lggr.Infow("finished replaying src chain", "time", time.Since(s))
+ }()
+ }
+ if r.dstStartBlock != 0 {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ s := time.Now()
+ r.lggr.Infow("start replaying dst chain", "fromBlock", r.dstStartBlock)
+ dstReplayErr := r.dst.Replay(ctx, int64(r.dstStartBlock))
+ errMu.Lock()
+ err = multierr.Combine(err, dstReplayErr)
+ errMu.Unlock()
+ r.lggr.Infow("finished replaying dst chain", "time", time.Since(s))
+ }()
+ }
+ wg.Wait()
+ if err != nil {
+ r.lggr.Criticalw("unexpected error replaying, continuing plugin boot without all the logs backfilled", "err", err)
+ }
+ if err := ctx.Err(); err != nil {
+ r.lggr.Errorw("context already cancelled", "err", err)
+ return
+ }
+ // Start oracle with all logs present from dstStartBlock on dst and
+ // all logs from srcStartBlock on src.
+ if err := r.oracle.Start(ctx); err != nil {
+ // Should never happen.
+ r.lggr.Errorw("unexpected error starting oracle", "err", err)
+ } else {
+ r.oracleStarted.Store(true)
+ }
+}
+
+func (r *BackfilledOracle) Close() error {
+ if r.oracleStarted.Load() {
+ // If the oracle is running, it must be Closed/stopped
+ if err := r.oracle.Close(); err != nil {
+ r.lggr.Errorw("unexpected error stopping oracle", "err", err)
+ return err
+ }
+ // Flag the oracle as closed with our internal variable that keeps track
+ // of its state. This will allow to re-start the process
+ r.oracleStarted.Store(false)
+ }
+ if r.cancelFn != nil {
+ // This is useful to step the previous tasks that are spawned in
+ // parallel before starting the Oracle. This will use the context to
+ // signal them to exit immediately.
+ //
+ // It can be possible this is the only way to stop the Start() async
+ // flow, specially when the previusly task are running (the replays) and
+ // `oracleStarted` would be false in that example. Calling `cancelFn()`
+ // will stop the replays and will prevent the oracle to start
+ r.cancelFn()
+ }
+ return nil
+}
+
+func NewChainAgnosticBackFilledOracle(lggr logger.Logger, srcProvider services.ServiceCtx, dstProvider services.ServiceCtx, oracle job.ServiceCtx) *ChainAgnosticBackFilledOracle {
+ return &ChainAgnosticBackFilledOracle{
+ srcProvider: srcProvider,
+ dstProvider: dstProvider,
+ oracle: oracle,
+ lggr: lggr,
+ }
+}
+
+type ChainAgnosticBackFilledOracle struct {
+ srcProvider services.ServiceCtx
+ dstProvider services.ServiceCtx
+ oracle job.ServiceCtx
+ lggr logger.Logger
+ oracleStarted atomic.Bool
+ cancelFn context.CancelFunc
+}
+
+func (r *ChainAgnosticBackFilledOracle) Start(_ context.Context) error {
+ go r.run()
+ return nil
+}
+
+func (r *ChainAgnosticBackFilledOracle) run() {
+ ctx, cancelFn := context.WithCancel(context.Background())
+ r.cancelFn = cancelFn
+ var err error
+ var errMu sync.Mutex
+ var wg sync.WaitGroup
+ // Replay in parallel if both requested.
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ s := time.Now()
+ srcReplayErr := r.srcProvider.Start(ctx)
+ errMu.Lock()
+ err = multierr.Combine(err, srcReplayErr)
+ errMu.Unlock()
+ r.lggr.Infow("finished replaying src chain", "time", time.Since(s))
+ }()
+
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ s := time.Now()
+ dstReplayErr := r.dstProvider.Start(ctx)
+ errMu.Lock()
+ err = multierr.Combine(err, dstReplayErr)
+ errMu.Unlock()
+ r.lggr.Infow("finished replaying dst chain", "time", time.Since(s))
+ }()
+
+ wg.Wait()
+ if err != nil {
+ r.lggr.Criticalw("unexpected error replaying, continuing plugin boot without all the logs backfilled", "err", err)
+ }
+ if err := ctx.Err(); err != nil {
+ r.lggr.Errorw("context already cancelled", "err", err)
+ }
+ // Start oracle with all logs present from dstStartBlock on dst and
+ // all logs from srcStartBlock on src.
+ if err := r.oracle.Start(ctx); err != nil {
+ // Should never happen.
+ r.lggr.Errorw("unexpected error starting oracle", "err", err)
+ } else {
+ r.oracleStarted.Store(true)
+ }
+}
+
+func (r *ChainAgnosticBackFilledOracle) Close() error {
+ if r.oracleStarted.Load() {
+ // If the oracle is running, it must be Closed/stopped
+ // TODO: Close should be safe to call in either case?
+ if err := r.oracle.Close(); err != nil {
+ r.lggr.Errorw("unexpected error stopping oracle", "err", err)
+ return err
+ }
+ // Flag the oracle as closed with our internal variable that keeps track
+ // of its state. This will allow to re-start the process
+ r.oracleStarted.Store(false)
+ }
+ if r.cancelFn != nil {
+ // This is useful to step the previous tasks that are spawned in
+ // parallel before starting the Oracle. This will use the context to
+ // signal them to exit immediately.
+ //
+ // It can be possible this is the only way to stop the Start() async
+ // flow, specially when the previusly task are running (the replays) and
+ // `oracleStarted` would be false in that example. Calling `cancelFn()`
+ // will stop the replays and will prevent the oracle to start
+ r.cancelFn()
+ }
+ return nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/oraclelib/backfilled_oracle_test.go b/core/services/ocr2/plugins/ccip/internal/oraclelib/backfilled_oracle_test.go
new file mode 100644
index 00000000000..6db1ebbadd9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/oraclelib/backfilled_oracle_test.go
@@ -0,0 +1,56 @@
+package oraclelib
+
+import (
+ "testing"
+
+ "github.com/pkg/errors"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ jobmocks "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks"
+)
+
+func TestBackfilledOracle(t *testing.T) {
+ // First scenario: Start() fails, check that all Replay are being called.
+ lp1 := lpmocks.NewLogPoller(t)
+ lp2 := lpmocks.NewLogPoller(t)
+ lp1.On("Replay", mock.Anything, int64(1)).Return(nil)
+ lp2.On("Replay", mock.Anything, int64(2)).Return(nil)
+ oracle1 := jobmocks.NewServiceCtx(t)
+ oracle1.On("Start", mock.Anything).Return(errors.New("Failed to start")).Twice()
+ job := NewBackfilledOracle(logger.TestLogger(t), lp1, lp2, 1, 2, oracle1)
+
+ job.Run()
+ assert.False(t, job.IsRunning())
+ job.Run()
+ assert.False(t, job.IsRunning())
+
+ /// Start -> Stop -> Start
+ oracle2 := jobmocks.NewServiceCtx(t)
+ oracle2.On("Start", mock.Anything).Return(nil).Twice()
+ oracle2.On("Close").Return(nil).Once()
+
+ job2 := NewBackfilledOracle(logger.TestLogger(t), lp1, lp2, 1, 2, oracle2)
+ job2.Run()
+ assert.True(t, job2.IsRunning())
+ assert.Nil(t, job2.Close())
+ assert.False(t, job2.IsRunning())
+ assert.Nil(t, job2.Close())
+ assert.False(t, job2.IsRunning())
+ job2.Run()
+ assert.True(t, job2.IsRunning())
+
+ /// Replay fails, but it starts anyway
+ lp11 := lpmocks.NewLogPoller(t)
+ lp12 := lpmocks.NewLogPoller(t)
+ lp11.On("Replay", mock.Anything, int64(1)).Return(errors.New("Replay failed")).Once()
+ lp12.On("Replay", mock.Anything, int64(2)).Return(errors.New("Replay failed")).Once()
+
+ oracle := jobmocks.NewServiceCtx(t)
+ oracle.On("Start", mock.Anything).Return(nil).Once()
+ job3 := NewBackfilledOracle(logger.NullLogger, lp11, lp12, 1, 2, oracle)
+ job3.Run()
+ assert.True(t, job3.IsRunning())
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/parseutil/bigint.go b/core/services/ocr2/plugins/ccip/internal/parseutil/bigint.go
new file mode 100644
index 00000000000..48d0d261653
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/parseutil/bigint.go
@@ -0,0 +1,44 @@
+package parseutil
+
+import (
+ "math/big"
+
+ "github.com/pkg/errors"
+ "github.com/shopspring/decimal"
+)
+
+func ParseBigIntFromAny(val any) (*big.Int, error) {
+ if val == nil {
+ return nil, errors.Errorf("nil value passed")
+ }
+
+ switch v := val.(type) {
+ case decimal.Decimal:
+ return ParseBigIntFromString(v.String())
+ case *decimal.Decimal:
+ return ParseBigIntFromString(v.String())
+ case *big.Int:
+ return v, nil
+ case string:
+ return ParseBigIntFromString(v)
+ case int:
+ return big.NewInt(int64(v)), nil
+ case int64:
+ return big.NewInt(v), nil
+ case float64:
+ i := new(big.Int)
+ big.NewFloat(v).Int(i)
+ return i, nil
+ default:
+ return nil, errors.Errorf("unsupported big int type %T", val)
+ }
+}
+
+func ParseBigIntFromString(v string) (*big.Int, error) {
+ valBigInt, success := new(big.Int).SetString(v, 10)
+ if !success {
+ return nil, errors.Errorf("unable to convert to integer %s", v)
+ }
+
+ return valBigInt, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/parseutil/bigint_test.go b/core/services/ocr2/plugins/ccip/internal/parseutil/bigint_test.go
new file mode 100644
index 00000000000..cea2f8cc19c
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/parseutil/bigint_test.go
@@ -0,0 +1,42 @@
+package parseutil
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/shopspring/decimal"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestParseBigIntFromAny(t *testing.T) {
+ decimalVal := decimal.New(123, 0)
+
+ testCases := []struct {
+ name string
+ val any
+ res *big.Int
+ expErr bool
+ }{
+ {name: "nil", val: nil, expErr: true},
+ {name: "string", val: "123", res: big.NewInt(123)},
+ {name: "decimal", val: decimal.New(123, 0), res: big.NewInt(123)},
+ {name: "decimal pointer", val: &decimalVal, res: big.NewInt(123)},
+ {name: "int64", val: int64(123), res: big.NewInt(123)},
+ {name: "int", val: 123, res: big.NewInt(123)},
+ {name: "float", val: 123.12, res: big.NewInt(123)},
+ {name: "uint8", val: uint8(12), expErr: true},
+ {name: "struct", val: struct{ name string }{name: "asd"}, expErr: true},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ res, err := ParseBigIntFromAny(tc.val)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equal(t, tc.res, res)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/all_price_getter_mock.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/all_price_getter_mock.go
new file mode 100644
index 00000000000..010c955c766
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/all_price_getter_mock.go
@@ -0,0 +1,269 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package pricegetter
+
+import (
+ context "context"
+ big "math/big"
+
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// MockAllTokensPriceGetter is an autogenerated mock type for the AllTokensPriceGetter type
+type MockAllTokensPriceGetter struct {
+ mock.Mock
+}
+
+type MockAllTokensPriceGetter_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockAllTokensPriceGetter) EXPECT() *MockAllTokensPriceGetter_Expecter {
+ return &MockAllTokensPriceGetter_Expecter{mock: &_m.Mock}
+}
+
+// Close provides a mock function with given fields:
+func (_m *MockAllTokensPriceGetter) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// MockAllTokensPriceGetter_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type MockAllTokensPriceGetter_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *MockAllTokensPriceGetter_Expecter) Close() *MockAllTokensPriceGetter_Close_Call {
+ return &MockAllTokensPriceGetter_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *MockAllTokensPriceGetter_Close_Call) Run(run func()) *MockAllTokensPriceGetter_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *MockAllTokensPriceGetter_Close_Call) Return(_a0 error) *MockAllTokensPriceGetter_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *MockAllTokensPriceGetter_Close_Call) RunAndReturn(run func() error) *MockAllTokensPriceGetter_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfiguredTokens provides a mock function with given fields: ctx, tokens
+func (_m *MockAllTokensPriceGetter) FilterConfiguredTokens(ctx context.Context, tokens []ccip.Address) ([]ccip.Address, []ccip.Address, error) {
+ ret := _m.Called(ctx, tokens)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfiguredTokens")
+ }
+
+ var r0 []ccip.Address
+ var r1 []ccip.Address
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) ([]ccip.Address, []ccip.Address, error)); ok {
+ return rf(ctx, tokens)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) []ccip.Address); ok {
+ r0 = rf(ctx, tokens)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []ccip.Address) []ccip.Address); ok {
+ r1 = rf(ctx, tokens)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).([]ccip.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context, []ccip.Address) error); ok {
+ r2 = rf(ctx, tokens)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// MockAllTokensPriceGetter_FilterConfiguredTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfiguredTokens'
+type MockAllTokensPriceGetter_FilterConfiguredTokens_Call struct {
+ *mock.Call
+}
+
+// FilterConfiguredTokens is a helper method to define mock.On call
+// - ctx context.Context
+// - tokens []ccip.Address
+func (_e *MockAllTokensPriceGetter_Expecter) FilterConfiguredTokens(ctx interface{}, tokens interface{}) *MockAllTokensPriceGetter_FilterConfiguredTokens_Call {
+ return &MockAllTokensPriceGetter_FilterConfiguredTokens_Call{Call: _e.mock.On("FilterConfiguredTokens", ctx, tokens)}
+}
+
+func (_c *MockAllTokensPriceGetter_FilterConfiguredTokens_Call) Run(run func(ctx context.Context, tokens []ccip.Address)) *MockAllTokensPriceGetter_FilterConfiguredTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]ccip.Address))
+ })
+ return _c
+}
+
+func (_c *MockAllTokensPriceGetter_FilterConfiguredTokens_Call) Return(configured []ccip.Address, unconfigured []ccip.Address, err error) *MockAllTokensPriceGetter_FilterConfiguredTokens_Call {
+ _c.Call.Return(configured, unconfigured, err)
+ return _c
+}
+
+func (_c *MockAllTokensPriceGetter_FilterConfiguredTokens_Call) RunAndReturn(run func(context.Context, []ccip.Address) ([]ccip.Address, []ccip.Address, error)) *MockAllTokensPriceGetter_FilterConfiguredTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetJobSpecTokenPricesUSD provides a mock function with given fields: ctx
+func (_m *MockAllTokensPriceGetter) GetJobSpecTokenPricesUSD(ctx context.Context) (map[ccip.Address]*big.Int, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetJobSpecTokenPricesUSD")
+ }
+
+ var r0 map[ccip.Address]*big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (map[ccip.Address]*big.Int, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) map[ccip.Address]*big.Int); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(map[ccip.Address]*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJobSpecTokenPricesUSD'
+type MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call struct {
+ *mock.Call
+}
+
+// GetJobSpecTokenPricesUSD is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *MockAllTokensPriceGetter_Expecter) GetJobSpecTokenPricesUSD(ctx interface{}) *MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call {
+ return &MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call{Call: _e.mock.On("GetJobSpecTokenPricesUSD", ctx)}
+}
+
+func (_c *MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call) Run(run func(ctx context.Context)) *MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call) Return(_a0 map[ccip.Address]*big.Int, _a1 error) *MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call) RunAndReturn(run func(context.Context) (map[ccip.Address]*big.Int, error)) *MockAllTokensPriceGetter_GetJobSpecTokenPricesUSD_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TokenPricesUSD provides a mock function with given fields: ctx, tokens
+func (_m *MockAllTokensPriceGetter) TokenPricesUSD(ctx context.Context, tokens []ccip.Address) (map[ccip.Address]*big.Int, error) {
+ ret := _m.Called(ctx, tokens)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TokenPricesUSD")
+ }
+
+ var r0 map[ccip.Address]*big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) (map[ccip.Address]*big.Int, error)); ok {
+ return rf(ctx, tokens)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) map[ccip.Address]*big.Int); ok {
+ r0 = rf(ctx, tokens)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(map[ccip.Address]*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []ccip.Address) error); ok {
+ r1 = rf(ctx, tokens)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockAllTokensPriceGetter_TokenPricesUSD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TokenPricesUSD'
+type MockAllTokensPriceGetter_TokenPricesUSD_Call struct {
+ *mock.Call
+}
+
+// TokenPricesUSD is a helper method to define mock.On call
+// - ctx context.Context
+// - tokens []ccip.Address
+func (_e *MockAllTokensPriceGetter_Expecter) TokenPricesUSD(ctx interface{}, tokens interface{}) *MockAllTokensPriceGetter_TokenPricesUSD_Call {
+ return &MockAllTokensPriceGetter_TokenPricesUSD_Call{Call: _e.mock.On("TokenPricesUSD", ctx, tokens)}
+}
+
+func (_c *MockAllTokensPriceGetter_TokenPricesUSD_Call) Run(run func(ctx context.Context, tokens []ccip.Address)) *MockAllTokensPriceGetter_TokenPricesUSD_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]ccip.Address))
+ })
+ return _c
+}
+
+func (_c *MockAllTokensPriceGetter_TokenPricesUSD_Call) Return(_a0 map[ccip.Address]*big.Int, _a1 error) *MockAllTokensPriceGetter_TokenPricesUSD_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockAllTokensPriceGetter_TokenPricesUSD_Call) RunAndReturn(run func(context.Context, []ccip.Address) (map[ccip.Address]*big.Int, error)) *MockAllTokensPriceGetter_TokenPricesUSD_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockAllTokensPriceGetter creates a new instance of MockAllTokensPriceGetter. 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 NewMockAllTokensPriceGetter(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockAllTokensPriceGetter {
+ mock := &MockAllTokensPriceGetter{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/evm.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/evm.go
new file mode 100644
index 00000000000..ac4002f53fb
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/evm.go
@@ -0,0 +1,256 @@
+package pricegetter
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+const decimalsMethodName = "decimals"
+const latestRoundDataMethodName = "latestRoundData"
+
+func init() {
+ // Ensure existence of latestRoundData method on the Aggregator contract.
+ aggregatorABI, err := abi.JSON(strings.NewReader(offchainaggregator.OffchainAggregatorABI))
+ if err != nil {
+ panic(err)
+ }
+ ensureMethodOnContract(aggregatorABI, decimalsMethodName)
+ ensureMethodOnContract(aggregatorABI, latestRoundDataMethodName)
+}
+
+func ensureMethodOnContract(abi abi.ABI, methodName string) {
+ if _, ok := abi.Methods[methodName]; !ok {
+ panic(fmt.Errorf("method %s not found on ABI: %+v", methodName, abi.Methods))
+ }
+}
+
+type DynamicPriceGetterClient struct {
+ BatchCaller rpclib.EvmBatchCaller
+}
+
+func NewDynamicPriceGetterClient(batchCaller rpclib.EvmBatchCaller) DynamicPriceGetterClient {
+ return DynamicPriceGetterClient{
+ BatchCaller: batchCaller,
+ }
+}
+
+type DynamicPriceGetter struct {
+ cfg config.DynamicPriceGetterConfig
+ evmClients map[uint64]DynamicPriceGetterClient
+ aggregatorAbi abi.ABI
+}
+
+func NewDynamicPriceGetterConfig(configJson string) (config.DynamicPriceGetterConfig, error) {
+ priceGetterConfig := config.DynamicPriceGetterConfig{}
+ err := json.Unmarshal([]byte(configJson), &priceGetterConfig)
+ if err != nil {
+ return config.DynamicPriceGetterConfig{}, fmt.Errorf("parsing dynamic price getter config: %w", err)
+ }
+ err = priceGetterConfig.Validate()
+ if err != nil {
+ return config.DynamicPriceGetterConfig{}, fmt.Errorf("validating price getter config: %w", err)
+ }
+ return priceGetterConfig, nil
+}
+
+// NewDynamicPriceGetter build a DynamicPriceGetter from a configuration and a map of chain ID to batch callers.
+// A batch caller should be provided for all retrieved prices.
+func NewDynamicPriceGetter(cfg config.DynamicPriceGetterConfig, evmClients map[uint64]DynamicPriceGetterClient) (*DynamicPriceGetter, error) {
+ if err := cfg.Validate(); err != nil {
+ return nil, fmt.Errorf("validating dynamic price getter config: %w", err)
+ }
+ aggregatorAbi, err := abi.JSON(strings.NewReader(offchainaggregator.OffchainAggregatorABI))
+ if err != nil {
+ return nil, fmt.Errorf("parsing offchainaggregator abi: %w", err)
+ }
+ priceGetter := DynamicPriceGetter{cfg, evmClients, aggregatorAbi}
+ return &priceGetter, nil
+}
+
+// FilterConfiguredTokens implements the PriceGetter interface.
+// It filters a list of token addresses for only those that have a price resolution rule configured on the PriceGetterConfig
+func (d *DynamicPriceGetter) FilterConfiguredTokens(ctx context.Context, tokens []cciptypes.Address) (configured []cciptypes.Address, unconfigured []cciptypes.Address, err error) {
+ configured = []cciptypes.Address{}
+ unconfigured = []cciptypes.Address{}
+ for _, tk := range tokens {
+ evmAddr, err := ccipcalc.GenericAddrToEvm(tk)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if _, isAgg := d.cfg.AggregatorPrices[evmAddr]; isAgg {
+ configured = append(configured, tk)
+ } else if _, isStatic := d.cfg.StaticPrices[evmAddr]; isStatic {
+ configured = append(configured, tk)
+ } else {
+ unconfigured = append(unconfigured, tk)
+ }
+ }
+ return configured, unconfigured, nil
+}
+
+// It returns the prices of all tokens defined in the price getter.
+func (d *DynamicPriceGetter) GetJobSpecTokenPricesUSD(ctx context.Context) (map[cciptypes.Address]*big.Int, error) {
+ return d.TokenPricesUSD(ctx, d.getAllTokensDefined())
+}
+
+// TokenPricesUSD implements the PriceGetter interface.
+// It returns static prices stored in the price getter, and batch calls aggregators (one per chain) to retrieve aggregator-based prices.
+func (d *DynamicPriceGetter) TokenPricesUSD(ctx context.Context, tokens []cciptypes.Address) (map[cciptypes.Address]*big.Int, error) {
+ prices, batchCallsPerChain, err := d.preparePricesAndBatchCallsPerChain(tokens)
+ if err != nil {
+ return nil, err
+ }
+ if err = d.performBatchCalls(ctx, batchCallsPerChain, prices); err != nil {
+ return nil, err
+ }
+ return prices, nil
+}
+
+func (d *DynamicPriceGetter) getAllTokensDefined() []cciptypes.Address {
+ tokens := make([]cciptypes.Address, 0)
+
+ for addr := range d.cfg.AggregatorPrices {
+ tokens = append(tokens, ccipcalc.EvmAddrToGeneric(addr))
+ }
+ for addr := range d.cfg.StaticPrices {
+ tokens = append(tokens, ccipcalc.EvmAddrToGeneric(addr))
+ }
+ return tokens
+}
+
+// performBatchCalls performs batch calls on all chains to retrieve token prices.
+func (d *DynamicPriceGetter) performBatchCalls(ctx context.Context, batchCallsPerChain map[uint64]*batchCallsForChain, prices map[cciptypes.Address]*big.Int) error {
+ for chainID, batchCalls := range batchCallsPerChain {
+ if err := d.performBatchCall(ctx, chainID, batchCalls, prices); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// performBatchCall performs a batch call on a given chain to retrieve token prices.
+func (d *DynamicPriceGetter) performBatchCall(ctx context.Context, chainID uint64, batchCalls *batchCallsForChain, prices map[cciptypes.Address]*big.Int) error {
+ // Retrieve the EVM caller for the chain.
+ client, exists := d.evmClients[chainID]
+ if !exists {
+ return fmt.Errorf("evm caller for chain %d not found", chainID)
+ }
+ evmCaller := client.BatchCaller
+
+ nbDecimalCalls := len(batchCalls.decimalCalls)
+ nbLatestRoundDataCalls := len(batchCalls.decimalCalls)
+
+ // Perform batched call (all decimals calls followed by latest round data calls).
+ calls := make([]rpclib.EvmCall, 0, nbDecimalCalls+nbLatestRoundDataCalls)
+ calls = append(calls, batchCalls.decimalCalls...)
+ calls = append(calls, batchCalls.latestRoundDataCalls...)
+
+ results, err := evmCaller.BatchCall(ctx, 0, calls)
+ if err != nil {
+ return fmt.Errorf("batch call on chain %d failed: %w", chainID, err)
+ }
+
+ // Extract results.
+ decimals := make([]uint8, 0, nbDecimalCalls)
+ latestRounds := make([]*big.Int, 0, nbLatestRoundDataCalls)
+
+ for i, res := range results[0:nbDecimalCalls] {
+ v, err1 := rpclib.ParseOutput[uint8](res, 0)
+ if err1 != nil {
+ callSignature := batchCalls.decimalCalls[i].String()
+ return fmt.Errorf("parse contract output while calling %v on chain %d: %w", callSignature, chainID, err1)
+ }
+ decimals = append(decimals, v)
+ }
+
+ for i, res := range results[nbDecimalCalls : nbDecimalCalls+nbLatestRoundDataCalls] {
+ // latestRoundData function has multiple outputs (roundId,answer,startedAt,updatedAt,answeredInRound).
+ // we want the second one (answer, at idx=1).
+ v, err1 := rpclib.ParseOutput[*big.Int](res, 1)
+ if err1 != nil {
+ callSignature := batchCalls.latestRoundDataCalls[i].String()
+ return fmt.Errorf("parse contract output while calling %v on chain %d: %w", callSignature, chainID, err1)
+ }
+ latestRounds = append(latestRounds, v)
+ }
+
+ // Normalize and store prices.
+ for i := range batchCalls.tokenOrder {
+ // Normalize to 1e18.
+ if decimals[i] < 18 {
+ latestRounds[i].Mul(latestRounds[i], big.NewInt(0).Exp(big.NewInt(10), big.NewInt(18-int64(decimals[i])), nil))
+ } else if decimals[i] > 18 {
+ latestRounds[i].Div(latestRounds[i], big.NewInt(0).Exp(big.NewInt(10), big.NewInt(int64(decimals[i])-18), nil))
+ }
+ prices[ccipcalc.EvmAddrToGeneric(batchCalls.tokenOrder[i])] = latestRounds[i]
+ }
+ return nil
+}
+
+// preparePricesAndBatchCallsPerChain uses this price getter to prepare for a list of tokens:
+// - the map of token address to their prices (static prices)
+// - the map of and batch calls per chain for the given tokens (dynamic prices)
+func (d *DynamicPriceGetter) preparePricesAndBatchCallsPerChain(tokens []cciptypes.Address) (map[cciptypes.Address]*big.Int, map[uint64]*batchCallsForChain, error) {
+ prices := make(map[cciptypes.Address]*big.Int, len(tokens))
+ batchCallsPerChain := make(map[uint64]*batchCallsForChain)
+ evmAddrs, err := ccipcalc.GenericAddrsToEvm(tokens...)
+ if err != nil {
+ return nil, nil, err
+ }
+ for _, tk := range evmAddrs {
+ if aggCfg, isAgg := d.cfg.AggregatorPrices[tk]; isAgg {
+ // Batch calls for aggregator-based token prices (one per chain).
+ if _, exists := batchCallsPerChain[aggCfg.ChainID]; !exists {
+ batchCallsPerChain[aggCfg.ChainID] = &batchCallsForChain{
+ decimalCalls: []rpclib.EvmCall{},
+ latestRoundDataCalls: []rpclib.EvmCall{},
+ tokenOrder: []common.Address{},
+ }
+ }
+ chainCalls := batchCallsPerChain[aggCfg.ChainID]
+ chainCalls.decimalCalls = append(chainCalls.decimalCalls, rpclib.NewEvmCall(
+ d.aggregatorAbi,
+ decimalsMethodName,
+ aggCfg.AggregatorContractAddress,
+ ))
+ chainCalls.latestRoundDataCalls = append(chainCalls.latestRoundDataCalls, rpclib.NewEvmCall(
+ d.aggregatorAbi,
+ latestRoundDataMethodName,
+ aggCfg.AggregatorContractAddress,
+ ))
+ chainCalls.tokenOrder = append(chainCalls.tokenOrder, tk)
+ } else if staticCfg, isStatic := d.cfg.StaticPrices[tk]; isStatic {
+ // Fill static prices.
+ prices[ccipcalc.EvmAddrToGeneric(tk)] = staticCfg.Price
+ } else {
+ return nil, nil, fmt.Errorf("no price resolution rule for token %s", tk.Hex())
+ }
+ }
+ return prices, batchCallsPerChain, nil
+}
+
+// batchCallsForChain Defines the batch calls to perform on a given chain.
+type batchCallsForChain struct {
+ decimalCalls []rpclib.EvmCall
+ latestRoundDataCalls []rpclib.EvmCall
+ tokenOrder []common.Address // required to maintain the order of the batched rpc calls for mapping the results.
+}
+
+func (d *DynamicPriceGetter) Close() error {
+ return nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/evm_test.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/evm_test.go
new file mode 100644
index 00000000000..78de2699688
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/evm_test.go
@@ -0,0 +1,772 @@
+package pricegetter
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks"
+)
+
+type testParameters struct {
+ cfg config.DynamicPriceGetterConfig
+ evmClients map[uint64]DynamicPriceGetterClient
+ tokens []common.Address
+ expectedTokenPrices map[common.Address]big.Int
+ expectedTokenPricesForAll map[common.Address]big.Int
+ evmCallErr bool
+ invalidConfigErrorExpected bool
+ priceResolutionErrorExpected bool
+}
+
+var (
+ TK1 common.Address
+ TK2 common.Address
+ TK3 common.Address
+ TK4 common.Address
+)
+
+func init() {
+ TK1 = utils.RandomAddress()
+ TK2 = utils.RandomAddress()
+ TK3 = utils.RandomAddress()
+ TK4 = utils.RandomAddress()
+}
+
+func TestDynamicPriceGetterWithEmptyInput(t *testing.T) {
+ tests := []struct {
+ name string
+ param testParameters
+ }{
+ {
+ name: "aggregator_only_valid",
+ param: testParamAggregatorOnly(t),
+ },
+ {
+ name: "aggregator_only_valid_multi",
+ param: testParamAggregatorOnlyMulti(t),
+ },
+ {
+ name: "static_only_valid",
+ param: testParamStaticOnly(),
+ },
+ {
+ name: "aggregator_and_static_valid",
+ param: testParamAggregatorAndStaticValid(t),
+ },
+ {
+ name: "aggregator_and_static_token_collision",
+ param: testParamAggregatorAndStaticTokenCollision(t),
+ },
+ {
+ name: "no_aggregator_for_token",
+ param: testParamNoAggregatorForToken(t),
+ },
+ {
+ name: "batchCall_returns_err",
+ param: testParamBatchCallReturnsErr(t),
+ },
+ {
+ name: "less_inputs_than_defined_prices",
+ param: testLessInputsThanDefinedPrices(t),
+ },
+ {
+ name: "get_all_tokens_aggregator_and_static",
+ param: testGetAllTokensAggregatorAndStatic(t),
+ },
+ {
+ name: "get_all_tokens_aggregator_only",
+ param: testGetAllTokensAggregatorOnly(t),
+ },
+ {
+ name: "get_all_tokens_static_only",
+ param: testGetAllTokensStaticOnly(),
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ pg, err := NewDynamicPriceGetter(test.param.cfg, test.param.evmClients)
+ if test.param.invalidConfigErrorExpected {
+ require.Error(t, err)
+ return
+ }
+ require.NoError(t, err)
+ ctx := testutils.Context(t)
+
+ var prices map[cciptypes.Address]*big.Int
+ var expectedTokens map[common.Address]big.Int
+ if len(test.param.expectedTokenPricesForAll) == 0 {
+ prices, err = pg.TokenPricesUSD(ctx, ccipcalc.EvmAddrsToGeneric(test.param.tokens...))
+ if test.param.evmCallErr {
+ require.Error(t, err)
+ return
+ }
+
+ if test.param.priceResolutionErrorExpected {
+ require.Error(t, err)
+ return
+ }
+ expectedTokens = test.param.expectedTokenPrices
+ } else {
+ prices, err = pg.GetJobSpecTokenPricesUSD(ctx)
+ expectedTokens = test.param.expectedTokenPricesForAll
+ }
+
+ require.NoError(t, err)
+ // Ensure all expected prices are present.
+ assert.True(t, len(prices) == len(expectedTokens))
+ // Check prices are matching expected result.
+ for tk, expectedPrice := range expectedTokens {
+ if prices[cciptypes.Address(tk.String())] == nil {
+ assert.Fail(t, "Token price not found")
+ }
+ assert.Equal(t, 0, expectedPrice.Cmp(prices[cciptypes.Address(tk.String())]),
+ "Token price mismatch: expected price %v, got %v", expectedPrice, *prices[cciptypes.Address(tk.String())])
+ }
+ })
+ }
+}
+
+func testParamAggregatorOnly(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK3: {
+ ChainID: 103,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK4: {
+ ChainID: 104,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{},
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(1396818990),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ // Real ETH/USD example from OP.
+ round2 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(2000),
+ Answer: big.NewInt(238879815123),
+ StartedAt: big.NewInt(1704897197),
+ UpdatedAt: big.NewInt(1704897197),
+ AnsweredInRound: big.NewInt(2000),
+ }
+ // Real LINK/ETH example from OP.
+ round3 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(3000),
+ Answer: big.NewInt(4468862777874802),
+ StartedAt: big.NewInt(1715743907),
+ UpdatedAt: big.NewInt(1715743907),
+ AnsweredInRound: big.NewInt(3000),
+ }
+ // Fake data for a token with more than 18 decimals.
+ round4 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(4000),
+ Answer: multExp(big.NewInt(1234567890), 10), // 20 digits.
+ StartedAt: big.NewInt(1715753907),
+ UpdatedAt: big.NewInt(1715753907),
+ AnsweredInRound: big.NewInt(4000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round2}),
+ uint64(103): mockClient(t, []uint8{18}, []aggregator_v3_interface.LatestRoundData{round3}),
+ uint64(104): mockClient(t, []uint8{20}, []aggregator_v3_interface.LatestRoundData{round4}),
+ }
+ expectedTokenPrices := map[common.Address]big.Int{
+ TK1: *multExp(round1.Answer, 10), // expected in 1e18 format.
+ TK2: *multExp(round2.Answer, 10), // expected in 1e18 format.
+ TK3: *round3.Answer, // already in 1e18 format (contract decimals==18).
+ TK4: *multExp(big.NewInt(1234567890), 8), // expected in 1e18 format.
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ tokens: []common.Address{TK1, TK2, TK3, TK4},
+ expectedTokenPrices: expectedTokenPrices,
+ invalidConfigErrorExpected: false,
+ }
+}
+
+// testParamAggregatorOnlyMulti test with several tokens on chain 102.
+func testParamAggregatorOnlyMulti(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK3: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{},
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(1396818990),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ // Real ETH/USD example from OP.
+ round2 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(2000),
+ Answer: big.NewInt(238879815123),
+ StartedAt: big.NewInt(1704897197),
+ UpdatedAt: big.NewInt(1704897197),
+ AnsweredInRound: big.NewInt(2000),
+ }
+ round3 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(3000),
+ Answer: big.NewInt(238879815125),
+ StartedAt: big.NewInt(1704897198),
+ UpdatedAt: big.NewInt(1704897198),
+ AnsweredInRound: big.NewInt(3000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): mockClient(t, []uint8{8, 8}, []aggregator_v3_interface.LatestRoundData{round2, round3}),
+ }
+ expectedTokenPrices := map[common.Address]big.Int{
+ TK1: *multExp(round1.Answer, 10),
+ TK2: *multExp(round2.Answer, 10),
+ TK3: *multExp(round3.Answer, 10),
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ invalidConfigErrorExpected: false,
+ tokens: []common.Address{TK1, TK2, TK3},
+ expectedTokenPrices: expectedTokenPrices,
+ }
+}
+
+func testParamStaticOnly() testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{},
+ StaticPrices: map[common.Address]config.StaticPriceConfig{
+ TK1: {
+ ChainID: 101,
+ Price: big.NewInt(1_234_000),
+ },
+ TK2: {
+ ChainID: 102,
+ Price: big.NewInt(2_234_000),
+ },
+ TK3: {
+ ChainID: 103,
+ Price: big.NewInt(3_234_000),
+ },
+ },
+ }
+ // Real LINK/USD example from OP.
+ evmClients := map[uint64]DynamicPriceGetterClient{}
+ expectedTokenPrices := map[common.Address]big.Int{
+ TK1: *cfg.StaticPrices[TK1].Price,
+ TK2: *cfg.StaticPrices[TK2].Price,
+ TK3: *cfg.StaticPrices[TK3].Price,
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ tokens: []common.Address{TK1, TK2, TK3},
+ expectedTokenPrices: expectedTokenPrices,
+ }
+}
+
+func testParamNoAggregatorForToken(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{
+ TK3: {
+ ChainID: 103,
+ Price: big.NewInt(1_234_000),
+ },
+ },
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(1396818990),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ // Real ETH/USD example from OP.
+ round2 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(2000),
+ Answer: big.NewInt(238879815123),
+ StartedAt: big.NewInt(1704897197),
+ UpdatedAt: big.NewInt(1704897197),
+ AnsweredInRound: big.NewInt(2000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round2}),
+ }
+ expectedTokenPrices := map[common.Address]big.Int{
+ TK1: *round1.Answer,
+ TK2: *round2.Answer,
+ TK3: *cfg.StaticPrices[TK3].Price,
+ TK4: *big.NewInt(0),
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ tokens: []common.Address{TK1, TK2, TK3, TK4},
+ expectedTokenPrices: expectedTokenPrices,
+ priceResolutionErrorExpected: true,
+ }
+}
+
+func testParamAggregatorAndStaticValid(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{
+ TK3: {
+ ChainID: 103,
+ Price: big.NewInt(1_234_000),
+ },
+ },
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(1396818990),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ // Real ETH/USD example from OP.
+ round2 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(2000),
+ Answer: big.NewInt(238879815123),
+ StartedAt: big.NewInt(1704897197),
+ UpdatedAt: big.NewInt(1704897197),
+ AnsweredInRound: big.NewInt(2000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round2}),
+ }
+ expectedTokenPrices := map[common.Address]big.Int{
+ TK1: *multExp(round1.Answer, 10),
+ TK2: *multExp(round2.Answer, 10),
+ TK3: *cfg.StaticPrices[TK3].Price,
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ tokens: []common.Address{TK1, TK2, TK3},
+ expectedTokenPrices: expectedTokenPrices,
+ }
+}
+
+func testParamAggregatorAndStaticTokenCollision(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK3: {
+ ChainID: 103,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{
+ TK3: {
+ ChainID: 103,
+ Price: big.NewInt(1_234_000),
+ },
+ },
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(1396818990),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ // Real ETH/USD example from OP.
+ round2 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(2000),
+ Answer: big.NewInt(238879815123),
+ StartedAt: big.NewInt(1704897197),
+ UpdatedAt: big.NewInt(1704897197),
+ AnsweredInRound: big.NewInt(2000),
+ }
+ round3 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(3000),
+ Answer: big.NewInt(238879815124),
+ StartedAt: big.NewInt(1704897198),
+ UpdatedAt: big.NewInt(1704897198),
+ AnsweredInRound: big.NewInt(3000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round2}),
+ uint64(103): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round3}),
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ tokens: []common.Address{TK1, TK2, TK3},
+ invalidConfigErrorExpected: true,
+ }
+}
+
+func testParamBatchCallReturnsErr(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{
+ TK3: {
+ ChainID: 103,
+ Price: big.NewInt(1_234_000),
+ },
+ },
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(1396818990),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): {
+ BatchCaller: mockErrCaller(t),
+ },
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ tokens: []common.Address{TK1, TK2, TK3},
+ evmCallErr: true,
+ }
+}
+
+func testLessInputsThanDefinedPrices(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK3: {
+ ChainID: 103,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{
+ TK4: {
+ ChainID: 104,
+ Price: big.NewInt(1_234_000),
+ },
+ },
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(3749350456),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ // Real ETH/USD example from OP.
+ round2 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(2000),
+ Answer: big.NewInt(238879815123),
+ StartedAt: big.NewInt(1704897197),
+ UpdatedAt: big.NewInt(1704897197),
+ AnsweredInRound: big.NewInt(2000),
+ }
+ // Real LINK/ETH example from OP.
+ round3 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(3000),
+ Answer: big.NewInt(4468862777874802),
+ StartedAt: big.NewInt(1715743907),
+ UpdatedAt: big.NewInt(1715743907),
+ AnsweredInRound: big.NewInt(3000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round2}),
+ uint64(103): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round3}),
+ }
+ expectedTokenPrices := map[common.Address]big.Int{
+ TK1: *multExp(round1.Answer, 10),
+ TK2: *multExp(round2.Answer, 10),
+ TK3: *multExp(round3.Answer, 10),
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ tokens: []common.Address{TK1, TK2, TK3},
+ expectedTokenPrices: expectedTokenPrices,
+ }
+}
+
+func testGetAllTokensAggregatorAndStatic(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK3: {
+ ChainID: 103,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{
+ TK4: {
+ ChainID: 104,
+ Price: big.NewInt(1_234_000),
+ },
+ },
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(3749350456),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ // Real ETH/USD example from OP.
+ round2 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(2000),
+ Answer: big.NewInt(238879815123),
+ StartedAt: big.NewInt(1704897197),
+ UpdatedAt: big.NewInt(1704897197),
+ AnsweredInRound: big.NewInt(2000),
+ }
+ // Real LINK/ETH example from OP.
+ round3 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(3000),
+ Answer: big.NewInt(4468862777874802),
+ StartedAt: big.NewInt(1715743907),
+ UpdatedAt: big.NewInt(1715743907),
+ AnsweredInRound: big.NewInt(3000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round2}),
+ uint64(103): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round3}),
+ }
+ expectedTokenPricesForAll := map[common.Address]big.Int{
+ TK1: *multExp(round1.Answer, 10),
+ TK2: *multExp(round2.Answer, 10),
+ TK3: *multExp(round3.Answer, 10),
+ TK4: *cfg.StaticPrices[TK4].Price,
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ expectedTokenPricesForAll: expectedTokenPricesForAll,
+ }
+}
+
+func testGetAllTokensAggregatorOnly(t *testing.T) testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{
+ TK1: {
+ ChainID: 101,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK2: {
+ ChainID: 102,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ TK3: {
+ ChainID: 103,
+ AggregatorContractAddress: utils.RandomAddress(),
+ },
+ },
+ StaticPrices: map[common.Address]config.StaticPriceConfig{},
+ }
+ // Real LINK/USD example from OP.
+ round1 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(1000),
+ Answer: big.NewInt(3749350456),
+ StartedAt: big.NewInt(1704896575),
+ UpdatedAt: big.NewInt(1704896575),
+ AnsweredInRound: big.NewInt(1000),
+ }
+ // Real ETH/USD example from OP.
+ round2 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(2000),
+ Answer: big.NewInt(238879815123),
+ StartedAt: big.NewInt(1704897197),
+ UpdatedAt: big.NewInt(1704897197),
+ AnsweredInRound: big.NewInt(2000),
+ }
+ // Real LINK/ETH example from OP.
+ round3 := aggregator_v3_interface.LatestRoundData{
+ RoundId: big.NewInt(3000),
+ Answer: big.NewInt(4468862777874802),
+ StartedAt: big.NewInt(1715743907),
+ UpdatedAt: big.NewInt(1715743907),
+ AnsweredInRound: big.NewInt(3000),
+ }
+ evmClients := map[uint64]DynamicPriceGetterClient{
+ uint64(101): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round1}),
+ uint64(102): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round2}),
+ uint64(103): mockClient(t, []uint8{8}, []aggregator_v3_interface.LatestRoundData{round3}),
+ }
+ expectedTokenPricesForAll := map[common.Address]big.Int{
+ TK1: *multExp(round1.Answer, 10),
+ TK2: *multExp(round2.Answer, 10),
+ TK3: *multExp(round3.Answer, 10),
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ expectedTokenPricesForAll: expectedTokenPricesForAll,
+ }
+}
+
+func testGetAllTokensStaticOnly() testParameters {
+ cfg := config.DynamicPriceGetterConfig{
+ AggregatorPrices: map[common.Address]config.AggregatorPriceConfig{},
+ StaticPrices: map[common.Address]config.StaticPriceConfig{
+ TK1: {
+ ChainID: 101,
+ Price: big.NewInt(1_234_000),
+ },
+ TK2: {
+ ChainID: 102,
+ Price: big.NewInt(2_234_000),
+ },
+ TK3: {
+ ChainID: 103,
+ Price: big.NewInt(3_234_000),
+ },
+ },
+ }
+
+ evmClients := map[uint64]DynamicPriceGetterClient{}
+ expectedTokenPricesForAll := map[common.Address]big.Int{
+ TK1: *cfg.StaticPrices[TK1].Price,
+ TK2: *cfg.StaticPrices[TK2].Price,
+ TK3: *cfg.StaticPrices[TK3].Price,
+ }
+ return testParameters{
+ cfg: cfg,
+ evmClients: evmClients,
+ expectedTokenPricesForAll: expectedTokenPricesForAll,
+ }
+}
+
+func mockClient(t *testing.T, decimals []uint8, rounds []aggregator_v3_interface.LatestRoundData) DynamicPriceGetterClient {
+ return DynamicPriceGetterClient{
+ BatchCaller: mockCaller(t, decimals, rounds),
+ }
+}
+
+func mockCaller(t *testing.T, decimals []uint8, rounds []aggregator_v3_interface.LatestRoundData) *rpclibmocks.EvmBatchCaller {
+ caller := rpclibmocks.NewEvmBatchCaller(t)
+
+ // Mock batch calls per chain: all decimals calls then all latestRoundData calls.
+ dataAndErrs := make([]rpclib.DataAndErr, 0, len(decimals)+len(rounds))
+ for _, d := range decimals {
+ dataAndErrs = append(dataAndErrs, rpclib.DataAndErr{
+ Outputs: []any{d},
+ })
+ }
+ for _, round := range rounds {
+ dataAndErrs = append(dataAndErrs, rpclib.DataAndErr{
+ Outputs: []any{round.RoundId, round.Answer, round.StartedAt, round.UpdatedAt, round.AnsweredInRound},
+ })
+ }
+ caller.On("BatchCall", mock.Anything, uint64(0), mock.Anything).Return(dataAndErrs, nil).Maybe()
+ return caller
+}
+
+func mockErrCaller(t *testing.T) *rpclibmocks.EvmBatchCaller {
+ caller := rpclibmocks.NewEvmBatchCaller(t)
+ caller.On("BatchCall", mock.Anything, uint64(0), mock.Anything).Return(nil, assert.AnError).Maybe()
+ return caller
+}
+
+// multExp returns the result of multiplying x by 10^e.
+func multExp(x *big.Int, e int64) *big.Int {
+ return big.NewInt(0).Mul(x, big.NewInt(0).Exp(big.NewInt(10), big.NewInt(e), nil))
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/mock.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/mock.go
new file mode 100644
index 00000000000..195649685b2
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/mock.go
@@ -0,0 +1,211 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package pricegetter
+
+import (
+ context "context"
+ big "math/big"
+
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// MockPriceGetter is an autogenerated mock type for the PriceGetter type
+type MockPriceGetter struct {
+ mock.Mock
+}
+
+type MockPriceGetter_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockPriceGetter) EXPECT() *MockPriceGetter_Expecter {
+ return &MockPriceGetter_Expecter{mock: &_m.Mock}
+}
+
+// Close provides a mock function with given fields:
+func (_m *MockPriceGetter) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// MockPriceGetter_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type MockPriceGetter_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *MockPriceGetter_Expecter) Close() *MockPriceGetter_Close_Call {
+ return &MockPriceGetter_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *MockPriceGetter_Close_Call) Run(run func()) *MockPriceGetter_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *MockPriceGetter_Close_Call) Return(_a0 error) *MockPriceGetter_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *MockPriceGetter_Close_Call) RunAndReturn(run func() error) *MockPriceGetter_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// FilterConfiguredTokens provides a mock function with given fields: ctx, tokens
+func (_m *MockPriceGetter) FilterConfiguredTokens(ctx context.Context, tokens []ccip.Address) ([]ccip.Address, []ccip.Address, error) {
+ ret := _m.Called(ctx, tokens)
+
+ if len(ret) == 0 {
+ panic("no return value specified for FilterConfiguredTokens")
+ }
+
+ var r0 []ccip.Address
+ var r1 []ccip.Address
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) ([]ccip.Address, []ccip.Address, error)); ok {
+ return rf(ctx, tokens)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) []ccip.Address); ok {
+ r0 = rf(ctx, tokens)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]ccip.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []ccip.Address) []ccip.Address); ok {
+ r1 = rf(ctx, tokens)
+ } else {
+ if ret.Get(1) != nil {
+ r1 = ret.Get(1).([]ccip.Address)
+ }
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context, []ccip.Address) error); ok {
+ r2 = rf(ctx, tokens)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// MockPriceGetter_FilterConfiguredTokens_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FilterConfiguredTokens'
+type MockPriceGetter_FilterConfiguredTokens_Call struct {
+ *mock.Call
+}
+
+// FilterConfiguredTokens is a helper method to define mock.On call
+// - ctx context.Context
+// - tokens []ccip.Address
+func (_e *MockPriceGetter_Expecter) FilterConfiguredTokens(ctx interface{}, tokens interface{}) *MockPriceGetter_FilterConfiguredTokens_Call {
+ return &MockPriceGetter_FilterConfiguredTokens_Call{Call: _e.mock.On("FilterConfiguredTokens", ctx, tokens)}
+}
+
+func (_c *MockPriceGetter_FilterConfiguredTokens_Call) Run(run func(ctx context.Context, tokens []ccip.Address)) *MockPriceGetter_FilterConfiguredTokens_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]ccip.Address))
+ })
+ return _c
+}
+
+func (_c *MockPriceGetter_FilterConfiguredTokens_Call) Return(configured []ccip.Address, unconfigured []ccip.Address, err error) *MockPriceGetter_FilterConfiguredTokens_Call {
+ _c.Call.Return(configured, unconfigured, err)
+ return _c
+}
+
+func (_c *MockPriceGetter_FilterConfiguredTokens_Call) RunAndReturn(run func(context.Context, []ccip.Address) ([]ccip.Address, []ccip.Address, error)) *MockPriceGetter_FilterConfiguredTokens_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// TokenPricesUSD provides a mock function with given fields: ctx, tokens
+func (_m *MockPriceGetter) TokenPricesUSD(ctx context.Context, tokens []ccip.Address) (map[ccip.Address]*big.Int, error) {
+ ret := _m.Called(ctx, tokens)
+
+ if len(ret) == 0 {
+ panic("no return value specified for TokenPricesUSD")
+ }
+
+ var r0 map[ccip.Address]*big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) (map[ccip.Address]*big.Int, error)); ok {
+ return rf(ctx, tokens)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, []ccip.Address) map[ccip.Address]*big.Int); ok {
+ r0 = rf(ctx, tokens)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(map[ccip.Address]*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, []ccip.Address) error); ok {
+ r1 = rf(ctx, tokens)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockPriceGetter_TokenPricesUSD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TokenPricesUSD'
+type MockPriceGetter_TokenPricesUSD_Call struct {
+ *mock.Call
+}
+
+// TokenPricesUSD is a helper method to define mock.On call
+// - ctx context.Context
+// - tokens []ccip.Address
+func (_e *MockPriceGetter_Expecter) TokenPricesUSD(ctx interface{}, tokens interface{}) *MockPriceGetter_TokenPricesUSD_Call {
+ return &MockPriceGetter_TokenPricesUSD_Call{Call: _e.mock.On("TokenPricesUSD", ctx, tokens)}
+}
+
+func (_c *MockPriceGetter_TokenPricesUSD_Call) Run(run func(ctx context.Context, tokens []ccip.Address)) *MockPriceGetter_TokenPricesUSD_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].([]ccip.Address))
+ })
+ return _c
+}
+
+func (_c *MockPriceGetter_TokenPricesUSD_Call) Return(_a0 map[ccip.Address]*big.Int, _a1 error) *MockPriceGetter_TokenPricesUSD_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockPriceGetter_TokenPricesUSD_Call) RunAndReturn(run func(context.Context, []ccip.Address) (map[ccip.Address]*big.Int, error)) *MockPriceGetter_TokenPricesUSD_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockPriceGetter creates a new instance of MockPriceGetter. 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 NewMockPriceGetter(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockPriceGetter {
+ mock := &MockPriceGetter{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline.go
new file mode 100644
index 00000000000..34977eda9f1
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline.go
@@ -0,0 +1,142 @@
+package pricegetter
+
+import (
+ "context"
+ "math/big"
+ "strings"
+ "time"
+
+ mapset "github.com/deckarep/golang-set/v2"
+ "github.com/google/uuid"
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/parseutil"
+ "github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
+)
+
+var _ PriceGetter = &PipelineGetter{}
+
+type PipelineGetter struct {
+ source string
+ runner pipeline.Runner
+ jobID int32
+ externalJobID uuid.UUID
+ name string
+ lggr logger.Logger
+}
+
+func NewPipelineGetter(source string, runner pipeline.Runner, jobID int32, externalJobID uuid.UUID, name string, lggr logger.Logger) (*PipelineGetter, error) {
+ _, err := pipeline.Parse(source)
+ if err != nil {
+ return nil, err
+ }
+
+ return &PipelineGetter{
+ source: source,
+ runner: runner,
+ jobID: jobID,
+ externalJobID: externalJobID,
+ name: name,
+ lggr: lggr,
+ }, nil
+}
+
+// FilterForConfiguredTokens implements the PriceGetter interface.
+// It filters a list of token addresses for only those that have a pipeline job configured on the TokenPricesUSDPipeline
+func (d *PipelineGetter) FilterConfiguredTokens(ctx context.Context, tokens []cciptypes.Address) (configured []cciptypes.Address, unconfigured []cciptypes.Address, err error) {
+ lcSource := strings.ToLower(d.source)
+ for _, tk := range tokens {
+ lcToken := strings.ToLower(string(tk))
+ if strings.Contains(lcSource, lcToken) {
+ configured = append(configured, tk)
+ } else {
+ unconfigured = append(unconfigured, tk)
+ }
+ }
+ return configured, unconfigured, nil
+}
+
+func (d *PipelineGetter) GetJobSpecTokenPricesUSD(ctx context.Context) (map[cciptypes.Address]*big.Int, error) {
+ prices, err := d.getPricesFromRunner(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ tokenPrices := make(map[cciptypes.Address]*big.Int)
+ for tokenAddressStr, rawPrice := range prices {
+ tokenAddressStr := ccipcalc.HexToAddress(tokenAddressStr)
+ castedPrice, err := parseutil.ParseBigIntFromAny(rawPrice)
+ if err != nil {
+ return nil, err
+ }
+
+ tokenPrices[tokenAddressStr] = castedPrice
+ }
+
+ return tokenPrices, nil
+}
+
+func (d *PipelineGetter) TokenPricesUSD(ctx context.Context, tokens []cciptypes.Address) (map[cciptypes.Address]*big.Int, error) {
+ prices, err := d.getPricesFromRunner(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ providedTokensSet := mapset.NewSet(tokens...)
+ tokenPrices := make(map[cciptypes.Address]*big.Int)
+ for tokenAddressStr, rawPrice := range prices {
+ tokenAddressStr := ccipcalc.HexToAddress(tokenAddressStr)
+ castedPrice, err := parseutil.ParseBigIntFromAny(rawPrice)
+ if err != nil {
+ return nil, err
+ }
+
+ if providedTokensSet.Contains(tokenAddressStr) {
+ tokenPrices[tokenAddressStr] = castedPrice
+ }
+ }
+
+ // The mapping of token address to source of token price has to live offchain.
+ // Best we can do is sanity check that the token price spec covers all our desired execution token prices.
+ for _, token := range tokens {
+ if _, ok := tokenPrices[token]; !ok {
+ return nil, errors.Errorf("missing token %s from tokensForFeeCoin spec, got %v", token, prices)
+ }
+ }
+
+ return tokenPrices, nil
+}
+
+func (d *PipelineGetter) getPricesFromRunner(ctx context.Context) (map[string]interface{}, error) {
+ _, trrs, err := d.runner.ExecuteRun(ctx, pipeline.Spec{
+ ID: d.jobID,
+ DotDagSource: d.source,
+ CreatedAt: time.Now(),
+ JobID: d.jobID,
+ JobName: d.name,
+ JobType: "",
+ }, pipeline.NewVarsFrom(map[string]interface{}{}))
+ if err != nil {
+ return nil, err
+ }
+ finalResult := trrs.FinalResult()
+ if finalResult.HasErrors() {
+ return nil, errors.Errorf("error getting prices %v", finalResult.AllErrors)
+ }
+ if len(finalResult.Values) != 1 {
+ return nil, errors.Errorf("invalid number of price results, expected 1 got %v", len(finalResult.Values))
+ }
+ prices, ok := finalResult.Values[0].(map[string]interface{})
+ if !ok {
+ return nil, errors.Errorf("expected map output of price pipeline, got %T", finalResult.Values[0])
+ }
+
+ return prices, nil
+}
+
+func (d *PipelineGetter) Close() error {
+ return d.runner.Close()
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline_test.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline_test.go
new file mode 100644
index 00000000000..8aeeff96b57
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/pipeline_test.go
@@ -0,0 +1,180 @@
+package pricegetter_test
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ config2 "github.com/smartcontractkit/chainlink-common/pkg/config"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/bridges"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
+ "github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
+
+ pipelinemocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks"
+
+ config "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+)
+
+func TestDataSource(t *testing.T) {
+ linkEth := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(`{"JuelsPerETH": "200000000000000000000"}`))
+ require.NoError(t, err)
+ }))
+ defer linkEth.Close()
+ usdcEth := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(`{"USDCWeiPerETH": "1000000000000000000000"}`)) // 1000 USDC / ETH
+ require.NoError(t, err)
+ }))
+ defer usdcEth.Close()
+ linkTokenAddress := ccipcalc.HexToAddress("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05")
+ usdcTokenAddress := ccipcalc.HexToAddress("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e10")
+ source := fmt.Sprintf(`
+ // Price 1
+ link [type=http method=GET url="%s"];
+ link_parse [type=jsonparse path="JuelsPerETH"];
+ link->link_parse;
+ // Price 2
+ usdc [type=http method=GET url="%s"];
+ usdc_parse [type=jsonparse path="USDCWeiPerETH"];
+ usdc->usdc_parse;
+ merge [type=merge left="{}" right="{\"%s\":$(link_parse), \"%s\":$(usdc_parse)}"];
+`, linkEth.URL, usdcEth.URL, linkTokenAddress, usdcTokenAddress)
+
+ priceGetter := newTestPipelineGetter(t, source)
+
+ // Ask for all prices present in spec.
+ prices, err := priceGetter.GetJobSpecTokenPricesUSD(context.Background())
+ require.NoError(t, err)
+ assert.Equal(t, prices, map[cciptypes.Address]*big.Int{
+ linkTokenAddress: big.NewInt(0).Mul(big.NewInt(200), big.NewInt(1000000000000000000)),
+ usdcTokenAddress: big.NewInt(0).Mul(big.NewInt(1000), big.NewInt(1000000000000000000)),
+ })
+
+ // Specifically ask for all prices
+ pricesWithInput, errWithInput := priceGetter.TokenPricesUSD(context.Background(), []cciptypes.Address{
+ linkTokenAddress,
+ usdcTokenAddress,
+ })
+ require.NoError(t, errWithInput)
+ assert.Equal(t, pricesWithInput, map[cciptypes.Address]*big.Int{
+ linkTokenAddress: big.NewInt(0).Mul(big.NewInt(200), big.NewInt(1000000000000000000)),
+ usdcTokenAddress: big.NewInt(0).Mul(big.NewInt(1000), big.NewInt(1000000000000000000)),
+ })
+
+ // Ask a non-existent price.
+ _, err = priceGetter.TokenPricesUSD(context.Background(), []cciptypes.Address{
+ ccipcalc.HexToAddress("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e11"),
+ })
+ require.Error(t, err)
+
+ // Ask only one price
+ prices, err = priceGetter.TokenPricesUSD(context.Background(), []cciptypes.Address{linkTokenAddress})
+ require.NoError(t, err)
+ assert.Equal(t, prices, map[cciptypes.Address]*big.Int{
+ linkTokenAddress: big.NewInt(0).Mul(big.NewInt(200), big.NewInt(1000000000000000000)),
+ })
+}
+
+func TestParsingDifferentFormats(t *testing.T) {
+ tests := []struct {
+ name string
+ inputValue string
+ expectedValue *big.Int
+ expectedError bool
+ }{
+ {
+ name: "number as string",
+ inputValue: "\"200000000000000000000\"",
+ expectedValue: new(big.Int).Mul(big.NewInt(200), big.NewInt(1e18)),
+ },
+ {
+ name: "number as big number",
+ inputValue: "500000000000000000000",
+ expectedValue: new(big.Int).Mul(big.NewInt(500), big.NewInt(1e18)),
+ },
+ {
+ name: "number as int64",
+ inputValue: "150",
+ expectedValue: big.NewInt(150),
+ },
+ {
+ name: "number in scientific notation",
+ inputValue: "3e22",
+ expectedValue: new(big.Int).Mul(big.NewInt(30000), big.NewInt(1e18)),
+ },
+ {
+ name: "number as string in scientific notation returns error",
+ inputValue: "\"3e22\"",
+ expectedError: true,
+ },
+ {
+ name: "invalid value should return error",
+ inputValue: "\"NaN\"",
+ expectedError: true,
+ },
+ {
+ name: "null should return error",
+ inputValue: "null",
+ expectedError: true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ token := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ _, err := fmt.Fprintf(w, `{"MyCoin": %s}`, tt.inputValue)
+ require.NoError(t, err)
+ }))
+ defer token.Close()
+
+ address := common.HexToAddress("0x94025780a1aB58868D9B2dBBB775f44b32e8E6e5")
+ source := fmt.Sprintf(`
+ // Price 1
+ coin [type=http method=GET url="%s"];
+ coin_parse [type=jsonparse path="MyCoin"];
+ coin->coin_parse;
+ merge [type=merge left="{}" right="{\"%s\":$(coin_parse)}"];
+ `, token.URL, strings.ToLower(address.String()))
+
+ prices, err := newTestPipelineGetter(t, source).
+ TokenPricesUSD(context.Background(), []cciptypes.Address{ccipcalc.EvmAddrToGeneric(address)})
+
+ if tt.expectedError {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ require.Equal(t, prices[ccipcalc.EvmAddrToGeneric(address)], tt.expectedValue)
+ }
+ })
+ }
+}
+
+func newTestPipelineGetter(t *testing.T, source string) *pricegetter.PipelineGetter {
+ lggr, _ := logger.NewLogger()
+ cfg := pipelinemocks.NewConfig(t)
+ cfg.On("MaxRunDuration").Return(time.Second)
+ cfg.On("DefaultHTTPTimeout").Return(*config2.MustNewDuration(time.Second))
+ cfg.On("DefaultHTTPLimit").Return(int64(1024 * 10))
+ cfg.On("VerboseLogging").Return(true)
+ db := pgtest.NewSqlxDB(t)
+ bridgeORM := bridges.NewORM(db)
+ runner := pipeline.NewRunner(pipeline.NewORM(db, lggr, config.NewTestGeneralConfig(t).JobPipeline().MaxSuccessfulRuns()),
+ bridgeORM, cfg, nil, nil, nil, nil, lggr, &http.Client{}, &http.Client{})
+ ds, err := pricegetter.NewPipelineGetter(source, runner, 1, uuid.New(), "test", lggr)
+ require.NoError(t, err)
+ return ds
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/pricegetter/pricegetter.go b/core/services/ocr2/plugins/ccip/internal/pricegetter/pricegetter.go
new file mode 100644
index 00000000000..d4bcfc57b6e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/pricegetter/pricegetter.go
@@ -0,0 +1,18 @@
+package pricegetter
+
+import (
+ "context"
+ "math/big"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+type PriceGetter interface {
+ cciptypes.PriceGetter
+}
+
+type AllTokensPriceGetter interface {
+ PriceGetter
+ // GetJobSpecTokenPricesUSD returns all token prices defined in the jobspec.
+ GetJobSpecTokenPricesUSD(ctx context.Context) (map[cciptypes.Address]*big.Int, error)
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/rpclib/evm.go b/core/services/ocr2/plugins/ccip/internal/rpclib/evm.go
new file mode 100644
index 00000000000..6c4aabb4355
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/rpclib/evm.go
@@ -0,0 +1,337 @@
+package rpclib
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "reflect"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/pkg/errors"
+ "golang.org/x/sync/errgroup"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+)
+
+var ErrEmptyOutput = errors.New("rpc call output is empty (make sure that the contract method exists and rpc is healthy)")
+
+type EvmBatchCaller interface {
+ // BatchCall executes all the provided EvmCall and returns the results in the same order
+ // of the calls. Pass blockNumber=0 to use the latest block.
+ BatchCall(ctx context.Context, blockNumber uint64, calls []EvmCall) ([]DataAndErr, error)
+}
+
+type BatchSender interface {
+ BatchCallContext(ctx context.Context, calls []rpc.BatchElem) error
+}
+
+const (
+ // DefaultRpcBatchSizeLimit defines the maximum number of rpc requests to be included in a batch.
+ DefaultRpcBatchSizeLimit = 100
+
+ // DefaultRpcBatchBackOffMultiplier defines the rate of reducing the batch size limit for retried calls.
+ // For example if limit is 20 and multiplier is 4:
+ // 1. 20
+ // 2. 20/4 = 5
+ // 3. 5/4 = 1
+ DefaultRpcBatchBackOffMultiplier = 5
+
+ // DefaultMaxParallelRpcCalls defines the default maximum number of individual in-parallel rpc calls.
+ DefaultMaxParallelRpcCalls = 10
+)
+
+// DynamicLimitedBatchCaller makes batched rpc calls and perform retries by reducing the batch size on each retry.
+type DynamicLimitedBatchCaller struct {
+ bc *defaultEvmBatchCaller
+}
+
+func NewDynamicLimitedBatchCaller(
+ lggr logger.Logger, batchSender BatchSender, batchSizeLimit, backOffMultiplier, parallelRpcCallsLimit uint,
+) *DynamicLimitedBatchCaller {
+ return &DynamicLimitedBatchCaller{
+ bc: newDefaultEvmBatchCaller(lggr, batchSender, batchSizeLimit, backOffMultiplier, parallelRpcCallsLimit),
+ }
+}
+
+func (c *DynamicLimitedBatchCaller) BatchCall(ctx context.Context, blockNumber uint64, calls []EvmCall) ([]DataAndErr, error) {
+ return c.bc.batchCallDynamicLimitRetries(ctx, blockNumber, calls)
+}
+
+type defaultEvmBatchCaller struct {
+ lggr logger.Logger
+ batchSender BatchSender
+ batchSizeLimit uint
+ parallelRpcCallsLimit uint
+ backOffMultiplier uint
+}
+
+// NewDefaultEvmBatchCaller returns a new batch caller instance.
+// batchCallLimit defines the maximum number of calls for BatchCallLimit method, pass 0 to keep the default.
+// backOffMultiplier defines the back-off strategy for retries on BatchCallDynamicLimitRetries method, pass 0 to keep the default.
+func newDefaultEvmBatchCaller(
+ lggr logger.Logger, batchSender BatchSender, batchSizeLimit, backOffMultiplier, parallelRpcCallsLimit uint,
+) *defaultEvmBatchCaller {
+ batchSize := uint(DefaultRpcBatchSizeLimit)
+ if batchSizeLimit > 0 {
+ batchSize = batchSizeLimit
+ }
+
+ multiplier := uint(DefaultRpcBatchBackOffMultiplier)
+ if backOffMultiplier > 0 {
+ multiplier = backOffMultiplier
+ }
+
+ parallelRpcCalls := uint(DefaultMaxParallelRpcCalls)
+ if parallelRpcCallsLimit > 0 {
+ parallelRpcCalls = parallelRpcCallsLimit
+ }
+
+ return &defaultEvmBatchCaller{
+ lggr: lggr,
+ batchSender: batchSender,
+ batchSizeLimit: batchSize,
+ parallelRpcCallsLimit: parallelRpcCalls,
+ backOffMultiplier: multiplier,
+ }
+}
+
+func (c *defaultEvmBatchCaller) batchCall(ctx context.Context, blockNumber uint64, calls []EvmCall) ([]DataAndErr, error) {
+ if len(calls) == 0 {
+ return nil, nil
+ }
+
+ packedOutputs := make([]string, len(calls))
+ rpcBatchCalls := make([]rpc.BatchElem, len(calls))
+
+ for i, call := range calls {
+ packedInputs, err := call.abi.Pack(call.methodName, call.args...)
+ if err != nil {
+ return nil, fmt.Errorf("pack %s(%+v): %w", call.methodName, call.args, err)
+ }
+
+ blockNumStr := "latest"
+ if blockNumber > 0 {
+ blockNumStr = hexutil.EncodeBig(big.NewInt(0).SetUint64(blockNumber))
+ }
+
+ rpcBatchCalls[i] = rpc.BatchElem{
+ Method: "eth_call",
+ Args: []any{
+ map[string]interface{}{
+ "from": common.Address{},
+ "to": call.contractAddress,
+ "data": hexutil.Bytes(packedInputs),
+ },
+ blockNumStr,
+ },
+ Result: &packedOutputs[i],
+ }
+ }
+
+ err := c.batchSender.BatchCallContext(ctx, rpcBatchCalls)
+ if err != nil {
+ return nil, fmt.Errorf("batch call context: %w", err)
+ }
+
+ results := make([]DataAndErr, len(calls))
+ for i, call := range calls {
+ if rpcBatchCalls[i].Error != nil {
+ results[i].Err = rpcBatchCalls[i].Error
+ continue
+ }
+
+ if packedOutputs[i] == "" {
+ // Some RPCs instead of returning "0x" are returning an empty string.
+ // We are overriding this behaviour for consistent handling of this scenario.
+ packedOutputs[i] = "0x"
+ }
+
+ b, err := hexutil.Decode(packedOutputs[i])
+ if err != nil {
+ return nil, fmt.Errorf("decode result %s: packedOutputs %s: %w", call, packedOutputs[i], err)
+ }
+
+ unpackedOutputs, err := call.abi.Unpack(call.methodName, b)
+ if err != nil {
+ if len(b) == 0 {
+ results[i].Err = fmt.Errorf("unpack result %s: %s: %w", call, err.Error(), ErrEmptyOutput)
+ } else {
+ results[i].Err = fmt.Errorf("unpack result %s: %w", call, err)
+ }
+ continue
+ }
+
+ results[i].Outputs = unpackedOutputs
+ }
+
+ return results, nil
+}
+
+func (c *defaultEvmBatchCaller) batchCallDynamicLimitRetries(ctx context.Context, blockNumber uint64, calls []EvmCall) ([]DataAndErr, error) {
+ lim := c.batchSizeLimit
+ // Limit the batch size to the number of calls
+ if uint(len(calls)) < lim {
+ lim = uint(len(calls))
+ }
+ for {
+ results, err := c.batchCallLimit(ctx, blockNumber, calls, lim)
+ if err == nil {
+ return results, nil
+ }
+
+ if lim <= 1 {
+ return nil, errors.Wrapf(err, "calls %+v", EVMCallsToString(calls))
+ }
+
+ newLim := lim / c.backOffMultiplier
+ if newLim == 0 || newLim == lim {
+ newLim = 1
+ }
+ lim = newLim
+ c.lggr.Errorf("retrying batch call with %d calls and %d limit that failed with error=%s",
+ len(calls), lim, err)
+ }
+}
+
+func (c *defaultEvmBatchCaller) batchCallLimit(ctx context.Context, blockNumber uint64, calls []EvmCall, batchSizeLimit uint) ([]DataAndErr, error) {
+ if batchSizeLimit <= 0 {
+ return c.batchCall(ctx, blockNumber, calls)
+ }
+
+ type job struct {
+ blockNumber uint64
+ calls []EvmCall
+ results []DataAndErr
+ }
+
+ jobs := make([]job, 0)
+ for i := 0; i < len(calls); i += int(batchSizeLimit) {
+ idxFrom := i
+ idxTo := idxFrom + int(batchSizeLimit)
+ if idxTo > len(calls) {
+ idxTo = len(calls)
+ }
+ jobs = append(jobs, job{blockNumber: blockNumber, calls: calls[idxFrom:idxTo], results: nil})
+ }
+
+ if c.parallelRpcCallsLimit > 1 {
+ eg := new(errgroup.Group)
+ eg.SetLimit(int(c.parallelRpcCallsLimit))
+ for jobIdx := range jobs {
+ jobIdx := jobIdx
+ eg.Go(func() error {
+ res, err := c.batchCall(ctx, jobs[jobIdx].blockNumber, jobs[jobIdx].calls)
+ if err != nil {
+ return err
+ }
+ jobs[jobIdx].results = res
+ return nil
+ })
+ }
+ if err := eg.Wait(); err != nil {
+ return nil, err
+ }
+ } else {
+ var err error
+ for jobIdx := range jobs {
+ jobs[jobIdx].results, err = c.batchCall(ctx, jobs[jobIdx].blockNumber, jobs[jobIdx].calls)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ results := make([]DataAndErr, 0)
+ for _, jb := range jobs {
+ results = append(results, jb.results...)
+ }
+ return results, nil
+}
+
+type AbiPackerUnpacker interface {
+ Pack(name string, args ...interface{}) ([]byte, error)
+ Unpack(name string, data []byte) ([]interface{}, error)
+}
+
+type EvmCall struct {
+ abi AbiPackerUnpacker
+ methodName string
+ contractAddress common.Address
+ args []any
+}
+
+func NewEvmCall(abi AbiPackerUnpacker, methodName string, contractAddress common.Address, args ...any) EvmCall {
+ return EvmCall{
+ abi: abi,
+ methodName: methodName,
+ contractAddress: contractAddress,
+ args: args,
+ }
+}
+
+func (c EvmCall) MethodName() string {
+ return c.methodName
+}
+
+func (c EvmCall) String() string {
+ return fmt.Sprintf("%s: %s(%+v)", c.contractAddress.String(), c.methodName, c.args)
+}
+
+func EVMCallsToString(calls []EvmCall) string {
+ callString := ""
+ for _, call := range calls {
+ callString += fmt.Sprintf("%s\n", call.String())
+ }
+ return callString
+}
+
+type DataAndErr struct {
+ Outputs []any
+ Err error
+}
+
+func ParseOutputs[T any](results []DataAndErr, parseFunc func(d DataAndErr) (T, error)) ([]T, error) {
+ parsed := make([]T, 0, len(results))
+
+ for _, res := range results {
+ v, err := parseFunc(res)
+ if err != nil {
+ return nil, fmt.Errorf("parse contract output: %w", err)
+ }
+ parsed = append(parsed, v)
+ }
+
+ return parsed, nil
+}
+
+func ParseOutput[T any](dataAndErr DataAndErr, idx int) (T, error) {
+ var parsed T
+
+ if dataAndErr.Err != nil {
+ return parsed, fmt.Errorf("rpc call error: %w", dataAndErr.Err)
+ }
+
+ if idx < 0 || idx >= len(dataAndErr.Outputs) {
+ return parsed, fmt.Errorf("idx %d is out of bounds for %d outputs", idx, len(dataAndErr.Outputs))
+ }
+
+ res, is := dataAndErr.Outputs[idx].(T)
+ if !is {
+ // some rpc types are not strictly defined
+ // for that reason we try to manually map the fields using json encoding
+ b, err := json.Marshal(dataAndErr.Outputs[idx])
+ if err == nil {
+ var empty T
+ if err := json.Unmarshal(b, &parsed); err == nil && !reflect.DeepEqual(parsed, empty) {
+ return parsed, nil
+ }
+ }
+
+ return parsed, fmt.Errorf("the result type is: %T, expected: %T", dataAndErr.Outputs[idx], parsed)
+ }
+
+ return res, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/rpclib/evm_test.go b/core/services/ocr2/plugins/ccip/internal/rpclib/evm_test.go
new file mode 100644
index 00000000000..1a3d7baf0fc
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/rpclib/evm_test.go
@@ -0,0 +1,223 @@
+package rpclib_test
+
+import (
+ "fmt"
+ "strconv"
+ "testing"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+
+ "github.com/cometbft/cometbft/libs/rand"
+ "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/pkg/errors"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+func TestDefaultEvmBatchCaller_BatchCallDynamicLimit(t *testing.T) {
+ testCases := []struct {
+ name string
+ maxBatchSize uint
+ backOffMultiplier uint
+ numCalls int
+ expectedBatchSizesOnEachRetry []int
+ }{
+ {
+ name: "defaults",
+ maxBatchSize: rpclib.DefaultRpcBatchSizeLimit,
+ backOffMultiplier: rpclib.DefaultRpcBatchBackOffMultiplier,
+ numCalls: 200,
+ expectedBatchSizesOnEachRetry: []int{100, 20, 4, 1},
+ },
+ {
+ name: "base simple scenario",
+ maxBatchSize: 20,
+ backOffMultiplier: 2,
+ numCalls: 100,
+ expectedBatchSizesOnEachRetry: []int{20, 10, 5, 2, 1},
+ },
+ {
+ name: "remainder",
+ maxBatchSize: 99,
+ backOffMultiplier: 5,
+ numCalls: 100,
+ expectedBatchSizesOnEachRetry: []int{99, 19, 3, 1},
+ },
+ {
+ name: "large back off multiplier",
+ maxBatchSize: 20,
+ backOffMultiplier: 18,
+ numCalls: 100,
+ expectedBatchSizesOnEachRetry: []int{20, 1},
+ },
+ {
+ name: "back off equal to batch size",
+ maxBatchSize: 20,
+ backOffMultiplier: 20,
+ numCalls: 100,
+ expectedBatchSizesOnEachRetry: []int{20, 1},
+ },
+ {
+ name: "back off larger than batch size",
+ maxBatchSize: 20,
+ backOffMultiplier: 220,
+ numCalls: 100,
+ expectedBatchSizesOnEachRetry: []int{20, 1},
+ },
+ {
+ name: "back off 1",
+ maxBatchSize: 20,
+ backOffMultiplier: 1,
+ numCalls: 100,
+ expectedBatchSizesOnEachRetry: []int{20, 1},
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ batchSizes := make([]int, 0)
+
+ ec := mocks.NewClient(t)
+ bc := rpclib.NewDynamicLimitedBatchCaller(logger.TestLogger(t), ec, tc.maxBatchSize, tc.backOffMultiplier, 1)
+ ctx := testutils.Context(t)
+ calls := make([]rpclib.EvmCall, tc.numCalls)
+ emptyAbi := abihelpers.MustParseABI("[]")
+ for i := range calls {
+ calls[i] = rpclib.NewEvmCall(emptyAbi, "", common.Address{})
+ }
+ ec.On("BatchCallContext", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
+ evmCalls := args.Get(1).([]rpc.BatchElem)
+ batchSizes = append(batchSizes, len(evmCalls))
+ }).Return(errors.New("some error"))
+ _, _ = bc.BatchCall(ctx, 123, calls)
+
+ assert.Equal(t, tc.expectedBatchSizesOnEachRetry, batchSizes)
+ })
+ }
+}
+
+func TestDefaultEvmBatchCaller_batchCallLimit(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ testCases := []struct {
+ numCalls uint
+ batchSize uint
+ parallelRpcCallsLimit uint
+ }{
+ {numCalls: 100, batchSize: 10, parallelRpcCallsLimit: 5},
+ {numCalls: 10, batchSize: 100, parallelRpcCallsLimit: 10},
+ {numCalls: 1, batchSize: 100, parallelRpcCallsLimit: 10},
+ {numCalls: 1000, batchSize: 10, parallelRpcCallsLimit: 2},
+ {numCalls: rand.Uint() % 1000, batchSize: rand.Uint() % 500, parallelRpcCallsLimit: rand.Uint() % 500},
+ }
+
+ for _, tc := range testCases {
+ t.Run(fmt.Sprintf("%v", tc), func(t *testing.T) {
+ ec := mocks.NewClient(t)
+ bc := rpclib.NewDynamicLimitedBatchCaller(logger.TestLogger(t), ec, tc.batchSize, 99999, tc.parallelRpcCallsLimit)
+
+ // generate the abi and the rpc calls
+ intTyp, err := abi.NewType("uint64", "uint64", nil)
+ assert.NoError(t, err)
+ calls := make([]rpclib.EvmCall, tc.numCalls)
+ mockAbi := abihelpers.MustParseABI("[]")
+ for i := range calls {
+ name := fmt.Sprintf("method_%d", i)
+ meth := abi.NewMethod(name, name, abi.Function, "nonpayable", true, false, abi.Arguments{abi.Argument{Name: "a", Type: intTyp}}, abi.Arguments{abi.Argument{Name: "b", Type: intTyp}})
+ mockAbi.Methods[name] = meth
+ calls[i] = rpclib.NewEvmCall(mockAbi, name, common.Address{}, uint64(i))
+ }
+
+ // mock the rpc call to batch call context
+ // for simplicity we just set an error
+ ec.On("BatchCallContext", mock.Anything, mock.Anything).
+ Run(func(args mock.Arguments) {
+ evmCalls := args.Get(1).([]rpc.BatchElem)
+ for i := range evmCalls {
+ arg := evmCalls[i].Args[0].(map[string]interface{})["data"].(hexutil.Bytes)
+ arg = arg[len(arg)-10:]
+ evmCalls[i].Error = fmt.Errorf("%s", arg)
+ }
+ }).Return(nil)
+
+ // make the call and make sure the results are received in order
+ results, _ := bc.BatchCall(ctx, 0, calls)
+ assert.Len(t, results, len(calls))
+ for i, res := range results {
+ resNum, err := strconv.ParseInt(res.Err.Error()[2:], 16, 64)
+ assert.NoError(t, err)
+ assert.Equal(t, int64(i), resNum)
+ }
+ })
+ }
+}
+
+func TestParseOutput(t *testing.T) {
+ type testCase[T any] struct {
+ name string
+ dataAndErr rpclib.DataAndErr
+ outputIdx int
+ expRes T
+ expErr bool
+ }
+
+ testCases := []testCase[string]{
+ {
+ name: "success",
+ dataAndErr: rpclib.DataAndErr{Outputs: []any{"abc"}, Err: nil},
+ outputIdx: 0,
+ expRes: "abc",
+ expErr: false,
+ },
+ {
+ name: "index error on empty list",
+ dataAndErr: rpclib.DataAndErr{Outputs: []any{}, Err: nil},
+ outputIdx: 0,
+ expErr: true,
+ },
+ {
+ name: "index error on non-empty list",
+ dataAndErr: rpclib.DataAndErr{Outputs: []any{"a", "b"}, Err: nil},
+ outputIdx: 2,
+ expErr: true,
+ },
+ {
+ name: "negative index",
+ dataAndErr: rpclib.DataAndErr{Outputs: []any{"a", "b"}, Err: nil},
+ outputIdx: -1,
+ expErr: true,
+ },
+ {
+ name: "wrong type",
+ dataAndErr: rpclib.DataAndErr{Outputs: []any{1234}, Err: nil},
+ outputIdx: 0,
+ expErr: true,
+ },
+ {
+ name: "has err",
+ dataAndErr: rpclib.DataAndErr{Outputs: []any{"abc"}, Err: fmt.Errorf("some err")},
+ outputIdx: 0,
+ expErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ res, err := rpclib.ParseOutput[string](tc.dataAndErr, tc.outputIdx)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expRes, res)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks/evm_mock.go b/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks/evm_mock.go
new file mode 100644
index 00000000000..aa42814186e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks/evm_mock.go
@@ -0,0 +1,97 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package rpclibmocks
+
+import (
+ context "context"
+
+ rpclib "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// EvmBatchCaller is an autogenerated mock type for the EvmBatchCaller type
+type EvmBatchCaller struct {
+ mock.Mock
+}
+
+type EvmBatchCaller_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *EvmBatchCaller) EXPECT() *EvmBatchCaller_Expecter {
+ return &EvmBatchCaller_Expecter{mock: &_m.Mock}
+}
+
+// BatchCall provides a mock function with given fields: ctx, blockNumber, calls
+func (_m *EvmBatchCaller) BatchCall(ctx context.Context, blockNumber uint64, calls []rpclib.EvmCall) ([]rpclib.DataAndErr, error) {
+ ret := _m.Called(ctx, blockNumber, calls)
+
+ if len(ret) == 0 {
+ panic("no return value specified for BatchCall")
+ }
+
+ var r0 []rpclib.DataAndErr
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, []rpclib.EvmCall) ([]rpclib.DataAndErr, error)); ok {
+ return rf(ctx, blockNumber, calls)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, uint64, []rpclib.EvmCall) []rpclib.DataAndErr); ok {
+ r0 = rf(ctx, blockNumber, calls)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]rpclib.DataAndErr)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, uint64, []rpclib.EvmCall) error); ok {
+ r1 = rf(ctx, blockNumber, calls)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// EvmBatchCaller_BatchCall_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BatchCall'
+type EvmBatchCaller_BatchCall_Call struct {
+ *mock.Call
+}
+
+// BatchCall is a helper method to define mock.On call
+// - ctx context.Context
+// - blockNumber uint64
+// - calls []rpclib.EvmCall
+func (_e *EvmBatchCaller_Expecter) BatchCall(ctx interface{}, blockNumber interface{}, calls interface{}) *EvmBatchCaller_BatchCall_Call {
+ return &EvmBatchCaller_BatchCall_Call{Call: _e.mock.On("BatchCall", ctx, blockNumber, calls)}
+}
+
+func (_c *EvmBatchCaller_BatchCall_Call) Run(run func(ctx context.Context, blockNumber uint64, calls []rpclib.EvmCall)) *EvmBatchCaller_BatchCall_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(uint64), args[2].([]rpclib.EvmCall))
+ })
+ return _c
+}
+
+func (_c *EvmBatchCaller_BatchCall_Call) Return(_a0 []rpclib.DataAndErr, _a1 error) *EvmBatchCaller_BatchCall_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *EvmBatchCaller_BatchCall_Call) RunAndReturn(run func(context.Context, uint64, []rpclib.EvmCall) ([]rpclib.DataAndErr, error)) *EvmBatchCaller_BatchCall_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewEvmBatchCaller creates a new instance of EvmBatchCaller. 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 NewEvmBatchCaller(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *EvmBatchCaller {
+ mock := &EvmBatchCaller{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/metrics.go b/core/services/ocr2/plugins/ccip/metrics.go
new file mode 100644
index 00000000000..f481b5d447d
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/metrics.go
@@ -0,0 +1,99 @@
+package ccip
+
+import (
+ "strconv"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+)
+
+var (
+ unexpiredCommitRoots = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "ccip_unexpired_commit_roots",
+ Help: "Number of unexpired commit roots processed by the plugin",
+ }, []string{"plugin", "source", "dest"})
+ messagesProcessed = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "ccip_number_of_messages_processed",
+ Help: "Number of messages processed by the plugin during different OCR phases",
+ }, []string{"plugin", "source", "dest", "ocrPhase"})
+ sequenceNumberCounter = promauto.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "ccip_sequence_number_counter",
+ Help: "Sequence number of the last message processed by the plugin",
+ }, []string{"plugin", "source", "dest", "ocrPhase"})
+)
+
+type ocrPhase string
+
+const (
+ Observation ocrPhase = "observation"
+ Report ocrPhase = "report"
+ ShouldAccept ocrPhase = "shouldAccept"
+)
+
+type PluginMetricsCollector interface {
+ NumberOfMessagesProcessed(phase ocrPhase, count int)
+ NumberOfMessagesBasedOnInterval(phase ocrPhase, seqNrMin, seqNrMax uint64)
+ UnexpiredCommitRoots(count int)
+ SequenceNumber(phase ocrPhase, seqNr uint64)
+}
+
+type pluginMetricsCollector struct {
+ pluginName string
+ source, dest string
+}
+
+func NewPluginMetricsCollector(pluginLabel string, sourceChainId, destChainId int64) *pluginMetricsCollector {
+ return &pluginMetricsCollector{
+ pluginName: pluginLabel,
+ source: strconv.FormatInt(sourceChainId, 10),
+ dest: strconv.FormatInt(destChainId, 10),
+ }
+}
+
+func (p *pluginMetricsCollector) NumberOfMessagesProcessed(phase ocrPhase, count int) {
+ messagesProcessed.
+ WithLabelValues(p.pluginName, p.source, p.dest, string(phase)).
+ Set(float64(count))
+}
+
+func (p *pluginMetricsCollector) NumberOfMessagesBasedOnInterval(phase ocrPhase, seqNrMin, seqNrMax uint64) {
+ messagesProcessed.
+ WithLabelValues(p.pluginName, p.source, p.dest, string(phase)).
+ Set(float64(seqNrMax - seqNrMin + 1))
+}
+
+func (p *pluginMetricsCollector) UnexpiredCommitRoots(count int) {
+ unexpiredCommitRoots.
+ WithLabelValues(p.pluginName, p.source, p.dest).
+ Set(float64(count))
+}
+
+func (p *pluginMetricsCollector) SequenceNumber(phase ocrPhase, seqNr uint64) {
+ // Don't publish price reports
+ if seqNr == 0 {
+ return
+ }
+
+ sequenceNumberCounter.
+ WithLabelValues(p.pluginName, p.source, p.dest, string(phase)).
+ Set(float64(seqNr))
+}
+
+var (
+ // NoopMetricsCollector is a no-op implementation of PluginMetricsCollector
+ NoopMetricsCollector PluginMetricsCollector = noop{}
+)
+
+type noop struct{}
+
+func (d noop) NumberOfMessagesProcessed(ocrPhase, int) {
+}
+
+func (d noop) NumberOfMessagesBasedOnInterval(ocrPhase, uint64, uint64) {
+}
+
+func (d noop) UnexpiredCommitRoots(int) {
+}
+
+func (d noop) SequenceNumber(ocrPhase, uint64) {
+}
diff --git a/core/services/ocr2/plugins/ccip/metrics_test.go b/core/services/ocr2/plugins/ccip/metrics_test.go
new file mode 100644
index 00000000000..eec67db7dd0
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/metrics_test.go
@@ -0,0 +1,47 @@
+package ccip
+
+import (
+ "testing"
+
+ "github.com/prometheus/client_golang/prometheus/testutil"
+ "github.com/stretchr/testify/assert"
+)
+
+const (
+ sourceChainId = 1337
+ destChainId = 2337
+)
+
+func Test_SequenceNumbers(t *testing.T) {
+ collector := NewPluginMetricsCollector("test", sourceChainId, destChainId)
+
+ collector.SequenceNumber(Report, 10)
+ assert.Equal(t, float64(10), testutil.ToFloat64(sequenceNumberCounter.WithLabelValues("test", "1337", "2337", "report")))
+
+ collector.SequenceNumber(Report, 0)
+ assert.Equal(t, float64(10), testutil.ToFloat64(sequenceNumberCounter.WithLabelValues("test", "1337", "2337", "report")))
+}
+
+func Test_NumberOfMessages(t *testing.T) {
+ collector := NewPluginMetricsCollector("test", sourceChainId, destChainId)
+ collector2 := NewPluginMetricsCollector("test2", destChainId, sourceChainId)
+
+ collector.NumberOfMessagesBasedOnInterval(Observation, 1, 10)
+ assert.Equal(t, float64(10), testutil.ToFloat64(messagesProcessed.WithLabelValues("test", "1337", "2337", "observation")))
+
+ collector.NumberOfMessagesBasedOnInterval(Report, 5, 30)
+ assert.Equal(t, float64(26), testutil.ToFloat64(messagesProcessed.WithLabelValues("test", "1337", "2337", "report")))
+
+ collector2.NumberOfMessagesProcessed(Report, 15)
+ assert.Equal(t, float64(15), testutil.ToFloat64(messagesProcessed.WithLabelValues("test2", "2337", "1337", "report")))
+}
+
+func Test_UnexpiredCommitRoots(t *testing.T) {
+ collector := NewPluginMetricsCollector("test", sourceChainId, destChainId)
+
+ collector.UnexpiredCommitRoots(10)
+ assert.Equal(t, float64(10), testutil.ToFloat64(unexpiredCommitRoots.WithLabelValues("test", "1337", "2337")))
+
+ collector.UnexpiredCommitRoots(5)
+ assert.Equal(t, float64(5), testutil.ToFloat64(unexpiredCommitRoots.WithLabelValues("test", "1337", "2337")))
+}
diff --git a/core/services/ocr2/plugins/ccip/observations.go b/core/services/ocr2/plugins/ccip/observations.go
new file mode 100644
index 00000000000..f79d667a550
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/observations.go
@@ -0,0 +1,149 @@
+package ccip
+
+import (
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "strings"
+
+ "github.com/smartcontractkit/libocr/commontypes"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+// Note if a breaking change is introduced to this struct nodes running different versions
+// will not be able to unmarshal each other's observations. Do not modify unless you
+// know what you are doing.
+type CommitObservation struct {
+ Interval cciptypes.CommitStoreInterval `json:"interval"`
+ TokenPricesUSD map[cciptypes.Address]*big.Int `json:"tokensPerFeeCoin"`
+ SourceGasPriceUSD *big.Int `json:"sourceGasPrice"` // Deprecated
+ SourceGasPriceUSDPerChain map[uint64]*big.Int `json:"sourceGasPriceUSDPerChain"`
+}
+
+// Marshal MUST be used instead of raw json.Marshal(o) since it contains backwards compatibility related changes.
+func (o CommitObservation) Marshal() ([]byte, error) {
+ obsCopy := o
+
+ // Similar to: commitObservationJSONBackComp but for commit observation marshaling.
+ tokenPricesUSD := make(map[cciptypes.Address]*big.Int, len(obsCopy.TokenPricesUSD))
+ for k, v := range obsCopy.TokenPricesUSD {
+ tokenPricesUSD[cciptypes.Address(strings.ToLower(string(k)))] = v
+ }
+ obsCopy.TokenPricesUSD = tokenPricesUSD
+
+ return json.Marshal(&obsCopy)
+}
+
+// ExecutionObservation stores messages as a map pointing from a sequence number (uint) to the message payload (MsgData)
+// Having it structured this way is critical because:
+// * it prevents having duplicated sequence numbers within a single ExecutionObservation (compared to the list representation)
+// * prevents malicious actors from passing multiple messages with the same sequence number
+// Note if a breaking change is introduced to this struct nodes running different versions
+// will not be able to unmarshal each other's observations. Do not modify unless you
+// know what you are doing.
+type ExecutionObservation struct {
+ Messages map[uint64]MsgData `json:"messages"`
+}
+
+type MsgData struct {
+ TokenData [][]byte `json:"tokenData"`
+}
+
+// ObservedMessage is a transient struct used for processing convenience within the plugin. It's easier to process observed messages
+// when all properties are flattened into a single structure.
+// It should not be serialized and returned from types.ReportingPlugin functions, please serialize/deserialize to/from ExecutionObservation instead using NewObservedMessage
+type ObservedMessage struct {
+ SeqNr uint64
+ MsgData
+}
+
+func NewExecutionObservation(observations []ObservedMessage) ExecutionObservation {
+ denormalized := make(map[uint64]MsgData, len(observations))
+ for _, o := range observations {
+ denormalized[o.SeqNr] = MsgData{TokenData: o.TokenData}
+ }
+ return ExecutionObservation{Messages: denormalized}
+}
+
+func NewObservedMessage(seqNr uint64, tokenData [][]byte) ObservedMessage {
+ return ObservedMessage{
+ SeqNr: seqNr,
+ MsgData: MsgData{TokenData: tokenData},
+ }
+}
+
+func (o ExecutionObservation) Marshal() ([]byte, error) {
+ return json.Marshal(&o)
+}
+
+// GetParsableObservations checks the given observations for formatting and value errors.
+// It returns all valid observations, potentially being an empty list. It will log
+// malformed observations but never error.
+//
+// GetParsableObservations MUST be used instead of raw json.Unmarshal(o) since it contains backwards compatibility changes.
+func GetParsableObservations[O CommitObservation | ExecutionObservation](l logger.Logger, observations []types.AttributedObservation) []O {
+ var parseableObservations []O
+ var observers []commontypes.OracleID
+ for _, ao := range observations {
+ if len(ao.Observation) == 0 {
+ // Empty observation
+ l.Infow("Discarded empty observation", "observer", ao.Observer)
+ continue
+ }
+ var ob O
+ var err error
+ obsJSON := ao.Observation
+
+ switch any(ob).(type) {
+ case CommitObservation:
+ commitObservation, err1 := commitObservationJSONBackComp(ao.Observation)
+ if err1 != nil {
+ l.Errorw("commit observation json backwards compatibility format failed", "err", err,
+ "observation", string(ao.Observation), "observer", ao.Observer)
+ continue
+ }
+ ob = any(commitObservation).(O)
+ default:
+ err = json.Unmarshal(obsJSON, &ob)
+ if err != nil {
+ l.Errorw("Received unmarshallable observation", "err", err, "observation", string(ao.Observation), "observer", ao.Observer)
+ continue
+ }
+ }
+
+ parseableObservations = append(parseableObservations, ob)
+ observers = append(observers, ao.Observer)
+ }
+ l.Infow(
+ "Parsed observations",
+ "observers", observers,
+ "observersLength", len(observers),
+ "observationsLength", len(parseableObservations),
+ "rawObservationLength", len(observations),
+ )
+ return parseableObservations
+}
+
+// For backwards compatibility, converts token prices to eip55.
+// Prior to cciptypes.Address we were using go-ethereum common.Address type which is
+// marshalled to lower-case while the string representation we used was eip55.
+// Nodes that run different ccip version should generate the same observations.
+func commitObservationJSONBackComp(obsJson []byte) (CommitObservation, error) {
+ var obs CommitObservation
+ err := json.Unmarshal(obsJson, &obs)
+ if err != nil {
+ return CommitObservation{}, fmt.Errorf("unmarshal observation: %w", err)
+ }
+ tokenPricesUSD := make(map[cciptypes.Address]*big.Int, len(obs.TokenPricesUSD))
+ for k, v := range obs.TokenPricesUSD {
+ tokenPricesUSD[ccipcalc.HexToAddress(string(k))] = v
+ }
+ obs.TokenPricesUSD = tokenPricesUSD
+ return obs, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/observations_test.go b/core/services/ocr2/plugins/ccip/observations_test.go
new file mode 100644
index 00000000000..a3143f157d7
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/observations_test.go
@@ -0,0 +1,305 @@
+package ccip
+
+import (
+ "encoding/json"
+ "math/big"
+ "strings"
+ "testing"
+
+ "github.com/leanovate/gopter"
+ "github.com/leanovate/gopter/gen"
+ "github.com/leanovate/gopter/prop"
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+)
+
+func TestObservationFilter(t *testing.T) {
+ lggr := logger.TestLogger(t)
+ obs1 := CommitObservation{Interval: cciptypes.CommitStoreInterval{Min: 1, Max: 10}}
+ b1, err := obs1.Marshal()
+ require.NoError(t, err)
+ nonEmpty := GetParsableObservations[CommitObservation](lggr, []types.AttributedObservation{{Observation: b1}, {Observation: []byte{}}})
+ require.Equal(t, 1, len(nonEmpty))
+ assert.Equal(t, nonEmpty[0].Interval, obs1.Interval)
+}
+
+// This is the observation format up to 1.4.16 release
+type CommitObservationLegacy struct {
+ Interval cciptypes.CommitStoreInterval `json:"interval"`
+ TokenPricesUSD map[cciptypes.Address]*big.Int `json:"tokensPerFeeCoin"`
+ SourceGasPriceUSD *big.Int `json:"sourceGasPrice"`
+}
+
+func TestObservationCompat_MultiChainGas(t *testing.T) {
+ obsLegacy := CommitObservationLegacy{
+ Interval: cciptypes.CommitStoreInterval{
+ Min: 1,
+ Max: 12,
+ },
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{ccipcalc.HexToAddress("0x1"): big.NewInt(1)},
+ SourceGasPriceUSD: big.NewInt(3)}
+ bL, err := json.Marshal(obsLegacy)
+ require.NoError(t, err)
+ obsNew := CommitObservation{
+ Interval: cciptypes.CommitStoreInterval{
+ Min: 1,
+ Max: 12,
+ },
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{ccipcalc.HexToAddress("0x1"): big.NewInt(1)},
+ SourceGasPriceUSD: big.NewInt(3),
+ }
+ bN, err := json.Marshal(obsNew)
+ require.NoError(t, err)
+
+ observations := GetParsableObservations[CommitObservation](logger.TestLogger(t), []types.AttributedObservation{{Observation: bL}, {Observation: bN}})
+
+ assert.Equal(t, 2, len(observations))
+ assert.Equal(t, observations[0], observations[1])
+}
+
+func TestCommitObservationJsonDeserialization(t *testing.T) {
+ expectedObservation := CommitObservation{
+ Interval: cciptypes.CommitStoreInterval{
+ Min: 1,
+ Max: 12,
+ },
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{
+ ccipcalc.HexToAddress("0x1"): big.NewInt(1)},
+ SourceGasPriceUSD: big.NewInt(3),
+ }
+
+ json := `{
+ "interval": {
+ "Min":1,
+ "Max":12
+ },
+ "tokensPerFeeCoin": {
+ "0x0000000000000000000000000000000000000001": 1
+ },
+ "sourceGasPrice": 3
+ }`
+
+ observations := GetParsableObservations[CommitObservation](logger.TestLogger(t), []types.AttributedObservation{{Observation: []byte(json)}})
+ assert.Equal(t, 1, len(observations))
+ assert.Equal(t, expectedObservation, observations[0])
+}
+
+func TestCommitObservationMarshal(t *testing.T) {
+ obs := CommitObservation{
+ Interval: cciptypes.CommitStoreInterval{
+ Min: 1,
+ Max: 12,
+ },
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{"0xAaAaAa": big.NewInt(1)},
+ SourceGasPriceUSD: big.NewInt(3),
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{123: big.NewInt(3)},
+ }
+
+ b, err := obs.Marshal()
+ require.NoError(t, err)
+ assert.Equal(t, `{"interval":{"Min":1,"Max":12},"tokensPerFeeCoin":{"0xaaaaaa":1},"sourceGasPrice":3,"sourceGasPriceUSDPerChain":{"123":3}}`, string(b))
+
+ // Make sure that the call to Marshal did not alter the original observation object.
+ assert.Len(t, obs.TokenPricesUSD, 1)
+ _, exists := obs.TokenPricesUSD["0xAaAaAa"]
+ assert.True(t, exists)
+ _, exists = obs.TokenPricesUSD["0xaaaaaa"]
+ assert.False(t, exists)
+
+ assert.Len(t, obs.SourceGasPriceUSDPerChain, 1)
+ _, exists = obs.SourceGasPriceUSDPerChain[123]
+ assert.True(t, exists)
+}
+
+func TestExecutionObservationJsonDeserialization(t *testing.T) {
+ expectedObservation := ExecutionObservation{Messages: map[uint64]MsgData{
+ 2: {TokenData: tokenData("c")},
+ 1: {TokenData: tokenData("c")},
+ }}
+
+ // ["YQ=="] is "a"
+ // ["Yw=="] is "c"
+ json := `{
+ "messages": {
+ "2":{"tokenData":["YQ=="]},
+ "1":{"tokenData":["Yw=="]},
+ "2":{"tokenData":["Yw=="]}
+ }
+ }`
+
+ observations := GetParsableObservations[ExecutionObservation](logger.TestLogger(t), []types.AttributedObservation{{Observation: []byte(json)}})
+ assert.Equal(t, 1, len(observations))
+ assert.Equal(t, 2, len(observations[0].Messages))
+ assert.Equal(t, expectedObservation, observations[0])
+}
+
+func TestObservationSize(t *testing.T) {
+ testParams := gopter.DefaultTestParameters()
+ testParams.MinSuccessfulTests = 100
+ p := gopter.NewProperties(testParams)
+ p.Property("bounded observation size", prop.ForAll(func(min, max uint64) bool {
+ o := NewExecutionObservation(
+ []ObservedMessage{
+ {
+ SeqNr: min,
+ MsgData: MsgData{},
+ },
+ {
+ SeqNr: max,
+ MsgData: MsgData{},
+ },
+ },
+ )
+ b, err := o.Marshal()
+ require.NoError(t, err)
+ return len(b) <= MaxObservationLength
+ }, gen.UInt64(), gen.UInt64()))
+ p.TestingRun(t)
+}
+
+func TestNewExecutionObservation(t *testing.T) {
+ tests := []struct {
+ name string
+ observations []ObservedMessage
+ want ExecutionObservation
+ }{
+ {
+ name: "nil observations",
+ observations: nil,
+ want: ExecutionObservation{Messages: map[uint64]MsgData{}},
+ },
+ {
+ name: "empty observations",
+ observations: []ObservedMessage{},
+ want: ExecutionObservation{Messages: map[uint64]MsgData{}},
+ },
+ {
+ name: "observations with different sequence numbers",
+ observations: []ObservedMessage{
+ NewObservedMessage(1, tokenData("a")),
+ NewObservedMessage(2, tokenData("b")),
+ NewObservedMessage(3, tokenData("c")),
+ },
+ want: ExecutionObservation{
+ Messages: map[uint64]MsgData{
+ 1: {TokenData: tokenData("a")},
+ 2: {TokenData: tokenData("b")},
+ 3: {TokenData: tokenData("c")},
+ },
+ },
+ },
+ {
+ name: "last one wins in case of duplicates",
+ observations: []ObservedMessage{
+ NewObservedMessage(1, tokenData("a")),
+ NewObservedMessage(1, tokenData("b")),
+ NewObservedMessage(1, tokenData("c")),
+ },
+ want: ExecutionObservation{
+ Messages: map[uint64]MsgData{
+ 1: {TokenData: tokenData("c")},
+ },
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equalf(t, tt.want, NewExecutionObservation(tt.observations), "NewExecutionObservation(%v)", tt.observations)
+ })
+ }
+}
+
+func tokenData(value string) [][]byte {
+ return [][]byte{[]byte(value)}
+}
+
+func TestCommitObservationJsonSerializationDeserialization(t *testing.T) {
+ jsonEncoded := `{
+ "interval": {
+ "Min":1,
+ "Max":12
+ },
+ "tokensPerFeeCoin": {
+ "0x0000000000000000000000000000000000000001": 1,
+ "0x507877C2E26f1387432D067D2DaAfa7d0420d90a": 2,
+ "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": 3
+ },
+ "sourceGasPrice": 3,
+ "sourceGasPriceUSDPerChain": {
+ "123":3
+ }
+ }`
+
+ expectedObservation := CommitObservation{
+ Interval: cciptypes.CommitStoreInterval{
+ Min: 1,
+ Max: 12,
+ },
+ TokenPricesUSD: map[cciptypes.Address]*big.Int{
+ cciptypes.Address("0x0000000000000000000000000000000000000001"): big.NewInt(1),
+ cciptypes.Address("0x507877C2E26f1387432D067D2DaAfa7d0420d90a"): big.NewInt(2), // json eip55->eip55 parsed
+ cciptypes.Address("0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa"): big.NewInt(3), // json lower->eip55 parsed
+ },
+ SourceGasPriceUSD: big.NewInt(3),
+ SourceGasPriceUSDPerChain: map[uint64]*big.Int{
+ 123: big.NewInt(3),
+ },
+ }
+
+ observations := GetParsableObservations[CommitObservation](logger.TestLogger(t), []types.AttributedObservation{
+ {Observation: []byte(jsonEncoded)},
+ })
+ assert.Equal(t, 1, len(observations))
+ assert.Equal(t, expectedObservation, observations[0])
+
+ backToJson, err := expectedObservation.Marshal()
+ // we expect the json encoded addresses to be lower-case
+ exp := strings.ReplaceAll(
+ jsonEncoded, "0x507877C2E26f1387432D067D2DaAfa7d0420d90a", strings.ToLower("0x507877C2E26f1387432D067D2DaAfa7d0420d90a"))
+ assert.NoError(t, err)
+ assert.JSONEq(t, exp, string(backToJson))
+
+ // and we expect to get the same results after we parse the lower-case addresses
+ observations = GetParsableObservations[CommitObservation](logger.TestLogger(t), []types.AttributedObservation{
+ {Observation: []byte(jsonEncoded)},
+ })
+ assert.Equal(t, 1, len(observations))
+ assert.Equal(t, expectedObservation, observations[0])
+}
+
+func TestAddressEncodingBackwardsCompatibility(t *testing.T) {
+ // The intention of this test is to remind including proper formatting of addresses after config is updated.
+ //
+ // The following tests will fail when a new cciptypes.Address field is added or removed.
+ // If you notice that the test is failing, make sure to apply proper address formatting
+ // after the struct is marshalled/unmarshalled and then include your new field in the expected fields slice to
+ // make this test pass or if you removed a field, remove it from the expected fields slice.
+
+ t.Run("job spec config", func(t *testing.T) {
+ exp := []string{"ccip.Address OffRamp"}
+
+ fields := testhelpers.FindStructFieldsOfCertainType(
+ "ccip.Address",
+ config.CommitPluginJobSpecConfig{PriceGetterConfig: &config.DynamicPriceGetterConfig{}},
+ )
+ assert.Equal(t, exp, fields)
+ })
+
+ t.Run("commit observation", func(t *testing.T) {
+ exp := []string{"map[ccip.Address]*big.Int TokenPricesUSD"}
+
+ fields := testhelpers.FindStructFieldsOfCertainType(
+ "ccip.Address",
+ CommitObservation{SourceGasPriceUSD: big.NewInt(0)},
+ )
+ assert.Equal(t, exp, fields)
+ })
+}
diff --git a/core/services/ocr2/plugins/ccip/pkg/leafer/leafer.go b/core/services/ocr2/plugins/ccip/pkg/leafer/leafer.go
new file mode 100644
index 00000000000..c334f159fd2
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/pkg/leafer/leafer.go
@@ -0,0 +1,61 @@
+package leafer
+
+import (
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0"
+)
+
+// LeafHasher converts a CCIPSendRequested event into something that can be hashed and hashes it.
+type LeafHasher interface {
+ HashLeaf(log types.Log) ([32]byte, error)
+}
+
+// Version is the contract to use.
+type Version string
+
+const (
+ V1_0_0 Version = "v1_0_0"
+ V1_2_0 Version = "v1_2_0"
+ V1_5_0 Version = "v1_5_0"
+)
+
+// MakeLeafHasher is a factory function to construct the onramp implementing the HashLeaf function for a given version.
+func MakeLeafHasher(ver Version, cl bind.ContractBackend, sourceChainSelector uint64, destChainSelector uint64, onRampId common.Address, ctx hashutil.Hasher[[32]byte]) (LeafHasher, error) {
+ switch ver {
+ case V1_0_0:
+ or, err := evm_2_evm_onramp_1_0_0.NewEVM2EVMOnRamp(onRampId, cl)
+ if err != nil {
+ return nil, err
+ }
+ h := v1_0_0.NewLeafHasher(sourceChainSelector, destChainSelector, onRampId, ctx, or)
+ return h, nil
+ case V1_2_0:
+ or, err := evm_2_evm_onramp_1_2_0.NewEVM2EVMOnRamp(onRampId, cl)
+ if err != nil {
+ return nil, err
+ }
+ h := v1_2_0.NewLeafHasher(sourceChainSelector, destChainSelector, onRampId, ctx, or)
+ return h, nil
+ case V1_5_0:
+ or, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(onRampId, cl)
+ if err != nil {
+ return nil, err
+ }
+ h := v1_5_0.NewLeafHasher(sourceChainSelector, destChainSelector, onRampId, ctx, or)
+ return h, nil
+ default:
+ return nil, fmt.Errorf("unknown version %q", ver)
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/prices/da_price_estimator.go b/core/services/ocr2/plugins/ccip/prices/da_price_estimator.go
new file mode 100644
index 00000000000..7c75b9bdd99
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/prices/da_price_estimator.go
@@ -0,0 +1,176 @@
+package prices
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+type DAGasPriceEstimator struct {
+ execEstimator GasPriceEstimator
+ l1Oracle rollups.L1Oracle
+ priceEncodingLength uint
+ daDeviationPPB int64
+ daOverheadGas int64
+ gasPerDAByte int64
+ daMultiplier int64
+}
+
+func NewDAGasPriceEstimator(
+ estimator gas.EvmFeeEstimator,
+ maxGasPrice *big.Int,
+ deviationPPB int64,
+ daDeviationPPB int64,
+) *DAGasPriceEstimator {
+ return &DAGasPriceEstimator{
+ execEstimator: NewExecGasPriceEstimator(estimator, maxGasPrice, deviationPPB),
+ l1Oracle: estimator.L1Oracle(),
+ priceEncodingLength: daGasPriceEncodingLength,
+ daDeviationPPB: daDeviationPPB,
+ }
+}
+
+func (g DAGasPriceEstimator) GetGasPrice(ctx context.Context) (*big.Int, error) {
+ execGasPrice, err := g.execEstimator.GetGasPrice(ctx)
+ if err != nil {
+ return nil, err
+ }
+ var gasPrice *big.Int = execGasPrice
+ if gasPrice.BitLen() > int(g.priceEncodingLength) {
+ return nil, fmt.Errorf("native gas price exceeded max range %+v", gasPrice)
+ }
+
+ if g.l1Oracle == nil {
+ return gasPrice, nil
+ }
+
+ daGasPriceWei, err := g.l1Oracle.GasPrice(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ if daGasPrice := daGasPriceWei.ToInt(); daGasPrice.Cmp(big.NewInt(0)) > 0 {
+ if daGasPrice.BitLen() > int(g.priceEncodingLength) {
+ return nil, fmt.Errorf("data availability gas price exceeded max range %+v", daGasPrice)
+ }
+
+ daGasPrice = new(big.Int).Lsh(daGasPrice, g.priceEncodingLength)
+ gasPrice = new(big.Int).Add(gasPrice, daGasPrice)
+ }
+
+ return gasPrice, nil
+}
+
+func (g DAGasPriceEstimator) DenoteInUSD(p *big.Int, wrappedNativePrice *big.Int) (*big.Int, error) {
+ daGasPrice, execGasPrice, err := g.parseEncodedGasPrice(p)
+ if err != nil {
+ return nil, err
+ }
+
+ // This assumes l1GasPrice is priced using the same native token as l2 native
+ daUSD := ccipcalc.CalculateUsdPerUnitGas(daGasPrice, wrappedNativePrice)
+ if daUSD.BitLen() > int(g.priceEncodingLength) {
+ return nil, fmt.Errorf("data availability gas price USD exceeded max range %+v", daUSD)
+ }
+ execUSD := ccipcalc.CalculateUsdPerUnitGas(execGasPrice, wrappedNativePrice)
+ if execUSD.BitLen() > int(g.priceEncodingLength) {
+ return nil, fmt.Errorf("exec gas price USD exceeded max range %+v", execUSD)
+ }
+
+ daUSD = new(big.Int).Lsh(daUSD, g.priceEncodingLength)
+ return new(big.Int).Add(daUSD, execUSD), nil
+}
+
+func (g DAGasPriceEstimator) Median(gasPrices []*big.Int) (*big.Int, error) {
+ daPrices := make([]*big.Int, len(gasPrices))
+ execPrices := make([]*big.Int, len(gasPrices))
+
+ for i := range gasPrices {
+ daGasPrice, execGasPrice, err := g.parseEncodedGasPrice(gasPrices[i])
+ if err != nil {
+ return nil, err
+ }
+
+ daPrices[i] = daGasPrice
+ execPrices[i] = execGasPrice
+ }
+
+ daMedian := ccipcalc.BigIntSortedMiddle(daPrices)
+ execMedian := ccipcalc.BigIntSortedMiddle(execPrices)
+
+ daMedian = new(big.Int).Lsh(daMedian, g.priceEncodingLength)
+ return new(big.Int).Add(daMedian, execMedian), nil
+}
+
+func (g DAGasPriceEstimator) Deviates(p1, p2 *big.Int) (bool, error) {
+ p1DAGasPrice, p1ExecGasPrice, err := g.parseEncodedGasPrice(p1)
+ if err != nil {
+ return false, err
+ }
+ p2DAGasPrice, p2ExecGasPrice, err := g.parseEncodedGasPrice(p2)
+ if err != nil {
+ return false, err
+ }
+
+ execDeviates, err := g.execEstimator.Deviates(p1ExecGasPrice, p2ExecGasPrice)
+ if err != nil {
+ return false, err
+ }
+ if execDeviates {
+ return execDeviates, nil
+ }
+
+ return ccipcalc.Deviates(p1DAGasPrice, p2DAGasPrice, g.daDeviationPPB), nil
+}
+
+func (g DAGasPriceEstimator) EstimateMsgCostUSD(p *big.Int, wrappedNativePrice *big.Int, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error) {
+ daGasPrice, execGasPrice, err := g.parseEncodedGasPrice(p)
+ if err != nil {
+ return nil, err
+ }
+
+ execCostUSD, err := g.execEstimator.EstimateMsgCostUSD(execGasPrice, wrappedNativePrice, msg)
+ if err != nil {
+ return nil, err
+ }
+
+ // If there is data availability price component, then include data availability cost in fee estimation
+ if daGasPrice.Cmp(big.NewInt(0)) > 0 {
+ daGasCostUSD := g.estimateDACostUSD(daGasPrice, wrappedNativePrice, msg)
+ execCostUSD = new(big.Int).Add(daGasCostUSD, execCostUSD)
+ }
+ return execCostUSD, nil
+}
+
+func (g DAGasPriceEstimator) parseEncodedGasPrice(p *big.Int) (*big.Int, *big.Int, error) {
+ if p.BitLen() > int(g.priceEncodingLength*2) {
+ return nil, nil, fmt.Errorf("encoded gas price exceeded max range %+v", p)
+ }
+
+ daGasPrice := new(big.Int).Rsh(p, g.priceEncodingLength)
+
+ daStart := new(big.Int).Lsh(big.NewInt(1), g.priceEncodingLength)
+ execGasPrice := new(big.Int).Mod(p, daStart)
+
+ return daGasPrice, execGasPrice, nil
+}
+
+func (g DAGasPriceEstimator) estimateDACostUSD(daGasPrice *big.Int, wrappedNativePrice *big.Int, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) *big.Int {
+ var sourceTokenDataLen int
+ for _, tokenData := range msg.SourceTokenData {
+ sourceTokenDataLen += len(tokenData)
+ }
+
+ dataLen := evmMessageFixedBytes + len(msg.Data) + len(msg.TokenAmounts)*evmMessageBytesPerToken + sourceTokenDataLen
+ dataGas := big.NewInt(int64(dataLen)*g.gasPerDAByte + g.daOverheadGas)
+
+ dataGasEstimate := new(big.Int).Mul(dataGas, daGasPrice)
+ dataGasEstimate = new(big.Int).Div(new(big.Int).Mul(dataGasEstimate, big.NewInt(g.daMultiplier)), big.NewInt(daMultiplierBase))
+
+ return ccipcalc.CalculateUsdPerUnitGas(dataGasEstimate, wrappedNativePrice)
+}
diff --git a/core/services/ocr2/plugins/ccip/prices/da_price_estimator_test.go b/core/services/ocr2/plugins/ccip/prices/da_price_estimator_test.go
new file mode 100644
index 00000000000..2f8616a8669
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/prices/da_price_estimator_test.go
@@ -0,0 +1,440 @@
+package prices
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups/mocks"
+)
+
+func encodeGasPrice(daPrice, execPrice *big.Int) *big.Int {
+ return new(big.Int).Add(new(big.Int).Lsh(daPrice, daGasPriceEncodingLength), execPrice)
+}
+
+func TestDAPriceEstimator_GetGasPrice(t *testing.T) {
+ ctx := context.Background()
+
+ testCases := []struct {
+ name string
+ daGasPrice *big.Int
+ execGasPrice *big.Int
+ expPrice *big.Int
+ expErr bool
+ }{
+ {
+ name: "base",
+ daGasPrice: big.NewInt(1),
+ execGasPrice: big.NewInt(0),
+ expPrice: encodeGasPrice(big.NewInt(1), big.NewInt(0)),
+ expErr: false,
+ },
+ {
+ name: "large values",
+ daGasPrice: big.NewInt(1e9), // 1 gwei
+ execGasPrice: big.NewInt(200e9), // 200 gwei
+ expPrice: encodeGasPrice(big.NewInt(1e9), big.NewInt(200e9)),
+ expErr: false,
+ },
+ {
+ name: "zero DA price",
+ daGasPrice: big.NewInt(0),
+ execGasPrice: big.NewInt(200e9),
+ expPrice: encodeGasPrice(big.NewInt(0), big.NewInt(200e9)),
+ expErr: false,
+ },
+ {
+ name: "zero exec price",
+ daGasPrice: big.NewInt(1e9),
+ execGasPrice: big.NewInt(0),
+ expPrice: encodeGasPrice(big.NewInt(1e9), big.NewInt(0)),
+ expErr: false,
+ },
+ {
+ name: "price out of bounds",
+ daGasPrice: new(big.Int).Lsh(big.NewInt(1), daGasPriceEncodingLength),
+ execGasPrice: big.NewInt(1),
+ expPrice: nil,
+ expErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ execEstimator := NewMockGasPriceEstimator(t)
+ execEstimator.On("GetGasPrice", ctx).Return(tc.execGasPrice, nil)
+
+ l1Oracle := mocks.NewL1Oracle(t)
+ l1Oracle.On("GasPrice", ctx).Return(assets.NewWei(tc.daGasPrice), nil)
+
+ g := DAGasPriceEstimator{
+ execEstimator: execEstimator,
+ l1Oracle: l1Oracle,
+ priceEncodingLength: daGasPriceEncodingLength,
+ }
+
+ gasPrice, err := g.GetGasPrice(ctx)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expPrice, gasPrice)
+ })
+ }
+
+ t.Run("nil L1 oracle", func(t *testing.T) {
+ expPrice := big.NewInt(1)
+
+ execEstimator := NewMockGasPriceEstimator(t)
+ execEstimator.On("GetGasPrice", ctx).Return(expPrice, nil)
+
+ g := DAGasPriceEstimator{
+ execEstimator: execEstimator,
+ l1Oracle: nil,
+ priceEncodingLength: daGasPriceEncodingLength,
+ }
+
+ gasPrice, err := g.GetGasPrice(ctx)
+ assert.NoError(t, err)
+ assert.Equal(t, expPrice, gasPrice)
+ })
+}
+
+func TestDAPriceEstimator_DenoteInUSD(t *testing.T) {
+ val1e18 := func(val int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(val)) }
+
+ testCases := []struct {
+ name string
+ gasPrice *big.Int
+ nativePrice *big.Int
+ expPrice *big.Int
+ }{
+ {
+ name: "base",
+ gasPrice: encodeGasPrice(big.NewInt(1e9), big.NewInt(10e9)),
+ nativePrice: val1e18(2_000),
+ expPrice: encodeGasPrice(big.NewInt(2000e9), big.NewInt(20000e9)),
+ },
+ {
+ name: "low price truncates to 0",
+ gasPrice: encodeGasPrice(big.NewInt(1e9), big.NewInt(10e9)),
+ nativePrice: big.NewInt(1),
+ expPrice: big.NewInt(0),
+ },
+ {
+ name: "high price",
+ gasPrice: encodeGasPrice(val1e18(1), val1e18(10)),
+ nativePrice: val1e18(2000),
+ expPrice: encodeGasPrice(val1e18(2_000), val1e18(20_000)),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ g := DAGasPriceEstimator{
+ priceEncodingLength: daGasPriceEncodingLength,
+ }
+
+ gasPrice, err := g.DenoteInUSD(tc.gasPrice, tc.nativePrice)
+ assert.NoError(t, err)
+ assert.True(t, tc.expPrice.Cmp(gasPrice) == 0)
+ })
+ }
+}
+
+func TestDAPriceEstimator_Median(t *testing.T) {
+ val1e18 := func(val int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(val)) }
+
+ testCases := []struct {
+ name string
+ gasPrices []*big.Int
+ expMedian *big.Int
+ }{
+ {
+ name: "base",
+ gasPrices: []*big.Int{
+ encodeGasPrice(big.NewInt(1), big.NewInt(1)),
+ encodeGasPrice(big.NewInt(2), big.NewInt(2)),
+ encodeGasPrice(big.NewInt(3), big.NewInt(3)),
+ },
+ expMedian: encodeGasPrice(big.NewInt(2), big.NewInt(2)),
+ },
+ {
+ name: "median 2",
+ gasPrices: []*big.Int{
+ encodeGasPrice(big.NewInt(1), big.NewInt(1)),
+ encodeGasPrice(big.NewInt(2), big.NewInt(2)),
+ },
+ expMedian: encodeGasPrice(big.NewInt(2), big.NewInt(2)),
+ },
+ {
+ name: "large values",
+ gasPrices: []*big.Int{
+ encodeGasPrice(val1e18(5), val1e18(5)),
+ encodeGasPrice(val1e18(4), val1e18(4)),
+ encodeGasPrice(val1e18(3), val1e18(3)),
+ encodeGasPrice(val1e18(2), val1e18(2)),
+ encodeGasPrice(val1e18(1), val1e18(1)),
+ },
+ expMedian: encodeGasPrice(val1e18(3), val1e18(3)),
+ },
+ {
+ name: "zeros",
+ gasPrices: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
+ expMedian: big.NewInt(0),
+ },
+ {
+ name: "picks median of each price component individually",
+ gasPrices: []*big.Int{
+ encodeGasPrice(val1e18(1), val1e18(3)),
+ encodeGasPrice(val1e18(2), val1e18(2)),
+ encodeGasPrice(val1e18(3), val1e18(1)),
+ },
+ expMedian: encodeGasPrice(val1e18(2), val1e18(2)),
+ },
+ {
+ name: "unsorted even number of price components",
+ gasPrices: []*big.Int{
+ encodeGasPrice(val1e18(1), val1e18(22)),
+ encodeGasPrice(val1e18(4), val1e18(33)),
+ encodeGasPrice(val1e18(2), val1e18(44)),
+ encodeGasPrice(val1e18(3), val1e18(11)),
+ },
+ expMedian: encodeGasPrice(val1e18(3), val1e18(33)),
+ },
+ {
+ name: "equal DA price components",
+ gasPrices: []*big.Int{
+ encodeGasPrice(val1e18(2), val1e18(22)),
+ encodeGasPrice(val1e18(2), val1e18(33)),
+ encodeGasPrice(val1e18(2), val1e18(44)),
+ encodeGasPrice(val1e18(2), val1e18(11)),
+ },
+ expMedian: encodeGasPrice(val1e18(2), val1e18(33)),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ g := DAGasPriceEstimator{
+ priceEncodingLength: daGasPriceEncodingLength,
+ }
+
+ gasPrice, err := g.Median(tc.gasPrices)
+ assert.NoError(t, err)
+ assert.True(t, tc.expMedian.Cmp(gasPrice) == 0)
+ })
+ }
+}
+
+func TestDAPriceEstimator_Deviates(t *testing.T) {
+ testCases := []struct {
+ name string
+ gasPrice1 *big.Int
+ gasPrice2 *big.Int
+ daDeviationPPB int64
+ execDeviationPPB int64
+ expDeviates bool
+ }{
+ {
+ name: "base",
+ gasPrice1: encodeGasPrice(big.NewInt(100e8), big.NewInt(100e8)),
+ gasPrice2: encodeGasPrice(big.NewInt(79e8), big.NewInt(79e8)),
+ daDeviationPPB: 2e8,
+ execDeviationPPB: 2e8,
+ expDeviates: true,
+ },
+ {
+ name: "negative difference also deviates",
+ gasPrice1: encodeGasPrice(big.NewInt(100e8), big.NewInt(100e8)),
+ gasPrice2: encodeGasPrice(big.NewInt(121e8), big.NewInt(121e8)),
+ daDeviationPPB: 2e8,
+ execDeviationPPB: 2e8,
+ expDeviates: true,
+ },
+ {
+ name: "only DA component deviates",
+ gasPrice1: encodeGasPrice(big.NewInt(100e8), big.NewInt(100e8)),
+ gasPrice2: encodeGasPrice(big.NewInt(150e8), big.NewInt(110e8)),
+ daDeviationPPB: 2e8,
+ execDeviationPPB: 2e8,
+ expDeviates: true,
+ },
+ {
+ name: "only exec component deviates",
+ gasPrice1: encodeGasPrice(big.NewInt(100e8), big.NewInt(100e8)),
+ gasPrice2: encodeGasPrice(big.NewInt(110e8), big.NewInt(150e8)),
+ daDeviationPPB: 2e8,
+ execDeviationPPB: 2e8,
+ expDeviates: true,
+ },
+ {
+ name: "both do not deviate",
+ gasPrice1: encodeGasPrice(big.NewInt(100e8), big.NewInt(100e8)),
+ gasPrice2: encodeGasPrice(big.NewInt(110e8), big.NewInt(110e8)),
+ daDeviationPPB: 2e8,
+ execDeviationPPB: 2e8,
+ expDeviates: false,
+ },
+ {
+ name: "zero DA price and exec deviates",
+ gasPrice1: encodeGasPrice(big.NewInt(0), big.NewInt(100e8)),
+ gasPrice2: encodeGasPrice(big.NewInt(0), big.NewInt(121e8)),
+ daDeviationPPB: 2e8,
+ execDeviationPPB: 2e8,
+ expDeviates: true,
+ },
+ {
+ name: "zero DA price and exec does not deviate",
+ gasPrice1: encodeGasPrice(big.NewInt(0), big.NewInt(100e8)),
+ gasPrice2: encodeGasPrice(big.NewInt(0), big.NewInt(110e8)),
+ daDeviationPPB: 2e8,
+ execDeviationPPB: 2e8,
+ expDeviates: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ g := DAGasPriceEstimator{
+ execEstimator: ExecGasPriceEstimator{
+ deviationPPB: tc.execDeviationPPB,
+ },
+ daDeviationPPB: tc.daDeviationPPB,
+ priceEncodingLength: daGasPriceEncodingLength,
+ }
+
+ deviated, err := g.Deviates(tc.gasPrice1, tc.gasPrice2)
+ assert.NoError(t, err)
+ if tc.expDeviates {
+ assert.True(t, deviated)
+ } else {
+ assert.False(t, deviated)
+ }
+ })
+ }
+}
+
+func TestDAPriceEstimator_EstimateMsgCostUSD(t *testing.T) {
+ execCostUSD := big.NewInt(100_000)
+
+ testCases := []struct {
+ name string
+ gasPrice *big.Int
+ wrappedNativePrice *big.Int
+ msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta
+ daOverheadGas int64
+ gasPerDAByte int64
+ daMultiplier int64
+ expUSD *big.Int
+ }{
+ {
+ name: "only DA overhead",
+ gasPrice: encodeGasPrice(big.NewInt(1e9), big.NewInt(0)), // 1 gwei DA price, 0 exec price
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ Data: []byte{},
+ TokenAmounts: []cciptypes.TokenAmount{},
+ SourceTokenData: [][]byte{},
+ },
+ },
+ daOverheadGas: 100_000,
+ gasPerDAByte: 0,
+ daMultiplier: 10_000, // 1x multiplier
+ expUSD: new(big.Int).Add(execCostUSD, big.NewInt(100_000e9)),
+ },
+ {
+ name: "include message data gas",
+ gasPrice: encodeGasPrice(big.NewInt(1e9), big.NewInt(0)), // 1 gwei DA price, 0 exec price
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ Data: make([]byte, 1_000),
+ TokenAmounts: make([]cciptypes.TokenAmount, 5),
+ SourceTokenData: [][]byte{
+ make([]byte, 10), make([]byte, 10), make([]byte, 10), make([]byte, 10), make([]byte, 10),
+ },
+ },
+ },
+ daOverheadGas: 100_000,
+ gasPerDAByte: 16,
+ daMultiplier: 10_000, // 1x multiplier
+ expUSD: new(big.Int).Add(execCostUSD, big.NewInt(134_208e9)),
+ },
+ {
+ name: "zero DA price",
+ gasPrice: big.NewInt(0), // 1 gwei DA price, 0 exec price
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ Data: []byte{},
+ TokenAmounts: []cciptypes.TokenAmount{},
+ SourceTokenData: [][]byte{},
+ },
+ },
+ daOverheadGas: 100_000,
+ gasPerDAByte: 16,
+ daMultiplier: 10_000, // 1x multiplier
+ expUSD: execCostUSD,
+ },
+ {
+ name: "double native price",
+ gasPrice: encodeGasPrice(big.NewInt(1e9), big.NewInt(0)), // 1 gwei DA price, 0 exec price
+ wrappedNativePrice: big.NewInt(2e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ Data: []byte{},
+ TokenAmounts: []cciptypes.TokenAmount{},
+ SourceTokenData: [][]byte{},
+ },
+ },
+ daOverheadGas: 100_000,
+ gasPerDAByte: 0,
+ daMultiplier: 10_000, // 1x multiplier
+ expUSD: new(big.Int).Add(execCostUSD, big.NewInt(200_000e9)),
+ },
+ {
+ name: "half multiplier",
+ gasPrice: encodeGasPrice(big.NewInt(1e9), big.NewInt(0)), // 1 gwei DA price, 0 exec price
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ Data: []byte{},
+ TokenAmounts: []cciptypes.TokenAmount{},
+ SourceTokenData: [][]byte{},
+ },
+ },
+ daOverheadGas: 100_000,
+ gasPerDAByte: 0,
+ daMultiplier: 5_000, // 0.5x multiplier
+ expUSD: new(big.Int).Add(execCostUSD, big.NewInt(50_000e9)),
+ },
+ }
+
+ for _, tc := range testCases {
+ execEstimator := NewMockGasPriceEstimator(t)
+ execEstimator.On("EstimateMsgCostUSD", mock.Anything, tc.wrappedNativePrice, tc.msg).Return(execCostUSD, nil)
+
+ t.Run(tc.name, func(t *testing.T) {
+ g := DAGasPriceEstimator{
+ execEstimator: execEstimator,
+ l1Oracle: nil,
+ priceEncodingLength: daGasPriceEncodingLength,
+ daOverheadGas: tc.daOverheadGas,
+ gasPerDAByte: tc.gasPerDAByte,
+ daMultiplier: tc.daMultiplier,
+ }
+
+ costUSD, err := g.EstimateMsgCostUSD(tc.gasPrice, tc.wrappedNativePrice, tc.msg)
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expUSD, costUSD)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/prices/exec_price_estimator.go b/core/services/ocr2/plugins/ccip/prices/exec_price_estimator.go
new file mode 100644
index 00000000000..031dc25ed84
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/prices/exec_price_estimator.go
@@ -0,0 +1,65 @@
+package prices
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+type ExecGasPriceEstimator struct {
+ estimator gas.EvmFeeEstimator
+ maxGasPrice *big.Int
+ deviationPPB int64
+}
+
+func NewExecGasPriceEstimator(estimator gas.EvmFeeEstimator, maxGasPrice *big.Int, deviationPPB int64) ExecGasPriceEstimator {
+ return ExecGasPriceEstimator{
+ estimator: estimator,
+ maxGasPrice: maxGasPrice,
+ deviationPPB: deviationPPB,
+ }
+}
+
+func (g ExecGasPriceEstimator) GetGasPrice(ctx context.Context) (*big.Int, error) {
+ gasPriceWei, _, err := g.estimator.GetFee(ctx, nil, 0, assets.NewWei(g.maxGasPrice), nil)
+ if err != nil {
+ return nil, err
+ }
+ // Use legacy if no dynamic is available.
+ gasPrice := gasPriceWei.Legacy.ToInt()
+ if gasPriceWei.DynamicFeeCap != nil {
+ gasPrice = gasPriceWei.DynamicFeeCap.ToInt()
+ }
+ if gasPrice == nil {
+ return nil, fmt.Errorf("missing gas price %+v", gasPriceWei)
+ }
+
+ return gasPrice, nil
+}
+
+func (g ExecGasPriceEstimator) DenoteInUSD(p *big.Int, wrappedNativePrice *big.Int) (*big.Int, error) {
+ return ccipcalc.CalculateUsdPerUnitGas(p, wrappedNativePrice), nil
+}
+
+func (g ExecGasPriceEstimator) Median(gasPrices []*big.Int) (*big.Int, error) {
+ return ccipcalc.BigIntSortedMiddle(gasPrices), nil
+}
+
+func (g ExecGasPriceEstimator) Deviates(p1 *big.Int, p2 *big.Int) (bool, error) {
+ return ccipcalc.Deviates(p1, p2, g.deviationPPB), nil
+}
+
+func (g ExecGasPriceEstimator) EstimateMsgCostUSD(p *big.Int, wrappedNativePrice *big.Int, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error) {
+ execGasAmount := new(big.Int).Add(big.NewInt(feeBoostingOverheadGas), msg.GasLimit)
+ execGasAmount = new(big.Int).Add(execGasAmount, new(big.Int).Mul(big.NewInt(int64(len(msg.Data))), big.NewInt(execGasPerPayloadByte)))
+ execGasAmount = new(big.Int).Add(execGasAmount, new(big.Int).Mul(big.NewInt(int64(len(msg.TokenAmounts))), big.NewInt(execGasPerToken)))
+
+ execGasCost := new(big.Int).Mul(execGasAmount, p)
+
+ return ccipcalc.CalculateUsdPerUnitGas(execGasCost, wrappedNativePrice), nil
+}
diff --git a/core/services/ocr2/plugins/ccip/prices/exec_price_estimator_test.go b/core/services/ocr2/plugins/ccip/prices/exec_price_estimator_test.go
new file mode 100644
index 00000000000..69538057094
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/prices/exec_price_estimator_test.go
@@ -0,0 +1,352 @@
+package prices
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+ "github.com/stretchr/testify/assert"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks"
+)
+
+func TestExecPriceEstimator_GetGasPrice(t *testing.T) {
+ ctx := context.Background()
+
+ testCases := []struct {
+ name string
+ sourceFeeEstimatorRespFee gas.EvmFee
+ sourceFeeEstimatorRespErr error
+ maxGasPrice *big.Int
+ expPrice *big.Int
+ expErr bool
+ }{
+ {
+ name: "gets legacy gas price",
+ sourceFeeEstimatorRespFee: gas.EvmFee{
+ Legacy: assets.NewWei(big.NewInt(10)),
+ DynamicFeeCap: nil,
+ },
+ sourceFeeEstimatorRespErr: nil,
+ maxGasPrice: big.NewInt(1),
+ expPrice: big.NewInt(10),
+ expErr: false,
+ },
+ {
+ name: "gets dynamic gas price",
+ sourceFeeEstimatorRespFee: gas.EvmFee{
+ Legacy: nil,
+ DynamicFeeCap: assets.NewWei(big.NewInt(20)),
+ },
+ sourceFeeEstimatorRespErr: nil,
+ maxGasPrice: big.NewInt(1),
+ expPrice: big.NewInt(20),
+ expErr: false,
+ },
+ {
+ name: "gets dynamic gas price over legacy gas price",
+ sourceFeeEstimatorRespFee: gas.EvmFee{
+ Legacy: assets.NewWei(big.NewInt(10)),
+ DynamicFeeCap: assets.NewWei(big.NewInt(20)),
+ },
+ sourceFeeEstimatorRespErr: nil,
+ maxGasPrice: big.NewInt(1),
+ expPrice: big.NewInt(20),
+ expErr: false,
+ },
+ {
+ name: "fee estimator error",
+ sourceFeeEstimatorRespFee: gas.EvmFee{
+ Legacy: assets.NewWei(big.NewInt(10)),
+ DynamicFeeCap: nil,
+ },
+ sourceFeeEstimatorRespErr: errors.New("fee estimator error"),
+ maxGasPrice: big.NewInt(1),
+ expPrice: nil,
+ expErr: true,
+ },
+ {
+ name: "nil gas price error",
+ sourceFeeEstimatorRespFee: gas.EvmFee{
+ Legacy: nil,
+ DynamicFeeCap: nil,
+ },
+ sourceFeeEstimatorRespErr: nil,
+ maxGasPrice: big.NewInt(1),
+ expPrice: nil,
+ expErr: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ sourceFeeEstimator := mocks.NewEvmFeeEstimator(t)
+ sourceFeeEstimator.On("GetFee", ctx, []byte(nil), uint64(0), assets.NewWei(tc.maxGasPrice), (*common.Address)(nil)).Return(
+ tc.sourceFeeEstimatorRespFee, uint64(0), tc.sourceFeeEstimatorRespErr)
+
+ g := ExecGasPriceEstimator{
+ estimator: sourceFeeEstimator,
+ maxGasPrice: tc.maxGasPrice,
+ }
+
+ gasPrice, err := g.GetGasPrice(ctx)
+ if tc.expErr {
+ assert.Nil(t, gasPrice)
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expPrice, gasPrice)
+ })
+ }
+}
+
+func TestExecPriceEstimator_DenoteInUSD(t *testing.T) {
+ val1e18 := func(val int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(val)) }
+
+ testCases := []struct {
+ name string
+ gasPrice *big.Int
+ nativePrice *big.Int
+ expPrice *big.Int
+ }{
+ {
+ name: "base",
+ gasPrice: big.NewInt(1e9),
+ nativePrice: val1e18(2_000),
+ expPrice: big.NewInt(2_000e9),
+ },
+ {
+ name: "low price truncates to 0",
+ gasPrice: big.NewInt(1e9),
+ nativePrice: big.NewInt(1),
+ expPrice: big.NewInt(0),
+ },
+ {
+ name: "high price",
+ gasPrice: val1e18(1),
+ nativePrice: val1e18(2_000),
+ expPrice: val1e18(2_000),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ g := ExecGasPriceEstimator{}
+
+ gasPrice, err := g.DenoteInUSD(tc.gasPrice, tc.nativePrice)
+ assert.NoError(t, err)
+ assert.True(t, tc.expPrice.Cmp(gasPrice) == 0)
+ })
+ }
+}
+
+func TestExecPriceEstimator_Median(t *testing.T) {
+ val1e18 := func(val int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(val)) }
+
+ testCases := []struct {
+ name string
+ gasPrices []*big.Int
+ expMedian *big.Int
+ }{
+ {
+ name: "base",
+ gasPrices: []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
+ expMedian: big.NewInt(2),
+ },
+ {
+ name: "median 1",
+ gasPrices: []*big.Int{big.NewInt(1)},
+ expMedian: big.NewInt(1),
+ },
+ {
+ name: "median 2",
+ gasPrices: []*big.Int{big.NewInt(1), big.NewInt(2)},
+ expMedian: big.NewInt(2),
+ },
+ {
+ name: "large values",
+ gasPrices: []*big.Int{val1e18(5), val1e18(4), val1e18(3), val1e18(2), val1e18(1)},
+ expMedian: val1e18(3),
+ },
+ {
+ name: "zeros",
+ gasPrices: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
+ expMedian: big.NewInt(0),
+ },
+ {
+ name: "unsorted even number of prices",
+ gasPrices: []*big.Int{big.NewInt(4), big.NewInt(2), big.NewInt(3), big.NewInt(1)},
+ expMedian: big.NewInt(3),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ g := ExecGasPriceEstimator{}
+
+ gasPrice, err := g.Median(tc.gasPrices)
+ assert.NoError(t, err)
+ assert.True(t, tc.expMedian.Cmp(gasPrice) == 0)
+ })
+ }
+}
+
+func TestExecPriceEstimator_Deviates(t *testing.T) {
+ testCases := []struct {
+ name string
+ gasPrice1 *big.Int
+ gasPrice2 *big.Int
+ deviationPPB int64
+ expDeviates bool
+ }{
+ {
+ name: "base",
+ gasPrice1: big.NewInt(100e8),
+ gasPrice2: big.NewInt(79e8),
+ deviationPPB: 2e8,
+ expDeviates: true,
+ },
+ {
+ name: "negative difference also deviates",
+ gasPrice1: big.NewInt(100e8),
+ gasPrice2: big.NewInt(121e8),
+ deviationPPB: 2e8,
+ expDeviates: true,
+ },
+ {
+ name: "larger difference deviates",
+ gasPrice1: big.NewInt(100e8),
+ gasPrice2: big.NewInt(70e8),
+ deviationPPB: 2e8,
+ expDeviates: true,
+ },
+ {
+ name: "smaller difference does not deviate",
+ gasPrice1: big.NewInt(100e8),
+ gasPrice2: big.NewInt(90e8),
+ deviationPPB: 2e8,
+ expDeviates: false,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ g := ExecGasPriceEstimator{
+ deviationPPB: tc.deviationPPB,
+ }
+
+ deviated, err := g.Deviates(tc.gasPrice1, tc.gasPrice2)
+ assert.NoError(t, err)
+ if tc.expDeviates {
+ assert.True(t, deviated)
+ } else {
+ assert.False(t, deviated)
+ }
+ })
+ }
+}
+
+func TestExecPriceEstimator_EstimateMsgCostUSD(t *testing.T) {
+ testCases := []struct {
+ name string
+ gasPrice *big.Int
+ wrappedNativePrice *big.Int
+ msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta
+ expUSD *big.Int
+ }{
+ {
+ name: "base",
+ gasPrice: big.NewInt(1e9), // 1 gwei
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ GasLimit: big.NewInt(100_000),
+ Data: []byte{},
+ TokenAmounts: []cciptypes.TokenAmount{},
+ },
+ },
+ expUSD: big.NewInt(300_000e9),
+ },
+ {
+ name: "base with data",
+ gasPrice: big.NewInt(1e9), // 1 gwei
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ GasLimit: big.NewInt(100_000),
+ Data: make([]byte, 1_000),
+ TokenAmounts: []cciptypes.TokenAmount{},
+ },
+ },
+ expUSD: big.NewInt(316_000e9),
+ },
+ {
+ name: "base with data and tokens",
+ gasPrice: big.NewInt(1e9), // 1 gwei
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ GasLimit: big.NewInt(100_000),
+ Data: make([]byte, 1_000),
+ TokenAmounts: make([]cciptypes.TokenAmount, 5),
+ },
+ },
+ expUSD: big.NewInt(366_000e9),
+ },
+ {
+ name: "empty msg",
+ gasPrice: big.NewInt(1e9), // 1 gwei
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ GasLimit: big.NewInt(0),
+ Data: []byte{},
+ TokenAmounts: []cciptypes.TokenAmount{},
+ },
+ },
+ expUSD: big.NewInt(200_000e9),
+ },
+ {
+ name: "double native price",
+ gasPrice: big.NewInt(1e9), // 1 gwei
+ wrappedNativePrice: big.NewInt(2e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ GasLimit: big.NewInt(0),
+ Data: []byte{},
+ TokenAmounts: []cciptypes.TokenAmount{},
+ },
+ },
+ expUSD: big.NewInt(400_000e9),
+ },
+ {
+ name: "zero gas price",
+ gasPrice: big.NewInt(0), // 1 gwei
+ wrappedNativePrice: big.NewInt(1e18), // $1
+ msg: cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ GasLimit: big.NewInt(0),
+ Data: []byte{},
+ TokenAmounts: []cciptypes.TokenAmount{},
+ },
+ },
+ expUSD: big.NewInt(0),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ g := ExecGasPriceEstimator{}
+
+ costUSD, err := g.EstimateMsgCostUSD(tc.gasPrice, tc.wrappedNativePrice, tc.msg)
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expUSD, costUSD)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator.go b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator.go
new file mode 100644
index 00000000000..49a6fbcc4ad
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator.go
@@ -0,0 +1,59 @@
+package prices
+
+import (
+ "math/big"
+
+ "github.com/Masterminds/semver/v3"
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+)
+
+const (
+ feeBoostingOverheadGas = 200_000
+ // execGasPerToken is lower-bound estimation of ERC20 releaseOrMint gas cost (Mint with static minter).
+ // Use this in per-token gas cost calc as heuristic to simplify estimation logic.
+ execGasPerToken = 10_000
+ // execGasPerPayloadByte is gas charged for passing each byte of `data` payload to CCIP receiver, ignores 4 gas per 0-byte rule.
+ // This can be a constant as it is part of EVM spec. Changes should be rare.
+ execGasPerPayloadByte = 16
+ // evmMessageFixedBytes is byte size of fixed-size fields in EVM2EVMMessage
+ // Updating EVM2EVMMessage involves an offchain upgrade, safe to keep this as constant in code.
+ evmMessageFixedBytes = 448
+ evmMessageBytesPerToken = 128 // Byte size of each token transfer, consisting of 1 EVMTokenAmount and 1 bytes, excl length of bytes
+ daMultiplierBase = int64(10000) // DA multiplier is in multiples of 0.0001, i.e. 1/daMultiplierBase
+ daGasPriceEncodingLength = 112 // Each gas price takes up at most GasPriceEncodingLength number of bits
+)
+
+// GasPriceEstimatorCommit provides gasPriceEstimatorCommon + features needed in commit plugin, e.g. price deviation check.
+type GasPriceEstimatorCommit interface {
+ cciptypes.GasPriceEstimatorCommit
+}
+
+// GasPriceEstimatorExec provides gasPriceEstimatorCommon + features needed in exec plugin, e.g. message cost estimation.
+type GasPriceEstimatorExec interface {
+ cciptypes.GasPriceEstimatorExec
+}
+
+// GasPriceEstimator provides complete gas price estimator functions.
+type GasPriceEstimator interface {
+ cciptypes.GasPriceEstimator
+}
+
+func NewGasPriceEstimatorForCommitPlugin(
+ commitStoreVersion semver.Version,
+ estimator gas.EvmFeeEstimator,
+ maxExecGasPrice *big.Int,
+ daDeviationPPB int64,
+ execDeviationPPB int64,
+) (GasPriceEstimatorCommit, error) {
+ switch commitStoreVersion.String() {
+ case "1.0.0", "1.1.0":
+ return NewExecGasPriceEstimator(estimator, maxExecGasPrice, execDeviationPPB), nil
+ case "1.2.0":
+ return NewDAGasPriceEstimator(estimator, maxExecGasPrice, execDeviationPPB, daDeviationPPB), nil
+ default:
+ return nil, errors.Errorf("Invalid commitStore version: %s", commitStoreVersion)
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_commit_mock.go b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_commit_mock.go
new file mode 100644
index 00000000000..0a366a66ac2
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_commit_mock.go
@@ -0,0 +1,269 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package prices
+
+import (
+ context "context"
+ big "math/big"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// MockGasPriceEstimatorCommit is an autogenerated mock type for the GasPriceEstimatorCommit type
+type MockGasPriceEstimatorCommit struct {
+ mock.Mock
+}
+
+type MockGasPriceEstimatorCommit_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockGasPriceEstimatorCommit) EXPECT() *MockGasPriceEstimatorCommit_Expecter {
+ return &MockGasPriceEstimatorCommit_Expecter{mock: &_m.Mock}
+}
+
+// DenoteInUSD provides a mock function with given fields: p, wrappedNativePrice
+func (_m *MockGasPriceEstimatorCommit) DenoteInUSD(p *big.Int, wrappedNativePrice *big.Int) (*big.Int, error) {
+ ret := _m.Called(p, wrappedNativePrice)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DenoteInUSD")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) (*big.Int, error)); ok {
+ return rf(p, wrappedNativePrice)
+ }
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) *big.Int); ok {
+ r0 = rf(p, wrappedNativePrice)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*big.Int, *big.Int) error); ok {
+ r1 = rf(p, wrappedNativePrice)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimatorCommit_DenoteInUSD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenoteInUSD'
+type MockGasPriceEstimatorCommit_DenoteInUSD_Call struct {
+ *mock.Call
+}
+
+// DenoteInUSD is a helper method to define mock.On call
+// - p *big.Int
+// - wrappedNativePrice *big.Int
+func (_e *MockGasPriceEstimatorCommit_Expecter) DenoteInUSD(p interface{}, wrappedNativePrice interface{}) *MockGasPriceEstimatorCommit_DenoteInUSD_Call {
+ return &MockGasPriceEstimatorCommit_DenoteInUSD_Call{Call: _e.mock.On("DenoteInUSD", p, wrappedNativePrice)}
+}
+
+func (_c *MockGasPriceEstimatorCommit_DenoteInUSD_Call) Run(run func(p *big.Int, wrappedNativePrice *big.Int)) *MockGasPriceEstimatorCommit_DenoteInUSD_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorCommit_DenoteInUSD_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimatorCommit_DenoteInUSD_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorCommit_DenoteInUSD_Call) RunAndReturn(run func(*big.Int, *big.Int) (*big.Int, error)) *MockGasPriceEstimatorCommit_DenoteInUSD_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Deviates provides a mock function with given fields: p1, p2
+func (_m *MockGasPriceEstimatorCommit) Deviates(p1 *big.Int, p2 *big.Int) (bool, error) {
+ ret := _m.Called(p1, p2)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Deviates")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) (bool, error)); ok {
+ return rf(p1, p2)
+ }
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) bool); ok {
+ r0 = rf(p1, p2)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*big.Int, *big.Int) error); ok {
+ r1 = rf(p1, p2)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimatorCommit_Deviates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Deviates'
+type MockGasPriceEstimatorCommit_Deviates_Call struct {
+ *mock.Call
+}
+
+// Deviates is a helper method to define mock.On call
+// - p1 *big.Int
+// - p2 *big.Int
+func (_e *MockGasPriceEstimatorCommit_Expecter) Deviates(p1 interface{}, p2 interface{}) *MockGasPriceEstimatorCommit_Deviates_Call {
+ return &MockGasPriceEstimatorCommit_Deviates_Call{Call: _e.mock.On("Deviates", p1, p2)}
+}
+
+func (_c *MockGasPriceEstimatorCommit_Deviates_Call) Run(run func(p1 *big.Int, p2 *big.Int)) *MockGasPriceEstimatorCommit_Deviates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorCommit_Deviates_Call) Return(_a0 bool, _a1 error) *MockGasPriceEstimatorCommit_Deviates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorCommit_Deviates_Call) RunAndReturn(run func(*big.Int, *big.Int) (bool, error)) *MockGasPriceEstimatorCommit_Deviates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetGasPrice provides a mock function with given fields: ctx
+func (_m *MockGasPriceEstimatorCommit) GetGasPrice(ctx context.Context) (*big.Int, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGasPrice")
+ }
+
+ 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
+}
+
+// MockGasPriceEstimatorCommit_GetGasPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGasPrice'
+type MockGasPriceEstimatorCommit_GetGasPrice_Call struct {
+ *mock.Call
+}
+
+// GetGasPrice is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *MockGasPriceEstimatorCommit_Expecter) GetGasPrice(ctx interface{}) *MockGasPriceEstimatorCommit_GetGasPrice_Call {
+ return &MockGasPriceEstimatorCommit_GetGasPrice_Call{Call: _e.mock.On("GetGasPrice", ctx)}
+}
+
+func (_c *MockGasPriceEstimatorCommit_GetGasPrice_Call) Run(run func(ctx context.Context)) *MockGasPriceEstimatorCommit_GetGasPrice_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorCommit_GetGasPrice_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimatorCommit_GetGasPrice_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorCommit_GetGasPrice_Call) RunAndReturn(run func(context.Context) (*big.Int, error)) *MockGasPriceEstimatorCommit_GetGasPrice_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Median provides a mock function with given fields: gasPrices
+func (_m *MockGasPriceEstimatorCommit) Median(gasPrices []*big.Int) (*big.Int, error) {
+ ret := _m.Called(gasPrices)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Median")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func([]*big.Int) (*big.Int, error)); ok {
+ return rf(gasPrices)
+ }
+ if rf, ok := ret.Get(0).(func([]*big.Int) *big.Int); ok {
+ r0 = rf(gasPrices)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func([]*big.Int) error); ok {
+ r1 = rf(gasPrices)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimatorCommit_Median_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Median'
+type MockGasPriceEstimatorCommit_Median_Call struct {
+ *mock.Call
+}
+
+// Median is a helper method to define mock.On call
+// - gasPrices []*big.Int
+func (_e *MockGasPriceEstimatorCommit_Expecter) Median(gasPrices interface{}) *MockGasPriceEstimatorCommit_Median_Call {
+ return &MockGasPriceEstimatorCommit_Median_Call{Call: _e.mock.On("Median", gasPrices)}
+}
+
+func (_c *MockGasPriceEstimatorCommit_Median_Call) Run(run func(gasPrices []*big.Int)) *MockGasPriceEstimatorCommit_Median_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorCommit_Median_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimatorCommit_Median_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorCommit_Median_Call) RunAndReturn(run func([]*big.Int) (*big.Int, error)) *MockGasPriceEstimatorCommit_Median_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockGasPriceEstimatorCommit creates a new instance of MockGasPriceEstimatorCommit. 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 NewMockGasPriceEstimatorCommit(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockGasPriceEstimatorCommit {
+ mock := &MockGasPriceEstimatorCommit{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_exec_mock.go b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_exec_mock.go
new file mode 100644
index 00000000000..8f778555b17
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_exec_mock.go
@@ -0,0 +1,274 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package prices
+
+import (
+ context "context"
+ big "math/big"
+
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// MockGasPriceEstimatorExec is an autogenerated mock type for the GasPriceEstimatorExec type
+type MockGasPriceEstimatorExec struct {
+ mock.Mock
+}
+
+type MockGasPriceEstimatorExec_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockGasPriceEstimatorExec) EXPECT() *MockGasPriceEstimatorExec_Expecter {
+ return &MockGasPriceEstimatorExec_Expecter{mock: &_m.Mock}
+}
+
+// DenoteInUSD provides a mock function with given fields: p, wrappedNativePrice
+func (_m *MockGasPriceEstimatorExec) DenoteInUSD(p *big.Int, wrappedNativePrice *big.Int) (*big.Int, error) {
+ ret := _m.Called(p, wrappedNativePrice)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DenoteInUSD")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) (*big.Int, error)); ok {
+ return rf(p, wrappedNativePrice)
+ }
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) *big.Int); ok {
+ r0 = rf(p, wrappedNativePrice)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*big.Int, *big.Int) error); ok {
+ r1 = rf(p, wrappedNativePrice)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimatorExec_DenoteInUSD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenoteInUSD'
+type MockGasPriceEstimatorExec_DenoteInUSD_Call struct {
+ *mock.Call
+}
+
+// DenoteInUSD is a helper method to define mock.On call
+// - p *big.Int
+// - wrappedNativePrice *big.Int
+func (_e *MockGasPriceEstimatorExec_Expecter) DenoteInUSD(p interface{}, wrappedNativePrice interface{}) *MockGasPriceEstimatorExec_DenoteInUSD_Call {
+ return &MockGasPriceEstimatorExec_DenoteInUSD_Call{Call: _e.mock.On("DenoteInUSD", p, wrappedNativePrice)}
+}
+
+func (_c *MockGasPriceEstimatorExec_DenoteInUSD_Call) Run(run func(p *big.Int, wrappedNativePrice *big.Int)) *MockGasPriceEstimatorExec_DenoteInUSD_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorExec_DenoteInUSD_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimatorExec_DenoteInUSD_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorExec_DenoteInUSD_Call) RunAndReturn(run func(*big.Int, *big.Int) (*big.Int, error)) *MockGasPriceEstimatorExec_DenoteInUSD_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// EstimateMsgCostUSD provides a mock function with given fields: p, wrappedNativePrice, msg
+func (_m *MockGasPriceEstimatorExec) EstimateMsgCostUSD(p *big.Int, wrappedNativePrice *big.Int, msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error) {
+ ret := _m.Called(p, wrappedNativePrice, msg)
+
+ if len(ret) == 0 {
+ panic("no return value specified for EstimateMsgCostUSD")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error)); ok {
+ return rf(p, wrappedNativePrice, msg)
+ }
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) *big.Int); ok {
+ r0 = rf(p, wrappedNativePrice, msg)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*big.Int, *big.Int, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) error); ok {
+ r1 = rf(p, wrappedNativePrice, msg)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EstimateMsgCostUSD'
+type MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call struct {
+ *mock.Call
+}
+
+// EstimateMsgCostUSD is a helper method to define mock.On call
+// - p *big.Int
+// - wrappedNativePrice *big.Int
+// - msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta
+func (_e *MockGasPriceEstimatorExec_Expecter) EstimateMsgCostUSD(p interface{}, wrappedNativePrice interface{}, msg interface{}) *MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call {
+ return &MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call{Call: _e.mock.On("EstimateMsgCostUSD", p, wrappedNativePrice, msg)}
+}
+
+func (_c *MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call) Run(run func(p *big.Int, wrappedNativePrice *big.Int, msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta)) *MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(*big.Int), args[2].(ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call) RunAndReturn(run func(*big.Int, *big.Int, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error)) *MockGasPriceEstimatorExec_EstimateMsgCostUSD_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetGasPrice provides a mock function with given fields: ctx
+func (_m *MockGasPriceEstimatorExec) GetGasPrice(ctx context.Context) (*big.Int, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGasPrice")
+ }
+
+ 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
+}
+
+// MockGasPriceEstimatorExec_GetGasPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGasPrice'
+type MockGasPriceEstimatorExec_GetGasPrice_Call struct {
+ *mock.Call
+}
+
+// GetGasPrice is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *MockGasPriceEstimatorExec_Expecter) GetGasPrice(ctx interface{}) *MockGasPriceEstimatorExec_GetGasPrice_Call {
+ return &MockGasPriceEstimatorExec_GetGasPrice_Call{Call: _e.mock.On("GetGasPrice", ctx)}
+}
+
+func (_c *MockGasPriceEstimatorExec_GetGasPrice_Call) Run(run func(ctx context.Context)) *MockGasPriceEstimatorExec_GetGasPrice_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorExec_GetGasPrice_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimatorExec_GetGasPrice_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorExec_GetGasPrice_Call) RunAndReturn(run func(context.Context) (*big.Int, error)) *MockGasPriceEstimatorExec_GetGasPrice_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Median provides a mock function with given fields: gasPrices
+func (_m *MockGasPriceEstimatorExec) Median(gasPrices []*big.Int) (*big.Int, error) {
+ ret := _m.Called(gasPrices)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Median")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func([]*big.Int) (*big.Int, error)); ok {
+ return rf(gasPrices)
+ }
+ if rf, ok := ret.Get(0).(func([]*big.Int) *big.Int); ok {
+ r0 = rf(gasPrices)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func([]*big.Int) error); ok {
+ r1 = rf(gasPrices)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimatorExec_Median_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Median'
+type MockGasPriceEstimatorExec_Median_Call struct {
+ *mock.Call
+}
+
+// Median is a helper method to define mock.On call
+// - gasPrices []*big.Int
+func (_e *MockGasPriceEstimatorExec_Expecter) Median(gasPrices interface{}) *MockGasPriceEstimatorExec_Median_Call {
+ return &MockGasPriceEstimatorExec_Median_Call{Call: _e.mock.On("Median", gasPrices)}
+}
+
+func (_c *MockGasPriceEstimatorExec_Median_Call) Run(run func(gasPrices []*big.Int)) *MockGasPriceEstimatorExec_Median_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorExec_Median_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimatorExec_Median_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimatorExec_Median_Call) RunAndReturn(run func([]*big.Int) (*big.Int, error)) *MockGasPriceEstimatorExec_Median_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockGasPriceEstimatorExec creates a new instance of MockGasPriceEstimatorExec. 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 NewMockGasPriceEstimatorExec(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockGasPriceEstimatorExec {
+ mock := &MockGasPriceEstimatorExec{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_mock.go b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_mock.go
new file mode 100644
index 00000000000..a513083319d
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/prices/gas_price_estimator_mock.go
@@ -0,0 +1,331 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package prices
+
+import (
+ context "context"
+ big "math/big"
+
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// MockGasPriceEstimator is an autogenerated mock type for the GasPriceEstimator type
+type MockGasPriceEstimator struct {
+ mock.Mock
+}
+
+type MockGasPriceEstimator_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockGasPriceEstimator) EXPECT() *MockGasPriceEstimator_Expecter {
+ return &MockGasPriceEstimator_Expecter{mock: &_m.Mock}
+}
+
+// DenoteInUSD provides a mock function with given fields: p, wrappedNativePrice
+func (_m *MockGasPriceEstimator) DenoteInUSD(p *big.Int, wrappedNativePrice *big.Int) (*big.Int, error) {
+ ret := _m.Called(p, wrappedNativePrice)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DenoteInUSD")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) (*big.Int, error)); ok {
+ return rf(p, wrappedNativePrice)
+ }
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) *big.Int); ok {
+ r0 = rf(p, wrappedNativePrice)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*big.Int, *big.Int) error); ok {
+ r1 = rf(p, wrappedNativePrice)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimator_DenoteInUSD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DenoteInUSD'
+type MockGasPriceEstimator_DenoteInUSD_Call struct {
+ *mock.Call
+}
+
+// DenoteInUSD is a helper method to define mock.On call
+// - p *big.Int
+// - wrappedNativePrice *big.Int
+func (_e *MockGasPriceEstimator_Expecter) DenoteInUSD(p interface{}, wrappedNativePrice interface{}) *MockGasPriceEstimator_DenoteInUSD_Call {
+ return &MockGasPriceEstimator_DenoteInUSD_Call{Call: _e.mock.On("DenoteInUSD", p, wrappedNativePrice)}
+}
+
+func (_c *MockGasPriceEstimator_DenoteInUSD_Call) Run(run func(p *big.Int, wrappedNativePrice *big.Int)) *MockGasPriceEstimator_DenoteInUSD_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_DenoteInUSD_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimator_DenoteInUSD_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_DenoteInUSD_Call) RunAndReturn(run func(*big.Int, *big.Int) (*big.Int, error)) *MockGasPriceEstimator_DenoteInUSD_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Deviates provides a mock function with given fields: p1, p2
+func (_m *MockGasPriceEstimator) Deviates(p1 *big.Int, p2 *big.Int) (bool, error) {
+ ret := _m.Called(p1, p2)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Deviates")
+ }
+
+ var r0 bool
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) (bool, error)); ok {
+ return rf(p1, p2)
+ }
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int) bool); ok {
+ r0 = rf(p1, p2)
+ } else {
+ r0 = ret.Get(0).(bool)
+ }
+
+ if rf, ok := ret.Get(1).(func(*big.Int, *big.Int) error); ok {
+ r1 = rf(p1, p2)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimator_Deviates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Deviates'
+type MockGasPriceEstimator_Deviates_Call struct {
+ *mock.Call
+}
+
+// Deviates is a helper method to define mock.On call
+// - p1 *big.Int
+// - p2 *big.Int
+func (_e *MockGasPriceEstimator_Expecter) Deviates(p1 interface{}, p2 interface{}) *MockGasPriceEstimator_Deviates_Call {
+ return &MockGasPriceEstimator_Deviates_Call{Call: _e.mock.On("Deviates", p1, p2)}
+}
+
+func (_c *MockGasPriceEstimator_Deviates_Call) Run(run func(p1 *big.Int, p2 *big.Int)) *MockGasPriceEstimator_Deviates_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(*big.Int))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_Deviates_Call) Return(_a0 bool, _a1 error) *MockGasPriceEstimator_Deviates_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_Deviates_Call) RunAndReturn(run func(*big.Int, *big.Int) (bool, error)) *MockGasPriceEstimator_Deviates_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// EstimateMsgCostUSD provides a mock function with given fields: p, wrappedNativePrice, msg
+func (_m *MockGasPriceEstimator) EstimateMsgCostUSD(p *big.Int, wrappedNativePrice *big.Int, msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error) {
+ ret := _m.Called(p, wrappedNativePrice, msg)
+
+ if len(ret) == 0 {
+ panic("no return value specified for EstimateMsgCostUSD")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error)); ok {
+ return rf(p, wrappedNativePrice, msg)
+ }
+ if rf, ok := ret.Get(0).(func(*big.Int, *big.Int, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) *big.Int); ok {
+ r0 = rf(p, wrappedNativePrice, msg)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(*big.Int, *big.Int, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) error); ok {
+ r1 = rf(p, wrappedNativePrice, msg)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimator_EstimateMsgCostUSD_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EstimateMsgCostUSD'
+type MockGasPriceEstimator_EstimateMsgCostUSD_Call struct {
+ *mock.Call
+}
+
+// EstimateMsgCostUSD is a helper method to define mock.On call
+// - p *big.Int
+// - wrappedNativePrice *big.Int
+// - msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta
+func (_e *MockGasPriceEstimator_Expecter) EstimateMsgCostUSD(p interface{}, wrappedNativePrice interface{}, msg interface{}) *MockGasPriceEstimator_EstimateMsgCostUSD_Call {
+ return &MockGasPriceEstimator_EstimateMsgCostUSD_Call{Call: _e.mock.On("EstimateMsgCostUSD", p, wrappedNativePrice, msg)}
+}
+
+func (_c *MockGasPriceEstimator_EstimateMsgCostUSD_Call) Run(run func(p *big.Int, wrappedNativePrice *big.Int, msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta)) *MockGasPriceEstimator_EstimateMsgCostUSD_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(*big.Int), args[1].(*big.Int), args[2].(ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_EstimateMsgCostUSD_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimator_EstimateMsgCostUSD_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_EstimateMsgCostUSD_Call) RunAndReturn(run func(*big.Int, *big.Int, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta) (*big.Int, error)) *MockGasPriceEstimator_EstimateMsgCostUSD_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// GetGasPrice provides a mock function with given fields: ctx
+func (_m *MockGasPriceEstimator) GetGasPrice(ctx context.Context) (*big.Int, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GetGasPrice")
+ }
+
+ 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
+}
+
+// MockGasPriceEstimator_GetGasPrice_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetGasPrice'
+type MockGasPriceEstimator_GetGasPrice_Call struct {
+ *mock.Call
+}
+
+// GetGasPrice is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *MockGasPriceEstimator_Expecter) GetGasPrice(ctx interface{}) *MockGasPriceEstimator_GetGasPrice_Call {
+ return &MockGasPriceEstimator_GetGasPrice_Call{Call: _e.mock.On("GetGasPrice", ctx)}
+}
+
+func (_c *MockGasPriceEstimator_GetGasPrice_Call) Run(run func(ctx context.Context)) *MockGasPriceEstimator_GetGasPrice_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_GetGasPrice_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimator_GetGasPrice_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_GetGasPrice_Call) RunAndReturn(run func(context.Context) (*big.Int, error)) *MockGasPriceEstimator_GetGasPrice_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// Median provides a mock function with given fields: gasPrices
+func (_m *MockGasPriceEstimator) Median(gasPrices []*big.Int) (*big.Int, error) {
+ ret := _m.Called(gasPrices)
+
+ if len(ret) == 0 {
+ panic("no return value specified for Median")
+ }
+
+ var r0 *big.Int
+ var r1 error
+ if rf, ok := ret.Get(0).(func([]*big.Int) (*big.Int, error)); ok {
+ return rf(gasPrices)
+ }
+ if rf, ok := ret.Get(0).(func([]*big.Int) *big.Int); ok {
+ r0 = rf(gasPrices)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*big.Int)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func([]*big.Int) error); ok {
+ r1 = rf(gasPrices)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockGasPriceEstimator_Median_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Median'
+type MockGasPriceEstimator_Median_Call struct {
+ *mock.Call
+}
+
+// Median is a helper method to define mock.On call
+// - gasPrices []*big.Int
+func (_e *MockGasPriceEstimator_Expecter) Median(gasPrices interface{}) *MockGasPriceEstimator_Median_Call {
+ return &MockGasPriceEstimator_Median_Call{Call: _e.mock.On("Median", gasPrices)}
+}
+
+func (_c *MockGasPriceEstimator_Median_Call) Run(run func(gasPrices []*big.Int)) *MockGasPriceEstimator_Median_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].([]*big.Int))
+ })
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_Median_Call) Return(_a0 *big.Int, _a1 error) *MockGasPriceEstimator_Median_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *MockGasPriceEstimator_Median_Call) RunAndReturn(run func([]*big.Int) (*big.Int, error)) *MockGasPriceEstimator_Median_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockGasPriceEstimator creates a new instance of MockGasPriceEstimator. 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 NewMockGasPriceEstimator(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockGasPriceEstimator {
+ mock := &MockGasPriceEstimator{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/proxycommitstore.go b/core/services/ocr2/plugins/ccip/proxycommitstore.go
new file mode 100644
index 00000000000..b06f957bd58
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/proxycommitstore.go
@@ -0,0 +1,135 @@
+package ccip
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "math/big"
+ "time"
+
+ "go.uber.org/multierr"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+// The disjunct methods in IncompleteSourceCommitStoreReader and IncompleteDestCommitStoreReader satisfy the full
+// CommitStoreReader iface in Union
+var _ cciptypes.CommitStoreReader = (*ProviderProxyCommitStoreReader)(nil)
+
+// ProviderProxyCommitStoreReader is a CommitStoreReader that proxies to two custom provider grpc backed implementations
+// of a CommitStoreReader.
+// [ProviderProxyCommitStoreReader] lives in the memory space of the reporting plugin factory and reporting plugin, and should have no chain-specific details.
+// Why? Historical implementations of a commit store consumed in reporting plugins mixed usage of a gas estimator from
+// the source relayer and contract read and write abilities to a dest relayer. This is not valid in LOOP world.
+type ProviderProxyCommitStoreReader struct {
+ srcCommitStoreReader IncompleteSourceCommitStoreReader
+ dstCommitStoreReader IncompleteDestCommitStoreReader
+}
+
+// IncompleteSourceCommitStoreReader contains only the methods of CommitStoreReader that are serviced by the source chain/relayer.
+type IncompleteSourceCommitStoreReader interface {
+ ChangeConfig(ctx context.Context, onchainConfig []byte, offchainConfig []byte) (cciptypes.Address, error)
+ GasPriceEstimator(ctx context.Context) (cciptypes.GasPriceEstimatorCommit, error)
+ OffchainConfig(ctx context.Context) (cciptypes.CommitOffchainConfig, error)
+ io.Closer
+}
+
+// IncompleteDestCommitStoreReader contains only the methods of CommitStoreReader that are serviced by the dest chain/relayer.
+type IncompleteDestCommitStoreReader interface {
+ DecodeCommitReport(ctx context.Context, report []byte) (cciptypes.CommitStoreReport, error)
+ EncodeCommitReport(ctx context.Context, report cciptypes.CommitStoreReport) ([]byte, error)
+ GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confirmations int) ([]cciptypes.CommitStoreReportWithTxMeta, error)
+ GetCommitReportMatchingSeqNum(ctx context.Context, seqNum uint64, confirmations int) ([]cciptypes.CommitStoreReportWithTxMeta, error)
+ GetCommitStoreStaticConfig(ctx context.Context) (cciptypes.CommitStoreStaticConfig, error)
+ GetExpectedNextSequenceNumber(ctx context.Context) (uint64, error)
+ GetLatestPriceEpochAndRound(ctx context.Context) (uint64, error)
+ IsBlessed(ctx context.Context, root [32]byte) (bool, error)
+ IsDestChainHealthy(ctx context.Context) (bool, error)
+ IsDown(ctx context.Context) (bool, error)
+ VerifyExecutionReport(ctx context.Context, report cciptypes.ExecReport) (bool, error)
+ io.Closer
+}
+
+func NewProviderProxyCommitStoreReader(srcReader cciptypes.CommitStoreReader, dstReader cciptypes.CommitStoreReader) *ProviderProxyCommitStoreReader {
+ return &ProviderProxyCommitStoreReader{
+ srcCommitStoreReader: srcReader,
+ dstCommitStoreReader: dstReader,
+ }
+}
+
+// ChangeConfig updates the offchainConfig values for the source relayer gas estimator by calling ChangeConfig
+// on the source relayer. Once this is called, GasPriceEstimator and OffchainConfig can be called.
+func (p *ProviderProxyCommitStoreReader) ChangeConfig(ctx context.Context, onchainConfig []byte, offchainConfig []byte) (cciptypes.Address, error) {
+ return p.srcCommitStoreReader.ChangeConfig(ctx, onchainConfig, offchainConfig)
+}
+
+func (p *ProviderProxyCommitStoreReader) DecodeCommitReport(ctx context.Context, report []byte) (cciptypes.CommitStoreReport, error) {
+ return p.dstCommitStoreReader.DecodeCommitReport(ctx, report)
+}
+
+func (p *ProviderProxyCommitStoreReader) EncodeCommitReport(ctx context.Context, report cciptypes.CommitStoreReport) ([]byte, error) {
+ return p.dstCommitStoreReader.EncodeCommitReport(ctx, report)
+}
+
+// GasPriceEstimator constructs a gas price estimator on the source relayer
+func (p *ProviderProxyCommitStoreReader) GasPriceEstimator(ctx context.Context) (cciptypes.GasPriceEstimatorCommit, error) {
+ return p.srcCommitStoreReader.GasPriceEstimator(ctx)
+}
+
+func (p *ProviderProxyCommitStoreReader) GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confirmations int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return p.dstCommitStoreReader.GetAcceptedCommitReportsGteTimestamp(ctx, ts, confirmations)
+}
+
+func (p *ProviderProxyCommitStoreReader) GetCommitReportMatchingSeqNum(ctx context.Context, seqNum uint64, confirmations int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return p.dstCommitStoreReader.GetCommitReportMatchingSeqNum(ctx, seqNum, confirmations)
+}
+
+func (p *ProviderProxyCommitStoreReader) GetCommitStoreStaticConfig(ctx context.Context) (cciptypes.CommitStoreStaticConfig, error) {
+ return p.dstCommitStoreReader.GetCommitStoreStaticConfig(ctx)
+}
+
+func (p *ProviderProxyCommitStoreReader) GetExpectedNextSequenceNumber(ctx context.Context) (uint64, error) {
+ return p.dstCommitStoreReader.GetExpectedNextSequenceNumber(ctx)
+}
+
+func (p *ProviderProxyCommitStoreReader) GetLatestPriceEpochAndRound(ctx context.Context) (uint64, error) {
+ return p.dstCommitStoreReader.GetLatestPriceEpochAndRound(ctx)
+}
+
+func (p *ProviderProxyCommitStoreReader) IsBlessed(ctx context.Context, root [32]byte) (bool, error) {
+ return p.dstCommitStoreReader.IsBlessed(ctx, root)
+}
+
+func (p *ProviderProxyCommitStoreReader) IsDestChainHealthy(ctx context.Context) (bool, error) {
+ return p.dstCommitStoreReader.IsDestChainHealthy(ctx)
+}
+
+func (p *ProviderProxyCommitStoreReader) IsDown(ctx context.Context) (bool, error) {
+ return p.dstCommitStoreReader.IsDown(ctx)
+}
+
+func (p *ProviderProxyCommitStoreReader) OffchainConfig(ctx context.Context) (cciptypes.CommitOffchainConfig, error) {
+ return p.srcCommitStoreReader.OffchainConfig(ctx)
+}
+
+func (p *ProviderProxyCommitStoreReader) VerifyExecutionReport(ctx context.Context, report cciptypes.ExecReport) (bool, error) {
+ return p.dstCommitStoreReader.VerifyExecutionReport(ctx, report)
+}
+
+// SetGasEstimator is invalid on ProviderProxyCommitStoreReader. The provider based impl's do not have SetGasEstimator
+// defined, so this serves no purpose other than satisfying an interface.
+func (p *ProviderProxyCommitStoreReader) SetGasEstimator(ctx context.Context, gpe gas.EvmFeeEstimator) error {
+ return fmt.Errorf("invalid usage of ProviderProxyCommitStoreReader")
+}
+
+// SetSourceMaxGasPrice is invalid on ProviderProxyCommitStoreReader. The provider based impl's do not have SetSourceMaxGasPrice
+// defined, so this serves no purpose other than satisfying an interface.
+func (p *ProviderProxyCommitStoreReader) SetSourceMaxGasPrice(ctx context.Context, sourceMaxGasPrice *big.Int) error {
+ return fmt.Errorf("invalid usage of ProviderProxyCommitStoreReader")
+}
+
+func (p *ProviderProxyCommitStoreReader) Close() error {
+ return multierr.Append(p.srcCommitStoreReader.Close(), p.dstCommitStoreReader.Close())
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/ccip_contracts.go b/core/services/ocr2/plugins/ccip/testhelpers/ccip_contracts.go
new file mode 100644
index 00000000000..805c49d91aa
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/ccip_contracts.go
@@ -0,0 +1,1580 @@
+package testhelpers
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog/log"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2/confighelper"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2/types"
+ ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/merklemulti"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_proxy_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_helper"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_helper_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0"
+)
+
+var (
+ // Source
+ SourcePool = "source Link pool"
+ SourcePriceRegistry = "source PriceRegistry"
+ OnRamp = "onramp"
+ OnRampNative = "onramp-native"
+ SourceRouter = "source router"
+
+ // Dest
+ OffRamp = "offramp"
+ DestPool = "dest Link pool"
+
+ Receiver = "receiver"
+ Sender = "sender"
+ Link = func(amount int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(amount)) }
+ HundredLink = Link(100)
+ LinkUSDValue = func(amount int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(amount)) }
+ SourceChainID = uint64(1000)
+ SourceChainSelector = uint64(11787463284727550157)
+ DestChainID = uint64(1337)
+ DestChainSelector = uint64(3379446385462418246)
+)
+
+// Backwards compat, in principle these statuses are version dependent
+// TODO: Adjust integration tests to be version agnostic using readers
+var (
+ ExecutionStateSuccess = MessageExecutionState(cciptypes.ExecutionStateSuccess)
+ ExecutionStateFailure = MessageExecutionState(cciptypes.ExecutionStateFailure)
+)
+
+type MessageExecutionState cciptypes.MessageExecutionState
+type CommitOffchainConfig struct {
+ v1_2_0.JSONCommitOffchainConfig
+}
+
+func (c CommitOffchainConfig) Encode() ([]byte, error) {
+ return ccipconfig.EncodeOffchainConfig(c.JSONCommitOffchainConfig)
+}
+
+func NewCommitOffchainConfig(
+ GasPriceHeartBeat config.Duration,
+ DAGasPriceDeviationPPB uint32,
+ ExecGasPriceDeviationPPB uint32,
+ TokenPriceHeartBeat config.Duration,
+ TokenPriceDeviationPPB uint32,
+ InflightCacheExpiry config.Duration) CommitOffchainConfig {
+ return CommitOffchainConfig{v1_2_0.JSONCommitOffchainConfig{
+ GasPriceHeartBeat: GasPriceHeartBeat,
+ DAGasPriceDeviationPPB: DAGasPriceDeviationPPB,
+ ExecGasPriceDeviationPPB: ExecGasPriceDeviationPPB,
+ TokenPriceHeartBeat: TokenPriceHeartBeat,
+ TokenPriceDeviationPPB: TokenPriceDeviationPPB,
+ InflightCacheExpiry: InflightCacheExpiry,
+ }}
+}
+
+type CommitOnchainConfig struct {
+ ccipdata.CommitOnchainConfig
+}
+
+func NewCommitOnchainConfig(
+ PriceRegistry common.Address,
+) CommitOnchainConfig {
+ return CommitOnchainConfig{ccipdata.CommitOnchainConfig{
+ PriceRegistry: PriceRegistry,
+ }}
+}
+
+type ExecOnchainConfig struct {
+ v1_5_0.ExecOnchainConfig
+}
+
+func NewExecOnchainConfig(
+ PermissionLessExecutionThresholdSeconds uint32,
+ Router common.Address,
+ PriceRegistry common.Address,
+ MaxNumberOfTokensPerMsg uint16,
+ MaxDataBytes uint32,
+ MaxPoolReleaseOrMintGas uint32,
+ MaxTokenTransferGas uint32,
+) ExecOnchainConfig {
+ return ExecOnchainConfig{v1_5_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: PermissionLessExecutionThresholdSeconds,
+ Router: Router,
+ PriceRegistry: PriceRegistry,
+ MaxNumberOfTokensPerMsg: MaxNumberOfTokensPerMsg,
+ MaxDataBytes: MaxDataBytes,
+ MaxPoolReleaseOrMintGas: MaxPoolReleaseOrMintGas,
+ MaxTokenTransferGas: MaxTokenTransferGas,
+ }}
+}
+
+type ExecOffchainConfig struct {
+ v1_2_0.JSONExecOffchainConfig
+}
+
+func (c ExecOffchainConfig) Encode() ([]byte, error) {
+ return ccipconfig.EncodeOffchainConfig(c.JSONExecOffchainConfig)
+}
+
+func NewExecOffchainConfig(
+ DestOptimisticConfirmations uint32,
+ BatchGasLimit uint32,
+ RelativeBoostPerWaitHour float64,
+ InflightCacheExpiry config.Duration,
+ RootSnoozeTime config.Duration,
+) ExecOffchainConfig {
+ return ExecOffchainConfig{v1_2_0.JSONExecOffchainConfig{
+ DestOptimisticConfirmations: DestOptimisticConfirmations,
+ BatchGasLimit: BatchGasLimit,
+ RelativeBoostPerWaitHour: RelativeBoostPerWaitHour,
+ InflightCacheExpiry: InflightCacheExpiry,
+ RootSnoozeTime: RootSnoozeTime,
+ }}
+}
+
+type MaybeRevertReceiver struct {
+ Receiver *maybe_revert_message_receiver.MaybeRevertMessageReceiver
+ Strict bool
+}
+
+type Common struct {
+ ChainID uint64
+ ChainSelector uint64
+ User *bind.TransactOpts
+ Chain *backends.SimulatedBackend
+ LinkToken *link_token_interface.LinkToken
+ LinkTokenPool *lock_release_token_pool.LockReleaseTokenPool
+ CustomToken *link_token_interface.LinkToken
+ WrappedNative *weth9.WETH9
+ WrappedNativePool *lock_release_token_pool.LockReleaseTokenPool
+ ARM *mock_arm_contract.MockARMContract
+ ARMProxy *arm_proxy_contract.ARMProxyContract
+ PriceRegistry *price_registry_1_2_0.PriceRegistry
+ TokenAdminRegistry *token_admin_registry.TokenAdminRegistry
+}
+
+type SourceChain struct {
+ Common
+ Router *router.Router
+ OnRamp *evm_2_evm_onramp.EVM2EVMOnRamp
+}
+
+type DestinationChain struct {
+ Common
+
+ CommitStoreHelper *commit_store_helper.CommitStoreHelper
+ CommitStore *commit_store.CommitStore
+ Router *router.Router
+ OffRamp *evm_2_evm_offramp.EVM2EVMOffRamp
+ Receivers []MaybeRevertReceiver
+}
+
+type OCR2Config struct {
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+}
+
+type BalanceAssertion struct {
+ Name string
+ Address common.Address
+ Expected string
+ Getter func(t *testing.T, addr common.Address) *big.Int
+ Within string
+}
+
+type BalanceReq struct {
+ Name string
+ Addr common.Address
+ Getter func(t *testing.T, addr common.Address) *big.Int
+}
+
+type CCIPContracts struct {
+ Source SourceChain
+ Dest DestinationChain
+ Oracles []confighelper.OracleIdentityExtra
+
+ commitOCRConfig, execOCRConfig *OCR2Config
+}
+
+func (c *CCIPContracts) DeployNewOffRamp(t *testing.T) {
+ prevOffRamp := common.HexToAddress("")
+ if c.Dest.OffRamp != nil {
+ prevOffRamp = c.Dest.OffRamp.Address()
+ }
+ offRampAddress, _, _, err := evm_2_evm_offramp.DeployEVM2EVMOffRamp(
+ c.Dest.User,
+ c.Dest.Chain,
+ evm_2_evm_offramp.EVM2EVMOffRampStaticConfig{
+ CommitStore: c.Dest.CommitStore.Address(),
+ ChainSelector: c.Dest.ChainSelector,
+ SourceChainSelector: c.Source.ChainSelector,
+ OnRamp: c.Source.OnRamp.Address(),
+ PrevOffRamp: prevOffRamp,
+ RmnProxy: c.Dest.ARMProxy.Address(), // RMN formerly ARM
+ TokenAdminRegistry: c.Dest.TokenAdminRegistry.Address(),
+ },
+ evm_2_evm_offramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: LinkUSDValue(100),
+ Rate: LinkUSDValue(1),
+ },
+ )
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+
+ c.Dest.OffRamp, err = evm_2_evm_offramp.NewEVM2EVMOffRamp(offRampAddress, c.Dest.Chain)
+ require.NoError(t, err)
+
+ c.Dest.Chain.Commit()
+ c.Source.Chain.Commit()
+}
+
+func (c *CCIPContracts) EnableOffRamp(t *testing.T) {
+ _, err := c.Dest.Router.ApplyRampUpdates(c.Dest.User, nil, nil, []router.RouterOffRamp{{SourceChainSelector: SourceChainSelector, OffRamp: c.Dest.OffRamp.Address()}})
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+
+ onChainConfig := c.CreateDefaultExecOnchainConfig(t)
+ offChainConfig := c.CreateDefaultExecOffchainConfig(t)
+
+ c.SetupExecOCR2Config(t, onChainConfig, offChainConfig)
+}
+
+func (c *CCIPContracts) EnableCommitStore(t *testing.T) {
+ onChainConfig := c.CreateDefaultCommitOnchainConfig(t)
+ offChainConfig := c.CreateDefaultCommitOffchainConfig(t)
+
+ c.SetupCommitOCR2Config(t, onChainConfig, offChainConfig)
+
+ _, err := c.Dest.PriceRegistry.ApplyPriceUpdatersUpdates(c.Dest.User, []common.Address{c.Dest.CommitStore.Address()}, []common.Address{})
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) DeployNewOnRamp(t *testing.T) {
+ t.Log("Deploying new onRamp")
+ // find the last onRamp
+ prevOnRamp := common.HexToAddress("")
+ if c.Source.OnRamp != nil {
+ prevOnRamp = c.Source.OnRamp.Address()
+ }
+ onRampAddress, _, _, err := evm_2_evm_onramp.DeployEVM2EVMOnRamp(
+ c.Source.User, // user
+ c.Source.Chain, // client
+ evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{
+ LinkToken: c.Source.LinkToken.Address(),
+ ChainSelector: c.Source.ChainSelector,
+ DestChainSelector: c.Dest.ChainSelector,
+ DefaultTxGasLimit: 200_000,
+ MaxNopFeesJuels: big.NewInt(0).Mul(big.NewInt(100_000_000), big.NewInt(1e18)),
+ PrevOnRamp: prevOnRamp,
+ RmnProxy: c.Source.ARM.Address(), // RMN, formerly ARM
+ TokenAdminRegistry: c.Source.TokenAdminRegistry.Address(),
+ },
+ evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig{
+ Router: c.Source.Router.Address(),
+ MaxNumberOfTokensPerMsg: 5,
+ DestGasOverhead: 350_000,
+ DestGasPerPayloadByte: 16,
+ DestDataAvailabilityOverheadGas: 33_596,
+ DestGasPerDataAvailabilityByte: 16,
+ DestDataAvailabilityMultiplierBps: 6840, // 0.684
+ PriceRegistry: c.Source.PriceRegistry.Address(),
+ MaxDataBytes: 1e5,
+ MaxPerMsgGasLimit: 4_000_000,
+ DefaultTokenFeeUSDCents: 50,
+ DefaultTokenDestGasOverhead: 34_000,
+ DefaultTokenDestBytesOverhead: 500,
+ },
+ evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: LinkUSDValue(100),
+ Rate: LinkUSDValue(1),
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: c.Source.LinkToken.Address(),
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: 1e18,
+ PremiumMultiplierWeiPerEth: 9e17,
+ Enabled: true,
+ },
+ {
+ Token: c.Source.WrappedNative.Address(),
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: 1e18,
+ PremiumMultiplierWeiPerEth: 1e18,
+ Enabled: true,
+ },
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: c.Source.LinkToken.Address(),
+ MinFeeUSDCents: 50, // $0.5
+ MaxFeeUSDCents: 1_000_000_00, // $ 1 million
+ DeciBps: 5_0, // 5 bps
+ DestGasOverhead: 34_000,
+ DestBytesOverhead: 32,
+ AggregateRateLimitEnabled: true,
+ },
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{},
+ )
+
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ c.Source.OnRamp, err = evm_2_evm_onramp.NewEVM2EVMOnRamp(onRampAddress, c.Source.Chain)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) EnableOnRamp(t *testing.T) {
+ t.Log("Setting onRamp on source router")
+ _, err := c.Source.Router.ApplyRampUpdates(c.Source.User, []router.RouterOnRamp{{DestChainSelector: c.Dest.ChainSelector, OnRamp: c.Source.OnRamp.Address()}}, nil, nil)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) DeployNewCommitStore(t *testing.T) {
+ commitStoreAddress, _, _, err := commit_store_helper_1_2_0.DeployCommitStoreHelper(
+ c.Dest.User, // user
+ c.Dest.Chain, // client
+ commit_store_helper_1_2_0.CommitStoreStaticConfig{
+ ChainSelector: c.Dest.ChainSelector,
+ SourceChainSelector: c.Source.ChainSelector,
+ OnRamp: c.Source.OnRamp.Address(),
+ ArmProxy: c.Dest.ARMProxy.Address(),
+ },
+ )
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+ c.Dest.CommitStoreHelper, err = commit_store_helper.NewCommitStoreHelper(commitStoreAddress, c.Dest.Chain)
+ require.NoError(t, err)
+ // since CommitStoreHelper derives from CommitStore, it's safe to instantiate both on same address
+ c.Dest.CommitStore, err = commit_store.NewCommitStore(commitStoreAddress, c.Dest.Chain)
+ require.NoError(t, err)
+}
+
+func (c *CCIPContracts) DeployNewPriceRegistry(t *testing.T) {
+ t.Log("Deploying new Price Registry")
+ destPricesAddress, _, _, err := price_registry_1_2_0.DeployPriceRegistry(
+ c.Dest.User,
+ c.Dest.Chain,
+ []common.Address{c.Dest.CommitStore.Address()},
+ []common.Address{c.Dest.LinkToken.Address()},
+ 60*60*24*14, // two weeks
+ )
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ c.Dest.PriceRegistry, err = price_registry_1_2_0.NewPriceRegistry(destPricesAddress, c.Dest.Chain)
+ require.NoError(t, err)
+
+ priceUpdates := price_registry_1_2_0.InternalPriceUpdates{
+ TokenPriceUpdates: []price_registry_1_2_0.InternalTokenPriceUpdate{
+ {
+ SourceToken: c.Dest.LinkToken.Address(),
+ UsdPerToken: big.NewInt(8e18), // 8usd
+ },
+ {
+ SourceToken: c.Dest.WrappedNative.Address(),
+ UsdPerToken: big.NewInt(1e18), // 1usd
+ },
+ },
+ GasPriceUpdates: []price_registry_1_2_0.InternalGasPriceUpdate{
+ {
+ DestChainSelector: c.Source.ChainSelector,
+ UsdPerUnitGas: big.NewInt(2000e9), // $2000 per eth * 1gwei = 2000e9
+ },
+ },
+ }
+ _, err = c.Dest.PriceRegistry.UpdatePrices(c.Dest.User, priceUpdates)
+ require.NoError(t, err)
+
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+
+ t.Logf("New Price Registry deployed at %s", destPricesAddress.String())
+}
+
+func (c *CCIPContracts) SetNopsOnRamp(t *testing.T, nopsAndWeights []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) {
+ tx, err := c.Source.OnRamp.SetNops(c.Source.User, nopsAndWeights)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ _, err = bind.WaitMined(context.Background(), c.Source.Chain, tx)
+ require.NoError(t, err)
+}
+
+func (c *CCIPContracts) GetSourceLinkBalance(t *testing.T, addr common.Address) *big.Int {
+ return GetBalance(t, c.Source.Chain, c.Source.LinkToken.Address(), addr)
+}
+
+func (c *CCIPContracts) GetDestLinkBalance(t *testing.T, addr common.Address) *big.Int {
+ return GetBalance(t, c.Dest.Chain, c.Dest.LinkToken.Address(), addr)
+}
+
+func (c *CCIPContracts) GetSourceWrappedTokenBalance(t *testing.T, addr common.Address) *big.Int {
+ return GetBalance(t, c.Source.Chain, c.Source.WrappedNative.Address(), addr)
+}
+
+func (c *CCIPContracts) GetDestWrappedTokenBalance(t *testing.T, addr common.Address) *big.Int {
+ return GetBalance(t, c.Dest.Chain, c.Dest.WrappedNative.Address(), addr)
+}
+
+func (c *CCIPContracts) AssertBalances(t *testing.T, bas []BalanceAssertion) {
+ for _, b := range bas {
+ actual := b.Getter(t, b.Address)
+ t.Log("Checking balance for", b.Name, "at", b.Address.Hex(), "got", actual)
+ require.NotNil(t, actual, "%v getter return nil", b.Name)
+ if b.Within == "" {
+ require.Equal(t, b.Expected, actual.String(), "wrong balance for %s got %s want %s", b.Name, actual, b.Expected)
+ } else {
+ bi, _ := big.NewInt(0).SetString(b.Expected, 10)
+ withinI, _ := big.NewInt(0).SetString(b.Within, 10)
+ high := big.NewInt(0).Add(bi, withinI)
+ low := big.NewInt(0).Sub(bi, withinI)
+ require.Equal(t, -1, actual.Cmp(high), "wrong balance for %s got %s outside expected range [%s, %s]", b.Name, actual, low, high)
+ require.Equal(t, 1, actual.Cmp(low), "wrong balance for %s got %s outside expected range [%s, %s]", b.Name, actual, low, high)
+ }
+ }
+}
+
+func AccountToAddress(accounts []ocr2types.Account) (addresses []common.Address, err error) {
+ for _, signer := range accounts {
+ bytes, err := hexutil.Decode(string(signer))
+ if err != nil {
+ return []common.Address{}, errors.Wrap(err, fmt.Sprintf("given address is not valid %s", signer))
+ }
+ if len(bytes) != 20 {
+ return []common.Address{}, errors.Errorf("address is not 20 bytes %s", signer)
+ }
+ addresses = append(addresses, common.BytesToAddress(bytes))
+ }
+ return addresses, nil
+}
+
+func OnchainPublicKeyToAddress(publicKeys []ocrtypes.OnchainPublicKey) (addresses []common.Address, err error) {
+ for _, signer := range publicKeys {
+ if len(signer) != 20 {
+ return []common.Address{}, errors.Errorf("address is not 20 bytes %s", signer)
+ }
+ addresses = append(addresses, common.BytesToAddress(signer))
+ }
+ return addresses, nil
+}
+
+func (c *CCIPContracts) DeriveOCR2Config(t *testing.T, oracles []confighelper.OracleIdentityExtra, rawOnchainConfig []byte, rawOffchainConfig []byte) *OCR2Config {
+ signers, transmitters, threshold, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests(
+ 2*time.Second, // deltaProgress
+ 1*time.Second, // deltaResend
+ 1*time.Second, // deltaRound
+ 500*time.Millisecond, // deltaGrace
+ 2*time.Second, // deltaStage
+ 3,
+ []int{1, 1, 1, 1},
+ oracles,
+ rawOffchainConfig,
+ 50*time.Millisecond, // Max duration query
+ 1*time.Second, // Max duration observation
+ 100*time.Millisecond,
+ 100*time.Millisecond,
+ 100*time.Millisecond,
+ 1, // faults
+ rawOnchainConfig,
+ )
+ require.NoError(t, err)
+ lggr := logger.TestLogger(t)
+ lggr.Infow("Setting Config on Oracle Contract",
+ "signers", signers,
+ "transmitters", transmitters,
+ "threshold", threshold,
+ "onchainConfig", onchainConfig,
+ "encodedConfigVersion", offchainConfigVersion,
+ )
+ signerAddresses, err := OnchainPublicKeyToAddress(signers)
+ require.NoError(t, err)
+ transmitterAddresses, err := AccountToAddress(transmitters)
+ require.NoError(t, err)
+
+ return &OCR2Config{
+ Signers: signerAddresses,
+ Transmitters: transmitterAddresses,
+ F: threshold,
+ OnchainConfig: onchainConfig,
+ OffchainConfigVersion: offchainConfigVersion,
+ OffchainConfig: offchainConfig,
+ }
+}
+
+func (c *CCIPContracts) SetupCommitOCR2Config(t *testing.T, commitOnchainConfig, commitOffchainConfig []byte) {
+ c.commitOCRConfig = c.DeriveOCR2Config(t, c.Oracles, commitOnchainConfig, commitOffchainConfig)
+ // Set the DON on the commit store
+ _, err := c.Dest.CommitStore.SetOCR2Config(
+ c.Dest.User,
+ c.commitOCRConfig.Signers,
+ c.commitOCRConfig.Transmitters,
+ c.commitOCRConfig.F,
+ c.commitOCRConfig.OnchainConfig,
+ c.commitOCRConfig.OffchainConfigVersion,
+ c.commitOCRConfig.OffchainConfig,
+ )
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) SetupExecOCR2Config(t *testing.T, execOnchainConfig, execOffchainConfig []byte) {
+ c.execOCRConfig = c.DeriveOCR2Config(t, c.Oracles, execOnchainConfig, execOffchainConfig)
+ // Same DON on the offramp
+ _, err := c.Dest.OffRamp.SetOCR2Config(
+ c.Dest.User,
+ c.execOCRConfig.Signers,
+ c.execOCRConfig.Transmitters,
+ c.execOCRConfig.F,
+ c.execOCRConfig.OnchainConfig,
+ c.execOCRConfig.OffchainConfigVersion,
+ c.execOCRConfig.OffchainConfig,
+ )
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) SetupOnchainConfig(t *testing.T, commitOnchainConfig, commitOffchainConfig, execOnchainConfig, execOffchainConfig []byte) int64 {
+ // Note We do NOT set the payees, payment is done in the OCR2Base implementation
+ blockBeforeConfig, err := c.Dest.Chain.BlockByNumber(context.Background(), nil)
+ require.NoError(t, err)
+
+ c.SetupCommitOCR2Config(t, commitOnchainConfig, commitOffchainConfig)
+ c.SetupExecOCR2Config(t, execOnchainConfig, execOffchainConfig)
+
+ return blockBeforeConfig.Number().Int64()
+}
+
+func (c *CCIPContracts) SendMessage(t *testing.T, gasLimit, tokenAmount *big.Int, receiverAddr common.Address) {
+ extraArgs, err := GetEVMExtraArgsV1(gasLimit, false)
+ require.NoError(t, err)
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: MustEncodeAddress(t, receiverAddr),
+ Data: []byte("hello"),
+ TokenAmounts: []router.ClientEVMTokenAmount{
+ {
+ Token: c.Source.LinkToken.Address(),
+ Amount: tokenAmount,
+ },
+ },
+ FeeToken: c.Source.LinkToken.Address(),
+ ExtraArgs: extraArgs,
+ }
+ fee, err := c.Source.Router.GetFee(nil, c.Dest.ChainSelector, msg)
+ require.NoError(t, err)
+ // Currently no overhead and 1gwei dest gas price. So fee is simply gasLimit * gasPrice.
+ // require.Equal(t, new(big.Int).Mul(gasLimit, gasPrice).String(), fee.String())
+ // Approve the fee amount + the token amount
+ _, err = c.Source.LinkToken.Approve(c.Source.User, c.Source.Router.Address(), new(big.Int).Add(fee, tokenAmount))
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.SendRequest(t, msg)
+}
+
+func GetBalances(t *testing.T, brs []BalanceReq) (map[string]*big.Int, error) {
+ m := make(map[string]*big.Int)
+ for _, br := range brs {
+ m[br.Name] = br.Getter(t, br.Addr)
+ if m[br.Name] == nil {
+ return nil, fmt.Errorf("%v getter return nil", br.Name)
+ }
+ }
+ return m, nil
+}
+
+func MustAddBigInt(a *big.Int, b string) *big.Int {
+ bi, _ := big.NewInt(0).SetString(b, 10)
+ return big.NewInt(0).Add(a, bi)
+}
+
+func MustSubBigInt(a *big.Int, b string) *big.Int {
+ bi, _ := big.NewInt(0).SetString(b, 10)
+ return big.NewInt(0).Sub(a, bi)
+}
+
+func MustEncodeAddress(t *testing.T, address common.Address) []byte {
+ bts, err := utils.ABIEncode(`[{"type":"address"}]`, address)
+ require.NoError(t, err)
+ return bts
+}
+
+func SetAdminAndRegisterPool(t *testing.T,
+ chain *backends.SimulatedBackend,
+ user *bind.TransactOpts,
+ tokenAdminRegistry *token_admin_registry.TokenAdminRegistry,
+ tokenAddress common.Address,
+ poolAddress common.Address) {
+ _, err := tokenAdminRegistry.ProposeAdministrator(user, tokenAddress, user.From)
+ require.NoError(t, err)
+ _, err = tokenAdminRegistry.AcceptAdminRole(user, tokenAddress)
+ require.NoError(t, err)
+ _, err = tokenAdminRegistry.SetPool(user, tokenAddress, poolAddress)
+ require.NoError(t, err)
+
+ chain.Commit()
+}
+
+func SetupCCIPContracts(t *testing.T, sourceChainID, sourceChainSelector, destChainID, destChainSelector uint64) CCIPContracts {
+ sourceChain, sourceUser := SetupChain(t)
+ destChain, destUser := SetupChain(t)
+
+ // ================================================================
+ // │ Deploy RMN │
+ // ================================================================
+
+ armSourceAddress, _, _, err := mock_arm_contract.DeployMockARMContract(
+ sourceUser,
+ sourceChain,
+ )
+ require.NoError(t, err)
+ sourceARM, err := mock_arm_contract.NewMockARMContract(armSourceAddress, sourceChain)
+ require.NoError(t, err)
+ armProxySourceAddress, _, _, err := arm_proxy_contract.DeployARMProxyContract(
+ sourceUser,
+ sourceChain,
+ armSourceAddress,
+ )
+ require.NoError(t, err)
+ sourceARMProxy, err := arm_proxy_contract.NewARMProxyContract(armProxySourceAddress, sourceChain)
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ armDestAddress, _, _, err := mock_arm_contract.DeployMockARMContract(
+ destUser,
+ destChain,
+ )
+ require.NoError(t, err)
+ armProxyDestAddress, _, _, err := arm_proxy_contract.DeployARMProxyContract(
+ destUser,
+ destChain,
+ armDestAddress,
+ )
+ require.NoError(t, err)
+ destChain.Commit()
+ destARM, err := mock_arm_contract.NewMockARMContract(armDestAddress, destChain)
+ require.NoError(t, err)
+ destARMProxy, err := arm_proxy_contract.NewARMProxyContract(armProxyDestAddress, destChain)
+ require.NoError(t, err)
+
+ // ================================================================
+ // │ Deploy TokenAdminRegistry │
+ // ================================================================
+
+ sourceTokenAdminRegistryAddress, _, _, err := token_admin_registry.DeployTokenAdminRegistry(sourceUser, sourceChain)
+ require.NoError(t, err)
+ sourceTokenAdminRegistry, err := token_admin_registry.NewTokenAdminRegistry(sourceTokenAdminRegistryAddress, sourceChain)
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ destTokenAdminRegistryAddress, _, _, err := token_admin_registry.DeployTokenAdminRegistry(destUser, destChain)
+ require.NoError(t, err)
+ destTokenAdminRegistry, err := token_admin_registry.NewTokenAdminRegistry(destTokenAdminRegistryAddress, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // ================================================================
+ // │ Deploy Tokens │
+ // ================================================================
+
+ // Deploy link token and pool on source chain
+ sourceLinkTokenAddress, _, _, err := link_token_interface.DeployLinkToken(sourceUser, sourceChain)
+ require.NoError(t, err)
+ sourceChain.Commit()
+ sourceLinkToken, err := link_token_interface.NewLinkToken(sourceLinkTokenAddress, sourceChain)
+ require.NoError(t, err)
+ t.Logf("Deloyed LINK token on source chain at %s", sourceLinkTokenAddress.String())
+
+ sourceWeth9addr, _, _, err := weth9.DeployWETH9(sourceUser, sourceChain)
+ require.NoError(t, err)
+ sourceWrapped, err := weth9.NewWETH9(sourceWeth9addr, sourceChain)
+ require.NoError(t, err)
+ t.Logf("Deloyed WETH9 token on source chain at %s", sourceWeth9addr.String())
+
+ sourceCustomTokenAddress, _, _, err := link_token_interface.DeployLinkToken(sourceUser, sourceChain)
+ require.NoError(t, err)
+ sourceCustomToken, err := link_token_interface.NewLinkToken(sourceCustomTokenAddress, sourceChain)
+ require.NoError(t, err)
+ destChain.Commit()
+ t.Logf("Deloyed custom token on source chain at %s", sourceCustomTokenAddress.String())
+
+ // Dest chain
+
+ destLinkTokenAddress, _, _, err := link_token_interface.DeployLinkToken(destUser, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+ destLinkToken, err := link_token_interface.NewLinkToken(destLinkTokenAddress, destChain)
+ require.NoError(t, err)
+ t.Logf("Deloyed LINK token on dest chain at %s", destLinkTokenAddress.String())
+
+ destWeth9addr, _, _, err := weth9.DeployWETH9(destUser, destChain)
+ require.NoError(t, err)
+ destWrapped, err := weth9.NewWETH9(destWeth9addr, destChain)
+ require.NoError(t, err)
+ t.Logf("Deloyed WETH9 token on dest chain at %s", destWeth9addr.String())
+
+ destCustomTokenAddress, _, _, err := link_token_interface.DeployLinkToken(destUser, destChain)
+ require.NoError(t, err)
+ destCustomToken, err := link_token_interface.NewLinkToken(destCustomTokenAddress, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+ t.Logf("Deloyed custom token on dest chain at %s", destCustomTokenAddress.String())
+
+ // ================================================================
+ // │ Deploy Routers │
+ // ================================================================
+
+ sourceRouterAddress, _, _, err := router.DeployRouter(sourceUser, sourceChain, sourceWeth9addr, armProxySourceAddress)
+ require.NoError(t, err)
+ sourceRouter, err := router.NewRouter(sourceRouterAddress, sourceChain)
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ destRouterAddress, _, _, err := router.DeployRouter(destUser, destChain, destWeth9addr, armProxyDestAddress)
+ require.NoError(t, err)
+ destRouter, err := router.NewRouter(destRouterAddress, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // ================================================================
+ // │ Deploy Pools │
+ // ================================================================
+
+ sourcePoolLinkAddress, _, _, err := lock_release_token_pool.DeployLockReleaseTokenPool(
+ sourceUser,
+ sourceChain,
+ sourceLinkTokenAddress,
+ []common.Address{},
+ armProxySourceAddress,
+ true,
+ sourceRouterAddress,
+ )
+ require.NoError(t, err)
+ sourceChain.Commit()
+ SetAdminAndRegisterPool(t, sourceChain, sourceUser, sourceTokenAdminRegistry, sourceLinkTokenAddress, sourcePoolLinkAddress)
+
+ sourceLinkPool, err := lock_release_token_pool.NewLockReleaseTokenPool(sourcePoolLinkAddress, sourceChain)
+ require.NoError(t, err)
+
+ sourceWeth9PoolAddress, _, _, err := lock_release_token_pool.DeployLockReleaseTokenPool(
+ sourceUser,
+ sourceChain,
+ sourceWeth9addr,
+ []common.Address{},
+ armProxySourceAddress,
+ true,
+ sourceRouterAddress,
+ )
+ require.NoError(t, err)
+ sourceChain.Commit()
+ SetAdminAndRegisterPool(t, sourceChain, sourceUser, sourceTokenAdminRegistry, sourceWeth9addr, sourceWeth9PoolAddress)
+
+ sourceWeth9Pool, err := lock_release_token_pool.NewLockReleaseTokenPool(sourceWeth9PoolAddress, sourceChain)
+ require.NoError(t, err)
+
+ // dest
+
+ destPoolLinkAddress, _, _, err := lock_release_token_pool.DeployLockReleaseTokenPool(
+ destUser,
+ destChain,
+ destLinkTokenAddress,
+ []common.Address{},
+ armProxyDestAddress,
+ true,
+ destRouterAddress,
+ )
+ require.NoError(t, err)
+ destChain.Commit()
+ SetAdminAndRegisterPool(t, destChain, destUser, destTokenAdminRegistry, destLinkTokenAddress, destPoolLinkAddress)
+
+ destLinkPool, err := lock_release_token_pool.NewLockReleaseTokenPool(destPoolLinkAddress, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // Float the offramp pool
+ o, err := destLinkPool.Owner(nil)
+ require.NoError(t, err)
+ require.Equal(t, destUser.From.String(), o.String())
+ _, err = destLinkPool.SetRebalancer(destUser, destUser.From)
+ require.NoError(t, err)
+ _, err = destLinkToken.Approve(destUser, destPoolLinkAddress, Link(200))
+ require.NoError(t, err)
+ _, err = destLinkPool.ProvideLiquidity(destUser, Link(200))
+ require.NoError(t, err)
+ destChain.Commit()
+
+ destWrappedPoolAddress, _, _, err := lock_release_token_pool.DeployLockReleaseTokenPool(
+ destUser,
+ destChain,
+ destWeth9addr,
+ []common.Address{},
+ armProxyDestAddress,
+ true,
+ destRouterAddress,
+ )
+ require.NoError(t, err)
+ destChain.Commit()
+ SetAdminAndRegisterPool(t, destChain, destUser, destTokenAdminRegistry, destWeth9addr, destWrappedPoolAddress)
+
+ destWrappedPool, err := lock_release_token_pool.NewLockReleaseTokenPool(destWrappedPoolAddress, destChain)
+ require.NoError(t, err)
+
+ poolFloatValue := big.NewInt(1e18)
+
+ destUser.Value = poolFloatValue
+ _, err = destWrapped.Deposit(destUser)
+ require.NoError(t, err)
+ destChain.Commit()
+ destUser.Value = nil
+
+ _, err = destWrapped.Transfer(destUser, destWrappedPool.Address(), poolFloatValue)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // ================================================================
+ // │ Configure token pools │
+ // ================================================================
+
+ abiEncodedDestLinkPool, err := abihelpers.EncodeAddress(destLinkPool.Address())
+ require.NoError(t, err)
+ abiEncodedDestLinkTokenAddress, err := abihelpers.EncodeAddress(destLinkToken.Address())
+ require.NoError(t, err)
+ _, err = sourceLinkPool.ApplyChainUpdates(
+ sourceUser,
+ []lock_release_token_pool.TokenPoolChainUpdate{{
+ RemoteChainSelector: DestChainSelector,
+ RemotePoolAddress: abiEncodedDestLinkPool,
+ RemoteTokenAddress: abiEncodedDestLinkTokenAddress,
+ Allowed: true,
+ OutboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ InboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ }},
+ )
+ require.NoError(t, err)
+
+ abiEncodedDestWrappedPool, err := abihelpers.EncodeAddress(destWrappedPool.Address())
+ require.NoError(t, err)
+ abiEncodedDestWrappedTokenAddr, err := abihelpers.EncodeAddress(destWeth9addr)
+ require.NoError(t, err)
+ _, err = sourceWeth9Pool.ApplyChainUpdates(
+ sourceUser,
+ []lock_release_token_pool.TokenPoolChainUpdate{{
+ RemoteChainSelector: DestChainSelector,
+ RemotePoolAddress: abiEncodedDestWrappedPool,
+ RemoteTokenAddress: abiEncodedDestWrappedTokenAddr,
+ Allowed: true,
+ OutboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ InboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ }},
+ )
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ abiEncodedSourceLinkPool, err := abihelpers.EncodeAddress(sourceLinkPool.Address())
+ require.NoError(t, err)
+ abiEncodedSourceLinkTokenAddr, err := abihelpers.EncodeAddress(sourceLinkTokenAddress)
+ require.NoError(t, err)
+ _, err = destLinkPool.ApplyChainUpdates(
+ destUser,
+ []lock_release_token_pool.TokenPoolChainUpdate{{
+ RemoteChainSelector: SourceChainSelector,
+ RemotePoolAddress: abiEncodedSourceLinkPool,
+ RemoteTokenAddress: abiEncodedSourceLinkTokenAddr,
+ Allowed: true,
+ OutboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ InboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ }},
+ )
+ require.NoError(t, err)
+
+ abiEncodedSourceWrappedPool, err := abihelpers.EncodeAddress(sourceWeth9Pool.Address())
+ require.NoError(t, err)
+ abiEncodedSourceWrappedTokenAddr, err := abihelpers.EncodeAddress(sourceWrapped.Address())
+ require.NoError(t, err)
+ _, err = destWrappedPool.ApplyChainUpdates(
+ destUser,
+ []lock_release_token_pool.TokenPoolChainUpdate{{
+ RemoteChainSelector: SourceChainSelector,
+ RemotePoolAddress: abiEncodedSourceWrappedPool,
+ RemoteTokenAddress: abiEncodedSourceWrappedTokenAddr,
+ Allowed: true,
+ OutboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ InboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ }},
+ )
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // ================================================================
+ // │ Deploy Price Registry │
+ // ================================================================
+
+ sourcePricesAddress, _, _, err := price_registry_1_2_0.DeployPriceRegistry(
+ sourceUser,
+ sourceChain,
+ nil,
+ []common.Address{sourceLinkTokenAddress, sourceWeth9addr},
+ 60*60*24*14, // two weeks
+ )
+ require.NoError(t, err)
+
+ srcPriceRegistry, err := price_registry_1_2_0.NewPriceRegistry(sourcePricesAddress, sourceChain)
+ require.NoError(t, err)
+
+ _, err = srcPriceRegistry.UpdatePrices(sourceUser, price_registry_1_2_0.InternalPriceUpdates{
+ TokenPriceUpdates: []price_registry_1_2_0.InternalTokenPriceUpdate{
+ {
+ SourceToken: sourceLinkTokenAddress,
+ UsdPerToken: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(20)),
+ },
+ {
+ SourceToken: sourceWeth9addr,
+ UsdPerToken: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2000)),
+ },
+ },
+ GasPriceUpdates: []price_registry_1_2_0.InternalGasPriceUpdate{
+ {
+ DestChainSelector: destChainSelector,
+ UsdPerUnitGas: big.NewInt(20000e9),
+ },
+ },
+ })
+ require.NoError(t, err)
+
+ // ================================================================
+ // │ Deploy Lane │
+ // ================================================================
+
+ onRampAddress, _, _, err := evm_2_evm_onramp.DeployEVM2EVMOnRamp(
+ sourceUser, // user
+ sourceChain, // client
+ evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{
+ LinkToken: sourceLinkTokenAddress,
+ ChainSelector: sourceChainSelector,
+ DestChainSelector: destChainSelector,
+ DefaultTxGasLimit: 200_000,
+ MaxNopFeesJuels: big.NewInt(0).Mul(big.NewInt(100_000_000), big.NewInt(1e18)),
+ PrevOnRamp: common.HexToAddress(""),
+ RmnProxy: armProxySourceAddress, // RMN, formerly ARM
+ TokenAdminRegistry: sourceTokenAdminRegistry.Address(),
+ },
+ evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig{
+ Router: sourceRouterAddress,
+ MaxNumberOfTokensPerMsg: 5,
+ DestGasOverhead: 350_000,
+ DestGasPerPayloadByte: 16,
+ DestDataAvailabilityOverheadGas: 33_596,
+ DestGasPerDataAvailabilityByte: 16,
+ DestDataAvailabilityMultiplierBps: 6840, // 0.684
+ PriceRegistry: sourcePricesAddress,
+ MaxDataBytes: 1e5,
+ MaxPerMsgGasLimit: 4_000_000,
+ DefaultTokenFeeUSDCents: 50,
+ DefaultTokenDestGasOverhead: 34_000,
+ DefaultTokenDestBytesOverhead: 500,
+ },
+ evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: LinkUSDValue(100),
+ Rate: LinkUSDValue(1),
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: sourceLinkTokenAddress,
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: 1e18,
+ PremiumMultiplierWeiPerEth: 9e17,
+ Enabled: true,
+ },
+ {
+ Token: sourceWeth9addr,
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: 1e18,
+ PremiumMultiplierWeiPerEth: 1e18,
+ Enabled: true,
+ },
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: sourceLinkTokenAddress,
+ MinFeeUSDCents: 50, // $0.5
+ MaxFeeUSDCents: 1_000_000_00, // $ 1 million
+ DeciBps: 5_0, // 5 bps
+ DestGasOverhead: 34_000,
+ DestBytesOverhead: 32,
+ AggregateRateLimitEnabled: true,
+ },
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{},
+ )
+ require.NoError(t, err)
+ onRamp, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(onRampAddress, sourceChain)
+ require.NoError(t, err)
+
+ _, err = sourceRouter.ApplyRampUpdates(sourceUser, []router.RouterOnRamp{{DestChainSelector: destChainSelector, OnRamp: onRampAddress}}, nil, nil)
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ destPriceRegistryAddress, _, _, err := price_registry_1_2_0.DeployPriceRegistry(
+ destUser,
+ destChain,
+ nil,
+ []common.Address{destLinkTokenAddress, destWeth9addr},
+ 60*60*24*14, // two weeks
+ )
+ require.NoError(t, err)
+ destPriceRegistry, err := price_registry_1_2_0.NewPriceRegistry(destPriceRegistryAddress, destChain)
+ require.NoError(t, err)
+
+ // Deploy commit store.
+ commitStoreAddress, _, _, err := commit_store_helper_1_2_0.DeployCommitStoreHelper(
+ destUser, // user
+ destChain, // client
+ commit_store_helper_1_2_0.CommitStoreStaticConfig{
+ ChainSelector: destChainSelector,
+ SourceChainSelector: sourceChainSelector,
+ OnRamp: onRamp.Address(),
+ ArmProxy: destARMProxy.Address(),
+ },
+ )
+ require.NoError(t, err)
+ destChain.Commit()
+ commitStore, err := commit_store.NewCommitStore(commitStoreAddress, destChain)
+ require.NoError(t, err)
+ commitStoreHelper, err := commit_store_helper.NewCommitStoreHelper(commitStoreAddress, destChain)
+ require.NoError(t, err)
+
+ offRampAddress, _, _, err := evm_2_evm_offramp.DeployEVM2EVMOffRamp(
+ destUser,
+ destChain,
+ evm_2_evm_offramp.EVM2EVMOffRampStaticConfig{
+ CommitStore: commitStore.Address(),
+ ChainSelector: destChainSelector,
+ SourceChainSelector: sourceChainSelector,
+ OnRamp: onRampAddress,
+ PrevOffRamp: common.HexToAddress(""),
+ RmnProxy: armProxyDestAddress, // RMN, formerly ARM
+ TokenAdminRegistry: destTokenAdminRegistryAddress,
+ },
+ evm_2_evm_offramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: LinkUSDValue(100),
+ Rate: LinkUSDValue(1),
+ },
+ )
+ require.NoError(t, err)
+ offRamp, err := evm_2_evm_offramp.NewEVM2EVMOffRamp(offRampAddress, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ _, err = destPriceRegistry.ApplyPriceUpdatersUpdates(destUser, []common.Address{commitStoreAddress}, []common.Address{})
+ require.NoError(t, err)
+ _, err = destRouter.ApplyRampUpdates(
+ destUser,
+ nil,
+ nil,
+ []router.RouterOffRamp{{SourceChainSelector: sourceChainSelector, OffRamp: offRampAddress}},
+ )
+ require.NoError(t, err)
+
+ // Deploy 2 revertable (one SS one non-SS)
+ revertingMessageReceiver1Address, _, _, err := maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver(destUser, destChain, false)
+ require.NoError(t, err)
+ revertingMessageReceiver1, _ := maybe_revert_message_receiver.NewMaybeRevertMessageReceiver(revertingMessageReceiver1Address, destChain)
+ revertingMessageReceiver2Address, _, _, err := maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver(destUser, destChain, false)
+ require.NoError(t, err)
+ revertingMessageReceiver2, _ := maybe_revert_message_receiver.NewMaybeRevertMessageReceiver(revertingMessageReceiver2Address, destChain)
+ // Need to commit here, or we will hit the block gas limit when deploying the executor
+ sourceChain.Commit()
+ destChain.Commit()
+
+ // Ensure we have at least finality blocks.
+ for i := 0; i < 50; i++ {
+ sourceChain.Commit()
+ destChain.Commit()
+ }
+
+ source := SourceChain{
+ Common: Common{
+ ChainID: sourceChainID,
+ ChainSelector: sourceChainSelector,
+ User: sourceUser,
+ Chain: sourceChain,
+ LinkToken: sourceLinkToken,
+ LinkTokenPool: sourceLinkPool,
+ CustomToken: sourceCustomToken,
+ ARM: sourceARM,
+ ARMProxy: sourceARMProxy,
+ PriceRegistry: srcPriceRegistry,
+ WrappedNative: sourceWrapped,
+ WrappedNativePool: sourceWeth9Pool,
+ TokenAdminRegistry: sourceTokenAdminRegistry,
+ },
+ Router: sourceRouter,
+ OnRamp: onRamp,
+ }
+ dest := DestinationChain{
+ Common: Common{
+ ChainID: destChainID,
+ ChainSelector: destChainSelector,
+ User: destUser,
+ Chain: destChain,
+ LinkToken: destLinkToken,
+ LinkTokenPool: destLinkPool,
+ CustomToken: destCustomToken,
+ ARM: destARM,
+ ARMProxy: destARMProxy,
+ PriceRegistry: destPriceRegistry,
+ WrappedNative: destWrapped,
+ WrappedNativePool: destWrappedPool,
+ TokenAdminRegistry: destTokenAdminRegistry,
+ },
+ CommitStoreHelper: commitStoreHelper,
+ CommitStore: commitStore,
+ Router: destRouter,
+ OffRamp: offRamp,
+ Receivers: []MaybeRevertReceiver{{Receiver: revertingMessageReceiver1, Strict: false}, {Receiver: revertingMessageReceiver2, Strict: true}},
+ }
+
+ return CCIPContracts{
+ Source: source,
+ Dest: dest,
+ }
+}
+
+func (c *CCIPContracts) SendRequest(t *testing.T, msg router.ClientEVM2AnyMessage) *types.Transaction {
+ tx, err := c.Source.Router.CcipSend(c.Source.User, c.Dest.ChainSelector, msg)
+ require.NoError(t, err)
+ ConfirmTxs(t, []*types.Transaction{tx}, c.Source.Chain)
+ return tx
+}
+
+func (c *CCIPContracts) AssertExecState(t *testing.T, log logpoller.Log, state MessageExecutionState, offRampOpts ...common.Address) {
+ var offRamp *evm_2_evm_offramp.EVM2EVMOffRamp
+ var err error
+ if len(offRampOpts) > 0 {
+ offRamp, err = evm_2_evm_offramp.NewEVM2EVMOffRamp(offRampOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.OffRamp, "no offRamp configured")
+ offRamp = c.Dest.OffRamp
+ }
+ executionStateChanged, err := offRamp.ParseExecutionStateChanged(log.ToGethLog())
+ require.NoError(t, err)
+ if MessageExecutionState(executionStateChanged.State) != state {
+ t.Log("Execution failed", hexutil.Encode(executionStateChanged.ReturnData))
+ t.Fail()
+ }
+}
+
+func GetEVMExtraArgsV1(gasLimit *big.Int, strict bool) ([]byte, error) {
+ EVMV1Tag := []byte{0x97, 0xa6, 0x57, 0xc9}
+
+ encodedArgs, err := utils.ABIEncode(`[{"type":"uint256"},{"type":"bool"}]`, gasLimit, strict)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(EVMV1Tag, encodedArgs...), nil
+}
+
+func GetEVMExtraArgsV2(gasLimit *big.Int, allowOutOfOrder bool) ([]byte, error) {
+ // see Client.sol.
+ EVMV2Tag := hexutil.MustDecode("0x181dcf10")
+
+ encodedArgs, err := utils.ABIEncode(`[{"type":"uint256"},{"type":"bool"}]`, gasLimit, allowOutOfOrder)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(EVMV2Tag, encodedArgs...), nil
+}
+
+type ManualExecArgs struct {
+ SourceChainID, DestChainID uint64
+ DestUser *bind.TransactOpts
+ SourceChain, DestChain bind.ContractBackend
+ SourceStartBlock *big.Int // the block in/after which failed ccip-send transaction was triggered
+ DestStartBlock uint64 // the start block for filtering ReportAccepted event (including the failed seq num)
+ // in destination chain. if not provided to be derived by ApproxDestStartBlock method
+ DestLatestBlockNum uint64 // current block number in destination
+ DestDeployedAt uint64 // destination block number for the initial destination contract deployment.
+ // Can be any number before the tx was reverted in destination chain. Preferably this needs to be set up with
+ // a value greater than zero to avoid performance issue in locating approximate destination block
+ SendReqLogIndex uint // log index of the CCIPSendRequested log in source chain
+ SendReqTxHash string // tx hash of the ccip-send transaction for which execution was reverted
+ CommitStore string
+ OnRamp string
+ OffRamp string
+ SeqNr uint64
+ GasLimit *big.Int
+}
+
+// ApproxDestStartBlock attempts to locate a block in destination chain with timestamp closest to the timestamp of the block
+// in source chain in which ccip-send transaction was included
+// it uses binary search to locate the block with the closest timestamp
+// if the block located has a timestamp greater than the timestamp of mentioned source block
+// it just returns the first block found with lesser timestamp of the source block
+// providing a value of args.DestDeployedAt ensures better performance by reducing the range of block numbers to be traversed
+func (args *ManualExecArgs) ApproxDestStartBlock() error {
+ sourceBlockHdr, err := args.SourceChain.HeaderByNumber(context.Background(), args.SourceStartBlock)
+ if err != nil {
+ return err
+ }
+ sendTxTime := sourceBlockHdr.Time
+ maxBlockNum := args.DestLatestBlockNum
+ // setting this to an approx value of 1000 considering destination chain would have at least 1000 blocks before the transaction started
+ minBlockNum := args.DestDeployedAt
+ closestBlockNum := uint64(math.Floor((float64(maxBlockNum) + float64(minBlockNum)) / 2))
+ var closestBlockHdr *types.Header
+ closestBlockHdr, err = args.DestChain.HeaderByNumber(context.Background(), big.NewInt(int64(closestBlockNum)))
+ if err != nil {
+ return err
+ }
+ // to reduce the number of RPC calls increase the value of blockOffset
+ blockOffset := uint64(10)
+ for {
+ blockNum := closestBlockHdr.Number.Uint64()
+ if minBlockNum > maxBlockNum {
+ break
+ }
+ timeDiff := math.Abs(float64(closestBlockHdr.Time - sendTxTime))
+ // break if the difference in timestamp is lesser than 1 minute
+ if timeDiff < 60 {
+ break
+ } else if closestBlockHdr.Time > sendTxTime {
+ maxBlockNum = blockNum - 1
+ } else {
+ minBlockNum = blockNum + 1
+ }
+ closestBlockNum = uint64(math.Floor((float64(maxBlockNum) + float64(minBlockNum)) / 2))
+ closestBlockHdr, err = args.DestChain.HeaderByNumber(context.Background(), big.NewInt(int64(closestBlockNum)))
+ if err != nil {
+ return err
+ }
+ }
+
+ for closestBlockHdr.Time > sendTxTime {
+ closestBlockNum = closestBlockNum - blockOffset
+ if closestBlockNum <= 0 {
+ return fmt.Errorf("approx destination blocknumber not found")
+ }
+ closestBlockHdr, err = args.DestChain.HeaderByNumber(context.Background(), big.NewInt(int64(closestBlockNum)))
+ if err != nil {
+ return err
+ }
+ }
+ args.DestStartBlock = closestBlockHdr.Number.Uint64()
+ fmt.Println("using approx destination start block number", args.DestStartBlock)
+ return nil
+}
+
+func (args *ManualExecArgs) FindSeqNrFromCCIPSendRequested() (uint64, error) {
+ var seqNr uint64
+ onRampContract, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(common.HexToAddress(args.OnRamp), args.SourceChain)
+ if err != nil {
+ return seqNr, err
+ }
+ iterator, err := onRampContract.FilterCCIPSendRequested(&bind.FilterOpts{
+ Start: args.SourceStartBlock.Uint64(),
+ })
+ if err != nil {
+ return seqNr, err
+ }
+ for iterator.Next() {
+ if iterator.Event.Raw.Index == args.SendReqLogIndex &&
+ iterator.Event.Raw.TxHash.Hex() == args.SendReqTxHash {
+ seqNr = iterator.Event.Message.SequenceNumber
+ break
+ }
+ }
+ if seqNr == 0 {
+ return seqNr,
+ fmt.Errorf("no CCIPSendRequested logs found for logIndex %d starting from block number %d", args.SendReqLogIndex, args.SourceStartBlock)
+ }
+ return seqNr, nil
+}
+
+func (args *ManualExecArgs) ExecuteManually() (*types.Transaction, error) {
+ if args.SourceChainID == 0 ||
+ args.DestChainID == 0 ||
+ args.DestUser == nil {
+ return nil, fmt.Errorf("chain ids and owners are mandatory for source and dest chain")
+ }
+ if !common.IsHexAddress(args.CommitStore) ||
+ !common.IsHexAddress(args.OffRamp) ||
+ !common.IsHexAddress(args.OnRamp) {
+ return nil, fmt.Errorf("contract addresses must be valid hex address")
+ }
+ if args.SendReqTxHash == "" {
+ return nil, fmt.Errorf("tx hash of ccip-send request are required")
+ }
+ if args.SourceStartBlock == nil {
+ return nil, fmt.Errorf("must provide the value of source block in/after which ccip-send tx was included")
+ }
+ if args.SeqNr == 0 {
+ if args.SendReqLogIndex == 0 {
+ return nil, fmt.Errorf("must provide the value of log index of ccip-send request")
+ }
+ // locate seq nr from CCIPSendRequested log
+ seqNr, err := args.FindSeqNrFromCCIPSendRequested()
+ if err != nil {
+ return nil, err
+ }
+ args.SeqNr = seqNr
+ }
+ commitStore, err := commit_store.NewCommitStore(common.HexToAddress(args.CommitStore), args.DestChain)
+ if err != nil {
+ return nil, err
+ }
+ if args.DestStartBlock < 1 {
+ err = args.ApproxDestStartBlock()
+ if err != nil {
+ return nil, err
+ }
+ }
+ iterator, err := commitStore.FilterReportAccepted(&bind.FilterOpts{Start: args.DestStartBlock})
+ if err != nil {
+ return nil, err
+ }
+
+ var commitReport *commit_store.CommitStoreCommitReport
+ for iterator.Next() {
+ if iterator.Event.Report.Interval.Min <= args.SeqNr && iterator.Event.Report.Interval.Max >= args.SeqNr {
+ commitReport = &iterator.Event.Report
+ fmt.Println("Found root")
+ break
+ }
+ }
+ if commitReport == nil {
+ return nil, fmt.Errorf("unable to find seq num %d in commit report", args.SeqNr)
+ }
+
+ return args.execute(commitReport)
+}
+
+func (args *ManualExecArgs) execute(report *commit_store.CommitStoreCommitReport) (*types.Transaction, error) {
+ log.Info().Msg("Executing request manually")
+ seqNr := args.SeqNr
+ // Build a merkle tree for the report
+ mctx := hashutil.NewKeccak()
+ onRampContract, err := evm_2_evm_onramp_1_2_0.NewEVM2EVMOnRamp(common.HexToAddress(args.OnRamp), args.SourceChain)
+ if err != nil {
+ return nil, err
+ }
+ leafHasher := v1_2_0.NewLeafHasher(args.SourceChainID, args.DestChainID, common.HexToAddress(args.OnRamp), mctx, onRampContract)
+ if leafHasher == nil {
+ return nil, fmt.Errorf("unable to create leaf hasher")
+ }
+
+ var leaves [][32]byte
+ var curr, prove int
+ var msgs []evm_2_evm_offramp.InternalEVM2EVMMessage
+ var manualExecGasLimits []*big.Int
+ var tokenData [][][]byte
+ sendRequestedIterator, err := onRampContract.FilterCCIPSendRequested(&bind.FilterOpts{
+ Start: args.SourceStartBlock.Uint64(),
+ })
+ if err != nil {
+ return nil, err
+ }
+ for sendRequestedIterator.Next() {
+ if sendRequestedIterator.Event.Message.SequenceNumber <= report.Interval.Max &&
+ sendRequestedIterator.Event.Message.SequenceNumber >= report.Interval.Min {
+ fmt.Println("Found seq num", sendRequestedIterator.Event.Message.SequenceNumber, report.Interval)
+ hash, err2 := leafHasher.HashLeaf(sendRequestedIterator.Event.Raw)
+ if err2 != nil {
+ return nil, err2
+ }
+ leaves = append(leaves, hash)
+ if sendRequestedIterator.Event.Message.SequenceNumber == seqNr {
+ fmt.Printf("Found proving %d %+v\n", curr, sendRequestedIterator.Event.Message)
+ var tokensAndAmounts []evm_2_evm_offramp.ClientEVMTokenAmount
+ for _, tokenAndAmount := range sendRequestedIterator.Event.Message.TokenAmounts {
+ tokensAndAmounts = append(tokensAndAmounts, evm_2_evm_offramp.ClientEVMTokenAmount{
+ Token: tokenAndAmount.Token,
+ Amount: tokenAndAmount.Amount,
+ })
+ }
+ msg := evm_2_evm_offramp.InternalEVM2EVMMessage{
+ SourceChainSelector: sendRequestedIterator.Event.Message.SourceChainSelector,
+ Sender: sendRequestedIterator.Event.Message.Sender,
+ Receiver: sendRequestedIterator.Event.Message.Receiver,
+ SequenceNumber: sendRequestedIterator.Event.Message.SequenceNumber,
+ GasLimit: sendRequestedIterator.Event.Message.GasLimit,
+ Strict: sendRequestedIterator.Event.Message.Strict,
+ Nonce: sendRequestedIterator.Event.Message.Nonce,
+ FeeToken: sendRequestedIterator.Event.Message.FeeToken,
+ FeeTokenAmount: sendRequestedIterator.Event.Message.FeeTokenAmount,
+ Data: sendRequestedIterator.Event.Message.Data,
+ TokenAmounts: tokensAndAmounts,
+ SourceTokenData: sendRequestedIterator.Event.Message.SourceTokenData,
+ MessageId: sendRequestedIterator.Event.Message.MessageId,
+ }
+ msgs = append(msgs, msg)
+ if args.GasLimit != nil {
+ msg.GasLimit = args.GasLimit
+ }
+ manualExecGasLimits = append(manualExecGasLimits, msg.GasLimit)
+ var msgTokenData [][]byte
+ for range sendRequestedIterator.Event.Message.TokenAmounts {
+ msgTokenData = append(msgTokenData, []byte{})
+ }
+
+ tokenData = append(tokenData, msgTokenData)
+ prove = curr
+ }
+ curr++
+ }
+ }
+ sendRequestedIterator.Close()
+ if msgs == nil {
+ return nil, fmt.Errorf("unable to find msg with seqNr %d", seqNr)
+ }
+ tree, err := merklemulti.NewTree(mctx, leaves)
+ if err != nil {
+ return nil, err
+ }
+ if tree.Root() != report.MerkleRoot {
+ return nil, fmt.Errorf("root doesn't match")
+ }
+
+ proof, err := tree.Prove([]int{prove})
+ if err != nil {
+ return nil, err
+ }
+
+ offRampProof := evm_2_evm_offramp.InternalExecutionReport{
+ Messages: msgs,
+ OffchainTokenData: tokenData,
+ Proofs: proof.Hashes,
+ ProofFlagBits: abihelpers.ProofFlagsToBits(proof.SourceFlags),
+ }
+ offRamp, err := evm_2_evm_offramp.NewEVM2EVMOffRamp(common.HexToAddress(args.OffRamp), args.DestChain)
+ if err != nil {
+ return nil, err
+ }
+ // Execute.
+ return offRamp.ManuallyExecute(args.DestUser, offRampProof, manualExecGasLimits)
+}
+
+func (c *CCIPContracts) ExecuteMessage(
+ t *testing.T,
+ req logpoller.Log,
+ txHash common.Hash,
+ destStartBlock uint64,
+) uint64 {
+ t.Log("Executing request manually")
+ sendReqReceipt, err := c.Source.Chain.TransactionReceipt(context.Background(), txHash)
+ require.NoError(t, err)
+ args := ManualExecArgs{
+ SourceChainID: c.Source.ChainID,
+ DestChainID: c.Dest.ChainID,
+ DestUser: c.Dest.User,
+ SourceChain: c.Source.Chain,
+ DestChain: c.Dest.Chain,
+ SourceStartBlock: sendReqReceipt.BlockNumber,
+ DestStartBlock: destStartBlock,
+ DestLatestBlockNum: c.Dest.Chain.Blockchain().CurrentBlock().Number.Uint64(),
+ SendReqLogIndex: uint(req.LogIndex),
+ SendReqTxHash: txHash.String(),
+ CommitStore: c.Dest.CommitStore.Address().String(),
+ OnRamp: c.Source.OnRamp.Address().String(),
+ OffRamp: c.Dest.OffRamp.Address().String(),
+ }
+ tx, err := args.ExecuteManually()
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+ c.Source.Chain.Commit()
+ rec, err := c.Dest.Chain.TransactionReceipt(context.Background(), tx.Hash())
+ require.NoError(t, err)
+ require.Equal(t, uint64(1), rec.Status, "manual execution failed")
+ t.Logf("Manual Execution completed for seqNum %d", args.SeqNr)
+ return args.SeqNr
+}
+
+func GetBalance(t *testing.T, chain bind.ContractBackend, tokenAddr common.Address, addr common.Address) *big.Int {
+ token, err := link_token_interface.NewLinkToken(tokenAddr, chain)
+ require.NoError(t, err)
+ bal, err := token.BalanceOf(nil, addr)
+ require.NoError(t, err)
+ return bal
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/config.go b/core/services/ocr2/plugins/ccip/testhelpers/config.go
new file mode 100644
index 00000000000..f70f1954f18
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/config.go
@@ -0,0 +1,73 @@
+// Package with set of configs that should be used only within tests suites
+
+package testhelpers
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0"
+)
+
+var PermissionLessExecutionThresholdSeconds = uint32(FirstBlockAge.Seconds())
+
+func (c *CCIPContracts) CreateDefaultCommitOnchainConfig(t *testing.T) []byte {
+ config, err := abihelpers.EncodeAbiStruct(ccipdata.CommitOnchainConfig{
+ PriceRegistry: c.Dest.PriceRegistry.Address(),
+ })
+ require.NoError(t, err)
+ return config
+}
+
+func (c *CCIPContracts) CreateDefaultCommitOffchainConfig(t *testing.T) []byte {
+ return c.createCommitOffchainConfig(t, 10*time.Second, 5*time.Second)
+}
+
+func (c *CCIPContracts) createCommitOffchainConfig(t *testing.T, feeUpdateHearBeat time.Duration, inflightCacheExpiry time.Duration) []byte {
+ config, err := NewCommitOffchainConfig(
+ *config.MustNewDuration(feeUpdateHearBeat),
+ 1,
+ 1,
+ *config.MustNewDuration(feeUpdateHearBeat),
+ 1,
+ *config.MustNewDuration(inflightCacheExpiry),
+ ).Encode()
+ require.NoError(t, err)
+ return config
+}
+
+func (c *CCIPContracts) CreateDefaultExecOnchainConfig(t *testing.T) []byte {
+ config, err := abihelpers.EncodeAbiStruct(v1_5_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: PermissionLessExecutionThresholdSeconds,
+ Router: c.Dest.Router.Address(),
+ PriceRegistry: c.Dest.PriceRegistry.Address(),
+ MaxDataBytes: 1e5,
+ MaxNumberOfTokensPerMsg: 5,
+ MaxPoolReleaseOrMintGas: 200_000,
+ MaxTokenTransferGas: 100_000,
+ })
+ require.NoError(t, err)
+ return config
+}
+
+func (c *CCIPContracts) CreateDefaultExecOffchainConfig(t *testing.T) []byte {
+ return c.createExecOffchainConfig(t, 1*time.Minute, 1*time.Minute)
+}
+
+func (c *CCIPContracts) createExecOffchainConfig(t *testing.T, inflightCacheExpiry time.Duration, rootSnoozeTime time.Duration) []byte {
+ config, err := NewExecOffchainConfig(
+ 1,
+ 5_000_000,
+ 0.07,
+ *config.MustNewDuration(inflightCacheExpiry),
+ *config.MustNewDuration(rootSnoozeTime),
+ ).Encode()
+ require.NoError(t, err)
+ return config
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go
new file mode 100644
index 00000000000..fe9021e4c14
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go
@@ -0,0 +1,1078 @@
+package integrationtesthelpers
+
+import (
+ "context"
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "net/http"
+ "net/http/httptest"
+ "slices"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ types3 "github.com/ethereum/go-ethereum/core/types"
+ "github.com/google/uuid"
+ "github.com/hashicorp/consul/sdk/freeport"
+ "github.com/jmoiron/sqlx"
+ "github.com/onsi/gomega"
+ "github.com/pkg/errors"
+
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap"
+ "k8s.io/utils/pointer" //nolint:staticcheck
+
+ "github.com/smartcontractkit/libocr/commontypes"
+ "github.com/smartcontractkit/libocr/offchainreporting2/confighelper"
+ types4 "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/loop"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core/mocks"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ evmUtils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
+ configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/logger/audit"
+ "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
+ feeds2 "github.com/smartcontractkit/chainlink/v2/core/services/feeds"
+ feedsMocks "github.com/smartcontractkit/chainlink/v2/core/services/feeds/mocks"
+ pb "github.com/smartcontractkit/chainlink/v2/core/services/feeds/proto"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key"
+ ksMocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_5_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap"
+ evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+ clutils "github.com/smartcontractkit/chainlink/v2/core/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/utils/crypto"
+ "github.com/smartcontractkit/chainlink/v2/plugins"
+)
+
+const (
+ execSpecTemplate = `
+ type = "offchainreporting2"
+ schemaVersion = 1
+ name = "ccip-exec-1"
+ externalJobID = "67ffad71-d90f-4fe3-b4e4-494924b707fb"
+ forwardingAllowed = false
+ maxTaskDuration = "0s"
+ contractID = "%s"
+ contractConfigConfirmations = 1
+ contractConfigTrackerPollInterval = "20s"
+ ocrKeyBundleID = "%s"
+ relay = "evm"
+ pluginType = "ccip-execution"
+ transmitterID = "%s"
+
+ [relayConfig]
+ chainID = 1_337
+
+ [pluginConfig]
+ destStartBlock = 50
+
+ [pluginConfig.USDCConfig]
+ AttestationAPI = "http://blah.com"
+ SourceMessageTransmitterAddress = "%s"
+ SourceTokenAddress = "%s"
+ AttestationAPITimeoutSeconds = 10
+ `
+ commitSpecTemplatePipeline = `
+ type = "offchainreporting2"
+ schemaVersion = 1
+ name = "ccip-commit-1"
+ externalJobID = "13c997cf-1a14-4ab7-9068-07ee6d2afa55"
+ forwardingAllowed = false
+ maxTaskDuration = "0s"
+ contractID = "%s"
+ contractConfigConfirmations = 1
+ contractConfigTrackerPollInterval = "20s"
+ ocrKeyBundleID = "%s"
+ relay = "evm"
+ pluginType = "ccip-commit"
+ transmitterID = "%s"
+
+ [relayConfig]
+ chainID = 1_337
+
+ [pluginConfig]
+ destStartBlock = 50
+ offRamp = "%s"
+ tokenPricesUSDPipeline = """
+ %s
+ """
+ `
+ commitSpecTemplateDynamicPriceGetter = `
+ type = "offchainreporting2"
+ schemaVersion = 1
+ name = "ccip-commit-1"
+ externalJobID = "13c997cf-1a14-4ab7-9068-07ee6d2afa55"
+ forwardingAllowed = false
+ maxTaskDuration = "0s"
+ contractID = "%s"
+ contractConfigConfirmations = 1
+ contractConfigTrackerPollInterval = "20s"
+ ocrKeyBundleID = "%s"
+ relay = "evm"
+ pluginType = "ccip-commit"
+ transmitterID = "%s"
+
+ [relayConfig]
+ chainID = 1_337
+
+ [pluginConfig]
+ destStartBlock = 50
+ offRamp = "%s"
+ priceGetterConfig = """
+ %s
+ """
+ `
+)
+
+type Node struct {
+ App chainlink.Application
+ Transmitter common.Address
+ PaymentReceiver common.Address
+ KeyBundle ocr2key.KeyBundle
+}
+
+func (node *Node) FindJobIDForContract(t *testing.T, addr common.Address) int32 {
+ jobs := node.App.JobSpawner().ActiveJobs()
+ for _, j := range jobs {
+ if j.Type == job.OffchainReporting2 && j.OCR2OracleSpec.ContractID == addr.Hex() {
+ return j.ID
+ }
+ }
+ t.Fatalf("Could not find job for contract %s", addr.Hex())
+ return 0
+}
+
+func (node *Node) EventuallyNodeUsesUpdatedPriceRegistry(t *testing.T, ccipContracts CCIPIntegrationTestHarness) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ log, err := c.LogPoller().LatestLogByEventSigWithConfs(
+ testutils.Context(t),
+ v1_0_0.UsdPerUnitGasUpdated,
+ ccipContracts.Dest.PriceRegistry.Address(),
+ 0,
+ )
+ // err can be transient errors such as sql row set empty
+ if err != nil {
+ return false
+ }
+ return log != nil
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "node is not using updated price registry %s", ccipContracts.Dest.PriceRegistry.Address().Hex())
+ return log
+}
+
+func (node *Node) EventuallyNodeUsesNewCommitConfig(t *testing.T, ccipContracts CCIPIntegrationTestHarness, commitCfg ccipdata.CommitOnchainConfig) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ log, err := c.LogPoller().LatestLogByEventSigWithConfs(
+ testutils.Context(t),
+ evmrelay.OCR2AggregatorLogDecoder.EventSig(),
+ ccipContracts.Dest.CommitStore.Address(),
+ 0,
+ )
+ require.NoError(t, err)
+ var latestCfg ccipdata.CommitOnchainConfig
+ if log != nil {
+ latestCfg, err = DecodeCommitOnChainConfig(log.Data)
+ require.NoError(t, err)
+ return latestCfg == commitCfg
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "node is using old cfg")
+ return log
+}
+
+func (node *Node) EventuallyNodeUsesNewExecConfig(t *testing.T, ccipContracts CCIPIntegrationTestHarness, execCfg v1_5_0.ExecOnchainConfig) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ log, err := c.LogPoller().LatestLogByEventSigWithConfs(
+ testutils.Context(t),
+ evmrelay.OCR2AggregatorLogDecoder.EventSig(),
+ ccipContracts.Dest.OffRamp.Address(),
+ 0,
+ )
+ require.NoError(t, err)
+ var latestCfg v1_5_0.ExecOnchainConfig
+ if log != nil {
+ latestCfg, err = DecodeExecOnChainConfig(log.Data)
+ require.NoError(t, err)
+ return latestCfg == execCfg
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "node is using old cfg")
+ return log
+}
+
+func (node *Node) EventuallyHasReqSeqNum(t *testing.T, ccipContracts *CCIPIntegrationTestHarness, onRamp common.Address, seqNum int) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Source.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ lgs, err := c.LogPoller().LogsDataWordRange(
+ testutils.Context(t),
+ v1_2_0.CCIPSendRequestEventSig,
+ onRamp,
+ v1_2_0.CCIPSendRequestSeqNumIndex,
+ abihelpers.EvmWord(uint64(seqNum)),
+ abihelpers.EvmWord(uint64(seqNum)),
+ 1,
+ )
+ require.NoError(t, err)
+ t.Log("Send requested", len(lgs))
+ if len(lgs) == 1 {
+ log = lgs[0]
+ return true
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "eventually has seq num")
+ return log
+}
+
+func (node *Node) EventuallyHasExecutedSeqNums(t *testing.T, ccipContracts *CCIPIntegrationTestHarness, offRamp common.Address, minSeqNum int, maxSeqNum int) []logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var logs []logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ lgs, err := c.LogPoller().IndexedLogsTopicRange(
+ testutils.Context(t),
+ v1_0_0.ExecutionStateChangedEvent,
+ offRamp,
+ v1_0_0.ExecutionStateChangedSeqNrIndex,
+ abihelpers.EvmWord(uint64(minSeqNum)),
+ abihelpers.EvmWord(uint64(maxSeqNum)),
+ 1,
+ )
+ require.NoError(t, err)
+ t.Logf("Have executed logs %d want %d", len(lgs), maxSeqNum-minSeqNum+1)
+ if len(lgs) == maxSeqNum-minSeqNum+1 {
+ logs = lgs
+ t.Logf("Seq Num %d-%d executed", minSeqNum, maxSeqNum)
+ return true
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "eventually has not executed seq num")
+ return logs
+}
+
+func (node *Node) ConsistentlySeqNumHasNotBeenExecuted(t *testing.T, ccipContracts *CCIPIntegrationTestHarness, offRamp common.Address, seqNum int) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Consistently(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ lgs, err := c.LogPoller().IndexedLogsTopicRange(
+ testutils.Context(t),
+ v1_0_0.ExecutionStateChangedEvent,
+ offRamp,
+ v1_0_0.ExecutionStateChangedSeqNrIndex,
+ abihelpers.EvmWord(uint64(seqNum)),
+ abihelpers.EvmWord(uint64(seqNum)),
+ 1,
+ )
+ require.NoError(t, err)
+ t.Log("Executed logs", lgs)
+ if len(lgs) == 1 {
+ log = lgs[0]
+ return true
+ }
+ return false
+ }, 10*time.Second, 1*time.Second).Should(gomega.BeFalse(), "seq number got executed")
+ return log
+}
+
+func (node *Node) AddJob(t *testing.T, spec *OCR2TaskJobSpec) {
+ specString, err := spec.String()
+ require.NoError(t, err)
+ ccipJob, err := validate.ValidatedOracleSpecToml(
+ testutils.Context(t),
+ node.App.GetConfig().OCR2(),
+ node.App.GetConfig().Insecure(),
+ specString,
+ // FIXME Ani
+ nil,
+ )
+ require.NoError(t, err)
+ err = node.App.AddJobV2(context.Background(), &ccipJob)
+ require.NoError(t, err)
+}
+
+func (node *Node) AddBootstrapJob(t *testing.T, spec *OCR2TaskJobSpec) {
+ specString, err := spec.String()
+ require.NoError(t, err)
+ ccipJob, err := ocrbootstrap.ValidatedBootstrapSpecToml(specString)
+ require.NoError(t, err)
+ err = node.App.AddJobV2(context.Background(), &ccipJob)
+ require.NoError(t, err)
+}
+
+func (node *Node) AddJobsWithSpec(t *testing.T, jobSpec *OCR2TaskJobSpec) {
+ // set node specific values
+ jobSpec.OCR2OracleSpec.OCRKeyBundleID.SetValid(node.KeyBundle.ID())
+ jobSpec.OCR2OracleSpec.TransmitterID.SetValid(node.Transmitter.Hex())
+ node.AddJob(t, jobSpec)
+}
+
+func setupNodeCCIP(
+ t *testing.T,
+ owner *bind.TransactOpts,
+ port int64,
+ dbName string,
+ sourceChain *backends.SimulatedBackend, destChain *backends.SimulatedBackend,
+ sourceChainID *big.Int, destChainID *big.Int,
+ bootstrapPeerID string,
+ bootstrapPort int64,
+) (chainlink.Application, string, common.Address, ocr2key.KeyBundle) {
+ trueRef, falseRef := true, false
+
+ // Do not want to load fixtures as they contain a dummy chainID.
+ loglevel := configv2.LogLevel(zap.DebugLevel)
+ config, db := heavyweight.FullTestDBNoFixturesV2(t, func(c *chainlink.Config, _ *chainlink.Secrets) {
+ p2pAddresses := []string{
+ fmt.Sprintf("127.0.0.1:%d", port),
+ }
+ c.Log.Level = &loglevel
+ c.Feature.UICSAKeys = &trueRef
+ c.Feature.FeedsManager = &trueRef
+ c.OCR.Enabled = &falseRef
+ c.OCR.DefaultTransactionQueueDepth = pointer.Uint32(200)
+ c.OCR2.Enabled = &trueRef
+ c.Feature.LogPoller = &trueRef
+ c.P2P.V2.Enabled = &trueRef
+
+ dur, err := config.NewDuration(500 * time.Millisecond)
+ if err != nil {
+ panic(err)
+ }
+ c.P2P.V2.DeltaDial = &dur
+
+ dur2, err := config.NewDuration(5 * time.Second)
+ if err != nil {
+ panic(err)
+ }
+
+ c.P2P.V2.DeltaReconcile = &dur2
+ c.P2P.V2.ListenAddresses = &p2pAddresses
+ c.P2P.V2.AnnounceAddresses = &p2pAddresses
+
+ c.EVM = []*v2.EVMConfig{createConfigV2Chain(sourceChainID), createConfigV2Chain(destChainID)}
+
+ if bootstrapPeerID != "" {
+ // Supply the bootstrap IP and port as a V2 peer address
+ c.P2P.V2.DefaultBootstrappers = &[]commontypes.BootstrapperLocator{
+ {
+ PeerID: bootstrapPeerID, Addrs: []string{
+ fmt.Sprintf("127.0.0.1:%d", bootstrapPort),
+ },
+ },
+ }
+ }
+ })
+
+ lggr := logger.TestLogger(t)
+ ctx := testutils.Context(t)
+
+ // The in-memory geth sim does not let you create a custom ChainID, it will always be 1337.
+ // In particular this means that if you sign an eip155 tx, the chainID used MUST be 1337
+ // and the CHAINID op code will always emit 1337. To work around this to simulate a "multichain"
+ // test, we fake different chainIDs using the wrapped sim cltest.SimulatedBackend so the RPC
+ // appears to operate on different chainIDs and we use an EthKeyStoreSim wrapper which always
+ // signs 1337 see https://github.com/smartcontractkit/chainlink-ccip/blob/a24dd436810250a458d27d8bb3fb78096afeb79c/core/services/ocr2/plugins/ccip/testhelpers/simulated_backend.go#L35
+ sourceClient := client.NewSimulatedBackendClient(t, sourceChain, sourceChainID)
+ destClient := client.NewSimulatedBackendClient(t, destChain, destChainID)
+ csaKeyStore := ksMocks.NewCSA(t)
+
+ key, err := csakey.NewV2()
+ require.NoError(t, err)
+ csaKeyStore.On("GetAll").Return([]csakey.KeyV2{key}, nil)
+ keyStore := NewKsa(db, lggr, csaKeyStore)
+
+ simEthKeyStore := testhelpers.EthKeyStoreSim{
+ ETHKS: keyStore.Eth(),
+ CSAKS: keyStore.CSA(),
+ }
+ mailMon := mailbox.NewMonitor("CCIP", lggr.Named("Mailbox"))
+ evmOpts := chainlink.EVMFactoryConfig{
+ ChainOpts: legacyevm.ChainOpts{
+ AppConfig: config,
+ GenEthClient: func(chainID *big.Int) client.Client {
+ if chainID.String() == sourceChainID.String() {
+ return sourceClient
+ } else if chainID.String() == destChainID.String() {
+ return destClient
+ }
+ t.Fatalf("invalid chain ID %v", chainID.String())
+ return nil
+ },
+ MailMon: mailMon,
+ DS: db,
+ },
+ CSAETHKeystore: simEthKeyStore,
+ }
+ loopRegistry := plugins.NewLoopRegistry(lggr.Named("LoopRegistry"), config.Tracing())
+ relayerFactory := chainlink.RelayerFactory{
+ Logger: lggr,
+ LoopRegistry: loopRegistry,
+ GRPCOpts: loop.GRPCOpts{},
+ CapabilitiesRegistry: coretypes.NewCapabilitiesRegistry(t),
+ }
+ testCtx := testutils.Context(t)
+ // evm alway enabled for backward compatibility
+ initOps := []chainlink.CoreRelayerChainInitFunc{
+ chainlink.InitEVM(testCtx, relayerFactory, evmOpts),
+ }
+
+ relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ app, err := chainlink.NewApplication(chainlink.ApplicationOpts{
+ Config: config,
+ DS: db,
+ KeyStore: keyStore,
+ RelayerChainInteroperators: relayChainInterops,
+ Logger: lggr,
+ ExternalInitiatorManager: nil,
+ CloseLogger: lggr.Sync,
+ UnrestrictedHTTPClient: &http.Client{},
+ RestrictedHTTPClient: &http.Client{},
+ AuditLogger: audit.NoopLogger,
+ MailMon: mailMon,
+ LoopRegistry: plugins.NewLoopRegistry(lggr, config.Tracing()),
+ })
+ require.NoError(t, err)
+ require.NoError(t, app.GetKeyStore().Unlock(ctx, "password"))
+ _, err = app.GetKeyStore().P2P().Create(ctx)
+ require.NoError(t, err)
+
+ p2pIDs, err := app.GetKeyStore().P2P().GetAll()
+ require.NoError(t, err)
+ require.Len(t, p2pIDs, 1)
+ peerID := p2pIDs[0].PeerID()
+
+ _, err = app.GetKeyStore().Eth().Create(testCtx, destChainID)
+ require.NoError(t, err)
+ sendingKeys, err := app.GetKeyStore().Eth().EnabledKeysForChain(testCtx, destChainID)
+ require.NoError(t, err)
+ require.Len(t, sendingKeys, 1)
+ transmitter := sendingKeys[0].Address
+ s, err := app.GetKeyStore().Eth().GetState(testCtx, sendingKeys[0].ID(), destChainID)
+ require.NoError(t, err)
+ lggr.Debug(fmt.Sprintf("Transmitter address %s chainID %s", transmitter, s.EVMChainID.String()))
+
+ // Fund the commitTransmitter address with some ETH
+ n, err := destChain.NonceAt(context.Background(), owner.From, nil)
+ require.NoError(t, err)
+
+ tx := types3.NewTransaction(n, transmitter, big.NewInt(1000000000000000000), 21000, big.NewInt(1000000000), nil)
+ signedTx, err := owner.Signer(owner.From, tx)
+ require.NoError(t, err)
+ err = destChain.SendTransaction(context.Background(), signedTx)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ kb, err := app.GetKeyStore().OCR2().Create(ctx, chaintype.EVM)
+ require.NoError(t, err)
+ return app, peerID.Raw(), transmitter, kb
+}
+
+func createConfigV2Chain(chainId *big.Int) *v2.EVMConfig {
+ // NOTE: For the executor jobs, the default of 500k is insufficient for a 3 message batch
+ defaultGasLimit := uint64(5000000)
+ tr := true
+
+ sourceC := v2.Defaults((*evmUtils.Big)(chainId))
+ sourceC.GasEstimator.LimitDefault = &defaultGasLimit
+ fixedPrice := "FixedPrice"
+ sourceC.GasEstimator.Mode = &fixedPrice
+ d, _ := config.NewDuration(100 * time.Millisecond)
+ sourceC.LogPollInterval = &d
+ fd := uint32(2)
+ sourceC.FinalityDepth = &fd
+ return &v2.EVMConfig{
+ ChainID: (*evmUtils.Big)(chainId),
+ Enabled: &tr,
+ Chain: sourceC,
+ Nodes: v2.EVMNodes{&v2.Node{}},
+ }
+}
+
+type CCIPIntegrationTestHarness struct {
+ testhelpers.CCIPContracts
+ Nodes []Node
+ Bootstrap Node
+}
+
+func SetupCCIPIntegrationTH(t *testing.T, sourceChainID, sourceChainSelector, destChainId, destChainSelector uint64) CCIPIntegrationTestHarness {
+ return CCIPIntegrationTestHarness{
+ CCIPContracts: testhelpers.SetupCCIPContracts(t, sourceChainID, sourceChainSelector, destChainId, destChainSelector),
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) CreatePricesPipeline(t *testing.T) (string, *httptest.Server, *httptest.Server) {
+ linkUSD := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(`{"UsdPerLink": "8000000000000000000"}`))
+ require.NoError(t, err)
+ }))
+ t.Cleanup(linkUSD.Close)
+
+ ethUSD := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(`{"UsdPerETH": "1700000000000000000000"}`))
+ require.NoError(t, err)
+ }))
+ t.Cleanup(ethUSD.Close)
+
+ sourceWrappedNative, err := c.Source.Router.GetWrappedNative(nil)
+ require.NoError(t, err)
+ destWrappedNative, err := c.Dest.Router.GetWrappedNative(nil)
+ require.NoError(t, err)
+ tokenPricesUSDPipeline := fmt.Sprintf(`
+// Price 1
+link [type=http method=GET url="%s"];
+link_parse [type=jsonparse path="UsdPerLink"];
+link->link_parse;
+eth [type=http method=GET url="%s"];
+eth_parse [type=jsonparse path="UsdPerETH"];
+eth->eth_parse;
+merge [type=merge left="{}" right="{\\\"%s\\\":$(link_parse), \\\"%s\\\":$(eth_parse), \\\"%s\\\":$(eth_parse)}"];`,
+ linkUSD.URL, ethUSD.URL, c.Dest.LinkToken.Address(), sourceWrappedNative, destWrappedNative)
+
+ return tokenPricesUSDPipeline, linkUSD, ethUSD
+}
+
+func (c *CCIPIntegrationTestHarness) AddAllJobs(t *testing.T, jobParams CCIPJobSpecParams) {
+ jobParams.OffRamp = c.Dest.OffRamp.Address()
+
+ commitSpec, err := jobParams.CommitJobSpec()
+ require.NoError(t, err)
+ geExecutionSpec, err := jobParams.ExecutionJobSpec()
+ require.NoError(t, err)
+ nodes := c.Nodes
+ for _, node := range nodes {
+ node.AddJobsWithSpec(t, commitSpec)
+ node.AddJobsWithSpec(t, geExecutionSpec)
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) jobSpecProposal(t *testing.T, specTemplate string, f func() (*OCR2TaskJobSpec, error), feedsManagerId int64, version int32, opts ...any) feeds2.ProposeJobArgs {
+ spec, err := f()
+ require.NoError(t, err)
+
+ args := []any{spec.OCR2OracleSpec.ContractID}
+ args = append(args, opts...)
+
+ return feeds2.ProposeJobArgs{
+ FeedsManagerID: feedsManagerId,
+ RemoteUUID: uuid.New(),
+ Multiaddrs: nil,
+ Version: version,
+ Spec: fmt.Sprintf(specTemplate, args...),
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) SetupFeedsManager(t *testing.T) {
+ ctx := testutils.Context(t)
+ for _, node := range c.Nodes {
+ f := node.App.GetFeedsService()
+
+ managers, err := f.ListManagers(ctx)
+ require.NoError(t, err)
+ if len(managers) > 0 {
+ // Use at most one feeds manager, don't register if one already exists
+ continue
+ }
+
+ secret := utils.RandomBytes32()
+ pkey, err := crypto.PublicKeyFromHex(hex.EncodeToString(secret[:]))
+ require.NoError(t, err)
+
+ m := feeds2.RegisterManagerParams{
+ Name: "CCIP",
+ URI: "http://localhost:8080",
+ PublicKey: *pkey,
+ }
+
+ connManager := feedsMocks.NewConnectionsManager(t)
+ connManager.On("Connect", mock.Anything).Maybe()
+ connManager.On("GetClient", mock.Anything).Maybe().Return(NoopFeedsClient{}, nil)
+ connManager.On("Close").Maybe().Return()
+ connManager.On("IsConnected", mock.Anything).Maybe().Return(true)
+ f.Unsafe_SetConnectionsManager(connManager)
+
+ _, err = f.RegisterManager(testutils.Context(t), m)
+ require.NoError(t, err)
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) ApproveJobSpecs(t *testing.T, jobParams CCIPJobSpecParams) {
+ ctx := testutils.Context(t)
+
+ for _, node := range c.Nodes {
+ f := node.App.GetFeedsService()
+ managers, err := f.ListManagers(ctx)
+ require.NoError(t, err)
+ require.Len(t, managers, 1, "expected exactly one feeds manager")
+
+ execSpec := c.jobSpecProposal(
+ t,
+ execSpecTemplate,
+ jobParams.ExecutionJobSpec,
+ managers[0].ID,
+ 1,
+ node.KeyBundle.ID(),
+ node.Transmitter.Hex(),
+ utils.RandomAddress().String(),
+ utils.RandomAddress().String(),
+ )
+ execId, err := f.ProposeJob(ctx, &execSpec)
+ require.NoError(t, err)
+
+ err = f.ApproveSpec(ctx, execId, true)
+ require.NoError(t, err)
+
+ var commitSpec feeds2.ProposeJobArgs
+ if jobParams.TokenPricesUSDPipeline != "" {
+ commitSpec = c.jobSpecProposal(
+ t,
+ commitSpecTemplatePipeline,
+ jobParams.CommitJobSpec,
+ managers[0].ID,
+ 2,
+ node.KeyBundle.ID(),
+ node.Transmitter.Hex(),
+ jobParams.OffRamp.String(),
+ jobParams.TokenPricesUSDPipeline,
+ )
+ } else {
+ commitSpec = c.jobSpecProposal(
+ t,
+ commitSpecTemplateDynamicPriceGetter,
+ jobParams.CommitJobSpec,
+ managers[0].ID,
+ 2,
+ node.KeyBundle.ID(),
+ node.Transmitter.Hex(),
+ jobParams.OffRamp.String(),
+ jobParams.PriceGetterConfig,
+ )
+ }
+
+ commitId, err := f.ProposeJob(ctx, &commitSpec)
+ require.NoError(t, err)
+
+ err = f.ApproveSpec(ctx, commitId, true)
+ require.NoError(t, err)
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) AllNodesHaveReqSeqNum(t *testing.T, seqNum int, onRampOpts ...common.Address) logpoller.Log {
+ var log logpoller.Log
+ nodes := c.Nodes
+ var onRamp common.Address
+ if len(onRampOpts) > 0 {
+ onRamp = onRampOpts[0]
+ } else {
+ require.NotNil(t, c.Source.OnRamp, "no onramp configured")
+ onRamp = c.Source.OnRamp.Address()
+ }
+ for _, node := range nodes {
+ log = node.EventuallyHasReqSeqNum(t, c, onRamp, seqNum)
+ }
+ return log
+}
+
+func (c *CCIPIntegrationTestHarness) AllNodesHaveExecutedSeqNums(t *testing.T, minSeqNum int, maxSeqNum int, offRampOpts ...common.Address) []logpoller.Log {
+ var logs []logpoller.Log
+ nodes := c.Nodes
+ var offRamp common.Address
+
+ if len(offRampOpts) > 0 {
+ offRamp = offRampOpts[0]
+ } else {
+ require.NotNil(t, c.Dest.OffRamp, "no offramp configured")
+ offRamp = c.Dest.OffRamp.Address()
+ }
+ for _, node := range nodes {
+ logs = node.EventuallyHasExecutedSeqNums(t, c, offRamp, minSeqNum, maxSeqNum)
+ }
+ return logs
+}
+
+func (c *CCIPIntegrationTestHarness) NoNodesHaveExecutedSeqNum(t *testing.T, seqNum int, offRampOpts ...common.Address) logpoller.Log {
+ var log logpoller.Log
+ nodes := c.Nodes
+ var offRamp common.Address
+ if len(offRampOpts) > 0 {
+ offRamp = offRampOpts[0]
+ } else {
+ require.NotNil(t, c.Dest.OffRamp, "no offramp configured")
+ offRamp = c.Dest.OffRamp.Address()
+ }
+ for _, node := range nodes {
+ log = node.ConsistentlySeqNumHasNotBeenExecuted(t, c, offRamp, seqNum)
+ }
+ return log
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallyPriceRegistryUpdated(t *testing.T, block uint64, srcSelector uint64, tokens []common.Address, sourceNative common.Address, priceRegistryOpts ...common.Address) {
+ var priceRegistry *price_registry_1_2_0.PriceRegistry
+ var err error
+ if len(priceRegistryOpts) > 0 {
+ priceRegistry, err = price_registry_1_2_0.NewPriceRegistry(priceRegistryOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.PriceRegistry, "no priceRegistry configured")
+ priceRegistry = c.Dest.PriceRegistry
+ }
+
+ g := gomega.NewGomegaWithT(t)
+ g.Eventually(func() bool {
+ it, err := priceRegistry.FilterUsdPerTokenUpdated(&bind.FilterOpts{Start: block}, tokens)
+ g.Expect(err).NotTo(gomega.HaveOccurred(), "Error filtering UsdPerTokenUpdated event")
+
+ tokensFetched := make([]common.Address, 0, len(tokens))
+ for it.Next() {
+ tokenFetched := it.Event.Token
+ tokensFetched = append(tokensFetched, tokenFetched)
+ t.Log("Token price updated", tokenFetched.String(), it.Event.Value.String(), it.Event.Timestamp.String())
+ }
+
+ for _, token := range tokens {
+ if !slices.Contains(tokensFetched, token) {
+ return false
+ }
+ }
+
+ return true
+ }, testutils.WaitTimeout(t), 10*time.Second).Should(gomega.BeTrue(), "Tokens prices has not been updated")
+
+ g.Eventually(func() bool {
+ it, err := priceRegistry.FilterUsdPerUnitGasUpdated(&bind.FilterOpts{Start: block}, []uint64{srcSelector})
+ g.Expect(err).NotTo(gomega.HaveOccurred(), "Error filtering UsdPerUnitGasUpdated event")
+ g.Expect(it.Next()).To(gomega.BeTrue(), "No UsdPerUnitGasUpdated event found")
+
+ return true
+ }, testutils.WaitTimeout(t), 10*time.Second).Should(gomega.BeTrue(), "source gas price has not been updated")
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallyCommitReportAccepted(t *testing.T, currentBlock uint64, commitStoreOpts ...common.Address) commit_store.CommitStoreCommitReport {
+ var commitStore *commit_store.CommitStore
+ var err error
+ if len(commitStoreOpts) > 0 {
+ commitStore, err = commit_store.NewCommitStore(commitStoreOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.CommitStore, "no commitStore configured")
+ commitStore = c.Dest.CommitStore
+ }
+ g := gomega.NewGomegaWithT(t)
+ var report commit_store.CommitStoreCommitReport
+ g.Eventually(func() bool {
+ it, err := commitStore.FilterReportAccepted(&bind.FilterOpts{Start: currentBlock})
+ g.Expect(err).NotTo(gomega.HaveOccurred(), "Error filtering ReportAccepted event")
+ g.Expect(it.Next()).To(gomega.BeTrue(), "No ReportAccepted event found")
+ report = it.Event.Report
+ if report.MerkleRoot != [32]byte{} {
+ t.Log("Report Accepted by commitStore")
+ return true
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "report has not been committed")
+ return report
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallyExecutionStateChangedToSuccess(t *testing.T, seqNum []uint64, blockNum uint64, offRampOpts ...common.Address) {
+ var offRamp *evm_2_evm_offramp.EVM2EVMOffRamp
+ var err error
+ if len(offRampOpts) > 0 {
+ offRamp, err = evm_2_evm_offramp.NewEVM2EVMOffRamp(offRampOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.OffRamp, "no offRamp configured")
+ offRamp = c.Dest.OffRamp
+ }
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ it, err := offRamp.FilterExecutionStateChanged(&bind.FilterOpts{Start: blockNum}, seqNum, [][32]byte{})
+ require.NoError(t, err)
+ for it.Next() {
+ if cciptypes.MessageExecutionState(it.Event.State) == cciptypes.ExecutionStateSuccess {
+ t.Logf("ExecutionStateChanged event found for seqNum %d", it.Event.SequenceNumber)
+ return true
+ }
+ }
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ return false
+ }, testutils.WaitTimeout(t), time.Second).
+ Should(gomega.BeTrue(), "ExecutionStateChanged Event")
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallyReportCommitted(t *testing.T, max int, commitStoreOpts ...common.Address) uint64 {
+ var commitStore *commit_store.CommitStore
+ var err error
+ var committedSeqNum uint64
+ if len(commitStoreOpts) > 0 {
+ commitStore, err = commit_store.NewCommitStore(commitStoreOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.CommitStore, "no commitStore configured")
+ commitStore = c.Dest.CommitStore
+ }
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ minSeqNum, err := commitStore.GetExpectedNextSequenceNumber(nil)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ t.Log("next expected seq num reported", minSeqNum)
+ committedSeqNum = minSeqNum
+ return minSeqNum > uint64(max)
+ }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue(), "report has not been committed")
+ return committedSeqNum
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallySendRequested(t *testing.T, seqNum uint64, onRampOpts ...common.Address) {
+ var onRamp *evm_2_evm_onramp.EVM2EVMOnRamp
+ var err error
+ if len(onRampOpts) > 0 {
+ onRamp, err = evm_2_evm_onramp.NewEVM2EVMOnRamp(onRampOpts[0], c.Source.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Source.OnRamp, "no onRamp configured")
+ onRamp = c.Source.OnRamp
+ }
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ it, err := onRamp.FilterCCIPSendRequested(nil)
+ require.NoError(t, err)
+ for it.Next() {
+ if it.Event.Message.SequenceNumber == seqNum {
+ t.Log("sendRequested generated for", seqNum)
+ return true
+ }
+ }
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ return false
+ }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue(), "sendRequested has not been generated")
+}
+
+func (c *CCIPIntegrationTestHarness) ConsistentlyReportNotCommitted(t *testing.T, max int, commitStoreOpts ...common.Address) {
+ var commitStore *commit_store.CommitStore
+ var err error
+ if len(commitStoreOpts) > 0 {
+ commitStore, err = commit_store.NewCommitStore(commitStoreOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.CommitStore, "no commitStore configured")
+ commitStore = c.Dest.CommitStore
+ }
+ gomega.NewGomegaWithT(t).Consistently(func() bool {
+ minSeqNum, err := commitStore.GetExpectedNextSequenceNumber(nil)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ t.Log("min seq num reported", minSeqNum)
+ return minSeqNum > uint64(max)
+ }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeFalse(), "report has been committed")
+}
+
+func (c *CCIPIntegrationTestHarness) SetupAndStartNodes(ctx context.Context, t *testing.T, bootstrapNodePort int64) (Node, []Node, int64) {
+ appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNodeCCIP(t, c.Dest.User, bootstrapNodePort,
+ "bootstrap_ccip", c.Source.Chain, c.Dest.Chain, big.NewInt(0).SetUint64(c.Source.ChainID),
+ big.NewInt(0).SetUint64(c.Dest.ChainID), "", 0)
+ var (
+ oracles []confighelper.OracleIdentityExtra
+ nodes []Node
+ )
+ err := appBootstrap.Start(ctx)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ require.NoError(t, appBootstrap.Stop())
+ })
+ bootstrapNode := Node{
+ App: appBootstrap,
+ Transmitter: bootstrapTransmitter,
+ KeyBundle: bootstrapKb,
+ }
+ // Set up the minimum 4 oracles all funded with destination ETH
+ for i := int64(0); i < 4; i++ {
+ app, peerID, transmitter, kb := setupNodeCCIP(
+ t,
+ c.Dest.User,
+ int64(freeport.GetOne(t)),
+ fmt.Sprintf("oracle_ccip%d", i),
+ c.Source.Chain,
+ c.Dest.Chain,
+ big.NewInt(0).SetUint64(c.Source.ChainID),
+ big.NewInt(0).SetUint64(c.Dest.ChainID),
+ bootstrapPeerID,
+ bootstrapNodePort,
+ )
+ nodes = append(nodes, Node{
+ App: app,
+ Transmitter: transmitter,
+ KeyBundle: kb,
+ })
+ offchainPublicKey, _ := hex.DecodeString(strings.TrimPrefix(kb.OnChainPublicKey(), "0x"))
+ oracles = append(oracles, confighelper.OracleIdentityExtra{
+ OracleIdentity: confighelper.OracleIdentity{
+ OnchainPublicKey: offchainPublicKey,
+ TransmitAccount: types4.Account(transmitter.String()),
+ OffchainPublicKey: kb.OffchainPublicKey(),
+ PeerID: peerID,
+ },
+ ConfigEncryptionPublicKey: kb.ConfigEncryptionPublicKey(),
+ })
+ err = app.Start(ctx)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ require.NoError(t, app.Stop())
+ })
+ }
+
+ c.Oracles = oracles
+ commitOnchainConfig := c.CreateDefaultCommitOnchainConfig(t)
+ commitOffchainConfig := c.CreateDefaultCommitOffchainConfig(t)
+ execOnchainConfig := c.CreateDefaultExecOnchainConfig(t)
+ execOffchainConfig := c.CreateDefaultExecOffchainConfig(t)
+
+ configBlock := c.SetupOnchainConfig(t, commitOnchainConfig, commitOffchainConfig, execOnchainConfig, execOffchainConfig)
+ c.Nodes = nodes
+ c.Bootstrap = bootstrapNode
+ return bootstrapNode, nodes, configBlock
+}
+
+func (c *CCIPIntegrationTestHarness) SetUpNodesAndJobs(t *testing.T, pricePipeline string, priceGetterConfig string, usdcAttestationAPI string) CCIPJobSpecParams {
+ // setup Jobs
+ ctx := context.Background()
+ // Starts nodes and configures them in the OCR contracts.
+ bootstrapNode, _, configBlock := c.SetupAndStartNodes(ctx, t, int64(freeport.GetOne(t)))
+
+ jobParams := c.NewCCIPJobSpecParams(pricePipeline, priceGetterConfig, configBlock, usdcAttestationAPI)
+
+ // Add the bootstrap job
+ c.Bootstrap.AddBootstrapJob(t, jobParams.BootstrapJob(c.Dest.CommitStore.Address().Hex()))
+ c.AddAllJobs(t, jobParams)
+
+ // Replay for bootstrap.
+ bc, err := bootstrapNode.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(c.Dest.ChainID, 10))
+ require.NoError(t, err)
+ require.NoError(t, bc.LogPoller().Replay(context.Background(), configBlock))
+ c.Dest.Chain.Commit()
+
+ return jobParams
+}
+func DecodeCommitOnChainConfig(encoded []byte) (ccipdata.CommitOnchainConfig, error) {
+ var onchainConfig ccipdata.CommitOnchainConfig
+ unpacked, err := abihelpers.DecodeOCR2Config(encoded)
+ if err != nil {
+ return onchainConfig, err
+ }
+ onChainCfg := unpacked.OnchainConfig
+ onchainConfig, err = abihelpers.DecodeAbiStruct[ccipdata.CommitOnchainConfig](onChainCfg)
+ if err != nil {
+ return onchainConfig, err
+ }
+ return onchainConfig, nil
+}
+
+func DecodeExecOnChainConfig(encoded []byte) (v1_5_0.ExecOnchainConfig, error) {
+ var onchainConfig v1_5_0.ExecOnchainConfig
+ unpacked, err := abihelpers.DecodeOCR2Config(encoded)
+ if err != nil {
+ return onchainConfig, errors.Wrap(err, "failed to unpack log data")
+ }
+ onChainCfg := unpacked.OnchainConfig
+ onchainConfig, err = abihelpers.DecodeAbiStruct[v1_5_0.ExecOnchainConfig](onChainCfg)
+ if err != nil {
+ return onchainConfig, err
+ }
+ return onchainConfig, nil
+}
+
+type ksa struct {
+ keystore.Master
+ csa keystore.CSA
+}
+
+func (k *ksa) CSA() keystore.CSA {
+ return k.csa
+}
+
+func NewKsa(db *sqlx.DB, lggr logger.Logger, csa keystore.CSA) *ksa {
+ return &ksa{
+ Master: keystore.New(db, clutils.FastScryptParams, lggr),
+ csa: csa,
+ }
+}
+
+type NoopFeedsClient struct{}
+
+func (n NoopFeedsClient) ApprovedJob(context.Context, *pb.ApprovedJobRequest) (*pb.ApprovedJobResponse, error) {
+ return &pb.ApprovedJobResponse{}, nil
+}
+
+func (n NoopFeedsClient) Healthcheck(context.Context, *pb.HealthcheckRequest) (*pb.HealthcheckResponse, error) {
+ return &pb.HealthcheckResponse{}, nil
+}
+
+func (n NoopFeedsClient) UpdateNode(context.Context, *pb.UpdateNodeRequest) (*pb.UpdateNodeResponse, error) {
+ return &pb.UpdateNodeResponse{}, nil
+}
+
+func (n NoopFeedsClient) RejectedJob(context.Context, *pb.RejectedJobRequest) (*pb.RejectedJobResponse, error) {
+ return &pb.RejectedJobResponse{}, nil
+}
+
+func (n NoopFeedsClient) CancelledJob(context.Context, *pb.CancelledJobRequest) (*pb.CancelledJobResponse, error) {
+ return &pb.CancelledJobResponse{}, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/jobspec.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/jobspec.go
new file mode 100644
index 00000000000..961e26d1cef
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/jobspec.go
@@ -0,0 +1,334 @@
+package integrationtesthelpers
+
+import (
+ "bytes"
+ "fmt"
+ "text/template"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/lib/pq"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay"
+ "github.com/smartcontractkit/chainlink/v2/core/store/models"
+)
+
+// OCR2TaskJobSpec represents an OCR2 job that is given to other nodes, meant to communicate with the bootstrap node,
+// and provide their answers
+type OCR2TaskJobSpec struct {
+ Name string `toml:"name"`
+ JobType string `toml:"type"`
+ MaxTaskDuration string `toml:"maxTaskDuration"` // Optional
+ ForwardingAllowed bool `toml:"forwardingAllowed"`
+ OCR2OracleSpec job.OCR2OracleSpec
+ ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node
+}
+
+// Type returns the type of the job
+func (o *OCR2TaskJobSpec) Type() string { return o.JobType }
+
+// String representation of the job
+func (o *OCR2TaskJobSpec) String() (string, error) {
+ var feedID string
+ if o.OCR2OracleSpec.FeedID != nil {
+ feedID = o.OCR2OracleSpec.FeedID.Hex()
+ }
+ specWrap := struct {
+ Name string
+ JobType string
+ MaxTaskDuration string
+ ForwardingAllowed bool
+ ContractID string
+ FeedID string
+ Relay string
+ PluginType string
+ RelayConfig map[string]interface{}
+ PluginConfig map[string]interface{}
+ P2PV2Bootstrappers []string
+ OCRKeyBundleID string
+ MonitoringEndpoint string
+ TransmitterID string
+ BlockchainTimeout time.Duration
+ TrackerSubscribeInterval time.Duration
+ TrackerPollInterval time.Duration
+ ContractConfirmations uint16
+ ObservationSource string
+ }{
+ Name: o.Name,
+ JobType: o.JobType,
+ ForwardingAllowed: o.ForwardingAllowed,
+ MaxTaskDuration: o.MaxTaskDuration,
+ ContractID: o.OCR2OracleSpec.ContractID,
+ FeedID: feedID,
+ Relay: o.OCR2OracleSpec.Relay,
+ PluginType: string(o.OCR2OracleSpec.PluginType),
+ RelayConfig: o.OCR2OracleSpec.RelayConfig,
+ PluginConfig: o.OCR2OracleSpec.PluginConfig,
+ P2PV2Bootstrappers: o.OCR2OracleSpec.P2PV2Bootstrappers,
+ OCRKeyBundleID: o.OCR2OracleSpec.OCRKeyBundleID.String,
+ MonitoringEndpoint: o.OCR2OracleSpec.MonitoringEndpoint.String,
+ TransmitterID: o.OCR2OracleSpec.TransmitterID.String,
+ BlockchainTimeout: o.OCR2OracleSpec.BlockchainTimeout.Duration(),
+ ContractConfirmations: o.OCR2OracleSpec.ContractConfigConfirmations,
+ TrackerPollInterval: o.OCR2OracleSpec.ContractConfigTrackerPollInterval.Duration(),
+ ObservationSource: o.ObservationSource,
+ }
+ ocr2TemplateString := `
+type = "{{ .JobType }}"
+name = "{{.Name}}"
+forwardingAllowed = {{.ForwardingAllowed}}
+{{if .MaxTaskDuration}}
+maxTaskDuration = "{{ .MaxTaskDuration }}" {{end}}
+{{if .PluginType}}
+pluginType = "{{ .PluginType }}" {{end}}
+relay = "{{.Relay}}"
+schemaVersion = 1
+contractID = "{{.ContractID}}"
+{{if .FeedID}}
+feedID = "{{.FeedID}}"
+{{end}}
+{{if eq .JobType "offchainreporting2" }}
+ocrKeyBundleID = "{{.OCRKeyBundleID}}" {{end}}
+{{if eq .JobType "offchainreporting2" }}
+transmitterID = "{{.TransmitterID}}" {{end}}
+{{if .BlockchainTimeout}}
+blockchainTimeout = "{{.BlockchainTimeout}}"
+{{end}}
+{{if .ContractConfirmations}}
+contractConfigConfirmations = {{.ContractConfirmations}}
+{{end}}
+{{if .TrackerPollInterval}}
+contractConfigTrackerPollInterval = "{{.TrackerPollInterval}}"
+{{end}}
+{{if .TrackerSubscribeInterval}}
+contractConfigTrackerSubscribeInterval = "{{.TrackerSubscribeInterval}}"
+{{end}}
+{{if .P2PV2Bootstrappers}}
+p2pv2Bootstrappers = [{{range .P2PV2Bootstrappers}}"{{.}}",{{end}}]{{end}}
+{{if .MonitoringEndpoint}}
+monitoringEndpoint = "{{.MonitoringEndpoint}}" {{end}}
+{{if .ObservationSource}}
+observationSource = """
+{{.ObservationSource}}
+"""{{end}}
+{{if eq .JobType "offchainreporting2" }}
+[pluginConfig]{{range $key, $value := .PluginConfig}}
+{{$key}} = {{$value}}{{end}}
+{{end}}
+[relayConfig]{{range $key, $value := .RelayConfig}}
+{{$key}} = {{$value}}{{end}}
+`
+ return MarshallTemplate(specWrap, "OCR2 Job", ocr2TemplateString)
+}
+
+// MarshallTemplate Helper to marshall templates
+func MarshallTemplate(jobSpec interface{}, name, templateString string) (string, error) {
+ var buf bytes.Buffer
+ tmpl, err := template.New(name).Parse(templateString)
+ if err != nil {
+ return "", err
+ }
+ err = tmpl.Execute(&buf, jobSpec)
+ if err != nil {
+ return "", err
+ }
+ return buf.String(), err
+}
+
+type JobType string
+
+const (
+ Commit JobType = "commit"
+ Execution JobType = "exec"
+ Boostrap JobType = "bootstrap"
+)
+
+func JobName(jobType JobType, source string, destination, version string) string {
+ if version != "" {
+ return fmt.Sprintf("ccip-%s-%s-%s-%s", jobType, source, destination, version)
+ }
+ return fmt.Sprintf("ccip-%s-%s-%s", jobType, source, destination)
+}
+
+type CCIPJobSpecParams struct {
+ Name string
+ Version string
+ OffRamp common.Address
+ CommitStore common.Address
+ SourceChainName string
+ DestChainName string
+ DestEvmChainId uint64
+ TokenPricesUSDPipeline string
+ PriceGetterConfig string
+ SourceStartBlock uint64
+ DestStartBlock uint64
+ USDCAttestationAPI string
+ USDCConfig *config.USDCConfig
+ P2PV2Bootstrappers pq.StringArray
+}
+
+func (params CCIPJobSpecParams) Validate() error {
+ if params.CommitStore == common.HexToAddress("0x0") {
+ return fmt.Errorf("must set commit store address")
+ }
+ return nil
+}
+
+func (params CCIPJobSpecParams) ValidateCommitJobSpec() error {
+ commonErr := params.Validate()
+ if commonErr != nil {
+ return commonErr
+ }
+ if params.OffRamp == common.HexToAddress("0x0") {
+ return fmt.Errorf("OffRamp cannot be empty for execution job")
+ }
+ // Validate token prices config
+ // NB: only validate the dynamic price getter config if present since we could also be using the pipeline instead.
+ // NB: make this test mandatory once we switch to dynamic price getter only.
+ if params.PriceGetterConfig != "" {
+ if _, err := pricegetter.NewDynamicPriceGetterConfig(params.PriceGetterConfig); err != nil {
+ return fmt.Errorf("invalid price getter config: %w", err)
+ }
+ }
+ return nil
+}
+
+func (params CCIPJobSpecParams) ValidateExecJobSpec() error {
+ commonErr := params.Validate()
+ if commonErr != nil {
+ return commonErr
+ }
+ if params.OffRamp == common.HexToAddress("0x0") {
+ return fmt.Errorf("OffRamp cannot be empty for execution job")
+ }
+ return nil
+}
+
+// CommitJobSpec generates template for CCIP-relay job spec.
+// OCRKeyBundleID,TransmitterID need to be set from the calling function
+func (params CCIPJobSpecParams) CommitJobSpec() (*OCR2TaskJobSpec, error) {
+ err := params.ValidateCommitJobSpec()
+ if err != nil {
+ return nil, fmt.Errorf("invalid job spec params: %w", err)
+ }
+
+ pluginConfig := map[string]interface{}{
+ "offRamp": fmt.Sprintf(`"%s"`, params.OffRamp.Hex()),
+ }
+ if params.TokenPricesUSDPipeline != "" {
+ pluginConfig["tokenPricesUSDPipeline"] = fmt.Sprintf(`"""
+%s
+"""`, params.TokenPricesUSDPipeline)
+ }
+ if params.PriceGetterConfig != "" {
+ pluginConfig["priceGetterConfig"] = fmt.Sprintf(`"""
+%s
+"""`, params.PriceGetterConfig)
+ }
+
+ ocrSpec := job.OCR2OracleSpec{
+ Relay: relay.NetworkEVM,
+ PluginType: types.CCIPCommit,
+ ContractID: params.CommitStore.Hex(),
+ ContractConfigConfirmations: 1,
+ ContractConfigTrackerPollInterval: models.Interval(20 * time.Second),
+ P2PV2Bootstrappers: params.P2PV2Bootstrappers,
+ PluginConfig: pluginConfig,
+ RelayConfig: map[string]interface{}{
+ "chainID": params.DestEvmChainId,
+ },
+ }
+ if params.DestStartBlock > 0 {
+ ocrSpec.PluginConfig["destStartBlock"] = params.DestStartBlock
+ }
+ if params.SourceStartBlock > 0 {
+ ocrSpec.PluginConfig["sourceStartBlock"] = params.SourceStartBlock
+ }
+ return &OCR2TaskJobSpec{
+ OCR2OracleSpec: ocrSpec,
+ JobType: "offchainreporting2",
+ Name: JobName(Commit, params.SourceChainName, params.DestChainName, params.Version),
+ }, nil
+}
+
+// ExecutionJobSpec generates template for CCIP-execution job spec.
+// OCRKeyBundleID,TransmitterID need to be set from the calling function
+func (params CCIPJobSpecParams) ExecutionJobSpec() (*OCR2TaskJobSpec, error) {
+ err := params.ValidateExecJobSpec()
+ if err != nil {
+ return nil, err
+ }
+ ocrSpec := job.OCR2OracleSpec{
+ Relay: relay.NetworkEVM,
+ PluginType: types.CCIPExecution,
+ ContractID: params.OffRamp.Hex(),
+ ContractConfigConfirmations: 1,
+ ContractConfigTrackerPollInterval: models.Interval(20 * time.Second),
+
+ P2PV2Bootstrappers: params.P2PV2Bootstrappers,
+ PluginConfig: map[string]interface{}{},
+ RelayConfig: map[string]interface{}{
+ "chainID": params.DestEvmChainId,
+ },
+ }
+ if params.DestStartBlock > 0 {
+ ocrSpec.PluginConfig["destStartBlock"] = params.DestStartBlock
+ }
+ if params.SourceStartBlock > 0 {
+ ocrSpec.PluginConfig["sourceStartBlock"] = params.SourceStartBlock
+ }
+ if params.USDCAttestationAPI != "" {
+ ocrSpec.PluginConfig["USDCConfig.AttestationAPI"] = fmt.Sprintf("\"%s\"", params.USDCAttestationAPI)
+ ocrSpec.PluginConfig["USDCConfig.SourceTokenAddress"] = fmt.Sprintf("\"%s\"", utils.RandomAddress().String())
+ ocrSpec.PluginConfig["USDCConfig.SourceMessageTransmitterAddress"] = fmt.Sprintf("\"%s\"", utils.RandomAddress().String())
+ ocrSpec.PluginConfig["USDCConfig.AttestationAPITimeoutSeconds"] = 5
+ }
+ if params.USDCConfig != nil {
+ ocrSpec.PluginConfig["USDCConfig.AttestationAPI"] = fmt.Sprintf(`"%s"`, params.USDCConfig.AttestationAPI)
+ ocrSpec.PluginConfig["USDCConfig.SourceTokenAddress"] = fmt.Sprintf(`"%s"`, params.USDCConfig.SourceTokenAddress)
+ ocrSpec.PluginConfig["USDCConfig.SourceMessageTransmitterAddress"] = fmt.Sprintf(`"%s"`, params.USDCConfig.SourceMessageTransmitterAddress)
+ ocrSpec.PluginConfig["USDCConfig.AttestationAPITimeoutSeconds"] = params.USDCConfig.AttestationAPITimeoutSeconds
+ }
+ return &OCR2TaskJobSpec{
+ OCR2OracleSpec: ocrSpec,
+ JobType: "offchainreporting2",
+ Name: JobName(Execution, params.SourceChainName, params.DestChainName, params.Version),
+ }, err
+}
+
+func (params CCIPJobSpecParams) BootstrapJob(contractID string) *OCR2TaskJobSpec {
+ bootstrapSpec := job.OCR2OracleSpec{
+ ContractID: contractID,
+ Relay: relay.NetworkEVM,
+ ContractConfigConfirmations: 1,
+ ContractConfigTrackerPollInterval: models.Interval(20 * time.Second),
+ RelayConfig: map[string]interface{}{
+ "chainID": params.DestEvmChainId,
+ },
+ }
+ return &OCR2TaskJobSpec{
+ Name: fmt.Sprintf("%s-%s", Boostrap, params.DestChainName),
+ JobType: "bootstrap",
+ OCR2OracleSpec: bootstrapSpec,
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) NewCCIPJobSpecParams(tokenPricesUSDPipeline string, priceGetterConfig string, configBlock int64, usdcAttestationAPI string) CCIPJobSpecParams {
+ return CCIPJobSpecParams{
+ CommitStore: c.Dest.CommitStore.Address(),
+ OffRamp: c.Dest.OffRamp.Address(),
+ DestEvmChainId: c.Dest.ChainID,
+ SourceChainName: "SimulatedSource",
+ DestChainName: "SimulatedDest",
+ TokenPricesUSDPipeline: tokenPricesUSDPipeline,
+ PriceGetterConfig: priceGetterConfig,
+ DestStartBlock: uint64(configBlock),
+ USDCAttestationAPI: usdcAttestationAPI,
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/offramp.go b/core/services/ocr2/plugins/ccip/testhelpers/offramp.go
new file mode 100644
index 00000000000..d10e693325d
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/offramp.go
@@ -0,0 +1,119 @@
+package testhelpers
+
+import (
+ "sync"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ mock_contracts "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+)
+
+type FakeOffRamp struct {
+ *mock_contracts.EVM2EVMOffRampInterface
+
+ rateLimiterState cciptypes.TokenBucketRateLimit
+ senderNonces map[common.Address]uint64
+ tokenToPool map[common.Address]common.Address
+ dynamicConfig evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig
+ sourceToDestTokens map[common.Address]common.Address
+
+ mu sync.RWMutex
+}
+
+func NewFakeOffRamp(t *testing.T) (*FakeOffRamp, common.Address) {
+ addr := utils.RandomAddress()
+ mockOffRamp := mock_contracts.NewEVM2EVMOffRampInterface(t)
+ mockOffRamp.On("Address").Return(addr).Maybe()
+
+ offRamp := &FakeOffRamp{EVM2EVMOffRampInterface: mockOffRamp}
+ return offRamp, addr
+}
+
+func (o *FakeOffRamp) CurrentRateLimiterState(opts *bind.CallOpts) (cciptypes.TokenBucketRateLimit, error) {
+ return getOffRampVal(o, func(o *FakeOffRamp) (cciptypes.TokenBucketRateLimit, error) { return o.rateLimiterState, nil })
+}
+
+func (o *FakeOffRamp) SetRateLimiterState(state cciptypes.TokenBucketRateLimit) {
+ setOffRampVal(o, func(o *FakeOffRamp) { o.rateLimiterState = state })
+}
+
+func (o *FakeOffRamp) GetSenderNonce(opts *bind.CallOpts, sender common.Address) (uint64, error) {
+ return getOffRampVal(o, func(o *FakeOffRamp) (uint64, error) { return o.senderNonces[sender], nil })
+}
+
+func (o *FakeOffRamp) SetSenderNonces(senderNonces map[cciptypes.Address]uint64) {
+ evmSenderNonces := make(map[common.Address]uint64)
+ for k, v := range senderNonces {
+ addrs, _ := ccipcalc.GenericAddrsToEvm(k)
+ evmSenderNonces[addrs[0]] = v
+ }
+
+ setOffRampVal(o, func(o *FakeOffRamp) { o.senderNonces = evmSenderNonces })
+}
+
+func (o *FakeOffRamp) GetPoolByDestToken(opts *bind.CallOpts, destToken common.Address) (common.Address, error) {
+ return getOffRampVal(o, func(o *FakeOffRamp) (common.Address, error) {
+ addr, exists := o.tokenToPool[destToken]
+ if !exists {
+ return common.Address{}, errors.New("not found")
+ }
+ return addr, nil
+ })
+}
+
+func (o *FakeOffRamp) SetTokenPools(tokenToPool map[common.Address]common.Address) {
+ setOffRampVal(o, func(o *FakeOffRamp) { o.tokenToPool = tokenToPool })
+}
+
+func (o *FakeOffRamp) GetDynamicConfig(opts *bind.CallOpts) (evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig, error) {
+ return getOffRampVal(o, func(o *FakeOffRamp) (evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig, error) {
+ return o.dynamicConfig, nil
+ })
+}
+
+func (o *FakeOffRamp) SetDynamicConfig(cfg evm_2_evm_offramp.EVM2EVMOffRampDynamicConfig) {
+ setOffRampVal(o, func(o *FakeOffRamp) { o.dynamicConfig = cfg })
+}
+
+func (o *FakeOffRamp) SetSourceToDestTokens(m map[common.Address]common.Address) {
+ setOffRampVal(o, func(o *FakeOffRamp) { o.sourceToDestTokens = m })
+}
+
+func (o *FakeOffRamp) GetSupportedTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ return getOffRampVal(o, func(o *FakeOffRamp) ([]common.Address, error) {
+ tks := make([]common.Address, 0, len(o.sourceToDestTokens))
+ for tk := range o.sourceToDestTokens {
+ tks = append(tks, tk)
+ }
+ return tks, nil
+ })
+}
+
+func (o *FakeOffRamp) GetDestinationTokens(opts *bind.CallOpts) ([]common.Address, error) {
+ return getOffRampVal(o, func(o *FakeOffRamp) ([]common.Address, error) {
+ tokens := make([]common.Address, 0, len(o.sourceToDestTokens))
+ for _, dst := range o.sourceToDestTokens {
+ tokens = append(tokens, dst)
+ }
+ return tokens, nil
+ })
+}
+
+func getOffRampVal[T any](o *FakeOffRamp, getter func(o *FakeOffRamp) (T, error)) (T, error) {
+ o.mu.RLock()
+ defer o.mu.RUnlock()
+ return getter(o)
+}
+
+func setOffRampVal(o *FakeOffRamp, setter func(o *FakeOffRamp)) {
+ o.mu.Lock()
+ defer o.mu.Unlock()
+ setter(o)
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/simulated_backend.go b/core/services/ocr2/plugins/ccip/testhelpers/simulated_backend.go
new file mode 100644
index 00000000000..ea91362aaae
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/simulated_backend.go
@@ -0,0 +1,75 @@
+package testhelpers
+
+import (
+ "context"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core"
+ ethtypes "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth/ethconfig"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore"
+)
+
+// FirstBlockAge is used to compute first block's timestamp in SimulatedBackend (time.Now() - FirstBlockAge)
+const FirstBlockAge = 24 * time.Hour
+
+func SetupChain(t *testing.T) (*backends.SimulatedBackend, *bind.TransactOpts) {
+ key, err := crypto.GenerateKey()
+ require.NoError(t, err)
+ user, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
+ require.NoError(t, err)
+ chain := backends.NewSimulatedBackend(core.GenesisAlloc{
+ user.From: {Balance: new(big.Int).Mul(big.NewInt(1000), big.NewInt(1e18))}},
+ ethconfig.Defaults.Miner.GasCeil)
+ // CCIP relies on block timestamps, but SimulatedBackend uses by default clock starting from 1970-01-01
+ // This trick is used to move the clock closer to the current time. We set first block to be X hours ago.
+ // Tests create plenty of transactions so this number can't be too low, every new block mined will tick the clock,
+ // if you mine more than "X hours" transactions, SimulatedBackend will panic because generated timestamps will be in the future.
+ // IMPORTANT: Any adjustments to FirstBlockAge will automatically update PermissionLessExecutionThresholdSeconds in tests
+ blockTime := time.UnixMilli(int64(chain.Blockchain().CurrentHeader().Time))
+ err = chain.AdjustTime(time.Since(blockTime) - FirstBlockAge)
+ require.NoError(t, err)
+ chain.Commit()
+ return chain, user
+}
+
+type EthKeyStoreSim struct {
+ ETHKS keystore.Eth
+ CSAKS keystore.CSA
+}
+
+func (ks EthKeyStoreSim) CSA() keystore.CSA {
+ return ks.CSAKS
+}
+
+func (ks EthKeyStoreSim) Eth() keystore.Eth {
+ return ks.ETHKS
+}
+
+func (ks EthKeyStoreSim) SignTx(address common.Address, tx *ethtypes.Transaction, chainID *big.Int) (*ethtypes.Transaction, error) {
+ if chainID.String() == "1000" {
+ // A terrible hack, just for the multichain test. All simulation clients run on chainID 1337.
+ // We let the DestChainSelector actually use 1337 to make sure the offchainConfig digests are properly generated.
+ return ks.ETHKS.SignTx(context.Background(), address, tx, big.NewInt(1337))
+ }
+ return ks.ETHKS.SignTx(context.Background(), address, tx, chainID)
+}
+
+var _ keystore.Eth = EthKeyStoreSim{}.ETHKS
+
+func ConfirmTxs(t *testing.T, txs []*ethtypes.Transaction, chain *backends.SimulatedBackend) {
+ chain.Commit()
+ for _, tx := range txs {
+ rec, err := bind.WaitMined(context.Background(), chain, tx)
+ require.NoError(t, err)
+ require.Equal(t, uint64(1), rec.Status)
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/structfields.go b/core/services/ocr2/plugins/ccip/testhelpers/structfields.go
new file mode 100644
index 00000000000..88e0fffa672
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/structfields.go
@@ -0,0 +1,44 @@
+package testhelpers
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+// FindStructFieldsOfCertainType recursively iterates over struct fields and returns all the fields of the provided type.
+func FindStructFieldsOfCertainType(targetType string, v any) []string {
+ typesAndFields := TypesAndFields("", reflect.ValueOf(v))
+ results := make([]string, 0)
+ for _, field := range typesAndFields {
+ if strings.Contains(field, targetType) {
+ results = append(results, field)
+ }
+ }
+ return results
+}
+
+// TypesAndFields will find and return all the fields and their types of the provided value.
+// NOTE: This is not intended for production use, it's a helper method for tests.
+func TypesAndFields(prefix string, v reflect.Value) []string {
+ results := make([]string, 0)
+
+ s := v
+ typeOfT := s.Type()
+ for i := 0; i < s.NumField(); i++ {
+ f := s.Field(i)
+ typeAndName := fmt.Sprintf("%s%s %v", prefix, f.Type(), typeOfT.Field(i).Name)
+ results = append(results, typeAndName)
+
+ if f.Kind().String() == "ptr" {
+ results = append(results, TypesAndFields(typeOfT.Field(i).Name, f.Elem())...)
+ }
+
+ if f.Kind().String() == "struct" {
+ x1 := reflect.ValueOf(f.Interface())
+ results = append(results, TypesAndFields(typeOfT.Field(i).Name, x1)...)
+ }
+ }
+
+ return results
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/ccip_contracts_1_4_0.go b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/ccip_contracts_1_4_0.go
new file mode 100644
index 00000000000..4ea5bb18d7e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/ccip_contracts_1_4_0.go
@@ -0,0 +1,1585 @@
+package testhelpers_1_4_0
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog/log"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2/confighelper"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2/types"
+ ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/hashutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/merklemulti"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_proxy_contract"
+ burn_mint_token_pool "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_2_0"
+ evm_2_evm_offramp "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ evm_2_evm_onramp "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool_1_0_0"
+ lock_release_token_pool "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+)
+
+var (
+ // Source
+ SourcePool = "source Link pool"
+ SourcePriceRegistry = "source PriceRegistry"
+ OnRamp = "onramp"
+ OnRampNative = "onramp-native"
+ SourceRouter = "source router"
+
+ // Dest
+ OffRamp = "offramp"
+ DestPool = "dest Link pool"
+
+ Receiver = "receiver"
+ Sender = "sender"
+ Link = func(amount int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(amount)) }
+ HundredLink = Link(100)
+ LinkUSDValue = func(amount int64) *big.Int { return new(big.Int).Mul(big.NewInt(1e18), big.NewInt(amount)) }
+ SourceChainID = uint64(1000)
+ SourceChainSelector = uint64(11787463284727550157)
+ DestChainID = uint64(1337)
+ DestChainSelector = uint64(3379446385462418246)
+)
+
+// Backwards compat, in principle these statuses are version dependent
+// TODO: Adjust integration tests to be version agnostic using readers
+var (
+ ExecutionStateSuccess = MessageExecutionState(cciptypes.ExecutionStateSuccess)
+ ExecutionStateFailure = MessageExecutionState(cciptypes.ExecutionStateFailure)
+)
+
+type MessageExecutionState cciptypes.MessageExecutionState
+type CommitOffchainConfig struct {
+ v1_2_0.JSONCommitOffchainConfig
+}
+
+func (c CommitOffchainConfig) Encode() ([]byte, error) {
+ return ccipconfig.EncodeOffchainConfig(c.JSONCommitOffchainConfig)
+}
+
+func NewCommitOffchainConfig(
+ GasPriceHeartBeat config.Duration,
+ DAGasPriceDeviationPPB uint32,
+ ExecGasPriceDeviationPPB uint32,
+ TokenPriceHeartBeat config.Duration,
+ TokenPriceDeviationPPB uint32,
+ InflightCacheExpiry config.Duration) CommitOffchainConfig {
+ return CommitOffchainConfig{v1_2_0.JSONCommitOffchainConfig{
+ GasPriceHeartBeat: GasPriceHeartBeat,
+ DAGasPriceDeviationPPB: DAGasPriceDeviationPPB,
+ ExecGasPriceDeviationPPB: ExecGasPriceDeviationPPB,
+ TokenPriceHeartBeat: TokenPriceHeartBeat,
+ TokenPriceDeviationPPB: TokenPriceDeviationPPB,
+ InflightCacheExpiry: InflightCacheExpiry,
+ }}
+}
+
+type CommitOnchainConfig struct {
+ ccipdata.CommitOnchainConfig
+}
+
+func NewCommitOnchainConfig(
+ PriceRegistry common.Address,
+) CommitOnchainConfig {
+ return CommitOnchainConfig{ccipdata.CommitOnchainConfig{
+ PriceRegistry: PriceRegistry,
+ }}
+}
+
+type ExecOnchainConfig struct {
+ v1_2_0.ExecOnchainConfig
+}
+
+func NewExecOnchainConfig(
+ PermissionLessExecutionThresholdSeconds uint32,
+ Router common.Address,
+ PriceRegistry common.Address,
+ MaxNumberOfTokensPerMsg uint16,
+ MaxDataBytes uint32,
+ MaxPoolReleaseOrMintGas uint32,
+) ExecOnchainConfig {
+ return ExecOnchainConfig{v1_2_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: PermissionLessExecutionThresholdSeconds,
+ Router: Router,
+ PriceRegistry: PriceRegistry,
+ MaxNumberOfTokensPerMsg: MaxNumberOfTokensPerMsg,
+ MaxDataBytes: MaxDataBytes,
+ MaxPoolReleaseOrMintGas: MaxPoolReleaseOrMintGas,
+ }}
+}
+
+type ExecOffchainConfig struct {
+ v1_2_0.JSONExecOffchainConfig
+}
+
+func (c ExecOffchainConfig) Encode() ([]byte, error) {
+ return ccipconfig.EncodeOffchainConfig(c.JSONExecOffchainConfig)
+}
+
+func NewExecOffchainConfig(
+ DestOptimisticConfirmations uint32,
+ BatchGasLimit uint32,
+ RelativeBoostPerWaitHour float64,
+ InflightCacheExpiry config.Duration,
+ RootSnoozeTime config.Duration,
+) ExecOffchainConfig {
+ return ExecOffchainConfig{v1_2_0.JSONExecOffchainConfig{
+ DestOptimisticConfirmations: DestOptimisticConfirmations,
+ BatchGasLimit: BatchGasLimit,
+ RelativeBoostPerWaitHour: RelativeBoostPerWaitHour,
+ InflightCacheExpiry: InflightCacheExpiry,
+ RootSnoozeTime: RootSnoozeTime,
+ }}
+}
+
+type MaybeRevertReceiver struct {
+ Receiver *maybe_revert_message_receiver.MaybeRevertMessageReceiver
+ Strict bool
+}
+
+type Common struct {
+ ChainID uint64
+ ChainSelector uint64
+ User *bind.TransactOpts
+ Chain *backends.SimulatedBackend
+ LinkToken *link_token_interface.LinkToken
+ LinkTokenPool *lock_release_token_pool.LockReleaseTokenPool
+ CustomToken *link_token_interface.LinkToken
+ WrappedNative *weth9.WETH9
+ WrappedNativePool *lock_release_token_pool_1_0_0.LockReleaseTokenPool
+ ARM *mock_arm_contract.MockARMContract
+ ARMProxy *arm_proxy_contract.ARMProxyContract
+ PriceRegistry *price_registry_1_2_0.PriceRegistry
+}
+
+type SourceChain struct {
+ Common
+ Router *router.Router
+ OnRamp *evm_2_evm_onramp.EVM2EVMOnRamp
+}
+
+type DestinationChain struct {
+ Common
+
+ CommitStore *commit_store_1_2_0.CommitStore
+ Router *router.Router
+ OffRamp *evm_2_evm_offramp.EVM2EVMOffRamp
+ Receivers []MaybeRevertReceiver
+}
+
+type OCR2Config struct {
+ Signers []common.Address
+ Transmitters []common.Address
+ F uint8
+ OnchainConfig []byte
+ OffchainConfigVersion uint64
+ OffchainConfig []byte
+}
+
+type BalanceAssertion struct {
+ Name string
+ Address common.Address
+ Expected string
+ Getter func(t *testing.T, addr common.Address) *big.Int
+ Within string
+}
+
+type BalanceReq struct {
+ Name string
+ Addr common.Address
+ Getter func(t *testing.T, addr common.Address) *big.Int
+}
+
+type CCIPContracts struct {
+ Source SourceChain
+ Dest DestinationChain
+ Oracles []confighelper.OracleIdentityExtra
+
+ commitOCRConfig, execOCRConfig *OCR2Config
+}
+
+func (c *CCIPContracts) DeployNewOffRamp(t *testing.T) {
+ prevOffRamp := common.HexToAddress("")
+ if c.Dest.OffRamp != nil {
+ prevOffRamp = c.Dest.OffRamp.Address()
+ }
+ offRampAddress, _, _, err := evm_2_evm_offramp.DeployEVM2EVMOffRamp(
+ c.Dest.User,
+ c.Dest.Chain,
+ evm_2_evm_offramp.EVM2EVMOffRampStaticConfig{
+ CommitStore: c.Dest.CommitStore.Address(),
+ ChainSelector: c.Dest.ChainSelector,
+ SourceChainSelector: c.Source.ChainSelector,
+ OnRamp: c.Source.OnRamp.Address(),
+ PrevOffRamp: prevOffRamp,
+ ArmProxy: c.Dest.ARMProxy.Address(),
+ },
+ []common.Address{c.Source.LinkToken.Address()}, // source tokens
+ []common.Address{c.Dest.LinkTokenPool.Address()}, // pools
+ evm_2_evm_offramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: LinkUSDValue(100),
+ Rate: LinkUSDValue(1),
+ },
+ )
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+
+ c.Dest.OffRamp, err = evm_2_evm_offramp.NewEVM2EVMOffRamp(offRampAddress, c.Dest.Chain)
+ require.NoError(t, err)
+
+ c.Dest.Chain.Commit()
+ c.Source.Chain.Commit()
+}
+
+func (c *CCIPContracts) EnableOffRamp(t *testing.T) {
+ _, err := c.Dest.Router.ApplyRampUpdates(c.Dest.User, nil, nil, []router.RouterOffRamp{{SourceChainSelector: SourceChainSelector, OffRamp: c.Dest.OffRamp.Address()}})
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+
+ onChainConfig := c.CreateDefaultExecOnchainConfig(t)
+ offChainConfig := c.CreateDefaultExecOffchainConfig(t)
+
+ c.SetupExecOCR2Config(t, onChainConfig, offChainConfig)
+}
+
+func (c *CCIPContracts) EnableCommitStore(t *testing.T) {
+ onChainConfig := c.CreateDefaultCommitOnchainConfig(t)
+ offChainConfig := c.CreateDefaultCommitOffchainConfig(t)
+
+ c.SetupCommitOCR2Config(t, onChainConfig, offChainConfig)
+
+ _, err := c.Dest.PriceRegistry.ApplyPriceUpdatersUpdates(c.Dest.User, []common.Address{c.Dest.CommitStore.Address()}, []common.Address{})
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) DeployNewOnRamp(t *testing.T) {
+ t.Log("Deploying new onRamp")
+ // find the last onRamp
+ prevOnRamp := common.HexToAddress("")
+ if c.Source.OnRamp != nil {
+ prevOnRamp = c.Source.OnRamp.Address()
+ }
+ onRampAddress, _, _, err := evm_2_evm_onramp.DeployEVM2EVMOnRamp(
+ c.Source.User, // user
+ c.Source.Chain, // client
+ evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{
+ LinkToken: c.Source.LinkToken.Address(),
+ ChainSelector: c.Source.ChainSelector,
+ DestChainSelector: c.Dest.ChainSelector,
+ DefaultTxGasLimit: 200_000,
+ MaxNopFeesJuels: big.NewInt(0).Mul(big.NewInt(100_000_000), big.NewInt(1e18)),
+ PrevOnRamp: prevOnRamp,
+ ArmProxy: c.Source.ARM.Address(), // ARM
+ },
+ evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig{
+ Router: c.Source.Router.Address(),
+ MaxNumberOfTokensPerMsg: 5,
+ DestGasOverhead: 350_000,
+ DestGasPerPayloadByte: 16,
+ DestDataAvailabilityOverheadGas: 33_596,
+ DestGasPerDataAvailabilityByte: 16,
+ DestDataAvailabilityMultiplierBps: 6840, // 0.684
+ PriceRegistry: c.Source.PriceRegistry.Address(),
+ MaxDataBytes: 1e5,
+ MaxPerMsgGasLimit: 4_000_000,
+ },
+ []evm_2_evm_onramp.InternalPoolUpdate{
+ {
+ Token: c.Source.LinkToken.Address(),
+ Pool: c.Source.LinkTokenPool.Address(),
+ },
+ },
+ evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: LinkUSDValue(100),
+ Rate: LinkUSDValue(1),
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: c.Source.LinkToken.Address(),
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: 1e18,
+ PremiumMultiplierWeiPerEth: 9e17,
+ Enabled: true,
+ },
+ {
+ Token: c.Source.WrappedNative.Address(),
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: 1e18,
+ PremiumMultiplierWeiPerEth: 1e18,
+ Enabled: true,
+ },
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: c.Source.LinkToken.Address(),
+ MinFeeUSDCents: 50, // $0.5
+ MaxFeeUSDCents: 1_000_000_00, // $ 1 million
+ DeciBps: 5_0, // 5 bps
+ DestGasOverhead: 34_000,
+ DestBytesOverhead: 32,
+ },
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{},
+ )
+
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ c.Source.OnRamp, err = evm_2_evm_onramp.NewEVM2EVMOnRamp(onRampAddress, c.Source.Chain)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) EnableOnRamp(t *testing.T) {
+ t.Log("Setting onRamp on source router")
+ _, err := c.Source.Router.ApplyRampUpdates(c.Source.User, []router.RouterOnRamp{{DestChainSelector: c.Dest.ChainSelector, OnRamp: c.Source.OnRamp.Address()}}, nil, nil)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) DeployNewCommitStore(t *testing.T) {
+ commitStoreAddress, _, _, err := commit_store_1_2_0.DeployCommitStore(
+ c.Dest.User, // user
+ c.Dest.Chain, // client
+ commit_store_1_2_0.CommitStoreStaticConfig{
+ ChainSelector: c.Dest.ChainSelector,
+ SourceChainSelector: c.Source.ChainSelector,
+ OnRamp: c.Source.OnRamp.Address(),
+ ArmProxy: c.Dest.ARMProxy.Address(),
+ },
+ )
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+ // since CommitStoreHelper derives from CommitStore, it's safe to instantiate both on same address
+ c.Dest.CommitStore, err = commit_store_1_2_0.NewCommitStore(commitStoreAddress, c.Dest.Chain)
+ require.NoError(t, err)
+}
+
+func (c *CCIPContracts) DeployNewPriceRegistry(t *testing.T) {
+ t.Log("Deploying new Price Registry")
+ destPricesAddress, _, _, err := price_registry_1_2_0.DeployPriceRegistry(
+ c.Dest.User,
+ c.Dest.Chain,
+ []common.Address{c.Dest.CommitStore.Address()},
+ []common.Address{c.Dest.LinkToken.Address()},
+ 60*60*24*14, // two weeks
+ )
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ c.Dest.PriceRegistry, err = price_registry_1_2_0.NewPriceRegistry(destPricesAddress, c.Dest.Chain)
+ require.NoError(t, err)
+
+ priceUpdates := price_registry_1_2_0.InternalPriceUpdates{
+ TokenPriceUpdates: []price_registry_1_2_0.InternalTokenPriceUpdate{
+ {
+ SourceToken: c.Dest.LinkToken.Address(),
+ UsdPerToken: big.NewInt(8e18), // 8usd
+ },
+ {
+ SourceToken: c.Dest.WrappedNative.Address(),
+ UsdPerToken: big.NewInt(1e18), // 1usd
+ },
+ },
+ GasPriceUpdates: []price_registry_1_2_0.InternalGasPriceUpdate{
+ {
+ DestChainSelector: c.Source.ChainSelector,
+ UsdPerUnitGas: big.NewInt(2000e9), // $2000 per eth * 1gwei = 2000e9
+ },
+ },
+ }
+ _, err = c.Dest.PriceRegistry.UpdatePrices(c.Dest.User, priceUpdates)
+ require.NoError(t, err)
+
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+
+ t.Logf("New Price Registry deployed at %s", destPricesAddress.String())
+}
+
+func (c *CCIPContracts) SetNopsOnRamp(t *testing.T, nopsAndWeights []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight) {
+ tx, err := c.Source.OnRamp.SetNops(c.Source.User, nopsAndWeights)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ _, err = bind.WaitMined(context.Background(), c.Source.Chain, tx)
+ require.NoError(t, err)
+}
+
+func (c *CCIPContracts) GetSourceLinkBalance(t *testing.T, addr common.Address) *big.Int {
+ return GetBalance(t, c.Source.Chain, c.Source.LinkToken.Address(), addr)
+}
+
+func (c *CCIPContracts) GetDestLinkBalance(t *testing.T, addr common.Address) *big.Int {
+ return GetBalance(t, c.Dest.Chain, c.Dest.LinkToken.Address(), addr)
+}
+
+func (c *CCIPContracts) GetSourceWrappedTokenBalance(t *testing.T, addr common.Address) *big.Int {
+ return GetBalance(t, c.Source.Chain, c.Source.WrappedNative.Address(), addr)
+}
+
+func (c *CCIPContracts) GetDestWrappedTokenBalance(t *testing.T, addr common.Address) *big.Int {
+ return GetBalance(t, c.Dest.Chain, c.Dest.WrappedNative.Address(), addr)
+}
+
+func (c *CCIPContracts) AssertBalances(t *testing.T, bas []BalanceAssertion) {
+ for _, b := range bas {
+ actual := b.Getter(t, b.Address)
+ t.Log("Checking balance for", b.Name, "at", b.Address.Hex(), "got", actual)
+ require.NotNil(t, actual, "%v getter return nil", b.Name)
+ if b.Within == "" {
+ require.Equal(t, b.Expected, actual.String(), "wrong balance for %s got %s want %s", b.Name, actual, b.Expected)
+ } else {
+ bi, _ := big.NewInt(0).SetString(b.Expected, 10)
+ withinI, _ := big.NewInt(0).SetString(b.Within, 10)
+ high := big.NewInt(0).Add(bi, withinI)
+ low := big.NewInt(0).Sub(bi, withinI)
+ require.Equal(t, -1, actual.Cmp(high), "wrong balance for %s got %s outside expected range [%s, %s]", b.Name, actual, low, high)
+ require.Equal(t, 1, actual.Cmp(low), "wrong balance for %s got %s outside expected range [%s, %s]", b.Name, actual, low, high)
+ }
+ }
+}
+
+func AccountToAddress(accounts []ocr2types.Account) (addresses []common.Address, err error) {
+ for _, signer := range accounts {
+ bytes, err := hexutil.Decode(string(signer))
+ if err != nil {
+ return []common.Address{}, errors.Wrap(err, fmt.Sprintf("given address is not valid %s", signer))
+ }
+ if len(bytes) != 20 {
+ return []common.Address{}, errors.Errorf("address is not 20 bytes %s", signer)
+ }
+ addresses = append(addresses, common.BytesToAddress(bytes))
+ }
+ return addresses, nil
+}
+
+func OnchainPublicKeyToAddress(publicKeys []ocrtypes.OnchainPublicKey) (addresses []common.Address, err error) {
+ for _, signer := range publicKeys {
+ if len(signer) != 20 {
+ return []common.Address{}, errors.Errorf("address is not 20 bytes %s", signer)
+ }
+ addresses = append(addresses, common.BytesToAddress(signer))
+ }
+ return addresses, nil
+}
+
+func (c *CCIPContracts) DeriveOCR2Config(t *testing.T, oracles []confighelper.OracleIdentityExtra, rawOnchainConfig []byte, rawOffchainConfig []byte) *OCR2Config {
+ signers, transmitters, threshold, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests(
+ 2*time.Second, // deltaProgress
+ 1*time.Second, // deltaResend
+ 1*time.Second, // deltaRound
+ 500*time.Millisecond, // deltaGrace
+ 2*time.Second, // deltaStage
+ 3,
+ []int{1, 1, 1, 1},
+ oracles,
+ rawOffchainConfig,
+ 50*time.Millisecond, // Max duration query
+ 1*time.Second, // Max duration observation
+ 100*time.Millisecond,
+ 100*time.Millisecond,
+ 100*time.Millisecond,
+ 1, // faults
+ rawOnchainConfig,
+ )
+ require.NoError(t, err)
+ lggr := logger.TestLogger(t)
+ lggr.Infow("Setting Config on Oracle Contract",
+ "signers", signers,
+ "transmitters", transmitters,
+ "threshold", threshold,
+ "onchainConfig", onchainConfig,
+ "encodedConfigVersion", offchainConfigVersion,
+ )
+ signerAddresses, err := OnchainPublicKeyToAddress(signers)
+ require.NoError(t, err)
+ transmitterAddresses, err := AccountToAddress(transmitters)
+ require.NoError(t, err)
+
+ return &OCR2Config{
+ Signers: signerAddresses,
+ Transmitters: transmitterAddresses,
+ F: threshold,
+ OnchainConfig: onchainConfig,
+ OffchainConfigVersion: offchainConfigVersion,
+ OffchainConfig: offchainConfig,
+ }
+}
+
+func (c *CCIPContracts) SetupCommitOCR2Config(t *testing.T, commitOnchainConfig, commitOffchainConfig []byte) {
+ c.commitOCRConfig = c.DeriveOCR2Config(t, c.Oracles, commitOnchainConfig, commitOffchainConfig)
+ // Set the DON on the commit store
+ _, err := c.Dest.CommitStore.SetOCR2Config(
+ c.Dest.User,
+ c.commitOCRConfig.Signers,
+ c.commitOCRConfig.Transmitters,
+ c.commitOCRConfig.F,
+ c.commitOCRConfig.OnchainConfig,
+ c.commitOCRConfig.OffchainConfigVersion,
+ c.commitOCRConfig.OffchainConfig,
+ )
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) SetupExecOCR2Config(t *testing.T, execOnchainConfig, execOffchainConfig []byte) {
+ c.execOCRConfig = c.DeriveOCR2Config(t, c.Oracles, execOnchainConfig, execOffchainConfig)
+ // Same DON on the offramp
+ _, err := c.Dest.OffRamp.SetOCR2Config(
+ c.Dest.User,
+ c.execOCRConfig.Signers,
+ c.execOCRConfig.Transmitters,
+ c.execOCRConfig.F,
+ c.execOCRConfig.OnchainConfig,
+ c.execOCRConfig.OffchainConfigVersion,
+ c.execOCRConfig.OffchainConfig,
+ )
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+}
+
+func (c *CCIPContracts) SetupOnchainConfig(t *testing.T, commitOnchainConfig, commitOffchainConfig, execOnchainConfig, execOffchainConfig []byte) int64 {
+ // Note We do NOT set the payees, payment is done in the OCR2Base implementation
+ blockBeforeConfig, err := c.Dest.Chain.BlockByNumber(context.Background(), nil)
+ require.NoError(t, err)
+
+ c.SetupCommitOCR2Config(t, commitOnchainConfig, commitOffchainConfig)
+ c.SetupExecOCR2Config(t, execOnchainConfig, execOffchainConfig)
+
+ return blockBeforeConfig.Number().Int64()
+}
+
+func (c *CCIPContracts) SetupLockAndMintTokenPool(
+ sourceTokenAddress common.Address,
+ wrappedTokenName,
+ wrappedTokenSymbol string) (common.Address, *burn_mint_erc677.BurnMintERC677, error) {
+ // Deploy dest token & pool
+ destTokenAddress, _, _, err := burn_mint_erc677.DeployBurnMintERC677(c.Dest.User, c.Dest.Chain, wrappedTokenName, wrappedTokenSymbol, 18, big.NewInt(0))
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+ c.Dest.Chain.Commit()
+
+ destToken, err := burn_mint_erc677.NewBurnMintERC677(destTokenAddress, c.Dest.Chain)
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+
+ destPoolAddress, _, destPool, err := burn_mint_token_pool.DeployBurnMintTokenPool(
+ c.Dest.User,
+ c.Dest.Chain,
+ destTokenAddress,
+ []common.Address{}, // pool originalSender allowList
+ c.Dest.ARMProxy.Address(),
+ c.Dest.Router.Address(),
+ )
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+ c.Dest.Chain.Commit()
+
+ _, err = destToken.GrantMintAndBurnRoles(c.Dest.User, destPoolAddress)
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+
+ _, err = destPool.ApplyChainUpdates(c.Dest.User,
+ []burn_mint_token_pool.TokenPoolChainUpdate{
+ {
+ RemoteChainSelector: c.Source.ChainSelector,
+ Allowed: true,
+ OutboundRateLimiterConfig: burn_mint_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ InboundRateLimiterConfig: burn_mint_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ },
+ })
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+ c.Dest.Chain.Commit()
+
+ sourcePoolAddress, _, sourcePool, err := lock_release_token_pool.DeployLockReleaseTokenPool(
+ c.Source.User,
+ c.Source.Chain,
+ sourceTokenAddress,
+ []common.Address{}, // empty allowList at deploy time indicates pool has no original sender restrictions
+ c.Source.ARMProxy.Address(),
+ true,
+ c.Source.Router.Address(),
+ )
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+ c.Source.Chain.Commit()
+
+ // set onRamp as valid caller for source pool
+ _, err = sourcePool.ApplyChainUpdates(c.Source.User, []lock_release_token_pool.TokenPoolChainUpdate{
+ {
+ RemoteChainSelector: c.Dest.ChainSelector,
+ Allowed: true,
+ OutboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ InboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ },
+ })
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+ c.Source.Chain.Commit()
+
+ wrappedNativeAddress, err := c.Source.Router.GetWrappedNative(nil)
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+
+ //native token is used as fee token
+ _, err = c.Source.PriceRegistry.UpdatePrices(c.Source.User, price_registry_1_2_0.InternalPriceUpdates{
+ TokenPriceUpdates: []price_registry_1_2_0.InternalTokenPriceUpdate{
+ {
+ SourceToken: sourceTokenAddress,
+ UsdPerToken: big.NewInt(5),
+ },
+ },
+ GasPriceUpdates: []price_registry_1_2_0.InternalGasPriceUpdate{},
+ })
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+ c.Source.Chain.Commit()
+
+ _, err = c.Source.PriceRegistry.ApplyFeeTokensUpdates(c.Source.User, []common.Address{wrappedNativeAddress}, nil)
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+ c.Source.Chain.Commit()
+
+ // add new token pool created above
+ _, err = c.Source.OnRamp.ApplyPoolUpdates(c.Source.User, nil, []evm_2_evm_onramp.InternalPoolUpdate{
+ {
+ Token: sourceTokenAddress,
+ Pool: sourcePoolAddress,
+ },
+ })
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+
+ _, err = c.Dest.OffRamp.ApplyPoolUpdates(c.Dest.User, nil, []evm_2_evm_offramp.InternalPoolUpdate{
+ {
+ Token: sourceTokenAddress,
+ Pool: destPoolAddress,
+ },
+ })
+ if err != nil {
+ return [20]byte{}, nil, err
+ }
+ c.Dest.Chain.Commit()
+
+ return sourcePoolAddress, destToken, err
+}
+
+func (c *CCIPContracts) SendMessage(t *testing.T, gasLimit, tokenAmount *big.Int, receiverAddr common.Address) {
+ extraArgs, err := GetEVMExtraArgsV1(gasLimit, false)
+ require.NoError(t, err)
+ msg := router.ClientEVM2AnyMessage{
+ Receiver: MustEncodeAddress(t, receiverAddr),
+ Data: []byte("hello"),
+ TokenAmounts: []router.ClientEVMTokenAmount{
+ {
+ Token: c.Source.LinkToken.Address(),
+ Amount: tokenAmount,
+ },
+ },
+ FeeToken: c.Source.LinkToken.Address(),
+ ExtraArgs: extraArgs,
+ }
+ fee, err := c.Source.Router.GetFee(nil, c.Dest.ChainSelector, msg)
+ require.NoError(t, err)
+ // Currently no overhead and 1gwei dest gas price. So fee is simply gasLimit * gasPrice.
+ // require.Equal(t, new(big.Int).Mul(gasLimit, gasPrice).String(), fee.String())
+ // Approve the fee amount + the token amount
+ _, err = c.Source.LinkToken.Approve(c.Source.User, c.Source.Router.Address(), new(big.Int).Add(fee, tokenAmount))
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.SendRequest(t, msg)
+}
+
+func GetBalances(t *testing.T, brs []BalanceReq) (map[string]*big.Int, error) {
+ m := make(map[string]*big.Int)
+ for _, br := range brs {
+ m[br.Name] = br.Getter(t, br.Addr)
+ if m[br.Name] == nil {
+ return nil, fmt.Errorf("%v getter return nil", br.Name)
+ }
+ }
+ return m, nil
+}
+
+func MustAddBigInt(a *big.Int, b string) *big.Int {
+ bi, _ := big.NewInt(0).SetString(b, 10)
+ return big.NewInt(0).Add(a, bi)
+}
+
+func MustSubBigInt(a *big.Int, b string) *big.Int {
+ bi, _ := big.NewInt(0).SetString(b, 10)
+ return big.NewInt(0).Sub(a, bi)
+}
+
+func MustEncodeAddress(t *testing.T, address common.Address) []byte {
+ bts, err := utils.ABIEncode(`[{"type":"address"}]`, address)
+ require.NoError(t, err)
+ return bts
+}
+
+func SetupCCIPContracts(t *testing.T, sourceChainID, sourceChainSelector, destChainID, destChainSelector uint64) CCIPContracts {
+ sourceChain, sourceUser := testhelpers.SetupChain(t)
+ destChain, destUser := testhelpers.SetupChain(t)
+
+ armSourceAddress, _, _, err := mock_arm_contract.DeployMockARMContract(
+ sourceUser,
+ sourceChain,
+ )
+ require.NoError(t, err)
+ sourceARM, err := mock_arm_contract.NewMockARMContract(armSourceAddress, sourceChain)
+ require.NoError(t, err)
+ armProxySourceAddress, _, _, err := arm_proxy_contract.DeployARMProxyContract(
+ sourceUser,
+ sourceChain,
+ armSourceAddress,
+ )
+ require.NoError(t, err)
+ sourceARMProxy, err := arm_proxy_contract.NewARMProxyContract(armProxySourceAddress, sourceChain)
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ armDestAddress, _, _, err := mock_arm_contract.DeployMockARMContract(
+ destUser,
+ destChain,
+ )
+ require.NoError(t, err)
+ armProxyDestAddress, _, _, err := arm_proxy_contract.DeployARMProxyContract(
+ destUser,
+ destChain,
+ armDestAddress,
+ )
+ require.NoError(t, err)
+ destChain.Commit()
+ destARM, err := mock_arm_contract.NewMockARMContract(armDestAddress, destChain)
+ require.NoError(t, err)
+ destARMProxy, err := arm_proxy_contract.NewARMProxyContract(armProxyDestAddress, destChain)
+ require.NoError(t, err)
+
+ // Deploy link token and pool on source chain
+ sourceLinkTokenAddress, _, _, err := link_token_interface.DeployLinkToken(sourceUser, sourceChain)
+ require.NoError(t, err)
+ sourceChain.Commit()
+ sourceLinkToken, err := link_token_interface.NewLinkToken(sourceLinkTokenAddress, sourceChain)
+ require.NoError(t, err)
+
+ // Create router
+ sourceWeth9addr, _, _, err := weth9.DeployWETH9(sourceUser, sourceChain)
+ require.NoError(t, err)
+ sourceWrapped, err := weth9.NewWETH9(sourceWeth9addr, sourceChain)
+ require.NoError(t, err)
+
+ sourceRouterAddress, _, _, err := router.DeployRouter(sourceUser, sourceChain, sourceWeth9addr, armProxySourceAddress)
+ require.NoError(t, err)
+ sourceRouter, err := router.NewRouter(sourceRouterAddress, sourceChain)
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ sourceWeth9PoolAddress, _, _, err := lock_release_token_pool_1_0_0.DeployLockReleaseTokenPool(
+ sourceUser,
+ sourceChain,
+ sourceWeth9addr,
+ []common.Address{},
+ armProxySourceAddress,
+ )
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ sourceWeth9Pool, err := lock_release_token_pool_1_0_0.NewLockReleaseTokenPool(sourceWeth9PoolAddress, sourceChain)
+ require.NoError(t, err)
+
+ sourcePoolAddress, _, _, err := lock_release_token_pool.DeployLockReleaseTokenPool(
+ sourceUser,
+ sourceChain,
+ sourceLinkTokenAddress,
+ []common.Address{},
+ armProxySourceAddress,
+ true,
+ sourceRouterAddress,
+ )
+ require.NoError(t, err)
+ sourceChain.Commit()
+ sourcePool, err := lock_release_token_pool.NewLockReleaseTokenPool(sourcePoolAddress, sourceChain)
+ require.NoError(t, err)
+
+ // Deploy custom token pool source
+ sourceCustomTokenAddress, _, _, err := link_token_interface.DeployLinkToken(sourceUser, sourceChain) // Just re-use this, it's an ERC20.
+ require.NoError(t, err)
+ sourceCustomToken, err := link_token_interface.NewLinkToken(sourceCustomTokenAddress, sourceChain)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // Deploy custom token pool dest
+ destCustomTokenAddress, _, _, err := link_token_interface.DeployLinkToken(destUser, destChain) // Just re-use this, it's an ERC20.
+ require.NoError(t, err)
+ destCustomToken, err := link_token_interface.NewLinkToken(destCustomTokenAddress, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // Deploy and configure onramp
+ sourcePricesAddress, _, _, err := price_registry_1_2_0.DeployPriceRegistry(
+ sourceUser,
+ sourceChain,
+ nil,
+ []common.Address{sourceLinkTokenAddress, sourceWeth9addr},
+ 60*60*24*14, // two weeks
+ )
+ require.NoError(t, err)
+
+ srcPriceRegistry, err := price_registry_1_2_0.NewPriceRegistry(sourcePricesAddress, sourceChain)
+ require.NoError(t, err)
+
+ _, err = srcPriceRegistry.UpdatePrices(sourceUser, price_registry_1_2_0.InternalPriceUpdates{
+ TokenPriceUpdates: []price_registry_1_2_0.InternalTokenPriceUpdate{
+ {
+ SourceToken: sourceLinkTokenAddress,
+ UsdPerToken: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(20)),
+ },
+ {
+ SourceToken: sourceWeth9addr,
+ UsdPerToken: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2000)),
+ },
+ },
+ GasPriceUpdates: []price_registry_1_2_0.InternalGasPriceUpdate{
+ {
+ DestChainSelector: destChainSelector,
+ UsdPerUnitGas: big.NewInt(20000e9),
+ },
+ },
+ })
+ require.NoError(t, err)
+
+ onRampAddress, _, _, err := evm_2_evm_onramp.DeployEVM2EVMOnRamp(
+ sourceUser, // user
+ sourceChain, // client
+ evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{
+ LinkToken: sourceLinkTokenAddress,
+ ChainSelector: sourceChainSelector,
+ DestChainSelector: destChainSelector,
+ DefaultTxGasLimit: 200_000,
+ MaxNopFeesJuels: big.NewInt(0).Mul(big.NewInt(100_000_000), big.NewInt(1e18)),
+ PrevOnRamp: common.HexToAddress(""),
+ ArmProxy: armProxySourceAddress, // ARM
+ },
+ evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig{
+ Router: sourceRouterAddress,
+ MaxNumberOfTokensPerMsg: 5,
+ DestGasOverhead: 350_000,
+ DestGasPerPayloadByte: 16,
+ DestDataAvailabilityOverheadGas: 33_596,
+ DestGasPerDataAvailabilityByte: 16,
+ DestDataAvailabilityMultiplierBps: 6840, // 0.684
+ PriceRegistry: sourcePricesAddress,
+ MaxDataBytes: 1e5,
+ MaxPerMsgGasLimit: 4_000_000,
+ },
+ []evm_2_evm_onramp.InternalPoolUpdate{
+ {
+ Token: sourceLinkTokenAddress,
+ Pool: sourcePoolAddress,
+ },
+ {
+ Token: sourceWeth9addr,
+ Pool: sourceWeth9PoolAddress,
+ },
+ },
+ evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: LinkUSDValue(100),
+ Rate: LinkUSDValue(1),
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: sourceLinkTokenAddress,
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: 1e18,
+ PremiumMultiplierWeiPerEth: 9e17,
+ Enabled: true,
+ },
+ {
+ Token: sourceWeth9addr,
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: 1e18,
+ PremiumMultiplierWeiPerEth: 1e18,
+ Enabled: true,
+ },
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: sourceLinkTokenAddress,
+ MinFeeUSDCents: 50, // $0.5
+ MaxFeeUSDCents: 1_000_000_00, // $ 1 million
+ DeciBps: 5_0, // 5 bps
+ DestGasOverhead: 34_000,
+ DestBytesOverhead: 32,
+ },
+ },
+ []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{},
+ )
+ require.NoError(t, err)
+ onRamp, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(onRampAddress, sourceChain)
+ require.NoError(t, err)
+ _, err = sourcePool.ApplyChainUpdates(
+ sourceUser,
+ []lock_release_token_pool.TokenPoolChainUpdate{{
+ RemoteChainSelector: DestChainSelector,
+ Allowed: true,
+ OutboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ InboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ }},
+ )
+ require.NoError(t, err)
+ _, err = sourceWeth9Pool.ApplyRampUpdates(sourceUser,
+ []lock_release_token_pool_1_0_0.TokenPoolRampUpdate{{Ramp: onRampAddress, Allowed: true,
+ RateLimiterConfig: lock_release_token_pool_1_0_0.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ }},
+ []lock_release_token_pool_1_0_0.TokenPoolRampUpdate{},
+ )
+ require.NoError(t, err)
+ sourceChain.Commit()
+ _, err = sourceRouter.ApplyRampUpdates(sourceUser, []router.RouterOnRamp{{DestChainSelector: destChainSelector, OnRamp: onRampAddress}}, nil, nil)
+ require.NoError(t, err)
+ sourceChain.Commit()
+
+ destWethaddr, _, _, err := weth9.DeployWETH9(destUser, destChain)
+ require.NoError(t, err)
+ destWrapped, err := weth9.NewWETH9(destWethaddr, destChain)
+ require.NoError(t, err)
+
+ // Create dest router
+ destRouterAddress, _, _, err := router.DeployRouter(destUser, destChain, destWethaddr, armProxyDestAddress)
+ require.NoError(t, err)
+ destChain.Commit()
+ destRouter, err := router.NewRouter(destRouterAddress, destChain)
+ require.NoError(t, err)
+
+ // Deploy link token and pool on destination chain
+ destLinkTokenAddress, _, _, err := link_token_interface.DeployLinkToken(destUser, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+ destLinkToken, err := link_token_interface.NewLinkToken(destLinkTokenAddress, destChain)
+ require.NoError(t, err)
+ destPoolAddress, _, _, err := lock_release_token_pool.DeployLockReleaseTokenPool(
+ destUser,
+ destChain,
+ destLinkTokenAddress,
+ []common.Address{},
+ armProxyDestAddress,
+ true,
+ destRouterAddress,
+ )
+ require.NoError(t, err)
+ destChain.Commit()
+ destPool, err := lock_release_token_pool.NewLockReleaseTokenPool(destPoolAddress, destChain)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // Float the offramp pool
+ o, err := destPool.Owner(nil)
+ require.NoError(t, err)
+ require.Equal(t, destUser.From.String(), o.String())
+ _, err = destPool.SetRebalancer(destUser, destUser.From)
+ require.NoError(t, err)
+ _, err = destLinkToken.Approve(destUser, destPoolAddress, Link(200))
+ require.NoError(t, err)
+ _, err = destPool.ProvideLiquidity(destUser, Link(200))
+ require.NoError(t, err)
+ destChain.Commit()
+
+ destWrappedPoolAddress, _, _, err := lock_release_token_pool_1_0_0.DeployLockReleaseTokenPool(
+ destUser,
+ destChain,
+ destWethaddr,
+ []common.Address{},
+ armProxyDestAddress,
+ )
+ require.NoError(t, err)
+ destWrappedPool, err := lock_release_token_pool_1_0_0.NewLockReleaseTokenPool(destWrappedPoolAddress, destChain)
+ require.NoError(t, err)
+
+ poolFloatValue := big.NewInt(1e18)
+
+ destUser.Value = poolFloatValue
+ _, err = destWrapped.Deposit(destUser)
+ require.NoError(t, err)
+ destChain.Commit()
+ destUser.Value = nil
+
+ _, err = destWrapped.Transfer(destUser, destWrappedPool.Address(), poolFloatValue)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ // Deploy and configure ge offramp.
+ destPricesAddress, _, _, err := price_registry_1_2_0.DeployPriceRegistry(
+ destUser,
+ destChain,
+ nil,
+ []common.Address{destLinkTokenAddress},
+ 60*60*24*14, // two weeks
+ )
+ require.NoError(t, err)
+ destPriceRegistry, err := price_registry_1_2_0.NewPriceRegistry(destPricesAddress, destChain)
+ require.NoError(t, err)
+
+ // Deploy commit store.
+ commitStoreAddress, _, _, err := commit_store_1_2_0.DeployCommitStore(
+ destUser, // user
+ destChain, // client
+ commit_store_1_2_0.CommitStoreStaticConfig{
+ ChainSelector: destChainSelector,
+ SourceChainSelector: sourceChainSelector,
+ OnRamp: onRamp.Address(),
+ ArmProxy: destARMProxy.Address(),
+ },
+ )
+ require.NoError(t, err)
+ destChain.Commit()
+ commitStore, err := commit_store_1_2_0.NewCommitStore(commitStoreAddress, destChain)
+ require.NoError(t, err)
+
+ offRampAddress, _, _, err := evm_2_evm_offramp.DeployEVM2EVMOffRamp(
+ destUser,
+ destChain,
+ evm_2_evm_offramp.EVM2EVMOffRampStaticConfig{
+ CommitStore: commitStore.Address(),
+ ChainSelector: destChainSelector,
+ SourceChainSelector: sourceChainSelector,
+ OnRamp: onRampAddress,
+ PrevOffRamp: common.HexToAddress(""),
+ ArmProxy: armProxyDestAddress,
+ },
+ []common.Address{sourceLinkTokenAddress, sourceWeth9addr},
+ []common.Address{destPoolAddress, destWrappedPool.Address()},
+ evm_2_evm_offramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: LinkUSDValue(100),
+ Rate: LinkUSDValue(1),
+ },
+ )
+ require.NoError(t, err)
+ offRamp, err := evm_2_evm_offramp.NewEVM2EVMOffRamp(offRampAddress, destChain)
+ require.NoError(t, err)
+ _, err = destPool.ApplyChainUpdates(destUser,
+ []lock_release_token_pool.TokenPoolChainUpdate{{
+ RemoteChainSelector: sourceChainSelector,
+ Allowed: true,
+ OutboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ InboundRateLimiterConfig: lock_release_token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ }},
+ )
+ require.NoError(t, err)
+
+ _, err = destWrappedPool.ApplyRampUpdates(destUser,
+ []lock_release_token_pool_1_0_0.TokenPoolRampUpdate{},
+ []lock_release_token_pool_1_0_0.TokenPoolRampUpdate{{
+ Ramp: offRampAddress,
+ Allowed: true,
+ RateLimiterConfig: lock_release_token_pool_1_0_0.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: HundredLink,
+ Rate: big.NewInt(1e18),
+ },
+ }},
+ )
+ require.NoError(t, err)
+
+ destChain.Commit()
+ _, err = destPriceRegistry.ApplyPriceUpdatersUpdates(destUser, []common.Address{commitStoreAddress}, []common.Address{})
+ require.NoError(t, err)
+ _, err = destRouter.ApplyRampUpdates(destUser, nil,
+ nil, []router.RouterOffRamp{{SourceChainSelector: sourceChainSelector, OffRamp: offRampAddress}})
+ require.NoError(t, err)
+
+ // Deploy 2 revertable (one SS one non-SS)
+ revertingMessageReceiver1Address, _, _, err := maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver(destUser, destChain, false)
+ require.NoError(t, err)
+ revertingMessageReceiver1, _ := maybe_revert_message_receiver.NewMaybeRevertMessageReceiver(revertingMessageReceiver1Address, destChain)
+ revertingMessageReceiver2Address, _, _, err := maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver(destUser, destChain, false)
+ require.NoError(t, err)
+ revertingMessageReceiver2, _ := maybe_revert_message_receiver.NewMaybeRevertMessageReceiver(revertingMessageReceiver2Address, destChain)
+ // Need to commit here, or we will hit the block gas limit when deploying the executor
+ sourceChain.Commit()
+ destChain.Commit()
+
+ // Ensure we have at least finality blocks.
+ for i := 0; i < 50; i++ {
+ sourceChain.Commit()
+ destChain.Commit()
+ }
+
+ source := SourceChain{
+ Common: Common{
+ ChainID: sourceChainID,
+ ChainSelector: sourceChainSelector,
+ User: sourceUser,
+ Chain: sourceChain,
+ LinkToken: sourceLinkToken,
+ LinkTokenPool: sourcePool,
+ CustomToken: sourceCustomToken,
+ ARM: sourceARM,
+ ARMProxy: sourceARMProxy,
+ PriceRegistry: srcPriceRegistry,
+ WrappedNative: sourceWrapped,
+ WrappedNativePool: sourceWeth9Pool,
+ },
+ Router: sourceRouter,
+ OnRamp: onRamp,
+ }
+ dest := DestinationChain{
+ Common: Common{
+ ChainID: destChainID,
+ ChainSelector: destChainSelector,
+ User: destUser,
+ Chain: destChain,
+ LinkToken: destLinkToken,
+ LinkTokenPool: destPool,
+ CustomToken: destCustomToken,
+ ARM: destARM,
+ ARMProxy: destARMProxy,
+ PriceRegistry: destPriceRegistry,
+ WrappedNative: destWrapped,
+ WrappedNativePool: destWrappedPool,
+ },
+ CommitStore: commitStore,
+ Router: destRouter,
+ OffRamp: offRamp,
+ Receivers: []MaybeRevertReceiver{{Receiver: revertingMessageReceiver1, Strict: false}, {Receiver: revertingMessageReceiver2, Strict: true}},
+ }
+
+ return CCIPContracts{
+ Source: source,
+ Dest: dest,
+ }
+}
+
+func (c *CCIPContracts) SendRequest(t *testing.T, msg router.ClientEVM2AnyMessage) *types.Transaction {
+ tx, err := c.Source.Router.CcipSend(c.Source.User, c.Dest.ChainSelector, msg)
+ require.NoError(t, err)
+ testhelpers.ConfirmTxs(t, []*types.Transaction{tx}, c.Source.Chain)
+ return tx
+}
+
+func (c *CCIPContracts) AssertExecState(t *testing.T, log logpoller.Log, state MessageExecutionState, offRampOpts ...common.Address) {
+ var offRamp *evm_2_evm_offramp.EVM2EVMOffRamp
+ var err error
+ if len(offRampOpts) > 0 {
+ offRamp, err = evm_2_evm_offramp.NewEVM2EVMOffRamp(offRampOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.OffRamp, "no offRamp configured")
+ offRamp = c.Dest.OffRamp
+ }
+ executionStateChanged, err := offRamp.ParseExecutionStateChanged(log.ToGethLog())
+ require.NoError(t, err)
+ if MessageExecutionState(executionStateChanged.State) != state {
+ t.Log("Execution failed", hexutil.Encode(executionStateChanged.ReturnData))
+ t.Fail()
+ }
+}
+
+func GetEVMExtraArgsV1(gasLimit *big.Int, strict bool) ([]byte, error) {
+ EVMV1Tag := []byte{0x97, 0xa6, 0x57, 0xc9}
+
+ encodedArgs, err := utils.ABIEncode(`[{"type":"uint256"},{"type":"bool"}]`, gasLimit, strict)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(EVMV1Tag, encodedArgs...), nil
+}
+
+type ManualExecArgs struct {
+ SourceChainID, DestChainID uint64
+ DestUser *bind.TransactOpts
+ SourceChain, DestChain bind.ContractBackend
+ SourceStartBlock *big.Int // the block in/after which failed ccip-send transaction was triggered
+ DestStartBlock uint64 // the start block for filtering ReportAccepted event (including the failed seq num)
+ // in destination chain. if not provided to be derived by ApproxDestStartBlock method
+ DestLatestBlockNum uint64 // current block number in destination
+ DestDeployedAt uint64 // destination block number for the initial destination contract deployment.
+ // Can be any number before the tx was reverted in destination chain. Preferably this needs to be set up with
+ // a value greater than zero to avoid performance issue in locating approximate destination block
+ SendReqLogIndex uint // log index of the CCIPSendRequested log in source chain
+ SendReqTxHash string // tx hash of the ccip-send transaction for which execution was reverted
+ CommitStore string
+ OnRamp string
+ OffRamp string
+ SeqNr uint64
+ GasLimit *big.Int
+}
+
+// ApproxDestStartBlock attempts to locate a block in destination chain with timestamp closest to the timestamp of the block
+// in source chain in which ccip-send transaction was included
+// it uses binary search to locate the block with the closest timestamp
+// if the block located has a timestamp greater than the timestamp of mentioned source block
+// it just returns the first block found with lesser timestamp of the source block
+// providing a value of args.DestDeployedAt ensures better performance by reducing the range of block numbers to be traversed
+func (args *ManualExecArgs) ApproxDestStartBlock() error {
+ sourceBlockHdr, err := args.SourceChain.HeaderByNumber(context.Background(), args.SourceStartBlock)
+ if err != nil {
+ return err
+ }
+ sendTxTime := sourceBlockHdr.Time
+ maxBlockNum := args.DestLatestBlockNum
+ // setting this to an approx value of 1000 considering destination chain would have at least 1000 blocks before the transaction started
+ minBlockNum := args.DestDeployedAt
+ closestBlockNum := uint64(math.Floor((float64(maxBlockNum) + float64(minBlockNum)) / 2))
+ var closestBlockHdr *types.Header
+ closestBlockHdr, err = args.DestChain.HeaderByNumber(context.Background(), big.NewInt(int64(closestBlockNum)))
+ if err != nil {
+ return err
+ }
+ // to reduce the number of RPC calls increase the value of blockOffset
+ blockOffset := uint64(10)
+ for {
+ blockNum := closestBlockHdr.Number.Uint64()
+ if minBlockNum > maxBlockNum {
+ break
+ }
+ timeDiff := math.Abs(float64(closestBlockHdr.Time - sendTxTime))
+ // break if the difference in timestamp is lesser than 1 minute
+ if timeDiff < 60 {
+ break
+ } else if closestBlockHdr.Time > sendTxTime {
+ maxBlockNum = blockNum - 1
+ } else {
+ minBlockNum = blockNum + 1
+ }
+ closestBlockNum = uint64(math.Floor((float64(maxBlockNum) + float64(minBlockNum)) / 2))
+ closestBlockHdr, err = args.DestChain.HeaderByNumber(context.Background(), big.NewInt(int64(closestBlockNum)))
+ if err != nil {
+ return err
+ }
+ }
+
+ for closestBlockHdr.Time > sendTxTime {
+ closestBlockNum = closestBlockNum - blockOffset
+ if closestBlockNum <= 0 {
+ return fmt.Errorf("approx destination blocknumber not found")
+ }
+ closestBlockHdr, err = args.DestChain.HeaderByNumber(context.Background(), big.NewInt(int64(closestBlockNum)))
+ if err != nil {
+ return err
+ }
+ }
+ args.DestStartBlock = closestBlockHdr.Number.Uint64()
+ fmt.Println("using approx destination start block number", args.DestStartBlock)
+ return nil
+}
+
+func (args *ManualExecArgs) FindSeqNrFromCCIPSendRequested() (uint64, error) {
+ var seqNr uint64
+ onRampContract, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(common.HexToAddress(args.OnRamp), args.SourceChain)
+ if err != nil {
+ return seqNr, err
+ }
+ iterator, err := onRampContract.FilterCCIPSendRequested(&bind.FilterOpts{
+ Start: args.SourceStartBlock.Uint64(),
+ })
+ if err != nil {
+ return seqNr, err
+ }
+ for iterator.Next() {
+ if iterator.Event.Raw.Index == args.SendReqLogIndex &&
+ iterator.Event.Raw.TxHash.Hex() == args.SendReqTxHash {
+ seqNr = iterator.Event.Message.SequenceNumber
+ break
+ }
+ }
+ if seqNr == 0 {
+ return seqNr,
+ fmt.Errorf("no CCIPSendRequested logs found for logIndex %d starting from block number %d", args.SendReqLogIndex, args.SourceStartBlock)
+ }
+ return seqNr, nil
+}
+
+func (args *ManualExecArgs) ExecuteManually() (*types.Transaction, error) {
+ if args.SourceChainID == 0 ||
+ args.DestChainID == 0 ||
+ args.DestUser == nil {
+ return nil, fmt.Errorf("chain ids and owners are mandatory for source and dest chain")
+ }
+ if !common.IsHexAddress(args.CommitStore) ||
+ !common.IsHexAddress(args.OffRamp) ||
+ !common.IsHexAddress(args.OnRamp) {
+ return nil, fmt.Errorf("contract addresses must be valid hex address")
+ }
+ if args.SendReqTxHash == "" {
+ return nil, fmt.Errorf("tx hash of ccip-send request are required")
+ }
+ if args.SourceStartBlock == nil {
+ return nil, fmt.Errorf("must provide the value of source block in/after which ccip-send tx was included")
+ }
+ if args.SeqNr == 0 {
+ if args.SendReqLogIndex == 0 {
+ return nil, fmt.Errorf("must provide the value of log index of ccip-send request")
+ }
+ // locate seq nr from CCIPSendRequested log
+ seqNr, err := args.FindSeqNrFromCCIPSendRequested()
+ if err != nil {
+ return nil, err
+ }
+ args.SeqNr = seqNr
+ }
+ commitStore, err := commit_store_1_2_0.NewCommitStore(common.HexToAddress(args.CommitStore), args.DestChain)
+ if err != nil {
+ return nil, err
+ }
+ if args.DestStartBlock < 1 {
+ err = args.ApproxDestStartBlock()
+ if err != nil {
+ return nil, err
+ }
+ }
+ iterator, err := commitStore.FilterReportAccepted(&bind.FilterOpts{Start: args.DestStartBlock})
+ if err != nil {
+ return nil, err
+ }
+
+ var commitReport *commit_store_1_2_0.CommitStoreCommitReport
+ for iterator.Next() {
+ if iterator.Event.Report.Interval.Min <= args.SeqNr && iterator.Event.Report.Interval.Max >= args.SeqNr {
+ commitReport = &iterator.Event.Report
+ fmt.Println("Found root")
+ break
+ }
+ }
+ if commitReport == nil {
+ return nil, fmt.Errorf("unable to find seq num %d in commit report", args.SeqNr)
+ }
+
+ return args.execute(commitReport)
+}
+
+func (args *ManualExecArgs) execute(report *commit_store_1_2_0.CommitStoreCommitReport) (*types.Transaction, error) {
+ log.Info().Msg("Executing request manually")
+ seqNr := args.SeqNr
+ // Build a merkle tree for the report
+ mctx := hashutil.NewKeccak()
+ onRampContract, err := evm_2_evm_onramp_1_2_0.NewEVM2EVMOnRamp(common.HexToAddress(args.OnRamp), args.SourceChain)
+ if err != nil {
+ return nil, err
+ }
+ leafHasher := v1_2_0.NewLeafHasher(args.SourceChainID, args.DestChainID, common.HexToAddress(args.OnRamp), mctx, onRampContract)
+ if leafHasher == nil {
+ return nil, fmt.Errorf("unable to create leaf hasher")
+ }
+
+ var leaves [][32]byte
+ var curr, prove int
+ var msgs []evm_2_evm_offramp.InternalEVM2EVMMessage
+ var manualExecGasLimits []*big.Int
+ var tokenData [][][]byte
+ sendRequestedIterator, err := onRampContract.FilterCCIPSendRequested(&bind.FilterOpts{
+ Start: args.SourceStartBlock.Uint64(),
+ })
+ if err != nil {
+ return nil, err
+ }
+ for sendRequestedIterator.Next() {
+ if sendRequestedIterator.Event.Message.SequenceNumber <= report.Interval.Max &&
+ sendRequestedIterator.Event.Message.SequenceNumber >= report.Interval.Min {
+ fmt.Println("Found seq num", sendRequestedIterator.Event.Message.SequenceNumber, report.Interval)
+ hash, err2 := leafHasher.HashLeaf(sendRequestedIterator.Event.Raw)
+ if err2 != nil {
+ return nil, err2
+ }
+ leaves = append(leaves, hash)
+ if sendRequestedIterator.Event.Message.SequenceNumber == seqNr {
+ fmt.Printf("Found proving %d %+v\n", curr, sendRequestedIterator.Event.Message)
+ var tokensAndAmounts []evm_2_evm_offramp.ClientEVMTokenAmount
+ for _, tokenAndAmount := range sendRequestedIterator.Event.Message.TokenAmounts {
+ tokensAndAmounts = append(tokensAndAmounts, evm_2_evm_offramp.ClientEVMTokenAmount{
+ Token: tokenAndAmount.Token,
+ Amount: tokenAndAmount.Amount,
+ })
+ }
+ msg := evm_2_evm_offramp.InternalEVM2EVMMessage{
+ SourceChainSelector: sendRequestedIterator.Event.Message.SourceChainSelector,
+ Sender: sendRequestedIterator.Event.Message.Sender,
+ Receiver: sendRequestedIterator.Event.Message.Receiver,
+ SequenceNumber: sendRequestedIterator.Event.Message.SequenceNumber,
+ GasLimit: sendRequestedIterator.Event.Message.GasLimit,
+ Strict: sendRequestedIterator.Event.Message.Strict,
+ Nonce: sendRequestedIterator.Event.Message.Nonce,
+ FeeToken: sendRequestedIterator.Event.Message.FeeToken,
+ FeeTokenAmount: sendRequestedIterator.Event.Message.FeeTokenAmount,
+ Data: sendRequestedIterator.Event.Message.Data,
+ TokenAmounts: tokensAndAmounts,
+ SourceTokenData: sendRequestedIterator.Event.Message.SourceTokenData,
+ MessageId: sendRequestedIterator.Event.Message.MessageId,
+ }
+ msgs = append(msgs, msg)
+ if args.GasLimit != nil {
+ msg.GasLimit = args.GasLimit
+ }
+ manualExecGasLimits = append(manualExecGasLimits, msg.GasLimit)
+ var msgTokenData [][]byte
+ for range sendRequestedIterator.Event.Message.TokenAmounts {
+ msgTokenData = append(msgTokenData, []byte{})
+ }
+
+ tokenData = append(tokenData, msgTokenData)
+ prove = curr
+ }
+ curr++
+ }
+ }
+ sendRequestedIterator.Close()
+ if msgs == nil {
+ return nil, fmt.Errorf("unable to find msg with seqNr %d", seqNr)
+ }
+ tree, err := merklemulti.NewTree(mctx, leaves)
+ if err != nil {
+ return nil, err
+ }
+ if tree.Root() != report.MerkleRoot {
+ return nil, fmt.Errorf("root doesn't match")
+ }
+
+ proof, err := tree.Prove([]int{prove})
+ if err != nil {
+ return nil, err
+ }
+
+ offRampProof := evm_2_evm_offramp.InternalExecutionReport{
+ Messages: msgs,
+ OffchainTokenData: tokenData,
+ Proofs: proof.Hashes,
+ ProofFlagBits: abihelpers.ProofFlagsToBits(proof.SourceFlags),
+ }
+ offRamp, err := evm_2_evm_offramp.NewEVM2EVMOffRamp(common.HexToAddress(args.OffRamp), args.DestChain)
+ if err != nil {
+ return nil, err
+ }
+ // Execute.
+ return offRamp.ManuallyExecute(args.DestUser, offRampProof, manualExecGasLimits)
+}
+
+func (c *CCIPContracts) ExecuteMessage(
+ t *testing.T,
+ req logpoller.Log,
+ txHash common.Hash,
+ destStartBlock uint64,
+) uint64 {
+ t.Log("Executing request manually")
+ sendReqReceipt, err := c.Source.Chain.TransactionReceipt(context.Background(), txHash)
+ require.NoError(t, err)
+ args := ManualExecArgs{
+ SourceChainID: c.Source.ChainID,
+ DestChainID: c.Dest.ChainID,
+ DestUser: c.Dest.User,
+ SourceChain: c.Source.Chain,
+ DestChain: c.Dest.Chain,
+ SourceStartBlock: sendReqReceipt.BlockNumber,
+ DestStartBlock: destStartBlock,
+ DestLatestBlockNum: c.Dest.Chain.Blockchain().CurrentBlock().Number.Uint64(),
+ SendReqLogIndex: uint(req.LogIndex),
+ SendReqTxHash: txHash.String(),
+ CommitStore: c.Dest.CommitStore.Address().String(),
+ OnRamp: c.Source.OnRamp.Address().String(),
+ OffRamp: c.Dest.OffRamp.Address().String(),
+ }
+ tx, err := args.ExecuteManually()
+ require.NoError(t, err)
+ c.Dest.Chain.Commit()
+ c.Source.Chain.Commit()
+ rec, err := c.Dest.Chain.TransactionReceipt(context.Background(), tx.Hash())
+ require.NoError(t, err)
+ require.Equal(t, uint64(1), rec.Status, "manual execution failed")
+ t.Logf("Manual Execution completed for seqNum %d", args.SeqNr)
+ return args.SeqNr
+}
+
+func GetBalance(t *testing.T, chain bind.ContractBackend, tokenAddr common.Address, addr common.Address) *big.Int {
+ token, err := link_token_interface.NewLinkToken(tokenAddr, chain)
+ require.NoError(t, err)
+ bal, err := token.BalanceOf(nil, addr)
+ require.NoError(t, err)
+ return bal
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go
new file mode 100644
index 00000000000..25be1c2a9a9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go
@@ -0,0 +1,1045 @@
+package testhelpers_1_4_0
+
+import (
+ "context"
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "net/http"
+ "net/http/httptest"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
+ "github.com/ethereum/go-ethereum/common"
+ types3 "github.com/ethereum/go-ethereum/core/types"
+ "github.com/google/uuid"
+ "github.com/hashicorp/consul/sdk/freeport"
+ "github.com/jmoiron/sqlx"
+ "github.com/onsi/gomega"
+ "github.com/pkg/errors"
+
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap"
+ "k8s.io/utils/pointer" //nolint:staticcheck
+
+ "github.com/smartcontractkit/libocr/commontypes"
+ "github.com/smartcontractkit/libocr/offchainreporting2/confighelper"
+ types4 "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/loop"
+ "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core/mocks"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ evmUtils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
+ configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/logger/audit"
+ "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
+ feeds2 "github.com/smartcontractkit/chainlink/v2/core/services/feeds"
+ feedsMocks "github.com/smartcontractkit/chainlink/v2/core/services/feeds/mocks"
+ pb "github.com/smartcontractkit/chainlink/v2/core/services/feeds/proto"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey"
+ "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key"
+ ksMocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_0_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+ integrationtesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/integration"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap"
+ evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+ clutils "github.com/smartcontractkit/chainlink/v2/core/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/utils/crypto"
+ "github.com/smartcontractkit/chainlink/v2/plugins"
+)
+
+const (
+ execSpecTemplate = `
+ type = "offchainreporting2"
+ schemaVersion = 1
+ name = "ccip-exec-1"
+ externalJobID = "67ffad71-d90f-4fe3-b4e4-494924b707fb"
+ forwardingAllowed = false
+ maxTaskDuration = "0s"
+ contractID = "%s"
+ contractConfigConfirmations = 1
+ contractConfigTrackerPollInterval = "20s"
+ ocrKeyBundleID = "%s"
+ relay = "evm"
+ pluginType = "ccip-execution"
+ transmitterID = "%s"
+
+ [relayConfig]
+ chainID = 1_337
+
+ [pluginConfig]
+ destStartBlock = 50
+
+ [pluginConfig.USDCConfig]
+ AttestationAPI = "http://blah.com"
+ SourceMessageTransmitterAddress = "%s"
+ SourceTokenAddress = "%s"
+ AttestationAPITimeoutSeconds = 10
+ `
+ commitSpecTemplatePipeline = `
+ type = "offchainreporting2"
+ schemaVersion = 1
+ name = "ccip-commit-1"
+ externalJobID = "13c997cf-1a14-4ab7-9068-07ee6d2afa55"
+ forwardingAllowed = false
+ maxTaskDuration = "0s"
+ contractID = "%s"
+ contractConfigConfirmations = 1
+ contractConfigTrackerPollInterval = "20s"
+ ocrKeyBundleID = "%s"
+ relay = "evm"
+ pluginType = "ccip-commit"
+ transmitterID = "%s"
+
+ [relayConfig]
+ chainID = 1_337
+
+ [pluginConfig]
+ destStartBlock = 50
+ offRamp = "%s"
+ tokenPricesUSDPipeline = """
+ %s
+ """
+ `
+ commitSpecTemplateDynamicPriceGetter = `
+ type = "offchainreporting2"
+ schemaVersion = 1
+ name = "ccip-commit-1"
+ externalJobID = "13c997cf-1a14-4ab7-9068-07ee6d2afa55"
+ forwardingAllowed = false
+ maxTaskDuration = "0s"
+ contractID = "%s"
+ contractConfigConfirmations = 1
+ contractConfigTrackerPollInterval = "20s"
+ ocrKeyBundleID = "%s"
+ relay = "evm"
+ pluginType = "ccip-commit"
+ transmitterID = "%s"
+
+ [relayConfig]
+ chainID = 1_337
+
+ [pluginConfig]
+ destStartBlock = 50
+ offRamp = "%s"
+ priceGetterConfig = """
+ %s
+ """
+ `
+)
+
+type Node struct {
+ App chainlink.Application
+ Transmitter common.Address
+ PaymentReceiver common.Address
+ KeyBundle ocr2key.KeyBundle
+}
+
+func (node *Node) FindJobIDForContract(t *testing.T, addr common.Address) int32 {
+ jobs := node.App.JobSpawner().ActiveJobs()
+ for _, j := range jobs {
+ if j.Type == job.OffchainReporting2 && j.OCR2OracleSpec.ContractID == addr.Hex() {
+ return j.ID
+ }
+ }
+ t.Fatalf("Could not find job for contract %s", addr.Hex())
+ return 0
+}
+
+func (node *Node) EventuallyNodeUsesUpdatedPriceRegistry(t *testing.T, ccipContracts CCIPIntegrationTestHarness) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ log, err := c.LogPoller().LatestLogByEventSigWithConfs(
+ testutils.Context(t),
+ v1_0_0.UsdPerUnitGasUpdated,
+ ccipContracts.Dest.PriceRegistry.Address(),
+ 0,
+ )
+ // err can be transient errors such as sql row set empty
+ if err != nil {
+ return false
+ }
+ return log != nil
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "node is not using updated price registry %s", ccipContracts.Dest.PriceRegistry.Address().Hex())
+ return log
+}
+
+func (node *Node) EventuallyNodeUsesNewCommitConfig(t *testing.T, ccipContracts CCIPIntegrationTestHarness, commitCfg ccipdata.CommitOnchainConfig) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ log, err := c.LogPoller().LatestLogByEventSigWithConfs(
+ testutils.Context(t),
+ evmrelay.OCR2AggregatorLogDecoder.EventSig(),
+ ccipContracts.Dest.CommitStore.Address(),
+ 0,
+ )
+ require.NoError(t, err)
+ var latestCfg ccipdata.CommitOnchainConfig
+ if log != nil {
+ latestCfg, err = DecodeCommitOnChainConfig(log.Data)
+ require.NoError(t, err)
+ return latestCfg == commitCfg
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "node is using old cfg")
+ return log
+}
+
+func (node *Node) EventuallyNodeUsesNewExecConfig(t *testing.T, ccipContracts CCIPIntegrationTestHarness, execCfg v1_2_0.ExecOnchainConfig) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ log, err := c.LogPoller().LatestLogByEventSigWithConfs(
+ testutils.Context(t),
+ evmrelay.OCR2AggregatorLogDecoder.EventSig(),
+ ccipContracts.Dest.OffRamp.Address(),
+ 0,
+ )
+ require.NoError(t, err)
+ var latestCfg v1_2_0.ExecOnchainConfig
+ if log != nil {
+ latestCfg, err = DecodeExecOnChainConfig(log.Data)
+ require.NoError(t, err)
+ return latestCfg == execCfg
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "node is using old cfg")
+ return log
+}
+
+func (node *Node) EventuallyHasReqSeqNum(t *testing.T, ccipContracts *CCIPIntegrationTestHarness, onRamp common.Address, seqNum int) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Source.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ lgs, err := c.LogPoller().LogsDataWordRange(
+ testutils.Context(t),
+ v1_2_0.CCIPSendRequestEventSig,
+ onRamp,
+ v1_2_0.CCIPSendRequestSeqNumIndex,
+ abihelpers.EvmWord(uint64(seqNum)),
+ abihelpers.EvmWord(uint64(seqNum)),
+ 1,
+ )
+ require.NoError(t, err)
+ t.Log("Send requested", len(lgs))
+ if len(lgs) == 1 {
+ log = lgs[0]
+ return true
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "eventually has seq num")
+ return log
+}
+
+func (node *Node) EventuallyHasExecutedSeqNums(t *testing.T, ccipContracts *CCIPIntegrationTestHarness, offRamp common.Address, minSeqNum int, maxSeqNum int) []logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var logs []logpoller.Log
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ lgs, err := c.LogPoller().IndexedLogsTopicRange(
+ testutils.Context(t),
+ v1_0_0.ExecutionStateChangedEvent,
+ offRamp,
+ v1_0_0.ExecutionStateChangedSeqNrIndex,
+ abihelpers.EvmWord(uint64(minSeqNum)),
+ abihelpers.EvmWord(uint64(maxSeqNum)),
+ 1,
+ )
+ require.NoError(t, err)
+ t.Logf("Have executed logs %d want %d", len(lgs), maxSeqNum-minSeqNum+1)
+ if len(lgs) == maxSeqNum-minSeqNum+1 {
+ logs = lgs
+ t.Logf("Seq Num %d-%d executed", minSeqNum, maxSeqNum)
+ return true
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "eventually has not executed seq num")
+ return logs
+}
+
+func (node *Node) ConsistentlySeqNumHasNotBeenExecuted(t *testing.T, ccipContracts *CCIPIntegrationTestHarness, offRamp common.Address, seqNum int) logpoller.Log {
+ c, err := node.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(ccipContracts.Dest.ChainID, 10))
+ require.NoError(t, err)
+ var log logpoller.Log
+ gomega.NewGomegaWithT(t).Consistently(func() bool {
+ ccipContracts.Source.Chain.Commit()
+ ccipContracts.Dest.Chain.Commit()
+ lgs, err := c.LogPoller().IndexedLogsTopicRange(
+ testutils.Context(t),
+ v1_0_0.ExecutionStateChangedEvent,
+ offRamp,
+ v1_0_0.ExecutionStateChangedSeqNrIndex,
+ abihelpers.EvmWord(uint64(seqNum)),
+ abihelpers.EvmWord(uint64(seqNum)),
+ 1,
+ )
+ require.NoError(t, err)
+ t.Log("Executed logs", lgs)
+ if len(lgs) == 1 {
+ log = lgs[0]
+ return true
+ }
+ return false
+ }, 10*time.Second, 1*time.Second).Should(gomega.BeFalse(), "seq number got executed")
+ return log
+}
+
+func (node *Node) AddJob(t *testing.T, spec *integrationtesthelpers.OCR2TaskJobSpec) {
+ specString, err := spec.String()
+ require.NoError(t, err)
+ ccipJob, err := validate.ValidatedOracleSpecToml(
+ testutils.Context(t),
+ node.App.GetConfig().OCR2(),
+ node.App.GetConfig().Insecure(),
+ specString,
+ // FIXME Ani
+ nil,
+ )
+ require.NoError(t, err)
+ err = node.App.AddJobV2(context.Background(), &ccipJob)
+ require.NoError(t, err)
+}
+
+func (node *Node) AddBootstrapJob(t *testing.T, spec *integrationtesthelpers.OCR2TaskJobSpec) {
+ specString, err := spec.String()
+ require.NoError(t, err)
+ ccipJob, err := ocrbootstrap.ValidatedBootstrapSpecToml(specString)
+ require.NoError(t, err)
+ err = node.App.AddJobV2(context.Background(), &ccipJob)
+ require.NoError(t, err)
+}
+
+func (node *Node) AddJobsWithSpec(t *testing.T, jobSpec *integrationtesthelpers.OCR2TaskJobSpec) {
+ // set node specific values
+ jobSpec.OCR2OracleSpec.OCRKeyBundleID.SetValid(node.KeyBundle.ID())
+ jobSpec.OCR2OracleSpec.TransmitterID.SetValid(node.Transmitter.Hex())
+ node.AddJob(t, jobSpec)
+}
+
+func setupNodeCCIP(
+ t *testing.T,
+ owner *bind.TransactOpts,
+ port int64,
+ dbName string,
+ sourceChain *backends.SimulatedBackend, destChain *backends.SimulatedBackend,
+ sourceChainID *big.Int, destChainID *big.Int,
+ bootstrapPeerID string,
+ bootstrapPort int64,
+) (chainlink.Application, string, common.Address, ocr2key.KeyBundle) {
+ trueRef, falseRef := true, false
+
+ // Do not want to load fixtures as they contain a dummy chainID.
+ loglevel := configv2.LogLevel(zap.DebugLevel)
+ config, db := heavyweight.FullTestDBNoFixturesV2(t, func(c *chainlink.Config, _ *chainlink.Secrets) {
+ p2pAddresses := []string{
+ fmt.Sprintf("127.0.0.1:%d", port),
+ }
+ c.Log.Level = &loglevel
+ c.Feature.UICSAKeys = &trueRef
+ c.Feature.FeedsManager = &trueRef
+ c.OCR.Enabled = &falseRef
+ c.OCR.DefaultTransactionQueueDepth = pointer.Uint32(200)
+ c.OCR2.Enabled = &trueRef
+ c.Feature.LogPoller = &trueRef
+ c.P2P.V2.Enabled = &trueRef
+
+ dur, err := config.NewDuration(500 * time.Millisecond)
+ if err != nil {
+ panic(err)
+ }
+ c.P2P.V2.DeltaDial = &dur
+
+ dur2, err := config.NewDuration(5 * time.Second)
+ if err != nil {
+ panic(err)
+ }
+
+ c.P2P.V2.DeltaReconcile = &dur2
+ c.P2P.V2.ListenAddresses = &p2pAddresses
+ c.P2P.V2.AnnounceAddresses = &p2pAddresses
+
+ c.EVM = []*v2.EVMConfig{createConfigV2Chain(sourceChainID), createConfigV2Chain(destChainID)}
+
+ if bootstrapPeerID != "" {
+ // Supply the bootstrap IP and port as a V2 peer address
+ c.P2P.V2.DefaultBootstrappers = &[]commontypes.BootstrapperLocator{
+ {
+ PeerID: bootstrapPeerID, Addrs: []string{
+ fmt.Sprintf("127.0.0.1:%d", bootstrapPort),
+ },
+ },
+ }
+ }
+ })
+
+ lggr := logger.TestLogger(t)
+
+ // The in-memory geth sim does not let you create a custom ChainID, it will always be 1337.
+ // In particular this means that if you sign an eip155 tx, the chainID used MUST be 1337
+ // and the CHAINID op code will always emit 1337. To work around this to simulate a "multichain"
+ // test, we fake different chainIDs using the wrapped sim cltest.SimulatedBackend so the RPC
+ // appears to operate on different chainIDs and we use an EthKeyStoreSim wrapper which always
+ // signs 1337 see https://github.com/smartcontractkit/chainlink-ccip/blob/a24dd436810250a458d27d8bb3fb78096afeb79c/core/services/ocr2/plugins/ccip/testhelpers/simulated_backend.go#L35
+ sourceClient := client.NewSimulatedBackendClient(t, sourceChain, sourceChainID)
+ destClient := client.NewSimulatedBackendClient(t, destChain, destChainID)
+ csaKeyStore := ksMocks.NewCSA(t)
+
+ key, err := csakey.NewV2()
+ require.NoError(t, err)
+ csaKeyStore.On("GetAll").Return([]csakey.KeyV2{key}, nil)
+ keyStore := NewKsa(db, lggr, csaKeyStore)
+
+ simEthKeyStore := testhelpers.EthKeyStoreSim{
+ ETHKS: keyStore.Eth(),
+ CSAKS: keyStore.CSA(),
+ }
+ mailMon := mailbox.NewMonitor("CCIP", lggr.Named("Mailbox"))
+ evmOpts := chainlink.EVMFactoryConfig{
+ ChainOpts: legacyevm.ChainOpts{
+ AppConfig: config,
+ GenEthClient: func(chainID *big.Int) client.Client {
+ if chainID.String() == sourceChainID.String() {
+ return sourceClient
+ } else if chainID.String() == destChainID.String() {
+ return destClient
+ }
+ t.Fatalf("invalid chain ID %v", chainID.String())
+ return nil
+ },
+ MailMon: mailMon,
+ DS: db,
+ },
+ CSAETHKeystore: simEthKeyStore,
+ }
+ loopRegistry := plugins.NewLoopRegistry(lggr.Named("LoopRegistry"), config.Tracing())
+ relayerFactory := chainlink.RelayerFactory{
+ Logger: lggr,
+ LoopRegistry: loopRegistry,
+ GRPCOpts: loop.GRPCOpts{},
+ CapabilitiesRegistry: coretypes.NewCapabilitiesRegistry(t),
+ }
+ testCtx := testutils.Context(t)
+ // evm alway enabled for backward compatibility
+ initOps := []chainlink.CoreRelayerChainInitFunc{
+ chainlink.InitEVM(testCtx, relayerFactory, evmOpts),
+ }
+
+ relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ app, err := chainlink.NewApplication(chainlink.ApplicationOpts{
+ Config: config,
+ DS: db,
+ KeyStore: keyStore,
+ RelayerChainInteroperators: relayChainInterops,
+ Logger: lggr,
+ ExternalInitiatorManager: nil,
+ CloseLogger: lggr.Sync,
+ UnrestrictedHTTPClient: &http.Client{},
+ RestrictedHTTPClient: &http.Client{},
+ AuditLogger: audit.NoopLogger,
+ MailMon: mailMon,
+ LoopRegistry: plugins.NewLoopRegistry(lggr, config.Tracing()),
+ })
+ ctx := testutils.Context(t)
+ require.NoError(t, err)
+ require.NoError(t, app.GetKeyStore().Unlock(ctx, "password"))
+ _, err = app.GetKeyStore().P2P().Create(ctx)
+ require.NoError(t, err)
+
+ p2pIDs, err := app.GetKeyStore().P2P().GetAll()
+ require.NoError(t, err)
+ require.Len(t, p2pIDs, 1)
+ peerID := p2pIDs[0].PeerID()
+
+ _, err = app.GetKeyStore().Eth().Create(testCtx, destChainID)
+ require.NoError(t, err)
+ sendingKeys, err := app.GetKeyStore().Eth().EnabledKeysForChain(testCtx, destChainID)
+ require.NoError(t, err)
+ require.Len(t, sendingKeys, 1)
+ transmitter := sendingKeys[0].Address
+ s, err := app.GetKeyStore().Eth().GetState(testCtx, sendingKeys[0].ID(), destChainID)
+ require.NoError(t, err)
+ lggr.Debug(fmt.Sprintf("Transmitter address %s chainID %s", transmitter, s.EVMChainID.String()))
+
+ // Fund the commitTransmitter address with some ETH
+ n, err := destChain.NonceAt(context.Background(), owner.From, nil)
+ require.NoError(t, err)
+
+ tx := types3.NewTransaction(n, transmitter, big.NewInt(1000000000000000000), 21000, big.NewInt(1000000000), nil)
+ signedTx, err := owner.Signer(owner.From, tx)
+ require.NoError(t, err)
+ err = destChain.SendTransaction(context.Background(), signedTx)
+ require.NoError(t, err)
+ destChain.Commit()
+
+ kb, err := app.GetKeyStore().OCR2().Create(ctx, chaintype.EVM)
+ require.NoError(t, err)
+ return app, peerID.Raw(), transmitter, kb
+}
+
+func createConfigV2Chain(chainId *big.Int) *v2.EVMConfig {
+ // NOTE: For the executor jobs, the default of 500k is insufficient for a 3 message batch
+ defaultGasLimit := uint64(5000000)
+ tr := true
+
+ sourceC := v2.Defaults((*evmUtils.Big)(chainId))
+ sourceC.GasEstimator.LimitDefault = &defaultGasLimit
+ fixedPrice := "FixedPrice"
+ sourceC.GasEstimator.Mode = &fixedPrice
+ d, _ := config.NewDuration(100 * time.Millisecond)
+ sourceC.LogPollInterval = &d
+ fd := uint32(2)
+ sourceC.FinalityDepth = &fd
+ return &v2.EVMConfig{
+ ChainID: (*evmUtils.Big)(chainId),
+ Enabled: &tr,
+ Chain: sourceC,
+ Nodes: v2.EVMNodes{&v2.Node{}},
+ }
+}
+
+type CCIPIntegrationTestHarness struct {
+ CCIPContracts
+ Nodes []Node
+ Bootstrap Node
+}
+
+func SetupCCIPIntegrationTH(t *testing.T, sourceChainID, sourceChainSelector, destChainId, destChainSelector uint64) CCIPIntegrationTestHarness {
+ return CCIPIntegrationTestHarness{
+ CCIPContracts: SetupCCIPContracts(t, sourceChainID, sourceChainSelector, destChainId, destChainSelector),
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) CreatePricesPipeline(t *testing.T) (string, *httptest.Server, *httptest.Server) {
+ linkUSD := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(`{"UsdPerLink": "8000000000000000000"}`))
+ require.NoError(t, err)
+ }))
+ ethUSD := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+ _, err := w.Write([]byte(`{"UsdPerETH": "1700000000000000000000"}`))
+ require.NoError(t, err)
+ }))
+ sourceWrappedNative, err := c.Source.Router.GetWrappedNative(nil)
+ require.NoError(t, err)
+ destWrappedNative, err := c.Dest.Router.GetWrappedNative(nil)
+ require.NoError(t, err)
+ tokenPricesUSDPipeline := fmt.Sprintf(`
+// Price 1
+link [type=http method=GET url="%s"];
+link_parse [type=jsonparse path="UsdPerLink"];
+link->link_parse;
+eth [type=http method=GET url="%s"];
+eth_parse [type=jsonparse path="UsdPerETH"];
+eth->eth_parse;
+merge [type=merge left="{}" right="{\\\"%s\\\":$(link_parse), \\\"%s\\\":$(eth_parse), \\\"%s\\\":$(eth_parse)}"];`,
+ linkUSD.URL, ethUSD.URL, c.Dest.LinkToken.Address(), sourceWrappedNative, destWrappedNative)
+
+ return tokenPricesUSDPipeline, linkUSD, ethUSD
+}
+
+func (c *CCIPIntegrationTestHarness) AddAllJobs(t *testing.T, jobParams integrationtesthelpers.CCIPJobSpecParams) {
+ jobParams.OffRamp = c.Dest.OffRamp.Address()
+
+ commitSpec, err := jobParams.CommitJobSpec()
+ require.NoError(t, err)
+ geExecutionSpec, err := jobParams.ExecutionJobSpec()
+ require.NoError(t, err)
+ nodes := c.Nodes
+ for _, node := range nodes {
+ node.AddJobsWithSpec(t, commitSpec)
+ node.AddJobsWithSpec(t, geExecutionSpec)
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) jobSpecProposal(t *testing.T, specTemplate string, f func() (*integrationtesthelpers.OCR2TaskJobSpec, error), feedsManagerId int64, version int32, opts ...any) feeds2.ProposeJobArgs {
+ spec, err := f()
+ require.NoError(t, err)
+
+ args := []any{spec.OCR2OracleSpec.ContractID}
+ args = append(args, opts...)
+
+ return feeds2.ProposeJobArgs{
+ FeedsManagerID: feedsManagerId,
+ RemoteUUID: uuid.New(),
+ Multiaddrs: nil,
+ Version: version,
+ Spec: fmt.Sprintf(specTemplate, args...),
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) SetupFeedsManager(t *testing.T) {
+ ctx := testutils.Context(t)
+ for _, node := range c.Nodes {
+ f := node.App.GetFeedsService()
+
+ managers, err := f.ListManagers(ctx)
+ require.NoError(t, err)
+ if len(managers) > 0 {
+ // Use at most one feeds manager, don't register if one already exists
+ continue
+ }
+
+ secret := utils.RandomBytes32()
+ pkey, err := crypto.PublicKeyFromHex(hex.EncodeToString(secret[:]))
+ require.NoError(t, err)
+
+ m := feeds2.RegisterManagerParams{
+ Name: "CCIP",
+ URI: "http://localhost:8080",
+ PublicKey: *pkey,
+ }
+
+ _, err = f.RegisterManager(testutils.Context(t), m)
+ require.NoError(t, err)
+
+ connManager := feedsMocks.NewConnectionsManager(t)
+ connManager.On("GetClient", mock.Anything).Maybe().Return(NoopFeedsClient{}, nil)
+ connManager.On("Close").Maybe().Return()
+ connManager.On("IsConnected", mock.Anything).Maybe().Return(true)
+ f.Unsafe_SetConnectionsManager(connManager)
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) ApproveJobSpecs(t *testing.T, jobParams integrationtesthelpers.CCIPJobSpecParams) {
+ ctx := testutils.Context(t)
+
+ for _, node := range c.Nodes {
+ f := node.App.GetFeedsService()
+ managers, err := f.ListManagers(ctx)
+ require.NoError(t, err)
+ require.Len(t, managers, 1, "expected exactly one feeds manager")
+
+ execSpec := c.jobSpecProposal(
+ t,
+ execSpecTemplate,
+ jobParams.ExecutionJobSpec,
+ managers[0].ID,
+ 1,
+ node.KeyBundle.ID(),
+ node.Transmitter.Hex(),
+ utils.RandomAddress().String(),
+ utils.RandomAddress().String(),
+ )
+ execId, err := f.ProposeJob(ctx, &execSpec)
+ require.NoError(t, err)
+
+ err = f.ApproveSpec(ctx, execId, true)
+ require.NoError(t, err)
+
+ var commitSpec feeds2.ProposeJobArgs
+ if jobParams.TokenPricesUSDPipeline != "" {
+ commitSpec = c.jobSpecProposal(
+ t,
+ commitSpecTemplatePipeline,
+ jobParams.CommitJobSpec,
+ managers[0].ID,
+ 2,
+ node.KeyBundle.ID(),
+ node.Transmitter.Hex(),
+ jobParams.OffRamp.String(),
+ jobParams.TokenPricesUSDPipeline,
+ )
+ } else {
+ commitSpec = c.jobSpecProposal(
+ t,
+ commitSpecTemplateDynamicPriceGetter,
+ jobParams.CommitJobSpec,
+ managers[0].ID,
+ 2,
+ node.KeyBundle.ID(),
+ node.Transmitter.Hex(),
+ jobParams.OffRamp.String(),
+ jobParams.PriceGetterConfig,
+ )
+ }
+
+ commitId, err := f.ProposeJob(ctx, &commitSpec)
+ require.NoError(t, err)
+
+ err = f.ApproveSpec(ctx, commitId, true)
+ require.NoError(t, err)
+ }
+}
+
+func (c *CCIPIntegrationTestHarness) AllNodesHaveReqSeqNum(t *testing.T, seqNum int, onRampOpts ...common.Address) logpoller.Log {
+ var log logpoller.Log
+ nodes := c.Nodes
+ var onRamp common.Address
+ if len(onRampOpts) > 0 {
+ onRamp = onRampOpts[0]
+ } else {
+ require.NotNil(t, c.Source.OnRamp, "no onramp configured")
+ onRamp = c.Source.OnRamp.Address()
+ }
+ for _, node := range nodes {
+ log = node.EventuallyHasReqSeqNum(t, c, onRamp, seqNum)
+ }
+ return log
+}
+
+func (c *CCIPIntegrationTestHarness) AllNodesHaveExecutedSeqNums(t *testing.T, minSeqNum int, maxSeqNum int, offRampOpts ...common.Address) []logpoller.Log {
+ var logs []logpoller.Log
+ nodes := c.Nodes
+ var offRamp common.Address
+
+ if len(offRampOpts) > 0 {
+ offRamp = offRampOpts[0]
+ } else {
+ require.NotNil(t, c.Dest.OffRamp, "no offramp configured")
+ offRamp = c.Dest.OffRamp.Address()
+ }
+ for _, node := range nodes {
+ logs = node.EventuallyHasExecutedSeqNums(t, c, offRamp, minSeqNum, maxSeqNum)
+ }
+ return logs
+}
+
+func (c *CCIPIntegrationTestHarness) NoNodesHaveExecutedSeqNum(t *testing.T, seqNum int, offRampOpts ...common.Address) logpoller.Log {
+ var log logpoller.Log
+ nodes := c.Nodes
+ var offRamp common.Address
+ if len(offRampOpts) > 0 {
+ offRamp = offRampOpts[0]
+ } else {
+ require.NotNil(t, c.Dest.OffRamp, "no offramp configured")
+ offRamp = c.Dest.OffRamp.Address()
+ }
+ for _, node := range nodes {
+ log = node.ConsistentlySeqNumHasNotBeenExecuted(t, c, offRamp, seqNum)
+ }
+ return log
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallyCommitReportAccepted(t *testing.T, currentBlock uint64, commitStoreOpts ...common.Address) commit_store_1_2_0.CommitStoreCommitReport {
+ var commitStore *commit_store_1_2_0.CommitStore
+ var err error
+ if len(commitStoreOpts) > 0 {
+ commitStore, err = commit_store_1_2_0.NewCommitStore(commitStoreOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.CommitStore, "no commitStore configured")
+ commitStore = c.Dest.CommitStore
+ }
+ g := gomega.NewGomegaWithT(t)
+ var report commit_store_1_2_0.CommitStoreCommitReport
+ g.Eventually(func() bool {
+ it, err := commitStore.FilterReportAccepted(&bind.FilterOpts{Start: currentBlock})
+ g.Expect(err).NotTo(gomega.HaveOccurred(), "Error filtering ReportAccepted event")
+ g.Expect(it.Next()).To(gomega.BeTrue(), "No ReportAccepted event found")
+ report = it.Event.Report
+ if report.MerkleRoot != [32]byte{} {
+ t.Log("Report Accepted by commitStore")
+ return true
+ }
+ return false
+ }, testutils.WaitTimeout(t), 1*time.Second).Should(gomega.BeTrue(), "report has not been committed")
+ return report
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallyExecutionStateChangedToSuccess(t *testing.T, seqNum []uint64, blockNum uint64, offRampOpts ...common.Address) {
+ var offRamp *evm_2_evm_offramp_1_2_0.EVM2EVMOffRamp
+ var err error
+ if len(offRampOpts) > 0 {
+ offRamp, err = evm_2_evm_offramp_1_2_0.NewEVM2EVMOffRamp(offRampOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.OffRamp, "no offRamp configured")
+ offRamp = c.Dest.OffRamp
+ }
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ it, err := offRamp.FilterExecutionStateChanged(&bind.FilterOpts{Start: blockNum}, seqNum, [][32]byte{})
+ require.NoError(t, err)
+ for it.Next() {
+ if cciptypes.MessageExecutionState(it.Event.State) == cciptypes.ExecutionStateSuccess {
+ t.Logf("ExecutionStateChanged event found for seqNum %d", it.Event.SequenceNumber)
+ return true
+ }
+ }
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ return false
+ }, testutils.WaitTimeout(t), time.Second).
+ Should(gomega.BeTrue(), "ExecutionStateChanged Event")
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallyReportCommitted(t *testing.T, max int, commitStoreOpts ...common.Address) uint64 {
+ var commitStore *commit_store_1_2_0.CommitStore
+ var err error
+ var committedSeqNum uint64
+ if len(commitStoreOpts) > 0 {
+ commitStore, err = commit_store_1_2_0.NewCommitStore(commitStoreOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.CommitStore, "no commitStore configured")
+ commitStore = c.Dest.CommitStore
+ }
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ minSeqNum, err := commitStore.GetExpectedNextSequenceNumber(nil)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ t.Log("next expected seq num reported", minSeqNum)
+ committedSeqNum = minSeqNum
+ return minSeqNum > uint64(max)
+ }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue(), "report has not been committed")
+ return committedSeqNum
+}
+
+func (c *CCIPIntegrationTestHarness) EventuallySendRequested(t *testing.T, seqNum uint64, onRampOpts ...common.Address) {
+ var onRamp *evm_2_evm_onramp_1_2_0.EVM2EVMOnRamp
+ var err error
+ if len(onRampOpts) > 0 {
+ onRamp, err = evm_2_evm_onramp_1_2_0.NewEVM2EVMOnRamp(onRampOpts[0], c.Source.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Source.OnRamp, "no onRamp configured")
+ onRamp = c.Source.OnRamp
+ }
+ gomega.NewGomegaWithT(t).Eventually(func() bool {
+ it, err := onRamp.FilterCCIPSendRequested(nil)
+ require.NoError(t, err)
+ for it.Next() {
+ if it.Event.Message.SequenceNumber == seqNum {
+ t.Log("sendRequested generated for", seqNum)
+ return true
+ }
+ }
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ return false
+ }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue(), "sendRequested has not been generated")
+}
+
+func (c *CCIPIntegrationTestHarness) ConsistentlyReportNotCommitted(t *testing.T, max int, commitStoreOpts ...common.Address) {
+ var commitStore *commit_store_1_2_0.CommitStore
+ var err error
+ if len(commitStoreOpts) > 0 {
+ commitStore, err = commit_store_1_2_0.NewCommitStore(commitStoreOpts[0], c.Dest.Chain)
+ require.NoError(t, err)
+ } else {
+ require.NotNil(t, c.Dest.CommitStore, "no commitStore configured")
+ commitStore = c.Dest.CommitStore
+ }
+ gomega.NewGomegaWithT(t).Consistently(func() bool {
+ minSeqNum, err := commitStore.GetExpectedNextSequenceNumber(nil)
+ require.NoError(t, err)
+ c.Source.Chain.Commit()
+ c.Dest.Chain.Commit()
+ t.Log("min seq num reported", minSeqNum)
+ return minSeqNum > uint64(max)
+ }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeFalse(), "report has been committed")
+}
+
+func (c *CCIPIntegrationTestHarness) SetupAndStartNodes(ctx context.Context, t *testing.T, bootstrapNodePort int64) (Node, []Node, int64) {
+ appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNodeCCIP(t, c.Dest.User, bootstrapNodePort,
+ "bootstrap_ccip", c.Source.Chain, c.Dest.Chain, big.NewInt(0).SetUint64(c.Source.ChainID),
+ big.NewInt(0).SetUint64(c.Dest.ChainID), "", 0)
+ var (
+ oracles []confighelper.OracleIdentityExtra
+ nodes []Node
+ )
+ err := appBootstrap.Start(ctx)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ require.NoError(t, appBootstrap.Stop())
+ })
+ bootstrapNode := Node{
+ App: appBootstrap,
+ Transmitter: bootstrapTransmitter,
+ KeyBundle: bootstrapKb,
+ }
+ // Set up the minimum 4 oracles all funded with destination ETH
+ for i := int64(0); i < 4; i++ {
+ app, peerID, transmitter, kb := setupNodeCCIP(
+ t,
+ c.Dest.User,
+ int64(freeport.GetOne(t)),
+ fmt.Sprintf("oracle_ccip%d", i),
+ c.Source.Chain,
+ c.Dest.Chain,
+ big.NewInt(0).SetUint64(c.Source.ChainID),
+ big.NewInt(0).SetUint64(c.Dest.ChainID),
+ bootstrapPeerID,
+ bootstrapNodePort,
+ )
+ nodes = append(nodes, Node{
+ App: app,
+ Transmitter: transmitter,
+ KeyBundle: kb,
+ })
+ offchainPublicKey, _ := hex.DecodeString(strings.TrimPrefix(kb.OnChainPublicKey(), "0x"))
+ oracles = append(oracles, confighelper.OracleIdentityExtra{
+ OracleIdentity: confighelper.OracleIdentity{
+ OnchainPublicKey: offchainPublicKey,
+ TransmitAccount: types4.Account(transmitter.String()),
+ OffchainPublicKey: kb.OffchainPublicKey(),
+ PeerID: peerID,
+ },
+ ConfigEncryptionPublicKey: kb.ConfigEncryptionPublicKey(),
+ })
+ err = app.Start(ctx)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ require.NoError(t, app.Stop())
+ })
+ }
+
+ c.Oracles = oracles
+ commitOnchainConfig := c.CreateDefaultCommitOnchainConfig(t)
+ commitOffchainConfig := c.CreateDefaultCommitOffchainConfig(t)
+ execOnchainConfig := c.CreateDefaultExecOnchainConfig(t)
+ execOffchainConfig := c.CreateDefaultExecOffchainConfig(t)
+
+ configBlock := c.SetupOnchainConfig(t, commitOnchainConfig, commitOffchainConfig, execOnchainConfig, execOffchainConfig)
+ c.Nodes = nodes
+ c.Bootstrap = bootstrapNode
+ return bootstrapNode, nodes, configBlock
+}
+
+func (c *CCIPIntegrationTestHarness) SetUpNodesAndJobs(t *testing.T, pricePipeline string, priceGetterConfig string, usdcAttestationAPI string) integrationtesthelpers.CCIPJobSpecParams {
+ // setup Jobs
+ ctx := context.Background()
+ // Starts nodes and configures them in the OCR contracts.
+ bootstrapNode, _, configBlock := c.SetupAndStartNodes(ctx, t, int64(freeport.GetOne(t)))
+
+ jobParams := c.NewCCIPJobSpecParams(pricePipeline, priceGetterConfig, configBlock, usdcAttestationAPI)
+
+ // Add the bootstrap job
+ c.Bootstrap.AddBootstrapJob(t, jobParams.BootstrapJob(c.Dest.CommitStore.Address().Hex()))
+ c.AddAllJobs(t, jobParams)
+
+ // Replay for bootstrap.
+ bc, err := bootstrapNode.App.GetRelayers().LegacyEVMChains().Get(strconv.FormatUint(c.Dest.ChainID, 10))
+ require.NoError(t, err)
+ require.NoError(t, bc.LogPoller().Replay(context.Background(), configBlock))
+ c.Dest.Chain.Commit()
+
+ return jobParams
+}
+
+func (c *CCIPIntegrationTestHarness) NewCCIPJobSpecParams(tokenPricesUSDPipeline string, priceGetterConfig string, configBlock int64, usdcAttestationAPI string) integrationtesthelpers.CCIPJobSpecParams {
+ return integrationtesthelpers.CCIPJobSpecParams{
+ CommitStore: c.Dest.CommitStore.Address(),
+ OffRamp: c.Dest.OffRamp.Address(),
+ DestEvmChainId: c.Dest.ChainID,
+ SourceChainName: "SimulatedSource",
+ DestChainName: "SimulatedDest",
+ TokenPricesUSDPipeline: tokenPricesUSDPipeline,
+ PriceGetterConfig: priceGetterConfig,
+ DestStartBlock: uint64(configBlock),
+ USDCAttestationAPI: usdcAttestationAPI,
+ }
+}
+
+func DecodeCommitOnChainConfig(encoded []byte) (ccipdata.CommitOnchainConfig, error) {
+ var onchainConfig ccipdata.CommitOnchainConfig
+ unpacked, err := abihelpers.DecodeOCR2Config(encoded)
+ if err != nil {
+ return onchainConfig, err
+ }
+ onChainCfg := unpacked.OnchainConfig
+ onchainConfig, err = abihelpers.DecodeAbiStruct[ccipdata.CommitOnchainConfig](onChainCfg)
+ if err != nil {
+ return onchainConfig, err
+ }
+ return onchainConfig, nil
+}
+
+func DecodeExecOnChainConfig(encoded []byte) (v1_2_0.ExecOnchainConfig, error) {
+ var onchainConfig v1_2_0.ExecOnchainConfig
+ unpacked, err := abihelpers.DecodeOCR2Config(encoded)
+ if err != nil {
+ return onchainConfig, errors.Wrap(err, "failed to unpack log data")
+ }
+ onChainCfg := unpacked.OnchainConfig
+ onchainConfig, err = abihelpers.DecodeAbiStruct[v1_2_0.ExecOnchainConfig](onChainCfg)
+ if err != nil {
+ return onchainConfig, err
+ }
+ return onchainConfig, nil
+}
+
+type ksa struct {
+ keystore.Master
+ csa keystore.CSA
+}
+
+func (k *ksa) CSA() keystore.CSA {
+ return k.csa
+}
+
+func NewKsa(db *sqlx.DB, lggr logger.Logger, csa keystore.CSA) *ksa {
+ return &ksa{
+ Master: keystore.New(db, clutils.FastScryptParams, lggr),
+ csa: csa,
+ }
+}
+
+type NoopFeedsClient struct{}
+
+func (n NoopFeedsClient) ApprovedJob(context.Context, *pb.ApprovedJobRequest) (*pb.ApprovedJobResponse, error) {
+ return &pb.ApprovedJobResponse{}, nil
+}
+
+func (n NoopFeedsClient) Healthcheck(context.Context, *pb.HealthcheckRequest) (*pb.HealthcheckResponse, error) {
+ return &pb.HealthcheckResponse{}, nil
+}
+
+func (n NoopFeedsClient) UpdateNode(context.Context, *pb.UpdateNodeRequest) (*pb.UpdateNodeResponse, error) {
+ return &pb.UpdateNodeResponse{}, nil
+}
+
+func (n NoopFeedsClient) RejectedJob(context.Context, *pb.RejectedJobRequest) (*pb.RejectedJobResponse, error) {
+ return &pb.RejectedJobResponse{}, nil
+}
+
+func (n NoopFeedsClient) CancelledJob(context.Context, *pb.CancelledJobRequest) (*pb.CancelledJobResponse, error) {
+ return &pb.CancelledJobResponse{}, nil
+}
diff --git a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/config_1_4_0.go b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/config_1_4_0.go
new file mode 100644
index 00000000000..751ae5c1a92
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/config_1_4_0.go
@@ -0,0 +1,73 @@
+// Package with set of configs that should be used only within tests suites
+
+package testhelpers_1_4_0
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+)
+
+var PermissionLessExecutionThresholdSeconds = uint32(testhelpers.FirstBlockAge.Seconds())
+
+func (c *CCIPContracts) CreateDefaultCommitOnchainConfig(t *testing.T) []byte {
+ config, err := abihelpers.EncodeAbiStruct(ccipdata.CommitOnchainConfig{
+ PriceRegistry: c.Dest.PriceRegistry.Address(),
+ })
+ require.NoError(t, err)
+ return config
+}
+
+func (c *CCIPContracts) CreateDefaultCommitOffchainConfig(t *testing.T) []byte {
+ return c.createCommitOffchainConfig(t, 10*time.Second, 5*time.Second)
+}
+
+func (c *CCIPContracts) createCommitOffchainConfig(t *testing.T, feeUpdateHearBeat time.Duration, inflightCacheExpiry time.Duration) []byte {
+ config, err := NewCommitOffchainConfig(
+ *config.MustNewDuration(feeUpdateHearBeat),
+ 1,
+ 1,
+ *config.MustNewDuration(feeUpdateHearBeat),
+ 1,
+ *config.MustNewDuration(inflightCacheExpiry),
+ ).Encode()
+ require.NoError(t, err)
+ return config
+}
+
+func (c *CCIPContracts) CreateDefaultExecOnchainConfig(t *testing.T) []byte {
+ config, err := abihelpers.EncodeAbiStruct(v1_2_0.ExecOnchainConfig{
+ PermissionLessExecutionThresholdSeconds: PermissionLessExecutionThresholdSeconds,
+ Router: c.Dest.Router.Address(),
+ PriceRegistry: c.Dest.PriceRegistry.Address(),
+ MaxDataBytes: 1e5,
+ MaxNumberOfTokensPerMsg: 5,
+ MaxPoolReleaseOrMintGas: 200_000,
+ })
+ require.NoError(t, err)
+ return config
+}
+
+func (c *CCIPContracts) CreateDefaultExecOffchainConfig(t *testing.T) []byte {
+ return c.createExecOffchainConfig(t, 1*time.Minute, 1*time.Minute)
+}
+
+func (c *CCIPContracts) createExecOffchainConfig(t *testing.T, inflightCacheExpiry time.Duration, rootSnoozeTime time.Duration) []byte {
+ config, err := NewExecOffchainConfig(
+ 1,
+ 5_000_000,
+ 0.07,
+ *config.MustNewDuration(inflightCacheExpiry),
+ *config.MustNewDuration(rootSnoozeTime),
+ ).Encode()
+ require.NoError(t, err)
+ return config
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/bgworker.go b/core/services/ocr2/plugins/ccip/tokendata/bgworker.go
new file mode 100644
index 00000000000..1a74ab2305b
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/bgworker.go
@@ -0,0 +1,213 @@
+package tokendata
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "sync"
+ "time"
+
+ "github.com/patrickmn/go-cache"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+)
+
+type msgResult struct {
+ TokenAmountIndex int
+ Err error
+ Data []byte
+}
+
+type Worker interface {
+ job.ServiceCtx
+ // AddJobsFromMsgs will include the provided msgs for background processing.
+ AddJobsFromMsgs(ctx context.Context, msgs []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta)
+
+ // GetMsgTokenData returns the token data for the provided msg. If data are not ready it keeps waiting
+ // until they get ready. Important: Make sure to pass a proper context with timeout.
+ GetMsgTokenData(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) ([][]byte, error)
+
+ GetReaders() map[cciptypes.Address]Reader
+}
+
+type BackgroundWorker struct {
+ tokenDataReaders map[cciptypes.Address]Reader
+ numWorkers int
+ jobsChan chan cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta
+ resultsCache *cache.Cache
+ timeoutDur time.Duration
+
+ services.StateMachine
+ wg *sync.WaitGroup
+ backgroundCtx context.Context //nolint:containedctx
+ backgroundCancel context.CancelFunc
+}
+
+func NewBackgroundWorker(
+ tokenDataReaders map[cciptypes.Address]Reader,
+ numWorkers int,
+ timeoutDur time.Duration,
+ expirationDur time.Duration,
+) *BackgroundWorker {
+ if expirationDur == 0 {
+ expirationDur = 24 * time.Hour
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ return &BackgroundWorker{
+ tokenDataReaders: tokenDataReaders,
+ numWorkers: numWorkers,
+ jobsChan: make(chan cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, numWorkers*100),
+ resultsCache: cache.New(expirationDur, expirationDur/2),
+ timeoutDur: timeoutDur,
+
+ wg: new(sync.WaitGroup),
+ backgroundCtx: ctx,
+ backgroundCancel: cancel,
+ }
+}
+
+func (w *BackgroundWorker) Start(context.Context) error {
+ return w.StateMachine.StartOnce("Token BackgroundWorker", func() error {
+ for i := 0; i < w.numWorkers; i++ {
+ w.wg.Add(1)
+ w.run()
+ }
+ return nil
+ })
+}
+
+func (w *BackgroundWorker) Close() error {
+ return w.StateMachine.StopOnce("Token BackgroundWorker", func() error {
+ w.backgroundCancel()
+ w.wg.Wait()
+ return nil
+ })
+}
+
+func (w *BackgroundWorker) AddJobsFromMsgs(ctx context.Context, msgs []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) {
+ w.wg.Add(1)
+ go func() {
+ defer w.wg.Done()
+ for _, msg := range msgs {
+ select {
+ case <-w.backgroundCtx.Done():
+ return
+ case <-ctx.Done():
+ return
+ default:
+ if len(msg.TokenAmounts) > 0 {
+ w.jobsChan <- msg
+ }
+ }
+ }
+ }()
+}
+
+func (w *BackgroundWorker) GetReaders() map[cciptypes.Address]Reader {
+ return w.tokenDataReaders
+}
+
+func (w *BackgroundWorker) GetMsgTokenData(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) ([][]byte, error) {
+ res, err := w.getMsgTokenData(ctx, msg.SequenceNumber)
+ if err != nil {
+ return nil, err
+ }
+
+ tokenDatas := make([][]byte, len(msg.TokenAmounts))
+ for _, r := range res {
+ if r.Err != nil {
+ return nil, r.Err
+ }
+ if r.TokenAmountIndex < 0 || r.TokenAmountIndex >= len(msg.TokenAmounts) {
+ return nil, fmt.Errorf("token data index inconsistency")
+ }
+ tokenDatas[r.TokenAmountIndex] = r.Data
+ }
+
+ return tokenDatas, nil
+}
+
+func (w *BackgroundWorker) run() {
+ go func() {
+ defer w.wg.Done()
+ for {
+ select {
+ case <-w.backgroundCtx.Done():
+ return
+ case msg := <-w.jobsChan:
+ w.workOnMsg(w.backgroundCtx, msg)
+ }
+ }
+ }()
+}
+
+func (w *BackgroundWorker) workOnMsg(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta) {
+ results := make([]msgResult, 0, len(msg.TokenAmounts))
+
+ cachedTokenData := make(map[int]msgResult) // tokenAmount index -> token data
+ if cachedData, exists := w.getFromCache(msg.SequenceNumber); exists {
+ for _, r := range cachedData {
+ cachedTokenData[r.TokenAmountIndex] = r
+ }
+ }
+
+ for i, token := range msg.TokenAmounts {
+ offchainTokenDataProvider, exists := w.tokenDataReaders[token.Token]
+ if !exists {
+ // No token data required
+ continue
+ }
+
+ // if the result exists in the cache and there wasn't any error keep the existing result
+ if cachedResult, exists := cachedTokenData[i]; exists && cachedResult.Err == nil {
+ results = append(results, cachedResult)
+ continue
+ }
+
+ // if there was any error or if the data do not exist in the cache make a call to the provider
+ timeoutCtx, cf := context.WithTimeout(ctx, w.timeoutDur)
+ tknData, err := offchainTokenDataProvider.ReadTokenData(timeoutCtx, msg, i)
+ cf()
+ results = append(results, msgResult{
+ TokenAmountIndex: i,
+ Err: err,
+ Data: tknData,
+ })
+ }
+
+ w.resultsCache.Set(strconv.FormatUint(msg.SequenceNumber, 10), results, cache.DefaultExpiration)
+}
+
+func (w *BackgroundWorker) getMsgTokenData(ctx context.Context, seqNum uint64) ([]msgResult, error) {
+ if msgTokenData, exists := w.getFromCache(seqNum); exists {
+ return msgTokenData, nil
+ }
+
+ ctx, cf := context.WithTimeout(ctx, w.timeoutDur)
+ defer cf()
+
+ // wait until the results are ready or until context timeout is reached
+ tick := time.NewTicker(100 * time.Millisecond)
+ for {
+ select {
+ case <-ctx.Done():
+ return nil, context.DeadlineExceeded
+ case <-tick.C:
+ if msgTokenData, exists := w.getFromCache(seqNum); exists {
+ return msgTokenData, nil
+ }
+ }
+ }
+}
+
+func (w *BackgroundWorker) getFromCache(seqNum uint64) ([]msgResult, bool) {
+ rawResult, found := w.resultsCache.Get(strconv.FormatUint(seqNum, 10))
+ if !found {
+ return nil, false
+ }
+ return rawResult.([]msgResult), true
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/bgworker_test.go b/core/services/ocr2/plugins/ccip/tokendata/bgworker_test.go
new file mode 100644
index 00000000000..5d505363ac7
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/bgworker_test.go
@@ -0,0 +1,188 @@
+package tokendata_test
+
+import (
+ "context"
+ "fmt"
+ "math/rand"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+)
+
+func TestBackgroundWorker(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ const numTokens = 100
+ const numWorkers = 20
+ const numMessages = 40
+ const maxReaderLatencyMS = 200
+ const percentOfTokensWithoutTokenData = 10
+
+ tokens := make([]cciptypes.Address, numTokens)
+ readers := make(map[cciptypes.Address]*tokendata.MockReader, numTokens)
+ tokenDataReaders := make(map[cciptypes.Address]tokendata.Reader, numTokens)
+ tokenData := make(map[cciptypes.Address][]byte)
+ delays := make(map[cciptypes.Address]time.Duration)
+
+ for i := range tokens {
+ tokens[i] = cciptypes.Address(utils.RandomAddress().String())
+ readers[tokens[i]] = tokendata.NewMockReader(t)
+ if rand.Intn(100) >= percentOfTokensWithoutTokenData {
+ tokenDataReaders[tokens[i]] = readers[tokens[i]]
+ tokenData[tokens[i]] = []byte(fmt.Sprintf("...token %x data...", tokens[i]))
+ }
+
+ // specify a random latency for the reader implementation
+ readerLatency := rand.Intn(maxReaderLatencyMS)
+ delays[tokens[i]] = time.Duration(readerLatency) * time.Millisecond
+ }
+ w := tokendata.NewBackgroundWorker(tokenDataReaders, numWorkers, 5*time.Second, time.Hour)
+ require.NoError(t, w.Start(ctx))
+
+ msgs := make([]cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, numMessages)
+ for i := range msgs {
+ tk := tokens[i%len(tokens)]
+
+ msgs[i] = cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: uint64(i + 1),
+ TokenAmounts: []cciptypes.TokenAmount{{Token: tk}},
+ },
+ }
+
+ reader := readers[tk]
+ reader.On("ReadTokenData", mock.Anything, msgs[i], 0).Run(func(args mock.Arguments) {
+ time.Sleep(delays[tk])
+ }).Return(tokenData[tk], nil).Maybe()
+ }
+
+ w.AddJobsFromMsgs(ctx, msgs)
+ // processing of the messages should have started at this point
+
+ tStart := time.Now()
+ for _, msg := range msgs {
+ b, err := w.GetMsgTokenData(ctx, msg) // fetched from provider
+ assert.NoError(t, err)
+ assert.Equal(t, tokenData[msg.TokenAmounts[0].Token], b[0])
+ }
+ assert.True(t, time.Since(tStart) < 600*time.Millisecond)
+ assert.True(t, time.Since(tStart) > 200*time.Millisecond)
+
+ tStart = time.Now()
+ for _, msg := range msgs {
+ b, err := w.GetMsgTokenData(ctx, msg) // fetched from cache
+ assert.NoError(t, err)
+ assert.Equal(t, tokenData[msg.TokenAmounts[0].Token], b[0])
+ }
+ assert.True(t, time.Since(tStart) < 200*time.Millisecond)
+
+ w.AddJobsFromMsgs(ctx, msgs) // same messages are added but they should already be in cache
+ tStart = time.Now()
+ for _, msg := range msgs {
+ b, err := w.GetMsgTokenData(ctx, msg)
+ assert.NoError(t, err)
+ assert.Equal(t, tokenData[msg.TokenAmounts[0].Token], b[0])
+ }
+ assert.True(t, time.Since(tStart) < 200*time.Millisecond)
+
+ require.NoError(t, w.Close())
+}
+
+func TestBackgroundWorker_RetryOnErrors(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ tk1 := cciptypes.Address(utils.RandomAddress().String())
+ tk2 := cciptypes.Address(utils.RandomAddress().String())
+
+ rdr1 := tokendata.NewMockReader(t)
+ rdr2 := tokendata.NewMockReader(t)
+
+ w := tokendata.NewBackgroundWorker(map[cciptypes.Address]tokendata.Reader{
+ tk1: rdr1,
+ tk2: rdr2,
+ }, 10, 5*time.Second, time.Hour)
+ require.NoError(t, w.Start(ctx))
+
+ msgs := []cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: uint64(1),
+ TokenAmounts: []cciptypes.TokenAmount{{Token: tk1}},
+ }},
+ {EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: uint64(2),
+ TokenAmounts: []cciptypes.TokenAmount{{Token: tk2}},
+ }},
+ }
+
+ rdr1.On("ReadTokenData", mock.Anything, msgs[0], 0).
+ Return([]byte("some data"), nil).Once()
+
+ // reader2 returns an error
+ rdr2.On("ReadTokenData", mock.Anything, msgs[1], 0).
+ Return(nil, fmt.Errorf("some err")).Once()
+
+ w.AddJobsFromMsgs(ctx, msgs)
+ // processing of the messages should have started at this point
+
+ tokenData, err := w.GetMsgTokenData(ctx, msgs[0])
+ assert.NoError(t, err)
+ assert.Equal(t, []byte("some data"), tokenData[0])
+
+ _, err = w.GetMsgTokenData(ctx, msgs[1])
+ assert.Error(t, err)
+ assert.Errorf(t, err, "some error")
+
+ // we make the second reader to return data
+ rdr2.On("ReadTokenData", mock.Anything, msgs[1], 0).
+ Return([]byte("some other data"), nil).Once()
+
+ // add the jobs again, at this point jobs that previously returned
+ // an error are removed from the cache
+ w.AddJobsFromMsgs(ctx, msgs)
+
+ // since reader1 returned some data before, we expect to get the cached result
+ tokenData, err = w.GetMsgTokenData(ctx, msgs[0])
+ assert.NoError(t, err)
+ assert.Equal(t, []byte("some data"), tokenData[0])
+
+ // wait some time for msg2 to be re-processed and error overwritten
+ time.Sleep(20 * time.Millisecond) // todo: improve the test
+
+ // for reader2 that returned an error before we expect to get data now
+ tokenData, err = w.GetMsgTokenData(ctx, msgs[1])
+ assert.NoError(t, err)
+ assert.Equal(t, []byte("some other data"), tokenData[0])
+
+ require.NoError(t, w.Close())
+}
+
+func TestBackgroundWorker_Timeout(t *testing.T) {
+ ctx := testutils.Context(t)
+
+ tk1 := cciptypes.Address(utils.RandomAddress().String())
+ tk2 := cciptypes.Address(utils.RandomAddress().String())
+
+ rdr1 := tokendata.NewMockReader(t)
+ rdr2 := tokendata.NewMockReader(t)
+
+ w := tokendata.NewBackgroundWorker(
+ map[cciptypes.Address]tokendata.Reader{tk1: rdr1, tk2: rdr2}, 10, 5*time.Second, time.Hour)
+ require.NoError(t, w.Start(ctx))
+
+ ctx, cf := context.WithTimeout(ctx, 500*time.Millisecond)
+ defer cf()
+
+ _, err := w.GetMsgTokenData(ctx, cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{SequenceNumber: 1}},
+ )
+ assert.Error(t, err)
+ require.NoError(t, w.Close())
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/http/http_client.go b/core/services/ocr2/plugins/ccip/tokendata/http/http_client.go
new file mode 100644
index 00000000000..79ec21b1b83
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/http/http_client.go
@@ -0,0 +1,48 @@
+package http
+
+import (
+ "context"
+ "io"
+ "net/http"
+ "time"
+
+ "github.com/pkg/errors"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+)
+
+type IHttpClient interface {
+ // Get issue a GET request to the given url and return the response body and status code.
+ Get(ctx context.Context, url string, timeout time.Duration) ([]byte, int, http.Header, error)
+}
+
+type HttpClient struct {
+}
+
+func (s *HttpClient) Get(ctx context.Context, url string, timeout time.Duration) ([]byte, int, http.Header, error) {
+ // Use a timeout to guard against attestation API hanging, causing observation timeout and failing to make any progress.
+ timeoutCtx, cancel := context.WithTimeoutCause(ctx, timeout, tokendata.ErrTimeout)
+ defer cancel()
+ req, err := http.NewRequestWithContext(timeoutCtx, http.MethodGet, url, nil)
+ if err != nil {
+ return nil, http.StatusBadRequest, nil, err
+ }
+ req.Header.Add("accept", "application/json")
+ res, err := http.DefaultClient.Do(req)
+ if err != nil {
+ if errors.Is(err, context.DeadlineExceeded) {
+ return nil, http.StatusRequestTimeout, nil, tokendata.ErrTimeout
+ }
+ // On error, res is nil in most cases, do not read res.StatusCode, return BadRequest
+ return nil, http.StatusBadRequest, nil, err
+ }
+ defer res.Body.Close()
+
+ // Explicitly signal if the API is being rate limited
+ if res.StatusCode == http.StatusTooManyRequests {
+ return nil, res.StatusCode, res.Header, tokendata.ErrRateLimit
+ }
+
+ body, err := io.ReadAll(res.Body)
+ return body, res.StatusCode, res.Header, err
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/http/observed_http_client.go b/core/services/ocr2/plugins/ccip/tokendata/http/observed_http_client.go
new file mode 100644
index 00000000000..d8fb9b1c576
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/http/observed_http_client.go
@@ -0,0 +1,69 @@
+package http
+
+import (
+ "context"
+ "net/http"
+ "strconv"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+)
+
+var (
+ usdcLatencyBuckets = []float64{
+ float64(10 * time.Millisecond),
+ float64(25 * time.Millisecond),
+ float64(50 * time.Millisecond),
+ float64(75 * time.Millisecond),
+ float64(100 * time.Millisecond),
+ float64(250 * time.Millisecond),
+ float64(500 * time.Millisecond),
+ float64(750 * time.Millisecond),
+ float64(1 * time.Second),
+ float64(2 * time.Second),
+ float64(3 * time.Second),
+ float64(4 * time.Second),
+ float64(5 * time.Second),
+ }
+ usdcClientHistogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Name: "ccip_usdc_client_request_total",
+ Help: "Latency of calls to the USDC client",
+ Buckets: usdcLatencyBuckets,
+ }, []string{"status", "success"})
+)
+
+type ObservedIHttpClient struct {
+ IHttpClient
+ histogram *prometheus.HistogramVec
+}
+
+// NewObservedIHttpClient Create a new ObservedIHttpClient with the USDC client metric.
+func NewObservedIHttpClient(origin IHttpClient) *ObservedIHttpClient {
+ return NewObservedIHttpClientWithMetric(origin, usdcClientHistogram)
+}
+
+func NewObservedIHttpClientWithMetric(origin IHttpClient, histogram *prometheus.HistogramVec) *ObservedIHttpClient {
+ return &ObservedIHttpClient{
+ IHttpClient: origin,
+ histogram: histogram,
+ }
+}
+
+func (o *ObservedIHttpClient) Get(ctx context.Context, url string, timeout time.Duration) ([]byte, int, http.Header, error) {
+ return withObservedHttpClient(o.histogram, func() ([]byte, int, http.Header, error) {
+ return o.IHttpClient.Get(ctx, url, timeout)
+ })
+}
+
+func withObservedHttpClient[T any](histogram *prometheus.HistogramVec, contract func() (T, int, http.Header, error)) (T, int, http.Header, error) {
+ contractExecutionStarted := time.Now()
+ value, status, headers, err := contract()
+ histogram.
+ WithLabelValues(
+ strconv.FormatInt(int64(status), 10),
+ strconv.FormatBool(err == nil),
+ ).
+ Observe(float64(time.Since(contractExecutionStarted)))
+ return value, status, headers, err
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/observability/usdc_client_test.go b/core/services/ocr2/plugins/ccip/tokendata/observability/usdc_client_test.go
new file mode 100644
index 00000000000..0567b725a8b
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/observability/usdc_client_test.go
@@ -0,0 +1,151 @@
+package observability
+
+import (
+ "context"
+ "encoding/json"
+ "math/big"
+ "math/rand"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "testing"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+ io_prometheus_client "github.com/prometheus/client_model/go"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+ http2 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata/http"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata/usdc"
+)
+
+type expected struct {
+ status string
+ result string
+ count int
+}
+
+func TestUSDCClientMonitoring(t *testing.T) {
+ tests := []struct {
+ name string
+ server *httptest.Server
+ requests int
+ expected []expected
+ }{
+ {
+ name: "success",
+ server: newSuccessServer(t),
+ requests: 5,
+ expected: []expected{
+ {"200", "true", 5},
+ {"429", "false", 0},
+ },
+ },
+ {
+ name: "rate_limited",
+ server: newRateLimitedServer(),
+ requests: 26,
+ expected: []expected{
+ {"200", "true", 0},
+ {"429", "false", 1},
+ },
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ testMonitoring(t, test.name, test.server, test.requests, test.expected, logger.TestLogger(t))
+ })
+ }
+}
+
+func testMonitoring(t *testing.T, name string, server *httptest.Server, requests int, expected []expected, log logger.Logger) {
+ server.Start()
+ defer server.Close()
+ attestationURI, err := url.ParseRequestURI(server.URL)
+ require.NoError(t, err)
+
+ // Define test histogram (avoid side effects from other tests if using the real usdcHistogram).
+ histogram := promauto.NewHistogramVec(prometheus.HistogramOpts{
+ Name: "test_client_histogram_" + name,
+ Help: "Latency of calls to the USDC mock client",
+ Buckets: []float64{float64(250 * time.Millisecond), float64(1 * time.Second), float64(5 * time.Second)},
+ }, []string{"status", "success"})
+
+ // Mock USDC reader.
+ usdcReader := mocks.NewUSDCReader(t)
+ msgBody := []byte{0xb0, 0xd1}
+ usdcReader.On("GetUSDCMessagePriorToLogIndexInTx", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(msgBody, nil)
+
+ // Service with monitored http client.
+ usdcTokenAddr := utils.RandomAddress()
+ observedHttpClient := http2.NewObservedIHttpClientWithMetric(&http2.HttpClient{}, histogram)
+ tokenDataReaderDefault := usdc.NewUSDCTokenDataReader(log, usdcReader, attestationURI, 0, usdcTokenAddr, usdc.APIIntervalRateLimitDisabled)
+ tokenDataReader := usdc.NewUSDCTokenDataReaderWithHttpClient(*tokenDataReaderDefault, observedHttpClient, usdcTokenAddr, usdc.APIIntervalRateLimitDisabled)
+ require.NotNil(t, tokenDataReader)
+
+ for i := 0; i < requests; i++ {
+ _, _ = tokenDataReader.ReadTokenData(context.Background(), cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ TokenAmounts: []cciptypes.TokenAmount{
+ {
+ Token: ccipcalc.EvmAddrToGeneric(usdcTokenAddr),
+ Amount: big.NewInt(rand.Int63()),
+ },
+ },
+ },
+ }, 0)
+ }
+
+ // Check that the metrics are updated as expected.
+ for _, e := range expected {
+ assert.Equal(t, e.count, counterFromHistogramByLabels(t, histogram, e.status, e.result))
+ }
+}
+
+func counterFromHistogramByLabels(t *testing.T, histogramVec *prometheus.HistogramVec, labels ...string) int {
+ observer, err := histogramVec.GetMetricWithLabelValues(labels...)
+ require.NoError(t, err)
+
+ metricCh := make(chan prometheus.Metric, 1)
+ observer.(prometheus.Histogram).Collect(metricCh)
+ close(metricCh)
+
+ metric := <-metricCh
+ pb := &io_prometheus_client.Metric{}
+ err = metric.Write(pb)
+ require.NoError(t, err)
+
+ return int(pb.GetHistogram().GetSampleCount())
+}
+
+func newSuccessServer(t *testing.T) *httptest.Server {
+ return httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ response := struct {
+ Status string `json:"status"`
+ Attestation string `json:"attestation"`
+ }{
+ Status: "complete",
+ Attestation: "720502893578a89a8a87982982ef781c18b193",
+ }
+ responseBytes, err := json.Marshal(response)
+ require.NoError(t, err)
+ _, err = w.Write(responseBytes)
+ require.NoError(t, err)
+ }))
+}
+
+func newRateLimitedServer() *httptest.Server {
+ return httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusTooManyRequests)
+ }))
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/reader.go b/core/services/ocr2/plugins/ccip/tokendata/reader.go
new file mode 100644
index 00000000000..16646bc7c5e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/reader.go
@@ -0,0 +1,19 @@
+package tokendata
+
+import (
+ "errors"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+)
+
+var (
+ ErrNotReady = errors.New("token data not ready")
+ ErrRateLimit = errors.New("token data API is being rate limited")
+ ErrTimeout = errors.New("token data API timed out")
+ ErrRequestsBlocked = errors.New("requests are currently blocked")
+)
+
+// Reader is an interface for fetching offchain token data
+type Reader interface {
+ cciptypes.TokenDataReader
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/reader_mock.go b/core/services/ocr2/plugins/ccip/tokendata/reader_mock.go
new file mode 100644
index 00000000000..39166d61590
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/reader_mock.go
@@ -0,0 +1,143 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package tokendata
+
+import (
+ context "context"
+
+ ccip "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// MockReader is an autogenerated mock type for the Reader type
+type MockReader struct {
+ mock.Mock
+}
+
+type MockReader_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockReader) EXPECT() *MockReader_Expecter {
+ return &MockReader_Expecter{mock: &_m.Mock}
+}
+
+// Close provides a mock function with given fields:
+func (_m *MockReader) Close() error {
+ ret := _m.Called()
+
+ if len(ret) == 0 {
+ panic("no return value specified for Close")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func() error); ok {
+ r0 = rf()
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// MockReader_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
+type MockReader_Close_Call struct {
+ *mock.Call
+}
+
+// Close is a helper method to define mock.On call
+func (_e *MockReader_Expecter) Close() *MockReader_Close_Call {
+ return &MockReader_Close_Call{Call: _e.mock.On("Close")}
+}
+
+func (_c *MockReader_Close_Call) Run(run func()) *MockReader_Close_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run()
+ })
+ return _c
+}
+
+func (_c *MockReader_Close_Call) Return(_a0 error) *MockReader_Close_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *MockReader_Close_Call) RunAndReturn(run func() error) *MockReader_Close_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ReadTokenData provides a mock function with given fields: ctx, msg, tokenIndex
+func (_m *MockReader) ReadTokenData(ctx context.Context, msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int) ([]byte, error) {
+ ret := _m.Called(ctx, msg, tokenIndex)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ReadTokenData")
+ }
+
+ var r0 []byte
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta, int) ([]byte, error)); ok {
+ return rf(ctx, msg, tokenIndex)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta, int) []byte); ok {
+ r0 = rf(ctx, msg, tokenIndex)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]byte)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta, int) error); ok {
+ r1 = rf(ctx, msg, tokenIndex)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// MockReader_ReadTokenData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadTokenData'
+type MockReader_ReadTokenData_Call struct {
+ *mock.Call
+}
+
+// ReadTokenData is a helper method to define mock.On call
+// - ctx context.Context
+// - msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta
+// - tokenIndex int
+func (_e *MockReader_Expecter) ReadTokenData(ctx interface{}, msg interface{}, tokenIndex interface{}) *MockReader_ReadTokenData_Call {
+ return &MockReader_ReadTokenData_Call{Call: _e.mock.On("ReadTokenData", ctx, msg, tokenIndex)}
+}
+
+func (_c *MockReader_ReadTokenData_Call) Run(run func(ctx context.Context, msg ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int)) *MockReader_ReadTokenData_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta), args[2].(int))
+ })
+ return _c
+}
+
+func (_c *MockReader_ReadTokenData_Call) Return(tokenData []byte, err error) *MockReader_ReadTokenData_Call {
+ _c.Call.Return(tokenData, err)
+ return _c
+}
+
+func (_c *MockReader_ReadTokenData_Call) RunAndReturn(run func(context.Context, ccip.EVM2EVMOnRampCCIPSendRequestedWithMeta, int) ([]byte, error)) *MockReader_ReadTokenData_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockReader creates a new instance of MockReader. 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 NewMockReader(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockReader {
+ mock := &MockReader{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc.go b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc.go
new file mode 100644
index 00000000000..aaa6086fbc9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc.go
@@ -0,0 +1,339 @@
+package usdc
+
+import (
+ "context"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "net/url"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/pkg/errors"
+ "golang.org/x/time/rate"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata/http"
+)
+
+const (
+ apiVersion = "v1"
+ attestationPath = "attestations"
+ defaultAttestationTimeout = 5 * time.Second
+
+ // defaultCoolDownDurationSec defines the default time to wait after getting rate limited.
+ // this value is only used if the 429 response does not contain the Retry-After header
+ defaultCoolDownDuration = 5 * time.Minute
+
+ // maxCoolDownDuration defines the maximum duration we can wait till firing the next request
+ maxCoolDownDuration = 10 * time.Minute
+
+ // defaultRequestInterval defines the rate in requests per second that the attestation API can be called.
+ // this is set according to the APIs documentated 10 requests per second rate limit.
+ defaultRequestInterval = 100 * time.Millisecond
+
+ // APIIntervalRateLimitDisabled is a special value to disable the rate limiting.
+ APIIntervalRateLimitDisabled = -1
+ // APIIntervalRateLimitDefault is a special value to select the default rate limit interval.
+ APIIntervalRateLimitDefault = 0
+)
+
+type attestationStatus string
+
+const (
+ attestationStatusSuccess attestationStatus = "complete"
+ attestationStatusPending attestationStatus = "pending_confirmations"
+)
+
+var (
+ ErrUnknownResponse = errors.New("unexpected response from attestation API")
+)
+
+// messageAndAttestation has to match the onchain struct `MessageAndAttestation` in the
+// USDC token pool.
+type messageAndAttestation struct {
+ Message []byte
+ Attestation []byte
+}
+
+func (m messageAndAttestation) AbiString() string {
+ return `
+ [{
+ "components": [
+ {"name": "message", "type": "bytes"},
+ {"name": "attestation", "type": "bytes"}
+ ],
+ "type": "tuple"
+ }]`
+}
+
+func (m messageAndAttestation) Validate() error {
+ if len(m.Message) == 0 {
+ return errors.New("message must be non-empty")
+ }
+ if len(m.Attestation) == 0 {
+ return errors.New("attestation must be non-empty")
+ }
+ return nil
+}
+
+type TokenDataReader struct {
+ lggr logger.Logger
+ usdcReader ccipdata.USDCReader
+ httpClient http.IHttpClient
+ attestationApi *url.URL
+ attestationApiTimeout time.Duration
+ usdcTokenAddress common.Address
+ rate *rate.Limiter
+
+ // coolDownUntil defines whether requests are blocked or not.
+ coolDownUntil time.Time
+ coolDownMu *sync.RWMutex
+}
+
+type attestationResponse struct {
+ Status attestationStatus `json:"status"`
+ Attestation string `json:"attestation"`
+ Error string `json:"error"`
+}
+
+var _ tokendata.Reader = &TokenDataReader{}
+
+func NewUSDCTokenDataReader(
+ lggr logger.Logger,
+ usdcReader ccipdata.USDCReader,
+ usdcAttestationApi *url.URL,
+ usdcAttestationApiTimeoutSeconds int,
+ usdcTokenAddress common.Address,
+ requestInterval time.Duration,
+) *TokenDataReader {
+ timeout := time.Duration(usdcAttestationApiTimeoutSeconds) * time.Second
+ if usdcAttestationApiTimeoutSeconds == 0 {
+ timeout = defaultAttestationTimeout
+ }
+
+ if requestInterval == APIIntervalRateLimitDisabled {
+ requestInterval = 0
+ } else if requestInterval == APIIntervalRateLimitDefault {
+ requestInterval = defaultRequestInterval
+ }
+
+ return &TokenDataReader{
+ lggr: lggr,
+ usdcReader: usdcReader,
+ httpClient: http.NewObservedIHttpClient(&http.HttpClient{}),
+ attestationApi: usdcAttestationApi,
+ attestationApiTimeout: timeout,
+ usdcTokenAddress: usdcTokenAddress,
+ coolDownMu: &sync.RWMutex{},
+ rate: rate.NewLimiter(rate.Every(requestInterval), 1),
+ }
+}
+
+func NewUSDCTokenDataReaderWithHttpClient(
+ origin TokenDataReader,
+ httpClient http.IHttpClient,
+ usdcTokenAddress common.Address,
+ requestInterval time.Duration,
+) *TokenDataReader {
+ return &TokenDataReader{
+ lggr: origin.lggr,
+ usdcReader: origin.usdcReader,
+ httpClient: httpClient,
+ attestationApi: origin.attestationApi,
+ attestationApiTimeout: origin.attestationApiTimeout,
+ coolDownMu: origin.coolDownMu,
+ usdcTokenAddress: usdcTokenAddress,
+ rate: rate.NewLimiter(rate.Every(requestInterval), 1),
+ }
+}
+
+// ReadTokenData queries the USDC attestation API to construct a message and
+// attestation response. When called back to back, or multiple times
+// concurrently, responses are delayed according how the request interval is
+// configured.
+func (s *TokenDataReader) ReadTokenData(ctx context.Context, msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int) ([]byte, error) {
+ if tokenIndex < 0 || tokenIndex >= len(msg.TokenAmounts) {
+ return nil, fmt.Errorf("token index out of bounds")
+ }
+
+ if s.inCoolDownPeriod() {
+ // rate limiting cool-down period, we prevent new requests from being sent
+ return nil, tokendata.ErrRequestsBlocked
+ }
+
+ if s.rate != nil {
+ // Wait blocks until it the attestation API can be called or the
+ // context is Done.
+ if waitErr := s.rate.Wait(ctx); waitErr != nil {
+ return nil, fmt.Errorf("usdc rate limiting error: %w", waitErr)
+ }
+ }
+
+ messageBody, err := s.getUSDCMessageBody(ctx, msg, tokenIndex)
+ if err != nil {
+ return []byte{}, errors.Wrap(err, "failed getting the USDC message body")
+ }
+
+ msgID := hexutil.Encode(msg.MessageID[:])
+ msgBody := hexutil.Encode(messageBody)
+ s.lggr.Infow("Calling attestation API", "messageBodyHash", msgBody, "messageID", msgID)
+
+ // The attestation API expects the hash of the message body
+ attestationResp, err := s.callAttestationApi(ctx, utils.Keccak256Fixed(messageBody))
+ if err != nil {
+ return []byte{}, errors.Wrap(err, "failed calling usdc attestation API ")
+ }
+
+ s.lggr.Infow("Got response from attestation API", "messageID", msgID,
+ "attestationStatus", attestationResp.Status, "attestation", attestationResp.Attestation,
+ "attestationError", attestationResp.Error)
+
+ switch attestationResp.Status {
+ case attestationStatusSuccess:
+ // The USDC pool needs a combination of the message body and the attestation
+ messageAndAttestation, err := encodeMessageAndAttestation(messageBody, attestationResp.Attestation)
+ if err != nil {
+ return nil, fmt.Errorf("failed to encode messageAndAttestation : %w", err)
+ }
+ return messageAndAttestation, nil
+ case attestationStatusPending:
+ return nil, tokendata.ErrNotReady
+ default:
+ s.lggr.Errorw("Unexpected response from attestation API", "attestationResp", attestationResp)
+ return nil, ErrUnknownResponse
+ }
+}
+
+// encodeMessageAndAttestation encodes the message body and attestation into a single byte array
+// that is readable onchain.
+func encodeMessageAndAttestation(messageBody []byte, attestation string) ([]byte, error) {
+ attestationBytes, err := hex.DecodeString(strings.TrimPrefix(attestation, "0x"))
+ if err != nil {
+ return nil, fmt.Errorf("failed to decode response attestation: %w", err)
+ }
+
+ return abihelpers.EncodeAbiStruct[messageAndAttestation](messageAndAttestation{
+ Message: messageBody,
+ Attestation: attestationBytes,
+ })
+}
+
+func (s *TokenDataReader) getUSDCMessageBody(
+ ctx context.Context,
+ msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta,
+ tokenIndex int,
+) ([]byte, error) {
+ usdcTokenEndOffset, err := s.getUsdcTokenEndOffset(msg, tokenIndex)
+ if err != nil {
+ return nil, fmt.Errorf("get usdc token %d end offset: %w", tokenIndex, err)
+ }
+
+ parsedMsgBody, err := s.usdcReader.GetUSDCMessagePriorToLogIndexInTx(ctx, int64(msg.LogIndex), usdcTokenEndOffset, msg.TxHash)
+ if err != nil {
+ return []byte{}, err
+ }
+
+ s.lggr.Infow("Got USDC message body", "messageBody", hexutil.Encode(parsedMsgBody), "messageID", hexutil.Encode(msg.MessageID[:]))
+ return parsedMsgBody, nil
+}
+
+func (s *TokenDataReader) getUsdcTokenEndOffset(msg cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta, tokenIndex int) (int, error) {
+ if tokenIndex >= len(msg.TokenAmounts) || tokenIndex < 0 {
+ return 0, fmt.Errorf("invalid token index %d for msg with %d tokens", tokenIndex, len(msg.TokenAmounts))
+ }
+
+ if msg.TokenAmounts[tokenIndex].Token != ccipcalc.EvmAddrToGeneric(s.usdcTokenAddress) {
+ return 0, fmt.Errorf("the specified token index %d is not a usdc token", tokenIndex)
+ }
+
+ usdcTokenEndOffset := 0
+ for i := tokenIndex + 1; i < len(msg.TokenAmounts); i++ {
+ evmTokenAddr, err := ccipcalc.GenericAddrToEvm(msg.TokenAmounts[i].Token)
+ if err != nil {
+ continue
+ }
+
+ if evmTokenAddr == s.usdcTokenAddress {
+ usdcTokenEndOffset++
+ }
+ }
+
+ return usdcTokenEndOffset, nil
+}
+
+// callAttestationApi calls the USDC attestation API with the given USDC message hash.
+// The attestation service rate limit is 10 requests per second. If you exceed 10 requests
+// per second, the service blocks all API requests for the next 5 minutes and returns an
+// HTTP 429 response.
+//
+// Documentation:
+//
+// https://developers.circle.com/stablecoins/reference/getattestation
+// https://developers.circle.com/stablecoins/docs/transfer-usdc-on-testnet-from-ethereum-to-avalanche
+func (s *TokenDataReader) callAttestationApi(ctx context.Context, usdcMessageHash [32]byte) (attestationResponse, error) {
+ body, _, headers, err := s.httpClient.Get(
+ ctx,
+ fmt.Sprintf("%s/%s/%s/0x%x", s.attestationApi, apiVersion, attestationPath, usdcMessageHash),
+ s.attestationApiTimeout,
+ )
+ switch {
+ case errors.Is(err, tokendata.ErrRateLimit):
+ coolDownDuration := defaultCoolDownDuration
+ if retryAfterHeader, exists := headers["Retry-After"]; exists && len(retryAfterHeader) > 0 {
+ if retryAfterSec, errParseInt := strconv.ParseInt(retryAfterHeader[0], 10, 64); errParseInt == nil {
+ coolDownDuration = time.Duration(retryAfterSec) * time.Second
+ }
+ }
+ s.setCoolDownPeriod(coolDownDuration)
+
+ // Explicitly signal if the API is being rate limited
+ return attestationResponse{}, tokendata.ErrRateLimit
+ case err != nil:
+ return attestationResponse{}, fmt.Errorf("request error: %w", err)
+ }
+
+ var response attestationResponse
+ err = json.Unmarshal(body, &response)
+ if err != nil {
+ return attestationResponse{}, err
+ }
+ if response.Error != "" {
+ return attestationResponse{}, fmt.Errorf("attestation API error: %s", response.Error)
+ }
+ if response.Status == "" {
+ return attestationResponse{}, fmt.Errorf("invalid attestation response: %s", string(body))
+ }
+ return response, nil
+}
+
+func (s *TokenDataReader) setCoolDownPeriod(d time.Duration) {
+ s.coolDownMu.Lock()
+ if d > maxCoolDownDuration {
+ d = maxCoolDownDuration
+ }
+ s.coolDownUntil = time.Now().Add(d)
+ s.coolDownMu.Unlock()
+}
+
+func (s *TokenDataReader) inCoolDownPeriod() bool {
+ s.coolDownMu.RLock()
+ defer s.coolDownMu.RUnlock()
+ return time.Now().Before(s.coolDownUntil)
+}
+
+func (s *TokenDataReader) Close() error {
+ return nil
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_blackbox_test.go b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_blackbox_test.go
new file mode 100644
index 00000000000..95b309ff74e
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_blackbox_test.go
@@ -0,0 +1,119 @@
+package usdc_test
+
+import (
+ "context"
+ "encoding/hex"
+ "encoding/json"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ ccipdatamocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata/usdc"
+)
+
+type attestationResponse struct {
+ Status string `json:"status"`
+ Attestation string `json:"attestation"`
+}
+
+func TestUSDCReader_ReadTokenData(t *testing.T) {
+ tests := []struct {
+ name string
+ attestationResponse attestationResponse
+ expectedError error
+ }{
+ {
+ name: "status complete",
+ attestationResponse: attestationResponse{
+ Status: "complete",
+ Attestation: "0x9049623e91719ef2aa63c55f357be2529b0e7122ae552c18aff8db58b4633c4d3920ff03d3a6d1ddf11f06bf64d7fd60d45447ac81f527ba628877dc5ca759651b08ffae25a6d3b1411749765244f0a1c131cbfe04430d687a2e12fd9d2e6dc08e118ad95d94ad832332cf3c4f7a4f3da0baa803b7be024b02db81951c0f0714de1b",
+ },
+ expectedError: nil,
+ },
+ {
+ name: "status pending",
+ attestationResponse: attestationResponse{
+ Status: "pending_confirmations",
+ Attestation: "720502893578a89a8a87982982ef781c18b193",
+ },
+ expectedError: tokendata.ErrNotReady,
+ },
+ {
+ name: "status invalid",
+ attestationResponse: attestationResponse{
+ Status: "invalid",
+ Attestation: "720502893578a89a8a87982982ef781c18b193",
+ },
+ expectedError: usdc.ErrUnknownResponse,
+ },
+ }
+ for _, test := range tests {
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ // Message is the bytes itself from MessageSend(bytes message)
+ // i.e. ABI parsed.
+ message := "0x0000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc0861"
+ expectedMessageAndAttestation := "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000f80000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc0861000000000000000000000000000000000000000000000000000000000000000000000000000000829049623e91719ef2aa63c55f357be2529b0e7122ae552c18aff8db58b4633c4d3920ff03d3a6d1ddf11f06bf64d7fd60d45447ac81f527ba628877dc5ca759651b08ffae25a6d3b1411749765244f0a1c131cbfe04430d687a2e12fd9d2e6dc08e118ad95d94ad832332cf3c4f7a4f3da0baa803b7be024b02db81951c0f0714de1b000000000000000000000000000000000000000000000000000000000000"
+ lggr := logger.TestLogger(t)
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ messageHash := utils.Keccak256Fixed(hexutil.MustDecode(message))
+ expectedUrl := "/v1/attestations/0x" + hex.EncodeToString(messageHash[:])
+ require.Equal(t, expectedUrl, r.URL.Path)
+
+ responseBytes, err2 := json.Marshal(test.attestationResponse)
+ require.NoError(t, err2)
+
+ _, err2 = w.Write(responseBytes)
+ require.NoError(t, err2)
+ }))
+
+ defer ts.Close()
+
+ seqNum := uint64(23825)
+ txHash := utils.RandomBytes32()
+ logIndex := int64(4)
+
+ usdcReader := ccipdatamocks.USDCReader{}
+ usdcReader.On("GetUSDCMessagePriorToLogIndexInTx",
+ mock.Anything,
+ logIndex,
+ 0,
+ common.Hash(txHash).String(),
+ ).Return(hexutil.MustDecode(message), nil)
+ attestationURI, err := url.ParseRequestURI(ts.URL)
+ require.NoError(t, err)
+
+ addr := utils.RandomAddress()
+ usdcService := usdc.NewUSDCTokenDataReader(lggr, &usdcReader, attestationURI, 0, addr, usdc.APIIntervalRateLimitDisabled)
+ msgAndAttestation, err := usdcService.ReadTokenData(context.Background(), cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ SequenceNumber: seqNum,
+ TokenAmounts: []cciptypes.TokenAmount{{Token: ccipcalc.EvmAddrToGeneric(addr), Amount: nil}},
+ },
+ TxHash: cciptypes.Hash(txHash).String(),
+ LogIndex: uint(logIndex),
+ }, 0)
+ if test.expectedError != nil {
+ require.Error(t, err)
+ require.Equal(t, test.expectedError, err)
+ return
+ }
+ require.NoError(t, err)
+ // Expected attestation for parsed body.
+ require.Equal(t, expectedMessageAndAttestation, hexutil.Encode(msgAndAttestation))
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_test.go b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_test.go
new file mode 100644
index 00000000000..c4221b2dc0f
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/tokendata/usdc/usdc_test.go
@@ -0,0 +1,423 @@
+package usdc
+
+import (
+ "context"
+ "encoding/json"
+ "math/big"
+ "math/rand"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata"
+ ccipdatamocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata"
+)
+
+var (
+ mockMsgTransmitter = utils.RandomAddress()
+)
+
+func TestUSDCReader_callAttestationApi(t *testing.T) {
+ t.Skipf("Skipping test because it uses the real USDC attestation API")
+ usdcMessageHash := "912f22a13e9ccb979b621500f6952b2afd6e75be7eadaed93fc2625fe11c52a2"
+ attestationURI, err := url.ParseRequestURI("https://iris-api-sandbox.circle.com")
+ require.NoError(t, err)
+ lggr := logger.TestLogger(t)
+ usdcReader, _ := ccipdata.NewUSDCReader(lggr, "job_123", mockMsgTransmitter, nil, false)
+ usdcService := NewUSDCTokenDataReader(lggr, usdcReader, attestationURI, 0, common.Address{}, APIIntervalRateLimitDisabled)
+
+ attestation, err := usdcService.callAttestationApi(context.Background(), [32]byte(common.FromHex(usdcMessageHash)))
+ require.NoError(t, err)
+
+ require.Equal(t, attestationStatusPending, attestation.Status)
+ require.Equal(t, "PENDING", attestation.Attestation)
+}
+
+func TestUSDCReader_callAttestationApiMock(t *testing.T) {
+ response := attestationResponse{
+ Status: attestationStatusSuccess,
+ Attestation: "720502893578a89a8a87982982ef781c18b193",
+ }
+
+ ts := getMockUSDCEndpoint(t, response)
+ defer ts.Close()
+ attestationURI, err := url.ParseRequestURI(ts.URL)
+ require.NoError(t, err)
+
+ lggr := logger.TestLogger(t)
+ lp := mocks.NewLogPoller(t)
+ usdcReader, _ := ccipdata.NewUSDCReader(lggr, "job_123", mockMsgTransmitter, lp, false)
+ usdcService := NewUSDCTokenDataReader(lggr, usdcReader, attestationURI, 0, common.Address{}, APIIntervalRateLimitDisabled)
+ attestation, err := usdcService.callAttestationApi(context.Background(), utils.RandomBytes32())
+ require.NoError(t, err)
+
+ require.Equal(t, response.Status, attestation.Status)
+ require.Equal(t, response.Attestation, attestation.Attestation)
+}
+
+func TestUSDCReader_callAttestationApiMockError(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ getTs func() *httptest.Server
+ parentTimeoutSeconds int
+ customTimeoutSeconds int
+ expectedError error
+ }{
+ {
+ name: "server error",
+ getTs: func() *httptest.Server {
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusInternalServerError)
+ }))
+ },
+ parentTimeoutSeconds: 60,
+ expectedError: nil,
+ },
+ {
+ name: "default timeout",
+ getTs: func() *httptest.Server {
+ response := attestationResponse{
+ Status: attestationStatusSuccess,
+ Attestation: "720502893578a89a8a87982982ef781c18b193",
+ }
+ responseBytes, _ := json.Marshal(response)
+
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ time.Sleep(defaultAttestationTimeout + time.Second)
+ _, err := w.Write(responseBytes)
+ require.NoError(t, err)
+ }))
+ },
+ parentTimeoutSeconds: 60,
+ expectedError: tokendata.ErrTimeout,
+ },
+ {
+ name: "custom timeout",
+ getTs: func() *httptest.Server {
+ response := attestationResponse{
+ Status: attestationStatusSuccess,
+ Attestation: "720502893578a89a8a87982982ef781c18b193",
+ }
+ responseBytes, _ := json.Marshal(response)
+
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ time.Sleep(2*time.Second + time.Second)
+ _, err := w.Write(responseBytes)
+ require.NoError(t, err)
+ }))
+ },
+ parentTimeoutSeconds: 60,
+ customTimeoutSeconds: 2,
+ expectedError: tokendata.ErrTimeout,
+ },
+ {
+ name: "error response",
+ getTs: func() *httptest.Server {
+ response := attestationResponse{
+ Error: "some error",
+ }
+ responseBytes, _ := json.Marshal(response)
+
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ _, err := w.Write(responseBytes)
+ require.NoError(t, err)
+ }))
+ },
+ parentTimeoutSeconds: 60,
+ expectedError: nil,
+ },
+ {
+ name: "invalid status",
+ getTs: func() *httptest.Server {
+ response := attestationResponse{
+ Status: "",
+ Attestation: "720502893578a89a8a87982982ef781c18b193",
+ }
+ responseBytes, _ := json.Marshal(response)
+
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ _, err := w.Write(responseBytes)
+ require.NoError(t, err)
+ }))
+ },
+ parentTimeoutSeconds: 60,
+ expectedError: nil,
+ },
+ {
+ name: "rate limit",
+ getTs: func() *httptest.Server {
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusTooManyRequests)
+ }))
+ },
+ parentTimeoutSeconds: 60,
+ expectedError: tokendata.ErrRateLimit,
+ },
+ {
+ name: "parent context timeout",
+ getTs: func() *httptest.Server {
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ time.Sleep(defaultAttestationTimeout + time.Second)
+ }))
+ },
+ parentTimeoutSeconds: 1,
+ expectedError: nil,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ ts := test.getTs()
+ defer ts.Close()
+
+ attestationURI, err := url.ParseRequestURI(ts.URL)
+ require.NoError(t, err)
+
+ lggr := logger.TestLogger(t)
+ lp := mocks.NewLogPoller(t)
+ usdcReader, _ := ccipdata.NewUSDCReader(lggr, "job_123", mockMsgTransmitter, lp, false)
+ usdcService := NewUSDCTokenDataReader(lggr, usdcReader, attestationURI, test.customTimeoutSeconds, common.Address{}, APIIntervalRateLimitDisabled)
+ lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil)
+ require.NoError(t, usdcReader.RegisterFilters())
+
+ parentCtx, cancel := context.WithTimeout(context.Background(), time.Duration(test.parentTimeoutSeconds)*time.Second)
+ defer cancel()
+
+ _, err = usdcService.callAttestationApi(parentCtx, utils.RandomBytes32())
+ require.Error(t, err)
+
+ if test.expectedError != nil {
+ require.True(t, errors.Is(err, test.expectedError))
+ }
+ lp.On("UnregisterFilter", mock.Anything, mock.Anything).Return(nil)
+ require.NoError(t, usdcReader.Close())
+ })
+ }
+}
+
+func getMockUSDCEndpoint(t *testing.T, response attestationResponse) *httptest.Server {
+ responseBytes, err := json.Marshal(response)
+ require.NoError(t, err)
+
+ return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ _, err := w.Write(responseBytes)
+ require.NoError(t, err)
+ }))
+}
+
+func TestGetUSDCMessageBody(t *testing.T) {
+ expectedBody := []byte("0x0000000000000001000000020000000000048d71000000000000000000000000eb08f243e5d3fcff26a9e38ae5520a669f4019d000000000000000000000000023a04d5935ed8bc8e3eb78db3541f0abfb001c6e0000000000000000000000006cb3ed9b441eb674b58495c8b3324b59faff5243000000000000000000000000000000005425890298aed601595a70ab815c96711a31bc65000000000000000000000000ab4f961939bfe6a93567cc57c59eed7084ce2131000000000000000000000000000000000000000000000000000000000000271000000000000000000000000035e08285cfed1ef159236728f843286c55fc0861")
+ usdcReader := ccipdatamocks.USDCReader{}
+ usdcReader.On("GetUSDCMessagePriorToLogIndexInTx", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(expectedBody, nil)
+
+ usdcTokenAddr := utils.RandomAddress()
+ lggr := logger.TestLogger(t)
+ usdcService := NewUSDCTokenDataReader(lggr, &usdcReader, nil, 0, usdcTokenAddr, APIIntervalRateLimitDisabled)
+
+ // Make the first call and assert the underlying function is called
+ body, err := usdcService.getUSDCMessageBody(context.Background(), cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ TokenAmounts: []cciptypes.TokenAmount{
+ {
+ Token: ccipcalc.EvmAddrToGeneric(usdcTokenAddr),
+ Amount: big.NewInt(rand.Int63()),
+ },
+ },
+ },
+ }, 0)
+ require.NoError(t, err)
+ require.Equal(t, body, expectedBody)
+
+ usdcReader.AssertNumberOfCalls(t, "GetUSDCMessagePriorToLogIndexInTx", 1)
+}
+
+func TestTokenDataReader_getUsdcTokenEndOffset(t *testing.T) {
+ usdcToken := utils.RandomAddress()
+ nonUsdcToken := utils.RandomAddress()
+
+ multipleTokens := []common.Address{
+ usdcToken, // 2
+ nonUsdcToken,
+ nonUsdcToken,
+ usdcToken, // 1
+ usdcToken, // 0
+ nonUsdcToken,
+ }
+
+ testCases := []struct {
+ name string
+ tokens []common.Address
+ tokenIndex int
+ expOffset int
+ expErr bool
+ }{
+ {name: "one non usdc token", tokens: []common.Address{nonUsdcToken}, tokenIndex: 0, expOffset: 0, expErr: true},
+ {name: "one usdc token", tokens: []common.Address{usdcToken}, tokenIndex: 0, expOffset: 0, expErr: false},
+ {name: "one usdc token wrong index", tokens: []common.Address{usdcToken}, tokenIndex: 1, expOffset: 0, expErr: true},
+ {name: "multiple tokens 1", tokens: multipleTokens, tokenIndex: 0, expOffset: 2},
+ {name: "multiple tokens - non usdc selected", tokens: multipleTokens, tokenIndex: 2, expErr: true},
+ {name: "multiple tokens 2", tokens: multipleTokens, tokenIndex: 3, expOffset: 1},
+ {name: "multiple tokens 3", tokens: multipleTokens, tokenIndex: 4, expOffset: 0},
+ {name: "multiple tokens not found", tokens: multipleTokens, tokenIndex: 5, expErr: true},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ r := &TokenDataReader{usdcTokenAddress: usdcToken}
+ tokenAmounts := make([]cciptypes.TokenAmount, len(tc.tokens))
+ for i := range tokenAmounts {
+ tokenAmounts[i] = cciptypes.TokenAmount{
+ Token: ccipcalc.EvmAddrToGeneric(tc.tokens[i]),
+ Amount: big.NewInt(rand.Int63()),
+ }
+ }
+ msg := cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{EVM2EVMMessage: cciptypes.EVM2EVMMessage{TokenAmounts: tokenAmounts}}
+ offset, err := r.getUsdcTokenEndOffset(msg, tc.tokenIndex)
+ if tc.expErr {
+ assert.Error(t, err)
+ return
+ }
+ assert.NoError(t, err)
+ assert.Equal(t, tc.expOffset, offset)
+ })
+ }
+}
+
+func TestUSDCReader_rateLimiting(t *testing.T) {
+ testCases := []struct {
+ name string
+ requests uint64
+ rateConfig time.Duration
+ testDuration time.Duration
+ timeout time.Duration
+ err string
+ }{
+ {
+ name: "no rate limit when disabled",
+ requests: 10,
+ rateConfig: APIIntervalRateLimitDisabled,
+ testDuration: 1 * time.Millisecond,
+ },
+ {
+ name: "yes rate limited with default config",
+ requests: 5,
+ rateConfig: APIIntervalRateLimitDefault,
+ testDuration: 4 * defaultRequestInterval,
+ },
+ {
+ name: "yes rate limited with config",
+ requests: 10,
+ rateConfig: 50 * time.Millisecond,
+ testDuration: 9 * 50 * time.Millisecond,
+ },
+ {
+ name: "timeout after first request",
+ requests: 5,
+ rateConfig: 100 * time.Millisecond,
+ testDuration: 1 * time.Millisecond,
+ timeout: 1 * time.Millisecond,
+ err: "usdc rate limiting error:",
+ },
+ {
+ name: "timeout after second request",
+ requests: 5,
+ rateConfig: 100 * time.Millisecond,
+ testDuration: 100 * time.Millisecond,
+ timeout: 150 * time.Millisecond,
+ err: "usdc rate limiting error:",
+ },
+ }
+
+ for _, tc := range testCases {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ response := attestationResponse{
+ Status: attestationStatusSuccess,
+ Attestation: "720502893578a89a8a87982982ef781c18b193",
+ }
+
+ ts := getMockUSDCEndpoint(t, response)
+ defer ts.Close()
+ attestationURI, err := url.ParseRequestURI(ts.URL)
+ require.NoError(t, err)
+
+ lggr := logger.TestLogger(t)
+ lp := mocks.NewLogPoller(t)
+ usdcReader, _ := ccipdata.NewUSDCReader(lggr, "job_123", mockMsgTransmitter, lp, false)
+ usdcService := NewUSDCTokenDataReader(lggr, usdcReader, attestationURI, 0, utils.RandomAddress(), tc.rateConfig)
+
+ ctx := context.Background()
+ if tc.timeout > 0 {
+ var cf context.CancelFunc
+ ctx, cf = context.WithTimeout(ctx, tc.timeout)
+ defer cf()
+ }
+
+ trigger := make(chan struct{})
+ errorChan := make(chan error, tc.requests)
+ wg := sync.WaitGroup{}
+ for i := 0; i < int(tc.requests); i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ <-trigger
+ _, err := usdcService.ReadTokenData(ctx, cciptypes.EVM2EVMOnRampCCIPSendRequestedWithMeta{
+ EVM2EVMMessage: cciptypes.EVM2EVMMessage{
+ TokenAmounts: []cciptypes.TokenAmount{{Token: ccipcalc.EvmAddrToGeneric(utils.ZeroAddress), Amount: nil}}, // trigger failure due to wrong address
+ },
+ }, 0)
+
+ errorChan <- err
+ }()
+ }
+
+ // Start the test
+ start := time.Now()
+ close(trigger)
+
+ // Wait for requests to complete
+ wg.Wait()
+ finish := time.Now()
+ close(errorChan)
+
+ // Collect errors
+ errorFound := false
+ for err := range errorChan {
+ if tc.err != "" && strings.Contains(err.Error(), tc.err) {
+ errorFound = true
+ } else if err != nil && !strings.Contains(err.Error(), "get usdc token 0 end offset") {
+ // Ignore that one error, it's expected because of how mocking is used.
+ // Anything else is unexpected.
+ require.Fail(t, "unexpected error", err)
+ }
+ }
+
+ if tc.err != "" {
+ assert.True(t, errorFound)
+ }
+ assert.WithinDuration(t, start.Add(tc.testDuration), finish, 50*time.Millisecond)
+ })
+ }
+}
diff --git a/core/services/ocr2/plugins/ccip/transactions.rlp b/core/services/ocr2/plugins/ccip/transactions.rlp
new file mode 100644
index 00000000000..96cfc2f4823
Binary files /dev/null and b/core/services/ocr2/plugins/ccip/transactions.rlp differ
diff --git a/core/services/ocr2/plugins/ccip/transmitter/transmitter.go b/core/services/ocr2/plugins/ccip/transmitter/transmitter.go
new file mode 100644
index 00000000000..3e2962b33a9
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/transmitter/transmitter.go
@@ -0,0 +1,143 @@
+package transmitter
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+
+ commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
+ "github.com/smartcontractkit/chainlink/v2/common/txmgr/types"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
+ statuschecker "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/statuschecker"
+)
+
+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)
+ GetTransactionStatus(ctx context.Context, transactionID string) (state commontypes.TransactionStatus, err error)
+}
+
+type Transmitter interface {
+ CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, txMeta *txmgr.TxMeta) error
+ FromAddress() common.Address
+}
+
+type transmitter struct {
+ txm txManager
+ fromAddresses []common.Address
+ gasLimit uint64
+ effectiveTransmitterAddress common.Address
+ strategy types.TxStrategy
+ checker txmgr.TransmitCheckerSpec
+ chainID *big.Int
+ keystore roundRobinKeystore
+ statuschecker statuschecker.CCIPTransactionStatusChecker // Used for CCIP's idempotency key generation
+}
+
+// NewTransmitter creates a new eth transmitter
+func NewTransmitter(
+ txm txManager,
+ fromAddresses []common.Address,
+ gasLimit uint64,
+ effectiveTransmitterAddress common.Address,
+ strategy types.TxStrategy,
+ checker txmgr.TransmitCheckerSpec,
+ chainID *big.Int,
+ keystore roundRobinKeystore,
+) (Transmitter, error) {
+ // Ensure that a keystore is provided.
+ if keystore == nil {
+ return nil, errors.New("nil keystore provided to transmitter")
+ }
+
+ return &transmitter{
+ txm: txm,
+ fromAddresses: fromAddresses,
+ gasLimit: gasLimit,
+ effectiveTransmitterAddress: effectiveTransmitterAddress,
+ strategy: strategy,
+ checker: checker,
+ chainID: chainID,
+ keystore: keystore,
+ }, nil
+}
+
+func NewTransmitterWithStatusChecker(
+ txm txManager,
+ fromAddresses []common.Address,
+ gasLimit uint64,
+ effectiveTransmitterAddress common.Address,
+ strategy types.TxStrategy,
+ checker txmgr.TransmitCheckerSpec,
+ chainID *big.Int,
+ keystore roundRobinKeystore,
+) (Transmitter, error) {
+ t, err := NewTransmitter(txm, fromAddresses, gasLimit, effectiveTransmitterAddress, strategy, checker, chainID, keystore)
+
+ if err != nil {
+ return nil, err
+ }
+
+ transmitter, ok := t.(*transmitter)
+ if !ok {
+ return nil, errors.New("failed to type assert Transmitter to *transmitter")
+ }
+ transmitter.statuschecker = statuschecker.NewTxmStatusChecker(txm.GetTransactionStatus)
+
+ return transmitter, nil
+}
+
+func (t *transmitter) CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, txMeta *txmgr.TxMeta) error {
+ roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(ctx, t.chainID, t.fromAddresses...)
+ if err != nil {
+ return fmt.Errorf("skipped OCR transmission, error getting round-robin address: %w", err)
+ }
+
+ var idempotencyKey *string
+
+ // Define idempotency key for CCIP Execution Plugin
+ if len(txMeta.MessageIDs) == 1 && t.statuschecker != nil {
+ messageId := txMeta.MessageIDs[0]
+ _, count, err1 := t.statuschecker.CheckMessageStatus(ctx, messageId)
+
+ if err1 != nil {
+ return errors.Wrap(err, "skipped OCR transmission, error getting message status")
+ }
+ idempotencyKey = func() *string {
+ s := fmt.Sprintf("%s-%d", messageId, count+1)
+ return &s
+ }()
+ }
+
+ _, err = t.txm.CreateTransaction(ctx, txmgr.TxRequest{
+ IdempotencyKey: idempotencyKey,
+ FromAddress: roundRobinFromAddress,
+ ToAddress: toAddress,
+ EncodedPayload: payload,
+ FeeLimit: t.gasLimit,
+ ForwarderAddress: t.forwarderAddress(),
+ Strategy: t.strategy,
+ Checker: t.checker,
+ Meta: txMeta,
+ })
+ return errors.Wrap(err, "skipped OCR transmission")
+}
+
+func (t *transmitter) FromAddress() common.Address {
+ return t.effectiveTransmitterAddress
+}
+
+func (t *transmitter) forwarderAddress() common.Address {
+ for _, a := range t.fromAddresses {
+ if a == t.effectiveTransmitterAddress {
+ return common.Address{}
+ }
+ }
+ return t.effectiveTransmitterAddress
+}
diff --git a/core/services/ocr2/plugins/ccip/transmitter/transmitter_test.go b/core/services/ocr2/plugins/ccip/transmitter/transmitter_test.go
new file mode 100644
index 00000000000..d177f1baa5c
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/transmitter/transmitter_test.go
@@ -0,0 +1,282 @@
+package transmitter
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/pkg/errors"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+
+ ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+ commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/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/testutils"
+ "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/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
+
+ "github.com/smartcontractkit/chainlink/v2/core/utils"
+)
+
+var (
+ FixtureChainID = *testutils.FixtureChainID
+ Password = testutils.Password
+)
+
+func newMockTxStrategy(t *testing.T) *commontxmmocks.TxStrategy {
+ return commontxmmocks.NewTxStrategy(t)
+}
+
+func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) {
+ t.Parallel()
+
+ db := pgtest.NewSqlxDB(t)
+ ethKeyStore := NewKeyStore(t, db).Eth()
+
+ _, fromAddress := MustInsertRandomKey(t, ethKeyStore)
+
+ gasLimit := uint64(1000)
+ chainID := big.NewInt(0)
+ effectiveTransmitterAddress := fromAddress
+ toAddress := testutils.NewAddress()
+ payload := []byte{1, 2, 3}
+ txm := txmmocks.NewMockEvmTxManager(t)
+ strategy := newMockTxStrategy(t)
+
+ transmitter, err := ocrcommon.NewTransmitter(
+ txm,
+ []common.Address{fromAddress},
+ gasLimit,
+ effectiveTransmitterAddress,
+ strategy,
+ txmgr.TransmitCheckerSpec{},
+ chainID,
+ ethKeyStore,
+ )
+ require.NoError(t, err)
+
+ txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{
+ FromAddress: fromAddress,
+ ToAddress: toAddress,
+ EncodedPayload: payload,
+ FeeLimit: gasLimit,
+ ForwarderAddress: common.Address{},
+ Meta: nil,
+ Strategy: strategy,
+ }).Return(txmgr.Tx{}, nil).Once()
+ require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil))
+}
+
+func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing.T) {
+ t.Parallel()
+
+ db := pgtest.NewSqlxDB(t)
+ ethKeyStore := NewKeyStore(t, db).Eth()
+
+ _, fromAddress := MustInsertRandomKey(t, ethKeyStore)
+ _, fromAddress2 := MustInsertRandomKey(t, ethKeyStore)
+
+ gasLimit := uint64(1000)
+ chainID := big.NewInt(0)
+ effectiveTransmitterAddress := common.Address{}
+ toAddress := testutils.NewAddress()
+ payload := []byte{1, 2, 3}
+ txm := txmmocks.NewMockEvmTxManager(t)
+ strategy := newMockTxStrategy(t)
+
+ transmitter, err := ocrcommon.NewTransmitter(
+ txm,
+ []common.Address{fromAddress, fromAddress2},
+ gasLimit,
+ effectiveTransmitterAddress,
+ strategy,
+ txmgr.TransmitCheckerSpec{},
+ chainID,
+ ethKeyStore,
+ )
+ require.NoError(t, err)
+
+ txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{
+ FromAddress: fromAddress,
+ ToAddress: toAddress,
+ EncodedPayload: payload,
+ FeeLimit: gasLimit,
+ ForwarderAddress: common.Address{},
+ Meta: nil,
+ Strategy: strategy,
+ }).Return(txmgr.Tx{}, nil).Once()
+ txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{
+ FromAddress: fromAddress2,
+ ToAddress: toAddress,
+ EncodedPayload: payload,
+ FeeLimit: gasLimit,
+ ForwarderAddress: common.Address{},
+ Meta: nil,
+ Strategy: strategy,
+ }).Return(txmgr.Tx{}, nil).Once()
+ require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil))
+ require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil))
+}
+
+func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_Round_Robin_Error(t *testing.T) {
+ t.Parallel()
+
+ db := pgtest.NewSqlxDB(t)
+ ethKeyStore := NewKeyStore(t, db).Eth()
+
+ fromAddress := common.Address{}
+
+ gasLimit := uint64(1000)
+ chainID := big.NewInt(0)
+ effectiveTransmitterAddress := common.Address{}
+ toAddress := testutils.NewAddress()
+ payload := []byte{1, 2, 3}
+ txm := txmmocks.NewMockEvmTxManager(t)
+ strategy := newMockTxStrategy(t)
+
+ transmitter, err := ocrcommon.NewTransmitter(
+ txm,
+ []common.Address{fromAddress},
+ gasLimit,
+ effectiveTransmitterAddress,
+ strategy,
+ txmgr.TransmitCheckerSpec{},
+ chainID,
+ ethKeyStore,
+ )
+ require.NoError(t, err)
+ require.Error(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil))
+}
+
+func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore_Error(t *testing.T) {
+ t.Parallel()
+
+ db := pgtest.NewSqlxDB(t)
+ ethKeyStore := NewKeyStore(t, db).Eth()
+
+ _, fromAddress := MustInsertRandomKey(t, ethKeyStore)
+ _, fromAddress2 := MustInsertRandomKey(t, ethKeyStore)
+
+ gasLimit := uint64(1000)
+ chainID := big.NewInt(0)
+ effectiveTransmitterAddress := common.Address{}
+ txm := txmmocks.NewMockEvmTxManager(t)
+ strategy := newMockTxStrategy(t)
+
+ _, err := ocrcommon.NewTransmitter(
+ txm,
+ []common.Address{fromAddress, fromAddress2},
+ gasLimit,
+ effectiveTransmitterAddress,
+ strategy,
+ txmgr.TransmitCheckerSpec{},
+ chainID,
+ nil,
+ )
+ require.Error(t, err)
+}
+
+func Test_Transmitter_With_StatusChecker_CreateEthTransaction(t *testing.T) {
+ t.Parallel()
+
+ db := pgtest.NewSqlxDB(t)
+ ethKeyStore := NewKeyStore(t, db).Eth()
+
+ _, fromAddress := MustInsertRandomKey(t, ethKeyStore)
+
+ gasLimit := uint64(1000)
+ chainID := big.NewInt(0)
+ effectiveTransmitterAddress := fromAddress
+ txm := txmmocks.NewMockEvmTxManager(t)
+ strategy := newMockTxStrategy(t)
+ toAddress := testutils.NewAddress()
+ payload := []byte{1, 2, 3}
+ idempotencyKey := "1-0"
+ txMeta := &txmgr.TxMeta{MessageIDs: []string{"1"}}
+
+ transmitter, err := NewTransmitterWithStatusChecker(
+ txm,
+ []common.Address{fromAddress},
+ gasLimit,
+ effectiveTransmitterAddress,
+ strategy,
+ txmgr.TransmitCheckerSpec{},
+ chainID,
+ ethKeyStore,
+ )
+ require.NoError(t, err)
+
+ // This case is for when the message ID was not found in the status checker
+ txm.On("GetTransactionStatus", mock.Anything, idempotencyKey).Return(types.Unknown, errors.New("dummy")).Once()
+
+ txm.On("CreateTransaction", mock.Anything, txmgr.TxRequest{
+ IdempotencyKey: &idempotencyKey,
+ FromAddress: fromAddress,
+ ToAddress: toAddress,
+ EncodedPayload: payload,
+ FeeLimit: gasLimit,
+ ForwarderAddress: common.Address{},
+ Meta: txMeta,
+ Strategy: strategy,
+ }).Return(txmgr.Tx{}, nil).Once()
+
+ require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, txMeta))
+ txm.AssertExpectations(t)
+}
+
+func NewKeyStore(t testing.TB, ds sqlutil.DataSource) keystore.Master {
+ ctx := testutils.Context(t)
+ keystore := keystore.NewInMemory(ds, utils.FastScryptParams, logger.TestLogger(t))
+ require.NoError(t, keystore.Unlock(ctx, Password))
+ return keystore
+}
+
+type RandomKey struct {
+ Nonce int64
+ Disabled bool
+
+ chainIDs []ubig.Big // nil: Fixture, set empty for none
+}
+
+func (r RandomKey) MustInsert(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) {
+ ctx := testutils.Context(t)
+ chainIDs := r.chainIDs
+ if chainIDs == nil {
+ chainIDs = []ubig.Big{*ubig.New(&FixtureChainID)}
+ }
+
+ key := MustGenerateRandomKey(t)
+ keystore.XXXTestingOnlyAdd(ctx, key)
+
+ for _, cid := range chainIDs {
+ require.NoError(t, keystore.Add(ctx, key.Address, cid.ToInt()))
+ require.NoError(t, keystore.Enable(ctx, key.Address, cid.ToInt()))
+ if r.Disabled {
+ require.NoError(t, keystore.Disable(ctx, key.Address, cid.ToInt()))
+ }
+ }
+
+ return key, key.Address
+}
+
+func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...ubig.Big) (ethkey.KeyV2, common.Address) {
+ r := RandomKey{}
+ if len(chainIDs) > 0 {
+ r.chainIDs = chainIDs
+ }
+ return r.MustInsert(t, keystore)
+}
+
+func MustGenerateRandomKey(t testing.TB) ethkey.KeyV2 {
+ key, err := ethkey.NewV2()
+ require.NoError(t, err)
+ return key
+}
diff --git a/core/services/ocr2/plugins/ccip/vars.go b/core/services/ocr2/plugins/ccip/vars.go
new file mode 100644
index 00000000000..a44f5e41d66
--- /dev/null
+++ b/core/services/ocr2/plugins/ccip/vars.go
@@ -0,0 +1,14 @@
+package ccip
+
+import (
+ "github.com/pkg/errors"
+)
+
+const (
+ MaxQueryLength = 0 // empty for both plugins
+ MaxObservationLength = 250_000 // plugins's Observation should make sure to cap to this limit
+ CommitPluginLabel = "commit"
+ ExecPluginLabel = "exec"
+)
+
+var ErrChainIsNotHealthy = errors.New("lane processing is stopped because of healthcheck failure, please see crit logs")
diff --git a/core/services/ocr2/plugins/mercury/config/config.go b/core/services/ocr2/plugins/mercury/config/config.go
index 5763b883ac0..40854bd8c0a 100644
--- a/core/services/ocr2/plugins/mercury/config/config.go
+++ b/core/services/ocr2/plugins/mercury/config/config.go
@@ -108,7 +108,7 @@ func ValidatePluginConfig(config PluginConfig, feedID mercuryutils.FeedID) (merr
if config.NativeFeedID != nil {
merr = errors.Join(merr, errors.New("nativeFeedID may not be specified for v1 jobs"))
}
- case 2, 3:
+ case 2, 3, 4:
if config.LinkFeedID == nil {
merr = errors.Join(merr, fmt.Errorf("linkFeedID must be specified for v%d jobs", feedID.Version()))
}
@@ -119,7 +119,7 @@ func ValidatePluginConfig(config PluginConfig, feedID mercuryutils.FeedID) (merr
merr = errors.Join(merr, fmt.Errorf("initialBlockNumber may not be specified for v%d jobs", feedID.Version()))
}
default:
- merr = errors.Join(merr, fmt.Errorf("got unsupported schema version %d; supported versions are 1,2,3", feedID.Version()))
+ merr = errors.Join(merr, fmt.Errorf("got unsupported schema version %d; supported versions are 1,2,3,4", feedID.Version()))
}
return merr
diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go
index 43d709453b7..9691e8d4fab 100644
--- a/core/services/ocr2/plugins/mercury/helpers_test.go
+++ b/core/services/ocr2/plugins/mercury/helpers_test.go
@@ -121,6 +121,7 @@ type Feed struct {
baseBenchmarkPrice *big.Int
baseBid *big.Int
baseAsk *big.Int
+ baseMarketStatus uint32
}
func randomFeedID(version uint16) [32]byte {
@@ -467,3 +468,97 @@ chainID = 1337
nativeFeedID,
))
}
+
+func addV4MercuryJob(
+ t *testing.T,
+ node Node,
+ i int,
+ verifierAddress common.Address,
+ bootstrapPeerID string,
+ bootstrapNodePort int,
+ bmBridge,
+ bidBridge,
+ askBridge,
+ marketStatusBridge string,
+ servers map[string]string,
+ clientPubKey ed25519.PublicKey,
+ feedName string,
+ feedID [32]byte,
+ linkFeedID [32]byte,
+ nativeFeedID [32]byte,
+) {
+ srvs := make([]string, 0, len(servers))
+ for u, k := range servers {
+ srvs = append(srvs, fmt.Sprintf("%q = %q", u, k))
+ }
+ serversStr := fmt.Sprintf("{ %s }", strings.Join(srvs, ", "))
+
+ node.AddJob(t, fmt.Sprintf(`
+type = "offchainreporting2"
+schemaVersion = 1
+name = "mercury-%[1]d-%[11]s"
+forwardingAllowed = false
+maxTaskDuration = "1s"
+contractID = "%[2]s"
+feedID = "0x%[10]x"
+contractConfigTrackerPollInterval = "1s"
+ocrKeyBundleID = "%[3]s"
+p2pv2Bootstrappers = [
+ "%[4]s"
+]
+relay = "evm"
+pluginType = "mercury"
+transmitterID = "%[9]x"
+observationSource = """
+ // Benchmark Price
+ price1 [type=bridge name="%[5]s" timeout="50ms" requestData="{\\"data\\":{\\"from\\":\\"ETH\\",\\"to\\":\\"USD\\"}}"];
+ price1_parse [type=jsonparse path="result"];
+ price1_multiply [type=multiply times=100000000 index=0];
+
+ price1 -> price1_parse -> price1_multiply;
+
+ // Bid
+ bid [type=bridge name="%[6]s" timeout="50ms" requestData="{\\"data\\":{\\"from\\":\\"ETH\\",\\"to\\":\\"USD\\"}}"];
+ bid_parse [type=jsonparse path="result"];
+ bid_multiply [type=multiply times=100000000 index=1];
+
+ bid -> bid_parse -> bid_multiply;
+
+ // Ask
+ ask [type=bridge name="%[7]s" timeout="50ms" requestData="{\\"data\\":{\\"from\\":\\"ETH\\",\\"to\\":\\"USD\\"}}"];
+ ask_parse [type=jsonparse path="result"];
+ ask_multiply [type=multiply times=100000000 index=2];
+
+ ask -> ask_parse -> ask_multiply;
+
+ // Market Status
+ marketstatus [type=bridge name="%[14]s" timeout="50ms" requestData="{\\"data\\":{\\"from\\":\\"ETH\\",\\"to\\":\\"USD\\"}}"];
+ marketstatus_parse [type=jsonparse path="result" index=3];
+
+ marketstatus -> marketstatus_parse;
+"""
+
+[pluginConfig]
+servers = %[8]s
+linkFeedID = "0x%[12]x"
+nativeFeedID = "0x%[13]x"
+
+[relayConfig]
+chainID = 1337
+ `,
+ i,
+ verifierAddress,
+ node.KeyBundle.ID(),
+ fmt.Sprintf("%s@127.0.0.1:%d", bootstrapPeerID, bootstrapNodePort),
+ bmBridge,
+ bidBridge,
+ askBridge,
+ serversStr,
+ clientPubKey,
+ feedID,
+ feedName,
+ linkFeedID,
+ nativeFeedID,
+ marketStatusBridge,
+ ))
+}
diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go
index 832a39237ee..9e34e9da8b4 100644
--- a/core/services/ocr2/plugins/mercury/integration_test.go
+++ b/core/services/ocr2/plugins/mercury/integration_test.go
@@ -24,22 +24,21 @@ import (
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/hashicorp/consul/sdk/freeport"
"github.com/shopspring/decimal"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.uber.org/zap/zapcore"
- "go.uber.org/zap/zaptest/observer"
-
"github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper"
ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
"github.com/smartcontractkit/wsrpc/credentials"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/zap/zapcore"
+ "go.uber.org/zap/zaptest/observer"
mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury"
v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1"
v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2"
v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3"
+ v4 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4"
datastreamsmercury "github.com/smartcontractkit/chainlink-data-streams/mercury"
-
"github.com/smartcontractkit/chainlink/v2/core/bridges"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
token "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface"
@@ -56,6 +55,7 @@ import (
reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec"
reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec"
reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec"
+ reportcodecv4 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v4/reportcodec"
"github.com/smartcontractkit/chainlink/v2/core/store/models"
)
@@ -146,9 +146,9 @@ func integration_MercuryV1(t *testing.T) {
pError := atomic.Int64{}
// feeds
- btcFeed := Feed{"BTC/USD", randomFeedID(1), big.NewInt(20_000 * multiplier), big.NewInt(19_997 * multiplier), big.NewInt(20_004 * multiplier)}
- ethFeed := Feed{"ETH/USD", randomFeedID(1), big.NewInt(1_568 * multiplier), big.NewInt(1_566 * multiplier), big.NewInt(1_569 * multiplier)}
- linkFeed := Feed{"LINK/USD", randomFeedID(1), big.NewInt(7150 * multiplier / 1000), big.NewInt(7123 * multiplier / 1000), big.NewInt(7177 * multiplier / 1000)}
+ btcFeed := Feed{"BTC/USD", randomFeedID(1), big.NewInt(20_000 * multiplier), big.NewInt(19_997 * multiplier), big.NewInt(20_004 * multiplier), 0}
+ ethFeed := Feed{"ETH/USD", randomFeedID(1), big.NewInt(1_568 * multiplier), big.NewInt(1_566 * multiplier), big.NewInt(1_569 * multiplier), 0}
+ linkFeed := Feed{"LINK/USD", randomFeedID(1), big.NewInt(7150 * multiplier / 1000), big.NewInt(7123 * multiplier / 1000), big.NewInt(7177 * multiplier / 1000), 0}
feeds := []Feed{btcFeed, ethFeed, linkFeed}
feedM := make(map[[32]byte]Feed, len(feeds))
for i := range feeds {
@@ -1036,3 +1036,308 @@ func integration_MercuryV3(t *testing.T) {
}
})
}
+
+func TestIntegration_MercuryV4(t *testing.T) {
+ t.Parallel()
+
+ integration_MercuryV4(t)
+}
+
+func integration_MercuryV4(t *testing.T) {
+ ctx := testutils.Context(t)
+ var logObservers []*observer.ObservedLogs
+ t.Cleanup(func() {
+ detectPanicLogs(t, logObservers)
+ })
+
+ testStartTimeStamp := uint32(time.Now().Unix())
+
+ // test vars
+ // pError is the probability that an EA will return an error instead of a result, as integer percentage
+ // pError = 0 means it will never return error
+ pError := atomic.Int64{}
+
+ // feeds
+ btcFeed := Feed{
+ name: "BTC/USD",
+ id: randomFeedID(4),
+ baseBenchmarkPrice: big.NewInt(20_000 * multiplier),
+ baseBid: big.NewInt(19_997 * multiplier),
+ baseAsk: big.NewInt(20_004 * multiplier),
+ baseMarketStatus: 1,
+ }
+ ethFeed := Feed{
+ name: "ETH/USD",
+ id: randomFeedID(4),
+ baseBenchmarkPrice: big.NewInt(1_568 * multiplier),
+ baseBid: big.NewInt(1_566 * multiplier),
+ baseAsk: big.NewInt(1_569 * multiplier),
+ baseMarketStatus: 2,
+ }
+ linkFeed := Feed{
+ name: "LINK/USD",
+ id: randomFeedID(4),
+ baseBenchmarkPrice: big.NewInt(7150 * multiplier / 1000),
+ baseBid: big.NewInt(7123 * multiplier / 1000),
+ baseAsk: big.NewInt(7177 * multiplier / 1000),
+ baseMarketStatus: 3,
+ }
+ feeds := []Feed{btcFeed, ethFeed, linkFeed}
+ feedM := make(map[[32]byte]Feed, len(feeds))
+ for i := range feeds {
+ feedM[feeds[i].id] = feeds[i]
+ }
+
+ clientCSAKeys := make([]csakey.KeyV2, n+1)
+ clientPubKeys := make([]ed25519.PublicKey, n+1)
+ for i := 0; i < n+1; i++ {
+ k := big.NewInt(int64(i))
+ key := csakey.MustNewV2XXXTestingOnly(k)
+ clientCSAKeys[i] = key
+ clientPubKeys[i] = key.PublicKey
+ }
+
+ // Test multi-send to three servers
+ const nSrvs = 3
+ reqChs := make([]chan request, nSrvs)
+ servers := make(map[string]string)
+ for i := 0; i < nSrvs; i++ {
+ k := csakey.MustNewV2XXXTestingOnly(big.NewInt(int64(-(i + 1))))
+ reqs := make(chan request, 100)
+ srv := NewMercuryServer(t, ed25519.PrivateKey(k.Raw()), reqs, func() []byte {
+ report, err := (&reportcodecv4.ReportCodec{}).BuildReport(v4.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1), MarketStatus: 1})
+ if err != nil {
+ panic(err)
+ }
+ return report
+ })
+ serverURL := startMercuryServer(t, srv, clientPubKeys)
+ reqChs[i] = reqs
+ servers[serverURL] = fmt.Sprintf("%x", k.PublicKey)
+ }
+ chainID := testutils.SimulatedChainID
+
+ steve, backend, verifier, verifierAddress := setupBlockchain(t)
+
+ // Setup bootstrap + oracle nodes
+ bootstrapNodePort := freeport.GetOne(t)
+ appBootstrap, bootstrapPeerID, _, bootstrapKb, observedLogs := setupNode(t, bootstrapNodePort, "bootstrap_mercury", backend, clientCSAKeys[n])
+ bootstrapNode := Node{App: appBootstrap, KeyBundle: bootstrapKb}
+ logObservers = append(logObservers, observedLogs)
+
+ // Commit blocks to finality depth to ensure LogPoller has finalized blocks to read from
+ ch, err := bootstrapNode.App.GetRelayers().LegacyEVMChains().Get(testutils.SimulatedChainID.String())
+ require.NoError(t, err)
+ finalityDepth := ch.Config().EVM().FinalityDepth()
+ for i := 0; i < int(finalityDepth); i++ {
+ backend.Commit()
+ }
+
+ // Set up n oracles
+ var (
+ oracles []confighelper.OracleIdentityExtra
+ nodes []Node
+ )
+ ports := freeport.GetN(t, n)
+ for i := 0; i < n; i++ {
+ app, peerID, transmitter, kb, observedLogs := setupNode(t, ports[i], fmt.Sprintf("oracle_mercury%d", i), backend, clientCSAKeys[i])
+
+ nodes = append(nodes, Node{
+ app, transmitter, kb,
+ })
+
+ offchainPublicKey, _ := hex.DecodeString(strings.TrimPrefix(kb.OnChainPublicKey(), "0x"))
+ oracles = append(oracles, confighelper.OracleIdentityExtra{
+ OracleIdentity: confighelper.OracleIdentity{
+ OnchainPublicKey: offchainPublicKey,
+ TransmitAccount: ocr2types.Account(fmt.Sprintf("%x", transmitter[:])),
+ OffchainPublicKey: kb.OffchainPublicKey(),
+ PeerID: peerID,
+ },
+ ConfigEncryptionPublicKey: kb.ConfigEncryptionPublicKey(),
+ })
+ logObservers = append(logObservers, observedLogs)
+ }
+
+ for _, feed := range feeds {
+ addBootstrapJob(t, bootstrapNode, chainID, verifierAddress, feed.name, feed.id)
+ }
+
+ createBridge := func(name string, i int, p *big.Int, marketStatus uint32, borm bridges.ORM) (bridgeName string) {
+ bridge := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
+ b, herr := io.ReadAll(req.Body)
+ require.NoError(t, herr)
+ require.Equal(t, `{"data":{"from":"ETH","to":"USD"}}`, string(b))
+
+ r := rand.Int63n(101)
+ if r > pError.Load() {
+ res.WriteHeader(http.StatusOK)
+
+ var val string
+ if p != nil {
+ val = decimal.NewFromBigInt(p, 0).Div(decimal.NewFromInt(multiplier)).Add(decimal.NewFromInt(int64(i)).Div(decimal.NewFromInt(100))).String()
+ } else {
+ val = fmt.Sprintf("%d", marketStatus)
+ }
+
+ resp := fmt.Sprintf(`{"result": %s}`, val)
+ _, herr = res.Write([]byte(resp))
+ require.NoError(t, herr)
+ } else {
+ res.WriteHeader(http.StatusInternalServerError)
+ resp := `{"error": "pError test error"}`
+ _, herr = res.Write([]byte(resp))
+ require.NoError(t, herr)
+ }
+ }))
+ t.Cleanup(bridge.Close)
+ u, _ := url.Parse(bridge.URL)
+ bridgeName = fmt.Sprintf("bridge-%s-%d", name, i)
+ require.NoError(t, borm.CreateBridgeType(ctx, &bridges.BridgeType{
+ Name: bridges.BridgeName(bridgeName),
+ URL: models.WebURL(*u),
+ }))
+
+ return bridgeName
+ }
+
+ // Add OCR jobs - one per feed on each node
+ for i, node := range nodes {
+ for j, feed := range feeds {
+ bmBridge := createBridge(fmt.Sprintf("benchmarkprice-%d", j), i, feed.baseBenchmarkPrice, 0, node.App.BridgeORM())
+ bidBridge := createBridge(fmt.Sprintf("bid-%d", j), i, feed.baseBid, 0, node.App.BridgeORM())
+ askBridge := createBridge(fmt.Sprintf("ask-%d", j), i, feed.baseAsk, 0, node.App.BridgeORM())
+ marketStatusBridge := createBridge(fmt.Sprintf("marketstatus-%d", j), i, nil, feed.baseMarketStatus, node.App.BridgeORM())
+
+ addV4MercuryJob(
+ t,
+ node,
+ i,
+ verifierAddress,
+ bootstrapPeerID,
+ bootstrapNodePort,
+ bmBridge,
+ bidBridge,
+ askBridge,
+ marketStatusBridge,
+ servers,
+ clientPubKeys[i],
+ feed.name,
+ feed.id,
+ randomFeedID(2),
+ randomFeedID(2),
+ )
+ }
+ }
+
+ // Setup config on contract
+ onchainConfig, err := (datastreamsmercury.StandardOnchainConfigCodec{}).Encode(rawOnchainConfig)
+ require.NoError(t, err)
+
+ reportingPluginConfig, err := json.Marshal(rawReportingPluginConfig)
+ require.NoError(t, err)
+
+ signers, _, _, onchainConfig, offchainConfigVersion, offchainConfig, err := ocr3confighelper.ContractSetConfigArgsForTestsMercuryV02(
+ 2*time.Second, // DeltaProgress
+ 20*time.Second, // DeltaResend
+ 400*time.Millisecond, // DeltaInitial
+ 100*time.Millisecond, // DeltaRound
+ 0, // DeltaGrace
+ 300*time.Millisecond, // DeltaCertifiedCommitRequest
+ 1*time.Minute, // DeltaStage
+ 100, // rMax
+ []int{len(nodes)}, // S
+ oracles,
+ reportingPluginConfig, // reportingPluginConfig []byte,
+ 250*time.Millisecond, // Max duration observation
+ int(f), // f
+ onchainConfig,
+ )
+
+ require.NoError(t, err)
+ signerAddresses, err := evm.OnchainPublicKeyToAddress(signers)
+ require.NoError(t, err)
+
+ offchainTransmitters := make([][32]byte, n)
+ for i := 0; i < n; i++ {
+ offchainTransmitters[i] = nodes[i].ClientPubKey
+ }
+
+ for _, feed := range feeds {
+ _, ferr := verifier.SetConfig(
+ steve,
+ feed.id,
+ signerAddresses,
+ offchainTransmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig,
+ nil,
+ )
+ require.NoError(t, ferr)
+ backend.Commit()
+ }
+
+ runTestSetup := func(reqs chan request) {
+ // Expect at least one report per feed from each oracle, per server
+ seen := make(map[[32]byte]map[credentials.StaticSizedPublicKey]struct{})
+ for i := range feeds {
+ // feedID will be deleted when all n oracles have reported
+ seen[feeds[i].id] = make(map[credentials.StaticSizedPublicKey]struct{}, n)
+ }
+
+ for req := range reqs {
+ v := make(map[string]interface{})
+ err := mercury.PayloadTypes.UnpackIntoMap(v, req.req.Payload)
+ require.NoError(t, err)
+ report, exists := v["report"]
+ if !exists {
+ t.Fatalf("expected payload %#v to contain 'report'", v)
+ }
+ reportElems := make(map[string]interface{})
+ err = reportcodecv4.ReportTypes.UnpackIntoMap(reportElems, report.([]byte))
+ require.NoError(t, err)
+
+ feedID := reportElems["feedId"].([32]uint8)
+ feed, exists := feedM[feedID]
+ require.True(t, exists)
+
+ if _, exists := seen[feedID]; !exists {
+ continue // already saw all oracles for this feed
+ }
+
+ expectedFee := datastreamsmercury.CalculateFee(big.NewInt(234567), rawReportingPluginConfig.BaseUSDFee)
+ expectedExpiresAt := reportElems["observationsTimestamp"].(uint32) + rawReportingPluginConfig.ExpirationWindow
+
+ assert.GreaterOrEqual(t, int(reportElems["observationsTimestamp"].(uint32)), int(testStartTimeStamp))
+ assert.InDelta(t, feed.baseBenchmarkPrice.Int64(), reportElems["benchmarkPrice"].(*big.Int).Int64(), 5000000)
+ assert.InDelta(t, feed.baseBid.Int64(), reportElems["bid"].(*big.Int).Int64(), 5000000)
+ assert.InDelta(t, feed.baseAsk.Int64(), reportElems["ask"].(*big.Int).Int64(), 5000000)
+ assert.NotZero(t, reportElems["validFromTimestamp"].(uint32))
+ assert.GreaterOrEqual(t, reportElems["observationsTimestamp"].(uint32), reportElems["validFromTimestamp"].(uint32))
+ assert.Equal(t, expectedExpiresAt, reportElems["expiresAt"].(uint32))
+ assert.Equal(t, expectedFee, reportElems["linkFee"].(*big.Int))
+ assert.Equal(t, expectedFee, reportElems["nativeFee"].(*big.Int))
+ assert.Equal(t, feed.baseMarketStatus, reportElems["marketStatus"].(uint32))
+
+ t.Logf("oracle %x reported for feed %s (0x%x)", req.pk, feed.name, feed.id)
+
+ seen[feedID][req.pk] = struct{}{}
+ if len(seen[feedID]) == n {
+ t.Logf("all oracles reported for feed %s (0x%x)", feed.name, feed.id)
+ delete(seen, feedID)
+ if len(seen) == 0 {
+ break // saw all oracles; success!
+ }
+ }
+ }
+ }
+
+ t.Run("receives at least one report per feed for every server from each oracle when EAs are at 100% reliability", func(t *testing.T) {
+ for i := 0; i < nSrvs; i++ {
+ reqs := reqChs[i]
+ runTestSetup(reqs)
+ }
+ })
+}
diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go
index c5eba78b0d8..0898c1821ec 100644
--- a/core/services/ocr2/plugins/mercury/plugin.go
+++ b/core/services/ocr2/plugins/mercury/plugin.go
@@ -13,6 +13,7 @@ import (
relaymercuryv1 "github.com/smartcontractkit/chainlink-data-streams/mercury/v1"
relaymercuryv2 "github.com/smartcontractkit/chainlink-data-streams/mercury/v2"
relaymercuryv3 "github.com/smartcontractkit/chainlink-data-streams/mercury/v3"
+ relaymercuryv4 "github.com/smartcontractkit/chainlink-data-streams/mercury/v4"
"github.com/smartcontractkit/chainlink-common/pkg/loop"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
@@ -29,6 +30,7 @@ import (
mercuryv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1"
mercuryv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2"
mercuryv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3"
+ mercuryv4 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v4"
"github.com/smartcontractkit/chainlink/v2/plugins"
)
@@ -136,6 +138,13 @@ func NewServices(
return nil, fmt.Errorf("failed to create mercury v3 factory: %w", err)
}
srvs = append(srvs, factoryServices...)
+ case 4:
+ factory, factoryServices, err = newv4factory(fCfg)
+ if err != nil {
+ abort()
+ return nil, fmt.Errorf("failed to create mercury v4 factory: %w", err)
+ }
+ srvs = append(srvs, factoryServices...)
default:
return nil, errors.Errorf("unknown Mercury report schema version: %d", feedID.Version())
}
@@ -162,6 +171,43 @@ type factoryCfg struct {
feedID utils.FeedID
}
+func newv4factory(factoryCfg factoryCfg) (ocr3types.MercuryPluginFactory, []job.ServiceCtx, error) {
+ var factory ocr3types.MercuryPluginFactory
+ srvs := make([]job.ServiceCtx, 0)
+
+ ds := mercuryv4.NewDataSource(
+ factoryCfg.orm,
+ factoryCfg.pipelineRunner,
+ factoryCfg.jb,
+ *factoryCfg.jb.PipelineSpec,
+ factoryCfg.feedID,
+ factoryCfg.lggr,
+ factoryCfg.saver,
+ factoryCfg.chEnhancedTelem,
+ factoryCfg.ocr2Provider.MercuryServerFetcher(),
+ *factoryCfg.reportingPluginConfig.LinkFeedID,
+ *factoryCfg.reportingPluginConfig.NativeFeedID,
+ )
+
+ loopCmd := env.MercuryPlugin.Cmd.Get()
+ loopEnabled := loopCmd != ""
+
+ if loopEnabled {
+ cmdFn, opts, mercuryLggr, err := initLoop(loopCmd, factoryCfg.cfg, factoryCfg.feedID, factoryCfg.lggr)
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to init loop for feed %s: %w", factoryCfg.feedID, err)
+ }
+ // in loop mode, the factory is grpc server, and we need to handle the server lifecycle
+ factoryServer := loop.NewMercuryV4Service(mercuryLggr, opts, cmdFn, factoryCfg.ocr2Provider, ds)
+ srvs = append(srvs, factoryServer)
+ // adapt the grpc server to the vanilla mercury plugin factory interface used by the oracle
+ factory = factoryServer
+ } else {
+ factory = relaymercuryv4.NewFactory(ds, factoryCfg.lggr, factoryCfg.ocr2Provider.OnchainConfigCodec(), factoryCfg.ocr2Provider.ReportCodecV4())
+ }
+ return factory, srvs, nil
+}
+
func newv3factory(factoryCfg factoryCfg) (ocr3types.MercuryPluginFactory, []job.ServiceCtx, error) {
var factory ocr3types.MercuryPluginFactory
srvs := make([]job.ServiceCtx, 0)
diff --git a/core/services/ocr2/plugins/mercury/plugin_test.go b/core/services/ocr2/plugins/mercury/plugin_test.go
index 95aaabec142..f9bef4a3f1a 100644
--- a/core/services/ocr2/plugins/mercury/plugin_test.go
+++ b/core/services/ocr2/plugins/mercury/plugin_test.go
@@ -21,6 +21,7 @@ import (
v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1"
v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2"
v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3"
+ v4 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4"
mercuryocr2 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury"
@@ -37,6 +38,7 @@ var (
v1FeedId = [32]uint8{00, 01, 107, 74, 167, 229, 124, 167, 182, 138, 225, 191, 69, 101, 63, 86, 182, 86, 253, 58, 163, 53, 239, 127, 174, 105, 107, 102, 63, 27, 132, 114}
v2FeedId = [32]uint8{00, 02, 107, 74, 167, 229, 124, 167, 182, 138, 225, 191, 69, 101, 63, 86, 182, 86, 253, 58, 163, 53, 239, 127, 174, 105, 107, 102, 63, 27, 132, 114}
v3FeedId = [32]uint8{00, 03, 107, 74, 167, 229, 124, 167, 182, 138, 225, 191, 69, 101, 63, 86, 182, 86, 253, 58, 163, 53, 239, 127, 174, 105, 107, 102, 63, 27, 132, 114}
+ v4FeedId = [32]uint8{00, 04, 107, 74, 167, 229, 124, 167, 182, 138, 225, 191, 69, 101, 63, 86, 182, 86, 253, 58, 163, 53, 239, 127, 174, 105, 107, 102, 63, 27, 132, 114}
testArgsNoPlugin = libocr2.MercuryOracleArgs{
LocalConfig: libocr2types.LocalConfig{
@@ -66,6 +68,13 @@ var (
"nativeFeedID": "0x00036b4aa7e57ca7b68ae1bf45653f56b656fd3aa335ef7fae696b663f1b8472",
}
+ v4jsonCfg = job.JSONConfig{
+ "serverURL": "example.com:80",
+ "serverPubKey": "724ff6eae9e900270edfff233e16322a70ec06e1a6e62a81ef13921f398f6c93",
+ "linkFeedID": "0x00026b4aa7e57ca7b68ae1bf45653f56b656fd3aa335ef7fae696b663f1b8472",
+ "nativeFeedID": "0x00036b4aa7e57ca7b68ae1bf45653f56b656fd3aa335ef7fae696b663f1b8472",
+ }
+
testJob = job.Job{
ID: 1,
ExternalJobID: uuid.Must(uuid.NewRandom()),
@@ -135,6 +144,15 @@ func TestNewServices(t *testing.T) {
wantServiceCnt: expectedEmbeddedServiceCnt,
wantErr: false,
},
+ {
+ name: "v4 legacy",
+ args: args{
+ pluginConfig: v4jsonCfg,
+ feedID: v4FeedId,
+ },
+ wantServiceCnt: expectedEmbeddedServiceCnt,
+ wantErr: false,
+ },
{
name: "v1 loop",
loopMode: true,
@@ -168,6 +186,17 @@ func TestNewServices(t *testing.T) {
wantErr: false,
wantLoopFactory: &loop.MercuryV3Service{},
},
+ {
+ name: "v4 loop",
+ loopMode: true,
+ args: args{
+ pluginConfig: v4jsonCfg,
+ feedID: v4FeedId,
+ },
+ wantServiceCnt: expectedLoopServiceCnt,
+ wantErr: false,
+ wantLoopFactory: &loop.MercuryV4Service{},
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -259,6 +288,9 @@ func (*testProvider) ReportCodecV2() v2.ReportCodec { return nil }
// ReportCodecV3 implements types.MercuryProvider.
func (*testProvider) ReportCodecV3() v3.ReportCodec { return nil }
+// ReportCodecV4 implements types.MercuryProvider.
+func (*testProvider) ReportCodecV4() v4.ReportCodec { return nil }
+
// Start implements types.MercuryProvider.
func (*testProvider) Start(context.Context) error { panic("unimplemented") }
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go
index d07af8a8de4..a5a00542179 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go
@@ -9,14 +9,13 @@ import (
"github.com/ethereum/go-ethereum/common"
- ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
-
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
+ ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types"
"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/logger"
"github.com/smartcontractkit/chainlink/v2/core/utils"
)
@@ -74,7 +73,7 @@ func NewBlockSubscriber(hb httypes.HeadBroadcaster, lp logpoller.LogPoller, fina
blockSize: lookbackDepth,
finalityDepth: finalityDepth,
latestBlock: atomic.Pointer[ocr2keepers.BlockKey]{},
- lggr: lggr.Named("BlockSubscriber"),
+ lggr: logger.Named(lggr, "BlockSubscriber"),
}
}
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go
index f84a48c1ff8..d54deea406f 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice.go
@@ -6,10 +6,11 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/cbor"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding"
)
@@ -45,7 +46,7 @@ func CheckGasPrice(ctx context.Context, upkeepId *big.Int, offchainConfigBytes [
}
lggr.Debugf("successfully decode offchain config for %s, max gas price is %s", upkeepId.String(), offchainConfig.MaxGasPrice.String())
- fee, _, err := ge.GetFee(ctx, []byte{}, feeLimit, assets.NewWei(big.NewInt(maxFeePrice)))
+ fee, _, err := ge.GetFee(ctx, []byte{}, feeLimit, assets.NewWei(big.NewInt(maxFeePrice)), nil)
if err != nil {
lggr.Errorw("failed to get fee, gas price check is disabled", "upkeepId", upkeepId.String(), "err", err)
return encoding.UpkeepFailureReasonNone
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice_test.go
index 9b5640051df..4418dd0f7c1 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice_test.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/gasprice/gasprice_test.go
@@ -86,13 +86,13 @@ func TestGasPrice_Check(t *testing.T) {
ctx := testutils.Context(t)
ge := gasMocks.NewEvmFeeEstimator(t)
if test.FailedToGetFee {
- ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
gas.EvmFee{},
feeLimit,
errors.New("failed to retrieve gas price"),
)
} else if test.CurrentLegacyGasPrice != nil {
- ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
gas.EvmFee{
Legacy: assets.NewWei(test.CurrentLegacyGasPrice),
},
@@ -100,7 +100,7 @@ func TestGasPrice_Check(t *testing.T) {
nil,
)
} else if test.CurrentDynamicGasPrice != nil {
- ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(
gas.EvmFee{
DynamicFeeCap: assets.NewWei(test.CurrentDynamicGasPrice),
DynamicTipCap: assets.NewWei(big.NewInt(1_000_000_000)),
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1.go
index e58d5ad9c93..00a56496a00 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1.go
@@ -6,8 +6,9 @@ import (
"sync"
"sync/atomic"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics"
)
@@ -79,7 +80,7 @@ type logBuffer struct {
func NewLogBuffer(lggr logger.Logger, lookback, blockRate, logLimit uint32) LogBuffer {
return &logBuffer{
- lggr: lggr.Named("KeepersRegistry.LogEventBufferV1"),
+ lggr: logger.Sugared(lggr).Named("KeepersRegistry").Named("LogEventBufferV1"),
opts: newLogBufferOptions(lookback, blockRate, logLimit),
lastBlockSeen: new(atomic.Int64),
queueIDs: []string{},
@@ -313,7 +314,7 @@ type upkeepLogQueue struct {
func newUpkeepLogQueue(lggr logger.Logger, id *big.Int, opts *logBufferOptions) *upkeepLogQueue {
return &upkeepLogQueue{
- lggr: lggr.With("upkeepID", id.String()),
+ lggr: logger.With(lggr, "upkeepID", id.String()),
id: id,
opts: opts,
logs: map[int64][]logpoller.Log{},
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1_test.go
index f742d39689c..4c46b9b3fea 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1_test.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_v1_test.go
@@ -54,8 +54,6 @@ func TestLogEventBufferV1_SyncFilters(t *testing.T) {
type readableLogger struct {
logger.Logger
DebugwFn func(msg string, keysAndValues ...interface{})
- NamedFn func(name string) logger.Logger
- WithFn func(args ...interface{}) logger.Logger
}
func (l *readableLogger) Debugw(msg string, keysAndValues ...interface{}) {
@@ -74,6 +72,7 @@ func TestLogEventBufferV1_EnqueueViolations(t *testing.T) {
t.Run("enqueuing logs for a block older than latest seen logs a message", func(t *testing.T) {
logReceived := false
readableLogger := &readableLogger{
+ Logger: logger.TestLogger(t),
DebugwFn: func(msg string, keysAndValues ...interface{}) {
if msg == "enqueuing logs from a block older than latest seen block" {
logReceived = true
@@ -103,6 +102,7 @@ func TestLogEventBufferV1_EnqueueViolations(t *testing.T) {
t.Run("enqueuing logs for the same block over multiple calls logs a message", func(t *testing.T) {
logReceived := false
readableLogger := &readableLogger{
+ Logger: logger.TestLogger(t),
DebugwFn: func(msg string, keysAndValues ...interface{}) {
if msg == "enqueuing logs again for a previously seen block" {
logReceived = true
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 7ec65ff4740..57b48841a20 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/factory.go
@@ -4,9 +4,10 @@ import (
"math/big"
"time"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
)
@@ -74,7 +75,7 @@ func (o *LogTriggersOptions) Defaults(finalityDepth int64) {
func (o *LogTriggersOptions) defaultBlockRate() uint32 {
switch o.chainID.Int64() {
- case 42161, 421613, 421614: // Arbitrum
+ case 42161, 421613, 421614: // Arbitrum, Arb Goerli, Arb Sepolia
return 2
default:
return 1
@@ -83,10 +84,10 @@ func (o *LogTriggersOptions) defaultBlockRate() uint32 {
func (o *LogTriggersOptions) defaultLogLimit() uint32 {
switch o.chainID.Int64() {
- case 1, 4, 5, 42, 11155111: // Eth
+ case 1, 4, 5, 42, 11155111: // Eth, Rinkeby, Goerli, Kovan, Sepolia
return 20
- case 10, 420, 56, 97, 137, 80001, 43113, 43114, 8453, 84531: // Optimism, BSC, Polygon, Avax, Base
- return 5
+ case 10, 420, 11155420, 56, 97, 137, 80001, 80002, 43114, 43113, 8453, 84531, 84532: // Optimism, OP Goerli, OP Sepolia, BSC, BSC Test, Polygon, Mumbai, Amoy, Avax, Avax Fuji, Base, Base Goerli, Base Sepolia
+ return 4
default:
return 1
}
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 f1de1ef5129..50b2ebc0d06 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go
@@ -16,13 +16,12 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
- ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
-
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
+ ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
ac "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_compatible_utils"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics"
"github.com/smartcontractkit/chainlink/v2/core/utils"
@@ -111,7 +110,7 @@ type logEventProvider struct {
func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, chainID *big.Int, packer LogDataPacker, filterStore UpkeepFilterStore, opts LogTriggersOptions) *logEventProvider {
return &logEventProvider{
threadCtrl: utils.NewThreadControl(),
- lggr: lggr.Named("KeepersRegistry.LogEventProvider"),
+ lggr: logger.Named(lggr, "KeepersRegistry.LogEventProvider"),
packer: packer,
buffer: NewLogBuffer(lggr, uint32(opts.LookbackBlocks), opts.BlockRate, opts.LogLimit),
poller: poller,
@@ -135,7 +134,7 @@ func (p *logEventProvider) SetConfig(cfg ocr2keepers.LogEventProviderConfig) {
logLimit = p.opts.defaultLogLimit()
}
- p.lggr.With("where", "setConfig").Infow("setting config ", "bockRate", blockRate, "logLimit", logLimit)
+ p.lggr.Infow("setting config", "where", "setConfig", "bockRate", blockRate, "logLimit", logLimit)
atomic.StoreUint32(&p.opts.BlockRate, blockRate)
atomic.StoreUint32(&p.opts.LogLimit, logLimit)
@@ -156,7 +155,7 @@ func (p *logEventProvider) Start(context.Context) error {
}
p.threadCtrl.Go(func(ctx context.Context) {
- lggr := p.lggr.With("where", "scheduler")
+ lggr := logger.With(p.lggr, "where", "scheduler")
p.scheduleReadJobs(ctx, func(ids []*big.Int) {
select {
@@ -369,7 +368,7 @@ func (p *logEventProvider) startReader(pctx context.Context, readQ <-chan []*big
ctx, cancel := context.WithCancel(pctx)
defer cancel()
- lggr := p.lggr.With("where", "reader")
+ lggr := logger.With(p.lggr, "where", "reader")
for {
select {
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle.go
index db47ac2ecd8..cbd493bf2e4 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle.go
@@ -10,6 +10,8 @@ import (
"github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
)
@@ -106,7 +108,7 @@ func (p *logEventProvider) register(ctx context.Context, lpFilter logpoller.Filt
if err != nil {
return fmt.Errorf("failed to get latest block while registering filter: %w", err)
}
- lggr := p.lggr.With("upkeepID", ufilter.upkeepID.String())
+ lggr := logger.With(p.lggr, "upkeepID", ufilter.upkeepID.String())
logPollerHasFilter := p.poller.HasFilter(lpFilter.Name)
filterStoreHasFilter := p.filterStore.Has(ufilter.upkeepID)
if filterStoreHasFilter {
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go
index 9e41008ed83..984856bf3cd 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go
@@ -14,18 +14,17 @@ import (
"sync/atomic"
"time"
- "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
-
"github.com/ethereum/go-ethereum/common"
- "github.com/smartcontractkit/chainlink-automation/pkg/v3/random"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
- "github.com/smartcontractkit/chainlink-common/pkg/services"
+ "github.com/smartcontractkit/chainlink-automation/pkg/v3/random"
+ "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/prommetrics"
"github.com/smartcontractkit/chainlink/v2/core/utils"
@@ -71,7 +70,7 @@ type logRecoverer struct {
services.StateMachine
threadCtrl utils.ThreadControl
- lggr logger.Logger
+ lggr logger.SugaredLogger
lookbackBlocks *atomic.Int64
blockTime *atomic.Int64
@@ -96,7 +95,7 @@ var _ LogRecoverer = &logRecoverer{}
func NewLogRecoverer(lggr logger.Logger, poller logpoller.LogPoller, client client.Client, stateStore core.UpkeepStateReader, packer LogDataPacker, filterStore UpkeepFilterStore, opts LogTriggersOptions) *logRecoverer {
rec := &logRecoverer{
- lggr: lggr.Named(LogRecovererServiceName),
+ lggr: logger.Sugared(lggr).Named(LogRecovererServiceName),
threadCtrl: utils.NewThreadControl(),
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 5a4b701f61a..17005939219 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
@@ -15,11 +15,11 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/patrickmn/go-cache"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
autov2common "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/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"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"
@@ -119,7 +119,7 @@ func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckRe
// buildResult checks if the upkeep is allowed by Mercury and builds a streams lookup request from the check result
func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keepers.CheckResult, checkResults []ocr2keepers.CheckResult, lookups map[int]*mercury.StreamsLookup) {
- lookupLggr := s.lggr.With("where", "StreamsLookup")
+ lookupLggr := logger.Sugared(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()
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 5e954475a8d..c02b7c10de5 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
@@ -11,14 +11,14 @@ import (
"strconv"
"time"
- automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
+ "github.com/avast/retry-go/v4"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
- "github.com/avast/retry-go/v4"
- "github.com/ethereum/go-ethereum/common/hexutil"
+ automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
- "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"
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 39a26b6b5d9..c2ffb2172b0 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
@@ -10,14 +10,14 @@ import (
"strings"
"time"
- automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
+ "github.com/avast/retry-go/v4"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
- "github.com/avast/retry-go/v4"
- "github.com/ethereum/go-ethereum/common/hexutil"
+ automationTypes "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
- "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"
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go
index 7f29cb3b7ac..c6262899a32 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go
@@ -3,11 +3,11 @@ package evm
import (
"context"
- "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
-
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
+
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider"
)
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go
index 16b8627cf74..25bd7a445e4 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go
@@ -10,10 +10,6 @@ import (
"sync"
"time"
- types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
-
- "github.com/smartcontractkit/chainlink-common/pkg/types"
-
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
@@ -22,19 +18,20 @@ import (
"github.com/pkg/errors"
"go.uber.org/multierr"
- evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
-
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
-
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
+ types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
"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/chains/legacyevm"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated"
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/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"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"
@@ -98,7 +95,7 @@ func NewEvmRegistry(
return &EvmRegistry{
stopCh: make(chan struct{}),
threadCtrl: utils.NewThreadControl(),
- lggr: lggr.Named(RegistryServiceName),
+ lggr: logger.Sugared(lggr).Named(RegistryServiceName),
poller: client.LogPoller(),
addr: addr,
client: client.Client(),
@@ -175,7 +172,7 @@ func (c *MercuryConfig) SetPluginRetry(k string, v interface{}, d time.Duration)
type EvmRegistry struct {
services.StateMachine
threadCtrl utils.ThreadControl
- lggr logger.Logger
+ lggr logger.SugaredLogger
poller logpoller.LogPoller
addr common.Address
client client.Client
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go
index 6f8785fda78..cb014e1d3ec 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go
@@ -8,10 +8,6 @@ import (
"sync/atomic"
"testing"
- types3 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
-
- types2 "github.com/smartcontractkit/chainlink-common/pkg/types"
-
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
@@ -20,8 +16,12 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ types2 "github.com/smartcontractkit/chainlink-common/pkg/types"
ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
+ types3 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
+
evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks"
gasMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
@@ -30,7 +30,6 @@ import (
ac "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_automation_v21_plus_common"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"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/mocks"
@@ -82,7 +81,7 @@ func TestRegistry_GetBlockAndUpkeepId(t *testing.T) {
}
func TestRegistry_VerifyCheckBlock(t *testing.T) {
- lggr := logger.TestLogger(t)
+ lggr := logger.Test(t)
upkeepId := ocr2keepers.UpkeepIdentifier{}
upkeepId.FromBigInt(big.NewInt(12345))
tests := []struct {
@@ -197,7 +196,7 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) {
}
bs.latestBlock.Store(tc.latestBlock)
e := &EvmRegistry{
- lggr: lggr,
+ lggr: logger.Sugared(lggr),
bs: bs,
poller: tc.poller,
}
@@ -229,7 +228,7 @@ func (p *mockLogPoller) IndexedLogs(ctx context.Context, eventSig common.Hash, a
}
func TestRegistry_VerifyLogExists(t *testing.T) {
- lggr := logger.TestLogger(t)
+ lggr := logger.Test(t)
upkeepId := ocr2keepers.UpkeepIdentifier{}
upkeepId.FromBigInt(big.NewInt(12345))
@@ -351,7 +350,7 @@ func TestRegistry_VerifyLogExists(t *testing.T) {
blocks: tc.blocks,
}
e := &EvmRegistry{
- lggr: lggr,
+ lggr: logger.Sugared(lggr),
bs: bs,
}
@@ -379,7 +378,7 @@ func TestRegistry_VerifyLogExists(t *testing.T) {
}
func TestRegistry_CheckUpkeeps(t *testing.T) {
- lggr := logger.TestLogger(t)
+ lggr := logger.Test(t)
uid0 := core.GenUpkeepID(types3.UpkeepType(0), "p0")
uid1 := core.GenUpkeepID(types3.UpkeepType(1), "p1")
uid2 := core.GenUpkeepID(types3.UpkeepType(1), "p2")
@@ -509,7 +508,7 @@ func TestRegistry_CheckUpkeeps(t *testing.T) {
}
bs.latestBlock.Store(tc.latestBlock)
e := &EvmRegistry{
- lggr: lggr,
+ lggr: logger.Sugared(lggr),
bs: bs,
poller: tc.poller,
}
@@ -669,7 +668,7 @@ func TestRegistry_SimulatePerformUpkeeps(t *testing.T) {
// setups up an evm registry for tests.
func setupEVMRegistry(t *testing.T) *EvmRegistry {
- lggr := logger.TestLogger(t)
+ lggr := logger.Test(t)
addr := common.HexToAddress("0x6cA639822c6C241Fa9A7A6b5032F6F7F1C513CAD")
keeperRegistryABI, err := abi.JSON(strings.NewReader(ac.IAutomationV21PlusCommonABI))
require.Nil(t, err, "need registry abi")
@@ -682,7 +681,7 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry {
ge := gasMocks.NewEvmFeeEstimator(t)
r := &EvmRegistry{
- lggr: lggr,
+ lggr: logger.Sugared(lggr),
poller: logPoller,
addr: addr,
client: client,
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 ab530f877ae..1a3f103dd10 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go
@@ -15,19 +15,19 @@ import (
"github.com/stretchr/testify/mock"
types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
- evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
- "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
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"
+ 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"
ac "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_compatible_utils"
autov2common "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/internal/testutils"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"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"
@@ -546,7 +546,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) {
} {
t.Run(tc.name, func(t *testing.T) {
ctx := tests.Context(t)
- lggr := logger.TestLogger(t)
+ lggr := logger.Test(t)
var hb types3.HeadBroadcaster
var lp logpoller.LogPoller
@@ -560,7 +560,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) {
bs: bs,
registry: tc.registry,
packer: tc.packer,
- lggr: lggr,
+ lggr: logger.Sugared(lggr),
}
err := registry.refreshLogTriggerUpkeeps(ctx, tc.ids)
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go
index f1a64688044..697f56c866b 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go
@@ -6,18 +6,17 @@ import (
"fmt"
"sync"
- "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
-
"github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
- "github.com/smartcontractkit/chainlink-common/pkg/services"
+ "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
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/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
)
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner.go
index d11970864ad..27a35ddff13 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/scanner.go
@@ -8,10 +8,11 @@ import (
"github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
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/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider"
)
@@ -43,7 +44,7 @@ func NewPerformedEventsScanner(
finalityDepth uint32,
) *performedEventsScanner {
return &performedEventsScanner{
- lggr: lggr.Named("EventsScanner"),
+ lggr: logger.Named(lggr, "EventsScanner"),
poller: poller,
registryAddress: registryAddress,
finalityDepth: finalityDepth,
diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go
index e6486ca56ae..27cac24a9fe 100644
--- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go
+++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go
@@ -8,13 +8,12 @@ import (
"sync"
"time"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation"
- "github.com/smartcontractkit/chainlink-common/pkg/services"
-
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/ocr2/plugins/ocr2keeper/evmregistry/v21/core"
"github.com/smartcontractkit/chainlink/v2/core/utils"
)
@@ -84,7 +83,7 @@ type upkeepStateStore struct {
func NewUpkeepStateStore(orm ORM, lggr logger.Logger, scanner PerformedLogsScanner) *upkeepStateStore {
return &upkeepStateStore{
orm: orm,
- lggr: lggr.Named(UpkeepStateStoreServiceName),
+ lggr: logger.Named(lggr, UpkeepStateStoreServiceName),
cache: map[string]*upkeepStateRecord{},
scanner: scanner,
retention: CacheExpiration,
diff --git a/core/services/ocr2/validate/validate.go b/core/services/ocr2/validate/validate.go
index 2993a67114e..a224249e1e8 100644
--- a/core/services/ocr2/validate/validate.go
+++ b/core/services/ocr2/validate/validate.go
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"os/exec"
+ "strings"
"github.com/lib/pq"
"github.com/pelletier/go-toml"
@@ -19,9 +20,11 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/config/env"
"github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config"
mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config"
"github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
"github.com/smartcontractkit/chainlink/v2/core/services/relay"
"github.com/smartcontractkit/chainlink/v2/plugins"
)
@@ -115,6 +118,10 @@ func validateSpec(ctx context.Context, tree *toml.Tree, spec job.Job, rc plugins
return nil
case types.Mercury:
return validateOCR2MercurySpec(spec.OCR2OracleSpec.PluginConfig, *spec.OCR2OracleSpec.FeedID)
+ case types.CCIPExecution:
+ return validateOCR2CCIPExecutionSpec(spec.OCR2OracleSpec.PluginConfig)
+ case types.CCIPCommit:
+ return validateOCR2CCIPCommitSpec(spec.OCR2OracleSpec.PluginConfig)
case types.LLO:
return validateOCR2LLOSpec(spec.OCR2OracleSpec.PluginConfig)
case types.GenericPlugin:
@@ -190,18 +197,6 @@ func (o *OCR2OnchainSigningStrategy) IsMultiChain() bool {
return o.StrategyName == "multi-chain"
}
-func (o *OCR2OnchainSigningStrategy) PublicKey() (string, error) {
- pk, ok := o.Config["publicKey"]
- if !ok {
- return "", nil
- }
- pkString, ok := pk.(string)
- if !ok {
- return "", fmt.Errorf("expected string publicKey value, but got: %T", pk)
- }
- return pkString, nil
-}
-
func (o *OCR2OnchainSigningStrategy) ConfigCopy() job.JSONConfig {
copiedConfig := make(job.JSONConfig)
for k, v := range o.Config {
@@ -244,13 +239,6 @@ func validateGenericPluginSpec(ctx context.Context, spec *job.OCR2OracleSpec, rc
if err != nil {
return err
}
- pk, ossErr := onchainSigningStrategy.PublicKey()
- if ossErr != nil {
- return ossErr
- }
- if pk == "" {
- return errors.New("generic config invalid: must provide public key for the onchain signing strategy")
- }
}
plugEnv := env.NewPlugin(p.PluginName)
@@ -313,11 +301,61 @@ func validateOCR2MercurySpec(jsonConfig job.JSONConfig, feedId [32]byte) error {
var pluginConfig mercuryconfig.PluginConfig
err := json.Unmarshal(jsonConfig.Bytes(), &pluginConfig)
if err != nil {
- return pkgerrors.Wrap(err, "error while unmarshaling plugin config")
+ return pkgerrors.Wrap(err, "error while unmarshalling plugin config")
}
return pkgerrors.Wrap(mercuryconfig.ValidatePluginConfig(pluginConfig, feedId), "Mercury PluginConfig is invalid")
}
+func validateOCR2CCIPExecutionSpec(jsonConfig job.JSONConfig) error {
+ if jsonConfig == nil {
+ return errors.New("pluginConfig is empty")
+ }
+ var cfg config.ExecPluginJobSpecConfig
+ err := json.Unmarshal(jsonConfig.Bytes(), &cfg)
+ if err != nil {
+ return pkgerrors.Wrap(err, "error while unmarshalling plugin config")
+ }
+ if cfg.USDCConfig != (config.USDCConfig{}) {
+ return cfg.USDCConfig.ValidateUSDCConfig()
+ }
+ return nil
+}
+
+func validateOCR2CCIPCommitSpec(jsonConfig job.JSONConfig) error {
+ if jsonConfig == nil {
+ return errors.New("pluginConfig is empty")
+ }
+ var cfg config.CommitPluginJobSpecConfig
+ err := json.Unmarshal(jsonConfig.Bytes(), &cfg)
+ if err != nil {
+ return pkgerrors.Wrap(err, "error while unmarshalling plugin config")
+ }
+
+ // Ensure that either the tokenPricesUSDPipeline or the priceGetterConfig is set, but not both.
+ emptyPipeline := strings.Trim(cfg.TokenPricesUSDPipeline, "\n\t ") == ""
+ emptyPriceGetter := cfg.PriceGetterConfig == nil
+ if emptyPipeline && emptyPriceGetter {
+ return fmt.Errorf("either tokenPricesUSDPipeline or priceGetterConfig must be set")
+ }
+ if !emptyPipeline && !emptyPriceGetter {
+ return fmt.Errorf("only one of tokenPricesUSDPipeline or priceGetterConfig must be set: %s and %v", cfg.TokenPricesUSDPipeline, cfg.PriceGetterConfig)
+ }
+
+ if !emptyPipeline {
+ _, err = pipeline.Parse(cfg.TokenPricesUSDPipeline)
+ if err != nil {
+ return pkgerrors.Wrap(err, "invalid token prices pipeline")
+ }
+ } else {
+ // Validate prices config (like it was done for the pipeline).
+ if emptyPriceGetter {
+ return pkgerrors.New("priceGetterConfig is empty")
+ }
+ }
+
+ return nil
+}
+
func validateOCR2LLOSpec(jsonConfig job.JSONConfig) error {
var pluginConfig lloconfig.PluginConfig
err := json.Unmarshal(jsonConfig.Bytes(), &pluginConfig)
diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go
index b92752c647d..1356e0db628 100644
--- a/core/services/ocr2/validate/validate_test.go
+++ b/core/services/ocr2/validate/validate_test.go
@@ -49,7 +49,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
juelsPerFeeCoinSource = """
ds1 [type=bridge name=voter_turnout];
@@ -105,7 +104,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
juelsPerFeeCoinSource = """
ds1 [type=bridge name=voter_turnout];
@@ -150,7 +148,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
`,
assertion: func(t *testing.T, os job.Job, err error) {
@@ -174,7 +171,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
`,
assertion: func(t *testing.T, os job.Job, err error) {
@@ -200,7 +196,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
`,
assertion: func(t *testing.T, os job.Job, err error) {
@@ -226,7 +221,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
`,
assertion: func(t *testing.T, os job.Job, err error) {
@@ -253,7 +247,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
`,
assertion: func(t *testing.T, os job.Job, err error) {
@@ -279,7 +272,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
`,
assertion: func(t *testing.T, os job.Job, err error) {
@@ -303,7 +295,6 @@ chainID = 1337
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
`,
assertion: func(t *testing.T, os job.Job, err error) {
@@ -344,7 +335,6 @@ answer1 [type=median index=0];
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
juelsPerFeeCoinSource = """
ds1 [type=bridge name=voter_turnout];
@@ -383,7 +373,6 @@ answer1 [type=median index=0];
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
juelsPerFeeCoinSource = """
->
@@ -415,7 +404,6 @@ answer1 [type=median index=0];
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
juelsPerFeeCoinSource = """
ds1 [type=bridge name=voter_turnout];
@@ -429,46 +417,6 @@ chainID = 1337
require.Contains(t, err.Error(), "no such relay blerg supported")
},
},
- {
- name: "Generic public onchain signing strategy with no public key",
- toml: `
-type = "offchainreporting2"
-pluginType = "plugin"
-schemaVersion = 1
-relay = "evm"
-contractID = "0x613a38AC1659769640aaE063C651F48E0250454C"
-p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq"
-p2pv2Bootstrappers = [
-"12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001",
-]
-ocrKeyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447"
-monitoringEndpoint = "chain.link:4321"
-transmitterID = "0xF67D0290337bca0847005C7ffD1BC75BA9AAE6e4"
-observationTimeout = "10s"
-observationSource = """
-ds1 [type=bridge name=voter_turnout];
-ds1_parse [type=jsonparse path="one,two"];
-ds1_multiply [type=multiply times=1.23];
-ds1 -> ds1_parse -> ds1_multiply -> answer1;
-answer1 [type=median index=0];
-"""
-[relayConfig]
-chainID = 1337
-[onchainSigningStrategy]
-strategyName = "single-chain"
-[onchainSigningStrategy.config]
-evm = ""
-publicKey = ""
-[pluginConfig]
-pluginName = "median"
-telemetryType = "median"
-OCRVersion=2
-`,
- assertion: func(t *testing.T, os job.Job, err error) {
- require.Error(t, err)
- require.Contains(t, err.Error(), "must provide public key for the onchain signing strategy")
- },
- },
{
name: "Generic plugin config validation - nothing provided",
toml: `
@@ -493,7 +441,6 @@ chainID = 4
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
`,
@@ -525,7 +472,6 @@ chainID = 4
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
PluginName="some random name"
@@ -559,7 +505,6 @@ chainID = 4
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
PluginName="some random name"
@@ -594,7 +539,6 @@ chainID = 4
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = ""
-publicKey = "0x1234567890123456789012345678901234567890"
[pluginConfig]
PluginName="some random name"
@@ -712,7 +656,6 @@ func TestOCR2OnchainSigningStrategy_Unmarshal(t *testing.T) {
strategyName = "single-chain"
[onchainSigningStrategy.config]
evm = "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17"
-publicKey = "0x1234567890123456789012345678901234567890"
`
oss := &envelope2{}
tree, err := toml.Load(payload)
@@ -725,12 +668,9 @@ publicKey = "0x1234567890123456789012345678901234567890"
err = json.Unmarshal(b, oss)
require.NoError(t, err)
- pk, err := oss.OnchainSigningStrategy.PublicKey()
- require.NoError(t, err)
kbID, err := oss.OnchainSigningStrategy.KeyBundleID("evm")
require.NoError(t, err)
assert.False(t, oss.OnchainSigningStrategy.IsMultiChain())
- assert.Equal(t, "0x1234567890123456789012345678901234567890", pk)
assert.Equal(t, "08d14c6eed757414d72055d28de6caf06535806c6a14e450f3a2f1c854420e17", kbID)
}
diff --git a/core/services/ocrcommon/adapters.go b/core/services/ocrcommon/adapters.go
index 372d9e37f15..53e62be9a07 100644
--- a/core/services/ocrcommon/adapters.go
+++ b/core/services/ocrcommon/adapters.go
@@ -87,12 +87,11 @@ type OCR3OnchainKeyringMultiChainAdapter struct {
lggr logger.Logger
}
-func NewOCR3OnchainKeyringMultiChainAdapter(ost map[string]ocr2key.KeyBundle, lggr logger.Logger) (*OCR3OnchainKeyringMultiChainAdapter, error) {
+func NewOCR3OnchainKeyringMultiChainAdapter(ost map[string]ocr2key.KeyBundle, publicKey ocrtypes.OnchainPublicKey, lggr logger.Logger) (*OCR3OnchainKeyringMultiChainAdapter, error) {
if len(ost) == 0 {
return nil, errors.New("no key bundles provided")
}
- // We don't need to check for the existence of `publicKey` in the keyBundles map because it is required on validation on `validate/validate.go`
- return &OCR3OnchainKeyringMultiChainAdapter{ost, ost["publicKey"].PublicKey(), lggr}, nil
+ return &OCR3OnchainKeyringMultiChainAdapter{ost, publicKey, lggr}, nil
}
func (a *OCR3OnchainKeyringMultiChainAdapter) PublicKey() ocrtypes.OnchainPublicKey {
diff --git a/core/services/ocrcommon/adapters_test.go b/core/services/ocrcommon/adapters_test.go
index fed854b0b32..e7d45627299 100644
--- a/core/services/ocrcommon/adapters_test.go
+++ b/core/services/ocrcommon/adapters_test.go
@@ -162,9 +162,9 @@ publicKey = "pub-key"
keyBundles[name] = os
}
- adapter, err := ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(keyBundles, logger.TestLogger(t))
+ adapter, err := ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(keyBundles, pk, logger.TestLogger(t))
require.NoError(t, err)
- _, err = ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(map[string]ocr2key.KeyBundle{}, logger.TestLogger(t))
+ _, err = ocrcommon.NewOCR3OnchainKeyringMultiChainAdapter(map[string]ocr2key.KeyBundle{}, pk, logger.TestLogger(t))
require.Error(t, err, "no key bundles provided")
sig, err := adapter.Sign(configDigest, seqNr, reportInfo)
diff --git a/core/services/ocrcommon/arbitrum_block_translator.go b/core/services/ocrcommon/arbitrum_block_translator.go
index 1b7c3712382..9179fe32270 100644
--- a/core/services/ocrcommon/arbitrum_block_translator.go
+++ b/core/services/ocrcommon/arbitrum_block_translator.go
@@ -10,9 +10,10 @@ import (
"github.com/pkg/errors"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/utils"
)
@@ -33,7 +34,7 @@ type ArbitrumBlockTranslator struct {
func NewArbitrumBlockTranslator(ethClient evmclient.Client, lggr logger.Logger) *ArbitrumBlockTranslator {
return &ArbitrumBlockTranslator{
ethClient,
- lggr.Named("ArbitrumBlockTranslator"),
+ logger.Named(lggr, "ArbitrumBlockTranslator"),
make(map[int64]int64),
sync.RWMutex{},
utils.KeyedMutex{},
diff --git a/core/services/ocrcommon/block_translator.go b/core/services/ocrcommon/block_translator.go
index d7ceffc5ea7..fa44d79c2d2 100644
--- a/core/services/ocrcommon/block_translator.go
+++ b/core/services/ocrcommon/block_translator.go
@@ -4,10 +4,11 @@ import (
"context"
"math/big"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/chaintype"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
)
// BlockTranslator converts emitted block numbers (from block.number) into a
diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go
index 2ef76800a42..2cb4fda9105 100644
--- a/core/services/ocrcommon/telemetry.go
+++ b/core/services/ocrcommon/telemetry.go
@@ -15,6 +15,8 @@ import (
v1types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1"
v2types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2"
v3types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3"
+ v4types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4"
+
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/job"
"github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
@@ -41,6 +43,7 @@ type EnhancedTelemetryMercuryData struct {
V1Observation *v1types.Observation
V2Observation *v2types.Observation
V3Observation *v3types.Observation
+ V4Observation *v4types.Observation
TaskRunResults pipeline.TaskRunResults
RepTimestamp ocrtypes.ReportTimestamp
FeedVersion mercuryutils.FeedVersion
@@ -298,6 +301,8 @@ func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(d Enhanced
ask := big.NewInt(0)
// v2+v3 fields
var mfts, lp, np int64
+ // v4 fields
+ var marketStatus telem.MarketStatus
switch {
case d.V1Observation != nil:
@@ -354,6 +359,29 @@ func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(d Enhanced
if obs.Ask.Err == nil && obs.Ask.Val != nil {
ask = obs.Ask.Val
}
+ case d.V4Observation != nil:
+ obs := *d.V4Observation
+ if obs.MaxFinalizedTimestamp.Err == nil {
+ mfts = obs.MaxFinalizedTimestamp.Val
+ }
+ if obs.LinkPrice.Err == nil && obs.LinkPrice.Val != nil {
+ lp = obs.LinkPrice.Val.Int64()
+ }
+ if obs.NativePrice.Err == nil && obs.NativePrice.Val != nil {
+ np = obs.NativePrice.Val.Int64()
+ }
+ if obs.BenchmarkPrice.Err == nil && obs.BenchmarkPrice.Val != nil {
+ bp = obs.BenchmarkPrice.Val
+ }
+ if obs.Bid.Err == nil && obs.Bid.Val != nil {
+ bid = obs.Bid.Val
+ }
+ if obs.Ask.Err == nil && obs.Ask.Val != nil {
+ ask = obs.Ask.Val
+ }
+ if obs.MarketStatus.Err == nil {
+ marketStatus = telem.MarketStatus(obs.MarketStatus.Val)
+ }
}
for _, trr := range d.TaskRunResults {
@@ -401,6 +429,7 @@ func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(d Enhanced
ObservationBenchmarkPriceString: stringOrEmpty(bp),
ObservationBidString: stringOrEmpty(bid),
ObservationAskString: stringOrEmpty(ask),
+ ObservationMarketStatus: marketStatus,
IsLinkFeed: d.IsLinkFeed,
LinkPrice: lp,
IsNativeFeed: d.IsNativeFeed,
diff --git a/core/services/pipeline/common.go b/core/services/pipeline/common.go
index 763e50546fd..1b36c8a664b 100644
--- a/core/services/pipeline/common.go
+++ b/core/services/pipeline/common.go
@@ -29,6 +29,7 @@ const (
BlockhashStoreJobType string = "blockhashstore"
BootstrapJobType string = "bootstrap"
CronJobType string = "cron"
+ CCIPJobType string = "ccip"
DirectRequestJobType string = "directrequest"
FluxMonitorJobType string = "fluxmonitor"
GatewayJobType string = "gateway"
diff --git a/core/services/registrysyncer/local_registry.go b/core/services/registrysyncer/local_registry.go
index 4e4a632bf87..d4bf4a49f53 100644
--- a/core/services/registrysyncer/local_registry.go
+++ b/core/services/registrysyncer/local_registry.go
@@ -16,7 +16,11 @@ type DonID uint32
type DON struct {
capabilities.DON
- CapabilityConfigurations map[string]capabilities.CapabilityConfiguration
+ CapabilityConfigurations map[string]CapabilityConfiguration
+}
+
+type CapabilityConfiguration struct {
+ Config []byte
}
type Capability struct {
@@ -26,22 +30,37 @@ type Capability struct {
type LocalRegistry struct {
lggr logger.Logger
- peerWrapper p2ptypes.PeerWrapper
+ getPeerID func() (p2ptypes.PeerID, error)
IDsToDONs map[DonID]DON
IDsToNodes map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo
IDsToCapabilities map[string]Capability
}
+func NewLocalRegistry(
+ lggr logger.Logger,
+ getPeerID func() (p2ptypes.PeerID, error),
+ IDsToDONs map[DonID]DON,
+ IDsToNodes map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo,
+ IDsToCapabilities map[string]Capability,
+) LocalRegistry {
+ return LocalRegistry{
+ lggr: lggr.Named("LocalRegistry"),
+ getPeerID: getPeerID,
+ IDsToDONs: IDsToDONs,
+ IDsToNodes: IDsToNodes,
+ IDsToCapabilities: IDsToCapabilities,
+ }
+}
+
func (l *LocalRegistry) LocalNode(ctx context.Context) (capabilities.Node, error) {
// Load the current nodes PeerWrapper, this gets us the current node's
// PeerID, allowing us to contextualize registry information in terms of DON ownership
// (eg. get my current DON configuration, etc).
- if l.peerWrapper.GetPeer() == nil {
+ pid, err := l.getPeerID()
+ if err != nil {
return capabilities.Node{}, errors.New("unable to get local node: peerWrapper hasn't started yet")
}
- pid := l.peerWrapper.GetPeer().ID()
-
var workflowDON capabilities.DON
capabilityDONs := []capabilities.DON{}
for _, d := range l.IDsToDONs {
@@ -70,15 +89,15 @@ func (l *LocalRegistry) LocalNode(ctx context.Context) (capabilities.Node, error
}, nil
}
-func (l *LocalRegistry) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) {
+func (l *LocalRegistry) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (CapabilityConfiguration, error) {
d, ok := l.IDsToDONs[DonID(donID)]
if !ok {
- return capabilities.CapabilityConfiguration{}, fmt.Errorf("could not find don %d", donID)
+ return CapabilityConfiguration{}, fmt.Errorf("could not find don %d", donID)
}
cc, ok := d.CapabilityConfigurations[capabilityID]
if !ok {
- return capabilities.CapabilityConfiguration{}, fmt.Errorf("could not find capability configuration for capability %s and donID %d", capabilityID, donID)
+ return CapabilityConfiguration{}, fmt.Errorf("could not find capability configuration for capability %s and donID %d", capabilityID, donID)
}
return cc, nil
diff --git a/core/services/registrysyncer/mocks/orm.go b/core/services/registrysyncer/mocks/orm.go
new file mode 100644
index 00000000000..d7777ecb6e4
--- /dev/null
+++ b/core/services/registrysyncer/mocks/orm.go
@@ -0,0 +1,142 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+
+ registrysyncer "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// ORM is an autogenerated mock type for the ORM type
+type ORM struct {
+ mock.Mock
+}
+
+type ORM_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *ORM) EXPECT() *ORM_Expecter {
+ return &ORM_Expecter{mock: &_m.Mock}
+}
+
+// AddLocalRegistry provides a mock function with given fields: ctx, localRegistry
+func (_m *ORM) AddLocalRegistry(ctx context.Context, localRegistry registrysyncer.LocalRegistry) error {
+ ret := _m.Called(ctx, localRegistry)
+
+ if len(ret) == 0 {
+ panic("no return value specified for AddLocalRegistry")
+ }
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, registrysyncer.LocalRegistry) error); ok {
+ r0 = rf(ctx, localRegistry)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// ORM_AddLocalRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddLocalRegistry'
+type ORM_AddLocalRegistry_Call struct {
+ *mock.Call
+}
+
+// AddLocalRegistry is a helper method to define mock.On call
+// - ctx context.Context
+// - localRegistry registrysyncer.LocalRegistry
+func (_e *ORM_Expecter) AddLocalRegistry(ctx interface{}, localRegistry interface{}) *ORM_AddLocalRegistry_Call {
+ return &ORM_AddLocalRegistry_Call{Call: _e.mock.On("AddLocalRegistry", ctx, localRegistry)}
+}
+
+func (_c *ORM_AddLocalRegistry_Call) Run(run func(ctx context.Context, localRegistry registrysyncer.LocalRegistry)) *ORM_AddLocalRegistry_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(registrysyncer.LocalRegistry))
+ })
+ return _c
+}
+
+func (_c *ORM_AddLocalRegistry_Call) Return(_a0 error) *ORM_AddLocalRegistry_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *ORM_AddLocalRegistry_Call) RunAndReturn(run func(context.Context, registrysyncer.LocalRegistry) error) *ORM_AddLocalRegistry_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// LatestLocalRegistry provides a mock function with given fields: ctx
+func (_m *ORM) LatestLocalRegistry(ctx context.Context) (*registrysyncer.LocalRegistry, error) {
+ ret := _m.Called(ctx)
+
+ if len(ret) == 0 {
+ panic("no return value specified for LatestLocalRegistry")
+ }
+
+ var r0 *registrysyncer.LocalRegistry
+ var r1 error
+ if rf, ok := ret.Get(0).(func(context.Context) (*registrysyncer.LocalRegistry, error)); ok {
+ return rf(ctx)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context) *registrysyncer.LocalRegistry); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(*registrysyncer.LocalRegistry)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// ORM_LatestLocalRegistry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LatestLocalRegistry'
+type ORM_LatestLocalRegistry_Call struct {
+ *mock.Call
+}
+
+// LatestLocalRegistry is a helper method to define mock.On call
+// - ctx context.Context
+func (_e *ORM_Expecter) LatestLocalRegistry(ctx interface{}) *ORM_LatestLocalRegistry_Call {
+ return &ORM_LatestLocalRegistry_Call{Call: _e.mock.On("LatestLocalRegistry", ctx)}
+}
+
+func (_c *ORM_LatestLocalRegistry_Call) Run(run func(ctx context.Context)) *ORM_LatestLocalRegistry_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context))
+ })
+ return _c
+}
+
+func (_c *ORM_LatestLocalRegistry_Call) Return(_a0 *registrysyncer.LocalRegistry, _a1 error) *ORM_LatestLocalRegistry_Call {
+ _c.Call.Return(_a0, _a1)
+ return _c
+}
+
+func (_c *ORM_LatestLocalRegistry_Call) RunAndReturn(run func(context.Context) (*registrysyncer.LocalRegistry, error)) *ORM_LatestLocalRegistry_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewORM creates a new instance of ORM. 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 NewORM(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *ORM {
+ mock := &ORM{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/registrysyncer/orm.go b/core/services/registrysyncer/orm.go
new file mode 100644
index 00000000000..cb08eaafeaf
--- /dev/null
+++ b/core/services/registrysyncer/orm.go
@@ -0,0 +1,167 @@
+package registrysyncer
+
+import (
+ "context"
+ "crypto/sha256"
+ "encoding/json"
+ "fmt"
+ "math/big"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
+
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
+)
+
+type capabilitiesRegistryNodeInfo struct {
+ NodeOperatorId uint32 `json:"nodeOperatorId"`
+ ConfigCount uint32 `json:"configCount"`
+ WorkflowDONId uint32 `json:"workflowDONId"`
+ Signer p2ptypes.PeerID `json:"signer"`
+ P2pId p2ptypes.PeerID `json:"p2pId"`
+ HashedCapabilityIds []p2ptypes.PeerID `json:"hashedCapabilityIds"`
+ CapabilitiesDONIds []string `json:"capabilitiesDONIds"`
+}
+
+func (l *LocalRegistry) MarshalJSON() ([]byte, error) {
+ idsToNodes := make(map[p2ptypes.PeerID]capabilitiesRegistryNodeInfo)
+ for k, v := range l.IDsToNodes {
+ hashedCapabilityIds := make([]p2ptypes.PeerID, len(v.HashedCapabilityIds))
+ for i, id := range v.HashedCapabilityIds {
+ hashedCapabilityIds[i] = p2ptypes.PeerID(id[:])
+ }
+ capabilitiesDONIds := make([]string, len(v.CapabilitiesDONIds))
+ for i, id := range v.CapabilitiesDONIds {
+ capabilitiesDONIds[i] = id.String()
+ }
+ idsToNodes[k] = capabilitiesRegistryNodeInfo{
+ NodeOperatorId: v.NodeOperatorId,
+ ConfigCount: v.ConfigCount,
+ WorkflowDONId: v.WorkflowDONId,
+ Signer: p2ptypes.PeerID(v.Signer[:]),
+ P2pId: p2ptypes.PeerID(v.P2pId[:]),
+ HashedCapabilityIds: hashedCapabilityIds,
+ CapabilitiesDONIds: capabilitiesDONIds,
+ }
+ }
+
+ b, err := json.Marshal(&struct {
+ IDsToDONs map[DonID]DON
+ IDsToNodes map[p2ptypes.PeerID]capabilitiesRegistryNodeInfo
+ IDsToCapabilities map[string]Capability
+ }{
+ IDsToDONs: l.IDsToDONs,
+ IDsToNodes: idsToNodes,
+ IDsToCapabilities: l.IDsToCapabilities,
+ })
+ if err != nil {
+ return []byte{}, err
+ }
+ return b, nil
+}
+
+func (l *LocalRegistry) UnmarshalJSON(data []byte) error {
+ temp := struct {
+ IDsToDONs map[DonID]DON
+ IDsToNodes map[p2ptypes.PeerID]capabilitiesRegistryNodeInfo
+ IDsToCapabilities map[string]Capability
+ }{
+ IDsToDONs: make(map[DonID]DON),
+ IDsToNodes: make(map[p2ptypes.PeerID]capabilitiesRegistryNodeInfo),
+ IDsToCapabilities: make(map[string]Capability),
+ }
+
+ if err := json.Unmarshal(data, &temp); err != nil {
+ return fmt.Errorf("failed to unmarshal state: %w", err)
+ }
+
+ l.IDsToDONs = temp.IDsToDONs
+
+ l.IDsToNodes = make(map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo)
+ for peerID, v := range temp.IDsToNodes {
+ hashedCapabilityIds := make([][32]byte, len(v.HashedCapabilityIds))
+ for i, id := range v.HashedCapabilityIds {
+ copy(hashedCapabilityIds[i][:], id[:])
+ }
+
+ capabilitiesDONIds := make([]*big.Int, len(v.CapabilitiesDONIds))
+ for i, id := range v.CapabilitiesDONIds {
+ bigInt := new(big.Int)
+ bigInt.SetString(id, 10)
+ capabilitiesDONIds[i] = bigInt
+ }
+ l.IDsToNodes[peerID] = kcr.CapabilitiesRegistryNodeInfo{
+ NodeOperatorId: v.NodeOperatorId,
+ ConfigCount: v.ConfigCount,
+ WorkflowDONId: v.WorkflowDONId,
+ Signer: v.Signer,
+ P2pId: v.P2pId,
+ HashedCapabilityIds: hashedCapabilityIds,
+ CapabilitiesDONIds: capabilitiesDONIds,
+ }
+ }
+
+ l.IDsToCapabilities = temp.IDsToCapabilities
+
+ return nil
+}
+
+type ORM interface {
+ AddLocalRegistry(ctx context.Context, localRegistry LocalRegistry) error
+ LatestLocalRegistry(ctx context.Context) (*LocalRegistry, error)
+}
+
+type orm struct {
+ ds sqlutil.DataSource
+ lggr logger.Logger
+}
+
+var _ ORM = (*orm)(nil)
+
+func NewORM(ds sqlutil.DataSource, lggr logger.Logger) orm {
+ namedLogger := lggr.Named("RegistrySyncerORM")
+ return orm{
+ ds: ds,
+ lggr: namedLogger,
+ }
+}
+
+func (orm orm) AddLocalRegistry(ctx context.Context, localRegistry LocalRegistry) error {
+ return sqlutil.TransactDataSource(ctx, orm.ds, nil, func(tx sqlutil.DataSource) error {
+ localRegistryJSON, err := localRegistry.MarshalJSON()
+ if err != nil {
+ return err
+ }
+ hash := sha256.Sum256(localRegistryJSON)
+ _, err = tx.ExecContext(
+ ctx,
+ `INSERT INTO registry_syncer_states (data, data_hash) VALUES ($1, $2) ON CONFLICT (data_hash) DO NOTHING`,
+ localRegistryJSON, fmt.Sprintf("%x", hash[:]),
+ )
+ if err != nil {
+ return err
+ }
+ _, err = tx.ExecContext(ctx, `DELETE FROM registry_syncer_states
+WHERE data_hash NOT IN (
+ SELECT data_hash FROM registry_syncer_states
+ ORDER BY id DESC
+ LIMIT 10
+);`)
+ return err
+ })
+}
+
+func (orm orm) LatestLocalRegistry(ctx context.Context) (*LocalRegistry, error) {
+ var localRegistry LocalRegistry
+ var localRegistryJSON string
+ err := orm.ds.GetContext(ctx, &localRegistryJSON, `SELECT data FROM registry_syncer_states ORDER BY id DESC LIMIT 1`)
+ if err != nil {
+ return nil, err
+ }
+ err = localRegistry.UnmarshalJSON([]byte(localRegistryJSON))
+ if err != nil {
+ return nil, err
+ }
+ return &localRegistry, nil
+}
diff --git a/core/services/registrysyncer/orm_test.go b/core/services/registrysyncer/orm_test.go
new file mode 100644
index 00000000000..03772ea22bf
--- /dev/null
+++ b/core/services/registrysyncer/orm_test.go
@@ -0,0 +1,145 @@
+package registrysyncer_test
+
+import (
+ "encoding/hex"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/types/known/durationpb"
+
+ ragetypes "github.com/smartcontractkit/libocr/ragep2p/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/capabilities"
+ capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
+ "github.com/smartcontractkit/chainlink-common/pkg/values"
+
+ kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+)
+
+func TestRegistrySyncerORM_InsertAndRetrieval(t *testing.T) {
+ db := pgtest.NewSqlxDB(t)
+ ctx := testutils.Context(t)
+ lggr := logger.TestLogger(t)
+ orm := registrysyncer.NewORM(db, lggr)
+
+ var states []registrysyncer.LocalRegistry
+ for i := 0; i < 11; i++ {
+ state := generateState(t)
+ err := orm.AddLocalRegistry(ctx, state)
+ require.NoError(t, err)
+ states = append(states, state)
+ }
+
+ var count int
+ err := db.Get(&count, `SELECT count(*) FROM registry_syncer_states`)
+ require.NoError(t, err)
+ assert.Equal(t, 10, count)
+
+ state, err := orm.LatestLocalRegistry(ctx)
+ require.NoError(t, err)
+ assert.Equal(t, states[10], *state)
+}
+
+func generateState(t *testing.T) registrysyncer.LocalRegistry {
+ dID := uint32(1)
+ var pid ragetypes.PeerID
+ err := pid.UnmarshalText([]byte("12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N"))
+ require.NoError(t, err)
+ nodes := [][32]byte{
+ pid,
+ randomWord(),
+ randomWord(),
+ randomWord(),
+ }
+ capabilityID := randomWord()
+ capabilityID2 := randomWord()
+ capabilityIDStr := hex.EncodeToString(capabilityID[:])
+ capabilityID2Str := hex.EncodeToString(capabilityID2[:])
+
+ config := &capabilitiespb.CapabilityConfig{
+ DefaultConfig: values.Proto(values.EmptyMap()).GetMapValue(),
+ RemoteConfig: &capabilitiespb.CapabilityConfig_RemoteTriggerConfig{
+ RemoteTriggerConfig: &capabilitiespb.RemoteTriggerConfig{
+ RegistrationRefresh: durationpb.New(20 * time.Second),
+ RegistrationExpiry: durationpb.New(60 * time.Second),
+ // F + 1
+ MinResponsesToAggregate: uint32(1) + 1,
+ MessageExpiry: durationpb.New(120 * time.Second),
+ },
+ },
+ }
+ configb, err := proto.Marshal(config)
+ require.NoError(t, err)
+
+ return registrysyncer.LocalRegistry{
+ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{
+ registrysyncer.DonID(dID): {
+ DON: capabilities.DON{
+ ID: dID,
+ ConfigVersion: uint32(0),
+ F: uint8(1),
+ IsPublic: true,
+ AcceptsWorkflows: true,
+ Members: toPeerIDs(nodes),
+ },
+ CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{
+ capabilityIDStr: {
+ Config: configb,
+ },
+ capabilityID2Str: {
+ Config: configb,
+ },
+ },
+ },
+ },
+ IDsToCapabilities: map[string]registrysyncer.Capability{
+ capabilityIDStr: {
+ ID: capabilityIDStr,
+ CapabilityType: capabilities.CapabilityTypeAction,
+ },
+ capabilityID2Str: {
+ ID: capabilityID2Str,
+ CapabilityType: capabilities.CapabilityTypeConsensus,
+ },
+ },
+ IDsToNodes: map[types.PeerID]kcr.CapabilitiesRegistryNodeInfo{
+ nodes[0]: {
+ NodeOperatorId: 1,
+ Signer: randomWord(),
+ P2pId: nodes[0],
+ HashedCapabilityIds: [][32]byte{capabilityID, capabilityID2},
+ CapabilitiesDONIds: []*big.Int{},
+ },
+ nodes[1]: {
+ NodeOperatorId: 1,
+ Signer: randomWord(),
+ P2pId: nodes[1],
+ HashedCapabilityIds: [][32]byte{capabilityID, capabilityID2},
+ CapabilitiesDONIds: []*big.Int{},
+ },
+ nodes[2]: {
+ NodeOperatorId: 1,
+ Signer: randomWord(),
+ P2pId: nodes[2],
+ HashedCapabilityIds: [][32]byte{capabilityID, capabilityID2},
+ CapabilitiesDONIds: []*big.Int{},
+ },
+ nodes[3]: {
+ NodeOperatorId: 1,
+ Signer: randomWord(),
+ P2pId: nodes[3],
+ HashedCapabilityIds: [][32]byte{capabilityID, capabilityID2},
+ CapabilitiesDONIds: []*big.Int{},
+ },
+ },
+ }
+}
diff --git a/core/services/registrysyncer/syncer.go b/core/services/registrysyncer/syncer.go
index 6a44ff561d5..ab50c448b5c 100644
--- a/core/services/registrysyncer/syncer.go
+++ b/core/services/registrysyncer/syncer.go
@@ -4,17 +4,14 @@ import (
"context"
"encoding/json"
"fmt"
+ "math/big"
"sync"
"time"
- "google.golang.org/protobuf/proto"
-
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
- capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
- "github.com/smartcontractkit/chainlink-common/pkg/values"
kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
"github.com/smartcontractkit/chainlink/v2/core/logger"
@@ -31,15 +28,33 @@ type Syncer interface {
AddLauncher(h ...Launcher)
}
+type ContractReaderFactory interface {
+ NewContractReader(context.Context, []byte) (types.ContractReader, error)
+}
+
+type RegistrySyncer interface {
+ Sync(ctx context.Context, isInitialSync bool) error
+ AddLauncher(launchers ...Launcher)
+ Start(ctx context.Context) error
+ Close() error
+ Ready() error
+ HealthReport() map[string]error
+ Name() string
+}
+
type registrySyncer struct {
services.StateMachine
stopCh services.StopChan
launchers []Launcher
reader types.ContractReader
- initReader func(ctx context.Context, lggr logger.Logger, relayer contractReaderFactory, registryAddress string) (types.ContractReader, error)
- relayer contractReaderFactory
+ initReader func(ctx context.Context, lggr logger.Logger, relayer ContractReaderFactory, registryAddress string) (types.ContractReader, error)
+ relayer ContractReaderFactory
registryAddress string
- peerWrapper p2ptypes.PeerWrapper
+ getPeerID func() (p2ptypes.PeerID, error)
+
+ orm ORM
+
+ updateChan chan *LocalRegistry
wg sync.WaitGroup
lggr logger.Logger
@@ -55,29 +70,27 @@ var (
// New instantiates a new RegistrySyncer
func New(
lggr logger.Logger,
- peerWrapper p2ptypes.PeerWrapper,
- relayer contractReaderFactory,
+ getPeerID func() (p2ptypes.PeerID, error),
+ relayer ContractReaderFactory,
registryAddress string,
-) (*registrySyncer, error) {
- stopCh := make(services.StopChan)
+ orm ORM,
+) (RegistrySyncer, error) {
return ®istrySyncer{
- stopCh: stopCh,
+ stopCh: make(services.StopChan),
+ updateChan: make(chan *LocalRegistry),
lggr: lggr.Named("RegistrySyncer"),
relayer: relayer,
registryAddress: registryAddress,
initReader: newReader,
- peerWrapper: peerWrapper,
+ orm: orm,
+ getPeerID: getPeerID,
}, nil
}
-type contractReaderFactory interface {
- NewContractReader(context.Context, []byte) (types.ContractReader, error)
-}
-
// NOTE: this can't be called while initializing the syncer and needs to be called in the sync loop.
// This is because Bind() makes an onchain call to verify that the contract address exists, and if
// called during initialization, this results in a "no live nodes" error.
-func newReader(ctx context.Context, lggr logger.Logger, relayer contractReaderFactory, remoteRegistryAddress string) (types.ContractReader, error) {
+func newReader(ctx context.Context, lggr logger.Logger, relayer ContractReaderFactory, remoteRegistryAddress string) (types.ContractReader, error) {
contractReaderConfig := evmrelaytypes.ChainReaderConfig{
Contracts: map[string]evmrelaytypes.ChainContractReader{
"CapabilitiesRegistry": {
@@ -124,6 +137,11 @@ func (s *registrySyncer) Start(ctx context.Context) error {
defer s.wg.Done()
s.syncLoop()
}()
+ s.wg.Add(1)
+ go func() {
+ defer s.wg.Done()
+ s.updateStateLoop()
+ }()
return nil
})
}
@@ -139,7 +157,7 @@ func (s *registrySyncer) syncLoop() {
// sync immediately once spinning up syncLoop, as by default a ticker will
// fire for the first time at T+N, where N is the interval.
s.lggr.Debug("starting initial sync with remote registry")
- err := s.sync(ctx)
+ err := s.Sync(ctx, true)
if err != nil {
s.lggr.Errorw("failed to sync with remote registry", "error", err)
}
@@ -150,7 +168,7 @@ func (s *registrySyncer) syncLoop() {
return
case <-ticker.C:
s.lggr.Debug("starting regular sync with the remote registry")
- err := s.sync(ctx)
+ err := s.Sync(ctx, false)
if err != nil {
s.lggr.Errorw("failed to sync with remote registry", "error", err)
}
@@ -158,29 +176,28 @@ func (s *registrySyncer) syncLoop() {
}
}
-func unmarshalCapabilityConfig(data []byte) (capabilities.CapabilityConfiguration, error) {
- cconf := &capabilitiespb.CapabilityConfig{}
- err := proto.Unmarshal(data, cconf)
- if err != nil {
- return capabilities.CapabilityConfiguration{}, err
- }
+func (s *registrySyncer) updateStateLoop() {
+ ctx, cancel := s.stopCh.NewCtx()
+ defer cancel()
- var rtc capabilities.RemoteTriggerConfig
- if prtc := cconf.GetRemoteTriggerConfig(); prtc != nil {
- rtc.RegistrationRefresh = prtc.RegistrationRefresh.AsDuration()
- rtc.RegistrationExpiry = prtc.RegistrationExpiry.AsDuration()
- rtc.MinResponsesToAggregate = prtc.MinResponsesToAggregate
- rtc.MessageExpiry = prtc.MessageExpiry.AsDuration()
+ for {
+ select {
+ case <-s.stopCh:
+ return
+ case localRegistry, ok := <-s.updateChan:
+ if !ok {
+ // channel has been closed, terminating.
+ return
+ }
+ if err := s.orm.AddLocalRegistry(ctx, *localRegistry); err != nil {
+ s.lggr.Errorw("failed to save state to local registry", "error", err)
+ }
+ }
}
-
- return capabilities.CapabilityConfiguration{
- DefaultConfig: values.FromMapValueProto(cconf.DefaultConfig),
- RemoteTriggerConfig: rtc,
- }, nil
}
func (s *registrySyncer) localRegistry(ctx context.Context) (*LocalRegistry, error) {
- caps := []kcr.CapabilitiesRegistryCapabilityInfo{}
+ var caps []kcr.CapabilitiesRegistryCapabilityInfo
err := s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getCapabilities", primitives.Unconfirmed, nil, &caps)
if err != nil {
return nil, err
@@ -198,7 +215,7 @@ func (s *registrySyncer) localRegistry(ctx context.Context) (*LocalRegistry, err
hashedIDsToCapabilityIDs[c.HashedId] = cid
}
- dons := []kcr.CapabilitiesRegistryDONInfo{}
+ var dons []kcr.CapabilitiesRegistryDONInfo
err = s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getDONs", primitives.Unconfirmed, nil, &dons)
if err != nil {
return nil, err
@@ -206,21 +223,16 @@ func (s *registrySyncer) localRegistry(ctx context.Context) (*LocalRegistry, err
idsToDONs := map[DonID]DON{}
for _, d := range dons {
- cc := map[string]capabilities.CapabilityConfiguration{}
+ cc := map[string]CapabilityConfiguration{}
for _, dc := range d.CapabilityConfigurations {
cid, ok := hashedIDsToCapabilityIDs[dc.CapabilityId]
if !ok {
return nil, fmt.Errorf("invariant violation: could not find full ID for hashed ID %s", dc.CapabilityId)
}
- cconf, innerErr := unmarshalCapabilityConfig(dc.Config)
- if innerErr != nil {
- return nil, innerErr
+ cc[cid] = CapabilityConfiguration{
+ Config: dc.Config,
}
-
- cconf.RemoteTriggerConfig.ApplyDefaults()
-
- cc[cid] = cconf
}
idsToDONs[DonID(d.Id)] = DON{
@@ -229,7 +241,7 @@ func (s *registrySyncer) localRegistry(ctx context.Context) (*LocalRegistry, err
}
}
- nodes := []kcr.CapabilitiesRegistryNodeInfo{}
+ var nodes []kcr.CapabilitiesRegistryNodeInfo
err = s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getNodes", primitives.Unconfirmed, nil, &nodes)
if err != nil {
return nil, err
@@ -242,14 +254,14 @@ func (s *registrySyncer) localRegistry(ctx context.Context) (*LocalRegistry, err
return &LocalRegistry{
lggr: s.lggr,
- peerWrapper: s.peerWrapper,
+ getPeerID: s.getPeerID,
IDsToDONs: idsToDONs,
IDsToCapabilities: idsToCapabilities,
IDsToNodes: idsToNodes,
}, nil
}
-func (s *registrySyncer) sync(ctx context.Context) error {
+func (s *registrySyncer) Sync(ctx context.Context, isInitialSync bool) error {
s.mu.RLock()
defer s.mu.RUnlock()
@@ -267,13 +279,44 @@ func (s *registrySyncer) sync(ctx context.Context) error {
s.reader = reader
}
- lr, err := s.localRegistry(ctx)
- if err != nil {
- return fmt.Errorf("failed to sync with remote registry: %w", err)
+ var lr *LocalRegistry
+ var err error
+
+ if isInitialSync {
+ s.lggr.Debug("syncing with local registry")
+ lr, err = s.orm.LatestLocalRegistry(ctx)
+ if err != nil {
+ s.lggr.Warnw("failed to sync with local registry, using remote registry instead", "error", err)
+ } else {
+ lr.lggr = s.lggr
+ lr.getPeerID = s.getPeerID
+ }
+ }
+
+ if lr == nil {
+ s.lggr.Debug("syncing with remote registry")
+ localRegistry, err := s.localRegistry(ctx)
+ if err != nil {
+ return fmt.Errorf("failed to sync with remote registry: %w", err)
+ }
+ lr = localRegistry
+ // Attempt to send local registry to the update channel without blocking
+ // This is to prevent the tests from hanging if they are not calling `Start()` on the syncer
+ select {
+ case <-s.stopCh:
+ s.lggr.Debug("sync cancelled, stopping")
+ case s.updateChan <- lr:
+ // Successfully sent state
+ s.lggr.Debug("remote registry update triggered successfully")
+ default:
+ // No one is ready to receive the state, handle accordingly
+ s.lggr.Debug("no listeners on update channel, remote registry update skipped")
+ }
}
for _, h := range s.launchers {
- if err := h.Launch(ctx, lr); err != nil {
+ lrCopy := deepCopyLocalRegistry(lr)
+ if err := h.Launch(ctx, &lrCopy); err != nil {
s.lggr.Errorf("error calling launcher: %s", err)
}
}
@@ -281,6 +324,58 @@ func (s *registrySyncer) sync(ctx context.Context) error {
return nil
}
+func deepCopyLocalRegistry(lr *LocalRegistry) LocalRegistry {
+ var lrCopy LocalRegistry
+ lrCopy.lggr = lr.lggr
+ lrCopy.getPeerID = lr.getPeerID
+ lrCopy.IDsToDONs = make(map[DonID]DON, len(lr.IDsToDONs))
+ for id, don := range lr.IDsToDONs {
+ d := capabilities.DON{
+ ID: don.ID,
+ ConfigVersion: don.ConfigVersion,
+ Members: make([]p2ptypes.PeerID, len(don.Members)),
+ F: don.F,
+ IsPublic: don.IsPublic,
+ AcceptsWorkflows: don.AcceptsWorkflows,
+ }
+ copy(d.Members, don.Members)
+ capCfgs := make(map[string]CapabilityConfiguration, len(don.CapabilityConfigurations))
+ for capID, capCfg := range don.CapabilityConfigurations {
+ capCfgs[capID] = CapabilityConfiguration{
+ Config: capCfg.Config[:],
+ }
+ }
+ lrCopy.IDsToDONs[id] = DON{
+ DON: d,
+ CapabilityConfigurations: capCfgs,
+ }
+ }
+
+ lrCopy.IDsToCapabilities = make(map[string]Capability, len(lr.IDsToCapabilities))
+ for id, capability := range lr.IDsToCapabilities {
+ cp := capability
+ lrCopy.IDsToCapabilities[id] = cp
+ }
+
+ lrCopy.IDsToNodes = make(map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo, len(lr.IDsToNodes))
+ for id, node := range lr.IDsToNodes {
+ nodeInfo := kcr.CapabilitiesRegistryNodeInfo{
+ NodeOperatorId: node.NodeOperatorId,
+ ConfigCount: node.ConfigCount,
+ WorkflowDONId: node.WorkflowDONId,
+ Signer: node.Signer,
+ P2pId: node.P2pId,
+ HashedCapabilityIds: make([][32]byte, len(node.HashedCapabilityIds)),
+ CapabilitiesDONIds: make([]*big.Int, len(node.CapabilitiesDONIds)),
+ }
+ copy(nodeInfo.HashedCapabilityIds, node.HashedCapabilityIds)
+ copy(nodeInfo.CapabilitiesDONIds, node.CapabilitiesDONIds)
+ lrCopy.IDsToNodes[id] = nodeInfo
+ }
+
+ return lrCopy
+}
+
func toCapabilityType(capabilityType uint8) capabilities.CapabilityType {
switch capabilityType {
case 0:
@@ -292,8 +387,7 @@ func toCapabilityType(capabilityType uint8) capabilities.CapabilityType {
case 3:
return capabilities.CapabilityTypeTarget
default:
- // Not found
- return capabilities.CapabilityType(-1)
+ return capabilities.CapabilityTypeUnknown
}
}
@@ -322,6 +416,9 @@ func (s *registrySyncer) AddLauncher(launchers ...Launcher) {
func (s *registrySyncer) Close() error {
return s.StopOnce("RegistrySyncer", func() error {
close(s.stopCh)
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ close(s.updateChan)
s.wg.Wait()
return nil
})
diff --git a/core/services/registrysyncer/syncer_test.go b/core/services/registrysyncer/syncer_test.go
index b926183394e..9e51b7498f0 100644
--- a/core/services/registrysyncer/syncer_test.go
+++ b/core/services/registrysyncer/syncer_test.go
@@ -1,4 +1,4 @@
-package registrysyncer
+package registrysyncer_test
import (
"context"
@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"math/big"
+ "sync"
"testing"
"time"
@@ -15,6 +16,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/durationpb"
@@ -25,6 +27,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/values"
capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
+
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
@@ -33,7 +36,8 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
"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"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
+ syncerMocks "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer/mocks"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
@@ -127,16 +131,51 @@ func randomWord() [32]byte {
}
type launcher struct {
- localRegistry *LocalRegistry
+ localRegistry *registrysyncer.LocalRegistry
+ mu sync.RWMutex
}
-func (l *launcher) Launch(ctx context.Context, localRegistry *LocalRegistry) error {
+func (l *launcher) Launch(ctx context.Context, localRegistry *registrysyncer.LocalRegistry) error {
+ l.mu.Lock()
+ defer l.mu.Unlock()
l.localRegistry = localRegistry
return nil
}
+type orm struct {
+ ormMock *syncerMocks.ORM
+ latestLocalRegistryCh chan struct{}
+ addLocalRegistryCh chan struct{}
+}
+
+func newORM(t *testing.T) *orm {
+ t.Helper()
+
+ return &orm{
+ ormMock: syncerMocks.NewORM(t),
+ latestLocalRegistryCh: make(chan struct{}, 1),
+ addLocalRegistryCh: make(chan struct{}, 1),
+ }
+}
+
+func (o *orm) Cleanup() {
+ close(o.latestLocalRegistryCh)
+ close(o.addLocalRegistryCh)
+}
+
+func (o *orm) AddLocalRegistry(ctx context.Context, localRegistry registrysyncer.LocalRegistry) error {
+ o.addLocalRegistryCh <- struct{}{}
+ err := o.ormMock.AddLocalRegistry(ctx, localRegistry)
+ return err
+}
+
+func (o *orm) LatestLocalRegistry(ctx context.Context) (*registrysyncer.LocalRegistry, error) {
+ o.latestLocalRegistryCh <- struct{}{}
+ return o.ormMock.LatestLocalRegistry(ctx)
+}
+
func toPeerIDs(ids [][32]byte) []p2ptypes.PeerID {
- pids := []p2ptypes.PeerID{}
+ var pids []p2ptypes.PeerID
for _, id := range ids {
pids = append(pids, id)
}
@@ -210,6 +249,7 @@ func TestReader_Integration(t *testing.T) {
RegistrationExpiry: durationpb.New(60 * time.Second),
// F + 1
MinResponsesToAggregate: uint32(1) + 1,
+ MessageExpiry: durationpb.New(120 * time.Second),
},
},
}
@@ -236,49 +276,38 @@ func TestReader_Integration(t *testing.T) {
require.NoError(t, err)
- wrapper := mocks.NewPeerWrapper(t)
+ db := pgtest.NewSqlxDB(t)
factory := newContractReaderFactory(t, sim)
- syncer, err := New(logger.TestLogger(t), wrapper, factory, regAddress.Hex())
+ syncerORM := registrysyncer.NewORM(db, logger.TestLogger(t))
+ syncer, err := registrysyncer.New(logger.TestLogger(t), func() (p2ptypes.PeerID, error) { return p2ptypes.PeerID{}, nil }, factory, regAddress.Hex(), syncerORM)
require.NoError(t, err)
l := &launcher{}
syncer.AddLauncher(l)
- err = syncer.sync(ctx)
+ err = syncer.Sync(ctx, false) // not looking to load from the DB in this specific test.
s := l.localRegistry
require.NoError(t, err)
assert.Len(t, s.IDsToCapabilities, 1)
gotCap := s.IDsToCapabilities[cid]
- assert.Equal(t, Capability{
+ assert.Equal(t, registrysyncer.Capability{
CapabilityType: capabilities.CapabilityTypeTarget,
ID: "write-chain@1.0.1",
}, gotCap)
assert.Len(t, s.IDsToDONs, 1)
- rtc := capabilities.RemoteTriggerConfig{
- RegistrationRefresh: 20 * time.Second,
- MinResponsesToAggregate: 2,
- RegistrationExpiry: 60 * time.Second,
- MessageExpiry: 120 * time.Second,
- }
- expectedDON := DON{
- DON: capabilities.DON{
- ID: 1,
- ConfigVersion: 1,
- IsPublic: true,
- AcceptsWorkflows: true,
- F: 1,
- Members: toPeerIDs(nodeSet),
- },
- CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{
- cid: {
- DefaultConfig: values.EmptyMap(),
- RemoteTriggerConfig: rtc,
- },
- },
+ expectedDON := capabilities.DON{
+ ID: 1,
+ ConfigVersion: 1,
+ IsPublic: true,
+ AcceptsWorkflows: true,
+ F: 1,
+ Members: toPeerIDs(nodeSet),
}
- assert.Equal(t, expectedDON, s.IDsToDONs[1])
+ gotDon := s.IDsToDONs[1]
+ assert.Equal(t, expectedDON, gotDon.DON)
+ assert.Equal(t, configb, gotDon.CapabilityConfigurations[cid].Config)
nodesInfo := []kcr.CapabilitiesRegistryNodeInfo{
{
@@ -321,6 +350,127 @@ func TestReader_Integration(t *testing.T) {
}, s.IDsToNodes)
}
+func TestSyncer_DBIntegration(t *testing.T) {
+ ctx := testutils.Context(t)
+ reg, regAddress, owner, sim := startNewChainWithRegistry(t)
+
+ _, err := reg.AddCapabilities(owner, []kcr.CapabilitiesRegistryCapability{writeChainCapability})
+ require.NoError(t, err, "AddCapability failed for %s", writeChainCapability.LabelledName)
+ sim.Commit()
+
+ cid, err := reg.GetHashedCapabilityId(&bind.CallOpts{}, writeChainCapability.LabelledName, writeChainCapability.Version)
+ require.NoError(t, err)
+
+ _, err = reg.AddNodeOperators(owner, []kcr.CapabilitiesRegistryNodeOperator{
+ {
+ Admin: owner.From,
+ Name: "TEST_NOP",
+ },
+ })
+ require.NoError(t, err)
+
+ nodeSet := [][32]byte{
+ randomWord(),
+ randomWord(),
+ randomWord(),
+ }
+
+ signersSet := [][32]byte{
+ randomWord(),
+ randomWord(),
+ randomWord(),
+ }
+
+ nodes := []kcr.CapabilitiesRegistryNodeParams{
+ {
+ // The first NodeOperatorId has id 1 since the id is auto-incrementing.
+ NodeOperatorId: uint32(1),
+ Signer: signersSet[0],
+ P2pId: nodeSet[0],
+ HashedCapabilityIds: [][32]byte{cid},
+ },
+ {
+ // The first NodeOperatorId has id 1 since the id is auto-incrementing.
+ NodeOperatorId: uint32(1),
+ Signer: signersSet[1],
+ P2pId: nodeSet[1],
+ HashedCapabilityIds: [][32]byte{cid},
+ },
+ {
+ // The first NodeOperatorId has id 1 since the id is auto-incrementing.
+ NodeOperatorId: uint32(1),
+ Signer: signersSet[2],
+ P2pId: nodeSet[2],
+ HashedCapabilityIds: [][32]byte{cid},
+ },
+ }
+ _, err = reg.AddNodes(owner, nodes)
+ require.NoError(t, err)
+
+ config := &capabilitiespb.CapabilityConfig{
+ DefaultConfig: values.Proto(values.EmptyMap()).GetMapValue(),
+ RemoteConfig: &capabilitiespb.CapabilityConfig_RemoteTriggerConfig{
+ RemoteTriggerConfig: &capabilitiespb.RemoteTriggerConfig{
+ RegistrationRefresh: durationpb.New(20 * time.Second),
+ RegistrationExpiry: durationpb.New(60 * time.Second),
+ // F + 1
+ MinResponsesToAggregate: uint32(1) + 1,
+ },
+ },
+ }
+ configb, err := proto.Marshal(config)
+ require.NoError(t, err)
+
+ cfgs := []kcr.CapabilitiesRegistryCapabilityConfiguration{
+ {
+ CapabilityId: cid,
+ Config: configb,
+ },
+ }
+ _, err = reg.AddDON(
+ owner,
+ nodeSet,
+ cfgs,
+ true,
+ true,
+ 1,
+ )
+ sim.Commit()
+
+ require.NoError(t, err)
+
+ factory := newContractReaderFactory(t, sim)
+ syncerORM := newORM(t)
+ syncerORM.ormMock.On("LatestLocalRegistry", mock.Anything).Return(nil, fmt.Errorf("no state found"))
+ syncerORM.ormMock.On("AddLocalRegistry", mock.Anything, mock.Anything).Return(nil)
+ syncer, err := newTestSyncer(logger.TestLogger(t), func() (p2ptypes.PeerID, error) { return p2ptypes.PeerID{}, nil }, factory, regAddress.Hex(), syncerORM)
+ require.NoError(t, err)
+ require.NoError(t, syncer.Start(ctx))
+ t.Cleanup(func() {
+ syncerORM.Cleanup()
+ require.NoError(t, syncer.Close())
+ })
+
+ l := &launcher{}
+ syncer.AddLauncher(l)
+
+ var latestLocalRegistryCalled, addLocalRegistryCalled bool
+ timeout := time.After(testutils.WaitTimeout(t))
+
+ for !latestLocalRegistryCalled || !addLocalRegistryCalled {
+ select {
+ case val := <-syncerORM.latestLocalRegistryCh:
+ assert.Equal(t, struct{}{}, val)
+ latestLocalRegistryCalled = true
+ case val := <-syncerORM.addLocalRegistryCh:
+ assert.Equal(t, struct{}{}, val)
+ addLocalRegistryCalled = true
+ case <-timeout:
+ t.Fatal("test timed out; channels did not received data")
+ }
+ }
+}
+
func TestSyncer_LocalNode(t *testing.T) {
ctx := tests.Context(t)
lggr := logger.TestLogger(t)
@@ -328,10 +478,6 @@ func TestSyncer_LocalNode(t *testing.T) {
var pid p2ptypes.PeerID
err := pid.UnmarshalText([]byte("12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N"))
require.NoError(t, err)
- peer := mocks.NewPeer(t)
- peer.On("ID").Return(pid)
- wrapper := mocks.NewPeerWrapper(t)
- wrapper.On("GetPeer").Return(peer)
workflowDonNodes := []p2ptypes.PeerID{
pid,
@@ -344,11 +490,11 @@ func TestSyncer_LocalNode(t *testing.T) {
// The below state describes a Workflow DON (AcceptsWorkflows = true),
// which exposes the streams-trigger and write_chain capabilities.
// We expect receivers to be wired up and both capabilities to be added to the registry.
- localRegistry := LocalRegistry{
- lggr: lggr,
- peerWrapper: wrapper,
- IDsToDONs: map[DonID]DON{
- DonID(dID): {
+ localRegistry := registrysyncer.NewLocalRegistry(
+ lggr,
+ func() (p2ptypes.PeerID, error) { return pid, nil },
+ map[registrysyncer.DonID]registrysyncer.DON{
+ registrysyncer.DonID(dID): {
DON: capabilities.DON{
ID: dID,
ConfigVersion: uint32(2),
@@ -359,7 +505,7 @@ func TestSyncer_LocalNode(t *testing.T) {
},
},
},
- IDsToNodes: map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo{
+ map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo{
workflowDonNodes[0]: {
NodeOperatorId: 1,
Signer: randomWord(),
@@ -381,7 +527,8 @@ func TestSyncer_LocalNode(t *testing.T) {
P2pId: workflowDonNodes[3],
},
},
- }
+ map[string]registrysyncer.Capability{},
+ )
node, err := localRegistry.LocalNode(ctx)
require.NoError(t, err)
@@ -401,3 +548,17 @@ func TestSyncer_LocalNode(t *testing.T) {
}
assert.Equal(t, expectedNode, node)
}
+
+func newTestSyncer(
+ lggr logger.Logger,
+ getPeerID func() (p2ptypes.PeerID, error),
+ relayer registrysyncer.ContractReaderFactory,
+ registryAddress string,
+ orm *orm,
+) (registrysyncer.RegistrySyncer, error) {
+ rs, err := registrysyncer.New(lggr, getPeerID, relayer, registryAddress, orm)
+ if err != nil {
+ return nil, err
+ }
+ return rs, nil
+}
diff --git a/core/services/relay/evm/batch_caller.go b/core/services/relay/evm/batch_caller.go
index 3ee4525827a..ce5a2bd722a 100644
--- a/core/services/relay/evm/batch_caller.go
+++ b/core/services/relay/evm/batch_caller.go
@@ -11,9 +11,10 @@ import (
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/types"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
)
var errEmptyOutput = errors.New("rpc call output is empty (make sure that the contract method exists and rpc is healthy)")
@@ -148,7 +149,7 @@ func (c *defaultEvmBatchCaller) batchCall(ctx context.Context, blockNumber uint6
map[string]interface{}{
"from": common.Address{},
"to": call.ContractAddress,
- "data": data,
+ "data": hexutil.Bytes(data),
},
blockNumStr,
},
diff --git a/core/services/relay/evm/batch_caller_test.go b/core/services/relay/evm/batch_caller_test.go
index 995e47618cc..048df90daba 100644
--- a/core/services/relay/evm/batch_caller_test.go
+++ b/core/services/relay/evm/batch_caller_test.go
@@ -1,12 +1,12 @@
package evm_test
import (
- "encoding/hex"
"fmt"
"math/big"
"testing"
"github.com/cometbft/cometbft/libs/rand"
+ "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rpc"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
@@ -152,12 +152,10 @@ func TestDefaultEvmBatchCaller_batchCallLimit(t *testing.T) {
Run(func(args mock.Arguments) {
evmCalls := args.Get(1).([]rpc.BatchElem)
for i := range evmCalls {
- arg := evmCalls[i].Args[0].(map[string]interface{})["data"].([]uint8)
- bytes, err := hex.DecodeString(fmt.Sprintf("%x", arg))
- require.NoError(t, err)
+ arg := evmCalls[i].Args[0].(map[string]interface{})["data"].(hexutil.Bytes)
str, isOk := evmCalls[i].Result.(*string)
require.True(t, isOk)
- *str = fmt.Sprintf("0x%064x", new(big.Int).SetBytes(bytes[24:]).Uint64())
+ *str = fmt.Sprintf("0x%064x", new(big.Int).SetBytes(arg[24:]).Uint64())
}
}).Return(nil)
diff --git a/core/services/relay/evm/ccip.go b/core/services/relay/evm/ccip.go
new file mode 100644
index 00000000000..3eefb7bec7b
--- /dev/null
+++ b/core/services/relay/evm/ccip.go
@@ -0,0 +1,203 @@
+package evm
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "time"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/prices"
+)
+
+var _ cciptypes.CommitStoreReader = (*IncompleteSourceCommitStoreReader)(nil)
+var _ cciptypes.CommitStoreReader = (*IncompleteDestCommitStoreReader)(nil)
+
+// IncompleteSourceCommitStoreReader is an implementation of CommitStoreReader with the only valid methods being
+// GasPriceEstimator, ChangeConfig, and OffchainConfig
+type IncompleteSourceCommitStoreReader struct {
+ estimator gas.EvmFeeEstimator
+ gasPriceEstimator *prices.DAGasPriceEstimator
+ sourceMaxGasPrice *big.Int
+ offchainConfig cciptypes.CommitOffchainConfig
+}
+
+func NewIncompleteSourceCommitStoreReader(estimator gas.EvmFeeEstimator, sourceMaxGasPrice *big.Int) *IncompleteSourceCommitStoreReader {
+ return &IncompleteSourceCommitStoreReader{
+ estimator: estimator,
+ sourceMaxGasPrice: sourceMaxGasPrice,
+ }
+}
+
+func (i *IncompleteSourceCommitStoreReader) ChangeConfig(ctx context.Context, onchainConfig []byte, offchainConfig []byte) (cciptypes.Address, error) {
+ onchainConfigParsed, err := abihelpers.DecodeAbiStruct[ccip.CommitOnchainConfig](onchainConfig)
+ if err != nil {
+ return "", err
+ }
+
+ offchainConfigParsed, err := ccipconfig.DecodeOffchainConfig[ccip.JSONCommitOffchainConfigV1_2_0](offchainConfig)
+ if err != nil {
+ return "", err
+ }
+
+ i.gasPriceEstimator = prices.NewDAGasPriceEstimator(
+ i.estimator,
+ i.sourceMaxGasPrice,
+ int64(offchainConfigParsed.ExecGasPriceDeviationPPB),
+ int64(offchainConfigParsed.DAGasPriceDeviationPPB),
+ )
+ i.offchainConfig = ccip.NewCommitOffchainConfig(
+ offchainConfigParsed.ExecGasPriceDeviationPPB,
+ offchainConfigParsed.GasPriceHeartBeat.Duration(),
+ offchainConfigParsed.TokenPriceDeviationPPB,
+ offchainConfigParsed.TokenPriceHeartBeat.Duration(),
+ offchainConfigParsed.InflightCacheExpiry.Duration(),
+ offchainConfigParsed.PriceReportingDisabled,
+ )
+
+ return cciptypes.Address(onchainConfigParsed.PriceRegistry.String()), nil
+}
+
+func (i *IncompleteSourceCommitStoreReader) DecodeCommitReport(ctx context.Context, report []byte) (cciptypes.CommitStoreReport, error) {
+ return cciptypes.CommitStoreReport{}, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) EncodeCommitReport(ctx context.Context, report cciptypes.CommitStoreReport) ([]byte, error) {
+ return []byte{}, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+// GasPriceEstimator returns an ExecGasPriceEstimator to satisfy the GasPriceEstimatorCommit interface,
+// with deviationPPB values hardcoded to 0 when this implementation is first constructed.
+// When ChangeConfig is called, another call to this method must be made to fetch a GasPriceEstimator with updated values
+func (i *IncompleteSourceCommitStoreReader) GasPriceEstimator(ctx context.Context) (cciptypes.GasPriceEstimatorCommit, error) {
+ return i.gasPriceEstimator, nil
+}
+
+func (i *IncompleteSourceCommitStoreReader) GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confirmations int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return nil, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) GetCommitReportMatchingSeqNum(ctx context.Context, seqNum uint64, confirmations int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return nil, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) GetCommitStoreStaticConfig(ctx context.Context) (cciptypes.CommitStoreStaticConfig, error) {
+ return cciptypes.CommitStoreStaticConfig{}, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) GetExpectedNextSequenceNumber(ctx context.Context) (uint64, error) {
+ return 0, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) GetLatestPriceEpochAndRound(ctx context.Context) (uint64, error) {
+ return 0, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) IsBlessed(ctx context.Context, root [32]byte) (bool, error) {
+ return false, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) IsDestChainHealthy(ctx context.Context) (bool, error) {
+ return false, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) IsDown(ctx context.Context) (bool, error) {
+ return false, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) OffchainConfig(ctx context.Context) (cciptypes.CommitOffchainConfig, error) {
+ return i.offchainConfig, nil
+}
+
+func (i *IncompleteSourceCommitStoreReader) VerifyExecutionReport(ctx context.Context, report cciptypes.ExecReport) (bool, error) {
+ return false, fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+func (i *IncompleteSourceCommitStoreReader) Close() error {
+ return fmt.Errorf("invalid usage of IncompleteSourceCommitStoreReader")
+}
+
+// IncompleteDestCommitStoreReader is an implementation of CommitStoreReader with all valid methods except
+// GasPriceEstimator, ChangeConfig, and OffchainConfig.
+type IncompleteDestCommitStoreReader struct {
+ cs cciptypes.CommitStoreReader
+}
+
+func NewIncompleteDestCommitStoreReader(lggr logger.Logger, versionFinder ccip.VersionFinder, address cciptypes.Address, ec client.Client, lp logpoller.LogPoller) (*IncompleteDestCommitStoreReader, error) {
+ cs, err := ccip.NewCommitStoreReader(lggr, versionFinder, address, ec, lp)
+ if err != nil {
+ return nil, err
+ }
+
+ return &IncompleteDestCommitStoreReader{
+ cs: cs,
+ }, nil
+}
+
+func (i *IncompleteDestCommitStoreReader) ChangeConfig(ctx context.Context, onchainConfig []byte, offchainConfig []byte) (cciptypes.Address, error) {
+ return "", fmt.Errorf("invalid usage of IncompleteDestCommitStoreReader")
+}
+
+func (i *IncompleteDestCommitStoreReader) DecodeCommitReport(ctx context.Context, report []byte) (cciptypes.CommitStoreReport, error) {
+ return i.cs.DecodeCommitReport(ctx, report)
+}
+
+func (i *IncompleteDestCommitStoreReader) EncodeCommitReport(ctx context.Context, report cciptypes.CommitStoreReport) ([]byte, error) {
+ return i.cs.EncodeCommitReport(ctx, report)
+}
+
+func (i *IncompleteDestCommitStoreReader) GasPriceEstimator(ctx context.Context) (cciptypes.GasPriceEstimatorCommit, error) {
+ return nil, fmt.Errorf("invalid usage of IncompleteDestCommitStoreReader")
+}
+
+func (i *IncompleteDestCommitStoreReader) GetAcceptedCommitReportsGteTimestamp(ctx context.Context, ts time.Time, confirmations int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return i.cs.GetAcceptedCommitReportsGteTimestamp(ctx, ts, confirmations)
+}
+
+func (i *IncompleteDestCommitStoreReader) GetCommitReportMatchingSeqNum(ctx context.Context, seqNum uint64, confirmations int) ([]cciptypes.CommitStoreReportWithTxMeta, error) {
+ return i.cs.GetCommitReportMatchingSeqNum(ctx, seqNum, confirmations)
+}
+
+func (i *IncompleteDestCommitStoreReader) GetCommitStoreStaticConfig(ctx context.Context) (cciptypes.CommitStoreStaticConfig, error) {
+ return i.cs.GetCommitStoreStaticConfig(ctx)
+}
+
+func (i *IncompleteDestCommitStoreReader) GetExpectedNextSequenceNumber(ctx context.Context) (uint64, error) {
+ return i.cs.GetExpectedNextSequenceNumber(ctx)
+}
+
+func (i *IncompleteDestCommitStoreReader) GetLatestPriceEpochAndRound(ctx context.Context) (uint64, error) {
+ return i.cs.GetLatestPriceEpochAndRound(ctx)
+}
+
+func (i *IncompleteDestCommitStoreReader) IsBlessed(ctx context.Context, root [32]byte) (bool, error) {
+ return i.cs.IsBlessed(ctx, root)
+}
+
+func (i *IncompleteDestCommitStoreReader) IsDestChainHealthy(ctx context.Context) (bool, error) {
+ return i.cs.IsDestChainHealthy(ctx)
+}
+
+func (i *IncompleteDestCommitStoreReader) IsDown(ctx context.Context) (bool, error) {
+ return i.cs.IsDown(ctx)
+}
+
+func (i *IncompleteDestCommitStoreReader) OffchainConfig(ctx context.Context) (cciptypes.CommitOffchainConfig, error) {
+ return cciptypes.CommitOffchainConfig{}, fmt.Errorf("invalid usage of IncompleteDestCommitStoreReader")
+}
+
+func (i *IncompleteDestCommitStoreReader) VerifyExecutionReport(ctx context.Context, report cciptypes.ExecReport) (bool, error) {
+ return i.cs.VerifyExecutionReport(ctx, report)
+}
+
+func (i *IncompleteDestCommitStoreReader) Close() error {
+ return i.cs.Close()
+}
diff --git a/core/services/relay/evm/ccip_test.go b/core/services/relay/evm/ccip_test.go
new file mode 100644
index 00000000000..8c0bfe182e1
--- /dev/null
+++ b/core/services/relay/evm/ccip_test.go
@@ -0,0 +1,18 @@
+package evm
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_CCIPSubjectUUID(t *testing.T) {
+ // We want the function to be
+ // (1) an actual function (i.e., deterministic)
+ assert.Equal(t, chainToUUID(big.NewInt(1)), chainToUUID(big.NewInt(1)))
+ // (2) injective (produce different results for different inputs)
+ assert.NotEqual(t, chainToUUID(big.NewInt(1)), chainToUUID(big.NewInt(2)))
+ // (3) stable across runs
+ assert.Equal(t, "c980e777-c95c-577b-83f6-ceb26a1a982d", chainToUUID(big.NewInt(1)).String())
+}
diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go
index d84c2f00a9c..0f1f6e72dd7 100644
--- a/core/services/relay/evm/chain_reader.go
+++ b/core/services/relay/evm/chain_reader.go
@@ -13,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/smartcontractkit/chainlink-common/pkg/codec"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
commonservices "github.com/smartcontractkit/chainlink-common/pkg/services"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
@@ -21,7 +22,6 @@ import (
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"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/logger"
"github.com/smartcontractkit/chainlink/v2/core/services"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
@@ -49,7 +49,7 @@ var _ commontypes.ContractTypeProvider = &chainReader{}
// Note that the ChainReaderService returned does not support anonymous events.
func NewChainReaderService(ctx context.Context, lggr logger.Logger, lp logpoller.LogPoller, ht logpoller.HeadTracker, client evmclient.Client, config types.ChainReaderConfig) (ChainReaderService, error) {
cr := &chainReader{
- lggr: lggr.Named("ChainReader"),
+ lggr: logger.Named(lggr, "ChainReader"),
ht: ht,
lp: lp,
client: client,
@@ -128,6 +128,10 @@ func (cr *chainReader) init(chainContractReaders map[string]types.ChainContractR
return err
}
}
+
+ if cr.bindings.contractBindings[contractName] == nil {
+ return fmt.Errorf("%w: no read bindings added for contract: %s", commontypes.ErrInvalidConfig, contractName)
+ }
cr.bindings.contractBindings[contractName].pollingFilter = chainContractReader.PollingFilter.ToLPFilter(eventSigsForContractFilter)
}
return nil
@@ -259,7 +263,7 @@ func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chain
return err
}
- // Encoder def's codec won't be used to encode, only for its type as input for GetLatestValue
+ // Encoder defs codec won't be used for encoding, but for storing caller filtering params which won't be hashed.
if err := cr.addEncoderDef(contractName, eventName, filterArgs, nil, chainReaderDefinition.InputModifications); err != nil {
return err
}
@@ -327,9 +331,11 @@ func (cr *chainReader) addQueryingReadBindings(contractName string, genericTopic
}
}
+// getEventInput returns codec entry for expected incoming event params and the modifier to be applied to the params.
func (cr *chainReader) getEventInput(def types.ChainReaderDefinition, contractName, eventName string) (
types.CodecEntry, codec.Modifier, error) {
inputInfo := cr.parsed.EncoderDefs[WrapItemType(contractName, eventName, true)]
+ // TODO can this be simplified? Isn't this same as inputInfo.Modifier()? BCI-3909
inMod, err := def.InputModifications.ToModifier(DecoderHooks...)
if err != nil {
return nil, nil, err
@@ -378,6 +384,8 @@ func (cr *chainReader) addDecoderDef(contractName, itemType string, outputs abi.
return output.Init()
}
+// setupEventInput returns abi args where indexed flag is set to false because we expect caller to filter with params that aren't hashed.
+// codecEntry has expected onchain types set, for e.g. indexed topics of type string or uint8[32] array are expected as common.Hash onchain.
func setupEventInput(event abi.Event, inputFields []string) ([]abi.Argument, types.CodecEntry, map[string]bool) {
topicFieldDefs := map[string]bool{}
for _, value := range inputFields {
diff --git a/core/services/relay/evm/chain_writer.go b/core/services/relay/evm/chain_writer.go
index f188ffeced2..c4567263791 100644
--- a/core/services/relay/evm/chain_writer.go
+++ b/core/services/relay/evm/chain_writer.go
@@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
commonservices "github.com/smartcontractkit/chainlink-common/pkg/services"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
@@ -18,7 +19,6 @@ import (
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
evmtxmgr "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
@@ -186,7 +186,7 @@ func (w *chainWriter) GetFeeComponents(ctx context.Context) (*commontypes.ChainF
return nil, fmt.Errorf("gas estimator not available")
}
- fee, _, err := w.ge.GetFee(ctx, nil, 0, w.maxGasPrice)
+ fee, _, err := w.ge.GetFee(ctx, nil, 0, w.maxGasPrice, nil)
if err != nil {
return nil, err
}
diff --git a/core/services/relay/evm/chain_writer_test.go b/core/services/relay/evm/chain_writer_test.go
index 66c85bfc2c3..f35e9eece5a 100644
--- a/core/services/relay/evm/chain_writer_test.go
+++ b/core/services/relay/evm/chain_writer_test.go
@@ -67,6 +67,7 @@ func TestChainWriter(t *testing.T) {
status commontypes.TransactionStatus
}{
{uuid.NewString(), commontypes.Unknown},
+ {uuid.NewString(), commontypes.Pending},
{uuid.NewString(), commontypes.Unconfirmed},
{uuid.NewString(), commontypes.Finalized},
{uuid.NewString(), commontypes.Failed},
@@ -86,7 +87,7 @@ func TestChainWriter(t *testing.T) {
})
t.Run("GetFeeComponents", func(t *testing.T) {
- ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
Legacy: assets.NewWei(big.NewInt(1000000001)),
DynamicFeeCap: assets.NewWei(big.NewInt(1000000002)),
DynamicTipCap: assets.NewWei(big.NewInt(1000000003)),
@@ -112,7 +113,7 @@ func TestChainWriter(t *testing.T) {
})
t.Run("Returns Legacy Fee in absence of Dynamic Fee", func(t *testing.T) {
- ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
Legacy: assets.NewWei(big.NewInt(1000000001)),
DynamicFeeCap: nil,
DynamicTipCap: assets.NewWei(big.NewInt(1000000003)),
@@ -124,7 +125,7 @@ func TestChainWriter(t *testing.T) {
})
t.Run("Fails when neither legacy or dynamic fee is available", func(t *testing.T) {
- ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
Legacy: nil,
DynamicFeeCap: nil,
DynamicTipCap: nil,
@@ -136,7 +137,7 @@ func TestChainWriter(t *testing.T) {
t.Run("Fails when GetFee returns an error", func(t *testing.T) {
expectedErr := fmt.Errorf("GetFee error")
- ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
Legacy: nil,
DynamicFeeCap: nil,
DynamicTipCap: nil,
@@ -146,7 +147,7 @@ func TestChainWriter(t *testing.T) {
})
t.Run("Fails when L1Oracle returns error", func(t *testing.T) {
- ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
+ ge.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{
Legacy: assets.NewWei(big.NewInt(1000000001)),
DynamicFeeCap: assets.NewWei(big.NewInt(1000000002)),
DynamicTipCap: assets.NewWei(big.NewInt(1000000003)),
diff --git a/core/services/relay/evm/commit_provider.go b/core/services/relay/evm/commit_provider.go
new file mode 100644
index 00000000000..f41df16a4fc
--- /dev/null
+++ b/core/services/relay/evm/commit_provider.go
@@ -0,0 +1,309 @@
+package evm
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+
+ "go.uber.org/multierr"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+)
+
+var _ commontypes.CCIPCommitProvider = (*SrcCommitProvider)(nil)
+var _ commontypes.CCIPCommitProvider = (*DstCommitProvider)(nil)
+
+type SrcCommitProvider struct {
+ lggr logger.Logger
+ startBlock uint64
+ client client.Client
+ lp logpoller.LogPoller
+ estimator gas.EvmFeeEstimator
+ maxGasPrice *big.Int
+
+ // these values will be lazily initialized
+ seenOnRampAddress *cciptypes.Address
+ seenSourceChainSelector *uint64
+ seenDestChainSelector *uint64
+}
+
+func NewSrcCommitProvider(
+ lggr logger.Logger,
+ startBlock uint64,
+ client client.Client,
+ lp logpoller.LogPoller,
+ srcEstimator gas.EvmFeeEstimator,
+ maxGasPrice *big.Int,
+) commontypes.CCIPCommitProvider {
+ return &SrcCommitProvider{
+ lggr: lggr,
+ startBlock: startBlock,
+ client: client,
+ lp: lp,
+ estimator: srcEstimator,
+ maxGasPrice: maxGasPrice,
+ }
+}
+
+type DstCommitProvider struct {
+ lggr logger.Logger
+ versionFinder ccip.VersionFinder
+ startBlock uint64
+ client client.Client
+ lp logpoller.LogPoller
+ contractTransmitter *contractTransmitter
+ configWatcher *configWatcher
+ gasEstimator gas.EvmFeeEstimator
+ maxGasPrice big.Int
+
+ // these values will be lazily initialized
+ seenCommitStoreAddress *cciptypes.Address
+ seenOffRampAddress *cciptypes.Address
+}
+
+func NewDstCommitProvider(
+ lggr logger.Logger,
+ versionFinder ccip.VersionFinder,
+ startBlock uint64,
+ client client.Client,
+ lp logpoller.LogPoller,
+ gasEstimator gas.EvmFeeEstimator,
+ maxGasPrice big.Int,
+ contractTransmitter contractTransmitter,
+ configWatcher *configWatcher,
+) commontypes.CCIPCommitProvider {
+ return &DstCommitProvider{
+ lggr: lggr,
+ versionFinder: versionFinder,
+ startBlock: startBlock,
+ client: client,
+ lp: lp,
+ contractTransmitter: &contractTransmitter,
+ configWatcher: configWatcher,
+ gasEstimator: gasEstimator,
+ maxGasPrice: maxGasPrice,
+ }
+}
+
+func (P *SrcCommitProvider) Name() string {
+ return "CCIPCommitProvider.SrcRelayerProvider"
+}
+
+// Close is called when the job that created this provider is deleted.
+// At this time, any of the methods on the provider may or may not have been called.
+// If NewOnRampReader has not been called, their corresponding
+// Close methods will be expected to error.
+func (P *SrcCommitProvider) Close() error {
+ versionFinder := ccip.NewEvmVersionFinder()
+
+ unregisterFuncs := make([]func() error, 0, 2)
+ unregisterFuncs = append(unregisterFuncs, func() error {
+ // avoid panic in the case NewOnRampReader wasn't called
+ if P.seenOnRampAddress == nil {
+ return nil
+ }
+ return ccip.CloseOnRampReader(P.lggr, versionFinder, *P.seenSourceChainSelector, *P.seenDestChainSelector, *P.seenOnRampAddress, P.lp, P.client)
+ })
+
+ var multiErr error
+ for _, fn := range unregisterFuncs {
+ if err := fn(); err != nil {
+ multiErr = multierr.Append(multiErr, err)
+ }
+ }
+ return multiErr
+}
+
+func (P *SrcCommitProvider) Ready() error {
+ return nil
+}
+
+func (P *SrcCommitProvider) HealthReport() map[string]error {
+ return make(map[string]error)
+}
+
+func (P *SrcCommitProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester {
+ // TODO CCIP-2494
+ // "OffchainConfigDigester called on SrcCommitProvider. Valid on DstCommitProvider."
+ return UnimplementedOffchainConfigDigester{}
+}
+
+func (P *SrcCommitProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker {
+ // // TODO CCIP-2494
+ // "ContractConfigTracker called on SrcCommitProvider. Valid on DstCommitProvider.")
+ return UnimplementedContractConfigTracker{}
+}
+
+func (P *SrcCommitProvider) ContractTransmitter() ocrtypes.ContractTransmitter {
+ // // TODO CCIP-2494
+ // "ContractTransmitter called on SrcCommitProvider. Valid on DstCommitProvider."
+ return UnimplementedContractTransmitter{}
+}
+
+func (P *SrcCommitProvider) ChainReader() commontypes.ContractReader {
+ return nil
+}
+
+func (P *SrcCommitProvider) Codec() commontypes.Codec {
+ return nil
+}
+
+func (P *DstCommitProvider) Name() string {
+ return "CCIPCommitProvider.DstRelayerProvider"
+}
+
+func (P *DstCommitProvider) Close() error {
+ versionFinder := ccip.NewEvmVersionFinder()
+
+ unregisterFuncs := make([]func() error, 0, 2)
+ unregisterFuncs = append(unregisterFuncs, func() error {
+ if P.seenCommitStoreAddress == nil {
+ return nil
+ }
+ return ccip.CloseCommitStoreReader(P.lggr, versionFinder, *P.seenCommitStoreAddress, P.client, P.lp)
+ })
+ unregisterFuncs = append(unregisterFuncs, func() error {
+ if P.seenOffRampAddress == nil {
+ return nil
+ }
+ return ccip.CloseOffRampReader(P.lggr, versionFinder, *P.seenOffRampAddress, P.client, P.lp, nil, big.NewInt(0))
+ })
+
+ var multiErr error
+ for _, fn := range unregisterFuncs {
+ if err := fn(); err != nil {
+ multiErr = multierr.Append(multiErr, err)
+ }
+ }
+ return multiErr
+}
+
+func (P *DstCommitProvider) Ready() error {
+ return nil
+}
+
+func (P *DstCommitProvider) HealthReport() map[string]error {
+ return make(map[string]error)
+}
+
+func (P *DstCommitProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester {
+ return P.configWatcher.OffchainConfigDigester()
+}
+
+func (P *DstCommitProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker {
+ return P.configWatcher.ContractConfigTracker()
+}
+
+func (P *DstCommitProvider) ContractTransmitter() ocrtypes.ContractTransmitter {
+ return P.contractTransmitter
+}
+
+func (P *DstCommitProvider) ChainReader() commontypes.ContractReader {
+ return nil
+}
+
+func (P *DstCommitProvider) Codec() commontypes.Codec {
+ return nil
+}
+
+func (P *SrcCommitProvider) Start(ctx context.Context) error {
+ if P.startBlock != 0 {
+ P.lggr.Infow("start replaying src chain", "fromBlock", P.startBlock)
+ return P.lp.Replay(ctx, int64(P.startBlock))
+ }
+ return nil
+}
+
+func (P *DstCommitProvider) Start(ctx context.Context) error {
+ if P.startBlock != 0 {
+ P.lggr.Infow("start replaying dst chain", "fromBlock", P.startBlock)
+ return P.lp.Replay(ctx, int64(P.startBlock))
+ }
+ return nil
+}
+
+func (P *SrcCommitProvider) NewPriceGetter(ctx context.Context) (priceGetter cciptypes.PriceGetter, err error) {
+ return nil, fmt.Errorf("can't construct a price getter from one relayer")
+}
+
+func (P *DstCommitProvider) NewPriceGetter(ctx context.Context) (priceGetter cciptypes.PriceGetter, err error) {
+ return nil, fmt.Errorf("can't construct a price getter from one relayer")
+}
+
+func (P *SrcCommitProvider) NewCommitStoreReader(ctx context.Context, commitStoreAddress cciptypes.Address) (commitStoreReader cciptypes.CommitStoreReader, err error) {
+ commitStoreReader = NewIncompleteSourceCommitStoreReader(P.estimator, P.maxGasPrice)
+ return
+}
+
+func (P *DstCommitProvider) NewCommitStoreReader(ctx context.Context, commitStoreAddress cciptypes.Address) (commitStoreReader cciptypes.CommitStoreReader, err error) {
+ P.seenCommitStoreAddress = &commitStoreAddress
+
+ versionFinder := ccip.NewEvmVersionFinder()
+ commitStoreReader, err = NewIncompleteDestCommitStoreReader(P.lggr, versionFinder, commitStoreAddress, P.client, P.lp)
+ return
+}
+
+func (P *SrcCommitProvider) NewOnRampReader(ctx context.Context, onRampAddress cciptypes.Address, sourceChainSelector uint64, destChainSelector uint64) (onRampReader cciptypes.OnRampReader, err error) {
+ P.seenOnRampAddress = &onRampAddress
+ P.seenSourceChainSelector = &sourceChainSelector
+ P.seenDestChainSelector = &destChainSelector
+
+ versionFinder := ccip.NewEvmVersionFinder()
+ onRampReader, err = ccip.NewOnRampReader(P.lggr, versionFinder, sourceChainSelector, destChainSelector, onRampAddress, P.lp, P.client)
+ return
+}
+
+func (P *DstCommitProvider) NewOnRampReader(ctx context.Context, onRampAddress cciptypes.Address, sourceChainSelector uint64, destChainSelector uint64) (onRampReader cciptypes.OnRampReader, err error) {
+ return nil, fmt.Errorf("invalid: NewOnRampReader called for DstCommitProvider.NewOnRampReader should be called on SrcCommitProvider")
+}
+
+func (P *SrcCommitProvider) NewOffRampReader(ctx context.Context, offRampAddr cciptypes.Address) (offRampReader cciptypes.OffRampReader, err error) {
+ return nil, fmt.Errorf("invalid: NewOffRampReader called for SrcCommitProvider. NewOffRampReader should be called on DstCommitProvider")
+}
+
+func (P *DstCommitProvider) NewOffRampReader(ctx context.Context, offRampAddr cciptypes.Address) (offRampReader cciptypes.OffRampReader, err error) {
+ offRampReader, err = ccip.NewOffRampReader(P.lggr, P.versionFinder, offRampAddr, P.client, P.lp, P.gasEstimator, &P.maxGasPrice, true)
+ return
+}
+
+func (P *SrcCommitProvider) NewPriceRegistryReader(ctx context.Context, addr cciptypes.Address) (priceRegistryReader cciptypes.PriceRegistryReader, err error) {
+ return nil, fmt.Errorf("invalid: NewPriceRegistryReader called for SrcCommitProvider. NewOffRampReader should be called on DstCommitProvider")
+}
+
+func (P *DstCommitProvider) NewPriceRegistryReader(ctx context.Context, addr cciptypes.Address) (priceRegistryReader cciptypes.PriceRegistryReader, err error) {
+ destPriceRegistry := ccip.NewEvmPriceRegistry(P.lp, P.client, P.lggr, ccip.CommitPluginLabel)
+ priceRegistryReader, err = destPriceRegistry.NewPriceRegistryReader(ctx, addr)
+ return
+}
+
+func (P *SrcCommitProvider) SourceNativeToken(ctx context.Context, sourceRouterAddr cciptypes.Address) (cciptypes.Address, error) {
+ sourceRouterAddrHex, err := ccip.GenericAddrToEvm(sourceRouterAddr)
+ if err != nil {
+ return "", err
+ }
+ sourceRouter, err := router.NewRouter(sourceRouterAddrHex, P.client)
+ if err != nil {
+ return "", err
+ }
+ sourceNative, err := sourceRouter.GetWrappedNative(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return "", err
+ }
+
+ return ccip.EvmAddrToGeneric(sourceNative), nil
+}
+
+func (P *DstCommitProvider) SourceNativeToken(ctx context.Context, sourceRouterAddr cciptypes.Address) (cciptypes.Address, error) {
+ return "", fmt.Errorf("invalid: SourceNativeToken called for DstCommitProvider. SourceNativeToken should be called on SrcCommitProvider")
+}
diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go
index 2280d60d7ee..a00b04b0786 100644
--- a/core/services/relay/evm/config_poller.go
+++ b/core/services/relay/evm/config_poller.go
@@ -15,11 +15,11 @@ import (
"github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
diff --git a/core/services/relay/evm/contract_transmitter.go b/core/services/relay/evm/contract_transmitter.go
index d594dfb9214..e2065bc60f7 100644
--- a/core/services/relay/evm/contract_transmitter.go
+++ b/core/services/relay/evm/contract_transmitter.go
@@ -12,13 +12,15 @@ import (
"github.com/ethereum/go-ethereum/common"
gethcommon "github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
+
"github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"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"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services"
)
@@ -102,7 +104,7 @@ func NewOCRContractTransmitter(
transmittedEventSig: transmitted.ID,
lp: lp,
contractReader: caller,
- lggr: lggr.Named("OCRContractTransmitter"),
+ lggr: logger.Named(lggr, "OCRContractTransmitter"),
reportToEvmTxMeta: reportToEvmTxMetaNoop,
excludeSigs: false,
retention: 0,
diff --git a/core/services/relay/evm/event_binding.go b/core/services/relay/evm/event_binding.go
index acfb1aa6300..7b62d862b35 100644
--- a/core/services/relay/evm/event_binding.go
+++ b/core/services/relay/evm/event_binding.go
@@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
"github.com/google/uuid"
"github.com/smartcontractkit/chainlink-common/pkg/codec"
@@ -168,7 +169,7 @@ func (e *eventBinding) QueryKey(ctx context.Context, filter query.KeyFilter, lim
}
remapped.Expressions = append(defaultExpressions, remapped.Expressions...)
- logs, err := e.lp.FilteredLogs(ctx, remapped, limitAndSort, e.contractName+"-"+e.eventName)
+ logs, err := e.lp.FilteredLogs(ctx, remapped, limitAndSort, e.contractName+"-"+e.address.String()+"-"+e.eventName)
if err != nil {
return nil, err
}
@@ -209,11 +210,13 @@ func (e *eventBinding) getLatestValueWithFilters(
return err
}
+ // convert caller chain agnostic params types to types representing onchain abi types, for e.g. bytes32.
checkedParams, err := e.inputModifier.TransformToOnChain(offChain, "" /* unused */)
if err != nil {
return err
}
+ // convert onchain params to native types similarly to generated abi wrappers, for e.g. fixed bytes32 abi type to [32]uint8.
nativeParams, err := e.inputInfo.ToNative(reflect.ValueOf(checkedParams))
if err != nil {
return err
@@ -224,34 +227,45 @@ func (e *eventBinding) getLatestValueWithFilters(
return err
}
- fai := filtersAndIndices[0]
- remainingFilters := filtersAndIndices[1:]
-
- logs, err := e.lp.IndexedLogs(ctx, e.hash, e.address, 1, []common.Hash{fai}, confs)
+ // Create limiter and filter for the query.
+ limiter := query.NewLimitAndSort(query.CountLimit(1), query.NewSortBySequence(query.Desc))
+ filter, err := query.Where(
+ "",
+ logpoller.NewAddressFilter(e.address),
+ logpoller.NewEventSigFilter(e.hash),
+ logpoller.NewConfirmationsFilter(confs),
+ createTopicFilters(filtersAndIndices),
+ )
if err != nil {
return wrapInternalErr(err)
}
- // TODO Use filtered logs here BCF-3316
- // TODO: there should be a better way to ask log poller to filter these
- // First, you should be able to ask for as many topics to match
- // Second, you should be able to get the latest only
- var logToUse *logpoller.Log
- for _, log := range logs {
- tmp := log
- if compareLogs(&tmp, logToUse) > 0 && matchesRemainingFilters(&tmp, remainingFilters) {
- // copy so that it's not pointing to the changing variable
- logToUse = &tmp
- }
+ // Gets the latest log that matches the filter and limiter.
+ logs, err := e.lp.FilteredLogs(ctx, filter, limiter, e.contractName+"-"+e.address.String()+"-"+e.eventName)
+ if err != nil {
+ return wrapInternalErr(err)
}
- if logToUse == nil {
+ if len(logs) == 0 {
return fmt.Errorf("%w: no events found", commontypes.ErrNotFound)
}
- return e.decodeLog(ctx, logToUse, into)
+ return e.decodeLog(ctx, &logs[0], into)
+}
+
+func createTopicFilters(filtersAndIndices []common.Hash) query.Expression {
+ var expressions []query.Expression
+ for topicID, fai := range filtersAndIndices {
+ // first topic index is 1-based, so we add 1.
+ expressions = append(expressions, logpoller.NewEventByTopicFilter(
+ uint64(topicID+1), []primitives.ValueComparator{{Value: fai.Hex(), Operator: primitives.Eq}},
+ ))
+ }
+ return query.And(expressions...)
}
+// convertToOffChainType creates a struct based on contract abi with applied codec modifiers.
+// Created type shouldn't have hashed types for indexed topics since incoming params wouldn't be hashed.
func (e *eventBinding) convertToOffChainType(params any) (any, error) {
offChain, err := e.codec.CreateType(WrapItemType(e.contractName, e.eventName, true), true)
if err != nil {
@@ -265,65 +279,35 @@ func (e *eventBinding) convertToOffChainType(params any) (any, error) {
return offChain, nil
}
-func compareLogs(log, use *logpoller.Log) int64 {
- if use == nil {
- return 1
- }
-
- if log.BlockNumber != use.BlockNumber {
- return log.BlockNumber - use.BlockNumber
+// encodeParams accepts nativeParams and encodes them to match onchain topics.
+func (e *eventBinding) encodeParams(nativeParams reflect.Value) ([]common.Hash, error) {
+ for nativeParams.Kind() == reflect.Pointer {
+ nativeParams = reflect.Indirect(nativeParams)
}
- return log.LogIndex - use.LogIndex
-}
-
-func matchesRemainingFilters(log *logpoller.Log, filters []common.Hash) bool {
- for i, rfai := range filters {
- if !reflect.DeepEqual(rfai[:], log.Topics[i+2]) {
- return false
- }
- }
-
- return true
-}
-
-func (e *eventBinding) encodeParams(item reflect.Value) ([]common.Hash, error) {
- for item.Kind() == reflect.Pointer {
- item = reflect.Indirect(item)
- }
-
- var topics []any
- switch item.Kind() {
+ var params []any
+ switch nativeParams.Kind() {
case reflect.Array, reflect.Slice:
- native, err := representArray(item, e.inputInfo)
+ native, err := representArray(nativeParams, e.inputInfo)
if err != nil {
return nil, err
}
- topics = []any{native}
+ params = []any{native}
case reflect.Struct, reflect.Map:
var err error
- if topics, err = unrollItem(item, e.inputInfo); err != nil {
+ if params, err = unrollItem(nativeParams, e.inputInfo); err != nil {
return nil, err
}
default:
- return nil, fmt.Errorf("%w: cannot encode kind %v", commontypes.ErrInvalidType, item.Kind())
+ return nil, fmt.Errorf("%w: cannot encode kind %v", commontypes.ErrInvalidType, nativeParams.Kind())
}
- // abi params allow you to Pack a pointers, but MakeTopics doesn't work with pointers.
- if err := e.derefTopics(topics); err != nil {
+ // abi params allow you to Pack a pointers, but makeTopics doesn't work with pointers.
+ if err := e.derefTopics(params); err != nil {
return nil, err
}
- hashes, err := abi.MakeTopics(topics)
- if err != nil {
- return nil, wrapInternalErr(err)
- }
-
- if len(hashes) != 1 {
- return nil, fmt.Errorf("%w: expected 1 filter set, got %d", commontypes.ErrInternal, len(hashes))
- }
-
- return hashes[0], nil
+ return e.makeTopics(params)
}
func (e *eventBinding) derefTopics(topics []any) error {
@@ -340,11 +324,38 @@ func (e *eventBinding) derefTopics(topics []any) error {
return nil
}
+// makeTopics encodes and hashes params filtering values to match onchain indexed topics.
+func (e *eventBinding) makeTopics(params []any) ([]common.Hash, error) {
+ // make topic value for non-fixed bytes array manually because geth MakeTopics doesn't support it
+ for i, topic := range params {
+ if abiArg := e.inputInfo.Args()[i]; abiArg.Type.T == abi.ArrayTy && (abiArg.Type.Elem != nil && abiArg.Type.Elem.T == abi.UintTy) {
+ packed, err := abi.Arguments{abiArg}.Pack(topic)
+ if err != nil {
+ return nil, err
+ }
+ params[i] = crypto.Keccak256Hash(packed)
+ }
+ }
+
+ hashes, err := abi.MakeTopics(params)
+ if err != nil {
+ return nil, wrapInternalErr(err)
+ }
+
+ if len(hashes) != 1 {
+ return nil, fmt.Errorf("%w: expected 1 filter set, got %d", commontypes.ErrInternal, len(hashes))
+ }
+
+ return hashes[0], nil
+}
+
func (e *eventBinding) decodeLog(ctx context.Context, log *logpoller.Log, into any) error {
+ // decode non indexed topics and apply output modifiers
if err := e.codec.Decode(ctx, log.Data, into, WrapItemType(e.contractName, e.eventName, false)); err != nil {
return err
}
+ // decode indexed topics which is rarely useful since most indexed topic types get Keccak256 hashed and should be just used for log filtering.
topics := make([]common.Hash, len(e.codecTopicInfo.Args()))
if len(log.Topics) < len(topics)+1 {
return fmt.Errorf("%w: not enough topics to decode", commontypes.ErrInvalidType)
@@ -436,6 +447,7 @@ func (e *eventBinding) remapExpression(key string, expression query.Expression)
// remap chain agnostic primitives to chain specific
func (e *eventBinding) remapPrimitive(key string, expression query.Expression) (query.Expression, error) {
switch primitive := expression.Primitive.(type) {
+ // TODO comparator primitive should undergo codec transformations and do hashed types handling similarly to how GetLatestValue handles it BCI-3910
case *primitives.Comparator:
if val, ok := e.eventDataWords[primitive.Name]; ok {
return logpoller.NewEventByWordFilter(e.hash, val, primitive.ValueComparators), nil
diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go
index 3b3393441a2..9596ab29d05 100644
--- a/core/services/relay/evm/evm.go
+++ b/core/services/relay/evm/evm.go
@@ -1,12 +1,14 @@
package evm
import (
+ "bytes"
"context"
+ "crypto/sha256"
"encoding/json"
"errors"
"fmt"
+ "math/big"
"strings"
- "sync"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
@@ -21,19 +23,25 @@ import (
ocr3capability "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core"
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/llo"
"github.com/smartcontractkit/chainlink/v2/core/services/llo/bm"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/ccipcommit"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/ccipexec"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ cciptransmitter "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/transmitter"
lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config"
mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config"
"github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
@@ -43,6 +51,7 @@ import (
reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec"
reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec"
reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec"
+ reportcodecv4 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v4/reportcodec"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
@@ -71,10 +80,61 @@ func init() {
var _ commontypes.Relayer = &Relayer{} //nolint:staticcheck
+// The current PluginProvider interface does not support an error return. This was fine up until CCIP.
+// CCIP is the first product to introduce the idea of incomplete implementations of a provider based on
+// what chain (for CCIP, src or dest) the provider is created for. The Unimplemented* implementations below allow us to return
+// a non nil value, which is hopefully a better developer experience should you find yourself using the right methods
+// but on the *wrong* provider.
+
+// [UnimplementedOffchainConfigDigester] satisfies the OCR OffchainConfigDigester interface
+type UnimplementedOffchainConfigDigester struct{}
+
+func (e UnimplementedOffchainConfigDigester) ConfigDigest(config ocrtypes.ContractConfig) (ocrtypes.ConfigDigest, error) {
+ return ocrtypes.ConfigDigest{}, fmt.Errorf("unimplemented for this relayer")
+}
+
+func (e UnimplementedOffchainConfigDigester) ConfigDigestPrefix() (ocrtypes.ConfigDigestPrefix, error) {
+ return 0, fmt.Errorf("unimplemented for this relayer")
+}
+
+// [UnimplementedContractConfigTracker] satisfies the OCR ContractConfigTracker interface
+type UnimplementedContractConfigTracker struct{}
+
+func (u UnimplementedContractConfigTracker) Notify() <-chan struct{} {
+ return nil
+}
+
+func (u UnimplementedContractConfigTracker) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest ocrtypes.ConfigDigest, err error) {
+ return 0, ocrtypes.ConfigDigest{}, fmt.Errorf("unimplemented for this relayer")
+}
+
+func (u UnimplementedContractConfigTracker) LatestConfig(ctx context.Context, changedInBlock uint64) (ocrtypes.ContractConfig, error) {
+ return ocrtypes.ContractConfig{}, fmt.Errorf("unimplemented for this relayer")
+}
+
+func (u UnimplementedContractConfigTracker) LatestBlockHeight(ctx context.Context) (blockHeight uint64, err error) {
+ return 0, fmt.Errorf("unimplemented for this relayer")
+}
+
+// [UnimplementedContractTransmitter] satisfies the OCR ContractTransmitter interface
+type UnimplementedContractTransmitter struct{}
+
+func (u UnimplementedContractTransmitter) Transmit(context.Context, ocrtypes.ReportContext, ocrtypes.Report, []ocrtypes.AttributedOnchainSignature) error {
+ return fmt.Errorf("unimplemented for this relayer")
+}
+
+func (u UnimplementedContractTransmitter) FromAccount() (ocrtypes.Account, error) {
+ return "", fmt.Errorf("unimplemented for this relayer")
+}
+
+func (u UnimplementedContractTransmitter) LatestConfigDigestAndEpoch(ctx context.Context) (configDigest ocrtypes.ConfigDigest, epoch uint32, err error) {
+ return ocrtypes.ConfigDigest{}, 0, fmt.Errorf("unimplemented for this relayer")
+}
+
type Relayer struct {
ds sqlutil.DataSource
chain legacyevm.Chain
- lggr logger.Logger
+ lggr logger.SugaredLogger
ks CSAETHKeystore
mercuryPool wsrpc.Pool
chainReader commontypes.ContractReader
@@ -126,15 +186,15 @@ func NewRelayer(lggr logger.Logger, chain legacyevm.Chain, opts RelayerOpts) (*R
if err != nil {
return nil, fmt.Errorf("cannot create evm relayer: %w", err)
}
- lggr = lggr.Named("Relayer")
+ sugared := logger.Sugared(lggr).Named("Relayer")
mercuryORM := mercury.NewORM(opts.DS)
lloORM := llo.NewORM(opts.DS, chain.ID())
- cdcFactory := llo.NewChannelDefinitionCacheFactory(lggr, lloORM, chain.LogPoller())
+ cdcFactory := llo.NewChannelDefinitionCacheFactory(sugared, lloORM, chain.LogPoller())
relayer := &Relayer{
ds: opts.DS,
chain: chain,
- lggr: lggr,
+ lggr: sugared,
ks: opts.CSAETHKeystore,
mercuryPool: opts.MercuryPool,
cdcFactory: cdcFactory,
@@ -208,7 +268,7 @@ func (r *Relayer) NewPluginProvider(rargs commontypes.RelayArgs, pargs commontyp
// TODO https://smartcontract-it.atlassian.net/browse/BCF-2887
ctx := context.Background()
- lggr := r.lggr.Named("PluginProvider").Named(rargs.ExternalJobID.String())
+ lggr := logger.Sugared(r.lggr).Named("PluginProvider").Named(rargs.ExternalJobID.String())
configWatcher, err := newStandardConfigProvider(ctx, r.lggr, r.chain, types.NewRelayOpts(rargs))
if err != nil {
@@ -232,7 +292,7 @@ func (r *Relayer) NewPluginProvider(rargs commontypes.RelayArgs, pargs commontyp
func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.MercuryProvider, error) {
// TODO https://smartcontract-it.atlassian.net/browse/BCF-2887
ctx := context.Background()
- lggr := r.lggr.Named("MercuryProvider").Named(rargs.ExternalJobID.String())
+ lggr := logger.Sugared(r.lggr).Named("MercuryProvider").Named(rargs.ExternalJobID.String())
relayOpts := types.NewRelayOpts(rargs)
relayConfig, err := relayOpts.RelayConfig()
if err != nil {
@@ -296,6 +356,7 @@ func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commonty
reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV1"))
reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV2"))
reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV3"))
+ reportCodecV4 := reportcodecv4.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV4"))
var transmitterCodec mercury.TransmitterReportDecoder
switch feedID.Version() {
@@ -305,12 +366,14 @@ func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commonty
transmitterCodec = reportCodecV2
case 3:
transmitterCodec = reportCodecV3
+ case 4:
+ transmitterCodec = reportCodecV4
default:
return nil, fmt.Errorf("invalid feed version %d", feedID.Version())
}
transmitter := mercury.NewTransmitter(lggr, r.transmitterCfg, clients, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.mercuryORM, transmitterCodec, r.triggerCapability)
- return NewMercuryProvider(cp, r.chainReader, r.codec, NewMercuryChainReader(r.chain.HeadTracker()), transmitter, reportCodecV1, reportCodecV2, reportCodecV3, lggr), nil
+ return NewMercuryProvider(cp, r.chainReader, r.codec, NewMercuryChainReader(r.chain.HeadTracker()), transmitter, reportCodecV1, reportCodecV2, reportCodecV3, reportCodecV4, lggr), nil
}
func (r *Relayer) NewLLOProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.LLOProvider, error) {
@@ -445,16 +508,15 @@ func FilterNamesFromRelayArgs(args commontypes.RelayArgs) (filterNames []string,
}
type configWatcher struct {
- services.StateMachine
- lggr logger.Logger
+ services.Service
+ eng *services.Engine
+
contractAddress common.Address
offchainDigester ocrtypes.OffchainConfigDigester
configPoller types.ConfigPoller
chain legacyevm.Chain
runReplay bool
fromBlock uint64
- stopCh services.StopChan
- wg sync.WaitGroup
}
func newConfigWatcher(lggr logger.Logger,
@@ -465,54 +527,41 @@ func newConfigWatcher(lggr logger.Logger,
fromBlock uint64,
runReplay bool,
) *configWatcher {
- return &configWatcher{
- lggr: lggr.Named("ConfigWatcher").Named(contractAddress.String()),
+ cw := &configWatcher{
contractAddress: contractAddress,
offchainDigester: offchainDigester,
configPoller: configPoller,
chain: chain,
runReplay: runReplay,
fromBlock: fromBlock,
- stopCh: make(chan struct{}),
- }
-}
-
-func (c *configWatcher) Name() string {
- return c.lggr.Name()
-}
-
-func (c *configWatcher) Start(ctx context.Context) error {
- return c.StartOnce(fmt.Sprintf("configWatcher %x", c.contractAddress), func() error {
- if c.runReplay && c.fromBlock != 0 {
- // Only replay if it's a brand runReplay job.
- c.wg.Add(1)
- go func() {
- defer c.wg.Done()
- ctx, cancel := c.stopCh.NewCtx()
- defer cancel()
- c.lggr.Infow("starting replay for config", "fromBlock", c.fromBlock)
- if err := c.configPoller.Replay(ctx, int64(c.fromBlock)); err != nil {
- c.lggr.Errorw("error replaying for config", "err", err)
- } else {
- c.lggr.Infow("completed replaying for config", "fromBlock", c.fromBlock)
- }
- }()
- }
- c.configPoller.Start()
- return nil
- })
-}
-
-func (c *configWatcher) Close() error {
- return c.StopOnce(fmt.Sprintf("configWatcher %x", c.contractAddress), func() error {
- close(c.stopCh)
- c.wg.Wait()
- return c.configPoller.Close()
- })
+ }
+ cw.Service, cw.eng = services.Config{
+ Name: fmt.Sprintf("ConfigWatcher.%s", contractAddress),
+ NewSubServices: nil,
+ Start: cw.start,
+ Close: cw.close,
+ }.NewServiceEngine(lggr)
+ return cw
+}
+
+func (c *configWatcher) start(ctx context.Context) error {
+ if c.runReplay && c.fromBlock != 0 {
+ // Only replay if it's a brand runReplay job.
+ c.eng.Go(func(ctx context.Context) {
+ c.eng.Infow("starting replay for config", "fromBlock", c.fromBlock)
+ if err := c.configPoller.Replay(ctx, int64(c.fromBlock)); err != nil {
+ c.eng.Errorw("error replaying for config", "err", err)
+ } else {
+ c.eng.Infow("completed replaying for config", "fromBlock", c.fromBlock)
+ }
+ })
+ }
+ c.configPoller.Start()
+ return nil
}
-func (c *configWatcher) HealthReport() map[string]error {
- return map[string]error{c.Name(): c.Healthy()}
+func (c *configWatcher) close() error {
+ return c.configPoller.Close()
}
func (c *configWatcher) OffchainConfigDigester() ocrtypes.OffchainConfigDigester {
@@ -614,6 +663,17 @@ func generateTransmitterFrom(ctx context.Context, rargs commontypes.RelayArgs, e
configWatcher.chain.ID(),
ethKeystore,
)
+ case commontypes.CCIPExecution:
+ transmitter, err = cciptransmitter.NewTransmitterWithStatusChecker(
+ configWatcher.chain.TxManager(),
+ fromAddresses,
+ gasLimit,
+ effectiveTransmitterAddress,
+ strategy,
+ checker,
+ configWatcher.chain.ID(),
+ ethKeystore,
+ )
default:
transmitter, err = ocrcommon.NewTransmitter(
configWatcher.chain.TxManager(),
@@ -655,7 +715,7 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp
// TODO https://smartcontract-it.atlassian.net/browse/BCF-2887
ctx := context.Background()
- lggr := r.lggr.Named("MedianProvider").Named(rargs.ExternalJobID.String())
+ lggr := logger.Sugared(r.lggr).Named("MedianProvider").Named(rargs.ExternalJobID.String())
relayOpts := types.NewRelayOpts(rargs)
relayConfig, err := relayOpts.RelayConfig()
if err != nil {
@@ -724,18 +784,164 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp
}
func (r *Relayer) NewAutomationProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.AutomationProvider, error) {
- lggr := r.lggr.Named("AutomationProvider").Named(rargs.ExternalJobID.String())
+ lggr := logger.Sugared(r.lggr).Named("AutomationProvider").Named(rargs.ExternalJobID.String())
ocr2keeperRelayer := NewOCR2KeeperRelayer(r.ds, r.chain, lggr.Named("OCR2KeeperRelayer"), r.ks.Eth())
return ocr2keeperRelayer.NewOCR2KeeperProvider(rargs, pargs)
}
-func (r *Relayer) NewCCIPCommitProvider(_ commontypes.RelayArgs, _ commontypes.PluginArgs) (commontypes.CCIPCommitProvider, error) {
- return nil, errors.New("ccip.commit is not supported for evm")
+func chainToUUID(chainID *big.Int) uuid.UUID {
+ // See https://www.rfc-editor.org/rfc/rfc4122.html#section-4.1.3 for the list of supported versions.
+ const VersionSHA1 = 5
+ var buf bytes.Buffer
+ buf.WriteString("CCIP:")
+ buf.Write(chainID.Bytes())
+ // We use SHA-256 instead of SHA-1 because the former has better collision resistance.
+ // The UUID will contain only the first 16 bytes of the hash.
+ // You can't say which algorithms was used just by looking at the UUID bytes.
+ return uuid.NewHash(sha256.New(), uuid.NameSpaceOID, buf.Bytes(), VersionSHA1)
+}
+
+// NewCCIPCommitProvider constructs a provider of type CCIPCommitProvider. Since this is happening in the Relayer,
+// which lives in a separate process from delegate which is requesting a provider, we need to wire in through pargs
+// which *type* (impl) of CCIPCommitProvider should be created. CCIP is currently a special case where the provider has a
+// subset of implementations of the complete interface as certain contracts in a CCIP lane are only deployed on the src
+// chain or on the dst chain. This results in the two implementations of providers: a src and dst implementation.
+func (r *Relayer) NewCCIPCommitProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.CCIPCommitProvider, error) {
+ // TODO https://smartcontract-it.atlassian.net/browse/BCF-2887
+ ctx := context.Background()
+
+ versionFinder := ccip.NewEvmVersionFinder()
+
+ var commitPluginConfig ccipconfig.CommitPluginConfig
+ err := json.Unmarshal(pargs.PluginConfig, &commitPluginConfig)
+ if err != nil {
+ return nil, err
+ }
+ sourceStartBlock := commitPluginConfig.SourceStartBlock
+ destStartBlock := commitPluginConfig.DestStartBlock
+
+ // The src chain implementation of this provider does not need a configWatcher or contractTransmitter;
+ // bail early.
+ if commitPluginConfig.IsSourceProvider {
+ return NewSrcCommitProvider(
+ r.lggr,
+ sourceStartBlock,
+ r.chain.Client(),
+ r.chain.LogPoller(),
+ r.chain.GasEstimator(),
+ r.chain.Config().EVM().GasEstimator().PriceMax().ToInt(),
+ ), nil
+ }
+
+ relayOpts := types.NewRelayOpts(rargs)
+ configWatcher, err := newStandardConfigProvider(ctx, r.lggr, r.chain, relayOpts)
+ if err != nil {
+ return nil, err
+ }
+ address := common.HexToAddress(relayOpts.ContractID)
+ typ, ver, err := ccipconfig.TypeAndVersion(address, r.chain.Client())
+ if err != nil {
+ return nil, err
+ }
+ fn, err := ccipcommit.CommitReportToEthTxMeta(typ, ver)
+ if err != nil {
+ return nil, err
+ }
+ subjectID := chainToUUID(configWatcher.chain.ID())
+ contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.ks.Eth(), configWatcher, configTransmitterOpts{
+ subjectID: &subjectID,
+ }, OCR2AggregatorTransmissionContractABI, WithReportToEthMetadata(fn), WithRetention(0))
+ if err != nil {
+ return nil, err
+ }
+
+ return NewDstCommitProvider(
+ r.lggr,
+ versionFinder,
+ destStartBlock,
+ r.chain.Client(),
+ r.chain.LogPoller(),
+ r.chain.GasEstimator(),
+ *r.chain.Config().EVM().GasEstimator().PriceMax().ToInt(),
+ *contractTransmitter,
+ configWatcher,
+ ), nil
}
-func (r *Relayer) NewCCIPExecProvider(_ commontypes.RelayArgs, _ commontypes.PluginArgs) (commontypes.CCIPExecProvider, error) {
- return nil, errors.New("ccip.exec is not supported for evm")
+// NewCCIPExecProvider constructs a provider of type CCIPExecProvider. Since this is happening in the Relayer,
+// which lives in a separate process from delegate which is requesting a provider, we need to wire in through pargs
+// which *type* (impl) of CCIPExecProvider should be created. CCIP is currently a special case where the provider has a
+// subset of implementations of the complete interface as certain contracts in a CCIP lane are only deployed on the src
+// chain or on the dst chain. This results in the two implementations of providers: a src and dst implementation.
+func (r *Relayer) NewCCIPExecProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.CCIPExecProvider, error) {
+ // TODO https://smartcontract-it.atlassian.net/browse/BCF-2887
+ ctx := context.Background()
+
+ versionFinder := ccip.NewEvmVersionFinder()
+
+ var execPluginConfig ccipconfig.ExecPluginConfig
+ err := json.Unmarshal(pargs.PluginConfig, &execPluginConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ usdcConfig := execPluginConfig.USDCConfig
+
+ // The src chain implementation of this provider does not need a configWatcher or contractTransmitter;
+ // bail early.
+ if execPluginConfig.IsSourceProvider {
+ return NewSrcExecProvider(
+ r.lggr,
+ versionFinder,
+ r.chain.Client(),
+ r.chain.GasEstimator(),
+ r.chain.Config().EVM().GasEstimator().PriceMax().ToInt(),
+ r.chain.LogPoller(),
+ execPluginConfig.SourceStartBlock,
+ execPluginConfig.JobID,
+ usdcConfig.AttestationAPI,
+ int(usdcConfig.AttestationAPITimeoutSeconds),
+ usdcConfig.AttestationAPIIntervalMilliseconds,
+ usdcConfig.SourceMessageTransmitterAddress,
+ )
+ }
+
+ relayOpts := types.NewRelayOpts(rargs)
+ configWatcher, err := newStandardConfigProvider(ctx, r.lggr, r.chain, relayOpts)
+ if err != nil {
+ return nil, err
+ }
+ address := common.HexToAddress(relayOpts.ContractID)
+ typ, ver, err := ccipconfig.TypeAndVersion(address, r.chain.Client())
+ if err != nil {
+ return nil, err
+ }
+ fn, err := ccipexec.ExecReportToEthTxMeta(ctx, typ, ver)
+ if err != nil {
+ return nil, err
+ }
+ subjectID := chainToUUID(configWatcher.chain.ID())
+ contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.ks.Eth(), configWatcher, configTransmitterOpts{
+ subjectID: &subjectID,
+ }, OCR2AggregatorTransmissionContractABI, WithReportToEthMetadata(fn), WithRetention(0))
+ if err != nil {
+ return nil, err
+ }
+
+ return NewDstExecProvider(
+ r.lggr,
+ versionFinder,
+ r.chain.Client(),
+ r.chain.LogPoller(),
+ execPluginConfig.DestStartBlock,
+ contractTransmitter,
+ configWatcher,
+ r.chain.GasEstimator(),
+ *r.chain.Config().EVM().GasEstimator().PriceMax().ToInt(),
+ r.chain.TxManager(),
+ cciptypes.Address(rargs.ContractID),
+ )
}
var _ commontypes.MedianProvider = (*medianProvider)(nil)
diff --git a/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go b/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go
index 4474f054dbc..7812ab202b1 100644
--- a/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go
+++ b/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go
@@ -32,9 +32,10 @@ import (
)
const (
- triggerWithDynamicTopic = "TriggeredEventWithDynamicTopic"
- triggerWithAllTopics = "TriggeredWithFourTopics"
- finalityDepth = 4
+ triggerWithDynamicTopic = "TriggeredEventWithDynamicTopic"
+ triggerWithAllTopics = "TriggeredWithFourTopics"
+ triggerWithAllTopicsWithHashed = "TriggeredWithFourTopicsWithHashed"
+ finalityDepth = 4
)
type EVMChainReaderInterfaceTesterHelper[T TestingT[T]] interface {
@@ -96,7 +97,7 @@ func (it *EVMChainReaderInterfaceTester[T]) Setup(t T) {
AnyContractName: {
ContractABI: chain_reader_tester.ChainReaderTesterMetaData.ABI,
ContractPollingFilter: types.ContractPollingFilter{
- GenericEventNames: []string{EventName, EventWithFilterName},
+ GenericEventNames: []string{EventName, EventWithFilterName, triggerWithAllTopicsWithHashed},
},
Configs: map[string]*types.ChainReaderDefinition{
MethodTakingLatestParamsReturningTestStruct: &methodTakingLatestParamsReturningTestStructConfig,
@@ -145,6 +146,13 @@ func (it *EVMChainReaderInterfaceTester[T]) Setup(t T) {
// These float values can map to different finality concepts across chains.
ConfidenceConfirmations: map[string]int{"0.0": int(evmtypes.Unconfirmed), "1.0": int(evmtypes.Finalized)},
},
+ triggerWithAllTopicsWithHashed: {
+ ChainSpecificName: triggerWithAllTopicsWithHashed,
+ ReadType: types.Event,
+ EventDefinitions: &types.EventDefinitions{
+ InputFields: []string{"Field1", "Field2", "Field3"},
+ },
+ },
MethodReturningSeenStruct: {
ChainSpecificName: "returnSeen",
InputModifications: codec.ModifiersConfig{
diff --git a/core/services/relay/evm/evmtesting/run_tests.go b/core/services/relay/evm/evmtesting/run_tests.go
index f958c055ca7..caa24e8ae2c 100644
--- a/core/services/relay/evm/evmtesting/run_tests.go
+++ b/core/services/relay/evm/evmtesting/run_tests.go
@@ -12,10 +12,9 @@ import (
clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
. "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with .
-
- "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
)
func RunChainReaderEvmTests[T TestingT[T]](t T, it *EVMChainReaderInterfaceTester[T]) {
@@ -74,6 +73,31 @@ func RunChainReaderEvmTests[T TestingT[T]](t T, it *EVMChainReaderInterfaceTeste
assert.Equal(t, int32(3), latest.Field3)
})
+ t.Run("Filtering can be done on indexed topics that get hashed", func(t T) {
+ it.Setup(t)
+ it.dirtyContracts = true
+ triggerFourTopicsWithHashed(t, it, "1", [32]uint8{2}, [32]byte{5})
+ triggerFourTopicsWithHashed(t, it, "2", [32]uint8{2}, [32]byte{3})
+ triggerFourTopicsWithHashed(t, it, "1", [32]uint8{3}, [32]byte{3})
+
+ ctx := it.Helper.Context(t)
+ cr := it.GetChainReader(t)
+ require.NoError(t, cr.Bind(ctx, it.GetBindings(t)))
+ var latest struct {
+ Field3 [32]byte
+ }
+ params := struct {
+ Field1 string
+ Field2 [32]uint8
+ Field3 [32]byte
+ }{Field1: "1", Field2: [32]uint8{2}, Field3: [32]byte{5}}
+
+ time.Sleep(it.MaxWaitTimeForEvents())
+ require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, triggerWithAllTopicsWithHashed, primitives.Unconfirmed, params, &latest))
+ // only checking Field3 topic makes sense since it isn't hashed, to check other fields we'd have to replicate solidity encoding and hashing
+ assert.Equal(t, [32]uint8{5}, latest.Field3)
+ })
+
t.Run("Bind returns error on missing contract at address", func(t T) {
it.Setup(t)
@@ -95,3 +119,12 @@ func triggerFourTopics[T TestingT[T]](t T, it *EVMChainReaderInterfaceTester[T],
it.IncNonce()
it.AwaitTx(t, tx)
}
+
+func triggerFourTopicsWithHashed[T TestingT[T]](t T, it *EVMChainReaderInterfaceTester[T], i1 string, i2 [32]uint8, i3 [32]byte) {
+ tx, err := it.contractTesters[it.address].ChainReaderTesterTransactor.TriggerWithFourTopicsWithHashed(it.GetAuthWithGasSet(t), i1, i2, i3)
+ require.NoError(t, err)
+ require.NoError(t, err)
+ it.Helper.Commit()
+ it.IncNonce()
+ it.AwaitTx(t, tx)
+}
diff --git a/core/services/relay/evm/exec_provider.go b/core/services/relay/evm/exec_provider.go
new file mode 100644
index 00000000000..db10f31f357
--- /dev/null
+++ b/core/services/relay/evm/exec_provider.go
@@ -0,0 +1,391 @@
+package evm
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "net/url"
+ "time"
+
+ "go.uber.org/multierr"
+
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+ commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
+ cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip"
+
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/tokendata/usdc"
+)
+
+type SrcExecProvider struct {
+ lggr logger.Logger
+ versionFinder ccip.VersionFinder
+ client client.Client
+ lp logpoller.LogPoller
+ startBlock uint64
+ estimator gas.EvmFeeEstimator
+ maxGasPrice *big.Int
+ usdcReader *ccip.USDCReaderImpl
+ usdcAttestationAPI string
+ usdcAttestationAPITimeoutSeconds int
+ usdcAttestationAPIIntervalMilliseconds int
+ usdcSrcMsgTransmitterAddr common.Address
+
+ // these values are nil and are updated for Close()
+ seenOnRampAddress *cciptypes.Address
+ seenSourceChainSelector *uint64
+ seenDestChainSelector *uint64
+}
+
+func NewSrcExecProvider(
+ lggr logger.Logger,
+ versionFinder ccip.VersionFinder,
+ client client.Client,
+ estimator gas.EvmFeeEstimator,
+ maxGasPrice *big.Int,
+ lp logpoller.LogPoller,
+ startBlock uint64,
+ jobID string,
+ usdcAttestationAPI string,
+ usdcAttestationAPITimeoutSeconds int,
+ usdcAttestationAPIIntervalMilliseconds int,
+ usdcSrcMsgTransmitterAddr common.Address,
+) (commontypes.CCIPExecProvider, error) {
+ var usdcReader *ccip.USDCReaderImpl
+ var err error
+ if usdcAttestationAPI != "" {
+ usdcReader, err = ccip.NewUSDCReader(lggr, jobID, usdcSrcMsgTransmitterAddr, lp, true)
+ if err != nil {
+ return nil, fmt.Errorf("new usdc reader: %w", err)
+ }
+ }
+
+ return &SrcExecProvider{
+ lggr: lggr,
+ versionFinder: versionFinder,
+ client: client,
+ estimator: estimator,
+ maxGasPrice: maxGasPrice,
+ lp: lp,
+ startBlock: startBlock,
+ usdcReader: usdcReader,
+ usdcAttestationAPI: usdcAttestationAPI,
+ usdcAttestationAPITimeoutSeconds: usdcAttestationAPITimeoutSeconds,
+ usdcAttestationAPIIntervalMilliseconds: usdcAttestationAPIIntervalMilliseconds,
+ usdcSrcMsgTransmitterAddr: usdcSrcMsgTransmitterAddr,
+ }, nil
+}
+
+func (s *SrcExecProvider) Name() string {
+ return "CCIP.SrcExecProvider"
+}
+
+func (s *SrcExecProvider) Start(ctx context.Context) error {
+ if s.startBlock != 0 {
+ s.lggr.Infow("start replaying src chain", "fromBlock", s.startBlock)
+ return s.lp.Replay(ctx, int64(s.startBlock))
+ }
+ return nil
+}
+
+// Close is called when the job that created this provider is closed.
+func (s *SrcExecProvider) Close() error {
+ versionFinder := ccip.NewEvmVersionFinder()
+
+ unregisterFuncs := make([]func() error, 0, 2)
+ unregisterFuncs = append(unregisterFuncs, func() error {
+ // avoid panic in the case NewOnRampReader wasn't called
+ if s.seenOnRampAddress == nil {
+ return nil
+ }
+ return ccip.CloseOnRampReader(s.lggr, versionFinder, *s.seenSourceChainSelector, *s.seenDestChainSelector, *s.seenOnRampAddress, s.lp, s.client)
+ })
+ unregisterFuncs = append(unregisterFuncs, func() error {
+ if s.usdcAttestationAPI == "" {
+ return nil
+ }
+ return ccip.CloseUSDCReader(s.lggr, s.lggr.Name(), s.usdcSrcMsgTransmitterAddr, s.lp)
+ })
+ var multiErr error
+ for _, fn := range unregisterFuncs {
+ if err := fn(); err != nil {
+ multiErr = multierr.Append(multiErr, err)
+ }
+ }
+ return multiErr
+}
+
+func (s *SrcExecProvider) Ready() error {
+ return nil
+}
+
+func (s *SrcExecProvider) HealthReport() map[string]error {
+ return make(map[string]error)
+}
+
+func (s *SrcExecProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester {
+ // TODO CCIP-2494
+ // OffchainConfigDigester called on SrcExecProvider. It should only be called on DstExecProvider
+ return UnimplementedOffchainConfigDigester{}
+}
+
+func (s *SrcExecProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker {
+ // TODO CCIP-2494
+ // "ContractConfigTracker called on SrcExecProvider. It should only be called on DstExecProvider
+ return UnimplementedContractConfigTracker{}
+}
+
+func (s *SrcExecProvider) ContractTransmitter() ocrtypes.ContractTransmitter {
+ // TODO CCIP-2494
+ // "ContractTransmitter called on SrcExecProvider. It should only be called on DstExecProvider
+ return UnimplementedContractTransmitter{}
+}
+
+func (s *SrcExecProvider) ChainReader() commontypes.ContractReader {
+ return nil
+}
+
+func (s *SrcExecProvider) Codec() commontypes.Codec {
+ return nil
+}
+
+func (s *SrcExecProvider) GetTransactionStatus(ctx context.Context, transactionID string) (types.TransactionStatus, error) {
+ return 0, fmt.Errorf("invalid: GetTransactionStatus called on SrcExecProvider. It should only be called on DstExecProvider")
+}
+
+func (s *SrcExecProvider) NewCommitStoreReader(ctx context.Context, addr cciptypes.Address) (commitStoreReader cciptypes.CommitStoreReader, err error) {
+ commitStoreReader = NewIncompleteSourceCommitStoreReader(s.estimator, s.maxGasPrice)
+ return
+}
+
+func (s *SrcExecProvider) NewOffRampReader(ctx context.Context, addr cciptypes.Address) (cciptypes.OffRampReader, error) {
+ return nil, fmt.Errorf("invalid: NewOffRampReader called on SrcExecProvider. Valid on DstExecProvider")
+}
+
+func (s *SrcExecProvider) NewOnRampReader(ctx context.Context, onRampAddress cciptypes.Address, sourceChainSelector uint64, destChainSelector uint64) (onRampReader cciptypes.OnRampReader, err error) {
+ s.seenOnRampAddress = &onRampAddress
+
+ versionFinder := ccip.NewEvmVersionFinder()
+ onRampReader, err = ccip.NewOnRampReader(s.lggr, versionFinder, sourceChainSelector, destChainSelector, onRampAddress, s.lp, s.client)
+ return
+}
+
+func (s *SrcExecProvider) NewPriceRegistryReader(ctx context.Context, addr cciptypes.Address) (priceRegistryReader cciptypes.PriceRegistryReader, err error) {
+ srcPriceRegistry := ccip.NewEvmPriceRegistry(s.lp, s.client, s.lggr, ccip.ExecPluginLabel)
+ priceRegistryReader, err = srcPriceRegistry.NewPriceRegistryReader(ctx, addr)
+ return
+}
+
+func (s *SrcExecProvider) NewTokenDataReader(ctx context.Context, tokenAddress cciptypes.Address) (tokenDataReader cciptypes.TokenDataReader, err error) {
+ attestationURI, err2 := url.ParseRequestURI(s.usdcAttestationAPI)
+ if err2 != nil {
+ return nil, fmt.Errorf("failed to parse USDC attestation API: %w", err2)
+ }
+ tokenAddr, err2 := ccip.GenericAddrToEvm(tokenAddress)
+ if err2 != nil {
+ return nil, fmt.Errorf("failed to parse token address: %w", err2)
+ }
+ tokenDataReader = usdc.NewUSDCTokenDataReader(
+ s.lggr,
+ s.usdcReader,
+ attestationURI,
+ s.usdcAttestationAPITimeoutSeconds,
+ tokenAddr,
+ time.Duration(s.usdcAttestationAPIIntervalMilliseconds)*time.Millisecond,
+ )
+ return
+}
+
+func (s *SrcExecProvider) NewTokenPoolBatchedReader(ctx context.Context, offRampAddr cciptypes.Address, sourceChainSelector uint64) (cciptypes.TokenPoolBatchedReader, error) {
+ return nil, fmt.Errorf("invalid: NewTokenPoolBatchedReader called on SrcExecProvider. It should only be called on DstExecProvdier")
+}
+
+func (s *SrcExecProvider) SourceNativeToken(ctx context.Context, sourceRouterAddr cciptypes.Address) (cciptypes.Address, error) {
+ sourceRouterAddrHex, err := ccip.GenericAddrToEvm(sourceRouterAddr)
+ if err != nil {
+ return "", err
+ }
+ sourceRouter, err := router.NewRouter(sourceRouterAddrHex, s.client)
+ if err != nil {
+ return "", err
+ }
+ sourceNative, err := sourceRouter.GetWrappedNative(&bind.CallOpts{Context: ctx})
+ if err != nil {
+ return "", err
+ }
+
+ return ccip.EvmAddrToGeneric(sourceNative), nil
+}
+
+type DstExecProvider struct {
+ lggr logger.Logger
+ versionFinder ccip.VersionFinder
+ client client.Client
+ lp logpoller.LogPoller
+ startBlock uint64
+ contractTransmitter *contractTransmitter
+ configWatcher *configWatcher
+ gasEstimator gas.EvmFeeEstimator
+ maxGasPrice big.Int
+ txm txmgr.TxManager
+ offRampAddress cciptypes.Address
+
+ // these values are nil and are updated for Close()
+ seenCommitStoreAddr *cciptypes.Address
+}
+
+func NewDstExecProvider(
+ lggr logger.Logger,
+ versionFinder ccip.VersionFinder,
+ client client.Client,
+ lp logpoller.LogPoller,
+ startBlock uint64,
+ contractTransmitter *contractTransmitter,
+ configWatcher *configWatcher,
+ gasEstimator gas.EvmFeeEstimator,
+ maxGasPrice big.Int,
+ txm txmgr.TxManager,
+ offRampAddress cciptypes.Address,
+) (commontypes.CCIPExecProvider, error) {
+ return &DstExecProvider{
+ lggr: lggr,
+ versionFinder: versionFinder,
+ client: client,
+ lp: lp,
+ startBlock: startBlock,
+ contractTransmitter: contractTransmitter,
+ configWatcher: configWatcher,
+ gasEstimator: gasEstimator,
+ maxGasPrice: maxGasPrice,
+ txm: txm,
+ offRampAddress: offRampAddress,
+ }, nil
+}
+
+func (d *DstExecProvider) Name() string {
+ return "CCIP.DestRelayerExecProvider"
+}
+
+func (d *DstExecProvider) Start(ctx context.Context) error {
+ if d.startBlock != 0 {
+ d.lggr.Infow("start replaying dst chain", "fromBlock", d.startBlock)
+ return d.lp.Replay(ctx, int64(d.startBlock))
+ }
+ return nil
+}
+
+// Close is called when the job that created this provider is deleted
+// At this time, any of the methods on the provider may or may not have been called.
+// If NewOnRampReader and NewCommitStoreReader have not been called, their corresponding
+// Close methods will be expected to error.
+func (d *DstExecProvider) Close() error {
+ versionFinder := ccip.NewEvmVersionFinder()
+
+ unregisterFuncs := make([]func() error, 0, 2)
+ unregisterFuncs = append(unregisterFuncs, func() error {
+ if d.seenCommitStoreAddr == nil {
+ return nil
+ }
+ return ccip.CloseCommitStoreReader(d.lggr, versionFinder, *d.seenCommitStoreAddr, d.client, d.lp)
+ })
+ unregisterFuncs = append(unregisterFuncs, func() error {
+ return ccip.CloseOffRampReader(d.lggr, versionFinder, d.offRampAddress, d.client, d.lp, nil, big.NewInt(0))
+ })
+
+ var multiErr error
+ for _, fn := range unregisterFuncs {
+ if err := fn(); err != nil {
+ multiErr = multierr.Append(multiErr, err)
+ }
+ }
+ return multiErr
+}
+
+func (d *DstExecProvider) Ready() error {
+ return nil
+}
+
+func (d *DstExecProvider) HealthReport() map[string]error {
+ return make(map[string]error)
+}
+
+func (d *DstExecProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester {
+ return d.configWatcher.OffchainConfigDigester()
+}
+
+func (d *DstExecProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker {
+ return d.configWatcher.ContractConfigTracker()
+}
+
+func (d *DstExecProvider) ContractTransmitter() ocrtypes.ContractTransmitter {
+ return d.contractTransmitter
+}
+
+func (d *DstExecProvider) ChainReader() commontypes.ContractReader {
+ return nil
+}
+
+func (d *DstExecProvider) Codec() commontypes.Codec {
+ return nil
+}
+
+func (d *DstExecProvider) GetTransactionStatus(ctx context.Context, transactionID string) (types.TransactionStatus, error) {
+ return d.txm.GetTransactionStatus(ctx, transactionID)
+}
+
+func (d *DstExecProvider) NewCommitStoreReader(ctx context.Context, addr cciptypes.Address) (commitStoreReader cciptypes.CommitStoreReader, err error) {
+ d.seenCommitStoreAddr = &addr
+
+ versionFinder := ccip.NewEvmVersionFinder()
+ commitStoreReader, err = NewIncompleteDestCommitStoreReader(d.lggr, versionFinder, addr, d.client, d.lp)
+ return
+}
+
+func (d *DstExecProvider) NewOffRampReader(ctx context.Context, offRampAddress cciptypes.Address) (offRampReader cciptypes.OffRampReader, err error) {
+ offRampReader, err = ccip.NewOffRampReader(d.lggr, d.versionFinder, offRampAddress, d.client, d.lp, d.gasEstimator, &d.maxGasPrice, true)
+ return
+}
+
+func (d *DstExecProvider) NewOnRampReader(ctx context.Context, addr cciptypes.Address, sourceChainSelector uint64, destChainSelector uint64) (cciptypes.OnRampReader, error) {
+ return nil, fmt.Errorf("invalid: NewOnRampReader called on DstExecProvider. It should only be called on SrcExecProvider")
+}
+
+func (d *DstExecProvider) NewPriceRegistryReader(ctx context.Context, addr cciptypes.Address) (priceRegistryReader cciptypes.PriceRegistryReader, err error) {
+ destPriceRegistry := ccip.NewEvmPriceRegistry(d.lp, d.client, d.lggr, ccip.ExecPluginLabel)
+ priceRegistryReader, err = destPriceRegistry.NewPriceRegistryReader(ctx, addr)
+ return
+}
+
+func (d *DstExecProvider) NewTokenDataReader(ctx context.Context, tokenAddress cciptypes.Address) (cciptypes.TokenDataReader, error) {
+ return nil, fmt.Errorf("invalid: NewTokenDataReader called on DstExecProvider. It should only be called on SrcExecProvider")
+}
+
+func (d *DstExecProvider) NewTokenPoolBatchedReader(ctx context.Context, offRampAddress cciptypes.Address, sourceChainSelector uint64) (tokenPoolBatchedReader cciptypes.TokenPoolBatchedReader, err error) {
+ batchCaller := ccip.NewDynamicLimitedBatchCaller(
+ d.lggr,
+ d.client,
+ uint(ccip.DefaultRpcBatchSizeLimit),
+ uint(ccip.DefaultRpcBatchBackOffMultiplier),
+ uint(ccip.DefaultMaxParallelRpcCalls),
+ )
+
+ tokenPoolBatchedReader, err = ccip.NewEVMTokenPoolBatchedReader(d.lggr, sourceChainSelector, offRampAddress, batchCaller)
+ if err != nil {
+ return nil, fmt.Errorf("new token pool batched reader: %w", err)
+ }
+ return
+}
+
+func (d *DstExecProvider) SourceNativeToken(ctx context.Context, addr cciptypes.Address) (cciptypes.Address, error) {
+ return "", fmt.Errorf("invalid: SourceNativeToken called on DstExecProvider. It should only be called on SrcExecProvider")
+}
diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go
index a04a991e379..1f1554eb111 100644
--- a/core/services/relay/evm/functions.go
+++ b/core/services/relay/evm/functions.go
@@ -8,17 +8,15 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
- "go.uber.org/multierr"
-
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr"
txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr"
"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/ocr2/plugins/functions/config"
functionsRelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions"
@@ -26,12 +24,29 @@ import (
)
type functionsProvider struct {
- services.StateMachine
+ services.Service
+ eng *services.Engine
+
configWatcher *configWatcher
contractTransmitter ContractTransmitter
logPollerWrapper evmRelayTypes.LogPollerWrapper
}
+func newFunctionsProvider(lggr logger.Logger, cw *configWatcher, ct ContractTransmitter, lpw evmRelayTypes.LogPollerWrapper) *functionsProvider {
+ p := &functionsProvider{
+ configWatcher: cw,
+ contractTransmitter: ct,
+ logPollerWrapper: lpw,
+ }
+ p.Service, p.eng = services.Config{
+ Name: "FunctionsProvider",
+ NewSubServices: func(lggr logger.Logger) []services.Service {
+ return []services.Service{p.configWatcher, p.logPollerWrapper}
+ },
+ }.NewServiceEngine(lggr)
+ return p
+}
+
var _ evmRelayTypes.FunctionsProvider = (*functionsProvider)(nil)
func (p *functionsProvider) ContractTransmitter() ocrtypes.ContractTransmitter {
@@ -47,23 +62,6 @@ func (p *functionsProvider) FunctionsEvents() commontypes.FunctionsEvents {
return nil
}
-func (p *functionsProvider) Start(ctx context.Context) error {
- return p.StartOnce("FunctionsProvider", func() error {
- if err := p.configWatcher.Start(ctx); err != nil {
- return err
- }
- return p.logPollerWrapper.Start(ctx)
- })
-}
-
-func (p *functionsProvider) Close() error {
- return p.StopOnce("FunctionsProvider", func() (err error) {
- err = multierr.Combine(err, p.logPollerWrapper.Close())
- err = multierr.Combine(err, p.configWatcher.Close())
- return
- })
-}
-
// Forward all calls to the underlying configWatcher
func (p *functionsProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigester {
return p.configWatcher.OffchainConfigDigester()
@@ -73,14 +71,6 @@ func (p *functionsProvider) ContractConfigTracker() ocrtypes.ContractConfigTrack
return p.configWatcher.ContractConfigTracker()
}
-func (p *functionsProvider) HealthReport() map[string]error {
- return p.configWatcher.HealthReport()
-}
-
-func (p *functionsProvider) Name() string {
- return p.configWatcher.Name()
-}
-
func (p *functionsProvider) ChainReader() commontypes.ContractReader {
return nil
}
@@ -127,11 +117,7 @@ func NewFunctionsProvider(ctx context.Context, chain legacyevm.Chain, rargs comm
} else {
lggr.Warn("no sending keys configured for functions plugin, not starting contract transmitter")
}
- return &functionsProvider{
- configWatcher: configWatcher,
- contractTransmitter: contractTransmitter,
- logPollerWrapper: logPollerWrapper,
- }, nil
+ return newFunctionsProvider(lggr, configWatcher, contractTransmitter, logPollerWrapper), nil
}
func newFunctionsConfigProvider(ctx context.Context, pluginType functionsRelay.FunctionsPluginType, chain legacyevm.Chain, args commontypes.RelayArgs, fromBlock uint64, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (*configWatcher, error) {
diff --git a/core/services/relay/evm/functions/config_poller.go b/core/services/relay/evm/functions/config_poller.go
index 71616f2e840..2cb21738b91 100644
--- a/core/services/relay/evm/functions/config_poller.go
+++ b/core/services/relay/evm/functions/config_poller.go
@@ -9,12 +9,13 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
- "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
+ "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
diff --git a/core/services/relay/evm/functions/contract_transmitter.go b/core/services/relay/evm/functions/contract_transmitter.go
index 23143ed3ef1..f588a02390c 100644
--- a/core/services/relay/evm/functions/contract_transmitter.go
+++ b/core/services/relay/evm/functions/contract_transmitter.go
@@ -13,14 +13,16 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
+
"github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"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"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/encoding"
evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
@@ -105,7 +107,7 @@ func NewFunctionsContractTransmitter(
transmittedEventSig: transmitted.ID,
lp: lp,
contractReader: caller,
- lggr: lggr.Named("OCRFunctionsContractTransmitter"),
+ lggr: logger.Named(lggr, "OCRFunctionsContractTransmitter"),
contractVersion: contractVersion,
reportCodec: codec,
txm: txm,
diff --git a/core/services/relay/evm/functions/logpoller_wrapper.go b/core/services/relay/evm/functions/logpoller_wrapper.go
index 559b1ec33f5..260c366eb8e 100644
--- a/core/services/relay/evm/functions/logpoller_wrapper.go
+++ b/core/services/relay/evm/functions/logpoller_wrapper.go
@@ -10,19 +10,20 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config"
evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
type logPollerWrapper struct {
- services.StateMachine
+ services.Service
+ eng *services.Engine
routerContract *functions_router.FunctionsRouter
pluginConfig config.PluginConfig
@@ -38,9 +39,6 @@ type logPollerWrapper struct {
detectedRequests detectedEvents
detectedResponses detectedEvents
mu sync.Mutex
- closeWait sync.WaitGroup
- stopCh services.StopChan
- lggr logger.Logger
}
type detectedEvent struct {
@@ -94,7 +92,7 @@ func NewLogPollerWrapper(routerContractAddress common.Address, pluginConfig conf
return nil, errors.Errorf("invalid config: number of required confirmation blocks >= pastBlocksToPoll")
}
- return &logPollerWrapper{
+ w := &logPollerWrapper{
routerContract: routerContract,
pluginConfig: pluginConfig,
requestBlockOffset: requestBlockOffset,
@@ -106,40 +104,25 @@ func NewLogPollerWrapper(routerContractAddress common.Address, pluginConfig conf
logPoller: logPoller,
client: client,
subscribers: make(map[string]evmRelayTypes.RouteUpdateSubscriber),
- stopCh: make(services.StopChan),
- lggr: lggr.Named("LogPollerWrapper"),
- }, nil
-}
-
-func (l *logPollerWrapper) Start(context.Context) error {
- return l.StartOnce("LogPollerWrapper", func() error {
- l.lggr.Infow("starting LogPollerWrapper", "routerContract", l.routerContract.Address().Hex(), "contractVersion", l.pluginConfig.ContractVersion)
- l.mu.Lock()
- defer l.mu.Unlock()
- if l.pluginConfig.ContractVersion != 1 {
- return errors.New("only contract version 1 is supported")
- }
- l.closeWait.Add(1)
- go l.checkForRouteUpdates()
- return nil
- })
-}
-
-func (l *logPollerWrapper) Close() error {
- return l.StopOnce("LogPollerWrapper", func() (err error) {
- l.lggr.Info("closing LogPollerWrapper")
- close(l.stopCh)
- l.closeWait.Wait()
- return nil
- })
+ }
+ w.Service, w.eng = services.Config{
+ Name: "LoggPollerWrapper",
+ Start: w.start,
+ }.NewServiceEngine(lggr)
+ return w, nil
}
-func (l *logPollerWrapper) HealthReport() map[string]error {
- return map[string]error{l.Name(): l.Ready()}
+func (l *logPollerWrapper) start(context.Context) error {
+ l.eng.Infow("starting LogPollerWrapper", "routerContract", l.routerContract.Address().Hex(), "contractVersion", l.pluginConfig.ContractVersion)
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ if l.pluginConfig.ContractVersion != 1 {
+ return errors.New("only contract version 1 is supported")
+ }
+ l.eng.Go(l.checkForRouteUpdates)
+ return nil
}
-func (l *logPollerWrapper) Name() string { return l.lggr.Name() }
-
// methods of LogPollerWrapper
func (l *logPollerWrapper) LatestEvents(ctx context.Context) ([]evmRelayTypes.OracleRequest, []evmRelayTypes.OracleResponse, error) {
l.mu.Lock()
@@ -166,7 +149,7 @@ func (l *logPollerWrapper) LatestEvents(ctx context.Context) ([]evmRelayTypes.Or
resultsReq := []evmRelayTypes.OracleRequest{}
resultsResp := []evmRelayTypes.OracleResponse{}
if len(coordinators) == 0 {
- l.lggr.Debug("LatestEvents: no non-zero coordinators to check")
+ l.eng.Debug("LatestEvents: no non-zero coordinators to check")
return resultsReq, resultsResp, errors.New("no non-zero coordinators to check")
}
@@ -174,32 +157,32 @@ func (l *logPollerWrapper) LatestEvents(ctx context.Context) ([]evmRelayTypes.Or
requestEndBlock := latestBlockNum - l.requestBlockOffset
requestLogs, err := l.logPoller.Logs(ctx, startBlockNum, requestEndBlock, functions_coordinator.FunctionsCoordinatorOracleRequest{}.Topic(), coordinator)
if err != nil {
- l.lggr.Errorw("LatestEvents: fetching request logs from LogPoller failed", "startBlock", startBlockNum, "endBlock", requestEndBlock)
+ l.eng.Errorw("LatestEvents: fetching request logs from LogPoller failed", "startBlock", startBlockNum, "endBlock", requestEndBlock)
return nil, nil, err
}
- l.lggr.Debugw("LatestEvents: fetched request logs", "nRequestLogs", len(requestLogs), "latestBlock", latest, "startBlock", startBlockNum, "endBlock", requestEndBlock)
+ l.eng.Debugw("LatestEvents: fetched request logs", "nRequestLogs", len(requestLogs), "latestBlock", latest, "startBlock", startBlockNum, "endBlock", requestEndBlock)
requestLogs = l.filterPreviouslyDetectedEvents(requestLogs, &l.detectedRequests, "requests")
responseEndBlock := latestBlockNum - l.responseBlockOffset
responseLogs, err := l.logPoller.Logs(ctx, startBlockNum, responseEndBlock, functions_coordinator.FunctionsCoordinatorOracleResponse{}.Topic(), coordinator)
if err != nil {
- l.lggr.Errorw("LatestEvents: fetching response logs from LogPoller failed", "startBlock", startBlockNum, "endBlock", responseEndBlock)
+ l.eng.Errorw("LatestEvents: fetching response logs from LogPoller failed", "startBlock", startBlockNum, "endBlock", responseEndBlock)
return nil, nil, err
}
- l.lggr.Debugw("LatestEvents: fetched request logs", "nResponseLogs", len(responseLogs), "latestBlock", latest, "startBlock", startBlockNum, "endBlock", responseEndBlock)
+ l.eng.Debugw("LatestEvents: fetched request logs", "nResponseLogs", len(responseLogs), "latestBlock", latest, "startBlock", startBlockNum, "endBlock", responseEndBlock)
responseLogs = l.filterPreviouslyDetectedEvents(responseLogs, &l.detectedResponses, "responses")
parsingContract, err := functions_coordinator.NewFunctionsCoordinator(coordinator, l.client)
if err != nil {
- l.lggr.Error("LatestEvents: creating a contract instance for parsing failed")
+ l.eng.Error("LatestEvents: creating a contract instance for parsing failed")
return nil, nil, err
}
- l.lggr.Debugw("LatestEvents: parsing logs", "nRequestLogs", len(requestLogs), "nResponseLogs", len(responseLogs), "coordinatorAddress", coordinator.Hex())
+ l.eng.Debugw("LatestEvents: parsing logs", "nRequestLogs", len(requestLogs), "nResponseLogs", len(responseLogs), "coordinatorAddress", coordinator.Hex())
for _, log := range requestLogs {
gethLog := log.ToGethLog()
oracleRequest, err := parsingContract.ParseOracleRequest(gethLog)
if err != nil {
- l.lggr.Errorw("LatestEvents: failed to parse a request log, skipping", "err", err)
+ l.eng.Errorw("LatestEvents: failed to parse a request log, skipping", "err", err)
continue
}
@@ -212,7 +195,7 @@ func (l *logPollerWrapper) LatestEvents(ctx context.Context) ([]evmRelayTypes.Or
bytes32Type, errType7 := abi.NewType("bytes32", "bytes32", nil)
if errType1 != nil || errType2 != nil || errType3 != nil || errType4 != nil || errType5 != nil || errType6 != nil || errType7 != nil {
- l.lggr.Errorw("LatestEvents: failed to initialize types", "errType1", errType1,
+ l.eng.Errorw("LatestEvents: failed to initialize types", "errType1", errType1,
"errType2", errType2, "errType3", errType3, "errType4", errType4, "errType5", errType5, "errType6", errType6, "errType7", errType7,
)
continue
@@ -244,7 +227,7 @@ func (l *logPollerWrapper) LatestEvents(ctx context.Context) ([]evmRelayTypes.Or
oracleRequest.Commitment.TimeoutTimestamp,
)
if err != nil {
- l.lggr.Errorw("LatestEvents: failed to pack commitment bytes, skipping", "err", err)
+ l.eng.Errorw("LatestEvents: failed to pack commitment bytes, skipping", "err", err)
}
resultsReq = append(resultsReq, evmRelayTypes.OracleRequest{
@@ -266,7 +249,7 @@ func (l *logPollerWrapper) LatestEvents(ctx context.Context) ([]evmRelayTypes.Or
gethLog := log.ToGethLog()
oracleResponse, err := parsingContract.ParseOracleResponse(gethLog)
if err != nil {
- l.lggr.Errorw("LatestEvents: failed to parse a response log, skipping")
+ l.eng.Errorw("LatestEvents: failed to parse a response log, skipping")
continue
}
resultsResp = append(resultsResp, evmRelayTypes.OracleResponse{
@@ -275,13 +258,13 @@ func (l *logPollerWrapper) LatestEvents(ctx context.Context) ([]evmRelayTypes.Or
}
}
- l.lggr.Debugw("LatestEvents: done", "nRequestLogs", len(resultsReq), "nResponseLogs", len(resultsResp), "startBlock", startBlockNum, "endBlock", latestBlockNum)
+ l.eng.Debugw("LatestEvents: done", "nRequestLogs", len(resultsReq), "nResponseLogs", len(resultsResp), "startBlock", startBlockNum, "endBlock", latestBlockNum)
return resultsReq, resultsResp, nil
}
func (l *logPollerWrapper) filterPreviouslyDetectedEvents(logs []logpoller.Log, detectedEvents *detectedEvents, filterType string) []logpoller.Log {
if len(logs) > maxLogsToProcess {
- l.lggr.Errorw("filterPreviouslyDetectedEvents: too many logs to process, only processing latest maxLogsToProcess logs", "filterType", filterType, "nLogs", len(logs), "maxLogsToProcess", maxLogsToProcess)
+ l.eng.Errorw("filterPreviouslyDetectedEvents: too many logs to process, only processing latest maxLogsToProcess logs", "filterType", filterType, "nLogs", len(logs), "maxLogsToProcess", maxLogsToProcess)
logs = logs[len(logs)-maxLogsToProcess:]
}
l.mu.Lock()
@@ -290,7 +273,7 @@ func (l *logPollerWrapper) filterPreviouslyDetectedEvents(logs []logpoller.Log,
for _, log := range logs {
var requestId [32]byte
if len(log.Topics) < 2 || len(log.Topics[1]) != 32 {
- l.lggr.Errorw("filterPreviouslyDetectedEvents: invalid log, skipping", "filterType", filterType, "log", log)
+ l.eng.Errorw("filterPreviouslyDetectedEvents: invalid log, skipping", "filterType", filterType, "log", log)
continue
}
copy(requestId[:], log.Topics[1]) // requestId is the second topic (1st topic is the event signature)
@@ -310,7 +293,7 @@ func (l *logPollerWrapper) filterPreviouslyDetectedEvents(logs []logpoller.Log,
expiredRequests++
}
detectedEvents.detectedEventsOrdered = detectedEvents.detectedEventsOrdered[expiredRequests:]
- l.lggr.Debugw("filterPreviouslyDetectedEvents: done", "filterType", filterType, "nLogs", len(logs), "nFilteredLogs", len(filteredLogs), "nExpiredRequests", expiredRequests, "previouslyDetectedCacheSize", len(detectedEvents.detectedEventsOrdered))
+ l.eng.Debugw("filterPreviouslyDetectedEvents: done", "filterType", filterType, "nLogs", len(logs), "nFilteredLogs", len(filteredLogs), "nExpiredRequests", expiredRequests, "previouslyDetectedCacheSize", len(detectedEvents.detectedEventsOrdered))
return filteredLogs
}
@@ -319,7 +302,7 @@ func (l *logPollerWrapper) SubscribeToUpdates(ctx context.Context, subscriberNam
if l.pluginConfig.ContractVersion == 0 {
// in V0, immediately set contract address to Oracle contract and never update again
if err := subscriber.UpdateRoutes(ctx, l.routerContract.Address(), l.routerContract.Address()); err != nil {
- l.lggr.Errorw("LogPollerWrapper: Failed to update routes", "subscriberName", subscriberName, "err", err)
+ l.eng.Errorw("LogPollerWrapper: Failed to update routes", "subscriberName", subscriberName, "err", err)
}
} else if l.pluginConfig.ContractVersion == 1 {
l.mu.Lock()
@@ -328,37 +311,36 @@ func (l *logPollerWrapper) SubscribeToUpdates(ctx context.Context, subscriberNam
}
}
-func (l *logPollerWrapper) checkForRouteUpdates() {
- defer l.closeWait.Done()
+func (l *logPollerWrapper) checkForRouteUpdates(ctx context.Context) {
freqSec := l.pluginConfig.ContractUpdateCheckFrequencySec
if freqSec == 0 {
- l.lggr.Errorw("LogPollerWrapper: ContractUpdateCheckFrequencySec is zero - route update checks disabled")
+ l.eng.Errorw("LogPollerWrapper: ContractUpdateCheckFrequencySec is zero - route update checks disabled")
return
}
- updateOnce := func() {
+ updateOnce := func(ctx context.Context) {
// NOTE: timeout == frequency here, could be changed to a separate config value
timeout := time.Duration(l.pluginConfig.ContractUpdateCheckFrequencySec) * time.Second
- ctx, cancel := l.stopCh.CtxCancel(context.WithTimeout(context.Background(), timeout))
+ ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
active, proposed, err := l.getCurrentCoordinators(ctx)
if err != nil {
- l.lggr.Errorw("LogPollerWrapper: error calling getCurrentCoordinators", "err", err)
+ l.eng.Errorw("LogPollerWrapper: error calling getCurrentCoordinators", "err", err)
return
}
l.handleRouteUpdate(ctx, active, proposed)
}
- updateOnce() // update once right away
+ updateOnce(ctx) // update once right away
ticker := time.NewTicker(time.Duration(freqSec) * time.Second)
defer ticker.Stop()
for {
select {
- case <-l.stopCh:
+ case <-ctx.Done():
return
case <-ticker.C:
- updateOnce()
+ updateOnce(ctx)
}
}
}
@@ -394,22 +376,22 @@ func (l *logPollerWrapper) handleRouteUpdate(ctx context.Context, activeCoordina
defer l.mu.Unlock()
if activeCoordinator == (common.Address{}) {
- l.lggr.Error("LogPollerWrapper: cannot update activeCoordinator to zero address")
+ l.eng.Error("LogPollerWrapper: cannot update activeCoordinator to zero address")
return
}
if activeCoordinator == l.activeCoordinator && proposedCoordinator == l.proposedCoordinator {
- l.lggr.Debug("LogPollerWrapper: no changes to routes")
+ l.eng.Debug("LogPollerWrapper: no changes to routes")
return
}
errActive := l.registerFilters(ctx, activeCoordinator)
errProposed := l.registerFilters(ctx, proposedCoordinator)
if errActive != nil || errProposed != nil {
- l.lggr.Errorw("LogPollerWrapper: Failed to register filters", "errorActive", errActive, "errorProposed", errProposed)
+ l.eng.Errorw("LogPollerWrapper: Failed to register filters", "errorActive", errActive, "errorProposed", errProposed)
return
}
- l.lggr.Debugw("LogPollerWrapper: new routes", "activeCoordinator", activeCoordinator.Hex(), "proposedCoordinator", proposedCoordinator.Hex())
+ l.eng.Debugw("LogPollerWrapper: new routes", "activeCoordinator", activeCoordinator.Hex(), "proposedCoordinator", proposedCoordinator.Hex())
l.activeCoordinator = activeCoordinator
l.proposedCoordinator = proposedCoordinator
@@ -417,7 +399,7 @@ func (l *logPollerWrapper) handleRouteUpdate(ctx context.Context, activeCoordina
for _, subscriber := range l.subscribers {
err := subscriber.UpdateRoutes(ctx, activeCoordinator, proposedCoordinator)
if err != nil {
- l.lggr.Errorw("LogPollerWrapper: Failed to update routes", "err", err)
+ l.eng.Errorw("LogPollerWrapper: Failed to update routes", "err", err)
}
}
@@ -430,9 +412,9 @@ func (l *logPollerWrapper) handleRouteUpdate(ctx context.Context, activeCoordina
continue
}
if err := l.logPoller.UnregisterFilter(ctx, filter.Name); err != nil {
- l.lggr.Errorw("LogPollerWrapper: Failed to unregister filter", "filterName", filter.Name, "err", err)
+ l.eng.Errorw("LogPollerWrapper: Failed to unregister filter", "filterName", filter.Name, "err", err)
}
- l.lggr.Debugw("LogPollerWrapper: Successfully unregistered filter", "filterName", filter.Name)
+ l.eng.Debugw("LogPollerWrapper: Successfully unregistered filter", "filterName", filter.Name)
}
}
diff --git a/core/services/relay/evm/llo_config_provider.go b/core/services/relay/evm/llo_config_provider.go
index 6efd0ccada2..71b6a39be25 100644
--- a/core/services/relay/evm/llo_config_provider.go
+++ b/core/services/relay/evm/llo_config_provider.go
@@ -6,8 +6,9 @@ import (
"github.com/ethereum/go-ethereum/common"
pkgerrors "github.com/pkg/errors"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/llo"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
diff --git a/core/services/relay/evm/llo_provider.go b/core/services/relay/evm/llo_provider.go
index b685565e6e0..caedf0e771c 100644
--- a/core/services/relay/evm/llo_provider.go
+++ b/core/services/relay/evm/llo_provider.go
@@ -6,12 +6,12 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
relaytypes "github.com/smartcontractkit/chainlink-common/pkg/types"
llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/llo"
)
@@ -35,7 +35,7 @@ func NewLLOProvider(
return &lloProvider{
cp,
transmitter,
- lggr.Named("LLOProvider"),
+ logger.Named(lggr, "LLOProvider"),
channelDefinitionCache,
services.MultiStart{},
}
diff --git a/core/services/relay/evm/median.go b/core/services/relay/evm/median.go
index 2407cff7140..60a63994bdc 100644
--- a/core/services/relay/evm/median.go
+++ b/core/services/relay/evm/median.go
@@ -8,16 +8,17 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
+
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
"github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median"
"github.com/smartcontractkit/libocr/offchainreporting2plus/types"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
offchain_aggregator_wrapper "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
)
var _ median.MedianContract = &medianContract{}
@@ -31,7 +32,7 @@ type medianContract struct {
}
func newMedianContract(configTracker types.ContractConfigTracker, contractAddress common.Address, chain legacyevm.Chain, specID int32, ds sqlutil.DataSource, lggr logger.Logger) (*medianContract, error) {
- lggr = lggr.Named("MedianContract")
+ lggr = logger.Named(lggr, "MedianContract")
contract, err := offchain_aggregator_wrapper.NewOffchainAggregator(contractAddress, chain.Client())
if err != nil {
return nil, errors.Wrap(err, "could not instantiate NewOffchainAggregator")
diff --git a/core/services/relay/evm/median_test.go b/core/services/relay/evm/median_test.go
index 9c474006aa7..a1578737b68 100644
--- a/core/services/relay/evm/median_test.go
+++ b/core/services/relay/evm/median_test.go
@@ -7,23 +7,23 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
func TestNewMedianProvider(t *testing.T) {
- lggr := logger.TestLogger(t)
+ lggr := logger.Test(t)
chain := mocks.NewChain(t)
chainID := testutils.NewRandomEVMChainID()
chain.On("ID").Return(chainID)
contractID := testutils.NewAddress()
- relayer := Relayer{lggr: lggr, chain: chain}
+ relayer := Relayer{lggr: logger.Sugared(lggr), chain: chain}
pargs := commontypes.PluginArgs{}
diff --git a/core/services/relay/evm/mercury/config_poller.go b/core/services/relay/evm/mercury/config_poller.go
index 2da541a8e42..e93ad339cea 100644
--- a/core/services/relay/evm/mercury/config_poller.go
+++ b/core/services/relay/evm/mercury/config_poller.go
@@ -11,9 +11,10 @@ import (
"github.com/pkg/errors"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils"
)
diff --git a/core/services/relay/evm/mercury/persistence_manager.go b/core/services/relay/evm/mercury/persistence_manager.go
index d7f3d8eaa0d..dfe75e7c3ce 100644
--- a/core/services/relay/evm/mercury/persistence_manager.go
+++ b/core/services/relay/evm/mercury/persistence_manager.go
@@ -7,9 +7,10 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb"
)
@@ -39,7 +40,7 @@ type PersistenceManager struct {
func NewPersistenceManager(lggr logger.Logger, serverURL string, orm ORM, jobID int32, maxTransmitQueueSize int, flushDeletesFrequency, pruneFrequency time.Duration) *PersistenceManager {
return &PersistenceManager{
- lggr: lggr.Named("MercuryPersistenceManager").With("serverURL", serverURL),
+ lggr: logger.Sugared(lggr).Named("MercuryPersistenceManager").With("serverURL", serverURL),
orm: orm,
serverURL: serverURL,
stopCh: make(services.StopChan),
diff --git a/core/services/relay/evm/mercury/queue.go b/core/services/relay/evm/mercury/queue.go
index 8b39be72a68..a450d21af6e 100644
--- a/core/services/relay/evm/mercury/queue.go
+++ b/core/services/relay/evm/mercury/queue.go
@@ -13,9 +13,9 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb"
)
@@ -42,7 +42,7 @@ type transmitQueue struct {
services.StateMachine
cond sync.Cond
- lggr logger.Logger
+ lggr logger.SugaredLogger
asyncDeleter asyncDeleter
mu *sync.RWMutex
@@ -76,7 +76,7 @@ func NewTransmitQueue(lggr logger.Logger, serverURL, feedID string, maxlen int,
return &transmitQueue{
services.StateMachine{},
sync.Cond{L: mu},
- lggr.Named("TransmitQueue"),
+ logger.Sugared(lggr).Named("TransmitQueue"),
asyncDeleter,
mu,
nil, // pq needs to be initialized by calling tq.Init before use
diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go
index f1434bf20f1..b914e67b453 100644
--- a/core/services/relay/evm/mercury/transmitter.go
+++ b/core/services/relay/evm/mercury/transmitter.go
@@ -27,10 +27,10 @@ import (
capStreams "github.com/smartcontractkit/chainlink-common/pkg/capabilities/datastreams"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers"
commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/types/mercury"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb"
@@ -110,7 +110,7 @@ type TransmitterConfig interface {
type mercuryTransmitter struct {
services.StateMachine
- lggr logger.Logger
+ lggr logger.SugaredLogger
cfg TransmitterConfig
orm ORM
@@ -147,7 +147,7 @@ func getPayloadTypes() abi.Arguments {
}
type server struct {
- lggr logger.Logger
+ lggr logger.SugaredLogger
transmitTimeout time.Duration
@@ -285,7 +285,7 @@ func (s *server) runQueueLoop(stopCh services.StopChan, wg *sync.WaitGroup, feed
func newServer(lggr logger.Logger, cfg TransmitterConfig, client wsrpc.Client, pm *PersistenceManager, serverURL, feedIDHex string) *server {
return &server{
- lggr,
+ logger.Sugared(lggr),
cfg.TransmitTimeout().Duration(),
client,
pm,
@@ -302,16 +302,17 @@ func newServer(lggr logger.Logger, cfg TransmitterConfig, client wsrpc.Client, p
}
func NewTransmitter(lggr logger.Logger, cfg TransmitterConfig, clients map[string]wsrpc.Client, fromAccount ed25519.PublicKey, jobID int32, feedID [32]byte, orm ORM, codec TransmitterReportDecoder, triggerCapability *triggers.MercuryTriggerService) *mercuryTransmitter {
+ sugared := logger.Sugared(lggr)
feedIDHex := fmt.Sprintf("0x%x", feedID[:])
servers := make(map[string]*server, len(clients))
for serverURL, client := range clients {
- cLggr := lggr.Named(serverURL).With("serverURL", serverURL)
+ cLggr := sugared.Named(serverURL).With("serverURL", serverURL)
pm := NewPersistenceManager(cLggr, serverURL, orm, jobID, int(cfg.TransmitQueueMaxSize()), flushDeletesFrequency, pruneFrequency)
servers[serverURL] = newServer(cLggr, cfg, client, pm, serverURL, feedIDHex)
}
return &mercuryTransmitter{
services.StateMachine{},
- lggr.Named("MercuryTransmitter").With("feedID", feedIDHex),
+ sugared.Named("MercuryTransmitter").With("feedID", feedIDHex),
cfg,
orm,
servers,
diff --git a/core/services/relay/evm/mercury/utils/feeds.go b/core/services/relay/evm/mercury/utils/feeds.go
index 6f8978bbf0d..36d6bc60f58 100644
--- a/core/services/relay/evm/mercury/utils/feeds.go
+++ b/core/services/relay/evm/mercury/utils/feeds.go
@@ -83,6 +83,7 @@ const (
REPORT_V1
REPORT_V2
REPORT_V3
+ REPORT_V4
_
)
@@ -110,3 +111,4 @@ func (f FeedID) Version() FeedVersion {
func (f FeedID) IsV1() bool { return f.Version() == REPORT_V1 }
func (f FeedID) IsV2() bool { return f.Version() == REPORT_V2 }
func (f FeedID) IsV3() bool { return f.Version() == REPORT_V3 }
+func (f FeedID) IsV4() bool { return f.Version() == REPORT_V4 }
diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go
index f4c6af32b8e..fb332dcc8ff 100644
--- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go
+++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go
@@ -11,8 +11,9 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils"
reporttypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/types"
)
diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go
index 33c5fa9a326..ebbdfac66cd 100644
--- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go
+++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go
@@ -9,9 +9,9 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils"
reporttypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/types"
)
diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go
index 601431838d2..1bf750fbf97 100644
--- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go
+++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go
@@ -9,9 +9,9 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils"
reporttypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/types"
)
diff --git a/core/services/relay/evm/mercury/v4/data_source.go b/core/services/relay/evm/mercury/v4/data_source.go
new file mode 100644
index 00000000000..f9c2c2d5de0
--- /dev/null
+++ b/core/services/relay/evm/mercury/v4/data_source.go
@@ -0,0 +1,290 @@
+package v4
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "math/big"
+ "sync"
+
+ pkgerrors "github.com/pkg/errors"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types/mercury"
+ v4types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4"
+ v4 "github.com/smartcontractkit/chainlink-data-streams/mercury/v4"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/job"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
+ "github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types"
+ mercurytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/types"
+ mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v4/reportcodec"
+ "github.com/smartcontractkit/chainlink/v2/core/utils"
+)
+
+type Runner interface {
+ ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error)
+}
+
+type LatestReportFetcher interface {
+ LatestPrice(ctx context.Context, feedID [32]byte) (*big.Int, error)
+ LatestTimestamp(context.Context) (int64, error)
+}
+
+type datasource struct {
+ pipelineRunner Runner
+ jb job.Job
+ spec pipeline.Spec
+ feedID mercuryutils.FeedID
+ lggr logger.Logger
+ saver ocrcommon.Saver
+ orm types.DataSourceORM
+ codec reportcodec.ReportCodec
+
+ fetcher LatestReportFetcher
+ linkFeedID mercuryutils.FeedID
+ nativeFeedID mercuryutils.FeedID
+
+ mu sync.RWMutex
+
+ chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData
+}
+
+var _ v4.DataSource = &datasource{}
+
+func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource {
+ return &datasource{pr, jb, spec, feedID, lggr, s, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan}
+}
+
+func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs v4types.Observation, pipelineExecutionErr error) {
+ var wg sync.WaitGroup
+ ctx, cancel := context.WithCancel(ctx)
+
+ if fetchMaxFinalizedTimestamp {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ latest, dbErr := ds.orm.LatestReport(ctx, ds.feedID)
+ if dbErr != nil {
+ obs.MaxFinalizedTimestamp.Err = dbErr
+ return
+ }
+ if latest != nil {
+ maxFinalizedBlockNumber, decodeErr := ds.codec.ObservationTimestampFromReport(latest)
+ obs.MaxFinalizedTimestamp.Val, obs.MaxFinalizedTimestamp.Err = int64(maxFinalizedBlockNumber), decodeErr
+ return
+ }
+ obs.MaxFinalizedTimestamp.Val, obs.MaxFinalizedTimestamp.Err = ds.fetcher.LatestTimestamp(ctx)
+ }()
+ }
+
+ var trrs pipeline.TaskRunResults
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ var run *pipeline.Run
+ run, trrs, pipelineExecutionErr = ds.executeRun(ctx)
+ if pipelineExecutionErr != nil {
+ cancel()
+ pipelineExecutionErr = fmt.Errorf("Observe failed while executing run: %w", pipelineExecutionErr)
+ return
+ }
+
+ ds.saver.Save(run)
+
+ var parsed parseOutput
+ parsed, pipelineExecutionErr = ds.parse(trrs)
+ if pipelineExecutionErr != nil {
+ cancel()
+ // This is not expected under normal circumstances
+ ds.lggr.Errorw("Observe failed while parsing run results", "err", pipelineExecutionErr)
+ pipelineExecutionErr = fmt.Errorf("Observe failed while parsing run results: %w", pipelineExecutionErr)
+ return
+ }
+ obs.BenchmarkPrice = parsed.benchmarkPrice
+ obs.Bid = parsed.bid
+ obs.Ask = parsed.ask
+ obs.MarketStatus = parsed.marketStatus
+ }()
+
+ var isLink, isNative bool
+ if ds.feedID == ds.linkFeedID {
+ isLink = true
+ } else {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ obs.LinkPrice.Val, obs.LinkPrice.Err = ds.fetcher.LatestPrice(ctx, ds.linkFeedID)
+ if obs.LinkPrice.Val == nil && obs.LinkPrice.Err == nil {
+ mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.linkFeedID.String()).Inc()
+ ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", v4.MissingPrice), "linkFeedID", ds.linkFeedID)
+ obs.LinkPrice.Val = v4.MissingPrice
+ } else if obs.LinkPrice.Err != nil {
+ mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.linkFeedID.String()).Inc()
+ ds.lggr.Errorw("Mercury server returned error querying LINK price feed", "err", obs.LinkPrice.Err, "linkFeedID", ds.linkFeedID)
+ }
+ }()
+ }
+
+ if ds.feedID == ds.nativeFeedID {
+ isNative = true
+ } else {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ obs.NativePrice.Val, obs.NativePrice.Err = ds.fetcher.LatestPrice(ctx, ds.nativeFeedID)
+ if obs.NativePrice.Val == nil && obs.NativePrice.Err == nil {
+ mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.nativeFeedID.String()).Inc()
+ ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", v4.MissingPrice), "nativeFeedID", ds.nativeFeedID)
+ obs.NativePrice.Val = v4.MissingPrice
+ } else if obs.NativePrice.Err != nil {
+ mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.nativeFeedID.String()).Inc()
+ ds.lggr.Errorw("Mercury server returned error querying native price feed", "err", obs.NativePrice.Err, "nativeFeedID", ds.nativeFeedID)
+ }
+ }()
+ }
+
+ wg.Wait()
+ cancel()
+
+ if pipelineExecutionErr != nil {
+ return
+ }
+
+ if isLink || isNative {
+ // run has now completed so it is safe to use benchmark price
+ if isLink {
+ // This IS the LINK feed, use our observed price
+ obs.LinkPrice.Val, obs.LinkPrice.Err = obs.BenchmarkPrice.Val, obs.BenchmarkPrice.Err
+ }
+ if isNative {
+ // This IS the native feed, use our observed price
+ obs.NativePrice.Val, obs.NativePrice.Err = obs.BenchmarkPrice.Val, obs.BenchmarkPrice.Err
+ }
+ }
+
+ ocrcommon.MaybeEnqueueEnhancedTelem(ds.jb, ds.chEnhancedTelem, ocrcommon.EnhancedTelemetryMercuryData{
+ V4Observation: &obs,
+ TaskRunResults: trrs,
+ RepTimestamp: repts,
+ FeedVersion: mercuryutils.REPORT_V4,
+ FetchMaxFinalizedTimestamp: fetchMaxFinalizedTimestamp,
+ IsLinkFeed: isLink,
+ IsNativeFeed: isNative,
+ })
+
+ return obs, nil
+}
+
+func toBigInt(val interface{}) (*big.Int, error) {
+ dec, err := utils.ToDecimal(val)
+ if err != nil {
+ return nil, err
+ }
+ return dec.BigInt(), nil
+}
+
+type parseOutput struct {
+ benchmarkPrice mercury.ObsResult[*big.Int]
+ bid mercury.ObsResult[*big.Int]
+ ask mercury.ObsResult[*big.Int]
+ marketStatus mercury.ObsResult[uint32]
+}
+
+func (ds *datasource) parse(trrs pipeline.TaskRunResults) (o parseOutput, merr error) {
+ var finaltrrs []pipeline.TaskRunResult
+ for _, trr := range trrs {
+ // only return terminal trrs from executeRun
+ if trr.IsTerminal() {
+ finaltrrs = append(finaltrrs, trr)
+ }
+ }
+
+ // pipeline.TaskRunResults comes ordered asc by index, this is guaranteed
+ // by the pipeline executor
+ if len(finaltrrs) != 4 {
+ return o, fmt.Errorf("invalid number of results, expected: 4, got: %d", len(finaltrrs))
+ }
+
+ merr = errors.Join(
+ setBenchmarkPrice(&o, finaltrrs[0].Result),
+ setBid(&o, finaltrrs[1].Result),
+ setAsk(&o, finaltrrs[2].Result),
+ setMarketStatus(&o, finaltrrs[3].Result),
+ )
+
+ return o, merr
+}
+
+func setBenchmarkPrice(o *parseOutput, res pipeline.Result) error {
+ if res.Error != nil {
+ o.benchmarkPrice.Err = res.Error
+ return res.Error
+ }
+ val, err := toBigInt(res.Value)
+ if err != nil {
+ return fmt.Errorf("failed to parse BenchmarkPrice: %w", err)
+ }
+ o.benchmarkPrice.Val = val
+ return nil
+}
+
+func setBid(o *parseOutput, res pipeline.Result) error {
+ if res.Error != nil {
+ o.bid.Err = res.Error
+ return res.Error
+ }
+ val, err := toBigInt(res.Value)
+ if err != nil {
+ return fmt.Errorf("failed to parse Bid: %w", err)
+ }
+ o.bid.Val = val
+ return nil
+}
+
+func setAsk(o *parseOutput, res pipeline.Result) error {
+ if res.Error != nil {
+ o.ask.Err = res.Error
+ return res.Error
+ }
+ val, err := toBigInt(res.Value)
+ if err != nil {
+ return fmt.Errorf("failed to parse Ask: %w", err)
+ }
+ o.ask.Val = val
+ return nil
+}
+
+func setMarketStatus(o *parseOutput, res pipeline.Result) error {
+ if res.Error != nil {
+ o.marketStatus.Err = res.Error
+ return res.Error
+ }
+ val, err := toBigInt(res.Value)
+ if err != nil {
+ return fmt.Errorf("failed to parse MarketStatus: %w", err)
+ }
+ o.marketStatus.Val = uint32(val.Int64())
+ return nil
+}
+
+// The context passed in here has a timeout of (ObservationTimeout + ObservationGracePeriod).
+// Upon context cancellation, its expected that we return any usable values within ObservationGracePeriod.
+func (ds *datasource) executeRun(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) {
+ vars := pipeline.NewVarsFrom(map[string]interface{}{
+ "jb": map[string]interface{}{
+ "databaseID": ds.jb.ID,
+ "externalJobID": ds.jb.ExternalJobID,
+ "name": ds.jb.Name.ValueOrZero(),
+ },
+ })
+
+ run, trrs, err := ds.pipelineRunner.ExecuteRun(ctx, ds.spec, vars)
+ if err != nil {
+ return nil, nil, pkgerrors.Wrapf(err, "error executing run for spec ID %v", ds.spec.ID)
+ }
+
+ return run, trrs, err
+}
diff --git a/core/services/relay/evm/mercury/v4/data_source_test.go b/core/services/relay/evm/mercury/v4/data_source_test.go
new file mode 100644
index 00000000000..bce9c3c6088
--- /dev/null
+++ b/core/services/relay/evm/mercury/v4/data_source_test.go
@@ -0,0 +1,349 @@
+package v4
+
+import (
+ "context"
+ "math/big"
+ "testing"
+
+ "github.com/pkg/errors"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/stretchr/testify/assert"
+
+ mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury"
+ relaymercuryv4 "github.com/smartcontractkit/chainlink-data-streams/mercury/v4"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+ "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
+ mercurymocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils"
+ reportcodecv4 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v4/reportcodec"
+)
+
+var _ mercurytypes.ServerFetcher = &mockFetcher{}
+
+type mockFetcher struct {
+ ts int64
+ tsErr error
+ linkPrice *big.Int
+ linkPriceErr error
+ nativePrice *big.Int
+ nativePriceErr error
+}
+
+var feedId utils.FeedID = [32]byte{1}
+var linkFeedId utils.FeedID = [32]byte{2}
+var nativeFeedId utils.FeedID = [32]byte{3}
+
+func (m *mockFetcher) FetchInitialMaxFinalizedBlockNumber(context.Context) (*int64, error) {
+ return nil, nil
+}
+
+func (m *mockFetcher) LatestPrice(ctx context.Context, fId [32]byte) (*big.Int, error) {
+ if fId == linkFeedId {
+ return m.linkPrice, m.linkPriceErr
+ } else if fId == nativeFeedId {
+ return m.nativePrice, m.nativePriceErr
+ }
+ return nil, nil
+}
+
+func (m *mockFetcher) LatestTimestamp(context.Context) (int64, error) {
+ return m.ts, m.tsErr
+}
+
+type mockORM struct {
+ report []byte
+ err error
+}
+
+func (m *mockORM) LatestReport(ctx context.Context, feedID [32]byte) (report []byte, err error) {
+ return m.report, m.err
+}
+
+type mockSaver struct {
+ r *pipeline.Run
+}
+
+func (ms *mockSaver) Save(r *pipeline.Run) {
+ ms.r = r
+}
+
+func Test_Datasource(t *testing.T) {
+ orm := &mockORM{}
+ ds := &datasource{orm: orm, lggr: logger.TestLogger(t)}
+ ctx := testutils.Context(t)
+ repts := ocrtypes.ReportTimestamp{}
+
+ fetcher := &mockFetcher{}
+ ds.fetcher = fetcher
+
+ saver := &mockSaver{}
+ ds.saver = saver
+
+ goodTrrs := []pipeline.TaskRunResult{
+ {
+ // bp
+ Result: pipeline.Result{Value: "122.345"},
+ Task: &mercurymocks.MockTask{},
+ },
+ {
+ // bid
+ Result: pipeline.Result{Value: "121.993"},
+ Task: &mercurymocks.MockTask{},
+ },
+ {
+ // ask
+ Result: pipeline.Result{Value: "123.111"},
+ Task: &mercurymocks.MockTask{},
+ },
+ {
+ // marketStatus
+ Result: pipeline.Result{Value: "1"},
+ Task: &mercurymocks.MockTask{},
+ },
+ }
+
+ ds.pipelineRunner = &mercurymocks.MockRunner{
+ Trrs: goodTrrs,
+ }
+
+ spec := pipeline.Spec{}
+ ds.spec = spec
+
+ t.Run("when fetchMaxFinalizedTimestamp=true", func(t *testing.T) {
+ t.Run("with latest report in database", func(t *testing.T) {
+ orm.report = buildSamplev4Report()
+ orm.err = nil
+
+ obs, err := ds.Observe(ctx, repts, true)
+ assert.NoError(t, err)
+
+ assert.NoError(t, obs.MaxFinalizedTimestamp.Err)
+ assert.Equal(t, int64(124), obs.MaxFinalizedTimestamp.Val)
+ })
+ t.Run("if querying latest report fails", func(t *testing.T) {
+ orm.report = nil
+ orm.err = errors.New("something exploded")
+
+ obs, err := ds.Observe(ctx, repts, true)
+ assert.NoError(t, err)
+
+ assert.EqualError(t, obs.MaxFinalizedTimestamp.Err, "something exploded")
+ assert.Zero(t, obs.MaxFinalizedTimestamp.Val)
+ })
+ t.Run("if codec fails to decode", func(t *testing.T) {
+ orm.report = []byte{1, 2, 3}
+ orm.err = nil
+
+ obs, err := ds.Observe(ctx, repts, true)
+ assert.NoError(t, err)
+
+ assert.EqualError(t, obs.MaxFinalizedTimestamp.Err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32")
+ assert.Zero(t, obs.MaxFinalizedTimestamp.Val)
+ })
+
+ orm.report = nil
+ orm.err = nil
+
+ t.Run("if LatestTimestamp returns error", func(t *testing.T) {
+ fetcher.tsErr = errors.New("some error")
+
+ obs, err := ds.Observe(ctx, repts, true)
+ assert.NoError(t, err)
+
+ assert.EqualError(t, obs.MaxFinalizedTimestamp.Err, "some error")
+ assert.Zero(t, obs.MaxFinalizedTimestamp.Val)
+ })
+
+ t.Run("if LatestTimestamp succeeds", func(t *testing.T) {
+ fetcher.tsErr = nil
+ fetcher.ts = 123
+
+ obs, err := ds.Observe(ctx, repts, true)
+ assert.NoError(t, err)
+
+ assert.Equal(t, int64(123), obs.MaxFinalizedTimestamp.Val)
+ assert.NoError(t, obs.MaxFinalizedTimestamp.Err)
+ })
+
+ t.Run("if LatestTimestamp succeeds but ts=0 (new feed)", func(t *testing.T) {
+ fetcher.tsErr = nil
+ fetcher.ts = 0
+
+ obs, err := ds.Observe(ctx, repts, true)
+ assert.NoError(t, err)
+
+ assert.NoError(t, obs.MaxFinalizedTimestamp.Err)
+ assert.Zero(t, obs.MaxFinalizedTimestamp.Val)
+ })
+
+ t.Run("when run execution succeeded", func(t *testing.T) {
+ t.Run("when feedId=linkFeedID=nativeFeedId", func(t *testing.T) {
+ t.Cleanup(func() {
+ ds.feedID, ds.linkFeedID, ds.nativeFeedID = feedId, linkFeedId, nativeFeedId
+ })
+
+ ds.feedID, ds.linkFeedID, ds.nativeFeedID = feedId, feedId, feedId
+
+ fetcher.ts = 123123
+ fetcher.tsErr = nil
+
+ obs, err := ds.Observe(ctx, repts, true)
+ assert.NoError(t, err)
+
+ assert.Equal(t, big.NewInt(122), obs.BenchmarkPrice.Val)
+ assert.NoError(t, obs.BenchmarkPrice.Err)
+ assert.Equal(t, big.NewInt(121), obs.Bid.Val)
+ assert.NoError(t, obs.Bid.Err)
+ assert.Equal(t, big.NewInt(123), obs.Ask.Val)
+ assert.NoError(t, obs.Ask.Err)
+ assert.Equal(t, int64(123123), obs.MaxFinalizedTimestamp.Val)
+ assert.NoError(t, obs.MaxFinalizedTimestamp.Err)
+ assert.Equal(t, big.NewInt(122), obs.LinkPrice.Val)
+ assert.NoError(t, obs.LinkPrice.Err)
+ assert.Equal(t, big.NewInt(122), obs.NativePrice.Val)
+ assert.NoError(t, obs.NativePrice.Err)
+ assert.Equal(t, uint32(1), obs.MarketStatus.Val)
+ assert.NoError(t, obs.MarketStatus.Err)
+ })
+ })
+ })
+
+ t.Run("when fetchMaxFinalizedTimestamp=false", func(t *testing.T) {
+ t.Run("when run execution fails, returns error", func(t *testing.T) {
+ t.Cleanup(func() {
+ ds.pipelineRunner = &mercurymocks.MockRunner{
+ Trrs: goodTrrs,
+ Err: nil,
+ }
+ })
+
+ ds.pipelineRunner = &mercurymocks.MockRunner{
+ Trrs: goodTrrs,
+ Err: errors.New("run execution failed"),
+ }
+
+ _, err := ds.Observe(ctx, repts, false)
+ assert.EqualError(t, err, "Observe failed while executing run: error executing run for spec ID 0: run execution failed")
+ })
+
+ t.Run("when parsing run results fails, return error", func(t *testing.T) {
+ t.Cleanup(func() {
+ runner := &mercurymocks.MockRunner{
+ Trrs: goodTrrs,
+ Err: nil,
+ }
+ ds.pipelineRunner = runner
+ })
+
+ badTrrs := []pipeline.TaskRunResult{
+ {
+ // benchmark price
+ Result: pipeline.Result{Value: "122.345"},
+ Task: &mercurymocks.MockTask{},
+ },
+ {
+ // bid
+ Result: pipeline.Result{Value: "121.993"},
+ Task: &mercurymocks.MockTask{},
+ },
+ {
+ // ask
+ Result: pipeline.Result{Error: errors.New("some error with ask")},
+ Task: &mercurymocks.MockTask{},
+ },
+ {
+ // marketStatus
+ Result: pipeline.Result{Value: "1"},
+ Task: &mercurymocks.MockTask{},
+ },
+ }
+
+ ds.pipelineRunner = &mercurymocks.MockRunner{
+ Trrs: badTrrs,
+ Err: nil,
+ }
+
+ _, err := ds.Observe(ctx, repts, false)
+ assert.EqualError(t, err, "Observe failed while parsing run results: some error with ask")
+ })
+
+ t.Run("when run execution succeeded", func(t *testing.T) {
+ t.Run("when feedId=linkFeedID=nativeFeedId", func(t *testing.T) {
+ t.Cleanup(func() {
+ ds.feedID, ds.linkFeedID, ds.nativeFeedID = feedId, linkFeedId, nativeFeedId
+ })
+
+ var feedId utils.FeedID = [32]byte{1}
+ ds.feedID, ds.linkFeedID, ds.nativeFeedID = feedId, feedId, feedId
+
+ obs, err := ds.Observe(ctx, repts, false)
+ assert.NoError(t, err)
+
+ assert.Equal(t, big.NewInt(122), obs.BenchmarkPrice.Val)
+ assert.NoError(t, obs.BenchmarkPrice.Err)
+ assert.Equal(t, big.NewInt(121), obs.Bid.Val)
+ assert.NoError(t, obs.Bid.Err)
+ assert.Equal(t, big.NewInt(123), obs.Ask.Val)
+ assert.NoError(t, obs.Ask.Err)
+ assert.Equal(t, int64(0), obs.MaxFinalizedTimestamp.Val)
+ assert.NoError(t, obs.MaxFinalizedTimestamp.Err)
+ assert.Equal(t, big.NewInt(122), obs.LinkPrice.Val)
+ assert.NoError(t, obs.LinkPrice.Err)
+ assert.Equal(t, big.NewInt(122), obs.NativePrice.Val)
+ assert.NoError(t, obs.NativePrice.Err)
+ assert.Equal(t, uint32(1), obs.MarketStatus.Val)
+ assert.NoError(t, obs.MarketStatus.Err)
+ })
+
+ t.Run("when fails to fetch linkPrice or nativePrice", func(t *testing.T) {
+ t.Cleanup(func() {
+ fetcher.linkPriceErr = nil
+ fetcher.nativePriceErr = nil
+ })
+
+ fetcher.linkPriceErr = errors.New("some error fetching link price")
+ fetcher.nativePriceErr = errors.New("some error fetching native price")
+
+ obs, err := ds.Observe(ctx, repts, false)
+ assert.NoError(t, err)
+
+ assert.Nil(t, obs.LinkPrice.Val)
+ assert.EqualError(t, obs.LinkPrice.Err, "some error fetching link price")
+ assert.Nil(t, obs.NativePrice.Val)
+ assert.EqualError(t, obs.NativePrice.Err, "some error fetching native price")
+ })
+
+ t.Run("when succeeds to fetch linkPrice or nativePrice but got nil (new feed)", func(t *testing.T) {
+ obs, err := ds.Observe(ctx, repts, false)
+ assert.NoError(t, err)
+
+ assert.Equal(t, obs.LinkPrice.Val, relaymercuryv4.MissingPrice)
+ assert.Nil(t, obs.LinkPrice.Err)
+ assert.Equal(t, obs.NativePrice.Val, relaymercuryv4.MissingPrice)
+ assert.Nil(t, obs.NativePrice.Err)
+ })
+ })
+ })
+}
+
+var sampleFeedID = [32]uint8{28, 145, 107, 74, 167, 229, 124, 167, 182, 138, 225, 191, 69, 101, 63, 86, 182, 86, 253, 58, 163, 53, 239, 127, 174, 105, 107, 102, 63, 27, 132, 114}
+
+func buildSamplev4Report() []byte {
+ feedID := sampleFeedID
+ timestamp := uint32(124)
+ bp := big.NewInt(242)
+ bid := big.NewInt(243)
+ ask := big.NewInt(244)
+ validFromTimestamp := uint32(123)
+ expiresAt := uint32(456)
+ linkFee := big.NewInt(3334455)
+ nativeFee := big.NewInt(556677)
+ marketStatus := uint32(1)
+
+ b, err := reportcodecv4.ReportTypes.Pack(feedID, validFromTimestamp, timestamp, nativeFee, linkFee, expiresAt, bp, bid, ask, marketStatus)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
diff --git a/core/services/relay/evm/mercury/v4/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v4/reportcodec/report_codec.go
new file mode 100644
index 00000000000..9c4cb0e509e
--- /dev/null
+++ b/core/services/relay/evm/mercury/v4/reportcodec/report_codec.go
@@ -0,0 +1,83 @@
+package reportcodec
+
+import (
+ "errors"
+ "fmt"
+ "math/big"
+
+ pkgerrors "github.com/pkg/errors"
+ ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ v4 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4"
+
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils"
+ reporttypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v4/types"
+)
+
+var ReportTypes = reporttypes.GetSchema()
+var maxReportLength = 32 * len(ReportTypes) // each arg is 256 bit EVM word
+var zero = big.NewInt(0)
+
+var _ v4.ReportCodec = &ReportCodec{}
+
+type ReportCodec struct {
+ logger logger.Logger
+ feedID utils.FeedID
+}
+
+func NewReportCodec(feedID [32]byte, lggr logger.Logger) *ReportCodec {
+ return &ReportCodec{lggr, feedID}
+}
+
+func (r *ReportCodec) BuildReport(rf v4.ReportFields) (ocrtypes.Report, error) {
+ var merr error
+ if rf.BenchmarkPrice == nil {
+ merr = errors.Join(merr, errors.New("benchmarkPrice may not be nil"))
+ }
+ if rf.Bid == nil {
+ merr = errors.Join(merr, errors.New("bid may not be nil"))
+ }
+ if rf.Ask == nil {
+ merr = errors.Join(merr, errors.New("ask may not be nil"))
+ }
+ if rf.LinkFee == nil {
+ merr = errors.Join(merr, errors.New("linkFee may not be nil"))
+ } else if rf.LinkFee.Cmp(zero) < 0 {
+ merr = errors.Join(merr, fmt.Errorf("linkFee may not be negative (got: %s)", rf.LinkFee))
+ }
+ if rf.NativeFee == nil {
+ merr = errors.Join(merr, errors.New("nativeFee may not be nil"))
+ } else if rf.NativeFee.Cmp(zero) < 0 {
+ merr = errors.Join(merr, fmt.Errorf("nativeFee may not be negative (got: %s)", rf.NativeFee))
+ }
+ if merr != nil {
+ return nil, merr
+ }
+ reportBytes, err := ReportTypes.Pack(r.feedID, rf.ValidFromTimestamp, rf.Timestamp, rf.NativeFee, rf.LinkFee, rf.ExpiresAt, rf.BenchmarkPrice, rf.Bid, rf.Ask, rf.MarketStatus)
+ return ocrtypes.Report(reportBytes), pkgerrors.Wrap(err, "failed to pack report blob")
+}
+
+func (r *ReportCodec) MaxReportLength(n int) (int, error) {
+ return maxReportLength, nil
+}
+
+func (r *ReportCodec) ObservationTimestampFromReport(report ocrtypes.Report) (uint32, error) {
+ decoded, err := r.Decode(report)
+ if err != nil {
+ return 0, err
+ }
+ return decoded.ObservationsTimestamp, nil
+}
+
+func (r *ReportCodec) Decode(report ocrtypes.Report) (*reporttypes.Report, error) {
+ return reporttypes.Decode(report)
+}
+
+func (r *ReportCodec) BenchmarkPriceFromReport(report ocrtypes.Report) (*big.Int, error) {
+ decoded, err := r.Decode(report)
+ if err != nil {
+ return nil, err
+ }
+ return decoded.BenchmarkPrice, nil
+}
diff --git a/core/services/relay/evm/mercury/v4/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v4/reportcodec/report_codec_test.go
new file mode 100644
index 00000000000..b62f42ef575
--- /dev/null
+++ b/core/services/relay/evm/mercury/v4/reportcodec/report_codec_test.go
@@ -0,0 +1,163 @@
+package reportcodec
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ v4 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4"
+)
+
+func newValidReportFields() v4.ReportFields {
+ return v4.ReportFields{
+ Timestamp: 242,
+ BenchmarkPrice: big.NewInt(243),
+ Bid: big.NewInt(244),
+ Ask: big.NewInt(245),
+ ValidFromTimestamp: 123,
+ ExpiresAt: 20,
+ LinkFee: big.NewInt(456),
+ NativeFee: big.NewInt(457),
+ MarketStatus: 1,
+ }
+}
+
+func Test_ReportCodec_BuildReport(t *testing.T) {
+ r := ReportCodec{}
+
+ t.Run("BuildReport errors on zero values", func(t *testing.T) {
+ _, err := r.BuildReport(v4.ReportFields{})
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "benchmarkPrice may not be nil")
+ assert.Contains(t, err.Error(), "linkFee may not be nil")
+ assert.Contains(t, err.Error(), "nativeFee may not be nil")
+ })
+
+ t.Run("BuildReport constructs a report from observations", func(t *testing.T) {
+ rf := newValidReportFields()
+ // only need to test happy path since validations are done in relaymercury
+
+ report, err := r.BuildReport(rf)
+ require.NoError(t, err)
+
+ reportElems := make(map[string]interface{})
+ err = ReportTypes.UnpackIntoMap(reportElems, report)
+ require.NoError(t, err)
+
+ assert.Equal(t, int(reportElems["observationsTimestamp"].(uint32)), 242)
+ assert.Equal(t, reportElems["benchmarkPrice"].(*big.Int).Int64(), int64(243))
+ assert.Equal(t, reportElems["bid"].(*big.Int).Int64(), int64(244))
+ assert.Equal(t, reportElems["ask"].(*big.Int).Int64(), int64(245))
+ assert.Equal(t, reportElems["validFromTimestamp"].(uint32), uint32(123))
+ assert.Equal(t, reportElems["expiresAt"].(uint32), uint32(20))
+ assert.Equal(t, reportElems["linkFee"].(*big.Int).Int64(), int64(456))
+ assert.Equal(t, reportElems["nativeFee"].(*big.Int).Int64(), int64(457))
+ assert.Equal(t, reportElems["marketStatus"].(uint32), uint32(1))
+
+ assert.Equal(t, types.Report{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xc9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0xc8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}, report)
+ max, err := r.MaxReportLength(4)
+ require.NoError(t, err)
+ assert.LessOrEqual(t, len(report), max)
+
+ t.Run("Decode decodes the report", func(t *testing.T) {
+ decoded, err := r.Decode(report)
+ require.NoError(t, err)
+
+ require.NotNil(t, decoded)
+
+ assert.Equal(t, uint32(242), decoded.ObservationsTimestamp)
+ assert.Equal(t, big.NewInt(243), decoded.BenchmarkPrice)
+ assert.Equal(t, big.NewInt(244), decoded.Bid)
+ assert.Equal(t, big.NewInt(245), decoded.Ask)
+ assert.Equal(t, uint32(123), decoded.ValidFromTimestamp)
+ assert.Equal(t, uint32(20), decoded.ExpiresAt)
+ assert.Equal(t, big.NewInt(456), decoded.LinkFee)
+ assert.Equal(t, big.NewInt(457), decoded.NativeFee)
+ assert.Equal(t, uint32(1), decoded.MarketStatus)
+ })
+ })
+
+ t.Run("errors on negative fee", func(t *testing.T) {
+ rf := newValidReportFields()
+ rf.LinkFee = big.NewInt(-1)
+ rf.NativeFee = big.NewInt(-1)
+ _, err := r.BuildReport(rf)
+ require.Error(t, err)
+
+ assert.Contains(t, err.Error(), "linkFee may not be negative (got: -1)")
+ assert.Contains(t, err.Error(), "nativeFee may not be negative (got: -1)")
+ })
+
+ t.Run("Decode errors on invalid report", func(t *testing.T) {
+ _, err := r.Decode([]byte{1, 2, 3})
+ assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32")
+
+ longBad := make([]byte, 64)
+ for i := 0; i < len(longBad); i++ {
+ longBad[i] = byte(i)
+ }
+ _, err = r.Decode(longBad)
+ assert.EqualError(t, err, "failed to decode report: abi: improperly encoded uint32 value")
+ })
+}
+
+func buildSampleReport(ts int64) []byte {
+ feedID := [32]byte{'f', 'o', 'o'}
+ timestamp := uint32(ts)
+ bp := big.NewInt(242)
+ bid := big.NewInt(243)
+ ask := big.NewInt(244)
+ validFromTimestamp := uint32(123)
+ expiresAt := uint32(456)
+ linkFee := big.NewInt(3334455)
+ nativeFee := big.NewInt(556677)
+ marketStatus := uint32(1)
+
+ b, err := ReportTypes.Pack(feedID, validFromTimestamp, timestamp, nativeFee, linkFee, expiresAt, bp, bid, ask, marketStatus)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+func Test_ReportCodec_ObservationTimestampFromReport(t *testing.T) {
+ r := ReportCodec{}
+
+ t.Run("ObservationTimestampFromReport extracts observation timestamp from a valid report", func(t *testing.T) {
+ report := buildSampleReport(123)
+
+ ts, err := r.ObservationTimestampFromReport(report)
+ require.NoError(t, err)
+
+ assert.Equal(t, ts, uint32(123))
+ })
+ t.Run("ObservationTimestampFromReport returns error when report is invalid", func(t *testing.T) {
+ report := []byte{1, 2, 3}
+
+ _, err := r.ObservationTimestampFromReport(report)
+ require.Error(t, err)
+
+ assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32")
+ })
+}
+
+func Test_ReportCodec_BenchmarkPriceFromReport(t *testing.T) {
+ r := ReportCodec{}
+
+ t.Run("BenchmarkPriceFromReport extracts the benchmark price from valid report", func(t *testing.T) {
+ report := buildSampleReport(123)
+
+ bp, err := r.BenchmarkPriceFromReport(report)
+ require.NoError(t, err)
+
+ assert.Equal(t, big.NewInt(242), bp)
+ })
+ t.Run("BenchmarkPriceFromReport errors on invalid report", func(t *testing.T) {
+ _, err := r.BenchmarkPriceFromReport([]byte{1, 2, 3})
+ require.Error(t, err)
+ assert.EqualError(t, err, "failed to decode report: abi: cannot marshal in to go type: length insufficient 3 require 32")
+ })
+}
diff --git a/core/services/relay/evm/mercury/v4/types/types.go b/core/services/relay/evm/mercury/v4/types/types.go
new file mode 100644
index 00000000000..3abdd262a65
--- /dev/null
+++ b/core/services/relay/evm/mercury/v4/types/types.go
@@ -0,0 +1,58 @@
+package reporttypes
+
+import (
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+)
+
+var schema = GetSchema()
+
+func GetSchema() abi.Arguments {
+ mustNewType := func(t string) abi.Type {
+ result, err := abi.NewType(t, "", []abi.ArgumentMarshaling{})
+ if err != nil {
+ panic(fmt.Sprintf("Unexpected error during abi.NewType: %s", err))
+ }
+ return result
+ }
+ return abi.Arguments([]abi.Argument{
+ {Name: "feedId", Type: mustNewType("bytes32")},
+ {Name: "validFromTimestamp", Type: mustNewType("uint32")},
+ {Name: "observationsTimestamp", Type: mustNewType("uint32")},
+ {Name: "nativeFee", Type: mustNewType("uint192")},
+ {Name: "linkFee", Type: mustNewType("uint192")},
+ {Name: "expiresAt", Type: mustNewType("uint32")},
+ {Name: "benchmarkPrice", Type: mustNewType("int192")},
+ {Name: "bid", Type: mustNewType("int192")},
+ {Name: "ask", Type: mustNewType("int192")},
+ {Name: "marketStatus", Type: mustNewType("uint32")},
+ })
+}
+
+type Report struct {
+ FeedId [32]byte
+ ObservationsTimestamp uint32
+ BenchmarkPrice *big.Int
+ Bid *big.Int
+ Ask *big.Int
+ ValidFromTimestamp uint32
+ ExpiresAt uint32
+ LinkFee *big.Int
+ NativeFee *big.Int
+ MarketStatus uint32
+}
+
+// Decode is made available to external users (i.e. mercury server)
+func Decode(report []byte) (*Report, error) {
+ values, err := schema.Unpack(report)
+ if err != nil {
+ return nil, fmt.Errorf("failed to decode report: %w", err)
+ }
+ decoded := new(Report)
+ if err = schema.Copy(decoded, values); err != nil {
+ return nil, fmt.Errorf("failed to copy report values to struct: %w", err)
+ }
+ return decoded, nil
+}
diff --git a/core/services/relay/evm/mercury_config_provider.go b/core/services/relay/evm/mercury_config_provider.go
index bd0749e5ae2..349650c0fc3 100644
--- a/core/services/relay/evm/mercury_config_provider.go
+++ b/core/services/relay/evm/mercury_config_provider.go
@@ -7,10 +7,10 @@ import (
"github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
@@ -31,7 +31,7 @@ func newMercuryConfigProvider(ctx context.Context, lggr logger.Logger, chain leg
}
cp, err := mercury.NewConfigPoller(
ctx,
- lggr.Named(relayConfig.FeedID.String()),
+ logger.Named(lggr, relayConfig.FeedID.String()),
chain.LogPoller(),
aggregatorAddress,
*relayConfig.FeedID,
diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go
index 48882b701c9..58806e3dd73 100644
--- a/core/services/relay/evm/mercury_provider.go
+++ b/core/services/relay/evm/mercury_provider.go
@@ -6,17 +6,18 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
-
mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury"
v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1"
v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2"
v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3"
+ v4 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4"
+
"github.com/smartcontractkit/chainlink-data-streams/mercury"
httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
evmmercury "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury"
)
@@ -30,6 +31,7 @@ type mercuryProvider struct {
reportCodecV1 v1.ReportCodec
reportCodecV2 v2.ReportCodec
reportCodecV3 v3.ReportCodec
+ reportCodecV4 v4.ReportCodec
mercuryChainReader mercurytypes.ChainReader
logger logger.Logger
ms services.MultiStart
@@ -44,6 +46,7 @@ func NewMercuryProvider(
reportCodecV1 v1.ReportCodec,
reportCodecV2 v2.ReportCodec,
reportCodecV3 v3.ReportCodec,
+ reportCodecV4 v4.ReportCodec,
lggr logger.Logger,
) *mercuryProvider {
return &mercuryProvider{
@@ -54,6 +57,7 @@ func NewMercuryProvider(
reportCodecV1,
reportCodecV2,
reportCodecV3,
+ reportCodecV4,
mercuryChainReader,
lggr,
services.MultiStart{},
@@ -115,6 +119,10 @@ func (p *mercuryProvider) ReportCodecV3() v3.ReportCodec {
return p.reportCodecV3
}
+func (p *mercuryProvider) ReportCodecV4() v4.ReportCodec {
+ return p.reportCodecV4
+}
+
func (p *mercuryProvider) ContractTransmitter() ocrtypes.ContractTransmitter {
return p.transmitter
}
diff --git a/core/services/relay/evm/method_binding.go b/core/services/relay/evm/method_binding.go
index 448f1b9fbf2..9ff57fd9342 100644
--- a/core/services/relay/evm/method_binding.go
+++ b/core/services/relay/evm/method_binding.go
@@ -8,14 +8,14 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
- "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/logger"
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
+ evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types"
)
type NoContractExistsError struct {
diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go
index b2d19c11702..2300f54b6ec 100644
--- a/core/services/relay/evm/ocr2keeper.go
+++ b/core/services/relay/evm/ocr2keeper.go
@@ -13,6 +13,7 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
"github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/automation"
@@ -20,7 +21,6 @@ import (
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"
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"
@@ -218,7 +218,7 @@ func newOCR2KeeperConfigProvider(ctx context.Context, lggr logger.Logger, chain
configPoller, err := NewConfigPoller(
ctx,
- lggr.With("contractID", rargs.ContractID),
+ logger.With(lggr, "contractID", rargs.ContractID),
CPConfig{
chain.Client(),
chain.LogPoller(),
diff --git a/core/services/relay/evm/plugin_provider.go b/core/services/relay/evm/plugin_provider.go
index ffcea48db2c..58bfc1e525a 100644
--- a/core/services/relay/evm/plugin_provider.go
+++ b/core/services/relay/evm/plugin_provider.go
@@ -5,10 +5,9 @@ import (
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/types"
-
- "github.com/smartcontractkit/chainlink/v2/core/logger"
)
type pluginProvider struct {
diff --git a/core/services/relay/evm/request_round_db.go b/core/services/relay/evm/request_round_db.go
index 1aa3dfd7471..07a2d1cbc3b 100644
--- a/core/services/relay/evm/request_round_db.go
+++ b/core/services/relay/evm/request_round_db.go
@@ -8,8 +8,8 @@ import (
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
)
// RequestRoundDB stores requested rounds for querying by the median plugin.
diff --git a/core/services/relay/evm/request_round_tracker.go b/core/services/relay/evm/request_round_tracker.go
index 7cf13775693..b9200fff757 100644
--- a/core/services/relay/evm/request_round_tracker.go
+++ b/core/services/relay/evm/request_round_tracker.go
@@ -12,13 +12,13 @@ import (
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/sqlutil"
evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/log"
offchain_aggregator_wrapper "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon"
)
diff --git a/core/services/relay/evm/standard_config_provider.go b/core/services/relay/evm/standard_config_provider.go
index 59f91c52f4a..91ca25413fa 100644
--- a/core/services/relay/evm/standard_config_provider.go
+++ b/core/services/relay/evm/standard_config_provider.go
@@ -10,8 +10,9 @@ import (
"github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
diff --git a/core/services/relay/evm/statuschecker/mocks/ccip_transaction_status_checker.go b/core/services/relay/evm/statuschecker/mocks/ccip_transaction_status_checker.go
new file mode 100644
index 00000000000..9bd59ccf4ef
--- /dev/null
+++ b/core/services/relay/evm/statuschecker/mocks/ccip_transaction_status_checker.go
@@ -0,0 +1,104 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package mocks
+
+import (
+ context "context"
+
+ mock "github.com/stretchr/testify/mock"
+
+ types "github.com/smartcontractkit/chainlink-common/pkg/types"
+)
+
+// CCIPTransactionStatusChecker is an autogenerated mock type for the CCIPTransactionStatusChecker type
+type CCIPTransactionStatusChecker struct {
+ mock.Mock
+}
+
+type CCIPTransactionStatusChecker_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *CCIPTransactionStatusChecker) EXPECT() *CCIPTransactionStatusChecker_Expecter {
+ return &CCIPTransactionStatusChecker_Expecter{mock: &_m.Mock}
+}
+
+// CheckMessageStatus provides a mock function with given fields: ctx, msgID
+func (_m *CCIPTransactionStatusChecker) CheckMessageStatus(ctx context.Context, msgID string) ([]types.TransactionStatus, int, error) {
+ ret := _m.Called(ctx, msgID)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CheckMessageStatus")
+ }
+
+ var r0 []types.TransactionStatus
+ var r1 int
+ var r2 error
+ if rf, ok := ret.Get(0).(func(context.Context, string) ([]types.TransactionStatus, int, error)); ok {
+ return rf(ctx, msgID)
+ }
+ if rf, ok := ret.Get(0).(func(context.Context, string) []types.TransactionStatus); ok {
+ r0 = rf(ctx, msgID)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]types.TransactionStatus)
+ }
+ }
+
+ if rf, ok := ret.Get(1).(func(context.Context, string) int); ok {
+ r1 = rf(ctx, msgID)
+ } else {
+ r1 = ret.Get(1).(int)
+ }
+
+ if rf, ok := ret.Get(2).(func(context.Context, string) error); ok {
+ r2 = rf(ctx, msgID)
+ } else {
+ r2 = ret.Error(2)
+ }
+
+ return r0, r1, r2
+}
+
+// CCIPTransactionStatusChecker_CheckMessageStatus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckMessageStatus'
+type CCIPTransactionStatusChecker_CheckMessageStatus_Call struct {
+ *mock.Call
+}
+
+// CheckMessageStatus is a helper method to define mock.On call
+// - ctx context.Context
+// - msgID string
+func (_e *CCIPTransactionStatusChecker_Expecter) CheckMessageStatus(ctx interface{}, msgID interface{}) *CCIPTransactionStatusChecker_CheckMessageStatus_Call {
+ return &CCIPTransactionStatusChecker_CheckMessageStatus_Call{Call: _e.mock.On("CheckMessageStatus", ctx, msgID)}
+}
+
+func (_c *CCIPTransactionStatusChecker_CheckMessageStatus_Call) Run(run func(ctx context.Context, msgID string)) *CCIPTransactionStatusChecker_CheckMessageStatus_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(string))
+ })
+ return _c
+}
+
+func (_c *CCIPTransactionStatusChecker_CheckMessageStatus_Call) Return(transactionStatuses []types.TransactionStatus, retryCounter int, err error) *CCIPTransactionStatusChecker_CheckMessageStatus_Call {
+ _c.Call.Return(transactionStatuses, retryCounter, err)
+ return _c
+}
+
+func (_c *CCIPTransactionStatusChecker_CheckMessageStatus_Call) RunAndReturn(run func(context.Context, string) ([]types.TransactionStatus, int, error)) *CCIPTransactionStatusChecker_CheckMessageStatus_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewCCIPTransactionStatusChecker creates a new instance of CCIPTransactionStatusChecker. 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 NewCCIPTransactionStatusChecker(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *CCIPTransactionStatusChecker {
+ mock := &CCIPTransactionStatusChecker{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/relay/evm/statuschecker/txm_status_checker.go b/core/services/relay/evm/statuschecker/txm_status_checker.go
new file mode 100644
index 00000000000..f22e6d78b9f
--- /dev/null
+++ b/core/services/relay/evm/statuschecker/txm_status_checker.go
@@ -0,0 +1,54 @@
+package statuschecker
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+)
+
+// CCIPTransactionStatusChecker is an interface that defines the method for checking the status of a transaction.
+// CheckMessageStatus checks the status of a transaction for a given message ID.
+// It returns a list of transaction statuses, the retry counter, and an error if any occurred during the process.
+//
+
+type CCIPTransactionStatusChecker interface {
+ CheckMessageStatus(ctx context.Context, msgID string) (transactionStatuses []types.TransactionStatus, retryCounter int, err error)
+}
+
+type TxmStatusChecker struct {
+ getTransactionStatus func(ctx context.Context, transactionID string) (types.TransactionStatus, error)
+}
+
+func NewTxmStatusChecker(getTransactionStatus func(ctx context.Context, transactionID string) (types.TransactionStatus, error)) *TxmStatusChecker {
+ return &TxmStatusChecker{getTransactionStatus: getTransactionStatus}
+}
+
+// CheckMessageStatus checks the status of a message by checking the status of all transactions associated with the message ID.
+// It returns a slice of all statuses and the number of transactions found (-1 if none).
+// The key will follow the format: -. TXM will be queried for each key until a NotFound error is returned.
+// The goal is to find all transactions associated with a message ID and snooze messages if they are fatal in the Execution Plugin.
+func (tsc *TxmStatusChecker) CheckMessageStatus(ctx context.Context, msgID string) ([]types.TransactionStatus, int, error) {
+ var counter int
+ const maxStatuses = 1000 // Cap the number of statuses to avoid infinite loop
+
+ allStatuses := make([]types.TransactionStatus, 0)
+
+ for {
+ transactionID := fmt.Sprintf("%s-%d", msgID, counter)
+ status, err := tsc.getTransactionStatus(ctx, transactionID)
+ if err != nil && status == types.Unknown {
+ // If the status is unknown and err not nil, it means the transaction was not found
+ break
+ }
+ allStatuses = append(allStatuses, status)
+ counter++
+
+ // Break the loop if the cap is reached
+ if counter >= maxStatuses {
+ return allStatuses, counter - 1, fmt.Errorf("maximum number of statuses reached, possible infinite loop")
+ }
+ }
+
+ return allStatuses, counter - 1, nil
+}
diff --git a/core/services/relay/evm/statuschecker/txm_status_checker_test.go b/core/services/relay/evm/statuschecker/txm_status_checker_test.go
new file mode 100644
index 00000000000..456d07e7a7d
--- /dev/null
+++ b/core/services/relay/evm/statuschecker/txm_status_checker_test.go
@@ -0,0 +1,103 @@
+package statuschecker
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/types"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
+)
+
+func Test_CheckMessageStatus(t *testing.T) {
+ testutils.SkipShort(t, "")
+ ctx := context.Background()
+ mockTxManager := mocks.NewMockEvmTxManager(t)
+ checker := NewTxmStatusChecker(mockTxManager.GetTransactionStatus)
+
+ msgID := "test-message-id"
+
+ // Define test cases
+ testCases := []struct {
+ name string
+ setupMock func()
+ expectedStatus []types.TransactionStatus
+ expectedCounter int
+ expectedError error
+ }{
+ {
+ name: "No transactions found",
+ setupMock: func() {
+ mockTxManager.Mock = mock.Mock{}
+ mockTxManager.On("GetTransactionStatus", ctx, "test-message-id-0").Return(types.Unknown, errors.New("failed to find transaction with IdempotencyKey test-message-id-0"))
+ },
+ expectedStatus: []types.TransactionStatus{},
+ expectedCounter: -1,
+ expectedError: nil,
+ },
+ {
+ name: "Single transaction found",
+ setupMock: func() {
+ mockTxManager.Mock = mock.Mock{}
+ mockTxManager.On("GetTransactionStatus", ctx, "test-message-id-0").Return(types.Finalized, nil)
+ mockTxManager.On("GetTransactionStatus", ctx, "test-message-id-1").Return(types.Unknown, errors.New("failed to find transaction with IdempotencyKey test-message-id-1"))
+ },
+ expectedStatus: []types.TransactionStatus{types.Finalized},
+ expectedCounter: 0,
+ expectedError: nil,
+ },
+ {
+ name: "Multiple transactions found",
+ setupMock: func() {
+ mockTxManager.Mock = mock.Mock{}
+ mockTxManager.On("GetTransactionStatus", ctx, "test-message-id-0").Return(types.Finalized, nil)
+ mockTxManager.On("GetTransactionStatus", ctx, "test-message-id-1").Return(types.Failed, nil)
+ mockTxManager.On("GetTransactionStatus", ctx, "test-message-id-2").Return(types.Unknown, errors.New("failed to find transaction with IdempotencyKey test-message-id-2"))
+ },
+ expectedStatus: []types.TransactionStatus{types.Finalized, types.Failed},
+ expectedCounter: 1,
+ expectedError: nil,
+ },
+ {
+ name: "Unknown status without nil (in progress)",
+ setupMock: func() {
+ mockTxManager.Mock = mock.Mock{}
+ mockTxManager.On("GetTransactionStatus", ctx, "test-message-id-0").Return(types.Unknown, nil)
+ mockTxManager.On("GetTransactionStatus", ctx, "test-message-id-1").Return(types.Unknown, errors.New("failed to find transaction with IdempotencyKey test-message-id-1"))
+ },
+ expectedStatus: []types.TransactionStatus{types.Unknown},
+ expectedCounter: 0,
+ expectedError: nil,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ tc.setupMock()
+ statuses, counter, err := checker.CheckMessageStatus(ctx, msgID)
+ assert.Equal(t, tc.expectedStatus, statuses)
+ assert.Equal(t, tc.expectedCounter, counter)
+ assert.Equal(t, tc.expectedError, err)
+ mockTxManager.AssertExpectations(t)
+ })
+ }
+}
+
+func Test_FailForMoreThan1000Retries(t *testing.T) {
+ ctx := context.Background()
+ mockTxManager := mocks.NewMockEvmTxManager(t)
+ checker := NewTxmStatusChecker(mockTxManager.GetTransactionStatus)
+
+ for i := 0; i < 1000; i++ {
+ mockTxManager.On("GetTransactionStatus", ctx, fmt.Sprintf("test-message-id-%d", i)).Return(types.Finalized, nil)
+ }
+
+ msgID := "test-message-id"
+ _, _, err := checker.CheckMessageStatus(ctx, msgID)
+ assert.EqualError(t, err, "maximum number of statuses reached, possible infinite loop")
+}
diff --git a/core/services/relay/evm/types/codec_entry.go b/core/services/relay/evm/types/codec_entry.go
index 38242c43a2d..9a8103cf7f9 100644
--- a/core/services/relay/evm/types/codec_entry.go
+++ b/core/services/relay/evm/types/codec_entry.go
@@ -200,7 +200,7 @@ func getNativeAndCheckedTypesForArg(arg *abi.Argument) (reflect.Type, reflect.Ty
return reflect.TypeOf(common.Hash{}), reflect.TypeOf(common.Hash{}), nil
}
fallthrough
- case abi.SliceTy, abi.TupleTy, abi.FixedBytesTy, abi.FixedPointTy, abi.FunctionTy:
+ case abi.SliceTy, abi.TupleTy, abi.FixedPointTy, abi.FunctionTy:
// https://github.com/ethereum/go-ethereum/blob/release/1.12/accounts/abi/topics.go#L78
return nil, nil, fmt.Errorf("%w: unsupported indexed type: %v", commontypes.ErrInvalidConfig, arg.Type)
default:
diff --git a/core/services/relay/evm/types/codec_entry_test.go b/core/services/relay/evm/types/codec_entry_test.go
index 06b08fcecf2..64e0998716a 100644
--- a/core/services/relay/evm/types/codec_entry_test.go
+++ b/core/services/relay/evm/types/codec_entry_test.go
@@ -273,17 +273,27 @@ func TestCodecEntry(t *testing.T) {
assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType())
})
- t.Run("Indexed non basic types change to hash", func(t *testing.T) {
- anyType, err := abi.NewType("string", "", []abi.ArgumentMarshaling{})
+ t.Run("Indexed string and bytes array change to hash", func(t *testing.T) {
+ stringType, err := abi.NewType("string", "", []abi.ArgumentMarshaling{})
require.NoError(t, err)
- entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, nil)
- require.NoError(t, entry.Init())
- nativeField, ok := entry.CheckedType().FieldByName("Name")
- require.True(t, ok)
- assert.Equal(t, reflect.TypeOf(&common.Hash{}), nativeField.Type)
- native, err := entry.ToNative(reflect.New(entry.CheckedType()))
+ arrayType, err := abi.NewType("uint8[32]", "", []abi.ArgumentMarshaling{})
require.NoError(t, err)
- assertHaveSameStructureAndNames(t, native.Type().Elem(), entry.CheckedType())
+
+ abiArgs := abi.Arguments{
+ {Name: "String", Type: stringType, Indexed: true},
+ {Name: "Array", Type: arrayType, Indexed: true},
+ }
+
+ for i := 0; i < len(abiArgs); i++ {
+ entry := NewCodecEntry(abi.Arguments{abiArgs[i]}, nil, nil)
+ require.NoError(t, entry.Init())
+ nativeField, ok := entry.CheckedType().FieldByName(abiArgs[i].Name)
+ require.True(t, ok)
+ assert.Equal(t, reflect.TypeOf(&common.Hash{}), nativeField.Type)
+ native, err := entry.ToNative(reflect.New(entry.CheckedType()))
+ require.NoError(t, err)
+ assertHaveSameStructureAndNames(t, native.Type().Elem(), entry.CheckedType())
+ }
})
t.Run("Too many indexed items returns an error", func(t *testing.T) {
diff --git a/core/services/relay/evm/write_target.go b/core/services/relay/evm/write_target.go
index fb1c694a2e7..699c5013eaa 100644
--- a/core/services/relay/evm/write_target.go
+++ b/core/services/relay/evm/write_target.go
@@ -7,10 +7,11 @@ import (
chainselectors "github.com/smartcontractkit/chain-selectors"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+
"github.com/smartcontractkit/chainlink/v2/core/capabilities/targets"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/forwarder"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
relayevmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)
@@ -31,8 +32,8 @@ func NewWriteTarget(ctx context.Context, relayer *Relayer, chain legacyevm.Chain
"forwarder": {
ContractABI: forwarder.KeystoneForwarderABI,
Configs: map[string]*relayevmtypes.ChainReaderDefinition{
- "getTransmitter": {
- ChainSpecificName: "getTransmitter",
+ "getTransmissionInfo": {
+ ChainSpecificName: "getTransmissionInfo",
},
},
},
@@ -46,6 +47,7 @@ func NewWriteTarget(ctx context.Context, relayer *Relayer, chain legacyevm.Chain
return nil, err
}
+ var gasLimit uint64 = 400_000
chainWriterConfig := relayevmtypes.ChainWriterConfig{
Contracts: map[string]*relayevmtypes.ContractConfig{
"forwarder": {
@@ -55,7 +57,7 @@ func NewWriteTarget(ctx context.Context, relayer *Relayer, chain legacyevm.Chain
ChainSpecificName: "report",
Checker: "simulate",
FromAddress: config.FromAddress().Address(),
- GasLimit: 200_000,
+ GasLimit: gasLimit,
},
},
},
@@ -73,5 +75,5 @@ func NewWriteTarget(ctx context.Context, relayer *Relayer, chain legacyevm.Chain
return nil, err
}
- return targets.NewWriteTarget(lggr, id, cr, cw, config.ForwarderAddress().String()), nil
+ return targets.NewWriteTarget(logger.Named(lggr, "WriteTarget"), id, cr, cw, config.ForwarderAddress().String(), gasLimit), nil
}
diff --git a/core/services/relay/evm/write_target_test.go b/core/services/relay/evm/write_target_test.go
index f3dcae220eb..54e36714226 100644
--- a/core/services/relay/evm/write_target_test.go
+++ b/core/services/relay/evm/write_target_test.go
@@ -1,7 +1,10 @@
package evm_test
import (
+ "bytes"
+ "encoding/hex"
"errors"
+ "fmt"
"math/big"
"testing"
@@ -9,6 +12,7 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/values"
"github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks"
+ "github.com/smartcontractkit/chainlink/v2/core/capabilities/targets"
"github.com/smartcontractkit/chainlink/v2/core/internal/cltest"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
@@ -36,16 +40,72 @@ import (
var forwardABI = types.MustGetABI(forwarder.KeystoneForwarderMetaData.ABI)
+func newMockedEncodeTransmissionInfo() ([]byte, error) {
+ info := targets.TransmissionInfo{
+ GasLimit: big.NewInt(0),
+ InvalidReceiver: false,
+ State: 0,
+ Success: false,
+ TransmissionId: [32]byte{},
+ Transmitter: common.HexToAddress("0x0"),
+ }
+
+ var buffer bytes.Buffer
+ gasLimitBytes := info.GasLimit.Bytes()
+ if len(gasLimitBytes) > 80 {
+ return nil, fmt.Errorf("GasLimit too large")
+ }
+ paddedGasLimit := make([]byte, 80-len(gasLimitBytes))
+ buffer.Write(paddedGasLimit)
+ buffer.Write(gasLimitBytes)
+
+ // Encode InvalidReceiver (as uint8)
+ if info.InvalidReceiver {
+ buffer.WriteByte(1)
+ } else {
+ buffer.WriteByte(0)
+ }
+
+ // Padding for InvalidReceiver to fit into 32 bytes
+ padInvalidReceiver := make([]byte, 31)
+ buffer.Write(padInvalidReceiver)
+
+ // Encode State (as uint8)
+ buffer.WriteByte(info.State)
+
+ // Padding for State to fit into 32 bytes
+ padState := make([]byte, 31)
+ buffer.Write(padState)
+
+ // Encode Success (as uint8)
+ if info.Success {
+ buffer.WriteByte(1)
+ } else {
+ buffer.WriteByte(0)
+ }
+
+ // Padding for Success to fit into 32 bytes
+ padSuccess := make([]byte, 31)
+ buffer.Write(padSuccess)
+
+ // Encode TransmissionId (as bytes32)
+ buffer.Write(info.TransmissionId[:])
+
+ // Encode Transmitter (as address)
+ buffer.Write(info.Transmitter.Bytes())
+
+ return buffer.Bytes(), nil
+}
+
func TestEvmWrite(t *testing.T) {
chain := evmmocks.NewChain(t)
txManager := txmmocks.NewMockEvmTxManager(t)
evmClient := evmclimocks.NewClient(t)
- // This probably isn't the best way to do this, but couldn't find a simpler way to mock the CallContract response
- var mockCall []byte
- for i := 0; i < 32; i++ {
- mockCall = append(mockCall, byte(0))
- }
+ // This is a very error-prone way to mock an on-chain response to a GetLatestValue("getTransmissionInfo") call
+ // It's a bit of a hack, but it's the best way to do it without a lot of refactoring
+ mockCall, err := newMockedEncodeTransmissionInfo()
+ require.NoError(t, err)
evmClient.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(mockCall, nil).Maybe()
evmClient.On("CodeAt", mock.Anything, mock.Anything, mock.Anything).Return([]byte("test"), nil)
@@ -87,14 +147,53 @@ func TestEvmWrite(t *testing.T) {
})
require.NoError(t, err)
+ reportMetadata := targets.ReportV1Metadata{
+ Version: 1,
+ WorkflowExecutionID: [32]byte{},
+ Timestamp: 0,
+ DonID: 0,
+ DonConfigVersion: 0,
+ WorkflowCID: [32]byte{},
+ WorkflowName: [10]byte{},
+ WorkflowOwner: [20]byte{},
+ ReportID: [2]byte{},
+ }
+
+ reportMetadataBytes, err := reportMetadata.Encode()
+ require.NoError(t, err)
+
+ signatures := [][]byte{}
+
+ validInputs, err := values.NewMap(map[string]any{
+ "signed_report": map[string]any{
+ "report": reportMetadataBytes,
+ "signatures": signatures,
+ "context": []byte{4, 5},
+ "id": []byte{9, 9},
+ },
+ })
+ require.NoError(t, err)
+
+ validMetadata := capabilities.RequestMetadata{
+ WorkflowID: hex.EncodeToString(reportMetadata.WorkflowCID[:]),
+ WorkflowOwner: hex.EncodeToString(reportMetadata.WorkflowOwner[:]),
+ WorkflowName: hex.EncodeToString(reportMetadata.WorkflowName[:]),
+ WorkflowExecutionID: hex.EncodeToString(reportMetadata.WorkflowExecutionID[:]),
+ }
+
+ validConfig, err := values.NewMap(map[string]any{
+ "Address": evmCfg.EVM().Workflow().ForwarderAddress().String(),
+ })
+ require.NoError(t, err)
+
txManager.On("CreateTransaction", mock.Anything, mock.Anything).Return(txmgr.Tx{}, nil).Run(func(args mock.Arguments) {
req := args.Get(1).(txmgr.TxRequest)
payload := make(map[string]any)
method := forwardABI.Methods["report"]
err = method.Inputs.UnpackIntoMap(payload, req.EncodedPayload[4:])
require.NoError(t, err)
- require.Equal(t, []byte{0x1, 0x2, 0x3}, payload["rawReport"])
- require.Equal(t, [][]byte{}, payload["signatures"])
+ require.Equal(t, reportMetadataBytes, payload["rawReport"])
+ require.Equal(t, signatures, payload["signatures"])
}).Once()
t.Run("succeeds with valid report", func(t *testing.T) {
@@ -102,59 +201,10 @@ func TestEvmWrite(t *testing.T) {
capability, err := evm.NewWriteTarget(ctx, relayer, chain, lggr)
require.NoError(t, err)
- config, err := values.NewMap(map[string]any{
- "Address": evmCfg.EVM().Workflow().ForwarderAddress().String(),
- })
- require.NoError(t, err)
-
- inputs, err := values.NewMap(map[string]any{
- "signed_report": map[string]any{
- "report": []byte{1, 2, 3},
- "signatures": [][]byte{},
- "context": []byte{4, 5},
- "id": []byte{9, 9},
- },
- })
- require.NoError(t, err)
-
- req := capabilities.CapabilityRequest{
- Metadata: capabilities.RequestMetadata{
- WorkflowID: "test-id",
- },
- Config: config,
- Inputs: inputs,
- }
-
- ch, err := capability.Execute(ctx, req)
- require.NoError(t, err)
-
- response := <-ch
- require.Nil(t, response.Err)
- })
-
- t.Run("succeeds with empty report", func(t *testing.T) {
- ctx := testutils.Context(t)
- capability, err := evm.NewWriteTarget(ctx, relayer, chain, logger.TestLogger(t))
- require.NoError(t, err)
-
- config, err := values.NewMap(map[string]any{
- "Address": evmCfg.EVM().Workflow().ForwarderAddress().String(),
- })
- require.NoError(t, err)
-
- inputs, err := values.NewMap(map[string]any{
- "signed_report": map[string]any{
- "report": nil,
- },
- })
- require.NoError(t, err)
-
req := capabilities.CapabilityRequest{
- Metadata: capabilities.RequestMetadata{
- WorkflowID: "test-id",
- },
- Config: config,
- Inputs: inputs,
+ Metadata: validMetadata,
+ Config: validConfig,
+ Inputs: validInputs,
}
ch, err := capability.Execute(ctx, req)
@@ -174,19 +224,10 @@ func TestEvmWrite(t *testing.T) {
})
require.NoError(t, err)
- inputs, err := values.NewMap(map[string]any{
- "signed_report": map[string]any{
- "report": nil,
- },
- })
- require.NoError(t, err)
-
req := capabilities.CapabilityRequest{
- Metadata: capabilities.RequestMetadata{
- WorkflowID: "test-id",
- },
- Config: invalidConfig,
- Inputs: inputs,
+ Metadata: validMetadata,
+ Config: invalidConfig,
+ Inputs: validInputs,
}
_, err = capability.Execute(ctx, req)
@@ -198,27 +239,10 @@ func TestEvmWrite(t *testing.T) {
capability, err := evm.NewWriteTarget(ctx, relayer, chain, logger.TestLogger(t))
require.NoError(t, err)
- config, err := values.NewMap(map[string]any{
- "Address": evmCfg.EVM().Workflow().ForwarderAddress().String(),
- })
- require.NoError(t, err)
-
- inputs, err := values.NewMap(map[string]any{
- "signed_report": map[string]any{
- "report": []byte{1, 2, 3},
- "signatures": [][]byte{},
- "context": []byte{4, 5},
- "id": []byte{9, 9},
- },
- })
- require.NoError(t, err)
-
req := capabilities.CapabilityRequest{
- Metadata: capabilities.RequestMetadata{
- WorkflowID: "test-id",
- },
- Config: config,
- Inputs: inputs,
+ Metadata: validMetadata,
+ Config: validConfig,
+ Inputs: validInputs,
}
txManager.On("CreateTransaction", mock.Anything, mock.Anything).Return(txmgr.Tx{}, errors.New("TXM error"))
diff --git a/core/services/synchronization/common.go b/core/services/synchronization/common.go
index 5f469c055d4..a6c0191e3a7 100644
--- a/core/services/synchronization/common.go
+++ b/core/services/synchronization/common.go
@@ -16,12 +16,19 @@ const (
OCR TelemetryType = "ocr"
OCR2Automation TelemetryType = "ocr2-automation"
OCR2Functions TelemetryType = "ocr2-functions"
+ OCR2CCIPCommit TelemetryType = "ocr2-ccip-commit"
+ OCR2CCIPExec TelemetryType = "ocr2-ccip-exec"
OCR2Threshold TelemetryType = "ocr2-threshold"
OCR2S4 TelemetryType = "ocr2-s4"
OCR2Median TelemetryType = "ocr2-median"
OCR3Mercury TelemetryType = "ocr3-mercury"
AutomationCustom TelemetryType = "automation-custom"
OCR3Automation TelemetryType = "ocr3-automation"
+ OCR3Rebalancer TelemetryType = "ocr3-rebalancer"
+ OCR3CCIPCommit TelemetryType = "ocr3-ccip-commit"
+ OCR3CCIPExec TelemetryType = "ocr3-ccip-exec"
+ OCR3CCIPBootstrap TelemetryType = "ocr3-bootstrap"
+ HeadReport TelemetryType = "head-report"
)
type TelemPayload struct {
diff --git a/core/services/synchronization/helpers_test.go b/core/services/synchronization/helpers_test.go
index 7bb2dde7633..aea9bf77f49 100644
--- a/core/services/synchronization/helpers_test.go
+++ b/core/services/synchronization/helpers_test.go
@@ -12,15 +12,15 @@ import (
// NewTestTelemetryIngressClient calls NewTelemetryIngressClient and injects telemClient.
func NewTestTelemetryIngressClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient) TelemetryService {
- tc := NewTelemetryIngressClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100, "test", "test")
+ tc := NewTelemetryIngressClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100)
tc.(*telemetryIngressClient).telemClient = telemClient
return tc
}
// NewTestTelemetryIngressBatchClient calls NewTelemetryIngressBatchClient and injects telemClient.
func NewTestTelemetryIngressBatchClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient, sendInterval time.Duration, uniconn bool) TelemetryService {
- tc := NewTelemetryIngressBatchClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100, 50, sendInterval, time.Second, uniconn, "test", "test")
- tc.(*telemetryIngressBatchClient).close = func() error { return nil }
+ tc := NewTelemetryIngressBatchClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100, 50, sendInterval, time.Second, uniconn)
+ tc.(*telemetryIngressBatchClient).closeFn = func() error { return nil }
tc.(*telemetryIngressBatchClient).telemClient = telemClient
return tc
}
diff --git a/core/services/synchronization/telem/telem.pb.go b/core/services/synchronization/telem/telem.pb.go
index e1945bc26d3..d51b9628e22 100644
--- a/core/services/synchronization/telem/telem.pb.go
+++ b/core/services/synchronization/telem/telem.pb.go
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.34.1
+// protoc-gen-go v1.34.2
// protoc v4.25.1
// source: core/services/synchronization/telem/telem.proto
@@ -264,7 +264,7 @@ func file_core_services_synchronization_telem_telem_proto_rawDescGZIP() []byte {
}
var file_core_services_synchronization_telem_telem_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
-var file_core_services_synchronization_telem_telem_proto_goTypes = []interface{}{
+var file_core_services_synchronization_telem_telem_proto_goTypes = []any{
(*TelemRequest)(nil), // 0: telem.TelemRequest
(*TelemBatchRequest)(nil), // 1: telem.TelemBatchRequest
(*TelemResponse)(nil), // 2: telem.TelemResponse
@@ -287,7 +287,7 @@ func file_core_services_synchronization_telem_telem_proto_init() {
return
}
if !protoimpl.UnsafeEnabled {
- file_core_services_synchronization_telem_telem_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*TelemRequest); i {
case 0:
return &v.state
@@ -299,7 +299,7 @@ func file_core_services_synchronization_telem_telem_proto_init() {
return nil
}
}
- file_core_services_synchronization_telem_telem_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*TelemBatchRequest); i {
case 0:
return &v.state
@@ -311,7 +311,7 @@ func file_core_services_synchronization_telem_telem_proto_init() {
return nil
}
}
- file_core_services_synchronization_telem_telem_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*TelemResponse); i {
case 0:
return &v.state
diff --git a/core/services/synchronization/telem/telem_automation_custom.pb.go b/core/services/synchronization/telem/telem_automation_custom.pb.go
index a53339eda05..30ddce6f790 100644
--- a/core/services/synchronization/telem/telem_automation_custom.pb.go
+++ b/core/services/synchronization/telem/telem_automation_custom.pb.go
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.34.1
+// protoc-gen-go v1.34.2
// protoc v4.25.1
// source: core/services/synchronization/telem/telem_automation_custom.proto
@@ -289,7 +289,7 @@ func file_core_services_synchronization_telem_telem_automation_custom_proto_rawD
}
var file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
-var file_core_services_synchronization_telem_telem_automation_custom_proto_goTypes = []interface{}{
+var file_core_services_synchronization_telem_telem_automation_custom_proto_goTypes = []any{
(*BlockNumber)(nil), // 0: telem.BlockNumber
(*NodeVersion)(nil), // 1: telem.NodeVersion
(*AutomationTelemWrapper)(nil), // 2: telem.AutomationTelemWrapper
@@ -310,7 +310,7 @@ func file_core_services_synchronization_telem_telem_automation_custom_proto_init
return
}
if !protoimpl.UnsafeEnabled {
- file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*BlockNumber); i {
case 0:
return &v.state
@@ -322,7 +322,7 @@ func file_core_services_synchronization_telem_telem_automation_custom_proto_init
return nil
}
}
- file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes[1].Exporter = func(v any, i int) any {
switch v := v.(*NodeVersion); i {
case 0:
return &v.state
@@ -334,7 +334,7 @@ func file_core_services_synchronization_telem_telem_automation_custom_proto_init
return nil
}
}
- file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*AutomationTelemWrapper); i {
case 0:
return &v.state
@@ -347,7 +347,7 @@ func file_core_services_synchronization_telem_telem_automation_custom_proto_init
}
}
}
- file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes[2].OneofWrappers = []interface{}{
+ file_core_services_synchronization_telem_telem_automation_custom_proto_msgTypes[2].OneofWrappers = []any{
(*AutomationTelemWrapper_BlockNumber)(nil),
(*AutomationTelemWrapper_NodeVersion)(nil),
}
diff --git a/core/services/synchronization/telem/telem_enhanced_ea.pb.go b/core/services/synchronization/telem/telem_enhanced_ea.pb.go
index a9a81dabfcc..c8983a06fea 100644
--- a/core/services/synchronization/telem/telem_enhanced_ea.pb.go
+++ b/core/services/synchronization/telem/telem_enhanced_ea.pb.go
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.34.1
+// protoc-gen-go v1.34.2
// protoc v4.25.1
// source: core/services/synchronization/telem/telem_enhanced_ea.proto
@@ -239,7 +239,7 @@ func file_core_services_synchronization_telem_telem_enhanced_ea_proto_rawDescGZI
}
var file_core_services_synchronization_telem_telem_enhanced_ea_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_core_services_synchronization_telem_telem_enhanced_ea_proto_goTypes = []interface{}{
+var file_core_services_synchronization_telem_telem_enhanced_ea_proto_goTypes = []any{
(*EnhancedEA)(nil), // 0: telem.EnhancedEA
}
var file_core_services_synchronization_telem_telem_enhanced_ea_proto_depIdxs = []int32{
@@ -256,7 +256,7 @@ func file_core_services_synchronization_telem_telem_enhanced_ea_proto_init() {
return
}
if !protoimpl.UnsafeEnabled {
- file_core_services_synchronization_telem_telem_enhanced_ea_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_enhanced_ea_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*EnhancedEA); i {
case 0:
return &v.state
diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go
index e152cb4b152..856619e1931 100644
--- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go
+++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.34.1
+// protoc-gen-go v1.34.2
// protoc v4.25.1
// source: core/services/synchronization/telem/telem_enhanced_ea_mercury.proto
@@ -20,6 +20,56 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
+type MarketStatus int32
+
+const (
+ // Same values as those used by OCR.
+ MarketStatus_UNKNOWN MarketStatus = 0
+ MarketStatus_CLOSED MarketStatus = 1
+ MarketStatus_OPEN MarketStatus = 2
+)
+
+// Enum value maps for MarketStatus.
+var (
+ MarketStatus_name = map[int32]string{
+ 0: "UNKNOWN",
+ 1: "CLOSED",
+ 2: "OPEN",
+ }
+ MarketStatus_value = map[string]int32{
+ "UNKNOWN": 0,
+ "CLOSED": 1,
+ "OPEN": 2,
+ }
+)
+
+func (x MarketStatus) Enum() *MarketStatus {
+ p := new(MarketStatus)
+ *p = x
+ return p
+}
+
+func (x MarketStatus) String() string {
+ return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (MarketStatus) Descriptor() protoreflect.EnumDescriptor {
+ return file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_enumTypes[0].Descriptor()
+}
+
+func (MarketStatus) Type() protoreflect.EnumType {
+ return &file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_enumTypes[0]
+}
+
+func (x MarketStatus) Number() protoreflect.EnumNumber {
+ return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use MarketStatus.Descriptor instead.
+func (MarketStatus) EnumDescriptor() ([]byte, []int) {
+ return file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescGZIP(), []int{0}
+}
+
type EnhancedEAMercury struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -58,10 +108,12 @@ type EnhancedEAMercury struct {
ObservationAsk int64 `protobuf:"varint,17,opt,name=observation_ask,json=observationAsk,proto3" json:"observation_ask,omitempty"` // This value overflows, will be reserved and removed in future versions
ObservationBidString string `protobuf:"bytes,23,opt,name=observation_bid_string,json=observationBidString,proto3" json:"observation_bid_string,omitempty"`
ObservationAskString string `protobuf:"bytes,24,opt,name=observation_ask_string,json=observationAskString,proto3" json:"observation_ask_string,omitempty"`
- ConfigDigest string `protobuf:"bytes,18,opt,name=config_digest,json=configDigest,proto3" json:"config_digest,omitempty"`
- Round int64 `protobuf:"varint,19,opt,name=round,proto3" json:"round,omitempty"`
- Epoch int64 `protobuf:"varint,20,opt,name=epoch,proto3" json:"epoch,omitempty"`
- AssetSymbol string `protobuf:"bytes,21,opt,name=asset_symbol,json=assetSymbol,proto3" json:"asset_symbol,omitempty"`
+ // v4
+ ObservationMarketStatus MarketStatus `protobuf:"varint,34,opt,name=observation_market_status,json=observationMarketStatus,proto3,enum=telem.MarketStatus" json:"observation_market_status,omitempty"`
+ ConfigDigest string `protobuf:"bytes,18,opt,name=config_digest,json=configDigest,proto3" json:"config_digest,omitempty"`
+ Round int64 `protobuf:"varint,19,opt,name=round,proto3" json:"round,omitempty"`
+ Epoch int64 `protobuf:"varint,20,opt,name=epoch,proto3" json:"epoch,omitempty"`
+ AssetSymbol string `protobuf:"bytes,21,opt,name=asset_symbol,json=assetSymbol,proto3" json:"asset_symbol,omitempty"`
}
func (x *EnhancedEAMercury) Reset() {
@@ -299,6 +351,13 @@ func (x *EnhancedEAMercury) GetObservationAskString() string {
return ""
}
+func (x *EnhancedEAMercury) GetObservationMarketStatus() MarketStatus {
+ if x != nil {
+ return x.ObservationMarketStatus
+ }
+ return MarketStatus_UNKNOWN
+}
+
func (x *EnhancedEAMercury) GetConfigDigest() string {
if x != nil {
return x.ConfigDigest
@@ -334,7 +393,7 @@ var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_raw
0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f,
0x74, 0x65, 0x6c, 0x65, 0x6d, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x5f, 0x65, 0x6e, 0x68, 0x61,
0x6e, 0x63, 0x65, 0x64, 0x5f, 0x65, 0x61, 0x5f, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x79, 0x2e,
- 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x22, 0xa9, 0x0c, 0x0a,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x22, 0xfa, 0x0c, 0x0a,
0x11, 0x45, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x45, 0x41, 0x4d, 0x65, 0x72, 0x63, 0x75,
0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x20, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b,
@@ -426,19 +485,28 @@ var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_raw
0x0a, 0x16, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x73,
0x6b, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14,
0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x73, 0x6b, 0x53, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x64,
- 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f, 0x6e,
- 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75,
- 0x6e, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x12,
- 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05,
- 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73,
- 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x73, 0x73,
- 0x65, 0x74, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x42, 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68,
- 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74,
- 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e,
- 0x6b, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
- 0x65, 0x73, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+ 0x72, 0x69, 0x6e, 0x67, 0x12, 0x4f, 0x0a, 0x19, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74,
+ 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75,
+ 0x73, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x2e,
+ 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x17, 0x6f, 0x62,
+ 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x53,
+ 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
+ 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x44, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f,
+ 0x75, 0x6e, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64,
+ 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52,
+ 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f,
+ 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x73,
+ 0x73, 0x65, 0x74, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2a, 0x31, 0x0a, 0x0c, 0x4d, 0x61, 0x72,
+ 0x6b, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b,
+ 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44,
+ 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4f, 0x50, 0x45, 0x4e, 0x10, 0x02, 0x42, 0x4e, 0x5a, 0x4c,
+ 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74,
+ 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69,
+ 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65,
+ 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69,
+ 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x62, 0x06, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -453,16 +521,19 @@ func file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_ra
return file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDescData
}
+var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_goTypes = []interface{}{
- (*EnhancedEAMercury)(nil), // 0: telem.EnhancedEAMercury
+var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_goTypes = []any{
+ (MarketStatus)(0), // 0: telem.MarketStatus
+ (*EnhancedEAMercury)(nil), // 1: telem.EnhancedEAMercury
}
var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_depIdxs = []int32{
- 0, // [0:0] is the sub-list for method output_type
- 0, // [0:0] is the sub-list for method input_type
- 0, // [0:0] is the sub-list for extension type_name
- 0, // [0:0] is the sub-list for extension extendee
- 0, // [0:0] is the sub-list for field type_name
+ 0, // 0: telem.EnhancedEAMercury.observation_market_status:type_name -> telem.MarketStatus
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
}
func init() { file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_init() }
@@ -471,7 +542,7 @@ func file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_in
return
}
if !protoimpl.UnsafeEnabled {
- file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*EnhancedEAMercury); i {
case 0:
return &v.state
@@ -489,13 +560,14 @@ func file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_in
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDesc,
- NumEnums: 0,
+ NumEnums: 1,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_goTypes,
DependencyIndexes: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_depIdxs,
+ EnumInfos: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_enumTypes,
MessageInfos: file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_msgTypes,
}.Build()
File_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto = out.File
diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto
index 8488eb1d509..bb41ff86ee3 100644
--- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto
+++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto
@@ -4,6 +4,13 @@ option go_package = "github.com/smartcontractkit/chainlink/v2/core/services/sync
package telem;
+enum MarketStatus {
+ // Same values as those used by OCR.
+ UNKNOWN = 0;
+ CLOSED = 1;
+ OPEN = 2;
+}
+
message EnhancedEAMercury {
uint32 version = 32;
@@ -44,6 +51,8 @@ message EnhancedEAMercury {
int64 observation_ask=17; // This value overflows, will be reserved and removed in future versions
string observation_bid_string = 23;
string observation_ask_string = 24;
+ // v4
+ MarketStatus observation_market_status=34;
string config_digest = 18;
int64 round=19;
diff --git a/core/services/synchronization/telem/telem_functions_request.pb.go b/core/services/synchronization/telem/telem_functions_request.pb.go
index 0a4a2649b4e..89aa9e3fe37 100644
--- a/core/services/synchronization/telem/telem_functions_request.pb.go
+++ b/core/services/synchronization/telem/telem_functions_request.pb.go
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.34.1
+// protoc-gen-go v1.34.2
// protoc v4.25.1
// source: core/services/synchronization/telem/telem_functions_request.proto
@@ -119,7 +119,7 @@ func file_core_services_synchronization_telem_telem_functions_request_proto_rawD
}
var file_core_services_synchronization_telem_telem_functions_request_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
-var file_core_services_synchronization_telem_telem_functions_request_proto_goTypes = []interface{}{
+var file_core_services_synchronization_telem_telem_functions_request_proto_goTypes = []any{
(*FunctionsRequest)(nil), // 0: telem.FunctionsRequest
}
var file_core_services_synchronization_telem_telem_functions_request_proto_depIdxs = []int32{
@@ -136,7 +136,7 @@ func file_core_services_synchronization_telem_telem_functions_request_proto_init
return
}
if !protoimpl.UnsafeEnabled {
- file_core_services_synchronization_telem_telem_functions_request_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ file_core_services_synchronization_telem_telem_functions_request_proto_msgTypes[0].Exporter = func(v any, i int) any {
switch v := v.(*FunctionsRequest); i {
case 0:
return &v.state
diff --git a/core/services/synchronization/telem/telem_head_report.pb.go b/core/services/synchronization/telem/telem_head_report.pb.go
new file mode 100644
index 00000000000..18e4532472b
--- /dev/null
+++ b/core/services/synchronization/telem/telem_head_report.pb.go
@@ -0,0 +1,255 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.33.0
+// protoc v4.25.1
+// source: core/services/synchronization/telem/telem_head_report.proto
+
+package telem
+
+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 HeadReportRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Chain string `protobuf:"bytes,1,opt,name=chain,proto3" json:"chain,omitempty"`
+ Latest *Block `protobuf:"bytes,2,opt,name=latest,proto3" json:"latest,omitempty"`
+ Finalized *Block `protobuf:"bytes,3,opt,name=finalized,proto3,oneof" json:"finalized,omitempty"`
+}
+
+func (x *HeadReportRequest) Reset() {
+ *x = HeadReportRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_core_services_synchronization_telem_telem_head_report_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *HeadReportRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*HeadReportRequest) ProtoMessage() {}
+
+func (x *HeadReportRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_core_services_synchronization_telem_telem_head_report_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 HeadReportRequest.ProtoReflect.Descriptor instead.
+func (*HeadReportRequest) Descriptor() ([]byte, []int) {
+ return file_core_services_synchronization_telem_telem_head_report_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *HeadReportRequest) GetChain() string {
+ if x != nil {
+ return x.Chain
+ }
+ return ""
+}
+
+func (x *HeadReportRequest) GetLatest() *Block {
+ if x != nil {
+ return x.Latest
+ }
+ return nil
+}
+
+func (x *HeadReportRequest) GetFinalized() *Block {
+ if x != nil {
+ return x.Finalized
+ }
+ return nil
+}
+
+type Block struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Timestamp uint64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
+ Number uint64 `protobuf:"varint,2,opt,name=number,proto3" json:"number,omitempty"`
+ Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty"`
+}
+
+func (x *Block) Reset() {
+ *x = Block{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_core_services_synchronization_telem_telem_head_report_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Block) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Block) ProtoMessage() {}
+
+func (x *Block) ProtoReflect() protoreflect.Message {
+ mi := &file_core_services_synchronization_telem_telem_head_report_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 Block.ProtoReflect.Descriptor instead.
+func (*Block) Descriptor() ([]byte, []int) {
+ return file_core_services_synchronization_telem_telem_head_report_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Block) GetTimestamp() uint64 {
+ if x != nil {
+ return x.Timestamp
+ }
+ return 0
+}
+
+func (x *Block) GetNumber() uint64 {
+ if x != nil {
+ return x.Number
+ }
+ return 0
+}
+
+func (x *Block) GetHash() string {
+ if x != nil {
+ return x.Hash
+ }
+ return ""
+}
+
+var File_core_services_synchronization_telem_telem_head_report_proto protoreflect.FileDescriptor
+
+var file_core_services_synchronization_telem_telem_head_report_proto_rawDesc = []byte{
+ 0x0a, 0x3b, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f,
+ 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f,
+ 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x5f, 0x68, 0x65, 0x61, 0x64,
+ 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74,
+ 0x65, 0x6c, 0x65, 0x6d, 0x22, 0x8e, 0x01, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x64, 0x52, 0x65, 0x70,
+ 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68,
+ 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e,
+ 0x12, 0x24, 0x0a, 0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
+ 0x32, 0x0c, 0x2e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x06,
+ 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x09, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69,
+ 0x7a, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x74, 0x65, 0x6c, 0x65,
+ 0x6d, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x00, 0x52, 0x09, 0x66, 0x69, 0x6e, 0x61, 0x6c,
+ 0x69, 0x7a, 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x66, 0x69, 0x6e, 0x61,
+ 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x22, 0x51, 0x0a, 0x05, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x1c,
+ 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x16, 0x0a, 0x06,
+ 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6e, 0x75,
+ 0x6d, 0x62, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01,
+ 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x42, 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68,
+ 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74,
+ 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e,
+ 0x6b, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
+ 0x65, 0x73, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69,
+ 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_core_services_synchronization_telem_telem_head_report_proto_rawDescOnce sync.Once
+ file_core_services_synchronization_telem_telem_head_report_proto_rawDescData = file_core_services_synchronization_telem_telem_head_report_proto_rawDesc
+)
+
+func file_core_services_synchronization_telem_telem_head_report_proto_rawDescGZIP() []byte {
+ file_core_services_synchronization_telem_telem_head_report_proto_rawDescOnce.Do(func() {
+ file_core_services_synchronization_telem_telem_head_report_proto_rawDescData = protoimpl.X.CompressGZIP(file_core_services_synchronization_telem_telem_head_report_proto_rawDescData)
+ })
+ return file_core_services_synchronization_telem_telem_head_report_proto_rawDescData
+}
+
+var file_core_services_synchronization_telem_telem_head_report_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_core_services_synchronization_telem_telem_head_report_proto_goTypes = []interface{}{
+ (*HeadReportRequest)(nil), // 0: telem.HeadReportRequest
+ (*Block)(nil), // 1: telem.Block
+}
+var file_core_services_synchronization_telem_telem_head_report_proto_depIdxs = []int32{
+ 1, // 0: telem.HeadReportRequest.latest:type_name -> telem.Block
+ 1, // 1: telem.HeadReportRequest.finalized:type_name -> telem.Block
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_core_services_synchronization_telem_telem_head_report_proto_init() }
+func file_core_services_synchronization_telem_telem_head_report_proto_init() {
+ if File_core_services_synchronization_telem_telem_head_report_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_core_services_synchronization_telem_telem_head_report_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*HeadReportRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_core_services_synchronization_telem_telem_head_report_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Block); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ file_core_services_synchronization_telem_telem_head_report_proto_msgTypes[0].OneofWrappers = []interface{}{}
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_core_services_synchronization_telem_telem_head_report_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_core_services_synchronization_telem_telem_head_report_proto_goTypes,
+ DependencyIndexes: file_core_services_synchronization_telem_telem_head_report_proto_depIdxs,
+ MessageInfos: file_core_services_synchronization_telem_telem_head_report_proto_msgTypes,
+ }.Build()
+ File_core_services_synchronization_telem_telem_head_report_proto = out.File
+ file_core_services_synchronization_telem_telem_head_report_proto_rawDesc = nil
+ file_core_services_synchronization_telem_telem_head_report_proto_goTypes = nil
+ file_core_services_synchronization_telem_telem_head_report_proto_depIdxs = nil
+}
diff --git a/core/services/synchronization/telem/telem_head_report.proto b/core/services/synchronization/telem/telem_head_report.proto
new file mode 100644
index 00000000000..6f4cf2ddae6
--- /dev/null
+++ b/core/services/synchronization/telem/telem_head_report.proto
@@ -0,0 +1,17 @@
+syntax = "proto3";
+
+option go_package = "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem";
+
+package telem;
+
+message HeadReportRequest {
+ string chainID = 1;
+ Block latest = 2;
+ optional Block finalized = 3;
+}
+
+message Block {
+ uint64 timestamp = 1;
+ uint64 number = 2;
+ string hash = 3;
+}
diff --git a/core/services/synchronization/telemetry_ingress_batch_client.go b/core/services/synchronization/telemetry_ingress_batch_client.go
index cade98cf606..26ce1e3066a 100644
--- a/core/services/synchronization/telemetry_ingress_batch_client.go
+++ b/core/services/synchronization/telemetry_ingress_batch_client.go
@@ -12,8 +12,9 @@ import (
"github.com/smartcontractkit/wsrpc"
"github.com/smartcontractkit/wsrpc/examples/simple/keys"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/timeutil"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem"
)
@@ -37,21 +38,18 @@ func (NoopTelemetryIngressBatchClient) Name() string { return
func (NoopTelemetryIngressBatchClient) Ready() error { return nil }
type telemetryIngressBatchClient struct {
- services.StateMachine
+ services.Service
+ eng *services.Engine
+
url *url.URL
ks keystore.CSA
serverPubKeyHex string
connected atomic.Bool
telemClient telemPb.TelemClient
- close func() error
-
- globalLogger logger.Logger
- logging bool
- lggr logger.Logger
+ closeFn func() error
- wgDone sync.WaitGroup
- chDone services.StopChan
+ logging bool
telemBufferSize uint
telemMaxBatchSize uint
@@ -66,8 +64,8 @@ type telemetryIngressBatchClient struct {
// NewTelemetryIngressBatchClient returns a client backed by wsrpc that
// can send telemetry to the telemetry ingress server
-func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, telemMaxBatchSize uint, telemSendInterval time.Duration, telemSendTimeout time.Duration, useUniconn bool, network string, chainID string) TelemetryService {
- return &telemetryIngressBatchClient{
+func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, telemMaxBatchSize uint, telemSendInterval time.Duration, telemSendTimeout time.Duration, useUniconn bool) TelemetryService {
+ c := &telemetryIngressBatchClient{
telemBufferSize: telemBufferSize,
telemMaxBatchSize: telemMaxBatchSize,
telemSendInterval: telemSendInterval,
@@ -75,13 +73,17 @@ func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks key
url: url,
ks: ks,
serverPubKeyHex: serverPubKeyHex,
- globalLogger: lggr,
logging: logging,
- lggr: lggr.Named("TelemetryIngressBatchClient").Named(network).Named(chainID),
- chDone: make(services.StopChan),
workers: make(map[string]*telemetryIngressBatchWorker),
useUniConn: useUniconn,
}
+ c.Service, c.eng = services.Config{
+ Name: "TelemetryIngressBatchClient",
+ Start: c.start,
+ Close: c.close,
+ }.NewServiceEngine(lggr)
+
+ return c
}
// Start connects the wsrpc client to the telemetry ingress server
@@ -90,71 +92,53 @@ func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks key
// an error and wsrpc will continue to retry the connection. Eventually when the ingress
// server does come back up, wsrpc will establish the connection without any interaction
// on behalf of the node operator.
-func (tc *telemetryIngressBatchClient) Start(ctx context.Context) error {
- return tc.StartOnce("TelemetryIngressBatchClient", func() error {
- clientPrivKey, err := tc.getCSAPrivateKey()
- if err != nil {
- return err
- }
+func (tc *telemetryIngressBatchClient) start(ctx context.Context) error {
+ clientPrivKey, err := tc.getCSAPrivateKey()
+ if err != nil {
+ return err
+ }
- serverPubKey := keys.FromHex(tc.serverPubKeyHex)
-
- // Initialize a new wsrpc client caller
- // This is used to call RPC methods on the server
- if tc.telemClient == nil { // only preset for tests
- if tc.useUniConn {
- tc.wgDone.Add(1)
- go func() {
- defer tc.wgDone.Done()
- ctx2, cancel := tc.chDone.NewCtx()
- defer cancel()
- conn, err := wsrpc.DialUniWithContext(ctx2, tc.lggr, tc.url.String(), clientPrivKey, serverPubKey)
- if err != nil {
- if ctx2.Err() != nil {
- tc.lggr.Warnw("gave up connecting to telemetry endpoint", "err", err)
- } else {
- tc.lggr.Criticalw("telemetry endpoint dial errored unexpectedly", "err", err, "server pubkey", tc.serverPubKeyHex)
- tc.SvcErrBuffer.Append(err)
- }
- return
- }
- tc.telemClient = telemPb.NewTelemClient(conn)
- tc.close = conn.Close
- tc.connected.Store(true)
- }()
- } else {
- // Spawns a goroutine that will eventually connect
- conn, err := wsrpc.DialWithContext(ctx, tc.url.String(), wsrpc.WithTransportCreds(clientPrivKey, serverPubKey), wsrpc.WithLogger(tc.lggr))
+ serverPubKey := keys.FromHex(tc.serverPubKeyHex)
+
+ // Initialize a new wsrpc client caller
+ // This is used to call RPC methods on the server
+ if tc.telemClient == nil { // only preset for tests
+ if tc.useUniConn {
+ tc.eng.Go(func(ctx context.Context) {
+ conn, err := wsrpc.DialUniWithContext(ctx, tc.eng, tc.url.String(), clientPrivKey, serverPubKey)
if err != nil {
- return fmt.Errorf("could not start TelemIngressBatchClient, Dial returned error: %v", err)
+ if ctx.Err() != nil {
+ tc.eng.Warnw("gave up connecting to telemetry endpoint", "err", err)
+ } else {
+ tc.eng.Criticalw("telemetry endpoint dial errored unexpectedly", "err", err, "server pubkey", tc.serverPubKeyHex)
+ tc.eng.EmitHealthErr(err)
+ }
+ return
}
tc.telemClient = telemPb.NewTelemClient(conn)
- tc.close = func() error { conn.Close(); return nil }
+ tc.closeFn = conn.Close
+ tc.connected.Store(true)
+ })
+ } else {
+ // Spawns a goroutine that will eventually connect
+ conn, err := wsrpc.DialWithContext(ctx, tc.url.String(), wsrpc.WithTransportCreds(clientPrivKey, serverPubKey), wsrpc.WithLogger(tc.eng))
+ if err != nil {
+ return fmt.Errorf("could not start TelemIngressBatchClient, Dial returned error: %v", err)
}
+ tc.telemClient = telemPb.NewTelemClient(conn)
+ tc.closeFn = func() error { conn.Close(); return nil }
}
+ }
- return nil
- })
+ return nil
}
// Close disconnects the wsrpc client from the ingress server and waits for all workers to exit
-func (tc *telemetryIngressBatchClient) Close() error {
- return tc.StopOnce("TelemetryIngressBatchClient", func() error {
- close(tc.chDone)
- tc.wgDone.Wait()
- if (tc.useUniConn && tc.connected.Load()) || !tc.useUniConn {
- return tc.close()
- }
- return nil
- })
-}
-
-func (tc *telemetryIngressBatchClient) Name() string {
- return tc.lggr.Name()
-}
-
-func (tc *telemetryIngressBatchClient) HealthReport() map[string]error {
- return map[string]error{tc.Name(): tc.Healthy()}
+func (tc *telemetryIngressBatchClient) close() error {
+ if (tc.useUniConn && tc.connected.Load()) || !tc.useUniConn {
+ return tc.closeFn()
+ }
+ return nil
}
// getCSAPrivateKey gets the client's CSA private key
@@ -175,7 +159,7 @@ func (tc *telemetryIngressBatchClient) getCSAPrivateKey() (privkey []byte, err e
// and a warning is logged.
func (tc *telemetryIngressBatchClient) Send(ctx context.Context, telemData []byte, contractID string, telemType TelemetryType) {
if tc.useUniConn && !tc.connected.Load() {
- tc.lggr.Warnw("not connected to telemetry endpoint", "endpoint", tc.url.String())
+ tc.eng.Warnw("not connected to telemetry endpoint", "endpoint", tc.url.String())
return
}
payload := TelemPayload{
@@ -206,18 +190,17 @@ func (tc *telemetryIngressBatchClient) findOrCreateWorker(payload TelemPayload)
if !found {
worker = NewTelemetryIngressBatchWorker(
tc.telemMaxBatchSize,
- tc.telemSendInterval,
tc.telemSendTimeout,
tc.telemClient,
- &tc.wgDone,
- tc.chDone,
make(chan TelemPayload, tc.telemBufferSize),
payload.ContractID,
payload.TelemType,
- tc.globalLogger,
+ tc.eng,
tc.logging,
)
- worker.Start()
+ tc.eng.GoTick(timeutil.NewTicker(func() time.Duration {
+ return tc.telemSendInterval
+ }), worker.Send)
tc.workers[workerKey] = worker
}
diff --git a/core/services/synchronization/telemetry_ingress_batch_worker.go b/core/services/synchronization/telemetry_ingress_batch_worker.go
index e7ea6595811..7eca26f02c9 100644
--- a/core/services/synchronization/telemetry_ingress_batch_worker.go
+++ b/core/services/synchronization/telemetry_ingress_batch_worker.go
@@ -2,13 +2,12 @@ package synchronization
import (
"context"
- "sync"
"sync/atomic"
"time"
"github.com/smartcontractkit/chainlink-common/pkg/services"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem"
)
@@ -18,11 +17,8 @@ type telemetryIngressBatchWorker struct {
services.Service
telemMaxBatchSize uint
- telemSendInterval time.Duration
telemSendTimeout time.Duration
telemClient telemPb.TelemClient
- wgDone *sync.WaitGroup
- chDone services.StopChan
chTelemetry chan TelemPayload
contractID string
telemType TelemetryType
@@ -35,65 +31,45 @@ type telemetryIngressBatchWorker struct {
// telemetry to the ingress server via WSRPC
func NewTelemetryIngressBatchWorker(
telemMaxBatchSize uint,
- telemSendInterval time.Duration,
telemSendTimeout time.Duration,
telemClient telemPb.TelemClient,
- wgDone *sync.WaitGroup,
- chDone chan struct{},
chTelemetry chan TelemPayload,
contractID string,
telemType TelemetryType,
- globalLogger logger.Logger,
+ lggr logger.Logger,
logging bool,
) *telemetryIngressBatchWorker {
return &telemetryIngressBatchWorker{
- telemSendInterval: telemSendInterval,
telemSendTimeout: telemSendTimeout,
telemMaxBatchSize: telemMaxBatchSize,
telemClient: telemClient,
- wgDone: wgDone,
- chDone: chDone,
chTelemetry: chTelemetry,
contractID: contractID,
telemType: telemType,
logging: logging,
- lggr: globalLogger.Named("TelemetryIngressBatchWorker"),
+ lggr: logger.Named(lggr, "TelemetryIngressBatchWorker"),
}
}
-// Start sends batched telemetry to the ingress server on an interval
-func (tw *telemetryIngressBatchWorker) Start() {
- tw.wgDone.Add(1)
- sendTicker := time.NewTicker(tw.telemSendInterval)
-
- go func() {
- defer tw.wgDone.Done()
-
- for {
- select {
- case <-sendTicker.C:
- if len(tw.chTelemetry) == 0 {
- continue
- }
+// Send sends batched telemetry to the ingress server on an interval
+func (tw *telemetryIngressBatchWorker) Send(ctx context.Context) {
+ if len(tw.chTelemetry) == 0 {
+ return
+ }
- // Send batched telemetry to the ingress server, log any errors
- telemBatchReq := tw.BuildTelemBatchReq()
- ctx, cancel := tw.chDone.CtxCancel(context.WithTimeout(context.Background(), tw.telemSendTimeout))
- _, err := tw.telemClient.TelemBatch(ctx, telemBatchReq)
- cancel()
+ // Send batched telemetry to the ingress server, log any errors
+ telemBatchReq := tw.BuildTelemBatchReq()
+ ctx, cancel := context.WithTimeout(ctx, tw.telemSendTimeout)
+ _, err := tw.telemClient.TelemBatch(ctx, telemBatchReq)
+ cancel()
- if err != nil {
- tw.lggr.Warnf("Could not send telemetry: %v", err)
- continue
- }
- if tw.logging {
- tw.lggr.Debugw("Successfully sent telemetry to ingress server", "contractID", telemBatchReq.ContractId, "telemType", telemBatchReq.TelemetryType, "telemetry", telemBatchReq.Telemetry)
- }
- case <-tw.chDone:
- return
- }
- }
- }()
+ if err != nil {
+ tw.lggr.Warnf("Could not send telemetry: %v", err)
+ return
+ }
+ if tw.logging {
+ tw.lggr.Debugw("Successfully sent telemetry to ingress server", "contractID", telemBatchReq.ContractId, "telemType", telemBatchReq.TelemetryType, "telemetry", telemBatchReq.Telemetry)
+ }
}
// logBufferFullWithExpBackoff logs messages at
diff --git a/core/services/synchronization/telemetry_ingress_batch_worker_test.go b/core/services/synchronization/telemetry_ingress_batch_worker_test.go
index 109022c7135..bf44ee9195a 100644
--- a/core/services/synchronization/telemetry_ingress_batch_worker_test.go
+++ b/core/services/synchronization/telemetry_ingress_batch_worker_test.go
@@ -1,7 +1,6 @@
package synchronization_test
import (
- "sync"
"testing"
"time"
@@ -22,11 +21,8 @@ func TestTelemetryIngressWorker_BuildTelemBatchReq(t *testing.T) {
chTelemetry := make(chan synchronization.TelemPayload, 10)
worker := synchronization.NewTelemetryIngressBatchWorker(
uint(maxTelemBatchSize),
- time.Millisecond*1,
time.Second,
mocks.NewTelemClient(t),
- &sync.WaitGroup{},
- make(chan struct{}),
chTelemetry,
"0xa",
synchronization.OCR,
diff --git a/core/services/synchronization/telemetry_ingress_client.go b/core/services/synchronization/telemetry_ingress_client.go
index dc4ced31d09..1ed55bb5468 100644
--- a/core/services/synchronization/telemetry_ingress_client.go
+++ b/core/services/synchronization/telemetry_ingress_client.go
@@ -4,15 +4,14 @@ import (
"context"
"errors"
"net/url"
- "sync"
"sync/atomic"
"time"
"github.com/smartcontractkit/wsrpc"
"github.com/smartcontractkit/wsrpc/examples/simple/keys"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem"
)
@@ -35,82 +34,59 @@ func (NoopTelemetryIngressClient) Name() string { return "Noop
func (NoopTelemetryIngressClient) Ready() error { return nil }
type telemetryIngressClient struct {
- services.StateMachine
+ services.Service
+ eng *services.Engine
+
url *url.URL
ks keystore.CSA
serverPubKeyHex string
telemClient telemPb.TelemClient
logging bool
- lggr logger.Logger
- wgDone sync.WaitGroup
- chDone services.StopChan
dropMessageCount atomic.Uint32
chTelemetry chan TelemPayload
}
// NewTelemetryIngressClient returns a client backed by wsrpc that
// can send telemetry to the telemetry ingress server
-func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, network string, chainID string) TelemetryService {
- return &telemetryIngressClient{
+func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint) TelemetryService {
+ c := &telemetryIngressClient{
url: url,
ks: ks,
serverPubKeyHex: serverPubKeyHex,
logging: logging,
- lggr: lggr.Named("TelemetryIngressClient").Named(network).Named(chainID),
chTelemetry: make(chan TelemPayload, telemBufferSize),
- chDone: make(services.StopChan),
}
+ c.Service, c.eng = services.Config{
+ Name: "TelemetryIngressClient",
+ Start: c.start,
+ }.NewServiceEngine(lggr)
+ return c
}
// Start connects the wsrpc client to the telemetry ingress server
-func (tc *telemetryIngressClient) Start(context.Context) error {
- return tc.StartOnce("TelemetryIngressClient", func() error {
- privkey, err := tc.getCSAPrivateKey()
- if err != nil {
- return err
- }
-
- tc.connect(privkey)
-
- return nil
- })
-}
-
-// Close disconnects the wsrpc client from the ingress server
-func (tc *telemetryIngressClient) Close() error {
- return tc.StopOnce("TelemetryIngressClient", func() error {
- close(tc.chDone)
- tc.wgDone.Wait()
- return nil
- })
-}
+func (tc *telemetryIngressClient) start(context.Context) error {
+ privkey, err := tc.getCSAPrivateKey()
+ if err != nil {
+ return err
+ }
-func (tc *telemetryIngressClient) Name() string {
- return tc.lggr.Name()
-}
+ tc.connect(privkey)
-func (tc *telemetryIngressClient) HealthReport() map[string]error {
- return map[string]error{tc.Name(): tc.Healthy()}
+ return nil
}
func (tc *telemetryIngressClient) connect(clientPrivKey []byte) {
- tc.wgDone.Add(1)
-
- go func() {
- defer tc.wgDone.Done()
- ctx, cancel := tc.chDone.NewCtx()
- defer cancel()
-
+ tc.eng.Go(func(ctx context.Context) {
serverPubKey := keys.FromHex(tc.serverPubKeyHex)
- conn, err := wsrpc.DialWithContext(ctx, tc.url.String(), wsrpc.WithTransportCreds(clientPrivKey, serverPubKey), wsrpc.WithLogger(tc.lggr))
+ conn, err := wsrpc.DialWithContext(ctx, tc.url.String(), wsrpc.WithTransportCreds(clientPrivKey, serverPubKey), wsrpc.WithLogger(tc.eng))
if err != nil {
if ctx.Err() != nil {
- tc.lggr.Warnw("gave up connecting to telemetry endpoint", "err", err)
+ tc.eng.Warnw("gave up connecting to telemetry endpoint", "err", err)
} else {
- tc.lggr.Criticalw("telemetry endpoint dial errored unexpectedly", "err", err)
- tc.SvcErrBuffer.Append(err)
+ tc.eng.Criticalw("telemetry endpoint dial errored unexpectedly", "err", err)
+ tc.eng.EmitHealthErr(err)
}
return
}
@@ -126,16 +102,12 @@ func (tc *telemetryIngressClient) connect(clientPrivKey []byte) {
tc.handleTelemetry()
// Wait for close
- <-tc.chDone
- }()
+ <-ctx.Done()
+ })
}
func (tc *telemetryIngressClient) handleTelemetry() {
- tc.wgDone.Add(1)
- go func() {
- defer tc.wgDone.Done()
- ctx, cancel := tc.chDone.NewCtx()
- defer cancel()
+ tc.eng.Go(func(ctx context.Context) {
for {
select {
case p := <-tc.chTelemetry:
@@ -148,17 +120,17 @@ func (tc *telemetryIngressClient) handleTelemetry() {
}
_, err := tc.telemClient.Telem(ctx, telemReq)
if err != nil {
- tc.lggr.Errorf("Could not send telemetry: %v", err)
+ tc.eng.Errorf("Could not send telemetry: %v", err)
continue
}
if tc.logging {
- tc.lggr.Debugw("successfully sent telemetry to ingress server", "contractID", p.ContractID, "telemetry", p.Telemetry)
+ tc.eng.Debugw("successfully sent telemetry to ingress server", "contractID", p.ContractID, "telemetry", p.Telemetry)
}
- case <-tc.chDone:
+ case <-ctx.Done():
return
}
}
- }()
+ })
}
// logBufferFullWithExpBackoff logs messages at
@@ -176,7 +148,7 @@ func (tc *telemetryIngressClient) handleTelemetry() {
func (tc *telemetryIngressClient) logBufferFullWithExpBackoff(payload TelemPayload) {
count := tc.dropMessageCount.Add(1)
if count > 0 && (count%100 == 0 || count&(count-1) == 0) {
- tc.lggr.Warnw("telemetry ingress client buffer full, dropping message", "telemetry", payload.Telemetry, "droppedCount", count)
+ tc.eng.Warnw("telemetry ingress client buffer full, dropping message", "telemetry", payload.Telemetry, "droppedCount", count)
}
}
diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go
index a65759a5c62..73a94b4b127 100644
--- a/core/services/telemetry/manager.go
+++ b/core/services/telemetry/manager.go
@@ -1,29 +1,29 @@
package telemetry
import (
- "context"
"net/url"
"strings"
"time"
"github.com/pkg/errors"
- "go.uber.org/multierr"
-
"github.com/smartcontractkit/libocr/commontypes"
+ "github.com/smartcontractkit/chainlink-common/pkg/logger"
+ common "github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink/v2/core/config"
- "github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
"github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
)
type Manager struct {
- services.StateMachine
- bufferSize uint
- endpoints []*telemetryEndpoint
- ks keystore.CSA
- lggr logger.Logger
+ services.Service
+ eng *services.Engine
+
+ bufferSize uint
+ endpoints []*telemetryEndpoint
+ ks keystore.CSA
+
logging bool
maxBatchSize uint
sendInterval time.Duration
@@ -45,9 +45,7 @@ type telemetryEndpoint struct {
func NewManager(cfg config.TelemetryIngress, csaKeyStore keystore.CSA, lggr logger.Logger) *Manager {
m := &Manager{
bufferSize: cfg.BufferSize(),
- endpoints: nil,
ks: csaKeyStore,
- lggr: lggr.Named("TelemetryManager"),
logging: cfg.Logging(),
maxBatchSize: cfg.MaxBatchSize(),
sendInterval: cfg.SendInterval(),
@@ -55,44 +53,21 @@ func NewManager(cfg config.TelemetryIngress, csaKeyStore keystore.CSA, lggr logg
uniConn: cfg.UniConn(),
useBatchSend: cfg.UseBatchSend(),
}
- for _, e := range cfg.Endpoints() {
- if err := m.addEndpoint(e); err != nil {
- m.lggr.Error(err)
- }
- }
- return m
-}
-
-func (m *Manager) Start(ctx context.Context) error {
- return m.StartOnce("TelemetryManager", func() error {
- var err error
- for _, e := range m.endpoints {
- err = multierr.Append(err, e.client.Start(ctx))
- }
- return err
- })
-}
-func (m *Manager) Close() error {
- return m.StopOnce("TelemetryManager", func() error {
- var err error
- for _, e := range m.endpoints {
- err = multierr.Append(err, e.client.Close())
- }
- return err
- })
-}
-
-func (m *Manager) Name() string {
- return m.lggr.Name()
-}
+ m.Service, m.eng = services.Config{
+ Name: "TelemetryManager",
+ NewSubServices: func(lggr common.Logger) (subs []services.Service) {
+ for _, e := range cfg.Endpoints() {
+ if sub, err := m.newEndpoint(e, lggr, cfg); err != nil {
+ lggr.Error(err)
+ } else {
+ subs = append(subs, sub)
+ }
+ }
+ return
+ },
+ }.NewServiceEngine(lggr)
-func (m *Manager) HealthReport() map[string]error {
- hr := map[string]error{m.Name(): m.Healthy()}
-
- for _, e := range m.endpoints {
- services.CopyHealth(hr, e.client.HealthReport())
- }
- return hr
+ return m
}
// GenMonitoringEndpoint creates a new monitoring endpoints based on the existing available endpoints defined in the core config TOML, if no endpoint for the network and chainID exists, a NOOP agent will be used and the telemetry will not be sent
@@ -100,7 +75,7 @@ func (m *Manager) GenMonitoringEndpoint(network string, chainID string, contract
e, found := m.getEndpoint(network, chainID)
if !found {
- m.lggr.Warnf("no telemetry endpoint found for network %q chainID %q, telemetry %q for contactID %q will NOT be sent", network, chainID, telemType, contractID)
+ m.eng.Warnf("no telemetry endpoint found for network %q chainID %q, telemetry %q for contactID %q will NOT be sent", network, chainID, telemType, contractID)
return &NoopAgent{}
}
@@ -111,32 +86,33 @@ func (m *Manager) GenMonitoringEndpoint(network string, chainID string, contract
return NewIngressAgent(e.client, network, chainID, contractID, telemType)
}
-func (m *Manager) addEndpoint(e config.TelemetryIngressEndpoint) error {
+func (m *Manager) newEndpoint(e config.TelemetryIngressEndpoint, lggr logger.Logger, cfg config.TelemetryIngress) (services.Service, error) {
if e.Network() == "" {
- return errors.New("cannot add telemetry endpoint, network cannot be empty")
+ return nil, errors.New("cannot add telemetry endpoint, network cannot be empty")
}
if e.ChainID() == "" {
- return errors.New("cannot add telemetry endpoint, chainID cannot be empty")
+ return nil, errors.New("cannot add telemetry endpoint, chainID cannot be empty")
}
if e.URL() == nil {
- return errors.New("cannot add telemetry endpoint, URL cannot be empty")
+ return nil, errors.New("cannot add telemetry endpoint, URL cannot be empty")
}
if e.ServerPubKey() == "" {
- return errors.New("cannot add telemetry endpoint, ServerPubKey cannot be empty")
+ return nil, errors.New("cannot add telemetry endpoint, ServerPubKey cannot be empty")
}
if _, found := m.getEndpoint(e.Network(), e.ChainID()); found {
- return errors.Errorf("cannot add telemetry endpoint for network %q and chainID %q, endpoint already exists", e.Network(), e.ChainID())
+ return nil, errors.Errorf("cannot add telemetry endpoint for network %q and chainID %q, endpoint already exists", e.Network(), e.ChainID())
}
+ lggr = logger.Sugared(lggr).Named(e.Network()).Named(e.ChainID())
var tClient synchronization.TelemetryService
if m.useBatchSend {
- tClient = synchronization.NewTelemetryIngressBatchClient(e.URL(), e.ServerPubKey(), m.ks, m.logging, m.lggr, m.bufferSize, m.maxBatchSize, m.sendInterval, m.sendTimeout, m.uniConn, e.Network(), e.ChainID())
+ tClient = synchronization.NewTelemetryIngressBatchClient(e.URL(), e.ServerPubKey(), m.ks, cfg.Logging(), lggr, cfg.BufferSize(), cfg.MaxBatchSize(), cfg.SendInterval(), cfg.SendTimeout(), cfg.UniConn())
} else {
- tClient = synchronization.NewTelemetryIngressClient(e.URL(), e.ServerPubKey(), m.ks, m.logging, m.lggr, m.bufferSize, e.Network(), e.ChainID())
+ tClient = synchronization.NewTelemetryIngressClient(e.URL(), e.ServerPubKey(), m.ks, cfg.Logging(), lggr, cfg.BufferSize())
}
te := telemetryEndpoint{
@@ -148,7 +124,7 @@ func (m *Manager) addEndpoint(e config.TelemetryIngressEndpoint) error {
}
m.endpoints = append(m.endpoints, &te)
- return nil
+ return te.client, nil
}
func (m *Manager) getEndpoint(network string, chainID string) (*telemetryEndpoint, bool) {
diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go
index 4e55cb75752..fef065b572c 100644
--- a/core/services/telemetry/manager_test.go
+++ b/core/services/telemetry/manager_test.go
@@ -156,7 +156,7 @@ func TestNewManager(t *testing.T) {
require.Equal(t, uint(123), m.bufferSize)
require.Equal(t, ks, m.ks)
- require.Equal(t, "TelemetryManager", m.lggr.Name())
+ require.Equal(t, "TelemetryManager", m.Name())
require.Equal(t, true, m.logging)
require.Equal(t, uint(51), m.maxBatchSize)
require.Equal(t, time.Millisecond*512, m.sendInterval)
diff --git a/core/services/telemetry/monitoring_endpoint_generator_mock.go b/core/services/telemetry/monitoring_endpoint_generator_mock.go
new file mode 100644
index 00000000000..a0fc503ecca
--- /dev/null
+++ b/core/services/telemetry/monitoring_endpoint_generator_mock.go
@@ -0,0 +1,88 @@
+// Code generated by mockery v2.43.2. DO NOT EDIT.
+
+package telemetry
+
+import (
+ commontypes "github.com/smartcontractkit/libocr/commontypes"
+ mock "github.com/stretchr/testify/mock"
+
+ synchronization "github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
+)
+
+// MockMonitoringEndpointGenerator is an autogenerated mock type for the MonitoringEndpointGenerator type
+type MockMonitoringEndpointGenerator struct {
+ mock.Mock
+}
+
+type MockMonitoringEndpointGenerator_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockMonitoringEndpointGenerator) EXPECT() *MockMonitoringEndpointGenerator_Expecter {
+ return &MockMonitoringEndpointGenerator_Expecter{mock: &_m.Mock}
+}
+
+// GenMonitoringEndpoint provides a mock function with given fields: network, chainID, contractID, telemType
+func (_m *MockMonitoringEndpointGenerator) GenMonitoringEndpoint(network string, chainID string, contractID string, telemType synchronization.TelemetryType) commontypes.MonitoringEndpoint {
+ ret := _m.Called(network, chainID, contractID, telemType)
+
+ if len(ret) == 0 {
+ panic("no return value specified for GenMonitoringEndpoint")
+ }
+
+ var r0 commontypes.MonitoringEndpoint
+ if rf, ok := ret.Get(0).(func(string, string, string, synchronization.TelemetryType) commontypes.MonitoringEndpoint); ok {
+ r0 = rf(network, chainID, contractID, telemType)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(commontypes.MonitoringEndpoint)
+ }
+ }
+
+ return r0
+}
+
+// MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenMonitoringEndpoint'
+type MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call struct {
+ *mock.Call
+}
+
+// GenMonitoringEndpoint is a helper method to define mock.On call
+// - network string
+// - chainID string
+// - contractID string
+// - telemType synchronization.TelemetryType
+func (_e *MockMonitoringEndpointGenerator_Expecter) GenMonitoringEndpoint(network interface{}, chainID interface{}, contractID interface{}, telemType interface{}) *MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call {
+ return &MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call{Call: _e.mock.On("GenMonitoringEndpoint", network, chainID, contractID, telemType)}
+}
+
+func (_c *MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call) Run(run func(network string, chainID string, contractID string, telemType synchronization.TelemetryType)) *MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(string), args[1].(string), args[2].(string), args[3].(synchronization.TelemetryType))
+ })
+ return _c
+}
+
+func (_c *MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call) Return(_a0 commontypes.MonitoringEndpoint) *MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call {
+ _c.Call.Return(_a0)
+ return _c
+}
+
+func (_c *MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call) RunAndReturn(run func(string, string, string, synchronization.TelemetryType) commontypes.MonitoringEndpoint) *MockMonitoringEndpointGenerator_GenMonitoringEndpoint_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// NewMockMonitoringEndpointGenerator creates a new instance of MockMonitoringEndpointGenerator. 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 NewMockMonitoringEndpointGenerator(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockMonitoringEndpointGenerator {
+ mock := &MockMonitoringEndpointGenerator{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
diff --git a/core/services/versioning/orm_test.go b/core/services/versioning/orm_test.go
index 3504c2bc772..e2f05e3903d 100644
--- a/core/services/versioning/orm_test.go
+++ b/core/services/versioning/orm_test.go
@@ -97,6 +97,87 @@ func Test_Version_CheckVersion(t *testing.T) {
assert.Equal(t, "9.9.8", dbv.String())
}
+func TestORM_CheckVersion_CCIP(t *testing.T) {
+ ctx := testutils.Context(t)
+ db := pgtest.NewSqlxDB(t)
+
+ lggr := logger.TestLogger(t)
+
+ orm := NewORM(db, lggr)
+
+ tests := []struct {
+ name string
+ currentVersion string
+ newVersion string
+ expectedError bool
+ }{
+ {
+ name: "ccip patch version bump from 0 -> 2",
+ currentVersion: "2.5.0-ccip1.4.0",
+ newVersion: "2.5.0-ccip1.4.2",
+ expectedError: false,
+ },
+ {
+ name: "ccip patch downgrade errors",
+ currentVersion: "2.5.0-ccip1.4.2",
+ newVersion: "2.5.0-ccip1.4.1",
+ expectedError: true,
+ },
+ {
+ name: "ccip patch version bump from 2 -> 10",
+ currentVersion: "2.5.0-ccip1.4.2",
+ newVersion: "2.5.0-ccip1.4.10",
+ expectedError: false,
+ },
+ {
+ name: "ccip patch version bump from 9 -> 101",
+ currentVersion: "2.5.0-ccip1.4.9",
+ newVersion: "2.5.0-ccip1.4.101",
+ expectedError: false,
+ },
+ {
+ name: "upgrading only core version",
+ currentVersion: "2.5.0-ccip1.4.10",
+ newVersion: "2.6.0-ccip1.4.10",
+ expectedError: false,
+ },
+ {
+ name: "downgrading only core version errors",
+ currentVersion: "2.6.0-ccip1.4.10",
+ newVersion: "2.5.0-ccip1.4.10",
+ expectedError: true,
+ },
+ {
+ name: "upgrading both core and ccip version",
+ currentVersion: "2.5.0-ccip1.4.10",
+ newVersion: "2.6.0-ccip1.4.11",
+ expectedError: false,
+ },
+ {
+ name: "upgrading both core and ccip version but minor version",
+ currentVersion: "2.5.0-ccip1.4.10",
+ newVersion: "2.6.0-ccip1.5.0",
+ expectedError: false,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ _, err := db.ExecContext(ctx, `TRUNCATE node_versions;`)
+ require.NoError(t, err)
+
+ require.NoError(t, orm.UpsertNodeVersion(ctx, NewNodeVersion(test.currentVersion)))
+ _, _, err = CheckVersion(ctx, db, lggr, test.newVersion)
+ if test.expectedError {
+ require.Error(t, err)
+ } else {
+ require.NoError(t, err)
+ }
+ })
+
+ }
+}
+
func TestORM_NodeVersion_FindLatestNodeVersion(t *testing.T) {
ctx := testutils.Context(t)
db := pgtest.NewSqlxDB(t)
diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go
index 889b19d0e04..9718dc376a7 100644
--- a/core/services/vrf/delegate_test.go
+++ b/core/services/vrf/delegate_test.go
@@ -83,7 +83,7 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv
btORM := bridges.NewORM(db)
ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr)
_, dbConfig, evmConfig := txmgr.MakeTestConfigs(t)
- txm, err := txmgr.NewTxm(db, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), nil, dbConfig, dbConfig.Listener(), ec, logger.TestLogger(t), nil, ks.Eth(), nil)
+ txm, err := txmgr.NewTxm(db, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), nil, dbConfig, dbConfig.Listener(), ec, logger.TestLogger(t), nil, ks.Eth(), nil, nil)
orm := headtracker.NewORM(*testutils.FixtureChainID, db)
require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), cltest.Head(51)))
jrm := job.NewORM(db, prm, btORM, ks, lggr)
diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go
index e9ae908565a..178b555667b 100644
--- a/core/services/vrf/v2/integration_v2_test.go
+++ b/core/services/vrf/v2/integration_v2_test.go
@@ -142,7 +142,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, txStore, nil, nil, nil, nil, nil)
return txm
}
diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go
index ac59f1fdb69..b7a8710c4f8 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, txStore, nil, nil, nil, nil, nil)
return txm
}
diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go
index ed5daaf2106..aa186f7650e 100644
--- a/core/services/workflows/engine.go
+++ b/core/services/workflows/engine.go
@@ -333,17 +333,18 @@ func (e *Engine) registerTrigger(ctx context.Context, t *triggerCapability, trig
return err
}
- t.config = tc
+ t.config.Store(tc)
triggerRegRequest := capabilities.CapabilityRequest{
Metadata: capabilities.RequestMetadata{
WorkflowID: e.workflow.id,
+ WorkflowOwner: e.workflow.owner,
+ WorkflowName: e.workflow.name,
WorkflowDonID: e.localNode.WorkflowDON.ID,
WorkflowDonConfigVersion: e.localNode.WorkflowDON.ConfigVersion,
- WorkflowName: e.workflow.name,
- WorkflowOwner: e.workflow.owner,
+ ReferenceID: t.Ref,
},
- Config: tc,
+ Config: t.config.Load(),
Inputs: triggerInputs,
}
eventsCh, err := t.trigger.RegisterTrigger(ctx, triggerRegRequest)
@@ -713,6 +714,10 @@ func (e *Engine) configForStep(ctx context.Context, executionID string, step *st
return step.config, nil
}
+ if capConfig.DefaultConfig == nil {
+ return step.config, nil
+ }
+
// Merge the configs for now; note that this means that a workflow can override
// all of the config set by the capability. This is probably not desirable in
// the long-term, but we don't know much about those use cases so stick to a simpler
@@ -759,6 +764,7 @@ func (e *Engine) executeStep(ctx context.Context, msg stepRequest) (*values.Map,
WorkflowName: e.workflow.name,
WorkflowDonID: e.localNode.WorkflowDON.ID,
WorkflowDonConfigVersion: e.localNode.WorkflowDON.ConfigVersion,
+ ReferenceID: msg.stepRef,
},
}
@@ -786,9 +792,10 @@ func (e *Engine) deregisterTrigger(ctx context.Context, t *triggerCapability, tr
WorkflowDonConfigVersion: e.localNode.WorkflowDON.ConfigVersion,
WorkflowName: e.workflow.name,
WorkflowOwner: e.workflow.owner,
+ ReferenceID: t.Ref,
},
Inputs: triggerInputs,
- Config: t.config,
+ Config: t.config.Load(),
}
// if t.trigger == nil, then we haven't initialized the workflow
diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go
index b8d5a9591ed..0a38bf719b2 100644
--- a/core/services/workflows/engine_test.go
+++ b/core/services/workflows/engine_test.go
@@ -11,8 +11,10 @@ import (
"github.com/shopspring/decimal"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ "google.golang.org/protobuf/proto"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
+ capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink-common/pkg/services/servicetest"
"github.com/smartcontractkit/chainlink-common/pkg/values"
"github.com/smartcontractkit/chainlink-common/pkg/workflows"
@@ -22,6 +24,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/job"
p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
+ "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer"
"github.com/smartcontractkit/chainlink/v2/core/services/workflows/store"
)
@@ -101,7 +104,7 @@ func newTestDBStore(t *testing.T, clock clockwork.Clock) store.Store {
type testConfigProvider struct {
localNode func(ctx context.Context) (capabilities.Node, error)
- configForCapability func(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error)
+ configForCapability func(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error)
}
func (t testConfigProvider) LocalNode(ctx context.Context) (capabilities.Node, error) {
@@ -118,12 +121,12 @@ func (t testConfigProvider) LocalNode(ctx context.Context) (capabilities.Node, e
}, nil
}
-func (t testConfigProvider) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) {
+func (t testConfigProvider) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error) {
if t.configForCapability != nil {
return t.configForCapability(ctx, capabilityID, donID)
}
- return capabilities.CapabilityConfiguration{DefaultConfig: values.EmptyMap()}, nil
+ return registrysyncer.CapabilityConfiguration{}, nil
}
// newTestEngine creates a new engine with some test defaults.
@@ -1028,11 +1031,9 @@ func TestEngine_MergesWorkflowConfigAndCRConfig(t *testing.T) {
simpleWorkflow,
)
reg.SetLocalRegistry(testConfigProvider{
- configForCapability: func(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) {
+ configForCapability: func(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error) {
if capabilityID != writeID {
- return capabilities.CapabilityConfiguration{
- DefaultConfig: values.EmptyMap(),
- }, nil
+ return registrysyncer.CapabilityConfiguration{}, nil
}
cm, err := values.WrapMap(map[string]any{
@@ -1040,12 +1041,15 @@ func TestEngine_MergesWorkflowConfigAndCRConfig(t *testing.T) {
"schedule": "allAtOnce",
})
if err != nil {
- return capabilities.CapabilityConfiguration{}, err
+ return registrysyncer.CapabilityConfiguration{}, err
}
- return capabilities.CapabilityConfiguration{
- DefaultConfig: cm,
- }, nil
+ cb, err := proto.Marshal(&capabilitiespb.CapabilityConfig{
+ DefaultConfig: values.ProtoMap(cm),
+ })
+ return registrysyncer.CapabilityConfiguration{
+ Config: cb,
+ }, err
},
})
@@ -1063,3 +1067,54 @@ func TestEngine_MergesWorkflowConfigAndCRConfig(t *testing.T) {
assert.Equal(t, m.(map[string]any)["deltaStage"], "1s")
assert.Equal(t, m.(map[string]any)["schedule"], "allAtOnce")
}
+
+func TestEngine_HandlesNilConfigOnchain(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, mockConsensus()))
+ writeID := "write_polygon-testnet-mumbai@1.0.0"
+
+ gotConfig := values.EmptyMap()
+ target := newMockCapability(
+ // Create a remote capability so we don't use the local transmission protocol.
+ capabilities.MustNewRemoteCapabilityInfo(
+ writeID,
+ capabilities.CapabilityTypeTarget,
+ "a write capability targeting polygon testnet",
+ &capabilities.DON{ID: 1},
+ ),
+ func(req capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) {
+ gotConfig = req.Config
+
+ return capabilities.CapabilityResponse{
+ Value: req.Inputs,
+ }, nil
+ },
+ )
+ require.NoError(t, reg.Add(ctx, target))
+
+ eng, testHooks := newTestEngine(
+ t,
+ reg,
+ simpleWorkflow,
+ )
+ reg.SetLocalRegistry(testConfigProvider{})
+
+ servicetest.Run(t, eng)
+
+ eid := getExecutionId(t, eng, testHooks)
+
+ state, err := eng.executionStates.Get(ctx, eid)
+ require.NoError(t, err)
+
+ assert.Equal(t, state.Status, store.StatusCompleted)
+
+ m, err := values.Unwrap(gotConfig)
+ require.NoError(t, err)
+ // The write target config contains three keys
+ assert.Len(t, m.(map[string]any), 3)
+}
diff --git a/core/services/workflows/models.go b/core/services/workflows/models.go
index 8d970dfa94f..1ff77225c4b 100644
--- a/core/services/workflows/models.go
+++ b/core/services/workflows/models.go
@@ -3,6 +3,7 @@ package workflows
import (
"errors"
"fmt"
+ "sync/atomic"
"github.com/dominikbraun/graph"
@@ -86,7 +87,8 @@ type step struct {
type triggerCapability struct {
workflows.StepDefinition
trigger capabilities.TriggerCapability
- config *values.Map
+
+ config atomic.Pointer[values.Map]
}
func Parse(yamlWorkflow string) (*workflow, error) {
diff --git a/core/services/workflows/state.go b/core/services/workflows/state.go
index 6fc61af3954..cd4247d0ee9 100644
--- a/core/services/workflows/state.go
+++ b/core/services/workflows/state.go
@@ -17,12 +17,10 @@ func copyState(es store.WorkflowExecution) store.WorkflowExecution {
for ref, step := range es.Steps {
var mval *values.Map
if step.Inputs != nil {
- mp := values.Proto(step.Inputs).GetMapValue()
- mval = values.FromMapValueProto(mp)
+ mval = step.Inputs.CopyMap()
}
- op := values.Proto(step.Outputs.Value)
- copiedov := values.FromProto(op)
+ copiedov := values.Copy(step.Outputs.Value)
newState := &store.WorkflowExecutionStep{
ExecutionID: step.ExecutionID,
diff --git a/core/services/workflows/store/store_db.go b/core/services/workflows/store/store_db.go
index e1d08629053..80ecfbb2d6e 100644
--- a/core/services/workflows/store/store_db.go
+++ b/core/services/workflows/store/store_db.go
@@ -127,7 +127,10 @@ func stepToState(step workflowStepRow) (*WorkflowExecutionStep, error) {
return nil, err
}
- inputs = values.FromMapValueProto(vmProto)
+ inputs, err = values.FromMapValueProto(vmProto)
+ if err != nil {
+ return nil, err
+ }
}
var (
@@ -146,7 +149,10 @@ func stepToState(step workflowStepRow) (*WorkflowExecutionStep, error) {
return nil, err
}
- outputs = values.FromProto(vProto)
+ outputs, err = values.FromProto(vProto)
+ if err != nil {
+ return nil, err
+ }
}
return &WorkflowExecutionStep{
diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go
index 9a8bf96573e..f4e91f0a2d2 100644
--- a/core/store/migrate/migrate_test.go
+++ b/core/store/migrate/migrate_test.go
@@ -618,3 +618,14 @@ func BenchmarkBackfillingRecordsWithMigration202(b *testing.B) {
require.NoError(b, err)
}
}
+
+func TestRollback_247_TxStateEnumUpdate(t *testing.T) {
+ ctx := testutils.Context(t)
+ _, db := heavyweight.FullTestDBV2(t, nil)
+ p, err := migrate.NewProvider(ctx, db.DB)
+ require.NoError(t, err)
+ _, err = p.DownTo(ctx, 54)
+ require.NoError(t, err)
+ _, err = p.UpTo(ctx, 247)
+ require.NoError(t, err)
+}
diff --git a/core/store/migrate/migrations/0248_add_tx_finalized_state.sql b/core/store/migrate/migrations/0248_add_tx_finalized_state.sql
new file mode 100644
index 00000000000..dcfe8eec734
--- /dev/null
+++ b/core/store/migrate/migrations/0248_add_tx_finalized_state.sql
@@ -0,0 +1,135 @@
+-- +goose Up
+-- Creating new column and enum instead of just adding new value to the existing enum so the migration changes match the rollback logic
+-- Otherwise, migration will complain about mismatching column order
+
+-- +goose StatementBegin
+-- Rename the existing enum with finalized state to mark it as old
+ALTER TYPE evm.txes_state RENAME TO txes_state_old;
+
+-- Create new enum without finalized state
+CREATE TYPE evm.txes_state AS ENUM (
+ 'unstarted',
+ 'in_progress',
+ 'fatal_error',
+ 'unconfirmed',
+ 'confirmed_missing_receipt',
+ 'confirmed',
+ 'finalized'
+);
+
+-- Add a new state column with the new enum type to the txes table
+ALTER TABLE evm.txes ADD COLUMN state_new evm.txes_state;
+
+-- Copy data from the old column to the new
+UPDATE evm.txes SET state_new = state::text::evm.txes_state;
+
+-- Drop constraints referring to old enum type on the old state column
+ALTER TABLE evm.txes ALTER COLUMN state DROP DEFAULT;
+ALTER TABLE evm.txes DROP CONSTRAINT chk_eth_txes_fsm;
+DROP INDEX IF EXISTS idx_eth_txes_state_from_address_evm_chain_id;
+DROP INDEX IF EXISTS idx_eth_txes_min_unconfirmed_nonce_for_key_evm_chain_id;
+DROP INDEX IF EXISTS idx_only_one_in_progress_tx_per_account_id_per_evm_chain_id;
+DROP INDEX IF EXISTS idx_eth_txes_unstarted_subject_id_evm_chain_id;
+
+-- Drop the old state column
+ALTER TABLE evm.txes DROP state;
+
+-- Drop the old enum type
+DROP TYPE evm.txes_state_old;
+
+-- Rename the new column name state to replace the old column
+ALTER TABLE evm.txes RENAME state_new TO state;
+
+-- Reset the state column's default
+ALTER TABLE evm.txes ALTER COLUMN state SET DEFAULT 'unstarted'::evm.txes_state, ALTER COLUMN state SET NOT NULL;
+
+-- Recreate constraint with finalized state
+ALTER TABLE evm.txes ADD CONSTRAINT chk_eth_txes_fsm CHECK (
+ state = 'unstarted'::evm.txes_state AND nonce IS NULL AND error IS NULL AND broadcast_at IS NULL AND initial_broadcast_at IS NULL
+ OR
+ state = 'in_progress'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NULL AND initial_broadcast_at IS NULL
+ OR
+ state = 'fatal_error'::evm.txes_state AND error IS NOT NULL
+ OR
+ state = 'unconfirmed'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NOT NULL AND initial_broadcast_at IS NOT NULL
+ OR
+ state = 'confirmed'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NOT NULL AND initial_broadcast_at IS NOT NULL
+ OR
+ state = 'confirmed_missing_receipt'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NOT NULL AND initial_broadcast_at IS NOT NULL
+ OR
+ state = 'finalized'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NOT NULL AND initial_broadcast_at IS NOT NULL
+) NOT VALID;
+
+-- Recreate index to include finalized state
+CREATE INDEX idx_eth_txes_state_from_address_evm_chain_id ON evm.txes(evm_chain_id, from_address, state) WHERE state <> 'confirmed'::evm.txes_state AND state <> 'finalized'::evm.txes_state;
+CREATE INDEX idx_eth_txes_min_unconfirmed_nonce_for_key_evm_chain_id ON evm.txes(evm_chain_id, from_address, nonce) WHERE state = 'unconfirmed'::evm.txes_state;
+CREATE UNIQUE INDEX idx_only_one_in_progress_tx_per_account_id_per_evm_chain_id ON evm.txes(evm_chain_id, from_address) WHERE state = 'in_progress'::evm.txes_state;
+CREATE INDEX idx_eth_txes_unstarted_subject_id_evm_chain_id ON evm.txes(evm_chain_id, subject, id) WHERE subject IS NOT NULL AND state = 'unstarted'::evm.txes_state;
+-- +goose StatementEnd
+
+-- +goose Down
+-- +goose StatementBegin
+
+-- Rename the existing enum with finalized state to mark it as old
+ALTER TYPE evm.txes_state RENAME TO txes_state_old;
+
+-- Create new enum without finalized state
+CREATE TYPE evm.txes_state AS ENUM (
+ 'unstarted',
+ 'in_progress',
+ 'fatal_error',
+ 'unconfirmed',
+ 'confirmed_missing_receipt',
+ 'confirmed'
+);
+
+-- Add a new state column with the new enum type to the txes table
+ALTER TABLE evm.txes ADD COLUMN state_new evm.txes_state;
+
+-- Update all transactions with finalized state to confirmed in the old state column
+UPDATE evm.txes SET state = 'confirmed'::evm.txes_state_old WHERE state = 'finalized'::evm.txes_state_old;
+
+-- Copy data from the old column to the new
+UPDATE evm.txes SET state_new = state::text::evm.txes_state;
+
+-- Drop constraints referring to old enum type on the old state column
+ALTER TABLE evm.txes ALTER COLUMN state DROP DEFAULT;
+ALTER TABLE evm.txes DROP CONSTRAINT chk_eth_txes_fsm;
+DROP INDEX IF EXISTS idx_eth_txes_state_from_address_evm_chain_id;
+DROP INDEX IF EXISTS idx_eth_txes_min_unconfirmed_nonce_for_key_evm_chain_id;
+DROP INDEX IF EXISTS idx_only_one_in_progress_tx_per_account_id_per_evm_chain_id;
+DROP INDEX IF EXISTS idx_eth_txes_unstarted_subject_id_evm_chain_id;
+
+-- Drop the old state column
+ALTER TABLE evm.txes DROP state;
+
+-- Drop the old enum type
+DROP TYPE evm.txes_state_old;
+
+-- Rename the new column name state to replace the old column
+ALTER TABLE evm.txes RENAME state_new TO state;
+
+-- Reset the state column's default
+ALTER TABLE evm.txes ALTER COLUMN state SET DEFAULT 'unstarted'::evm.txes_state, ALTER COLUMN state SET NOT NULL;
+
+-- Recereate constraint without finalized state
+ALTER TABLE evm.txes ADD CONSTRAINT chk_eth_txes_fsm CHECK (
+ state = 'unstarted'::evm.txes_state AND nonce IS NULL AND error IS NULL AND broadcast_at IS NULL AND initial_broadcast_at IS NULL
+ OR
+ state = 'in_progress'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NULL AND initial_broadcast_at IS NULL
+ OR
+ state = 'fatal_error'::evm.txes_state AND error IS NOT NULL
+ OR
+ state = 'unconfirmed'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NOT NULL AND initial_broadcast_at IS NOT NULL
+ OR
+ state = 'confirmed'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NOT NULL AND initial_broadcast_at IS NOT NULL
+ OR
+ state = 'confirmed_missing_receipt'::evm.txes_state AND nonce IS NOT NULL AND error IS NULL AND broadcast_at IS NOT NULL AND initial_broadcast_at IS NOT NULL
+) NOT VALID;
+
+-- Recreate index with new enum type
+CREATE INDEX idx_eth_txes_state_from_address_evm_chain_id ON evm.txes(evm_chain_id, from_address, state) WHERE state <> 'confirmed'::evm.txes_state;
+CREATE INDEX idx_eth_txes_min_unconfirmed_nonce_for_key_evm_chain_id ON evm.txes(evm_chain_id, from_address, nonce) WHERE state = 'unconfirmed'::evm.txes_state;
+CREATE UNIQUE INDEX idx_only_one_in_progress_tx_per_account_id_per_evm_chain_id ON evm.txes(evm_chain_id, from_address) WHERE state = 'in_progress'::evm.txes_state;
+CREATE INDEX idx_eth_txes_unstarted_subject_id_evm_chain_id ON evm.txes(evm_chain_id, subject, id) WHERE subject IS NOT NULL AND state = 'unstarted'::evm.txes_state;
+-- +goose StatementEnd
diff --git a/core/store/migrate/migrations/0249_registry_syncer_state.sql b/core/store/migrate/migrations/0249_registry_syncer_state.sql
new file mode 100644
index 00000000000..e34a3790a38
--- /dev/null
+++ b/core/store/migrate/migrations/0249_registry_syncer_state.sql
@@ -0,0 +1,11 @@
+-- +goose Up
+CREATE TABLE registry_syncer_states (
+ id SERIAL PRIMARY KEY,
+ data JSONB NOT NULL,
+ data_hash TEXT NOT NULL UNIQUE,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now()
+);
+-- +goose Down
+-- +goose StatementBegin
+DROP TABLE registry_syncer_states;
+-- +goose StatementEnd
diff --git a/core/store/migrate/migrations/0250_ccip_token_prices_fix.sql b/core/store/migrate/migrations/0250_ccip_token_prices_fix.sql
new file mode 100644
index 00000000000..6c6cf02b43f
--- /dev/null
+++ b/core/store/migrate/migrations/0250_ccip_token_prices_fix.sql
@@ -0,0 +1,49 @@
+-- +goose Up
+
+-- We need to re-create tables from scratch because of the unique constraint on tokens and chains selectors
+DROP TABLE ccip.observed_token_prices;
+DROP TABLE ccip.observed_gas_prices;
+
+CREATE TABLE ccip.observed_token_prices
+(
+ chain_selector NUMERIC(20, 0) NOT NULL,
+ token_addr BYTEA NOT NULL,
+ token_price NUMERIC(78, 0) NOT NULL,
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
+ PRIMARY KEY (chain_selector, token_addr)
+);
+
+CREATE TABLE ccip.observed_gas_prices
+(
+ chain_selector NUMERIC(20, 0) NOT NULL,
+ source_chain_selector NUMERIC(20, 0) NOT NULL,
+ gas_price NUMERIC(78, 0) NOT NULL,
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
+ PRIMARY KEY (chain_selector, source_chain_selector)
+);
+
+-- +goose Down
+DROP TABLE ccip.observed_token_prices;
+DROP TABLE ccip.observed_gas_prices;
+
+-- Restore state from migration 0236_ccip_prices_cache.sql
+CREATE TABLE ccip.observed_gas_prices
+(
+ chain_selector NUMERIC(20, 0) NOT NULL,
+ job_id INTEGER NOT NULL,
+ source_chain_selector NUMERIC(20, 0) NOT NULL,
+ gas_price NUMERIC(78, 0) NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
+);
+
+CREATE TABLE ccip.observed_token_prices
+(
+ chain_selector NUMERIC(20, 0) NOT NULL,
+ job_id INTEGER NOT NULL,
+ token_addr BYTEA NOT NULL,
+ token_price NUMERIC(78, 0) NOT NULL,
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
+);
+
+CREATE INDEX idx_ccip_gas_prices_chain_gas_price_timestamp ON ccip.observed_gas_prices (chain_selector, source_chain_selector, created_at DESC);
+CREATE INDEX idx_ccip_token_prices_token_price_timestamp ON ccip.observed_token_prices (chain_selector, token_addr, created_at DESC);
diff --git a/core/web/evm_transfer_controller.go b/core/web/evm_transfer_controller.go
index 88d3dead4c8..3e14aaccd3e 100644
--- a/core/web/evm_transfer_controller.go
+++ b/core/web/evm_transfer_controller.go
@@ -54,7 +54,7 @@ func (tc *EVMTransfersController) Create(c *gin.Context) {
}
if !tr.AllowHigherAmounts {
- err = ValidateEthBalanceForTransfer(c, chain, tr.FromAddress, tr.Amount)
+ err = ValidateEthBalanceForTransfer(c, chain, tr.FromAddress, tr.Amount, tr.DestinationAddress)
if err != nil {
jsonAPIError(c, http.StatusUnprocessableEntity, errors.Errorf("transaction failed: %v", err))
return
@@ -92,7 +92,7 @@ func (tc *EVMTransfersController) Create(c *gin.Context) {
}
// ValidateEthBalanceForTransfer validates that the current balance can cover the transaction amount
-func ValidateEthBalanceForTransfer(c *gin.Context, chain legacyevm.Chain, fromAddr common.Address, amount assets.Eth) error {
+func ValidateEthBalanceForTransfer(c *gin.Context, chain legacyevm.Chain, fromAddr common.Address, amount assets.Eth, toAddr common.Address) error {
var err error
var balance *big.Int
@@ -116,7 +116,7 @@ func ValidateEthBalanceForTransfer(c *gin.Context, chain legacyevm.Chain, fromAd
gasLimit := chain.Config().EVM().GasEstimator().LimitTransfer()
estimator := chain.GasEstimator()
- amountWithFees, err := estimator.GetMaxCost(c, amount, nil, gasLimit, chain.Config().EVM().GasEstimator().PriceMaxKey(fromAddr))
+ amountWithFees, err := estimator.GetMaxCost(c, amount, nil, gasLimit, chain.Config().EVM().GasEstimator().PriceMaxKey(fromAddr), &toAddr)
if err != nil {
return err
}
diff --git a/core/web/health_controller.go b/core/web/health_controller.go
index bd775671d73..ee08c39fcf1 100644
--- a/core/web/health_controller.go
+++ b/core/web/health_controller.go
@@ -69,6 +69,8 @@ func (hc *HealthController) Readyz(c *gin.Context) {
}
func (hc *HealthController) Health(c *gin.Context) {
+ _, failing := c.GetQuery("failing")
+
status := http.StatusOK
checker := hc.App.GetHealthChecker()
@@ -89,6 +91,8 @@ func (hc *HealthController) Health(c *gin.Context) {
if err != nil {
status = HealthStatusFailing
output = err.Error()
+ } else if failing {
+ continue // omit from returned data
}
checks = append(checks, presenters.Check{
diff --git a/core/web/health_controller_test.go b/core/web/health_controller_test.go
index 21da1fb2e44..14367b1e4bb 100644
--- a/core/web/health_controller_test.go
+++ b/core/web/health_controller_test.go
@@ -97,6 +97,12 @@ var (
bodyHTML string
//go:embed testdata/body/health.txt
bodyTXT string
+ //go:embed testdata/body/health-failing.json
+ bodyJSONFailing string
+ //go:embed testdata/body/health-failing.html
+ bodyHTMLFailing string
+ //go:embed testdata/body/health-failing.txt
+ bodyTXTFailing string
)
func TestHealthController_Health_body(t *testing.T) {
@@ -111,6 +117,12 @@ func TestHealthController_Health_body(t *testing.T) {
{"html", "/health", map[string]string{"Accept": gin.MIMEHTML}, bodyHTML},
{"text", "/health", map[string]string{"Accept": gin.MIMEPlain}, bodyTXT},
{".txt", "/health.txt", nil, bodyTXT},
+
+ {"default-failing", "/health?failing", nil, bodyJSONFailing},
+ {"json-failing", "/health?failing", map[string]string{"Accept": gin.MIMEJSON}, bodyJSONFailing},
+ {"html-failing", "/health?failing", map[string]string{"Accept": gin.MIMEHTML}, bodyHTMLFailing},
+ {"text-failing", "/health?failing", map[string]string{"Accept": gin.MIMEPlain}, bodyTXTFailing},
+ {".txt-failing", "/health.txt?failing", nil, bodyTXTFailing},
} {
t.Run(tc.name, func(t *testing.T) {
app := cltest.NewApplicationWithKey(t)
diff --git a/core/web/presenters/aptos_key.go b/core/web/presenters/aptos_key.go
index 6460c325f97..8c0c09ed10a 100644
--- a/core/web/presenters/aptos_key.go
+++ b/core/web/presenters/aptos_key.go
@@ -5,7 +5,8 @@ import "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/apt
// AptosKeyResource represents a Aptos key JSONAPI resource.
type AptosKeyResource struct {
JAID
- PubKey string `json:"publicKey"`
+ Account string `json:"account"`
+ PubKey string `json:"publicKey"`
}
// GetName implements the api2go EntityNamer interface
@@ -15,8 +16,9 @@ func (AptosKeyResource) GetName() string {
func NewAptosKeyResource(key aptoskey.Key) *AptosKeyResource {
r := &AptosKeyResource{
- JAID: JAID{ID: key.ID()},
- PubKey: key.PublicKeyStr(),
+ JAID: JAID{ID: key.ID()},
+ Account: key.Account(),
+ PubKey: key.PublicKeyStr(),
}
return r
diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go
index ad6bf617a82..bb518650516 100644
--- a/core/web/presenters/job.go
+++ b/core/web/presenters/job.go
@@ -468,6 +468,26 @@ func NewStandardCapabilitiesSpec(spec *job.StandardCapabilitiesSpec) *StandardCa
}
}
+type CCIPSpec struct {
+ CreatedAt time.Time `json:"createdAt"`
+ UpdatedAt time.Time `json:"updatedAt"`
+ CapabilityVersion string `json:"capabilityVersion"`
+ CapabilityLabelledName string `json:"capabilityLabelledName"`
+ OCRKeyBundleIDs map[string]interface{} `json:"ocrKeyBundleIDs"`
+ P2PKeyID string `json:"p2pKeyID"`
+}
+
+func NewCCIPSpec(spec *job.CCIPSpec) *CCIPSpec {
+ return &CCIPSpec{
+ CreatedAt: spec.CreatedAt,
+ UpdatedAt: spec.UpdatedAt,
+ CapabilityVersion: spec.CapabilityVersion,
+ CapabilityLabelledName: spec.CapabilityLabelledName,
+ OCRKeyBundleIDs: spec.OCRKeyBundleIDs,
+ P2PKeyID: spec.P2PKeyID,
+ }
+}
+
// JobError represents errors on the job
type JobError struct {
ID int64 `json:"id"`
@@ -512,6 +532,7 @@ type JobResource struct {
GatewaySpec *GatewaySpec `json:"gatewaySpec"`
WorkflowSpec *WorkflowSpec `json:"workflowSpec"`
StandardCapabilitiesSpec *StandardCapabilitiesSpec `json:"standardCapabilitiesSpec"`
+ CCIPSpec *CCIPSpec `json:"ccipSpec"`
PipelineSpec PipelineSpec `json:"pipelineSpec"`
Errors []JobError `json:"errors"`
}
@@ -562,6 +583,8 @@ func NewJobResource(j job.Job) *JobResource {
resource.WorkflowSpec = NewWorkflowSpec(j.WorkflowSpec)
case job.StandardCapabilities:
resource.StandardCapabilitiesSpec = NewStandardCapabilitiesSpec(j.StandardCapabilitiesSpec)
+ case job.CCIP:
+ resource.CCIPSpec = NewCCIPSpec(j.CCIPSpec)
case job.LegacyGasStationServer, job.LegacyGasStationSidecar:
// unsupported
}
diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go
index 5de71f918e3..75697c6e068 100644
--- a/core/web/presenters/job_test.go
+++ b/core/web/presenters/job_test.go
@@ -130,6 +130,7 @@ func TestJob(t *testing.T) {
"bootstrapSpec": null,
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -208,6 +209,7 @@ func TestJob(t *testing.T) {
"bootstrapSpec": null,
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -296,6 +298,7 @@ func TestJob(t *testing.T) {
"bootstrapSpec": null,
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -361,6 +364,7 @@ func TestJob(t *testing.T) {
"bootstrapSpec": null,
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -423,6 +427,7 @@ func TestJob(t *testing.T) {
"bootstrapSpec": null,
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -481,6 +486,7 @@ func TestJob(t *testing.T) {
"bootstrapSpec": null,
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -566,7 +572,9 @@ func TestJob(t *testing.T) {
"dotDagSource": ""
},
"gatewaySpec": null,
- "standardCapabilitiesSpec": null,
+ "standardCapabilitiesSpec": null,
+ "standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -649,6 +657,7 @@ func TestJob(t *testing.T) {
},
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -731,6 +740,7 @@ func TestJob(t *testing.T) {
},
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -780,14 +790,14 @@ func TestJob(t *testing.T) {
"blockhashStoreSpec": null,
"blockHeaderFeederSpec": null,
"bootstrapSpec": {
- "blockchainTimeout":"0s",
- "contractConfigConfirmations":0,
- "contractConfigTrackerPollInterval":"0s",
- "contractConfigTrackerSubscribeInterval":"0s",
- "contractID":"0x16988483b46e695f6c8D58e6e1461DC703e008e1",
- "createdAt":"0001-01-01T00:00:00Z",
- "relay":"evm",
- "relayConfig":{"chainID":1337},
+ "blockchainTimeout":"0s",
+ "contractConfigConfirmations":0,
+ "contractConfigTrackerPollInterval":"0s",
+ "contractConfigTrackerSubscribeInterval":"0s",
+ "contractID":"0x16988483b46e695f6c8D58e6e1461DC703e008e1",
+ "createdAt":"0001-01-01T00:00:00Z",
+ "relay":"evm",
+ "relayConfig":{"chainID":1337},
"updatedAt":"0001-01-01T00:00:00Z"
},
"pipelineSpec": {
@@ -797,6 +807,7 @@ func TestJob(t *testing.T) {
},
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": []
}
}
@@ -855,6 +866,7 @@ func TestJob(t *testing.T) {
"updatedAt":"0001-01-01T00:00:00Z"
},
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"pipelineSpec": {
"id": 1,
"jobID": 0,
@@ -919,6 +931,7 @@ func TestJob(t *testing.T) {
"bootstrapSpec": null,
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"pipelineSpec": {
"id": 1,
"jobID": 0,
@@ -979,6 +992,72 @@ func TestJob(t *testing.T) {
"createdAt":"0001-01-01T00:00:00Z",
"updatedAt":"0001-01-01T00:00:00Z"
},
+ "ccipSpec": null,
+ "pipelineSpec": {
+ "id": 1,
+ "jobID": 0,
+ "dotDagSource": ""
+ },
+ "errors": []
+ }
+ }
+ }`,
+ },
+ {
+ name: "ccip spec",
+ job: job.Job{
+ ID: 1,
+ CCIPSpec: &job.CCIPSpec{
+ ID: 3,
+ CreatedAt: timestamp,
+ UpdatedAt: timestamp,
+ CapabilityVersion: "4.5.9",
+ CapabilityLabelledName: "ccip",
+ },
+ PipelineSpec: &pipeline.Spec{
+ ID: 1,
+ DotDagSource: "",
+ },
+ ExternalJobID: uuid.MustParse("0eec7e1d-d0d2-476c-a1a8-72dfb6633f46"),
+ Type: job.CCIP,
+ SchemaVersion: 1,
+ Name: null.StringFrom("ccip test"),
+ },
+ want: `
+ {
+ "data": {
+ "type": "jobs",
+ "id": "1",
+ "attributes": {
+ "name": "ccip test",
+ "type": "ccip",
+ "schemaVersion": 1,
+ "maxTaskDuration": "0s",
+ "externalJobID": "0eec7e1d-d0d2-476c-a1a8-72dfb6633f46",
+ "directRequestSpec": null,
+ "fluxMonitorSpec": null,
+ "gasLimit": null,
+ "forwardingAllowed": false,
+ "cronSpec": null,
+ "offChainReportingOracleSpec": null,
+ "offChainReporting2OracleSpec": null,
+ "keeperSpec": null,
+ "vrfSpec": null,
+ "webhookSpec": null,
+ "workflowSpec": null,
+ "blockhashStoreSpec": null,
+ "blockHeaderFeederSpec": null,
+ "bootstrapSpec": null,
+ "gatewaySpec": null,
+ "standardCapabilitiesSpec": null,
+ "ccipSpec": {
+ "capabilityVersion":"4.5.9",
+ "capabilityLabelledName":"ccip",
+ "ocrKeyBundleIDs": null,
+ "p2pKeyID": "",
+ "createdAt":"2000-01-01T00:00:00Z",
+ "updatedAt":"2000-01-01T00:00:00Z"
+ },
"pipelineSpec": {
"id": 1,
"jobID": 0,
@@ -1058,6 +1137,7 @@ func TestJob(t *testing.T) {
"bootstrapSpec": null,
"gatewaySpec": null,
"standardCapabilitiesSpec": null,
+ "ccipSpec": null,
"errors": [{
"id": 200,
"description": "some error",
diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml
index 1bad3fd91c6..f1325d824ea 100644
--- a/core/web/resolver/testdata/config-empty-effective.toml
+++ b/core/web/resolver/testdata/config-empty-effective.toml
@@ -6,6 +6,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml
index 3e083bd1844..f67d4737b57 100644
--- a/core/web/resolver/testdata/config-full.toml
+++ b/core/web/resolver/testdata/config-full.toml
@@ -6,6 +6,7 @@ ShutdownGracePeriod = '10s'
FeedsManager = true
LogPoller = true
UICSAKeys = true
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1m0s'
@@ -290,6 +291,7 @@ OperatorFactoryAddress = '0xa5B85635Be42F21f94F28034B7DA440EeFF0F418'
RPCDefaultBatchSize = 17
RPCBlockQueryDelay = 10
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '15m0s'
[EVM.Transactions]
ForwardersEnabled = true
@@ -314,6 +316,7 @@ LimitDefault = 12
LimitMax = 17
LimitMultiplier = '1.234'
LimitTransfer = 100
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 10
BumpThreshold = 6
diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml
index f391804b7cd..55f998156c8 100644
--- a/core/web/resolver/testdata/config-multi-chain-effective.toml
+++ b/core/web/resolver/testdata/config-multi-chain-effective.toml
@@ -6,6 +6,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
@@ -277,6 +278,7 @@ OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '9m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -301,6 +303,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -376,6 +379,7 @@ OperatorFactoryAddress = '0x8007e24251b1D2Fc518Eb843A701d9cD21fe0aA3'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -400,6 +404,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -469,6 +474,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 10
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '6m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -493,6 +499,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '20 gwei'
BumpPercent = 20
BumpThreshold = 5
diff --git a/core/web/testdata/body/health-failing.html b/core/web/testdata/body/health-failing.html
new file mode 100644
index 00000000000..6b667a3ba69
--- /dev/null
+++ b/core/web/testdata/body/health-failing.html
@@ -0,0 +1,47 @@
+
+
+ EVM
+
+ 0
+
+ HeadTracker
+
+ HeadListener
+ Listener is not connected
+
+
+
+
diff --git a/core/web/testdata/body/health-failing.json b/core/web/testdata/body/health-failing.json
new file mode 100644
index 00000000000..185b98b8da5
--- /dev/null
+++ b/core/web/testdata/body/health-failing.json
@@ -0,0 +1 @@
+{"data":[{"type":"checks","id":"EVM.0.HeadTracker.HeadListener","attributes":{"name":"EVM.0.HeadTracker.HeadListener","status":"failing","output":"Listener is not connected"}}]}
diff --git a/core/web/testdata/body/health-failing.txt b/core/web/testdata/body/health-failing.txt
new file mode 100644
index 00000000000..c6b948c3f93
--- /dev/null
+++ b/core/web/testdata/body/health-failing.txt
@@ -0,0 +1,2 @@
+! EVM.0.HeadTracker.HeadListener
+ Listener is not connected
diff --git a/core/web/testdata/body/health.html b/core/web/testdata/body/health.html
index 2a1b2227530..d2b6db906b4 100644
--- a/core/web/testdata/body/health.html
+++ b/core/web/testdata/body/health.html
@@ -63,12 +63,18 @@
Confirmer
+
+ Finalizer
+
WrappedEvmEstimator
+
+ HeadReporter
+
JobSpawner
@@ -96,9 +102,6 @@
BridgeCache
-
- PromReporter
-
TelemetryManager
diff --git a/core/web/testdata/body/health.json b/core/web/testdata/body/health.json
index 10415c0abdc..81ed7ff6d11 100644
--- a/core/web/testdata/body/health.json
+++ b/core/web/testdata/body/health.json
@@ -90,6 +90,15 @@
"output": ""
}
},
+ {
+ "type": "checks",
+ "id": "EVM.0.Txm.Finalizer",
+ "attributes": {
+ "name": "EVM.0.Txm.Finalizer",
+ "status": "passing",
+ "output": ""
+ }
+ },
{
"type": "checks",
"id": "EVM.0.Txm.WrappedEvmEstimator",
@@ -99,6 +108,15 @@
"output": ""
}
},
+ {
+ "type": "checks",
+ "id": "HeadReporter",
+ "attributes": {
+ "name": "HeadReporter",
+ "status": "passing",
+ "output": ""
+ }
+ },
{
"type": "checks",
"id": "JobSpawner",
@@ -162,15 +180,6 @@
"output": ""
}
},
- {
- "type": "checks",
- "id": "PromReporter",
- "attributes": {
- "name": "PromReporter",
- "status": "passing",
- "output": ""
- }
- },
{
"type": "checks",
"id": "TelemetryManager",
diff --git a/core/web/testdata/body/health.txt b/core/web/testdata/body/health.txt
index 09c8cff6c2d..6b165d26d99 100644
--- a/core/web/testdata/body/health.txt
+++ b/core/web/testdata/body/health.txt
@@ -9,7 +9,9 @@ ok EVM.0.Txm
ok EVM.0.Txm.BlockHistoryEstimator
ok EVM.0.Txm.Broadcaster
ok EVM.0.Txm.Confirmer
+ok EVM.0.Txm.Finalizer
ok EVM.0.Txm.WrappedEvmEstimator
+ok HeadReporter
ok JobSpawner
ok Mailbox.Monitor
ok Mercury.WSRPCPool
@@ -17,5 +19,4 @@ ok Mercury.WSRPCPool.CacheSet
ok PipelineORM
ok PipelineRunner
ok PipelineRunner.BridgeCache
-ok PromReporter
ok TelemetryManager
diff --git a/docs/CONFIG.md b/docs/CONFIG.md
index 7a4d3ca62ca..32ab35b7cc0 100644
--- a/docs/CONFIG.md
+++ b/docs/CONFIG.md
@@ -51,6 +51,7 @@ ShutdownGracePeriod is the maximum time allowed to shut down gracefully. If exce
FeedsManager = true # Default
LogPoller = false # Default
UICSAKeys = false # Default
+CCIP = true # Default
```
@@ -72,6 +73,12 @@ UICSAKeys = false # Default
```
UICSAKeys enables CSA Keys in the UI.
+### CCIP
+```toml
+CCIP = true # Default
+```
+CCIP enables the CCIP service.
+
## Database
```toml
[Database]
@@ -1786,6 +1793,7 @@ OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '9m0s'
[Transactions]
ForwardersEnabled = false
@@ -1810,6 +1818,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -1879,6 +1888,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -1903,6 +1913,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -1972,6 +1983,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -1996,6 +2008,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -2065,6 +2078,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -2089,6 +2103,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -2159,6 +2174,7 @@ NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '13m0s'
[Transactions]
ForwardersEnabled = false
@@ -2183,6 +2199,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
@@ -2252,6 +2269,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -2276,6 +2294,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -2345,6 +2364,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -2369,6 +2389,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -2439,6 +2460,7 @@ OperatorFactoryAddress = '0x8007e24251b1D2Fc518Eb843A701d9cD21fe0aA3'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -2463,6 +2485,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -2532,6 +2555,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 2
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '45s'
[Transactions]
ForwardersEnabled = false
@@ -2556,6 +2580,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -2624,6 +2649,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -2648,6 +2674,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -2716,6 +2743,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -2740,6 +2768,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -2809,6 +2838,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 2
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '40s'
[Transactions]
ForwardersEnabled = false
@@ -2833,6 +2863,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -2903,6 +2934,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '2m0s'
[Transactions]
ForwardersEnabled = false
@@ -2927,6 +2959,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -2996,6 +3029,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 2
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3020,6 +3054,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -3089,6 +3124,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 10
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '6m0s'
[Transactions]
ForwardersEnabled = false
@@ -3113,6 +3149,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '20 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -3182,6 +3219,7 @@ NoNewHeadsThreshold = '12m0s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 15
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3206,6 +3244,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '20 mwei'
BumpPercent = 40
BumpThreshold = 3
@@ -3275,6 +3314,7 @@ NoNewHeadsThreshold = '6m0s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 15
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3299,6 +3339,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 mwei'
BumpPercent = 40
BumpThreshold = 3
@@ -3368,6 +3409,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 2
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3392,6 +3434,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -3461,6 +3504,7 @@ NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3485,6 +3529,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
@@ -3554,6 +3599,7 @@ NoNewHeadsThreshold = '1m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3578,6 +3624,7 @@ LimitDefault = 100000000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -3647,6 +3694,7 @@ NoNewHeadsThreshold = '1m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3671,6 +3719,7 @@ LimitDefault = 100000000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -3740,6 +3789,7 @@ NoNewHeadsThreshold = '1m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3764,6 +3814,7 @@ LimitDefault = 100000000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -3834,6 +3885,7 @@ NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3858,6 +3910,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
@@ -3927,6 +3980,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -3951,6 +4005,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -4019,6 +4074,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4043,6 +4099,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -4112,6 +4169,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4136,6 +4194,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -4205,6 +4264,7 @@ NoNewHeadsThreshold = '6m0s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 15
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4229,6 +4289,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 mwei'
BumpPercent = 40
BumpThreshold = 3
@@ -4298,6 +4359,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '40s'
[Transactions]
ForwardersEnabled = false
@@ -4322,6 +4384,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -4391,6 +4454,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '40s'
[Transactions]
ForwardersEnabled = false
@@ -4415,6 +4479,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -4483,6 +4548,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4507,6 +4573,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 0
@@ -4576,6 +4643,7 @@ NoNewHeadsThreshold = '12m0s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4600,6 +4668,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '20 mwei'
BumpPercent = 40
BumpThreshold = 3
@@ -4669,6 +4738,7 @@ NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4693,6 +4763,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
@@ -4762,6 +4833,7 @@ NoNewHeadsThreshold = '12m0s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4786,6 +4858,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '20 mwei'
BumpPercent = 40
BumpThreshold = 3
@@ -4855,6 +4928,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 2
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4879,6 +4953,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -4947,6 +5022,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -4971,6 +5047,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -5040,6 +5117,7 @@ NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '15m0s'
[Transactions]
ForwardersEnabled = false
@@ -5064,6 +5142,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
@@ -5133,6 +5212,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '2m0s'
[Transactions]
ForwardersEnabled = false
@@ -5157,6 +5237,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -5205,6 +5286,198 @@ GasLimit = 5400000
+L3X Mainnet (12324)
+
+```toml
+AutoCreateKey = true
+BlockBackfillDepth = 10
+BlockBackfillSkip = false
+ChainType = 'arbitrum'
+FinalityDepth = 10
+FinalityTagEnabled = true
+LinkContractAddress = '0x79f531a3D07214304F259DC28c7191513223bcf3'
+LogBackfillBatchSize = 1000
+LogPollInterval = '10s'
+LogKeepBlocksDepth = 100000
+LogPrunePageSize = 0
+BackupLogPollerBlockDelay = 100
+MinIncomingConfirmations = 3
+MinContractPayment = '0.00001 link'
+NonceAutoSync = true
+NoNewHeadsThreshold = '0s'
+RPCDefaultBatchSize = 250
+RPCBlockQueryDelay = 1
+FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
+
+[Transactions]
+ForwardersEnabled = false
+MaxInFlight = 16
+MaxQueued = 250
+ReaperInterval = '1h0m0s'
+ReaperThreshold = '168h0m0s'
+ResendAfterThreshold = '1m0s'
+
+[Transactions.AutoPurge]
+Enabled = false
+
+[BalanceMonitor]
+Enabled = true
+
+[GasEstimator]
+Mode = 'Arbitrum'
+PriceDefault = '100 mwei'
+PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether'
+PriceMin = '0'
+LimitDefault = 500000
+LimitMax = 1000000000
+LimitMultiplier = '1'
+LimitTransfer = 21000
+EstimateGasLimit = false
+BumpMin = '5 gwei'
+BumpPercent = 20
+BumpThreshold = 5
+EIP1559DynamicFees = false
+FeeCapDefault = '1 micro'
+TipCapDefault = '1 wei'
+TipCapMin = '1 wei'
+
+[GasEstimator.BlockHistory]
+BatchSize = 25
+BlockHistorySize = 8
+CheckInclusionBlocks = 12
+CheckInclusionPercentile = 90
+TransactionPercentile = 60
+
+[HeadTracker]
+HistoryDepth = 100
+MaxBufferSize = 3
+SamplingInterval = '1s'
+MaxAllowedFinalityDepth = 10000
+FinalityTagBypass = true
+
+[NodePool]
+PollFailureThreshold = 5
+PollInterval = '10s'
+SelectionMode = 'HighestHead'
+SyncThreshold = 5
+LeaseDuration = '0s'
+NodeIsSyncingEnabled = false
+FinalizedBlockPollInterval = '5s'
+EnforceRepeatableRead = false
+DeathDeclarationDelay = '10s'
+
+[OCR]
+ContractConfirmations = 1
+ContractTransmitterTransmitTimeout = '10s'
+DatabaseTimeout = '10s'
+DeltaCOverride = '168h0m0s'
+DeltaCJitterOverride = '1h0m0s'
+ObservationGracePeriod = '1s'
+
+[OCR2]
+[OCR2.Automation]
+GasLimit = 5400000
+```
+
+
+
+L3X Sepolia (12325)
+
+```toml
+AutoCreateKey = true
+BlockBackfillDepth = 10
+BlockBackfillSkip = false
+ChainType = 'arbitrum'
+FinalityDepth = 10
+FinalityTagEnabled = true
+LinkContractAddress = '0xa71848C99155DA0b245981E5ebD1C94C4be51c43'
+LogBackfillBatchSize = 1000
+LogPollInterval = '10s'
+LogKeepBlocksDepth = 100000
+LogPrunePageSize = 0
+BackupLogPollerBlockDelay = 100
+MinIncomingConfirmations = 3
+MinContractPayment = '0.00001 link'
+NonceAutoSync = true
+NoNewHeadsThreshold = '0s'
+RPCDefaultBatchSize = 250
+RPCBlockQueryDelay = 1
+FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
+
+[Transactions]
+ForwardersEnabled = false
+MaxInFlight = 16
+MaxQueued = 250
+ReaperInterval = '1h0m0s'
+ReaperThreshold = '168h0m0s'
+ResendAfterThreshold = '1m0s'
+
+[Transactions.AutoPurge]
+Enabled = false
+
+[BalanceMonitor]
+Enabled = true
+
+[GasEstimator]
+Mode = 'Arbitrum'
+PriceDefault = '100 mwei'
+PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether'
+PriceMin = '0'
+LimitDefault = 500000
+LimitMax = 1000000000
+LimitMultiplier = '1'
+LimitTransfer = 21000
+EstimateGasLimit = false
+BumpMin = '5 gwei'
+BumpPercent = 20
+BumpThreshold = 5
+EIP1559DynamicFees = false
+FeeCapDefault = '1 micro'
+TipCapDefault = '1 wei'
+TipCapMin = '1 wei'
+
+[GasEstimator.BlockHistory]
+BatchSize = 25
+BlockHistorySize = 8
+CheckInclusionBlocks = 12
+CheckInclusionPercentile = 90
+TransactionPercentile = 60
+
+[HeadTracker]
+HistoryDepth = 100
+MaxBufferSize = 3
+SamplingInterval = '1s'
+MaxAllowedFinalityDepth = 10000
+FinalityTagBypass = true
+
+[NodePool]
+PollFailureThreshold = 5
+PollInterval = '10s'
+SelectionMode = 'HighestHead'
+SyncThreshold = 5
+LeaseDuration = '0s'
+NodeIsSyncingEnabled = false
+FinalizedBlockPollInterval = '5s'
+EnforceRepeatableRead = false
+DeathDeclarationDelay = '10s'
+
+[OCR]
+ContractConfirmations = 1
+ContractTransmitterTransmitTimeout = '10s'
+DatabaseTimeout = '10s'
+DeltaCOverride = '168h0m0s'
+DeltaCJitterOverride = '1h0m0s'
+ObservationGracePeriod = '1s'
+
+[OCR2]
+[OCR2.Automation]
+GasLimit = 5400000
+```
+
+
+
Arbitrum Mainnet (42161)
```toml
@@ -5227,6 +5500,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -5251,6 +5525,7 @@ LimitDefault = 500000
LimitMax = 1000000000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -5320,6 +5595,7 @@ NoNewHeadsThreshold = '1m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '1m0s'
[Transactions]
ForwardersEnabled = false
@@ -5344,6 +5620,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '2 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -5413,6 +5690,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 2
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '1m0s'
[Transactions]
ForwardersEnabled = false
@@ -5437,6 +5715,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -5506,6 +5785,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 2
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '1m0s'
[Transactions]
ForwardersEnabled = false
@@ -5530,6 +5810,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -5599,6 +5880,7 @@ NoNewHeadsThreshold = '1m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '1m0s'
[Transactions]
ForwardersEnabled = false
@@ -5623,6 +5905,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '2 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -5691,6 +5974,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -5715,6 +5999,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 40
BumpThreshold = 3
@@ -5783,6 +6068,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -5807,6 +6093,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -5875,6 +6162,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -5899,6 +6187,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 40
BumpThreshold = 3
@@ -5968,6 +6257,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -5992,6 +6282,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -6061,6 +6352,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 10
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -6078,13 +6370,14 @@ Enabled = true
[GasEstimator]
Mode = 'BlockHistory'
-PriceDefault = '1 gwei'
+PriceDefault = '25 gwei'
PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether'
-PriceMin = '1 gwei'
+PriceMin = '25 gwei'
LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '20 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -6153,6 +6446,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 100
RPCBlockQueryDelay = 10
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '12m0s'
[Transactions]
ForwardersEnabled = false
@@ -6170,13 +6464,14 @@ Enabled = true
[GasEstimator]
Mode = 'BlockHistory'
-PriceDefault = '20 gwei'
+PriceDefault = '25 gwei'
PriceMax = '115792089237316195423570985008687907853269984665.640564039457584007913129639935 tether'
-PriceMin = '1 gwei'
+PriceMin = '25 gwei'
LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '20 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -6246,6 +6541,7 @@ NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -6270,6 +6566,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
@@ -6339,6 +6636,7 @@ NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '12m0s'
[Transactions]
ForwardersEnabled = false
@@ -6363,6 +6661,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
@@ -6433,6 +6732,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -6457,6 +6757,7 @@ LimitDefault = 500000
LimitMax = 1000000000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -6527,6 +6828,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -6551,6 +6853,7 @@ LimitDefault = 500000
LimitMax = 1000000000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -6620,6 +6923,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -6644,6 +6948,7 @@ LimitDefault = 500000
LimitMax = 1000000000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 5
@@ -6713,6 +7018,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -6737,6 +7043,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '1 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -6806,6 +7113,7 @@ NoNewHeadsThreshold = '0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -6830,6 +7138,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '1 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -6899,6 +7208,7 @@ NoNewHeadsThreshold = '3m0s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -6923,6 +7233,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -6992,6 +7303,7 @@ NoNewHeadsThreshold = '40s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '15m0s'
[Transactions]
ForwardersEnabled = false
@@ -7016,6 +7328,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '100 wei'
BumpPercent = 20
BumpThreshold = 3
@@ -7085,6 +7398,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -7109,6 +7423,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -7178,6 +7493,7 @@ NoNewHeadsThreshold = '30s'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '0s'
[Transactions]
ForwardersEnabled = false
@@ -7202,6 +7518,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
@@ -7287,7 +7604,7 @@ BlockBackfillSkip enables skipping of very long backfills.
ChainType = 'arbitrum' # Example
```
ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID.
-Available types: `arbitrum`, `celo`, `gnosis`, `kroma`, `metis`, `optimismBedrock`, `scroll`, `wemix`, `xlayer`, `zksync`
+Available types: `arbitrum`, `celo`, `gnosis`, `hedera`, `kroma`, `metis`, `optimismBedrock`, `scroll`, `wemix`, `xlayer`, `zksync`
### FinalityDepth
```toml
@@ -7438,6 +7755,15 @@ The latest finalized block on chain is 64, so block 63 is the latest finalized f
Block 64 will be treated as finalized by CL Node only when chain's latest finalized block is 65. As chain finalizes blocks in batches of 32,
CL Node has to wait for a whole new batch to be finalized to treat block 64 as finalized.
+### NoNewFinalizedHeadsThreshold
+```toml
+NoNewFinalizedHeadsThreshold = '0' # Default
+```
+NoNewFinalizedHeadsThreshold controls how long to wait for new finalized block before `NodePool` marks rpc endpoints as
+out-of-sync. Only applicable if `FinalityTagEnabled=true`
+
+Set to zero to disable.
+
## EVM.Transactions
```toml
[EVM.Transactions]
@@ -7554,6 +7880,7 @@ LimitDefault = 500_000 # Default
LimitMax = 500_000 # Default
LimitMultiplier = '1.0' # Default
LimitTransfer = 21_000 # Default
+EstimateGasLimit = false # Default
BumpMin = '5 gwei' # Default
BumpPercent = 20 # Default
BumpThreshold = 3 # Default
@@ -7648,6 +7975,12 @@ LimitTransfer = 21_000 # Default
```
LimitTransfer is the gas limit used for an ordinary ETH transfer.
+### EstimateGasLimit
+```toml
+EstimateGasLimit = false # Default
+```
+EstimateGasLimit enables estimating gas limits for transactions. This feature respects the gas limit provided during transaction creation as an upper bound.
+
### BumpMin
```toml
BumpMin = '5 gwei' # Default
diff --git a/go.md b/go.md
index d9ed0d0a660..f58a5e23e4c 100644
--- a/go.md
+++ b/go.md
@@ -5,11 +5,7 @@ flowchart LR
chainlink-cosmos
chainlink-solana
chainlink-starknet/relayer
- subgraph chainlink-integrations
- direction LR
- chainlink-integrations/evm/relayer
- chainlink-integrations/common
- end
+ chainlink-evm
end
subgraph products
@@ -21,13 +17,20 @@ flowchart LR
chainlink-vrf
end
+ subgraph tdh2
+ tdh2/go/tdh2
+ tdh2/go/ocr2/decryptionplugin
+ end
+
classDef outline stroke-dasharray:6,fill:none;
- class chains,products outline
+ class chains,products,tdh2 outline
chainlink/v2 --> chain-selectors
click chain-selectors href "https://github.com/smartcontractkit/chain-selectors"
chainlink/v2 --> chainlink-automation
click chainlink-automation href "https://github.com/smartcontractkit/chainlink-automation"
+ chainlink/v2 --> chainlink-ccip
+ click chainlink-ccip href "https://github.com/smartcontractkit/chainlink-ccip"
chainlink/v2 --> chainlink-common
click chainlink-common href "https://github.com/smartcontractkit/chainlink-common"
chainlink/v2 --> chainlink-cosmos
@@ -50,6 +53,8 @@ flowchart LR
click wsrpc href "https://github.com/smartcontractkit/wsrpc"
chainlink-automation --> chainlink-common
chainlink-automation --> libocr
+ chainlink-ccip --> chainlink-common
+ chainlink-ccip --> libocr
chainlink-common --> libocr
chainlink-cosmos --> chainlink-common
chainlink-cosmos --> libocr
diff --git a/go.mod b/go.mod
index 5dd79d36327..22df244575c 100644
--- a/go.mod
+++ b/go.mod
@@ -9,11 +9,12 @@ require (
github.com/NethermindEth/juno v0.3.1
github.com/NethermindEth/starknet.go v0.7.1-0.20240401080518-34a506f3cfdb
github.com/XSAM/otelsql v0.27.0
- github.com/avast/retry-go/v4 v4.5.1
+ github.com/avast/retry-go/v4 v4.6.0
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/deckarep/golang-set/v2 v2.6.0
github.com/dominikbraun/graph v0.23.0
github.com/esote/minmaxheap v1.0.0
github.com/ethereum/go-ethereum v1.13.8
@@ -67,16 +68,18 @@ require (
github.com/prometheus/prometheus v0.48.1
github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/go-internal v1.12.0
+ github.com/rs/zerolog v1.30.0
github.com/scylladb/go-reflectx v1.0.1
github.com/shirou/gopsutil/v3 v3.24.3
github.com/shopspring/decimal v1.4.0
- github.com/smartcontractkit/chain-selectors v1.0.10
+ github.com/smartcontractkit/chain-selectors v1.0.21
github.com/smartcontractkit/chainlink-automation v1.0.4
- github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1
+ github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95
+ github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45
- github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa
+ github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827
- github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e
+ github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7
github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1
@@ -92,26 +95,28 @@ require (
github.com/umbracle/ethgo v0.1.3
github.com/unrolled/secure v1.13.0
github.com/urfave/cli v1.22.14
+ github.com/wk8/go-ordered-map/v2 v2.1.8
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.49.0
go.opentelemetry.io/otel v1.28.0
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0
- golang.org/x/crypto v0.25.0
- golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7
- golang.org/x/mod v0.19.0
- golang.org/x/net v0.27.0
- golang.org/x/sync v0.7.0
- golang.org/x/term v0.22.0
- golang.org/x/text v0.16.0
+ golang.org/x/crypto v0.26.0
+ golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
+ golang.org/x/mod v0.20.0
+ golang.org/x/net v0.28.0
+ golang.org/x/sync v0.8.0
+ golang.org/x/term v0.23.0
+ golang.org/x/text v0.17.0
golang.org/x/time v0.5.0
- golang.org/x/tools v0.23.0
+ golang.org/x/tools v0.24.0
gonum.org/v1/gonum v0.15.0
google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.34.2
gopkg.in/guregu/null.v4 v4.0.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
+ k8s.io/utils v0.0.0-20230711102312-30195339c3c7
)
require (
@@ -174,7 +179,6 @@ require (
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/deckarep/golang-set/v2 v2.3.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
@@ -219,7 +223,7 @@ require (
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
- github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // indirect
+ github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
@@ -251,7 +255,7 @@ require (
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/compress v1.17.3 // indirect
+ github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
@@ -312,7 +316,6 @@ 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.4 // indirect
github.com/zondax/hid v0.9.1 // indirect
@@ -333,7 +336,7 @@ require (
go.uber.org/ratelimit v0.3.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
- golang.org/x/sys v0.22.0 // indirect
+ golang.org/x/sys v0.23.0 // indirect
google.golang.org/api v0.188.0 // indirect
google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect
diff --git a/go.sum b/go.sum
index 4f0edd8701e..13f045ef2ce 100644
--- a/go.sum
+++ b/go.sum
@@ -150,8 +150,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
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/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o=
-github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc=
+github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
+github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4=
@@ -264,6 +264,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk=
github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis=
@@ -314,8 +315,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g=
-github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
+github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
@@ -491,6 +492,7 @@ 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 v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@@ -629,8 +631,8 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ=
github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88=
-github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo=
-github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
github.com/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug=
github.com/graph-gophers/dataloader v5.0.0+incompatible/go.mod h1:jk4jk0c5ZISbKaMe8WsVopGB5/15GvGHMdMdPtwlRp4=
github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0=
@@ -834,8 +836,8 @@ github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
-github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
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=
@@ -1093,6 +1095,7 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99
github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo=
github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c=
@@ -1132,20 +1135,22 @@ 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/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/chain-selectors v1.0.21 h1:KCR9SA7PhOexaBzFieHoLv1WonwhVOPtOStpqTmLC4E=
+github.com/smartcontractkit/chain-selectors v1.0.21/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8=
github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM=
-github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1 h1:pdEpjgbZ5w/Sd5lzg/XiuC5gVyrmSovOo+3nUD46SP8=
-github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1/go.mod h1:Jg1sCTsbxg76YByI8ifpFby3FvVqISStHT8ypy9ocmY=
+github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 h1:LAgJTg9Yr/uCo2g7Krp88Dco2U45Y6sbJVl8uKoLkys=
+github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95/go.mod h1:/ZWraCBaDDgaIN1prixYcbVvIk/6HeED9+8zbWQ+TMo=
+github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5 h1:+XvRzgHlcaZYLMJ5HR3HzOjvXNmpVKQFZbuHZiRno68=
+github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5/go.mod h1:5rmU5YKBkIOwWkuNZi26sMXlBUBm6weBFXh+8BEEp2s=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 h1:NBQLtqk8zsyY4qTJs+NElI3aDFTcAo83JHvqD04EvB0=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45/go.mod h1:LV0h7QBQUpoC2UUi6TcUvcIFm1xjP/DtEcqV8+qeLUs=
-github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa h1:g75H8oh2ws52s8BekwvGQ9XvBVu3E7WM1rfiA0PN0zk=
-github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa/go.mod h1:wZvLHX/Sd9hskN51016cTFcT3G62KXVa6xbVDS7tRjc=
+github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2 h1:KH6tpCw5hu8u6UTtgll7a8mE4sIbHCbmtzHJdKuRwBw=
+github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2/go.mod h1:V/86loaFSH0dqqUEHqyXVbyNqDRSjvcf9BRomWFTljU=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 h1:BCHu4pNP6arrcHLEWx61XjLaonOd2coQNyL0NTUcaMc=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827/go.mod h1:OPX+wC2TWQsyLNpR7daMt2vMpmsNcoBxbZyGTHr6tiA=
-github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e h1:PzwzlHNv1YbJ6ZIdl/pIFRoOuOS4V4WLvjZvFUnZFL4=
-github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e/go.mod h1:hsFhop+SlQHKD+DEFjZrMJmbauT1A/wvtZIeeo4PxFU=
+github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f h1:b0Ifwk7eK3fwJ0R69Ovhv5XvZ1/TUAfHkU5Jp7wbNZ0=
+github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f/go.mod h1:Ml88TJTwZCj6yHDkAEN/EhxVutzSlk+kDZgfibRIqF0=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799 h1:HyLTySm7BR+oNfZqDTkVJ25wnmcTtxBBD31UkFL+kEM=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799/go.mod h1:UVFRacRkP7O7TQAzFmR52v5mUlxf+G1ovMlCQAB/cHU=
github.com/smartcontractkit/go-plugin v0.0.0-20240208201424-b3b91517de16 h1:TFe+FvzxClblt6qRfqEhUfa4kFQx5UobuoFGO2W4mMo=
@@ -1421,8 +1426,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
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.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
-golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
-golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
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=
@@ -1433,8 +1438,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
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-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA=
-golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
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=
@@ -1462,8 +1467,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/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.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
-golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1519,8 +1524,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
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.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
-golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
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=
@@ -1545,8 +1550,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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=
@@ -1631,8 +1636,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.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
-golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.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=
@@ -1641,8 +1646,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.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
-golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
+golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
+golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
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=
@@ -1656,8 +1661,8 @@ 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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
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=
@@ -1729,8 +1734,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
-golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1911,6 +1916,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
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=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
+k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI5yiP5WwlfDoIyc=
+k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk=
diff --git a/heroku.yml b/heroku.yml
deleted file mode 100644
index bb95afa1213..00000000000
--- a/heroku.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-build:
- docker:
- web: Dockerfile.web
- config:
- REACT_APP_INFURA_KEY:
- REACT_APP_GA_ID:
diff --git a/integration-tests/README.md b/integration-tests/README.md
index fcfefe97a73..1510c8c91b7 100644
--- a/integration-tests/README.md
+++ b/integration-tests/README.md
@@ -27,6 +27,8 @@ version = "your tag"
The `./testconfig/overrides.toml` file **should never be committed** and has been added to the [.gitignore](../.gitignore) file as it can often contain secrets like private keys and RPC URLs.
+For more information on how to configure the tests, see the [testconfig README](./testconfig/README.md).
+
## Build
If you'd like to run the tests on a local build of Chainlink, you can point to your own docker image, or build a fresh one with `make`.
@@ -76,8 +78,7 @@ make test_soak_ocr_reorg_2
Run reorg/automation_reorg_test.go with reorg settings:
-1. Use Simulated Geth network and put GethReorgConfig in overrides.toml
-
+1. Use Simulated Geth network and put GethReorgConfig in overrides.toml
```toml
[Network]
@@ -128,3 +129,9 @@ Run soak/ocr_test.go with RPC network chaos by bringing down network to RPC node
```bash
make test_soak_ocr_rpc_down_half_cl_nodes
```
+
+### Debugging HTTP and RPC clients
+```bash
+export SETH_LOG_LEVEL=debug
+export RESTY_DEBUG=true
+```
diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go
index 65db18ad6f7..b274b59416b 100644
--- a/integration-tests/actions/actions.go
+++ b/integration-tests/actions/actions.go
@@ -27,6 +27,7 @@ import (
"github.com/smartcontractkit/chainlink-testing-framework/utils/conversions"
"github.com/smartcontractkit/chainlink/integration-tests/contracts"
ethContracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum"
+ "github.com/smartcontractkit/chainlink/integration-tests/wrappers"
"github.com/ethereum/go-ethereum/accounts/abi"
@@ -1024,18 +1025,42 @@ func SendLinkFundsToDeploymentAddresses(
toTransferToMultiCallContract := big.NewInt(0).Mul(linkAmountPerUpkeep, big.NewInt(int64(totalUpkeeps+concurrency)))
toTransferPerClient := big.NewInt(0).Mul(linkAmountPerUpkeep, big.NewInt(int64(operationsPerAddress+1)))
- err := linkToken.Transfer(multicallAddress.Hex(), toTransferToMultiCallContract)
+
+ // As a hack we use the geth wrapper directly, because we need to access receipt to get block number, which we will use to query the balance
+ // This is needed as querying with 'latest' block number very rarely, but still, return stale balance. That's happening even though we wait for
+ // the transaction to be mined.
+ linkInstance, err := link_token_interface.NewLinkToken(common.HexToAddress(linkToken.Address()), wrappers.MustNewWrappedContractBackend(nil, chainClient))
if err != nil {
- return errors.Wrapf(err, "Error transferring LINK to multicall contract")
+ return err
+ }
+
+ tx, err := chainClient.Decode(linkInstance.Transfer(chainClient.NewTXOpts(), multicallAddress, toTransferToMultiCallContract))
+ if err != nil {
+ return err
+ }
+
+ if tx.Receipt == nil {
+ return fmt.Errorf("transaction receipt for LINK transfer to multicall contract is nil")
}
- balance, err := linkToken.BalanceOf(context.Background(), multicallAddress.Hex())
+ multiBalance, err := linkInstance.BalanceOf(&bind.CallOpts{From: chainClient.Addresses[0], BlockNumber: tx.Receipt.BlockNumber}, multicallAddress)
if err != nil {
return errors.Wrapf(err, "Error getting LINK balance of multicall contract")
}
- if balance.Cmp(toTransferToMultiCallContract) < 0 {
- return fmt.Errorf("Incorrect LINK balance of multicall contract. Expected at least: %s. Got: %s", toTransferToMultiCallContract.String(), balance.String())
+ // Old code that's querying latest block
+ //err := linkToken.Transfer(multicallAddress.Hex(), toTransferToMultiCallContract)
+ //if err != nil {
+ // return errors.Wrapf(err, "Error transferring LINK to multicall contract")
+ //}
+ //
+ //balance, err := linkToken.BalanceOf(context.Background(), multicallAddress.Hex())
+ //if err != nil {
+ // return errors.Wrapf(err, "Error getting LINK balance of multicall contract")
+ //}
+
+ if multiBalance.Cmp(toTransferToMultiCallContract) < 0 {
+ return fmt.Errorf("Incorrect LINK balance of multicall contract. Expected at least: %s. Got: %s", toTransferToMultiCallContract.String(), multiBalance.String())
}
// Transfer LINK to ephemeral keys
@@ -1060,18 +1085,24 @@ func SendLinkFundsToDeploymentAddresses(
}
boundContract := bind.NewBoundContract(multicallAddress, multiCallABI, chainClient.Client, chainClient.Client, chainClient.Client)
// call aggregate3 to group all msg call data and send them in a single transaction
- _, err = chainClient.Decode(boundContract.Transact(chainClient.NewTXOpts(), "aggregate3", call))
+ ephemeralTx, err := chainClient.Decode(boundContract.Transact(chainClient.NewTXOpts(), "aggregate3", call))
if err != nil {
return errors.Wrapf(err, "Error calling Multicall contract")
}
+ if ephemeralTx.Receipt == nil {
+ return fmt.Errorf("transaction receipt for LINK transfer to ephemeral keys is nil")
+ }
+
for i := 1; i <= concurrency; i++ {
- balance, err := linkToken.BalanceOf(context.Background(), chainClient.Addresses[i].Hex())
+ ephemeralBalance, err := linkInstance.BalanceOf(&bind.CallOpts{From: chainClient.Addresses[0], BlockNumber: ephemeralTx.Receipt.BlockNumber}, chainClient.Addresses[i])
+ // Old code that's querying latest block, for now we prefer to use block number from the transaction receipt
+ //balance, err := linkToken.BalanceOf(context.Background(), chainClient.Addresses[i].Hex())
if err != nil {
return errors.Wrapf(err, "Error getting LINK balance of ephemeral key %d", i)
}
- if balance.Cmp(toTransferPerClient) < 0 {
- return fmt.Errorf("Incorrect LINK balance after transfer. Ephemeral key %d. Expected: %s. Got: %s", i, toTransferPerClient.String(), balance.String())
+ if ephemeralBalance.Cmp(toTransferPerClient) < 0 {
+ return fmt.Errorf("Incorrect LINK balance after transfer. Ephemeral key %d. Expected: %s. Got: %s", i, toTransferPerClient.String(), ephemeralBalance.String())
}
}
@@ -1216,7 +1247,7 @@ func RandBool() bool {
return rand.Intn(2) == 1
}
-func ContinuouslyGenerateTXsOnChain(sethClient *seth.Client, stopChannel chan bool, l zerolog.Logger) (bool, error) {
+func ContinuouslyGenerateTXsOnChain(sethClient *seth.Client, stopChannel chan bool, wg *sync.WaitGroup, l zerolog.Logger) (bool, error) {
counterContract, err := contracts.DeployCounterContract(sethClient)
if err != nil {
return false, err
@@ -1230,6 +1261,10 @@ func ContinuouslyGenerateTXsOnChain(sethClient *seth.Client, stopChannel chan bo
select {
case <-stopChannel:
l.Info().Str("Number of generated transactions on chain", count.String()).Msg("Stopping generating txs on chain. Desired block number reached.")
+ sleepDuration := time.Second * 10
+ l.Info().Str("Waiting for", sleepDuration.String()).Msg("Waiting for transactions to be mined and avoid nonce issues")
+ time.Sleep(sleepDuration)
+ wg.Done()
return true, nil
default:
err = counterContract.Increment()
diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go
index 05c4501fbe6..3e552371f98 100644
--- a/integration-tests/actions/automation_ocr_helpers.go
+++ b/integration-tests/actions/automation_ocr_helpers.go
@@ -438,7 +438,7 @@ func deployRegistry(
wethToken contracts.WETHToken,
ethUSDFeed contracts.MockETHUSDFeed,
) contracts.KeeperRegistry {
- ef, err := contracts.DeployMockETHLINKFeed(client, big.NewInt(2e18))
+ ef, err := contracts.DeployMockLINKETHFeed(client, big.NewInt(2e18))
require.NoError(t, err, "Deploying mock ETH-Link feed shouldn't fail")
gf, err := contracts.DeployMockGASFeed(client, big.NewInt(2e11))
require.NoError(t, err, "Deploying mock gas feed shouldn't fail")
diff --git a/integration-tests/actions/automationv2/actions.go b/integration-tests/actions/automationv2/actions.go
index 40caf15917b..9075b863b65 100644
--- a/integration-tests/actions/automationv2/actions.go
+++ b/integration-tests/actions/automationv2/actions.go
@@ -62,8 +62,9 @@ type AutomationTest struct {
LinkToken contracts.LinkToken
Transcoder contracts.UpkeepTranscoder
- EthLinkFeed contracts.MockETHLINKFeed
- EthUSDFeed contracts.MockETHUSDFeed
+ LINKETHFeed contracts.MockLINKETHFeed
+ ETHUSDFeed contracts.MockETHUSDFeed
+ LINKUSDFeed contracts.MockETHUSDFeed
WETHToken contracts.WETHToken
GasFeed contracts.MockGasFeed
Registry contracts.KeeperRegistry
@@ -192,31 +193,30 @@ func (a *AutomationTest) LoadTranscoder(address string) error {
return nil
}
-func (a *AutomationTest) DeployEthLinkFeed() error {
- ethLinkFeed, err := contracts.DeployMockETHLINKFeed(a.ChainClient, a.RegistrySettings.FallbackLinkPrice)
+func (a *AutomationTest) DeployLinkEthFeed() error {
+ ethLinkFeed, err := contracts.DeployMockLINKETHFeed(a.ChainClient, a.RegistrySettings.FallbackLinkPrice)
if err != nil {
return err
}
- a.EthLinkFeed = ethLinkFeed
+ a.LINKETHFeed = ethLinkFeed
return nil
}
-func (a *AutomationTest) LoadEthLinkFeed(address string) error {
- ethLinkFeed, err := contracts.LoadMockETHLINKFeed(a.ChainClient, common.HexToAddress(address))
+func (a *AutomationTest) LoadLinkEthFeed(address string) error {
+ ethLinkFeed, err := contracts.LoadMockLINKETHFeed(a.ChainClient, common.HexToAddress(address))
if err != nil {
return err
}
- a.EthLinkFeed = ethLinkFeed
+ a.LINKETHFeed = ethLinkFeed
return nil
}
func (a *AutomationTest) DeployEthUSDFeed() error {
- // FallbackLinkPrice and FallbackETHPrice are the same
ethUSDFeed, err := contracts.DeployMockETHUSDFeed(a.ChainClient, a.RegistrySettings.FallbackLinkPrice)
if err != nil {
return err
}
- a.EthUSDFeed = ethUSDFeed
+ a.ETHUSDFeed = ethUSDFeed
return nil
}
@@ -225,7 +225,25 @@ func (a *AutomationTest) LoadEthUSDFeed(address string) error {
if err != nil {
return err
}
- a.EthUSDFeed = ethUSDFeed
+ a.ETHUSDFeed = ethUSDFeed
+ return nil
+}
+
+func (a *AutomationTest) DeployLinkUSDFeed() error {
+ linkUSDFeed, err := contracts.DeployMockETHUSDFeed(a.ChainClient, a.RegistrySettings.FallbackLinkPrice)
+ if err != nil {
+ return err
+ }
+ a.LINKUSDFeed = linkUSDFeed
+ return nil
+}
+
+func (a *AutomationTest) LoadLinkUSDFeed(address string) error {
+ linkUSDFeed, err := contracts.LoadMockETHUSDFeed(a.ChainClient, common.HexToAddress(address))
+ if err != nil {
+ return err
+ }
+ a.LINKUSDFeed = linkUSDFeed
return nil
}
@@ -269,13 +287,13 @@ func (a *AutomationTest) DeployRegistry() error {
registryOpts := &contracts.KeeperRegistryOpts{
RegistryVersion: a.RegistrySettings.RegistryVersion,
LinkAddr: a.LinkToken.Address(),
- ETHFeedAddr: a.EthLinkFeed.Address(),
+ ETHFeedAddr: a.LINKETHFeed.Address(),
GasFeedAddr: a.GasFeed.Address(),
TranscoderAddr: a.Transcoder.Address(),
RegistrarAddr: utils.ZeroAddress.Hex(),
Settings: a.RegistrySettings,
- LinkUSDFeedAddr: a.EthUSDFeed.Address(),
- NativeUSDFeedAddr: a.EthUSDFeed.Address(),
+ LinkUSDFeedAddr: a.ETHUSDFeed.Address(),
+ NativeUSDFeedAddr: a.LINKUSDFeed.Address(),
WrappedNativeAddr: a.WETHToken.Address(),
}
registry, err := contracts.DeployKeeperRegistry(a.ChainClient, registryOpts)
@@ -563,7 +581,7 @@ func (a *AutomationTest) SetConfigOnRegistry() error {
{
GasFeePPB: 100,
FlatFeeMilliCents: big.NewInt(500),
- PriceFeed: common.HexToAddress(a.EthUSDFeed.Address()), // ETH/USD feed and LINK/USD feed are the same
+ PriceFeed: common.HexToAddress(a.ETHUSDFeed.Address()),
Decimals: 18,
FallbackPrice: big.NewInt(1000),
MinSpend: big.NewInt(200),
@@ -571,7 +589,7 @@ func (a *AutomationTest) SetConfigOnRegistry() error {
{
GasFeePPB: 100,
FlatFeeMilliCents: big.NewInt(500),
- PriceFeed: common.HexToAddress(a.EthUSDFeed.Address()), // ETH/USD feed and LINK/USD feed are the same
+ PriceFeed: common.HexToAddress(a.LINKUSDFeed.Address()),
Decimals: 18,
FallbackPrice: big.NewInt(1000),
MinSpend: big.NewInt(200),
@@ -853,14 +871,17 @@ func (a *AutomationTest) SetupAutomationDeployment(t *testing.T) {
err = a.DeployWETH()
require.NoError(t, err, "Error deploying weth token contract")
- err = a.DeployEthLinkFeed()
- require.NoError(t, err, "Error deploying eth link feed contract")
+ err = a.DeployLinkEthFeed()
+ require.NoError(t, err, "Error deploying link eth feed contract")
err = a.DeployGasFeed()
require.NoError(t, err, "Error deploying gas feed contract")
err = a.DeployEthUSDFeed()
require.NoError(t, err, "Error deploying eth usd feed contract")
+ err = a.DeployLinkUSDFeed()
+ require.NoError(t, err, "Error deploying link usd feed contract")
+
err = a.DeployTranscoder()
require.NoError(t, err, "Error deploying transcoder contract")
@@ -873,7 +894,7 @@ func (a *AutomationTest) SetupAutomationDeployment(t *testing.T) {
}
func (a *AutomationTest) LoadAutomationDeployment(t *testing.T, linkTokenAddress,
- ethLinkFeedAddress, gasFeedAddress, transcoderAddress, registryAddress, registrarAddress string) {
+ linkEthFeedAddress, linkUsdFeedAddress, EthUsdFeedAddress, gasFeedAddress, transcoderAddress, registryAddress, registrarAddress string) {
l := logging.GetTestLogger(t)
err := a.CollectNodeDetails()
require.NoError(t, err, "Error collecting node details")
@@ -883,10 +904,14 @@ func (a *AutomationTest) LoadAutomationDeployment(t *testing.T, linkTokenAddress
err = a.LoadLINK(linkTokenAddress)
require.NoError(t, err, "Error loading link token contract")
- err = a.LoadEthLinkFeed(ethLinkFeedAddress)
- require.NoError(t, err, "Error loading eth link feed contract")
+ err = a.LoadLinkEthFeed(linkEthFeedAddress)
+ require.NoError(t, err, "Error loading link eth feed contract")
err = a.LoadEthGasFeed(gasFeedAddress)
require.NoError(t, err, "Error loading gas feed contract")
+ err = a.LoadEthUSDFeed(EthUsdFeedAddress)
+ require.NoError(t, err, "Error loading eth usd feed contract")
+ err = a.LoadLinkUSDFeed(linkUsdFeedAddress)
+ require.NoError(t, err, "Error loading link usd feed contract")
err = a.LoadTranscoder(transcoderAddress)
require.NoError(t, err, "Error loading transcoder contract")
err = a.LoadRegistry(registryAddress)
diff --git a/integration-tests/actions/keeper_helpers.go b/integration-tests/actions/keeper_helpers.go
index ee1662cc180..618ca969334 100644
--- a/integration-tests/actions/keeper_helpers.go
+++ b/integration-tests/actions/keeper_helpers.go
@@ -81,7 +81,7 @@ func DeployKeeperContracts(
client *seth.Client,
linkFundsForEachUpkeep *big.Int,
) (contracts.KeeperRegistry, contracts.KeeperRegistrar, []contracts.KeeperConsumer, []*big.Int) {
- ef, err := contracts.DeployMockETHLINKFeed(client, big.NewInt(2e18))
+ ef, err := contracts.DeployMockLINKETHFeed(client, big.NewInt(2e18))
require.NoError(t, err, "Deploying mock ETH-Link feed shouldn't fail")
gf, err := contracts.DeployMockGASFeed(client, big.NewInt(2e11))
require.NoError(t, err, "Deploying mock gas feed shouldn't fail")
@@ -136,7 +136,7 @@ func DeployPerformanceKeeperContracts(
checkGasToBurn, // How much gas should be burned on checkUpkeep() calls
performGasToBurn int64, // How much gas should be burned on performUpkeep() calls
) (contracts.KeeperRegistry, contracts.KeeperRegistrar, []contracts.KeeperConsumerPerformance, []*big.Int) {
- ef, err := contracts.DeployMockETHLINKFeed(chainClient, big.NewInt(2e18))
+ ef, err := contracts.DeployMockLINKETHFeed(chainClient, big.NewInt(2e18))
require.NoError(t, err, "Deploying mock ETH-Link feed shouldn't fail")
gf, err := contracts.DeployMockGASFeed(chainClient, big.NewInt(2e11))
require.NoError(t, err, "Deploying mock gas feed shouldn't fail")
@@ -196,7 +196,7 @@ func DeployPerformDataCheckerContracts(
linkFundsForEachUpkeep *big.Int,
expectedData []byte,
) (contracts.KeeperRegistry, contracts.KeeperRegistrar, []contracts.KeeperPerformDataChecker, []*big.Int) {
- ef, err := contracts.DeployMockETHLINKFeed(chainClient, big.NewInt(2e18))
+ ef, err := contracts.DeployMockLINKETHFeed(chainClient, big.NewInt(2e18))
require.NoError(t, err, "Deploying mock ETH-Link feed shouldn't fail")
gf, err := contracts.DeployMockGASFeed(chainClient, big.NewInt(2e11))
require.NoError(t, err, "Deploying mock gas feed shouldn't fail")
diff --git a/integration-tests/actions/private_network.go b/integration-tests/actions/private_network.go
index 70239a60060..f10371d41a6 100644
--- a/integration-tests/actions/private_network.go
+++ b/integration-tests/actions/private_network.go
@@ -4,6 +4,7 @@ import (
"github.com/rs/zerolog"
ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
+ ctf_config_types "github.com/smartcontractkit/chainlink-testing-framework/config/types"
ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env"
)
@@ -12,8 +13,8 @@ func EthereumNetworkConfigFromConfig(l zerolog.Logger, config ctf_config.GlobalT
l.Warn().Msg("No TOML private ethereum network config found, will use old geth")
ethBuilder := ctf_test_env.NewEthereumNetworkBuilder()
network, err = ethBuilder.
- WithEthereumVersion(ctf_config.EthereumVersion_Eth1).
- WithExecutionLayer(ctf_config.ExecutionLayer_Geth).
+ WithEthereumVersion(ctf_config_types.EthereumVersion_Eth1).
+ WithExecutionLayer(ctf_config_types.ExecutionLayer_Geth).
Build()
return
diff --git a/integration-tests/actions/vrf/common/actions.go b/integration-tests/actions/vrf/common/actions.go
index e599c705ef0..e1bda549e71 100644
--- a/integration-tests/actions/vrf/common/actions.go
+++ b/integration-tests/actions/vrf/common/actions.go
@@ -10,6 +10,8 @@ import (
"testing"
"time"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
+
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/go-resty/resty/v2"
@@ -19,7 +21,7 @@ import (
ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env"
"github.com/smartcontractkit/chainlink-testing-framework/utils/conversions"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext"
"github.com/smartcontractkit/chainlink/integration-tests/actions"
"github.com/smartcontractkit/chainlink/integration-tests/client"
@@ -366,7 +368,7 @@ func BuildNewCLEnvForVRF(l zerolog.Logger, t *testing.T, envConfig VRFEnvConfig,
if err != nil {
return nil, nil, fmt.Errorf("%s, err: %w", "error getting first evm network", err)
}
- sethClient, err := seth_utils.GetChainClient(envConfig.TestConfig, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, envConfig.TestConfig, evmNetwork)
if err != nil {
return nil, nil, fmt.Errorf("%s, err: %w", "error getting seth client", err)
}
@@ -384,6 +386,35 @@ func BuildNewCLEnvForVRF(l zerolog.Logger, t *testing.T, envConfig VRFEnvConfig,
return env, sethClient, nil
}
+func LoadExistingCLEnvForVRF(
+ t *testing.T,
+ envConfig VRFEnvConfig,
+ commonExistingEnvConfig *vrf_common_config.ExistingEnvConfig,
+ l zerolog.Logger,
+) (*test_env.CLClusterTestEnv, *seth.Client, error) {
+ env, err := test_env.NewCLTestEnvBuilder().
+ WithTestInstance(t).
+ WithTestConfig(&envConfig.TestConfig).
+ WithCustomCleanup(envConfig.CleanupFn).
+ Build()
+ if err != nil {
+ return nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err)
+ }
+ evmNetwork, err := env.GetFirstEvmNetwork()
+ if err != nil {
+ return nil, nil, err
+ }
+ sethClient, err := utils.TestAwareSethClient(t, envConfig.TestConfig, evmNetwork)
+ if err != nil {
+ return nil, nil, err
+ }
+ err = FundNodesIfNeeded(testcontext.Get(t), commonExistingEnvConfig, sethClient, l)
+ if err != nil {
+ return nil, nil, err
+ }
+ return env, sethClient, nil
+}
+
func GetRPCUrl(env *test_env.CLClusterTestEnv, chainID int64) (string, error) {
provider, err := env.GetRpcProvider(chainID)
if err != nil {
@@ -399,7 +430,7 @@ type RPCRawClient struct {
}
func NewRPCRawClient(url string) *RPCRawClient {
- isDebug := os.Getenv("DEBUG_RESTY") == "true"
+ isDebug := os.Getenv("RESTY_DEBUG") == "true"
restyClient := resty.New().SetDebug(isDebug).SetBaseURL(url)
return &RPCRawClient{
resty: restyClient,
diff --git a/integration-tests/actions/vrf/common/models.go b/integration-tests/actions/vrf/common/models.go
index 9baa5c96e1d..f51fd84ba07 100644
--- a/integration-tests/actions/vrf/common/models.go
+++ b/integration-tests/actions/vrf/common/models.go
@@ -55,6 +55,7 @@ type VRFContracts struct {
VRFV2PlusConsumer []contracts.VRFv2PlusLoadTestConsumer
LinkToken contracts.LinkToken
MockETHLINKFeed contracts.VRFMockETHLINKFeed
+ LinkNativeFeedAddress string
}
type VRFOwnerConfig struct {
diff --git a/integration-tests/actions/vrf/vrfv2/contract_steps.go b/integration-tests/actions/vrf/vrfv2/contract_steps.go
index 324b65b5d6c..1b909be9b83 100644
--- a/integration-tests/actions/vrf/vrfv2/contract_steps.go
+++ b/integration-tests/actions/vrf/vrfv2/contract_steps.go
@@ -635,7 +635,7 @@ func SetupNewConsumersAndSubs(
) ([]contracts.VRFv2LoadTestConsumer, []uint64, error) {
consumers, err := DeployVRFV2Consumers(sethClient, coordinator.Address(), numberOfConsumerContractsToDeployAndAddToSub)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
l.Info().
Str("Coordinator", *testConfig.VRFv2.ExistingEnvConfig.ExistingEnvConfig.CoordinatorAddress).
@@ -649,7 +649,7 @@ func SetupNewConsumersAndSubs(
numberOfSubToCreate,
)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
return consumers, subIDs, nil
}
diff --git a/integration-tests/actions/vrf/vrfv2/setup_steps.go b/integration-tests/actions/vrf/vrfv2/setup_steps.go
index c13aed807a9..c025a563046 100644
--- a/integration-tests/actions/vrf/vrfv2/setup_steps.go
+++ b/integration-tests/actions/vrf/vrfv2/setup_steps.go
@@ -8,8 +8,6 @@ import (
"github.com/smartcontractkit/seth"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
-
"github.com/ethereum/go-ethereum/common"
"github.com/rs/zerolog"
"golang.org/x/sync/errgroup"
@@ -371,38 +369,30 @@ func SetupVRFV2ForNewEnv(
func SetupVRFV2ForExistingEnv(t *testing.T, envConfig vrfcommon.VRFEnvConfig, l zerolog.Logger) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, *seth.Client, error) {
commonExistingEnvConfig := envConfig.TestConfig.VRFv2.ExistingEnvConfig.ExistingEnvConfig
- env, err := test_env.NewCLTestEnvBuilder().
- WithTestInstance(t).
- WithTestConfig(&envConfig.TestConfig).
- WithCustomCleanup(envConfig.CleanupFn).
- Build()
- if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err)
- }
- evmNetwork, err := env.GetFirstEvmNetwork()
- if err != nil {
- return nil, nil, nil, nil, err
- }
- sethClient, err := seth_utils.GetChainClient(envConfig.TestConfig, *evmNetwork)
+ env, sethClient, err := vrfcommon.LoadExistingCLEnvForVRF(
+ t,
+ envConfig,
+ commonExistingEnvConfig,
+ l,
+ )
if err != nil {
- return nil, nil, nil, nil, err
+ return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading existing CL env", err)
}
- coordinator, err := contracts.LoadVRFCoordinatorV2(sethClient, *commonExistingEnvConfig.ConsumerAddress)
+ coordinator, err := contracts.LoadVRFCoordinatorV2(sethClient, *commonExistingEnvConfig.CoordinatorAddress)
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading VRFCoordinator2", err)
}
- linkAddr := common.HexToAddress(*commonExistingEnvConfig.LinkAddress)
- linkToken, err := contracts.LoadLinkTokenContract(l, sethClient, linkAddr)
+ linkAddress, err := coordinator.GetLinkAddress(testcontext.Get(t))
if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading LinkToken", err)
+ return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error getting Link address from Coordinator", err)
}
- err = vrfcommon.FundNodesIfNeeded(testcontext.Get(t), commonExistingEnvConfig, sethClient, l)
+ linkToken, err := contracts.LoadLinkTokenContract(l, sethClient, common.HexToAddress(linkAddress.String()))
if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading LinkToken", err)
}
blockHashStoreAddress, err := coordinator.GetBlockHashStoreAddress(testcontext.Get(t))
if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, nil, nil, err
}
blockHashStore, err := contracts.LoadBlockHashStore(sethClient, blockHashStoreAddress.String())
if err != nil {
@@ -449,13 +439,13 @@ func SetupSubsAndConsumersForExistingEnv(
l,
)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
} else {
addr := common.HexToAddress(*commonExistingEnvConfig.ConsumerAddress)
consumer, err := contracts.LoadVRFv2LoadTestConsumer(sethClient, addr)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
consumers = append(consumers, consumer)
subIDs = append(subIDs, *testConfig.VRFv2.ExistingEnvConfig.SubID)
@@ -471,7 +461,7 @@ func SetupSubsAndConsumersForExistingEnv(
l,
)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, 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
index 479b00d952e..5a4ec9ba11a 100644
--- a/integration-tests/actions/vrf/vrfv2plus/contract_steps.go
+++ b/integration-tests/actions/vrf/vrfv2plus/contract_steps.go
@@ -56,7 +56,7 @@ func DeployVRFV2_5Contracts(
}
batchCoordinator, err := contracts.DeployBatchVRFCoordinatorV2Plus(chainClient, coordinator.Address())
if err != nil {
- return nil, fmt.Errorf("%s, err %w", ErrDeployBatchCoordinatorV2Plus, err)
+ return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployBatchCoordinatorV2Plus, err)
}
return &vrfcommon.VRFContracts{
CoordinatorV2Plus: coordinator,
@@ -407,7 +407,7 @@ func DeployVRFV2PlusDirectFundingContracts(
linkTokenAddress string,
linkEthFeedAddress string,
coordinator contracts.VRFCoordinatorV2_5,
- consumerContractsAmount int,
+ numberOfConsumerContracts int,
wrapperSubId *big.Int,
configGeneral *vrfv2plusconfig.General,
) (*VRFV2PlusWrapperContracts, error) {
@@ -432,7 +432,7 @@ func DeployVRFV2PlusDirectFundingContracts(
return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployWrapper, err)
}
}
- consumers, err := DeployVRFV2PlusWrapperConsumers(sethClient, vrfv2PlusWrapper, consumerContractsAmount)
+ consumers, err := DeployVRFV2PlusWrapperConsumers(sethClient, vrfv2PlusWrapper, numberOfConsumerContracts)
if err != nil {
return nil, err
}
@@ -545,9 +545,9 @@ func WaitRandomWordsFulfilledEvent(
return randomWordsFulfilledEvent, err
}
-func DeployVRFV2PlusWrapperConsumers(client *seth.Client, vrfV2PlusWrapper contracts.VRFV2PlusWrapper, consumerContractsAmount int) ([]contracts.VRFv2PlusWrapperLoadTestConsumer, error) {
+func DeployVRFV2PlusWrapperConsumers(client *seth.Client, vrfV2PlusWrapper contracts.VRFV2PlusWrapper, numberOfConsumerContracts int) ([]contracts.VRFv2PlusWrapperLoadTestConsumer, error) {
var consumers []contracts.VRFv2PlusWrapperLoadTestConsumer
- for i := 1; i <= consumerContractsAmount; i++ {
+ for i := 1; i <= numberOfConsumerContracts; i++ {
loadTestConsumer, err := contracts.DeployVRFV2PlusWrapperLoadTestConsumer(client, vrfV2PlusWrapper.Address())
if err != nil {
return nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrAdvancedConsumer, err)
@@ -609,7 +609,7 @@ func SetupNewConsumersAndSubs(
) ([]contracts.VRFv2PlusLoadTestConsumer, []*big.Int, error) {
consumers, err := DeployVRFV2PlusConsumers(sethClient, coordinator, consumerContractsAmount)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
l.Info().
Str("Coordinator", *testConfig.VRFv2Plus.ExistingEnvConfig.ExistingEnvConfig.CoordinatorAddress).
@@ -627,7 +627,7 @@ func SetupNewConsumersAndSubs(
*testConfig.VRFv2Plus.General.SubscriptionBillingType,
)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
return consumers, subIDs, nil
}
@@ -652,3 +652,57 @@ func CancelSubsAndReturnFunds(ctx context.Context, vrfContracts *vrfcommon.VRFCo
}
}
}
+
+func FundWrapperConsumer(
+ sethClient *seth.Client,
+ subFundingType string,
+ linkToken contracts.LinkToken,
+ wrapperConsumer contracts.VRFv2PlusWrapperLoadTestConsumer,
+ vrfv2PlusConfig *vrfv2plusconfig.General,
+ l zerolog.Logger,
+) error {
+ fundConsumerWithLink := func() error {
+ //fund consumer with Link
+ linkAmount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2PlusConfig.WrapperConsumerFundingAmountLink))
+ l.Info().
+ Str("Link Amount", linkAmount.String()).
+ Str("WrapperConsumerAddress", wrapperConsumer.Address()).Msg("Funding WrapperConsumer with Link")
+ return linkToken.Transfer(
+ wrapperConsumer.Address(),
+ linkAmount,
+ )
+ }
+ fundConsumerWithNative := func() error {
+ //fund consumer with Eth (native token)
+ _, err := actions.SendFunds(l, sethClient, actions.FundsToSendPayload{
+ ToAddress: common.HexToAddress(wrapperConsumer.Address()),
+ Amount: conversions.EtherToWei(big.NewFloat(*vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)),
+ PrivateKey: sethClient.PrivateKeys[0],
+ })
+ return err
+ }
+ switch vrfv2plusconfig.BillingType(subFundingType) {
+ case vrfv2plusconfig.BillingType_Link:
+ err := fundConsumerWithLink()
+ if err != nil {
+ return err
+ }
+ case vrfv2plusconfig.BillingType_Native:
+ err := fundConsumerWithNative()
+ if err != nil {
+ return err
+ }
+ case vrfv2plusconfig.BillingType_Link_and_Native:
+ err := fundConsumerWithLink()
+ if err != nil {
+ return err
+ }
+ err = fundConsumerWithNative()
+ if err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("invalid billing type: %s", subFundingType)
+ }
+ return nil
+}
diff --git a/integration-tests/actions/vrf/vrfv2plus/models.go b/integration-tests/actions/vrf/vrfv2plus/models.go
index a2ca8ec582b..5198439c050 100644
--- a/integration-tests/actions/vrf/vrfv2plus/models.go
+++ b/integration-tests/actions/vrf/vrfv2plus/models.go
@@ -5,6 +5,6 @@ import (
)
type VRFV2PlusWrapperContracts struct {
- VRFV2PlusWrapper contracts.VRFV2PlusWrapper
- LoadTestConsumers []contracts.VRFv2PlusWrapperLoadTestConsumer
+ VRFV2PlusWrapper contracts.VRFV2PlusWrapper
+ WrapperConsumers []contracts.VRFv2PlusWrapperLoadTestConsumer
}
diff --git a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go
index f3c7d53d6ee..4833afb9fef 100644
--- a/integration-tests/actions/vrf/vrfv2plus/setup_steps.go
+++ b/integration-tests/actions/vrf/vrfv2plus/setup_steps.go
@@ -8,8 +8,6 @@ import (
"github.com/smartcontractkit/seth"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
-
"github.com/shopspring/decimal"
"golang.org/x/sync/errgroup"
@@ -17,7 +15,6 @@ import (
"github.com/google/uuid"
"github.com/rs/zerolog"
- "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions"
"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"
@@ -28,7 +25,7 @@ import (
"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"
+ vrfv2plusconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus"
"github.com/smartcontractkit/chainlink/integration-tests/types"
)
@@ -201,7 +198,7 @@ func SetupVRFV2_5Environment(
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 {
+func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, config *vrfv2plusconfig.General, pubKeyCompressed string, l zerolog.Logger, vrfNode *vrfcommon.VRFNode) error {
vrfJobSpecConfig := vrfcommon.VRFJobSpecConfig{
ForwardingAllowed: *config.VRFJobForwardingAllowed,
CoordinatorAddress: contracts.CoordinatorV2Plus.Address(),
@@ -235,7 +232,10 @@ func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, config *v
nodeConfig := node.NewConfig(vrfNode.CLNode.NodeConfig,
node.WithKeySpecificMaxGasPrice(vrfNode.TXKeyAddressStrings, *config.CLNodeMaxGasPriceGWei),
)
- l.Info().Msg("Restarting Node with new sending key PriceMax configuration")
+ l.Info().
+ Strs("Sending Keys", vrfNode.TXKeyAddressStrings).
+ Int64("Price Max Setting", *config.CLNodeMaxGasPriceGWei).
+ Msg("Restarting Node with new sending key PriceMax configuration")
err = vrfNode.CLNode.Restart(nodeConfig)
if err != nil {
return fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrRestartCLNode, err)
@@ -243,29 +243,119 @@ func setupVRFNode(contracts *vrfcommon.VRFContracts, chainID *big.Int, config *v
return nil
}
-func SetupVRFV2PlusWrapperEnvironment(
+func SetupVRFV2PlusWrapperForExistingEnv(
ctx context.Context,
+ sethClient *seth.Client,
+ vrfContracts *vrfcommon.VRFContracts,
+ keyHash [32]byte,
+ vrfv2PlusTestConfig types.VRFv2PlusTestConfig,
+ numberOfConsumerContracts int,
l zerolog.Logger,
+) (*VRFV2PlusWrapperContracts, *big.Int, error) {
+ config := *vrfv2PlusTestConfig.GetVRFv2PlusConfig()
+ var wrapper contracts.VRFV2PlusWrapper
+ var err error
+ if *config.ExistingEnvConfig.UseExistingWrapper {
+ wrapper, err = contracts.LoadVRFV2PlusWrapper(sethClient, *config.ExistingEnvConfig.WrapperAddress)
+ if err != nil {
+ return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, "error loading VRFV2PlusWrapper", err)
+ }
+ } else {
+ wrapperSubId, err := CreateSubAndFindSubID(ctx, sethClient, vrfContracts.CoordinatorV2Plus)
+ if err != nil {
+ return nil, nil, err
+ }
+ wrapper, err = contracts.DeployVRFV2PlusWrapper(sethClient, vrfContracts.LinkToken.Address(), vrfContracts.LinkNativeFeedAddress, vrfContracts.CoordinatorV2Plus.Address(), wrapperSubId)
+ if err != nil {
+ return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, ErrDeployWrapper, err)
+ }
+ err = FundSubscriptions(
+ big.NewFloat(*config.General.SubscriptionFundingAmountNative),
+ big.NewFloat(*config.General.SubscriptionFundingAmountLink),
+ vrfContracts.LinkToken,
+ vrfContracts.CoordinatorV2Plus,
+ []*big.Int{wrapperSubId},
+ *config.General.SubscriptionBillingType,
+ )
+ if err != nil {
+ return nil, nil, err
+ }
+ err = vrfContracts.CoordinatorV2Plus.AddConsumer(wrapperSubId, wrapper.Address())
+ if err != nil {
+ return nil, nil, err
+ }
+ err = wrapper.SetConfig(
+ *config.General.WrapperGasOverhead,
+ *config.General.CoordinatorGasOverheadNative,
+ *config.General.CoordinatorGasOverheadLink,
+ *config.General.CoordinatorGasOverheadPerWord,
+ *config.General.CoordinatorNativePremiumPercentage,
+ *config.General.CoordinatorLinkPremiumPercentage,
+ keyHash,
+ *config.General.WrapperMaxNumberOfWords,
+ *config.General.StalenessSeconds,
+ decimal.RequireFromString(*config.General.FallbackWeiPerUnitLink).BigInt(),
+ *config.General.FulfillmentFlatFeeNativePPM,
+ *config.General.FulfillmentFlatFeeLinkDiscountPPM,
+ )
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+ wrapperSubID, err := wrapper.GetSubID(ctx)
+ if err != nil {
+ return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, "error getting subID", err)
+ }
+ var wrapperConsumers []contracts.VRFv2PlusWrapperLoadTestConsumer
+ if *config.ExistingEnvConfig.CreateFundAddWrapperConsumers {
+ wrapperConsumers, err = DeployVRFV2PlusWrapperConsumers(sethClient, wrapper, numberOfConsumerContracts)
+ if err != nil {
+ return nil, nil, err
+ }
+ } else {
+ wrapperConsumer, err := contracts.LoadVRFV2WrapperLoadTestConsumer(sethClient, *config.ExistingEnvConfig.WrapperConsumerAddress)
+ if err != nil {
+ return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, "error loading VRFV2WrapperLoadTestConsumer", err)
+ }
+ wrapperConsumers = append(wrapperConsumers, wrapperConsumer)
+ }
+ wrapperContracts := &VRFV2PlusWrapperContracts{wrapper, wrapperConsumers}
+ for _, consumer := range wrapperConsumers {
+ err = FundWrapperConsumer(
+ sethClient,
+ *config.General.SubscriptionBillingType,
+ vrfContracts.LinkToken,
+ consumer,
+ config.General,
+ l,
+ )
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+ return wrapperContracts, wrapperSubID, nil
+}
+
+func SetupVRFV2PlusWrapperForNewEnv(
+ ctx context.Context,
sethClient *seth.Client,
vrfv2PlusTestConfig types.VRFv2PlusTestConfig,
- linkToken contracts.LinkToken,
- mockNativeLINKFeed contracts.MockETHLINKFeed,
- coordinator contracts.VRFCoordinatorV2_5,
+ vrfContracts *vrfcommon.VRFContracts,
keyHash [32]byte,
wrapperConsumerContractsAmount int,
+ l zerolog.Logger,
) (*VRFV2PlusWrapperContracts, *big.Int, error) {
// external EOA has to create a subscription for the wrapper first
- wrapperSubId, err := CreateSubAndFindSubID(ctx, sethClient, coordinator)
+ wrapperSubId, err := CreateSubAndFindSubID(ctx, sethClient, vrfContracts.CoordinatorV2Plus)
if err != nil {
return nil, nil, err
}
-
vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General
wrapperContracts, err := DeployVRFV2PlusDirectFundingContracts(
sethClient,
- linkToken.Address(),
- mockNativeLINKFeed.Address(),
- coordinator,
+ vrfContracts.LinkToken.Address(),
+ vrfContracts.MockETHLINKFeed.Address(),
+ vrfContracts.CoordinatorV2Plus,
wrapperConsumerContractsAmount,
wrapperSubId,
vrfv2PlusConfig,
@@ -273,13 +363,11 @@ func SetupVRFV2PlusWrapperEnvironment(
if err != nil {
return nil, nil, fmt.Errorf(vrfcommon.ErrGenericFormat, vrfcommon.ErrWaitTXsComplete, err)
}
-
// once the wrapper is deployed, wrapper address will become consumer of external EOA subscription
- err = coordinator.AddConsumer(wrapperSubId, wrapperContracts.VRFV2PlusWrapper.Address())
+ err = vrfContracts.CoordinatorV2Plus.AddConsumer(wrapperSubId, wrapperContracts.VRFV2PlusWrapper.Address())
if err != nil {
return nil, nil, err
}
-
err = wrapperContracts.VRFV2PlusWrapper.SetConfig(
*vrfv2PlusConfig.WrapperGasOverhead,
*vrfv2PlusConfig.CoordinatorGasOverheadNative,
@@ -297,53 +385,35 @@ func SetupVRFV2PlusWrapperEnvironment(
if err != nil {
return nil, nil, err
}
-
//fund sub
wrapperSubID, err := wrapperContracts.VRFV2PlusWrapper.GetSubID(ctx)
if err != nil {
return nil, nil, err
}
-
err = FundSubscriptions(
big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative),
big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink),
- linkToken,
- coordinator,
+ vrfContracts.LinkToken,
+ vrfContracts.CoordinatorV2Plus,
[]*big.Int{wrapperSubID},
*vrfv2PlusConfig.SubscriptionBillingType,
)
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
- }
-
- //fund consumer with Eth (native token)
- _, err = actions.SendFunds(l, sethClient, actions.FundsToSendPayload{
- ToAddress: common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address()),
- Amount: conversions.EtherToWei(big.NewFloat(*vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)),
- PrivateKey: sethClient.PrivateKeys[0],
- })
- if err != nil {
- return nil, nil, err
- }
-
- wrapperConsumerBalanceBeforeRequestWei, err := sethClient.Client.BalanceAt(ctx, common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address()), nil)
- if err != nil {
- return nil, nil, err
+ for _, consumer := range wrapperContracts.WrapperConsumers {
+ err = FundWrapperConsumer(
+ sethClient,
+ *vrfv2PlusConfig.SubscriptionBillingType,
+ vrfContracts.LinkToken,
+ consumer,
+ vrfv2PlusConfig,
+ l,
+ )
+ if err != nil {
+ return nil, nil, err
+ }
}
- l.Info().
- Str("WrapperConsumerBalanceBeforeRequestWei", wrapperConsumerBalanceBeforeRequestWei.String()).
- Str("WrapperConsumerAddress", wrapperContracts.LoadTestConsumers[0].Address()).
- Msg("WrapperConsumerBalanceBeforeRequestWei")
-
return wrapperContracts, wrapperSubID, nil
}
@@ -421,47 +491,45 @@ func SetupVRFV2PlusForNewEnv(
func SetupVRFV2PlusForExistingEnv(t *testing.T, envConfig vrfcommon.VRFEnvConfig, l zerolog.Logger) (*vrfcommon.VRFContracts, *vrfcommon.VRFKeyData, *test_env.CLClusterTestEnv, *seth.Client, error) {
commonExistingEnvConfig := envConfig.TestConfig.VRFv2Plus.ExistingEnvConfig.ExistingEnvConfig
- env, err := test_env.NewCLTestEnvBuilder().
- WithTestInstance(t).
- WithTestConfig(&envConfig.TestConfig).
- WithCustomCleanup(envConfig.CleanupFn).
- Build()
- if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error creating test env", err)
- }
- evmNetwork, err := env.GetFirstEvmNetwork()
- if err != nil {
- return nil, nil, nil, nil, err
- }
- sethClient, err := seth_utils.GetChainClient(envConfig.TestConfig, *evmNetwork)
+ env, sethClient, err := vrfcommon.LoadExistingCLEnvForVRF(
+ t,
+ envConfig,
+ commonExistingEnvConfig,
+ l,
+ )
if err != nil {
- return nil, nil, nil, nil, err
+ return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading existing CL env", err)
}
coordinator, err := contracts.LoadVRFCoordinatorV2_5(sethClient, *commonExistingEnvConfig.CoordinatorAddress)
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading VRFCoordinator2_5", err)
}
- linkToken, err := contracts.LoadLinkTokenContract(l, sethClient, common.HexToAddress(*commonExistingEnvConfig.LinkAddress))
+ linkAddress, err := coordinator.GetLinkAddress(testcontext.Get(t))
+ if err != nil {
+ return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error getting Link address from Coordinator", err)
+ }
+ linkToken, err := contracts.LoadLinkTokenContract(l, sethClient, common.HexToAddress(linkAddress.String()))
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading LinkToken", err)
}
- err = vrfcommon.FundNodesIfNeeded(testcontext.Get(t), commonExistingEnvConfig, sethClient, l)
+ linkNativeFeedAddress, err := coordinator.GetLinkNativeFeed(testcontext.Get(t))
if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error getting Link address from Coordinator", err)
}
blockHashStoreAddress, err := coordinator.GetBlockHashStoreAddress(testcontext.Get(t))
if err != nil {
- return nil, nil, nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, nil, nil, err
}
blockHashStore, err := contracts.LoadBlockHashStore(sethClient, blockHashStoreAddress.String())
if err != nil {
return nil, nil, nil, nil, fmt.Errorf("%s, err: %w", "error loading BlockHashStore", err)
}
vrfContracts := &vrfcommon.VRFContracts{
- CoordinatorV2Plus: coordinator,
- VRFV2PlusConsumer: nil,
- LinkToken: linkToken,
- BHS: blockHashStore,
+ CoordinatorV2Plus: coordinator,
+ VRFV2PlusConsumer: nil,
+ LinkToken: linkToken,
+ BHS: blockHashStore,
+ LinkNativeFeedAddress: linkNativeFeedAddress.String(),
}
vrfKey := &vrfcommon.VRFKeyData{
VRFKey: nil,
@@ -500,12 +568,12 @@ func SetupSubsAndConsumersForExistingEnv(
l,
)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
} else {
consumer, err := contracts.LoadVRFv2PlusLoadTestConsumer(sethClient, *commonExistingEnvConfig.ConsumerAddress)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
consumers = append(consumers, consumer)
var ok bool
@@ -527,21 +595,65 @@ func SetupSubsAndConsumersForExistingEnv(
l,
)
if err != nil {
- return nil, nil, fmt.Errorf("err: %w", err)
+ return nil, nil, err
}
}
return subIDs, consumers, nil
}
func SelectBillingTypeWithDistribution(billingType string, distributionFn func() bool) (bool, error) {
- switch vrfv2plus_config.BillingType(billingType) {
- case vrfv2plus_config.BillingType_Link:
+ switch vrfv2plusconfig.BillingType(billingType) {
+ case vrfv2plusconfig.BillingType_Link:
return false, nil
- case vrfv2plus_config.BillingType_Native:
+ case vrfv2plusconfig.BillingType_Native:
return true, nil
- case vrfv2plus_config.BillingType_Link_and_Native:
+ case vrfv2plusconfig.BillingType_Link_and_Native:
return distributionFn(), nil
default:
return false, fmt.Errorf("invalid billing type: %s", billingType)
}
}
+
+func SetupVRFV2PlusWrapperUniverse(
+ ctx context.Context,
+ sethClient *seth.Client,
+ vrfContracts *vrfcommon.VRFContracts,
+ config *tc.TestConfig,
+ keyHash [32]byte,
+ numberOfConsumerContracts int,
+ l zerolog.Logger,
+) (*VRFV2PlusWrapperContracts, *big.Int, error) {
+ var (
+ wrapperContracts *VRFV2PlusWrapperContracts
+ wrapperSubID *big.Int
+ err error
+ )
+ if *config.VRFv2Plus.General.UseExistingEnv {
+ wrapperContracts, wrapperSubID, err = SetupVRFV2PlusWrapperForExistingEnv(
+ ctx,
+ sethClient,
+ vrfContracts,
+ keyHash,
+ config,
+ numberOfConsumerContracts,
+ l,
+ )
+ if err != nil {
+ return nil, nil, err
+ }
+ } else {
+ wrapperContracts, wrapperSubID, err = SetupVRFV2PlusWrapperForNewEnv(
+ ctx,
+ sethClient,
+ config,
+ vrfContracts,
+ keyHash,
+ numberOfConsumerContracts,
+ l,
+ )
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+ return wrapperContracts, wrapperSubID, nil
+}
diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go
index 177b3521013..ab54885b28e 100644
--- a/integration-tests/benchmark/keeper_test.go
+++ b/integration-tests/benchmark/keeper_test.go
@@ -10,26 +10,26 @@ import (
"github.com/stretchr/testify/require"
"github.com/smartcontractkit/chainlink-testing-framework/blockchain"
- ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
- env_client "github.com/smartcontractkit/chainlink-testing-framework/k8s/client"
+ ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/config"
+ envclient "github.com/smartcontractkit/chainlink-testing-framework/k8s/client"
"github.com/smartcontractkit/chainlink-testing-framework/k8s/environment"
"github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink"
"github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum"
"github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg"
"github.com/smartcontractkit/chainlink-testing-framework/logging"
"github.com/smartcontractkit/chainlink-testing-framework/networks"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+ sethutils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
"github.com/smartcontractkit/chainlink/integration-tests/actions"
"github.com/smartcontractkit/chainlink/integration-tests/contracts"
- eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum"
+ ethcontracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum"
tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig"
"github.com/smartcontractkit/chainlink/integration-tests/testsetups"
"github.com/smartcontractkit/chainlink/integration-tests/types"
)
var (
- performanceChainlinkResources = map[string]interface{}{
+ chainlinkResources = map[string]interface{}{
"resources": map[string]interface{}{
"requests": map[string]interface{}{
"cpu": "1000m",
@@ -41,7 +41,7 @@ var (
},
},
}
- performanceDbResources = map[string]interface{}{
+ dbResources = map[string]interface{}{
"resources": map[string]interface{}{
"requests": map[string]interface{}{
"cpu": "1000m",
@@ -55,33 +55,6 @@ var (
"stateful": true,
"capacity": "10Gi",
}
-
- soakChainlinkResources = map[string]interface{}{
- "resources": map[string]interface{}{
- "requests": map[string]interface{}{
- "cpu": "350m",
- "memory": "1Gi",
- },
- "limits": map[string]interface{}{
- "cpu": "350m",
- "memory": "1Gi",
- },
- },
- }
- soakDbResources = map[string]interface{}{
- "resources": map[string]interface{}{
- "requests": map[string]interface{}{
- "cpu": "250m",
- "memory": "256Mi",
- },
- "limits": map[string]interface{}{
- "cpu": "250m",
- "memory": "256Mi",
- },
- },
- "stateful": true,
- "capacity": "10Gi",
- }
)
type NetworkConfig struct {
@@ -115,9 +88,9 @@ func TestAutomationBenchmark(t *testing.T) {
benchmarkTestNetwork := getNetworkConfig(&config)
l.Info().Str("Namespace", testEnvironment.Cfg.Namespace).Msg("Connected to Keepers Benchmark Environment")
- testNetwork := seth_utils.MustReplaceSimulatedNetworkUrlWithK8(l, benchmarkNetwork, *testEnvironment)
+ testNetwork := sethutils.MustReplaceSimulatedNetworkUrlWithK8(l, benchmarkNetwork, *testEnvironment)
- chainClient, err := seth_utils.GetChainClientWithConfigFunction(&config, testNetwork, seth_utils.OneEphemeralKeysLiveTestnetAutoFixFn)
+ chainClient, err := sethutils.GetChainClientWithConfigFunction(&config, testNetwork, sethutils.OneEphemeralKeysLiveTestnetAutoFixFn)
require.NoError(t, err, "Error getting Seth client")
registryVersions := addRegistry(&config)
@@ -167,46 +140,53 @@ func TestAutomationBenchmark(t *testing.T) {
t.Cleanup(func() {
if err = actions.TeardownRemoteSuite(keeperBenchmarkTest.TearDownVals(t)); err != nil {
l.Error().Err(err).Msg("Error when tearing down remote suite")
+ } else {
+ err := testEnvironment.Client.RemoveNamespace(testEnvironment.Cfg.Namespace)
+ if err != nil {
+ l.Error().Err(err).Msg("Error removing namespace")
+ }
}
})
keeperBenchmarkTest.Setup(testEnvironment, &config)
keeperBenchmarkTest.Run()
}
-func addRegistry(config *tc.TestConfig) []eth_contracts.KeeperRegistryVersion {
+func addRegistry(config *tc.TestConfig) []ethcontracts.KeeperRegistryVersion {
switch *config.Keeper.Common.RegistryToTest {
case "1_1":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_1_1}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_1_1}
case "1_2":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_1_2}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_1_2}
case "1_3":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_1_3}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_1_3}
case "2_0":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_0}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_2_0}
case "2_1":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_1}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_2_1}
case "2_2":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_2}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_2_2}
+ case "2_3":
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_2_3}
case "2_0-1_3":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_0, eth_contracts.RegistryVersion_1_3}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_2_0, ethcontracts.RegistryVersion_1_3}
case "2_1-2_0-1_3":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_1,
- eth_contracts.RegistryVersion_2_0, eth_contracts.RegistryVersion_1_3}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_2_1,
+ ethcontracts.RegistryVersion_2_0, ethcontracts.RegistryVersion_1_3}
case "2_2-2_1":
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_2, eth_contracts.RegistryVersion_2_1}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_2_2, ethcontracts.RegistryVersion_2_1}
case "2_0-Multiple":
- return repeatRegistries(eth_contracts.RegistryVersion_2_0, *config.Keeper.Common.NumberOfRegistries)
+ return repeatRegistries(ethcontracts.RegistryVersion_2_0, *config.Keeper.Common.NumberOfRegistries)
case "2_1-Multiple":
- return repeatRegistries(eth_contracts.RegistryVersion_2_1, *config.Keeper.Common.NumberOfRegistries)
+ return repeatRegistries(ethcontracts.RegistryVersion_2_1, *config.Keeper.Common.NumberOfRegistries)
case "2_2-Multiple":
- return repeatRegistries(eth_contracts.RegistryVersion_2_2, *config.Keeper.Common.NumberOfRegistries)
+ return repeatRegistries(ethcontracts.RegistryVersion_2_2, *config.Keeper.Common.NumberOfRegistries)
default:
- return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_0}
+ return []ethcontracts.KeeperRegistryVersion{ethcontracts.RegistryVersion_2_0}
}
}
-func repeatRegistries(registryVersion eth_contracts.KeeperRegistryVersion, numberOfRegistries int) []eth_contracts.KeeperRegistryVersion {
- repeatedRegistries := make([]eth_contracts.KeeperRegistryVersion, 0)
+func repeatRegistries(registryVersion ethcontracts.KeeperRegistryVersion, numberOfRegistries int) []ethcontracts.KeeperRegistryVersion {
+ repeatedRegistries := make([]ethcontracts.KeeperRegistryVersion, 0)
for i := 0; i < numberOfRegistries; i++ {
repeatedRegistries = append(repeatedRegistries, registryVersion)
}
@@ -288,6 +268,11 @@ var networkConfig = map[string]NetworkConfig{
blockTime: time.Second,
deltaStage: 20 * time.Second,
},
+ networks.ScrollSepolia.Name: {
+ upkeepSLA: int64(120),
+ blockTime: 3 * time.Second,
+ deltaStage: 20 * time.Second,
+ },
}
func SetupAutomationBenchmarkEnv(t *testing.T, keeperTestConfig types.KeeperBenchmarkTestConfig) (*environment.Environment, blockchain.EVMNetwork) {
@@ -316,12 +301,8 @@ func SetupAutomationBenchmarkEnv(t *testing.T, keeperTestConfig types.KeeperBenc
PreventPodEviction: true,
})
- dbResources := performanceDbResources
- chainlinkResources := performanceChainlinkResources
- if strings.Contains(strings.ToLower(strings.Join(keeperTestConfig.GetConfigurationNames(), ",")), "soak") {
- chainlinkResources = soakChainlinkResources
- dbResources = soakDbResources
- }
+ dbResources := dbResources
+ chainlinkResources := chainlinkResources
// Test can run on simulated, simulated-non-dev, testnets
if testNetwork.Name == networks.SimulatedEVMNonDev.Name {
@@ -389,10 +370,10 @@ func SetupAutomationBenchmarkEnv(t *testing.T, keeperTestConfig types.KeeperBenc
// for simulated-nod-dev each CL node gets its own RPC node
if testNetwork.Name == networks.SimulatedEVMNonDev.Name {
podName := fmt.Sprintf("%s-ethereum-geth:%d", testNetwork.Name, i)
- txNodeInternalWs, err := testEnvironment.Fwd.FindPort(podName, "geth", "ws-rpc").As(env_client.RemoteConnection, env_client.WS)
+ txNodeInternalWs, err := testEnvironment.Fwd.FindPort(podName, "geth", "ws-rpc").As(envclient.RemoteConnection, envclient.WS)
require.NoError(t, err, "Error finding WS ports")
internalWsURLs = append(internalWsURLs, txNodeInternalWs)
- txNodeInternalHttp, err := testEnvironment.Fwd.FindPort(podName, "geth", "http-rpc").As(env_client.RemoteConnection, env_client.HTTP)
+ txNodeInternalHttp, err := testEnvironment.Fwd.FindPort(podName, "geth", "http-rpc").As(envclient.RemoteConnection, envclient.HTTP)
require.NoError(t, err, "Error finding HTTP ports")
internalHttpURLs = append(internalHttpURLs, txNodeInternalHttp)
// for testnets with more than 1 RPC nodes
@@ -412,8 +393,8 @@ func SetupAutomationBenchmarkEnv(t *testing.T, keeperTestConfig types.KeeperBenc
testNetwork.URLs = []string{internalWsURLs[i]}
var overrideFn = func(_ interface{}, target interface{}) {
- ctf_config.MustConfigOverrideChainlinkVersion(keeperTestConfig.GetChainlinkImageConfig(), target)
- ctf_config.MightConfigOverridePyroscopeKey(keeperTestConfig.GetPyroscopeConfig(), target)
+ ctfconfig.MustConfigOverrideChainlinkVersion(keeperTestConfig.GetChainlinkImageConfig(), target)
+ ctfconfig.MightConfigOverridePyroscopeKey(keeperTestConfig.GetPyroscopeConfig(), target)
}
tomlConfig, err := actions.BuildTOMLNodeConfigForK8s(keeperTestConfig, testNetwork)
diff --git a/integration-tests/ccip-tests/Makefile b/integration-tests/ccip-tests/Makefile
new file mode 100644
index 00000000000..d33d9569153
--- /dev/null
+++ b/integration-tests/ccip-tests/Makefile
@@ -0,0 +1,73 @@
+## To Override the default config:
+# example usage: make set_config override_toml=../config/config.toml network_config_toml=../config/network.toml
+.PHONY: set_config
+set_config:
+ if [ -s "$(override_toml)" ]; then \
+ echo "Overriding config with $(override_toml)"; \
+ echo "export BASE64_CCIP_CONFIG_OVERRIDE=$$(base64 -i $(override_toml))" > ./testconfig/override/.env; \
+ echo "export TEST_BASE64_CCIP_CONFIG_OVERRIDE=$$(base64 -i $(override_toml))" >> ./testconfig/override/.env; \
+ echo "BASE64_CCIP_CONFIG_OVERRIDE=$$(base64 -i $(override_toml))" > ./testconfig/override/debug.env; \
+ echo "TEST_BASE64_CCIP_CONFIG_OVERRIDE=$$(base64 -i $(override_toml))" >> ./testconfig/override/debug.env; \
+ else \
+ echo "No override config found, using default config"; \
+ echo > ./testconfig/override/.env; \
+ fi
+ if [ -s "$(network_config_toml)" ]; then \
+ echo "Overriding network config with $(network_config_toml)"; \
+ echo "export BASE64_NETWORK_CONFIG=$$(base64 -i $(network_config_toml))" >> ./testconfig/override/.env; \
+ fi
+
+ @echo "Checking for test secrets file in ~/.testsecrets...";
+ @if [ ! -f ~/.testsecrets ]; then \
+ echo "WARNING: ~/.testsecrets file not found. No test secrets will be set. To set test secrets, refer to ./testconfig/examples/.testsecrets.example for the list of secrets and instruction how to set them up."; \
+ else \
+ echo "Test secrets will be loaded from ~/.testsecrets file."; \
+ fi
+
+
+# example usage: make test_load_ccip testimage=chainlink-ccip-tests:latest testname=TestLoadCCIPStableRPS override_toml=./testconfig/override/config.toml network_config_toml=../config/network.toml
+.PHONY: test_load_ccip
+test_load_ccip: set_config
+ source ./testconfig/override/.env && \
+ DATABASE_URL=postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable \
+ ENV_JOB_IMAGE=$(testimage) \
+ TEST_SUITE=load \
+ TEST_ARGS="-test.timeout 900h" \
+ DETACH_RUNNER=true \
+ RR_MEM=16Gi \
+ RR_CPU=4 \
+ go test -timeout 24h -count=1 -v -run ^$(testname)$$ ./load
+
+
+# example usage: make test_smoke_ccip testimage=chainlink-ccip-tests:latest testname=TestSmokeCCIPForBidirectionalLane override_toml=../testconfig/override/config.toml network_config_toml=../config/network.toml
+.PHONY: test_smoke_ccip
+test_smoke_ccip: set_config
+ source ./testconfig/override/.env && \
+ DATABASE_URL=postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable \
+ ENV_JOB_IMAGE=$(testimage) \
+ TEST_SUITE=smoke \
+ TEST_ARGS="-test.timeout 900h" \
+ DETACH_RUNNER=true \
+ go test -timeout 24h -count=1 -v -run ^$(testname)$$ ./smoke
+
+# run ccip smoke tests with default config; explicitly sets the override config to empty
+# example usage: make test_smoke_ccip_default testname=TestSmokeCCIPForBidirectionalLane
+.PHONY: test_smoke_ccip_default
+test_smoke_ccip_default: set_config
+ source ./testconfig/override/.env && \
+ DATABASE_URL=postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable \
+ BASE64_CCIP_CONFIG_OVERRIDE="" \
+ TEST_BASE64_CCIP_CONFIG_OVERRIDE="" \
+ ENV_JOB_IMAGE="" \
+ TEST_SUITE=smoke \
+ TEST_ARGS="-test.timeout 900h" \
+ DETACH_RUNNER=true \
+ go test -timeout 24h -count=1 -v -run ^$(testname)$$ ./smoke
+
+
+# image: the name for the chainlink image being built, example: image=chainlink
+# tag: the tag for the chainlink image being built, example: tag=latest
+# example usage: make build_ccip_image image=chainlink-ccip tag=latest
+.PHONY: build_ccip_image
+build_ccip_image:
+ docker build -f ../../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t $(image):$(tag) ../../
diff --git a/integration-tests/ccip-tests/README.md b/integration-tests/ccip-tests/README.md
new file mode 100644
index 00000000000..f7182338f7f
--- /dev/null
+++ b/integration-tests/ccip-tests/README.md
@@ -0,0 +1,121 @@
+# CCIP Tests
+
+Here lives the integration tests for ccip, utilizing our [chainlink-testing-framework](https://github.com/smartcontractkit/chainlink-testing-framework) and [integration-tests](https://github.com/smartcontractkit/ccip/tree/ccip-develop/integration-tests)
+
+## Setup the Tests
+
+CCIP tests are designed to be highly configurable. Instead of writing many tests to check specific scenarios, the philosophy is to write a few unique tests and make them adjustable through the use of test inputs and configurations. There are a few different ways to set this configuration:
+
+1. Default test input - set via TOML - If no specific input is set; the tests will run with default inputs mentioned in [default.toml](./testconfig/tomls/ccip-default.toml).
+Please refer to the [testconfig README](../testconfig/README.md) for a more detailed look at how testconfig works.
+2. If you want to run your test with a different config, you can override the default inputs. You can either write an [overrides.toml](../testconfig/README.md#configuration-and-overrides) file, or set the env var `BASE64_CCIP_CONFIG_OVERRIDE` containing the base64 encoded TOML file content with updated test input parameters.
+For example, if you want to override the `Network` input in test and want to run your test on `avalanche testnet` and `arbitrum goerli` network, you need to:
+ 1. Create a TOML file with the following content:
+
+ ```toml
+ [CCIP]
+ [CCIP.Env]
+ [CCIP.Env.Network]
+ selected_networks= ['AVALANCHE_FUJI', 'ARBITRUM_GOERLI']
+ ```
+
+ 2. Encode it using the `base64` command
+ 3. Set the env var `BASE64_CCIP_CONFIG_OVERRIDE` with the encoded content.
+
+ ```bash
+ export BASE64_CCIP_CONFIG_OVERRIDE=$(base64 -i )
+ ```
+
+ [mainnet.toml](./testconfig/override/mainnet.toml), [override.toml](./testconfig/examples/override.toml.example) are some of the sample override TOML files.
+
+ For example - In order to run the smoke test (TestSmokeCCIPForBidirectionalLane) on mainnet, run the test with following env var set:
+
+ ```bash
+ export BASE64_CCIP_CONFIG_OVERRIDE=$(base64 -i ./testconfig/override/mainnet.toml)
+ ```
+
+3. Secrets - You also need to set some secrets. This is a mandatory step needed to run the tests. Please refer to [.testsecrets.example](./examples/.testsecrets.example) for the list of secrets and instruction how to set them up.
+ - The chainlink image and tag are required secrets for all the tests.
+ - If you are running tests in live networks like testnet and mainnet, you need to set the secrets (rpc urls and private keys) for the respective networks.
+ - If you are running tests in simulated networks no network specific secrets are required.
+ here is a sample secrets.toml file, for running the tests in simulated networks, with the chainlink image and tag set as secrets:
+
+**Please note that the secrets should NOT be checked in to the repo and should be kept locally.**
+
+We recommend against changing the content of [secrets.toml.example](./testconfig/examples/secrets.toml.example). Please create a new file and set it as the secrets file.
+
+You can run this command to ignore any changes to the file.
+
+```bash
+git update-index --skip-worktree
+```
+
+## Running the Tests
+
+There are two ways to run the tests:
+
+1. Using local docker containers
+2. Using a remote kubernetes cluster
+
+### Using Local Docker Containers
+
+In order to run the tests locally, you need to have docker installed and running on your machine.
+You can use a specific chainlink image and tag (if you already have one) for the tests. Otherwise, you can build the image using the following command:
+
+```bash
+make build_ccip_image image=chainlink-ccip tag=latest-dev # please choose the image and tag name as per your choice
+```
+
+For a local run, tests creates two private geth networks and runs the tests on them. Running tests on testnet and mainnet is not supported yet for local docker tests and must be run in a kubernetes environment.
+
+1. [Setting the test inputs](#setup-the-tests)
+ 1. If required, create an `override.toml` with the required test inputs. If you want to run the tests with default parameters, you can skip this step.
+ 2. Create a TOML file with the secrets.
+2. Run the following command to run the smoke tests with your custom override toml and secrets.
+
+```bash
+# mark the testimage as empty for running the tests in local docker containers
+make test_smoke_ccip testimage="" testname=TestSmokeCCIPForBidirectionalLane override_toml="" secret_toml=""
+```
+
+If you don't want to bother with any overrides, you can run with the default TOML settings with the below command.
+
+```bash
+make test_smoke_ccip_default testname=TestSmokeCCIPForBidirectionalLane secret_toml=""
+```
+
+```mermaid
+---
+title: Basic Docker Test Environment
+---
+flowchart
+ subgraph SD[DON]
+ CL1[Node 1]
+ CL2[Node 2]
+ CL3[Node 3]
+ CL4[Node 4]
+ CL5[Node 5]
+ CL6[Node 6]
+ CL1---CL2
+ CL2---CL3
+ CL3---CL4
+ CL4---CL5
+ CL5---CL6
+ end
+ subgraph Chains
+ SC1[[Private Chain 1]]
+ SC2[[Private Chain 2]]
+ end
+ SC1<-->SD
+ SC2<-->SD
+ MS([Mock Server])
+ MS-->SD
+ TC[/Test Code\]
+ TC<-->MS
+ TC<-->Chains
+ TC<-->SD
+```
+
+### Using Remote Kubernetes Cluster
+
+For running more complex and intensive tests (like load and chaos tests) you need to connect the test to a Kubernetes cluster. These tests have more complex setup and running instructions. We endeavor to make these easier to run and configure, but for the time being please seek a member of the QA/Test Tooling team if you want to run these.
diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go
new file mode 100644
index 00000000000..7594a9dc447
--- /dev/null
+++ b/integration-tests/ccip-tests/actions/ccip_helpers.go
@@ -0,0 +1,4380 @@
+package actions
+
+import (
+ "context"
+ crypto_rand "crypto/rand"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "net/http"
+ "runtime"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "dario.cat/mergo"
+ "github.com/AlekSi/pointer"
+ "github.com/ethereum/go-ethereum"
+ "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"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/atomic"
+ "golang.org/x/exp/rand"
+ "golang.org/x/sync/errgroup"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr"
+
+ chainselectors "github.com/smartcontractkit/chain-selectors"
+
+ commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+ ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client"
+ ctftestenv "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/foundry"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg"
+ "github.com/smartcontractkit/chainlink-testing-framework/networks"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts/laneconfig"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testreporters"
+ testutils "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/utils"
+ "github.com/smartcontractkit/chainlink/integration-tests/client"
+ "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+ integrationtesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/integration"
+ bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math"
+)
+
+const (
+ ChaosGroupExecution = "ExecutionNodesAll" // all execution nodes
+ ChaosGroupCommit = "CommitNodesAll" // all commit nodes
+ ChaosGroupCommitFaultyPlus = "CommitMajority" // >f number of nodes
+ ChaosGroupCommitFaulty = "CommitMinority" // f number of nodes
+ ChaosGroupExecutionFaultyPlus = "ExecutionNodesMajority" // > f number of nodes
+ ChaosGroupExecutionFaulty = "ExecutionNodesMinority" // f number of nodes
+
+ ChaosGroupCommitAndExecFaulty = "CommitAndExecutionNodesMinority" // f number of nodes
+ ChaosGroupCommitAndExecFaultyPlus = "CommitAndExecutionNodesMajority" // >f number of nodes
+ ChaosGroupCCIPGeth = "CCIPGeth" // both source and destination simulated geth networks
+ ChaosGroupNetworkACCIPGeth = "CCIPNetworkAGeth"
+ ChaosGroupNetworkBCCIPGeth = "CCIPNetworkBGeth"
+
+ defaultUSDCDestBytesOverhead = 640
+ defaultUSDCDestGasOverhead = 150_000
+ DefaultDestinationGasLimit = 600_000
+ // DefaultResubscriptionTimeout denotes the max backoff duration for resubscription for various watch events
+ // if the subscription keeps failing even after this duration, the test will fail
+ DefaultResubscriptionTimeout = 2 * time.Hour
+)
+
+// TODO: These should be refactored along with the default CCIP test setup to use optional config functions
+var (
+ // DefaultPermissionlessExecThreshold denotes how long the DON will retry a transaction before giving up,
+ // otherwise known as the "Smart Execution Time Window". If a transaction fails to execute within this time window,
+ // the DON will give up and the transaction will need Manual Execution as detailed here: https://docs.chain.link/ccip/concepts/manual-execution#manual-execution
+ // For performance tests: the higher the load/throughput, the higher value we might need here to guarantee that nonces are not blocked
+ // 1 day should be enough for most of the cases
+ DefaultPermissionlessExecThreshold = time.Hour * 8
+ DefaultMaxNoOfTokensInMsg uint16 = 50
+)
+
+type CCIPTOMLEnv struct {
+ Networks []blockchain.EVMNetwork
+}
+
+var (
+ NetworkChart = reorg.TXNodesAppLabel
+ NetworkName = func(name string) string {
+ return strings.ReplaceAll(strings.ToLower(name), " ", "-")
+ }
+ InflightExpiryExec = 3 * time.Minute
+ InflightExpiryCommit = 3 * time.Minute
+ BatchGasLimit = uint32(7_000_000)
+
+ MaxDataBytes = uint32(50_000)
+
+ RootSnoozeTime = 3 * time.Minute
+ GethLabel = func(name string) string {
+ name = NetworkName(name)
+ switch NetworkChart {
+ case reorg.TXNodesAppLabel:
+ return fmt.Sprintf("%s-ethereum-geth", name)
+ case foundry.ChartName:
+ return name
+ }
+ return ""
+ }
+ // ApprovedAmountToRouter is the default amount which gets approved for router so that it can transfer token and use the fee token for fee payment
+ ApprovedAmountToRouter = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1))
+ ApprovedFeeAmountToRouter = new(big.Int).Mul(big.NewInt(int64(GasFeeMultiplier)), big.NewInt(1e5))
+ GasFeeMultiplier uint64 = 12e17
+ LinkToUSD = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(20))
+ WrappedNativeToUSD = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1.7e3))
+)
+
+func GetUSDCDomain(networkName string, simulated bool) (uint32, error) {
+ if simulated {
+ // generate a random domain for simulated networks
+ return rand.Uint32(), nil
+ }
+ lookup := map[string]uint32{
+ networks.AvalancheFuji.Name: 1,
+ networks.OptimismGoerli.Name: 2,
+ networks.ArbitrumGoerli.Name: 3,
+ networks.BaseGoerli.Name: 6,
+ networks.PolygonMumbai.Name: 7,
+ }
+ if val, ok := lookup[networkName]; ok {
+ return val, nil
+ }
+ return 0, fmt.Errorf("USDC domain not found for chain %s", networkName)
+}
+
+type CCIPCommon struct {
+ Logger *zerolog.Logger
+ ChainClient blockchain.EVMClient
+ // Deployer deploys all CCIP contracts
+ Deployer *contracts.CCIPContractsDeployer
+ // tokenDeployer is used exclusively for deploying self-serve tokens and their pools
+ tokenDeployer *contracts.CCIPContractsDeployer
+ FeeToken *contracts.LinkToken
+ BridgeTokens []*contracts.ERC20Token
+ PriceAggregators map[common.Address]*contracts.MockAggregator
+ NoOfTokensNeedingDynamicPrice int
+ BridgeTokenPools []*contracts.TokenPool
+ RateLimiterConfig contracts.RateLimiterConfig
+ ARMContract *common.Address
+ ARM *contracts.ARM // populate only if the ARM contracts is not a mock and can be used to verify various ARM events; keep this nil for mock ARM
+ Router *contracts.Router
+ PriceRegistry *contracts.PriceRegistry
+ TokenAdminRegistry *contracts.TokenAdminRegistry
+ WrappedNative common.Address
+ MulticallEnabled bool
+ MulticallContract common.Address
+ ExistingDeployment bool
+ USDCMockDeployment *bool
+ TokenMessenger *common.Address
+ TokenTransmitter *contracts.TokenTransmitter
+ IsConnectionRestoredRecently *atomic.Bool
+
+ poolFunds *big.Int
+ tokenPriceUpdateWatcherMu *sync.Mutex
+ tokenPriceUpdateWatcher map[common.Address]*big.Int // key - token; value - timestamp of update
+ gasUpdateWatcherMu *sync.Mutex
+ gasUpdateWatcher map[uint64]*big.Int // key - destchain id; value - timestamp of update
+ GasUpdateEvents []contracts.GasUpdateEvent
+}
+
+// FreeUpUnusedSpace sets nil to various elements of ccipModule which are only used
+// during lane set up and not used for rest of the test duration
+// this is called mainly by load test to keep the memory usage minimum for high number of lanes
+func (ccipModule *CCIPCommon) FreeUpUnusedSpace() {
+ ccipModule.PriceAggregators = nil
+ ccipModule.BridgeTokenPools = nil
+ ccipModule.TokenMessenger = nil
+ ccipModule.TokenTransmitter = nil
+ runtime.GC()
+}
+
+func (ccipModule *CCIPCommon) UnvoteToCurseARM() error {
+ if ccipModule.ARM != nil {
+ return fmt.Errorf("real ARM deployed. cannot curse through test")
+ }
+ if ccipModule.ARMContract == nil {
+ return fmt.Errorf("no ARM contract is set")
+ }
+ arm, err := mock_arm_contract.NewMockARMContract(*ccipModule.ARMContract, ccipModule.ChainClient.Backend())
+ if err != nil {
+ return fmt.Errorf("error instantiating arm %w", err)
+ }
+ opts, err := ccipModule.ChainClient.TransactionOpts(ccipModule.ChainClient.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting owners for ARM OwnerUnvoteToCurse %w", err)
+ }
+ tx, err := arm.OwnerUnvoteToCurse0(opts, []mock_arm_contract.RMNUnvoteToCurseRecord{})
+ if err != nil {
+ return fmt.Errorf("error in calling OwnerUnvoteToCurse %w", err)
+ }
+ err = ccipModule.ChainClient.ProcessTransaction(tx)
+ if err != nil {
+ return err
+ }
+ log.Info().
+ Str("ARM", arm.Address().Hex()).
+ Msg("ARM is uncursed")
+ return ccipModule.ChainClient.WaitForEvents()
+}
+
+func (ccipModule *CCIPCommon) IsCursed() (bool, error) {
+ if ccipModule.ARM != nil {
+ return false, fmt.Errorf("real ARM deployed. cannot validate cursing")
+ }
+ if ccipModule.ARMContract == nil {
+ return false, fmt.Errorf("no ARM contract is set")
+ }
+ arm, err := mock_arm_contract.NewMockARMContract(*ccipModule.ARMContract, ccipModule.ChainClient.Backend())
+ if err != nil {
+ return false, fmt.Errorf("error instantiating arm %w", err)
+ }
+ return arm.IsCursed0(nil)
+}
+
+func (ccipModule *CCIPCommon) CurseARM() (*types.Transaction, error) {
+ if ccipModule.ARM != nil {
+ return nil, fmt.Errorf("real ARM deployed. cannot curse through test")
+ }
+ if ccipModule.ARMContract == nil {
+ return nil, fmt.Errorf("no ARM contract is set")
+ }
+ arm, err := mock_arm_contract.NewMockARMContract(*ccipModule.ARMContract, ccipModule.ChainClient.Backend())
+ if err != nil {
+ return nil, fmt.Errorf("error instantiating arm %w", err)
+ }
+ opts, err := ccipModule.ChainClient.TransactionOpts(ccipModule.ChainClient.GetDefaultWallet())
+ if err != nil {
+ return nil, fmt.Errorf("error getting owners for ARM VoteToCurse %w", err)
+ }
+ tx, err := arm.VoteToCurse(opts, [32]byte{})
+ if err != nil {
+ return nil, fmt.Errorf("error in calling VoteToCurse %w", err)
+ }
+ err = ccipModule.ChainClient.ProcessTransaction(tx)
+ if err != nil {
+ return tx, err
+ }
+ log.Info().
+ Str("ARM", arm.Address().Hex()).
+ Str("Network", ccipModule.ChainClient.GetNetworkName()).
+ Msg("ARM is cursed")
+ return tx, ccipModule.ChainClient.WaitForEvents()
+}
+
+func (ccipModule *CCIPCommon) LoadContractAddresses(conf *laneconfig.LaneConfig, noOfTokens *int) {
+ if conf != nil {
+ if common.IsHexAddress(conf.FeeToken) {
+ ccipModule.FeeToken = &contracts.LinkToken{
+ EthAddress: common.HexToAddress(conf.FeeToken),
+ }
+ }
+ if conf.IsNativeFeeToken {
+ ccipModule.FeeToken = &contracts.LinkToken{
+ EthAddress: common.HexToAddress("0x0"),
+ }
+ }
+
+ if common.IsHexAddress(conf.Router) {
+ ccipModule.Router = &contracts.Router{
+ EthAddress: common.HexToAddress(conf.Router),
+ }
+ }
+ if common.IsHexAddress(conf.ARM) {
+ addr := common.HexToAddress(conf.ARM)
+ ccipModule.ARMContract = &addr
+ if !conf.IsMockARM {
+ ccipModule.ARM = &contracts.ARM{
+ EthAddress: addr,
+ }
+ }
+ }
+ if common.IsHexAddress(conf.PriceRegistry) {
+ ccipModule.PriceRegistry = &contracts.PriceRegistry{
+ EthAddress: common.HexToAddress(conf.PriceRegistry),
+ }
+ }
+ if common.IsHexAddress(conf.WrappedNative) {
+ ccipModule.WrappedNative = common.HexToAddress(conf.WrappedNative)
+ }
+ if common.IsHexAddress(conf.Multicall) {
+ ccipModule.MulticallContract = common.HexToAddress(conf.Multicall)
+ }
+ if common.IsHexAddress(conf.TokenMessenger) {
+ addr := common.HexToAddress(conf.TokenMessenger)
+ ccipModule.TokenMessenger = &addr
+ }
+ if common.IsHexAddress(conf.TokenTransmitter) {
+ ccipModule.TokenTransmitter = &contracts.TokenTransmitter{
+ ContractAddress: common.HexToAddress(conf.TokenTransmitter),
+ }
+ }
+ if len(conf.BridgeTokens) > 0 {
+ // if noOfTokens is set, then only take that many tokens from the list
+ // the lane config can have more tokens than required for the test
+ if noOfTokens != nil {
+ if len(conf.BridgeTokens) > *noOfTokens {
+ conf.BridgeTokens = conf.BridgeTokens[:*noOfTokens]
+ }
+ }
+ var tokens []*contracts.ERC20Token
+ for _, token := range conf.BridgeTokens {
+ if common.IsHexAddress(token) {
+ tokens = append(tokens, &contracts.ERC20Token{
+ ContractAddress: common.HexToAddress(token),
+ })
+ }
+ }
+ ccipModule.BridgeTokens = tokens
+ }
+ if len(conf.BridgeTokenPools) > 0 {
+ // if noOfTokens is set, then only take that many tokenpools from the list
+ // the lane config can have more tokenpools than required for the test
+ if noOfTokens != nil {
+ if len(conf.BridgeTokenPools) > *noOfTokens {
+ conf.BridgeTokenPools = conf.BridgeTokenPools[:*noOfTokens]
+ }
+ }
+ var pools []*contracts.TokenPool
+ for _, pool := range conf.BridgeTokenPools {
+ if common.IsHexAddress(pool) {
+ pools = append(pools, &contracts.TokenPool{
+ EthAddress: common.HexToAddress(pool),
+ })
+ }
+ }
+ ccipModule.BridgeTokenPools = pools
+ }
+ if len(conf.PriceAggregators) > 0 {
+ priceAggrs := make(map[common.Address]*contracts.MockAggregator)
+ for token, aggr := range conf.PriceAggregators {
+ if common.IsHexAddress(aggr) {
+ priceAggrs[common.HexToAddress(token)] = &contracts.MockAggregator{
+ ContractAddress: common.HexToAddress(aggr),
+ }
+ }
+ }
+ ccipModule.PriceAggregators = priceAggrs
+ }
+ if common.IsHexAddress(conf.TokenAdminRegistry) {
+ ccipModule.TokenAdminRegistry = &contracts.TokenAdminRegistry{
+ EthAddress: common.HexToAddress(conf.TokenAdminRegistry),
+ }
+ }
+ }
+}
+
+// ApproveTokens approves tokens for the router to send usually a massive amount of tokens enough to cover all the ccip transfers
+// to be triggered by the test.
+// Also, if the test is using self-serve tokens and pools deployed by a separate `tokenDeployer` address, this sends some of those tokens
+// to the default `ccipOwner` address to be used for the test.
+func (ccipModule *CCIPCommon) ApproveTokens() error {
+ isApproved := false
+ for _, token := range ccipModule.BridgeTokens {
+ // TODO: We send half of token funds back to the CCIP Deployer account, which isn't particularly realistic.
+ // See CCIP-2477
+ if token.OwnerWallet.Address() != ccipModule.ChainClient.GetDefaultWallet().Address() &&
+ !ccipModule.ExistingDeployment {
+ tokenBalance, err := token.BalanceOf(context.Background(), token.OwnerWallet.Address())
+ if err != nil {
+ return fmt.Errorf("failed to get balance of token %s: %w", token.ContractAddress.Hex(), err)
+ }
+ tokenBalance.Div(tokenBalance, big.NewInt(2)) // Send half of the balance to the default wallet
+ err = token.Transfer(token.OwnerWallet, ccipModule.ChainClient.GetDefaultWallet().Address(), tokenBalance)
+ if err != nil {
+ return fmt.Errorf("failed to transfer token from '%s' to '%s' %s: %w",
+ token.ContractAddress.Hex(), token.OwnerAddress.Hex(), ccipModule.ChainClient.GetDefaultWallet().Address(), err,
+ )
+ }
+ }
+
+ err := token.Approve(ccipModule.ChainClient.GetDefaultWallet(), ccipModule.Router.Address(), ApprovedAmountToRouter)
+ if err != nil {
+ return fmt.Errorf("failed to approve token %s: %w", token.ContractAddress.Hex(), err)
+ }
+ if token.ContractAddress == ccipModule.FeeToken.EthAddress {
+ isApproved = true
+ }
+ }
+ if ccipModule.FeeToken.EthAddress != common.HexToAddress("0x0") {
+ amount := ApprovedFeeAmountToRouter
+ if isApproved {
+ amount = new(big.Int).Add(ApprovedAmountToRouter, ApprovedFeeAmountToRouter)
+ }
+ allowance, err := ccipModule.FeeToken.Allowance(ccipModule.ChainClient.GetDefaultWallet().Address(), ccipModule.Router.Address())
+ if err != nil {
+ return fmt.Errorf("failed to get allowance for token %s: %w", ccipModule.FeeToken.Address(), err)
+ }
+ if allowance.Cmp(amount) < 0 {
+ err := ccipModule.FeeToken.Approve(ccipModule.Router.Address(), amount)
+ if err != nil {
+ return fmt.Errorf("failed to approve fee token %s: %w", ccipModule.FeeToken.EthAddress.String(), err)
+ }
+ }
+ }
+ ccipModule.Logger.Info().Msg("Tokens approved")
+
+ return nil
+}
+
+func (ccipModule *CCIPCommon) CleanUp() error {
+ if !ccipModule.ExistingDeployment {
+ for i, pool := range ccipModule.BridgeTokenPools {
+ if !pool.IsLockRelease() {
+ continue
+ }
+ bal, err := ccipModule.BridgeTokens[i].BalanceOf(context.Background(), pool.Address())
+ if err != nil {
+ return fmt.Errorf("error in getting pool balance %w", err)
+ }
+ if bal.Cmp(big.NewInt(0)) == 0 {
+ continue
+ }
+ err = pool.RemoveLiquidity(bal)
+ if err != nil {
+ return fmt.Errorf("error in removing liquidity %w", err)
+ }
+ }
+ err := ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error in waiting for events %wfmt.Sprintf(\"Setting mockserver response\")", err)
+ }
+ }
+ return nil
+}
+
+func (ccipModule *CCIPCommon) WaitForPriceUpdates(
+ ctx context.Context,
+ lggr *zerolog.Logger,
+ timeout time.Duration,
+ destChainId uint64,
+ allTokens []common.Address,
+) error {
+ destChainSelector, err := chainselectors.SelectorFromChainId(destChainId)
+ if err != nil {
+ return err
+ }
+ // check if price is already updated
+ price, err := ccipModule.PriceRegistry.Instance.GetDestinationChainGasPrice(nil, destChainSelector)
+ if err != nil {
+ return err
+ }
+
+ if price.Timestamp > 0 && price.Value.Cmp(big.NewInt(0)) > 0 {
+ lggr.Info().
+ Str("Price Registry", ccipModule.PriceRegistry.Address()).
+ Uint64("dest chain", destChainId).
+ Str("source chain", ccipModule.ChainClient.GetNetworkName()).
+ Msg("Price already updated")
+ return nil
+ }
+ // if not, wait for price update
+ lggr.Info().Msgf("Waiting for UsdPerUnitGas and UsdPerTokenUpdated for dest chain %d Price Registry %s", destChainId, ccipModule.PriceRegistry.Address())
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+ localCtx, cancel := context.WithTimeout(ctx, timeout)
+ defer cancel()
+ var tokensMissingForUpdate common.Address
+ for {
+ select {
+ case <-ticker.C:
+ ccipModule.gasUpdateWatcherMu.Lock()
+ timestampOfUpdate, ok := ccipModule.gasUpdateWatcher[destChainId]
+ ccipModule.gasUpdateWatcherMu.Unlock()
+ tokenPricesUpdated := false
+ if len(allTokens) > 0 {
+ ccipModule.tokenPriceUpdateWatcherMu.Lock()
+ for _, token := range allTokens {
+ timestampOfTokenUpdate, okToken := ccipModule.tokenPriceUpdateWatcher[token]
+ // we consider token prices updated only if all tokens have been updated
+ // if any token is missing, we retry
+ if !okToken || timestampOfTokenUpdate.Cmp(big.NewInt(0)) < 1 {
+ tokenPricesUpdated = false
+ tokensMissingForUpdate = token
+ break
+ }
+ tokenPricesUpdated = true
+ }
+ ccipModule.tokenPriceUpdateWatcherMu.Unlock()
+ }
+
+ if tokenPricesUpdated && ok && timestampOfUpdate.Cmp(big.NewInt(0)) == 1 {
+ lggr.Info().
+ Str("Price Registry", ccipModule.PriceRegistry.Address()).
+ Uint64("dest chain", destChainId).
+ Str("source chain", ccipModule.ChainClient.GetNetworkName()).
+ Msg("Price updated")
+ return nil
+ }
+ case <-localCtx.Done():
+ if tokensMissingForUpdate != (common.Address{}) {
+ return fmt.Errorf("price Updates not found for token %s", tokensMissingForUpdate.Hex())
+ }
+ return fmt.Errorf("price Updates not found for chain %d", destChainId)
+ }
+ }
+}
+
+// WatchForPriceUpdates helps to ensure the price updates are happening in price registry by subscribing to a couple
+// of price update events and add the event details to watchers. It subscribes to 'UsdPerUnitGasUpdated'
+// and 'UsdPerTokenUpdated' event.
+func (ccipModule *CCIPCommon) WatchForPriceUpdates(ctx context.Context, lggr *zerolog.Logger) error {
+ gasUpdateEventLatest := make(chan *price_registry.PriceRegistryUsdPerUnitGasUpdated)
+ tokenUpdateEvent := make(chan *price_registry.PriceRegistryUsdPerTokenUpdated)
+ sub := event.Resubscribe(DefaultResubscriptionTimeout, func(_ context.Context) (event.Subscription, error) {
+ lggr.Info().Msg("Subscribing to UsdPerUnitGasUpdated event")
+ eventSub, err := ccipModule.PriceRegistry.WatchUsdPerUnitGasUpdated(nil, gasUpdateEventLatest, nil)
+ if err != nil {
+ log.Error().Err(err).Msg("error in subscribing to UsdPerUnitGasUpdated event")
+ }
+ return eventSub, err
+ })
+ if sub == nil {
+ return fmt.Errorf("no event subscription found")
+ }
+ tokenUpdateSub := event.Resubscribe(DefaultResubscriptionTimeout, func(_ context.Context) (event.Subscription, error) {
+ lggr.Info().Msg("Subscribing to UsdPerTokenUpdated event")
+ eventSub, err := ccipModule.PriceRegistry.WatchUsdPerTokenUpdated(nil, tokenUpdateEvent)
+ if err != nil {
+ log.Error().Err(err).Msg("error in subscribing to UsdPerTokenUpdated event")
+ }
+ return eventSub, err
+ })
+ if tokenUpdateSub == nil {
+ return fmt.Errorf("no event subscription found")
+ }
+ processEvent := func(value, timestamp *big.Int, destChainSelector uint64, raw types.Log) error {
+ destChain, err := chainselectors.ChainIdFromSelector(destChainSelector)
+ if err != nil {
+ return err
+ }
+ ccipModule.gasUpdateWatcherMu.Lock()
+ ccipModule.gasUpdateWatcher[destChain] = timestamp
+
+ ccipModule.GasUpdateEvents = append(ccipModule.GasUpdateEvents, contracts.GasUpdateEvent{
+ Sender: raw.Address.Hex(),
+ Tx: raw.TxHash.Hex(),
+ Value: value,
+ DestChain: destChain,
+ Source: ccipModule.ChainClient.GetNetworkName(),
+ })
+ ccipModule.gasUpdateWatcherMu.Unlock()
+ lggr.Info().
+ Uint64("chainSelector", destChainSelector).
+ Uint64("dest_chain", destChain).
+ Str("price_registry", ccipModule.PriceRegistry.Address()).
+ Str("tx hash", raw.TxHash.Hex()).
+ Msgf("UsdPerUnitGasUpdated event received for dest chain: %d, source chain: %s",
+ destChain, ccipModule.ChainClient.GetNetworkName())
+ return nil
+ }
+ go func() {
+ defer func() {
+ sub.Unsubscribe()
+ tokenUpdateSub.Unsubscribe()
+ ccipModule.gasUpdateWatcher = nil
+ ccipModule.gasUpdateWatcherMu = nil
+ ccipModule.GasUpdateEvents = nil
+ ccipModule.tokenPriceUpdateWatcher = nil
+ ccipModule.tokenPriceUpdateWatcherMu = nil
+ }()
+ for {
+ select {
+ case e := <-gasUpdateEventLatest:
+ err := processEvent(e.Value, e.Timestamp, e.DestChain, e.Raw)
+ if err != nil {
+ continue
+ }
+ case tk := <-tokenUpdateEvent:
+ ccipModule.tokenPriceUpdateWatcherMu.Lock()
+ ccipModule.tokenPriceUpdateWatcher[tk.Token] = tk.Timestamp
+ ccipModule.tokenPriceUpdateWatcherMu.Unlock()
+ lggr.Info().
+ Str("token", tk.Token.Hex()).
+ Str("chain", ccipModule.ChainClient.GetNetworkName()).
+ Str("price_registry", ccipModule.PriceRegistry.Address()).
+ Msg("UsdPerTokenUpdated event received")
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ return nil
+}
+
+// UpdateTokenPricesAtRegularInterval updates aggregator contract with updated answer at regular interval.
+// At each iteration of ticker it chooses one of the aggregator contracts and updates its round answer.
+func (ccipModule *CCIPCommon) UpdateTokenPricesAtRegularInterval(ctx context.Context, lggr *zerolog.Logger, interval time.Duration, conf *laneconfig.LaneConfig) error {
+ if ccipModule.ExistingDeployment {
+ return nil
+ }
+ var aggregators []*contracts.MockAggregator
+ for _, aggregatorContract := range conf.PriceAggregators {
+ contract, err := ccipModule.Deployer.NewMockAggregator(common.HexToAddress(aggregatorContract))
+ if err != nil {
+ return err
+ }
+ aggregators = append(aggregators, contract)
+ }
+ go func(aggregators []*contracts.MockAggregator) {
+ rand.NewSource(uint64(time.Now().UnixNano()))
+ ticker := time.NewTicker(interval)
+ for {
+ select {
+ case <-ticker.C:
+ // randomly choose an aggregator contract from slice of aggregators
+ randomIndex := rand.Intn(len(aggregators))
+ err := aggregators[randomIndex].UpdateRoundData(nil, ptr.Ptr(-5), ptr.Ptr(2))
+ if err != nil {
+ lggr.Error().Err(err).Msg("error in updating round data")
+ continue
+ }
+ case <-ctx.Done():
+ return
+ }
+ }
+ }(aggregators)
+ return nil
+}
+
+// SyncUSDCDomain makes domain updates to Source usdc pool domain with -
+// 1. USDC domain from destination chain's token transmitter contract
+// 2. Destination pool address as allowed caller
+func (ccipModule *CCIPCommon) SyncUSDCDomain(destTransmitter *contracts.TokenTransmitter, destPools []*contracts.TokenPool, destChainID uint64) error {
+ // if not USDC new deployment, return
+ // if existing deployment, consider that no syncing is required and return
+ if ccipModule.ExistingDeployment || !ccipModule.IsUSDCDeployment() {
+ return nil
+ }
+ if destTransmitter == nil {
+ return fmt.Errorf("invalid address")
+ }
+ destChainSelector, err := chainselectors.SelectorFromChainId(destChainID)
+ if err != nil {
+ return fmt.Errorf("invalid chain id %w", err)
+ }
+
+ // sync USDC domain
+ for i, pool := range ccipModule.BridgeTokenPools {
+ if !pool.IsUSDC() {
+ continue
+ }
+ if destPools[i] == nil {
+ return fmt.Errorf("invalid pool address")
+ }
+ if !destPools[i].IsUSDC() {
+ return fmt.Errorf("corresponding dest pool is not USDC pool")
+ }
+ err = pool.SyncUSDCDomain(destTransmitter, destPools[i].EthAddress, destChainSelector)
+ if err != nil {
+ return err
+ }
+ err = destPools[i].MintUSDCToUSDCPool()
+ if err != nil {
+ return err
+ }
+ }
+
+ return ccipModule.ChainClient.WaitForEvents()
+}
+
+func (ccipModule *CCIPCommon) PollRPCConnection(ctx context.Context, lggr *zerolog.Logger) {
+ for {
+ select {
+ case reconnectTime := <-ccipModule.ChainClient.ConnectionRestored():
+ if ccipModule.IsConnectionRestoredRecently == nil {
+ ccipModule.IsConnectionRestoredRecently = atomic.NewBool(true)
+ } else {
+ ccipModule.IsConnectionRestoredRecently.Store(true)
+ }
+ lggr.Info().Time("Restored At", reconnectTime).Str("Network", ccipModule.ChainClient.GetNetworkName()).Msg("Connection Restored")
+ case issueTime := <-ccipModule.ChainClient.ConnectionIssue():
+ if ccipModule.IsConnectionRestoredRecently == nil {
+ ccipModule.IsConnectionRestoredRecently = atomic.NewBool(false)
+ } else {
+ ccipModule.IsConnectionRestoredRecently.Store(false)
+ }
+ lggr.Info().Time("Started At", issueTime).Str("Network", ccipModule.ChainClient.GetNetworkName()).Msg("RPC Disconnected")
+ case <-ctx.Done():
+ return
+ }
+ }
+}
+
+func (ccipModule *CCIPCommon) IsUSDCDeployment() bool {
+ return pointer.GetBool(ccipModule.USDCMockDeployment)
+}
+
+func (ccipModule *CCIPCommon) WriteLaneConfig(conf *laneconfig.LaneConfig) {
+ var btAddresses, btpAddresses []string
+ priceAggrs := make(map[string]string)
+ for i, bt := range ccipModule.BridgeTokens {
+ btAddresses = append(btAddresses, bt.Address())
+ btpAddresses = append(btpAddresses, ccipModule.BridgeTokenPools[i].Address())
+ }
+ for k, v := range ccipModule.PriceAggregators {
+ priceAggrs[k.Hex()] = v.ContractAddress.Hex()
+ }
+ conf.CommonContracts = laneconfig.CommonContracts{
+ FeeToken: ccipModule.FeeToken.Address(),
+ BridgeTokens: btAddresses,
+ BridgeTokenPools: btpAddresses,
+ ARM: ccipModule.ARMContract.Hex(),
+ Router: ccipModule.Router.Address(),
+ PriceRegistry: ccipModule.PriceRegistry.Address(),
+ PriceAggregators: priceAggrs,
+ WrappedNative: ccipModule.WrappedNative.Hex(),
+ Multicall: ccipModule.MulticallContract.Hex(),
+ }
+ if ccipModule.TokenAdminRegistry != nil {
+ conf.CommonContracts.TokenAdminRegistry = ccipModule.TokenAdminRegistry.Address()
+ }
+ if ccipModule.TokenTransmitter != nil {
+ conf.CommonContracts.TokenTransmitter = ccipModule.TokenTransmitter.ContractAddress.Hex()
+ }
+ if ccipModule.TokenMessenger != nil {
+ conf.CommonContracts.TokenMessenger = ccipModule.TokenMessenger.Hex()
+ }
+ if ccipModule.ARM == nil {
+ conf.CommonContracts.IsMockARM = true
+ }
+}
+
+func (ccipModule *CCIPCommon) AddPriceAggregatorToken(token common.Address, initialAns *big.Int) error {
+ // check if dynamic price update is enabled
+ if ccipModule.NoOfTokensNeedingDynamicPrice <= 0 {
+ return nil
+ }
+ var err error
+ if aggregator, ok := ccipModule.PriceAggregators[token]; !ok {
+ ccipModule.PriceAggregators[token], err = ccipModule.Deployer.DeployMockAggregator(18, initialAns)
+ if err != nil {
+ return fmt.Errorf("deploying mock aggregator contract shouldn't fail %w", err)
+ }
+ } else {
+ ccipModule.PriceAggregators[token], err = ccipModule.Deployer.NewMockAggregator(aggregator.ContractAddress)
+ if err != nil {
+ return fmt.Errorf("error instantiating price aggregator for token %s", token.Hex())
+ }
+ }
+ ccipModule.NoOfTokensNeedingDynamicPrice--
+ return nil
+}
+
+// DeployContracts deploys the contracts which are necessary in both source and dest chain
+// This reuses common contracts for bidirectional lanes
+func (ccipModule *CCIPCommon) DeployContracts(
+ noOfTokens int,
+ tokenDeployerFns []blockchain.ContractDeployer,
+ conf *laneconfig.LaneConfig,
+) error {
+ var err error
+ cd := ccipModule.Deployer
+
+ ccipModule.LoadContractAddresses(conf, &noOfTokens)
+ if ccipModule.ARM != nil {
+ arm, err := cd.NewARMContract(ccipModule.ARM.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new ARM contract shouldn't fail %w", err)
+ }
+ ccipModule.ARM = arm
+ } else {
+ // deploy a mock ARM contract
+ if ccipModule.ARMContract == nil {
+ if ccipModule.ExistingDeployment {
+ return fmt.Errorf("ARM contract address is not provided in lane config")
+ }
+ ccipModule.ARMContract, err = cd.DeployMockARMContract()
+ if err != nil {
+ return fmt.Errorf("deploying mock ARM contract shouldn't fail %w", err)
+ }
+ err = ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error in waiting for mock ARM deployment %w", err)
+ }
+ }
+ }
+ if ccipModule.WrappedNative == common.HexToAddress("0x0") {
+ if ccipModule.ExistingDeployment {
+ return fmt.Errorf("wrapped native contract address is not provided in lane config")
+ }
+ weth9addr, err := cd.DeployWrappedNative()
+ if err != nil {
+ return fmt.Errorf("deploying wrapped native shouldn't fail %w", err)
+ }
+ err = ccipModule.AddPriceAggregatorToken(*weth9addr, WrappedNativeToUSD)
+ if err != nil {
+ return fmt.Errorf("deploying mock aggregator contract shouldn't fail %w", err)
+ }
+ err = ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("waiting for deploying wrapped native shouldn't fail %w", err)
+ }
+ ccipModule.WrappedNative = *weth9addr
+ }
+
+ if ccipModule.Router == nil {
+ if ccipModule.ExistingDeployment {
+ return fmt.Errorf("router contract address is not provided in lane config")
+ }
+ ccipModule.Router, err = cd.DeployRouter(ccipModule.WrappedNative, *ccipModule.ARMContract)
+ if err != nil {
+ return fmt.Errorf("deploying router shouldn't fail %w", err)
+ }
+ err = ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error in waiting for router deployment %w", err)
+ }
+ } else {
+ r, err := cd.NewRouter(ccipModule.Router.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new router contract shouldn't fail %w", err)
+ }
+ ccipModule.Router = r
+ }
+ if ccipModule.FeeToken == nil {
+ if ccipModule.ExistingDeployment {
+ return fmt.Errorf("FeeToken contract address is not provided in lane config")
+ }
+ // deploy link token
+ token, err := cd.DeployLinkTokenContract()
+ if err != nil {
+ return fmt.Errorf("deploying fee token contract shouldn't fail %w", err)
+ }
+
+ ccipModule.FeeToken = token
+ err = ccipModule.AddPriceAggregatorToken(ccipModule.FeeToken.EthAddress, LinkToUSD)
+ if err != nil {
+ return fmt.Errorf("deploying mock aggregator contract shouldn't fail %w", err)
+ }
+ err = ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error in waiting for feetoken deployment %w", err)
+ }
+ } else {
+ token, err := cd.NewLinkTokenContract(common.HexToAddress(ccipModule.FeeToken.Address()))
+ if err != nil {
+ return fmt.Errorf("getting fee token contract shouldn't fail %w", err)
+ }
+ ccipModule.FeeToken = token
+ }
+
+ // If the number of deployed bridge tokens does not match noOfTokens, deploy rest of the tokens in case ExistingDeployment is false
+ // In case of ExistingDeployment as true use whatever is provided in laneconfig
+ if len(ccipModule.BridgeTokens) < noOfTokens && !ccipModule.ExistingDeployment {
+ // deploy bridge token.
+ for i := len(ccipModule.BridgeTokens); i < noOfTokens; i++ {
+ var token *contracts.ERC20Token
+
+ if len(tokenDeployerFns) != noOfTokens {
+ if ccipModule.IsUSDCDeployment() && i == 0 {
+ // if it's USDC deployment, we deploy the burn mint token 677 with decimal 6 and cast it to ERC20Token
+ usdcToken, err := ccipModule.tokenDeployer.DeployBurnMintERC677(new(big.Int).Mul(big.NewInt(1e6), big.NewInt(1e18)))
+ if err != nil {
+ return fmt.Errorf("deploying bridge usdc token contract shouldn't fail %w", err)
+ }
+ token, err = ccipModule.tokenDeployer.NewERC20TokenContract(usdcToken.ContractAddress)
+ if err != nil {
+ return fmt.Errorf("getting new bridge usdc token contract shouldn't fail %w", err)
+ }
+ if ccipModule.TokenTransmitter == nil {
+ domain, err := GetUSDCDomain(ccipModule.ChainClient.GetNetworkName(), ccipModule.ChainClient.NetworkSimulated())
+ if err != nil {
+ return fmt.Errorf("error in getting USDC domain %w", err)
+ }
+
+ ccipModule.TokenTransmitter, err = ccipModule.tokenDeployer.DeployTokenTransmitter(domain, usdcToken.ContractAddress)
+ if err != nil {
+ return fmt.Errorf("deploying token transmitter shouldn't fail %w", err)
+ }
+ }
+ if ccipModule.TokenMessenger == nil {
+ if ccipModule.TokenTransmitter == nil {
+ return fmt.Errorf("TokenTransmitter contract address is not provided")
+ }
+ ccipModule.TokenMessenger, err = ccipModule.tokenDeployer.DeployTokenMessenger(ccipModule.TokenTransmitter.ContractAddress)
+ if err != nil {
+ return fmt.Errorf("deploying token messenger shouldn't fail %w", err)
+ }
+ err = ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error in waiting for mock TokenMessenger and Transmitter deployment %w", err)
+ }
+ }
+
+ // grant minter role to token messenger
+ err = usdcToken.GrantMintAndBurn(*ccipModule.TokenMessenger)
+ if err != nil {
+ return fmt.Errorf("granting minter role to token messenger shouldn't fail %w", err)
+ }
+ err = usdcToken.GrantMintAndBurn(ccipModule.TokenTransmitter.ContractAddress)
+ if err != nil {
+ return fmt.Errorf("granting minter role to token transmitter shouldn't fail %w", err)
+ }
+ } else {
+ // otherwise we deploy link token and cast it to ERC20Token
+ linkToken, err := ccipModule.tokenDeployer.DeployLinkTokenContract()
+ if err != nil {
+ return fmt.Errorf("deploying bridge token contract shouldn't fail %w", err)
+ }
+ token, err = ccipModule.tokenDeployer.NewERC20TokenContract(common.HexToAddress(linkToken.Address()))
+ if err != nil {
+ return fmt.Errorf("getting new bridge token contract shouldn't fail %w", err)
+ }
+ err = ccipModule.AddPriceAggregatorToken(linkToken.EthAddress, LinkToUSD)
+ if err != nil {
+ return fmt.Errorf("deploying mock aggregator contract shouldn't fail %w", err)
+ }
+ }
+ } else {
+ token, err = ccipModule.tokenDeployer.DeployERC20TokenContract(tokenDeployerFns[i])
+ if err != nil {
+ return fmt.Errorf("deploying bridge token contract shouldn't fail %w", err)
+ }
+ err = ccipModule.AddPriceAggregatorToken(token.ContractAddress, LinkToUSD)
+ if err != nil {
+ return fmt.Errorf("deploying mock aggregator contract shouldn't fail %w", err)
+ }
+ }
+ ccipModule.BridgeTokens = append(ccipModule.BridgeTokens, token)
+
+ }
+ if err = ccipModule.ChainClient.WaitForEvents(); err != nil {
+ return fmt.Errorf("error in waiting for bridge token deployment %w", err)
+ }
+ }
+
+ var tokens []*contracts.ERC20Token
+ for _, token := range ccipModule.BridgeTokens {
+ newToken, err := ccipModule.tokenDeployer.NewERC20TokenContract(common.HexToAddress(token.Address()))
+ if err != nil {
+ return fmt.Errorf("getting new bridge token contract shouldn't fail %w", err)
+ }
+ tokens = append(tokens, newToken)
+ }
+ ccipModule.BridgeTokens = tokens
+ if len(ccipModule.BridgeTokenPools) != len(ccipModule.BridgeTokens) {
+ if ccipModule.ExistingDeployment {
+ return fmt.Errorf("bridge token pool contract address is not provided in lane config")
+ }
+ // deploy native token pool
+ for i := len(ccipModule.BridgeTokenPools); i < len(ccipModule.BridgeTokens); i++ {
+ token := ccipModule.BridgeTokens[i]
+ // usdc pool need to be the first one in the slice
+ if ccipModule.IsUSDCDeployment() && i == 0 {
+ // deploy usdc token pool in case of usdc deployment
+ if ccipModule.TokenMessenger == nil {
+ return fmt.Errorf("TokenMessenger contract address is not provided")
+ }
+ if ccipModule.TokenTransmitter == nil {
+ return fmt.Errorf("TokenTransmitter contract address is not provided")
+ }
+ usdcPool, err := ccipModule.tokenDeployer.DeployUSDCTokenPoolContract(token.Address(), *ccipModule.TokenMessenger, *ccipModule.ARMContract, ccipModule.Router.Instance.Address())
+ if err != nil {
+ return fmt.Errorf("deploying bridge Token pool(usdc) shouldn't fail %w", err)
+ }
+
+ ccipModule.BridgeTokenPools = append(ccipModule.BridgeTokenPools, usdcPool)
+ } else {
+ // deploy lock release token pool in case of non-usdc deployment
+ btp, err := ccipModule.tokenDeployer.DeployLockReleaseTokenPoolContract(token.Address(), *ccipModule.ARMContract, ccipModule.Router.Instance.Address())
+ if err != nil {
+ return fmt.Errorf("deploying bridge Token pool(lock&release) shouldn't fail %w", err)
+ }
+ ccipModule.BridgeTokenPools = append(ccipModule.BridgeTokenPools, btp)
+
+ err = btp.AddLiquidity(token, token.OwnerWallet, ccipModule.poolFunds)
+ if err != nil {
+ return fmt.Errorf("adding liquidity token to dest pool shouldn't fail %w", err)
+ }
+ }
+ }
+ } else {
+ var pools []*contracts.TokenPool
+ for _, pool := range ccipModule.BridgeTokenPools {
+ newPool, err := ccipModule.tokenDeployer.NewLockReleaseTokenPoolContract(pool.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new bridge token pool contract shouldn't fail %w", err)
+ }
+ pools = append(pools, newPool)
+ }
+ ccipModule.BridgeTokenPools = pools
+ }
+
+ // no need to have price registry for existing deployment, we consider that it's already deployed
+ if !ccipModule.ExistingDeployment {
+ if ccipModule.PriceRegistry == nil {
+ // we will update the price updates later based on source and dest PriceUpdates
+ ccipModule.PriceRegistry, err = cd.DeployPriceRegistry(
+ []common.Address{
+ common.HexToAddress(ccipModule.FeeToken.Address()),
+ common.HexToAddress(ccipModule.WrappedNative.Hex()),
+ })
+ if err != nil {
+ return fmt.Errorf("deploying PriceRegistry shouldn't fail %w", err)
+ }
+ err = ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error in waiting for PriceRegistry deployment %w", err)
+ }
+ } else {
+ ccipModule.PriceRegistry, err = cd.NewPriceRegistry(ccipModule.PriceRegistry.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new PriceRegistry contract shouldn't fail %w", err)
+ }
+ }
+ }
+ if ccipModule.MulticallContract == (common.Address{}) && ccipModule.MulticallEnabled {
+ ccipModule.MulticallContract, err = cd.DeployMultiCallContract()
+ if err != nil {
+ return fmt.Errorf("deploying multicall contract shouldn't fail %w", err)
+ }
+ }
+
+ // if the version is after 1.4.0, we need to deploy TokenAdminRegistry
+ // no need to have token admin registry for existing deployment, we consider that it's already deployed
+ if contracts.NeedTokenAdminRegistry() && !ccipModule.ExistingDeployment {
+ if ccipModule.TokenAdminRegistry == nil {
+ // deploy token admin registry
+ ccipModule.TokenAdminRegistry, err = cd.DeployTokenAdminRegistry()
+ if err != nil {
+ return fmt.Errorf("deploying token admin registry shouldn't fail %w", err)
+ }
+ err = ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error in waiting for token admin registry deployment %w", err)
+ }
+
+ if len(ccipModule.BridgeTokens) != len(ccipModule.BridgeTokenPools) {
+ return fmt.Errorf("tokens number %d and pools number %d do not match", len(ccipModule.BridgeTokens), len(ccipModule.BridgeTokenPools))
+ }
+ // add all pools to registry
+ for i, pool := range ccipModule.BridgeTokenPools {
+ token := ccipModule.BridgeTokens[i]
+ err := ccipModule.TokenAdminRegistry.SetAdminAndRegisterPool(token.ContractAddress, pool.EthAddress)
+ if err != nil {
+ return fmt.Errorf("error setting up token %s and pool %s on TokenAdminRegistry : %w", token.Address(), pool.Address(), err)
+ }
+ }
+ err = ccipModule.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error in waiting for token admin registry set up with tokens and pools %w", err)
+ }
+ } else {
+ ccipModule.TokenAdminRegistry, err = cd.NewTokenAdminRegistry(ccipModule.TokenAdminRegistry.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new token admin registry contract shouldn't fail %w", err)
+ }
+ }
+ }
+ ccipModule.Logger.Info().Msg("Finished deploying common contracts")
+ // approve router to spend fee token
+ return ccipModule.ApproveTokens()
+}
+
+func (ccipModule *CCIPCommon) AvgBlockTime(ctx context.Context) (time.Duration, error) {
+ return ccipModule.ChainClient.AvgBlockTime(ctx)
+}
+
+// DynamicPriceGetterConfig specifies the configuration for the price getter in price pipeline.
+// This should match pricegetter.DynamicPriceGetterConfig in core/services/ocr2/plugins/ccip/internal/pricegetter
+type DynamicPriceGetterConfig struct {
+ AggregatorPrices map[common.Address]AggregatorPriceConfig `json:"aggregatorPrices"`
+ StaticPrices map[common.Address]StaticPriceConfig `json:"staticPrices"`
+}
+
+func (d *DynamicPriceGetterConfig) AddPriceConfig(
+ tokenAddr string,
+ aggregatorMap map[common.Address]*contracts.MockAggregator,
+ price *big.Int,
+ chainID uint64,
+) error {
+ aggregatorContract, ok := aggregatorMap[common.HexToAddress(tokenAddr)]
+ if !ok || aggregatorContract == nil {
+ return d.AddStaticPriceConfig(tokenAddr, chainID, price)
+ }
+ return d.AddAggregatorPriceConfig(tokenAddr, aggregatorMap, price)
+}
+
+func (d *DynamicPriceGetterConfig) AddAggregatorPriceConfig(
+ tokenAddr string,
+ aggregatorMap map[common.Address]*contracts.MockAggregator,
+ price *big.Int,
+) error {
+ aggregatorContract, ok := aggregatorMap[common.HexToAddress(tokenAddr)]
+ if !ok || aggregatorContract == nil {
+ return fmt.Errorf("aggregator contract not found for token %s", tokenAddr)
+ }
+ // update round Data
+ err := aggregatorContract.UpdateRoundData(price, nil, nil)
+ if err != nil {
+ return fmt.Errorf("error in updating round data %w", err)
+ }
+
+ d.AggregatorPrices[common.HexToAddress(tokenAddr)] = AggregatorPriceConfig{
+ ChainID: aggregatorContract.ChainID(),
+ AggregatorContractAddress: aggregatorContract.ContractAddress,
+ }
+ return nil
+}
+
+func (d *DynamicPriceGetterConfig) AddStaticPriceConfig(tokenAddr string, chainID uint64, price *big.Int) error {
+ d.StaticPrices[common.HexToAddress(tokenAddr)] = StaticPriceConfig{
+ ChainID: chainID,
+ Price: price,
+ }
+ return nil
+}
+
+func (d *DynamicPriceGetterConfig) String() (string, error) {
+ tokenPricesConfigBytes, err := json.MarshalIndent(d, "", " ")
+ if err != nil {
+ return "", fmt.Errorf("error in marshalling token prices config %w", err)
+ }
+ return string(tokenPricesConfigBytes), nil
+}
+
+// AggregatorPriceConfig specifies a price retrieved from an aggregator contract.
+// This should match pricegetter.AggregatorPriceConfig in core/services/ocr2/plugins/ccip/internal/pricegetter
+type AggregatorPriceConfig struct {
+ ChainID uint64 `json:"chainID,string"`
+ AggregatorContractAddress common.Address `json:"contractAddress"`
+}
+
+// StaticPriceConfig specifies a price defined statically.
+// This should match pricegetter.StaticPriceConfig in core/services/ocr2/plugins/ccip/internal/pricegetter
+type StaticPriceConfig struct {
+ ChainID uint64 `json:"chainID,string"`
+ Price *big.Int `json:"price"`
+}
+
+func NewCCIPCommonFromConfig(
+ logger *zerolog.Logger,
+ testGroupConf *testconfig.CCIPTestGroupConfig,
+ chainClient blockchain.EVMClient,
+ laneConfig *laneconfig.LaneConfig,
+) (*CCIPCommon, error) {
+ newCCIPModule, err := DefaultCCIPModule(logger, testGroupConf, chainClient)
+ if err != nil {
+ return nil, err
+ }
+ newCD := newCCIPModule.Deployer
+ newCCIPModule.LoadContractAddresses(laneConfig, testGroupConf.TokenConfig.NoOfTokensPerChain)
+ if newCCIPModule.TokenAdminRegistry != nil {
+ newCCIPModule.TokenAdminRegistry, err = newCD.NewTokenAdminRegistry(common.HexToAddress(newCCIPModule.TokenAdminRegistry.Address()))
+ if err != nil {
+ return nil, err
+ }
+ }
+ var arm *contracts.ARM
+ if newCCIPModule.ARM != nil {
+ arm, err = newCD.NewARMContract(*newCCIPModule.ARMContract)
+ if err != nil {
+ return nil, err
+ }
+ newCCIPModule.ARM = arm
+ }
+ var pools []*contracts.TokenPool
+ for i := range newCCIPModule.BridgeTokenPools {
+ // if there is usdc token, the corresponding pool will always be added as first one in the slice
+ if newCCIPModule.IsUSDCDeployment() && i == 0 {
+ pool, err := newCCIPModule.tokenDeployer.NewUSDCTokenPoolContract(common.HexToAddress(newCCIPModule.BridgeTokenPools[i].Address()))
+ if err != nil {
+ return nil, err
+ }
+ pools = append(pools, pool)
+ } else {
+ pool, err := newCCIPModule.tokenDeployer.NewLockReleaseTokenPoolContract(common.HexToAddress(newCCIPModule.BridgeTokenPools[i].Address()))
+ if err != nil {
+ return nil, err
+ }
+ pools = append(pools, pool)
+ }
+ }
+ newCCIPModule.BridgeTokenPools = pools
+ var tokens []*contracts.ERC20Token
+ for i := range newCCIPModule.BridgeTokens {
+ token, err := newCCIPModule.tokenDeployer.NewERC20TokenContract(common.HexToAddress(newCCIPModule.BridgeTokens[i].Address()))
+ if err != nil {
+ return nil, err
+ }
+ tokens = append(tokens, token)
+ }
+ newCCIPModule.BridgeTokens = tokens
+ priceAggregators := make(map[common.Address]*contracts.MockAggregator)
+ for k, v := range newCCIPModule.PriceAggregators {
+ aggregator, err := newCD.NewMockAggregator(v.ContractAddress)
+ if err != nil {
+ return nil, err
+ }
+ priceAggregators[k] = aggregator
+ }
+ newCCIPModule.PriceAggregators = priceAggregators
+ newCCIPModule.FeeToken, err = newCCIPModule.Deployer.NewLinkTokenContract(common.HexToAddress(newCCIPModule.FeeToken.Address()))
+ if err != nil {
+ return nil, err
+ }
+ if newCCIPModule.PriceRegistry != nil {
+ newCCIPModule.PriceRegistry, err = newCCIPModule.Deployer.NewPriceRegistry(common.HexToAddress(newCCIPModule.PriceRegistry.Address()))
+ if err != nil {
+ return nil, err
+ }
+ }
+ newCCIPModule.Router, err = newCCIPModule.Deployer.NewRouter(common.HexToAddress(newCCIPModule.Router.Address()))
+ if err != nil {
+ return nil, err
+ }
+ if newCCIPModule.TokenTransmitter != nil {
+ newCCIPModule.TokenTransmitter, err = newCCIPModule.Deployer.NewTokenTransmitter(newCCIPModule.TokenTransmitter.ContractAddress)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return newCCIPModule, nil
+}
+
+func DefaultCCIPModule(
+ logger *zerolog.Logger,
+ testGroupConf *testconfig.CCIPTestGroupConfig,
+ chainClient blockchain.EVMClient,
+) (*CCIPCommon, error) {
+ networkCfg := chainClient.GetNetworkConfig()
+ tokenDeployerChainClient, err := blockchain.ConcurrentEVMClient(*networkCfg, nil, chainClient, *logger)
+ if err != nil {
+ return nil, errors.WithStack(fmt.Errorf("failed to create token deployment chain client for %s: %w", networkCfg.Name, err))
+ }
+ // If we want to deploy tokens as a non CCIP owner, we need to set the default wallet to something other than the first one. The first wallet is used as default CCIP owner for all other ccip contract deployment.
+ // This is not needed for existing deployment as the tokens and pools are already deployed.
+ if contracts.NeedTokenAdminRegistry() &&
+ !pointer.GetBool(testGroupConf.TokenConfig.CCIPOwnerTokens) &&
+ !pointer.GetBool(testGroupConf.ExistingDeployment) &&
+ len(tokenDeployerChainClient.GetWallets()) > 1 {
+ if err = tokenDeployerChainClient.SetDefaultWallet(1); err != nil {
+ return nil, errors.WithStack(fmt.Errorf("failed to set default wallet for token deployment client %s: %w", networkCfg.Name, err))
+ }
+ }
+ cd, err := contracts.NewCCIPContractsDeployer(logger, chainClient)
+ if err != nil {
+ return nil, err
+ }
+ tokenCD, err := contracts.NewCCIPContractsDeployer(logger, tokenDeployerChainClient)
+ if err != nil {
+ return nil, err
+ }
+ return &CCIPCommon{
+ Logger: logger,
+ ChainClient: chainClient,
+ Deployer: cd,
+ tokenDeployer: tokenCD,
+ RateLimiterConfig: contracts.RateLimiterConfig{
+ Rate: contracts.FiftyCoins,
+ Capacity: contracts.HundredCoins,
+ },
+ ExistingDeployment: pointer.GetBool(testGroupConf.ExistingDeployment),
+ MulticallEnabled: pointer.GetBool(testGroupConf.MulticallInOneTx),
+ USDCMockDeployment: testGroupConf.USDCMockDeployment,
+ NoOfTokensNeedingDynamicPrice: pointer.GetInt(testGroupConf.TokenConfig.NoOfTokensWithDynamicPrice),
+ poolFunds: testhelpers.Link(5),
+ gasUpdateWatcherMu: &sync.Mutex{},
+ gasUpdateWatcher: make(map[uint64]*big.Int),
+ tokenPriceUpdateWatcherMu: &sync.Mutex{},
+ tokenPriceUpdateWatcher: make(map[common.Address]*big.Int),
+ PriceAggregators: make(map[common.Address]*contracts.MockAggregator),
+ }, nil
+}
+
+type SourceCCIPModule struct {
+ Common *CCIPCommon
+ Sender common.Address
+ TransferAmount []*big.Int
+ MsgDataLength int64
+ DestinationChainId uint64
+ DestChainSelector uint64
+ DestNetworkName string
+ OnRamp *contracts.OnRamp
+ SrcStartBlock uint64
+ CCIPSendRequestedWatcher *sync.Map // map[string]*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested
+ NewFinalizedBlockNum atomic.Uint64
+ NewFinalizedBlockTimestamp atomic.Time
+}
+
+func (sourceCCIP *SourceCCIPModule) PayCCIPFeeToOwnerAddress() error {
+ isNativeFee := sourceCCIP.Common.FeeToken.EthAddress == common.HexToAddress("0x0")
+ if isNativeFee {
+ err := sourceCCIP.OnRamp.WithdrawNonLinkFees(sourceCCIP.Common.WrappedNative)
+ if err != nil {
+ return err
+ }
+ } else {
+ err := sourceCCIP.OnRamp.SetNops()
+ if err != nil {
+ return err
+ }
+ err = sourceCCIP.OnRamp.PayNops()
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (sourceCCIP *SourceCCIPModule) LoadContracts(conf *laneconfig.LaneConfig) {
+ if conf != nil {
+ cfg, ok := conf.SrcContracts[sourceCCIP.DestNetworkName]
+ if ok {
+ if common.IsHexAddress(cfg.OnRamp) {
+ sourceCCIP.OnRamp = &contracts.OnRamp{
+ EthAddress: common.HexToAddress(cfg.OnRamp),
+ }
+ }
+ if cfg.DeployedAt > 0 {
+ sourceCCIP.SrcStartBlock = cfg.DeployedAt
+ }
+ }
+ }
+}
+
+// SetAllTokenTransferFeeConfigs sets a default transfer fee config for all BridgeTokens on the CCIP source chain.
+// enableAggregateRateLimit is used to enable/disable aggregate rate limit for all BridgeTokens.
+func (sourceCCIP *SourceCCIPModule) SetAllTokenTransferFeeConfigs(enableAggregateRateLimit bool) error {
+ var tokenTransferFeeConfig []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs
+ var tokens, pools []common.Address
+ if len(sourceCCIP.Common.BridgeTokens) != len(sourceCCIP.Common.BridgeTokenPools) {
+ return fmt.Errorf("tokens number %d and pools number %d do not match", len(sourceCCIP.Common.BridgeTokens), len(sourceCCIP.Common.BridgeTokenPools))
+ }
+ for i, token := range sourceCCIP.Common.BridgeTokens {
+ tokens = append(tokens, token.ContractAddress)
+ pools = append(pools, sourceCCIP.Common.BridgeTokenPools[i].EthAddress)
+ conf := evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ Token: token.ContractAddress,
+ MinFeeUSDCents: 50, // $0.5
+ MaxFeeUSDCents: 1_000_000_00, // $ 1 million
+ DeciBps: 5_0, // 5 bps
+ AggregateRateLimitEnabled: enableAggregateRateLimit,
+ }
+ if sourceCCIP.Common.BridgeTokenPools[i].IsUSDC() {
+ conf.DestBytesOverhead = defaultUSDCDestBytesOverhead
+ conf.DestGasOverhead = defaultUSDCDestGasOverhead
+ }
+ tokenTransferFeeConfig = append(tokenTransferFeeConfig, conf)
+ }
+ err := sourceCCIP.OnRamp.SetTokenTransferFeeConfig(tokenTransferFeeConfig)
+ if err != nil {
+ return fmt.Errorf("setting token transfer fee config shouldn't fail %w", err)
+ }
+ // this is required for v1.2.0 ramps
+ err = sourceCCIP.OnRamp.ApplyPoolUpdates(tokens, pools)
+ if err != nil {
+ return fmt.Errorf("applying pool updates shouldn't fail %w", err)
+ }
+ return nil
+}
+
+// DeployContracts deploys all CCIP contracts specific to the source chain
+func (sourceCCIP *SourceCCIPModule) DeployContracts(lane *laneconfig.LaneConfig) error {
+ var err error
+ contractDeployer := sourceCCIP.Common.Deployer
+ log.Info().Msg("Deploying source chain specific contracts")
+
+ sourceCCIP.LoadContracts(lane)
+ sourceChainSelector, err := chainselectors.SelectorFromChainId(sourceCCIP.Common.ChainClient.GetChainID().Uint64())
+ if err != nil {
+ return fmt.Errorf("getting chain selector shouldn't fail %w", err)
+ }
+
+ if sourceCCIP.OnRamp == nil {
+ if sourceCCIP.Common.ExistingDeployment {
+ return fmt.Errorf("existing deployment is set to true but no onramp address is provided")
+ }
+ var tokensAndPools []evm_2_evm_onramp_1_2_0.InternalPoolUpdate
+ var tokenTransferFeeConfig []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs
+
+ sourceCCIP.SrcStartBlock, err = sourceCCIP.Common.ChainClient.LatestBlockNumber(context.Background())
+ if err != nil {
+ return fmt.Errorf("getting latest block number shouldn't fail %w", err)
+ }
+ var tokenAdminReg common.Address
+ if contracts.NeedTokenAdminRegistry() {
+ if sourceCCIP.Common.TokenAdminRegistry == nil {
+ return fmt.Errorf("token admin registry contract address is not provided in lane config")
+ }
+ tokenAdminReg = sourceCCIP.Common.TokenAdminRegistry.EthAddress
+ }
+ sourceCCIP.OnRamp, err = contractDeployer.DeployOnRamp(
+ sourceChainSelector,
+ sourceCCIP.DestChainSelector,
+ tokensAndPools,
+ *sourceCCIP.Common.ARMContract,
+ sourceCCIP.Common.Router.EthAddress,
+ sourceCCIP.Common.PriceRegistry.EthAddress,
+ tokenAdminReg,
+ sourceCCIP.Common.RateLimiterConfig,
+ []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs{
+ {
+ Token: common.HexToAddress(sourceCCIP.Common.FeeToken.Address()),
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: GasFeeMultiplier,
+ PremiumMultiplierWeiPerEth: 1e18,
+ Enabled: true,
+ },
+ {
+ Token: sourceCCIP.Common.WrappedNative,
+ NetworkFeeUSDCents: 1_00,
+ GasMultiplierWeiPerEth: GasFeeMultiplier,
+ PremiumMultiplierWeiPerEth: 1e18,
+ Enabled: true,
+ },
+ }, tokenTransferFeeConfig, sourceCCIP.Common.FeeToken.EthAddress)
+
+ if err != nil {
+ return fmt.Errorf("onRamp deployment shouldn't fail %w", err)
+ }
+
+ err = sourceCCIP.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("waiting for onRamp deployment shouldn't fail %w", err)
+ }
+
+ // update source Router with OnRamp address
+ err = sourceCCIP.Common.Router.SetOnRamp(sourceCCIP.DestChainSelector, sourceCCIP.OnRamp.EthAddress)
+ if err != nil {
+ return fmt.Errorf("setting onramp on the router shouldn't fail %w", err)
+ }
+ // now sync the pools and tokens
+ err := sourceCCIP.SetAllTokenTransferFeeConfigs(true)
+ if err != nil {
+ return err
+ }
+ } else {
+ sourceCCIP.OnRamp, err = contractDeployer.NewOnRamp(sourceCCIP.OnRamp.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new onramp contractshouldn't fail %w", err)
+ }
+ }
+ return nil
+}
+
+func (sourceCCIP *SourceCCIPModule) CollectBalanceRequirements() []testhelpers.BalanceReq {
+ var balancesReq []testhelpers.BalanceReq
+ for _, token := range sourceCCIP.Common.BridgeTokens {
+ balancesReq = append(balancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("BridgeToken-%s-Address-%s", token.Address(), sourceCCIP.Sender.Hex()),
+ Addr: sourceCCIP.Sender,
+ Getter: GetterForLinkToken(token.BalanceOf, sourceCCIP.Sender.Hex()),
+ })
+ }
+ for i, pool := range sourceCCIP.Common.BridgeTokenPools {
+ balancesReq = append(balancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("BridgeToken-%s-TokenPool-%s", sourceCCIP.Common.BridgeTokens[i].Address(), pool.Address()),
+ Addr: pool.EthAddress,
+ Getter: GetterForLinkToken(sourceCCIP.Common.BridgeTokens[i].BalanceOf, pool.Address()),
+ })
+ }
+
+ if sourceCCIP.Common.FeeToken.Address() != common.HexToAddress("0x0").String() {
+ balancesReq = append(balancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("FeeToken-%s-Address-%s", sourceCCIP.Common.FeeToken.Address(), sourceCCIP.Sender.Hex()),
+ Addr: sourceCCIP.Sender,
+ Getter: GetterForLinkToken(sourceCCIP.Common.FeeToken.BalanceOf, sourceCCIP.Sender.Hex()),
+ })
+ balancesReq = append(balancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("FeeToken-%s-Router-%s", sourceCCIP.Common.FeeToken.Address(), sourceCCIP.Common.Router.Address()),
+ Addr: sourceCCIP.Common.Router.EthAddress,
+ Getter: GetterForLinkToken(sourceCCIP.Common.FeeToken.BalanceOf, sourceCCIP.Common.Router.Address()),
+ })
+ balancesReq = append(balancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("FeeToken-%s-OnRamp-%s", sourceCCIP.Common.FeeToken.Address(), sourceCCIP.OnRamp.Address()),
+ Addr: sourceCCIP.OnRamp.EthAddress,
+ Getter: GetterForLinkToken(sourceCCIP.Common.FeeToken.BalanceOf, sourceCCIP.OnRamp.Address()),
+ })
+ balancesReq = append(balancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("FeeToken-%s-Prices-%s", sourceCCIP.Common.FeeToken.Address(), sourceCCIP.Common.PriceRegistry.Address()),
+ Addr: sourceCCIP.Common.PriceRegistry.EthAddress,
+ Getter: GetterForLinkToken(sourceCCIP.Common.FeeToken.BalanceOf, sourceCCIP.Common.PriceRegistry.Address()),
+ })
+ }
+ return balancesReq
+}
+
+func (sourceCCIP *SourceCCIPModule) UpdateBalance(
+ noOfReq int64,
+ totalFee *big.Int,
+ balances *BalanceSheet,
+) {
+ if len(sourceCCIP.TransferAmount) > 0 {
+ for i := range sourceCCIP.TransferAmount {
+ if sourceCCIP.TransferAmount[i] == nil { // nil transfer amount means no transfer for this token
+ continue
+ }
+ // if length of sourceCCIP.TransferAmount is more than available bridge token use first bridge token
+ token := sourceCCIP.Common.BridgeTokens[0]
+ if i < len(sourceCCIP.Common.BridgeTokens) {
+ token = sourceCCIP.Common.BridgeTokens[i]
+ }
+ name := fmt.Sprintf("BridgeToken-%s-Address-%s", token.Address(), sourceCCIP.Sender.Hex())
+ balances.Update(name, BalanceItem{
+ Address: sourceCCIP.Sender,
+ Getter: GetterForLinkToken(token.BalanceOf, sourceCCIP.Sender.Hex()),
+ AmtToSub: bigmath.Mul(big.NewInt(noOfReq), sourceCCIP.TransferAmount[i]),
+ })
+ }
+ for i := range sourceCCIP.TransferAmount {
+ // if length of sourceCCIP.TransferAmount is more than available bridge token use first bridge token
+ pool := sourceCCIP.Common.BridgeTokenPools[0]
+ index := 0
+ if i < len(sourceCCIP.Common.BridgeTokenPools) {
+ pool = sourceCCIP.Common.BridgeTokenPools[i]
+ index = i
+ }
+
+ name := fmt.Sprintf("BridgeToken-%s-TokenPool-%s", sourceCCIP.Common.BridgeTokens[index].Address(), pool.Address())
+ balances.Update(name, BalanceItem{
+ Address: pool.EthAddress,
+ Getter: GetterForLinkToken(sourceCCIP.Common.BridgeTokens[index].BalanceOf, pool.Address()),
+ AmtToAdd: bigmath.Mul(big.NewInt(noOfReq), sourceCCIP.TransferAmount[i]),
+ })
+ }
+ }
+ if sourceCCIP.Common.FeeToken.Address() != common.HexToAddress("0x0").String() {
+ name := fmt.Sprintf("FeeToken-%s-Address-%s", sourceCCIP.Common.FeeToken.Address(), sourceCCIP.Sender.Hex())
+ balances.Update(name, BalanceItem{
+ Address: sourceCCIP.Sender,
+ Getter: GetterForLinkToken(sourceCCIP.Common.FeeToken.BalanceOf, sourceCCIP.Sender.Hex()),
+ AmtToSub: totalFee,
+ })
+ name = fmt.Sprintf("FeeToken-%s-Prices-%s", sourceCCIP.Common.FeeToken.Address(), sourceCCIP.Common.PriceRegistry.Address())
+ balances.Update(name, BalanceItem{
+ Address: sourceCCIP.Common.PriceRegistry.EthAddress,
+ Getter: GetterForLinkToken(sourceCCIP.Common.FeeToken.BalanceOf, sourceCCIP.Common.PriceRegistry.Address()),
+ })
+ name = fmt.Sprintf("FeeToken-%s-Router-%s", sourceCCIP.Common.FeeToken.Address(), sourceCCIP.Common.Router.Address())
+ balances.Update(name, BalanceItem{
+ Address: sourceCCIP.Common.Router.EthAddress,
+ Getter: GetterForLinkToken(sourceCCIP.Common.FeeToken.BalanceOf, sourceCCIP.Common.Router.Address()),
+ })
+ name = fmt.Sprintf("FeeToken-%s-OnRamp-%s", sourceCCIP.Common.FeeToken.Address(), sourceCCIP.OnRamp.Address())
+ balances.Update(name, BalanceItem{
+ Address: sourceCCIP.OnRamp.EthAddress,
+ Getter: GetterForLinkToken(sourceCCIP.Common.FeeToken.BalanceOf, sourceCCIP.OnRamp.Address()),
+ AmtToAdd: totalFee,
+ })
+ }
+}
+
+func (sourceCCIP *SourceCCIPModule) AssertSendRequestedLogFinalized(
+ lggr *zerolog.Logger,
+ txHash common.Hash,
+ sendReqData []*contracts.SendReqEventData,
+ prevEventAt time.Time,
+ reqStats []*testreporters.RequestStat,
+) (time.Time, uint64, error) {
+ if len(sendReqData) != len(reqStats) {
+ return time.Time{}, 0, fmt.Errorf("sendReqData and reqStats length mismatch")
+ }
+ var gasUsed uint64
+ receipt, err := sourceCCIP.Common.ChainClient.GetTxReceipt(txHash)
+ if err == nil {
+ gasUsed = receipt.GasUsed
+ }
+ lggr.Info().Msg("Waiting for CCIPSendRequested event log to be finalized")
+ finalizedBlockNum, finalizedAt, err := sourceCCIP.Common.ChainClient.WaitForFinalizedTx(txHash)
+ if err != nil || finalizedBlockNum == nil {
+ for i, stat := range reqStats {
+ stat.UpdateState(lggr, stat.SeqNum, testreporters.SourceLogFinalized, time.Since(prevEventAt), testreporters.Failure, &testreporters.TransactionStats{
+ MsgID: fmt.Sprintf("0x%x", sendReqData[i].MessageId[:]),
+ Fee: sendReqData[i].Fee.String(),
+ NoOfTokensSent: sendReqData[i].NoOfTokens,
+ MessageBytesLength: int64(sendReqData[i].DataLength),
+ TxHash: txHash.Hex(),
+ })
+ }
+ return time.Time{}, 0, fmt.Errorf("error waiting for CCIPSendRequested event log to be finalized - %w", err)
+ }
+ for i, stat := range reqStats {
+ stat.UpdateState(lggr, stat.SeqNum, testreporters.SourceLogFinalized, finalizedAt.Sub(prevEventAt), testreporters.Success,
+ &testreporters.TransactionStats{
+ MsgID: fmt.Sprintf("0x%x", sendReqData[i].MessageId[:]),
+ Fee: sendReqData[i].Fee.String(),
+ GasUsed: gasUsed,
+ NoOfTokensSent: sendReqData[i].NoOfTokens,
+ MessageBytesLength: int64(sendReqData[i].DataLength),
+ TxHash: txHash.Hex(),
+ FinalizedByBlock: finalizedBlockNum.String(),
+ FinalizedAt: finalizedAt.String(),
+ })
+ }
+ return finalizedAt, finalizedBlockNum.Uint64(), nil
+}
+
+func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe *commonconfig.Duration) *time.Time {
+ if timeframe == nil {
+ return nil
+ }
+ var foundAt *time.Time
+ lastSeenTimestamp := time.Now().UTC().Add(-timeframe.Duration())
+ sourceCCIP.CCIPSendRequestedWatcher.Range(func(_, value any) bool {
+ if sendRequestedEvents, exists := value.([]*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested); exists {
+ for _, sendRequestedEvent := range sendRequestedEvents {
+ raw := sendRequestedEvent.Raw
+ hdr, err := sourceCCIP.Common.ChainClient.HeaderByNumber(context.Background(), big.NewInt(int64(raw.BlockNumber)))
+ if err == nil {
+ if hdr.Timestamp.After(lastSeenTimestamp) {
+ foundAt = pointer.ToTime(hdr.Timestamp)
+ return false
+ }
+ }
+ }
+ }
+ return true
+ })
+ return foundAt
+}
+
+func (sourceCCIP *SourceCCIPModule) AssertEventCCIPSendRequested(
+ lggr *zerolog.Logger,
+ txHash string,
+ timeout time.Duration,
+ prevEventAt time.Time,
+ reqStat []*testreporters.RequestStat,
+) ([]*contracts.SendReqEventData, time.Time, error) {
+ lggr.Info().Str("Timeout", timeout.String()).Msg("Waiting for CCIPSendRequested event")
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+ timer := time.NewTimer(timeout)
+ defer timer.Stop()
+ resetTimer := 0
+ for {
+ select {
+ case <-ticker.C:
+ value, ok := sourceCCIP.CCIPSendRequestedWatcher.Load(txHash)
+ if ok {
+ // if sendrequested events are found, check if the number of events are same as the number of requests
+ if sendRequestedEvents, exists := value.([]*contracts.SendReqEventData); exists && len(sendRequestedEvents) == len(reqStat) {
+ // if the value is processed, delete it from the map
+ sourceCCIP.CCIPSendRequestedWatcher.Delete(txHash)
+ for i, sendRequestedEvent := range sendRequestedEvents {
+ seqNum := sendRequestedEvent.SequenceNumber
+ lggr = ptr.Ptr(lggr.With().
+ Uint64("SequenceNumber", seqNum).
+ Str("MsgID", fmt.Sprintf("0x%x", sendRequestedEvent.MessageId[:])).
+ Logger())
+ // prevEventAt is the time when the message was successful, this should be same as the time when the event was emitted
+ reqStat[i].UpdateState(lggr, seqNum, testreporters.CCIPSendRe, 0, testreporters.Success, nil)
+ }
+ var err error
+ if len(sendRequestedEvents) == 0 {
+ err = fmt.Errorf("message logs not found, no CCIPSendRequested event found for tx %s", txHash)
+ }
+ return sendRequestedEvents, prevEventAt, err
+ }
+ }
+ case <-timer.C:
+ // if there is connection issue reset the timer :
+ if sourceCCIP.Common.IsConnectionRestoredRecently != nil && !sourceCCIP.Common.IsConnectionRestoredRecently.Load() {
+ if resetTimer > 2 {
+ for _, stat := range reqStat {
+ stat.UpdateState(lggr, 0, testreporters.CCIPSendRe, time.Since(prevEventAt), testreporters.Failure,
+ &testreporters.TransactionStats{
+ TxHash: txHash,
+ })
+ }
+ return nil, time.Now(), fmt.Errorf("possible RPC issue - CCIPSendRequested event is not found for tx %s", txHash)
+ }
+ resetTimer++
+ timer.Reset(timeout)
+ lggr.Info().Int("count of reset", resetTimer).Msg("Resetting timer to validate CCIPSendRequested event")
+ continue
+ }
+ for _, stat := range reqStat {
+ stat.UpdateState(lggr, 0, testreporters.CCIPSendRe, time.Since(prevEventAt), testreporters.Failure,
+ &testreporters.TransactionStats{
+ TxHash: txHash,
+ })
+ }
+ return nil, time.Now(), fmt.Errorf("CCIPSendRequested event is not found for tx %s", txHash)
+ }
+ }
+}
+
+// CCIPMsg constructs the message for a CCIP request
+func (sourceCCIP *SourceCCIPModule) CCIPMsg(
+ receiver common.Address,
+ gasLimit *big.Int,
+) (router.ClientEVM2AnyMessage, error) {
+ length := sourceCCIP.MsgDataLength
+ var data string
+ if length > 0 {
+ b := make([]byte, length)
+ _, err := crypto_rand.Read(b)
+ if err != nil {
+ return router.ClientEVM2AnyMessage{}, fmt.Errorf("failed generating random string: %w", err)
+ }
+ randomString := base64.URLEncoding.EncodeToString(b)
+ data = randomString[:length]
+ }
+
+ tokenAndAmounts := []router.ClientEVMTokenAmount{}
+ for i, amount := range sourceCCIP.TransferAmount {
+ if amount == nil { // make nil transfer amount 0 to avoid panics
+ sourceCCIP.TransferAmount[i] = big.NewInt(0)
+ }
+ token := sourceCCIP.Common.BridgeTokens[0]
+ // if length of sourceCCIP.TransferAmount is more than available bridge token use first bridge token
+ if i < len(sourceCCIP.Common.BridgeTokens) {
+ token = sourceCCIP.Common.BridgeTokens[i]
+ }
+ if amount == nil || amount.Cmp(big.NewInt(0)) == 0 {
+ log.Warn().
+ Str("Token Address", token.Address()).
+ Int("Token Index", i).
+ Msg("Not sending a request for token transfer as the amount is 0 or nil")
+ continue
+ }
+ tokenAndAmounts = append(tokenAndAmounts, router.ClientEVMTokenAmount{
+ Token: common.HexToAddress(token.Address()), Amount: amount,
+ })
+ }
+
+ receiverAddr, err := utils.ABIEncode(`[{"type":"address"}]`, receiver)
+ if err != nil {
+ return router.ClientEVM2AnyMessage{}, fmt.Errorf("failed encoding the receiver address: %w", err)
+ }
+
+ extraArgsV1, err := testhelpers.GetEVMExtraArgsV1(gasLimit, false)
+ if err != nil {
+ return router.ClientEVM2AnyMessage{}, fmt.Errorf("failed encoding the options field: %w", err)
+ }
+ // form the message for transfer
+ return router.ClientEVM2AnyMessage{
+ Receiver: receiverAddr,
+ Data: []byte(data),
+ TokenAmounts: tokenAndAmounts,
+ FeeToken: common.HexToAddress(sourceCCIP.Common.FeeToken.Address()),
+ ExtraArgs: extraArgsV1,
+ }, nil
+}
+
+// SendRequest sends a CCIP request to the source chain's router contract
+func (sourceCCIP *SourceCCIPModule) SendRequest(
+ receiver common.Address,
+ gasLimit *big.Int,
+) (common.Hash, time.Duration, *big.Int, error) {
+ var d time.Duration
+ destChainSelector, err := chainselectors.SelectorFromChainId(sourceCCIP.DestinationChainId)
+ if err != nil {
+ return common.Hash{}, d, nil, fmt.Errorf("failed getting the chain selector: %w", err)
+ }
+ // form the message for transfer
+ msg, err := sourceCCIP.CCIPMsg(receiver, gasLimit)
+ if err != nil {
+ return common.Hash{}, d, nil, fmt.Errorf("failed forming the ccip msg: %w", err)
+ }
+
+ fee, err := sourceCCIP.Common.Router.GetFee(destChainSelector, msg)
+ if err != nil {
+ log.Info().Interface("Msg", msg).Msg("CCIP msg")
+ reason, _ := blockchain.RPCErrorFromError(err)
+ if reason != "" {
+ return common.Hash{}, d, nil, fmt.Errorf("failed getting the fee: %s", reason)
+ }
+ return common.Hash{}, d, nil, fmt.Errorf("failed getting the fee: %w", err)
+ }
+ log.Info().Str("Fee", fee.String()).Msg("Calculated fee")
+
+ var sendTx *types.Transaction
+ timeNow := time.Now()
+ feeToken := common.HexToAddress(sourceCCIP.Common.FeeToken.Address())
+ // initiate the transfer
+ // if the fee token address is 0x0 it will use Native as fee token and the fee amount should be mentioned in bind.TransactOpts's value
+ if feeToken != (common.Address{}) {
+ sendTx, err = sourceCCIP.Common.Router.CCIPSendAndProcessTx(destChainSelector, msg, nil)
+ if err != nil {
+ txHash := common.Hash{}
+ if sendTx != nil {
+ txHash = sendTx.Hash()
+ }
+ return txHash, time.Since(timeNow), nil, fmt.Errorf("failed initiating the transfer ccip-send: %w", err)
+ }
+ } else {
+ sendTx, err = sourceCCIP.Common.Router.CCIPSendAndProcessTx(destChainSelector, msg, fee)
+ if err != nil {
+ txHash := common.Hash{}
+ if sendTx != nil {
+ txHash = sendTx.Hash()
+ }
+ return txHash, time.Since(timeNow), nil, fmt.Errorf("failed initiating the transfer ccip-send: %w", err)
+ }
+ }
+
+ log.Info().
+ Str("Network", sourceCCIP.Common.ChainClient.GetNetworkName()).
+ Str("Send token transaction", sendTx.Hash().String()).
+ Str("lane", fmt.Sprintf("%s-->%s", sourceCCIP.Common.ChainClient.GetNetworkName(), sourceCCIP.DestNetworkName)).
+ Msg("Sending token")
+ return sendTx.Hash(), time.Since(timeNow), fee, nil
+}
+
+func DefaultSourceCCIPModule(
+ logger *zerolog.Logger,
+ testConf *testconfig.CCIPTestGroupConfig,
+ chainClient blockchain.EVMClient,
+ destChainId uint64,
+ destChain string,
+ laneConf *laneconfig.LaneConfig,
+) (*SourceCCIPModule, error) {
+ cmn, err := NewCCIPCommonFromConfig(
+ logger, testConf, chainClient, laneConf,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ destChainSelector, err := chainselectors.SelectorFromChainId(destChainId)
+ if err != nil {
+ return nil, fmt.Errorf("failed getting the chain selector: %w", err)
+ }
+ source := &SourceCCIPModule{
+ Common: cmn,
+ TransferAmount: testConf.MsgDetails.TransferAmounts(),
+ MsgDataLength: pointer.GetInt64(testConf.MsgDetails.DataLength),
+ DestinationChainId: destChainId,
+ DestChainSelector: destChainSelector,
+ DestNetworkName: destChain,
+ Sender: common.HexToAddress(chainClient.GetDefaultWallet().Address()),
+ CCIPSendRequestedWatcher: &sync.Map{},
+ }
+
+ return source, nil
+}
+
+type DestCCIPModule struct {
+ Common *CCIPCommon
+ SourceChainId uint64
+ SourceChainSelector uint64
+ SourceNetworkName string
+ CommitStore *contracts.CommitStore
+ ReceiverDapp *contracts.ReceiverDapp
+ OffRamp *contracts.OffRamp
+ ReportAcceptedWatcher *sync.Map
+ ExecStateChangedWatcher *sync.Map
+ ReportBlessedWatcher *sync.Map
+ ReportBlessedBySeqNum *sync.Map
+ NextSeqNumToCommit *atomic.Uint64
+ DestStartBlock uint64
+}
+
+func (destCCIP *DestCCIPModule) LoadContracts(conf *laneconfig.LaneConfig) {
+ if conf != nil {
+ cfg, ok := conf.DestContracts[destCCIP.SourceNetworkName]
+ if ok {
+ if common.IsHexAddress(cfg.OffRamp) {
+ destCCIP.OffRamp = &contracts.OffRamp{
+ EthAddress: common.HexToAddress(cfg.OffRamp),
+ }
+ }
+ if common.IsHexAddress(cfg.CommitStore) {
+ destCCIP.CommitStore = &contracts.CommitStore{
+ EthAddress: common.HexToAddress(cfg.CommitStore),
+ }
+ }
+ if common.IsHexAddress(cfg.ReceiverDapp) {
+ destCCIP.ReceiverDapp = &contracts.ReceiverDapp{
+ EthAddress: common.HexToAddress(cfg.ReceiverDapp),
+ }
+ }
+ }
+ }
+}
+
+func (destCCIP *DestCCIPModule) SyncTokensAndPools(srcTokens []*contracts.ERC20Token) error {
+ if destCCIP.OffRamp.Instance.V1_2_0 == nil {
+ return nil
+ }
+ var sourceTokens, pools []common.Address
+
+ for _, token := range srcTokens {
+ sourceTokens = append(sourceTokens, common.HexToAddress(token.Address()))
+ }
+
+ for i := range destCCIP.Common.BridgeTokenPools {
+ pools = append(pools, destCCIP.Common.BridgeTokenPools[i].EthAddress)
+ }
+ if len(sourceTokens) != len(pools) {
+ return fmt.Errorf("source token and destination pool length mismatch")
+ }
+ // if number of tokens are more than 10, then we need to split the tokens in batch of 10 and call sync
+ // otherwise the tx gets too large and we will get out of gas error
+ if len(sourceTokens) > 10 {
+ for i := 0; i < len(sourceTokens); i += 10 {
+ end := i + 10
+ if end > len(sourceTokens) {
+ end = len(sourceTokens)
+ }
+ err := destCCIP.OffRamp.SyncTokensAndPools(sourceTokens[i:end], pools[i:end])
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ return destCCIP.OffRamp.SyncTokensAndPools(sourceTokens, pools)
+}
+
+// AddRateLimitTokens adds token pairs to the OffRamp's rate limiting
+func (destCCIP *DestCCIPModule) AddRateLimitTokens(srcTokens, destTokens []*contracts.ERC20Token) error {
+ if destCCIP.OffRamp.Instance.Latest == nil {
+ return nil
+ }
+ if srcTokens == nil || destTokens == nil {
+ return fmt.Errorf("source or destination tokens are nil")
+ }
+
+ if len(srcTokens) != len(destTokens) {
+ return fmt.Errorf("source and destination token length mismatch")
+ }
+
+ var sourceTokenAddresses, destTokenAddresses []common.Address
+
+ for i, token := range srcTokens {
+ sourceTokenAddresses = append(sourceTokenAddresses, common.HexToAddress(token.Address()))
+ destTokenAddresses = append(destTokenAddresses, common.HexToAddress(destTokens[i].Address()))
+ }
+
+ // if number of tokens are more than 10, then we need to split the tokens in batch of 10 and update the rate limit
+ // otherwise the tx gets too large and we will get out of gas error
+ if len(sourceTokenAddresses) > 10 {
+ for i := 0; i < len(sourceTokenAddresses); i += 10 {
+ end := i + 10
+ if end > len(sourceTokenAddresses) {
+ end = len(sourceTokenAddresses)
+ }
+ err := destCCIP.OffRamp.AddRateLimitTokens(sourceTokenAddresses[i:end], destTokenAddresses[i:end])
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ return destCCIP.OffRamp.AddRateLimitTokens(sourceTokenAddresses, destTokenAddresses)
+}
+
+// RemoveRateLimitTokens removes token pairs from the OffRamp's rate limiting.
+// If you ask to remove a token pair that doesn't exist, it will return an error.
+func (destCCIP *DestCCIPModule) RemoveRateLimitTokens(ctx context.Context, srcTokens, destTokens []*contracts.ERC20Token) error {
+ if srcTokens == nil || destTokens == nil {
+ return fmt.Errorf("source or destination tokens are nil")
+ }
+
+ if len(srcTokens) != len(destTokens) {
+ return fmt.Errorf("source and destination token length mismatch")
+ }
+
+ var sourceTokenAddresses, destTokenAddresses []common.Address
+
+ for i, token := range srcTokens {
+ sourceTokenAddresses = append(sourceTokenAddresses, common.HexToAddress(token.Address()))
+ destTokenAddresses = append(destTokenAddresses, common.HexToAddress(destTokens[i].Address()))
+ }
+
+ return destCCIP.OffRamp.RemoveRateLimitTokens(ctx, sourceTokenAddresses, destTokenAddresses)
+}
+
+// RemoveAllRateLimitTokens removes all token pairs from the OffRamp's rate limiting.
+func (destCCIP *DestCCIPModule) RemoveAllRateLimitTokens(ctx context.Context) error {
+ return destCCIP.OffRamp.RemoveAllRateLimitTokens(ctx)
+}
+
+// DeployContracts deploys all CCIP contracts specific to the destination chain
+func (destCCIP *DestCCIPModule) DeployContracts(
+ sourceCCIP SourceCCIPModule,
+ lane *laneconfig.LaneConfig,
+) error {
+ var err error
+ contractDeployer := destCCIP.Common.Deployer
+ log.Info().Msg("Deploying destination chain specific contracts")
+ destCCIP.LoadContracts(lane)
+ destChainSelector, err := chainselectors.SelectorFromChainId(destCCIP.Common.ChainClient.GetChainID().Uint64())
+ if err != nil {
+ return fmt.Errorf("failed to get chain selector for destination chain id %d: %w", destCCIP.Common.ChainClient.GetChainID().Uint64(), err)
+ }
+ destCCIP.DestStartBlock, err = destCCIP.Common.ChainClient.LatestBlockNumber(context.Background())
+ if err != nil {
+ return fmt.Errorf("getting latest block number shouldn't fail %w", err)
+ }
+ if !destCCIP.Common.ExistingDeployment && len(sourceCCIP.Common.BridgeTokenPools) != len(destCCIP.Common.BridgeTokenPools) {
+ return fmt.Errorf("source and destination token pool number does not match")
+ }
+
+ if destCCIP.CommitStore == nil {
+ if destCCIP.Common.ExistingDeployment {
+ return fmt.Errorf("commit store address not provided in lane config")
+ }
+ // commitStore responsible for validating the transfer message
+ destCCIP.CommitStore, err = contractDeployer.DeployCommitStore(
+ destCCIP.SourceChainSelector,
+ destChainSelector,
+ sourceCCIP.OnRamp.EthAddress,
+ *destCCIP.Common.ARMContract,
+ )
+ if err != nil {
+ return fmt.Errorf("deploying commitstore shouldn't fail %w", err)
+ }
+ err = destCCIP.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("waiting for commitstore deployment shouldn't fail %w", err)
+ }
+
+ // CommitStore can update
+ err = destCCIP.Common.PriceRegistry.AddPriceUpdater(destCCIP.CommitStore.EthAddress)
+ if err != nil {
+ return fmt.Errorf("setting commitstore as fee updater shouldn't fail %w", err)
+ }
+ err = destCCIP.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("waiting for setting commitstore as fee updater shouldn't fail %w", err)
+ }
+ } else {
+ destCCIP.CommitStore, err = contractDeployer.NewCommitStore(destCCIP.CommitStore.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new commitstore shouldn't fail %w", err)
+ }
+ }
+
+ if destCCIP.OffRamp == nil {
+ if destCCIP.Common.ExistingDeployment {
+ return fmt.Errorf("offramp address not provided in lane config")
+ }
+ var tokenAdminReg common.Address
+ if contracts.NeedTokenAdminRegistry() {
+ if destCCIP.Common.TokenAdminRegistry == nil {
+ return fmt.Errorf("token admin registry contract address is not provided in lane config")
+ }
+ tokenAdminReg = destCCIP.Common.TokenAdminRegistry.EthAddress
+ }
+ destCCIP.OffRamp, err = contractDeployer.DeployOffRamp(
+ destCCIP.SourceChainSelector,
+ destChainSelector,
+ destCCIP.CommitStore.EthAddress,
+ sourceCCIP.OnRamp.EthAddress,
+ destCCIP.Common.RateLimiterConfig,
+ []common.Address{},
+ []common.Address{},
+ *destCCIP.Common.ARMContract,
+ tokenAdminReg,
+ )
+ if err != nil {
+ return fmt.Errorf("deploying offramp shouldn't fail %w", err)
+ }
+ err = destCCIP.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("waiting for offramp deployment shouldn't fail %w", err)
+ }
+
+ // apply offramp updates
+ _, err = destCCIP.Common.Router.AddOffRamp(destCCIP.OffRamp.EthAddress, destCCIP.SourceChainSelector)
+ if err != nil {
+ return fmt.Errorf("setting offramp as fee updater shouldn't fail %w", err)
+ }
+
+ err = destCCIP.AddRateLimitTokens(sourceCCIP.Common.BridgeTokens, destCCIP.Common.BridgeTokens)
+ if err != nil {
+ return fmt.Errorf("setting rate limited tokens shouldn't fail %w", err)
+ }
+ err = destCCIP.SyncTokensAndPools(sourceCCIP.Common.BridgeTokens)
+ if err != nil {
+ return fmt.Errorf("syncing tokens and pools shouldn't fail %w", err)
+ }
+ err = destCCIP.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("waiting for events on destination contract shouldn't fail %w", err)
+ }
+ } else {
+ destCCIP.OffRamp, err = contractDeployer.NewOffRamp(destCCIP.OffRamp.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new offramp shouldn't fail %w", err)
+ }
+ }
+ if destCCIP.ReceiverDapp == nil {
+ // ReceiverDapp
+ destCCIP.ReceiverDapp, err = contractDeployer.DeployReceiverDapp(false)
+ if err != nil {
+ return fmt.Errorf("receiverDapp contract should be deployed successfully %w", err)
+ }
+ err = destCCIP.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("waiting for events on destination contract deployments %w", err)
+ }
+ } else {
+ destCCIP.ReceiverDapp, err = contractDeployer.NewReceiverDapp(destCCIP.ReceiverDapp.EthAddress)
+ if err != nil {
+ return fmt.Errorf("getting new receiverDapp shouldn't fail %w", err)
+ }
+ }
+ return nil
+}
+
+func (destCCIP *DestCCIPModule) CollectBalanceRequirements() []testhelpers.BalanceReq {
+ var destBalancesReq []testhelpers.BalanceReq
+ for _, token := range destCCIP.Common.BridgeTokens {
+ destBalancesReq = append(destBalancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("BridgeToken-%s-Address-%s", token.Address(), destCCIP.ReceiverDapp.Address()),
+ Addr: destCCIP.ReceiverDapp.EthAddress,
+ Getter: GetterForLinkToken(token.BalanceOf, destCCIP.ReceiverDapp.Address()),
+ })
+ }
+ for i, pool := range destCCIP.Common.BridgeTokenPools {
+ destBalancesReq = append(destBalancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("BridgeToken-%s-TokenPool-%s", destCCIP.Common.BridgeTokens[i].Address(), pool.Address()),
+ Addr: pool.EthAddress,
+ Getter: GetterForLinkToken(destCCIP.Common.BridgeTokens[i].BalanceOf, pool.Address()),
+ })
+ }
+ if destCCIP.Common.FeeToken.Address() != common.HexToAddress("0x0").String() {
+ destBalancesReq = append(destBalancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("FeeToken-%s-Address-%s", destCCIP.Common.FeeToken.Address(), destCCIP.ReceiverDapp.Address()),
+ Addr: destCCIP.ReceiverDapp.EthAddress,
+ Getter: GetterForLinkToken(destCCIP.Common.FeeToken.BalanceOf, destCCIP.ReceiverDapp.Address()),
+ })
+ destBalancesReq = append(destBalancesReq, testhelpers.BalanceReq{
+ Name: fmt.Sprintf("FeeToken-%s-OffRamp-%s", destCCIP.Common.FeeToken.Address(), destCCIP.OffRamp.Address()),
+ Addr: destCCIP.OffRamp.EthAddress,
+ Getter: GetterForLinkToken(destCCIP.Common.FeeToken.BalanceOf, destCCIP.OffRamp.Address()),
+ })
+ }
+ return destBalancesReq
+}
+
+func (destCCIP *DestCCIPModule) UpdateBalance(
+ transferAmount []*big.Int,
+ noOfReq int64,
+ balance *BalanceSheet,
+) {
+ if len(transferAmount) > 0 {
+ for i := range transferAmount {
+ token := destCCIP.Common.BridgeTokens[0]
+ if i < len(destCCIP.Common.BridgeTokens) {
+ token = destCCIP.Common.BridgeTokens[i]
+ }
+ name := fmt.Sprintf("BridgeToken-%s-Address-%s", token.Address(), destCCIP.ReceiverDapp.Address())
+ balance.Update(name, BalanceItem{
+ Address: destCCIP.ReceiverDapp.EthAddress,
+ Getter: GetterForLinkToken(token.BalanceOf, destCCIP.ReceiverDapp.Address()),
+ AmtToAdd: bigmath.Mul(big.NewInt(noOfReq), transferAmount[i]),
+ })
+ }
+ for i := range transferAmount {
+ pool := destCCIP.Common.BridgeTokenPools[0]
+ index := 0
+ if i < len(destCCIP.Common.BridgeTokenPools) {
+ pool = destCCIP.Common.BridgeTokenPools[i]
+ index = i
+ }
+ name := fmt.Sprintf("BridgeToken-%s-TokenPool-%s", destCCIP.Common.BridgeTokens[index].Address(), pool.Address())
+ balance.Update(name, BalanceItem{
+ Address: pool.EthAddress,
+ Getter: GetterForLinkToken(destCCIP.Common.BridgeTokens[index].BalanceOf, pool.Address()),
+ AmtToSub: bigmath.Mul(big.NewInt(noOfReq), transferAmount[i]),
+ })
+ }
+ }
+ if destCCIP.Common.FeeToken.Address() != common.HexToAddress("0x0").String() {
+ name := fmt.Sprintf("FeeToken-%s-OffRamp-%s", destCCIP.Common.FeeToken.Address(), destCCIP.OffRamp.Address())
+ balance.Update(name, BalanceItem{
+ Address: destCCIP.OffRamp.EthAddress,
+ Getter: GetterForLinkToken(destCCIP.Common.FeeToken.BalanceOf, destCCIP.OffRamp.Address()),
+ })
+
+ name = fmt.Sprintf("FeeToken-%s-Address-%s", destCCIP.Common.FeeToken.Address(), destCCIP.ReceiverDapp.Address())
+ balance.Update(name, BalanceItem{
+ Address: destCCIP.ReceiverDapp.EthAddress,
+ Getter: GetterForLinkToken(destCCIP.Common.FeeToken.BalanceOf, destCCIP.ReceiverDapp.Address()),
+ })
+ }
+}
+
+// AssertNoReportAcceptedEventReceived validates that no ExecutionStateChangedEvent is emitted for mentioned timeRange after lastSeenTimestamp
+func (destCCIP *DestCCIPModule) AssertNoReportAcceptedEventReceived(lggr *zerolog.Logger, timeRange time.Duration, lastSeenTimestamp time.Time) error {
+ ctx, cancel := context.WithTimeout(context.Background(), timeRange)
+ defer cancel()
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ticker.C:
+ var eventFoundAfterCursing *time.Time
+ // verify if CommitReportAccepted is received, it's not generated after provided lastSeenTimestamp
+ destCCIP.ReportAcceptedWatcher.Range(func(_, value any) bool {
+ e, exists := value.(*evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged)
+ if exists {
+ vLogs := e.Raw
+ hdr, err := destCCIP.Common.ChainClient.HeaderByNumber(ctx, big.NewInt(int64(vLogs.BlockNumber)))
+ if err != nil {
+ return true
+ }
+ if hdr.Timestamp.After(lastSeenTimestamp) {
+ eventFoundAfterCursing = pointer.ToTime(hdr.Timestamp)
+ return false
+ }
+ }
+ return true
+ })
+ if eventFoundAfterCursing != nil {
+ return fmt.Errorf("CommitReportAccepted Event detected at %s after %s", lastSeenTimestamp, eventFoundAfterCursing.String())
+ }
+ case <-ctx.Done():
+ lggr.Info().Msgf("successfully validated that no CommitReportAccepted detected after %s for %s", lastSeenTimestamp, timeRange)
+ return nil
+ }
+ }
+}
+
+// AssertNoExecutionStateChangedEventReceived validates that no ExecutionStateChangedEvent is emitted for mentioned timeRange after lastSeenTimestamp
+func (destCCIP *DestCCIPModule) AssertNoExecutionStateChangedEventReceived(
+ lggr *zerolog.Logger,
+ timeRange time.Duration,
+ lastSeenTimestamp time.Time,
+) error {
+ ctx, cancel := context.WithTimeout(context.Background(), timeRange)
+ defer cancel()
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+ lggr.Info().Str("Wait Time", timeRange.String()).Time("Since", lastSeenTimestamp).Msg("Waiting to ensure no ExecutionStateChanged event")
+ for {
+ select {
+ case <-ticker.C:
+ var eventFoundAfterCursing *time.Time
+ // verify if ExecutionStateChanged is received, it's not generated after provided lastSeenTimestamp
+ destCCIP.ExecStateChangedWatcher.Range(func(_, value any) bool {
+ e, exists := value.(*contracts.EVM2EVMOffRampExecutionStateChanged)
+ if exists {
+ vLogs := e.LogInfo
+ hdr, err := destCCIP.Common.ChainClient.HeaderByNumber(ctx, big.NewInt(int64(vLogs.BlockNumber)))
+ if err != nil {
+ return true
+ }
+ if hdr.Timestamp.After(lastSeenTimestamp) {
+ eventFoundAfterCursing = pointer.ToTime(hdr.Timestamp)
+ return false
+ }
+ }
+ return true
+ })
+ if eventFoundAfterCursing != nil {
+ return fmt.Errorf("ExecutionStateChanged Event detected at %s after %s", lastSeenTimestamp, eventFoundAfterCursing.String())
+ }
+ case <-ctx.Done():
+ lggr.Info().Msgf("Successfully validated that no ExecutionStateChanged detected after %s for %s", lastSeenTimestamp, timeRange)
+ return nil
+ }
+ }
+}
+
+func (destCCIP *DestCCIPModule) AssertEventExecutionStateChanged(
+ lggr *zerolog.Logger,
+ seqNum uint64,
+ timeout time.Duration,
+ timeNow time.Time,
+ reqStat *testreporters.RequestStat,
+ execState testhelpers.MessageExecutionState,
+) (uint8, error) {
+ lggr.Info().Int64("seqNum", int64(seqNum)).Str("Timeout", timeout.String()).Msg("Waiting for ExecutionStateChanged event")
+ timer := time.NewTimer(timeout)
+ defer timer.Stop()
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+ resetTimer := 0
+ for {
+ select {
+ case <-ticker.C:
+ value, ok := destCCIP.ExecStateChangedWatcher.Load(seqNum)
+ if ok && value != nil {
+ e, exists := value.(*contracts.EVM2EVMOffRampExecutionStateChanged)
+ // find the type of the value
+ if exists {
+ // if the value is processed, delete it from the map
+ destCCIP.ExecStateChangedWatcher.Delete(seqNum)
+ vLogs := e.LogInfo
+ receivedAt := time.Now().UTC()
+ hdr, err := destCCIP.Common.ChainClient.HeaderByNumber(context.Background(), big.NewInt(int64(vLogs.BlockNumber)))
+ if err == nil {
+ receivedAt = hdr.Timestamp
+ }
+ receipt, err := destCCIP.Common.ChainClient.GetTxReceipt(vLogs.TxHash)
+ if err != nil {
+ lggr.Warn().Msg("Failed to get receipt for ExecStateChanged event")
+ }
+ var gasUsed uint64
+ if receipt != nil {
+ gasUsed = receipt.GasUsed
+ }
+ if testhelpers.MessageExecutionState(e.State) == execState {
+ lggr.Info().Int64("seqNum", int64(seqNum)).Uint8("ExecutionState", e.State).Msg("ExecutionStateChanged event received")
+ reqStat.UpdateState(lggr, seqNum, testreporters.ExecStateChanged, receivedAt.Sub(timeNow),
+ testreporters.Success,
+ &testreporters.TransactionStats{
+ TxHash: vLogs.TxHash.Hex(),
+ MsgID: fmt.Sprintf("0x%x", e.MessageId[:]),
+ GasUsed: gasUsed,
+ },
+ )
+ return e.State, nil
+ }
+ reqStat.UpdateState(lggr, seqNum, testreporters.ExecStateChanged, time.Since(timeNow), testreporters.Failure, nil)
+ return e.State, fmt.Errorf("ExecutionStateChanged event state - expected %d actual - %d with data %x for seq num %v for lane %d-->%d",
+ execState, testhelpers.MessageExecutionState(e.State), e.ReturnData, seqNum, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ }
+ case <-timer.C:
+ // if there is connection issue reset the context :
+ if destCCIP.Common.IsConnectionRestoredRecently != nil && !destCCIP.Common.IsConnectionRestoredRecently.Load() {
+ // if timer already has been reset 2 times we fail with warning
+ if resetTimer > 2 {
+ reqStat.UpdateState(lggr, seqNum, testreporters.ExecStateChanged, time.Since(timeNow), testreporters.Failure, nil)
+ return 0, fmt.Errorf("possible RPC issues - ExecutionStateChanged event not found for seq num %d for lane %d-->%d",
+ seqNum, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ timer.Reset(timeout)
+ resetTimer++
+ lggr.Info().Int("count of reset", resetTimer).Msg("Resetting timer to validate ExecutionStateChanged event")
+ continue
+ }
+ reqStat.UpdateState(lggr, seqNum, testreporters.ExecStateChanged, time.Since(timeNow), testreporters.Failure, nil)
+ return 0, fmt.Errorf("ExecutionStateChanged event not found for seq num %d for lane %d-->%d",
+ seqNum, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ }
+}
+
+func (destCCIP *DestCCIPModule) AssertEventReportAccepted(
+ lggr *zerolog.Logger,
+ seqNum uint64,
+ timeout time.Duration,
+ prevEventAt time.Time,
+ reqStat *testreporters.RequestStat,
+) (*contracts.CommitStoreReportAccepted, time.Time, error) {
+ lggr.Info().Int64("seqNum", int64(seqNum)).Str("Timeout", timeout.String()).Msg("Waiting for ReportAccepted event")
+ timer := time.NewTimer(timeout)
+ defer timer.Stop()
+ resetTimerCount := 0
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ticker.C:
+ value, ok := destCCIP.ReportAcceptedWatcher.Load(seqNum)
+ if ok && value != nil {
+ reportAccepted, exists := value.(*contracts.CommitStoreReportAccepted)
+ if exists {
+ // if the value is processed, delete it from the map
+ destCCIP.ReportAcceptedWatcher.Delete(seqNum)
+ receivedAt := time.Now().UTC()
+ hdr, err := destCCIP.Common.ChainClient.HeaderByNumber(context.Background(), big.NewInt(int64(reportAccepted.LogInfo.BlockNumber)))
+ if err == nil {
+ receivedAt = hdr.Timestamp
+ }
+
+ totalTime := receivedAt.Sub(prevEventAt)
+ // we cannot calculate the exact time at which block was finalized
+ // as a result sometimes we get a time which is slightly after the block was marked as finalized
+ // in such cases we get a negative time difference between finalized and report accepted if the commit
+ // has happened almost immediately after block being finalized
+ // in such cases we set the time difference to 1 second
+ if totalTime < 0 {
+ lggr.Warn().
+ Uint64("seqNum", seqNum).
+ Time("finalized at", prevEventAt).
+ Time("ReportAccepted at", receivedAt).
+ Msg("ReportAccepted event received before finalized timestamp")
+ totalTime = time.Second
+ }
+ receipt, err := destCCIP.Common.ChainClient.GetTxReceipt(reportAccepted.LogInfo.TxHash)
+ if err != nil {
+ lggr.Warn().Msg("Failed to get receipt for ReportAccepted event")
+ }
+ var gasUsed uint64
+ if receipt != nil {
+ gasUsed = receipt.GasUsed
+ }
+ reqStat.UpdateState(lggr, seqNum, testreporters.Commit, totalTime, testreporters.Success,
+ &testreporters.TransactionStats{
+ GasUsed: gasUsed,
+ TxHash: reportAccepted.LogInfo.TxHash.Hex(),
+ CommitRoot: fmt.Sprintf("%x", reportAccepted.MerkleRoot),
+ })
+ return reportAccepted, receivedAt, nil
+ }
+ }
+ case <-timer.C:
+ // if there is connection issue reset the context :
+ if destCCIP.Common.IsConnectionRestoredRecently != nil && !destCCIP.Common.IsConnectionRestoredRecently.Load() {
+ if resetTimerCount > 2 {
+ reqStat.UpdateState(lggr, seqNum, testreporters.Commit, time.Since(prevEventAt), testreporters.Failure, nil)
+ return nil, time.Now().UTC(), fmt.Errorf("possible RPC issue - ReportAccepted is not found for seq num %d lane %d-->%d",
+ seqNum, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ timer.Reset(timeout)
+ resetTimerCount++
+ lggr.Info().Int("count of reset", resetTimerCount).Msg("Resetting timer to validate ReportAccepted event")
+ continue
+ }
+ reqStat.UpdateState(lggr, seqNum, testreporters.Commit, time.Since(prevEventAt), testreporters.Failure, nil)
+ return nil, time.Now().UTC(), fmt.Errorf("ReportAccepted is not found for seq num %d lane %d-->%d",
+ seqNum, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ }
+}
+
+func (destCCIP *DestCCIPModule) AssertReportBlessed(
+ lggr *zerolog.Logger,
+ seqNum uint64,
+ timeout time.Duration,
+ CommitReport contracts.CommitStoreReportAccepted,
+ prevEventAt time.Time,
+ reqStat *testreporters.RequestStat,
+) (time.Time, error) {
+ if destCCIP.Common.ARM == nil {
+ lggr.Info().
+ Uint64("commit store interval Min", CommitReport.Min).
+ Uint64("commit store interval Max", CommitReport.Max).
+ Hex("Root", CommitReport.MerkleRoot[:]).
+ Msg("Skipping ReportBlessed check for mock ARM")
+ return prevEventAt, nil
+ }
+ lggr.Info().
+ Str("Timeout", timeout.String()).
+ Uint64("commit store interval Min", CommitReport.Min).
+ Uint64("commit store interval Max", CommitReport.Max).
+ Msg("Waiting for Report To be blessed")
+ timer := time.NewTimer(timeout)
+ defer timer.Stop()
+ resetTimerCount := 0
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ticker.C:
+ var value any
+ var foundAsRoot, ok bool
+ value, foundAsRoot = destCCIP.ReportBlessedWatcher.Load(CommitReport.MerkleRoot)
+ receivedAt := time.Now().UTC()
+ ok = foundAsRoot
+ if !foundAsRoot {
+ // if the value is not found as root, check if it is found as sequence number
+ value, ok = destCCIP.ReportBlessedBySeqNum.Load(seqNum)
+ }
+ if ok && value != nil {
+ vLogs, exists := value.(*contracts.LogInfo)
+ if exists {
+ // if the root is found, set the value for all the sequence numbers in the interval and delete the root from the map
+ if foundAsRoot {
+ // set the value for all the sequence numbers in the interval
+ for i := CommitReport.Min; i <= CommitReport.Max; i++ {
+ destCCIP.ReportBlessedBySeqNum.Store(i, vLogs)
+ }
+ // if the value is processed, delete it from the map
+ destCCIP.ReportBlessedWatcher.Delete(CommitReport.MerkleRoot)
+ } else {
+ // if the value is processed, delete it from the map
+ destCCIP.ReportBlessedBySeqNum.Delete(seqNum)
+ }
+ hdr, err := destCCIP.Common.ChainClient.HeaderByNumber(context.Background(), big.NewInt(int64(vLogs.BlockNumber)))
+ if err == nil {
+ receivedAt = hdr.Timestamp
+ }
+ receipt, err := destCCIP.Common.ChainClient.GetTxReceipt(vLogs.TxHash)
+ if err != nil {
+ lggr.Warn().Err(err).Msg("Failed to get receipt for ReportBlessed event")
+ }
+ var gasUsed uint64
+ if receipt != nil {
+ gasUsed = receipt.GasUsed
+ }
+ reqStat.UpdateState(lggr, seqNum, testreporters.ReportBlessed, receivedAt.Sub(prevEventAt), testreporters.Success,
+ &testreporters.TransactionStats{
+ GasUsed: gasUsed,
+ TxHash: vLogs.TxHash.String(),
+ CommitRoot: fmt.Sprintf("%x", CommitReport.MerkleRoot),
+ })
+ return receivedAt, nil
+ }
+ }
+ case <-timer.C:
+ // if there is connection issue reset the context :
+ if destCCIP.Common.IsConnectionRestoredRecently != nil && !destCCIP.Common.IsConnectionRestoredRecently.Load() {
+ if resetTimerCount > 2 {
+ reqStat.UpdateState(lggr, seqNum, testreporters.ReportBlessed, time.Since(prevEventAt), testreporters.Failure, nil)
+ return time.Now().UTC(), fmt.Errorf("possible RPC issue - ReportBlessed is not found for interval min - %d max - %d lane %d-->%d",
+ CommitReport.Min, CommitReport.Max, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ timer.Reset(timeout)
+ resetTimerCount++
+ lggr.Info().Int("count of reset", resetTimerCount).Msg("Resetting timer to validate ReportBlessed event")
+ continue
+ }
+ reqStat.UpdateState(lggr, seqNum, testreporters.ReportBlessed, time.Since(prevEventAt), testreporters.Failure, nil)
+ return time.Now().UTC(), fmt.Errorf("ReportBlessed is not found for interval min - %d max - %d lane %d-->%d",
+ CommitReport.Min, CommitReport.Max, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ }
+}
+
+func (destCCIP *DestCCIPModule) AssertSeqNumberExecuted(
+ lggr *zerolog.Logger,
+ seqNumberBefore uint64,
+ timeout time.Duration,
+ timeNow time.Time,
+ reqStat *testreporters.RequestStat,
+) error {
+ lggr.Info().Int64("seqNum", int64(seqNumberBefore)).Str("Timeout", timeout.String()).Msg("Waiting to be processed by commit store")
+ timer := time.NewTimer(timeout)
+ defer timer.Stop()
+ resetTimerCount := 0
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ticker.C:
+ if destCCIP.NextSeqNumToCommit.Load() > seqNumberBefore {
+ return nil
+ }
+ seqNumberAfter, err := destCCIP.CommitStore.Instance.GetExpectedNextSequenceNumber(nil)
+ if err != nil {
+ // if we get error instead of returning error we continue, in case it's a temporary RPC failure .
+ continue
+ }
+ if seqNumberAfter > seqNumberBefore {
+ destCCIP.NextSeqNumToCommit.Store(seqNumberAfter)
+ return nil
+ }
+ case <-timer.C:
+ // if there is connection issue reset the context :
+ if destCCIP.Common.IsConnectionRestoredRecently != nil && !destCCIP.Common.IsConnectionRestoredRecently.Load() {
+ if resetTimerCount > 2 {
+ reqStat.UpdateState(lggr, seqNumberBefore, testreporters.Commit, time.Since(timeNow), testreporters.Failure, nil)
+ return fmt.Errorf("possible RPC issue - sequence number is not increased for seq num %d lane %d-->%d",
+ seqNumberBefore, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ timer.Reset(timeout)
+ resetTimerCount++
+ lggr.Info().Int("count of reset", resetTimerCount).Msg("Resetting timer to validate seqnumber increase in commit store")
+ continue
+ }
+ reqStat.UpdateState(lggr, seqNumberBefore, testreporters.Commit, time.Since(timeNow), testreporters.Failure, nil)
+ return fmt.Errorf("sequence number is not increased for seq num %d lane %d-->%d",
+ seqNumberBefore, destCCIP.SourceChainId, destCCIP.Common.ChainClient.GetChainID())
+ }
+ }
+}
+
+func DefaultDestinationCCIPModule(
+ logger *zerolog.Logger,
+ testConf *testconfig.CCIPTestGroupConfig,
+ chainClient blockchain.EVMClient,
+ sourceChainId uint64,
+ sourceChain string,
+ laneConf *laneconfig.LaneConfig,
+) (*DestCCIPModule, error) {
+ cmn, err := NewCCIPCommonFromConfig(
+ logger, testConf, chainClient, laneConf,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ sourceChainSelector, err := chainselectors.SelectorFromChainId(sourceChainId)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get chain selector for source chain id %d: %w", sourceChainId, err)
+ }
+ return &DestCCIPModule{
+ Common: cmn,
+ SourceChainId: sourceChainId,
+ SourceChainSelector: sourceChainSelector,
+ SourceNetworkName: sourceChain,
+ NextSeqNumToCommit: atomic.NewUint64(1),
+ ReportBlessedWatcher: &sync.Map{},
+ ReportBlessedBySeqNum: &sync.Map{},
+ ExecStateChangedWatcher: &sync.Map{},
+ ReportAcceptedWatcher: &sync.Map{},
+ }, nil
+}
+
+type CCIPRequest struct {
+ ReqNo int64
+ txHash string
+ txConfirmationTimestamp time.Time
+ RequestStat *testreporters.RequestStat
+}
+
+func CCIPRequestFromTxHash(txHash common.Hash, chainClient blockchain.EVMClient) (CCIPRequest, *types.Receipt, error) {
+ rcpt, err := chainClient.GetTxReceipt(txHash)
+ if err != nil {
+ return CCIPRequest{}, nil, err
+ }
+
+ hdr, err := chainClient.HeaderByNumber(context.Background(), rcpt.BlockNumber)
+ if err != nil {
+ return CCIPRequest{}, nil, err
+ }
+ txConfirmationTimestamp := hdr.Timestamp
+
+ return CCIPRequest{
+ txHash: txHash.Hex(),
+ txConfirmationTimestamp: txConfirmationTimestamp,
+ }, rcpt, nil
+}
+
+type CCIPLane struct {
+ Test *testing.T
+ Logger *zerolog.Logger
+ SourceNetworkName string
+ DestNetworkName string
+ SourceChain blockchain.EVMClient
+ DestChain blockchain.EVMClient
+ Source *SourceCCIPModule
+ Dest *DestCCIPModule
+ NumberOfReq int
+ Reports *testreporters.CCIPLaneStats
+ Balance *BalanceSheet
+ SentReqs map[common.Hash][]CCIPRequest
+ TotalFee *big.Int // total fee for all the requests. Used for balance validation.
+ ValidationTimeout time.Duration
+ Context context.Context
+ SrcNetworkLaneCfg *laneconfig.LaneConfig
+ DstNetworkLaneCfg *laneconfig.LaneConfig
+ PriceReportingDisabled bool
+}
+
+func (lane *CCIPLane) TokenPricesConfig() (string, error) {
+ d := &DynamicPriceGetterConfig{
+ AggregatorPrices: make(map[common.Address]AggregatorPriceConfig),
+ StaticPrices: make(map[common.Address]StaticPriceConfig),
+ }
+ // for each token if there is a price aggregator, add it to the aggregator prices
+ // else add it to the static prices
+ for _, token := range lane.Dest.Common.BridgeTokens {
+ err := d.AddPriceConfig(token.Address(), lane.Dest.Common.PriceAggregators, LinkToUSD, lane.DestChain.GetChainID().Uint64())
+ if err != nil {
+ return "", fmt.Errorf("error in adding PriceConfig for source bridge token %s: %w", token.Address(), err)
+ }
+ }
+ err := d.AddPriceConfig(lane.Dest.Common.FeeToken.Address(), lane.Dest.Common.PriceAggregators, LinkToUSD, lane.DestChain.GetChainID().Uint64())
+ if err != nil {
+ return "", fmt.Errorf("error adding PriceConfig for dest Fee token %s: %w", lane.Dest.Common.FeeToken.Address(), err)
+ }
+ err = d.AddPriceConfig(lane.Dest.Common.WrappedNative.Hex(), lane.Dest.Common.PriceAggregators, WrappedNativeToUSD, lane.DestChain.GetChainID().Uint64())
+ if err != nil {
+ return "", fmt.Errorf("error in adding PriceConfig for dest WrappedNative token %s: %w", lane.Dest.Common.WrappedNative.Hex(), err)
+ }
+ err = d.AddPriceConfig(lane.Source.Common.WrappedNative.Hex(), lane.Source.Common.PriceAggregators, WrappedNativeToUSD, lane.SourceChain.GetChainID().Uint64())
+ if err != nil {
+ return "", fmt.Errorf("error in adding PriceConfig for source WrappedNative token %s: %w", lane.Source.Common.WrappedNative.Hex(), err)
+ }
+ return d.String()
+}
+
+func (lane *CCIPLane) SetRemoteChainsOnPool() error {
+ if lane.Source.Common.ExistingDeployment {
+ return nil
+ }
+ if len(lane.Source.Common.BridgeTokenPools) != len(lane.Dest.Common.BridgeTokenPools) {
+ return fmt.Errorf("source (%d) and dest (%d) bridge token pools length should be same",
+ len(lane.Source.Common.BridgeTokenPools), len(lane.Dest.Common.BridgeTokenPools),
+ )
+ }
+ for i, srcPool := range lane.Source.Common.BridgeTokenPools {
+ sourceToken := lane.Source.Common.BridgeTokens[i]
+ destToken := lane.Dest.Common.BridgeTokens[i]
+ dstPool := lane.Dest.Common.BridgeTokenPools[i]
+
+ err := srcPool.SetRemoteChainOnPool(lane.Source.DestChainSelector, dstPool.EthAddress, destToken.ContractAddress)
+ if err != nil {
+ return err
+ }
+ err = dstPool.SetRemoteChainOnPool(lane.Dest.SourceChainSelector, srcPool.EthAddress, sourceToken.ContractAddress)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// OptimizeStorage sets nil to various elements of CCIPLane which are only used
+// during lane set up and not used for rest of the test duration
+// this is called mainly by load test to keep the memory usage minimum for high number of lanes
+func (lane *CCIPLane) OptimizeStorage() {
+ lane.Source.Common.FreeUpUnusedSpace()
+ lane.Dest.Common.FreeUpUnusedSpace()
+ lane.DstNetworkLaneCfg = nil
+ lane.SrcNetworkLaneCfg = nil
+ // close all header subscriptions for dest chains
+ queuedEvents := lane.Dest.Common.ChainClient.GetHeaderSubscriptions()
+ for subName := range queuedEvents {
+ lane.Dest.Common.ChainClient.DeleteHeaderEventSubscription(subName)
+ }
+ // close all header subscriptions for source chains except for finalized header
+ queuedEvents = lane.Source.Common.ChainClient.GetHeaderSubscriptions()
+ for subName := range queuedEvents {
+ if subName == blockchain.FinalizedHeaderKey {
+ continue
+ }
+ lane.Source.Common.ChainClient.DeleteHeaderEventSubscription(subName)
+ }
+}
+
+func (lane *CCIPLane) UpdateLaneConfig() {
+ lane.Source.Common.WriteLaneConfig(lane.SrcNetworkLaneCfg)
+ lane.SrcNetworkLaneCfg.SrcContractsMu.Lock()
+ lane.SrcNetworkLaneCfg.SrcContracts[lane.Source.DestNetworkName] = laneconfig.SourceContracts{
+ OnRamp: lane.Source.OnRamp.Address(),
+ DeployedAt: lane.Source.SrcStartBlock,
+ }
+ lane.SrcNetworkLaneCfg.SrcContractsMu.Unlock()
+ lane.Dest.Common.WriteLaneConfig(lane.DstNetworkLaneCfg)
+ lane.DstNetworkLaneCfg.DestContractsMu.Lock()
+ lane.DstNetworkLaneCfg.DestContracts[lane.Dest.SourceNetworkName] = laneconfig.DestContracts{
+ OffRamp: lane.Dest.OffRamp.Address(),
+ CommitStore: lane.Dest.CommitStore.Address(),
+ ReceiverDapp: lane.Dest.ReceiverDapp.Address(),
+ }
+ lane.DstNetworkLaneCfg.DestContractsMu.Unlock()
+}
+
+func (lane *CCIPLane) RecordStateBeforeTransfer() {
+ // collect the balance assert.ment to verify balances after transfer
+ bal, err := testhelpers.GetBalances(lane.Test, lane.Source.CollectBalanceRequirements())
+ require.NoError(lane.Test, err, "fetching source balance")
+ lane.Balance.RecordBalance(bal)
+
+ bal, err = testhelpers.GetBalances(lane.Test, lane.Dest.CollectBalanceRequirements())
+ require.NoError(lane.Test, err, "fetching dest balance")
+ lane.Balance.RecordBalance(bal)
+
+ // save the current block numbers to use in various filter log requests
+ lane.TotalFee = big.NewInt(0)
+ lane.NumberOfReq = 0
+ lane.SentReqs = make(map[common.Hash][]CCIPRequest)
+}
+
+func (lane *CCIPLane) AddToSentReqs(txHash common.Hash, reqStats []*testreporters.RequestStat) (*types.Receipt, error) {
+ request, rcpt, err := CCIPRequestFromTxHash(txHash, lane.Source.Common.ChainClient)
+ if err != nil {
+ for _, stat := range reqStats {
+ stat.UpdateState(lane.Logger, 0, testreporters.TX, 0, testreporters.Failure, nil)
+ }
+ return rcpt, fmt.Errorf("could not get request from tx hash %s: %w", txHash.Hex(), err)
+ }
+ var allRequests []CCIPRequest
+ for _, stat := range reqStats {
+ allRequests = append(allRequests, CCIPRequest{
+ ReqNo: stat.ReqNo,
+ txHash: rcpt.TxHash.Hex(),
+ txConfirmationTimestamp: request.txConfirmationTimestamp,
+ RequestStat: stat,
+ })
+ lane.NumberOfReq++
+ }
+ lane.SentReqs[rcpt.TxHash] = allRequests
+ return rcpt, nil
+}
+
+// Multicall sends multiple ccip-send requests in a single transaction
+// It will create one transaction for all the requests and will wait for the confirmation
+func (lane *CCIPLane) Multicall(noOfRequests int, multiSendAddr common.Address) error {
+ var ccipMultipleMsg []contracts.CCIPMsgData
+ feeToken := common.HexToAddress(lane.Source.Common.FeeToken.Address())
+ genericMsg, err := lane.Source.CCIPMsg(lane.Dest.ReceiverDapp.EthAddress, big.NewInt(DefaultDestinationGasLimit))
+ if err != nil {
+ return fmt.Errorf("failed to form the ccip message: %w", err)
+ }
+ destChainSelector, err := chainselectors.SelectorFromChainId(lane.Source.DestinationChainId)
+ if err != nil {
+ return fmt.Errorf("failed getting the chain selector: %w", err)
+ }
+ var reqStats []*testreporters.RequestStat
+ var txstats []*testreporters.TransactionStats
+ for i := 1; i <= noOfRequests; i++ {
+ // form the message for transfer
+ msg := genericMsg
+ msg.Data = []byte(fmt.Sprintf("msg %d", i))
+ sendData := contracts.CCIPMsgData{
+ Msg: msg,
+ RouterAddr: lane.Source.Common.Router.EthAddress,
+ ChainSelector: destChainSelector,
+ }
+
+ fee, err := lane.Source.Common.Router.GetFee(destChainSelector, msg)
+ if err != nil {
+ reason, _ := blockchain.RPCErrorFromError(err)
+ if reason != "" {
+ return fmt.Errorf("failed getting the fee: %s", reason)
+ }
+ return fmt.Errorf("failed getting the fee: %w", err)
+ }
+ log.Info().Str("fee", fee.String()).Msg("calculated fee")
+ sendData.Fee = fee
+ lane.TotalFee = new(big.Int).Add(lane.TotalFee, fee)
+ ccipMultipleMsg = append(ccipMultipleMsg, sendData)
+ // if token transfer is required, transfer the token amount to multisend
+ for j, amount := range lane.Source.TransferAmount {
+ // if length of sourceCCIP.TransferAmount is more than available bridge token use first bridge token
+ token := lane.Source.Common.BridgeTokens[0]
+ if j < len(lane.Source.Common.BridgeTokens) {
+ token = lane.Source.Common.BridgeTokens[j]
+ }
+ err = token.Transfer(lane.SourceChain.GetDefaultWallet(), multiSendAddr.Hex(), amount)
+ if err != nil {
+ return err
+ }
+ }
+ stat := testreporters.NewCCIPRequestStats(int64(lane.NumberOfReq+i), lane.SourceNetworkName, lane.DestNetworkName)
+ txstats = append(txstats, &testreporters.TransactionStats{
+ Fee: fee.String(),
+ NoOfTokensSent: len(msg.TokenAmounts),
+ MessageBytesLength: int64(len(msg.Data)),
+ })
+ reqStats = append(reqStats, stat)
+ }
+ isNative := true
+ // transfer the fee amount to multisend
+ if feeToken != (common.Address{}) {
+ isNative = false
+ err = lane.Source.Common.FeeToken.Transfer(multiSendAddr.Hex(), lane.TotalFee)
+ if err != nil {
+ return err
+ }
+ }
+
+ tx, err := contracts.MultiCallCCIP(lane.Source.Common.ChainClient, multiSendAddr.Hex(), ccipMultipleMsg, isNative)
+ if err != nil {
+ // update the stats as failure for all the requests in the multicall tx
+ for _, stat := range reqStats {
+ stat.UpdateState(lane.Logger, 0, testreporters.TX, 0, testreporters.Failure, nil)
+ }
+ return fmt.Errorf("failed to send the multicall: %w", err)
+ }
+ rcpt, err := lane.AddToSentReqs(tx.Hash(), reqStats)
+ if err != nil {
+ return err
+ }
+ var gasUsed uint64
+ if rcpt != nil {
+ gasUsed = rcpt.GasUsed
+ }
+ // update the stats for all the requests in the multicall tx
+ for i, stat := range reqStats {
+ txstats[i].GasUsed = gasUsed
+ txstats[i].TxHash = tx.Hash().Hex()
+ stat.UpdateState(lane.Logger, 0, testreporters.TX, 0, testreporters.Success, txstats[i])
+ }
+ return nil
+}
+
+// SendRequests sends individual ccip-send requests in different transactions
+// It will create noOfRequests transactions
+func (lane *CCIPLane) SendRequests(noOfRequests int, gasLimit *big.Int) error {
+ for i := 1; i <= noOfRequests; i++ {
+ stat := testreporters.NewCCIPRequestStats(int64(lane.NumberOfReq+i), lane.SourceNetworkName, lane.DestNetworkName)
+ txHash, txConfirmationDur, fee, err := lane.Source.SendRequest(
+ lane.Dest.ReceiverDapp.EthAddress,
+ gasLimit,
+ )
+ if err != nil {
+ stat.UpdateState(lane.Logger, 0, testreporters.TX, txConfirmationDur, testreporters.Failure, nil)
+ return fmt.Errorf("could not send request: %w", err)
+ }
+ err = lane.Source.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ stat.UpdateState(lane.Logger, 0, testreporters.TX, txConfirmationDur, testreporters.Failure, nil)
+ return fmt.Errorf("could not send request: %w", err)
+ }
+
+ noOfTokens := 0
+ for _, tokenAmount := range lane.Source.TransferAmount { // Only count tokens that are actually sent
+ if tokenAmount != nil && tokenAmount.Cmp(big.NewInt(0)) > 0 {
+ noOfTokens++
+ }
+ }
+ _, err = lane.AddToSentReqs(txHash, []*testreporters.RequestStat{stat})
+ if err != nil {
+ return err
+ }
+ stat.UpdateState(lane.Logger, 0, testreporters.TX, txConfirmationDur, testreporters.Success, nil)
+ lane.TotalFee = bigmath.Add(lane.TotalFee, fee)
+ }
+
+ return nil
+}
+
+// manualExecutionOpts modify how ExecuteManually behaves
+type manualExecutionOpts struct {
+ timeout time.Duration
+}
+
+// ManualExecutionOption is a function that modifies ExecuteManually behavior
+type ManualExecutionOption func(*manualExecutionOpts)
+
+// WithConfirmationTimeout sets a custom timeout for waiting for the confirmation of the manual execution
+func WithConfirmationTimeout(timeout time.Duration) ManualExecutionOption {
+ return func(opts *manualExecutionOpts) {
+ opts.timeout = timeout
+ }
+}
+
+// ExecuteManually attempts to execute pending CCIP transactions manually.
+// This is necessary in situations where Smart Execution window for that message is over and Offchain plugin
+// will not attempt to execute the message.In such situation any further message from same sender will not be executed until
+// the blocking message is executed by the OffRamp.
+// More info: https://docs.chain.link/ccip/concepts/manual-execution#manual-execution
+func (lane *CCIPLane) ExecuteManually(options ...ManualExecutionOption) error {
+ var opts manualExecutionOpts
+ for _, opt := range options {
+ if opt != nil {
+ opt(&opts)
+ }
+ }
+ if opts.timeout == 0 {
+ opts.timeout = lane.ValidationTimeout
+ }
+
+ onRampABI, err := abi.JSON(strings.NewReader(evm_2_evm_onramp.EVM2EVMOnRampABI))
+ if err != nil {
+ return err
+ }
+ sendReqTopic := onRampABI.Events["CCIPSendRequested"].ID
+ for txHash, req := range lane.SentReqs {
+ for _, ccipReq := range req {
+ lane.Logger.Info().Str("ccip-send", txHash.Hex()).Msg("Executing request manually")
+ seqNum := ccipReq.RequestStat.SeqNum
+ sendReqReceipt, err := lane.Source.Common.ChainClient.GetTxReceipt(txHash)
+ if err != nil {
+ return err
+ }
+ if sendReqReceipt == nil {
+ return fmt.Errorf("could not find the receipt for tx %s", txHash.Hex())
+ }
+ commitStat, ok := ccipReq.RequestStat.StatusByPhase[testreporters.Commit]
+ if !ok {
+ return fmt.Errorf("could not find the commit phase in the request stats, reqNo %d", ccipReq.RequestStat.ReqNo)
+ }
+ commitTx := commitStat.SendTransactionStats.TxHash
+ commitReceipt, err := lane.DestChain.GetTxReceipt(common.HexToHash(commitTx))
+ if err != nil {
+ return err
+ }
+ var logIndex uint
+ // find the send request log index sendReqReceipt
+ for _, sendReqLog := range sendReqReceipt.Logs {
+ if sendReqLog.Topics[0] == sendReqTopic {
+ logSeqNum, err := lane.Source.OnRamp.Instance.ParseCCIPSendRequested(*sendReqLog)
+ if err != nil {
+ return err
+ }
+ if logSeqNum == seqNum {
+ logIndex = sendReqLog.Index
+ }
+ }
+ }
+ destChainSelector, err := chainselectors.SelectorFromChainId(lane.DestChain.GetChainID().Uint64())
+ if err != nil {
+ return err
+ }
+ sourceChainSelector, err := chainselectors.SelectorFromChainId(lane.SourceChain.GetChainID().Uint64())
+ if err != nil {
+ return err
+ }
+ // Calling `TransactionOpts` will automatically increase the nonce, so if this fails, any other destination transactions will time out
+ destUser, err := lane.DestChain.TransactionOpts(lane.DestChain.GetDefaultWallet())
+ if err != nil {
+ return err
+ }
+ args := testhelpers.ManualExecArgs{
+ SourceChainID: sourceChainSelector,
+ DestChainID: destChainSelector,
+ DestUser: destUser,
+ SourceChain: lane.SourceChain.Backend(),
+ DestChain: lane.DestChain.Backend(),
+ SourceStartBlock: sendReqReceipt.BlockNumber,
+ DestStartBlock: commitReceipt.BlockNumber.Uint64(),
+ SendReqTxHash: txHash.Hex(),
+ CommitStore: lane.Dest.CommitStore.Address(),
+ OnRamp: lane.Source.OnRamp.Address(),
+ OffRamp: lane.Dest.OffRamp.Address(),
+ SendReqLogIndex: logIndex,
+ GasLimit: big.NewInt(DefaultDestinationGasLimit),
+ }
+ timeNow := time.Now().UTC()
+ tx, err := args.ExecuteManually()
+ if err != nil {
+ return fmt.Errorf("could not execute manually: %w seqNum %d", err, seqNum)
+ }
+
+ ctx, cancel := context.WithTimeout(context.Background(), opts.timeout)
+ rec, err := bind.WaitMined(ctx, lane.DestChain.DeployBackend(), tx)
+ if err != nil {
+ cancel()
+ return fmt.Errorf("could not get receipt: %w seqNum %d", err, seqNum)
+ }
+ cancel()
+ if rec.Status != 1 {
+ return fmt.Errorf(
+ "manual execution failed for seqNum %d with receipt status %d, use the revert-reason script on this transaction hash '%s' and this sender address '%s'",
+ seqNum, rec.Status, tx.Hash().Hex(), destUser.From.Hex(),
+ )
+ }
+ lane.Logger.Info().Uint64("seqNum", seqNum).Msg("Manual Execution completed")
+ _, err = lane.Dest.AssertEventExecutionStateChanged(lane.Logger, seqNum, opts.timeout,
+ timeNow, ccipReq.RequestStat, testhelpers.ExecutionStateSuccess,
+ )
+ if err != nil {
+ return fmt.Errorf("could not validate ExecutionStateChanged event: %w", err)
+ }
+ }
+ }
+ return nil
+}
+
+// validationOptions are used in the ValidateRequests function to specify which phase is expected to fail and how
+type validationOptions struct {
+ phaseExpectedToFail testreporters.Phase // the phase expected to fail
+ expectedErrorMessage string // if provided, we're looking for a specific error message
+ timeout time.Duration // timeout for the validation
+}
+
+// ValidationOptionFunc is a function that can be passed to ValidateRequests to specify which phase is expected to fail
+type ValidationOptionFunc func(opts *validationOptions)
+
+// PhaseSpecificValidationOptionFunc can specify how exactly you want a phase to fail
+type PhaseSpecificValidationOptionFunc func(*validationOptions)
+
+// WithErrorMessage specifies the expected error message for the phase that is expected to fail.
+func WithErrorMessage(expectedErrorMessage string) PhaseSpecificValidationOptionFunc {
+ return func(opts *validationOptions) {
+ opts.expectedErrorMessage = expectedErrorMessage
+ }
+}
+
+// WithTimeout specifies a custom timeout for validating that the phase failed.
+func WithTimeout(timeout time.Duration) PhaseSpecificValidationOptionFunc {
+ return func(opts *validationOptions) {
+ opts.timeout = timeout
+ }
+}
+
+// ExpectPhaseToFail specifies that a specific phase is expected to fail.
+// You can optionally provide an expected error message, if you don't have one in mind, just pass an empty string.
+// shouldExist is used to specify whether the phase should exist or not, which is only applicable to the `ExecStateChanged` phase.
+// If you expect the `ExecStateChanged` events to be there, but in a "failed" state, set this to true.
+// It will otherwise be ignored.
+func ExpectPhaseToFail(phase testreporters.Phase, phaseSpecificOptions ...PhaseSpecificValidationOptionFunc) ValidationOptionFunc {
+ return func(opts *validationOptions) {
+ opts.phaseExpectedToFail = phase
+ for _, f := range phaseSpecificOptions {
+ if f != nil {
+ f(opts)
+ }
+ }
+ }
+}
+
+// ValidateRequests validates all sent request events.
+// If you expect a specific phase to fail, you can pass a validationOptionFunc to specify exactly which one.
+// If not, just pass in nil.
+func (lane *CCIPLane) ValidateRequests(validationOptionFuncs ...ValidationOptionFunc) {
+ var opts validationOptions
+ for _, f := range validationOptionFuncs {
+ if f != nil {
+ f(&opts)
+ }
+ }
+ for txHash, ccipReqs := range lane.SentReqs {
+ require.Greater(lane.Test, len(ccipReqs), 0, "no ccip requests found for tx hash")
+ require.NoError(lane.Test, lane.ValidateRequestByTxHash(txHash, opts), "validating request events by tx hash")
+ }
+ if len(validationOptionFuncs) > 0 {
+ return
+ }
+ // Asserting balances reliably work only for simulated private chains. The testnet contract balances might get updated by other transactions
+ // verify the fee amount is deducted from sender, added to receiver token balances and
+ if len(lane.Source.TransferAmount) > 0 && len(lane.Source.Common.BridgeTokens) > 0 {
+ lane.Source.UpdateBalance(int64(lane.NumberOfReq), lane.TotalFee, lane.Balance)
+ lane.Dest.UpdateBalance(lane.Source.TransferAmount, int64(lane.NumberOfReq), lane.Balance)
+ }
+}
+
+// ValidateRequestByTxHash validates the request events by tx hash.
+// If a phaseExpectedToFail is provided, it will return no error if that phase fails, but will error if it succeeds.
+func (lane *CCIPLane) ValidateRequestByTxHash(txHash common.Hash, opts validationOptions) error {
+ var (
+ reqStats []*testreporters.RequestStat
+ timeout = lane.ValidationTimeout
+ ccipRequests = lane.SentReqs[txHash]
+ txConfirmation = ccipRequests[0].txConfirmationTimestamp
+ )
+ require.Greater(lane.Test, len(ccipRequests), 0, "no ccip requests found for tx hash")
+
+ defer func() {
+ for _, req := range ccipRequests {
+ lane.Reports.UpdatePhaseStatsForReq(req.RequestStat)
+ }
+ }()
+ for _, req := range ccipRequests {
+ reqStats = append(reqStats, req.RequestStat)
+ }
+
+ if opts.phaseExpectedToFail == testreporters.CCIPSendRe && opts.timeout != 0 {
+ timeout = opts.timeout
+ }
+ msgLogs, ccipSendReqGenAt, err := lane.Source.AssertEventCCIPSendRequested(
+ lane.Logger, txHash.Hex(), timeout, txConfirmation, reqStats,
+ )
+ if shouldReturn, phaseErr := isPhaseValid(lane.Logger, testreporters.CCIPSendRe, opts, err); shouldReturn {
+ return phaseErr
+ }
+
+ sourceLogFinalizedAt, _, err := lane.Source.AssertSendRequestedLogFinalized(lane.Logger, txHash, msgLogs, ccipSendReqGenAt, reqStats)
+ if shouldReturn, phaseErr := isPhaseValid(lane.Logger, testreporters.SourceLogFinalized, opts, err); shouldReturn {
+ return phaseErr
+ }
+ for _, msgLog := range msgLogs {
+ seqNumber := msgLog.SequenceNumber
+ lane.Logger = ptr.Ptr(lane.Logger.With().Str("msgId", fmt.Sprintf("0x%x", msgLog.MessageId[:])).Logger())
+ var reqStat *testreporters.RequestStat
+ for _, stat := range reqStats {
+ if stat.SeqNum == seqNumber {
+ reqStat = stat
+ break
+ }
+ }
+ if reqStat == nil {
+ return fmt.Errorf("could not find request stat for seq number %d", seqNumber)
+ }
+
+ if opts.phaseExpectedToFail == testreporters.Commit && opts.timeout != 0 {
+ timeout = opts.timeout
+ }
+ err = lane.Dest.AssertSeqNumberExecuted(lane.Logger, seqNumber, timeout, sourceLogFinalizedAt, reqStat)
+ if shouldReturn, phaseErr := isPhaseValid(lane.Logger, testreporters.Commit, opts, err); shouldReturn {
+ return phaseErr
+ }
+
+ // Verify whether commitStore has accepted the report
+ commitReport, reportAcceptedAt, err := lane.Dest.AssertEventReportAccepted(
+ lane.Logger, seqNumber, timeout, sourceLogFinalizedAt, reqStat,
+ )
+ if shouldReturn, phaseErr := isPhaseValid(lane.Logger, testreporters.Commit, opts, err); shouldReturn {
+ return phaseErr
+ }
+
+ if opts.phaseExpectedToFail == testreporters.ReportBlessed && opts.timeout != 0 {
+ timeout = opts.timeout
+ }
+ reportBlessedAt, err := lane.Dest.AssertReportBlessed(lane.Logger, seqNumber, timeout, *commitReport, reportAcceptedAt, reqStat)
+ if shouldReturn, phaseErr := isPhaseValid(lane.Logger, testreporters.ReportBlessed, opts, err); shouldReturn {
+ return phaseErr
+ }
+
+ if opts.phaseExpectedToFail == testreporters.ExecStateChanged && opts.timeout != 0 {
+ timeout = opts.timeout
+ }
+ // Verify whether the execution state is changed and the transfer is successful
+ _, err = lane.Dest.AssertEventExecutionStateChanged(
+ lane.Logger, seqNumber,
+ timeout,
+ reportBlessedAt,
+ reqStat,
+ testhelpers.ExecutionStateSuccess,
+ )
+ if shouldReturn, phaseErr := isPhaseValid(lane.Logger, testreporters.ExecStateChanged, opts, err); shouldReturn {
+ return phaseErr
+ }
+ }
+ return nil
+}
+
+// isPhaseValid checks if the phase is in a valid state or not given expectations.
+// If `shouldComplete` is true, it means that the phase validation is meant to end and we should return from the calling function.
+func isPhaseValid(
+ logger *zerolog.Logger,
+ currentPhase testreporters.Phase,
+ opts validationOptions,
+ err error,
+) (shouldComplete bool, validationError error) {
+ // If no phase is expected to fail or the current phase is not the one expected to fail, we just return what we were given
+ if opts.phaseExpectedToFail == "" || currentPhase != opts.phaseExpectedToFail {
+ return err != nil, err
+ }
+ if err == nil && currentPhase == opts.phaseExpectedToFail {
+ return true, fmt.Errorf("expected phase '%s' to fail, but it passed", opts.phaseExpectedToFail)
+ }
+ logmsg := logger.Info().Str("Failed with Error", err.Error()).Str("Phase", string(currentPhase))
+ if opts.expectedErrorMessage != "" {
+ if !strings.Contains(err.Error(), opts.expectedErrorMessage) {
+ return true, fmt.Errorf("expected phase '%s' to fail with error message '%s' but got error '%s'", currentPhase, opts.expectedErrorMessage, err.Error())
+ }
+ logmsg.Str("Expected Error Message", opts.expectedErrorMessage)
+ }
+ logmsg.Msg("Expected phase to fail and it did")
+ return true, nil
+}
+
+// DisableAllRateLimiting disables all rate limiting for the lane, including ARL and token pool rate limits
+func (lane *CCIPLane) DisableAllRateLimiting() error {
+ src := lane.Source
+ dest := lane.Dest
+
+ // Tell OnRamp to not include any tokens in ARL
+ err := src.SetAllTokenTransferFeeConfigs(false)
+ if err != nil {
+ return fmt.Errorf("error disabling token transfer fee config for OnRamp: %w", err)
+ }
+ err = dest.RemoveAllRateLimitTokens(context.Background())
+ if err != nil {
+ return fmt.Errorf("error removing rate limited tokens for OffRamp: %w", err)
+ }
+ // Disable ARL for OnRamp and OffRamp
+ err = src.OnRamp.SetRateLimit(evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(0),
+ Rate: big.NewInt(0),
+ })
+ if err != nil {
+ return fmt.Errorf("error disabling rate limit for source onramp: %w", err)
+ }
+ err = dest.OffRamp.SetRateLimit(contracts.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(0),
+ Rate: big.NewInt(0),
+ })
+ if err != nil {
+ return fmt.Errorf("error disabling rate limit for destination offramp: %w", err)
+ }
+ // Disable individual token pool rate limits
+ for i, tokenPool := range src.Common.BridgeTokenPools {
+ err = tokenPool.SetRemoteChainRateLimits(src.DestChainSelector, token_pool.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(0),
+ Rate: big.NewInt(0),
+ })
+ if err != nil {
+ return fmt.Errorf("error disabling rate limit for token pool %d: %w", i, err)
+ }
+ }
+ for i, tokenPool := range dest.Common.BridgeTokenPools {
+ err = tokenPool.SetRemoteChainRateLimits(dest.SourceChainSelector, token_pool.RateLimiterConfig{
+ IsEnabled: false,
+ Capacity: big.NewInt(0),
+ Rate: big.NewInt(0),
+ })
+ if err != nil {
+ return fmt.Errorf("error disabling rate limit for token pool %d: %w", i, err)
+ }
+ }
+ err = src.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error waiting for source chain events: %w", err)
+ }
+ err = dest.Common.ChainClient.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error waiting for destination chain events: %w", err)
+ }
+ lane.Logger.Info().Msg("Disabled all rate limiting")
+ return nil
+}
+
+func (lane *CCIPLane) StartEventWatchers() error {
+ lane.Logger.Info().Msg("Starting event watchers")
+ if lane.Source.Common.ChainClient.GetNetworkConfig().FinalityDepth == 0 {
+ err := lane.Source.Common.ChainClient.PollFinality()
+ if err != nil {
+ return err
+ }
+ }
+
+ go lane.Source.Common.PollRPCConnection(lane.Context, lane.Logger)
+ go lane.Dest.Common.PollRPCConnection(lane.Context, lane.Logger)
+
+ sendReqEventLatest := make(chan *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested)
+ senReqSub := event.Resubscribe(DefaultResubscriptionTimeout, func(_ context.Context) (event.Subscription, error) {
+ sub, err := lane.Source.OnRamp.WatchCCIPSendRequested(nil, sendReqEventLatest)
+ if err != nil {
+ log.Error().Err(err).Msg("error in subscribing to CCIPSendRequested event")
+ }
+ return sub, err
+ })
+ if senReqSub == nil {
+ return fmt.Errorf("failed to subscribe to CCIPSendRequested event")
+ }
+ go func(sub event.Subscription) {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case e := <-sendReqEventLatest:
+ lane.Logger.Info().Msgf("CCIPSendRequested event received for seq number %d", e.Message.SequenceNumber)
+ eventsForTx, ok := lane.Source.CCIPSendRequestedWatcher.Load(e.Raw.TxHash.Hex())
+ if ok {
+ lane.Source.CCIPSendRequestedWatcher.Store(e.Raw.TxHash.Hex(), append(eventsForTx.([]*contracts.SendReqEventData),
+ &contracts.SendReqEventData{
+ MessageId: e.Message.MessageId,
+ SequenceNumber: e.Message.SequenceNumber,
+ DataLength: len(e.Message.Data),
+ NoOfTokens: len(e.Message.TokenAmounts),
+ LogInfo: contracts.LogInfo{
+ BlockNumber: e.Raw.BlockNumber,
+ TxHash: e.Raw.TxHash,
+ },
+ Fee: e.Message.FeeTokenAmount,
+ }))
+ } else {
+ lane.Source.CCIPSendRequestedWatcher.Store(e.Raw.TxHash.Hex(), []*contracts.SendReqEventData{
+ {
+ MessageId: e.Message.MessageId,
+ SequenceNumber: e.Message.SequenceNumber,
+ DataLength: len(e.Message.Data),
+ NoOfTokens: len(e.Message.TokenAmounts),
+ LogInfo: contracts.LogInfo{
+ BlockNumber: e.Raw.BlockNumber,
+ TxHash: e.Raw.TxHash,
+ },
+ Fee: e.Message.FeeTokenAmount,
+ },
+ })
+ }
+
+ lane.Source.CCIPSendRequestedWatcher = testutils.DeleteNilEntriesFromMap(lane.Source.CCIPSendRequestedWatcher)
+ case <-lane.Context.Done():
+ return
+ }
+ }
+ }(senReqSub)
+
+ reportAcceptedEvent := make(chan *commit_store.CommitStoreReportAccepted)
+ reportAccSub := event.Resubscribe(DefaultResubscriptionTimeout, func(_ context.Context) (event.Subscription, error) {
+ sub, err := lane.Dest.CommitStore.WatchReportAccepted(nil, reportAcceptedEvent)
+ if err != nil {
+ log.Error().Err(err).Msg("error in subscribing to ReportAccepted event")
+ }
+ return sub, err
+ })
+ if reportAccSub == nil {
+ return fmt.Errorf("failed to subscribe to ReportAccepted event")
+ }
+ go func(sub event.Subscription) {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case e := <-reportAcceptedEvent:
+ lane.Logger.Info().Interface("Interval", e.Report.Interval).Msgf("ReportAccepted event received")
+ for i := e.Report.Interval.Min; i <= e.Report.Interval.Max; i++ {
+ lane.Dest.ReportAcceptedWatcher.Store(i, &contracts.CommitStoreReportAccepted{
+ Min: e.Report.Interval.Min,
+ Max: e.Report.Interval.Max,
+ MerkleRoot: e.Report.MerkleRoot,
+ LogInfo: contracts.LogInfo{
+ BlockNumber: e.Raw.BlockNumber,
+ TxHash: e.Raw.TxHash,
+ },
+ })
+ }
+ lane.Dest.ReportAcceptedWatcher = testutils.DeleteNilEntriesFromMap(lane.Dest.ReportAcceptedWatcher)
+ case <-lane.Context.Done():
+ return
+ }
+ }
+ }(reportAccSub)
+
+ if lane.Dest.Common.ARM != nil {
+ reportBlessedEvent := make(chan *arm_contract.ARMContractTaggedRootBlessed)
+ blessedSub := event.Resubscribe(DefaultResubscriptionTimeout, func(_ context.Context) (event.Subscription, error) {
+ sub, err := lane.Dest.Common.ARM.Instance.WatchTaggedRootBlessed(nil, reportBlessedEvent, nil)
+ if err != nil {
+ log.Error().Err(err).Msg("error in subscribing to TaggedRootBlessed event")
+ }
+ return sub, err
+ })
+ if blessedSub == nil {
+ return fmt.Errorf("failed to subscribe to TaggedRootBlessed event")
+ }
+ go func(sub event.Subscription) {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case e := <-reportBlessedEvent:
+ lane.Logger.Info().Msgf("TaggedRootBlessed event received for root %x", e.TaggedRoot.Root)
+ if e.TaggedRoot.CommitStore == lane.Dest.CommitStore.EthAddress {
+ lane.Dest.ReportBlessedWatcher.Store(e.TaggedRoot.Root, &contracts.LogInfo{
+ BlockNumber: e.Raw.BlockNumber,
+ TxHash: e.Raw.TxHash,
+ })
+ }
+ lane.Dest.ReportBlessedWatcher = testutils.DeleteNilEntriesFromMap(lane.Dest.ReportBlessedWatcher)
+ case <-lane.Context.Done():
+ return
+ }
+ }
+ }(blessedSub)
+ }
+
+ execStateChangedEventLatest := make(chan *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged)
+ execSub := event.Resubscribe(DefaultResubscriptionTimeout, func(_ context.Context) (event.Subscription, error) {
+ sub, err := lane.Dest.OffRamp.WatchExecutionStateChanged(nil, execStateChangedEventLatest, nil, nil)
+ if err != nil {
+ log.Error().Err(err).Msg("error in subscribing to ExecutionStateChanged event")
+ }
+ return sub, err
+ })
+ if execSub == nil {
+ return fmt.Errorf("failed to subscribe to ExecutionStateChanged event")
+ }
+ go func(sub event.Subscription) {
+ defer sub.Unsubscribe()
+ for {
+ select {
+ case e := <-execStateChangedEventLatest:
+ lane.Logger.Info().Msgf("Execution state changed event received for seq number %d", e.SequenceNumber)
+ lane.Dest.ExecStateChangedWatcher.Store(e.SequenceNumber, &contracts.EVM2EVMOffRampExecutionStateChanged{
+ SequenceNumber: e.SequenceNumber,
+ MessageId: e.MessageId,
+ State: e.State,
+ ReturnData: e.ReturnData,
+ LogInfo: contracts.LogInfo{
+ BlockNumber: e.Raw.BlockNumber,
+ TxHash: e.Raw.TxHash,
+ },
+ })
+ lane.Dest.ExecStateChangedWatcher = testutils.DeleteNilEntriesFromMap(lane.Dest.ExecStateChangedWatcher)
+ case <-lane.Context.Done():
+ return
+ }
+ }
+ }(execSub)
+ return nil
+}
+
+func (lane *CCIPLane) CleanUp(clearFees bool) error {
+ lane.Logger.Info().Msg("Cleaning up lane")
+ if lane.Source.Common.ChainClient.GetNetworkConfig().FinalityDepth == 0 {
+ lane.Source.Common.ChainClient.CancelFinalityPolling()
+ }
+ // recover fees from onRamp contract
+ if clearFees && !lane.Source.Common.ChainClient.NetworkSimulated() {
+ err := lane.Source.PayCCIPFeeToOwnerAddress()
+ if err != nil {
+ return err
+ }
+ }
+ err := lane.Dest.Common.ChainClient.Close()
+ if err != nil {
+ return err
+ }
+ return lane.Source.Common.ChainClient.Close()
+}
+
+// DeployNewCCIPLane sets up a lane and initiates lane.Source and lane.Destination
+// If configureCLNodes is true it sets up jobs and contract config for the lane
+func (lane *CCIPLane) DeployNewCCIPLane(
+ setUpCtx context.Context,
+ env *CCIPTestEnv,
+ testConf *testconfig.CCIPTestGroupConfig,
+ bootstrapAdded *atomic.Bool,
+ jobErrGroup *errgroup.Group,
+) error {
+ var (
+ err error
+ sourceChainClient = lane.SourceChain
+ destChainClient = lane.DestChain
+ srcConf = lane.SrcNetworkLaneCfg
+ destConf = lane.DstNetworkLaneCfg
+ commitAndExecOnSameDON = pointer.GetBool(testConf.CommitAndExecuteOnSameDON)
+ withPipeline = pointer.GetBool(testConf.TokenConfig.WithPipeline)
+ configureCLNodes = !pointer.GetBool(testConf.ExistingDeployment)
+ )
+
+ lane.Source, err = DefaultSourceCCIPModule(
+ lane.Logger,
+ testConf,
+ sourceChainClient, destChainClient.GetChainID().Uint64(),
+ destChainClient.GetNetworkName(),
+ srcConf,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create source module: %w", err)
+ }
+ lane.Dest, err = DefaultDestinationCCIPModule(
+ lane.Logger, testConf,
+ destChainClient, sourceChainClient.GetChainID().Uint64(),
+ sourceChainClient.GetNetworkName(), destConf,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create destination module: %w", err)
+ }
+
+ // deploy all source contracts
+ err = lane.Source.DeployContracts(srcConf)
+ if err != nil {
+ return fmt.Errorf("failed to deploy source contracts: %w", err)
+ }
+ // deploy all destination contracts
+ err = lane.Dest.DeployContracts(*lane.Source, destConf)
+ if err != nil {
+ return fmt.Errorf("failed to deploy destination contracts: %w", err)
+ }
+ // if it's a new USDC deployment, sync the USDC domain
+ err = lane.Source.Common.SyncUSDCDomain(lane.Dest.Common.TokenTransmitter, lane.Dest.Common.BridgeTokenPools, lane.Source.DestinationChainId)
+ if err != nil {
+ return fmt.Errorf("failed to sync USDC domain: %w", err)
+ }
+
+ lane.UpdateLaneConfig()
+
+ // if lane is being set up for already configured CL nodes and contracts
+ // no further action is necessary
+ if !configureCLNodes {
+ return nil
+ }
+ err = lane.Source.Common.WatchForPriceUpdates(setUpCtx, lane.Logger)
+ if err != nil {
+ return fmt.Errorf("error in starting price update watch %w", err)
+ }
+ if env == nil {
+ return fmt.Errorf("test environment not set")
+ }
+ // wait for the CL nodes to be ready before moving ahead with job creation
+ err = env.CLNodeWithKeyReady.Wait()
+ if err != nil {
+ return fmt.Errorf("failed to wait for CL nodes to be ready: %w", err)
+ }
+ clNodesWithKeys := env.CLNodesWithKeys
+ // set up ocr2 jobs
+ clNodes, exists := clNodesWithKeys[lane.Dest.Common.ChainClient.GetChainID().String()]
+ if !exists {
+ return fmt.Errorf("could not find CL nodes for %s", lane.Dest.Common.ChainClient.GetChainID().String())
+ }
+ bootstrapCommit := clNodes[0]
+ var bootstrapExec *client.CLNodesWithKeys
+ commitNodes := clNodes[env.CommitNodeStartIndex : env.CommitNodeStartIndex+env.NumOfCommitNodes]
+ execNodes := clNodes[env.ExecNodeStartIndex : env.ExecNodeStartIndex+env.NumOfExecNodes]
+ if !commitAndExecOnSameDON {
+ if len(clNodes) < 11 {
+ return fmt.Errorf("not enough CL nodes for separate commit and execution nodes")
+ }
+ bootstrapExec = clNodes[1] // for a set-up of different commit and execution nodes second node is the bootstrapper for execution nodes
+ }
+
+ // save the current block numbers. If there is a delay between job start up and ocr config set up, the jobs will
+ // replay the log polling from these mentioned block number. The dest block number should ideally be the block number on which
+ // contract config is set and the source block number should be the one on which the ccip send request is performed.
+ // Here for simplicity we are just taking the current block number just before the job is created.
+ currentBlockOnDest, err := destChainClient.LatestBlockNumber(context.Background())
+ if err != nil {
+ return fmt.Errorf("getting current block should be successful in destination chain %w", err)
+ }
+
+ var killgrave *ctftestenv.Killgrave
+ if env.LocalCluster != nil {
+ killgrave = env.LocalCluster.MockAdapter
+ }
+ var tokenAddresses []string
+ for _, token := range lane.Dest.Common.BridgeTokens {
+ tokenAddresses = append(tokenAddresses, token.Address())
+ }
+ tokenAddresses = append(tokenAddresses, lane.Dest.Common.FeeToken.Address(), lane.Source.Common.WrappedNative.Hex(), lane.Dest.Common.WrappedNative.Hex())
+
+ // Only one off pipeline or price getter to be set.
+ tokenPricesUSDPipeline := ""
+ tokenPricesConfigJson := ""
+ if withPipeline {
+ tokensUSDUrl := TokenPricePipelineURLs(tokenAddresses, killgrave, env.MockServer)
+ tokenPricesUSDPipeline = TokenFeeForMultipleTokenAddr(tokensUSDUrl)
+ } else {
+ tokenPricesConfigJson, err = lane.TokenPricesConfig()
+ if err != nil {
+ return fmt.Errorf("error getting token prices config %w", err)
+ }
+ lane.Logger.Info().Str("tokenPricesConfigJson", tokenPricesConfigJson).Msg("Price getter config")
+ }
+
+ jobParams := integrationtesthelpers.CCIPJobSpecParams{
+ OffRamp: lane.Dest.OffRamp.EthAddress,
+ CommitStore: lane.Dest.CommitStore.EthAddress,
+ SourceChainName: sourceChainClient.GetNetworkName(),
+ DestChainName: destChainClient.GetNetworkName(),
+ DestEvmChainId: destChainClient.GetChainID().Uint64(),
+ SourceStartBlock: lane.Source.SrcStartBlock,
+ TokenPricesUSDPipeline: tokenPricesUSDPipeline,
+ PriceGetterConfig: tokenPricesConfigJson,
+ DestStartBlock: currentBlockOnDest,
+ }
+ if !lane.Source.Common.ExistingDeployment && lane.Source.Common.IsUSDCDeployment() {
+ api := ""
+ if killgrave != nil {
+ api = killgrave.InternalEndpoint
+ }
+ if env.MockServer != nil {
+ api = env.MockServer.Config.ClusterURL
+ }
+ if lane.Source.Common.TokenTransmitter == nil {
+ return fmt.Errorf("token transmitter address not set")
+ }
+ // Only one USDC allowed per chain
+ jobParams.USDCConfig = &config.USDCConfig{
+ SourceTokenAddress: common.HexToAddress(lane.Source.Common.BridgeTokens[0].Address()),
+ SourceMessageTransmitterAddress: lane.Source.Common.TokenTransmitter.ContractAddress,
+ AttestationAPI: api,
+ AttestationAPITimeoutSeconds: 5,
+ }
+ }
+ if !bootstrapAdded.Load() {
+ bootstrapAdded.Store(true)
+ err := CreateBootstrapJob(jobParams, bootstrapCommit, bootstrapExec)
+ if err != nil {
+ return fmt.Errorf("failed to create bootstrap job: %w", err)
+ }
+ }
+
+ bootstrapCommitP2PId := bootstrapCommit.KeysBundle.P2PKeys.Data[0].Attributes.PeerID
+ var p2pBootstrappersExec, p2pBootstrappersCommit *client.P2PData
+ if bootstrapExec != nil {
+ p2pBootstrappersExec = &client.P2PData{
+ InternalIP: bootstrapExec.Node.InternalIP(),
+ PeerID: bootstrapExec.KeysBundle.P2PKeys.Data[0].Attributes.PeerID,
+ }
+ }
+
+ p2pBootstrappersCommit = &client.P2PData{
+ InternalIP: bootstrapCommit.Node.InternalIP(),
+ PeerID: bootstrapCommitP2PId,
+ }
+
+ jobParams.P2PV2Bootstrappers = []string{p2pBootstrappersCommit.P2PV2Bootstrapper()}
+
+ err = SetOCR2Config(lane.Context, lane.Logger, *testConf, commitNodes, execNodes, *lane.Dest, lane.PriceReportingDisabled)
+ if err != nil {
+ return fmt.Errorf("failed to set ocr2 config: %w", err)
+ }
+
+ err = CreateOCR2CCIPCommitJobs(lane.Logger, jobParams, commitNodes, env.nodeMutexes, jobErrGroup)
+ if err != nil {
+ return fmt.Errorf("failed to create ocr2 commit jobs: %w", err)
+ }
+ if p2pBootstrappersExec != nil {
+ jobParams.P2PV2Bootstrappers = []string{p2pBootstrappersExec.P2PV2Bootstrapper()}
+ }
+
+ err = CreateOCR2CCIPExecutionJobs(lane.Logger, jobParams, execNodes, env.nodeMutexes, jobErrGroup)
+ if err != nil {
+ return fmt.Errorf("failed to create ocr2 execution jobs: %w", err)
+ }
+
+ if err := lane.Source.Common.ChainClient.WaitForEvents(); err != nil {
+ return fmt.Errorf("failed to wait for events: %w", err)
+ }
+ if err := lane.Dest.Common.ChainClient.WaitForEvents(); err != nil {
+ return fmt.Errorf("failed to wait for events: %w", err)
+ }
+ lane.Dest.Common.ChainClient.ParallelTransactions(false)
+ lane.Source.Common.ChainClient.ParallelTransactions(false)
+
+ return nil
+}
+
+// SetOCR2Config sets the oracle config in ocr2 contracts. If execNodes is nil, commit and execution jobs are set up in same DON
+func SetOCR2Config(
+ ctx context.Context,
+ lggr *zerolog.Logger,
+ testConf testconfig.CCIPTestGroupConfig,
+ commitNodes,
+ execNodes []*client.CLNodesWithKeys,
+ destCCIP DestCCIPModule,
+ priceReportingDisabled bool,
+) error {
+ inflightExpiryExec := commonconfig.MustNewDuration(InflightExpiryExec)
+ inflightExpiryCommit := commonconfig.MustNewDuration(InflightExpiryCommit)
+ blockTime, err := destCCIP.Common.AvgBlockTime(ctx)
+ if err != nil {
+ return fmt.Errorf("failed to get avg block time: %w", err)
+ }
+
+ OCR2ParamsForCommit := contracts.OCR2ParamsForCommit(blockTime)
+ OCR2ParamsForExec := contracts.OCR2ParamsForExec(blockTime)
+ // if test config has custom ocr2 params, merge them with default params to replace default with custom ocr2 params provided in config
+ // for commit and exec
+ if testConf.CommitOCRParams != nil {
+ err := mergo.Merge(&OCR2ParamsForCommit, testConf.CommitOCRParams, mergo.WithOverride)
+ if err != nil {
+ return err
+ }
+ }
+ if testConf.ExecOCRParams != nil {
+ err := mergo.Merge(&OCR2ParamsForExec, testConf.ExecOCRParams, mergo.WithOverride)
+ if err != nil {
+ return err
+ }
+ }
+ lggr.Info().
+ Dur("AvgBlockTimeOnDest", blockTime).
+ Interface("OCRParmsForCommit", OCR2ParamsForCommit).
+ Interface("OCRParmsForExec", OCR2ParamsForExec).
+ Msg("Setting OCR2 config")
+ commitOffchainCfg, err := contracts.NewCommitOffchainConfig(
+ *commonconfig.MustNewDuration(5 * time.Second),
+ 1e6,
+ 1e6,
+ *commonconfig.MustNewDuration(5 * time.Second),
+ 1e6,
+ *inflightExpiryCommit,
+ priceReportingDisabled,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create commit offchain config: %w", err)
+ }
+
+ commitOnchainCfg, err := contracts.NewCommitOnchainConfig(
+ destCCIP.Common.PriceRegistry.EthAddress,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create commit onchain config: %w", err)
+ }
+ signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig, err := contracts.NewOffChainAggregatorV2ConfigForCCIPPlugin(
+ commitNodes, commitOffchainCfg, commitOnchainCfg, OCR2ParamsForCommit, 3*time.Minute)
+ if err != nil {
+ return fmt.Errorf("failed to create ocr2 config params for commit: %w", err)
+ }
+
+ err = destCCIP.CommitStore.SetOCR2Config(signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ if err != nil {
+ return fmt.Errorf("failed to set ocr2 config for commit: %w", err)
+ }
+
+ nodes := commitNodes
+ // if commit and exec job is set up in different DON
+ if len(execNodes) > 0 {
+ nodes = execNodes
+ }
+ if destCCIP.OffRamp != nil {
+ execOffchainCfg, err := contracts.NewExecOffchainConfig(
+ 1,
+ BatchGasLimit,
+ 0.7,
+ *inflightExpiryExec,
+ *commonconfig.MustNewDuration(RootSnoozeTime),
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create exec offchain config: %w", err)
+ }
+ execOnchainCfg, err := contracts.NewExecOnchainConfig(
+ uint32(DefaultPermissionlessExecThreshold.Seconds()),
+ destCCIP.Common.Router.EthAddress,
+ destCCIP.Common.PriceRegistry.EthAddress,
+ DefaultMaxNoOfTokensInMsg,
+ MaxDataBytes,
+ 200_000,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create exec onchain config: %w", err)
+ }
+ signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig, err = contracts.NewOffChainAggregatorV2ConfigForCCIPPlugin(
+ nodes,
+ execOffchainCfg,
+ execOnchainCfg,
+ OCR2ParamsForExec,
+ 3*time.Minute,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create ocr2 config params for exec: %w", err)
+ }
+ err = destCCIP.OffRamp.SetOCR2Config(signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ if err != nil {
+ return fmt.Errorf("failed to set ocr2 config for exec: %w", err)
+ }
+ }
+ return destCCIP.Common.ChainClient.WaitForEvents()
+}
+
+func CreateBootstrapJob(
+ jobParams integrationtesthelpers.CCIPJobSpecParams,
+ bootstrapCommit *client.CLNodesWithKeys,
+ bootstrapExec *client.CLNodesWithKeys,
+) error {
+ _, err := bootstrapCommit.Node.MustCreateJob(jobParams.BootstrapJob(jobParams.CommitStore.Hex()))
+ if err != nil {
+ return fmt.Errorf("shouldn't fail creating bootstrap job on bootstrap node %w", err)
+ }
+ if bootstrapExec != nil {
+ _, err := bootstrapExec.Node.MustCreateJob(jobParams.BootstrapJob(jobParams.OffRamp.Hex()))
+ if err != nil {
+ return fmt.Errorf("shouldn't fail creating bootstrap job on bootstrap node %w", err)
+ }
+ }
+ return nil
+}
+
+func CreateOCR2CCIPCommitJobs(
+ lggr *zerolog.Logger,
+ jobParams integrationtesthelpers.CCIPJobSpecParams,
+ commitNodes []*client.CLNodesWithKeys,
+ mutexes []*sync.Mutex,
+ group *errgroup.Group,
+) error {
+ ocr2SpecCommit, err := jobParams.CommitJobSpec()
+ if err != nil {
+ return fmt.Errorf("failed to create ocr2 commit job spec: %w", err)
+ }
+ createJob := func(index int, node *client.CLNodesWithKeys, ocr2SpecCommit client.OCR2TaskJobSpec, mu *sync.Mutex) error {
+ mu.Lock()
+ defer mu.Unlock()
+ ocr2SpecCommit.OCR2OracleSpec.OCRKeyBundleID.SetValid(node.KeysBundle.OCR2Key.Data.ID)
+ ocr2SpecCommit.OCR2OracleSpec.TransmitterID.SetValid(node.KeysBundle.EthAddress)
+ lggr.Info().Msgf("Creating CCIP-Commit job on OCR node %d job name %s", index+1, ocr2SpecCommit.Name)
+ _, err = node.Node.MustCreateJob(&ocr2SpecCommit)
+ if err != nil {
+ return fmt.Errorf("shouldn't fail creating CCIP-Commit job on OCR node %d job name %s - %w", index+1, ocr2SpecCommit.Name, err)
+ }
+ return nil
+ }
+
+ testSpec := client.OCR2TaskJobSpec{
+ Name: ocr2SpecCommit.Name,
+ JobType: ocr2SpecCommit.JobType,
+ OCR2OracleSpec: ocr2SpecCommit.OCR2OracleSpec,
+ }
+ for i, node := range commitNodes {
+ node := node
+ i := i
+ group.Go(func() error {
+ return createJob(i, node, testSpec, mutexes[i])
+ })
+ }
+ return nil
+}
+
+func CreateOCR2CCIPExecutionJobs(
+ lggr *zerolog.Logger,
+ jobParams integrationtesthelpers.CCIPJobSpecParams,
+ execNodes []*client.CLNodesWithKeys,
+ mutexes []*sync.Mutex,
+ group *errgroup.Group,
+) error {
+ ocr2SpecExec, err := jobParams.ExecutionJobSpec()
+ if err != nil {
+ return fmt.Errorf("failed to create ocr2 execution job spec: %w", err)
+ }
+ createJob := func(index int, node *client.CLNodesWithKeys, ocr2SpecExec client.OCR2TaskJobSpec, mu *sync.Mutex) error {
+ mu.Lock()
+ defer mu.Unlock()
+ ocr2SpecExec.OCR2OracleSpec.OCRKeyBundleID.SetValid(node.KeysBundle.OCR2Key.Data.ID)
+ ocr2SpecExec.OCR2OracleSpec.TransmitterID.SetValid(node.KeysBundle.EthAddress)
+ lggr.Info().Msgf("Creating CCIP-Exec job on OCR node %d job name %s", index+1, ocr2SpecExec.Name)
+ _, err = node.Node.MustCreateJob(&ocr2SpecExec)
+ if err != nil {
+ return fmt.Errorf("shouldn't fail creating CCIP-Exec job on OCR node %d job name %s - %w", index+1,
+ ocr2SpecExec.Name, err)
+ }
+ return nil
+ }
+ if ocr2SpecExec != nil {
+ for i, node := range execNodes {
+ node := node
+ i := i
+ group.Go(func() error {
+ return createJob(i, node, client.OCR2TaskJobSpec{
+ Name: ocr2SpecExec.Name,
+ JobType: ocr2SpecExec.JobType,
+ MaxTaskDuration: ocr2SpecExec.MaxTaskDuration,
+ ForwardingAllowed: ocr2SpecExec.ForwardingAllowed,
+ OCR2OracleSpec: ocr2SpecExec.OCR2OracleSpec,
+ ObservationSource: ocr2SpecExec.ObservationSource,
+ }, mutexes[i])
+ })
+ }
+ }
+ return nil
+}
+
+func TokenFeeForMultipleTokenAddr(tokenAddrToURL map[string]string) string {
+ source := ""
+ right := ""
+ i := 1
+ for addr, url := range tokenAddrToURL {
+ source = source + fmt.Sprintf(`
+token%d [type=http method=GET url="%s"];
+token%d_parse [type=jsonparse path="data,result"];
+token%d->token%d_parse;`, i, url, i, i, i)
+ right = right + fmt.Sprintf(` \\\"%s\\\":$(token%d_parse),`, addr, i)
+ i++
+ }
+ right = right[:len(right)-1]
+ source = fmt.Sprintf(`%s
+merge [type=merge left="{}" right="{%s}"];`, source, right)
+
+ return source
+}
+
+type CCIPTestEnv struct {
+ MockServer *ctfClient.MockserverClient
+ LocalCluster *test_env.CLClusterTestEnv
+ CLNodesWithKeys map[string][]*client.CLNodesWithKeys // key - network chain-id
+ CLNodes []*client.ChainlinkK8sClient
+ nodeMutexes []*sync.Mutex
+ ExecNodeStartIndex int
+ CommitNodeStartIndex int
+ NumOfAllowedFaultyCommit int
+ NumOfAllowedFaultyExec int
+ NumOfCommitNodes int
+ NumOfExecNodes int
+ K8Env *environment.Environment
+ CLNodeWithKeyReady *errgroup.Group // denotes if keys are created in chainlink node and ready to be used for job creation
+}
+
+func (c *CCIPTestEnv) ChaosLabelForGeth(t *testing.T, srcChain, destChain string) {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, map[string]string{
+ "app": GethLabel(srcChain),
+ }, ChaosGroupNetworkACCIPGeth)
+ require.NoError(t, err)
+
+ err = c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, map[string]string{
+ "app": GethLabel(destChain),
+ }, ChaosGroupNetworkBCCIPGeth)
+ require.NoError(t, err)
+ gethNetworksLabels := []string{GethLabel(srcChain), GethLabel(destChain)}
+ c.ChaosLabelForAllGeth(t, gethNetworksLabels)
+
+}
+
+func (c *CCIPTestEnv) ChaosLabelForAllGeth(t *testing.T, gethNetworksLabels []string) {
+ for _, gethNetworkLabel := range gethNetworksLabels {
+ err := c.K8Env.Client.AddLabel(c.K8Env.Cfg.Namespace,
+ fmt.Sprintf("app=%s", gethNetworkLabel),
+ fmt.Sprintf("geth=%s", ChaosGroupCCIPGeth))
+ require.NoError(t, err)
+ }
+}
+
+func (c *CCIPTestEnv) ChaosLabelForCLNodes(t *testing.T) {
+ allowedFaulty := c.NumOfAllowedFaultyCommit
+ commitStartInstance := c.CommitNodeStartIndex + 1
+ execStartInstance := c.ExecNodeStartIndex + 1
+ for i := commitStartInstance; i < len(c.CLNodes); i++ {
+ labelSelector := map[string]string{
+ "app": "chainlink-0",
+ "instance": fmt.Sprintf("node-%d", i),
+ }
+ if i >= commitStartInstance && i < commitStartInstance+allowedFaulty+1 {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, labelSelector, ChaosGroupCommitAndExecFaultyPlus)
+ require.NoError(t, err)
+ }
+ if i >= commitStartInstance && i < commitStartInstance+allowedFaulty {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, labelSelector, ChaosGroupCommitAndExecFaulty)
+ require.NoError(t, err)
+ }
+
+ // commit node starts from index 2
+ if i >= commitStartInstance && i < commitStartInstance+c.NumOfCommitNodes {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, labelSelector, ChaosGroupCommit)
+ require.NoError(t, err)
+ }
+ if i >= commitStartInstance && i < commitStartInstance+c.NumOfAllowedFaultyCommit+1 {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, labelSelector, ChaosGroupCommitFaultyPlus)
+ require.NoError(t, err)
+ }
+ if i >= commitStartInstance && i < commitStartInstance+c.NumOfAllowedFaultyCommit {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, labelSelector, ChaosGroupCommitFaulty)
+ require.NoError(t, err)
+ }
+ if i >= execStartInstance && i < execStartInstance+c.NumOfExecNodes {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, labelSelector, ChaosGroupExecution)
+ require.NoError(t, err)
+ }
+ if i >= execStartInstance && i < execStartInstance+c.NumOfAllowedFaultyExec+1 {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, labelSelector, ChaosGroupExecutionFaultyPlus)
+ require.NoError(t, err)
+ }
+ if i >= execStartInstance && i < execStartInstance+c.NumOfAllowedFaultyExec {
+ err := c.K8Env.Client.LabelChaosGroupByLabels(c.K8Env.Cfg.Namespace, labelSelector, ChaosGroupExecutionFaulty)
+ require.NoError(t, err)
+ }
+ }
+}
+
+func (c *CCIPTestEnv) ConnectToExistingNodes(envConfig *testconfig.Common) error {
+ if envConfig.ExistingCLCluster == nil {
+ return fmt.Errorf("existing cluster is nil")
+ }
+ noOfNodes := pointer.GetInt(envConfig.ExistingCLCluster.NoOfNodes)
+ namespace := pointer.GetString(envConfig.ExistingCLCluster.Name)
+
+ for i := 0; i < noOfNodes; i++ {
+ cfg := envConfig.ExistingCLCluster.NodeConfigs[i]
+ if cfg == nil {
+ return fmt.Errorf("node %d config is nil", i+1)
+ }
+ clClient, err := client.NewChainlinkK8sClient(cfg, cfg.InternalIP, namespace)
+ if err != nil {
+ return fmt.Errorf("failed to create chainlink client: %w for node %d config %v", err, i+1, cfg)
+ }
+ c.CLNodes = append(c.CLNodes, clClient)
+ c.nodeMutexes = append(c.nodeMutexes, &sync.Mutex{})
+ }
+
+ return nil
+}
+
+func (c *CCIPTestEnv) ConnectToDeployedNodes() error {
+ if c.LocalCluster != nil {
+ // for local cluster, fetch the values from the local cluster
+ for _, chainlinkNode := range c.LocalCluster.ClCluster.Nodes {
+ c.nodeMutexes = append(c.nodeMutexes, &sync.Mutex{})
+ c.CLNodes = append(c.CLNodes, &client.ChainlinkK8sClient{
+ ChainlinkClient: chainlinkNode.API,
+ })
+ }
+ } else {
+ // in case of k8s, we need to connect to the chainlink nodes
+ log.Info().Msg("Connecting to launched resources")
+ chainlinkK8sNodes, err := client.ConnectChainlinkNodes(c.K8Env)
+ if err != nil {
+ return fmt.Errorf("failed to connect to chainlink nodes: %w", err)
+ }
+ if len(chainlinkK8sNodes) == 0 {
+ return fmt.Errorf("no CL node found")
+ }
+
+ for range chainlinkK8sNodes {
+ c.nodeMutexes = append(c.nodeMutexes, &sync.Mutex{})
+ }
+ c.CLNodes = chainlinkK8sNodes
+ if _, exists := c.K8Env.URLs[mockserver.InternalURLsKey]; exists {
+ c.MockServer = ctfClient.ConnectMockServer(c.K8Env)
+ }
+ }
+ return nil
+}
+
+// SetUpNodeKeysAndFund creates node keys and funds the nodes
+func (c *CCIPTestEnv) SetUpNodeKeysAndFund(
+ logger *zerolog.Logger,
+ nodeFund *big.Float,
+ chains []blockchain.EVMClient,
+) error {
+ if c.CLNodes == nil || len(c.CLNodes) == 0 {
+ return fmt.Errorf("no chainlink nodes to setup")
+ }
+ var chainlinkNodes []*client.ChainlinkClient
+ for _, node := range c.CLNodes {
+ chainlinkNodes = append(chainlinkNodes, node.ChainlinkClient)
+ }
+ nodesWithKeys := make(map[string][]*client.CLNodesWithKeys)
+
+ populateKeys := func(chain blockchain.EVMClient) error {
+ log.Info().Str("chain id", chain.GetChainID().String()).Msg("creating node keys for chain")
+ _, clNodes, err := client.CreateNodeKeysBundle(chainlinkNodes, "evm", chain.GetChainID().String())
+ if err != nil {
+ return fmt.Errorf("failed to create node keys for chain %s: %w", chain.GetChainID().String(), err)
+ }
+ if len(clNodes) == 0 {
+ return fmt.Errorf("no CL node with keys found for chain %s", chain.GetNetworkName())
+ }
+
+ nodesWithKeys[chain.GetChainID().String()] = clNodes
+ return nil
+ }
+
+ fund := func(ec blockchain.EVMClient) error {
+ cfg := ec.GetNetworkConfig()
+ if cfg == nil {
+ return fmt.Errorf("blank network config")
+ }
+ c1, err := blockchain.ConcurrentEVMClient(*cfg, c.K8Env, ec, *logger)
+ if err != nil {
+ return fmt.Errorf("getting concurrent evmclient chain %s %w", ec.GetNetworkName(), err)
+ }
+ defer func() {
+ if c1 != nil {
+ c1.Close()
+ }
+ }()
+ log.Info().Str("chain id", c1.GetChainID().String()).Msg("Funding Chainlink nodes for chain")
+ for i := 1; i < len(chainlinkNodes); i++ {
+ cl := chainlinkNodes[i]
+ m := c.nodeMutexes[i]
+ toAddress, err := cl.EthAddressesForChain(c1.GetChainID().String())
+ if err != nil {
+ return err
+ }
+ for _, addr := range toAddress {
+ toAddr := common.HexToAddress(addr)
+ gasEstimates, err := c1.EstimateGas(ethereum.CallMsg{
+ To: &toAddr,
+ })
+ if err != nil {
+ return err
+ }
+ m.Lock()
+ err = c1.Fund(addr, nodeFund, gasEstimates)
+ m.Unlock()
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return c1.WaitForEvents()
+ }
+ grp, _ := errgroup.WithContext(context.Background())
+ for _, chain := range chains {
+ err := populateKeys(chain)
+ if err != nil {
+ return err
+ }
+ }
+ for _, chain := range chains {
+ chain := chain
+ grp.Go(func() error {
+ return fund(chain)
+ })
+ }
+ err := grp.Wait()
+ if err != nil {
+ return fmt.Errorf("error funding nodes %w", err)
+ }
+ c.CLNodesWithKeys = nodesWithKeys
+
+ return nil
+}
+
+func AssertBalances(t *testing.T, bas []testhelpers.BalanceAssertion) {
+ logEvent := log.Info()
+ for _, b := range bas {
+ actual := b.Getter(t, b.Address)
+ assert.NotNil(t, actual, "%v getter return nil", b.Name)
+ if b.Within == "" {
+ assert.Equal(t, b.Expected, actual.String(), "wrong balance for %s got %s want %s", b.Name, actual, b.Expected)
+ logEvent.Interface(b.Name, struct {
+ Exp string
+ Actual string
+ }{
+ Exp: b.Expected,
+ Actual: actual.String(),
+ })
+ } else {
+ bi, _ := big.NewInt(0).SetString(b.Expected, 10)
+ withinI, _ := big.NewInt(0).SetString(b.Within, 10)
+ high := big.NewInt(0).Add(bi, withinI)
+ low := big.NewInt(0).Sub(bi, withinI)
+ assert.Equal(t, -1, actual.Cmp(high),
+ "wrong balance for %s got %s outside expected range [%s, %s]", b.Name, actual, low, high)
+ assert.Equal(t, 1, actual.Cmp(low),
+ "wrong balance for %s got %s outside expected range [%s, %s]", b.Name, actual, low, high)
+ logEvent.Interface(b.Name, struct {
+ ExpRange string
+ Actual string
+ }{
+ ExpRange: fmt.Sprintf("[%s, %s]", low, high),
+ Actual: actual.String(),
+ })
+ }
+ }
+ logEvent.Msg("balance assertions succeeded")
+}
+
+type BalFunc func(ctx context.Context, addr string) (*big.Int, error)
+
+func GetterForLinkToken(getBalance BalFunc, addr string) func(t *testing.T, _ common.Address) *big.Int {
+ return func(t *testing.T, _ common.Address) *big.Int {
+ balance, err := getBalance(context.Background(), addr)
+ assert.NoError(t, err)
+ return balance
+ }
+}
+
+type BalanceItem struct {
+ Address common.Address
+ Getter func(t *testing.T, addr common.Address) *big.Int
+ PreviousBalance *big.Int
+ AmtToAdd *big.Int
+ AmtToSub *big.Int
+}
+
+type BalanceSheet struct {
+ mu *sync.Mutex
+ Items map[string]BalanceItem
+ PrevBalance map[string]*big.Int
+}
+
+func (b *BalanceSheet) Update(key string, item BalanceItem) {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+ prev, ok := b.Items[key]
+ if !ok {
+ b.Items[key] = item
+ return
+ }
+ amtToAdd, amtToSub := big.NewInt(0), big.NewInt(0)
+ if prev.AmtToAdd != nil {
+ amtToAdd = prev.AmtToAdd
+ }
+ if prev.AmtToSub != nil {
+ amtToSub = prev.AmtToSub
+ }
+ if item.AmtToAdd != nil {
+ amtToAdd = new(big.Int).Add(amtToAdd, item.AmtToAdd)
+ }
+ if item.AmtToSub != nil {
+ amtToSub = new(big.Int).Add(amtToSub, item.AmtToSub)
+ }
+
+ b.Items[key] = BalanceItem{
+ Address: item.Address,
+ Getter: item.Getter,
+ AmtToAdd: amtToAdd,
+ AmtToSub: amtToSub,
+ }
+}
+
+func (b *BalanceSheet) RecordBalance(bal map[string]*big.Int) {
+ b.mu.Lock()
+ defer b.mu.Unlock()
+ for key, value := range bal {
+ if _, ok := b.PrevBalance[key]; !ok {
+ b.PrevBalance[key] = value
+ }
+ }
+}
+
+func (b *BalanceSheet) Verify(t *testing.T) {
+ var balAssertions []testhelpers.BalanceAssertion
+ for key, item := range b.Items {
+ prevBalance, ok := b.PrevBalance[key]
+ require.Truef(t, ok, "previous balance is not captured for %s", key)
+ exp := prevBalance
+ if item.AmtToAdd != nil {
+ exp = new(big.Int).Add(exp, item.AmtToAdd)
+ }
+ if item.AmtToSub != nil {
+ exp = new(big.Int).Sub(exp, item.AmtToSub)
+ }
+ balAssertions = append(balAssertions, testhelpers.BalanceAssertion{
+ Name: key,
+ Address: item.Address,
+ Getter: item.Getter,
+ Expected: exp.String(),
+ })
+ }
+ AssertBalances(t, balAssertions)
+}
+
+func NewBalanceSheet() *BalanceSheet {
+ return &BalanceSheet{
+ mu: &sync.Mutex{},
+ Items: make(map[string]BalanceItem),
+ PrevBalance: make(map[string]*big.Int),
+ }
+}
+
+// SetMockServerWithUSDCAttestation responds with a mock attestation for any msgHash
+// The path is set with regex to match any path that starts with /v1/attestations
+func SetMockServerWithUSDCAttestation(
+ killGrave *ctftestenv.Killgrave,
+ mockserver *ctfClient.MockserverClient,
+) error {
+ path := "/v1/attestations"
+ response := struct {
+ Status string `json:"status"`
+ Attestation string `json:"attestation"`
+ Error string `json:"error"`
+ }{
+ Status: "complete",
+ Attestation: "0x9049623e91719ef2aa63c55f357be2529b0e7122ae552c18aff8db58b4633c4d3920ff03d3a6d1ddf11f06bf64d7fd60d45447ac81f527ba628877dc5ca759651b08ffae25a6d3b1411749765244f0a1c131cbfe04430d687a2e12fd9d2e6dc08e118ad95d94ad832332cf3c4f7a4f3da0baa803b7be024b02db81951c0f0714de1b",
+ }
+ if killGrave == nil && mockserver == nil {
+ return fmt.Errorf("both killgrave and mockserver are nil")
+ }
+ log.Info().Str("path", path).Msg("setting attestation-api response for any msgHash")
+ if killGrave != nil {
+ err := killGrave.SetAnyValueResponse(fmt.Sprintf("%s/{_hash:.*}", path), []string{http.MethodGet}, response)
+ if err != nil {
+ return fmt.Errorf("failed to set killgrave server value: %w", err)
+ }
+ }
+ if mockserver != nil {
+ err := mockserver.SetAnyValueResponse(fmt.Sprintf("%s/.*", path), response)
+ if err != nil {
+ return fmt.Errorf("failed to set mockserver value: %w URL = %s", err, fmt.Sprintf("%s/%s/.*", mockserver.LocalURL(), path))
+ }
+ }
+ return nil
+}
+
+// SetMockserverWithTokenPriceValue sets the mock responses in mockserver that are read by chainlink nodes
+// to simulate different price feed value.
+// it keeps updating the response every 15 seconds to simulate price feed updates
+func SetMockserverWithTokenPriceValue(
+ killGrave *ctftestenv.Killgrave,
+ mockserver *ctfClient.MockserverClient,
+) {
+ wg := &sync.WaitGroup{}
+ path := "token_contract_"
+ wg.Add(1)
+ go func() {
+ set := true
+ // keep updating token value every 15 second
+ for {
+ if killGrave == nil && mockserver == nil {
+ log.Fatal().Msg("both killgrave and mockserver are nil")
+ return
+ }
+ tokenValue := big.NewInt(time.Now().UnixNano()).String()
+ if killGrave != nil {
+ err := killGrave.SetAdapterBasedAnyValuePath(fmt.Sprintf("%s{.*}", path), []string{http.MethodGet}, tokenValue)
+ if err != nil {
+ log.Fatal().Err(err).Msg("failed to set killgrave server value")
+ return
+ }
+ }
+ if mockserver != nil {
+ err := mockserver.SetAnyValuePath(fmt.Sprintf("/%s.*", path), tokenValue)
+ if err != nil {
+ log.Fatal().Err(err).Str("URL", fmt.Sprintf("%s/%s/.*", mockserver.LocalURL(), path)).Msg("failed to set mockserver value")
+ return
+ }
+ }
+ if set {
+ set = false
+ wg.Done()
+ }
+ time.Sleep(15 * time.Second)
+ }
+ }()
+ // wait for the first value to be set
+ wg.Wait()
+}
+
+// TokenPricePipelineURLs returns the mockserver urls for the token price pipeline
+func TokenPricePipelineURLs(
+ tokenAddresses []string,
+ killGrave *ctftestenv.Killgrave,
+ mockserver *ctfClient.MockserverClient,
+) map[string]string {
+ mapTokenURL := make(map[string]string)
+
+ for _, tokenAddr := range tokenAddresses {
+ path := fmt.Sprintf("token_contract_%s", tokenAddr[2:12])
+ if mockserver != nil {
+ mapTokenURL[tokenAddr] = fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, path)
+ }
+ if killGrave != nil {
+ mapTokenURL[tokenAddr] = fmt.Sprintf("%s/%s", killGrave.InternalEndpoint, path)
+ }
+ }
+
+ return mapTokenURL
+}
diff --git a/integration-tests/ccip-tests/actions/ccip_helpers_test.go b/integration-tests/ccip-tests/actions/ccip_helpers_test.go
new file mode 100644
index 00000000000..4ca1061d6f2
--- /dev/null
+++ b/integration-tests/ccip-tests/actions/ccip_helpers_test.go
@@ -0,0 +1,105 @@
+package actions
+
+import (
+ "errors"
+ "testing"
+
+ "github.com/rs/zerolog"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testreporters"
+)
+
+func TestIsPhaseValid(t *testing.T) {
+ // isPhaseValid has some complex logic that could lead to false negatives
+ t.Parallel()
+ logger := zerolog.New(zerolog.Nop())
+
+ testCases := []struct {
+ name string
+ currentPhase testreporters.Phase
+ opts validationOptions
+ phaseErr error
+
+ expectedShouldReturn bool
+ expectedErr error
+ }{
+ {
+ name: "should return error immediately if phase error is present and no phase is expected to fail",
+ currentPhase: testreporters.CCIPSendRe,
+ opts: validationOptions{},
+ phaseErr: errors.New("some error"),
+
+ expectedShouldReturn: true,
+ expectedErr: errors.New("some error"),
+ },
+ {
+ name: "should return with no error if phase is expected to fail and phase error present",
+ currentPhase: testreporters.CCIPSendRe,
+ opts: validationOptions{
+ phaseExpectedToFail: testreporters.CCIPSendRe,
+ },
+ phaseErr: errors.New("some error"),
+
+ expectedShouldReturn: true,
+ expectedErr: nil,
+ },
+ {
+ name: "should return with error if phase is expected to fail and no phase error present",
+ currentPhase: testreporters.CCIPSendRe,
+ opts: validationOptions{
+ phaseExpectedToFail: testreporters.CCIPSendRe,
+ },
+ phaseErr: nil,
+
+ expectedShouldReturn: true,
+ expectedErr: errors.New("expected phase 'CCIPSendRequested' to fail, but it passed"),
+ },
+ {
+ name: "should not return if phase is not expected to fail and no phase error present",
+ currentPhase: testreporters.CCIPSendRe,
+ opts: validationOptions{
+ phaseExpectedToFail: testreporters.ExecStateChanged,
+ },
+ phaseErr: nil,
+
+ expectedShouldReturn: false,
+ expectedErr: nil,
+ },
+ {
+ name: "should return with no error if phase is expected to fail with specific error message and that error message is present",
+ currentPhase: testreporters.CCIPSendRe,
+ opts: validationOptions{
+ phaseExpectedToFail: testreporters.CCIPSendRe,
+ expectedErrorMessage: "some error",
+ },
+ phaseErr: errors.New("some error"),
+
+ expectedShouldReturn: true,
+ expectedErr: nil,
+ },
+ {
+ name: "should return with error if phase is expected to fail with specific error message and that error message is not present",
+ currentPhase: testreporters.CCIPSendRe,
+ opts: validationOptions{
+ phaseExpectedToFail: testreporters.CCIPSendRe,
+ expectedErrorMessage: "some error",
+ },
+ phaseErr: errors.New("some other error"),
+
+ expectedShouldReturn: true,
+ expectedErr: errors.New("expected phase 'CCIPSendRequested' to fail with error message 'some error' but got error 'some other error'"),
+ },
+ }
+
+ for _, tc := range testCases {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+
+ shouldReturn, err := isPhaseValid(&logger, tc.currentPhase, tc.opts, tc.phaseErr)
+ require.Equal(t, tc.expectedShouldReturn, shouldReturn, "shouldReturn not as expected")
+ require.Equal(t, tc.expectedErr, err, "err not as expected")
+ })
+ }
+}
diff --git a/integration-tests/ccip-tests/chaos/ccip_test.go b/integration-tests/ccip-tests/chaos/ccip_test.go
new file mode 100644
index 00000000000..4b1dda7a91e
--- /dev/null
+++ b/integration-tests/ccip-tests/chaos/ccip_test.go
@@ -0,0 +1,153 @@
+package chaos_test
+
+import (
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos"
+ "github.com/smartcontractkit/chainlink-testing-framework/logging"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups"
+)
+
+/* @network-chaos and @pod-chaos are split intentionally into 2 parallel groups
+we can't use chaos.NewNetworkPartition and chaos.NewFailPods in parallel
+because of jsii runtime bug, see Makefile and please use those targets to run tests
+In .github/workflows/ccip-chaos-tests.yml we use these tags to run these tests separately
+*/
+
+func TestChaosCCIP(t *testing.T) {
+ inputs := []struct {
+ testName string
+ chaosFunc chaos.ManifestFunc
+ chaosProps *chaos.Props
+ waitForChaosRecovery bool
+ }{
+ {
+ testName: "CCIP works after rpc is down for NetworkA @network-chaos",
+ chaosFunc: chaos.NewNetworkPartition,
+ chaosProps: &chaos.Props{
+ FromLabels: &map[string]*string{actions.ChaosGroupNetworkACCIPGeth: ptr.Ptr("1")},
+ // chainlink-0 is default label set for all cll nodes
+ ToLabels: &map[string]*string{"app": ptr.Ptr("chainlink-0")},
+ DurationStr: "1m",
+ },
+ waitForChaosRecovery: true,
+ },
+ {
+ testName: "CCIP works after rpc is down for NetworkB @network-chaos",
+ chaosFunc: chaos.NewNetworkPartition,
+ chaosProps: &chaos.Props{
+ FromLabels: &map[string]*string{actions.ChaosGroupNetworkBCCIPGeth: ptr.Ptr("1")},
+ ToLabels: &map[string]*string{"app": ptr.Ptr("chainlink-0")},
+ DurationStr: "1m",
+ },
+ waitForChaosRecovery: true,
+ },
+ {
+ testName: "CCIP works after 2 rpc's are down for all cll nodes @network-chaos",
+ chaosFunc: chaos.NewNetworkPartition,
+ chaosProps: &chaos.Props{
+ FromLabels: &map[string]*string{"geth": ptr.Ptr(actions.ChaosGroupCCIPGeth)},
+ ToLabels: &map[string]*string{"app": ptr.Ptr("chainlink-0")},
+ DurationStr: "1m",
+ },
+ waitForChaosRecovery: true,
+ },
+ {
+ testName: "CCIP Commit works after majority of CL nodes are recovered from pod failure @pod-chaos",
+ chaosFunc: chaos.NewFailPods,
+ chaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupCommitFaultyPlus: ptr.Ptr("1")},
+ DurationStr: "1m",
+ },
+ waitForChaosRecovery: true,
+ },
+ {
+ testName: "CCIP Execution works after majority of CL nodes are recovered from pod failure @pod-chaos",
+ chaosFunc: chaos.NewFailPods,
+ chaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupExecutionFaultyPlus: ptr.Ptr("1")},
+ DurationStr: "1m",
+ },
+ waitForChaosRecovery: true,
+ },
+ {
+ testName: "CCIP Commit works while minority of CL nodes are in failed state for pod failure @pod-chaos",
+ chaosFunc: chaos.NewFailPods,
+ chaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupCommitFaulty: ptr.Ptr("1")},
+ DurationStr: "90s",
+ },
+ waitForChaosRecovery: false,
+ },
+ {
+ testName: "CCIP Execution works while minority of CL nodes are in failed state for pod failure @pod-chaos",
+ chaosFunc: chaos.NewFailPods,
+ chaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupExecutionFaulty: ptr.Ptr("1")},
+ DurationStr: "90s",
+ },
+ waitForChaosRecovery: false,
+ },
+ }
+
+ for _, in := range inputs {
+ in := in
+ t.Run(in.testName, func(t *testing.T) {
+ t.Parallel()
+ l := logging.GetTestLogger(t)
+ testCfg := testsetups.NewCCIPTestConfig(t, l, testconfig.Chaos)
+ var numOfRequests = 3
+
+ setUpArgs := testsetups.CCIPDefaultTestSetUp(
+ t, &l, "chaos-ccip", nil, testCfg)
+
+ if len(setUpArgs.Lanes) == 0 {
+ return
+ }
+
+ lane := setUpArgs.Lanes[0].ForwardLane
+
+ tearDown := setUpArgs.TearDown
+ testEnvironment := setUpArgs.Env.K8Env
+ testSetup := setUpArgs.Env
+
+ testSetup.ChaosLabelForGeth(t, lane.SourceChain.GetNetworkName(), lane.DestChain.GetNetworkName())
+ testSetup.ChaosLabelForCLNodes(t)
+
+ lane.RecordStateBeforeTransfer()
+ // Send the ccip-request and verify ocr2 is running
+ err := lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+ lane.ValidateRequests(nil)
+
+ // apply chaos
+ chaosId, err := testEnvironment.Chaos.Run(in.chaosFunc(testEnvironment.Cfg.Namespace, in.chaosProps))
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ if chaosId != "" {
+ require.NoError(t, testEnvironment.Chaos.Stop(chaosId))
+ }
+ require.NoError(t, tearDown())
+ })
+ lane.RecordStateBeforeTransfer()
+ // Now send the ccip-request while the chaos is at play
+ err = lane.SendRequests(numOfRequests, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+ if in.waitForChaosRecovery {
+ // wait for chaos to be recovered before further validation
+ require.NoError(t, testEnvironment.Chaos.WaitForAllRecovered(chaosId, 1*time.Minute))
+ } else {
+ l.Info().Msg("proceeding without waiting for chaos recovery")
+ }
+ lane.ValidateRequests(nil)
+ })
+ }
+}
diff --git a/integration-tests/ccip-tests/contracts/contract_deployer.go b/integration-tests/ccip-tests/contracts/contract_deployer.go
new file mode 100644
index 00000000000..8656656e0b2
--- /dev/null
+++ b/integration-tests/ccip-tests/contracts/contract_deployer.go
@@ -0,0 +1,1586 @@
+package contracts
+
+import (
+ "context"
+ "crypto/ed25519"
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "strings"
+ "time"
+
+ "github.com/Masterminds/semver/v3"
+ "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"
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+ "golang.org/x/crypto/curve25519"
+
+ ocrconfighelper2 "github.com/smartcontractkit/libocr/offchainreporting2/confighelper"
+ ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2/types"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/client"
+ "github.com/smartcontractkit/chainlink/integration-tests/contracts"
+ "github.com/smartcontractkit/chainlink/integration-tests/wrappers"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_messenger"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_transmitter"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_v3_aggregator_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface"
+ type_and_version "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/type_and_version_interface_wrapper"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/erc20"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+ ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
+)
+
+// MatchContractVersionsOrAbove checks if the current contract versions for the test match or exceed the provided contract versions
+func MatchContractVersionsOrAbove(requiredContractVersions map[Name]Version) error {
+ for contractName, r := range requiredContractVersions {
+ required := r
+ if contractVersion, ok := VersionMap[contractName]; !ok {
+ return fmt.Errorf("contract %s not found in version map", contractName)
+ } else if contractVersion.Compare(&required.Version) < 0 {
+ return fmt.Errorf("contract %s version %s is less than required version %s", contractName, contractVersion, required.Version)
+ }
+ }
+ return nil
+}
+
+// NeedTokenAdminRegistry checks if token admin registry is needed for the current version of ccip
+// if the version is less than 1.5.0-dev, then token admin registry is not needed
+func NeedTokenAdminRegistry() bool {
+ return MatchContractVersionsOrAbove(map[Name]Version{
+ TokenPoolContract: V1_5_0_dev,
+ }) == nil
+}
+
+// CCIPContractsDeployer provides the implementations for deploying CCIP ETH contracts
+type CCIPContractsDeployer struct {
+ evmClient blockchain.EVMClient
+ logger *zerolog.Logger
+}
+
+// NewCCIPContractsDeployer returns an instance of a contract deployer for CCIP
+func NewCCIPContractsDeployer(logger *zerolog.Logger, bcClient blockchain.EVMClient) (*CCIPContractsDeployer, error) {
+ return &CCIPContractsDeployer{
+ evmClient: bcClient,
+ logger: logger,
+ }, nil
+}
+
+func (e *CCIPContractsDeployer) Client() blockchain.EVMClient {
+ return e.evmClient
+}
+
+func (e *CCIPContractsDeployer) DeployMultiCallContract() (common.Address, error) {
+ multiCallABI, err := abi.JSON(strings.NewReader(MultiCallABI))
+ if err != nil {
+ return common.Address{}, err
+ }
+ address, tx, _, err := e.evmClient.DeployContract("MultiCall Contract", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ address, tx, contract, err := bind.DeployContract(auth, multiCallABI, common.FromHex(MultiCallBIN), wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, contract, err
+ })
+ if err != nil {
+ return common.Address{}, err
+ }
+ r, err := bind.WaitMined(context.Background(), e.evmClient.DeployBackend(), tx)
+ if err != nil {
+ return common.Address{}, err
+ }
+ if r.Status != types.ReceiptStatusSuccessful {
+ return common.Address{}, fmt.Errorf("deploy multicall failed")
+ }
+ return *address, nil
+}
+
+func (e *CCIPContractsDeployer) DeployTokenMessenger(tokenTransmitter common.Address) (*common.Address, error) {
+ address, _, _, err := e.evmClient.DeployContract("Mock Token Messenger", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ address, tx, contract, err := mock_usdc_token_messenger.DeployMockE2EUSDCTokenMessenger(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil), 0, tokenTransmitter)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, contract, err
+ })
+
+ return address, err
+}
+
+func (e *CCIPContractsDeployer) NewTokenTransmitter(addr common.Address) (*TokenTransmitter, error) {
+ transmitter, err := mock_usdc_token_transmitter.NewMockE2EUSDCTransmitter(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "Mock USDC Token Transmitter").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &TokenTransmitter{
+ client: e.evmClient,
+ instance: transmitter,
+ ContractAddress: addr,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) DeployTokenTransmitter(domain uint32, usdcToken common.Address) (*TokenTransmitter, error) {
+ address, _, instance, err := e.evmClient.DeployContract("Mock Token Transmitter", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ address, tx, contract, err := mock_usdc_token_transmitter.DeployMockE2EUSDCTransmitter(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil), 0, domain, usdcToken)
+ if err != nil {
+ return common.Address{}, nil, nil, err
+ }
+ return address, tx, contract, err
+ })
+
+ if err != nil {
+ return nil, fmt.Errorf("error in deploying usdc token transmitter: %w", err)
+ }
+
+ return &TokenTransmitter{
+ client: e.evmClient,
+ instance: instance.(*mock_usdc_token_transmitter.MockE2EUSDCTransmitter),
+ ContractAddress: *address,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) DeployLinkTokenContract() (*LinkToken, error) {
+ address, _, instance, err := e.evmClient.DeployContract("Link Token", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return link_token_interface.DeployLinkToken(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ })
+
+ if err != nil {
+ return nil, err
+ }
+ return &LinkToken{
+ client: e.evmClient,
+ logger: e.logger,
+ instance: instance.(*link_token_interface.LinkToken),
+ EthAddress: *address,
+ }, err
+}
+
+// DeployBurnMintERC677 deploys a BurnMintERC677 contract, mints given amount ( if provided) to the owner address and returns the ERC20Token wrapper instance
+func (e *CCIPContractsDeployer) DeployBurnMintERC677(ownerMintingAmount *big.Int) (*ERC677Token, error) {
+ address, _, instance, err := e.evmClient.DeployContract("Burn Mint ERC 677", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return burn_mint_erc677.DeployBurnMintERC677(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil), "Test Token ERC677", "TERC677", 6, new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e9)))
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ token := &ERC677Token{
+ client: e.evmClient,
+ logger: e.logger,
+ ContractAddress: *address,
+ instance: instance.(*burn_mint_erc677.BurnMintERC677),
+ OwnerAddress: common.HexToAddress(e.evmClient.GetDefaultWallet().Address()),
+ OwnerWallet: e.evmClient.GetDefaultWallet(),
+ }
+ if ownerMintingAmount != nil {
+ // grant minter role to owner and mint tokens
+ err = token.GrantMintRole(common.HexToAddress(e.evmClient.GetDefaultWallet().Address()))
+ if err != nil {
+ return token, fmt.Errorf("granting minter role to owner shouldn't fail %w", err)
+ }
+ err = e.evmClient.WaitForEvents()
+ if err != nil {
+ return token, fmt.Errorf("error in waiting for granting mint role %w", err)
+ }
+ err = token.Mint(common.HexToAddress(e.evmClient.GetDefaultWallet().Address()), ownerMintingAmount)
+ if err != nil {
+ return token, fmt.Errorf("minting tokens shouldn't fail %w", err)
+ }
+ }
+ return token, err
+}
+
+func (e *CCIPContractsDeployer) DeployERC20TokenContract(deployerFn blockchain.ContractDeployer) (*ERC20Token, error) {
+ address, _, _, err := e.evmClient.DeployContract("Custom ERC20 Token", deployerFn)
+ if err != nil {
+ return nil, err
+ }
+ err = e.evmClient.WaitForEvents()
+ if err != nil {
+ return nil, err
+ }
+ return e.NewERC20TokenContract(*address)
+}
+
+func (e *CCIPContractsDeployer) NewLinkTokenContract(addr common.Address) (*LinkToken, error) {
+ token, err := link_token_interface.NewLinkToken(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "Link Token").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &LinkToken{
+ client: e.evmClient,
+ logger: e.logger,
+ instance: token,
+ EthAddress: addr,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) NewERC20TokenContract(addr common.Address) (*ERC20Token, error) {
+ token, err := erc20.NewERC20(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "ERC20 Token").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &ERC20Token{
+ client: e.evmClient,
+ logger: e.logger,
+ instance: token,
+ ContractAddress: addr,
+ OwnerAddress: common.HexToAddress(e.evmClient.GetDefaultWallet().Address()),
+ OwnerWallet: e.evmClient.GetDefaultWallet(),
+ }, err
+}
+
+func (e *CCIPContractsDeployer) NewLockReleaseTokenPoolContract(addr common.Address) (
+ *TokenPool,
+ error,
+) {
+ version := VersionMap[TokenPoolContract]
+ e.logger.Info().Str("Version", version.String()).Msg("New LockRelease Token Pool")
+ switch version {
+ case Latest:
+ pool, err := lock_release_token_pool.NewLockReleaseTokenPool(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "Native Token Pool").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ poolInstance, err := token_pool.NewTokenPool(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPool{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &TokenPoolWrapper{
+ Latest: &LatestPool{
+ PoolInterface: poolInstance,
+ LockReleasePool: pool,
+ },
+ },
+ EthAddress: addr,
+ OwnerAddress: common.HexToAddress(e.evmClient.GetDefaultWallet().Address()),
+ OwnerWallet: e.evmClient.GetDefaultWallet(),
+ }, err
+ case V1_4_0:
+ pool, err := lock_release_token_pool_1_4_0.NewLockReleaseTokenPool(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "Native Token Pool").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ poolInstance, err := token_pool_1_4_0.NewTokenPool(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPool{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &TokenPoolWrapper{
+ V1_4_0: &V1_4_0Pool{
+ PoolInterface: poolInstance,
+ LockReleasePool: pool,
+ },
+ },
+ EthAddress: addr,
+ OwnerAddress: common.HexToAddress(e.evmClient.GetDefaultWallet().Address()),
+ OwnerWallet: e.evmClient.GetDefaultWallet(),
+ }, err
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) NewUSDCTokenPoolContract(addr common.Address) (
+ *TokenPool,
+ error,
+) {
+ version := VersionMap[TokenPoolContract]
+ e.logger.Info().Str("Version", version.String()).Msg("New USDC Token Pool")
+ switch version {
+ case Latest:
+ pool, err := usdc_token_pool.NewUSDCTokenPool(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "USDC Token Pool").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ poolInterface, err := token_pool.NewTokenPool(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPool{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &TokenPoolWrapper{
+ Latest: &LatestPool{
+ PoolInterface: poolInterface,
+ USDCPool: pool,
+ },
+ },
+ EthAddress: addr,
+ OwnerAddress: common.HexToAddress(e.evmClient.GetDefaultWallet().Address()),
+ OwnerWallet: e.evmClient.GetDefaultWallet(),
+ }, err
+ case V1_4_0:
+ pool, err := usdc_token_pool_1_4_0.NewUSDCTokenPool(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "USDC Token Pool").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ poolInterface, err := token_pool_1_4_0.NewTokenPool(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ return &TokenPool{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &TokenPoolWrapper{
+ V1_4_0: &V1_4_0Pool{
+ PoolInterface: poolInterface,
+ USDCPool: pool,
+ },
+ },
+ EthAddress: addr,
+ OwnerAddress: common.HexToAddress(e.evmClient.GetDefaultWallet().Address()),
+ OwnerWallet: e.evmClient.GetDefaultWallet(),
+ }, err
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+
+}
+
+func (e *CCIPContractsDeployer) DeployUSDCTokenPoolContract(tokenAddr string, tokenMessenger, rmnProxy common.Address, router common.Address) (
+ *TokenPool,
+ error,
+) {
+ version := VersionMap[TokenPoolContract]
+ e.logger.Debug().Str("Token", tokenAddr).Msg("Deploying USDC token pool")
+ token := common.HexToAddress(tokenAddr)
+ switch version {
+ case Latest:
+ address, _, _, err := e.evmClient.DeployContract("USDC Token Pool", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return usdc_token_pool.DeployUSDCTokenPool(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ tokenMessenger,
+ token,
+ []common.Address{},
+ rmnProxy,
+ router,
+ )
+ })
+
+ if err != nil {
+ return nil, err
+ }
+ return e.NewUSDCTokenPoolContract(*address)
+ case V1_4_0:
+ address, _, _, err := e.evmClient.DeployContract("USDC Token Pool", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return usdc_token_pool_1_4_0.DeployUSDCTokenPool(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ tokenMessenger,
+ token,
+ []common.Address{},
+ rmnProxy,
+ router,
+ )
+ })
+
+ if err != nil {
+ return nil, err
+ }
+ return e.NewUSDCTokenPoolContract(*address)
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) DeployLockReleaseTokenPoolContract(tokenAddr string, rmnProxy common.Address, router common.Address) (
+ *TokenPool,
+ error,
+) {
+ version := VersionMap[TokenPoolContract]
+ e.logger.Info().Str("Version", version.String()).Msg("Deploying LockRelease Token Pool")
+ token := common.HexToAddress(tokenAddr)
+ switch version {
+ case Latest:
+ address, _, _, err := e.evmClient.DeployContract("LockRelease Token Pool", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return lock_release_token_pool.DeployLockReleaseTokenPool(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ token,
+ []common.Address{},
+ rmnProxy,
+ true,
+ router,
+ )
+ })
+
+ if err != nil {
+ return nil, err
+ }
+ return e.NewLockReleaseTokenPoolContract(*address)
+ case V1_4_0:
+ address, _, _, err := e.evmClient.DeployContract("LockRelease Token Pool", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return lock_release_token_pool_1_4_0.DeployLockReleaseTokenPool(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ token,
+ []common.Address{},
+ rmnProxy,
+ true,
+ router,
+ )
+ })
+
+ if err != nil {
+ return nil, err
+ }
+ return e.NewLockReleaseTokenPoolContract(*address)
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) DeployMockARMContract() (*common.Address, error) {
+ address, _, _, err := e.evmClient.DeployContract("Mock ARM Contract", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return mock_arm_contract.DeployMockARMContract(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ })
+ return address, err
+}
+
+func (e *CCIPContractsDeployer) NewARMContract(addr common.Address) (*ARM, error) {
+ arm, err := arm_contract.NewARMContract(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "Mock ARM Contract").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+
+ return &ARM{
+ client: e.evmClient,
+ Instance: arm,
+ EthAddress: addr,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) NewCommitStore(addr common.Address) (
+ *CommitStore,
+ error,
+) {
+ version := VersionMap[CommitStoreContract]
+ e.logger.Info().Str("Version", version.String()).Msg("New CommitStore")
+ switch version {
+ case Latest:
+ ins, err := commit_store.NewCommitStore(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "CommitStore").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &CommitStore{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &CommitStoreWrapper{
+ Latest: ins,
+ },
+ EthAddress: addr,
+ }, err
+ case V1_2_0:
+ ins, err := commit_store_1_2_0.NewCommitStore(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "CommitStore").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &CommitStore{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &CommitStoreWrapper{
+ V1_2_0: ins,
+ },
+ EthAddress: addr,
+ }, err
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) DeployCommitStore(sourceChainSelector, destChainSelector uint64, onRamp common.Address, armProxy common.Address) (*CommitStore, error) {
+ version, ok := VersionMap[CommitStoreContract]
+ if !ok {
+ return nil, fmt.Errorf("versioning not supported: %s", version)
+ }
+ e.logger.Info().Str("Version", version.String()).Msg("Deploying CommitStore")
+ switch version {
+ case Latest:
+ address, _, instance, err := e.evmClient.DeployContract("CommitStore Contract", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return commit_store.DeployCommitStore(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ commit_store.CommitStoreStaticConfig{
+ ChainSelector: destChainSelector,
+ SourceChainSelector: sourceChainSelector,
+ OnRamp: onRamp,
+ RmnProxy: armProxy,
+ },
+ )
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStore{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &CommitStoreWrapper{
+ Latest: instance.(*commit_store.CommitStore),
+ },
+ EthAddress: *address,
+ }, err
+ case V1_2_0:
+ address, _, instance, err := e.evmClient.DeployContract("CommitStore Contract", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return commit_store_1_2_0.DeployCommitStore(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ commit_store_1_2_0.CommitStoreStaticConfig{
+ ChainSelector: destChainSelector,
+ SourceChainSelector: sourceChainSelector,
+ OnRamp: onRamp,
+ ArmProxy: armProxy,
+ },
+ )
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &CommitStore{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &CommitStoreWrapper{
+ V1_2_0: instance.(*commit_store_1_2_0.CommitStore),
+ },
+ EthAddress: *address,
+ }, err
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) DeployReceiverDapp(revert bool) (
+ *ReceiverDapp,
+ error,
+) {
+ address, _, instance, err := e.evmClient.DeployContract("ReceiverDapp", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil), revert)
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &ReceiverDapp{
+ client: e.evmClient,
+ logger: e.logger,
+ instance: instance.(*maybe_revert_message_receiver.MaybeRevertMessageReceiver),
+ EthAddress: *address,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) NewReceiverDapp(addr common.Address) (
+ *ReceiverDapp,
+ error,
+) {
+ ins, err := maybe_revert_message_receiver.NewMaybeRevertMessageReceiver(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "ReceiverDapp").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &ReceiverDapp{
+ client: e.evmClient,
+ logger: e.logger,
+ instance: ins,
+ EthAddress: addr,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) DeployRouter(wrappedNative common.Address, armAddress common.Address) (
+ *Router,
+ error,
+) {
+ address, _, instance, err := e.evmClient.DeployContract("Router", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return router.DeployRouter(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil), wrappedNative, armAddress)
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &Router{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: instance.(*router.Router),
+ EthAddress: *address,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) NewRouter(addr common.Address) (
+ *Router,
+ error,
+) {
+ r, err := router.NewRouter(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "Router").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ if err != nil {
+ return nil, err
+ }
+ return &Router{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: r,
+ EthAddress: addr,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) NewPriceRegistry(addr common.Address) (
+ *PriceRegistry,
+ error,
+) {
+ var wrapper *PriceRegistryWrapper
+ version := VersionMap[PriceRegistryContract]
+ e.logger.Info().Str("Version", version.String()).Msg("New PriceRegistry")
+ switch version {
+ case Latest:
+ ins, err := price_registry_1_2_0.NewPriceRegistry(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, fmt.Errorf("error in creating price registry instance: %w", err)
+ }
+ wrapper = &PriceRegistryWrapper{
+ V1_2_0: ins,
+ }
+ case V1_2_0:
+ ins, err := price_registry_1_2_0.NewPriceRegistry(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, fmt.Errorf("error in creating price registry instance: %w", err)
+ }
+ wrapper = &PriceRegistryWrapper{
+ V1_2_0: ins,
+ }
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "PriceRegistry").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &PriceRegistry{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: wrapper,
+ EthAddress: addr,
+ }, nil
+}
+
+func (e *CCIPContractsDeployer) DeployPriceRegistry(tokens []common.Address) (*PriceRegistry, error) {
+ var address *common.Address
+ var wrapper *PriceRegistryWrapper
+ var err error
+ var instance interface{}
+ version := VersionMap[PriceRegistryContract]
+ e.logger.Info().Str("Version", version.String()).Msg("Deploying PriceRegistry")
+ switch version {
+ case Latest:
+ address, _, instance, err = e.evmClient.DeployContract("PriceRegistry", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return price_registry_1_2_0.DeployPriceRegistry(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil), nil, tokens, 60*60*24*14)
+ })
+ if err != nil {
+ return nil, err
+ }
+ wrapper = &PriceRegistryWrapper{
+ V1_2_0: instance.(*price_registry_1_2_0.PriceRegistry),
+ }
+ case V1_2_0:
+ address, _, instance, err = e.evmClient.DeployContract("PriceRegistry", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return price_registry_1_2_0.DeployPriceRegistry(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil), nil, tokens, 60*60*24*14)
+ })
+ if err != nil {
+ return nil, err
+ }
+ wrapper = &PriceRegistryWrapper{
+ V1_2_0: instance.(*price_registry_1_2_0.PriceRegistry),
+ }
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+ reg := &PriceRegistry{
+ client: e.evmClient,
+ logger: e.logger,
+ EthAddress: *address,
+ Instance: wrapper,
+ }
+ return reg, err
+}
+
+func (e *CCIPContractsDeployer) DeployTokenAdminRegistry() (*TokenAdminRegistry, error) {
+ address, _, instance, err := e.evmClient.DeployContract("TokenAdminRegistry", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return token_admin_registry.DeployTokenAdminRegistry(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &TokenAdminRegistry{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: instance.(*token_admin_registry.TokenAdminRegistry),
+ EthAddress: *address,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) NewTokenAdminRegistry(addr common.Address) (
+ *TokenAdminRegistry,
+ error,
+) {
+ ins, err := token_admin_registry.NewTokenAdminRegistry(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "TokenAdminRegistry").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &TokenAdminRegistry{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: ins,
+ EthAddress: addr,
+ }, err
+}
+
+func (e *CCIPContractsDeployer) NewOnRamp(addr common.Address) (
+ *OnRamp,
+ error,
+) {
+ version := VersionMap[OnRampContract]
+ e.logger.Info().Str("Version", version.String()).Msg("New OnRamp")
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "OnRamp").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ switch version {
+ case V1_2_0:
+ ins, err := evm_2_evm_onramp_1_2_0.NewEVM2EVMOnRamp(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ return &OnRamp{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &OnRampWrapper{V1_2_0: ins},
+ EthAddress: addr,
+ }, err
+ case Latest:
+ ins, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ return &OnRamp{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &OnRampWrapper{Latest: ins},
+ EthAddress: addr,
+ }, nil
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) DeployOnRamp(
+ sourceChainSelector, destChainSelector uint64,
+ tokensAndPools []evm_2_evm_onramp_1_2_0.InternalPoolUpdate,
+ rmn,
+ router,
+ priceRegistry,
+ tokenAdminRegistry common.Address,
+ opts RateLimiterConfig,
+ feeTokenConfig []evm_2_evm_onramp.EVM2EVMOnRampFeeTokenConfigArgs,
+ tokenTransferFeeConfig []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs,
+ linkTokenAddress common.Address,
+) (*OnRamp, error) {
+ version := VersionMap[OnRampContract]
+ e.logger.Info().Str("Version", version.String()).Msg("Deploying OnRamp")
+ switch version {
+ case V1_2_0:
+ feeTokenConfigV1_2_0 := make([]evm_2_evm_onramp_1_2_0.EVM2EVMOnRampFeeTokenConfigArgs, len(feeTokenConfig))
+ for i, f := range feeTokenConfig {
+ feeTokenConfigV1_2_0[i] = evm_2_evm_onramp_1_2_0.EVM2EVMOnRampFeeTokenConfigArgs{
+ Token: f.Token,
+ NetworkFeeUSDCents: f.NetworkFeeUSDCents,
+ GasMultiplierWeiPerEth: f.GasMultiplierWeiPerEth,
+ PremiumMultiplierWeiPerEth: f.PremiumMultiplierWeiPerEth,
+ Enabled: f.Enabled,
+ }
+ }
+ tokenTransferFeeConfigV1_2_0 := make([]evm_2_evm_onramp_1_2_0.EVM2EVMOnRampTokenTransferFeeConfigArgs, len(tokenTransferFeeConfig))
+ for i, f := range tokenTransferFeeConfig {
+ tokenTransferFeeConfigV1_2_0[i] = evm_2_evm_onramp_1_2_0.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ Token: f.Token,
+ MinFeeUSDCents: f.MinFeeUSDCents,
+ MaxFeeUSDCents: f.MaxFeeUSDCents,
+ DeciBps: f.DeciBps,
+ DestGasOverhead: f.DestGasOverhead,
+ DestBytesOverhead: f.DestBytesOverhead,
+ }
+ }
+ address, _, instance, err := e.evmClient.DeployContract("OnRamp", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return evm_2_evm_onramp_1_2_0.DeployEVM2EVMOnRamp(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ evm_2_evm_onramp_1_2_0.EVM2EVMOnRampStaticConfig{
+ LinkToken: linkTokenAddress,
+ ChainSelector: sourceChainSelector, // source chain id
+ DestChainSelector: destChainSelector, // destinationChainSelector
+ DefaultTxGasLimit: 200_000,
+ MaxNopFeesJuels: big.NewInt(0).Mul(big.NewInt(100_000_000), big.NewInt(1e18)),
+ PrevOnRamp: common.HexToAddress(""),
+ ArmProxy: rmn,
+ },
+ evm_2_evm_onramp_1_2_0.EVM2EVMOnRampDynamicConfig{
+ Router: router,
+ MaxNumberOfTokensPerMsg: 50,
+ DestGasOverhead: 350_000,
+ DestGasPerPayloadByte: 16,
+ DestDataAvailabilityOverheadGas: 33_596,
+ DestGasPerDataAvailabilityByte: 16,
+ DestDataAvailabilityMultiplierBps: 6840, // 0.684
+ PriceRegistry: priceRegistry,
+ MaxDataBytes: 50000,
+ MaxPerMsgGasLimit: 4_000_000,
+ },
+ tokensAndPools,
+ evm_2_evm_onramp_1_2_0.RateLimiterConfig{
+ Capacity: opts.Capacity,
+ Rate: opts.Rate,
+ },
+ feeTokenConfigV1_2_0,
+ tokenTransferFeeConfigV1_2_0,
+ []evm_2_evm_onramp_1_2_0.EVM2EVMOnRampNopAndWeight{},
+ )
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &OnRamp{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &OnRampWrapper{
+ V1_2_0: instance.(*evm_2_evm_onramp_1_2_0.EVM2EVMOnRamp),
+ },
+ EthAddress: *address,
+ }, nil
+ case Latest:
+ address, _, instance, err := e.evmClient.DeployContract("OnRamp", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return evm_2_evm_onramp.DeployEVM2EVMOnRamp(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ evm_2_evm_onramp.EVM2EVMOnRampStaticConfig{
+ LinkToken: linkTokenAddress,
+ ChainSelector: sourceChainSelector, // source chain id
+ DestChainSelector: destChainSelector, // destinationChainSelector
+ DefaultTxGasLimit: 200_000,
+ MaxNopFeesJuels: big.NewInt(0).Mul(big.NewInt(100_000_000), big.NewInt(1e18)),
+ PrevOnRamp: common.HexToAddress(""),
+ RmnProxy: rmn,
+ TokenAdminRegistry: tokenAdminRegistry,
+ },
+ evm_2_evm_onramp.EVM2EVMOnRampDynamicConfig{
+ Router: router,
+ MaxNumberOfTokensPerMsg: 50,
+ DestGasOverhead: 350_000,
+ DestGasPerPayloadByte: 16,
+ DestDataAvailabilityOverheadGas: 33_596,
+ DestGasPerDataAvailabilityByte: 16,
+ DestDataAvailabilityMultiplierBps: 6840, // 0.684
+ PriceRegistry: priceRegistry,
+ MaxDataBytes: 50000,
+ MaxPerMsgGasLimit: 4_000_000,
+ DefaultTokenFeeUSDCents: 50,
+ DefaultTokenDestGasOverhead: 125_000,
+ DefaultTokenDestBytesOverhead: 500,
+ },
+ evm_2_evm_onramp.RateLimiterConfig{
+ Capacity: opts.Capacity,
+ Rate: opts.Rate,
+ },
+ feeTokenConfig,
+ tokenTransferFeeConfig,
+ []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{},
+ )
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &OnRamp{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &OnRampWrapper{
+ Latest: instance.(*evm_2_evm_onramp.EVM2EVMOnRamp),
+ },
+ EthAddress: *address,
+ }, err
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) NewOffRamp(addr common.Address) (
+ *OffRamp,
+ error,
+) {
+ version := VersionMap[OffRampContract]
+ e.logger.Info().Str("Version", version.String()).Msg("New OffRamp")
+ switch version {
+ case V1_2_0:
+ ins, err := evm_2_evm_offramp_1_2_0.NewEVM2EVMOffRamp(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "OffRamp").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &OffRamp{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &OffRampWrapper{V1_2_0: ins},
+ EthAddress: addr,
+ }, err
+ case Latest:
+ ins, err := evm_2_evm_offramp.NewEVM2EVMOffRamp(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, err
+ }
+ e.logger.Info().
+ Str("Contract Address", addr.Hex()).
+ Str("Contract Name", "OffRamp").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &OffRamp{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &OffRampWrapper{Latest: ins},
+ EthAddress: addr,
+ }, err
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) DeployOffRamp(
+ sourceChainSelector, destChainSelector uint64,
+ commitStore, onRamp common.Address,
+ opts RateLimiterConfig,
+ sourceTokens, pools []common.Address,
+ rmnProxy common.Address,
+ tokenAdminRegistry common.Address,
+) (*OffRamp, error) {
+ version := VersionMap[OffRampContract]
+ e.logger.Info().Str("Version", version.String()).Msg("Deploying OffRamp")
+ switch version {
+ case V1_2_0:
+ address, _, instance, err := e.evmClient.DeployContract("OffRamp Contract", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return evm_2_evm_offramp_1_2_0.DeployEVM2EVMOffRamp(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ evm_2_evm_offramp_1_2_0.EVM2EVMOffRampStaticConfig{
+ CommitStore: commitStore,
+ ChainSelector: destChainSelector,
+ SourceChainSelector: sourceChainSelector,
+ OnRamp: onRamp,
+ PrevOffRamp: common.Address{},
+ ArmProxy: rmnProxy,
+ },
+ sourceTokens,
+ pools,
+ evm_2_evm_offramp_1_2_0.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: opts.Capacity,
+ Rate: opts.Rate,
+ },
+ )
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &OffRamp{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &OffRampWrapper{
+ V1_2_0: instance.(*evm_2_evm_offramp_1_2_0.EVM2EVMOffRamp),
+ },
+ EthAddress: *address,
+ }, err
+ case Latest:
+ staticConfig := evm_2_evm_offramp.EVM2EVMOffRampStaticConfig{
+ CommitStore: commitStore,
+ ChainSelector: destChainSelector,
+ SourceChainSelector: sourceChainSelector,
+ OnRamp: onRamp,
+ PrevOffRamp: common.Address{},
+ RmnProxy: rmnProxy,
+ TokenAdminRegistry: tokenAdminRegistry,
+ }
+ address, _, instance, err := e.evmClient.DeployContract("OffRamp Contract", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return evm_2_evm_offramp.DeployEVM2EVMOffRamp(
+ auth,
+ wrappers.MustNewWrappedContractBackend(e.evmClient, nil),
+ staticConfig,
+ evm_2_evm_offramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: opts.Capacity,
+ Rate: opts.Rate,
+ },
+ )
+ })
+ e.logger.Info().Msg(fmt.Sprintf("deploying offramp with static config: %+v", staticConfig))
+
+ if err != nil {
+ return nil, err
+ }
+ return &OffRamp{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: &OffRampWrapper{
+ Latest: instance.(*evm_2_evm_offramp.EVM2EVMOffRamp),
+ },
+ EthAddress: *address,
+ }, err
+ default:
+ return nil, fmt.Errorf("version not supported: %s", version)
+ }
+}
+
+func (e *CCIPContractsDeployer) DeployWrappedNative() (*common.Address, error) {
+ address, _, _, err := e.evmClient.DeployContract("WrappedNative", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return weth9.DeployWETH9(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ })
+ if err != nil {
+ return nil, err
+ }
+ return address, err
+}
+
+func (e *CCIPContractsDeployer) DeployMockAggregator(decimals uint8, initialAns *big.Int) (*MockAggregator, error) {
+ address, _, instance, err := e.evmClient.DeployContract("MockAggregator", func(
+ auth *bind.TransactOpts,
+ _ bind.ContractBackend,
+ ) (common.Address, *types.Transaction, interface{}, error) {
+ return mock_v3_aggregator_contract.DeployMockV3Aggregator(auth, wrappers.MustNewWrappedContractBackend(e.evmClient, nil), decimals, initialAns)
+ })
+ if err != nil {
+ return nil, fmt.Errorf("deploying mock aggregator: %w", err)
+ }
+ e.logger.Info().
+ Str("Contract Address", address.Hex()).
+ Str("Contract Name", "MockAggregator").
+ Str("From", e.evmClient.GetDefaultWallet().Address()).
+ Str("Network Name", e.evmClient.GetNetworkConfig().Name).
+ Msg("New contract")
+ return &MockAggregator{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: instance.(*mock_v3_aggregator_contract.MockV3Aggregator),
+ ContractAddress: *address,
+ }, nil
+}
+
+func (e *CCIPContractsDeployer) NewMockAggregator(addr common.Address) (*MockAggregator, error) {
+ ins, err := mock_v3_aggregator_contract.NewMockV3Aggregator(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return nil, fmt.Errorf("creating mock aggregator: %w", err)
+ }
+ return &MockAggregator{
+ client: e.evmClient,
+ logger: e.logger,
+ Instance: ins,
+ ContractAddress: addr,
+ }, nil
+}
+
+func (e *CCIPContractsDeployer) TypeAndVersion(addr common.Address) (string, error) {
+ tv, err := type_and_version.NewTypeAndVersionInterface(addr, wrappers.MustNewWrappedContractBackend(e.evmClient, nil))
+ if err != nil {
+ return "", err
+ }
+ tvStr, err := tv.TypeAndVersion(nil)
+ if err != nil {
+ return "", fmt.Errorf("error calling typeAndVersion on addr: %s %w", addr.Hex(), err)
+ }
+ e.logger.Info().
+ Str("TypeAndVersion", tvStr).
+ Str("Contract Address", addr.Hex()).
+ Msg("TypeAndVersion")
+
+ _, versionStr, err := ccipconfig.ParseTypeAndVersion(tvStr)
+ if err != nil {
+ return versionStr, err
+ }
+ v, err := semver.NewVersion(versionStr)
+ if err != nil {
+ return "", fmt.Errorf("failed parsing version %s: %w", versionStr, err)
+ }
+ return v.String(), nil
+}
+
+// OCR2ParamsForCommit and OCR2ParamsForExec -
+// These functions return the default OCR2 parameters for Commit and Exec respectively.
+// Refer to CommitOCRParams and ExecOCRParams in CCIPTestConfig located in testconfig/ccip.go to override these values with custom param values.
+func OCR2ParamsForCommit(blockTime time.Duration) contracts.OffChainAggregatorV2Config {
+ // slow blocktime chains like Ethereum
+ if blockTime >= 10*time.Second {
+ return contracts.OffChainAggregatorV2Config{
+ DeltaProgress: 2 * time.Minute,
+ DeltaResend: 5 * time.Second,
+ DeltaRound: 90 * time.Second,
+ DeltaGrace: 5 * time.Second,
+ DeltaStage: 60 * time.Second,
+ MaxDurationQuery: 100 * time.Millisecond,
+ MaxDurationObservation: 35 * time.Second,
+ MaxDurationReport: 10 * time.Second,
+ MaxDurationShouldAcceptFinalizedReport: 5 * time.Second,
+ MaxDurationShouldTransmitAcceptedReport: 10 * time.Second,
+ }
+ }
+ // fast blocktime chains like Avalanche
+ return contracts.OffChainAggregatorV2Config{
+ DeltaProgress: 2 * time.Minute,
+ DeltaResend: 5 * time.Second,
+ DeltaRound: 60 * time.Second,
+ DeltaGrace: 5 * time.Second,
+ DeltaStage: 25 * time.Second,
+ MaxDurationQuery: 100 * time.Millisecond,
+ MaxDurationObservation: 35 * time.Second,
+ MaxDurationReport: 10 * time.Second,
+ MaxDurationShouldAcceptFinalizedReport: 5 * time.Second,
+ MaxDurationShouldTransmitAcceptedReport: 10 * time.Second,
+ }
+}
+
+func OCR2ParamsForExec(blockTime time.Duration) contracts.OffChainAggregatorV2Config {
+ // slow blocktime chains like Ethereum
+ if blockTime >= 10*time.Second {
+ return contracts.OffChainAggregatorV2Config{
+ DeltaProgress: 2 * time.Minute,
+ DeltaResend: 5 * time.Second,
+ DeltaRound: 90 * time.Second,
+ DeltaGrace: 5 * time.Second,
+ DeltaStage: 60 * time.Second,
+ MaxDurationQuery: 100 * time.Millisecond,
+ MaxDurationObservation: 35 * time.Second,
+ MaxDurationReport: 10 * time.Second,
+ MaxDurationShouldAcceptFinalizedReport: 5 * time.Second,
+ MaxDurationShouldTransmitAcceptedReport: 10 * time.Second,
+ }
+ }
+ // fast blocktime chains like Avalanche
+ return contracts.OffChainAggregatorV2Config{
+ DeltaProgress: 120 * time.Second,
+ DeltaResend: 5 * time.Second,
+ DeltaRound: 30 * time.Second,
+ DeltaGrace: 5 * time.Second,
+ DeltaStage: 10 * time.Second,
+ MaxDurationQuery: 100 * time.Millisecond,
+ MaxDurationObservation: 35 * time.Second,
+ MaxDurationReport: 10 * time.Second,
+ MaxDurationShouldAcceptFinalizedReport: 5 * time.Second,
+ MaxDurationShouldTransmitAcceptedReport: 10 * time.Second,
+ }
+}
+
+func OffChainAggregatorV2ConfigWithNodes(numberNodes int, inflightExpiry time.Duration, cfg contracts.OffChainAggregatorV2Config) contracts.OffChainAggregatorV2Config {
+ if numberNodes <= 4 {
+ log.Err(fmt.Errorf("insufficient number of nodes (%d) supplied for OCR, need at least 5", numberNodes)).
+ Int("Number Chainlink Nodes", numberNodes).
+ Msg("You likely need more chainlink nodes to properly configure OCR, try 5 or more.")
+ }
+ s := make([]int, 0)
+ for i := 0; i < numberNodes; i++ {
+ s = append(s, 1)
+ }
+ faultyNodes := 0
+ if numberNodes > 1 {
+ faultyNodes = (numberNodes - 1) / 3
+ }
+ if faultyNodes == 0 {
+ faultyNodes = 1
+ }
+ if cfg.DeltaStage == 0 {
+ cfg.DeltaStage = inflightExpiry
+ }
+ return contracts.OffChainAggregatorV2Config{
+ DeltaProgress: cfg.DeltaProgress,
+ DeltaResend: cfg.DeltaResend,
+ DeltaRound: cfg.DeltaRound,
+ DeltaGrace: cfg.DeltaGrace,
+ DeltaStage: cfg.DeltaStage,
+ RMax: 3,
+ S: s,
+ F: faultyNodes,
+ Oracles: []ocrconfighelper2.OracleIdentityExtra{},
+ MaxDurationQuery: cfg.MaxDurationQuery,
+ MaxDurationObservation: cfg.MaxDurationObservation,
+ MaxDurationReport: cfg.MaxDurationReport,
+ MaxDurationShouldAcceptFinalizedReport: cfg.MaxDurationShouldAcceptFinalizedReport,
+ MaxDurationShouldTransmitAcceptedReport: cfg.MaxDurationShouldTransmitAcceptedReport,
+ OnchainConfig: []byte{},
+ }
+}
+
+func stripKeyPrefix(key string) string {
+ chunks := strings.Split(key, "_")
+ if len(chunks) == 3 {
+ return chunks[2]
+ }
+ return key
+}
+
+func NewCommitOffchainConfig(
+ GasPriceHeartBeat config.Duration,
+ DAGasPriceDeviationPPB uint32,
+ ExecGasPriceDeviationPPB uint32,
+ TokenPriceHeartBeat config.Duration,
+ TokenPriceDeviationPPB uint32,
+ InflightCacheExpiry config.Duration,
+ _ bool, // TODO: priceReportingDisabled added after this merge
+) (ccipconfig.OffchainConfig, error) {
+ switch VersionMap[CommitStoreContract] {
+ case Latest:
+ return testhelpers.NewCommitOffchainConfig(
+ GasPriceHeartBeat,
+ DAGasPriceDeviationPPB,
+ ExecGasPriceDeviationPPB,
+ TokenPriceHeartBeat,
+ TokenPriceDeviationPPB,
+ InflightCacheExpiry,
+ ), nil
+ case V1_2_0:
+ return testhelpers_1_4_0.NewCommitOffchainConfig(
+ GasPriceHeartBeat,
+ DAGasPriceDeviationPPB,
+ ExecGasPriceDeviationPPB,
+ TokenPriceHeartBeat,
+ TokenPriceDeviationPPB,
+ InflightCacheExpiry,
+ ), nil
+ default:
+ return nil, fmt.Errorf("version not supported: %s", VersionMap[CommitStoreContract])
+ }
+}
+
+func NewCommitOnchainConfig(
+ PriceRegistry common.Address,
+) (abihelpers.AbiDefined, error) {
+ switch VersionMap[CommitStoreContract] {
+ case Latest:
+ return testhelpers.NewCommitOnchainConfig(PriceRegistry), nil
+ case V1_2_0:
+ return testhelpers_1_4_0.NewCommitOnchainConfig(PriceRegistry), nil
+ default:
+ return nil, fmt.Errorf("version not supported: %s", VersionMap[CommitStoreContract])
+ }
+}
+
+func NewExecOnchainConfig(
+ PermissionLessExecutionThresholdSeconds uint32,
+ Router common.Address,
+ PriceRegistry common.Address,
+ MaxNumberOfTokensPerMsg uint16,
+ MaxDataBytes uint32,
+ MaxPoolReleaseOrMintGas uint32,
+) (abihelpers.AbiDefined, error) {
+ switch VersionMap[OffRampContract] {
+ case Latest:
+ return testhelpers.NewExecOnchainConfig(
+ PermissionLessExecutionThresholdSeconds,
+ Router,
+ PriceRegistry,
+ MaxNumberOfTokensPerMsg,
+ MaxDataBytes,
+ MaxPoolReleaseOrMintGas, // TODO: obsolete soon after this merge
+ 50_000, // TODO: MaxTokenTransferGas, obsolete soon after this merge
+ ), nil
+ case V1_2_0:
+ return testhelpers_1_4_0.NewExecOnchainConfig(
+ PermissionLessExecutionThresholdSeconds,
+ Router,
+ PriceRegistry,
+ MaxNumberOfTokensPerMsg,
+ MaxDataBytes,
+ MaxPoolReleaseOrMintGas,
+ ), nil
+ default:
+ return nil, fmt.Errorf("version not supported: %s", VersionMap[OffRampContract])
+ }
+}
+
+func NewExecOffchainConfig(
+ destOptimisticConfirmations uint32,
+ batchGasLimit uint32,
+ relativeBoostPerWaitHour float64,
+ inflightCacheExpiry config.Duration,
+ rootSnoozeTime config.Duration,
+) (ccipconfig.OffchainConfig, error) {
+ switch VersionMap[OffRampContract] {
+ case Latest:
+ return testhelpers.NewExecOffchainConfig(
+ destOptimisticConfirmations,
+ batchGasLimit,
+ relativeBoostPerWaitHour,
+ inflightCacheExpiry,
+ rootSnoozeTime,
+ ), nil
+ case V1_2_0:
+ return testhelpers_1_4_0.NewExecOffchainConfig(
+ destOptimisticConfirmations,
+ batchGasLimit,
+ relativeBoostPerWaitHour,
+ inflightCacheExpiry,
+ rootSnoozeTime,
+ ), nil
+ default:
+ return nil, fmt.Errorf("version not supported: %s", VersionMap[OffRampContract])
+ }
+}
+
+func NewOffChainAggregatorV2ConfigForCCIPPlugin[T ccipconfig.OffchainConfig](
+ nodes []*client.CLNodesWithKeys,
+ offchainCfg T,
+ onchainCfg abihelpers.AbiDefined,
+ ocr2Params contracts.OffChainAggregatorV2Config,
+ inflightExpiry time.Duration,
+) (
+ signers []common.Address,
+ transmitters []common.Address,
+ f_ uint8,
+ onchainConfig_ []byte,
+ offchainConfigVersion uint64,
+ offchainConfig []byte,
+ err error,
+) {
+ oracleIdentities := make([]ocrconfighelper2.OracleIdentityExtra, 0)
+ ocrConfig := OffChainAggregatorV2ConfigWithNodes(len(nodes), inflightExpiry, ocr2Params)
+ var onChainKeys []ocrtypes2.OnchainPublicKey
+ for i, nodeWithKeys := range nodes {
+ ocr2Key := nodeWithKeys.KeysBundle.OCR2Key.Data
+ offChainPubKeyTemp, err := hex.DecodeString(stripKeyPrefix(ocr2Key.Attributes.OffChainPublicKey))
+ if err != nil {
+ return nil, nil, 0, nil, 0, nil, err
+ }
+ formattedOnChainPubKey := stripKeyPrefix(ocr2Key.Attributes.OnChainPublicKey)
+ cfgPubKeyTemp, err := hex.DecodeString(stripKeyPrefix(ocr2Key.Attributes.ConfigPublicKey))
+ if err != nil {
+ return nil, nil, 0, nil, 0, nil, err
+ }
+ cfgPubKeyBytes := [ed25519.PublicKeySize]byte{}
+ copy(cfgPubKeyBytes[:], cfgPubKeyTemp)
+ offChainPubKey := [curve25519.PointSize]byte{}
+ copy(offChainPubKey[:], offChainPubKeyTemp)
+ ethAddress := nodeWithKeys.KeysBundle.EthAddress
+ p2pKeys := nodeWithKeys.KeysBundle.P2PKeys
+ peerID := p2pKeys.Data[0].Attributes.PeerID
+ oracleIdentities = append(oracleIdentities, ocrconfighelper2.OracleIdentityExtra{
+ OracleIdentity: ocrconfighelper2.OracleIdentity{
+ OffchainPublicKey: offChainPubKey,
+ OnchainPublicKey: common.HexToAddress(formattedOnChainPubKey).Bytes(),
+ PeerID: peerID,
+ TransmitAccount: ocrtypes2.Account(ethAddress),
+ },
+ ConfigEncryptionPublicKey: cfgPubKeyBytes,
+ })
+ onChainKeys = append(onChainKeys, oracleIdentities[i].OnchainPublicKey)
+ transmitters = append(transmitters, common.HexToAddress(ethAddress))
+ }
+ signers, err = evm.OnchainPublicKeyToAddress(onChainKeys)
+ if err != nil {
+ return nil, nil, 0, nil, 0, nil, err
+ }
+ ocrConfig.Oracles = oracleIdentities
+ ocrConfig.ReportingPluginConfig, err = ccipconfig.EncodeOffchainConfig(offchainCfg)
+ if err != nil {
+ return nil, nil, 0, nil, 0, nil, err
+ }
+ ocrConfig.OnchainConfig, err = abihelpers.EncodeAbiStruct(onchainCfg)
+ if err != nil {
+ return nil, nil, 0, nil, 0, nil, err
+ }
+
+ _, _, f_, onchainConfig_, offchainConfigVersion, offchainConfig, err = ocrconfighelper2.ContractSetConfigArgsForTests(
+ ocrConfig.DeltaProgress,
+ ocrConfig.DeltaResend,
+ ocrConfig.DeltaRound,
+ ocrConfig.DeltaGrace,
+ ocrConfig.DeltaStage,
+ ocrConfig.RMax,
+ ocrConfig.S,
+ ocrConfig.Oracles,
+ ocrConfig.ReportingPluginConfig,
+ ocrConfig.MaxDurationQuery,
+ ocrConfig.MaxDurationObservation,
+ ocrConfig.MaxDurationReport,
+ ocrConfig.MaxDurationShouldAcceptFinalizedReport,
+ ocrConfig.MaxDurationShouldTransmitAcceptedReport,
+ ocrConfig.F,
+ ocrConfig.OnchainConfig,
+ )
+ return
+}
diff --git a/integration-tests/ccip-tests/contracts/contract_models.go b/integration-tests/ccip-tests/contracts/contract_models.go
new file mode 100644
index 00000000000..7008d51b622
--- /dev/null
+++ b/integration-tests/ccip-tests/contracts/contract_models.go
@@ -0,0 +1,2247 @@
+package contracts
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/AlekSi/pointer"
+ "github.com/Masterminds/semver/v3"
+ "github.com/ethereum/go-ethereum/accounts/abi/bind"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/rs/zerolog"
+ "golang.org/x/exp/rand"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/wrappers"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_arm_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_transmitter"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_v3_aggregator_contract"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_2_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool_1_4_0"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/erc20"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
+)
+
+type LogInfo struct {
+ BlockNumber uint64
+ TxHash common.Hash
+}
+
+// Name denotes a contract name
+type Name string
+
+// Version wraps a semver.Version object to provide some custom unmarshalling
+type Version struct {
+ semver.Version
+}
+
+// GasUpdateEvent holds the event details of Gas price update
+type GasUpdateEvent struct {
+ Sender string
+ Tx string
+ Value *big.Int
+ DestChain uint64
+ Source string
+}
+
+// MustVersion creates a new Version object from a semver string and panics if it fails
+func MustVersion(version string) Version {
+ v := semver.MustParse(version)
+ return Version{Version: *v}
+}
+
+// UnmarshalTOML unmarshals TOML data into a Version object
+func (v *Version) UnmarshalText(data []byte) error {
+ str := strings.Trim(string(data), `"`)
+ str = strings.Trim(str, `'`)
+ if strings.ToLower(str) == "latest" {
+ *v = Latest
+ return nil
+ }
+ ver, err := semver.NewVersion(str)
+ if err != nil {
+ return fmt.Errorf("failed to parse version from '%s': %w", str, err)
+ }
+ v.Version = *ver
+ return nil
+}
+
+// Latest returns true if the version is the latest version
+func (v *Version) Latest() bool {
+ return v.Version.Equal(&Latest.Version)
+}
+
+const (
+ Network = "Network Name"
+ PriceRegistryContract Name = "PriceRegistry"
+ OffRampContract Name = "OffRamp"
+ OnRampContract Name = "OnRamp"
+ TokenPoolContract Name = "TokenPool"
+ CommitStoreContract Name = "CommitStore"
+
+ defaultDestByteOverhead = uint32(32)
+ defaultDestGasOverhead = uint32(125_000)
+)
+
+var (
+ V1_2_0 = MustVersion("1.2.0")
+ V1_4_0 = MustVersion("1.4.0")
+ V1_5_0_dev = MustVersion("1.5.0-dev")
+ LatestPoolVersion = V1_5_0_dev
+ Latest = V1_5_0_dev
+ VersionMap = map[Name]Version{
+ PriceRegistryContract: V1_2_0,
+ OffRampContract: Latest,
+ OnRampContract: Latest,
+ CommitStoreContract: Latest,
+ TokenPoolContract: Latest,
+ }
+ SupportedContracts = map[Name]map[string]bool{
+ PriceRegistryContract: {
+ Latest.String(): true,
+ V1_2_0.String(): true,
+ },
+ OffRampContract: {
+ Latest.String(): true,
+ V1_2_0.String(): true,
+ },
+ OnRampContract: {
+ Latest.String(): true,
+ V1_2_0.String(): true,
+ },
+ CommitStoreContract: {
+ Latest.String(): true,
+ V1_2_0.String(): true,
+ },
+ TokenPoolContract: {
+ Latest.String(): true,
+ V1_4_0.String(): true,
+ },
+ }
+
+ FiftyCoins = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(50))
+ HundredCoins = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(100))
+)
+
+// CheckVersionSupported checks if a given version is supported for a given contract
+func CheckVersionSupported(name Name, version Version) error {
+ if contract, ok := SupportedContracts[name]; ok {
+ if isSupported, ok := contract[version.String()]; ok {
+ if isSupported {
+ return nil
+ }
+ return fmt.Errorf("version %s is not supported for contract %s", version.String(), name)
+ }
+ return fmt.Errorf("version %s is not supported for contract %s", version.String(), name)
+ }
+ return fmt.Errorf("contract %s is not supported", name)
+}
+
+type RateLimiterConfig struct {
+ IsEnabled bool
+ Rate *big.Int
+ Capacity *big.Int
+ Tokens *big.Int
+}
+
+type ARMConfig struct {
+ ARMWeightsByParticipants map[string]*big.Int // mapping : ARM participant address => weight
+ ThresholdForBlessing *big.Int
+ ThresholdForBadSignal *big.Int
+}
+
+type TokenTransmitter struct {
+ client blockchain.EVMClient
+ instance *mock_usdc_token_transmitter.MockE2EUSDCTransmitter
+ ContractAddress common.Address
+}
+
+type ERC677Token struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ instance *burn_mint_erc677.BurnMintERC677
+ ContractAddress common.Address
+ OwnerAddress common.Address
+ OwnerWallet *blockchain.EthereumWallet
+}
+
+func (token *ERC677Token) GrantMintAndBurn(burnAndMinter common.Address) error {
+ opts, err := token.client.TransactionOpts(token.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ token.logger.Info().
+ Str(Network, token.client.GetNetworkName()).
+ Str("BurnAndMinter", burnAndMinter.Hex()).
+ Str("Token", token.ContractAddress.Hex()).
+ Msg("Granting mint and burn roles")
+ tx, err := token.instance.GrantMintAndBurnRoles(opts, burnAndMinter)
+ if err != nil {
+ return fmt.Errorf("failed to grant mint and burn roles: %w", err)
+ }
+ return token.client.ProcessTransaction(tx)
+}
+
+func (token *ERC677Token) GrantMintRole(minter common.Address) error {
+ opts, err := token.client.TransactionOpts(token.OwnerWallet)
+ if err != nil {
+ return err
+ }
+ token.logger.Info().
+ Str(Network, token.client.GetNetworkName()).
+ Str("Minter", minter.Hex()).
+ Str("Token", token.ContractAddress.Hex()).
+ Msg("Granting mint roles")
+ tx, err := token.instance.GrantMintRole(opts, minter)
+ if err != nil {
+ return fmt.Errorf("failed to grant mint role: %w", err)
+ }
+ return token.client.ProcessTransaction(tx)
+}
+
+func (token *ERC677Token) Mint(to common.Address, amount *big.Int) error {
+ opts, err := token.client.TransactionOpts(token.OwnerWallet)
+ if err != nil {
+ return err
+ }
+ token.logger.Info().
+ Str(Network, token.client.GetNetworkName()).
+ Str("To", to.Hex()).
+ Str("Token", token.ContractAddress.Hex()).
+ Str("Amount", amount.String()).
+ Msg("Minting tokens")
+ tx, err := token.instance.Mint(opts, to, amount)
+ if err != nil {
+ return fmt.Errorf("failed to mint tokens: %w", err)
+ }
+ return token.client.ProcessTransaction(tx)
+}
+
+type ERC20Token struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ instance *erc20.ERC20
+ ContractAddress common.Address
+ OwnerAddress common.Address
+ OwnerWallet *blockchain.EthereumWallet
+}
+
+func (token *ERC20Token) Address() string {
+ return token.ContractAddress.Hex()
+}
+
+func (token *ERC20Token) BalanceOf(ctx context.Context, addr string) (*big.Int, error) {
+ opts := &bind.CallOpts{
+ From: common.HexToAddress(token.client.GetDefaultWallet().Address()),
+ Context: ctx,
+ }
+ balance, err := token.instance.BalanceOf(opts, common.HexToAddress(addr))
+ if err != nil {
+ return nil, fmt.Errorf("failed to get balance: %w", err)
+ }
+ return balance, nil
+}
+
+// Allowance returns the amount which spender is still allowed to withdraw from owner
+// https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20-allowance-address-address-
+func (token *ERC20Token) Allowance(owner, spender string) (*big.Int, error) {
+ allowance, err := token.instance.Allowance(nil, common.HexToAddress(owner), common.HexToAddress(spender))
+ if err != nil {
+ return nil, err
+ }
+ return allowance, nil
+}
+
+// Approve approves the spender to spend the given amount of tokens on behalf of another account
+// https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20-approve-address-uint256-
+func (token *ERC20Token) Approve(onBehalf *blockchain.EthereumWallet, spender string, amount *big.Int) error {
+ onBehalfBalance, err := token.BalanceOf(context.Background(), onBehalf.Address())
+ if err != nil {
+ return fmt.Errorf("failed to get balance of onBehalf: %w", err)
+ }
+ currentAllowance, err := token.Allowance(onBehalf.Address(), spender)
+ if err != nil {
+ return fmt.Errorf("failed to get current allowance for '%s' on behalf of '%s': %w", spender, onBehalf.Address(), err)
+ }
+ opts, err := token.client.TransactionOpts(onBehalf)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction options: %w", err)
+ }
+ log := token.logger.Info().
+ Str("On Behalf Of", onBehalf.Address()).
+ Str("On Behalf Of Balance", onBehalfBalance.String()).
+ Str("Spender", spender).
+ Str("Spender Current Allowance", currentAllowance.String()).
+ Str("Token", token.Address()).
+ Str("Amount", amount.String()).
+ Uint64("Nonce", opts.Nonce.Uint64()).
+ Str(Network, token.client.GetNetworkConfig().Name)
+ tx, err := token.instance.Approve(opts, common.HexToAddress(spender), amount)
+ if err != nil {
+ log.Err(err).Msg("Error Approving ERC20 Transfer")
+ return fmt.Errorf("failed to approve ERC20: %w", err)
+ }
+ log.Str("Hash", tx.Hash().Hex()).Msg("Approving ERC20 Transfer")
+ return token.client.ProcessTransaction(tx)
+}
+
+func (token *ERC20Token) Transfer(from *blockchain.EthereumWallet, to string, amount *big.Int) error {
+ opts, err := token.client.TransactionOpts(from)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction options: %w", err)
+ }
+ token.logger.Info().
+ Str("From", from.Address()).
+ Str("To", to).
+ Str("Amount", amount.String()).
+ Uint64("Nonce", opts.Nonce.Uint64()).
+ Str(Network, token.client.GetNetworkConfig().Name).
+ Msg("Transferring ERC20")
+ tx, err := token.instance.Transfer(opts, common.HexToAddress(to), amount)
+ if err != nil {
+ return fmt.Errorf("failed to transfer ERC20: %w", err)
+ }
+ return token.client.ProcessTransaction(tx)
+}
+
+type LinkToken struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ instance *link_token_interface.LinkToken
+ EthAddress common.Address
+}
+
+func (l *LinkToken) Address() string {
+ return l.EthAddress.Hex()
+}
+
+func (l *LinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) {
+ opts := &bind.CallOpts{
+ From: common.HexToAddress(l.client.GetDefaultWallet().Address()),
+ Context: ctx,
+ }
+ balance, err := l.instance.BalanceOf(opts, common.HexToAddress(addr))
+ if err != nil {
+ return nil, fmt.Errorf("failed to get LINK balance: %w", err)
+ }
+ return balance, nil
+}
+
+func (l *LinkToken) Allowance(owner, spender string) (*big.Int, error) {
+ allowance, err := l.instance.Allowance(nil, common.HexToAddress(owner), common.HexToAddress(spender))
+ if err != nil {
+ return nil, err
+ }
+ return allowance, nil
+}
+
+func (l *LinkToken) Approve(to string, amount *big.Int) error {
+ opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ l.logger.Info().
+ Str("From", l.client.GetDefaultWallet().Address()).
+ Str("To", to).
+ Str("Token", l.Address()).
+ Str("Amount", amount.String()).
+ Uint64("Nonce", opts.Nonce.Uint64()).
+ Str(Network, l.client.GetNetworkConfig().Name).
+ Msg("Approving LINK Transfer")
+ tx, err := l.instance.Approve(opts, common.HexToAddress(to), amount)
+ if err != nil {
+ return fmt.Errorf("failed to approve LINK transfer: %w", err)
+ }
+ return l.client.ProcessTransaction(tx)
+}
+
+func (l *LinkToken) Transfer(to string, amount *big.Int) error {
+ opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ l.logger.Info().
+ Str("From", l.client.GetDefaultWallet().Address()).
+ Str("To", to).
+ Str("Amount", amount.String()).
+ Uint64("Nonce", opts.Nonce.Uint64()).
+ Str(Network, l.client.GetNetworkConfig().Name).
+ Msg("Transferring LINK")
+ tx, err := l.instance.Transfer(opts, common.HexToAddress(to), amount)
+ if err != nil {
+ return fmt.Errorf("failed to transfer LINK: %w", err)
+ }
+ return l.client.ProcessTransaction(tx)
+}
+
+type LatestPool struct {
+ PoolInterface *token_pool.TokenPool
+ LockReleasePool *lock_release_token_pool.LockReleaseTokenPool
+ USDCPool *usdc_token_pool.USDCTokenPool
+}
+
+type V1_4_0Pool struct {
+ PoolInterface *token_pool_1_4_0.TokenPool
+ LockReleasePool *lock_release_token_pool_1_4_0.LockReleaseTokenPool
+ USDCPool *usdc_token_pool_1_4_0.USDCTokenPool
+}
+
+type TokenPoolWrapper struct {
+ Latest *LatestPool
+ V1_4_0 *V1_4_0Pool
+}
+
+func (w TokenPoolWrapper) SetRebalancer(opts *bind.TransactOpts, from common.Address) (*types.Transaction, error) {
+ if w.Latest != nil && w.Latest.LockReleasePool != nil {
+ return w.Latest.LockReleasePool.SetRebalancer(opts, from)
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.LockReleasePool != nil {
+ return w.V1_4_0.LockReleasePool.SetRebalancer(opts, from)
+ }
+ return nil, fmt.Errorf("no pool found to set rebalancer")
+}
+
+func (w TokenPoolWrapper) SetUSDCDomains(opts *bind.TransactOpts, updates []usdc_token_pool.USDCTokenPoolDomainUpdate) (*types.Transaction, error) {
+ if w.Latest != nil && w.Latest.USDCPool != nil {
+ return w.Latest.USDCPool.SetDomains(opts, updates)
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.USDCPool != nil {
+ V1_4_0Updates := make([]usdc_token_pool_1_4_0.USDCTokenPoolDomainUpdate, len(updates))
+ for i, update := range updates {
+ V1_4_0Updates[i] = usdc_token_pool_1_4_0.USDCTokenPoolDomainUpdate{
+ AllowedCaller: update.AllowedCaller,
+ DomainIdentifier: update.DomainIdentifier,
+ DestChainSelector: update.DestChainSelector,
+ Enabled: update.Enabled,
+ }
+ }
+ return w.V1_4_0.USDCPool.SetDomains(opts, V1_4_0Updates)
+ }
+ return nil, fmt.Errorf("no pool found to set USDC domains")
+}
+
+func (w TokenPoolWrapper) WithdrawLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ if w.Latest != nil && w.Latest.LockReleasePool != nil {
+ return w.Latest.LockReleasePool.WithdrawLiquidity(opts, amount)
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.LockReleasePool != nil {
+ return w.V1_4_0.LockReleasePool.WithdrawLiquidity(opts, amount)
+ }
+ return nil, fmt.Errorf("no pool found to withdraw liquidity")
+}
+
+func (w TokenPoolWrapper) ProvideLiquidity(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) {
+ if w.Latest != nil && w.Latest.LockReleasePool != nil {
+ return w.Latest.LockReleasePool.ProvideLiquidity(opts, amount)
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.LockReleasePool != nil {
+ return w.V1_4_0.LockReleasePool.ProvideLiquidity(opts, amount)
+ }
+ return nil, fmt.Errorf("no pool found to provide liquidity")
+}
+
+func (w TokenPoolWrapper) IsSupportedChain(opts *bind.CallOpts, remoteChainSelector uint64) (bool, error) {
+ if w.Latest != nil && w.Latest.PoolInterface != nil {
+ return w.Latest.PoolInterface.IsSupportedChain(opts, remoteChainSelector)
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.PoolInterface != nil {
+ return w.V1_4_0.PoolInterface.IsSupportedChain(opts, remoteChainSelector)
+ }
+ return false, fmt.Errorf("no pool found to check if chain is supported")
+}
+
+func (w TokenPoolWrapper) ApplyChainUpdates(opts *bind.TransactOpts, update []token_pool.TokenPoolChainUpdate) (*types.Transaction, error) {
+ if w.Latest != nil && w.Latest.PoolInterface != nil {
+ return w.Latest.PoolInterface.ApplyChainUpdates(opts, update)
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.PoolInterface != nil {
+ V1_4_0Updates := make([]token_pool_1_4_0.TokenPoolChainUpdate, len(update))
+ for i, u := range update {
+ V1_4_0Updates[i] = token_pool_1_4_0.TokenPoolChainUpdate{
+ RemoteChainSelector: u.RemoteChainSelector,
+ Allowed: u.Allowed,
+ InboundRateLimiterConfig: token_pool_1_4_0.RateLimiterConfig{
+ IsEnabled: u.InboundRateLimiterConfig.IsEnabled,
+ Capacity: u.InboundRateLimiterConfig.Capacity,
+ Rate: u.InboundRateLimiterConfig.Rate,
+ },
+ OutboundRateLimiterConfig: token_pool_1_4_0.RateLimiterConfig{
+ IsEnabled: u.OutboundRateLimiterConfig.IsEnabled,
+ Capacity: u.OutboundRateLimiterConfig.Capacity,
+ Rate: u.OutboundRateLimiterConfig.Rate,
+ },
+ }
+ }
+ return w.V1_4_0.PoolInterface.ApplyChainUpdates(opts, V1_4_0Updates)
+ }
+ return nil, fmt.Errorf("no pool found to apply chain updates")
+}
+
+func (w TokenPoolWrapper) SetChainRateLimiterConfig(opts *bind.TransactOpts, selector uint64, out token_pool.RateLimiterConfig, in token_pool.RateLimiterConfig) (*types.Transaction, error) {
+ if w.Latest != nil && w.Latest.PoolInterface != nil {
+ return w.Latest.PoolInterface.SetChainRateLimiterConfig(opts, selector, out, in)
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.PoolInterface != nil {
+ return w.V1_4_0.PoolInterface.SetChainRateLimiterConfig(opts, selector,
+ token_pool_1_4_0.RateLimiterConfig{
+ IsEnabled: out.IsEnabled,
+ Capacity: out.Capacity,
+ Rate: out.Rate,
+ }, token_pool_1_4_0.RateLimiterConfig{
+ IsEnabled: in.IsEnabled,
+ Capacity: in.Capacity,
+ Rate: in.Rate,
+ })
+ }
+ return nil, fmt.Errorf("no pool found to set chain rate limiter config")
+}
+
+func (w TokenPoolWrapper) GetCurrentOutboundRateLimiterState(opts *bind.CallOpts, selector uint64) (*RateLimiterConfig, error) {
+ if w.Latest != nil && w.Latest.PoolInterface != nil {
+ rl, err := w.Latest.PoolInterface.GetCurrentOutboundRateLimiterState(opts, selector)
+ if err != nil {
+ return nil, err
+ }
+ return &RateLimiterConfig{
+ IsEnabled: rl.IsEnabled,
+ Capacity: rl.Capacity,
+ Rate: rl.Rate,
+ Tokens: rl.Tokens,
+ }, nil
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.PoolInterface != nil {
+ rl, err := w.V1_4_0.PoolInterface.GetCurrentOutboundRateLimiterState(opts, selector)
+ if err != nil {
+ return nil, err
+ }
+ return &RateLimiterConfig{
+ IsEnabled: rl.IsEnabled,
+ Capacity: rl.Capacity,
+ Rate: rl.Rate,
+ Tokens: rl.Tokens,
+ }, nil
+ }
+ return nil, fmt.Errorf("no pool found to get current outbound rate limiter state")
+}
+
+func (w TokenPoolWrapper) GetCurrentInboundRateLimiterState(opts *bind.CallOpts, selector uint64) (*RateLimiterConfig, error) {
+ if w.Latest != nil && w.Latest.PoolInterface != nil {
+ rl, err := w.Latest.PoolInterface.GetCurrentInboundRateLimiterState(opts, selector)
+ if err != nil {
+ return nil, err
+ }
+ return &RateLimiterConfig{
+ IsEnabled: rl.IsEnabled,
+ Capacity: rl.Capacity,
+ Rate: rl.Rate,
+ Tokens: rl.Tokens,
+ }, nil
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.PoolInterface != nil {
+ rl, err := w.V1_4_0.PoolInterface.GetCurrentInboundRateLimiterState(opts, selector)
+ if err != nil {
+ return nil, err
+ }
+ return &RateLimiterConfig{
+ IsEnabled: rl.IsEnabled,
+ Capacity: rl.Capacity,
+ Rate: rl.Rate,
+ Tokens: rl.Tokens,
+ }, nil
+ }
+ return nil, fmt.Errorf("no pool found to get current outbound rate limiter state")
+}
+
+func (w TokenPoolWrapper) SetRouter(opts *bind.TransactOpts, routerAddr common.Address) (*types.Transaction, error) {
+ if w.Latest != nil && w.Latest.PoolInterface != nil {
+ return w.Latest.PoolInterface.SetRouter(opts, routerAddr)
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.PoolInterface != nil {
+ return w.V1_4_0.PoolInterface.SetRouter(opts, routerAddr)
+ }
+ return nil, fmt.Errorf("no pool found to set router")
+}
+
+func (w TokenPoolWrapper) GetRouter(opts *bind.CallOpts) (common.Address, error) {
+ if w.Latest != nil && w.Latest.PoolInterface != nil {
+ addr, err := w.Latest.PoolInterface.GetRouter(opts)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return addr, nil
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.PoolInterface != nil {
+ addr, err := w.V1_4_0.PoolInterface.GetRouter(opts)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return addr, nil
+ }
+ return common.Address{}, fmt.Errorf("no pool found to get router")
+}
+
+func (w TokenPoolWrapper) GetRebalancer(opts *bind.CallOpts) (common.Address, error) {
+ if w.Latest != nil && w.Latest.LockReleasePool != nil {
+ addr, err := w.Latest.LockReleasePool.GetRebalancer(opts)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return addr, nil
+ }
+ if w.V1_4_0 != nil && w.V1_4_0.LockReleasePool != nil {
+ addr, err := w.V1_4_0.LockReleasePool.GetRebalancer(opts)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return addr, nil
+ }
+ return common.Address{}, fmt.Errorf("no pool found to get rebalancer")
+}
+
+// TokenPool represents a TokenPool address
+type TokenPool struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ Instance *TokenPoolWrapper
+ EthAddress common.Address
+ OwnerAddress common.Address
+ OwnerWallet *blockchain.EthereumWallet
+}
+
+func (pool *TokenPool) Address() string {
+ return pool.EthAddress.Hex()
+}
+
+func (pool *TokenPool) IsUSDC() bool {
+ if pool.Instance.Latest != nil && pool.Instance.Latest.USDCPool != nil {
+ return true
+ }
+ if pool.Instance.V1_4_0 != nil && pool.Instance.V1_4_0.USDCPool != nil {
+ return true
+ }
+ return false
+}
+
+func (pool *TokenPool) IsLockRelease() bool {
+ if pool.Instance.Latest != nil && pool.Instance.Latest.LockReleasePool != nil {
+ return true
+ }
+ if pool.Instance.V1_4_0 != nil && pool.Instance.V1_4_0.LockReleasePool != nil {
+ return true
+ }
+ return false
+}
+
+func (pool *TokenPool) SyncUSDCDomain(destTokenTransmitter *TokenTransmitter, destPoolAddr common.Address, destChainSelector uint64) error {
+ if !pool.IsUSDC() {
+ return fmt.Errorf("pool is not a USDC pool, cannot sync domain")
+ }
+
+ var allowedCallerBytes [32]byte
+ copy(allowedCallerBytes[12:], destPoolAddr.Bytes())
+ destTokenTransmitterIns, err := mock_usdc_token_transmitter.NewMockE2EUSDCTransmitter(
+ destTokenTransmitter.ContractAddress, destTokenTransmitter.client.Backend(),
+ )
+ if err != nil {
+ return fmt.Errorf("failed to create mock USDC token transmitter: %w", err)
+ }
+ domain, err := destTokenTransmitterIns.LocalDomain(nil)
+ if err != nil {
+ return fmt.Errorf("failed to get local domain: %w", err)
+ }
+ opts, err := pool.client.TransactionOpts(pool.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str("From", pool.OwnerAddress.Hex()).
+ Str(Network, pool.client.GetNetworkName()).
+ Uint32("Domain", domain).
+ Str("Allowed Caller", destPoolAddr.Hex()).
+ Str("Dest Chain Selector", fmt.Sprintf("%d", destChainSelector)).
+ Msg("Syncing USDC Domain")
+ tx, err := pool.Instance.SetUSDCDomains(opts, []usdc_token_pool.USDCTokenPoolDomainUpdate{
+ {
+ AllowedCaller: allowedCallerBytes,
+ DomainIdentifier: domain,
+ DestChainSelector: destChainSelector,
+ Enabled: true,
+ },
+ })
+ if err != nil {
+ return fmt.Errorf("failed to set domain: %w", err)
+ }
+ return pool.client.ProcessTransaction(tx)
+}
+
+// MintUSDCToUSDCPool mints 100 USDC tokens to the pool if it is a USDC pool.
+// This helps provide liquidity to the pool which is necessary for USDC tests to function properly.
+func (pool *TokenPool) MintUSDCToUSDCPool() error {
+ if !pool.IsUSDC() {
+ return fmt.Errorf("pool is not a USDC pool, cannot send USDC")
+ }
+ usdcToken, err := pool.GetToken()
+ if err != nil {
+ return fmt.Errorf("failed to get dest usdc token: %w", err)
+ }
+ usdcInstance, err := burn_mint_erc677.NewBurnMintERC677(usdcToken, pool.client.Backend())
+ if err != nil {
+ return fmt.Errorf("failed to get dest usdc token instance: %w", err)
+ }
+
+ opts, err := pool.client.TransactionOpts(pool.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+
+ tx, err := usdcInstance.Mint(opts, pool.EthAddress, HundredCoins)
+ if err != nil {
+ return fmt.Errorf("failed to mint usdc tokens to destPool: %w", err)
+ }
+ return pool.client.ProcessTransaction(tx)
+}
+
+func (pool *TokenPool) RemoveLiquidity(amount *big.Int) error {
+ if !pool.IsLockRelease() {
+ return fmt.Errorf("pool is not a lock release pool, cannot remove liquidity")
+ }
+ opts, err := pool.client.TransactionOpts(pool.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str("Amount", amount.String()).
+ Msg("Initiating removing funds from pool")
+ tx, err := pool.Instance.WithdrawLiquidity(opts, amount)
+ if err != nil {
+ return fmt.Errorf("failed to withdraw liquidity: %w", err)
+ }
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str("Amount", amount.String()).
+ Str(Network, pool.client.GetNetworkConfig().Name).
+ Msg("Liquidity removed")
+ return pool.client.ProcessTransaction(tx)
+}
+
+// AddLiquidity approves the token pool to spend the given amount of tokens from the given wallet
+func (pool *TokenPool) AddLiquidity(token *ERC20Token, fromWallet *blockchain.EthereumWallet, amount *big.Int) error {
+ if !pool.IsLockRelease() {
+ return fmt.Errorf("pool is not a lock release pool, cannot add liquidity")
+ }
+ pool.logger.Info().
+ Str("Token", token.Address()).
+ Str("Token Pool", pool.Address()).
+ Msg("Initiating adding liquidity to token pool")
+ err := token.Approve(fromWallet, pool.Address(), amount)
+ if err != nil {
+ return fmt.Errorf("failed to approve token transfer: %w", err)
+ }
+ err = pool.client.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("failed to wait for events: %w", err)
+ }
+ opts, err := pool.client.TransactionOpts(pool.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ _, err = pool.Instance.SetRebalancer(opts, opts.From)
+ if err != nil {
+ return fmt.Errorf("failed to set rebalancer: %w", err)
+ }
+ opts, err = pool.client.TransactionOpts(pool.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Msg("Initiating adding Tokens in pool")
+ tx, err := pool.Instance.ProvideLiquidity(opts, amount)
+ if err != nil {
+ return fmt.Errorf("failed to provide liquidity: %w", err)
+ }
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str("Token", token.Address()).
+ Str(Network, pool.client.GetNetworkConfig().Name).
+ Msg("Liquidity added")
+ return pool.client.ProcessTransaction(tx)
+}
+
+func (pool *TokenPool) SetRemoteChainOnPool(remoteChainSelector uint64, remotePoolAddresses common.Address, remoteTokenAddress common.Address) error {
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Msg("Setting remote chain on pool")
+ var selectorsToUpdate []token_pool.TokenPoolChainUpdate
+
+ isSupported, err := pool.Instance.IsSupportedChain(nil, remoteChainSelector)
+ if err != nil {
+ return fmt.Errorf("failed to get if chain is supported: %w", err)
+ }
+ // Check if remote chain is already supported, if yes return
+ if isSupported {
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str(Network, pool.client.GetNetworkName()).
+ Uint64("Remote Chain Selector", remoteChainSelector).
+ Msg("Remote chain is already supported")
+ return nil
+ }
+ // if not, add it
+ encodedPoolAddress, err := abihelpers.EncodeAddress(remotePoolAddresses)
+ if err != nil {
+ return fmt.Errorf("failed to encode address: %w", err)
+ }
+
+ encodedTokenAddress, err := abihelpers.EncodeAddress(remoteTokenAddress)
+ if err != nil {
+ return fmt.Errorf("failed to encode token address: %w", err)
+ }
+
+ selectorsToUpdate = append(selectorsToUpdate, token_pool.TokenPoolChainUpdate{
+ RemoteChainSelector: remoteChainSelector,
+ RemotePoolAddress: encodedPoolAddress,
+ RemoteTokenAddress: encodedTokenAddress,
+ Allowed: true,
+ InboundRateLimiterConfig: token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e9)),
+ Rate: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e5)),
+ },
+ OutboundRateLimiterConfig: token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e9)),
+ Rate: new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1e5)),
+ },
+ })
+ opts, err := pool.client.TransactionOpts(pool.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := pool.Instance.ApplyChainUpdates(opts, selectorsToUpdate)
+ if err != nil {
+ return fmt.Errorf("failed to set chain updates on token pool: %w", err)
+ }
+
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Uint64("Chain selector", remoteChainSelector).
+ Str(Network, pool.client.GetNetworkConfig().Name).
+ Msg("Remote chains set on token pool")
+ return pool.client.ProcessTransaction(tx)
+}
+
+// SetRemoteChainRateLimits sets the rate limits for the token pool on the remote chain
+func (pool *TokenPool) SetRemoteChainRateLimits(remoteChainSelector uint64, rl token_pool.RateLimiterConfig) error {
+ opts, err := pool.client.TransactionOpts(pool.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str("Remote chain selector", strconv.FormatUint(remoteChainSelector, 10)).
+ Interface("RateLimiterConfig", rl).
+ Msg("Setting Rate Limit on token pool")
+ tx, err := pool.Instance.SetChainRateLimiterConfig(opts, remoteChainSelector, rl, rl)
+
+ if err != nil {
+ return fmt.Errorf("error setting rate limit token pool: %w", err)
+ }
+
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str("Remote chain selector", strconv.FormatUint(remoteChainSelector, 10)).
+ Interface("RateLimiterConfig", rl).
+ Msg("Rate Limit on token pool is set")
+ return pool.client.ProcessTransaction(tx)
+}
+
+func (pool *TokenPool) SetRouter(routerAddr common.Address) error {
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Msg("Setting router on pool")
+ opts, err := pool.client.TransactionOpts(pool.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := pool.Instance.SetRouter(opts, routerAddr)
+ if err != nil {
+ return fmt.Errorf("failed to set router: %w", err)
+
+ }
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str("Router", routerAddr.String()).
+ Msg("Router set on pool")
+ return pool.client.ProcessTransaction(tx)
+}
+
+func (pool *TokenPool) GetRouter() (common.Address, error) {
+ return pool.Instance.GetRouter(nil)
+}
+
+func (pool *TokenPool) GetToken() (common.Address, error) {
+ if pool.Instance.V1_4_0 != nil && pool.Instance.V1_4_0.PoolInterface != nil {
+ return pool.Instance.V1_4_0.PoolInterface.GetToken(nil)
+ }
+ if pool.Instance.Latest != nil && pool.Instance.Latest.PoolInterface != nil {
+ return pool.Instance.Latest.PoolInterface.GetToken(nil)
+ }
+ return common.Address{}, fmt.Errorf("no pool found to get token")
+}
+
+func (pool *TokenPool) SetRebalancer(rebalancerAddress common.Address) error {
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Msg("Setting rebalancer on pool")
+ opts, err := pool.client.TransactionOpts(pool.OwnerWallet)
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := pool.Instance.SetRebalancer(opts, rebalancerAddress)
+ if err != nil {
+ return fmt.Errorf("failed to set router: %w", err)
+
+ }
+ pool.logger.Info().
+ Str("Token Pool", pool.Address()).
+ Str("Rebalancer", rebalancerAddress.String()).
+ Msg("Rebalancer set on pool")
+ return pool.client.ProcessTransaction(tx)
+}
+
+func (pool *TokenPool) GetRebalancer() (common.Address, error) {
+ return pool.Instance.GetRebalancer(nil)
+}
+
+type ARM struct {
+ client blockchain.EVMClient
+ Instance *arm_contract.ARMContract
+ EthAddress common.Address
+}
+
+func (arm *ARM) Address() string {
+ return arm.EthAddress.Hex()
+}
+
+type MockARM struct {
+ client blockchain.EVMClient
+ Instance *mock_arm_contract.MockARMContract
+ EthAddress common.Address
+}
+
+func (arm *MockARM) SetClient(client blockchain.EVMClient) {
+ arm.client = client
+}
+func (arm *MockARM) Address() string {
+ return arm.EthAddress.Hex()
+}
+
+type CommitStoreReportAccepted struct {
+ Min uint64
+ Max uint64
+ MerkleRoot [32]byte
+ LogInfo LogInfo
+}
+
+type CommitStoreWrapper struct {
+ Latest *commit_store.CommitStore
+ V1_2_0 *commit_store_1_2_0.CommitStore
+}
+
+func (w CommitStoreWrapper) SetOCR2Config(opts *bind.TransactOpts,
+ signers []common.Address,
+ transmitters []common.Address,
+ f uint8,
+ onchainConfig []byte,
+ offchainConfigVersion uint64,
+ offchainConfig []byte,
+) (*types.Transaction, error) {
+ if w.Latest != nil {
+ return w.Latest.SetOCR2Config(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ }
+ if w.V1_2_0 != nil {
+ return w.V1_2_0.SetOCR2Config(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig)
+ }
+ return nil, fmt.Errorf("no instance found to set OCR2 config")
+}
+
+func (w CommitStoreWrapper) GetExpectedNextSequenceNumber(opts *bind.CallOpts) (uint64, error) {
+ if w.Latest != nil {
+ return w.Latest.GetExpectedNextSequenceNumber(opts)
+ }
+ if w.V1_2_0 != nil {
+ return w.V1_2_0.GetExpectedNextSequenceNumber(opts)
+ }
+ return 0, fmt.Errorf("no instance found to get expected next sequence number")
+}
+
+type CommitStore struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ Instance *CommitStoreWrapper
+ EthAddress common.Address
+}
+
+func (b *CommitStore) Address() string {
+ return b.EthAddress.Hex()
+}
+
+// SetOCR2Config sets the offchain reporting protocol configuration
+func (b *CommitStore) SetOCR2Config(
+ signers []common.Address,
+ transmitters []common.Address,
+ f uint8,
+ onchainConfig []byte,
+ offchainConfigVersion uint64,
+ offchainConfig []byte,
+) error {
+ b.logger.Info().Str("Contract Address", b.Address()).Msg("Configuring OCR config for CommitStore Contract")
+ // Set Config
+ opts, err := b.client.TransactionOpts(b.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ tx, err := b.Instance.SetOCR2Config(
+ opts,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig,
+ )
+ b.logger.Debug().
+ Interface("signerAddresses", signers).
+ Interface("transmitterAddresses", transmitters).
+ Str(Network, b.client.GetNetworkConfig().Name).
+ Str("Tx", tx.Hash().Hex()).
+ Msg("Configuring CommitStore")
+
+ if err != nil {
+ return fmt.Errorf("error setting OCR2 config: %w", err)
+ }
+ return b.client.ProcessTransaction(tx)
+}
+
+// WatchReportAccepted watches for report accepted events
+// There is no need to differentiate between the two versions of the contract as the event signature is the same
+// we can cast the contract to the latest version
+func (b *CommitStore) WatchReportAccepted(opts *bind.WatchOpts, acceptedEvent chan *commit_store.CommitStoreReportAccepted) (event.Subscription, error) {
+ if b.Instance.Latest != nil {
+ return b.Instance.Latest.WatchReportAccepted(opts, acceptedEvent)
+ }
+ if b.Instance.V1_2_0 != nil {
+ newCommitStore, err := commit_store.NewCommitStore(b.EthAddress, wrappers.MustNewWrappedContractBackend(b.client, nil))
+ if err != nil {
+ return nil, fmt.Errorf("failed to create new CommitStore contract: %w", err)
+ }
+ return newCommitStore.WatchReportAccepted(opts, acceptedEvent)
+ }
+ return nil, fmt.Errorf("no instance found to watch for report accepted")
+}
+
+type ReceiverDapp struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ instance *maybe_revert_message_receiver.MaybeRevertMessageReceiver
+ EthAddress common.Address
+}
+
+func (rDapp *ReceiverDapp) Address() string {
+ return rDapp.EthAddress.Hex()
+}
+
+func (rDapp *ReceiverDapp) ToggleRevert(revert bool) error {
+ opts, err := rDapp.client.TransactionOpts(rDapp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ tx, err := rDapp.instance.SetRevert(opts, revert)
+ if err != nil {
+ return fmt.Errorf("error setting revert: %w", err)
+ }
+ rDapp.logger.Info().
+ Bool("revert", revert).
+ Str("tx", tx.Hash().String()).
+ Str("ReceiverDapp", rDapp.Address()).
+ Str(Network, rDapp.client.GetNetworkConfig().Name).
+ Msg("ReceiverDapp revert set")
+ return rDapp.client.ProcessTransaction(tx)
+}
+
+type InternalTimestampedPackedUint224 struct {
+ Value *big.Int
+ Timestamp uint32
+}
+
+type PriceRegistryUsdPerUnitGasUpdated struct {
+ DestChain uint64
+ Value *big.Int
+ Timestamp *big.Int
+ Raw types.Log
+}
+
+type PriceRegistryWrapper struct {
+ Latest *price_registry.PriceRegistry
+ V1_2_0 *price_registry_1_2_0.PriceRegistry
+}
+
+func (p *PriceRegistryWrapper) GetTokenPrice(opts *bind.CallOpts, token common.Address) (*big.Int, error) {
+ if p.Latest != nil {
+ price, err := p.Latest.GetTokenPrice(opts, token)
+ if err != nil {
+ return nil, err
+ }
+ return price.Value, nil
+ }
+ if p.V1_2_0 != nil {
+ p, err := p.V1_2_0.GetTokenPrice(opts, token)
+ if err != nil {
+ return nil, err
+ }
+ return p.Value, nil
+ }
+ return nil, fmt.Errorf("no instance found to get token price")
+}
+
+func (p *PriceRegistryWrapper) AddPriceUpdater(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) {
+ if p.Latest != nil {
+ return p.Latest.ApplyAuthorizedCallerUpdates(
+ opts,
+ price_registry.AuthorizedCallersAuthorizedCallerArgs{
+ AddedCallers: []common.Address{addr},
+ RemovedCallers: []common.Address{},
+ },
+ )
+ }
+ if p.V1_2_0 != nil {
+ return p.V1_2_0.ApplyPriceUpdatersUpdates(opts, []common.Address{addr}, []common.Address{})
+ }
+ return nil, fmt.Errorf("no instance found to add price updater")
+}
+
+func (p *PriceRegistryWrapper) AddFeeToken(opts *bind.TransactOpts, addr common.Address) (*types.Transaction, error) {
+ if p.Latest != nil {
+ return p.Latest.ApplyFeeTokensUpdates(opts, []common.Address{addr}, []common.Address{})
+ }
+ if p.V1_2_0 != nil {
+ return p.V1_2_0.ApplyFeeTokensUpdates(opts, []common.Address{addr}, []common.Address{})
+ }
+ return nil, fmt.Errorf("no instance found to add fee token")
+}
+
+func (p *PriceRegistryWrapper) GetDestinationChainGasPrice(opts *bind.CallOpts, chainselector uint64) (InternalTimestampedPackedUint224, error) {
+ if p.Latest != nil {
+ price, err := p.Latest.GetDestinationChainGasPrice(opts, chainselector)
+ if err != nil {
+ return InternalTimestampedPackedUint224{}, err
+ }
+ return InternalTimestampedPackedUint224{
+ Value: price.Value,
+ Timestamp: price.Timestamp,
+ }, nil
+ }
+ if p.V1_2_0 != nil {
+ price, err := p.V1_2_0.GetDestinationChainGasPrice(opts, chainselector)
+ if err != nil {
+ return InternalTimestampedPackedUint224{}, err
+ }
+ return InternalTimestampedPackedUint224{
+ Value: price.Value,
+ Timestamp: price.Timestamp,
+ }, nil
+ }
+ return InternalTimestampedPackedUint224{}, fmt.Errorf("no instance found to add fee token")
+}
+
+type InternalGasPriceUpdate struct {
+ DestChainSelector uint64
+ UsdPerUnitGas *big.Int
+}
+
+type InternalTokenPriceUpdate struct {
+ SourceToken common.Address
+ UsdPerToken *big.Int
+}
+
+type PriceRegistry struct {
+ client blockchain.EVMClient
+ Instance *PriceRegistryWrapper
+ logger *zerolog.Logger
+ EthAddress common.Address
+}
+
+func (c *PriceRegistry) Address() string {
+ return c.EthAddress.Hex()
+}
+
+func (c *PriceRegistry) AddPriceUpdater(addr common.Address) error {
+ opts, err := c.client.TransactionOpts(c.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ tx, err := c.Instance.AddPriceUpdater(opts, addr)
+ if err != nil {
+ return fmt.Errorf("error adding price updater: %w", err)
+ }
+ c.logger.Info().
+ Str("updaters", addr.Hex()).
+ Str(Network, c.client.GetNetworkConfig().Name).
+ Msg("PriceRegistry updater added")
+ return c.client.ProcessTransaction(tx)
+}
+
+func (c *PriceRegistry) AddFeeToken(addr common.Address) error {
+ opts, err := c.client.TransactionOpts(c.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ tx, err := c.Instance.AddFeeToken(opts, addr)
+ if err != nil {
+ return fmt.Errorf("error adding fee token: %w", err)
+ }
+ c.logger.Info().
+ Str("feeTokens", addr.Hex()).
+ Str(Network, c.client.GetNetworkConfig().Name).
+ Msg("PriceRegistry feeToken set")
+ return c.client.ProcessTransaction(tx)
+}
+
+func (c *PriceRegistry) UpdatePrices(tokenUpdates []InternalTokenPriceUpdate, gasUpdates []InternalGasPriceUpdate) error {
+ opts, err := c.client.TransactionOpts(c.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ var tx *types.Transaction
+ if c.Instance.Latest != nil {
+ var tokenUpdatesLatest []price_registry.InternalTokenPriceUpdate
+ var gasUpdatesLatest []price_registry.InternalGasPriceUpdate
+ for _, update := range tokenUpdates {
+ tokenUpdatesLatest = append(tokenUpdatesLatest, price_registry.InternalTokenPriceUpdate{
+ SourceToken: update.SourceToken,
+ UsdPerToken: update.UsdPerToken,
+ })
+ }
+ for _, update := range gasUpdates {
+ gasUpdatesLatest = append(gasUpdatesLatest, price_registry.InternalGasPriceUpdate{
+ DestChainSelector: update.DestChainSelector,
+ UsdPerUnitGas: update.UsdPerUnitGas,
+ })
+ }
+ tx, err = c.Instance.Latest.UpdatePrices(opts, price_registry.InternalPriceUpdates{
+ TokenPriceUpdates: tokenUpdatesLatest,
+ GasPriceUpdates: gasUpdatesLatest,
+ })
+ if err != nil {
+ return fmt.Errorf("error updating prices: %w", err)
+ }
+ }
+ if c.Instance.V1_2_0 != nil {
+ var tokenUpdates_1_2_0 []price_registry_1_2_0.InternalTokenPriceUpdate
+ var gasUpdates_1_2_0 []price_registry_1_2_0.InternalGasPriceUpdate
+ for _, update := range tokenUpdates {
+ tokenUpdates_1_2_0 = append(tokenUpdates_1_2_0, price_registry_1_2_0.InternalTokenPriceUpdate{
+ SourceToken: update.SourceToken,
+ UsdPerToken: update.UsdPerToken,
+ })
+ }
+ for _, update := range gasUpdates {
+ gasUpdates_1_2_0 = append(gasUpdates_1_2_0, price_registry_1_2_0.InternalGasPriceUpdate{
+ DestChainSelector: update.DestChainSelector,
+ UsdPerUnitGas: update.UsdPerUnitGas,
+ })
+ }
+ tx, err = c.Instance.V1_2_0.UpdatePrices(opts, price_registry_1_2_0.InternalPriceUpdates{
+ TokenPriceUpdates: tokenUpdates_1_2_0,
+ GasPriceUpdates: gasUpdates_1_2_0,
+ })
+ if err != nil {
+ return fmt.Errorf("error updating prices: %w", err)
+ }
+ }
+ if tx == nil {
+ return fmt.Errorf("no instance found to update prices")
+ }
+ c.logger.Info().
+ Str(Network, c.client.GetNetworkConfig().Name).
+ Interface("tokenUpdates", tokenUpdates).
+ Interface("gasUpdates", gasUpdates).
+ Msg("Prices updated")
+ return c.client.ProcessTransaction(tx)
+}
+
+func (c *PriceRegistry) WatchUsdPerUnitGasUpdated(opts *bind.WatchOpts, latest chan *price_registry.PriceRegistryUsdPerUnitGasUpdated, destChain []uint64) (event.Subscription, error) {
+ if c.Instance.Latest != nil {
+ return c.Instance.Latest.WatchUsdPerUnitGasUpdated(opts, latest, destChain)
+ }
+ if c.Instance.V1_2_0 != nil {
+ newP, err := price_registry.NewPriceRegistry(c.Instance.V1_2_0.Address(), wrappers.MustNewWrappedContractBackend(c.client, nil))
+ if err != nil {
+ return nil, fmt.Errorf("failed to create new PriceRegistry contract: %w", err)
+ }
+ return newP.WatchUsdPerUnitGasUpdated(opts, latest, destChain)
+ }
+ return nil, fmt.Errorf("no instance found to watch for price updates for gas")
+}
+
+func (c *PriceRegistry) WatchUsdPerTokenUpdated(opts *bind.WatchOpts, latest chan *price_registry.PriceRegistryUsdPerTokenUpdated) (event.Subscription, error) {
+ if c.Instance.Latest != nil {
+ return c.Instance.Latest.WatchUsdPerTokenUpdated(opts, latest, nil)
+ }
+ if c.Instance.V1_2_0 != nil {
+ newP, err := price_registry.NewPriceRegistry(c.Instance.V1_2_0.Address(), wrappers.MustNewWrappedContractBackend(c.client, nil))
+ if err != nil {
+ return nil, fmt.Errorf("failed to create new PriceRegistry contract: %w", err)
+ }
+ return newP.WatchUsdPerTokenUpdated(opts, latest, nil)
+ }
+ return nil, fmt.Errorf("no instance found to watch for price updates for tokens")
+}
+
+type TokenAdminRegistry struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ Instance *token_admin_registry.TokenAdminRegistry
+ EthAddress common.Address
+}
+
+func (r *TokenAdminRegistry) Address() string {
+ return r.EthAddress.Hex()
+}
+
+func (r *TokenAdminRegistry) SetAdminAndRegisterPool(tokenAddr, poolAddr common.Address) error {
+ opts, err := r.client.TransactionOpts(r.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ tx, err := r.Instance.ProposeAdministrator(opts, tokenAddr, opts.From)
+ if err != nil {
+ return fmt.Errorf("error setting admin for token %s : %w", tokenAddr.Hex(), err)
+ }
+ err = r.client.ProcessTransaction(tx)
+ if err != nil {
+ return fmt.Errorf("error processing tx for setting admin on token %w", err)
+ }
+ r.logger.Info().
+ Str("Admin", opts.From.Hex()).
+ Str("Token", tokenAddr.Hex()).
+ Str("TokenAdminRegistry", r.Address()).
+ Msg("Admin is set for token on TokenAdminRegistry")
+ err = r.client.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error waiting for tx for setting admin on pool %w", err)
+ }
+ opts, err = r.client.TransactionOpts(r.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ tx, err = r.Instance.AcceptAdminRole(opts, tokenAddr)
+ if err != nil {
+ return fmt.Errorf("error accepting admin role for token %s : %w", tokenAddr.Hex(), err)
+ }
+ err = r.client.ProcessTransaction(tx)
+ if err != nil {
+ return fmt.Errorf("error processing tx for accepting admin role for token %w", err)
+ }
+ r.logger.Info().
+ Str("Token", tokenAddr.Hex()).
+ Str("TokenAdminRegistry", r.Address()).
+ Msg("Admin role is accepted for token on TokenAdminRegistry")
+ err = r.client.WaitForEvents()
+ if err != nil {
+ return fmt.Errorf("error waiting for tx for accepting admin role for token %w", err)
+ }
+ opts, err = r.client.TransactionOpts(r.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ tx, err = r.Instance.SetPool(opts, tokenAddr, poolAddr)
+ if err != nil {
+ return fmt.Errorf("error setting token %s and pool %s : %w", tokenAddr.Hex(), poolAddr.Hex(), err)
+ }
+ r.logger.Info().
+ Str("Token", tokenAddr.Hex()).
+ Str("Pool", poolAddr.Hex()).
+ Str("TokenAdminRegistry", r.Address()).
+ Msg("token and pool are set on TokenAdminRegistry")
+ err = r.client.ProcessTransaction(tx)
+ if err != nil {
+ return fmt.Errorf("error processing tx for setting token %s and pool %s : %w", tokenAddr.Hex(), poolAddr.Hex(), err)
+ }
+ return nil
+}
+
+type Router struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ Instance *router.Router
+ EthAddress common.Address
+}
+
+func (r *Router) Address() string {
+ return r.EthAddress.Hex()
+}
+
+func (r *Router) SetOnRamp(chainSelector uint64, onRamp common.Address) error {
+ opts, err := r.client.TransactionOpts(r.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ r.logger.Info().
+ Str("Router", r.Address()).
+ Str("OnRamp", onRamp.Hex()).
+ Str(Network, r.client.GetNetworkName()).
+ Str("ChainSelector", strconv.FormatUint(chainSelector, 10)).
+ Msg("Setting on ramp for r")
+
+ tx, err := r.Instance.ApplyRampUpdates(opts, []router.RouterOnRamp{{DestChainSelector: chainSelector, OnRamp: onRamp}}, nil, nil)
+ if err != nil {
+ return fmt.Errorf("error applying ramp updates: %w", err)
+ }
+ r.logger.Info().
+ Str("onRamp", onRamp.Hex()).
+ Str("Network Name", r.client.GetNetworkConfig().Name).
+ Msg("Router is configured")
+ return r.client.ProcessTransaction(tx)
+}
+
+func (r *Router) CCIPSend(destChainSelector uint64, msg router.ClientEVM2AnyMessage, valueForNative *big.Int) (*types.Transaction, error) {
+ opts, err := r.client.TransactionOpts(r.client.GetDefaultWallet())
+ if err != nil {
+ return nil, fmt.Errorf("error getting transaction opts: %w", err)
+ }
+ if valueForNative != nil {
+ opts.Value = valueForNative
+ }
+
+ r.logger.Info().
+ Str(Network, r.client.GetNetworkName()).
+ Str("Router", r.Address()).
+ Interface("TokensAndAmounts", msg.TokenAmounts).
+ Str("FeeToken", msg.FeeToken.Hex()).
+ Str("ExtraArgs", fmt.Sprintf("0x%x", msg.ExtraArgs[:])).
+ Str("Receiver", fmt.Sprintf("0x%x", msg.Receiver[:])).
+ Msg("Sending msg")
+ return r.Instance.CcipSend(opts, destChainSelector, msg)
+}
+
+func (r *Router) CCIPSendAndProcessTx(destChainSelector uint64, msg router.ClientEVM2AnyMessage, valueForNative *big.Int) (*types.Transaction, error) {
+ tx, err := r.CCIPSend(destChainSelector, msg, valueForNative)
+ if err != nil {
+ return nil, fmt.Errorf("failed to send msg: %w", err)
+ }
+ r.logger.Info().
+ Str("Router", r.Address()).
+ Str("txHash", tx.Hash().Hex()).
+ Str(Network, r.client.GetNetworkConfig().Name).
+ Str("Chain Selector", strconv.FormatUint(destChainSelector, 10)).
+ Msg("Message Sent")
+ return tx, r.client.ProcessTransaction(tx)
+}
+
+func (r *Router) AddOffRamp(offRamp common.Address, sourceChainId uint64) (*types.Transaction, error) {
+ opts, err := r.client.TransactionOpts(r.client.GetDefaultWallet())
+ if err != nil {
+ return nil, fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := r.Instance.ApplyRampUpdates(opts, nil, nil, []router.RouterOffRamp{{SourceChainSelector: sourceChainId, OffRamp: offRamp}})
+ if err != nil {
+ return nil, fmt.Errorf("failed to add offRamp: %w", err)
+ }
+ r.logger.Info().
+ Str("offRamp", offRamp.Hex()).
+ Str(Network, r.client.GetNetworkConfig().Name).
+ Msg("offRamp is added to Router")
+ return tx, r.client.ProcessTransaction(tx)
+}
+
+func (r *Router) SetWrappedNative(wNative common.Address) (*types.Transaction, error) {
+ opts, err := r.client.TransactionOpts(r.client.GetDefaultWallet())
+ if err != nil {
+ return nil, fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := r.Instance.SetWrappedNative(opts, wNative)
+ if err != nil {
+ return nil, fmt.Errorf("failed to set wrapped native: %w", err)
+ }
+ r.logger.Info().
+ Str("wrapped native", wNative.Hex()).
+ Str("router", r.Address()).
+ Str(Network, r.client.GetNetworkConfig().Name).
+ Msg("wrapped native is added for Router")
+ return tx, r.client.ProcessTransaction(tx)
+}
+
+func (r *Router) GetFee(destChainSelector uint64, message router.ClientEVM2AnyMessage) (*big.Int, error) {
+ return r.Instance.GetFee(nil, destChainSelector, message)
+}
+
+type SendReqEventData struct {
+ MessageId [32]byte
+ SequenceNumber uint64
+ DataLength int
+ NoOfTokens int
+ LogInfo LogInfo
+ Fee *big.Int
+}
+
+type OnRampWrapper struct {
+ Latest *evm_2_evm_onramp.EVM2EVMOnRamp
+ V1_2_0 *evm_2_evm_onramp_1_2_0.EVM2EVMOnRamp
+}
+
+func (w OnRampWrapper) SetNops(opts *bind.TransactOpts, owner common.Address) (*types.Transaction, error) {
+ if w.Latest != nil {
+ return w.Latest.SetNops(opts, []evm_2_evm_onramp.EVM2EVMOnRampNopAndWeight{
+ {
+ Nop: owner,
+ Weight: 1,
+ },
+ })
+ }
+ if w.V1_2_0 != nil {
+ return w.V1_2_0.SetNops(opts, []evm_2_evm_onramp_1_2_0.EVM2EVMOnRampNopAndWeight{
+ {
+ Nop: owner,
+ Weight: 1,
+ },
+ })
+ }
+ return nil, fmt.Errorf("no instance found to set nops")
+}
+
+func (w OnRampWrapper) SetTokenTransferFeeConfig(
+ opts *bind.TransactOpts,
+ config []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs,
+ addresses []common.Address,
+) (*types.Transaction, error) {
+ if w.Latest != nil {
+ return w.Latest.SetTokenTransferFeeConfig(opts, config, addresses)
+ }
+ if w.V1_2_0 != nil {
+ var configV12 []evm_2_evm_onramp_1_2_0.EVM2EVMOnRampTokenTransferFeeConfigArgs
+ for _, c := range config {
+ configV12 = append(configV12, evm_2_evm_onramp_1_2_0.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ Token: c.Token,
+ MinFeeUSDCents: c.MinFeeUSDCents,
+ MaxFeeUSDCents: c.MaxFeeUSDCents,
+ DeciBps: c.DeciBps,
+ DestGasOverhead: c.DestGasOverhead,
+ DestBytesOverhead: c.DestBytesOverhead,
+ })
+ }
+ return w.V1_2_0.SetTokenTransferFeeConfig(opts, configV12)
+ }
+ return nil, fmt.Errorf("no instance found to set token transfer fee config")
+}
+
+func (w OnRampWrapper) PayNops(opts *bind.TransactOpts) (*types.Transaction, error) {
+ if w.Latest != nil {
+ return w.Latest.PayNops(opts)
+ }
+ if w.V1_2_0 != nil {
+ return w.V1_2_0.PayNops(opts)
+ }
+ return nil, fmt.Errorf("no instance found to pay nops")
+}
+
+func (w OnRampWrapper) WithdrawNonLinkFees(opts *bind.TransactOpts, native common.Address, owner common.Address) (*types.Transaction, error) {
+ if w.Latest != nil {
+ return w.Latest.WithdrawNonLinkFees(opts, native, owner)
+ }
+ if w.V1_2_0 != nil {
+ return w.V1_2_0.WithdrawNonLinkFees(opts, native, owner)
+ }
+ return nil, fmt.Errorf("no instance found to withdraw non link fees")
+}
+
+func (w OnRampWrapper) SetRateLimiterConfig(opts *bind.TransactOpts, config evm_2_evm_onramp.RateLimiterConfig) (*types.Transaction, error) {
+ if w.Latest != nil {
+ return w.Latest.SetRateLimiterConfig(opts, config)
+ }
+ if w.V1_2_0 != nil {
+ return w.V1_2_0.SetRateLimiterConfig(opts, evm_2_evm_onramp_1_2_0.RateLimiterConfig{
+ IsEnabled: config.IsEnabled,
+ Capacity: config.Capacity,
+ Rate: config.Rate,
+ })
+ }
+ return nil, fmt.Errorf("no instance found to set rate limiter config")
+}
+
+func (w OnRampWrapper) ParseCCIPSendRequested(l types.Log) (uint64, error) {
+ if w.Latest != nil {
+ sendReq, err := w.Latest.ParseCCIPSendRequested(l)
+ if err != nil {
+ return 0, err
+ }
+ return sendReq.Message.SequenceNumber, nil
+ }
+ if w.V1_2_0 != nil {
+ sendReq, err := w.V1_2_0.ParseCCIPSendRequested(l)
+ if err != nil {
+ return 0, err
+ }
+ return sendReq.Message.SequenceNumber, nil
+ }
+ return 0, fmt.Errorf("no instance found to parse CCIPSendRequested")
+}
+
+func (w OnRampWrapper) GetDynamicConfig(opts *bind.CallOpts) (uint32, error) {
+ if w.Latest != nil {
+ cfg, err := w.Latest.GetDynamicConfig(opts)
+ if err != nil {
+ return 0, err
+ }
+ return cfg.MaxDataBytes, nil
+ }
+ if w.V1_2_0 != nil {
+ cfg, err := w.V1_2_0.GetDynamicConfig(opts)
+ if err != nil {
+ return 0, err
+ }
+ return cfg.MaxDataBytes, nil
+ }
+ return 0, fmt.Errorf("no instance found to get dynamic config")
+}
+
+func (w OnRampWrapper) ApplyPoolUpdates(opts *bind.TransactOpts, tokens []common.Address, pools []common.Address) (*types.Transaction, error) {
+ if w.Latest != nil {
+ return nil, fmt.Errorf("latest version does not support ApplyPoolUpdates")
+ }
+ if w.V1_2_0 != nil {
+ var poolUpdates []evm_2_evm_onramp_1_2_0.InternalPoolUpdate
+ if len(tokens) != len(pools) {
+ return nil, fmt.Errorf("tokens and pools length mismatch")
+ }
+ for i, token := range tokens {
+ poolUpdates = append(poolUpdates, evm_2_evm_onramp_1_2_0.InternalPoolUpdate{
+ Token: token,
+ Pool: pools[i],
+ })
+ }
+ return w.V1_2_0.ApplyPoolUpdates(opts, []evm_2_evm_onramp_1_2_0.InternalPoolUpdate{}, poolUpdates)
+ }
+ return nil, fmt.Errorf("no instance found to apply pool updates")
+}
+
+// CurrentRateLimiterState returns the current state of the rate limiter
+func (w OnRampWrapper) CurrentRateLimiterState(opts *bind.CallOpts) (*RateLimiterConfig, error) {
+ if w.Latest != nil {
+ rlConfig, err := w.Latest.CurrentRateLimiterState(opts)
+ if err != nil {
+ return nil, err
+ }
+ return &RateLimiterConfig{
+ IsEnabled: rlConfig.IsEnabled,
+ Rate: rlConfig.Rate,
+ Capacity: rlConfig.Capacity,
+ Tokens: rlConfig.Tokens,
+ }, err
+ }
+ if w.V1_2_0 != nil {
+ rlConfig, err := w.V1_2_0.CurrentRateLimiterState(opts)
+ if err != nil {
+ return nil, err
+ }
+ return &RateLimiterConfig{
+ IsEnabled: rlConfig.IsEnabled,
+ Rate: rlConfig.Rate,
+ Capacity: rlConfig.Capacity,
+ Tokens: rlConfig.Tokens,
+ }, err
+ }
+ return nil, fmt.Errorf("no instance found to get current rate limiter state")
+}
+
+type OnRamp struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ Instance *OnRampWrapper
+ EthAddress common.Address
+}
+
+// WatchCCIPSendRequested returns a subscription to watch for CCIPSendRequested events
+// there is no difference in the event between the two versions
+// so we can use the latest version to watch for events
+func (onRamp *OnRamp) WatchCCIPSendRequested(opts *bind.WatchOpts, sendReqEvent chan *evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested) (event.Subscription, error) {
+ if onRamp.Instance.Latest != nil {
+ return onRamp.Instance.Latest.WatchCCIPSendRequested(opts, sendReqEvent)
+ }
+ // cast the contract to the latest version so that we can watch for events with latest wrapper
+ if onRamp.Instance.V1_2_0 != nil {
+ newRamp, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(onRamp.EthAddress, wrappers.MustNewWrappedContractBackend(onRamp.client, nil))
+ if err != nil {
+ return nil, fmt.Errorf("failed to cast to latest version: %w", err)
+ }
+ return newRamp.WatchCCIPSendRequested(opts, sendReqEvent)
+ }
+ // should never reach here
+ return nil, fmt.Errorf("no instance found to watch for CCIPSendRequested")
+}
+
+func (onRamp *OnRamp) Address() string {
+ return onRamp.EthAddress.Hex()
+}
+
+func (onRamp *OnRamp) SetNops() error {
+ opts, err := onRamp.client.TransactionOpts(onRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ owner := common.HexToAddress(onRamp.client.GetDefaultWallet().Address())
+ // set the payee to the default wallet
+ tx, err := onRamp.Instance.SetNops(opts, owner)
+ if err != nil {
+ return fmt.Errorf("failed to set nops: %w", err)
+ }
+ return onRamp.client.ProcessTransaction(tx)
+}
+
+// SetTokenTransferFeeConfig sets the token transfer fee configuration for the OnRamp
+func (onRamp *OnRamp) SetTokenTransferFeeConfig(tokenTransferFeeConfig []evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs) error {
+ opts, err := onRamp.client.TransactionOpts(onRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ for i := range tokenTransferFeeConfig {
+ if tokenTransferFeeConfig[i].DestBytesOverhead == 0 {
+ tokenTransferFeeConfig[i].DestBytesOverhead = defaultDestByteOverhead
+ }
+ if tokenTransferFeeConfig[i].DestGasOverhead == 0 {
+ tokenTransferFeeConfig[i].DestGasOverhead = defaultDestGasOverhead
+ }
+ }
+ tx, err := onRamp.Instance.SetTokenTransferFeeConfig(opts, tokenTransferFeeConfig, []common.Address{})
+ if err != nil {
+ return fmt.Errorf("failed to set token transfer fee config: %w", err)
+ }
+ onRamp.logger.Info().
+ Interface("tokenTransferFeeConfig", tokenTransferFeeConfig).
+ Str("onRamp", onRamp.Address()).
+ Str(Network, onRamp.client.GetNetworkConfig().Name).
+ Msg("TokenTransferFeeConfig set in OnRamp")
+ return onRamp.client.ProcessTransaction(tx)
+}
+
+func (onRamp *OnRamp) PayNops() error {
+ opts, err := onRamp.client.TransactionOpts(onRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := onRamp.Instance.PayNops(opts)
+ if err != nil {
+ return fmt.Errorf("failed to pay nops: %w", err)
+ }
+ return onRamp.client.ProcessTransaction(tx)
+}
+
+func (onRamp *OnRamp) WithdrawNonLinkFees(wrappedNative common.Address) error {
+ opts, err := onRamp.client.TransactionOpts(onRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ owner := common.HexToAddress(onRamp.client.GetDefaultWallet().Address())
+ tx, err := onRamp.Instance.WithdrawNonLinkFees(opts, wrappedNative, owner)
+ if err != nil {
+ return fmt.Errorf("failed to withdraw non link fees: %w", err)
+ }
+ return onRamp.client.ProcessTransaction(tx)
+}
+
+// SetRateLimit sets the Aggregate Rate Limit (ARL) values for the OnRamp
+func (onRamp *OnRamp) SetRateLimit(rlConfig evm_2_evm_onramp.RateLimiterConfig) error {
+ opts, err := onRamp.client.TransactionOpts(onRamp.client.GetDefaultWallet())
+ if err != nil {
+ return err
+ }
+ tx, err := onRamp.Instance.SetRateLimiterConfig(opts, rlConfig)
+ if err != nil {
+ return fmt.Errorf("failed to set rate limit: %w", err)
+ }
+ onRamp.logger.Info().
+ Bool("Enabled", rlConfig.IsEnabled).
+ Str("capacity", rlConfig.Capacity.String()).
+ Str("rate", rlConfig.Rate.String()).
+ Str("onRamp", onRamp.Address()).
+ Str(Network, onRamp.client.GetNetworkConfig().Name).
+ Msg("Setting Rate limit in OnRamp")
+ return onRamp.client.ProcessTransaction(tx)
+}
+
+func (onRamp *OnRamp) ApplyPoolUpdates(tokens []common.Address, pools []common.Address) error {
+ // if the latest version is used, no need to apply pool updates
+ if onRamp.Instance.Latest != nil {
+ return nil
+ }
+ opts, err := onRamp.client.TransactionOpts(onRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := onRamp.Instance.ApplyPoolUpdates(opts, tokens, pools)
+ if err != nil {
+ return fmt.Errorf("failed to apply pool updates: %w", err)
+ }
+ onRamp.logger.Info().
+ Interface("tokens", tokens).
+ Interface("pools", pools).
+ Str("onRamp", onRamp.Address()).
+ Str(Network, onRamp.client.GetNetworkConfig().Name).
+ Msg("poolUpdates set in OnRamp")
+ return onRamp.client.ProcessTransaction(tx)
+}
+
+// OffRamp represents the OffRamp CCIP contract on the destination chain
+type OffRamp struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ Instance *OffRampWrapper
+ EthAddress common.Address
+}
+
+func (offRamp *OffRamp) Address() string {
+ return offRamp.EthAddress.Hex()
+}
+
+// WatchExecutionStateChanged returns a subscription to watch for ExecutionStateChanged events
+// there is no difference in the event between the two versions
+// so we can use the latest version to watch for events
+func (offRamp *OffRamp) WatchExecutionStateChanged(
+ opts *bind.WatchOpts,
+ execEvent chan *evm_2_evm_offramp.EVM2EVMOffRampExecutionStateChanged,
+ sequenceNumber []uint64,
+ messageId [][32]byte,
+) (event.Subscription, error) {
+ if offRamp.Instance.Latest != nil {
+ return offRamp.Instance.Latest.WatchExecutionStateChanged(opts, execEvent, sequenceNumber, messageId)
+ }
+ if offRamp.Instance.V1_2_0 != nil {
+ newOffRamp, err := evm_2_evm_offramp.NewEVM2EVMOffRamp(offRamp.EthAddress, wrappers.MustNewWrappedContractBackend(offRamp.client, nil))
+ if err != nil {
+ return nil, fmt.Errorf("failed to cast to latest version of OffRamp from v1_2_0: %w", err)
+ }
+ return newOffRamp.WatchExecutionStateChanged(opts, execEvent, sequenceNumber, messageId)
+ }
+ return nil, fmt.Errorf("no instance found to watch for ExecutionStateChanged")
+}
+
+// SetOCR2Config sets the offchain reporting protocol configuration
+func (offRamp *OffRamp) SetOCR2Config(
+ signers []common.Address,
+ transmitters []common.Address,
+ f uint8,
+ onchainConfig []byte,
+ offchainConfigVersion uint64,
+ offchainConfig []byte,
+) error {
+ offRamp.logger.Info().Str("Contract Address", offRamp.Address()).Msg("Configuring OffRamp Contract")
+ // Set Config
+ opts, err := offRamp.client.TransactionOpts(offRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction options: %w", err)
+ }
+ offRamp.logger.Debug().
+ Interface("SignerAddresses", signers).
+ Interface("TransmitterAddresses", transmitters).
+ Str(Network, offRamp.client.GetNetworkConfig().Name).
+ Msg("Configuring OffRamp")
+ if offRamp.Instance.Latest != nil {
+ tx, err := offRamp.Instance.Latest.SetOCR2Config(
+ opts,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to set latest OCR2 config: %w", err)
+ }
+ return offRamp.client.ProcessTransaction(tx)
+ }
+ if offRamp.Instance.V1_2_0 != nil {
+ tx, err := offRamp.Instance.V1_2_0.SetOCR2Config(
+ opts,
+ signers,
+ transmitters,
+ f,
+ onchainConfig,
+ offchainConfigVersion,
+ offchainConfig,
+ )
+ if err != nil {
+ return fmt.Errorf("failed to set 1.2 OCR2 config: %w", err)
+ }
+ return offRamp.client.ProcessTransaction(tx)
+ }
+ return fmt.Errorf("no instance found to set OCR2 config")
+}
+
+// AddRateLimitTokens adds token pairs to the OffRamp's rate limit
+func (offRamp *OffRamp) AddRateLimitTokens(sourceTokens, destTokens []common.Address) error {
+ if offRamp.Instance.V1_2_0 != nil {
+ return nil
+ }
+
+ if len(sourceTokens) != len(destTokens) {
+ return fmt.Errorf("source and dest tokens must be of the same length")
+ }
+ opts, err := offRamp.client.TransactionOpts(offRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+
+ if offRamp.Instance.Latest != nil {
+ rateLimitTokens := make([]evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, len(sourceTokens))
+ for i, sourceToken := range sourceTokens {
+ rateLimitTokens[i] = evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken{
+ SourceToken: sourceToken,
+ DestToken: destTokens[i],
+ }
+ }
+
+ tx, err := offRamp.Instance.Latest.UpdateRateLimitTokens(opts, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken{}, rateLimitTokens)
+ if err != nil {
+ return fmt.Errorf("failed to apply rate limit tokens updates: %w", err)
+ }
+ offRamp.logger.Info().
+ Interface("rateLimitToken adds", rateLimitTokens).
+ Str("offRamp", offRamp.Address()).
+ Str(Network, offRamp.client.GetNetworkConfig().Name).
+ Msg("rateLimitTokens set in OffRamp")
+ return offRamp.client.ProcessTransaction(tx)
+ }
+ return fmt.Errorf("no supported OffRamp version instance found")
+}
+
+// RemoveRateLimitTokens removes token pairs to the OffRamp's rate limit.
+// If you ask to remove a token pair that doesn't exist, it will return an error.
+func (offRamp *OffRamp) RemoveRateLimitTokens(ctx context.Context, sourceTokens, destTokens []common.Address) error {
+ callOpts := &bind.CallOpts{
+ From: common.HexToAddress(offRamp.client.GetDefaultWallet().Address()),
+ Context: ctx,
+ }
+
+ switch {
+ case offRamp.Instance.Latest != nil:
+ existingRateLimitTokens, err := offRamp.Instance.Latest.GetAllRateLimitTokens(callOpts)
+ if err != nil {
+ return fmt.Errorf("failed to get all rate limit tokens: %w", err)
+ }
+
+ rateLimitTokens := make([]evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, len(sourceTokens))
+ for i, sourceToken := range sourceTokens {
+ destToken := destTokens[i]
+ // Check if the source rate limit token exists
+ foundIndex := -1
+ for j, existingSourceToken := range existingRateLimitTokens.SourceTokens {
+ if existingSourceToken == sourceToken {
+ foundIndex = j
+ break
+ }
+ }
+ if foundIndex == -1 {
+ return fmt.Errorf("source rate limit token not found for pair: %s -> %s", sourceTokens[i].Hex(), destTokens[i].Hex())
+ }
+ // Check if the matching dest rate limit token exists
+ if existingRateLimitTokens.DestTokens[foundIndex] != destToken {
+ return fmt.Errorf("dest rate limit token not found for pair: %s -> %s", sourceTokens[i].Hex(), destTokens[i].Hex())
+ }
+ // Update the existing rate limit tokens to remove the pair for visibility
+ existingRateLimitTokens.SourceTokens = append(existingRateLimitTokens.SourceTokens[:foundIndex], existingRateLimitTokens.SourceTokens[foundIndex+1:]...)
+ existingRateLimitTokens.DestTokens = append(existingRateLimitTokens.DestTokens[:foundIndex], existingRateLimitTokens.DestTokens[foundIndex+1:]...)
+
+ rateLimitTokens[i] = evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken{
+ SourceToken: sourceToken,
+ DestToken: destToken,
+ }
+ }
+
+ opts, err := offRamp.client.TransactionOpts(offRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := offRamp.Instance.Latest.UpdateRateLimitTokens(opts, rateLimitTokens, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken{})
+ if err != nil {
+ return fmt.Errorf("failed to remove rate limit tokens: %w", err)
+ }
+ offRamp.logger.Info().
+ Interface("RateLimitTokens Remaining", existingRateLimitTokens).
+ Interface("RateLimitTokens Removed", rateLimitTokens).
+ Str("OffRamp", offRamp.Address()).
+ Str(Network, offRamp.client.GetNetworkConfig().Name).
+ Msg("RateLimitTokens Removed from OffRamp")
+ return offRamp.client.ProcessTransaction(tx)
+ case offRamp.Instance.V1_2_0 != nil:
+ return nil
+ }
+ return fmt.Errorf("no supported OffRamp version instance found")
+}
+
+// RemoveAllRateLimitTokens removes all token pairs from the OffRamp's rate limit.
+func (offRamp *OffRamp) RemoveAllRateLimitTokens(ctx context.Context) error {
+ callOpts := &bind.CallOpts{
+ From: common.HexToAddress(offRamp.client.GetDefaultWallet().Address()),
+ Context: ctx,
+ }
+
+ switch {
+ case offRamp.Instance.Latest != nil:
+ allRateLimitTokens, err := offRamp.Instance.Latest.GetAllRateLimitTokens(callOpts)
+ if err != nil {
+ return fmt.Errorf("failed to get all rate limit tokens: %w", err)
+ }
+
+ rateLimitTokens := make([]evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken, len(allRateLimitTokens.SourceTokens))
+ for i, sourceToken := range allRateLimitTokens.SourceTokens {
+ rateLimitTokens[i] = evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken{
+ SourceToken: sourceToken,
+ DestToken: allRateLimitTokens.DestTokens[i],
+ }
+ }
+
+ opts, err := offRamp.client.TransactionOpts(offRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ tx, err := offRamp.Instance.Latest.UpdateRateLimitTokens(opts, rateLimitTokens, []evm_2_evm_offramp.EVM2EVMOffRampRateLimitToken{})
+ if err != nil {
+ return fmt.Errorf("failed to remove rate limit tokens: %w", err)
+ }
+ offRamp.logger.Info().
+ Interface("RateLimitTokens Removed", rateLimitTokens).
+ Str("OffRamp", offRamp.Address()).
+ Str(Network, offRamp.client.GetNetworkConfig().Name).
+ Msg("Removed all RateLimitTokens from OffRamp")
+ return offRamp.client.ProcessTransaction(tx)
+ case offRamp.Instance.V1_2_0 != nil:
+ return nil
+ }
+ return fmt.Errorf("no supported OffRamp version instance found")
+}
+
+// SetRateLimit sets the Aggregate Rate Limit (ARL) values for the OffRamp
+func (offRamp *OffRamp) SetRateLimit(rlConfig RateLimiterConfig) error {
+ opts, err := offRamp.client.TransactionOpts(offRamp.client.GetDefaultWallet())
+ if err != nil {
+ return err
+ }
+ offRamp.logger.Info().
+ Bool("Enabled", rlConfig.IsEnabled).
+ Str("Capacity", rlConfig.Capacity.String()).
+ Str("Rate", rlConfig.Rate.String()).
+ Str("OffRamp", offRamp.Address()).
+ Str(Network, offRamp.client.GetNetworkConfig().Name).
+ Msg("Setting Rate limit on OffRamp")
+
+ switch {
+ case offRamp.Instance.Latest != nil:
+ tx, err := offRamp.Instance.Latest.SetRateLimiterConfig(opts, evm_2_evm_offramp.RateLimiterConfig{
+ IsEnabled: rlConfig.IsEnabled,
+ Capacity: rlConfig.Capacity,
+ Rate: rlConfig.Rate,
+ })
+ if err != nil {
+ return fmt.Errorf("failed to set rate limit: %w", err)
+ }
+ return offRamp.client.ProcessTransaction(tx)
+ case offRamp.Instance.V1_2_0 != nil:
+ tx, err := offRamp.Instance.V1_2_0.SetRateLimiterConfig(opts, evm_2_evm_offramp_1_2_0.RateLimiterConfig{
+ IsEnabled: rlConfig.IsEnabled,
+ Capacity: rlConfig.Capacity,
+ Rate: rlConfig.Rate,
+ })
+ if err != nil {
+ return fmt.Errorf("failed to set rate limit: %w", err)
+ }
+ return offRamp.client.ProcessTransaction(tx)
+ }
+ return fmt.Errorf("no supported OffRamp version instance found")
+}
+
+func (offRamp *OffRamp) SyncTokensAndPools(sourceTokens, pools []common.Address) error {
+ if offRamp.Instance.Latest != nil {
+ return nil
+ }
+ opts, err := offRamp.client.TransactionOpts(offRamp.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("failed to get transaction opts: %w", err)
+ }
+ if offRamp.Instance.V1_2_0 != nil {
+ var tokenUpdates []evm_2_evm_offramp_1_2_0.InternalPoolUpdate
+ for i, srcToken := range sourceTokens {
+ tokenUpdates = append(tokenUpdates, evm_2_evm_offramp_1_2_0.InternalPoolUpdate{
+ Token: srcToken,
+ Pool: pools[i],
+ })
+ }
+ tx, err := offRamp.Instance.V1_2_0.ApplyPoolUpdates(opts, []evm_2_evm_offramp_1_2_0.InternalPoolUpdate{}, tokenUpdates)
+ if err != nil {
+ return fmt.Errorf("failed to apply pool updates: %w", err)
+ }
+ offRamp.logger.Info().
+ Interface("tokenUpdates", tokenUpdates).
+ Str("offRamp", offRamp.Address()).
+ Str(Network, offRamp.client.GetNetworkConfig().Name).
+ Msg("tokenUpdates set in OffRamp")
+ return offRamp.client.ProcessTransaction(tx)
+ }
+ return fmt.Errorf("no instance found to sync tokens and pools")
+}
+
+// OffRampWrapper wraps multiple versions of the OffRamp contract as we support multiple at once.
+// If you are using any of the functions in this struct, be sure to follow best practices:
+// 1. If the function does not make sense for a specific version,
+// (e.g. crucial functionality that changes state, but doesn't exist yet) return an error.
+// 2. If the function does not make sense for a specific version, but calling it doesn't change how execution would work
+// (e.g. functionality that wouldn't change state), you can return a nil or default value, treating it as a no-op.
+// 3. If no valid versions are available, return an error.
+//
+// See CurrentRateLimiterState, WatchExecutionStateChanged, and AddRateLimitTokens for examples.
+type OffRampWrapper struct {
+ Latest *evm_2_evm_offramp.EVM2EVMOffRamp
+ V1_2_0 *evm_2_evm_offramp_1_2_0.EVM2EVMOffRamp
+}
+
+// CurrentRateLimiterState retrieves the current rate limiter state for the OffRamp contract
+func (offRamp *OffRampWrapper) CurrentRateLimiterState(opts *bind.CallOpts) (RateLimiterConfig, error) {
+ if offRamp.Latest != nil {
+ rlConfig, err := offRamp.Latest.CurrentRateLimiterState(opts)
+ if err != nil {
+ return RateLimiterConfig{}, err
+ }
+ return RateLimiterConfig{
+ IsEnabled: rlConfig.IsEnabled,
+ Capacity: rlConfig.Capacity,
+ Rate: rlConfig.Rate,
+ }, nil
+ }
+ if offRamp.V1_2_0 != nil {
+ rlConfig, err := offRamp.V1_2_0.CurrentRateLimiterState(opts)
+ if err != nil {
+ return RateLimiterConfig{}, err
+ }
+ return RateLimiterConfig{
+ IsEnabled: rlConfig.IsEnabled,
+ Capacity: rlConfig.Capacity,
+ Rate: rlConfig.Rate,
+ }, nil
+ }
+ return RateLimiterConfig{}, fmt.Errorf("no instance found to get rate limiter state")
+}
+
+type EVM2EVMOffRampExecutionStateChanged struct {
+ SequenceNumber uint64
+ MessageId [32]byte
+ State uint8
+ ReturnData []byte
+ LogInfo LogInfo
+}
+
+type MockAggregator struct {
+ client blockchain.EVMClient
+ logger *zerolog.Logger
+ Instance *mock_v3_aggregator_contract.MockV3Aggregator
+ ContractAddress common.Address
+ RoundId *big.Int
+ Answer *big.Int
+}
+
+func (a *MockAggregator) ChainID() uint64 {
+ return a.client.GetChainID().Uint64()
+}
+
+// UpdateRoundData updates the round data in the aggregator contract
+// if answer is nil, it will set next round data by adding random percentage( within provided range) to the previous round data
+func (a *MockAggregator) UpdateRoundData(answer *big.Int, minP, maxP *int) error {
+ if answer == nil && (minP == nil || maxP == nil) {
+ return fmt.Errorf("minP and maxP are required to update round data with random percentage if answer is nil")
+ }
+ // if round id is nil, set it to 1
+ if a.RoundId == nil {
+ a.RoundId = big.NewInt(1)
+ }
+ // if there is no answer provided and last saved answer is nil
+ // we fetch the last round data from chain
+ // and set the answer to the aggregator's latest answer and round id to the aggregator's latest round id
+ if answer == nil && a.Answer == nil {
+ roundData, err := a.Instance.LatestRoundData(nil)
+ if err != nil || roundData.RoundId == nil || roundData.Answer == nil {
+ return fmt.Errorf("unable to get latest round data: %w", err)
+ }
+ a.Answer = roundData.Answer
+ a.RoundId = roundData.RoundId
+ }
+
+ // if answer is nil, we calculate the answer with random percentage (within the provided range) of latest answer
+ if answer == nil {
+ rand.Seed(uint64(time.Now().UnixNano()))
+ randomNumber := rand.Intn(pointer.GetInt(maxP)-pointer.GetInt(minP)+1) + pointer.GetInt(minP)
+ // answer = previous round answer + (previous round answer * random percentage)
+ answer = new(big.Int).Add(a.Answer, new(big.Int).Div(new(big.Int).Mul(a.Answer, big.NewInt(int64(randomNumber))), big.NewInt(100)))
+ }
+ // increment the round id
+ round := new(big.Int).Add(a.RoundId, big.NewInt(1))
+ // save the round data as the latest round data
+ a.RoundId = round
+ a.Answer = answer
+ opts, err := a.client.TransactionOpts(a.client.GetDefaultWallet())
+ if err != nil {
+ return fmt.Errorf("unable to get transaction opts: %w", err)
+ }
+ a.logger.Info().
+ Str("Contract Address", a.ContractAddress.Hex()).
+ Str("Network Name", a.client.GetNetworkConfig().Name).
+ Msg("Updating Round Data")
+ tx, err := a.Instance.UpdateRoundData(opts, round, answer, big.NewInt(time.Now().UTC().UnixNano()), big.NewInt(time.Now().UTC().UnixNano()))
+ if err != nil {
+ return fmt.Errorf("unable to update round data: %w", err)
+ }
+ a.logger.Info().
+ Str("Contract Address", a.ContractAddress.Hex()).
+ Str("Network Name", a.client.GetNetworkConfig().Name).
+ Str("Round", round.String()).
+ Str("Answer", answer.String()).
+ Msg("Updated Round Data")
+ ctx, cancel := context.WithTimeout(context.Background(), a.client.GetNetworkConfig().Timeout.Duration)
+ defer cancel()
+ rec, err := bind.WaitMined(ctx, a.client.DeployBackend(), tx)
+ if err != nil {
+ return fmt.Errorf("error waiting for tx %s to be mined", tx.Hash().Hex())
+ }
+ if rec.Status != types.ReceiptStatusSuccessful {
+ return fmt.Errorf("tx %s failed while updating round data", tx.Hash().Hex())
+ }
+
+ return a.client.MarkTxAsSentOnL2(tx)
+}
diff --git a/integration-tests/ccip-tests/contracts/laneconfig/contracts-1.2.json b/integration-tests/ccip-tests/contracts/laneconfig/contracts-1.2.json
new file mode 100644
index 00000000000..4de4d1e504d
--- /dev/null
+++ b/integration-tests/ccip-tests/contracts/laneconfig/contracts-1.2.json
@@ -0,0 +1,634 @@
+{
+ "lane_configs": {
+ "Arbitrum Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xe06b0e8c4bd455153e8794ad7Ea8Ff5A14B64E4b",
+ "router": "0x141fa059441E0ca23ce184B6A78bafD2A517DdE8",
+ "price_registry": "0x13015e4E6f839E1Aa1016DF521ea458ecA20438c",
+ "wrapped_native": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
+ "src_contracts": {
+ "Avalanche Mainnet": {
+ "on_ramp": "0x05B723f3db92430FbE4395fD03E40Cc7e9D17988",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x77b60F85b25fD501E3ddED6C1fe7bF565C08A22A",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x79f3ABeCe5A3AFFf32D47F4CFe45e7b65c9a2D91",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xCe11020D56e5FDbfE46D9FC3021641FfbBB5AdEE",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0xC09b72E8128620C40D89649019d995Cc79f030C3",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x122F05F49e90508F089eE8D0d868d1a4f3E5a809",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x66a0046ac9FA104eB38B04cfF391CcD0122E6FbC",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Mainnet": {
+ "off_ramp": "0xe0109912157d5B75ea8b3181123Cf32c73bc9920",
+ "commit_store": "0xDaa61b8Cd85977820f92d1e749E1D9F55Da6CCEA",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xdB19F77F87661f9be0F557cf9a1ebeCf7D8F206c",
+ "commit_store": "0x6e37f4c82d9A31cc42B445874dd3c3De97AB553f",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0xB1b705c2315fced1B38baE463BE7DDef531e47fA",
+ "commit_store": "0x310cECbFf14Ad0307EfF762F461a487C1abb90bf",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x542ba1902044069330e8c5b36A84EC503863722f",
+ "commit_store": "0x060331fEdA35691e54876D957B4F9e3b8Cb47d20",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xeeed4D86F3E0e6d32A6Ad29d8De6A0Dc91963A5f",
+ "commit_store": "0xbbB563c4d98020b9c0f3Cc34c2C0Ef9676806E35",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x9bDA7c8DCda4E39aFeB483cc0B7E3C1f6E0D5AB1",
+ "commit_store": "0x63a0AeaadAe851b990bBD9dc41f5C1B08b32026d",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xEEf5Fb4c4953F9cA9ab1f25cE590776AfFc2c455",
+ "commit_store": "0xD268286A277095a9C3C90205110831a84505881c",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Avalanche Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x5947BB275c521040051D82396192181b413227A3",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xdFD6C0dc67666DE3bB36b31eec5c7B1542A82C1E",
+ "router": "0xF4c7E640EdA248ef95972845a62bdC74237805dB",
+ "price_registry": "0xfA4edD04eaAcDB07c8D73621bc1790eC50D8c489",
+ "wrapped_native": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x98f51B041e493fc4d72B8BD33218480bA0c66DDF",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x268fb4311D2c6CB2bbA01CCA9AC073Fb3bfd1C7c",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x8eaae6462816CB4957184c48B86afA7642D8Bf2B",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xD0701FcC7818c31935331B02Eb21e91eC71a1704",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x8629008887E073260c5434D6CaCFc83C3001d211",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x97500490d9126f34cf9aA0126d64623E170319Ef",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x9b1ed9De069Be4d50957464b359f98eD0Bf34dd5",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x770b1375F86E7a9bf30DBe3F97bea67193dC9135",
+ "commit_store": "0x23E2b34Ce8e12c53f8a39AD4b3FFCa845f8E617C",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0x4d6A796Bc85dcDF41ce9AaEB50B094C6b589748f",
+ "commit_store": "0xc4C4358FA01a04D6c6FE3b96a351946d4c2715C2",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x83F53Fc798FEbfFbdF84830AD403b9989187a06C",
+ "commit_store": "0xD8ceCE2D7794385E00Ce3EF94550E732b0A0B959",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x5B833BD6456c604Eb396C0fBa477aD49e82B1A2a",
+ "commit_store": "0x23E23958D220B774680f91c2c91a6f2B2f610d7e",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xb68A3EE8bD0A09eE221cf1859Dd5a4d5765188Fe",
+ "commit_store": "0x83DCeeCf822981F9F8552925eEfd88CAc1905dEA",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x19250aBE66B88F214d02B6f3BF80F4118290C619",
+ "commit_store": "0x87A0935cE6254dB1252bBac90d1D07D04846aDCA",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x317dE8bc5c3292E494b6496586696d4966A922B0",
+ "commit_store": "0x97Fbf3d6DEac16adC721aE9187CeEa1e610aC7Af",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Base Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x88Fb150BDc53A65fe94Dea0c9BA0a6dAf8C6e196",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x38660c8CC222c0192b635c2ac09687B4F25cCE5F",
+ "router": "0x881e3A65B4d4a04dD529061dd0071cf975F58bCD",
+ "price_registry": "0x6337a58D4BD7Ba691B66341779e8f87d4679923a",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x1E5Ca70d1e7A1B26061125738a880BBeA42FeB21",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xBE5a9E336D9614024B4Fa10D8112671fc9A42d96",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xdd4Fb402d41Beb0eEeF6CfB1bf445f50bDC8c981",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xDEA286dc0E01Cb4755650A6CF8d1076b454eA1cb",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0xd952FEAcDd5919Cc5E9454b53bF45d4E73dD6457",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x3DB8Bea142e41cA3633890d0e5640F99a895D6A5",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x8531E63aE9279a1f0D09eba566CD1b092b95f3D5",
+ "commit_store": "0x327E13f54c7871a2416006B33B4822eAAD357916",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x8345F2fF67e5A65e85dc955DE1414832608E00aD",
+ "commit_store": "0xd0b13be4c53A6262b47C5DDd36F0257aa714F562",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x48a51f5D38BE630Ddd6417Ea2D9052B8efc91a18",
+ "commit_store": "0xF97127e77252284EC9D4bc13C247c9D1A99F72B0",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xEC0cFe335a4d53dBA70CB650Ab56eEc32788F0BB",
+ "commit_store": "0x0ae3c2c7FB789bd05A450CD3075D11f6c2Ca4F77",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xf50c0d2a8B6Db60f1D93E60f03d0413D56153E4F",
+ "commit_store": "0x16f72C15165f7C9d74c12fDF188E399d4d3724e4",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x75F29f058b31106F99caFdc17c9b26ADfcC7b5D7",
+ "commit_store": "0xb719616E732581B570232DfB13Ca49D27667Af9f",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "BSC Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x404460C6A5EdE2D891e8297795264fDe62ADBB75",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x3DB43b96B2625F4232e9Df900d464dd2c64C0021",
+ "router": "0x34B03Cb9086d7D758AC55af71584F81A598759FE",
+ "price_registry": "0xd64aAbD70A71d9f0A00B99F6EFc1626aA2dD43C7",
+ "wrapped_native": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
+ "src_contracts": {
+ "Avalanche Mainnet": {
+ "on_ramp": "0x6aa72a998859eF93356c6521B72155D355D0Cfd2",
+ "deployed_at": 11111111
+ },
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x2788b46BAcFF49BD89562e6bA5c5FBbbE5Fa92F7",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x70bC7f7a6D936b289bBF5c0E19ECE35B437E2e36",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x0Bf40b034872D0b364f3DCec04C7434a4Da1C8d9",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x4FEB11A454C9E8038A8d0aDF599Fe7612ce114bA",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x6bD4754D86fc87FE5b463D368f26a3587a08347c",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x1467fF8f249f5bc604119Af26a47035886f856BE",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Mainnet": {
+ "off_ramp": "0x37a6fa55fe61061Ae97bF7314Ae270eCF71c5ED3",
+ "commit_store": "0x1f558F6dcf0224Ef1F78A24814FED548B9602c80",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x3DA330fd8Ef10d93cFB7D4f8ecE7BC1F10811feC",
+ "commit_store": "0x86D55Ff492cfBBAf0c0D42D4EE615144E78b3D02",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0x574c697deab06B805D8780898B3F136a1F4892Dc",
+ "commit_store": "0x002B164b1dcf4E92F352DC625A01Be0E890EdEea",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x181Bb1E97b0bDD1D85E741ad0943552D3682cc35",
+ "commit_store": "0x3fF27A34fF0FA77921C3438e67f58da1a83e9Ce1",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xE7E080C8d62d595a223C577C7C8d1f75d9A5E664",
+ "commit_store": "0xF4d53346bDb6d393C74B0B72Aa7D6689a3eAad79",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x26af2046Da85d7f6712D5edCa81B9E3b2e7A60Ab",
+ "commit_store": "0x4C1dA405a789AC2853A69D8290B8B9b47a0374F8",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xC027C5AEb230008c243Be463A73571e581F94c13",
+ "commit_store": "0x2EB426C8C54D740d1FC856eB3Ff96feA03957978",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Ethereum Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x514910771AF9Ca656af840dff83E8264EcF986CA",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x8B63b3DE93431C0f756A493644d128134291fA1b",
+ "router": "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D",
+ "price_registry": "0x8c9b2Efb7c64C394119270bfecE7f54763b958Ad",
+ "wrapped_native": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x925228D7B82d883Dde340A55Fe8e6dA56244A22C",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0x3df8dAe2d123081c4D5E946E655F7c109B9Dd630",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0xe2c2AB221AA0b957805f229d2AA57fBE2f4dADf7",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x91D25A56Db77aD5147437d8B83Eb563D46eBFa69",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x86B47d8411006874eEf8E4584BdFD7be8e5549d1",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x35F0ca9Be776E4B38659944c257bDd0ba75F1B8B",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0xCbE7e5DA76dC99Ac317adF6d99137005FDA4E2C4",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0xeFC4a18af59398FF23bfe7325F2401aD44286F4d",
+ "commit_store": "0x9B2EEd6A1e16cB50Ed4c876D2dD69468B21b7749",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x569940e02D4425eac61A7601632eC00d69f75c17",
+ "commit_store": "0x2aa101BF99CaeF7fc1355D4c493a1fe187A007cE",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xdf85c8381954694E74abD07488f452b4c2Cddfb3",
+ "commit_store": "0x8DC27D621c41a32140e22E2a4dAf1259639BAe04",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x7Afe7088aff57173565F4b034167643AA8b9171c",
+ "commit_store": "0x87c55D48DF6EF7B08153Ab079e76bFEcbb793D75",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xB095900fB91db00E6abD247A5A5AD1cee3F20BF7",
+ "commit_store": "0x4af4B497c998007eF83ad130318eB2b925a79dc8",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x0af338F0E314c7551bcE0EF516d46d855b0Ee395",
+ "commit_store": "0xD37a60E8C36E802D2E1a6321832Ee85556Beeb76",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x3a129e6C18b23d18BA9E6Aa14Dc2e79d1f91c6c5",
+ "commit_store": "0x31f6ab382DDeb9A316Ab61C3945a5292a50a89AB",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Kroma Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xC1F6f7622ad37C3f46cDF6F8AA0344ADE80BF450",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xB59779d3364BC6d71168245f9ebb96469E5a5a98",
+ "router": "0xE93E8B0d1b1CEB44350C8758ed1E2799CCee31aB",
+ "price_registry": "0x8155B4710e7bbC90924E957104F94Afd4f95Eca2",
+ "wrapped_native": "0x4200000000000000000000000000000000000001",
+ "src_contracts": {
+ "WeMix Mainnet": {
+ "on_ramp": "0x3C5Ab46fA1dB1dECD854224654313a69bf9fcAD3",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "WeMix Mainnet": {
+ "off_ramp": "0x2B555774B3D1dcbcd76efb7751F3c5FbCFABC5C4",
+ "commit_store": "0x213124614aAf31eBCE7c612A12aac5f8aAD77DE4",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Optimism Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x8C7C2C3362a42308BB5c368677Ad321D11693b81",
+ "router": "0x3206695CaE29952f4b0c22a169725a865bc8Ce0f",
+ "price_registry": "0xb52545aECE8C73A97E52a146757EC15b90Ed8488",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x0C9BE7Cfd12c735E5aaE047C1dCB845d54E518C3",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xD0D3E757bFBce7ae1881DDD7F6d798DDcE588445",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x0b1760A8112183303c5526C6b24569fd3A274f3B",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xa3c9544B82846C45BE37593d5d9ACffbE61BF3A6",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x55183Db1d2aE0b63e4c92A64bEF2CBfc2032B127",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x6B57145e322c877E7D91Ed8E31266eB5c02F7EfC",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x82e9f4C5ec4a84E310d60D462a12042E5cbA0954",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x0C9BE7Cfd12c735E5aaE047C1dCB845d54E518C3",
+ "commit_store": "0x55028780918330FD00a34a61D9a7Efd3f43ca845",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x8dc6490A6204dF846BaBE809cB695ba17Df1F9B1",
+ "commit_store": "0xA190660787B6B183Dd82B243eA10e609327c7308",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xBAE6560eCa9B77Cb047158C783e36F7735C86037",
+ "commit_store": "0x6168aDF58e1Ad446BaD45c6275Bef60Ef4FFBAb8",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0xE14501F2838F2fA1Ceb52E78ABdA289EcE1705EA",
+ "commit_store": "0xa8DD25B29787527Df283211C24Ac72B17150A696",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xd2D98Be6a1C241e86C807e51cED6ABb51d044203",
+ "commit_store": "0x4d75A5cE454b264b187BeE9e189aF1564a68408D",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x7c6221880A1D62506b1A08Dab3Bf695A49AcDD22",
+ "commit_store": "0x0684076EE3595221861C50cDb9Cb66402Ec11Cb9",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x3e5B3b7559D39563a74434157b31781322dA712D",
+ "commit_store": "0x7954372FF6f80908e5A2dC2a19d796A1005f91D2",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Polygon Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xD7AcF65dA1E1f34b663aB199a474F209bF2b0523",
+ "router": "0x849c5ED5a80F5B408Dd4969b78c2C8fdf0565Bfe",
+ "price_registry": "0x30D873664Ba766C983984C7AF9A921ccE36D34e1",
+ "wrapped_native": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0xD16D025330Edb91259EEA8ed499daCd39087c295",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0x5FA30697e90eB30954895c45b028F7C0dDD39b12",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x20B028A2e0F6CCe3A11f3CE5F2B8986F932e89b4",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xF5b5A2fC11BF46B1669C3B19d98B19C79109Dca9",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xFd77c53AA4eF0E3C01f5Ac012BF7Cc7A3ECf5168",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x3111cfbF5e84B5D9BD952dd8e957f4Ca75f728Cf",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x5060eF647a1F66BE6eE27FAe3046faf8D53CeB2d",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0xa8a9eDa2867c2E0CE0d5ECe273961F1EcC3CC25B",
+ "commit_store": "0xbD4480658dca8496a65046dfD1BDD44EF897Bdb5",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0xB9e3680639c9F0C4e0b02FD81C445094426244Ae",
+ "commit_store": "0x8c63d4e67f7c4af6FEd2f56A34fB4e01CB807CFF",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xD0FA7DE2D18A0c59D3fD7dfC7aB4e913C6Aa7b68",
+ "commit_store": "0xF88053B9DAC8Dd3039a4eFa8639159aaa3F2D4Cb",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x592773924741F0Da889a0dfdab71171Dd11E054C",
+ "commit_store": "0xEC4d35E1A85f770f4D93BA43a462c9d87Ef7017e",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x45320085fF051361D301eC1044318213A5387A15",
+ "commit_store": "0x4Dc771B5ef21ef60c33e2987E092345f2b63aE08",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xBa754ecd3CFA7E9093F688EAc3860cf9D07Fc0AC",
+ "commit_store": "0x04C0D5302E3D8Ca0A0019141a52a23B59cdb70e4",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xd7c877ea02310Cce9278D9A048Aa1Bb9aF72F00d",
+ "commit_store": "0x92A1C927E8E10Ab6A40E5A5154e2300D278d1a67",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "WeMix Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x80f1FcdC96B55e459BF52b998aBBE2c364935d69",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x07aaC8B69A62dB5bd3d244091916EbF2fac17b76",
+ "router": "0x7798b795Fde864f4Cd1b124a38Ba9619B7F8A442",
+ "price_registry": "0x252863688762aD86868D3d3076233Eacd80c7055",
+ "wrapped_native": "0x7D72b22a74A216Af4a002a1095C8C707d6eC1C5f",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x9aBfd6f4C865610692AB6fb1Be862575809fFabf",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xbE0Cfae74677F8dd16a246a3a5c8cbB1973118f4",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x56657ec4D15C71f7F3C17ba2b21C853A24Dc5381",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x70f3b0FD7e6a4B9B623e9AB859604A9EE03e48BD",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x777058C1e1dcE4eB8001F38631a1cd9450816e5a",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x190bcE84CF2d500B878966F4Cf98a50d78f2675E",
+ "deployed_at": 11111111
+ },
+ "Kroma Mainnet": {
+ "on_ramp": "0x47E9AE0A815C94836202E696748A5d5476aD8735",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x2ba68a395B72a6E3498D312efeD755ed2f3CF223",
+ "commit_store": "0xdAeC234DA83F68707Bb8AcB2ee6a01a5FD4c2391",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0xFac907F9a1087B846Faa75A14C5d34A8639233d8",
+ "commit_store": "0xF2812063446c7deD2CA306c67A68364BdDcbEfc5",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x6ec9ca4Cba62cA17c55F05ad2000B46192f02035",
+ "commit_store": "0x84534BE763366a69710E119c100832955795B34B",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0x87220D01DF0fF27149B47227897074653788fd23",
+ "commit_store": "0xF8dD2be2C6FA43e48A17146380CbEBBB4291807b",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x8f0229804513A9Bc00c1308414AB279Dbc718ae1",
+ "commit_store": "0x3A85D1b8641d83a87957C6ECF1b62151213e0842",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xF92Fa796F5307b029c65CA26f322a6D86f211194",
+ "commit_store": "0xbeC110FF43D52be2066B06525304A9924E16b73b",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Kroma Mainnet": {
+ "off_ramp": "0xF886d8DC64E544af4835cbf91e5678A54D95B80e",
+ "commit_store": "0x8794C9534658fdCC44f2FF6645Bf31cf9F6d2d5D",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/contracts/laneconfig/contracts.json b/integration-tests/ccip-tests/contracts/laneconfig/contracts.json
new file mode 100644
index 00000000000..4d20e2a4d57
--- /dev/null
+++ b/integration-tests/ccip-tests/contracts/laneconfig/contracts.json
@@ -0,0 +1,243 @@
+{
+ "lane_configs": {
+ "Arbitrum Mainnet": {
+ "fee_token": "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4",
+ "bridge_tokens": [
+ "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4"
+ ],
+ "bridge_tokens_pools": [
+ ""
+ ],
+ "arm": "0xe06b0e8c4bd455153e8794ad7Ea8Ff5A14B64E4b",
+ "router": "0xE92634289A1841A979C11C2f618B33D376e4Ba85",
+ "price_registry": "0xeBec5Cb8651FCD0Fd86Bd1BBb8562f5028D5102E",
+ "wrapped_native": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
+ "src_contracts": {
+ "Ethereum Mainnet": {
+ "on_ramp": "0x98dd9E9b8AE458225119Ab5B8c947A9d1cd0B648",
+ "deployed_at": 126471491
+ }
+ },
+ "dest_contracts": {
+ "Ethereum Mainnet": {
+ "off_ramp": "0x7b1f908ceBf41d5829D0134c7dfD6aa0f163C97d",
+ "commit_store": "0x8E2adA223f8514C2E6E6Fb0877a19018B67256fF",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Avalanche Mainnet": {
+ "fee_token": "0x5947BB275c521040051D82396192181b413227A3",
+ "bridge_tokens": [
+ "0x5947BB275c521040051D82396192181b413227A3"
+ ],
+ "bridge_tokens_pools": [
+ "0x8A3e8D8614189d7ad0CF3f1a0D787Da79eBCEc17"
+ ],
+ "arm": "0xdFD6C0dc67666DE3bB36b31eec5c7B1542A82C1E",
+ "router": "0x27F39D0af3303703750D4001fCc1844c6491563c",
+ "price_registry": "0x2d3b38E0a4DFFDad2A613f7760bE1683F272eA18",
+ "wrapped_native": "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7",
+ "src_contracts": {
+ "Ethereum Mainnet": {
+ "on_ramp": "0x3D3817270db2b89e9F68bA27297fb4672082f942",
+ "deployed_at": 32263102
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x2d306510FE83Cdb33Ff1658c71C181e9567F0009",
+ "deployed_at": 32562460
+ }
+ },
+ "dest_contracts": {
+ "Ethereum Mainnet": {
+ "off_ramp": "0x2BF2611a07e2cA880b814d53325e9b2ee0BbfD2f",
+ "commit_store": "0x5eBE880c4d340892dA1b0F32798a7A28e17e6E65",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0xC65F15b8178c2Fd653183130C6E003d196C39eC2",
+ "commit_store": "0xa9DC27fAc318fdDCa08E215ca157Fa5C7A832d80",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Base Mainnet": {
+ "fee_token": "0x88Fb150BDc53A65fe94Dea0c9BA0a6dAf8C6e196",
+ "arm": "0x38660c8CC222c0192b635c2ac09687B4F25cCE5F",
+ "router": "0x673AA85efd75080031d44fcA061575d1dA427A28",
+ "price_registry": "0x1bA15c57c8b74cD32443D7583E7f6d7c638aCf46",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Ethereum Mainnet": {
+ "on_ramp": "0xD44371bFDe87f2db3eA6Df242091351A06c2e181",
+ "deployed_at": 3316617
+ }
+ },
+ "dest_contracts": {
+ "Ethereum Mainnet": {
+ "off_ramp": "0x391B9B016C3bBA61F02e7ddd345130415908B9c7",
+ "commit_store": "0x398d2164a3F61353B4619814A31cC74A7741612E",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "BSC Mainnet": {
+ "fee_token": "0x404460C6A5EdE2D891e8297795264fDe62ADBB75",
+ "bridge_tokens": [
+ "0x404460C6A5EdE2D891e8297795264fDe62ADBB75"
+ ],
+ "bridge_tokens_pools": [
+ ""
+ ],
+ "arm": "0x3DB43b96B2625F4232e9Df900d464dd2c64C0021",
+ "router": "0x536d7E53D0aDeB1F20E7c81fea45d02eC9dBD698",
+ "price_registry": "0x18C3D917D55Bc1784a3d4729AA3e2C1ecd662fFd",
+ "wrapped_native": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
+ "src_contracts": {
+ "Ethereum Mainnet": {
+ "on_ramp": "0x1f17D464652f5Bd74a03446FeA20590CCfB3332D",
+ "deployed_at": 31312405
+ }
+ },
+ "dest_contracts": {
+ "Ethereum Mainnet": {
+ "off_ramp": "0xEcaa7473b57956647C8Cff5a909520e7A0A4a5f6",
+ "commit_store": "0x9C68a868db2C27E9A7Ce43b73272A5d7ecFB5865",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Ethereum Mainnet": {
+ "fee_token": "0x514910771AF9Ca656af840dff83E8264EcF986CA",
+ "bridge_tokens": [
+ "0x514910771AF9Ca656af840dff83E8264EcF986CA"
+ ],
+ "bridge_tokens_pools": [
+ "0xC2291992A08eBFDfedfE248F2CCD34Da63570DF4"
+ ],
+ "arm": "0x8B63b3DE93431C0f756A493644d128134291fA1b",
+ "router": "0xE561d5E02207fb5eB32cca20a699E0d8919a1476",
+ "price_registry": "0x020082A7a9c2510e1921116001152DEE4da81985",
+ "wrapped_native": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x333f976915195ba9044fD0cd603cEcE936f6264e",
+ "deployed_at": 18029393
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xd0B5Fc9790a6085b048b8Aa1ED26ca2b3b282CF2",
+ "deployed_at": 17636709
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xdF1d7FD22aC3aB5171E275796f123224039f3b24",
+ "deployed_at": 18029385
+ },
+ "Base Mainnet": {
+ "on_ramp": "0xe2Eb229e88F56691e96bb98256707Bc62160FE73",
+ "deployed_at": 18029431
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0xCC19bC4D43d17eB6859F0d22BA300967C97780b0",
+ "deployed_at": 17636647
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x0f27c8532457b66D6037141DEB0ed479Dad04B3c",
+ "deployed_at": 17636734
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x61135E701a2214C170c5F596D0067798FEfbaaE4",
+ "commit_store": "0x3d3467e1036Ee25F6F4aa15e3Abf77443A23144C",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x1C207dabc46902dF9028b27D6d301c3849b2D12c",
+ "commit_store": "0x40c558575093eC1099CC21B020d9b8D13c74417F",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0xC7176620daf49A39a17FF9A6C2DE1eAA6033EE94",
+ "commit_store": "0x7986C9892389854cAAbAC785ff18123B0070a5Fd",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xfF51C00546AA3d9051a4B96Ae81346E14709CD24",
+ "commit_store": "0x2D1708ff2a15adbE313eA8C6035aA24d0FBA1c77",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0x41627a90f2c6238f2BADAB72D5aB050B857fdAb5",
+ "commit_store": "0x8bEFCa744c6f2b567b1863dcF055C593afdC11A0",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0xBDd822f3bC2EAB6818CfA3053107831D4E93fE72",
+ "commit_store": "0x20718EfbC25Dba60FD51c2c81362b83f7C411A6D",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Optimism Mainnet": {
+ "fee_token": "0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6",
+ "bridge_tokens": [
+ "0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6"
+ ],
+ "bridge_tokens_pools": [
+ "0x841b32B5309ba30cFbf4534667fC3D99EdF05B7A"
+ ],
+ "arm": "0x8C7C2C3362a42308BB5c368677Ad321D11693b81",
+ "router": "0x261c05167db67B2b619f9d312e0753f3721ad6E8",
+ "price_registry": "0x9270AAA75F4B9038f4c25fEc665B02a150a90361",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Ethereum Mainnet": {
+ "on_ramp": "0xad1b1F2A6DD55627e3893B771A00Cd43F69DcE35",
+ "deployed_at": 106535110
+ }
+ },
+ "dest_contracts": {
+ "Ethereum Mainnet": {
+ "off_ramp": "0x032F957BfbB8C535a1b2048f8b4FA27E1F2018Fd",
+ "commit_store": "0xa4D34ca38244F6c8AB640315d7257221408B6596",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ },
+ "Polygon Mainnet": {
+ "fee_token": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1",
+ "bridge_tokens": [
+ "0xb0897686c545045aFc77CF20eC7A532E3120E0F1"
+ ],
+ "bridge_tokens_pools": [
+ "0x086892015567fb8764d02c6845C85C25C8FcA389"
+ ],
+ "arm": "0xD7AcF65dA1E1f34b663aB199a474F209bF2b0523",
+ "router": "0x3C3D92629A02a8D95D5CB9650fe49C3544f69B43",
+ "price_registry": "0x68590799942eed65f9f1fB2277B9F6584A5957B8",
+ "wrapped_native": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270",
+ "src_contracts": {
+ "Avalanche Mainnet": {
+ "on_ramp": "0x47D945f7bbb814B65775a89c71F5D2229BE96CE9",
+ "deployed_at": 45041759
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xAE0e486Fa6577188d586A8e4c12360FB82E2a386",
+ "deployed_at": 44762064
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Mainnet": {
+ "off_ramp": "0xd59A3770c3e05479152b8581Ae0839f51b315E6A",
+ "commit_store": "0xC2870bF94E24657f7f5E75cF458e391D23CD84B5",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xa73bf37F78CD1629ff11Fa2B397CED39F49F6efe",
+ "commit_store": "0x779cA414cAC21c76AbE9213861b1bE9187d495F9",
+ "receiver_dapp": "0xAFa2c441a83bBCEDc2E8c5c6f66248aFD8b9af3d"
+ }
+ }
+ }
+ }
+}
diff --git a/integration-tests/ccip-tests/contracts/laneconfig/parse_contracts.go b/integration-tests/ccip-tests/contracts/laneconfig/parse_contracts.go
new file mode 100644
index 00000000000..332bd48ab31
--- /dev/null
+++ b/integration-tests/ccip-tests/contracts/laneconfig/parse_contracts.go
@@ -0,0 +1,227 @@
+package laneconfig
+
+import (
+ _ "embed"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "sync"
+
+ "github.com/ethereum/go-ethereum/common"
+ "go.uber.org/multierr"
+)
+
+var (
+ //go:embed contracts.json
+ ExistingContracts []byte
+ laneMu = &sync.Mutex{}
+)
+
+type CommonContracts struct {
+ IsNativeFeeToken bool `json:"is_native_fee_token,omitempty"`
+ IsMockARM bool `json:"is_mock_arm,omitempty"`
+ FeeToken string `json:"fee_token"`
+ BridgeTokens []string `json:"bridge_tokens,omitempty"`
+ BridgeTokenPools []string `json:"bridge_tokens_pools,omitempty"`
+ PriceAggregators map[string]string `json:"price_aggregators,omitempty"`
+ ARM string `json:"arm"`
+ Router string `json:"router"`
+ PriceRegistry string `json:"price_registry,omitempty"`
+ WrappedNative string `json:"wrapped_native"`
+ Multicall string `json:"multicall,omitempty"`
+ TokenTransmitter string `json:"token_transmitter,omitempty"`
+ TokenMessenger string `json:"token_messenger,omitempty"`
+ TokenAdminRegistry string `json:"token_admin_registry,omitempty"`
+}
+
+type SourceContracts struct {
+ OnRamp string `json:"on_ramp"`
+ DeployedAt uint64 `json:"deployed_at"`
+}
+
+type DestContracts struct {
+ OffRamp string `json:"off_ramp"`
+ CommitStore string `json:"commit_store"`
+ ReceiverDapp string `json:"receiver_dapp"`
+}
+
+type LaneConfig struct {
+ CommonContracts
+ SrcContractsMu *sync.Mutex `json:"-"`
+ SrcContracts map[string]SourceContracts `json:"src_contracts"` // key destination chain id
+ DestContractsMu *sync.Mutex `json:"-"`
+ DestContracts map[string]DestContracts `json:"dest_contracts"` // key source chain id
+}
+
+func (l *LaneConfig) Validate() error {
+ var laneConfigError error
+
+ if l.ARM == "" || !common.IsHexAddress(l.ARM) {
+ laneConfigError = multierr.Append(laneConfigError, errors.New("must set proper address for arm"))
+ }
+
+ if l.FeeToken != "" && !common.IsHexAddress(l.FeeToken) {
+ laneConfigError = multierr.Append(laneConfigError, errors.New("must set proper address for fee_token"))
+ }
+
+ for _, token := range l.BridgeTokens {
+ if token != "" && !common.IsHexAddress(token) {
+ laneConfigError = multierr.Append(laneConfigError, errors.New("must set proper address for bridge_tokens"))
+ }
+ }
+
+ for _, pool := range l.BridgeTokenPools {
+ if pool != "" && !common.IsHexAddress(pool) {
+ laneConfigError = multierr.Append(laneConfigError, errors.New("must set proper address for bridge_tokens_pools"))
+ }
+ }
+ if l.Router == "" || !common.IsHexAddress(l.Router) {
+ laneConfigError = multierr.Append(laneConfigError, errors.New("must set proper address for router"))
+ }
+ if l.PriceRegistry == "" || !common.IsHexAddress(l.PriceRegistry) {
+ laneConfigError = multierr.Append(laneConfigError, errors.New("must set proper address for price_registry"))
+ }
+ if l.WrappedNative == "" || !common.IsHexAddress(l.WrappedNative) {
+ laneConfigError = multierr.Append(laneConfigError, errors.New("must set proper address for wrapped_native"))
+ }
+ if l.Multicall == "" || !common.IsHexAddress(l.Multicall) {
+ laneConfigError = multierr.Append(laneConfigError, errors.New("must set proper address for multicall"))
+ }
+ return laneConfigError
+}
+
+type Lanes struct {
+ LaneConfigs map[string]*LaneConfig `json:"lane_configs"`
+}
+
+func (l *Lanes) ReadLaneConfig(networkA string) *LaneConfig {
+ laneMu.Lock()
+ defer laneMu.Unlock()
+ cfg, ok := l.LaneConfigs[networkA]
+ if !ok {
+ l.LaneConfigs[networkA] = &LaneConfig{
+ SrcContracts: make(map[string]SourceContracts),
+ DestContracts: make(map[string]DestContracts),
+ SrcContractsMu: &sync.Mutex{},
+ DestContractsMu: &sync.Mutex{},
+ }
+ return l.LaneConfigs[networkA]
+ }
+ if cfg.SrcContractsMu == nil {
+ l.LaneConfigs[networkA].SrcContractsMu = &sync.Mutex{}
+ }
+ if cfg.DestContractsMu == nil {
+ l.LaneConfigs[networkA].DestContractsMu = &sync.Mutex{}
+ }
+ return l.LaneConfigs[networkA]
+}
+
+// CopyCommonContracts copies network config for common contracts from fromNetwork to toNetwork
+// if the toNetwork already exists, it does nothing
+// If reuse is set to false, it only retains the token contracts
+func (l *Lanes) CopyCommonContracts(fromNetwork, toNetwork string, reuse, isTokenTransfer bool) {
+ laneMu.Lock()
+ defer laneMu.Unlock()
+ // if the toNetwork already exists, return
+ if _, ok := l.LaneConfigs[toNetwork]; ok {
+ return
+ }
+ existing, ok := l.LaneConfigs[fromNetwork]
+ if !ok {
+ l.LaneConfigs[toNetwork] = &LaneConfig{
+ SrcContracts: make(map[string]SourceContracts),
+ DestContracts: make(map[string]DestContracts),
+ SrcContractsMu: &sync.Mutex{},
+ DestContractsMu: &sync.Mutex{},
+ }
+ return
+ }
+ cfg := &LaneConfig{
+ SrcContracts: make(map[string]SourceContracts),
+ SrcContractsMu: &sync.Mutex{},
+ DestContractsMu: &sync.Mutex{},
+ DestContracts: make(map[string]DestContracts),
+ CommonContracts: CommonContracts{
+ WrappedNative: existing.WrappedNative,
+ Multicall: existing.Multicall,
+ },
+ }
+ // if reuse is set to true, it copies all the common contracts except the router
+ if reuse {
+ cfg.CommonContracts.FeeToken = existing.FeeToken
+ cfg.CommonContracts.PriceRegistry = existing.PriceRegistry
+ cfg.CommonContracts.TokenAdminRegistry = existing.TokenAdminRegistry
+ cfg.CommonContracts.PriceAggregators = existing.PriceAggregators
+ cfg.CommonContracts.ARM = existing.ARM
+ cfg.CommonContracts.IsMockARM = existing.IsMockARM
+ cfg.CommonContracts.Multicall = existing.Multicall
+ }
+ // if it is a token transfer, it copies the bridge token contracts
+ if isTokenTransfer {
+ cfg.CommonContracts.BridgeTokens = existing.BridgeTokens
+ if reuse {
+ cfg.CommonContracts.BridgeTokenPools = existing.BridgeTokenPools
+ }
+ }
+ l.LaneConfigs[toNetwork] = cfg
+}
+
+func (l *Lanes) WriteLaneConfig(networkA string, cfg *LaneConfig) error {
+ laneMu.Lock()
+ defer laneMu.Unlock()
+ if l.LaneConfigs == nil {
+ l.LaneConfigs = make(map[string]*LaneConfig)
+ }
+ err := cfg.Validate()
+ if err != nil {
+ return err
+ }
+ l.LaneConfigs[networkA] = cfg
+ return nil
+}
+
+func ReadLanesFromExistingDeployment(contracts []byte) (*Lanes, error) {
+ // if contracts is empty, use the existing contracts from contracts.json
+ if len(contracts) == 0 {
+ contracts = ExistingContracts
+ }
+ var lanes Lanes
+ if err := json.Unmarshal(contracts, &lanes); err != nil {
+ return nil, err
+ }
+ return &lanes, nil
+}
+
+func CreateDeploymentJSON(path string) (*Lanes, error) {
+ existingLanes := Lanes{
+ LaneConfigs: make(map[string]*LaneConfig),
+ }
+ err := WriteLanesToJSON(path, &existingLanes)
+ return &existingLanes, err
+}
+
+func WriteLanesToJSON(path string, lanes *Lanes) error {
+ b, err := json.MarshalIndent(lanes, "", " ")
+ if err != nil {
+ return err
+ }
+ // Get the directory part of the file path.
+ dir := filepath.Dir(path)
+ // Check if the directory exists.
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ // The directory does not exist, create it.
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ return fmt.Errorf("failed to create directory: %w", err)
+ }
+ }
+
+ f, err := os.Create(path)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ _, err = f.Write(b)
+ return err
+}
diff --git a/integration-tests/ccip-tests/contracts/multicall.go b/integration-tests/ccip-tests/contracts/multicall.go
new file mode 100644
index 00000000000..7db7f37519b
--- /dev/null
+++ b/integration-tests/ccip-tests/contracts/multicall.go
@@ -0,0 +1,280 @@
+package contracts
+
+import (
+ "context"
+ "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"
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog/log"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/erc20"
+)
+
+const (
+ MultiCallABI = "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call3[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call3Value[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3Value\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"blockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBasefee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"basefee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryAggregate\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryBlockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]"
+ MultiCallBIN = "0x608060405234801561001057600080fd5b50610ee0806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461025a578063bce38bd714610275578063c3077fa914610288578063ee82ac5e1461029b57600080fd5b80634d2301cc146101ec57806372425d9d1461022157806382ad56cb1461023457806386d516e81461024757600080fd5b80633408e470116100c65780633408e47014610191578063399542e9146101a45780633e64a696146101c657806342cbb15c146101d957600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d610128366004610a85565b6102ba565b6040516101119190610bbe565b61014d610148366004610a85565b6104ef565b604051610111929190610bd8565b34801561016757600080fd5b50437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0140610107565b34801561019d57600080fd5b5046610107565b6101b76101b2366004610c60565b610690565b60405161011193929190610cba565b3480156101d257600080fd5b5048610107565b3480156101e557600080fd5b5043610107565b3480156101f857600080fd5b50610107610207366004610ce2565b73ffffffffffffffffffffffffffffffffffffffff163190565b34801561022d57600080fd5b5044610107565b61012d610242366004610a85565b6106ab565b34801561025357600080fd5b5045610107565b34801561026657600080fd5b50604051418152602001610111565b61012d610283366004610c60565b61085a565b6101b7610296366004610a85565b610a1a565b3480156102a757600080fd5b506101076102b6366004610d18565b4090565b60606000828067ffffffffffffffff8111156102d8576102d8610d31565b60405190808252806020026020018201604052801561031e57816020015b6040805180820190915260008152606060208201528152602001906001900390816102f65790505b5092503660005b8281101561047757600085828151811061034157610341610d60565b6020026020010151905087878381811061035d5761035d610d60565b905060200281019061036f9190610d8f565b6040810135958601959093506103886020850185610ce2565b73ffffffffffffffffffffffffffffffffffffffff16816103ac6060870187610dcd565b6040516103ba929190610e32565b60006040518083038185875af1925050503d80600081146103f7576040519150601f19603f3d011682016040523d82523d6000602084013e6103fc565b606091505b50602080850191909152901515808452908501351761046d577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b5050600101610325565b508234146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561050c5761050c610d31565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b5091503660005b8281101561068657600087878381811061056257610562610d60565b90506020028101906105749190610e42565b92506105836020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166105a66020850185610dcd565b6040516105b4929190610e32565b6000604051808303816000865af19150503d80600081146105f1576040519150601f19603f3d011682016040523d82523d6000602084013e6105f6565b606091505b5086848151811061060957610609610d60565b602090810291909101015290508061067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b50600101610546565b5050509250929050565b43804060606106a086868661085a565b905093509350939050565b6060818067ffffffffffffffff8111156106c7576106c7610d31565b60405190808252806020026020018201604052801561070d57816020015b6040805180820190915260008152606060208201528152602001906001900390816106e55790505b5091503660005b828110156104e657600084828151811061073057610730610d60565b6020026020010151905086868381811061074c5761074c610d60565b905060200281019061075e9190610e76565b925061076d6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166107906040850185610dcd565b60405161079e929190610e32565b6000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b506020808401919091529015158083529084013517610851577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b50600101610714565b6060818067ffffffffffffffff81111561087657610876610d31565b6040519080825280602002602001820160405280156108bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816108945790505b5091503660005b82811015610a105760008482815181106108df576108df610d60565b602002602001015190508686838181106108fb576108fb610d60565b905060200281019061090d9190610e42565b925061091c6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff1661093f6020850185610dcd565b60405161094d929190610e32565b6000604051808303816000865af19150503d806000811461098a576040519150601f19603f3d011682016040523d82523d6000602084013e61098f565b606091505b506020830152151581528715610a07578051610a07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b506001016108c3565b5050509392505050565b6000806060610a2b60018686610690565b919790965090945092505050565b60008083601f840112610a4b57600080fd5b50813567ffffffffffffffff811115610a6357600080fd5b6020830191508360208260051b8501011115610a7e57600080fd5b9250929050565b60008060208385031215610a9857600080fd5b823567ffffffffffffffff811115610aaf57600080fd5b610abb85828601610a39565b90969095509350505050565b6000815180845260005b81811015610aed57602081850181015186830182015201610ad1565b81811115610aff576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b84811015610bb1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051151584528401516040858501819052610b9d81860183610ac7565b9a86019a9450505090830190600101610b4f565b5090979650505050505050565b602081526000610bd16020830184610b32565b9392505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610c52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452610c40868351610ac7565b95509284019290840190600101610c06565b509398975050505050505050565b600080600060408486031215610c7557600080fd5b83358015158114610c8557600080fd5b9250602084013567ffffffffffffffff811115610ca157600080fd5b610cad86828701610a39565b9497909650939450505050565b838152826020820152606060408201526000610cd96060830184610b32565b95945050505050565b600060208284031215610cf457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610bd157600080fd5b600060208284031215610d2a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112610dc357600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e0257600080fd5b83018035915067ffffffffffffffff821115610e1d57600080fd5b602001915036819003821315610a7e57600080fd5b8183823760009101908152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610dc357600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610dc357600080fdfea2646970667358221220bb2b5c71a328032f97c676ae39a1ec2148d3e5d6f73d95e9b17910152d61f16264736f6c634300080c0033"
+)
+
+type CallWithValue struct {
+ Target common.Address
+ AllowFailure bool
+ Value *big.Int
+ CallData []byte
+}
+
+type Call struct {
+ Target common.Address
+ AllowFailure bool
+ CallData []byte
+}
+
+type Result struct {
+ Success bool
+ ReturnData []byte
+}
+type CCIPMsgData struct {
+ RouterAddr common.Address
+ ChainSelector uint64
+ Msg router.ClientEVM2AnyMessage
+ Fee *big.Int
+}
+
+func TransferTokenCallData(to common.Address, amount *big.Int) ([]byte, error) {
+ erc20ABI, err := abi.JSON(strings.NewReader(erc20.ERC20ABI))
+ if err != nil {
+ return nil, err
+ }
+ transferToken := erc20ABI.Methods["transfer"]
+ inputs, err := transferToken.Inputs.Pack(to, amount)
+ if err != nil {
+ return nil, err
+ }
+ inputs = append(transferToken.ID[:], inputs...)
+ return inputs, nil
+}
+
+// ApproveTokenCallData returns the call data for approving a token with approve function of erc20 contract
+func ApproveTokenCallData(to common.Address, amount *big.Int) ([]byte, error) {
+ erc20ABI, err := abi.JSON(strings.NewReader(erc20.ERC20ABI))
+ if err != nil {
+ return nil, err
+ }
+ approveToken := erc20ABI.Methods["approve"]
+ inputs, err := approveToken.Inputs.Pack(to, amount)
+ if err != nil {
+ return nil, err
+ }
+ inputs = append(approveToken.ID[:], inputs...)
+ return inputs, nil
+}
+
+// CCIPSendCallData returns the call data for sending a CCIP message with ccipSend function of router contract
+func CCIPSendCallData(msg CCIPMsgData) ([]byte, error) {
+ routerABI, err := abi.JSON(strings.NewReader(router.RouterABI))
+ if err != nil {
+ return nil, err
+ }
+ ccipSend := routerABI.Methods["ccipSend"]
+ sendID := ccipSend.ID
+ inputs, err := ccipSend.Inputs.Pack(
+ msg.ChainSelector,
+ msg.Msg,
+ )
+ if err != nil {
+ return nil, err
+ }
+ inputs = append(sendID[:], inputs...)
+ return inputs, nil
+}
+
+func WaitForSuccessfulTxMined(evmClient blockchain.EVMClient, tx *types.Transaction) error {
+ log.Info().Str("tx", tx.Hash().Hex()).Msg("waiting for tx to be mined")
+ receipt, err := bind.WaitMined(context.Background(), evmClient.DeployBackend(), tx)
+ if err != nil {
+ return err
+ }
+ if receipt.Status != types.ReceiptStatusSuccessful {
+ // TODO: Add error reason from receipt/tx
+ return fmt.Errorf("tx failed %s", tx.Hash().Hex())
+ }
+ log.Info().Str("tx", tx.Hash().Hex()).Str("Network", evmClient.GetNetworkName()).Msg("tx mined successfully")
+ return nil
+}
+
+// MultiCallCCIP sends multiple CCIP messages in a single transaction
+// if native is true, it will send msg with native as fee. In this case the msg should be sent with a
+// msg.value equivalent to the total fee with the help of aggregate3Value
+//
+// if native is false, it will send msg with fee in specific feetoken. In this case the msg should be sent without value with the help of aggregate3.
+// In both cases, if there are any bridge tokens included in ccip transfer, the amount for corresponding token should be approved to the router contract as spender.
+// The approval should be done by calling approval function as part of the call data of aggregate3 or aggregate3Value
+// If feetoken is used as fee, the amount for feetoken should be approved to the router contract as spender and should be done as part of the call data of aggregate3
+// In case of native as fee, there is no need for fee amount approval
+func MultiCallCCIP(
+ evmClient blockchain.EVMClient,
+ address string,
+ msgData []CCIPMsgData,
+ native bool,
+) (*types.Transaction, error) {
+ contractAddress := common.HexToAddress(address)
+ multiCallABI, err := abi.JSON(strings.NewReader(MultiCallABI))
+ if err != nil {
+ return nil, err
+ }
+ boundContract := bind.NewBoundContract(contractAddress, multiCallABI, evmClient.Backend(), evmClient.Backend(), evmClient.Backend())
+
+ // if native, use aggregate3Value to send msg with value
+ if native {
+ var callData []CallWithValue
+ allValue := big.NewInt(0)
+ // create call data for each msg
+ for _, msg := range msgData {
+ if msg.Msg.FeeToken != (common.Address{}) {
+ return nil, fmt.Errorf("fee token should be %s for native as fee", common.HexToAddress("0x0").Hex())
+ }
+ // approve bridge token
+ for _, tokenAndAmount := range msg.Msg.TokenAmounts {
+ inputs, err := ApproveTokenCallData(msg.RouterAddr, tokenAndAmount.Amount)
+ if err != nil {
+ return nil, err
+ }
+ data := CallWithValue{Target: tokenAndAmount.Token, AllowFailure: false, Value: big.NewInt(0), CallData: inputs}
+ callData = append(callData, data)
+ }
+ inputs, err := CCIPSendCallData(msg)
+ if err != nil {
+ return nil, err
+ }
+ data := CallWithValue{Target: msg.RouterAddr, AllowFailure: false, Value: msg.Fee, CallData: inputs}
+ callData = append(callData, data)
+ allValue.Add(allValue, msg.Fee)
+ }
+
+ opts, err := evmClient.TransactionOpts(evmClient.GetDefaultWallet())
+ if err != nil {
+ return nil, err
+ }
+ // the value of transactionOpts is the sum of the value of all msg, which is the total fee of all ccip-sends
+ opts.Value = allValue
+
+ // call aggregate3Value to group all msg call data and send them in a single transaction
+ tx, err := boundContract.Transact(opts, "aggregate3Value", callData)
+ if err != nil {
+ return nil, err
+ }
+ err = evmClient.MarkTxAsSentOnL2(tx)
+ if err != nil {
+ return nil, err
+ }
+ err = WaitForSuccessfulTxMined(evmClient, tx)
+ if err != nil {
+ return nil, errors.Wrapf(err, "multicall failed for ccip-send; multicall %s", contractAddress.Hex())
+ }
+ return tx, nil
+ }
+ // if with feetoken, use aggregate3 to send msg without value
+ var callData []Call
+ // create call data for each msg
+ for _, msg := range msgData {
+ isFeeTokenAndBridgeTokenSame := false
+ // approve bridge token
+ for _, tokenAndAmount := range msg.Msg.TokenAmounts {
+ var inputs []byte
+ // if feetoken is same as bridge token, approve total amount including transfer amount + fee amount
+ if tokenAndAmount.Token == msg.Msg.FeeToken {
+ isFeeTokenAndBridgeTokenSame = true
+ inputs, err = ApproveTokenCallData(msg.RouterAddr, new(big.Int).Add(msg.Fee, tokenAndAmount.Amount))
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ inputs, err = ApproveTokenCallData(msg.RouterAddr, tokenAndAmount.Amount)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ callData = append(callData, Call{Target: tokenAndAmount.Token, AllowFailure: false, CallData: inputs})
+ }
+ // approve fee token if not already approved
+ if msg.Fee != nil && msg.Fee.Cmp(big.NewInt(0)) > 0 && !isFeeTokenAndBridgeTokenSame {
+ inputs, err := ApproveTokenCallData(msg.RouterAddr, msg.Fee)
+ if err != nil {
+ return nil, err
+ }
+ callData = append(callData, Call{Target: msg.Msg.FeeToken, AllowFailure: false, CallData: inputs})
+ }
+
+ inputs, err := CCIPSendCallData(msg)
+ if err != nil {
+ return nil, err
+ }
+ callData = append(callData, Call{Target: msg.RouterAddr, AllowFailure: false, CallData: inputs})
+ }
+ opts, err := evmClient.TransactionOpts(evmClient.GetDefaultWallet())
+ if err != nil {
+ return nil, err
+ }
+
+ // call aggregate3 to group all msg call data and send them in a single transaction
+ tx, err := boundContract.Transact(opts, "aggregate3", callData)
+ if err != nil {
+ return nil, err
+ }
+ err = WaitForSuccessfulTxMined(evmClient, tx)
+ if err != nil {
+ return tx, errors.Wrapf(err, "multicall failed for ccip-send; router %s", contractAddress.Hex())
+ }
+ return tx, nil
+}
+
+func TransferTokens(
+ evmClient blockchain.EVMClient,
+ contractAddress common.Address,
+ tokens []*ERC20Token,
+) error {
+ multiCallABI, err := abi.JSON(strings.NewReader(MultiCallABI))
+ if err != nil {
+ return err
+ }
+ var callData []Call
+ boundContract := bind.NewBoundContract(contractAddress, multiCallABI, evmClient.Backend(), evmClient.Backend(), evmClient.Backend())
+ for _, token := range tokens {
+ var inputs []byte
+ balance, err := token.BalanceOf(context.Background(), contractAddress.Hex())
+ if err != nil {
+ return err
+ }
+ inputs, err = TransferTokenCallData(common.HexToAddress(evmClient.GetDefaultWallet().Address()), balance)
+ if err != nil {
+ return err
+ }
+ data := Call{Target: token.ContractAddress, AllowFailure: false, CallData: inputs}
+ callData = append(callData, data)
+ }
+
+ opts, err := evmClient.TransactionOpts(evmClient.GetDefaultWallet())
+ if err != nil {
+ return err
+ }
+
+ // call aggregate3 to group all msg call data and send them in a single transaction
+ tx, err := boundContract.Transact(opts, "aggregate3", callData)
+ if err != nil {
+ return err
+ }
+ err = WaitForSuccessfulTxMined(evmClient, tx)
+ if err != nil {
+ return errors.Wrapf(err, "token transfer failed for token; router %s", contractAddress.Hex())
+ }
+ return nil
+}
diff --git a/integration-tests/ccip-tests/load/ccip_loadgen.go b/integration-tests/ccip-tests/load/ccip_loadgen.go
new file mode 100644
index 00000000000..4ed54a45fdb
--- /dev/null
+++ b/integration-tests/ccip-tests/load/ccip_loadgen.go
@@ -0,0 +1,363 @@
+package load
+
+import (
+ "context"
+ crypto_rand "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "math/big"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/AlekSi/pointer"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/rs/zerolog"
+ chain_selectors "github.com/smartcontractkit/chain-selectors"
+ "github.com/smartcontractkit/wasp"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/atomic"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig"
+ "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+ "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testreporters"
+)
+
+// CCIPLaneOptimized is a light-weight version of CCIPLane, It only contains elements which are used during load triggering and validation
+type CCIPLaneOptimized struct {
+ Logger *zerolog.Logger
+ SourceNetworkName string
+ DestNetworkName string
+ Source *actions.SourceCCIPModule
+ Dest *actions.DestCCIPModule
+ Reports *testreporters.CCIPLaneStats
+}
+
+type CCIPE2ELoad struct {
+ t *testing.T
+ Lane *CCIPLaneOptimized
+ NoOfReq int64 // approx no of Request fired
+ CurrentMsgSerialNo *atomic.Int64 // current msg serial number in the load sequence
+ CallTimeOut time.Duration // max time to wait for various on-chain events
+ msg router.ClientEVM2AnyMessage
+ MaxDataBytes uint32
+ SendMaxDataIntermittentlyInMsgCount int64
+ SkipRequestIfAnotherRequestTriggeredWithin *config.Duration
+ LastFinalizedTxBlock atomic.Uint64
+ LastFinalizedTimestamp atomic.Time
+ MsgProfiles *testconfig.MsgProfile
+ EOAReceiver []byte
+}
+
+func NewCCIPLoad(
+ t *testing.T,
+ lane *actions.CCIPLane,
+ timeout time.Duration,
+ noOfReq int64,
+ m *testconfig.MsgProfile,
+ sendMaxDataIntermittentlyInEveryMsgCount int64,
+ SkipRequestIfAnotherRequestTriggeredWithin *config.Duration,
+) *CCIPE2ELoad {
+ // to avoid holding extra data
+ loadLane := &CCIPLaneOptimized{
+ Logger: lane.Logger,
+ SourceNetworkName: lane.SourceNetworkName,
+ DestNetworkName: lane.DestNetworkName,
+ Source: lane.Source,
+ Dest: lane.Dest,
+ Reports: lane.Reports,
+ }
+
+ return &CCIPE2ELoad{
+ t: t,
+ Lane: loadLane,
+ CurrentMsgSerialNo: atomic.NewInt64(1),
+ CallTimeOut: timeout,
+ NoOfReq: noOfReq,
+ SendMaxDataIntermittentlyInMsgCount: sendMaxDataIntermittentlyInEveryMsgCount,
+ SkipRequestIfAnotherRequestTriggeredWithin: SkipRequestIfAnotherRequestTriggeredWithin,
+ MsgProfiles: m,
+ }
+}
+
+// BeforeAllCall funds subscription, approves the token transfer amount.
+// Needs to be called before load sequence is started.
+// Needs to approve and fund for the entire sequence.
+func (c *CCIPE2ELoad) BeforeAllCall() {
+ sourceCCIP := c.Lane.Source
+ destCCIP := c.Lane.Dest
+
+ receiver, err := utils.ABIEncode(`[{"type":"address"}]`, destCCIP.ReceiverDapp.EthAddress)
+ require.NoError(c.t, err, "Failed encoding the receiver address")
+ c.msg = router.ClientEVM2AnyMessage{
+ Receiver: receiver,
+ FeeToken: common.HexToAddress(sourceCCIP.Common.FeeToken.Address()),
+ Data: []byte("message with Id 1"),
+ }
+ var tokenAndAmounts []router.ClientEVMTokenAmount
+ if len(c.Lane.Source.Common.BridgeTokens) > 0 {
+ for i := range c.Lane.Source.TransferAmount {
+ // if length of sourceCCIP.TransferAmount is more than available bridge token use first bridge token
+ token := sourceCCIP.Common.BridgeTokens[0]
+ if i < len(sourceCCIP.Common.BridgeTokens) {
+ token = sourceCCIP.Common.BridgeTokens[i]
+ }
+ tokenAndAmounts = append(tokenAndAmounts, router.ClientEVMTokenAmount{
+ Token: common.HexToAddress(token.Address()), Amount: c.Lane.Source.TransferAmount[i],
+ })
+ }
+ c.msg.TokenAmounts = tokenAndAmounts
+ }
+ // we might need to change the receiver to the default wallet of destination based on the gaslimit of msg
+ // Get the receiver's bytecode to check if it's a contract or EOA
+ bytecode, err := c.Lane.Dest.Common.ChainClient.Backend().CodeAt(context.Background(), c.Lane.Dest.ReceiverDapp.EthAddress, nil)
+ require.NoError(c.t, err, "Failed to get bytecode of the receiver contract")
+ // if the bytecode is empty, it's an EOA,
+ // In that case save the receiver address as EOA to be used in the message
+ // Otherwise save destination's default wallet address as EOA
+ // so that it can be used later for msgs with gaslimit 0
+ if len(bytecode) > 0 {
+ receiver, err := utils.ABIEncode(`[{"type":"address"}]`, common.HexToAddress(c.Lane.Dest.Common.ChainClient.GetDefaultWallet().Address()))
+ require.NoError(c.t, err, "Failed encoding the receiver address")
+ c.EOAReceiver = receiver
+ } else {
+ c.EOAReceiver = c.msg.Receiver
+ }
+ if c.SendMaxDataIntermittentlyInMsgCount > 0 {
+ c.MaxDataBytes, err = sourceCCIP.OnRamp.Instance.GetDynamicConfig(nil)
+ require.NoError(c.t, err, "failed to fetch dynamic config")
+ }
+ // if the msg is sent via multicall, transfer the token transfer amount to multicall contract
+ if sourceCCIP.Common.MulticallEnabled &&
+ sourceCCIP.Common.MulticallContract != (common.Address{}) &&
+ len(c.Lane.Source.Common.BridgeTokens) > 0 {
+ for i, amount := range sourceCCIP.TransferAmount {
+ // if length of sourceCCIP.TransferAmount is more than available bridge token use first bridge token
+ token := sourceCCIP.Common.BridgeTokens[0]
+ if i < len(sourceCCIP.Common.BridgeTokens) {
+ token = sourceCCIP.Common.BridgeTokens[i]
+ }
+ amountToApprove := new(big.Int).Mul(amount, big.NewInt(c.NoOfReq))
+ bal, err := token.BalanceOf(context.Background(), sourceCCIP.Common.MulticallContract.Hex())
+ require.NoError(c.t, err, "Failed to get token balance")
+ if bal.Cmp(amountToApprove) < 0 {
+ err := token.Transfer(token.OwnerWallet, sourceCCIP.Common.MulticallContract.Hex(), amountToApprove)
+ require.NoError(c.t, err, "Failed to approve token transfer amount")
+ }
+ }
+ }
+
+ c.LastFinalizedTxBlock.Store(c.Lane.Source.NewFinalizedBlockNum.Load())
+ c.LastFinalizedTimestamp.Store(c.Lane.Source.NewFinalizedBlockTimestamp.Load())
+
+ sourceCCIP.Common.ChainClient.ParallelTransactions(false)
+ destCCIP.Common.ChainClient.ParallelTransactions(false)
+}
+
+func (c *CCIPE2ELoad) CCIPMsg() (router.ClientEVM2AnyMessage, *testreporters.RequestStat, error) {
+ msgSerialNo := c.CurrentMsgSerialNo.Load()
+ c.CurrentMsgSerialNo.Inc()
+ msgDetails := c.MsgProfiles.MsgDetailsForIteration(msgSerialNo)
+ stats := testreporters.NewCCIPRequestStats(msgSerialNo, c.Lane.SourceNetworkName, c.Lane.DestNetworkName)
+ // form the message for transfer
+ msgLength := pointer.GetInt64(msgDetails.DataLength)
+ gasLimit := pointer.GetInt64(msgDetails.DestGasLimit)
+ msg := c.msg
+ if msgLength > 0 && msgDetails.IsDataTransfer() {
+ if c.SendMaxDataIntermittentlyInMsgCount > 0 {
+ // every SendMaxDataIntermittentlyInMsgCount message will have extra data with almost MaxDataBytes
+ if msgSerialNo%c.SendMaxDataIntermittentlyInMsgCount == 0 {
+ msgLength = int64(c.MaxDataBytes - 1)
+ }
+ }
+ b := make([]byte, msgLength)
+ _, err := crypto_rand.Read(b)
+ if err != nil {
+ return router.ClientEVM2AnyMessage{}, stats, fmt.Errorf("failed to generate random string %w", err)
+ }
+ randomString := base64.URLEncoding.EncodeToString(b)
+ msg.Data = []byte(randomString[:msgLength])
+ }
+ if !msgDetails.IsTokenTransfer() {
+ msg.TokenAmounts = []router.ClientEVMTokenAmount{}
+ }
+ extraArgsV1, err := testhelpers.GetEVMExtraArgsV1(big.NewInt(gasLimit), false)
+ if err != nil {
+ return router.ClientEVM2AnyMessage{}, stats, err
+ }
+ msg.ExtraArgs = extraArgsV1
+ // if gaslimit is 0, set the receiver to EOA
+ if gasLimit == 0 {
+ msg.Receiver = c.EOAReceiver
+ }
+ return msg, stats, nil
+}
+
+func (c *CCIPE2ELoad) Call(_ *wasp.Generator) *wasp.Response {
+ res := &wasp.Response{}
+ sourceCCIP := c.Lane.Source
+ recentRequestFoundAt := sourceCCIP.IsRequestTriggeredWithinTimeframe(c.SkipRequestIfAnotherRequestTriggeredWithin)
+ if recentRequestFoundAt != nil {
+ c.Lane.Logger.
+ Info().
+ Str("Found At=", recentRequestFoundAt.String()).
+ Msgf("Skipping ...Another Request found within given timeframe %s", c.SkipRequestIfAnotherRequestTriggeredWithin.String())
+ return res
+ }
+ // if there is an connection error , we will skip sending the request
+ // this is to avoid sending the request when the connection is not restored yet
+ if sourceCCIP.Common.IsConnectionRestoredRecently != nil {
+ if !sourceCCIP.Common.IsConnectionRestoredRecently.Load() {
+ c.Lane.Logger.Info().Msg("RPC Connection Error.. skipping this request")
+ res.Failed = true
+ res.Error = "RPC Connection error .. this request was skipped"
+ return res
+ }
+ c.Lane.Logger.Info().Msg("Connection is restored, Resuming load")
+ }
+ msg, stats, err := c.CCIPMsg()
+ if err != nil {
+ res.Error = err.Error()
+ res.Failed = true
+ return res
+ }
+ msgSerialNo := stats.ReqNo
+ // create a sub-logger for the request
+ lggr := c.Lane.Logger.With().Int64("msg Number", stats.ReqNo).Logger()
+
+ feeToken := sourceCCIP.Common.FeeToken.EthAddress
+ // initiate the transfer
+ lggr.Debug().Str("triggeredAt", time.Now().GoString()).Msg("triggering transfer")
+ var sendTx *types.Transaction
+
+ destChainSelector, err := chain_selectors.SelectorFromChainId(sourceCCIP.DestinationChainId)
+ if err != nil {
+ res.Error = fmt.Sprintf("reqNo %d err %s - while getting selector from chainid", msgSerialNo, err.Error())
+ res.Failed = true
+ return res
+ }
+
+ // initiate the transfer
+ // if the token address is 0x0 it will use Native as fee token and the fee amount should be mentioned in bind.TransactOpts's value
+ fee, err := sourceCCIP.Common.Router.GetFee(destChainSelector, msg)
+ if err != nil {
+ res.Error = fmt.Sprintf("reqNo %d err %s - while getting fee from router", msgSerialNo, err.Error())
+ res.Failed = true
+ return res
+ }
+ startTime := time.Now().UTC()
+ if feeToken != common.HexToAddress("0x0") {
+ sendTx, err = sourceCCIP.Common.Router.CCIPSendAndProcessTx(destChainSelector, msg, nil)
+ } else {
+ // add a bit buffer to fee
+ sendTx, err = sourceCCIP.Common.Router.CCIPSendAndProcessTx(destChainSelector, msg, new(big.Int).Add(big.NewInt(1e5), fee))
+ }
+ if err != nil {
+ stats.UpdateState(&lggr, 0, testreporters.TX, time.Since(startTime), testreporters.Failure, nil)
+ res.Error = fmt.Sprintf("ccip-send tx error %s for reqNo %d", err.Error(), msgSerialNo)
+ res.Data = stats.StatusByPhase
+ res.Failed = true
+ return res
+ }
+
+ // the msg is no longer needed, so we can clear it to avoid holding extra data during load
+ // nolint:ineffassign,staticcheck
+ msg = router.ClientEVM2AnyMessage{}
+
+ txConfirmationTime := time.Now().UTC()
+ lggr = lggr.With().Str("Msg Tx", sendTx.Hash().String()).Logger()
+
+ stats.UpdateState(&lggr, 0, testreporters.TX, txConfirmationTime.Sub(startTime), testreporters.Success, nil)
+ err = c.Validate(lggr, sendTx, txConfirmationTime, []*testreporters.RequestStat{stats})
+ if err != nil {
+ res.Error = err.Error()
+ res.Failed = true
+ res.Data = stats.StatusByPhase
+ return res
+ }
+ res.Data = stats.StatusByPhase
+ return res
+}
+
+func (c *CCIPE2ELoad) Validate(lggr zerolog.Logger, sendTx *types.Transaction, txConfirmationTime time.Time, stats []*testreporters.RequestStat) error {
+ // wait for
+ // - CCIPSendRequested Event log to be generated,
+ msgLogs, sourceLogTime, err := c.Lane.Source.AssertEventCCIPSendRequested(&lggr, sendTx.Hash().Hex(), c.CallTimeOut, txConfirmationTime, stats)
+ if err != nil {
+ return err
+ }
+
+ lstFinalizedBlock := c.LastFinalizedTxBlock.Load()
+ var sourceLogFinalizedAt time.Time
+ // if the finality tag is enabled and the last finalized block is greater than the block number of the message
+ // consider the message finalized
+ if c.Lane.Source.Common.ChainClient.GetNetworkConfig().FinalityDepth == 0 &&
+ lstFinalizedBlock != 0 && lstFinalizedBlock > msgLogs[0].LogInfo.BlockNumber {
+ sourceLogFinalizedAt = c.LastFinalizedTimestamp.Load()
+ for i, stat := range stats {
+ stat.UpdateState(&lggr, stat.SeqNum, testreporters.SourceLogFinalized,
+ sourceLogFinalizedAt.Sub(sourceLogTime), testreporters.Success,
+ &testreporters.TransactionStats{
+ TxHash: msgLogs[i].LogInfo.TxHash.Hex(),
+ FinalizedByBlock: strconv.FormatUint(lstFinalizedBlock, 10),
+ FinalizedAt: sourceLogFinalizedAt.String(),
+ Fee: msgLogs[i].Fee.String(),
+ NoOfTokensSent: msgLogs[i].NoOfTokens,
+ MessageBytesLength: int64(msgLogs[i].DataLength),
+ MsgID: fmt.Sprintf("0x%x", msgLogs[i].MessageId[:]),
+ })
+ }
+ } else {
+ var finalizingBlock uint64
+ sourceLogFinalizedAt, finalizingBlock, err = c.Lane.Source.AssertSendRequestedLogFinalized(
+ &lggr, msgLogs[0].LogInfo.TxHash, msgLogs, sourceLogTime, stats)
+ if err != nil {
+ return err
+ }
+ c.LastFinalizedTxBlock.Store(finalizingBlock)
+ c.LastFinalizedTimestamp.Store(sourceLogFinalizedAt)
+ }
+
+ for _, msgLog := range msgLogs {
+ seqNum := msgLog.SequenceNumber
+ var reqStat *testreporters.RequestStat
+ lggr = lggr.With().Str("MsgID", fmt.Sprintf("0x%x", msgLog.MessageId[:])).Logger()
+ for _, stat := range stats {
+ if stat.SeqNum == seqNum {
+ reqStat = stat
+ break
+ }
+ }
+ if reqStat == nil {
+ return fmt.Errorf("could not find request stat for seq number %d", seqNum)
+ }
+ // wait for
+ // - CommitStore to increase the seq number,
+ err = c.Lane.Dest.AssertSeqNumberExecuted(&lggr, seqNum, c.CallTimeOut, sourceLogFinalizedAt, reqStat)
+ if err != nil {
+ return err
+ }
+ // wait for ReportAccepted event
+ commitReport, reportAcceptedAt, err := c.Lane.Dest.AssertEventReportAccepted(&lggr, seqNum, c.CallTimeOut, sourceLogFinalizedAt, reqStat)
+ if err != nil || commitReport == nil {
+ return err
+ }
+ blessedAt, err := c.Lane.Dest.AssertReportBlessed(&lggr, seqNum, c.CallTimeOut, *commitReport, reportAcceptedAt, reqStat)
+ if err != nil {
+ return err
+ }
+ _, err = c.Lane.Dest.AssertEventExecutionStateChanged(&lggr, seqNum, c.CallTimeOut, blessedAt, reqStat, testhelpers.ExecutionStateSuccess)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go b/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go
new file mode 100644
index 00000000000..ad3960dee2e
--- /dev/null
+++ b/integration-tests/ccip-tests/load/ccip_multicall_loadgen.go
@@ -0,0 +1,271 @@
+package load
+
+import (
+ "fmt"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/prometheus/common/model"
+ "github.com/rs/zerolog"
+ "golang.org/x/sync/errgroup"
+
+ chain_selectors "github.com/smartcontractkit/chain-selectors"
+ "github.com/smartcontractkit/wasp"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+ "github.com/smartcontractkit/chainlink-testing-framework/logging"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testreporters"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups"
+)
+
+// CCIPMultiCallLoadGenerator represents a load generator for the CCIP lanes originating from same network
+// The purpose of this load generator is to group ccip-send calls for the CCIP lanes originating from same network
+// This is to avoid the scenario of hitting rpc rate limit for the same network if the load generator is sending
+// too many ccip-send calls to the same network hitting the rpc rate limit
+type CCIPMultiCallLoadGenerator struct {
+ t *testing.T
+ logger zerolog.Logger
+ client blockchain.EVMClient
+ E2ELoads map[string]*CCIPE2ELoad
+ MultiCall string
+ NoOfRequestsPerUnitTime int64
+ labels model.LabelSet
+ loki *wasp.LokiClient
+ responses chan map[string]MultiCallReturnValues
+ Done chan struct{}
+}
+
+type MultiCallReturnValues struct {
+ Msgs []contracts.CCIPMsgData
+ Stats []*testreporters.RequestStat
+}
+
+func NewMultiCallLoadGenerator(testCfg *testsetups.CCIPTestConfig, lanes []*actions.CCIPLane, noOfRequestsPerUnitTime int64, labels map[string]string) (*CCIPMultiCallLoadGenerator, error) {
+ // check if all lanes are from same network
+ source := lanes[0].Source.Common.ChainClient.GetChainID()
+ multiCall := lanes[0].Source.Common.MulticallContract.Hex()
+ if multiCall == "" {
+ return nil, fmt.Errorf("multicall address cannot be empty")
+ }
+ for i := 1; i < len(lanes); i++ {
+ if source.String() != lanes[i].Source.Common.ChainClient.GetChainID().String() {
+ return nil, fmt.Errorf("all lanes should be from same network; expected %s, got %s", source, lanes[i].Source.Common.ChainClient.GetChainID())
+ }
+ if lanes[i].Source.Common.MulticallContract.Hex() != multiCall {
+ return nil, fmt.Errorf("multicall address should be same for all lanes")
+ }
+ }
+ client := lanes[0].Source.Common.ChainClient
+ lggr := logging.GetTestLogger(testCfg.Test).With().Str("Source Network", client.GetNetworkName()).Logger()
+ ls := wasp.LabelsMapToModel(labels)
+ if err := ls.Validate(); err != nil {
+ return nil, err
+ }
+ lokiConfig := testCfg.EnvInput.Logging.Loki
+ loki, err := wasp.NewLokiClient(wasp.NewLokiConfig(lokiConfig.Endpoint, lokiConfig.TenantId, nil, nil))
+ if err != nil {
+ return nil, err
+ }
+ m := &CCIPMultiCallLoadGenerator{
+ t: testCfg.Test,
+ client: client,
+ MultiCall: multiCall,
+ logger: lggr,
+ NoOfRequestsPerUnitTime: noOfRequestsPerUnitTime,
+ E2ELoads: make(map[string]*CCIPE2ELoad),
+ labels: ls,
+ loki: loki,
+ responses: make(chan map[string]MultiCallReturnValues),
+ Done: make(chan struct{}),
+ }
+ for _, lane := range lanes {
+ // for multicall load generator, we don't want to send max data intermittently, it might
+ // cause oversized data for multicall
+ ccipLoad := NewCCIPLoad(
+ testCfg.Test, lane, testCfg.TestGroupInput.PhaseTimeout.Duration(),
+ 100000,
+ testCfg.TestGroupInput.LoadProfile.MsgProfile, 0,
+ testCfg.TestGroupInput.LoadProfile.SkipRequestIfAnotherRequestTriggeredWithin,
+ )
+ ccipLoad.BeforeAllCall()
+ m.E2ELoads[fmt.Sprintf("%s-%s", lane.SourceNetworkName, lane.DestNetworkName)] = ccipLoad
+ }
+
+ m.StartLokiStream()
+ return m, nil
+}
+
+func (m *CCIPMultiCallLoadGenerator) Stop() error {
+ m.Done <- struct{}{}
+ tokenMap := make(map[string]struct{})
+ var tokens []*contracts.ERC20Token
+ for _, e2eLoad := range m.E2ELoads {
+ for i := range e2eLoad.Lane.Source.TransferAmount {
+ // if length of sourceCCIP.TransferAmount is more than available bridge token use first bridge token
+ token := e2eLoad.Lane.Source.Common.BridgeTokens[0]
+ if i < len(e2eLoad.Lane.Source.Common.BridgeTokens) {
+ token = e2eLoad.Lane.Source.Common.BridgeTokens[i]
+ }
+ if _, ok := tokenMap[token.Address()]; !ok {
+ tokens = append(tokens, e2eLoad.Lane.Source.Common.BridgeTokens[i])
+ }
+ }
+ }
+ if len(tokens) > 0 {
+ return contracts.TransferTokens(m.client, common.HexToAddress(m.MultiCall), tokens)
+ }
+ return nil
+}
+
+func (m *CCIPMultiCallLoadGenerator) StartLokiStream() {
+ go func() {
+ for {
+ select {
+ case <-m.Done:
+ m.logger.Info().Msg("stopping loki client from multi call load generator")
+ m.loki.Stop()
+ return
+ case rValues := <-m.responses:
+ m.HandleLokiLogs(rValues)
+ }
+ }
+ }()
+}
+
+func (m *CCIPMultiCallLoadGenerator) HandleLokiLogs(rValues map[string]MultiCallReturnValues) {
+ for dest, rValue := range rValues {
+ labels := m.labels.Merge(model.LabelSet{
+ "dest_chain": model.LabelValue(dest),
+ "test_data_type": "responses",
+ "go_test_name": model.LabelValue(m.t.Name()),
+ })
+ for _, stat := range rValue.Stats {
+ err := m.loki.HandleStruct(labels, time.Now().UTC(), stat.StatusByPhase)
+ if err != nil {
+ m.logger.Error().Err(err).Msg("error while handling loki logs")
+ }
+ }
+ }
+}
+
+func (m *CCIPMultiCallLoadGenerator) Call(_ *wasp.Generator) *wasp.Response {
+ res := &wasp.Response{}
+ msgs, returnValuesByDest, err := m.MergeCalls()
+ if err != nil {
+ res.Error = err.Error()
+ res.Failed = true
+ return res
+ }
+ defer func() {
+ m.responses <- returnValuesByDest
+ }()
+ m.logger.Info().Interface("msgs", msgs).Msgf("Sending %d ccip-send calls", len(msgs))
+ startTime := time.Now().UTC()
+ // for now we are using all ccip-sends with native
+ sendTx, err := contracts.MultiCallCCIP(m.client, m.MultiCall, msgs, true)
+ if err != nil {
+ res.Error = err.Error()
+ res.Failed = true
+ return res
+ }
+
+ lggr := m.logger.With().Str("Msg Tx", sendTx.Hash().String()).Logger()
+ txConfirmationTime := time.Now().UTC()
+ for _, rValues := range returnValuesByDest {
+ if len(rValues.Stats) != len(rValues.Msgs) {
+ res.Error = fmt.Sprintf("number of stats %d and msgs %d should be same", len(rValues.Stats), len(rValues.Msgs))
+ res.Failed = true
+ return res
+ }
+ for _, stat := range rValues.Stats {
+ stat.UpdateState(&lggr, 0, testreporters.TX, startTime.Sub(txConfirmationTime), testreporters.Success, nil)
+ }
+ }
+
+ validateGrp := errgroup.Group{}
+ // wait for
+ // - CCIPSendRequested Event log to be generated,
+ for _, rValues := range returnValuesByDest {
+ key := fmt.Sprintf("%s-%s", rValues.Stats[0].SourceNetwork, rValues.Stats[0].DestNetwork)
+ c, ok := m.E2ELoads[key]
+ if !ok {
+ res.Error = fmt.Sprintf("load for %s not found", key)
+ res.Failed = true
+ return res
+ }
+
+ lggr = lggr.With().Str("Source Network", c.Lane.Source.Common.ChainClient.GetNetworkName()).Str("Dest Network", c.Lane.Dest.Common.ChainClient.GetNetworkName()).Logger()
+ stats := rValues.Stats
+ txConfirmationTime := txConfirmationTime
+ sendTx := sendTx
+ lggr := lggr
+ validateGrp.Go(func() error {
+ return c.Validate(lggr, sendTx, txConfirmationTime, stats)
+ })
+ }
+ err = validateGrp.Wait()
+ if err != nil {
+ res.Error = err.Error()
+ res.Failed = true
+ return res
+ }
+
+ return res
+}
+
+func (m *CCIPMultiCallLoadGenerator) MergeCalls() ([]contracts.CCIPMsgData, map[string]MultiCallReturnValues, error) {
+ var ccipMsgs []contracts.CCIPMsgData
+ statDetails := make(map[string]MultiCallReturnValues)
+
+ for _, e2eLoad := range m.E2ELoads {
+ destChainSelector, err := chain_selectors.SelectorFromChainId(e2eLoad.Lane.Source.DestinationChainId)
+ if err != nil {
+ return ccipMsgs, statDetails, err
+ }
+
+ allFee := big.NewInt(0)
+ var allStatsForDest []*testreporters.RequestStat
+ var allMsgsForDest []contracts.CCIPMsgData
+ for i := int64(0); i < m.NoOfRequestsPerUnitTime; i++ {
+ msg, stats, err := e2eLoad.CCIPMsg()
+ if err != nil {
+ return ccipMsgs, statDetails, err
+ }
+ msg.FeeToken = common.Address{}
+ fee, err := e2eLoad.Lane.Source.Common.Router.GetFee(destChainSelector, msg)
+ if err != nil {
+ return ccipMsgs, statDetails, err
+ }
+ // transfer fee to the multicall address
+ if msg.FeeToken != (common.Address{}) {
+ allFee = new(big.Int).Add(allFee, fee)
+ }
+ msgData := contracts.CCIPMsgData{
+ RouterAddr: e2eLoad.Lane.Source.Common.Router.EthAddress,
+ ChainSelector: destChainSelector,
+ Msg: msg,
+ Fee: fee,
+ }
+ ccipMsgs = append(ccipMsgs, msgData)
+
+ allStatsForDest = append(allStatsForDest, stats)
+ allMsgsForDest = append(allMsgsForDest, msgData)
+ }
+ statDetails[e2eLoad.Lane.DestNetworkName] = MultiCallReturnValues{
+ Stats: allStatsForDest,
+ Msgs: allMsgsForDest,
+ }
+ // transfer fee to the multicall address
+ if allFee.Cmp(big.NewInt(0)) > 0 {
+ if err := e2eLoad.Lane.Source.Common.FeeToken.Transfer(e2eLoad.Lane.Source.Common.MulticallContract.Hex(), allFee); err != nil {
+ return ccipMsgs, statDetails, err
+ }
+ }
+ }
+ return ccipMsgs, statDetails, nil
+}
diff --git a/integration-tests/ccip-tests/load/ccip_test.go b/integration-tests/ccip-tests/load/ccip_test.go
new file mode 100644
index 00000000000..0d14549ec96
--- /dev/null
+++ b/integration-tests/ccip-tests/load/ccip_test.go
@@ -0,0 +1,331 @@
+package load
+
+import (
+ "testing"
+ "time"
+
+ "github.com/rs/zerolog/log"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos"
+ "github.com/smartcontractkit/chainlink-testing-framework/logging"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups"
+)
+
+func TestLoadCCIPStableRPS(t *testing.T) {
+ t.Parallel()
+ lggr := logging.GetTestLogger(t)
+ testArgs := NewLoadArgs(t, lggr)
+ testArgs.Setup()
+ // if the test runs on remote runner
+ if len(testArgs.TestSetupArgs.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ log.Info().Msg("Tearing down the environment")
+ require.NoError(t, testArgs.TestSetupArgs.TearDown())
+ })
+ testArgs.TriggerLoadByLane()
+ testArgs.Wait()
+}
+
+// TestLoadCCIPWithUpgradeNodeVersion starts all nodes with a specific version, triggers load and then upgrades the node version as the load is running
+func TestLoadCCIPWithUpgradeNodeVersion(t *testing.T) {
+ t.Parallel()
+ lggr := logging.GetTestLogger(t)
+ testArgs := NewLoadArgs(t, lggr)
+ testArgs.Setup()
+ // if the test runs on remote runner
+ if len(testArgs.TestSetupArgs.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ log.Info().Msg("Tearing down the environment")
+ require.NoError(t, testArgs.TestSetupArgs.TearDown())
+ })
+ testArgs.TriggerLoadByLane()
+ testArgs.lggr.Info().Msg("Waiting for load to start on all lanes")
+ // wait for load runner to start
+ testArgs.LoadStarterWg.Wait()
+ // sleep for 30s to let load run for a while
+ time.Sleep(30 * time.Second)
+ // upgrade node version for few nodes
+ err := testsetups.UpgradeNodes(testArgs.t, testArgs.lggr, testArgs.TestCfg, testArgs.TestSetupArgs.Env)
+ require.NoError(t, err)
+ // after upgrade send a request to all lanes as a sanity check
+ testArgs.SanityCheck()
+ // now wait for the load to finish
+ testArgs.Wait()
+}
+
+func TestLoadCCIPStableRPSTriggerBySource(t *testing.T) {
+ t.Parallel()
+ lggr := logging.GetTestLogger(t)
+ testArgs := NewLoadArgs(t, lggr)
+ testArgs.TestCfg.TestGroupInput.MulticallInOneTx = ptr.Ptr(true)
+ testArgs.Setup()
+ // if the test runs on remote runner
+ if len(testArgs.TestSetupArgs.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ log.Info().Msg("Tearing down the environment")
+ testArgs.TearDown()
+ })
+ testArgs.TriggerLoadBySource()
+ testArgs.Wait()
+}
+
+func TestLoadCCIPStableRequestTriggeringWithNetworkChaos(t *testing.T) {
+ t.Parallel()
+ lggr := logging.GetTestLogger(t)
+ testArgs := NewLoadArgs(t, lggr)
+ testArgs.Setup()
+ // if the test runs on remote runner
+ if len(testArgs.TestSetupArgs.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ log.Info().Msg("Tearing down the environment")
+ require.NoError(t, testArgs.TestSetupArgs.TearDown())
+ })
+ testEnv := testArgs.TestSetupArgs.Env
+ require.NotNil(t, testEnv)
+ require.NotNil(t, testEnv.K8Env)
+
+ // apply network chaos so that chainlink's RPC calls are affected by some network delay for the duration of the test
+ var gethNetworksLabels []string
+ for _, net := range testArgs.TestCfg.SelectedNetworks {
+ gethNetworksLabels = append(gethNetworksLabels, actions.GethLabel(net.Name))
+ }
+ testEnv.ChaosLabelForAllGeth(t, gethNetworksLabels)
+ if testArgs.TestCfg.TestGroupInput.LoadProfile.NetworkChaosDelay == nil {
+ testArgs.TestCfg.TestGroupInput.LoadProfile.NetworkChaosDelay = config.MustNewDuration(200 * time.Millisecond)
+ }
+ chaosId, err := testEnv.K8Env.Chaos.Run(
+ chaos.NewNetworkLatency(
+ testEnv.K8Env.Cfg.Namespace, &chaos.Props{
+ FromLabels: &map[string]*string{"geth": ptr.Ptr(actions.ChaosGroupCCIPGeth)},
+ ToLabels: &map[string]*string{"app": ptr.Ptr("chainlink-0")},
+ DurationStr: testArgs.TestCfg.TestGroupInput.LoadProfile.TestDuration.String(),
+ Delay: testArgs.TestCfg.TestGroupInput.LoadProfile.NetworkChaosDelay.Duration().String(),
+ }))
+ require.NoError(t, err)
+
+ t.Cleanup(func() {
+ if chaosId != "" {
+ require.NoError(t, testEnv.K8Env.Chaos.Stop(chaosId))
+ }
+ })
+
+ // now trigger the load
+ testArgs.TriggerLoadByLane()
+ testArgs.Wait()
+}
+
+// This test applies pod chaos to the CL nodes asynchronously and sequentially while the load is running
+// the pod chaos is applied at a regular interval throughout the test duration
+// this test needs to be run for a longer duration to see the effects of pod chaos
+// in this test commit and execution are set up to be on the same node
+func TestLoadCCIPStableWithMajorityNodeFailure(t *testing.T) {
+ t.Parallel()
+
+ inputs := []ChaosConfig{
+ {
+ ChaosName: "CCIP works after majority of CL nodes are recovered from pod failure @pod-chaos",
+ ChaosFunc: chaos.NewFailPods,
+ ChaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupCommitFaultyPlus: ptr.Ptr("1")},
+ DurationStr: "2m",
+ },
+ },
+ }
+
+ lggr := logging.GetTestLogger(t)
+ testArgs := NewLoadArgs(t, lggr, inputs...)
+
+ var allChaosDur time.Duration
+ // to override the default duration of chaos with test input
+ for i := range inputs {
+ inputs[i].ChaosProps.DurationStr = testArgs.TestCfg.TestGroupInput.ChaosDuration.String()
+ allChaosDur += testArgs.TestCfg.TestGroupInput.ChaosDuration.Duration()
+ inputs[i].WaitBetweenChaos = testArgs.TestCfg.TestGroupInput.LoadProfile.WaitBetweenChaosDuringLoad.Duration()
+ allChaosDur += inputs[i].WaitBetweenChaos
+ }
+
+ // the duration of load test should be greater than the duration of chaos
+ if testArgs.TestCfg.TestGroupInput.LoadProfile.TestDuration.Duration() < allChaosDur+2*time.Minute {
+ t.Fatalf("Skipping the test as the test duration is less than the chaos duration")
+ }
+
+ testArgs.Setup()
+ // if the test runs on remote runner
+ if len(testArgs.TestSetupArgs.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ log.Info().Msg("Tearing down the environment")
+ require.NoError(t, testArgs.TestSetupArgs.TearDown())
+ })
+
+ testEnv := testArgs.TestSetupArgs.Env
+ require.NotNil(t, testEnv)
+ require.NotNil(t, testEnv.K8Env)
+
+ testArgs.TriggerLoadByLane()
+ testArgs.ApplyChaos()
+ testArgs.Wait()
+}
+
+// This test applies pod chaos to the CL nodes asynchronously and sequentially while the load is running
+// the pod chaos is applied at a regular interval throughout the test duration
+// this test needs to be run for a longer duration to see the effects of pod chaos
+// in this test commit and execution are set up to be on the same node
+func TestLoadCCIPStableWithMinorityNodeFailure(t *testing.T) {
+ t.Parallel()
+
+ inputs := []ChaosConfig{
+ {
+ ChaosName: "CCIP works while minority of CL nodes are in failed state for pod failure @pod-chaos",
+ ChaosFunc: chaos.NewFailPods,
+ ChaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupCommitFaulty: ptr.Ptr("1")},
+ DurationStr: "4m",
+ },
+ },
+ }
+
+ lggr := logging.GetTestLogger(t)
+ testArgs := NewLoadArgs(t, lggr, inputs...)
+
+ var allChaosDur time.Duration
+ // to override the default duration of chaos with test input
+ for i := range inputs {
+ inputs[i].ChaosProps.DurationStr = testArgs.TestCfg.TestGroupInput.ChaosDuration.String()
+ allChaosDur += testArgs.TestCfg.TestGroupInput.ChaosDuration.Duration()
+ inputs[i].WaitBetweenChaos = testArgs.TestCfg.TestGroupInput.LoadProfile.WaitBetweenChaosDuringLoad.Duration()
+ allChaosDur += inputs[i].WaitBetweenChaos
+ }
+
+ // the duration of load test should be greater than the duration of chaos
+ if testArgs.TestCfg.TestGroupInput.LoadProfile.TestDuration.Duration() < allChaosDur+2*time.Minute {
+ t.Fatalf("Skipping the test as the test duration is less than the chaos duration")
+ }
+
+ testArgs.Setup()
+ // if the test runs on remote runner
+ if len(testArgs.TestSetupArgs.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ log.Info().Msg("Tearing down the environment")
+ require.NoError(t, testArgs.TestSetupArgs.TearDown())
+ })
+
+ testEnv := testArgs.TestSetupArgs.Env
+ require.NotNil(t, testEnv)
+ require.NotNil(t, testEnv.K8Env)
+
+ testArgs.TriggerLoadByLane()
+ testArgs.ApplyChaos()
+ testArgs.Wait()
+}
+
+// This test applies pod chaos to the CL nodes asynchronously and sequentially while the load is running
+// the pod chaos is applied at a regular interval throughout the test duration
+// in this test commit and execution are set up to be on different node
+func TestLoadCCIPStableWithPodChaosDiffCommitAndExec(t *testing.T) {
+ t.Parallel()
+ inputs := []ChaosConfig{
+ {
+ ChaosName: "CCIP Commit works after majority of CL nodes are recovered from pod failure @pod-chaos",
+ ChaosFunc: chaos.NewFailPods,
+ ChaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupCommitFaultyPlus: ptr.Ptr("1")},
+ DurationStr: "2m",
+ },
+ },
+ {
+ ChaosName: "CCIP Execution works after majority of CL nodes are recovered from pod failure @pod-chaos",
+ ChaosFunc: chaos.NewFailPods,
+ ChaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupExecutionFaultyPlus: ptr.Ptr("1")},
+ DurationStr: "2m",
+ },
+ },
+ {
+ ChaosName: "CCIP Commit works while minority of CL nodes are in failed state for pod failure @pod-chaos",
+ ChaosFunc: chaos.NewFailPods,
+ ChaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupCommitFaulty: ptr.Ptr("1")},
+ DurationStr: "4m",
+ },
+ },
+ {
+ ChaosName: "CCIP Execution works while minority of CL nodes are in failed state for pod failure @pod-chaos",
+ ChaosFunc: chaos.NewFailPods,
+ ChaosProps: &chaos.Props{
+ LabelsSelector: &map[string]*string{actions.ChaosGroupExecutionFaulty: ptr.Ptr("1")},
+ DurationStr: "4m",
+ },
+ },
+ }
+ for _, in := range inputs {
+ in := in
+ t.Run(in.ChaosName, func(t *testing.T) {
+ t.Parallel()
+ lggr := logging.GetTestLogger(t)
+ testArgs := NewLoadArgs(t, lggr, in)
+ testArgs.TestCfg.TestGroupInput.LoadProfile.TestDuration = config.MustNewDuration(5 * time.Minute)
+ testArgs.TestCfg.TestGroupInput.LoadProfile.TimeUnit = config.MustNewDuration(1 * time.Second)
+ testArgs.TestCfg.TestGroupInput.LoadProfile.RequestPerUnitTime = []int64{2}
+ testArgs.TestCfg.TestGroupInput.PhaseTimeout = config.MustNewDuration(15 * time.Minute)
+
+ testArgs.Setup()
+ // if the test runs on remote runner
+ if len(testArgs.TestSetupArgs.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ log.Info().Msg("Tearing down the environment")
+ require.NoError(t, testArgs.TestSetupArgs.TearDown())
+ })
+ testArgs.SanityCheck()
+ testArgs.TriggerLoadByLane()
+ testArgs.ApplyChaos()
+ testArgs.Wait()
+ })
+ }
+}
+
+// TestLoadCCIPStableRPSAfterARMCurseAndUncurse validates that after ARM curse is lifted
+// all pending requests get delivered.
+// The test pauses loadgen while ARM is cursed and resumes it when curse is lifted.
+// There is a known limitation of this test - if the test is run on remote-runner with high frequency
+// the remote-runner pod gets evicted after the loadgen is resumed.
+// The recommended frequency for this test 2req/min
+func TestLoadCCIPStableRPSAfterARMCurseAndUncurse(t *testing.T) {
+ t.Skipf("need to be enabled as part of CCIP-2277")
+ t.Parallel()
+ lggr := logging.GetTestLogger(t)
+ testArgs := NewLoadArgs(t, lggr)
+ testArgs.Setup()
+ // if the test runs on remote runner
+ if len(testArgs.TestSetupArgs.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ log.Info().Msg("Tearing down the environment")
+ require.NoError(t, testArgs.TestSetupArgs.TearDown())
+ })
+ testArgs.TriggerLoadByLane()
+ // wait for certain time so that few messages are sent
+ time.Sleep(2 * time.Minute)
+ // now validate the curse
+ testArgs.ValidateCurseFollowedByUncurse()
+ testArgs.Wait()
+}
diff --git a/integration-tests/ccip-tests/load/helper.go b/integration-tests/ccip-tests/load/helper.go
new file mode 100644
index 00000000000..9522a6c346b
--- /dev/null
+++ b/integration-tests/ccip-tests/load/helper.go
@@ -0,0 +1,483 @@
+package load
+
+import (
+ "context"
+ "fmt"
+ "math"
+ "math/big"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/AlekSi/pointer"
+ "github.com/rs/zerolog"
+ "github.com/smartcontractkit/wasp"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/atomic"
+ "golang.org/x/sync/errgroup"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
+)
+
+type ChaosConfig struct {
+ ChaosName string
+ ChaosFunc chaos.ManifestFunc
+ ChaosProps *chaos.Props
+ WaitBetweenChaos time.Duration
+}
+
+// WaspSchedule calculates the load schedule based on the provided request per unit time and duration
+// if multiple step durations are provided, it will calculate the schedule based on the step duration and
+// corresponding request per unit time by matching the index of the request per unit time and step duration slice
+func WaspSchedule(rps []int64, duration *config.Duration, steps []*config.Duration) []*wasp.Segment {
+ var segments []*wasp.Segment
+ var segmentDuration time.Duration
+
+ if len(rps) > 1 {
+ for i, req := range rps {
+ duration := steps[i].Duration()
+ segmentDuration += duration
+ segments = append(segments, wasp.Plain(req, duration)...)
+ }
+ totalDuration := duration.Duration()
+ repeatTimes := totalDuration.Seconds() / segmentDuration.Seconds()
+ return wasp.CombineAndRepeat(int(math.Round(repeatTimes)), segments)
+ }
+ return wasp.Plain(rps[0], duration.Duration())
+}
+
+type LoadArgs struct {
+ t *testing.T
+ Ctx context.Context
+ lggr *zerolog.Logger
+ RunnerWg *errgroup.Group // to wait on individual load generators run
+ LoadStarterWg *sync.WaitGroup // waits for all the runners to start
+ TestCfg *testsetups.CCIPTestConfig
+ TestSetupArgs *testsetups.CCIPTestSetUpOutputs
+ ChaosExps []ChaosConfig
+ LoadgenTearDowns []func()
+ Labels map[string]string
+ pauseLoad *atomic.Bool
+}
+
+func (l *LoadArgs) SetReportParams() {
+ var qParams []string
+ for k, v := range l.Labels {
+ qParams = append(qParams, fmt.Sprintf("var-%s=%s", k, v))
+ }
+ // add one of the source and destination network to the grafana query params
+ if len(l.TestSetupArgs.Lanes) > 0 {
+ qParams = append(qParams, fmt.Sprintf("var-source_chain=%s", l.TestSetupArgs.Lanes[0].ForwardLane.SourceNetworkName))
+ qParams = append(qParams, fmt.Sprintf("var-dest_chain=%s", l.TestSetupArgs.Lanes[0].ForwardLane.DestNetworkName))
+ }
+ err := l.TestSetupArgs.Reporter.AddToGrafanaDashboardQueryParams(qParams...)
+ require.NoError(l.t, err, "failed to set grafana query params")
+}
+
+func (l *LoadArgs) Setup() {
+ lggr := l.lggr
+ existing := pointer.GetBool(l.TestCfg.TestGroupInput.ExistingDeployment)
+ envName := "load-ccip"
+ if existing {
+ envName = "ccip-runner"
+ }
+ l.TestSetupArgs = testsetups.CCIPDefaultTestSetUp(l.TestCfg.Test, lggr, envName, nil, l.TestCfg)
+ namespace := l.TestCfg.TestGroupInput.LoadProfile.TestRunName
+ if l.TestSetupArgs.Env != nil && l.TestSetupArgs.Env.K8Env != nil && l.TestSetupArgs.Env.K8Env.Cfg != nil {
+ namespace = l.TestSetupArgs.Env.K8Env.Cfg.Namespace
+ }
+ l.Labels = map[string]string{
+ "test_group": "load",
+ "test_id": "ccip",
+ "namespace": namespace,
+ }
+ l.TestSetupArgs.Reporter.SetGrafanaURLProvider(l.TestCfg.EnvInput)
+ l.SetReportParams()
+}
+
+func (l *LoadArgs) scheduleForDest(destNetworkName string) []*wasp.Segment {
+ require.Greater(l.t, len(l.TestCfg.TestGroupInput.LoadProfile.RequestPerUnitTime), 0, "RequestPerUnitTime must be set")
+ // try to locate if there is a frequency provided for the destination network
+ // to locate the frequency, we check if the destination network name contains the network name in the frequency map
+ // if found, use that frequency for the destination network
+ // otherwise, use the default frequency
+ if l.TestCfg.TestGroupInput.LoadProfile.FrequencyByDestination != nil {
+ for networkName, freq := range l.TestCfg.TestGroupInput.LoadProfile.FrequencyByDestination {
+ if strings.Contains(destNetworkName, networkName) {
+ return WaspSchedule(
+ freq.RequestPerUnitTime,
+ l.TestCfg.TestGroupInput.LoadProfile.TestDuration,
+ freq.StepDuration)
+ }
+ }
+ }
+
+ return WaspSchedule(
+ l.TestCfg.TestGroupInput.LoadProfile.RequestPerUnitTime,
+ l.TestCfg.TestGroupInput.LoadProfile.TestDuration,
+ l.TestCfg.TestGroupInput.LoadProfile.StepDuration)
+}
+
+func (l *LoadArgs) SanityCheck() {
+ var allLanes []*actions.CCIPLane
+ for _, lane := range l.TestSetupArgs.Lanes {
+ allLanes = append(allLanes, lane.ForwardLane)
+ if lane.ReverseLane != nil {
+ allLanes = append(allLanes, lane.ReverseLane)
+ }
+ }
+ for _, lane := range allLanes {
+ ccipLoad := NewCCIPLoad(
+ l.TestCfg.Test, lane,
+ l.TestCfg.TestGroupInput.PhaseTimeout.Duration(),
+ 1, l.TestCfg.TestGroupInput.LoadProfile.MsgProfile,
+ 0, nil,
+ )
+ ccipLoad.BeforeAllCall()
+ resp := ccipLoad.Call(nil)
+ require.False(l.t, resp.Failed, "request failed in sanity check")
+ }
+}
+
+// ValidateCurseFollowedByUncurse assumes the lanes under test are bi-directional.
+// It assumes requests in both direction are in flight when this is called.
+// It assumes the ARM is not already cursed, it will fail the test if it is in cursed state.
+// It curses source ARM for forward lanes so that destination curse is also validated for reverse lanes.
+// It waits for 2 minutes for curse to be seen by ccip plugins and contracts.
+// It captures the curse timestamp to verify no execution state changed event is emitted after the cure is applied.
+// It uncurses the source ARM at the end so that it can be verified that rest of the requests are processed as expected.
+// Validates that even after uncursing the lane should not function for 30 more minutes.
+func (l *LoadArgs) ValidateCurseFollowedByUncurse() {
+ var lanes []*actions.CCIPLane
+ for _, lane := range l.TestSetupArgs.Lanes {
+ lanes = append(lanes, lane.ForwardLane)
+ }
+ // check if source is already cursed
+ for _, lane := range lanes {
+ cursed, err := lane.Source.Common.IsCursed()
+ require.NoError(l.t, err, "cannot get cursed state")
+ if cursed {
+ require.Fail(l.t, "test will not work if ARM is already cursed")
+ }
+ }
+ // before cursing set pause
+ l.pauseLoad.Store(true)
+ // wait for some time for pause to be active in wasp
+ l.lggr.Info().Msg("Waiting for 1 minute after applying pause on load")
+ time.Sleep(1 * time.Minute)
+ curseTimeStamps := make(map[string]time.Time)
+ for _, lane := range lanes {
+ if _, exists := curseTimeStamps[lane.SourceNetworkName]; exists {
+ continue
+ }
+ curseTx, err := lane.Source.Common.CurseARM()
+ require.NoError(l.t, err, "error in cursing arm")
+ require.NotNil(l.t, curseTx, "invalid cursetx")
+ receipt, err := lane.Source.Common.ChainClient.GetTxReceipt(curseTx.Hash())
+ require.NoError(l.t, err)
+ hdr, err := lane.Source.Common.ChainClient.HeaderByNumber(context.Background(), receipt.BlockNumber)
+ require.NoError(l.t, err)
+ curseTimeStamps[lane.SourceNetworkName] = hdr.Timestamp
+ l.lggr.Info().Str("Source", lane.SourceNetworkName).Msg("Curse is applied on source")
+ l.lggr.Info().Str("Destination", lane.SourceNetworkName).Msg("Curse is applied on destination")
+ }
+
+ l.lggr.Info().Msg("Curse is applied on all lanes. Waiting for 2 minutes")
+ time.Sleep(2 * time.Minute)
+
+ for _, lane := range lanes {
+ // try to send requests on lanes on which curse is applied on source RMN and the request should revert
+ // data-only transfer is sufficient
+ lane.Source.TransferAmount = []*big.Int{}
+ failedTx, _, _, err := lane.Source.SendRequest(
+ lane.Dest.ReceiverDapp.EthAddress,
+ big.NewInt(actions.DefaultDestinationGasLimit), // gas limit
+ )
+ if lane.Source.Common.ChainClient.GetNetworkConfig().MinimumConfirmations > 0 {
+ require.Error(l.t, err)
+ } else {
+ require.NoError(l.t, err)
+ }
+ errReason, v, err := lane.Source.Common.ChainClient.RevertReasonFromTx(failedTx, router.RouterABI)
+ require.NoError(l.t, err)
+ require.Equal(l.t, "BadARMSignal", errReason)
+ lane.Logger.Info().
+ Str("Revert Reason", errReason).
+ Interface("Args", v).
+ Str("FailedTx", failedTx.Hex()).
+ Msg("Msg sent while source ARM is cursed")
+ }
+
+ // now uncurse all
+ for _, lane := range lanes {
+ require.NoError(l.t, lane.Source.Common.UnvoteToCurseARM(), "error to unvote in cursing arm")
+ }
+ l.lggr.Info().Msg("Curse is lifted on all lanes")
+ // lift the pause on load test
+ l.pauseLoad.Store(false)
+
+ // now add the reverse lanes so that destination curse is also verified
+ // we add the reverse lanes now to verify absence of commit and execution for the reverse lanes
+ for _, lane := range l.TestSetupArgs.Lanes {
+ lanes = append(lanes, lane.ReverseLane)
+ }
+
+ // verify that even after uncursing the lane should not function for 30 more minutes,
+ // i.e no execution state changed or commit report accepted event is generated
+ errGrp := &errgroup.Group{}
+ for _, lane := range lanes {
+ lane := lane
+ curseTimeStamp, exists := curseTimeStamps[lane.SourceNetworkName]
+ // if curse timestamp does not exist for source, it will exist for destination
+ if !exists {
+ curseTimeStamp, exists = curseTimeStamps[lane.DestNetworkName]
+ require.Truef(l.t, exists, "did not find curse time stamp for lane %s->%s", lane.SourceNetworkName, lane.DestNetworkName)
+ }
+ errGrp.Go(func() error {
+ lane.Logger.Info().Msg("Validating no CommitReportAccepted event is received for 29 minutes")
+ // we allow additional 1 minute after curse timestamp for curse to be visible by plugin
+ return lane.Dest.AssertNoReportAcceptedEventReceived(lane.Logger, 25*time.Minute, curseTimeStamp.Add(1*time.Minute))
+ })
+ errGrp.Go(func() error {
+ lane.Logger.Info().Msg("Validating no ExecutionStateChanged event is received for 25 minutes")
+ // we allow additional 1 minute after curse timestamp for curse to be visible by plugin
+ return lane.Dest.AssertNoExecutionStateChangedEventReceived(lane.Logger, 25*time.Minute, curseTimeStamp.Add(1*time.Minute))
+ })
+ }
+ l.lggr.Info().Msg("waiting for no commit/execution validation")
+ err := errGrp.Wait()
+ require.NoError(l.t, err, "error received to validate no commit/execution is generated after lane is cursed")
+}
+
+func (l *LoadArgs) TriggerLoadByLane() {
+ l.TestSetupArgs.Reporter.SetDuration(l.TestCfg.TestGroupInput.LoadProfile.TestDuration.Duration())
+
+ // start load for a lane
+ startLoad := func(lane *actions.CCIPLane) {
+ lane.Logger.Info().
+ Str("Source Network", lane.SourceNetworkName).
+ Str("Destination Network", lane.DestNetworkName).
+ Msg("Starting load for lane")
+ sendMaxData := pointer.GetInt64(l.TestCfg.TestGroupInput.LoadProfile.SendMaxDataInEveryMsgCount)
+ ccipLoad := NewCCIPLoad(
+ l.TestCfg.Test, lane, l.TestCfg.TestGroupInput.PhaseTimeout.Duration(),
+ 100000, l.TestCfg.TestGroupInput.LoadProfile.MsgProfile, sendMaxData,
+ l.TestCfg.TestGroupInput.LoadProfile.SkipRequestIfAnotherRequestTriggeredWithin,
+ )
+ ccipLoad.BeforeAllCall()
+ // if it's not multicall set the tokens to nil to free up some space,
+ // we have already formed the msg to be sent in load, there is no need to store the bridge tokens anymore
+ // In case of multicall we still need the BridgeTokens to transfer amount from mutlicall to owner
+ if !lane.Source.Common.MulticallEnabled {
+ lane.Source.Common.BridgeTokens = nil
+ lane.Dest.Common.BridgeTokens = nil
+ }
+ // no need for price registry in load
+ lane.Source.Common.PriceRegistry = nil
+ lane.Dest.Common.PriceRegistry = nil
+ lokiConfig := l.TestCfg.EnvInput.Logging.Loki
+ labels := make(map[string]string)
+ for k, v := range l.Labels {
+ labels[k] = v
+ }
+ labels["source_chain"] = lane.SourceNetworkName
+ labels["dest_chain"] = lane.DestNetworkName
+ waspCfg := &wasp.Config{
+ T: l.TestCfg.Test,
+ GenName: fmt.Sprintf("lane %s-> %s", lane.SourceNetworkName, lane.DestNetworkName),
+ Schedule: l.scheduleForDest(lane.DestNetworkName),
+ LoadType: wasp.RPS,
+ RateLimitUnitDuration: l.TestCfg.TestGroupInput.LoadProfile.TimeUnit.Duration(),
+ CallResultBufLen: 10, // we keep the last 10 call results for each generator, as the detailed report is generated at the end of the test
+ CallTimeout: (l.TestCfg.TestGroupInput.PhaseTimeout.Duration()) * 5,
+ Gun: ccipLoad,
+ Logger: *ccipLoad.Lane.Logger,
+ LokiConfig: wasp.NewLokiConfig(lokiConfig.Endpoint, lokiConfig.TenantId, nil, nil),
+ Labels: labels,
+ FailOnErr: pointer.GetBool(l.TestCfg.TestGroupInput.LoadProfile.FailOnFirstErrorInLoad),
+ }
+ waspCfg.LokiConfig.Timeout = time.Minute
+ loadRunner, err := wasp.NewGenerator(waspCfg)
+ require.NoError(l.TestCfg.Test, err, "initiating loadgen for lane %s --> %s",
+ lane.SourceNetworkName, lane.DestNetworkName)
+ loadRunner.Run(false)
+ l.AddToRunnerGroup(loadRunner)
+ }
+
+ for _, lane := range l.TestSetupArgs.Lanes {
+ lane := lane
+ l.LoadStarterWg.Add(1)
+ go func() {
+ defer l.LoadStarterWg.Done()
+ startLoad(lane.ForwardLane)
+ }()
+ if pointer.GetBool(l.TestSetupArgs.Cfg.TestGroupInput.BiDirectionalLane) {
+ l.LoadStarterWg.Add(1)
+ go func() {
+ defer l.LoadStarterWg.Done()
+ startLoad(lane.ReverseLane)
+ }()
+ }
+ }
+}
+
+func (l *LoadArgs) AddToRunnerGroup(gen *wasp.Generator) {
+ // watch for pause signal
+ go func(gen *wasp.Generator) {
+ ticker := time.NewTicker(time.Second)
+ pausedOnce := false
+ resumedAlready := false
+ for {
+ select {
+ case <-ticker.C:
+ if l.pauseLoad.Load() && !pausedOnce {
+ gen.Pause()
+ pausedOnce = true
+ continue
+ }
+ if pausedOnce && !resumedAlready && !l.pauseLoad.Load() {
+ gen.Resume()
+ resumedAlready = true
+ }
+ case <-l.Ctx.Done():
+ return
+ }
+ }
+ }(gen)
+ l.RunnerWg.Go(func() error {
+ _, failed := gen.Wait()
+ if failed {
+ return fmt.Errorf("load run is failed")
+ }
+ if len(gen.Errors()) > 0 {
+ return fmt.Errorf("error in load sequence call %v", gen.Errors())
+ }
+ return nil
+ })
+}
+
+func (l *LoadArgs) Wait() {
+ l.lggr.Info().Msg("Waiting for load to start on all lanes")
+ // wait for load runner to start
+ l.LoadStarterWg.Wait()
+ l.lggr.Info().Msg("Waiting for load to finish on all lanes")
+ // wait for load runner to finish
+ err := l.RunnerWg.Wait()
+ require.NoError(l.t, err, "load run is failed")
+ l.lggr.Info().Msg("Load finished on all lanes")
+}
+
+func (l *LoadArgs) ApplyChaos() {
+ testEnv := l.TestSetupArgs.Env
+ if testEnv == nil || testEnv.K8Env == nil {
+ l.lggr.Warn().Msg("test environment is nil, skipping chaos")
+ return
+ }
+ testEnv.ChaosLabelForCLNodes(l.TestCfg.Test)
+
+ for _, exp := range l.ChaosExps {
+ if exp.WaitBetweenChaos > 0 {
+ l.lggr.Info().Msgf("sleeping for %s after chaos %s", exp.WaitBetweenChaos, exp.ChaosName)
+ time.Sleep(exp.WaitBetweenChaos)
+ }
+ l.lggr.Info().Msgf("Starting to apply chaos %s at %s", exp.ChaosName, time.Now().UTC())
+ // apply chaos
+ chaosId, err := testEnv.K8Env.Chaos.Run(exp.ChaosFunc(testEnv.K8Env.Cfg.Namespace, exp.ChaosProps))
+ require.NoError(l.t, err)
+ if chaosId != "" {
+ chaosDur, err := time.ParseDuration(exp.ChaosProps.DurationStr)
+ require.NoError(l.t, err)
+ err = testEnv.K8Env.Chaos.WaitForAllRecovered(chaosId, chaosDur+1*time.Minute)
+ require.NoError(l.t, err)
+ l.lggr.Info().Msgf("chaos %s is recovered at %s", exp.ChaosName, time.Now().UTC())
+ err = testEnv.K8Env.Chaos.Stop(chaosId)
+ require.NoError(l.t, err)
+ l.lggr.Info().Msgf("stopped chaos %s at %s", exp.ChaosName, time.Now().UTC())
+ }
+ }
+}
+
+func (l *LoadArgs) TearDown() {
+ for _, tearDn := range l.LoadgenTearDowns {
+ tearDn()
+ }
+ if l.TestSetupArgs.TearDown != nil {
+ require.NoError(l.t, l.TestSetupArgs.TearDown())
+ }
+}
+
+func (l *LoadArgs) TriggerLoadBySource() {
+ require.NotNil(l.t, l.TestCfg.TestGroupInput.LoadProfile.TestDuration, "test duration input is nil")
+ require.GreaterOrEqual(l.t, 1, len(l.TestCfg.TestGroupInput.LoadProfile.RequestPerUnitTime), "time unit input must be specified")
+ l.TestSetupArgs.Reporter.SetDuration(l.TestCfg.TestGroupInput.LoadProfile.TestDuration.Duration())
+ var laneBySource = make(map[string][]*actions.CCIPLane)
+ for _, lane := range l.TestSetupArgs.Lanes {
+ laneBySource[lane.ForwardLane.SourceNetworkName] = append(laneBySource[lane.ForwardLane.SourceNetworkName], lane.ForwardLane)
+ if lane.ReverseLane != nil {
+ laneBySource[lane.ReverseLane.SourceNetworkName] = append(laneBySource[lane.ReverseLane.SourceNetworkName], lane.ReverseLane)
+ }
+ }
+ for source, lanes := range laneBySource {
+ source := source
+ lanes := lanes
+ l.LoadStarterWg.Add(1)
+ go func() {
+ defer l.LoadStarterWg.Done()
+ l.lggr.Info().
+ Str("Source Network", source).
+ Msg("Starting load for source")
+ allLabels := make(map[string]string)
+ for k, v := range l.Labels {
+ allLabels[k] = v
+ }
+ allLabels["source_chain"] = source
+ multiCallGen, err := NewMultiCallLoadGenerator(l.TestCfg, lanes, l.TestCfg.TestGroupInput.LoadProfile.RequestPerUnitTime[0], allLabels)
+ require.NoError(l.t, err)
+ lokiConfig := l.TestCfg.EnvInput.Logging.Loki
+ loadRunner, err := wasp.NewGenerator(&wasp.Config{
+ T: l.TestCfg.Test,
+ GenName: fmt.Sprintf("Source %s", source),
+ Schedule: wasp.Plain(1, l.TestCfg.TestGroupInput.LoadProfile.TestDuration.Duration()), // hardcoded request per unit time to 1 as we are using multiCallGen
+ LoadType: wasp.RPS,
+ RateLimitUnitDuration: l.TestCfg.TestGroupInput.LoadProfile.TimeUnit.Duration(),
+ CallResultBufLen: 10, // we keep the last 10 call results for each generator, as the detailed report is generated at the end of the test
+ CallTimeout: (l.TestCfg.TestGroupInput.PhaseTimeout.Duration()) * 5,
+ Gun: multiCallGen,
+ Logger: multiCallGen.logger,
+ LokiConfig: wasp.NewLokiConfig(lokiConfig.Endpoint, lokiConfig.TenantId, nil, nil),
+ Labels: allLabels,
+ FailOnErr: pointer.GetBool(l.TestCfg.TestGroupInput.LoadProfile.FailOnFirstErrorInLoad),
+ })
+ require.NoError(l.TestCfg.Test, err, "initiating loadgen for source %s", source)
+ loadRunner.Run(false)
+ l.AddToRunnerGroup(loadRunner)
+ l.LoadgenTearDowns = append(l.LoadgenTearDowns, func() {
+ require.NoError(l.t, multiCallGen.Stop())
+ })
+ }()
+ }
+}
+
+func NewLoadArgs(t *testing.T, lggr zerolog.Logger, chaosExps ...ChaosConfig) *LoadArgs {
+ wg, _ := errgroup.WithContext(testcontext.Get(t))
+ ctx := testcontext.Get(t)
+ return &LoadArgs{
+ t: t,
+ Ctx: ctx,
+ lggr: &lggr,
+ RunnerWg: wg,
+ TestCfg: testsetups.NewCCIPTestConfig(t, lggr, testconfig.Load),
+ ChaosExps: chaosExps,
+ LoadStarterWg: &sync.WaitGroup{},
+ pauseLoad: atomic.NewBool(false),
+ }
+}
diff --git a/integration-tests/ccip-tests/smoke/ccip_test.go b/integration-tests/ccip-tests/smoke/ccip_test.go
new file mode 100644
index 00000000000..9a34044a5d8
--- /dev/null
+++ b/integration-tests/ccip-tests/smoke/ccip_test.go
@@ -0,0 +1,1008 @@
+package smoke
+
+import (
+ "fmt"
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/AlekSi/pointer"
+ "github.com/stretchr/testify/require"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/logging"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr"
+
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testreporters"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups"
+)
+
+type testDefinition struct {
+ testName string
+ lane *actions.CCIPLane
+}
+
+func TestSmokeCCIPForBidirectionalLane(t *testing.T) {
+ t.Parallel()
+ log := logging.GetTestLogger(t)
+ TestCfg := testsetups.NewCCIPTestConfig(t, log, testconfig.Smoke)
+ require.NotNil(t, TestCfg.TestGroupInput.MsgDetails.DestGasLimit)
+ gasLimit := big.NewInt(*TestCfg.TestGroupInput.MsgDetails.DestGasLimit)
+ setUpOutput := testsetups.CCIPDefaultTestSetUp(t, &log, "smoke-ccip", nil, TestCfg)
+ if len(setUpOutput.Lanes) == 0 {
+ log.Info().Msg("No lanes found")
+ return
+ }
+
+ t.Cleanup(func() {
+ // If we are running a test that is a token transfer, we need to verify the balance.
+ // skip the balance check for existing deployment, there can be multiple external requests in progress for existing deployments
+ // other than token transfer initiated by the test, which can affect the balance check
+ // therefore we check the balance only for the ccip environment created by the test
+ if TestCfg.TestGroupInput.MsgDetails.IsTokenTransfer() &&
+ !pointer.GetBool(TestCfg.TestGroupInput.USDCMockDeployment) &&
+ !pointer.GetBool(TestCfg.TestGroupInput.ExistingDeployment) {
+ setUpOutput.Balance.Verify(t)
+ }
+ require.NoError(t, setUpOutput.TearDown())
+ })
+
+ // Create test definitions for each lane.
+ var tests []testDefinition
+ for _, lane := range setUpOutput.Lanes {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("CCIP message transfer from network %s to network %s",
+ lane.ForwardLane.SourceNetworkName, lane.ForwardLane.DestNetworkName),
+ lane: lane.ForwardLane,
+ })
+ if lane.ReverseLane != nil {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("CCIP message transfer from network %s to network %s",
+ lane.ReverseLane.SourceNetworkName, lane.ReverseLane.DestNetworkName),
+ lane: lane.ReverseLane,
+ })
+ }
+ }
+
+ // Execute tests.
+ log.Info().Int("Total Lanes", len(tests)).Msg("Starting CCIP test")
+ for _, test := range tests {
+ tc := test
+ t.Run(tc.testName, func(t *testing.T) {
+ t.Parallel()
+ tc.lane.Test = t
+ log.Info().
+ Str("Source", tc.lane.SourceNetworkName).
+ Str("Destination", tc.lane.DestNetworkName).
+ Msgf("Starting lane %s -> %s", tc.lane.SourceNetworkName, tc.lane.DestNetworkName)
+
+ tc.lane.RecordStateBeforeTransfer()
+ err := tc.lane.SendRequests(1, gasLimit)
+ require.NoError(t, err)
+ tc.lane.ValidateRequests()
+ })
+ }
+}
+
+func TestSmokeCCIPRateLimit(t *testing.T) {
+ t.Parallel()
+ log := logging.GetTestLogger(t)
+ TestCfg := testsetups.NewCCIPTestConfig(t, log, testconfig.Smoke)
+ require.True(t, TestCfg.TestGroupInput.MsgDetails.IsTokenTransfer(), "Test config should have token transfer message type")
+ setUpOutput := testsetups.CCIPDefaultTestSetUp(t, &log, "smoke-ccip", nil, TestCfg)
+ if len(setUpOutput.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ require.NoError(t, setUpOutput.TearDown())
+ })
+
+ var tests []testDefinition
+ for _, lane := range setUpOutput.Lanes {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("Network %s to network %s",
+ lane.ForwardLane.SourceNetworkName, lane.ForwardLane.DestNetworkName),
+ lane: lane.ForwardLane,
+ })
+ }
+
+ // if we are running in simulated or in testnet mode, we can set the rate limit to test friendly values
+ // For mainnet, we need to set this as false to avoid changing the deployed contract config
+ setRateLimit := true
+ AggregatedRateLimitCapacity := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(30))
+ AggregatedRateLimitRate := big.NewInt(1e17)
+
+ TokenPoolRateLimitCapacity := new(big.Int).Mul(big.NewInt(1e17), big.NewInt(1))
+ TokenPoolRateLimitRate := big.NewInt(1e14)
+
+ for _, test := range tests {
+ tc := test
+ t.Run(fmt.Sprintf("%s - Rate Limit", tc.testName), func(t *testing.T) {
+ tc.lane.Test = t
+ src := tc.lane.Source
+ // add liquidity to pools on both networks
+ if !pointer.GetBool(TestCfg.TestGroupInput.ExistingDeployment) {
+ addLiquidity(t, src.Common, new(big.Int).Mul(AggregatedRateLimitCapacity, big.NewInt(20)))
+ addLiquidity(t, tc.lane.Dest.Common, new(big.Int).Mul(AggregatedRateLimitCapacity, big.NewInt(20)))
+ }
+ log.Info().
+ Str("Source", tc.lane.SourceNetworkName).
+ Str("Destination", tc.lane.DestNetworkName).
+ Msgf("Starting lane %s -> %s", tc.lane.SourceNetworkName, tc.lane.DestNetworkName)
+
+ // capture the rate limit config before we change it
+ prevRLOnRamp, err := src.OnRamp.Instance.CurrentRateLimiterState(nil)
+ require.NoError(t, err)
+ tc.lane.Logger.Info().Interface("rate limit", prevRLOnRamp).Msg("Initial OnRamp rate limiter state")
+
+ prevOnRampRLTokenPool, err := src.Common.BridgeTokenPools[0].Instance.GetCurrentOutboundRateLimiterState(
+ nil, tc.lane.Source.DestChainSelector,
+ ) // TODO RENS maybe?
+ require.NoError(t, err)
+ tc.lane.Logger.Info().
+ Interface("rate limit", prevOnRampRLTokenPool).
+ Str("pool", src.Common.BridgeTokenPools[0].Address()).
+ Str("onRamp", src.OnRamp.Address()).
+ Msg("Initial Token Pool rate limiter state")
+
+ // some sanity checks
+ rlOffRamp, err := tc.lane.Dest.OffRamp.Instance.CurrentRateLimiterState(nil)
+ require.NoError(t, err)
+ tc.lane.Logger.Info().Interface("rate limit", rlOffRamp).Msg("Initial OffRamp rate limiter state")
+ if rlOffRamp.IsEnabled {
+ require.GreaterOrEqual(t, rlOffRamp.Capacity.Cmp(prevRLOnRamp.Capacity), 0,
+ "OffRamp Aggregated capacity should be greater than or equal to OnRamp Aggregated capacity",
+ )
+ }
+
+ prevOffRampRLTokenPool, err := tc.lane.Dest.Common.BridgeTokenPools[0].Instance.GetCurrentInboundRateLimiterState(
+ nil, tc.lane.Dest.SourceChainSelector,
+ ) // TODO RENS maybe?
+ require.NoError(t, err)
+ tc.lane.Logger.Info().
+ Interface("rate limit", prevOffRampRLTokenPool).
+ Str("pool", tc.lane.Dest.Common.BridgeTokenPools[0].Address()).
+ Str("offRamp", tc.lane.Dest.OffRamp.Address()).
+ Msg("Initial Token Pool rate limiter state")
+ if prevOffRampRLTokenPool.IsEnabled {
+ require.GreaterOrEqual(t, prevOffRampRLTokenPool.Capacity.Cmp(prevOnRampRLTokenPool.Capacity), 0,
+ "OffRamp Token Pool capacity should be greater than or equal to OnRamp Token Pool capacity",
+ )
+ }
+
+ AggregatedRateLimitChanged := false
+ TokenPoolRateLimitChanged := false
+
+ // reset the rate limit config to what it was before the tc
+ t.Cleanup(func() {
+ if AggregatedRateLimitChanged {
+ require.NoError(t, src.OnRamp.SetRateLimit(evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: prevRLOnRamp.IsEnabled,
+ Capacity: prevRLOnRamp.Capacity,
+ Rate: prevRLOnRamp.Rate,
+ }), "setting rate limit")
+ require.NoError(t, src.Common.ChainClient.WaitForEvents(), "waiting for events")
+ }
+ if TokenPoolRateLimitChanged {
+ require.NoError(t, src.Common.BridgeTokenPools[0].SetRemoteChainRateLimits(src.DestChainSelector,
+ token_pool.RateLimiterConfig{
+ Capacity: prevOnRampRLTokenPool.Capacity,
+ IsEnabled: prevOnRampRLTokenPool.IsEnabled,
+ Rate: prevOnRampRLTokenPool.Rate,
+ }))
+ require.NoError(t, src.Common.ChainClient.WaitForEvents(), "waiting for events")
+ }
+ })
+
+ if setRateLimit {
+ if prevRLOnRamp.Capacity.Cmp(AggregatedRateLimitCapacity) != 0 ||
+ prevRLOnRamp.Rate.Cmp(AggregatedRateLimitRate) != 0 ||
+ !prevRLOnRamp.IsEnabled {
+ require.NoError(t, src.OnRamp.SetRateLimit(evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: AggregatedRateLimitCapacity,
+ Rate: AggregatedRateLimitRate,
+ }), "setting rate limit on onramp")
+ require.NoError(t, src.Common.ChainClient.WaitForEvents(), "waiting for events")
+ AggregatedRateLimitChanged = true
+ }
+ } else {
+ AggregatedRateLimitCapacity = prevRLOnRamp.Capacity
+ AggregatedRateLimitRate = prevRLOnRamp.Rate
+ }
+
+ rlOnRamp, err := src.OnRamp.Instance.CurrentRateLimiterState(nil)
+ require.NoError(t, err)
+ tc.lane.Logger.Info().Interface("rate limit", rlOnRamp).Msg("OnRamp rate limiter state")
+ require.True(t, rlOnRamp.IsEnabled, "OnRamp rate limiter should be enabled")
+
+ tokenPrice, err := src.Common.PriceRegistry.Instance.GetTokenPrice(nil, src.Common.BridgeTokens[0].ContractAddress)
+ require.NoError(t, err)
+ tc.lane.Logger.Info().Str("tokenPrice.Value", tokenPrice.String()).Msg("Price Registry Token Price")
+
+ totalTokensForOnRampCapacity := new(big.Int).Mul(
+ big.NewInt(1e18),
+ new(big.Int).Div(rlOnRamp.Capacity, tokenPrice),
+ )
+
+ tc.lane.Source.Common.ChainClient.ParallelTransactions(true)
+
+ // current tokens are equal to the full capacity - should fail
+ src.TransferAmount[0] = rlOnRamp.Tokens
+ tc.lane.Logger.Info().Str("tokensToSend", rlOnRamp.Tokens.String()).Msg("Aggregated Capacity")
+ // approve the tokens
+ require.NoError(t, src.Common.BridgeTokens[0].Approve(
+ tc.lane.Source.Common.ChainClient.GetDefaultWallet(), src.Common.Router.Address(), src.TransferAmount[0]),
+ )
+ require.NoError(t, tc.lane.Source.Common.ChainClient.WaitForEvents())
+ failedTx, _, _, err := tc.lane.Source.SendRequest(
+ tc.lane.Dest.ReceiverDapp.EthAddress,
+ big.NewInt(actions.DefaultDestinationGasLimit), // gas limit
+ )
+ require.NoError(t, err)
+ require.Error(t, tc.lane.Source.Common.ChainClient.WaitForEvents())
+ errReason, v, err := tc.lane.Source.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI)
+ require.NoError(t, err)
+ tc.lane.Logger.Info().
+ Str("Revert Reason", errReason).
+ Interface("Args", v).
+ Str("TokensSent", src.TransferAmount[0].String()).
+ Str("Token", tc.lane.Source.Common.BridgeTokens[0].Address()).
+ Str("FailedTx", failedTx.Hex()).
+ Msg("Msg sent with tokens more than AggregateValueMaxCapacity")
+ require.Equal(t, "AggregateValueMaxCapacityExceeded", errReason)
+
+ // 99% of the aggregated capacity - should succeed
+ tokensToSend := new(big.Int).Div(new(big.Int).Mul(totalTokensForOnRampCapacity, big.NewInt(99)), big.NewInt(100))
+ tc.lane.Logger.Info().Str("tokensToSend", tokensToSend.String()).Msg("99% of Aggregated Capacity")
+ tc.lane.RecordStateBeforeTransfer()
+ src.TransferAmount[0] = tokensToSend
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+
+ // try to send again with amount more than the amount refilled by rate and
+ // this should fail, as the refill rate is not enough to refill the capacity
+ src.TransferAmount[0] = new(big.Int).Mul(AggregatedRateLimitRate, big.NewInt(10))
+ failedTx, _, _, err = tc.lane.Source.SendRequest(
+ tc.lane.Dest.ReceiverDapp.EthAddress,
+ big.NewInt(actions.DefaultDestinationGasLimit), // gas limit
+ )
+ tc.lane.Logger.Info().Str("tokensToSend", src.TransferAmount[0].String()).Msg("More than Aggregated Rate")
+ require.NoError(t, err)
+ require.Error(t, tc.lane.Source.Common.ChainClient.WaitForEvents())
+ errReason, v, err = tc.lane.Source.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI)
+ require.NoError(t, err)
+ tc.lane.Logger.Info().
+ Str("Revert Reason", errReason).
+ Interface("Args", v).
+ Str("TokensSent", src.TransferAmount[0].String()).
+ Str("Token", tc.lane.Source.Common.BridgeTokens[0].Address()).
+ Str("FailedTx", failedTx.Hex()).
+ Msg("Msg sent with tokens more than AggregateValueRate")
+ require.Equal(t, "AggregateValueRateLimitReached", errReason)
+
+ // validate the successful request was delivered to the destination
+ tc.lane.ValidateRequests()
+
+ // now set the token pool rate limit
+ if setRateLimit {
+ if prevOnRampRLTokenPool.Capacity.Cmp(TokenPoolRateLimitCapacity) != 0 ||
+ prevOnRampRLTokenPool.Rate.Cmp(TokenPoolRateLimitRate) != 0 ||
+ !prevOnRampRLTokenPool.IsEnabled {
+ require.NoError(t, src.Common.BridgeTokenPools[0].SetRemoteChainRateLimits(
+ src.DestChainSelector,
+ token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: TokenPoolRateLimitCapacity,
+ Rate: TokenPoolRateLimitRate,
+ }), "error setting rate limit on token pool")
+ require.NoError(t, src.Common.ChainClient.WaitForEvents(), "waiting for events")
+ TokenPoolRateLimitChanged = true
+ }
+ } else {
+ TokenPoolRateLimitCapacity = prevOnRampRLTokenPool.Capacity
+ TokenPoolRateLimitRate = prevOnRampRLTokenPool.Rate
+ }
+
+ rlOnPool, err := src.Common.BridgeTokenPools[0].Instance.GetCurrentOutboundRateLimiterState(nil, src.DestChainSelector)
+ require.NoError(t, err)
+ require.True(t, rlOnPool.IsEnabled, "Token Pool rate limiter should be enabled")
+
+ // try to send more than token pool capacity - should fail
+ tokensToSend = new(big.Int).Add(TokenPoolRateLimitCapacity, big.NewInt(2))
+
+ // wait for the AggregateCapacity to be refilled
+ onRampState, err := src.OnRamp.Instance.CurrentRateLimiterState(nil)
+ if err != nil {
+ return
+ }
+ if AggregatedRateLimitCapacity.Cmp(onRampState.Capacity) > 0 {
+ capacityToBeFilled := new(big.Int).Sub(AggregatedRateLimitCapacity, onRampState.Capacity)
+ durationToFill := time.Duration(new(big.Int).Div(capacityToBeFilled, AggregatedRateLimitRate).Int64())
+ tc.lane.Logger.Info().
+ Dur("wait duration", durationToFill).
+ Str("current capacity", onRampState.Capacity.String()).
+ Str("tokensToSend", tokensToSend.String()).
+ Msg("Waiting for aggregated capacity to be available")
+ time.Sleep(durationToFill * time.Second)
+ }
+
+ src.TransferAmount[0] = tokensToSend
+ tc.lane.Logger.Info().Str("tokensToSend", tokensToSend.String()).Msg("More than Token Pool Capacity")
+
+ failedTx, _, _, err = tc.lane.Source.SendRequest(
+ tc.lane.Dest.ReceiverDapp.EthAddress,
+ big.NewInt(actions.DefaultDestinationGasLimit), // gas limit
+ )
+ require.NoError(t, err)
+ require.Error(t, tc.lane.Source.Common.ChainClient.WaitForEvents())
+ errReason, v, err = tc.lane.Source.Common.ChainClient.RevertReasonFromTx(failedTx, lock_release_token_pool.LockReleaseTokenPoolABI)
+ require.NoError(t, err)
+ tc.lane.Logger.Info().
+ Str("Revert Reason", errReason).
+ Interface("Args", v).
+ Str("TokensSent", src.TransferAmount[0].String()).
+ Str("Token", tc.lane.Source.Common.BridgeTokens[0].Address()).
+ Str("FailedTx", failedTx.Hex()).
+ Msg("Msg sent with tokens more than token pool capacity")
+ require.Equal(t, "TokenMaxCapacityExceeded", errReason)
+
+ // try to send 99% of token pool capacity - should succeed
+ tokensToSend = new(big.Int).Div(new(big.Int).Mul(TokenPoolRateLimitCapacity, big.NewInt(99)), big.NewInt(100))
+ src.TransferAmount[0] = tokensToSend
+ tc.lane.Logger.Info().Str("tokensToSend", tokensToSend.String()).Msg("99% of Token Pool Capacity")
+ tc.lane.RecordStateBeforeTransfer()
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+
+ // try to send again with amount more than the amount refilled by token pool rate and
+ // this should fail, as the refill rate is not enough to refill the capacity
+ tokensToSend = new(big.Int).Mul(TokenPoolRateLimitRate, big.NewInt(20))
+ tc.lane.Logger.Info().Str("tokensToSend", tokensToSend.String()).Msg("More than TokenPool Rate")
+ src.TransferAmount[0] = tokensToSend
+ // approve the tokens
+ require.NoError(t, src.Common.BridgeTokens[0].Approve(
+ src.Common.ChainClient.GetDefaultWallet(), src.Common.Router.Address(), src.TransferAmount[0]),
+ )
+ require.NoError(t, tc.lane.Source.Common.ChainClient.WaitForEvents())
+ failedTx, _, _, err = tc.lane.Source.SendRequest(
+ tc.lane.Dest.ReceiverDapp.EthAddress,
+ big.NewInt(actions.DefaultDestinationGasLimit),
+ )
+ require.NoError(t, err)
+ require.Error(t, tc.lane.Source.Common.ChainClient.WaitForEvents())
+ errReason, v, err = tc.lane.Source.Common.ChainClient.RevertReasonFromTx(failedTx, lock_release_token_pool.LockReleaseTokenPoolABI)
+ require.NoError(t, err)
+ tc.lane.Logger.Info().
+ Str("Revert Reason", errReason).
+ Interface("Args", v).
+ Str("TokensSent", src.TransferAmount[0].String()).
+ Str("Token", tc.lane.Source.Common.BridgeTokens[0].Address()).
+ Str("FailedTx", failedTx.Hex()).
+ Msg("Msg sent with tokens more than TokenPool Rate")
+ require.Equal(t, "TokenRateLimitReached", errReason)
+
+ // validate that the successful transfers are reflected in destination
+ tc.lane.ValidateRequests()
+ })
+ }
+}
+
+func TestSmokeCCIPOnRampLimits(t *testing.T) {
+ t.Parallel()
+
+ log := logging.GetTestLogger(t)
+ TestCfg := testsetups.NewCCIPTestConfig(t, log, testconfig.Smoke, testsetups.WithNoTokensPerMessage(4), testsetups.WithTokensPerChain(4))
+ require.False(t, pointer.GetBool(TestCfg.TestGroupInput.ExistingDeployment),
+ "This test modifies contract state. Before running it, ensure you are willing and able to do so.",
+ )
+ err := contracts.MatchContractVersionsOrAbove(map[contracts.Name]contracts.Version{
+ contracts.OffRampContract: contracts.V1_5_0_dev,
+ contracts.OnRampContract: contracts.V1_5_0_dev,
+ })
+ require.NoError(t, err, "Required contract versions not met")
+
+ setUpOutput := testsetups.CCIPDefaultTestSetUp(t, &log, "smoke-ccip", nil, TestCfg)
+ if len(setUpOutput.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ require.NoError(t, setUpOutput.TearDown())
+ })
+
+ var tests []testDefinition
+ for _, lane := range setUpOutput.Lanes {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("Network %s to network %s",
+ lane.ForwardLane.SourceNetworkName, lane.ForwardLane.DestNetworkName),
+ lane: lane.ForwardLane,
+ })
+ }
+
+ var (
+ capacityLimit = big.NewInt(1e16)
+ overCapacityAmount = new(big.Int).Add(capacityLimit, big.NewInt(1))
+
+ // token without any transfer config
+ freeTokenIndex = 0
+ // token with bps non-zero, no agg rate limit
+ bpsTokenIndex = 1
+ // token with bps zero, with agg rate limit on
+ aggRateTokenIndex = 2
+ // token with both bps and agg rate limit
+ bpsAndAggTokenIndex = 3
+ )
+
+ for _, tc := range tests {
+ t.Run(fmt.Sprintf("%s - OnRamp Limits", tc.testName), func(t *testing.T) {
+ tc.lane.Test = t
+ src := tc.lane.Source
+ dest := tc.lane.Dest
+ require.GreaterOrEqual(t, len(src.Common.BridgeTokens), 2, "At least two bridge tokens needed for test")
+ require.GreaterOrEqual(t, len(src.Common.BridgeTokenPools), 2, "At least two bridge token pools needed for test")
+ require.GreaterOrEqual(t, len(dest.Common.BridgeTokens), 2, "At least two bridge tokens needed for test")
+ require.GreaterOrEqual(t, len(dest.Common.BridgeTokenPools), 2, "At least two bridge token pools needed for test")
+ addLiquidity(t, src.Common, new(big.Int).Mul(capacityLimit, big.NewInt(20)))
+ addLiquidity(t, dest.Common, new(big.Int).Mul(capacityLimit, big.NewInt(20)))
+
+ var (
+ freeToken = src.Common.BridgeTokens[freeTokenIndex]
+ bpsToken = src.Common.BridgeTokens[bpsTokenIndex]
+ aggRateToken = src.Common.BridgeTokens[aggRateTokenIndex]
+ bpsAndAggToken = src.Common.BridgeTokens[bpsAndAggTokenIndex]
+ )
+ tc.lane.Logger.Info().
+ Str("Free Token", freeToken.ContractAddress.Hex()).
+ Str("BPS Token", bpsToken.ContractAddress.Hex()).
+ Str("Agg Rate Token", aggRateToken.ContractAddress.Hex()).
+ Str("BPS and Agg Rate Token", bpsAndAggToken.ContractAddress.Hex()).
+ Msg("Tokens for rate limit testing")
+ err := tc.lane.DisableAllRateLimiting()
+ require.NoError(t, err, "Error disabling rate limits")
+
+ // Set reasonable rate limits for the tokens
+ err = src.OnRamp.SetTokenTransferFeeConfig([]evm_2_evm_onramp.EVM2EVMOnRampTokenTransferFeeConfigArgs{
+ {
+ Token: bpsToken.ContractAddress,
+ AggregateRateLimitEnabled: false,
+ DeciBps: 10,
+ },
+ {
+ Token: aggRateToken.ContractAddress,
+ AggregateRateLimitEnabled: true,
+ },
+ {
+ Token: bpsAndAggToken.ContractAddress,
+ AggregateRateLimitEnabled: true,
+ DeciBps: 10,
+ },
+ })
+ require.NoError(t, err, "Error setting OnRamp transfer fee config")
+ err = src.OnRamp.SetRateLimit(evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: capacityLimit,
+ Rate: new(big.Int).Mul(capacityLimit, big.NewInt(500)), // Set a high rate to avoid it getting in the way
+ })
+ require.NoError(t, err, "Error setting OnRamp rate limits")
+ err = src.Common.ChainClient.WaitForEvents()
+ require.NoError(t, err, "Error waiting for events")
+
+ // Send all tokens under their limits and ensure they succeed
+ src.TransferAmount[freeTokenIndex] = overCapacityAmount
+ src.TransferAmount[bpsTokenIndex] = overCapacityAmount
+ src.TransferAmount[aggRateTokenIndex] = big.NewInt(1)
+ src.TransferAmount[bpsAndAggTokenIndex] = big.NewInt(1)
+ tc.lane.RecordStateBeforeTransfer()
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+ tc.lane.ValidateRequests()
+
+ // Check that capacity limits are enforced
+ src.TransferAmount[freeTokenIndex] = big.NewInt(0)
+ src.TransferAmount[bpsTokenIndex] = big.NewInt(0)
+ src.TransferAmount[aggRateTokenIndex] = overCapacityAmount
+ src.TransferAmount[bpsAndAggTokenIndex] = big.NewInt(0)
+ failedTx, _, _, err := tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.Error(t, err, "Limited token transfer should immediately revert")
+ errReason, _, err := src.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI)
+ require.NoError(t, err)
+ require.Equal(t, "AggregateValueMaxCapacityExceeded", errReason, "Expected capacity limit reached error")
+ tc.lane.Logger.
+ Info().
+ Str("Token", aggRateToken.ContractAddress.Hex()).
+ Msg("Limited token transfer failed on source chain (a good thing in this context)")
+
+ src.TransferAmount[aggRateTokenIndex] = big.NewInt(0)
+ src.TransferAmount[bpsAndAggTokenIndex] = overCapacityAmount
+ failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.Error(t, err, "Limited token transfer should immediately revert")
+ errReason, _, err = src.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI)
+ require.NoError(t, err)
+ require.Equal(t, "AggregateValueMaxCapacityExceeded", errReason, "Expected capacity limit reached error")
+ tc.lane.Logger.
+ Info().
+ Str("Token", aggRateToken.ContractAddress.Hex()).
+ Msg("Limited token transfer failed on source chain (a good thing in this context)")
+
+ // Set a high price for the tokens to more easily trigger aggregate rate limits
+ // Aggregate rate limits are based on USD price of the tokens
+ err = src.Common.PriceRegistry.UpdatePrices([]contracts.InternalTokenPriceUpdate{
+ {
+ SourceToken: aggRateToken.ContractAddress,
+ UsdPerToken: big.NewInt(100),
+ },
+ {
+ SourceToken: bpsAndAggToken.ContractAddress,
+ UsdPerToken: big.NewInt(100),
+ },
+ }, []contracts.InternalGasPriceUpdate{})
+ require.NoError(t, err, "Error updating prices")
+ // Enable aggregate rate limiting for the limited tokens
+ err = src.OnRamp.SetRateLimit(evm_2_evm_onramp.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: new(big.Int).Mul(capacityLimit, big.NewInt(5000)), // Set a high capacity to avoid it getting in the way
+ Rate: big.NewInt(1),
+ })
+ require.NoError(t, err, "Error setting OnRamp rate limits")
+ err = src.Common.ChainClient.WaitForEvents()
+ require.NoError(t, err, "Error waiting for events")
+
+ // Send aggregate unlimited tokens and ensure they succeed
+ src.TransferAmount[freeTokenIndex] = overCapacityAmount
+ src.TransferAmount[bpsTokenIndex] = overCapacityAmount
+ src.TransferAmount[aggRateTokenIndex] = big.NewInt(0)
+ src.TransferAmount[bpsAndAggTokenIndex] = big.NewInt(0)
+ tc.lane.RecordStateBeforeTransfer()
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+ tc.lane.ValidateRequests()
+
+ // Check that aggregate rate limits are enforced on limited tokens
+ src.TransferAmount[freeTokenIndex] = big.NewInt(0)
+ src.TransferAmount[bpsTokenIndex] = big.NewInt(0)
+ src.TransferAmount[aggRateTokenIndex] = capacityLimit
+ src.TransferAmount[bpsAndAggTokenIndex] = big.NewInt(0)
+ failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.Error(t, err, "Aggregate rate limited token transfer should immediately revert")
+ errReason, _, err = src.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI)
+ require.NoError(t, err)
+ require.Equal(t, "AggregateValueRateLimitReached", errReason, "Expected aggregate rate limit reached error")
+ tc.lane.Logger.
+ Info().
+ Str("Token", aggRateToken.ContractAddress.Hex()).
+ Msg("Limited token transfer failed on source chain (a good thing in this context)")
+
+ src.TransferAmount[aggRateTokenIndex] = big.NewInt(0)
+ src.TransferAmount[bpsAndAggTokenIndex] = capacityLimit
+ failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.Error(t, err, "Aggregate rate limited token transfer should immediately revert")
+ errReason, _, err = src.Common.ChainClient.RevertReasonFromTx(failedTx, evm_2_evm_onramp.EVM2EVMOnRampABI)
+ require.NoError(t, err)
+ require.Equal(t, "AggregateValueRateLimitReached", errReason, "Expected aggregate rate limit reached error")
+ tc.lane.Logger.
+ Info().
+ Str("Token", aggRateToken.ContractAddress.Hex()).
+ Msg("Limited token transfer failed on source chain (a good thing in this context)")
+ })
+ }
+}
+
+func TestSmokeCCIPOffRampCapacityLimit(t *testing.T) {
+ t.Parallel()
+
+ capacityLimited := contracts.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: big.NewInt(1e16),
+ Rate: new(big.Int).Mul(big.NewInt(1e16), big.NewInt(10)), // Set a high rate limit to avoid it getting in the way
+ }
+ testOffRampRateLimits(t, capacityLimited)
+}
+
+func TestSmokeCCIPOffRampAggRateLimit(t *testing.T) {
+ t.Parallel()
+
+ aggRateLimited := contracts.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: new(big.Int).Mul(big.NewInt(1e16), big.NewInt(10)), // Set a high capacity limit to avoid it getting in the way
+ Rate: big.NewInt(1),
+ }
+ testOffRampRateLimits(t, aggRateLimited)
+}
+
+func TestSmokeCCIPTokenPoolRateLimits(t *testing.T) {
+ t.Parallel()
+
+ log := logging.GetTestLogger(t)
+ TestCfg := testsetups.NewCCIPTestConfig(t, log, testconfig.Smoke, testsetups.WithNoTokensPerMessage(4), testsetups.WithTokensPerChain(4))
+ require.False(t, pointer.GetBool(TestCfg.TestGroupInput.ExistingDeployment),
+ "This test modifies contract state. Before running it, ensure you are willing and able to do so.",
+ )
+ err := contracts.MatchContractVersionsOrAbove(map[contracts.Name]contracts.Version{
+ contracts.OffRampContract: contracts.V1_5_0_dev,
+ contracts.OnRampContract: contracts.V1_5_0_dev,
+ })
+ require.NoError(t, err, "Required contract versions not met")
+
+ setUpOutput := testsetups.CCIPDefaultTestSetUp(t, &log, "smoke-ccip", nil, TestCfg)
+ if len(setUpOutput.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ require.NoError(t, setUpOutput.TearDown())
+ })
+
+ var tests []testDefinition
+ for _, lane := range setUpOutput.Lanes {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("Network %s to network %s",
+ lane.ForwardLane.SourceNetworkName, lane.ForwardLane.DestNetworkName),
+ lane: lane.ForwardLane,
+ })
+ }
+
+ var (
+ capacityLimit = big.NewInt(1e16)
+ overCapacityAmount = new(big.Int).Add(capacityLimit, big.NewInt(1))
+
+ // token without any limits
+ freeTokenIndex = 0
+ // token with rate limits
+ limitedTokenIndex = 1
+ )
+
+ for _, tc := range tests {
+ t.Run(fmt.Sprintf("%s - Token Pool Rate Limits", tc.testName), func(t *testing.T) {
+ tc.lane.Test = t
+ src := tc.lane.Source
+ dest := tc.lane.Dest
+ require.GreaterOrEqual(t, len(src.Common.BridgeTokens), 2, "At least two bridge tokens needed for test")
+ require.GreaterOrEqual(t, len(src.Common.BridgeTokenPools), 2, "At least two bridge token pools needed for test")
+ require.GreaterOrEqual(t, len(dest.Common.BridgeTokens), 2, "At least two bridge tokens needed for test")
+ require.GreaterOrEqual(t, len(dest.Common.BridgeTokenPools), 2, "At least two bridge token pools needed for test")
+ addLiquidity(t, src.Common, new(big.Int).Mul(capacityLimit, big.NewInt(20)))
+ addLiquidity(t, dest.Common, new(big.Int).Mul(capacityLimit, big.NewInt(20)))
+
+ var (
+ freeToken = src.Common.BridgeTokens[freeTokenIndex]
+ limitedToken = src.Common.BridgeTokens[limitedTokenIndex]
+ limitedTokenPool = src.Common.BridgeTokenPools[limitedTokenIndex]
+ )
+ tc.lane.Logger.Info().
+ Str("Free Token", freeToken.ContractAddress.Hex()).
+ Str("Limited Token", limitedToken.ContractAddress.Hex()).
+ Msg("Tokens for rate limit testing")
+ err := tc.lane.DisableAllRateLimiting() // Make sure this is pure
+ require.NoError(t, err, "Error disabling rate limits")
+
+ // Check capacity limits
+ err = limitedTokenPool.SetRemoteChainRateLimits(src.DestChainSelector, token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: capacityLimit,
+ Rate: new(big.Int).Sub(capacityLimit, big.NewInt(1)), // Set as high rate as possible to avoid it getting in the way
+ })
+ require.NoError(t, err, "Error setting token pool rate limit")
+ err = src.Common.ChainClient.WaitForEvents()
+ require.NoError(t, err, "Error waiting for events")
+
+ // Send all tokens under their limits and ensure they succeed
+ src.TransferAmount[freeTokenIndex] = overCapacityAmount
+ src.TransferAmount[limitedTokenIndex] = big.NewInt(1)
+ tc.lane.RecordStateBeforeTransfer()
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+ tc.lane.ValidateRequests()
+
+ // Send limited token over capacity and ensure it fails
+ src.TransferAmount[freeTokenIndex] = big.NewInt(0)
+ src.TransferAmount[limitedTokenIndex] = overCapacityAmount
+ failedTx, _, _, err := tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.Error(t, err, "Limited token transfer should immediately revert")
+ errReason, _, err := src.Common.ChainClient.RevertReasonFromTx(failedTx, lock_release_token_pool.LockReleaseTokenPoolABI)
+ require.NoError(t, err)
+ require.Equal(t, "TokenMaxCapacityExceeded", errReason, "Expected token capacity error")
+ tc.lane.Logger.
+ Info().
+ Str("Token", limitedToken.ContractAddress.Hex()).
+ Msg("Limited token transfer failed on source chain (a good thing in this context)")
+
+ // Check rate limit
+ err = limitedTokenPool.SetRemoteChainRateLimits(src.DestChainSelector, token_pool.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: new(big.Int).Mul(capacityLimit, big.NewInt(2)), // Set a high capacity to avoid it getting in the way
+ Rate: big.NewInt(1),
+ })
+ require.NoError(t, err, "Error setting token pool rate limit")
+ err = src.Common.ChainClient.WaitForEvents()
+ require.NoError(t, err, "Error waiting for events")
+
+ // Send all tokens under their limits and ensure they succeed
+ src.TransferAmount[freeTokenIndex] = overCapacityAmount
+ src.TransferAmount[limitedTokenIndex] = capacityLimit
+ tc.lane.RecordStateBeforeTransfer()
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+ tc.lane.ValidateRequests()
+
+ // Send limited token over rate limit and ensure it fails
+ src.TransferAmount[freeTokenIndex] = big.NewInt(0)
+ src.TransferAmount[limitedTokenIndex] = capacityLimit
+ failedTx, _, _, err = tc.lane.Source.SendRequest(tc.lane.Dest.ReceiverDapp.EthAddress, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.Error(t, err, "Limited token transfer should immediately revert")
+ errReason, _, err = src.Common.ChainClient.RevertReasonFromTx(failedTx, lock_release_token_pool.LockReleaseTokenPoolABI)
+ require.NoError(t, err)
+ require.Equal(t, "TokenRateLimitReached", errReason, "Expected rate limit reached error")
+ tc.lane.Logger.
+ Info().
+ Str("Token", limitedToken.ContractAddress.Hex()).
+ Msg("Limited token transfer failed on source chain (a good thing in this context)")
+ })
+ }
+}
+
+func TestSmokeCCIPMulticall(t *testing.T) {
+ t.Parallel()
+ log := logging.GetTestLogger(t)
+ TestCfg := testsetups.NewCCIPTestConfig(t, log, testconfig.Smoke)
+ // enable multicall in one tx for this test
+ TestCfg.TestGroupInput.MulticallInOneTx = ptr.Ptr(true)
+ setUpOutput := testsetups.CCIPDefaultTestSetUp(t, &log, "smoke-ccip", nil, TestCfg)
+ if len(setUpOutput.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ require.NoError(t, setUpOutput.TearDown())
+ })
+
+ var tests []testDefinition
+ for _, lane := range setUpOutput.Lanes {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("CCIP message transfer from network %s to network %s",
+ lane.ForwardLane.SourceNetworkName, lane.ForwardLane.DestNetworkName),
+ lane: lane.ForwardLane,
+ })
+ if lane.ReverseLane != nil {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("CCIP message transfer from network %s to network %s",
+ lane.ReverseLane.SourceNetworkName, lane.ReverseLane.DestNetworkName),
+ lane: lane.ReverseLane,
+ })
+ }
+ }
+
+ log.Info().Int("Total Lanes", len(tests)).Msg("Starting CCIP test")
+ for _, test := range tests {
+ tc := test
+ t.Run(tc.testName, func(t *testing.T) {
+ t.Parallel()
+ tc.lane.Test = t
+ log.Info().
+ Str("Source", tc.lane.SourceNetworkName).
+ Str("Destination", tc.lane.DestNetworkName).
+ Msgf("Starting lane %s -> %s", tc.lane.SourceNetworkName, tc.lane.DestNetworkName)
+
+ tc.lane.RecordStateBeforeTransfer()
+ err := tc.lane.Multicall(TestCfg.TestGroupInput.NoOfSendsInMulticall, tc.lane.Source.Common.MulticallContract)
+ require.NoError(t, err)
+ tc.lane.ValidateRequests()
+ })
+ }
+}
+
+func TestSmokeCCIPManuallyExecuteAfterExecutionFailingDueToInsufficientGas(t *testing.T) {
+ t.Parallel()
+ log := logging.GetTestLogger(t)
+ TestCfg := testsetups.NewCCIPTestConfig(t, log, testconfig.Smoke)
+ setUpOutput := testsetups.CCIPDefaultTestSetUp(t, &log, "smoke-ccip", nil, TestCfg)
+ if len(setUpOutput.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ if TestCfg.TestGroupInput.MsgDetails.IsTokenTransfer() {
+ setUpOutput.Balance.Verify(t)
+ }
+ require.NoError(t, setUpOutput.TearDown())
+ })
+
+ var tests []testDefinition
+ for _, lane := range setUpOutput.Lanes {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("CCIP message transfer from network %s to network %s",
+ lane.ForwardLane.SourceNetworkName, lane.ForwardLane.DestNetworkName),
+ lane: lane.ForwardLane,
+ })
+ if lane.ReverseLane != nil {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("CCIP message transfer from network %s to network %s",
+ lane.ReverseLane.SourceNetworkName, lane.ReverseLane.DestNetworkName),
+ lane: lane.ReverseLane,
+ })
+ }
+ }
+
+ log.Info().Int("Total Lanes", len(tests)).Msg("Starting CCIP test")
+ for _, test := range tests {
+ tc := test
+ t.Run(tc.testName, func(t *testing.T) {
+ t.Parallel()
+ tc.lane.Test = t
+ log.Info().
+ Str("Source", tc.lane.SourceNetworkName).
+ Str("Destination", tc.lane.DestNetworkName).
+ Msgf("Starting lane %s -> %s", tc.lane.SourceNetworkName, tc.lane.DestNetworkName)
+
+ tc.lane.RecordStateBeforeTransfer()
+ // send with insufficient gas for ccip-receive to fail
+ err := tc.lane.SendRequests(1, big.NewInt(0))
+ require.NoError(t, err)
+ tc.lane.ValidateRequests(actions.ExpectPhaseToFail(testreporters.ExecStateChanged))
+ // wait for events
+ err = tc.lane.Dest.Common.ChainClient.WaitForEvents()
+ require.NoError(t, err)
+ // execute all failed ccip requests manually
+ err = tc.lane.ExecuteManually()
+ require.NoError(t, err)
+ if len(tc.lane.Source.TransferAmount) > 0 {
+ tc.lane.Source.UpdateBalance(int64(tc.lane.NumberOfReq), tc.lane.TotalFee, tc.lane.Balance)
+ tc.lane.Dest.UpdateBalance(tc.lane.Source.TransferAmount, int64(tc.lane.NumberOfReq), tc.lane.Balance)
+ }
+ })
+ }
+}
+
+// add liquidity to pools on both networks
+func addLiquidity(t *testing.T, ccipCommon *actions.CCIPCommon, amount *big.Int) {
+ t.Helper()
+
+ for i, btp := range ccipCommon.BridgeTokenPools {
+ token := ccipCommon.BridgeTokens[i]
+ err := btp.AddLiquidity(
+ token, token.OwnerWallet, amount,
+ )
+ require.NoError(t, err)
+ }
+}
+
+// testOffRampRateLimits tests the rate limiting functionality of the OffRamp contract
+// it's broken into a helper to help parallelize and keep the tests DRY
+func testOffRampRateLimits(t *testing.T, rateLimiterConfig contracts.RateLimiterConfig) {
+ t.Helper()
+
+ log := logging.GetTestLogger(t)
+ TestCfg := testsetups.NewCCIPTestConfig(t, log, testconfig.Smoke)
+ require.False(t, pointer.GetBool(TestCfg.TestGroupInput.ExistingDeployment),
+ "This test modifies contract state. Before running it, ensure you are willing and able to do so.",
+ )
+ err := contracts.MatchContractVersionsOrAbove(map[contracts.Name]contracts.Version{
+ contracts.OffRampContract: contracts.V1_5_0_dev,
+ })
+ require.NoError(t, err, "Required contract versions not met")
+ require.False(t, pointer.GetBool(TestCfg.TestGroupInput.ExistingDeployment), "This test modifies contract state and cannot be run on existing deployments")
+
+ // Set the default permissionless exec threshold lower so that we can manually execute the transactions faster
+ // Tuning this too low stops any transactions from being realistically executed
+ actions.DefaultPermissionlessExecThreshold = 1 * time.Minute
+
+ setUpOutput := testsetups.CCIPDefaultTestSetUp(t, &log, "smoke-ccip", nil, TestCfg)
+ if len(setUpOutput.Lanes) == 0 {
+ return
+ }
+ t.Cleanup(func() {
+ require.NoError(t, setUpOutput.TearDown())
+ })
+
+ var tests []testDefinition
+ for _, lane := range setUpOutput.Lanes {
+ tests = append(tests, testDefinition{
+ testName: fmt.Sprintf("Network %s to network %s",
+ lane.ForwardLane.SourceNetworkName, lane.ForwardLane.DestNetworkName),
+ lane: lane.ForwardLane,
+ })
+ }
+
+ var (
+ freeTokenIndex = 0
+ limitedTokenIndex = 1
+ )
+
+ for _, tc := range tests {
+ t.Run(fmt.Sprintf("%s - OffRamp Limits", tc.testName), func(t *testing.T) {
+ tc.lane.Test = t
+ src := tc.lane.Source
+ dest := tc.lane.Dest
+ var (
+ capacityLimit = rateLimiterConfig.Capacity
+ overLimitAmount = new(big.Int).Add(capacityLimit, big.NewInt(1))
+ )
+ require.GreaterOrEqual(t, len(src.Common.BridgeTokens), 2, "At least two bridge tokens needed for test")
+ require.GreaterOrEqual(t, len(src.Common.BridgeTokenPools), 2, "At least two bridge token pools needed for test")
+ require.GreaterOrEqual(t, len(dest.Common.BridgeTokens), 2, "At least two bridge tokens needed for test")
+ require.GreaterOrEqual(t, len(dest.Common.BridgeTokenPools), 2, "At least two bridge token pools needed for test")
+ addLiquidity(t, src.Common, new(big.Int).Mul(capacityLimit, big.NewInt(20)))
+ addLiquidity(t, dest.Common, new(big.Int).Mul(capacityLimit, big.NewInt(20)))
+
+ var (
+ freeSrcToken = src.Common.BridgeTokens[freeTokenIndex]
+ freeDestToken = dest.Common.BridgeTokens[freeTokenIndex]
+ limitedSrcToken = src.Common.BridgeTokens[limitedTokenIndex]
+ limitedDestToken = dest.Common.BridgeTokens[limitedTokenIndex]
+ )
+ tc.lane.Logger.Info().
+ Str("Free Source Token", freeSrcToken.Address()).
+ Str("Free Dest Token", freeDestToken.Address()).
+ Str("Limited Source Token", limitedSrcToken.Address()).
+ Str("Limited Dest Token", limitedDestToken.Address()).
+ Msg("Tokens for rate limit testing")
+
+ err := tc.lane.DisableAllRateLimiting()
+ require.NoError(t, err, "Error disabling rate limits")
+
+ // Send both tokens with no rate limits and ensure they succeed
+ src.TransferAmount[freeTokenIndex] = overLimitAmount
+ src.TransferAmount[limitedTokenIndex] = overLimitAmount
+ tc.lane.RecordStateBeforeTransfer()
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err)
+ tc.lane.ValidateRequests()
+
+ // Enable capacity limiting on the destination chain for the limited token
+ err = dest.AddRateLimitTokens([]*contracts.ERC20Token{limitedSrcToken}, []*contracts.ERC20Token{limitedDestToken})
+ require.NoError(t, err, "Error setting destination rate limits")
+ err = dest.OffRamp.SetRateLimit(rateLimiterConfig)
+ require.NoError(t, err, "Error setting destination rate limits")
+ err = dest.Common.ChainClient.WaitForEvents()
+ require.NoError(t, err, "Error waiting for events")
+ tc.lane.Logger.Debug().Str("Token", limitedSrcToken.ContractAddress.Hex()).Msg("Enabled capacity limit on destination chain")
+
+ // Send free token that should not have a rate limit and should succeed
+ src.TransferAmount[freeTokenIndex] = overLimitAmount
+ src.TransferAmount[limitedTokenIndex] = big.NewInt(0)
+ tc.lane.RecordStateBeforeTransfer()
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err, "Free token transfer failed")
+ tc.lane.ValidateRequests()
+ tc.lane.Logger.Info().Str("Token", freeSrcToken.ContractAddress.Hex()).Msg("Free token transfer succeeded")
+
+ // Send limited token with rate limit that should fail on the destination chain
+ src.TransferAmount[freeTokenIndex] = big.NewInt(0)
+ src.TransferAmount[limitedTokenIndex] = overLimitAmount
+ tc.lane.RecordStateBeforeTransfer()
+ err = tc.lane.SendRequests(1, big.NewInt(actions.DefaultDestinationGasLimit))
+ require.NoError(t, err, "Failed to send rate limited token transfer")
+
+ // We should see the ExecStateChanged phase fail on the OffRamp
+ tc.lane.ValidateRequests(actions.ExpectPhaseToFail(testreporters.ExecStateChanged))
+ tc.lane.Logger.Info().
+ Str("Token", limitedSrcToken.ContractAddress.Hex()).
+ Msg("Limited token transfer failed on destination chain (a good thing in this context)")
+
+ // Manually execute the rate limited token transfer and expect a similar error
+ tc.lane.Logger.Info().Str("Wait Time", actions.DefaultPermissionlessExecThreshold.String()).Msg("Waiting for Exec Threshold to Expire")
+ time.Sleep(actions.DefaultPermissionlessExecThreshold) // Give time to exit the window
+ // See above comment on timeout
+ err = tc.lane.ExecuteManually(actions.WithConfirmationTimeout(time.Minute))
+ require.Error(t, err, "There should be errors executing manually at this point")
+ tc.lane.Logger.Debug().Str("Error", err.Error()).Msg("Manually executed rate limited token transfer failed as expected")
+
+ // Change limits to make it viable
+ err = dest.OffRamp.SetRateLimit(contracts.RateLimiterConfig{
+ IsEnabled: true,
+ Capacity: new(big.Int).Mul(capacityLimit, big.NewInt(100)),
+ Rate: new(big.Int).Mul(capacityLimit, big.NewInt(100)),
+ })
+ require.NoError(t, err, "Error setting destination rate limits")
+ err = dest.Common.ChainClient.WaitForEvents()
+ require.NoError(t, err, "Error waiting for events")
+
+ // Execute again manually and expect a pass
+ err = tc.lane.ExecuteManually()
+ require.NoError(t, err, "Error manually executing transaction after rate limit is lifted")
+ })
+ }
+
+}
diff --git a/integration-tests/ccip-tests/testconfig/README.md b/integration-tests/ccip-tests/testconfig/README.md
new file mode 100644
index 00000000000..51009e49a20
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/README.md
@@ -0,0 +1,827 @@
+# CCIP Configuration
+
+The CCIP configuration is used to specify the test configuration for running the CCIP integration tests.
+The configuration is specified in a TOML file. The configuration is used to specify the test environment, test type, test parameters, and other necessary details for running the tests.
+The test config is read in following order:
+
+- The test reads the default configuration from [ccip-default.toml](./tomls/ccip-default.toml).
+- The default can be overridden by specifying the test config in a separate file.
+ - The file content needs to be encoded in base64 format and set in `BASE64_CCIP_CONFIG_OVERRIDE` environment variable.
+ - The config mentioned in this file will override the default config.
+ - Example override file - [override.toml.example](./examples/override.toml.example)
+- If there are sensitive details like private keys, credentials in test config, they can be specified in a separate dotenv file as env vars
+ - The `~/.testsecrets` file in home directory is automatically loaded and should have all test secrets as env vars
+ - Example secret file - [.testsecrets.example](./examples/.testsecrets.example)
+
+## CCIP.ContractVersions
+
+Specifies contract versions of different contracts to be referred by test.
+Supported versions are:
+
+- **PriceRegistry**: '1.2.0', 'Latest'
+- **OffRamp**: '1.2.0', 'Latest'
+- **OnRamp**: '1.2.0', 'Latest'
+- **TokenPool**: '1.4.0', 'Latest'
+- **CommitStore**: '1.2.0', 'Latest'
+
+Example Usage:
+
+```toml
+[CCIP.ContractVersions]
+PriceRegistry = "1.2.0"
+OffRamp = "1.2.0"
+OnRamp = "1.2.0"
+TokenPool = "1.4.0"
+CommitStore = "1.2.0"
+```
+
+## CCIP.Deployments
+
+CCIP Deployment contains all necessary contract addresses for various networks. This is mandatory if the test are to be run for [existing deployments](#ccipgroupstestgroupexistingdeployment)
+The deployment data can be specified -
+
+- Under `CCIP.Deployments.Data` field with value as stringify format of json.
+- Under `CCIP.Deployments.DataFile` field with value as the path of the file containing the deployment data in json format.
+
+The json schema is specified in https://github.com/smartcontractkit/ccip/blob/ccip-develop/integration-tests/ccip-tests/contracts/laneconfig/parse_contracts.go#L96
+
+Example Usage:
+
+```toml
+[CCIP.Deployments]
+Data = """
+{
+ "lane_configs": {
+ "Arbitrum Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4",
+ "bridge_tokens": ["0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"],
+ "bridge_tokens_pools": ["0x82aF49947D8a07e3bd95BD0d56f35241523fBab1"],
+ "arm": "0xe06b0e8c4bd455153e8794ad7Ea8Ff5A14B64E4b",
+ "router": "0x141fa059441E0ca23ce184B6A78bafD2A517DdE8",
+ "price_registry": "0x13015e4E6f839E1Aa1016DF521ea458ecA20438c",
+ "wrapped_native": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
+ "src_contracts": {
+ "Ethereum Mainnet": {
+ "on_ramp": "0xCe11020D56e5FDbfE46D9FC3021641FfbBB5AdEE",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Ethereum Mainnet": {
+ "off_ramp": "0x542ba1902044069330e8c5b36A84EC503863722f",
+ "commit_store": "0x060331fEdA35691e54876D957B4F9e3b8Cb47d20",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Ethereum Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x514910771AF9Ca656af840dff83E8264EcF986CA",
+ "bridge_tokens": ["0x8B63b3DE93431C0f756A493644d128134291fA1b"],
+ "bridge_tokens_pools": ["0x8B63b3DE93431C0f756A493644d128134291fA1b"],
+ "arm": "0x8B63b3DE93431C0f756A493644d128134291fA1b",
+ "router": "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D",
+ "price_registry": "0x8c9b2Efb7c64C394119270bfecE7f54763b958Ad",
+ "wrapped_native": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x925228D7B82d883Dde340A55Fe8e6dA56244A22C",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0xeFC4a18af59398FF23bfe7325F2401aD44286F4d",
+ "commit_store": "0x9B2EEd6A1e16cB50Ed4c876D2dD69468B21b7749",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ }
+ }
+}
+"""
+```
+
+Or,
+
+```toml
+[CCIP.Deployments]
+DataFile = ''
+```
+
+## CCIP.Env
+
+Specifies the environment details for the test to be run on.
+Mandatory fields are:
+
+- **Networks**: [CCIP.Env.Networks](#ccipenvnetworks)
+- **NewCLCluster**: [CCIP.Env.NewCLCluster](#ccipenvnewclcluster) - This is mandatory if the test needs to deploy Chainlink nodes.
+- **ExistingCLCluster**: [CCIP.Env.ExistingCLCluster](#ccipenvexistingclcluster) - This is mandatory if the test needs to run on existing Chainlink nodes to deploy ccip jobs.
+
+Test needs network/chain details to be set through configuration. This configuration is mandatory for running the tests.
+you have option to set the network details in two ways:
+
+1. Using [CCIP.Env.Networks](#ccipenvnetworks)
+2. Using a separate network config file -
+ - refer to the example - [network_config.toml.example](./examples/network_config.toml.example)
+ - once all necessary values are set, encode the toml file content in base64 format,
+ - set the base64'ed string content in `BASE64_NETWORK_CONFIG` environment variable.
+
+### CCIP.Env.Networks
+
+Specifies the network details for the test to be run.
+The NetworkConfig is imported from https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/config/network.go#L39
+
+#### CCIP.Env.Networks.selected_networks
+
+It denotes the network names in which tests will be run. These networks are used to deploy ccip contracts and set up lanes between them.
+If more than 2 networks are specified, then lanes will be set up between all possible pairs of networks.
+
+For example , if `selected_networks = ['SIMULATED_1', 'SIMULATED_2', 'SIMULATED_3']`, it denotes that lanes will be set up between SIMULATED_1 and SIMULATED_2, SIMULATED_1 and SIMULATED_3, SIMULATED_2 and SIMULATED_3
+This behaviour can be varied based on [NoOfNetworks](#ccipgroupstestgroupnoofnetworks), [NetworkPairs](#ccipgroupstestgroupnetworkpairs), [MaxNoOfLanes](#ccipgroupstestgroupmaxnooflanes) fields in test config.
+
+The name of the networks are taken from [known_networks](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/networks/known_networks.go#L884) in chainlink-testing-framework
+If the network is not present in known_networks, then the network details can be specified in the config file itself under the following `EVMNetworks` key.
+
+#### CCIP.Env.Network.EVMNetworks
+
+Specifies the network config to be used while creating blockchain EVMClient for test.
+It is a map of network name to EVMNetworks where key is network name specified under `CCIP.Env.Networks.selected_networks` and value is `EVMNetwork`.
+The EVMNetwork is imported from [EVMNetwork](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/blockchain/config.go#L43) in chainlink-testing-framework.
+
+If `CCIP.Env.Network.EVMNetworks` config is not set for a network name specified under `CCIP.Env.Networks.selected_networks`, test will try to find the corresponding network config from defined networks in `MappedNetworks` under [known_networks.go](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/networks/known_networks.go)
+
+#### CCIP.Env.Network.AnvilConfigs
+
+If the test needs to run on chains created using Anvil, then the AnvilConfigs can be specified.
+It is a map of network name to `AnvilConfig` where key is network name specified under `CCIP.Env.Networks.selected_networks` and value is `AnvilConfig`.
+The AnvilConfig is imported from [AnvilConfig](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/config/network.go#L20) in chainlink-testing-framework.
+
+**The following network configs are required for tests running on live networks. It can be ignored if the tests are running on simulated networks.**
+Refer to [secrets.toml.example](./examples/secrets.toml.example) for details.
+
+#### CCIP.ENV.Network.RpcHttpUrls
+
+RpcHttpUrls is the RPC HTTP endpoints for each network, key is the network name as declared in selected_networks slice.
+
+#### CCIP.ENV.Network.RpcWsUrls
+
+RpcWsUrls is the RPC WS endpoints for each network, key is the network name as declared in selected_networks slice.
+
+#### CCIP.ENV.Network.WalletKeys
+
+WalletKeys is the private keys for each network, key is the network name as declared in selected_networks slice.
+
+Example Usage of Network Config:
+
+```toml
+[CCIP.Env.Network]
+selected_networks= ['PRIVATE-CHAIN-1', 'PRIVATE-CHAIN-2']
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-1]
+evm_name = 'private-chain-1'
+evm_chain_id = 2337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 400
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-2]
+evm_name = 'private-chain-2'
+evm_chain_id = 1337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 400
+
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-1]
+block_time = 1
+
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-2]
+block_time = 1
+```
+
+### CCIP.Env.NewCLCluster
+
+The NewCLCluster config holds the overall deployment configuration for Chainlink nodes.
+
+#### CCIP.Env.NewCLCluster.NoOfNodes
+
+Specifies the number of Chainlink nodes to be deployed.
+
+#### CCIP.Env.NewCLCluster.Common
+
+Specifies the common configuration for all Chainlink nodes if they share the same configuration.
+
+##### Name
+
+Name of the node.
+
+##### NeedsUpgrade
+
+Indicates if the node needs an upgrade during test.
+
+##### ChainlinkImage
+
+Configuration for the Chainlink image.
+
+##### ChainlinkUpgradeImage
+
+Configuration for the Chainlink upgrade image. It is used when the node needs an upgrade.
+
+##### BaseConfigTOML
+
+String containing the base configuration toml content for the Chainlink node config.
+
+##### CommonChainConfigTOML
+
+String containing the common chain configuration toml content for all EVMNodes in chainlink node config.
+
+##### ChainConfigTOMLByChain
+
+String containing the chain-specific configuration toml content for individual EVMNodes in chainlink node config. This is keyed by chain ID.
+
+##### DBImage
+
+Database image for the Chainlink node.
+
+##### DBTag
+
+Database tag/version for the Chainlink node.
+
+#### CCIP.Env.NewCLCluster.Nodes
+
+Specifies the configuration for individual nodes if they differ from the common configuration. The fields are the same as the common configuration.
+
+#### CCIP.Env.NewCLCluster.NodeMemory
+
+Specifies the memory to be allocated for each Chainlink node. This is valid only if the deployment is on Kubernetes.
+
+#### CCIP.Env.NewCLCluster.NodeCPU
+
+Specifies the CPU to be allocated for each Chainlink node. This is valid only if the deployment is on Kubernetes.
+
+#### CCIP.Env.NewCLCluster.DBMemory
+
+Specifies the memory to be allocated for the database. This is valid only if the deployment is on Kubernetes.
+
+#### CCIP.Env.NewCLCluster.DBCPU
+
+Specifies the CPU to be allocated for the database. This is valid only if the deployment is on Kubernetes.
+
+#### CCIP.Env.NewCLCluster.IsStateful
+
+Specifies whether the deployment is StatefulSet on Kubernetes.
+
+#### CCIP.Env.NewCLCluster.DBStorageClass
+
+Specifies the storage class for the database. This is valid only if the deployment is StatefulSet on Kubernetes.
+
+#### CCIP.Env.NewCLCluster.DBCapacity
+
+Specifies the capacity of the database. This is valid only if the deployment is StatefulSet on Kubernetes.
+
+#### CCIP.Env.NewCLCluster.PromPgExporter
+
+Specifies whether to enable Prometheus PostgreSQL exporter. This is valid only if the deployment is on Kubernetes.
+
+#### CCIP.Env.NewCLCluster.DBArgs
+
+Specifies the arguments to be passed to the database. This is valid only if the deployment is on Kubernetes.
+
+Example Usage:
+
+```toml
+[CCIP.Env.NewCLCluster]
+NoOfNodes = 17
+NodeMemory = '12Gi'
+NodeCPU = '6'
+DBMemory = '10Gi'
+DBCPU = '2'
+DBStorageClass = 'gp3'
+PromPgExporter = true
+DBCapacity = '50Gi'
+IsStateful = true
+DBArgs = ['shared_buffers=2048MB', 'effective_cache_size=4096MB', 'work_mem=64MB']
+
+[CCIP.Env.NewCLCluster.Common]
+Name = 'node1'
+DBImage = 'postgres'
+DBTag = '13.12'
+CommonChainConfigTOML = """
+[HeadTracker]
+HistoryDepth = 400
+
+[GasEstimator]
+PriceMax = '200 gwei'
+LimitDefault = 6000000
+FeeCapDefault = '200 gwei'
+"""
+```
+
+### CCIP.Env.ExistingCLCluster
+
+The ExistingCLCluster config holds the overall connection configuration for existing Chainlink nodes.
+It is needed when the tests are to be run on Chainlink nodes already deployed on some environment.
+If this is specified, test will not need to connect to k8 namespace using [CCIP.Env.EnvToConnect](#ccipenvenvtoconnect).
+Test can directly connect to the existing Chainlink nodes using node credentials without knowing the k8 namespace details.
+
+#### CCIP.Env.ExistingCLCluster.Name
+
+Specifies the name of the existing Chainlink cluster. This is used to identify the cluster in the test.
+
+#### CCIP.Env.ExistingCLCluster.NoOfNodes
+
+Specifies the number of Chainlink nodes in the existing cluster.
+
+#### CCIP.Env.ExistingCLCluster.NodeConfigs
+
+Specifies the configuration for individual nodes in the existing cluster. Each node config contains the following fields to connect to the Chainlink node:
+
+##### CCIP.Env.ExistingCLCluster.NodeConfigs.URL
+
+The URL of the Chainlink node.
+
+##### CCIP.Env.ExistingCLCluster.NodeConfigs.Email
+
+The username/email of the Chainlink node credential.
+
+##### CCIP.Env.ExistingCLCluster.NodeConfigs.Password
+
+The password of the Chainlink node credential.
+
+##### CCIP.Env.ExistingCLCluster.NodeConfigs.InternalIP
+
+The internal IP of the Chainlink node.
+
+Example Usage:
+
+```toml
+[CCIP.Env.ExistingCLCluster]
+Name = 'crib-sample'
+NoOfNodes = 5
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-sample-demo-node1.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-1'
+
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-sample-demo-node2.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-2'
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-sample-demo-node3.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-3'
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-ani-demo-node4.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-4'
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-sample-demo-node5.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-5'
+```
+
+### CCIP.Env.EnvToConnect
+
+This is specified when the test needs to connect to already existing k8s namespace. User needs to have access to the k8 namespace to run the tests through specific kubeconfig file.
+Example usage:
+
+```toml
+[CCIP.Env]
+EnvToConnect="load-ccip-c8972"
+```
+
+### CCIP.ENV.TTL
+
+Specifies the time to live for the k8 namespace. This is used to terminate the namespace after the tests are run. This is only valid if the tests are run on k8s.
+Example usage:
+
+```toml
+[CCIP.Env]
+TTL = "11h"
+```
+
+### CCIP.Env.Logging
+
+Specifies the logging configuration for the test. Imported from [LoggingConfig](https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/config/logging.go#L11) in chainlink-testing-framework.
+Example usage:
+
+```toml
+[CCIP.Env.Logging]
+test_log_collect = false # if set to true will save logs even if test did not fail
+
+[CCIP.Env.Logging.LogStream]
+# supported targets: file, loki, in-memory. if empty no logs will be persistet
+log_targets = ["file"]
+# context timeout for starting log producer and also time-frame for requesting logs
+log_producer_timeout = "10s"
+# number of retries before log producer gives up and stops listening to logs
+log_producer_retry_limit = 10
+
+[CCIP.Env.Logging.Loki]
+tenant_id = "..."
+endpoint = "https://loki...."
+
+[CCIP.Env.Logging.Grafana]
+base_url = "https://grafana..../"
+dashboard_url = "/d/6vjVx-1V8/ccip-long-running-tests"
+```
+
+### CCIP.Env.Lane.LeaderLaneEnabled
+
+Specifies whether to enable the leader lane feature. This setting is only applicable for new deployments.
+
+## CCIP.Groups
+
+Specifies the test config specific to each test type. Available test types are:
+
+- **CCIP.Groups.load**
+- **CCIP.Groups.smoke**
+- **CCIP.Groups.chaos**
+
+### CCIP.Groups.[testgroup].KeepEnvAlive
+
+Specifies whether to keep the k8 namespace alive after the test is run. This is only valid if the tests are run on k8s.
+
+### CCIP.Groups.[testgroup].BiDirectionalLane
+
+Specifies whether to set up bi-directional lanes between networks.
+
+### CCIP.Groups.[testgroup].CommitAndExecuteOnSameDON
+
+Specifies whether commit and execution jobs are to be run on the same Chainlink node.
+
+### CCIP.Groups.[testgroup].NoOfCommitNodes
+
+Specifies the number of nodes on which commit jobs are to be run. This needs to be lesser than the total number of nodes mentioned in [CCIP.Env.NewCLCluster.NoOfNodes](#ccipenvnewclclusternoofnodes) or [CCIP.Env.ExistingCLCluster.NoOfNodes](#ccipenvexistingclclusternoofnodes).
+If the value of total nodes is `n`, then the max value of NoOfCommitNodes should be less than `n-1`. As the first node is used for bootstrap job.
+If the NoOfCommitNodes is lesser than `n-1`, then the remaining nodes are used for execution jobs if `CCIP.Groups.[testgroup].CommitAndExecuteOnSameDON` is set to false.
+
+### CCIP.Groups.[testgroup].TokenConfig
+
+Specifies the token configuration for the test. The token configuration is used to set up tokens and token pools for all chains.
+
+#### CCIP.Groups.[testgroup].TokenConfig.NoOfTokensPerChain
+
+Specifies the number of tokens to be set up for each chain.
+
+#### CCIP.Groups.[testgroup].TokenConfig.WithPipeline
+
+Specifies whether to set up token pipelines in commit jobspec. If set to false, the token prices will be set with DynamicPriceGetterConfig.
+
+#### CCIP.Groups.[testgroup].TokenConfig.TimeoutForPriceUpdate
+
+Specifies the timeout to wait for token and gas price updates to be available in price registry for each chain.
+
+#### CCIP.Groups.[testgroup].TokenConfig.NoOfTokensWithDynamicPrice
+
+Specifies the number of tokens to be set up with dynamic price update. The rest of the tokens will be set up with static price. This is only valid if [WithPipeline](#ccipgroupstestgrouptokenconfigwithpipeline) is set to false.
+
+#### CCIP.Groups.[testgroup].TokenConfig.DynamicPriceUpdateInterval
+
+Specifies the interval for dynamic price update for tokens. This is only valid if [NoOfTokensWithDynamicPrice](#ccipgroupstestgrouptokenconfignooftokenswithdynamicprice) is set to value greater tha zero.
+
+#### CCIP.Groups.[testgroup].TokenConfig.CCIPOwnerTokens
+
+Specifies the tokens to be owned by the CCIP owner. If this is false, the tokens and pools will be owned by an address other than rest of CCIP contract admin addresses.
+This is applicable only if the contract versions are '1.5' or higher.
+
+Example Usage:
+
+```toml
+[CCIP.Groups.load.TokenConfig]
+TimeoutForPriceUpdate = '15m'
+NoOfTokensPerChain = 60
+NoOfTokensWithDynamicPrice = 15
+DynamicPriceUpdateInterval ='15s'
+CCIPOwnerTokens = true
+```
+
+### CCIP.Groups.[testgroup].MsgDetails
+
+Specifies the ccip message details to be sent by the test.
+
+#### CCIP.Groups.[testgroup].MsgDetails.MsgType
+
+Specifies the type of message to be sent. The supported message types are:
+
+- **Token**
+- **Data**
+- **DataWithToken**
+
+#### CCIP.Groups.[testgroup].MsgDetails.DestGasLimit
+
+Specifies the gas limit for the destination chain. This is used to in `ExtraArgs` field of CCIPMessage. Change this to 0, if you are doing ccip-send to an EOA in the destination chain.
+
+#### CCIP.Groups.[testgroup].MsgDetails.DataLength
+
+Specifies the length of data to be sent in the message. This is only valid if [MsgType](#ccipgroupstestgroupmsgdetailsmsgtype) is set to 'Data' or 'DataWithToken'.
+
+#### CCIP.Groups.[testgroup].MsgDetails.NoOfTokens
+
+Specifies the number of tokens to be sent in the message. This is only valid if [MsgType](#ccipgroupstestgroupmsgdetailsmsgtype) is set to 'Token' or 'DataWithToken'.
+It needs to be less than or equal to [NoOfTokensPerChain](#ccipgroupstestgrouptokenconfignooftokensperchain) specified in the test config.
+
+#### CCIP.Groups.[testgroup].MsgDetails.TokenAmount
+
+Specifies the amount for each token to be sent in the message. This is only valid if [MsgType](#ccipgroupstestgroupmsgdetailsmsgtype) is set to 'Token' or 'DataWithToken'.
+
+Example Usage:
+
+```toml
+[CCIP.Groups.smoke.MsgDetails]
+MsgType = 'DataWithToken'
+DestGasLimit = 100000
+DataLength = 1000
+NoOfTokens = 2
+AmountPerToken = 1
+```
+
+### CCIP.Groups.[testgroup].MulticallInOneTx
+
+Specifies whether to send multiple ccip messages in a single transaction.
+
+### CCIP.Groups.[testgroup].NoOfSendsInMulticall
+
+Specifies the number of ccip messages to be sent in a single transaction. This is only valid if [MulticallInOneTx](#ccipgroupstestgroupmulticallinonetx) is set to true.
+
+### CCIP.Groups.[testgroup].PhaseTimeout
+
+The test validates various events in a ccip request lifecycle, like commit, execute, etc. This field specifies the timeout for each phase in the lifecycle.
+The timeout is calculated from the time the previous phase event is received.
+The following contract events are validated:
+
+- **CCIPSendRequested on OnRamp**
+- **CCIPSendRequested event log to be Finalized**
+- **ReportAccepted on CommitStore**
+- **TaggedRootBlessed on ARM/RMN**
+- **ExecutionStateChanged on OffRamp**
+
+### CCIP.Groups.[testgroup].LocalCluster
+
+Specifies whether the test is to be run on a local docker. If set to true, the test environment will be set up on a local docker.
+
+### CCIP.Groups.[testgroup].ExistingDeployment
+
+Specifies whether the test is to be run on existing deployments. If set to true, the test will use the deployment data specified in [CCIP.Deployments](#ccipdeployments) for interacting with the ccip contracts.
+If the deployment data does not contain the required contract addresses, the test will fail.
+
+### CCIP.Groups.[testgroup].ReuseContracts
+
+Test loads contract/lane config from [contracts.json](../contracts/laneconfig/contracts.json) if no lane config is specified in [CCIP.Deployments](#ccipdeployments)
+If a certain contract is present in the contracts.json, the test will use the contract address from the contracts.json.
+This field specifies whether to reuse the contracts from [contracts.json](../contracts/laneconfig/contracts.json)
+For example if the contracts.json contains the contract address for PriceRegistry for `Arbitrum Mainnet`, the test by default will use the contract address from contracts.json instead of redeploying the contract.
+If `ReuseContracts` is set to false, the test will redeploy the contract instead of using the contract address from contracts.json.
+
+### CCIP.Groups.[testgroup].NodeFunding
+
+Specified the native token funding for each Chainlink node. It assumes that the native token decimals is 18.
+The funding is done by the private key specified in [CCIP.Env.Networks](#ccipenvnetworks) for each network.
+The funding is done only if the test is run on local docker or k8s. This is not applicable for [existing deployments](#ccipgroupstestgroupexistingdeployment) is set to true.
+
+### CCIP.Groups.[testgroup].NetworkPairs
+
+Specifies the network pairs for which the test is to be run. The test will set up lanes only between the specified network pairs.
+If the network pairs are not specified, the test will set up lanes between all possible pairs of networks mentioned in selected_networks in [CCIP.Env.Networks](#ccipenvnetworksselectednetworks)
+
+### CCIP.Groups.[testgroup].NoOfNetworks
+
+Specifies the number of networks to be used for the test.
+If the number of networks is greater than the total number of networks specified in [CCIP.Env.Networks.selected_networks](#ccipenvnetworksselectednetworks):
+
+- the test will fail if the networks are live networks.
+- the test will create equal number of replicas of the first network with a new chain id if the networks are simulated networks.
+ For example, if the `selected_networks` is ['SIMULATED_1','SIMULATED_2'] and `NoOfNetworks` is 3, the test will create 1 more network config by copying the network config of `SIMULATED_1` with a different chain id and use that as 3rd network.
+
+### CCIP.Groups.[testgroup].NoOfRoutersPerPair
+
+Specifies the number of routers to be set up for each network.
+
+### CCIP.Groups.[testgroup].MaxNoOfLanes
+
+Specifies the maximum number of lanes to be set up between networks. If this values is not set, the test will set up lanes between all possible pairs of networks mentioned in `selected_networks` in [CCIP.Env.Networks](#ccipenvnetworksselectednetworks).
+For example, if `selected_networks = ['SIMULATED_1', 'SIMULATED_2', 'SIMULATED_3']`, and `MaxNoOfLanes` is set to 2, it denotes that the test will randomly select the 2 lanes between all possible pairs `SIMULATED_1`, `SIMULATED_2`, and `SIMULATED_3` for the test run.
+
+### CCIP.Groups.[testgroup].DenselyConnectedNetworkChainIds
+
+This is applicable only if [MaxNoOfLanes](#ccipgroupstestgroupmaxnooflanes) is specified.
+Specifies the chain ids for networks to be densely connected. If this is provided the test will include all possible pairs of networks mentioned in `DenselyConnectedNetworkChainIds`.
+The rest of the networks will be connected randomly based on the value of `MaxNoOfLanes`.
+
+### CCIP.Groups.[testgroup].ChaosDuration
+
+Specifies the duration for which the chaos experiment is to be run. This is only valid if the test type is 'chaos'.
+
+### CCIP.Groups.[testgroup].USDCMockDeployment
+
+Specifies whether to deploy USDC mock contract for the test. This is only valid if the test is not run on [existing deployments](#ccipgroupstestgroupexistingdeployment).
+
+The following fields are used for various parameters in OCR2 commit and execution jobspecs. All of these are only valid if the test is not run on [existing deployments](#ccipgroupstestgroupexistingdeployment).
+
+### CCIP.Groups.[testgroup].CommitOCRParams
+
+Specifies the OCR parameters for the commit job. This is only valid if the test is not run on [existing deployments](#ccipgroupstestgroupexistingdeployment).
+
+### CCIP.Groups.[testgroup].ExecuteOCRParams
+
+Specifies the OCR parameters for the execute job. This is only valid if the test is not run on [existing deployments](#ccipgroupstestgroupexistingdeployment).
+
+### CCIP.Groups.[testgroup].CommitInflightExpiry
+
+Specifies the value for the `InflightExpiry` in commit job's offchain config. This is only valid if the test is not run on [existing deployments](#ccipgroupstestgroupexistingdeployment).
+
+### CCIP.Groups.[testgroup].OffRampConfig
+
+Specifies the offramp configuration for the execution job. This is only valid if the test is not run on [existing deployments](#ccipgroupstestgroupexistingdeployment).
+This is used to set values for following fields in execution jobspec's offchain and onchain config:
+
+- **OffRampConfig.MaxDataBytes**
+- **OffRampConfig.BatchGasLimit**
+- **OffRampConfig.InflightExpiry**
+- **OffRampConfig.RootSnooze**
+
+Example Usage:
+
+```toml
+[CCIP.Groups.load]
+CommitInflightExpiry = '5m'
+
+[CCIP.Groups.load.CommitOCRParams]
+DeltaProgress = '2m'
+DeltaResend = '5s'
+DeltaRound = '75s'
+DeltaGrace = '5s'
+MaxDurationQuery = '100ms'
+MaxDurationObservation = '35s'
+MaxDurationReport = '10s'
+MaxDurationShouldAcceptFinalizedReport = '5s'
+MaxDurationShouldTransmitAcceptedReport = '10s'
+
+[CCIP.Groups.load.ExecOCRParams]
+DeltaProgress = '2m'
+DeltaResend = '5s'
+DeltaRound = '75s'
+DeltaGrace = '5s'
+MaxDurationQuery = '100ms'
+MaxDurationObservation = '35s'
+MaxDurationReport = '10s'
+MaxDurationShouldAcceptFinalizedReport = '5s'
+MaxDurationShouldTransmitAcceptedReport = '10s'
+
+[CCIP.Groups.load.OffRampConfig]
+BatchGasLimit = 11000000
+MaxDataBytes = 1000
+InflightExpiry = '5m'
+RootSnooze = '5m'
+```
+
+### CCIP.Groups.[testgroup].StoreLaneConfig
+
+This is only valid if the tests are run on remote runners in k8s. If set to true, the test will store the lane config in the remote runner.
+
+### CCIP.Groups.[testgroup].LoadProfile
+
+Specifies the load profile for the test. Only valid if the testgroup is 'load'.
+
+### CCIP.Groups.[testgroup].LoadProfile.LoadFrequency.[DestNetworkName]
+
+#### CCIP.Groups.[testgroup].LoadProfile.RequestPerUnitTime
+
+Specifies the number of requests to be sent per unit time. This is applicable to all networks if [LoadFrequency](#ccipgroupstestgrouploadprofileloadfrequencydestnetworkname) is not specified for a destination network.
+
+#### CCIP.Groups.[testgroup].LoadProfile.TimeUnit
+
+Specifies the unit of time for the load profile. This is applicable to all networks if [LoadFrequency](#ccipgroupstestgrouploadprofileloadfrequencydestnetworkname) is not specified for a destination network.
+
+#### CCIP.Groups.[testgroup].LoadProfile.StepDuration
+
+Specifies the duration for each step in the load profile. This is applicable to all networks if [LoadFrequency](#ccipgroupstestgrouploadprofileloadfrequencydestnetworkname) is not specified for a destination network.
+
+#### CCIP.Groups.[testgroup].LoadProfile.TestDuration
+
+Specifies the total duration for the load test.
+
+#### CCIP.Groups.[testgroup].LoadProfile.NetworkChaosDelay
+
+Specifies the duration network delay used for `NetworkChaos` experiment. This is only valid if the test is run on k8s and not on [existing deployments](#ccipgroupstestgroupexistingdeployment).
+
+#### CCIP.Groups.[testgroup].LoadProfile.WaitBetweenChaosDuringLoad
+
+If there are multiple chaos experiments, this specifies the duration to wait between each chaos experiment. This is only valid if the test is run on k8s and not on [existing deployments](#ccipgroupstestgroupexistingdeployment).
+
+#### CCIP.Groups.[testgroup].LoadProfile.SkipRequestIfAnotherRequestTriggeredWithin
+
+If a request is triggered within this duration, the test will skip sending another request during load run. For Example, if `SkipRequestIfAnotherRequestTriggeredWithin` is set to `40m`, and a request is triggered at 0th second, the test will skip sending another request for another 40m.
+This particular field is used to avoid sending multiple requests in a short duration during load run.
+
+#### CCIP.Groups.[testgroup].LoadProfile.OptimizeSpace
+
+This is used internally to optimize memory usage during load run. If set to true, after the initial lane set up is over the test will discard the lane config to save memory.
+The test will only store contract addresses strictly necessary to trigger/validate ccip-send requests.
+Except for following contracts all other contract addresses will be discarded after the initial lane set up -
+
+- Router
+- ARM
+- CommitStore
+- OffRamp
+- OnRamp
+
+#### CCIP.Groups.[testgroup].LoadProfile.FailOnFirstErrorInLoad
+
+If set to true, the test will fail on the first error encountered during load run. If set to false, the test will continue to run even if there are errors during load run.
+
+#### CCIP.Groups.[testgroup].LoadProfile.SendMaxDataInEveryMsgCount
+
+Specifies the number of requests to send with maximum data in every mentioned count iteration.
+For example, if `SendMaxDataInEveryMsgCount` is set to 5, the test will send ccip message with max allowable data length(as set in onRamp config) in every 5th request.
+
+#### CCIP.Groups.[testgroup].LoadProfile.TestRunName
+
+Specifies the name of the test run. This is used to identify the test run in CCIP test dashboard or logs. If multiple tests are run with same `TestRunName`, the test results will be aggregated under the same test run in grafana dashboard.
+This is used when multiple iterations of tests are run against same release version to aggregate the results under same dashboard view.
+
+#### CCIP.Groups.[testgroup].LoadProfile.MsgProfile
+
+Specifies the message profile for the test. The message profile is used to set up multiple ccip message details during load test.
+
+##### CCIP.Groups.[testgroup].LoadProfile.MsgProfile.Frequencies
+
+Specifies the frequency of each message profile.
+For example, if `Frequencies` is set to [1, 2, 3], the test will send 1st message profile 1 time, 2nd message profile 2 times, and 3rd message profile 3 times in each iteration. Each iteration will be defined by (1+2+3) = 6 requests.
+Example Breakdown:
+
+- Frequencies = [4, 12, 3, 1]
+- Total Sum of Frequencies = 4 + 12 + 3 + 1 = 20
+- Percentages:
+ - Message Type 1: (4 / 20) * 100% = 20%
+ - Message Type 2: (12 / 20) * 100% = 60%
+ - Message Type 3: (3 / 20) * 100% = 15%
+ - Message Type 4: (1 / 20) * 100% = 5%
+ These percentages reflect how often each message type should appear in the total set of messages.
+ Please note - if the total set of messages is not equal to the multiple of sum of frequencies, the percentages will not be accurate.
+
+##### CCIP.Groups.[testgroup].LoadProfile.MsgProfile.MsgDetails
+
+Specifies the message details for each message profile. The fields are the same as [CCIP.Groups.[testgroup].MsgDetails](#ccipgroupstestgroupmsgdetails).
+
+example usage:
+
+```toml
+# to represent 20%, 60%, 15%, 5% of the total messages
+[CCIP.Groups.load.LoadProfile.MsgProfile]
+Frequencies = [4,12,3,1]
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Token'
+DestGasLimit = 0
+DataLength = 0
+NoOfTokens = 5
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'DataWithToken'
+DestGasLimit = 500000
+DataLength = 5000
+NoOfTokens = 5
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 800000
+DataLength = 10000
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 2500000
+DataLength = 10000
+```
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/ccip.go b/integration-tests/ccip-tests/testconfig/ccip.go
new file mode 100644
index 00000000000..7d9419828e9
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/ccip.go
@@ -0,0 +1,428 @@
+package testconfig
+
+import (
+ "fmt"
+ "math/big"
+ "os"
+
+ "github.com/AlekSi/pointer"
+ "github.com/pelletier/go-toml/v2"
+ "github.com/rs/zerolog"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/config"
+ ctfK8config "github.com/smartcontractkit/chainlink-testing-framework/k8s/config"
+
+ ccipcontracts "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts"
+ testutils "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/utils"
+ "github.com/smartcontractkit/chainlink/integration-tests/contracts"
+)
+
+const (
+ CONTRACTS_OVERRIDE_CONFIG string = "BASE64_CCIP_CONFIG_OVERRIDE_CONTRACTS"
+ TokenOnlyTransfer string = "Token"
+ DataOnlyTransfer string = "Data"
+ DataAndTokenTransfer string = "DataWithToken"
+)
+
+type OffRampConfig struct {
+ MaxDataBytes *uint32 `toml:",omitempty"`
+ BatchGasLimit *uint32 `toml:",omitempty"`
+ InflightExpiry *config.Duration `toml:",omitempty"`
+ RootSnooze *config.Duration `toml:",omitempty"`
+}
+
+type MsgDetails struct {
+ MsgType *string `toml:",omitempty"`
+ DestGasLimit *int64 `toml:",omitempty"`
+ DataLength *int64 `toml:",omitempty"`
+ NoOfTokens *int `toml:",omitempty"`
+ AmountPerToken *int64 `toml:",omitempty"`
+}
+
+func (m *MsgDetails) IsTokenTransfer() bool {
+ return pointer.GetString(m.MsgType) == "Token" || pointer.GetString(m.MsgType) == "DataWithToken"
+}
+
+func (m *MsgDetails) IsDataTransfer() bool {
+ return pointer.GetString(m.MsgType) == "Data" || pointer.GetString(m.MsgType) == "DataWithToken"
+}
+
+func (m *MsgDetails) TransferAmounts() []*big.Int {
+ var transferAmounts []*big.Int
+ if m.IsTokenTransfer() {
+ for i := 0; i < pointer.GetInt(m.NoOfTokens); i++ {
+ transferAmounts = append(transferAmounts, big.NewInt(pointer.GetInt64(m.AmountPerToken)))
+ }
+ }
+ return transferAmounts
+}
+
+func (m *MsgDetails) Validate() error {
+ if m == nil {
+ return fmt.Errorf("msg details should be set")
+ }
+ if m.MsgType == nil {
+ return fmt.Errorf("msg type should be set")
+ }
+ if m.IsDataTransfer() {
+ if m.DataLength == nil || *m.DataLength == 0 {
+ return fmt.Errorf("data length should be set and greater than 0")
+ }
+ }
+ if m.DestGasLimit == nil {
+ return fmt.Errorf("destination gas limit should be set")
+ }
+ if pointer.GetString(m.MsgType) != DataOnlyTransfer &&
+ pointer.GetString(m.MsgType) != TokenOnlyTransfer &&
+ pointer.GetString(m.MsgType) != DataAndTokenTransfer {
+ return fmt.Errorf("msg type should be - %s/%s/%s", DataOnlyTransfer, TokenOnlyTransfer, DataAndTokenTransfer)
+ }
+
+ if m.IsTokenTransfer() {
+ if pointer.GetInt64(m.AmountPerToken) == 0 {
+ return fmt.Errorf("token amount should be greater than 0")
+ }
+
+ if pointer.GetInt(m.NoOfTokens) == 0 {
+ return fmt.Errorf("number of tokens in msg should be greater than 0")
+ }
+ }
+
+ return nil
+}
+
+// TokenConfig defines the configuration for tokens in a CCIP test group
+type TokenConfig struct {
+ NoOfTokensPerChain *int `toml:",omitempty"`
+ WithPipeline *bool `toml:",omitempty"`
+ TimeoutForPriceUpdate *config.Duration `toml:",omitempty"`
+ NoOfTokensWithDynamicPrice *int `toml:",omitempty"`
+ DynamicPriceUpdateInterval *config.Duration `toml:",omitempty"`
+ // CCIPOwnerTokens dictates if tokens are deployed and controlled by the default CCIP owner account
+ // By default, all tokens are deployed and owned by a separate address
+ CCIPOwnerTokens *bool `toml:",omitempty"`
+}
+
+func (tc *TokenConfig) IsDynamicPriceUpdate() bool {
+ return tc.NoOfTokensWithDynamicPrice != nil && *tc.NoOfTokensWithDynamicPrice > 0
+}
+
+func (tc *TokenConfig) IsPipelineSpec() bool {
+ return pointer.GetBool(tc.WithPipeline)
+}
+
+func (tc *TokenConfig) Validate() error {
+ if tc == nil {
+ return fmt.Errorf("token config should be set")
+ }
+ if tc.TimeoutForPriceUpdate == nil || tc.TimeoutForPriceUpdate.Duration().Minutes() == 0 {
+ return fmt.Errorf("timeout for price update should be set")
+ }
+ if tc.NoOfTokensWithDynamicPrice != nil && *tc.NoOfTokensWithDynamicPrice > 0 {
+ if tc.DynamicPriceUpdateInterval == nil || tc.DynamicPriceUpdateInterval.Duration().Minutes() == 0 {
+ return fmt.Errorf("dynamic price update interval should be set if NoOfTokensWithDynamicPrice is greater than 0")
+ }
+ }
+ return nil
+}
+
+type MsgProfile struct {
+ MsgDetails *[]*MsgDetails `toml:",omitempty"`
+ Frequencies []int `toml:",omitempty"`
+ matrixByFreq []int
+ mapMsgDetails map[int]*MsgDetails
+}
+
+// msgDetailsIndexMatrixByFrequency creates a matrix of msg details index based on their frequency
+// This matrix is used to select a msg detail based on the iteration number
+// For example, if we have 3 msg details (msg1,msg2,msg3) with frequencies 2, 3, 5 respectively,
+// the matrixByFreq will be [0,0,1,1,1,2,2,2,2,2]
+// and mapMsgDetails will be {0:msg1, 1:msg2, 2:msg3}
+// So, for iteration 0, msg1 will be selected, for iteration 1, msg1 will be selected, for iteration 2, msg2 will be selected and so on
+// This is useful to select a msg detail based on the iteration number
+func (m *MsgProfile) msgDetailsIndexMatrixByFrequency() {
+ m.mapMsgDetails = make(map[int]*MsgDetails)
+ for i, msg := range *m.MsgDetails {
+ m.mapMsgDetails[i] = msg
+ }
+ m.matrixByFreq = make([]int, 0)
+ for i, freq := range m.Frequencies {
+ for j := 0; j < freq; j++ {
+ m.matrixByFreq = append(m.matrixByFreq, i)
+ }
+ }
+ // we do not need frequencies and msg details after creating the matrix
+ m.Frequencies = nil
+ m.MsgDetails = nil
+}
+
+// MsgDetailsForIteration returns the msg details for the given iteration
+// The iteration is used to select the msg details based on their frequency
+// Refer to msgDetailsIndexMatrixByFrequency for more details
+// If the iteration is greater than the number of matrixByFreq, it will loop back to the first msg detail
+// if the final iteration in a load run is lesser than the number of matrixByFreq, there is a chance that some of the msg details might not be selected
+func (m *MsgProfile) MsgDetailsForIteration(it int64) *MsgDetails {
+ index := (it - 1) % int64(len(m.matrixByFreq))
+ return m.mapMsgDetails[m.matrixByFreq[index]]
+}
+
+// MsgDetailWithMaxToken returns the msg details with the max no of tokens in the msg profile
+func (m *MsgProfile) MsgDetailWithMaxToken() *MsgDetails {
+ allDetails := *m.MsgDetails
+ msgDetails := allDetails[0]
+ for _, msg := range allDetails {
+ if msg.NoOfTokens != nil && pointer.GetInt(msg.NoOfTokens) > pointer.GetInt(msgDetails.NoOfTokens) {
+ msgDetails = msg
+ }
+ }
+ return msgDetails
+}
+
+func (m *MsgProfile) Validate() error {
+ if m == nil {
+ return fmt.Errorf("msg profile should be set")
+ }
+ if m.MsgDetails == nil {
+ return fmt.Errorf("msg details should be set")
+ }
+ allDetails := *m.MsgDetails
+ if len(allDetails) == 0 {
+ return fmt.Errorf("msg details should be set")
+ }
+ if len(m.Frequencies) == 0 {
+ return fmt.Errorf("frequencies should be set")
+ }
+ if len(allDetails) != len(m.Frequencies) {
+ return fmt.Errorf("number of msg details %d and frequencies %d should be same", len(allDetails), len(m.Frequencies))
+ }
+ for _, msg := range allDetails {
+ if err := msg.Validate(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+type LoadFrequency struct {
+ RequestPerUnitTime []int64 `toml:",omitempty"`
+ TimeUnit *config.Duration `toml:",omitempty"`
+ StepDuration []*config.Duration `toml:",omitempty"`
+}
+
+type LoadProfile struct {
+ MsgProfile *MsgProfile `toml:",omitempty"`
+ FrequencyByDestination map[string]*LoadFrequency `toml:",omitempty"`
+ RequestPerUnitTime []int64 `toml:",omitempty"`
+ TimeUnit *config.Duration `toml:",omitempty"`
+ StepDuration []*config.Duration `toml:",omitempty"`
+ TestDuration *config.Duration `toml:",omitempty"`
+ NetworkChaosDelay *config.Duration `toml:",omitempty"`
+ WaitBetweenChaosDuringLoad *config.Duration `toml:",omitempty"`
+ SkipRequestIfAnotherRequestTriggeredWithin *config.Duration `toml:",omitempty"`
+ OptimizeSpace *bool `toml:",omitempty"`
+ FailOnFirstErrorInLoad *bool `toml:",omitempty"`
+ SendMaxDataInEveryMsgCount *int64 `toml:",omitempty"`
+ TestRunName string `toml:",omitempty"`
+}
+
+func (l *LoadProfile) Validate() error {
+ if l == nil {
+ return fmt.Errorf("load profile should be set")
+ }
+ if err := l.MsgProfile.Validate(); err != nil {
+ return err
+ }
+ if len(l.RequestPerUnitTime) == 0 {
+ return fmt.Errorf("request per unit time should be set")
+ }
+ if l.TimeUnit == nil || l.TimeUnit.Duration().Minutes() == 0 {
+ return fmt.Errorf("time unit should be set")
+ }
+ if l.TestDuration == nil || l.TestDuration.Duration().Minutes() == 0 {
+ return fmt.Errorf("test duration should be set")
+ }
+ return nil
+}
+
+func (l *LoadProfile) SetTestRunName(name string) {
+ if l.TestRunName == "" && name != "" {
+ l.TestRunName = name
+ }
+}
+
+// CCIPTestGroupConfig defines configuration input to change how a particular CCIP test group should run
+type CCIPTestGroupConfig struct {
+ Type string `toml:",omitempty"`
+ KeepEnvAlive *bool `toml:",omitempty"`
+ BiDirectionalLane *bool `toml:",omitempty"`
+ CommitAndExecuteOnSameDON *bool `toml:",omitempty"`
+ NoOfCommitNodes int `toml:",omitempty"`
+ MsgDetails *MsgDetails `toml:",omitempty"`
+ TokenConfig *TokenConfig `toml:",omitempty"`
+ MulticallInOneTx *bool `toml:",omitempty"`
+ NoOfSendsInMulticall int `toml:",omitempty"`
+ PhaseTimeout *config.Duration `toml:",omitempty"`
+ LocalCluster *bool `toml:",omitempty"`
+ ExistingDeployment *bool `toml:",omitempty"`
+ ReuseContracts *bool `toml:",omitempty"`
+ NodeFunding float64 `toml:",omitempty"`
+ NetworkPairs []string `toml:",omitempty"`
+ DenselyConnectedNetworkChainIds []string `toml:",omitempty"`
+ NoOfNetworks int `toml:",omitempty"`
+ NoOfRoutersPerPair int `toml:",omitempty"`
+ MaxNoOfLanes int `toml:",omitempty"`
+ ChaosDuration *config.Duration `toml:",omitempty"`
+ USDCMockDeployment *bool `toml:",omitempty"`
+ CommitOCRParams *contracts.OffChainAggregatorV2Config `toml:",omitempty"`
+ ExecOCRParams *contracts.OffChainAggregatorV2Config `toml:",omitempty"`
+ OffRampConfig *OffRampConfig `toml:",omitempty"`
+ CommitInflightExpiry *config.Duration `toml:",omitempty"`
+ StoreLaneConfig *bool `toml:",omitempty"`
+ LoadProfile *LoadProfile `toml:",omitempty"`
+}
+
+func (c *CCIPTestGroupConfig) Validate() error {
+ if c.Type == Load {
+ if err := c.LoadProfile.Validate(); err != nil {
+ return err
+ }
+ if c.MsgDetails == nil {
+ c.MsgDetails = c.LoadProfile.MsgProfile.MsgDetailWithMaxToken()
+ }
+ c.LoadProfile.MsgProfile.msgDetailsIndexMatrixByFrequency()
+ if c.ExistingDeployment != nil && *c.ExistingDeployment {
+ if c.LoadProfile.TestRunName == "" && os.Getenv(ctfK8config.EnvVarJobImage) != "" {
+ return fmt.Errorf("test run name should be set if existing deployment is true and test is running in k8s")
+ }
+ }
+ }
+ err := c.MsgDetails.Validate()
+ if err != nil {
+ return err
+ }
+ if c.PhaseTimeout != nil && (c.PhaseTimeout.Duration().Minutes() < 1 || c.PhaseTimeout.Duration().Minutes() > 50) {
+ return fmt.Errorf("phase timeout should be between 1 and 50 minutes")
+ }
+
+ if c.NoOfCommitNodes < 4 {
+ return fmt.Errorf("insuffcient number of commit nodes provided")
+ }
+ if err := c.TokenConfig.Validate(); err != nil {
+ return err
+ }
+
+ if c.MsgDetails.IsTokenTransfer() {
+ if pointer.GetInt(c.TokenConfig.NoOfTokensPerChain) == 0 {
+ return fmt.Errorf("number of tokens per chain should be greater than 0")
+ }
+ }
+ if c.MulticallInOneTx != nil {
+ if c.NoOfSendsInMulticall == 0 {
+ return fmt.Errorf("number of sends in multisend should be greater than 0 if multisend is true")
+ }
+ }
+
+ return nil
+}
+
+type CCIPContractConfig struct {
+ DataFile *string `toml:",omitempty"`
+ Data string `toml:",omitempty"`
+}
+
+func (c *CCIPContractConfig) DataFilePath() string {
+ return pointer.GetString(c.DataFile)
+}
+
+// ContractsData reads the contract config passed in TOML
+// CCIPContractConfig can accept contract config in string mentioned in Data field
+// It also accepts DataFile. Data takes precedence over DataFile
+// If you are providing contract config in DataFile, this will read the content of the file
+// and set it to CONTRACTS_OVERRIDE_CONFIG env var in base 64 encoded format.
+// This comes handy while running tests in remote runner. It ensures that you won't have to deal with copying the
+// DataFile to remote runner pod. Instead, you can pass the base64ed content of the file with the help of
+// an env var.
+func (c *CCIPContractConfig) ContractsData() ([]byte, error) {
+ // check if CONTRACTS_OVERRIDE_CONFIG is provided
+ // load config from env var if specified for contracts
+ rawConfig := os.Getenv(CONTRACTS_OVERRIDE_CONFIG)
+ if rawConfig != "" {
+ err := DecodeConfig(rawConfig, &c)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if c == nil {
+ return nil, nil
+ }
+ if c.Data != "" {
+ return []byte(c.Data), nil
+ }
+ // if DataFilePath is given, update c.Data with the content of file so that we can set CONTRACTS_OVERRIDE_CONFIG
+ // to pass the file content to remote runner with override config var
+ if c.DataFilePath() != "" {
+ // if there is regex provided in filepath, reformat the filepath with actual filepath matching the regex
+ filePath, err := testutils.FirstFileFromMatchingPath(c.DataFilePath())
+ if err != nil {
+ return nil, fmt.Errorf("error finding contract config file %s: %w", c.DataFilePath(), err)
+ }
+ dataContent, err := os.ReadFile(filePath)
+ if err != nil {
+ return dataContent, fmt.Errorf("error reading contract config file %s : %w", filePath, err)
+ }
+ c.Data = string(dataContent)
+ // encode it to base64 and set to CONTRACTS_OVERRIDE_CONFIG so that the same content can be passed to remote runner
+ // we add TEST_ prefix to CONTRACTS_OVERRIDE_CONFIG to ensure the env var is ported to remote runner.
+ _, err = EncodeConfigAndSetEnv(c, fmt.Sprintf("TEST_%s", CONTRACTS_OVERRIDE_CONFIG))
+ return dataContent, err
+ }
+ return nil, nil
+}
+
+type CCIP struct {
+ Env *Common `toml:",omitempty"`
+ ContractVersions map[ccipcontracts.Name]ccipcontracts.Version `toml:",omitempty"`
+ Deployments *CCIPContractConfig `toml:",omitempty"`
+ Groups map[string]*CCIPTestGroupConfig `toml:",omitempty"`
+}
+
+// LoadFromEnv loads selected env vars into the CCIP config
+func (c *CCIP) LoadFromEnv() error {
+ if c.Env == nil {
+ c.Env = &Common{}
+ }
+ err := c.Env.ReadFromEnvVar()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (c *CCIP) Validate() error {
+ if c.Env != nil {
+ err := c.Env.Validate()
+ if err != nil {
+ return err
+ }
+ }
+
+ for name, grp := range c.Groups {
+ grp.Type = name
+ if err := grp.Validate(); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *CCIP) ApplyOverrides(fromCfg *CCIP) error {
+ if fromCfg == nil {
+ return nil
+ }
+ logBytes, err := toml.Marshal(fromCfg)
+ if err != nil {
+ return err
+ }
+ return ctfconfig.BytesToAnyTomlStruct(zerolog.Logger{}, "", "", c, logBytes)
+}
diff --git a/integration-tests/ccip-tests/testconfig/examples/.testsecrets.example b/integration-tests/ccip-tests/testconfig/examples/.testsecrets.example
new file mode 100644
index 00000000000..52afa77015e
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/examples/.testsecrets.example
@@ -0,0 +1,39 @@
+# DO NOT UPDATE THIS FILE WITH ANY SECRET VALUES.
+# This file serves as a template for the actual ~/.testsecrets file. Follow these steps to use it:
+# 1. Create a copy of this template in your home directory under ~/.testsecrets
+# 2. Update ~/.testsecrets with actual secret values required for your tests. The file will be automatically loaded by the test framework
+# 3. Only include secrets necessary for the tests you are running. For example, if you are only running tests on Ethereum Mainnet, you do not need secrets for Base Mainnet. Comment other env vars.
+# DO NOT COMMIT THE ACTUAL SECRETS FILE TO THE REPOSITORY.
+
+# Chainlink image used for NewCLCluster
+E2E_TEST_CHAINLINK_IMAGE="***.dkr.ecr.***.amazonaws.com/chainlink-ccip"
+
+# Chainlink upgrade image for NewCLCluster. Used only for upgrade tests
+E2E_TEST_CHAINLINK_UPGRADE_IMAGE="***.dkr.ecr.***.amazonaws.com/chainlink-ccip"
+
+# Ethereum network secrets
+E2E_TEST_ETHEREUM_MAINNET_WALLET_KEY=""
+E2E_TEST_ETHEREUM_MAINNET_RPC_HTTP_URL=""
+E2E_TEST_ETHEREUM_MAINNET_RPC_HTTP_URL_1=""
+E2E_TEST_ETHEREUM_MAINNET_RPC_WS_URL=""
+E2E_TEST_ETHEREUM_MAINNET_RPC_WS_URL_1=""
+
+# Base network secrets
+E2E_TEST_BASE_MAINNET_WALLET_KEY=""
+E2E_TEST_BASE_MAINNET_RPC_HTTP_URL=""
+E2E_TEST_BASE_MAINNET_RPC_HTTP_URL_1=""
+E2E_TEST_BASE_MAINNET_RPC_WS_URL=""
+E2E_TEST_BASE_MAINNET_RPC_WS_URL_1=""
+
+# Other networks secrets (pattern for envs)
+# E2E_TEST_(.+)_WALLET_KEY_(\d+)=""
+# E2E_TEST_(.+)_RPC_HTTP_URL_(\d+)=""
+# E2E_TEST_(.+)_RPC_WS_URL_(\d+)=""
+
+# Loki secrets
+E2E_TEST_LOKI_TENANT_ID=""
+E2E_TEST_LOKI_ENDPOINT=""
+
+# Grafana secrets
+E2E_TEST_GRAFANA_BASE_URL=""
+E2E_TEST_GRAFANA_DASHBOARD_URL="/d/6vjVx-1V8/ccip-long-running-tests"
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/examples/network_config.toml.example b/integration-tests/ccip-tests/testconfig/examples/network_config.toml.example
new file mode 100644
index 00000000000..ffed99a7718
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/examples/network_config.toml.example
@@ -0,0 +1,168 @@
+[RpcHttpUrls]
+ETHEREUM_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+AVALANCHE_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+BASE_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+ARBITRUM_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+BSC_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+OPTIMISM_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+POLYGON_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+WEMIX_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+KROMA_MAINNET = [
+ 'https:....',
+ 'https:......',
+]
+
+OPTIMISM_SEPOLIA = [
+ 'https:....',
+ 'https:......',
+]
+SEPOLIA = [
+ 'https:....',
+ 'https:......',
+]
+AVALANCHE_FUJI = [
+ 'https:....',
+ 'https:......',
+]
+ARBITRUM_SEPOLIA = [
+ 'https:....',
+ 'https:......',
+]
+POLYGON_MUMBAI = [
+ 'https:....',
+ 'https:......',
+]
+BASE_SEPOLIA = [
+ 'https:....',
+ 'https:......',
+]
+BSC_TESTNET = [
+ 'https:....',
+ 'https:......',
+]
+KROMA_SEPOLIA = [
+ 'https:....',
+ 'https:......',
+]
+WEMIX_TESTNET = [
+ 'https:....',
+ 'https:......',
+]
+
+[RpcWsUrls]
+ETHEREUM_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+AVALANCHE_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+BASE_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+ARBITRUM_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+BSC_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+POLYGON_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+OPTIMISM_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+WEMIX_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+KROMA_MAINNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+OPTIMISM_SEPOLIA = [
+ 'wss://......',
+ 'wss://.........'
+]
+SEPOLIA = [
+ 'wss://......',
+ 'wss://.........'
+]
+AVALANCHE_FUJI = [
+ 'wss://......',
+ 'wss://.........'
+]
+ARBITRUM_SEPOLIA = [
+ 'wss://......',
+ 'wss://.........'
+]
+POLYGON_MUMBAI = [
+ 'wss://......',
+ 'wss://.........'
+]
+BASE_SEPOLIA = [
+ 'wss://......',
+ 'wss://.........'
+]
+BSC_TESTNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+KROMA_SEPOLIA = [
+ 'wss://......',
+ 'wss://.........'
+]
+WEMIX_TESTNET = [
+ 'wss://......',
+ 'wss://.........'
+]
+
+[WalletKeys]
+ETHEREUM_MAINNET = ['']
+AVALANCHE_MAINNET = ['']
+BASE_MAINNET = ['']
+ARBITRUM_MAINNET = ['']
+BSC_MAINNET = ['']
+POLYGON_MAINNET = ['']
+OPTIMISM_MAINNET = ['']
+WEMIX_MAINNET = ['']
+KROMA_MAINNET = ['']
+OPTIMISM_SEPOLIA = ['']
+SEPOLIA = ['']
+AVALANCHE_FUJI = ['']
+ARBITRUM_SEPOLIA = ['']
+POLYGON_MUMBAI = ['']
+BASE_SEPOLIA = ['']
+BSC_TESTNET = ['']
+KROMA_SEPOLIA = ['']
+WEMIX_TESTNET = ['']
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/examples/override.toml.example b/integration-tests/ccip-tests/testconfig/examples/override.toml.example
new file mode 100644
index 00000000000..281a4e8963f
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/examples/override.toml.example
@@ -0,0 +1,119 @@
+
+[CCIP]
+[CCIP.Deployments]
+Data = """
+{
+ "lane_configs": {
+ "geth_1337": {
+ "is_mock_arm": true,
+ "fee_token": "0x42699A7612A82f1d9C36148af9C77354759b210b",
+ "bridge_tokens": [
+ "0x42699A7612A82f1d9C36148af9C77354759b210b"
+ ],
+ "bridge_tokens_pools": [
+ "0xecb550de5c73e6690ab4521c03ec9d476617167e"
+ ],
+ "arm": "0x99c6a236913907dce5714cfa4a179d4f2c0b93d9",
+ "router": "0x96c1f5d31c4c627d6e84a046d4790cac4f17d3ed",
+ "price_registry": "0x625c70baf2dfb2cf06cf6673e6bbad1672427605",
+ "wrapped_native": "0x9B8397f1B0FEcD3a1a40CdD5E8221Fa461898517",
+ "src_contracts": {
+ "geth_2337": {
+ "on_ramp": "0xe62b93777e666224cc8029c21a31311554e2f10e",
+ "deployed_at": 71207
+ }
+ },
+ "dest_contracts": {
+ "geth_2337": {
+ "off_ramp": "0xba1a4f08001416a630e19e34abd260f039874e92",
+ "commit_store": "0x297e29cd7be020c211495f98a3d794a8ae000165",
+ "receiver_dapp": ""
+ }
+ }
+ },
+ "geth_2337": {
+ "is_mock_arm": true,
+ "fee_token": "0x42699A7612A82f1d9C36148af9C77354759b210b",
+ "bridge_tokens": [
+ "0x42699A7612A82f1d9C36148af9C77354759b210b"
+ ],
+ "bridge_tokens_pools": [
+ "0xc7555581de61f6db45ea28547d6d5e0722ed6fbe"
+ ],
+ "arm": "0x2b33e63e99cbb1847a2735e08c61d9034b13a171",
+ "router": "0x27a107a95b36c4510ea926f0f886ff7772248e66",
+ "price_registry": "0x4a6ea541263c363478da333239e38e96e2cc8653",
+ "wrapped_native": "0x9B8397f1B0FEcD3a1a40CdD5E8221Fa461898517",
+ "src_contracts": {
+ "geth_1337": {
+ "on_ramp": "0x96c1f5d31c4c627d6e84a046d4790cac4f17d3ed",
+ "deployed_at": 71209
+ }
+ },
+ "dest_contracts": {
+ "geth_1337": {
+ "off_ramp": "0xe62b93777e666224cc8029c21a31311554e2f10e",
+ "commit_store": "0xa1dc9167b1a8f201d15b48bdd5d77f8360845ced",
+ "receiver_dapp": ""
+ }
+ }
+ }
+ }
+}
+"""
+
+[CCIP.Env]
+EnvUser = 'crib-deployment'
+Mockserver = 'http://mockserver:1080'
+
+[CCIP.Env.Network]
+selected_networks = ['geth_1337', 'geth_2337']
+
+[CCIP.Env.Network.EVMNetworks.geth_1337]
+evm_name = 'geth_1337'
+evm_chain_id = 1337
+evm_urls = ['wss://chain-alpha-rpc.nodeops.sand.cldev.sh/ws/']
+evm_http_urls = ['https://chain-alpha-rpc.nodeops.sand.cldev.sh/']
+evm_keys = ['8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 500000
+evm_transaction_timeout = '2m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 10000
+evm_supports_eip1559 = false
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1
+
+[CCIP.Env.Network.EVMNetworks.geth_2337]
+evm_name = 'geth_2337'
+evm_chain_id = 2337
+evm_urls = ['wss://chain-beta-rpc.nodeops.sand.cldev.sh/ws/']
+evm_http_urls = ['https://chain-beta-rpc.nodeops.sand.cldev.sh/']
+evm_keys = ['8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 500000
+evm_transaction_timeout = '2m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 10000
+evm_supports_eip1559 = false
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1
+
+[CCIP.Env.ExistingCLCluster]
+Name = 'crib-mono-repo-test'
+
+[CCIP.Groups]
+[CCIP.Groups.smoke]
+LocalCluster = false
+ExistingDeployment = true
+
+
+[CCIP.Groups.smoke.MsgDetails]
+MsgType = 'DataWithToken'
+DestGasLimit = 100000
+DataLength = 1000
+NoOfTokens = 1
+AmountPerToken = 1
+
diff --git a/integration-tests/ccip-tests/testconfig/global.go b/integration-tests/ccip-tests/testconfig/global.go
new file mode 100644
index 00000000000..25e87bac2aa
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/global.go
@@ -0,0 +1,688 @@
+package testconfig
+
+import (
+ "bytes"
+ _ "embed"
+ "encoding/base64"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/AlekSi/pointer"
+ "github.com/pelletier/go-toml/v2"
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog/log"
+ "github.com/smartcontractkit/seth"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env"
+ "github.com/smartcontractkit/chainlink-testing-framework/logging"
+ "github.com/smartcontractkit/chainlink-testing-framework/networks"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/config"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/client"
+)
+
+const (
+ OVERIDECONFIG = "BASE64_CCIP_CONFIG_OVERRIDE"
+
+ ErrReadConfig = "failed to read TOML config"
+ ErrUnmarshalConfig = "failed to unmarshal TOML config"
+ Load string = "load"
+ Chaos string = "chaos"
+ Smoke string = "smoke"
+ ProductCCIP = "CCIP"
+)
+
+var (
+ //go:embed tomls/ccip-default.toml
+ DefaultConfig []byte
+)
+
+func GlobalTestConfig() *Config {
+ var err error
+ cfg, err := NewConfig()
+ if err != nil {
+ log.Fatal().Err(err).Msg("Failed to load config")
+ }
+ return cfg
+}
+
+// GenericConfig is an interface for all product based config types to implement
+type GenericConfig interface {
+ Validate() error
+ ApplyOverrides(from interface{}) error
+}
+
+// Config is the top level config struct. It contains config for all product based tests.
+type Config struct {
+ CCIP *CCIP `toml:",omitempty"`
+}
+
+func (c *Config) Validate() error {
+ return c.CCIP.Validate()
+}
+
+func (c *Config) TOMLString() string {
+ buf := new(bytes.Buffer)
+ err := toml.NewEncoder(buf).Encode(c)
+ if err != nil {
+ log.Fatal().Err(err).Msg("Failed to encode config to TOML")
+ }
+ return buf.String()
+}
+
+func DecodeConfig(rawConfig string, c any) error {
+ d, err := base64.StdEncoding.DecodeString(rawConfig)
+ if err != nil {
+ return errors.Wrap(err, ErrReadConfig)
+ }
+ err = toml.Unmarshal(d, c)
+ if err != nil {
+ return errors.Wrap(err, ErrUnmarshalConfig)
+ }
+ return nil
+}
+
+// EncodeConfigAndSetEnv encodes the given struct to base64
+// and sets env var ( if not empty) with the encoded base64 string
+func EncodeConfigAndSetEnv(c any, envVar string) (string, error) {
+ srcBytes, err := toml.Marshal(c)
+ if err != nil {
+ return "", err
+ }
+ encodedStr := base64.StdEncoding.EncodeToString(srcBytes)
+ if envVar == "" {
+ return encodedStr, nil
+ }
+ return encodedStr, os.Setenv(envVar, encodedStr)
+}
+
+func NewConfig() (*Config, error) {
+ cfg := &Config{}
+ var override *Config
+ // var secrets *Config
+ // load config from default file
+ err := config.DecodeTOML(bytes.NewReader(DefaultConfig), cfg)
+ if err != nil {
+ return nil, errors.Wrap(err, ErrReadConfig)
+ }
+
+ // load config overrides from env var if specified
+ // there can be multiple overrides separated by comma
+ rawConfigs, _ := osutil.GetEnv(OVERIDECONFIG)
+ if rawConfigs != "" {
+ for _, rawConfig := range strings.Split(rawConfigs, ",") {
+ err = DecodeConfig(rawConfig, &override)
+ if err != nil {
+ return nil, fmt.Errorf("failed to decode override config: %w", err)
+ }
+ if override != nil {
+ // apply overrides for all products
+ if override.CCIP != nil {
+ if cfg.CCIP == nil {
+ cfg.CCIP = override.CCIP
+ } else {
+ err = cfg.CCIP.ApplyOverrides(override.CCIP)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+ }
+ }
+ // read secrets for all products
+ if cfg.CCIP != nil {
+ err := ctfconfig.LoadSecretEnvsFromFiles()
+ if err != nil {
+ return nil, errors.Wrap(err, "error loading testsecrets files")
+ }
+ err = cfg.CCIP.LoadFromEnv()
+ if err != nil {
+ return nil, errors.Wrap(err, "error loading env vars into CCIP config")
+ }
+ // validate all products
+ err = cfg.CCIP.Validate()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return cfg, nil
+}
+
+// Common is the generic config struct which can be used with product specific configs.
+// It contains generic DON and networks config which can be applied to all product based tests.
+type Common struct {
+ EnvUser string `toml:",omitempty"`
+ EnvToConnect *string `toml:",omitempty"`
+ TTL *config.Duration `toml:",omitempty"`
+ ExistingCLCluster *CLCluster `toml:",omitempty"` // ExistingCLCluster is the existing chainlink cluster to use, if specified it will be used instead of creating a new one
+ Mockserver *string `toml:",omitempty"`
+ NewCLCluster *ChainlinkDeployment `toml:",omitempty"` // NewCLCluster is the new chainlink cluster to create, if specified along with ExistingCLCluster this will be ignored
+ Network *ctfconfig.NetworkConfig `toml:",omitempty"`
+ PrivateEthereumNetworks map[string]*ctfconfig.EthereumNetworkConfig `toml:",omitempty"`
+ Logging *ctfconfig.LoggingConfig `toml:",omitempty"`
+}
+
+// ReadFromEnvVar loads selected env vars into the config
+func (p *Common) ReadFromEnvVar() error {
+ logger := logging.GetTestLogger(nil)
+
+ testLogCollect := ctfconfig.MustReadEnvVar_Boolean(ctfconfig.E2E_TEST_LOG_COLLECT_ENV)
+ if testLogCollect != nil {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.TestLogCollect", ctfconfig.E2E_TEST_LOG_COLLECT_ENV)
+ p.Logging.TestLogCollect = testLogCollect
+ }
+
+ loggingRunID := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_LOGGING_RUN_ID_ENV)
+ if loggingRunID != "" {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.RunID", ctfconfig.E2E_TEST_LOGGING_RUN_ID_ENV)
+ p.Logging.RunId = &loggingRunID
+ }
+
+ logstreamLogTargets := ctfconfig.MustReadEnvVar_Strings(ctfconfig.E2E_TEST_LOG_STREAM_LOG_TARGETS_ENV, ",")
+ if len(logstreamLogTargets) > 0 {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ if p.Logging.LogStream == nil {
+ p.Logging.LogStream = &ctfconfig.LogStreamConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.LogStream.LogTargets", ctfconfig.E2E_TEST_LOG_STREAM_LOG_TARGETS_ENV)
+ p.Logging.LogStream.LogTargets = logstreamLogTargets
+ }
+
+ lokiTenantID := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_LOKI_TENANT_ID_ENV)
+ if lokiTenantID != "" {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ if p.Logging.Loki == nil {
+ p.Logging.Loki = &ctfconfig.LokiConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.Loki.TenantId", ctfconfig.E2E_TEST_LOKI_TENANT_ID_ENV)
+ p.Logging.Loki.TenantId = &lokiTenantID
+ }
+
+ lokiEndpoint := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_LOKI_ENDPOINT_ENV)
+ if lokiEndpoint != "" {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ if p.Logging.Loki == nil {
+ p.Logging.Loki = &ctfconfig.LokiConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.Loki.Endpoint", ctfconfig.E2E_TEST_LOKI_ENDPOINT_ENV)
+ p.Logging.Loki.Endpoint = &lokiEndpoint
+ }
+
+ lokiBasicAuth := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_LOKI_BASIC_AUTH_ENV)
+ if lokiBasicAuth != "" {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ if p.Logging.Loki == nil {
+ p.Logging.Loki = &ctfconfig.LokiConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.Loki.BasicAuth", ctfconfig.E2E_TEST_LOKI_BASIC_AUTH_ENV)
+ p.Logging.Loki.BasicAuth = &lokiBasicAuth
+ }
+
+ lokiBearerToken := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_LOKI_BEARER_TOKEN_ENV)
+ if lokiBearerToken != "" {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ if p.Logging.Loki == nil {
+ p.Logging.Loki = &ctfconfig.LokiConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.Loki.BearerToken", ctfconfig.E2E_TEST_LOKI_BEARER_TOKEN_ENV)
+ p.Logging.Loki.BearerToken = &lokiBearerToken
+ }
+
+ grafanaBaseUrl := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_GRAFANA_BASE_URL_ENV)
+ if grafanaBaseUrl != "" {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ if p.Logging.Grafana == nil {
+ p.Logging.Grafana = &ctfconfig.GrafanaConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.Grafana.BaseUrl", ctfconfig.E2E_TEST_GRAFANA_BASE_URL_ENV)
+ p.Logging.Grafana.BaseUrl = &grafanaBaseUrl
+ }
+
+ grafanaDashboardUrl := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_GRAFANA_DASHBOARD_URL_ENV)
+ if grafanaDashboardUrl != "" {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ if p.Logging.Grafana == nil {
+ p.Logging.Grafana = &ctfconfig.GrafanaConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.Grafana.DashboardUrl", ctfconfig.E2E_TEST_GRAFANA_DASHBOARD_URL_ENV)
+ p.Logging.Grafana.DashboardUrl = &grafanaDashboardUrl
+ }
+
+ grafanaBearerToken := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_GRAFANA_BEARER_TOKEN_ENV)
+ if grafanaBearerToken != "" {
+ if p.Logging == nil {
+ p.Logging = &ctfconfig.LoggingConfig{}
+ }
+ if p.Logging.Grafana == nil {
+ p.Logging.Grafana = &ctfconfig.GrafanaConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Logging.Grafana.BearerToken", ctfconfig.E2E_TEST_GRAFANA_BEARER_TOKEN_ENV)
+ p.Logging.Grafana.BearerToken = &grafanaBearerToken
+ }
+
+ selectedNetworks := ctfconfig.MustReadEnvVar_Strings(ctfconfig.E2E_TEST_SELECTED_NETWORK_ENV, ",")
+ if len(selectedNetworks) > 0 {
+ if p.Network == nil {
+ p.Network = &ctfconfig.NetworkConfig{}
+ }
+ logger.Debug().Msgf("Using %s env var to override Network.SelectedNetworks", ctfconfig.E2E_TEST_SELECTED_NETWORK_ENV)
+ p.Network.SelectedNetworks = selectedNetworks
+ }
+
+ walletKeys := ctfconfig.ReadEnvVarGroupedMap(ctfconfig.E2E_TEST_WALLET_KEY_ENV, ctfconfig.E2E_TEST_WALLET_KEYS_ENV)
+ if len(walletKeys) > 0 {
+ if p.Network == nil {
+ p.Network = &ctfconfig.NetworkConfig{}
+ }
+ logger.Debug().Msgf("Using %s and/or %s env vars to override Network.WalletKeys", ctfconfig.E2E_TEST_WALLET_KEY_ENV, ctfconfig.E2E_TEST_WALLET_KEYS_ENV)
+ p.Network.WalletKeys = walletKeys
+ }
+
+ rpcHttpUrls := ctfconfig.ReadEnvVarGroupedMap(ctfconfig.E2E_TEST_RPC_HTTP_URL_ENV, ctfconfig.E2E_TEST_RPC_HTTP_URLS_ENV)
+ if len(rpcHttpUrls) > 0 {
+ if p.Network == nil {
+ p.Network = &ctfconfig.NetworkConfig{}
+ }
+ logger.Debug().Msgf("Using %s and/or %s env vars to override Network.RpcHttpUrls", ctfconfig.E2E_TEST_RPC_HTTP_URL_ENV, ctfconfig.E2E_TEST_RPC_HTTP_URLS_ENV)
+ p.Network.RpcHttpUrls = rpcHttpUrls
+ }
+
+ rpcWsUrls := ctfconfig.ReadEnvVarGroupedMap(ctfconfig.E2E_TEST_RPC_WS_URL_ENV, ctfconfig.E2E_TEST_RPC_WS_URLS_ENV)
+ if len(rpcWsUrls) > 0 {
+ if p.Network == nil {
+ p.Network = &ctfconfig.NetworkConfig{}
+ }
+ logger.Debug().Msgf("Using %s and/or %s env vars to override Network.RpcWsUrls", ctfconfig.E2E_TEST_RPC_WS_URL_ENV, ctfconfig.E2E_TEST_RPC_WS_URLS_ENV)
+ p.Network.RpcWsUrls = rpcWsUrls
+ }
+
+ chainlinkImage := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_CHAINLINK_IMAGE_ENV)
+ if chainlinkImage != "" {
+ if p.NewCLCluster == nil {
+ p.NewCLCluster = &ChainlinkDeployment{}
+ }
+ if p.NewCLCluster.Common == nil {
+ p.NewCLCluster.Common = &Node{}
+ }
+ if p.NewCLCluster.Common.ChainlinkImage == nil {
+ p.NewCLCluster.Common.ChainlinkImage = &ctfconfig.ChainlinkImageConfig{}
+ }
+
+ logger.Debug().Msgf("Using %s env var to override NewCLCluster.Common.ChainlinkImage.Image", ctfconfig.E2E_TEST_CHAINLINK_IMAGE_ENV)
+ p.NewCLCluster.Common.ChainlinkImage.Image = &chainlinkImage
+ }
+
+ chainlinkVersion := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_CHAINLINK_VERSION_ENV)
+ if chainlinkVersion != "" {
+ if p.NewCLCluster == nil {
+ p.NewCLCluster = &ChainlinkDeployment{}
+ }
+ if p.NewCLCluster.Common == nil {
+ p.NewCLCluster.Common = &Node{}
+ }
+ if p.NewCLCluster.Common.ChainlinkImage == nil {
+ p.NewCLCluster.Common.ChainlinkImage = &ctfconfig.ChainlinkImageConfig{}
+ }
+
+ logger.Debug().Msgf("Using %s env var to override NewCLCluster.Common.ChainlinkImage.Version", ctfconfig.E2E_TEST_CHAINLINK_VERSION_ENV)
+ p.NewCLCluster.Common.ChainlinkImage.Version = &chainlinkVersion
+ }
+
+ chainlinkPostgresVersion := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_CHAINLINK_POSTGRES_VERSION_ENV)
+ if chainlinkPostgresVersion != "" {
+ if p.NewCLCluster == nil {
+ p.NewCLCluster = &ChainlinkDeployment{}
+ }
+ if p.NewCLCluster.Common == nil {
+ p.NewCLCluster.Common = &Node{}
+ }
+ if p.NewCLCluster.Common.ChainlinkImage == nil {
+ p.NewCLCluster.Common.ChainlinkImage = &ctfconfig.ChainlinkImageConfig{}
+ }
+
+ logger.Debug().Msgf("Using %s env var to override NewCLCluster.Common.ChainlinkImage.PostgresVersion", ctfconfig.E2E_TEST_CHAINLINK_POSTGRES_VERSION_ENV)
+ p.NewCLCluster.Common.ChainlinkImage.PostgresVersion = &chainlinkPostgresVersion
+ }
+
+ chainlinkUpgradeImage := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_CHAINLINK_UPGRADE_IMAGE_ENV)
+ if chainlinkUpgradeImage != "" {
+ if p.NewCLCluster == nil {
+ p.NewCLCluster = &ChainlinkDeployment{}
+ }
+ if p.NewCLCluster.Common == nil {
+ p.NewCLCluster.Common = &Node{}
+ }
+ if p.NewCLCluster.Common.ChainlinkUpgradeImage == nil {
+ p.NewCLCluster.Common.ChainlinkUpgradeImage = &ctfconfig.ChainlinkImageConfig{}
+ }
+
+ logger.Debug().Msgf("Using %s env var to override NewCLCluster.Common.ChainlinkUpgradeImage.Image", ctfconfig.E2E_TEST_CHAINLINK_UPGRADE_IMAGE_ENV)
+ p.NewCLCluster.Common.ChainlinkUpgradeImage.Image = &chainlinkUpgradeImage
+ }
+
+ chainlinkUpgradeVersion := ctfconfig.MustReadEnvVar_String(ctfconfig.E2E_TEST_CHAINLINK_UPGRADE_VERSION_ENV)
+ if chainlinkUpgradeVersion != "" {
+ if p.NewCLCluster == nil {
+ p.NewCLCluster = &ChainlinkDeployment{}
+ }
+ if p.NewCLCluster.Common == nil {
+ p.NewCLCluster.Common = &Node{}
+ }
+ if p.NewCLCluster.Common.ChainlinkImage == nil {
+ p.NewCLCluster.Common.ChainlinkImage = &ctfconfig.ChainlinkImageConfig{}
+ }
+
+ logger.Debug().Msgf("Using %s env var to override NewCLCluster.Common.ChainlinkUpgradeImage.Version", ctfconfig.E2E_TEST_CHAINLINK_UPGRADE_VERSION_ENV)
+ p.NewCLCluster.Common.ChainlinkUpgradeImage.Version = &chainlinkUpgradeVersion
+ }
+
+ return nil
+}
+
+func (p *Common) GetNodeConfig() *ctfconfig.NodeConfig {
+ return &ctfconfig.NodeConfig{
+ BaseConfigTOML: p.NewCLCluster.Common.BaseConfigTOML,
+ CommonChainConfigTOML: p.NewCLCluster.Common.CommonChainConfigTOML,
+ ChainConfigTOMLByChainID: p.NewCLCluster.Common.ChainConfigTOMLByChain,
+ }
+}
+
+func (p *Common) GetSethConfig() *seth.Config {
+ return nil
+}
+
+func (p *Common) Validate() error {
+ if err := p.Logging.Validate(); err != nil {
+ return fmt.Errorf("error validating logging config %w", err)
+ }
+ if p.Network == nil {
+ return errors.New("no networks specified")
+ }
+ // read the default network config, if specified
+ p.Network.UpperCaseNetworkNames()
+ p.Network.OverrideURLsAndKeysFromEVMNetwork()
+ err := p.Network.Default()
+ if err != nil {
+ return fmt.Errorf("error reading default network config %w", err)
+ }
+ if err := p.Network.Validate(); err != nil {
+ return fmt.Errorf("error validating networks config %w", err)
+ }
+ if p.NewCLCluster == nil && p.ExistingCLCluster == nil {
+ return errors.New("no chainlink or existing cluster specified")
+ }
+
+ for k, v := range p.PrivateEthereumNetworks {
+ // this is the only value we need to generate dynamically before starting a new simulated chain
+ if v.EthereumChainConfig != nil {
+ p.PrivateEthereumNetworks[k].EthereumChainConfig.GenerateGenesisTimestamp()
+ }
+
+ builder := test_env.NewEthereumNetworkBuilder()
+ ethNetwork, err := builder.WithExistingConfig(*v).Build()
+ if err != nil {
+ return fmt.Errorf("error building private ethereum network ethNetworks %w", err)
+ }
+
+ p.PrivateEthereumNetworks[k] = ðNetwork.EthereumNetworkConfig
+ }
+
+ if p.ExistingCLCluster != nil {
+ if err := p.ExistingCLCluster.Validate(); err != nil {
+ return fmt.Errorf("error validating existing chainlink cluster config %w", err)
+ }
+ if p.Mockserver == nil {
+ return errors.New("no mockserver specified for existing chainlink cluster")
+ }
+ log.Warn().Msg("Using existing chainlink cluster, overriding new chainlink cluster config if specified")
+ p.NewCLCluster = nil
+ } else {
+ if p.NewCLCluster != nil {
+ if err := p.NewCLCluster.Validate(); err != nil {
+ return fmt.Errorf("error validating chainlink config %w", err)
+ }
+ }
+ }
+ return nil
+}
+
+func (p *Common) EVMNetworks() ([]blockchain.EVMNetwork, []string, error) {
+ evmNetworks := networks.MustGetSelectedNetworkConfig(p.Network)
+ if len(p.Network.SelectedNetworks) != len(evmNetworks) {
+ return nil, p.Network.SelectedNetworks, fmt.Errorf("selected networks %v do not match evm networks %v", p.Network.SelectedNetworks, evmNetworks)
+ }
+ return evmNetworks, p.Network.SelectedNetworks, nil
+}
+
+func (p *Common) GetLoggingConfig() *ctfconfig.LoggingConfig {
+ return p.Logging
+}
+
+func (p *Common) GetChainlinkImageConfig() *ctfconfig.ChainlinkImageConfig {
+ return p.NewCLCluster.Common.ChainlinkImage
+}
+
+func (p *Common) GetPyroscopeConfig() *ctfconfig.PyroscopeConfig {
+ return nil
+}
+
+func (p *Common) GetPrivateEthereumNetworkConfig() *ctfconfig.EthereumNetworkConfig {
+ return nil
+}
+
+func (p *Common) GetNetworkConfig() *ctfconfig.NetworkConfig {
+ return p.Network
+}
+
+// Returns Grafana URL from Logging config
+func (p *Common) GetGrafanaBaseURL() (string, error) {
+ if p.Logging.Grafana == nil || p.Logging.Grafana.BaseUrl == nil {
+ return "", errors.New("grafana base url not set")
+ }
+
+ return strings.TrimSuffix(*p.Logging.Grafana.BaseUrl, "/"), nil
+}
+
+// Returns Grafana Dashboard URL from Logging config
+func (p *Common) GetGrafanaDashboardURL() (string, error) {
+ if p.Logging.Grafana == nil || p.Logging.Grafana.DashboardUrl == nil {
+ return "", errors.New("grafana dashboard url not set")
+ }
+
+ url := *p.Logging.Grafana.DashboardUrl
+ if !strings.HasPrefix(url, "/") {
+ url = "/" + url
+ }
+
+ return url, nil
+}
+
+type CLCluster struct {
+ Name *string `toml:",omitempty"`
+ NoOfNodes *int `toml:",omitempty"`
+ NodeConfigs []*client.ChainlinkConfig `toml:",omitempty"`
+}
+
+func (c *CLCluster) Validate() error {
+ if c.NoOfNodes == nil || len(c.NodeConfigs) == 0 {
+ return fmt.Errorf("no chainlink nodes specified")
+ }
+ if *c.NoOfNodes != len(c.NodeConfigs) {
+ return fmt.Errorf("number of nodes %d does not match number of node configs %d", *c.NoOfNodes, len(c.NodeConfigs))
+ }
+ for i, nodeConfig := range c.NodeConfigs {
+ if nodeConfig.URL == "" {
+ return fmt.Errorf("node %d url not specified", i+1)
+ }
+ if nodeConfig.Password == "" {
+ return fmt.Errorf("node %d password not specified", i+1)
+ }
+ if nodeConfig.Email == "" {
+ return fmt.Errorf("node %d email not specified", i+1)
+ }
+ if nodeConfig.InternalIP == "" {
+ return fmt.Errorf("node %d internal ip not specified", i+1)
+ }
+ }
+
+ return nil
+}
+
+type ChainlinkDeployment struct {
+ Common *Node `toml:",omitempty"`
+ NodeMemory string `toml:",omitempty"`
+ NodeCPU string `toml:",omitempty"`
+ DBMemory string `toml:",omitempty"`
+ DBCPU string `toml:",omitempty"`
+ DBCapacity string `toml:",omitempty"`
+ DBStorageClass *string `toml:",omitempty"`
+ PromPgExporter *bool `toml:",omitempty"`
+ IsStateful *bool `toml:",omitempty"`
+ DBArgs []string `toml:",omitempty"`
+ NoOfNodes *int `toml:",omitempty"`
+ Nodes []*Node `toml:",omitempty"` // to be mentioned only if diff nodes follow diff configs; not required if all nodes follow CommonConfig
+}
+
+func (c *ChainlinkDeployment) Validate() error {
+ if c.Common == nil {
+ return errors.New("common config can't be empty")
+ }
+ if c.Common.ChainlinkImage == nil {
+ return errors.New("chainlink image can't be empty")
+ }
+ if err := c.Common.ChainlinkImage.Validate(); err != nil {
+ return err
+ }
+ if c.Common.DBImage == "" || c.Common.DBTag == "" {
+ return errors.New("must provide db image and tag")
+ }
+ if c.NoOfNodes == nil {
+ return errors.New("chainlink config is invalid, NoOfNodes should be specified")
+ }
+ if c.Nodes != nil && len(c.Nodes) > 0 {
+ noOfNodes := pointer.GetInt(c.NoOfNodes)
+ if noOfNodes != len(c.Nodes) {
+ return errors.New("chainlink config is invalid, NoOfNodes and Nodes length mismatch")
+ }
+ for i := range c.Nodes {
+ // merge common config with node specific config
+ c.Nodes[i].Merge(c.Common)
+ node := c.Nodes[i]
+ if node.ChainlinkImage == nil {
+ return fmt.Errorf("node %s: chainlink image can't be empty", node.Name)
+ }
+ if err := node.ChainlinkImage.Validate(); err != nil {
+ return fmt.Errorf("node %s: %w", node.Name, err)
+ }
+ if node.DBImage == "" || node.DBTag == "" {
+ return fmt.Errorf("node %s: must provide db image and tag", node.Name)
+ }
+ }
+ }
+ return nil
+}
+
+type Node struct {
+ Name string `toml:",omitempty"`
+ NeedsUpgrade *bool `toml:",omitempty"`
+ ChainlinkImage *ctfconfig.ChainlinkImageConfig `toml:"ChainlinkImage"`
+ ChainlinkUpgradeImage *ctfconfig.ChainlinkImageConfig `toml:"ChainlinkUpgradeImage"`
+ BaseConfigTOML string `toml:",omitempty"`
+ CommonChainConfigTOML string `toml:",omitempty"`
+ ChainConfigTOMLByChain map[string]string `toml:",omitempty"` // key is chainID
+ DBImage string `toml:",omitempty"`
+ DBTag string `toml:",omitempty"`
+}
+
+// Merge merges non-empty values
+func (n *Node) Merge(from *Node) {
+ if from == nil || n == nil {
+ return
+ }
+ if n.Name == "" {
+ n.Name = from.Name
+ }
+ if n.ChainlinkImage == nil {
+ if from.ChainlinkImage != nil {
+ n.ChainlinkImage = &ctfconfig.ChainlinkImageConfig{
+ Image: from.ChainlinkImage.Image,
+ Version: from.ChainlinkImage.Version,
+ }
+ }
+ } else {
+ if n.ChainlinkImage.Image == nil && from.ChainlinkImage != nil {
+ n.ChainlinkImage.Image = from.ChainlinkImage.Image
+ }
+ if n.ChainlinkImage.Version == nil && from.ChainlinkImage != nil {
+ n.ChainlinkImage.Version = from.ChainlinkImage.Version
+ }
+ }
+ // merge upgrade image only if the nodes is marked as NeedsUpgrade to true
+ if pointer.GetBool(n.NeedsUpgrade) {
+ if n.ChainlinkUpgradeImage == nil {
+ if from.ChainlinkUpgradeImage != nil {
+ n.ChainlinkUpgradeImage = &ctfconfig.ChainlinkImageConfig{
+ Image: from.ChainlinkUpgradeImage.Image,
+ Version: from.ChainlinkUpgradeImage.Version,
+ }
+ }
+ } else {
+ if n.ChainlinkUpgradeImage.Image == nil && from.ChainlinkUpgradeImage != nil {
+ n.ChainlinkUpgradeImage.Image = from.ChainlinkUpgradeImage.Image
+ }
+ if n.ChainlinkUpgradeImage.Version == nil && from.ChainlinkUpgradeImage != nil {
+ n.ChainlinkUpgradeImage.Version = from.ChainlinkUpgradeImage.Version
+ }
+ }
+ }
+
+ if n.DBImage == "" {
+ n.DBImage = from.DBImage
+ }
+ if n.DBTag == "" {
+ n.DBTag = from.DBTag
+ }
+ if n.BaseConfigTOML == "" {
+ n.BaseConfigTOML = from.BaseConfigTOML
+ }
+ if n.CommonChainConfigTOML == "" {
+ n.CommonChainConfigTOML = from.CommonChainConfigTOML
+ }
+ if n.ChainConfigTOMLByChain == nil {
+ n.ChainConfigTOMLByChain = from.ChainConfigTOMLByChain
+ } else {
+ for k, v := range from.ChainConfigTOMLByChain {
+ if _, ok := n.ChainConfigTOMLByChain[k]; !ok {
+ n.ChainConfigTOMLByChain[k] = v
+ }
+ }
+ }
+}
diff --git a/integration-tests/ccip-tests/testconfig/override/mainnet-secondary.toml b/integration-tests/ccip-tests/testconfig/override/mainnet-secondary.toml
new file mode 100644
index 00000000000..7d457774b02
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/override/mainnet-secondary.toml
@@ -0,0 +1,712 @@
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+[CCIP.Deployments]
+Data = """
+{
+ "lane_configs": {
+ "Arbitrum Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4",
+ "bridge_tokens": ["0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"],
+ "bridge_tokens_pools": ["0x34700F5faE61Ba628c4269BdCbA12DA53bbfa726"],
+ "arm": "0xe06b0e8c4bd455153e8794ad7Ea8Ff5A14B64E4b",
+ "router": "0x141fa059441E0ca23ce184B6A78bafD2A517DdE8",
+ "price_registry": "0x13015e4E6f839E1Aa1016DF521ea458ecA20438c",
+ "wrapped_native": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
+ "version" : "1.4.0",
+ "src_contracts": {
+ "Avalanche Mainnet": {
+ "on_ramp": "0x05B723f3db92430FbE4395fD03E40Cc7e9D17988",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x77b60F85b25fD501E3ddED6C1fe7bF565C08A22A",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x79f3ABeCe5A3AFFf32D47F4CFe45e7b65c9a2D91",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xCe11020D56e5FDbfE46D9FC3021641FfbBB5AdEE",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0xC09b72E8128620C40D89649019d995Cc79f030C3",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x122F05F49e90508F089eE8D0d868d1a4f3E5a809",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x66a0046ac9FA104eB38B04cfF391CcD0122E6FbC",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Mainnet": {
+ "off_ramp": "0xe0109912157d5B75ea8b3181123Cf32c73bc9920",
+ "commit_store": "0xDaa61b8Cd85977820f92d1e749E1D9F55Da6CCEA",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xdB19F77F87661f9be0F557cf9a1ebeCf7D8F206c",
+ "commit_store": "0x6e37f4c82d9A31cc42B445874dd3c3De97AB553f",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0xB1b705c2315fced1B38baE463BE7DDef531e47fA",
+ "commit_store": "0x310cECbFf14Ad0307EfF762F461a487C1abb90bf",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x542ba1902044069330e8c5b36A84EC503863722f",
+ "commit_store": "0x060331fEdA35691e54876D957B4F9e3b8Cb47d20",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xeeed4D86F3E0e6d32A6Ad29d8De6A0Dc91963A5f",
+ "commit_store": "0xbbB563c4d98020b9c0f3Cc34c2C0Ef9676806E35",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x9bDA7c8DCda4E39aFeB483cc0B7E3C1f6E0D5AB1",
+ "commit_store": "0x63a0AeaadAe851b990bBD9dc41f5C1B08b32026d",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xEEf5Fb4c4953F9cA9ab1f25cE590776AfFc2c455",
+ "commit_store": "0xD268286A277095a9C3C90205110831a84505881c",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Avalanche Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x5947BB275c521040051D82396192181b413227A3",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xdFD6C0dc67666DE3bB36b31eec5c7B1542A82C1E",
+ "router": "0xF4c7E640EdA248ef95972845a62bdC74237805dB",
+ "price_registry": "0xfA4edD04eaAcDB07c8D73621bc1790eC50D8c489",
+ "wrapped_native": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x98f51B041e493fc4d72B8BD33218480bA0c66DDF",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x268fb4311D2c6CB2bbA01CCA9AC073Fb3bfd1C7c",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x8eaae6462816CB4957184c48B86afA7642D8Bf2B",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xD0701FcC7818c31935331B02Eb21e91eC71a1704",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x8629008887E073260c5434D6CaCFc83C3001d211",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x97500490d9126f34cf9aA0126d64623E170319Ef",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x9b1ed9De069Be4d50957464b359f98eD0Bf34dd5",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x770b1375F86E7a9bf30DBe3F97bea67193dC9135",
+ "commit_store": "0x23E2b34Ce8e12c53f8a39AD4b3FFCa845f8E617C",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0x4d6A796Bc85dcDF41ce9AaEB50B094C6b589748f",
+ "commit_store": "0xc4C4358FA01a04D6c6FE3b96a351946d4c2715C2",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x83F53Fc798FEbfFbdF84830AD403b9989187a06C",
+ "commit_store": "0xD8ceCE2D7794385E00Ce3EF94550E732b0A0B959",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x5B833BD6456c604Eb396C0fBa477aD49e82B1A2a",
+ "commit_store": "0x23E23958D220B774680f91c2c91a6f2B2f610d7e",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xb68A3EE8bD0A09eE221cf1859Dd5a4d5765188Fe",
+ "commit_store": "0x83DCeeCf822981F9F8552925eEfd88CAc1905dEA",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x19250aBE66B88F214d02B6f3BF80F4118290C619",
+ "commit_store": "0x87A0935cE6254dB1252bBac90d1D07D04846aDCA",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x317dE8bc5c3292E494b6496586696d4966A922B0",
+ "commit_store": "0x97Fbf3d6DEac16adC721aE9187CeEa1e610aC7Af",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Base Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x88Fb150BDc53A65fe94Dea0c9BA0a6dAf8C6e196",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x38660c8CC222c0192b635c2ac09687B4F25cCE5F",
+ "router": "0x881e3A65B4d4a04dD529061dd0071cf975F58bCD",
+ "price_registry": "0x6337a58D4BD7Ba691B66341779e8f87d4679923a",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x1E5Ca70d1e7A1B26061125738a880BBeA42FeB21",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xBE5a9E336D9614024B4Fa10D8112671fc9A42d96",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xdd4Fb402d41Beb0eEeF6CfB1bf445f50bDC8c981",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xDEA286dc0E01Cb4755650A6CF8d1076b454eA1cb",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0xd952FEAcDd5919Cc5E9454b53bF45d4E73dD6457",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x3DB8Bea142e41cA3633890d0e5640F99a895D6A5",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x8531E63aE9279a1f0D09eba566CD1b092b95f3D5",
+ "commit_store": "0x327E13f54c7871a2416006B33B4822eAAD357916",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x8345F2fF67e5A65e85dc955DE1414832608E00aD",
+ "commit_store": "0xd0b13be4c53A6262b47C5DDd36F0257aa714F562",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x48a51f5D38BE630Ddd6417Ea2D9052B8efc91a18",
+ "commit_store": "0xF97127e77252284EC9D4bc13C247c9D1A99F72B0",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xEC0cFe335a4d53dBA70CB650Ab56eEc32788F0BB",
+ "commit_store": "0x0ae3c2c7FB789bd05A450CD3075D11f6c2Ca4F77",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xf50c0d2a8B6Db60f1D93E60f03d0413D56153E4F",
+ "commit_store": "0x16f72C15165f7C9d74c12fDF188E399d4d3724e4",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x75F29f058b31106F99caFdc17c9b26ADfcC7b5D7",
+ "commit_store": "0xb719616E732581B570232DfB13Ca49D27667Af9f",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "BSC Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x404460C6A5EdE2D891e8297795264fDe62ADBB75",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x3DB43b96B2625F4232e9Df900d464dd2c64C0021",
+ "router": "0x34B03Cb9086d7D758AC55af71584F81A598759FE",
+ "price_registry": "0xd64aAbD70A71d9f0A00B99F6EFc1626aA2dD43C7",
+ "wrapped_native": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
+ "src_contracts": {
+ "Avalanche Mainnet": {
+ "on_ramp": "0x6aa72a998859eF93356c6521B72155D355D0Cfd2",
+ "deployed_at": 11111111
+ },
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x2788b46BAcFF49BD89562e6bA5c5FBbbE5Fa92F7",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x70bC7f7a6D936b289bBF5c0E19ECE35B437E2e36",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x0Bf40b034872D0b364f3DCec04C7434a4Da1C8d9",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x4FEB11A454C9E8038A8d0aDF599Fe7612ce114bA",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x6bD4754D86fc87FE5b463D368f26a3587a08347c",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x1467fF8f249f5bc604119Af26a47035886f856BE",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Mainnet": {
+ "off_ramp": "0x37a6fa55fe61061Ae97bF7314Ae270eCF71c5ED3",
+ "commit_store": "0x1f558F6dcf0224Ef1F78A24814FED548B9602c80",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x3DA330fd8Ef10d93cFB7D4f8ecE7BC1F10811feC",
+ "commit_store": "0x86D55Ff492cfBBAf0c0D42D4EE615144E78b3D02",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0x574c697deab06B805D8780898B3F136a1F4892Dc",
+ "commit_store": "0x002B164b1dcf4E92F352DC625A01Be0E890EdEea",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x181Bb1E97b0bDD1D85E741ad0943552D3682cc35",
+ "commit_store": "0x3fF27A34fF0FA77921C3438e67f58da1a83e9Ce1",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xE7E080C8d62d595a223C577C7C8d1f75d9A5E664",
+ "commit_store": "0xF4d53346bDb6d393C74B0B72Aa7D6689a3eAad79",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x26af2046Da85d7f6712D5edCa81B9E3b2e7A60Ab",
+ "commit_store": "0x4C1dA405a789AC2853A69D8290B8B9b47a0374F8",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xC027C5AEb230008c243Be463A73571e581F94c13",
+ "commit_store": "0x2EB426C8C54D740d1FC856eB3Ff96feA03957978",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Ethereum Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x514910771AF9Ca656af840dff83E8264EcF986CA",
+ "bridge_tokens": ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"],
+ "bridge_tokens_pools": ["0x69c24c970B65e22Ac26864aF10b2295B7d78f93A"],
+ "arm": "0x8B63b3DE93431C0f756A493644d128134291fA1b",
+ "router": "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D",
+ "price_registry": "0x8c9b2Efb7c64C394119270bfecE7f54763b958Ad",
+ "wrapped_native": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x925228D7B82d883Dde340A55Fe8e6dA56244A22C",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0x3df8dAe2d123081c4D5E946E655F7c109B9Dd630",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0xe2c2AB221AA0b957805f229d2AA57fBE2f4dADf7",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x91D25A56Db77aD5147437d8B83Eb563D46eBFa69",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x86B47d8411006874eEf8E4584BdFD7be8e5549d1",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x35F0ca9Be776E4B38659944c257bDd0ba75F1B8B",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0xCbE7e5DA76dC99Ac317adF6d99137005FDA4E2C4",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0xeFC4a18af59398FF23bfe7325F2401aD44286F4d",
+ "commit_store": "0x9B2EEd6A1e16cB50Ed4c876D2dD69468B21b7749",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x569940e02D4425eac61A7601632eC00d69f75c17",
+ "commit_store": "0x2aa101BF99CaeF7fc1355D4c493a1fe187A007cE",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xdf85c8381954694E74abD07488f452b4c2Cddfb3",
+ "commit_store": "0x8DC27D621c41a32140e22E2a4dAf1259639BAe04",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x7Afe7088aff57173565F4b034167643AA8b9171c",
+ "commit_store": "0x87c55D48DF6EF7B08153Ab079e76bFEcbb793D75",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xB095900fB91db00E6abD247A5A5AD1cee3F20BF7",
+ "commit_store": "0x4af4B497c998007eF83ad130318eB2b925a79dc8",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x0af338F0E314c7551bcE0EF516d46d855b0Ee395",
+ "commit_store": "0xD37a60E8C36E802D2E1a6321832Ee85556Beeb76",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x3a129e6C18b23d18BA9E6Aa14Dc2e79d1f91c6c5",
+ "commit_store": "0x31f6ab382DDeb9A316Ab61C3945a5292a50a89AB",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Kroma Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xC1F6f7622ad37C3f46cDF6F8AA0344ADE80BF450",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xB59779d3364BC6d71168245f9ebb96469E5a5a98",
+ "router": "0xE93E8B0d1b1CEB44350C8758ed1E2799CCee31aB",
+ "price_registry": "0x8155B4710e7bbC90924E957104F94Afd4f95Eca2",
+ "wrapped_native": "0x4200000000000000000000000000000000000001",
+ "src_contracts": {
+ "WeMix Mainnet": {
+ "on_ramp": "0x3C5Ab46fA1dB1dECD854224654313a69bf9fcAD3",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "WeMix Mainnet": {
+ "off_ramp": "0x2B555774B3D1dcbcd76efb7751F3c5FbCFABC5C4",
+ "commit_store": "0x213124614aAf31eBCE7c612A12aac5f8aAD77DE4",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Optimism Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6",
+ "bridge_tokens": ["0x4200000000000000000000000000000000000006"],
+ "bridge_tokens_pools": ["0x86E715415D8C8435903d1e8204fA1e9784Aa7305"],
+ "arm": "0x8C7C2C3362a42308BB5c368677Ad321D11693b81",
+ "router": "0x3206695CaE29952f4b0c22a169725a865bc8Ce0f",
+ "price_registry": "0xb52545aECE8C73A97E52a146757EC15b90Ed8488",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x0C9BE7Cfd12c735E5aaE047C1dCB845d54E518C3",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xD0D3E757bFBce7ae1881DDD7F6d798DDcE588445",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x0b1760A8112183303c5526C6b24569fd3A274f3B",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xa3c9544B82846C45BE37593d5d9ACffbE61BF3A6",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x55183Db1d2aE0b63e4c92A64bEF2CBfc2032B127",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x6B57145e322c877E7D91Ed8E31266eB5c02F7EfC",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x82e9f4C5ec4a84E310d60D462a12042E5cbA0954",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x0C9BE7Cfd12c735E5aaE047C1dCB845d54E518C3",
+ "commit_store": "0x55028780918330FD00a34a61D9a7Efd3f43ca845",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x8dc6490A6204dF846BaBE809cB695ba17Df1F9B1",
+ "commit_store": "0xA190660787B6B183Dd82B243eA10e609327c7308",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xBAE6560eCa9B77Cb047158C783e36F7735C86037",
+ "commit_store": "0x6168aDF58e1Ad446BaD45c6275Bef60Ef4FFBAb8",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0xE14501F2838F2fA1Ceb52E78ABdA289EcE1705EA",
+ "commit_store": "0xa8DD25B29787527Df283211C24Ac72B17150A696",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xd2D98Be6a1C241e86C807e51cED6ABb51d044203",
+ "commit_store": "0x4d75A5cE454b264b187BeE9e189aF1564a68408D",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x7c6221880A1D62506b1A08Dab3Bf695A49AcDD22",
+ "commit_store": "0x0684076EE3595221861C50cDb9Cb66402Ec11Cb9",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x3e5B3b7559D39563a74434157b31781322dA712D",
+ "commit_store": "0x7954372FF6f80908e5A2dC2a19d796A1005f91D2",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Polygon Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xD7AcF65dA1E1f34b663aB199a474F209bF2b0523",
+ "router": "0x849c5ED5a80F5B408Dd4969b78c2C8fdf0565Bfe",
+ "price_registry": "0x30D873664Ba766C983984C7AF9A921ccE36D34e1",
+ "wrapped_native": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0xD16D025330Edb91259EEA8ed499daCd39087c295",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0x5FA30697e90eB30954895c45b028F7C0dDD39b12",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x20B028A2e0F6CCe3A11f3CE5F2B8986F932e89b4",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xF5b5A2fC11BF46B1669C3B19d98B19C79109Dca9",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xFd77c53AA4eF0E3C01f5Ac012BF7Cc7A3ECf5168",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x3111cfbF5e84B5D9BD952dd8e957f4Ca75f728Cf",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x5060eF647a1F66BE6eE27FAe3046faf8D53CeB2d",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0xa8a9eDa2867c2E0CE0d5ECe273961F1EcC3CC25B",
+ "commit_store": "0xbD4480658dca8496a65046dfD1BDD44EF897Bdb5",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0xB9e3680639c9F0C4e0b02FD81C445094426244Ae",
+ "commit_store": "0x8c63d4e67f7c4af6FEd2f56A34fB4e01CB807CFF",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xD0FA7DE2D18A0c59D3fD7dfC7aB4e913C6Aa7b68",
+ "commit_store": "0xF88053B9DAC8Dd3039a4eFa8639159aaa3F2D4Cb",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x592773924741F0Da889a0dfdab71171Dd11E054C",
+ "commit_store": "0xEC4d35E1A85f770f4D93BA43a462c9d87Ef7017e",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x45320085fF051361D301eC1044318213A5387A15",
+ "commit_store": "0x4Dc771B5ef21ef60c33e2987E092345f2b63aE08",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xBa754ecd3CFA7E9093F688EAc3860cf9D07Fc0AC",
+ "commit_store": "0x04C0D5302E3D8Ca0A0019141a52a23B59cdb70e4",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xd7c877ea02310Cce9278D9A048Aa1Bb9aF72F00d",
+ "commit_store": "0x92A1C927E8E10Ab6A40E5A5154e2300D278d1a67",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "WeMix Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x80f1FcdC96B55e459BF52b998aBBE2c364935d69",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x07aaC8B69A62dB5bd3d244091916EbF2fac17b76",
+ "router": "0x7798b795Fde864f4Cd1b124a38Ba9619B7F8A442",
+ "price_registry": "0x252863688762aD86868D3d3076233Eacd80c7055",
+ "wrapped_native": "0x7D72b22a74A216Af4a002a1095C8C707d6eC1C5f",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x9aBfd6f4C865610692AB6fb1Be862575809fFabf",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xbE0Cfae74677F8dd16a246a3a5c8cbB1973118f4",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x56657ec4D15C71f7F3C17ba2b21C853A24Dc5381",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x70f3b0FD7e6a4B9B623e9AB859604A9EE03e48BD",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x777058C1e1dcE4eB8001F38631a1cd9450816e5a",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x190bcE84CF2d500B878966F4Cf98a50d78f2675E",
+ "deployed_at": 11111111
+ },
+ "Kroma Mainnet": {
+ "on_ramp": "0x47E9AE0A815C94836202E696748A5d5476aD8735",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x2ba68a395B72a6E3498D312efeD755ed2f3CF223",
+ "commit_store": "0xdAeC234DA83F68707Bb8AcB2ee6a01a5FD4c2391",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0xFac907F9a1087B846Faa75A14C5d34A8639233d8",
+ "commit_store": "0xF2812063446c7deD2CA306c67A68364BdDcbEfc5",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x6ec9ca4Cba62cA17c55F05ad2000B46192f02035",
+ "commit_store": "0x84534BE763366a69710E119c100832955795B34B",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0x87220D01DF0fF27149B47227897074653788fd23",
+ "commit_store": "0xF8dD2be2C6FA43e48A17146380CbEBBB4291807b",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x8f0229804513A9Bc00c1308414AB279Dbc718ae1",
+ "commit_store": "0x3A85D1b8641d83a87957C6ECF1b62151213e0842",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xF92Fa796F5307b029c65CA26f322a6D86f211194",
+ "commit_store": "0xbeC110FF43D52be2066B06525304A9924E16b73b",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Kroma Mainnet": {
+ "off_ramp": "0xF886d8DC64E544af4835cbf91e5678A54D95B80e",
+ "commit_store": "0x8794C9534658fdCC44f2FF6645Bf31cf9F6d2d5D",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ }
+ }
+}
+"""
+
+[CCIP.Env]
+TTL = '8h'
+
+[CCIP.Env.Network]
+selected_networks = [
+ 'ETHEREUM_MAINNET',
+ 'ARBITRUM_MAINNET',
+ 'OPTIMISM_MAINNET'
+ ]
+
+[CCIP.Groups.load]
+NetworkPairs = [
+ 'ETHEREUM_MAINNET,OPTIMISM_MAINNET',
+ 'ETHEREUM_MAINNET,ARBITRUM_MAINNET',
+ 'ARBITRUM_MAINNET,OPTIMISM_MAINNET' # added as batch 1
+]
+
+BiDirectionalLane = true
+PhaseTimeout = '40m'
+ExistingDeployment = true
+
+[CCIP.Groups.load.TokenConfig]
+NoOfTokensPerChain = 1
+CCIPOwnerTokens = true
+
+[CCIP.Groups.load.LoadProfile]
+RequestPerUnitTime = [1]
+TimeUnit = '3h'
+TestDuration = '24h'
+TestRunName = 'mainnet-2.7-ccip1.2'
+FailOnFirstErrorInLoad = true
+SkipRequestIfAnotherRequestTriggeredWithin = '40m'
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 0
+DataLength = 100
+NoOfTokens = 1
+AmountPerToken = 1
+
+[CCIP.Groups.smoke]
+# these are all the valid network pairs
+NetworkPairs = [
+ 'ETHEREUM_MAINNET,OPTIMISM_MAINNET',
+ 'ETHEREUM_MAINNET,ARBITRUM_MAINNET',
+ 'ARBITRUM_MAINNET,OPTIMISM_MAINNET'
+]
+
+BiDirectionalLane = true
+DestGasLimit = 0
+PhaseTimeout = '20m'
+LocalCluster = false
+ExistingDeployment = true
+ReuseContracts = true
+
+[CCIP.Groups.smoke.TokenConfig]
+NoOfTokensPerChain = 1
+CCIPOwnerTokens = true
+
+[CCIP.Groups.smoke.MsgDetails]
+MsgType = 'Data'
+DestGasLimit = 0
+DataLength = 100
+NoOfTokens = 1
+AmountPerToken = 1
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/override/mainnet.toml b/integration-tests/ccip-tests/testconfig/override/mainnet.toml
new file mode 100644
index 00000000000..72695ba7545
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/override/mainnet.toml
@@ -0,0 +1,767 @@
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+[CCIP.Deployments]
+Data = """
+{
+ "lane_configs": {
+ "Arbitrum Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xf97f4df75117a78c1A5a0DBb814Af92458539FB4",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xe06b0e8c4bd455153e8794ad7Ea8Ff5A14B64E4b",
+ "router": "0x141fa059441E0ca23ce184B6A78bafD2A517DdE8",
+ "price_registry": "0x13015e4E6f839E1Aa1016DF521ea458ecA20438c",
+ "wrapped_native": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
+ "version" : "1.4.0",
+ "src_contracts": {
+ "Avalanche Mainnet": {
+ "on_ramp": "0x05B723f3db92430FbE4395fD03E40Cc7e9D17988",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x77b60F85b25fD501E3ddED6C1fe7bF565C08A22A",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x79f3ABeCe5A3AFFf32D47F4CFe45e7b65c9a2D91",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xCe11020D56e5FDbfE46D9FC3021641FfbBB5AdEE",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0xC09b72E8128620C40D89649019d995Cc79f030C3",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x122F05F49e90508F089eE8D0d868d1a4f3E5a809",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x66a0046ac9FA104eB38B04cfF391CcD0122E6FbC",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Mainnet": {
+ "off_ramp": "0xe0109912157d5B75ea8b3181123Cf32c73bc9920",
+ "commit_store": "0xDaa61b8Cd85977820f92d1e749E1D9F55Da6CCEA",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xdB19F77F87661f9be0F557cf9a1ebeCf7D8F206c",
+ "commit_store": "0x6e37f4c82d9A31cc42B445874dd3c3De97AB553f",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0xB1b705c2315fced1B38baE463BE7DDef531e47fA",
+ "commit_store": "0x310cECbFf14Ad0307EfF762F461a487C1abb90bf",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x542ba1902044069330e8c5b36A84EC503863722f",
+ "commit_store": "0x060331fEdA35691e54876D957B4F9e3b8Cb47d20",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xeeed4D86F3E0e6d32A6Ad29d8De6A0Dc91963A5f",
+ "commit_store": "0xbbB563c4d98020b9c0f3Cc34c2C0Ef9676806E35",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x9bDA7c8DCda4E39aFeB483cc0B7E3C1f6E0D5AB1",
+ "commit_store": "0x63a0AeaadAe851b990bBD9dc41f5C1B08b32026d",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xEEf5Fb4c4953F9cA9ab1f25cE590776AfFc2c455",
+ "commit_store": "0xD268286A277095a9C3C90205110831a84505881c",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Avalanche Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x5947BB275c521040051D82396192181b413227A3",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xdFD6C0dc67666DE3bB36b31eec5c7B1542A82C1E",
+ "router": "0xF4c7E640EdA248ef95972845a62bdC74237805dB",
+ "price_registry": "0xfA4edD04eaAcDB07c8D73621bc1790eC50D8c489",
+ "wrapped_native": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x98f51B041e493fc4d72B8BD33218480bA0c66DDF",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x268fb4311D2c6CB2bbA01CCA9AC073Fb3bfd1C7c",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x8eaae6462816CB4957184c48B86afA7642D8Bf2B",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xD0701FcC7818c31935331B02Eb21e91eC71a1704",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x8629008887E073260c5434D6CaCFc83C3001d211",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x97500490d9126f34cf9aA0126d64623E170319Ef",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x9b1ed9De069Be4d50957464b359f98eD0Bf34dd5",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x770b1375F86E7a9bf30DBe3F97bea67193dC9135",
+ "commit_store": "0x23E2b34Ce8e12c53f8a39AD4b3FFCa845f8E617C",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0x4d6A796Bc85dcDF41ce9AaEB50B094C6b589748f",
+ "commit_store": "0xc4C4358FA01a04D6c6FE3b96a351946d4c2715C2",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x83F53Fc798FEbfFbdF84830AD403b9989187a06C",
+ "commit_store": "0xD8ceCE2D7794385E00Ce3EF94550E732b0A0B959",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x5B833BD6456c604Eb396C0fBa477aD49e82B1A2a",
+ "commit_store": "0x23E23958D220B774680f91c2c91a6f2B2f610d7e",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xb68A3EE8bD0A09eE221cf1859Dd5a4d5765188Fe",
+ "commit_store": "0x83DCeeCf822981F9F8552925eEfd88CAc1905dEA",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x19250aBE66B88F214d02B6f3BF80F4118290C619",
+ "commit_store": "0x87A0935cE6254dB1252bBac90d1D07D04846aDCA",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x317dE8bc5c3292E494b6496586696d4966A922B0",
+ "commit_store": "0x97Fbf3d6DEac16adC721aE9187CeEa1e610aC7Af",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Base Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x88Fb150BDc53A65fe94Dea0c9BA0a6dAf8C6e196",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x38660c8CC222c0192b635c2ac09687B4F25cCE5F",
+ "router": "0x881e3A65B4d4a04dD529061dd0071cf975F58bCD",
+ "price_registry": "0x6337a58D4BD7Ba691B66341779e8f87d4679923a",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x1E5Ca70d1e7A1B26061125738a880BBeA42FeB21",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xBE5a9E336D9614024B4Fa10D8112671fc9A42d96",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xdd4Fb402d41Beb0eEeF6CfB1bf445f50bDC8c981",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xDEA286dc0E01Cb4755650A6CF8d1076b454eA1cb",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0xd952FEAcDd5919Cc5E9454b53bF45d4E73dD6457",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x3DB8Bea142e41cA3633890d0e5640F99a895D6A5",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x8531E63aE9279a1f0D09eba566CD1b092b95f3D5",
+ "commit_store": "0x327E13f54c7871a2416006B33B4822eAAD357916",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x8345F2fF67e5A65e85dc955DE1414832608E00aD",
+ "commit_store": "0xd0b13be4c53A6262b47C5DDd36F0257aa714F562",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x48a51f5D38BE630Ddd6417Ea2D9052B8efc91a18",
+ "commit_store": "0xF97127e77252284EC9D4bc13C247c9D1A99F72B0",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xEC0cFe335a4d53dBA70CB650Ab56eEc32788F0BB",
+ "commit_store": "0x0ae3c2c7FB789bd05A450CD3075D11f6c2Ca4F77",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xf50c0d2a8B6Db60f1D93E60f03d0413D56153E4F",
+ "commit_store": "0x16f72C15165f7C9d74c12fDF188E399d4d3724e4",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x75F29f058b31106F99caFdc17c9b26ADfcC7b5D7",
+ "commit_store": "0xb719616E732581B570232DfB13Ca49D27667Af9f",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "BSC Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x404460C6A5EdE2D891e8297795264fDe62ADBB75",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x3DB43b96B2625F4232e9Df900d464dd2c64C0021",
+ "router": "0x34B03Cb9086d7D758AC55af71584F81A598759FE",
+ "price_registry": "0xd64aAbD70A71d9f0A00B99F6EFc1626aA2dD43C7",
+ "wrapped_native": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
+ "src_contracts": {
+ "Avalanche Mainnet": {
+ "on_ramp": "0x6aa72a998859eF93356c6521B72155D355D0Cfd2",
+ "deployed_at": 11111111
+ },
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x2788b46BAcFF49BD89562e6bA5c5FBbbE5Fa92F7",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x70bC7f7a6D936b289bBF5c0E19ECE35B437E2e36",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x0Bf40b034872D0b364f3DCec04C7434a4Da1C8d9",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x4FEB11A454C9E8038A8d0aDF599Fe7612ce114bA",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x6bD4754D86fc87FE5b463D368f26a3587a08347c",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x1467fF8f249f5bc604119Af26a47035886f856BE",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Mainnet": {
+ "off_ramp": "0x37a6fa55fe61061Ae97bF7314Ae270eCF71c5ED3",
+ "commit_store": "0x1f558F6dcf0224Ef1F78A24814FED548B9602c80",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x3DA330fd8Ef10d93cFB7D4f8ecE7BC1F10811feC",
+ "commit_store": "0x86D55Ff492cfBBAf0c0D42D4EE615144E78b3D02",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0x574c697deab06B805D8780898B3F136a1F4892Dc",
+ "commit_store": "0x002B164b1dcf4E92F352DC625A01Be0E890EdEea",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x181Bb1E97b0bDD1D85E741ad0943552D3682cc35",
+ "commit_store": "0x3fF27A34fF0FA77921C3438e67f58da1a83e9Ce1",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xE7E080C8d62d595a223C577C7C8d1f75d9A5E664",
+ "commit_store": "0xF4d53346bDb6d393C74B0B72Aa7D6689a3eAad79",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x26af2046Da85d7f6712D5edCa81B9E3b2e7A60Ab",
+ "commit_store": "0x4C1dA405a789AC2853A69D8290B8B9b47a0374F8",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xC027C5AEb230008c243Be463A73571e581F94c13",
+ "commit_store": "0x2EB426C8C54D740d1FC856eB3Ff96feA03957978",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Ethereum Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x514910771AF9Ca656af840dff83E8264EcF986CA",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x8B63b3DE93431C0f756A493644d128134291fA1b",
+ "router": "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D",
+ "price_registry": "0x8c9b2Efb7c64C394119270bfecE7f54763b958Ad",
+ "wrapped_native": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x925228D7B82d883Dde340A55Fe8e6dA56244A22C",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0x3df8dAe2d123081c4D5E946E655F7c109B9Dd630",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0xe2c2AB221AA0b957805f229d2AA57fBE2f4dADf7",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x91D25A56Db77aD5147437d8B83Eb563D46eBFa69",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x86B47d8411006874eEf8E4584BdFD7be8e5549d1",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x35F0ca9Be776E4B38659944c257bDd0ba75F1B8B",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0xCbE7e5DA76dC99Ac317adF6d99137005FDA4E2C4",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0xeFC4a18af59398FF23bfe7325F2401aD44286F4d",
+ "commit_store": "0x9B2EEd6A1e16cB50Ed4c876D2dD69468B21b7749",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x569940e02D4425eac61A7601632eC00d69f75c17",
+ "commit_store": "0x2aa101BF99CaeF7fc1355D4c493a1fe187A007cE",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xdf85c8381954694E74abD07488f452b4c2Cddfb3",
+ "commit_store": "0x8DC27D621c41a32140e22E2a4dAf1259639BAe04",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x7Afe7088aff57173565F4b034167643AA8b9171c",
+ "commit_store": "0x87c55D48DF6EF7B08153Ab079e76bFEcbb793D75",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xB095900fB91db00E6abD247A5A5AD1cee3F20BF7",
+ "commit_store": "0x4af4B497c998007eF83ad130318eB2b925a79dc8",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x0af338F0E314c7551bcE0EF516d46d855b0Ee395",
+ "commit_store": "0xD37a60E8C36E802D2E1a6321832Ee85556Beeb76",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x3a129e6C18b23d18BA9E6Aa14Dc2e79d1f91c6c5",
+ "commit_store": "0x31f6ab382DDeb9A316Ab61C3945a5292a50a89AB",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Kroma Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xC1F6f7622ad37C3f46cDF6F8AA0344ADE80BF450",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xB59779d3364BC6d71168245f9ebb96469E5a5a98",
+ "router": "0xE93E8B0d1b1CEB44350C8758ed1E2799CCee31aB",
+ "price_registry": "0x8155B4710e7bbC90924E957104F94Afd4f95Eca2",
+ "wrapped_native": "0x4200000000000000000000000000000000000001",
+ "src_contracts": {
+ "WeMix Mainnet": {
+ "on_ramp": "0x3C5Ab46fA1dB1dECD854224654313a69bf9fcAD3",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "WeMix Mainnet": {
+ "off_ramp": "0x2B555774B3D1dcbcd76efb7751F3c5FbCFABC5C4",
+ "commit_store": "0x213124614aAf31eBCE7c612A12aac5f8aAD77DE4",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Optimism Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x350a791Bfc2C21F9Ed5d10980Dad2e2638ffa7f6",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x8C7C2C3362a42308BB5c368677Ad321D11693b81",
+ "router": "0x3206695CaE29952f4b0c22a169725a865bc8Ce0f",
+ "price_registry": "0xb52545aECE8C73A97E52a146757EC15b90Ed8488",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x0C9BE7Cfd12c735E5aaE047C1dCB845d54E518C3",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xD0D3E757bFBce7ae1881DDD7F6d798DDcE588445",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x0b1760A8112183303c5526C6b24569fd3A274f3B",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xa3c9544B82846C45BE37593d5d9ACffbE61BF3A6",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x55183Db1d2aE0b63e4c92A64bEF2CBfc2032B127",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x6B57145e322c877E7D91Ed8E31266eB5c02F7EfC",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x82e9f4C5ec4a84E310d60D462a12042E5cbA0954",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x0C9BE7Cfd12c735E5aaE047C1dCB845d54E518C3",
+ "commit_store": "0x55028780918330FD00a34a61D9a7Efd3f43ca845",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0x8dc6490A6204dF846BaBE809cB695ba17Df1F9B1",
+ "commit_store": "0xA190660787B6B183Dd82B243eA10e609327c7308",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xBAE6560eCa9B77Cb047158C783e36F7735C86037",
+ "commit_store": "0x6168aDF58e1Ad446BaD45c6275Bef60Ef4FFBAb8",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0xE14501F2838F2fA1Ceb52E78ABdA289EcE1705EA",
+ "commit_store": "0xa8DD25B29787527Df283211C24Ac72B17150A696",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xd2D98Be6a1C241e86C807e51cED6ABb51d044203",
+ "commit_store": "0x4d75A5cE454b264b187BeE9e189aF1564a68408D",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x7c6221880A1D62506b1A08Dab3Bf695A49AcDD22",
+ "commit_store": "0x0684076EE3595221861C50cDb9Cb66402Ec11Cb9",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0x3e5B3b7559D39563a74434157b31781322dA712D",
+ "commit_store": "0x7954372FF6f80908e5A2dC2a19d796A1005f91D2",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Polygon Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0xb0897686c545045aFc77CF20eC7A532E3120E0F1",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0xD7AcF65dA1E1f34b663aB199a474F209bF2b0523",
+ "router": "0x849c5ED5a80F5B408Dd4969b78c2C8fdf0565Bfe",
+ "price_registry": "0x30D873664Ba766C983984C7AF9A921ccE36D34e1",
+ "wrapped_native": "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0xD16D025330Edb91259EEA8ed499daCd39087c295",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0x5FA30697e90eB30954895c45b028F7C0dDD39b12",
+ "deployed_at": 11111111
+ },
+ "Base Mainnet": {
+ "on_ramp": "0x20B028A2e0F6CCe3A11f3CE5F2B8986F932e89b4",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0xF5b5A2fC11BF46B1669C3B19d98B19C79109Dca9",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0xFd77c53AA4eF0E3C01f5Ac012BF7Cc7A3ECf5168",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x3111cfbF5e84B5D9BD952dd8e957f4Ca75f728Cf",
+ "deployed_at": 11111111
+ },
+ "WeMix Mainnet": {
+ "on_ramp": "0x5060eF647a1F66BE6eE27FAe3046faf8D53CeB2d",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0xa8a9eDa2867c2E0CE0d5ECe273961F1EcC3CC25B",
+ "commit_store": "0xbD4480658dca8496a65046dfD1BDD44EF897Bdb5",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0xB9e3680639c9F0C4e0b02FD81C445094426244Ae",
+ "commit_store": "0x8c63d4e67f7c4af6FEd2f56A34fB4e01CB807CFF",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Mainnet": {
+ "off_ramp": "0xD0FA7DE2D18A0c59D3fD7dfC7aB4e913C6Aa7b68",
+ "commit_store": "0xF88053B9DAC8Dd3039a4eFa8639159aaa3F2D4Cb",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x592773924741F0Da889a0dfdab71171Dd11E054C",
+ "commit_store": "0xEC4d35E1A85f770f4D93BA43a462c9d87Ef7017e",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0x45320085fF051361D301eC1044318213A5387A15",
+ "commit_store": "0x4Dc771B5ef21ef60c33e2987E092345f2b63aE08",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0xBa754ecd3CFA7E9093F688EAc3860cf9D07Fc0AC",
+ "commit_store": "0x04C0D5302E3D8Ca0A0019141a52a23B59cdb70e4",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Mainnet": {
+ "off_ramp": "0xd7c877ea02310Cce9278D9A048Aa1Bb9aF72F00d",
+ "commit_store": "0x92A1C927E8E10Ab6A40E5A5154e2300D278d1a67",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "WeMix Mainnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x80f1FcdC96B55e459BF52b998aBBE2c364935d69",
+ "bridge_tokens": [],
+ "bridge_tokens_pools": [],
+ "arm": "0x07aaC8B69A62dB5bd3d244091916EbF2fac17b76",
+ "router": "0x7798b795Fde864f4Cd1b124a38Ba9619B7F8A442",
+ "price_registry": "0x252863688762aD86868D3d3076233Eacd80c7055",
+ "wrapped_native": "0x7D72b22a74A216Af4a002a1095C8C707d6eC1C5f",
+ "src_contracts": {
+ "Arbitrum Mainnet": {
+ "on_ramp": "0x9aBfd6f4C865610692AB6fb1Be862575809fFabf",
+ "deployed_at": 11111111
+ },
+ "Avalanche Mainnet": {
+ "on_ramp": "0xbE0Cfae74677F8dd16a246a3a5c8cbB1973118f4",
+ "deployed_at": 11111111
+ },
+ "BSC Mainnet": {
+ "on_ramp": "0x56657ec4D15C71f7F3C17ba2b21C853A24Dc5381",
+ "deployed_at": 11111111
+ },
+ "Optimism Mainnet": {
+ "on_ramp": "0x70f3b0FD7e6a4B9B623e9AB859604A9EE03e48BD",
+ "deployed_at": 11111111
+ },
+ "Polygon Mainnet": {
+ "on_ramp": "0x777058C1e1dcE4eB8001F38631a1cd9450816e5a",
+ "deployed_at": 11111111
+ },
+ "Ethereum Mainnet": {
+ "on_ramp": "0x190bcE84CF2d500B878966F4Cf98a50d78f2675E",
+ "deployed_at": 11111111
+ },
+ "Kroma Mainnet": {
+ "on_ramp": "0x47E9AE0A815C94836202E696748A5d5476aD8735",
+ "deployed_at": 11111111
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Mainnet": {
+ "off_ramp": "0x2ba68a395B72a6E3498D312efeD755ed2f3CF223",
+ "commit_store": "0xdAeC234DA83F68707Bb8AcB2ee6a01a5FD4c2391",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Mainnet": {
+ "off_ramp": "0xFac907F9a1087B846Faa75A14C5d34A8639233d8",
+ "commit_store": "0xF2812063446c7deD2CA306c67A68364BdDcbEfc5",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Mainnet": {
+ "off_ramp": "0x6ec9ca4Cba62cA17c55F05ad2000B46192f02035",
+ "commit_store": "0x84534BE763366a69710E119c100832955795B34B",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Mainnet": {
+ "off_ramp": "0x87220D01DF0fF27149B47227897074653788fd23",
+ "commit_store": "0xF8dD2be2C6FA43e48A17146380CbEBBB4291807b",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Mainnet": {
+ "off_ramp": "0x8f0229804513A9Bc00c1308414AB279Dbc718ae1",
+ "commit_store": "0x3A85D1b8641d83a87957C6ECF1b62151213e0842",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Ethereum Mainnet": {
+ "off_ramp": "0xF92Fa796F5307b029c65CA26f322a6D86f211194",
+ "commit_store": "0xbeC110FF43D52be2066B06525304A9924E16b73b",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Kroma Mainnet": {
+ "off_ramp": "0xF886d8DC64E544af4835cbf91e5678A54D95B80e",
+ "commit_store": "0x8794C9534658fdCC44f2FF6645Bf31cf9F6d2d5D",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ }
+ }
+}
+"""
+
+[CCIP.Env]
+TTL = '8h'
+
+[CCIP.Env.Network]
+selected_networks = [
+ 'ETHEREUM_MAINNET',
+ 'ARBITRUM_MAINNET',
+ 'BASE_MAINNET',
+ 'WEMIX_MAINNET',
+ 'OPTIMISM_MAINNET',
+ 'POLYGON_MAINNET',
+ 'AVALANCHE_MAINNET',
+ 'BSC_MAINNET',
+ 'KROMA_MAINNET'
+ ]
+
+[CCIP.Groups.load]
+NetworkPairs = [
+ 'ETHEREUM_MAINNET,OPTIMISM_MAINNET',
+ 'ETHEREUM_MAINNET,AVALANCHE_MAINNET',
+ 'ETHEREUM_MAINNET,POLYGON_MAINNET',
+ 'ETHEREUM_MAINNET,BSC_MAINNET',
+ 'ETHEREUM_MAINNET,ARBITRUM_MAINNET',
+ 'ETHEREUM_MAINNET,BASE_MAINNET',
+ 'ETHEREUM_MAINNET,WEMIX_MAINNET',
+ 'AVALANCHE_MAINNET,POLYGON_MAINNET',
+ 'BASE_MAINNET,OPTIMISM_MAINNET',
+ 'BASE_MAINNET,ARBITRUM_MAINNET',
+ 'AVALANCHE_MAINNET,BSC_MAINNET',
+ 'BSC_MAINNET,POLYGON_MAINNET',
+ 'OPTIMISM_MAINNET,POLYGON_MAINNET',
+ 'BASE_MAINNET,BSC_MAINNET',
+ 'POLYGON_MAINNET,ARBITRUM_MAINNET', # added as batch 1
+ 'ARBITRUM_MAINNET,BSC_MAINNET', # added as batch 1
+ 'ARBITRUM_MAINNET,OPTIMISM_MAINNET', # added as batch 1
+ 'AVALANCHE_MAINNET,OPTIMISM_MAINNET', # added as batch 2
+ 'AVALANCHE_MAINNET,ARBITRUM_MAINNET', # added as batch 2
+ 'BASE_MAINNET,POLYGON_MAINNET', # added as batch 2
+ 'BSC_MAINNET,OPTIMISM_MAINNET', # added as batch 2
+ 'AVALANCHE_MAINNET,BASE_MAINNET', # added as batch 2
+ 'WEMIX_MAINNET,KROMA_MAINNET',
+ 'BSC_MAINNET,WEMIX_MAINNET', # added as batch 2
+ 'AVALANCHE_MAINNET,WEMIX_MAINNET', # added as batch 2
+ 'POLYGON_MAINNET,WEMIX_MAINNET', # added as batch 2
+ 'WEMIX_MAINNET,ARBITRUM_MAINNET', # added as batch 2
+ 'OPTIMISM_MAINNET,WEMIX_MAINNET' # added as batch 2
+]
+
+BiDirectionalLane = true
+PhaseTimeout = '20m'
+ExistingDeployment = true
+
+[CCIP.Groups.load.TokenConfig]
+NoOfTokensPerChain = 1
+
+[CCIP.Groups.load.LoadProfile]
+RequestPerUnitTime = [1]
+TimeUnit = '1h'
+TestDuration = '5h'
+TestRunName = 'mainnet-2.7-ccip1.2'
+FailOnFirstErrorInLoad = true
+SkipRequestIfAnotherRequestTriggeredWithin = '40m'
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 0
+DataLength = 100
+NoOfTokens = 1
+AmountPerToken = 1
+
+[CCIP.Groups.smoke]
+# these are all the valid network pairs
+NetworkPairs = [
+ 'ETHEREUM_MAINNET,OPTIMISM_MAINNET',
+ 'ETHEREUM_MAINNET,AVALANCHE_MAINNET',
+ 'ETHEREUM_MAINNET,POLYGON_MAINNET',
+ 'ETHEREUM_MAINNET,BSC_MAINNET',
+ 'ETHEREUM_MAINNET,ARBITRUM_MAINNET',
+ 'ETHEREUM_MAINNET,BASE_MAINNET',
+ 'ETHEREUM_MAINNET,WEMIX_MAINNET',
+ 'AVALANCHE_MAINNET,POLYGON_MAINNET',
+ 'BASE_MAINNET,OPTIMISM_MAINNET',
+ 'BASE_MAINNET,ARBITRUM_MAINNET',
+ 'AVALANCHE_MAINNET,BSC_MAINNET',
+ 'BSC_MAINNET,POLYGON_MAINNET',
+ 'OPTIMISM_MAINNET,POLYGON_MAINNET',
+ 'BASE_MAINNET,BSC_MAINNET',
+ 'POLYGON_MAINNET,ARBITRUM_MAINNET', # added as batch 1
+ 'ARBITRUM_MAINNET,BSC_MAINNET', # added as batch 1
+ 'ARBITRUM_MAINNET,OPTIMISM_MAINNET', # added as batch 1
+ 'AVALANCHE_MAINNET,OPTIMISM_MAINNET', # added as batch 2
+ 'AVALANCHE_MAINNET,ARBITRUM_MAINNET', # added as batch 2
+ 'BASE_MAINNET,POLYGON_MAINNET', # added as batch 2
+ 'BSC_MAINNET,OPTIMISM_MAINNET', # added as batch 2
+ 'AVALANCHE_MAINNET,BASE_MAINNET', # added as batch 2
+ 'WEMIX_MAINNET,KROMA_MAINNET',
+ 'BSC_MAINNET,WEMIX_MAINNET', # added as batch 2
+ 'AVALANCHE_MAINNET,WEMIX_MAINNET', # added as batch 2
+ 'POLYGON_MAINNET,WEMIX_MAINNET', # added as batch 2
+ 'WEMIX_MAINNET,ARBITRUM_MAINNET', # added as batch 2
+ 'OPTIMISM_MAINNET,WEMIX_MAINNET' # added as batch 2
+]
+
+BiDirectionalLane = true
+PhaseTimeout = '20m'
+LocalCluster = false
+ExistingDeployment = true
+ReuseContracts = true
+
+
+[CCIP.Groups.smoke.TokenConfig]
+NoOfTokensPerChain = 1
+CCIPOwnerTokens = true
+
+[CCIP.Groups.smoke.MsgDetails]
+MsgType = 'Data'
+DestGasLimit = 0
+DataLength = 100
+NoOfTokens = 1
+AmountPerToken = 1
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/ccip-crib.toml b/integration-tests/ccip-tests/testconfig/tomls/ccip-crib.toml
new file mode 100644
index 00000000000..12afcea791f
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/ccip-crib.toml
@@ -0,0 +1,96 @@
+[CCIP]
+[CCIP.Env]
+Mockserver = 'http://mockserver:1080'
+
+[CCIP.Env.Network]
+selected_networks = ['AVALANCHE_FUJI', 'BSC_TESTNET']
+
+[CCIP.Env.Network.EVMNetworks.AVALANCHE_FUJI]
+evm_name = 'Avalanche Fuji'
+evm_chain_id = 43113
+evm_urls = ['wss://...']
+evm_http_urls = ['https://...']
+evm_keys = ['']
+evm_simulated = false
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 50000
+evm_transaction_timeout = '2m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_tag = true
+
+[CCIP.Env.Network.EVMNetworks.BSC_TESTNET]
+evm_name = 'BSC Testnet'
+evm_chain_id = 97
+evm_urls = ['wss://...']
+evm_http_urls = ['https://...']
+evm_keys = ['']
+evm_simulated = false
+client_implementation = 'BSC'
+evm_chainlink_transaction_limit = 50000
+evm_transaction_timeout = '2m'
+evm_minimum_confirmations = 3
+evm_gas_estimation_buffer = 0
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_tag = true
+
+[CCIP.Env.ExistingCLCluster]
+Name = 'crib-ani'
+NoOfNodes = 6
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-ani-demo-node1.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-1'
+
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-ani-demo-node2.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-2'
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-ani-demo-node3.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-3'
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-ani-demo-node4.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-4'
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-ani-demo-node5.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-5'
+
+[[CCIP.Env.ExistingCLCluster.NodeConfigs]]
+URL = 'https://crib-ani-demo-node6.main.stage.cldev.sh/'
+Email = 'notreal@fakeemail.ch'
+Password = 'fj293fbBnlQ!f9vNs'
+InternalIP = 'app-node-6'
+
+[CCIP.Groups]
+[CCIP.Groups.smoke]
+LocalCluster = false
+TestRunName = 'crib-ani-demo'
+NodeFunding = 1000.0
+
+
+[CCIP.Groups.load]
+LocalCluster = false
+
+[CCIP.Groups.load.LoadProfile]
+TestRunName = 'crib-ani-demo'
+TimeUnit = '1s'
+TestDuration = '15m'
+RequestPerUnitTime = [1]
+NodeFunding = 1000.0
diff --git a/integration-tests/ccip-tests/testconfig/tomls/ccip-default.toml b/integration-tests/ccip-tests/testconfig/tomls/ccip-default.toml
new file mode 100644
index 00000000000..0157ac24fb4
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/ccip-default.toml
@@ -0,0 +1,440 @@
+# this file contains the deafult configuration for the test
+# all secrets must be stored in .env file and sourced before running the test
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = 'latest'
+OffRamp = 'latest'
+OnRamp = 'latest'
+CommitStore = 'latest'
+TokenPool = 'latest'
+
+# all variables to set up the test environment
+[CCIP.Env]
+TTL = '5h'
+# networks between which lanes will be set up and the messages will be sent
+# if more than 2 networks are specified, then lanes will be set up between all possible pairs of networks
+# for example , if Networks = ['SIMULATED_1', 'SIMULATED_2', 'SIMULATED_3'],
+# then lanes will be set up between SIMULATED_1 and SIMULATED_2, SIMULATED_1 and SIMULATED_3, SIMULATED_2 and SIMULATED_3
+# default value is ['SIMULATED_1', 'SIMULATED_2'] which means that test will create two private geth networks from scratch and set up lanes between them
+[CCIP.Env.Network]
+selected_networks = ['SIMULATED_1', 'SIMULATED_2']
+
+# PrivateEthereumNetworks.NETWORK_NAME contains the configuration of private ethereum network that includes ethereum version, evm node client, chain id,
+# certain chain configurations, addresses to fund or custom docker images to be used. These are non-dev networks, but they all run just a single node.
+[CCIP.Env.PrivateEthereumNetworks.SIMULATED_1]
+# either eth1 or eth2 (for post-Merge); for eth2 Prysm is used for consensus layer.
+ethereum_version = "eth1"
+# geth, besu, erigon or nethermind
+execution_layer = "geth"
+# eth2-only, if set to true environment startup will wait until at least 1 epoch has been finalised
+wait_for_finalization=false
+
+[CCIP.Env.PrivateEthereumNetworks.SIMULATED_1.EthereumChainConfig]
+# eth2-only, the lower the value the faster the block production (3 is minimum)
+seconds_per_slot = 3
+# eth2-only, the lower the value the faster the epoch finalisation (2 is minimum)
+slots_per_epoch = 2
+# eht2-only, the lower tha value the faster the chain starts (10 is minimum)
+genesis_delay = 15
+# eth2-only, number of validators
+validator_count = 4
+chain_id = 1337
+# address that should be founded in genesis wih ETH
+addresses_to_fund = [
+ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
+]
+
+[CCIP.Env.PrivateEthereumNetworks.SIMULATED_1.EthereumChainConfig.HardForkEpochs]
+# eth2-only, epoch at which chain will upgrade do Dencun or Deneb/Cancun (1 is minimum)
+Deneb = 500
+
+#[CCIP.Env.PrivateEthereumNetworks.SIMULATED_1.CustomDockerImages]
+# custom docker image that will be used for execution layer client. It has to be one of: hyperledger/besu, nethermind/nethermind, thorax/erigon or ethereum/client-go.
+# instead of using a specific tag you can also use "latest_available" to use latest published tag in Github or "latest_stable" to use latest stable release from Github
+# (if corresponding Docker image on Docker Hub has not been published environment creation will fail).
+#execution_layer="hyperledger/besu:latest_stable"
+
+[CCIP.Env.PrivateEthereumNetworks.SIMULATED_2]
+ethereum_version = "eth1"
+execution_layer = "geth"
+
+[CCIP.Env.PrivateEthereumNetworks.SIMULATED_2.EthereumChainConfig]
+seconds_per_slot = 3
+slots_per_epoch = 2
+genesis_delay = 15
+validator_count = 4
+chain_id = 2337
+addresses_to_fund = [
+ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
+ "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
+]
+
+[CCIP.Env.PrivateEthereumNetworks.SIMULATED_2.EthereumChainConfig.HardForkEpochs]
+Deneb = 500
+
+[CCIP.Env.Logging]
+test_log_collect = false # if set to true will save logs even if test did not fail
+
+[CCIP.Env.Logging.LogStream]
+# supported targets: file, loki, in-memory. if empty no logs will be persistet
+log_targets = ["file"]
+# context timeout for starting log producer and also time-frame for requesting logs
+log_producer_timeout = "10s"
+# number of retries before log producer gives up and stops listening to logs
+log_producer_retry_limit = 10
+
+# these values will be used to set up chainlink DON
+# along with these values, the secrets needs to be specified as part of .env variables
+#
+[CCIP.Env.NewCLCluster]
+NoOfNodes = 6 # number of chainlink nodes to be set up in DON, including one bootstrap node
+# if tests are run in k8s, then the following values will be used to set up chainlink nodes and postgresql database,
+# in case of local deployment through docker container, these values will be ignored
+# for k8s deployment, helm charts are used from https://github.com/smartcontractkit/chainlink-testing-framework/tree/main/charts/chainlink/templates
+NodeMemory = '4Gi' # memory to be allocated to each chainlink node; only used if tests are in k8s
+NodeCPU = '2' # cpu to be allocated to each chainlink node ; only used if tests are in k8s
+DBMemory = '4Gi' # memory to be allocated to postgresql database ; only used if tests are in k8s
+DBCPU = '2' # cpu to be allocated to postgresql database ; only used if tests are in k8s
+DBCapacity = '10Gi' # disk space to be allocated to postgresql database ; only used if tests are in k8s in stateful deployment
+IsStateful = true # if true, chainlink nodes and postgresql database will be deployed as stateful set in k8s
+DBArgs = [
+ 'shared_buffers=1536MB',
+ 'effective_cache_size=4096MB',
+ 'work_mem=64MB',
+] # postgresql database arguments ; only used if tests are in k8s
+
+# these values will be used to set up chainlink DON, if all the chainlink nodes are deployed with same configuration
+[CCIP.Env.NewCLCluster.Common]
+Name = 'node1' # name of the chainlink node, used as prefix for all the chainlink node names , used for k8s deployment
+DBImage = 'postgres' # postgresql database image to be used for k8s deployment
+DBTag = '13.12' # postgresql database image tag to be used for k8s deployment
+# override config toml file for chainlink nodes
+BaseConfigTOML = """
+[Feature]
+LogPoller = true
+CCIP = true
+
+[Log]
+Level = 'debug'
+JSONConsole = true
+
+[Log.File]
+MaxSize = '0b'
+
+[WebServer]
+AllowOrigins = '*'
+HTTPPort = 6688
+SecureCookies = false
+HTTPWriteTimeout = '1m'
+
+[WebServer.RateLimit]
+Authenticated = 2000
+Unauthenticated = 1000
+
+[WebServer.TLS]
+HTTPSPort = 0
+
+[Database]
+MaxIdleConns = 10
+MaxOpenConns = 20
+MigrateOnStartup = true
+
+[OCR2]
+Enabled = true
+DefaultTransactionQueueDepth = 0
+
+[OCR]
+Enabled = false
+DefaultTransactionQueueDepth = 0
+
+[P2P]
+[P2P.V2]
+Enabled = true
+ListenAddresses = ['0.0.0.0:6690']
+AnnounceAddresses = ['0.0.0.0:6690']
+DeltaDial = '500ms'
+DeltaReconcile = '5s'
+"""
+
+# override config toml related to EVMNode configs for chainlink nodes; applicable to all EVM node configs in chainlink toml
+CommonChainConfigTOML = """
+[GasEstimator]
+PriceMax = '200 gwei'
+LimitDefault = 6000000
+FeeCapDefault = '200 gwei'
+"""
+
+# chainlink override config toml for EVMNode config specific to EVM chains with chain id as mentioned in the key
+[CCIP.Env.NewCLCluster.Common.ChainConfigTOMLByChain]
+# applicable for arbitrum-goerli chain
+421613 = """
+[GasEstimator]
+PriceMax = '400 gwei'
+LimitDefault = 100000000
+FeeCapDefault = '200 gwei'
+BumpThreshold = 60
+BumpPercent = 20
+BumpMin = '100 gwei'
+"""
+
+# applicable for optimism-goerli chain
+420 = """
+[GasEstimator]
+PriceMax = '150 gwei'
+LimitDefault = 6000000
+FeeCapDefault = '150 gwei'
+BumpThreshold = 60
+BumpPercent = 20
+BumpMin = '100 gwei'
+
+[GasEstimator.BlockHistory]
+BlockHistorySize = 200
+EIP1559FeeCapBufferBlocks = 0
+"""
+
+# applicable for base-goerli chain
+84531 = """
+[GasEstimator]
+PriceMax = '150 gwei'
+LimitDefault = 6000000
+FeeCapDefault = '150 gwei'
+BumpThreshold = 60
+BumpPercent = 20
+BumpMin = '100 gwei'
+
+[GasEstimator.BlockHistory]
+BlockHistorySize = 200
+EIP1559FeeCapBufferBlocks = 0
+"""
+
+# applicable for avalanche-fuji chain
+43113 = """
+[GasEstimator]
+PriceMax = '200 gwei'
+LimitDefault = 6000000
+FeeCapDefault = '200 gwei'
+BumpThreshold = 60
+"""
+
+# applicable for sepolia chain
+11155111 = """
+[GasEstimator]
+PriceMax = '200 gwei'
+LimitDefault = 6000000
+FeeCapDefault = '200 gwei'
+
+[GasEstimator.BlockHistory]
+BlockHistorySize = 200
+EIP1559FeeCapBufferBlocks = 0
+"""
+
+# the following configs are specific to each test type, smoke, load , chaos, etc...
+[CCIP.Groups]
+[CCIP.Groups.smoke]
+# uncomment the following with specific values of lane combinations to be tested, if you want to run your tests to run only on these specific network pairs
+# if specific network pairs are not mentioned, then all the network pairs will be tested based on values in CCIP.Env.NetworkPairs and CCIP.Groups..NoOfNetworks
+# if specified, CCIP.Groups..NetworkPairs takes precedence over CCIP.Env.NetworkPairs and CCIP.Groups..NoOfNetworks
+#NetworkPairs = ['SEPOLIA,OPTIMISM_GOERLI','SEPOLIA,POLYGON_MUMBAI','AVALANCHE_FUJI,SEPOLIA','SEPOLIA,BASE_GOERLI','SEPOLIA,BSC_TESTNET','SEPOLIA,WEMIX_TESTNET','AVALANCHE_FUJI,OPTIMISM_GOERLI','AVALANCHE_FUJI,POLYGON_MUMBAI','AVALANCHE_FUJI,BSC_TESTNET','AVALANCHE_FUJI,BASE_GOERLI','OPTIMISM_GOERLI,BASE_GOERLI','OPTIMISM_GOERLI,POLYGON_MUMBAI','BSC_TESTNET,POLYGON_MUMBAI','BSC_TESTNET,BASE_GOERLI','WEMIX_TESTNET,KROMA_SEPOLIA']
+
+KeepEnvAlive = false # if true, the test will not tear down the test environment after the test is finished
+CommitAndExecuteOnSameDON = true # if true, and the test is building the env from scratch, same chainlink nodes will be used for Commit and Execution jobs.
+# Otherwise Commit and execution jobs will be set up in different nodes based on the number of nodes specified in NoOfCommitNodes and CCIP.Env.NewCLCluster.NoOfNodes
+BiDirectionalLane = true # True uses both the lanes. If bidirectional is false only one way lane is set up.
+NoOfCommitNodes = 5 # no of chainlink nodes with Commit job
+PhaseTimeout = '10m' # Duration to wait for the each phase validation(SendRequested, Commit, RMN Blessing, Execution) to time-out.
+LocalCluster = true # if true, the test will use the local docker container, otherwise it will use the k8s cluster
+ExistingDeployment = false # true if the tests are run on existing environment with already set-up jobs, smart contracts, etc...
+# In this case the test will only be used to send and verify ccip requests considering that lanes are already functioning.
+# In case of ExistingDeployment = false, the test will deploy it's own contracts and spin up new chainlink nodes with ccip jobs. It will then use
+# the newly deployed contracts to send and verify ccip requests.
+
+ReuseContracts = true # Whether to reuse the contracts deployed in the previous run. Default value is true unless specified
+NodeFunding = 1.0 # Amount of native currency to fund the chainlink node with for each network. Default value is 1 for smoke and 20 for load unless specified
+NoOfRoutersPerPair = 1 # denotes the number of routers to be deployed per network. mostly required for scalability tests.
+MulticallInOneTx = false # if set to true, multiple ccip-send is grouped under one blockchain transaction
+NoOfSendsInMulticall = 5 # if MulticallInOneTx=true , this denotes the number of ccip-sends to group in one transaction
+
+NoOfNetworks = 2 # this is used with Networks in `CCIP.Env`, `NoOfNetworks < len(CCIP.Env.Networks)` test only uses first NoOfNetworks from` CCIP.Env.Networks`.
+# This value is ignored if CCIP.Groups..NetworkPairs is provided
+
+
+[CCIP.Groups.smoke.MsgDetails]
+MsgType = 'DataWithToken' # type of message to be sent, either 'Token' or 'DataWithToken' Or 'Data'
+DestGasLimit = 100000 # change this to 0 gas limit if you are doing ccip-send to an EOA
+DataLength = 1000 # length of the data to be sent in ccip message if MsgType = 'Data'/'DataWithToken'
+NoOfTokens = 2 # number of bridge tokens to be sent in ccip message if MsgType = 'Token'/'DataWithToken'
+AmountPerToken = 1 # amount to be sent for each bridge token in ccip message if MsgType = 'Token'/'DataWithToken'
+
+[CCIP.Groups.smoke.TokenConfig]
+TimeoutForPriceUpdate = '15m' # Duration to wait for the price update to time-out.
+# Now testing only with dynamic price getter (no pipeline).
+# Could be removed once the pipeline is completely removed.
+WithPipeline = false
+NoOfTokensPerChain = 2 # number of bridge tokens to be deployed per network; if MsgType = 'Token'/'DataWithToken'
+CCIPOwnerTokens = false # if true, the test will use deploy the tokens by the CCIPOwner, otherwise the tokens will be deployed by a non-owner account, only applicable for 1.5 pools and onwards
+
+#NoOfTokensWithDynamicPrice = 15 # number of tokens with dynamic price to be deployed
+#DynamicPriceUpdateInterval ='15s' # Periodic interval to update the price of tokens, if there are tokens with dynamic price
+
+# uncomment the following if you want to run your tests with specific number of lanes;
+# in this case out of all the possible lane combinations, only the ones with the specified number of lanes will be considered
+# for example, if you have provided CCIP.Env.Networks = ['SIMULATED_1', 'SIMULATED_2', 'SIMULATED_3'] and CCIP.Groups..MaxNoOfLanes = 2,
+# then only random combinations of 2 lanes from the following will be considered for the test :
+# ['SIMULATED_1', 'SIMULATED_2'], ['SIMULATED_1', 'SIMULATED_3'], ['SIMULATED_2', 'SIMULATED_3']
+#MaxNoOfLanes = # maximum number of lanes to be added in the test; mainly used for scalability tests
+
+
+[CCIP.Groups.load]
+# uncomment the following with specific values of lane combinations to be tested, if you want to run your tests to run only on these specific network pairs
+# if specific network pairs are not mentioned, then all the network pairs will be tested based on values in CCIP.Env.NetworkPairs and CCIP.Groups..NoOfNetworks
+# if specified, CCIP.Groups..NetworkPairs takes precedence over CCIP.Env.NetworkPairs and CCIP.Groups..NoOfNetworks
+#NetworkPairs = ['SEPOLIA,OPTIMISM_GOERLI','SEPOLIA,POLYGON_MUMBAI','AVALANCHE_FUJI,SEPOLIA','SEPOLIA,BASE_GOERLI','SEPOLIA,BSC_TESTNET','SEPOLIA,WEMIX_TESTNET','AVALANCHE_FUJI,OPTIMISM_GOERLI','AVALANCHE_FUJI,POLYGON_MUMBAI','AVALANCHE_FUJI,BSC_TESTNET','AVALANCHE_FUJI,BASE_GOERLI','OPTIMISM_GOERLI,BASE_GOERLI','OPTIMISM_GOERLI,POLYGON_MUMBAI','BSC_TESTNET,POLYGON_MUMBAI','BSC_TESTNET,BASE_GOERLI','WEMIX_TESTNET,KROMA_SEPOLIA']
+
+KeepEnvAlive = false # same as above
+CommitAndExecuteOnSameDON = true # same as above
+BiDirectionalLane = true # same as above
+NoOfCommitNodes = 5 # same as above
+PhaseTimeout = '10m' # same as above
+LocalCluster = false # same as above
+ExistingDeployment = false # same as above
+ReuseContracts = true # same as above
+NodeFunding = 20.0 # same as above
+NoOfRoutersPerPair = 1 # same as above
+MulticallInOneTx = false # same as above
+NoOfSendsInMulticall = 5 # same as above
+NoOfNetworks = 2 # same as above
+
+[CCIP.Groups.load.OffRampConfig]
+BatchGasLimit = 11000000
+
+[CCIP.Groups.load.LoadProfile]
+RequestPerUnitTime = [1] # number of ccip requests to be sent per unit time
+TimeUnit = '10s' # unit of time for RequestPerUnitTime
+TestDuration = '10m' # load test duration, not used for smoke tests
+WaitBetweenChaosDuringLoad = '2m' # Duration to wait between each chaos injection during load test; only valid for chaos tests
+NetworkChaosDelay = '100ms' # Duration for network chaos delay; only valid for chaos tests using network chaos
+
+# uncomment the following if you want your test results to be reflected under CCIP test grafana dashboard with namespace label same as the value of the following variable
+# TestRunName = __ i.e prod-testnet-2.7.1-ccip1.2.1-beta
+# Message Frequency Distribution Example
+
+# The 'Frequencies' array configures the relative frequency of different message types.
+# Each value in the array represents the relative frequency of a message type,
+# determining how often each type appears relative to the others.
+#[CCIP.Groups.load.LoadProfile.MsgProfile]
+#Frequencies = [4, 12, 3, 1]
+
+# Example Breakdown:
+# - Frequencies = [4, 12, 3, 1]
+# - Total Sum of Frequencies = 4 + 12 + 3 + 1 = 20
+# - Percentages:
+# - Message Type 1: (4 / 20) * 100% = 20%
+# - Message Type 2: (12 / 20) * 100% = 60%
+# - Message Type 3: (3 / 20) * 100% = 15%
+# - Message Type 4: (1 / 20) * 100% = 5%
+# These percentages reflect how often each message type should appear in the total set of messages.
+# Please note - if the total set of messages is not equal to the multiple of sum of frequencies, the percentages will not be accurate.
+[CCIP.Groups.load.LoadProfile.MsgProfile]
+Frequencies = [1] # frequency of each message type in the MsgDetails
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'DataWithToken' # type of message to be sent, either 'Token' or 'DataWithToken' Or 'Data'
+DestGasLimit = 100000 # change this to 0 gas limit if you are doing ccip-send to an EOA
+DataLength = 1000 # length of the data to be sent in ccip message if MsgType = 'Data'/'DataWithToken'
+NoOfTokens = 2 # number of bridge tokens to be sent in ccip message if MsgType = 'Token'/'DataWithToken'
+AmountPerToken = 1 # amount to be sent for each bridge token in ccip message if MsgType = 'Token'/'DataWithToken'
+
+
+[CCIP.Groups.load.TokenConfig]
+TimeoutForPriceUpdate = '15m' # Duration to wait for the price update to time-out.
+# Now testing only with dynamic price getter (no pipeline).
+# Could be removed once the pipeline is completely removed.
+WithPipeline = false
+NoOfTokensPerChain = 2 # number of bridge tokens to be deployed per network; if MsgType = 'Token'/'DataWithToken'
+CCIPOwnerTokens = false # if true, the test will use deploy the tokens by the CCIPOwner, otherwise the tokens and pools will be deployed by a non-owner account,
+# only applicable for 1.5 pools and onwards, if you are running with pre-1.5 pools, then set this to true to deploy token pools by CCIPOwner, otherwise
+# the test will fail
+
+#NoOfTokensWithDynamicPrice = 15 # number of tokens with dynamic price to be deployed
+#DynamicPriceUpdateInterval ='15s' # Periodic interval to update the price of tokens, if there are tokens with dynamic price
+
+# uncomment the following if you want to run your tests with specific number of lanes;
+# in this case out of all the possible lane combinations, only the ones with the specified number of lanes will be considered
+# for example, if you have provided CCIP.Env.Networks = ['SIMULATED_1', 'SIMULATED_2', 'SIMULATED_3'] and CCIP.Groups..MaxNoOfLanes = 2,
+# then only random combinations of 2 lanes from the following will be considered for the test :
+# ['SIMULATED_1', 'SIMULATED_2'], ['SIMULATED_1', 'SIMULATED_3'], ['SIMULATED_2', 'SIMULATED_3']
+#MaxNoOfLanes = # maximum number of lanes to be added in the test; mainly used for scalability tests
+#
+
+# Uncomment the following if you want to run your tests with updated OCR params
+# otherwise test will use default OCR params from -
+# https://github.com/smartcontractkit/chainlink/blob/develop/integration-tests/ccip-tests/contracts/contract_deployer.go#L729-L751
+## OCR Params
+#CommitInflightExpiry = '2m'
+#ExecInflightExpiry = '2m'
+#
+#[CCIP.Groups.load.CommitOCRParams]
+#DeltaProgress = '2m'
+#DeltaResend = '5s'
+#DeltaRound = '75s'
+#DeltaGrace = '5s'
+#MaxDurationQuery = '100ms'
+#MaxDurationObservation = '35s'
+#MaxDurationReport = '10s'
+#MaxDurationShouldAcceptFinalizedReport = '5s'
+#MaxDurationShouldTransmitAcceptedReport = '10s'
+#
+#[CCIP.Groups.load.ExecOCRParams]
+#DeltaProgress = '100s'
+#DeltaResend = '5s'
+#DeltaRound = '40s'
+#DeltaGrace = '5s'
+#MaxDurationQuery = '100ms'
+#MaxDurationObservation = '20s'
+#MaxDurationReport = '8s'
+#MaxDurationShouldAcceptFinalizedReport = '5s'
+#MaxDurationShouldTransmitAcceptedReport = '8s'
+
+[CCIP.Groups.chaos]
+# uncomment the following with specific values of lane combinations to be tested, if you want to run your tests to run only on these specific network pairs
+# if specific network pairs are not mentioned, then all the network pairs will be tested based on values in CCIP.Env.NetworkPairs and CCIP.Groups..NoOfNetworks
+# if specified, CCIP.Groups..NetworkPairs takes precedence over CCIP.Env.NetworkPairs and CCIP.Groups..NoOfNetworks
+#NetworkPairs = ['SEPOLIA,OPTIMISM_GOERLI','SEPOLIA,POLYGON_MUMBAI','AVALANCHE_FUJI,SEPOLIA','SEPOLIA,BASE_GOERLI','SEPOLIA,BSC_TESTNET','SEPOLIA,WEMIX_TESTNET','AVALANCHE_FUJI,OPTIMISM_GOERLI','AVALANCHE_FUJI,POLYGON_MUMBAI','AVALANCHE_FUJI,BSC_TESTNET','AVALANCHE_FUJI,BASE_GOERLI','OPTIMISM_GOERLI,BASE_GOERLI','OPTIMISM_GOERLI,POLYGON_MUMBAI','BSC_TESTNET,POLYGON_MUMBAI','BSC_TESTNET,BASE_GOERLI','WEMIX_TESTNET,KROMA_SEPOLIA']
+KeepEnvAlive = false
+CommitAndExecuteOnSameDON = false
+BiDirectionalLane = true
+NoOfCommitNodes = 5
+PhaseTimeout = '50m'
+LocalCluster = false
+ExistingDeployment = false
+ReuseContracts = true
+NodeFunding = 20.0
+NoOfRoutersPerPair = 1
+MulticallInOneTx = false
+NoOfSendsInMulticall = 5
+NoOfNetworks = 2
+# chaos test settings
+ChaosDuration = '10m' # Duration for whichever chaos will be injected; only valid for chaos tests
+
+
+[CCIP.Groups.chaos.MsgDetails]
+MsgType = 'DataWithToken' # type of message to be sent, either 'Token' or 'DataWithToken' Or 'Data'
+DestGasLimit = 100000 # change this to 0 gas limit if you are doing ccip-send to an EOA
+DataLength = 1000 # length of the data to be sent in ccip message if MsgType = 'Data'/'DataWithToken'
+NoOfTokens = 2 # number of bridge tokens to be sent in ccip message if MsgType = 'Token'/'DataWithToken'
+AmountPerToken = 1 # amount to be sent for each bridge token in ccip message if MsgType = 'Token'/'DataWithToken'
+
+[CCIP.Groups.chaos.TokenConfig]
+TimeoutForPriceUpdate = '15m' # Duration to wait for the price update to time-out.
+# Now testing only with dynamic price getter (no pipeline).
+# Could be removed once the pipeline is completely removed.
+WithPipeline = false
+NoOfTokensPerChain = 2 # number of bridge tokens to be deployed per network; if MsgType = 'Token'/'DataWithToken'
+
+# uncomment the following if you want to run your tests with specific number of lanes;
+# in this case out of all the possible lane combinations, only the ones with the specified number of lanes will be considered
+# for example, if you have provided CCIP.Env.Networks = ['SIMULATED_1', 'SIMULATED_2', 'SIMULATED_3'] and CCIP.Groups..MaxNoOfLanes = 2,
+# then only random combinations of 2 lanes from the following will be considered for the test :
+# ['SIMULATED_1', 'SIMULATED_2'], ['SIMULATED_1', 'SIMULATED_3'], ['SIMULATED_2', 'SIMULATED_3']
+#MaxNoOfLanes = # maximum number of lanes to be added in the test; mainly used for scalability tests
diff --git a/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/baseline.toml b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/baseline.toml
new file mode 100644
index 00000000000..d48c0b0f797
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/baseline.toml
@@ -0,0 +1,189 @@
+## Baseline performance test on simulated environment (with chaos)
+## 40 chains / 400 lanes
+## historyDepth 200 / finalityDepth 200
+## block_time = 1s
+## throughput 1msg / 5s
+## 20% Token, 60% DataWithToken, 15% Regular size msgs, 5% Large msgs
+##
+## make test_load_ccip testimage=.dkr.ecr..amazonaws.com/chainlink-ccip-tests:ccip-develop \
+## testname=TestLoadCCIPStableRequestTriggeringWithNetworkChaos \
+## override_toml=./testconfig/tomls/ccip-1.4-stress/baseline.toml \
+## secret_toml=./testconfig/tomls/secrets.toml
+
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+[CCIP.Env]
+TTL = '8h'
+
+[CCIP.Env.Network]
+selected_networks= ['PRIVATE-CHAIN-1', 'PRIVATE-CHAIN-2']
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-1]
+evm_name = 'private-chain-1'
+evm_chain_id = 2337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 200
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-2]
+evm_name = 'private-chain-2'
+evm_chain_id = 1337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 200
+
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-1]
+block_time = 1
+
+#
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-2]
+block_time = 1
+
+[CCIP.Env.NewCLCluster]
+NoOfNodes = 17
+NodeMemory = '10Gi'
+NodeCPU = '6'
+DBMemory = '16Gi'
+DBCPU = '4'
+DBStorageClass = 'gp3'
+PromPgExporter = true
+DBCapacity = '50Gi'
+IsStateful = true
+DBArgs = ['shared_buffers=4096MB', 'effective_cache_size=8192MB', 'work_mem=128MB']
+
+[CCIP.Env.NewCLCluster.Common]
+BaseConfigTOML = """
+[Feature]
+LogPoller = true
+CCIP = true
+
+[Log]
+Level = 'debug'
+JSONConsole = true
+
+[Log.File]
+MaxSize = '0b'
+
+[WebServer]
+AllowOrigins = '*'
+HTTPPort = 6688
+SecureCookies = false
+HTTPWriteTimeout = '1m'
+
+[WebServer.RateLimit]
+Authenticated = 2000
+Unauthenticated = 1000
+
+[WebServer.TLS]
+HTTPSPort = 0
+
+[Database]
+MaxIdleConns = 20
+MaxOpenConns = 30
+MigrateOnStartup = true
+
+[OCR2]
+Enabled = true
+DefaultTransactionQueueDepth = 0
+
+[OCR]
+Enabled = false
+DefaultTransactionQueueDepth = 0
+
+[P2P]
+[P2P.V2]
+Enabled = true
+ListenAddresses = ['0.0.0.0:6690']
+AnnounceAddresses = ['0.0.0.0:6690']
+DeltaDial = '500ms'
+DeltaReconcile = '5s'
+"""
+
+CommonChainConfigTOML = """
+[HeadTracker]
+HistoryDepth = 200
+
+[GasEstimator]
+PriceMax = '200 gwei'
+LimitDefault = 6000000
+FeeCapDefault = '200 gwei'
+"""
+
+[CCIP.Groups]
+[CCIP.Groups.load]
+KeepEnvAlive = true
+NoOfCommitNodes = 16
+PhaseTimeout = '40m'
+NodeFunding = 1000.0
+NoOfRoutersPerPair = 2
+NoOfNetworks = 40
+MaxNoOfLanes = 400
+
+[CCIP.Groups.load.OffRampConfig]
+BatchGasLimit = 11000000
+
+[CCIP.Groups.load.TokenConfig]
+TimeoutForPriceUpdate = '15m'
+NoOfTokensPerChain = 10
+NoOfTokensWithDynamicPrice = 10
+DynamicPriceUpdateInterval ='15s'
+CCIPOwnerTokens = true
+
+[CCIP.Groups.load.LoadProfile]
+TestDuration = '4h'
+TimeUnit = '5s'
+RequestPerUnitTime = [1]
+OptimizeSpace = true
+NetworkChaosDelay = '100ms'
+
+# to represent 20%, 60%, 15%, 5% of the total messages
+[CCIP.Groups.load.LoadProfile.MsgProfile]
+Frequencies = [4,12,3,1]
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Token'
+DestGasLimit = 0
+DataLength = 0
+NoOfTokens = 1
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'DataWithToken'
+DestGasLimit = 500000
+DataLength = 5000
+NoOfTokens = 1
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 800000
+DataLength = 10000
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 2500000
+DataLength = 10000
diff --git a/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/prod-testnet.toml b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/prod-testnet.toml
new file mode 100644
index 00000000000..f8321584c84
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/prod-testnet.toml
@@ -0,0 +1,964 @@
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+
+[CCIP.Deployments]
+Data = """
+{
+ "lane_configs": {
+ "Arbitrum Sepolia": {
+ "is_native_fee_token": true,
+ "fee_token": "0xb1D4538B4571d411F07960EF2838Ce337FE1E80E",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x5EF7a726Fd21Fd9D77D34E3C56cfDD8691F7F0ac",
+ "router": "0x2a9C5afB0d0e4BAb2BCdaE109EC4b0c4Be15a165",
+ "price_registry": "0x89D5b13908b9063abCC6791dc724bF7B7c93634C",
+ "wrapped_native": "0xE591bf0A0CF924A0674d7792db046B23CEbF5f34",
+ "src_contracts": {
+ "Avalanche Fuji": {
+ "on_ramp": "0x1Cb56374296ED19E86F68fA437ee679FD7798DaA",
+ "deployed_at": 33999325
+ },
+ "Base Sepolia": {
+ "on_ramp": "0x7854E73C73e7F9bb5b0D5B4861E997f4C6E8dcC6",
+ "deployed_at": 9199926
+ },
+ "Gnosis Chiado": {
+ "on_ramp": "0x973CbE752258D32AE82b60CD1CB656Eebb588dF0",
+ "deployed_at": 42809650
+ },
+ "Optimism Sepolia": {
+ "on_ramp": "0x701Fe16916dd21EFE2f535CA59611D818B017877",
+ "deployed_at": 35180131
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0x4205E1Ca0202A248A5D42F5975A8FE56F3E302e9",
+ "deployed_at": 35180131
+ },
+ "WeMix Testnet": {
+ "on_ramp": "0xBD4106fBE4699FE212A34Cc21b10BFf22b02d959",
+ "deployed_at": 18816676
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Fuji": {
+ "off_ramp": "0xcab0EF91Bee323d1A617c0a027eE753aFd6997E4",
+ "commit_store": "0x0d90b9b96cBFa0D01635ce12982ccE1b70827c7a",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Sepolia": {
+ "off_ramp": "0xc1982985720B959E66c19b64F783361Eb9B60F26",
+ "commit_store": "0x28F66bB336f6db713d6ad2a3bd1B7a531282A159",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Gnosis Chiado": {
+ "off_ramp": "0x935C26F9a9122E5F9a27f2d3803e74c75B94f5a3",
+ "commit_store": "0xEdb963Ec5c2E5AbdFdCF137eF44A445a7fa4787A",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Sepolia": {
+ "off_ramp": "0xfD404A89e1d195F0c65be1A9042C77745197659e",
+ "commit_store": "0x84B7B012c95f8A152B44Ab3e952f2dEE424fA8e1",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0x1c71f141b4630EBE52d6aF4894812960abE207eB",
+ "commit_store": "0xaB0c8Ba51E7Fa3E5693a4Fbb39473520FD85d173",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Testnet": {
+ "off_ramp": "0x262e16C8D42aa07bE13e58F81e7D9F62F6DE2830",
+ "commit_store": "0xc132eFAf929299E5ee704Fa6D9796CFa23Bb8b2C",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Avalanche Fuji": {
+ "fee_token": "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x0ea0D7B2b78DD3A926fC76d6875a287F0AEB158F",
+ "router": "0xF694E193200268f9a4868e4Aa017A0118C9a8177",
+ "price_registry": "0x19e157E5fb1DAec1aE4BaB113fdf077F980704AA",
+ "wrapped_native": "0xd00ae08403B9bbb9124bB305C09058E32C39A48c",
+ "src_contracts": {
+ "Arbitrum Sepolia": {
+ "on_ramp": "0x8bB16BEDbFd62D1f905ACe8DBBF2954c8EEB4f66",
+ "deployed_at": 31888860
+ },
+ "BSC Testnet": {
+ "on_ramp": "0xF25ECF1Aad9B2E43EDc2960cF66f325783245535",
+ "deployed_at": 33214865
+ },
+ "Base Sepolia": {
+ "on_ramp": "0x1A674645f3EB4147543FCA7d40C5719cbd997362",
+ "deployed_at": 31235262
+ },
+ "Gnosis Chiado": {
+ "on_ramp": "0x1532e5b204ee2b2244170c78E743CB9c168F4DF9",
+ "deployed_at": 32817266
+ },
+ "Optimism Sepolia": {
+ "on_ramp": "0xC334DE5b020e056d0fE766dE46e8d9f306Ffa1E2",
+ "deployed_at": 30396804
+ },
+ "Polygon Amoy": {
+ "on_ramp": "0x610F76A35E17DA4542518D85FfEa12645eF111Fc",
+ "deployed_at": 31982368
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0x5724B4Cc39a9690135F7273b44Dfd3BA6c0c69aD",
+ "deployed_at": 33214865
+ },
+ "WeMix Testnet": {
+ "on_ramp": "0x677B5ab5C8522d929166c064d5700F147b15fa33",
+ "deployed_at": 30436465
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Sepolia": {
+ "off_ramp": "0x90A74072e7B0c2d59e13aB4d8f93c8198c413194",
+ "commit_store": "0xf3458CFd2fdf4a6CF0Ce296d520DD21eB194828b",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Testnet": {
+ "off_ramp": "0x10b28009E5D776F1f5AAA73941CE8953B8f42d26",
+ "commit_store": "0xacDD582F271eCF22FAd6764cCDe1c4a534b732A8",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Sepolia": {
+ "off_ramp": "0xdBdE8510226d1E060A3bf982b67705C67f5697e2",
+ "commit_store": "0x8Ee73BC9492b4182D289E5C1e66e40CD876CC00F",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Gnosis Chiado": {
+ "off_ramp": "0x56dF55aF5F0A4689f3364230587a68eD6A314fAd",
+ "commit_store": "0xabA7ff98094c4cc7A075812EefF2CD21f6400235",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Sepolia": {
+ "off_ramp": "0x3d7CbC95DCC33257F14D6Eb780c88Bd56C6335BB",
+ "commit_store": "0x1fcDC02edDfb405f378ba53cF9E6104feBcB7542",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Amoy": {
+ "off_ramp": "0x3e33290B90fD0FF30a3FA138934DF028E4eCA348",
+ "commit_store": "0xCFe3556Aa42d40be09BD23aa80448a19443BE5B1",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0x9e5e4324F8608D54A50a317832d456a392E4F8C2",
+ "commit_store": "0x92A51eD3F041B39EbD1e464C1f7cb1e8f8A8c63f",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Testnet": {
+ "off_ramp": "0xD0D338318bC6837b091FC7AB5F2a94B7783507d5",
+ "commit_store": "0xd9D479208235c7355848ff4aF26eB5aacfDC30c6",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "BSC Testnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0xF9a21B587111e7E8745Fb8b13750014f19DB0014",
+ "router": "0xE1053aE1857476f36A3C62580FF9b016E8EE8F6f",
+ "price_registry": "0xCCDf022c9d31DC26Ebab4FB92432724a5b79809a",
+ "wrapped_native": "0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd",
+ "src_contracts": {
+ "Avalanche Fuji": {
+ "on_ramp": "0xa2515683E99F50ADbE177519A46bb20FfdBaA5de",
+ "deployed_at": 40500000
+ },
+ "Base Sepolia": {
+ "on_ramp": "0x3E807220Ca84b997c0d1928162227b46C618e0c5",
+ "deployed_at": 37115558
+ },
+ "Gnosis Chiado": {
+ "on_ramp": "0x8735f991d41eA9cA9D2CC75cD201e4B7C866E63e",
+ "deployed_at": 40228352
+ },
+ "Polygon Amoy": {
+ "on_ramp": "0xf37CcbfC04adc1B56a46B36F811D52C744a1AF78",
+ "deployed_at": 39572254
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0xB1DE44B04C00eaFe9915a3C07a0CaeA4410537dF",
+ "deployed_at": 38150066
+ },
+ "WeMix Testnet": {
+ "on_ramp": "0x89268Afc1BEA0782a27ba84124E3F42b196af927",
+ "deployed_at": 38184995
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Fuji": {
+ "off_ramp": "0x6e6fFCb6B4BED91ff0CC8C2e57EC029dA7DB80C2",
+ "commit_store": "0x38Bc38Bd824b6eE87571f9D3CFbe6D6E28E3Dc62",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Sepolia": {
+ "off_ramp": "0x2C61FD7E93Dc79422861282145c59B56dFbc3a8c",
+ "commit_store": "0x42fAe5B3605804CF6d08632d7A25864e24F792Ae",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Gnosis Chiado": {
+ "off_ramp": "0x71a44a60832B0F8B63232C9516e7E6aEc3A373Dc",
+ "commit_store": "0xAC24299a91b72d1Cb5B31147e3CF54964D896974",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Amoy": {
+ "off_ramp": "0x63440C7747d37bc6154b5538AE32b54FE0965AfA",
+ "commit_store": "0xAD22fA198CECfC534927aE1D480c460d5bB3460F",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0xf1c128Fe52Ea78CcAAB407509292E61ce38C1523",
+ "commit_store": "0x59dFD870dC4bd76A7B879A4f705Fdcd2595f85f9",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Testnet": {
+ "off_ramp": "0xfd9B19c3725da5B517aA705B848ff3f21F98280e",
+ "commit_store": "0x3c1F1412563188aBc8FE3fd53E8F1Cb601CaB4f9",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Base Sepolia": {
+ "is_native_fee_token": true,
+ "fee_token": "0xE4aB69C077896252FAFBD49EFD26B5D171A32410",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x5aA82cA372782d6CC33AA4C830Df2a91017A7e1b",
+ "router": "0xD3b06cEbF099CE7DA4AcCf578aaebFDBd6e88a93",
+ "price_registry": "0x4D20536e60832bE579Cd38E89Dc03d11E1741FbA",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Arbitrum Sepolia": {
+ "on_ramp": "0x58622a80c6DdDc072F2b527a99BE1D0934eb2b50",
+ "deployed_at": 5146539
+ },
+ "Avalanche Fuji": {
+ "on_ramp": "0xAbA09a1b7b9f13E05A6241292a66793Ec7d43357",
+ "deployed_at": 7810235
+ },
+ "BSC Testnet": {
+ "on_ramp": "0xD806966beAB5A3C75E5B90CDA4a6922C6A9F0c9d",
+ "deployed_at": 5144127
+ },
+ "Gnosis Chiado": {
+ "on_ramp": "0x2Eff2d1BF5C557d6289D208a7a43608f5E3FeCc2",
+ "deployed_at": 9817141
+ },
+ "Optimism Sepolia": {
+ "on_ramp": "0x3b39Cd9599137f892Ad57A4f54158198D445D147",
+ "deployed_at": 5147649
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0x6486906bB2d85A6c0cCEf2A2831C11A2059ebfea",
+ "deployed_at": 7810235
+ },
+ "ethereum-testnet-sepolia-mode-1": {
+ "on_ramp": "0x3d0115386C01436870a2c47e6297962284E70BA6",
+ "deployed_at": 10409731
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Sepolia": {
+ "off_ramp": "0xd364C06ac99a82a00d3eFF9F2F78E4Abe4b9baAA",
+ "commit_store": "0xdE8d0f47a71eA3fDFBD3162271652f2847939097",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Fuji": {
+ "off_ramp": "0xAd91214efFee446500940c764DF77AF18427294F",
+ "commit_store": "0x1242b6c5e0e349b8d4BCf0938f961C4B4f7EA3Fa",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Testnet": {
+ "off_ramp": "0xd5E9508921434e8758f4540D55c1c066b7cc1598",
+ "commit_store": "0x1a86b29364D1B3fA3386329A361aA98A104b2742",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Gnosis Chiado": {
+ "off_ramp": "0x9Bb7e398ef9Acfe9cA584C39B1E233Cba62BB9f7",
+ "commit_store": "0x1F4B82cDebaC5e3a0Dd53183D47e51808B4a64cB",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Sepolia": {
+ "off_ramp": "0x86a3910908eCaAA31Fcd9F0fC8841D8E98f1511d",
+ "commit_store": "0xE99a87C9b5ed4D2b6060195DEea5106ffF655736",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0x189F61D9B886Dd2975D5Abc893c8Cf5f5effda71",
+ "commit_store": "0xEE7e27346DCD1e711348D0F7f7ECB53a9a3a08a7",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "ethereum-testnet-sepolia-mode-1": {
+ "off_ramp": "0xB26647A23e8b4284375e5C74b77c9557aE709D03",
+ "commit_store": "0x4b4fEB401d3E613e1D6242E155C83A80BF9ac2C9",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Gnosis Chiado": {
+ "is_native_fee_token": true,
+ "fee_token": "0xDCA67FD8324990792C0bfaE95903B8A64097754F",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0xb6f1Fe2CDE891eFd5Efd2A563C4C2F2549163718",
+ "router": "0x19b1bac554111517831ACadc0FD119D23Bb14391",
+ "price_registry": "0x2F4ACd1f8986c6B1788159C4c9a5fC3fceCCE363",
+ "wrapped_native": "0x18c8a7ec7897177E4529065a7E7B0878358B3BfF",
+ "src_contracts": {
+ "Arbitrum Sepolia": {
+ "on_ramp": "0x473b49fb592B54a4BfCD55d40E048431982879C9",
+ "deployed_at": 9718588
+ },
+ "Avalanche Fuji": {
+ "on_ramp": "0x610F76A35E17DA4542518D85FfEa12645eF111Fc",
+ "deployed_at": 9718676
+ },
+ "BSC Testnet": {
+ "on_ramp": "0xE48E6AA1fc7D0411acEA95F8C6CaD972A37721D4",
+ "deployed_at": 9718302
+ },
+ "Base Sepolia": {
+ "on_ramp": "0x41b4A51cAfb699D9504E89d19D71F92E886028a8",
+ "deployed_at": 9718513
+ },
+ "Optimism Sepolia": {
+ "on_ramp": "0xAae733212981e06D9C978Eb5148F8af03F54b6EF",
+ "deployed_at": 9718420
+ },
+ "Polygon Amoy": {
+ "on_ramp": "0x01800fCDd892e37f7829937271840A6F041bE62E",
+ "deployed_at": 9718194
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0x4ac7FBEc2A7298AbDf0E0F4fDC45015836C4bAFe",
+ "deployed_at": 8487681
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Sepolia": {
+ "off_ramp": "0x9aA82DBB53bf02096B771D40e9432A323a78fB26",
+ "commit_store": "0x5CdbA91aBC0cD81FC56bc10Ad1835C9E5fB38e5F",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Fuji": {
+ "off_ramp": "0x3e33290B90fD0FF30a3FA138934DF028E4eCA348",
+ "commit_store": "0xCFe3556Aa42d40be09BD23aa80448a19443BE5B1",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Testnet": {
+ "off_ramp": "0xbc4AD54e91b213D4279af92c0C5518c0b96cf62D",
+ "commit_store": "0xff84e8Dd4Fd17eaBb23b6AeA6e1981830e54389C",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Sepolia": {
+ "off_ramp": "0x4117953A5ceeF12f5B8C1E973b470ab83a8CebA6",
+ "commit_store": "0x94ad41296186E81f31e1ed0B1BcF5fa9e1721C27",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Sepolia": {
+ "off_ramp": "0x33d2898F8fb7714FD1661791766f40754982a343",
+ "commit_store": "0x55d6Df194472f02CD481e506A277c4A29D0D1bCc",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Amoy": {
+ "off_ramp": "0x450543b1d85ca79885851D7b74dc982981b78229",
+ "commit_store": "0x23B79d940A769FE31b4C867A8BAE80117f24Ca81",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0xbf9036529123DE264bFA0FC7362fE25B650D4B16",
+ "commit_store": "0x5f7F1abD5c5EdaF2636D58B980e85355AF0Ef80d",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Kroma Sepolia": {
+ "is_native_fee_token": true,
+ "fee_token": "0xa75cCA5b404ec6F4BB6EC4853D177FE7057085c8",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x1E4e4e0d6f6631A45C616F71a1A5cF208DB9eCDe",
+ "router": "0xA8C0c11bf64AF62CDCA6f93D3769B88BdD7cb93D",
+ "price_registry": "0xa1ed3A3aA29166C9c8448654A8cA6b7916BC8379",
+ "wrapped_native": "0x4200000000000000000000000000000000000001",
+ "src_contracts": {
+ "WeMix Testnet": {
+ "on_ramp": "0x6ea155Fc77566D9dcE01B8aa5D7968665dc4f0C5",
+ "deployed_at": 10290904
+ }
+ },
+ "dest_contracts": {
+ "WeMix Testnet": {
+ "off_ramp": "0xB602B6E5Caf08ac0C920EAE585aed100a8cF6f3B",
+ "commit_store": "0x89D5b13908b9063abCC6791dc724bF7B7c93634C",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Optimism Sepolia": {
+ "is_native_fee_token": true,
+ "fee_token": "0xE4aB69C077896252FAFBD49EFD26B5D171A32410",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0xf06Ff5D2084295909119ca541E93635E7D582FFc",
+ "router": "0x114A20A10b43D4115e5aeef7345a1A71d2a60C57",
+ "price_registry": "0x782a7Ba95215f2F7c3dD4C153cbB2Ae3Ec2d3215",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Arbitrum Sepolia": {
+ "on_ramp": "0x1a86b29364D1B3fA3386329A361aA98A104b2742",
+ "deployed_at": 10841494
+ },
+ "Avalanche Fuji": {
+ "on_ramp": "0x6b38CC6Fa938D5AB09Bdf0CFe580E226fDD793cE",
+ "deployed_at": 8677537
+ },
+ "Base Sepolia": {
+ "on_ramp": "0xe284D2315a28c4d62C419e8474dC457b219DB969",
+ "deployed_at": 7130524
+ },
+ "Gnosis Chiado": {
+ "on_ramp": "0x835a5b8e6CA17c2bB5A336c93a4E22478E6F1C8A",
+ "deployed_at": 11799783
+ },
+ "Polygon Amoy": {
+ "on_ramp": "0x2Cf26fb01E9ccDb831414B766287c0A9e4551089",
+ "deployed_at": 10813146
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0xC8b93b46BF682c39B3F65Aa1c135bC8A95A5E43a",
+ "deployed_at": 12165583
+ },
+ "WeMix Testnet": {
+ "on_ramp": "0xc7E53f6aB982af7A7C3e470c8cCa283d3399BDAd",
+ "deployed_at": 8733017
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Sepolia": {
+ "off_ramp": "0xDc2c7A3d8068C6F09F0F3648d24C84e372F6014d",
+ "commit_store": "0xb1aFb5cbE3c29b5Db71F21442BA9EfD450BC23C3",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Fuji": {
+ "off_ramp": "0x1F350718e015EB20E5065C09F4A7a3f66888aEeD",
+ "commit_store": "0x98650A8EB59f75D93563aB34FcF603b1A30e4CBF",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Sepolia": {
+ "off_ramp": "0x0a750ca77369e03613d7640548F4b2b1c695c3Bb",
+ "commit_store": "0x8fEBC74C26129C8d7E60288C6dCCc75eb494aA3C",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Gnosis Chiado": {
+ "off_ramp": "0xCE2CE7F940B7c839384e5D7e079A6aE80e8AD6dB",
+ "commit_store": "0x1b9D78Ec1CEEC439F0b7eA6C428A1a607D9FA7e4",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Amoy": {
+ "off_ramp": "0xD667b5706592D0b040C78fEe5EE17D243b7dCB41",
+ "commit_store": "0x96101BA5250EE9295c193693C1e08A55bC593664",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0x260AF9b83e0d2Bb6C9015fC9f0BfF8858A0CCE68",
+ "commit_store": "0x7a0bB92Bc8663abe6296d0162A9b41a2Cb2E0358",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Testnet": {
+ "off_ramp": "0x9C08B7712af0344188aa5087D9e6aD0f47191037",
+ "commit_store": "0x4BE6DB0B884169a6A207fe5cad01eB4C025a13dB",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Polygon Amoy": {
+ "is_native_fee_token": true,
+ "fee_token": "0x0Fd9e8d3aF1aaee056EB9e802c3A762a667b1904",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x50b023c5b33AEe5Adef15C2E95C2fEC690a52fa1",
+ "router": "0x9C32fCB86BF0f4a1A8921a9Fe46de3198bb884B2",
+ "price_registry": "0xfb2f2A207dC428da81fbAFfDDe121761f8Be1194",
+ "wrapped_native": "0x360ad4f9a9A8EFe9A8DCB5f461c4Cc1047E1Dcf9",
+ "src_contracts": {
+ "Avalanche Fuji": {
+ "on_ramp": "0x8Fb98b3837578aceEA32b454f3221FE18D7Ce903",
+ "deployed_at": 6004551
+ },
+ "BSC Testnet": {
+ "on_ramp": "0xC6683ac4a0F62803Bec89a5355B36495ddF2C38b",
+ "deployed_at": 6005330
+ },
+ "Gnosis Chiado": {
+ "on_ramp": "0x2331F6D614C9Fd613Ff59a1aB727f1EDf6c37A68",
+ "deployed_at": 6897885
+ },
+ "Optimism Sepolia": {
+ "on_ramp": "0xA52cDAeb43803A80B3c0C2296f5cFe57e695BE11",
+ "deployed_at": 6004902
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0x35347A2fC1f2a4c5Eae03339040d0b83b09e6FDA",
+ "deployed_at": 6004056
+ },
+ "WeMix Testnet": {
+ "on_ramp": "0x26546096F64B5eF9A1DcDAe70Df6F4f8c2E10C61",
+ "deployed_at": 6005611
+ }
+ },
+ "dest_contracts": {
+ "Avalanche Fuji": {
+ "off_ramp": "0xa733ce82a84335b2E9D864312225B0F3D5d80600",
+ "commit_store": "0x09B0F93fC2111aE439e853884173AC5b2F809885",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Testnet": {
+ "off_ramp": "0x948dfaa4842fc23e0e362Fe8D4396AaE4E6DF7EA",
+ "commit_store": "0x7F4e739D40E58BBd59dAD388171d18e37B26326f",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Gnosis Chiado": {
+ "off_ramp": "0x17c542a28e08AEF5697251601C7b2B621d153D42",
+ "commit_store": "0x811250c20fAB9a1b7ca245453aC214ba637fBEB5",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Sepolia": {
+ "off_ramp": "0xfFdE9E8c34A27BEBeaCcAcB7b3044A0A364455C9",
+ "commit_store": "0x74ED442ad211050e9C05Dc9A267E037E3d74A03B",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0xFb04129aD1EEDB741CC705ebC1978a7aB63e51f6",
+ "commit_store": "0x63f875240149d29136053C954Ca164a9BfA81F77",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Testnet": {
+ "off_ramp": "0xdE8451E952Eb43350614839cCAA84f7C8701a09C",
+ "commit_store": "0xaCdaBa07ECad81dc634458b98673931DD9d3Bc14",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "Sepolia Testnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x779877A7B0D9E8603169DdbD7836e478b4624789",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0xB4d360459F32Dd641Ef5A6985fFbAC5c4e5521aA",
+ "router": "0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59",
+ "price_registry": "0x9EF7D57a4ea30b9e37794E55b0C75F2A70275dCc",
+ "wrapped_native": "0x097D90c9d3E0B50Ca60e1ae45F6A81010f9FB534",
+ "src_contracts": {
+ "Arbitrum Sepolia": {
+ "on_ramp": "0xe4Dd3B16E09c016402585a8aDFdB4A18f772a07e",
+ "deployed_at": 5737506
+ },
+ "Avalanche Fuji": {
+ "on_ramp": "0x0477cA0a35eE05D3f9f424d88bC0977ceCf339D4",
+ "deployed_at": 5944649
+ },
+ "BSC Testnet": {
+ "on_ramp": "0xD990f8aFA5BCB02f95eEd88ecB7C68f5998bD618",
+ "deployed_at": 5383500
+ },
+ "Base Sepolia": {
+ "on_ramp": "0x2B70a05320cB069e0fB55084D402343F832556E7",
+ "deployed_at": 5619657
+ },
+ "Gnosis Chiado": {
+ "on_ramp": "0x3E842E3A79A00AFdd03B52390B1caC6306Ea257E",
+ "deployed_at": 5386355
+ },
+ "Optimism Sepolia": {
+ "on_ramp": "0x69CaB5A0a08a12BaFD8f5B195989D709E396Ed4d",
+ "deployed_at": 5937506
+ },
+ "Polygon Amoy": {
+ "on_ramp": "0x9f656e0361Fb5Df2ac446102c8aB31855B591692",
+ "deployed_at": 5723315
+ },
+ "WeMix Testnet": {
+ "on_ramp": "0xedFc22336Eb0B9B11Ff37C07777db27BCcDe3C65",
+ "deployed_at": 5393931
+ },
+ "celo-testnet-alfajores": {
+ "on_ramp": "0x3C86d16F52C10B2ff6696a0e1b8E0BcfCC085948",
+ "deployed_at": 5704643
+ },
+ "ethereum-testnet-sepolia-blast-1": {
+ "on_ramp": "0xDB75E9D9ca7577CcBd7232741be954cf26194a66",
+ "deployed_at": 6040848
+ },
+ "ethereum-testnet-sepolia-metis-1": {
+ "on_ramp": "0x1C4640914cd57c5f02a68048A0fbb0E12d904223",
+ "deployed_at": 6002793
+ },
+ "ethereum-testnet-sepolia-mode-1": {
+ "on_ramp": "0xc630fbD4D0F6AEB00aD0793FB827b54fBB78e981",
+ "deployed_at": 5970819
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Sepolia": {
+ "off_ramp": "0xF18896AB20a09A29e64fdEbA99FDb8EC328f43b1",
+ "commit_store": "0x93Ff9Dd39Dc01eac1fc4d2c9211D95Ee458CAB94",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Fuji": {
+ "off_ramp": "0x000b26f604eAadC3D874a4404bde6D64a97d95ca",
+ "commit_store": "0x2dD9273F8208B8393350508131270A6574A69784",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Testnet": {
+ "off_ramp": "0xdE2d8E126e08d675fCD7fFa5a6CE49925f3Dc692",
+ "commit_store": "0x0050ac355a82caB31194507f94174297bf0655A7",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Base Sepolia": {
+ "off_ramp": "0x31c0B81832B333419f0DfD36A69F502cF9094aed",
+ "commit_store": "0xDFcde9d698a2B32DB2537DC9B752Cadd1D846a52",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Gnosis Chiado": {
+ "off_ramp": "0x7db0115A0b3AAb01d30bf81123c5DD7B0C41Add5",
+ "commit_store": "0x6640723Ea801178c4383FA016b9781e7ef1016EF",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Sepolia": {
+ "off_ramp": "0xD50590D4438411EDe47029b0FD7901A7145E5Df6",
+ "commit_store": "0xe85EEE9Fd434A7b8a586Ee086E828abF41839479",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Amoy": {
+ "off_ramp": "0x5032cbC0C4aEeD25bb6E45D8B3fAF05DB0688C5d",
+ "commit_store": "0xe6201C9996Cc7B6E828E10CbE937E693d577D318",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "WeMix Testnet": {
+ "off_ramp": "0x46b639a3C1a4CBfD326b94a2dB7415c27157282f",
+ "commit_store": "0x7b74554678816b045c1e7409327E086bD436aa46",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "celo-testnet-alfajores": {
+ "off_ramp": "0xB435E0f73c18C5a12C324CA1d02F81F2C3e6e761",
+ "commit_store": "0xbc5d74957F171e75F92c8F0E1C317A25a56a416D",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "ethereum-testnet-sepolia-blast-1": {
+ "off_ramp": "0x4e897e5cF3aC307F0541B2151A88bCD781c153a3",
+ "commit_store": "0xB656652841F347178e193951C4663652aCe36B74",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "ethereum-testnet-sepolia-metis-1": {
+ "off_ramp": "0x4DB693A93E9d5196ECD42EC56CDEAe99dFC652ED",
+ "commit_store": "0xBfACd78F1412B6f93Ac23409bf456aFec1ABd845",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "ethereum-testnet-sepolia-mode-1": {
+ "off_ramp": "0xbEfd8D65F6643De54F0b1268A3bf4618ff85dcB4",
+ "commit_store": "0x0C161D3470b45Cc677661654C30ce4AdE6aCD288",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "WeMix Testnet": {
+ "is_native_fee_token": true,
+ "fee_token": "0x3580c7A817cCD41f7e02143BFa411D4EeAE78093",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x46fF31494651593973D9b38a872ED5B06f45A693",
+ "router": "0xA8C0c11bf64AF62CDCA6f93D3769B88BdD7cb93D",
+ "price_registry": "0x89D17571DB7C9540eeB36760E3c749C8fb984569",
+ "wrapped_native": "0xbE3686643c05f00eC46e73da594c78098F7a9Ae7",
+ "src_contracts": {
+ "Arbitrum Sepolia": {
+ "on_ramp": "0xA9DE3F7A617D67bC50c56baaCb9E0373C15EbfC6",
+ "deployed_at": 51216113
+ },
+ "Avalanche Fuji": {
+ "on_ramp": "0xC4aC84da458ba8e40210D2dF94C76E9a41f70069",
+ "deployed_at": 51214769
+ },
+ "BSC Testnet": {
+ "on_ramp": "0x5AD6eed6Be0ffaDCA4105050CF0E584D87E0c2F1",
+ "deployed_at": 51213771
+ },
+ "Kroma Sepolia": {
+ "on_ramp": "0x428C4dc89b6Bf908B82d77C9CBceA786ea8cc7D0",
+ "deployed_at": 51239062
+ },
+ "Optimism Sepolia": {
+ "on_ramp": "0x1961a7De751451F410391c251D4D4F98D71B767D",
+ "deployed_at": 51216748
+ },
+ "Polygon Amoy": {
+ "on_ramp": "0xd55148e841e76265B484d399eC71b7076ecB1216",
+ "deployed_at": 55378685
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0x4d57C6d8037C65fa66D6231844785a428310a735",
+ "deployed_at": 51239309
+ }
+ },
+ "dest_contracts": {
+ "Arbitrum Sepolia": {
+ "off_ramp": "0xeB1dFaB2464Bf0574D43e764E0c758f92e7ecAFb",
+ "commit_store": "0xcEaCa2B7890065c485f3E58657358a185Ad33791",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Avalanche Fuji": {
+ "off_ramp": "0x98e811Df9D2512f1aaf58D534607F583D6c54A4F",
+ "commit_store": "0x8e538351F6E5B2daF3c90C565C3738bca69a2716",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "BSC Testnet": {
+ "off_ramp": "0xB0e7f0fCcD3c961C473E7c44D939C1cDb4Cec1cB",
+ "commit_store": "0x4B56D8d53f1A6e0117B09700067De99581aA5542",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Kroma Sepolia": {
+ "off_ramp": "0xD685D2d224dd6D0Db2D56497db6270D77D9a7966",
+ "commit_store": "0x7e062D6880779a0347e7742058C1b1Ee4AA0B137",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Optimism Sepolia": {
+ "off_ramp": "0xA5f97Bc69Bf06e7C37B93265c5457420A92c5F4b",
+ "commit_store": "0xd48b9213583074f518D8f4336FDf35370D450132",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Polygon Amoy": {
+ "off_ramp": "0x6c8f5999B06FDE17B11E4e3C1062b761766F960f",
+ "commit_store": "0x957c3c2056192e58A8485eF31165fC490d474239",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0x8AB103843ED9D28D2C5DAf5FdB9c3e1CE2B6c876",
+ "commit_store": "0x7d5297c5506ee2A7Ef121Da9bE02b6a6AD30b392",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "celo-testnet-alfajores": {
+ "is_native_fee_token": true,
+ "fee_token": "0x32E08557B14FaD8908025619797221281D439071",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0xbE8FD4b84ca8CC2cFAeeEf8dc1388E44860eeEeb",
+ "router": "0xb00E95b773528E2Ea724DB06B75113F239D15Dca",
+ "price_registry": "0x8F048206D11B2c69b8963E2EBd5968D141e022f4",
+ "wrapped_native": "0x99604d0e2EfE7ABFb58BdE565b5330Bb46Ab3Dca",
+ "src_contracts": {
+ "Sepolia Testnet": {
+ "on_ramp": "0x16a020c4bbdE363FaB8481262D30516AdbcfcFc8",
+ "deployed_at": 23561364
+ }
+ },
+ "dest_contracts": {
+ "Sepolia Testnet": {
+ "off_ramp": "0xa1b97F92D806BA040daf419AFC2765DC723683a4",
+ "commit_store": "0xcd92C0599Ac515e7588865cC45Eee21A74816aFc",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "ethereum-testnet-sepolia-blast-1": {
+ "is_native_fee_token": true,
+ "fee_token": "0x02c359ebf98fc8BF793F970F9B8302bb373BdF32",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x9C32fCB86BF0f4a1A8921a9Fe46de3198bb884B2",
+ "router": "0xfb2f2A207dC428da81fbAFfDDe121761f8Be1194",
+ "price_registry": "0xc8acE9dF450FaD007755C6C9AB4f0e9c8626E29C",
+ "wrapped_native": "0x4200000000000000000000000000000000000023",
+ "src_contracts": {
+ "Sepolia Testnet": {
+ "on_ramp": "0x85Ef19FC4C63c70744995DC38CAAEC185E0c619f",
+ "deployed_at": 6429339
+ }
+ },
+ "dest_contracts": {
+ "Sepolia Testnet": {
+ "off_ramp": "0x92cD24C278D34C726f377703E50875d8f9535dC2",
+ "commit_store": "0xcE1b4D50CeD56850182Bd58Ace91171cB249B873",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "ethereum-testnet-sepolia-metis-1": {
+ "is_native_fee_token": true,
+ "fee_token": "0x9870D6a0e05F867EAAe696e106741843F7fD116D",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x26546096F64B5eF9A1DcDAe70Df6F4f8c2E10C61",
+ "router": "0xaCdaBa07ECad81dc634458b98673931DD9d3Bc14",
+ "price_registry": "0x5DCE866b3ae6E0Ed153f0e149D7203A1B266cdF5",
+ "wrapped_native": "0x5c48e07062aC4E2Cf4b9A768a711Aef18e8fbdA0",
+ "src_contracts": {
+ "Sepolia Testnet": {
+ "on_ramp": "0x2Eff2d1BF5C557d6289D208a7a43608f5E3FeCc2",
+ "deployed_at": 858864
+ }
+ },
+ "dest_contracts": {
+ "Sepolia Testnet": {
+ "off_ramp": "0x9Bb7e398ef9Acfe9cA584C39B1E233Cba62BB9f7",
+ "commit_store": "0x1F4B82cDebaC5e3a0Dd53183D47e51808B4a64cB",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ },
+ "ethereum-testnet-sepolia-mode-1": {
+ "is_native_fee_token": true,
+ "fee_token": "0x925a4bfE64AE2bFAC8a02b35F78e60C29743755d",
+ "bridge_tokens": [
+ ],
+ "bridge_tokens_pools": [
+ ],
+ "price_aggregators": null,
+ "arm": "0x11545812A8d64e4A3A0Ec36b6F70D87b42Ce4a01",
+ "router": "0xc49ec0eB4beb48B8Da4cceC51AA9A5bD0D0A4c43",
+ "price_registry": "0xa733ce82a84335b2E9D864312225B0F3D5d80600",
+ "wrapped_native": "0x4200000000000000000000000000000000000006",
+ "src_contracts": {
+ "Base Sepolia": {
+ "on_ramp": "0x73f7E074bd7291706a0C5412f51DB46441B1aDCB",
+ "deployed_at": 14359909
+ },
+ "Sepolia Testnet": {
+ "on_ramp": "0xfFdE9E8c34A27BEBeaCcAcB7b3044A0A364455C9",
+ "deployed_at": 14359680
+ }
+ },
+ "dest_contracts": {
+ "Base Sepolia": {
+ "off_ramp": "0x137a38c6b1Ad20101F93516aB2159Df525309168",
+ "commit_store": "0x8F43d867969F14619895d71E0A5b89E0bb20bF70",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ },
+ "Sepolia Testnet": {
+ "off_ramp": "0xcD44cec849B6a8eBd5551D6DFeEcA452257Dfe4d",
+ "commit_store": "0xbA66f08733E6715D33edDfb5a5947676bb45d0e0",
+ "receiver_dapp": "0x1A2A69e3eB1382FE34Bc579AdD5Bae39e31d4A2c"
+ }
+ }
+ }
+ }
+}
+"""
+
+[CCIP.Env]
+TTL = '8h'
+
+[CCIP.Env.Network]
+selected_networks = [
+ 'ARBITRUM_SEPOLIA',
+ 'AVALANCHE_FUJI',
+ 'OPTIMISM_SEPOLIA',
+ 'BASE_SEPOLIA',
+ 'BSC_TESTNET',
+ 'WEMIX_TESTNET',
+ 'SEPOLIA',
+ 'POLYGON_AMOY',
+ 'KROMA_SEPOLIA',
+ 'BLAST_SEPOLIA'
+]
+
+[CCIP.Groups.load]
+NetworkPairs = [
+ 'AVALANCHE_FUJI,SEPOLIA',
+ 'OPTIMISM_SEPOLIA,BASE_SEPOLIA'
+]
+
+BiDirectionalLane = true
+PhaseTimeout = '45m'
+ExistingDeployment = true
+
+NoOfTokensPerChain = 1
+
+[CCIP.Groups.load.LoadProfile]
+RequestPerUnitTime = [1]
+TimeUnit = '5s'
+TestDuration = '1h'
+TestRunName = 'v2.12.0-ccip1.4.16-load'
+
+# to represent 20%, 60%, 15%, 5% of the total messages
+[CCIP.Groups.load.LoadProfile.MsgProfile]
+Frequencies = [4,12,3,1]
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Token'
+DestGasLimit = 0
+DataLength = 0
+NoOfTokens = 5
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'DataWithToken'
+DestGasLimit = 500000
+DataLength = 5000
+NoOfTokens = 5
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 800000
+DataLength = 10000
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 2500000
+DataLength = 10000
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/sample-scalability.toml b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/sample-scalability.toml
new file mode 100644
index 00000000000..872a6ae565c
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/sample-scalability.toml
@@ -0,0 +1,129 @@
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+[CCIP.Env]
+TTL = '15h'
+
+[CCIP.Env.Network]
+selected_networks= ['PRIVATE-CHAIN-1', 'PRIVATE-CHAIN-2']
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-1]
+evm_name = 'private-chain-1'
+evm_chain_id = 2337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-2]
+evm_name = 'private-chain-2'
+evm_chain_id = 1337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1
+
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-1]
+block_time = 1
+#
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-2]
+block_time = 1
+
+[CCIP.Env.NewCLCluster]
+NoOfNodes = 17
+NodeMemory = '12Gi'
+NodeCPU = '6'
+DBMemory = '10Gi'
+DBCPU = '2'
+DBStorageClass = 'gp3'
+PromPgExporter = true
+DBCapacity = '50Gi'
+IsStateful = true
+DBArgs = ['shared_buffers=2048MB', 'effective_cache_size=4096MB', 'work_mem=64MB']
+
+#[CCIP.Env.NewCLCluster.Common]
+#CommonChainConfigTOML = """
+#[HeadTracker]
+#HistoryDepth = 3000
+#
+#[GasEstimator]
+#PriceMax = '200 gwei'
+#LimitDefault = 6000000
+#FeeCapDefault = '200 gwei'
+#"""
+
+[CCIP.Groups]
+[CCIP.Groups.load]
+KeepEnvAlive = true
+NoOfCommitNodes = 16
+PhaseTimeout = '40m'
+NodeFunding = 1000.0
+NoOfRoutersPerPair = 2
+NoOfNetworks = 40
+MaxNoOfLanes = 200
+
+[CCIP.Groups.load.OffRampConfig]
+BatchGasLimit = 11000000
+
+[CCIP.Groups.load.TokenConfig]
+TimeoutForPriceUpdate = '15m'
+NoOfTokensPerChain = 60
+NoOfTokensWithDynamicPrice = 15
+DynamicPriceUpdateInterval ='15s'
+CCIPOwnerTokens = true
+
+[CCIP.Groups.load.LoadProfile]
+TestDuration = '4h'
+TimeUnit = '5s'
+RequestPerUnitTime = [1]
+OptimizeSpace = true
+NetworkChaosDelay = '100ms'
+
+# to represent 20%, 60%, 15%, 5% of the total messages
+[CCIP.Groups.load.LoadProfile.MsgProfile]
+Frequencies = [4,12,3,1]
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Token'
+DestGasLimit = 0
+DataLength = 0
+NoOfTokens = 5
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'DataWithToken'
+DestGasLimit = 500000
+DataLength = 5000
+NoOfTokens = 5
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 800000
+DataLength = 10000
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 2500000
+DataLength = 10000
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/tier-a.toml b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/tier-a.toml
new file mode 100644
index 00000000000..5270de7f6d4
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/tier-a.toml
@@ -0,0 +1,240 @@
+## Baseline performance test on simulated environment (with chaos)
+## 40 chains / 400 lanes
+## historyDepth 200 / finalityDepth 200
+## block_time = 1s
+## throughput 1msg / 5s
+## 20% Token, 60% DataWithToken, 15% Regular size msgs, 5% Large msgs
+##
+## make test_load_ccip testimage=.dkr.ecr..amazonaws.com/chainlink-ccip-tests:ccip-develop \
+## testname=TestLoadCCIPStableRequestTriggeringWithNetworkChaos \
+## override_toml=./testconfig/tomls/ccip1.4-stress/tier-a.toml \
+## secret_toml=./testconfig/tomls/secrets.toml
+
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+[CCIP.Env]
+TTL = '8h'
+
+[CCIP.Env.Network]
+selected_networks= ['PRIVATE-CHAIN-1', 'SLOW-CHAIN-1', 'SLOW-CHAIN-2', 'SLOW-CHAIN-3']
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-1]
+evm_name = 'private-chain-1'
+evm_chain_id = 2337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1
+
+[CCIP.Env.Network.EVMNetworks.SLOW-CHAIN-1]
+evm_name = 'slow-chain-1'
+evm_chain_id = 90000001
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1
+
+[CCIP.Env.Network.EVMNetworks.SLOW-CHAIN-2]
+evm_name = 'slow-chain-2'
+evm_chain_id = 90000002
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1
+
+[CCIP.Env.Network.EVMNetworks.SLOW-CHAIN-3]
+evm_name = 'slow-chain-3'
+evm_chain_id = 1337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1
+
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-1]
+block_time = 2
+
+#
+[CCIP.Env.Network.AnvilConfigs.SLOW-CHAIN-1]
+block_time = 12
+
+[CCIP.Env.Network.AnvilConfigs.SLOW-CHAIN-2]
+block_time = 12
+
+[CCIP.Env.Network.AnvilConfigs.SLOW-CHAIN-3]
+block_time = 12
+
+[CCIP.Env.NewCLCluster]
+NoOfNodes = 17
+NodeMemory = '10Gi'
+NodeCPU = '6'
+DBMemory = '16Gi'
+DBCPU = '4'
+DBStorageClass = 'gp3'
+PromPgExporter = true
+DBCapacity = '50Gi'
+IsStateful = true
+DBArgs = ['shared_buffers=4096MB', 'effective_cache_size=8192MB', 'work_mem=128MB']
+
+[CCIP.Env.NewCLCluster.Common]
+BaseConfigTOML = """
+[Feature]
+LogPoller = true
+CCIP = true
+
+[Log]
+Level = 'debug'
+JSONConsole = true
+
+[Log.File]
+MaxSize = '0b'
+
+[WebServer]
+AllowOrigins = '*'
+HTTPPort = 6688
+SecureCookies = false
+HTTPWriteTimeout = '1m'
+
+[WebServer.RateLimit]
+Authenticated = 2000
+Unauthenticated = 1000
+
+[WebServer.TLS]
+HTTPSPort = 0
+
+[Database]
+MaxIdleConns = 20
+MaxOpenConns = 30
+MigrateOnStartup = true
+
+[OCR2]
+Enabled = true
+DefaultTransactionQueueDepth = 0
+
+[OCR]
+Enabled = false
+DefaultTransactionQueueDepth = 0
+
+[P2P]
+[P2P.V2]
+Enabled = true
+ListenAddresses = ['0.0.0.0:6690']
+AnnounceAddresses = ['0.0.0.0:6690']
+DeltaDial = '500ms'
+DeltaReconcile = '5s'
+"""
+
+#CommonChainConfigTOML = """
+#[HeadTracker]
+#HistoryDepth = 200
+#
+#[GasEstimator]
+#PriceMax = '200 gwei'
+#LimitDefault = 6000000
+#FeeCapDefault = '200 gwei'
+#"""
+
+[CCIP.Groups]
+[CCIP.Groups.load]
+DenselyConnectedNetworkChainIds = ['90000001', '90000002', '1337']
+KeepEnvAlive = true
+NoOfCommitNodes = 16
+PhaseTimeout = '40m'
+NodeFunding = 1000.0
+NoOfRoutersPerPair = 2
+NoOfNetworks = 40
+MaxNoOfLanes = 400
+
+[CCIP.Groups.load.OffRampConfig]
+BatchGasLimit = 11000000
+
+[CCIP.Groups.load.TokenConfig]
+TimeoutForPriceUpdate = '15m'
+NoOfTokensPerChain = 60
+NoOfTokensWithDynamicPrice = 15
+DynamicPriceUpdateInterval ='5m'
+CCIPOwnerTokens = true
+
+[CCIP.Groups.load.LoadProfile]
+TestDuration = '4h'
+OptimizeSpace = true
+NetworkChaosDelay = '100ms'
+TimeUnit = '5s'
+RequestPerUnitTime = [1]
+
+[CCIP.Groups.load.LoadProfile.LoadFrequency.slow-chain-1]
+TimeUnit = '10s'
+RequestPerUnitTime = [1]
+
+[CCIP.Groups.load.LoadProfile.LoadFrequency.slow-chain-2]
+TimeUnit = '10s'
+RequestPerUnitTime = [1]
+
+[CCIP.Groups.load.LoadProfile.LoadFrequency.slow-chain-3]
+TimeUnit = '10s'
+RequestPerUnitTime = [1]
+
+# to represent 20%, 60%, 15%, 5% of the total messages
+[CCIP.Groups.load.LoadProfile.MsgProfile]
+Frequencies = [4,12,3,1]
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Token'
+DestGasLimit = 0
+DataLength = 0
+NoOfTokens = 5
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'DataWithToken'
+DestGasLimit = 500000
+DataLength = 5000
+NoOfTokens = 5
+AmountPerToken = 1
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 800000
+DataLength = 10000
+
+[[CCIP.Groups.load.LoadProfile.MsgProfile.MsgDetails]]
+MsgType = 'Data'
+DestGasLimit = 2500000
+DataLength = 10000
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/tier-b.toml b/integration-tests/ccip-tests/testconfig/tomls/ccip1.4-stress/tier-b.toml
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/integration-tests/ccip-tests/testconfig/tomls/contract-version1.4.toml b/integration-tests/ccip-tests/testconfig/tomls/contract-version1.4.toml
new file mode 100644
index 00000000000..392b058e5c8
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/contract-version1.4.toml
@@ -0,0 +1,13 @@
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+[CCIP.Groups.smoke.TokenConfig]
+CCIPOwnerTokens = true
+
+[CCIP.Groups.load.TokenConfig]
+CCIPOwnerTokens = true
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/db-compatibility.toml b/integration-tests/ccip-tests/testconfig/tomls/db-compatibility.toml
new file mode 100644
index 00000000000..9de5925cb11
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/db-compatibility.toml
@@ -0,0 +1,34 @@
+[CCIP]
+[CCIP.Env]
+[CCIP.Env.NewCLCluster]
+NoOfNodes = 6
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node1'
+DBImage = 'postgres'
+DBTag = '13.14'
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node2'
+DBImage = 'postgres'
+DBTag = '12.18'
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node3'
+DBImage = 'postgres'
+DBTag = '14.11'
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node4'
+DBImage = 'postgres'
+DBTag = '14.8'
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node5'
+DBImage = 'postgres'
+DBTag = '15.6'
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node6'
+DBImage = 'postgres'
+DBTag = '15.6'
diff --git a/integration-tests/ccip-tests/testconfig/tomls/leader-lane.toml b/integration-tests/ccip-tests/testconfig/tomls/leader-lane.toml
new file mode 100644
index 00000000000..76b97ad97ba
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/leader-lane.toml
@@ -0,0 +1,4 @@
+[CCIP]
+[CCIP.Groups.smoke]
+NoOfNetworks = 4
+NoOfRoutersPerPair = 2
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/load-with-arm-curse-uncurse.toml b/integration-tests/ccip-tests/testconfig/tomls/load-with-arm-curse-uncurse.toml
new file mode 100644
index 00000000000..e49f1184af7
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/load-with-arm-curse-uncurse.toml
@@ -0,0 +1,20 @@
+[CCIP]
+[CCIP.Env]
+TTL = '15h'
+
+[CCIP.Groups]
+[CCIP.Groups.load]
+KeepEnvAlive = true
+PhaseTimeout = '50m'
+NodeFunding = 1000.0
+
+
+[CCIP.Groups.load.LoadProfile]
+RequestPerUnitTime = [1]
+TimeUnit = '1m'
+TestDuration = '30m'
+SendMaxDataInEveryMsgCount = 0
+
+
+
+
diff --git a/integration-tests/ccip-tests/testconfig/tomls/node-post-upgrade-compatibility.toml b/integration-tests/ccip-tests/testconfig/tomls/node-post-upgrade-compatibility.toml
new file mode 100644
index 00000000000..c1c6c651442
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/node-post-upgrade-compatibility.toml
@@ -0,0 +1,45 @@
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+[CCIP.Deployments]
+DataFile = 'lane-config/.*.json'
+
+[CCIP.Env]
+[CCIP.Env.NewCLCluster]
+NoOfNodes = 6
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node-1'
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node-2'
+NeedsUpgrade = true
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node-3'
+NeedsUpgrade = true
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node-4'
+NeedsUpgrade = true
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node-5'
+NeedsUpgrade = true
+
+[[CCIP.Env.NewCLCluster.Nodes]]
+Name = 'node-6'
+NeedsUpgrade = true
+
+[CCIP.Groups]
+[CCIP.Groups.load]
+LocalCluster = false
+ExistingDeployment = true
+
+[CCIP.Groups.load.LoadProfile]
+TestRunName = 'upgrade-test'
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/node-pre-upgrade-compatibility.toml b/integration-tests/ccip-tests/testconfig/tomls/node-pre-upgrade-compatibility.toml
new file mode 100644
index 00000000000..36ada834193
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/node-pre-upgrade-compatibility.toml
@@ -0,0 +1,13 @@
+[CCIP]
+[CCIP.ContractVersions]
+PriceRegistry = '1.2.0'
+OffRamp = '1.2.0'
+OnRamp = '1.2.0'
+TokenPool = '1.4.0'
+CommitStore = '1.2.0'
+
+[CCIP.Groups]
+[CCIP.Groups.smoke]
+LocalCluster = false
+KeepEnvAlive = true
+StoreLaneConfig = true
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/usdc_mock_deployment.toml b/integration-tests/ccip-tests/testconfig/tomls/usdc_mock_deployment.toml
new file mode 100644
index 00000000000..82a3d492163
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/usdc_mock_deployment.toml
@@ -0,0 +1,10 @@
+[CCIP]
+[CCIP.Groups]
+[CCIP.Groups.smoke]
+USDCMockDeployment = true
+
+[CCIP.Groups.smoke.TokenConfig]
+NoOfTokensPerChain = 2
+
+[CCIP.Groups.smoke.MsgDetails]
+NoOfTokens = 3
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testconfig/tomls/varied-block-time-sample.toml b/integration-tests/ccip-tests/testconfig/tomls/varied-block-time-sample.toml
new file mode 100644
index 00000000000..dfe947af115
--- /dev/null
+++ b/integration-tests/ccip-tests/testconfig/tomls/varied-block-time-sample.toml
@@ -0,0 +1,47 @@
+[CCIP]
+[CCIP.Env]
+[CCIP.Env.Network]
+selected_networks= ['PRIVATE-CHAIN-1', 'PRIVATE-CHAIN-2']
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-1]
+evm_name = 'private-chain-1'
+evm_chain_id = 2337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 100 # with 50 blocks of finality, and 12s block time, we have 20 minutes of finality
+
+[CCIP.Env.Network.EVMNetworks.PRIVATE-CHAIN-2]
+evm_name = 'private-chain-2'
+evm_chain_id = 1337
+evm_urls = ['wss://ignore-this-url.com']
+evm_http_urls = ['https://ignore-this-url.com']
+evm_keys = ['ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80']
+evm_simulated = true
+client_implementation = 'Ethereum'
+evm_chainlink_transaction_limit = 5000
+evm_transaction_timeout = '3m'
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 1000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_finality_depth = 1 # with 1 block of finality, and 1s block time, we have instant finality
+
+
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-1]
+block_time = 12
+
+[CCIP.Env.Network.AnvilConfigs.PRIVATE-CHAIN-2]
+block_time = 1
+
+[CCIP.Groups]
+[CCIP.Groups.smoke]
+LocalCluster = false
\ No newline at end of file
diff --git a/integration-tests/ccip-tests/testreporters/ccip.go b/integration-tests/ccip-tests/testreporters/ccip.go
new file mode 100644
index 00000000000..b567f6a6291
--- /dev/null
+++ b/integration-tests/ccip-tests/testreporters/ccip.go
@@ -0,0 +1,476 @@
+package testreporters
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/rs/zerolog"
+ "github.com/slack-go/slack"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/config"
+ "github.com/smartcontractkit/chainlink-testing-framework/testreporters"
+)
+
+type Phase string
+type Status string
+
+const (
+ // These are the different phases of a CCIP transaction lifecycle
+ // You can see an illustration of the flow here: https://docs.chain.link/images/ccip/ccip-diagram-04_v04.webp
+ TX Phase = "CCIP-Send Transaction" // The initial transaction is sent from the client to the OnRamp
+ CCIPSendRe Phase = "CCIPSendRequested" // The OnRamp emits the CCIPSendRequested event which acknowledges the transaction requesting a CCIP transfer
+ SourceLogFinalized Phase = "SourceLogFinalizedTentatively" // The source chain finalizes the transaction where the CCIPSendRequested event was emitted
+ Commit Phase = "Commit-ReportAccepted" // The destination chain commits to the transaction and emits the ReportAccepted event
+ ReportBlessed Phase = "ReportBlessedByARM" // The destination chain emits the ReportBlessed event. This is triggered by the RMN, for tests we usually mock it.
+ E2E Phase = "CommitAndExecute" // This is effectively an alias for the below phase, but it's used to represent the end-to-end flow
+ ExecStateChanged Phase = "ExecutionStateChanged" // The destination chain emits the ExecutionStateChanged event. This indicates that the transaction has been executed
+
+ Success Status = "✅"
+ Failure Status = "❌"
+ Unsure = "⚠️"
+ slackFile string = "payload_ccip.json"
+)
+
+type AggregatorMetrics struct {
+ Min float64 `json:"min_duration_for_successful_requests(s),omitempty"`
+ Max float64 `json:"max_duration_for_successful_requests(s),omitempty"`
+ Avg float64 `json:"avg_duration_for_successful_requests(s),omitempty"`
+ sum float64
+ count int
+}
+type TransactionStats struct {
+ Fee string `json:"fee,omitempty"`
+ MsgID string `json:"msg_id,omitempty"`
+ GasUsed uint64 `json:"gas_used,omitempty"`
+ TxHash string `json:"tx_hash,omitempty"`
+ NoOfTokensSent int `json:"no_of_tokens_sent,omitempty"`
+ MessageBytesLength int64 `json:"message_bytes_length,omitempty"`
+ FinalizedByBlock string `json:"finalized_block_num,omitempty"`
+ FinalizedAt string `json:"finalized_at,omitempty"`
+ CommitRoot string `json:"commit_root,omitempty"`
+}
+
+type PhaseStat struct {
+ SeqNum uint64 `json:"seq_num,omitempty"`
+ Duration float64 `json:"duration,omitempty"`
+ Status Status `json:"success"`
+ SendTransactionStats *TransactionStats `json:"ccip_send_data,omitempty"`
+}
+
+type RequestStat struct {
+ ReqNo int64
+ SeqNum uint64
+ SourceNetwork string
+ DestNetwork string
+ StatusByPhase map[Phase]PhaseStat `json:"status_by_phase,omitempty"`
+}
+
+func (stat *RequestStat) UpdateState(
+ lggr *zerolog.Logger,
+ seqNum uint64,
+ step Phase,
+ duration time.Duration,
+ state Status,
+ sendTransactionStats *TransactionStats,
+) {
+ durationInSec := duration.Seconds()
+ stat.SeqNum = seqNum
+ phaseDetails := PhaseStat{
+ SeqNum: seqNum,
+ Duration: durationInSec,
+ Status: state,
+ SendTransactionStats: sendTransactionStats,
+ }
+
+ event := lggr.Info()
+ if seqNum != 0 {
+ event.Uint64("seq num", seqNum)
+ }
+ // if any of the phase fails mark the E2E as failed
+ if state == Failure || state == Unsure {
+ stat.StatusByPhase[E2E] = PhaseStat{
+ SeqNum: seqNum,
+ Status: state,
+ }
+ stat.StatusByPhase[step] = phaseDetails
+ lggr.Info().
+ Str(fmt.Sprint(E2E), string(state)).
+ Msgf("reqNo %d", stat.ReqNo)
+ event.Str(string(step), string(state)).Msgf("reqNo %d", stat.ReqNo)
+ } else {
+ event.Str(string(step), string(Success)).Msgf("reqNo %d", stat.ReqNo)
+ // we don't want to save phase details for TX and CCIPSendRe to avoid redundancy if these phases are successful
+ if step != TX && step != CCIPSendRe {
+ stat.StatusByPhase[step] = phaseDetails
+ }
+ if step == Commit || step == ReportBlessed || step == ExecStateChanged {
+ stat.StatusByPhase[E2E] = PhaseStat{
+ SeqNum: seqNum,
+ Status: state,
+ Duration: stat.StatusByPhase[step].Duration + stat.StatusByPhase[E2E].Duration,
+ }
+ if step == ExecStateChanged {
+ lggr.Info().
+ Str(fmt.Sprint(E2E), string(Success)).
+ Msgf("reqNo %d", stat.ReqNo)
+ }
+ }
+ }
+}
+
+func NewCCIPRequestStats(reqNo int64, source, dest string) *RequestStat {
+ return &RequestStat{
+ ReqNo: reqNo,
+ StatusByPhase: make(map[Phase]PhaseStat),
+ SourceNetwork: source,
+ DestNetwork: dest,
+ }
+}
+
+type CCIPLaneStats struct {
+ lane string
+ lggr *zerolog.Logger
+ TotalRequests int64 `json:"total_requests,omitempty"` // TotalRequests is the total number of requests made
+ SuccessCountsByPhase map[Phase]int64 `json:"success_counts_by_phase,omitempty"` // SuccessCountsByPhase is the number of requests that succeeded in each phase
+ FailedCountsByPhase map[Phase]int64 `json:"failed_counts_by_phase,omitempty"` // FailedCountsByPhase is the number of requests that failed in each phase
+ DurationStatByPhase map[Phase]AggregatorMetrics `json:"duration_stat_by_phase,omitempty"` // DurationStatByPhase is the duration statistics for each phase
+ statusByPhaseByRequests sync.Map
+}
+
+func (testStats *CCIPLaneStats) UpdatePhaseStatsForReq(stat *RequestStat) {
+ testStats.statusByPhaseByRequests.Store(stat.ReqNo, stat.StatusByPhase)
+}
+
+func (testStats *CCIPLaneStats) Aggregate(phase Phase, durationInSec float64) {
+ if prevDur, ok := testStats.DurationStatByPhase[phase]; !ok {
+ testStats.DurationStatByPhase[phase] = AggregatorMetrics{
+ Min: durationInSec,
+ Max: durationInSec,
+ sum: durationInSec,
+ count: 1,
+ }
+ } else {
+ if prevDur.Min > durationInSec {
+ prevDur.Min = durationInSec
+ }
+ if prevDur.Max < durationInSec {
+ prevDur.Max = durationInSec
+ }
+ prevDur.sum = prevDur.sum + durationInSec
+ prevDur.count++
+ testStats.DurationStatByPhase[phase] = prevDur
+ }
+}
+
+func (testStats *CCIPLaneStats) Finalize(lane string) {
+ phases := []Phase{E2E, TX, CCIPSendRe, SourceLogFinalized, Commit, ReportBlessed, ExecStateChanged}
+ events := make(map[Phase]*zerolog.Event)
+ testStats.statusByPhaseByRequests.Range(func(key, value interface{}) bool {
+ if reqNo, ok := key.(int64); ok {
+ if stat, ok := value.(map[Phase]PhaseStat); ok {
+ for phase, phaseStat := range stat {
+ if phaseStat.Status == Success {
+ testStats.SuccessCountsByPhase[phase]++
+ testStats.Aggregate(phase, phaseStat.Duration)
+ } else {
+ testStats.FailedCountsByPhase[phase]++
+ }
+ }
+ }
+ if reqNo > testStats.TotalRequests {
+ testStats.TotalRequests = reqNo
+ }
+ }
+ return true
+ })
+ // if no phase stats are found return
+ if testStats.TotalRequests <= 0 {
+ return
+ }
+ testStats.lggr.Info().Int64("Total Requests Triggerred", testStats.TotalRequests).Msg("Test Run Completed")
+ for _, phase := range phases {
+ events[phase] = testStats.lggr.Info().Str("Phase", string(phase))
+ if phaseStat, ok := testStats.DurationStatByPhase[phase]; ok {
+ testStats.DurationStatByPhase[phase] = AggregatorMetrics{
+ Min: phaseStat.Min,
+ Max: phaseStat.Max,
+ Avg: phaseStat.sum / float64(phaseStat.count),
+ }
+ events[phase].
+ Str("Min Duration for Successful Requests", fmt.Sprintf("%.02f", testStats.DurationStatByPhase[phase].Min)).
+ Str("Max Duration for Successful Requests", fmt.Sprintf("%.02f", testStats.DurationStatByPhase[phase].Max)).
+ Str("Average Duration for Successful Requests", fmt.Sprintf("%.02f", testStats.DurationStatByPhase[phase].Avg))
+ }
+ if failed, ok := testStats.FailedCountsByPhase[phase]; ok {
+ events[phase].Int64("Failed Count", failed)
+ }
+ if s, ok := testStats.SuccessCountsByPhase[phase]; ok {
+ events[phase].Int64("Successful Count", s)
+ }
+ events[phase].Msgf("Phase Stats for Lane %s", lane)
+ }
+}
+
+type CCIPTestReporter struct {
+ t *testing.T
+ logger *zerolog.Logger
+ startTime int64
+ endTime int64
+ grafanaURLProvider testreporters.GrafanaURLProvider
+ grafanaURL string
+ grafanaQueryParams []string
+ namespace string
+ reportFilePath string
+ duration time.Duration // duration is the duration of the test
+ FailedLanes map[string]Phase `json:"failed_lanes_and_phases,omitempty"` // FailedLanes is the list of lanes that failed and the phase at which it failed
+ LaneStats map[string]*CCIPLaneStats `json:"lane_stats"` // LaneStats is the statistics for each lane
+ mu *sync.Mutex
+ sendSlackReport bool
+}
+
+func (r *CCIPTestReporter) SetSendSlackReport(sendSlackReport bool) {
+ r.sendSlackReport = sendSlackReport
+}
+
+func (r *CCIPTestReporter) CompleteGrafanaDashboardURL() error {
+ if r.grafanaURLProvider == nil {
+ return fmt.Errorf("grafana URL provider is not set")
+ }
+ grafanaUrl, err := r.grafanaURLProvider.GetGrafanaBaseURL()
+ if err != nil {
+ return err
+ }
+
+ dashboardUrl, err := r.grafanaURLProvider.GetGrafanaDashboardURL()
+ if err != nil {
+ return err
+ }
+ r.grafanaURL = fmt.Sprintf("%s%s", grafanaUrl, dashboardUrl)
+ err = r.AddToGrafanaDashboardQueryParams(
+ fmt.Sprintf("from=%d", r.startTime),
+ fmt.Sprintf("to=%d", r.endTime),
+ fmt.Sprintf("var-remote_runner=%s", r.namespace))
+ if err != nil {
+ return err
+ }
+
+ err = r.FormatGrafanaURLWithQueryParameters()
+ if err != nil {
+ return fmt.Errorf("error formatting grafana URL: %w", err)
+ }
+ r.logger.Info().Str("Dashboard", r.grafanaURL).Msg("Dashboard URL")
+ return nil
+}
+
+// FormatGrafanaURLWithQueryParameters adds query params to the grafana URL
+// The query params are added in the format ?key=value if the grafana URL does not have any query params
+// If the grafana URL already has query params, the query params are added in the format &key=value
+// The function parameter qParam should be in the format key=value
+// If the function parameter qParam does not contain an =, an error is returned
+func (r *CCIPTestReporter) FormatGrafanaURLWithQueryParameters() error {
+ for _, v := range r.grafanaQueryParams {
+ if !strings.Contains(v, "=") {
+ return fmt.Errorf("invalid query param %s", v)
+ }
+ if strings.Contains(r.grafanaURL, "?") {
+ r.grafanaURL = fmt.Sprintf("%s&%s", r.grafanaURL, v)
+ continue
+ }
+ r.grafanaURL = fmt.Sprintf("%s?%s", r.grafanaURL, v)
+ }
+ return nil
+}
+
+// AddToGrafanaDashboardQueryParams adds query params to the QueryParams slice
+// The function parameter qParam should be in the format key=value
+// If the function parameter qParam does not contain an =, an error is returned
+func (r *CCIPTestReporter) AddToGrafanaDashboardQueryParams(qParams ...string) error {
+ for _, qParam := range qParams {
+ if !strings.Contains(qParam, "=") {
+ return fmt.Errorf("invalid query param %s", qParam)
+ }
+ r.grafanaQueryParams = append(r.grafanaQueryParams, qParam)
+ }
+ return nil
+}
+
+// SendSlackNotification sends a slack notification to the specified channel set in the environment variable "SLACK_CHANNEL"
+// notifying the user set in the environment variable "SLACK_USER"
+// The function returns an error if the slack notification fails
+func (r *CCIPTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client, _ testreporters.GrafanaURLProvider) error {
+ if r.sendSlackReport {
+ r.logger.Info().Msg("Sending Slack notification")
+ } else {
+ r.logger.Info().Msg("Slack notification not enabled")
+ return nil
+ }
+ if testreporters.SlackAPIKey == "" || testreporters.SlackChannel == "" || testreporters.SlackUserID == "" {
+ r.logger.Warn().Msg("Slack API Key, Channel or User ID not set. Skipping Slack notification")
+ return nil
+ }
+ if slackClient == nil {
+ slackClient = slack.New(testreporters.SlackAPIKey)
+ }
+
+ var msgTexts []string
+ headerText := ":white_check_mark: CCIP Test PASSED :white_check_mark:"
+ if t.Failed() {
+ headerText = ":x: CCIP Test FAILED :x:"
+ }
+ // If grafanaURLProvider is not set, form the message notifying about the failed lanes with the report file path
+ if r.grafanaURLProvider == nil {
+ for name, lane := range r.LaneStats {
+ if lane.FailedCountsByPhase[E2E] > 0 {
+ msgTexts = append(msgTexts,
+ fmt.Sprintf("lane %s :x:", name),
+ fmt.Sprintf(
+ "\nNumber of ccip-send= %d"+
+ "\nNo of failed requests = %d", lane.TotalRequests, lane.FailedCountsByPhase[E2E]))
+ }
+ }
+
+ msgTexts = append(msgTexts, fmt.Sprintf(
+ "\nTest Run Summary created on _remote-test-runner_ at _%s_\nNotifying <@%s>",
+ r.reportFilePath, testreporters.SlackUserID))
+ } else {
+ // If grafanaURLProvider is set, form the message with the grafana dashboard link
+ err := r.CompleteGrafanaDashboardURL()
+ if err != nil {
+ return fmt.Errorf("error formatting grafana dashboard URL: %w", err)
+ }
+ msgTexts = append(msgTexts, fmt.Sprintf(
+ "\nTest Run Completed \nNotifying <@%s>\n<%s|CCIP Long Running Tests Dashboard>",
+ testreporters.SlackUserID, r.grafanaURL))
+ }
+
+ messageBlocks := testreporters.SlackNotifyBlocks(headerText, r.namespace, msgTexts)
+ ts, err := testreporters.SendSlackMessage(slackClient, slack.MsgOptionBlocks(messageBlocks...))
+ if err != nil {
+ fmt.Println(messageBlocks)
+ return fmt.Errorf("failed to send slack message: %w", err)
+ }
+ // if grafanaURLProvider is set, we don't want to write the report in a file
+ // the report will be shared in terms of grafana dashboard link
+ if r.grafanaURLProvider == nil {
+ return testreporters.UploadSlackFile(slackClient, slack.FileUploadParameters{
+ Title: fmt.Sprintf("CCIP Test Report %s", r.namespace),
+ Filetype: "json",
+ Filename: fmt.Sprintf("ccip_report_%s.csv", r.namespace),
+ File: r.reportFilePath,
+ InitialComment: fmt.Sprintf("CCIP Test Report %s.", r.namespace),
+ Channels: []string{testreporters.SlackChannel},
+ ThreadTimestamp: ts,
+ })
+ }
+ return nil
+}
+
+func (r *CCIPTestReporter) WriteReport(folderPath string) error {
+ l := r.logger
+ for k := range r.LaneStats {
+ r.LaneStats[k].Finalize(k)
+ // if E2E for the lane has failed
+ if _, ok := r.LaneStats[k].FailedCountsByPhase[E2E]; ok {
+ // find the phase at which it failed
+ for phase, count := range r.LaneStats[k].FailedCountsByPhase {
+ if count > 0 && phase != E2E {
+ r.FailedLanes[k] = phase
+ break
+ }
+ }
+ }
+ }
+ if len(r.FailedLanes) > 0 {
+ r.logger.Info().Interface("List of Failed Lanes", r.FailedLanes).Msg("Failed Lanes")
+ }
+
+ // if grafanaURLProvider is set, we don't want to write the report in a file
+ // the report will be shared in terms of grafana dashboard link
+ if r.grafanaURLProvider != nil {
+ return nil
+ }
+ l.Debug().Str("Folder Path", folderPath).Msg("Writing CCIP Test Report")
+ if err := testreporters.MkdirIfNotExists(folderPath); err != nil {
+ return err
+ }
+ reportLocation := filepath.Join(folderPath, slackFile)
+ r.reportFilePath = reportLocation
+ slackFile, err := os.Create(reportLocation)
+ defer func() {
+ err = slackFile.Close()
+ if err != nil {
+ l.Error().Err(err).Msg("Error closing slack file")
+ }
+ }()
+ if err != nil {
+ return err
+ }
+ stats, err := json.MarshalIndent(r, "", " ")
+ if err != nil {
+ return err
+ }
+ _, err = slackFile.Write(stats)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// SetNamespace sets the namespace of the report for clean reports
+func (r *CCIPTestReporter) SetNamespace(namespace string) {
+ // if the test is run in remote runner, the namespace will be set to the remote runner's namespace
+ if value, set := os.LookupEnv(config.EnvVarNamespace); set && value != "" {
+ r.namespace = value
+ return
+ }
+ // if the namespace is not set, set it to the namespace provided
+ r.namespace = namespace
+}
+
+// SetDuration sets the duration of the test
+func (r *CCIPTestReporter) SetDuration(d time.Duration) {
+ r.duration = d
+}
+
+func (r *CCIPTestReporter) SetGrafanaURLProvider(provider testreporters.GrafanaURLProvider) {
+ r.grafanaURLProvider = provider
+}
+
+func (r *CCIPTestReporter) AddNewLane(name string, lggr *zerolog.Logger) *CCIPLaneStats {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ i := &CCIPLaneStats{
+ lane: name,
+ lggr: lggr,
+ FailedCountsByPhase: make(map[Phase]int64),
+ SuccessCountsByPhase: make(map[Phase]int64),
+ DurationStatByPhase: make(map[Phase]AggregatorMetrics),
+ }
+ r.LaneStats[name] = i
+ return i
+}
+
+func (r *CCIPTestReporter) SendReport(t *testing.T, namespace string, slackSend bool) error {
+ logsPath := filepath.Join("logs", fmt.Sprintf("%s-%s-%d", t.Name(), namespace, time.Now().Unix()))
+ r.SetNamespace(namespace)
+ r.endTime = time.Now().UTC().UnixMilli()
+ r.SetSendSlackReport(r.namespace != "" && slackSend)
+ return testreporters.SendReport(t, namespace, logsPath, r, nil)
+}
+
+func NewCCIPTestReporter(t *testing.T, lggr *zerolog.Logger) *CCIPTestReporter {
+ return &CCIPTestReporter{
+ LaneStats: make(map[string]*CCIPLaneStats),
+ startTime: time.Now().UTC().UnixMilli(),
+ logger: lggr,
+ t: t,
+ mu: &sync.Mutex{},
+ FailedLanes: make(map[string]Phase),
+ }
+}
diff --git a/integration-tests/ccip-tests/testsetups/ccip.go b/integration-tests/ccip-tests/testsetups/ccip.go
new file mode 100644
index 00000000000..207773aace4
--- /dev/null
+++ b/integration-tests/ccip-tests/testsetups/ccip.go
@@ -0,0 +1,1436 @@
+package testsetups
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ "math/rand"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/AlekSi/pointer"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/google/uuid"
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/atomic"
+ "go.uber.org/multierr"
+ "go.uber.org/zap/zapcore"
+ "golang.org/x/sync/errgroup"
+
+ chainselectors "github.com/smartcontractkit/chain-selectors"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+ ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client"
+ ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
+ ctf_config_types "github.com/smartcontractkit/chainlink-testing-framework/config/types"
+ ctftestenv "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/config"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment"
+ "github.com/smartcontractkit/chainlink-testing-framework/networks"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext"
+
+ integrationactions "github.com/smartcontractkit/chainlink/integration-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/contracts/laneconfig"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig"
+ ccipconfig "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testconfig"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testreporters"
+ testutils "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/utils"
+ "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env"
+)
+
+var (
+ GethResourceProfile = map[string]interface{}{
+ "requests": map[string]interface{}{
+ "cpu": "4",
+ "memory": "6Gi",
+ },
+ "limits": map[string]interface{}{
+ "cpu": "4",
+ "memory": "6Gi",
+ },
+ }
+ // to set default values through test config use sync.once
+ setContractVersion sync.Once
+ setOCRParams sync.Once
+ setConfigOverrides sync.Once
+)
+
+type NetworkPair struct {
+ NetworkA blockchain.EVMNetwork
+ NetworkB blockchain.EVMNetwork
+ ChainClientA blockchain.EVMClient
+ ChainClientB blockchain.EVMClient
+}
+
+// LeaderLane is to hold the details of leader lane source and destination network
+type LeaderLane struct {
+ source string
+ dest string
+}
+
+type CCIPTestConfig struct {
+ Test *testing.T
+ EnvInput *testconfig.Common
+ TestGroupInput *testconfig.CCIPTestGroupConfig
+ VersionInput map[contracts.Name]contracts.Version
+ ContractsInput *testconfig.CCIPContractConfig
+ AllNetworks map[string]blockchain.EVMNetwork
+ SelectedNetworks []blockchain.EVMNetwork
+ NetworkPairs []NetworkPair
+ LeaderLanes []LeaderLane
+ GethResourceProfile map[string]interface{}
+}
+
+func (c *CCIPTestConfig) useExistingDeployment() bool {
+ return pointer.GetBool(c.TestGroupInput.ExistingDeployment)
+}
+
+func (c *CCIPTestConfig) useSeparateTokenDeployer() bool {
+ return contracts.NeedTokenAdminRegistry() &&
+ !pointer.GetBool(c.TestGroupInput.TokenConfig.CCIPOwnerTokens) &&
+ !c.useExistingDeployment()
+}
+
+func (c *CCIPTestConfig) MultiCallEnabled() bool {
+ return pointer.GetBool(c.TestGroupInput.MulticallInOneTx)
+}
+
+func (c *CCIPTestConfig) localCluster() bool {
+ return pointer.GetBool(c.TestGroupInput.LocalCluster)
+}
+
+func (c *CCIPTestConfig) ExistingCLCluster() bool {
+ return c.EnvInput.ExistingCLCluster != nil
+}
+
+func (c *CCIPTestConfig) CLClusterNeedsUpgrade() bool {
+ if c.EnvInput.NewCLCluster == nil {
+ return false
+ }
+ if c.EnvInput.NewCLCluster.Common != nil && c.EnvInput.NewCLCluster.Common.ChainlinkUpgradeImage != nil {
+ return true
+ }
+ for _, node := range c.EnvInput.NewCLCluster.Nodes {
+ if node.ChainlinkUpgradeImage != nil {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *CCIPTestConfig) AddPairToNetworkList(networkA, networkB blockchain.EVMNetwork) {
+ if c.AllNetworks == nil {
+ c.AllNetworks = make(map[string]blockchain.EVMNetwork)
+ }
+ firstOfPairs := []blockchain.EVMNetwork{networkA}
+ secondOfPairs := []blockchain.EVMNetwork{networkB}
+ // if no of lanes per pair is greater than 1, copy common contracts from the same network
+ // if no of lanes per pair is more than 1, the networks are added into the inputs.AllNetworks with a suffix of -
+ // for example, if no of lanes per pair is 2, and the network pairs are called "testnetA", "testnetB",
+ // the network will be added as "testnetA-1", testnetA-2","testnetB-1", testnetB-2"
+ // to deploy 4 lanes between same network pair "testnetA", "testnetB".
+ // lanes - testnetA-1<->testnetB-1, testnetA-1<-->testnetB-2 , testnetA-2<--> testnetB-1, testnetA-2<--> testnetB-2
+ if c.TestGroupInput.NoOfRoutersPerPair > 1 {
+ firstOfPairs[0].Name = fmt.Sprintf("%s-%d", firstOfPairs[0].Name, 1)
+ secondOfPairs[0].Name = fmt.Sprintf("%s-%d", secondOfPairs[0].Name, 1)
+ for i := 1; i < c.TestGroupInput.NoOfRoutersPerPair; i++ {
+ netsA := networkA
+ netsA.Name = fmt.Sprintf("%s-%d", netsA.Name, i+1)
+ netsB := networkB
+ netsB.Name = fmt.Sprintf("%s-%d", netsB.Name, i+1)
+ firstOfPairs = append(firstOfPairs, netsA)
+ secondOfPairs = append(secondOfPairs, netsB)
+ }
+ }
+
+ for i := range firstOfPairs {
+ c.AllNetworks[firstOfPairs[i].Name] = firstOfPairs[i]
+ c.AllNetworks[secondOfPairs[i].Name] = secondOfPairs[i]
+ c.NetworkPairs = append(c.NetworkPairs, NetworkPair{
+ NetworkA: firstOfPairs[i],
+ NetworkB: secondOfPairs[i],
+ })
+ }
+}
+
+func (c *CCIPTestConfig) SetNetworkPairs(lggr zerolog.Logger) error {
+ var allError error
+ var err error
+ var inputNetworks []string
+ c.SelectedNetworks, inputNetworks, err = c.EnvInput.EVMNetworks()
+ if err != nil {
+ allError = multierr.Append(allError, fmt.Errorf("failed to get networks: %w", err))
+ return allError
+ }
+
+ networkByChainName := make(map[string]blockchain.EVMNetwork)
+ for i, net := range c.SelectedNetworks {
+ networkByChainName[inputNetworks[i]] = net
+ }
+ // if network pairs are provided, then use them
+ if c.TestGroupInput.NetworkPairs != nil {
+ networkPairs := c.TestGroupInput.NetworkPairs
+
+ for _, pair := range networkPairs {
+ networkNames := strings.Split(pair, ",")
+ if len(networkNames) != 2 {
+ allError = multierr.Append(allError, fmt.Errorf("invalid network pair"))
+ }
+ // check if the network names are valid
+ network1, ok := networkByChainName[networkNames[0]]
+ if !ok {
+ allError = multierr.Append(allError, fmt.Errorf("network %s not found in network config", networkNames[0]))
+ }
+ network2, ok := networkByChainName[networkNames[1]]
+ if !ok {
+ allError = multierr.Append(allError, fmt.Errorf("network %s not found in network config", networkNames[1]))
+ }
+ c.AddPairToNetworkList(network1, network2)
+ }
+ lggr.Info().Int("Pairs", len(c.NetworkPairs)).Msg("No Of Lanes")
+ return allError
+ }
+
+ if c.TestGroupInput.NoOfNetworks == 0 {
+ c.TestGroupInput.NoOfNetworks = len(c.SelectedNetworks)
+ }
+ // TODO remove this when CTF network timeout is fixed
+ for i := range c.SelectedNetworks {
+ c.SelectedNetworks[i].Timeout = blockchain.StrDuration{
+ Duration: 3 * time.Minute,
+ }
+ }
+ simulated := c.SelectedNetworks[0].Simulated
+ for i := 1; i < len(c.SelectedNetworks); i++ {
+ if c.SelectedNetworks[i].Simulated != simulated {
+ lggr.Fatal().Msg("networks must be of the same type either simulated or real")
+ }
+ }
+
+ // if the networks are not simulated use the first p.NoOfNetworks networks from the selected networks
+ if !simulated && len(c.SelectedNetworks) != c.TestGroupInput.NoOfNetworks {
+ if len(c.SelectedNetworks) < c.TestGroupInput.NoOfNetworks {
+ allError = multierr.Append(allError, fmt.Errorf("not enough networks provided"))
+ } else {
+ c.SelectedNetworks = c.SelectedNetworks[:c.TestGroupInput.NoOfNetworks]
+ }
+ }
+ // If provided networks is lesser than the required number of networks
+ // and the provided networks are simulated network, create replicas of the provided networks with
+ // different chain ids
+ if simulated && len(c.SelectedNetworks) < c.TestGroupInput.NoOfNetworks {
+ actualNoOfNetworks := len(c.SelectedNetworks)
+ n := c.SelectedNetworks[0]
+ var chainIDs []int64
+ existingChainIDs := make(map[uint64]struct{})
+ for _, net := range c.SelectedNetworks {
+ existingChainIDs[uint64(net.ChainID)] = struct{}{}
+ }
+ for _, id := range chainselectors.TestChainIds() {
+ // if the chain id already exists in the already provided selected networks, skip it
+ if _, exists := existingChainIDs[id]; exists {
+ continue
+ }
+ chainIDs = append(chainIDs, int64(id))
+ }
+ for i := 0; i < c.TestGroupInput.NoOfNetworks-actualNoOfNetworks; i++ {
+ chainID := chainIDs[i]
+ // if i is greater than the number of simulated pvt keys, rotate the keys
+ if i > len(networks.AdditionalSimulatedPvtKeys)-1 {
+ networks.AdditionalSimulatedPvtKeys = append(networks.AdditionalSimulatedPvtKeys, networks.AdditionalSimulatedPvtKeys...)
+ }
+ name := fmt.Sprintf("private-chain-%d", len(c.SelectedNetworks)+1)
+ c.SelectedNetworks = append(c.SelectedNetworks, blockchain.EVMNetwork{
+ Name: name,
+ ChainID: chainID,
+ Simulated: true,
+ PrivateKeys: []string{
+ networks.AdditionalSimulatedPvtKeys[i],
+ "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // second key for token deployments
+ },
+ ChainlinkTransactionLimit: n.ChainlinkTransactionLimit,
+ Timeout: n.Timeout,
+ MinimumConfirmations: n.MinimumConfirmations,
+ GasEstimationBuffer: n.GasEstimationBuffer + 1000,
+ ClientImplementation: n.ClientImplementation,
+ DefaultGasLimit: n.DefaultGasLimit,
+ FinalityDepth: n.FinalityDepth,
+ SupportsEIP1559: true,
+ })
+ if existing, ok := c.EnvInput.Network.AnvilConfigs[strings.ToUpper(n.Name)]; c.EnvInput.Network.AnvilConfigs != nil && ok {
+ c.EnvInput.Network.AnvilConfigs[strings.ToUpper(name)] = existing
+ }
+
+ chainConfig := &ctf_config.EthereumChainConfig{}
+ err := chainConfig.Default()
+ if err != nil {
+ allError = multierr.Append(allError, fmt.Errorf("failed to get default chain config: %w", err))
+ } else {
+ chainConfig.ChainID = int(chainID)
+ eth1 := ctf_config_types.EthereumVersion_Eth1
+ geth := ctf_config_types.ExecutionLayer_Geth
+
+ c.EnvInput.PrivateEthereumNetworks[fmt.Sprint(chainID)] = &ctf_config.EthereumNetworkConfig{
+ EthereumVersion: ð1,
+ ExecutionLayer: &geth,
+ EthereumChainConfig: chainConfig,
+ }
+ }
+ }
+ }
+
+ if c.TestGroupInput.NoOfNetworks > 2 {
+ c.FormNetworkPairCombinations()
+ } else {
+ c.AddPairToNetworkList(c.SelectedNetworks[0], c.SelectedNetworks[1])
+ }
+
+ // if the number of lanes is lesser than the number of network pairs, choose first c.TestGroupInput.MaxNoOfLanes pairs
+ if c.TestGroupInput.MaxNoOfLanes > 0 && c.TestGroupInput.MaxNoOfLanes < len(c.NetworkPairs) {
+ var newNetworkPairs []NetworkPair
+ denselyConnectedNetworks := make(map[string]struct{})
+ // if densely connected networks are provided, choose all the network pairs containing the networks mentioned in the list for DenselyConnectedNetworkChainIds
+ if c.TestGroupInput.DenselyConnectedNetworkChainIds != nil && len(c.TestGroupInput.DenselyConnectedNetworkChainIds) > 0 {
+ for _, n := range c.TestGroupInput.DenselyConnectedNetworkChainIds {
+ denselyConnectedNetworks[n] = struct{}{}
+ }
+ for _, pair := range c.NetworkPairs {
+ if _, exists := denselyConnectedNetworks[strconv.FormatInt(pair.NetworkA.ChainID, 10)]; exists {
+ newNetworkPairs = append(newNetworkPairs, pair)
+ }
+ }
+ }
+ // shuffle the network pairs, we want to randomly distribute the network pairs among all available networks
+ rand.Shuffle(len(c.NetworkPairs), func(i, j int) {
+ c.NetworkPairs[i], c.NetworkPairs[j] = c.NetworkPairs[j], c.NetworkPairs[i]
+ })
+ // now add the remaining network pairs by skipping the already covered networks
+ // and adding the remaining pair from the shuffled list
+ i := len(newNetworkPairs)
+ j := 0
+ for i < c.TestGroupInput.MaxNoOfLanes {
+ pair := c.NetworkPairs[j]
+ // if the network is already covered, skip it
+ if _, exists := denselyConnectedNetworks[strconv.FormatInt(pair.NetworkA.ChainID, 10)]; !exists {
+ newNetworkPairs = append(newNetworkPairs, pair)
+ i++
+ }
+ j++
+ }
+ c.NetworkPairs = newNetworkPairs
+ }
+
+ // setting leader lane details to network pairs if it is enabled and only in simulated environments
+ if !pointer.GetBool(c.TestGroupInput.ExistingDeployment) {
+ c.defineLeaderLanes(lggr)
+ }
+ for _, n := range c.NetworkPairs {
+ lggr.Info().
+ Str("NetworkA", fmt.Sprintf("%s-%d", n.NetworkA.Name, n.NetworkA.ChainID)).
+ Str("NetworkB", fmt.Sprintf("%s-%d", n.NetworkB.Name, n.NetworkB.ChainID)).
+ Msg("Network Pairs")
+ }
+ for _, lane := range c.LeaderLanes {
+ lggr.Info().
+ Str("Source", lane.source).
+ Str("Destination", lane.dest).
+ Msg("Leader Lane: ")
+ }
+ lggr.Info().Int("Pairs", len(c.NetworkPairs)).Msg("No Of Lanes")
+
+ return allError
+}
+
+// defineLeaderLanes goes over the available network pairs and define one leader lane per destination
+func (c *CCIPTestConfig) defineLeaderLanes(lggr zerolog.Logger) {
+ if !isLeaderLaneFeatureEnabled(&lggr) {
+ return
+ }
+ // the way we are defining leader lane is simply by tagging the destination as key along with the first source network
+ // as value to the map.
+ leaderLanes := make(map[string]string)
+ for _, n := range c.NetworkPairs {
+ if _, ok := leaderLanes[n.NetworkB.Name]; !ok {
+ leaderLanes[n.NetworkB.Name] = n.NetworkA.Name
+ }
+ if pointer.GetBool(c.TestGroupInput.BiDirectionalLane) {
+ if _, ok := leaderLanes[n.NetworkA.Name]; !ok {
+ leaderLanes[n.NetworkA.Name] = n.NetworkB.Name
+ }
+ }
+ }
+ for k, v := range leaderLanes {
+ c.LeaderLanes = append(c.LeaderLanes, LeaderLane{
+ source: v,
+ dest: k,
+ })
+ }
+}
+
+// isPriceReportingDisabled checks the given lane is leader lane and return boolean accordingly
+func (c *CCIPTestConfig) isPriceReportingDisabled(lggr *zerolog.Logger, source, dest string) bool {
+ for _, leader := range c.LeaderLanes {
+ if leader.source == source && leader.dest == dest {
+ lggr.Debug().
+ Str("Source", source).
+ Str("Destination", dest).
+ Msg("Non-leader lane")
+ return true
+ }
+ }
+ return false
+}
+
+func isLeaderLaneFeatureEnabled(lggr *zerolog.Logger) bool {
+ if err := contracts.MatchContractVersionsOrAbove(map[contracts.Name]contracts.Version{
+ contracts.OffRampContract: contracts.V1_2_0,
+ contracts.OnRampContract: contracts.V1_2_0,
+ }); err != nil {
+ lggr.Info().Str("Required contract version", contracts.V1_2_0.String()).Msg("Leader lane feature is not enabled")
+ return false
+ }
+ return true
+}
+
+func (c *CCIPTestConfig) FormNetworkPairCombinations() {
+ for i := 0; i < c.TestGroupInput.NoOfNetworks; i++ {
+ for j := i + 1; j < c.TestGroupInput.NoOfNetworks; j++ {
+ c.AddPairToNetworkList(c.SelectedNetworks[i], c.SelectedNetworks[j])
+ }
+ }
+}
+
+func (c *CCIPTestConfig) SetContractVersion() error {
+ if c.VersionInput == nil {
+ return nil
+ }
+ for contractName, version := range c.VersionInput {
+ err := contracts.CheckVersionSupported(contractName, version)
+ if err != nil {
+ return err
+ }
+ contracts.VersionMap[contractName] = version
+ }
+ return nil
+}
+
+func (c *CCIPTestConfig) SetOCRParams() error {
+ if c.TestGroupInput.OffRampConfig != nil {
+ if c.TestGroupInput.OffRampConfig.InflightExpiry != nil &&
+ c.TestGroupInput.OffRampConfig.InflightExpiry.Duration() > 0 {
+ actions.InflightExpiryExec = c.TestGroupInput.OffRampConfig.InflightExpiry.Duration()
+ }
+ if pointer.GetUint32(c.TestGroupInput.OffRampConfig.BatchGasLimit) > 0 {
+ actions.BatchGasLimit = pointer.GetUint32(c.TestGroupInput.OffRampConfig.BatchGasLimit)
+ }
+ if pointer.GetUint32(c.TestGroupInput.OffRampConfig.MaxDataBytes) > 0 {
+ actions.MaxDataBytes = pointer.GetUint32(c.TestGroupInput.OffRampConfig.MaxDataBytes)
+ }
+ if c.TestGroupInput.OffRampConfig.RootSnooze != nil &&
+ c.TestGroupInput.OffRampConfig.RootSnooze.Duration() > 0 {
+ actions.RootSnoozeTime = c.TestGroupInput.OffRampConfig.RootSnooze.Duration()
+ }
+ }
+ if c.TestGroupInput.CommitInflightExpiry != nil && c.TestGroupInput.CommitInflightExpiry.Duration() > 0 {
+ actions.InflightExpiryCommit = c.TestGroupInput.CommitInflightExpiry.Duration()
+ }
+ return nil
+}
+
+// TestConfigOverrideOption is a function that modifies the test config and overrides any values passed in by test files
+// This is useful for setting up test specific configurations.
+// The return should be a short, explanatory string that describes the change made by the override.
+// This is logged at the beginning of the test run.
+type TestConfigOverrideOption func(*CCIPTestConfig) string
+
+// UseCCIPOwnerTokens defines whether all tokens are deployed by the same address as the CCIP owner
+func UseCCIPOwnerTokens(yes bool) TestConfigOverrideOption {
+ return func(c *CCIPTestConfig) string {
+ c.TestGroupInput.TokenConfig.CCIPOwnerTokens = pointer.ToBool(yes)
+ return fmt.Sprintf("CCIPOwnerTokens set to %t", yes)
+ }
+}
+
+// WithTokensPerChain sets the number of tokens to deploy on each chain
+func WithTokensPerChain(count int) TestConfigOverrideOption {
+ return func(c *CCIPTestConfig) string {
+ c.TestGroupInput.TokenConfig.NoOfTokensPerChain = pointer.ToInt(count)
+ return fmt.Sprintf("NoOfTokensPerChain set to %d", count)
+ }
+}
+
+// WithMsgDetails sets the message details for the test
+func WithMsgDetails(details *testconfig.MsgDetails) TestConfigOverrideOption {
+ return func(c *CCIPTestConfig) string {
+ c.TestGroupInput.MsgDetails = details
+ return "Message set"
+ }
+}
+
+// WithNoTokensPerMessage sets how many tokens can be sent in a single message
+func WithNoTokensPerMessage(noOfTokens int) TestConfigOverrideOption {
+ return func(c *CCIPTestConfig) string {
+ c.TestGroupInput.MsgDetails.NoOfTokens = pointer.ToInt(noOfTokens)
+ return fmt.Sprintf("MsgDetails.NoOfTokens set to %d", noOfTokens)
+ }
+}
+
+// NewCCIPTestConfig reads the CCIP test config from TOML files, applies any overrides, and configures the test environment
+func NewCCIPTestConfig(t *testing.T, lggr zerolog.Logger, tType string, overrides ...TestConfigOverrideOption) *CCIPTestConfig {
+ testCfg := ccipconfig.GlobalTestConfig()
+ groupCfg, exists := testCfg.CCIP.Groups[tType]
+ if !exists {
+ t.Fatalf("group config for %s does not exist", tType)
+ }
+ if tType == ccipconfig.Load {
+ if testCfg.CCIP.Env.Logging == nil || testCfg.CCIP.Env.Logging.Loki == nil {
+ t.Fatal("loki config is required to be set for load test")
+ }
+ if testCfg.CCIP.Env.Logging == nil || testCfg.CCIP.Env.Logging.Grafana == nil {
+ t.Fatal("grafana config is required for load test")
+ }
+ }
+ if pointer.GetBool(groupCfg.KeepEnvAlive) {
+ err := os.Setenv(config.EnvVarKeepEnvironments, "ALWAYS")
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ ccipTestConfig := &CCIPTestConfig{
+ Test: t,
+ EnvInput: testCfg.CCIP.Env,
+ ContractsInput: testCfg.CCIP.Deployments,
+ VersionInput: testCfg.CCIP.ContractVersions,
+ TestGroupInput: groupCfg,
+ GethResourceProfile: GethResourceProfile,
+ }
+ setContractVersion.Do(func() {
+ err := ccipTestConfig.SetContractVersion()
+ if err != nil {
+ t.Fatal(err)
+ }
+ })
+ setOCRParams.Do(func() {
+ err := ccipTestConfig.SetOCRParams()
+ if err != nil {
+ t.Fatal(err)
+ }
+ })
+ setConfigOverrides.Do(func() {
+ overrideMessages := []string{}
+ for _, override := range overrides {
+ if override != nil {
+ overrideMessages = append(overrideMessages, override(ccipTestConfig))
+ }
+ }
+ if len(overrideMessages) > 0 {
+ lggr.Debug().Int("Overrides", len(overrideMessages)).Msg("Test Specific Config Overrides Applied")
+ for _, msg := range overrideMessages {
+ lggr.Debug().Msg(msg)
+ }
+ }
+ })
+ err := ccipTestConfig.SetNetworkPairs(lggr)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return ccipTestConfig
+}
+
+type BiDirectionalLaneConfig struct {
+ NetworkA blockchain.EVMNetwork
+ NetworkB blockchain.EVMNetwork
+ ForwardLane *actions.CCIPLane
+ ReverseLane *actions.CCIPLane
+}
+
+type CCIPTestSetUpOutputs struct {
+ SetUpContext context.Context
+ Cfg *CCIPTestConfig
+ LaneContractsByNetwork *sync.Map
+ laneMutex *sync.Mutex
+ Lanes []*BiDirectionalLaneConfig
+ Reporter *testreporters.CCIPTestReporter
+ LaneConfigFile string
+ LaneConfig *laneconfig.Lanes
+ TearDown func() error
+ Env *actions.CCIPTestEnv
+ Balance *actions.BalanceSheet
+ BootstrapAdded *atomic.Bool
+ JobAddGrp *errgroup.Group
+}
+
+func (o *CCIPTestSetUpOutputs) AddToLanes(lane *BiDirectionalLaneConfig) {
+ o.laneMutex.Lock()
+ defer o.laneMutex.Unlock()
+ o.Lanes = append(o.Lanes, lane)
+}
+
+func (o *CCIPTestSetUpOutputs) ReadLanes() []*BiDirectionalLaneConfig {
+ o.laneMutex.Lock()
+ defer o.laneMutex.Unlock()
+ return o.Lanes
+}
+
+func (o *CCIPTestSetUpOutputs) DeployChainContracts(
+ lggr *zerolog.Logger,
+ chainClient blockchain.EVMClient,
+ networkCfg blockchain.EVMNetwork,
+ noOfTokens int,
+ tokenDeployerFns []blockchain.ContractDeployer,
+) error {
+ var k8Env *environment.Environment
+ ccipEnv := o.Env
+ if ccipEnv != nil {
+ k8Env = ccipEnv.K8Env
+ }
+ if k8Env != nil && chainClient.NetworkSimulated() {
+ networkCfg.URLs = k8Env.URLs[chainClient.GetNetworkConfig().Name]
+ }
+
+ mainChainClient, err := blockchain.ConcurrentEVMClient(networkCfg, k8Env, chainClient, *lggr)
+ if err != nil {
+ return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkCfg.Name, err))
+ }
+
+ mainChainClient.ParallelTransactions(true)
+ defer mainChainClient.Close()
+ ccipCommon, err := actions.DefaultCCIPModule(
+ lggr, o.Cfg.TestGroupInput, mainChainClient,
+ )
+ if err != nil {
+ return errors.WithStack(fmt.Errorf("failed to create ccip common module for %s: %w", networkCfg.Name, err))
+ }
+
+ cfg := o.LaneConfig.ReadLaneConfig(networkCfg.Name)
+
+ err = ccipCommon.DeployContracts(noOfTokens, tokenDeployerFns, cfg)
+ if err != nil {
+ return errors.WithStack(fmt.Errorf("failed to deploy common ccip contracts for %s: %w", networkCfg.Name, err))
+ }
+ ccipCommon.WriteLaneConfig(cfg)
+ o.LaneContractsByNetwork.Store(networkCfg.Name, cfg)
+
+ return nil
+}
+
+func (o *CCIPTestSetUpOutputs) SetupDynamicTokenPriceUpdates() error {
+ interval := o.Cfg.TestGroupInput.TokenConfig.DynamicPriceUpdateInterval.Duration()
+ covered := make(map[string]struct{})
+ for _, lanes := range o.ReadLanes() {
+ lane := lanes.ForwardLane
+ if _, exists := covered[lane.SourceNetworkName]; !exists {
+ covered[lane.SourceNetworkName] = struct{}{}
+ err := lane.Source.Common.UpdateTokenPricesAtRegularInterval(lane.Context, lane.Logger, interval, o.LaneConfig.ReadLaneConfig(lane.SourceNetworkName))
+ if err != nil {
+ return err
+ }
+ }
+ if _, exists := covered[lane.DestNetworkName]; !exists {
+ covered[lane.DestNetworkName] = struct{}{}
+ err := lane.Dest.Common.UpdateTokenPricesAtRegularInterval(lane.Context, lane.Logger, interval, o.LaneConfig.ReadLaneConfig(lane.DestNetworkName))
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (o *CCIPTestSetUpOutputs) AddLanesForNetworkPair(
+ lggr *zerolog.Logger,
+ networkA, networkB blockchain.EVMNetwork,
+ chainClientA, chainClientB blockchain.EVMClient,
+) error {
+ var (
+ t = o.Cfg.Test
+ allErrors atomic.Error
+ k8Env *environment.Environment
+ ccipEnv = o.Env
+ namespace = ""
+ )
+
+ if o.Cfg.TestGroupInput.LoadProfile != nil {
+ namespace = o.Cfg.TestGroupInput.LoadProfile.TestRunName
+ }
+ bidirectional := pointer.GetBool(o.Cfg.TestGroupInput.BiDirectionalLane)
+ if ccipEnv != nil {
+ k8Env = ccipEnv.K8Env
+ if k8Env != nil {
+ namespace = k8Env.Cfg.Namespace
+ }
+ }
+
+ setUpFuncs, ctx := errgroup.WithContext(testcontext.Get(t))
+
+ // Use new set of clients(sourceChainClient,destChainClient)
+ // with new header subscriptions(otherwise transactions
+ // on one lane will keep on waiting for transactions on other lane for the same network)
+ // Currently for simulated network clients(from same network) created with NewEVMClient does not sync nonce
+ // ConcurrentEVMClient is a work-around for that.
+ sourceChainClientA2B, err := blockchain.ConcurrentEVMClient(networkA, k8Env, chainClientA, *lggr)
+ if err != nil {
+ return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkA.Name, err))
+ }
+
+ sourceChainClientA2B.ParallelTransactions(true)
+
+ destChainClientA2B, err := blockchain.ConcurrentEVMClient(networkB, k8Env, chainClientB, *lggr)
+ if err != nil {
+ return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkB.Name, err))
+ }
+ destChainClientA2B.ParallelTransactions(true)
+
+ ccipLaneA2B := &actions.CCIPLane{
+ Test: t,
+ SourceChain: sourceChainClientA2B,
+ DestChain: destChainClientA2B,
+ SourceNetworkName: actions.NetworkName(networkA.Name),
+ DestNetworkName: actions.NetworkName(networkB.Name),
+ ValidationTimeout: o.Cfg.TestGroupInput.PhaseTimeout.Duration(),
+ SentReqs: make(map[common.Hash][]actions.CCIPRequest),
+ TotalFee: big.NewInt(0),
+ Balance: o.Balance,
+ Context: testcontext.Get(t),
+ }
+ // if it non leader lane, disable the price reporting
+ ccipLaneA2B.PriceReportingDisabled = len(o.Cfg.LeaderLanes) > 0 &&
+ !o.Cfg.isPriceReportingDisabled(lggr, ccipLaneA2B.SourceNetworkName, ccipLaneA2B.DestNetworkName)
+
+ contractsA, ok := o.LaneContractsByNetwork.Load(networkA.Name)
+ if !ok {
+ return errors.WithStack(fmt.Errorf("failed to load lane contracts for %s", networkA.Name))
+ }
+ srcCfg := contractsA.(*laneconfig.LaneConfig)
+ ccipLaneA2B.SrcNetworkLaneCfg = srcCfg
+ contractsB, ok := o.LaneContractsByNetwork.Load(networkB.Name)
+ if !ok {
+ return errors.WithStack(fmt.Errorf("failed to load lane contracts for %s", networkB.Name))
+ }
+ destCfg := contractsB.(*laneconfig.LaneConfig)
+ ccipLaneA2B.DstNetworkLaneCfg = destCfg
+
+ a2blogger := lggr.With().Str("env", namespace).Str("Lane",
+ fmt.Sprintf("%s-->%s", ccipLaneA2B.SourceNetworkName, ccipLaneA2B.DestNetworkName)).Logger()
+ ccipLaneA2B.Logger = &a2blogger
+ ccipLaneA2B.Reports = o.Reporter.AddNewLane(fmt.Sprintf("%s To %s",
+ networkA.Name, networkB.Name), ccipLaneA2B.Logger)
+
+ bidirectionalLane := &BiDirectionalLaneConfig{
+ NetworkA: networkA,
+ NetworkB: networkB,
+ ForwardLane: ccipLaneA2B,
+ }
+
+ var ccipLaneB2A *actions.CCIPLane
+
+ if bidirectional {
+ sourceChainClientB2A, err := blockchain.ConcurrentEVMClient(networkB, k8Env, chainClientB, *lggr)
+ if err != nil {
+ return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkB.Name, err))
+ }
+ sourceChainClientB2A.ParallelTransactions(true)
+
+ destChainClientB2A, err := blockchain.ConcurrentEVMClient(networkA, k8Env, chainClientA, *lggr)
+ if err != nil {
+ return errors.WithStack(fmt.Errorf("failed to create chain client for %s: %w", networkA.Name, err))
+ }
+ destChainClientB2A.ParallelTransactions(true)
+
+ ccipLaneB2A = &actions.CCIPLane{
+ Test: t,
+ SourceNetworkName: actions.NetworkName(networkB.Name),
+ DestNetworkName: actions.NetworkName(networkA.Name),
+ SourceChain: sourceChainClientB2A,
+ DestChain: destChainClientB2A,
+ ValidationTimeout: o.Cfg.TestGroupInput.PhaseTimeout.Duration(),
+ Balance: o.Balance,
+ SentReqs: make(map[common.Hash][]actions.CCIPRequest),
+ TotalFee: big.NewInt(0),
+ Context: testcontext.Get(t),
+ SrcNetworkLaneCfg: ccipLaneA2B.DstNetworkLaneCfg,
+ DstNetworkLaneCfg: ccipLaneA2B.SrcNetworkLaneCfg,
+ }
+ // if it non leader lane, disable the price reporting
+ ccipLaneB2A.PriceReportingDisabled = len(o.Cfg.LeaderLanes) > 0 &&
+ !o.Cfg.isPriceReportingDisabled(lggr, ccipLaneB2A.SourceNetworkName, ccipLaneB2A.DestNetworkName)
+ b2aLogger := lggr.With().Str("env", namespace).Str("Lane",
+ fmt.Sprintf("%s-->%s", ccipLaneB2A.SourceNetworkName, ccipLaneB2A.DestNetworkName)).Logger()
+ ccipLaneB2A.Logger = &b2aLogger
+ ccipLaneB2A.Reports = o.Reporter.AddNewLane(
+ fmt.Sprintf("%s To %s", networkB.Name, networkA.Name), ccipLaneB2A.Logger)
+ bidirectionalLane.ReverseLane = ccipLaneB2A
+ }
+ o.AddToLanes(bidirectionalLane)
+
+ setUpFuncs.Go(func() error {
+ lggr.Info().Msgf("Setting up lane %s to %s", networkA.Name, networkB.Name)
+ err := ccipLaneA2B.DeployNewCCIPLane(
+ o.SetUpContext, o.Env,
+ o.Cfg.TestGroupInput, o.BootstrapAdded, o.JobAddGrp,
+ )
+ if err != nil {
+ allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("deploying lane %s to %s; err - %w", networkA.Name, networkB.Name, errors.WithStack(err))))
+ return err
+ }
+ err = o.LaneConfig.WriteLaneConfig(networkA.Name, ccipLaneA2B.SrcNetworkLaneCfg)
+ if err != nil {
+ lggr.Error().Err(err).Msgf("error deploying lane %s to %s", networkA.Name, networkB.Name)
+ allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %w", networkA.Name, errors.WithStack(err))))
+ return err
+ }
+ err = o.LaneConfig.WriteLaneConfig(networkB.Name, ccipLaneA2B.DstNetworkLaneCfg)
+ if err != nil {
+ allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %w", networkB.Name, errors.WithStack(err))))
+ return err
+ }
+
+ // we need to set the remote chains on the pool after the lane is deployed
+ // it's sufficient to do this only for the forward lane, as the destination pools will also be updated with source pool updates
+ // The reverse lane will have the same pools as the forward lane but in reverse order of source and destination
+ err = ccipLaneA2B.SetRemoteChainsOnPool()
+ if err != nil {
+ allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("error setting remote chains; err - %w", errors.WithStack(err))))
+ return err
+ }
+ lggr.Info().Msgf("done setting up lane %s to %s", networkA.Name, networkB.Name)
+ if o.Cfg.TestGroupInput.LoadProfile != nil && pointer.GetBool(o.Cfg.TestGroupInput.LoadProfile.OptimizeSpace) {
+ // This is to optimize memory space for load tests with high number of networks, lanes, tokens
+ ccipLaneA2B.OptimizeStorage()
+ }
+ return nil
+ })
+
+ setUpFuncs.Go(func() error {
+ if bidirectional {
+ lggr.Info().Msgf("Setting up lane %s to %s", networkB.Name, networkA.Name)
+ err := ccipLaneB2A.DeployNewCCIPLane(
+ o.SetUpContext, o.Env,
+ o.Cfg.TestGroupInput, o.BootstrapAdded, o.JobAddGrp,
+ )
+ if err != nil {
+ lggr.Error().Err(err).Msgf("error deploying lane %s to %s", networkB.Name, networkA.Name)
+ allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("deploying lane %s to %s; err - %w", networkB.Name, networkA.Name, errors.WithStack(err))))
+ return err
+ }
+
+ err = o.LaneConfig.WriteLaneConfig(networkB.Name, ccipLaneB2A.SrcNetworkLaneCfg)
+ if err != nil {
+ allErrors.Store(multierr.Append(allErrors.Load(), fmt.Errorf("writing lane config for %s; err - %w", networkA.Name, errors.WithStack(err))))
+ return err
+ }
+ err = o.LaneConfig.WriteLaneConfig(networkA.Name, ccipLaneB2A.DstNetworkLaneCfg)
+ if err != nil {
+ allErrors.Store(
+ multierr.Append(
+ allErrors.Load(),
+ fmt.Errorf("writing lane config for %s; err - %w", networkB.Name, errors.WithStack(err)),
+ ),
+ )
+ return err
+ }
+ lggr.Info().Msgf("done setting up lane %s to %s", networkB.Name, networkA.Name)
+ if o.Cfg.TestGroupInput.LoadProfile != nil && pointer.GetBool(o.Cfg.TestGroupInput.LoadProfile.OptimizeSpace) {
+ // This is to optimize memory space for load tests with high number of networks, lanes, tokens
+ ccipLaneB2A.OptimizeStorage()
+ }
+ return nil
+ }
+ return nil
+ })
+
+ errs := make(chan error, 1)
+ go func() {
+ errs <- setUpFuncs.Wait()
+ }()
+
+ // wait for either context to get cancelled or all the error-groups to finish execution
+ for {
+ select {
+ case err := <-errs:
+ // check if there has been any error while waiting for the error groups
+ // to finish execution
+ return err
+ case <-ctx.Done():
+ lggr.Print(ctx.Err())
+ return allErrors.Load()
+ }
+ }
+}
+
+func (o *CCIPTestSetUpOutputs) StartEventWatchers() {
+ for _, lane := range o.ReadLanes() {
+ err := lane.ForwardLane.StartEventWatchers()
+ require.NoError(o.Cfg.Test, err)
+ if lane.ReverseLane != nil {
+ err = lane.ReverseLane.StartEventWatchers()
+ require.NoError(o.Cfg.Test, err)
+ }
+ }
+}
+
+func (o *CCIPTestSetUpOutputs) WaitForPriceUpdates() {
+ t := o.Cfg.Test
+ priceUpdateGrp, _ := errgroup.WithContext(o.SetUpContext)
+ for _, lanes := range o.ReadLanes() {
+ lanes := lanes
+ forwardLane := lanes.ForwardLane
+ reverseLane := lanes.ReverseLane
+ waitForUpdate := func(lane *actions.CCIPLane) error {
+ defer func() {
+ lane.Logger.Info().
+ Str("source_chain", lane.Source.Common.ChainClient.GetNetworkName()).
+ Uint64("dest_chain", lane.Source.DestinationChainId).
+ Str("price_registry", lane.Source.Common.PriceRegistry.Address()).
+ Msg("Stopping price update watch")
+
+ }()
+ var allTokens []common.Address
+ for _, token := range lane.Source.Common.BridgeTokens {
+ allTokens = append(allTokens, token.ContractAddress)
+ }
+ allTokens = append(allTokens, lane.Source.Common.FeeToken.EthAddress)
+ lane.Logger.Info().
+ Str("source_chain", lane.Source.Common.ChainClient.GetNetworkName()).
+ Uint64("dest_chain", lane.Source.DestinationChainId).
+ Str("price_registry", lane.Source.Common.PriceRegistry.Address()).
+ Msgf("Waiting for price update")
+ err := lane.Source.Common.WaitForPriceUpdates(
+ o.SetUpContext, lane.Logger,
+ o.Cfg.TestGroupInput.TokenConfig.TimeoutForPriceUpdate.Duration(),
+ lane.Source.DestinationChainId,
+ allTokens,
+ )
+ if err != nil {
+ return errors.Wrapf(err, "waiting for price update failed on lane %s-->%s", lane.SourceNetworkName, lane.DestNetworkName)
+ }
+ return nil
+ }
+
+ priceUpdateGrp.Go(func() error {
+ return waitForUpdate(forwardLane)
+ })
+ if lanes.ReverseLane != nil {
+ priceUpdateGrp.Go(func() error {
+ return waitForUpdate(reverseLane)
+ })
+ }
+ }
+
+ require.NoError(t, priceUpdateGrp.Wait())
+}
+
+// CheckGasUpdateTransaction checks the gas update transactions count
+func (o *CCIPTestSetUpOutputs) CheckGasUpdateTransaction(lggr *zerolog.Logger) error {
+ transactionsBySource := make(map[string]string)
+ destToSourcesList := make(map[string][]string)
+ // create a map to hold the unique destination with list of sources
+ for _, n := range o.Cfg.NetworkPairs {
+ destToSourcesList[n.NetworkB.Name] = append(destToSourcesList[n.NetworkB.Name], n.NetworkA.Name)
+ if pointer.GetBool(o.Cfg.TestGroupInput.BiDirectionalLane) {
+ destToSourcesList[n.NetworkA.Name] = append(destToSourcesList[n.NetworkA.Name], n.NetworkB.Name)
+ }
+ }
+ lggr.Debug().Interface("list", destToSourcesList).Msg("Dest to Source")
+ // a function to read the gas update events and create a map with unique source and store the tx hash
+ filterGasUpdateEventTxBySource := func(lane *actions.CCIPLane) error {
+ for _, g := range lane.Source.Common.GasUpdateEvents {
+ if g.Value == nil {
+ return fmt.Errorf("gas update value should not be nil in tx %s", g.Tx)
+ }
+ if _, ok := transactionsBySource[g.Source]; !ok {
+ transactionsBySource[g.Source] = g.Tx
+ }
+ }
+ return nil
+ }
+
+ for _, lane := range o.ReadLanes() {
+ if err := filterGasUpdateEventTxBySource(lane.ForwardLane); err != nil {
+ return fmt.Errorf("error in filtering gas update transactions in the lane source: %s and destination: %s, error: %w",
+ lane.ForwardLane.SourceNetworkName, lane.ForwardLane.DestNetworkName, err)
+ }
+ if lane.ReverseLane != nil {
+ if err := filterGasUpdateEventTxBySource(lane.ReverseLane); err != nil {
+ return fmt.Errorf("error in filtering gas update transactions in the lane source: %s and destination: %s, error: %w",
+ lane.ReverseLane.SourceNetworkName, lane.ReverseLane.DestNetworkName, err)
+ }
+ }
+ }
+
+ lggr.Debug().Interface("Tx hashes by source", transactionsBySource).Msg("Checked Gas Update Transactions by Source")
+ // when leader lane setup is enabled, number of unique transaction from the source
+ // should match the number of leader lanes defined.
+ if len(transactionsBySource) != len(o.Cfg.LeaderLanes) {
+ lggr.Error().
+ Int("Tx hashes expected", len(o.Cfg.LeaderLanes)).
+ Int("Tx hashes received", len(transactionsBySource)).
+ Int("Leader lanes count", len(o.Cfg.LeaderLanes)).
+ Msg("Checked Gas Update transactions count doesn't match")
+ return fmt.Errorf("checked Gas Update transactions count doesn't match")
+ }
+ lggr.Debug().
+ Int("Tx hashes by source", len(transactionsBySource)).
+ Int("Leader lanes count", len(o.Cfg.LeaderLanes)).
+ Msg("Checked Gas Update transactions count matches")
+
+ return nil
+}
+
+// CCIPDefaultTestSetUp sets up the environment for CCIP tests
+// if configureCLNode is set as false, it assumes:
+// 1. contracts are already deployed on live networks
+// 2. CL nodes are set up and configured with existing contracts
+// 3. No k8 env deployment is needed
+// It reuses already deployed contracts from the addresses provided in ../contracts/ccip/laneconfig/contracts.json
+//
+// If bidirectional is true it sets up two-way lanes between NetworkA and NetworkB. Same CL nodes are used for both the lanes.
+// If bidirectional is false only one way lane is set up.
+//
+// Returns -
+// 1. CCIPLane for NetworkA --> NetworkB
+// 2. If bidirectional is true, CCIPLane for NetworkB --> NetworkA
+// 3. If configureCLNode is true, the tearDown func to call when environment needs to be destroyed
+func CCIPDefaultTestSetUp(
+ t *testing.T,
+ lggr *zerolog.Logger,
+ envName string,
+ tokenDeployerFns []blockchain.ContractDeployer,
+ testConfig *CCIPTestConfig,
+) *CCIPTestSetUpOutputs {
+ var err error
+ reportPath := "tmp_laneconfig"
+ filepath := fmt.Sprintf("./%s/tmp_%s.json", reportPath, strings.ReplaceAll(t.Name(), "/", "_"))
+ reportFile := testutils.FileNameFromPath(filepath)
+ parent, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ setUpArgs := &CCIPTestSetUpOutputs{
+ SetUpContext: parent,
+ Cfg: testConfig,
+ Reporter: testreporters.NewCCIPTestReporter(t, lggr),
+ LaneConfigFile: filepath,
+ LaneContractsByNetwork: &sync.Map{},
+ Balance: actions.NewBalanceSheet(),
+ BootstrapAdded: atomic.NewBool(false),
+ JobAddGrp: &errgroup.Group{},
+ laneMutex: &sync.Mutex{},
+ }
+
+ contractsData, err := setUpArgs.Cfg.ContractsInput.ContractsData()
+ require.NoError(t, err, "error reading existing lane config")
+
+ chainClientByChainID := setUpArgs.CreateEnvironment(lggr, envName, reportPath)
+ // if test is run in remote runner, register a clean-up to copy the laneconfig file
+ if value, set := os.LookupEnv(config.EnvVarJobImage); set && value != "" &&
+ (setUpArgs.Env != nil && setUpArgs.Env.K8Env != nil) &&
+ pointer.GetBool(setUpArgs.Cfg.TestGroupInput.StoreLaneConfig) {
+ t.Cleanup(func() {
+ path := fmt.Sprintf("reports/%s/%s", reportPath, reportFile)
+ dir, err := os.Getwd()
+ require.NoError(t, err)
+ destPath := fmt.Sprintf("%s/%s", dir, reportFile)
+ lggr.Info().Str("srcPath", path).Str("dstPath", destPath).Msg("copying lane config")
+ err = setUpArgs.Env.K8Env.CopyFromPod("app=runner-data",
+ "remote-test-runner-data-files", path, destPath)
+ require.NoError(t, err, "error getting lane config")
+ })
+ }
+ if setUpArgs.Env != nil {
+ ccipEnv := setUpArgs.Env
+ if ccipEnv.K8Env != nil && ccipEnv.K8Env.WillUseRemoteRunner() {
+ return setUpArgs
+ }
+ }
+
+ setUpArgs.LaneConfig, err = laneconfig.ReadLanesFromExistingDeployment(contractsData)
+ require.NoError(t, err)
+
+ if setUpArgs.LaneConfig == nil {
+ setUpArgs.LaneConfig = &laneconfig.Lanes{LaneConfigs: make(map[string]*laneconfig.LaneConfig)}
+ }
+ laneCfgFile, err := os.Stat(setUpArgs.LaneConfigFile)
+ if err == nil && laneCfgFile.Size() > 0 {
+ // remove the existing lane config file
+ err = os.Remove(setUpArgs.LaneConfigFile)
+ require.NoError(t, err, "error while removing existing lane config file - %s", setUpArgs.LaneConfigFile)
+ }
+
+ configureCLNode := !testConfig.useExistingDeployment()
+
+ // if no of lanes per pair is greater than 1, copy common contracts from the same network
+ // if no of lanes per pair is more than 1, the networks are added into the testConfig.AllNetworks with a suffix of -
+ // for example, if no of lanes per pair is 2, and the network pairs are called "testnetA", "testnetB",
+ // the network will be added as "testnetA-1", testnetA-2","testnetB-1", testnetB-2"
+ // to deploy 2 lanes between same network pair "testnetA", "testnetB".
+ // In the following the common contracts will be copied from "testnetA" to "testnetA-1" and "testnetA-2" and
+ // from "testnetB" to "testnetB-1" and "testnetB-2"
+ for n := range testConfig.AllNetworks {
+ if setUpArgs.Cfg.TestGroupInput.NoOfRoutersPerPair > 1 {
+ regex := regexp.MustCompile(`-(\d+)$`)
+ networkNameToReadCfg := regex.ReplaceAllString(n, "")
+ reuse := pointer.GetBool(testConfig.TestGroupInput.ReuseContracts)
+ // if reuse contracts is true, copy common contracts from the same network except the router contract
+ setUpArgs.LaneConfig.CopyCommonContracts(
+ networkNameToReadCfg, n,
+ reuse, testConfig.TestGroupInput.MsgDetails.IsTokenTransfer(),
+ )
+ }
+ }
+
+ // deploy all chain specific common contracts
+ chainAddGrp, _ := errgroup.WithContext(setUpArgs.SetUpContext)
+ lggr.Info().Msg("Deploying common contracts")
+
+ // If we have a token admin registry, we need to use a separate to deploy our test tokens from so that the tokens
+ // are not owned by the same account that owns the other CCIP contracts. This emulates self-serve token setups where
+ // the token owner is different from the CCIP contract owner.
+ if testConfig.useSeparateTokenDeployer() {
+ for _, net := range testConfig.AllNetworks {
+ chainClient := chainClientByChainID[net.ChainID]
+ require.NotNil(t, chainClient, "Chain client not found for chainID %d", net.ChainID)
+ require.GreaterOrEqual(t, len(chainClient.GetWallets()), 2, "The test is using a TokenAdminRegistry, and has CCIPOwnerTokens set to 'false'. The test needs a second wallet to deploy token contracts from. Please add a second wallet to the 'evm_clients' config option.")
+ tokenDeployerWallet := chainClient.GetWallets()[1]
+ // TODO: This is a total guess at how much funds we need to deploy the tokens. This could be way off, especially on live chains.
+ // There aren't a lot of good ways to estimate this though. See CCIP-2471.
+ recommendedTokenBalance := new(big.Int).Mul(big.NewInt(5e18), big.NewInt(int64(pointer.GetInt(testConfig.TestGroupInput.TokenConfig.NoOfTokensPerChain))))
+ currentTokenBalance, err := chainClient.BalanceAt(context.Background(), common.HexToAddress(tokenDeployerWallet.Address()))
+ require.NoError(t, err)
+ if currentTokenBalance.Cmp(recommendedTokenBalance) < 0 {
+ lggr.Warn().
+ Str("Token Deployer Address", tokenDeployerWallet.Address()).
+ Uint64("Current Balance", currentTokenBalance.Uint64()).
+ Uint64("Recommended Balance", recommendedTokenBalance.Uint64()).
+ Msg("Token Deployer wallet may be underfunded. Please ensure it has enough funds to deploy the tokens.")
+ }
+ }
+ }
+
+ for _, net := range testConfig.AllNetworks {
+ chainClient := chainClientByChainID[net.ChainID]
+ net := net
+ net.HTTPURLs = chainClient.GetNetworkConfig().HTTPURLs
+ net.URLs = chainClient.GetNetworkConfig().URLs
+ chainAddGrp.Go(func() error {
+ return setUpArgs.DeployChainContracts(
+ lggr, chainClient, net,
+ pointer.GetInt(testConfig.TestGroupInput.TokenConfig.NoOfTokensPerChain),
+ tokenDeployerFns,
+ )
+ })
+ }
+ require.NoError(t, chainAddGrp.Wait(), "Deploying common contracts shouldn't fail")
+
+ // set up mock server for price pipeline and usdc attestation if not using existing deployment
+ if !pointer.GetBool(setUpArgs.Cfg.TestGroupInput.ExistingDeployment) {
+ var killgrave *ctftestenv.Killgrave
+ if setUpArgs.Env.LocalCluster != nil {
+ killgrave = setUpArgs.Env.LocalCluster.MockAdapter
+ }
+ if setUpArgs.Cfg.TestGroupInput.TokenConfig.IsPipelineSpec() {
+ // set up mock server for price pipeline. need to set it once for all the lanes as the price pipeline path uses
+ // regex to match the path for all tokens across all lanes
+ actions.SetMockserverWithTokenPriceValue(killgrave, setUpArgs.Env.MockServer)
+ }
+ if pointer.GetBool(setUpArgs.Cfg.TestGroupInput.USDCMockDeployment) {
+ // if it's a new USDC deployment, set up mock server for attestation,
+ // we need to set it only once for all the lanes as the attestation path uses regex to match the path for
+ // all messages across all lanes
+ err = actions.SetMockServerWithUSDCAttestation(killgrave, setUpArgs.Env.MockServer)
+ require.NoError(t, err, "failed to set up mock server for attestation")
+ }
+ }
+ // deploy all lane specific contracts
+ lggr.Info().Msg("Deploying lane specific contracts")
+ laneAddGrp, _ := errgroup.WithContext(setUpArgs.SetUpContext)
+ // for memory management set a batch size for active lane deployment group
+ laneAddGrp.SetLimit(200)
+ for _, networkPair := range testConfig.NetworkPairs {
+ n := networkPair
+ var ok bool
+ n.ChainClientA, ok = chainClientByChainID[n.NetworkA.ChainID]
+ require.True(t, ok, "Chain client for chainID %d not found", n.NetworkA.ChainID)
+ n.ChainClientB, ok = chainClientByChainID[n.NetworkB.ChainID]
+ require.True(t, ok, "Chain client for chainID %d not found", n.NetworkB.ChainID)
+
+ n.NetworkA.HTTPURLs = n.ChainClientA.GetNetworkConfig().HTTPURLs
+ n.NetworkA.URLs = n.ChainClientA.GetNetworkConfig().URLs
+ n.NetworkB.HTTPURLs = n.ChainClientB.GetNetworkConfig().HTTPURLs
+ n.NetworkB.URLs = n.ChainClientB.GetNetworkConfig().URLs
+
+ laneAddGrp.Go(func() error {
+ return setUpArgs.AddLanesForNetworkPair(
+ lggr, n.NetworkA, n.NetworkB,
+ chainClientByChainID[n.NetworkA.ChainID], chainClientByChainID[n.NetworkB.ChainID],
+ )
+ })
+ }
+ require.NoError(t, laneAddGrp.Wait())
+ err = laneconfig.WriteLanesToJSON(setUpArgs.LaneConfigFile, setUpArgs.LaneConfig)
+ require.NoError(t, err)
+
+ require.Equal(t, len(setUpArgs.Lanes), len(testConfig.NetworkPairs),
+ "Number of bi-directional lanes should be equal to number of network pairs")
+ // only required for env set up
+ setUpArgs.LaneContractsByNetwork = nil
+
+ if configureCLNode {
+ // wait for all jobs to get created
+ lggr.Info().Msg("Waiting for jobs to be created")
+ require.NoError(t, setUpArgs.JobAddGrp.Wait(), "Creating jobs shouldn't fail")
+ // wait for price updates to be available
+ setUpArgs.WaitForPriceUpdates()
+ if isLeaderLaneFeatureEnabled(lggr) && !pointer.GetBool(setUpArgs.Cfg.TestGroupInput.ExistingDeployment) {
+ require.NoError(t, setUpArgs.CheckGasUpdateTransaction(lggr), "gas update transaction check shouldn't fail")
+ }
+ // if dynamic price update is required
+ if setUpArgs.Cfg.TestGroupInput.TokenConfig.IsDynamicPriceUpdate() {
+ require.NoError(t, setUpArgs.SetupDynamicTokenPriceUpdates(), "setting up dynamic price update should not fail")
+ }
+ }
+
+ // start event watchers for all lanes
+ setUpArgs.StartEventWatchers()
+ // now that lane configs are already dumped to file, we can clean up the lane config map
+ setUpArgs.LaneConfig = nil
+ setUpArgs.TearDown = func() error {
+ var errs error
+ for _, lanes := range setUpArgs.Lanes {
+ // if existing deployment is true, don't attempt to pay ccip fees
+ err := lanes.ForwardLane.CleanUp(configureCLNode)
+ if err != nil {
+ errs = multierr.Append(errs, err)
+ }
+ if lanes.ReverseLane != nil {
+ // if existing deployment is true, don't attempt to pay ccip fees
+ err := lanes.ReverseLane.CleanUp(configureCLNode)
+ if err != nil {
+ errs = multierr.Append(errs, err)
+ }
+ }
+ }
+ return errs
+ }
+ lggr.Info().Msg("Test setup completed")
+ return setUpArgs
+}
+
+// CreateEnvironment creates the environment for the test and registers the test clean-up function to tear down the set-up environment
+// It returns the map of chainID to EVMClient
+func (o *CCIPTestSetUpOutputs) CreateEnvironment(
+ lggr *zerolog.Logger,
+ envName string,
+ reportPath string,
+) map[int64]blockchain.EVMClient {
+ var (
+ testConfig = o.Cfg
+ t = o.Cfg.Test
+
+ ccipEnv *actions.CCIPTestEnv
+ k8Env *environment.Environment
+ err error
+ chains []blockchain.EVMClient
+ local *test_env.CLClusterTestEnv
+ deployCL func() error
+ )
+
+ envConfig := createEnvironmentConfig(t, envName, testConfig, reportPath)
+
+ configureCLNode := !testConfig.useExistingDeployment() || pointer.GetString(testConfig.EnvInput.EnvToConnect) != ""
+ namespace := ""
+ if testConfig.TestGroupInput.LoadProfile != nil {
+ namespace = testConfig.TestGroupInput.LoadProfile.TestRunName
+ }
+ require.False(t, testConfig.localCluster() && testConfig.ExistingCLCluster(),
+ "local cluster and existing cluster cannot be true at the same time")
+ // if it's a new deployment, deploy the env
+ // Or if EnvToConnect is given connect to that k8 environment
+ if configureCLNode {
+ if !testConfig.ExistingCLCluster() {
+ // if it's a local cluster, deploy the local cluster in docker
+ if testConfig.localCluster() {
+ local, deployCL = DeployLocalCluster(t, testConfig)
+ ccipEnv = &actions.CCIPTestEnv{
+ LocalCluster: local,
+ }
+ namespace = "local-docker-deployment"
+ } else {
+ // Otherwise, deploy the k8s env
+ lggr.Info().Msg("Deploying test environment")
+ // deploy the env if configureCLNode is true
+ k8Env = DeployEnvironments(t, envConfig, testConfig)
+ ccipEnv = &actions.CCIPTestEnv{K8Env: k8Env}
+ namespace = ccipEnv.K8Env.Cfg.Namespace
+ }
+ } else {
+ // if there is already a cluster, use the existing cluster to connect to the nodes
+ ccipEnv = &actions.CCIPTestEnv{}
+ mockserverURL := pointer.GetString(testConfig.EnvInput.Mockserver)
+ require.NotEmpty(t, mockserverURL, "mockserver URL cannot be nil")
+ ccipEnv.MockServer = ctfClient.NewMockserverClient(&ctfClient.MockserverConfig{
+ LocalURL: mockserverURL,
+ ClusterURL: mockserverURL,
+ })
+ }
+ ccipEnv.CLNodeWithKeyReady, _ = errgroup.WithContext(o.SetUpContext)
+ o.Env = ccipEnv
+ if ccipEnv.K8Env != nil && ccipEnv.K8Env.WillUseRemoteRunner() {
+ return nil
+ }
+ } else {
+ // if configureCLNode is false it means we don't need to deploy any additional pods,
+ // use a placeholder env to create just the remote runner in it.
+ if value, set := os.LookupEnv(config.EnvVarJobImage); set && value != "" {
+ k8Env = environment.New(envConfig)
+ err = k8Env.Run()
+ require.NoErrorf(t, err, "error creating environment remote runner")
+ o.Env = &actions.CCIPTestEnv{K8Env: k8Env}
+ if k8Env.WillUseRemoteRunner() {
+ return nil
+ }
+ }
+ }
+ if o.Cfg.TestGroupInput.LoadProfile != nil {
+ o.Cfg.TestGroupInput.LoadProfile.SetTestRunName(namespace)
+ }
+ chainByChainID := make(map[int64]blockchain.EVMClient)
+ if pointer.GetBool(testConfig.TestGroupInput.LocalCluster) {
+ require.NotNil(t, ccipEnv.LocalCluster, "Local cluster shouldn't be nil")
+ for _, n := range ccipEnv.LocalCluster.EVMNetworks {
+ if evmClient, err := blockchain.NewEVMClientFromNetwork(*n, *lggr); err == nil {
+ chainByChainID[evmClient.GetChainID().Int64()] = evmClient
+ chains = append(chains, evmClient)
+ } else {
+ lggr.Error().Err(err).Msgf("EVMClient for chainID %d not found", n.ChainID)
+ }
+ }
+ } else {
+ for _, n := range testConfig.SelectedNetworks {
+ if _, ok := chainByChainID[n.ChainID]; ok {
+ continue
+ }
+ var ec blockchain.EVMClient
+ if k8Env == nil {
+ ec, err = blockchain.ConnectEVMClient(n, *lggr)
+ } else {
+ log.Info().Interface("urls", k8Env.URLs).Msg("URLs")
+ ec, err = blockchain.NewEVMClient(n, k8Env, *lggr)
+ }
+ require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail")
+ chains = append(chains, ec)
+ chainByChainID[n.ChainID] = ec
+ }
+ }
+ if configureCLNode {
+ ccipEnv.CLNodeWithKeyReady.Go(func() error {
+ var totalNodes int
+ if !o.Cfg.ExistingCLCluster() {
+ if ccipEnv.LocalCluster != nil {
+ err = deployCL()
+ if err != nil {
+ return err
+ }
+ }
+ err = ccipEnv.ConnectToDeployedNodes()
+ if err != nil {
+ return fmt.Errorf("error connecting to chainlink nodes: %w", err)
+ }
+ totalNodes = pointer.GetInt(testConfig.EnvInput.NewCLCluster.NoOfNodes)
+ } else {
+ totalNodes = pointer.GetInt(testConfig.EnvInput.ExistingCLCluster.NoOfNodes)
+ err = ccipEnv.ConnectToExistingNodes(o.Cfg.EnvInput)
+ if err != nil {
+ return fmt.Errorf("error deploying and connecting to chainlink nodes: %w", err)
+ }
+ }
+ err = ccipEnv.SetUpNodeKeysAndFund(lggr, big.NewFloat(testConfig.TestGroupInput.NodeFunding), chains)
+ if err != nil {
+ return fmt.Errorf("error setting up nodes and keys %w", err)
+ }
+ // first node is the bootstrapper
+ ccipEnv.CommitNodeStartIndex = 1
+ ccipEnv.ExecNodeStartIndex = 1
+ ccipEnv.NumOfCommitNodes = testConfig.TestGroupInput.NoOfCommitNodes
+ ccipEnv.NumOfExecNodes = ccipEnv.NumOfCommitNodes
+ if !pointer.GetBool(testConfig.TestGroupInput.CommitAndExecuteOnSameDON) {
+ if len(ccipEnv.CLNodesWithKeys) < 11 {
+ return fmt.Errorf("not enough CL nodes for separate commit and execution nodes")
+ }
+ if testConfig.TestGroupInput.NoOfCommitNodes >= totalNodes {
+ return fmt.Errorf("number of commit nodes can not be greater than total number of nodes in DON")
+ }
+ // first two nodes are reserved for bootstrap commit and bootstrap exec
+ ccipEnv.CommitNodeStartIndex = 2
+ ccipEnv.ExecNodeStartIndex = 2 + testConfig.TestGroupInput.NoOfCommitNodes
+ ccipEnv.NumOfExecNodes = totalNodes - (2 + testConfig.TestGroupInput.NoOfCommitNodes)
+ if ccipEnv.NumOfExecNodes < 4 {
+ return fmt.Errorf("insufficient number of exec nodes")
+ }
+ }
+ ccipEnv.NumOfAllowedFaultyExec = (ccipEnv.NumOfExecNodes - 1) / 3
+ ccipEnv.NumOfAllowedFaultyCommit = (ccipEnv.NumOfCommitNodes - 1) / 3
+ return nil
+ })
+ }
+
+ t.Cleanup(func() {
+ if configureCLNode {
+ if ccipEnv.LocalCluster != nil {
+ err := ccipEnv.LocalCluster.Terminate()
+ require.NoError(t, err, "Local cluster termination shouldn't fail")
+ require.NoError(t, o.Reporter.SendReport(t, namespace, false), "Aggregating and sending report shouldn't fail")
+ return
+ }
+ if pointer.GetBool(testConfig.TestGroupInput.KeepEnvAlive) || testConfig.ExistingCLCluster() {
+ require.NoError(t, o.Reporter.SendReport(t, namespace, true), "Aggregating and sending report shouldn't fail")
+ return
+ }
+ lggr.Info().Msg("Tearing down the environment")
+ err = integrationactions.TeardownSuite(t, nil, ccipEnv.K8Env, ccipEnv.CLNodes, o.Reporter, zapcore.DPanicLevel, o.Cfg.EnvInput)
+ require.NoError(t, err, "Environment teardown shouldn't fail")
+ } else {
+ //just send the report
+ require.NoError(t, o.Reporter.SendReport(t, namespace, true), "Aggregating and sending report shouldn't fail")
+ }
+ })
+ return chainByChainID
+}
+
+func createEnvironmentConfig(t *testing.T, envName string, testConfig *CCIPTestConfig, reportPath string) *environment.Config {
+ envConfig := &environment.Config{
+ NamespacePrefix: envName,
+ Test: t,
+ // PreventPodEviction: true, //TODO: enable this once we have a way to handle pod eviction
+ }
+ if pointer.GetBool(testConfig.TestGroupInput.StoreLaneConfig) {
+ envConfig.ReportPath = reportPath
+ }
+ // if there is already existing namespace, no need to update any manifest there, we just connect to it
+ existingEnv := pointer.GetString(testConfig.EnvInput.EnvToConnect)
+ if existingEnv != "" {
+ envConfig.Namespace = existingEnv
+ envConfig.NamespacePrefix = ""
+ envConfig.SkipManifestUpdate = true
+ envConfig.RunnerName = fmt.Sprintf("%s-%s", environment.REMOTE_RUNNER_NAME, uuid.NewString()[0:5])
+ }
+ if testConfig.EnvInput.TTL != nil {
+ envConfig.TTL = testConfig.EnvInput.TTL.Duration()
+ }
+ if testConfig.TestGroupInput.LoadProfile != nil && testConfig.TestGroupInput.LoadProfile.TestDuration != nil {
+ approxDur := testConfig.TestGroupInput.LoadProfile.TestDuration.Duration() + 3*time.Hour
+ if envConfig.TTL < approxDur {
+ envConfig.TTL = approxDur
+ }
+ }
+ return envConfig
+}
diff --git a/integration-tests/ccip-tests/testsetups/test_env.go b/integration-tests/ccip-tests/testsetups/test_env.go
new file mode 100644
index 00000000000..63018c9fe44
--- /dev/null
+++ b/integration-tests/ccip-tests/testsetups/test_env.go
@@ -0,0 +1,594 @@
+package testsetups
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+ "testing"
+
+ "github.com/AlekSi/pointer"
+ "github.com/pkg/errors"
+ "github.com/rs/zerolog"
+ "github.com/stretchr/testify/require"
+
+ ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
+ ctf_config_types "github.com/smartcontractkit/chainlink-testing-framework/config/types"
+ "github.com/smartcontractkit/chainlink-testing-framework/networks"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/foundry"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver"
+ mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+ ctftestenv "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink"
+ "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+ k8config "github.com/smartcontractkit/chainlink-testing-framework/k8s/config"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/actions"
+ "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/types/config/node"
+ "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env"
+ integrationnodes "github.com/smartcontractkit/chainlink/integration-tests/types/config/node"
+ evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml"
+ corechainlink "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
+)
+
+func SetResourceProfile(cpu, mem string) map[string]interface{} {
+ return map[string]interface{}{
+ "requests": map[string]interface{}{
+ "cpu": cpu,
+ "memory": mem,
+ },
+ "limits": map[string]interface{}{
+ "cpu": cpu,
+ "memory": mem,
+ },
+ }
+}
+
+func setNodeConfig(nets []blockchain.EVMNetwork, nodeConfig, commonChain string, configByChain map[string]string) (*corechainlink.Config, string, error) {
+ var tomlCfg *corechainlink.Config
+ var err error
+ var commonChainConfig *evmcfg.Chain
+ if commonChain != "" {
+ err = config.DecodeTOML(bytes.NewReader([]byte(commonChain)), &commonChainConfig)
+ if err != nil {
+ return nil, "", err
+ }
+ }
+ configByChainMap := make(map[int64]evmcfg.Chain)
+ for k, v := range configByChain {
+ var chain evmcfg.Chain
+ err = config.DecodeTOML(bytes.NewReader([]byte(v)), &chain)
+ if err != nil {
+ return nil, "", err
+ }
+ chainId, err := strconv.ParseInt(k, 10, 64)
+ if err != nil {
+ return nil, "", err
+ }
+ configByChainMap[chainId] = chain
+ }
+ if nodeConfig == "" {
+ tomlCfg = integrationnodes.NewConfig(
+ integrationnodes.NewBaseConfig(),
+ node.WithPrivateEVMs(nets, commonChainConfig, configByChainMap))
+ } else {
+ tomlCfg, err = node.NewConfigFromToml([]byte(nodeConfig), node.WithPrivateEVMs(nets, commonChainConfig, configByChainMap))
+ if err != nil {
+ return nil, "", err
+ }
+ }
+ tomlStr, err := tomlCfg.TOMLString()
+ return tomlCfg, tomlStr, err
+}
+
+func ChainlinkPropsForUpdate(
+ t *testing.T,
+ testInputs *CCIPTestConfig,
+) (map[string]any, int) {
+ updateProps := make(map[string]any)
+ upgradeImage := pointer.GetString(testInputs.EnvInput.NewCLCluster.Common.ChainlinkUpgradeImage.Image)
+ upgradeTag := pointer.GetString(testInputs.EnvInput.NewCLCluster.Common.ChainlinkUpgradeImage.Version)
+ noOfNodesToUpgrade := 0
+ if len(testInputs.EnvInput.NewCLCluster.Nodes) > 0 {
+ var nodesMap []map[string]any
+ for _, clNode := range testInputs.EnvInput.NewCLCluster.Nodes {
+ if !pointer.GetBool(clNode.NeedsUpgrade) {
+ continue
+ }
+ upgradeImage = pointer.GetString(clNode.ChainlinkUpgradeImage.Image)
+ upgradeTag = pointer.GetString(clNode.ChainlinkUpgradeImage.Version)
+ if upgradeImage == "" || upgradeTag == "" {
+ continue
+ }
+ nodeConfig := clNode.BaseConfigTOML
+ commonChainConfig := clNode.CommonChainConfigTOML
+ chainConfigByChain := clNode.ChainConfigTOMLByChain
+ if nodeConfig == "" {
+ nodeConfig = testInputs.EnvInput.NewCLCluster.Common.BaseConfigTOML
+ }
+ if commonChainConfig == "" {
+ commonChainConfig = testInputs.EnvInput.NewCLCluster.Common.CommonChainConfigTOML
+ }
+ if chainConfigByChain == nil {
+ chainConfigByChain = testInputs.EnvInput.NewCLCluster.Common.ChainConfigTOMLByChain
+ }
+
+ _, tomlStr, err := setNodeConfig(
+ testInputs.SelectedNetworks,
+ nodeConfig, commonChainConfig, chainConfigByChain,
+ )
+ require.NoError(t, err)
+ nodesMap = append(nodesMap, map[string]any{
+ "name": clNode.Name,
+ "chainlink": map[string]any{
+ "image": map[string]any{
+ "image": upgradeImage,
+ "version": upgradeTag,
+ },
+ },
+ "toml": tomlStr,
+ })
+ noOfNodesToUpgrade++
+ }
+ updateProps["nodes"] = nodesMap
+ } else {
+ if upgradeImage == "" || upgradeTag == "" {
+ return nil, 0
+ }
+ updateProps["chainlink"] = map[string]interface{}{
+ "image": map[string]interface{}{
+ "image": upgradeImage,
+ "version": upgradeTag,
+ },
+ }
+ _, tomlStr, err := setNodeConfig(
+ testInputs.SelectedNetworks,
+ testInputs.EnvInput.NewCLCluster.Common.BaseConfigTOML,
+ testInputs.EnvInput.NewCLCluster.Common.CommonChainConfigTOML,
+ testInputs.EnvInput.NewCLCluster.Common.ChainConfigTOMLByChain,
+ )
+ require.NoError(t, err)
+ updateProps["toml"] = tomlStr
+ noOfNodesToUpgrade = pointer.GetInt(testInputs.EnvInput.NewCLCluster.NoOfNodes)
+ }
+ return updateProps, noOfNodesToUpgrade
+}
+
+func ChainlinkChart(
+ t *testing.T,
+ testInputs *CCIPTestConfig,
+ nets []blockchain.EVMNetwork,
+) environment.ConnectedChart {
+ require.NotNil(t, testInputs.EnvInput.NewCLCluster.Common, "Chainlink Common config is not specified")
+ clProps := make(map[string]interface{})
+ clProps["prometheus"] = true
+ var formattedArgs []string
+ if len(testInputs.EnvInput.NewCLCluster.DBArgs) > 0 {
+ for _, arg := range testInputs.EnvInput.NewCLCluster.DBArgs {
+ formattedArgs = append(formattedArgs, "-c")
+ formattedArgs = append(formattedArgs, arg)
+ }
+ }
+ clProps["db"] = map[string]interface{}{
+ "resources": SetResourceProfile(testInputs.EnvInput.NewCLCluster.DBCPU, testInputs.EnvInput.NewCLCluster.DBMemory),
+ "additionalArgs": formattedArgs,
+ "stateful": pointer.GetBool(testInputs.EnvInput.NewCLCluster.IsStateful),
+ "capacity": testInputs.EnvInput.NewCLCluster.DBCapacity,
+ "storageClassName": pointer.GetString(testInputs.EnvInput.NewCLCluster.DBStorageClass),
+ "enablePrometheusPostgresExporter": pointer.GetBool(testInputs.EnvInput.NewCLCluster.PromPgExporter),
+ "image": map[string]any{
+ "image": testInputs.EnvInput.NewCLCluster.Common.DBImage,
+ "version": testInputs.EnvInput.NewCLCluster.Common.DBTag,
+ },
+ }
+ clProps["chainlink"] = map[string]interface{}{
+ "resources": SetResourceProfile(testInputs.EnvInput.NewCLCluster.NodeCPU, testInputs.EnvInput.NewCLCluster.NodeMemory),
+ "image": map[string]any{
+ "image": pointer.GetString(testInputs.EnvInput.NewCLCluster.Common.ChainlinkImage.Image),
+ "version": pointer.GetString(testInputs.EnvInput.NewCLCluster.Common.ChainlinkImage.Version),
+ },
+ }
+
+ require.NotNil(t, testInputs.EnvInput, "no env test input specified")
+
+ if len(testInputs.EnvInput.NewCLCluster.Nodes) > 0 {
+ var nodesMap []map[string]any
+ for _, clNode := range testInputs.EnvInput.NewCLCluster.Nodes {
+ nodeConfig := clNode.BaseConfigTOML
+ commonChainConfig := clNode.CommonChainConfigTOML
+ chainConfigByChain := clNode.ChainConfigTOMLByChain
+ if nodeConfig == "" {
+ nodeConfig = testInputs.EnvInput.NewCLCluster.Common.BaseConfigTOML
+ }
+ if commonChainConfig == "" {
+ commonChainConfig = testInputs.EnvInput.NewCLCluster.Common.CommonChainConfigTOML
+ }
+ if chainConfigByChain == nil {
+ chainConfigByChain = testInputs.EnvInput.NewCLCluster.Common.ChainConfigTOMLByChain
+ }
+
+ _, tomlStr, err := setNodeConfig(nets, nodeConfig, commonChainConfig, chainConfigByChain)
+ require.NoError(t, err)
+ nodesMap = append(nodesMap, map[string]any{
+ "name": clNode.Name,
+ "chainlink": map[string]any{
+ "image": map[string]any{
+ "image": pointer.GetString(clNode.ChainlinkImage.Image),
+ "version": pointer.GetString(clNode.ChainlinkImage.Version),
+ },
+ },
+ "db": map[string]any{
+ "image": map[string]any{
+ "image": clNode.DBImage,
+ "version": clNode.DBTag,
+ },
+ "storageClassName": "gp3",
+ },
+ "toml": tomlStr,
+ })
+ }
+ clProps["nodes"] = nodesMap
+ return chainlink.New(0, clProps)
+ }
+ clProps["replicas"] = pointer.GetInt(testInputs.EnvInput.NewCLCluster.NoOfNodes)
+ _, tomlStr, err := setNodeConfig(
+ nets,
+ testInputs.EnvInput.NewCLCluster.Common.BaseConfigTOML,
+ testInputs.EnvInput.NewCLCluster.Common.CommonChainConfigTOML,
+ testInputs.EnvInput.NewCLCluster.Common.ChainConfigTOMLByChain,
+ )
+ require.NoError(t, err)
+ clProps["toml"] = tomlStr
+ return chainlink.New(0, clProps)
+}
+
+func DeployLocalCluster(
+ t *testing.T,
+ testInputs *CCIPTestConfig,
+) (*test_env.CLClusterTestEnv, func() error) {
+ selectedNetworks := testInputs.SelectedNetworks
+
+ privateEthereumNetworks := []*ctf_config.EthereumNetworkConfig{}
+ for _, network := range testInputs.EnvInput.PrivateEthereumNetworks {
+ privateEthereumNetworks = append(privateEthereumNetworks, network)
+
+ for _, networkCfg := range networks.MustGetSelectedNetworkConfig(testInputs.EnvInput.Network) {
+ for _, key := range networkCfg.PrivateKeys {
+ address, err := conversions.PrivateKeyHexToAddress(key)
+ require.NoError(t, err, "failed to convert private key to address: %w", err)
+ network.EthereumChainConfig.AddressesToFund = append(
+ network.EthereumChainConfig.AddressesToFund, address.Hex(),
+ )
+ }
+ }
+ }
+
+ if len(selectedNetworks) > len(privateEthereumNetworks) {
+ seen := make(map[int64]bool)
+ missing := []blockchain.EVMNetwork{}
+
+ for _, network := range privateEthereumNetworks {
+ seen[int64(network.EthereumChainConfig.ChainID)] = true
+ }
+
+ for _, network := range selectedNetworks {
+ if !seen[network.ChainID] {
+ missing = append(missing, network)
+ }
+ }
+
+ for _, network := range missing {
+ chainConfig := &ctf_config.EthereumChainConfig{}
+ err := chainConfig.Default()
+ if err != nil {
+ require.NoError(t, err, "failed to get default chain config: %w", err)
+ } else {
+ chainConfig.ChainID = int(network.ChainID)
+ eth1 := ctf_config_types.EthereumVersion_Eth1
+ geth := ctf_config_types.ExecutionLayer_Geth
+
+ privateEthereumNetworks = append(privateEthereumNetworks, &ctf_config.EthereumNetworkConfig{
+ EthereumVersion: ð1,
+ ExecutionLayer: &geth,
+ EthereumChainConfig: chainConfig,
+ })
+ }
+ }
+
+ require.Equal(t, len(selectedNetworks), len(privateEthereumNetworks), "failed to create undefined selected networks. Maybe some of them had the same chain ids?")
+ }
+
+ env, err := test_env.NewCLTestEnvBuilder().
+ WithTestConfig(testInputs.EnvInput).
+ WithTestInstance(t).
+ WithPrivateEthereumNetworks(privateEthereumNetworks).
+ WithMockAdapter().
+ WithoutCleanup().
+ Build()
+ require.NoError(t, err)
+ // the builder builds network with a static network config, we don't want that.
+ env.EVMNetworks = []*blockchain.EVMNetwork{}
+ for i, networkCfg := range selectedNetworks {
+ rpcProvider, err := env.GetRpcProvider(networkCfg.ChainID)
+ require.NoError(t, err, "Error getting rpc provider")
+ selectedNetworks[i].URLs = rpcProvider.PrivateWsUrsl()
+ selectedNetworks[i].HTTPURLs = rpcProvider.PrivateHttpUrls()
+ newNetwork := networkCfg
+ newNetwork.URLs = rpcProvider.PublicWsUrls()
+ newNetwork.HTTPURLs = rpcProvider.PublicHttpUrls()
+ env.EVMNetworks = append(env.EVMNetworks, &newNetwork)
+ }
+ testInputs.SelectedNetworks = selectedNetworks
+
+ // a func to start the CL nodes asynchronously
+ deployCL := func() error {
+ noOfNodes := pointer.GetInt(testInputs.EnvInput.NewCLCluster.NoOfNodes)
+ // if individual nodes are specified, then deploy them with specified configs
+ if len(testInputs.EnvInput.NewCLCluster.Nodes) > 0 {
+ for _, clNode := range testInputs.EnvInput.NewCLCluster.Nodes {
+ toml, _, err := setNodeConfig(
+ selectedNetworks,
+ clNode.BaseConfigTOML,
+ clNode.CommonChainConfigTOML,
+ clNode.ChainConfigTOMLByChain,
+ )
+ if err != nil {
+ return err
+ }
+ ccipNode, err := test_env.NewClNode(
+ []string{env.DockerNetwork.Name},
+ pointer.GetString(clNode.ChainlinkImage.Image),
+ pointer.GetString(clNode.ChainlinkImage.Version),
+ toml,
+ env.LogStream,
+ test_env.WithPgDBOptions(
+ ctftestenv.WithPostgresImageName(clNode.DBImage),
+ ctftestenv.WithPostgresImageVersion(clNode.DBTag),
+ ),
+ )
+ if err != nil {
+ return err
+ }
+ ccipNode.SetTestLogger(t)
+ env.ClCluster.Nodes = append(env.ClCluster.Nodes, ccipNode)
+ }
+ } else {
+ // if no individual nodes are specified, then deploy the number of nodes specified in the env input with common config
+ for i := 0; i < noOfNodes; i++ {
+ toml, _, err := setNodeConfig(
+ selectedNetworks,
+ testInputs.EnvInput.NewCLCluster.Common.BaseConfigTOML,
+ testInputs.EnvInput.NewCLCluster.Common.CommonChainConfigTOML,
+ testInputs.EnvInput.NewCLCluster.Common.ChainConfigTOMLByChain,
+ )
+ if err != nil {
+ return err
+ }
+ ccipNode, err := test_env.NewClNode(
+ []string{env.DockerNetwork.Name},
+ pointer.GetString(testInputs.EnvInput.NewCLCluster.Common.ChainlinkImage.Image),
+ pointer.GetString(testInputs.EnvInput.NewCLCluster.Common.ChainlinkImage.Version),
+ toml,
+ env.LogStream,
+ test_env.WithPgDBOptions(
+ ctftestenv.WithPostgresImageName(testInputs.EnvInput.NewCLCluster.Common.DBImage),
+ ctftestenv.WithPostgresImageVersion(testInputs.EnvInput.NewCLCluster.Common.DBTag),
+ ),
+ )
+ if err != nil {
+ return err
+ }
+ ccipNode.SetTestLogger(t)
+ env.ClCluster.Nodes = append(env.ClCluster.Nodes, ccipNode)
+ }
+ }
+ return env.ClCluster.Start()
+ }
+ return env, deployCL
+}
+
+// UpgradeNodes restarts chainlink nodes in the given range with upgrade image
+// startIndex and endIndex are inclusive
+func UpgradeNodes(
+ t *testing.T,
+ lggr *zerolog.Logger,
+ testInputs *CCIPTestConfig,
+ ccipEnv *actions.CCIPTestEnv,
+) error {
+ lggr.Info().
+ Msg("Upgrading node version")
+ // if the test is running on local docker
+ if pointer.GetBool(testInputs.TestGroupInput.LocalCluster) {
+ env := ccipEnv.LocalCluster
+ for i, clNode := range env.ClCluster.Nodes {
+ upgradeImage := pointer.GetString(testInputs.EnvInput.NewCLCluster.Common.ChainlinkUpgradeImage.Image)
+ upgradeTag := pointer.GetString(testInputs.EnvInput.NewCLCluster.Common.ChainlinkUpgradeImage.Version)
+ // if individual node upgrade image is provided, use that
+ if len(testInputs.EnvInput.NewCLCluster.Nodes) > 0 {
+ if i < len(testInputs.EnvInput.NewCLCluster.Nodes) {
+ upgradeImage = pointer.GetString(testInputs.EnvInput.NewCLCluster.Nodes[i].ChainlinkUpgradeImage.Image)
+ upgradeTag = pointer.GetString(testInputs.EnvInput.NewCLCluster.Nodes[i].ChainlinkUpgradeImage.Version)
+ }
+ }
+ if upgradeImage == "" || upgradeTag == "" {
+ continue
+ }
+ err := clNode.UpgradeVersion(upgradeImage, upgradeTag)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ // if the test is running on k8s
+ k8Env := ccipEnv.K8Env
+ if k8Env == nil {
+ return errors.New("k8s environment is nil, cannot restart nodes")
+ }
+ props, noOfNodesToUpgrade := ChainlinkPropsForUpdate(t, testInputs)
+ chartName := ccipEnv.CLNodes[0].ChartName
+ // explicitly set the env var into false to allow manifest update
+ // if tests are run in remote runner, it might be set to true to disable manifest update
+ err := os.Setenv(k8config.EnvVarSkipManifestUpdate, "false")
+ if err != nil {
+ return err
+ }
+ k8Env.Cfg.SkipManifestUpdate = false
+ lggr.Info().
+ Str("Chart Name", chartName).
+ Interface("Upgrade Details", props).
+ Msg("Upgrading Chainlink Node")
+ k8Env, err = k8Env.UpdateHelm(chartName, props)
+ if err != nil {
+ return err
+ }
+ err = k8Env.RunUpdated(noOfNodesToUpgrade)
+ // Run the new environment and wait for changes to show
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// DeployEnvironments deploys K8 env for CCIP tests. For tests running on simulated geth it deploys -
+// 1. two simulated geth network in non-dev mode
+// 2. mockserver ( to set mock price feed details)
+// 3. chainlink nodes
+func DeployEnvironments(
+ t *testing.T,
+ envconfig *environment.Config,
+ testInputs *CCIPTestConfig,
+) *environment.Environment {
+ selectedNetworks := testInputs.SelectedNetworks
+ testEnvironment := environment.New(envconfig)
+ numOfTxNodes := 1
+ var charts []string
+ for i, network := range selectedNetworks {
+ if testInputs.EnvInput.Network.AnvilConfigs != nil {
+ // if anvilconfig is specified for a network addhelm for anvil
+ if anvilConfig, exists := testInputs.EnvInput.Network.AnvilConfigs[strings.ToUpper(network.Name)]; exists {
+ charts = append(charts, foundry.ChartName)
+ if anvilConfig.BaseFee == nil {
+ anvilConfig.BaseFee = pointer.ToInt64(1000000)
+ }
+ if anvilConfig.BlockGaslimit == nil {
+ anvilConfig.BlockGaslimit = pointer.ToInt64(100000000)
+ }
+ testEnvironment.
+ AddHelm(foundry.NewVersioned("0.2.1", &foundry.Props{
+ NetworkName: network.Name,
+ Values: map[string]interface{}{
+ "fullnameOverride": actions.NetworkName(network.Name),
+ "image": map[string]interface{}{
+ "repository": "ghcr.io/foundry-rs/foundry",
+ "tag": "nightly-5ac78a9cd4b94dc53d1fe5e0f42372b28b5a7559",
+ // "tag": "nightly-ea2eff95b5c17edd3ffbdfc6daab5ce5cc80afc0",
+ },
+ "anvil": map[string]interface{}{
+ "chainId": fmt.Sprintf("%d", network.ChainID),
+ "blockTime": anvilConfig.BlockTime,
+ "forkURL": anvilConfig.URL,
+ "forkBlockNumber": anvilConfig.BlockNumber,
+ "forkRetries": anvilConfig.Retries,
+ "forkTimeout": anvilConfig.Timeout,
+ "forkComputeUnitsPerSecond": anvilConfig.ComputePerSecond,
+ "forkNoRateLimit": anvilConfig.RateLimitDisabled,
+ "blocksToKeepInMemory": anvilConfig.BlocksToKeepInMem,
+ "blockGasLimit": fmt.Sprintf("%d", pointer.GetInt64(anvilConfig.BlockGaslimit)),
+ "baseFee": fmt.Sprintf("%d", pointer.GetInt64(anvilConfig.BaseFee)),
+ },
+ "resources": GethResourceProfile,
+ "cache": map[string]interface{}{
+ "capacity": "150Gi",
+ },
+ },
+ }))
+ selectedNetworks[i].Simulated = true
+ actions.NetworkChart = foundry.ChartName
+ continue
+ }
+ }
+
+ if !network.Simulated {
+ charts = append(charts, "")
+ continue
+ }
+ charts = append(charts, strings.ReplaceAll(strings.ToLower(network.Name), " ", "-"))
+ testEnvironment.
+ AddHelm(reorg.New(&reorg.Props{
+ NetworkName: network.Name,
+ NetworkType: "simulated-geth-non-dev",
+ Values: map[string]interface{}{
+ "geth": map[string]interface{}{
+ "genesis": map[string]interface{}{
+ "networkId": fmt.Sprint(network.ChainID),
+ },
+ "tx": map[string]interface{}{
+ "replicas": strconv.Itoa(numOfTxNodes),
+ "resources": testInputs.GethResourceProfile,
+ },
+ "miner": map[string]interface{}{
+ "replicas": "0",
+ "resources": testInputs.GethResourceProfile,
+ },
+ },
+ "bootnode": map[string]interface{}{
+ "replicas": "1",
+ },
+ },
+ }))
+ }
+ if pointer.GetBool(testInputs.TestGroupInput.USDCMockDeployment) ||
+ pointer.GetBool(testInputs.TestGroupInput.TokenConfig.WithPipeline) {
+ testEnvironment.
+ AddHelm(mockservercfg.New(nil)).
+ AddHelm(mockserver.New(nil))
+ }
+ err := testEnvironment.Run()
+ require.NoError(t, err)
+
+ if testEnvironment.WillUseRemoteRunner() {
+ return testEnvironment
+ }
+ urlFinder := func(network blockchain.EVMNetwork, chart string) ([]string, []string) {
+ if !network.Simulated {
+ return network.URLs, network.HTTPURLs
+ }
+ networkName := actions.NetworkName(network.Name)
+ var internalWsURLs, internalHttpURLs []string
+ switch chart {
+ case foundry.ChartName:
+ internalWsURLs = append(internalWsURLs, fmt.Sprintf("ws://%s:8545", networkName))
+ internalHttpURLs = append(internalHttpURLs, fmt.Sprintf("http://%s:8545", networkName))
+ case networkName:
+ for i := 0; i < numOfTxNodes; i++ {
+ internalWsURLs = append(internalWsURLs, fmt.Sprintf("ws://%s-ethereum-geth:8546", networkName))
+ internalHttpURLs = append(internalHttpURLs, fmt.Sprintf("http://%s-ethereum-geth:8544", networkName))
+ }
+ default:
+ return network.URLs, network.HTTPURLs
+ }
+
+ return internalWsURLs, internalHttpURLs
+ }
+ var nets []blockchain.EVMNetwork
+ for i := range selectedNetworks {
+ nets = append(nets, selectedNetworks[i])
+ nets[i].URLs, nets[i].HTTPURLs = urlFinder(selectedNetworks[i], charts[i])
+ }
+
+ err = testEnvironment.
+ AddHelm(ChainlinkChart(t, testInputs, nets)).
+ Run()
+ require.NoError(t, err)
+ return testEnvironment
+}
diff --git a/integration-tests/ccip-tests/types/config/node/core.go b/integration-tests/ccip-tests/types/config/node/core.go
new file mode 100644
index 00000000000..eb12598f948
--- /dev/null
+++ b/integration-tests/ccip-tests/types/config/node/core.go
@@ -0,0 +1,67 @@
+package node
+
+import (
+ "bytes"
+ "fmt"
+ "math/big"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+ "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr"
+
+ "github.com/smartcontractkit/chainlink-common/pkg/config"
+
+ "github.com/smartcontractkit/chainlink/integration-tests/types/config/node"
+ itutils "github.com/smartcontractkit/chainlink/integration-tests/utils"
+ evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml"
+ ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
+ "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
+)
+
+func NewConfigFromToml(tomlConfig []byte, opts ...node.NodeConfigOpt) (*chainlink.Config, error) {
+ var cfg chainlink.Config
+ err := config.DecodeTOML(bytes.NewReader(tomlConfig), &cfg)
+ if err != nil {
+ return nil, err
+ }
+ for _, opt := range opts {
+ opt(&cfg)
+ }
+ return &cfg, nil
+}
+
+func WithPrivateEVMs(networks []blockchain.EVMNetwork, commonChainConfig *evmcfg.Chain, chainSpecificConfig map[int64]evmcfg.Chain) node.NodeConfigOpt {
+ var evmConfigs []*evmcfg.EVMConfig
+ for _, network := range networks {
+ var evmNodes []*evmcfg.Node
+ for i := range network.URLs {
+ evmNodes = append(evmNodes, &evmcfg.Node{
+ Name: ptr.Ptr(fmt.Sprintf("%s-%d", network.Name, i)),
+ WSURL: itutils.MustURL(network.URLs[i]),
+ HTTPURL: itutils.MustURL(network.HTTPURLs[i]),
+ })
+ }
+ evmConfig := &evmcfg.EVMConfig{
+ ChainID: ubig.New(big.NewInt(network.ChainID)),
+ Nodes: evmNodes,
+ Chain: evmcfg.Chain{},
+ }
+ if commonChainConfig != nil {
+ evmConfig.Chain = *commonChainConfig
+ }
+ if chainSpecificConfig == nil {
+ if overriddenChainCfg, ok := chainSpecificConfig[network.ChainID]; ok {
+ evmConfig.Chain = overriddenChainCfg
+ }
+ }
+ if evmConfig.Chain.FinalityDepth == nil && network.FinalityDepth > 0 {
+ evmConfig.Chain.FinalityDepth = ptr.Ptr(uint32(network.FinalityDepth))
+ }
+ if evmConfig.Chain.FinalityTagEnabled == nil && network.FinalityTag {
+ evmConfig.Chain.FinalityTagEnabled = ptr.Ptr(network.FinalityTag)
+ }
+ evmConfigs = append(evmConfigs, evmConfig)
+ }
+ return func(c *chainlink.Config) {
+ c.EVM = evmConfigs
+ }
+}
diff --git a/integration-tests/ccip-tests/utils/common.go b/integration-tests/ccip-tests/utils/common.go
new file mode 100644
index 00000000000..afa8158e450
--- /dev/null
+++ b/integration-tests/ccip-tests/utils/common.go
@@ -0,0 +1,32 @@
+package utils
+
+import (
+ "path/filepath"
+ "runtime"
+ "sync"
+)
+
+func ProjectRoot() string {
+ _, b, _, _ := runtime.Caller(0)
+ return filepath.Join(filepath.Dir(b), "/..")
+}
+
+// DeleteNilEntriesFromMap checks for nil entry in map, store all not-nil entries to another map and deallocates previous map
+// Deleting keys from a map actually does not delete the key, It just sets the corresponding value to nil.
+func DeleteNilEntriesFromMap(inputMap *sync.Map) *sync.Map {
+ newMap := &sync.Map{}
+ foundNil := false
+ inputMap.Range(func(key, value any) bool {
+ if value != nil {
+ newMap.Store(key, value)
+ }
+ if value == nil {
+ foundNil = true
+ }
+ return true
+ })
+ if foundNil {
+ runtime.GC()
+ }
+ return newMap
+}
diff --git a/integration-tests/ccip-tests/utils/fileutil.go b/integration-tests/ccip-tests/utils/fileutil.go
new file mode 100644
index 00000000000..43e048e1f6b
--- /dev/null
+++ b/integration-tests/ccip-tests/utils/fileutil.go
@@ -0,0 +1,63 @@
+package utils
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+
+ "github.com/rs/zerolog/log"
+)
+
+// FilesWithRegex returns all filepaths under root folder matching with regex pattern
+func FilesWithRegex(root, pattern string) ([]string, error) {
+ r, err := regexp.Compile(pattern)
+ if err != nil {
+ return nil, err
+ }
+ var filenames []string
+ err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ // Check if the file matches the regex pattern
+ if !info.IsDir() && r.MatchString(info.Name()) {
+ filenames = append(filenames, path)
+ }
+
+ return nil
+ })
+ return filenames, err
+}
+
+func FileNameFromPath(path string) string {
+ if !strings.Contains(path, "/") {
+ return path
+ }
+ return strings.Split(path, "/")[len(strings.Split(path, "/"))-1]
+}
+
+// FirstFileFromMatchingPath formats the given filepathWithPattern with actual file path
+// if filepathWithPattern is provided with a regex expression it returns the first filepath
+// matching with the regex.
+// if there is no regex provided in filepathWithPattern it just returns the provided filepath
+func FirstFileFromMatchingPath(filepathWithPattern string) (string, error) {
+ filename := FileNameFromPath(filepathWithPattern)
+ if strings.Contains(filepathWithPattern, "/") {
+ rootFolder := strings.Split(filepathWithPattern, filename)[0]
+ allFiles, err := FilesWithRegex(rootFolder, filename)
+ if err != nil {
+ return "", fmt.Errorf("error trying to find file %s:%w", filepathWithPattern, err)
+ }
+ if len(allFiles) == 0 {
+ return "", fmt.Errorf("error trying to find file %s", filepathWithPattern)
+ }
+ if len(allFiles) > 1 {
+ log.Warn().Str("path", filepathWithPattern).Msg("more than one contract config files found in location, using the first one")
+ }
+ return allFiles[0], nil
+ }
+ return filepathWithPattern, nil
+}
diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go
index 54a02cf64f3..200c97a795f 100644
--- a/integration-tests/chaos/ocr_chaos_test.go
+++ b/integration-tests/chaos/ocr_chaos_test.go
@@ -178,9 +178,7 @@ func TestOCRChaos(t *testing.T) {
require.NoError(t, err, "Error tearing down environment")
})
- ms, err := ctfClient.ConnectMockServer(testEnvironment)
- require.NoError(t, err, "Creating mockserver clients shouldn't fail")
-
+ ms := ctfClient.ConnectMockServer(testEnvironment)
linkContract, err := contracts.DeployLinkTokenContract(l, seth)
require.NoError(t, err, "Error deploying link token contract")
diff --git a/integration-tests/citool/cmd/check_tests_cmd.go b/integration-tests/citool/cmd/check_tests_cmd.go
deleted file mode 100644
index 3ef3712a572..00000000000
--- a/integration-tests/citool/cmd/check_tests_cmd.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package cmd
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "regexp"
- "strings"
-
- "github.com/spf13/cobra"
- "gopkg.in/yaml.v3"
-)
-
-type JobConfig struct {
- Jobs map[string]struct {
- Strategy struct {
- Matrix struct {
- Test []struct {
- Path string `yaml:"path"`
- TestOpts string `yaml:"testOpts"`
- } `yaml:"test"`
- } `yaml:"matrix"`
- } `yaml:"strategy"`
- } `yaml:"jobs"`
-}
-
-var checkTestsCmd = &cobra.Command{
- Use: "check-tests [directory] [yaml file]",
- Short: "Check if all tests in a directory are included in the test configurations YAML file",
- Args: cobra.ExactArgs(2),
- Run: func(_ *cobra.Command, args []string) {
- directory := args[0]
- yamlFile := args[1]
- excludedDirs := []string{"../../citool"}
- tests, err := extractTests(directory, excludedDirs)
- if err != nil {
- fmt.Println("Error extracting tests:", err)
- os.Exit(1)
- }
-
- checkTestsInPipeline(yamlFile, tests)
- },
-}
-
-// extractTests scans the given directory and subdirectories (except the excluded ones)
-// for Go test files, extracts test function names, and returns a slice of Test.
-func extractTests(dir string, excludeDirs []string) ([]Test, error) {
- var tests []Test
-
- // Resolve to absolute path
- absDir, err := filepath.Abs(dir)
- if err != nil {
- return nil, err
- }
-
- // filepath.WalkDir provides more control and is more efficient for skipping directories
- err = filepath.WalkDir(absDir, func(path string, d os.DirEntry, err error) error {
- if err != nil {
- return err
- }
-
- // Check if the current path is one of the excluded directories
- for _, exclude := range excludeDirs {
- absExclude, _ := filepath.Abs(exclude)
- if strings.HasPrefix(path, absExclude) {
- if d.IsDir() {
- return filepath.SkipDir // Skip this directory
- }
- return nil // Skip this file
- }
- }
-
- if !d.IsDir() && strings.HasSuffix(d.Name(), "_test.go") {
- content, err := os.ReadFile(path)
- if err != nil {
- return err
- }
- re := regexp.MustCompile(`func (Test\w+)`)
- matches := re.FindAllSubmatch(content, -1)
- for _, match := range matches {
- funcName := string(match[1])
- if funcName == "TestMain" { // Skip "TestMain"
- continue
- }
- tests = append(tests, Test{
- Name: funcName,
- Path: mustExtractSubpath(path, "integration-tests"),
- })
- }
- }
- return nil
- })
-
- return tests, err
-}
-
-// ExtractSubpath extracts a specific subpath from a given full path.
-// If the subpath is not found, it returns an error.
-func mustExtractSubpath(fullPath, subPath string) string {
- index := strings.Index(fullPath, subPath)
- if index == -1 {
- panic("subpath not found in the provided full path")
- }
- return fullPath[index:]
-}
-
-func checkTestsInPipeline(yamlFile string, tests []Test) {
- data, err := os.ReadFile(yamlFile)
- if err != nil {
- fmt.Printf("Error reading YAML file: %s\n", err)
- return
- }
-
- var config Config
- err = yaml.Unmarshal(data, &config)
- if err != nil {
- fmt.Printf("Error parsing YAML: %s\n", err)
- return
- }
-
- missingTests := []string{} // Track missing tests
-
- for _, test := range tests {
- found := false
- for _, item := range config.Tests {
- if item.Path == test.Path {
- if strings.Contains(item.TestCmd, "-test.run") {
- if matchTestNameInCmd(item.TestCmd, test.Name) {
- found = true
- break
- }
- } else {
- found = true
- break
- }
- }
- }
- if !found {
- missingTests = append(missingTests, fmt.Sprintf("ERROR: Test '%s' in file '%s' does not have CI configuration in '%s'", test.Name, test.Path, yamlFile))
- }
- }
-
- if len(missingTests) > 0 {
- for _, missing := range missingTests {
- fmt.Println(missing)
- }
- os.Exit(1) // Exit with a failure status
- }
-}
-
-// matchTestNameInCmd checks if the given test name matches the -test.run pattern in the command string.
-func matchTestNameInCmd(cmd string, testName string) bool {
- testRunRegex := regexp.MustCompile(`-test\.run ([^\s]+)`)
- matches := testRunRegex.FindStringSubmatch(cmd)
- if len(matches) > 1 {
- // Extract the regex pattern used in the -test.run command
- pattern := matches[1]
-
- // Escape regex metacharacters in the testName before matching
- escapedTestName := regexp.QuoteMeta(testName)
-
- // Check if the escaped test name matches the extracted pattern
- return regexp.MustCompile(pattern).MatchString(escapedTestName)
- }
- return false
-}
diff --git a/integration-tests/citool/cmd/check_tests_cmd_test.go b/integration-tests/citool/cmd/check_tests_cmd_test.go
deleted file mode 100644
index 4b7f50e7f06..00000000000
--- a/integration-tests/citool/cmd/check_tests_cmd_test.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package cmd
-
-import (
- "testing"
-)
-
-func TestMatchTestNameInCmd(t *testing.T) {
- tests := []struct {
- cmd string
- testName string
- expected bool
- }{
- {"go test -test.run ^TestExample$", "TestExample", true},
- {"go test -test.run ^TestExample$", "TestAnother", false},
- {"go test -test.run ^TestExample$ -v", "TestExample", true},
- {"go test -test.run ^TestExamplePart$", "TestExample", false},
- {"go test -test.run ^TestWithNumbers123$", "TestWithNumbers123", true},
- {"go test -test.run ^Test_With_Underscores$", "Test_With_Underscores", true},
- {"go test -test.run ^Test-With-Dash$", "Test-With-Dash", true},
- {"go test -test.run ^TestWithSpace Space$", "TestWithSpace Space", true},
- {"go test -test.run ^TestWithNewline\nNewline$", "TestWithNewline\nNewline", true},
- {"go test -test.run ^TestOne$|^TestTwo$", "TestOne", true},
- {"go test -test.run ^TestOne$|^TestTwo$", "TestTwo", true},
- {"go test -test.run ^TestOne$|^TestTwo$", "TestThree", false},
- {"go test -test.run TestOne|TestTwo", "TestTwo", true},
- {"go test -test.run TestOne|TestTwo", "TestOne", true},
- {"go test -test.run TestOne|TestTwo|TestThree", "TestFour", false},
- {"go test -test.run ^TestOne$|TestTwo$", "TestTwo", true},
- {"go test -test.run ^TestOne$|TestTwo|TestThree$", "TestThree", true},
- {"go test -test.run TestOne|TestTwo|TestThree", "TestOne", true},
- {"go test -test.run TestOne|TestTwo|TestThree", "TestThree", true},
- {"go test -test.run ^TestA$|^TestB$|^TestC$", "TestA", true},
- {"go test -test.run ^TestA$|^TestB$|^TestC$", "TestB", true},
- {"go test -test.run ^TestA$|^TestB$|^TestC$", "TestD", false},
- {"go test -test.run TestA|^TestB$|TestC", "TestB", true},
- {"go test -test.run ^TestA|^TestB|TestC$", "TestA", true},
- {"go test -test.run ^TestA|^TestB|TestC$", "TestC", true},
- {"go test -test.run ^TestA|^TestB|TestC$", "TestD", false},
- }
-
- for _, tt := range tests {
- result := matchTestNameInCmd(tt.cmd, tt.testName)
- if result != tt.expected {
- t.Errorf("matchTestNameInCmd(%s, %s) = %t; expected %t", tt.cmd, tt.testName, result, tt.expected)
- }
- }
-}
diff --git a/integration-tests/citool/cmd/create_test_config_cmd.go b/integration-tests/citool/cmd/create_test_config_cmd.go
deleted file mode 100644
index bc1b65bcdcd..00000000000
--- a/integration-tests/citool/cmd/create_test_config_cmd.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package cmd
-
-import (
- "fmt"
- "os"
-
- "github.com/pelletier/go-toml/v2"
- "github.com/spf13/cobra"
-
- ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
-)
-
-var createTestConfigCmd = &cobra.Command{
- Use: "create",
- Short: "Create a test config from the provided flags",
- Run: func(cmd *cobra.Command, _ []string) {
- var tc ctf_config.TestConfig
-
- var version, postgresVersion *string
- if cmd.Flags().Changed(ChainlinkVersionFlag) {
- version = &oc.ChainlinkVersion
- }
- if cmd.Flags().Changed(ChainlinkPostgresVersionFlag) {
- version = &oc.ChainlinkPostgresVersion
- }
- if version != nil || postgresVersion != nil {
- tc.ChainlinkImage = &ctf_config.ChainlinkImageConfig{
- Version: version,
- PostgresVersion: postgresVersion,
- }
- }
-
- var upgradeVersion *string
- if cmd.Flags().Changed(ChainlinkUpgradeVersionFlag) {
- upgradeVersion = &oc.ChainlinkUpgradeVersion
- }
- if upgradeVersion != nil {
- tc.ChainlinkUpgradeImage = &ctf_config.ChainlinkImageConfig{
- Version: upgradeVersion,
- }
- }
-
- var selectedNetworks *[]string
- if cmd.Flags().Changed(SelectedNetworksFlag) {
- selectedNetworks = &oc.SelectedNetworks
- }
- if selectedNetworks != nil {
- tc.Network = &ctf_config.NetworkConfig{
- SelectedNetworks: oc.SelectedNetworks,
- }
- }
-
- var peryscopeEnabled *bool
- var pyroscopeServerURL, pyroscopeEnvironment, pyroscopeKey *string
- if cmd.Flags().Changed(PyroscopeEnabledFlag) {
- peryscopeEnabled = &oc.PyroscopeEnabled
- }
- if cmd.Flags().Changed(PyroscopeServerURLFlag) {
- pyroscopeServerURL = &oc.PyroscopeServerURL
- }
- if cmd.Flags().Changed(PyroscopeKeyFlag) {
- pyroscopeKey = &oc.PyroscopeKey
- }
- if cmd.Flags().Changed(PyroscopeEnvironmentFlag) {
- pyroscopeEnvironment = &oc.PyroscopeEnvironment
- }
- if peryscopeEnabled != nil {
- tc.Pyroscope = &ctf_config.PyroscopeConfig{
- Enabled: peryscopeEnabled,
- ServerUrl: pyroscopeServerURL,
- Environment: pyroscopeEnvironment,
- Key: pyroscopeKey,
- }
- }
-
- var testLogCollect *bool
- if cmd.Flags().Changed(LoggingTestLogCollectFlag) {
- testLogCollect = &oc.LoggingTestLogCollect
- }
- var loggingRunID *string
- if cmd.Flags().Changed(LoggingRunIDFlag) {
- loggingRunID = &oc.LoggingRunID
- }
- var loggingLogTargets []string
- if cmd.Flags().Changed(LoggingLogTargetsFlag) {
- loggingLogTargets = oc.LoggingLogTargets
- }
- var loggingLokiTenantID *string
- if cmd.Flags().Changed(LoggingLokiTenantIDFlag) {
- loggingLokiTenantID = &oc.LoggingLokiTenantID
- }
- var loggingLokiBasicAuth *string
- if cmd.Flags().Changed(LoggingLokiBasicAuthFlag) {
- loggingLokiBasicAuth = &oc.LoggingLokiBasicAuth
- }
- var loggingLokiEndpoint *string
- if cmd.Flags().Changed(LoggingLokiEndpointFlag) {
- loggingLokiEndpoint = &oc.LoggingLokiEndpoint
- }
- var loggingGrafanaBaseURL *string
- if cmd.Flags().Changed(LoggingGrafanaBaseURLFlag) {
- loggingGrafanaBaseURL = &oc.LoggingGrafanaBaseURL
- }
- var loggingGrafanaDashboardURL *string
- if cmd.Flags().Changed(LoggingGrafanaDashboardURLFlag) {
- loggingGrafanaDashboardURL = &oc.LoggingGrafanaDashboardURL
- }
- var loggingGrafanaBearerToken *string
- if cmd.Flags().Changed(LoggingGrafanaBearerTokenFlag) {
- loggingGrafanaBearerToken = &oc.LoggingGrafanaBearerToken
- }
-
- if testLogCollect != nil || loggingRunID != nil || loggingLogTargets != nil || loggingLokiEndpoint != nil || loggingLokiTenantID != nil || loggingLokiBasicAuth != nil || loggingGrafanaBaseURL != nil || loggingGrafanaDashboardURL != nil || loggingGrafanaBearerToken != nil {
- tc.Logging = &ctf_config.LoggingConfig{}
- tc.Logging.TestLogCollect = testLogCollect
- tc.Logging.RunId = loggingRunID
- if loggingLogTargets != nil {
- tc.Logging.LogStream = &ctf_config.LogStreamConfig{
- LogTargets: loggingLogTargets,
- }
- }
- if loggingLokiTenantID != nil || loggingLokiBasicAuth != nil || loggingLokiEndpoint != nil {
- tc.Logging.Loki = &ctf_config.LokiConfig{
- TenantId: loggingLokiTenantID,
- BasicAuth: loggingLokiBasicAuth,
- Endpoint: loggingLokiEndpoint,
- }
- }
- if loggingGrafanaBaseURL != nil || loggingGrafanaDashboardURL != nil || loggingGrafanaBearerToken != nil {
- tc.Logging.Grafana = &ctf_config.GrafanaConfig{
- BaseUrl: loggingGrafanaBaseURL,
- DashboardUrl: loggingGrafanaDashboardURL,
- BearerToken: loggingGrafanaBearerToken,
- }
- }
- }
-
- var privateEthereumNetworkExecutionLayer *string
- if cmd.Flags().Changed(PrivateEthereumNetworkExecutionLayerFlag) {
- privateEthereumNetworkExecutionLayer = &oc.PrivateEthereumNetworkExecutionLayer
- }
- var privateEthereumNetworkEthereumVersion *string
- if cmd.Flags().Changed(PrivateEthereumNetworkEthereumVersionFlag) {
- privateEthereumNetworkEthereumVersion = &oc.PrivateEthereumNetworkEthereumVersion
- }
- var privateEthereumNetworkCustomDockerImage *string
- if cmd.Flags().Changed(PrivateEthereumNetworkCustomDockerImageFlag) {
- privateEthereumNetworkCustomDockerImage = &oc.PrivateEthereumNetworkCustomDockerImages
- }
- if privateEthereumNetworkExecutionLayer != nil || privateEthereumNetworkEthereumVersion != nil || privateEthereumNetworkCustomDockerImage != nil {
- var el ctf_config.ExecutionLayer
- if privateEthereumNetworkExecutionLayer != nil {
- el = ctf_config.ExecutionLayer(*privateEthereumNetworkExecutionLayer)
- }
- var ev ctf_config.EthereumVersion
- if privateEthereumNetworkEthereumVersion != nil {
- ev = ctf_config.EthereumVersion(*privateEthereumNetworkEthereumVersion)
- }
- var customImages map[ctf_config.ContainerType]string
- if privateEthereumNetworkCustomDockerImage != nil {
- customImages = map[ctf_config.ContainerType]string{"execution_layer": *privateEthereumNetworkCustomDockerImage}
- }
- tc.PrivateEthereumNetwork = &ctf_config.EthereumNetworkConfig{
- ExecutionLayer: &el,
- EthereumVersion: &ev,
- CustomDockerImages: customImages,
- }
- }
-
- configToml, err := toml.Marshal(tc)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error marshalling TestConfig to TOML: %v\n", err)
- os.Exit(1)
- }
-
- fmt.Fprintln(cmd.OutOrStdout(), string(configToml))
- },
-}
diff --git a/integration-tests/citool/cmd/csv_export_cmd.go b/integration-tests/citool/cmd/csv_export_cmd.go
deleted file mode 100644
index 8fe13440c81..00000000000
--- a/integration-tests/citool/cmd/csv_export_cmd.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package cmd
-
-import (
- "encoding/csv"
- "fmt"
- "os"
- "strings"
-
- "github.com/spf13/cobra"
- "gopkg.in/yaml.v3"
-)
-
-var csvExportCmd = &cobra.Command{
- Use: "csvexport",
- Short: "Export tests to CSV format",
- Run: func(cmd *cobra.Command, _ []string) {
- configFile, _ := cmd.Flags().GetString("file")
- if err := exportConfigToCSV(configFile); err != nil {
- fmt.Fprintf(os.Stderr, "Error: %v\n", err)
- os.Exit(1)
- }
- },
-}
-
-func init() {
- csvExportCmd.Flags().StringP("file", "f", "", "Path to YML file")
- err := csvExportCmd.MarkFlagRequired("file")
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error: %v\n", err)
- os.Exit(1)
- }
-}
-
-func exportConfigToCSV(configFile string) error {
- // Read the YAML file
- bytes, err := os.ReadFile(configFile)
- if err != nil {
- return err
- }
-
- // Unmarshal the YAML into the Config struct
- var config Config
- if err := yaml.Unmarshal(bytes, &config); err != nil {
- return err
- }
-
- // Create a CSV file
- file, err := os.Create("output.csv")
- if err != nil {
- return err
- }
- defer file.Close()
-
- writer := csv.NewWriter(file)
- defer writer.Flush()
-
- // Write CSV headers
- headers := []string{"ID", "Test Path", "Test Env Type", "Runs On", "Test Cmd", "Test Config Override Required", "Test Secrets Required", "Remote Runner Memory", "Pyroscope Env", "Workflows", "Test Inputs"}
- if err := writer.Write(headers); err != nil {
- return err
- }
-
- // Iterate over Tests and write data to CSV
- for _, test := range config.Tests {
- workflows := strings.Join(test.Workflows, ", ") // Combine workflows into a single CSV field
- // Serialize TestInputs
- testInputs := serializeMap(test.TestInputs)
-
- record := []string{
- test.ID,
- test.Path,
- test.TestEnvType,
- test.RunsOn,
- test.TestCmd,
- fmt.Sprintf("%t", test.TestConfigOverrideRequired),
- fmt.Sprintf("%t", test.TestSecretsRequired),
- test.RemoteRunnerMemory,
- test.PyroscopeEnv,
- workflows,
- testInputs,
- }
- if err := writer.Write(record); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func serializeMap(inputs map[string]string) string {
- pairs := make([]string, 0, len(inputs))
- for key, value := range inputs {
- pairs = append(pairs, fmt.Sprintf("%s=%s", key, value))
- }
- return strings.Join(pairs, ", ")
-}
diff --git a/integration-tests/citool/cmd/filter_cmd.go b/integration-tests/citool/cmd/filter_cmd.go
deleted file mode 100644
index c1d5f22357d..00000000000
--- a/integration-tests/citool/cmd/filter_cmd.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package cmd
-
-import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "log"
- "os"
- "regexp"
- "strings"
-
- "github.com/spf13/cobra"
- "gopkg.in/yaml.v2"
-
- "github.com/smartcontractkit/chainlink-testing-framework/utils"
-)
-
-// Filter tests based on workflow, test type, and test IDs.
-func filterTests(allTests []CITestConf, workflow, testType, ids string, envresolve bool) []CITestConf {
- workflowFilter := workflow
- typeFilter := testType
- idFilter := strings.Split(ids, ",")
-
- var filteredTests []CITestConf
-
- for _, test := range allTests {
- workflowMatch := workflow == "" || contains(test.Workflows, workflowFilter)
- typeMatch := testType == "" || test.TestEnvType == typeFilter
- idMatch := ids == "*" || ids == "" || contains(idFilter, test.ID)
-
- if workflowMatch && typeMatch && idMatch {
- test.IDSanitized = sanitizeTestID(test.ID)
- filteredTests = append(filteredTests, test)
- }
- if envresolve {
- for k, v := range test.TestInputs {
- test.TestInputs[k] = utils.MustResolveEnvPlaceholder(v)
- }
- }
- }
-
- return filteredTests
-}
-
-func filterAndMergeTests(allTests []CITestConf, workflow, testType, base64Tests string, envresolve bool) ([]CITestConf, error) {
- decodedBytes, err := base64.StdEncoding.DecodeString(base64Tests)
- if err != nil {
- return nil, err
- }
- var decodedTests []CITestConf
- err = yaml.Unmarshal(decodedBytes, &decodedTests)
- if err != nil {
- return nil, err
- }
-
- idFilter := make(map[string]CITestConf)
- for _, dt := range decodedTests {
- idFilter[dt.ID] = dt
- }
-
- var filteredTests []CITestConf
- for _, test := range allTests {
- workflowMatch := workflow == "" || contains(test.Workflows, workflow)
- typeMatch := testType == "" || test.TestEnvType == testType
-
- if decodedTest, exists := idFilter[test.ID]; exists && workflowMatch && typeMatch {
- // Override test inputs from the base64 encoded tests
- for k, v := range decodedTest.TestInputs {
- if test.TestInputs == nil {
- test.TestInputs = make(map[string]string)
- }
- test.TestInputs[k] = v
- }
- test.IDSanitized = sanitizeTestID(test.ID)
- filteredTests = append(filteredTests, test)
- }
- if envresolve {
- for k, v := range test.TestInputs {
- test.TestInputs[k] = utils.MustResolveEnvPlaceholder(v)
- }
- }
- }
-
- return filteredTests, nil
-}
-
-func sanitizeTestID(id string) string {
- // Define a regular expression that matches any character not a letter, digit, hyphen
- re := regexp.MustCompile(`[^a-zA-Z0-9-_]+`)
- // Replace all occurrences of disallowed characters with "_"
- return re.ReplaceAllString(id, "_")
-}
-
-// Utility function to check if a slice contains a string.
-func contains(slice []string, element string) bool {
- for _, s := range slice {
- if s == element {
- return true
- }
- }
- return false
-}
-
-// filterCmd represents the filter command
-var filterCmd = &cobra.Command{
- Use: "filter",
- Short: "Filter test configurations based on specified criteria",
- Long: `Filters tests from a YAML configuration based on name, workflow, test type, and test IDs.
-Example usage:
-./e2e_tests_tool filter --file .github/e2e-tests.yml --workflow "Run Nightly E2E Tests" --test-env-type "docker" --test-ids "test1,test2"`,
- Run: func(cmd *cobra.Command, _ []string) {
- yamlFile, _ := cmd.Flags().GetString("file")
- workflow, _ := cmd.Flags().GetString("workflow")
- testType, _ := cmd.Flags().GetString("test-env-type")
- testIDs, _ := cmd.Flags().GetString("test-ids")
- testMap, _ := cmd.Flags().GetString("test-list")
- envresolve, _ := cmd.Flags().GetBool("envresolve")
-
- data, err := os.ReadFile(yamlFile)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error reading YAML file: %v\n", err)
- os.Exit(1)
- }
-
- var config Config
- err = yaml.Unmarshal(data, &config)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error parsing YAML file %s data: %v\n", yamlFile, err)
- os.Exit(1)
- }
-
- var filteredTests []CITestConf
- if testMap == "" {
- filteredTests = filterTests(config.Tests, workflow, testType, testIDs, envresolve)
- } else {
- filteredTests, err = filterAndMergeTests(config.Tests, workflow, testType, testMap, envresolve)
- if err != nil {
- log.Fatalf("Error filtering and merging tests: %v", err)
- }
- }
- matrix := map[string][]CITestConf{"tests": filteredTests}
- matrixJSON, err := json.Marshal(matrix)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error marshaling matrix to JSON: %v\n", err)
- os.Exit(1)
- }
-
- fmt.Printf("%s", matrixJSON)
- },
-}
-
-func init() {
- filterCmd.Flags().StringP("file", "f", "", "Path to the YAML file")
- filterCmd.Flags().String("test-list", "", "Base64 encoded list of tests (YML objects) to filter by. Can include test_inputs for each test.")
- filterCmd.Flags().StringP("test-ids", "i", "*", "Comma-separated list of test IDs to filter by")
- filterCmd.Flags().StringP("test-env-type", "y", "", "Type of test to filter by")
- filterCmd.Flags().StringP("workflow", "t", "", "Workflow filter")
- filterCmd.Flags().Bool("envresolve", false, "Resolve environment variables in test inputs")
-
- err := filterCmd.MarkFlagRequired("file")
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error marking flag as required: %v\n", err)
- os.Exit(1)
- }
-}
diff --git a/integration-tests/citool/cmd/filter_cmd_test.go b/integration-tests/citool/cmd/filter_cmd_test.go
deleted file mode 100644
index ff6e9c981de..00000000000
--- a/integration-tests/citool/cmd/filter_cmd_test.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package cmd
-
-import (
- "testing"
-)
-
-func TestFilterTestsByID(t *testing.T) {
- tests := []CITestConf{
- {ID: "run_all_in_ocr_tests_go", TestEnvType: "docker"},
- {ID: "run_all_in_ocr2_tests_go", TestEnvType: "docker"},
- {ID: "run_all_in_ocr3_tests_go", TestEnvType: "k8s_remote_runner"},
- }
-
- cases := []struct {
- description string
- inputIDs string
- expectedLen int
- }{
- {"Filter by single ID", "run_all_in_ocr_tests_go", 1},
- {"Filter by multiple IDs", "run_all_in_ocr_tests_go,run_all_in_ocr2_tests_go", 2},
- {"Wildcard to include all", "*", 3},
- {"Empty ID string to include all", "", 3},
- }
-
- for _, c := range cases {
- t.Run(c.description, func(t *testing.T) {
- filtered := filterTests(tests, "", "", c.inputIDs, false)
- if len(filtered) != c.expectedLen {
- t.Errorf("FilterTests(%s) returned %d tests, expected %d", c.description, len(filtered), c.expectedLen)
- }
- })
- }
-}
-
-func TestFilterTestsIntegration(t *testing.T) {
- tests := []CITestConf{
- {ID: "run_all_in_ocr_tests_go", TestEnvType: "docker", Workflows: []string{"Run Nightly E2E Tests"}},
- {ID: "run_all_in_ocr2_tests_go", TestEnvType: "docker", Workflows: []string{"Run PR E2E Tests"}},
- {ID: "run_all_in_ocr3_tests_go", TestEnvType: "k8s_remote_runner", Workflows: []string{"Run PR E2E Tests"}},
- }
-
- cases := []struct {
- description string
- inputNames string
- inputWorkflow string
- inputTestType string
- inputIDs string
- expectedLen int
- }{
- {"Filter by test type and ID", "", "", "docker", "run_all_in_ocr2_tests_go", 1},
- {"Filter by trigger and test type", "", "Run PR E2E Tests", "docker", "*", 1},
- {"No filters applied", "", "", "", "*", 3},
- {"Filter mismatching all criteria", "", "Run Nightly E2E Tests", "", "", 1},
- }
-
- for _, c := range cases {
- t.Run(c.description, func(t *testing.T) {
- filtered := filterTests(tests, c.inputWorkflow, c.inputTestType, c.inputIDs, false)
- if len(filtered) != c.expectedLen {
- t.Errorf("FilterTests(%s) returned %d tests, expected %d", c.description, len(filtered), c.expectedLen)
- }
- })
- }
-}
diff --git a/integration-tests/citool/cmd/root_cmd.go b/integration-tests/citool/cmd/root_cmd.go
deleted file mode 100644
index fdb4efd5724..00000000000
--- a/integration-tests/citool/cmd/root_cmd.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package cmd
-
-import (
- "os"
-
- "github.com/spf13/cobra"
-)
-
-// rootCmd represents the base command when called without any subcommands
-var rootCmd = &cobra.Command{
- Use: "citool",
- Short: "A tool to manage E2E tests on Github CI",
-}
-
-// Execute adds all child commands to the root command and sets flags appropriately.
-// This is called by main.main(). It only needs to happen once to the rootCmd.
-func Execute() {
- err := rootCmd.Execute()
- if err != nil {
- os.Exit(1)
- }
-}
-
-func init() {
- rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
-
- rootCmd.AddCommand(checkTestsCmd)
- rootCmd.AddCommand(filterCmd)
- rootCmd.AddCommand(csvExportCmd)
- rootCmd.AddCommand(testConfigCmd)
- testConfigCmd.AddCommand(createTestConfigCmd)
-}
diff --git a/integration-tests/citool/cmd/test_config_cmd.go b/integration-tests/citool/cmd/test_config_cmd.go
deleted file mode 100644
index 0c0e272353b..00000000000
--- a/integration-tests/citool/cmd/test_config_cmd.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package cmd
-
-import (
- "strings"
-
- "github.com/spf13/cobra"
-
- "github.com/smartcontractkit/chainlink-testing-framework/utils"
-)
-
-var testConfigCmd = &cobra.Command{
- Use: "test-config",
- Short: "Manage test config",
-}
-
-// OverrideConfig holds the configuration data for overrides
-type OverrideConfig struct {
- ChainlinkImage string
- ChainlinkVersion string
- ChainlinkUpgradeImage string
- ChainlinkUpgradeVersion string
- ChainlinkPostgresVersion string
- SelectedNetworks []string
- PyroscopeEnabled bool
- PyroscopeServerURL string
- PyroscopeEnvironment string
- PyroscopeKey string
- LoggingTestLogCollect bool
- LoggingRunID string
- LoggingLogTargets []string
- LoggingLokiTenantID string
- LoggingLokiEndpoint string
- LoggingLokiBasicAuth string
- LoggingGrafanaBaseURL string
- LoggingGrafanaDashboardURL string
- LoggingGrafanaBearerToken string
- PrivateEthereumNetworkExecutionLayer string
- PrivateEthereumNetworkEthereumVersion string
- PrivateEthereumNetworkCustomDockerImages string
-}
-
-const (
- ChainlinkVersionFlag = "chainlink-version"
- ChainlinkUpgradeVersionFlag = "chainlink-upgrade-version"
- ChainlinkPostgresVersionFlag = "chainlink-postgres-version"
- SelectedNetworksFlag = "selected-networks"
- FromBase64ConfigFlag = "from-base64-config"
- LoggingLokiBasicAuthFlag = "logging-loki-basic-auth"
- LoggingLokiEndpointFlag = "logging-loki-endpoint"
- LoggingRunIDFlag = "logging-run-id"
- LoggingLokiTenantIDFlag = "logging-loki-tenant-id"
- LoggingGrafanaBaseURLFlag = "logging-grafana-base-url"
- LoggingGrafanaDashboardURLFlag = "logging-grafana-dashboard-url"
- LoggingGrafanaBearerTokenFlag = "logging-grafana-bearer-token"
- LoggingLogTargetsFlag = "logging-log-targets"
- LoggingTestLogCollectFlag = "logging-test-log-collect"
- PyroscopeEnabledFlag = "pyroscope-enabled"
- PyroscopeServerURLFlag = "pyroscope-server-url"
- PyroscopeKeyFlag = "pyroscope-key"
- PyroscopeEnvironmentFlag = "pyroscope-environment"
- PrivateEthereumNetworkExecutionLayerFlag = "private-ethereum-network-execution-layer"
- PrivateEthereumNetworkEthereumVersionFlag = "private-ethereum-network-ethereum-version"
- PrivateEthereumNetworkCustomDockerImageFlag = "private-ethereum-network-custom-docker-image"
-)
-
-var oc OverrideConfig
-
-func init() {
- cmds := []*cobra.Command{createTestConfigCmd}
- for _, c := range cmds {
- c.Flags().StringArrayVar(&oc.SelectedNetworks, SelectedNetworksFlag, nil, "Selected networks")
- c.Flags().StringVar(&oc.ChainlinkVersion, ChainlinkVersionFlag, "", "Chainlink version")
- c.Flags().StringVar(&oc.ChainlinkUpgradeVersion, ChainlinkUpgradeVersionFlag, "", "Chainlink upgrade version")
- c.Flags().StringVar(&oc.ChainlinkPostgresVersion, ChainlinkPostgresVersionFlag, "", "Chainlink Postgres version")
- c.Flags().BoolVar(&oc.PyroscopeEnabled, PyroscopeEnabledFlag, false, "Pyroscope enabled")
- c.Flags().StringVar(&oc.PyroscopeServerURL, PyroscopeServerURLFlag, "", "Pyroscope server URL")
- c.Flags().StringVar(&oc.PyroscopeKey, PyroscopeKeyFlag, "", "Pyroscope key")
- c.Flags().StringVar(&oc.PyroscopeEnvironment, PyroscopeEnvironmentFlag, "", "Pyroscope environment")
- c.Flags().BoolVar(&oc.LoggingTestLogCollect, LoggingTestLogCollectFlag, false, "Test log collect")
- c.Flags().StringVar(&oc.LoggingRunID, LoggingRunIDFlag, "", "Run ID")
- c.Flags().StringArrayVar(&oc.LoggingLogTargets, LoggingLogTargetsFlag, nil, "Logging.LogStream.LogTargets")
- c.Flags().StringVar(&oc.LoggingLokiEndpoint, LoggingLokiEndpointFlag, "", "")
- c.Flags().StringVar(&oc.LoggingLokiTenantID, LoggingLokiTenantIDFlag, "", "")
- c.Flags().StringVar(&oc.LoggingLokiBasicAuth, LoggingLokiBasicAuthFlag, "", "")
- c.Flags().StringVar(&oc.LoggingGrafanaBaseURL, LoggingGrafanaBaseURLFlag, "", "")
- c.Flags().StringVar(&oc.LoggingGrafanaDashboardURL, LoggingGrafanaDashboardURLFlag, "", "")
- c.Flags().StringVar(&oc.LoggingGrafanaBearerToken, LoggingGrafanaBearerTokenFlag, "", "")
- c.Flags().StringVar(&oc.PrivateEthereumNetworkExecutionLayer, PrivateEthereumNetworkExecutionLayerFlag, "", "")
- c.Flags().StringVar(&oc.PrivateEthereumNetworkEthereumVersion, PrivateEthereumNetworkEthereumVersionFlag, "", "")
- c.Flags().StringVar(&oc.PrivateEthereumNetworkCustomDockerImages, PrivateEthereumNetworkCustomDockerImageFlag, "", "")
-
- c.PreRun = func(_ *cobra.Command, _ []string) {
- // Resolve selected networks environment variable if set
- if len(oc.SelectedNetworks) > 0 {
- _, hasEnvVar := utils.LookupEnvVarName(oc.SelectedNetworks[0])
- if hasEnvVar {
- selectedNetworks := utils.MustResolveEnvPlaceholder(oc.SelectedNetworks[0])
- oc.SelectedNetworks = strings.Split(selectedNetworks, ",")
- }
- }
-
- // Resolve all other environment variables
- oc.ChainlinkImage = utils.MustResolveEnvPlaceholder(oc.ChainlinkImage)
- oc.ChainlinkVersion = utils.MustResolveEnvPlaceholder(oc.ChainlinkVersion)
- oc.ChainlinkUpgradeImage = utils.MustResolveEnvPlaceholder(oc.ChainlinkUpgradeImage)
- oc.ChainlinkUpgradeVersion = utils.MustResolveEnvPlaceholder(oc.ChainlinkUpgradeVersion)
- oc.ChainlinkPostgresVersion = utils.MustResolveEnvPlaceholder(oc.ChainlinkPostgresVersion)
- oc.PyroscopeServerURL = utils.MustResolveEnvPlaceholder(oc.PyroscopeServerURL)
- oc.PyroscopeKey = utils.MustResolveEnvPlaceholder(oc.PyroscopeKey)
- oc.PyroscopeEnvironment = utils.MustResolveEnvPlaceholder(oc.PyroscopeEnvironment)
- oc.LoggingRunID = utils.MustResolveEnvPlaceholder(oc.LoggingRunID)
- oc.LoggingLokiTenantID = utils.MustResolveEnvPlaceholder(oc.LoggingLokiTenantID)
- oc.LoggingLokiEndpoint = utils.MustResolveEnvPlaceholder(oc.LoggingLokiEndpoint)
- oc.LoggingLokiBasicAuth = utils.MustResolveEnvPlaceholder(oc.LoggingLokiBasicAuth)
- oc.LoggingGrafanaBaseURL = utils.MustResolveEnvPlaceholder(oc.LoggingGrafanaBaseURL)
- oc.LoggingGrafanaDashboardURL = utils.MustResolveEnvPlaceholder(oc.LoggingGrafanaDashboardURL)
- oc.LoggingGrafanaBearerToken = utils.MustResolveEnvPlaceholder(oc.LoggingGrafanaBearerToken)
- oc.PrivateEthereumNetworkExecutionLayer = utils.MustResolveEnvPlaceholder(oc.PrivateEthereumNetworkExecutionLayer)
- oc.PrivateEthereumNetworkEthereumVersion = utils.MustResolveEnvPlaceholder(oc.PrivateEthereumNetworkEthereumVersion)
- oc.PrivateEthereumNetworkCustomDockerImages = utils.MustResolveEnvPlaceholder(oc.PrivateEthereumNetworkCustomDockerImages)
- }
- }
-}
diff --git a/integration-tests/citool/cmd/test_config_cmd_test.go b/integration-tests/citool/cmd/test_config_cmd_test.go
deleted file mode 100644
index fb1ef5332bd..00000000000
--- a/integration-tests/citool/cmd/test_config_cmd_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package cmd
-
-import (
- "bytes"
- "testing"
-
- "github.com/pelletier/go-toml/v2"
- "github.com/spf13/cobra"
- "github.com/stretchr/testify/assert"
-
- ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
-)
-
-func TestCreateTestConfigCmd(t *testing.T) {
- tests := []struct {
- name string
- args []string
- want interface{}
- check func(t *testing.T, tc *ctf_config.TestConfig)
- wantErr bool
- }{
- {
- name: "LoggingLogTargets",
- args: []string{"create", "--logging-log-targets=target1", "--logging-log-targets=target2"},
- check: func(t *testing.T, tc *ctf_config.TestConfig) {
- assert.NotNil(t, tc.Logging)
- assert.NotNil(t, tc.Logging.LogStream)
- assert.Equal(t, []string{"target1", "target2"}, tc.Logging.LogStream.LogTargets)
- },
- },
- {
- name: "PrivateEthereumNetworkExecutionLayerFlag",
- args: []string{"create", "--private-ethereum-network-execution-layer=geth", "--private-ethereum-network-ethereum-version=1.10.0"},
- check: func(t *testing.T, tc *ctf_config.TestConfig) {
- assert.NotNil(t, tc.PrivateEthereumNetwork)
- assert.NotNil(t, tc.PrivateEthereumNetwork.ExecutionLayer)
- assert.Equal(t, ctf_config.ExecutionLayer("geth"), *tc.PrivateEthereumNetwork.ExecutionLayer)
- assert.Equal(t, ctf_config.EthereumVersion("1.10.0"), *tc.PrivateEthereumNetwork.EthereumVersion)
- },
- },
- {
- name: "PrivateEthereumNetworkCustomDockerImageFlag",
- args: []string{"create", "--private-ethereum-network-execution-layer=geth", "--private-ethereum-network-ethereum-version=1.10.0", "--private-ethereum-network-custom-docker-image=custom-image:v1.0"},
- check: func(t *testing.T, tc *ctf_config.TestConfig) {
- assert.NotNil(t, tc.PrivateEthereumNetwork)
- assert.NotNil(t, tc.PrivateEthereumNetwork.ExecutionLayer)
- assert.Equal(t, map[ctf_config.ContainerType]string{"execution_layer": "custom-image:v1.0"}, tc.PrivateEthereumNetwork.CustomDockerImages)
- },
- },
- }
-
- rootCmd := &cobra.Command{}
- rootCmd.AddCommand(createTestConfigCmd)
-
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- rootCmd.SetArgs(tt.args)
- var out bytes.Buffer
- rootCmd.SetOutput(&out)
- err := rootCmd.Execute()
- if (err != nil) != tt.wantErr {
- t.Fatalf("Execute() error = %v, wantErr %v", err, tt.wantErr)
- }
- var tc ctf_config.TestConfig
- err = toml.Unmarshal(out.Bytes(), &tc)
- if err != nil {
- t.Fatalf("Failed to unmarshal output: %v", err)
- }
- if tt.check != nil {
- tt.check(t, &tc)
- }
- })
- }
-}
diff --git a/integration-tests/citool/cmd/types.go b/integration-tests/citool/cmd/types.go
deleted file mode 100644
index 3c347e9406b..00000000000
--- a/integration-tests/citool/cmd/types.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package cmd
-
-type Test struct {
- Name string
- Path string
-}
-
-// CITestConf defines the configuration for running a test in a CI environment, specifying details like test ID, path, type, runner settings, command, and associated workflows.
-type CITestConf struct {
- ID string `yaml:"id" json:"id"`
- IDSanitized string `json:"id_sanitized"`
- Path string `yaml:"path" json:"path"`
- TestEnvType string `yaml:"test_env_type" json:"test_env_type"`
- RunsOn string `yaml:"runs_on" json:"runs_on"`
- TestCmd string `yaml:"test_cmd" json:"test_cmd"`
- TestConfigOverrideRequired bool `yaml:"test_config_override_required" json:"testConfigOverrideRequired"`
- TestSecretsRequired bool `yaml:"test_secrets_required" json:"testSecretsRequired"`
- TestInputs map[string]string `yaml:"test_inputs" json:"test_inputs"`
- RemoteRunnerMemory string `yaml:"remote_runner_memory" json:"remoteRunnerMemory"`
- PyroscopeEnv string `yaml:"pyroscope_env" json:"pyroscopeEnv"`
- Workflows []string `yaml:"workflows" json:"workflows"`
-}
-
-type Config struct {
- Tests []CITestConf `yaml:"runner-test-matrix"`
-}
diff --git a/integration-tests/citool/main.go b/integration-tests/citool/main.go
deleted file mode 100644
index 4fa6cac56e5..00000000000
--- a/integration-tests/citool/main.go
+++ /dev/null
@@ -1,9 +0,0 @@
-package main
-
-import (
- "github.com/smartcontractkit/chainlink/integration-tests/citool/cmd"
-)
-
-func main() {
- cmd.Execute()
-}
diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go
index 08a47101dc1..da17dcf0d75 100644
--- a/integration-tests/client/chainlink.go
+++ b/integration-tests/client/chainlink.go
@@ -2,6 +2,7 @@
package client
import (
+ "crypto/tls"
"fmt"
"math/big"
"net/http"
@@ -45,14 +46,10 @@ type ChainlinkClient struct {
// NewChainlinkClient creates a new Chainlink model using a provided config
func NewChainlinkClient(c *ChainlinkConfig, logger zerolog.Logger) (*ChainlinkClient, error) {
- rc, err := initRestyClient(c.URL, c.Email, c.Password, c.HTTPTimeout)
+ rc, err := initRestyClient(c.URL, c.Email, c.Password, c.Headers, c.HTTPTimeout)
if err != nil {
return nil, err
}
- _, isSet := os.LookupEnv("CL_CLIENT_DEBUG")
- if isSet {
- rc.SetDebug(true)
- }
return &ChainlinkClient{
Config: c,
APIClient: rc,
@@ -61,8 +58,11 @@ func NewChainlinkClient(c *ChainlinkConfig, logger zerolog.Logger) (*ChainlinkCl
}, nil
}
-func initRestyClient(url string, email string, password string, timeout *time.Duration) (*resty.Client, error) {
- rc := resty.New().SetBaseURL(url)
+func initRestyClient(url string, email string, password string, headers map[string]string, timeout *time.Duration) (*resty.Client, error) {
+ isDebug := os.Getenv("RESTY_DEBUG") == "true"
+ // G402 - TODO: certificates
+ //nolint
+ rc := resty.New().SetBaseURL(url).SetHeaders(headers).SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).SetDebug(isDebug)
if timeout != nil {
rc.SetTimeout(*timeout)
}
@@ -74,7 +74,7 @@ func initRestyClient(url string, email string, password string, timeout *time.Du
for i := 0; i < retryCount; i++ {
resp, err = rc.R().SetBody(session).Post("/sessions")
if err != nil {
- log.Debug().Err(err).Str("URL", url).Interface("Session Details", session).Msg("Error connecting to Chainlink node, retrying")
+ log.Warn().Err(err).Str("URL", url).Interface("Session Details", session).Msg("Error connecting to Chainlink node, retrying")
time.Sleep(5 * time.Second)
} else {
break
diff --git a/integration-tests/client/chainlink_k8s.go b/integration-tests/client/chainlink_k8s.go
index 794e93f7276..077b8f7ca48 100644
--- a/integration-tests/client/chainlink_k8s.go
+++ b/integration-tests/client/chainlink_k8s.go
@@ -2,7 +2,6 @@
package client
import (
- "os"
"regexp"
"github.com/rs/zerolog/log"
@@ -23,14 +22,10 @@ type ChainlinkK8sClient struct {
// NewChainlink creates a new Chainlink model using a provided config
func NewChainlinkK8sClient(c *ChainlinkConfig, podName, chartName string) (*ChainlinkK8sClient, error) {
- rc, err := initRestyClient(c.URL, c.Email, c.Password, c.HTTPTimeout)
+ rc, err := initRestyClient(c.URL, c.Email, c.Password, c.Headers, c.HTTPTimeout)
if err != nil {
return nil, err
}
- _, isSet := os.LookupEnv("CL_CLIENT_DEBUG")
- if isSet {
- rc.SetDebug(true)
- }
return &ChainlinkK8sClient{
ChainlinkClient: &ChainlinkClient{
APIClient: rc,
diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go
index a0435d53368..86e9f75902d 100644
--- a/integration-tests/client/chainlink_models.go
+++ b/integration-tests/client/chainlink_models.go
@@ -20,11 +20,12 @@ type EIServiceConfig struct {
// ChainlinkConfig represents the variables needed to connect to a Chainlink node
type ChainlinkConfig struct {
- URL string `toml:",omitempty"`
- Email string `toml:",omitempty"`
- Password string `toml:",omitempty"`
- InternalIP string `toml:",omitempty"`
- HTTPTimeout *time.Duration `toml:"-"`
+ URL string `toml:",omitempty"`
+ Email string `toml:",omitempty"`
+ Password string `toml:",omitempty"`
+ InternalIP string `toml:",omitempty"`
+ Headers map[string]string `toml:",omitempty"`
+ HTTPTimeout *time.Duration `toml:"-"`
}
// ResponseSlice is the generic model that can be used for all Chainlink API responses that are an slice
diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go
index 5983f95c9f5..ea63f1aa4db 100644
--- a/integration-tests/contracts/contract_models.go
+++ b/integration-tests/contracts/contract_models.go
@@ -224,7 +224,7 @@ type JobByInstance struct {
Instance string
}
-type MockETHLINKFeed interface {
+type MockLINKETHFeed interface {
Address() string
LatestRoundData() (*big.Int, error)
LatestRoundDataUpdatedAt() (*big.Int, error)
diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go
index 45825a18ff3..c798c4921c6 100644
--- a/integration-tests/contracts/contract_vrf_models.go
+++ b/integration-tests/contracts/contract_vrf_models.go
@@ -76,6 +76,8 @@ type VRFCoordinatorV2 interface {
WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error)
OracleWithdraw(recipient common.Address, amount *big.Int) error
GetBlockHashStoreAddress(ctx context.Context) (common.Address, error)
+ GetLinkAddress(ctx context.Context) (common.Address, error)
+ GetLinkNativeFeed(ctx context.Context) (common.Address, error)
}
type VRFCoordinatorV2_5 interface {
@@ -121,6 +123,8 @@ type VRFCoordinatorV2_5 interface {
ParseRandomWordsFulfilled(log types.Log) (*CoordinatorRandomWordsFulfilled, error)
WaitForConfigSetEvent(timeout time.Duration) (*CoordinatorConfigSet, error)
GetBlockHashStoreAddress(ctx context.Context) (common.Address, error)
+ GetLinkAddress(ctx context.Context) (common.Address, error)
+ GetLinkNativeFeed(ctx context.Context) (common.Address, error)
}
type VRFCoordinatorV2PlusUpgradedVersion interface {
diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go
index 2db6aeb4637..0d493dff45e 100644
--- a/integration-tests/contracts/ethereum_contracts.go
+++ b/integration-tests/contracts/ethereum_contracts.go
@@ -770,12 +770,12 @@ func DeployLinkTokenContract(l zerolog.Logger, client *seth.Client) (*EthereumLi
}
func LoadLinkTokenContract(l zerolog.Logger, client *seth.Client, address common.Address) (*EthereumLinkToken, error) {
- abi, err := link_token_interface.LinkTokenMetaData.GetAbi()
+ linkABI, err := link_token_interface.LinkTokenMetaData.GetAbi()
if err != nil {
return &EthereumLinkToken{}, fmt.Errorf("failed to get LinkToken ABI: %w", err)
}
- client.ContractStore.AddABI("LinkToken", *abi)
+ client.ContractStore.AddABI("LinkToken", *linkABI)
client.ContractStore.AddBIN("LinkToken", common.FromHex(link_token_interface.LinkTokenMetaData.Bin))
linkToken, err := link_token_interface.NewLinkToken(address, wrappers.MustNewWrappedContractBackend(nil, client))
@@ -1195,19 +1195,19 @@ func (v *EthereumMockETHLINKFeed) LatestRoundDataUpdatedAt() (*big.Int, error) {
return data.UpdatedAt, nil
}
-func DeployMockETHLINKFeed(client *seth.Client, answer *big.Int) (MockETHLINKFeed, error) {
+func DeployMockLINKETHFeed(client *seth.Client, answer *big.Int) (MockLINKETHFeed, error) {
abi, err := mock_ethlink_aggregator_wrapper.MockETHLINKAggregatorMetaData.GetAbi()
if err != nil {
- return &EthereumMockETHLINKFeed{}, fmt.Errorf("failed to get MockETHLINKFeed ABI: %w", err)
+ return &EthereumMockETHLINKFeed{}, fmt.Errorf("failed to get MockLINKETHFeed ABI: %w", err)
}
- data, err := client.DeployContract(client.NewTXOpts(), "MockETHLINKFeed", *abi, common.FromHex(mock_ethlink_aggregator_wrapper.MockETHLINKAggregatorMetaData.Bin), answer)
+ data, err := client.DeployContract(client.NewTXOpts(), "MockLINKETHFeed", *abi, common.FromHex(mock_ethlink_aggregator_wrapper.MockETHLINKAggregatorMetaData.Bin), answer)
if err != nil {
- return &EthereumMockETHLINKFeed{}, fmt.Errorf("MockETHLINKFeed instance deployment have failed: %w", err)
+ return &EthereumMockETHLINKFeed{}, fmt.Errorf("MockLINKETHFeed instance deployment have failed: %w", err)
}
instance, err := mock_ethlink_aggregator_wrapper.NewMockETHLINKAggregator(data.Address, wrappers.MustNewWrappedContractBackend(nil, client))
if err != nil {
- return &EthereumMockETHLINKFeed{}, fmt.Errorf("failed to instantiate MockETHLINKFeed instance: %w", err)
+ return &EthereumMockETHLINKFeed{}, fmt.Errorf("failed to instantiate MockLINKETHFeed instance: %w", err)
}
return &EthereumMockETHLINKFeed{
@@ -1217,17 +1217,17 @@ func DeployMockETHLINKFeed(client *seth.Client, answer *big.Int) (MockETHLINKFee
}, nil
}
-func LoadMockETHLINKFeed(client *seth.Client, address common.Address) (MockETHLINKFeed, error) {
+func LoadMockLINKETHFeed(client *seth.Client, address common.Address) (MockLINKETHFeed, error) {
abi, err := mock_ethlink_aggregator_wrapper.MockETHLINKAggregatorMetaData.GetAbi()
if err != nil {
- return &EthereumMockETHLINKFeed{}, fmt.Errorf("failed to get MockETHLINKFeed ABI: %w", err)
+ return &EthereumMockETHLINKFeed{}, fmt.Errorf("failed to get MockLINKETHFeed ABI: %w", err)
}
- client.ContractStore.AddABI("MockETHLINKFeed", *abi)
- client.ContractStore.AddBIN("MockETHLINKFeed", common.FromHex(mock_ethlink_aggregator_wrapper.MockETHLINKAggregatorMetaData.Bin))
+ client.ContractStore.AddABI("MockLINKETHFeed", *abi)
+ client.ContractStore.AddBIN("MockLINKETHFeed", common.FromHex(mock_ethlink_aggregator_wrapper.MockETHLINKAggregatorMetaData.Bin))
instance, err := mock_ethlink_aggregator_wrapper.NewMockETHLINKAggregator(address, wrappers.MustNewWrappedContractBackend(nil, client))
if err != nil {
- return &EthereumMockETHLINKFeed{}, fmt.Errorf("failed to instantiate MockETHLINKFeed instance: %w", err)
+ return &EthereumMockETHLINKFeed{}, fmt.Errorf("failed to instantiate MockLINKETHFeed instance: %w", err)
}
return &EthereumMockETHLINKFeed{
diff --git a/integration-tests/contracts/ethereum_contracts_automation.go b/integration-tests/contracts/ethereum_contracts_automation.go
index bd0e1aafc82..9c01511ff11 100644
--- a/integration-tests/contracts/ethereum_contracts_automation.go
+++ b/integration-tests/contracts/ethereum_contracts_automation.go
@@ -147,7 +147,7 @@ type EthereumKeeperRegistry struct {
func (v *EthereumKeeperRegistry) ReorgProtectionEnabled() bool {
chainId := v.client.ChainID
// reorg protection is disabled in polygon zkEVM and Scroll bc currently there is no way to get the block hash onchain
- return v.version != ethereum.RegistryVersion_2_2 || (chainId != 1101 && chainId != 1442 && chainId != 2442 && chainId != 534352 && chainId != 534351)
+ return v.version < ethereum.RegistryVersion_2_2 || (chainId != 1101 && chainId != 1442 && chainId != 2442 && chainId != 534352 && chainId != 534351)
}
func (v *EthereumKeeperRegistry) ChainModuleAddress() common.Address {
diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go
index 28fdd15b13e..38aa5c58f0f 100644
--- a/integration-tests/contracts/ethereum_keeper_contracts.go
+++ b/integration-tests/contracts/ethereum_keeper_contracts.go
@@ -150,6 +150,7 @@ type KeeperRegistrySettings struct {
MaxPerformGas uint32 // max gas allowed for an upkeep within perform
FallbackGasPrice *big.Int // gas price used if the gas price feed is stale
FallbackLinkPrice *big.Int // LINK price used if the LINK price feed is stale
+ FallbackNativePrice *big.Int // Native price used if the Native price feed is stale
MaxCheckDataSize uint32
MaxPerformDataSize uint32
MaxRevertDataSize uint32
diff --git a/integration-tests/contracts/ethereum_vrf_contracts.go b/integration-tests/contracts/ethereum_vrf_contracts.go
index e4dbb87d0b2..a09cc809c63 100644
--- a/integration-tests/contracts/ethereum_vrf_contracts.go
+++ b/integration-tests/contracts/ethereum_vrf_contracts.go
@@ -13,6 +13,7 @@ import (
"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/vrfv2plus_wrapper"
+ "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_optimism"
"github.com/smartcontractkit/seth"
@@ -546,3 +547,22 @@ func LoadVRFV2PlusWrapperOptimism(seth *seth.Client, addr string) (*EthereumVRFV
wrapper: contract,
}, nil
}
+
+func LoadVRFV2WrapperLoadTestConsumer(seth *seth.Client, addr string) (*EthereumVRFV2PlusWrapperLoadTestConsumer, error) {
+ address := common.HexToAddress(addr)
+ abi, err := vrfv2plus_wrapper_load_test_consumer.VRFV2PlusWrapperLoadTestConsumerMetaData.GetAbi()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get VRFV2PlusWrapperLoadTestConsumer ABI: %w", err)
+ }
+ seth.ContractStore.AddABI("VRFV2PlusWrapperLoadTestConsumer", *abi)
+ seth.ContractStore.AddBIN("VRFV2PlusWrapperLoadTestConsumer", common.FromHex(vrfv2plus_wrapper_load_test_consumer.VRFV2PlusWrapperLoadTestConsumerMetaData.Bin))
+ contract, err := vrfv2plus_wrapper_load_test_consumer.NewVRFV2PlusWrapperLoadTestConsumer(address, wrappers.MustNewWrappedContractBackend(nil, seth))
+ if err != nil {
+ return nil, fmt.Errorf("failed to instantiate VRFV2PlusWrapperLoadTestConsumer instance: %w", err)
+ }
+ return &EthereumVRFV2PlusWrapperLoadTestConsumer{
+ client: seth,
+ address: address,
+ consumer: contract,
+ }, nil
+}
diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go
index a9d1a93769d..df4a6fb9fbe 100644
--- a/integration-tests/contracts/ethereum_vrfv2_contracts.go
+++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go
@@ -594,6 +594,30 @@ func (v *EthereumVRFCoordinatorV2) ParseLog(log types.Log) (generated.AbigenLog,
return v.coordinator.ParseLog(log)
}
+func (v *EthereumVRFCoordinatorV2) GetLinkAddress(ctx context.Context) (common.Address, error) {
+ opts := &bind.CallOpts{
+ From: v.client.MustGetRootKeyAddress(),
+ Context: ctx,
+ }
+ address, err := v.coordinator.LINK(opts)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return address, nil
+}
+
+func (v *EthereumVRFCoordinatorV2) GetLinkNativeFeed(ctx context.Context) (common.Address, error) {
+ opts := &bind.CallOpts{
+ From: v.client.MustGetRootKeyAddress(),
+ Context: ctx,
+ }
+ address, err := v.coordinator.LINKETHFEED(opts)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return address, nil
+}
+
// CancelSubscription cancels subscription by Sub owner,
// return funds to specified address,
// checks if pending requests for a sub exist
diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go
index 8e099b4f6bc..9b286a1d057 100644
--- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go
+++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go
@@ -340,6 +340,30 @@ func (v *EthereumVRFCoordinatorV2_5) GetBlockHashStoreAddress(ctx context.Contex
return blockHashStoreAddress, nil
}
+func (v *EthereumVRFCoordinatorV2_5) GetLinkAddress(ctx context.Context) (common.Address, error) {
+ opts := &bind.CallOpts{
+ From: v.client.MustGetRootKeyAddress(),
+ Context: ctx,
+ }
+ address, err := v.coordinator.LINK(opts)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return address, nil
+}
+
+func (v *EthereumVRFCoordinatorV2_5) GetLinkNativeFeed(ctx context.Context) (common.Address, error) {
+ opts := &bind.CallOpts{
+ From: v.client.MustGetRootKeyAddress(),
+ Context: ctx,
+ }
+ address, err := v.coordinator.LINKNATIVEFEED(opts)
+ if err != nil {
+ return common.Address{}, err
+ }
+ return address, nil
+}
+
// OwnerCancelSubscription cancels subscription by Coordinator owner
// return funds to sub owner,
// does not check if pending requests for a sub exist
diff --git a/integration-tests/crib/README.md b/integration-tests/crib/README.md
index ecf393f780d..e895cca6763 100644
--- a/integration-tests/crib/README.md
+++ b/integration-tests/crib/README.md
@@ -1,4 +1,4 @@
-### CRIB Health Check Test
+### Example e2e product test using CRIB
## Setup CRIB
This is a simple smoke + chaos test for CRIB deployment.
@@ -12,8 +12,15 @@ devspace deploy --debug --profile local-dev-simulated-core-ocr1
## Run the tests
```shell
-CRIB_NAMESPACE=crib-oh-my-crib
-CRIB_NETWORK=geth # only "geth" is supported for now
-CRIB_NODES=5 # min 5 nodes
+export CRIB_NAMESPACE=crib-oh-my-crib
+export CRIB_NETWORK=geth # only "geth" is supported for now
+export CRIB_NODES=5 # min 5 nodes
+#export SETH_LOG_LEVEL=debug # these two can be enabled to debug connection issues
+#export RESTY_DEBUG=true
+#export TEST_PERSISTENCE=true # to run the chaos test
+export GAP_URL=https://localhost:8080/primary # only applicable in CI, unset the var to connect locally
go test -v -run TestCRIB
-```
\ No newline at end of file
+```
+
+## Configuring CI workflow
+We are using GAP and GATI to access the infrastructure, please follow [configuration guide](https://smartcontract-it.atlassian.net/wiki/spaces/CRIB/pages/909967436/CRIB+CI+Integration)
\ No newline at end of file
diff --git a/integration-tests/crib/chaos.go b/integration-tests/crib/chaos.go
index bbf6ca681cd..463ced483fa 100644
--- a/integration-tests/crib/chaos.go
+++ b/integration-tests/crib/chaos.go
@@ -4,16 +4,17 @@ import (
"time"
"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
- "github.com/smartcontractkit/havoc/k8schaos"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/havoc"
)
-func rebootCLNamespace(delay time.Duration, namespace string) (*k8schaos.Chaos, error) {
- k8sClient, err := k8schaos.NewChaosMeshClient()
+func rebootCLNamespace(delay time.Duration, namespace string) (*havoc.Chaos, error) {
+ k8sClient, err := havoc.NewChaosMeshClient()
if err != nil {
return nil, err
}
- return k8schaos.NewChaos(k8schaos.ChaosOpts{
+ return havoc.NewChaos(havoc.ChaosOpts{
Description: "Reboot CRIB",
DelayCreate: delay,
Object: &v1alpha1.PodChaos{
@@ -40,6 +41,6 @@ func rebootCLNamespace(delay time.Duration, namespace string) (*k8schaos.Chaos,
},
},
Client: k8sClient,
- Logger: &k8schaos.Logger,
+ Logger: &havoc.Logger,
})
}
diff --git a/integration-tests/crib/connect.go b/integration-tests/crib/connect.go
index 91d7d8ee1a0..c180b2ff2ea 100644
--- a/integration-tests/crib/connect.go
+++ b/integration-tests/crib/connect.go
@@ -1,11 +1,11 @@
package crib
import (
- "fmt"
- "os"
- "strconv"
+ "net/http"
"time"
+ "github.com/smartcontractkit/chainlink-testing-framework/crib"
+
"github.com/pkg/errors"
"github.com/smartcontractkit/seth"
@@ -18,17 +18,7 @@ import (
"github.com/smartcontractkit/chainlink/integration-tests/client"
)
-const (
- // these are constants for simulated CRIB that should never change
- // CRIB: https://github.com/smartcontractkit/crib/tree/main/core
- // Core Chart: https://github.com/smartcontractkit/infra-charts/tree/main/chainlink-cluster
- mockserverCRIBTemplate = "https://%s-mockserver%s"
- internalNodeDNSTemplate = "app-node%d"
- ingressNetworkWSURLTemplate = "wss://%s-geth-1337-ws%s"
- ingressNetworkHTTPURLTemplate = "https://%s-geth-1337-http%s"
-)
-
-func setSethConfig(cfg tc.TestConfig, netWSURL string, netHTTPURL string) {
+func setSethConfig(cfg tc.TestConfig, netWSURL string, netHTTPURL string, headers http.Header) {
netName := "CRIB_SIMULATED"
cfg.Network.SelectedNetworks = []string{netName}
cfg.Network.RpcHttpUrls = map[string][]string{}
@@ -36,6 +26,7 @@ func setSethConfig(cfg tc.TestConfig, netWSURL string, netHTTPURL string) {
cfg.Network.RpcWsUrls = map[string][]string{}
cfg.Network.RpcWsUrls[netName] = []string{netWSURL}
cfg.Seth.EphemeralAddrs = ptr.Ptr(int64(0))
+ cfg.Seth.RPCHeaders = headers
}
// ConnectRemote connects to a local environment, see https://github.com/smartcontractkit/crib/tree/main/core
@@ -47,52 +38,33 @@ func ConnectRemote() (
[]*client.ChainlinkK8sClient,
error,
) {
- ingressSuffix := os.Getenv("K8S_STAGING_INGRESS_SUFFIX")
- if ingressSuffix == "" {
- return nil, nil, nil, nil, errors.New("K8S_STAGING_INGRESS_SUFFIX must be set to connect to k8s ingresses")
- }
- cribNamespace := os.Getenv("CRIB_NAMESPACE")
- if cribNamespace == "" {
- return nil, nil, nil, nil, errors.New("CRIB_NAMESPACE must be set to connect")
- }
- cribNetwork := os.Getenv("CRIB_NETWORK")
- if cribNetwork == "" {
- return nil, nil, nil, nil, errors.New("CRIB_NETWORK must be set to connect, only 'geth' is supported for now")
- }
- cribNodes := os.Getenv("CRIB_NODES")
- nodes, err := strconv.Atoi(cribNodes)
+ vars, err := crib.CoreDONSimulatedConnection()
if err != nil {
- return nil, nil, nil, nil, errors.New("CRIB_NODES must be a number, 5-19 nodes")
+ return nil, nil, nil, nil, err
}
+ // TODO: move all the parts of ConnectRemote() to CTF when Seth config refactor is finalized
config, err := tc.GetConfig([]string{"CRIB"}, tc.OCR)
if err != nil {
return nil, nil, nil, nil, err
}
- if nodes < 2 {
- return nil, nil, nil, nil, fmt.Errorf("not enough chainlink nodes, need at least 2, TOML key: [CRIB.nodes]")
- }
- mockserverURL := fmt.Sprintf(mockserverCRIBTemplate, cribNamespace, ingressSuffix)
var sethClient *seth.Client
- switch cribNetwork {
+ switch vars.Network {
case "geth":
- netWSURL := fmt.Sprintf(ingressNetworkWSURLTemplate, cribNamespace, ingressSuffix)
- netHTTPURL := fmt.Sprintf(ingressNetworkHTTPURLTemplate, cribNamespace, ingressSuffix)
- setSethConfig(config, netWSURL, netHTTPURL)
+ setSethConfig(config, vars.NetworkWSURL, vars.NetworkHTTPURL, vars.BlockchainNodeHeaders)
net := blockchain.EVMNetwork{
- Name: cribNetwork,
- Simulated: true,
- SupportsEIP1559: true,
- ClientImplementation: blockchain.EthereumClientImplementation,
- ChainID: 1337,
- PrivateKeys: []string{
- "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
- },
- URLs: []string{netWSURL},
- HTTPURLs: []string{netHTTPURL},
+ Name: vars.Network,
+ Simulated: true,
+ SupportsEIP1559: true,
+ ClientImplementation: blockchain.EthereumClientImplementation,
+ ChainID: vars.ChainID,
+ PrivateKeys: vars.PrivateKeys,
+ URLs: []string{vars.NetworkWSURL},
+ HTTPURLs: []string{vars.NetworkHTTPURL},
ChainlinkTransactionLimit: 500000,
Timeout: blockchain.StrDuration{Duration: 2 * time.Minute},
MinimumConfirmations: 1,
GasEstimationBuffer: 10000,
+ Headers: vars.BlockchainNodeHeaders,
}
sethClient, err = seth_utils.GetChainClient(config, net)
if err != nil {
@@ -104,31 +76,34 @@ func ConnectRemote() (
// bootstrap node
clClients := make([]*client.ChainlinkK8sClient, 0)
c, err := client.NewChainlinkK8sClient(&client.ChainlinkConfig{
- URL: fmt.Sprintf("https://%s-node%d%s", cribNamespace, 1, ingressSuffix),
Email: client.CLNodeTestEmail,
- InternalIP: fmt.Sprintf(internalNodeDNSTemplate, 1),
Password: client.CLNodeTestPassword,
- }, fmt.Sprintf(internalNodeDNSTemplate, 1), cribNamespace)
+ URL: vars.NodeURLs[0],
+ InternalIP: vars.NodeInternalDNS[0],
+ Headers: vars.NodeHeaders[0],
+ }, vars.NodeInternalDNS[0], vars.Namespace)
if err != nil {
return nil, nil, nil, nil, err
}
clClients = append(clClients, c)
// all the other nodes, indices of nodes in CRIB starts with 1
- for i := 2; i <= nodes; i++ {
+ for i := 1; i < vars.Nodes; i++ {
cl, err := client.NewChainlinkK8sClient(&client.ChainlinkConfig{
- URL: fmt.Sprintf("https://%s-node%d%s", cribNamespace, i, ingressSuffix),
Email: client.CLNodeTestEmail,
- InternalIP: fmt.Sprintf(internalNodeDNSTemplate, i),
Password: client.CLNodeTestPassword,
- }, fmt.Sprintf(internalNodeDNSTemplate, i), cribNamespace)
+ URL: vars.NodeURLs[i],
+ InternalIP: vars.NodeInternalDNS[i],
+ Headers: vars.NodeHeaders[i],
+ }, vars.NodeInternalDNS[i], vars.Namespace)
if err != nil {
return nil, nil, nil, nil, err
}
clClients = append(clClients, cl)
}
mockServerClient := msClient.NewMockserverClient(&msClient.MockserverConfig{
- LocalURL: mockserverURL,
- ClusterURL: mockserverURL,
+ LocalURL: vars.MockserverURL,
+ ClusterURL: "http://mockserver:1080",
+ Headers: vars.MockserverHeaders,
})
//nolint:gosec // G602 - false positive https://github.com/securego/gosec/issues/1005
diff --git a/integration-tests/crib/ocr_test.go b/integration-tests/crib/ocr_test.go
index b84af02a196..0b7c38597cc 100644
--- a/integration-tests/crib/ocr_test.go
+++ b/integration-tests/crib/ocr_test.go
@@ -6,7 +6,8 @@ import (
"testing"
"time"
- "github.com/smartcontractkit/havoc/k8schaos"
+ "github.com/smartcontractkit/chainlink-testing-framework/havoc"
+
"github.com/stretchr/testify/require"
"github.com/smartcontractkit/chainlink/integration-tests/actions"
@@ -33,22 +34,24 @@ func TestCRIB(t *testing.T) {
err = actions.WatchNewOCRRound(l, sethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), 5*time.Minute)
require.NoError(t, err, "Error watching for new OCR round")
- ch, err := rebootCLNamespace(
- 1*time.Second,
- os.Getenv("CRIB_NAMESPACE"),
- )
- ch.Create(context.Background())
- ch.AddListener(k8schaos.NewChaosLogger(l))
- t.Cleanup(func() {
- err := ch.Delete(context.Background())
- require.NoError(t, err)
- })
- require.Eventually(t, func() bool {
- err = actions.WatchNewOCRRound(l, sethClient, 3, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), 5*time.Minute)
- if err != nil {
- l.Info().Err(err).Msg("OCR round is not there yet")
- return false
- }
- return true
- }, 3*time.Minute, 5*time.Second)
+ if os.Getenv("TEST_PERSISTENCE") != "" {
+ ch, err := rebootCLNamespace(
+ 1*time.Second,
+ os.Getenv("CRIB_NAMESPACE"),
+ )
+ ch.Create(context.Background())
+ ch.AddListener(havoc.NewChaosLogger(l))
+ t.Cleanup(func() {
+ err := ch.Delete(context.Background())
+ require.NoError(t, err)
+ })
+ require.Eventually(t, func() bool {
+ err = actions.WatchNewOCRRound(l, sethClient, 3, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), 5*time.Minute)
+ if err != nil {
+ l.Info().Err(err).Msg("OCR round is not there yet")
+ return false
+ }
+ return true
+ }, 20*time.Minute, 5*time.Second)
+ }
}
diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go
index 0b7c9de5ffb..1ab577bf54e 100644
--- a/integration-tests/docker/test_env/test_env_builder.go
+++ b/integration-tests/docker/test_env/test_env_builder.go
@@ -3,15 +3,18 @@ package test_env
import (
"fmt"
"os"
+ "path/filepath"
"slices"
"strings"
"testing"
+ "time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
-
"go.uber.org/zap/zapcore"
+ "github.com/smartcontractkit/seth"
+
"github.com/smartcontractkit/chainlink-testing-framework/blockchain"
ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
"github.com/smartcontractkit/chainlink-testing-framework/docker/test_env"
@@ -19,10 +22,10 @@ import (
"github.com/smartcontractkit/chainlink-testing-framework/logstream"
"github.com/smartcontractkit/chainlink-testing-framework/networks"
"github.com/smartcontractkit/chainlink-testing-framework/testreporters"
+ "github.com/smartcontractkit/chainlink-testing-framework/testsummary"
"github.com/smartcontractkit/chainlink-testing-framework/utils/osutil"
- "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
-
"github.com/smartcontractkit/chainlink/integration-tests/types/config/node"
+ "github.com/smartcontractkit/chainlink/v2/core/services/chainlink"
)
type CleanUpType string
@@ -255,7 +258,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) {
b.t.Cleanup(func() {
b.l.Info().Msg("Shutting down LogStream")
logPath, err := osutil.GetAbsoluteFolderPath("logs")
- if err != nil {
+ if err == nil {
b.l.Info().Str("Absolute path", logPath).Msg("LogStream logs folder location")
}
@@ -280,7 +283,8 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) {
// new logs can be added to the log stream, so parallel processing would get stuck on waiting for it to be unlocked
LogScanningLoop:
for i := 0; i < b.clNodesCount; i++ {
- if b == nil || b.te == nil || b.te.ClCluster == nil || b.te.ClCluster.Nodes == nil || b.te.ClCluster.Nodes[i] == nil || len(b.te.ClCluster.Nodes)-1 < i {
+ // if something went wrong during environment setup we might not have all nodes, and we don't want an NPE
+ if b == nil || b.te == nil || b.te.ClCluster == nil || b.te.ClCluster.Nodes == nil || len(b.te.ClCluster.Nodes)-1 < i || b.te.ClCluster.Nodes[i] == nil {
continue
}
// ignore count return, because we are only interested in the error
@@ -307,6 +311,47 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) {
b.te.LogStream.SaveLogLocationInTestSummary()
}
b.l.Info().Msg("Finished shutting down LogStream")
+
+ if b.t.Failed() || *b.testConfig.GetLoggingConfig().TestLogCollect {
+ b.l.Info().Msg("Dump state of all Postgres DBs used by Chainlink Nodes")
+
+ dbDumpFolder := "db_dumps"
+ dbDumpPath := fmt.Sprintf("%s/%s-%s", dbDumpFolder, b.t.Name(), time.Now().Format("2006-01-02T15-04-05"))
+ if err := os.MkdirAll(dbDumpPath, os.ModePerm); err != nil {
+ b.l.Error().Err(err).Msg("Error creating folder for Postgres DB dump")
+ return
+ }
+
+ absDbDumpPath, err := osutil.GetAbsoluteFolderPath(dbDumpFolder)
+ if err == nil {
+ b.l.Info().Str("Absolute path", absDbDumpPath).Msg("PostgresDB dump folder location")
+ }
+
+ for i := 0; i < b.clNodesCount; i++ {
+ // if something went wrong during environment setup we might not have all nodes, and we don't want an NPE
+ if b == nil || b.te == nil || b.te.ClCluster == nil || b.te.ClCluster.Nodes == nil || len(b.te.ClCluster.Nodes)-1 < i || b.te.ClCluster.Nodes[i] == nil || b.te.ClCluster.Nodes[i].PostgresDb == nil {
+ continue
+ }
+
+ filePath := filepath.Join(dbDumpPath, fmt.Sprintf("postgres_db_dump_%s.sql", b.te.ClCluster.Nodes[i].ContainerName))
+ localDbDumpFile, err := os.Create(filePath)
+ if err != nil {
+ b.l.Error().Err(err).Msg("Error creating localDbDumpFile for Postgres DB dump")
+ _ = localDbDumpFile.Close()
+ continue
+ }
+
+ if err := b.te.ClCluster.Nodes[i].PostgresDb.ExecPgDumpFromContainer(localDbDumpFile); err != nil {
+ b.l.Error().Err(err).Msg("Error dumping Postgres DB")
+ }
+ _ = localDbDumpFile.Close()
+ }
+ b.l.Info().Msg("Finished dumping state of all Postgres DBs used by Chainlink Nodes")
+ }
+
+ if b.testConfig.GetSethConfig() != nil && ((b.t.Failed() && slices.Contains(b.testConfig.GetSethConfig().TraceOutputs, seth.TraceOutput_DOT) && b.testConfig.GetSethConfig().TracingLevel != seth.TracingLevel_None) || (!b.t.Failed() && slices.Contains(b.testConfig.GetSethConfig().TraceOutputs, seth.TraceOutput_DOT) && b.testConfig.GetSethConfig().TracingLevel == seth.TracingLevel_All)) {
+ _ = testsummary.AddEntry(b.t.Name(), "dot_graphs", "true")
+ }
})
} else {
b.l.Warn().Msg("LogStream won't be cleaned up, because either test instance is not set or cleanup type is set to none")
diff --git a/integration-tests/go.mod b/integration-tests/go.mod
index 19a7218a3df..708a369fc9a 100644
--- a/integration-tests/go.mod
+++ b/integration-tests/go.mod
@@ -6,12 +6,15 @@ go 1.22.5
replace github.com/smartcontractkit/chainlink/v2 => ../
require (
- github.com/avast/retry-go/v4 v4.5.1
+ dario.cat/mergo v1.0.0
+ github.com/AlekSi/pointer v1.1.0
+ github.com/Masterminds/semver/v3 v3.2.1
+ github.com/avast/retry-go/v4 v4.6.0
github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df
- github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240709130330-9f4feec7553f
+ github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240821051457-da69c6d9617a
github.com/cli/go-gh/v2 v2.0.0
github.com/ethereum/go-ethereum v1.13.8
- github.com/fxamacker/cbor/v2 v2.6.0
+ github.com/fxamacker/cbor/v2 v2.7.0
github.com/go-resty/resty/v2 v2.11.0
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.6.0
@@ -22,32 +25,36 @@ require (
github.com/onsi/gomega v1.33.1
github.com/pelletier/go-toml/v2 v2.2.2
github.com/pkg/errors v0.9.1
- github.com/rs/zerolog v1.31.0
+ github.com/prometheus/common v0.55.0
+ github.com/rs/zerolog v1.33.0
github.com/scylladb/go-reflectx v1.0.1
github.com/segmentio/ksuid v1.0.4
github.com/shopspring/decimal v1.4.0
github.com/slack-go/slack v0.12.2
+ github.com/smartcontractkit/chain-selectors v1.0.21
github.com/smartcontractkit/chainlink-automation v1.0.4
- github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1
- github.com/smartcontractkit/chainlink-testing-framework v1.32.7
- github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239
+ github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5
+ github.com/smartcontractkit/chainlink-testing-framework v1.34.6
+ github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.1
+ github.com/smartcontractkit/chainlink-testing-framework/havoc v0.0.0-20240822140612-df8e03c10dc1
github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000
- github.com/smartcontractkit/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7
- github.com/smartcontractkit/seth v1.0.12
+ github.com/smartcontractkit/seth v1.1.2
github.com/smartcontractkit/wasp v0.4.5
- github.com/spf13/cobra v1.8.0
+ github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
github.com/test-go/testify v1.1.4
github.com/testcontainers/testcontainers-go v0.28.0
github.com/umbracle/ethgo v0.1.3
+ go.uber.org/atomic v1.11.0
+ go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0
- golang.org/x/sync v0.7.0
- golang.org/x/text v0.16.0
+ golang.org/x/crypto v0.26.0
+ golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
+ golang.org/x/sync v0.8.0
+ golang.org/x/text v0.17.0
gopkg.in/guregu/null.v4 v4.0.0
- gopkg.in/yaml.v2 v2.4.0
- gopkg.in/yaml.v3 v3.0.1
- k8s.io/apimachinery v0.28.2
+ k8s.io/apimachinery v0.31.0
)
// avoids ambigious imports of indirect dependencies
@@ -60,7 +67,6 @@ require (
cosmossdk.io/depinject v1.0.0-alpha.3 // indirect
cosmossdk.io/errors v1.0.0 // indirect
cosmossdk.io/math v1.0.1 // indirect
- dario.cat/mergo v1.0.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.1 // indirect
@@ -78,7 +84,6 @@ require (
github.com/K-Phoen/sdk v0.12.4 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // 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/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
@@ -90,14 +95,30 @@ require (
github.com/armon/go-metrics v0.4.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/avast/retry-go v3.0.0+incompatible // indirect
+ github.com/awalterschulze/gographviz v2.0.3+incompatible // indirect
github.com/aws/aws-sdk-go v1.45.25 // indirect
+ github.com/aws/aws-sdk-go-v2 v1.30.4 // indirect
+ github.com/aws/aws-sdk-go-v2/config v1.27.28 // indirect
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.28 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect
+ github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 // indirect
github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect
github.com/aws/jsii-runtime-go v1.75.0 // indirect
+ github.com/aws/smithy-go v1.20.4 // 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
github.com/bits-and-blooms/bitset v1.10.0 // indirect
+ github.com/blang/semver/v4 v4.0.0 // indirect
github.com/blendle/zapdriver v1.3.1 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
@@ -142,7 +163,7 @@ require (
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/deckarep/golang-set/v2 v2.3.0 // indirect
+ github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dennwc/varint v1.0.0 // indirect
github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 // indirect
@@ -162,15 +183,13 @@ require (
github.com/emicklei/go-restful/v3 v3.12.1 // indirect
github.com/esote/minmaxheap v1.0.0 // indirect
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
- github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect
github.com/fatih/camelcase v1.0.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
- github.com/fsnotify/fsnotify v1.6.0 // indirect
- github.com/fvbommel/sortorder v1.1.0 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gagliardetto/binary v0.7.7 // indirect
github.com/gagliardetto/solana-go v1.8.4 // indirect
@@ -223,7 +242,7 @@ require (
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-20240424215950-a892ee059fd6 // indirect
+ github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gorilla/context v1.1.1 // indirect
@@ -239,7 +258,7 @@ require (
github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 // indirect
github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 // indirect
github.com/grafana/pyroscope-go v1.1.1 // indirect
- github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // indirect
+ github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
@@ -269,6 +288,7 @@ require (
github.com/hashicorp/serf v0.10.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
+ github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/holiman/uint256 v1.2.4 // indirect
github.com/huandu/skiplist v1.2.0 // indirect
@@ -295,7 +315,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
- github.com/klauspost/compress v1.17.3 // indirect
+ github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
@@ -336,6 +356,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect
+ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
@@ -357,11 +378,10 @@ require (
github.com/prometheus/alertmanager v0.26.0 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
- github.com/prometheus/common v0.55.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.15.1 // indirect
- github.com/prometheus/prometheus v1.8.2-0.20200727090838-6f296594a852 // indirect
+ github.com/prometheus/prometheus v0.48.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
@@ -375,11 +395,11 @@ require (
github.com/shirou/gopsutil/v3 v3.24.3 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
- github.com/smartcontractkit/chain-selectors v1.0.10 // indirect
+ github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 // indirect
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 // indirect
- github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa // indirect
+ github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2 // indirect
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 // indirect
- github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e // indirect
+ github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f // indirect
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799 // 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
@@ -422,10 +442,10 @@ require (
github.com/zondax/ledger-go v0.14.1 // indirect
go.dedis.ch/fixbuf v1.0.3 // indirect
go.dedis.ch/kyber/v3 v3.1.0 // indirect
- go.etcd.io/bbolt v1.3.8 // indirect
- go.etcd.io/etcd/api/v3 v3.5.10 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
- go.etcd.io/etcd/client/v3 v3.5.10 // indirect
+ go.etcd.io/bbolt v1.3.9 // indirect
+ go.etcd.io/etcd/api/v3 v3.5.14 // indirect
+ go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
+ go.etcd.io/etcd/client/v3 v3.5.14 // indirect
go.mongodb.org/mongo-driver v1.15.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect
@@ -440,21 +460,17 @@ require (
go.opentelemetry.io/otel/trace v1.28.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
- go.uber.org/atomic v1.11.0 // indirect
go.uber.org/goleak v1.3.0 // indirect
- go.uber.org/multierr v1.11.0 // indirect
go.uber.org/ratelimit v0.3.0 // indirect
go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect
golang.org/x/arch v0.8.0 // indirect
- golang.org/x/crypto v0.25.0 // indirect
- golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 // indirect
- golang.org/x/mod v0.19.0 // indirect
- golang.org/x/net v0.27.0 // indirect
+ golang.org/x/mod v0.20.0 // indirect
+ golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
- golang.org/x/sys v0.22.0 // indirect
- golang.org/x/term v0.22.0 // indirect
+ golang.org/x/sys v0.23.0 // indirect
+ golang.org/x/term v0.23.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.23.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d // indirect
@@ -462,25 +478,28 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20240711142825-46eb208f015d // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
+ gopkg.in/evanphx/json-patch.v4 v4.12.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
- k8s.io/api v0.28.2 // indirect
- k8s.io/apiextensions-apiserver v0.28.1 // indirect
- k8s.io/cli-runtime v0.28.2 // indirect
- k8s.io/client-go v0.28.2 // indirect
- k8s.io/component-base v0.28.2 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+ k8s.io/api v0.31.0 // indirect
+ k8s.io/apiextensions-apiserver v0.31.0 // indirect
+ k8s.io/cli-runtime v0.31.0 // indirect
+ k8s.io/client-go v0.31.0 // indirect
+ k8s.io/component-base v0.31.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f // indirect
- k8s.io/kubectl v0.28.1 // indirect
- k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect
+ k8s.io/kubectl v0.31.0 // indirect
+ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // 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/controller-runtime v0.16.2 // indirect
+ sigs.k8s.io/controller-runtime v0.19.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
- sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
- sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
+ sigs.k8s.io/kustomize/api v0.17.2 // indirect
+ sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
@@ -507,37 +526,3 @@ replace (
github.com/prometheus/client_golang => github.com/prometheus/client_golang v1.14.0
github.com/prometheus/common => github.com/prometheus/common v0.42.0
)
-
-replace (
- k8s.io/api => k8s.io/api v0.28.2
- k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.28.2
- k8s.io/apimachinery => k8s.io/apimachinery v0.28.2
- k8s.io/apiserver => k8s.io/apiserver v0.28.2
- k8s.io/cli-runtime => k8s.io/cli-runtime v0.28.2
- k8s.io/client-go => k8s.io/client-go v0.28.2
- k8s.io/cloud-provider => k8s.io/cloud-provider v0.28.2
- k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.28.2
- k8s.io/code-generator => k8s.io/code-generator v0.28.2
- k8s.io/component-base => k8s.io/component-base v0.28.2
- k8s.io/component-helpers => k8s.io/component-helpers v0.28.2
- k8s.io/controller-manager => k8s.io/controller-manager v0.28.2
- k8s.io/cri-api => k8s.io/cri-api v0.28.2
- k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.28.2
- k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.28.2
- k8s.io/endpointslice => k8s.io/endpointslice v0.28.2
- k8s.io/kms => k8s.io/kms v0.28.2
- k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.28.2
- k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.28.2
- k8s.io/kube-proxy => k8s.io/kube-proxy v0.28.2
- k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.28.2
- k8s.io/kubectl => k8s.io/kubectl v0.28.2
- k8s.io/kubelet => k8s.io/kubelet v0.28.2
- k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.28.2
- k8s.io/metrics => k8s.io/metrics v0.28.2
- k8s.io/mount-utils => k8s.io/mount-utils v0.28.2
- k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.28.2
- k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.28.2
- k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.28.2
- k8s.io/sample-controller => k8s.io/sample-controller v0.28.2
- sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.16.2
-)
diff --git a/integration-tests/go.sum b/integration-tests/go.sum
index 23f1d900d15..b8c3d5c94aa 100644
--- a/integration-tests/go.sum
+++ b/integration-tests/go.sum
@@ -207,17 +207,47 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
-github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o=
-github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc=
+github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
+github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
+github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E=
+github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=
github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
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/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8=
+github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
+github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg=
+github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5 h1:UDXu9dqpCZYonj7poM4kFISjzTdWI0v3WUusM+w+Gfc=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5/go.mod h1:5NPkI3RsTOhwz1CuG7VVSgJCm3CINKkoIaUbUZWQ67w=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0=
github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3sWOxO2Dfja0iA1W7ZcI7g=
github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI=
github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4=
github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYSN6/mGyHI6O3I=
+github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4=
+github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
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=
@@ -236,6 +266,8 @@ github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsy
github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88=
github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
+github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE=
github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
@@ -277,8 +309,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
-github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240709130330-9f4feec7553f h1:onZ3oc6l1Gz8pVpQ0c1U1Cb11kIMoDb3xtEy/iZbYZM=
-github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240709130330-9f4feec7553f/go.mod h1:x11iCbZV6hzzSQWMq610B6Wl5Lg1dhwqcVfeiWQQnQQ=
+github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240821051457-da69c6d9617a h1:6Pg3a6j/41QDzH/oYcMLwwKsf3x/HXcu9W/dBaf2Hzs=
+github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240821051457-da69c6d9617a/go.mod h1:x11iCbZV6hzzSQWMq610B6Wl5Lg1dhwqcVfeiWQQnQQ=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
@@ -388,8 +420,8 @@ github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHf
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
-github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ=
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA=
@@ -413,8 +445,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g=
-github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
+github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
@@ -516,12 +548,10 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
-github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
-github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
-github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA=
-github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
+github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
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/gagliardetto/binary v0.7.7 h1:QZpT38+sgoPg+TIQjH94sLbl/vX+nlIRA37pEyOsjfY=
@@ -585,8 +615,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/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.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
-github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
+github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
+github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -680,15 +710,12 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe
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 h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
-github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
-github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
+github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
-github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
-github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
-github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
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 v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
@@ -805,8 +832,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
-github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
+github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
@@ -860,8 +887,8 @@ github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 h1:wQ0FnSeeb
github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0=
github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ=
github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88=
-github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo=
-github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
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/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug=
@@ -1106,8 +1133,8 @@ github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
-github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
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=
@@ -1150,6 +1177,8 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhn
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/linode/linodego v1.19.0 h1:n4WJrcr9+30e9JGZ6DI0nZbm5SdAj1kSwvvt/998YUw=
github.com/linode/linodego v1.19.0/go.mod h1:XZFR+yJ9mm2kwf6itZ6SCpu+6w3KnIevV0Uu5HNWJgQ=
+github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
+github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@@ -1287,6 +1316,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
@@ -1311,8 +1342,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
-github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g=
-github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
+github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
+github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
@@ -1432,8 +1463,8 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
-github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
-github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
+github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
@@ -1482,36 +1513,38 @@ 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/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/chain-selectors v1.0.21 h1:KCR9SA7PhOexaBzFieHoLv1WonwhVOPtOStpqTmLC4E=
+github.com/smartcontractkit/chain-selectors v1.0.21/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8=
github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM=
-github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1 h1:pdEpjgbZ5w/Sd5lzg/XiuC5gVyrmSovOo+3nUD46SP8=
-github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1/go.mod h1:Jg1sCTsbxg76YByI8ifpFby3FvVqISStHT8ypy9ocmY=
+github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 h1:LAgJTg9Yr/uCo2g7Krp88Dco2U45Y6sbJVl8uKoLkys=
+github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95/go.mod h1:/ZWraCBaDDgaIN1prixYcbVvIk/6HeED9+8zbWQ+TMo=
+github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5 h1:+XvRzgHlcaZYLMJ5HR3HzOjvXNmpVKQFZbuHZiRno68=
+github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5/go.mod h1:5rmU5YKBkIOwWkuNZi26sMXlBUBm6weBFXh+8BEEp2s=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 h1:NBQLtqk8zsyY4qTJs+NElI3aDFTcAo83JHvqD04EvB0=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45/go.mod h1:LV0h7QBQUpoC2UUi6TcUvcIFm1xjP/DtEcqV8+qeLUs=
-github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa h1:g75H8oh2ws52s8BekwvGQ9XvBVu3E7WM1rfiA0PN0zk=
-github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa/go.mod h1:wZvLHX/Sd9hskN51016cTFcT3G62KXVa6xbVDS7tRjc=
+github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2 h1:KH6tpCw5hu8u6UTtgll7a8mE4sIbHCbmtzHJdKuRwBw=
+github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2/go.mod h1:V/86loaFSH0dqqUEHqyXVbyNqDRSjvcf9BRomWFTljU=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 h1:BCHu4pNP6arrcHLEWx61XjLaonOd2coQNyL0NTUcaMc=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827/go.mod h1:OPX+wC2TWQsyLNpR7daMt2vMpmsNcoBxbZyGTHr6tiA=
-github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e h1:PzwzlHNv1YbJ6ZIdl/pIFRoOuOS4V4WLvjZvFUnZFL4=
-github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e/go.mod h1:hsFhop+SlQHKD+DEFjZrMJmbauT1A/wvtZIeeo4PxFU=
+github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f h1:b0Ifwk7eK3fwJ0R69Ovhv5XvZ1/TUAfHkU5Jp7wbNZ0=
+github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f/go.mod h1:Ml88TJTwZCj6yHDkAEN/EhxVutzSlk+kDZgfibRIqF0=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799 h1:HyLTySm7BR+oNfZqDTkVJ25wnmcTtxBBD31UkFL+kEM=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799/go.mod h1:UVFRacRkP7O7TQAzFmR52v5mUlxf+G1ovMlCQAB/cHU=
-github.com/smartcontractkit/chainlink-testing-framework v1.32.7 h1:/I6Upq9KdnleWnUF1W3c3mAgMowAgi0yAcn8Vh5Px50=
-github.com/smartcontractkit/chainlink-testing-framework v1.32.7/go.mod h1:Y1D6k7KLPZ52kwp3WJxShp4Wzw22jKldIzMT2yosipI=
-github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 h1:Kk5OVlx/5g9q3Z3lhxytZS4/f8ds1MiNM8yaHgK3Oe8=
-github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU=
+github.com/smartcontractkit/chainlink-testing-framework v1.34.6 h1:x6pdcJ1hcdRJEQxyQltSMbLs+g5ddRw1HOLuLOAnSaI=
+github.com/smartcontractkit/chainlink-testing-framework v1.34.6/go.mod h1:tweBFcNZQpKfRtXDQBrvVRrnAmGclByiyuyF/qAU/Eo=
+github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.1 h1:1/r1wQZ4TOFpZ13w94r7amdF096Z96RuEnkOmrz1BGE=
+github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.1/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU=
+github.com/smartcontractkit/chainlink-testing-framework/havoc v0.0.0-20240822140612-df8e03c10dc1 h1:7LbvjrRseY/Cu9mgPO31SgdEUiZJJemc6glCfpLdMtM=
+github.com/smartcontractkit/chainlink-testing-framework/havoc v0.0.0-20240822140612-df8e03c10dc1/go.mod h1:7AOGJdlSPycsHxgbOLP9EJyHxRxB9+dD2Q7lJFMPwWk=
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/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37 h1:ZEhn2Yo1jY4hqy8nasDL4k4pNtopT3rS3Ap1GDb7ODc=
-github.com/smartcontractkit/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37/go.mod h1:/kFr0D7SI/vueXl1N03uzOun4nViGPFRyA5X6eL3jXw=
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7 h1:e38V5FYE7DA1JfKXeD5Buo/7lczALuVXlJ8YNTAUxcw=
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM=
-github.com/smartcontractkit/seth v1.0.12 h1:iVdgMx42XWanPPnBaM5StR4c1XsTr/0/B/kKRZL5BsY=
-github.com/smartcontractkit/seth v1.0.12/go.mod h1:thWtbLyW4nRHJGzC5heknQDORoJPErE15sF34LHkorg=
+github.com/smartcontractkit/seth v1.1.2 h1:98v9VUFUpNhU7UofeF/bGyUIVv9jnt+JlIE+I8mhX2c=
+github.com/smartcontractkit/seth v1.1.2/go.mod h1:cDfKHi/hJLpO9sRpVbrflrHCOV+MJPAMJHloExJnIXk=
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=
@@ -1540,8 +1573,8 @@ github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cA
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
-github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
-github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@@ -1703,14 +1736,14 @@ go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRL
go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4=
go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
-go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
-go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
-go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI=
-go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0=
-go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U=
-go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao=
-go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc=
+go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
+go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
+go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0=
+go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU=
+go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ=
+go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
+go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
+go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
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=
@@ -1822,8 +1855,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
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.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
-golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
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=
@@ -1834,8 +1867,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
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-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA=
-golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
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=
@@ -1863,8 +1896,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/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.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
-golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1926,8 +1959,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.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.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
-golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
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=
@@ -1956,8 +1989,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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=
@@ -2043,7 +2076,6 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
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.0.0-20221010170243-090e33056c14/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=
@@ -2054,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.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
-golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.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=
@@ -2067,8 +2099,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.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
-golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
+golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
+golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
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=
@@ -2082,8 +2114,8 @@ 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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
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=
@@ -2161,8 +2193,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
-golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2302,6 +2334,8 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
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/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
+gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
@@ -2346,26 +2380,26 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
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=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
-k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw=
-k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg=
-k8s.io/apiextensions-apiserver v0.28.2 h1:J6/QRWIKV2/HwBhHRVITMLYoypCoPY1ftigDM0Kn+QU=
-k8s.io/apiextensions-apiserver v0.28.2/go.mod h1:5tnkxLGa9nefefYzWuAlWZ7RZYuN/765Au8cWLA6SRg=
-k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ=
-k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU=
-k8s.io/cli-runtime v0.28.2 h1:64meB2fDj10/ThIMEJLO29a1oujSm0GQmKzh1RtA/uk=
-k8s.io/cli-runtime v0.28.2/go.mod h1:bTpGOvpdsPtDKoyfG4EG041WIyFZLV9qq4rPlkyYfDA=
-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/component-base v0.28.2 h1:Yc1yU+6AQSlpJZyvehm/NkJBII72rzlEsd6MkBQ+G0E=
-k8s.io/component-base v0.28.2/go.mod h1:4IuQPQviQCg3du4si8GpMrhAIegxpsgPngPRR/zWpzc=
+k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo=
+k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE=
+k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk=
+k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk=
+k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc=
+k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
+k8s.io/cli-runtime v0.31.0 h1:V2Q1gj1u3/WfhD475HBQrIYsoryg/LrhhK4RwpN+DhA=
+k8s.io/cli-runtime v0.31.0/go.mod h1:vg3H94wsubuvWfSmStDbekvbla5vFGC+zLWqcf+bGDw=
+k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8=
+k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU=
+k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs=
+k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f h1:2sXuKesAYbRHxL3aE2PN6zX/gcJr22cjrsej+W784Tc=
k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc=
-k8s.io/kubectl v0.28.2 h1:fOWOtU6S0smdNjG1PB9WFbqEIMlkzU5ahyHkc7ESHgM=
-k8s.io/kubectl v0.28.2/go.mod h1:6EQWTPySF1fn7yKoQZHYf9TPwIl2AygHEcJoxFekr64=
-k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
-k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/kubectl v0.31.0 h1:kANwAAPVY02r4U4jARP/C+Q1sssCcN/1p9Nk+7BQKVg=
+k8s.io/kubectl v0.31.0/go.mod h1:pB47hhFypGsaHAPjlwrNbvhXgmuAr01ZBvAIIUaI8d4=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/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=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
@@ -2377,14 +2411,14 @@ 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/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQVuIPU=
-sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU=
+sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q=
+sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4=
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/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
-sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
-sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
-sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
+sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g=
+sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0=
+sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ=
+sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod
index 75575382c76..ba5c1d3ef94 100644
--- a/integration-tests/load/go.mod
+++ b/integration-tests/load/go.mod
@@ -13,15 +13,15 @@ require (
github.com/go-resty/resty/v2 v2.11.0
github.com/pelletier/go-toml/v2 v2.2.2
github.com/pkg/errors v0.9.1
- github.com/rs/zerolog v1.31.0
+ github.com/rs/zerolog v1.33.0
github.com/slack-go/slack v0.12.2
github.com/smartcontractkit/chainlink-automation v1.0.4
- github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1
- github.com/smartcontractkit/chainlink-testing-framework v1.32.7
+ github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5
+ github.com/smartcontractkit/chainlink-testing-framework v1.34.6
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-20240717100443-f6226e09bee7
- github.com/smartcontractkit/seth v1.0.12
+ github.com/smartcontractkit/seth v1.1.2
github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1
github.com/smartcontractkit/wasp v0.4.7
github.com/stretchr/testify v1.9.0
@@ -35,11 +35,30 @@ require (
cosmossdk.io/depinject v1.0.0-alpha.3 // indirect
cosmossdk.io/errors v1.0.0 // indirect
cosmossdk.io/math v1.0.1 // indirect
+ github.com/awalterschulze/gographviz v2.0.3+incompatible // indirect
+ github.com/aws/aws-sdk-go-v2 v1.30.4 // indirect
+ github.com/aws/aws-sdk-go-v2/config v1.27.28 // indirect
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.28 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
+ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect
+ github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 // indirect
+ github.com/aws/smithy-go v1.20.4 // indirect
+ github.com/blang/semver/v4 v4.0.0 // indirect
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 // indirect
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 // indirect
- k8s.io/apimachinery v0.30.2 // indirect
+ github.com/smartcontractkit/chainlink-testing-framework/havoc v0.0.0-20240822140612-df8e03c10dc1 // indirect
+ gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
+ k8s.io/apimachinery v0.31.0 // indirect
)
// avoids ambigious imports of indirect dependencies
@@ -76,7 +95,7 @@ require (
github.com/armon/go-metrics v0.4.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/avast/retry-go v3.0.0+incompatible // indirect
- github.com/avast/retry-go/v4 v4.5.1 // indirect
+ github.com/avast/retry-go/v4 v4.6.0 // indirect
github.com/aws/aws-sdk-go v1.45.25 // indirect
github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect
github.com/aws/jsii-runtime-go v1.75.0 // indirect
@@ -98,7 +117,7 @@ require (
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
- github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240709130330-9f4feec7553f // indirect
+ github.com/chaos-mesh/chaos-mesh/api v0.0.0-20240821051457-da69c6d9617a // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/cockroachdb/errors v1.9.1 // indirect
@@ -130,7 +149,7 @@ require (
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
- github.com/deckarep/golang-set/v2 v2.3.0 // indirect
+ github.com/deckarep/golang-set/v2 v2.6.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dennwc/varint v1.0.0 // indirect
github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 // indirect
@@ -157,9 +176,9 @@ require (
github.com/fatih/camelcase v1.0.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
- github.com/fsnotify/fsnotify v1.6.0 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fvbommel/sortorder v1.1.0 // indirect
- github.com/fxamacker/cbor/v2 v2.6.0 // indirect
+ github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gagliardetto/binary v0.7.7 // indirect
github.com/gagliardetto/solana-go v1.8.4 // indirect
@@ -212,7 +231,7 @@ require (
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-20240424215950-a892ee059fd6 // indirect
+ github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/context v1.1.1 // indirect
@@ -228,7 +247,7 @@ require (
github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 // indirect
github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 // indirect
github.com/grafana/pyroscope-go v1.1.1 // indirect
- github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // indirect
+ github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
@@ -285,7 +304,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/julienschmidt/httprouter v1.3.0 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
- github.com/klauspost/compress v1.17.3 // indirect
+ github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
@@ -352,7 +371,7 @@ require (
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.15.1 // indirect
- github.com/prometheus/prometheus v1.8.2-0.20200727090838-6f296594a852 // indirect
+ github.com/prometheus/prometheus v0.48.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
@@ -368,13 +387,12 @@ require (
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
- github.com/smartcontractkit/chain-selectors v1.0.10 // indirect
- github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa // indirect
+ github.com/smartcontractkit/chain-selectors v1.0.21 // indirect
+ github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2 // indirect
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 // indirect
- github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e // indirect
+ github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f // indirect
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799 // indirect
- github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 // indirect
- github.com/smartcontractkit/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37 // indirect
+ github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.2-0.20240805111647-acf86c1e347a // indirect
github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect
github.com/smartcontractkit/wsrpc v0.7.3 // indirect
github.com/soheilhy/cmux v0.1.5 // indirect
@@ -419,10 +437,10 @@ require (
github.com/zondax/ledger-go v0.14.1 // indirect
go.dedis.ch/fixbuf v1.0.3 // indirect
go.dedis.ch/kyber/v3 v3.1.0 // indirect
- go.etcd.io/bbolt v1.3.8 // indirect
- go.etcd.io/etcd/api/v3 v3.5.10 // indirect
- go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
- go.etcd.io/etcd/client/v3 v3.5.10 // indirect
+ go.etcd.io/bbolt v1.3.9 // indirect
+ go.etcd.io/etcd/api/v3 v3.5.14 // indirect
+ go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
+ go.etcd.io/etcd/client/v3 v3.5.14 // indirect
go.mongodb.org/mongo-driver v1.15.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 // indirect
@@ -443,17 +461,17 @@ require (
go.uber.org/zap v1.27.0 // indirect
go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect
golang.org/x/arch v0.8.0 // indirect
- golang.org/x/crypto v0.25.0 // indirect
- golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 // indirect
- golang.org/x/mod v0.19.0 // indirect
- golang.org/x/net v0.27.0 // indirect
+ golang.org/x/crypto v0.26.0 // indirect
+ golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect
+ golang.org/x/mod v0.20.0 // indirect
+ golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
- golang.org/x/sync v0.7.0 // indirect
- golang.org/x/sys v0.22.0 // indirect
- golang.org/x/term v0.22.0 // indirect
- golang.org/x/text v0.16.0 // indirect
+ golang.org/x/sync v0.8.0 // indirect
+ golang.org/x/sys v0.23.0 // indirect
+ golang.org/x/term v0.23.0 // indirect
+ golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.23.0 // indirect
+ golang.org/x/tools v0.24.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
google.golang.org/genproto v0.0.0-20240711142825-46eb208f015d // indirect
@@ -467,22 +485,22 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
- k8s.io/api v0.30.2 // indirect
- k8s.io/apiextensions-apiserver v0.30.2 // indirect
- k8s.io/cli-runtime v0.28.2 // indirect
+ k8s.io/api v0.31.0 // indirect
+ k8s.io/apiextensions-apiserver v0.31.0 // indirect
+ k8s.io/cli-runtime v0.31.0 // indirect
k8s.io/client-go v1.5.2 // indirect
- k8s.io/component-base v0.30.2 // indirect
+ k8s.io/component-base v0.31.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f // indirect
- k8s.io/kubectl v0.28.1 // indirect
- k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect
+ k8s.io/kubectl v0.31.0 // indirect
+ k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // 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/controller-runtime v0.18.4 // indirect
+ sigs.k8s.io/controller-runtime v0.19.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
- sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
- sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
+ sigs.k8s.io/kustomize/api v0.17.2 // indirect
+ sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect; indirect nhooyr.io/websocket v1.8.7 // indirect
)
diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum
index 05af3d1b0a0..7f6dddca8d1 100644
--- a/integration-tests/load/go.sum
+++ b/integration-tests/load/go.sum
@@ -207,17 +207,47 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
-github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o=
-github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc=
+github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA=
+github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE=
+github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E=
+github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=
github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
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/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8=
+github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
+github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg=
+github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5 h1:UDXu9dqpCZYonj7poM4kFISjzTdWI0v3WUusM+w+Gfc=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.5/go.mod h1:5NPkI3RsTOhwz1CuG7VVSgJCm3CINKkoIaUbUZWQ67w=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c=
+github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8=
+github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0=
github.com/aws/constructs-go/constructs/v10 v10.1.255 h1:5hARfEmhBqHSTQf/C3QLA3sWOxO2Dfja0iA1W7ZcI7g=
github.com/aws/constructs-go/constructs/v10 v10.1.255/go.mod h1:DCdBSjN04Ck2pajCacTD4RKFqSA7Utya8d62XreYctI=
github.com/aws/jsii-runtime-go v1.75.0 h1:NhpUfyiL7/wsRuUekFsz8FFBCYLfPD/l61kKg9kL/a4=
github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYSN6/mGyHI6O3I=
+github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4=
+github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
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=
@@ -236,6 +266,8 @@ github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsy
github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88=
github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
+github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE=
github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc=
github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c=
@@ -403,8 +435,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g=
-github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
+github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
+github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
@@ -506,12 +538,12 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fvbommel/sortorder v1.1.0 h1:fUmoe+HLsBTctBDoaBwpQo5N+nrCp8g/BjKb/6ZQmYw=
github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
-github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA=
-github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
+github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
+github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
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/gagliardetto/binary v0.7.7 h1:QZpT38+sgoPg+TIQjH94sLbl/vX+nlIRA37pEyOsjfY=
@@ -670,15 +702,12 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe
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 h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
-github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
-github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
+github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
-github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
-github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
-github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
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 v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
@@ -795,8 +824,8 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
-github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
+github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM=
+github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
@@ -850,8 +879,8 @@ github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 h1:wQ0FnSeeb
github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0=
github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ=
github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88=
-github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo=
-github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
+github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
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/graph-gophers/dataloader v5.0.0+incompatible h1:R+yjsbrNq1Mo3aPG+Z/EKYrXrXXUNJHOgbRt+U6jOug=
@@ -1094,8 +1123,8 @@ github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA=
-github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
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=
@@ -1414,8 +1443,8 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
-github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
-github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
+github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
+github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
@@ -1464,36 +1493,38 @@ 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/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/chain-selectors v1.0.21 h1:KCR9SA7PhOexaBzFieHoLv1WonwhVOPtOStpqTmLC4E=
+github.com/smartcontractkit/chain-selectors v1.0.21/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8=
github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM=
-github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1 h1:pdEpjgbZ5w/Sd5lzg/XiuC5gVyrmSovOo+3nUD46SP8=
-github.com/smartcontractkit/chainlink-common v0.2.2-0.20240723123524-e407ecd120b1/go.mod h1:Jg1sCTsbxg76YByI8ifpFby3FvVqISStHT8ypy9ocmY=
+github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 h1:LAgJTg9Yr/uCo2g7Krp88Dco2U45Y6sbJVl8uKoLkys=
+github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95/go.mod h1:/ZWraCBaDDgaIN1prixYcbVvIk/6HeED9+8zbWQ+TMo=
+github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5 h1:+XvRzgHlcaZYLMJ5HR3HzOjvXNmpVKQFZbuHZiRno68=
+github.com/smartcontractkit/chainlink-common v0.2.2-0.20240823093917-c07a4fa0caa5/go.mod h1:5rmU5YKBkIOwWkuNZi26sMXlBUBm6weBFXh+8BEEp2s=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 h1:NBQLtqk8zsyY4qTJs+NElI3aDFTcAo83JHvqD04EvB0=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45/go.mod h1:LV0h7QBQUpoC2UUi6TcUvcIFm1xjP/DtEcqV8+qeLUs=
-github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa h1:g75H8oh2ws52s8BekwvGQ9XvBVu3E7WM1rfiA0PN0zk=
-github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240718160222-2dc0c8136bfa/go.mod h1:wZvLHX/Sd9hskN51016cTFcT3G62KXVa6xbVDS7tRjc=
+github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2 h1:KH6tpCw5hu8u6UTtgll7a8mE4sIbHCbmtzHJdKuRwBw=
+github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240820130645-cf4b159fbba2/go.mod h1:V/86loaFSH0dqqUEHqyXVbyNqDRSjvcf9BRomWFTljU=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 h1:BCHu4pNP6arrcHLEWx61XjLaonOd2coQNyL0NTUcaMc=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827/go.mod h1:OPX+wC2TWQsyLNpR7daMt2vMpmsNcoBxbZyGTHr6tiA=
-github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e h1:PzwzlHNv1YbJ6ZIdl/pIFRoOuOS4V4WLvjZvFUnZFL4=
-github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240712132946-267a37c5ac6e/go.mod h1:hsFhop+SlQHKD+DEFjZrMJmbauT1A/wvtZIeeo4PxFU=
+github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f h1:b0Ifwk7eK3fwJ0R69Ovhv5XvZ1/TUAfHkU5Jp7wbNZ0=
+github.com/smartcontractkit/chainlink-solana v1.1.1-0.20240821170223-a2f5c39f457f/go.mod h1:Ml88TJTwZCj6yHDkAEN/EhxVutzSlk+kDZgfibRIqF0=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799 h1:HyLTySm7BR+oNfZqDTkVJ25wnmcTtxBBD31UkFL+kEM=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240709043547-03612098f799/go.mod h1:UVFRacRkP7O7TQAzFmR52v5mUlxf+G1ovMlCQAB/cHU=
-github.com/smartcontractkit/chainlink-testing-framework v1.32.7 h1:/I6Upq9KdnleWnUF1W3c3mAgMowAgi0yAcn8Vh5Px50=
-github.com/smartcontractkit/chainlink-testing-framework v1.32.7/go.mod h1:Y1D6k7KLPZ52kwp3WJxShp4Wzw22jKldIzMT2yosipI=
-github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239 h1:Kk5OVlx/5g9q3Z3lhxytZS4/f8ds1MiNM8yaHgK3Oe8=
-github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.0-20240405215812-5a72bc9af239/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU=
+github.com/smartcontractkit/chainlink-testing-framework v1.34.6 h1:x6pdcJ1hcdRJEQxyQltSMbLs+g5ddRw1HOLuLOAnSaI=
+github.com/smartcontractkit/chainlink-testing-framework v1.34.6/go.mod h1:tweBFcNZQpKfRtXDQBrvVRrnAmGclByiyuyF/qAU/Eo=
+github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.2-0.20240805111647-acf86c1e347a h1:8GtvGJaGyKzx/ar1yX74GxrzIYWTZVTyv4pYB/1ln8w=
+github.com/smartcontractkit/chainlink-testing-framework/grafana v0.0.2-0.20240805111647-acf86c1e347a/go.mod h1:DC8sQMyTlI/44UCTL8QWFwb0bYNoXCfjwCv2hMivYZU=
+github.com/smartcontractkit/chainlink-testing-framework/havoc v0.0.0-20240822140612-df8e03c10dc1 h1:7LbvjrRseY/Cu9mgPO31SgdEUiZJJemc6glCfpLdMtM=
+github.com/smartcontractkit/chainlink-testing-framework/havoc v0.0.0-20240822140612-df8e03c10dc1/go.mod h1:7AOGJdlSPycsHxgbOLP9EJyHxRxB9+dD2Q7lJFMPwWk=
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/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37 h1:ZEhn2Yo1jY4hqy8nasDL4k4pNtopT3rS3Ap1GDb7ODc=
-github.com/smartcontractkit/havoc/k8schaos v0.0.0-20240409145249-e78d20847e37/go.mod h1:/kFr0D7SI/vueXl1N03uzOun4nViGPFRyA5X6eL3jXw=
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7 h1:e38V5FYE7DA1JfKXeD5Buo/7lczALuVXlJ8YNTAUxcw=
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM=
-github.com/smartcontractkit/seth v1.0.12 h1:iVdgMx42XWanPPnBaM5StR4c1XsTr/0/B/kKRZL5BsY=
-github.com/smartcontractkit/seth v1.0.12/go.mod h1:thWtbLyW4nRHJGzC5heknQDORoJPErE15sF34LHkorg=
+github.com/smartcontractkit/seth v1.1.2 h1:98v9VUFUpNhU7UofeF/bGyUIVv9jnt+JlIE+I8mhX2c=
+github.com/smartcontractkit/seth v1.1.2/go.mod h1:cDfKHi/hJLpO9sRpVbrflrHCOV+MJPAMJHloExJnIXk=
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=
@@ -1685,14 +1716,14 @@ go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRL
go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4=
go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
-go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
-go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
-go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI=
-go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0=
-go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U=
-go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao=
-go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc=
+go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
+go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
+go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0=
+go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU=
+go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ=
+go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI=
+go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg=
+go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk=
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=
@@ -1804,8 +1835,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
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.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
-golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
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=
@@ -1816,8 +1847,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
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-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA=
-golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
+golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
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=
@@ -1845,8 +1876,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/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.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
-golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1908,8 +1939,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.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.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
-golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
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=
@@ -1938,8 +1969,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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=
@@ -2023,7 +2054,6 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
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.0.0-20221010170243-090e33056c14/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=
@@ -2034,8 +2064,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.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
-golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
+golang.org/x/sys v0.23.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=
@@ -2047,8 +2077,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.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
-golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
+golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
+golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
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=
@@ -2062,8 +2092,8 @@ 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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
-golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
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=
@@ -2141,8 +2171,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
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.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
-golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2282,6 +2312,8 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
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/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
+gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
@@ -2344,8 +2376,8 @@ k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f h1:2sXuKesAYbRHxL3aE2PN6z
k8s.io/kube-openapi v0.0.0-20240709000822-3c01b740850f/go.mod h1:UxDHUPsUwTOOxSU+oXURfFBcAS6JwiRXTYqYwfuGowc=
k8s.io/kubectl v0.28.2 h1:fOWOtU6S0smdNjG1PB9WFbqEIMlkzU5ahyHkc7ESHgM=
k8s.io/kubectl v0.28.2/go.mod h1:6EQWTPySF1fn7yKoQZHYf9TPwIl2AygHEcJoxFekr64=
-k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
-k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A=
+k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/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=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
@@ -2361,10 +2393,10 @@ sigs.k8s.io/controller-runtime v0.16.2 h1:mwXAVuEk3EQf478PQwQ48zGOXvW27UJc8NHktQ
sigs.k8s.io/controller-runtime v0.16.2/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU=
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/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0=
-sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY=
-sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U=
-sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag=
+sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g=
+sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0=
+sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ=
+sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go
index 0075300c7d3..7913d26904c 100644
--- a/integration-tests/load/vrfv2/vrfv2_test.go
+++ b/integration-tests/load/vrfv2/vrfv2_test.go
@@ -82,6 +82,8 @@ func TestVRFV2Performance(t *testing.T) {
Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.")
} else {
if *vrfv2Config.General.CancelSubsAfterTestRun {
+ // wait for all txs to be mined in order to avoid nonce issues
+ time.Sleep(10 * time.Second)
//cancel subs and return funds to sub owner
vrfv2.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l)
}
diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go
index e8e1d7779c1..a1e5deabcbd 100644
--- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go
+++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go
@@ -81,6 +81,8 @@ func TestVRFV2PlusPerformance(t *testing.T) {
Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.")
} else {
if *testConfig.VRFv2Plus.General.CancelSubsAfterTestRun {
+ // wait for all txs to be mined in order to avoid nonce issues
+ time.Sleep(10 * time.Second)
//cancel subs and return funds to sub owner
vrfv2plus.CancelSubsAndReturnFunds(testcontext.Get(t), vrfContracts, sethClient.MustGetRootKeyAddress().Hex(), subIDsForCancellingAfterTest, l)
}
diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go
index 1b9cf5819b9..808e394d69b 100644
--- a/integration-tests/reorg/automation_reorg_test.go
+++ b/integration-tests/reorg/automation_reorg_test.go
@@ -43,7 +43,7 @@ var (
)
var logScannerSettings = test_env.GetDefaultChainlinkNodeLogScannerSettingsWithExtraAllowedMessages(testreporters.NewAllowedLogMessage(
- "Got very old block with number",
+ "Got very old block.",
"It is expected, because we are causing reorgs",
zapcore.DPanicLevel,
testreporters.WarnAboutAllowedMsgs_No,
diff --git a/integration-tests/smoke/README.md b/integration-tests/smoke/README.md
index 266720c7bc6..c4aa2b91a14 100644
--- a/integration-tests/smoke/README.md
+++ b/integration-tests/smoke/README.md
@@ -75,9 +75,3 @@ Then execute:
go test -v -run ${TestName}
```
-
-
-### Debugging CL client API calls
-```bash
-export CL_CLIENT_DEBUG=true
-```
\ No newline at end of file
diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go
index 92b25dfd522..39a9f754920 100644
--- a/integration-tests/smoke/automation_test.go
+++ b/integration-tests/smoke/automation_test.go
@@ -12,7 +12,7 @@ import (
"testing"
"time"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -1427,7 +1427,7 @@ func setupAutomationTestDocker(
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(automationTestConfig, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, automationTestConfig, evmNetwork)
require.NoError(t, err, "Error getting seth client")
err = actions.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs()), big.NewFloat(*automationTestConfig.GetCommonConfig().ChainlinkNodeFunding))
diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go
index d8773690b23..d66cdbd2849 100644
--- a/integration-tests/smoke/flux_test.go
+++ b/integration-tests/smoke/flux_test.go
@@ -8,12 +8,13 @@ import (
"testing"
"time"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
+
"github.com/ethereum/go-ethereum/common"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
"github.com/smartcontractkit/chainlink-testing-framework/logging"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
"github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext"
"github.com/smartcontractkit/chainlink/integration-tests/actions"
@@ -49,7 +50,7 @@ func TestFluxBasic(t *testing.T) {
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(config, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, config, evmNetwork)
require.NoError(t, err, "Error getting seth client")
adapterUUID := uuid.NewString()
diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go
index a249775dc6a..1eff96cb7a2 100644
--- a/integration-tests/smoke/forwarder_ocr_test.go
+++ b/integration-tests/smoke/forwarder_ocr_test.go
@@ -6,7 +6,7 @@ import (
"testing"
"time"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
@@ -49,7 +49,7 @@ func TestForwarderOCRBasic(t *testing.T) {
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(config, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, config, evmNetwork)
require.NoError(t, err, "Error getting seth client")
err = actions.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs()), big.NewFloat(*config.Common.ChainlinkNodeFunding))
diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go
index 863b36e4ede..e3cced94fd7 100644
--- a/integration-tests/smoke/forwarders_ocr2_test.go
+++ b/integration-tests/smoke/forwarders_ocr2_test.go
@@ -7,7 +7,7 @@ import (
"testing"
"time"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
@@ -50,7 +50,7 @@ func TestForwarderOCR2Basic(t *testing.T) {
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(config, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, config, evmNetwork)
require.NoError(t, err, "Error getting seth client")
err = actions.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs()), big.NewFloat(*config.Common.ChainlinkNodeFunding))
diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go
index 4ff1c90bd1e..b6118025a19 100644
--- a/integration-tests/smoke/keeper_test.go
+++ b/integration-tests/smoke/keeper_test.go
@@ -8,7 +8,7 @@ import (
"testing"
"time"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/onsi/gomega"
@@ -1243,7 +1243,7 @@ func setupKeeperTest(l zerolog.Logger, t *testing.T, config *tc.TestConfig) (
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(config, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, config, evmNetwork)
require.NoError(t, err, "Error getting seth client")
err = actions.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs()), big.NewFloat(*config.Common.ChainlinkNodeFunding))
diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go
index 56a95c50bda..90afff94cf3 100644
--- a/integration-tests/smoke/ocr2_test.go
+++ b/integration-tests/smoke/ocr2_test.go
@@ -8,7 +8,7 @@ import (
"testing"
"time"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/rs/zerolog"
@@ -163,7 +163,7 @@ func prepareORCv2SmokeTestEnv(t *testing.T, testData ocr2test, l zerolog.Logger,
evmNetwork, err := testEnv.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(config, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, config, evmNetwork)
require.NoError(t, err, "Error getting seth client")
nodeClients := testEnv.ClCluster.NodeAPIs()
diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go
index 0b4ac3de30b..8d17a020714 100644
--- a/integration-tests/smoke/ocr_test.go
+++ b/integration-tests/smoke/ocr_test.go
@@ -5,8 +5,6 @@ import (
"testing"
"time"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
-
"github.com/ethereum/go-ethereum/common"
"github.com/rs/zerolog"
"github.com/smartcontractkit/seth"
@@ -19,6 +17,7 @@ import (
"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/utils"
)
const (
@@ -99,7 +98,7 @@ func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(config, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, config, evmNetwork)
require.NoError(t, err, "Error getting seth client")
nodeClients := env.ClCluster.NodeAPIs()
diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go
index 515d9dea33c..1558b447327 100644
--- a/integration-tests/smoke/runlog_test.go
+++ b/integration-tests/smoke/runlog_test.go
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
"github.com/google/uuid"
"github.com/onsi/gomega"
@@ -47,7 +47,7 @@ func TestRunLogBasic(t *testing.T) {
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(config, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, config, evmNetwork)
require.NoError(t, err, "Error getting seth client")
err = actions.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs()), big.NewFloat(*config.Common.ChainlinkNodeFunding))
diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go
index 04e760796db..53e74ac7ff1 100644
--- a/integration-tests/smoke/vrf_test.go
+++ b/integration-tests/smoke/vrf_test.go
@@ -6,6 +6,8 @@ import (
"testing"
"time"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
+
"github.com/google/uuid"
"github.com/onsi/gomega"
"github.com/rs/zerolog"
@@ -13,7 +15,6 @@ import (
"github.com/stretchr/testify/require"
"github.com/smartcontractkit/chainlink-testing-framework/logging"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
"github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext"
"github.com/smartcontractkit/chainlink/integration-tests/actions"
@@ -204,7 +205,7 @@ func prepareVRFtestEnv(t *testing.T, l zerolog.Logger) (*test_env.CLClusterTestE
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- sethClient, err := seth_utils.GetChainClient(config, *evmNetwork)
+ sethClient, err := utils.TestAwareSethClient(t, config, evmNetwork)
require.NoError(t, err, "Error getting seth client")
err = actions.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs()), big.NewFloat(*config.Common.ChainlinkNodeFunding))
diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go
index 7a53d2c57c8..48fbc0071c5 100644
--- a/integration-tests/smoke/vrfv2_test.go
+++ b/integration-tests/smoke/vrfv2_test.go
@@ -1063,7 +1063,7 @@ func TestVRFV2NodeReorg(t *testing.T) {
chainlinkNodeLogScannerSettings := test_env.GetDefaultChainlinkNodeLogScannerSettingsWithExtraAllowedMessages(
testreporters.NewAllowedLogMessage(
- "This is a problem and either means a very deep re-org occurred",
+ "Got very old block.",
"Test is expecting a reorg to occur",
zapcore.DPanicLevel,
testreporters.WarnAboutAllowedMsgs_No),
diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go
index f519aa6cd5f..a1ac5fd5544 100644
--- a/integration-tests/smoke/vrfv2plus_test.go
+++ b/integration-tests/smoke/vrfv2plus_test.go
@@ -289,16 +289,14 @@ func TestVRFv2Plus(t *testing.T) {
t.Run("Direct Funding", func(t *testing.T) {
configCopy := config.MustCopy().(tc.TestConfig)
- wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment(
+ wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperUniverse(
testcontext.Get(t),
- l,
sethClient,
+ vrfContracts,
&configCopy,
- vrfContracts.LinkToken,
- vrfContracts.MockETHLINKFeed,
- vrfContracts.CoordinatorV2Plus,
vrfKey.KeyHash,
1,
+ l,
)
require.NoError(t, err)
@@ -307,7 +305,7 @@ func TestVRFv2Plus(t *testing.T) {
testConfig := configCopy.VRFv2Plus.General
var isNativeBilling = false
- wrapperConsumerJuelsBalanceBeforeRequest, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address())
+ wrapperConsumerJuelsBalanceBeforeRequest, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), wrapperContracts.WrapperConsumers[0].Address())
require.NoError(t, err, "error getting wrapper consumer balance")
wrapperSubscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID)
@@ -315,7 +313,7 @@ func TestVRFv2Plus(t *testing.T) {
subBalanceBeforeRequest := wrapperSubscription.Balance
randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment(
- wrapperContracts.LoadTestConsumers[0],
+ wrapperContracts.WrapperConsumers[0],
vrfContracts.CoordinatorV2Plus,
vrfKey,
wrapperSubID,
@@ -331,13 +329,13 @@ func TestVRFv2Plus(t *testing.T) {
subBalanceAfterRequest := wrapperSubscription.Balance
require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest)
- consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId)
+ consumerStatus, err := wrapperContracts.WrapperConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId)
require.NoError(t, err, "error getting rand request status")
require.True(t, consumerStatus.Fulfilled)
expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid)
- wrapperConsumerJuelsBalanceAfterRequest, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address())
+ wrapperConsumerJuelsBalanceAfterRequest, err := vrfContracts.LinkToken.BalanceOf(testcontext.Get(t), wrapperContracts.WrapperConsumers[0].Address())
require.NoError(t, err, "error getting wrapper consumer balance")
require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest)
@@ -356,7 +354,7 @@ func TestVRFv2Plus(t *testing.T) {
testConfig := configCopy.VRFv2Plus.General
var isNativeBilling = true
- wrapperConsumerBalanceBeforeRequestWei, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address()), nil)
+ wrapperConsumerBalanceBeforeRequestWei, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.WrapperConsumers[0].Address()), nil)
require.NoError(t, err, "error getting wrapper consumer balance")
wrapperSubscription, err := vrfContracts.CoordinatorV2Plus.GetSubscription(testcontext.Get(t), wrapperSubID)
@@ -364,7 +362,7 @@ func TestVRFv2Plus(t *testing.T) {
subBalanceBeforeRequest := wrapperSubscription.NativeBalance
randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment(
- wrapperContracts.LoadTestConsumers[0],
+ wrapperContracts.WrapperConsumers[0],
vrfContracts.CoordinatorV2Plus,
vrfKey,
wrapperSubID,
@@ -380,13 +378,13 @@ func TestVRFv2Plus(t *testing.T) {
subBalanceAfterRequest := wrapperSubscription.NativeBalance
require.Equal(t, expectedSubBalanceWei, subBalanceAfterRequest)
- consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId)
+ consumerStatus, err := wrapperContracts.WrapperConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId)
require.NoError(t, err, "error getting rand request status")
require.True(t, consumerStatus.Fulfilled)
expectedWrapperConsumerWeiBalance := new(big.Int).Sub(wrapperConsumerBalanceBeforeRequestWei, consumerStatus.Paid)
- wrapperConsumerBalanceAfterRequestWei, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address()), nil)
+ wrapperConsumerBalanceAfterRequestWei, err := sethClient.Client.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.WrapperConsumers[0].Address()), nil)
require.NoError(t, err, "error getting wrapper consumer balance")
require.Equal(t, expectedWrapperConsumerWeiBalance, wrapperConsumerBalanceAfterRequestWei)
@@ -1063,16 +1061,14 @@ func TestVRFv2PlusMigration(t *testing.T) {
t.Run("Test migration of direct billing using VRFV2PlusWrapper subID", func(t *testing.T) {
configCopy := config.MustCopy().(tc.TestConfig)
- wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment(
+ wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperUniverse(
testcontext.Get(t),
- l,
sethClient,
+ vrfContracts,
&configCopy,
- vrfContracts.LinkToken,
- vrfContracts.MockETHLINKFeed,
- vrfContracts.CoordinatorV2Plus,
vrfKey.KeyHash,
1,
+ l,
)
require.NoError(t, err)
subID := wrapperSubID
@@ -1203,7 +1199,7 @@ func TestVRFv2PlusMigration(t *testing.T) {
// Verify rand requests fulfills with Link Token billing
isNativeBilling := false
randomWordsFulfilledEvent, err := vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment(
- wrapperContracts.LoadTestConsumers[0],
+ wrapperContracts.WrapperConsumers[0],
newCoordinator,
vrfKey,
subID,
@@ -1212,14 +1208,14 @@ func TestVRFv2PlusMigration(t *testing.T) {
l,
)
require.NoError(t, err, "error requesting randomness and waiting for fulfilment")
- consumerStatus, err := wrapperContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId)
+ consumerStatus, err := wrapperContracts.WrapperConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId)
require.NoError(t, err, "error getting rand request status")
require.True(t, consumerStatus.Fulfilled)
// Verify rand requests fulfills with Native Token billing
isNativeBilling = true
randomWordsFulfilledEvent, err = vrfv2plus.DirectFundingRequestRandomnessAndWaitForFulfillment(
- wrapperContracts.LoadTestConsumers[0],
+ wrapperContracts.WrapperConsumers[0],
newCoordinator,
vrfKey,
subID,
@@ -1228,7 +1224,7 @@ func TestVRFv2PlusMigration(t *testing.T) {
l,
)
require.NoError(t, err, "error requesting randomness and waiting for fulfilment")
- consumerStatus, err = wrapperContracts.LoadTestConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId)
+ consumerStatus, err = wrapperContracts.WrapperConsumers[0].GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId)
require.NoError(t, err, "error getting rand request status")
require.True(t, consumerStatus.Fulfilled)
})
@@ -1347,11 +1343,10 @@ func TestVRFV2PlusWithBHS(t *testing.T) {
}()
if *configCopy.VRFv2Plus.General.GenerateTXsOnChain {
+ wg.Add(1)
go func() {
- _, err := actions.ContinuouslyGenerateTXsOnChain(sethClient, desiredBlockNumberReached, l)
+ _, err := actions.ContinuouslyGenerateTXsOnChain(sethClient, desiredBlockNumberReached, &wg, l)
require.NoError(t, err)
- // Wait to let the transactions be mined and avoid nonce issues
- time.Sleep(time.Second * 5)
}()
}
wg.Wait()
@@ -1959,7 +1954,7 @@ func TestVRFv2PlusNodeReorg(t *testing.T) {
}
chainlinkNodeLogScannerSettings := test_env.GetDefaultChainlinkNodeLogScannerSettingsWithExtraAllowedMessages(
testreporters.NewAllowedLogMessage(
- "This is a problem and either means a very deep re-org occurred",
+ "Got very old block.",
"Test is expecting a reorg to occur",
zapcore.DPanicLevel,
testreporters.WarnAboutAllowedMsgs_No),
diff --git a/integration-tests/soak/forwarder_ocr_test.go b/integration-tests/soak/forwarder_ocr_test.go
index dd7eb102170..9b129783665 100644
--- a/integration-tests/soak/forwarder_ocr_test.go
+++ b/integration-tests/soak/forwarder_ocr_test.go
@@ -42,6 +42,11 @@ func executeForwarderOCRSoakTest(t *testing.T, config *tc.TestConfig) {
t.Cleanup(func() {
if err := actions.TeardownRemoteSuite(ocrSoakTest.TearDownVals(t)); err != nil {
l.Error().Err(err).Msg("Error tearing down environment")
+ } else {
+ err := ocrSoakTest.Environment().Client.RemoveNamespace(ocrSoakTest.Environment().Cfg.Namespace)
+ if err != nil {
+ l.Error().Err(err).Msg("Error removing namespace")
+ }
}
})
ocrSoakTest.Setup(config)
diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go
index 1f437e565eb..998af1da73c 100644
--- a/integration-tests/soak/ocr_test.go
+++ b/integration-tests/soak/ocr_test.go
@@ -14,9 +14,10 @@ import (
"github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
"github.com/google/uuid"
- "github.com/smartcontractkit/havoc/k8schaos"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "github.com/smartcontractkit/chainlink-testing-framework/havoc"
+
"github.com/smartcontractkit/chainlink-testing-framework/networks"
"github.com/smartcontractkit/chainlink-testing-framework/utils/ptr"
"github.com/smartcontractkit/chainlink/integration-tests/actions"
@@ -100,7 +101,7 @@ func TestOCRSoak_RPCDownForAllCLNodes(t *testing.T) {
require.NoError(t, err, "Error creating chaos")
ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config,
testsetups.WithNamespace(namespace),
- testsetups.WithChaos([]*k8schaos.Chaos{chaos}),
+ testsetups.WithChaos([]*havoc.Chaos{chaos}),
)
require.NoError(t, err, "Error creating OCR soak test")
executeOCRSoakTest(t, ocrSoakTest, &config)
@@ -133,7 +134,7 @@ func TestOCRSoak_RPCDownForHalfCLNodes(t *testing.T) {
require.NoError(t, err, "Error creating chaos")
ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config,
testsetups.WithNamespace(namespace),
- testsetups.WithChaos([]*k8schaos.Chaos{chaos}),
+ testsetups.WithChaos([]*havoc.Chaos{chaos}),
)
require.NoError(t, err, "Error creating OCR soak test")
executeOCRSoakTest(t, ocrSoakTest, &config)
@@ -160,6 +161,11 @@ func executeOCRSoakTest(t *testing.T, test *testsetups.OCRSoakTest, config *tc.T
t.Cleanup(func() {
if err := actions.TeardownRemoteSuite(test.TearDownVals(t)); err != nil {
l.Error().Err(err).Msg("Error tearing down environment")
+ } else {
+ err := test.Environment().Client.RemoveNamespace(test.Environment().Cfg.Namespace)
+ if err != nil {
+ l.Error().Err(err).Msg("Error removing namespace")
+ }
}
})
if test.Interrupted() {
@@ -181,12 +187,12 @@ type GethNetworkDownChaosOpts struct {
Duration time.Duration
}
-func gethNetworkDownChaos(opts GethNetworkDownChaosOpts) (*k8schaos.Chaos, error) {
- k8sClient, err := k8schaos.NewChaosMeshClient()
+func gethNetworkDownChaos(opts GethNetworkDownChaosOpts) (*havoc.Chaos, error) {
+ k8sClient, err := havoc.NewChaosMeshClient()
if err != nil {
return nil, err
}
- return k8schaos.NewChaos(k8schaos.ChaosOpts{
+ return havoc.NewChaos(havoc.ChaosOpts{
Description: opts.Description,
DelayCreate: opts.DelayCreate,
Object: &v1alpha1.NetworkChaos{
@@ -220,7 +226,7 @@ func gethNetworkDownChaos(opts GethNetworkDownChaosOpts) (*k8schaos.Chaos, error
},
},
Client: k8sClient,
- Logger: &k8schaos.Logger,
+ Logger: &havoc.Logger,
})
}
diff --git a/integration-tests/test.Dockerfile b/integration-tests/test.Dockerfile
index fc6eefd650c..2e928ab29f8 100644
--- a/integration-tests/test.Dockerfile
+++ b/integration-tests/test.Dockerfile
@@ -1,10 +1,18 @@
ARG BASE_IMAGE
ARG IMAGE_VERSION=latest
-FROM ${BASE_IMAGE}:${IMAGE_VERSION}
+FROM ${BASE_IMAGE}:${IMAGE_VERSION} AS build-env
ARG SUITES=chaos migration performance reorg smoke soak benchmark
COPY . testdir/
WORKDIR /go/testdir
RUN /go/testdir/integration-tests/scripts/buildTests "${SUITES}"
+
+FROM ${BASE_IMAGE}:${IMAGE_VERSION}
+
+RUN mkdir -p /go/testdir/integration-tests/scripts
+COPY --from=build-env /go/pkg /go/pkg
+COPY --from=build-env /go/testdir/integration-tests/*.test /go/testdir/integration-tests/
+COPY --from=build-env /go/testdir/integration-tests/scripts /go/testdir/integration-tests/scripts/
+
ENTRYPOINT ["/go/testdir/integration-tests/scripts/entrypoint"]
diff --git a/integration-tests/testconfig/README.md b/integration-tests/testconfig/README.md
index 7ff6cedd24c..878b36bc756 100644
--- a/integration-tests/testconfig/README.md
+++ b/integration-tests/testconfig/README.md
@@ -137,7 +137,9 @@ DefaultTransactionQueueDepth = 0
"""
```
Note that you cannot override individual values in BaseConfigTOML. You must provide the entire configuration.
+This corresponds to [Config struct](../../core/services/chainlink/config.go) in Chainlink Node that excludes all chain-specific configuration, which is built based on selected_networks and either Chainlink Node's defaults for each network, or `ChainConfigTOMLByChainID` (if an entry with matching chain id is defined) or `CommonChainConfigTOML` (if no entry with matching chain id is defined).
+If BaseConfigTOML is empty, then default base config provided by the Chainlink Node is used. If tracing is enabled unique id will be generated and shared between all Chainlink nodes in the same test.
To set base config for EVM chains use `NodeConfig.CommonChainConfigTOML`. Example:
```toml
@@ -153,12 +155,12 @@ FeeCapDefault = '200 gwei'
"""
```
-This is the default configuration used for all EVM chains unless ChainConfigTOMLByChainID is specified.
+This is the default configuration used for all EVM chains unless `ChainConfigTOMLByChainID` is specified. Do remember that if either `ChainConfigTOMLByChainID` or `CommonChainConfigTOML` is defined, it will override any defaults that Chainlink Node might have for the given network. Part of the configuration that defines blockchain node URLs is always dynamically generated based on the EVMNetwork configuration.
To set custom per-chain config use `[NodeConfig.ChainConfigTOMLByChainID]`. Example:
```toml
[NodeConfig.ChainConfigTOMLByChainID]
-# applicable for arbitrum-goerli chain
+# applicable only to arbitrum-goerli chain
421613 = """
[GasEstimator]
PriceMax = '400 gwei'
@@ -170,7 +172,8 @@ BumpMin = '100 gwei'
"""
```
-For more examples see `example.toml` in product TOML configs like `testconfig/automation/example.toml`.
+For more examples see `example.toml` in product TOML configs like `testconfig/automation/example.toml`. If either ChainConfigTOMLByChainID or CommonChainConfigTOML is defined, it will override any defaults that Chainlink Node might have for the given network. Part of the configuration that defines blockchain node URLs is always dynamically generated based on the EVMNetwork configuration.
+Currently, all networks are treated as EVM networks. There's no way to provide Solana, Starknet, Cosmos or Aptos configuration yet.
### Setting env vars for Chainlink Node
diff --git a/integration-tests/testconfig/common/vrf/common.go b/integration-tests/testconfig/common/vrf/common.go
index e213191075f..326f7c98c76 100644
--- a/integration-tests/testconfig/common/vrf/common.go
+++ b/integration-tests/testconfig/common/vrf/common.go
@@ -71,10 +71,13 @@ func (c *PerformanceConfig) Validate() error {
type ExistingEnvConfig struct {
CoordinatorAddress *string `toml:"coordinator_address"`
+ UseExistingWrapper *bool `toml:"use_existing_wrapper"`
+ WrapperAddress *string `toml:"wrapper_address"`
ConsumerAddress *string `toml:"consumer_address"`
- LinkAddress *string `toml:"link_address"`
+ WrapperConsumerAddress *string `toml:"wrapper_consumer_address"`
KeyHash *string `toml:"key_hash"`
CreateFundSubsAndAddConsumers *bool `toml:"create_fund_subs_and_add_consumers"`
+ CreateFundAddWrapperConsumers *bool `toml:"create_fund_add_wrapper_consumers"`
NodeSendingKeys []string `toml:"node_sending_keys"`
Funding
}
@@ -83,23 +86,33 @@ func (c *ExistingEnvConfig) Validate() error {
if c.CreateFundSubsAndAddConsumers == nil {
return errors.New("create_fund_subs_and_add_consumers must be set ")
}
+ if c.CreateFundAddWrapperConsumers == nil {
+ return errors.New("create_fund_add_wrapper_consumers must be set ")
+ }
if c.CoordinatorAddress == nil {
return errors.New("coordinator_address must be set when using existing environment")
}
if !common.IsHexAddress(*c.CoordinatorAddress) {
return errors.New("coordinator_address must be a valid hex address")
}
+ if c.UseExistingWrapper == nil {
+ return errors.New("use_existing_wrapper must be set ")
+ }
+ if *c.UseExistingWrapper {
+ if c.WrapperAddress == nil {
+ return errors.New("wrapper_address must be set when using `use_existing_wrapper=true`")
+ }
+ if !common.IsHexAddress(*c.WrapperAddress) {
+ return errors.New("wrapper_address must be a valid hex address")
+ }
+ }
if c.KeyHash == nil {
return errors.New("key_hash must be set when using existing environment")
}
if *c.KeyHash == "" {
return errors.New("key_hash must be a non-empty string")
}
- if *c.CreateFundSubsAndAddConsumers {
- if err := c.Funding.Validate(); err != nil {
- return err
- }
- } else {
+ if !*c.CreateFundSubsAndAddConsumers {
if c.ConsumerAddress == nil || *c.ConsumerAddress == "" {
return errors.New("consumer_address must be set when using existing environment")
}
@@ -107,7 +120,14 @@ func (c *ExistingEnvConfig) Validate() error {
return errors.New("consumer_address must be a valid hex address")
}
}
-
+ if !*c.CreateFundAddWrapperConsumers {
+ if c.WrapperConsumerAddress == nil || *c.WrapperConsumerAddress == "" {
+ return errors.New("wrapper_consumer_address must be set when using existing environment")
+ }
+ if !common.IsHexAddress(*c.WrapperConsumerAddress) {
+ return errors.New("wrapper_consumer_address must be a valid hex address")
+ }
+ }
if c.NodeSendingKeys != nil {
for _, key := range c.NodeSendingKeys {
if !common.IsHexAddress(key) {
@@ -115,7 +135,6 @@ func (c *ExistingEnvConfig) Validate() error {
}
}
}
-
return nil
}
@@ -127,7 +146,6 @@ func (c *Funding) Validate() error {
if c.NodeSendingKeyFundingMin != nil && *c.NodeSendingKeyFundingMin <= 0 {
return errors.New("when set node_sending_key_funding_min must be a positive value")
}
-
return nil
}
diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml
index d317d05bc49..2bb73f42ad9 100644
--- a/integration-tests/testconfig/default.toml
+++ b/integration-tests/testconfig/default.toml
@@ -1,37 +1,72 @@
[Logging]
+# set to true to flush logs to selected target regardless of test result; otherwise logs are only flushed if test failed
test_log_collect = false
[Logging.LogStream]
+# supported targets: file, loki, in-memory. if empty no logs will be persisted
log_targets = ["file"]
+# context timeout for starting log producer and also time-frame for requesting logs
log_producer_timeout = "10s"
+# number of retries before log producer gives up and stops listening to logs
log_producer_retry_limit = 10
[ChainlinkImage]
+# postgres version to use
postgres_version = "15.6"
+# chainlink image to use
image = "public.ecr.aws/chainlink/chainlink"
+# chainlink image tag to use
version = "2.12.0"
[Common]
+# chainlink node funding in native token
chainlink_node_funding = 0.5
[Network]
+# slice of networks to use; at lesat one network must be selected; each selected network must either be already defined in the CTF as a known network, or be defined in
+# TOML test files as a new network
selected_networks = ["simulated"]
[PrivateEthereumNetwork]
+# ethereum version to use; eth1 or eth2 (post-merge)
ethereum_version = "eth1"
+# execution layer to use; geth, besu, nethermind, erigon or reth
execution_layer = "geth"
[PrivateEthereumNetwork.EthereumChainConfig]
+# duration of single slot, lower => faster block production, must be >= 3
seconds_per_slot = 3
+# number of slots in epoch, lower => faster epoch finalisation, must be >= 2
slots_per_epoch = 2
+# extra genesis delay, no need to modify, but it should be after all validators/beacon chain starts
genesis_delay = 15
+# number of validators in the network
validator_count = 4
+# chain id to use
chain_id = 1337
+# slice of addresses that will be funded with native token in genesis
addresses_to_fund = ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"]
+# map of hard fork epochs for each network; key is fork name, value is hard fork epoch
+# keep in mind that this depends on the specific version of eth2 client you are using
+# this configuration is fault-tolerant and incorrect forks will be ignored
[PrivateEthereumNetwork.EthereumChainConfig.HardForkEpochs]
Deneb = 500
+# General config of the Chainklink node corresponding to core/services/chainlink/config.go (Config struct) that excludes
+# all chain-specific configuration, which is built based on selected_networks and either Chainlink Node's defaults for
+# each network, or ChainConfigTOMLByChainID (if an entry with matching chain id is defined) or CommonChainConfigTOML (if no
+# entry with matching chain id is defined).
+#
+# Please remember that if either ChainConfigTOMLByChainID or CommonChainConfigTOML is defined, it will override any defaults
+# that Chainlink Node might have for the given network. Part of the configuration that defines blockchain node URLs is always
+# dynamically generated based on the EVMNetwork configuration.
+#
+# Last, but not least, currently all selected networks are treated as EVM networks. There's no way to provide Solana, Starknet,
+# Cosmos or Aptos configuration yet.
+#
+# If BaseConfigTOML is empty, then default base config provided by the Chainlink Node is used.
+# Also, if tracing is enabled unique id will be generated and shared between all Chainlink nodes in the same test.
[NodeConfig]
BaseConfigTOML = """
[Feature]
@@ -78,12 +113,14 @@ DeltaDial = '500ms'
DeltaReconcile = '5s'
"""
-# override config toml related to EVMNode configs for chainlink nodes; applicable to all EVM node configs in chainlink toml
+# Overrides default config TOML related to EVMNode configs for chainlink nodes; applicable to all EVM node configs in chainlink TOML.
+# Do not use it, if you want the default values to be used. Passing blockchain nodes URLs here will have no effect.
CommonChainConfigTOML = """
"""
[NodeConfig.ChainConfigTOMLByChainID]
-# applicable for simulated chain
+# Chain-specific EVMNode config TOML for chainlink nodes; applicable to all EVM node configs in chainlink TOML. It takes precedence
+# over CommonChainConfigTOML and Chainlink Node's defaults. Passing blockchain nodes URLs here will have no effect.
1337 = """
AutoCreateKey = true
FinalityDepth = 1
@@ -97,13 +134,13 @@ FeeCapDefault = '200 gwei'
[Seth]
# controls which transactions are decoded/traced. Possbile values are: none, all, reverted (default).
# if transaction level doesn't match, then calling Decode() does nothing. It's advised to keep it set
-# to 'reverted' to limit noise. If you combine it with 'trace_to_json' it will save all possible data
-# in JSON files for reverted transactions.
+# to 'reverted' to limit noise.
tracing_level = "reverted"
-# saves each decoding/tracing results to JSON files; what exactly is saved depends on what we
+# saves each decoding/tracing results to DOT files; what exactly is saved depends on what we
# were able te decode, we try to save maximum information possible. It can either be:
# just tx hash, decoded transaction or call trace. Which transactions traces are saved depends
# on 'tracing_level'.
+trace_outputs = ["dot", "console"]
# number of addresses to be generated and runtime, if set to 0, no addresses will be generated
# each generated address will receive a proportion of native tokens from root private key's balance
@@ -286,11 +323,11 @@ eip_1559_dynamic_fees = true
# automated gas estimation for live networks
# if set to true we will dynamically estimate gas for every transaction (based on suggested values, priority and congestion rate for last X blocks)
-# gas_price_estimation_enabled = true
+ gas_price_estimation_enabled = true
# number of blocks to use for congestion rate estimation (it will determine buffer added on top of suggested values)
-# gas_price_estimation_blocks = 100
+ gas_price_estimation_blocks = 100
# transaction priority, which determines adjustment factor multiplier applied to suggested values (fast - 1.2x, standard - 1x, slow - 0.8x)
-# gas_price_estimation_tx_priority = "standard"
+ gas_price_estimation_tx_priority = "standard"
# URLs
# if set they will overwrite URLs from EVMNetwork that Seth uses, can be either WS(S) or HTTP(S)
@@ -309,7 +346,7 @@ gas_price = 200_000_000_000
# EIP-1559 transactions
gas_fee_cap = 200_000_000_000
-gas_tip_cap = 2_000_000_000
+gas_tip_cap = 25_000_000_000
[[Seth.networks]]
name = "Polygon zkEVM Goerli"
@@ -413,3 +450,271 @@ gas_price_estimation_enabled = true
gas_price_estimation_blocks = 100
# priority of the transaction, can be "fast", "standard" or "slow" (the higher the priority, the higher adjustment factor will be used for gas estimation) [default: "standard"]
gas_price_estimation_tx_priority = "standard"
+
+
+[[Seth.networks]]
+name = "Nexon Mainnet"
+transaction_timeout = "3m"
+eip_1559_dynamic_fees = true
+transfer_gas_fee = 21_000
+
+# manual settings, used when gas_price_estimation_enabled is false or when it fails
+# legacy transactions
+gas_price = 30_000_000_000
+
+# EIP-1559 transactions
+gas_fee_cap = 30_000_000_000
+gas_tip_cap = 1_800_000_000
+
+
+[Network.EVMNetworks.NEXON_MAINNET]
+evm_name = "NEXON_MAINNET"
+#evm_urls = ["rpc ws endpoint"]
+#evm_http_urls = ["rpc http endpoint"]
+client_implementation = "Ethereum"
+#evm_keys = ["private keys you want to use"]
+evm_simulated = false
+evm_chainlink_transaction_limit = 5000
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 10000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_chain_id = 60118
+
+[[Seth.networks]]
+name = "Nexon Stage"
+transaction_timeout = "3m"
+eip_1559_dynamic_fees = true
+transfer_gas_fee = 21_000
+
+# manual settings, used when gas_price_estimation_enabled is false or when it fails
+# legacy transactions
+gas_price = 30_000_000_000
+
+# EIP-1559 transactions
+gas_fee_cap = 30_000_000_000
+gas_tip_cap = 1_800_000_000
+
+
+[Network.EVMNetworks.NEXON_STAGE]
+evm_name = "NEXON_STAGE"
+#evm_urls = ["rpc ws endpoint"]
+#evm_http_urls = ["rpc http endpoint"]
+client_implementation = "Ethereum"
+#evm_keys = ["private keys you want to use"]
+evm_simulated = false
+evm_chainlink_transaction_limit = 5000
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 10000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_chain_id = 847799
+
+
+####
+
+[[Seth.networks]]
+name = "Nexon QA"
+transaction_timeout = "3m"
+eip_1559_dynamic_fees = true
+transfer_gas_fee = 21_000
+
+# manual settings, used when gas_price_estimation_enabled is false or when it fails
+# legacy transactions
+gas_price = 30_000_000_000
+
+# EIP-1559 transactions
+gas_fee_cap = 30_000_000_000
+gas_tip_cap = 1_800_000_000
+
+
+[Network.EVMNetworks.NEXON_QA]
+evm_name = "NEXON_QA"
+#evm_urls = ["rpc ws endpoint"]
+#evm_http_urls = ["rpc http endpoint"]
+client_implementation = "Ethereum"
+#evm_keys = ["private keys you want to use"]
+evm_simulated = false
+evm_chainlink_transaction_limit = 5000
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 10000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_chain_id = 807424
+
+#####
+
+[[Seth.networks]]
+name = "Nexon Test"
+transaction_timeout = "3m"
+eip_1559_dynamic_fees = true
+transfer_gas_fee = 21_000
+
+# manual settings, used when gas_price_estimation_enabled is false or when it fails
+# legacy transactions
+gas_price = 30_000_000_000
+
+# EIP-1559 transactions
+gas_fee_cap = 30_000_000_000
+gas_tip_cap = 1_800_000_000
+
+
+[Network.EVMNetworks.NEXON_TEST]
+evm_name = "NEXON_TEST"
+#evm_urls = ["rpc ws endpoint"]
+#evm_http_urls = ["rpc http endpoint"]
+client_implementation = "Ethereum"
+#evm_keys = ["private keys you want to use"]
+evm_simulated = false
+evm_chainlink_transaction_limit = 5000
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 10000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_chain_id = 595581
+
+#####
+[[Seth.networks]]
+name = "Nexon Dev"
+transaction_timeout = "3m"
+eip_1559_dynamic_fees = true
+transfer_gas_fee = 21_000
+
+# manual settings, used when gas_price_estimation_enabled is false or when it fails
+# legacy transactions
+gas_price = 30_000_000_000
+
+# EIP-1559 transactions
+gas_fee_cap = 30_000_000_000
+gas_tip_cap = 1_800_000_000
+
+
+[Network.EVMNetworks.NEXON_DEV]
+evm_name = "NEXON_DEV"
+#evm_urls = ["rpc ws endpoint"]
+#evm_http_urls = ["rpc http endpoint"]
+client_implementation = "Ethereum"
+#evm_keys = ["private keys you want to use"]
+evm_simulated = false
+evm_chainlink_transaction_limit = 5000
+evm_minimum_confirmations = 1
+evm_gas_estimation_buffer = 10000
+evm_supports_eip1559 = true
+evm_default_gas_limit = 6000000
+evm_chain_id = 5668
+
+[[Seth.networks]]
+name = "LINEA_SEPOLIA"
+chain_id = "59141"
+transaction_timeout = "10m"
+transfer_gas_fee = 21_000
+gas_price = 200_000_000_000_000
+eip_1559_dynamic_fees = false
+gas_fee_cap = 109_694_825_437
+gas_tip_cap = 30_000_000_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 1000
+gas_price_estimation_tx_priority = "standard"
+
+[[Seth.networks]]
+name = "LINEA_MAINNET"
+chain_id = "59144"
+transaction_timeout = "10m"
+transfer_gas_fee = 21_000
+gas_price = 200_000_000_000_000
+eip_1559_dynamic_fees = false
+gas_fee_cap = 109_694_825_437
+gas_tip_cap = 30_000_000_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 1000
+gas_price_estimation_tx_priority = "standard"
+
+[[Seth.networks]]
+name = "ZKSYNC_SEPOLIA"
+chain_id = "300"
+transaction_timeout = "3m"
+transfer_gas_fee = 21_000
+gas_price = 200_000_000_000
+eip_1559_dynamic_fees = true
+gas_fee_cap = 109_694_825_437
+gas_tip_cap = 30_000_000_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 1000
+gas_price_estimation_tx_priority = "standard"
+
+[[Seth.networks]]
+name = "ZKSYNC_MAINNET"
+chain_id = "324"
+transaction_timeout = "3m"
+transfer_gas_fee = 21_000
+gas_price = 200_000_000_000
+eip_1559_dynamic_fees = true
+gas_fee_cap = 109_694_825_437
+gas_tip_cap = 30_000_000_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 1000
+gas_price_estimation_tx_priority = "standard"
+
+[[Seth.networks]]
+name = "POLYGON_ZKEVM_CARDONA"
+transaction_timeout = "3m"
+transfer_gas_fee = 21_000
+gas_price = 743_000_000
+eip_1559_dynamic_fees = false
+gas_fee_cap = 1_725_800_000
+gas_tip_cap = 822_800_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 1000
+gas_price_estimation_tx_priority = "standard"
+
+[[Seth.networks]]
+name = "HEDERA_TESTNET"
+transaction_timeout = "3m"
+transfer_gas_fee = 800_000
+gas_limit = 2_000_000
+gas_price = 2_500_000_000_000
+eip_1559_dynamic_fees = false
+gas_fee_cap = 109_694_825_437
+gas_tip_cap = 30_000_000_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 1000
+gas_price_estimation_tx_priority = "standard"
+
+[[Seth.networks]]
+name = "TREASURE_RUBY"
+chain_id = "978657"
+transaction_timeout = "10m"
+transfer_gas_fee = 21_000
+gas_price = 100_000_000
+eip_1559_dynamic_fees = true
+gas_fee_cap = 200_000_000
+gas_tip_cap = 100_000_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 1000
+gas_price_estimation_tx_priority = "standard"
+
+[[Seth.networks]]
+name = "XLAYER_MAINNET"
+chain_id = "196"
+transaction_timeout = "10m"
+transfer_gas_fee = 21_000
+gas_price = 13_400_000_000
+eip_1559_dynamic_fees = false
+gas_fee_cap = 109_694_825_437
+gas_tip_cap = 30_000_000_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 500
+gas_price_estimation_tx_priority = "standard"
+
+[[Seth.networks]]
+name = "XLAYER_SEPOLIA"
+chain_id = "195"
+transaction_timeout = "10m"
+transfer_gas_fee = 21_000
+gas_price = 200_000_000_000
+eip_1559_dynamic_fees = false
+gas_fee_cap = 109_694_825_437
+gas_tip_cap = 30_000_000_000
+gas_price_estimation_enabled = true
+gas_price_estimation_blocks = 500
+gas_price_estimation_tx_priority = "standard"
diff --git a/integration-tests/testconfig/keeper/keeper.toml b/integration-tests/testconfig/keeper/keeper.toml
index b4a6a3b2c0e..39eae1ea53c 100644
--- a/integration-tests/testconfig/keeper/keeper.toml
+++ b/integration-tests/testconfig/keeper/keeper.toml
@@ -57,7 +57,21 @@ contract_call_interval = "4s"
[Seth]
# keeper benchmark running on simulated network requires 100k per node
-root_key_funds_buffer = 700_000
+root_key_funds_buffer = 1_000_000
+
+[Benchmark.Keeper.Common]
+registry_to_test = "2_1"
+number_of_registries = 1
+number_of_nodes = 6
+number_of_upkeeps = 1000
+upkeep_gas_limit = 1500000
+check_gas_to_burn = 10000
+perform_gas_to_burn = 1000
+max_perform_gas = 5000000
+block_range = 3600
+block_interval = 60
+forces_single_tx_key = false
+delete_jobs_on_end = true
[Benchmark.NodeConfig]
BaseConfigTOML = """
@@ -95,3 +109,54 @@ HistoryDepth = 100
Mode = 'FixedPrice'
LimitDefault = 5_000_000
"""
+
+[Soak.Keeper.Common]
+registry_to_test = "2_1"
+number_of_registries = 1
+number_of_nodes = 6
+number_of_upkeeps = 50
+upkeep_gas_limit = 1500000
+check_gas_to_burn = 10000
+perform_gas_to_burn = 1000
+max_perform_gas = 5000000
+block_range = 28800
+block_interval = 300
+forces_single_tx_key = false
+delete_jobs_on_end = true
+
+[Soak.NodeConfig]
+BaseConfigTOML = """
+[Feature]
+LogPoller = true
+
+[OCR2]
+Enabled = true
+
+[P2P]
+[P2P.V2]
+Enabled = true
+AnnounceAddresses = ["0.0.0.0:6690"]
+ListenAddresses = ["0.0.0.0:6690"]
+[Keeper]
+TurnLookBack = 0
+[WebServer]
+HTTPWriteTimeout = '1h'
+"""
+
+CommonChainConfigTOML = """
+"""
+
+[Soak.NodeConfig.ChainConfigTOMLByChainID]
+# applicable for simulated chain
+1337 = """
+FinalityDepth = 50
+LogPollInterval = '1s'
+MinIncomingConfirmations = 1
+
+[HeadTracker]
+HistoryDepth = 100
+
+[GasEstimator]
+Mode = 'FixedPrice'
+LimitDefault = 5_000_000
+"""
diff --git a/integration-tests/testconfig/vrfv2/config.go b/integration-tests/testconfig/vrfv2/config.go
index 76d54a45d5b..5e940403961 100644
--- a/integration-tests/testconfig/vrfv2/config.go
+++ b/integration-tests/testconfig/vrfv2/config.go
@@ -3,8 +3,6 @@ package testconfig
import (
"errors"
- "github.com/ethereum/go-ethereum/common"
-
vrf_common_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/common/vrf"
)
@@ -52,10 +50,6 @@ func (c *ExistingEnvConfig) Validate() error {
if *c.SubID == 0 {
return errors.New("sub_id must be positive value")
}
-
- if c.LinkAddress != nil && !common.IsHexAddress(*c.LinkAddress) {
- return errors.New("link_address must be a valid hex address")
- }
}
return c.Funding.Validate()
diff --git a/integration-tests/testconfig/vrfv2/vrfv2.toml b/integration-tests/testconfig/vrfv2/vrfv2.toml
index 011e90c15fd..de7200b1e79 100644
--- a/integration-tests/testconfig/vrfv2/vrfv2.toml
+++ b/integration-tests/testconfig/vrfv2/vrfv2.toml
@@ -113,11 +113,17 @@ bhf_job_run_timeout = "1h"
[VRFv2.ExistingEnv]
coordinator_address = ""
-consumer_address = ""
-sub_id = 1
key_hash = ""
+
+use_existing_wrapper = false
+wrapper_address = ""
create_fund_subs_and_add_consumers = true
-link_address = ""
+sub_id = 1
+consumer_address = ""
+
+create_fund_add_wrapper_consumers = true
+wrapper_consumer_address = ""
+
node_sending_key_funding_min = 10
node_sending_keys = [
"",
diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml
index 8f8aa9530e7..860c0c158bf 100644
--- a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml
+++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml
@@ -19,6 +19,7 @@ MaxSize = '0b'
[WebServer]
AllowOrigins = '*'
HTTPPort = 6688
+HTTPWriteTimeout = '1m0s'
SecureCookies = false
[WebServer.RateLimit]
@@ -57,7 +58,7 @@ BatchSize = 100
"""
[Common]
-chainlink_node_funding = 0.5
+chainlink_node_funding = 0.7
[VRFv2Plus]
[VRFv2Plus.General]
@@ -138,11 +139,17 @@ bhf_job_run_timeout = "1h"
[VRFv2Plus.ExistingEnv]
coordinator_address = ""
-consumer_address = ""
-sub_id = ""
key_hash = ""
+
+use_existing_wrapper = false
+wrapper_address = ""
create_fund_subs_and_add_consumers = true
-link_address = ""
+sub_id = ""
+consumer_address = ""
+
+create_fund_add_wrapper_consumers = true
+wrapper_consumer_address = ""
+
node_sending_key_funding_min = 1
node_sending_keys = []
@@ -272,7 +279,6 @@ key_hash = "0xd360445bacd26df47086ccf255c4f932d297ed8d5c7334b51eed32f61c541601"
#key_hash = "0x2328cbee29e32d0b6662d6df82ff0fea7be300bd310561c92f515c9ee19464f1"
#key_hash = "0x25f4e2d0509f42ec77db5380f3433a89fe623fa75f65d5b398d5f498327be4dd"
create_fund_subs_and_add_consumers = true
-link_address = "0x0Fd9e8d3aF1aaee056EB9e802c3A762a667b1904"
node_sending_key_funding_min = 10
node_sending_keys = [
"0xD96013C241f1741C35a135321969f92Aae02A12F",
@@ -407,7 +413,6 @@ consumer_address = ""
sub_id = ""
key_hash = "0xe13aa26fe94bfcd2ae055911f4d3bf1aed54ca6cf77af34e17f918802fd69ba1"
create_fund_subs_and_add_consumers = true
-link_address = "0xb1D4538B4571d411F07960EF2838Ce337FE1E80E"
node_sending_key_funding_min = 20
node_sending_keys = [
"0xbE21ae371FcA1aC2d8A152e707D21e68d7d99252",
@@ -551,7 +556,6 @@ consumer_address = ""
sub_id = ""
key_hash = "0x5b03254a80ea3eb72139ff0423cb88be42612780c3dd25f1d95a5ba7708a4be1"
create_fund_subs_and_add_consumers = true
-link_address = "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846"
node_sending_key_funding_min = 50
node_sending_keys = [
"0x3D7Da5D6A23CA2240CE576C8638C1798a023920a",
@@ -676,7 +680,6 @@ consumer_address = ""
sub_id = ""
key_hash = "0xf5b4a359df0598eef89872ea2170f2afa844dbf74b417e6d44d4bda9420aceb2"
create_fund_subs_and_add_consumers = true
-link_address = "0x779877A7B0D9E8603169DdbD7836e478b4624789"
node_sending_key_funding_min = 50
node_sending_keys = [
"0x0c0DC7f33A1256f0247c5ea75861d385fa5FED31",
@@ -799,7 +802,6 @@ consumer_address = ""
sub_id = ""
key_hash = "0x4d43763d3eff849a89cf578a42787baa32132d7a80032125710e95b3972cd214"
create_fund_subs_and_add_consumers = true
-link_address = "0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06"
node_sending_key_funding_min = 150
node_sending_keys = [
"0x4EE2Cc6D50E8acb6BaEf673B03559525a6c92fB8",
@@ -878,7 +880,6 @@ consumer_address = ""
sub_id = ""
key_hash = "0x7d5692e71807c4c02f5a109627a9ad2b12a361a346790a306983af9a5e3a186f"
create_fund_subs_and_add_consumers = true
-link_address = "0x92Bd61014c5BDc4A43BBbaAEa63d0694BE43ECDd"
node_sending_key_funding_min = 30
node_sending_keys = [
"0xB97c0C52A2B957b45DA213e652c76090DDd0FEc6",
@@ -965,7 +966,6 @@ consumer_address = ""
sub_id = ""
key_hash = "0xdc023892a41e5fe74ec7c4c2e8c0a808b01aea7acaf2b2ae30f4e08df877c48b"
create_fund_subs_and_add_consumers = true
-link_address = "0xE4DDEDb5A220eC218791dC35b1b4D737ba813EE7"
node_sending_key_funding_min = 30
node_sending_keys = [
"0xF3d9879a75BBD85890056D7c6cB37C555F9b41A3",
@@ -1051,7 +1051,6 @@ consumer_address = ""
sub_id = ""
key_hash = "0x0cb2a18e8b762cb4c8f7b17a6cc02ac7b9d2a3346f048cfd2f5d37677f8747d8"
create_fund_subs_and_add_consumers = true
-link_address = "0xD694472F1CD02E1f3fc3534386bda6802fCFe0f7"
node_sending_key_funding_min = 30
node_sending_keys = [
"0xBFD780Af421e98C35918e10B9d6da7389C3e1D10",
@@ -1138,7 +1137,6 @@ consumer_address = ""
sub_id = ""
key_hash = "0xbc9f525e3e1d9e2336f7c77d5f33f5b60aab3765944617fed7f66a6afecac616"
create_fund_subs_and_add_consumers = true
-link_address = "0x8E3f5E6dFeb4498437149b0d347ef51427dB1DE2"
node_sending_key_funding_min = 30
node_sending_keys = [
]
diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go
index 4803a5249f0..5ea3fb8a3cc 100644
--- a/integration-tests/testsetups/keeper_benchmark.go
+++ b/integration-tests/testsetups/keeper_benchmark.go
@@ -62,9 +62,11 @@ type KeeperBenchmarkTest struct {
chainClient *seth.Client
testConfig tt.KeeperBenchmarkTestConfig
- linkToken contracts.LinkToken
- ethFeed contracts.MockETHLINKFeed
- gasFeed contracts.MockGasFeed
+ linkToken contracts.LinkToken
+ linkethFeed contracts.MockLINKETHFeed
+ gasFeed contracts.MockGasFeed
+ ethusdFeed contracts.MockETHUSDFeed
+ wrappedNative contracts.WETHToken
}
// UpkeepConfig dictates details of how the test's upkeep contracts should be called and configured
@@ -163,10 +165,10 @@ func (k *KeeperBenchmarkTest) Setup(env *environment.Environment, config tt.Keep
}
if common.IsHexAddress(c.EthFeedAddress) {
- _, err = contracts.LoadMockETHLINKFeed(k.chainClient, common.HexToAddress(c.EthFeedAddress))
+ _, err = contracts.LoadMockLINKETHFeed(k.chainClient, common.HexToAddress(c.EthFeedAddress))
require.NoError(k.t, err, "Loading ETH-Link feed Contract shouldn't fail")
} else {
- k.ethFeed, err = contracts.DeployMockETHLINKFeed(k.chainClient, big.NewInt(2e18))
+ k.linkethFeed, err = contracts.DeployMockLINKETHFeed(k.chainClient, big.NewInt(2e18))
require.NoError(k.t, err, "Deploying mock ETH-Link feed shouldn't fail")
}
@@ -178,6 +180,11 @@ func (k *KeeperBenchmarkTest) Setup(env *environment.Environment, config tt.Keep
require.NoError(k.t, err, "Deploying mock gas feed shouldn't fail")
}
+ k.ethusdFeed, err = contracts.DeployMockETHUSDFeed(k.chainClient, big.NewInt(200000000000))
+ require.NoError(k.t, err, "Deploying mock ETH-USD feed shouldn't fail")
+ k.wrappedNative, err = contracts.DeployWETHTokenContract(k.log, k.chainClient)
+ require.NoError(k.t, err, "Deploying WETH Token Contract shouldn't fail")
+
for index := range inputs.RegistryVersions {
k.log.Info().Int("Index", index).Msg("Starting Test Setup")
k.DeployBenchmarkKeeperContracts(index)
@@ -191,7 +198,7 @@ func (k *KeeperBenchmarkTest) Setup(env *environment.Environment, config tt.Keep
for index := range keysToFund {
// Fund chainlink nodes
nodesToFund := k.chainlinkNodes
- if inputs.RegistryVersions[index] == ethereum.RegistryVersion_2_0 || inputs.RegistryVersions[index] == ethereum.RegistryVersion_2_1 || inputs.RegistryVersions[index] == ethereum.RegistryVersion_2_2 {
+ if inputs.RegistryVersions[index] >= ethereum.RegistryVersion_2_0 {
nodesToFund = k.chainlinkNodes[1:]
}
err = actions.FundChainlinkNodesAtKeyIndexFromRootAddress(k.log, k.chainClient, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(nodesToFund), k.Inputs.ChainlinkNodeFunding, index)
@@ -240,15 +247,14 @@ func (k *KeeperBenchmarkTest) Run() {
txKeyId = 0
}
kr := k.keeperRegistries[rIndex]
- // TODO: need to add the LINK, WETH and WETH/USD feed to support v23
ocrConfig, err := actions.BuildAutoOCR2ConfigVarsWithKeyIndex(
- k.t, nodesWithoutBootstrap, *inputs.KeeperRegistrySettings, kr.Address(), k.Inputs.DeltaStage, txKeyId, common.Address{}, kr.ChainModuleAddress(), kr.ReorgProtectionEnabled(), nil, nil, nil,
+ k.t, nodesWithoutBootstrap, *inputs.KeeperRegistrySettings, kr.Address(), k.Inputs.DeltaStage, txKeyId, common.Address{}, kr.ChainModuleAddress(), kr.ReorgProtectionEnabled(), k.linkToken, k.wrappedNative, k.ethusdFeed,
)
require.NoError(k.t, err, "Building OCR config shouldn't fail")
rv := inputs.RegistryVersions[rIndex]
// Send keeper jobs to registry and chainlink nodes
- if rv == ethereum.RegistryVersion_2_0 || rv == ethereum.RegistryVersion_2_1 || rv == ethereum.RegistryVersion_2_2 {
+ if rv >= ethereum.RegistryVersion_2_0 {
actions.CreateOCRKeeperJobs(k.t, k.chainlinkNodes, kr.Address(), k.chainClient.ChainID, txKeyId, rv)
if rv == ethereum.RegistryVersion_2_0 {
err = kr.SetConfig(*inputs.KeeperRegistrySettings, ocrConfig)
@@ -708,7 +714,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts(index int) {
registry, err = contracts.DeployKeeperRegistry(k.chainClient, &contracts.KeeperRegistryOpts{
RegistryVersion: registryVersion,
LinkAddr: k.linkToken.Address(),
- ETHFeedAddr: k.ethFeed.Address(),
+ ETHFeedAddr: k.linkethFeed.Address(),
GasFeedAddr: k.gasFeed.Address(),
TranscoderAddr: actions.ZeroAddress.Hex(),
RegistrarAddr: actions.ZeroAddress.Hex(),
@@ -731,13 +737,13 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts(index int) {
require.NoError(k.t, err, "Funding keeper registrar contract shouldn't fail")
} else { // OCR automation - v2.X
registry, registrar = actions.DeployAutoOCRRegistryAndRegistrar(
- k.t, k.chainClient, registryVersion, *k.Inputs.KeeperRegistrySettings, k.linkToken, nil, nil,
+ k.t, k.chainClient, registryVersion, *k.Inputs.KeeperRegistrySettings, k.linkToken, k.wrappedNative, k.ethusdFeed,
)
// Fund the registry with LINK
err := k.linkToken.Transfer(registry.Address(), big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(k.Inputs.Upkeeps.NumberOfUpkeeps))))
require.NoError(k.t, err, "Funding keeper registry contract shouldn't fail")
- ocrConfig, err := actions.BuildAutoOCR2ConfigVars(k.t, k.chainlinkNodes[1:], *k.Inputs.KeeperRegistrySettings, registrar.Address(), k.Inputs.DeltaStage, registry.ChainModuleAddress(), registry.ReorgProtectionEnabled(), nil, nil, nil)
+ ocrConfig, err := actions.BuildAutoOCR2ConfigVars(k.t, k.chainlinkNodes[1:], *k.Inputs.KeeperRegistrySettings, registrar.Address(), k.Inputs.DeltaStage, registry.ChainModuleAddress(), registry.ReorgProtectionEnabled(), k.linkToken, k.wrappedNative, k.ethusdFeed)
require.NoError(k.t, err, "Building OCR config shouldn't fail")
k.log.Debug().Interface("KeeperRegistrySettings", *k.Inputs.KeeperRegistrySettings).Interface("OCRConfig", ocrConfig).Msg("Config")
require.NoError(k.t, err, "Error building OCR config vars")
diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go
index 45c334bf69d..ff6ce5749a9 100644
--- a/integration-tests/testsetups/ocr.go
+++ b/integration-tests/testsetups/ocr.go
@@ -29,7 +29,7 @@ import (
"github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator"
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
- "github.com/smartcontractkit/havoc/k8schaos"
+ "github.com/smartcontractkit/chainlink-testing-framework/havoc"
"github.com/smartcontractkit/chainlink-testing-framework/blockchain"
ctf_client "github.com/smartcontractkit/chainlink-testing-framework/client"
@@ -91,12 +91,12 @@ type OCRSoakTest struct {
reorgHappened bool // flag to indicate if a reorg happened during the test
gasSpikeSimulationHappened bool // flag to indicate if a gas spike simulation happened during the test
gasLimitSimulationHappened bool // flag to indicate if a gas limit simulation happened during the test
- chaosList []*k8schaos.Chaos // list of chaos simulations to run during the test
+ chaosList []*havoc.Chaos // list of chaos simulations to run during the test
}
type OCRSoakTestOption = func(c *OCRSoakTest)
-func WithChaos(chaosList []*k8schaos.Chaos) OCRSoakTestOption {
+func WithChaos(chaosList []*havoc.Chaos) OCRSoakTestOption {
return func(c *OCRSoakTest) {
c.chaosList = chaosList
}
@@ -277,7 +277,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) {
nodes, err := client.ConnectChainlinkNodes(o.testEnvironment)
require.NoError(o.t, err, "Connecting to chainlink nodes shouldn't fail")
o.bootstrapNode, o.workerNodes = nodes[0], nodes[1:]
- o.mockServer, err = ctf_client.ConnectMockServer(o.testEnvironment)
+ o.mockServer = ctf_client.ConnectMockServer(o.testEnvironment)
require.NoError(o.t, err, "Creating mockserver clients shouldn't fail")
linkContract, err := contracts.DeployLinkTokenContract(o.log, sethClient)
@@ -546,11 +546,7 @@ func (o *OCRSoakTest) LoadState() error {
}
}
- o.mockServer, err = ctf_client.ConnectMockServerURL(testState.MockServerURL)
- if err != nil {
- return err
- }
-
+ o.mockServer = ctf_client.ConnectMockServerURL(testState.MockServerURL)
return err
}
@@ -683,11 +679,11 @@ func (o *OCRSoakTest) testLoop(testDuration time.Duration, newValue int) {
if len(o.chaosList) > 0 {
for _, chaos := range o.chaosList {
chaos.Create(context.Background())
- chaos.AddListener(k8schaos.NewChaosLogger(o.log))
+ chaos.AddListener(havoc.NewChaosLogger(o.log))
chaos.AddListener(ocrTestChaosListener{t: o.t})
// Add Grafana annotation if configured
if o.Config.Logging.Grafana != nil && o.Config.Logging.Grafana.BaseUrl != nil && o.Config.Logging.Grafana.BearerToken != nil && o.Config.Logging.Grafana.DashboardUID != nil {
- chaos.AddListener(k8schaos.NewSingleLineGrafanaAnnotator(*o.Config.Logging.Grafana.BaseUrl, *o.Config.Logging.Grafana.BearerToken, *o.Config.Logging.Grafana.DashboardUID, o.log))
+ chaos.AddListener(havoc.NewSingleLineGrafanaAnnotator(*o.Config.Logging.Grafana.BaseUrl, *o.Config.Logging.Grafana.BearerToken, *o.Config.Logging.Grafana.DashboardUID, o.log))
} else {
o.log.Warn().Msg("Skipping Grafana annotation for chaos simulation. Grafana config is missing either BearerToken, BaseUrl or DashboardUID")
}
@@ -1112,28 +1108,28 @@ type ocrTestChaosListener struct {
t *testing.T
}
-func (l ocrTestChaosListener) OnChaosCreated(_ k8schaos.Chaos) {
+func (l ocrTestChaosListener) OnChaosCreated(_ havoc.Chaos) {
}
-func (l ocrTestChaosListener) OnChaosCreationFailed(chaos k8schaos.Chaos, reason error) {
+func (l ocrTestChaosListener) OnChaosCreationFailed(chaos havoc.Chaos, reason error) {
// Fail the test if chaos creation fails during chaos simulation
require.FailNow(l.t, "Error creating chaos simulation", reason.Error(), chaos)
}
-func (l ocrTestChaosListener) OnChaosStarted(_ k8schaos.Chaos) {
+func (l ocrTestChaosListener) OnChaosStarted(_ havoc.Chaos) {
}
-func (l ocrTestChaosListener) OnChaosPaused(_ k8schaos.Chaos) {
+func (l ocrTestChaosListener) OnChaosPaused(_ havoc.Chaos) {
}
-func (l ocrTestChaosListener) OnChaosEnded(_ k8schaos.Chaos) {
+func (l ocrTestChaosListener) OnChaosEnded(_ havoc.Chaos) {
}
-func (l ocrTestChaosListener) OnChaosStatusUnknown(_ k8schaos.Chaos) {
+func (l ocrTestChaosListener) OnChaosStatusUnknown(_ havoc.Chaos) {
}
-func (l ocrTestChaosListener) OnScheduleCreated(_ k8schaos.Schedule) {
+func (l ocrTestChaosListener) OnScheduleCreated(_ havoc.Schedule) {
}
-func (l ocrTestChaosListener) OnScheduleDeleted(_ k8schaos.Schedule) {
+func (l ocrTestChaosListener) OnScheduleDeleted(_ havoc.Schedule) {
}
diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go
index daa4784ec16..bacb5db6ed4 100644
--- a/integration-tests/universal/log_poller/helpers.go
+++ b/integration-tests/universal/log_poller/helpers.go
@@ -13,6 +13,8 @@ import (
"testing"
"time"
+ "github.com/smartcontractkit/chainlink/integration-tests/utils"
+
"github.com/jmoiron/sqlx"
"github.com/smartcontractkit/seth"
"github.com/smartcontractkit/wasp"
@@ -30,7 +32,6 @@ import (
ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env"
"github.com/smartcontractkit/chainlink-testing-framework/logging"
"github.com/smartcontractkit/chainlink-testing-framework/networks"
- seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
"github.com/smartcontractkit/chainlink/integration-tests/actions"
"github.com/smartcontractkit/chainlink/integration-tests/client"
"github.com/smartcontractkit/chainlink/integration-tests/contracts"
@@ -1059,7 +1060,7 @@ func SetupLogPollerTestDocker(
evmNetwork, err := env.GetFirstEvmNetwork()
require.NoError(t, err, "Error getting first evm network")
- chainClient, err := seth_utils.GetChainClient(testConfig, *evmNetwork)
+ chainClient, err := utils.TestAwareSethClient(t, testConfig, evmNetwork)
require.NoError(t, err, "Error getting seth client")
err = actions.FundChainlinkNodesFromRootAddress(l, chainClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(env.ClCluster.NodeAPIs()), big.NewFloat(chainlinkNodeFunding))
diff --git a/integration-tests/utils/seth.go b/integration-tests/utils/seth.go
new file mode 100644
index 00000000000..237be1a508d
--- /dev/null
+++ b/integration-tests/utils/seth.go
@@ -0,0 +1,25 @@
+package utils
+
+import (
+ "fmt"
+ "testing"
+
+ pkg_seth "github.com/smartcontractkit/seth"
+
+ "github.com/smartcontractkit/chainlink-testing-framework/blockchain"
+ ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config"
+ seth_utils "github.com/smartcontractkit/chainlink-testing-framework/utils/seth"
+)
+
+// DynamicArtifactDirConfigFn returns a function that sets Seth's artifacts directory to a unique directory for the test
+func DynamicArtifactDirConfigFn(t *testing.T) func(*pkg_seth.Config) error {
+ return func(cfg *pkg_seth.Config) error {
+ cfg.ArtifactsDir = fmt.Sprintf("seth_artifacts/%s", t.Name())
+ return nil
+ }
+}
+
+// TestAwareSethClient returns a Seth client with the artifacts directory set to a unique directory for the test
+func TestAwareSethClient(t *testing.T, sethConfig ctf_config.SethConfig, evmNetwork *blockchain.EVMNetwork) (*pkg_seth.Client, error) {
+ return seth_utils.GetChainClientWithConfigFunction(sethConfig, *evmNetwork, DynamicArtifactDirConfigFn(t))
+}
diff --git a/operator_ui/install.go b/operator_ui/install.go
index 1e09783db66..14d920ddd43 100644
--- a/operator_ui/install.go
+++ b/operator_ui/install.go
@@ -22,7 +22,7 @@ func main() {
fullRepo = owner + "/" + repo
tagPath = "operator_ui/TAG"
unpackDir = "core/web/assets"
- downloadTimeoutSeconds = 10
+ downloadTimeoutSeconds = 30
)
// Grab first argument as root directory
if len(os.Args) < 2 {
diff --git a/testdata/scripts/health/default.txtar b/testdata/scripts/health/default.txtar
index 1dbf6b8eb96..777d3e5e126 100644
--- a/testdata/scripts/health/default.txtar
+++ b/testdata/scripts/health/default.txtar
@@ -31,6 +31,7 @@ fj293fbBnlQ!f9vNs
HTTPPort = $PORT
-- out.txt --
+ok HeadReporter
ok JobSpawner
ok Mailbox.Monitor
ok Mercury.WSRPCPool
@@ -38,12 +39,20 @@ ok Mercury.WSRPCPool.CacheSet
ok PipelineORM
ok PipelineRunner
ok PipelineRunner.BridgeCache
-ok PromReporter
ok TelemetryManager
-- out.json --
{
"data": [
+ {
+ "type": "checks",
+ "id": "HeadReporter",
+ "attributes": {
+ "name": "HeadReporter",
+ "status": "passing",
+ "output": ""
+ }
+ },
{
"type": "checks",
"id": "JobSpawner",
@@ -107,15 +116,6 @@ ok TelemetryManager
"output": ""
}
},
- {
- "type": "checks",
- "id": "PromReporter",
- "attributes": {
- "name": "PromReporter",
- "status": "passing",
- "output": ""
- }
- },
{
"type": "checks",
"id": "TelemetryManager",
diff --git a/testdata/scripts/health/help.txtar b/testdata/scripts/health/help.txtar
index 07eb0509e73..68176f05a4e 100644
--- a/testdata/scripts/health/help.txtar
+++ b/testdata/scripts/health/help.txtar
@@ -9,5 +9,6 @@ USAGE:
chainlink health [command options] [arguments...]
OPTIONS:
- --json, -j json output
+ --failing, -f filter for failing services
+ --json, -j json output
diff --git a/testdata/scripts/health/multi-chain.txtar b/testdata/scripts/health/multi-chain.txtar
index 8178f8e8213..bba3b3e111f 100644
--- a/testdata/scripts/health/multi-chain.txtar
+++ b/testdata/scripts/health/multi-chain.txtar
@@ -15,6 +15,14 @@ cp stdout compact.json
exec jq . compact.json
cmp stdout out.json
+exec chainlink --remote-node-url $NODEURL health -failing
+cmp stdout out-unhealthy.txt
+
+exec chainlink --remote-node-url $NODEURL health -f -json
+cp stdout compact.json
+exec jq . compact.json
+cmp stdout out-unhealthy.json
+
-- testdb.txt --
CL_DATABASE_URL
-- testport.txt --
@@ -74,7 +82,9 @@ ok EVM.1.Txm
ok EVM.1.Txm.BlockHistoryEstimator
ok EVM.1.Txm.Broadcaster
ok EVM.1.Txm.Confirmer
+ok EVM.1.Txm.Finalizer
ok EVM.1.Txm.WrappedEvmEstimator
+ok HeadReporter
ok JobSpawner
ok Mailbox.Monitor
ok Mercury.WSRPCPool
@@ -82,11 +92,14 @@ ok Mercury.WSRPCPool.CacheSet
ok PipelineORM
ok PipelineRunner
ok PipelineRunner.BridgeCache
-ok PromReporter
ok Solana.Bar
ok StarkNet.Baz
ok TelemetryManager
+-- out-unhealthy.txt --
+! EVM.1.HeadTracker.HeadListener
+ Listener is not connected
+
-- out.json --
{
"data": [
@@ -207,6 +220,15 @@ ok TelemetryManager
"output": ""
}
},
+ {
+ "type": "checks",
+ "id": "EVM.1.Txm.Finalizer",
+ "attributes": {
+ "name": "EVM.1.Txm.Finalizer",
+ "status": "passing",
+ "output": ""
+ }
+ },
{
"type": "checks",
"id": "EVM.1.Txm.WrappedEvmEstimator",
@@ -216,6 +238,15 @@ ok TelemetryManager
"output": ""
}
},
+ {
+ "type": "checks",
+ "id": "HeadReporter",
+ "attributes": {
+ "name": "HeadReporter",
+ "status": "passing",
+ "output": ""
+ }
+ },
{
"type": "checks",
"id": "JobSpawner",
@@ -279,15 +310,6 @@ ok TelemetryManager
"output": ""
}
},
- {
- "type": "checks",
- "id": "PromReporter",
- "attributes": {
- "name": "PromReporter",
- "status": "passing",
- "output": ""
- }
- },
{
"type": "checks",
"id": "Solana.Bar",
@@ -317,3 +339,17 @@ ok TelemetryManager
}
]
}
+-- out-unhealthy.json --
+{
+ "data": [
+ {
+ "type": "checks",
+ "id": "EVM.1.HeadTracker.HeadListener",
+ "attributes": {
+ "name": "EVM.1.HeadTracker.HeadListener",
+ "status": "failing",
+ "output": "Listener is not connected"
+ }
+ }
+ ]
+}
diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar
index 1063d9c2a5a..ff8b4889c49 100644
--- a/testdata/scripts/node/validate/default.txtar
+++ b/testdata/scripts/node/validate/default.txtar
@@ -18,6 +18,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar
index 327e84c51bb..016d416d5f6 100644
--- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar
+++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar
@@ -62,6 +62,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
@@ -333,6 +334,7 @@ OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '9m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -357,6 +359,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
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 724b59e52d3..f8a98b2c49a 100644
--- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar
+++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar
@@ -62,6 +62,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
@@ -333,6 +334,7 @@ OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '9m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -357,6 +359,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar
index e0eefcba85b..aef3b106a59 100644
--- a/testdata/scripts/node/validate/disk-based-logging.txtar
+++ b/testdata/scripts/node/validate/disk-based-logging.txtar
@@ -62,6 +62,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
@@ -333,6 +334,7 @@ OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '9m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -357,6 +359,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
diff --git a/testdata/scripts/node/validate/invalid-ocr-p2p.txtar b/testdata/scripts/node/validate/invalid-ocr-p2p.txtar
index 6a09dd06c47..0cdf001eccd 100644
--- a/testdata/scripts/node/validate/invalid-ocr-p2p.txtar
+++ b/testdata/scripts/node/validate/invalid-ocr-p2p.txtar
@@ -47,6 +47,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar
index 1955e919da3..2912a803274 100644
--- a/testdata/scripts/node/validate/invalid.txtar
+++ b/testdata/scripts/node/validate/invalid.txtar
@@ -52,6 +52,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
@@ -323,6 +324,7 @@ OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '9m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -347,6 +349,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar
index 3ba20f6f9d6..ce40c91f669 100644
--- a/testdata/scripts/node/validate/valid.txtar
+++ b/testdata/scripts/node/validate/valid.txtar
@@ -59,6 +59,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
@@ -330,6 +331,7 @@ OperatorFactoryAddress = '0x3E64Cd889482443324F91bFA9c84fE72A511f48A'
RPCDefaultBatchSize = 250
RPCBlockQueryDelay = 1
FinalizedBlockOffset = 0
+NoNewFinalizedHeadsThreshold = '9m0s'
[EVM.Transactions]
ForwardersEnabled = false
@@ -354,6 +356,7 @@ LimitDefault = 500000
LimitMax = 500000
LimitMultiplier = '1'
LimitTransfer = 21000
+EstimateGasLimit = false
BumpMin = '5 gwei'
BumpPercent = 20
BumpThreshold = 3
diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar
index a652943e26b..dea40ec8da0 100644
--- a/testdata/scripts/node/validate/warnings.txtar
+++ b/testdata/scripts/node/validate/warnings.txtar
@@ -41,6 +41,7 @@ ShutdownGracePeriod = '5s'
FeedsManager = true
LogPoller = false
UICSAKeys = false
+CCIP = true
[Database]
DefaultIdleInTxSessionTimeout = '1h0m0s'
diff --git a/tools/bin/goreleaser_utils b/tools/bin/goreleaser_utils
index 4e1b3ffc4db..fa9553274c5 100755
--- a/tools/bin/goreleaser_utils
+++ b/tools/bin/goreleaser_utils
@@ -68,11 +68,13 @@ before_hook() {
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"
+ cp "$gobin"/chainlink* "$lib_path/linux_amd64/plugins"
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"
+ cp "$gobin"/chainlink* "$lib_path/linux_arm64/plugins"
}
install_local_plugins() {
@@ -94,10 +96,10 @@ get_remote_plugin_paths() {
)
for plugin in "${plugins[@]}"; do
- plugin_dep_name=$(echo "$plugin" | cut -d"|" -f1)
- plugin_main=$(echo "$plugin" | cut -d"|" -f2)
+ plugin_dep_name=$(echo "$plugin" | cut -d"|" -f1)
+ plugin_main=$(echo "$plugin" | cut -d"|" -f2)
- full_plugin_path=$(go list -m -f "{{.Dir}}" "$plugin_dep_name")"$plugin_main"
+ full_plugin_path=$(go list -m -f "{{.Dir}}" "$plugin_dep_name")"$plugin_main"
echo "$full_plugin_path"
done
}
diff --git a/tools/bin/modgraph b/tools/bin/modgraph
index 4d8ad108c65..4080e53abe9 100755
--- a/tools/bin/modgraph
+++ b/tools/bin/modgraph
@@ -11,11 +11,7 @@ flowchart LR
chainlink-cosmos
chainlink-solana
chainlink-starknet/relayer
- subgraph chainlink-integrations
- direction LR
- chainlink-integrations/evm/relayer
- chainlink-integrations/common
- end
+ chainlink-evm
end
subgraph products
@@ -27,8 +23,13 @@ flowchart LR
chainlink-vrf
end
+ subgraph tdh2
+ tdh2/go/tdh2
+ tdh2/go/ocr2/decryptionplugin
+ end
+
classDef outline stroke-dasharray:6,fill:none;
- class chains,products outline
+ class chains,products,tdh2 outline
"
go mod graph | \
# org only
diff --git a/tools/ci/gorace_test b/tools/ci/gorace_test
deleted file mode 100755
index ebf0b892817..00000000000
--- a/tools/ci/gorace_test
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-GORACE="halt_on_error=1" go test -v -race -parallel 2 -p 1 chainlink/core/internal chainlink/core/services
diff --git a/tools/ci/init_gcloud b/tools/ci/init_gcloud
deleted file mode 100755
index f1ebb12b59a..00000000000
--- a/tools/ci/init_gcloud
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-if [ -z "$GCLOUD_SERVICE_KEY" ]
-then
- echo "Skipping gcloud initiation because no service key is set"
- exit 0
-else
- echo $GCLOUD_SERVICE_KEY > ${HOME}/gcloud-service-key.json
- gcloud auth activate-service-account --key-file=${HOME}/gcloud-service-key.json
- gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
- gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}
-fi